# # install the orchaRd package
# install.packages("devtools")
# install.packages("remotes")
# devtools::install_github("itchyshin/orchard_plot", subdir = "orchaRd", force = TRUE, build_vignettes = TRUE)
# devtools::install_github("MathiasHarrer/dmetar")
# devtools::install_github("daniel1noble/metaAidR")

# these packages need be obtained from github not from cran
#remotes::install_github("rvlenth/emmeans", dependencies = TRUE, build_opts = "")
# remotes::install_github("wviechtb/metafor")
#devtools::install_github("MathiasHarrer/dmetar")
# @TO-DO -  I do not think it is working yet
##remotes::install_github("rlesur/klippy")
## Installing package into 'C:/Users/localadmin/AppData/Local/R/win-library/4.2'
## (as 'lib' is unspecified)
## package 'openxlsx' successfully unpacked and MD5 sums checked
## 
## The downloaded binary packages are in
##  C:\Users\localadmin\AppData\Local\Temp\Rtmpq2Enhb\downloaded_packages
## 
## openxlsx installed
## Installing package into 'C:/Users/localadmin/AppData/Local/R/win-library/4.2'
## (as 'lib' is unspecified)
## also installing the dependencies 'XML', 'rentrez', 'rncl'
## package 'XML' successfully unpacked and MD5 sums checked
## package 'rentrez' successfully unpacked and MD5 sums checked
## package 'rncl' successfully unpacked and MD5 sums checked
## package 'rotl' successfully unpacked and MD5 sums checked
## 
## The downloaded binary packages are in
##  C:\Users\localadmin\AppData\Local\Temp\Rtmpq2Enhb\downloaded_packages
## 
## rotl installed
## Installing package into 'C:/Users/localadmin/AppData/Local/R/win-library/4.2'
## (as 'lib' is unspecified)
## package 'here' successfully unpacked and MD5 sums checked
## 
## The downloaded binary packages are in
##  C:\Users\localadmin\AppData\Local\Temp\Rtmpq2Enhb\downloaded_packages
## 
## here installed
## Installing package into 'C:/Users/localadmin/AppData/Local/R/win-library/4.2'
## (as 'lib' is unspecified)
## also installing the dependencies 'xts', 'TTR', 'modeltools', 'DEoptimR', 'quantmod', 'mclust', 'flexmix', 'prabclus', 'diptest', 'robustbase', 'kernlab', 'anytime', 'fracdiff', 'lmtest', 'timeDate', 'tseries', 'urca', 'zoo', 'RcppArmadillo', 'moments', 'fpc', 'tsibble', 'forecast', 'viridis', 'nullabor'
## package 'xts' successfully unpacked and MD5 sums checked
## package 'TTR' successfully unpacked and MD5 sums checked
## package 'modeltools' successfully unpacked and MD5 sums checked
## package 'DEoptimR' successfully unpacked and MD5 sums checked
## package 'quantmod' successfully unpacked and MD5 sums checked
## package 'mclust' successfully unpacked and MD5 sums checked
## package 'flexmix' successfully unpacked and MD5 sums checked
## package 'prabclus' successfully unpacked and MD5 sums checked
## package 'diptest' successfully unpacked and MD5 sums checked
## package 'robustbase' successfully unpacked and MD5 sums checked
## package 'kernlab' successfully unpacked and MD5 sums checked
## package 'anytime' successfully unpacked and MD5 sums checked
## package 'fracdiff' successfully unpacked and MD5 sums checked
## package 'lmtest' successfully unpacked and MD5 sums checked
## package 'timeDate' successfully unpacked and MD5 sums checked
## package 'tseries' successfully unpacked and MD5 sums checked
## package 'urca' successfully unpacked and MD5 sums checked
## package 'zoo' successfully unpacked and MD5 sums checked
## package 'RcppArmadillo' successfully unpacked and MD5 sums checked
## package 'moments' successfully unpacked and MD5 sums checked
## package 'fpc' successfully unpacked and MD5 sums checked
## package 'tsibble' successfully unpacked and MD5 sums checked
## package 'forecast' successfully unpacked and MD5 sums checked
## package 'viridis' successfully unpacked and MD5 sums checked
## package 'nullabor' successfully unpacked and MD5 sums checked
## package 'metaviz' successfully unpacked and MD5 sums checked
## 
## The downloaded binary packages are in
##  C:\Users\localadmin\AppData\Local\Temp\Rtmpq2Enhb\downloaded_packages
## 
## metaviz installed
## Installing package into 'C:/Users/localadmin/AppData/Local/R/win-library/4.2'
## (as 'lib' is unspecified)
## also installing the dependency 'CompQuadForm'
## package 'CompQuadForm' successfully unpacked and MD5 sums checked
## package 'meta' successfully unpacked and MD5 sums checked
## 
## The downloaded binary packages are in
##  C:\Users\localadmin\AppData\Local\Temp\Rtmpq2Enhb\downloaded_packages
## 
## meta installed
## Installing package into 'C:/Users/localadmin/AppData/Local/R/win-library/4.2'
## (as 'lib' is unspecified)
## also installing the dependencies 'gridGraphics', 'yulab.utils'
## package 'gridGraphics' successfully unpacked and MD5 sums checked
## package 'yulab.utils' successfully unpacked and MD5 sums checked
## package 'ggplotify' successfully unpacked and MD5 sums checked
## 
## The downloaded binary packages are in
##  C:\Users\localadmin\AppData\Local\Temp\Rtmpq2Enhb\downloaded_packages
## 
## ggplotify installed
## Installing package into 'C:/Users/localadmin/AppData/Local/R/win-library/4.2'
## (as 'lib' is unspecified)

Appendix S1: Survey of publication bias tests reported in ecology and evolution meta-analyses

S1.1: Survey method

The main objective of the literature survey was to capture the types of publication bias methods recently used in the field of ecology and evolution. The survey reported here was conducted alongside a larger survey on reporting standards from the PRISMA-EcoEvo project (Preferred Reporting Items for Systematic reviews and Meta-Analyses in Ecology and Evolutionary Biology; full details and materials provided in O’Dea et al. (2021). The survey was based on 102 meta-analysis papers published between 1 January 2010 and 25 March 2019. We aimed for the sample of 102 meta-analyses to be representative of recently published meta-analyses in ecology and evolutionary biology journals.

S1.1.1 Representative Sample

To select the representative sample of meta-analysis publications, we first searched the Scopus database for papers with (“meta-analy*” OR “metaanaly*” OR “meta-regression”) in the title, abstract, or keywords (where the asterisk allows for any ending to the word, such as “meta-analyses” or “meta-analysis”), restricted the date to papers published after 2009, and restricted the ISSN (International Standard Serial Number) to journals classified as ‘Ecology’ and/or ‘Evolutionary Biology’ by the 2017 rankings of the ISI InCites Journal Citation Reports. On 25 March 2019 this search returned 1,668 papers from 134 journals.

Second, the returned papers were categorised as being from journals listed as ‘Ecology’, ‘Evolution’, or ‘Both’, and we reduced the number of journals and papers. To reduce the number of journals we arranged journals in descending order of frequency (i.e. to indicate which journals published the most meta-analyses). After removing journals in more applied sub-fields (such as ecology economics), we retained the top 10 journals classified as ecology, the top 10 journals classified as evolutionary biology, and the top 11 journals classified as both ecology and evolutionary biology. The list of 31 retained journals is shown in Table S1. Next, we selected 297 studies to be screened for inclusion in the sample, by using the ‘sample’ function in R (v. 3.5.1; R Core Team, 2018) to randomly select up to 17 studies from the journals classified as ‘Evolutionary Biology’ (57 studies total) or ‘Both’ (150 studies total), and up to 9 studies from journals classified as ‘Ecology’ (90 studies total).

Table S1.1

Journals screened in our search for a representative sample of meta-analyses published in ecology and evolutionary biology. ISI Classification is based on the 2017 ISI InCites Journal Citation Reports. The number of papers returned from the Scopus database search is described by ‘N hits’, while the number of studies selected for screening is described by ‘N screened’.

# getting the data and formatting some variables (turning character vectors to factors)
read_excel(here("data/TableS1.xlsx"), na = "NA") %>% 
  #mutate_if(is.character, as.factor) %>%  
  kableExtra::kbl() %>%
  kableExtra::kable_paper() %>% 
  kableExtra::kable_styling("striped", position = "left")
ISI Classification Full Journal Title N hits N screened
Both Proceedings of the Royal Society of London B: Biological Sciences 47 17
Both Ecology and Evolution 43 17
Both Molecular Ecology 35 17
Both Journal of Evolutionary Biology 32 17
Both Evolution 25 17
Both American Naturalist 20 17
Both Biology Letters 17 17
Both Evolutionary Ecology 14 14
Both Nature Ecology & Evolution 7 7
Both Heredity 5 5
Both Molecular Ecology Resources 5 5
Ecology Global Change Biology 135 9
Ecology Ecology Letters 98 9
Ecology Oikos 65 9
Ecology Global Ecology and Biogeography 51 9
Ecology Biological Conservation 49 9
Ecology Oecologia 47 9
Ecology Conservation Biology 43 9
Ecology Journal of Applied Ecology 42 9
Ecology Journal of Ecology 35 9
Ecology Marine Ecology Progress Series 35 9
Evolution BMC Evolutionary Biology 12 12
Evolution Evolutionary Applications 10 10
Evolution Biological Journal of the Linnean Society 9 9
Evolution Molecular Biology and Evolution 7 7
Evolution Genome Biology and Evolution 4 4
Evolution Molecular Phylogenetics and Evolution 4 4
Evolution Evolutionary Bioinformatics 3 3
Evolution Evolutionary Biology 3 3
Evolution Journal of Heredity 3 3
Evolution Systematic Biology 2 2

S1.1.2 Inclusion criteria and screening methods

The sample of 102 meta-analysis papers met the following four inclusion criteria: (1) the study addressed a question in the fields of ecology and evolutionary biology; (2) claimed to present results from a meta-analysis; (3) performed a search for, and collected, data from the primary literature; (4) used a statistical model to analyse effect sizes that were collected from multiple studies. Paper screening was conducted in two stages. First, two authors (RO and ML) conducted parallel abstract screening. Conflicting decisions were discussed and resolved. Second, 64% of screened abstracts underwent parallel full-text screening by RO and ML, in consultation with SN.

S1.1.3 Assessing 102 meta-analysis papers

Papers were independently assessed by seven authors (RO, DN, JK, MJ, ML, RO, SN, and TP) as part of a larger survey. The one survey question pertaining to this publication bias project was: “Which publication bias tests are reported in the paper? (Select all that apply)”. There were 11 possible choices for respondents to select: (A) Funnel plots (including contour-enhanced funnel plots); (B) Normal quantile (QQ) plots (Wang & Bushman); (C) Correlation-based tests (e.g. Begg & Manzumdar rank correlation); (D) Regression-based tests (e.g. Egger regression and its variants); (E) File drawer numbers or fail-safe N (Rosenthal, Orwin or Rosenberg method); (F) Trim-and-fill tests; (G) P-curve, P-uniform or its variants; (H) Selection (method) models (e.g. Copas, Hedges or Iyengar & Greenhouse model); (I) Time-lag bias tests (e.g., regression or correlation on the relationship between effect sizes and time or cumulative meta-analysis); (J) None reported and (K) ‘Other’ methods. According to Sutton (2009) (see also Vevea et al., 2019), Methods A-D are tests detecting publication bias, whereas Methods E-F are assessing the impact of publication bias.

S1.2 Results

Among the 102 assessed papers, 17.8% did not report any tests of publication bias. Most meta-analysis papers reported one or more tests of publication bias (17.8% of assessed papers did not include any assessment of publication bias). These results suggest tests of publication bias have become more common in recent years in ecology and evolutionary biology, as over half of older meta-analyses assessed by Nakagawa and Santos (2012) and Koricheva and Gurevitch (2014) did not report any tests of publication bias (although our results are not directly comparable, due to the different survey methods). Still, inferential tests of publication bias remain uncommon. By far the most popular test of publication bias were funnel plots (32.4%; Table S2), with all remaining methods represented by fewer than 15% of papers. All methods except ‘selection models’ were present in at least one paper (with ‘other’ being selected for a weighted histogram used by Loydi et al. (2013; Table S2). The absence of selection model methods could be because these methods are comparatively technically challenging, or because ecologists and evolutionary biologists are not yet aware of the benefits of these methods.

Table S1.2

Frequency with which publication bias tests were reported in the 102 meta-analysis publications, ranked in order of decreasing popularity. No tests were reported for 17.80% of papers.

# getting the data and formatting some variables (turning character vectors to factors)
read_excel(here("data/TableS2.xlsx"), na = "NA") %>% 
  #mutate_if(is.character, as.factor) %>%  
  kableExtra::kbl() %>%
  kableExtra::kable_paper() %>% 
  kableExtra::kable_styling("striped", position = "left")
Publication Bias Test Number of Papers Reporting Test Percentage of Papers Reporting Test
  1. Funnel plots
69 0.324
  1. Fail-safe N
30 0.141
  1. Regression-based methods
25 0.117
  1. Correlation-based methods
20 0.094
  1. Trim-and-fill tests
16 0.075
  1. Time-lag bias tests
10 0.047
  1. P-value-based methods
3 0.014
  1. Normal quantile (QQ) plots
1 0.005
  1. Other (weighted histogram)
1 0.005
  1. Selection models
0 0.000

Appendix S2: Equivalence between Equations 8 and 9

As in the main text, Equation 8 is as follows \[ z_{i} = \beta_{0} + \beta_{1}prec_i + e_i,\\ \] where \(e_{i} \sim \mathcal{N}(0, \sigma_e^2)\). We can rewrite this as:

\[ \frac{y_{i}}{se_i} = \beta_{0} + \beta_{1}\left(\frac{1}{se_{i}}\right) + e_i,\\ \] If we multiple both sides by \(se_i\), we have:

\[ y_{i} = \beta_{0}se_i + \beta_{1} + e_{i}se_{i}, \]

which is basically the same, if \(\beta_0\) and \(\beta_1\) are swapped, as:

\[ y_{i} = \beta_{0} + \beta_{1}se_i + \epsilon_i, \] where \(\epsilon_i \sim \mathcal{N}(0, v_i\phi)\) as in Equation 9. We can show this using simulated data as well (we use the data for Figure 3 and 4). Below the first result is from Equation 8 and the second Equation 9:

# creating data - the same data as Figures 3 + 4
set.seed(77777)
# setting parameters
n.effect <- 100
sigma2.s <- 0.05
   beta1 <- 0.2

# using negative binomial we get a good spread of sample sizes
n.sample <- rnbinom(n.effect, mu = 30, size = 0.7) + 4

# variance for Zr
vi <- 1/(n.sample - 3)

# moderator x 1
xi <- rnorm(n.effect)

# there is an overall effect of r = 0.2 (Zr = 0.203, which we get from the `atanh` function)
Zr <- atanh(0.2) + beta1*xi + rnorm(n.effect, 0, sqrt(sigma2.s)) + rnorm(n.effect, 0, sqrt(vi))
#qplot(Zr, 1/sqrt(vi))

# data frame
dat <- data.frame(yi = Zr, vi = vi, sei = sqrt(vi), xi = xi, ni = n.sample, prec = 1 / sqrt(vi), wi = 1/vi, zi = Zr/sqrt(vi))
      rows <- 1:nrow(dat)
  expected <- which(1/dat$sei < 5 & dat$yi < 0.25)
unexpected <- which(1/dat$sei > 4.7 & dat$yi > 0.25)
 col_point <- ifelse(rows %in% expected, "red", ifelse(rows %in% unexpected, "blue", "black"))
dat$col_point <- col_point

# data with "publication bias"
dat2 <- dat[dat$col_point != "red", ]

# demonstration that they are the same
eq_8 <- lm(zi ~ prec, data = dat2)
eq_9 <- lm(yi ~ sei, weight = wi, data = dat2)
summary(eq_8)
## 
## Call:
## lm(formula = zi ~ prec, data = dat2)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
## -5.389 -1.011 -0.027  0.969  5.082 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   1.6657     0.4465    3.73  0.00038 ***
## prec         -0.0382     0.0741   -0.52  0.60743    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 1.73 on 73 degrees of freedom
## Multiple R-squared:  0.00363,    Adjusted R-squared:  -0.01 
## F-statistic: 0.266 on 1 and 73 DF,  p-value: 0.607
summary(eq_9)
## 
## Call:
## lm(formula = yi ~ sei, data = dat2, weights = wi)
## 
## Weighted Residuals:
##    Min     1Q Median     3Q    Max 
## -5.389 -1.011 -0.027  0.969  5.082 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -0.0382     0.0741   -0.52  0.60743    
## sei           1.6657     0.4465    3.73  0.00038 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 1.73 on 73 degrees of freedom
## Multiple R-squared:  0.16,   Adjusted R-squared:  0.149 
## F-statistic: 13.9 on 1 and 73 DF,  p-value: 0.000375

As you can see above, Equation 8’s intercept is identical to the slope of Equation 9, while Equation 8’s slope is identical to Equation 9’s intercept. Note that corresponding standard errors (SE) are also the same.

Appendix S3: Fail-safe N comparisons

We use the function fsn() in the R package, metafor, as in this web page: https://wviechtb.github.io/metafor/reference/fsn.html.

# example data using risk ratio (not response ratio)
dat <- escalc(measure="RR", ai=tpos, bi=tneg, ci=cpos, di=cneg, data=dat.bcg)
fsn(yi, vi, data=dat, type="Rosenthal")
## 
## Fail-safe N Calculation Using the Rosenthal Approach
## 
## Observed Significance Level: <.0001
## Target Significance Level:   0.05
## 
## Fail-safe N: 598
# setting effect size targe as -0.1
fsn(yi, vi,  data=dat, type="Orwin", target = 0.1)
## 
## Fail-safe N Calculation Using the Orwin Approach
## 
## Average Effect Size: -0.7407
## Target Effect Size:  -0.1000
## 
## Fail-safe N: 84
fsn(yi, vi, data=dat, type="Rosenberg")
## 
## Fail-safe N Calculation Using the Rosenberg Approach
## 
## Average Effect Size:         -0.4303
## Observed Significance Level: <.0001
## Target Significance Level:   0.05
## 
## Fail-safe N: 370

Appendix S4: Multilevel meta-regression method for publication bias

In this section, we provide worked examples to show how to test for publication bias in meta-analytic datasets with high heterogeneity and several layers of non-independence, including phylogenetic non-independence (a common feature of meta-analytic datasets in ecology and evolution; Senior et al. 2016, Noble et al. 2017). We used two openly available meta-analytic datasets to show how to implement our suggested multilevel meta-regression method (see main text) on correlation effect sizes (Zr: section S4.1) and effect sizes based on mean differences between two groups (SMD, lnRR: section S4.2).

S4.1: Correlation effect sizes (Zr)

# importing dataset with correlation coefficients
dataset.r.original <- read.xlsx(here("data","ft044.xlsx"), colNames = TRUE, sheet = 1)

# transforming r to Zr for the analyses, and estimating VZr for the weighting
dataset.r.original$Sample.size <- as.numeric(dataset.r.original$Sample.size)

# subset dataset to those with 4 or more individuals (this removes two rows, one without sample size and one with sample size = 3). Effect sizes based on 3 individuals won't be able to be analyzed because VZr is then infinite (as the denominator when calculating VZr is zero).
dataset.r.original <- dataset.r.original[dataset.r.original$Sample.size>3 & !(is.na(dataset.r.original$Sample.size)),]

dataset.r.original$yi <- atanh(dataset.r.original$Correlation)
dataset.r.original$vi <- 1/(as.numeric(dataset.r.original$Sample.size)-3)  

# renaming some variables to make it easier
dataset.r.original$study <- dataset.r.original$Reference
dataset.r.original <- dataset.r.original[ , !names(dataset.r.original) %in% c("Reference")]

For our first worked example, we use the dataset provided by Garamszegi et al. (2012), who found support for correlations across different behavioural traits within animal populations. Here, we re-analyse the data from Garamszegi et al. (2012) by first conducting a phylogenetic multilevel intercept-only meta-analytic model and then testing for evidence of publication bias following the approaches outlined in the main text.

S4.1.1 - Phylogenetic relationships

Since multiple animal species (n = 65) are included in this dataset, we need to consider phylogenetic non-independence in our statistical models (Chamberlain et al. 2012, Cinar et al. 2020). For that, we first search for the species in the Open Tree Taxonomy (Rees and Cranston 2017) to confirm and correct the species names, then build a phylogenetic tree for all the species included in the dataset (Figure S1) by retrieving their phylogenetic relationships from the Open Tree of Life (Hinchliff et al. 2015) using the R package rotl (Michonneau et al. 2016). Next, we estimate branch lengths following Grafen (1989) as implemented in the function ‘compute.brlen()’ of the R package ape (Paradis and Schliep 2019). Finally, we construct a phylogenetic relatedness correlation matrix that will be fitted as part of the random effect structure of our models (see below).

# fixing a typo in the original list of species names
dataset.r.original$Species <- ifelse(dataset.r.original$Species=="Acrochephalus schoenobaenus",
                                     "Acrocephalus schoenobaenus",
                                     dataset.r.original$Species)

# updating a name that was not being well recognized by the Open Tree Taxonomy
dataset.r.original$Species <- ifelse(dataset.r.original$Species=="Eurotestudo boettgeri",
                                     "Testudo boettgeri",
                                     dataset.r.original$Species)

# fixing another typo in the original list of species names
dataset.r.original$Species <- ifelse(dataset.r.original$Species=="Taenopygia guttata",
                                     "Taeniopygia guttata",
                                     dataset.r.original$Species)

# # obtaining dataframe listing the Open Tree identifiers potentially matching our list of species (or you can load the data below)
#taxa <- tnrs_match_names(names = unique(dataset.r.original$Species))

# # saving the taxonomic data created on the 18th of February 2021 to speed the process in the future and make the code fully reproducible if taxonomic changes are implemented in the future
# save(taxa,file = "taxa_Open_Tree_of_Life_20210218.RData")

# loading the taxonomic data (taxa) created on the 18th of February 2021
load(here("data", "taxa_Open_Tree_of_Life_20210218.RData"))

# # check approximate matches
# taxa[taxa$approximate_match==TRUE,]
# 
# # check synonyms matches
# taxa[taxa$is_synonym==TRUE,]
# 
# # check number of matches
# taxa[taxa$number_matches>1,]

# # some further checks
# ott_id_tocheck <- taxa[taxa$number_matches != 1,"ott_id"]

# for(i in 1:length(ott_id_tocheck)){
#   print(inspect(taxa, ott_id = ott_id_tocheck[i]))
# }

# all phylogenetic data seems in order now

# however, the ott_id for Parma unifasciata cannot be found when retrieving the phylogenetic relationships, so to get around this we are going to use the ott_id of another Parma species, Parma oligolepis (ott_id = 323186). In this case it is fine because we only include two species belonging to the genus Parma, and therefore, the phylogenetic relationship will be the same for our purposes
# tnrs_match_names(names = 'Parma oligolepis')
# taxa[taxa$unique_name=="Parma unifasciata","ott_id"] <- 323186

# # retrieving phylogenetic relationships among taxa in the form of a trimmed sub-tree (you can simply load the tree at the bottom)
# tree <- tol_induced_subtree(ott_ids = taxa[["ott_id"]], label_format = "name")

# # we need to check for the existence of polytomies
# is.binary.tree(tree) # No polytomies, so we can proceed.

# to confirm that our tree covers all the species we wanted it to include, and make sure that the species names in our database match those in the tree, we use the following code

# tree$tip.label <- gsub("_"," ", tree$tip.label)
# intersect(as.character(tree$tip.label), as.character(dataset.r.original$Species))
# setdiff(as.character(dataset.r.original$Species), as.character(tree$tip.label)) #listed in our database but not in the tree
# setdiff(as.character(tree$tip.label),as.character(dataset.r.original$Species)) # listed in the tree but not in our database

# All but Pan and Parma oligolepis are the same species, the "problem" is that synonyms have been used in the tree. We are going to leave all the names as in Open Tree of Life except Pan and Parma oligolepis, which we are going to substitute by Pan troglodytes and Parma unifasciata

# # we start by fixing the following names in the tree
# tree$tip.label[tree$tip.label=="Pan"]<-"Pan troglodytes"
# tree$tip.label[tree$tip.label=="Parma oligolepis"]<-"Parma unifasciata"

# setdiff(as.character(dataset.r.original$Species), as.character(tree$tip.label)) #listed in our database but not in the tree
# setdiff(as.character(tree$tip.label),as.character(dataset.r.original$Species)) # listed in the tree but not in our database


# changing the names in our database to follow those in the tree. We are creating a new Species.updated variable so that it is clear that this list of Species is an updated version compared to the original one
dataset.r.original$Species.updated <- dataset.r.original$Species

dataset.r.original$Species.updated <- ifelse(dataset.r.original$Species.updated=="Carduelis chloris",
                                             "Chloris chloris",
                                             dataset.r.original$Species.updated)

dataset.r.original$Species.updated <- ifelse(dataset.r.original$Species.updated=="Dendroica pensylvaniaca",
                                             "Setophaga pensylvanica",
                                             dataset.r.original$Species.updated)

dataset.r.original$Species.updated <- ifelse(dataset.r.original$Species.updated=="Sylvia melanocephala",
                                             "Curruca melanocephala",
                                             dataset.r.original$Species.updated)

# we are also updating the original Species variable since we have to fit both Species and Species.updated in our models (see below)
dataset.r.original$Species <- dataset.r.original$Species.updated

# setdiff(as.character(dataset.r.original$Species.updated), as.character(tree$tip.label)) #listed in our database but not in the tree
# setdiff(as.character(tree$tip.label),as.character(dataset.r.original$Species.updated)) # listed in the tree but not in our database

# all in order

# we can now save the tree
#save(tree, file = "tree_20211802.Rdata")

dataset.r <- dataset.r.original

# load the saved tree (tree)
load(here("data","tree_20211802.Rdata")) 

# compute branch lengths of tree
phylo_branch <- compute.brlen(tree, method = "Grafen", power = 1)

# # check tree is ultrametric
# is.ultrametric(phylo_branch) # TRUE

# matrix to be included in the models
phylo_cor <- vcv(phylo_branch, cor = T)
Figure S4.1
plot(tree, type = "fan", cex=0.65, label.offset =.05, no.margin = TRUE) #check: https://www.rdocumentation.org/packages/ape/versions/5.3/topics/plot.phylo
Phylogenetic tree of all species included in the meta-analytic dataset. Notice that some of the names shown in the tree correspond to the most updated synonyms according to the Open Tree Taxonomy (Rees and Cranston 2017) of those originally avialable in the dataset of Garamszegi et al. (2012).

Phylogenetic tree of all species included in the meta-analytic dataset. Notice that some of the names shown in the tree correspond to the most updated synonyms according to the Open Tree Taxonomy (Rees and Cranston 2017) of those originally avialable in the dataset of Garamszegi et al. (2012).



S4.1.2: Exploratory data analysis

Before running any meta-analytic model, it is important to explore the meta-analytic dataset to search for potential outliers that could represent data extraction errors. To do so, we can draw funnel plots showing the standard error and the inverse of the standard error (i.e. precision) as the y-axes (Figure S4.2). From these funnel plots (Figure S4.2), we conclude that no clear outliers seem to be present in this meta-analytic dataset.

Figure S4.2
par(mfrow = c(1, 2))
funnel(dataset.r$yi, dataset.r$vi, yaxis="sei",
       #xlim = c(-3, 3),
       xlab = "Effect size (Zr)", digits = 2, las = 1) 
funnel(dataset.r$yi, dataset.r$vi, yaxis="seinv",
       #xlim = c(-3, 3),
       xlab = "Effect size (Zr)",  digits = 2, las = 1) 
Funnel plots with SE (left-hand side) and precision (1/SE; right-hand side) as measures of uncertainty to explore the existence of outliers in the meta-analytic dataset.

Funnel plots with SE (left-hand side) and precision (1/SE; right-hand side) as measures of uncertainty to explore the existence of outliers in the meta-analytic dataset.



S4.1.3: Multilevel meta-analysis

Now that we have created a matrix with the phylogenetic relationships among species and have confirmed that no outliers seem to be present, we can then use the dataset from Garamszegi et al. (2012) to provide a worked example on how to test for publication bias using the multilevel meta-regression method suggested in the main text. First, let’s have a look at the detailed results of a multilevel phylogenetic meta-analytic (intercept-only) model (Table S4.1), including the corresponding funnel plot showing the overall effect or meta-analytic mean (Figure S4.3).

# creating a unit-level random effect to model residual variance in metafor
dataset.r$obsID <- 1:nrow(dataset.r)

# running multilevel intercept-only meta-analytic model
meta.analysis.model.r <- rma.mv(yi, vi,
                                mods=~1,
                                random=list(~ 1 | Species.updated, # phylo effect
                                            ~ 1 | Species, # non-phylo effect
                                            ~ 1 | study, 
                                            ~ 1 | obsID), 
                                R = list(Species.updated = phylo_cor), #phylogenetic relatedness
                                method="REML",
                                test="t", # using t dist rather than z because t is a better, more conservative distribution than z
                                data=dataset.r)

# print(meta.analysis.model.r, digits=3)

# extracting the mean, 95% confidence intervals and 95% prediction intervals
metaanalytic.mean.model.r <- predict(meta.analysis.model.r, digits=3)

# estimating I2 as measure of heterogeneity
I2.model.r <- i2_ml(meta.analysis.model.r, method = "matrix")

# creating a data.frame with the meta-analytic mean and heterogeneity estimates
table.model.r <- data.frame(n=length(unique(dataset.r$study)),
                            k=nrow(dataset.r),
                            mean=round(metaanalytic.mean.model.r[[1]],2),
                            CI=paste0("[",round(metaanalytic.mean.model.r[[3]],2),",",round(metaanalytic.mean.model.r[[4]],2),"]"),
                            PI=paste0("[",round(metaanalytic.mean.model.r[[5]],2),",",round(metaanalytic.mean.model.r[[6]],2),"]"),
                            I2_obsID=round(I2.model.r[["I2_obsID"]],1),
                            I2_paperID=round(I2.model.r[["I2_study"]],1),
                            I2_nonphylo=round(I2.model.r[["I2_Species"]],1), 
                            I2_phylo=round(I2.model.r[["I2_Species.updated"]]*100,1),
                            I2_total=round(I2.model.r[["I2_Total"]],1)
)

# creating a nicely-formatted table using the R package 'gt'
table.model.r.gt <- table.model.r %>% 
  gt::gt() %>% 
  cols_label(n=md("**n**"),
             k=md("**k**"),
             mean=md("**Meta-analytic mean**"),
             CI=md("**95% CI**"),
             PI=md("**95% PI**"),
             I2_obsID=md("***I*<sup>2</sup><sub>residual</sub>\n(%)**"),
             I2_paperID=md("***I*<sup>2</sup><sub>study</sub>\n(%)**"),
             I2_nonphylo=md("***I*<sup>2</sup><sub>non-phylogeny</sub>\n(%)**"),
             I2_phylo=md("***I*<sup>2</sup><sub>phylogeny</sub>\n(%)**"),
             I2_total=md("***I*<sup>2</sup><sub>total</sub>    \n(%)**"),
  ) %>%
  cols_align(align = "center") %>%
  tab_source_note(source_note = md("n = number of studies; k = number of effects; CI = confidence interval; PI = prediction interval; *I*<sup>2</sup> = heterogeneity")) #%>%
# tab_options(table.width=770)

table.model.r.gt
n k Meta-analytic mean 95% CI 95% PI I2residual (%) I2study (%) I2non-phylogeny (%) I2phylogeny (%) I2total
(%)
88 104 0.29 [0.17,0.41] [-0.25,0.83] 15.9 29.5 20.9 807 74.3
n = number of studies; k = number of effects; CI = confidence interval; PI = prediction interval; I2 = heterogeneity

Table S4.1. Results of the phylogenetic multilevel intercept-only meta-analysis testing the relationship between behaviours across species. Estimates are presented as standardized effect sizes using Fisher’s transformation of the correlation coefficient (i.e. Zr).



Figure S4.3
funnel(meta.analysis.model.r, yaxis="seinv",
       xlab = "Effect size (Zr)")
Funnel plot, using precision (1/SE) as a measure of uncertainty, showing the meta-analytic mean obtained in the phylogenetic multilevel intercept-only meta-analysis as a dotted vertical line.

Funnel plot, using precision (1/SE) as a measure of uncertainty, showing the meta-analytic mean obtained in the phylogenetic multilevel intercept-only meta-analysis as a dotted vertical line.



S4.1.4: Publication bias tests with multilevel meta-regression

S4.1.4.1: Meta-regression with SE (uni-moderator)

To test for publication bias, we can first fit a phylogenetic multilevel meta-regression to explore whether there is some evidence of small-study effects in our meta-analytic dataset. To do so, we fit a uni-moderator phylogenetic multilevel meta-regression including the effect sizes’ standard errors (SE or sei) as the only moderator (see Equation 21 from the main text). This meta-regression will provide some information about the existence of small-study effects (i.e. asymmetry in the distribution of effect sizes), but the best evidence for small-study effects will come from the all-in publication bias test (multi-moderator meta-regression) described in section S4.1.4.3, since this multi-moderator meta-regression will test whether asymmetry exists after accounting for the heterogeneity explained by all the included moderators (more in the main text).

# creating a variable for the standard error of each effect size (i.e. the square root of the sampling variance, see Figure 1 from the main text)
dataset.r$sei <- sqrt(dataset.r$vi)

# Application of Equation 21 from the main text
publication.bias.model.r.se <- rma.mv(yi, vi,
                                      mod =~1+sei,
                                      random=list(~ 1 | Species.updated, # phylo effect
                                                  ~ 1 | Species, # non-phylo effect
                                                  ~ 1 | study, 
                                                  ~ 1 | obsID), 
                                      R = list(Species.updated = phylo_cor), #phylogenetic relatedness
                                      method="REML",
                                      test="t", # using t dist rather than z 
                                      data=dataset.r)

# print(publication.bias.model.r.se,digits=3)

# extracting the mean and 95% confidence intervals
estimates.publication.bias.model.r.se <- estimates.CI(publication.bias.model.r.se)

According to this uni-moderator meta-regression, there is some indication of small-study effects since the slope of the moderator ‘SE’ is close to statistical significance (slope = 0.75, 95% CI = [-0.01,1.51]; R2marginal = 13.4%), showing that effect sizes with larger SE (more uncertain effect sizes) tend to be larger. Nonetheless, as mentioned above, we will confirm the existence of small-study effects after accounting for some of the heterogeneity present in the data using the all-in publication bias test (multi-moderator meta-regression) described in section S4.1.4.3.

S4.1.4.2: Meta-regression with year of publication (uni-moderator)

To test for time-lag bias (also called decline effects) we can first fit a uni-moderator phylogenetic multilevel meta-regression including the year of publication (mean-centred) as the only moderator (see Equation 23 from the main text). The estimated slope for year of publication will provide some evidence on whether effect sizes have changed linearly over time since the first effect size was published; however, as above, the best evidence for such decline effects will come from the all-in publication bias test (multi-moderator meta-regression) described in section S4.1.4.3, since this multi-moderator meta-regression will test for the existence of decline effects after accounting for the heterogeneity explained by all the included moderators (more in the main text).

# creating a variable with the year of publication
dataset.r$year <- as.numeric(str_extract(dataset.r$study, "(\\d)+"))

# mean-centring year of publication to help with interpretation, particularly in S4.1.4.3.
dataset.r$year.c <- as.vector(scale(dataset.r$year, scale = F))

# Application of Equation 23 from the main manuscript
publication.bias.model.r.timelag <- rma.mv(yi, vi,
                                           mods=~1+year.c,
                                           random=list(~ 1 | Species.updated, # phylo effect
                                                       ~ 1 | Species, # non-phylo effect
                                                       ~ 1 | study, 
                                                       ~ 1 | obsID), 
                                           R = list(Species.updated = phylo_cor), #phylogenetic relatedness
                                           method="REML",
                                           test="t", # using t dist rather than z 
                                           data=dataset.r)

# summary(publication.bias.model.r.timelag)

# extracting the mean and 95% confidence intervals
estimates.publication.bias.model.r.timelag <- estimates.CI(publication.bias.model.r.timelag)

According to this uni-moderator meta-regression, there is no indication of decline effects since the slope of the moderator ‘year of publication’ is essentially zero (slope = 0, 95% CI = [-0.01,0.01]; R2marginal = 0.3%). Nonetheless, as mentioned above, we need to confirm this pattern after accounting for some of the heterogeneity present in the data using the all-in publication bias test (multi-moderator meta-regression) described in section S4.1.4.3.

S4.1.4.3: All-in publication bias test (multi-moderator)

When heterogeneity exists (which is normally the case in ecology and evolution; Senior et al. 2016), it is best to combine Equations 21 and 23 with other moderators since those additional moderators will generally be expected to explain some of the heterogeneity. That is, this all-in publication bias test (multi-moderator meta-regression) would be the best test of small-study (publication bias) and decline effects (time-lag bias) in most meta-analytic datasets. For our data, we will run a multi-moderator phylogenetic multilevel meta-regression including the effect sizes’ standard errors, the year of publication (mean-centred) and a moderator originally included in Garamszegi et al. (2012), ‘captivity status’ (CaptivityC). Although Garamszegi et al. (2012) included other moderators in their model (i.e. species, taxonomic class, spatial overlap, age, sex and season), we decided to focus only on those moderators that were available for the entire dataset (i.e. no NA’s or missing data, see Table 2 in Garamszegi et al. 2012), and we also excluded ‘species’ (and ‘taxonomic class’) since species effects are already captured as a random effect and correlation matrix in our phylogenetic approach.

# Application of Equation 24 from the main manuscript
publication.bias.model.r.all.se <- rma.mv(yi, vi,
                                          mods=~1+
                                            sei+
                                            year.c+
                                            CaptivityC,   
                                          random=list(~ 1 | Species.updated, # phylo effect
                                                      ~ 1 | Species, # non-phylo effect
                                                      ~ 1 | study, 
                                                      ~ 1 | obsID), 
                                          R = list(Species.updated = phylo_cor), #phylogenetic relatedness
                                          method="REML",
                                          test="t", # using t dist rather than z
                                          data=dataset.r)

#summary(publication.bias.model.r.all.se)

# extracting the mean and 95% confidence intervals
estimates.publication.bias.model.r.all.se <- estimates.CI(publication.bias.model.r.all.se)

The all-in publication bias test agrees with what we observed in the uni-moderator meta-regressions above (sections S4.1.4.1 and S4.1.4.2). First, the multi-moderator meta-regression shows a statistically significant slope for the moderator ‘SE’ (slope = 0.12, 95% CI = [-0.09,0.33]; Figure S4.4), showing evidence of small-study effects. In other words, the largest effect sizes in the dataset tend to be those with the lowest precision (i.e. larger uncertainty; Figure S4.4). This result agrees with the findings originally reported in Garamszegi et al. (2012), where the authors found evidence of publication bias after applying a simple correlation method proposed by Begg and Mazumdar (1994) and the trim-and-fill method (Duval and Tweedie 2000a,b) - although bear in mind that we do not recommend to use those simpler methods for meta-analytic datasets with multiple levels of non-independence and high heterogeneity (more in the main text; see alternative in section S5). Second, the all-in publication bias test also confirms that there is no evidence of decline effects in the data since the slope of the moderator ‘year of publication’ was again indistinguishable from zero (slope = 0.82, 95% CI = [0.03,1.61]; Figure S4.5). Overall, the moderators included in this multi-moderator meta-regression explained a total of 16.5% (i.e. R2marginal) of the heterogeneity observed in the meta-analytic model (see Table S4.1).

Figure S4.4
# predicting effect sizes for a range of SE from the minimum observed in the data to the maximum observed in data, while year is kept at its mean value, in this case 0 since year was mean-centred
# condition on FC
predict.publication.bias.model.r.all.se.plot.1 <- predict(publication.bias.model.r.all.se,
                                                          newmods=cbind(seq(min(dataset.r$sei),
                                                                            max(dataset.r$sei),
                                                                            0.005),
                                                                        c(0), 0, 0, 0, 0))

newdat <- data.frame(sei=seq(min(dataset.r$sei),
                             max(dataset.r$sei),
                             0.005),
                     fit=predict.publication.bias.model.r.all.se.plot.1$pred,
                     upper=predict.publication.bias.model.r.all.se.plot.1$ci.ub,
                     lower=predict.publication.bias.model.r.all.se.plot.1$ci.lb,
                     stringsAsFactors=FALSE)

xaxis <- dataset.r$sei
yaxis <- dataset.r$yi

plot(xaxis,yaxis,
     type="n",
     ylab="",
     xlab="",
     xaxt="n",
     yaxt="n",
     ylim=c(-2.25,2.25),
     xlim=c(0,1))

abline(a=0,b=0, lwd=1, lty=1)

axis(1,at=seq(0,1,0.1),
     cex.axis=0.8,tck=-0.02)

axis(2,
     at=round(seq(-2.5,2.25,0.5),1),
     cex.axis=0.8,las=2,tck=-0.02)

title(xlab = "standard error (SE)", 
      ylab = "effect size (Zr)",
      line = 2.75, cex.lab=1.4)

points(xaxis,yaxis,
       bg=rgb(0,0,0, 0.1),
       col=rgb(0,0,0, 0.2),
       pch=21,
       cex=1)

lines(newdat$sei, newdat$fit, lwd=2.75,col="darkorchid4") 

polygon(c(newdat$sei,rev(newdat$sei)),
        c(newdat$lower,rev(newdat$upper)),
        border=NA,col=rgb(104/255,34/255,139/255, 0.5))
Effect sizes with larger standard errors tend to be larger, providing evidence of small-study effects in the meta-analytic dataset. The solid line represents the model estimate and the shading shows its 95% confidence intervals.

Effect sizes with larger standard errors tend to be larger, providing evidence of small-study effects in the meta-analytic dataset. The solid line represents the model estimate and the shading shows its 95% confidence intervals.



Figure S4.5
# predicting effect sizes for a range of years from the minimum observed in the data to the maximum observed in data, while SE is kept at its mean value. Keep in mind that alternative ways could be used, for example, one could use median-centring rather than mean-centring.
# conditioned on FC
predict.publication.bias.model.r.all.se.plot.2 <- predict(publication.bias.model.r.all.se,
                                                          newmods=cbind(mean(dataset.r$sei),
                                                                        seq(min(dataset.r$year.c),
                                                                            max(dataset.r$year.c),
                                                                            0.25),0, 0,0,0))




newdat <- data.frame(year=seq(min(dataset.r$year),
                              max(dataset.r$year),
                              0.25),
                     fit=predict.publication.bias.model.r.all.se.plot.2$pred,
                     upper=predict.publication.bias.model.r.all.se.plot.2$ci.ub,
                     lower=predict.publication.bias.model.r.all.se.plot.2$ci.lb,
                     stringsAsFactors=FALSE)

xaxis <- dataset.r$year
yaxis <- dataset.r$yi
cex.study <- (1/dataset.r$sei)/4

plot(xaxis,yaxis,
     type="n",
     ylab="",
     xlab="",
     xaxt="n",
     yaxt="n",
     ylim=c(-2.25,2.25),
     xlim=c(min(dataset.r$year),max(dataset.r$year)))

abline(a=0,b=0, lwd=1, lty=1)

axis(1,at=seq(min(dataset.r$year),max(dataset.r$year),5),
     cex.axis=0.8,tck=-0.02)

axis(2,
     at=round(seq(-2.5,2.25,0.5),1),
     cex.axis=0.8,las=2,tck=-0.02)

title(xlab = "year of publication", 
      ylab = "effect size (Zr)",
      line = 2.75, cex.lab=1.4)

points(xaxis,yaxis,
       bg=rgb(0,0,0, 0.1),
       col=rgb(0,0,0, 0.2),
       pch=21,
       cex=cex.study)

lines(newdat$year, newdat$fit, lwd=2.75,col="darkorchid4") 

polygon(c(newdat$year,rev(newdat$year)),
        c(newdat$lower,rev(newdat$upper)),
        border=NA,col=rgb(104/255,34/255,139/255, 0.5))
The overall effect size has not changed over time. The solid line represents the model estimate, the shading shows its 95% confidence intervals and individual effect sizes are scaled by their precision (1/SE).

The overall effect size has not changed over time. The solid line represents the model estimate, the shading shows its 95% confidence intervals and individual effect sizes are scaled by their precision (1/SE).



S4.1.5: Adjusting overall effect size estimates for Zr

Once we have confirmed that there is evidence of small-study effects (see above), the next step in our suggested two-step approach is to calculate the adjusted overall effect size, that is, the overall effect once we account for publication bias (see the main text).

In a simpler meta-regression model (only with the moderator ‘SE’), the best estimate for the adjusted overall effect size would be the intercept of that model, when the intercept is not significant (i.e. Stanley and Doucouliagos 2012, 2014; more in the main text and also see our corrigendum). Note that Stanley (2017) suggests to use the significance level of 10% to assess the intercept’s statistical significance. In a complex model with a categorical variables, it is difficult to decide what is the intercept. Nonetheless, the models above suggest that there are indications of some effects at least in some categories. Therefore, in the all-in publication bias test, our approach to estimate the adjusted overall effect is to fit a similar multi-moderator regression to the one above but including the effect sizes’ sampling variances (SV or vi) instead of their standard errors as a moderator. This is because when there is an (true) overall effect, the use of ‘SV’ leads to an adjusted overall effect that is less downward biased than when using ‘SE’ (more in the main text; Stanley and Doucouliagos 2012, 2014). Note that when there is weak evidence for an overall effects, fitting ‘SE’ gives the best estimate of adjusted effects.

What moderators one should include in this version of the all-in publication bias test depends on what we want the adjusted overall effect size to reflect. Keep in mind that one of the purposes of including moderators in this all-in test is to explain as much heterogeneity as possible. We are going to add one more moderator ‘captivity status’ (CaptivityC), which has 5 levels (we refer to it as the full model). We will obtain marginalized means, using the R package emmeans. Importantly, we should keep in mind that publication bias tests should be treated as sensitivity analyses to test the robustness of results from the original analysis (Noble et al., 2017). Importantly, none of the estimated adjusted overall effects should be treated as the real overall value if publication bias did not exist; after all, we can never be sure of what has not been published.

# full model
publication.bias.model.r.v.1 <- rma.mv(yi, vi,
                                       mods=~ 1 + vi + 
                                         year.c +
                                         CaptivityC, # take Class - that is already a part of phylo   
                                       random=list(~ 1 | Species.updated, # phylo effect
                                                   ~ 1 | Species, # non-phylo effect
                                                   ~ 1 | study, 
                                                   ~ 1 | obsID), 
                                       R = list(Species.updated = phylo_cor), #phylogenetic relatedness
                                       method="REML",
                                       test="t", # using t dist rather than z
                                       data=dataset.r)

# preparation to get marginalized mean (when vi = 0 and year.c = 0)
res.publication.bias.model.r.v.1 <- qdrg(object = publication.bias.model.r.v.1, data = dataset.r, at = list(vi = 0, year.c = 0))
# marginalized overall mean at vi = 0 and year.c = 0; also weights = "prop" or "cells" average things over proportionally. if not specified, all groups (levels) get the same weights
overall.res.publication.bias.model.r.v.1 <- emmeans(res.publication.bias.model.r.v.1, specs = ~1, df = publication.bias.model.r.v.1$ddf, weights = "prop") # using effect size - 7 
# marginalised means for different levels for CaptivityC
mm.publication.bias.model.r.v.1 <- emmeans(res.publication.bias.model.r.v.1, specs = "CaptivityC", df = publication.bias.model.r.v.1$ddf)

# comparing results without correcting for publication bias
publication.bias.model.r.v.1b <- rma.mv(yi, vi,
                                        mods=~ -1 +
                                          CaptivityC, # take Class - that is already a part of phylo   
                                        random=list(~ 1 | Species.updated, # phylo effect
                                                    ~ 1 | Species, # non-phylo effect
                                                    ~ 1 | study, 
                                                    ~ 1 | obsID), 
                                        R = list(Species.updated = phylo_cor), #phylogenetic relatedness
                                        method="REML",
                                        test="t", # using t dist rather than z
                                        data=dataset.r)

# extracting the mean and 95% confidence intervals
estimates.publication.bias.model.r.v.1 <- estimates.CI2(mm.publication.bias.model.r.v.1)
estimates.publication.bias.model.r.v.1b <- estimates.CI(publication.bias.model.r.v.1b)

The full model provided an adjusted overall effect size that was slightly smaller (adjusted effect = 0.01, 95% CI = [0.03,97]) than that obtained by the multilevel meta-analysis (unadjusted effect = 0.29, 95% CI = [0.17,0.41]; more in section S4.1.3), highlighting the downward correction of the overall effect after accounting for publication bias. The full model also showed slightly smaller effects for all levels of the categorical factor ‘captivity status’ than the unadjusted model (Table S4.2).

# creating a table to show the results of model 2
table.comparing.captivity.levels <- merge(estimates.publication.bias.model.r.v.1,
                                          estimates.publication.bias.model.r.v.1b,
                                          by="estimate",
                                          all.x=T)

# rounding estimates
table.comparing.captivity.levels <- table.comparing.captivity.levels %>% mutate(across(where(is.numeric), round, 2))


table.comparing.captivity.levels <- data.frame(captivity.level = table.comparing.captivity.levels[,1],
                                               adjusted.mean=table.comparing.captivity.levels[,2],               adjusted.CI=paste0("[",table.comparing.captivity.levels[,3],",",table.comparing.captivity.levels[,4],"]"),
                                               unadjusted.mean=table.comparing.captivity.levels[,5],                                               unadjusted.CI=paste0("[",table.comparing.captivity.levels[,6],",",table.comparing.captivity.levels[,7],"]"))

table.comparing.captivity.levels[,1] <- c("FC","FW","WCT","WCT & FC", "WCT & FW")

# creating a formatted table using the R package 'gt'
table.model.r.captivity.gt <- table.comparing.captivity.levels %>% 
  gt() %>% 
  cols_label(captivity.level=md("**Captivity status**"),
             adjusted.mean=md("**Adjusted mean**"),
             adjusted.CI=md("**Adjusted 95% CI**"),
             unadjusted.mean=md("**Unadjusted mean**"),
             unadjusted.CI=md("**Unadjusted 95% CI**")) %>%
  cols_align(align = "center")

table.model.r.captivity.gt
Captivity status Adjusted mean Adjusted 95% CI Unadjusted mean Unadjusted 95% CI
FC 0.00 [0,0] 0.28 [0.15,0.41]
FW -0.01 [-0.24,0.22] 0.27 [0.05,0.49]
WCT 0.03 [-0.12,0.18] 0.30 [0.16,0.45]
WCT & FC 0.18 [-0.17,0.53] 0.43 [0.09,0.78]
WCT & FW -0.12 [-0.39,0.15] 0.16 [-0.12,0.43]

Table S4.2. Results for all levels of the moderator ‘captivity status’, both adjusted and unadjusted for publication bias using the all-in publication bias test (multi-moderator meta-regression). Estimates are presented as standardized effect sizes using Fisher’s transformation of the correlation coefficient (i.e. Zr).



S4.2: Mean differences between two groups (lnRR and SMD)

For our second worked example, we use the meta-analytic dataset provided by Murphy et al. 2013. This meta-analysis tested whether human-caused disturbances led a change in species richness across both terrestrial and aquatic biomes, using the log response ratio (i.e., lnRR). Briefly, the authors found that human-mediated disturbances led to a statistically significant 18.3% decline in species richness across five anthropogenic disturbances (species invasions, nutrient addition, temperature increase, habitat loss or fragmentation, and land-use change). Here, we use this dataset to show how to use multilevel meta-regression approach to both detect and adjust for publication bias.

# importing dataset with mean differences
dataset.original.mean.diff<-read_excel(here("data", "ft027.xlsx"), col_names = TRUE)

#names(dataset.original.mean.diff)
#str(dataset.original.mean.diff)


# lnRR
dataset.rr  <- escalc(measure = "ROM",
                      m1i = T_mean,
                      m2i = C_mean,
                      sd1i = T_sd,
                      sd2i = C_sd,
                      n1i = T_N,
                      n2i = C_N,
                      data = dataset.original.mean.diff,
                      append = T)

dataset.smd <- escalc(measure = "SMD",
                      m1i = T_mean,
                      m2i = C_mean,
                      sd1i = T_sd,
                      sd2i = C_sd,
                      n1i = T_N,
                      n2i = C_N,
                      data = dataset.original.mean.diff,
                      append = T)

#Warning message:
#Some 'yi' and/or 'vi' values equal to +-Inf. Recoded to NAs. 

# clean NA
dataset.rr <- dataset.rr[!is.na(dataset.rr$yi) & dataset.rr$vi != 0, ]

dataset.smd <- dataset.smd[!is.na(dataset.smd$yi) & dataset.smd$vi != 0, ]

S4.2.1: Exploratory data analysis

Before analysis, it is important to explore the meta-analytic dataset. To identify outliers (which are sometimes caused by data extraction errors, or typos in the data source), Figure S4.6 shows funnel plots with the standard error and the inverse of the standard error (i.e. precision) in the y-axes (Figure S4.6).

Figure S4.6
# we find some strange data in SMD and lnRR 
par(mfrow = c(1, 2))
funnel(dataset.rr$yi, dataset.rr$vi, yaxis="seinv",
       #xlim = c(-3, 3),
       ylab = "Precision (1/SE)",
       xlab = "Effect size (lnRR)") 
funnel(dataset.smd$yi, dataset.smd$vi, yaxis="seinv",
       #xlim = c(-3, 3),
       ylab = "Precision (1/SE)",
       xlab = "Effect size (SMD)") 
Funnel plots with 1/SE for lnRR (left-hand side) and SMD (right-hand side) as measures of uncertainty to visualise outliers in the meta-analytic dataset.

Funnel plots with 1/SE for lnRR (left-hand side) and SMD (right-hand side) as measures of uncertainty to visualise outliers in the meta-analytic dataset.

Data exploration found usual outliers in both the lnRR and SMD data. For this example we have removed these outliers. However, for a real meta-analysis, the source of those outliers should be investigated, and the decision about whether or not to remove unusual effect sizes should be justified and reported in the paper. Next, we checked the funnel plots again (Figure S4.7). This time, the funnel plots seemed to be more normal.

Figure S4.7

Funnel plots with 1/SE as the measure of uncertainty for lnRR (left-hand side) and SMD (right-hand side) after removing outliers in the meta-analytic dataset.

# removing outliers
dataset.rr <- dataset.rr[dataset.rr$vi != min(dataset.rr$vi), ]

dataset.smd <- dataset.smd[dataset.smd$yi != min(dataset.smd$yi),]


par(mfrow = c(1, 2))
funnel(dataset.rr$yi, dataset.rr$vi, yaxis="seinv",
       #xlim = c(-3, 3),
       ylab = "Precision (1/SE)",
       xlab = "Effect size (lnRR)") 
funnel(dataset.smd$yi, dataset.smd$vi, yaxis="seinv",
       #xlim = c(-3, 3),
       ylab = "Precision (1/SE)",
       xlab = "Effect size (SMD)") 
Funnel plots with effective sample size as the measure of uncertainty for lnRR (left-hand side) and SMD (right-hand side).

Funnel plots with effective sample size as the measure of uncertainty for lnRR (left-hand side) and SMD (right-hand side).

To avoid ‘artefactual’ funnel asymmetry, we suggest using the “effective sample size” rather than SE for mean difference effect sizes, such as lnRR and SMD. Let’s check the funnel plots (Figure S4.8) which use effective sample size on the y-axis.

Figure S4.8
# calculating "effective sample size" to account for unbalanced sampling, for SMD and lnRR (e_n, hereafter, see Equation 25 from the main manuscript)

dataset.rr$e_n <- with(dataset.rr, (4*(C_N*T_N)) / (C_N + T_N))
dataset.smd$e_n <- with(dataset.smd, (4*(C_N*T_N)) / (C_N + T_N))

#using effective sampling size
par(mfrow = c(1, 2))
funnel(dataset.rr$yi, dataset.rr$vi, ni = dataset.rr$e_n, yaxis="ni",
       #xlim = c(-3, 3),
       ylab = "Effective sample size",
       xlab = "Effect size (lnRR)") 
funnel(dataset.smd$yi, dataset.smd$vi, ni = dataset.smd$e_n, yaxis="ni",
       #xlim = c(-3, 3),
       ylab = "Effective sample size",
       xlab = "Effect size (SMD)") 

Comparing the funnel plots using effective sample size (Figure 4.8) with 1/SE (Figure 4.7) we notice that data points in funnel plots with effective sample sizes looked more ‘scattered’, whereas data points in funnel plots with 1/SE looked more ‘crowded’. This is because SE is correlated more strongly with the effect size than effective sample size, owing to similarities between the effect size and sampling variance equations for both lnRR and SMR (i.e., compare equations 1 and 2, and equations 3 and 4, in the main text). For example, the SMD’s variance has the square of the point estimate (i.e. SMD) in its equation, which leads to a correlation between SMDs and sampling SE. This can result in ‘artefactual’ funnel asymmetry.

S4.2.2: Multilevel meta-analysis

Next, we showcase how to test for the presence of publication bias using the multilevel meta-regression method suggested in the main text. First, we re-analyse the dataset using a multilevel meta-analytic (intercept-only) model and make corresponding funnel plot showing the overall effect or meta-analytic mean.

# creating a unit-level random effect to model residual variance in metafor
dataset.rr$obsID <- 1:nrow(dataset.rr)
dataset.smd$obsID <- 1:nrow(dataset.smd)

# running multilevel intercept-only meta-analytic model
meta.analysis.model.rr <- rma.mv(yi, vi,
                                 mods = ~ 1,
                                 random = list(~1  | Disturbance_category,
                                               ~ 1 | paperID, 
                                               ~ 1 | obsID),
                                 method = "REML",
                                 test = "t", 
                                 data = dataset.rr)


meta.analysis.model.smd <- rma.mv(yi, vi,
                                  mods = ~ 1,
                                  random = list(~1  | Disturbance_category,
                                                ~ 1 | paperID, 
                                                ~ 1 | obsID),
                                  method = "REML",
                                  test = "t", 
                                  data = dataset.smd)

# extracting the mean, 95% confidence intervals and 95% prediction intervals
 metaanalytic.mean.model.rr <- predict(meta.analysis.model.rr, digits=3)
metaanalytic.mean.model.smd <- predict(meta.analysis.model.smd, digits=3)

# estimating relative heterogeneity I2
 I2.model.rr <- i2_ml(meta.analysis.model.rr)
I2.model.smd <- i2_ml(meta.analysis.model.smd)

# creating a table to show the heterogeneity estimates
table.model.rr <- data.frame(n=length(unique(dataset.rr$paperID)),
                             k=nrow(dataset.rr),
                             mean=round(metaanalytic.mean.model.rr[[1]],2),
                             CI=paste0("[",round(metaanalytic.mean.model.rr[[3]],2),",",round(metaanalytic.mean.model.rr[[4]],2),"]"),
                             PI=paste0("[",round(metaanalytic.mean.model.rr[[5]],2),",",round(metaanalytic.mean.model.rr[[6]],2),"]"),
                             I2_obsID=round(I2.model.rr[[4]],1),
                             I2_paperID=round(I2.model.rr[[3]],1),
                             I2_Disturbance=round(I2.model.rr[[2]],1),
                             I2_total=round(I2.model.rr[[1]],1))

rownames(table.model.rr) <- NULL

#write.csv(table.model.RR, "./table/table.model.RR.csv", row.names = FALSE)

table.model.smd <- data.frame(n=length(unique(dataset.smd$paperID)),
                             k=nrow(dataset.smd),
                             mean=round(metaanalytic.mean.model.smd[[1]],2),
                             CI=paste0("[",round(metaanalytic.mean.model.smd[[3]],2),",",round(metaanalytic.mean.model.smd[[4]],2),"]"),
                             PI=paste0("[",round(metaanalytic.mean.model.smd[[5]],2),",",round(metaanalytic.mean.model.smd[[6]],2),"]"),
                             I2_obsID=round(I2.model.smd[[4]],1),
                             I2_paperID=round(I2.model.smd[[3]],1),
                             I2_Disturbance=round(I2.model.smd[[2]],1),
                             I2_total=round(I2.model.smd[[1]],1))

rownames(table.model.smd) <- NULL


#write.csv(table.model.SMD, "./table/table.model.SMD.csv", row.names = FALSE)

# creating a formatted table using the R package 'gt'
table.model.rr.gt <- table.model.rr %>% 
  gt::gt() %>% 
  cols_label(n=md("**n**"),
             k=md("**k**"),
             mean=md("**Meta-analytic mean**"),
             CI=md("**95% CI**"),
             PI=md("**95% PI**"),
             I2_obsID=md("***I*<sup>2</sup><sub>residual</sub> (%)**"),
             I2_paperID=md("***I*<sup>2</sup><sub>study</sub> (%)**"),
             I2_Disturbance=md("***I*<sup>2</sup><sub>Disturbance</sub> (%)**"),
             I2_total=md("***I*<sup>2</sup><sub>total</sub> (%)**")) %>%
  cols_align(align = "center") %>%
  tab_source_note(source_note = md("n = number of studies; k = number of effects; CI = confidence interval; PI = prediction interval; *I*<sup>2</sup> = heterogeneity"))

table.model.rr.gt
n k Meta-analytic mean 95% CI 95% PI I2residual (%) I2study (%) I2Disturbance (%) I2total (%)
243 325 -0.16 [-0.24,-0.09] [-0.89,0.56] 57.9 32.7 4 94.6
n = number of studies; k = number of effects; CI = confidence interval; PI = prediction interval; I2 = heterogeneity
table.model.smd.gt <- table.model.smd %>% 
  gt() %>% 
  cols_label(n=md("**n**"),
             k=md("**k**"),
             mean=md("**Meta-analytic mean**"),
             CI=md("**95% CI**"),
             PI=md("**95% PI**"),
             I2_obsID=md("***I*<sup>2</sup><sub>residual</sub> (%)**"),
             I2_paperID=md("***I*<sup>2</sup><sub>study</sub> (%)**"),
             I2_Disturbance=md("***I*<sup>2</sup><sub>Disturbance</sub> (%)**"),
             I2_total=md("***I*<sup>2</sup><sub>total</sub> (%)**")) %>%
  cols_align(align = "center") %>%
  tab_source_note(source_note = md("n = number of studies; k = number of effects; CI = confidence interval; PI = prediction interval; *I*<sup>2</sup> = heterogeneity"))  

table.model.smd.gt
n k Meta-analytic mean 95% CI 95% PI I2residual (%) I2study (%) I2Disturbance (%) I2total (%)
240 321 -0.49 [-0.64,-0.35] [-2.54,1.55] 27.7 57.3 0 85
n = number of studies; k = number of effects; CI = confidence interval; PI = prediction interval; I2 = heterogeneity

Table S4.2 Results of the multilevel intercept-only meta-analysis testing the effects of human-caused disturbances on changes in species richness across both terrestrial and aquatic biomes. Estimates are presented as standardized effect sizes using the log response ratio (i.e. lnRR, top) and standardized mean difference (i.e. SMD, bottom).



S4.2.3: Publication bias tests with mulitlevel meta-regression

S4.2.3.1: Meta-regression with effective sampling size (uni-moderator)

To test for publication bias (evidence of small-study effects), we first fitted a uni-moderator multilevel meta-regression including the square root of the inverse of effective sample size \(\sqrt{\frac{1}{\tilde{n}}}\) (Equation 26) as the only moderator (see Equation 27 from the main text). This meta-regression will provide some information about the existence of small-study effects (i.e. asymmetry in the distribution of effect sizes) after accounting for non-independence. However, as we explained in main text, the best evidence comes from the approach which models both heterogeneity and non-independence, by using a multi-moderator multilevel meta-regression model that includes all the important moderators (see all-in publication bias test described in section S4.2.4.3).

# calculating the inverse of the "effective sample size" to account for unbalanced sampling, for SMD and lnRR (see Equation 25 from the main manuscript)

dataset.rr$inv_n_tilda <-  with(dataset.rr, (C_N + T_N)/(C_N*T_N))
dataset.rr$sqrt_inv_n_tilda <-  with(dataset.rr, sqrt(inv_n_tilda))

dataset.smd$inv_n_tilda <- with(dataset.smd, (C_N + T_N)/(C_N*T_N))
dataset.smd$sqrt_inv_n_tilda <- with(dataset.smd, sqrt(inv_n_tilda))

# Application of Equation 27 from the main manuscript
publication.bias.model.rr.srin <- rma.mv(yi, vi,
                                         mods= ~ 1 + sqrt_inv_n_tilda,
                                         random=list(~ 1 | Disturbance_category,
                                                     ~ 1 | obsID, 
                                                     ~ 1 | paperID),
                                         method="REML",
                                         test = "t", 
                                         data=dataset.rr)

publication.bias.model.smd.srin <- rma.mv(yi, vi,
                                          mods= ~ 1 + sqrt_inv_n_tilda,
                                          random=list(~ 1 | Disturbance_category,
                                                      ~ 1 | obsID, 
                                                      ~ 1 | paperID),
                                          method="REML",
                                          test = "t", 
                                          data=dataset.smd)

# extracting the mean and 95% confidence intervals
estimates.publication.bias.model.rr.srin <- estimates.CI(publication.bias.model.rr.srin)

estimates.publication.bias.model.smd.srin <- estimates.CI(publication.bias.model.smd.srin)

Effect sizes with larger uncertainty [larger sqrt(inv_n_tilda)] tend to be larger (i.e. small-study effects) as indicated because the statistically significant slope of the moderator ‘sqrt_inv_n_tilda’ for lnRR (slope = -0.26, 95% CI = [-0.49,-0.03]; R2marginal = 2.3%) and SMD (slope = -0.8, 95% CI = [-1.56,-0.03]; R2marginal = 2.3%). In S4.2.3.3, we will use all-in publication bias test (multi-moderator meta-regression)see whether the small-study effects exist after accounting for some of the heterogeneity present in the data.

S4.2.3.2: Time-lag bias test (uni-moderator)

To test for time-lag bias (or the decline effect), we include the year of publication (mean-centred) as a single moderating variable (see Equation 23 from the main text).

# mean-centring year of publication to help with interpretation, particularly in S4.1.4.3.
dataset.rr$year.c <- as.vector(scale(dataset.rr$year, scale = F))
dataset.smd$year.c <- as.vector(scale(dataset.smd$year, scale = F))

# Application of Equation 23 from the main manuscript
publication.bias.model.rr.timelag <- rma.mv(yi, vi,
                                            mods= ~ 1 + year.c,
                                            random=list(~ 1 | Disturbance_category, 
                                                        ~ 1 | obsID, 
                                                        ~ 1 | paperID),
                                            method="REML",
                                            test = "t", 
                                            data=dataset.rr)

publication.bias.model.smd.timelag <- rma.mv(yi, vi,
                                             mods= ~ 1 + year.c,
                                             random=list(~ 1 | Disturbance_category,
                                                         ~ 1 | obsID, 
                                                         ~ 1 | paperID),
                                             method="REML",
                                             test = "t", 
                                             data=dataset.smd)

# extracting the mean and 95% confidence intervals
estimates.publication.bias.model.rr.timelag <- estimates.CI(publication.bias.model.rr.timelag)
estimates.publication.bias.model.smd.timelag <- estimates.CI(publication.bias.model.smd.timelag)

According to this uni-moderator meta-regression, there is an indication of decline effects since the slope of the moderator ‘year of publication’ is close to statistical significance for lnRR (slope = 0.01, 95% CI = [0,0.02]; R2marginal = 1.6%) and SMD (slope = 0.03, 95% CI = [0,0.06]; R2marginal = 1.6%).

S4.2.3.3: All-in publication bias test (multiple moderators)

To get the best evidence of small-study effects and time-lag bias, we run a multi-moderator meta-regression including the square of inverse of effective sample size, the year of publication (mean-centred) and the study approach (either experimental or observational; a moderator originally included in Murphy et al. 2013).

# preparing the moderators that need to be included in a meta-regression that also contains a  moderator with the standard errors of the effect sizes and the year of publication

# Application of Equation 29 from the main manuscript
publication.bias.model.rr.all.srin <- rma.mv(yi, vi,
                                                 mods= ~ -1 + sqrt_inv_n_tilda + 
                                                   year.c + 
                                                   Experimental.or.Observational.,
                                                 random=list(
                                                             ~ 1 | Disturbance_category,
                                                             ~ 1 | obsID, 
                                                             ~ 1 | paperID),
                                                 method="REML",
                                                 test = "t", 
                                                 data=dataset.rr,
                                                 control=list(optimizer="optim", optmethod="Nelder-Mead"))



publication.bias.model.smd.all.srin <- rma.mv(yi, vi,
                                                 mods= ~ -1 + sqrt_inv_n_tilda + 
                                                   year.c + 
                                                   Experimental.or.Observational.,
                                                 random=list(
                                                           ~ 1 | Disturbance_category,
                                                           ~ 1 | obsID, 
                                                           ~ 1 | paperID),
                                                 method="REML",
                                                 test = "t", 
                                                 data=dataset.smd,
                                                 control=list(optimizer="optim", optmethod="Nelder-Mead"))


# extracting the mean and 95% confidence intervals
estimates.publication.bias.model.rr.all.srin <- estimates.CI(publication.bias.model.rr.all.srin)
estimates.publication.bias.model.smd.all.srin <- estimates.CI(publication.bias.model.smd.all.srin)

The all-in publication bias test is similar to the uni-moderator meta-regressions above for small-study effects (sections S4.2.4.1) but had some differences for time-lag effects (S4.2.4.2).

First, the multi-moderator meta-regression show a statistically significant slope for the moderator ‘sqrt_inv_n_tilda’ (slope for lnRR = -0.25, 95% CI = [-0.47,-0.03]; Figure S4.9) and (slope for SMD = -0.94, 95% CI = [-1.72,-0.15]; Figure S4.10), confirming evidence of small-study effects. Note that Murphy et al. (2013) originally reported no funnel asymmetry from visual inspection, however, we do not recommend using this method for meta-analytic datasets with multiple levels of non-independence and high heterogeneity.

Second, the all-in publication bias test show no evidence of decline effects for lnRR since the moderator ‘year of publication’ is indistinguishable from zero (slope = 0.01, 95% CI = [0,0.02]; Figure S4.12). However, the effect size SMD tend to show evidence of decline effects, as the slope of publication year is close to statistical significance (slope = 0.03, 95% CI = [0,0.06]; Figure S4.13).

Figure S4.9
# predicting effect sizes for a range of sqrt(inv_n_tilda) from the minimum observed in the data to the maximum observed in data, while year is kept at its mean value, in this case 0 since year was mean-centred
# conditioned on observational studies
predict.publication.bias.model.rr.all.srin.plot.1 <- 
predict(publication.bias.model.rr.all.srin, newmods=cbind(seq(min(dataset.rr$sqrt_inv_n_tilda), max(dataset.rr$sqrt_inv_n_tilda), length.out=324), c(0), c(0), 1))


newdat <- data.frame(sei= seq(min(dataset.rr$sqrt_inv_n_tilda), max(dataset.rr$sqrt_inv_n_tilda), length.out=324),
                     fit=predict.publication.bias.model.rr.all.srin.plot.1$pred,
                     upper=predict.publication.bias.model.rr.all.srin.plot.1$ci.ub,
                     lower=predict.publication.bias.model.rr.all.srin.plot.1$ci.lb,
                     stringsAsFactors=FALSE)

xaxis <- dataset.rr$sqrt_inv_n_tilda
yaxis <- dataset.rr$yi


plot(xaxis,yaxis,
     type="n",
     ylab="",
     xlab="",
     xaxt="n",
     yaxt="n"
     )
abline(a=0,b=0, lwd=1, lty=1)
axis(1,at=seq(0,1.6,0.2),
     cex.axis=0.8,tck=-0.02)
axis(2,
     at=round(seq(-3,2,0.5),1),
     cex.axis=0.8,las=2,tck=-0.02)
title(xlab = "square root of inverse of effective sample size", 
      ylab = "effect size (lnRR)",
      line = 2.75, cex.lab=1.4)
points(xaxis,yaxis,
       bg=rgb(0,0,0, 0.1),
       col=rgb(0,0,0, 0.2),
       pch=21,
       cex=1)
lines(newdat$sei, newdat$fit, lwd=2.75,col="darkorchid4") 
polygon(c(newdat$sei,rev(newdat$sei)),
        c(newdat$lower,rev(newdat$upper)),
        border=NA,col=rgb(104/255,34/255,139/255, 0.5))
More negative estimates of lnRR are less certain (larger square root of inverse of effective sample size), showing evidence of small-study effects in the meta-analytic dataset. The solid line represents the model estimate and the shading shows its 95% confidence intervals.

More negative estimates of lnRR are less certain (larger square root of inverse of effective sample size), showing evidence of small-study effects in the meta-analytic dataset. The solid line represents the model estimate and the shading shows its 95% confidence intervals.

Figure S4.10
# predicting effect sizes for a range of SE from the minimum observed in the data to the maximum observed in data, while year is kept at its mean value, in this case 0 since year was mean-centred
#conditioned on observational studies
predict.publication.bias.model.smd.all.srin.plot.1 <- predict(publication.bias.model.smd.all.srin, newmods=cbind(seq(min(dataset.smd$sqrt_inv_n_tilda), max(dataset.smd$sqrt_inv_n_tilda), length.out=320), c(0), c(0), 1))


newdat <- data.frame(sei= seq(min(dataset.smd$sqrt_inv_n_tilda), max(dataset.smd$sqrt_inv_n_tilda), length.out=320),
                     fit=predict.publication.bias.model.smd.all.srin.plot.1$pred,
                     upper=predict.publication.bias.model.smd.all.srin.plot.1$ci.ub,
                     lower=predict.publication.bias.model.smd.all.srin.plot.1$ci.lb,
                     stringsAsFactors=FALSE)

xaxis <- dataset.smd$sqrt_inv_n_tilda
yaxis <- dataset.smd$yi
plot(xaxis,yaxis,
     type="n",
     ylab="",
     xlab="",
     xaxt="n",
     yaxt="n"
     )
abline(a=0,b=0, lwd=1, lty=1)
axis(1,at=seq(0,1.2,0.2),
     cex.axis=0.8,tck=-0.02)
axis(2,
     at=round(seq(-8,4,2),1),
     cex.axis=0.8,las=2,tck=-0.02)
title(xlab = "square root of inverse of effective sample size", 
      ylab = "effect size (SMD)",
      line = 2.75, cex.lab=1.4)
points(xaxis,yaxis,
       bg=rgb(0,0,0, 0.1),
       col=rgb(0,0,0, 0.2),
       pch=21,
       cex=1)
lines(newdat$sei, newdat$fit, lwd=2.75,col="darkorchid4") 
polygon(c(newdat$sei,rev(newdat$sei)),
        c(newdat$lower,rev(newdat$upper)),
        border=NA,col=rgb(104/255,34/255,139/255, 0.5))



Figure S4.11
# predicting effect sizes for a range of sqrt(inv_n_tilda) from the minimum observed in the data to the maximum observed in data, while year is kept at its mean value, in this case 0 since year was mean-centred
#conditioned on observational studies
predict.publication.bias.model.rr.all.srin.plot.2 <- 
predict(publication.bias.model.rr.all.srin, newmods=cbind(mean(dataset.rr$sqrt_inv_n_tilda),seq(min(dataset.rr$year.c), max(dataset.rr$year.c), length.out=324), c(0), 1))


newdat <- data.frame(year = seq(min(dataset.rr$year), max(dataset.rr$year), length.out=324),
                     fit=predict.publication.bias.model.rr.all.srin.plot.2$pred,
                     upper=predict.publication.bias.model.rr.all.srin.plot.2$ci.ub,
                     lower=predict.publication.bias.model.rr.all.srin.plot.2$ci.lb,
                     stringsAsFactors=FALSE)

xaxis <- dataset.rr$year
yaxis <- dataset.rr$yi
plot(xaxis,yaxis,
     type="n",
     ylab="",
     xlab="",
     xaxt="n",
     yaxt="n"
     )
abline(a=0,b=0, lwd=1, lty=1)
axis(1,at=seq(1989,2013,5),
     cex.axis=0.8,tck=-0.02)
axis(2,
     at=round(seq(-3,2,0.5),1),
     cex.axis=0.8,las=2,tck=-0.02)
title(xlab = "year of publication", 
      ylab = "effect size (lnRR)",
      line = 2.75, cex.lab=1.4)
points(xaxis,yaxis,
       bg=rgb(0,0,0, 0.1),
       col=rgb(0,0,0, 0.2),
       pch=21,
       cex=1)
lines(newdat$year, newdat$fit, lwd=2.75,col="darkorchid4") 
polygon(c(newdat$year,rev(newdat$year)),
        c(newdat$lower,rev(newdat$upper)),
        border=NA,col=rgb(104/255,34/255,139/255, 0.5))
The average effect, as measured by lnRR, did not statistically significantly change with time. The solid line represents the model estimate, the shading shows its 95% confidence intervals.

The average effect, as measured by lnRR, did not statistically significantly change with time. The solid line represents the model estimate, the shading shows its 95% confidence intervals.

Figure S4.12
# predicting effect sizes for a range of sqrt(inv_n_tilda) from the minimum observed in the data to the maximum observed in data, while year is kept at its mean value, in this case 0 since year was mean-centred
# conditioned observational studies
predict.publication.bias.model.smd.all.srin.plot.2 <- 
predict(publication.bias.model.smd.all.srin, newmods=cbind(mean(dataset.smd$sqrt_inv_n_tilda),seq(min(dataset.smd$year.c), max(dataset.smd$year.c), length.out=320), c(0), 1))


newdat <- data.frame(year= seq(min(dataset.smd$year), max(dataset.smd$year), length.out=320),
                     fit=predict.publication.bias.model.smd.all.srin.plot.2$pred,
                     upper=predict.publication.bias.model.smd.all.srin.plot.2$ci.ub,
                     lower=predict.publication.bias.model.smd.all.srin.plot.2$ci.lb,
                     stringsAsFactors=FALSE)

xaxis <- dataset.smd$year
yaxis <- dataset.smd$yi
plot(xaxis,yaxis,
     type="n",
     ylab="",
     xlab="",
     xaxt="n",
     yaxt="n"
     )
abline(a=0,b=0, lwd=1, lty=1)
axis(1,at=seq(1989,2013,5),
     cex.axis=0.8,tck=-0.02)
axis(2,
     at=round(seq(-8,4,2),1),
     cex.axis=0.8,las=2,tck=-0.02)
title(xlab = "year of publication", 
      ylab = "effect size (SMD)",
      line = 2.75, cex.lab=1.4)
points(xaxis,yaxis,
       bg=rgb(0,0,0, 0.1),
       col=rgb(0,0,0, 0.2),
       pch=21,
       cex=1)
lines(newdat$year, newdat$fit, lwd=2.75,col="darkorchid4") 
polygon(c(newdat$year,rev(newdat$year)),
        c(newdat$lower,rev(newdat$upper)),
        border=NA,col=rgb(104/255,34/255,139/255, 0.5))
The average effect, as measured by SMD, has declined, although non-signficant, over the timespan captured by this dataset. The solid line represents the model estimate, the shading shows its 95% confidence intervals.

The average effect, as measured by SMD, has declined, although non-signficant, over the timespan captured by this dataset. The solid line represents the model estimate, the shading shows its 95% confidence intervals.



S4.2.4: Adjusting overall effect size estimates for lnRR and SMD

In the main text we provide a two-step approach to calculate the bias-corrected overall effect size estimate. The rationale is that, when no uncertainty exists (theoretically), we can get the potential true effect from a multiple-moderator multilevel-model (i.e. all-in publication bias test, where the inclusion of moderator variables reduces heterogeneity). We add two more moderators Experimental.or.Observational. (2 levels) and Disturbance_category (10 levels; we refer to this model as the full model).

The models above do not provide strong evidence that there are a significant overall effect (or a significant intercept or at least, one group being significant at the alpha level at 10%, which translates to a t value of > ~1.65 in magnitude). However, the meta-regression model only with Experimental.or.Observational. provides good evidence that there are some overall effects. Therefore, here, we should try both scenarios: \(\sqrt(1/\tilde{n})\) and \(1/\tilde{n}\). The former provides the best estimate when there is no evidence that an overall effect exists or some groups have non-zero effects while the latter is best when there is such evidence.

# lnRR

# with sqrt(1/~n)
# preparation to get marginalized mean (when sqrt_inv_n_tilda = 0 and year.c = 0)
res.publication.bias.model.rr.v.0 <- qdrg(object = publication.bias.model.rr.all.srin, data = dataset.rr, at = list(inv_n_tilda = 0, year.c = 0))
# marginalized overall mean at inv_n_tilda = 0 and year.c = 0; also weights = "prop" or "cells" average things over proportionally. if not specified, all groups (levels) get the same weights
overall.res.publication.bias.model.rr.v.0 <- emmeans(res.publication.bias.model.rr.v.0, specs = ~1, df = publication.bias.model.rr.all.srin$ddf, weights = "prop") # using effect size - 7 
# marginalized means for different levels for Experimental.or.Observational.
mm.publication.bias.model.rr.v.0 <- emmeans(res.publication.bias.model.rr.v.0, specs = "Experimental.or.Observational.", df = publication.bias.model.rr.all.srin$ddf, weights = "prop")

# with 1/~n
# providing an adjusted effect for each level of CaptivityC
publication.bias.model.rr.v.1 <- rma.mv(yi, vi,
                                       mods=~-1+inv_n_tilda + 
                                         year.c +
                                         Experimental.or.Observational. + 
                                         Disturbance_category,  # this can be a random effect but placing this here to show how emmeans works
                                        random=list(
                                                   ~ 1 | obsID, 
                                                   ~ 1 | paperID),
                                                 method ="REML",
                                                   test = "t", 
                                                   data = dataset.rr,
                                                control = list(optimizer="optim", optmethod="Nelder-Mead"))

# preparation to get marginalized mean (when inv_n_tilda = 0 and year.c = 0)
res.publication.bias.model.rr.v.1 <- qdrg(object = publication.bias.model.rr.v.1, data = dataset.rr, at = list(inv_n_tilda = 0, year.c = 0))
# marginalized overall mean at inv_n_tilda = 0 and year.c = 0; also weights = "prop" or "cells" average things over proportionally. if not specified, all groups (levels) get the same weights
overall.res.publication.bias.model.rr.v.1 <- emmeans(res.publication.bias.model.rr.v.1, specs = ~1, df = publication.bias.model.rr.v.1$ddf, weights = "prop") # using effect size - 7 
# marginalized means for different levels for Experimental.or.Observational.
mm.publication.bias.model.rr.v.1 <- emmeans(res.publication.bias.model.rr.v.1, specs = "Experimental.or.Observational.", df = publication.bias.model.rr.v.1$ddf, weights = "prop")
# estiamted marginalised mean
#mm.publication.bias.model.r.v.1 <- emmeans(res.publication.bias.model.rr.v.1, specs = "Experimental.or.Observational.", df = publication.bias.model.rr.v.1$dfs, weights = "equal")

# model 3b: comparing results without correcting for publication bias
publication.bias.model.rr.v.1b <- rma.mv(yi, vi,
                                       mods=~-1+ Experimental.or.Observational., 
                                        random=list(
                                                   ~ 1 | obsID, 
                                                   ~ 1 | paperID),
                                                 method = "REML",
                                                   test = "t", 
                                                   data = dataset.rr,
                                                control = list(optimizer="optim", optmethod="Nelder-Mead"))

# extracting the mean and 95% confidence intervals
estimates.publication.bias.model.rr.v.0 <- estimates.CI2(mm.publication.bias.model.rr.v.0)
estimates.publication.bias.model.rr.v.1 <- estimates.CI2(mm.publication.bias.model.rr.v.1)
estimates.publication.bias.model.rr.v.1b <- estimates.CI(publication.bias.model.rr.v.1b)

# SMD
# with sqrt(1/~n)
# preparation to get marginalized mean (when sqrt_inv_n_tilda = 0 and year.c = 0)
res.publication.bias.model.smd.v.0 <- qdrg(object = publication.bias.model.smd.all.srin, data = dataset.smd, at = list(inv_n_tilda = 0, year.c = 0))
# marginalized overall mean at inv_n_tilda = 0 and year.c = 0; also weights = "prop" or "cells" average things over proportionally. if not specified, all groups (levels) get the same weights
overall.res.publication.bias.model.smd.v.0 <- emmeans(res.publication.bias.model.smd.v.0, specs = ~1, df = publication.bias.model.smd.all.srin$ddf, weights = "prop") # using effect size - 7 
# marginalized means for different levels for Experimental.or.Observational.
mm.publication.bias.model.smd.v.0 <- emmeans(res.publication.bias.model.smd.v.0, specs = "Experimental.or.Observational.", df = publication.bias.model.smd.all.srin$ddf, weights = "prop")

# model 3: providing an adjusted effect for each level of CaptivityC
publication.bias.model.smd.v.1 <- rma.mv(yi, vi,
                                       mods=~-1+ inv_n_tilda + 
                                         year.c +
                                         Experimental.or.Observational., 
                                        random=list(
                                                   ~ 1 | Disturbance_category,
                                                   ~ 1 | obsID, 
                                                   ~ 1 | paperID),
                                                 method = "REML",
                                                   test = "t", 
                                                   data = dataset.smd,
                                                control = list(optimizer="optim", optmethod="Nelder-Mead"))
# preparation to get marginalized mean (when inv_n_tilda = 0 and year.c = 0)
res.publication.bias.model.smd.v.1 <- qdrg(object = publication.bias.model.smd.v.1, data = dataset.smd, at = list(inv_n_tilda = 0, year.c = 0))
# marginalized overall mean at inv_n_tilda = 0 and year.c = 0; also weights = "prop" or "cells" average things over proportionally. if not specified, all groups (levels) get the same weights
overall.res.publication.bias.model.smd.v.1 <- emmeans(res.publication.bias.model.smd.v.1, specs = ~1, df = publication.bias.model.smd.v.1$ddf, weights = "prop") # using effect size - 7 
# marginalized means for different levels for Experimental.or.Observational.
mm.publication.bias.model.smd.v.1 <- emmeans(res.publication.bias.model.smd.v.1, specs = "Experimental.or.Observational.", df = publication.bias.model.smd.v.1$ddf, weights = "prop")


# model 3b: comparing results without correcting for publication bias
publication.bias.model.smd.v.1b <- rma.mv(yi, vi,
                                       mods=~-1+ Experimental.or.Observational.,   
                                        random=list(
                                                   ~ 1 | Disturbance_category,
                                                   ~ 1 | obsID, 
                                                   ~ 1 | paperID),
                                                 method = "REML",
                                                   test = "t", 
                                                   data = dataset.smd,
                                                control = list(optimizer="optim", optmethod="Nelder-Mead"))


# extracting the mean and 95% confidence intervals
estimates.publication.bias.model.smd.v.0 <- estimates.CI2(mm.publication.bias.model.smd.v.0)
estimates.publication.bias.model.smd.v.1 <- estimates.CI2(mm.publication.bias.model.smd.v.1)
estimates.publication.bias.model.smd.v.1b <- estimates.CI(publication.bias.model.smd.v.1b)

The full model with \(\sqrt(1/\tilde{n})\) provided an adjusted overall lnRR that was slightly larger in magnitude from the unadjusted estimate (adjusted effect = -0.19, 95% CI = [0.02,321]; unadjusted effect = -0.16, 95% CI = [-0.24,-0.09]; th model in section S4.2.2). This is unexpected as the adjusted estimate should be closer to zero than the unadjusted one). On the other hand, the model with \(1/\tilde{n}\) provided a smaller overall value as expected (adjusted effect = -0.09, 95% CI = [0.04,312]). . Given those, we conclude that it is probably more appropriate to take the adjusted estimates from the model with \(1/\tilde{n}\) than the model with \(\sqrt(1/\tilde{n})\). In Table S4.3, show that the estimates from the unadjusted model and the adjusted model with \(\sqrt(1/\tilde{n})\) while the adjusted model with \(\sqrt(1/\tilde{n})\) gave smaller estimates in magnitude, which should be expected for adjusted effects. We suggest that we use the estimates from the method with \(1/\tilde{n}\) (Adjusted mean 2 and Adjusted 95% CI 2).

# creating a table to show the results of model 2
table.comparing.Exp.or.Obs.levels0 <- merge(estimates.publication.bias.model.rr.v.0,
                                          estimates.publication.bias.model.rr.v.1,
                                          by="estimate",
                                          all.x=T)

table.comparing.Exp.or.Obs.levels <- merge(table.comparing.Exp.or.Obs.levels0,
                                          estimates.publication.bias.model.rr.v.1b,
                                          by="estimate",
                                          all.x=T)
# rounding estimates
table.comparing.Exp.or.Obs.levels <- table.comparing.Exp.or.Obs.levels %>% mutate_at(vars(mean.x, lower.x,upper.x,mean.y,lower.y,upper.y, mean,lower,upper), list(~round(., 2)))

table.comparing.Exp.or.Obs.levels <- data.frame(Exp.or.Obs.level = table.comparing.Exp.or.Obs.levels[,1],
                                               adjusted.mean1=table.comparing.Exp.or.Obs.levels[,2],               
                                               adjusted.CI1 = paste0("[",table.comparing.Exp.or.Obs.levels[,3],",",
                                                                    table.comparing.Exp.or.Obs.levels[,4],"]"),
                                               adjusted.mean2=table.comparing.Exp.or.Obs.levels[,5],               
                                               adjusted.CI2 = paste0("[",table.comparing.Exp.or.Obs.levels[,6],",",
                                                                    table.comparing.Exp.or.Obs.levels[,7],"]"),
                                               unadjusted.mean = table.comparing.Exp.or.Obs.levels[,8],                     
                                               unadjusted.CI = paste0("[",table.comparing.Exp.or.Obs.levels[,9],",",
                                                                    table.comparing.Exp.or.Obs.levels[,10],"]")
                                               )

table.comparing.Exp.or.Obs.levels[,1] <- c("Experimental","Observational")
# creating a formatted table using the R package 'gt'
table.comparing.Exp.or.Obs.levels.gt <- table.comparing.Exp.or.Obs.levels %>% 
  gt() %>% 
  cols_label(Exp.or.Obs.level=md("**Study type**"),
             adjusted.mean1=md("**Adjusted mean 1**"),
             adjusted.CI1=md("**Adjusted 95% CI 1**"),
             adjusted.mean2=md("**Adjusted mean 2**"),
             adjusted.CI2=md("**Adjusted 95% CI 2**"),
             unadjusted.mean=md("**Unadjusted mean**"),
             unadjusted.CI=md("**Unadjusted 95% CI**"),
             ) %>%
  cols_align(align = "center")
table.comparing.Exp.or.Obs.levels.gt
Study type Adjusted mean 1 Adjusted 95% CI 1 Adjusted mean 2 Adjusted 95% CI 2 Unadjusted mean Unadjusted 95% CI
Experimental -0.07 [-0.14,0.01] -0.06 [-0.18,0.07] -0.08 [-0.15,0]
Observational -0.25 [-0.31,-0.19] -0.10 [-0.2,-0.01] -0.25 [-0.31,-0.18]

Table S4.3. The estimates of all levels of the moderator Experimental.or.Observational. and their adjusted estimates (1 and 2) using the all-in publication bias test (multi-moderator meta-regression). ‘Adjusted 1’ is with \(\sqrt(1/\tilde{n})\) while ‘Adjusted 2’ with \(1/\tilde{n}\). Estimates are presented as lnRR.

SMD also show similar patterns for the adjusted overall effects (Adjusted 1 with \(\sqrt(1/\tilde{n})\) and Adjusted 2 with \(1/\tilde{n}\) ) after accounting for publication bias and time-lag bias: (Adjusted 2 = -0.52, 95% CI = [0.08,317]; Adjusted 1 with \(\sqrt(1/\tilde{n})\) and Adjusted 2 with \(1/\tilde{n}\) ) after accounting for publication bias and time-lag bias: (Adjusted 2 = -0.27, 95% CI = [0.13,317]; unadjusted effect = -0.49, 95% CI = [-0.64,-0.35]; more in section S4.2.2). As with lnRR, Table S4.4 show that the estimates from the unadjusted model and the adjusted model with \(\sqrt(1/\tilde{n})\) while the adjusted model with \(\sqrt(1/\tilde{n})\) gave smaller estimates in magnitude. Therefore, for SMD, we also suggest that we use the estimates from the method with \(1/\tilde{n}\) (Adjusted mean 2 and Adjusted 95% CI 2). Also, we believe that the use of \(1/\tilde{n}\) may be always warranted because it is likely that a non-zero effect almost always exists, while when there is no overall effect, it probably does not matter whether we use \(\sqrt(1/\tilde{n})\) or \(1/\tilde{n}\) to adjust such an overall effect (whose true effect is zero).

# creating a table to show the results of model 2
table.comparing.Exp.or.Obs.levels0 <- merge(estimates.publication.bias.model.smd.v.0,
                                          estimates.publication.bias.model.smd.v.1,
                                          by="estimate",
                                          all.x=T)

table.comparing.Exp.or.Obs.levels <- merge(table.comparing.Exp.or.Obs.levels0,
                                          estimates.publication.bias.model.smd.v.1b,
                                          by="estimate",
                                          all.x=T)
# rounding estimates
table.comparing.Exp.or.Obs.levels <- table.comparing.Exp.or.Obs.levels %>% mutate_at(vars(mean.x, lower.x,upper.x,mean.y,lower.y,upper.y, mean,lower,upper), list(~round(., 2)))

table.comparing.Exp.or.Obs.levels <- data.frame(Exp.or.Obs.level = table.comparing.Exp.or.Obs.levels[,1],
                                               adjusted.mean1=table.comparing.Exp.or.Obs.levels[,2],               
                                               adjusted.CI1 = paste0("[",table.comparing.Exp.or.Obs.levels[,3],",",
                                                                    table.comparing.Exp.or.Obs.levels[,4],"]"),
                                               adjusted.mean2=table.comparing.Exp.or.Obs.levels[,5],               
                                               adjusted.CI2 = paste0("[",table.comparing.Exp.or.Obs.levels[,6],",",
                                                                    table.comparing.Exp.or.Obs.levels[,7],"]"),
                                               unadjusted.mean = table.comparing.Exp.or.Obs.levels[,8],                     
                                               unadjusted.CI = paste0("[",table.comparing.Exp.or.Obs.levels[,9],",",
                                                                    table.comparing.Exp.or.Obs.levels[,10],"]")
                                               )

table.comparing.Exp.or.Obs.levels[,1] <- c("Experimental","Observational")
# creating a formatted table using the R package 'gt'
table.comparing.Exp.or.Obs.levels.gt <- table.comparing.Exp.or.Obs.levels %>% 
  gt() %>% 
  cols_label(Exp.or.Obs.level=md("**Study type**"),
             adjusted.mean1=md("**Adjusted mean 1**"),
             adjusted.CI1=md("**Adjusted 95% CI 1**"),
             adjusted.mean2=md("**Adjusted mean 2**"),
             adjusted.CI2=md("**Adjusted 95% CI 2**"),
             unadjusted.mean=md("**Unadjusted mean**"),
             unadjusted.CI=md("**Unadjusted 95% CI**"),
             ) %>%
  cols_align(align = "center")
table.comparing.Exp.or.Obs.levels.gt
Study type Adjusted mean 1 Adjusted 95% CI 1 Adjusted mean 2 Adjusted 95% CI 2 Unadjusted mean Unadjusted 95% CI
Experimental -0.33 [-0.57,-0.1] -0.10 [-0.45,0.25] -0.37 [-0.6,-0.13]
Observational -0.62 [-0.82,-0.43] -0.37 [-0.64,-0.09] -0.57 [-0.76,-0.39]

Table S4.4. The estimates of all levels of the moderator Experimental.or.Observational. and their adjusted estimates (1 and 2) using the all-in publication bias test (multi-moderator meta-regression). ‘Adjusted 1’ is with \(\sqrt(1/\tilde{n})\) while ‘Adjusted 2’ with \(1/\tilde{n}\). Estimates are presented as SMD.

S4.3: Extra plot – Figure 6a-d (redrawn using effective sample size)

Here we redraw Figure 6a-d using effective sample size or more accurately, \(\tilde{n}\). We note that Figure 6b-d in the main text use standard errors (SE) of different types of residuals so panels b, c and d may not be directly comparable between Figure 6 and this redrawn figure.

#include_graphics("./R/fig.png")

Figure 6a-d redrawn

Appendix S5: Alternative approches

S5.1: Averaging and sampling: correlation effect sizes (Zr)

S5.1.1: Averaging

To aggregate (average) effect sizes per study we will use the function ‘aggregate()’ from the R package metafor (Viechtbauer 2010) using a compound symmetric structure (‘struct=CS’) and a value of 0.5 for rho following Noble et al. (2017). That is, when averaging effect sizes per study we are not assuming that the effect sizes of a study are independent to each other, but instead that they are correlated and, since we do not know the real value of that correlation, we will estimate it as 0.5 for all studies. The function ‘aggregate()’ will then combine multiple estimates within the same study using inverse-variance weighting taking the 0.5 correlation into consideration. More information about the function ‘aggregate()’ can be found by typing ?metafor::aggregate, including how ‘aggregate()’ deals with other variables (e.g. moderators) in the dataset.

# you will need the development version of "metafor" package to run this bit
# rho = 0.5 is as in Noble et al (Mol Ecol)
dataset.r <- escalc(yi=yi, vi=vi, data=dataset.r)
dataset.r.agg <- aggregate(dataset.r, cluster=study, struct="CS", rho = 0.5)
S5.1.1.1: Trim-and-fill test

Using the aggregated data (see above), we will then fit the trim-and-fill method (Duval and Tweedie 2000a,b). The trim-and-fill method is a non-parametric method that can be used to both detect and correct for publication bias and, although it can handle some heterogeneity, it performs worse as heterogeneity increases (Peters et al., 2007; Moreno et al., 2009; more in the main text). Since we aggregated our data, we can now run a random-effects meta-analytic model rather than a multilevel model as used in section S.4, and we will run the trim-and-fill method using this model. Note that we used the method by Knapp and Hartung (2003; test = "knha") rather than the default z (Wald-type) tests; this test has been shown to perform better.

# random/mixed-effects meta-analytic model
meta.analysis.model.r.agg <- rma(yi, vi, test="knha",data=dataset.r,slab=study)

# trim-and-fill method
trimfill.r <- trimfill(meta.analysis.model.r.agg)

The trim-and-fill method identified 15 (SE = 6.65) missing studies (Figure S5.1) and estimated an adjusted overall effect of 0.2 (95% CI = [0.13,0.27]), which is similar to the adjusted overall effect estimated by our suggested multilevel meta-regression method (0, 95% CI = [0,0]; more in section S4.1.4.3).



Figure S5.1
funnel(trimfill.r, yaxis="seinv")
Funnel plot using precision (1/SE) as a measure of uncertainty and showing the adjusted meta-analytic mean (vertical line) and the  missing effect sizes (white points) according to the trim-and-fill method.

Funnel plot using precision (1/SE) as a measure of uncertainty and showing the adjusted meta-analytic mean (vertical line) and the missing effect sizes (white points) according to the trim-and-fill method.



S5.1.1.2: Selection model (3 PSM)

Using the aggregated data (see above), we will also fit a selection model-based method (reviewed by Marks-Anglin & Chen, 2020). Although there are many selection model methods, all of them model how effect sizes are missing based on p values, effect sizes and/or sampling variance, and can provide an adjusted overall effect (e.g. Rodgers & Pustejovsky, 2020; more in the main text). Contrary to other methods, selection models can deal with and model heterogeneity (e.g. Citkowicz and Vevea 2017), but cannot deal with non-independent effect sizes. We will run a step function selection model based on one cut-point (\(\alpha = 0.05\)); this model is sometimes referred to as a 3 parameter selection model (3PM; more in the main text; Rodgers & Pustejovsky, 2020; more by typing ?metafor::selmodel). Note that here we need to use the maximum likehoold method (ML) rather than restricted maximum likelihood (REML).

# without moderators
meta.analysis.r.agg0 <- rma(yi, vi, 
                            method="ML", #method needs to set to "ML" rather than "REML" as in all models above 
                            test="knha", #knha is meant to be better than Z and t, but it is not implemented for multilevel models
                            data=dataset.r)


three.PSM.r0 <- selmodel(meta.analysis.r.agg0, type="stepfun", steps=c(0.05,1)) #note that steps=c(0.05) would be give the same results

# look at confidence intervals - not just point estimate
# summary(three.PSM.r0)

# with moderators 
meta.regression.r.agg <- rma(yi, vi, 
                             mod = ~ year.c + 
                               CaptivityC - 1, 
                             method="ML",
                             test="knha", 
                             data=dataset.r)


three.PSM.r <- selmodel(meta.regression.r.agg, type="stepfun", steps=c(0.05))

# summary(three.PSM.r)

# extracting the mean and 95% confidence intervals
estimates.three.PSM.r <- estimates.CI(three.PSM.r)

The step function selection model based on one cut-point (\(\alpha = 0.05\)) for the intercept-only model estimated an adjusted overall effect of 0.31 (95% CI = [0.21,0.41]; Figure S5.2), which is larger than the original overall effect estimated by the meta-analytic model (0.29, 95% CI = [0.17,0.41]; more in section S4.1.4.3). Overall, the selection model estimated adjusted overall effects that were either very similar or even slightly larger than the original unadjusted effect sizes (Table S5.1), which might indicate that the specific selection model that we used (i.e. one cut-point \(\alpha = 0.05\)) was not an adequate approximation for the underlying selection process.



Figure S5.2
par(mfrow = c(1, 2))
plot(three.PSM.r0, ylim = c(0,2),col="red", lty = 3)
plot(three.PSM.r, ylim = c(0,2),col="red", lty = 3)
Results of a step function selection model based on one cut-point ($lpha = 0.05$) for a model without any moderators (left-hand figure) and a model including both 'year of publication' and 'captivity status' as moderators (right-hand figure).

Results of a step function selection model based on one cut-point (\(lpha = 0.05\)) for a model without any moderators (left-hand figure) and a model including both ‘year of publication’ and ‘captivity status’ as moderators (right-hand figure).



# creating a table to show the results of the selection model
table.comparing.captivity.levels.3PSM <- merge(estimates.three.PSM.r[c(2:6),],
                                               estimates.publication.bias.model.r.v.1b,
                                               by="estimate",
                                               all.x=T)

# rounding estimates
table.comparing.captivity.levels.3PSM <- table.comparing.captivity.levels.3PSM %>% mutate_at(vars(mean.x, lower.x,upper.x,mean.y,lower.y,upper.y), list(~round(., 2)))

table.comparing.captivity.levels.3PSM <- data.frame(captivity.level = table.comparing.captivity.levels.3PSM[,1],
                                                    adjusted.mean=table.comparing.captivity.levels.3PSM[,2],               adjusted.CI=paste0("[",table.comparing.captivity.levels.3PSM[,3],",",table.comparing.captivity.levels.3PSM[,4],"]"),
                                                    unadjusted.mean=table.comparing.captivity.levels.3PSM[,5],                                               unadjusted.CI=paste0("[",table.comparing.captivity.levels.3PSM[,6],",",table.comparing.captivity.levels.3PSM[,7],"]"))

table.comparing.captivity.levels.3PSM[,1] <- c("FC","FW","WCT","WCT & FC", "WCT & FW")

# creating a formatted table using the R package 'gt'
table.model.r.captivity.gt.3PSM <- table.comparing.captivity.levels.3PSM %>% 
  gt::gt() %>% 
  cols_label(captivity.level=md("**Captivity status**"),
             adjusted.mean=md("**Adjusted mean**"),
             adjusted.CI=md("**Adjusted 95% CI**"),
             unadjusted.mean=md("**Unadjusted mean**"),
             unadjusted.CI=md("**Unadjusted 95% CI**")) %>%
  cols_align(align = "center")

table.model.r.captivity.gt.3PSM
Captivity status Adjusted mean Adjusted 95% CI Unadjusted mean Unadjusted 95% CI
FC 0.29 [0.17,0.41] 0.28 [0.15,0.41]
FW 0.26 [0.06,0.47] 0.27 [0.05,0.49]
WCT 0.36 [0.24,0.48] 0.30 [0.16,0.45]
WCT & FC 0.41 [0.1,0.72] 0.43 [0.09,0.78]
WCT & FW 0.12 [-0.14,0.38] 0.16 [-0.12,0.43]

Table S5.1. Results adjusted and unadjusted for publication bias for all levels of the moderator ‘captivity status’ using a step function selection model based on one cut-point (\(\alpha = 0.05\)). Estimates are presented as standardized effect sizes using Fisher’s transformation of the correlation coefficient (i.e. Zr).



S5.1.1.3: Cumulative meta-analysis

Last, using the aggregated data (see above), we will also perform a cumulative meta-analysis using the function cumul() from the R package metafor (Viechtbauer 2010). By displaying the results of this cumulative meta-analysis as a forest plot, we can see if there is evidence of decline effects (more in the text), which we do not seem to have in this dataset (Figure S5.3).



Figure S5.3
cum.meta.analysis.model.r.agg <- cumul(meta.analysis.model.r.agg,order=order(dataset.r$year))
forest(cum.meta.analysis.model.r.agg, xlab = "Overall estimate (Zr)",digits=c(2,1),cex=0.3, header="Author(s) and year")
Forest plot showing the results of a cumulative meta-analysis, showing no clear evidence of decline effects.

Forest plot showing the results of a cumulative meta-analysis, showing no clear evidence of decline effects.



S5.1.2: Sampling

To sample one effect size per study we will write a custom function that, for each simulation: (i) randomly selects one effect size per study to generate a meta-analytic dataset; (ii) fits the publication bias test of interest; and (iii) extracts estimates from the publication bias test output. This process will be repeated 1000 times (i.e. 1000 samplings).



S5.1.2.1: Trim-and-fill test

For an introduction to the trim-and-fill method see section S5.1.1.1 and the main text. Below are the summary results of the trim-and-fill method after running 1000 randomizations.

# function for randomly selecting 1 effect size from each study
func_S5.1.2.1 <- function(sim = 1){
  
  # splitting dataframe into each study
  study_list <- split(dataset.r, dataset.r$study)
  
  # randomly extracting one effect size per study
  SingleStudyES_dataset.r <- dplyr::bind_rows(lapply(study_list, function(x) 
    x[sample(1:nrow(x), 1),c("study","yi","vi")]))
  
  # running the model on the dataframe now each study only has a single effect size
  model.tmp.r <- rma(yi, vi, test="knha",data=SingleStudyES_dataset.r) 
  
  # applying trim-and-fill method
  TAF <- trimfill(model.tmp.r)
 
  # creating a dataframe with results from the trim-and-fill methods, with:
  #n = number of missing studies
  #beta = adjusted overall effect
  df <- data.frame(sim,
                   n=TAF$k0,
                   beta=TAF$beta[[1]])
  
  return(df)
}

# applying the function 1000 times
#trimfill.sampling.r <- dplyr::bind_rows(lapply(1:1000, function(x) func_S5.1.2.1(x)))
# saving data to save time 
# save(trimfill.sampling.r,file = here("data","trimfill_sampling_r_1000s.RData"))

# loading the saved data
load(here("data","trimfill_sampling_r_1000s.RData"))

The median number of missing studies was 10 (range = 0 - 16; Figure S5.4A), which is seemingly lower than the number of missing studies estimated using the aggregated data (n = 15; more in section S5.1.1.1). Additionally, the median adjusted overall effect according to the trim-and-fill method was 0.21 (range = 0.17 - 0.28; Figure S5.4B), which is very similar to the adjusted overall effect estimated using the aggregated data (0.2; more in section S5.1.1.1), but still lower than the adjusted overall effect estimated by our suggested multilevel meta-regression method (0, 95% CI = [0,0]; more in section S4.1.4.3).



Figure S5.4
# plotting the distribution of the number of missing studies according to the trim-and-fill method
n.r <- ggplot(data=trimfill.sampling.r,aes(x=n)) +
  geom_density(alpha=.5,fill="darkorchid4") +
  geom_vline(data=trimfill.sampling.r, aes(xintercept=median(n)),
             linetype="dashed", size=1)

# plotting the distribution of the adjusted overall effect according to the trim-and-fill method
betas.r <- ggplot(data=trimfill.sampling.r,aes(x=beta)) +
  geom_density(alpha=.5,fill="darkorchid4") +
  geom_vline(data=trimfill.sampling.r, aes(xintercept=median(beta)),
             linetype="dashed", size=1)

ggarrange(n.r, betas.r, 
          labels = c("A", "B"),
          ncol = 2, nrow = 1)
Distribution of 1000 (A) estimated number of missing studies according to the trim-and-fill method, and (B) adjusted overall effect sizes according to the trim-and-fill method. The dashed line shows the median value.

Distribution of 1000 (A) estimated number of missing studies according to the trim-and-fill method, and (B) adjusted overall effect sizes according to the trim-and-fill method. The dashed line shows the median value.



S5.1.2.2: Selection model (3 PSM)

For an introduction to selection models see section S5.1.1.2 and the main text. As before, we will run a step function selection model based on one cut-point (\(\alpha = 0.05\)); this model is sometimes referred to as a 3 parameter selection model. For simplicity, we will only run the selection model for the intercept-only model (but see section S5.1.1.2 for how to run a selection model for a meta-regression). Below are the summary results of the 3 parameter selection model after running 1000 randomizations.

func_S5.1.2.2 <- function(sim = 1){
  
  # splitting dataframe into each study
  study_list <- split(dataset.r, dataset.r$study)
  
  # randomly extracting one effect size per study
  SingleStudyES_dataset.r <- dplyr::bind_rows(lapply(study_list, function(x) 
    x[sample(1:nrow(x), 1),c("study","yi","vi")]))
  
  # running the model on the dataframe now each study only has a single effect size
  model.tmp.r.agg0 <- rma(yi, vi, method="ML", test="knha",data=SingleStudyES_dataset.r)
  
  #extracting the adjusted overall effect according to the selection model for each database
  threePSM.vector.r <- selmodel(model.tmp.r.agg0, type="stepfun", steps=c(0.05))$beta[[1]]
  
  #creating a dataframe with the n.randomization.r of estimated number of missing studies and adjusted overall effects
  df <- data.frame(sim, beta=threePSM.vector.r)

  return(df)
}

# applying the function 1000 times
#threePSM.sampling.r <- dplyr::bind_rows(lapply(1:1000, function(x) func_S5.1.2.2(x)))
# save(threePSM.sampling.r,file = here("data","3PSM_sampling_r_1000s.RData"))

# loading the data extracted from the 1000 iterations above
load(here("data","3PSM_sampling_r_1000s.RData"))

The median adjusted overall effect according to the 3 parameter selection model was 0.27 (range = 0.12 - 0.34; Figure S5.4B), which is similar to the adjusted overall effect estimated using the aggregated data (0.31; 95% CI = [0.21,0.41]; more in section S5.1.1.2) and to the adjusted overall effect estimated by our suggested multilevel meta-regession method (0, 95% CI = [0,0]; more in section S4.1.4.3).



Figure S5.5
# plotting the distribution of adjusted overall effect sizes according to the 3 parameter selection model
ggplot(data=threePSM.sampling.r,aes(x=beta)) +
  geom_density(alpha=.5,fill="darkorchid4") +
  geom_vline(data=threePSM.sampling.r, aes(xintercept=median(beta)),
             linetype="dashed", size=1)
Distribution of 1000 adjusted overall effect sizes according to the 3 parameter selection model. The dashed line shows the median value.

Distribution of 1000 adjusted overall effect sizes according to the 3 parameter selection model. The dashed line shows the median value.



S5.1.2.3: Cumulative meta-analysis

For an introduction to cumulative meta-analysis see section S5.1.1.3 and the main text. Here, we will perform a sampling procedure where we run a cumulative meta-analysis test for each dataset and extract the mean effects estimated by the cumulative meta-analysis. We will then plot the median and 95% quantiles of those mean effects at each step. As before, the forest plot does not show any clear evidence of decline effects in this dataset (Figure S5.6).

func_S5.1.2.3 <- function(sim = 1){
  # arranging by study year
  dat_ordered <- dataset.r[order(dataset.r$year),c("study","yi","vi","year")]
  
  # splitting dataframe into each study
  study_list <- split(dat_ordered, dat_ordered$study)
  
  # randomly extracting one effect size per study
  SingleStudyES_dataset.r <- dplyr::bind_rows(lapply(study_list, function(x) 
    x[sample(1:nrow(x), 1),]))
  
  # running MA
   model.tmp.r <- rma(yi, vi, test="knha",data=SingleStudyES_dataset.r) 
   
   # cumulative meta-analysis
   CMA <- cumul(model.tmp.r,order=order(SingleStudyES_dataset.r$year))
   
   # dataframe with meta-analytic mean
    df <- data.frame(sim, beta = CMA$estimate)
  return(df)
}

# applying the function 1000 times
#threePSM.sampling.r <- dplyr::bind_rows(lapply(1:1000, function(x) func_S5.1.2.3(x)))
# save(threePSM.sampling.r,file = here("data","3PSM_sampling_r_1000s.RData"))

# loading the saved data
load(here("data","cumul_sampling_r_1000s.RData"))
Figure S5.6
cumul.sampling.r.summarized <- as.data.frame(cumul.sampling.r 
                                             %>% group_by(order) %>% 
                                               summarise(median = median(beta), 
                                                         lowCI = quantile(beta,probs = c(0.025)), 
                                                         hiCI = quantile(beta,probs = c(0.975))))


# reverses the factor level ordering for labels after coord_flip()
cumul.sampling.r.summarized$order <- factor(cumul.sampling.r.summarized$order, levels=rev(cumul.sampling.r.summarized$order))

ggplot(data=cumul.sampling.r.summarized, aes(x=order, y=median, ymin=lowCI, ymax=hiCI)) +
  geom_pointrange() + 
  geom_hline(yintercept=0, lty=2) +  # add a dotted line at x=1 after flip
  coord_flip() +  # flip coordinates (puts labels on y axis)
  xlab("Order of publication") + ylab("Mean (95% CI)") +
  theme_bw() 
Median and 95% quantiles of 1000 effect sizes estimated according to cumulative meta-analysis showing no evidence of decline effects.

Median and 95% quantiles of 1000 effect sizes estimated according to cumulative meta-analysis showing no evidence of decline effects.



S5.2: Averaging and sampling: mean differences between two groups (lnRR and SMD)

S5.2.1: Averaging

# rho = 0.5 is as in Noble et al (Mol Ecol)
dataset.rr <- escalc(yi=yi, vi=vi, data=dataset.rr)
dataset.rr.agg <- aggregate(dataset.rr, cluster=paperID, struct="CS", rho = 0.5)

dataset.smd <- escalc(yi=yi, vi=vi, data=dataset.smd)
dataset.smd.agg <- aggregate(dataset.smd, cluster=paperID, struct="CS", rho = 0.5)
S5.2.1.1: Trim and fill test

Using the aggregated data (see Equation 30 in main text), we will then fit the trim-and-fill method (Duval and Tweedie 2000a,b). The trim-and-fill method is a non-parametric method that can be used to both detect and correct for publication bias and, although it can handle some heterogeneity, it performs worse as heterogeneity increases (Peters et al., 2007; Moreno et al., 2009; more in the main text). We will apply the trim-and-fill method to meta-analytic models with no random effects (since we aggregated our data we no longer need to fit a multilevel model to account for non-independent effect sizes).

# lnRR
meta.analysis.model.rr.agg <- rma(yi, vi, test="knha", # using t dist rather than z
                                  data=dataset.rr.agg)
trimfill.rr <- trimfill(meta.analysis.model.rr.agg)

#SMD
meta.analysis.model.smd.agg <- rma(yi, vi, test="knha", # using t dist rather than z
                                   data=dataset.smd.agg)
trimfill.smd <- trimfill(meta.analysis.model.smd.agg)

The trim-and-fill method identified 0 (SE = 8.88) missing studies (Figure S5.7) and estimated an adjusted overall effect of -0.15 (95% CI = [-0.2,-0.1]).



Figure S5.7
par(mfrow = c(1,2))
funnel(trimfill.rr, yaxis="seinv",
       ylab = "Precision (1/SE)",
       xlab = "Effect size (lnRR)") 
funnel(trimfill.smd, yaxis="seinv",
       ylab = "Precision (1/SE)",
       xlab = "Effect size (SMD)") 
Funnel plot using precision (1/SE) as a measure of uncertainty and showing the adjusted meta-analytic mean (vertical line) and the  missing effect sizes (white points) according to the trim-and-fill method.

Funnel plot using precision (1/SE) as a measure of uncertainty and showing the adjusted meta-analytic mean (vertical line) and the missing effect sizes (white points) according to the trim-and-fill method.

Using the aggregated data (see above), we will also fit a selection model-based method (reviewed by Marks-Anglin & Chen, 2020). Although there are many selection models, all of them model how effect sizes are missing based on p values, effect sizes and/or sampling variance, and can provide an adjusted overall effect (e.g. Rodgers & Pustejovsky, 2020; more in the main text). Contrary to other methods, selection models can deal with and model heterogeneity (e.g. Citkowicz and Vevea 2017), but cannot deal with non-independent effect sizes. We will run a step function selection model based on one cut-point (\(\alpha = 0.05\)); this model is sometimes referred to as a 3 parameter selection model (3PM; more in the main text; Rodgers & Pustejovsky, 2020).

S5.2.1.2: Selection model (3 PSM)
# lnRR
# without moderators

# moderator
meta.regression.rr.agg0 <- rma(yi, vi, 
                               method="ML",
                               test="knha", 
                               data=dataset.rr)


three.PSM.rr0 <- selmodel(meta.regression.rr.agg0, type="stepfun", steps=c(0.05, 1))

#summary(three.PSM.rr0)


# with moderator
meta.regression.rr.agg <- rma(yi, vi, 
                              mod = ~ year.c 
                              + Experimental.or.Observational. - 1, 
                              method="ML",
                              test="knha", 
                              data=dataset.rr)


three.PSM.rr <- selmodel(meta.regression.rr.agg, type="stepfun", steps=c(0.05, 1))



## SMD

# without moderators
meta.regression.smd.agg0 <- rma(yi, vi, 
                                method="ML",
                                test="knha", 
                                data=dataset.smd)


three.PSM.smd0 <- selmodel(meta.regression.smd.agg0, type="stepfun", steps=c(0.05, 1))


# with moderators
meta.regression.smd.agg <- rma(yi, vi, 
                               mod = ~ year.c 
                               + Experimental.or.Observational. - 1, 
                               method="ML",
                               test="knha", 
                               data=dataset.smd)


three.PSM.smd <- selmodel(meta.regression.smd.agg, type="stepfun", steps=c(0.05, 1))


# extracting the mean and 95% confidence intervals
estimates.three.PSM.rr <- estimates.CI(three.PSM.rr)
estimates.three.PSM.smd <- estimates.CI(three.PSM.smd)

The step function selection model based on one cut-point (\(\alpha = 0.05\)) for the intercept-only model estimated an adjusted overall lnRR of -0.1 (95% CI = [-0.18,-0.01]; Figure S5.8), which is smaller than the original overall effect estimated by the meta-analytic model (0.29, 95% CI = [0.17,0.41]; more in section S4.2.3.3). SMD showed the same pattern. Overall, the selection model estimated adjusted overall effects that were either very similar or even slightly larger than the original unadjusted effect sizes (Table S5.2), which might indicate that the specific selection model that we used (i.e. one cut-point of \(\alpha = 0.05\)) was not an adequate approximation for the underlying selection process.



Figure S5.8

Results of a step function selection model based on one cut-point (\(\alpha = 0.05\)) for a model without any moderators (left-hand figure, top panel for lnRR, bottom for SMD) and a model including both ‘year of publication’ and ‘Experimental.or.Observational.’ as moderators (right-hand figure, top panel for lnRR, bottom for SMD).

par(mfrow = c(1, 2))
plot(three.PSM.rr0, col="red", lty = 3)
plot(three.PSM.rr, col="red", lty = 3)



par(mfrow = c(1, 2))
plot(three.PSM.smd0, col="red", lty = 3)
plot(three.PSM.smd, col="red", lty = 3)



# creating a table to show the results of the selection model
table.comparing.Exp.or.Obs.levels.3PSM <- merge(estimates.three.PSM.rr[c(2:3),],
                                               estimates.publication.bias.model.rr.v.1b,
                                               by="estimate",
                                               all.x=T)
# rounding estimates
table.comparing.Exp.or.Obs.levels.3PSM <- table.comparing.Exp.or.Obs.levels.3PSM %>% mutate_at(vars(mean.x, lower.x,upper.x,mean.y,lower.y,upper.y), list(~round(., 2)))

table.comparing.Exp.or.Obs.levels.3PSM <- data.frame(Exp.or.Obs.level = table.comparing.Exp.or.Obs.levels.3PSM[,1],
                                                    adjusted.mean=table.comparing.Exp.or.Obs.levels.3PSM[,2],               adjusted.CI=paste0("[",table.comparing.Exp.or.Obs.levels.3PSM[,3],",",table.comparing.Exp.or.Obs.levels.3PSM[,4],"]"),
                                                    unadjusted.mean=table.comparing.Exp.or.Obs.levels.3PSM[,5],                                               unadjusted.CI=paste0("[",table.comparing.Exp.or.Obs.levels.3PSM[,6],",",table.comparing.Exp.or.Obs.levels.3PSM[,7],"]"))
table.comparing.Exp.or.Obs.levels.3PSM[,1] <- c("Experimental","Observational")
# creating a formatted table using the R package 'gt'
table.model.rr.Exp.or.Obs.gt.3PSM <- table.comparing.Exp.or.Obs.levels.3PSM %>% 
  gt() %>% 
  cols_label(Exp.or.Obs.level=md("**Experimental.or.Observational.**"),
             adjusted.mean=md("**Adjusted mean**"),
             adjusted.CI=md("**Adjusted 95% CI**"),
             unadjusted.mean=md("**Unadjusted mean**"),
             unadjusted.CI=md("**Unadjusted 95% CI**")) %>%
  cols_align(align = "center")
table.model.rr.Exp.or.Obs.gt.3PSM 
Experimental.or.Observational. Adjusted mean Adjusted 95% CI Unadjusted mean Unadjusted 95% CI
Experimental 0.06 [-0.06,0.19] -0.08 [-0.15,0]
Observational -0.19 [-0.27,-0.11] -0.25 [-0.31,-0.18]

Table S5.2. Adjusted and unadjusted for publication bias results for all levels of the moderator ‘Experimental.or.Observational.’ using a step function selection model based on one cut-point (\(\alpha = 0.05\)). Estimates are presented as standardized effect sizes using lnRR.



# creating a table to show the results of the selection model
table.comparing.Exp.or.Obs.levels.3PSM <- merge(estimates.three.PSM.smd[c(2:3),],
                                               estimates.publication.bias.model.smd.v.1b,
                                               by="estimate",
                                               all.x=T)
# rounding estimates
table.comparing.Exp.or.Obs.levels.3PSM <- table.comparing.Exp.or.Obs.levels.3PSM %>% mutate_at(vars(mean.x, lower.x,upper.x,mean.y,lower.y,upper.y), list(~round(., 2)))

table.comparing.Exp.or.Obs.levels.3PSM <- data.frame(Exp.or.Obs.level = table.comparing.Exp.or.Obs.levels.3PSM[,1],
                                                    adjusted.mean=table.comparing.Exp.or.Obs.levels.3PSM[,2],               adjusted.CI=paste0("[",table.comparing.Exp.or.Obs.levels.3PSM[,3],",",table.comparing.Exp.or.Obs.levels.3PSM[,4],"]"),
                                                    unadjusted.mean=table.comparing.Exp.or.Obs.levels.3PSM[,5],                                               unadjusted.CI=paste0("[",table.comparing.Exp.or.Obs.levels.3PSM[,6],",",table.comparing.Exp.or.Obs.levels.3PSM[,7],"]"))
table.comparing.Exp.or.Obs.levels.3PSM[,1] <- c("Experimental","Observational")
# creating a formatted table using the R package 'gt'
table.model.smd.Exp.or.Obs.gt.3PSM <- table.comparing.Exp.or.Obs.levels.3PSM %>% 
  gt() %>% 
  cols_label(Exp.or.Obs.level=md("**Experimental.or.Observational.**"),
             adjusted.mean=md("**Adjusted mean**"),
             adjusted.CI=md("**Adjusted 95% CI**"),
             unadjusted.mean=md("**Unadjusted mean**"),
             unadjusted.CI=md("**Unadjusted 95% CI**")) %>%
  cols_align(align = "center")
table.model.smd.Exp.or.Obs.gt.3PSM
Experimental.or.Observational. Adjusted mean Adjusted 95% CI Unadjusted mean Unadjusted 95% CI
Experimental -0.14 [-0.46,0.17] -0.37 [-0.6,-0.13]
Observational -0.49 [-0.71,-0.26] -0.57 [-0.76,-0.39]

Table S5.3. Adjusted and unadjusted for publication bias results for all levels of the moderator ‘Experimental.or.Observational.’ using a step function selection model based on one cut-point (\(\alpha = 0.05\)). Estimates are presented as standardized effect sizes using SMD.



S5.2.1.3: Cumlative meta-analysis

Last, using the aggregated data (see above), we will also perform a cumulative meta-analysis using the function cumul() from the R package metafor (Viechtbauer 2010). By displaying the results of this cumulative meta-analysis as a forest plot, we can see if there is evidence of decline effects (more in the text), which we do not seem to have for lnRR (Figure S5.9, left-hand) and SMD (Figure S5.10, left-hand).



# lnRR
cum.meta.analysis.model.rr.agg <- cumul(meta.analysis.model.rr.agg)

# SMD
cum.meta.analysis.model.smd.agg <- cumul(meta.analysis.model.smd.agg)

par(mfrow = c(1, 2))
forest(cum.meta.analysis.model.rr.agg, xlab = "Overall estimate (lnRR)")
forest(cum.meta.analysis.model.smd.agg, xlab = "Overall estimate (SMD)")



S5.2.2: Sampling

As in S5.1.2, we will run the trim-and-fill test on 1000 datasets, each with only 1 effect size per study (sampled randomly).



S5.2.2.1: Trim and fill test

For an introduction to the trim-and-fill method see section S5.2.1.1 and the main text. Below are the summary results of the trim-and-fill method after running 1000 randomizations.

# function for randomly selecting 1 effect size from each study
func_S5.2.2.1 <- function(sim = 1, df){
  
  # splitting dataframe into each study
  study_list <- split(df, df$paperID)
  
  # randomly extracting one effect size per study
  SingleStudyES_df <- dplyr::bind_rows(lapply(study_list, function(x) 
    x[sample(1:nrow(x), 1),c("paperID","yi","vi")]))
  
  # running the model on the dataframe now each study only has a single effect size
  model.tmp <- rma(yi, vi, test="knha",data=SingleStudyES_df) 
  
  # applying trim-and-fill method
  TAF <- trimfill(model.tmp)
 
  # creating a dataframe with results from the trim-and-fill methods, with:
  #n = number of missing studies
  #beta = adjusted overall effect
  df <- data.frame(sim,
                   n=TAF$k0,
                   beta=TAF$beta[[1]])
  
  return(df)
}

# applying the function 1000 times for lnRR
#trimfill.sampling.rr <- dplyr::bind_rows(lapply(1:1000, function(x) func_S5.2.2.1(sim = x, df = dataset.rr)))
# saving data to save time 
# save(trimfill.sampling.rr,file = here("data","trimfill_sampling_rr_1000s.RData"))
load(here("data","trimfill_sampling_rr_1000s.RData"))

# applying the function 1000 times for SMR
#trimfill.sampling.smd <- dplyr::bind_rows(lapply(1:1000, function(x) func_S5.2.2.1(sim = x, df = dataset.smd)))
# saving data to save time 
# save(trimfill.sampling.smd,file = here("data","trimfill_sampling_smd_1000s.RData"))
load(here("data","trimfill_sampling_smd_1000s.RData"))

The median number of missing studies for lnRR was 0 (range = 0 - 17; Figure S5.9A). Additionally, the median adjusted overall lnRR according to the trim-and-fill method was -0.17 (range = -0.2 - -0.11; Figure S5.9B), which is larger than the adjusted overall lnRR estimated by our suggested multilevel meta-regession method (-0.06, 95% CI = [-0.18,0.07]; more in section S4.2.4.3).



Figure S5.9
# plotting the distribution of the number of missing studies according to the trim-and-fill method
n.rr <- ggplot(data=trimfill.sampling.rr,aes(x=n)) +
  geom_density(alpha=.5,fill="darkorchid4") +
  geom_vline(data=trimfill.sampling.rr, aes(xintercept=median(n)),
             linetype="dashed", size=1)
# plotting the distribution of the adjusted overall effect according to the trim-and-fill method
betas.rr <- ggplot(data=trimfill.sampling.rr,aes(x=beta)) +
  geom_density(alpha=.5,fill="darkorchid4") +
  geom_vline(data=trimfill.sampling.rr, aes(xintercept=median(beta)),
             linetype="dashed", size=1)
ggarrange(n.rr, betas.rr, 
          labels = c("A", "B"),
          ncol = 2, nrow = 1)
Distribution of `r n.randomization.rr.TAF` (A) estimated number of missing studies according to the trim-and-fill method, and (B) adjusted overall lnRR according to the trim-and-fill method. The dashed line shows the median value.

Distribution of r n.randomization.rr.TAF (A) estimated number of missing studies according to the trim-and-fill method, and (B) adjusted overall lnRR according to the trim-and-fill method. The dashed line shows the median value.



The median number of missing studies for SMD was 0 (range = 0 - 1; Figure S5.10A). Additionally, the median adjusted overall SMD according to the trim-and-fill method was -0.5 (range = -0.57 - -0.43; Figure S5.10B), which is larger than the adjusted overall SMD estimated by our suggested multilevel meta-regression method (-0.1, 95% CI = [-0.45,0.25]; more in section S4.2.4.3).



Figure S5.10
# plotting the distribution of the number of missing studies according to the trim-and-fill method
n.smd <- ggplot(data=trimfill.sampling.smd,aes(x=n)) +
  geom_density(alpha=.5,fill="darkorchid4") +
  geom_vline(data=trimfill.sampling.smd, aes(xintercept=median(n)),
             linetype="dashed", size=1)
# plotting the distribution of the adjusted overall effect according to the trim-and-fill method
betas.smd <- ggplot(data=trimfill.sampling.smd,aes(x=beta)) +
  geom_density(alpha=.5,fill="darkorchid4") +
  geom_vline(data=trimfill.sampling.smd, aes(xintercept=median(beta)),
             linetype="dashed", size=1)
ggarrange(n.smd, betas.smd, 
          labels = c("A", "B"),
          ncol = 2, nrow = 1)
Distribution of `r n.randomization.smd.TAF` (A) estimated number of missing studies according to the trim-and-fill method, and (B) adjusted overall SMD according to the trim-and-fill method. The dashed line shows the median value.

Distribution of r n.randomization.smd.TAF (A) estimated number of missing studies according to the trim-and-fill method, and (B) adjusted overall SMD according to the trim-and-fill method. The dashed line shows the median value.



S5.2.2.2: Selection model (3 PSM)

For an introduction to selection models see section S5.2.1.2 and the main text. As before, we ran a step function selection model based on one cut-point (\(\alpha = 0.05\)); this model is sometimes referred to as a 3 parameter selection model. For simplicity, we only ran the selection model for the intercept-only model (but see section S5.2.1.2 for how to run a selection model for a meta-regression). Below are the summary results of the 3 parameter selection model after running 1000 randomizations.

# function for randomly selecting 1 effect size from each study
func_S5.2.2.2 <- function(sim = 1, df){
  
  # splitting dataframe into each study
  study_list <- split(df, df$paperID)
  
  # randomly extracting one effect size per study
  SingleStudyES_df <- dplyr::bind_rows(lapply(study_list, function(x) 
    x[sample(1:nrow(x), 1),c("paperID","yi","vi")]))
  
  # running the model on the dataframe now each study only has a single effect size
  model.tmp <- rma(yi, vi, method="ML", test="knha",data=SingleStudyES_df )
  
  # extracting the adjusted overall effect according to the selection model 
  threePSM.vector <- selmodel(model.tmp, type="stepfun", steps=c(0.05))$beta[[1]]
  
  # creating a dataframe with the n.randomization.r of estimated number 
  # of missing studies and adjusted overall effects
  threePSM.sampling <- data.frame(sim, beta=threePSM.vector)
  
  return(threePSM.sampling)
}

# applying the function 1000 times for lnRR
#threePSM.sampling.rr <- dplyr::bind_rows(lapply(1:1000, function(x) func_S5.2.2.2(sim = x, df = dataset.rr)))
# saving data to save time 
# save(threePSM.sampling.rr,file = here("data","3PSM_sampling_rr_1000s.RData"))
load(here("data","3PSM_sampling_rr_1000s.RData"))

The median adjusted overall lnRR according to the 3 parameter selection model was -0.07 (range = -0.11 - -0.01; Figure S5.4B), which is smaller than the adjusted overall lnRR estimated by our suggested multilevel meta-regression method (-0.06, 95% CI = [-0.18,0.07]; more in section S4.2.4.3).



Figure S5.11
# plotting the distribution of adjusted overall effect sizes according to the 3 parameter selection model
ggplot(data=threePSM.sampling.rr,aes(x=beta)) +
  geom_density(alpha=.5,fill="darkorchid4") +
  geom_vline(data=threePSM.sampling.rr, aes(xintercept=median(beta)),
             linetype="dashed", size=1)
Distribution of `r n.randomization.rr.3PSM` adjusted overall lnRR according to the 3 parameter selection model. The dashed line shows the median value.

Distribution of r n.randomization.rr.3PSM adjusted overall lnRR according to the 3 parameter selection model. The dashed line shows the median value.



# applying the function 1000 times for SMD
#threePSM.sampling.smd <- dplyr::bind_rows(lapply(1:1000, function(x) func_S5.2.2.2(sim = x, df = dataset.smd)))
# saving data to save time 
# save(threePSM.sampling.smd,file = here("data","3PSM_sampling_smd_1000s.RData"))
load(here("data","3PSM_sampling_smd_1000s.RData"))

The median adjusted overall SMD according to the 3 parameter selection model was -0.29 (range = -0.38 - -0.2; Figure S5.4B), which is smaller than the adjusted overall SMD estimated by our suggested multilevel meta-regession method (-0.1, 95% CI = [-0.45,0.25]; more in section S4.2.4.3).



Figure S5.12
# plotting the distribution of adjusted overall effect sizes according to the 3 parameter selection model
ggplot(data=threePSM.sampling.smd,aes(x=beta)) +
  geom_density(alpha=.5,fill="darkorchid4") +
  geom_vline(data=threePSM.sampling.smd, aes(xintercept=median(beta)),
             linetype="dashed", size=1)
Distribution of `r n.randomization.smd.3PSM` adjusted overall SMD according to the 3 parameter selection model. The dashed line shows the median value.

Distribution of r n.randomization.smd.3PSM adjusted overall SMD according to the 3 parameter selection model. The dashed line shows the median value.



S5.2.2.3: Cumlative meta-analysis

For an introduction to cumulative meta-analysis see section S5.2.1.3 and the main text. Here, we performed a sampling procedure where we ran a cumulative meta-analysis test for each dataset and extracted the mean effects estimated by the cumulative meta-analysis. We then plotted the median and 95% quantiles of those mean effects at each step. As before, the forest plot does not show any clear evidence of decline effects in this dataset (Figure S5.6).

func_S5.2.2.3 <- function(sim = 1, df = dataset.rr){
  
  # splitting dataframe into each study
  study_list <- split(df, df$paperID)
  
  # randomly extracting one effect size per study
  SingleStudyES_df <- dplyr::bind_rows(lapply(study_list, function(x) 
    x[sample(1:nrow(x), 1),c("paperID","year","yi","vi")]))
  
  # running the model on the dataframe now each study only has a single effect size
  model.tmp <- rma(yi, vi, method="ML", test="knha",data=SingleStudyES_df)
  
  # order of years
  year_order <- order(SingleStudyES_df$year)
  
  #cumulative meta-analysis
  cumul.ma <- metafor::cumul(x = model.tmp, order = year_order)

  # dataframe for export
  df <- data.frame(order = 1:length(year_order),
                   year = SingleStudyES_df$year[year_order],
                   sim,
                   beta = as.vector(cumul.ma$estimate),
                   lb = as.vector(cumul.ma$ci.lb),
                   ub = as.vector(cumul.ma$ci.ub))
  
  return(df)
}

# running function 1000 times
# @TO-DO: is 1000 really necessary here? It takes a very long time and the dataframe is enormous (because it's 1000 x all the years)
# cumul.sampling.rr <- dplyr::bind_rows(lapply(1:1000, function(x) func_S5.2.2.3(sim = x, df = dataset.rr)))
# save(cumul.sampling.rr,file = here("data","cumul_sampling_rr_1000s.RData"))
# cumul.sampling.smd <- dplyr::bind_rows(lapply(1:1000, function(x) func_S5.2.2.3(sim = x, df = dataset.smd)))
# save(cumul.sampling.smd,file = here("data","cumul_sampling_smd_1000s.RData"))

load(here("data","cumul_sampling_rr_1000s.RData"))
load(here("data","cumul_sampling_smd_1000s.RData"))
Figure S5.13
cumul.sampling.rr.summarized <- as.data.frame(cumul.sampling.rr 
                                             %>% group_by(order) %>% 
                                               summarise(median = median(beta), 
                                                         lowCI = quantile(beta,probs = c(0.025)), 
                                                         hiCI = quantile(beta,probs = c(0.975))))
# reverses the factor level ordering for labels after coord_flip()
cumul.sampling.rr.summarized$order <- factor(cumul.sampling.rr.summarized$order, levels=rev(cumul.sampling.rr.summarized$order))
ggplot(data=cumul.sampling.rr.summarized, aes(x=order, y=median, ymin=lowCI, ymax=hiCI)) +
  geom_pointrange() + 
  geom_hline(yintercept=0, lty=2) +  # add a dotted line at x=1 after flip
  coord_flip() +  # flip coordinates (puts labels on y axis)
  xlab("Order of publication") + ylab("Overall lnRR (95% CI)") +
  theme_bw() 
Median and 95% quantiles of `r n.randomization.rr.CM` lnRR estimated according to cumulative meta-analysis showing evidence of decline effects.

Median and 95% quantiles of r n.randomization.rr.CM lnRR estimated according to cumulative meta-analysis showing evidence of decline effects.



Figure S5.13
cumul.sampling.smd.summarized <- as.data.frame(cumul.sampling.smd 
                                             %>% group_by(order) %>% 
                                               summarise(median = median(beta), 
                                                         lowCI = quantile(beta,probs = c(0.025)), 
                                                         hiCI = quantile(beta,probs = c(0.975))))
# reverses the factor level ordering for labels after coord_flip()
cumul.sampling.smd.summarized$order <- factor(cumul.sampling.smd.summarized$order, levels=rev(cumul.sampling.smd.summarized$order))
ggplot(data=cumul.sampling.smd.summarized, aes(x=order, y=median, ymin=lowCI, ymax=hiCI)) +
  geom_pointrange() + 
  geom_hline(yintercept=0, lty=2) +  # add a dotted line at x=1 after flip
  coord_flip() +  # flip coordinates (puts labels on y axis)
  xlab("Order of publication") + ylab("Overall SMD (95% CI)") +
  theme_bw() 
Median and 95% quantiles of `r n.randomization.smd.CM` SMD estimated according to cumulative meta-analysis showing evidence of decline effects.

Median and 95% quantiles of r n.randomization.smd.CM SMD estimated according to cumulative meta-analysis showing evidence of decline effects.



Appendix extra: Figure’s R code

Code for Fig. 1

There is no code for Fig. 1 (created in PowerPoint)

Code for Fig. 2
# loading data
PB <- read.csv("./Survey/PubBias_tests.csv")
Item16 <- read.csv("./Survey/Item16PRISMAEcoEvo.csv")

# number of times each test was represented
PB %>% group_by(PB_reported_in_paper) %>% tally() %>% ungroup %>% arrange(n) %>% 
  mutate(percent = paste0(round(n/sum(n)*100,1), "%")) -> Ntests
# selection methods were not reported in any papers
Ntests <- rbind(Ntests,
                data.frame(PB_reported_in_paper = "Selection (method) models (e.g. Copas, Hedges or Iyengar & Greenhouse model)",
                           n = 0,
                           percent = "0.0%"))

# making label for graphs
PB_labels <- Ntests$PB_reported_in_paper
PB_labels <- case_when(PB_labels == "Funnel plots (including contour-enhanced funnel plots)" ~ "(A) Funnel plots",
                       PB_labels == "Regression-based test (e.g. Egger regression and its variants)" ~ "(D) Regression-based methods",
                       PB_labels == "Time-lag bias tests (e.g., regression or correlation on the relationship between effect size and time or cumulative meta-analysis)" ~ "(I) Time-lag bias tests",
                       PB_labels == "File drawer numbers or fail safe N (Rosenthal, Orwin or Rosenberg method)" ~ "(E) Fail-safe N",
                       PB_labels == "Trim-and-fill tests" ~ "(F) Trim-and-fill tests",
                       PB_labels == "P-curve, P-uniform or its variants" ~ "(G) P-value-based methods",
                       PB_labels == "Weighted histogram" ~ "(K) Other (weighted histogram)",
                       PB_labels == "Correlation-based tests (e.g. Begg & Manzumdar rank correlation)" ~ "(C) Correlation-based methods",
                       PB_labels == "Normal quantile (QQ) plots (Wang & Bushman)" ~ "(B) Normal quantile (QQ) plots",
                       PB_labels == "None reported" ~ "(J) None reported",
                       PB_labels == "Selection (method) models (e.g. Copas, Hedges or Iyengar & Greenhouse model)" ~ "(H) Selection models")

# putting in same order as survey question
Ntests$PB_label <- factor(PB_labels, levels = rev(sort(PB_labels)))

# ggplot theme
background.colour = "white"
tm <- theme(panel.background = element_rect(fill = background.colour),
            plot.background = element_rect(fill = background.colour),
            panel.grid = element_blank(),
            axis.line = element_line(size = 0.75, colour = "black"),
            axis.ticks = element_line(size = 0.75, colour = "black"),
            axis.ticks.length = unit(0.1,"cm"),
            axis.text.x = element_text(size = 14, colour = "black"),
            axis.title = element_text(size = 18, colour = "black"),
            axis.text.y = element_text(hjust = 0, size = 16, colour = "black"),
            axis.title.y = element_blank(),
            axis.title.x = element_text(margin = margin(t=10,r=0,b=2,l=0)),
           # axis.title.x = element_blank(),
            plot.title = element_text(size = 18, colour = "black", face = "bold", hjust = 0.5, margin = margin(t=2,r=0,b=10,l=0)),
            legend.background = element_rect(fill = background.colour),
            legend.title = element_blank(),
            legend.text = element_text(size = 16, margin = margin(2,0,2,0)),
            legend.spacing.y = unit(1, "cm"),
            legend.position = "bottom",
            text =  element_text(family = "Arial"),
            legend.key = element_blank(),
            plot.margin = unit(c(0.3,1,0.3,0.3), "cm"))

# colour to fill columns
colcol = "#cad7ed"

## Plot of the types of tests

fig2 <- ggplot(Ntests) + tm + theme(plot.title = element_text(hjust = -1)) +
  geom_col(aes(PB_label, n), fill = colcol, colour = "black", width = 0.75, size = 1) +
  geom_text(aes(x = PB_label, y = n, label = percent), hjust = -0.1, size = 5, family = "Arial") +
  scale_y_continuous(expand = c(0,0), limits = c(0, 80)) +
  coord_flip() +
  labs(x = "type of publication bias test",
       y = "number of papers reporting test") 

#fig2
Code for Fig. 3
# creating data

set.seed(77777)

# setting parameters
n.effect <- 100
sigma2.s <- 0.05
beta1 <- 0.2
# using negative binomial we get good spread of sample size
n.sample <- rnbinom(n.effect, mu = 30, size = 0.7) + 4
# variance for Zr
vi <- 1/(n.sample - 3)
# moderator x 1
xi <- rnorm(n.effect)

# there is underling overall effect to r = 0.2 or Zr = 0.203
Zr <- atanh(0.2) + beta1*xi + rnorm(n.effect, 0, sqrt(sigma2.s)) + rnorm(n.effect, 0, sqrt(vi))
#qplot(Zr, 1/sqrt(vi))

dat <- data.frame(yi = Zr, vi = vi, sei = sqrt(vi), xi = xi, ni = n.sample, prec = 1 / sqrt(vi), wi = 1/vi, zi = Zr/sqrt(vi))

rows <- 1:nrow(dat)
expected <- which(1/dat$sei < 5 & dat$yi < 0.25)
unexpected <- which(1/dat$sei > 4.7 & dat$yi > 0.25)

col_point <- ifelse(rows %in% expected, "red", ifelse(rows %in% unexpected, "blue", "black"))

dat$col_point <- col_point

#https://stackoverflow.com/questions/50012553/combining-plots-created-by-r-base-lattice-and-ggplot2
# saving base plot as an object https://www.andrewheiss.com/blog/2016/12/08/save-base-graphics-as-pseudo-objects-in-r/

mod_ra <- rma(yi, vi, data = dat)
mod_fe <- rma(yi, vi, data = dat, method = "FE")

# margin controlling
#par(mar=c(5,4,0,0) + 0.1)

# DL for sunset plot and enhanced counter - making it - 0.01 < p < 0.05 

# a
pdf(NULL)
dev.control(displaylist="enable")
par(mar=c(4,4,0.1,0) + 0.1)
funnel(dat$yi, dat$vi, ni = dat$ni, yaxis="ni",
       xlim = c(-3, 3),
       refline=mod_ra$beta, xlab = "Effect size (Zr)") 
a <- recordPlot()
invisible(dev.off())


# b
pdf(NULL)
dev.control(displaylist="enable")
par(mar=c(4,4,0.1,0) + 0.1)
funnel(mod_ra, yaxis="seinv", col = col_point,  
       ylim = c(1, 12), xlim = c(-3, 3),
       ylab = "Precison (1/SE)", xlab = "Effect size (Zr)")
legend(x = 1.4, y = 12, legend = c("expected", "","unexpected"), pch = c(19, 0, 19), col = c("red", "grey83", "blue"), bty = "n")
b <- recordPlot()
invisible(dev.off())


# c
pdf(NULL)
dev.control(displaylist="enable")
par(mar=c(4,4,0.1,0) + 0.1)
funnel(mod_ra, 
       yaxis = "sei", 
       xlim = c(-3, 3),
       level = c(95, 99), 
       shade = c("white", "gray55"), 
       refline = 0, legend = F, 
       ylab = "Standard error (SE)", xlab = "Effect size (Zr)")
legend(x = 1, y = 0, legend = c("0.01 < p < 0.05"), pch = c(15), col = c("gray55"), bty = "n")
c <- recordPlot()
invisible(dev.off())

# d
d <- viz_sunset(dat[,c("yi", "sei")], 
                power_contours = "continuous", 
                contours = T,
                power_stats = F,
                xlab = "Effect size (Zr)",
                ylab = "Standard error (SE)")


# e
# meta-regression (random-effects model)
mod_re1 <- rma(yi, vi, mod = ~ xi, data = dat)


pdf(NULL)
dev.control(displaylist="enable")
par(mar=c(4,4,0.1,0) + 0.1)
funnel(mod_re1, 
       yaxis = "sei", 
       xlim = c(-3, 3), ylim = c(0, 1),
       #level = c(95, 99), 
       #shade = c("white", "gray75"), 
       refline = 0, legend = F,  ylab = "Standard error (SE)", xlab = "Standardized residuls (Zr)")
#legend(x = 1, y = 0, legend = c("0.01 < p < 0.05", ""), pch = c(15, 0), col = c("gray75", "white"), bg = "white")
e <- recordPlot()
invisible(dev.off())

# f

# 
mod <- metagen(TE = yi, seTE = sqrt(vi) , data = dat)

pdf(NULL)
dev.control(displaylist="enable")
par(mar=c(4,4,0.1,0) + 0.1)
#radial.rma(mod_fe, xlim = c(0, 12.5), zlab = "Z score", xlab = "Precision (1/SE)") 
#legend(1,1, "test", bty = "n")
radial(mod, level = 0.95, pch = 19,  xlab = "Precision (1/SE)", ylab = "Z score")
abline(a = 0, b = 0.1908, lwd = 1.5)
f <- recordPlot()
invisible(dev.off())

# fig 3
fig3 <- (ggdraw(a) + ggdraw(b)) /(ggdraw(c) + ggdraw(d))/ (plot_grid(e) + ggdraw(f)) + plot_annotation(tag_levels = 'a')

fig3
Code for Fig. 4
# creating data with publication bias

dat2 <- dat[dat$col_point != "red", ]

# meta-analysis
mod_ra2 <- rma(yi, vi, data = dat2)

# egger regression (the same as in S2)
egger1 <- lm(zi ~ prec, data = dat2)
egger2 <- lm(yi ~ sei, weight = wi, data = dat2)

# data for time-lag bias
set.seed(123)
position <- sample(1:nrow(dat2), size = 15)

dat3 <- dat2[sort(position), ]

sorting <- c(12, 13, 14, 3, 4, 9, 8, 5, 10, 11,  6, 7, 2, 15, 1)

dat3 <- dat3[sorting, ]        
dat3$year <- c(2000, 2001, 2003, 2005, 2006, 2007, 2008, 2009, 2010, 2012, 2013, 2014, 2016, 2018, 2019)

# cumlatie meta-analysis
cum <- rma(yi, vi, data=dat3)
cum_ma <- cumul(cum)
#forest(cum_ma, xlab = "Overall estimate (Zr)")


# meta-regression

mod_re2 <- rma(yi, vi, mod = ~ year, data = dat3)

# funnel
taf <- trimfill(mod_ra2)

# Plotting from here

p1 <-  ggplot(dat2, aes(prec, zi)) + geom_point() +
  geom_hline(yintercept = 0, linetype = "dashed") + 
  geom_hline(yintercept = egger1$coefficients[[1]]) +
  #geom_smooth(method = "lm") + 
  labs(x = "Precision (1/SE)", 
       y = "Z score")

p2 <- ggplot(dat2, aes(sei, yi)) + geom_point() +
  # geom_smooth(method = "lm") + 
  geom_hline(yintercept = 0, linetype = "dashed") + 
  geom_abline(intercept = egger2$coefficients[[1]], slope = egger2$coefficients[[2]]) +
  labs(x = "Standard error (SE)", 
       y = "Effect size (Zr)")

# c and d
# probably 15 data points for cumulative meta-analyses

cum <- rma(yi, vi, data=dat3)
cum_ma <- cumul(cum)

# p3
pdf(NULL)
dev.control(displaylist="enable")
par(mar=c(4,4,0.1,0) + 0.1)
forest(cum_ma, xlab = "Overall estimate (Zr)")
p3 <- recordPlot()
invisible(dev.off())

# p4
p4 <- ggplot(dat3, aes(x = year, y = yi, size = prec)) +
  geom_hline(yintercept = 0, linetype = "dashed") + 
  geom_abline(intercept = mod_re2$beta[[1]], slope = mod_re2$beta[[2]]) +
  geom_point(shape = 21, fill = "grey90") + 
  labs(x = "Publication year", y = "Effect size (Zr)", size ="Precision (1/SE)") + 
  guides(fill = "none", colour = "none") +
  theme(legend.position = c(0, 0.15), legend.justification = c(0, 1)) +
  theme(legend.direction = "horizontal") +
  # theme(legend.background = element_rect(fill = "white", colour = "black")) +
  theme(legend.background = element_blank()) +
  theme(axis.text.y = element_text(size = 10, colour = "black", hjust = 0.5, angle = 90))

# p5
pdf(NULL)
dev.control(displaylist="enable")
par(mar=c(4,4,0.1,0) + 0.1)
funnel(taf, yaxis="seinv", col = col_point,  estimator="R0",
       ylim = c(1, 12), 
       #xlim = c(-3, 3),
       ylab = "Precison (1/SE)", xlab = "Effect size (Zr)")
p5 <- recordPlot()
invisible(dev.off())

# p6
pdf(NULL)
dev.control(displaylist="enable")
par(mar=c(4,4,0.1,0) + 0.1)
funnel(taf, yaxis="sei", col = col_point,  estimator="R0",
       #xlim = c(-3, 3),
       ylab = "Standard error (SE)", xlab = "Effect size (Zr)")
p6 <- recordPlot()
invisible(dev.off())


# e and f
# maybe use the same datasets as Fig 3

# fig 4
fig4 <- (plot_grid(p1) + plot_grid(p2)) /(ggdraw(p3) + plot_grid(p4))/(plot_grid(p5) + plot_grid(p6)) + plot_annotation(tag_levels = 'a')

fig4
Code for Fig. 5
# dmetr

#devtools::install_github("MathiasHarrer/dmetar")
#library(dmetar)

####################
# preparation#######
####################

# chanting the pcurve function in dmetar so fonts are large enough to see
pcurve2 <- function (x, effect.estimation = FALSE, N, dmin = 0, dmax = 1) 
{
    metaobject = x
    rm(x)
    if (!(class(metaobject)[1] %in% c("metagen", "metabin", "metacont", 
        "metacor", "metainc", "meta", "metaprop"))) {
        for (i in 1:length(colnames(metaobject))) {
            te.exists = FALSE
            if (colnames(metaobject)[i] == "TE") {
                te.exists = TRUE
                break
            }
            else {
            }
        }
        for (i in 1:length(colnames(metaobject))) {
            sete.exists = FALSE
            if (colnames(metaobject)[i] == "seTE") {
                sete.exists = TRUE
                break
            }
            else {
            }
        }
        for (i in 1:length(colnames(metaobject))) {
            studlab.exists = FALSE
            if (colnames(metaobject)[i] == "studlab") {
                studlab.exists = TRUE
                break
            }
            else {
            }
        }
        if (te.exists == FALSE | sete.exists == FALSE | studlab.exists == 
            FALSE) {
            stop("x must be a meta-analysis object generated by meta functions or a data.frame with columns labeled studlab, TE, and seTE.")
        }
    }
    options(scipen = 999)
    zvalues.input = abs(metaobject$TE/metaobject$seTE)
    getncp.f = function(df1, df2, power) {
        error = function(ncp_est, power, x, df1, df2) pf(x, df1 = df1, 
            df2 = df2, ncp = ncp_est) - (1 - power)
        xc = qf(p = 0.95, df1 = df1, df2 = df2)
        return(uniroot(error, c(0, 1000), x = xc, df1 = df1, 
            df2 = df2, power = power)$root)
    }
    getncp.c = function(df, power) {
        xc = qchisq(p = 0.95, df = df)
        error = function(ncp_est, power, x, df) pchisq(x, df = df, 
            ncp = ncp_est) - (1 - power)
        return(uniroot(error, c(0, 1000), x = xc, df = df, power = power)$root)
    }
    getncp = function(family, df1, df2, power) {
        if (family == "f") 
            ncp = getncp.f(df1 = df1, df2 = df2, power = power)
        if (family == "c") 
            ncp = getncp.c(df = df1, power = power)
        return(ncp)
    }
    percent <- function(x, digits = 0, format = "f", ...) {
        paste(formatC(100 * x, format = format, digits = digits, 
            ...), "%", sep = "")
    }
    pbound = function(p) pmin(pmax(p, 0.00000000000000022), 1 - 
        0.00000000000000022)
    prop33 = function(pc) {
        prop = ifelse(family == "f" & p < 0.05, 1 - pf(qf(1 - 
            pc, df1 = df1, df2 = df2), df1 = df1, df2 = df2, 
            ncp = ncp33), NA)
        prop = ifelse(family == "c" & p < 0.05, 1 - pchisq(qchisq(1 - 
            pc, df = df1), df = df1, ncp = ncp33), prop)
        prop
    }
    stouffer = function(pp) sum(qnorm(pp), na.rm = TRUE)/sqrt(sum(!is.na(pp)))
    zvalues.input = paste("z=", zvalues.input, sep = "")
    filek = "input"
    raw = zvalues.input
    raw = tolower(raw)
    ktot = length(raw)
    k = seq(from = 1, to = length(raw))
    stat = substring(raw, 1, 1)
    test = ifelse(stat == "r", "t", stat)
    family = test
    family = ifelse(test == "t", "f", family)
    family = ifelse(test == "z", "c", family)
    par1 = str_locate(raw, "\\(")[, 1]
    par2 = str_locate(raw, "\\)")[, 1]
    comma = str_locate(raw, ",")[, 1]
    eq = str_locate(raw, "=")[, 1]
    df = as.numeric(ifelse(test == "t", substring(raw, par1 + 
        1, par2 - 1), NA))
    df1 = as.numeric(ifelse(test == "f", substring(raw, par1 + 
        1, comma - 1), NA))
    df1 = as.numeric(ifelse(test == "z", 1, df1))
    df1 = as.numeric(ifelse(test == "t", 1, df1))
    df1 = as.numeric(ifelse(test == "c", substring(raw, par1 + 
        1, par2 - 1), df1))
    df2 = as.numeric(ifelse(test == "f", substring(raw, comma + 
        1, par2 - 1), NA))
    df2 = as.numeric(ifelse(test == "t", df, df2))
    equal = abs(as.numeric(substring(raw, eq + 1)))
    value = ifelse((stat == "f" | stat == "c"), equal, NA)
    value = ifelse(stat == "r", (equal/(sqrt((1 - equal^2)/df2)))^2, 
        value)
    value = ifelse(stat == "t", equal^2, value)
    value = ifelse(stat == "z", equal^2, value)
    p = ifelse(family == "f", 1 - pf(value, df1 = df1, df2 = df2), 
        NA)
    p = ifelse(family == "c", 1 - pchisq(value, df = df1), p)
    p = pbound(p)
    ksig = sum(p < 0.05, na.rm = TRUE)
    khalf = sum(p < 0.025, na.rm = TRUE)
    if (ksig <= 2) {
        stop("Two or less significant (p<0.05) effect sizes were detected, so p-curve analysis cannot be conducted.")
    }
    ppr = as.numeric(ifelse(p < 0.05, 20 * p, NA))
    ppr = pbound(ppr)
    ppr.half = as.numeric(ifelse(p < 0.025, 40 * p, NA))
    ppr.half = pbound(ppr.half)
    ncp33 = mapply(getncp, df1 = df1, df2 = df2, power = 1/3, 
        family = family)
    pp33 = ifelse(family == "f" & p < 0.05, 3 * (pf(value, df1 = df1, 
        df2 = df2, ncp = ncp33) - 2/3), NA)
    pp33 = ifelse(family == "c" & p < 0.05, 3 * (pchisq(value, 
        df = df1, ncp = ncp33) - 2/3), pp33)
    pp33 = pbound(pp33)
    prop25 = 3 * prop33(0.025)
    prop25.sig = prop25[p < 0.05]
    pp33.half = ifelse(family == "f" & p < 0.025, (1/prop25) * 
        (pf(value, df1 = df1, df2 = df2, ncp = ncp33) - (1 - 
            prop25)), NA)
    pp33.half = ifelse(family == "c" & p < 0.025, (1/prop25) * 
        (pchisq(value, df = df1, ncp = ncp33) - (1 - prop25)), 
        pp33.half)
    pp33.half = pbound(pp33.half)
    Zppr = stouffer(ppr)
    Zpp33 = stouffer(pp33)
    Zppr.half = stouffer(ppr.half)
    Zpp33.half = stouffer(pp33.half)
    p.Zppr = pnorm(Zppr)
    p.Zpp33 = pnorm(Zpp33)
    p.Zppr.half = pnorm(Zppr.half)
    p.Zpp33.half = pnorm(Zpp33.half)
    main.results = as.numeric(c(ktot, ksig, khalf, Zppr, p.Zppr, 
        Zpp33, p.Zpp33, Zppr.half, p.Zppr.half, Zpp33.half, p.Zpp33.half))
    prop25.obs = sum(p < 0.025)/sum(p < 0.05)
    binom.r = 1 - pbinom(q = prop25.obs * ksig - 1, prob = 0.5, 
        size = ksig)
    binom.33 = ppoibin(kk = prop25.obs * ksig, pp = prop25[p < 
        0.05])
    binomial = c(mean(prop25.sig), prop25.obs, binom.r, binom.33)
    cleanp = function(p) {
        p.clean = round(p, 4)
        p.clean = substr(p.clean, 2, 6)
        p.clean = paste0("= ", p.clean)
        if (p < 0.0001) 
            p.clean = " < .0001"
        if (p > 0.9999) 
            p.clean = " > .9999"
        return(p.clean)
    }
    if (khalf == 0) {
        Zppr.half = "N/A"
        p.Zppr.half = "=N/A"
        Zpp33.half = "N/A"
        p.Zpp33.half = "=N/A"
    }
    if (khalf > 0) {
        Zppr.half = round(Zppr.half, 2)
        Zpp33.half = round(Zpp33.half, 2)
        p.Zppr.half = cleanp(p.Zppr.half)
        p.Zpp33.half = cleanp(p.Zpp33.half)
    }
    Zppr = round(Zppr, 2)
    Zpp33 = round(Zpp33, 2)
    p.Zppr = cleanp(p.Zppr)
    p.Zpp33 = cleanp(p.Zpp33)
    binom.r = cleanp(binom.r)
    binom.33 = cleanp(binom.33)
    powerfit = function(power_est) {
        ncp_est = mapply(getncp, df1 = df1, df2 = df2, power = power_est, 
            family = family)
        pp_est = ifelse(family == "f" & p < 0.05, (pf(value, 
            df1 = df1, df2 = df2, ncp = ncp_est) - (1 - power_est))/power_est, 
            NA)
        pp_est = ifelse(family == "c" & p < 0.05, (pchisq(value, 
            df = df1, ncp = ncp_est) - (1 - power_est))/power_est, 
            pp_est)
        pp_est = pbound(pp_est)
        return(stouffer(pp_est))
    }
    fit = c()
    fit = abs(powerfit(0.051))
    for (i in 6:99) fit = c(fit, abs(powerfit(i/100)))
    mini = match(min(fit, na.rm = TRUE), fit)
    hat = (mini + 4)/100
    x.power = seq(from = 5, to = 99)/100
    get.power_pct = function(pct) {
        z = qnorm(pct)
        error = function(power_est, z) powerfit(power_est) - 
            z
        return(uniroot(error, c(0.0501, 0.99), z)$root)
    }
    p.power.05 = pnorm(powerfit(0.051))
    p.power.99 = pnorm(powerfit(0.99))
    if (p.power.05 <= 0.95) 
        power.ci.lb = 0.05
    if (p.power.99 >= 0.95) 
        power.ci.lb = 0.99
    if (p.power.05 > 0.95 && p.power.99 < 0.95) 
        power.ci.lb = get.power_pct(0.95)
    if (p.power.05 <= 0.05) 
        power.ci.ub = 0.05
    if (p.power.99 >= 0.05) 
        power.ci.ub = 0.99
    if (p.power.05 > 0.05 && p.power.99 < 0.05) 
        power.ci.ub = get.power_pct(0.05)
    power_results = c(power.ci.lb, hat, power.ci.ub)
    gcdf1 = prop33(0.01)
    gcdf2 = prop33(0.02)
    gcdf3 = prop33(0.03)
    gcdf4 = prop33(0.04)
    green1 = mean(gcdf1, na.rm = TRUE) * 3
    green2 = mean(gcdf2 - gcdf1, na.rm = TRUE) * 3
    green3 = mean(gcdf3 - gcdf2, na.rm = TRUE) * 3
    green4 = mean(gcdf4 - gcdf3, na.rm = TRUE) * 3
    green5 = mean(1/3 - gcdf4, na.rm = TRUE) * 3
    green = 100 * c(green1, green2, green3, green4, green5)
    ps = ceiling(p[p < 0.05] * 100)/100
    blue = c()
    for (i in c(0.01, 0.02, 0.03, 0.04, 0.05)) blue = c(blue, 
        sum(ps == i, na.rm = TRUE)/ksig * 100)
    red = c(20, 20, 20, 20, 20)
    x = c(0.01, 0.02, 0.03, 0.04, 0.05)
    par(mar = c(6, 5.5, 1.5, 3))
    moveup = max(max(blue[2:5]) - 66, 0)
    ylim = c(0, 105 + moveup)
    legend.top = 100 + moveup
    plot(x, blue, type = "l", col = "dodgerblue2", main = "", 
        lwd = 2, xlab = "", ylab = "", xaxt = "n", yaxt = "n", 
        xlim = c(0.01, 0.051), ylim = ylim, bty = "L", las = 1, 
        axes = F)
    x_ = c(".01", ".02", ".03", ".04", ".05")
    axis(1, at = x, labels = x_)
    y_ = c("0%", "25%", "50%", "75%", "100%")
    y = c(0, 25, 50, 75, 100)
    axis(2, at = y, labels = y_, las = 1, cex.axis = 1.2)
    mtext("Percentage of test results", font = 2, side = 2, line = 3.85, 
        cex = 1.25)
    mtext("p            ", font = 4, side = 1, line = 2.3, cex = 1.25)
    mtext(" -value", font = 2, side = 1, line = 2.3, cex = 1.5)
    points(x, blue, type = "p", pch = 20, bg = "dodgerblue2", 
        col = "dodgerblue2")
    text(x + 0.00075, blue + 3.5, percent(round(blue)/100), col = "black", 
        cex = 0.75)
    lines(x, red, type = "l", col = "firebrick2", lwd = 1.25, 
        lty = 3)
    lines(x, green, type = "l", col = "springgreen4", lwd = 1.5, 
        lty = 5)
    tab1 = 0.017
    tab2 = tab1 + 0.0015
    gap1 = 9
    gap2 = 4
    font.col = "gray44"
    text.blue = paste0("Power estimate: ", percent(hat), ", CI(", 
        percent(power.ci.lb), ",", percent(power.ci.ub), ")")
    text(tab1, legend.top, adj = 0, cex = 0.85, bquote("Observed " * 
        italic(p) * "-curve"))
    text(tab2, legend.top - gap2, adj = 0, cex = 0.68, text.blue, 
        col = font.col)
    text.red = bquote("Tests for right-skewness: " * italic(p) * 
        ""[Full] ~ .(p.Zppr) * ",  " * italic(p) * ""[Half] ~ 
        .(p.Zppr.half))
    text(tab1, legend.top - gap1, adj = 0, cex = 0.85, "Null of no effect")
    text(tab2, legend.top - gap1 - gap2, adj = 0, cex = 0.68, 
        text.red, col = font.col)
    text.green = bquote("Tests for flatness: " * italic(p) * 
        ""[Full] ~ .(p.Zpp33) * ",  " * italic(p) * ""[half] ~ 
        .(p.Zpp33.half) * ",  " * italic(p) * ""[Binomial] ~ 
        .(binom.33))
    text(tab1, legend.top - 2 * gap1, adj = 0, cex = 0.85, "Null of 33% power")
    text(tab2, legend.top - 2 * gap1 - gap2, adj = 0, cex = 0.68, 
        text.green, col = font.col)
    segments(x0 = tab1 - 0.005, x1 = tab1 - 0.001, y0 = legend.top, 
        y1 = legend.top, col = "dodgerblue2", lty = 1, lwd = 1.5)
    segments(x0 = tab1 - 0.005, x1 = tab1 - 0.001, y0 = legend.top - 
        gap1, y1 = legend.top - gap1, col = "firebrick2", lty = 3, 
        lwd = 1.5)
    segments(x0 = tab1 - 0.005, x1 = tab1 - 0.001, y0 = legend.top - 
        2 * gap1, y1 = legend.top - 2 * gap1, col = "springgreen4", 
        lty = 2, lwd = 1.5)
    rect(tab1 - 0.0065, legend.top - 2 * gap1 - gap2 - 3, tab1 + 
        0.032, legend.top + 3, border = "gray85")
    msgx = bquote("Note: The observed " * italic(p) * "-curve includes " * 
        .(ksig) * " statistically significant (" * italic(p) * 
        " < .05) results, of which " * .(khalf) * " are " * italic(p) * 
        " < .025.")
    mtext(msgx, side = 1, line = 4, cex = 0.9, adj = 0)
    kns = ktot - ksig
    if (kns == 0) 
        ns_msg = "There were no non-significant results entered."
    if (kns == 1) 
        ns_msg = bquote("There was one additional result entered but excluded from " * 
            italic(p) * "-curve because it was " * italic(p) * 
            " > .05.")
    if (kns > 1) 
        ns_msg = bquote("There were " * .(kns) * " additional results entered but excluded from " * 
            italic(p) * "-curve because they were " * italic(p) * 
            " > .05.")
    mtext(ns_msg, side = 1, line = 4.75, cex = 0.9, adj = 0)
    table_calc = data.frame(raw, p, ppr, ppr.half, pp33, pp33.half, 
        qnorm(ppr), qnorm(ppr.half), qnorm(pp33), qnorm(pp33.half))
    headers1 = c("Entered statistic", "p-value", "ppr", "ppr half", 
        "pp33%", "pp33 half", "Z-R", "Z-R half", "Z-33", "z-33 half")
    table_calc = setNames(table_calc, headers1)
    headers2 = c("p-value", "Observed (blue)", "Power 33% (Green)", 
        "Flat (Red)")
    table_figure = setNames(data.frame(x, blue, green, red), 
        headers2)
    dropk = function(pp, k, droplow) {
        pp = pp[!is.na(pp)]
        n = length(pp)
        pp = sort(pp)
        if (k == 0) 
            ppk = pp
        if (droplow == 1 & k > 0) {
            ppk = (pp[(1 + k):n])
            ppmin = min(pp[k], k/(n + 1))
            ppk = (ppk - ppmin)/(1 - ppmin)
        }
        if (droplow == 0 & k > 0) {
            ppk = pp[1:(n - k)]
            ppmax = max(pp[n - k + 1], (n - k)/(n + 1))
            ppk = ppk/ppmax
        }
        ppk = pmax(ppk, 0.00001)
        ppk = pmin(ppk, 0.99999)
        Z = sum(qnorm(ppk))/sqrt(n - k)
        return(pnorm(Z))
    }
    droplow.r = droplow.33 = drophigh.r = drophigh.33 = c()
    for (i in 0:(round(ksig/2) - 1)) {
        droplow.r = c(droplow.r, dropk(pp = ppr, k = i, droplow = 1))
        drophigh.r = c(drophigh.r, dropk(pp = ppr, k = i, droplow = 0))
        droplow.33 = c(droplow.33, dropk(pp = pp33, k = i, droplow = 1))
        drophigh.33 = c(drophigh.33, dropk(pp = pp33, k = i, 
            droplow = 0))
    }
    if (khalf > 0) {
        droplow.halfr = drophigh.halfr = c()
        for (i in 0:(round(khalf/2) - 1)) {
            droplow.halfr = c(droplow.halfr, dropk(pp = ppr.half, 
                k = i, droplow = 1))
            drophigh.halfr = c(drophigh.halfr, dropk(pp = ppr.half, 
                k = i, droplow = 0))
        }
    }
    plotdrop = function(var, col) {
        k = length(var)
        plot(0:(k - 1), var, xlab = "", ylab = "", type = "b", 
            yaxt = "n", xaxt = "n", main = "", cex.main = 1.15, 
            ylim = c(0, 1), col = col)
        points(0, var[1], pch = 19, cex = 1.6)
        abline(h = 0.05, col = "red")
        axis(2, c(0.05, 2:9/10), labels = c(".05", ".2", ".3", 
            ".4", ".5", "6", "7", ".8", ".9"), las = 1, cex.axis = 1.5)
        axis(1, c(0:(k - 1)), las = 1, cex.axis = 1.4)
    }
    if (effect.estimation == TRUE) {
        ci.to.t = function(TE, lower, upper, n) {
            z.to.d = function(z, n) {
                d = (2 * z)/sqrt(n)
                return(abs(d))
            }
            ci.to.p = function(est, lower, upper) {
                SE = (upper - lower)/(2 * 1.96)
                z = abs(est/SE)
                p = exp(-0.717 * z - 0.416 * z^2)
                return(p)
            }
            d.to.t = function(d, n) {
                df = n - 2
                t = (d * sqrt(df))/2
                return(t)
            }
            p = ci.to.p(TE, lower, upper)
            z = abs(qnorm(p/2))
            d = z.to.d(z, n)
            t = d.to.t(d, n)
            return(t)
        }
        loss = function(t_obs, df_obs, d_est) {
            t_obs = abs(t_obs)
            p_obs = 2 * (1 - pt(t_obs, df = df_obs))
            t.sig = subset(t_obs, p_obs < 0.05)
            df.sig = subset(df_obs, p_obs < 0.05)
            ncp_est = sqrt((df.sig + 2)/4) * d_est
            tc = qt(0.975, df.sig)
            power_est = 1 - pt(tc, df.sig, ncp_est)
            p_larger = pt(t.sig, df = df.sig, ncp = ncp_est)
            ppr = (p_larger - (1 - power_est))/power_est
            KSD = ks.test(ppr, punif)$statistic
            return(KSD)
        }
        if (missing(N)) {
            stop("If 'effect.estimation=TRUE', argument 'N' must be provided.")
        }
        if (length(N) != length(metaobject$TE)) {
            stop("N must be of same length as the number of studies contained in x.")
        }
        lower = metaobject$TE - (metaobject$seTE * 1.96)
        upper = metaobject$TE + (metaobject$seTE * 1.96)
        t_obs = ci.to.t(metaobject$TE, lower, upper, N)
        df_obs = N - 2
        loss.all = c()
        di = c()
        for (i in 0:((dmax - dmin) * 100)) {
            d = dmin + i/100
            di = c(di, d)
            options(warn = -1)
            loss.all = c(loss.all, loss(df_obs = df_obs, t_obs = t_obs, 
                d_est = d))
            options(warn = 0)
        }
        imin = match(min(loss.all), loss.all)
        dstart = dmin + imin/100
        dhat = optimize(loss, c(dstart - 0.1, dstart + 0.1), 
            df_obs = df_obs, t_obs = t_obs)
        options(warn = -0)
        plot(di, loss.all, xlab = "Effect size\nCohen-d", ylab = "Loss (D stat in KS test)", 
            ylim = c(0, 1), main = "How well does each effect size fit? (lower is better)")
        points(dhat$minimum, dhat$objective, pch = 19, col = "red", 
            cex = 2)
        text(dhat$minimum, dhat$objective - 0.08, paste0("p-curve's estimate of effect size:\nd=", 
            round(dhat$minimum, 3)), col = "red")
    }
    main.results = round(main.results, 3)
    ktotal = round(main.results[1])
    k.sign = round(main.results[2])
    k.025 = round(main.results[3])
    skew.full.z = main.results[4]
    skew.full.p = main.results[5]
    flat.full.z = main.results[6]
    flat.full.p = main.results[7]
    skew.half.z = main.results[8]
    skew.half.p = main.results[9]
    flat.half.z = main.results[10]
    flat.half.p = main.results[11]
    skew.binomial.p = round(binomial[3], 3)
    flat.binomial.p = round(binomial[4], 3)
    skewness = c(skew.binomial.p, skew.full.z, skew.full.p, skew.half.z, 
        skew.half.p)
    flatness = c(flat.binomial.p, flat.full.z, flat.full.p, flat.half.z, 
        flat.half.p)
    colnames.df = c("pBinomial", "zFull", "pFull", "zHalf", "pHalf")
    rownames.df = c("Right-skewness test", "Flatness test")
    pcurveResults = rbind(skewness, flatness)
    colnames(pcurveResults) = colnames.df
    rownames(pcurveResults) = rownames.df
    power_results = round(power_results, 3)
    powerEstimate = power_results[2]
    powerLower = power_results[1]
    powerUpper = power_results[3]
    Power = as.data.frame(cbind(powerEstimate, powerLower, powerUpper))
    rownames(Power) = ""
    if (skew.half.p < 0.05 | (skew.half.p < 0.1 & skew.full.p < 
        0.1)) {
        presence.ev = "yes"
    }
    else {
        presence.ev = "no"
    }
    if (flat.full.p < 0.05 | (flat.half.p < 0.1 & flat.binomial.p < 
        0.1)) {
        absence.ev = "yes"
    }
    else {
        absence.ev = "no"
    }
    PlotData = round(table_figure, 3)
    table_calc[, 1] = NULL
    colnames(table_calc) = c("p", "ppSkewFull", "ppSkewHalf", 
        "ppFlatFull", "ppFlatHalf", "zSkewFull", "zSkewHalf", 
        "zFlatFull", "zFlatHalf")
    Input = cbind(metaobject$TE, round(table_calc, 3))
    rownames(Input) = paste(1:length(metaobject$TE), metaobject$studlab)
    colnames(Input)[1] = "TE"
    if (effect.estimation == TRUE) {
        dEstimate = round(dhat$minimum, 3)
        return.list = list(pcurveResults = pcurveResults, Power = Power, 
            PlotData = PlotData, Input = Input, EvidencePresent = presence.ev, 
            EvidenceAbsent = absence.ev, kInput = ktot, kAnalyzed = k.sign, 
            kp0.25 = k.025, dEstimate = dEstimate, I2 = metaobject$I2, 
            class.meta.object = class(metaobject)[1])
        class(return.list) = c("pcurve", "effect.estimation")
    }
    else {
        return.list = list(pcurveResults = pcurveResults, Power = Power, 
            PlotData = PlotData, Input = Input, EvidencePresent = presence.ev, 
            EvidenceAbsent = absence.ev, kInput = ktot, kAnalyzed = k.sign, 
            kp0.25 = k.025, I2 = metaobject$I2, class.meta.object = class(metaobject)[1])
        class(return.list) = c("pcurve", "no.effect.estimation")
    }
    cat("  ", "\n")
    invisible(return.list)
    return.list
}

# this is required for pcurve function
library(poibin)

#########################
# Drawing starts here ###
#########################

p_dat <- data.frame("studlab" = as.factor(1:nrow(dat2)), "TE" = dat2$yi, "seTE" = dat2$sei)
#pcurve(p_dat)

pdf(NULL)
dev.control(displaylist="enable")
par(mar=c(4,4,0,0) + 0.1, cex = 1.2) # NOTE: here is where you can change the font size for at least some parts of the graph. E.g. add cex = 2 - this did ont seem to work well. 
invisible(pcurve2(p_dat))
#mtext(msgx, side = 1, line = 4, cex = 2, adj = 0)
plot<- recordPlot()
invisible(dev.off())

# turuning the base plot into ggplot
plot <- ggdraw(plot)

#dat2

model <- rma(yi, vi = vi, data = dat2, method = "ML", mod = ~ xi)

# only sel1 and sel3 are used
#sel0 <- selmodel(model, type = "beta")
sel1 <- selmodel(model, type="halfnorm", prec="sei", scaleprec=FALSE)
#sel2 <- selmodel(model, type="negexp",   prec="sei", scaleprec=FALSE)
sel3 <- selmodel(model, type="logistic", prec="sei", scaleprec=FALSE)
#sel4 <- selmodel(model, type="power",    prec="sei",  scaleprec=FALSE)
sel1b <- selmodel(model, type="halfnorm")
#sel2b <- selmodel(model, type="negexp")
sel3b <- selmodel(model, type="logistic")
#sel4b <- selmodel(model, type="power")

# step function 
sel5 <- selmodel(model, type="stepfun", steps=c(0.05, 0.10, 0.50, 1.00))
#sel6 <- selmodel(model, type="stepfun", steps=c(0.001, 0.01, 0.05, 0.10, 0.25, 0.50, 0.75, 1))
sel7 <- selmodel(model, type="stepfun", steps=c(0.05, 1))

#plot(sel5, ylim = c(0,1))
#plot(sel6, add=TRUE, col="red", scale = T)
#plot(sel7, add=TRUE, col="red")
#legend(x = 0.5, y = 1, legend = c("3 cutpoints", "","1 cutpoint (3 PMS)"), lty =c(1, 0, 1), col = c("black", "", "red"), bty = "n")

# plotting from here
pA <- plot +  theme(plot.margin=unit(c(-1,0,-1,0),"cm"))

# B
pdf(NULL)
dev.control(displaylist="enable")
par(mar=c(4,4,0.1,0) + 0.1)
plot(sel1)
plot(sel3, add=TRUE, col="red")
plot(sel1b, add=TRUE, lty = "dotted")
plot(sel3b, add=TRUE, col="red", lty = "dotted")
legend(x = 0.6, y = 1, legend = c("half-normal", "","logistic"), lty =c(1, 0, 1), col = c("black", "", "red"), bty = "n")
pB <- recordPlot()
invisible(dev.off())

# C
pdf(NULL)
dev.control(displaylist="enable")
par(mar=c(4,4,0.1,0) + 0.1)
plot(sel5, ylim = c(0,1))
plot(sel7, add=TRUE, col="red", lty = 3)
legend(x = 0.5, y = 1, legend = c("3 cutpoints", "","1 cutpoint (3 PSM)"), lty =c(1, 0, 1), col = c("black", "", "red"), bty = "n")
pC <- recordPlot()
invisible(dev.off())

# Fig 5
fig5 <- pA /(ggdraw(pB) + ggdraw(pC)) + plot_annotation(tag_levels = 'a')

fig5
Code for Fig. 6 (+ Fig 6 redrawn)
########################
# Zr data creation #####
#######################

set.seed(777)
# setting parameters
n.study  <- 70
sigma2.s <- 0.05
sigma2.u <- 0.05
beta1 <- 0.1
beta2 <- - 0.05
# using negative binomial we get good spread of sample size
n.sample <- rnbinom(n.study, mu = 30, size = 0.2) + 4

# the number of effect size per study
set.seed(777777)
n.es.per.s <- rpois(n.study,3) + 1
#sum(n.es.per.s)

n.effect <- sum(n.es.per.s)
# variance for Zr
vi <- 1/(rep(n.sample, n.es.per.s) - 3)

# In the text, we have two moderators
# moderator x 1 - study level
x1j <- rnorm(n.study)
# moderator x 2 - effect isze level
x2i <- rnorm(n.effect)

# study position
place <- rep(1:n.study, n.es.per.s)

# there is underling overall effect to r = 0.3 or Zr = 0.3095196
Zr <- 0 + rnorm(n.study, 0, sqrt(sigma2.s))[place] + 
  rnorm(n.effect, 0, sqrt(sigma2.u)) + rnorm(n.effect, 0, sqrt(vi))

#qplot(Zr, 1/sqrt(vi))

datA <- data.frame(yi = Zr, vi = vi, sei = sqrt(vi), x1 = x1j[place], x2 = x2i, ni = n.sample[place], prec = 1 / sqrt(vi), wi = 1/vi, zi = Zr/sqrt(vi), studyID = place, effectID = 1:n.effect)


# cutting publication mbias like stuff
expected <- c(which(1/datA$sei < 5.5 & datA$yi < 0.2), which(1/datA$sei < 3 & datA$yi < 0.7))

datB <- datA[-expected, ]

#qplot(x = yi, y = 1/sqrt(vi), data = datB)

mod_ma <- rma.mv(yi, vi, mod = ~ sqrt(vi), random = list(~ 1 | studyID, ~1 | effectID), data = datB)

mod_mb <- rma.mv(yi, vi, mod = ~ vi, random = list(~ 1 | studyID, ~1 | effectID), data = datB)

#summary(mod_ma)
#summary(mod_mb)


# creating curve lines
x = seq(0, 1, by = 0.001)
#x <- x[-1000]
y =  mod_mb$beta[[1]] + sqrt(x)* mod_mb$beta[[2]]

vi_curve <- tibble(x = x, y = y)

############################
# lnRR - data creation #####
############################

set.seed(777)
# setting parameters
n.study  <- 30
sigma2.s <- 0.01
sigma2.u <- 0.005
beta1 <- 0.1
beta2 <- -0.01
# using negative binomial we get good spread of sample size
n.sample <- rnbinom(n.study, mu = 40, size = 0.5) + 4

# the number of effect size per study
set.seed(7777)
n.es.per.s <- rpois(n.study,3) + 1
#sum(n.es.per.s)

# sample size
n.effect <- sum(n.es.per.s)

# cv for each study

cv <- sample(seq(0.3, 0.35,by = 0.001), n.effect, replace = T)

rep_sample <- rep(n.sample, times = n.es.per.s)

# variance for lnRR
# balanced design
vi <- (2*cv^2)/rep_sample


# In the text, we have two moderators
# moderator x 1 - study level
x1j <- rnorm(n.study)
# moderator x 2 - effect isze level
x2i <- rnorm(n.effect)

# study position

pos <- rep(1:n.study, n.es.per.s)

# there is underling overall effect to lnRR = 0.2

dat3 <- data.frame(vi = vi, sei = sqrt(vi), x1 = x1j[pos], x2 = x2i, ni = n.sample[pos], prec = 1 / sqrt(vi), wi = 1/vi, studyID = pos, effectID = 1:n.effect)

# ni here is sample size per group - we have the same N for control and treatment groups
dat3$n_tilde <- (dat3$ni^2)/dat3$ni*2
# 

# M matrix (V = VCV)
sigma <- make_VCV_matrix(dat3, "vi", "studyID", "effectID", rho = 0)

lnRR<- 0.3 + beta1*x1j[pos] + beta2*x2i + rnorm(n.study, 0, sqrt(sigma2.s))[pos] + 
  rnorm(n.effect, 0, sqrt(sigma2.u)) +  MASS::mvrnorm(1, rep(0, n.effect), sigma)

dat3$yi <- lnRR

mod_ml <- rma.mv(yi, vi, mod = ~ x1 + x2, random = list(~ 1 | studyID, ~1 | effectID), data = dat3)

# residuals - standardized
#summary(mod_ml)
#funnel(mod_ml, yaxis="seinv", col = inferno(25)[pos])

# residual marginal
residm <- dat3$yi - predict(mod_ml)[[1]]
vi_residm <- vi + predict(mod_ml)[[2]]^2 # adding prediction errors 


# residual conditional 1 & 2 + its error
blups <- ranef(mod_ml)

study_effect <- blups$studyID[[1]][pos]
vi_study <- (blups$studyID[[2]][pos])^2

residc1 <- dat3$yi - (predict(mod_ml)[[1]] + study_effect)
vi_residc1 <- vi_residm + vi_study

effect_effect <- blups$effectID[[1]]
vi_effect <- blups$effectID[[1]]^2

residc2 <- dat3$yi - (predict(mod_ml)[[1]] + study_effect + effect_effect)
vi_residc2 <- vi_residm + vi_study + vi_effect


# plotting
# Panel A
mod1 <- rma(yi, vi, data = dat3)
pdf(NULL)
dev.control(displaylist="enable")
par(mar=c(4,4,0.1,0) + 0.1)
funnel(mod1, col =inferno(25)[pos],
       ylim = c(0, 0.26), xlim = c(-0.6, 0.8),
       ylab = "Standard error (SE)", xlab = "Effect size (lnRR)")
pa <- recordPlot()
invisible(dev.off())

#Panel A+

pdf(NULL)
dev.control(displaylist="enable")
par(mar=c(4,4,0.1,0) + 0.1)
funnel(dat3$yi, dat3$vi, ni = dat3$n_tilde, yaxis="ni",
       refline=mod1$beta, 
       col =inferno(25)[pos],
       ylim = c(0, 250), xlim = c(-0.6, 0.8),
      ylab = bquote("Effective sample size " (tilde(n))), xlab = "Effect size (lnRR)") 
pa2 <- recordPlot()
invisible(dev.off())


# Panel B
pdf(NULL)
dev.control(displaylist="enable")
par(mar=c(4,4,0.1,0) + 0.1)
funnel (residm, vi = vi_residm, yaxis = "sei",  col = inferno(25)[pos],  
        ylim = c(0, 0.26), xlim = c(-0.6, 0.8),
        ylab = "Standard error (SE)", xlab = "Residuals marginal (lnRR)")
pb <- recordPlot()
invisible(dev.off())

# Panel B+
pdf(NULL)
dev.control(displaylist="enable")
par(mar=c(4,4,0.1,0) + 0.1)
funnel(residm, vi = vi_residm, ni = dat3$n_tilde, yaxis="ni",
       #refline=mod1$beta, 
       col =inferno(25)[pos],
       ylim = c(0, 250), xlim = c(-0.6, 0.8),
       ylab = bquote("Effective sample size " (tilde(n))), xlab = "Residual marginal (lnRR)") 
pb2 <- recordPlot()
invisible(dev.off())


# Panel C
pdf(NULL)
dev.control(displaylist="enable")
par(mar=c(4,4,0.1,0) + 0.1)
funnel(residc1, vi = vi_residc1, yaxis = "sei",  col = inferno(25)[pos],
       ylim = c(0, 0.26), xlim = c(-0.6, 0.8),
       ylab = "Standard error (SE)", 
       xlab = "Residuals conditional 1 (lnRR)")
pc <- recordPlot()
invisible(dev.off())

# Panel C+
pdf(NULL)
dev.control(displaylist="enable")
par(mar=c(4,4,0.1,0) + 0.1)
funnel(residc1, vi = vi_residc1, ni = dat3$n_tilde, yaxis="ni",
       #refline=mod1$beta, 
       col =inferno(25)[pos],
       ylim = c(0, 250), xlim = c(-0.6, 0.8),
       ylab = bquote("Effective sample size " (tilde(n))), xlab = "Residuals conditional 1 (lnRR)") 
pc2 <- recordPlot()
invisible(dev.off())


# Panel D
pdf(NULL)
dev.control(displaylist="enable")
par(mar=c(4,4,0.1,0) + 0.1)
funnel(residc2, vi = vi_residc2, yaxis = "sei",  col = inferno(25)[pos],
       ylim = c(0, 0.26), xlim = c(-0.6, 0.8),
       ylab = "Standard error (SE)", 
       xlab = "Residuals conditional 2 (lnRR)")
pd <- recordPlot()
invisible(dev.off())

# Panel D+
pdf(NULL)
dev.control(displaylist="enable")
par(mar=c(4,4,0.1,0) + 0.1)
funnel(residc2, vi = vi_residc2, ni = dat3$n_tilde, yaxis="ni",
       #refline=mod1$beta, 
       col =inferno(25)[pos],
       ylim = c(0, 250), xlim = c(-0.6, 0.8),
       ylab = bquote("Effective sample size " (tilde(n))), xlab = "Residuals conditional 2 (lnRR)") 
pd2 <- recordPlot()
invisible(dev.off())


# Panel E
pe <- ggplot(datB, aes(sei, yi)) + geom_point() + 
  geom_line(data = vi_curve, mapping = aes(x = x, y = y, col = "red")) +
  #geom_point(aes(col = studyID)) +
  # geom_smooth(method = "lm") + 
  geom_hline(yintercept = 0, linetype = "dashed") + 
  geom_abline(intercept = mod_ma$beta[[1]], slope = mod_ma$beta[[2]]) +
  xlim(0, 1) + ylim(-1.5, 2.5) + 
  labs(x = "Standard error (SE)", y = "Effect size (Zr)")+ 
  theme(legend.position = "none")
# F

# Variance
pf <- ggplot(datB, aes(vi, yi)) + geom_point() + 
  #geom_point(aes(col = studyID)) +
  # geom_smooth(method = "lm") + 
  geom_hline(yintercept = 0, linetype = "dashed") + 
  geom_abline(intercept = mod_mb$beta[[1]], slope = mod_mb$beta[[2]], col = "red") +
  xlim(0, 1) + ylim(-1.5, 2.5) + 
  labs(x = "Sampling variance", y = "Effect size (Zr)")

# fig6
fig6 <- (ggdraw(pa) + ggdraw(pb)) /(ggdraw(pc) + ggdraw(pd))/(plot_grid(pe) + plot_grid(pf)) + plot_annotation(tag_levels = 'a')

fig6

#fig6+

fig6_extra <-  (ggdraw(pa2) + ggdraw(pb2)) /(ggdraw(pc2) + ggdraw(pd2)) + plot_annotation(tag_levels = 'a')

fig6_extra
Code for Fig. 7

There is no code for Fig. 7 (created in PowerPoint)

Acknowledgement

SN is extremely grateful to Russell Lenth for making his emmeans work for metafor objects.

R Session Information

sessionInfo() %>% pander::pander()

R version 4.2.0 (2022-04-22 ucrt)

Platform: x86_64-w64-mingw32/x64 (64-bit)

locale: LC_COLLATE=English_Germany.utf8, LC_CTYPE=English_Germany.utf8, LC_MONETARY=English_Germany.utf8, LC_NUMERIC=C and LC_TIME=English_Germany.utf8

attached base packages: grid, stats, graphics, grDevices, utils, datasets, methods and base

other attached packages: emmeans(v.1.7.4-1), ggpubr(v.0.4.0), viridis(v.0.6.2), viridisLite(v.0.4.0), ggplotify(v.0.1.0), meta(v.5.5-0), metaviz(v.0.3.1), cowplot(v.1.1.1), orchaRd(v.2.0), readxl(v.1.4.0), lme4(v.1.1-29), here(v.1.0.1), patchwork(v.1.1.1), kableExtra(v.1.3.4), knitr(v.1.39), ape(v.5.6-2), rotl(v.3.0.12), openxlsx(v.4.2.5), pander(v.0.6.5), gt(v.0.7.0), metafor(v.3.4-0), metadat(v.1.2-0), Matrix(v.1.4-1), forcats(v.0.5.1), stringr(v.1.4.0), dplyr(v.1.0.9), purrr(v.0.3.4), readr(v.2.1.2), tidyr(v.1.2.0), tibble(v.3.1.7), ggplot2(v.3.3.6), tidyverse(v.1.3.1) and R.rsp(v.0.44.0)

loaded via a namespace (and not attached): minqa(v.1.2.4), colorspace(v.2.0-3), ggsignif(v.0.6.3), ellipsis(v.0.3.2), rprojroot(v.2.0.3), estimability(v.1.3), fs(v.1.5.2), rstudioapi(v.0.13), farver(v.2.1.0), mvtnorm(v.1.1-3), fansi(v.1.0.3), lubridate(v.1.8.0), mathjaxr(v.1.6-0), xml2(v.1.3.3), codetools(v.0.2-18), splines(v.4.2.0), R.methodsS3(v.1.8.2), jsonlite(v.1.8.0), nloptr(v.2.0.1), broom(v.0.8.0), dbplyr(v.2.1.1), R.oo(v.1.25.0), BiocManager(v.1.30.18), rentrez(v.1.2.3), compiler(v.4.2.0), httr(v.1.4.3), backports(v.1.4.1), assertthat(v.0.2.1), fastmap(v.1.1.0), cli(v.3.3.0), htmltools(v.0.5.2), prettyunits(v.1.1.1), tools(v.4.2.0), coda(v.0.19-4), gtable(v.0.3.0), glue(v.1.6.2), Rcpp(v.1.0.8.3), carData(v.3.0-5), cellranger(v.1.1.0), jquerylib(v.0.1.4), vctrs(v.0.4.1), svglite(v.2.1.0), nlme(v.3.1-157), xfun(v.0.31), rvest(v.1.0.2), CompQuadForm(v.1.4.3), lifecycle(v.1.0.1), pacman(v.0.5.1), rstatix(v.0.7.0), XML(v.3.99-0.10), MASS(v.7.3-57), scales(v.1.2.0), hms(v.1.1.1), parallel(v.4.2.0), yaml(v.2.3.5), gridExtra(v.2.3), yulab.utils(v.0.0.5), sass(v.0.4.1), stringi(v.1.7.6), highr(v.0.9), boot(v.1.3-28), zip(v.2.2.0), commonmark(v.1.8.0), rlang(v.1.0.2), pkgconfig(v.2.0.3), systemfonts(v.1.0.4), rncl(v.0.8.6), evaluate(v.0.15), lattice(v.0.20-45), labeling(v.0.4.2), tidyselect(v.1.1.2), magrittr(v.2.0.3), R6(v.2.5.1), generics(v.0.1.2), DBI(v.1.1.2), pillar(v.1.7.0), haven(v.2.5.0), withr(v.2.5.0), abind(v.1.4-5), car(v.3.0-13), modelr(v.0.1.8), crayon(v.1.5.1), utf8(v.1.2.2), tzdb(v.0.3.0), rmarkdown(v.2.14), progress(v.1.2.2), reprex(v.2.0.1), digest(v.0.6.29), webshot(v.0.5.3), xtable(v.1.8-4), R.cache(v.0.15.0), numDeriv(v.2016.8-1.1), gridGraphics(v.0.5-1), R.utils(v.2.11.0), munsell(v.0.5.0) and bslib(v.0.3.1)

References

Begg, C. B., & Mazumdar, M. (1994a). Operating Characteristics of a Rank Correlation Test for Publication Bias. Biometrics, 50(4), 1088. https://doi.org/10.2307/2533446
Begg, C. B., & Mazumdar, M. (1994b). Operating characteristics of a rank correlation test for publication bias. Biometrics, 1088–1101.
Chamberlain, S. A., Hovick, S. M., Dibble, C. J., Rasmussen, N. L., Van Allen, B. G., Maitner, B. S., Ahern, J. R., Bell-Dereske, L. P., Roy, C. L., Meza-Lopez, M.others. (2012). Does phylogeny matter? Assessing the impact of phylogenetic information in ecological meta-analysis. Ecology Letters, 15(6), 627–636.
Cinar, O., Nakagawa, S., & Viechtbauer, W. (2020). Phylogenetic multilevel meta-analysis: A simulation study on the importance of modeling the phylogeny.
Citkowicz, M., & Vevea, J. L. (2017). A parsimonious weight function for modeling publication bias. Psychological Methods, 22(1), 28.
Copas, J. B., & Li, H. G. (1997). Inference for Non-random Samples. Journal of the Royal Statistical Society: Series B (Statistical Methodology), 59(1), 55–95. https://doi.org/10.1111/1467-9868.00055
Duval, S., & Tweedie, R. (2000a). A nonparametric “trim and fill” method of accounting for publication bias in meta-analysis. Journal of the American Statistical Association, 95(449), 89–98.
Duval, S., & Tweedie, R. (2000b). Trim and fill: A simple funnel-plot–based method of testing and adjusting for publication bias in meta-analysis. Biometrics, 56(2), 455–463.
Garamszegi, L. Z., Markó, G., & Herczeg, G. (2012). A meta-analysis of correlated behaviours with implications for behavioural syndromes: Mean effect size, publication bias, phylogenetic effects and the role of mediator variables. Evolutionary Ecology, 26(5), 1213–1235.
Hedges, L. V. (1984). Estimation of Effect Size under Nonrandom Sampling: The Effects of Censoring Studies Yielding Statistically Insignificant Mean Differences. Journal of Educational Statistics, 9(1), 61–85. https://doi.org/10.3102/10769986009001061
Hinchliff, C. E., Smith, S. A., Allman, J. F., Burleigh, J. G., Chaudhary, R., Coghill, L. M., Crandall, K. A., Deng, J., Drew, B. T., Gazis, R.others. (2015). Synthesis of phylogeny and taxonomy into a comprehensive tree of life. Proceedings of the National Academy of Sciences, 112(41), 12764–12769.
Iyengar, S., & Greenhouse, J. B. (1988). Selection Models and the File Drawer Problem. Statistical Science, 3(1), 109–117. https://doi.org/10.1214/ss/1177013012
Knapp, G., & Hartung, J. (2003). Improved tests for a random effects meta-regression with a single covariate. Statistics in Medicine, 22(17), 2693–2710.
Marks-Anglin, A., & Chen, Y. (2020). A historical review of publication bias. Research Synthesis Methods, 11(6), 725–742.
Michonneau, F., Brown, J. W., & Winter, D. J. (2016). Rotl: An r package to interact with the open tree of life data. Methods in Ecology and Evolution, 7(12), 1476–1481.
Murphy, Grace EP, & Romanuk, T. N. (2014). A meta‐analysis of declines in local species richness from human disturbances. Ecology and Evolution, 4(1), 91–103.
Nakagawa, S., Lagisz, M., O’Dea, R. E., Rutkowska, J., Yang, Y., Noble, D., & Senior, A. M. (2020). The orchard plot: Cultivating a forest plot for use in ecology, evolution and beyond. Research Synthesis Methods. https://doi.org/10.1002/jrsm.1424
Nakagawa, S., & Santos, E. S. (2012). Methodological issues and advances in biological meta-analysis. Evolutionary Ecology, 26(5), 1253–1274.
Noble, D. W., Lagisz, M., O’Dea, R. E., & Nakagawa, S. (2017). Nonindependence and sensitivity analyses in ecological and evolutionary meta-analyses. Molecular Ecology, 26(9), 2410–2425.
O’Dea, Rose E, Jennions, Michael D, Koricheva, J, Lagisz, Malgorzata, Noble, Daniel W, Parker, Timothy H, & Nakagawa, S. (2021). Estimated and perceived reporting quality of meta-analyses in ecology and evolution (O. S. Framework, Ed.). http://doi.org/10.17605/OSF.IO/2XPFG
Orwin, R. G. (1983). A Fail-Safe N for Effect Size in Meta-Analysis. Journal of Educational Statistics, 8(2), 157. https://doi.org/10.2307/1164923
Paradis, E., & Schliep, K. (2019). Ape 5.0: An environment for modern phylogenetics and evolutionary analyses in r. Bioinformatics, 35(3), 526–528.
Peters, J. L., Sutton, A. J., Jones, D. R., Abrams, K. R., & Rushton, L. (2007). Performance of the trim and fill method in the presence of publication bias and between-study heterogeneity. Statistics in Medicine, 26(25), 4544–4562.
Rees, J. A., & Cranston, K. (2017). Automated assembly of a reference taxonomy for phylogenetic data synthesis. Biodiversity Data Journal, 5.
Rosenberg, M. S. (2005). The file-drawer problem revisited: A general weighted method for calculating fail-safe numbers in meta-analysis. Evolution, 59(2), 464–468. https://doi.org/10.1111/j.0014-3820.2005.tb01004.x
Rosenthal, R. (1979). The file drawer problem and tolerance for null results. Psychological Bulletin, 86(3), 638–641. https://doi.org/10.1037/0033-2909.86.3.638
Senior, A. M., Grueber, C. E., Kamiya, T., Lagisz, M., O’dwyer, K., Santos, E. S., & Nakagawa, S. (2016). Heterogeneity in ecological and evolutionary meta-analyses: Its magnitude and implications. Ecology, 97(12), 3293–3299.
Senior, A. M., Viechtbauer, W., & Nakagawa, S. (2020). Revisiting and expanding the meta-analysis of variation: The log coefficient of variation ratio, lnCVR. Research Synthesis Methods. https://doi.org/10.1002/jrsm.1423
Stanley, T. D., & Doucouliagos, H. (2014). Meta-regression approximations to reduce publication selection bias. Research Synthesis Methods, 5(1), 60–78.
Sutton, A. J. (2009). Publication Bias. In The handbook of research synthesis and meta-analysis (2nd ed.).
Viechtbauer, W. (2010). Conducting meta-analyses in R with the metafor package. Journal of Statistical Software, 36(3), 1–48. http://www.jstatsoft.org/v36/i03/
Vivea, J. L., Coburn, K., & Sutton, A. J. (2019). Publication bias. In The handbook of research synthesis and meta-analysis (3rd ed., pp. 383–429). Russell Sage Foundation.
Wang, M. C., & Bushman, B. J. (1998). Using the normal quantile plot to explore meta-analytic data sets. Psychological Methods, 3(1), 46–54. https://doi.org/10.1037/1082-989X.3.1.46
LS0tDQp0aXRsZTogTWV0aG9kcyBmb3IgdGVzdGluZyBwdWJsaWNhdGlvbiBiaWFzIGluIGVjb2xvZ2ljYWwgYW5kIGV2b2x1dGlvbmFyeSBtZXRhLWFuYWx5c2VzDQphdXRob3I6IFNoaW5pY2hpIE5ha2FnYXdhLCBNYWxnb3J6YXRhIExhZ2lzeiwgTWljaGFlbCBELiBKZW5uaW9ucywgSnVsaWEgS29yaWNoZXZhLCBEYW5pZWwgVy5BLiBOb2JsZSwgVGltb3RoeSBILiBQYXJrZXIsIEFsZnJlZG8gU2FuY2hlei1Ub2phciwgWWVmZW5nIFlhbmcsIFJvc2UgRS4gTydEZWENCmRhdGU6ICdgciBmb3JtYXQoU3lzLnRpbWUoKSwgIiVkICVCLCAlWSIpYCcNCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBkZXB0aDogNQ0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICB0b2NfZGVwdGg6IDUNCiAgcGRmX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQpzdWJ0aXRsZTogU3VwcGxlbWVudGFyeSBJbmZvcm1hdGlvbiAtIEFwcGVuZGl4IFMxLVM1IGluY2x1ZGluZyBmaWd1cmUgY29kZQ0KYmlibGlvZ3JhcGh5OiByZWZlcmVuY2VzLmJpYg0KYmlibGlvLXN0eWxlOiAiYXBhbGlrZSINCmNzbDogamFuZS5jc2wNCiNsaW5rLWNpdGF0aW9uczogeWVzDQpub2NpdGU6IHwgDQogIEB2aWVjaHRiYXVlcjIwMTBjb25kdWN0aW5nLCBAbmFrYWdhd2EyMDEybWV0aG9kb2xvZ2ljYWwsIEBzZW5pb3IyMDE2aGV0ZXJvZ2VuZWl0eSwgQG1pY2hvbm5lYXUyMDE2cm90bCwgQHBhcmFkaXMyMDE5YXBlLCBAbmFrYWdhd2EyMDE5b3JjaGFyZCwgIEBzZW5pb3IyMDIwcmV2aXNpdGluZywgQG5vYmxlMjAxN25vbmluZGVwZW5kZW5jZSwgQGdhcmFtc3plZ2kyMDEybWV0YSwgQGNpbmFyMjAyMHBoeWxvZ2VuZXRpYywgQGNoYW1iZXJsYWluMjAxMmRvZXMsIEBoaW5jaGxpZmYyMDE1c3ludGhlc2lzLCBAcmVlczIwMTdhdXRvbWF0ZWQsIEBiZWdnMTk5NG9wZXJhdGluZywgQGR1dmFsMjAwMHRyaW0sIEBkdXZhbDIwMDBub25wYXJhbWV0cmljLCBAc3RhbmxleTIwMTRtZXRhLCBAcGV0ZXJzMjAwN3BlcmZvcm1hbmNlLCBAbWFya3MyMDIwaGlzdG9yaWNhbCwgQGNpdGtvd2ljejIwMTdwYXJzaW1vbmlvdXMsIEBtdXJwaHkyMDE0bWV0YSwgQG9kZWEyMDIxcHJpc21hLCBAd2FuZ191c2luZ18xOTk4LCBAaGVkZ2VzX2VzdGltYXRpb25fMTk4NCwgQHJvc2VudGhhbF9maWxlXzE5NzksIEBiZWdnX29wZXJhdGluZ18xOTk0LCBAaXllbmdhcl9zZWxlY3Rpb25fMTk4OCwgQHJvc2VuYmVyZ19maWxlLWRyYXdlcl8yMDA1LCBAY29wYXNfaW5mZXJlbmNlXzE5OTcsIEBvcndpbl9mYWlsLXNhZmVfMTk4MywgQHZpdmVhX3B1YmxpY2F0aW9uXzIwMTksIEBzdXR0b25fcHVibGljYXRpb25fMjAwOSAsIEBzdXR0b25fcHVibGljYXRpb25fMjAwOSwgQGtuYXBwMjAwM2ltcHJvdmVkLCBzdGFubGV5MjAxN2xpbWl0YXRpb25zDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGUgPSBGQUxTRX0NCiMga25pdHIgc2V0dGluZw0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICAjbWVzc2FnZSA9IEZBTFNFLA0KICB3YXJuaW5nID0gRkFMU0UsICMgbm8gd2FybmluZ3MNCiAgdGlkeSA9IFRSVUUsDQogIGNhY2hlID0gVFJVRQ0KKQ0KDQojIGNsZWFuaW5nIHVwDQpybShsaXN0ID0gbHMoKSkNCg0KIyMgbnVtYmVycyA+PSAxMF41IHdpbGwgYmUgZGVub3RlZCBpbiBzY2llbnRpZmljIG5vdGF0aW9uLCBhbmQgcm91bmRlZCB0byAyIGRpZ2l0cw0Kb3B0aW9ucyhkaWdpdHM9MykNCmBgYA0KDQpgYGB7ciBpbnN0YWxsIGRldmVsb3BpbmcgcGFja2FnZXMsIGV2YWwgPSBGQUxTRX0NCiMgIyBpbnN0YWxsIHRoZSBvcmNoYVJkIHBhY2thZ2UNCiMgaW5zdGFsbC5wYWNrYWdlcygiZGV2dG9vbHMiKQ0KIyBpbnN0YWxsLnBhY2thZ2VzKCJyZW1vdGVzIikNCiMgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJpdGNoeXNoaW4vb3JjaGFyZF9wbG90Iiwgc3ViZGlyID0gIm9yY2hhUmQiLCBmb3JjZSA9IFRSVUUsIGJ1aWxkX3ZpZ25ldHRlcyA9IFRSVUUpDQojIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigiTWF0aGlhc0hhcnJlci9kbWV0YXIiKQ0KIyBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoImRhbmllbDFub2JsZS9tZXRhQWlkUiIpDQoNCiMgdGhlc2UgcGFja2FnZXMgbmVlZCBiZSBvYnRhaW5lZCBmcm9tIGdpdGh1YiBub3QgZnJvbSBjcmFuDQojcmVtb3Rlczo6aW5zdGFsbF9naXRodWIoInJ2bGVudGgvZW1tZWFucyIsIGRlcGVuZGVuY2llcyA9IFRSVUUsIGJ1aWxkX29wdHMgPSAiIikNCiMgcmVtb3Rlczo6aW5zdGFsbF9naXRodWIoInd2aWVjaHRiL21ldGFmb3IiKQ0KI2RldnRvb2xzOjppbnN0YWxsX2dpdGh1YigiTWF0aGlhc0hhcnJlci9kbWV0YXIiKQ0KIyBAVE8tRE8gLSAgSSBkbyBub3QgdGhpbmsgaXQgaXMgd29ya2luZyB5ZXQNCiMjcmVtb3Rlczo6aW5zdGFsbF9naXRodWIoInJsZXN1ci9rbGlwcHkiKQ0KYGBgDQoNCmBgYHtyIGtsaXBweSwgZWNobz1GQUxTRSwgaW5jbHVkZT1UUlVFfQ0KIyBAVE8tRE86IHBhY2thZ2Ug4oCYa2xpcHB54oCZIGlzIG5vdCBhdmFpbGFibGUgKGZvciBSIHZlcnNpb24gNC4wLjIpDQoja2xpcHB5OjprbGlwcHkodG9vbHRpcF9tZXNzYWdlID0gJ0NsaWNrIHRvIENvcHkgQ29kZScsIHRvb2x0aXBfc3VjY2VzcyA9ICdEb25lJywgcG9zaXRpb24gPSAncmlnaHQnLCBjb2xvciA9ICJyZWQiKQ0KYGBgDQoNCmBgYHtyIGxvYWRpbmcgcGFja2FnZXMsIGVjaG8gPSBGQUxTRSwgZXZhbCA9IFRSVUV9DQojIG5lZWQgcGFjbWFuIHRvIGluc3RhbGwgdGhlIHJlc3QNCiMgaW5zdGFsbC5wYWNrYWdlcygicGFjbWFuIikNCg0KIyByZXF1aXJlZCBwYWNrYWdlcw0KcGFjbWFuOjpwX2xvYWQoUi5yc3AsDQogICAgICAgICAgICAgICB0aWR5dmVyc2UsDQogICAgICAgICAgICAgICBtZXRhZm9yLA0KICAgICAgICAgICAgICAgZ3QsDQogICAgICAgICAgICAgICBwYW5kZXIsDQogICAgICAgICAgICAgICBzdHJpbmdyLA0KICAgICAgICAgICAgICAgb3Blbnhsc3gsDQogICAgICAgICAgICAgICByb3RsLA0KICAgICAgICAgICAgICAgYXBlLA0KICAgICAgICAgICAgICAga25pdHIsDQogICAgICAgICAgICAgICBrYWJsZUV4dHJhLA0KICAgICAgICAgICAgICAgcGF0Y2h3b3JrLA0KICAgICAgICAgICAgICAgaGVyZSwNCiAgICAgICAgICAgICAgIGxtZTQsDQogICAgICAgICAgICAgICByZWFkeGwsDQogICAgICAgICAgICAgICBvcmNoYVJkLA0KICAgICAgICAgICAgICAgcGF0Y2h3b3JrLA0KICAgICAgICAgICAgICAgY293cGxvdCwNCiAgICAgICAgICAgICAgIG1ldGF2aXosDQogICAgICAgICAgICAgICBtZXRhLA0KICAgICAgICAgICAgICAgZ2dwbG90aWZ5LA0KICAgICAgICAgICAgICAgZ3JpZCwNCiAgICAgICAgICAgICAgICNkbWV0YXIsDQogICAgICAgICAgICAgICB2aXJpZGlzLA0KICAgICAgICAgICAgICAgbWV0YUFpZFIsDQogICAgICAgICAgICAgICBnZ3B1YnIsDQogICAgICAgICAgICAgICAja2xpcHB5LA0KICAgICAgICAgICAgICAgZW1tZWFucw0KKQ0KDQojIGN1c3RvbSBmdW5jdGlvbiBmb3IgZXh0cmFjdGluZyBtZWFuIGFuZCBDSSBmcm9tIGVhY2ggbWV0YWZvciBtb2RlbA0KZXN0aW1hdGVzLkNJIDwtIGZ1bmN0aW9uKG1vZGVsKXsNCiAgZGIubWYgPC0gZGF0YS5mcmFtZShtb2RlbCRiLHJvdy5uYW1lcyA9IDE6bnJvdyhtb2RlbCRiKSkNCiAgZGIubWYgPC0gY2JpbmQoZGIubWYsbW9kZWwkY2kubGIsbW9kZWwkY2kudWIscm93Lm5hbWVzKG1vZGVsJGIpKQ0KICBuYW1lcyhkYi5tZikgPC0gYygibWVhbiIsImxvd2VyIiwidXBwZXIiLCJlc3RpbWF0ZSIpDQogIHJldHVybihkYi5tZlssYygiZXN0aW1hdGUiLCJtZWFuIiwibG93ZXIiLCJ1cHBlciIpXSkNCn0NCg0KIyBjdXN0b20gZnVuY3Rpb24gZm9yIGV4dHJhY3RpbmcgbWVhbiBhbmQgQ0kgZm9yIGVtbWVhbnMgKG1hcmdpbmFsaXplZCBtZWFucykgDQplc3RpbWF0ZXMuQ0kyIDwtIGZ1bmN0aW9uKHJlcyl7DQogICAgZGIubWYgPC0gZGF0YS5mcmFtZShzdW1tYXJ5KHJlcylbLDJdLHJvdy5uYW1lcyA9IDE6bGVuZ3RoKCBzdW1tYXJ5KHJlcylbLDJdKSkNCiAgZGIubWYgPC0gY2JpbmQoZGIubWYsc3VtbWFyeShyZXMpWyw1XSxzdW1tYXJ5KHJlcylbLDZdLHBhc3RlMChuYW1lcyhyZXNAbGV2ZWxzKSxzdW1tYXJ5KHJlcylbLDFdICkpDQogIG5hbWVzKGRiLm1mKSA8LSBjKCJtZWFuIiwibG93ZXIiLCJ1cHBlciIsImVzdGltYXRlIikNCiAgcmV0dXJuKGRiLm1mWyxjKCJlc3RpbWF0ZSIsIm1lYW4iLCJsb3dlciIsInVwcGVyIildKQ0KfQ0KYGBgDQoNCiMjIEFwcGVuZGl4IFMxOiBTdXJ2ZXkgb2YgcHVibGljYXRpb24gYmlhcyB0ZXN0cyByZXBvcnRlZCBpbiBlY29sb2d5IGFuZCBldm9sdXRpb24gbWV0YS1hbmFseXNlcw0KDQojIyMgUzEuMTogU3VydmV5IG1ldGhvZA0KDQpUaGUgbWFpbiBvYmplY3RpdmUgb2YgdGhlIGxpdGVyYXR1cmUgc3VydmV5IHdhcyB0byBjYXB0dXJlIHRoZSB0eXBlcyBvZiBwdWJsaWNhdGlvbiBiaWFzIG1ldGhvZHMgcmVjZW50bHkgdXNlZCBpbiB0aGUgZmllbGQgb2YgZWNvbG9neSBhbmQgZXZvbHV0aW9uLiBUaGUgc3VydmV5IHJlcG9ydGVkIGhlcmUgd2FzIGNvbmR1Y3RlZCBhbG9uZ3NpZGUgYSBsYXJnZXIgc3VydmV5IG9uIHJlcG9ydGluZyBzdGFuZGFyZHMgZnJvbSB0aGUgUFJJU01BLUVjb0V2byBwcm9qZWN0IChQcmVmZXJyZWQgUmVwb3J0aW5nIEl0ZW1zIGZvciBTeXN0ZW1hdGljIHJldmlld3MgYW5kIE1ldGEtQW5hbHlzZXMgaW4gRWNvbG9neSBhbmQgRXZvbHV0aW9uYXJ5IEJpb2xvZ3k7IGZ1bGwgZGV0YWlscyBhbmQgbWF0ZXJpYWxzIHByb3ZpZGVkIGluIE8nRGVhIGV0IGFsLiAoMjAyMSkuIFRoZSBzdXJ2ZXkgd2FzIGJhc2VkIG9uIDEwMiBtZXRhLWFuYWx5c2lzIHBhcGVycyBwdWJsaXNoZWQgYmV0d2VlbiAxIEphbnVhcnkgMjAxMCBhbmQgMjUgTWFyY2ggMjAxOS4gV2UgYWltZWQgZm9yIHRoZSBzYW1wbGUgb2YgMTAyIG1ldGEtYW5hbHlzZXMgdG8gYmUgcmVwcmVzZW50YXRpdmUgb2YgcmVjZW50bHkgcHVibGlzaGVkIG1ldGEtYW5hbHlzZXMgaW4gZWNvbG9neSBhbmQgZXZvbHV0aW9uYXJ5IGJpb2xvZ3kgam91cm5hbHMuDQoNCiMjIyMgUzEuMS4xIFJlcHJlc2VudGF0aXZlIFNhbXBsZQ0KDQpUbyBzZWxlY3QgdGhlIHJlcHJlc2VudGF0aXZlIHNhbXBsZSBvZiBtZXRhLWFuYWx5c2lzIHB1YmxpY2F0aW9ucywgd2UgZmlyc3Qgc2VhcmNoZWQgdGhlIFNjb3B1cyBkYXRhYmFzZSBmb3IgcGFwZXJzIHdpdGggKCJtZXRhLWFuYWx5XCoiIE9SICJtZXRhYW5hbHlcKiIgT1IgIm1ldGEtcmVncmVzc2lvbiIpIGluIHRoZSB0aXRsZSwgYWJzdHJhY3QsIG9yIGtleXdvcmRzICh3aGVyZSB0aGUgYXN0ZXJpc2sgYWxsb3dzIGZvciBhbnkgZW5kaW5nIHRvIHRoZSB3b3JkLCBzdWNoIGFzICJtZXRhLWFuYWx5c2VzIiBvciAibWV0YS1hbmFseXNpcyIpLCByZXN0cmljdGVkIHRoZSBkYXRlIHRvIHBhcGVycyBwdWJsaXNoZWQgYWZ0ZXIgMjAwOSwgYW5kIHJlc3RyaWN0ZWQgdGhlIElTU04gKEludGVybmF0aW9uYWwgU3RhbmRhcmQgU2VyaWFsIE51bWJlcikgdG8gam91cm5hbHMgY2xhc3NpZmllZCBhcyAnRWNvbG9neScgYW5kL29yICdFdm9sdXRpb25hcnkgQmlvbG9neScgYnkgdGhlIDIwMTcgcmFua2luZ3Mgb2YgdGhlIElTSSBJbkNpdGVzIEpvdXJuYWwgQ2l0YXRpb24gUmVwb3J0cy4gT24gMjUgTWFyY2ggMjAxOSB0aGlzIHNlYXJjaCByZXR1cm5lZCAxLDY2OCBwYXBlcnMgZnJvbSAxMzQgam91cm5hbHMuDQoNClNlY29uZCwgdGhlIHJldHVybmVkIHBhcGVycyB3ZXJlIGNhdGVnb3Jpc2VkIGFzIGJlaW5nIGZyb20gam91cm5hbHMgbGlzdGVkIGFzICdFY29sb2d5JywgJ0V2b2x1dGlvbicsIG9yICdCb3RoJywgYW5kIHdlIHJlZHVjZWQgdGhlIG51bWJlciBvZiBqb3VybmFscyBhbmQgcGFwZXJzLiBUbyByZWR1Y2UgdGhlIG51bWJlciBvZiBqb3VybmFscyB3ZSBhcnJhbmdlZCBqb3VybmFscyBpbiBkZXNjZW5kaW5nIG9yZGVyIG9mIGZyZXF1ZW5jeSAoaS5lLiB0byBpbmRpY2F0ZSB3aGljaCBqb3VybmFscyBwdWJsaXNoZWQgdGhlIG1vc3QgbWV0YS1hbmFseXNlcykuIEFmdGVyIHJlbW92aW5nIGpvdXJuYWxzIGluIG1vcmUgYXBwbGllZCBzdWItZmllbGRzIChzdWNoIGFzIGVjb2xvZ3kgZWNvbm9taWNzKSwgd2UgcmV0YWluZWQgdGhlIHRvcCAxMCBqb3VybmFscyBjbGFzc2lmaWVkIGFzIGVjb2xvZ3ksIHRoZSB0b3AgMTAgam91cm5hbHMgY2xhc3NpZmllZCBhcyBldm9sdXRpb25hcnkgYmlvbG9neSwgYW5kIHRoZSB0b3AgMTEgam91cm5hbHMgY2xhc3NpZmllZCBhcyBib3RoIGVjb2xvZ3kgYW5kIGV2b2x1dGlvbmFyeSBiaW9sb2d5LiBUaGUgbGlzdCBvZiAzMSByZXRhaW5lZCBqb3VybmFscyBpcyBzaG93biBpbiBUYWJsZSBTMS4gTmV4dCwgd2Ugc2VsZWN0ZWQgMjk3IHN0dWRpZXMgdG8gYmUgc2NyZWVuZWQgZm9yIGluY2x1c2lvbiBpbiB0aGUgc2FtcGxlLCBieSB1c2luZyB0aGUgJ3NhbXBsZScgZnVuY3Rpb24gaW4gUiAodi4gMy41LjE7IFIgQ29yZSBUZWFtLCAyMDE4KSB0byByYW5kb21seSBzZWxlY3QgdXAgdG8gMTcgc3R1ZGllcyBmcm9tIHRoZSBqb3VybmFscyBjbGFzc2lmaWVkIGFzICdFdm9sdXRpb25hcnkgQmlvbG9neScgKDU3IHN0dWRpZXMgdG90YWwpIG9yICdCb3RoJyAoMTUwIHN0dWRpZXMgdG90YWwpLCBhbmQgdXAgdG8gOSBzdHVkaWVzIGZyb20gam91cm5hbHMgY2xhc3NpZmllZCBhcyAnRWNvbG9neScgKDkwIHN0dWRpZXMgdG90YWwpLg0KDQojIyMjIyBUYWJsZSBTMS4xDQoNCkpvdXJuYWxzIHNjcmVlbmVkIGluIG91ciBzZWFyY2ggZm9yIGEgcmVwcmVzZW50YXRpdmUgc2FtcGxlIG9mIG1ldGEtYW5hbHlzZXMgcHVibGlzaGVkIGluIGVjb2xvZ3kgYW5kIGV2b2x1dGlvbmFyeSBiaW9sb2d5LiBJU0kgQ2xhc3NpZmljYXRpb24gaXMgYmFzZWQgb24gdGhlIDIwMTcgSVNJIEluQ2l0ZXMgSm91cm5hbCBDaXRhdGlvbiBSZXBvcnRzLiBUaGUgbnVtYmVyIG9mIHBhcGVycyByZXR1cm5lZCBmcm9tIHRoZSBTY29wdXMgZGF0YWJhc2Ugc2VhcmNoIGlzIGRlc2NyaWJlZCBieSAnTiBoaXRzJywgd2hpbGUgdGhlIG51bWJlciBvZiBzdHVkaWVzIHNlbGVjdGVkIGZvciBzY3JlZW5pbmcgaXMgZGVzY3JpYmVkIGJ5ICdOIHNjcmVlbmVkJy4NCg0KYGBge3J9DQojIGdldHRpbmcgdGhlIGRhdGEgYW5kIGZvcm1hdHRpbmcgc29tZSB2YXJpYWJsZXMgKHR1cm5pbmcgY2hhcmFjdGVyIHZlY3RvcnMgdG8gZmFjdG9ycykNCnJlYWRfZXhjZWwoaGVyZSgiZGF0YS9UYWJsZVMxLnhsc3giKSwgbmEgPSAiTkEiKSAlPiUgDQogICNtdXRhdGVfaWYoaXMuY2hhcmFjdGVyLCBhcy5mYWN0b3IpICU+JSAgDQogIGthYmxlRXh0cmE6OmtibCgpICU+JQ0KICBrYWJsZUV4dHJhOjprYWJsZV9wYXBlcigpICU+JSANCiAga2FibGVFeHRyYTo6a2FibGVfc3R5bGluZygic3RyaXBlZCIsIHBvc2l0aW9uID0gImxlZnQiKQ0KYGBgDQoNCiMjIyMgUzEuMS4yIEluY2x1c2lvbiBjcml0ZXJpYSBhbmQgc2NyZWVuaW5nIG1ldGhvZHMNCg0KVGhlIHNhbXBsZSBvZiAxMDIgbWV0YS1hbmFseXNpcyBwYXBlcnMgbWV0IHRoZSBmb2xsb3dpbmcgZm91ciBpbmNsdXNpb24gY3JpdGVyaWE6ICgxKSB0aGUgc3R1ZHkgYWRkcmVzc2VkIGEgcXVlc3Rpb24gaW4gdGhlIGZpZWxkcyBvZiBlY29sb2d5IGFuZCBldm9sdXRpb25hcnkgYmlvbG9neTsgKDIpIGNsYWltZWQgdG8gcHJlc2VudCByZXN1bHRzIGZyb20gYSBtZXRhLWFuYWx5c2lzOyAoMykgcGVyZm9ybWVkIGEgc2VhcmNoIGZvciwgYW5kIGNvbGxlY3RlZCwgZGF0YSBmcm9tIHRoZSBwcmltYXJ5IGxpdGVyYXR1cmU7ICg0KSB1c2VkIGEgc3RhdGlzdGljYWwgbW9kZWwgdG8gYW5hbHlzZSBlZmZlY3Qgc2l6ZXMgdGhhdCB3ZXJlIGNvbGxlY3RlZCBmcm9tIG11bHRpcGxlIHN0dWRpZXMuIFBhcGVyIHNjcmVlbmluZyB3YXMgY29uZHVjdGVkIGluIHR3byBzdGFnZXMuIEZpcnN0LCB0d28gYXV0aG9ycyAoUk8gYW5kIE1MKSBjb25kdWN0ZWQgcGFyYWxsZWwgYWJzdHJhY3Qgc2NyZWVuaW5nLiBDb25mbGljdGluZyBkZWNpc2lvbnMgd2VyZSBkaXNjdXNzZWQgYW5kIHJlc29sdmVkLiBTZWNvbmQsIDY0JSBvZiBzY3JlZW5lZCBhYnN0cmFjdHMgdW5kZXJ3ZW50IHBhcmFsbGVsIGZ1bGwtdGV4dCBzY3JlZW5pbmcgYnkgUk8gYW5kIE1MLCBpbiBjb25zdWx0YXRpb24gd2l0aCBTTi4NCg0KIyMjIyBTMS4xLjMgQXNzZXNzaW5nIDEwMiBtZXRhLWFuYWx5c2lzIHBhcGVycw0KDQpQYXBlcnMgd2VyZSBpbmRlcGVuZGVudGx5IGFzc2Vzc2VkIGJ5IHNldmVuIGF1dGhvcnMgKFJPLCBETiwgSkssIE1KLCBNTCwgUk8sIFNOLCBhbmQgVFApIGFzIHBhcnQgb2YgYSBsYXJnZXIgc3VydmV5LiBUaGUgb25lIHN1cnZleSBxdWVzdGlvbiBwZXJ0YWluaW5nIHRvIHRoaXMgcHVibGljYXRpb24gYmlhcyBwcm9qZWN0IHdhczogIldoaWNoIHB1YmxpY2F0aW9uIGJpYXMgdGVzdHMgYXJlIHJlcG9ydGVkIGluIHRoZSBwYXBlcj8gKFNlbGVjdCBhbGwgdGhhdCBhcHBseSkiLiBUaGVyZSB3ZXJlIDExIHBvc3NpYmxlIGNob2ljZXMgZm9yIHJlc3BvbmRlbnRzIHRvIHNlbGVjdDogKEEpIEZ1bm5lbCBwbG90cyAoaW5jbHVkaW5nIGNvbnRvdXItZW5oYW5jZWQgZnVubmVsIHBsb3RzKTsgKEIpIE5vcm1hbCBxdWFudGlsZSAoUVEpIHBsb3RzIChXYW5nICYgQnVzaG1hbik7IChDKSBDb3JyZWxhdGlvbi1iYXNlZCB0ZXN0cyAoZS5nLiBCZWdnICYgTWFuenVtZGFyIHJhbmsgY29ycmVsYXRpb24pOyAoRCkgUmVncmVzc2lvbi1iYXNlZCB0ZXN0cyAoZS5nLiBFZ2dlciByZWdyZXNzaW9uIGFuZCBpdHMgdmFyaWFudHMpOyAoRSkgRmlsZSBkcmF3ZXIgbnVtYmVycyBvciBmYWlsLXNhZmUgTiAoUm9zZW50aGFsLCBPcndpbiBvciBSb3NlbmJlcmcgbWV0aG9kKTsgKEYpIFRyaW0tYW5kLWZpbGwgdGVzdHM7IChHKSBQLWN1cnZlLCBQLXVuaWZvcm0gb3IgaXRzIHZhcmlhbnRzOyAoSCkgU2VsZWN0aW9uIChtZXRob2QpIG1vZGVscyAoZS5nLiBDb3BhcywgSGVkZ2VzIG9yIEl5ZW5nYXIgJiBHcmVlbmhvdXNlIG1vZGVsKTsgKEkpIFRpbWUtbGFnIGJpYXMgdGVzdHMgKGUuZy4sIHJlZ3Jlc3Npb24gb3IgY29ycmVsYXRpb24gb24gdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGVmZmVjdCBzaXplcyBhbmQgdGltZSBvciBjdW11bGF0aXZlIG1ldGEtYW5hbHlzaXMpOyAoSikgTm9uZSByZXBvcnRlZCBhbmQgKEspICdPdGhlcicgbWV0aG9kcy4gQWNjb3JkaW5nIHRvIFN1dHRvbiAoMjAwOSkgKHNlZSBhbHNvIFZldmVhIGV0IGFsLiwgMjAxOSksIE1ldGhvZHMgQS1EIGFyZSB0ZXN0cyBkZXRlY3RpbmcgcHVibGljYXRpb24gYmlhcywgd2hlcmVhcyBNZXRob2RzIEUtRiBhcmUgYXNzZXNzaW5nIHRoZSBpbXBhY3Qgb2YgcHVibGljYXRpb24gYmlhcy4NCg0KIyMjIFMxLjIgUmVzdWx0cw0KDQpBbW9uZyB0aGUgMTAyIGFzc2Vzc2VkIHBhcGVycywgMTcuOCUgZGlkIG5vdCByZXBvcnQgYW55IHRlc3RzIG9mIHB1YmxpY2F0aW9uIGJpYXMuIE1vc3QgbWV0YS1hbmFseXNpcyBwYXBlcnMgcmVwb3J0ZWQgb25lIG9yIG1vcmUgdGVzdHMgb2YgcHVibGljYXRpb24gYmlhcyAoMTcuOCUgb2YgYXNzZXNzZWQgcGFwZXJzIGRpZCBub3QgaW5jbHVkZSBhbnkgYXNzZXNzbWVudCBvZiBwdWJsaWNhdGlvbiBiaWFzKS4gVGhlc2UgcmVzdWx0cyBzdWdnZXN0IHRlc3RzIG9mIHB1YmxpY2F0aW9uIGJpYXMgaGF2ZSBiZWNvbWUgbW9yZSBjb21tb24gaW4gcmVjZW50IHllYXJzIGluIGVjb2xvZ3kgYW5kIGV2b2x1dGlvbmFyeSBiaW9sb2d5LCBhcyBvdmVyIGhhbGYgb2Ygb2xkZXIgbWV0YS1hbmFseXNlcyBhc3Nlc3NlZCBieSBOYWthZ2F3YSBhbmQgU2FudG9zICgyMDEyKSBhbmQgS29yaWNoZXZhIGFuZCBHdXJldml0Y2ggKDIwMTQpIGRpZCBub3QgcmVwb3J0IGFueSB0ZXN0cyBvZiBwdWJsaWNhdGlvbiBiaWFzIChhbHRob3VnaCBvdXIgcmVzdWx0cyBhcmUgbm90IGRpcmVjdGx5IGNvbXBhcmFibGUsIGR1ZSB0byB0aGUgZGlmZmVyZW50IHN1cnZleSBtZXRob2RzKS4gU3RpbGwsIGluZmVyZW50aWFsIHRlc3RzIG9mIHB1YmxpY2F0aW9uIGJpYXMgcmVtYWluIHVuY29tbW9uLiBCeSBmYXIgdGhlIG1vc3QgcG9wdWxhciB0ZXN0IG9mIHB1YmxpY2F0aW9uIGJpYXMgd2VyZSBmdW5uZWwgcGxvdHMgKDMyLjQlOyBUYWJsZSBTMiksIHdpdGggYWxsIHJlbWFpbmluZyBtZXRob2RzIHJlcHJlc2VudGVkIGJ5IGZld2VyIHRoYW4gMTUlIG9mIHBhcGVycy4gQWxsIG1ldGhvZHMgZXhjZXB0ICdzZWxlY3Rpb24gbW9kZWxzJyB3ZXJlIHByZXNlbnQgaW4gYXQgbGVhc3Qgb25lIHBhcGVyICh3aXRoICdvdGhlcicgYmVpbmcgc2VsZWN0ZWQgZm9yIGEgd2VpZ2h0ZWQgaGlzdG9ncmFtIHVzZWQgYnkgTG95ZGkgZXQgYWwuICgyMDEzOyBUYWJsZSBTMikuIFRoZSBhYnNlbmNlIG9mIHNlbGVjdGlvbiBtb2RlbCBtZXRob2RzIGNvdWxkIGJlIGJlY2F1c2UgdGhlc2UgbWV0aG9kcyBhcmUgY29tcGFyYXRpdmVseSB0ZWNobmljYWxseSBjaGFsbGVuZ2luZywgb3IgYmVjYXVzZSBlY29sb2dpc3RzIGFuZCBldm9sdXRpb25hcnkgYmlvbG9naXN0cyBhcmUgbm90IHlldCBhd2FyZSBvZiB0aGUgYmVuZWZpdHMgb2YgdGhlc2UgbWV0aG9kcy4NCg0KIyMjIyMgVGFibGUgUzEuMg0KDQpGcmVxdWVuY3kgd2l0aCB3aGljaCBwdWJsaWNhdGlvbiBiaWFzIHRlc3RzIHdlcmUgcmVwb3J0ZWQgaW4gdGhlIDEwMiBtZXRhLWFuYWx5c2lzIHB1YmxpY2F0aW9ucywgcmFua2VkIGluIG9yZGVyIG9mIGRlY3JlYXNpbmcgcG9wdWxhcml0eS4gTm8gdGVzdHMgd2VyZSByZXBvcnRlZCBmb3IgMTcuODAlIG9mIHBhcGVycy4NCg0KYGBge3J9DQojIGdldHRpbmcgdGhlIGRhdGEgYW5kIGZvcm1hdHRpbmcgc29tZSB2YXJpYWJsZXMgKHR1cm5pbmcgY2hhcmFjdGVyIHZlY3RvcnMgdG8gZmFjdG9ycykNCnJlYWRfZXhjZWwoaGVyZSgiZGF0YS9UYWJsZVMyLnhsc3giKSwgbmEgPSAiTkEiKSAlPiUgDQogICNtdXRhdGVfaWYoaXMuY2hhcmFjdGVyLCBhcy5mYWN0b3IpICU+JSAgDQogIGthYmxlRXh0cmE6OmtibCgpICU+JQ0KICBrYWJsZUV4dHJhOjprYWJsZV9wYXBlcigpICU+JSANCiAga2FibGVFeHRyYTo6a2FibGVfc3R5bGluZygic3RyaXBlZCIsIHBvc2l0aW9uID0gImxlZnQiKQ0KYGBgDQoNCiMjIEFwcGVuZGl4IFMyOiBFcXVpdmFsZW5jZSBiZXR3ZWVuIEVxdWF0aW9ucyA4IGFuZCA5DQoNCkFzIGluIHRoZSBtYWluIHRleHQsIEVxdWF0aW9uIDggaXMgYXMgZm9sbG93cyAkJA0Kel97aX0gPSBcYmV0YV97MH0gKyBcYmV0YV97MX1wcmVjX2kgKyBlX2ksXFwNCiQkIHdoZXJlICRlX3tpfSBcc2ltIFxtYXRoY2Fse059KDAsIFxzaWdtYV9lXjIpJC4gV2UgY2FuIHJld3JpdGUgdGhpcyBhczoNCg0KJCQNClxmcmFje3lfe2l9fXtzZV9pfSA9IFxiZXRhX3swfSArIFxiZXRhX3sxfVxsZWZ0KFxmcmFjezF9e3NlX3tpfX1ccmlnaHQpICsgZV9pLFxcDQokJCBJZiB3ZSBtdWx0aXBsZSBib3RoIHNpZGVzIGJ5ICRzZV9pJCwgd2UgaGF2ZToNCg0KJCQNCnlfe2l9ID0gXGJldGFfezB9c2VfaSArIFxiZXRhX3sxfSArIGVfe2l9c2Vfe2l9LA0KJCQNCg0Kd2hpY2ggaXMgYmFzaWNhbGx5IHRoZSBzYW1lLCBpZiAkXGJldGFfMCQgYW5kICRcYmV0YV8xJCBhcmUgc3dhcHBlZCwgYXM6DQoNCiQkDQp5X3tpfSA9IFxiZXRhX3swfSArIFxiZXRhX3sxfXNlX2kgKyBcZXBzaWxvbl9pLA0KJCQgd2hlcmUgJFxlcHNpbG9uX2kgXHNpbSBcbWF0aGNhbHtOfSgwLCB2X2lccGhpKSQgYXMgaW4gRXF1YXRpb24gOS4gV2UgY2FuIHNob3cgdGhpcyB1c2luZyBzaW11bGF0ZWQgZGF0YSBhcyB3ZWxsICh3ZSB1c2UgdGhlIGRhdGEgZm9yIEZpZ3VyZSAzIGFuZCA0KS4gQmVsb3cgdGhlIGZpcnN0IHJlc3VsdCBpcyBmcm9tIEVxdWF0aW9uIDggYW5kIHRoZSBzZWNvbmQgRXF1YXRpb24gOToNCg0KYGBge3J9DQojIGNyZWF0aW5nIGRhdGEgLSB0aGUgc2FtZSBkYXRhIGFzIEZpZ3VyZXMgMyArIDQNCnNldC5zZWVkKDc3Nzc3KQ0KIyBzZXR0aW5nIHBhcmFtZXRlcnMNCm4uZWZmZWN0IDwtIDEwMA0Kc2lnbWEyLnMgPC0gMC4wNQ0KICAgYmV0YTEgPC0gMC4yDQoNCiMgdXNpbmcgbmVnYXRpdmUgYmlub21pYWwgd2UgZ2V0IGEgZ29vZCBzcHJlYWQgb2Ygc2FtcGxlIHNpemVzDQpuLnNhbXBsZSA8LSBybmJpbm9tKG4uZWZmZWN0LCBtdSA9IDMwLCBzaXplID0gMC43KSArIDQNCg0KIyB2YXJpYW5jZSBmb3IgWnINCnZpIDwtIDEvKG4uc2FtcGxlIC0gMykNCg0KIyBtb2RlcmF0b3IgeCAxDQp4aSA8LSBybm9ybShuLmVmZmVjdCkNCg0KIyB0aGVyZSBpcyBhbiBvdmVyYWxsIGVmZmVjdCBvZiByID0gMC4yIChaciA9IDAuMjAzLCB3aGljaCB3ZSBnZXQgZnJvbSB0aGUgYGF0YW5oYCBmdW5jdGlvbikNClpyIDwtIGF0YW5oKDAuMikgKyBiZXRhMSp4aSArIHJub3JtKG4uZWZmZWN0LCAwLCBzcXJ0KHNpZ21hMi5zKSkgKyBybm9ybShuLmVmZmVjdCwgMCwgc3FydCh2aSkpDQojcXBsb3QoWnIsIDEvc3FydCh2aSkpDQoNCiMgZGF0YSBmcmFtZQ0KZGF0IDwtIGRhdGEuZnJhbWUoeWkgPSBaciwgdmkgPSB2aSwgc2VpID0gc3FydCh2aSksIHhpID0geGksIG5pID0gbi5zYW1wbGUsIHByZWMgPSAxIC8gc3FydCh2aSksIHdpID0gMS92aSwgemkgPSBaci9zcXJ0KHZpKSkNCiAgICAgIHJvd3MgPC0gMTpucm93KGRhdCkNCiAgZXhwZWN0ZWQgPC0gd2hpY2goMS9kYXQkc2VpIDwgNSAmIGRhdCR5aSA8IDAuMjUpDQp1bmV4cGVjdGVkIDwtIHdoaWNoKDEvZGF0JHNlaSA+IDQuNyAmIGRhdCR5aSA+IDAuMjUpDQogY29sX3BvaW50IDwtIGlmZWxzZShyb3dzICVpbiUgZXhwZWN0ZWQsICJyZWQiLCBpZmVsc2Uocm93cyAlaW4lIHVuZXhwZWN0ZWQsICJibHVlIiwgImJsYWNrIikpDQpkYXQkY29sX3BvaW50IDwtIGNvbF9wb2ludA0KDQojIGRhdGEgd2l0aCAicHVibGljYXRpb24gYmlhcyINCmRhdDIgPC0gZGF0W2RhdCRjb2xfcG9pbnQgIT0gInJlZCIsIF0NCg0KIyBkZW1vbnN0cmF0aW9uIHRoYXQgdGhleSBhcmUgdGhlIHNhbWUNCmVxXzggPC0gbG0oemkgfiBwcmVjLCBkYXRhID0gZGF0MikNCmVxXzkgPC0gbG0oeWkgfiBzZWksIHdlaWdodCA9IHdpLCBkYXRhID0gZGF0MikNCmBgYA0KDQpgYGB7cn0NCnN1bW1hcnkoZXFfOCkNCnN1bW1hcnkoZXFfOSkNCmBgYA0KDQpBcyB5b3UgY2FuIHNlZSBhYm92ZSwgRXF1YXRpb24gOCdzIGludGVyY2VwdCBpcyBpZGVudGljYWwgdG8gdGhlIHNsb3BlIG9mIEVxdWF0aW9uIDksIHdoaWxlIEVxdWF0aW9uIDgncyBzbG9wZSBpcyBpZGVudGljYWwgdG8gRXF1YXRpb24gOSdzIGludGVyY2VwdC4gTm90ZSB0aGF0IGNvcnJlc3BvbmRpbmcgc3RhbmRhcmQgZXJyb3JzIChTRSkgYXJlIGFsc28gdGhlIHNhbWUuDQoNCiMjIEFwcGVuZGl4IFMzOiBGYWlsLXNhZmUgKk4qIGNvbXBhcmlzb25zDQoNCldlIHVzZSB0aGUgZnVuY3Rpb24gYGZzbigpYCBpbiB0aGUgUiBwYWNrYWdlLCBgbWV0YWZvcmAsIGFzIGluIHRoaXMgd2ViIHBhZ2U6IDxodHRwczovL3d2aWVjaHRiLmdpdGh1Yi5pby9tZXRhZm9yL3JlZmVyZW5jZS9mc24uaHRtbD4uDQoNCmBgYHtyfQ0KIyBleGFtcGxlIGRhdGEgdXNpbmcgcmlzayByYXRpbyAobm90IHJlc3BvbnNlIHJhdGlvKQ0KZGF0IDwtIGVzY2FsYyhtZWFzdXJlPSJSUiIsIGFpPXRwb3MsIGJpPXRuZWcsIGNpPWNwb3MsIGRpPWNuZWcsIGRhdGE9ZGF0LmJjZykNCmZzbih5aSwgdmksIGRhdGE9ZGF0LCB0eXBlPSJSb3NlbnRoYWwiKQ0KIyBzZXR0aW5nIGVmZmVjdCBzaXplIHRhcmdlIGFzIC0wLjENCmZzbih5aSwgdmksICBkYXRhPWRhdCwgdHlwZT0iT3J3aW4iLCB0YXJnZXQgPSAwLjEpDQpmc24oeWksIHZpLCBkYXRhPWRhdCwgdHlwZT0iUm9zZW5iZXJnIikNCmBgYA0KDQojIyBBcHBlbmRpeCBTNDogTXVsdGlsZXZlbCBtZXRhLXJlZ3Jlc3Npb24gbWV0aG9kIGZvciBwdWJsaWNhdGlvbiBiaWFzDQoNCkluIHRoaXMgc2VjdGlvbiwgd2UgcHJvdmlkZSB3b3JrZWQgZXhhbXBsZXMgdG8gc2hvdyBob3cgdG8gdGVzdCBmb3IgcHVibGljYXRpb24gYmlhcyBpbiBtZXRhLWFuYWx5dGljIGRhdGFzZXRzIHdpdGggaGlnaCBoZXRlcm9nZW5laXR5IGFuZCBzZXZlcmFsIGxheWVycyBvZiBub24taW5kZXBlbmRlbmNlLCBpbmNsdWRpbmcgcGh5bG9nZW5ldGljIG5vbi1pbmRlcGVuZGVuY2UgKGEgY29tbW9uIGZlYXR1cmUgb2YgbWV0YS1hbmFseXRpYyBkYXRhc2V0cyBpbiBlY29sb2d5IGFuZCBldm9sdXRpb247IFNlbmlvciBldCBhbC4gMjAxNiwgTm9ibGUgZXQgYWwuIDIwMTcpLiBXZSB1c2VkIHR3byBvcGVubHkgYXZhaWxhYmxlIG1ldGEtYW5hbHl0aWMgZGF0YXNldHMgdG8gc2hvdyBob3cgdG8gaW1wbGVtZW50IG91ciBzdWdnZXN0ZWQgbXVsdGlsZXZlbCBtZXRhLXJlZ3Jlc3Npb24gbWV0aG9kIChzZWUgbWFpbiB0ZXh0KSBvbiBjb3JyZWxhdGlvbiBlZmZlY3Qgc2l6ZXMgKCpacio6IHNlY3Rpb24gUzQuMSkgYW5kIGVmZmVjdCBzaXplcyBiYXNlZCBvbiBtZWFuIGRpZmZlcmVuY2VzIGJldHdlZW4gdHdvIGdyb3VwcyAoU01ELCBsblJSOiBzZWN0aW9uIFM0LjIpLg0KDQojIyMgUzQuMTogQ29ycmVsYXRpb24gZWZmZWN0IHNpemVzICgqWnIqKQ0KDQpgYGB7ciwgcmVzdWx0cz0iaGlkZSJ9DQojIGltcG9ydGluZyBkYXRhc2V0IHdpdGggY29ycmVsYXRpb24gY29lZmZpY2llbnRzDQpkYXRhc2V0LnIub3JpZ2luYWwgPC0gcmVhZC54bHN4KGhlcmUoImRhdGEiLCJmdDA0NC54bHN4IiksIGNvbE5hbWVzID0gVFJVRSwgc2hlZXQgPSAxKQ0KDQojIHRyYW5zZm9ybWluZyByIHRvIFpyIGZvciB0aGUgYW5hbHlzZXMsIGFuZCBlc3RpbWF0aW5nIFZaciBmb3IgdGhlIHdlaWdodGluZw0KZGF0YXNldC5yLm9yaWdpbmFsJFNhbXBsZS5zaXplIDwtIGFzLm51bWVyaWMoZGF0YXNldC5yLm9yaWdpbmFsJFNhbXBsZS5zaXplKQ0KDQojIHN1YnNldCBkYXRhc2V0IHRvIHRob3NlIHdpdGggNCBvciBtb3JlIGluZGl2aWR1YWxzICh0aGlzIHJlbW92ZXMgdHdvIHJvd3MsIG9uZSB3aXRob3V0IHNhbXBsZSBzaXplIGFuZCBvbmUgd2l0aCBzYW1wbGUgc2l6ZSA9IDMpLiBFZmZlY3Qgc2l6ZXMgYmFzZWQgb24gMyBpbmRpdmlkdWFscyB3b24ndCBiZSBhYmxlIHRvIGJlIGFuYWx5emVkIGJlY2F1c2UgVlpyIGlzIHRoZW4gaW5maW5pdGUgKGFzIHRoZSBkZW5vbWluYXRvciB3aGVuIGNhbGN1bGF0aW5nIFZaciBpcyB6ZXJvKS4NCmRhdGFzZXQuci5vcmlnaW5hbCA8LSBkYXRhc2V0LnIub3JpZ2luYWxbZGF0YXNldC5yLm9yaWdpbmFsJFNhbXBsZS5zaXplPjMgJiAhKGlzLm5hKGRhdGFzZXQuci5vcmlnaW5hbCRTYW1wbGUuc2l6ZSkpLF0NCg0KZGF0YXNldC5yLm9yaWdpbmFsJHlpIDwtIGF0YW5oKGRhdGFzZXQuci5vcmlnaW5hbCRDb3JyZWxhdGlvbikNCmRhdGFzZXQuci5vcmlnaW5hbCR2aSA8LSAxLyhhcy5udW1lcmljKGRhdGFzZXQuci5vcmlnaW5hbCRTYW1wbGUuc2l6ZSktMykgIA0KDQojIHJlbmFtaW5nIHNvbWUgdmFyaWFibGVzIHRvIG1ha2UgaXQgZWFzaWVyDQpkYXRhc2V0LnIub3JpZ2luYWwkc3R1ZHkgPC0gZGF0YXNldC5yLm9yaWdpbmFsJFJlZmVyZW5jZQ0KZGF0YXNldC5yLm9yaWdpbmFsIDwtIGRhdGFzZXQuci5vcmlnaW5hbFsgLCAhbmFtZXMoZGF0YXNldC5yLm9yaWdpbmFsKSAlaW4lIGMoIlJlZmVyZW5jZSIpXQ0KYGBgDQoNCkZvciBvdXIgZmlyc3Qgd29ya2VkIGV4YW1wbGUsIHdlIHVzZSB0aGUgZGF0YXNldCBwcm92aWRlZCBieSBHYXJhbXN6ZWdpIGV0IGFsLiAoMjAxMiksIHdobyBmb3VuZCBzdXBwb3J0IGZvciBjb3JyZWxhdGlvbnMgYWNyb3NzIGRpZmZlcmVudCBiZWhhdmlvdXJhbCB0cmFpdHMgd2l0aGluIGFuaW1hbCBwb3B1bGF0aW9ucy4gSGVyZSwgd2UgcmUtYW5hbHlzZSB0aGUgZGF0YSBmcm9tIEdhcmFtc3plZ2kgZXQgYWwuICgyMDEyKSBieSBmaXJzdCBjb25kdWN0aW5nIGEgcGh5bG9nZW5ldGljIG11bHRpbGV2ZWwgaW50ZXJjZXB0LW9ubHkgbWV0YS1hbmFseXRpYyBtb2RlbCBhbmQgdGhlbiB0ZXN0aW5nIGZvciBldmlkZW5jZSBvZiBwdWJsaWNhdGlvbiBiaWFzIGZvbGxvd2luZyB0aGUgYXBwcm9hY2hlcyBvdXRsaW5lZCBpbiB0aGUgbWFpbiB0ZXh0Lg0KDQojIyMjIFM0LjEuMSAtIFBoeWxvZ2VuZXRpYyByZWxhdGlvbnNoaXBzDQoNClNpbmNlIG11bHRpcGxlIGFuaW1hbCBzcGVjaWVzIChuID0gYHIgbGVuZ3RoKHVuaXF1ZShkYXRhc2V0LnIub3JpZ2luYWwkU3BlY2llcykpYCkgYXJlIGluY2x1ZGVkIGluIHRoaXMgZGF0YXNldCwgd2UgbmVlZCB0byBjb25zaWRlciBwaHlsb2dlbmV0aWMgbm9uLWluZGVwZW5kZW5jZSBpbiBvdXIgc3RhdGlzdGljYWwgbW9kZWxzIChDaGFtYmVybGFpbiBldCBhbC4gMjAxMiwgQ2luYXIgZXQgYWwuIDIwMjApLiBGb3IgdGhhdCwgd2UgZmlyc3Qgc2VhcmNoIGZvciB0aGUgc3BlY2llcyBpbiB0aGUgT3BlbiBUcmVlIFRheG9ub215IChSZWVzIGFuZCBDcmFuc3RvbiAyMDE3KSB0byBjb25maXJtIGFuZCBjb3JyZWN0IHRoZSBzcGVjaWVzIG5hbWVzLCB0aGVuIGJ1aWxkIGEgcGh5bG9nZW5ldGljIHRyZWUgZm9yIGFsbCB0aGUgc3BlY2llcyBpbmNsdWRlZCBpbiB0aGUgZGF0YXNldCAoRmlndXJlIFMxKSBieSByZXRyaWV2aW5nIHRoZWlyIHBoeWxvZ2VuZXRpYyByZWxhdGlvbnNoaXBzIGZyb20gdGhlIE9wZW4gVHJlZSBvZiBMaWZlIChIaW5jaGxpZmYgZXQgYWwuIDIwMTUpIHVzaW5nIHRoZSBSIHBhY2thZ2UgYHJvdGxgIChNaWNob25uZWF1IGV0IGFsLiAyMDE2KS4gTmV4dCwgd2UgZXN0aW1hdGUgYnJhbmNoIGxlbmd0aHMgZm9sbG93aW5nIEdyYWZlbiAoMTk4OSkgYXMgaW1wbGVtZW50ZWQgaW4gdGhlIGZ1bmN0aW9uICdjb21wdXRlLmJybGVuKCknIG9mIHRoZSBSIHBhY2thZ2UgYGFwZWAgKFBhcmFkaXMgYW5kIFNjaGxpZXAgMjAxOSkuIEZpbmFsbHksIHdlIGNvbnN0cnVjdCBhIHBoeWxvZ2VuZXRpYyByZWxhdGVkbmVzcyBjb3JyZWxhdGlvbiBtYXRyaXggdGhhdCB3aWxsIGJlIGZpdHRlZCBhcyBwYXJ0IG9mIHRoZSByYW5kb20gZWZmZWN0IHN0cnVjdHVyZSBvZiBvdXIgbW9kZWxzIChzZWUgYmVsb3cpLg0KDQpgYGB7cn0NCiMgZml4aW5nIGEgdHlwbyBpbiB0aGUgb3JpZ2luYWwgbGlzdCBvZiBzcGVjaWVzIG5hbWVzDQpkYXRhc2V0LnIub3JpZ2luYWwkU3BlY2llcyA8LSBpZmVsc2UoZGF0YXNldC5yLm9yaWdpbmFsJFNwZWNpZXM9PSJBY3JvY2hlcGhhbHVzIHNjaG9lbm9iYWVudXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBY3JvY2VwaGFsdXMgc2Nob2Vub2JhZW51cyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YXNldC5yLm9yaWdpbmFsJFNwZWNpZXMpDQoNCiMgdXBkYXRpbmcgYSBuYW1lIHRoYXQgd2FzIG5vdCBiZWluZyB3ZWxsIHJlY29nbml6ZWQgYnkgdGhlIE9wZW4gVHJlZSBUYXhvbm9teQ0KZGF0YXNldC5yLm9yaWdpbmFsJFNwZWNpZXMgPC0gaWZlbHNlKGRhdGFzZXQuci5vcmlnaW5hbCRTcGVjaWVzPT0iRXVyb3Rlc3R1ZG8gYm9ldHRnZXJpIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVGVzdHVkbyBib2V0dGdlcmkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGFzZXQuci5vcmlnaW5hbCRTcGVjaWVzKQ0KDQojIGZpeGluZyBhbm90aGVyIHR5cG8gaW4gdGhlIG9yaWdpbmFsIGxpc3Qgb2Ygc3BlY2llcyBuYW1lcw0KZGF0YXNldC5yLm9yaWdpbmFsJFNwZWNpZXMgPC0gaWZlbHNlKGRhdGFzZXQuci5vcmlnaW5hbCRTcGVjaWVzPT0iVGFlbm9weWdpYSBndXR0YXRhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVGFlbmlvcHlnaWEgZ3V0dGF0YSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YXNldC5yLm9yaWdpbmFsJFNwZWNpZXMpDQoNCiMgIyBvYnRhaW5pbmcgZGF0YWZyYW1lIGxpc3RpbmcgdGhlIE9wZW4gVHJlZSBpZGVudGlmaWVycyBwb3RlbnRpYWxseSBtYXRjaGluZyBvdXIgbGlzdCBvZiBzcGVjaWVzIChvciB5b3UgY2FuIGxvYWQgdGhlIGRhdGEgYmVsb3cpDQojdGF4YSA8LSB0bnJzX21hdGNoX25hbWVzKG5hbWVzID0gdW5pcXVlKGRhdGFzZXQuci5vcmlnaW5hbCRTcGVjaWVzKSkNCg0KIyAjIHNhdmluZyB0aGUgdGF4b25vbWljIGRhdGEgY3JlYXRlZCBvbiB0aGUgMTh0aCBvZiBGZWJydWFyeSAyMDIxIHRvIHNwZWVkIHRoZSBwcm9jZXNzIGluIHRoZSBmdXR1cmUgYW5kIG1ha2UgdGhlIGNvZGUgZnVsbHkgcmVwcm9kdWNpYmxlIGlmIHRheG9ub21pYyBjaGFuZ2VzIGFyZSBpbXBsZW1lbnRlZCBpbiB0aGUgZnV0dXJlDQojIHNhdmUodGF4YSxmaWxlID0gInRheGFfT3Blbl9UcmVlX29mX0xpZmVfMjAyMTAyMTguUkRhdGEiKQ0KDQojIGxvYWRpbmcgdGhlIHRheG9ub21pYyBkYXRhICh0YXhhKSBjcmVhdGVkIG9uIHRoZSAxOHRoIG9mIEZlYnJ1YXJ5IDIwMjENCmxvYWQoaGVyZSgiZGF0YSIsICJ0YXhhX09wZW5fVHJlZV9vZl9MaWZlXzIwMjEwMjE4LlJEYXRhIikpDQoNCiMgIyBjaGVjayBhcHByb3hpbWF0ZSBtYXRjaGVzDQojIHRheGFbdGF4YSRhcHByb3hpbWF0ZV9tYXRjaD09VFJVRSxdDQojIA0KIyAjIGNoZWNrIHN5bm9ueW1zIG1hdGNoZXMNCiMgdGF4YVt0YXhhJGlzX3N5bm9ueW09PVRSVUUsXQ0KIyANCiMgIyBjaGVjayBudW1iZXIgb2YgbWF0Y2hlcw0KIyB0YXhhW3RheGEkbnVtYmVyX21hdGNoZXM+MSxdDQoNCiMgIyBzb21lIGZ1cnRoZXIgY2hlY2tzDQojIG90dF9pZF90b2NoZWNrIDwtIHRheGFbdGF4YSRudW1iZXJfbWF0Y2hlcyAhPSAxLCJvdHRfaWQiXQ0KDQojIGZvcihpIGluIDE6bGVuZ3RoKG90dF9pZF90b2NoZWNrKSl7DQojICAgcHJpbnQoaW5zcGVjdCh0YXhhLCBvdHRfaWQgPSBvdHRfaWRfdG9jaGVja1tpXSkpDQojIH0NCg0KIyBhbGwgcGh5bG9nZW5ldGljIGRhdGEgc2VlbXMgaW4gb3JkZXIgbm93DQoNCiMgaG93ZXZlciwgdGhlIG90dF9pZCBmb3IgUGFybWEgdW5pZmFzY2lhdGEgY2Fubm90IGJlIGZvdW5kIHdoZW4gcmV0cmlldmluZyB0aGUgcGh5bG9nZW5ldGljIHJlbGF0aW9uc2hpcHMsIHNvIHRvIGdldCBhcm91bmQgdGhpcyB3ZSBhcmUgZ29pbmcgdG8gdXNlIHRoZSBvdHRfaWQgb2YgYW5vdGhlciBQYXJtYSBzcGVjaWVzLCBQYXJtYSBvbGlnb2xlcGlzIChvdHRfaWQgPSAzMjMxODYpLiBJbiB0aGlzIGNhc2UgaXQgaXMgZmluZSBiZWNhdXNlIHdlIG9ubHkgaW5jbHVkZSB0d28gc3BlY2llcyBiZWxvbmdpbmcgdG8gdGhlIGdlbnVzIFBhcm1hLCBhbmQgdGhlcmVmb3JlLCB0aGUgcGh5bG9nZW5ldGljIHJlbGF0aW9uc2hpcCB3aWxsIGJlIHRoZSBzYW1lIGZvciBvdXIgcHVycG9zZXMNCiMgdG5yc19tYXRjaF9uYW1lcyhuYW1lcyA9ICdQYXJtYSBvbGlnb2xlcGlzJykNCiMgdGF4YVt0YXhhJHVuaXF1ZV9uYW1lPT0iUGFybWEgdW5pZmFzY2lhdGEiLCJvdHRfaWQiXSA8LSAzMjMxODYNCg0KIyAjIHJldHJpZXZpbmcgcGh5bG9nZW5ldGljIHJlbGF0aW9uc2hpcHMgYW1vbmcgdGF4YSBpbiB0aGUgZm9ybSBvZiBhIHRyaW1tZWQgc3ViLXRyZWUgKHlvdSBjYW4gc2ltcGx5IGxvYWQgdGhlIHRyZWUgYXQgdGhlIGJvdHRvbSkNCiMgdHJlZSA8LSB0b2xfaW5kdWNlZF9zdWJ0cmVlKG90dF9pZHMgPSB0YXhhW1sib3R0X2lkIl1dLCBsYWJlbF9mb3JtYXQgPSAibmFtZSIpDQoNCiMgIyB3ZSBuZWVkIHRvIGNoZWNrIGZvciB0aGUgZXhpc3RlbmNlIG9mIHBvbHl0b21pZXMNCiMgaXMuYmluYXJ5LnRyZWUodHJlZSkgIyBObyBwb2x5dG9taWVzLCBzbyB3ZSBjYW4gcHJvY2VlZC4NCg0KIyB0byBjb25maXJtIHRoYXQgb3VyIHRyZWUgY292ZXJzIGFsbCB0aGUgc3BlY2llcyB3ZSB3YW50ZWQgaXQgdG8gaW5jbHVkZSwgYW5kIG1ha2Ugc3VyZSB0aGF0IHRoZSBzcGVjaWVzIG5hbWVzIGluIG91ciBkYXRhYmFzZSBtYXRjaCB0aG9zZSBpbiB0aGUgdHJlZSwgd2UgdXNlIHRoZSBmb2xsb3dpbmcgY29kZQ0KDQojIHRyZWUkdGlwLmxhYmVsIDwtIGdzdWIoIl8iLCIgIiwgdHJlZSR0aXAubGFiZWwpDQojIGludGVyc2VjdChhcy5jaGFyYWN0ZXIodHJlZSR0aXAubGFiZWwpLCBhcy5jaGFyYWN0ZXIoZGF0YXNldC5yLm9yaWdpbmFsJFNwZWNpZXMpKQ0KIyBzZXRkaWZmKGFzLmNoYXJhY3RlcihkYXRhc2V0LnIub3JpZ2luYWwkU3BlY2llcyksIGFzLmNoYXJhY3Rlcih0cmVlJHRpcC5sYWJlbCkpICNsaXN0ZWQgaW4gb3VyIGRhdGFiYXNlIGJ1dCBub3QgaW4gdGhlIHRyZWUNCiMgc2V0ZGlmZihhcy5jaGFyYWN0ZXIodHJlZSR0aXAubGFiZWwpLGFzLmNoYXJhY3RlcihkYXRhc2V0LnIub3JpZ2luYWwkU3BlY2llcykpICMgbGlzdGVkIGluIHRoZSB0cmVlIGJ1dCBub3QgaW4gb3VyIGRhdGFiYXNlDQoNCiMgQWxsIGJ1dCBQYW4gYW5kIFBhcm1hIG9saWdvbGVwaXMgYXJlIHRoZSBzYW1lIHNwZWNpZXMsIHRoZSAicHJvYmxlbSIgaXMgdGhhdCBzeW5vbnltcyBoYXZlIGJlZW4gdXNlZCBpbiB0aGUgdHJlZS4gV2UgYXJlIGdvaW5nIHRvIGxlYXZlIGFsbCB0aGUgbmFtZXMgYXMgaW4gT3BlbiBUcmVlIG9mIExpZmUgZXhjZXB0IFBhbiBhbmQgUGFybWEgb2xpZ29sZXBpcywgd2hpY2ggd2UgYXJlIGdvaW5nIHRvIHN1YnN0aXR1dGUgYnkgUGFuIHRyb2dsb2R5dGVzIGFuZCBQYXJtYSB1bmlmYXNjaWF0YQ0KDQojICMgd2Ugc3RhcnQgYnkgZml4aW5nIHRoZSBmb2xsb3dpbmcgbmFtZXMgaW4gdGhlIHRyZWUNCiMgdHJlZSR0aXAubGFiZWxbdHJlZSR0aXAubGFiZWw9PSJQYW4iXTwtIlBhbiB0cm9nbG9keXRlcyINCiMgdHJlZSR0aXAubGFiZWxbdHJlZSR0aXAubGFiZWw9PSJQYXJtYSBvbGlnb2xlcGlzIl08LSJQYXJtYSB1bmlmYXNjaWF0YSINCg0KIyBzZXRkaWZmKGFzLmNoYXJhY3RlcihkYXRhc2V0LnIub3JpZ2luYWwkU3BlY2llcyksIGFzLmNoYXJhY3Rlcih0cmVlJHRpcC5sYWJlbCkpICNsaXN0ZWQgaW4gb3VyIGRhdGFiYXNlIGJ1dCBub3QgaW4gdGhlIHRyZWUNCiMgc2V0ZGlmZihhcy5jaGFyYWN0ZXIodHJlZSR0aXAubGFiZWwpLGFzLmNoYXJhY3RlcihkYXRhc2V0LnIub3JpZ2luYWwkU3BlY2llcykpICMgbGlzdGVkIGluIHRoZSB0cmVlIGJ1dCBub3QgaW4gb3VyIGRhdGFiYXNlDQoNCg0KIyBjaGFuZ2luZyB0aGUgbmFtZXMgaW4gb3VyIGRhdGFiYXNlIHRvIGZvbGxvdyB0aG9zZSBpbiB0aGUgdHJlZS4gV2UgYXJlIGNyZWF0aW5nIGEgbmV3IFNwZWNpZXMudXBkYXRlZCB2YXJpYWJsZSBzbyB0aGF0IGl0IGlzIGNsZWFyIHRoYXQgdGhpcyBsaXN0IG9mIFNwZWNpZXMgaXMgYW4gdXBkYXRlZCB2ZXJzaW9uIGNvbXBhcmVkIHRvIHRoZSBvcmlnaW5hbCBvbmUNCmRhdGFzZXQuci5vcmlnaW5hbCRTcGVjaWVzLnVwZGF0ZWQgPC0gZGF0YXNldC5yLm9yaWdpbmFsJFNwZWNpZXMNCg0KZGF0YXNldC5yLm9yaWdpbmFsJFNwZWNpZXMudXBkYXRlZCA8LSBpZmVsc2UoZGF0YXNldC5yLm9yaWdpbmFsJFNwZWNpZXMudXBkYXRlZD09IkNhcmR1ZWxpcyBjaGxvcmlzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDaGxvcmlzIGNobG9yaXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YXNldC5yLm9yaWdpbmFsJFNwZWNpZXMudXBkYXRlZCkNCg0KZGF0YXNldC5yLm9yaWdpbmFsJFNwZWNpZXMudXBkYXRlZCA8LSBpZmVsc2UoZGF0YXNldC5yLm9yaWdpbmFsJFNwZWNpZXMudXBkYXRlZD09IkRlbmRyb2ljYSBwZW5zeWx2YW5pYWNhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTZXRvcGhhZ2EgcGVuc3lsdmFuaWNhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGFzZXQuci5vcmlnaW5hbCRTcGVjaWVzLnVwZGF0ZWQpDQoNCmRhdGFzZXQuci5vcmlnaW5hbCRTcGVjaWVzLnVwZGF0ZWQgPC0gaWZlbHNlKGRhdGFzZXQuci5vcmlnaW5hbCRTcGVjaWVzLnVwZGF0ZWQ9PSJTeWx2aWEgbWVsYW5vY2VwaGFsYSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ3VycnVjYSBtZWxhbm9jZXBoYWxhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGFzZXQuci5vcmlnaW5hbCRTcGVjaWVzLnVwZGF0ZWQpDQoNCiMgd2UgYXJlIGFsc28gdXBkYXRpbmcgdGhlIG9yaWdpbmFsIFNwZWNpZXMgdmFyaWFibGUgc2luY2Ugd2UgaGF2ZSB0byBmaXQgYm90aCBTcGVjaWVzIGFuZCBTcGVjaWVzLnVwZGF0ZWQgaW4gb3VyIG1vZGVscyAoc2VlIGJlbG93KQ0KZGF0YXNldC5yLm9yaWdpbmFsJFNwZWNpZXMgPC0gZGF0YXNldC5yLm9yaWdpbmFsJFNwZWNpZXMudXBkYXRlZA0KDQojIHNldGRpZmYoYXMuY2hhcmFjdGVyKGRhdGFzZXQuci5vcmlnaW5hbCRTcGVjaWVzLnVwZGF0ZWQpLCBhcy5jaGFyYWN0ZXIodHJlZSR0aXAubGFiZWwpKSAjbGlzdGVkIGluIG91ciBkYXRhYmFzZSBidXQgbm90IGluIHRoZSB0cmVlDQojIHNldGRpZmYoYXMuY2hhcmFjdGVyKHRyZWUkdGlwLmxhYmVsKSxhcy5jaGFyYWN0ZXIoZGF0YXNldC5yLm9yaWdpbmFsJFNwZWNpZXMudXBkYXRlZCkpICMgbGlzdGVkIGluIHRoZSB0cmVlIGJ1dCBub3QgaW4gb3VyIGRhdGFiYXNlDQoNCiMgYWxsIGluIG9yZGVyDQoNCiMgd2UgY2FuIG5vdyBzYXZlIHRoZSB0cmVlDQojc2F2ZSh0cmVlLCBmaWxlID0gInRyZWVfMjAyMTE4MDIuUmRhdGEiKQ0KDQpkYXRhc2V0LnIgPC0gZGF0YXNldC5yLm9yaWdpbmFsDQoNCiMgbG9hZCB0aGUgc2F2ZWQgdHJlZSAodHJlZSkNCmxvYWQoaGVyZSgiZGF0YSIsInRyZWVfMjAyMTE4MDIuUmRhdGEiKSkgDQoNCiMgY29tcHV0ZSBicmFuY2ggbGVuZ3RocyBvZiB0cmVlDQpwaHlsb19icmFuY2ggPC0gY29tcHV0ZS5icmxlbih0cmVlLCBtZXRob2QgPSAiR3JhZmVuIiwgcG93ZXIgPSAxKQ0KDQojICMgY2hlY2sgdHJlZSBpcyB1bHRyYW1ldHJpYw0KIyBpcy51bHRyYW1ldHJpYyhwaHlsb19icmFuY2gpICMgVFJVRQ0KDQojIG1hdHJpeCB0byBiZSBpbmNsdWRlZCBpbiB0aGUgbW9kZWxzDQpwaHlsb19jb3IgPC0gdmN2KHBoeWxvX2JyYW5jaCwgY29yID0gVCkNCmBgYA0KDQojIyMjIyBGaWd1cmUgUzQuMQ0KDQpgYGB7ciwgZmlnLmhlaWdodCA9IDksIGZpZy53aWR0aCA9IDkuNSwgZmlnLmFsaWduID0gImNlbnRlciIsIGZpZy5jYXA9IlBoeWxvZ2VuZXRpYyB0cmVlIG9mIGFsbCBzcGVjaWVzIGluY2x1ZGVkIGluIHRoZSBtZXRhLWFuYWx5dGljIGRhdGFzZXQuIE5vdGljZSB0aGF0IHNvbWUgb2YgdGhlIG5hbWVzIHNob3duIGluIHRoZSB0cmVlIGNvcnJlc3BvbmQgdG8gdGhlIG1vc3QgdXBkYXRlZCBzeW5vbnltcyBhY2NvcmRpbmcgdG8gdGhlIE9wZW4gVHJlZSBUYXhvbm9teSAoUmVlcyBhbmQgQ3JhbnN0b24gMjAxNykgb2YgdGhvc2Ugb3JpZ2luYWxseSBhdmlhbGFibGUgaW4gdGhlIGRhdGFzZXQgb2YgR2FyYW1zemVnaSBldCBhbC4gKDIwMTIpLiJ9DQpwbG90KHRyZWUsIHR5cGUgPSAiZmFuIiwgY2V4PTAuNjUsIGxhYmVsLm9mZnNldCA9LjA1LCBuby5tYXJnaW4gPSBUUlVFKSAjY2hlY2s6IGh0dHBzOi8vd3d3LnJkb2N1bWVudGF0aW9uLm9yZy9wYWNrYWdlcy9hcGUvdmVyc2lvbnMvNS4zL3RvcGljcy9wbG90LnBoeWxvDQpgYGANCg0KPGJyLz48YnIvPg0KDQojIyMjIFM0LjEuMjogRXhwbG9yYXRvcnkgZGF0YSBhbmFseXNpcw0KDQpCZWZvcmUgcnVubmluZyBhbnkgbWV0YS1hbmFseXRpYyBtb2RlbCwgaXQgaXMgaW1wb3J0YW50IHRvIGV4cGxvcmUgdGhlIG1ldGEtYW5hbHl0aWMgZGF0YXNldCB0byBzZWFyY2ggZm9yIHBvdGVudGlhbCBvdXRsaWVycyB0aGF0IGNvdWxkIHJlcHJlc2VudCBkYXRhIGV4dHJhY3Rpb24gZXJyb3JzLiBUbyBkbyBzbywgd2UgY2FuIGRyYXcgZnVubmVsIHBsb3RzIHNob3dpbmcgdGhlIHN0YW5kYXJkIGVycm9yIGFuZCB0aGUgaW52ZXJzZSBvZiB0aGUgc3RhbmRhcmQgZXJyb3IgKGkuZS4gcHJlY2lzaW9uKSBhcyB0aGUgeS1heGVzIChGaWd1cmUgUzQuMikuIEZyb20gdGhlc2UgZnVubmVsIHBsb3RzIChGaWd1cmUgUzQuMiksIHdlIGNvbmNsdWRlIHRoYXQgbm8gY2xlYXIgb3V0bGllcnMgc2VlbSB0byBiZSBwcmVzZW50IGluIHRoaXMgbWV0YS1hbmFseXRpYyBkYXRhc2V0Lg0KDQojIyMjIyBGaWd1cmUgUzQuMg0KDQpgYGB7ciwgZmlnLmNhcD0iRnVubmVsIHBsb3RzIHdpdGggU0UgKGxlZnQtaGFuZCBzaWRlKSBhbmQgcHJlY2lzaW9uICgxL1NFOyByaWdodC1oYW5kIHNpZGUpIGFzIG1lYXN1cmVzIG9mIHVuY2VydGFpbnR5IHRvIGV4cGxvcmUgdGhlIGV4aXN0ZW5jZSBvZiBvdXRsaWVycyBpbiB0aGUgbWV0YS1hbmFseXRpYyBkYXRhc2V0LiJ9DQpwYXIobWZyb3cgPSBjKDEsIDIpKQ0KZnVubmVsKGRhdGFzZXQuciR5aSwgZGF0YXNldC5yJHZpLCB5YXhpcz0ic2VpIiwNCiAgICAgICAjeGxpbSA9IGMoLTMsIDMpLA0KICAgICAgIHhsYWIgPSAiRWZmZWN0IHNpemUgKFpyKSIsIGRpZ2l0cyA9IDIsIGxhcyA9IDEpIA0KZnVubmVsKGRhdGFzZXQuciR5aSwgZGF0YXNldC5yJHZpLCB5YXhpcz0ic2VpbnYiLA0KICAgICAgICN4bGltID0gYygtMywgMyksDQogICAgICAgeGxhYiA9ICJFZmZlY3Qgc2l6ZSAoWnIpIiwgIGRpZ2l0cyA9IDIsIGxhcyA9IDEpIA0KYGBgDQoNCjxici8+PGJyLz4NCg0KIyMjIyBTNC4xLjM6IE11bHRpbGV2ZWwgbWV0YS1hbmFseXNpcw0KDQpOb3cgdGhhdCB3ZSBoYXZlIGNyZWF0ZWQgYSBtYXRyaXggd2l0aCB0aGUgcGh5bG9nZW5ldGljIHJlbGF0aW9uc2hpcHMgYW1vbmcgc3BlY2llcyBhbmQgaGF2ZSBjb25maXJtZWQgdGhhdCBubyBvdXRsaWVycyBzZWVtIHRvIGJlIHByZXNlbnQsIHdlIGNhbiB0aGVuIHVzZSB0aGUgZGF0YXNldCBmcm9tIEdhcmFtc3plZ2kgZXQgYWwuICgyMDEyKSB0byBwcm92aWRlIGEgd29ya2VkIGV4YW1wbGUgb24gaG93IHRvIHRlc3QgZm9yIHB1YmxpY2F0aW9uIGJpYXMgdXNpbmcgdGhlIG11bHRpbGV2ZWwgbWV0YS1yZWdyZXNzaW9uIG1ldGhvZCBzdWdnZXN0ZWQgaW4gdGhlIG1haW4gdGV4dC4gRmlyc3QsIGxldCdzIGhhdmUgYSBsb29rIGF0IHRoZSBkZXRhaWxlZCByZXN1bHRzIG9mIGEgbXVsdGlsZXZlbCBwaHlsb2dlbmV0aWMgbWV0YS1hbmFseXRpYyAoaW50ZXJjZXB0LW9ubHkpIG1vZGVsIChUYWJsZSBTNC4xKSwgaW5jbHVkaW5nIHRoZSBjb3JyZXNwb25kaW5nIGZ1bm5lbCBwbG90IHNob3dpbmcgdGhlIG92ZXJhbGwgZWZmZWN0IG9yIG1ldGEtYW5hbHl0aWMgbWVhbiAoRmlndXJlIFM0LjMpLg0KDQpgYGB7cn0NCiMgY3JlYXRpbmcgYSB1bml0LWxldmVsIHJhbmRvbSBlZmZlY3QgdG8gbW9kZWwgcmVzaWR1YWwgdmFyaWFuY2UgaW4gbWV0YWZvcg0KZGF0YXNldC5yJG9ic0lEIDwtIDE6bnJvdyhkYXRhc2V0LnIpDQoNCiMgcnVubmluZyBtdWx0aWxldmVsIGludGVyY2VwdC1vbmx5IG1ldGEtYW5hbHl0aWMgbW9kZWwNCm1ldGEuYW5hbHlzaXMubW9kZWwuciA8LSBybWEubXYoeWksIHZpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RzPX4xLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb209bGlzdCh+IDEgfCBTcGVjaWVzLnVwZGF0ZWQsICMgcGh5bG8gZWZmZWN0DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH4gMSB8IFNwZWNpZXMsICMgbm9uLXBoeWxvIGVmZmVjdA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB+IDEgfCBzdHVkeSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH4gMSB8IG9ic0lEKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFIgPSBsaXN0KFNwZWNpZXMudXBkYXRlZCA9IHBoeWxvX2NvciksICNwaHlsb2dlbmV0aWMgcmVsYXRlZG5lc3MNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kPSJSRU1MIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdD0idCIsICMgdXNpbmcgdCBkaXN0IHJhdGhlciB0aGFuIHogYmVjYXVzZSB0IGlzIGEgYmV0dGVyLCBtb3JlIGNvbnNlcnZhdGl2ZSBkaXN0cmlidXRpb24gdGhhbiB6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE9ZGF0YXNldC5yKQ0KDQojIHByaW50KG1ldGEuYW5hbHlzaXMubW9kZWwuciwgZGlnaXRzPTMpDQoNCiMgZXh0cmFjdGluZyB0aGUgbWVhbiwgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGFuZCA5NSUgcHJlZGljdGlvbiBpbnRlcnZhbHMNCm1ldGFhbmFseXRpYy5tZWFuLm1vZGVsLnIgPC0gcHJlZGljdChtZXRhLmFuYWx5c2lzLm1vZGVsLnIsIGRpZ2l0cz0zKQ0KDQojIGVzdGltYXRpbmcgSTIgYXMgbWVhc3VyZSBvZiBoZXRlcm9nZW5laXR5DQpJMi5tb2RlbC5yIDwtIGkyX21sKG1ldGEuYW5hbHlzaXMubW9kZWwuciwgbWV0aG9kID0gIm1hdHJpeCIpDQoNCiMgY3JlYXRpbmcgYSBkYXRhLmZyYW1lIHdpdGggdGhlIG1ldGEtYW5hbHl0aWMgbWVhbiBhbmQgaGV0ZXJvZ2VuZWl0eSBlc3RpbWF0ZXMNCnRhYmxlLm1vZGVsLnIgPC0gZGF0YS5mcmFtZShuPWxlbmd0aCh1bmlxdWUoZGF0YXNldC5yJHN0dWR5KSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgaz1ucm93KGRhdGFzZXQuciksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhbj1yb3VuZChtZXRhYW5hbHl0aWMubWVhbi5tb2RlbC5yW1sxXV0sMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgQ0k9cGFzdGUwKCJbIixyb3VuZChtZXRhYW5hbHl0aWMubWVhbi5tb2RlbC5yW1szXV0sMiksIiwiLHJvdW5kKG1ldGFhbmFseXRpYy5tZWFuLm1vZGVsLnJbWzRdXSwyKSwiXSIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBJPXBhc3RlMCgiWyIscm91bmQobWV0YWFuYWx5dGljLm1lYW4ubW9kZWwucltbNV1dLDIpLCIsIixyb3VuZChtZXRhYW5hbHl0aWMubWVhbi5tb2RlbC5yW1s2XV0sMiksIl0iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBJMl9vYnNJRD1yb3VuZChJMi5tb2RlbC5yW1siSTJfb2JzSUQiXV0sMSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgSTJfcGFwZXJJRD1yb3VuZChJMi5tb2RlbC5yW1siSTJfc3R1ZHkiXV0sMSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgSTJfbm9ucGh5bG89cm91bmQoSTIubW9kZWwucltbIkkyX1NwZWNpZXMiXV0sMSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIEkyX3BoeWxvPXJvdW5kKEkyLm1vZGVsLnJbWyJJMl9TcGVjaWVzLnVwZGF0ZWQiXV0qMTAwLDEpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIEkyX3RvdGFsPXJvdW5kKEkyLm1vZGVsLnJbWyJJMl9Ub3RhbCJdXSwxKQ0KKQ0KDQojIGNyZWF0aW5nIGEgbmljZWx5LWZvcm1hdHRlZCB0YWJsZSB1c2luZyB0aGUgUiBwYWNrYWdlICdndCcNCnRhYmxlLm1vZGVsLnIuZ3QgPC0gdGFibGUubW9kZWwuciAlPiUgDQogIGd0OjpndCgpICU+JSANCiAgY29sc19sYWJlbChuPW1kKCIqKm4qKiIpLA0KICAgICAgICAgICAgIGs9bWQoIioqayoqIiksDQogICAgICAgICAgICAgbWVhbj1tZCgiKipNZXRhLWFuYWx5dGljIG1lYW4qKiIpLA0KICAgICAgICAgICAgIENJPW1kKCIqKjk1JSBDSSoqIiksDQogICAgICAgICAgICAgUEk9bWQoIioqOTUlIFBJKioiKSwNCiAgICAgICAgICAgICBJMl9vYnNJRD1tZCgiKioqSSo8c3VwPjI8L3N1cD48c3ViPnJlc2lkdWFsPC9zdWI+XG4oJSkqKiIpLA0KICAgICAgICAgICAgIEkyX3BhcGVySUQ9bWQoIioqKkkqPHN1cD4yPC9zdXA+PHN1Yj5zdHVkeTwvc3ViPlxuKCUpKioiKSwNCiAgICAgICAgICAgICBJMl9ub25waHlsbz1tZCgiKioqSSo8c3VwPjI8L3N1cD48c3ViPm5vbi1waHlsb2dlbnk8L3N1Yj5cbiglKSoqIiksDQogICAgICAgICAgICAgSTJfcGh5bG89bWQoIioqKkkqPHN1cD4yPC9zdXA+PHN1Yj5waHlsb2dlbnk8L3N1Yj5cbiglKSoqIiksDQogICAgICAgICAgICAgSTJfdG90YWw9bWQoIioqKkkqPHN1cD4yPC9zdXA+PHN1Yj50b3RhbDwvc3ViPiAgICBcbiglKSoqIiksDQogICkgJT4lDQogIGNvbHNfYWxpZ24oYWxpZ24gPSAiY2VudGVyIikgJT4lDQogIHRhYl9zb3VyY2Vfbm90ZShzb3VyY2Vfbm90ZSA9IG1kKCJuID0gbnVtYmVyIG9mIHN0dWRpZXM7IGsgPSBudW1iZXIgb2YgZWZmZWN0czsgQ0kgPSBjb25maWRlbmNlIGludGVydmFsOyBQSSA9IHByZWRpY3Rpb24gaW50ZXJ2YWw7ICpJKjxzdXA+Mjwvc3VwPiA9IGhldGVyb2dlbmVpdHkiKSkgIyU+JQ0KIyB0YWJfb3B0aW9ucyh0YWJsZS53aWR0aD03NzApDQoNCnRhYmxlLm1vZGVsLnIuZ3QNCg0KYGBgDQoNCioqVGFibGUgUzQuMS4qKiBSZXN1bHRzIG9mIHRoZSBwaHlsb2dlbmV0aWMgbXVsdGlsZXZlbCBpbnRlcmNlcHQtb25seSBtZXRhLWFuYWx5c2lzIHRlc3RpbmcgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGJlaGF2aW91cnMgYWNyb3NzIHNwZWNpZXMuIEVzdGltYXRlcyBhcmUgcHJlc2VudGVkIGFzIHN0YW5kYXJkaXplZCBlZmZlY3Qgc2l6ZXMgdXNpbmcgRmlzaGVyJ3MgdHJhbnNmb3JtYXRpb24gb2YgdGhlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50IChpLmUuICpaciopLg0KDQo8YnIvPjxici8+DQoNCiMjIyMjIEZpZ3VyZSBTNC4zDQoNCmBgYHtyLCBmaWcuY2FwPSJGdW5uZWwgcGxvdCwgdXNpbmcgcHJlY2lzaW9uICgxL1NFKSBhcyBhIG1lYXN1cmUgb2YgdW5jZXJ0YWludHksIHNob3dpbmcgdGhlIG1ldGEtYW5hbHl0aWMgbWVhbiBvYnRhaW5lZCBpbiB0aGUgcGh5bG9nZW5ldGljIG11bHRpbGV2ZWwgaW50ZXJjZXB0LW9ubHkgbWV0YS1hbmFseXNpcyBhcyBhIGRvdHRlZCB2ZXJ0aWNhbCBsaW5lLiJ9DQpmdW5uZWwobWV0YS5hbmFseXNpcy5tb2RlbC5yLCB5YXhpcz0ic2VpbnYiLA0KICAgICAgIHhsYWIgPSAiRWZmZWN0IHNpemUgKFpyKSIpDQpgYGANCg0KPGJyLz48YnIvPg0KDQojIyMjIFM0LjEuNDogUHVibGljYXRpb24gYmlhcyB0ZXN0cyB3aXRoIG11bHRpbGV2ZWwgbWV0YS1yZWdyZXNzaW9uDQoNCiMjIyMjIFM0LjEuNC4xOiBNZXRhLXJlZ3Jlc3Npb24gd2l0aCBTRSAodW5pLW1vZGVyYXRvcikNCg0KVG8gdGVzdCBmb3IgcHVibGljYXRpb24gYmlhcywgd2UgY2FuIGZpcnN0IGZpdCBhIHBoeWxvZ2VuZXRpYyBtdWx0aWxldmVsIG1ldGEtcmVncmVzc2lvbiB0byBleHBsb3JlIHdoZXRoZXIgdGhlcmUgaXMgc29tZSBldmlkZW5jZSBvZiBzbWFsbC1zdHVkeSBlZmZlY3RzIGluIG91ciBtZXRhLWFuYWx5dGljIGRhdGFzZXQuIFRvIGRvIHNvLCB3ZSBmaXQgYSB1bmktbW9kZXJhdG9yIHBoeWxvZ2VuZXRpYyBtdWx0aWxldmVsIG1ldGEtcmVncmVzc2lvbiBpbmNsdWRpbmcgdGhlIGVmZmVjdCBzaXplcycgc3RhbmRhcmQgZXJyb3JzIChTRSBvciBzZWkpIGFzIHRoZSBvbmx5IG1vZGVyYXRvciAoc2VlIEVxdWF0aW9uIDIxIGZyb20gdGhlIG1haW4gdGV4dCkuIFRoaXMgbWV0YS1yZWdyZXNzaW9uIHdpbGwgcHJvdmlkZSBzb21lIGluZm9ybWF0aW9uIGFib3V0IHRoZSBleGlzdGVuY2Ugb2Ygc21hbGwtc3R1ZHkgZWZmZWN0cyAoaS5lLiBhc3ltbWV0cnkgaW4gdGhlIGRpc3RyaWJ1dGlvbiBvZiBlZmZlY3Qgc2l6ZXMpLCBidXQgdGhlIGJlc3QgZXZpZGVuY2UgZm9yIHNtYWxsLXN0dWR5IGVmZmVjdHMgd2lsbCBjb21lIGZyb20gdGhlIGFsbC1pbiBwdWJsaWNhdGlvbiBiaWFzIHRlc3QgKG11bHRpLW1vZGVyYXRvciBtZXRhLXJlZ3Jlc3Npb24pIGRlc2NyaWJlZCBpbiBzZWN0aW9uIFM0LjEuNC4zLCBzaW5jZSB0aGlzIG11bHRpLW1vZGVyYXRvciBtZXRhLXJlZ3Jlc3Npb24gd2lsbCB0ZXN0IHdoZXRoZXIgYXN5bW1ldHJ5IGV4aXN0cyBhZnRlciBhY2NvdW50aW5nIGZvciB0aGUgaGV0ZXJvZ2VuZWl0eSBleHBsYWluZWQgYnkgYWxsIHRoZSBpbmNsdWRlZCBtb2RlcmF0b3JzIChtb3JlIGluIHRoZSBtYWluIHRleHQpLg0KDQpgYGB7cn0NCiMgY3JlYXRpbmcgYSB2YXJpYWJsZSBmb3IgdGhlIHN0YW5kYXJkIGVycm9yIG9mIGVhY2ggZWZmZWN0IHNpemUgKGkuZS4gdGhlIHNxdWFyZSByb290IG9mIHRoZSBzYW1wbGluZyB2YXJpYW5jZSwgc2VlIEZpZ3VyZSAxIGZyb20gdGhlIG1haW4gdGV4dCkNCmRhdGFzZXQuciRzZWkgPC0gc3FydChkYXRhc2V0LnIkdmkpDQoNCiMgQXBwbGljYXRpb24gb2YgRXF1YXRpb24gMjEgZnJvbSB0aGUgbWFpbiB0ZXh0DQpwdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnIuc2UgPC0gcm1hLm12KHlpLCB2aSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kID1+MStzZWksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmRvbT1saXN0KH4gMSB8IFNwZWNpZXMudXBkYXRlZCwgIyBwaHlsbyBlZmZlY3QNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfiAxIHwgU3BlY2llcywgIyBub24tcGh5bG8gZWZmZWN0DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH4gMSB8IHN0dWR5LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfiAxIHwgb2JzSUQpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUiA9IGxpc3QoU3BlY2llcy51cGRhdGVkID0gcGh5bG9fY29yKSwgI3BoeWxvZ2VuZXRpYyByZWxhdGVkbmVzcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2Q9IlJFTUwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXN0PSJ0IiwgIyB1c2luZyB0IGRpc3QgcmF0aGVyIHRoYW4geiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1kYXRhc2V0LnIpDQoNCiMgcHJpbnQocHVibGljYXRpb24uYmlhcy5tb2RlbC5yLnNlLGRpZ2l0cz0zKQ0KDQojIGV4dHJhY3RpbmcgdGhlIG1lYW4gYW5kIDk1JSBjb25maWRlbmNlIGludGVydmFscw0KZXN0aW1hdGVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuci5zZSA8LSBlc3RpbWF0ZXMuQ0kocHVibGljYXRpb24uYmlhcy5tb2RlbC5yLnNlKQ0KYGBgDQoNCkFjY29yZGluZyB0byB0aGlzIHVuaS1tb2RlcmF0b3IgbWV0YS1yZWdyZXNzaW9uLCB0aGVyZSBpcyBzb21lIGluZGljYXRpb24gb2Ygc21hbGwtc3R1ZHkgZWZmZWN0cyBzaW5jZSB0aGUgc2xvcGUgb2YgdGhlIG1vZGVyYXRvciAnU0UnIGlzIGNsb3NlIHRvIHN0YXRpc3RpY2FsIHNpZ25pZmljYW5jZSAoc2xvcGUgPSBgciByb3VuZChlc3RpbWF0ZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5yLnNlWzIsMl0sMilgLCA5NSUgQ0kgPSBbYHIgcm91bmQoZXN0aW1hdGVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuci5zZVsyLDNdLDIpYCxgciByb3VuZChlc3RpbWF0ZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5yLnNlWzIsNF0sMilgXTsgKlIqPHN1cD4yPC9zdXA+PHN1Yj5tYXJnaW5hbDwvc3ViPiA9IGByIHJvdW5kKG9yY2hhUmQ6OnIyX21sKHB1YmxpY2F0aW9uLmJpYXMubW9kZWwuci5zZSlbWzFdXSoxMDAsMSlgJSksIHNob3dpbmcgdGhhdCBlZmZlY3Qgc2l6ZXMgd2l0aCBsYXJnZXIgU0UgKG1vcmUgdW5jZXJ0YWluIGVmZmVjdCBzaXplcykgdGVuZCB0byBiZSBsYXJnZXIuIE5vbmV0aGVsZXNzLCBhcyBtZW50aW9uZWQgYWJvdmUsIHdlIHdpbGwgY29uZmlybSB0aGUgZXhpc3RlbmNlIG9mIHNtYWxsLXN0dWR5IGVmZmVjdHMgYWZ0ZXIgYWNjb3VudGluZyBmb3Igc29tZSBvZiB0aGUgaGV0ZXJvZ2VuZWl0eSBwcmVzZW50IGluIHRoZSBkYXRhIHVzaW5nIHRoZSBhbGwtaW4gcHVibGljYXRpb24gYmlhcyB0ZXN0IChtdWx0aS1tb2RlcmF0b3IgbWV0YS1yZWdyZXNzaW9uKSBkZXNjcmliZWQgaW4gc2VjdGlvbiBTNC4xLjQuMy4NCg0KIyMjIyMgUzQuMS40LjI6IE1ldGEtcmVncmVzc2lvbiB3aXRoIHllYXIgb2YgcHVibGljYXRpb24gKHVuaS1tb2RlcmF0b3IpDQoNClRvIHRlc3QgZm9yIHRpbWUtbGFnIGJpYXMgKGFsc28gY2FsbGVkIGRlY2xpbmUgZWZmZWN0cykgd2UgY2FuIGZpcnN0IGZpdCBhIHVuaS1tb2RlcmF0b3IgcGh5bG9nZW5ldGljIG11bHRpbGV2ZWwgbWV0YS1yZWdyZXNzaW9uIGluY2x1ZGluZyB0aGUgeWVhciBvZiBwdWJsaWNhdGlvbiAobWVhbi1jZW50cmVkKSBhcyB0aGUgb25seSBtb2RlcmF0b3IgKHNlZSBFcXVhdGlvbiAyMyBmcm9tIHRoZSBtYWluIHRleHQpLiBUaGUgZXN0aW1hdGVkIHNsb3BlIGZvciB5ZWFyIG9mIHB1YmxpY2F0aW9uIHdpbGwgcHJvdmlkZSBzb21lIGV2aWRlbmNlIG9uIHdoZXRoZXIgZWZmZWN0IHNpemVzIGhhdmUgY2hhbmdlZCBsaW5lYXJseSBvdmVyIHRpbWUgc2luY2UgdGhlIGZpcnN0IGVmZmVjdCBzaXplIHdhcyBwdWJsaXNoZWQ7IGhvd2V2ZXIsIGFzIGFib3ZlLCB0aGUgYmVzdCBldmlkZW5jZSBmb3Igc3VjaCBkZWNsaW5lIGVmZmVjdHMgd2lsbCBjb21lIGZyb20gdGhlIGFsbC1pbiBwdWJsaWNhdGlvbiBiaWFzIHRlc3QgKG11bHRpLW1vZGVyYXRvciBtZXRhLXJlZ3Jlc3Npb24pIGRlc2NyaWJlZCBpbiBzZWN0aW9uIFM0LjEuNC4zLCBzaW5jZSB0aGlzIG11bHRpLW1vZGVyYXRvciBtZXRhLXJlZ3Jlc3Npb24gd2lsbCB0ZXN0IGZvciB0aGUgZXhpc3RlbmNlIG9mIGRlY2xpbmUgZWZmZWN0cyBhZnRlciBhY2NvdW50aW5nIGZvciB0aGUgaGV0ZXJvZ2VuZWl0eSBleHBsYWluZWQgYnkgYWxsIHRoZSBpbmNsdWRlZCBtb2RlcmF0b3JzIChtb3JlIGluIHRoZSBtYWluIHRleHQpLg0KDQpgYGB7cn0NCiMgY3JlYXRpbmcgYSB2YXJpYWJsZSB3aXRoIHRoZSB5ZWFyIG9mIHB1YmxpY2F0aW9uDQpkYXRhc2V0LnIkeWVhciA8LSBhcy5udW1lcmljKHN0cl9leHRyYWN0KGRhdGFzZXQuciRzdHVkeSwgIihcXGQpKyIpKQ0KDQojIG1lYW4tY2VudHJpbmcgeWVhciBvZiBwdWJsaWNhdGlvbiB0byBoZWxwIHdpdGggaW50ZXJwcmV0YXRpb24sIHBhcnRpY3VsYXJseSBpbiBTNC4xLjQuMy4NCmRhdGFzZXQuciR5ZWFyLmMgPC0gYXMudmVjdG9yKHNjYWxlKGRhdGFzZXQuciR5ZWFyLCBzY2FsZSA9IEYpKQ0KDQojIEFwcGxpY2F0aW9uIG9mIEVxdWF0aW9uIDIzIGZyb20gdGhlIG1haW4gbWFudXNjcmlwdA0KcHVibGljYXRpb24uYmlhcy5tb2RlbC5yLnRpbWVsYWcgPC0gcm1hLm12KHlpLCB2aSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RzPX4xK3llYXIuYywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb209bGlzdCh+IDEgfCBTcGVjaWVzLnVwZGF0ZWQsICMgcGh5bG8gZWZmZWN0DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfiAxIHwgU3BlY2llcywgIyBub24tcGh5bG8gZWZmZWN0DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfiAxIHwgc3R1ZHksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH4gMSB8IG9ic0lEKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUiA9IGxpc3QoU3BlY2llcy51cGRhdGVkID0gcGh5bG9fY29yKSwgI3BoeWxvZ2VuZXRpYyByZWxhdGVkbmVzcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZD0iUkVNTCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdD0idCIsICMgdXNpbmcgdCBkaXN0IHJhdGhlciB0aGFuIHogDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1kYXRhc2V0LnIpDQoNCiMgc3VtbWFyeShwdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnIudGltZWxhZykNCg0KIyBleHRyYWN0aW5nIHRoZSBtZWFuIGFuZCA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbHMNCmVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnIudGltZWxhZyA8LSBlc3RpbWF0ZXMuQ0kocHVibGljYXRpb24uYmlhcy5tb2RlbC5yLnRpbWVsYWcpDQpgYGANCg0KQWNjb3JkaW5nIHRvIHRoaXMgdW5pLW1vZGVyYXRvciBtZXRhLXJlZ3Jlc3Npb24sIHRoZXJlIGlzIG5vIGluZGljYXRpb24gb2YgZGVjbGluZSBlZmZlY3RzIHNpbmNlIHRoZSBzbG9wZSBvZiB0aGUgbW9kZXJhdG9yICd5ZWFyIG9mIHB1YmxpY2F0aW9uJyBpcyBlc3NlbnRpYWxseSB6ZXJvIChzbG9wZSA9IGByIHJvdW5kKGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnIudGltZWxhZ1syLDJdLDIpYCwgOTUlIENJID0gW2ByIHJvdW5kKGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnIudGltZWxhZ1syLDNdLDIpYCxgciByb3VuZChlc3RpbWF0ZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5yLnRpbWVsYWdbMiw0XSwyKWBdOyAqUio8c3VwPjI8L3N1cD48c3ViPm1hcmdpbmFsPC9zdWI+ID0gYHIgcm91bmQob3JjaGFSZDo6cjJfbWwocHVibGljYXRpb24uYmlhcy5tb2RlbC5yLnRpbWVsYWcpW1sxXV0qMTAwLDEpYCUpLiBOb25ldGhlbGVzcywgYXMgbWVudGlvbmVkIGFib3ZlLCB3ZSBuZWVkIHRvIGNvbmZpcm0gdGhpcyBwYXR0ZXJuIGFmdGVyIGFjY291bnRpbmcgZm9yIHNvbWUgb2YgdGhlIGhldGVyb2dlbmVpdHkgcHJlc2VudCBpbiB0aGUgZGF0YSB1c2luZyB0aGUgYWxsLWluIHB1YmxpY2F0aW9uIGJpYXMgdGVzdCAobXVsdGktbW9kZXJhdG9yIG1ldGEtcmVncmVzc2lvbikgZGVzY3JpYmVkIGluIHNlY3Rpb24gUzQuMS40LjMuDQoNCiMjIyMjIFM0LjEuNC4zOiBBbGwtaW4gcHVibGljYXRpb24gYmlhcyB0ZXN0IChtdWx0aS1tb2RlcmF0b3IpDQoNCldoZW4gaGV0ZXJvZ2VuZWl0eSBleGlzdHMgKHdoaWNoIGlzIG5vcm1hbGx5IHRoZSBjYXNlIGluIGVjb2xvZ3kgYW5kIGV2b2x1dGlvbjsgU2VuaW9yIGV0IGFsLiAyMDE2KSwgaXQgaXMgYmVzdCB0byBjb21iaW5lIEVxdWF0aW9ucyAyMSBhbmQgMjMgd2l0aCBvdGhlciBtb2RlcmF0b3JzIHNpbmNlIHRob3NlIGFkZGl0aW9uYWwgbW9kZXJhdG9ycyB3aWxsIGdlbmVyYWxseSBiZSBleHBlY3RlZCB0byBleHBsYWluIHNvbWUgb2YgdGhlIGhldGVyb2dlbmVpdHkuIFRoYXQgaXMsIHRoaXMgYWxsLWluIHB1YmxpY2F0aW9uIGJpYXMgdGVzdCAobXVsdGktbW9kZXJhdG9yIG1ldGEtcmVncmVzc2lvbikgd291bGQgYmUgdGhlIGJlc3QgdGVzdCBvZiBzbWFsbC1zdHVkeSAocHVibGljYXRpb24gYmlhcykgYW5kIGRlY2xpbmUgZWZmZWN0cyAodGltZS1sYWcgYmlhcykgaW4gbW9zdCBtZXRhLWFuYWx5dGljIGRhdGFzZXRzLiBGb3Igb3VyIGRhdGEsIHdlIHdpbGwgcnVuIGEgbXVsdGktbW9kZXJhdG9yIHBoeWxvZ2VuZXRpYyBtdWx0aWxldmVsIG1ldGEtcmVncmVzc2lvbiBpbmNsdWRpbmcgdGhlIGVmZmVjdCBzaXplcycgc3RhbmRhcmQgZXJyb3JzLCB0aGUgeWVhciBvZiBwdWJsaWNhdGlvbiAobWVhbi1jZW50cmVkKSBhbmQgYSBtb2RlcmF0b3Igb3JpZ2luYWxseSBpbmNsdWRlZCBpbiBHYXJhbXN6ZWdpIGV0IGFsLiAoMjAxMiksICdjYXB0aXZpdHkgc3RhdHVzJyAoYENhcHRpdml0eUNgKS4gQWx0aG91Z2ggR2FyYW1zemVnaSBldCBhbC4gKDIwMTIpIGluY2x1ZGVkIG90aGVyIG1vZGVyYXRvcnMgaW4gdGhlaXIgbW9kZWwgKGkuZS4gc3BlY2llcywgdGF4b25vbWljIGNsYXNzLCBzcGF0aWFsIG92ZXJsYXAsIGFnZSwgc2V4IGFuZCBzZWFzb24pLCB3ZSBkZWNpZGVkIHRvIGZvY3VzIG9ubHkgb24gdGhvc2UgbW9kZXJhdG9ycyB0aGF0IHdlcmUgYXZhaWxhYmxlIGZvciB0aGUgZW50aXJlIGRhdGFzZXQgKGkuZS4gbm8gTkEncyBvciBtaXNzaW5nIGRhdGEsIHNlZSBUYWJsZSAyIGluIEdhcmFtc3plZ2kgZXQgYWwuIDIwMTIpLCBhbmQgd2UgYWxzbyBleGNsdWRlZCAnc3BlY2llcycgKGFuZCAndGF4b25vbWljIGNsYXNzJykgc2luY2Ugc3BlY2llcyBlZmZlY3RzIGFyZSBhbHJlYWR5IGNhcHR1cmVkIGFzIGEgcmFuZG9tIGVmZmVjdCBhbmQgY29ycmVsYXRpb24gbWF0cml4IGluIG91ciBwaHlsb2dlbmV0aWMgYXBwcm9hY2guDQoNCmBgYHtyfQ0KIyBBcHBsaWNhdGlvbiBvZiBFcXVhdGlvbiAyNCBmcm9tIHRoZSBtYWluIG1hbnVzY3JpcHQNCnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuci5hbGwuc2UgPC0gcm1hLm12KHlpLCB2aSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZHM9fjErDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlaSsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhci5jKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDYXB0aXZpdHlDLCAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFuZG9tPWxpc3QofiAxIHwgU3BlY2llcy51cGRhdGVkLCAjIHBoeWxvIGVmZmVjdA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfiAxIHwgU3BlY2llcywgIyBub24tcGh5bG8gZWZmZWN0DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB+IDEgfCBzdHVkeSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB+IDEgfCBvYnNJRCksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUiA9IGxpc3QoU3BlY2llcy51cGRhdGVkID0gcGh5bG9fY29yKSwgI3BoeWxvZ2VuZXRpYyByZWxhdGVkbmVzcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kPSJSRU1MIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlc3Q9InQiLCAjIHVzaW5nIHQgZGlzdCByYXRoZXIgdGhhbiB6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhPWRhdGFzZXQucikNCg0KI3N1bW1hcnkocHVibGljYXRpb24uYmlhcy5tb2RlbC5yLmFsbC5zZSkNCg0KIyBleHRyYWN0aW5nIHRoZSBtZWFuIGFuZCA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbHMNCmVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnIuYWxsLnNlIDwtIGVzdGltYXRlcy5DSShwdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnIuYWxsLnNlKQ0KYGBgDQoNClRoZSBhbGwtaW4gcHVibGljYXRpb24gYmlhcyB0ZXN0IGFncmVlcyB3aXRoIHdoYXQgd2Ugb2JzZXJ2ZWQgaW4gdGhlIHVuaS1tb2RlcmF0b3IgbWV0YS1yZWdyZXNzaW9ucyBhYm92ZSAoc2VjdGlvbnMgUzQuMS40LjEgYW5kIFM0LjEuNC4yKS4gRmlyc3QsIHRoZSBtdWx0aS1tb2RlcmF0b3IgbWV0YS1yZWdyZXNzaW9uIHNob3dzIGEgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBzbG9wZSBmb3IgdGhlIG1vZGVyYXRvciAnU0UnIChzbG9wZSA9IGByIHJvdW5kKGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnIuYWxsLnNlWzEsMl0sMilgLCA5NSUgQ0kgPSBbYHIgcm91bmQoZXN0aW1hdGVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuci5hbGwuc2VbMSwzXSwyKWAsYHIgcm91bmQoZXN0aW1hdGVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuci5hbGwuc2VbMSw0XSwyKWBdOyBGaWd1cmUgUzQuNCksIHNob3dpbmcgZXZpZGVuY2Ugb2Ygc21hbGwtc3R1ZHkgZWZmZWN0cy4gSW4gb3RoZXIgd29yZHMsIHRoZSBsYXJnZXN0IGVmZmVjdCBzaXplcyBpbiB0aGUgZGF0YXNldCB0ZW5kIHRvIGJlIHRob3NlIHdpdGggdGhlIGxvd2VzdCBwcmVjaXNpb24gKGkuZS4gbGFyZ2VyIHVuY2VydGFpbnR5OyBGaWd1cmUgUzQuNCkuIFRoaXMgcmVzdWx0IGFncmVlcyB3aXRoIHRoZSBmaW5kaW5ncyBvcmlnaW5hbGx5IHJlcG9ydGVkIGluIEdhcmFtc3plZ2kgZXQgYWwuICgyMDEyKSwgd2hlcmUgdGhlIGF1dGhvcnMgZm91bmQgZXZpZGVuY2Ugb2YgcHVibGljYXRpb24gYmlhcyBhZnRlciBhcHBseWluZyBhIHNpbXBsZSBjb3JyZWxhdGlvbiBtZXRob2QgcHJvcG9zZWQgYnkgQmVnZyBhbmQgTWF6dW1kYXIgKDE5OTQpIGFuZCB0aGUgdHJpbS1hbmQtZmlsbCBtZXRob2QgKER1dmFsIGFuZCBUd2VlZGllIDIwMDBhLGIpIC0gYWx0aG91Z2ggYmVhciBpbiBtaW5kIHRoYXQgd2UgZG8gbm90IHJlY29tbWVuZCB0byB1c2UgdGhvc2Ugc2ltcGxlciBtZXRob2RzIGZvciBtZXRhLWFuYWx5dGljIGRhdGFzZXRzIHdpdGggbXVsdGlwbGUgbGV2ZWxzIG9mIG5vbi1pbmRlcGVuZGVuY2UgYW5kIGhpZ2ggaGV0ZXJvZ2VuZWl0eSAobW9yZSBpbiB0aGUgbWFpbiB0ZXh0OyBzZWUgYWx0ZXJuYXRpdmUgaW4gc2VjdGlvbiBTNSkuIFNlY29uZCwgdGhlIGFsbC1pbiBwdWJsaWNhdGlvbiBiaWFzIHRlc3QgYWxzbyBjb25maXJtcyB0aGF0IHRoZXJlIGlzIG5vIGV2aWRlbmNlIG9mIGRlY2xpbmUgZWZmZWN0cyBpbiB0aGUgZGF0YSBzaW5jZSB0aGUgc2xvcGUgb2YgdGhlIG1vZGVyYXRvciAneWVhciBvZiBwdWJsaWNhdGlvbicgd2FzIGFnYWluIGluZGlzdGluZ3Vpc2hhYmxlIGZyb20gemVybyAoc2xvcGUgPSBgciByb3VuZChlc3RpbWF0ZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5yLmFsbC5zZVsyLDJdLDIpYCwgOTUlIENJID0gW2ByIHJvdW5kKGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnIuYWxsLnNlWzIsM10sMilgLGByIHJvdW5kKGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnIuYWxsLnNlWzIsNF0sMilgXTsgRmlndXJlIFM0LjUpLiBPdmVyYWxsLCB0aGUgbW9kZXJhdG9ycyBpbmNsdWRlZCBpbiB0aGlzIG11bHRpLW1vZGVyYXRvciBtZXRhLXJlZ3Jlc3Npb24gZXhwbGFpbmVkIGEgdG90YWwgb2YgYHIgcm91bmQob3JjaGFSZDo6cjJfbWwocHVibGljYXRpb24uYmlhcy5tb2RlbC5yLmFsbC5zZSlbWzFdXSoxMDAsMSlgJSAoaS5lLiAqUio8c3VwPjI8L3N1cD48c3ViPm1hcmdpbmFsPC9zdWI+KSBvZiB0aGUgaGV0ZXJvZ2VuZWl0eSBvYnNlcnZlZCBpbiB0aGUgbWV0YS1hbmFseXRpYyBtb2RlbCAoc2VlIFRhYmxlIFM0LjEpLg0KDQojIyMjIyBGaWd1cmUgUzQuNA0KDQpgYGB7ciBmaWcuaGVpZ2h0ID0gNS41LCBmaWcud2lkdGggPSA3LjUsIGZpZy5hbGlnbiA9ICJjZW50ZXIiLCBmaWcuY2FwPSJFZmZlY3Qgc2l6ZXMgd2l0aCBsYXJnZXIgc3RhbmRhcmQgZXJyb3JzIHRlbmQgdG8gYmUgbGFyZ2VyLCBwcm92aWRpbmcgZXZpZGVuY2Ugb2Ygc21hbGwtc3R1ZHkgZWZmZWN0cyBpbiB0aGUgbWV0YS1hbmFseXRpYyBkYXRhc2V0LiBUaGUgc29saWQgbGluZSByZXByZXNlbnRzIHRoZSBtb2RlbCBlc3RpbWF0ZSBhbmQgdGhlIHNoYWRpbmcgc2hvd3MgaXRzIDk1JSBjb25maWRlbmNlIGludGVydmFscy4ifQ0KIyBwcmVkaWN0aW5nIGVmZmVjdCBzaXplcyBmb3IgYSByYW5nZSBvZiBTRSBmcm9tIHRoZSBtaW5pbXVtIG9ic2VydmVkIGluIHRoZSBkYXRhIHRvIHRoZSBtYXhpbXVtIG9ic2VydmVkIGluIGRhdGEsIHdoaWxlIHllYXIgaXMga2VwdCBhdCBpdHMgbWVhbiB2YWx1ZSwgaW4gdGhpcyBjYXNlIDAgc2luY2UgeWVhciB3YXMgbWVhbi1jZW50cmVkDQojIGNvbmRpdGlvbiBvbiBGQw0KcHJlZGljdC5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnIuYWxsLnNlLnBsb3QuMSA8LSBwcmVkaWN0KHB1YmxpY2F0aW9uLmJpYXMubW9kZWwuci5hbGwuc2UsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3bW9kcz1jYmluZChzZXEobWluKGRhdGFzZXQuciRzZWkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heChkYXRhc2V0LnIkc2VpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLjAwNSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKDApLCAwLCAwLCAwLCAwKSkNCg0KbmV3ZGF0IDwtIGRhdGEuZnJhbWUoc2VpPXNlcShtaW4oZGF0YXNldC5yJHNlaSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heChkYXRhc2V0LnIkc2VpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMC4wMDUpLA0KICAgICAgICAgICAgICAgICAgICAgZml0PXByZWRpY3QucHVibGljYXRpb24uYmlhcy5tb2RlbC5yLmFsbC5zZS5wbG90LjEkcHJlZCwNCiAgICAgICAgICAgICAgICAgICAgIHVwcGVyPXByZWRpY3QucHVibGljYXRpb24uYmlhcy5tb2RlbC5yLmFsbC5zZS5wbG90LjEkY2kudWIsDQogICAgICAgICAgICAgICAgICAgICBsb3dlcj1wcmVkaWN0LnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuci5hbGwuc2UucGxvdC4xJGNpLmxiLA0KICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSkNCg0KeGF4aXMgPC0gZGF0YXNldC5yJHNlaQ0KeWF4aXMgPC0gZGF0YXNldC5yJHlpDQoNCnBsb3QoeGF4aXMseWF4aXMsDQogICAgIHR5cGU9Im4iLA0KICAgICB5bGFiPSIiLA0KICAgICB4bGFiPSIiLA0KICAgICB4YXh0PSJuIiwNCiAgICAgeWF4dD0ibiIsDQogICAgIHlsaW09YygtMi4yNSwyLjI1KSwNCiAgICAgeGxpbT1jKDAsMSkpDQoNCmFibGluZShhPTAsYj0wLCBsd2Q9MSwgbHR5PTEpDQoNCmF4aXMoMSxhdD1zZXEoMCwxLDAuMSksDQogICAgIGNleC5heGlzPTAuOCx0Y2s9LTAuMDIpDQoNCmF4aXMoMiwNCiAgICAgYXQ9cm91bmQoc2VxKC0yLjUsMi4yNSwwLjUpLDEpLA0KICAgICBjZXguYXhpcz0wLjgsbGFzPTIsdGNrPS0wLjAyKQ0KDQp0aXRsZSh4bGFiID0gInN0YW5kYXJkIGVycm9yIChTRSkiLCANCiAgICAgIHlsYWIgPSAiZWZmZWN0IHNpemUgKFpyKSIsDQogICAgICBsaW5lID0gMi43NSwgY2V4LmxhYj0xLjQpDQoNCnBvaW50cyh4YXhpcyx5YXhpcywNCiAgICAgICBiZz1yZ2IoMCwwLDAsIDAuMSksDQogICAgICAgY29sPXJnYigwLDAsMCwgMC4yKSwNCiAgICAgICBwY2g9MjEsDQogICAgICAgY2V4PTEpDQoNCmxpbmVzKG5ld2RhdCRzZWksIG5ld2RhdCRmaXQsIGx3ZD0yLjc1LGNvbD0iZGFya29yY2hpZDQiKSANCg0KcG9seWdvbihjKG5ld2RhdCRzZWkscmV2KG5ld2RhdCRzZWkpKSwNCiAgICAgICAgYyhuZXdkYXQkbG93ZXIscmV2KG5ld2RhdCR1cHBlcikpLA0KICAgICAgICBib3JkZXI9TkEsY29sPXJnYigxMDQvMjU1LDM0LzI1NSwxMzkvMjU1LCAwLjUpKQ0KYGBgDQoNCjxici8+PGJyLz4NCg0KIyMjIyMgRmlndXJlIFM0LjUNCg0KYGBge3IgZmlnLmhlaWdodCA9IDUuNSwgZmlnLndpZHRoID0gNy41LCBmaWcuYWxpZ24gPSAiY2VudGVyIiwgZmlnLmNhcD0iVGhlIG92ZXJhbGwgZWZmZWN0IHNpemUgaGFzIG5vdCBjaGFuZ2VkIG92ZXIgdGltZS4gVGhlIHNvbGlkIGxpbmUgcmVwcmVzZW50cyB0aGUgbW9kZWwgZXN0aW1hdGUsIHRoZSBzaGFkaW5nIHNob3dzIGl0cyA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbHMgYW5kIGluZGl2aWR1YWwgZWZmZWN0IHNpemVzIGFyZSBzY2FsZWQgYnkgdGhlaXIgcHJlY2lzaW9uICgxL1NFKS4ifQ0KIyBwcmVkaWN0aW5nIGVmZmVjdCBzaXplcyBmb3IgYSByYW5nZSBvZiB5ZWFycyBmcm9tIHRoZSBtaW5pbXVtIG9ic2VydmVkIGluIHRoZSBkYXRhIHRvIHRoZSBtYXhpbXVtIG9ic2VydmVkIGluIGRhdGEsIHdoaWxlIFNFIGlzIGtlcHQgYXQgaXRzIG1lYW4gdmFsdWUuIEtlZXAgaW4gbWluZCB0aGF0IGFsdGVybmF0aXZlIHdheXMgY291bGQgYmUgdXNlZCwgZm9yIGV4YW1wbGUsIG9uZSBjb3VsZCB1c2UgbWVkaWFuLWNlbnRyaW5nIHJhdGhlciB0aGFuIG1lYW4tY2VudHJpbmcuDQojIGNvbmRpdGlvbmVkIG9uIEZDDQpwcmVkaWN0LnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuci5hbGwuc2UucGxvdC4yIDwtIHByZWRpY3QocHVibGljYXRpb24uYmlhcy5tb2RlbC5yLmFsbC5zZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXdtb2RzPWNiaW5kKG1lYW4oZGF0YXNldC5yJHNlaSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXEobWluKGRhdGFzZXQuciR5ZWFyLmMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heChkYXRhc2V0LnIkeWVhci5jKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLjI1KSwwLCAwLDAsMCkpDQoNCg0KDQoNCm5ld2RhdCA8LSBkYXRhLmZyYW1lKHllYXI9c2VxKG1pbihkYXRhc2V0LnIkeWVhciksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXgoZGF0YXNldC5yJHllYXIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMC4yNSksDQogICAgICAgICAgICAgICAgICAgICBmaXQ9cHJlZGljdC5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnIuYWxsLnNlLnBsb3QuMiRwcmVkLA0KICAgICAgICAgICAgICAgICAgICAgdXBwZXI9cHJlZGljdC5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnIuYWxsLnNlLnBsb3QuMiRjaS51YiwNCiAgICAgICAgICAgICAgICAgICAgIGxvd2VyPXByZWRpY3QucHVibGljYXRpb24uYmlhcy5tb2RlbC5yLmFsbC5zZS5wbG90LjIkY2kubGIsDQogICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKQ0KDQp4YXhpcyA8LSBkYXRhc2V0LnIkeWVhcg0KeWF4aXMgPC0gZGF0YXNldC5yJHlpDQpjZXguc3R1ZHkgPC0gKDEvZGF0YXNldC5yJHNlaSkvNA0KDQpwbG90KHhheGlzLHlheGlzLA0KICAgICB0eXBlPSJuIiwNCiAgICAgeWxhYj0iIiwNCiAgICAgeGxhYj0iIiwNCiAgICAgeGF4dD0ibiIsDQogICAgIHlheHQ9Im4iLA0KICAgICB5bGltPWMoLTIuMjUsMi4yNSksDQogICAgIHhsaW09YyhtaW4oZGF0YXNldC5yJHllYXIpLG1heChkYXRhc2V0LnIkeWVhcikpKQ0KDQphYmxpbmUoYT0wLGI9MCwgbHdkPTEsIGx0eT0xKQ0KDQpheGlzKDEsYXQ9c2VxKG1pbihkYXRhc2V0LnIkeWVhciksbWF4KGRhdGFzZXQuciR5ZWFyKSw1KSwNCiAgICAgY2V4LmF4aXM9MC44LHRjaz0tMC4wMikNCg0KYXhpcygyLA0KICAgICBhdD1yb3VuZChzZXEoLTIuNSwyLjI1LDAuNSksMSksDQogICAgIGNleC5heGlzPTAuOCxsYXM9Mix0Y2s9LTAuMDIpDQoNCnRpdGxlKHhsYWIgPSAieWVhciBvZiBwdWJsaWNhdGlvbiIsIA0KICAgICAgeWxhYiA9ICJlZmZlY3Qgc2l6ZSAoWnIpIiwNCiAgICAgIGxpbmUgPSAyLjc1LCBjZXgubGFiPTEuNCkNCg0KcG9pbnRzKHhheGlzLHlheGlzLA0KICAgICAgIGJnPXJnYigwLDAsMCwgMC4xKSwNCiAgICAgICBjb2w9cmdiKDAsMCwwLCAwLjIpLA0KICAgICAgIHBjaD0yMSwNCiAgICAgICBjZXg9Y2V4LnN0dWR5KQ0KDQpsaW5lcyhuZXdkYXQkeWVhciwgbmV3ZGF0JGZpdCwgbHdkPTIuNzUsY29sPSJkYXJrb3JjaGlkNCIpIA0KDQpwb2x5Z29uKGMobmV3ZGF0JHllYXIscmV2KG5ld2RhdCR5ZWFyKSksDQogICAgICAgIGMobmV3ZGF0JGxvd2VyLHJldihuZXdkYXQkdXBwZXIpKSwNCiAgICAgICAgYm9yZGVyPU5BLGNvbD1yZ2IoMTA0LzI1NSwzNC8yNTUsMTM5LzI1NSwgMC41KSkNCmBgYA0KDQo8YnIvPjxici8+DQoNCiMjIyMgUzQuMS41OiBBZGp1c3Rpbmcgb3ZlcmFsbCBlZmZlY3Qgc2l6ZSBlc3RpbWF0ZXMgZm9yIFpyDQoNCk9uY2Ugd2UgaGF2ZSBjb25maXJtZWQgdGhhdCB0aGVyZSBpcyBldmlkZW5jZSBvZiBzbWFsbC1zdHVkeSBlZmZlY3RzIChzZWUgYWJvdmUpLCB0aGUgbmV4dCBzdGVwIGluIG91ciBzdWdnZXN0ZWQgdHdvLXN0ZXAgYXBwcm9hY2ggaXMgdG8gY2FsY3VsYXRlIHRoZSBhZGp1c3RlZCBvdmVyYWxsIGVmZmVjdCBzaXplLCB0aGF0IGlzLCB0aGUgb3ZlcmFsbCBlZmZlY3Qgb25jZSB3ZSBhY2NvdW50IGZvciBwdWJsaWNhdGlvbiBiaWFzIChzZWUgdGhlIG1haW4gdGV4dCkuDQoNCkluIGEgc2ltcGxlciBtZXRhLXJlZ3Jlc3Npb24gbW9kZWwgKG9ubHkgd2l0aCB0aGUgbW9kZXJhdG9yICdTRScpLCB0aGUgYmVzdCBlc3RpbWF0ZSBmb3IgdGhlIGFkanVzdGVkIG92ZXJhbGwgZWZmZWN0IHNpemUgd291bGQgYmUgdGhlICppbnRlcmNlcHQqIG9mIHRoYXQgbW9kZWwsIHdoZW4gdGhlIGludGVyY2VwdCBpcyBub3Qgc2lnbmlmaWNhbnQgKGkuZS4gU3RhbmxleSBhbmQgRG91Y291bGlhZ29zIDIwMTIsIDIwMTQ7IG1vcmUgaW4gdGhlIG1haW4gdGV4dCBhbmQgYWxzbyBzZWUgb3VyIGNvcnJpZ2VuZHVtKS4gTm90ZSB0aGF0IFN0YW5sZXkgKDIwMTcpIHN1Z2dlc3RzIHRvIHVzZSB0aGUgc2lnbmlmaWNhbmNlIGxldmVsIG9mIDEwJSB0byBhc3Nlc3MgdGhlIGludGVyY2VwdCdzIHN0YXRpc3RpY2FsIHNpZ25pZmljYW5jZS4gSW4gYSBjb21wbGV4IG1vZGVsIHdpdGggYSBjYXRlZ29yaWNhbCB2YXJpYWJsZXMsIGl0IGlzIGRpZmZpY3VsdCB0byBkZWNpZGUgd2hhdCBpcyB0aGUgaW50ZXJjZXB0LiBOb25ldGhlbGVzcywgdGhlIG1vZGVscyBhYm92ZSBzdWdnZXN0IHRoYXQgdGhlcmUgYXJlIGluZGljYXRpb25zIG9mIHNvbWUgZWZmZWN0cyBhdCBsZWFzdCBpbiBzb21lIGNhdGVnb3JpZXMuIFRoZXJlZm9yZSwgaW4gdGhlIGFsbC1pbiBwdWJsaWNhdGlvbiBiaWFzIHRlc3QsIG91ciBhcHByb2FjaCB0byBlc3RpbWF0ZSB0aGUgYWRqdXN0ZWQgb3ZlcmFsbCBlZmZlY3QgaXMgdG8gZml0IGEgc2ltaWxhciBtdWx0aS1tb2RlcmF0b3IgcmVncmVzc2lvbiB0byB0aGUgb25lIGFib3ZlIGJ1dCBpbmNsdWRpbmcgdGhlIGVmZmVjdCBzaXplcycgc2FtcGxpbmcgdmFyaWFuY2VzIChTViBvciB2aSkgaW5zdGVhZCBvZiB0aGVpciBzdGFuZGFyZCBlcnJvcnMgYXMgYSBtb2RlcmF0b3IuIFRoaXMgaXMgYmVjYXVzZSB3aGVuIHRoZXJlIGlzIGFuICh0cnVlKSBvdmVyYWxsIGVmZmVjdCwgdGhlIHVzZSBvZiAnU1YnIGxlYWRzIHRvIGFuIGFkanVzdGVkIG92ZXJhbGwgZWZmZWN0IHRoYXQgaXMgbGVzcyBkb3dud2FyZCBiaWFzZWQgdGhhbiB3aGVuIHVzaW5nICdTRScgKG1vcmUgaW4gdGhlIG1haW4gdGV4dDsgU3RhbmxleSBhbmQgRG91Y291bGlhZ29zIDIwMTIsIDIwMTQpLiBOb3RlIHRoYXQgd2hlbiB0aGVyZSBpcyB3ZWFrIGV2aWRlbmNlIGZvciBhbiBvdmVyYWxsIGVmZmVjdHMsIGZpdHRpbmcgJ1NFJyBnaXZlcyB0aGUgYmVzdCBlc3RpbWF0ZSBvZiBhZGp1c3RlZCBlZmZlY3RzLg0KDQpXaGF0IG1vZGVyYXRvcnMgb25lIHNob3VsZCBpbmNsdWRlIGluIHRoaXMgdmVyc2lvbiBvZiB0aGUgYWxsLWluIHB1YmxpY2F0aW9uIGJpYXMgdGVzdCBkZXBlbmRzIG9uIHdoYXQgd2Ugd2FudCB0aGUgYWRqdXN0ZWQgb3ZlcmFsbCBlZmZlY3Qgc2l6ZSB0byByZWZsZWN0LiBLZWVwIGluIG1pbmQgdGhhdCBvbmUgb2YgdGhlIHB1cnBvc2VzIG9mIGluY2x1ZGluZyBtb2RlcmF0b3JzIGluIHRoaXMgYWxsLWluIHRlc3QgaXMgdG8gZXhwbGFpbiBhcyBtdWNoIGhldGVyb2dlbmVpdHkgYXMgcG9zc2libGUuIFdlIGFyZSBnb2luZyB0byBhZGQgb25lIG1vcmUgbW9kZXJhdG9yICdjYXB0aXZpdHkgc3RhdHVzJyAoYENhcHRpdml0eUNgKSwgd2hpY2ggaGFzIDUgbGV2ZWxzICh3ZSByZWZlciB0byBpdCBhcyB0aGUgZnVsbCBtb2RlbCkuIFdlIHdpbGwgb2J0YWluIG1hcmdpbmFsaXplZCBtZWFucywgdXNpbmcgdGhlIFIgcGFja2FnZSBgZW1tZWFuc2AuIEltcG9ydGFudGx5LCB3ZSBzaG91bGQga2VlcCBpbiBtaW5kIHRoYXQgcHVibGljYXRpb24gYmlhcyB0ZXN0cyBzaG91bGQgYmUgdHJlYXRlZCBhcyBzZW5zaXRpdml0eSBhbmFseXNlcyB0byB0ZXN0IHRoZSByb2J1c3RuZXNzIG9mIHJlc3VsdHMgZnJvbSB0aGUgb3JpZ2luYWwgYW5hbHlzaXMgKE5vYmxlIGV0IGFsLiwgMjAxNykuIEltcG9ydGFudGx5LCBub25lIG9mIHRoZSBlc3RpbWF0ZWQgYWRqdXN0ZWQgb3ZlcmFsbCBlZmZlY3RzIHNob3VsZCBiZSB0cmVhdGVkIGFzIHRoZSByZWFsIG92ZXJhbGwgdmFsdWUgaWYgcHVibGljYXRpb24gYmlhcyBkaWQgbm90IGV4aXN0OyBhZnRlciBhbGwsIHdlIGNhbiBuZXZlciBiZSBzdXJlIG9mIHdoYXQgaGFzIG5vdCBiZWVuIHB1Ymxpc2hlZC4NCg0KYGBge3J9DQojIGZ1bGwgbW9kZWwNCnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuci52LjEgPC0gcm1hLm12KHlpLCB2aSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZHM9fiAxICsgdmkgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhci5jICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ2FwdGl2aXR5QywgIyB0YWtlIENsYXNzIC0gdGhhdCBpcyBhbHJlYWR5IGEgcGFydCBvZiBwaHlsbyAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFuZG9tPWxpc3QofiAxIHwgU3BlY2llcy51cGRhdGVkLCAjIHBoeWxvIGVmZmVjdA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfiAxIHwgU3BlY2llcywgIyBub24tcGh5bG8gZWZmZWN0DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB+IDEgfCBzdHVkeSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB+IDEgfCBvYnNJRCksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUiA9IGxpc3QoU3BlY2llcy51cGRhdGVkID0gcGh5bG9fY29yKSwgI3BoeWxvZ2VuZXRpYyByZWxhdGVkbmVzcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kPSJSRU1MIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlc3Q9InQiLCAjIHVzaW5nIHQgZGlzdCByYXRoZXIgdGhhbiB6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhPWRhdGFzZXQucikNCg0KIyBwcmVwYXJhdGlvbiB0byBnZXQgbWFyZ2luYWxpemVkIG1lYW4gKHdoZW4gdmkgPSAwIGFuZCB5ZWFyLmMgPSAwKQ0KcmVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuci52LjEgPC0gcWRyZyhvYmplY3QgPSBwdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnIudi4xLCBkYXRhID0gZGF0YXNldC5yLCBhdCA9IGxpc3QodmkgPSAwLCB5ZWFyLmMgPSAwKSkNCiMgbWFyZ2luYWxpemVkIG92ZXJhbGwgbWVhbiBhdCB2aSA9IDAgYW5kIHllYXIuYyA9IDA7IGFsc28gd2VpZ2h0cyA9ICJwcm9wIiBvciAiY2VsbHMiIGF2ZXJhZ2UgdGhpbmdzIG92ZXIgcHJvcG9ydGlvbmFsbHkuIGlmIG5vdCBzcGVjaWZpZWQsIGFsbCBncm91cHMgKGxldmVscykgZ2V0IHRoZSBzYW1lIHdlaWdodHMNCm92ZXJhbGwucmVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuci52LjEgPC0gZW1tZWFucyhyZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5yLnYuMSwgc3BlY3MgPSB+MSwgZGYgPSBwdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnIudi4xJGRkZiwgd2VpZ2h0cyA9ICJwcm9wIikgIyB1c2luZyBlZmZlY3Qgc2l6ZSAtIDcgDQojIG1hcmdpbmFsaXNlZCBtZWFucyBmb3IgZGlmZmVyZW50IGxldmVscyBmb3IgQ2FwdGl2aXR5Qw0KbW0ucHVibGljYXRpb24uYmlhcy5tb2RlbC5yLnYuMSA8LSBlbW1lYW5zKHJlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnIudi4xLCBzcGVjcyA9ICJDYXB0aXZpdHlDIiwgZGYgPSBwdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnIudi4xJGRkZikNCg0KIyBjb21wYXJpbmcgcmVzdWx0cyB3aXRob3V0IGNvcnJlY3RpbmcgZm9yIHB1YmxpY2F0aW9uIGJpYXMNCnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuci52LjFiIDwtIHJtYS5tdih5aSwgdmksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kcz1+IC0xICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENhcHRpdml0eUMsICMgdGFrZSBDbGFzcyAtIHRoYXQgaXMgYWxyZWFkeSBhIHBhcnQgb2YgcGh5bG8gICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb209bGlzdCh+IDEgfCBTcGVjaWVzLnVwZGF0ZWQsICMgcGh5bG8gZWZmZWN0DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfiAxIHwgU3BlY2llcywgIyBub24tcGh5bG8gZWZmZWN0DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfiAxIHwgc3R1ZHksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH4gMSB8IG9ic0lEKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUiA9IGxpc3QoU3BlY2llcy51cGRhdGVkID0gcGh5bG9fY29yKSwgI3BoeWxvZ2VuZXRpYyByZWxhdGVkbmVzcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZD0iUkVNTCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdD0idCIsICMgdXNpbmcgdCBkaXN0IHJhdGhlciB0aGFuIHoNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhPWRhdGFzZXQucikNCg0KIyBleHRyYWN0aW5nIHRoZSBtZWFuIGFuZCA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbHMNCmVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnIudi4xIDwtIGVzdGltYXRlcy5DSTIobW0ucHVibGljYXRpb24uYmlhcy5tb2RlbC5yLnYuMSkNCmVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnIudi4xYiA8LSBlc3RpbWF0ZXMuQ0kocHVibGljYXRpb24uYmlhcy5tb2RlbC5yLnYuMWIpDQpgYGANCg0KVGhlIGZ1bGwgbW9kZWwgcHJvdmlkZWQgYW4gYWRqdXN0ZWQgb3ZlcmFsbCBlZmZlY3Qgc2l6ZSB0aGF0IHdhcyBzbGlnaHRseSBzbWFsbGVyIChhZGp1c3RlZCBlZmZlY3QgPSBgciByb3VuZChzdW1tYXJ5KG92ZXJhbGwucmVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuci52LjEpWywyXSwyKWAsIDk1JSBDSSA9IFtgciByb3VuZChzdW1tYXJ5KG92ZXJhbGwucmVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuci52LjEpWywzXSwyKWAsYHIgcm91bmQoc3VtbWFyeShvdmVyYWxsLnJlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnIudi4xKVssNF0sMilgXSkgdGhhbiB0aGF0IG9idGFpbmVkIGJ5IHRoZSBtdWx0aWxldmVsIG1ldGEtYW5hbHlzaXMgKHVuYWRqdXN0ZWQgZWZmZWN0ID0gYHIgcm91bmQobWV0YWFuYWx5dGljLm1lYW4ubW9kZWwucltbMV1dLDIpYCwgOTUlIENJID0gW2ByIHJvdW5kKG1ldGFhbmFseXRpYy5tZWFuLm1vZGVsLnJbWzNdXSwyKWAsYHIgcm91bmQobWV0YWFuYWx5dGljLm1lYW4ubW9kZWwucltbNF1dLDIpYF07IG1vcmUgaW4gc2VjdGlvbiBTNC4xLjMpLCBoaWdobGlnaHRpbmcgdGhlIGRvd253YXJkIGNvcnJlY3Rpb24gb2YgdGhlIG92ZXJhbGwgZWZmZWN0IGFmdGVyIGFjY291bnRpbmcgZm9yIHB1YmxpY2F0aW9uIGJpYXMuIFRoZSBmdWxsIG1vZGVsIGFsc28gc2hvd2VkIHNsaWdodGx5IHNtYWxsZXIgZWZmZWN0cyBmb3IgYWxsIGxldmVscyBvZiB0aGUgY2F0ZWdvcmljYWwgZmFjdG9yICdjYXB0aXZpdHkgc3RhdHVzJyB0aGFuIHRoZSB1bmFkanVzdGVkIG1vZGVsIChUYWJsZSBTNC4yKS4NCg0KYGBge3J9DQojIGNyZWF0aW5nIGEgdGFibGUgdG8gc2hvdyB0aGUgcmVzdWx0cyBvZiBtb2RlbCAyDQp0YWJsZS5jb21wYXJpbmcuY2FwdGl2aXR5LmxldmVscyA8LSBtZXJnZShlc3RpbWF0ZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5yLnYuMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnIudi4xYiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5PSJlc3RpbWF0ZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbGwueD1UKQ0KDQojIHJvdW5kaW5nIGVzdGltYXRlcw0KdGFibGUuY29tcGFyaW5nLmNhcHRpdml0eS5sZXZlbHMgPC0gdGFibGUuY29tcGFyaW5nLmNhcHRpdml0eS5sZXZlbHMgJT4lIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIHJvdW5kLCAyKSkNCg0KDQp0YWJsZS5jb21wYXJpbmcuY2FwdGl2aXR5LmxldmVscyA8LSBkYXRhLmZyYW1lKGNhcHRpdml0eS5sZXZlbCA9IHRhYmxlLmNvbXBhcmluZy5jYXB0aXZpdHkubGV2ZWxzWywxXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRqdXN0ZWQubWVhbj10YWJsZS5jb21wYXJpbmcuY2FwdGl2aXR5LmxldmVsc1ssMl0sICAgICAgICAgICAgICAgYWRqdXN0ZWQuQ0k9cGFzdGUwKCJbIix0YWJsZS5jb21wYXJpbmcuY2FwdGl2aXR5LmxldmVsc1ssM10sIiwiLHRhYmxlLmNvbXBhcmluZy5jYXB0aXZpdHkubGV2ZWxzWyw0XSwiXSIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmFkanVzdGVkLm1lYW49dGFibGUuY29tcGFyaW5nLmNhcHRpdml0eS5sZXZlbHNbLDVdLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5hZGp1c3RlZC5DST1wYXN0ZTAoIlsiLHRhYmxlLmNvbXBhcmluZy5jYXB0aXZpdHkubGV2ZWxzWyw2XSwiLCIsdGFibGUuY29tcGFyaW5nLmNhcHRpdml0eS5sZXZlbHNbLDddLCJdIikpDQoNCnRhYmxlLmNvbXBhcmluZy5jYXB0aXZpdHkubGV2ZWxzWywxXSA8LSBjKCJGQyIsIkZXIiwiV0NUIiwiV0NUICYgRkMiLCAiV0NUICYgRlciKQ0KDQojIGNyZWF0aW5nIGEgZm9ybWF0dGVkIHRhYmxlIHVzaW5nIHRoZSBSIHBhY2thZ2UgJ2d0Jw0KdGFibGUubW9kZWwuci5jYXB0aXZpdHkuZ3QgPC0gdGFibGUuY29tcGFyaW5nLmNhcHRpdml0eS5sZXZlbHMgJT4lIA0KICBndCgpICU+JSANCiAgY29sc19sYWJlbChjYXB0aXZpdHkubGV2ZWw9bWQoIioqQ2FwdGl2aXR5IHN0YXR1cyoqIiksDQogICAgICAgICAgICAgYWRqdXN0ZWQubWVhbj1tZCgiKipBZGp1c3RlZCBtZWFuKioiKSwNCiAgICAgICAgICAgICBhZGp1c3RlZC5DST1tZCgiKipBZGp1c3RlZCA5NSUgQ0kqKiIpLA0KICAgICAgICAgICAgIHVuYWRqdXN0ZWQubWVhbj1tZCgiKipVbmFkanVzdGVkIG1lYW4qKiIpLA0KICAgICAgICAgICAgIHVuYWRqdXN0ZWQuQ0k9bWQoIioqVW5hZGp1c3RlZCA5NSUgQ0kqKiIpKSAlPiUNCiAgY29sc19hbGlnbihhbGlnbiA9ICJjZW50ZXIiKQ0KDQp0YWJsZS5tb2RlbC5yLmNhcHRpdml0eS5ndA0KYGBgDQoNCioqVGFibGUgUzQuMi4qKiBSZXN1bHRzIGZvciBhbGwgbGV2ZWxzIG9mIHRoZSBtb2RlcmF0b3IgJ2NhcHRpdml0eSBzdGF0dXMnLCBib3RoIGFkanVzdGVkIGFuZCB1bmFkanVzdGVkIGZvciBwdWJsaWNhdGlvbiBiaWFzIHVzaW5nIHRoZSBhbGwtaW4gcHVibGljYXRpb24gYmlhcyB0ZXN0IChtdWx0aS1tb2RlcmF0b3IgbWV0YS1yZWdyZXNzaW9uKS4gRXN0aW1hdGVzIGFyZSBwcmVzZW50ZWQgYXMgc3RhbmRhcmRpemVkIGVmZmVjdCBzaXplcyB1c2luZyBGaXNoZXIncyB0cmFuc2Zvcm1hdGlvbiBvZiB0aGUgY29ycmVsYXRpb24gY29lZmZpY2llbnQgKGkuZS4gKlpyKikuDQoNCjxici8+PGJyLz4NCg0KIyMjIFM0LjI6IE1lYW4gZGlmZmVyZW5jZXMgYmV0d2VlbiB0d28gZ3JvdXBzIChsblJSIGFuZCBTTUQpDQoNCkZvciBvdXIgc2Vjb25kIHdvcmtlZCBleGFtcGxlLCB3ZSB1c2UgdGhlIG1ldGEtYW5hbHl0aWMgZGF0YXNldCBwcm92aWRlZCBieSBNdXJwaHkgZXQgYWwuIDIwMTMuIFRoaXMgbWV0YS1hbmFseXNpcyB0ZXN0ZWQgd2hldGhlciBodW1hbi1jYXVzZWQgZGlzdHVyYmFuY2VzIGxlZCBhIGNoYW5nZSBpbiBzcGVjaWVzIHJpY2huZXNzIGFjcm9zcyBib3RoIHRlcnJlc3RyaWFsIGFuZCBhcXVhdGljIGJpb21lcywgdXNpbmcgdGhlIGxvZyByZXNwb25zZSByYXRpbyAoaS5lLiwgbG5SUikuIEJyaWVmbHksIHRoZSBhdXRob3JzIGZvdW5kIHRoYXQgaHVtYW4tbWVkaWF0ZWQgZGlzdHVyYmFuY2VzIGxlZCB0byBhIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgMTguMyUgZGVjbGluZSBpbiBzcGVjaWVzIHJpY2huZXNzIGFjcm9zcyBmaXZlIGFudGhyb3BvZ2VuaWMgZGlzdHVyYmFuY2VzIChzcGVjaWVzIGludmFzaW9ucywgbnV0cmllbnQgYWRkaXRpb24sIHRlbXBlcmF0dXJlIGluY3JlYXNlLCBoYWJpdGF0IGxvc3Mgb3IgZnJhZ21lbnRhdGlvbiwgYW5kIGxhbmQtdXNlIGNoYW5nZSkuIEhlcmUsIHdlIHVzZSB0aGlzIGRhdGFzZXQgdG8gc2hvdyBob3cgdG8gdXNlIG11bHRpbGV2ZWwgbWV0YS1yZWdyZXNzaW9uIGFwcHJvYWNoIHRvIGJvdGggZGV0ZWN0IGFuZCBhZGp1c3QgZm9yIHB1YmxpY2F0aW9uIGJpYXMuDQoNCmBgYHtyLCByZXN1bHRzPSJoaWRlIn0NCiMgaW1wb3J0aW5nIGRhdGFzZXQgd2l0aCBtZWFuIGRpZmZlcmVuY2VzDQpkYXRhc2V0Lm9yaWdpbmFsLm1lYW4uZGlmZjwtcmVhZF9leGNlbChoZXJlKCJkYXRhIiwgImZ0MDI3Lnhsc3giKSwgY29sX25hbWVzID0gVFJVRSkNCg0KI25hbWVzKGRhdGFzZXQub3JpZ2luYWwubWVhbi5kaWZmKQ0KI3N0cihkYXRhc2V0Lm9yaWdpbmFsLm1lYW4uZGlmZikNCg0KDQojIGxuUlINCmRhdGFzZXQucnIgIDwtIGVzY2FsYyhtZWFzdXJlID0gIlJPTSIsDQogICAgICAgICAgICAgICAgICAgICAgbTFpID0gVF9tZWFuLA0KICAgICAgICAgICAgICAgICAgICAgIG0yaSA9IENfbWVhbiwNCiAgICAgICAgICAgICAgICAgICAgICBzZDFpID0gVF9zZCwNCiAgICAgICAgICAgICAgICAgICAgICBzZDJpID0gQ19zZCwNCiAgICAgICAgICAgICAgICAgICAgICBuMWkgPSBUX04sDQogICAgICAgICAgICAgICAgICAgICAgbjJpID0gQ19OLA0KICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBkYXRhc2V0Lm9yaWdpbmFsLm1lYW4uZGlmZiwNCiAgICAgICAgICAgICAgICAgICAgICBhcHBlbmQgPSBUKQ0KDQpkYXRhc2V0LnNtZCA8LSBlc2NhbGMobWVhc3VyZSA9ICJTTUQiLA0KICAgICAgICAgICAgICAgICAgICAgIG0xaSA9IFRfbWVhbiwNCiAgICAgICAgICAgICAgICAgICAgICBtMmkgPSBDX21lYW4sDQogICAgICAgICAgICAgICAgICAgICAgc2QxaSA9IFRfc2QsDQogICAgICAgICAgICAgICAgICAgICAgc2QyaSA9IENfc2QsDQogICAgICAgICAgICAgICAgICAgICAgbjFpID0gVF9OLA0KICAgICAgICAgICAgICAgICAgICAgIG4yaSA9IENfTiwNCiAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gZGF0YXNldC5vcmlnaW5hbC5tZWFuLmRpZmYsDQogICAgICAgICAgICAgICAgICAgICAgYXBwZW5kID0gVCkNCg0KI1dhcm5pbmcgbWVzc2FnZToNCiNTb21lICd5aScgYW5kL29yICd2aScgdmFsdWVzIGVxdWFsIHRvICstSW5mLiBSZWNvZGVkIHRvIE5Bcy4gDQoNCiMgY2xlYW4gTkENCmRhdGFzZXQucnIgPC0gZGF0YXNldC5yclshaXMubmEoZGF0YXNldC5yciR5aSkgJiBkYXRhc2V0LnJyJHZpICE9IDAsIF0NCg0KZGF0YXNldC5zbWQgPC0gZGF0YXNldC5zbWRbIWlzLm5hKGRhdGFzZXQuc21kJHlpKSAmIGRhdGFzZXQuc21kJHZpICE9IDAsIF0NCmBgYA0KDQojIyMjIFM0LjIuMTogRXhwbG9yYXRvcnkgZGF0YSBhbmFseXNpcw0KDQpCZWZvcmUgYW5hbHlzaXMsIGl0IGlzIGltcG9ydGFudCB0byBleHBsb3JlIHRoZSBtZXRhLWFuYWx5dGljIGRhdGFzZXQuIFRvIGlkZW50aWZ5IG91dGxpZXJzICh3aGljaCBhcmUgc29tZXRpbWVzIGNhdXNlZCBieSBkYXRhIGV4dHJhY3Rpb24gZXJyb3JzLCBvciB0eXBvcyBpbiB0aGUgZGF0YSBzb3VyY2UpLCBGaWd1cmUgUzQuNiBzaG93cyBmdW5uZWwgcGxvdHMgd2l0aCB0aGUgc3RhbmRhcmQgZXJyb3IgYW5kIHRoZSBpbnZlcnNlIG9mIHRoZSBzdGFuZGFyZCBlcnJvciAoaS5lLiBwcmVjaXNpb24pIGluIHRoZSB5LWF4ZXMgKEZpZ3VyZSBTNC42KS4NCg0KIyMjIyMgRmlndXJlIFM0LjYNCg0KYGBge3IsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PSA4LCBmaWcuY2FwPSJGdW5uZWwgcGxvdHMgd2l0aCAxL1NFIGZvciBsblJSIChsZWZ0LWhhbmQgc2lkZSkgYW5kIFNNRCAocmlnaHQtaGFuZCBzaWRlKSBhcyBtZWFzdXJlcyBvZiB1bmNlcnRhaW50eSB0byB2aXN1YWxpc2Ugb3V0bGllcnMgaW4gdGhlIG1ldGEtYW5hbHl0aWMgZGF0YXNldC4ifQ0KIyB3ZSBmaW5kIHNvbWUgc3RyYW5nZSBkYXRhIGluIFNNRCBhbmQgbG5SUiANCnBhcihtZnJvdyA9IGMoMSwgMikpDQpmdW5uZWwoZGF0YXNldC5yciR5aSwgZGF0YXNldC5yciR2aSwgeWF4aXM9InNlaW52IiwNCiAgICAgICAjeGxpbSA9IGMoLTMsIDMpLA0KICAgICAgIHlsYWIgPSAiUHJlY2lzaW9uICgxL1NFKSIsDQogICAgICAgeGxhYiA9ICJFZmZlY3Qgc2l6ZSAobG5SUikiKSANCmZ1bm5lbChkYXRhc2V0LnNtZCR5aSwgZGF0YXNldC5zbWQkdmksIHlheGlzPSJzZWludiIsDQogICAgICAgI3hsaW0gPSBjKC0zLCAzKSwNCiAgICAgICB5bGFiID0gIlByZWNpc2lvbiAoMS9TRSkiLA0KICAgICAgIHhsYWIgPSAiRWZmZWN0IHNpemUgKFNNRCkiKSANCmBgYA0KDQpEYXRhIGV4cGxvcmF0aW9uIGZvdW5kIHVzdWFsIG91dGxpZXJzIGluIGJvdGggdGhlIGxuUlIgYW5kIFNNRCBkYXRhLiBGb3IgdGhpcyBleGFtcGxlIHdlIGhhdmUgcmVtb3ZlZCB0aGVzZSBvdXRsaWVycy4gSG93ZXZlciwgZm9yIGEgcmVhbCBtZXRhLWFuYWx5c2lzLCB0aGUgc291cmNlIG9mIHRob3NlIG91dGxpZXJzIHNob3VsZCBiZSBpbnZlc3RpZ2F0ZWQsIGFuZCB0aGUgZGVjaXNpb24gYWJvdXQgd2hldGhlciBvciBub3QgdG8gcmVtb3ZlIHVudXN1YWwgZWZmZWN0IHNpemVzIHNob3VsZCBiZSBqdXN0aWZpZWQgYW5kIHJlcG9ydGVkIGluIHRoZSBwYXBlci4gTmV4dCwgd2UgY2hlY2tlZCB0aGUgZnVubmVsIHBsb3RzIGFnYWluIChGaWd1cmUgUzQuNykuIFRoaXMgdGltZSwgdGhlIGZ1bm5lbCBwbG90cyBzZWVtZWQgdG8gYmUgbW9yZSBub3JtYWwuDQoNCiMjIyMjIEZpZ3VyZSBTNC43DQoNCkZ1bm5lbCBwbG90cyB3aXRoIDEvU0UgYXMgdGhlIG1lYXN1cmUgb2YgdW5jZXJ0YWludHkgZm9yIGxuUlIgKGxlZnQtaGFuZCBzaWRlKSBhbmQgU01EIChyaWdodC1oYW5kIHNpZGUpIGFmdGVyIHJlbW92aW5nIG91dGxpZXJzIGluIHRoZSBtZXRhLWFuYWx5dGljIGRhdGFzZXQuDQoNCmBgYHtyLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD0gOCwgZmlnLmNhcD0iRnVubmVsIHBsb3RzIHdpdGggZWZmZWN0aXZlIHNhbXBsZSBzaXplIGFzIHRoZSBtZWFzdXJlIG9mIHVuY2VydGFpbnR5IGZvciBsblJSIChsZWZ0LWhhbmQgc2lkZSkgYW5kIFNNRCAocmlnaHQtaGFuZCBzaWRlKS4ifQ0KIyByZW1vdmluZyBvdXRsaWVycw0KZGF0YXNldC5yciA8LSBkYXRhc2V0LnJyW2RhdGFzZXQucnIkdmkgIT0gbWluKGRhdGFzZXQucnIkdmkpLCBdDQoNCmRhdGFzZXQuc21kIDwtIGRhdGFzZXQuc21kW2RhdGFzZXQuc21kJHlpICE9IG1pbihkYXRhc2V0LnNtZCR5aSksXQ0KDQoNCnBhcihtZnJvdyA9IGMoMSwgMikpDQpmdW5uZWwoZGF0YXNldC5yciR5aSwgZGF0YXNldC5yciR2aSwgeWF4aXM9InNlaW52IiwNCiAgICAgICAjeGxpbSA9IGMoLTMsIDMpLA0KICAgICAgIHlsYWIgPSAiUHJlY2lzaW9uICgxL1NFKSIsDQogICAgICAgeGxhYiA9ICJFZmZlY3Qgc2l6ZSAobG5SUikiKSANCmZ1bm5lbChkYXRhc2V0LnNtZCR5aSwgZGF0YXNldC5zbWQkdmksIHlheGlzPSJzZWludiIsDQogICAgICAgI3hsaW0gPSBjKC0zLCAzKSwNCiAgICAgICB5bGFiID0gIlByZWNpc2lvbiAoMS9TRSkiLA0KICAgICAgIHhsYWIgPSAiRWZmZWN0IHNpemUgKFNNRCkiKSANCmBgYA0KDQpUbyBhdm9pZCAnYXJ0ZWZhY3R1YWwnIGZ1bm5lbCBhc3ltbWV0cnksIHdlIHN1Z2dlc3QgdXNpbmcgdGhlICJlZmZlY3RpdmUgc2FtcGxlIHNpemUiIHJhdGhlciB0aGFuIFNFIGZvciBtZWFuIGRpZmZlcmVuY2UgZWZmZWN0IHNpemVzLCBzdWNoIGFzIGxuUlIgYW5kIFNNRC4gTGV0J3MgY2hlY2sgdGhlIGZ1bm5lbCBwbG90cyAoRmlndXJlIFM0LjgpIHdoaWNoIHVzZSBlZmZlY3RpdmUgc2FtcGxlIHNpemUgb24gdGhlIHktYXhpcy4NCg0KIyMjIyMgRmlndXJlIFM0LjgNCg0KYGBge3IsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PSA4fQ0KIyBjYWxjdWxhdGluZyAiZWZmZWN0aXZlIHNhbXBsZSBzaXplIiB0byBhY2NvdW50IGZvciB1bmJhbGFuY2VkIHNhbXBsaW5nLCBmb3IgU01EIGFuZCBsblJSIChlX24sIGhlcmVhZnRlciwgc2VlIEVxdWF0aW9uIDI1IGZyb20gdGhlIG1haW4gbWFudXNjcmlwdCkNCg0KZGF0YXNldC5yciRlX24gPC0gd2l0aChkYXRhc2V0LnJyLCAoNCooQ19OKlRfTikpIC8gKENfTiArIFRfTikpDQpkYXRhc2V0LnNtZCRlX24gPC0gd2l0aChkYXRhc2V0LnNtZCwgKDQqKENfTipUX04pKSAvIChDX04gKyBUX04pKQ0KDQojdXNpbmcgZWZmZWN0aXZlIHNhbXBsaW5nIHNpemUNCnBhcihtZnJvdyA9IGMoMSwgMikpDQpmdW5uZWwoZGF0YXNldC5yciR5aSwgZGF0YXNldC5yciR2aSwgbmkgPSBkYXRhc2V0LnJyJGVfbiwgeWF4aXM9Im5pIiwNCiAgICAgICAjeGxpbSA9IGMoLTMsIDMpLA0KICAgICAgIHlsYWIgPSAiRWZmZWN0aXZlIHNhbXBsZSBzaXplIiwNCiAgICAgICB4bGFiID0gIkVmZmVjdCBzaXplIChsblJSKSIpIA0KZnVubmVsKGRhdGFzZXQuc21kJHlpLCBkYXRhc2V0LnNtZCR2aSwgbmkgPSBkYXRhc2V0LnNtZCRlX24sIHlheGlzPSJuaSIsDQogICAgICAgI3hsaW0gPSBjKC0zLCAzKSwNCiAgICAgICB5bGFiID0gIkVmZmVjdGl2ZSBzYW1wbGUgc2l6ZSIsDQogICAgICAgeGxhYiA9ICJFZmZlY3Qgc2l6ZSAoU01EKSIpIA0KDQpgYGANCg0KQ29tcGFyaW5nIHRoZSBmdW5uZWwgcGxvdHMgdXNpbmcgZWZmZWN0aXZlIHNhbXBsZSBzaXplIChGaWd1cmUgNC44KSB3aXRoIDEvU0UgKEZpZ3VyZSA0LjcpIHdlIG5vdGljZSB0aGF0IGRhdGEgcG9pbnRzIGluIGZ1bm5lbCBwbG90cyB3aXRoIGVmZmVjdGl2ZSBzYW1wbGUgc2l6ZXMgbG9va2VkIG1vcmUgJ3NjYXR0ZXJlZCcsIHdoZXJlYXMgZGF0YSBwb2ludHMgaW4gZnVubmVsIHBsb3RzIHdpdGggMS9TRSBsb29rZWQgbW9yZSAnY3Jvd2RlZCcuIFRoaXMgaXMgYmVjYXVzZSBTRSBpcyBjb3JyZWxhdGVkIG1vcmUgc3Ryb25nbHkgd2l0aCB0aGUgZWZmZWN0IHNpemUgdGhhbiBlZmZlY3RpdmUgc2FtcGxlIHNpemUsIG93aW5nIHRvIHNpbWlsYXJpdGllcyBiZXR3ZWVuIHRoZSBlZmZlY3Qgc2l6ZSBhbmQgc2FtcGxpbmcgdmFyaWFuY2UgZXF1YXRpb25zIGZvciBib3RoIGxuUlIgYW5kIFNNUiAoaS5lLiwgY29tcGFyZSBlcXVhdGlvbnMgMSBhbmQgMiwgYW5kIGVxdWF0aW9ucyAzIGFuZCA0LCBpbiB0aGUgbWFpbiB0ZXh0KS4gRm9yIGV4YW1wbGUsIHRoZSBTTUQncyB2YXJpYW5jZSBoYXMgdGhlIHNxdWFyZSBvZiB0aGUgcG9pbnQgZXN0aW1hdGUgKGkuZS4gU01EKSBpbiBpdHMgZXF1YXRpb24sIHdoaWNoIGxlYWRzIHRvIGEgY29ycmVsYXRpb24gYmV0d2VlbiBTTURzIGFuZCBzYW1wbGluZyBTRS4gVGhpcyBjYW4gcmVzdWx0IGluICdhcnRlZmFjdHVhbCcgZnVubmVsIGFzeW1tZXRyeS4NCg0KIyMjIyBTNC4yLjI6IE11bHRpbGV2ZWwgbWV0YS1hbmFseXNpcw0KDQpOZXh0LCB3ZSBzaG93Y2FzZSBob3cgdG8gdGVzdCBmb3IgdGhlIHByZXNlbmNlIG9mIHB1YmxpY2F0aW9uIGJpYXMgdXNpbmcgdGhlIG11bHRpbGV2ZWwgbWV0YS1yZWdyZXNzaW9uIG1ldGhvZCBzdWdnZXN0ZWQgaW4gdGhlIG1haW4gdGV4dC4gRmlyc3QsIHdlIHJlLWFuYWx5c2UgdGhlIGRhdGFzZXQgdXNpbmcgYSBtdWx0aWxldmVsIG1ldGEtYW5hbHl0aWMgKGludGVyY2VwdC1vbmx5KSBtb2RlbCBhbmQgbWFrZSBjb3JyZXNwb25kaW5nIGZ1bm5lbCBwbG90IHNob3dpbmcgdGhlIG92ZXJhbGwgZWZmZWN0IG9yIG1ldGEtYW5hbHl0aWMgbWVhbi4NCg0KYGBge3J9DQojIGNyZWF0aW5nIGEgdW5pdC1sZXZlbCByYW5kb20gZWZmZWN0IHRvIG1vZGVsIHJlc2lkdWFsIHZhcmlhbmNlIGluIG1ldGFmb3INCmRhdGFzZXQucnIkb2JzSUQgPC0gMTpucm93KGRhdGFzZXQucnIpDQpkYXRhc2V0LnNtZCRvYnNJRCA8LSAxOm5yb3coZGF0YXNldC5zbWQpDQoNCiMgcnVubmluZyBtdWx0aWxldmVsIGludGVyY2VwdC1vbmx5IG1ldGEtYW5hbHl0aWMgbW9kZWwNCm1ldGEuYW5hbHlzaXMubW9kZWwucnIgPC0gcm1hLm12KHlpLCB2aSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZHMgPSB+IDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb20gPSBsaXN0KH4xICB8IERpc3R1cmJhbmNlX2NhdGVnb3J5LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB+IDEgfCBwYXBlcklELCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfiAxIHwgb2JzSUQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gIlJFTUwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdCA9ICJ0IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gZGF0YXNldC5ycikNCg0KDQptZXRhLmFuYWx5c2lzLm1vZGVsLnNtZCA8LSBybWEubXYoeWksIHZpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZHMgPSB+IDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFuZG9tID0gbGlzdCh+MSAgfCBEaXN0dXJiYW5jZV9jYXRlZ29yeSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH4gMSB8IHBhcGVySUQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfiAxIHwgb2JzSUQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJSRU1MIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXN0ID0gInQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gZGF0YXNldC5zbWQpDQoNCiMgZXh0cmFjdGluZyB0aGUgbWVhbiwgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGFuZCA5NSUgcHJlZGljdGlvbiBpbnRlcnZhbHMNCiBtZXRhYW5hbHl0aWMubWVhbi5tb2RlbC5yciA8LSBwcmVkaWN0KG1ldGEuYW5hbHlzaXMubW9kZWwucnIsIGRpZ2l0cz0zKQ0KbWV0YWFuYWx5dGljLm1lYW4ubW9kZWwuc21kIDwtIHByZWRpY3QobWV0YS5hbmFseXNpcy5tb2RlbC5zbWQsIGRpZ2l0cz0zKQ0KDQojIGVzdGltYXRpbmcgcmVsYXRpdmUgaGV0ZXJvZ2VuZWl0eSBJMg0KIEkyLm1vZGVsLnJyIDwtIGkyX21sKG1ldGEuYW5hbHlzaXMubW9kZWwucnIpDQpJMi5tb2RlbC5zbWQgPC0gaTJfbWwobWV0YS5hbmFseXNpcy5tb2RlbC5zbWQpDQoNCiMgY3JlYXRpbmcgYSB0YWJsZSB0byBzaG93IHRoZSBoZXRlcm9nZW5laXR5IGVzdGltYXRlcw0KdGFibGUubW9kZWwucnIgPC0gZGF0YS5mcmFtZShuPWxlbmd0aCh1bmlxdWUoZGF0YXNldC5yciRwYXBlcklEKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGs9bnJvdyhkYXRhc2V0LnJyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhbj1yb3VuZChtZXRhYW5hbHl0aWMubWVhbi5tb2RlbC5ycltbMV1dLDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDST1wYXN0ZTAoIlsiLHJvdW5kKG1ldGFhbmFseXRpYy5tZWFuLm1vZGVsLnJyW1szXV0sMiksIiwiLHJvdW5kKG1ldGFhbmFseXRpYy5tZWFuLm1vZGVsLnJyW1s0XV0sMiksIl0iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUEk9cGFzdGUwKCJbIixyb3VuZChtZXRhYW5hbHl0aWMubWVhbi5tb2RlbC5ycltbNV1dLDIpLCIsIixyb3VuZChtZXRhYW5hbHl0aWMubWVhbi5tb2RlbC5ycltbNl1dLDIpLCJdIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIEkyX29ic0lEPXJvdW5kKEkyLm1vZGVsLnJyW1s0XV0sMSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIEkyX3BhcGVySUQ9cm91bmQoSTIubW9kZWwucnJbWzNdXSwxKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSTJfRGlzdHVyYmFuY2U9cm91bmQoSTIubW9kZWwucnJbWzJdXSwxKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSTJfdG90YWw9cm91bmQoSTIubW9kZWwucnJbWzFdXSwxKSkNCg0Kcm93bmFtZXModGFibGUubW9kZWwucnIpIDwtIE5VTEwNCg0KI3dyaXRlLmNzdih0YWJsZS5tb2RlbC5SUiwgIi4vdGFibGUvdGFibGUubW9kZWwuUlIuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpDQoNCnRhYmxlLm1vZGVsLnNtZCA8LSBkYXRhLmZyYW1lKG49bGVuZ3RoKHVuaXF1ZShkYXRhc2V0LnNtZCRwYXBlcklEKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGs9bnJvdyhkYXRhc2V0LnNtZCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lYW49cm91bmQobWV0YWFuYWx5dGljLm1lYW4ubW9kZWwuc21kW1sxXV0sMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIENJPXBhc3RlMCgiWyIscm91bmQobWV0YWFuYWx5dGljLm1lYW4ubW9kZWwuc21kW1szXV0sMiksIiwiLHJvdW5kKG1ldGFhbmFseXRpYy5tZWFuLm1vZGVsLnNtZFtbNF1dLDIpLCJdIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBJPXBhc3RlMCgiWyIscm91bmQobWV0YWFuYWx5dGljLm1lYW4ubW9kZWwuc21kW1s1XV0sMiksIiwiLHJvdW5kKG1ldGFhbmFseXRpYy5tZWFuLm1vZGVsLnNtZFtbNl1dLDIpLCJdIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIEkyX29ic0lEPXJvdW5kKEkyLm1vZGVsLnNtZFtbNF1dLDEpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJMl9wYXBlcklEPXJvdW5kKEkyLm1vZGVsLnNtZFtbM11dLDEpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJMl9EaXN0dXJiYW5jZT1yb3VuZChJMi5tb2RlbC5zbWRbWzJdXSwxKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSTJfdG90YWw9cm91bmQoSTIubW9kZWwuc21kW1sxXV0sMSkpDQoNCnJvd25hbWVzKHRhYmxlLm1vZGVsLnNtZCkgPC0gTlVMTA0KDQoNCiN3cml0ZS5jc3YodGFibGUubW9kZWwuU01ELCAiLi90YWJsZS90YWJsZS5tb2RlbC5TTUQuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpDQoNCiMgY3JlYXRpbmcgYSBmb3JtYXR0ZWQgdGFibGUgdXNpbmcgdGhlIFIgcGFja2FnZSAnZ3QnDQp0YWJsZS5tb2RlbC5yci5ndCA8LSB0YWJsZS5tb2RlbC5yciAlPiUgDQogIGd0OjpndCgpICU+JSANCiAgY29sc19sYWJlbChuPW1kKCIqKm4qKiIpLA0KICAgICAgICAgICAgIGs9bWQoIioqayoqIiksDQogICAgICAgICAgICAgbWVhbj1tZCgiKipNZXRhLWFuYWx5dGljIG1lYW4qKiIpLA0KICAgICAgICAgICAgIENJPW1kKCIqKjk1JSBDSSoqIiksDQogICAgICAgICAgICAgUEk9bWQoIioqOTUlIFBJKioiKSwNCiAgICAgICAgICAgICBJMl9vYnNJRD1tZCgiKioqSSo8c3VwPjI8L3N1cD48c3ViPnJlc2lkdWFsPC9zdWI+ICglKSoqIiksDQogICAgICAgICAgICAgSTJfcGFwZXJJRD1tZCgiKioqSSo8c3VwPjI8L3N1cD48c3ViPnN0dWR5PC9zdWI+ICglKSoqIiksDQogICAgICAgICAgICAgSTJfRGlzdHVyYmFuY2U9bWQoIioqKkkqPHN1cD4yPC9zdXA+PHN1Yj5EaXN0dXJiYW5jZTwvc3ViPiAoJSkqKiIpLA0KICAgICAgICAgICAgIEkyX3RvdGFsPW1kKCIqKipJKjxzdXA+Mjwvc3VwPjxzdWI+dG90YWw8L3N1Yj4gKCUpKioiKSkgJT4lDQogIGNvbHNfYWxpZ24oYWxpZ24gPSAiY2VudGVyIikgJT4lDQogIHRhYl9zb3VyY2Vfbm90ZShzb3VyY2Vfbm90ZSA9IG1kKCJuID0gbnVtYmVyIG9mIHN0dWRpZXM7IGsgPSBudW1iZXIgb2YgZWZmZWN0czsgQ0kgPSBjb25maWRlbmNlIGludGVydmFsOyBQSSA9IHByZWRpY3Rpb24gaW50ZXJ2YWw7ICpJKjxzdXA+Mjwvc3VwPiA9IGhldGVyb2dlbmVpdHkiKSkNCg0KdGFibGUubW9kZWwucnIuZ3QNCg0KDQp0YWJsZS5tb2RlbC5zbWQuZ3QgPC0gdGFibGUubW9kZWwuc21kICU+JSANCiAgZ3QoKSAlPiUgDQogIGNvbHNfbGFiZWwobj1tZCgiKipuKioiKSwNCiAgICAgICAgICAgICBrPW1kKCIqKmsqKiIpLA0KICAgICAgICAgICAgIG1lYW49bWQoIioqTWV0YS1hbmFseXRpYyBtZWFuKioiKSwNCiAgICAgICAgICAgICBDST1tZCgiKio5NSUgQ0kqKiIpLA0KICAgICAgICAgICAgIFBJPW1kKCIqKjk1JSBQSSoqIiksDQogICAgICAgICAgICAgSTJfb2JzSUQ9bWQoIioqKkkqPHN1cD4yPC9zdXA+PHN1Yj5yZXNpZHVhbDwvc3ViPiAoJSkqKiIpLA0KICAgICAgICAgICAgIEkyX3BhcGVySUQ9bWQoIioqKkkqPHN1cD4yPC9zdXA+PHN1Yj5zdHVkeTwvc3ViPiAoJSkqKiIpLA0KICAgICAgICAgICAgIEkyX0Rpc3R1cmJhbmNlPW1kKCIqKipJKjxzdXA+Mjwvc3VwPjxzdWI+RGlzdHVyYmFuY2U8L3N1Yj4gKCUpKioiKSwNCiAgICAgICAgICAgICBJMl90b3RhbD1tZCgiKioqSSo8c3VwPjI8L3N1cD48c3ViPnRvdGFsPC9zdWI+ICglKSoqIikpICU+JQ0KICBjb2xzX2FsaWduKGFsaWduID0gImNlbnRlciIpICU+JQ0KICB0YWJfc291cmNlX25vdGUoc291cmNlX25vdGUgPSBtZCgibiA9IG51bWJlciBvZiBzdHVkaWVzOyBrID0gbnVtYmVyIG9mIGVmZmVjdHM7IENJID0gY29uZmlkZW5jZSBpbnRlcnZhbDsgUEkgPSBwcmVkaWN0aW9uIGludGVydmFsOyAqSSo8c3VwPjI8L3N1cD4gPSBoZXRlcm9nZW5laXR5IikpICANCg0KdGFibGUubW9kZWwuc21kLmd0DQpgYGANCg0KKipUYWJsZSBTNC4yKiogUmVzdWx0cyBvZiB0aGUgbXVsdGlsZXZlbCBpbnRlcmNlcHQtb25seSBtZXRhLWFuYWx5c2lzIHRlc3RpbmcgdGhlIGVmZmVjdHMgb2YgaHVtYW4tY2F1c2VkIGRpc3R1cmJhbmNlcyBvbiBjaGFuZ2VzIGluIHNwZWNpZXMgcmljaG5lc3MgYWNyb3NzIGJvdGggdGVycmVzdHJpYWwgYW5kIGFxdWF0aWMgYmlvbWVzLiBFc3RpbWF0ZXMgYXJlIHByZXNlbnRlZCBhcyBzdGFuZGFyZGl6ZWQgZWZmZWN0IHNpemVzIHVzaW5nIHRoZSBsb2cgcmVzcG9uc2UgcmF0aW8gKGkuZS4gbG5SUiwgdG9wKSBhbmQgc3RhbmRhcmRpemVkIG1lYW4gZGlmZmVyZW5jZSAoaS5lLiBTTUQsIGJvdHRvbSkuDQoNCjxici8+PGJyLz4NCg0KIyMjIyBTNC4yLjM6IFB1YmxpY2F0aW9uIGJpYXMgdGVzdHMgd2l0aCBtdWxpdGxldmVsIG1ldGEtcmVncmVzc2lvbg0KDQojIyMjIyBTNC4yLjMuMTogTWV0YS1yZWdyZXNzaW9uIHdpdGggZWZmZWN0aXZlIHNhbXBsaW5nIHNpemUgKHVuaS1tb2RlcmF0b3IpDQoNClRvIHRlc3QgZm9yIHB1YmxpY2F0aW9uIGJpYXMgKGV2aWRlbmNlIG9mIHNtYWxsLXN0dWR5IGVmZmVjdHMpLCB3ZSBmaXJzdCBmaXR0ZWQgYSB1bmktbW9kZXJhdG9yIG11bHRpbGV2ZWwgbWV0YS1yZWdyZXNzaW9uIGluY2x1ZGluZyB0aGUgc3F1YXJlIHJvb3Qgb2YgdGhlIGludmVyc2Ugb2YgZWZmZWN0aXZlIHNhbXBsZSBzaXplICRcc3FydHtcZnJhY3sxfXtcdGlsZGV7bn19fSQgKEVxdWF0aW9uIDI2KSBhcyB0aGUgb25seSBtb2RlcmF0b3IgKHNlZSBFcXVhdGlvbiAyNyBmcm9tIHRoZSBtYWluIHRleHQpLiBUaGlzIG1ldGEtcmVncmVzc2lvbiB3aWxsIHByb3ZpZGUgc29tZSBpbmZvcm1hdGlvbiBhYm91dCB0aGUgZXhpc3RlbmNlIG9mIHNtYWxsLXN0dWR5IGVmZmVjdHMgKGkuZS4gYXN5bW1ldHJ5IGluIHRoZSBkaXN0cmlidXRpb24gb2YgZWZmZWN0IHNpemVzKSBhZnRlciBhY2NvdW50aW5nIGZvciBub24taW5kZXBlbmRlbmNlLiBIb3dldmVyLCBhcyB3ZSBleHBsYWluZWQgaW4gbWFpbiB0ZXh0LCB0aGUgYmVzdCBldmlkZW5jZSBjb21lcyBmcm9tIHRoZSBhcHByb2FjaCB3aGljaCBtb2RlbHMgYm90aCBoZXRlcm9nZW5laXR5IGFuZCBub24taW5kZXBlbmRlbmNlLCBieSB1c2luZyBhIG11bHRpLW1vZGVyYXRvciBtdWx0aWxldmVsIG1ldGEtcmVncmVzc2lvbiBtb2RlbCB0aGF0IGluY2x1ZGVzIGFsbCB0aGUgaW1wb3J0YW50IG1vZGVyYXRvcnMgKHNlZSBhbGwtaW4gcHVibGljYXRpb24gYmlhcyB0ZXN0IGRlc2NyaWJlZCBpbiBzZWN0aW9uIFM0LjIuNC4zKS4NCg0KYGBge3J9DQojIGNhbGN1bGF0aW5nIHRoZSBpbnZlcnNlIG9mIHRoZSAiZWZmZWN0aXZlIHNhbXBsZSBzaXplIiB0byBhY2NvdW50IGZvciB1bmJhbGFuY2VkIHNhbXBsaW5nLCBmb3IgU01EIGFuZCBsblJSIChzZWUgRXF1YXRpb24gMjUgZnJvbSB0aGUgbWFpbiBtYW51c2NyaXB0KQ0KDQpkYXRhc2V0LnJyJGludl9uX3RpbGRhIDwtICB3aXRoKGRhdGFzZXQucnIsIChDX04gKyBUX04pLyhDX04qVF9OKSkNCmRhdGFzZXQucnIkc3FydF9pbnZfbl90aWxkYSA8LSAgd2l0aChkYXRhc2V0LnJyLCBzcXJ0KGludl9uX3RpbGRhKSkNCg0KZGF0YXNldC5zbWQkaW52X25fdGlsZGEgPC0gd2l0aChkYXRhc2V0LnNtZCwgKENfTiArIFRfTikvKENfTipUX04pKQ0KZGF0YXNldC5zbWQkc3FydF9pbnZfbl90aWxkYSA8LSB3aXRoKGRhdGFzZXQuc21kLCBzcXJ0KGludl9uX3RpbGRhKSkNCg0KIyBBcHBsaWNhdGlvbiBvZiBFcXVhdGlvbiAyNyBmcm9tIHRoZSBtYWluIG1hbnVzY3JpcHQNCnB1YmxpY2F0aW9uLmJpYXMubW9kZWwucnIuc3JpbiA8LSBybWEubXYoeWksIHZpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RzPSB+IDEgKyBzcXJ0X2ludl9uX3RpbGRhLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb209bGlzdCh+IDEgfCBEaXN0dXJiYW5jZV9jYXRlZ29yeSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfiAxIHwgb2JzSUQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB+IDEgfCBwYXBlcklEKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kPSJSRU1MIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdCA9ICJ0IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE9ZGF0YXNldC5ycikNCg0KcHVibGljYXRpb24uYmlhcy5tb2RlbC5zbWQuc3JpbiA8LSBybWEubXYoeWksIHZpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kcz0gfiAxICsgc3FydF9pbnZfbl90aWxkYSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmRvbT1saXN0KH4gMSB8IERpc3R1cmJhbmNlX2NhdGVnb3J5LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfiAxIHwgb2JzSUQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfiAxIHwgcGFwZXJJRCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2Q9IlJFTUwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdCA9ICJ0IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhPWRhdGFzZXQuc21kKQ0KDQojIGV4dHJhY3RpbmcgdGhlIG1lYW4gYW5kIDk1JSBjb25maWRlbmNlIGludGVydmFscw0KZXN0aW1hdGVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwucnIuc3JpbiA8LSBlc3RpbWF0ZXMuQ0kocHVibGljYXRpb24uYmlhcy5tb2RlbC5yci5zcmluKQ0KDQplc3RpbWF0ZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5zbWQuc3JpbiA8LSBlc3RpbWF0ZXMuQ0kocHVibGljYXRpb24uYmlhcy5tb2RlbC5zbWQuc3JpbikNCmBgYA0KDQpFZmZlY3Qgc2l6ZXMgd2l0aCBsYXJnZXIgdW5jZXJ0YWludHkgW2xhcmdlciBzcXJ0KGludl9uXF90aWxkYSldIHRlbmQgdG8gYmUgbGFyZ2VyIChpLmUuIHNtYWxsLXN0dWR5IGVmZmVjdHMpIGFzIGluZGljYXRlZCBiZWNhdXNlIHRoZSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IHNsb3BlIG9mIHRoZSBtb2RlcmF0b3IgJ3NxcnRfaW52X25cX3RpbGRhJyBmb3IgbG5SUiAoc2xvcGUgPSBgciByb3VuZChlc3RpbWF0ZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5yci5zcmluWzIsMl0sMilgLCA5NSUgQ0kgPSBbYHIgcm91bmQoZXN0aW1hdGVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwucnIuc3JpblsyLDNdLDIpYCxgciByb3VuZChlc3RpbWF0ZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5yci5zcmluWzIsNF0sMilgXTsgKlIqPHN1cD4yPC9zdXA+PHN1Yj5tYXJnaW5hbDwvc3ViPiA9IGByIHJvdW5kKG9yY2hhUmQ6OnIyX21sKHB1YmxpY2F0aW9uLmJpYXMubW9kZWwucnIuc3JpbilbWzFdXSoxMDAsMSlgJSkgYW5kIFNNRCAoc2xvcGUgPSBgciByb3VuZChlc3RpbWF0ZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5zbWQuc3JpblsyLDJdLDIpYCwgOTUlIENJID0gW2ByIHJvdW5kKGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC5zcmluWzIsM10sMilgLGByIHJvdW5kKGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC5zcmluWzIsNF0sMilgXTsgKlIqPHN1cD4yPC9zdXA+PHN1Yj5tYXJnaW5hbDwvc3ViPiA9IGByIHJvdW5kKG9yY2hhUmQ6OnIyX21sKHB1YmxpY2F0aW9uLmJpYXMubW9kZWwuc21kLnNyaW4pW1sxXV0qMTAwLDEpYCUpLiBJbiBTNC4yLjMuMywgd2Ugd2lsbCB1c2UgYWxsLWluIHB1YmxpY2F0aW9uIGJpYXMgdGVzdCAobXVsdGktbW9kZXJhdG9yIG1ldGEtcmVncmVzc2lvbilzZWUgd2hldGhlciB0aGUgc21hbGwtc3R1ZHkgZWZmZWN0cyBleGlzdCBhZnRlciBhY2NvdW50aW5nIGZvciBzb21lIG9mIHRoZSBoZXRlcm9nZW5laXR5IHByZXNlbnQgaW4gdGhlIGRhdGEuDQoNCiMjIyMjIFM0LjIuMy4yOiBUaW1lLWxhZyBiaWFzIHRlc3QgKHVuaS1tb2RlcmF0b3IpDQoNClRvIHRlc3QgZm9yIHRpbWUtbGFnIGJpYXMgKG9yIHRoZSBkZWNsaW5lIGVmZmVjdCksIHdlIGluY2x1ZGUgdGhlIHllYXIgb2YgcHVibGljYXRpb24gKG1lYW4tY2VudHJlZCkgYXMgYSBzaW5nbGUgbW9kZXJhdGluZyB2YXJpYWJsZSAoc2VlIEVxdWF0aW9uIDIzIGZyb20gdGhlIG1haW4gdGV4dCkuDQoNCmBgYHtyfQ0KIyBtZWFuLWNlbnRyaW5nIHllYXIgb2YgcHVibGljYXRpb24gdG8gaGVscCB3aXRoIGludGVycHJldGF0aW9uLCBwYXJ0aWN1bGFybHkgaW4gUzQuMS40LjMuDQpkYXRhc2V0LnJyJHllYXIuYyA8LSBhcy52ZWN0b3Ioc2NhbGUoZGF0YXNldC5yciR5ZWFyLCBzY2FsZSA9IEYpKQ0KZGF0YXNldC5zbWQkeWVhci5jIDwtIGFzLnZlY3RvcihzY2FsZShkYXRhc2V0LnNtZCR5ZWFyLCBzY2FsZSA9IEYpKQ0KDQojIEFwcGxpY2F0aW9uIG9mIEVxdWF0aW9uIDIzIGZyb20gdGhlIG1haW4gbWFudXNjcmlwdA0KcHVibGljYXRpb24uYmlhcy5tb2RlbC5yci50aW1lbGFnIDwtIHJtYS5tdih5aSwgdmksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZHM9IH4gMSArIHllYXIuYywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFuZG9tPWxpc3QofiAxIHwgRGlzdHVyYmFuY2VfY2F0ZWdvcnksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB+IDEgfCBvYnNJRCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH4gMSB8IHBhcGVySUQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2Q9IlJFTUwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXN0ID0gInQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1kYXRhc2V0LnJyKQ0KDQpwdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC50aW1lbGFnIDwtIHJtYS5tdih5aSwgdmksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RzPSB+IDEgKyB5ZWFyLmMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb209bGlzdCh+IDEgfCBEaXN0dXJiYW5jZV9jYXRlZ29yeSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH4gMSB8IG9ic0lELCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH4gMSB8IHBhcGVySUQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kPSJSRU1MIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlc3QgPSAidCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1kYXRhc2V0LnNtZCkNCg0KIyBleHRyYWN0aW5nIHRoZSBtZWFuIGFuZCA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbHMNCmVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLnRpbWVsYWcgPC0gZXN0aW1hdGVzLkNJKHB1YmxpY2F0aW9uLmJpYXMubW9kZWwucnIudGltZWxhZykNCmVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC50aW1lbGFnIDwtIGVzdGltYXRlcy5DSShwdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC50aW1lbGFnKQ0KYGBgDQoNCkFjY29yZGluZyB0byB0aGlzIHVuaS1tb2RlcmF0b3IgbWV0YS1yZWdyZXNzaW9uLCB0aGVyZSBpcyBhbiBpbmRpY2F0aW9uIG9mIGRlY2xpbmUgZWZmZWN0cyBzaW5jZSB0aGUgc2xvcGUgb2YgdGhlIG1vZGVyYXRvciAneWVhciBvZiBwdWJsaWNhdGlvbicgaXMgY2xvc2UgdG8gc3RhdGlzdGljYWwgc2lnbmlmaWNhbmNlIGZvciBsblJSIChzbG9wZSA9IGByIHJvdW5kKGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLnRpbWVsYWdbMiwyXSwyKWAsIDk1JSBDSSA9IFtgciByb3VuZChlc3RpbWF0ZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5yci50aW1lbGFnWzIsM10sMilgLGByIHJvdW5kKGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLnRpbWVsYWdbMiw0XSwyKWBdOyAqUio8c3VwPjI8L3N1cD48c3ViPm1hcmdpbmFsPC9zdWI+ID0gYHIgcm91bmQob3JjaGFSZDo6cjJfbWwocHVibGljYXRpb24uYmlhcy5tb2RlbC5yci50aW1lbGFnKVtbMV1dKjEwMCwxKWAlKSBhbmQgU01EIChzbG9wZSA9IGByIHJvdW5kKGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC50aW1lbGFnWzIsMl0sMilgLCA5NSUgQ0kgPSBbYHIgcm91bmQoZXN0aW1hdGVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuc21kLnRpbWVsYWdbMiwzXSwyKWAsYHIgcm91bmQoZXN0aW1hdGVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuc21kLnRpbWVsYWdbMiw0XSwyKWBdOyAqUio8c3VwPjI8L3N1cD48c3ViPm1hcmdpbmFsPC9zdWI+ID0gYHIgcm91bmQob3JjaGFSZDo6cjJfbWwocHVibGljYXRpb24uYmlhcy5tb2RlbC5zbWQudGltZWxhZylbWzFdXSoxMDAsMSlgJSkuDQoNCiMjIyMjIFM0LjIuMy4zOiBBbGwtaW4gcHVibGljYXRpb24gYmlhcyB0ZXN0IChtdWx0aXBsZSBtb2RlcmF0b3JzKQ0KDQpUbyBnZXQgdGhlIGJlc3QgZXZpZGVuY2Ugb2Ygc21hbGwtc3R1ZHkgZWZmZWN0cyBhbmQgdGltZS1sYWcgYmlhcywgd2UgcnVuIGEgbXVsdGktbW9kZXJhdG9yIG1ldGEtcmVncmVzc2lvbiBpbmNsdWRpbmcgdGhlIHNxdWFyZSBvZiBpbnZlcnNlIG9mIGVmZmVjdGl2ZSBzYW1wbGUgc2l6ZSwgdGhlIHllYXIgb2YgcHVibGljYXRpb24gKG1lYW4tY2VudHJlZCkgYW5kIHRoZSBzdHVkeSBhcHByb2FjaCAoZWl0aGVyIGV4cGVyaW1lbnRhbCBvciBvYnNlcnZhdGlvbmFsOyBhIG1vZGVyYXRvciBvcmlnaW5hbGx5IGluY2x1ZGVkIGluIE11cnBoeSBldCBhbC4gMjAxMykuDQoNCmBgYHtyfQ0KIyBwcmVwYXJpbmcgdGhlIG1vZGVyYXRvcnMgdGhhdCBuZWVkIHRvIGJlIGluY2x1ZGVkIGluIGEgbWV0YS1yZWdyZXNzaW9uIHRoYXQgYWxzbyBjb250YWlucyBhICBtb2RlcmF0b3Igd2l0aCB0aGUgc3RhbmRhcmQgZXJyb3JzIG9mIHRoZSBlZmZlY3Qgc2l6ZXMgYW5kIHRoZSB5ZWFyIG9mIHB1YmxpY2F0aW9uDQoNCiMgQXBwbGljYXRpb24gb2YgRXF1YXRpb24gMjkgZnJvbSB0aGUgbWFpbiBtYW51c2NyaXB0DQpwdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLmFsbC5zcmluIDwtIHJtYS5tdih5aSwgdmksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kcz0gfiAtMSArIHNxcnRfaW52X25fdGlsZGEgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIuYyArIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRXhwZXJpbWVudGFsLm9yLk9ic2VydmF0aW9uYWwuLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmRvbT1saXN0KA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH4gMSB8IERpc3R1cmJhbmNlX2NhdGVnb3J5LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH4gMSB8IG9ic0lELCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB+IDEgfCBwYXBlcklEKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2Q9IlJFTUwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlc3QgPSAidCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE9ZGF0YXNldC5yciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cm9sPWxpc3Qob3B0aW1pemVyPSJvcHRpbSIsIG9wdG1ldGhvZD0iTmVsZGVyLU1lYWQiKSkNCg0KDQoNCnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuc21kLmFsbC5zcmluIDwtIHJtYS5tdih5aSwgdmksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kcz0gfiAtMSArIHNxcnRfaW52X25fdGlsZGEgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIuYyArIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRXhwZXJpbWVudGFsLm9yLk9ic2VydmF0aW9uYWwuLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmRvbT1saXN0KA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB+IDEgfCBEaXN0dXJiYW5jZV9jYXRlZ29yeSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfiAxIHwgb2JzSUQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB+IDEgfCBwYXBlcklEKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2Q9IlJFTUwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlc3QgPSAidCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE9ZGF0YXNldC5zbWQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJvbD1saXN0KG9wdGltaXplcj0ib3B0aW0iLCBvcHRtZXRob2Q9Ik5lbGRlci1NZWFkIikpDQoNCg0KIyBleHRyYWN0aW5nIHRoZSBtZWFuIGFuZCA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbHMNCmVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLmFsbC5zcmluIDwtIGVzdGltYXRlcy5DSShwdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLmFsbC5zcmluKQ0KZXN0aW1hdGVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuc21kLmFsbC5zcmluIDwtIGVzdGltYXRlcy5DSShwdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC5hbGwuc3JpbikNCg0KYGBgDQoNClRoZSBhbGwtaW4gcHVibGljYXRpb24gYmlhcyB0ZXN0IGlzIHNpbWlsYXIgdG8gdGhlIHVuaS1tb2RlcmF0b3IgbWV0YS1yZWdyZXNzaW9ucyBhYm92ZSBmb3Igc21hbGwtc3R1ZHkgZWZmZWN0cyAoc2VjdGlvbnMgUzQuMi40LjEpIGJ1dCBoYWQgc29tZSBkaWZmZXJlbmNlcyBmb3IgdGltZS1sYWcgZWZmZWN0cyAoUzQuMi40LjIpLg0KDQpGaXJzdCwgdGhlIG11bHRpLW1vZGVyYXRvciBtZXRhLXJlZ3Jlc3Npb24gc2hvdyBhIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgc2xvcGUgZm9yIHRoZSBtb2RlcmF0b3IgJ3NxcnRfaW52X25cX3RpbGRhJyAoc2xvcGUgZm9yIGxuUlIgPSBgciByb3VuZChlc3RpbWF0ZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5yci5hbGwuc3JpblsxLDJdLDIpYCwgOTUlIENJID0gW2ByIHJvdW5kKGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLmFsbC5zcmluWzEsM10sMilgLGByIHJvdW5kKGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLmFsbC5zcmluWzEsNF0sMilgXTsgRmlndXJlIFM0LjkpIGFuZCAoc2xvcGUgZm9yIFNNRCA9IGByIHJvdW5kKGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC5hbGwuc3JpblsxLDJdLDIpYCwgOTUlIENJID0gW2ByIHJvdW5kKGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC5hbGwuc3JpblsxLDNdLDIpYCxgciByb3VuZChlc3RpbWF0ZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5zbWQuYWxsLnNyaW5bMSw0XSwyKWBdOyBGaWd1cmUgUzQuMTApLCBjb25maXJtaW5nIGV2aWRlbmNlIG9mIHNtYWxsLXN0dWR5IGVmZmVjdHMuIE5vdGUgdGhhdCBNdXJwaHkgZXQgYWwuICgyMDEzKSBvcmlnaW5hbGx5IHJlcG9ydGVkIG5vIGZ1bm5lbCBhc3ltbWV0cnkgZnJvbSB2aXN1YWwgaW5zcGVjdGlvbiwgaG93ZXZlciwgd2UgZG8gbm90IHJlY29tbWVuZCB1c2luZyB0aGlzIG1ldGhvZCBmb3IgbWV0YS1hbmFseXRpYyBkYXRhc2V0cyB3aXRoIG11bHRpcGxlIGxldmVscyBvZiBub24taW5kZXBlbmRlbmNlIGFuZCBoaWdoIGhldGVyb2dlbmVpdHkuDQoNClNlY29uZCwgdGhlIGFsbC1pbiBwdWJsaWNhdGlvbiBiaWFzIHRlc3Qgc2hvdyBubyBldmlkZW5jZSBvZiBkZWNsaW5lIGVmZmVjdHMgZm9yIGxuUlIgc2luY2UgdGhlIG1vZGVyYXRvciAneWVhciBvZiBwdWJsaWNhdGlvbicgaXMgaW5kaXN0aW5ndWlzaGFibGUgZnJvbSB6ZXJvIChzbG9wZSA9IGByIHJvdW5kKGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLmFsbC5zcmluWzIsMl0sMilgLCA5NSUgQ0kgPSBbYHIgcm91bmQoZXN0aW1hdGVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwucnIuYWxsLnNyaW5bMiwzXSwyKWAsYHIgcm91bmQoZXN0aW1hdGVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwucnIuYWxsLnNyaW5bMiw0XSwyKWBdOyBGaWd1cmUgUzQuMTIpLiBIb3dldmVyLCB0aGUgZWZmZWN0IHNpemUgU01EIHRlbmQgdG8gc2hvdyBldmlkZW5jZSBvZiBkZWNsaW5lIGVmZmVjdHMsIGFzIHRoZSBzbG9wZSBvZiBwdWJsaWNhdGlvbiB5ZWFyIGlzIGNsb3NlIHRvIHN0YXRpc3RpY2FsIHNpZ25pZmljYW5jZSAoc2xvcGUgPSBgciByb3VuZChlc3RpbWF0ZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5zbWQuYWxsLnNyaW5bMiwyXSwyKWAsIDk1JSBDSSA9IFtgciByb3VuZChlc3RpbWF0ZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5zbWQuYWxsLnNyaW5bMiwzXSwyKWAsYHIgcm91bmQoZXN0aW1hdGVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuc21kLmFsbC5zcmluWzIsNF0sMilgXTsgRmlndXJlIFM0LjEzKS4NCg0KIyMjIyMgRmlndXJlIFM0LjkNCg0KYGBge3IgZmlnLmhlaWdodCA9IDUuNSwgZmlnLndpZHRoID0gNy41LCBmaWcuYWxpZ24gPSAiY2VudGVyIiwgZmlnLmNhcD0iTW9yZSBuZWdhdGl2ZSBlc3RpbWF0ZXMgb2YgbG5SUiBhcmUgbGVzcyBjZXJ0YWluIChsYXJnZXIgc3F1YXJlIHJvb3Qgb2YgaW52ZXJzZSBvZiBlZmZlY3RpdmUgc2FtcGxlIHNpemUpLCBzaG93aW5nIGV2aWRlbmNlIG9mIHNtYWxsLXN0dWR5IGVmZmVjdHMgaW4gdGhlIG1ldGEtYW5hbHl0aWMgZGF0YXNldC4gVGhlIHNvbGlkIGxpbmUgcmVwcmVzZW50cyB0aGUgbW9kZWwgZXN0aW1hdGUgYW5kIHRoZSBzaGFkaW5nIHNob3dzIGl0cyA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbHMuIn0NCiMgcHJlZGljdGluZyBlZmZlY3Qgc2l6ZXMgZm9yIGEgcmFuZ2Ugb2Ygc3FydChpbnZfbl90aWxkYSkgZnJvbSB0aGUgbWluaW11bSBvYnNlcnZlZCBpbiB0aGUgZGF0YSB0byB0aGUgbWF4aW11bSBvYnNlcnZlZCBpbiBkYXRhLCB3aGlsZSB5ZWFyIGlzIGtlcHQgYXQgaXRzIG1lYW4gdmFsdWUsIGluIHRoaXMgY2FzZSAwIHNpbmNlIHllYXIgd2FzIG1lYW4tY2VudHJlZA0KIyBjb25kaXRpb25lZCBvbiBvYnNlcnZhdGlvbmFsIHN0dWRpZXMNCnByZWRpY3QucHVibGljYXRpb24uYmlhcy5tb2RlbC5yci5hbGwuc3Jpbi5wbG90LjEgPC0gDQpwcmVkaWN0KHB1YmxpY2F0aW9uLmJpYXMubW9kZWwucnIuYWxsLnNyaW4sIG5ld21vZHM9Y2JpbmQoc2VxKG1pbihkYXRhc2V0LnJyJHNxcnRfaW52X25fdGlsZGEpLCBtYXgoZGF0YXNldC5yciRzcXJ0X2ludl9uX3RpbGRhKSwgbGVuZ3RoLm91dD0zMjQpLCBjKDApLCBjKDApLCAxKSkNCg0KDQpuZXdkYXQgPC0gZGF0YS5mcmFtZShzZWk9IHNlcShtaW4oZGF0YXNldC5yciRzcXJ0X2ludl9uX3RpbGRhKSwgbWF4KGRhdGFzZXQucnIkc3FydF9pbnZfbl90aWxkYSksIGxlbmd0aC5vdXQ9MzI0KSwNCiAgICAgICAgICAgICAgICAgICAgIGZpdD1wcmVkaWN0LnB1YmxpY2F0aW9uLmJpYXMubW9kZWwucnIuYWxsLnNyaW4ucGxvdC4xJHByZWQsDQogICAgICAgICAgICAgICAgICAgICB1cHBlcj1wcmVkaWN0LnB1YmxpY2F0aW9uLmJpYXMubW9kZWwucnIuYWxsLnNyaW4ucGxvdC4xJGNpLnViLA0KICAgICAgICAgICAgICAgICAgICAgbG93ZXI9cHJlZGljdC5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLmFsbC5zcmluLnBsb3QuMSRjaS5sYiwNCiAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpDQoNCnhheGlzIDwtIGRhdGFzZXQucnIkc3FydF9pbnZfbl90aWxkYQ0KeWF4aXMgPC0gZGF0YXNldC5yciR5aQ0KDQoNCnBsb3QoeGF4aXMseWF4aXMsDQogICAgIHR5cGU9Im4iLA0KICAgICB5bGFiPSIiLA0KICAgICB4bGFiPSIiLA0KICAgICB4YXh0PSJuIiwNCiAgICAgeWF4dD0ibiINCiAgICAgKQ0KYWJsaW5lKGE9MCxiPTAsIGx3ZD0xLCBsdHk9MSkNCmF4aXMoMSxhdD1zZXEoMCwxLjYsMC4yKSwNCiAgICAgY2V4LmF4aXM9MC44LHRjaz0tMC4wMikNCmF4aXMoMiwNCiAgICAgYXQ9cm91bmQoc2VxKC0zLDIsMC41KSwxKSwNCiAgICAgY2V4LmF4aXM9MC44LGxhcz0yLHRjaz0tMC4wMikNCnRpdGxlKHhsYWIgPSAic3F1YXJlIHJvb3Qgb2YgaW52ZXJzZSBvZiBlZmZlY3RpdmUgc2FtcGxlIHNpemUiLCANCiAgICAgIHlsYWIgPSAiZWZmZWN0IHNpemUgKGxuUlIpIiwNCiAgICAgIGxpbmUgPSAyLjc1LCBjZXgubGFiPTEuNCkNCnBvaW50cyh4YXhpcyx5YXhpcywNCiAgICAgICBiZz1yZ2IoMCwwLDAsIDAuMSksDQogICAgICAgY29sPXJnYigwLDAsMCwgMC4yKSwNCiAgICAgICBwY2g9MjEsDQogICAgICAgY2V4PTEpDQpsaW5lcyhuZXdkYXQkc2VpLCBuZXdkYXQkZml0LCBsd2Q9Mi43NSxjb2w9ImRhcmtvcmNoaWQ0IikgDQpwb2x5Z29uKGMobmV3ZGF0JHNlaSxyZXYobmV3ZGF0JHNlaSkpLA0KICAgICAgICBjKG5ld2RhdCRsb3dlcixyZXYobmV3ZGF0JHVwcGVyKSksDQogICAgICAgIGJvcmRlcj1OQSxjb2w9cmdiKDEwNC8yNTUsMzQvMjU1LDEzOS8yNTUsIDAuNSkpDQpgYGANCg0KIyMjIyMgRmlndXJlIFM0LjEwDQoNCmBgYHtyIGZpZy5oZWlnaHQgPSA1LjUsIGZpZy53aWR0aCA9IDcuNSwgZmlnLmFsaWduID0gImNlbnRlciIsIGZvZy5jYXB0aW9uID0gIk1vcmUgbmVnYXRpdmUgZXN0aW1hdGVzIG9mIFNNRCBoYXZlIHNtYWxsZXIgZWZmZWN0aXZlIHNhbXBsZSBzaXplcyAobGFyZ2VyIHNxdWFyZSByb290IG9mIGludmVyc2Ugb2YgZWZmZWN0aXZlIHNhbXBsZSBzaXplKSwgc2hvd2luZyBldmlkZW5jZSBvZiBzbWFsbC1zdHVkeSBlZmZlY3RzIGluIHRoZSBtZXRhLWFuYWx5dGljIGRhdGFzZXQuIFRoZSBzb2xpZCBsaW5lIHJlcHJlc2VudHMgdGhlIG1vZGVsIGVzdGltYXRlIGFuZCB0aGUgc2hhZGluZyBzaG93cyBpdHMgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzLiJ9DQojIHByZWRpY3RpbmcgZWZmZWN0IHNpemVzIGZvciBhIHJhbmdlIG9mIFNFIGZyb20gdGhlIG1pbmltdW0gb2JzZXJ2ZWQgaW4gdGhlIGRhdGEgdG8gdGhlIG1heGltdW0gb2JzZXJ2ZWQgaW4gZGF0YSwgd2hpbGUgeWVhciBpcyBrZXB0IGF0IGl0cyBtZWFuIHZhbHVlLCBpbiB0aGlzIGNhc2UgMCBzaW5jZSB5ZWFyIHdhcyBtZWFuLWNlbnRyZWQNCiNjb25kaXRpb25lZCBvbiBvYnNlcnZhdGlvbmFsIHN0dWRpZXMNCnByZWRpY3QucHVibGljYXRpb24uYmlhcy5tb2RlbC5zbWQuYWxsLnNyaW4ucGxvdC4xIDwtIHByZWRpY3QocHVibGljYXRpb24uYmlhcy5tb2RlbC5zbWQuYWxsLnNyaW4sIG5ld21vZHM9Y2JpbmQoc2VxKG1pbihkYXRhc2V0LnNtZCRzcXJ0X2ludl9uX3RpbGRhKSwgbWF4KGRhdGFzZXQuc21kJHNxcnRfaW52X25fdGlsZGEpLCBsZW5ndGgub3V0PTMyMCksIGMoMCksIGMoMCksIDEpKQ0KDQoNCm5ld2RhdCA8LSBkYXRhLmZyYW1lKHNlaT0gc2VxKG1pbihkYXRhc2V0LnNtZCRzcXJ0X2ludl9uX3RpbGRhKSwgbWF4KGRhdGFzZXQuc21kJHNxcnRfaW52X25fdGlsZGEpLCBsZW5ndGgub3V0PTMyMCksDQogICAgICAgICAgICAgICAgICAgICBmaXQ9cHJlZGljdC5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC5hbGwuc3Jpbi5wbG90LjEkcHJlZCwNCiAgICAgICAgICAgICAgICAgICAgIHVwcGVyPXByZWRpY3QucHVibGljYXRpb24uYmlhcy5tb2RlbC5zbWQuYWxsLnNyaW4ucGxvdC4xJGNpLnViLA0KICAgICAgICAgICAgICAgICAgICAgbG93ZXI9cHJlZGljdC5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC5hbGwuc3Jpbi5wbG90LjEkY2kubGIsDQogICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKQ0KDQp4YXhpcyA8LSBkYXRhc2V0LnNtZCRzcXJ0X2ludl9uX3RpbGRhDQp5YXhpcyA8LSBkYXRhc2V0LnNtZCR5aQ0KcGxvdCh4YXhpcyx5YXhpcywNCiAgICAgdHlwZT0ibiIsDQogICAgIHlsYWI9IiIsDQogICAgIHhsYWI9IiIsDQogICAgIHhheHQ9Im4iLA0KICAgICB5YXh0PSJuIg0KICAgICApDQphYmxpbmUoYT0wLGI9MCwgbHdkPTEsIGx0eT0xKQ0KYXhpcygxLGF0PXNlcSgwLDEuMiwwLjIpLA0KICAgICBjZXguYXhpcz0wLjgsdGNrPS0wLjAyKQ0KYXhpcygyLA0KICAgICBhdD1yb3VuZChzZXEoLTgsNCwyKSwxKSwNCiAgICAgY2V4LmF4aXM9MC44LGxhcz0yLHRjaz0tMC4wMikNCnRpdGxlKHhsYWIgPSAic3F1YXJlIHJvb3Qgb2YgaW52ZXJzZSBvZiBlZmZlY3RpdmUgc2FtcGxlIHNpemUiLCANCiAgICAgIHlsYWIgPSAiZWZmZWN0IHNpemUgKFNNRCkiLA0KICAgICAgbGluZSA9IDIuNzUsIGNleC5sYWI9MS40KQ0KcG9pbnRzKHhheGlzLHlheGlzLA0KICAgICAgIGJnPXJnYigwLDAsMCwgMC4xKSwNCiAgICAgICBjb2w9cmdiKDAsMCwwLCAwLjIpLA0KICAgICAgIHBjaD0yMSwNCiAgICAgICBjZXg9MSkNCmxpbmVzKG5ld2RhdCRzZWksIG5ld2RhdCRmaXQsIGx3ZD0yLjc1LGNvbD0iZGFya29yY2hpZDQiKSANCnBvbHlnb24oYyhuZXdkYXQkc2VpLHJldihuZXdkYXQkc2VpKSksDQogICAgICAgIGMobmV3ZGF0JGxvd2VyLHJldihuZXdkYXQkdXBwZXIpKSwNCiAgICAgICAgYm9yZGVyPU5BLGNvbD1yZ2IoMTA0LzI1NSwzNC8yNTUsMTM5LzI1NSwgMC41KSkNCmBgYA0KDQo8YnIvPjxici8+DQoNCiMjIyMjIEZpZ3VyZSBTNC4xMQ0KDQpgYGB7ciBmaWcuaGVpZ2h0ID0gNS41LCBmaWcud2lkdGggPSA3LjUsIGZpZy5hbGlnbiA9ICJjZW50ZXIiLCBmaWcuY2FwPSJUaGUgYXZlcmFnZSBlZmZlY3QsIGFzIG1lYXN1cmVkIGJ5IGxuUlIsIGRpZCBub3Qgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudGx5IGNoYW5nZSB3aXRoIHRpbWUuIFRoZSBzb2xpZCBsaW5lIHJlcHJlc2VudHMgdGhlIG1vZGVsIGVzdGltYXRlLCB0aGUgc2hhZGluZyBzaG93cyBpdHMgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzLiJ9DQojIHByZWRpY3RpbmcgZWZmZWN0IHNpemVzIGZvciBhIHJhbmdlIG9mIHNxcnQoaW52X25fdGlsZGEpIGZyb20gdGhlIG1pbmltdW0gb2JzZXJ2ZWQgaW4gdGhlIGRhdGEgdG8gdGhlIG1heGltdW0gb2JzZXJ2ZWQgaW4gZGF0YSwgd2hpbGUgeWVhciBpcyBrZXB0IGF0IGl0cyBtZWFuIHZhbHVlLCBpbiB0aGlzIGNhc2UgMCBzaW5jZSB5ZWFyIHdhcyBtZWFuLWNlbnRyZWQNCiNjb25kaXRpb25lZCBvbiBvYnNlcnZhdGlvbmFsIHN0dWRpZXMNCnByZWRpY3QucHVibGljYXRpb24uYmlhcy5tb2RlbC5yci5hbGwuc3Jpbi5wbG90LjIgPC0gDQpwcmVkaWN0KHB1YmxpY2F0aW9uLmJpYXMubW9kZWwucnIuYWxsLnNyaW4sIG5ld21vZHM9Y2JpbmQobWVhbihkYXRhc2V0LnJyJHNxcnRfaW52X25fdGlsZGEpLHNlcShtaW4oZGF0YXNldC5yciR5ZWFyLmMpLCBtYXgoZGF0YXNldC5yciR5ZWFyLmMpLCBsZW5ndGgub3V0PTMyNCksIGMoMCksIDEpKQ0KDQoNCm5ld2RhdCA8LSBkYXRhLmZyYW1lKHllYXIgPSBzZXEobWluKGRhdGFzZXQucnIkeWVhciksIG1heChkYXRhc2V0LnJyJHllYXIpLCBsZW5ndGgub3V0PTMyNCksDQogICAgICAgICAgICAgICAgICAgICBmaXQ9cHJlZGljdC5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLmFsbC5zcmluLnBsb3QuMiRwcmVkLA0KICAgICAgICAgICAgICAgICAgICAgdXBwZXI9cHJlZGljdC5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLmFsbC5zcmluLnBsb3QuMiRjaS51YiwNCiAgICAgICAgICAgICAgICAgICAgIGxvd2VyPXByZWRpY3QucHVibGljYXRpb24uYmlhcy5tb2RlbC5yci5hbGwuc3Jpbi5wbG90LjIkY2kubGIsDQogICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKQ0KDQp4YXhpcyA8LSBkYXRhc2V0LnJyJHllYXINCnlheGlzIDwtIGRhdGFzZXQucnIkeWkNCnBsb3QoeGF4aXMseWF4aXMsDQogICAgIHR5cGU9Im4iLA0KICAgICB5bGFiPSIiLA0KICAgICB4bGFiPSIiLA0KICAgICB4YXh0PSJuIiwNCiAgICAgeWF4dD0ibiINCiAgICAgKQ0KYWJsaW5lKGE9MCxiPTAsIGx3ZD0xLCBsdHk9MSkNCmF4aXMoMSxhdD1zZXEoMTk4OSwyMDEzLDUpLA0KICAgICBjZXguYXhpcz0wLjgsdGNrPS0wLjAyKQ0KYXhpcygyLA0KICAgICBhdD1yb3VuZChzZXEoLTMsMiwwLjUpLDEpLA0KICAgICBjZXguYXhpcz0wLjgsbGFzPTIsdGNrPS0wLjAyKQ0KdGl0bGUoeGxhYiA9ICJ5ZWFyIG9mIHB1YmxpY2F0aW9uIiwgDQogICAgICB5bGFiID0gImVmZmVjdCBzaXplIChsblJSKSIsDQogICAgICBsaW5lID0gMi43NSwgY2V4LmxhYj0xLjQpDQpwb2ludHMoeGF4aXMseWF4aXMsDQogICAgICAgYmc9cmdiKDAsMCwwLCAwLjEpLA0KICAgICAgIGNvbD1yZ2IoMCwwLDAsIDAuMiksDQogICAgICAgcGNoPTIxLA0KICAgICAgIGNleD0xKQ0KbGluZXMobmV3ZGF0JHllYXIsIG5ld2RhdCRmaXQsIGx3ZD0yLjc1LGNvbD0iZGFya29yY2hpZDQiKSANCnBvbHlnb24oYyhuZXdkYXQkeWVhcixyZXYobmV3ZGF0JHllYXIpKSwNCiAgICAgICAgYyhuZXdkYXQkbG93ZXIscmV2KG5ld2RhdCR1cHBlcikpLA0KICAgICAgICBib3JkZXI9TkEsY29sPXJnYigxMDQvMjU1LDM0LzI1NSwxMzkvMjU1LCAwLjUpKQ0KYGBgDQoNCiMjIyMjIEZpZ3VyZSBTNC4xMg0KDQpgYGB7ciBmaWcuaGVpZ2h0ID0gNS41LCBmaWcud2lkdGggPSA3LjUsIGZpZy5hbGlnbiA9ICJjZW50ZXIiLCBmaWcuY2FwPSJUaGUgYXZlcmFnZSBlZmZlY3QsIGFzIG1lYXN1cmVkIGJ5IFNNRCwgaGFzIGRlY2xpbmVkLCBhbHRob3VnaCBub24tc2lnbmZpY2FudCwgb3ZlciB0aGUgdGltZXNwYW4gY2FwdHVyZWQgYnkgdGhpcyBkYXRhc2V0LiBUaGUgc29saWQgbGluZSByZXByZXNlbnRzIHRoZSBtb2RlbCBlc3RpbWF0ZSwgdGhlIHNoYWRpbmcgc2hvd3MgaXRzIDk1JSBjb25maWRlbmNlIGludGVydmFscy4ifQ0KIyBwcmVkaWN0aW5nIGVmZmVjdCBzaXplcyBmb3IgYSByYW5nZSBvZiBzcXJ0KGludl9uX3RpbGRhKSBmcm9tIHRoZSBtaW5pbXVtIG9ic2VydmVkIGluIHRoZSBkYXRhIHRvIHRoZSBtYXhpbXVtIG9ic2VydmVkIGluIGRhdGEsIHdoaWxlIHllYXIgaXMga2VwdCBhdCBpdHMgbWVhbiB2YWx1ZSwgaW4gdGhpcyBjYXNlIDAgc2luY2UgeWVhciB3YXMgbWVhbi1jZW50cmVkDQojIGNvbmRpdGlvbmVkIG9ic2VydmF0aW9uYWwgc3R1ZGllcw0KcHJlZGljdC5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC5hbGwuc3Jpbi5wbG90LjIgPC0gDQpwcmVkaWN0KHB1YmxpY2F0aW9uLmJpYXMubW9kZWwuc21kLmFsbC5zcmluLCBuZXdtb2RzPWNiaW5kKG1lYW4oZGF0YXNldC5zbWQkc3FydF9pbnZfbl90aWxkYSksc2VxKG1pbihkYXRhc2V0LnNtZCR5ZWFyLmMpLCBtYXgoZGF0YXNldC5zbWQkeWVhci5jKSwgbGVuZ3RoLm91dD0zMjApLCBjKDApLCAxKSkNCg0KDQpuZXdkYXQgPC0gZGF0YS5mcmFtZSh5ZWFyPSBzZXEobWluKGRhdGFzZXQuc21kJHllYXIpLCBtYXgoZGF0YXNldC5zbWQkeWVhciksIGxlbmd0aC5vdXQ9MzIwKSwNCiAgICAgICAgICAgICAgICAgICAgIGZpdD1wcmVkaWN0LnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuc21kLmFsbC5zcmluLnBsb3QuMiRwcmVkLA0KICAgICAgICAgICAgICAgICAgICAgdXBwZXI9cHJlZGljdC5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC5hbGwuc3Jpbi5wbG90LjIkY2kudWIsDQogICAgICAgICAgICAgICAgICAgICBsb3dlcj1wcmVkaWN0LnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuc21kLmFsbC5zcmluLnBsb3QuMiRjaS5sYiwNCiAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpDQoNCnhheGlzIDwtIGRhdGFzZXQuc21kJHllYXINCnlheGlzIDwtIGRhdGFzZXQuc21kJHlpDQpwbG90KHhheGlzLHlheGlzLA0KICAgICB0eXBlPSJuIiwNCiAgICAgeWxhYj0iIiwNCiAgICAgeGxhYj0iIiwNCiAgICAgeGF4dD0ibiIsDQogICAgIHlheHQ9Im4iDQogICAgICkNCmFibGluZShhPTAsYj0wLCBsd2Q9MSwgbHR5PTEpDQpheGlzKDEsYXQ9c2VxKDE5ODksMjAxMyw1KSwNCiAgICAgY2V4LmF4aXM9MC44LHRjaz0tMC4wMikNCmF4aXMoMiwNCiAgICAgYXQ9cm91bmQoc2VxKC04LDQsMiksMSksDQogICAgIGNleC5heGlzPTAuOCxsYXM9Mix0Y2s9LTAuMDIpDQp0aXRsZSh4bGFiID0gInllYXIgb2YgcHVibGljYXRpb24iLCANCiAgICAgIHlsYWIgPSAiZWZmZWN0IHNpemUgKFNNRCkiLA0KICAgICAgbGluZSA9IDIuNzUsIGNleC5sYWI9MS40KQ0KcG9pbnRzKHhheGlzLHlheGlzLA0KICAgICAgIGJnPXJnYigwLDAsMCwgMC4xKSwNCiAgICAgICBjb2w9cmdiKDAsMCwwLCAwLjIpLA0KICAgICAgIHBjaD0yMSwNCiAgICAgICBjZXg9MSkNCmxpbmVzKG5ld2RhdCR5ZWFyLCBuZXdkYXQkZml0LCBsd2Q9Mi43NSxjb2w9ImRhcmtvcmNoaWQ0IikgDQpwb2x5Z29uKGMobmV3ZGF0JHllYXIscmV2KG5ld2RhdCR5ZWFyKSksDQogICAgICAgIGMobmV3ZGF0JGxvd2VyLHJldihuZXdkYXQkdXBwZXIpKSwNCiAgICAgICAgYm9yZGVyPU5BLGNvbD1yZ2IoMTA0LzI1NSwzNC8yNTUsMTM5LzI1NSwgMC41KSkNCmBgYA0KDQo8YnIvPjxici8+DQoNCiMjIyMgUzQuMi40OiBBZGp1c3Rpbmcgb3ZlcmFsbCBlZmZlY3Qgc2l6ZSBlc3RpbWF0ZXMgZm9yIGxuUlIgYW5kIFNNRA0KDQpJbiB0aGUgbWFpbiB0ZXh0IHdlIHByb3ZpZGUgYSB0d28tc3RlcCBhcHByb2FjaCB0byBjYWxjdWxhdGUgdGhlIGJpYXMtY29ycmVjdGVkIG92ZXJhbGwgZWZmZWN0IHNpemUgZXN0aW1hdGUuIFRoZSByYXRpb25hbGUgaXMgdGhhdCwgd2hlbiBubyB1bmNlcnRhaW50eSBleGlzdHMgKHRoZW9yZXRpY2FsbHkpLCB3ZSBjYW4gZ2V0IHRoZSBwb3RlbnRpYWwgdHJ1ZSBlZmZlY3QgZnJvbSBhIG11bHRpcGxlLW1vZGVyYXRvciBtdWx0aWxldmVsLW1vZGVsIChpLmUuIGFsbC1pbiBwdWJsaWNhdGlvbiBiaWFzIHRlc3QsIHdoZXJlIHRoZSBpbmNsdXNpb24gb2YgbW9kZXJhdG9yIHZhcmlhYmxlcyByZWR1Y2VzIGhldGVyb2dlbmVpdHkpLiBXZSBhZGQgdHdvIG1vcmUgbW9kZXJhdG9ycyBgRXhwZXJpbWVudGFsLm9yLk9ic2VydmF0aW9uYWwuYCAoMiBsZXZlbHMpIGFuZCBgRGlzdHVyYmFuY2VfY2F0ZWdvcnlgICgxMCBsZXZlbHM7IHdlIHJlZmVyIHRvIHRoaXMgbW9kZWwgYXMgdGhlIGZ1bGwgbW9kZWwpLiANCg0KVGhlIG1vZGVscyBhYm92ZSBkbyBub3QgcHJvdmlkZSBzdHJvbmcgZXZpZGVuY2UgdGhhdCB0aGVyZSBhcmUgYSBzaWduaWZpY2FudCBvdmVyYWxsIGVmZmVjdCAob3IgYSBzaWduaWZpY2FudCBpbnRlcmNlcHQgb3IgYXQgbGVhc3QsIG9uZSBncm91cCBiZWluZyBzaWduaWZpY2FudCBhdCB0aGUgYWxwaGEgbGV2ZWwgYXQgMTAlLCB3aGljaCB0cmFuc2xhdGVzIHRvIGEgdCB2YWx1ZSBvZiA+IH4xLjY1IGluIG1hZ25pdHVkZSkuIEhvd2V2ZXIsIHRoZSBtZXRhLXJlZ3Jlc3Npb24gbW9kZWwgb25seSB3aXRoIGBFeHBlcmltZW50YWwub3IuT2JzZXJ2YXRpb25hbC5gIHByb3ZpZGVzIGdvb2QgZXZpZGVuY2UgdGhhdCB0aGVyZSBhcmUgc29tZSBvdmVyYWxsIGVmZmVjdHMuICBUaGVyZWZvcmUsIGhlcmUsIHdlIHNob3VsZCB0cnkgYm90aCBzY2VuYXJpb3M6ICRcc3FydCgxL1x0aWxkZXtufSkkIGFuZCAkMS9cdGlsZGV7bn0kLiBUaGUgZm9ybWVyIHByb3ZpZGVzIHRoZSBiZXN0IGVzdGltYXRlIHdoZW4gdGhlcmUgaXMgbm8gZXZpZGVuY2UgdGhhdCBhbiBvdmVyYWxsIGVmZmVjdCBleGlzdHMgb3Igc29tZSBncm91cHMgaGF2ZSBub24temVybyBlZmZlY3RzIHdoaWxlIHRoZSBsYXR0ZXIgaXMgYmVzdCB3aGVuIHRoZXJlIGlzIHN1Y2ggZXZpZGVuY2UuIA0KDQpgYGB7cn0NCiMgbG5SUg0KDQojIHdpdGggc3FydCgxL35uKQ0KIyBwcmVwYXJhdGlvbiB0byBnZXQgbWFyZ2luYWxpemVkIG1lYW4gKHdoZW4gc3FydF9pbnZfbl90aWxkYSA9IDAgYW5kIHllYXIuYyA9IDApDQpyZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5yci52LjAgPC0gcWRyZyhvYmplY3QgPSBwdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLmFsbC5zcmluLCBkYXRhID0gZGF0YXNldC5yciwgYXQgPSBsaXN0KGludl9uX3RpbGRhID0gMCwgeWVhci5jID0gMCkpDQojIG1hcmdpbmFsaXplZCBvdmVyYWxsIG1lYW4gYXQgaW52X25fdGlsZGEgPSAwIGFuZCB5ZWFyLmMgPSAwOyBhbHNvIHdlaWdodHMgPSAicHJvcCIgb3IgImNlbGxzIiBhdmVyYWdlIHRoaW5ncyBvdmVyIHByb3BvcnRpb25hbGx5LiBpZiBub3Qgc3BlY2lmaWVkLCBhbGwgZ3JvdXBzIChsZXZlbHMpIGdldCB0aGUgc2FtZSB3ZWlnaHRzDQpvdmVyYWxsLnJlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLnYuMCA8LSBlbW1lYW5zKHJlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLnYuMCwgc3BlY3MgPSB+MSwgZGYgPSBwdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLmFsbC5zcmluJGRkZiwgd2VpZ2h0cyA9ICJwcm9wIikgIyB1c2luZyBlZmZlY3Qgc2l6ZSAtIDcgDQojIG1hcmdpbmFsaXplZCBtZWFucyBmb3IgZGlmZmVyZW50IGxldmVscyBmb3IgRXhwZXJpbWVudGFsLm9yLk9ic2VydmF0aW9uYWwuDQptbS5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLnYuMCA8LSBlbW1lYW5zKHJlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLnYuMCwgc3BlY3MgPSAiRXhwZXJpbWVudGFsLm9yLk9ic2VydmF0aW9uYWwuIiwgZGYgPSBwdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLmFsbC5zcmluJGRkZiwgd2VpZ2h0cyA9ICJwcm9wIikNCg0KIyB3aXRoIDEvfm4NCiMgcHJvdmlkaW5nIGFuIGFkanVzdGVkIGVmZmVjdCBmb3IgZWFjaCBsZXZlbCBvZiBDYXB0aXZpdHlDDQpwdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLnYuMSA8LSBybWEubXYoeWksIHZpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kcz1+LTEraW52X25fdGlsZGEgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhci5jICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRXhwZXJpbWVudGFsLm9yLk9ic2VydmF0aW9uYWwuICsgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERpc3R1cmJhbmNlX2NhdGVnb3J5LCAgIyB0aGlzIGNhbiBiZSBhIHJhbmRvbSBlZmZlY3QgYnV0IHBsYWNpbmcgdGhpcyBoZXJlIHRvIHNob3cgaG93IGVtbWVhbnMgd29ya3MNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb209bGlzdCgNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH4gMSB8IG9ic0lELCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH4gMSB8IHBhcGVySUQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9IlJFTUwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdCA9ICJ0IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gZGF0YXNldC5yciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyb2wgPSBsaXN0KG9wdGltaXplcj0ib3B0aW0iLCBvcHRtZXRob2Q9Ik5lbGRlci1NZWFkIikpDQoNCiMgcHJlcGFyYXRpb24gdG8gZ2V0IG1hcmdpbmFsaXplZCBtZWFuICh3aGVuIGludl9uX3RpbGRhID0gMCBhbmQgeWVhci5jID0gMCkNCnJlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLnYuMSA8LSBxZHJnKG9iamVjdCA9IHB1YmxpY2F0aW9uLmJpYXMubW9kZWwucnIudi4xLCBkYXRhID0gZGF0YXNldC5yciwgYXQgPSBsaXN0KGludl9uX3RpbGRhID0gMCwgeWVhci5jID0gMCkpDQojIG1hcmdpbmFsaXplZCBvdmVyYWxsIG1lYW4gYXQgaW52X25fdGlsZGEgPSAwIGFuZCB5ZWFyLmMgPSAwOyBhbHNvIHdlaWdodHMgPSAicHJvcCIgb3IgImNlbGxzIiBhdmVyYWdlIHRoaW5ncyBvdmVyIHByb3BvcnRpb25hbGx5LiBpZiBub3Qgc3BlY2lmaWVkLCBhbGwgZ3JvdXBzIChsZXZlbHMpIGdldCB0aGUgc2FtZSB3ZWlnaHRzDQpvdmVyYWxsLnJlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLnYuMSA8LSBlbW1lYW5zKHJlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLnYuMSwgc3BlY3MgPSB+MSwgZGYgPSBwdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLnYuMSRkZGYsIHdlaWdodHMgPSAicHJvcCIpICMgdXNpbmcgZWZmZWN0IHNpemUgLSA3IA0KIyBtYXJnaW5hbGl6ZWQgbWVhbnMgZm9yIGRpZmZlcmVudCBsZXZlbHMgZm9yIEV4cGVyaW1lbnRhbC5vci5PYnNlcnZhdGlvbmFsLg0KbW0ucHVibGljYXRpb24uYmlhcy5tb2RlbC5yci52LjEgPC0gZW1tZWFucyhyZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5yci52LjEsIHNwZWNzID0gIkV4cGVyaW1lbnRhbC5vci5PYnNlcnZhdGlvbmFsLiIsIGRmID0gcHVibGljYXRpb24uYmlhcy5tb2RlbC5yci52LjEkZGRmLCB3ZWlnaHRzID0gInByb3AiKQ0KIyBlc3RpYW10ZWQgbWFyZ2luYWxpc2VkIG1lYW4NCiNtbS5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnIudi4xIDwtIGVtbWVhbnMocmVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwucnIudi4xLCBzcGVjcyA9ICJFeHBlcmltZW50YWwub3IuT2JzZXJ2YXRpb25hbC4iLCBkZiA9IHB1YmxpY2F0aW9uLmJpYXMubW9kZWwucnIudi4xJGRmcywgd2VpZ2h0cyA9ICJlcXVhbCIpDQoNCiMgbW9kZWwgM2I6IGNvbXBhcmluZyByZXN1bHRzIHdpdGhvdXQgY29ycmVjdGluZyBmb3IgcHVibGljYXRpb24gYmlhcw0KcHVibGljYXRpb24uYmlhcy5tb2RlbC5yci52LjFiIDwtIHJtYS5tdih5aSwgdmksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RzPX4tMSsgRXhwZXJpbWVudGFsLm9yLk9ic2VydmF0aW9uYWwuLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb209bGlzdCgNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH4gMSB8IG9ic0lELCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH4gMSB8IHBhcGVySUQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJSRU1MIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlc3QgPSAidCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGRhdGFzZXQucnIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cm9sID0gbGlzdChvcHRpbWl6ZXI9Im9wdGltIiwgb3B0bWV0aG9kPSJOZWxkZXItTWVhZCIpKQ0KDQojIGV4dHJhY3RpbmcgdGhlIG1lYW4gYW5kIDk1JSBjb25maWRlbmNlIGludGVydmFscw0KZXN0aW1hdGVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwucnIudi4wIDwtIGVzdGltYXRlcy5DSTIobW0ucHVibGljYXRpb24uYmlhcy5tb2RlbC5yci52LjApDQplc3RpbWF0ZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5yci52LjEgPC0gZXN0aW1hdGVzLkNJMihtbS5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLnYuMSkNCmVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLnYuMWIgPC0gZXN0aW1hdGVzLkNJKHB1YmxpY2F0aW9uLmJpYXMubW9kZWwucnIudi4xYikNCg0KIyBTTUQNCiMgd2l0aCBzcXJ0KDEvfm4pDQojIHByZXBhcmF0aW9uIHRvIGdldCBtYXJnaW5hbGl6ZWQgbWVhbiAod2hlbiBzcXJ0X2ludl9uX3RpbGRhID0gMCBhbmQgeWVhci5jID0gMCkNCnJlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC52LjAgPC0gcWRyZyhvYmplY3QgPSBwdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC5hbGwuc3JpbiwgZGF0YSA9IGRhdGFzZXQuc21kLCBhdCA9IGxpc3QoaW52X25fdGlsZGEgPSAwLCB5ZWFyLmMgPSAwKSkNCiMgbWFyZ2luYWxpemVkIG92ZXJhbGwgbWVhbiBhdCBpbnZfbl90aWxkYSA9IDAgYW5kIHllYXIuYyA9IDA7IGFsc28gd2VpZ2h0cyA9ICJwcm9wIiBvciAiY2VsbHMiIGF2ZXJhZ2UgdGhpbmdzIG92ZXIgcHJvcG9ydGlvbmFsbHkuIGlmIG5vdCBzcGVjaWZpZWQsIGFsbCBncm91cHMgKGxldmVscykgZ2V0IHRoZSBzYW1lIHdlaWdodHMNCm92ZXJhbGwucmVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuc21kLnYuMCA8LSBlbW1lYW5zKHJlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC52LjAsIHNwZWNzID0gfjEsIGRmID0gcHVibGljYXRpb24uYmlhcy5tb2RlbC5zbWQuYWxsLnNyaW4kZGRmLCB3ZWlnaHRzID0gInByb3AiKSAjIHVzaW5nIGVmZmVjdCBzaXplIC0gNyANCiMgbWFyZ2luYWxpemVkIG1lYW5zIGZvciBkaWZmZXJlbnQgbGV2ZWxzIGZvciBFeHBlcmltZW50YWwub3IuT2JzZXJ2YXRpb25hbC4NCm1tLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuc21kLnYuMCA8LSBlbW1lYW5zKHJlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC52LjAsIHNwZWNzID0gIkV4cGVyaW1lbnRhbC5vci5PYnNlcnZhdGlvbmFsLiIsIGRmID0gcHVibGljYXRpb24uYmlhcy5tb2RlbC5zbWQuYWxsLnNyaW4kZGRmLCB3ZWlnaHRzID0gInByb3AiKQ0KDQojIG1vZGVsIDM6IHByb3ZpZGluZyBhbiBhZGp1c3RlZCBlZmZlY3QgZm9yIGVhY2ggbGV2ZWwgb2YgQ2FwdGl2aXR5Qw0KcHVibGljYXRpb24uYmlhcy5tb2RlbC5zbWQudi4xIDwtIHJtYS5tdih5aSwgdmksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RzPX4tMSsgaW52X25fdGlsZGEgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhci5jICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRXhwZXJpbWVudGFsLm9yLk9ic2VydmF0aW9uYWwuLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb209bGlzdCgNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH4gMSB8IERpc3R1cmJhbmNlX2NhdGVnb3J5LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfiAxIHwgb2JzSUQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfiAxIHwgcGFwZXJJRCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gIlJFTUwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdCA9ICJ0IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gZGF0YXNldC5zbWQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cm9sID0gbGlzdChvcHRpbWl6ZXI9Im9wdGltIiwgb3B0bWV0aG9kPSJOZWxkZXItTWVhZCIpKQ0KIyBwcmVwYXJhdGlvbiB0byBnZXQgbWFyZ2luYWxpemVkIG1lYW4gKHdoZW4gaW52X25fdGlsZGEgPSAwIGFuZCB5ZWFyLmMgPSAwKQ0KcmVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuc21kLnYuMSA8LSBxZHJnKG9iamVjdCA9IHB1YmxpY2F0aW9uLmJpYXMubW9kZWwuc21kLnYuMSwgZGF0YSA9IGRhdGFzZXQuc21kLCBhdCA9IGxpc3QoaW52X25fdGlsZGEgPSAwLCB5ZWFyLmMgPSAwKSkNCiMgbWFyZ2luYWxpemVkIG92ZXJhbGwgbWVhbiBhdCBpbnZfbl90aWxkYSA9IDAgYW5kIHllYXIuYyA9IDA7IGFsc28gd2VpZ2h0cyA9ICJwcm9wIiBvciAiY2VsbHMiIGF2ZXJhZ2UgdGhpbmdzIG92ZXIgcHJvcG9ydGlvbmFsbHkuIGlmIG5vdCBzcGVjaWZpZWQsIGFsbCBncm91cHMgKGxldmVscykgZ2V0IHRoZSBzYW1lIHdlaWdodHMNCm92ZXJhbGwucmVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuc21kLnYuMSA8LSBlbW1lYW5zKHJlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC52LjEsIHNwZWNzID0gfjEsIGRmID0gcHVibGljYXRpb24uYmlhcy5tb2RlbC5zbWQudi4xJGRkZiwgd2VpZ2h0cyA9ICJwcm9wIikgIyB1c2luZyBlZmZlY3Qgc2l6ZSAtIDcgDQojIG1hcmdpbmFsaXplZCBtZWFucyBmb3IgZGlmZmVyZW50IGxldmVscyBmb3IgRXhwZXJpbWVudGFsLm9yLk9ic2VydmF0aW9uYWwuDQptbS5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC52LjEgPC0gZW1tZWFucyhyZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5zbWQudi4xLCBzcGVjcyA9ICJFeHBlcmltZW50YWwub3IuT2JzZXJ2YXRpb25hbC4iLCBkZiA9IHB1YmxpY2F0aW9uLmJpYXMubW9kZWwuc21kLnYuMSRkZGYsIHdlaWdodHMgPSAicHJvcCIpDQoNCg0KIyBtb2RlbCAzYjogY29tcGFyaW5nIHJlc3VsdHMgd2l0aG91dCBjb3JyZWN0aW5nIGZvciBwdWJsaWNhdGlvbiBiaWFzDQpwdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC52LjFiIDwtIHJtYS5tdih5aSwgdmksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RzPX4tMSsgRXhwZXJpbWVudGFsLm9yLk9ic2VydmF0aW9uYWwuLCAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmRvbT1saXN0KA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfiAxIHwgRGlzdHVyYmFuY2VfY2F0ZWdvcnksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB+IDEgfCBvYnNJRCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB+IDEgfCBwYXBlcklEKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAiUkVNTCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXN0ID0gInQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBkYXRhc2V0LnNtZCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyb2wgPSBsaXN0KG9wdGltaXplcj0ib3B0aW0iLCBvcHRtZXRob2Q9Ik5lbGRlci1NZWFkIikpDQoNCg0KIyBleHRyYWN0aW5nIHRoZSBtZWFuIGFuZCA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbHMNCmVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC52LjAgPC0gZXN0aW1hdGVzLkNJMihtbS5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC52LjApDQplc3RpbWF0ZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5zbWQudi4xIDwtIGVzdGltYXRlcy5DSTIobW0ucHVibGljYXRpb24uYmlhcy5tb2RlbC5zbWQudi4xKQ0KZXN0aW1hdGVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuc21kLnYuMWIgPC0gZXN0aW1hdGVzLkNJKHB1YmxpY2F0aW9uLmJpYXMubW9kZWwuc21kLnYuMWIpDQpgYGANCg0KVGhlIGZ1bGwgbW9kZWwgd2l0aCAkXHNxcnQoMS9cdGlsZGV7bn0pJCBwcm92aWRlZCBhbiBhZGp1c3RlZCBvdmVyYWxsIGxuUlIgdGhhdCB3YXMgc2xpZ2h0bHkgbGFyZ2VyIGluIG1hZ25pdHVkZSBmcm9tIHRoZSB1bmFkanVzdGVkIGVzdGltYXRlIChhZGp1c3RlZCBlZmZlY3QgPSBgciByb3VuZChzdW1tYXJ5KG92ZXJhbGwucmVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwucnIudi4wKVssMl0sMilgLCA5NSUgQ0kgPSBbYHIgcm91bmQoc3VtbWFyeShvdmVyYWxsLnJlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLnYuMClbLDNdLDIpYCxgciByb3VuZChzdW1tYXJ5KG92ZXJhbGwucmVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwucnIudi4wKVssNF0sMilgXTsgdW5hZGp1c3RlZCBlZmZlY3QgPSBgciByb3VuZChtZXRhYW5hbHl0aWMubWVhbi5tb2RlbC5ycltbMV1dLDIpYCwgOTUlIENJID0gW2ByIHJvdW5kKG1ldGFhbmFseXRpYy5tZWFuLm1vZGVsLnJyW1szXV0sMilgLGByIHJvdW5kKG1ldGFhbmFseXRpYy5tZWFuLm1vZGVsLnJyW1s0XV0sMilgXTsgdGggbW9kZWwgaW4gc2VjdGlvbiBTNC4yLjIpLiBUaGlzIGlzIHVuZXhwZWN0ZWQgYXMgdGhlIGFkanVzdGVkIGVzdGltYXRlIHNob3VsZCBiZSBjbG9zZXIgdG8gemVybyB0aGFuIHRoZSB1bmFkanVzdGVkIG9uZSkuIE9uIHRoZSBvdGhlciBoYW5kLCB0aGUgbW9kZWwgd2l0aCAkMS9cdGlsZGV7bn0kIHByb3ZpZGVkIGEgc21hbGxlciBvdmVyYWxsIHZhbHVlIGFzIGV4cGVjdGVkIChhZGp1c3RlZCBlZmZlY3QgPSBgciByb3VuZChzdW1tYXJ5KG92ZXJhbGwucmVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwucnIudi4xKVssMl0sMilgLCA5NSUgQ0kgPSBbYHIgcm91bmQoc3VtbWFyeShvdmVyYWxsLnJlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLnYuMSlbLDNdLDIpYCxgciByb3VuZChzdW1tYXJ5KG92ZXJhbGwucmVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwucnIudi4xKVssNF0sMilgXSkuIC4gR2l2ZW4gdGhvc2UsIHdlIGNvbmNsdWRlIHRoYXQgaXQgaXMgcHJvYmFibHkgbW9yZSBhcHByb3ByaWF0ZSB0byB0YWtlIHRoZSBhZGp1c3RlZCBlc3RpbWF0ZXMgZnJvbSB0aGUgbW9kZWwgd2l0aCAkMS9cdGlsZGV7bn0kIHRoYW4gdGhlIG1vZGVsIHdpdGggJFxzcXJ0KDEvXHRpbGRle259KSQuIEluIFRhYmxlIFM0LjMsICBzaG93IHRoYXQgdGhlIGVzdGltYXRlcyBmcm9tIHRoZSB1bmFkanVzdGVkIG1vZGVsIGFuZCB0aGUgYWRqdXN0ZWQgbW9kZWwgd2l0aCAgJFxzcXJ0KDEvXHRpbGRle259KSQgd2hpbGUgdGhlIGFkanVzdGVkIG1vZGVsIHdpdGggICRcc3FydCgxL1x0aWxkZXtufSkkIGdhdmUgc21hbGxlciBlc3RpbWF0ZXMgaW4gbWFnbml0dWRlLCB3aGljaCBzaG91bGQgYmUgZXhwZWN0ZWQgZm9yIGFkanVzdGVkIGVmZmVjdHMuIFdlIHN1Z2dlc3QgdGhhdCB3ZSB1c2UgdGhlIGVzdGltYXRlcyBmcm9tIHRoZSBtZXRob2Qgd2l0aCAkMS9cdGlsZGV7bn0kIChBZGp1c3RlZCBtZWFuIDIgYW5kIEFkanVzdGVkIDk1JSBDSSAyKS4gDQoNCmBgYHtyfQ0KDQojIGNyZWF0aW5nIGEgdGFibGUgdG8gc2hvdyB0aGUgcmVzdWx0cyBvZiBtb2RlbCAyDQp0YWJsZS5jb21wYXJpbmcuRXhwLm9yLk9icy5sZXZlbHMwIDwtIG1lcmdlKGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLnYuMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLnYuMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5PSJlc3RpbWF0ZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbGwueD1UKQ0KDQp0YWJsZS5jb21wYXJpbmcuRXhwLm9yLk9icy5sZXZlbHMgPC0gbWVyZ2UodGFibGUuY29tcGFyaW5nLkV4cC5vci5PYnMubGV2ZWxzMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLnYuMWIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieT0iZXN0aW1hdGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxsLng9VCkNCiMgcm91bmRpbmcgZXN0aW1hdGVzDQp0YWJsZS5jb21wYXJpbmcuRXhwLm9yLk9icy5sZXZlbHMgPC0gdGFibGUuY29tcGFyaW5nLkV4cC5vci5PYnMubGV2ZWxzICU+JSBtdXRhdGVfYXQodmFycyhtZWFuLngsIGxvd2VyLngsdXBwZXIueCxtZWFuLnksbG93ZXIueSx1cHBlci55LCBtZWFuLGxvd2VyLHVwcGVyKSwgbGlzdCh+cm91bmQoLiwgMikpKQ0KDQp0YWJsZS5jb21wYXJpbmcuRXhwLm9yLk9icy5sZXZlbHMgPC0gZGF0YS5mcmFtZShFeHAub3IuT2JzLmxldmVsID0gdGFibGUuY29tcGFyaW5nLkV4cC5vci5PYnMubGV2ZWxzWywxXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRqdXN0ZWQubWVhbjE9dGFibGUuY29tcGFyaW5nLkV4cC5vci5PYnMubGV2ZWxzWywyXSwgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRqdXN0ZWQuQ0kxID0gcGFzdGUwKCJbIix0YWJsZS5jb21wYXJpbmcuRXhwLm9yLk9icy5sZXZlbHNbLDNdLCIsIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFibGUuY29tcGFyaW5nLkV4cC5vci5PYnMubGV2ZWxzWyw0XSwiXSIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZGp1c3RlZC5tZWFuMj10YWJsZS5jb21wYXJpbmcuRXhwLm9yLk9icy5sZXZlbHNbLDVdLCAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZGp1c3RlZC5DSTIgPSBwYXN0ZTAoIlsiLHRhYmxlLmNvbXBhcmluZy5FeHAub3IuT2JzLmxldmVsc1ssNl0sIiwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YWJsZS5jb21wYXJpbmcuRXhwLm9yLk9icy5sZXZlbHNbLDddLCJdIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuYWRqdXN0ZWQubWVhbiA9IHRhYmxlLmNvbXBhcmluZy5FeHAub3IuT2JzLmxldmVsc1ssOF0sICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuYWRqdXN0ZWQuQ0kgPSBwYXN0ZTAoIlsiLHRhYmxlLmNvbXBhcmluZy5FeHAub3IuT2JzLmxldmVsc1ssOV0sIiwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YWJsZS5jb21wYXJpbmcuRXhwLm9yLk9icy5sZXZlbHNbLDEwXSwiXSIpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkNCg0KdGFibGUuY29tcGFyaW5nLkV4cC5vci5PYnMubGV2ZWxzWywxXSA8LSBjKCJFeHBlcmltZW50YWwiLCJPYnNlcnZhdGlvbmFsIikNCiMgY3JlYXRpbmcgYSBmb3JtYXR0ZWQgdGFibGUgdXNpbmcgdGhlIFIgcGFja2FnZSAnZ3QnDQp0YWJsZS5jb21wYXJpbmcuRXhwLm9yLk9icy5sZXZlbHMuZ3QgPC0gdGFibGUuY29tcGFyaW5nLkV4cC5vci5PYnMubGV2ZWxzICU+JSANCiAgZ3QoKSAlPiUgDQogIGNvbHNfbGFiZWwoRXhwLm9yLk9icy5sZXZlbD1tZCgiKipTdHVkeSB0eXBlKioiKSwNCiAgICAgICAgICAgICBhZGp1c3RlZC5tZWFuMT1tZCgiKipBZGp1c3RlZCBtZWFuIDEqKiIpLA0KICAgICAgICAgICAgIGFkanVzdGVkLkNJMT1tZCgiKipBZGp1c3RlZCA5NSUgQ0kgMSoqIiksDQogICAgICAgICAgICAgYWRqdXN0ZWQubWVhbjI9bWQoIioqQWRqdXN0ZWQgbWVhbiAyKioiKSwNCiAgICAgICAgICAgICBhZGp1c3RlZC5DSTI9bWQoIioqQWRqdXN0ZWQgOTUlIENJIDIqKiIpLA0KICAgICAgICAgICAgIHVuYWRqdXN0ZWQubWVhbj1tZCgiKipVbmFkanVzdGVkIG1lYW4qKiIpLA0KICAgICAgICAgICAgIHVuYWRqdXN0ZWQuQ0k9bWQoIioqVW5hZGp1c3RlZCA5NSUgQ0kqKiIpLA0KICAgICAgICAgICAgICkgJT4lDQogIGNvbHNfYWxpZ24oYWxpZ24gPSAiY2VudGVyIikNCnRhYmxlLmNvbXBhcmluZy5FeHAub3IuT2JzLmxldmVscy5ndA0KYGBgDQoNCioqVGFibGUgUzQuMyoqLiBUaGUgZXN0aW1hdGVzIG9mIGFsbCBsZXZlbHMgb2YgdGhlIG1vZGVyYXRvciBgRXhwZXJpbWVudGFsLm9yLk9ic2VydmF0aW9uYWwuYCBhbmQgdGhlaXIgYWRqdXN0ZWQgZXN0aW1hdGVzICgxIGFuZCAyKSB1c2luZyB0aGUgYWxsLWluIHB1YmxpY2F0aW9uIGJpYXMgdGVzdCAobXVsdGktbW9kZXJhdG9yIG1ldGEtcmVncmVzc2lvbikuICdBZGp1c3RlZCAxJyBpcyB3aXRoICRcc3FydCgxL1x0aWxkZXtufSkkIHdoaWxlICdBZGp1c3RlZCAyJyB3aXRoICQxL1x0aWxkZXtufSQuIEVzdGltYXRlcyBhcmUgcHJlc2VudGVkIGFzIGxuUlIuDQoNClNNRCBhbHNvIHNob3cgc2ltaWxhciBwYXR0ZXJucyBmb3IgdGhlIGFkanVzdGVkIG92ZXJhbGwgZWZmZWN0cyAoQWRqdXN0ZWQgMSB3aXRoICRcc3FydCgxL1x0aWxkZXtufSkkICBhbmQgQWRqdXN0ZWQgMiB3aXRoICQxL1x0aWxkZXtufSQgKSBhZnRlciBhY2NvdW50aW5nIGZvciBwdWJsaWNhdGlvbiBiaWFzIGFuZCB0aW1lLWxhZyBiaWFzOiAoQWRqdXN0ZWQgMiA9IGByIHJvdW5kKHN1bW1hcnkob3ZlcmFsbC5yZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5zbWQudi4wKVssMl0sMilgLCA5NSUgQ0kgPSBbYHIgcm91bmQoc3VtbWFyeShvdmVyYWxsLnJlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC52LjApWywzXSwyKWAsYHIgcm91bmQoc3VtbWFyeShvdmVyYWxsLnJlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC52LjApWyw0XSwyKWBdOyBBZGp1c3RlZCAxIHdpdGggJFxzcXJ0KDEvXHRpbGRle259KSQgIGFuZCBBZGp1c3RlZCAyIHdpdGggJDEvXHRpbGRle259JCApIGFmdGVyIGFjY291bnRpbmcgZm9yIHB1YmxpY2F0aW9uIGJpYXMgYW5kIHRpbWUtbGFnIGJpYXM6IChBZGp1c3RlZCAyID0gYHIgcm91bmQoc3VtbWFyeShvdmVyYWxsLnJlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC52LjEpWywyXSwyKWAsIDk1JSBDSSA9IFtgciByb3VuZChzdW1tYXJ5KG92ZXJhbGwucmVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuc21kLnYuMSlbLDNdLDIpYCxgciByb3VuZChzdW1tYXJ5KG92ZXJhbGwucmVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuc21kLnYuMSlbLDRdLDIpYF07IHVuYWRqdXN0ZWQgZWZmZWN0ID0gYHIgcm91bmQobWV0YWFuYWx5dGljLm1lYW4ubW9kZWwuc21kW1sxXV0sMilgLCA5NSUgQ0kgPSBbYHIgcm91bmQobWV0YWFuYWx5dGljLm1lYW4ubW9kZWwuc21kW1szXV0sMilgLGByIHJvdW5kKG1ldGFhbmFseXRpYy5tZWFuLm1vZGVsLnNtZFtbNF1dLDIpYF07IG1vcmUgaW4gc2VjdGlvbiBTNC4yLjIpLiBBcyB3aXRoIGxuUlIsIFRhYmxlIFM0LjQgc2hvdyB0aGF0IHRoZSBlc3RpbWF0ZXMgZnJvbSB0aGUgdW5hZGp1c3RlZCBtb2RlbCBhbmQgdGhlIGFkanVzdGVkIG1vZGVsIHdpdGggICRcc3FydCgxL1x0aWxkZXtufSkkIHdoaWxlIHRoZSBhZGp1c3RlZCBtb2RlbCB3aXRoICAkXHNxcnQoMS9cdGlsZGV7bn0pJCBnYXZlIHNtYWxsZXIgZXN0aW1hdGVzIGluIG1hZ25pdHVkZS4gVGhlcmVmb3JlLCBmb3IgU01ELCB3ZSBhbHNvIHN1Z2dlc3QgdGhhdCB3ZSB1c2UgdGhlIGVzdGltYXRlcyBmcm9tIHRoZSBtZXRob2Qgd2l0aCAkMS9cdGlsZGV7bn0kIChBZGp1c3RlZCBtZWFuIDIgYW5kIEFkanVzdGVkIDk1JSBDSSAyKS4gQWxzbywgd2UgYmVsaWV2ZSB0aGF0IHRoZSB1c2Ugb2YgJDEvXHRpbGRle259JCBtYXkgYmUgYWx3YXlzIHdhcnJhbnRlZCBiZWNhdXNlIGl0IGlzIGxpa2VseSB0aGF0IGEgbm9uLXplcm8gZWZmZWN0IGFsbW9zdCBhbHdheXMgZXhpc3RzLCB3aGlsZSB3aGVuIHRoZXJlIGlzIG5vIG92ZXJhbGwgZWZmZWN0LCBpdCBwcm9iYWJseSBkb2VzIG5vdCBtYXR0ZXIgd2hldGhlciB3ZSB1c2UgJFxzcXJ0KDEvXHRpbGRle259KSQgb3IgJDEvXHRpbGRle259JCB0byBhZGp1c3Qgc3VjaCBhbiBvdmVyYWxsIGVmZmVjdCAod2hvc2UgdHJ1ZSBlZmZlY3QgaXMgemVybykuIA0KDQpgYGB7cn0NCg0KIyBjcmVhdGluZyBhIHRhYmxlIHRvIHNob3cgdGhlIHJlc3VsdHMgb2YgbW9kZWwgMg0KdGFibGUuY29tcGFyaW5nLkV4cC5vci5PYnMubGV2ZWxzMCA8LSBtZXJnZShlc3RpbWF0ZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5zbWQudi4wLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXN0aW1hdGVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuc21kLnYuMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5PSJlc3RpbWF0ZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbGwueD1UKQ0KDQp0YWJsZS5jb21wYXJpbmcuRXhwLm9yLk9icy5sZXZlbHMgPC0gbWVyZ2UodGFibGUuY29tcGFyaW5nLkV4cC5vci5PYnMubGV2ZWxzMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC52LjFiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnk9ImVzdGltYXRlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsbC54PVQpDQojIHJvdW5kaW5nIGVzdGltYXRlcw0KdGFibGUuY29tcGFyaW5nLkV4cC5vci5PYnMubGV2ZWxzIDwtIHRhYmxlLmNvbXBhcmluZy5FeHAub3IuT2JzLmxldmVscyAlPiUgbXV0YXRlX2F0KHZhcnMobWVhbi54LCBsb3dlci54LHVwcGVyLngsbWVhbi55LGxvd2VyLnksdXBwZXIueSwgbWVhbixsb3dlcix1cHBlciksIGxpc3QofnJvdW5kKC4sIDIpKSkNCg0KdGFibGUuY29tcGFyaW5nLkV4cC5vci5PYnMubGV2ZWxzIDwtIGRhdGEuZnJhbWUoRXhwLm9yLk9icy5sZXZlbCA9IHRhYmxlLmNvbXBhcmluZy5FeHAub3IuT2JzLmxldmVsc1ssMV0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFkanVzdGVkLm1lYW4xPXRhYmxlLmNvbXBhcmluZy5FeHAub3IuT2JzLmxldmVsc1ssMl0sICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFkanVzdGVkLkNJMSA9IHBhc3RlMCgiWyIsdGFibGUuY29tcGFyaW5nLkV4cC5vci5PYnMubGV2ZWxzWywzXSwiLCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhYmxlLmNvbXBhcmluZy5FeHAub3IuT2JzLmxldmVsc1ssNF0sIl0iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRqdXN0ZWQubWVhbjI9dGFibGUuY29tcGFyaW5nLkV4cC5vci5PYnMubGV2ZWxzWyw1XSwgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRqdXN0ZWQuQ0kyID0gcGFzdGUwKCJbIix0YWJsZS5jb21wYXJpbmcuRXhwLm9yLk9icy5sZXZlbHNbLDZdLCIsIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFibGUuY29tcGFyaW5nLkV4cC5vci5PYnMubGV2ZWxzWyw3XSwiXSIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmFkanVzdGVkLm1lYW4gPSB0YWJsZS5jb21wYXJpbmcuRXhwLm9yLk9icy5sZXZlbHNbLDhdLCAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmFkanVzdGVkLkNJID0gcGFzdGUwKCJbIix0YWJsZS5jb21wYXJpbmcuRXhwLm9yLk9icy5sZXZlbHNbLDldLCIsIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFibGUuY29tcGFyaW5nLkV4cC5vci5PYnMubGV2ZWxzWywxMF0sIl0iKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApDQoNCnRhYmxlLmNvbXBhcmluZy5FeHAub3IuT2JzLmxldmVsc1ssMV0gPC0gYygiRXhwZXJpbWVudGFsIiwiT2JzZXJ2YXRpb25hbCIpDQojIGNyZWF0aW5nIGEgZm9ybWF0dGVkIHRhYmxlIHVzaW5nIHRoZSBSIHBhY2thZ2UgJ2d0Jw0KdGFibGUuY29tcGFyaW5nLkV4cC5vci5PYnMubGV2ZWxzLmd0IDwtIHRhYmxlLmNvbXBhcmluZy5FeHAub3IuT2JzLmxldmVscyAlPiUgDQogIGd0KCkgJT4lIA0KICBjb2xzX2xhYmVsKEV4cC5vci5PYnMubGV2ZWw9bWQoIioqU3R1ZHkgdHlwZSoqIiksDQogICAgICAgICAgICAgYWRqdXN0ZWQubWVhbjE9bWQoIioqQWRqdXN0ZWQgbWVhbiAxKioiKSwNCiAgICAgICAgICAgICBhZGp1c3RlZC5DSTE9bWQoIioqQWRqdXN0ZWQgOTUlIENJIDEqKiIpLA0KICAgICAgICAgICAgIGFkanVzdGVkLm1lYW4yPW1kKCIqKkFkanVzdGVkIG1lYW4gMioqIiksDQogICAgICAgICAgICAgYWRqdXN0ZWQuQ0kyPW1kKCIqKkFkanVzdGVkIDk1JSBDSSAyKioiKSwNCiAgICAgICAgICAgICB1bmFkanVzdGVkLm1lYW49bWQoIioqVW5hZGp1c3RlZCBtZWFuKioiKSwNCiAgICAgICAgICAgICB1bmFkanVzdGVkLkNJPW1kKCIqKlVuYWRqdXN0ZWQgOTUlIENJKioiKSwNCiAgICAgICAgICAgICApICU+JQ0KICBjb2xzX2FsaWduKGFsaWduID0gImNlbnRlciIpDQp0YWJsZS5jb21wYXJpbmcuRXhwLm9yLk9icy5sZXZlbHMuZ3QNCmBgYA0KDQoqKlRhYmxlIFM0LjQqKi4gVGhlIGVzdGltYXRlcyBvZiBhbGwgbGV2ZWxzIG9mIHRoZSBtb2RlcmF0b3IgYEV4cGVyaW1lbnRhbC5vci5PYnNlcnZhdGlvbmFsLmAgYW5kIHRoZWlyIGFkanVzdGVkIGVzdGltYXRlcyAoMSBhbmQgMikgdXNpbmcgdGhlIGFsbC1pbiBwdWJsaWNhdGlvbiBiaWFzIHRlc3QgKG11bHRpLW1vZGVyYXRvciBtZXRhLXJlZ3Jlc3Npb24pLiAnQWRqdXN0ZWQgMScgaXMgd2l0aCAkXHNxcnQoMS9cdGlsZGV7bn0pJCB3aGlsZSAnQWRqdXN0ZWQgMicgd2l0aCAkMS9cdGlsZGV7bn0kLiBFc3RpbWF0ZXMgYXJlIHByZXNlbnRlZCBhcyBTTUQuDQoNCiMjIyBTNC4zOiBFeHRyYSBwbG90IC0tIEZpZ3VyZSA2YS1kIChyZWRyYXduIHVzaW5nIGVmZmVjdGl2ZSBzYW1wbGUgc2l6ZSkNCg0KSGVyZSB3ZSByZWRyYXcgRmlndXJlIDZhLWQgdXNpbmcgZWZmZWN0aXZlIHNhbXBsZSBzaXplIG9yIG1vcmUgYWNjdXJhdGVseSwgJFx0aWxkZXtufSQuIFdlIG5vdGUgdGhhdCBGaWd1cmUgNmItZCBpbiB0aGUgbWFpbiB0ZXh0IHVzZSBzdGFuZGFyZCBlcnJvcnMgKFNFKSBvZiBkaWZmZXJlbnQgdHlwZXMgb2YgcmVzaWR1YWxzIHNvIHBhbmVscyBiLCBjIGFuZCBkIG1heSBub3QgYmUgZGlyZWN0bHkgY29tcGFyYWJsZSBiZXR3ZWVuIEZpZ3VyZSA2IGFuZCB0aGlzIHJlZHJhd24gZmlndXJlLg0KDQpgYGB7ciwgZHBpID0gMTAsIGZpZy5hbGlnbiA9ICJjZW50ZXIiLCBmaWcuY2FwPSJGaWd1cmUgNmEtZCByZWRyYXduIn0NCiNpbmNsdWRlX2dyYXBoaWNzKCIuL1IvZmlnLnBuZyIpDQpgYGANCg0KIVtdKGZpZy5wbmcpDQoNCioqRmlndXJlIDZhLWQgcmVkcmF3bioqDQoNCiMjIEFwcGVuZGl4IFM1OiBBbHRlcm5hdGl2ZSBhcHByb2NoZXMNCg0KIyMjIFM1LjE6IEF2ZXJhZ2luZyBhbmQgc2FtcGxpbmc6IGNvcnJlbGF0aW9uIGVmZmVjdCBzaXplcyAoKlpyKikNCg0KIyMjIyBTNS4xLjE6IEF2ZXJhZ2luZw0KDQpUbyBhZ2dyZWdhdGUgKGF2ZXJhZ2UpIGVmZmVjdCBzaXplcyBwZXIgc3R1ZHkgd2Ugd2lsbCB1c2UgdGhlIGZ1bmN0aW9uICdhZ2dyZWdhdGUoKScgZnJvbSB0aGUgUiBwYWNrYWdlIGBtZXRhZm9yYCAoVmllY2h0YmF1ZXIgMjAxMCkgdXNpbmcgYSBjb21wb3VuZCBzeW1tZXRyaWMgc3RydWN0dXJlICgnc3RydWN0PUNTJykgYW5kIGEgdmFsdWUgb2YgMC41IGZvciByaG8gZm9sbG93aW5nIE5vYmxlIGV0IGFsLiAoMjAxNykuIFRoYXQgaXMsIHdoZW4gYXZlcmFnaW5nIGVmZmVjdCBzaXplcyBwZXIgc3R1ZHkgd2UgYXJlIG5vdCBhc3N1bWluZyB0aGF0IHRoZSBlZmZlY3Qgc2l6ZXMgb2YgYSBzdHVkeSBhcmUgaW5kZXBlbmRlbnQgdG8gZWFjaCBvdGhlciwgYnV0IGluc3RlYWQgdGhhdCB0aGV5IGFyZSBjb3JyZWxhdGVkIGFuZCwgc2luY2Ugd2UgZG8gbm90IGtub3cgdGhlIHJlYWwgdmFsdWUgb2YgdGhhdCBjb3JyZWxhdGlvbiwgd2Ugd2lsbCBlc3RpbWF0ZSBpdCBhcyAwLjUgZm9yIGFsbCBzdHVkaWVzLiBUaGUgZnVuY3Rpb24gJ2FnZ3JlZ2F0ZSgpJyB3aWxsIHRoZW4gY29tYmluZSBtdWx0aXBsZSBlc3RpbWF0ZXMgd2l0aGluIHRoZSBzYW1lIHN0dWR5IHVzaW5nIGludmVyc2UtdmFyaWFuY2Ugd2VpZ2h0aW5nIHRha2luZyB0aGUgMC41IGNvcnJlbGF0aW9uIGludG8gY29uc2lkZXJhdGlvbi4gTW9yZSBpbmZvcm1hdGlvbiBhYm91dCB0aGUgZnVuY3Rpb24gJ2FnZ3JlZ2F0ZSgpJyBjYW4gYmUgZm91bmQgYnkgdHlwaW5nIGA/bWV0YWZvcjo6YWdncmVnYXRlYCwgaW5jbHVkaW5nIGhvdyAnYWdncmVnYXRlKCknIGRlYWxzIHdpdGggb3RoZXIgdmFyaWFibGVzIChlLmcuIG1vZGVyYXRvcnMpIGluIHRoZSBkYXRhc2V0Lg0KDQpgYGB7cn0NCiMgeW91IHdpbGwgbmVlZCB0aGUgZGV2ZWxvcG1lbnQgdmVyc2lvbiBvZiAibWV0YWZvciIgcGFja2FnZSB0byBydW4gdGhpcyBiaXQNCiMgcmhvID0gMC41IGlzIGFzIGluIE5vYmxlIGV0IGFsIChNb2wgRWNvbCkNCmRhdGFzZXQuciA8LSBlc2NhbGMoeWk9eWksIHZpPXZpLCBkYXRhPWRhdGFzZXQucikNCmRhdGFzZXQuci5hZ2cgPC0gYWdncmVnYXRlKGRhdGFzZXQuciwgY2x1c3Rlcj1zdHVkeSwgc3RydWN0PSJDUyIsIHJobyA9IDAuNSkNCmBgYA0KDQojIyMjIyBTNS4xLjEuMTogVHJpbS1hbmQtZmlsbCB0ZXN0DQoNClVzaW5nIHRoZSBhZ2dyZWdhdGVkIGRhdGEgKHNlZSBhYm92ZSksIHdlIHdpbGwgdGhlbiBmaXQgdGhlIHRyaW0tYW5kLWZpbGwgbWV0aG9kIChEdXZhbCBhbmQgVHdlZWRpZSAyMDAwYSxiKS4gVGhlIHRyaW0tYW5kLWZpbGwgbWV0aG9kIGlzIGEgbm9uLXBhcmFtZXRyaWMgbWV0aG9kIHRoYXQgY2FuIGJlIHVzZWQgdG8gYm90aCBkZXRlY3QgYW5kIGNvcnJlY3QgZm9yIHB1YmxpY2F0aW9uIGJpYXMgYW5kLCBhbHRob3VnaCBpdCBjYW4gaGFuZGxlIHNvbWUgaGV0ZXJvZ2VuZWl0eSwgaXQgcGVyZm9ybXMgd29yc2UgYXMgaGV0ZXJvZ2VuZWl0eSBpbmNyZWFzZXMgKFBldGVycyBldCBhbC4sIDIwMDc7IE1vcmVubyBldCBhbC4sIDIwMDk7IG1vcmUgaW4gdGhlIG1haW4gdGV4dCkuIFNpbmNlIHdlIGFnZ3JlZ2F0ZWQgb3VyIGRhdGEsIHdlIGNhbiBub3cgcnVuIGEgcmFuZG9tLWVmZmVjdHMgbWV0YS1hbmFseXRpYyBtb2RlbCByYXRoZXIgdGhhbiBhIG11bHRpbGV2ZWwgbW9kZWwgYXMgdXNlZCBpbiBzZWN0aW9uIFMuNCwgYW5kIHdlIHdpbGwgcnVuIHRoZSB0cmltLWFuZC1maWxsIG1ldGhvZCB1c2luZyB0aGlzIG1vZGVsLiBOb3RlIHRoYXQgd2UgdXNlZCB0aGUgbWV0aG9kIGJ5IEtuYXBwIGFuZCBIYXJ0dW5nICgyMDAzOyBgdGVzdCA9ICJrbmhhImApIHJhdGhlciB0aGFuIHRoZSBkZWZhdWx0IHogKFdhbGQtdHlwZSkgdGVzdHM7IHRoaXMgdGVzdCBoYXMgYmVlbiBzaG93biB0byBwZXJmb3JtIGJldHRlci4NCg0KYGBge3J9DQojIHJhbmRvbS9taXhlZC1lZmZlY3RzIG1ldGEtYW5hbHl0aWMgbW9kZWwNCm1ldGEuYW5hbHlzaXMubW9kZWwuci5hZ2cgPC0gcm1hKHlpLCB2aSwgdGVzdD0ia25oYSIsZGF0YT1kYXRhc2V0LnIsc2xhYj1zdHVkeSkNCg0KIyB0cmltLWFuZC1maWxsIG1ldGhvZA0KdHJpbWZpbGwuciA8LSB0cmltZmlsbChtZXRhLmFuYWx5c2lzLm1vZGVsLnIuYWdnKQ0KYGBgDQoNClRoZSB0cmltLWFuZC1maWxsIG1ldGhvZCBpZGVudGlmaWVkIGByIHRyaW1maWxsLnIkazBgIChTRSA9IGByIHJvdW5kKHRyaW1maWxsLnIkc2UuazAsMilgKSBtaXNzaW5nIHN0dWRpZXMgKEZpZ3VyZSBTNS4xKSBhbmQgZXN0aW1hdGVkIGFuIGFkanVzdGVkIG92ZXJhbGwgZWZmZWN0IG9mIGByIHJvdW5kKHRyaW1maWxsLnIkYmV0YVtbMV1dLDIpYCAoOTUlIENJID0gW2ByIHJvdW5kKHRyaW1maWxsLnIkY2kubGJbWzFdXSwyKWAsYHIgcm91bmQodHJpbWZpbGwuciRjaS51YltbMV1dLDIpYF0pLCB3aGljaCBpcyBzaW1pbGFyIHRvIHRoZSBhZGp1c3RlZCBvdmVyYWxsIGVmZmVjdCBlc3RpbWF0ZWQgYnkgb3VyIHN1Z2dlc3RlZCBtdWx0aWxldmVsIG1ldGEtcmVncmVzc2lvbiBtZXRob2QgKGByIHJvdW5kKGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnIudi4xWzEsMl0sMilgLCA5NSUgQ0kgPSBbYHIgcm91bmQoZXN0aW1hdGVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuci52LjFbMSwzXSwyKWAsYHIgcm91bmQoZXN0aW1hdGVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuci52LjFbMSw0XSwyKWBdOyBtb3JlIGluIHNlY3Rpb24gUzQuMS40LjMpLg0KDQo8YnIvPjxici8+DQoNCiMjIyMjIEZpZ3VyZSBTNS4xDQoNCmBgYHtyIGZpZy5hbGlnbiA9ICJjZW50ZXIiLCBmaWcuY2FwPSJGdW5uZWwgcGxvdCB1c2luZyBwcmVjaXNpb24gKDEvU0UpIGFzIGEgbWVhc3VyZSBvZiB1bmNlcnRhaW50eSBhbmQgc2hvd2luZyB0aGUgYWRqdXN0ZWQgbWV0YS1hbmFseXRpYyBtZWFuICh2ZXJ0aWNhbCBsaW5lKSBhbmQgdGhlICBtaXNzaW5nIGVmZmVjdCBzaXplcyAod2hpdGUgcG9pbnRzKSBhY2NvcmRpbmcgdG8gdGhlIHRyaW0tYW5kLWZpbGwgbWV0aG9kLiJ9DQpmdW5uZWwodHJpbWZpbGwuciwgeWF4aXM9InNlaW52IikNCmBgYA0KDQo8YnIvPjxici8+DQoNCiMjIyMjIFM1LjEuMS4yOiBTZWxlY3Rpb24gbW9kZWwgKDMgUFNNKQ0KDQpVc2luZyB0aGUgYWdncmVnYXRlZCBkYXRhIChzZWUgYWJvdmUpLCB3ZSB3aWxsIGFsc28gZml0IGEgc2VsZWN0aW9uIG1vZGVsLWJhc2VkIG1ldGhvZCAocmV2aWV3ZWQgYnkgTWFya3MtQW5nbGluICYgQ2hlbiwgMjAyMCkuIEFsdGhvdWdoIHRoZXJlIGFyZSBtYW55IHNlbGVjdGlvbiBtb2RlbCBtZXRob2RzLCBhbGwgb2YgdGhlbSBtb2RlbCBob3cgZWZmZWN0IHNpemVzIGFyZSBtaXNzaW5nIGJhc2VkIG9uIHAgdmFsdWVzLCBlZmZlY3Qgc2l6ZXMgYW5kL29yIHNhbXBsaW5nIHZhcmlhbmNlLCBhbmQgY2FuIHByb3ZpZGUgYW4gYWRqdXN0ZWQgb3ZlcmFsbCBlZmZlY3QgKGUuZy4gUm9kZ2VycyAmIFB1c3Rlam92c2t5LCAyMDIwOyBtb3JlIGluIHRoZSBtYWluIHRleHQpLiBDb250cmFyeSB0byBvdGhlciBtZXRob2RzLCBzZWxlY3Rpb24gbW9kZWxzIGNhbiBkZWFsIHdpdGggYW5kIG1vZGVsIGhldGVyb2dlbmVpdHkgKGUuZy4gQ2l0a293aWN6IGFuZCBWZXZlYSAyMDE3KSwgYnV0IGNhbm5vdCBkZWFsIHdpdGggbm9uLWluZGVwZW5kZW50IGVmZmVjdCBzaXplcy4gV2Ugd2lsbCBydW4gYSBzdGVwIGZ1bmN0aW9uIHNlbGVjdGlvbiBtb2RlbCBiYXNlZCBvbiBvbmUgY3V0LXBvaW50ICgkXGFscGhhID0gMC4wNSQpOyB0aGlzIG1vZGVsIGlzIHNvbWV0aW1lcyByZWZlcnJlZCB0byBhcyBhIDMgcGFyYW1ldGVyIHNlbGVjdGlvbiBtb2RlbCAoM1BNOyBtb3JlIGluIHRoZSBtYWluIHRleHQ7IFJvZGdlcnMgJiBQdXN0ZWpvdnNreSwgMjAyMDsgbW9yZSBieSB0eXBpbmcgYD9tZXRhZm9yOjpzZWxtb2RlbGApLiBOb3RlIHRoYXQgaGVyZSB3ZSBuZWVkIHRvIHVzZSB0aGUgbWF4aW11bSBsaWtlaG9vbGQgbWV0aG9kIChNTCkgcmF0aGVyIHRoYW4gcmVzdHJpY3RlZCBtYXhpbXVtIGxpa2VsaWhvb2QgKFJFTUwpLg0KDQpgYGB7cn0NCiMgd2l0aG91dCBtb2RlcmF0b3JzDQptZXRhLmFuYWx5c2lzLnIuYWdnMCA8LSBybWEoeWksIHZpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2Q9Ik1MIiwgI21ldGhvZCBuZWVkcyB0byBzZXQgdG8gIk1MIiByYXRoZXIgdGhhbiAiUkVNTCIgYXMgaW4gYWxsIG1vZGVscyBhYm92ZSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXN0PSJrbmhhIiwgI2tuaGEgaXMgbWVhbnQgdG8gYmUgYmV0dGVyIHRoYW4gWiBhbmQgdCwgYnV0IGl0IGlzIG5vdCBpbXBsZW1lbnRlZCBmb3IgbXVsdGlsZXZlbCBtb2RlbHMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhPWRhdGFzZXQucikNCg0KDQp0aHJlZS5QU00ucjAgPC0gc2VsbW9kZWwobWV0YS5hbmFseXNpcy5yLmFnZzAsIHR5cGU9InN0ZXBmdW4iLCBzdGVwcz1jKDAuMDUsMSkpICNub3RlIHRoYXQgc3RlcHM9YygwLjA1KSB3b3VsZCBiZSBnaXZlIHRoZSBzYW1lIHJlc3VsdHMNCg0KIyBsb29rIGF0IGNvbmZpZGVuY2UgaW50ZXJ2YWxzIC0gbm90IGp1c3QgcG9pbnQgZXN0aW1hdGUNCiMgc3VtbWFyeSh0aHJlZS5QU00ucjApDQoNCiMgd2l0aCBtb2RlcmF0b3JzIA0KbWV0YS5yZWdyZXNzaW9uLnIuYWdnIDwtIHJtYSh5aSwgdmksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2QgPSB+IHllYXIuYyArIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENhcHRpdml0eUMgLSAxLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kPSJNTCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlc3Q9ImtuaGEiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1kYXRhc2V0LnIpDQoNCg0KdGhyZWUuUFNNLnIgPC0gc2VsbW9kZWwobWV0YS5yZWdyZXNzaW9uLnIuYWdnLCB0eXBlPSJzdGVwZnVuIiwgc3RlcHM9YygwLjA1KSkNCg0KIyBzdW1tYXJ5KHRocmVlLlBTTS5yKQ0KDQojIGV4dHJhY3RpbmcgdGhlIG1lYW4gYW5kIDk1JSBjb25maWRlbmNlIGludGVydmFscw0KZXN0aW1hdGVzLnRocmVlLlBTTS5yIDwtIGVzdGltYXRlcy5DSSh0aHJlZS5QU00ucikNCmBgYA0KDQpUaGUgc3RlcCBmdW5jdGlvbiBzZWxlY3Rpb24gbW9kZWwgYmFzZWQgb24gb25lIGN1dC1wb2ludCAoJFxhbHBoYSA9IDAuMDUkKSBmb3IgdGhlIGludGVyY2VwdC1vbmx5IG1vZGVsIGVzdGltYXRlZCBhbiBhZGp1c3RlZCBvdmVyYWxsIGVmZmVjdCBvZiBgciByb3VuZCh0aHJlZS5QU00ucjAkYmV0YVtbMV1dLDIpYCAoOTUlIENJID0gW2ByIHJvdW5kKHRocmVlLlBTTS5yMCRjaS5sYltbMV1dLDIpYCxgciByb3VuZCh0aHJlZS5QU00ucjAkY2kudWJbWzFdXSwyKWBdOyBGaWd1cmUgUzUuMiksIHdoaWNoIGlzIGxhcmdlciB0aGFuIHRoZSBvcmlnaW5hbCBvdmVyYWxsIGVmZmVjdCBlc3RpbWF0ZWQgYnkgdGhlIG1ldGEtYW5hbHl0aWMgbW9kZWwgKGByIHJvdW5kKG1ldGFhbmFseXRpYy5tZWFuLm1vZGVsLnJbWzFdXSwyKWAsIDk1JSBDSSA9IFtgciByb3VuZChtZXRhYW5hbHl0aWMubWVhbi5tb2RlbC5yW1szXV0sMilgLGByIHJvdW5kKG1ldGFhbmFseXRpYy5tZWFuLm1vZGVsLnJbWzRdXSwyKWBdOyBtb3JlIGluIHNlY3Rpb24gUzQuMS40LjMpLiBPdmVyYWxsLCB0aGUgc2VsZWN0aW9uIG1vZGVsIGVzdGltYXRlZCBhZGp1c3RlZCBvdmVyYWxsIGVmZmVjdHMgdGhhdCB3ZXJlIGVpdGhlciB2ZXJ5IHNpbWlsYXIgb3IgZXZlbiBzbGlnaHRseSBsYXJnZXIgdGhhbiB0aGUgb3JpZ2luYWwgdW5hZGp1c3RlZCBlZmZlY3Qgc2l6ZXMgKFRhYmxlIFM1LjEpLCB3aGljaCBtaWdodCBpbmRpY2F0ZSB0aGF0IHRoZSBzcGVjaWZpYyBzZWxlY3Rpb24gbW9kZWwgdGhhdCB3ZSB1c2VkIChpLmUuIG9uZSBjdXQtcG9pbnQgJFxhbHBoYSA9IDAuMDUkKSB3YXMgbm90IGFuIGFkZXF1YXRlIGFwcHJveGltYXRpb24gZm9yIHRoZSB1bmRlcmx5aW5nIHNlbGVjdGlvbiBwcm9jZXNzLg0KDQo8YnIvPjxici8+DQoNCiMjIyMjIEZpZ3VyZSBTNS4yDQoNCmBgYHtyIGZpZy5hbGlnbiA9ICJjZW50ZXIiLCBmaWcuY2FwPSJSZXN1bHRzIG9mIGEgc3RlcCBmdW5jdGlvbiBzZWxlY3Rpb24gbW9kZWwgYmFzZWQgb24gb25lIGN1dC1wb2ludCAoJFxhbHBoYSA9IDAuMDUkKSBmb3IgYSBtb2RlbCB3aXRob3V0IGFueSBtb2RlcmF0b3JzIChsZWZ0LWhhbmQgZmlndXJlKSBhbmQgYSBtb2RlbCBpbmNsdWRpbmcgYm90aCAneWVhciBvZiBwdWJsaWNhdGlvbicgYW5kICdjYXB0aXZpdHkgc3RhdHVzJyBhcyBtb2RlcmF0b3JzIChyaWdodC1oYW5kIGZpZ3VyZSkuIn0NCnBhcihtZnJvdyA9IGMoMSwgMikpDQpwbG90KHRocmVlLlBTTS5yMCwgeWxpbSA9IGMoMCwyKSxjb2w9InJlZCIsIGx0eSA9IDMpDQpwbG90KHRocmVlLlBTTS5yLCB5bGltID0gYygwLDIpLGNvbD0icmVkIiwgbHR5ID0gMykNCmBgYA0KDQo8YnIvPjxici8+DQoNCmBgYHtyfQ0KIyBjcmVhdGluZyBhIHRhYmxlIHRvIHNob3cgdGhlIHJlc3VsdHMgb2YgdGhlIHNlbGVjdGlvbiBtb2RlbA0KdGFibGUuY29tcGFyaW5nLmNhcHRpdml0eS5sZXZlbHMuM1BTTSA8LSBtZXJnZShlc3RpbWF0ZXMudGhyZWUuUFNNLnJbYygyOjYpLF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnIudi4xYiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnk9ImVzdGltYXRlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxsLng9VCkNCg0KIyByb3VuZGluZyBlc3RpbWF0ZXMNCnRhYmxlLmNvbXBhcmluZy5jYXB0aXZpdHkubGV2ZWxzLjNQU00gPC0gdGFibGUuY29tcGFyaW5nLmNhcHRpdml0eS5sZXZlbHMuM1BTTSAlPiUgbXV0YXRlX2F0KHZhcnMobWVhbi54LCBsb3dlci54LHVwcGVyLngsbWVhbi55LGxvd2VyLnksdXBwZXIueSksIGxpc3QofnJvdW5kKC4sIDIpKSkNCg0KdGFibGUuY29tcGFyaW5nLmNhcHRpdml0eS5sZXZlbHMuM1BTTSA8LSBkYXRhLmZyYW1lKGNhcHRpdml0eS5sZXZlbCA9IHRhYmxlLmNvbXBhcmluZy5jYXB0aXZpdHkubGV2ZWxzLjNQU01bLDFdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFkanVzdGVkLm1lYW49dGFibGUuY29tcGFyaW5nLmNhcHRpdml0eS5sZXZlbHMuM1BTTVssMl0sICAgICAgICAgICAgICAgYWRqdXN0ZWQuQ0k9cGFzdGUwKCJbIix0YWJsZS5jb21wYXJpbmcuY2FwdGl2aXR5LmxldmVscy4zUFNNWywzXSwiLCIsdGFibGUuY29tcGFyaW5nLmNhcHRpdml0eS5sZXZlbHMuM1BTTVssNF0sIl0iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmFkanVzdGVkLm1lYW49dGFibGUuY29tcGFyaW5nLmNhcHRpdml0eS5sZXZlbHMuM1BTTVssNV0sICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmFkanVzdGVkLkNJPXBhc3RlMCgiWyIsdGFibGUuY29tcGFyaW5nLmNhcHRpdml0eS5sZXZlbHMuM1BTTVssNl0sIiwiLHRhYmxlLmNvbXBhcmluZy5jYXB0aXZpdHkubGV2ZWxzLjNQU01bLDddLCJdIikpDQoNCnRhYmxlLmNvbXBhcmluZy5jYXB0aXZpdHkubGV2ZWxzLjNQU01bLDFdIDwtIGMoIkZDIiwiRlciLCJXQ1QiLCJXQ1QgJiBGQyIsICJXQ1QgJiBGVyIpDQoNCiMgY3JlYXRpbmcgYSBmb3JtYXR0ZWQgdGFibGUgdXNpbmcgdGhlIFIgcGFja2FnZSAnZ3QnDQp0YWJsZS5tb2RlbC5yLmNhcHRpdml0eS5ndC4zUFNNIDwtIHRhYmxlLmNvbXBhcmluZy5jYXB0aXZpdHkubGV2ZWxzLjNQU00gJT4lIA0KICBndDo6Z3QoKSAlPiUgDQogIGNvbHNfbGFiZWwoY2FwdGl2aXR5LmxldmVsPW1kKCIqKkNhcHRpdml0eSBzdGF0dXMqKiIpLA0KICAgICAgICAgICAgIGFkanVzdGVkLm1lYW49bWQoIioqQWRqdXN0ZWQgbWVhbioqIiksDQogICAgICAgICAgICAgYWRqdXN0ZWQuQ0k9bWQoIioqQWRqdXN0ZWQgOTUlIENJKioiKSwNCiAgICAgICAgICAgICB1bmFkanVzdGVkLm1lYW49bWQoIioqVW5hZGp1c3RlZCBtZWFuKioiKSwNCiAgICAgICAgICAgICB1bmFkanVzdGVkLkNJPW1kKCIqKlVuYWRqdXN0ZWQgOTUlIENJKioiKSkgJT4lDQogIGNvbHNfYWxpZ24oYWxpZ24gPSAiY2VudGVyIikNCg0KdGFibGUubW9kZWwuci5jYXB0aXZpdHkuZ3QuM1BTTQ0KYGBgDQoNCioqVGFibGUgUzUuMS4qKiBSZXN1bHRzIGFkanVzdGVkIGFuZCB1bmFkanVzdGVkIGZvciBwdWJsaWNhdGlvbiBiaWFzIGZvciBhbGwgbGV2ZWxzIG9mIHRoZSBtb2RlcmF0b3IgJ2NhcHRpdml0eSBzdGF0dXMnIHVzaW5nIGEgc3RlcCBmdW5jdGlvbiBzZWxlY3Rpb24gbW9kZWwgYmFzZWQgb24gb25lIGN1dC1wb2ludCAoJFxhbHBoYSA9IDAuMDUkKS4gRXN0aW1hdGVzIGFyZSBwcmVzZW50ZWQgYXMgc3RhbmRhcmRpemVkIGVmZmVjdCBzaXplcyB1c2luZyBGaXNoZXIncyB0cmFuc2Zvcm1hdGlvbiBvZiB0aGUgY29ycmVsYXRpb24gY29lZmZpY2llbnQgKGkuZS4gKlpyKikuDQoNCjxici8+PGJyLz4NCg0KIyMjIyMgUzUuMS4xLjM6IEN1bXVsYXRpdmUgbWV0YS1hbmFseXNpcw0KDQpMYXN0LCB1c2luZyB0aGUgYWdncmVnYXRlZCBkYXRhIChzZWUgYWJvdmUpLCB3ZSB3aWxsIGFsc28gcGVyZm9ybSBhIGN1bXVsYXRpdmUgbWV0YS1hbmFseXNpcyB1c2luZyB0aGUgZnVuY3Rpb24gYGN1bXVsKClgIGZyb20gdGhlIFIgcGFja2FnZSBgbWV0YWZvcmAgKFZpZWNodGJhdWVyIDIwMTApLiBCeSBkaXNwbGF5aW5nIHRoZSByZXN1bHRzIG9mIHRoaXMgY3VtdWxhdGl2ZSBtZXRhLWFuYWx5c2lzIGFzIGEgZm9yZXN0IHBsb3QsIHdlIGNhbiBzZWUgaWYgdGhlcmUgaXMgZXZpZGVuY2Ugb2YgZGVjbGluZSBlZmZlY3RzIChtb3JlIGluIHRoZSB0ZXh0KSwgd2hpY2ggd2UgZG8gbm90IHNlZW0gdG8gaGF2ZSBpbiB0aGlzIGRhdGFzZXQgKEZpZ3VyZSBTNS4zKS4NCg0KPGJyLz48YnIvPg0KDQojIyMjIyBGaWd1cmUgUzUuMw0KDQpgYGB7ciBmaWcuYWxpZ24gPSAiY2VudGVyIiwgZmlnLmNhcD0iRm9yZXN0IHBsb3Qgc2hvd2luZyB0aGUgcmVzdWx0cyBvZiBhIGN1bXVsYXRpdmUgbWV0YS1hbmFseXNpcywgc2hvd2luZyBubyBjbGVhciBldmlkZW5jZSBvZiBkZWNsaW5lIGVmZmVjdHMuIn0NCmN1bS5tZXRhLmFuYWx5c2lzLm1vZGVsLnIuYWdnIDwtIGN1bXVsKG1ldGEuYW5hbHlzaXMubW9kZWwuci5hZ2csb3JkZXI9b3JkZXIoZGF0YXNldC5yJHllYXIpKQ0KZm9yZXN0KGN1bS5tZXRhLmFuYWx5c2lzLm1vZGVsLnIuYWdnLCB4bGFiID0gIk92ZXJhbGwgZXN0aW1hdGUgKFpyKSIsZGlnaXRzPWMoMiwxKSxjZXg9MC4zLCBoZWFkZXI9IkF1dGhvcihzKSBhbmQgeWVhciIpDQpgYGANCg0KPGJyLz48YnIvPg0KDQojIyMjIFM1LjEuMjogU2FtcGxpbmcNCg0KVG8gc2FtcGxlIG9uZSBlZmZlY3Qgc2l6ZSBwZXIgc3R1ZHkgd2Ugd2lsbCB3cml0ZSBhIGN1c3RvbSBmdW5jdGlvbiB0aGF0LCBmb3IgZWFjaCBzaW11bGF0aW9uOiAoaSkgcmFuZG9tbHkgc2VsZWN0cyBvbmUgZWZmZWN0IHNpemUgcGVyIHN0dWR5IHRvIGdlbmVyYXRlIGEgbWV0YS1hbmFseXRpYyBkYXRhc2V0OyAoaWkpIGZpdHMgdGhlIHB1YmxpY2F0aW9uIGJpYXMgdGVzdCBvZiBpbnRlcmVzdDsgYW5kIChpaWkpIGV4dHJhY3RzIGVzdGltYXRlcyBmcm9tIHRoZSBwdWJsaWNhdGlvbiBiaWFzIHRlc3Qgb3V0cHV0LiBUaGlzIHByb2Nlc3Mgd2lsbCBiZSByZXBlYXRlZCAxMDAwIHRpbWVzIChpLmUuIDEwMDAgc2FtcGxpbmdzKS4NCg0KPGJyLz48YnIvPg0KDQojIyMjIyBTNS4xLjIuMTogVHJpbS1hbmQtZmlsbCB0ZXN0DQoNCkZvciBhbiBpbnRyb2R1Y3Rpb24gdG8gdGhlIHRyaW0tYW5kLWZpbGwgbWV0aG9kIHNlZSBzZWN0aW9uIFM1LjEuMS4xIGFuZCB0aGUgbWFpbiB0ZXh0LiBCZWxvdyBhcmUgdGhlIHN1bW1hcnkgcmVzdWx0cyBvZiB0aGUgdHJpbS1hbmQtZmlsbCBtZXRob2QgYWZ0ZXIgcnVubmluZyAxMDAwIHJhbmRvbWl6YXRpb25zLg0KDQpgYGB7cn0NCiMgZnVuY3Rpb24gZm9yIHJhbmRvbWx5IHNlbGVjdGluZyAxIGVmZmVjdCBzaXplIGZyb20gZWFjaCBzdHVkeQ0KZnVuY19TNS4xLjIuMSA8LSBmdW5jdGlvbihzaW0gPSAxKXsNCiAgDQogICMgc3BsaXR0aW5nIGRhdGFmcmFtZSBpbnRvIGVhY2ggc3R1ZHkNCiAgc3R1ZHlfbGlzdCA8LSBzcGxpdChkYXRhc2V0LnIsIGRhdGFzZXQuciRzdHVkeSkNCiAgDQogICMgcmFuZG9tbHkgZXh0cmFjdGluZyBvbmUgZWZmZWN0IHNpemUgcGVyIHN0dWR5DQogIFNpbmdsZVN0dWR5RVNfZGF0YXNldC5yIDwtIGRwbHlyOjpiaW5kX3Jvd3MobGFwcGx5KHN0dWR5X2xpc3QsIGZ1bmN0aW9uKHgpIA0KICAgIHhbc2FtcGxlKDE6bnJvdyh4KSwgMSksYygic3R1ZHkiLCJ5aSIsInZpIildKSkNCiAgDQogICMgcnVubmluZyB0aGUgbW9kZWwgb24gdGhlIGRhdGFmcmFtZSBub3cgZWFjaCBzdHVkeSBvbmx5IGhhcyBhIHNpbmdsZSBlZmZlY3Qgc2l6ZQ0KICBtb2RlbC50bXAuciA8LSBybWEoeWksIHZpLCB0ZXN0PSJrbmhhIixkYXRhPVNpbmdsZVN0dWR5RVNfZGF0YXNldC5yKSANCiAgDQogICMgYXBwbHlpbmcgdHJpbS1hbmQtZmlsbCBtZXRob2QNCiAgVEFGIDwtIHRyaW1maWxsKG1vZGVsLnRtcC5yKQ0KIA0KICAjIGNyZWF0aW5nIGEgZGF0YWZyYW1lIHdpdGggcmVzdWx0cyBmcm9tIHRoZSB0cmltLWFuZC1maWxsIG1ldGhvZHMsIHdpdGg6DQogICNuID0gbnVtYmVyIG9mIG1pc3Npbmcgc3R1ZGllcw0KICAjYmV0YSA9IGFkanVzdGVkIG92ZXJhbGwgZWZmZWN0DQogIGRmIDwtIGRhdGEuZnJhbWUoc2ltLA0KICAgICAgICAgICAgICAgICAgIG49VEFGJGswLA0KICAgICAgICAgICAgICAgICAgIGJldGE9VEFGJGJldGFbWzFdXSkNCiAgDQogIHJldHVybihkZikNCn0NCg0KIyBhcHBseWluZyB0aGUgZnVuY3Rpb24gMTAwMCB0aW1lcw0KI3RyaW1maWxsLnNhbXBsaW5nLnIgPC0gZHBseXI6OmJpbmRfcm93cyhsYXBwbHkoMToxMDAwLCBmdW5jdGlvbih4KSBmdW5jX1M1LjEuMi4xKHgpKSkNCiMgc2F2aW5nIGRhdGEgdG8gc2F2ZSB0aW1lIA0KIyBzYXZlKHRyaW1maWxsLnNhbXBsaW5nLnIsZmlsZSA9IGhlcmUoImRhdGEiLCJ0cmltZmlsbF9zYW1wbGluZ19yXzEwMDBzLlJEYXRhIikpDQoNCiMgbG9hZGluZyB0aGUgc2F2ZWQgZGF0YQ0KbG9hZChoZXJlKCJkYXRhIiwidHJpbWZpbGxfc2FtcGxpbmdfcl8xMDAwcy5SRGF0YSIpKQ0KYGBgDQoNClRoZSBtZWRpYW4gbnVtYmVyIG9mIG1pc3Npbmcgc3R1ZGllcyB3YXMgYHIgbWVkaWFuKHRyaW1maWxsLnNhbXBsaW5nLnIkbilgIChyYW5nZSA9IGByIG1pbih0cmltZmlsbC5zYW1wbGluZy5yJG4pYCAtIGByIG1heCh0cmltZmlsbC5zYW1wbGluZy5yJG4pYDsgRmlndXJlIFM1LjRBKSwgd2hpY2ggaXMgc2VlbWluZ2x5IGxvd2VyIHRoYW4gdGhlIG51bWJlciBvZiBtaXNzaW5nIHN0dWRpZXMgZXN0aW1hdGVkIHVzaW5nIHRoZSBhZ2dyZWdhdGVkIGRhdGEgKG4gPSBgciB0cmltZmlsbC5yJGswYDsgbW9yZSBpbiBzZWN0aW9uIFM1LjEuMS4xKS4gQWRkaXRpb25hbGx5LCB0aGUgbWVkaWFuIGFkanVzdGVkIG92ZXJhbGwgZWZmZWN0IGFjY29yZGluZyB0byB0aGUgdHJpbS1hbmQtZmlsbCBtZXRob2Qgd2FzIGByIHJvdW5kKG1lZGlhbih0cmltZmlsbC5zYW1wbGluZy5yJGJldGEpLDIpYCAocmFuZ2UgPSBgciByb3VuZChtaW4odHJpbWZpbGwuc2FtcGxpbmcuciRiZXRhKSwyKWAgLSBgciByb3VuZChtYXgodHJpbWZpbGwuc2FtcGxpbmcuciRiZXRhKSwyKWA7IEZpZ3VyZSBTNS40QiksIHdoaWNoIGlzIHZlcnkgc2ltaWxhciB0byB0aGUgYWRqdXN0ZWQgb3ZlcmFsbCBlZmZlY3QgZXN0aW1hdGVkIHVzaW5nIHRoZSBhZ2dyZWdhdGVkIGRhdGEgKGByIHJvdW5kKHRyaW1maWxsLnIkYltbMV1dLDIpYDsgbW9yZSBpbiBzZWN0aW9uIFM1LjEuMS4xKSwgYnV0IHN0aWxsIGxvd2VyIHRoYW4gdGhlIGFkanVzdGVkIG92ZXJhbGwgZWZmZWN0IGVzdGltYXRlZCBieSBvdXIgc3VnZ2VzdGVkIG11bHRpbGV2ZWwgbWV0YS1yZWdyZXNzaW9uIG1ldGhvZCAoYHIgcm91bmQoZXN0aW1hdGVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuci52LjFbMSwyXSwyKWAsIDk1JSBDSSA9IFtgciByb3VuZChlc3RpbWF0ZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5yLnYuMVsxLDNdLDIpYCxgciByb3VuZChlc3RpbWF0ZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5yLnYuMVsxLDRdLDIpYF07IG1vcmUgaW4gc2VjdGlvbiBTNC4xLjQuMykuDQoNCjxici8+PGJyLz4NCg0KIyMjIyMgRmlndXJlIFM1LjQNCg0KYGBge3IgZmlnLmFsaWduID0gImNlbnRlciIsIGZpZy5jYXA9IkRpc3RyaWJ1dGlvbiBvZiAxMDAwIChBKSBlc3RpbWF0ZWQgbnVtYmVyIG9mIG1pc3Npbmcgc3R1ZGllcyBhY2NvcmRpbmcgdG8gdGhlIHRyaW0tYW5kLWZpbGwgbWV0aG9kLCBhbmQgKEIpIGFkanVzdGVkIG92ZXJhbGwgZWZmZWN0IHNpemVzIGFjY29yZGluZyB0byB0aGUgdHJpbS1hbmQtZmlsbCBtZXRob2QuIFRoZSBkYXNoZWQgbGluZSBzaG93cyB0aGUgbWVkaWFuIHZhbHVlLiJ9DQojIHBsb3R0aW5nIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIG51bWJlciBvZiBtaXNzaW5nIHN0dWRpZXMgYWNjb3JkaW5nIHRvIHRoZSB0cmltLWFuZC1maWxsIG1ldGhvZA0Kbi5yIDwtIGdncGxvdChkYXRhPXRyaW1maWxsLnNhbXBsaW5nLnIsYWVzKHg9bikpICsNCiAgZ2VvbV9kZW5zaXR5KGFscGhhPS41LGZpbGw9ImRhcmtvcmNoaWQ0IikgKw0KICBnZW9tX3ZsaW5lKGRhdGE9dHJpbWZpbGwuc2FtcGxpbmcuciwgYWVzKHhpbnRlcmNlcHQ9bWVkaWFuKG4pKSwNCiAgICAgICAgICAgICBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKQ0KDQojIHBsb3R0aW5nIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIGFkanVzdGVkIG92ZXJhbGwgZWZmZWN0IGFjY29yZGluZyB0byB0aGUgdHJpbS1hbmQtZmlsbCBtZXRob2QNCmJldGFzLnIgPC0gZ2dwbG90KGRhdGE9dHJpbWZpbGwuc2FtcGxpbmcucixhZXMoeD1iZXRhKSkgKw0KICBnZW9tX2RlbnNpdHkoYWxwaGE9LjUsZmlsbD0iZGFya29yY2hpZDQiKSArDQogIGdlb21fdmxpbmUoZGF0YT10cmltZmlsbC5zYW1wbGluZy5yLCBhZXMoeGludGVyY2VwdD1tZWRpYW4oYmV0YSkpLA0KICAgICAgICAgICAgIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpDQoNCmdnYXJyYW5nZShuLnIsIGJldGFzLnIsIA0KICAgICAgICAgIGxhYmVscyA9IGMoIkEiLCAiQiIpLA0KICAgICAgICAgIG5jb2wgPSAyLCBucm93ID0gMSkNCmBgYA0KDQo8YnIvPjxici8+DQoNCiMjIyMjIFM1LjEuMi4yOiBTZWxlY3Rpb24gbW9kZWwgKDMgUFNNKQ0KDQpGb3IgYW4gaW50cm9kdWN0aW9uIHRvIHNlbGVjdGlvbiBtb2RlbHMgc2VlIHNlY3Rpb24gUzUuMS4xLjIgYW5kIHRoZSBtYWluIHRleHQuIEFzIGJlZm9yZSwgd2Ugd2lsbCBydW4gYSBzdGVwIGZ1bmN0aW9uIHNlbGVjdGlvbiBtb2RlbCBiYXNlZCBvbiBvbmUgY3V0LXBvaW50ICgkXGFscGhhID0gMC4wNSQpOyB0aGlzIG1vZGVsIGlzIHNvbWV0aW1lcyByZWZlcnJlZCB0byBhcyBhIDMgcGFyYW1ldGVyIHNlbGVjdGlvbiBtb2RlbC4gRm9yIHNpbXBsaWNpdHksIHdlIHdpbGwgb25seSBydW4gdGhlIHNlbGVjdGlvbiBtb2RlbCBmb3IgdGhlIGludGVyY2VwdC1vbmx5IG1vZGVsIChidXQgc2VlIHNlY3Rpb24gUzUuMS4xLjIgZm9yIGhvdyB0byBydW4gYSBzZWxlY3Rpb24gbW9kZWwgZm9yIGEgbWV0YS1yZWdyZXNzaW9uKS4gQmVsb3cgYXJlIHRoZSBzdW1tYXJ5IHJlc3VsdHMgb2YgdGhlIDMgcGFyYW1ldGVyIHNlbGVjdGlvbiBtb2RlbCBhZnRlciBydW5uaW5nIDEwMDAgcmFuZG9taXphdGlvbnMuDQoNCmBgYHtyfQ0KZnVuY19TNS4xLjIuMiA8LSBmdW5jdGlvbihzaW0gPSAxKXsNCiAgDQogICMgc3BsaXR0aW5nIGRhdGFmcmFtZSBpbnRvIGVhY2ggc3R1ZHkNCiAgc3R1ZHlfbGlzdCA8LSBzcGxpdChkYXRhc2V0LnIsIGRhdGFzZXQuciRzdHVkeSkNCiAgDQogICMgcmFuZG9tbHkgZXh0cmFjdGluZyBvbmUgZWZmZWN0IHNpemUgcGVyIHN0dWR5DQogIFNpbmdsZVN0dWR5RVNfZGF0YXNldC5yIDwtIGRwbHlyOjpiaW5kX3Jvd3MobGFwcGx5KHN0dWR5X2xpc3QsIGZ1bmN0aW9uKHgpIA0KICAgIHhbc2FtcGxlKDE6bnJvdyh4KSwgMSksYygic3R1ZHkiLCJ5aSIsInZpIildKSkNCiAgDQogICMgcnVubmluZyB0aGUgbW9kZWwgb24gdGhlIGRhdGFmcmFtZSBub3cgZWFjaCBzdHVkeSBvbmx5IGhhcyBhIHNpbmdsZSBlZmZlY3Qgc2l6ZQ0KICBtb2RlbC50bXAuci5hZ2cwIDwtIHJtYSh5aSwgdmksIG1ldGhvZD0iTUwiLCB0ZXN0PSJrbmhhIixkYXRhPVNpbmdsZVN0dWR5RVNfZGF0YXNldC5yKQ0KICANCiAgI2V4dHJhY3RpbmcgdGhlIGFkanVzdGVkIG92ZXJhbGwgZWZmZWN0IGFjY29yZGluZyB0byB0aGUgc2VsZWN0aW9uIG1vZGVsIGZvciBlYWNoIGRhdGFiYXNlDQogIHRocmVlUFNNLnZlY3Rvci5yIDwtIHNlbG1vZGVsKG1vZGVsLnRtcC5yLmFnZzAsIHR5cGU9InN0ZXBmdW4iLCBzdGVwcz1jKDAuMDUpKSRiZXRhW1sxXV0NCiAgDQogICNjcmVhdGluZyBhIGRhdGFmcmFtZSB3aXRoIHRoZSBuLnJhbmRvbWl6YXRpb24uciBvZiBlc3RpbWF0ZWQgbnVtYmVyIG9mIG1pc3Npbmcgc3R1ZGllcyBhbmQgYWRqdXN0ZWQgb3ZlcmFsbCBlZmZlY3RzDQogIGRmIDwtIGRhdGEuZnJhbWUoc2ltLCBiZXRhPXRocmVlUFNNLnZlY3Rvci5yKQ0KDQogIHJldHVybihkZikNCn0NCg0KIyBhcHBseWluZyB0aGUgZnVuY3Rpb24gMTAwMCB0aW1lcw0KI3RocmVlUFNNLnNhbXBsaW5nLnIgPC0gZHBseXI6OmJpbmRfcm93cyhsYXBwbHkoMToxMDAwLCBmdW5jdGlvbih4KSBmdW5jX1M1LjEuMi4yKHgpKSkNCiMgc2F2ZSh0aHJlZVBTTS5zYW1wbGluZy5yLGZpbGUgPSBoZXJlKCJkYXRhIiwiM1BTTV9zYW1wbGluZ19yXzEwMDBzLlJEYXRhIikpDQoNCiMgbG9hZGluZyB0aGUgZGF0YSBleHRyYWN0ZWQgZnJvbSB0aGUgMTAwMCBpdGVyYXRpb25zIGFib3ZlDQpsb2FkKGhlcmUoImRhdGEiLCIzUFNNX3NhbXBsaW5nX3JfMTAwMHMuUkRhdGEiKSkNCmBgYA0KDQpUaGUgbWVkaWFuIGFkanVzdGVkIG92ZXJhbGwgZWZmZWN0IGFjY29yZGluZyB0byB0aGUgMyBwYXJhbWV0ZXIgc2VsZWN0aW9uIG1vZGVsIHdhcyBgciByb3VuZChtZWRpYW4odGhyZWVQU00uc2FtcGxpbmcuciRiZXRhKSwyKWAgKHJhbmdlID0gYHIgcm91bmQobWluKHRocmVlUFNNLnNhbXBsaW5nLnIkYmV0YSksMilgIC0gYHIgcm91bmQobWF4KHRocmVlUFNNLnNhbXBsaW5nLnIkYmV0YSksMilgOyBGaWd1cmUgUzUuNEIpLCB3aGljaCBpcyBzaW1pbGFyIHRvIHRoZSBhZGp1c3RlZCBvdmVyYWxsIGVmZmVjdCBlc3RpbWF0ZWQgdXNpbmcgdGhlIGFnZ3JlZ2F0ZWQgZGF0YSAoYHIgcm91bmQodGhyZWUuUFNNLnIwJGJldGFbWzFdXSwyKWA7IDk1JSBDSSA9IFtgciByb3VuZCh0aHJlZS5QU00ucjAkY2kubGJbWzFdXSwyKWAsYHIgcm91bmQodGhyZWUuUFNNLnIwJGNpLnViW1sxXV0sMilgXTsgbW9yZSBpbiBzZWN0aW9uIFM1LjEuMS4yKSBhbmQgdG8gdGhlIGFkanVzdGVkIG92ZXJhbGwgZWZmZWN0IGVzdGltYXRlZCBieSBvdXIgc3VnZ2VzdGVkIG11bHRpbGV2ZWwgbWV0YS1yZWdlc3Npb24gbWV0aG9kIChgciByb3VuZChlc3RpbWF0ZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5yLnYuMVsxLDJdLDIpYCwgOTUlIENJID0gW2ByIHJvdW5kKGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnIudi4xWzEsM10sMilgLGByIHJvdW5kKGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnIudi4xWzEsNF0sMilgXTsgbW9yZSBpbiBzZWN0aW9uIFM0LjEuNC4zKS4NCg0KPGJyLz48YnIvPg0KDQojIyMjIyBGaWd1cmUgUzUuNQ0KDQpgYGB7ciBmaWcuYWxpZ24gPSAiY2VudGVyIiwgZmlnLmNhcD0iRGlzdHJpYnV0aW9uIG9mIDEwMDAgYWRqdXN0ZWQgb3ZlcmFsbCBlZmZlY3Qgc2l6ZXMgYWNjb3JkaW5nIHRvIHRoZSAzIHBhcmFtZXRlciBzZWxlY3Rpb24gbW9kZWwuIFRoZSBkYXNoZWQgbGluZSBzaG93cyB0aGUgbWVkaWFuIHZhbHVlLiJ9DQojIHBsb3R0aW5nIHRoZSBkaXN0cmlidXRpb24gb2YgYWRqdXN0ZWQgb3ZlcmFsbCBlZmZlY3Qgc2l6ZXMgYWNjb3JkaW5nIHRvIHRoZSAzIHBhcmFtZXRlciBzZWxlY3Rpb24gbW9kZWwNCmdncGxvdChkYXRhPXRocmVlUFNNLnNhbXBsaW5nLnIsYWVzKHg9YmV0YSkpICsNCiAgZ2VvbV9kZW5zaXR5KGFscGhhPS41LGZpbGw9ImRhcmtvcmNoaWQ0IikgKw0KICBnZW9tX3ZsaW5lKGRhdGE9dGhyZWVQU00uc2FtcGxpbmcuciwgYWVzKHhpbnRlcmNlcHQ9bWVkaWFuKGJldGEpKSwNCiAgICAgICAgICAgICBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKQ0KYGBgDQoNCjxici8+PGJyLz4NCg0KIyMjIyMgUzUuMS4yLjM6IEN1bXVsYXRpdmUgbWV0YS1hbmFseXNpcw0KDQpGb3IgYW4gaW50cm9kdWN0aW9uIHRvIGN1bXVsYXRpdmUgbWV0YS1hbmFseXNpcyBzZWUgc2VjdGlvbiBTNS4xLjEuMyBhbmQgdGhlIG1haW4gdGV4dC4gSGVyZSwgd2Ugd2lsbCBwZXJmb3JtIGEgc2FtcGxpbmcgcHJvY2VkdXJlIHdoZXJlIHdlIHJ1biBhIGN1bXVsYXRpdmUgbWV0YS1hbmFseXNpcyB0ZXN0IGZvciBlYWNoIGRhdGFzZXQgYW5kIGV4dHJhY3QgdGhlIG1lYW4gZWZmZWN0cyBlc3RpbWF0ZWQgYnkgdGhlIGN1bXVsYXRpdmUgbWV0YS1hbmFseXNpcy4gV2Ugd2lsbCB0aGVuIHBsb3QgdGhlIG1lZGlhbiBhbmQgOTUlIHF1YW50aWxlcyBvZiB0aG9zZSBtZWFuIGVmZmVjdHMgYXQgZWFjaCBzdGVwLiBBcyBiZWZvcmUsIHRoZSBmb3Jlc3QgcGxvdCBkb2VzIG5vdCBzaG93IGFueSBjbGVhciBldmlkZW5jZSBvZiBkZWNsaW5lIGVmZmVjdHMgaW4gdGhpcyBkYXRhc2V0IChGaWd1cmUgUzUuNikuDQoNCmBgYHtyIGZpZy5hbGlnbiA9ICJjZW50ZXIifQ0KZnVuY19TNS4xLjIuMyA8LSBmdW5jdGlvbihzaW0gPSAxKXsNCiAgIyBhcnJhbmdpbmcgYnkgc3R1ZHkgeWVhcg0KICBkYXRfb3JkZXJlZCA8LSBkYXRhc2V0LnJbb3JkZXIoZGF0YXNldC5yJHllYXIpLGMoInN0dWR5IiwieWkiLCJ2aSIsInllYXIiKV0NCiAgDQogICMgc3BsaXR0aW5nIGRhdGFmcmFtZSBpbnRvIGVhY2ggc3R1ZHkNCiAgc3R1ZHlfbGlzdCA8LSBzcGxpdChkYXRfb3JkZXJlZCwgZGF0X29yZGVyZWQkc3R1ZHkpDQogIA0KICAjIHJhbmRvbWx5IGV4dHJhY3Rpbmcgb25lIGVmZmVjdCBzaXplIHBlciBzdHVkeQ0KICBTaW5nbGVTdHVkeUVTX2RhdGFzZXQuciA8LSBkcGx5cjo6YmluZF9yb3dzKGxhcHBseShzdHVkeV9saXN0LCBmdW5jdGlvbih4KSANCiAgICB4W3NhbXBsZSgxOm5yb3coeCksIDEpLF0pKQ0KICANCiAgIyBydW5uaW5nIE1BDQogICBtb2RlbC50bXAuciA8LSBybWEoeWksIHZpLCB0ZXN0PSJrbmhhIixkYXRhPVNpbmdsZVN0dWR5RVNfZGF0YXNldC5yKSANCiAgIA0KICAgIyBjdW11bGF0aXZlIG1ldGEtYW5hbHlzaXMNCiAgIENNQSA8LSBjdW11bChtb2RlbC50bXAucixvcmRlcj1vcmRlcihTaW5nbGVTdHVkeUVTX2RhdGFzZXQuciR5ZWFyKSkNCiAgIA0KICAgIyBkYXRhZnJhbWUgd2l0aCBtZXRhLWFuYWx5dGljIG1lYW4NCiAgICBkZiA8LSBkYXRhLmZyYW1lKHNpbSwgYmV0YSA9IENNQSRlc3RpbWF0ZSkNCiAgcmV0dXJuKGRmKQ0KfQ0KDQojIGFwcGx5aW5nIHRoZSBmdW5jdGlvbiAxMDAwIHRpbWVzDQojdGhyZWVQU00uc2FtcGxpbmcuciA8LSBkcGx5cjo6YmluZF9yb3dzKGxhcHBseSgxOjEwMDAsIGZ1bmN0aW9uKHgpIGZ1bmNfUzUuMS4yLjMoeCkpKQ0KIyBzYXZlKHRocmVlUFNNLnNhbXBsaW5nLnIsZmlsZSA9IGhlcmUoImRhdGEiLCIzUFNNX3NhbXBsaW5nX3JfMTAwMHMuUkRhdGEiKSkNCg0KIyBsb2FkaW5nIHRoZSBzYXZlZCBkYXRhDQpsb2FkKGhlcmUoImRhdGEiLCJjdW11bF9zYW1wbGluZ19yXzEwMDBzLlJEYXRhIikpDQpgYGANCg0KIyMjIyMgRmlndXJlIFM1LjYNCg0KYGBge3IgZmlnLmFsaWduID0gImNlbnRlciIsIGZpZy5jYXA9Ik1lZGlhbiBhbmQgOTUlIHF1YW50aWxlcyBvZiAxMDAwIGVmZmVjdCBzaXplcyBlc3RpbWF0ZWQgYWNjb3JkaW5nIHRvIGN1bXVsYXRpdmUgbWV0YS1hbmFseXNpcyBzaG93aW5nIG5vIGV2aWRlbmNlIG9mIGRlY2xpbmUgZWZmZWN0cy4ifQ0KY3VtdWwuc2FtcGxpbmcuci5zdW1tYXJpemVkIDwtIGFzLmRhdGEuZnJhbWUoY3VtdWwuc2FtcGxpbmcuciANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICU+JSBncm91cF9ieShvcmRlcikgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdW1tYXJpc2UobWVkaWFuID0gbWVkaWFuKGJldGEpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvd0NJID0gcXVhbnRpbGUoYmV0YSxwcm9icyA9IGMoMC4wMjUpKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoaUNJID0gcXVhbnRpbGUoYmV0YSxwcm9icyA9IGMoMC45NzUpKSkpDQoNCg0KIyByZXZlcnNlcyB0aGUgZmFjdG9yIGxldmVsIG9yZGVyaW5nIGZvciBsYWJlbHMgYWZ0ZXIgY29vcmRfZmxpcCgpDQpjdW11bC5zYW1wbGluZy5yLnN1bW1hcml6ZWQkb3JkZXIgPC0gZmFjdG9yKGN1bXVsLnNhbXBsaW5nLnIuc3VtbWFyaXplZCRvcmRlciwgbGV2ZWxzPXJldihjdW11bC5zYW1wbGluZy5yLnN1bW1hcml6ZWQkb3JkZXIpKQ0KDQpnZ3Bsb3QoZGF0YT1jdW11bC5zYW1wbGluZy5yLnN1bW1hcml6ZWQsIGFlcyh4PW9yZGVyLCB5PW1lZGlhbiwgeW1pbj1sb3dDSSwgeW1heD1oaUNJKSkgKw0KICBnZW9tX3BvaW50cmFuZ2UoKSArIA0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MCwgbHR5PTIpICsgICMgYWRkIGEgZG90dGVkIGxpbmUgYXQgeD0xIGFmdGVyIGZsaXANCiAgY29vcmRfZmxpcCgpICsgICMgZmxpcCBjb29yZGluYXRlcyAocHV0cyBsYWJlbHMgb24geSBheGlzKQ0KICB4bGFiKCJPcmRlciBvZiBwdWJsaWNhdGlvbiIpICsgeWxhYigiTWVhbiAoOTUlIENJKSIpICsNCiAgdGhlbWVfYncoKSANCmBgYA0KDQo8YnIvPjxici8+DQoNCiMjIyBTNS4yOiBBdmVyYWdpbmcgYW5kIHNhbXBsaW5nOiBtZWFuIGRpZmZlcmVuY2VzIGJldHdlZW4gdHdvIGdyb3VwcyAobG5SUiBhbmQgU01EKQ0KDQojIyMjIFM1LjIuMTogQXZlcmFnaW5nDQoNCmBgYHtyfQ0KIyByaG8gPSAwLjUgaXMgYXMgaW4gTm9ibGUgZXQgYWwgKE1vbCBFY29sKQ0KZGF0YXNldC5yciA8LSBlc2NhbGMoeWk9eWksIHZpPXZpLCBkYXRhPWRhdGFzZXQucnIpDQpkYXRhc2V0LnJyLmFnZyA8LSBhZ2dyZWdhdGUoZGF0YXNldC5yciwgY2x1c3Rlcj1wYXBlcklELCBzdHJ1Y3Q9IkNTIiwgcmhvID0gMC41KQ0KDQpkYXRhc2V0LnNtZCA8LSBlc2NhbGMoeWk9eWksIHZpPXZpLCBkYXRhPWRhdGFzZXQuc21kKQ0KZGF0YXNldC5zbWQuYWdnIDwtIGFnZ3JlZ2F0ZShkYXRhc2V0LnNtZCwgY2x1c3Rlcj1wYXBlcklELCBzdHJ1Y3Q9IkNTIiwgcmhvID0gMC41KQ0KYGBgDQoNCiMjIyMjIFM1LjIuMS4xOiBUcmltIGFuZCBmaWxsIHRlc3QNCg0KVXNpbmcgdGhlIGFnZ3JlZ2F0ZWQgZGF0YSAoc2VlIEVxdWF0aW9uIDMwIGluIG1haW4gdGV4dCksIHdlIHdpbGwgdGhlbiBmaXQgdGhlIHRyaW0tYW5kLWZpbGwgbWV0aG9kIChEdXZhbCBhbmQgVHdlZWRpZSAyMDAwYSxiKS4gVGhlIHRyaW0tYW5kLWZpbGwgbWV0aG9kIGlzIGEgbm9uLXBhcmFtZXRyaWMgbWV0aG9kIHRoYXQgY2FuIGJlIHVzZWQgdG8gYm90aCBkZXRlY3QgYW5kIGNvcnJlY3QgZm9yIHB1YmxpY2F0aW9uIGJpYXMgYW5kLCBhbHRob3VnaCBpdCBjYW4gaGFuZGxlIHNvbWUgaGV0ZXJvZ2VuZWl0eSwgaXQgcGVyZm9ybXMgd29yc2UgYXMgaGV0ZXJvZ2VuZWl0eSBpbmNyZWFzZXMgKFBldGVycyBldCBhbC4sIDIwMDc7IE1vcmVubyBldCBhbC4sIDIwMDk7IG1vcmUgaW4gdGhlIG1haW4gdGV4dCkuIFdlIHdpbGwgYXBwbHkgdGhlIHRyaW0tYW5kLWZpbGwgbWV0aG9kIHRvIG1ldGEtYW5hbHl0aWMgbW9kZWxzIHdpdGggbm8gcmFuZG9tIGVmZmVjdHMgKHNpbmNlIHdlIGFnZ3JlZ2F0ZWQgb3VyIGRhdGEgd2Ugbm8gbG9uZ2VyIG5lZWQgdG8gZml0IGEgbXVsdGlsZXZlbCBtb2RlbCB0byBhY2NvdW50IGZvciBub24taW5kZXBlbmRlbnQgZWZmZWN0IHNpemVzKS4NCg0KYGBge3J9DQojIGxuUlINCm1ldGEuYW5hbHlzaXMubW9kZWwucnIuYWdnIDwtIHJtYSh5aSwgdmksIHRlc3Q9ImtuaGEiLCAjIHVzaW5nIHQgZGlzdCByYXRoZXIgdGhhbiB6DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1kYXRhc2V0LnJyLmFnZykNCnRyaW1maWxsLnJyIDwtIHRyaW1maWxsKG1ldGEuYW5hbHlzaXMubW9kZWwucnIuYWdnKQ0KDQojU01EDQptZXRhLmFuYWx5c2lzLm1vZGVsLnNtZC5hZ2cgPC0gcm1hKHlpLCB2aSwgdGVzdD0ia25oYSIsICMgdXNpbmcgdCBkaXN0IHJhdGhlciB0aGFuIHoNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1kYXRhc2V0LnNtZC5hZ2cpDQp0cmltZmlsbC5zbWQgPC0gdHJpbWZpbGwobWV0YS5hbmFseXNpcy5tb2RlbC5zbWQuYWdnKQ0KYGBgDQoNClRoZSB0cmltLWFuZC1maWxsIG1ldGhvZCBpZGVudGlmaWVkIGByIHRyaW1maWxsLnJyJGswYCAoU0UgPSBgciByb3VuZCh0cmltZmlsbC5yciRzZS5rMCwyKWApIG1pc3Npbmcgc3R1ZGllcyAoRmlndXJlIFM1LjcpIGFuZCBlc3RpbWF0ZWQgYW4gYWRqdXN0ZWQgb3ZlcmFsbCBlZmZlY3Qgb2YgYHIgcm91bmQodHJpbWZpbGwucnIkYmV0YVtbMV1dLDIpYCAoOTUlIENJID0gW2ByIHJvdW5kKHRyaW1maWxsLnJyJGNpLmxiW1sxXV0sMilgLGByIHJvdW5kKHRyaW1maWxsLnJyJGNpLnViW1sxXV0sMilgXSkuDQoNCjxici8+PGJyLz4NCg0KIyMjIyMgRmlndXJlIFM1LjcNCg0KYGBge3IgZmlnLmFsaWduID0gImNlbnRlciIsIGZpZy5jYXA9IkZ1bm5lbCBwbG90IHVzaW5nIHByZWNpc2lvbiAoMS9TRSkgYXMgYSBtZWFzdXJlIG9mIHVuY2VydGFpbnR5IGFuZCBzaG93aW5nIHRoZSBhZGp1c3RlZCBtZXRhLWFuYWx5dGljIG1lYW4gKHZlcnRpY2FsIGxpbmUpIGFuZCB0aGUgIG1pc3NpbmcgZWZmZWN0IHNpemVzICh3aGl0ZSBwb2ludHMpIGFjY29yZGluZyB0byB0aGUgdHJpbS1hbmQtZmlsbCBtZXRob2QuIn0NCnBhcihtZnJvdyA9IGMoMSwyKSkNCmZ1bm5lbCh0cmltZmlsbC5yciwgeWF4aXM9InNlaW52IiwNCiAgICAgICB5bGFiID0gIlByZWNpc2lvbiAoMS9TRSkiLA0KICAgICAgIHhsYWIgPSAiRWZmZWN0IHNpemUgKGxuUlIpIikgDQpmdW5uZWwodHJpbWZpbGwuc21kLCB5YXhpcz0ic2VpbnYiLA0KICAgICAgIHlsYWIgPSAiUHJlY2lzaW9uICgxL1NFKSIsDQogICAgICAgeGxhYiA9ICJFZmZlY3Qgc2l6ZSAoU01EKSIpIA0KYGBgDQoNClVzaW5nIHRoZSBhZ2dyZWdhdGVkIGRhdGEgKHNlZSBhYm92ZSksIHdlIHdpbGwgYWxzbyBmaXQgYSBzZWxlY3Rpb24gbW9kZWwtYmFzZWQgbWV0aG9kIChyZXZpZXdlZCBieSBNYXJrcy1BbmdsaW4gJiBDaGVuLCAyMDIwKS4gQWx0aG91Z2ggdGhlcmUgYXJlIG1hbnkgc2VsZWN0aW9uIG1vZGVscywgYWxsIG9mIHRoZW0gbW9kZWwgaG93IGVmZmVjdCBzaXplcyBhcmUgbWlzc2luZyBiYXNlZCBvbiBwIHZhbHVlcywgZWZmZWN0IHNpemVzIGFuZC9vciBzYW1wbGluZyB2YXJpYW5jZSwgYW5kIGNhbiBwcm92aWRlIGFuIGFkanVzdGVkIG92ZXJhbGwgZWZmZWN0IChlLmcuIFJvZGdlcnMgJiBQdXN0ZWpvdnNreSwgMjAyMDsgbW9yZSBpbiB0aGUgbWFpbiB0ZXh0KS4gQ29udHJhcnkgdG8gb3RoZXIgbWV0aG9kcywgc2VsZWN0aW9uIG1vZGVscyBjYW4gZGVhbCB3aXRoIGFuZCBtb2RlbCBoZXRlcm9nZW5laXR5IChlLmcuIENpdGtvd2ljeiBhbmQgVmV2ZWEgMjAxNyksIGJ1dCBjYW5ub3QgZGVhbCB3aXRoIG5vbi1pbmRlcGVuZGVudCBlZmZlY3Qgc2l6ZXMuIFdlIHdpbGwgcnVuIGEgc3RlcCBmdW5jdGlvbiBzZWxlY3Rpb24gbW9kZWwgYmFzZWQgb24gb25lIGN1dC1wb2ludCAoJFxhbHBoYSA9IDAuMDUkKTsgdGhpcyBtb2RlbCBpcyBzb21ldGltZXMgcmVmZXJyZWQgdG8gYXMgYSAzIHBhcmFtZXRlciBzZWxlY3Rpb24gbW9kZWwgKDNQTTsgbW9yZSBpbiB0aGUgbWFpbiB0ZXh0OyBSb2RnZXJzICYgUHVzdGVqb3Zza3ksIDIwMjApLg0KDQojIyMjIyBTNS4yLjEuMjogU2VsZWN0aW9uIG1vZGVsICgzIFBTTSkNCg0KYGBge3J9DQojIGxuUlINCiMgd2l0aG91dCBtb2RlcmF0b3JzDQoNCiMgbW9kZXJhdG9yDQptZXRhLnJlZ3Jlc3Npb24ucnIuYWdnMCA8LSBybWEoeWksIHZpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2Q9Ik1MIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXN0PSJrbmhhIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1kYXRhc2V0LnJyKQ0KDQoNCnRocmVlLlBTTS5ycjAgPC0gc2VsbW9kZWwobWV0YS5yZWdyZXNzaW9uLnJyLmFnZzAsIHR5cGU9InN0ZXBmdW4iLCBzdGVwcz1jKDAuMDUsIDEpKQ0KDQojc3VtbWFyeSh0aHJlZS5QU00ucnIwKQ0KDQoNCiMgd2l0aCBtb2RlcmF0b3INCm1ldGEucmVncmVzc2lvbi5yci5hZ2cgPC0gcm1hKHlpLCB2aSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2QgPSB+IHllYXIuYyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICsgRXhwZXJpbWVudGFsLm9yLk9ic2VydmF0aW9uYWwuIC0gMSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2Q9Ik1MIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlc3Q9ImtuaGEiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE9ZGF0YXNldC5ycikNCg0KDQp0aHJlZS5QU00ucnIgPC0gc2VsbW9kZWwobWV0YS5yZWdyZXNzaW9uLnJyLmFnZywgdHlwZT0ic3RlcGZ1biIsIHN0ZXBzPWMoMC4wNSwgMSkpDQoNCg0KDQojIyBTTUQNCg0KIyB3aXRob3V0IG1vZGVyYXRvcnMNCm1ldGEucmVncmVzc2lvbi5zbWQuYWdnMCA8LSBybWEoeWksIHZpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kPSJNTCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlc3Q9ImtuaGEiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1kYXRhc2V0LnNtZCkNCg0KDQp0aHJlZS5QU00uc21kMCA8LSBzZWxtb2RlbChtZXRhLnJlZ3Jlc3Npb24uc21kLmFnZzAsIHR5cGU9InN0ZXBmdW4iLCBzdGVwcz1jKDAuMDUsIDEpKQ0KDQoNCiMgd2l0aCBtb2RlcmF0b3JzDQptZXRhLnJlZ3Jlc3Npb24uc21kLmFnZyA8LSBybWEoeWksIHZpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2QgPSB+IHllYXIuYyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICArIEV4cGVyaW1lbnRhbC5vci5PYnNlcnZhdGlvbmFsLiAtIDEsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZD0iTUwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlc3Q9ImtuaGEiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhPWRhdGFzZXQuc21kKQ0KDQoNCnRocmVlLlBTTS5zbWQgPC0gc2VsbW9kZWwobWV0YS5yZWdyZXNzaW9uLnNtZC5hZ2csIHR5cGU9InN0ZXBmdW4iLCBzdGVwcz1jKDAuMDUsIDEpKQ0KDQoNCiMgZXh0cmFjdGluZyB0aGUgbWVhbiBhbmQgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzDQplc3RpbWF0ZXMudGhyZWUuUFNNLnJyIDwtIGVzdGltYXRlcy5DSSh0aHJlZS5QU00ucnIpDQplc3RpbWF0ZXMudGhyZWUuUFNNLnNtZCA8LSBlc3RpbWF0ZXMuQ0kodGhyZWUuUFNNLnNtZCkNCmBgYA0KDQpUaGUgc3RlcCBmdW5jdGlvbiBzZWxlY3Rpb24gbW9kZWwgYmFzZWQgb24gb25lIGN1dC1wb2ludCAoJFxhbHBoYSA9IDAuMDUkKSBmb3IgdGhlIGludGVyY2VwdC1vbmx5IG1vZGVsIGVzdGltYXRlZCBhbiBhZGp1c3RlZCBvdmVyYWxsIGxuUlIgb2YgYHIgcm91bmQodGhyZWUuUFNNLnJyMCRiZXRhW1sxXV0sMilgICg5NSUgQ0kgPSBbYHIgcm91bmQodGhyZWUuUFNNLnJyMCRjaS5sYltbMV1dLDIpYCxgciByb3VuZCh0aHJlZS5QU00ucnIwJGNpLnViW1sxXV0sMilgXTsgRmlndXJlIFM1LjgpLCB3aGljaCBpcyBzbWFsbGVyIHRoYW4gdGhlIG9yaWdpbmFsIG92ZXJhbGwgZWZmZWN0IGVzdGltYXRlZCBieSB0aGUgbWV0YS1hbmFseXRpYyBtb2RlbCAoYHIgcm91bmQobWV0YWFuYWx5dGljLm1lYW4ubW9kZWwucltbMV1dLDIpYCwgOTUlIENJID0gW2ByIHJvdW5kKG1ldGFhbmFseXRpYy5tZWFuLm1vZGVsLnJbWzNdXSwyKWAsYHIgcm91bmQobWV0YWFuYWx5dGljLm1lYW4ubW9kZWwucltbNF1dLDIpYF07IG1vcmUgaW4gc2VjdGlvbiBTNC4yLjMuMykuIFNNRCBzaG93ZWQgdGhlIHNhbWUgcGF0dGVybi4gT3ZlcmFsbCwgdGhlIHNlbGVjdGlvbiBtb2RlbCBlc3RpbWF0ZWQgYWRqdXN0ZWQgb3ZlcmFsbCBlZmZlY3RzIHRoYXQgd2VyZSBlaXRoZXIgdmVyeSBzaW1pbGFyIG9yIGV2ZW4gc2xpZ2h0bHkgbGFyZ2VyIHRoYW4gdGhlIG9yaWdpbmFsIHVuYWRqdXN0ZWQgZWZmZWN0IHNpemVzIChUYWJsZSBTNS4yKSwgd2hpY2ggbWlnaHQgaW5kaWNhdGUgdGhhdCB0aGUgc3BlY2lmaWMgc2VsZWN0aW9uIG1vZGVsIHRoYXQgd2UgdXNlZCAoaS5lLiBvbmUgY3V0LXBvaW50IG9mICRcYWxwaGEgPSAwLjA1JCkgd2FzIG5vdCBhbiBhZGVxdWF0ZSBhcHByb3hpbWF0aW9uIGZvciB0aGUgdW5kZXJseWluZyBzZWxlY3Rpb24gcHJvY2Vzcy4NCg0KPGJyLz48YnIvPg0KDQojIyMjIyBGaWd1cmUgUzUuOA0KDQpSZXN1bHRzIG9mIGEgc3RlcCBmdW5jdGlvbiBzZWxlY3Rpb24gbW9kZWwgYmFzZWQgb24gb25lIGN1dC1wb2ludCAoJFxhbHBoYSA9IDAuMDUkKSBmb3IgYSBtb2RlbCB3aXRob3V0IGFueSBtb2RlcmF0b3JzIChsZWZ0LWhhbmQgZmlndXJlLCB0b3AgcGFuZWwgZm9yIGxuUlIsIGJvdHRvbSBmb3IgU01EKSBhbmQgYSBtb2RlbCBpbmNsdWRpbmcgYm90aCAneWVhciBvZiBwdWJsaWNhdGlvbicgYW5kICdFeHBlcmltZW50YWwub3IuT2JzZXJ2YXRpb25hbC4nIGFzIG1vZGVyYXRvcnMgKHJpZ2h0LWhhbmQgZmlndXJlLCB0b3AgcGFuZWwgZm9yIGxuUlIsIGJvdHRvbSBmb3IgU01EKS4NCg0KYGBge3IgZmlnLmFsaWduID0gImNlbnRlciJ9DQpwYXIobWZyb3cgPSBjKDEsIDIpKQ0KcGxvdCh0aHJlZS5QU00ucnIwLCBjb2w9InJlZCIsIGx0eSA9IDMpDQpwbG90KHRocmVlLlBTTS5yciwgY29sPSJyZWQiLCBsdHkgPSAzKQ0KYGBgDQoNCjxici8+PGJyLz4NCg0KYGBge3IgZmlnLmFsaWduID0gImNlbnRlciJ9DQpwYXIobWZyb3cgPSBjKDEsIDIpKQ0KcGxvdCh0aHJlZS5QU00uc21kMCwgY29sPSJyZWQiLCBsdHkgPSAzKQ0KcGxvdCh0aHJlZS5QU00uc21kLCBjb2w9InJlZCIsIGx0eSA9IDMpDQpgYGANCg0KPGJyLz48YnIvPg0KDQpgYGB7cn0NCiMgY3JlYXRpbmcgYSB0YWJsZSB0byBzaG93IHRoZSByZXN1bHRzIG9mIHRoZSBzZWxlY3Rpb24gbW9kZWwNCnRhYmxlLmNvbXBhcmluZy5FeHAub3IuT2JzLmxldmVscy4zUFNNIDwtIG1lcmdlKGVzdGltYXRlcy50aHJlZS5QU00ucnJbYygyOjMpLF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLnYuMWIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5PSJlc3RpbWF0ZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsbC54PVQpDQojIHJvdW5kaW5nIGVzdGltYXRlcw0KdGFibGUuY29tcGFyaW5nLkV4cC5vci5PYnMubGV2ZWxzLjNQU00gPC0gdGFibGUuY29tcGFyaW5nLkV4cC5vci5PYnMubGV2ZWxzLjNQU00gJT4lIG11dGF0ZV9hdCh2YXJzKG1lYW4ueCwgbG93ZXIueCx1cHBlci54LG1lYW4ueSxsb3dlci55LHVwcGVyLnkpLCBsaXN0KH5yb3VuZCguLCAyKSkpDQoNCnRhYmxlLmNvbXBhcmluZy5FeHAub3IuT2JzLmxldmVscy4zUFNNIDwtIGRhdGEuZnJhbWUoRXhwLm9yLk9icy5sZXZlbCA9IHRhYmxlLmNvbXBhcmluZy5FeHAub3IuT2JzLmxldmVscy4zUFNNWywxXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZGp1c3RlZC5tZWFuPXRhYmxlLmNvbXBhcmluZy5FeHAub3IuT2JzLmxldmVscy4zUFNNWywyXSwgICAgICAgICAgICAgICBhZGp1c3RlZC5DST1wYXN0ZTAoIlsiLHRhYmxlLmNvbXBhcmluZy5FeHAub3IuT2JzLmxldmVscy4zUFNNWywzXSwiLCIsdGFibGUuY29tcGFyaW5nLkV4cC5vci5PYnMubGV2ZWxzLjNQU01bLDRdLCJdIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5hZGp1c3RlZC5tZWFuPXRhYmxlLmNvbXBhcmluZy5FeHAub3IuT2JzLmxldmVscy4zUFNNWyw1XSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuYWRqdXN0ZWQuQ0k9cGFzdGUwKCJbIix0YWJsZS5jb21wYXJpbmcuRXhwLm9yLk9icy5sZXZlbHMuM1BTTVssNl0sIiwiLHRhYmxlLmNvbXBhcmluZy5FeHAub3IuT2JzLmxldmVscy4zUFNNWyw3XSwiXSIpKQ0KdGFibGUuY29tcGFyaW5nLkV4cC5vci5PYnMubGV2ZWxzLjNQU01bLDFdIDwtIGMoIkV4cGVyaW1lbnRhbCIsIk9ic2VydmF0aW9uYWwiKQ0KIyBjcmVhdGluZyBhIGZvcm1hdHRlZCB0YWJsZSB1c2luZyB0aGUgUiBwYWNrYWdlICdndCcNCnRhYmxlLm1vZGVsLnJyLkV4cC5vci5PYnMuZ3QuM1BTTSA8LSB0YWJsZS5jb21wYXJpbmcuRXhwLm9yLk9icy5sZXZlbHMuM1BTTSAlPiUgDQogIGd0KCkgJT4lIA0KICBjb2xzX2xhYmVsKEV4cC5vci5PYnMubGV2ZWw9bWQoIioqRXhwZXJpbWVudGFsLm9yLk9ic2VydmF0aW9uYWwuKioiKSwNCiAgICAgICAgICAgICBhZGp1c3RlZC5tZWFuPW1kKCIqKkFkanVzdGVkIG1lYW4qKiIpLA0KICAgICAgICAgICAgIGFkanVzdGVkLkNJPW1kKCIqKkFkanVzdGVkIDk1JSBDSSoqIiksDQogICAgICAgICAgICAgdW5hZGp1c3RlZC5tZWFuPW1kKCIqKlVuYWRqdXN0ZWQgbWVhbioqIiksDQogICAgICAgICAgICAgdW5hZGp1c3RlZC5DST1tZCgiKipVbmFkanVzdGVkIDk1JSBDSSoqIikpICU+JQ0KICBjb2xzX2FsaWduKGFsaWduID0gImNlbnRlciIpDQp0YWJsZS5tb2RlbC5yci5FeHAub3IuT2JzLmd0LjNQU00gDQpgYGANCg0KKipUYWJsZSBTNS4yLioqIEFkanVzdGVkIGFuZCB1bmFkanVzdGVkIGZvciBwdWJsaWNhdGlvbiBiaWFzIHJlc3VsdHMgZm9yIGFsbCBsZXZlbHMgb2YgdGhlIG1vZGVyYXRvciAnRXhwZXJpbWVudGFsLm9yLk9ic2VydmF0aW9uYWwuJyB1c2luZyBhIHN0ZXAgZnVuY3Rpb24gc2VsZWN0aW9uIG1vZGVsIGJhc2VkIG9uIG9uZSBjdXQtcG9pbnQgKCRcYWxwaGEgPSAwLjA1JCkuIEVzdGltYXRlcyBhcmUgcHJlc2VudGVkIGFzIHN0YW5kYXJkaXplZCBlZmZlY3Qgc2l6ZXMgdXNpbmcgbG5SUi4NCg0KPGJyLz48YnIvPg0KDQpgYGB7cn0NCiMgY3JlYXRpbmcgYSB0YWJsZSB0byBzaG93IHRoZSByZXN1bHRzIG9mIHRoZSBzZWxlY3Rpb24gbW9kZWwNCnRhYmxlLmNvbXBhcmluZy5FeHAub3IuT2JzLmxldmVscy4zUFNNIDwtIG1lcmdlKGVzdGltYXRlcy50aHJlZS5QU00uc21kW2MoMjozKSxdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlc3RpbWF0ZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5zbWQudi4xYiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnk9ImVzdGltYXRlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxsLng9VCkNCiMgcm91bmRpbmcgZXN0aW1hdGVzDQp0YWJsZS5jb21wYXJpbmcuRXhwLm9yLk9icy5sZXZlbHMuM1BTTSA8LSB0YWJsZS5jb21wYXJpbmcuRXhwLm9yLk9icy5sZXZlbHMuM1BTTSAlPiUgbXV0YXRlX2F0KHZhcnMobWVhbi54LCBsb3dlci54LHVwcGVyLngsbWVhbi55LGxvd2VyLnksdXBwZXIueSksIGxpc3QofnJvdW5kKC4sIDIpKSkNCg0KdGFibGUuY29tcGFyaW5nLkV4cC5vci5PYnMubGV2ZWxzLjNQU00gPC0gZGF0YS5mcmFtZShFeHAub3IuT2JzLmxldmVsID0gdGFibGUuY29tcGFyaW5nLkV4cC5vci5PYnMubGV2ZWxzLjNQU01bLDFdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFkanVzdGVkLm1lYW49dGFibGUuY29tcGFyaW5nLkV4cC5vci5PYnMubGV2ZWxzLjNQU01bLDJdLCAgICAgICAgICAgICAgIGFkanVzdGVkLkNJPXBhc3RlMCgiWyIsdGFibGUuY29tcGFyaW5nLkV4cC5vci5PYnMubGV2ZWxzLjNQU01bLDNdLCIsIix0YWJsZS5jb21wYXJpbmcuRXhwLm9yLk9icy5sZXZlbHMuM1BTTVssNF0sIl0iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmFkanVzdGVkLm1lYW49dGFibGUuY29tcGFyaW5nLkV4cC5vci5PYnMubGV2ZWxzLjNQU01bLDVdLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5hZGp1c3RlZC5DST1wYXN0ZTAoIlsiLHRhYmxlLmNvbXBhcmluZy5FeHAub3IuT2JzLmxldmVscy4zUFNNWyw2XSwiLCIsdGFibGUuY29tcGFyaW5nLkV4cC5vci5PYnMubGV2ZWxzLjNQU01bLDddLCJdIikpDQp0YWJsZS5jb21wYXJpbmcuRXhwLm9yLk9icy5sZXZlbHMuM1BTTVssMV0gPC0gYygiRXhwZXJpbWVudGFsIiwiT2JzZXJ2YXRpb25hbCIpDQojIGNyZWF0aW5nIGEgZm9ybWF0dGVkIHRhYmxlIHVzaW5nIHRoZSBSIHBhY2thZ2UgJ2d0Jw0KdGFibGUubW9kZWwuc21kLkV4cC5vci5PYnMuZ3QuM1BTTSA8LSB0YWJsZS5jb21wYXJpbmcuRXhwLm9yLk9icy5sZXZlbHMuM1BTTSAlPiUgDQogIGd0KCkgJT4lIA0KICBjb2xzX2xhYmVsKEV4cC5vci5PYnMubGV2ZWw9bWQoIioqRXhwZXJpbWVudGFsLm9yLk9ic2VydmF0aW9uYWwuKioiKSwNCiAgICAgICAgICAgICBhZGp1c3RlZC5tZWFuPW1kKCIqKkFkanVzdGVkIG1lYW4qKiIpLA0KICAgICAgICAgICAgIGFkanVzdGVkLkNJPW1kKCIqKkFkanVzdGVkIDk1JSBDSSoqIiksDQogICAgICAgICAgICAgdW5hZGp1c3RlZC5tZWFuPW1kKCIqKlVuYWRqdXN0ZWQgbWVhbioqIiksDQogICAgICAgICAgICAgdW5hZGp1c3RlZC5DST1tZCgiKipVbmFkanVzdGVkIDk1JSBDSSoqIikpICU+JQ0KICBjb2xzX2FsaWduKGFsaWduID0gImNlbnRlciIpDQp0YWJsZS5tb2RlbC5zbWQuRXhwLm9yLk9icy5ndC4zUFNNDQpgYGANCg0KKipUYWJsZSBTNS4zLioqIEFkanVzdGVkIGFuZCB1bmFkanVzdGVkIGZvciBwdWJsaWNhdGlvbiBiaWFzIHJlc3VsdHMgZm9yIGFsbCBsZXZlbHMgb2YgdGhlIG1vZGVyYXRvciAnRXhwZXJpbWVudGFsLm9yLk9ic2VydmF0aW9uYWwuJyB1c2luZyBhIHN0ZXAgZnVuY3Rpb24gc2VsZWN0aW9uIG1vZGVsIGJhc2VkIG9uIG9uZSBjdXQtcG9pbnQgKCRcYWxwaGEgPSAwLjA1JCkuIEVzdGltYXRlcyBhcmUgcHJlc2VudGVkIGFzIHN0YW5kYXJkaXplZCBlZmZlY3Qgc2l6ZXMgdXNpbmcgU01ELg0KDQo8YnIvPjxici8+DQoNCiMjIyMjIFM1LjIuMS4zOiBDdW1sYXRpdmUgbWV0YS1hbmFseXNpcw0KDQpMYXN0LCB1c2luZyB0aGUgYWdncmVnYXRlZCBkYXRhIChzZWUgYWJvdmUpLCB3ZSB3aWxsIGFsc28gcGVyZm9ybSBhIGN1bXVsYXRpdmUgbWV0YS1hbmFseXNpcyB1c2luZyB0aGUgZnVuY3Rpb24gYGN1bXVsKClgIGZyb20gdGhlIFIgcGFja2FnZSBgbWV0YWZvcmAgKFZpZWNodGJhdWVyIDIwMTApLiBCeSBkaXNwbGF5aW5nIHRoZSByZXN1bHRzIG9mIHRoaXMgY3VtdWxhdGl2ZSBtZXRhLWFuYWx5c2lzIGFzIGEgZm9yZXN0IHBsb3QsIHdlIGNhbiBzZWUgaWYgdGhlcmUgaXMgZXZpZGVuY2Ugb2YgZGVjbGluZSBlZmZlY3RzIChtb3JlIGluIHRoZSB0ZXh0KSwgd2hpY2ggd2UgZG8gbm90IHNlZW0gdG8gaGF2ZSBmb3IgbG5SUiAoRmlndXJlIFM1LjksIGxlZnQtaGFuZCkgYW5kIFNNRCAoRmlndXJlIFM1LjEwLCBsZWZ0LWhhbmQpLg0KDQo8YnIvPjxici8+DQoNCmBgYHtyLCBmaWcuaGVpZ2h0PSA4LCBmaWcud2lkdGg9IDd9DQojIGxuUlINCmN1bS5tZXRhLmFuYWx5c2lzLm1vZGVsLnJyLmFnZyA8LSBjdW11bChtZXRhLmFuYWx5c2lzLm1vZGVsLnJyLmFnZykNCg0KIyBTTUQNCmN1bS5tZXRhLmFuYWx5c2lzLm1vZGVsLnNtZC5hZ2cgPC0gY3VtdWwobWV0YS5hbmFseXNpcy5tb2RlbC5zbWQuYWdnKQ0KDQpwYXIobWZyb3cgPSBjKDEsIDIpKQ0KZm9yZXN0KGN1bS5tZXRhLmFuYWx5c2lzLm1vZGVsLnJyLmFnZywgeGxhYiA9ICJPdmVyYWxsIGVzdGltYXRlIChsblJSKSIpDQpmb3Jlc3QoY3VtLm1ldGEuYW5hbHlzaXMubW9kZWwuc21kLmFnZywgeGxhYiA9ICJPdmVyYWxsIGVzdGltYXRlIChTTUQpIikNCmBgYA0KDQo8YnIvPjxici8+DQoNCiMjIyMgUzUuMi4yOiBTYW1wbGluZw0KDQpBcyBpbiBTNS4xLjIsIHdlIHdpbGwgcnVuIHRoZSB0cmltLWFuZC1maWxsIHRlc3Qgb24gMTAwMCBkYXRhc2V0cywgZWFjaCB3aXRoIG9ubHkgMSBlZmZlY3Qgc2l6ZSBwZXIgc3R1ZHkgKHNhbXBsZWQgcmFuZG9tbHkpLg0KDQo8YnIvPjxici8+DQoNCiMjIyMjIFM1LjIuMi4xOiBUcmltIGFuZCBmaWxsIHRlc3QNCg0KRm9yIGFuIGludHJvZHVjdGlvbiB0byB0aGUgdHJpbS1hbmQtZmlsbCBtZXRob2Qgc2VlIHNlY3Rpb24gUzUuMi4xLjEgYW5kIHRoZSBtYWluIHRleHQuIEJlbG93IGFyZSB0aGUgc3VtbWFyeSByZXN1bHRzIG9mIHRoZSB0cmltLWFuZC1maWxsIG1ldGhvZCBhZnRlciBydW5uaW5nIDEwMDAgcmFuZG9taXphdGlvbnMuDQoNCmBgYHtyfQ0KIyBmdW5jdGlvbiBmb3IgcmFuZG9tbHkgc2VsZWN0aW5nIDEgZWZmZWN0IHNpemUgZnJvbSBlYWNoIHN0dWR5DQpmdW5jX1M1LjIuMi4xIDwtIGZ1bmN0aW9uKHNpbSA9IDEsIGRmKXsNCiAgDQogICMgc3BsaXR0aW5nIGRhdGFmcmFtZSBpbnRvIGVhY2ggc3R1ZHkNCiAgc3R1ZHlfbGlzdCA8LSBzcGxpdChkZiwgZGYkcGFwZXJJRCkNCiAgDQogICMgcmFuZG9tbHkgZXh0cmFjdGluZyBvbmUgZWZmZWN0IHNpemUgcGVyIHN0dWR5DQogIFNpbmdsZVN0dWR5RVNfZGYgPC0gZHBseXI6OmJpbmRfcm93cyhsYXBwbHkoc3R1ZHlfbGlzdCwgZnVuY3Rpb24oeCkgDQogICAgeFtzYW1wbGUoMTpucm93KHgpLCAxKSxjKCJwYXBlcklEIiwieWkiLCJ2aSIpXSkpDQogIA0KICAjIHJ1bm5pbmcgdGhlIG1vZGVsIG9uIHRoZSBkYXRhZnJhbWUgbm93IGVhY2ggc3R1ZHkgb25seSBoYXMgYSBzaW5nbGUgZWZmZWN0IHNpemUNCiAgbW9kZWwudG1wIDwtIHJtYSh5aSwgdmksIHRlc3Q9ImtuaGEiLGRhdGE9U2luZ2xlU3R1ZHlFU19kZikgDQogIA0KICAjIGFwcGx5aW5nIHRyaW0tYW5kLWZpbGwgbWV0aG9kDQogIFRBRiA8LSB0cmltZmlsbChtb2RlbC50bXApDQogDQogICMgY3JlYXRpbmcgYSBkYXRhZnJhbWUgd2l0aCByZXN1bHRzIGZyb20gdGhlIHRyaW0tYW5kLWZpbGwgbWV0aG9kcywgd2l0aDoNCiAgI24gPSBudW1iZXIgb2YgbWlzc2luZyBzdHVkaWVzDQogICNiZXRhID0gYWRqdXN0ZWQgb3ZlcmFsbCBlZmZlY3QNCiAgZGYgPC0gZGF0YS5mcmFtZShzaW0sDQogICAgICAgICAgICAgICAgICAgbj1UQUYkazAsDQogICAgICAgICAgICAgICAgICAgYmV0YT1UQUYkYmV0YVtbMV1dKQ0KICANCiAgcmV0dXJuKGRmKQ0KfQ0KDQojIGFwcGx5aW5nIHRoZSBmdW5jdGlvbiAxMDAwIHRpbWVzIGZvciBsblJSDQojdHJpbWZpbGwuc2FtcGxpbmcucnIgPC0gZHBseXI6OmJpbmRfcm93cyhsYXBwbHkoMToxMDAwLCBmdW5jdGlvbih4KSBmdW5jX1M1LjIuMi4xKHNpbSA9IHgsIGRmID0gZGF0YXNldC5ycikpKQ0KIyBzYXZpbmcgZGF0YSB0byBzYXZlIHRpbWUgDQojIHNhdmUodHJpbWZpbGwuc2FtcGxpbmcucnIsZmlsZSA9IGhlcmUoImRhdGEiLCJ0cmltZmlsbF9zYW1wbGluZ19ycl8xMDAwcy5SRGF0YSIpKQ0KbG9hZChoZXJlKCJkYXRhIiwidHJpbWZpbGxfc2FtcGxpbmdfcnJfMTAwMHMuUkRhdGEiKSkNCg0KIyBhcHBseWluZyB0aGUgZnVuY3Rpb24gMTAwMCB0aW1lcyBmb3IgU01SDQojdHJpbWZpbGwuc2FtcGxpbmcuc21kIDwtIGRwbHlyOjpiaW5kX3Jvd3MobGFwcGx5KDE6MTAwMCwgZnVuY3Rpb24oeCkgZnVuY19TNS4yLjIuMShzaW0gPSB4LCBkZiA9IGRhdGFzZXQuc21kKSkpDQojIHNhdmluZyBkYXRhIHRvIHNhdmUgdGltZSANCiMgc2F2ZSh0cmltZmlsbC5zYW1wbGluZy5zbWQsZmlsZSA9IGhlcmUoImRhdGEiLCJ0cmltZmlsbF9zYW1wbGluZ19zbWRfMTAwMHMuUkRhdGEiKSkNCmxvYWQoaGVyZSgiZGF0YSIsInRyaW1maWxsX3NhbXBsaW5nX3NtZF8xMDAwcy5SRGF0YSIpKQ0KYGBgDQoNClRoZSBtZWRpYW4gbnVtYmVyIG9mIG1pc3Npbmcgc3R1ZGllcyBmb3IgbG5SUiB3YXMgYHIgbWVkaWFuKHRyaW1maWxsLnNhbXBsaW5nLnJyJG4pYCAocmFuZ2UgPSBgciBtaW4odHJpbWZpbGwuc2FtcGxpbmcucnIkbilgIC0gYHIgbWF4KHRyaW1maWxsLnNhbXBsaW5nLnJyJG4pYDsgRmlndXJlIFM1LjlBKS4gQWRkaXRpb25hbGx5LCB0aGUgbWVkaWFuIGFkanVzdGVkIG92ZXJhbGwgbG5SUiBhY2NvcmRpbmcgdG8gdGhlIHRyaW0tYW5kLWZpbGwgbWV0aG9kIHdhcyBgciByb3VuZChtZWRpYW4odHJpbWZpbGwuc2FtcGxpbmcucnIkYmV0YSksMilgIChyYW5nZSA9IGByIHJvdW5kKG1pbih0cmltZmlsbC5zYW1wbGluZy5yciRiZXRhKSwyKWAgLSBgciByb3VuZChtYXgodHJpbWZpbGwuc2FtcGxpbmcucnIkYmV0YSksMilgOyBGaWd1cmUgUzUuOUIpLCB3aGljaCBpcyBsYXJnZXIgdGhhbiB0aGUgYWRqdXN0ZWQgb3ZlcmFsbCBsblJSIGVzdGltYXRlZCBieSBvdXIgc3VnZ2VzdGVkIG11bHRpbGV2ZWwgbWV0YS1yZWdlc3Npb24gbWV0aG9kIChgciByb3VuZChlc3RpbWF0ZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5yci52LjFbMSwyXSwyKWAsIDk1JSBDSSA9IFtgciByb3VuZChlc3RpbWF0ZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5yci52LjFbMSwzXSwyKWAsYHIgcm91bmQoZXN0aW1hdGVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwucnIudi4xWzEsNF0sMilgXTsgbW9yZSBpbiBzZWN0aW9uIFM0LjIuNC4zKS4NCg0KPGJyLz48YnIvPg0KDQojIyMjIyBGaWd1cmUgUzUuOQ0KDQpgYGB7ciBmaWcuYWxpZ24gPSAiY2VudGVyIiwgZmlnLmNhcD0iRGlzdHJpYnV0aW9uIG9mIGByIG4ucmFuZG9taXphdGlvbi5yci5UQUZgIChBKSBlc3RpbWF0ZWQgbnVtYmVyIG9mIG1pc3Npbmcgc3R1ZGllcyBhY2NvcmRpbmcgdG8gdGhlIHRyaW0tYW5kLWZpbGwgbWV0aG9kLCBhbmQgKEIpIGFkanVzdGVkIG92ZXJhbGwgbG5SUiBhY2NvcmRpbmcgdG8gdGhlIHRyaW0tYW5kLWZpbGwgbWV0aG9kLiBUaGUgZGFzaGVkIGxpbmUgc2hvd3MgdGhlIG1lZGlhbiB2YWx1ZS4ifQ0KIyBwbG90dGluZyB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBudW1iZXIgb2YgbWlzc2luZyBzdHVkaWVzIGFjY29yZGluZyB0byB0aGUgdHJpbS1hbmQtZmlsbCBtZXRob2QNCm4ucnIgPC0gZ2dwbG90KGRhdGE9dHJpbWZpbGwuc2FtcGxpbmcucnIsYWVzKHg9bikpICsNCiAgZ2VvbV9kZW5zaXR5KGFscGhhPS41LGZpbGw9ImRhcmtvcmNoaWQ0IikgKw0KICBnZW9tX3ZsaW5lKGRhdGE9dHJpbWZpbGwuc2FtcGxpbmcucnIsIGFlcyh4aW50ZXJjZXB0PW1lZGlhbihuKSksDQogICAgICAgICAgICAgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkNCiMgcGxvdHRpbmcgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgYWRqdXN0ZWQgb3ZlcmFsbCBlZmZlY3QgYWNjb3JkaW5nIHRvIHRoZSB0cmltLWFuZC1maWxsIG1ldGhvZA0KYmV0YXMucnIgPC0gZ2dwbG90KGRhdGE9dHJpbWZpbGwuc2FtcGxpbmcucnIsYWVzKHg9YmV0YSkpICsNCiAgZ2VvbV9kZW5zaXR5KGFscGhhPS41LGZpbGw9ImRhcmtvcmNoaWQ0IikgKw0KICBnZW9tX3ZsaW5lKGRhdGE9dHJpbWZpbGwuc2FtcGxpbmcucnIsIGFlcyh4aW50ZXJjZXB0PW1lZGlhbihiZXRhKSksDQogICAgICAgICAgICAgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkNCmdnYXJyYW5nZShuLnJyLCBiZXRhcy5yciwgDQogICAgICAgICAgbGFiZWxzID0gYygiQSIsICJCIiksDQogICAgICAgICAgbmNvbCA9IDIsIG5yb3cgPSAxKQ0KYGBgDQoNCjxici8+PGJyLz4NCg0KVGhlIG1lZGlhbiBudW1iZXIgb2YgbWlzc2luZyBzdHVkaWVzIGZvciBTTUQgd2FzIGByIG1lZGlhbih0cmltZmlsbC5zYW1wbGluZy5zbWQkbilgIChyYW5nZSA9IGByIG1pbih0cmltZmlsbC5zYW1wbGluZy5zbWQkbilgIC0gYHIgbWF4KHRyaW1maWxsLnNhbXBsaW5nLnNtZCRuKWA7IEZpZ3VyZSBTNS4xMEEpLiBBZGRpdGlvbmFsbHksIHRoZSBtZWRpYW4gYWRqdXN0ZWQgb3ZlcmFsbCBTTUQgYWNjb3JkaW5nIHRvIHRoZSB0cmltLWFuZC1maWxsIG1ldGhvZCB3YXMgYHIgcm91bmQobWVkaWFuKHRyaW1maWxsLnNhbXBsaW5nLnNtZCRiZXRhKSwyKWAgKHJhbmdlID0gYHIgcm91bmQobWluKHRyaW1maWxsLnNhbXBsaW5nLnNtZCRiZXRhKSwyKWAgLSBgciByb3VuZChtYXgodHJpbWZpbGwuc2FtcGxpbmcuc21kJGJldGEpLDIpYDsgRmlndXJlIFM1LjEwQiksIHdoaWNoIGlzIGxhcmdlciB0aGFuIHRoZSBhZGp1c3RlZCBvdmVyYWxsIFNNRCBlc3RpbWF0ZWQgYnkgb3VyIHN1Z2dlc3RlZCBtdWx0aWxldmVsIG1ldGEtcmVncmVzc2lvbiBtZXRob2QgKGByIHJvdW5kKGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC52LjFbMSwyXSwyKWAsIDk1JSBDSSA9IFtgciByb3VuZChlc3RpbWF0ZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5zbWQudi4xWzEsM10sMilgLGByIHJvdW5kKGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC52LjFbMSw0XSwyKWBdOyBtb3JlIGluIHNlY3Rpb24gUzQuMi40LjMpLg0KDQo8YnIvPjxici8+DQoNCiMjIyMjIEZpZ3VyZSBTNS4xMA0KDQpgYGB7ciBmaWcuYWxpZ24gPSAiY2VudGVyIiwgZmlnLmNhcD0iRGlzdHJpYnV0aW9uIG9mIGByIG4ucmFuZG9taXphdGlvbi5zbWQuVEFGYCAoQSkgZXN0aW1hdGVkIG51bWJlciBvZiBtaXNzaW5nIHN0dWRpZXMgYWNjb3JkaW5nIHRvIHRoZSB0cmltLWFuZC1maWxsIG1ldGhvZCwgYW5kIChCKSBhZGp1c3RlZCBvdmVyYWxsIFNNRCBhY2NvcmRpbmcgdG8gdGhlIHRyaW0tYW5kLWZpbGwgbWV0aG9kLiBUaGUgZGFzaGVkIGxpbmUgc2hvd3MgdGhlIG1lZGlhbiB2YWx1ZS4ifQ0KIyBwbG90dGluZyB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBudW1iZXIgb2YgbWlzc2luZyBzdHVkaWVzIGFjY29yZGluZyB0byB0aGUgdHJpbS1hbmQtZmlsbCBtZXRob2QNCm4uc21kIDwtIGdncGxvdChkYXRhPXRyaW1maWxsLnNhbXBsaW5nLnNtZCxhZXMoeD1uKSkgKw0KICBnZW9tX2RlbnNpdHkoYWxwaGE9LjUsZmlsbD0iZGFya29yY2hpZDQiKSArDQogIGdlb21fdmxpbmUoZGF0YT10cmltZmlsbC5zYW1wbGluZy5zbWQsIGFlcyh4aW50ZXJjZXB0PW1lZGlhbihuKSksDQogICAgICAgICAgICAgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkNCiMgcGxvdHRpbmcgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgYWRqdXN0ZWQgb3ZlcmFsbCBlZmZlY3QgYWNjb3JkaW5nIHRvIHRoZSB0cmltLWFuZC1maWxsIG1ldGhvZA0KYmV0YXMuc21kIDwtIGdncGxvdChkYXRhPXRyaW1maWxsLnNhbXBsaW5nLnNtZCxhZXMoeD1iZXRhKSkgKw0KICBnZW9tX2RlbnNpdHkoYWxwaGE9LjUsZmlsbD0iZGFya29yY2hpZDQiKSArDQogIGdlb21fdmxpbmUoZGF0YT10cmltZmlsbC5zYW1wbGluZy5zbWQsIGFlcyh4aW50ZXJjZXB0PW1lZGlhbihiZXRhKSksDQogICAgICAgICAgICAgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkNCmdnYXJyYW5nZShuLnNtZCwgYmV0YXMuc21kLCANCiAgICAgICAgICBsYWJlbHMgPSBjKCJBIiwgIkIiKSwNCiAgICAgICAgICBuY29sID0gMiwgbnJvdyA9IDEpDQpgYGANCg0KPGJyLz48YnIvPg0KDQojIyMjIyBTNS4yLjIuMjogU2VsZWN0aW9uIG1vZGVsICgzIFBTTSkNCg0KRm9yIGFuIGludHJvZHVjdGlvbiB0byBzZWxlY3Rpb24gbW9kZWxzIHNlZSBzZWN0aW9uIFM1LjIuMS4yIGFuZCB0aGUgbWFpbiB0ZXh0LiBBcyBiZWZvcmUsIHdlIHJhbiBhIHN0ZXAgZnVuY3Rpb24gc2VsZWN0aW9uIG1vZGVsIGJhc2VkIG9uIG9uZSBjdXQtcG9pbnQgKCRcYWxwaGEgPSAwLjA1JCk7IHRoaXMgbW9kZWwgaXMgc29tZXRpbWVzIHJlZmVycmVkIHRvIGFzIGEgMyBwYXJhbWV0ZXIgc2VsZWN0aW9uIG1vZGVsLiBGb3Igc2ltcGxpY2l0eSwgd2Ugb25seSByYW4gdGhlIHNlbGVjdGlvbiBtb2RlbCBmb3IgdGhlIGludGVyY2VwdC1vbmx5IG1vZGVsIChidXQgc2VlIHNlY3Rpb24gUzUuMi4xLjIgZm9yIGhvdyB0byBydW4gYSBzZWxlY3Rpb24gbW9kZWwgZm9yIGEgbWV0YS1yZWdyZXNzaW9uKS4gQmVsb3cgYXJlIHRoZSBzdW1tYXJ5IHJlc3VsdHMgb2YgdGhlIDMgcGFyYW1ldGVyIHNlbGVjdGlvbiBtb2RlbCBhZnRlciBydW5uaW5nIDEwMDAgcmFuZG9taXphdGlvbnMuDQoNCmBgYHtyfQ0KIyBmdW5jdGlvbiBmb3IgcmFuZG9tbHkgc2VsZWN0aW5nIDEgZWZmZWN0IHNpemUgZnJvbSBlYWNoIHN0dWR5DQpmdW5jX1M1LjIuMi4yIDwtIGZ1bmN0aW9uKHNpbSA9IDEsIGRmKXsNCiAgDQogICMgc3BsaXR0aW5nIGRhdGFmcmFtZSBpbnRvIGVhY2ggc3R1ZHkNCiAgc3R1ZHlfbGlzdCA8LSBzcGxpdChkZiwgZGYkcGFwZXJJRCkNCiAgDQogICMgcmFuZG9tbHkgZXh0cmFjdGluZyBvbmUgZWZmZWN0IHNpemUgcGVyIHN0dWR5DQogIFNpbmdsZVN0dWR5RVNfZGYgPC0gZHBseXI6OmJpbmRfcm93cyhsYXBwbHkoc3R1ZHlfbGlzdCwgZnVuY3Rpb24oeCkgDQogICAgeFtzYW1wbGUoMTpucm93KHgpLCAxKSxjKCJwYXBlcklEIiwieWkiLCJ2aSIpXSkpDQogIA0KICAjIHJ1bm5pbmcgdGhlIG1vZGVsIG9uIHRoZSBkYXRhZnJhbWUgbm93IGVhY2ggc3R1ZHkgb25seSBoYXMgYSBzaW5nbGUgZWZmZWN0IHNpemUNCiAgbW9kZWwudG1wIDwtIHJtYSh5aSwgdmksIG1ldGhvZD0iTUwiLCB0ZXN0PSJrbmhhIixkYXRhPVNpbmdsZVN0dWR5RVNfZGYgKQ0KICANCiAgIyBleHRyYWN0aW5nIHRoZSBhZGp1c3RlZCBvdmVyYWxsIGVmZmVjdCBhY2NvcmRpbmcgdG8gdGhlIHNlbGVjdGlvbiBtb2RlbCANCiAgdGhyZWVQU00udmVjdG9yIDwtIHNlbG1vZGVsKG1vZGVsLnRtcCwgdHlwZT0ic3RlcGZ1biIsIHN0ZXBzPWMoMC4wNSkpJGJldGFbWzFdXQ0KICANCiAgIyBjcmVhdGluZyBhIGRhdGFmcmFtZSB3aXRoIHRoZSBuLnJhbmRvbWl6YXRpb24uciBvZiBlc3RpbWF0ZWQgbnVtYmVyIA0KICAjIG9mIG1pc3Npbmcgc3R1ZGllcyBhbmQgYWRqdXN0ZWQgb3ZlcmFsbCBlZmZlY3RzDQogIHRocmVlUFNNLnNhbXBsaW5nIDwtIGRhdGEuZnJhbWUoc2ltLCBiZXRhPXRocmVlUFNNLnZlY3RvcikNCiAgDQogIHJldHVybih0aHJlZVBTTS5zYW1wbGluZykNCn0NCg0KIyBhcHBseWluZyB0aGUgZnVuY3Rpb24gMTAwMCB0aW1lcyBmb3IgbG5SUg0KI3RocmVlUFNNLnNhbXBsaW5nLnJyIDwtIGRwbHlyOjpiaW5kX3Jvd3MobGFwcGx5KDE6MTAwMCwgZnVuY3Rpb24oeCkgZnVuY19TNS4yLjIuMihzaW0gPSB4LCBkZiA9IGRhdGFzZXQucnIpKSkNCiMgc2F2aW5nIGRhdGEgdG8gc2F2ZSB0aW1lIA0KIyBzYXZlKHRocmVlUFNNLnNhbXBsaW5nLnJyLGZpbGUgPSBoZXJlKCJkYXRhIiwiM1BTTV9zYW1wbGluZ19ycl8xMDAwcy5SRGF0YSIpKQ0KbG9hZChoZXJlKCJkYXRhIiwiM1BTTV9zYW1wbGluZ19ycl8xMDAwcy5SRGF0YSIpKQ0KYGBgDQoNClRoZSBtZWRpYW4gYWRqdXN0ZWQgb3ZlcmFsbCBsblJSIGFjY29yZGluZyB0byB0aGUgMyBwYXJhbWV0ZXIgc2VsZWN0aW9uIG1vZGVsIHdhcyBgciByb3VuZChtZWRpYW4odGhyZWVQU00uc2FtcGxpbmcucnIkYmV0YSksMilgIChyYW5nZSA9IGByIHJvdW5kKG1pbih0aHJlZVBTTS5zYW1wbGluZy5yciRiZXRhKSwyKWAgLSBgciByb3VuZChtYXgodGhyZWVQU00uc2FtcGxpbmcucnIkYmV0YSksMilgOyBGaWd1cmUgUzUuNEIpLCB3aGljaCBpcyBzbWFsbGVyIHRoYW4gdGhlIGFkanVzdGVkIG92ZXJhbGwgbG5SUiBlc3RpbWF0ZWQgYnkgb3VyIHN1Z2dlc3RlZCBtdWx0aWxldmVsIG1ldGEtcmVncmVzc2lvbiBtZXRob2QgKGByIHJvdW5kKGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLnYuMVsxLDJdLDIpYCwgOTUlIENJID0gW2ByIHJvdW5kKGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnJyLnYuMVsxLDNdLDIpYCxgciByb3VuZChlc3RpbWF0ZXMucHVibGljYXRpb24uYmlhcy5tb2RlbC5yci52LjFbMSw0XSwyKWBdOyBtb3JlIGluIHNlY3Rpb24gUzQuMi40LjMpLg0KDQo8YnIvPjxici8+DQoNCiMjIyMjIEZpZ3VyZSBTNS4xMQ0KDQpgYGB7ciBmaWcuYWxpZ24gPSAiY2VudGVyIiwgZmlnLmNhcD0iRGlzdHJpYnV0aW9uIG9mIGByIG4ucmFuZG9taXphdGlvbi5yci4zUFNNYCBhZGp1c3RlZCBvdmVyYWxsIGxuUlIgYWNjb3JkaW5nIHRvIHRoZSAzIHBhcmFtZXRlciBzZWxlY3Rpb24gbW9kZWwuIFRoZSBkYXNoZWQgbGluZSBzaG93cyB0aGUgbWVkaWFuIHZhbHVlLiJ9DQojIHBsb3R0aW5nIHRoZSBkaXN0cmlidXRpb24gb2YgYWRqdXN0ZWQgb3ZlcmFsbCBlZmZlY3Qgc2l6ZXMgYWNjb3JkaW5nIHRvIHRoZSAzIHBhcmFtZXRlciBzZWxlY3Rpb24gbW9kZWwNCmdncGxvdChkYXRhPXRocmVlUFNNLnNhbXBsaW5nLnJyLGFlcyh4PWJldGEpKSArDQogIGdlb21fZGVuc2l0eShhbHBoYT0uNSxmaWxsPSJkYXJrb3JjaGlkNCIpICsNCiAgZ2VvbV92bGluZShkYXRhPXRocmVlUFNNLnNhbXBsaW5nLnJyLCBhZXMoeGludGVyY2VwdD1tZWRpYW4oYmV0YSkpLA0KICAgICAgICAgICAgIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpDQpgYGANCg0KPGJyLz48YnIvPg0KDQpgYGB7cn0NCiMgYXBwbHlpbmcgdGhlIGZ1bmN0aW9uIDEwMDAgdGltZXMgZm9yIFNNRA0KI3RocmVlUFNNLnNhbXBsaW5nLnNtZCA8LSBkcGx5cjo6YmluZF9yb3dzKGxhcHBseSgxOjEwMDAsIGZ1bmN0aW9uKHgpIGZ1bmNfUzUuMi4yLjIoc2ltID0geCwgZGYgPSBkYXRhc2V0LnNtZCkpKQ0KIyBzYXZpbmcgZGF0YSB0byBzYXZlIHRpbWUgDQojIHNhdmUodGhyZWVQU00uc2FtcGxpbmcuc21kLGZpbGUgPSBoZXJlKCJkYXRhIiwiM1BTTV9zYW1wbGluZ19zbWRfMTAwMHMuUkRhdGEiKSkNCmxvYWQoaGVyZSgiZGF0YSIsIjNQU01fc2FtcGxpbmdfc21kXzEwMDBzLlJEYXRhIikpDQpgYGANCg0KVGhlIG1lZGlhbiBhZGp1c3RlZCBvdmVyYWxsIFNNRCBhY2NvcmRpbmcgdG8gdGhlIDMgcGFyYW1ldGVyIHNlbGVjdGlvbiBtb2RlbCB3YXMgYHIgcm91bmQobWVkaWFuKHRocmVlUFNNLnNhbXBsaW5nLnNtZCRiZXRhKSwyKWAgKHJhbmdlID0gYHIgcm91bmQobWluKHRocmVlUFNNLnNhbXBsaW5nLnNtZCRiZXRhKSwyKWAgLSBgciByb3VuZChtYXgodGhyZWVQU00uc2FtcGxpbmcuc21kJGJldGEpLDIpYDsgRmlndXJlIFM1LjRCKSwgd2hpY2ggaXMgc21hbGxlciB0aGFuIHRoZSBhZGp1c3RlZCBvdmVyYWxsIFNNRCBlc3RpbWF0ZWQgYnkgb3VyIHN1Z2dlc3RlZCBtdWx0aWxldmVsIG1ldGEtcmVnZXNzaW9uIG1ldGhvZCAoYHIgcm91bmQoZXN0aW1hdGVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuc21kLnYuMVsxLDJdLDIpYCwgOTUlIENJID0gW2ByIHJvdW5kKGVzdGltYXRlcy5wdWJsaWNhdGlvbi5iaWFzLm1vZGVsLnNtZC52LjFbMSwzXSwyKWAsYHIgcm91bmQoZXN0aW1hdGVzLnB1YmxpY2F0aW9uLmJpYXMubW9kZWwuc21kLnYuMVsxLDRdLDIpYF07IG1vcmUgaW4gc2VjdGlvbiBTNC4yLjQuMykuDQoNCjxici8+PGJyLz4NCg0KIyMjIyMgRmlndXJlIFM1LjEyDQoNCmBgYHtyIGZpZy5hbGlnbiA9ICJjZW50ZXIiLCBmaWcuY2FwPSJEaXN0cmlidXRpb24gb2YgYHIgbi5yYW5kb21pemF0aW9uLnNtZC4zUFNNYCBhZGp1c3RlZCBvdmVyYWxsIFNNRCBhY2NvcmRpbmcgdG8gdGhlIDMgcGFyYW1ldGVyIHNlbGVjdGlvbiBtb2RlbC4gVGhlIGRhc2hlZCBsaW5lIHNob3dzIHRoZSBtZWRpYW4gdmFsdWUuIn0NCiMgcGxvdHRpbmcgdGhlIGRpc3RyaWJ1dGlvbiBvZiBhZGp1c3RlZCBvdmVyYWxsIGVmZmVjdCBzaXplcyBhY2NvcmRpbmcgdG8gdGhlIDMgcGFyYW1ldGVyIHNlbGVjdGlvbiBtb2RlbA0KZ2dwbG90KGRhdGE9dGhyZWVQU00uc2FtcGxpbmcuc21kLGFlcyh4PWJldGEpKSArDQogIGdlb21fZGVuc2l0eShhbHBoYT0uNSxmaWxsPSJkYXJrb3JjaGlkNCIpICsNCiAgZ2VvbV92bGluZShkYXRhPXRocmVlUFNNLnNhbXBsaW5nLnNtZCwgYWVzKHhpbnRlcmNlcHQ9bWVkaWFuKGJldGEpKSwNCiAgICAgICAgICAgICBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKQ0KYGBgDQoNCjxici8+PGJyLz4NCg0KIyMjIyMgUzUuMi4yLjM6IEN1bWxhdGl2ZSBtZXRhLWFuYWx5c2lzDQoNCkZvciBhbiBpbnRyb2R1Y3Rpb24gdG8gY3VtdWxhdGl2ZSBtZXRhLWFuYWx5c2lzIHNlZSBzZWN0aW9uIFM1LjIuMS4zIGFuZCB0aGUgbWFpbiB0ZXh0LiBIZXJlLCB3ZSBwZXJmb3JtZWQgYSBzYW1wbGluZyBwcm9jZWR1cmUgd2hlcmUgd2UgcmFuIGEgY3VtdWxhdGl2ZSBtZXRhLWFuYWx5c2lzIHRlc3QgZm9yIGVhY2ggZGF0YXNldCBhbmQgZXh0cmFjdGVkIHRoZSBtZWFuIGVmZmVjdHMgZXN0aW1hdGVkIGJ5IHRoZSBjdW11bGF0aXZlIG1ldGEtYW5hbHlzaXMuIFdlIHRoZW4gcGxvdHRlZCB0aGUgbWVkaWFuIGFuZCA5NSUgcXVhbnRpbGVzIG9mIHRob3NlIG1lYW4gZWZmZWN0cyBhdCBlYWNoIHN0ZXAuIEFzIGJlZm9yZSwgdGhlIGZvcmVzdCBwbG90IGRvZXMgbm90IHNob3cgYW55IGNsZWFyIGV2aWRlbmNlIG9mIGRlY2xpbmUgZWZmZWN0cyBpbiB0aGlzIGRhdGFzZXQgKEZpZ3VyZSBTNS42KS4NCg0KYGBge3IgZmlnLmFsaWduID0gImNlbnRlciJ9DQpmdW5jX1M1LjIuMi4zIDwtIGZ1bmN0aW9uKHNpbSA9IDEsIGRmID0gZGF0YXNldC5ycil7DQogIA0KICAjIHNwbGl0dGluZyBkYXRhZnJhbWUgaW50byBlYWNoIHN0dWR5DQogIHN0dWR5X2xpc3QgPC0gc3BsaXQoZGYsIGRmJHBhcGVySUQpDQogIA0KICAjIHJhbmRvbWx5IGV4dHJhY3Rpbmcgb25lIGVmZmVjdCBzaXplIHBlciBzdHVkeQ0KICBTaW5nbGVTdHVkeUVTX2RmIDwtIGRwbHlyOjpiaW5kX3Jvd3MobGFwcGx5KHN0dWR5X2xpc3QsIGZ1bmN0aW9uKHgpIA0KICAgIHhbc2FtcGxlKDE6bnJvdyh4KSwgMSksYygicGFwZXJJRCIsInllYXIiLCJ5aSIsInZpIildKSkNCiAgDQogICMgcnVubmluZyB0aGUgbW9kZWwgb24gdGhlIGRhdGFmcmFtZSBub3cgZWFjaCBzdHVkeSBvbmx5IGhhcyBhIHNpbmdsZSBlZmZlY3Qgc2l6ZQ0KICBtb2RlbC50bXAgPC0gcm1hKHlpLCB2aSwgbWV0aG9kPSJNTCIsIHRlc3Q9ImtuaGEiLGRhdGE9U2luZ2xlU3R1ZHlFU19kZikNCiAgDQogICMgb3JkZXIgb2YgeWVhcnMNCiAgeWVhcl9vcmRlciA8LSBvcmRlcihTaW5nbGVTdHVkeUVTX2RmJHllYXIpDQogIA0KICAjY3VtdWxhdGl2ZSBtZXRhLWFuYWx5c2lzDQogIGN1bXVsLm1hIDwtIG1ldGFmb3I6OmN1bXVsKHggPSBtb2RlbC50bXAsIG9yZGVyID0geWVhcl9vcmRlcikNCg0KICAjIGRhdGFmcmFtZSBmb3IgZXhwb3J0DQogIGRmIDwtIGRhdGEuZnJhbWUob3JkZXIgPSAxOmxlbmd0aCh5ZWFyX29yZGVyKSwNCiAgICAgICAgICAgICAgICAgICB5ZWFyID0gU2luZ2xlU3R1ZHlFU19kZiR5ZWFyW3llYXJfb3JkZXJdLA0KICAgICAgICAgICAgICAgICAgIHNpbSwNCiAgICAgICAgICAgICAgICAgICBiZXRhID0gYXMudmVjdG9yKGN1bXVsLm1hJGVzdGltYXRlKSwNCiAgICAgICAgICAgICAgICAgICBsYiA9IGFzLnZlY3RvcihjdW11bC5tYSRjaS5sYiksDQogICAgICAgICAgICAgICAgICAgdWIgPSBhcy52ZWN0b3IoY3VtdWwubWEkY2kudWIpKQ0KICANCiAgcmV0dXJuKGRmKQ0KfQ0KDQojIHJ1bm5pbmcgZnVuY3Rpb24gMTAwMCB0aW1lcw0KIyBAVE8tRE86IGlzIDEwMDAgcmVhbGx5IG5lY2Vzc2FyeSBoZXJlPyBJdCB0YWtlcyBhIHZlcnkgbG9uZyB0aW1lIGFuZCB0aGUgZGF0YWZyYW1lIGlzIGVub3Jtb3VzIChiZWNhdXNlIGl0J3MgMTAwMCB4IGFsbCB0aGUgeWVhcnMpDQojIGN1bXVsLnNhbXBsaW5nLnJyIDwtIGRwbHlyOjpiaW5kX3Jvd3MobGFwcGx5KDE6MTAwMCwgZnVuY3Rpb24oeCkgZnVuY19TNS4yLjIuMyhzaW0gPSB4LCBkZiA9IGRhdGFzZXQucnIpKSkNCiMgc2F2ZShjdW11bC5zYW1wbGluZy5ycixmaWxlID0gaGVyZSgiZGF0YSIsImN1bXVsX3NhbXBsaW5nX3JyXzEwMDBzLlJEYXRhIikpDQojIGN1bXVsLnNhbXBsaW5nLnNtZCA8LSBkcGx5cjo6YmluZF9yb3dzKGxhcHBseSgxOjEwMDAsIGZ1bmN0aW9uKHgpIGZ1bmNfUzUuMi4yLjMoc2ltID0geCwgZGYgPSBkYXRhc2V0LnNtZCkpKQ0KIyBzYXZlKGN1bXVsLnNhbXBsaW5nLnNtZCxmaWxlID0gaGVyZSgiZGF0YSIsImN1bXVsX3NhbXBsaW5nX3NtZF8xMDAwcy5SRGF0YSIpKQ0KDQpsb2FkKGhlcmUoImRhdGEiLCJjdW11bF9zYW1wbGluZ19ycl8xMDAwcy5SRGF0YSIpKQ0KbG9hZChoZXJlKCJkYXRhIiwiY3VtdWxfc2FtcGxpbmdfc21kXzEwMDBzLlJEYXRhIikpDQpgYGANCg0KIyMjIyMgRmlndXJlIFM1LjEzDQoNCmBgYHtyIGZpZy5hbGlnbiA9ICJjZW50ZXIiLCBmaWcuY2FwPSJNZWRpYW4gYW5kIDk1JSBxdWFudGlsZXMgb2YgYHIgbi5yYW5kb21pemF0aW9uLnJyLkNNYCBsblJSIGVzdGltYXRlZCBhY2NvcmRpbmcgdG8gY3VtdWxhdGl2ZSBtZXRhLWFuYWx5c2lzIHNob3dpbmcgZXZpZGVuY2Ugb2YgZGVjbGluZSBlZmZlY3RzLiJ9DQpjdW11bC5zYW1wbGluZy5yci5zdW1tYXJpemVkIDwtIGFzLmRhdGEuZnJhbWUoY3VtdWwuc2FtcGxpbmcucnIgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAlPiUgZ3JvdXBfYnkob3JkZXIpICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VtbWFyaXNlKG1lZGlhbiA9IG1lZGlhbihiZXRhKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dDSSA9IHF1YW50aWxlKGJldGEscHJvYnMgPSBjKDAuMDI1KSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGlDSSA9IHF1YW50aWxlKGJldGEscHJvYnMgPSBjKDAuOTc1KSkpKQ0KIyByZXZlcnNlcyB0aGUgZmFjdG9yIGxldmVsIG9yZGVyaW5nIGZvciBsYWJlbHMgYWZ0ZXIgY29vcmRfZmxpcCgpDQpjdW11bC5zYW1wbGluZy5yci5zdW1tYXJpemVkJG9yZGVyIDwtIGZhY3RvcihjdW11bC5zYW1wbGluZy5yci5zdW1tYXJpemVkJG9yZGVyLCBsZXZlbHM9cmV2KGN1bXVsLnNhbXBsaW5nLnJyLnN1bW1hcml6ZWQkb3JkZXIpKQ0KZ2dwbG90KGRhdGE9Y3VtdWwuc2FtcGxpbmcucnIuc3VtbWFyaXplZCwgYWVzKHg9b3JkZXIsIHk9bWVkaWFuLCB5bWluPWxvd0NJLCB5bWF4PWhpQ0kpKSArDQogIGdlb21fcG9pbnRyYW5nZSgpICsgDQogIGdlb21faGxpbmUoeWludGVyY2VwdD0wLCBsdHk9MikgKyAgIyBhZGQgYSBkb3R0ZWQgbGluZSBhdCB4PTEgYWZ0ZXIgZmxpcA0KICBjb29yZF9mbGlwKCkgKyAgIyBmbGlwIGNvb3JkaW5hdGVzIChwdXRzIGxhYmVscyBvbiB5IGF4aXMpDQogIHhsYWIoIk9yZGVyIG9mIHB1YmxpY2F0aW9uIikgKyB5bGFiKCJPdmVyYWxsIGxuUlIgKDk1JSBDSSkiKSArDQogIHRoZW1lX2J3KCkgDQpgYGANCg0KPGJyLz48YnIvPg0KDQojIyMjIyBGaWd1cmUgUzUuMTMNCg0KYGBge3IgZmlnLmFsaWduID0gImNlbnRlciIsIGZpZy5jYXA9Ik1lZGlhbiBhbmQgOTUlIHF1YW50aWxlcyBvZiBgciBuLnJhbmRvbWl6YXRpb24uc21kLkNNYCBTTUQgZXN0aW1hdGVkIGFjY29yZGluZyB0byBjdW11bGF0aXZlIG1ldGEtYW5hbHlzaXMgc2hvd2luZyBldmlkZW5jZSBvZiBkZWNsaW5lIGVmZmVjdHMuIn0NCmN1bXVsLnNhbXBsaW5nLnNtZC5zdW1tYXJpemVkIDwtIGFzLmRhdGEuZnJhbWUoY3VtdWwuc2FtcGxpbmcuc21kIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJT4lIGdyb3VwX2J5KG9yZGVyKSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZShtZWRpYW4gPSBtZWRpYW4oYmV0YSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG93Q0kgPSBxdWFudGlsZShiZXRhLHByb2JzID0gYygwLjAyNSkpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhpQ0kgPSBxdWFudGlsZShiZXRhLHByb2JzID0gYygwLjk3NSkpKSkNCiMgcmV2ZXJzZXMgdGhlIGZhY3RvciBsZXZlbCBvcmRlcmluZyBmb3IgbGFiZWxzIGFmdGVyIGNvb3JkX2ZsaXAoKQ0KY3VtdWwuc2FtcGxpbmcuc21kLnN1bW1hcml6ZWQkb3JkZXIgPC0gZmFjdG9yKGN1bXVsLnNhbXBsaW5nLnNtZC5zdW1tYXJpemVkJG9yZGVyLCBsZXZlbHM9cmV2KGN1bXVsLnNhbXBsaW5nLnNtZC5zdW1tYXJpemVkJG9yZGVyKSkNCmdncGxvdChkYXRhPWN1bXVsLnNhbXBsaW5nLnNtZC5zdW1tYXJpemVkLCBhZXMoeD1vcmRlciwgeT1tZWRpYW4sIHltaW49bG93Q0ksIHltYXg9aGlDSSkpICsNCiAgZ2VvbV9wb2ludHJhbmdlKCkgKyANCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTAsIGx0eT0yKSArICAjIGFkZCBhIGRvdHRlZCBsaW5lIGF0IHg9MSBhZnRlciBmbGlwDQogIGNvb3JkX2ZsaXAoKSArICAjIGZsaXAgY29vcmRpbmF0ZXMgKHB1dHMgbGFiZWxzIG9uIHkgYXhpcykNCiAgeGxhYigiT3JkZXIgb2YgcHVibGljYXRpb24iKSArIHlsYWIoIk92ZXJhbGwgU01EICg5NSUgQ0kpIikgKw0KICB0aGVtZV9idygpIA0KYGBgDQoNCjxici8+PGJyLz4NCg0KIyMgQXBwZW5kaXggZXh0cmE6IEZpZ3VyZSdzIFIgY29kZQ0KDQojIyMjIyBDb2RlIGZvciBGaWcuIDENCg0KVGhlcmUgaXMgbm8gY29kZSBmb3IgRmlnLiAxIChjcmVhdGVkIGluIFBvd2VyUG9pbnQpDQoNCiMjIyMjIENvZGUgZm9yIEZpZy4gMg0KDQpgYGB7ciwgZXZhbCA9IEZBTFNFfQ0KIyBsb2FkaW5nIGRhdGENClBCIDwtIHJlYWQuY3N2KCIuL1N1cnZleS9QdWJCaWFzX3Rlc3RzLmNzdiIpDQpJdGVtMTYgPC0gcmVhZC5jc3YoIi4vU3VydmV5L0l0ZW0xNlBSSVNNQUVjb0V2by5jc3YiKQ0KDQojIG51bWJlciBvZiB0aW1lcyBlYWNoIHRlc3Qgd2FzIHJlcHJlc2VudGVkDQpQQiAlPiUgZ3JvdXBfYnkoUEJfcmVwb3J0ZWRfaW5fcGFwZXIpICU+JSB0YWxseSgpICU+JSB1bmdyb3VwICU+JSBhcnJhbmdlKG4pICU+JSANCiAgbXV0YXRlKHBlcmNlbnQgPSBwYXN0ZTAocm91bmQobi9zdW0obikqMTAwLDEpLCAiJSIpKSAtPiBOdGVzdHMNCiMgc2VsZWN0aW9uIG1ldGhvZHMgd2VyZSBub3QgcmVwb3J0ZWQgaW4gYW55IHBhcGVycw0KTnRlc3RzIDwtIHJiaW5kKE50ZXN0cywNCiAgICAgICAgICAgICAgICBkYXRhLmZyYW1lKFBCX3JlcG9ydGVkX2luX3BhcGVyID0gIlNlbGVjdGlvbiAobWV0aG9kKSBtb2RlbHMgKGUuZy4gQ29wYXMsIEhlZGdlcyBvciBJeWVuZ2FyICYgR3JlZW5ob3VzZSBtb2RlbCkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgbiA9IDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBwZXJjZW50ID0gIjAuMCUiKSkNCg0KIyBtYWtpbmcgbGFiZWwgZm9yIGdyYXBocw0KUEJfbGFiZWxzIDwtIE50ZXN0cyRQQl9yZXBvcnRlZF9pbl9wYXBlcg0KUEJfbGFiZWxzIDwtIGNhc2Vfd2hlbihQQl9sYWJlbHMgPT0gIkZ1bm5lbCBwbG90cyAoaW5jbHVkaW5nIGNvbnRvdXItZW5oYW5jZWQgZnVubmVsIHBsb3RzKSIgfiAiKEEpIEZ1bm5lbCBwbG90cyIsDQogICAgICAgICAgICAgICAgICAgICAgIFBCX2xhYmVscyA9PSAiUmVncmVzc2lvbi1iYXNlZCB0ZXN0IChlLmcuIEVnZ2VyIHJlZ3Jlc3Npb24gYW5kIGl0cyB2YXJpYW50cykiIH4gIihEKSBSZWdyZXNzaW9uLWJhc2VkIG1ldGhvZHMiLA0KICAgICAgICAgICAgICAgICAgICAgICBQQl9sYWJlbHMgPT0gIlRpbWUtbGFnIGJpYXMgdGVzdHMgKGUuZy4sIHJlZ3Jlc3Npb24gb3IgY29ycmVsYXRpb24gb24gdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGVmZmVjdCBzaXplIGFuZCB0aW1lIG9yIGN1bXVsYXRpdmUgbWV0YS1hbmFseXNpcykiIH4gIihJKSBUaW1lLWxhZyBiaWFzIHRlc3RzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgUEJfbGFiZWxzID09ICJGaWxlIGRyYXdlciBudW1iZXJzIG9yIGZhaWwgc2FmZSBOIChSb3NlbnRoYWwsIE9yd2luIG9yIFJvc2VuYmVyZyBtZXRob2QpIiB+ICIoRSkgRmFpbC1zYWZlIE4iLA0KICAgICAgICAgICAgICAgICAgICAgICBQQl9sYWJlbHMgPT0gIlRyaW0tYW5kLWZpbGwgdGVzdHMiIH4gIihGKSBUcmltLWFuZC1maWxsIHRlc3RzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgUEJfbGFiZWxzID09ICJQLWN1cnZlLCBQLXVuaWZvcm0gb3IgaXRzIHZhcmlhbnRzIiB+ICIoRykgUC12YWx1ZS1iYXNlZCBtZXRob2RzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgUEJfbGFiZWxzID09ICJXZWlnaHRlZCBoaXN0b2dyYW0iIH4gIihLKSBPdGhlciAod2VpZ2h0ZWQgaGlzdG9ncmFtKSIsDQogICAgICAgICAgICAgICAgICAgICAgIFBCX2xhYmVscyA9PSAiQ29ycmVsYXRpb24tYmFzZWQgdGVzdHMgKGUuZy4gQmVnZyAmIE1hbnp1bWRhciByYW5rIGNvcnJlbGF0aW9uKSIgfiAiKEMpIENvcnJlbGF0aW9uLWJhc2VkIG1ldGhvZHMiLA0KICAgICAgICAgICAgICAgICAgICAgICBQQl9sYWJlbHMgPT0gIk5vcm1hbCBxdWFudGlsZSAoUVEpIHBsb3RzIChXYW5nICYgQnVzaG1hbikiIH4gIihCKSBOb3JtYWwgcXVhbnRpbGUgKFFRKSBwbG90cyIsDQogICAgICAgICAgICAgICAgICAgICAgIFBCX2xhYmVscyA9PSAiTm9uZSByZXBvcnRlZCIgfiAiKEopIE5vbmUgcmVwb3J0ZWQiLA0KICAgICAgICAgICAgICAgICAgICAgICBQQl9sYWJlbHMgPT0gIlNlbGVjdGlvbiAobWV0aG9kKSBtb2RlbHMgKGUuZy4gQ29wYXMsIEhlZGdlcyBvciBJeWVuZ2FyICYgR3JlZW5ob3VzZSBtb2RlbCkiIH4gIihIKSBTZWxlY3Rpb24gbW9kZWxzIikNCg0KIyBwdXR0aW5nIGluIHNhbWUgb3JkZXIgYXMgc3VydmV5IHF1ZXN0aW9uDQpOdGVzdHMkUEJfbGFiZWwgPC0gZmFjdG9yKFBCX2xhYmVscywgbGV2ZWxzID0gcmV2KHNvcnQoUEJfbGFiZWxzKSkpDQoNCiMgZ2dwbG90IHRoZW1lDQpiYWNrZ3JvdW5kLmNvbG91ciA9ICJ3aGl0ZSINCnRtIDwtIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IGJhY2tncm91bmQuY29sb3VyKSwNCiAgICAgICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gYmFja2dyb3VuZC5jb2xvdXIpLA0KICAgICAgICAgICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShzaXplID0gMC43NSwgY29sb3VyID0gImJsYWNrIiksDQogICAgICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKHNpemUgPSAwLjc1LCBjb2xvdXIgPSAiYmxhY2siKSwNCiAgICAgICAgICAgIGF4aXMudGlja3MubGVuZ3RoID0gdW5pdCgwLjEsImNtIiksDQogICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGNvbG91ciA9ICJibGFjayIpLA0KICAgICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGNvbG91ciA9ICJibGFjayIpLA0KICAgICAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLCBzaXplID0gMTYsIGNvbG91ciA9ICJibGFjayIpLA0KICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbih0PTEwLHI9MCxiPTIsbD0wKSksDQogICAgICAgICAgICMgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGNvbG91ciA9ICJibGFjayIsIGZhY2UgPSAiYm9sZCIsIGhqdXN0ID0gMC41LCBtYXJnaW4gPSBtYXJnaW4odD0yLHI9MCxiPTEwLGw9MCkpLA0KICAgICAgICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IGJhY2tncm91bmQuY29sb3VyKSwNCiAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgbWFyZ2luID0gbWFyZ2luKDIsMCwyLDApKSwNCiAgICAgICAgICAgIGxlZ2VuZC5zcGFjaW5nLnkgPSB1bml0KDEsICJjbSIpLA0KICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsDQogICAgICAgICAgICB0ZXh0ID0gIGVsZW1lbnRfdGV4dChmYW1pbHkgPSAiQXJpYWwiKSwNCiAgICAgICAgICAgIGxlZ2VuZC5rZXkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICBwbG90Lm1hcmdpbiA9IHVuaXQoYygwLjMsMSwwLjMsMC4zKSwgImNtIikpDQoNCiMgY29sb3VyIHRvIGZpbGwgY29sdW1ucw0KY29sY29sID0gIiNjYWQ3ZWQiDQoNCiMjIFBsb3Qgb2YgdGhlIHR5cGVzIG9mIHRlc3RzDQoNCmZpZzIgPC0gZ2dwbG90KE50ZXN0cykgKyB0bSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAtMSkpICsNCiAgZ2VvbV9jb2woYWVzKFBCX2xhYmVsLCBuKSwgZmlsbCA9IGNvbGNvbCwgY29sb3VyID0gImJsYWNrIiwgd2lkdGggPSAwLjc1LCBzaXplID0gMSkgKw0KICBnZW9tX3RleHQoYWVzKHggPSBQQl9sYWJlbCwgeSA9IG4sIGxhYmVsID0gcGVyY2VudCksIGhqdXN0ID0gLTAuMSwgc2l6ZSA9IDUsIGZhbWlseSA9ICJBcmlhbCIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSwgbGltaXRzID0gYygwLCA4MCkpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgbGFicyh4ID0gInR5cGUgb2YgcHVibGljYXRpb24gYmlhcyB0ZXN0IiwNCiAgICAgICB5ID0gIm51bWJlciBvZiBwYXBlcnMgcmVwb3J0aW5nIHRlc3QiKSANCg0KI2ZpZzINCmBgYA0KDQojIyMjIyBDb2RlIGZvciBGaWcuIDMNCg0KYGBge3IsIGZpZy5oZWlnaHQ9IDgsIGZpZy53aWR0aD0gNywgZXZhbCA9IEZBTFNFfQ0KDQojIGNyZWF0aW5nIGRhdGENCg0Kc2V0LnNlZWQoNzc3NzcpDQoNCiMgc2V0dGluZyBwYXJhbWV0ZXJzDQpuLmVmZmVjdCA8LSAxMDANCnNpZ21hMi5zIDwtIDAuMDUNCmJldGExIDwtIDAuMg0KIyB1c2luZyBuZWdhdGl2ZSBiaW5vbWlhbCB3ZSBnZXQgZ29vZCBzcHJlYWQgb2Ygc2FtcGxlIHNpemUNCm4uc2FtcGxlIDwtIHJuYmlub20obi5lZmZlY3QsIG11ID0gMzAsIHNpemUgPSAwLjcpICsgNA0KIyB2YXJpYW5jZSBmb3IgWnINCnZpIDwtIDEvKG4uc2FtcGxlIC0gMykNCiMgbW9kZXJhdG9yIHggMQ0KeGkgPC0gcm5vcm0obi5lZmZlY3QpDQoNCiMgdGhlcmUgaXMgdW5kZXJsaW5nIG92ZXJhbGwgZWZmZWN0IHRvIHIgPSAwLjIgb3IgWnIgPSAwLjIwMw0KWnIgPC0gYXRhbmgoMC4yKSArIGJldGExKnhpICsgcm5vcm0obi5lZmZlY3QsIDAsIHNxcnQoc2lnbWEyLnMpKSArIHJub3JtKG4uZWZmZWN0LCAwLCBzcXJ0KHZpKSkNCiNxcGxvdChaciwgMS9zcXJ0KHZpKSkNCg0KZGF0IDwtIGRhdGEuZnJhbWUoeWkgPSBaciwgdmkgPSB2aSwgc2VpID0gc3FydCh2aSksIHhpID0geGksIG5pID0gbi5zYW1wbGUsIHByZWMgPSAxIC8gc3FydCh2aSksIHdpID0gMS92aSwgemkgPSBaci9zcXJ0KHZpKSkNCg0Kcm93cyA8LSAxOm5yb3coZGF0KQ0KZXhwZWN0ZWQgPC0gd2hpY2goMS9kYXQkc2VpIDwgNSAmIGRhdCR5aSA8IDAuMjUpDQp1bmV4cGVjdGVkIDwtIHdoaWNoKDEvZGF0JHNlaSA+IDQuNyAmIGRhdCR5aSA+IDAuMjUpDQoNCmNvbF9wb2ludCA8LSBpZmVsc2Uocm93cyAlaW4lIGV4cGVjdGVkLCAicmVkIiwgaWZlbHNlKHJvd3MgJWluJSB1bmV4cGVjdGVkLCAiYmx1ZSIsICJibGFjayIpKQ0KDQpkYXQkY29sX3BvaW50IDwtIGNvbF9wb2ludA0KDQojaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvNTAwMTI1NTMvY29tYmluaW5nLXBsb3RzLWNyZWF0ZWQtYnktci1iYXNlLWxhdHRpY2UtYW5kLWdncGxvdDINCiMgc2F2aW5nIGJhc2UgcGxvdCBhcyBhbiBvYmplY3QgaHR0cHM6Ly93d3cuYW5kcmV3aGVpc3MuY29tL2Jsb2cvMjAxNi8xMi8wOC9zYXZlLWJhc2UtZ3JhcGhpY3MtYXMtcHNldWRvLW9iamVjdHMtaW4tci8NCg0KbW9kX3JhIDwtIHJtYSh5aSwgdmksIGRhdGEgPSBkYXQpDQptb2RfZmUgPC0gcm1hKHlpLCB2aSwgZGF0YSA9IGRhdCwgbWV0aG9kID0gIkZFIikNCg0KIyBtYXJnaW4gY29udHJvbGxpbmcNCiNwYXIobWFyPWMoNSw0LDAsMCkgKyAwLjEpDQoNCiMgREwgZm9yIHN1bnNldCBwbG90IGFuZCBlbmhhbmNlZCBjb3VudGVyIC0gbWFraW5nIGl0IC0gMC4wMSA8IHAgPCAwLjA1IA0KDQojIGENCnBkZihOVUxMKQ0KZGV2LmNvbnRyb2woZGlzcGxheWxpc3Q9ImVuYWJsZSIpDQpwYXIobWFyPWMoNCw0LDAuMSwwKSArIDAuMSkNCmZ1bm5lbChkYXQkeWksIGRhdCR2aSwgbmkgPSBkYXQkbmksIHlheGlzPSJuaSIsDQogICAgICAgeGxpbSA9IGMoLTMsIDMpLA0KICAgICAgIHJlZmxpbmU9bW9kX3JhJGJldGEsIHhsYWIgPSAiRWZmZWN0IHNpemUgKFpyKSIpIA0KYSA8LSByZWNvcmRQbG90KCkNCmludmlzaWJsZShkZXYub2ZmKCkpDQoNCg0KIyBiDQpwZGYoTlVMTCkNCmRldi5jb250cm9sKGRpc3BsYXlsaXN0PSJlbmFibGUiKQ0KcGFyKG1hcj1jKDQsNCwwLjEsMCkgKyAwLjEpDQpmdW5uZWwobW9kX3JhLCB5YXhpcz0ic2VpbnYiLCBjb2wgPSBjb2xfcG9pbnQsICANCiAgICAgICB5bGltID0gYygxLCAxMiksIHhsaW0gPSBjKC0zLCAzKSwNCiAgICAgICB5bGFiID0gIlByZWNpc29uICgxL1NFKSIsIHhsYWIgPSAiRWZmZWN0IHNpemUgKFpyKSIpDQpsZWdlbmQoeCA9IDEuNCwgeSA9IDEyLCBsZWdlbmQgPSBjKCJleHBlY3RlZCIsICIiLCJ1bmV4cGVjdGVkIiksIHBjaCA9IGMoMTksIDAsIDE5KSwgY29sID0gYygicmVkIiwgImdyZXk4MyIsICJibHVlIiksIGJ0eSA9ICJuIikNCmIgPC0gcmVjb3JkUGxvdCgpDQppbnZpc2libGUoZGV2Lm9mZigpKQ0KDQoNCiMgYw0KcGRmKE5VTEwpDQpkZXYuY29udHJvbChkaXNwbGF5bGlzdD0iZW5hYmxlIikNCnBhcihtYXI9Yyg0LDQsMC4xLDApICsgMC4xKQ0KZnVubmVsKG1vZF9yYSwgDQogICAgICAgeWF4aXMgPSAic2VpIiwgDQogICAgICAgeGxpbSA9IGMoLTMsIDMpLA0KICAgICAgIGxldmVsID0gYyg5NSwgOTkpLCANCiAgICAgICBzaGFkZSA9IGMoIndoaXRlIiwgImdyYXk1NSIpLCANCiAgICAgICByZWZsaW5lID0gMCwgbGVnZW5kID0gRiwgDQogICAgICAgeWxhYiA9ICJTdGFuZGFyZCBlcnJvciAoU0UpIiwgeGxhYiA9ICJFZmZlY3Qgc2l6ZSAoWnIpIikNCmxlZ2VuZCh4ID0gMSwgeSA9IDAsIGxlZ2VuZCA9IGMoIjAuMDEgPCBwIDwgMC4wNSIpLCBwY2ggPSBjKDE1KSwgY29sID0gYygiZ3JheTU1IiksIGJ0eSA9ICJuIikNCmMgPC0gcmVjb3JkUGxvdCgpDQppbnZpc2libGUoZGV2Lm9mZigpKQ0KDQojIGQNCmQgPC0gdml6X3N1bnNldChkYXRbLGMoInlpIiwgInNlaSIpXSwgDQogICAgICAgICAgICAgICAgcG93ZXJfY29udG91cnMgPSAiY29udGludW91cyIsIA0KICAgICAgICAgICAgICAgIGNvbnRvdXJzID0gVCwNCiAgICAgICAgICAgICAgICBwb3dlcl9zdGF0cyA9IEYsDQogICAgICAgICAgICAgICAgeGxhYiA9ICJFZmZlY3Qgc2l6ZSAoWnIpIiwNCiAgICAgICAgICAgICAgICB5bGFiID0gIlN0YW5kYXJkIGVycm9yIChTRSkiKQ0KDQoNCiMgZQ0KIyBtZXRhLXJlZ3Jlc3Npb24gKHJhbmRvbS1lZmZlY3RzIG1vZGVsKQ0KbW9kX3JlMSA8LSBybWEoeWksIHZpLCBtb2QgPSB+IHhpLCBkYXRhID0gZGF0KQ0KDQoNCnBkZihOVUxMKQ0KZGV2LmNvbnRyb2woZGlzcGxheWxpc3Q9ImVuYWJsZSIpDQpwYXIobWFyPWMoNCw0LDAuMSwwKSArIDAuMSkNCmZ1bm5lbChtb2RfcmUxLCANCiAgICAgICB5YXhpcyA9ICJzZWkiLCANCiAgICAgICB4bGltID0gYygtMywgMyksIHlsaW0gPSBjKDAsIDEpLA0KICAgICAgICNsZXZlbCA9IGMoOTUsIDk5KSwgDQogICAgICAgI3NoYWRlID0gYygid2hpdGUiLCAiZ3JheTc1IiksIA0KICAgICAgIHJlZmxpbmUgPSAwLCBsZWdlbmQgPSBGLCAgeWxhYiA9ICJTdGFuZGFyZCBlcnJvciAoU0UpIiwgeGxhYiA9ICJTdGFuZGFyZGl6ZWQgcmVzaWR1bHMgKFpyKSIpDQojbGVnZW5kKHggPSAxLCB5ID0gMCwgbGVnZW5kID0gYygiMC4wMSA8IHAgPCAwLjA1IiwgIiIpLCBwY2ggPSBjKDE1LCAwKSwgY29sID0gYygiZ3JheTc1IiwgIndoaXRlIiksIGJnID0gIndoaXRlIikNCmUgPC0gcmVjb3JkUGxvdCgpDQppbnZpc2libGUoZGV2Lm9mZigpKQ0KDQojIGYNCg0KIyANCm1vZCA8LSBtZXRhZ2VuKFRFID0geWksIHNlVEUgPSBzcXJ0KHZpKSAsIGRhdGEgPSBkYXQpDQoNCnBkZihOVUxMKQ0KZGV2LmNvbnRyb2woZGlzcGxheWxpc3Q9ImVuYWJsZSIpDQpwYXIobWFyPWMoNCw0LDAuMSwwKSArIDAuMSkNCiNyYWRpYWwucm1hKG1vZF9mZSwgeGxpbSA9IGMoMCwgMTIuNSksIHpsYWIgPSAiWiBzY29yZSIsIHhsYWIgPSAiUHJlY2lzaW9uICgxL1NFKSIpIA0KI2xlZ2VuZCgxLDEsICJ0ZXN0IiwgYnR5ID0gIm4iKQ0KcmFkaWFsKG1vZCwgbGV2ZWwgPSAwLjk1LCBwY2ggPSAxOSwgIHhsYWIgPSAiUHJlY2lzaW9uICgxL1NFKSIsIHlsYWIgPSAiWiBzY29yZSIpDQphYmxpbmUoYSA9IDAsIGIgPSAwLjE5MDgsIGx3ZCA9IDEuNSkNCmYgPC0gcmVjb3JkUGxvdCgpDQppbnZpc2libGUoZGV2Lm9mZigpKQ0KDQojIGZpZyAzDQpmaWczIDwtIChnZ2RyYXcoYSkgKyBnZ2RyYXcoYikpIC8oZ2dkcmF3KGMpICsgZ2dkcmF3KGQpKS8gKHBsb3RfZ3JpZChlKSArIGdnZHJhdyhmKSkgKyBwbG90X2Fubm90YXRpb24odGFnX2xldmVscyA9ICdhJykNCg0KZmlnMw0KYGBgDQoNCiMjIyMjIENvZGUgZm9yIEZpZy4gNA0KDQpgYGB7ciwgZmlnLmhlaWdodD0gOCwgZmlnLndpZHRoPSA4LCBldmFsID0gRkFMU0V9DQojIGNyZWF0aW5nIGRhdGEgd2l0aCBwdWJsaWNhdGlvbiBiaWFzDQoNCmRhdDIgPC0gZGF0W2RhdCRjb2xfcG9pbnQgIT0gInJlZCIsIF0NCg0KIyBtZXRhLWFuYWx5c2lzDQptb2RfcmEyIDwtIHJtYSh5aSwgdmksIGRhdGEgPSBkYXQyKQ0KDQojIGVnZ2VyIHJlZ3Jlc3Npb24gKHRoZSBzYW1lIGFzIGluIFMyKQ0KZWdnZXIxIDwtIGxtKHppIH4gcHJlYywgZGF0YSA9IGRhdDIpDQplZ2dlcjIgPC0gbG0oeWkgfiBzZWksIHdlaWdodCA9IHdpLCBkYXRhID0gZGF0MikNCg0KIyBkYXRhIGZvciB0aW1lLWxhZyBiaWFzDQpzZXQuc2VlZCgxMjMpDQpwb3NpdGlvbiA8LSBzYW1wbGUoMTpucm93KGRhdDIpLCBzaXplID0gMTUpDQoNCmRhdDMgPC0gZGF0Mltzb3J0KHBvc2l0aW9uKSwgXQ0KDQpzb3J0aW5nIDwtIGMoMTIsIDEzLCAxNCwgMywgNCwgOSwgOCwgNSwgMTAsIDExLCAgNiwgNywgMiwgMTUsIDEpDQoNCmRhdDMgPC0gZGF0M1tzb3J0aW5nLCBdICAgICAgICANCmRhdDMkeWVhciA8LSBjKDIwMDAsIDIwMDEsIDIwMDMsIDIwMDUsIDIwMDYsIDIwMDcsIDIwMDgsIDIwMDksIDIwMTAsIDIwMTIsIDIwMTMsIDIwMTQsIDIwMTYsIDIwMTgsIDIwMTkpDQoNCiMgY3VtbGF0aWUgbWV0YS1hbmFseXNpcw0KY3VtIDwtIHJtYSh5aSwgdmksIGRhdGE9ZGF0MykNCmN1bV9tYSA8LSBjdW11bChjdW0pDQojZm9yZXN0KGN1bV9tYSwgeGxhYiA9ICJPdmVyYWxsIGVzdGltYXRlIChacikiKQ0KDQoNCiMgbWV0YS1yZWdyZXNzaW9uDQoNCm1vZF9yZTIgPC0gcm1hKHlpLCB2aSwgbW9kID0gfiB5ZWFyLCBkYXRhID0gZGF0MykNCg0KIyBmdW5uZWwNCnRhZiA8LSB0cmltZmlsbChtb2RfcmEyKQ0KDQojIFBsb3R0aW5nIGZyb20gaGVyZQ0KDQpwMSA8LSAgZ2dwbG90KGRhdDIsIGFlcyhwcmVjLCB6aSkpICsgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIikgKyANCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gZWdnZXIxJGNvZWZmaWNpZW50c1tbMV1dKSArDQogICNnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKSArIA0KICBsYWJzKHggPSAiUHJlY2lzaW9uICgxL1NFKSIsIA0KICAgICAgIHkgPSAiWiBzY29yZSIpDQoNCnAyIDwtIGdncGxvdChkYXQyLCBhZXMoc2VpLCB5aSkpICsgZ2VvbV9wb2ludCgpICsNCiAgIyBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKSArIA0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArIA0KICBnZW9tX2FibGluZShpbnRlcmNlcHQgPSBlZ2dlcjIkY29lZmZpY2llbnRzW1sxXV0sIHNsb3BlID0gZWdnZXIyJGNvZWZmaWNpZW50c1tbMl1dKSArDQogIGxhYnMoeCA9ICJTdGFuZGFyZCBlcnJvciAoU0UpIiwgDQogICAgICAgeSA9ICJFZmZlY3Qgc2l6ZSAoWnIpIikNCg0KIyBjIGFuZCBkDQojIHByb2JhYmx5IDE1IGRhdGEgcG9pbnRzIGZvciBjdW11bGF0aXZlIG1ldGEtYW5hbHlzZXMNCg0KY3VtIDwtIHJtYSh5aSwgdmksIGRhdGE9ZGF0MykNCmN1bV9tYSA8LSBjdW11bChjdW0pDQoNCiMgcDMNCnBkZihOVUxMKQ0KZGV2LmNvbnRyb2woZGlzcGxheWxpc3Q9ImVuYWJsZSIpDQpwYXIobWFyPWMoNCw0LDAuMSwwKSArIDAuMSkNCmZvcmVzdChjdW1fbWEsIHhsYWIgPSAiT3ZlcmFsbCBlc3RpbWF0ZSAoWnIpIikNCnAzIDwtIHJlY29yZFBsb3QoKQ0KaW52aXNpYmxlKGRldi5vZmYoKSkNCg0KIyBwNA0KcDQgPC0gZ2dwbG90KGRhdDMsIGFlcyh4ID0geWVhciwgeSA9IHlpLCBzaXplID0gcHJlYykpICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIikgKyANCiAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gbW9kX3JlMiRiZXRhW1sxXV0sIHNsb3BlID0gbW9kX3JlMiRiZXRhW1syXV0pICsNCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBmaWxsID0gImdyZXk5MCIpICsgDQogIGxhYnMoeCA9ICJQdWJsaWNhdGlvbiB5ZWFyIiwgeSA9ICJFZmZlY3Qgc2l6ZSAoWnIpIiwgc2l6ZSA9IlByZWNpc2lvbiAoMS9TRSkiKSArIA0KICBndWlkZXMoZmlsbCA9ICJub25lIiwgY29sb3VyID0gIm5vbmUiKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMCwgMC4xNSksIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygwLCAxKSkgKw0KICB0aGVtZShsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiKSArDQogICMgdGhlbWUobGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIsIGNvbG91ciA9ICJibGFjayIpKSArDQogIHRoZW1lKGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpKSArDQogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwgY29sb3VyID0gImJsYWNrIiwgaGp1c3QgPSAwLjUsIGFuZ2xlID0gOTApKQ0KDQojIHA1DQpwZGYoTlVMTCkNCmRldi5jb250cm9sKGRpc3BsYXlsaXN0PSJlbmFibGUiKQ0KcGFyKG1hcj1jKDQsNCwwLjEsMCkgKyAwLjEpDQpmdW5uZWwodGFmLCB5YXhpcz0ic2VpbnYiLCBjb2wgPSBjb2xfcG9pbnQsICBlc3RpbWF0b3I9IlIwIiwNCiAgICAgICB5bGltID0gYygxLCAxMiksIA0KICAgICAgICN4bGltID0gYygtMywgMyksDQogICAgICAgeWxhYiA9ICJQcmVjaXNvbiAoMS9TRSkiLCB4bGFiID0gIkVmZmVjdCBzaXplIChacikiKQ0KcDUgPC0gcmVjb3JkUGxvdCgpDQppbnZpc2libGUoZGV2Lm9mZigpKQ0KDQojIHA2DQpwZGYoTlVMTCkNCmRldi5jb250cm9sKGRpc3BsYXlsaXN0PSJlbmFibGUiKQ0KcGFyKG1hcj1jKDQsNCwwLjEsMCkgKyAwLjEpDQpmdW5uZWwodGFmLCB5YXhpcz0ic2VpIiwgY29sID0gY29sX3BvaW50LCAgZXN0aW1hdG9yPSJSMCIsDQogICAgICAgI3hsaW0gPSBjKC0zLCAzKSwNCiAgICAgICB5bGFiID0gIlN0YW5kYXJkIGVycm9yIChTRSkiLCB4bGFiID0gIkVmZmVjdCBzaXplIChacikiKQ0KcDYgPC0gcmVjb3JkUGxvdCgpDQppbnZpc2libGUoZGV2Lm9mZigpKQ0KDQoNCiMgZSBhbmQgZg0KIyBtYXliZSB1c2UgdGhlIHNhbWUgZGF0YXNldHMgYXMgRmlnIDMNCg0KIyBmaWcgNA0KZmlnNCA8LSAocGxvdF9ncmlkKHAxKSArIHBsb3RfZ3JpZChwMikpIC8oZ2dkcmF3KHAzKSArIHBsb3RfZ3JpZChwNCkpLyhwbG90X2dyaWQocDUpICsgcGxvdF9ncmlkKHA2KSkgKyBwbG90X2Fubm90YXRpb24odGFnX2xldmVscyA9ICdhJykNCg0KZmlnNA0KYGBgDQoNCiMjIyMjIENvZGUgZm9yIEZpZy4gNQ0KDQpgYGB7ciwgZmlnLmhlaWdodD0gOCwgZmlnLndpZHRoPSA3LCBtZXNzYWdlID0gRkFMU0UsIGV2YWwgPSBGQUxTRX0NCiMgZG1ldHINCg0KI2RldnRvb2xzOjppbnN0YWxsX2dpdGh1YigiTWF0aGlhc0hhcnJlci9kbWV0YXIiKQ0KI2xpYnJhcnkoZG1ldGFyKQ0KDQojIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyBwcmVwYXJhdGlvbiMjIyMjIyMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjDQoNCiMgY2hhbnRpbmcgdGhlIHBjdXJ2ZSBmdW5jdGlvbiBpbiBkbWV0YXIgc28gZm9udHMgYXJlIGxhcmdlIGVub3VnaCB0byBzZWUNCnBjdXJ2ZTIgPC0gZnVuY3Rpb24gKHgsIGVmZmVjdC5lc3RpbWF0aW9uID0gRkFMU0UsIE4sIGRtaW4gPSAwLCBkbWF4ID0gMSkgDQp7DQogICAgbWV0YW9iamVjdCA9IHgNCiAgICBybSh4KQ0KICAgIGlmICghKGNsYXNzKG1ldGFvYmplY3QpWzFdICVpbiUgYygibWV0YWdlbiIsICJtZXRhYmluIiwgIm1ldGFjb250IiwgDQogICAgICAgICJtZXRhY29yIiwgIm1ldGFpbmMiLCAibWV0YSIsICJtZXRhcHJvcCIpKSkgew0KICAgICAgICBmb3IgKGkgaW4gMTpsZW5ndGgoY29sbmFtZXMobWV0YW9iamVjdCkpKSB7DQogICAgICAgICAgICB0ZS5leGlzdHMgPSBGQUxTRQ0KICAgICAgICAgICAgaWYgKGNvbG5hbWVzKG1ldGFvYmplY3QpW2ldID09ICJURSIpIHsNCiAgICAgICAgICAgICAgICB0ZS5leGlzdHMgPSBUUlVFDQogICAgICAgICAgICAgICAgYnJlYWsNCiAgICAgICAgICAgIH0NCiAgICAgICAgICAgIGVsc2Ugew0KICAgICAgICAgICAgfQ0KICAgICAgICB9DQogICAgICAgIGZvciAoaSBpbiAxOmxlbmd0aChjb2xuYW1lcyhtZXRhb2JqZWN0KSkpIHsNCiAgICAgICAgICAgIHNldGUuZXhpc3RzID0gRkFMU0UNCiAgICAgICAgICAgIGlmIChjb2xuYW1lcyhtZXRhb2JqZWN0KVtpXSA9PSAic2VURSIpIHsNCiAgICAgICAgICAgICAgICBzZXRlLmV4aXN0cyA9IFRSVUUNCiAgICAgICAgICAgICAgICBicmVhaw0KICAgICAgICAgICAgfQ0KICAgICAgICAgICAgZWxzZSB7DQogICAgICAgICAgICB9DQogICAgICAgIH0NCiAgICAgICAgZm9yIChpIGluIDE6bGVuZ3RoKGNvbG5hbWVzKG1ldGFvYmplY3QpKSkgew0KICAgICAgICAgICAgc3R1ZGxhYi5leGlzdHMgPSBGQUxTRQ0KICAgICAgICAgICAgaWYgKGNvbG5hbWVzKG1ldGFvYmplY3QpW2ldID09ICJzdHVkbGFiIikgew0KICAgICAgICAgICAgICAgIHN0dWRsYWIuZXhpc3RzID0gVFJVRQ0KICAgICAgICAgICAgICAgIGJyZWFrDQogICAgICAgICAgICB9DQogICAgICAgICAgICBlbHNlIHsNCiAgICAgICAgICAgIH0NCiAgICAgICAgfQ0KICAgICAgICBpZiAodGUuZXhpc3RzID09IEZBTFNFIHwgc2V0ZS5leGlzdHMgPT0gRkFMU0UgfCBzdHVkbGFiLmV4aXN0cyA9PSANCiAgICAgICAgICAgIEZBTFNFKSB7DQogICAgICAgICAgICBzdG9wKCJ4IG11c3QgYmUgYSBtZXRhLWFuYWx5c2lzIG9iamVjdCBnZW5lcmF0ZWQgYnkgbWV0YSBmdW5jdGlvbnMgb3IgYSBkYXRhLmZyYW1lIHdpdGggY29sdW1ucyBsYWJlbGVkIHN0dWRsYWIsIFRFLCBhbmQgc2VURS4iKQ0KICAgICAgICB9DQogICAgfQ0KICAgIG9wdGlvbnMoc2NpcGVuID0gOTk5KQ0KICAgIHp2YWx1ZXMuaW5wdXQgPSBhYnMobWV0YW9iamVjdCRURS9tZXRhb2JqZWN0JHNlVEUpDQogICAgZ2V0bmNwLmYgPSBmdW5jdGlvbihkZjEsIGRmMiwgcG93ZXIpIHsNCiAgICAgICAgZXJyb3IgPSBmdW5jdGlvbihuY3BfZXN0LCBwb3dlciwgeCwgZGYxLCBkZjIpIHBmKHgsIGRmMSA9IGRmMSwgDQogICAgICAgICAgICBkZjIgPSBkZjIsIG5jcCA9IG5jcF9lc3QpIC0gKDEgLSBwb3dlcikNCiAgICAgICAgeGMgPSBxZihwID0gMC45NSwgZGYxID0gZGYxLCBkZjIgPSBkZjIpDQogICAgICAgIHJldHVybih1bmlyb290KGVycm9yLCBjKDAsIDEwMDApLCB4ID0geGMsIGRmMSA9IGRmMSwgDQogICAgICAgICAgICBkZjIgPSBkZjIsIHBvd2VyID0gcG93ZXIpJHJvb3QpDQogICAgfQ0KICAgIGdldG5jcC5jID0gZnVuY3Rpb24oZGYsIHBvd2VyKSB7DQogICAgICAgIHhjID0gcWNoaXNxKHAgPSAwLjk1LCBkZiA9IGRmKQ0KICAgICAgICBlcnJvciA9IGZ1bmN0aW9uKG5jcF9lc3QsIHBvd2VyLCB4LCBkZikgcGNoaXNxKHgsIGRmID0gZGYsIA0KICAgICAgICAgICAgbmNwID0gbmNwX2VzdCkgLSAoMSAtIHBvd2VyKQ0KICAgICAgICByZXR1cm4odW5pcm9vdChlcnJvciwgYygwLCAxMDAwKSwgeCA9IHhjLCBkZiA9IGRmLCBwb3dlciA9IHBvd2VyKSRyb290KQ0KICAgIH0NCiAgICBnZXRuY3AgPSBmdW5jdGlvbihmYW1pbHksIGRmMSwgZGYyLCBwb3dlcikgew0KICAgICAgICBpZiAoZmFtaWx5ID09ICJmIikgDQogICAgICAgICAgICBuY3AgPSBnZXRuY3AuZihkZjEgPSBkZjEsIGRmMiA9IGRmMiwgcG93ZXIgPSBwb3dlcikNCiAgICAgICAgaWYgKGZhbWlseSA9PSAiYyIpIA0KICAgICAgICAgICAgbmNwID0gZ2V0bmNwLmMoZGYgPSBkZjEsIHBvd2VyID0gcG93ZXIpDQogICAgICAgIHJldHVybihuY3ApDQogICAgfQ0KICAgIHBlcmNlbnQgPC0gZnVuY3Rpb24oeCwgZGlnaXRzID0gMCwgZm9ybWF0ID0gImYiLCAuLi4pIHsNCiAgICAgICAgcGFzdGUoZm9ybWF0QygxMDAgKiB4LCBmb3JtYXQgPSBmb3JtYXQsIGRpZ2l0cyA9IGRpZ2l0cywgDQogICAgICAgICAgICAuLi4pLCAiJSIsIHNlcCA9ICIiKQ0KICAgIH0NCiAgICBwYm91bmQgPSBmdW5jdGlvbihwKSBwbWluKHBtYXgocCwgMC4wMDAwMDAwMDAwMDAwMDAyMiksIDEgLSANCiAgICAgICAgMC4wMDAwMDAwMDAwMDAwMDAyMikNCiAgICBwcm9wMzMgPSBmdW5jdGlvbihwYykgew0KICAgICAgICBwcm9wID0gaWZlbHNlKGZhbWlseSA9PSAiZiIgJiBwIDwgMC4wNSwgMSAtIHBmKHFmKDEgLSANCiAgICAgICAgICAgIHBjLCBkZjEgPSBkZjEsIGRmMiA9IGRmMiksIGRmMSA9IGRmMSwgZGYyID0gZGYyLCANCiAgICAgICAgICAgIG5jcCA9IG5jcDMzKSwgTkEpDQogICAgICAgIHByb3AgPSBpZmVsc2UoZmFtaWx5ID09ICJjIiAmIHAgPCAwLjA1LCAxIC0gcGNoaXNxKHFjaGlzcSgxIC0gDQogICAgICAgICAgICBwYywgZGYgPSBkZjEpLCBkZiA9IGRmMSwgbmNwID0gbmNwMzMpLCBwcm9wKQ0KICAgICAgICBwcm9wDQogICAgfQ0KICAgIHN0b3VmZmVyID0gZnVuY3Rpb24ocHApIHN1bShxbm9ybShwcCksIG5hLnJtID0gVFJVRSkvc3FydChzdW0oIWlzLm5hKHBwKSkpDQogICAgenZhbHVlcy5pbnB1dCA9IHBhc3RlKCJ6PSIsIHp2YWx1ZXMuaW5wdXQsIHNlcCA9ICIiKQ0KICAgIGZpbGVrID0gImlucHV0Ig0KICAgIHJhdyA9IHp2YWx1ZXMuaW5wdXQNCiAgICByYXcgPSB0b2xvd2VyKHJhdykNCiAgICBrdG90ID0gbGVuZ3RoKHJhdykNCiAgICBrID0gc2VxKGZyb20gPSAxLCB0byA9IGxlbmd0aChyYXcpKQ0KICAgIHN0YXQgPSBzdWJzdHJpbmcocmF3LCAxLCAxKQ0KICAgIHRlc3QgPSBpZmVsc2Uoc3RhdCA9PSAiciIsICJ0Iiwgc3RhdCkNCiAgICBmYW1pbHkgPSB0ZXN0DQogICAgZmFtaWx5ID0gaWZlbHNlKHRlc3QgPT0gInQiLCAiZiIsIGZhbWlseSkNCiAgICBmYW1pbHkgPSBpZmVsc2UodGVzdCA9PSAieiIsICJjIiwgZmFtaWx5KQ0KICAgIHBhcjEgPSBzdHJfbG9jYXRlKHJhdywgIlxcKCIpWywgMV0NCiAgICBwYXIyID0gc3RyX2xvY2F0ZShyYXcsICJcXCkiKVssIDFdDQogICAgY29tbWEgPSBzdHJfbG9jYXRlKHJhdywgIiwiKVssIDFdDQogICAgZXEgPSBzdHJfbG9jYXRlKHJhdywgIj0iKVssIDFdDQogICAgZGYgPSBhcy5udW1lcmljKGlmZWxzZSh0ZXN0ID09ICJ0Iiwgc3Vic3RyaW5nKHJhdywgcGFyMSArIA0KICAgICAgICAxLCBwYXIyIC0gMSksIE5BKSkNCiAgICBkZjEgPSBhcy5udW1lcmljKGlmZWxzZSh0ZXN0ID09ICJmIiwgc3Vic3RyaW5nKHJhdywgcGFyMSArIA0KICAgICAgICAxLCBjb21tYSAtIDEpLCBOQSkpDQogICAgZGYxID0gYXMubnVtZXJpYyhpZmVsc2UodGVzdCA9PSAieiIsIDEsIGRmMSkpDQogICAgZGYxID0gYXMubnVtZXJpYyhpZmVsc2UodGVzdCA9PSAidCIsIDEsIGRmMSkpDQogICAgZGYxID0gYXMubnVtZXJpYyhpZmVsc2UodGVzdCA9PSAiYyIsIHN1YnN0cmluZyhyYXcsIHBhcjEgKyANCiAgICAgICAgMSwgcGFyMiAtIDEpLCBkZjEpKQ0KICAgIGRmMiA9IGFzLm51bWVyaWMoaWZlbHNlKHRlc3QgPT0gImYiLCBzdWJzdHJpbmcocmF3LCBjb21tYSArIA0KICAgICAgICAxLCBwYXIyIC0gMSksIE5BKSkNCiAgICBkZjIgPSBhcy5udW1lcmljKGlmZWxzZSh0ZXN0ID09ICJ0IiwgZGYsIGRmMikpDQogICAgZXF1YWwgPSBhYnMoYXMubnVtZXJpYyhzdWJzdHJpbmcocmF3LCBlcSArIDEpKSkNCiAgICB2YWx1ZSA9IGlmZWxzZSgoc3RhdCA9PSAiZiIgfCBzdGF0ID09ICJjIiksIGVxdWFsLCBOQSkNCiAgICB2YWx1ZSA9IGlmZWxzZShzdGF0ID09ICJyIiwgKGVxdWFsLyhzcXJ0KCgxIC0gZXF1YWxeMikvZGYyKSkpXjIsIA0KICAgICAgICB2YWx1ZSkNCiAgICB2YWx1ZSA9IGlmZWxzZShzdGF0ID09ICJ0IiwgZXF1YWxeMiwgdmFsdWUpDQogICAgdmFsdWUgPSBpZmVsc2Uoc3RhdCA9PSAieiIsIGVxdWFsXjIsIHZhbHVlKQ0KICAgIHAgPSBpZmVsc2UoZmFtaWx5ID09ICJmIiwgMSAtIHBmKHZhbHVlLCBkZjEgPSBkZjEsIGRmMiA9IGRmMiksIA0KICAgICAgICBOQSkNCiAgICBwID0gaWZlbHNlKGZhbWlseSA9PSAiYyIsIDEgLSBwY2hpc3EodmFsdWUsIGRmID0gZGYxKSwgcCkNCiAgICBwID0gcGJvdW5kKHApDQogICAga3NpZyA9IHN1bShwIDwgMC4wNSwgbmEucm0gPSBUUlVFKQ0KICAgIGtoYWxmID0gc3VtKHAgPCAwLjAyNSwgbmEucm0gPSBUUlVFKQ0KICAgIGlmIChrc2lnIDw9IDIpIHsNCiAgICAgICAgc3RvcCgiVHdvIG9yIGxlc3Mgc2lnbmlmaWNhbnQgKHA8MC4wNSkgZWZmZWN0IHNpemVzIHdlcmUgZGV0ZWN0ZWQsIHNvIHAtY3VydmUgYW5hbHlzaXMgY2Fubm90IGJlIGNvbmR1Y3RlZC4iKQ0KICAgIH0NCiAgICBwcHIgPSBhcy5udW1lcmljKGlmZWxzZShwIDwgMC4wNSwgMjAgKiBwLCBOQSkpDQogICAgcHByID0gcGJvdW5kKHBwcikNCiAgICBwcHIuaGFsZiA9IGFzLm51bWVyaWMoaWZlbHNlKHAgPCAwLjAyNSwgNDAgKiBwLCBOQSkpDQogICAgcHByLmhhbGYgPSBwYm91bmQocHByLmhhbGYpDQogICAgbmNwMzMgPSBtYXBwbHkoZ2V0bmNwLCBkZjEgPSBkZjEsIGRmMiA9IGRmMiwgcG93ZXIgPSAxLzMsIA0KICAgICAgICBmYW1pbHkgPSBmYW1pbHkpDQogICAgcHAzMyA9IGlmZWxzZShmYW1pbHkgPT0gImYiICYgcCA8IDAuMDUsIDMgKiAocGYodmFsdWUsIGRmMSA9IGRmMSwgDQogICAgICAgIGRmMiA9IGRmMiwgbmNwID0gbmNwMzMpIC0gMi8zKSwgTkEpDQogICAgcHAzMyA9IGlmZWxzZShmYW1pbHkgPT0gImMiICYgcCA8IDAuMDUsIDMgKiAocGNoaXNxKHZhbHVlLCANCiAgICAgICAgZGYgPSBkZjEsIG5jcCA9IG5jcDMzKSAtIDIvMyksIHBwMzMpDQogICAgcHAzMyA9IHBib3VuZChwcDMzKQ0KICAgIHByb3AyNSA9IDMgKiBwcm9wMzMoMC4wMjUpDQogICAgcHJvcDI1LnNpZyA9IHByb3AyNVtwIDwgMC4wNV0NCiAgICBwcDMzLmhhbGYgPSBpZmVsc2UoZmFtaWx5ID09ICJmIiAmIHAgPCAwLjAyNSwgKDEvcHJvcDI1KSAqIA0KICAgICAgICAocGYodmFsdWUsIGRmMSA9IGRmMSwgZGYyID0gZGYyLCBuY3AgPSBuY3AzMykgLSAoMSAtIA0KICAgICAgICAgICAgcHJvcDI1KSksIE5BKQ0KICAgIHBwMzMuaGFsZiA9IGlmZWxzZShmYW1pbHkgPT0gImMiICYgcCA8IDAuMDI1LCAoMS9wcm9wMjUpICogDQogICAgICAgIChwY2hpc3EodmFsdWUsIGRmID0gZGYxLCBuY3AgPSBuY3AzMykgLSAoMSAtIHByb3AyNSkpLCANCiAgICAgICAgcHAzMy5oYWxmKQ0KICAgIHBwMzMuaGFsZiA9IHBib3VuZChwcDMzLmhhbGYpDQogICAgWnBwciA9IHN0b3VmZmVyKHBwcikNCiAgICBacHAzMyA9IHN0b3VmZmVyKHBwMzMpDQogICAgWnBwci5oYWxmID0gc3RvdWZmZXIocHByLmhhbGYpDQogICAgWnBwMzMuaGFsZiA9IHN0b3VmZmVyKHBwMzMuaGFsZikNCiAgICBwLlpwcHIgPSBwbm9ybShacHByKQ0KICAgIHAuWnBwMzMgPSBwbm9ybShacHAzMykNCiAgICBwLlpwcHIuaGFsZiA9IHBub3JtKFpwcHIuaGFsZikNCiAgICBwLlpwcDMzLmhhbGYgPSBwbm9ybShacHAzMy5oYWxmKQ0KICAgIG1haW4ucmVzdWx0cyA9IGFzLm51bWVyaWMoYyhrdG90LCBrc2lnLCBraGFsZiwgWnBwciwgcC5acHByLCANCiAgICAgICAgWnBwMzMsIHAuWnBwMzMsIFpwcHIuaGFsZiwgcC5acHByLmhhbGYsIFpwcDMzLmhhbGYsIHAuWnBwMzMuaGFsZikpDQogICAgcHJvcDI1Lm9icyA9IHN1bShwIDwgMC4wMjUpL3N1bShwIDwgMC4wNSkNCiAgICBiaW5vbS5yID0gMSAtIHBiaW5vbShxID0gcHJvcDI1Lm9icyAqIGtzaWcgLSAxLCBwcm9iID0gMC41LCANCiAgICAgICAgc2l6ZSA9IGtzaWcpDQogICAgYmlub20uMzMgPSBwcG9pYmluKGtrID0gcHJvcDI1Lm9icyAqIGtzaWcsIHBwID0gcHJvcDI1W3AgPCANCiAgICAgICAgMC4wNV0pDQogICAgYmlub21pYWwgPSBjKG1lYW4ocHJvcDI1LnNpZyksIHByb3AyNS5vYnMsIGJpbm9tLnIsIGJpbm9tLjMzKQ0KICAgIGNsZWFucCA9IGZ1bmN0aW9uKHApIHsNCiAgICAgICAgcC5jbGVhbiA9IHJvdW5kKHAsIDQpDQogICAgICAgIHAuY2xlYW4gPSBzdWJzdHIocC5jbGVhbiwgMiwgNikNCiAgICAgICAgcC5jbGVhbiA9IHBhc3RlMCgiPSAiLCBwLmNsZWFuKQ0KICAgICAgICBpZiAocCA8IDAuMDAwMSkgDQogICAgICAgICAgICBwLmNsZWFuID0gIiA8IC4wMDAxIg0KICAgICAgICBpZiAocCA+IDAuOTk5OSkgDQogICAgICAgICAgICBwLmNsZWFuID0gIiA+IC45OTk5Ig0KICAgICAgICByZXR1cm4ocC5jbGVhbikNCiAgICB9DQogICAgaWYgKGtoYWxmID09IDApIHsNCiAgICAgICAgWnBwci5oYWxmID0gIk4vQSINCiAgICAgICAgcC5acHByLmhhbGYgPSAiPU4vQSINCiAgICAgICAgWnBwMzMuaGFsZiA9ICJOL0EiDQogICAgICAgIHAuWnBwMzMuaGFsZiA9ICI9Ti9BIg0KICAgIH0NCiAgICBpZiAoa2hhbGYgPiAwKSB7DQogICAgICAgIFpwcHIuaGFsZiA9IHJvdW5kKFpwcHIuaGFsZiwgMikNCiAgICAgICAgWnBwMzMuaGFsZiA9IHJvdW5kKFpwcDMzLmhhbGYsIDIpDQogICAgICAgIHAuWnBwci5oYWxmID0gY2xlYW5wKHAuWnBwci5oYWxmKQ0KICAgICAgICBwLlpwcDMzLmhhbGYgPSBjbGVhbnAocC5acHAzMy5oYWxmKQ0KICAgIH0NCiAgICBacHByID0gcm91bmQoWnBwciwgMikNCiAgICBacHAzMyA9IHJvdW5kKFpwcDMzLCAyKQ0KICAgIHAuWnBwciA9IGNsZWFucChwLlpwcHIpDQogICAgcC5acHAzMyA9IGNsZWFucChwLlpwcDMzKQ0KICAgIGJpbm9tLnIgPSBjbGVhbnAoYmlub20ucikNCiAgICBiaW5vbS4zMyA9IGNsZWFucChiaW5vbS4zMykNCiAgICBwb3dlcmZpdCA9IGZ1bmN0aW9uKHBvd2VyX2VzdCkgew0KICAgICAgICBuY3BfZXN0ID0gbWFwcGx5KGdldG5jcCwgZGYxID0gZGYxLCBkZjIgPSBkZjIsIHBvd2VyID0gcG93ZXJfZXN0LCANCiAgICAgICAgICAgIGZhbWlseSA9IGZhbWlseSkNCiAgICAgICAgcHBfZXN0ID0gaWZlbHNlKGZhbWlseSA9PSAiZiIgJiBwIDwgMC4wNSwgKHBmKHZhbHVlLCANCiAgICAgICAgICAgIGRmMSA9IGRmMSwgZGYyID0gZGYyLCBuY3AgPSBuY3BfZXN0KSAtICgxIC0gcG93ZXJfZXN0KSkvcG93ZXJfZXN0LCANCiAgICAgICAgICAgIE5BKQ0KICAgICAgICBwcF9lc3QgPSBpZmVsc2UoZmFtaWx5ID09ICJjIiAmIHAgPCAwLjA1LCAocGNoaXNxKHZhbHVlLCANCiAgICAgICAgICAgIGRmID0gZGYxLCBuY3AgPSBuY3BfZXN0KSAtICgxIC0gcG93ZXJfZXN0KSkvcG93ZXJfZXN0LCANCiAgICAgICAgICAgIHBwX2VzdCkNCiAgICAgICAgcHBfZXN0ID0gcGJvdW5kKHBwX2VzdCkNCiAgICAgICAgcmV0dXJuKHN0b3VmZmVyKHBwX2VzdCkpDQogICAgfQ0KICAgIGZpdCA9IGMoKQ0KICAgIGZpdCA9IGFicyhwb3dlcmZpdCgwLjA1MSkpDQogICAgZm9yIChpIGluIDY6OTkpIGZpdCA9IGMoZml0LCBhYnMocG93ZXJmaXQoaS8xMDApKSkNCiAgICBtaW5pID0gbWF0Y2gobWluKGZpdCwgbmEucm0gPSBUUlVFKSwgZml0KQ0KICAgIGhhdCA9IChtaW5pICsgNCkvMTAwDQogICAgeC5wb3dlciA9IHNlcShmcm9tID0gNSwgdG8gPSA5OSkvMTAwDQogICAgZ2V0LnBvd2VyX3BjdCA9IGZ1bmN0aW9uKHBjdCkgew0KICAgICAgICB6ID0gcW5vcm0ocGN0KQ0KICAgICAgICBlcnJvciA9IGZ1bmN0aW9uKHBvd2VyX2VzdCwgeikgcG93ZXJmaXQocG93ZXJfZXN0KSAtIA0KICAgICAgICAgICAgeg0KICAgICAgICByZXR1cm4odW5pcm9vdChlcnJvciwgYygwLjA1MDEsIDAuOTkpLCB6KSRyb290KQ0KICAgIH0NCiAgICBwLnBvd2VyLjA1ID0gcG5vcm0ocG93ZXJmaXQoMC4wNTEpKQ0KICAgIHAucG93ZXIuOTkgPSBwbm9ybShwb3dlcmZpdCgwLjk5KSkNCiAgICBpZiAocC5wb3dlci4wNSA8PSAwLjk1KSANCiAgICAgICAgcG93ZXIuY2kubGIgPSAwLjA1DQogICAgaWYgKHAucG93ZXIuOTkgPj0gMC45NSkgDQogICAgICAgIHBvd2VyLmNpLmxiID0gMC45OQ0KICAgIGlmIChwLnBvd2VyLjA1ID4gMC45NSAmJiBwLnBvd2VyLjk5IDwgMC45NSkgDQogICAgICAgIHBvd2VyLmNpLmxiID0gZ2V0LnBvd2VyX3BjdCgwLjk1KQ0KICAgIGlmIChwLnBvd2VyLjA1IDw9IDAuMDUpIA0KICAgICAgICBwb3dlci5jaS51YiA9IDAuMDUNCiAgICBpZiAocC5wb3dlci45OSA+PSAwLjA1KSANCiAgICAgICAgcG93ZXIuY2kudWIgPSAwLjk5DQogICAgaWYgKHAucG93ZXIuMDUgPiAwLjA1ICYmIHAucG93ZXIuOTkgPCAwLjA1KSANCiAgICAgICAgcG93ZXIuY2kudWIgPSBnZXQucG93ZXJfcGN0KDAuMDUpDQogICAgcG93ZXJfcmVzdWx0cyA9IGMocG93ZXIuY2kubGIsIGhhdCwgcG93ZXIuY2kudWIpDQogICAgZ2NkZjEgPSBwcm9wMzMoMC4wMSkNCiAgICBnY2RmMiA9IHByb3AzMygwLjAyKQ0KICAgIGdjZGYzID0gcHJvcDMzKDAuMDMpDQogICAgZ2NkZjQgPSBwcm9wMzMoMC4wNCkNCiAgICBncmVlbjEgPSBtZWFuKGdjZGYxLCBuYS5ybSA9IFRSVUUpICogMw0KICAgIGdyZWVuMiA9IG1lYW4oZ2NkZjIgLSBnY2RmMSwgbmEucm0gPSBUUlVFKSAqIDMNCiAgICBncmVlbjMgPSBtZWFuKGdjZGYzIC0gZ2NkZjIsIG5hLnJtID0gVFJVRSkgKiAzDQogICAgZ3JlZW40ID0gbWVhbihnY2RmNCAtIGdjZGYzLCBuYS5ybSA9IFRSVUUpICogMw0KICAgIGdyZWVuNSA9IG1lYW4oMS8zIC0gZ2NkZjQsIG5hLnJtID0gVFJVRSkgKiAzDQogICAgZ3JlZW4gPSAxMDAgKiBjKGdyZWVuMSwgZ3JlZW4yLCBncmVlbjMsIGdyZWVuNCwgZ3JlZW41KQ0KICAgIHBzID0gY2VpbGluZyhwW3AgPCAwLjA1XSAqIDEwMCkvMTAwDQogICAgYmx1ZSA9IGMoKQ0KICAgIGZvciAoaSBpbiBjKDAuMDEsIDAuMDIsIDAuMDMsIDAuMDQsIDAuMDUpKSBibHVlID0gYyhibHVlLCANCiAgICAgICAgc3VtKHBzID09IGksIG5hLnJtID0gVFJVRSkva3NpZyAqIDEwMCkNCiAgICByZWQgPSBjKDIwLCAyMCwgMjAsIDIwLCAyMCkNCiAgICB4ID0gYygwLjAxLCAwLjAyLCAwLjAzLCAwLjA0LCAwLjA1KQ0KICAgIHBhcihtYXIgPSBjKDYsIDUuNSwgMS41LCAzKSkNCiAgICBtb3ZldXAgPSBtYXgobWF4KGJsdWVbMjo1XSkgLSA2NiwgMCkNCiAgICB5bGltID0gYygwLCAxMDUgKyBtb3ZldXApDQogICAgbGVnZW5kLnRvcCA9IDEwMCArIG1vdmV1cA0KICAgIHBsb3QoeCwgYmx1ZSwgdHlwZSA9ICJsIiwgY29sID0gImRvZGdlcmJsdWUyIiwgbWFpbiA9ICIiLCANCiAgICAgICAgbHdkID0gMiwgeGxhYiA9ICIiLCB5bGFiID0gIiIsIHhheHQgPSAibiIsIHlheHQgPSAibiIsIA0KICAgICAgICB4bGltID0gYygwLjAxLCAwLjA1MSksIHlsaW0gPSB5bGltLCBidHkgPSAiTCIsIGxhcyA9IDEsIA0KICAgICAgICBheGVzID0gRikNCiAgICB4XyA9IGMoIi4wMSIsICIuMDIiLCAiLjAzIiwgIi4wNCIsICIuMDUiKQ0KICAgIGF4aXMoMSwgYXQgPSB4LCBsYWJlbHMgPSB4XykNCiAgICB5XyA9IGMoIjAlIiwgIjI1JSIsICI1MCUiLCAiNzUlIiwgIjEwMCUiKQ0KICAgIHkgPSBjKDAsIDI1LCA1MCwgNzUsIDEwMCkNCiAgICBheGlzKDIsIGF0ID0geSwgbGFiZWxzID0geV8sIGxhcyA9IDEsIGNleC5heGlzID0gMS4yKQ0KICAgIG10ZXh0KCJQZXJjZW50YWdlIG9mIHRlc3QgcmVzdWx0cyIsIGZvbnQgPSAyLCBzaWRlID0gMiwgbGluZSA9IDMuODUsIA0KICAgICAgICBjZXggPSAxLjI1KQ0KICAgIG10ZXh0KCJwICAgICAgICAgICAgIiwgZm9udCA9IDQsIHNpZGUgPSAxLCBsaW5lID0gMi4zLCBjZXggPSAxLjI1KQ0KICAgIG10ZXh0KCIgLXZhbHVlIiwgZm9udCA9IDIsIHNpZGUgPSAxLCBsaW5lID0gMi4zLCBjZXggPSAxLjUpDQogICAgcG9pbnRzKHgsIGJsdWUsIHR5cGUgPSAicCIsIHBjaCA9IDIwLCBiZyA9ICJkb2RnZXJibHVlMiIsIA0KICAgICAgICBjb2wgPSAiZG9kZ2VyYmx1ZTIiKQ0KICAgIHRleHQoeCArIDAuMDAwNzUsIGJsdWUgKyAzLjUsIHBlcmNlbnQocm91bmQoYmx1ZSkvMTAwKSwgY29sID0gImJsYWNrIiwgDQogICAgICAgIGNleCA9IDAuNzUpDQogICAgbGluZXMoeCwgcmVkLCB0eXBlID0gImwiLCBjb2wgPSAiZmlyZWJyaWNrMiIsIGx3ZCA9IDEuMjUsIA0KICAgICAgICBsdHkgPSAzKQ0KICAgIGxpbmVzKHgsIGdyZWVuLCB0eXBlID0gImwiLCBjb2wgPSAic3ByaW5nZ3JlZW40IiwgbHdkID0gMS41LCANCiAgICAgICAgbHR5ID0gNSkNCiAgICB0YWIxID0gMC4wMTcNCiAgICB0YWIyID0gdGFiMSArIDAuMDAxNQ0KICAgIGdhcDEgPSA5DQogICAgZ2FwMiA9IDQNCiAgICBmb250LmNvbCA9ICJncmF5NDQiDQogICAgdGV4dC5ibHVlID0gcGFzdGUwKCJQb3dlciBlc3RpbWF0ZTogIiwgcGVyY2VudChoYXQpLCAiLCBDSSgiLCANCiAgICAgICAgcGVyY2VudChwb3dlci5jaS5sYiksICIsIiwgcGVyY2VudChwb3dlci5jaS51YiksICIpIikNCiAgICB0ZXh0KHRhYjEsIGxlZ2VuZC50b3AsIGFkaiA9IDAsIGNleCA9IDAuODUsIGJxdW90ZSgiT2JzZXJ2ZWQgIiAqIA0KICAgICAgICBpdGFsaWMocCkgKiAiLWN1cnZlIikpDQogICAgdGV4dCh0YWIyLCBsZWdlbmQudG9wIC0gZ2FwMiwgYWRqID0gMCwgY2V4ID0gMC42OCwgdGV4dC5ibHVlLCANCiAgICAgICAgY29sID0gZm9udC5jb2wpDQogICAgdGV4dC5yZWQgPSBicXVvdGUoIlRlc3RzIGZvciByaWdodC1za2V3bmVzczogIiAqIGl0YWxpYyhwKSAqIA0KICAgICAgICAiIltGdWxsXSB+IC4ocC5acHByKSAqICIsICAiICogaXRhbGljKHApICogIiJbSGFsZl0gfiANCiAgICAgICAgLihwLlpwcHIuaGFsZikpDQogICAgdGV4dCh0YWIxLCBsZWdlbmQudG9wIC0gZ2FwMSwgYWRqID0gMCwgY2V4ID0gMC44NSwgIk51bGwgb2Ygbm8gZWZmZWN0IikNCiAgICB0ZXh0KHRhYjIsIGxlZ2VuZC50b3AgLSBnYXAxIC0gZ2FwMiwgYWRqID0gMCwgY2V4ID0gMC42OCwgDQogICAgICAgIHRleHQucmVkLCBjb2wgPSBmb250LmNvbCkNCiAgICB0ZXh0LmdyZWVuID0gYnF1b3RlKCJUZXN0cyBmb3IgZmxhdG5lc3M6ICIgKiBpdGFsaWMocCkgKiANCiAgICAgICAgIiJbRnVsbF0gfiAuKHAuWnBwMzMpICogIiwgICIgKiBpdGFsaWMocCkgKiAiIltoYWxmXSB+IA0KICAgICAgICAuKHAuWnBwMzMuaGFsZikgKiAiLCAgIiAqIGl0YWxpYyhwKSAqICIiW0Jpbm9taWFsXSB+IA0KICAgICAgICAuKGJpbm9tLjMzKSkNCiAgICB0ZXh0KHRhYjEsIGxlZ2VuZC50b3AgLSAyICogZ2FwMSwgYWRqID0gMCwgY2V4ID0gMC44NSwgIk51bGwgb2YgMzMlIHBvd2VyIikNCiAgICB0ZXh0KHRhYjIsIGxlZ2VuZC50b3AgLSAyICogZ2FwMSAtIGdhcDIsIGFkaiA9IDAsIGNleCA9IDAuNjgsIA0KICAgICAgICB0ZXh0LmdyZWVuLCBjb2wgPSBmb250LmNvbCkNCiAgICBzZWdtZW50cyh4MCA9IHRhYjEgLSAwLjAwNSwgeDEgPSB0YWIxIC0gMC4wMDEsIHkwID0gbGVnZW5kLnRvcCwgDQogICAgICAgIHkxID0gbGVnZW5kLnRvcCwgY29sID0gImRvZGdlcmJsdWUyIiwgbHR5ID0gMSwgbHdkID0gMS41KQ0KICAgIHNlZ21lbnRzKHgwID0gdGFiMSAtIDAuMDA1LCB4MSA9IHRhYjEgLSAwLjAwMSwgeTAgPSBsZWdlbmQudG9wIC0gDQogICAgICAgIGdhcDEsIHkxID0gbGVnZW5kLnRvcCAtIGdhcDEsIGNvbCA9ICJmaXJlYnJpY2syIiwgbHR5ID0gMywgDQogICAgICAgIGx3ZCA9IDEuNSkNCiAgICBzZWdtZW50cyh4MCA9IHRhYjEgLSAwLjAwNSwgeDEgPSB0YWIxIC0gMC4wMDEsIHkwID0gbGVnZW5kLnRvcCAtIA0KICAgICAgICAyICogZ2FwMSwgeTEgPSBsZWdlbmQudG9wIC0gMiAqIGdhcDEsIGNvbCA9ICJzcHJpbmdncmVlbjQiLCANCiAgICAgICAgbHR5ID0gMiwgbHdkID0gMS41KQ0KICAgIHJlY3QodGFiMSAtIDAuMDA2NSwgbGVnZW5kLnRvcCAtIDIgKiBnYXAxIC0gZ2FwMiAtIDMsIHRhYjEgKyANCiAgICAgICAgMC4wMzIsIGxlZ2VuZC50b3AgKyAzLCBib3JkZXIgPSAiZ3JheTg1IikNCiAgICBtc2d4ID0gYnF1b3RlKCJOb3RlOiBUaGUgb2JzZXJ2ZWQgIiAqIGl0YWxpYyhwKSAqICItY3VydmUgaW5jbHVkZXMgIiAqIA0KICAgICAgICAuKGtzaWcpICogIiBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50ICgiICogaXRhbGljKHApICogDQogICAgICAgICIgPCAuMDUpIHJlc3VsdHMsIG9mIHdoaWNoICIgKiAuKGtoYWxmKSAqICIgYXJlICIgKiBpdGFsaWMocCkgKiANCiAgICAgICAgIiA8IC4wMjUuIikNCiAgICBtdGV4dChtc2d4LCBzaWRlID0gMSwgbGluZSA9IDQsIGNleCA9IDAuOSwgYWRqID0gMCkNCiAgICBrbnMgPSBrdG90IC0ga3NpZw0KICAgIGlmIChrbnMgPT0gMCkgDQogICAgICAgIG5zX21zZyA9ICJUaGVyZSB3ZXJlIG5vIG5vbi1zaWduaWZpY2FudCByZXN1bHRzIGVudGVyZWQuIg0KICAgIGlmIChrbnMgPT0gMSkgDQogICAgICAgIG5zX21zZyA9IGJxdW90ZSgiVGhlcmUgd2FzIG9uZSBhZGRpdGlvbmFsIHJlc3VsdCBlbnRlcmVkIGJ1dCBleGNsdWRlZCBmcm9tICIgKiANCiAgICAgICAgICAgIGl0YWxpYyhwKSAqICItY3VydmUgYmVjYXVzZSBpdCB3YXMgIiAqIGl0YWxpYyhwKSAqIA0KICAgICAgICAgICAgIiA+IC4wNS4iKQ0KICAgIGlmIChrbnMgPiAxKSANCiAgICAgICAgbnNfbXNnID0gYnF1b3RlKCJUaGVyZSB3ZXJlICIgKiAuKGtucykgKiAiIGFkZGl0aW9uYWwgcmVzdWx0cyBlbnRlcmVkIGJ1dCBleGNsdWRlZCBmcm9tICIgKiANCiAgICAgICAgICAgIGl0YWxpYyhwKSAqICItY3VydmUgYmVjYXVzZSB0aGV5IHdlcmUgIiAqIGl0YWxpYyhwKSAqIA0KICAgICAgICAgICAgIiA+IC4wNS4iKQ0KICAgIG10ZXh0KG5zX21zZywgc2lkZSA9IDEsIGxpbmUgPSA0Ljc1LCBjZXggPSAwLjksIGFkaiA9IDApDQogICAgdGFibGVfY2FsYyA9IGRhdGEuZnJhbWUocmF3LCBwLCBwcHIsIHBwci5oYWxmLCBwcDMzLCBwcDMzLmhhbGYsIA0KICAgICAgICBxbm9ybShwcHIpLCBxbm9ybShwcHIuaGFsZiksIHFub3JtKHBwMzMpLCBxbm9ybShwcDMzLmhhbGYpKQ0KICAgIGhlYWRlcnMxID0gYygiRW50ZXJlZCBzdGF0aXN0aWMiLCAicC12YWx1ZSIsICJwcHIiLCAicHByIGhhbGYiLCANCiAgICAgICAgInBwMzMlIiwgInBwMzMgaGFsZiIsICJaLVIiLCAiWi1SIGhhbGYiLCAiWi0zMyIsICJ6LTMzIGhhbGYiKQ0KICAgIHRhYmxlX2NhbGMgPSBzZXROYW1lcyh0YWJsZV9jYWxjLCBoZWFkZXJzMSkNCiAgICBoZWFkZXJzMiA9IGMoInAtdmFsdWUiLCAiT2JzZXJ2ZWQgKGJsdWUpIiwgIlBvd2VyIDMzJSAoR3JlZW4pIiwgDQogICAgICAgICJGbGF0IChSZWQpIikNCiAgICB0YWJsZV9maWd1cmUgPSBzZXROYW1lcyhkYXRhLmZyYW1lKHgsIGJsdWUsIGdyZWVuLCByZWQpLCANCiAgICAgICAgaGVhZGVyczIpDQogICAgZHJvcGsgPSBmdW5jdGlvbihwcCwgaywgZHJvcGxvdykgew0KICAgICAgICBwcCA9IHBwWyFpcy5uYShwcCldDQogICAgICAgIG4gPSBsZW5ndGgocHApDQogICAgICAgIHBwID0gc29ydChwcCkNCiAgICAgICAgaWYgKGsgPT0gMCkgDQogICAgICAgICAgICBwcGsgPSBwcA0KICAgICAgICBpZiAoZHJvcGxvdyA9PSAxICYgayA+IDApIHsNCiAgICAgICAgICAgIHBwayA9IChwcFsoMSArIGspOm5dKQ0KICAgICAgICAgICAgcHBtaW4gPSBtaW4ocHBba10sIGsvKG4gKyAxKSkNCiAgICAgICAgICAgIHBwayA9IChwcGsgLSBwcG1pbikvKDEgLSBwcG1pbikNCiAgICAgICAgfQ0KICAgICAgICBpZiAoZHJvcGxvdyA9PSAwICYgayA+IDApIHsNCiAgICAgICAgICAgIHBwayA9IHBwWzE6KG4gLSBrKV0NCiAgICAgICAgICAgIHBwbWF4ID0gbWF4KHBwW24gLSBrICsgMV0sIChuIC0gaykvKG4gKyAxKSkNCiAgICAgICAgICAgIHBwayA9IHBway9wcG1heA0KICAgICAgICB9DQogICAgICAgIHBwayA9IHBtYXgocHBrLCAwLjAwMDAxKQ0KICAgICAgICBwcGsgPSBwbWluKHBwaywgMC45OTk5OSkNCiAgICAgICAgWiA9IHN1bShxbm9ybShwcGspKS9zcXJ0KG4gLSBrKQ0KICAgICAgICByZXR1cm4ocG5vcm0oWikpDQogICAgfQ0KICAgIGRyb3Bsb3cuciA9IGRyb3Bsb3cuMzMgPSBkcm9waGlnaC5yID0gZHJvcGhpZ2guMzMgPSBjKCkNCiAgICBmb3IgKGkgaW4gMDoocm91bmQoa3NpZy8yKSAtIDEpKSB7DQogICAgICAgIGRyb3Bsb3cuciA9IGMoZHJvcGxvdy5yLCBkcm9wayhwcCA9IHBwciwgayA9IGksIGRyb3Bsb3cgPSAxKSkNCiAgICAgICAgZHJvcGhpZ2guciA9IGMoZHJvcGhpZ2guciwgZHJvcGsocHAgPSBwcHIsIGsgPSBpLCBkcm9wbG93ID0gMCkpDQogICAgICAgIGRyb3Bsb3cuMzMgPSBjKGRyb3Bsb3cuMzMsIGRyb3BrKHBwID0gcHAzMywgayA9IGksIGRyb3Bsb3cgPSAxKSkNCiAgICAgICAgZHJvcGhpZ2guMzMgPSBjKGRyb3BoaWdoLjMzLCBkcm9wayhwcCA9IHBwMzMsIGsgPSBpLCANCiAgICAgICAgICAgIGRyb3Bsb3cgPSAwKSkNCiAgICB9DQogICAgaWYgKGtoYWxmID4gMCkgew0KICAgICAgICBkcm9wbG93LmhhbGZyID0gZHJvcGhpZ2guaGFsZnIgPSBjKCkNCiAgICAgICAgZm9yIChpIGluIDA6KHJvdW5kKGtoYWxmLzIpIC0gMSkpIHsNCiAgICAgICAgICAgIGRyb3Bsb3cuaGFsZnIgPSBjKGRyb3Bsb3cuaGFsZnIsIGRyb3BrKHBwID0gcHByLmhhbGYsIA0KICAgICAgICAgICAgICAgIGsgPSBpLCBkcm9wbG93ID0gMSkpDQogICAgICAgICAgICBkcm9waGlnaC5oYWxmciA9IGMoZHJvcGhpZ2guaGFsZnIsIGRyb3BrKHBwID0gcHByLmhhbGYsIA0KICAgICAgICAgICAgICAgIGsgPSBpLCBkcm9wbG93ID0gMCkpDQogICAgICAgIH0NCiAgICB9DQogICAgcGxvdGRyb3AgPSBmdW5jdGlvbih2YXIsIGNvbCkgew0KICAgICAgICBrID0gbGVuZ3RoKHZhcikNCiAgICAgICAgcGxvdCgwOihrIC0gMSksIHZhciwgeGxhYiA9ICIiLCB5bGFiID0gIiIsIHR5cGUgPSAiYiIsIA0KICAgICAgICAgICAgeWF4dCA9ICJuIiwgeGF4dCA9ICJuIiwgbWFpbiA9ICIiLCBjZXgubWFpbiA9IDEuMTUsIA0KICAgICAgICAgICAgeWxpbSA9IGMoMCwgMSksIGNvbCA9IGNvbCkNCiAgICAgICAgcG9pbnRzKDAsIHZhclsxXSwgcGNoID0gMTksIGNleCA9IDEuNikNCiAgICAgICAgYWJsaW5lKGggPSAwLjA1LCBjb2wgPSAicmVkIikNCiAgICAgICAgYXhpcygyLCBjKDAuMDUsIDI6OS8xMCksIGxhYmVscyA9IGMoIi4wNSIsICIuMiIsICIuMyIsIA0KICAgICAgICAgICAgIi40IiwgIi41IiwgIjYiLCAiNyIsICIuOCIsICIuOSIpLCBsYXMgPSAxLCBjZXguYXhpcyA9IDEuNSkNCiAgICAgICAgYXhpcygxLCBjKDA6KGsgLSAxKSksIGxhcyA9IDEsIGNleC5heGlzID0gMS40KQ0KICAgIH0NCiAgICBpZiAoZWZmZWN0LmVzdGltYXRpb24gPT0gVFJVRSkgew0KICAgICAgICBjaS50by50ID0gZnVuY3Rpb24oVEUsIGxvd2VyLCB1cHBlciwgbikgew0KICAgICAgICAgICAgei50by5kID0gZnVuY3Rpb24oeiwgbikgew0KICAgICAgICAgICAgICAgIGQgPSAoMiAqIHopL3NxcnQobikNCiAgICAgICAgICAgICAgICByZXR1cm4oYWJzKGQpKQ0KICAgICAgICAgICAgfQ0KICAgICAgICAgICAgY2kudG8ucCA9IGZ1bmN0aW9uKGVzdCwgbG93ZXIsIHVwcGVyKSB7DQogICAgICAgICAgICAgICAgU0UgPSAodXBwZXIgLSBsb3dlcikvKDIgKiAxLjk2KQ0KICAgICAgICAgICAgICAgIHogPSBhYnMoZXN0L1NFKQ0KICAgICAgICAgICAgICAgIHAgPSBleHAoLTAuNzE3ICogeiAtIDAuNDE2ICogel4yKQ0KICAgICAgICAgICAgICAgIHJldHVybihwKQ0KICAgICAgICAgICAgfQ0KICAgICAgICAgICAgZC50by50ID0gZnVuY3Rpb24oZCwgbikgew0KICAgICAgICAgICAgICAgIGRmID0gbiAtIDINCiAgICAgICAgICAgICAgICB0ID0gKGQgKiBzcXJ0KGRmKSkvMg0KICAgICAgICAgICAgICAgIHJldHVybih0KQ0KICAgICAgICAgICAgfQ0KICAgICAgICAgICAgcCA9IGNpLnRvLnAoVEUsIGxvd2VyLCB1cHBlcikNCiAgICAgICAgICAgIHogPSBhYnMocW5vcm0ocC8yKSkNCiAgICAgICAgICAgIGQgPSB6LnRvLmQoeiwgbikNCiAgICAgICAgICAgIHQgPSBkLnRvLnQoZCwgbikNCiAgICAgICAgICAgIHJldHVybih0KQ0KICAgICAgICB9DQogICAgICAgIGxvc3MgPSBmdW5jdGlvbih0X29icywgZGZfb2JzLCBkX2VzdCkgew0KICAgICAgICAgICAgdF9vYnMgPSBhYnModF9vYnMpDQogICAgICAgICAgICBwX29icyA9IDIgKiAoMSAtIHB0KHRfb2JzLCBkZiA9IGRmX29icykpDQogICAgICAgICAgICB0LnNpZyA9IHN1YnNldCh0X29icywgcF9vYnMgPCAwLjA1KQ0KICAgICAgICAgICAgZGYuc2lnID0gc3Vic2V0KGRmX29icywgcF9vYnMgPCAwLjA1KQ0KICAgICAgICAgICAgbmNwX2VzdCA9IHNxcnQoKGRmLnNpZyArIDIpLzQpICogZF9lc3QNCiAgICAgICAgICAgIHRjID0gcXQoMC45NzUsIGRmLnNpZykNCiAgICAgICAgICAgIHBvd2VyX2VzdCA9IDEgLSBwdCh0YywgZGYuc2lnLCBuY3BfZXN0KQ0KICAgICAgICAgICAgcF9sYXJnZXIgPSBwdCh0LnNpZywgZGYgPSBkZi5zaWcsIG5jcCA9IG5jcF9lc3QpDQogICAgICAgICAgICBwcHIgPSAocF9sYXJnZXIgLSAoMSAtIHBvd2VyX2VzdCkpL3Bvd2VyX2VzdA0KICAgICAgICAgICAgS1NEID0ga3MudGVzdChwcHIsIHB1bmlmKSRzdGF0aXN0aWMNCiAgICAgICAgICAgIHJldHVybihLU0QpDQogICAgICAgIH0NCiAgICAgICAgaWYgKG1pc3NpbmcoTikpIHsNCiAgICAgICAgICAgIHN0b3AoIklmICdlZmZlY3QuZXN0aW1hdGlvbj1UUlVFJywgYXJndW1lbnQgJ04nIG11c3QgYmUgcHJvdmlkZWQuIikNCiAgICAgICAgfQ0KICAgICAgICBpZiAobGVuZ3RoKE4pICE9IGxlbmd0aChtZXRhb2JqZWN0JFRFKSkgew0KICAgICAgICAgICAgc3RvcCgiTiBtdXN0IGJlIG9mIHNhbWUgbGVuZ3RoIGFzIHRoZSBudW1iZXIgb2Ygc3R1ZGllcyBjb250YWluZWQgaW4geC4iKQ0KICAgICAgICB9DQogICAgICAgIGxvd2VyID0gbWV0YW9iamVjdCRURSAtIChtZXRhb2JqZWN0JHNlVEUgKiAxLjk2KQ0KICAgICAgICB1cHBlciA9IG1ldGFvYmplY3QkVEUgKyAobWV0YW9iamVjdCRzZVRFICogMS45NikNCiAgICAgICAgdF9vYnMgPSBjaS50by50KG1ldGFvYmplY3QkVEUsIGxvd2VyLCB1cHBlciwgTikNCiAgICAgICAgZGZfb2JzID0gTiAtIDINCiAgICAgICAgbG9zcy5hbGwgPSBjKCkNCiAgICAgICAgZGkgPSBjKCkNCiAgICAgICAgZm9yIChpIGluIDA6KChkbWF4IC0gZG1pbikgKiAxMDApKSB7DQogICAgICAgICAgICBkID0gZG1pbiArIGkvMTAwDQogICAgICAgICAgICBkaSA9IGMoZGksIGQpDQogICAgICAgICAgICBvcHRpb25zKHdhcm4gPSAtMSkNCiAgICAgICAgICAgIGxvc3MuYWxsID0gYyhsb3NzLmFsbCwgbG9zcyhkZl9vYnMgPSBkZl9vYnMsIHRfb2JzID0gdF9vYnMsIA0KICAgICAgICAgICAgICAgIGRfZXN0ID0gZCkpDQogICAgICAgICAgICBvcHRpb25zKHdhcm4gPSAwKQ0KICAgICAgICB9DQogICAgICAgIGltaW4gPSBtYXRjaChtaW4obG9zcy5hbGwpLCBsb3NzLmFsbCkNCiAgICAgICAgZHN0YXJ0ID0gZG1pbiArIGltaW4vMTAwDQogICAgICAgIGRoYXQgPSBvcHRpbWl6ZShsb3NzLCBjKGRzdGFydCAtIDAuMSwgZHN0YXJ0ICsgMC4xKSwgDQogICAgICAgICAgICBkZl9vYnMgPSBkZl9vYnMsIHRfb2JzID0gdF9vYnMpDQogICAgICAgIG9wdGlvbnMod2FybiA9IC0wKQ0KICAgICAgICBwbG90KGRpLCBsb3NzLmFsbCwgeGxhYiA9ICJFZmZlY3Qgc2l6ZVxuQ29oZW4tZCIsIHlsYWIgPSAiTG9zcyAoRCBzdGF0IGluIEtTIHRlc3QpIiwgDQogICAgICAgICAgICB5bGltID0gYygwLCAxKSwgbWFpbiA9ICJIb3cgd2VsbCBkb2VzIGVhY2ggZWZmZWN0IHNpemUgZml0PyAobG93ZXIgaXMgYmV0dGVyKSIpDQogICAgICAgIHBvaW50cyhkaGF0JG1pbmltdW0sIGRoYXQkb2JqZWN0aXZlLCBwY2ggPSAxOSwgY29sID0gInJlZCIsIA0KICAgICAgICAgICAgY2V4ID0gMikNCiAgICAgICAgdGV4dChkaGF0JG1pbmltdW0sIGRoYXQkb2JqZWN0aXZlIC0gMC4wOCwgcGFzdGUwKCJwLWN1cnZlJ3MgZXN0aW1hdGUgb2YgZWZmZWN0IHNpemU6XG5kPSIsIA0KICAgICAgICAgICAgcm91bmQoZGhhdCRtaW5pbXVtLCAzKSksIGNvbCA9ICJyZWQiKQ0KICAgIH0NCiAgICBtYWluLnJlc3VsdHMgPSByb3VuZChtYWluLnJlc3VsdHMsIDMpDQogICAga3RvdGFsID0gcm91bmQobWFpbi5yZXN1bHRzWzFdKQ0KICAgIGsuc2lnbiA9IHJvdW5kKG1haW4ucmVzdWx0c1syXSkNCiAgICBrLjAyNSA9IHJvdW5kKG1haW4ucmVzdWx0c1szXSkNCiAgICBza2V3LmZ1bGwueiA9IG1haW4ucmVzdWx0c1s0XQ0KICAgIHNrZXcuZnVsbC5wID0gbWFpbi5yZXN1bHRzWzVdDQogICAgZmxhdC5mdWxsLnogPSBtYWluLnJlc3VsdHNbNl0NCiAgICBmbGF0LmZ1bGwucCA9IG1haW4ucmVzdWx0c1s3XQ0KICAgIHNrZXcuaGFsZi56ID0gbWFpbi5yZXN1bHRzWzhdDQogICAgc2tldy5oYWxmLnAgPSBtYWluLnJlc3VsdHNbOV0NCiAgICBmbGF0LmhhbGYueiA9IG1haW4ucmVzdWx0c1sxMF0NCiAgICBmbGF0LmhhbGYucCA9IG1haW4ucmVzdWx0c1sxMV0NCiAgICBza2V3LmJpbm9taWFsLnAgPSByb3VuZChiaW5vbWlhbFszXSwgMykNCiAgICBmbGF0LmJpbm9taWFsLnAgPSByb3VuZChiaW5vbWlhbFs0XSwgMykNCiAgICBza2V3bmVzcyA9IGMoc2tldy5iaW5vbWlhbC5wLCBza2V3LmZ1bGwueiwgc2tldy5mdWxsLnAsIHNrZXcuaGFsZi56LCANCiAgICAgICAgc2tldy5oYWxmLnApDQogICAgZmxhdG5lc3MgPSBjKGZsYXQuYmlub21pYWwucCwgZmxhdC5mdWxsLnosIGZsYXQuZnVsbC5wLCBmbGF0LmhhbGYueiwgDQogICAgICAgIGZsYXQuaGFsZi5wKQ0KICAgIGNvbG5hbWVzLmRmID0gYygicEJpbm9taWFsIiwgInpGdWxsIiwgInBGdWxsIiwgInpIYWxmIiwgInBIYWxmIikNCiAgICByb3duYW1lcy5kZiA9IGMoIlJpZ2h0LXNrZXduZXNzIHRlc3QiLCAiRmxhdG5lc3MgdGVzdCIpDQogICAgcGN1cnZlUmVzdWx0cyA9IHJiaW5kKHNrZXduZXNzLCBmbGF0bmVzcykNCiAgICBjb2xuYW1lcyhwY3VydmVSZXN1bHRzKSA9IGNvbG5hbWVzLmRmDQogICAgcm93bmFtZXMocGN1cnZlUmVzdWx0cykgPSByb3duYW1lcy5kZg0KICAgIHBvd2VyX3Jlc3VsdHMgPSByb3VuZChwb3dlcl9yZXN1bHRzLCAzKQ0KICAgIHBvd2VyRXN0aW1hdGUgPSBwb3dlcl9yZXN1bHRzWzJdDQogICAgcG93ZXJMb3dlciA9IHBvd2VyX3Jlc3VsdHNbMV0NCiAgICBwb3dlclVwcGVyID0gcG93ZXJfcmVzdWx0c1szXQ0KICAgIFBvd2VyID0gYXMuZGF0YS5mcmFtZShjYmluZChwb3dlckVzdGltYXRlLCBwb3dlckxvd2VyLCBwb3dlclVwcGVyKSkNCiAgICByb3duYW1lcyhQb3dlcikgPSAiIg0KICAgIGlmIChza2V3LmhhbGYucCA8IDAuMDUgfCAoc2tldy5oYWxmLnAgPCAwLjEgJiBza2V3LmZ1bGwucCA8IA0KICAgICAgICAwLjEpKSB7DQogICAgICAgIHByZXNlbmNlLmV2ID0gInllcyINCiAgICB9DQogICAgZWxzZSB7DQogICAgICAgIHByZXNlbmNlLmV2ID0gIm5vIg0KICAgIH0NCiAgICBpZiAoZmxhdC5mdWxsLnAgPCAwLjA1IHwgKGZsYXQuaGFsZi5wIDwgMC4xICYgZmxhdC5iaW5vbWlhbC5wIDwgDQogICAgICAgIDAuMSkpIHsNCiAgICAgICAgYWJzZW5jZS5ldiA9ICJ5ZXMiDQogICAgfQ0KICAgIGVsc2Ugew0KICAgICAgICBhYnNlbmNlLmV2ID0gIm5vIg0KICAgIH0NCiAgICBQbG90RGF0YSA9IHJvdW5kKHRhYmxlX2ZpZ3VyZSwgMykNCiAgICB0YWJsZV9jYWxjWywgMV0gPSBOVUxMDQogICAgY29sbmFtZXModGFibGVfY2FsYykgPSBjKCJwIiwgInBwU2tld0Z1bGwiLCAicHBTa2V3SGFsZiIsIA0KICAgICAgICAicHBGbGF0RnVsbCIsICJwcEZsYXRIYWxmIiwgInpTa2V3RnVsbCIsICJ6U2tld0hhbGYiLCANCiAgICAgICAgInpGbGF0RnVsbCIsICJ6RmxhdEhhbGYiKQ0KICAgIElucHV0ID0gY2JpbmQobWV0YW9iamVjdCRURSwgcm91bmQodGFibGVfY2FsYywgMykpDQogICAgcm93bmFtZXMoSW5wdXQpID0gcGFzdGUoMTpsZW5ndGgobWV0YW9iamVjdCRURSksIG1ldGFvYmplY3Qkc3R1ZGxhYikNCiAgICBjb2xuYW1lcyhJbnB1dClbMV0gPSAiVEUiDQogICAgaWYgKGVmZmVjdC5lc3RpbWF0aW9uID09IFRSVUUpIHsNCiAgICAgICAgZEVzdGltYXRlID0gcm91bmQoZGhhdCRtaW5pbXVtLCAzKQ0KICAgICAgICByZXR1cm4ubGlzdCA9IGxpc3QocGN1cnZlUmVzdWx0cyA9IHBjdXJ2ZVJlc3VsdHMsIFBvd2VyID0gUG93ZXIsIA0KICAgICAgICAgICAgUGxvdERhdGEgPSBQbG90RGF0YSwgSW5wdXQgPSBJbnB1dCwgRXZpZGVuY2VQcmVzZW50ID0gcHJlc2VuY2UuZXYsIA0KICAgICAgICAgICAgRXZpZGVuY2VBYnNlbnQgPSBhYnNlbmNlLmV2LCBrSW5wdXQgPSBrdG90LCBrQW5hbHl6ZWQgPSBrLnNpZ24sIA0KICAgICAgICAgICAga3AwLjI1ID0gay4wMjUsIGRFc3RpbWF0ZSA9IGRFc3RpbWF0ZSwgSTIgPSBtZXRhb2JqZWN0JEkyLCANCiAgICAgICAgICAgIGNsYXNzLm1ldGEub2JqZWN0ID0gY2xhc3MobWV0YW9iamVjdClbMV0pDQogICAgICAgIGNsYXNzKHJldHVybi5saXN0KSA9IGMoInBjdXJ2ZSIsICJlZmZlY3QuZXN0aW1hdGlvbiIpDQogICAgfQ0KICAgIGVsc2Ugew0KICAgICAgICByZXR1cm4ubGlzdCA9IGxpc3QocGN1cnZlUmVzdWx0cyA9IHBjdXJ2ZVJlc3VsdHMsIFBvd2VyID0gUG93ZXIsIA0KICAgICAgICAgICAgUGxvdERhdGEgPSBQbG90RGF0YSwgSW5wdXQgPSBJbnB1dCwgRXZpZGVuY2VQcmVzZW50ID0gcHJlc2VuY2UuZXYsIA0KICAgICAgICAgICAgRXZpZGVuY2VBYnNlbnQgPSBhYnNlbmNlLmV2LCBrSW5wdXQgPSBrdG90LCBrQW5hbHl6ZWQgPSBrLnNpZ24sIA0KICAgICAgICAgICAga3AwLjI1ID0gay4wMjUsIEkyID0gbWV0YW9iamVjdCRJMiwgY2xhc3MubWV0YS5vYmplY3QgPSBjbGFzcyhtZXRhb2JqZWN0KVsxXSkNCiAgICAgICAgY2xhc3MocmV0dXJuLmxpc3QpID0gYygicGN1cnZlIiwgIm5vLmVmZmVjdC5lc3RpbWF0aW9uIikNCiAgICB9DQogICAgY2F0KCIgICIsICJcbiIpDQogICAgaW52aXNpYmxlKHJldHVybi5saXN0KQ0KICAgIHJldHVybi5saXN0DQp9DQoNCiMgdGhpcyBpcyByZXF1aXJlZCBmb3IgcGN1cnZlIGZ1bmN0aW9uDQpsaWJyYXJ5KHBvaWJpbikNCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyBEcmF3aW5nIHN0YXJ0cyBoZXJlICMjIw0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KDQpwX2RhdCA8LSBkYXRhLmZyYW1lKCJzdHVkbGFiIiA9IGFzLmZhY3RvcigxOm5yb3coZGF0MikpLCAiVEUiID0gZGF0MiR5aSwgInNlVEUiID0gZGF0MiRzZWkpDQojcGN1cnZlKHBfZGF0KQ0KDQpwZGYoTlVMTCkNCmRldi5jb250cm9sKGRpc3BsYXlsaXN0PSJlbmFibGUiKQ0KcGFyKG1hcj1jKDQsNCwwLDApICsgMC4xLCBjZXggPSAxLjIpICMgTk9URTogaGVyZSBpcyB3aGVyZSB5b3UgY2FuIGNoYW5nZSB0aGUgZm9udCBzaXplIGZvciBhdCBsZWFzdCBzb21lIHBhcnRzIG9mIHRoZSBncmFwaC4gRS5nLiBhZGQgY2V4ID0gMiAtIHRoaXMgZGlkIG9udCBzZWVtIHRvIHdvcmsgd2VsbC4gDQppbnZpc2libGUocGN1cnZlMihwX2RhdCkpDQojbXRleHQobXNneCwgc2lkZSA9IDEsIGxpbmUgPSA0LCBjZXggPSAyLCBhZGogPSAwKQ0KcGxvdDwtIHJlY29yZFBsb3QoKQ0KaW52aXNpYmxlKGRldi5vZmYoKSkNCg0KIyB0dXJ1bmluZyB0aGUgYmFzZSBwbG90IGludG8gZ2dwbG90DQpwbG90IDwtIGdnZHJhdyhwbG90KQ0KDQojZGF0Mg0KDQptb2RlbCA8LSBybWEoeWksIHZpID0gdmksIGRhdGEgPSBkYXQyLCBtZXRob2QgPSAiTUwiLCBtb2QgPSB+IHhpKQ0KDQojIG9ubHkgc2VsMSBhbmQgc2VsMyBhcmUgdXNlZA0KI3NlbDAgPC0gc2VsbW9kZWwobW9kZWwsIHR5cGUgPSAiYmV0YSIpDQpzZWwxIDwtIHNlbG1vZGVsKG1vZGVsLCB0eXBlPSJoYWxmbm9ybSIsIHByZWM9InNlaSIsIHNjYWxlcHJlYz1GQUxTRSkNCiNzZWwyIDwtIHNlbG1vZGVsKG1vZGVsLCB0eXBlPSJuZWdleHAiLCAgIHByZWM9InNlaSIsIHNjYWxlcHJlYz1GQUxTRSkNCnNlbDMgPC0gc2VsbW9kZWwobW9kZWwsIHR5cGU9ImxvZ2lzdGljIiwgcHJlYz0ic2VpIiwgc2NhbGVwcmVjPUZBTFNFKQ0KI3NlbDQgPC0gc2VsbW9kZWwobW9kZWwsIHR5cGU9InBvd2VyIiwgICAgcHJlYz0ic2VpIiwgIHNjYWxlcHJlYz1GQUxTRSkNCnNlbDFiIDwtIHNlbG1vZGVsKG1vZGVsLCB0eXBlPSJoYWxmbm9ybSIpDQojc2VsMmIgPC0gc2VsbW9kZWwobW9kZWwsIHR5cGU9Im5lZ2V4cCIpDQpzZWwzYiA8LSBzZWxtb2RlbChtb2RlbCwgdHlwZT0ibG9naXN0aWMiKQ0KI3NlbDRiIDwtIHNlbG1vZGVsKG1vZGVsLCB0eXBlPSJwb3dlciIpDQoNCiMgc3RlcCBmdW5jdGlvbiANCnNlbDUgPC0gc2VsbW9kZWwobW9kZWwsIHR5cGU9InN0ZXBmdW4iLCBzdGVwcz1jKDAuMDUsIDAuMTAsIDAuNTAsIDEuMDApKQ0KI3NlbDYgPC0gc2VsbW9kZWwobW9kZWwsIHR5cGU9InN0ZXBmdW4iLCBzdGVwcz1jKDAuMDAxLCAwLjAxLCAwLjA1LCAwLjEwLCAwLjI1LCAwLjUwLCAwLjc1LCAxKSkNCnNlbDcgPC0gc2VsbW9kZWwobW9kZWwsIHR5cGU9InN0ZXBmdW4iLCBzdGVwcz1jKDAuMDUsIDEpKQ0KDQojcGxvdChzZWw1LCB5bGltID0gYygwLDEpKQ0KI3Bsb3Qoc2VsNiwgYWRkPVRSVUUsIGNvbD0icmVkIiwgc2NhbGUgPSBUKQ0KI3Bsb3Qoc2VsNywgYWRkPVRSVUUsIGNvbD0icmVkIikNCiNsZWdlbmQoeCA9IDAuNSwgeSA9IDEsIGxlZ2VuZCA9IGMoIjMgY3V0cG9pbnRzIiwgIiIsIjEgY3V0cG9pbnQgKDMgUE1TKSIpLCBsdHkgPWMoMSwgMCwgMSksIGNvbCA9IGMoImJsYWNrIiwgIiIsICJyZWQiKSwgYnR5ID0gIm4iKQ0KDQojIHBsb3R0aW5nIGZyb20gaGVyZQ0KcEEgPC0gcGxvdCArICB0aGVtZShwbG90Lm1hcmdpbj11bml0KGMoLTEsMCwtMSwwKSwiY20iKSkNCg0KIyBCDQpwZGYoTlVMTCkNCmRldi5jb250cm9sKGRpc3BsYXlsaXN0PSJlbmFibGUiKQ0KcGFyKG1hcj1jKDQsNCwwLjEsMCkgKyAwLjEpDQpwbG90KHNlbDEpDQpwbG90KHNlbDMsIGFkZD1UUlVFLCBjb2w9InJlZCIpDQpwbG90KHNlbDFiLCBhZGQ9VFJVRSwgbHR5ID0gImRvdHRlZCIpDQpwbG90KHNlbDNiLCBhZGQ9VFJVRSwgY29sPSJyZWQiLCBsdHkgPSAiZG90dGVkIikNCmxlZ2VuZCh4ID0gMC42LCB5ID0gMSwgbGVnZW5kID0gYygiaGFsZi1ub3JtYWwiLCAiIiwibG9naXN0aWMiKSwgbHR5ID1jKDEsIDAsIDEpLCBjb2wgPSBjKCJibGFjayIsICIiLCAicmVkIiksIGJ0eSA9ICJuIikNCnBCIDwtIHJlY29yZFBsb3QoKQ0KaW52aXNpYmxlKGRldi5vZmYoKSkNCg0KIyBDDQpwZGYoTlVMTCkNCmRldi5jb250cm9sKGRpc3BsYXlsaXN0PSJlbmFibGUiKQ0KcGFyKG1hcj1jKDQsNCwwLjEsMCkgKyAwLjEpDQpwbG90KHNlbDUsIHlsaW0gPSBjKDAsMSkpDQpwbG90KHNlbDcsIGFkZD1UUlVFLCBjb2w9InJlZCIsIGx0eSA9IDMpDQpsZWdlbmQoeCA9IDAuNSwgeSA9IDEsIGxlZ2VuZCA9IGMoIjMgY3V0cG9pbnRzIiwgIiIsIjEgY3V0cG9pbnQgKDMgUFNNKSIpLCBsdHkgPWMoMSwgMCwgMSksIGNvbCA9IGMoImJsYWNrIiwgIiIsICJyZWQiKSwgYnR5ID0gIm4iKQ0KcEMgPC0gcmVjb3JkUGxvdCgpDQppbnZpc2libGUoZGV2Lm9mZigpKQ0KDQojIEZpZyA1DQpmaWc1IDwtIHBBIC8oZ2dkcmF3KHBCKSArIGdnZHJhdyhwQykpICsgcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSAnYScpDQoNCmZpZzUNCmBgYA0KDQojIyMjIyBDb2RlIGZvciBGaWcuIDYgKCsgRmlnIDYgcmVkcmF3bikNCg0KYGBge3IsIGZpZy5oZWlnaHQ9IDgsIGZpZy53aWR0aD0gNywgbWVzc2FnZSA9IEZBTFNFLCBldmFsID0gRkFMU0V9DQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgWnIgZGF0YSBjcmVhdGlvbiAjIyMjIw0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCg0Kc2V0LnNlZWQoNzc3KQ0KIyBzZXR0aW5nIHBhcmFtZXRlcnMNCm4uc3R1ZHkgIDwtIDcwDQpzaWdtYTIucyA8LSAwLjA1DQpzaWdtYTIudSA8LSAwLjA1DQpiZXRhMSA8LSAwLjENCmJldGEyIDwtIC0gMC4wNQ0KIyB1c2luZyBuZWdhdGl2ZSBiaW5vbWlhbCB3ZSBnZXQgZ29vZCBzcHJlYWQgb2Ygc2FtcGxlIHNpemUNCm4uc2FtcGxlIDwtIHJuYmlub20obi5zdHVkeSwgbXUgPSAzMCwgc2l6ZSA9IDAuMikgKyA0DQoNCiMgdGhlIG51bWJlciBvZiBlZmZlY3Qgc2l6ZSBwZXIgc3R1ZHkNCnNldC5zZWVkKDc3Nzc3NykNCm4uZXMucGVyLnMgPC0gcnBvaXMobi5zdHVkeSwzKSArIDENCiNzdW0obi5lcy5wZXIucykNCg0Kbi5lZmZlY3QgPC0gc3VtKG4uZXMucGVyLnMpDQojIHZhcmlhbmNlIGZvciBacg0KdmkgPC0gMS8ocmVwKG4uc2FtcGxlLCBuLmVzLnBlci5zKSAtIDMpDQoNCiMgSW4gdGhlIHRleHQsIHdlIGhhdmUgdHdvIG1vZGVyYXRvcnMNCiMgbW9kZXJhdG9yIHggMSAtIHN0dWR5IGxldmVsDQp4MWogPC0gcm5vcm0obi5zdHVkeSkNCiMgbW9kZXJhdG9yIHggMiAtIGVmZmVjdCBpc3plIGxldmVsDQp4MmkgPC0gcm5vcm0obi5lZmZlY3QpDQoNCiMgc3R1ZHkgcG9zaXRpb24NCnBsYWNlIDwtIHJlcCgxOm4uc3R1ZHksIG4uZXMucGVyLnMpDQoNCiMgdGhlcmUgaXMgdW5kZXJsaW5nIG92ZXJhbGwgZWZmZWN0IHRvIHIgPSAwLjMgb3IgWnIgPSAwLjMwOTUxOTYNClpyIDwtIDAgKyBybm9ybShuLnN0dWR5LCAwLCBzcXJ0KHNpZ21hMi5zKSlbcGxhY2VdICsgDQogIHJub3JtKG4uZWZmZWN0LCAwLCBzcXJ0KHNpZ21hMi51KSkgKyBybm9ybShuLmVmZmVjdCwgMCwgc3FydCh2aSkpDQoNCiNxcGxvdChaciwgMS9zcXJ0KHZpKSkNCg0KZGF0QSA8LSBkYXRhLmZyYW1lKHlpID0gWnIsIHZpID0gdmksIHNlaSA9IHNxcnQodmkpLCB4MSA9IHgxaltwbGFjZV0sIHgyID0geDJpLCBuaSA9IG4uc2FtcGxlW3BsYWNlXSwgcHJlYyA9IDEgLyBzcXJ0KHZpKSwgd2kgPSAxL3ZpLCB6aSA9IFpyL3NxcnQodmkpLCBzdHVkeUlEID0gcGxhY2UsIGVmZmVjdElEID0gMTpuLmVmZmVjdCkNCg0KDQojIGN1dHRpbmcgcHVibGljYXRpb24gbWJpYXMgbGlrZSBzdHVmZg0KZXhwZWN0ZWQgPC0gYyh3aGljaCgxL2RhdEEkc2VpIDwgNS41ICYgZGF0QSR5aSA8IDAuMiksIHdoaWNoKDEvZGF0QSRzZWkgPCAzICYgZGF0QSR5aSA8IDAuNykpDQoNCmRhdEIgPC0gZGF0QVstZXhwZWN0ZWQsIF0NCg0KI3FwbG90KHggPSB5aSwgeSA9IDEvc3FydCh2aSksIGRhdGEgPSBkYXRCKQ0KDQptb2RfbWEgPC0gcm1hLm12KHlpLCB2aSwgbW9kID0gfiBzcXJ0KHZpKSwgcmFuZG9tID0gbGlzdCh+IDEgfCBzdHVkeUlELCB+MSB8IGVmZmVjdElEKSwgZGF0YSA9IGRhdEIpDQoNCm1vZF9tYiA8LSBybWEubXYoeWksIHZpLCBtb2QgPSB+IHZpLCByYW5kb20gPSBsaXN0KH4gMSB8IHN0dWR5SUQsIH4xIHwgZWZmZWN0SUQpLCBkYXRhID0gZGF0QikNCg0KI3N1bW1hcnkobW9kX21hKQ0KI3N1bW1hcnkobW9kX21iKQ0KDQoNCiMgY3JlYXRpbmcgY3VydmUgbGluZXMNCnggPSBzZXEoMCwgMSwgYnkgPSAwLjAwMSkNCiN4IDwtIHhbLTEwMDBdDQp5ID0gIG1vZF9tYiRiZXRhW1sxXV0gKyBzcXJ0KHgpKiBtb2RfbWIkYmV0YVtbMl1dDQoNCnZpX2N1cnZlIDwtIHRpYmJsZSh4ID0geCwgeSA9IHkpDQoNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgbG5SUiAtIGRhdGEgY3JlYXRpb24gIyMjIyMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCg0Kc2V0LnNlZWQoNzc3KQ0KIyBzZXR0aW5nIHBhcmFtZXRlcnMNCm4uc3R1ZHkgIDwtIDMwDQpzaWdtYTIucyA8LSAwLjAxDQpzaWdtYTIudSA8LSAwLjAwNQ0KYmV0YTEgPC0gMC4xDQpiZXRhMiA8LSAtMC4wMQ0KIyB1c2luZyBuZWdhdGl2ZSBiaW5vbWlhbCB3ZSBnZXQgZ29vZCBzcHJlYWQgb2Ygc2FtcGxlIHNpemUNCm4uc2FtcGxlIDwtIHJuYmlub20obi5zdHVkeSwgbXUgPSA0MCwgc2l6ZSA9IDAuNSkgKyA0DQoNCiMgdGhlIG51bWJlciBvZiBlZmZlY3Qgc2l6ZSBwZXIgc3R1ZHkNCnNldC5zZWVkKDc3NzcpDQpuLmVzLnBlci5zIDwtIHJwb2lzKG4uc3R1ZHksMykgKyAxDQojc3VtKG4uZXMucGVyLnMpDQoNCiMgc2FtcGxlIHNpemUNCm4uZWZmZWN0IDwtIHN1bShuLmVzLnBlci5zKQ0KDQojIGN2IGZvciBlYWNoIHN0dWR5DQoNCmN2IDwtIHNhbXBsZShzZXEoMC4zLCAwLjM1LGJ5ID0gMC4wMDEpLCBuLmVmZmVjdCwgcmVwbGFjZSA9IFQpDQoNCnJlcF9zYW1wbGUgPC0gcmVwKG4uc2FtcGxlLCB0aW1lcyA9IG4uZXMucGVyLnMpDQoNCiMgdmFyaWFuY2UgZm9yIGxuUlINCiMgYmFsYW5jZWQgZGVzaWduDQp2aSA8LSAoMipjdl4yKS9yZXBfc2FtcGxlDQoNCg0KIyBJbiB0aGUgdGV4dCwgd2UgaGF2ZSB0d28gbW9kZXJhdG9ycw0KIyBtb2RlcmF0b3IgeCAxIC0gc3R1ZHkgbGV2ZWwNCngxaiA8LSBybm9ybShuLnN0dWR5KQ0KIyBtb2RlcmF0b3IgeCAyIC0gZWZmZWN0IGlzemUgbGV2ZWwNCngyaSA8LSBybm9ybShuLmVmZmVjdCkNCg0KIyBzdHVkeSBwb3NpdGlvbg0KDQpwb3MgPC0gcmVwKDE6bi5zdHVkeSwgbi5lcy5wZXIucykNCg0KIyB0aGVyZSBpcyB1bmRlcmxpbmcgb3ZlcmFsbCBlZmZlY3QgdG8gbG5SUiA9IDAuMg0KDQpkYXQzIDwtIGRhdGEuZnJhbWUodmkgPSB2aSwgc2VpID0gc3FydCh2aSksIHgxID0geDFqW3Bvc10sIHgyID0geDJpLCBuaSA9IG4uc2FtcGxlW3Bvc10sIHByZWMgPSAxIC8gc3FydCh2aSksIHdpID0gMS92aSwgc3R1ZHlJRCA9IHBvcywgZWZmZWN0SUQgPSAxOm4uZWZmZWN0KQ0KDQojIG5pIGhlcmUgaXMgc2FtcGxlIHNpemUgcGVyIGdyb3VwIC0gd2UgaGF2ZSB0aGUgc2FtZSBOIGZvciBjb250cm9sIGFuZCB0cmVhdG1lbnQgZ3JvdXBzDQpkYXQzJG5fdGlsZGUgPC0gKGRhdDMkbmleMikvZGF0MyRuaSoyDQojIA0KDQojIE0gbWF0cml4IChWID0gVkNWKQ0Kc2lnbWEgPC0gbWFrZV9WQ1ZfbWF0cml4KGRhdDMsICJ2aSIsICJzdHVkeUlEIiwgImVmZmVjdElEIiwgcmhvID0gMCkNCg0KbG5SUjwtIDAuMyArIGJldGExKngxaltwb3NdICsgYmV0YTIqeDJpICsgcm5vcm0obi5zdHVkeSwgMCwgc3FydChzaWdtYTIucykpW3Bvc10gKyANCiAgcm5vcm0obi5lZmZlY3QsIDAsIHNxcnQoc2lnbWEyLnUpKSArICBNQVNTOjptdnJub3JtKDEsIHJlcCgwLCBuLmVmZmVjdCksIHNpZ21hKQ0KDQpkYXQzJHlpIDwtIGxuUlINCg0KbW9kX21sIDwtIHJtYS5tdih5aSwgdmksIG1vZCA9IH4geDEgKyB4MiwgcmFuZG9tID0gbGlzdCh+IDEgfCBzdHVkeUlELCB+MSB8IGVmZmVjdElEKSwgZGF0YSA9IGRhdDMpDQoNCiMgcmVzaWR1YWxzIC0gc3RhbmRhcmRpemVkDQojc3VtbWFyeShtb2RfbWwpDQojZnVubmVsKG1vZF9tbCwgeWF4aXM9InNlaW52IiwgY29sID0gaW5mZXJubygyNSlbcG9zXSkNCg0KIyByZXNpZHVhbCBtYXJnaW5hbA0KcmVzaWRtIDwtIGRhdDMkeWkgLSBwcmVkaWN0KG1vZF9tbClbWzFdXQ0KdmlfcmVzaWRtIDwtIHZpICsgcHJlZGljdChtb2RfbWwpW1syXV1eMiAjIGFkZGluZyBwcmVkaWN0aW9uIGVycm9ycyANCg0KDQojIHJlc2lkdWFsIGNvbmRpdGlvbmFsIDEgJiAyICsgaXRzIGVycm9yDQpibHVwcyA8LSByYW5lZihtb2RfbWwpDQoNCnN0dWR5X2VmZmVjdCA8LSBibHVwcyRzdHVkeUlEW1sxXV1bcG9zXQ0Kdmlfc3R1ZHkgPC0gKGJsdXBzJHN0dWR5SURbWzJdXVtwb3NdKV4yDQoNCnJlc2lkYzEgPC0gZGF0MyR5aSAtIChwcmVkaWN0KG1vZF9tbClbWzFdXSArIHN0dWR5X2VmZmVjdCkNCnZpX3Jlc2lkYzEgPC0gdmlfcmVzaWRtICsgdmlfc3R1ZHkNCg0KZWZmZWN0X2VmZmVjdCA8LSBibHVwcyRlZmZlY3RJRFtbMV1dDQp2aV9lZmZlY3QgPC0gYmx1cHMkZWZmZWN0SURbWzFdXV4yDQoNCnJlc2lkYzIgPC0gZGF0MyR5aSAtIChwcmVkaWN0KG1vZF9tbClbWzFdXSArIHN0dWR5X2VmZmVjdCArIGVmZmVjdF9lZmZlY3QpDQp2aV9yZXNpZGMyIDwtIHZpX3Jlc2lkbSArIHZpX3N0dWR5ICsgdmlfZWZmZWN0DQoNCg0KIyBwbG90dGluZw0KIyBQYW5lbCBBDQptb2QxIDwtIHJtYSh5aSwgdmksIGRhdGEgPSBkYXQzKQ0KcGRmKE5VTEwpDQpkZXYuY29udHJvbChkaXNwbGF5bGlzdD0iZW5hYmxlIikNCnBhcihtYXI9Yyg0LDQsMC4xLDApICsgMC4xKQ0KZnVubmVsKG1vZDEsIGNvbCA9aW5mZXJubygyNSlbcG9zXSwNCiAgICAgICB5bGltID0gYygwLCAwLjI2KSwgeGxpbSA9IGMoLTAuNiwgMC44KSwNCiAgICAgICB5bGFiID0gIlN0YW5kYXJkIGVycm9yIChTRSkiLCB4bGFiID0gIkVmZmVjdCBzaXplIChsblJSKSIpDQpwYSA8LSByZWNvcmRQbG90KCkNCmludmlzaWJsZShkZXYub2ZmKCkpDQoNCiNQYW5lbCBBKw0KDQpwZGYoTlVMTCkNCmRldi5jb250cm9sKGRpc3BsYXlsaXN0PSJlbmFibGUiKQ0KcGFyKG1hcj1jKDQsNCwwLjEsMCkgKyAwLjEpDQpmdW5uZWwoZGF0MyR5aSwgZGF0MyR2aSwgbmkgPSBkYXQzJG5fdGlsZGUsIHlheGlzPSJuaSIsDQogICAgICAgcmVmbGluZT1tb2QxJGJldGEsIA0KICAgICAgIGNvbCA9aW5mZXJubygyNSlbcG9zXSwNCiAgICAgICB5bGltID0gYygwLCAyNTApLCB4bGltID0gYygtMC42LCAwLjgpLA0KICAgICAgeWxhYiA9IGJxdW90ZSgiRWZmZWN0aXZlIHNhbXBsZSBzaXplICIgKHRpbGRlKG4pKSksIHhsYWIgPSAiRWZmZWN0IHNpemUgKGxuUlIpIikgDQpwYTIgPC0gcmVjb3JkUGxvdCgpDQppbnZpc2libGUoZGV2Lm9mZigpKQ0KDQoNCiMgUGFuZWwgQg0KcGRmKE5VTEwpDQpkZXYuY29udHJvbChkaXNwbGF5bGlzdD0iZW5hYmxlIikNCnBhcihtYXI9Yyg0LDQsMC4xLDApICsgMC4xKQ0KZnVubmVsIChyZXNpZG0sIHZpID0gdmlfcmVzaWRtLCB5YXhpcyA9ICJzZWkiLCAgY29sID0gaW5mZXJubygyNSlbcG9zXSwgIA0KICAgICAgICB5bGltID0gYygwLCAwLjI2KSwgeGxpbSA9IGMoLTAuNiwgMC44KSwNCiAgICAgICAgeWxhYiA9ICJTdGFuZGFyZCBlcnJvciAoU0UpIiwgeGxhYiA9ICJSZXNpZHVhbHMgbWFyZ2luYWwgKGxuUlIpIikNCnBiIDwtIHJlY29yZFBsb3QoKQ0KaW52aXNpYmxlKGRldi5vZmYoKSkNCg0KIyBQYW5lbCBCKw0KcGRmKE5VTEwpDQpkZXYuY29udHJvbChkaXNwbGF5bGlzdD0iZW5hYmxlIikNCnBhcihtYXI9Yyg0LDQsMC4xLDApICsgMC4xKQ0KZnVubmVsKHJlc2lkbSwgdmkgPSB2aV9yZXNpZG0sIG5pID0gZGF0MyRuX3RpbGRlLCB5YXhpcz0ibmkiLA0KICAgICAgICNyZWZsaW5lPW1vZDEkYmV0YSwgDQogICAgICAgY29sID1pbmZlcm5vKDI1KVtwb3NdLA0KICAgICAgIHlsaW0gPSBjKDAsIDI1MCksIHhsaW0gPSBjKC0wLjYsIDAuOCksDQogICAgICAgeWxhYiA9IGJxdW90ZSgiRWZmZWN0aXZlIHNhbXBsZSBzaXplICIgKHRpbGRlKG4pKSksIHhsYWIgPSAiUmVzaWR1YWwgbWFyZ2luYWwgKGxuUlIpIikgDQpwYjIgPC0gcmVjb3JkUGxvdCgpDQppbnZpc2libGUoZGV2Lm9mZigpKQ0KDQoNCiMgUGFuZWwgQw0KcGRmKE5VTEwpDQpkZXYuY29udHJvbChkaXNwbGF5bGlzdD0iZW5hYmxlIikNCnBhcihtYXI9Yyg0LDQsMC4xLDApICsgMC4xKQ0KZnVubmVsKHJlc2lkYzEsIHZpID0gdmlfcmVzaWRjMSwgeWF4aXMgPSAic2VpIiwgIGNvbCA9IGluZmVybm8oMjUpW3Bvc10sDQogICAgICAgeWxpbSA9IGMoMCwgMC4yNiksIHhsaW0gPSBjKC0wLjYsIDAuOCksDQogICAgICAgeWxhYiA9ICJTdGFuZGFyZCBlcnJvciAoU0UpIiwgDQogICAgICAgeGxhYiA9ICJSZXNpZHVhbHMgY29uZGl0aW9uYWwgMSAobG5SUikiKQ0KcGMgPC0gcmVjb3JkUGxvdCgpDQppbnZpc2libGUoZGV2Lm9mZigpKQ0KDQojIFBhbmVsIEMrDQpwZGYoTlVMTCkNCmRldi5jb250cm9sKGRpc3BsYXlsaXN0PSJlbmFibGUiKQ0KcGFyKG1hcj1jKDQsNCwwLjEsMCkgKyAwLjEpDQpmdW5uZWwocmVzaWRjMSwgdmkgPSB2aV9yZXNpZGMxLCBuaSA9IGRhdDMkbl90aWxkZSwgeWF4aXM9Im5pIiwNCiAgICAgICAjcmVmbGluZT1tb2QxJGJldGEsIA0KICAgICAgIGNvbCA9aW5mZXJubygyNSlbcG9zXSwNCiAgICAgICB5bGltID0gYygwLCAyNTApLCB4bGltID0gYygtMC42LCAwLjgpLA0KICAgICAgIHlsYWIgPSBicXVvdGUoIkVmZmVjdGl2ZSBzYW1wbGUgc2l6ZSAiICh0aWxkZShuKSkpLCB4bGFiID0gIlJlc2lkdWFscyBjb25kaXRpb25hbCAxIChsblJSKSIpIA0KcGMyIDwtIHJlY29yZFBsb3QoKQ0KaW52aXNpYmxlKGRldi5vZmYoKSkNCg0KDQojIFBhbmVsIEQNCnBkZihOVUxMKQ0KZGV2LmNvbnRyb2woZGlzcGxheWxpc3Q9ImVuYWJsZSIpDQpwYXIobWFyPWMoNCw0LDAuMSwwKSArIDAuMSkNCmZ1bm5lbChyZXNpZGMyLCB2aSA9IHZpX3Jlc2lkYzIsIHlheGlzID0gInNlaSIsICBjb2wgPSBpbmZlcm5vKDI1KVtwb3NdLA0KICAgICAgIHlsaW0gPSBjKDAsIDAuMjYpLCB4bGltID0gYygtMC42LCAwLjgpLA0KICAgICAgIHlsYWIgPSAiU3RhbmRhcmQgZXJyb3IgKFNFKSIsIA0KICAgICAgIHhsYWIgPSAiUmVzaWR1YWxzIGNvbmRpdGlvbmFsIDIgKGxuUlIpIikNCnBkIDwtIHJlY29yZFBsb3QoKQ0KaW52aXNpYmxlKGRldi5vZmYoKSkNCg0KIyBQYW5lbCBEKw0KcGRmKE5VTEwpDQpkZXYuY29udHJvbChkaXNwbGF5bGlzdD0iZW5hYmxlIikNCnBhcihtYXI9Yyg0LDQsMC4xLDApICsgMC4xKQ0KZnVubmVsKHJlc2lkYzIsIHZpID0gdmlfcmVzaWRjMiwgbmkgPSBkYXQzJG5fdGlsZGUsIHlheGlzPSJuaSIsDQogICAgICAgI3JlZmxpbmU9bW9kMSRiZXRhLCANCiAgICAgICBjb2wgPWluZmVybm8oMjUpW3Bvc10sDQogICAgICAgeWxpbSA9IGMoMCwgMjUwKSwgeGxpbSA9IGMoLTAuNiwgMC44KSwNCiAgICAgICB5bGFiID0gYnF1b3RlKCJFZmZlY3RpdmUgc2FtcGxlIHNpemUgIiAodGlsZGUobikpKSwgeGxhYiA9ICJSZXNpZHVhbHMgY29uZGl0aW9uYWwgMiAobG5SUikiKSANCnBkMiA8LSByZWNvcmRQbG90KCkNCmludmlzaWJsZShkZXYub2ZmKCkpDQoNCg0KIyBQYW5lbCBFDQpwZSA8LSBnZ3Bsb3QoZGF0QiwgYWVzKHNlaSwgeWkpKSArIGdlb21fcG9pbnQoKSArIA0KICBnZW9tX2xpbmUoZGF0YSA9IHZpX2N1cnZlLCBtYXBwaW5nID0gYWVzKHggPSB4LCB5ID0geSwgY29sID0gInJlZCIpKSArDQogICNnZW9tX3BvaW50KGFlcyhjb2wgPSBzdHVkeUlEKSkgKw0KICAjIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIpICsgDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIpICsgDQogIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IG1vZF9tYSRiZXRhW1sxXV0sIHNsb3BlID0gbW9kX21hJGJldGFbWzJdXSkgKw0KICB4bGltKDAsIDEpICsgeWxpbSgtMS41LCAyLjUpICsgDQogIGxhYnMoeCA9ICJTdGFuZGFyZCBlcnJvciAoU0UpIiwgeSA9ICJFZmZlY3Qgc2l6ZSAoWnIpIikrIA0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQojIEYNCg0KIyBWYXJpYW5jZQ0KcGYgPC0gZ2dwbG90KGRhdEIsIGFlcyh2aSwgeWkpKSArIGdlb21fcG9pbnQoKSArIA0KICAjZ2VvbV9wb2ludChhZXMoY29sID0gc3R1ZHlJRCkpICsNCiAgIyBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKSArIA0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArIA0KICBnZW9tX2FibGluZShpbnRlcmNlcHQgPSBtb2RfbWIkYmV0YVtbMV1dLCBzbG9wZSA9IG1vZF9tYiRiZXRhW1syXV0sIGNvbCA9ICJyZWQiKSArDQogIHhsaW0oMCwgMSkgKyB5bGltKC0xLjUsIDIuNSkgKyANCiAgbGFicyh4ID0gIlNhbXBsaW5nIHZhcmlhbmNlIiwgeSA9ICJFZmZlY3Qgc2l6ZSAoWnIpIikNCg0KIyBmaWc2DQpmaWc2IDwtIChnZ2RyYXcocGEpICsgZ2dkcmF3KHBiKSkgLyhnZ2RyYXcocGMpICsgZ2dkcmF3KHBkKSkvKHBsb3RfZ3JpZChwZSkgKyBwbG90X2dyaWQocGYpKSArIHBsb3RfYW5ub3RhdGlvbih0YWdfbGV2ZWxzID0gJ2EnKQ0KDQpmaWc2DQoNCiNmaWc2Kw0KDQpmaWc2X2V4dHJhIDwtICAoZ2dkcmF3KHBhMikgKyBnZ2RyYXcocGIyKSkgLyhnZ2RyYXcocGMyKSArIGdnZHJhdyhwZDIpKSArIHBsb3RfYW5ub3RhdGlvbih0YWdfbGV2ZWxzID0gJ2EnKQ0KDQpmaWc2X2V4dHJhDQoNCmBgYA0KDQojIyMjIyBDb2RlIGZvciBGaWcuIDcNCg0KVGhlcmUgaXMgbm8gY29kZSBmb3IgRmlnLiA3IChjcmVhdGVkIGluIFBvd2VyUG9pbnQpDQoNCiMjIEFja25vd2xlZGdlbWVudA0KDQpTTiBpcyBleHRyZW1lbHkgZ3JhdGVmdWwgdG8gUnVzc2VsbCBMZW50aCBmb3IgbWFraW5nIGhpcyBgZW1tZWFuc2Agd29yayBmb3IgYG1ldGFmb3JgIG9iamVjdHMuDQoNCiMjIFIgU2Vzc2lvbiBJbmZvcm1hdGlvbg0KDQpgYGB7cn0NCnNlc3Npb25JbmZvKCkgJT4lIHBhbmRlcjo6cGFuZGVyKCkNCmBgYA0KDQojIyBSZWZlcmVuY2VzDQo=