1 How Accurate Do I Have To Be?

You are at strategy meeting to solve a business problem. The crux of the situation is the business owners, board members, stakeholders, customers, process owners, special interest groups, and concerned parents, need to know how exactly to produce the product, output, or service that is the best solution.

This is an intensely complex system with plenty of “magic bullet” solutions in the ditch behind you.

You, as the data guru are faced with this situation.

You have at your disposal reality bending algorithms and mind-reading social media troll farms.

Wow!

How accurate do you have to be?

2 Describe a Complex System

What will the output be?

What will the output be?

Industrial processes, biological and chemical systems are very complex owing to the large number of factors and they interact with each other to produce the final result. As complex as the systems are, the predictive models are equally complex. Not only do they have a large number of unknown parameters, but the algorithms themselves have a large number of unknown hyperparameters. These hyperparameters can dramatically increase model performance and improve training times. Tuning can be a complex and expensive process.

Tuning hyperparameters of a deep neural network, probe drilling for oil at given geographic coordinates or evaluating the effectiveness of a drug candidate taken from a chemical search space then it is important to minimize the number of samples drawn from the black box function

Parameters Configurations and values your machine learning algorithm learns from your data during training. These parameters can interact to create complex, non-linear systems.

Hyperparameters Express high level concepts, such as statistical assumptions( eg. regularization), are fixed before training or are hard to learn from data (eg. neural network architecture), and influence the objective, test time performance, and computational cost.

For this vignette we are going to use data from a very complex, non-linear system. The research paper, Modeling of strength of high performance concrete using artificial neural networks by I-Cheng Yeh published in Cement and Concrete Research, Vol. 28, No. 12, pp. 1797-1808 (1998) is our choice.

From the paper, we know that the strength of High Performance Concrete follows a very non-linear relationship with the predictor variables and is poorly modeled by normal regression methods.

A strength model based on ANN is more accurate than a model based on regression analysis

The dataset contains 1030, examples and the following features:

This vignette is based on the RPubs article by Jean Dos Santos. It covers:

3 Load Packages

Package management is an integral part of an analytic and modeling project and I use the pacman package to handle installation and loading. There are a lot of tools associated with this project and I have arranged them in a logical sequence. In the manner of reproducible research, I go back and add to this section to add packages as I proceed through the project. In the spirit of The Lean Startup, this script is always a minimally viable product.

#rm(list = ls())

pacman::p_load(
  # text formatting
  knitr, #A General-Purpose Package for Dynamic Report Generation in R
  kableExtra, #Construct Complex Table with 'kable' and Pipe Syntax

  # reading and manipulating data
  data.table, # very fast reading, writing and manipulation of large datasets
  tidyverse, # The tidy verse collection of data manipulation and graphics packages (Hadley Wickham)
  tidylog, # reporting of tidyr functions
  
  # statistical manipulation
  MASS, # "Modern Applied Statistics with S" (4th edition, 2002)
  
  # model definition and management              
  caret,  # Classification and Regression Training (Max Kuhn)
  
  # EDA and visualization
  plotly, # Create Interactive Web Graphics via 'plotly.js'
  GGally, # Extension to 'ggplot2'
  gridExtra, # Miscellaneous Functions for "Grid" Graphics
  ggthemes, # Extra Themes, Scales and Geoms for 'ggplot2'
  corrplot, # Visualization of a Correlation Matrix
  qqplotr, # Quantile-Quantile Plot Extensions for 'ggplot2'
  umap, # Uniform Manifold Approximation and Projection
  factoextra, # Extract and Visualize the Results of Multivariate Data Analyses
  ggpubr, # 'ggplot2' Based Publication Ready Plots
  funModeling, # EDA and rapid assessment of input data
  DataExplorer, # EDA and visualization similar to funModeling
  
  # ML and optimization routines
  pls, # Partial Least Squares and Principal Component Regression
  xgboost, # Extreme Gradient Boosting
    pso, # Particle Swarm Optimization
  GA, # Genetic Algorithms
  DEoptim, # Global Optimization by Differential Evolution
  
  # Bayesian optimization suite
  smoof,  #Single and Multi-Objective Optimization Test Functions
  mlr, # Machine Learning in R
  mlrMBO, # Bayesian Optimization and Model-Based Optimization of Expensive Black-Box Functions
  mlrHyperopt, # Hyperparameter optimization with mlr and mlrMBO
  ParamHelpers, # Functions for parameter descriptions and operations in black-box optimization, tuning and machine learning. Parameters can be described (type, constraints, defaults, etc.), combined to parameter sets and can in general be programmed on. A useful OptPath object (archive) to log function evaluations is also provided.

  # Caret based Bayesian optimization
  rBayesianOptimization, # update is expected in early 2019
  
  # parallel processing and performance
  tictoc, # Functions for timing R scripts, as well as implementations of Stack and List structures
  parallel, # Support for parallel computation, including random-number generation
  doParallel, # Foreach Parallel Adaptor for the 'parallel' Package
  
  # tools for spacial data
  fields, # Tools for Spatial Data
  
  # tools for explainable models
  DALEX2, # Machine Learning (ML) models are widely used and have various applications in classification or regression. Models created with boosting, bagging, stacking or similar techniques are often used due to their high performance, but such black-box models usually lack of interpretability.
  # DALEX package contains various explainers that help to understand the link between input variables and model output. The single_variable() explainer extracts conditional response of a model as a function of a single selected variable. It is a wrapper over packages 'pdp' (Greenwell 2017) <doi:10.32614/RJ-2017-016>, 'ALEPlot' (Apley 2018) <arXiv:1612.08468>  and 'factorMerger' (Sitko and Biecek 2017) <arXiv:1709.04412>.
  # The single_prediction() explainer attributes parts of a model prediction to particular variables used in the model. It is a wrapper over 'breakDown' package (Staniak and Biecek 2018) <doi:10.32614/RJ-2018-072>. The variable_dropout() explainer calculates variable importance scores based on variable shuffling (Fisher at al. 2018) <arXiv:1801.01489>. All these explainers can be plotted with generic plot() function and compared across different models.
  modelStudio, #Interactive Studio with explanations for ML Predictive models

  # if not installed, load and install
  install = TRUE)
library("tidylog", warn.conflicts = FALSE)

3.1 … and Functions For Visualizations

Voilin plots are pretty cool and the default palettes often do not have enough information to generate a palette if your variable has more than about 12 ‘bins’ so we do a bit of RColorBrewer palette tuning.

4 Import the Data

The dataset can be downloaded through the UCI Machine learning Repository, and reformatted in Excel as a csv file in the data directory. Excel creates far too many problems with automatic date, time, and number conversions for me to trust it.

Observations: 1,030
Variables: 9
$ Cement           <dbl> 540.0, 540.0, 332.5, 332.5, 198.6, 266.0, 380.0, 380.0, 266.0, 475.0, 198.6, 198....
$ Slag             <dbl> 0.0, 0.0, 142.5, 142.5, 132.4, 114.0, 95.0, 95.0, 114.0, 0.0, 132.4, 132.4, 47.5,...
$ Ash              <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...
$ Water            <dbl> 162, 162, 228, 228, 192, 228, 228, 228, 228, 228, 192, 192, 228, 228, 228, 228, 1...
$ Superplasticizer <dbl> 2.5, 2.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0...
$ Coarse_Aggregate <dbl> 1040.0, 1055.0, 932.0, 932.0, 978.4, 932.0, 932.0, 932.0, 932.0, 932.0, 978.4, 97...
$ Fine_Aggregate   <dbl> 676.0, 676.0, 594.0, 594.0, 825.5, 670.0, 594.0, 594.0, 670.0, 594.0, 825.5, 825....
$ Age              <int> 28, 28, 270, 365, 360, 90, 365, 28, 28, 28, 90, 28, 270, 90, 28, 90, 90, 365, 90,...
$ Strength         <dbl> 79.99, 61.89, 40.27, 41.05, 44.30, 47.03, 43.70, 36.45, 45.85, 39.29, 38.07, 28.0...

The data shows the data has 1030 observations with 9 continuous target and predictors.

5 Pre-Processing and Exploratory Data Analysis

5.1 Missing Values, Complete Cases, Near Zero Variances, and Similar Traps

This is an overview of number of zero, missing, and unique values.

[1] "Complete Cases"
   Mode    TRUE 
logical    1030 

All values are continuous variables, and data are complete: imputation is not required. Arrange columns so target is in column 1, just…, because I like it. There are no non-zero variance predictors or target. There is no need to delete non-zero variance predictors.

5.2 Density Kernels

I have a look for strikingly non-normal distributions and outliers. This is a prelude to scaling.

First the response variable,

   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   2.33   23.71   34.45   35.82   46.13   82.60 

Now the predictors

gather: reorganized (Cement, Slag, Ash, Water, Superplasticizer, 㠼㸵) into (Component) [was 1030x9, now 8240x2]
summarise_all: now 8 rows and 5 columns, ungrouped

There is some clustering of predictors, especially age, and there appear be no clear outliers or related problems.

Slag, ash and Superplasticizer show a large proportion of zeros and skew the approximately unimodel distributions. Age shows a very non-normal distribution.

5.4 Take the Logarithm of the Age Predictor for Clarity

The logarithm of Age makes the partial least squares regression(PLS) and principal components regression(PCR) behave much better. Typical values for RMSE have decreased from 11-12 to 7.7-8.2 following transformation of the Age parameter.

5.5 Check for Correlated Predictors and Plot the Correlogram

Historical data can sometimes show clustering that creates problems in modeling. Strong correlations can also be used to identify clusters.

    Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
-0.65753 -0.25924 -0.09367 -0.06380  0.08243  0.55218 
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
                                                

Even when retaining correlations at a significance of 0.05, there are none big enough to create problems with later analysis. There are some indications that water content and superplastizer are important. No correlations between the target variable and any of the predictor variables jump out as large. This will take some effort during modeling.

5.6 Linear Dependencies

This is to check if there are any clear linear dependencies in the data. This is related to the correlation tested above. There are none: the relationship between variables is more complex.

             Length Class  Mode
linearCombos 0      -none- list
remove       0      -none- NULL

Interactions between variables can be investigated using a parallel coordinates plot.

5.7 Z-Scale All Data

Now that the data have been screened for possible problems, we can look at the distributions of each predictor and target to get a feeling for potential clusters and relationships. We will do this using the preprocess function in caret. The scale function will scale all variables to their z values.

5.8 Edited, Screened and Transformed Data Ready For Analysis

gather: reorganized (Cement, Slag, Ash, Water, Superplasticizer, 㠼㸵) into (Component, Value) [was 1030x9, now 8240x3]

The data should look approximately on the same scale with approximately similar variances for regression models. This is not a requirement for XGBoost or LightGBM.

6 Check For Potential Clustering

Use UMAP to look for potential clustering in the predictor variables. This is to investigate whether the predictor data is diverse and extensive. Any clustering may show physical or convenience based restrictions governing the experimental data. There appear to be some clusters with unknown origin. The mid and lower right hand side clusters seem to show a preference for concrete with strong and weak strength.

failed creating initial embedding; using random embedding insteadx

7 Some PCA to Assess Combinations of Variables

There’s a few pretty good reasons to use PCA. We actually capture 66.3% of variance in the dataset by just using three principal components. Since this is purely introductory I’ll skip the math and give you a quick rundown of the workings of PCA:

Importance of components:
                          PC1    PC2    PC3    PC4    PC5     PC6     PC7
Standard deviation     1.4761 1.1862 1.0394 0.9853 0.9203 0.61604 0.36952
Proportion of Variance 0.3113 0.2010 0.1543 0.1387 0.1210 0.05422 0.01951
Cumulative Proportion  0.3113 0.5123 0.6666 0.8053 0.9263 0.98049 1.00000

The scree plot shows there are no “magic” combinations of variables that will solve our problem - keep digging.

The Variables - PCA plot indicates that Age is relatively unimportant in the first two PCA dimensions.

8 Generate Train and Test Set

We start with the split of data into test and train. Since there is no time dependence of consecutive observations, we can used random sampling to construct train/test and folds within the train set.

Look at this blog post

9 Training Parameters(repeated_cv and adaptive_cv)

10 The Response Surface for Cement

I like to get an idea about the non-linearity of the problem before going too much in depth. Complexities will show up when:

Let’s plot strength as a function of the first three PCA components to get an idea of the non-linearity of the strength of concrete. It has a number of peaks showing the non-linearity of the systems. This means that a simple regression will not capture the response surface well. We also have to accept random variation in the experimental setup - the data does not come from a replicated experiment.

11 Baseline Principal Component Regression Model with Train/Test Split

Data:   X dimension: 826 8 
    Y dimension: 826 1
Fit method: svdpc
Number of components considered: 7
TRAINING: % variance explained
          1 comps  2 comps  3 comps  4 comps  5 comps  6 comps  7 comps
X         26.9591  44.1239    60.79    74.30    86.84    97.36    99.61
.outcome   0.7167   0.8946    28.46    54.25    62.84    75.37    80.30

12 Baseline Partial Least Squares Model with Train/Test Split

Data:   X dimension: 826 8 
    Y dimension: 826 1
Fit method: oscorespls
Number of components considered: 7
TRAINING: % variance explained
          1 comps  2 comps  3 comps  4 comps  5 comps  6 comps  7 comps
X           15.14    34.75    52.21    58.98    69.71    74.49    83.72
.outcome    74.52    77.66    79.07    80.93    81.27    82.03    82.37

13 XGBoost for Regression

PLS and PCA regressions do not require hyperparameters. In order to get better results from more advanced algorithms, each method needs to be run with the optimum set of hyperparameters. There is no general way to determine these before conducting analysis.

The analysis so far indicates that each variable is pretty important for the final prediction, but the linear models only get just so far with an RMSE of about 7.7-8.2, and Rsquare of 0.773-0.798. XGBoost was chosen for further modeling based on perfomance and speed and its structure allowing a fit to non-linear and complex problems.

XGBoost stands for eXtreme Gradient Boosting. The name xgboost, though, actually refers to the engineering goal to push the limit of computations resources for boosted tree algorithms. Which is the reason why many people use xgboost. - Tianqi Chen

We will used the xgbLinear model, while it is called a regression and contains the word, “linear”, a regression tree is a nonlinear mode: It is really a “regularized linear model” using delta with elastic net regularization (L1 + L2 + L2 bias) and parallel coordinate descent optimization. It is also an ensemble learner that results in a non-linear transfer function.

Trees

Trees

An XGBoost model will allow the determination of interactions between variables. The model, however, will require the determination of hyperparameters, defined as any parameter not determined from the data. This means user defined assumptions such as regularization, scaling, transformation, feature engineering, neural net architecture, number of epochs, and learning rate (eta). Individual algorithms have a set of hyperparameters commonly used for tuning. For XGBoost, we will be changing:

13.2 RS - Random Search Using Random Adaptive Sampling

We are going to see if we can reach similar results to the grid search by choosing the same number of configurations, but chosen randomly.

13.2.2 RS - Summarize the Optimization

13.2.4 RS - Investigate Interactions Between Hyperparameter Values

Of course, we see that the the hyperspace of sampling is larger than the grid search, but the algorithm hones in on the best areas in hyperspace. We are seeing, in general, higher values of lambda, alpha and eta are better and that results don’t change much after about 200 rounds. This took 1102.33 sec to reach this solution by evaluating 672 models.

13.2.5 RS - Test The Model with Optimized RS Settings

6.33 sec elapsed
eXtreme Gradient Boosting 

No pre-processing
Resampling: Cross-Validated (5 fold, repeated 3 times) 
Summary of sample sizes: 662, 661, 660, 660, 661, 661, ... 
Resampling results:

  RMSE      Rsquared   MAE     
  4.686568  0.9214965  3.176164

Tuning parameter 'nrounds' was held constant at a value of 64
Tuning parameter 'lambda' was held constant at
 a value of 0.3400763
Tuning parameter 'alpha' was held constant at a value of 0.0004462638
Tuning
 parameter 'eta' was held constant at a value of 2.104762

13.3 GA - Genetic Algorithm

Since this is an optimization problem, we can use optimization techniques to assess and refine the best combinations of hyperparemeters. This approach has two requirements:

  • a function to evaluate the score for strategies, called the fitness
  • the minimum and maximum values allowable for each hyperparameter
  • the population size

Good article here from the R-bloggers mailing list. There is a vignette here by Luca Scrucca.

Have a look at this article

13.3.2 GA - Run The Optimization and Save the Model

GA | iter = 1 | Mean = -4.832574 | Best = -4.595089
GA | iter = 2 | Mean = -4.738141 | Best = -4.595089
GA | iter = 3 | Mean = -4.706129 | Best = -4.573569
GA | iter = 4 | Mean = -4.612675 | Best = -4.548229
GA | iter = 5 | Mean = -4.651435 | Best = -4.548229
GA | iter = 6 | Mean = -4.710580 | Best = -4.548229
GA | iter = 7 | Mean = -4.658474 | Best = -4.548229
GA | iter = 8 | Mean = -4.623334 | Best = -4.512393
GA | iter = 9 | Mean = -4.649231 | Best = -4.502360
GA | iter = 10 | Mean = -4.666363 | Best = -4.502360
Time difference of 10.13395 mins
eXtreme Gradient Boosting 

No pre-processing
Resampling: Cross-Validated (5 fold, repeated 3 times) 
Summary of sample sizes: 662, 661, 660, 660, 661, 661, ... 
Resampling results:

  RMSE      Rsquared   MAE     
  4.672078  0.9212513  3.080341

Tuning parameter 'nrounds' was held constant at a value of 464
Tuning parameter 'lambda' was held constant
 at a value of 1.195233
Tuning parameter 'alpha' was held constant at a value of 0.3587536
Tuning
 parameter 'eta' was held constant at a value of 0.593926

13.3.3 GA - Summarize the Optimization

-- Genetic Algorithm ------------------- 

GA settings: 
Type                  =  real-valued 
Population size       =  10 
Number of generations =  10 
Elitism               =  0.3 
Crossover probability =  0.8 
Mutation probability  =  0.5 
Search domain = 
        x1 x2 x3 x4
lower   10 -5 -3 -3
upper 1000  3  1  1

GA results: 
Iterations             = 10 
Fitness function value = -4.50236 
Solution = 
          x1         x2         x3         x4
[1,] 464.327 -0.2262676 -0.4452038 0.07745264

13.4 DE - Differential Evolution

The DEoptim package will be used to optimize the hyperparameters of the XGBoost model using differential evolution. In the same manner as the genetic algorithm above, we first define a custom objective function to be minimized: this will be the cross-validated RMSE.

13.4.2 DE - Run The Optimization

Run the model (1344.78 sec elapsed)

Iteration: 1 bestvalit: 4.420695 bestmemit:  272.853577    1.567570   -1.261362    0.967354
Iteration: 2 bestvalit: 4.420695 bestmemit:  272.853577    1.567570   -1.261362    0.967354
Iteration: 3 bestvalit: 4.420695 bestmemit:  272.853577    1.567570   -1.261362    0.967354
Iteration: 4 bestvalit: 4.420695 bestmemit:  272.853577    1.567570   -1.261362    0.967354
Iteration: 5 bestvalit: 4.420695 bestmemit:  272.853577    1.567570   -1.261362    0.967354
Iteration: 6 bestvalit: 4.396566 bestmemit:  551.286888    1.075946   -0.840488    0.776022
Iteration: 7 bestvalit: 4.345567 bestmemit:  459.508884   -0.069906    0.246125    0.560392
Iteration: 8 bestvalit: 4.345567 bestmemit:  459.508884   -0.069906    0.246125    0.560392
Iteration: 9 bestvalit: 4.345567 bestmemit:  459.508884   -0.069906    0.246125    0.560392
Iteration: 10 bestvalit: 4.345567 bestmemit:  459.508884   -0.069906    0.246125    0.560392
Time difference of 55.42633 mins

13.4.4 DE - Test The Model with Optimized DE Settings

11.12 sec elapsed
eXtreme Gradient Boosting 

No pre-processing
Resampling: Cross-Validated (5 fold, repeated 3 times) 
Summary of sample sizes: 662, 661, 660, 660, 661, 661, ... 
Resampling results:

  RMSE      Rsquared   MAE     
  4.482818  0.9273562  2.982487

Tuning parameter 'nrounds' was held constant at a value of 460
Tuning parameter 'lambda' was held constant
 at a value of 3.634057
Tuning parameter 'alpha' was held constant at a value of 1.762483
Tuning
 parameter 'eta' was held constant at a value of 0.851323

13.5 PSO - Particle Swarm Optimization

We will use the pso package to optimize the four hyperparameters. Just like the Genetic Algorithm and Differential Evolution ww will define a function to be optimized.

13.5.2 PSO - Run The Optimization

We can now use the pso::psoptim() function to run the search

S=10, K=3, p=0.271, w0=0.7213, w1=0.7213, c.p=1.193, c.g=1.193
v.max=NA, d=990, vectorize=TRUE, hybrid=off
It 1: fitness=4.47
It 2: fitness=4.47
It 3: fitness=4.422
It 4: fitness=4.422
It 5: fitness=4.422
It 6: fitness=4.422
It 7: fitness=4.422
It 8: fitness=4.422
It 9: fitness=4.422
It 10: fitness=4.422
Maximal number of iterations reached
Time difference of 11.49972 mins

13.5.4 PSO - Test The Model with Optimized PSO Settings

12.21 sec elapsed
eXtreme Gradient Boosting 

No pre-processing
Resampling: Cross-Validated (5 fold, repeated 3 times) 
Summary of sample sizes: 662, 661, 660, 660, 661, 661, ... 
Resampling results:

  RMSE      Rsquared   MAE     
  4.705027  0.9204373  3.129531

Tuning parameter 'nrounds' was held constant at a value of 682
Tuning parameter 'lambda' was held constant
 at a value of 1
Tuning parameter 'alpha' was held constant at a value of 1
Tuning parameter 'eta' was
 held constant at a value of 2.016966

13.6 BO - Bayesian Optimization

Bayesian optimization is an approach to optimizing objective functions that take a long time (minutes or hours) to evaluate. It is best-suited for optimization over continuous domains of less than 20 dimensions, and tolerates stochastic noise in function evaluations. It builds a surrogate for the objective and quantifies the uncertainty in that surrogate using a Bayesian machine learning technique, Gaussian process regression, and then uses an acquisition function defined from this surrogate to decide where to sample.

Optimization by Bayesian methods spans volumes, this will hit only the high points to get the job done. The methods here are very flexible and can be applied to a variety of ML algorithms. The schemes fit into two toolset camps.

The mlr Toolset

The mlr camp has a large suite of related tools for defining, running, tuning and evaluating ML models.

The caret Toolset

The caret camp follows the model definition and logic used thus far, vide supra.

  • The caret tools.

As before, define a function to be optimized. I’m going to use the same definition as the one used for the particle swarm optimization and modify it to return the RMSE and the cross-validated preditions, as required by rBayesianOptimization.

13.6.3 BO - Run the optimization

20 points in hyperparameter space were pre-sampled
elapsed = 8.41  Round = 21  x1 = 273.0000   x2 = -3.3029    x3 = 0.1317 x4 = -1.6704    Value = -4.6980 
elapsed = 8.59  Round = 22  x1 = 378.0000   x2 = 0.2134 x3 = -0.7879    x4 = -0.3965    Value = -4.7937 
elapsed = 9.33  Round = 23  x1 = 577.0000   x2 = -3.9956    x3 = -0.8811    x4 = -1.9679    Value = -4.8322 
elapsed = 9.00  Round = 24  x1 = 909.0000   x2 = -2.8622    x3 = 0.1574 x4 = -1.0858    Value = -4.5641 
elapsed = 7.69  Round = 25  x1 = 210.0000   x2 = -1.9111    x3 = -2.9067    x4 = 0.0652 Value = -4.5660 
elapsed = 11.56 Round = 26  x1 = 899.0000   x2 = -4.8929    x3 = -1.0911    x4 = -2.6630    Value = -4.8647 
elapsed = 10.11 Round = 27  x1 = 945.0000   x2 = -1.9409    x3 = -0.0707    x4 = 0.5013 Value = -4.7460 
elapsed = 8.73  Round = 28  x1 = 664.0000   x2 = 1.9575 x3 = -0.2291    x4 = -1.6437    Value = -4.7064 
elapsed = 13.25 Round = 29  x1 = 633.0000   x2 = -2.2772    x3 = -1.0895    x4 = 0.3578 Value = -4.6366 
elapsed = 3.05  Round = 30  x1 = 71.0000    x2 = -1.1434    x3 = 0.4448 x4 = -1.6133    Value = -4.8764 
elapsed = 8.69  Round = 31  x1 = 214.0000   x2 = -0.2035    x3 = -1.2476    x4 = -1.6649    Value = -4.7625 
elapsed = 6.97  Round = 32  x1 = 185.0000   x2 = -1.0517    x3 = -2.0208    x4 = -1.0946    Value = -4.7394 
elapsed = 22.92 Round = 33  x1 = 690.0000   x2 = -3.5103    x3 = -2.7173    x4 = 0.5688 Value = -4.6244 
elapsed = 13.59 Round = 34  x1 = 390.0000   x2 = 1.6190 x3 = -2.6021    x4 = 0.4574 Value = -4.6105 
elapsed = 12.91 Round = 35  x1 = 772.0000   x2 = 0.3477 x3 = -1.7349    x4 = -1.4400    Value = -4.9973 
elapsed = 11.37 Round = 36  x1 = 503.0000   x2 = 1.3539 x3 = -0.9255    x4 = 0.1093 Value = -4.7277 
elapsed = 12.64 Round = 37  x1 = 720.0000   x2 = -4.1365    x3 = -0.3520    x4 = 0.8425 Value = -4.4594 
elapsed = 12.56 Round = 38  x1 = 992.0000   x2 = 0.7897 x3 = -1.3727    x4 = -1.2614    Value = -4.7657 
elapsed = 5.26  Round = 39  x1 = 386.0000   x2 = -1.7098    x3 = 0.6515 x4 = -0.1499    Value = -4.6417 
elapsed = 12.58 Round = 40  x1 = 780.0000   x2 = 1.5676 x3 = -1.8256    x4 = -1.4000    Value = -4.8411 
elapsed = 12.35 Round = 41  x1 = 935.0000   x2 = 0.1765 x3 = -1.1637    x4 = -1.6986    Value = -4.7265 
elapsed = 14.83 Round = 42  x1 = 909.0000   x2 = -3.3086    x3 = -0.3244    x4 = 0.8438 Value = -4.5552 
elapsed = 22.93 Round = 43  x1 = 773.0000   x2 = -3.6624    x3 = -2.6182    x4 = 0.8686 Value = -4.4360 
elapsed = 8.05  Round = 44  x1 = 626.0000   x2 = -3.8004    x3 = 0.1738 x4 = 0.8758 Value = -4.5831 
elapsed = 15.03 Round = 45  x1 = 681.0000   x2 = 2.5676 x3 = -2.5975    x4 = 0.2275 Value = -4.5831 
elapsed = 19.20 Round = 46  x1 = 864.0000   x2 = -4.1074    x3 = -2.6283    x4 = 0.5991 Value = -4.5171 
elapsed = 11.19 Round = 47  x1 = 797.0000   x2 = -4.3500    x3 = -0.2751    x4 = 0.8402 Value = -4.4480 
elapsed = 21.28 Round = 48  x1 = 860.0000   x2 = -0.6660    x3 = -2.9421    x4 = 0.6450 Value = -4.4497 
elapsed = 9.12  Round = 49  x1 = 699.0000   x2 = -0.3703    x3 = -0.2847    x4 = 0.4009 Value = -4.7358 
elapsed = 12.02 Round = 50  x1 = 980.0000   x2 = 1.9156 x3 = -0.2964    x4 = 0.6458 Value = -4.6951 
elapsed = 12.30 Round = 51  x1 = 773.0000   x2 = -3.7512    x3 = -0.3155    x4 = 1.0000 Value = -4.4232 
elapsed = 20.27 Round = 52  x1 = 752.0000   x2 = -2.6248    x3 = -2.5501    x4 = 0.7032 Value = -4.5145 
elapsed = 7.36  Round = 53  x1 = 854.0000   x2 = -3.2271    x3 = 0.9393 x4 = 0.9625 Value = -4.5646 
elapsed = 20.43 Round = 54  x1 = 694.0000   x2 = -2.1185    x3 = -2.1646    x4 = 0.9736 Value = -4.5319 
elapsed = 24.84 Round = 55  x1 = 872.0000   x2 = -0.1053    x3 = -2.8603    x4 = 0.7957 Value = -4.5019 
elapsed = 23.84 Round = 56  x1 = 843.0000   x2 = -0.9169    x3 = -2.1367    x4 = 0.7053 Value = -4.5409 
elapsed = 25.31 Round = 57  x1 = 823.0000   x2 = -2.1762    x3 = -2.9400    x4 = 1.0000 Value = -4.5146 
elapsed = 8.22  Round = 58  x1 = 775.0000   x2 = 2.5669 x3 = 0.5518 x4 = 0.6411 Value = -4.5335 
elapsed = 7.74  Round = 59  x1 = 701.0000   x2 = -3.2843    x3 = 0.7942 x4 = 1.0000 Value = -4.7025 
elapsed = 25.02 Round = 60  x1 = 960.0000   x2 = -3.4291    x3 = -2.9635    x4 = 0.7953 Value = -4.5574 
elapsed = 27.01 Round = 61  x1 = 868.0000   x2 = 2.5777 x3 = -2.5853    x4 = 1.0000 Value = -4.4351 
elapsed = 27.93 Round = 62  x1 = 858.0000   x2 = -1.1272    x3 = -2.6916    x4 = 1.0000 Value = -4.4897 
elapsed = 11.67 Round = 63  x1 = 686.0000   x2 = 0.7470 x3 = -0.2481    x4 = 1.0000 Value = -4.4904 
elapsed = 23.33 Round = 64  x1 = 775.0000   x2 = -3.9130    x3 = -2.5404    x4 = 1.0000 Value = -4.5202 
elapsed = 20.86 Round = 65  x1 = 735.0000   x2 = 0.2635 x3 = -2.9401    x4 = 0.6138 Value = -4.5449 
elapsed = 19.14 Round = 66  x1 = 700.0000   x2 = -2.8481    x3 = -2.0700    x4 = 0.6463 Value = -4.5600 
elapsed = 14.23 Round = 67  x1 = 781.0000   x2 = -3.6805    x3 = -0.4549    x4 = 0.9725 Value = -4.4834 
elapsed = 18.33 Round = 68  x1 = 884.0000   x2 = -3.9917    x3 = -2.9099    x4 = 0.2773 Value = -4.6843 
elapsed = 25.08 Round = 69  x1 = 793.0000   x2 = -2.9913    x3 = -2.0464    x4 = 1.0000 Value = -4.5901 
elapsed = 28.95 Round = 70  x1 = 970.0000   x2 = 2.4240 x3 = -2.5725    x4 = 0.8547 Value = -4.5453 
elapsed = 13.84 Round = 71  x1 = 655.0000   x2 = -2.5102    x3 = -0.4337    x4 = 1.0000 Value = -4.5129 

 Best Parameters Found: 
Round = 51  x1 = 773.0000   x2 = -3.7512    x3 = -0.3155    x4 = 1.0000 Value = -4.4232 
Time difference of 22.43552 mins

13.6.5 BO - Test The Model with Optimized BO Settings

18.36 sec elapsed
eXtreme Gradient Boosting 

No pre-processing
Resampling: Cross-Validated (5 fold, repeated 3 times) 
Summary of sample sizes: 662, 661, 660, 660, 661, 661, ... 
Resampling results:

  RMSE      Rsquared   MAE     
  4.457225  0.9284931  2.939831

Tuning parameter 'nrounds' was held constant at a value of 773
Tuning parameter 'lambda' was held constant
 at a value of 10
Tuning parameter 'alpha' was held constant at a value of 0.4835916
Tuning parameter
 'eta' was held constant at a value of 0.0001773221

14 Summary of All Training Runs

# Create summary table
Summary_Table_Training <- bind_rows(
  GS_XGBoost_Linear_model_fin$results %>% arrange(RMSE) %>% .[1,] %>% select(RMSE, MAE, Rsquared, nrounds, eta, lambda, alpha) %>% round(5),
  RS_XGBoost_Linear_model_fin$results %>% arrange(RMSE) %>% .[1,] %>% select(RMSE, MAE, Rsquared, nrounds, eta, lambda, alpha) %>% round(5),
  GA_XGBoost_Linear_model_fin$results %>% arrange(RMSE) %>% .[1,] %>% select(RMSE, MAE, Rsquared, nrounds, eta, lambda, alpha) %>% round(5),
  DE_XGBoost_Linear_model_fin$results %>% arrange(RMSE) %>% .[1,] %>% select(RMSE, MAE, Rsquared, nrounds, eta, lambda, alpha) %>% round(5),
  PSO_XGBoost_Linear_model_fin$results %>% arrange(RMSE) %>% .[1,] %>% select(RMSE, MAE, Rsquared, nrounds, eta, lambda, alpha) %>% round(5),
  BO_XGBoost_Linear_model_fin$results %>% arrange(RMSE) %>% .[1,] %>% select(RMSE, MAE, Rsquared, nrounds, eta, lambda, alpha) %>% round(5))

Summary_Table_Training <- Summary_Table_Training %>% 
  add_column(Method = c("Grid Search", "Adaptive Random Search", "Genetic Algorithm", "Differential Evolution", "Particle Swarm Optimization", "Bayesian Optimization"), .before = 1) %>% 
  add_column(`Processing Time` = round(c(GS_T1-GS_T0, RS_T1-RS_T0, GA_T1-GA_T0, DE_T1-DE_T0, PSO_T1-PSO_T0, BO_T1- BO_T0),0))

#Summary_Table_Training <- Summary_Table_Training %>% 
#  add_column(Method = c("Grid Search", "Random Search", "Genetic Algorithm", "Differential Evolution", "Particle #Swarm Optimization"), .before = 1)

# Print table
Summary_Table_Training %>% 
  kable(align = "c", caption = "Training Set Statistics and Hyperparameter Values of XGBoost Models.") %>% 
  kableExtra::kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"), full_width = T, position = "center") %>%
  kableExtra::footnote(general = paste0("Note:\nSummary statistics obtained using ", CV_folds, "-fold cross validation repeated ", CV_repeats, " times.","\nGrid and Random Search  performed with adaptive resampling."), general_title = "\n ")
Training Set Statistics and Hyperparameter Values of XGBoost Models.
Method RMSE MAE Rsquared nrounds eta lambda alpha Processing Time
Grid Search 4.62847 3.06958 0.92303 150 0.03000 0.90000 1.00000 14 mins
Adaptive Random Search 4.68657 3.17616 0.92150 64 2.10476 0.34008 0.00045 5 mins
Genetic Algorithm 4.67208 3.08034 0.92125 464 0.59393 1.19523 0.35875 10 mins
Differential Evolution 4.48896 2.91747 0.92742 386 269.92122 8.71728 0.47104 55 mins
Particle Swarm Optimization 4.70503 3.12953 0.92044 682 2.01697 1.00000 1.00000 11 mins
Bayesian Optimization 4.45722 2.93983 0.92849 773 0.00018 10.00000 0.48359 22 mins

Note:
Summary statistics obtained using 5-fold cross validation repeated 3 times.
Grid and Random Search performed with adaptive resampling.

15 Performance On Test Set

#Custom functions to plot observed, predicted and residual values for each method
library(ggplot2, quietly = T, verbose = F)

# Function to plot observed vs predicted values
predicted_observed_plot <- function(predicted_val, observed_val, residual_val, model_name = "", R_squared, ...) {
  
  plot <- ggplot(mapping = aes(x = predicted_val, y = observed_val, col = abs(residual_val))) +
  geom_point(alpha = 0.9, size = 2) +
  geom_abline(intercept = 0, slope = 1) +
    # facet_wrap(~) +
    labs(title = paste0(model_name, "\nPredicted vs Observed: Test Set"),
         subtitle = paste0("R-squared: ", R_squared),
         x = "Predicted",
         y = "Observed",
         col = "Absolute Deviation") +
  theme_bw() +
  theme(aspect.ratio = 0.9, panel.grid.minor.x = element_blank(), legend.title = element_text(size = 10, face="bold"), legend.text = element_text(size = 9), plot.title = element_text(size=12, face="bold"), axis.title=element_text(size=10, face="bold"), axis.text.x = element_text(angle = 0), legend.position = "none") +
  # scale_x_continuous(expand = c(0,0)) +
  # scale_y_continuous(expand = c(0,0)) + 
  coord_equal() + scale_color_viridis_c(direction = -1)

  return (plot)
}

# Function to plot residuals
residuals_plot <- function(predicted_val, residual_val, model_name = "", MAE, RMSE, ...) {

  plot <- ggplot(mapping = aes(x = predicted_val, y = residual_val, col = abs(residual_val))) +
  geom_point(alpha = 0.9, size = 2) +
  geom_abline(intercept = 0, slope = 0) +
    # facet_wrap(~) +
    labs(
       title = paste0(model_name, "\nResiduals: Test Set"),
       subtitle = paste0("RMSE: ", RMSE, ", MAE: ", round(MAE, 3)),
       x = "Predicted",
       y = "Residual",
       col = "Absolute Deviation"
       ) +
  theme_bw() +
  theme(aspect.ratio = 0.9, panel.grid.minor.x = element_blank(), legend.title = element_text(size = 10, face="bold"), legend.text = element_text(size = 9), plot.title = element_text(size=12, face="bold"), axis.title=element_text(size=10, face="bold"), axis.text.x = element_text(angle = 0), legend.position = "none") +
  # scale_x_continuous(expand = c(0,0)) +
  # scale_y_continuous(expand = c(0,0)) +
  coord_equal() + scale_color_viridis_c(direction = -1)

  return (plot)
}

15.0.7 Create Summary Table

Test Set Statistics of XGBoost Models.
Method RMSE MAE R-squared
Grid Search 4.96996 2.97559 0.9580
Random Search 5.10291 3.24413 0.9555
Genetic Algorithm 4.77734 2.78170 0.9611
Differential Evolution 4.63936 2.66680 0.9633
Particle Swarm Optimization 4.99273 3.01354 0.9577
Bayesian Optimization 4.50993 2.68133 0.9653

16 Summary

The Bayesian approuch with primed values is superior to all other approaches in terms of accuracy and computing resources.

LS0tDQp0aXRsZTogIkh5cGVycGFyYW1ldGVyIFR1bmluZyBUZWNobmlxdWVzIg0Kc3VidGl0bGU6ICJBcHBsaWNhYmxlIHRvIGEgdmFyaWV0eSBvZiBNYWNoaW5lIExlYXJuaW5nIEFsZ29yaXRobXMiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIGZpZ19oZWlnaHQ6IDQuNQ0KICAgIGZpZ193aWR0aDogNw0KICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRoZW1lOiBjb3Ntbw0KICAgIHRvYzogeWVzDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgdG9jOiB5ZXMNCmF1dGhvcjogTm90ZXMgYnkgQWxhc3RhaXIgSy4gTXVpcg0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KYGBgDQoNCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoNCmJvZHl7IC8qIE5vcm1hbCAgKi8NCmZvbnQtc2l6ZTogMThweDsNCn0NCnRkIHsgIC8qIFRhYmxlICAqLw0KZm9udC1zaXplOiAyMHB4Ow0KfQ0KaDEudGl0bGUgew0KICBmb250LXNpemU6IDM0cHg7DQogIGNvbG9yOiBEYXJrQmx1ZTsNCn0NCmgxIHsgLyogSGVhZGVyIDEgKi8NCiAgZm9udC1zaXplOiAyOHB4Ow0KICBjb2xvcjogRGFya0JsdWU7DQp9DQpoMiB7IC8qIEhlYWRlciAyICovDQogIGZvbnQtc2l6ZTogMjRweDsNCiAgY29sb3I6IERhcmtCbHVlOw0KfQ0KaDMgeyAvKiBIZWFkZXIgMyAqLw0KICBmb250LXNpemU6IDIwcHg7DQogIGNvbG9yOiBEYXJrQmx1ZTsNCn0NCmg0IHsgLyogSGVhZGVyIDQgKi8NCiAgZm9udC1zaXplOiAxOHB4Ow0KICBjb2xvcjogRGFya0JsdWU7DQp9DQpjb2RlLnJ7IC8qIENvZGUgYmxvY2sgKi8NCiAgZm9udC1zaXplOiAyMHB4Ow0KfQ0KcHJlIHsgLyogQ29kZSBibG9jayAtIGRldGVybWluZXMgY29kZSBzcGFjaW5nIGJldHdlZW4gbGluZXMgKi8NCiAgZm9udC1zaXplOiAxOHB4Ow0KfQ0KPC9zdHlsZT4NCg0KIyBIb3cgQWNjdXJhdGUgRG8gSSBIYXZlIFRvIEJlPw0KDQpZb3UgYXJlIGF0IHN0cmF0ZWd5IG1lZXRpbmcgdG8gc29sdmUgYSBidXNpbmVzcyBwcm9ibGVtLiBUaGUgY3J1eCBvZiB0aGUgc2l0dWF0aW9uIGlzIHRoZSBidXNpbmVzcyBvd25lcnMsIGJvYXJkIG1lbWJlcnMsIHN0YWtlaG9sZGVycywgY3VzdG9tZXJzLCBwcm9jZXNzIG93bmVycywgc3BlY2lhbCBpbnRlcmVzdCBncm91cHMsIGFuZCBjb25jZXJuZWQgcGFyZW50cywgbmVlZCB0byBrbm93IGhvdyAqZXhhY3RseSogdG8gcHJvZHVjZSB0aGUgcHJvZHVjdCwgb3V0cHV0LCBvciBzZXJ2aWNlIHRoYXQgaXMgdGhlIGJlc3Qgc29sdXRpb24uDQoNClRoaXMgaXMgYW4gaW50ZW5zZWx5IGNvbXBsZXggc3lzdGVtIHdpdGggcGxlbnR5IG9mICJtYWdpYyBidWxsZXQiIHNvbHV0aW9ucyBpbiB0aGUgZGl0Y2ggYmVoaW5kIHlvdS4NCg0KWW91LCBhcyB0aGUgKipkYXRhIGd1cnUqKiBhcmUgZmFjZWQgd2l0aCB0aGlzIHNpdHVhdGlvbi4NCg0KWW91IGhhdmUgYXQgeW91ciBkaXNwb3NhbCByZWFsaXR5IGJlbmRpbmcgYWxnb3JpdGhtcyBhbmQgbWluZC1yZWFkaW5nIHNvY2lhbCBtZWRpYSB0cm9sbCBmYXJtcy4NCg0KV293IQ0KDQotIHdoZXJlIGRvIHlvdSBzdGFydD8NCi0gKip3aGVuIGRvIHlvdSBzdG9wPyoqDQoNCj4qKkhvdyBhY2N1cmF0ZSBkbyB5b3UgaGF2ZSB0byBiZT8qKg0KDQojIERlc2NyaWJlIGEgQ29tcGxleCBTeXN0ZW0NCg0KIVtXaGF0IHdpbGwgdGhlIG91dHB1dCBiZT9dKC4vZmlndXJlcy9mdW5jdGlvbl9mMTkucG5nKQ0KDQpJbmR1c3RyaWFsIHByb2Nlc3NlcywgYmlvbG9naWNhbCBhbmQgY2hlbWljYWwgc3lzdGVtcyBhcmUgdmVyeSBjb21wbGV4IG93aW5nIHRvIHRoZSBsYXJnZSBudW1iZXIgb2YgZmFjdG9ycyBhbmQgdGhleSBpbnRlcmFjdCB3aXRoIGVhY2ggb3RoZXIgdG8gcHJvZHVjZSB0aGUgZmluYWwgcmVzdWx0LiBBcyBjb21wbGV4IGFzIHRoZSBzeXN0ZW1zIGFyZSwgdGhlIHByZWRpY3RpdmUgbW9kZWxzIGFyZSBlcXVhbGx5IGNvbXBsZXguIE5vdCBvbmx5IGRvIHRoZXkgaGF2ZSBhIGxhcmdlIG51bWJlciBvZiB1bmtub3duIHBhcmFtZXRlcnMsIGJ1dCB0aGUgYWxnb3JpdGhtcyB0aGVtc2VsdmVzIGhhdmUgYSBsYXJnZSBudW1iZXIgb2YgdW5rbm93biBoeXBlcnBhcmFtZXRlcnMuIFRoZXNlIGh5cGVycGFyYW1ldGVycyBjYW4gZHJhbWF0aWNhbGx5IGluY3JlYXNlIG1vZGVsIHBlcmZvcm1hbmNlIGFuZCBpbXByb3ZlIHRyYWluaW5nIHRpbWVzLiBUdW5pbmcgY2FuIGJlIGEgY29tcGxleCBhbmQgZXhwZW5zaXZlIHByb2Nlc3MuDQoNClR1bmluZyBoeXBlcnBhcmFtZXRlcnMgb2YgYSBkZWVwIG5ldXJhbCBuZXR3b3JrLCBwcm9iZSBkcmlsbGluZyBmb3Igb2lsIGF0IGdpdmVuIGdlb2dyYXBoaWMgY29vcmRpbmF0ZXMgb3IgZXZhbHVhdGluZyB0aGUgZWZmZWN0aXZlbmVzcyBvZiBhIGRydWcgY2FuZGlkYXRlIHRha2VuIGZyb20gYSBjaGVtaWNhbCBzZWFyY2ggc3BhY2UgdGhlbiBpdCBpcyBpbXBvcnRhbnQgdG8gbWluaW1pemUgdGhlIG51bWJlciBvZiBzYW1wbGVzIGRyYXduIGZyb20gdGhlIGJsYWNrIGJveCBmdW5jdGlvbg0KDQoNCj4gKipQYXJhbWV0ZXJzKioNCj4gQ29uZmlndXJhdGlvbnMgYW5kIHZhbHVlcyB5b3VyIG1hY2hpbmUgbGVhcm5pbmcgYWxnb3JpdGhtIGxlYXJucyBmcm9tIHlvdXIgZGF0YSBkdXJpbmcgdHJhaW5pbmcuIFRoZXNlIHBhcmFtZXRlcnMgY2FuIGludGVyYWN0IHRvIGNyZWF0ZSBjb21wbGV4LCBub24tbGluZWFyIHN5c3RlbXMuDQoNCj4gKipIeXBlcnBhcmFtZXRlcnMqKiANCj4gRXhwcmVzcyBoaWdoIGxldmVsIGNvbmNlcHRzLCBzdWNoIGFzIHN0YXRpc3RpY2FsIGFzc3VtcHRpb25zKCBlZy4gcmVndWxhcml6YXRpb24pLCBhcmUgZml4ZWQgYmVmb3JlIHRyYWluaW5nIG9yIGFyZSBoYXJkIHRvIGxlYXJuIGZyb20gZGF0YSAoZWcuIG5ldXJhbCBuZXR3b3JrIGFyY2hpdGVjdHVyZSksIGFuZCBpbmZsdWVuY2UgdGhlIG9iamVjdGl2ZSwgdGVzdCB0aW1lIHBlcmZvcm1hbmNlLCBhbmQgY29tcHV0YXRpb25hbCBjb3N0Lg0KDQpGb3IgdGhpcyB2aWduZXR0ZSB3ZSBhcmUgZ29pbmcgdG8gdXNlIGRhdGEgZnJvbSBhIHZlcnkgY29tcGxleCwgbm9uLWxpbmVhciBzeXN0ZW0uIFRoZSByZXNlYXJjaCBwYXBlciwgW01vZGVsaW5nIG9mIHN0cmVuZ3RoIG9mIGhpZ2ggcGVyZm9ybWFuY2UgY29uY3JldGUgdXNpbmcgYXJ0aWZpY2lhbCBuZXVyYWwgbmV0d29ya3NdKGh0dHBzOi8vd3d3LnNjaWVuY2VkaXJlY3QuY29tL3NjaWVuY2UvYXJ0aWNsZS9waWkvUzAwMDg4ODQ2OTgwMDE2NTMpIGJ5IEktQ2hlbmcgWWVoIHB1Ymxpc2hlZCBpbiBDZW1lbnQgYW5kIENvbmNyZXRlIFJlc2VhcmNoLCBWb2wuIDI4LCBOby4gMTIsIHBwLiAxNzk3LTE4MDggKDE5OTgpIGlzIG91ciBjaG9pY2UuDQoNCkZyb20gdGhlIHBhcGVyLCB3ZSBrbm93IHRoYXQgdGhlIHN0cmVuZ3RoIG9mIEhpZ2ggUGVyZm9ybWFuY2UgQ29uY3JldGUgZm9sbG93cyBhIHZlcnkgbm9uLWxpbmVhciByZWxhdGlvbnNoaXAgd2l0aCB0aGUgcHJlZGljdG9yIHZhcmlhYmxlcyBhbmQgaXMgcG9vcmx5IG1vZGVsZWQgYnkgbm9ybWFsIHJlZ3Jlc3Npb24gbWV0aG9kcy4NCg0KPiBBIHN0cmVuZ3RoIG1vZGVsIGJhc2VkIG9uIEFOTiBpcyBtb3JlIGFjY3VyYXRlIHRoYW4gYSBtb2RlbCBiYXNlZCBvbiByZWdyZXNzaW9uIGFuYWx5c2lzDQoNClRoZSBkYXRhc2V0IGNvbnRhaW5zIDEwMzAsIGV4YW1wbGVzIGFuZCB0aGUgZm9sbG93aW5nIGZlYXR1cmVzOg0KDQotIElucHV0IFZhcmlhYmxlOiBDZW1lbnQgKCRrZy9tXjMkIG1peHR1cmUpDQotIElucHV0IFZhcmlhYmxlOiBCbGFzdCBGdXJuYWNlIFNsYWcgKCRrZy9tXjMkIG1peHR1cmUpDQotIElucHV0IFZhcmlhYmxlOiBGbHkgQXNoICgka2cvbV4zJCBtaXh0dXJlKQ0KLSBJbnB1dCBWYXJpYWJsZTogV2F0ZXIgKCRrZy9tXjMkIG1peHR1cmUpDQotIElucHV0IFZhcmlhYmxlOiBTdXBlcnBsYXN0aWNpemVyICgka2cvbV4zJCBtaXh0dXJlKQ0KLSBJbnB1dCBWYXJpYWJsZTogQ29hcnNlIEFnZ3JlZ2F0ZSAoJGtnL21eMyQgbWl4dHVyZSkNCi0gSW5wdXQgVmFyaWFibGU6IEZpbmUgQWdncmVnYXRlICgka2cvbV4zJCBtaXh0dXJlKQ0KLSBJbnB1dCBWYXJpYWJsZTogQWdlIChkYXlzKQ0KLSBPdXRwdXQgVmFyaWFibGU6IENvbmNyZXRlIGNvbXByZXNzaXZlIHN0cmVuZ3RoICgkTVBhJCkNCg0KVGhpcyB2aWduZXR0ZSBpcyBiYXNlZCBvbiB0aGUgW1JQdWJzIGFydGljbGVdKGh0dHA6Ly9ycHVicy5jb20vamVhbmRzYW50b3M4OC9zZWFyY2hfbWV0aG9kc19mb3JfaHlwZXJwYXJhbWV0ZXJfdHVuaW5nX2luX3IpIGJ5IEplYW4gRG9zIFNhbnRvcy4gSXQgY292ZXJzOg0KDQotIGhldXJpc3RpY3MgYW5kIG1hbnVhbCBzZWFyY2ggKGd1dCBmZWVsaW5ncykNCiAgIC0gc2VsZWN0IGh5cGVycGFyYW1ldGVyIHNldHRpbmdzIGJhc2VkIG9uIGV4cGVyaWVuY2Ugd2l0aCBzaW1pbGFyIHByb2JsZW1zDQotIGdyaWQgc2VhcmNoDQogICAtIGRlZmluZSBhIHJhbmdlIGFuZCBzdGVwIHNpemUgZm9yIGVhY2ggaHlwZXJwYXJhbWV0ZXIgdG8gZGVmaW5lIGFuIG4tZGltZW5zaW9uYWwgZ3JpZA0KICAgLSB0aGUgZ3JpZCBtYXkgYmUgc3ViLXNhbXBsZWQsIGVnLiBMYXRpbiBzcXVhcmVzIA0KLSBhZGFwdGl2ZSByYW5kb20gc2VhcmNoDQogICAtIGEgc2V0IG9mIHZhbHVlcyBvZiBoeXBlcnBhcmFtZXRlcnMgYXJlIGdlbmVyYXRlZCB0aGF0IGRlcGVuZCBvbiB0aGUgdmFsdWVzIG9mIHRoZSB2YXJpYWJsZSBvZiBpbnRlcmVzdCBvYnNlcnZlZCBkdXJpbmcgdGhlIHN1cnZleQ0KLSBnZW5ldGljIGFsZ29yaXRobXMNCiAgIC0gZmlyc3QgY2hvb3NlIGEgcmFuZG9tIHBvcHVsYXRpb24gb2YgaHlwZXJwYXJhbWV0ZXJzLCBjYWxjdWxhdGUgdGhlIGxvc3MgZnVuY3Rpb24gZm9yIGVhY2ggc2V0LCB0aGVuIGNyZWF0ZSBvZmZzcHJpbmcgb2YgeW91ciBiZXR0ZXIgc29sdXRpb25zIHdpdGggc29tZSBtdXRhdGlvbiwgY2FsY3VsYXRlIHRoZSBsb3NzIGZ1bmN0aW9uIGZvciB0aGlzIG5ldyBnZW5lcmF0aW9uLCBhbmQgcmVwZWF0IHRoZSB3aG9sZSBwcm9jZXNzIHVudGlsIGl0IGNvbnZlcmdlcw0KLSBkaWZmZXJlbnRpYWwgZXZvbHV0aW9uDQogICAtIGEgdmFyaWF0aW9uIG9mIGdlbmV0aWMgYWxnb3JpdGhtcyB3aGVyZSBhIHBvcHVsYXRpb24gb2YgYWxnb3JpdGhtcyBldm9sdmVzDQotIHBhcnRpY2xlIHN3YXJtIG9wdGltaXphdGlvbg0KICAgLSBhbm90aGVyIG1ldGhvZCBiYXNlZCBvbiBhbiBpbml0aWFsIGFycmF5IG9mIHJhbmRvbSBwb2ludHMgd2l0aCBsb2NhbCBpbXByb3ZlbWVudA0KLSBCYXllc2lhbiBtZXRob2RzDQogICAtIGFuIGluaXRpYWwgYXJyYXkgb2YgcmFuZG9tIHBvaW50cyBpcyBldmFsdWF0ZWQgd2l0aCBhIGxvc3MgZnVuY3Rpb24gYW5kIHJlc3VsdHMgYXJlIHVzZWQgdG8gbW9kaWZ5IHdlaWdodHMNCi0gQXV0b01MIGluIEgyTw0KICAgLSB0aGlzIGNhbiBpbmNsdWRlIGF1dG9tYXRpYyBzZWxlY3Rpb24gb2YgaHlwZXJwYXJhbWV0ZXJzIGF0IHRoZSBsZXZlbCBvZiBtb2RlbCBhcmNoaXRlY3R1cmUNCg0KIyBMb2FkIFBhY2thZ2VzDQoNClBhY2thZ2UgbWFuYWdlbWVudCBpcyBhbiBpbnRlZ3JhbCBwYXJ0IG9mIGFuIGFuYWx5dGljIGFuZCBtb2RlbGluZyBwcm9qZWN0IGFuZCBJIHVzZSB0aGUgYHBhY21hbmAgcGFja2FnZSB0byBoYW5kbGUgaW5zdGFsbGF0aW9uIGFuZCBsb2FkaW5nLiBUaGVyZSBhcmUgYSBsb3Qgb2YgdG9vbHMgYXNzb2NpYXRlZCB3aXRoIHRoaXMgcHJvamVjdCBhbmQgSSBoYXZlIGFycmFuZ2VkIHRoZW0gaW4gYSBsb2dpY2FsIHNlcXVlbmNlLiBJbiB0aGUgbWFubmVyIG9mIHJlcHJvZHVjaWJsZSByZXNlYXJjaCwgSSBnbyBiYWNrIGFuZCBhZGQgdG8gdGhpcyBzZWN0aW9uIHRvIGFkZCBwYWNrYWdlcyBhcyBJIHByb2NlZWQgdGhyb3VnaCB0aGUgcHJvamVjdC4gSW4gdGhlIHNwaXJpdCBvZiAqKlRoZSBMZWFuIFN0YXJ0dXAqKiwgdGhpcyBzY3JpcHQgaXMgYWx3YXlzIGEgKiptaW5pbWFsbHkgdmlhYmxlIHByb2R1Y3QqKi4NCg0KYGBge3IsIGVjaG8gPSBUUlVFfQ0KI3JtKGxpc3QgPSBscygpKQ0KDQpwYWNtYW46OnBfbG9hZCgNCiAgIyB0ZXh0IGZvcm1hdHRpbmcNCiAga25pdHIsICNBIEdlbmVyYWwtUHVycG9zZSBQYWNrYWdlIGZvciBEeW5hbWljIFJlcG9ydCBHZW5lcmF0aW9uIGluIFINCiAga2FibGVFeHRyYSwgI0NvbnN0cnVjdCBDb21wbGV4IFRhYmxlIHdpdGggJ2thYmxlJyBhbmQgUGlwZSBTeW50YXgNCg0KICAjIHJlYWRpbmcgYW5kIG1hbmlwdWxhdGluZyBkYXRhDQogIGRhdGEudGFibGUsICMgdmVyeSBmYXN0IHJlYWRpbmcsIHdyaXRpbmcgYW5kIG1hbmlwdWxhdGlvbiBvZiBsYXJnZSBkYXRhc2V0cw0KICB0aWR5dmVyc2UsICMgVGhlIHRpZHkgdmVyc2UgY29sbGVjdGlvbiBvZiBkYXRhIG1hbmlwdWxhdGlvbiBhbmQgZ3JhcGhpY3MgcGFja2FnZXMgKEhhZGxleSBXaWNraGFtKQ0KICB0aWR5bG9nLCAjIHJlcG9ydGluZyBvZiB0aWR5ciBmdW5jdGlvbnMNCiAgDQogICMgc3RhdGlzdGljYWwgbWFuaXB1bGF0aW9uDQogIE1BU1MsICMgIk1vZGVybiBBcHBsaWVkIFN0YXRpc3RpY3Mgd2l0aCBTIiAoNHRoIGVkaXRpb24sIDIwMDIpDQogIA0KICAjIG1vZGVsIGRlZmluaXRpb24gYW5kIG1hbmFnZW1lbnQgICAgICAgICAgICAgIA0KICBjYXJldCwgICMgQ2xhc3NpZmljYXRpb24gYW5kIFJlZ3Jlc3Npb24gVHJhaW5pbmcgKE1heCBLdWhuKQ0KICANCiAgIyBFREEgYW5kIHZpc3VhbGl6YXRpb24NCiAgcGxvdGx5LCAjIENyZWF0ZSBJbnRlcmFjdGl2ZSBXZWIgR3JhcGhpY3MgdmlhICdwbG90bHkuanMnDQogIEdHYWxseSwgIyBFeHRlbnNpb24gdG8gJ2dncGxvdDInDQogIGdyaWRFeHRyYSwgIyBNaXNjZWxsYW5lb3VzIEZ1bmN0aW9ucyBmb3IgIkdyaWQiIEdyYXBoaWNzDQogIGdndGhlbWVzLCAjIEV4dHJhIFRoZW1lcywgU2NhbGVzIGFuZCBHZW9tcyBmb3IgJ2dncGxvdDInDQogIGNvcnJwbG90LCAjIFZpc3VhbGl6YXRpb24gb2YgYSBDb3JyZWxhdGlvbiBNYXRyaXgNCiAgcXFwbG90ciwgIyBRdWFudGlsZS1RdWFudGlsZSBQbG90IEV4dGVuc2lvbnMgZm9yICdnZ3Bsb3QyJw0KICB1bWFwLCAjIFVuaWZvcm0gTWFuaWZvbGQgQXBwcm94aW1hdGlvbiBhbmQgUHJvamVjdGlvbg0KICBmYWN0b2V4dHJhLCAjIEV4dHJhY3QgYW5kIFZpc3VhbGl6ZSB0aGUgUmVzdWx0cyBvZiBNdWx0aXZhcmlhdGUgRGF0YSBBbmFseXNlcw0KICBnZ3B1YnIsICMgJ2dncGxvdDInIEJhc2VkIFB1YmxpY2F0aW9uIFJlYWR5IFBsb3RzDQogIGZ1bk1vZGVsaW5nLCAjIEVEQSBhbmQgcmFwaWQgYXNzZXNzbWVudCBvZiBpbnB1dCBkYXRhDQogIERhdGFFeHBsb3JlciwgIyBFREEgYW5kIHZpc3VhbGl6YXRpb24gc2ltaWxhciB0byBmdW5Nb2RlbGluZw0KICANCiAgIyBNTCBhbmQgb3B0aW1pemF0aW9uIHJvdXRpbmVzDQogIHBscywgIyBQYXJ0aWFsIExlYXN0IFNxdWFyZXMgYW5kIFByaW5jaXBhbCBDb21wb25lbnQgUmVncmVzc2lvbg0KICB4Z2Jvb3N0LCAjIEV4dHJlbWUgR3JhZGllbnQgQm9vc3RpbmcNCiAgICBwc28sICMgUGFydGljbGUgU3dhcm0gT3B0aW1pemF0aW9uDQogIEdBLCAjIEdlbmV0aWMgQWxnb3JpdGhtcw0KICBERW9wdGltLCAjIEdsb2JhbCBPcHRpbWl6YXRpb24gYnkgRGlmZmVyZW50aWFsIEV2b2x1dGlvbg0KICANCiAgIyBCYXllc2lhbiBvcHRpbWl6YXRpb24gc3VpdGUNCiAgc21vb2YsICAjU2luZ2xlIGFuZCBNdWx0aS1PYmplY3RpdmUgT3B0aW1pemF0aW9uIFRlc3QgRnVuY3Rpb25zDQogIG1sciwgIyBNYWNoaW5lIExlYXJuaW5nIGluIFINCiAgbWxyTUJPLCAjIEJheWVzaWFuIE9wdGltaXphdGlvbiBhbmQgTW9kZWwtQmFzZWQgT3B0aW1pemF0aW9uIG9mIEV4cGVuc2l2ZSBCbGFjay1Cb3ggRnVuY3Rpb25zDQogIG1sckh5cGVyb3B0LCAjIEh5cGVycGFyYW1ldGVyIG9wdGltaXphdGlvbiB3aXRoIG1sciBhbmQgbWxyTUJPDQogIFBhcmFtSGVscGVycywgIyBGdW5jdGlvbnMgZm9yIHBhcmFtZXRlciBkZXNjcmlwdGlvbnMgYW5kIG9wZXJhdGlvbnMgaW4gYmxhY2stYm94IG9wdGltaXphdGlvbiwgdHVuaW5nIGFuZCBtYWNoaW5lIGxlYXJuaW5nLiBQYXJhbWV0ZXJzIGNhbiBiZSBkZXNjcmliZWQgKHR5cGUsIGNvbnN0cmFpbnRzLCBkZWZhdWx0cywgZXRjLiksIGNvbWJpbmVkIHRvIHBhcmFtZXRlciBzZXRzIGFuZCBjYW4gaW4gZ2VuZXJhbCBiZSBwcm9ncmFtbWVkIG9uLiBBIHVzZWZ1bCBPcHRQYXRoIG9iamVjdCAoYXJjaGl2ZSkgdG8gbG9nIGZ1bmN0aW9uIGV2YWx1YXRpb25zIGlzIGFsc28gcHJvdmlkZWQuDQoNCiAgIyBDYXJldCBiYXNlZCBCYXllc2lhbiBvcHRpbWl6YXRpb24NCiAgckJheWVzaWFuT3B0aW1pemF0aW9uLCAjIHVwZGF0ZSBpcyBleHBlY3RlZCBpbiBlYXJseSAyMDE5DQogIA0KICAjIHBhcmFsbGVsIHByb2Nlc3NpbmcgYW5kIHBlcmZvcm1hbmNlDQogIHRpY3RvYywgIyBGdW5jdGlvbnMgZm9yIHRpbWluZyBSIHNjcmlwdHMsIGFzIHdlbGwgYXMgaW1wbGVtZW50YXRpb25zIG9mIFN0YWNrIGFuZCBMaXN0IHN0cnVjdHVyZXMNCiAgcGFyYWxsZWwsICMgU3VwcG9ydCBmb3IgcGFyYWxsZWwgY29tcHV0YXRpb24sIGluY2x1ZGluZyByYW5kb20tbnVtYmVyIGdlbmVyYXRpb24NCiAgZG9QYXJhbGxlbCwgIyBGb3JlYWNoIFBhcmFsbGVsIEFkYXB0b3IgZm9yIHRoZSAncGFyYWxsZWwnIFBhY2thZ2UNCiAgDQogICMgdG9vbHMgZm9yIHNwYWNpYWwgZGF0YQ0KICBmaWVsZHMsICMgVG9vbHMgZm9yIFNwYXRpYWwgRGF0YQ0KICANCiAgIyB0b29scyBmb3IgZXhwbGFpbmFibGUgbW9kZWxzDQogIERBTEVYMiwgIyBNYWNoaW5lIExlYXJuaW5nIChNTCkgbW9kZWxzIGFyZSB3aWRlbHkgdXNlZCBhbmQgaGF2ZSB2YXJpb3VzIGFwcGxpY2F0aW9ucyBpbiBjbGFzc2lmaWNhdGlvbiBvciByZWdyZXNzaW9uLiBNb2RlbHMgY3JlYXRlZCB3aXRoIGJvb3N0aW5nLCBiYWdnaW5nLCBzdGFja2luZyBvciBzaW1pbGFyIHRlY2huaXF1ZXMgYXJlIG9mdGVuIHVzZWQgZHVlIHRvIHRoZWlyIGhpZ2ggcGVyZm9ybWFuY2UsIGJ1dCBzdWNoIGJsYWNrLWJveCBtb2RlbHMgdXN1YWxseSBsYWNrIG9mIGludGVycHJldGFiaWxpdHkuDQogICMgREFMRVggcGFja2FnZSBjb250YWlucyB2YXJpb3VzIGV4cGxhaW5lcnMgdGhhdCBoZWxwIHRvIHVuZGVyc3RhbmQgdGhlIGxpbmsgYmV0d2VlbiBpbnB1dCB2YXJpYWJsZXMgYW5kIG1vZGVsIG91dHB1dC4gVGhlIHNpbmdsZV92YXJpYWJsZSgpIGV4cGxhaW5lciBleHRyYWN0cyBjb25kaXRpb25hbCByZXNwb25zZSBvZiBhIG1vZGVsIGFzIGEgZnVuY3Rpb24gb2YgYSBzaW5nbGUgc2VsZWN0ZWQgdmFyaWFibGUuIEl0IGlzIGEgd3JhcHBlciBvdmVyIHBhY2thZ2VzICdwZHAnIChHcmVlbndlbGwgMjAxNykgPGRvaToxMC4zMjYxNC9SSi0yMDE3LTAxNj4sICdBTEVQbG90JyAoQXBsZXkgMjAxOCkgPGFyWGl2OjE2MTIuMDg0Njg+ICBhbmQgJ2ZhY3Rvck1lcmdlcicgKFNpdGtvIGFuZCBCaWVjZWsgMjAxNykgPGFyWGl2OjE3MDkuMDQ0MTI+Lg0KICAjIFRoZSBzaW5nbGVfcHJlZGljdGlvbigpIGV4cGxhaW5lciBhdHRyaWJ1dGVzIHBhcnRzIG9mIGEgbW9kZWwgcHJlZGljdGlvbiB0byBwYXJ0aWN1bGFyIHZhcmlhYmxlcyB1c2VkIGluIHRoZSBtb2RlbC4gSXQgaXMgYSB3cmFwcGVyIG92ZXIgJ2JyZWFrRG93bicgcGFja2FnZSAoU3RhbmlhayBhbmQgQmllY2VrIDIwMTgpIDxkb2k6MTAuMzI2MTQvUkotMjAxOC0wNzI+LiBUaGUgdmFyaWFibGVfZHJvcG91dCgpIGV4cGxhaW5lciBjYWxjdWxhdGVzIHZhcmlhYmxlIGltcG9ydGFuY2Ugc2NvcmVzIGJhc2VkIG9uIHZhcmlhYmxlIHNodWZmbGluZyAoRmlzaGVyIGF0IGFsLiAyMDE4KSA8YXJYaXY6MTgwMS4wMTQ4OT4uIEFsbCB0aGVzZSBleHBsYWluZXJzIGNhbiBiZSBwbG90dGVkIHdpdGggZ2VuZXJpYyBwbG90KCkgZnVuY3Rpb24gYW5kIGNvbXBhcmVkIGFjcm9zcyBkaWZmZXJlbnQgbW9kZWxzLg0KICBtb2RlbFN0dWRpbywgI0ludGVyYWN0aXZlIFN0dWRpbyB3aXRoIGV4cGxhbmF0aW9ucyBmb3IgTUwgUHJlZGljdGl2ZSBtb2RlbHMNCg0KICAjIGlmIG5vdCBpbnN0YWxsZWQsIGxvYWQgYW5kIGluc3RhbGwNCiAgaW5zdGFsbCA9IFRSVUUpDQpsaWJyYXJ5KCJ0aWR5bG9nIiwgd2Fybi5jb25mbGljdHMgPSBGQUxTRSkNCmBgYA0KDQojIyAuLi4gYW5kIEZ1bmN0aW9ucyBGb3IgVmlzdWFsaXphdGlvbnMNCg0KVm9pbGluIHBsb3RzIGFyZSBwcmV0dHkgY29vbCBhbmQgdGhlIGRlZmF1bHQgcGFsZXR0ZXMgb2Z0ZW4gZG8gbm90IGhhdmUgZW5vdWdoIGluZm9ybWF0aW9uIHRvIGdlbmVyYXRlIGEgcGFsZXR0ZSBpZiB5b3VyIHZhcmlhYmxlIGhhcyBtb3JlIHRoYW4gYWJvdXQgMTIgJ2JpbnMnIHNvIHdlIGRvIGEgYml0IG9mIGBSQ29sb3JCcmV3ZXJgIHBhbGV0dGUgdHVuaW5nLg0KDQpgYGB7ciwgZWNobyA9IEZBTFNFfQ0KZ2V0UGFsZXR0ZSA9IGNvbG9yUmFtcFBhbGV0dGUoUkNvbG9yQnJld2VyOjpicmV3ZXIucGFsKDgsICJTZXQyIikpKDI2KSANCg0KIyBmb3IgdGVzdGluZyBvZiBzaWduaWZpY2FuY2UgaW4gY29ycmVsYXRpb24gcGxvdHMNCiMgbWF0IDogaXMgYSBtYXRyaXggb2YgZGF0YQ0KY29yLm10ZXN0IDwtIGZ1bmN0aW9uKG1hdCwgLi4uKSB7DQogICAgbWF0IDwtIGFzLm1hdHJpeChtYXQpDQogICAgbiA8LSBuY29sKG1hdCkNCiAgICBwLm1hdDwtIG1hdHJpeChOQSwgbiwgbikNCiAgICBkaWFnKHAubWF0KSA8LSAwDQogICAgZm9yIChpIGluIDE6KG4gLSAxKSkgew0KICAgICAgICBmb3IgKGogaW4gKGkgKyAxKTpuKSB7DQogICAgICAgICAgICB0bXAgPC0gY29yLnRlc3QobWF0WywgaV0sIG1hdFssIGpdLCAuLi4pDQogICAgICAgICAgICBwLm1hdFtpLCBqXSA8LSBwLm1hdFtqLCBpXSA8LSB0bXAkcC52YWx1ZQ0KICAgICAgICB9DQogICAgfQ0KICBjb2xuYW1lcyhwLm1hdCkgPC0gcm93bmFtZXMocC5tYXQpIDwtIGNvbG5hbWVzKG1hdCkNCiAgcC5tYXQNCn0NCg0KIyBzb21ld2hhdCBoYWNraXNoIHNvbHV0aW9uIHRvOg0KIyBodHRwczovL3R3aXR0ZXIuY29tL0VhbW9uQ2FkZGlnYW4vc3RhdHVzLzY0Njc1OTc1MTI0MjYyMDkyOA0KIyBiYXNlZCBtb3N0bHkgb24gY29weS9wYXN0aW5nIGZyb20gZ2dwbG90MiBnZW9tX3Zpb2xpbiBzb3VyY2U6DQojIGh0dHBzOi8vZ2l0aHViLmNvbS9oYWRsZXkvZ2dwbG90Mi9ibG9iL21hc3Rlci9SL2dlb20tdmlvbGluLnINCg0KIiV8fCUiIDwtIGZ1bmN0aW9uKGEsIGIpIHsNCiAgaWYgKCFpcy5udWxsKGEpKSBhIGVsc2UgYg0KfQ0KDQpnZW9tX2ZsYXRfdmlvbGluIDwtIGZ1bmN0aW9uKG1hcHBpbmcgPSBOVUxMLCBkYXRhID0gTlVMTCwgc3RhdCA9ICJ5ZGVuc2l0eSIsDQogICAgICAgICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9ICJkb2RnZSIsIHRyaW0gPSBUUlVFLCBzY2FsZSA9ICJhcmVhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gTkEsIGluaGVyaXQuYWVzID0gVFJVRSwgLi4uKSB7DQogIGxheWVyKA0KICAgIGRhdGEgPSBkYXRhLA0KICAgIG1hcHBpbmcgPSBtYXBwaW5nLA0KICAgIHN0YXQgPSBzdGF0LA0KICAgIGdlb20gPSBHZW9tRmxhdFZpb2xpbiwNCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uLA0KICAgIHNob3cubGVnZW5kID0gc2hvdy5sZWdlbmQsDQogICAgaW5oZXJpdC5hZXMgPSBpbmhlcml0LmFlcywNCiAgICBwYXJhbXMgPSBsaXN0KA0KICAgICAgdHJpbSA9IHRyaW0sDQogICAgICBzY2FsZSA9IHNjYWxlLA0KICAgICAgLi4uDQogICAgKQ0KICApDQp9DQoNCiMnIEByZG5hbWUgZ2dwbG90Mi1nZ3Byb3RvDQojJyBAZm9ybWF0IE5VTEwNCiMnIEB1c2FnZSBOVUxMDQojJyBAZXhwb3J0DQpHZW9tRmxhdFZpb2xpbiA8LQ0KICBnZ3Byb3RvKCJHZW9tRmxhdFZpb2xpbiIsIEdlb20sDQogICAgICAgICAgc2V0dXBfZGF0YSA9IGZ1bmN0aW9uKGRhdGEsIHBhcmFtcykgew0KICAgICAgICAgICAgZGF0YSR3aWR0aCA8LSBkYXRhJHdpZHRoICV8fCUNCiAgICAgICAgICAgICAgcGFyYW1zJHdpZHRoICV8fCUgKHJlc29sdXRpb24oZGF0YSR4LCBGQUxTRSkgKiAwLjkpDQogICAgICAgICAgICANCiAgICAgICAgICAgICMgeW1pbiwgeW1heCwgeG1pbiwgYW5kIHhtYXggZGVmaW5lIHRoZSBib3VuZGluZyByZWN0YW5nbGUgZm9yIGVhY2ggZ3JvdXANCiAgICAgICAgICAgIGRhdGEgJT4lDQogICAgICAgICAgICAgIGdyb3VwX2J5KGdyb3VwKSAlPiUNCiAgICAgICAgICAgICAgbXV0YXRlKHltaW4gPSBtaW4oeSksDQogICAgICAgICAgICAgICAgICAgICB5bWF4ID0gbWF4KHkpLA0KICAgICAgICAgICAgICAgICAgICAgeG1pbiA9IHgsDQogICAgICAgICAgICAgICAgICAgICB4bWF4ID0geCArIHdpZHRoIC8gMikNCiAgICAgICAgICAgIA0KICAgICAgICAgIH0sDQogICAgICAgICAgDQogICAgICAgICAgZHJhd19ncm91cCA9IGZ1bmN0aW9uKGRhdGEsIHBhbmVsX3NjYWxlcywgY29vcmQpIHsNCiAgICAgICAgICAgICMgRmluZCB0aGUgcG9pbnRzIGZvciB0aGUgbGluZSB0byBnbyBhbGwgdGhlIHdheSBhcm91bmQNCiAgICAgICAgICAgIGRhdGEgPC0gdHJhbnNmb3JtKGRhdGEsIHhtaW52ID0geCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhtYXh2ID0geCArIHZpb2xpbndpZHRoICogKHhtYXggLSB4KSkNCiAgICAgICAgICAgIA0KICAgICAgICAgICAgIyBNYWtlIHN1cmUgaXQncyBzb3J0ZWQgcHJvcGVybHkgdG8gZHJhdyB0aGUgb3V0bGluZQ0KICAgICAgICAgICAgbmV3ZGF0YSA8LSByYmluZChwbHlyOjphcnJhbmdlKHRyYW5zZm9ybShkYXRhLCB4ID0geG1pbnYpLCB5KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGx5cjo6YXJyYW5nZSh0cmFuc2Zvcm0oZGF0YSwgeCA9IHhtYXh2KSwgLXkpKQ0KICAgICAgICAgICAgDQogICAgICAgICAgICAjIENsb3NlIHRoZSBwb2x5Z29uOiBzZXQgZmlyc3QgYW5kIGxhc3QgcG9pbnQgdGhlIHNhbWUNCiAgICAgICAgICAgICMgTmVlZGVkIGZvciBjb29yZF9wb2xhciBhbmQgc3VjaA0KICAgICAgICAgICAgbmV3ZGF0YSA8LSByYmluZChuZXdkYXRhLCBuZXdkYXRhWzEsXSkNCiAgICAgICAgICAgIA0KICAgICAgICAgICAgZ2dwbG90Mjo6OmdnbmFtZSgiZ2VvbV9mbGF0X3Zpb2xpbiIsIEdlb21Qb2x5Z29uJGRyYXdfcGFuZWwobmV3ZGF0YSwgcGFuZWxfc2NhbGVzLCBjb29yZCkpDQogICAgICAgICAgfSwNCiAgICAgICAgICANCiAgICAgICAgICBkcmF3X2tleSA9IGRyYXdfa2V5X3BvbHlnb24sDQogICAgICAgICAgDQogICAgICAgICAgZGVmYXVsdF9hZXMgPSBhZXMod2VpZ2h0ID0gMSwgY29sb3VyID0gImdyZXkyMCIsIGZpbGwgPSAid2hpdGUiLCBzaXplID0gMC41LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gTkEsIGxpbmV0eXBlID0gInNvbGlkIiksDQogICAgICAgICAgDQogICAgICAgICAgcmVxdWlyZWRfYWVzID0gYygieCIsICJ5IikNCikNCg0KcmFpbmNsb3VkX3RoZW1lID0gdGhlbWUoDQogIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwNCiAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksDQogIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpLA0KICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwNCiAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgdmp1c3QgPSAwLjUpLA0KICBsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTYpLA0KICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xNiksDQogIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsDQogIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQobGluZWhlaWdodD0uOCwgZmFjZT0iYm9sZCIsIHNpemUgPSAxNiksDQogIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgYXhpcy5saW5lLnggPSBlbGVtZW50X2xpbmUoY29sb3VyID0gJ2JsYWNrJywgc2l6ZT0wLjUsIGxpbmV0eXBlPSdzb2xpZCcpLA0KICBheGlzLmxpbmUueSA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAnYmxhY2snLCBzaXplPTAuNSwgbGluZXR5cGU9J3NvbGlkJykNCikNCg0KbGIgPC0gZnVuY3Rpb24oeCkgbWVhbih4KSAtIHNkKHgpDQp1YiA8LSBmdW5jdGlvbih4KSBtZWFuKHgpICsgc2QoeCkNCmBgYA0KDQojIEltcG9ydCB0aGUgRGF0YQ0KDQpUaGUgZGF0YXNldCBjYW4gYmUgZG93bmxvYWRlZCB0aHJvdWdoIHRoZSBbVUNJIE1hY2hpbmUgbGVhcm5pbmcgUmVwb3NpdG9yeV0oaHR0cHM6Ly9hcmNoaXZlLmljcy51Y2kuZWR1L21sL2RhdGFzZXRzL2NvbmNyZXRlK2NvbXByZXNzaXZlK3N0cmVuZ3RoKSwgYW5kIHJlZm9ybWF0dGVkIGluIEV4Y2VsIGFzIGEgKmNzdiogZmlsZSBpbiB0aGUgZGF0YSBkaXJlY3RvcnkuIEV4Y2VsIGNyZWF0ZXMgZmFyIHRvbyBtYW55IHByb2JsZW1zIHdpdGggYXV0b21hdGljIGRhdGUsIHRpbWUsIGFuZCBudW1iZXIgY29udmVyc2lvbnMgZm9yIG1lIHRvIHRydXN0IGl0Lg0KDQpgYGB7ciwgZWNobyA9IHRydWV9DQpjb25jcmV0ZV9kYXRhIDwtIGZyZWFkKGZpbGUgPSAiLi9kYXRhL0NvbmNyZXRlX0RhdGEuY3N2IikNCmNvbG5hbWVzKGNvbmNyZXRlX2RhdGEpIDwtIGMoIkNlbWVudCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTbGFnIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFzaCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJXYXRlciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTdXBlcnBsYXN0aWNpemVyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNvYXJzZV9BZ2dyZWdhdGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRmluZV9BZ2dyZWdhdGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQWdlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlN0cmVuZ3RoIikNCmRwbHlyOjpnbGltcHNlKGNvbmNyZXRlX2RhdGEpDQpgYGANCg0KVGhlIGRhdGEgc2hvd3MgdGhlIGRhdGEgaGFzIGByIG5yb3coY29uY3JldGVfZGF0YSlgIG9ic2VydmF0aW9ucyB3aXRoIGByIG5jb2woY29uY3JldGVfZGF0YSlgIGNvbnRpbnVvdXMgdGFyZ2V0IGFuZCBwcmVkaWN0b3JzLg0KDQojIFByZS1Qcm9jZXNzaW5nIGFuZCBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzDQoNCiMjIE1pc3NpbmcgVmFsdWVzLCBDb21wbGV0ZSBDYXNlcywgTmVhciBaZXJvIFZhcmlhbmNlcywgYW5kIFNpbWlsYXIgVHJhcHMNCg0KVGhpcyBpcyBhbiBvdmVydmlldyBvZiBudW1iZXIgb2YgemVybywgbWlzc2luZywgYW5kIHVuaXF1ZSB2YWx1ZXMuDQoNCmBgYHtyfQ0KZnVuTW9kZWxpbmc6OmRmX3N0YXR1cyhjb25jcmV0ZV9kYXRhKQ0KYGBgDQoNCmBgYHtyLCBlY2hvPVRSVUV9DQojIHJlb3JkZXIgY29sdW1ucw0KcHJlZHMgPC0gc2V0ZGlmZihuYW1lcyhjb25jcmV0ZV9kYXRhKSwgIlN0cmVuZ3RoIikNCmNvbmNyZXRlX2RhdGFfc2hvcnQgPC0gZHBseXI6OnNlbGVjdChjb25jcmV0ZV9kYXRhLCBjKCJTdHJlbmd0aCIsIHByZWRzKSkNCg0KcHJpbnQoIkNvbXBsZXRlIENhc2VzIikNCmNvbXBsZXRlLmNhc2VzKGNvbmNyZXRlX2RhdGFfc2hvcnQpICU+JQ0KICBzdW1tYXJ5DQpgYGANCg0KYGBge3IsIGVjaG89VFJVRX0NCm56diA8LSBuZWFyWmVyb1Zhcihjb25jcmV0ZV9kYXRhX3Nob3J0LCBzYXZlTWV0cmljcyA9IFRSVUUpDQpuenYNCg0KI2NvbmNyZXRlX2RhdGExIDwtIGNvbmNyZXRlX2RhdGFbLCAtbnp2XQ0KYGBgDQoNCkFsbCB2YWx1ZXMgYXJlIGNvbnRpbnVvdXMgdmFyaWFibGVzLCBhbmQgZGF0YSBhcmUgY29tcGxldGU6IGltcHV0YXRpb24gaXMgbm90IHJlcXVpcmVkLiBBcnJhbmdlIGNvbHVtbnMgc28gdGFyZ2V0IGlzIGluIGNvbHVtbiAxLCBqdXN0Li4uLCBiZWNhdXNlIEkgbGlrZSBpdC4gVGhlcmUgYXJlIG5vIG5vbi16ZXJvIHZhcmlhbmNlIHByZWRpY3RvcnMgb3IgdGFyZ2V0LiBUaGVyZSBpcyBubyBuZWVkIHRvIGRlbGV0ZSBub24temVybyB2YXJpYW5jZSBwcmVkaWN0b3JzLg0KDQojIyBEZW5zaXR5IEtlcm5lbHMNCg0KSSBoYXZlIGEgbG9vayBmb3Igc3RyaWtpbmdseSBub24tbm9ybWFsIGRpc3RyaWJ1dGlvbnMgYW5kIG91dGxpZXJzLiBUaGlzIGlzIGEgcHJlbHVkZSB0byBzY2FsaW5nLg0KDQpGaXJzdCB0aGUgcmVzcG9uc2UgdmFyaWFibGUsDQoNCmBgYHtyLCBlY2hvPVRSVUV9DQpnZ3Bsb3QoZGF0YSA9IGNvbmNyZXRlX2RhdGFfc2hvcnQsIGFlcyh4ID0gU3RyZW5ndGgpKSArIA0KICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjQsIGZpbGwgPSAiYmx1ZSIsIGFkanVzdCA9IDAuMjUpICsgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KRGF0YUV4cGxvcmVyOjpwbG90X3FxKGNvbmNyZXRlX2RhdGEkU3RyZW5ndGgpDQpzdW1tYXJ5KGNvbmNyZXRlX2RhdGFfc2hvcnQkU3RyZW5ndGgpDQpgYGANCg0KTm93IHRoZSBwcmVkaWN0b3JzDQoNCmBgYHtyLCBlY2hvPVRSVUV9DQpjb25jcmV0ZV9kYXRhX2xvbmcgPC0gY29uY3JldGVfZGF0YV9zaG9ydCAlPiUNCiAgZ2F0aGVyKGMoIkNlbWVudCIsDQogICAgICAgICAgICJTbGFnIiwNCiAgICAgICAgICAgIkFzaCIsDQogICAgICAgICAgICJXYXRlciIsDQogICAgICAgICAgICJTdXBlcnBsYXN0aWNpemVyIiwNCiAgICAgICAgICAgIkNvYXJzZV9BZ2dyZWdhdGUiLA0KICAgICAgICAgICAiRmluZV9BZ2dyZWdhdGUiLA0KICAgICAgICAgICAiQWdlIiksIA0KICAgICAgICAga2V5ID0gIkNvbXBvbmVudCIsIHZhbHVlID0gIlN0cmVuZ3RoIikNCiNnbGltcHNlKGNvbmNyZXRlX2RhdGFfbG9uZykNCg0KbGIgPC0gZnVuY3Rpb24oeCkgbWVhbih4KSAtIHNkKHgpDQp1YiA8LSBmdW5jdGlvbih4KSBtZWFuKHgpICsgc2QoeCkNCg0Kc3VtbGQgPC0gY29uY3JldGVfZGF0YV9sb25nICU+JSANCiAgZ3JvdXBfYnkoQ29tcG9uZW50KSAlPiUgDQogIHN1bW1hcmlzZV9hbGwobGlzdChtZWFuID0gbWVhbiwgbWVkaWFuID0gbWVkaWFuLCBsb3dlciA9IGxiLCB1cHBlciA9IHViKSkNCiNzdW1sZA0KDQpnZ3Bsb3QoZGF0YSA9IGNvbmNyZXRlX2RhdGFfbG9uZywgYWVzKHggPSBTdHJlbmd0aCkpICsgDQogIGdlb21fZGVuc2l0eShhZXMoZmlsbCA9IENvbXBvbmVudCksIGFscGhhID0gMC40LCBhZGp1c3QgPSAwLjI1KSArIA0KICBmYWNldF93cmFwKH4gQ29tcG9uZW50LCBzY2FsZXMgPSAiZnJlZSIpICsgDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KYGBgDQoNClRoZXJlIGlzIHNvbWUgY2x1c3RlcmluZyBvZiBwcmVkaWN0b3JzLCBlc3BlY2lhbGx5IGBhZ2VgLCBhbmQgdGhlcmUgYXBwZWFyIGJlIG5vIGNsZWFyIG91dGxpZXJzIG9yIHJlbGF0ZWQgcHJvYmxlbXMuDQoNCmBgYHtyfQ0KY29uY3JldGVfZGF0YSAlPiUNCiAgZHBseXI6OnNlbGVjdCgtU3RyZW5ndGgpICU+JQ0KICBEYXRhRXhwbG9yZXI6OnBsb3RfcXEoKQ0KYGBgDQoNClNsYWcsIGFzaCBhbmQgU3VwZXJwbGFzdGljaXplciBzaG93IGEgbGFyZ2UgcHJvcG9ydGlvbiBvZiB6ZXJvcyBhbmQgc2tldyB0aGUgYXBwcm94aW1hdGVseSB1bmltb2RlbCBkaXN0cmlidXRpb25zLiBBZ2Ugc2hvd3MgYSB2ZXJ5IG5vbi1ub3JtYWwgZGlzdHJpYnV0aW9uLg0KDQojIyBFeGFtaW5lIHRoZSBEaXN0cmlidXRpb24gb2YgdGhlIGBBZ2VgIFBhcmFtZXRlcg0KDQpgYGB7cn0NCnRhYmxlKGNvbmNyZXRlX2RhdGFfc2hvcnQkQWdlKQ0KDQojIFVzZSBmaXRkaXN0ciBmcm9tIE1BU1MgdG8gZXN0aW1hdGUgZGlzdHJpYnV0aW9uIHBhcmFtcw0KcGFyYW1zIDwtIGFzLmxpc3QoZml0ZGlzdHIoY29uY3JldGVfZGF0YV9zaG9ydCRBZ2UsIGRlbnNmdW4gPSAibG9nbm9ybWFsIikkZXN0aW1hdGUpDQpnZ3Bsb3QoZGF0YSA9IGNvbmNyZXRlX2RhdGFfc2hvcnQsIGFlcyhzYW1wbGUgPSBBZ2UpKSArDQogIHN0YXRfcXEoZGlzdHJpYnV0aW9uICA9IHN0YXRzOjpxbG5vcm0sIGRwYXJhbXMgPSBwYXJhbXMpICsNCiAgZ2VvbV9xcShnZW9tID0gInBvaW50IikgKw0KICBzdGF0X3FxX2JhbmQoZGlzdHJpYnV0aW9uID0gImxub3JtIiwgZHBhcmFtcyA9IHBhcmFtcykgKw0KICBzdGF0X3FxX2xpbmUoZGlzdHJpYnV0aW9uID0gImxub3JtIixkcGFyYW1zID0gcGFyYW1zKSArDQogIGxhYnModGl0bGUgPSAiUS1RIFBsb3Qgb2YgbG9nKEFnZSkiLCB4ID0gIlRoZW9yZXRpY2FsIFF1YW50aWxlcyIsIHkgPSAiU2FtcGxlIFF1YW50aWxlcyIpDQpEYXRhRXhwbG9yZXI6OnBsb3RfcXEobG9nKGNvbmNyZXRlX2RhdGFfc2hvcnQkQWdlKSkNCmBgYA0KDQoNCmBgYHtyfQ0KcDEgPC0gZ2dwbG90KGRhdGEgPSBjb25jcmV0ZV9kYXRhX3Nob3J0LCBhZXMoeCA9IEFnZSkpICsgDQogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNCwgZmlsbCA9ICJibHVlIiwgYWRqdXN0ID0gMC4yNSkgKyANCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArDQogICAgbGFicyh0aXRsZSA9ICJBZ2UgRGlzdHJpYnV0aW9uIiwgeCA9ICJBZ2UiLCB5ID0gIiIpDQoNCnAyIDwtIGdncGxvdChkYXRhID0gY29uY3JldGVfZGF0YV9zaG9ydCwgYWVzKHggPSBsb2coQWdlKSkpICsgDQogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNCwgZmlsbCA9ICJibHVlIiwgYWRqdXN0ID0gMC4yNSkgKyANCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArDQogICAgbGFicyh0aXRsZSA9ICJsb2coQWdlKSBEaXN0cmlidXRpb24iLCB4ID0gImxvZyhBZ2UpIiwgeSA9ICIiKQ0KDQpjb3dwbG90OjpwbG90X2dyaWQocDEsIHAyLCBuY29sID0gMikNCnJtKHAxLCBwMikNCmBgYA0KDQojIyBUYWtlIHRoZSBMb2dhcml0aG0gb2YgdGhlIGBBZ2VgIFByZWRpY3RvciBmb3IgQ2xhcml0eQ0KDQpUaGUgbG9nYXJpdGhtIG9mIGBBZ2VgIG1ha2VzIHRoZSBwYXJ0aWFsIGxlYXN0IHNxdWFyZXMgcmVncmVzc2lvbihQTFMpIGFuZCBwcmluY2lwYWwgY29tcG9uZW50cyByZWdyZXNzaW9uKFBDUikgYmVoYXZlIG11Y2ggYmV0dGVyLiBUeXBpY2FsIHZhbHVlcyBmb3IgUk1TRSBoYXZlIGRlY3JlYXNlZCBmcm9tIDExLTEyIHRvIDcuNy04LjIgZm9sbG93aW5nIHRyYW5zZm9ybWF0aW9uIG9mIHRoZSBgQWdlYCBwYXJhbWV0ZXIuIA0KDQpgYGB7cn0NCmNvbmNyZXRlX2RhdGFfc2hvcnQkQWdlID0gbG9nKGNvbmNyZXRlX2RhdGFfc2hvcnQkQWdlKQ0KYGBgDQoNCiMjIENoZWNrIGZvciBDb3JyZWxhdGVkIFByZWRpY3RvcnMgYW5kIFBsb3QgdGhlIENvcnJlbG9ncmFtDQoNCkhpc3RvcmljYWwgZGF0YSBjYW4gc29tZXRpbWVzIHNob3cgY2x1c3RlcmluZyB0aGF0IGNyZWF0ZXMgcHJvYmxlbXMgaW4gbW9kZWxpbmcuIFN0cm9uZyBjb3JyZWxhdGlvbnMgY2FuIGFsc28gYmUgdXNlZCB0byBpZGVudGlmeSBjbHVzdGVycy4NCg0KYGBge3IsIGV2YWw9VFJVRX0NCmNvbmNyZXRlX2RhdGFfY29yciA8LSBjb3IoY29uY3JldGVfZGF0YV9zaG9ydCwgdXNlPSJhbGwub2JzIiwgbWV0aG9kID0gInBlYXJzb24iKQ0KDQpoaWdoQ29yciA8LSBzdW0oYWJzKGNvbmNyZXRlX2RhdGFfY29yclt1cHBlci50cmkoY29uY3JldGVfZGF0YV9jb3JyKV0pID4gMC45OTkpDQpzdW1tYXJ5KGNvbmNyZXRlX2RhdGFfY29yclt1cHBlci50cmkoY29uY3JldGVfZGF0YV9jb3JyKV0pDQoNCmhpZ2hseUNvckRlc2NyIDwtIGZpbmRDb3JyZWxhdGlvbihjb25jcmV0ZV9kYXRhX2NvcnIsIGN1dG9mZiA9IDAuNzUpDQpmaWx0ZXJlZERlc2NyIDwtIGNvbmNyZXRlX2RhdGFfY29yclssLWhpZ2hseUNvckRlc2NyXQ0KDQpkZXNjckNvcjIgPC0gY29yKGZpbHRlcmVkRGVzY3IpDQpzdW1tYXJ5KGRlc2NyQ29yMlt1cHBlci50cmkoZGVzY3JDb3IyKV0pDQoNCnAubWF0IDwtIGNvci5tdGVzdChjb25jcmV0ZV9kYXRhX3Nob3J0KQ0KDQpjb3JycGxvdDo6Y29ycnBsb3QoY29uY3JldGVfZGF0YV9jb3JyLCBtZXRob2QgPSAiY2lyY2xlIiwgdHlwZSA9ICJsb3dlciIsIG9yZGVyID0gImhjbHVzdCIsDQogICAgICAgICBwLm1hdCA9IHAubWF0LCBzaWcubGV2ZWwgPSAwLjA1KQ0KYGBgDQoNCmBgYHtyLCBldmFsPVRSVUUsIGZpZy5oZWlnaHQ9Ni4wLCBmaWcud2lkdGg9Ni4wfQ0KIyByZWZlcmVuY2UgKGh0dHBzOi8vZ2l0aHViLmNvbS9nZ29iaS9nZ2FsbHkvaXNzdWVzLzEzOSMpDQpteV9jdXN0b21fc21vb3RoIDwtIGZ1bmN0aW9uKGRhdGEsIG1hcHBpbmcsIC4uLikgew0KICBnZ3Bsb3QoZGF0YSA9IGRhdGEsIG1hcHBpbmcgPSBtYXBwaW5nKSArDQogICAgZ2VvbV9wb2ludChjb2xvciA9IEkoImJsdWUiKSwgYWxwaGEgPSAwLjEsIHNpemUgPSAwLjEpICsgDQogICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sb3IgPSBJKCJibGFjayIpLCAuLi4pDQp9DQpjb25jcmV0ZV9kYXRhX3Nob3J0ICU+JQ0KICBnZ3BhaXJzKHVwcGVyID0gbGlzdChjb250aW51b3VzID0gd3JhcChnZ2FsbHlfY29yLCBzaXplID0gMykpLA0KICAgICAgICAgIGxvd2VyID0gbGlzdChjb250aW51b3VzID0gbXlfY3VzdG9tX3Ntb290aCksIA0KICAgICAgICAgIGF4aXNMYWJlbHMgPSAiaW50ZXJuYWwiKSArDQogIGxhYnModGl0bGUgPSAiQ29ycmVsYXRpb24gUGxvdHMiKQ0KYGBgDQoNCmBgYHtyLCBldmFsPVRSVUUsIGZpZy5oZWlnaHQ9Mi4wLCBmaWcud2lkdGg9OH0NCmNvbmNyZXRlX2RhdGFfc2hvcnQgJT4lDQogIGdnZHVvKGNvbHVtbnNYID0gMjo5LCANCiAgICAgICAgY29sdW1uc1kgPSAxLCANCiAgICAgICAgdHlwZXMgPSBsaXN0KGNvbnRpbnVvdXMgPSAic21vb3RoX2xtIiksDQogICAgICAgIG1hcHBpbmcgPSBnZ3Bsb3QyOjphZXMoY29sb3IgPSAtU3RyZW5ndGgsIGFscGhhID0gMC4zKSkgKw0KICB0aGVtZV9idygpDQpgYGANCg0KRXZlbiB3aGVuIHJldGFpbmluZyBjb3JyZWxhdGlvbnMgYXQgYSBzaWduaWZpY2FuY2Ugb2YgMC4wNSwgdGhlcmUgYXJlIG5vbmUgYmlnIGVub3VnaCB0byBjcmVhdGUgcHJvYmxlbXMgd2l0aCBsYXRlciBhbmFseXNpcy4gVGhlcmUgYXJlIHNvbWUgaW5kaWNhdGlvbnMgdGhhdCB3YXRlciBjb250ZW50IGFuZCBzdXBlcnBsYXN0aXplciBhcmUgaW1wb3J0YW50LiBObyBjb3JyZWxhdGlvbnMgYmV0d2VlbiB0aGUgdGFyZ2V0IHZhcmlhYmxlIGFuZCBhbnkgb2YgdGhlIHByZWRpY3RvciB2YXJpYWJsZXMganVtcCBvdXQgYXMgbGFyZ2UuIFRoaXMgd2lsbCB0YWtlIHNvbWUgZWZmb3J0IGR1cmluZyBtb2RlbGluZy4NCg0KIyMgTGluZWFyIERlcGVuZGVuY2llcw0KDQpUaGlzIGlzIHRvIGNoZWNrIGlmIHRoZXJlIGFyZSBhbnkgY2xlYXIgbGluZWFyIGRlcGVuZGVuY2llcyBpbiB0aGUgZGF0YS4gVGhpcyBpcyByZWxhdGVkIHRvIHRoZSBjb3JyZWxhdGlvbiB0ZXN0ZWQgYWJvdmUuIFRoZXJlIGFyZSBub25lOiB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdmFyaWFibGVzIGlzIG1vcmUgY29tcGxleC4NCg0KYGBge3IsIGVjaG89VFJVRX0NCmNvbWJvSW5mbyA8LSBmaW5kTGluZWFyQ29tYm9zKGNvbmNyZXRlX2RhdGFfc2hvcnQpDQpzdW1tYXJ5KGNvbWJvSW5mbykNCmBgYA0KDQpJbnRlcmFjdGlvbnMgYmV0d2VlbiB2YXJpYWJsZXMgY2FuIGJlIGludmVzdGlnYXRlZCB1c2luZyBhIHBhcmFsbGVsIGNvb3JkaW5hdGVzIHBsb3QuDQoNCmBgYHtyfQ0KI21pbihjb25jcmV0ZV9kYXRhJFN0cmVuZ3RoKQ0KI21heChjb25jcmV0ZV9kYXRhJFN0cmVuZ3RoKQ0KY29uY3JldGVfZGF0YV9zaG9ydCAlPiUNCiMgIG11dGF0ZShBZ2UgPSBsb2coQWdlKSkgJT4lDQogIHBsb3RfbHkod2lkdGggPSA3MDAsIGhlaWdodCA9IDQ1MCkgJT4lDQogIGFkZF90cmFjZSh0eXBlID0gJ3BhcmNvb3JkcycsDQogICAgICAgICAgICBsaW5lID0gbGlzdChjb2xvciA9IH5TdHJlbmd0aCwNCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yc2NhbGUgPSBsaXN0KGdldFBhbGV0dGUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgY21pbiA9IDEsDQogICAgICAgICAgICAgICAgICAgICAgICBjbWF4ID0gOTApLA0KICAgICAgICAgICAgZGltZW5zaW9ucyA9IGxpc3QoDQogICAgICAgICAgICAgIGxpc3QocmFuZ2UgPSBjKH5taW4oU3RyZW5ndGgpLH5tYXgoU3RyZW5ndGgpKSwNCiAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICdTdHJlbmd0aCcsIHZhbHVlcyA9IH5TdHJlbmd0aCksDQogICAgICAgICAgICAgIGxpc3QocmFuZ2UgPSBjKH5taW4oQ2VtZW50KSx+bWF4KENlbWVudCkpLA0KICAgICAgICAgICAgICAgICAgIHZpc2libGUgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgIGxhYmVsID0gJ0NlbWVudCcsIHZhbHVlcyA9IH5DZW1lbnQpLA0KICAgICAgICAgICAgICBsaXN0KHJhbmdlID0gYyh+bWluKFNsYWcpLH5tYXgoU2xhZykpLA0KICAgICAgICAgICAgICAgICAgIGxhYmVsID0gJ1NsYWcnLCB2YWx1ZXMgPSB+U2xhZyksDQogICAgICAgICAgICAgIGxpc3QocmFuZ2UgPSBjKH5taW4oQXNoKSx+bWF4KEFzaCkpLA0KICAgICAgICAgICAgICAgICAgIGxhYmVsID0gJ0FzaCcsIHZhbHVlcyA9IH5Bc2gpLA0KICAgICAgICAgICAgICBsaXN0KHJhbmdlID0gYyh+bWluKENlbWVudCksfm1heChDZW1lbnQpKSwNCiAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICdXYXRlcicsIHZhbHVlcyA9IH5XYXRlciksDQogICAgICAgICAgICAgIGxpc3QocmFuZ2UgPSBjKH5taW4oU3VwZXJwbGFzdGljaXplciksfm1heChTdXBlcnBsYXN0aWNpemVyKSksDQogICAgICAgICAgICAgICAgICAgbGFiZWwgPSAnU3VwZXJwbGFzdGljaXplcicsIHZhbHVlcyA9IH5TdXBlcnBsYXN0aWNpemVyKSwNCiAgICAgICAgICAgICAgbGlzdChyYW5nZSA9IGMofm1pbihDb2Fyc2VfQWdncmVnYXRlKSx+bWF4KENvYXJzZV9BZ2dyZWdhdGUpKSwNCiAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICdDb2Fyc2VfQWdncmVnYXRlJywgdmFsdWVzID0gfkNvYXJzZV9BZ2dyZWdhdGUpLA0KICAgICAgICAgICAgICBsaXN0KHJhbmdlID0gYyh+bWluKEZpbmVfQWdncmVnYXRlKSx+bWF4KEZpbmVfQWdncmVnYXRlKSksDQogICAgICAgICAgICAgICAgICAgbGFiZWwgPSAnRmluZV9BZ2dyZWdhdGUnLCB2YWx1ZXMgPSB+RmluZV9BZ2dyZWdhdGUpLA0KICAgICAgICAgICAgICBsaXN0KHJhbmdlID0gYyh+bWluKEFnZSksfm1heChBZ2UpKSwNCiAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICdBZ2UnLCB2YWx1ZXMgPSB+QWdlKQ0KICAgICAgICAgICAgKQ0KICApDQpgYGANCg0KIyMgWi1TY2FsZSBBbGwgRGF0YQ0KDQpOb3cgdGhhdCB0aGUgZGF0YSBoYXZlIGJlZW4gc2NyZWVuZWQgZm9yIHBvc3NpYmxlIHByb2JsZW1zLCB3ZSBjYW4gbG9vayBhdCB0aGUgZGlzdHJpYnV0aW9ucyBvZiBlYWNoIHByZWRpY3RvciBhbmQgdGFyZ2V0IHRvIGdldCBhIGZlZWxpbmcgZm9yIHBvdGVudGlhbCBjbHVzdGVycyBhbmQgcmVsYXRpb25zaGlwcy4gV2Ugd2lsbCBkbyB0aGlzIHVzaW5nIHRoZSBgcHJlcHJvY2Vzc2AgZnVuY3Rpb24gaW4gYGNhcmV0YC4gVGhlIGBzY2FsZWAgZnVuY3Rpb24gd2lsbCBzY2FsZSBhbGwgdmFyaWFibGVzIHRvIHRoZWlyIGB6YCB2YWx1ZXMuDQoNCmBgYHtyLCBlY2hvPVRSVUV9DQpwcmVQcm9jVmFsdWVzIDwtIHByZVByb2Nlc3MoY29uY3JldGVfZGF0YV9zaG9ydFssLTFdLCBtZXRob2QgPSBjKCJjZW50ZXIiLCAic2NhbGUiKSkNCmNvbmNyZXRlX2RhdGFfdHJhbnNmb3JtZWQgPC0gcHJlZGljdChwcmVQcm9jVmFsdWVzLCBjb25jcmV0ZV9kYXRhX3Nob3J0WywtMV0pDQpjb25jcmV0ZV9kYXRhX3NjYWxlZCA8LSBjYmluZChjb25jcmV0ZV9kYXRhX3Nob3J0WywgMV0sIGNvbmNyZXRlX2RhdGFfdHJhbnNmb3JtZWQpDQpgYGANCg0KIyMgRWRpdGVkLCBTY3JlZW5lZCBhbmQgVHJhbnNmb3JtZWQgRGF0YSBSZWFkeSBGb3IgQW5hbHlzaXMNCg0KYGBge3IsIGVjaG8gPSBUUlVFfQ0KY29uY3JldGVfZGF0YV9sb25nX3NjYWxlZCA8LSBjb25jcmV0ZV9kYXRhX3NjYWxlZCAlPiUgDQogIGdhdGhlcihjKCJDZW1lbnQiLA0KICAgICAgICAgICAiU2xhZyIsDQogICAgICAgICAgICJBc2giLA0KICAgICAgICAgICAiV2F0ZXIiLA0KICAgICAgICAgICAiU3VwZXJwbGFzdGljaXplciIsDQogICAgICAgICAgICJDb2Fyc2VfQWdncmVnYXRlIiwNCiAgICAgICAgICAgIkZpbmVfQWdncmVnYXRlIiwNCiAgICAgICAgICAgIkFnZSIpLCANCiAgICAgICAgIGtleSA9ICJDb21wb25lbnQiLCB2YWx1ZSA9ICJWYWx1ZSIpDQoNCiNjb25jcmV0ZV9kYXRhX2xvbmdfc2NhbGVkICU+JQ0KIyAgZ3JvdXBfYnkoQ29tcG9uZW50KSAlPiUNCiMgIHN1bW1hcmlzZShtZWFuID0gbWVhbihTdHJlbmd0aCksIHNkID0gc2QoU3RyZW5ndGgpKQ0KYGBgDQoNClRoZSBkYXRhIHNob3VsZCBsb29rIGFwcHJveGltYXRlbHkgb24gdGhlIHNhbWUgc2NhbGUgd2l0aCBhcHByb3hpbWF0ZWx5IHNpbWlsYXIgdmFyaWFuY2VzIGZvciByZWdyZXNzaW9uIG1vZGVscy4gVGhpcyBpcyBub3QgYSByZXF1aXJlbWVudCBmb3IgWEdCb29zdCBvciBMaWdodEdCTS4NCg0KYGBge3IsIGVjaG89VFJVRX0NCmdncGxvdChkYXRhID0gY29uY3JldGVfZGF0YV9sb25nX3NjYWxlZCwgYWVzKHggPSBWYWx1ZSkpICsgDQogIGdlb21fZGVuc2l0eShhZXMoZmlsbCA9IENvbXBvbmVudCksIGFscGhhID0gMC40LCBhZGp1c3QgPSAwLjUpICsgDQogIGZhY2V0X3dyYXAofiBDb21wb25lbnQsIHNjYWxlcyA9ICJmaXhlZCIpICsgDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArDQogIGxhYnModGl0bGUgPSAiWiBTY2FsZWQgUHJlZGljdG9ycyIpDQpgYGANCg0KDQpgYGB7ciwgZWNobz1UUlVFfQ0KZ2dwbG90KGRhdGEgPSBjb25jcmV0ZV9kYXRhX2xvbmdfc2NhbGVkLCANCiAgICAgICBhZXMoeCA9IENvbXBvbmVudCwgeSA9IFZhbHVlLCBmaWxsID0gQ29tcG9uZW50KSkgKw0KICBnZW9tX2ZsYXRfdmlvbGluKHBvc2l0aW9uID0gcG9zaXRpb25fbnVkZ2UoeCA9IC4yLCB5ID0gMCksIGFscGhhID0gLjgsIHNjYWxlID0gIndpZHRoIiwgYWRqdXN0ID0gMC4yNSkgKw0KICAjICBnZW9tX2ZsYXRfdmlvbGluKHBvc2l0aW9uID0gcG9zaXRpb25fbnVkZ2UoeCA9IC4yLCB5ID0gMCksIGFscGhhID0gLjgpICsNCiAgZ2VvbV9wb2ludChhZXMoeSA9IFZhbHVlLCBjb2xvciA9IENvbXBvbmVudCksIA0KICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyKHdpZHRoID0gLjE1KSwgc2l6ZSA9IC41LCBhbHBoYSA9IDAuOCkgKw0KICBnZW9tX2JveHBsb3Qod2lkdGggPSAuMSwgb3V0bGllci5zaGFwZSA9IE5BLCBhbHBoYSA9IDAuNSkgKw0KICBleHBhbmRfbGltaXRzKHggPSA1LjI1KSArDQogIGd1aWRlcyhmaWxsID0gRkFMU0UpICsNCiAgZ3VpZGVzKGNvbG9yID0gRkFMU0UpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiU3BlY3RyYWwiKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU3BlY3RyYWwiKSArDQogIHRoZW1lX2J3KCkgKw0KICByYWluY2xvdWRfdGhlbWUNCmBgYA0KDQojIENoZWNrIEZvciBQb3RlbnRpYWwgQ2x1c3RlcmluZw0KDQpVc2UgVU1BUCB0byBsb29rIGZvciBwb3RlbnRpYWwgY2x1c3RlcmluZyBpbiB0aGUgKipwcmVkaWN0b3IgdmFyaWFibGVzKiouIFRoaXMgaXMgdG8gaW52ZXN0aWdhdGUgd2hldGhlciB0aGUgcHJlZGljdG9yIGRhdGEgaXMgZGl2ZXJzZSBhbmQgZXh0ZW5zaXZlLiBBbnkgY2x1c3RlcmluZyBtYXkgc2hvdyBwaHlzaWNhbCBvciBjb252ZW5pZW5jZSBiYXNlZCByZXN0cmljdGlvbnMgZ292ZXJuaW5nIHRoZSBleHBlcmltZW50YWwgZGF0YS4gVGhlcmUgYXBwZWFyIHRvIGJlIHNvbWUgY2x1c3RlcnMgd2l0aCB1bmtub3duIG9yaWdpbi4gVGhlIG1pZCBhbmQgbG93ZXIgcmlnaHQgaGFuZCBzaWRlIGNsdXN0ZXJzIHNlZW0gdG8gc2hvdyBhIHByZWZlcmVuY2UgZm9yIGNvbmNyZXRlIHdpdGggc3Ryb25nIGFuZCB3ZWFrIHN0cmVuZ3RoLiANCg0KYGBge3IsIGV2YWw9VFJVRSwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9Ni41fQ0KY3VzdG9tLmNvbmZpZyA9IHVtYXAuZGVmYXVsdHMNCmN1c3RvbS5jb25maWckcmFuZG9tX3N0YXRlID0gMTIzDQoNCmNvbmNyZXRlX2RhdGFfdW1hcCA8LSB1bWFwKGQgPSBjb25jcmV0ZV9kYXRhX3NjYWxlZFssLTFdLCBjdXN0b20uY29uZmlnKQ0KdGVtcC5kZiA8LSBkYXRhLnRhYmxlKHggPSBjb25jcmV0ZV9kYXRhX3VtYXAkbGF5b3V0WywxXSwgDQogICAgIHkgPSBjb25jcmV0ZV9kYXRhX3VtYXAkbGF5b3V0WywyXSwNCiAgICAgU3RyZW5ndGggPSBjb25jcmV0ZV9kYXRhX3NjYWxlZCRTdHJlbmd0aCkNCm1pZCA8LSBtZWFuKHRlbXAuZGYkU3RyZW5ndGgpDQpnZ3Bsb3QoZGF0YSA9IHRlbXAuZGYsIGFlcyh4ID0geCwgeSA9IHksIGNvbG9yID0gU3RyZW5ndGgpKSArDQogIGdlb21fcG9pbnQoKSArDQogIHNjYWxlX2NvbG9yX2dyYWRpZW50MihtaWRwb2ludD1taWQsIGxvdz0iYmx1ZSIsIG1pZD0id2hpdGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgaGlnaD0icmVkIiwgc3BhY2UgPSJMYWIiICkNCmBgYA0KDQojIFNvbWUgUENBIHRvIEFzc2VzcyBDb21iaW5hdGlvbnMgb2YgVmFyaWFibGVzDQoNClRoZXJl4oCZcyBhIGZldyBwcmV0dHkgZ29vZCByZWFzb25zIHRvIHVzZSBQQ0EuIFdlIGFjdHVhbGx5IGNhcHR1cmUgNjYuMyUgb2YgdmFyaWFuY2UgaW4gdGhlIGRhdGFzZXQgYnkganVzdCB1c2luZyB0aHJlZSBwcmluY2lwYWwgY29tcG9uZW50cy4gU2luY2UgdGhpcyBpcyBwdXJlbHkgaW50cm9kdWN0b3J5IEnigJlsbCBza2lwIHRoZSBtYXRoIGFuZCBnaXZlIHlvdSBhIHF1aWNrIHJ1bmRvd24gb2YgdGhlIHdvcmtpbmdzIG9mIFBDQToNCg0KLSBTdGFuZGFyZGl6ZSB0aGUgZGF0YSAoQ2VudGVyIGFuZCBzY2FsZSkuDQotIENhbGN1bGF0ZSB0aGUgRWlnZW52ZWN0b3JzIGFuZCBFaWdlbnZhbHVlcyBmcm9tIHRoZSBjb3ZhcmlhbmNlIG1hdHJpeCBvciBjb3JyZWxhdGlvbiBtYXRyaXggKE9uZSBjb3VsZCBhbHNvIHVzZSBTaW5ndWxhciBWZWN0b3IgRGVjb21wb3NpdGlvbikuDQotIFNvcnQgdGhlIEVpZ2VudmFsdWVzIGluIGRlc2NlbmRpbmcgb3JkZXIgYW5kIGNob29zZSB0aGUgSyBsYXJnZXN0IEVpZ2VudmVjdG9ycyAoV2hlcmUgSyBpcyB0aGUgZGVzaXJlZCBudW1iZXIgb2YgZGltZW5zaW9ucyBvZiB0aGUgbmV3IGZlYXR1cmUgc3Vic3BhY2UgayDiiaQgZCkuDQotIENvbnN0cnVjdCB0aGUgcHJvamVjdGlvbiBtYXRyaXggVyBmcm9tIHRoZSBzZWxlY3RlZCBLIEVpZ2VudmVjdG9ycy4NCi0gVHJhbnNmb3JtIHRoZSBvcmlnaW5hbCBkYXRhc2V0IFggdmlhIFcgdG8gb2J0YWluIGEgSy1kaW1lbnNpb25hbCBmZWF0dXJlIHN1YnNwYWNlIFkuDQoNCmBgYHtyLCBldmFsID0gVFJVRX0NCmNvbmNyZXRlX3BjYSA8LSBwcmNvbXAoY29uY3JldGVfZGF0YV90cmFuc2Zvcm1lZFssMjo4XSwgc2NhbGUgPSBUUlVFKQ0KIyBzY3JlZSBwbG90DQpzdW1tYXJ5KGNvbmNyZXRlX3BjYSkNCg0KZnZpel9laWcoY29uY3JldGVfcGNhKQ0KDQpmdml6X3BjYV92YXIoY29uY3JldGVfcGNhLA0KICAgICAgICAgICAgIGNvbC52YXIgPSAiY29udHJpYiIsICMgQ29sb3IgYnkgY29udHJpYnV0aW9ucyB0byB0aGUgUEMNCiAgICAgICAgICAgICBncmFkaWVudC5jb2xzID0gYygiIzAwQUZCQiIsICIjRTdCODAwIiwgIiNGQzRFMDciKSwNCiAgICAgICAgICAgICByZXBlbCA9IFRSVUUpICAgICAjIEF2b2lkIHRleHQgb3ZlcmxhcHBpbmcNCg0KIyAzRCBwbG90IG9mIHRoZSBmaXJzdCB0d28gUENBcyB3aXRoIHogYXMgU3RyZW5ndGgNCmNvbmNyZXRlX2Nvb3JkIDwtIGdldF9wY2FfaW5kKGNvbmNyZXRlX3BjYSkNCmNvbmNyZXRlX2RhdGFfM0QgPC0gZGF0YS50YWJsZShEaW0xID0gY29uY3JldGVfY29vcmQkY29vcmRbLDFdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERpbTIgPSBjb25jcmV0ZV9jb29yZCRjb29yZFssMl0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRGltMyA9IGNvbmNyZXRlX2Nvb3JkJGNvb3JkWywzXSkNCmNvbmNyZXRlX2RhdGFfM0QgPC0gY2JpbmQoY29uY3JldGVfZGF0YV8zRCwgdGVtcC5kZiRTdHJlbmd0aCkNCm1pZCA8LSBtZWFuKHRlbXAuZGYkU3RyZW5ndGgpDQpnZ3Bsb3QoY29uY3JldGVfZGF0YV8zRCwgYWVzKHggPSBEaW0xLCB5ID0gRGltMiwgY29sb3IgPSBWMikpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgICBzY2FsZV9jb2xvcl9ncmFkaWVudDIobWlkcG9pbnQ9bWlkLCBsb3c9ImJsdWUiLCBtaWQ9IndoaXRlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgIGhpZ2g9InJlZCIsIHNwYWNlID0iTGFiIiApDQpgYGANCg0KVGhlIHNjcmVlIHBsb3Qgc2hvd3MgdGhlcmUgYXJlIG5vICJtYWdpYyIgY29tYmluYXRpb25zIG9mIHZhcmlhYmxlcyB0aGF0IHdpbGwgc29sdmUgb3VyIHByb2JsZW0gLSBrZWVwIGRpZ2dpbmcuDQoNClRoZSAqKlZhcmlhYmxlcyAtIFBDQSoqIHBsb3QgaW5kaWNhdGVzIHRoYXQgYEFnZWAgaXMgcmVsYXRpdmVseSB1bmltcG9ydGFudCBpbiB0aGUgZmlyc3QgdHdvIFBDQSBkaW1lbnNpb25zLg0KDQojIEdlbmVyYXRlIFRyYWluIGFuZCBUZXN0IFNldA0KDQpXZSBzdGFydCB3aXRoIHRoZSBzcGxpdCBvZiBkYXRhIGludG8gdGVzdCBhbmQgdHJhaW4uIFNpbmNlIHRoZXJlIGlzIG5vIHRpbWUgZGVwZW5kZW5jZSBvZiBjb25zZWN1dGl2ZSBvYnNlcnZhdGlvbnMsIHdlIGNhbiB1c2VkIHJhbmRvbSBzYW1wbGluZyB0byBjb25zdHJ1Y3QgdHJhaW4vdGVzdCBhbmQgZm9sZHMgd2l0aGluIHRoZSB0cmFpbiBzZXQuDQoNCkxvb2sgYXQgW3RoaXMgYmxvZyBwb3N0XShodHRwczovL3d3dy5kaXNwbGF5ci5jb20vdXNpbmctcGFydGlhbC1sZWFzdC1zcXVhcmVzLXRvLWNvbmR1Y3QtcmVsYXRpdmUtaW1wb3J0YW5jZS1hbmFseXNpcy1pbi1yLykNCg0KYGBge3IsIGVjaG8gPSBGQUxTRX0NCiNjb25jcmV0ZV9kYXRhX3NjYWxlZCAlPiUNCiMgIHBpdm90X2xvbmdlcihjb2xzID0gMTo4KSAlPiUNCiMgIGdyb3VwX2J5KG5hbWUpICU+JQ0KIyAgc3VtbWFyaXNlX2FsbChjKG1lYW49bWVhbiwgc2Q9c2QpKQ0KDQpybSh0cmFpbi5kYXRhLCB0ZXN0LmRhdGEpDQpzZXQuc2VlZCg0MikNCnNlbCA8LSBjcmVhdGVEYXRhUGFydGl0aW9uKGNvbmNyZXRlX2RhdGFfc2NhbGVkJFN0cmVuZ3RoLCBwID0gMC44LCBsaXN0ID0gRkFMU0UpDQp0cmFpbi5kYXRhIDwtIGNvbmNyZXRlX2RhdGFfc2NhbGVkW3NlbCxdDQp0ZXN0LmRhdGEgPC0gY29uY3JldGVfZGF0YV9zY2FsZWRbLXNlbCxdDQpgYGANCg0KIyBUcmFpbmluZyBQYXJhbWV0ZXJzKHJlcGVhdGVkX2N2IGFuZCBhZGFwdGl2ZV9jdikNCg0KYGBge3J9DQojIFRyYWluaW5nIFBhcmFtZXRlcnMNCkNWX2ZvbGRzIDwtIDUgIyBudW1iZXIgb2YgZm9sZHMNCkNWX3JlcGVhdHMgPC0gMyAjIG51bWJlciBvZiByZXBlYXRzDQptaW5pbXVtX3Jlc2FtcGxpbmcgPC0gNSAjIG1pbmltdW0gbnVtYmVyIG9mIHJlc2FtcGxlcw0KDQojIFRyYWluaW5nIFNldHRpbmdzDQpzZXQuc2VlZCgxKQ0KDQojIHRyYWluQ29udHJvbCBvYmplY3QgZm9yIHN0YW5kYXJkIHJlcGVhdGVkIGNyb3NzLXZhbGlkYXRpb24NCnRyYWluX2NvbnRyb2wgPC0gY2FyZXQ6OnRyYWluQ29udHJvbCgNCiAgbWV0aG9kID0gInJlcGVhdGVkY3YiLCANCiAgbnVtYmVyID0gQ1ZfZm9sZHMsIA0KICByZXBlYXRzID0gQ1ZfcmVwZWF0cywgDQogIHZlcmJvc2VJdGVyID0gRkFMU0UsIA0KICByZXR1cm5EYXRhID0gRkFMU0UNCikgDQoNCiMgdHJhaW5Db250cm9sIG9iamVjdCBmb3IgcmVwZWF0ZWQgY3Jvc3MtdmFsaWRhdGlvbiB3aXRoIGdyaWQgc2VhcmNoDQphZGFwdF9jb250cm9sX2dyaWQgPC0gY2FyZXQ6OnRyYWluQ29udHJvbCgNCiAgbWV0aG9kID0gImFkYXB0aXZlX2N2IiwgDQogIG51bWJlciA9IENWX2ZvbGRzLCANCiAgcmVwZWF0cyA9IENWX3JlcGVhdHMsIA0KICBhZGFwdGl2ZSA9IGxpc3QoDQogICAgbWluID0gbWluaW11bV9yZXNhbXBsaW5nLCANCiAgICBhbHBoYSA9IDAuMDUsICMgQ0kgdXNlZCB0byBleGNsdWRlIHBhcmFtZXRlciBzZXR0aW5ncw0KICAgIG1ldGhvZCA9ICJnbHMiLCAjIGdlbmVyYWxpemVkIGxlYXN0IHNxdWFyZXMNCiAgICBjb21wbGV0ZSA9IFRSVUUNCiAgKSwgDQogIHNlYXJjaCA9ICJncmlkIiwgIyBleGVjdXRlIGdyaWQgc2VhcmNoDQogIHZlcmJvc2VJdGVyID0gRkFMU0UsIHJldHVybkRhdGEgPSBGQUxTRSkgDQoNCiMgdHJhaW5Db250cm9sIG9iamVjdCBmb3IgcmVwZWF0ZWQgY3Jvc3MtdmFsaWRhdGlvbiB3aXRoIHJhbmRvbSBzZWFyY2gNCmFkYXB0X2NvbnRyb2xfcmFuZG9tIDwtIGNhcmV0Ojp0cmFpbkNvbnRyb2woDQogIG1ldGhvZCA9ICJhZGFwdGl2ZV9jdiIsIA0KICBudW1iZXIgPSBDVl9mb2xkcywgDQogIHJlcGVhdHMgPSBDVl9yZXBlYXRzLCANCiAgYWRhcHRpdmUgPSBsaXN0KA0KICAgIG1pbiA9IG1pbmltdW1fcmVzYW1wbGluZywgDQogICAgYWxwaGEgPSAwLjA1LCAjIENJIHVzZWQgdG8gZXhjbHVkZSBwYXJhbWV0ZXIgc2V0dGluZ3MNCiAgICBtZXRob2QgPSAiZ2xzIiwgIyBnZW5lcmFsaXplZCBsZWFzdCBzcXVhcmVzDQogICAgY29tcGxldGUgPSBUUlVFDQogICksIA0KICBzZWFyY2ggPSAicmFuZG9tIiwgIyBleGVjdXRlIHJhbmRvbSBzZWFyY2gNCiAgdmVyYm9zZUl0ZXIgPSBGQUxTRSwgcmV0dXJuRGF0YSA9IEZBTFNFDQopIA0KYGBgDQoNCiMgVGhlIFJlc3BvbnNlIFN1cmZhY2UgZm9yIENlbWVudA0KDQpJIGxpa2UgdG8gZ2V0IGFuIGlkZWEgYWJvdXQgdGhlIG5vbi1saW5lYXJpdHkgb2YgdGhlIHByb2JsZW0gYmVmb3JlIGdvaW5nIHRvbyBtdWNoIGluIGRlcHRoLiBDb21wbGV4aXRpZXMgd2lsbCBzaG93IHVwIHdoZW46DQoNCi0gUENBIGRvZXMgbm90IHNob3cgYSBkaXN0aW5jdCAqKmVsYm93Ig0KLSBQQ0EgY29tcG9uZW50cyBkbyBub3Qgc2hvdyBhIGxhcmdlIGN1bXVsYXRpdmUgcHJvcG9ydGlvbiBhZiB2YXJpYXRpb24gYWZ0ZXIgdGhlIGZpcnN0IGZldyBjb21wb25lbnRzDQotIFRoZSBncmFwaCBvZiB0aGUgcmVzcG9uc2Ugc3VyZmFjZSBzaG93cyBhIGxvdCBvZiBub24tbGluZWFyIGJlaGF2aW91cg0KDQpMZXQncyBwbG90IHN0cmVuZ3RoIGFzIGEgZnVuY3Rpb24gb2YgdGhlIGZpcnN0IHRocmVlIFBDQSBjb21wb25lbnRzIHRvIGdldCBhbiBpZGVhIG9mIHRoZSBub24tbGluZWFyaXR5IG9mIHRoZSBzdHJlbmd0aCBvZiBjb25jcmV0ZS4gSXQgaGFzIGEgbnVtYmVyIG9mIHBlYWtzIHNob3dpbmcgdGhlIG5vbi1saW5lYXJpdHkgb2YgdGhlIHN5c3RlbXMuIFRoaXMgbWVhbnMgdGhhdCBhIHNpbXBsZSByZWdyZXNzaW9uIHdpbGwgbm90IGNhcHR1cmUgdGhlIHJlc3BvbnNlIHN1cmZhY2Ugd2VsbC4gV2UgYWxzbyBoYXZlIHRvIGFjY2VwdCByYW5kb20gdmFyaWF0aW9uIGluIHRoZSBleHBlcmltZW50YWwgc2V0dXAgLSB0aGUgZGF0YSBkb2VzIG5vdCBjb21lIGZyb20gYSByZXBsaWNhdGVkIGV4cGVyaW1lbnQuDQoNCmBgYHtyLCBldmFsPVRSVUV9DQpwbG90X2x5KHR5cGUgPSAic2NhdHRlcjNkIiwNCiAgICAgICAgbW9kZSA9ICJtYXJrZXJzIiwNCiAgICAgICAgc3ltYm9sID0gImNpcmNsZS1kb3QiLA0KICAgICAgICBzaXplID0gMywNCiAgICAgICAgeCA9IGNvbmNyZXRlX2RhdGFfM0QkRGltMSwNCiAgICAgICAgeSA9IGNvbmNyZXRlX2RhdGFfM0QkRGltMiwgDQogICAgICAgIHogPSBjb25jcmV0ZV9kYXRhXzNEJERpbTMsDQogICAgICAgIGNvbG9yID0gY29uY3JldGVfZGF0YV8zRCRWMikNCg0KI3RlbXAgPC0gZGlzdGluY3QoY29uY3JldGVfZGF0YV8zRCwgRGltMSwgRGltMiwgLmtlZXBfYWxsID0gVFJVRSkNCiNnZ3Bsb3QoZGF0YSA9IHRlbXAsIGFlcyh4ID0gRGltMSwgeSA9IERpbTIsIHogPSBWMikpICsNCiMgIHN0YXRfc3VtbWFyeV8yZChjb2xvdXIgPSAid2hpdGUiLCBiaW5zID0gMTAwLCBmdW4gPSBtZWFuKSArDQojICBzY2FsZV9maWxsX2dyYWRpZW50MihtaWQgPSAiYmx1ZSIsIGhpZ2ggPSJyZWQiLCBzcGFjZSA9ICJMYWIiKQ0KYGBgDQoNCiMgQmFzZWxpbmUgUHJpbmNpcGFsIENvbXBvbmVudCBSZWdyZXNzaW9uIE1vZGVsIHdpdGggVHJhaW4vVGVzdCBTcGxpdA0KDQpgYGB7cn0NCiMgQnVpbGQgdGhlIG1vZGVsIG9uIHRyYWluaW5nIHNldA0KbW9kZWwgPC0gY2FyZXQ6OnRyYWluKA0KICBTdHJlbmd0aCB+IC4sDQogIGRhdGEgPSB0cmFpbi5kYXRhLCANCiAgbWV0aG9kID0gInBjciIsDQogIHNjYWxlID0gVFJVRSwNCiAgdHJDb250cm9sID0gdHJhaW5Db250cm9sKCJjdiIsIG51bWJlciA9IDEwKSwNCiAgdHVuZUxlbmd0aCA9IDEwDQopDQojbGlicmFyeShwbHMpDQojY3YgPSBSTVNFUChtb2RlbCkNCg0KIyBQbG90IG1vZGVsIFJNU0UgdnMgZGlmZmVyZW50IHZhbHVlcyBvZiBjb21wb25lbnRzDQpwbG90KG1vZGVsKQ0KIyBQcmludCB0aGUgYmVzdCB0dW5pbmcgcGFyYW1ldGVyIG5jb21wIHRoYXQNCiMgbWluaW1pemUgdGhlIGNyb3NzLXZhbGlkYXRpb24gZXJyb3IsIFJNU0UNCm1vZGVsJGJlc3RUdW5lDQpzdW1tYXJ5KG1vZGVsJGZpbmFsTW9kZWwpDQoNCiMgTWFrZSBwcmVkaWN0aW9ucw0KcHJlZGljdGlvbnMgPC0gbW9kZWwgJT4lIHByZWRpY3QodGVzdC5kYXRhKQ0KIyBNb2RlbCBwZXJmb3JtYW5jZSBtZXRyaWNzDQpkYXRhLmZyYW1lKA0KICBSTVNFID0gY2FyZXQ6OlJNU0UocHJlZGljdGlvbnMsIHRlc3QuZGF0YSRTdHJlbmd0aCksDQogIFJzcXVhcmUgPSBjYXJldDo6UjIocHJlZGljdGlvbnMsIHRlc3QuZGF0YSRTdHJlbmd0aCkNCikNCmBgYA0KDQoNCiMgQmFzZWxpbmUgUGFydGlhbCBMZWFzdCBTcXVhcmVzIE1vZGVsIHdpdGggVHJhaW4vVGVzdCBTcGxpdA0KDQpgYGB7cn0NCiMgQnVpbGQgdGhlIG1vZGVsIG9uIHRyYWluaW5nIHNldA0Kc2V0LnNlZWQoNDIpDQptb2RlbCA8LSBjYXJldDo6dHJhaW4oDQogIFN0cmVuZ3Rofi4sIGRhdGEgPSB0cmFpbi5kYXRhLCBtZXRob2QgPSAicGxzIiwNCiAgc2NhbGUgPSBUUlVFLA0KICB0ckNvbnRyb2wgPSB0cmFpbkNvbnRyb2woImN2IiwgbnVtYmVyID0gMTApLA0KICB0dW5lTGVuZ3RoID0gMTANCiAgKQ0KIyBQbG90IG1vZGVsIFJNU0UgdnMgZGlmZmVyZW50IHZhbHVlcyBvZiBjb21wb25lbnRzDQpwbG90KG1vZGVsKQ0KIyBQcmludCB0aGUgYmVzdCB0dW5pbmcgcGFyYW1ldGVyIG5jb21wIHRoYXQNCiMgbWluaW1pemUgdGhlIGNyb3NzLXZhbGlkYXRpb24gZXJyb3IsIFJNU0UNCm1vZGVsJGJlc3RUdW5lDQpzdW1tYXJ5KG1vZGVsJGZpbmFsTW9kZWwpDQoNCiMgTWFrZSBwcmVkaWN0aW9ucw0KcHJlZGljdGlvbnMgPC0gbW9kZWwgJT4lDQogIHByZWRpY3QodGVzdC5kYXRhKQ0KIyBNb2RlbCBwZXJmb3JtYW5jZSBtZXRyaWNzDQpkYXRhLmZyYW1lKA0KICBSTVNFID0gY2FyZXQ6OlJNU0UocHJlZGljdGlvbnMsIHRlc3QuZGF0YSRTdHJlbmd0aCksDQogIFJzcXVhcmUgPSBjYXJldDo6UjIocHJlZGljdGlvbnMsIHRlc3QuZGF0YSRTdHJlbmd0aCkNCikNCmBgYA0KDQojIFhHQm9vc3QgZm9yIFJlZ3Jlc3Npb24NCg0KUExTIGFuZCBQQ0EgcmVncmVzc2lvbnMgZG8gbm90IHJlcXVpcmUgaHlwZXJwYXJhbWV0ZXJzLiBJbiBvcmRlciB0byBnZXQgYmV0dGVyIHJlc3VsdHMgZnJvbSBtb3JlIGFkdmFuY2VkIGFsZ29yaXRobXMsIGVhY2ggbWV0aG9kIG5lZWRzIHRvIGJlIHJ1biB3aXRoIHRoZSBvcHRpbXVtIHNldCBvZiBoeXBlcnBhcmFtZXRlcnMuIFRoZXJlIGlzIG5vIGdlbmVyYWwgd2F5IHRvIGRldGVybWluZSB0aGVzZSBiZWZvcmUgY29uZHVjdGluZyBhbmFseXNpcy4NCg0KVGhlIGFuYWx5c2lzIHNvIGZhciBpbmRpY2F0ZXMgdGhhdCBlYWNoIHZhcmlhYmxlIGlzIHByZXR0eSBpbXBvcnRhbnQgZm9yIHRoZSBmaW5hbCBwcmVkaWN0aW9uLCBidXQgdGhlIGxpbmVhciBtb2RlbHMgb25seSBnZXQganVzdCBzbyBmYXIgd2l0aCBhbiBSTVNFIG9mIGFib3V0IDcuNy04LjIsIGFuZCBSc3F1YXJlIG9mIDAuNzczLTAuNzk4LiBYR0Jvb3N0IHdhcyBjaG9zZW4gZm9yIGZ1cnRoZXIgbW9kZWxpbmcgYmFzZWQgb24gcGVyZm9tYW5jZSBhbmQgc3BlZWQgYW5kIGl0cyBzdHJ1Y3R1cmUgYWxsb3dpbmcgYSBmaXQgdG8gbm9uLWxpbmVhciBhbmQgY29tcGxleCBwcm9ibGVtcy4gDQoNCj5YR0Jvb3N0IHN0YW5kcyBmb3IgZVh0cmVtZSBHcmFkaWVudCBCb29zdGluZy4NCj5UaGUgbmFtZSB4Z2Jvb3N0LCB0aG91Z2gsIGFjdHVhbGx5IHJlZmVycyB0byB0aGUgZW5naW5lZXJpbmcgZ29hbCB0byBwdXNoIHRoZSBsaW1pdCBvZiBjb21wdXRhdGlvbnMgcmVzb3VyY2VzIGZvciBib29zdGVkIHRyZWUgYWxnb3JpdGhtcy4gV2hpY2ggaXMgdGhlIHJlYXNvbiB3aHkgbWFueSBwZW9wbGUgdXNlIHhnYm9vc3QuIC0gVGlhbnFpIENoZW4NCg0KV2Ugd2lsbCB1c2VkIHRoZSAqeGdiTGluZWFyKiBtb2RlbCwgd2hpbGUgaXQgaXMgY2FsbGVkIGEgcmVncmVzc2lvbiBhbmQgY29udGFpbnMgdGhlIHdvcmQsICJsaW5lYXIiLCBhIHJlZ3Jlc3Npb24gdHJlZSBpcyBhIG5vbmxpbmVhciBtb2RlOiBJdCBpcyByZWFsbHkgYSDigJxyZWd1bGFyaXplZCBsaW5lYXIgbW9kZWzigJ0gdXNpbmcgZGVsdGEgd2l0aCBlbGFzdGljIG5ldCByZWd1bGFyaXphdGlvbiAoTDEgKyBMMiArIEwyIGJpYXMpIGFuZCBwYXJhbGxlbCBjb29yZGluYXRlIGRlc2NlbnQgb3B0aW1pemF0aW9uLiBJdCBpcyBhbHNvIGFuIGVuc2VtYmxlIGxlYXJuZXIgdGhhdCByZXN1bHRzIGluIGEgbm9uLWxpbmVhciB0cmFuc2ZlciBmdW5jdGlvbi4gICANCg0KIVtUcmVlc10oLi9maWd1cmVzL3RyZWVzLmpwZykNCg0KDQpBbiBbWEdCb29zdCBtb2RlbF0oaHR0cDovL2RtbGMuY3Mud2FzaGluZ3Rvbi5lZHUvZGF0YS9wZGYvWEdCb29zdEFyeGl2LnBkZikgd2lsbCBhbGxvdyB0aGUgZGV0ZXJtaW5hdGlvbiBvZiBpbnRlcmFjdGlvbnMgYmV0d2VlbiB2YXJpYWJsZXMuIFRoZSBtb2RlbCwgaG93ZXZlciwgd2lsbCByZXF1aXJlIHRoZSBkZXRlcm1pbmF0aW9uIG9mICpoeXBlcnBhcmFtZXRlcnMqLCBkZWZpbmVkIGFzIGFueSBwYXJhbWV0ZXIgKipub3QqKiBkZXRlcm1pbmVkIGZyb20gdGhlIGRhdGEuIFRoaXMgbWVhbnMgdXNlciBkZWZpbmVkIGFzc3VtcHRpb25zIHN1Y2ggYXMgcmVndWxhcml6YXRpb24sIHNjYWxpbmcsIHRyYW5zZm9ybWF0aW9uLCBmZWF0dXJlIGVuZ2luZWVyaW5nLCBuZXVyYWwgbmV0IGFyY2hpdGVjdHVyZSwgbnVtYmVyIG9mIGVwb2NocywgYW5kIGxlYXJuaW5nIHJhdGUgKGV0YSkuIEluZGl2aWR1YWwgYWxnb3JpdGhtcyBoYXZlIGEgc2V0IG9mIGh5cGVycGFyYW1ldGVycyBjb21tb25seSB1c2VkIGZvciB0dW5pbmcuIEZvciBYR0Jvb3N0LCB3ZSB3aWxsIGJlIGNoYW5naW5nOg0KDQojIyBHUyAtIEdyaWQgU2VhcmNoDQotIGBucm91bmRzYCAtIG51bWJlciBvZiBib29zdGluZyBpdGVyYXRpb25zDQotIGBldGFgIC0gc3RlcCBzaXplIHNocmlua2FnZQ0KLSBgbGFtYmRhYCAtIEwyIHJlZ3VsYXJpemF0aW9uDQotIGBhbHBoYWAgLSBMMSByZWd1bGFyaXphdGlvbg0KDQojIyMgR1MgLSBDcmVhdGUgVGhlIEdyaWQNCg0KYGBge3J9DQpYR0Jvb3N0X2dyaWQgPC0gZXhwYW5kLmdyaWQoDQogIG5yb3VuZHMgPSBjKDUwLCA3NSwgMTAwLCAxNTAsIDIyNSwgMzI1KSwgIyBudW1iZXIgb2YgYm9vc3RpbmcgaXRlcmF0aW9ucw0KICBldGEgPSBjKDAuMDEsIDAuMDMsIDAuMTAsIDEuMCksICMgbGVhcm5pbmcgcmF0ZSwgbG93IG1lYW5zIGxlc3Mgb3ZlcmZpdHRpbmcNCiAgbGFtYmRhID0gYygwLjEsIDAuMywgMC41LCAwLjc1LCAwLjksIDEuMCksICMgTDIgcmVndWxhcml6YXRpb24gKFJpZGdlIHJlZ3Jlc3Npb24pDQogIGFscGhhID0gYygwLjEsIDAuNSwgMC44LCAxLjApICMgTDEgcmVndWxhcml6YXRpb24gKExhc3NvIHJlZ3Jlc3Npb24pDQopDQpgYGANCg0KVGhpcyBtZWFucyAkNio0KjYqNCA9IDU3NiQgY29tYmluYXRpb25zIGFuZCB0YWtlcyBhYm91dCAxIHNlb25kIHBlciBjb21iaW5hdGlvbi4gVHJhaW5pbmcgd2lsbCBiZSBkb25lIHdpdGggYWRhcHRpdmUgc2FtcGxpbmcgd2l0aCBhIG1pbmltdW0gcmVzYW1wbGluZyBudW1iZXIgb2YgNS4NCg0KIyMjIEdTIC0gUnVuIHRoZSBTZWFyY2ggYW5kIFNhdmUgdGhlIE1vZGVsIA0KDQpgYGB7cn0NCkdTX1QwIDwtIFN5cy50aW1lKCkNCmNsdXN0ZXIgPC0gbWFrZUNsdXN0ZXIoZGV0ZWN0Q29yZXMoKSAtIDEpICMgbnVtYmVyIG9mIGNvcmVzLCBsZWF2ZSAxIGNvcmUgZm9yIE9TDQpyZWdpc3RlckRvUGFyYWxsZWwoY2x1c3RlcikgIyByZWdpc3RlciB0aGUgcGFyYWxsZWwgcHJvY2Vzc2luZw0KDQpzZXQuc2VlZCgxKTsgDQoNCiMgVHJhaW4gbW9kZWwgd2l0aCBncmlkIHNlYXJjaA0KR1NfWEdCb29zdF9MaW5lYXJfbW9kZWwgPC0gY2FyZXQ6OnRyYWluKA0KICBTdHJlbmd0aCB+LiwgDQogIGRhdGEgPSB0cmFpbi5kYXRhLA0KICBtZXRob2QgPSAieGdiTGluZWFyIiwNCiAgdHJDb250cm9sID0gYWRhcHRfY29udHJvbF9ncmlkLA0KICB2ZXJib3NlID0gRkFMU0UsIA0KICBzaWxlbnQgPSAxLA0KICAjIHR1bmVMZW5ndGggPSAyMA0KICB0dW5lR3JpZCA9IFhHQm9vc3RfZ3JpZA0KKQ0KDQpzdG9wQ2x1c3RlcihjbHVzdGVyKSAjIHNodXQgZG93biB0aGUgY2x1c3RlciANCnJlZ2lzdGVyRG9TRVEoKSAjICBmb3JjZSBSIHRvIHJldHVybiB0byBzaW5nbGUgdGhyZWFkZWQgcHJvY2Vzc2luZw0KR1NfVDEgPC0gU3lzLnRpbWUoKQ0KR1NfVDEgLSBHU19UMA0KDQpzYXZlUkRTKG9iamVjdCA9IEdTX1hHQm9vc3RfTGluZWFyX21vZGVsLCANCiAgICAgICAgZmlsZSA9ICIuL01vZGVscy9HU19YR0Jvb3N0X0xpbmVhcl9tb2RlbC5yZHMiKQ0Kc2F2ZVJEUyhvYmplY3QgPSBHU19YR0Jvb3N0X0xpbmVhcl9tb2RlbCRmaW5hbE1vZGVsLCANCiAgICAgICAgZmlsZSA9IHBhc3RlMCgiTW9kZWxzL0dTX1hHQm9vc3RfTGluZWFyX21vZGVsXyIsDQogICAgICAgICAgICAgICAgICAgICAgY2xhc3MoR1NfWEdCb29zdF9MaW5lYXJfbW9kZWwkZmluYWxNb2RlbClbMV0sIi5yZHMiKSkNCmBgYA0KDQoNCg0KDQoNCg0KIyMjIEdTIC0gU3VtbWFyaXplIHRoZSBTZWFyY2gNCg0KYGBge3J9DQpHU19YR0Jvb3N0X0xpbmVhcl9tb2RlbA0KYGBgDQoNCiMjIyBHUyAtIFBsb3QgdGhlIFNlYXJjaCBQcm9ncmVzcw0KDQpgYGB7ciwgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9OH0NCnJtKGRhdGFfcG9pbnRzKQ0KZGF0YV9wb2ludHMgPC0gZGF0YS50YWJsZShHU19YR0Jvb3N0X0xpbmVhcl9tb2RlbCRyZXN1bHRzJG5yb3VuZHMpDQpkYXRhX3BvaW50cyRldGEgPC0gR1NfWEdCb29zdF9MaW5lYXJfbW9kZWwkcmVzdWx0cyRldGENCmRhdGFfcG9pbnRzJGFscGhhIDwtIEdTX1hHQm9vc3RfTGluZWFyX21vZGVsJHJlc3VsdHMkYWxwaGENCmRhdGFfcG9pbnRzJGxhbWJkYSA8LSBHU19YR0Jvb3N0X0xpbmVhcl9tb2RlbCRyZXN1bHRzJGxhbWJkYQ0KZGF0YV9wb2ludHMkUk1TRSA8LSBHU19YR0Jvb3N0X0xpbmVhcl9tb2RlbCRyZXN1bHRzJFJNU0UNCmNvbG5hbWVzKGRhdGFfcG9pbnRzKSA8LSBjKCJucm91bmRzIiwgImV0YSIsICJhbHBoYSIsICJsYW1iZGEiLCAiUk1TRSIpDQoNCmRhdGFfcG9pbnRzICU+JQ0KICBwaXZvdF9sb25nZXIoY29scyA9IGMoIm5yb3VuZHMiLCAiZXRhIiwgImFscGhhIiwgImxhbWJkYSIsICJSTVNFIikpICU+JQ0KICBnZ3Bsb3QoYWVzKHkgPSB2YWx1ZSwgeCA9IHNlcV9hbG9uZyh2YWx1ZSkpKSArDQogIGdlb21fbGluZShjb2wgPSAiYmx1ZSIpICsNCiAgZmFjZXRfd3JhcCh+bmFtZSwgc2NhbGVzID0gImZyZWVfeSIsIG5jb2wgPSAzKSArDQogICAgc2NhbGVfeF9jb250aW51b3VzKG5hbWUgPSAiT3B0aW1pemF0aW9uIFBoYXNlIikgKw0KICBsYWJzKHRpdGxlID0gIlN5c3RlbWF0aWMgR3JpZCBTZWFyY2giKSArDQogICAgdGhlbWUoYXhpcy50aXRsZS54PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpY2tzLng9ZWxlbWVudF9ibGFuaygpKSArDQogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIiIpDQpgYGANCg0KIyMjIyBHUyAtIFBsb3QgVGhlIFJNU0UgUmVzdWx0cw0KDQpgYGB7ciwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9OH0NClJNU0VfcGxvdF9YR0Jvb3N0X0xpbmVhciA8LSBHU19YR0Jvb3N0X0xpbmVhcl9tb2RlbCRyZXN1bHRzICU+JSANCiAgZHBseXI6OnNlbGVjdChucm91bmRzLCBsYW1iZGEsIGFscGhhLCBldGEsIFJNU0UpICU+JSANCiAgZ2F0aGVyKGtleSA9IFBhcmFtZXRlciwgdmFsdWUgPSBWYWx1ZSwgLW5yb3VuZHMsIC1sYW1iZGEsIC1hbHBoYSwgLWV0YSkgJT4lIA0KICBmaWx0ZXIoUGFyYW1ldGVyID09ICJSTVNFIikgJT4lIA0KICBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4ID0gbnJvdW5kcywgeSA9IFZhbHVlLCBjb2wgPSBmYWN0b3IobGFtYmRhKSwgc2hhcGUgPSBmYWN0b3IoYWxwaGEpKSkgKw0KICAgIGdlb21fbGluZShzaXplID0gMSkgKw0KICAgIGdlb21fcG9pbnQoc2l6ZSA9IDIpICsNCiAgICBmYWNldF93cmFwKH5ldGEpICsNCiAgICBsYWJzKHRpdGxlID0gIkF2ZXJhZ2UgQ3Jvc3MtdmFsaWRhdGVkIFJNU0Ugb2YgWEdCb29zdCBMaW5lYXIgTW9kZWwiLA0KICAgICAgIHN1YnRpdGxlID0gIlRpbGVzIHJlcHJlc2VudGF0aXZlIG9mIHN0ZXAgc2l6ZSBzaHJpbmthZ2UgKGV0YSkiLA0KICAgICAgIHggPSAiIyBCb29zdGluZyBJdGVyYXRpb25zIiwNCiAgICAgICB5ID0gIlJNU0UiLA0KICAgICAgIGNvbCA9ICJsYW1iZGEiLA0KICAgICAgIHNoYXBlID0gImFscGhhIg0KICAgICAgICkgKw0KICB0aGVtZV9idygpICsNCiAgdGhlbWUoDQogICAgICAgICMgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwgZmFjZT0iYm9sZCIpLA0KICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOSksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xNiksDQogICAgICAgIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTAsIGZhY2U9ImJvbGQiKSwNCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwKSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gdW5pcXVlKEdTX1hHQm9vc3RfTGluZWFyX21vZGVsJHJlc3VsdHMkbnJvdW5kcykpICsNCiAgc2NhbGVfY29sb3JfYnJld2VyKHR5cGUgPSAicXVhbCIsIHBhbGV0dGUgPSAiU2V0MSIpDQpSTVNFX3Bsb3RfWEdCb29zdF9MaW5lYXINCmBgYA0KDQojIyMjIEdTIC0gUGxvdCB0aGUgTUFFIFJlc3VsdHMNCg0KYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTh9DQpNQUVfcGxvdF9YR0Jvb3N0X0xpbmVhciA8LSBHU19YR0Jvb3N0X0xpbmVhcl9tb2RlbCRyZXN1bHRzICU+JSANCiAgZHBseXI6OnNlbGVjdChucm91bmRzLCBsYW1iZGEsIGFscGhhLCBldGEsIE1BRSkgJT4lIA0KICBnYXRoZXIoa2V5ID0gUGFyYW1ldGVyLCB2YWx1ZSA9IFZhbHVlLCAtbnJvdW5kcywgLWxhbWJkYSwgLWFscGhhLCAtZXRhKSAlPiUgDQogIGZpbHRlcihQYXJhbWV0ZXIgPT0gIk1BRSIpICU+JSANCiAgZ2dwbG90KG1hcHBpbmcgPSBhZXMoeCA9IG5yb3VuZHMsIHkgPSBWYWx1ZSwgY29sID0gZmFjdG9yKGxhbWJkYSksIHNoYXBlID0gZmFjdG9yKGFscGhhKSkpICsNCiAgICBnZW9tX2xpbmUoc2l6ZSA9IDEpICsNCiAgICBnZW9tX3BvaW50KHNpemUgPSAyKSArDQogICAgZmFjZXRfd3JhcCh+ZXRhKSArDQogICAgbGFicyh0aXRsZSA9ICJBdmVyYWdlIENyb3NzLXZhbGlkYXRlZCBNQUUgb2YgWEdCb29zdCBMaW5lYXIgTW9kZWwiLA0KICAgICAgIHN1YnRpdGxlID0gIlRpbGVzIHJlcHJlc2VudGF0aXZlIG9mIHN0ZXAgc2l6ZSBzaHJpbmthZ2UgKGV0YSkiLA0KICAgICAgIHggPSAiIyBCb29zdGluZyBJdGVyYXRpb25zIiwNCiAgICAgICB5ID0gIk1BRSIsDQogICAgICAgY29sID0gImxhbWJkYSIsDQogICAgICAgc2hhcGUgPSAiYWxwaGEiDQogICAgICAgKSArDQogIHRoZW1lX2J3KCkgKw0KICB0aGVtZSgNCiAgICAgICAgIyBwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBmYWNlPSJib2xkIiksDQogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE2KSwNCiAgICAgICAgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMCwgZmFjZT0iYm9sZCIpLA0KICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDApKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSB1bmlxdWUoR1NfWEdCb29zdF9MaW5lYXJfbW9kZWwkcmVzdWx0cyRucm91bmRzKSkgKw0KICBzY2FsZV9jb2xvcl9icmV3ZXIodHlwZSA9ICJxdWFsIiwgcGFsZXR0ZSA9ICJTZXQxIikNCk1BRV9wbG90X1hHQm9vc3RfTGluZWFyDQpgYGANCg0KIyMjIyBHUyAtIFBsb3QgdGhlIFJTcXVhcmVkIFJlc3VsdHMNCg0KYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTh9DQpSc3F1YXJlZF9wbG90X1hHQm9vc3RfTGluZWFyIDwtIEdTX1hHQm9vc3RfTGluZWFyX21vZGVsJHJlc3VsdHMgJT4lIA0KICBkcGx5cjo6c2VsZWN0KG5yb3VuZHMsIGxhbWJkYSwgYWxwaGEsIGV0YSwgUnNxdWFyZWQpICU+JSANCiAgZ2F0aGVyKGtleSA9IFBhcmFtZXRlciwgdmFsdWUgPSBWYWx1ZSwgLW5yb3VuZHMsIC1sYW1iZGEsIC1hbHBoYSwgLWV0YSkgJT4lIA0KICBmaWx0ZXIoUGFyYW1ldGVyID09ICJSc3F1YXJlZCIpICU+JSANCiAgZ2dwbG90KG1hcHBpbmcgPSBhZXMoeCA9IG5yb3VuZHMsIHkgPSBWYWx1ZSwgY29sID0gZmFjdG9yKGxhbWJkYSksIHNoYXBlID0gZmFjdG9yKGFscGhhKSkpICsNCiAgICBnZW9tX2xpbmUoc2l6ZSA9IDEpICsNCiAgICBnZW9tX3BvaW50KHNpemUgPSAyKSArDQogICAgZmFjZXRfd3JhcCh+ZXRhKSArDQogICAgbGFicyh0aXRsZSA9ICJBdmVyYWdlIENyb3NzLXZhbGlkYXRlZCBSLXNxdWFyZWQgb2YgWEdCb29zdCBMaW5lYXIgTW9kZWwiLA0KICAgICAgIHN1YnRpdGxlID0gIlRpbGVzIHJlcHJlc2VudGF0aXZlIG9mIHN0ZXAgc2l6ZSBzaHJpbmthZ2UgKGV0YSkiLA0KICAgICAgIHggPSAiIyBCb29zdGluZyBJdGVyYXRpb25zIiwNCiAgICAgICB5ID0gIlItc3F1YXJlZCIsDQogICAgICAgY29sID0gImxhbWJkYSIsDQogICAgICAgc2hhcGUgPSAiYWxwaGEiDQogICAgICAgKSArDQogIHRoZW1lX2J3KCkgKw0KICB0aGVtZSgNCiAgICAgICAgIyBwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBmYWNlPSJib2xkIiksDQogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE2KSwNCiAgICAgICAgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMCwgZmFjZT0iYm9sZCIpLA0KICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDApKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSB1bmlxdWUoR1NfWEdCb29zdF9MaW5lYXJfbW9kZWwkcmVzdWx0cyRucm91bmRzKSkgKw0KICBzY2FsZV9jb2xvcl9icmV3ZXIodHlwZSA9ICJxdWFsIiwgcGFsZXR0ZSA9ICJTZXQxIikgDQpSc3F1YXJlZF9wbG90X1hHQm9vc3RfTGluZWFyDQpgYGANCg0KIyMjIEdTIC0gSW52ZXN0aWdhdGUgSW50ZXJhY3Rpb25zIEJldHdlZW4gSHlwZXJwYXJhbWV0ZXIgVmFsdWVzDQoNCmBgYHtyfQ0KZ2V0UGFsZXR0ZSA9IGNvbG9yUmFtcFBhbGV0dGUoUkNvbG9yQnJld2VyOjpicmV3ZXIucGFsKDgsICJTZXQyIikpKDEwKSANCkdTX1hHQm9vc3RfTGluZWFyX21vZGVsJHJlc3VsdHMgJT4lDQogIHBsb3RfbHkod2lkdGggPSA3MDAsIGhlaWdodCA9IDUwMCkgJT4lDQogIGFkZF90cmFjZSh0eXBlID0gJ3BhcmNvb3JkcycsDQogICAgICAgICAgICBsaW5lID0gbGlzdChjb2xvciA9IH5STVNFLA0KICAgICAgICAgICAgICAgICAgICAgICAgY29sb3JzY2FsZSA9IGxpc3QoZ2V0UGFsZXR0ZSksDQogICAgICAgICAgICAgICAgICAgICAgICBjbWluID0gNC42MCwNCiAgICAgICAgICAgICAgICAgICAgICAgIGNtYXggPSA0Ljg1KSwNCiAgICAgICAgICAgIGRpbWVuc2lvbnMgPSBsaXN0KA0KICAgICAgICAgICAgICBsaXN0KHJhbmdlID0gYyh+bWluKFJNU0UpLH5tYXgoUk1TRSkpLA0KICAgICAgICAgICAgICAgICAgIGxhYmVsID0gJ1JNU0UnLCB2YWx1ZXMgPSB+Uk1TRSksDQogICAgICAgICAgICAgIGxpc3QocmFuZ2UgPSBjKH5taW4obnJvdW5kcyksfm1heChucm91bmRzKSksDQogICAgICAgICAgICAgICAgICAgbGFiZWwgPSAnbnJvdW5kcycsIHZhbHVlcyA9IH5ucm91bmRzKSwNCiAgICAgICAgICAgICAgbGlzdChyYW5nZSA9IGMofm1pbihldGEpLH5tYXgoZXRhKSksDQogICAgICAgICAgICAgICAgICAgbGFiZWwgPSAnZXRhJywgdmFsdWVzID0gfmV0YSksDQogICAgICAgICAgICAgIGxpc3QocmFuZ2UgPSBjKH5taW4obGFtYmRhKSx+bWF4KGxhbWJkYSkpLA0KICAgICAgICAgICAgICAgICAgIGxhYmVsID0gJ2xhbWJkYScsIHZhbHVlcyA9IH5sYW1iZGEpLA0KICAgICAgICAgICAgICBsaXN0KHJhbmdlID0gYyh+bWluKGFscGhhKSx+bWF4KGFscGhhKSksDQogICAgICAgICAgICAgICAgICAgbGFiZWwgPSAnYWxwaGEnLCB2YWx1ZXMgPSB+YWxwaGEpDQogICAgICAgICAgICApDQogICkNCmBgYA0KDQpXZSBhcmUgc2VlaW5nLCBpbiBnZW5lcmFsLCBoaWdoZXIgdmFsdWVzIG9mIGxhbWJkYSwgYWxwaGEgYW5kIGV0YSBhcmUgYmV0dGVyIGFuZCB0aGF0IHJlc3VsdHMgZG9uJ3QgY2hhbmdlIG11Y2ggYWZ0ZXIgYWJvdXQgMjAwIHJvdW5kcy4gVGhpcyB0b29rIDExMDIuMzMgc2VjIHRvIHJlYWNoIHRoaXMgc29sdXRpb24gYnkgZXZhbHVhdGluZyA2NzIgbW9kZWxzLg0KDQojIyMgR1MgLSBUZXN0IFRoZSBNb2RlbCB3aXRoIE9wdGltaXplZCBHUyBTZXR0aW5ncw0KDQpgYGB7cn0NCiMgR3JpZCBvZiBvcHRpbWFsIGh5cGVycGFyYW1ldGVyIHZhbHVlcw0KDQpHU19YR0Jvb3N0X0xpbmVhcl9ncmlkIDwtIGV4cGFuZC5ncmlkKA0KICBucm91bmRzID0gR1NfWEdCb29zdF9MaW5lYXJfbW9kZWwkYmVzdFR1bmUkbnJvdW5kcywgICMgbGVhcm5pbmcgcmF0ZSwgbG93IHZhbHVlIG1lYW5zIG1vZGVsIGlzIG1vcmUgcm9idXN0IHRvIG92ZXJmaXR0aW5nDQogIGV0YSA9IEdTX1hHQm9vc3RfTGluZWFyX21vZGVsJGJlc3RUdW5lJGV0YSwgIyBudW1iZXIgb2YgYm9vc3RpbmcgaXRlcmF0aW9ucw0KICBhbHBoYSA9IEdTX1hHQm9vc3RfTGluZWFyX21vZGVsJGJlc3RUdW5lJGFscGhhLCAjIEwyIFJlZ3VsYXJpemF0aW9uIChSaWRnZSBSZWdyZXNzaW9uKQ0KICBsYW1iZGEgPSBHU19YR0Jvb3N0X0xpbmVhcl9tb2RlbCRiZXN0VHVuZSRsYW1iZGEgIyBMMSBSZWd1bGFyaXphdGlvbiAoTGFzc28gUmVncmVzc2lvbikNCikNCg0KdGljKCkNCmNsdXN0ZXIgPC0gbWFrZUNsdXN0ZXIoZGV0ZWN0Q29yZXMoKSAtIDEpICMgbnVtYmVyIG9mIGNvcmVzLCBjb252ZW50aW9uIHRvIGxlYXZlIDEgY29yZSBmb3IgT1MNCnJlZ2lzdGVyRG9QYXJhbGxlbChjbHVzdGVyKSAjIHJlZ2lzdGVyIHRoZSBwYXJhbGxlbCBwcm9jZXNzaW5nDQoNCnNldC5zZWVkKDEpDQojIFRyYWluIG1vZGVsIHdpdGggb3B0aW1hbCB2YWx1ZXMNCkdTX1hHQm9vc3RfTGluZWFyX21vZGVsX2ZpbiA8LSBjYXJldDo6dHJhaW4oDQogIFN0cmVuZ3RoIH4uLCANCiAgZGF0YSA9IHRyYWluLmRhdGEsIA0KICBtZXRob2QgPSAieGdiTGluZWFyIiwNCiAgdHJDb250cm9sID0gdHJhaW5fY29udHJvbCwNCiAgdmVyYm9zZSA9IEYsIG1ldHJpYyA9ICJSTVNFIiwgbWF4aW1pemUgPSBGQUxTRSwNCiAgc2lsZW50ID0gMSwNCiAgIyB0dW5lTGVuZ3RoID0gMQ0KICB0dW5lR3JpZCA9IEdTX1hHQm9vc3RfTGluZWFyX2dyaWQNCikNCg0Kc3RvcENsdXN0ZXIoY2x1c3RlcikgIyBzaHV0IGRvd24gdGhlIGNsdXN0ZXIgDQpyZWdpc3RlckRvU0VRKCkgIyAgZm9yY2UgUiB0byByZXR1cm4gdG8gc2luZ2xlIHRocmVhZGVkIHByb2Nlc3NpbmcNCnRvYygpDQoNCkdTX1hHQm9vc3RfTGluZWFyX21vZGVsX2Zpbg0KDQpzYXZlUkRTKG9iamVjdCA9IEdTX1hHQm9vc3RfTGluZWFyX21vZGVsX2ZpbiwgZmlsZSA9ICJNb2RlbHMvR1NfWEdCb29zdF9MaW5lYXJfbW9kZWwucmRzIikNCmBgYA0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQojIyBSUyAtIFJhbmRvbSBTZWFyY2ggVXNpbmcgUmFuZG9tIEFkYXB0aXZlIFNhbXBsaW5nDQoNCldlIGFyZSBnb2luZyB0byBzZWUgaWYgd2UgY2FuIHJlYWNoIHNpbWlsYXIgcmVzdWx0cyB0byB0aGUgZ3JpZCBzZWFyY2ggYnkgY2hvb3NpbmcgdGhlIHNhbWUgbnVtYmVyIG9mIGNvbmZpZ3VyYXRpb25zLCBidXQgY2hvc2VuIHJhbmRvbWx5Lg0KDQpgYGB7cn0NCm5fY29tYmluYXRpb25zIDwtIG5yb3coWEdCb29zdF9ncmlkKQ0KYGBgDQoNCiMjIyBSUyAtIFJ1biB0aGUgT3B0aW1pemF0aW9uIGFuZCBTYXZlIHRoZSBNb2RlbA0KDQpgYGB7cn0NClJTX1QwIDwtIFN5cy50aW1lKCkNCmNsdXN0ZXIgPC0gbWFrZUNsdXN0ZXIoZGV0ZWN0Q29yZXMoKSAtIDEpICMgbnVtYmVyIG9mIGNvcmVzLCBsZWF2ZSAxIGNvcmUgZm9yIE9TDQpyZWdpc3RlckRvUGFyYWxsZWwoY2x1c3RlcikgIyByZWdpc3RlciB0aGUgcGFyYWxsZWwgcHJvY2Vzc2luZw0KDQpzZXQuc2VlZCgxKQ0KIyBUcmFpbiBtb2RlbCB3aXRoIGdyaWQgc2VhcmNoDQpSU19YR0Jvb3N0X0xpbmVhcl9tb2RlbCA8LSBjYXJldDo6dHJhaW4oDQogIFN0cmVuZ3RoIH4uLCANCiAgZGF0YSA9IHRyYWluLmRhdGEsDQogIG1ldGhvZCA9ICJ4Z2JMaW5lYXIiLA0KICB0ckNvbnRyb2wgPSBhZGFwdF9jb250cm9sX3JhbmRvbSwNCiAgdmVyYm9zZSA9IEZBTFNFLCANCiAgc2lsZW50ID0gMSwNCiAgdHVuZUxlbmd0aCA9IG5fY29tYmluYXRpb25zDQojICB0dW5lTGVuZ3RoID0gMjANCikNCnN0b3BDbHVzdGVyKGNsdXN0ZXIpICMgc2h1dCBkb3duIHRoZSBjbHVzdGVyIA0KcmVnaXN0ZXJEb1NFUSgpICMgIGZvcmNlIFIgdG8gcmV0dXJuIHRvIHNpbmdsZSB0aHJlYWRlZCBwcm9jZXNzaW5nDQpSU19UMSA8LSBTeXMudGltZSgpDQpSU19UMSAtIFJTX1QwDQoNCiNSU19YR0Jvb3N0X0xpbmVhcl9tb2RlbCA8LSByZWFkUkRTKGZpbGUgPSAiTW9kZWxzL1JTX1hHQm9vc3RfTGluZWFyX21vZGVsLnJkcyIpDQoNCnNhdmVSRFMob2JqZWN0ID0gUlNfWEdCb29zdF9MaW5lYXJfbW9kZWwsIGZpbGUgPSAiTW9kZWxzL1JTX1hHQm9vc3RfTGluZWFyX21vZGVsLnJkcyIpDQpzYXZlUkRTKG9iamVjdCA9IFJTX1hHQm9vc3RfTGluZWFyX21vZGVsJGZpbmFsTW9kZWwsIGZpbGUgPSBwYXN0ZTAoIk1vZGVscy9SU19YR0Jvb3N0X0xpbmVhcl9tb2RlbF8iLCBjbGFzcyhSU19YR0Jvb3N0X0xpbmVhcl9tb2RlbCRmaW5hbE1vZGVsKVsxXSwiLnJkcyIpKQ0KYGBgDQoNCiMjIyBSUyAtIFN1bW1hcml6ZSB0aGUgT3B0aW1pemF0aW9uDQoNCmBgYHtyfQ0KUlNfWEdCb29zdF9MaW5lYXJfbW9kZWwNCmBgYA0KDQojIyMgUlMgLSBHcmlkIFNlYXJjaCBQcm9ncmVzcw0KDQpgYGB7ciwgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9OH0NCnJtKGRhdGFfcG9pbnRzKQ0KZGF0YV9wb2ludHMgPC0gZGF0YS50YWJsZShSU19YR0Jvb3N0X0xpbmVhcl9tb2RlbCRyZXN1bHRzJG5yb3VuZHMpDQpkYXRhX3BvaW50cyRldGEgPC0gUlNfWEdCb29zdF9MaW5lYXJfbW9kZWwkcmVzdWx0cyRldGENCmRhdGFfcG9pbnRzJGFscGhhIDwtIFJTX1hHQm9vc3RfTGluZWFyX21vZGVsJHJlc3VsdHMkYWxwaGENCmRhdGFfcG9pbnRzJGxhbWJkYSA8LSBSU19YR0Jvb3N0X0xpbmVhcl9tb2RlbCRyZXN1bHRzJGxhbWJkYQ0KZGF0YV9wb2ludHMkUk1TRSA8LSBSU19YR0Jvb3N0X0xpbmVhcl9tb2RlbCRyZXN1bHRzJFJNU0UNCmNvbG5hbWVzKGRhdGFfcG9pbnRzKSA8LSBjKCJucm91bmRzIiwgImV0YSIsICJhbHBoYSIsICJsYW1iZGEiLCAiUk1TRSIpDQoNCmRhdGFfcG9pbnRzICU+JQ0KICBwaXZvdF9sb25nZXIoY29scyA9IGMoIm5yb3VuZHMiLCAiZXRhIiwgImFscGhhIiwgImxhbWJkYSIsICJSTVNFIikpICU+JQ0KICBnZ3Bsb3QoYWVzKHkgPSB2YWx1ZSwgeCA9IHNlcV9hbG9uZyh2YWx1ZSkpKSArDQogIGdlb21fbGluZShjb2wgPSAiYmx1ZSIpICsNCiAgZmFjZXRfd3JhcCh+bmFtZSwgc2NhbGVzID0gImZyZWVfeSIsIG5jb2wgPSAzKSArDQogICAgc2NhbGVfeF9jb250aW51b3VzKG5hbWUgPSAiT3B0aW1pemF0aW9uIFBoYXNlIikgKw0KICBsYWJzKHRpdGxlID0gIkFkYXB0aXZlIFJhbmRvbSBTZWFyY2giKSArDQogICAgdGhlbWUoYXhpcy50aXRsZS54PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpY2tzLng9ZWxlbWVudF9ibGFuaygpKSArDQogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIiIpDQpgYGANCg0KDQoNCg0KDQoNCg0KDQoNCiMjIyBSUyAtIEludmVzdGlnYXRlIEludGVyYWN0aW9ucyBCZXR3ZWVuIEh5cGVycGFyYW1ldGVyIFZhbHVlcw0KDQpgYGB7cn0NCmdldFBhbGV0dGUgPSBjb2xvclJhbXBQYWxldHRlKFJDb2xvckJyZXdlcjo6YnJld2VyLnBhbCg4LCAiU2V0MiIpKSgxMCkgDQpSU19YR0Jvb3N0X0xpbmVhcl9tb2RlbCRyZXN1bHRzICU+JQ0KICBwbG90X2x5KHdpZHRoID0gNzAwLCBoZWlnaHQgPSA1MDApICU+JQ0KICBhZGRfdHJhY2UodHlwZSA9ICdwYXJjb29yZHMnLA0KICAgICAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSB+Uk1TRSwNCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yc2NhbGUgPSBsaXN0KGdldFBhbGV0dGUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgY21pbiA9IDQuNjAsDQogICAgICAgICAgICAgICAgICAgICAgICBjbWF4ID0gNC44NSksDQogICAgICAgICAgICBkaW1lbnNpb25zID0gbGlzdCgNCiAgICAgICAgICAgICAgI2xpc3QocmFuZ2UgPSBjKH5taW4oUk1TRSksfm1heChSTVNFKSksDQogICAgICAgICAgICAgIGxpc3QocmFuZ2UgPSBjKH5taW4oUk1TRSksNS41KSwNCiAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICdSTVNFJywgdmFsdWVzID0gflJNU0UpLA0KICAgICAgICAgICAgICBsaXN0KHJhbmdlID0gYyh+bWluKG5yb3VuZHMpLH5tYXgobnJvdW5kcykpLA0KICAgICAgICAgICAgICAgICAgIGxhYmVsID0gJ25yb3VuZHMnLCB2YWx1ZXMgPSB+bnJvdW5kcyksDQogICAgICAgICAgICAgIGxpc3QocmFuZ2UgPSBjKH5taW4oZXRhKSx+bWF4KGV0YSkpLA0KICAgICAgICAgICAgICAgICAgIGxhYmVsID0gJ2V0YScsIHZhbHVlcyA9IH5ldGEpLA0KICAgICAgICAgICAgICBsaXN0KHJhbmdlID0gYyh+bWluKGxhbWJkYSksfm1heChsYW1iZGEpKSwNCiAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICdsYW1iZGEnLCB2YWx1ZXMgPSB+bGFtYmRhKSwNCiAgICAgICAgICAgICAgbGlzdChyYW5nZSA9IGMofm1pbihhbHBoYSksfm1heChhbHBoYSkpLA0KICAgICAgICAgICAgICAgICAgIGxhYmVsID0gJ2FscGhhJywgdmFsdWVzID0gfmFscGhhKQ0KICAgICAgICAgICAgKQ0KICApDQpgYGANCg0KT2YgY291cnNlLCB3ZSBzZWUgdGhhdCB0aGUgdGhlIGh5cGVyc3BhY2Ugb2Ygc2FtcGxpbmcgaXMgbGFyZ2VyIHRoYW4gdGhlIGdyaWQgc2VhcmNoLCBidXQgdGhlIGFsZ29yaXRobSBob25lcyBpbiBvbiB0aGUgYmVzdCBhcmVhcyBpbiBoeXBlcnNwYWNlLiBXZSBhcmUgc2VlaW5nLCBpbiBnZW5lcmFsLCBoaWdoZXIgdmFsdWVzIG9mIGxhbWJkYSwgYWxwaGEgYW5kIGV0YSBhcmUgYmV0dGVyIGFuZCB0aGF0IHJlc3VsdHMgZG9uJ3QgY2hhbmdlIG11Y2ggYWZ0ZXIgYWJvdXQgMjAwIHJvdW5kcy4gVGhpcyB0b29rIDExMDIuMzMgc2VjIHRvIHJlYWNoIHRoaXMgc29sdXRpb24gYnkgZXZhbHVhdGluZyA2NzIgbW9kZWxzLg0KDQojIyMgUlMgLSBUZXN0IFRoZSBNb2RlbCB3aXRoIE9wdGltaXplZCBSUyBTZXR0aW5ncw0KDQpgYGB7cn0NClJTX1hHQm9vc3RfTGluZWFyX21vZGVsJGJlc3RUdW5lDQpgYGANCg0KYGBge3J9DQojIEdyaWQgb2Ygb3B0aW1hbCBoeXBlcnBhcmFtZXRlciB2YWx1ZXMNCg0KUlNfWEdCb29zdF9MaW5lYXJfZ3JpZCA8LSBleHBhbmQuZ3JpZCgNCiAgbnJvdW5kcyA9IFJTX1hHQm9vc3RfTGluZWFyX21vZGVsJGJlc3RUdW5lJG5yb3VuZHMsICAjIGxlYXJuaW5nIHJhdGUsIGxvdyB2YWx1ZSBtZWFucyBtb2RlbCBpcyBtb3JlIHJvYnVzdCB0byBvdmVyZml0dGluZw0KICBldGEgPSBSU19YR0Jvb3N0X0xpbmVhcl9tb2RlbCRiZXN0VHVuZSRldGEsICMgbnVtYmVyIG9mIGJvb3N0aW5nIGl0ZXJhdGlvbnMNCiAgYWxwaGEgPSBSU19YR0Jvb3N0X0xpbmVhcl9tb2RlbCRiZXN0VHVuZSRhbHBoYSwgIyBMMiBSZWd1bGFyaXphdGlvbiAoUmlkZ2UgUmVncmVzc2lvbikNCiAgbGFtYmRhID0gUlNfWEdCb29zdF9MaW5lYXJfbW9kZWwkYmVzdFR1bmUkbGFtYmRhICMgTDEgUmVndWxhcml6YXRpb24gKExhc3NvIFJlZ3Jlc3Npb24pDQopDQoNCnRpYygpDQpjbHVzdGVyIDwtIG1ha2VDbHVzdGVyKGRldGVjdENvcmVzKCkgLSAxKSAjIG51bWJlciBvZiBjb3JlcywgY29udmVudGlvbiB0byBsZWF2ZSAxIGNvcmUgZm9yIE9TDQpyZWdpc3RlckRvUGFyYWxsZWwoY2x1c3RlcikgIyByZWdpc3RlciB0aGUgcGFyYWxsZWwgcHJvY2Vzc2luZw0KDQpzZXQuc2VlZCgxKQ0KIyBUcmFpbiBtb2RlbCB3aXRoIG9wdGltYWwgdmFsdWVzDQpSU19YR0Jvb3N0X0xpbmVhcl9tb2RlbF9maW4gPC0gY2FyZXQ6OnRyYWluKA0KICBTdHJlbmd0aCB+LiwgDQogIGRhdGEgPSB0cmFpbi5kYXRhLCANCiAgbWV0aG9kID0gInhnYkxpbmVhciIsDQogIHRyQ29udHJvbCA9IHRyYWluX2NvbnRyb2wsDQogIHZlcmJvc2UgPSBGLCBtZXRyaWMgPSAiUk1TRSIsIG1heGltaXplID0gRkFMU0UsDQogIHNpbGVudCA9IDEsDQogIHR1bmVHcmlkID0gKFJTX1hHQm9vc3RfTGluZWFyX2dyaWQpDQopDQoNCnN0b3BDbHVzdGVyKGNsdXN0ZXIpICMgc2h1dCBkb3duIHRoZSBjbHVzdGVyIA0KcmVnaXN0ZXJEb1NFUSgpICMgIGZvcmNlIFIgdG8gcmV0dXJuIHRvIHNpbmdsZSB0aHJlYWRlZCBwcm9jZXNzaW5nDQp0b2MoKQ0KDQpSU19YR0Jvb3N0X0xpbmVhcl9tb2RlbF9maW4NCg0Kc2F2ZVJEUyhvYmplY3QgPSBSU19YR0Jvb3N0X0xpbmVhcl9tb2RlbF9maW4sIGZpbGUgPSAiTW9kZWxzL1JTX1hHQm9vc3RfTGluZWFyX21vZGVsLnJkcyIpDQpgYGANCg0KDQoNCg0KDQoNCg0KDQojIyBHQSAtIEdlbmV0aWMgQWxnb3JpdGhtDQoNClNpbmNlIHRoaXMgaXMgYW4gb3B0aW1pemF0aW9uIHByb2JsZW0sIHdlIGNhbiB1c2Ugb3B0aW1pemF0aW9uIHRlY2huaXF1ZXMgdG8gYXNzZXNzIGFuZCByZWZpbmUgdGhlIGJlc3QgY29tYmluYXRpb25zIG9mIGh5cGVycGFyZW1ldGVycy4gVGhpcyBhcHByb2FjaCBoYXMgdHdvIHJlcXVpcmVtZW50czoNCg0KLSBhIGZ1bmN0aW9uIHRvIGV2YWx1YXRlIHRoZSBzY29yZSBmb3Igc3RyYXRlZ2llcywgY2FsbGVkIHRoZSAqKmZpdG5lc3MqKg0KLSB0aGUgbWluaW11bSBhbmQgbWF4aW11bSB2YWx1ZXMgYWxsb3dhYmxlIGZvciBlYWNoIGh5cGVycGFyYW1ldGVyDQotIHRoZSBwb3B1bGF0aW9uIHNpemUNCg0KDQpHb29kIFthcnRpY2xlIGhlcmVdKGh0dHBzOi8vYmxvZy5kYXRhc2NpZW5jZWhlcm9lcy5jb20vZmVhdHVyZS1zZWxlY3Rpb24tdXNpbmctZ2VuZXRpYy1hbGdvcml0aG1zLWluLXIvKSBmcm9tIHRoZSBSLWJsb2dnZXJzIG1haWxpbmcgbGlzdC4gVGhlcmUgaXMgYSB2aWduZXR0ZSBbaGVyZV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL0dBL3ZpZ25ldHRlcy9HQS5odG1sKSBieSBMdWNhIFNjcnVjY2EuDQoNCkhhdmUgYSBsb29rIGF0IFt0aGlzIGFydGljbGVdKGh0dHBzOi8vdG93YXJkc2RhdGFzY2llbmNlLmNvbS9oeXBlcnBhcmFtZXRlci10dW5pbmctaW4teGdib29zdC11c2luZy1nZW5ldGljLWFsZ29yaXRobS0xN2JkMmU1ODFiMTcpDQoNCiMjIyBHQSAtIENyZWF0ZSBUaGUgRnVuY3Rpb24gRm9yIEFzc2Vzc2luZyBTb2x1dGlvbnMNCg0KYGBge3J9DQojIENyZWF0ZSBjdXN0b20gZnVuY3Rpb24gZm9yIGFzc2Vzc2luZyBzb2x1dGlvbnMNCmV2YWxfZnVuY3Rpb25fWEdCb29zdF9MaW5lYXIgPC0gZnVuY3Rpb24oeDEsIHgyLCB4MywgeDQsIGRhdGEsIHRyYWluX3NldHRpbmdzKSB7DQogIHN1cHByZXNzV2FybmluZ3MoDQogICAgWEdCb29zdF9MaW5lYXJfbW9kZWwgPC0gY2FyZXQ6OnRyYWluKA0KICAgICAgU3RyZW5ndGggfi4sIA0KICAgICAgZGF0YSA9IGRhdGEsDQogICAgICBtZXRob2QgPSAieGdiTGluZWFyIiwNCiAgICAgIHRyQ29udHJvbCA9IHRyYWluX3NldHRpbmdzLA0KICAgICAgdmVyYm9zZSA9IEZBTFNFLCANCiAgICAgIHNpbGVudCA9IDEsDQogICAgICB0dW5lR3JpZCA9IGV4cGFuZC5ncmlkKA0KICAgICAgICBucm91bmRzID0gcm91bmQoeDEpLCAjIG51bWJlciBvZiBib29zdGluZyBpdGVyYXRpb25zDQogICAgICAgIGV0YSA9IDEwXngyLCAjIGxlYXJuaW5nIHJhdGUsIGxvdyB2YWx1ZSBtZWFucyBtb2RlbCBpcyBtb3JlIHJvYnVzdCB0byBvdmVyZml0dGluZw0KICAgICAgICBhbHBoYSA9IDEwXngzLCAjIEwxIFJlZ3VsYXJpemF0aW9uIChlcXVpdmFsZW50IHRvIExhc3NvIFJlZ3Jlc3Npb24pIG9uIHdlaWdodHMNCiAgICAgICAgbGFtYmRhID0gMTBeeDQgIyBMMiBSZWd1bGFyaXphdGlvbiAoZXF1aXZhbGVudCB0byByaWRnZSBSZWdyZXNzaW9uKSBvbiB3ZWlnaHRzDQogICAgICApIA0KICAgICkNCiAgKQ0KcmV0dXJuKC1YR0Jvb3N0X0xpbmVhcl9tb2RlbCRyZXN1bHRzJFJNU0UpICMgbWluaW1pemUgUk1TRQ0KfQ0KDQojIERlZmluZSBtaW5pbXVtIGFuZCBtYXhpbXVtIHZhbHVlcyBmb3IgZWFjaCBpbnB1dA0KbnJvdW5kc19taW5fbWF4IDwtIGMoMTAsMTBeMykNCmV0YV9taW5fbWF4IDwtIGMoLTUsMykNCmFscGhhX21pbl9tYXggPC0gYygtMywxKQ0KbGFtYmRhX21pbl9tYXggPC0gYygtMywxKQ0KDQojIFNldCBwYXJhbWV0ZXIgc2V0dGluZ3MgZm9yIHNlYXJjaCBhbGdvcml0aG0NCm1heF9pdGVyIDwtIDEwICMgbWF4aW11bSBudW1iZXIgb2YgaXRlcmF0aW9ucw0KcG9wX3NpemUgPC0gMTAgIyBwb3B1bGF0aW9uIHNpemUNCmBgYA0KDQojIyMgR0EgLSBSdW4gVGhlIE9wdGltaXphdGlvbiBhbmQgU2F2ZSB0aGUgTW9kZWwNCg0KYGBge3J9DQpzZXQuc2VlZCgxKQ0KY2x1c3RlciA8LSBtYWtlQ2x1c3RlcihkZXRlY3RDb3JlcygpIC0gMSkgIyBudW1iZXIgb2YgY29yZXMsIGxlYXZlIDEgY29yZSBmb3IgT1MNCnJlZ2lzdGVyRG9QYXJhbGxlbChjbHVzdGVyKSAjIHJlZ2lzdGVyIHRoZSBwYXJhbGxlbCBwcm9jZXNzaW5nDQpuX2NvcmVzIDwtIGxlbmd0aChjbHVzdGVyKQ0KDQpHQV9UMCA8LSBTeXMudGltZSgpDQojIFJ1biBnZW5ldGljIGFsZ29yaXRobQ0KR0FfbW9kZWxfWEdCb29zdF9MaW5lYXIgPC0gR0E6OmdhKA0KICB0eXBlID0gInJlYWwtdmFsdWVkIiwgDQogIGZpdG5lc3MgPSBmdW5jdGlvbih4KSBldmFsX2Z1bmN0aW9uX1hHQm9vc3RfTGluZWFyKHhbMV0seFsyXSx4WzNdLHhbNF0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gdHJhaW4uZGF0YSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYWluX3NldHRpbmdzID0gdHJhaW5fY29udHJvbCksIA0KICBsb3dlciA9IGMoDQogICAgbnJvdW5kc19taW5fbWF4WzFdLCBldGFfbWluX21heFsxXSwgYWxwaGFfbWluX21heFsxXSwgbGFtYmRhX21pbl9tYXhbMV0NCiAgKSwgIyBtaW5pbXVtIHZhbHVlcw0KICB1cHBlciA9IGMoDQogICAgbnJvdW5kc19taW5fbWF4WzJdLCBldGFfbWluX21heFsyXSwgYWxwaGFfbWluX21heFsyXSwgbGFtYmRhX21pbl9tYXhbMl0NCiAgKSwgIyBtYXhpbXVtIHZhbHVlcw0KICBwb3BTaXplID0gcG9wX3NpemUsICMgcG9wdWxhdGlvbiBzaXplDQogIG1heGl0ZXIgPSBtYXhfaXRlciwgIyBudW1iZXIgb2YgaXRlcmF0aW9ucw0KICBwbXV0YXRpb24gPSAwLjUsICMgcHJvYmFiaWxpdHkgb2YgbXV0YXRpb24NCiAgZWxpdGlzbSA9IDAuMywgIyBwZXJjZW50YWdlIG9mIGVsaXRpc20gKGZyYWN0aW9uIG9mIGJlc3QgY3VycmVudCBzb2x1dGlvbnMgdXNlZCBvbiBuZXh0IHJvdW5kKQ0KICAjIHN1Z2dlc3Rpb25zID0gc3RhcnRpbmdfcG9pbnQsDQogIHBhcmFsbGVsID0gbl9jb3JlcywgDQogIG9wdGltID0gRiwgDQogIGtlZXBCZXN0ID0gVCwNCiAgc2VlZCA9IDENCikNCnN0b3BDbHVzdGVyKGNsdXN0ZXIpICMgc2h1dCBkb3duIHRoZSBjbHVzdGVyIA0KcmVnaXN0ZXJEb1NFUSgpICMgIGZvcmNlIFIgdG8gcmV0dXJuIHRvIHNpbmdsZSB0aHJlYWRlZCBwcm9jZXNzaW5nDQpHQV9UMSA8LSBTeXMudGltZSgpDQpHQV9UMSAtIEdBX1QwDQoNCkdBX1hHQm9vc3RfTGluZWFyX21vZGVsDQpzYXZlUkRTKG9iamVjdCA9IEdBX1hHQm9vc3RfTGluZWFyX21vZGVsLCBmaWxlID0gcGFzdGUwKCJNb2RlbHMvR0FfWEdCb29zdF9MaW5lYXJfbW9kZWxfIiwgc3RyaW5ncjo6c3RyX3JlbW92ZV9hbGwoU3lzLnRpbWUoKSwgcGF0dGVybiA9ICI6IiksIi5yZHMiKSkNCnNhdmVSRFMob2JqZWN0ID0gR0FfWEdCb29zdF9MaW5lYXJfbW9kZWwkZmluYWxNb2RlbCwgZmlsZSA9IHBhc3RlMCgiTW9kZWxzL0dBX1hHQm9vc3RfTGluZWFyX21vZGVsXyIsIGNsYXNzKEdBX1hHQm9vc3RfTGluZWFyX21vZGVsJGZpbmFsTW9kZWwpWzFdLCAiXyIsIHN0cmluZ3I6OnN0cl9yZW1vdmVfYWxsKFN5cy50aW1lKCksIHBhdHRlcm4gPSAiOiIpLCIucmRzIikpDQpgYGANCg0KIyMjIEdBIC0gU3VtbWFyaXplIHRoZSBPcHRpbWl6YXRpb24NCg0KYGBge3J9DQpzdW1tYXJ5KEdBX21vZGVsX1hHQm9vc3RfTGluZWFyKQ0KYGBgDQoNCmBgYHtyfQ0KR0E6OnBsb3QuZ2EoR0FfbW9kZWxfWEdCb29zdF9MaW5lYXIsIG1haW4gPSAiR2VuZXRpYyBBbGdvcml0aG06IFJNU0UgdmFsdWVzIGF0IGVhY2ggaXRlcmF0aW9uIikNCmBgYA0KDQojIyMgR0EgLSBUZXN0IFRoZSBNb2RlbCB3aXRoIE9wdGltaXplZCBHRSBTZXR0aW5ncw0KDQpgYGB7cn0NCiMgR3JpZCBvZiBvcHRpbWFsIGh5cGVycGFyYW1ldGVyIHZhbHVlcw0KR0FfWEdCb29zdF9MaW5lYXJfZ3JpZCA8LSBleHBhbmQuZ3JpZCgNCiAgbnJvdW5kcyA9IHJvdW5kKEdBX21vZGVsX1hHQm9vc3RfTGluZWFyQHNvbHV0aW9uWzFdKSwgICMgbGVhcm5pbmcgcmF0ZSwgbG93IHZhbHVlIG1lYW5zIG1vZGVsIGlzIG1vcmUgcm9idXN0IHRvIG92ZXJmaXR0aW5nDQogIGV0YSA9IDEwXkdBX21vZGVsX1hHQm9vc3RfTGluZWFyQHNvbHV0aW9uWzJdLCAjIG51bWJlciBvZiBib29zdGluZyBpdGVyYXRpb25zDQogIGFscGhhID0gMTBeR0FfbW9kZWxfWEdCb29zdF9MaW5lYXJAc29sdXRpb25bM10sICMgTDIgUmVndWxhcml6YXRpb24gKFJpZGdlIFJlZ3Jlc3Npb24pDQogIGxhbWJkYSA9IDEwXkdBX21vZGVsX1hHQm9vc3RfTGluZWFyQHNvbHV0aW9uWzRdICMgTDEgUmVndWxhcml6YXRpb24gKExhc3NvIFJlZ3Jlc3Npb24pDQopDQoNCnRpYygpDQpjbHVzdGVyIDwtIG1ha2VDbHVzdGVyKGRldGVjdENvcmVzKCkgLSAxKSAjIG51bWJlciBvZiBjb3JlcywgY29udmVudGlvbiB0byBsZWF2ZSAxIGNvcmUgZm9yIE9TDQpyZWdpc3RlckRvUGFyYWxsZWwoY2x1c3RlcikgIyByZWdpc3RlciB0aGUgcGFyYWxsZWwgcHJvY2Vzc2luZw0KDQpzZXQuc2VlZCgxKQ0KIyBUcmFpbiBtb2RlbCB3aXRoIG9wdGltYWwgdmFsdWVzDQpHQV9YR0Jvb3N0X0xpbmVhcl9tb2RlbF9maW4gPC0gY2FyZXQ6OnRyYWluKA0KICBTdHJlbmd0aCB+LiwgDQogIGRhdGEgPSB0cmFpbi5kYXRhLCANCiAgbWV0aG9kID0gInhnYkxpbmVhciIsDQogIHRyQ29udHJvbCA9IHRyYWluX2NvbnRyb2wsDQogIHZlcmJvc2UgPSBGLCBtZXRyaWMgPSAiUk1TRSIsIG1heGltaXplID0gRkFMU0UsDQogIHNpbGVudCA9IDEsDQogICMgdHVuZUxlbmd0aCA9IDENCiAgdHVuZUdyaWQgPSBHQV9YR0Jvb3N0X0xpbmVhcl9ncmlkDQopDQoNCnN0b3BDbHVzdGVyKGNsdXN0ZXIpICMgc2h1dCBkb3duIHRoZSBjbHVzdGVyIA0KcmVnaXN0ZXJEb1NFUSgpICMgIGZvcmNlIFIgdG8gcmV0dXJuIHRvIHNpbmdsZSB0aHJlYWRlZCBwcm9jZXNzaW5nDQp0b2MoKQ0KDQpzYXZlUkRTKG9iamVjdCA9IEdBX1hHQm9vc3RfTGluZWFyX21vZGVsX2ZpbiwgZmlsZSA9IHBhc3RlMCgiTW9kZWxzL0dBX1hHQm9vc3RfTGluZWFyX21vZGVsX2Zpbl8iLCBzdHJpbmdyOjpzdHJfcmVtb3ZlX2FsbChTeXMudGltZSgpLCBwYXR0ZXJuID0gIjoiKSwiLnJkcyIpKQ0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KDQoNCiMjIERFIC0gRGlmZmVyZW50aWFsIEV2b2x1dGlvbg0KDQpUaGUgYERFb3B0aW1gIHBhY2thZ2Ugd2lsbCBiZSB1c2VkIHRvIG9wdGltaXplIHRoZSBoeXBlcnBhcmFtZXRlcnMgb2YgdGhlIFhHQm9vc3QgbW9kZWwgdXNpbmcgZGlmZmVyZW50aWFsIGV2b2x1dGlvbi4gSW4gdGhlIHNhbWUgbWFubmVyIGFzIHRoZSBnZW5ldGljIGFsZ29yaXRobSBhYm92ZSwgd2UgZmlyc3QgZGVmaW5lIGEgY3VzdG9tIG9iamVjdGl2ZSBmdW5jdGlvbiB0byBiZSBtaW5pbWl6ZWQ6IHRoaXMgd2lsbCBiZSB0aGUgY3Jvc3MtdmFsaWRhdGVkIFJNU0UuIA0KDQoNCiMjIyBERSAtIENyZWF0ZSBUaGUgRnVuY3Rpb24gRm9yIEFzc2Vzc2luZyBTb2x1dGlvbnMNCg0KYGBge3J9DQojIENyZWF0ZSBjdXN0b20gZnVuY3Rpb24gZm9yIGFzc2Vzc2luZyBzb2x1dGlvbnMNCmV2YWxfZnVuY3Rpb25fWEdCb29zdF9MaW5lYXIgPC0gZnVuY3Rpb24oeCwgZGF0YSwgdHJhaW5fc2V0dGluZ3MpIHsNCiAgeDEgPC0geFsxXQ0KICB4MiA8LSB4WzJdDQogIHgzIDwtIHhbM10NCiAgeDQgPC0geFs0XQ0KICBzdXBwcmVzc1dhcm5pbmdzKA0KICAgIFhHQm9vc3RfTGluZWFyX21vZGVsIDwtIGNhcmV0Ojp0cmFpbigNCiAgICAgIFN0cmVuZ3RoIH4uLCANCiAgICAgIGRhdGEgPSBkYXRhLA0KICAgICAgbWV0aG9kID0gInhnYkxpbmVhciIsDQogICAgICB0ckNvbnRyb2wgPSB0cmFpbl9zZXR0aW5ncywNCiAgICAgIHZlcmJvc2UgPSBGQUxTRSwgDQogICAgICBzaWxlbnQgPSAxLA0KICAgICAgdHVuZUdyaWQgPSBleHBhbmQuZ3JpZCgNCiAgICAgICAgbnJvdW5kcyA9IHJvdW5kKHgxKSwgIyBudW1iZXIgb2YgYm9vc3RpbmcgaXRlcmF0aW9ucw0KICAgICAgICBldGEgPSAxMF54MiwgIyBsZWFybmluZyByYXRlLCBsb3cgdmFsdWUgbWVhbnMgbW9kZWwgaXMgbW9yZSByb2J1c3QgdG8gb3ZlcmZpdHRpbmcNCiAgICAgICAgYWxwaGEgPSAxMF54MywgIyBMMSBSZWd1bGFyaXphdGlvbiAoZXF1aXZhbGVudCB0byBMYXNzbyBSZWdyZXNzaW9uKSBvbiB3ZWlnaHRzDQogICAgICAgIGxhbWJkYSA9IDEwXng0ICMgTDIgUmVndWxhcml6YXRpb24gKGVxdWl2YWxlbnQgdG8gcmlkZ2UgUmVncmVzc2lvbikgb24gd2VpZ2h0cw0KICAgICAgKSANCiAgICApDQogICkNCiAgcmV0dXJuKFhHQm9vc3RfTGluZWFyX21vZGVsJHJlc3VsdHMkUk1TRSkgIyBtaW5pbWl6ZSBSTVNFDQp9DQoNCiMgRGVmaW5lIG1pbmltdW0gYW5kIG1heGltdW0gdmFsdWVzIGZvciBlYWNoIGlucHV0DQpucm91bmRzX21pbl9tYXggPC0gYygxMCwxMF4zKQ0KZXRhX21pbl9tYXggPC0gYygtNSwzKQ0KYWxwaGFfbWluX21heCA8LSBjKC0zLDEpDQpsYW1iZGFfbWluX21heCA8LSBjKC0zLDEpDQoNCiMgU2V0IHBhcmFtZXRlciBzZXR0aW5ncyBmb3Igc2VhcmNoIGFsZ29yaXRobQ0KbWF4X2l0ZXIgPC0gMTAgIyBtYXhpbXVtIG51bWJlciBvZiBpdGVyYXRpb25zDQpwb3Bfc2l6ZSA8LSA0MCAjIHBvcHVsYXRpb24gc2l6ZQ0KYGBgDQoNCiMjIyBERSAtIFJ1biBUaGUgT3B0aW1pemF0aW9uDQoNClJ1biB0aGUgbW9kZWwgKDEzNDQuNzggc2VjIGVsYXBzZWQpDQoNCmBgYHtyfQ0KREVfVDAgPC0gU3lzLnRpbWUoKQ0Kc2V0LnNlZWQoMSkNCm5fY29yZXMgPC0gZGV0ZWN0Q29yZXMoKSAtIDENCmNsdXN0ZXIgPC0gbWFrZUNsdXN0ZXIoZGV0ZWN0Q29yZXMoKSAtIDEpICMgbnVtYmVyIG9mIGNvcmVzLCBjb252ZW50aW9uIHRvIGxlYXZlIDEgY29yZSBmb3IgT1MNCnJlZ2lzdGVyRG9QYXJhbGxlbChjbHVzdGVyKSAjIHJlZ2lzdGVyIHRoZSBwYXJhbGxlbCBwcm9jZXNzaW5nDQoNCiMgUnVuIGRpZmZlcmVudGlhbCBldm9sdXRpb24gYWxnb3JpdGhtDQpERV9tb2RlbF9YR0Jvb3N0X0xpbmVhciA8LSBERW9wdGltOjpERW9wdGltKA0KICBmbiA9IGV2YWxfZnVuY3Rpb25fWEdCb29zdF9MaW5lYXIsIA0KICBsb3dlciA9IGMobnJvdW5kc19taW5fbWF4WzFdLCBldGFfbWluX21heFsxXSwgYWxwaGFfbWluX21heFsxXSwgbGFtYmRhX21pbl9tYXhbMV0pLA0KICB1cHBlciA9IGMobnJvdW5kc19taW5fbWF4WzJdLCBldGFfbWluX21heFsyXSwgYWxwaGFfbWluX21heFsyXSwgbGFtYmRhX21pbl9tYXhbMl0pLCANCiAgY29udHJvbCA9IERFb3B0aW0uY29udHJvbCgNCiAgICBOUCA9IHBvcF9zaXplLCAjIHBvcHVsYXRpb24gc2l6ZQ0KICAgIGl0ZXJtYXggPSBtYXhfaXRlciwgIyBtYXhpbXVtIG51bWJlciBvZiBpdGVyYXRpb25zDQogICAgQ1IgPSAwLjUsICMgcHJvYmFiaWxpdHkgb2YgY3Jvc3NvdmVyDQogICAgc3RvcmVwb3BmcmVxID0gMSwgIyBzdG9yZSBldmVyeSBwb3B1bGF0aW9uDQogICAgcGFyYWxsZWxUeXBlID0gMSAjIHJ1biBwYXJhbGxlbCBwcm9jZXNzaW5nDQogICksDQogIGRhdGEgPSB0cmFpbi5kYXRhLA0KICB0cmFpbl9zZXR0aW5ncyA9IHRyYWluX2NvbnRyb2wNCikNCnN0b3BDbHVzdGVyKGNsdXN0ZXIpICMgc2h1dCBkb3duIHRoZSBjbHVzdGVyIA0KcmVnaXN0ZXJEb1NFUSgpICMgIGZvcmNlIFIgdG8gcmV0dXJuIHRvIHNpbmdsZSB0aHJlYWRlZCBwcm9jZXNzaW5nDQpERV9UMSA8LSBTeXMudGltZSgpDQpERV9UMSAtIERFX1QwDQoNCnNhdmVSRFMob2JqZWN0ID0gREVfWEdCb29zdF9MaW5lYXJfbW9kZWwsIGZpbGUgPSBwYXN0ZTAoIk1vZGVscy9ERV9YR0Jvb3N0X0xpbmVhcl9tb2RlbF8iLCBzdHJpbmdyOjpzdHJfcmVtb3ZlX2FsbChTeXMudGltZSgpLCBwYXR0ZXJuID0gIjoiKSwiLnJkcyIpKQ0KYGBgDQoNCiMjIyBERSAtIFN1bW1hcml6ZSBUaGUgT3B0aW1pemF0aW9uDQoNCmBgYHtyfQ0KIyBQcmludCBzZWFyY2ggcmVzdWx0cw0Kc3VtbWFyeShERV9tb2RlbF9YR0Jvb3N0X0xpbmVhcikNCg0KREVfc29sdXRpb25zIDwtIERFX21vZGVsX1hHQm9vc3RfTGluZWFyJG9wdGltJGJlc3RtZW0NCg0KIyBQbG90IHJlc3VsdHMNCmdncGxvdChtYXBwaW5nID0gYWVzKHggPSAxOmxlbmd0aChERV9tb2RlbF9YR0Jvb3N0X0xpbmVhciRtZW1iZXIkYmVzdHZhbGl0KSwgDQogICAgICAgICAgICAgICAgICAgICB5ID0gREVfbW9kZWxfWEdCb29zdF9MaW5lYXIkbWVtYmVyJGJlc3R2YWxpdCkpICsNCiAgICBnZW9tX2xpbmUoY29sID0gImdyZXk1MCIpICsgDQogICAgZ2VvbV9wb2ludChjb2wgPSAiZ3JleTUwIikgKw0KICAgIHRoZW1lX2J3KCkgKw0KICAgIHRoZW1lKGFzcGVjdC5yYXRpbyA9IDAuOSkgKw0KICAgIGxhYnMoeCA9ICJJdGVyYXRpb24iLCB5ID0gIlJNU0UiLCANCiAgICAgICAgIHRpdGxlID0gIkJlc3QgUk1TRSB2YWx1ZSBhdCBlYWNoIGl0ZXJhdGlvbiIsIA0KICAgICAgICAgc3VidGl0bGUgPSAiUmVzdWx0cyB1c2luZyBEaWZmZXJlbnRpYWwgRXZvbHV0aW9uIikgKw0KICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSAxOkRFX21vZGVsX1hHQm9vc3RfTGluZWFyJG9wdGltJGl0ZXIsIA0KICAgICAgICAgICAgICAgICAgICAgICBtaW5vcl9icmVha3MgPSBOVUxMKQ0KYGBgDQoNCiMjIyBERSAtIFRlc3QgVGhlIE1vZGVsIHdpdGggT3B0aW1pemVkIERFIFNldHRpbmdzDQoNCmBgYHtyfQ0KIyBHcmlkIG9mIG9wdGltYWwgaHlwZXJwYXJhbWV0ZXIgdmFsdWVzDQpERV9YR0Jvb3N0X0xpbmVhcl9ncmlkIDwtIGV4cGFuZC5ncmlkKA0KICBucm91bmRzID0gcm91bmQoREVfc29sdXRpb25zWzFdKSwgICMgbGVhcm5pbmcgcmF0ZSwgbG93IHZhbHVlIG1lYW5zIG1vZGVsIGlzIG1vcmUgcm9idXN0IHRvIG92ZXJmaXR0aW5nDQogIGV0YSA9IDEwXkRFX3NvbHV0aW9uc1syXSwgIyBudW1iZXIgb2YgYm9vc3RpbmcgaXRlcmF0aW9ucw0KICBhbHBoYSA9IDEwXkRFX3NvbHV0aW9uc1szXSwgIyBMMiBSZWd1bGFyaXphdGlvbiAoUmlkZ2UgUmVncmVzc2lvbikNCiAgbGFtYmRhID0gMTBeREVfc29sdXRpb25zWzRdICMgTDEgUmVndWxhcml6YXRpb24gKExhc3NvIFJlZ3Jlc3Npb24pDQopDQoNCnRpYygpDQpjbHVzdGVyIDwtIG1ha2VDbHVzdGVyKGRldGVjdENvcmVzKCkgLSAxKSAjIG51bWJlciBvZiBjb3JlcywgY29udmVudGlvbiB0byBsZWF2ZSAxIGNvcmUgZm9yIE9TDQpyZWdpc3RlckRvUGFyYWxsZWwoY2x1c3RlcikgIyByZWdpc3RlciB0aGUgcGFyYWxsZWwgcHJvY2Vzc2luZw0KDQpzZXQuc2VlZCgxKQ0KIyBUcmFpbiBtb2RlbCB3aXRoIG9wdGltYWwgdmFsdWVzDQpERV9YR0Jvb3N0X0xpbmVhcl9tb2RlbCA8LSBjYXJldDo6dHJhaW4oDQogIFN0cmVuZ3RoIH4uLCANCiAgZGF0YSA9IHRyYWluLmRhdGEsIA0KICBtZXRob2QgPSAieGdiTGluZWFyIiwNCiAgdHJDb250cm9sID0gdHJhaW5fY29udHJvbCwNCiAgdmVyYm9zZSA9IEYsIG1ldHJpYyA9ICJSTVNFIiwgbWF4aW1pemUgPSBGQUxTRSwNCiAgc2lsZW50ID0gMSwNCiAgIyB0dW5lTGVuZ3RoID0gMQ0KICB0dW5lR3JpZCA9IERFX1hHQm9vc3RfTGluZWFyX2dyaWQNCikNCg0Kc3RvcENsdXN0ZXIoY2x1c3RlcikgIyBzaHV0IGRvd24gdGhlIGNsdXN0ZXIgDQpyZWdpc3RlckRvU0VRKCkgIyAgZm9yY2UgUiB0byByZXR1cm4gdG8gc2luZ2xlIHRocmVhZGVkIHByb2Nlc3NpbmcNCnRvYygpDQoNCnNhdmVSRFMob2JqZWN0ID0gREVfWEdCb29zdF9MaW5lYXJfbW9kZWxfZmluLCBmaWxlID0gcGFzdGUwKCJNb2RlbHMvREVfWEdCb29zdF9MaW5lYXJfbW9kZWxfZmluXyIsIHN0cmluZ3I6OnN0cl9yZW1vdmVfYWxsKFN5cy50aW1lKCksIHBhdHRlcm4gPSAiOiIpLCIucmRzIikpDQpgYGANCg0KYGBge3J9DQpERV9YR0Jvb3N0X0xpbmVhcl9tb2RlbA0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KDQoNCiMjIFBTTyAtIFBhcnRpY2xlIFN3YXJtIE9wdGltaXphdGlvbg0KDQpXZSB3aWxsIHVzZSB0aGUgYHBzb2AgcGFja2FnZSB0byBvcHRpbWl6ZSB0aGUgZm91ciBoeXBlcnBhcmFtZXRlcnMuIEp1c3QgbGlrZSB0aGUgR2VuZXRpYyBBbGdvcml0aG0gYW5kIERpZmZlcmVudGlhbCBFdm9sdXRpb24gd3cgd2lsbCBkZWZpbmUgYSBmdW5jdGlvbiB0byBiZSBvcHRpbWl6ZWQuDQoNCg0KIyMjIFBTTyAtIENyZWF0ZSBUaGUgRnVuY3Rpb24gRm9yIEFzc2Vzc2luZyBTb2x1dGlvbnMNCg0KYGBge3J9DQojIENyZWF0ZSBjdXN0b20gZnVuY3Rpb24gZm9yIGFzc2Vzc2luZyBzb2x1dGlvbnMNCmV2YWxfZnVuY3Rpb25fWEdCb29zdF9MaW5lYXIgPC0gZnVuY3Rpb24oeCwgZGF0YSwgdHJhaW5fc2V0dGluZ3MpIHsNCiAgeDEgPC0geFsxXQ0KICB4MiA8LSB4WzJdDQogIHgzIDwtIHhbM10NCiAgeDQgPC0geFs0XQ0KICANCiAgc3VwcHJlc3NXYXJuaW5ncygNCiAgICAjIENyZWF0ZSBkYXRhZnJhbWUgd2l0aCBwcm9wb3J0aW9uIG9mIGVhY2ggc29saWQgY29tcG9uZW50DQogICAgWEdCb29zdF9MaW5lYXJfbW9kZWwgPC0gY2FyZXQ6OnRyYWluKA0KICAgICAgU3RyZW5ndGggfi4sIA0KICAgICAgZGF0YSA9IGRhdGEsDQogICAgICBtZXRob2QgPSAieGdiTGluZWFyIiwNCiAgICAgIHRyQ29udHJvbCA9IHRyYWluX3NldHRpbmdzLA0KICAgICAgdmVyYm9zZSA9IEZBTFNFLCANCiAgICAgIHNpbGVudCA9IDEsDQogICAgICB0dW5lR3JpZCA9IGV4cGFuZC5ncmlkKA0KICAgICAgICBucm91bmRzID0gcm91bmQoeDEpLCAjIG51bWJlciBvZiBib29zdGluZyBpdGVyYXRpb25zDQogICAgICAgIGV0YSA9IDEwXngyLCAjIGxlYXJuaW5nIHJhdGUsIGxvdyB2YWx1ZSBtZWFucyBtb2RlbCBpcyBtb3JlIHJvYnVzdCB0byBvdmVyZml0dGluZw0KICAgICAgICBhbHBoYSA9IDEwXngzLCAjIEwxIFJlZ3VsYXJpemF0aW9uIChlcXVpdmFsZW50IHRvIExhc3NvIFJlZ3Jlc3Npb24pIG9uIHdlaWdodHMNCiAgICAgICAgbGFtYmRhID0gMTBeeDQgIyBMMiBSZWd1bGFyaXphdGlvbiAoZXF1aXZhbGVudCB0byByaWRnZSBSZWdyZXNzaW9uKSBvbiB3ZWlnaHRzDQogICAgICApIA0KICAgICkNCikNCiAgICByZXR1cm4oWEdCb29zdF9MaW5lYXJfbW9kZWwkcmVzdWx0cyRSTVNFKSAjIG1pbmltaXplIFJNU0UNCg0KfQ0KDQojIERlZmluZSBtaW5pbXVtIGFuZCBtYXhpbXVtIHZhbHVlcyBmb3IgZWFjaCBpbnB1dA0KbnJvdW5kc19taW5fbWF4IDwtIGMoMTAsMTBeMykNCmV0YV9taW5fbWF4IDwtIGMoLTUsMykNCmFscGhhX21pbl9tYXggPC0gYygtMywxKQ0KbGFtYmRhX21pbl9tYXggPC0gYygtMywxKQ0KYGBgDQoNCiMjIyBQU08gLSBSdW4gVGhlIE9wdGltaXphdGlvbg0KDQpXZSBjYW4gbm93IHVzZSB0aGUgYHBzbzo6cHNvcHRpbSgpYCBmdW5jdGlvbiB0byBydW4gdGhlIHNlYXJjaA0KDQpgYGB7cn0NCiMgU2V0IHBhcmFtZXRlciBzZXR0aW5ncyBmb3Igc2VhcmNoIGFsZ29yaXRobQ0KbWF4X2l0ZXIgPC0gMTAgIyBtYXhpbXVtIG51bWJlciBvZiBpdGVyYXRpb25zDQpwb3Bfc2l6ZSA8LSAxMCAjIHBvcHVsYXRpb24gc2l6ZQ0KDQpzZXQuc2VlZCgxKQ0KY2x1c3RlciA8LSBtYWtlQ2x1c3RlcihkZXRlY3RDb3JlcygpIC0gMSkgIyBudW1iZXIgb2YgY29yZXMsIGNvbnZlbnRpb24gdG8gbGVhdmUgMSBjb3JlIGZvciBPUw0KcmVnaXN0ZXJEb1BhcmFsbGVsKGNsdXN0ZXIpICMgcmVnaXN0ZXIgdGhlIHBhcmFsbGVsIHByb2Nlc3NpbmcNCm5fY29yZXMgPC0gZGV0ZWN0Q29yZXMoKS0xDQoNClBTT19UMCA8LSBTeXMudGltZSgpDQojIFJ1biBzZWFyY2ggYWxnb3JpdGhtDQpQU09fbW9kZWxfWEdCb29zdF9MaW5lYXIgPC0gcHNvOjpwc29wdGltKA0KICBwYXIgPSByZXAoTkEsIDQpLA0KICBmbiA9IGV2YWxfZnVuY3Rpb25fWEdCb29zdF9MaW5lYXIsIA0KICBsb3dlciA9IGMobnJvdW5kc19taW5fbWF4WzFdLCBldGFfbWluX21heFsxXSwgYWxwaGFfbWluX21heFsxXSwgbGFtYmRhX21pbl9tYXhbMV0pLA0KICB1cHBlciA9IGMobnJvdW5kc19taW5fbWF4WzJdLCBldGFfbWluX21heFsyXSwgYWxwaGFfbWluX21heFsyXSwgbGFtYmRhX21pbl9tYXhbMl0pLCANCiAgY29udHJvbCA9IGxpc3QoDQogICAgdHJhY2UgPSAxLCAjICBwcm9kdWNlIHRyYWNpbmcgaW5mb3JtYXRpb24gb24gdGhlIHByb2dyZXNzIG9mIHRoZSBvcHRpbWl6YXRpb24NCiAgICBtYXhpdCA9IG1heF9pdGVyLCAjIG1heGltdW0gbnVtYmVyIG9mIGl0ZXJhdGlvbnMNCiAgICBSRVBPUlQgPSAxLCAjICBmcmVxdWVuY3kgZm9yIHJlcG9ydHMNCiAgICB0cmFjZS5zdGF0cyA9IFQsDQogICAgcyA9IHBvcF9zaXplLCAjIFN3YXJtIFNpemUsDQogICAgbWF4aXQuc3RhZ25hdGUgPSByb3VuZCgwLjc1Km1heF9pdGVyKSwgIyBtYXhpbXVtIG51bWJlciBvZiBpdGVyYXRpb25zIHdpdGhvdXQgaW1wcm92ZW1lbnQNCiAgICB2ZWN0b3JpemUgPSBULA0KICAgIHR5cGUgPSAiU1BTTzIwMTEiICMgbWV0aG9kIHVzZWQNCiAgKSwNCiAgZGF0YSA9IHRyYWluLmRhdGEsDQogIHRyYWluX3NldHRpbmdzID0gdHJhaW5fY29udHJvbA0KKQ0KDQpzdG9wQ2x1c3RlcihjbHVzdGVyKSAjIHNodXQgZG93biB0aGUgY2x1c3RlciANCnJlZ2lzdGVyRG9TRVEoKSAjICBmb3JjZSBSIHRvIHJldHVybiB0byBzaW5nbGUgdGhyZWFkZWQgcHJvY2Vzc2luZw0KUFNPX1QxIDwtIFN5cy50aW1lKCkNClBTT19UMSAtIFBTT19UMA0KDQpzYXZlUkRTKG9iamVjdCA9IFBTT19YR0Jvb3N0X0xpbmVhcl9tb2RlbCwgZmlsZSA9IHBhc3RlMCgiTW9kZWxzL1BTT19YR0Jvb3N0X0xpbmVhcl9tb2RlbF8iLCBzdHJpbmdyOjpzdHJfcmVtb3ZlX2FsbChTeXMudGltZSgpLCBwYXR0ZXJuID0gIjoiKSwiLnJkcyIpKQ0Kc2F2ZVJEUyhvYmplY3QgPSBQU09fWEdCb29zdF9MaW5lYXJfbW9kZWwkZmluYWxNb2RlbCwgZmlsZSA9IHBhc3RlMCgiTW9kZWxzL1BTT19YR0Jvb3N0X0xpbmVhcl9tb2RlbF8iLCBjbGFzcyhQU09fWEdCb29zdF9MaW5lYXJfbW9kZWwkZmluYWxNb2RlbClbMV0sICJfIiwgc3RyaW5ncjo6c3RyX3JlbW92ZV9hbGwoU3lzLnRpbWUoKSwgcGF0dGVybiA9ICI6IiksIi5yZHMiKSkNCmBgYA0KDQojIyMgUFNPIC0gU3VtbWFyaXplIFRoZSBPcHRpbWl6YXRpb24NCg0KYGBge3J9DQpQU09fc3VtbWFyeSA8LSBkYXRhLmZyYW1lKA0KICBJdGVyYXRpb24gPSBQU09fbW9kZWxfWEdCb29zdF9MaW5lYXIkc3RhdHMkaXQsDQogIE1lYW4gPSBQU09fbW9kZWxfWEdCb29zdF9MaW5lYXIkc3RhdHMkZiAlPiUgc2FwcGx5KEZVTiA9IG1lYW4pLA0KICBNZWRpYW4gPSBQU09fbW9kZWxfWEdCb29zdF9MaW5lYXIkc3RhdHMkZiAlPiUgc2FwcGx5KEZVTiA9IG1lZGlhbiksDQogIEJlc3QgPSBQU09fbW9kZWxfWEdCb29zdF9MaW5lYXIkc3RhdHMkZXJyb3IgJT4lIHNhcHBseShGVU4gPSBtaW4pDQopDQpQU09fc3VtbWFyeSAlPiUgDQogIGdhdGhlcihrZXkgPSAiUGFyYW1ldGVyIiwgdmFsdWUgPSAiVmFsdWUiLCAtIEl0ZXJhdGlvbikgJT4lIA0KICBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4ID0gSXRlcmF0aW9uLCB5ID0gVmFsdWUsIGNvbCA9IFBhcmFtZXRlcikpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBnZW9tX3BvaW50KCkgKw0KICB0aGVtZV9idygpICsNCiAgdGhlbWUoYXNwZWN0LnJhdGlvID0gMC45KSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBQU09fbW9kZWxfWEdCb29zdF9MaW5lYXIkc3RhdHMkaXQsIG1pbm9yX2JyZWFrcyA9IE5VTEwpICsNCiAgbGFicyh4ID0gIkl0ZXJhdGlvbiIsIHkgPSAiUk1TRSIsIHRpdGxlID0gIlJNU0UgdmFsdWVzIGF0IGVhY2ggaXRlcmF0aW9uIiwgc3VidGl0bGUgPSAiUmVzdWx0cyB1c2luZyBQYXJ0aWNsZSBTd2FybSBPcHRpbWl6YXRpb24iKSArDQogIHNjYWxlX2NvbG9yX2JyZXdlcih0eXBlID0gInF1YWwiLCBwYWxldHRlID0gIlNldDEiKQ0KYGBgDQoNCiMjIyBQU08gLSBUZXN0IFRoZSBNb2RlbCB3aXRoIE9wdGltaXplZCBQU08gU2V0dGluZ3MNCg0KYGBge3J9DQojIEdyaWQgb2Ygb3B0aW1hbCBoeXBlcnBhcmFtZXRlciB2YWx1ZXMNClBTT19YR0Jvb3N0X0xpbmVhcl9ncmlkIDwtIGV4cGFuZC5ncmlkKA0KICBucm91bmRzID0gcm91bmQoUFNPX21vZGVsX1hHQm9vc3RfTGluZWFyJHBhclsxXSksICAjIG51bWJlciBvZiBib29zdGluZyBpdGVyYXRpb25zDQogIGxhbWJkYSA9IFBTT19tb2RlbF9YR0Jvb3N0X0xpbmVhciRwYXJbNF0sICMgTDEgUmVndWxhcml6YXRpb24gKExhc3NvIFJlZ3Jlc3Npb24pDQogIGFscGhhID0gUFNPX21vZGVsX1hHQm9vc3RfTGluZWFyJHBhclszXSwgIyBMMiBSZWd1bGFyaXphdGlvbiAoUmlkZ2UgUmVncmVzc2lvbikNCiAgZXRhID0gUFNPX21vZGVsX1hHQm9vc3RfTGluZWFyJHBhclsyXSAjIGxlYXJuaW5nIHJhdGUsIGxvdyB2YWx1ZSBtZWFucyBtb2RlbCBpcyBtb3JlIHJvYnVzdCB0byBvdmVyZml0dGluZw0KKQ0KDQp0aWMoKQ0KY2x1c3RlciA8LSBtYWtlQ2x1c3RlcihkZXRlY3RDb3JlcygpIC0gMSkgIyBudW1iZXIgb2YgY29yZXMsIGNvbnZlbnRpb24gdG8gbGVhdmUgMSBjb3JlIGZvciBPUw0KcmVnaXN0ZXJEb1BhcmFsbGVsKGNsdXN0ZXIpICMgcmVnaXN0ZXIgdGhlIHBhcmFsbGVsIHByb2Nlc3NpbmcNCg0Kc2V0LnNlZWQoMSkNCiMgVHJhaW4gbW9kZWwgd2l0aCBvcHRpbWFsIHZhbHVlcw0KI21vZGVsTG9va3VwKG1vZGVsID0gInhnYkxpbmVhciIpDQpQU09fWEdCb29zdF9MaW5lYXJfbW9kZWxfZmluIDwtIGNhcmV0Ojp0cmFpbigNCiAgU3RyZW5ndGggfi4sIA0KICBkYXRhID0gdHJhaW4uZGF0YSwgDQogIG1ldGhvZCA9ICJ4Z2JMaW5lYXIiLA0KICB0ckNvbnRyb2wgPSB0cmFpbl9jb250cm9sLA0KICB2ZXJib3NlID0gRiwgbWV0cmljID0gIlJNU0UiLCBtYXhpbWl6ZSA9IEZBTFNFLA0KICBzaWxlbnQgPSAxLA0KICB0dW5lR3JpZCA9IFBTT19YR0Jvb3N0X0xpbmVhcl9ncmlkDQopDQoNCnN0b3BDbHVzdGVyKGNsdXN0ZXIpICMgc2h1dCBkb3duIHRoZSBjbHVzdGVyIA0KcmVnaXN0ZXJEb1NFUSgpICMgIGZvcmNlIFIgdG8gcmV0dXJuIHRvIHNpbmdsZSB0aHJlYWRlZCBwcm9jZXNzaW5nDQp0b2MoKQ0KDQpQU09fWEdCb29zdF9MaW5lYXJfbW9kZWxfZmluDQoNCnNhdmVSRFMob2JqZWN0ID0gUFNPX1hHQm9vc3RfTGluZWFyX21vZGVsX2ZpbiwgZmlsZSA9IHBhc3RlMCgiTW9kZWxzL1BTT19YR0Jvb3N0X0xpbmVhcl9tb2RlbF9maW4iLCBzdHJpbmdyOjpzdHJfcmVtb3ZlX2FsbChTeXMudGltZSgpLCBwYXR0ZXJuID0gIjoiKSwiLnJkcyIpKQ0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KDQojIyBCTyAtIEJheWVzaWFuIE9wdGltaXphdGlvbg0KDQpCYXllc2lhbiBvcHRpbWl6YXRpb24gaXMgYW4gYXBwcm9hY2ggdG8gb3B0aW1pemluZyBvYmplY3RpdmUgZnVuY3Rpb25zIHRoYXQgdGFrZSBhIGxvbmcgdGltZSAobWludXRlcyBvciBob3VycykgdG8gZXZhbHVhdGUuIEl0IGlzIGJlc3Qtc3VpdGVkIGZvciBvcHRpbWl6YXRpb24gb3ZlciBjb250aW51b3VzIGRvbWFpbnMgb2YgbGVzcyB0aGFuIDIwIGRpbWVuc2lvbnMsIGFuZCB0b2xlcmF0ZXMgc3RvY2hhc3RpYyBub2lzZSBpbiBmdW5jdGlvbiBldmFsdWF0aW9ucy4gSXQgYnVpbGRzIGEgc3Vycm9nYXRlIGZvciB0aGUgb2JqZWN0aXZlIGFuZCBxdWFudGlmaWVzIHRoZSB1bmNlcnRhaW50eSBpbiB0aGF0IHN1cnJvZ2F0ZSB1c2luZyBhIEJheWVzaWFuIG1hY2hpbmUgbGVhcm5pbmcgdGVjaG5pcXVlLCBHYXVzc2lhbiBwcm9jZXNzIHJlZ3Jlc3Npb24sIGFuZCB0aGVuIHVzZXMgYW4gYWNxdWlzaXRpb24gZnVuY3Rpb24gZGVmaW5lZCBmcm9tIHRoaXMgc3Vycm9nYXRlIHRvIGRlY2lkZSB3aGVyZSB0byBzYW1wbGUuDQoNCk9wdGltaXphdGlvbiBieSBCYXllc2lhbiBtZXRob2RzIFtzcGFucyB2b2x1bWVzXShodHRwOi8vcGFwZXJzLm5pcHMuY2MvcGFwZXIvNDUyMi1wcmFjdGljYWwtYmF5ZXNpYW4tb3B0aW1pemF0aW9uLW9mLW1hY2hpbmUtbGVhcm5pbmctYWxnb3JpdGhtcy5wZGYpLCB0aGlzIHdpbGwgaGl0IG9ubHkgdGhlIGhpZ2ggcG9pbnRzIHRvIGdldCB0aGUgam9iIGRvbmUuIFRoZSBtZXRob2RzIGhlcmUgYXJlIHZlcnkgZmxleGlibGUgYW5kIGNhbiBiZSBhcHBsaWVkIHRvIGEgdmFyaWV0eSBvZiBNTCBhbGdvcml0aG1zLiBUaGUgc2NoZW1lcyBmaXQgaW50byB0d28gdG9vbHNldCBjYW1wcy4NCg0KKipUaGUgYG1scmAgVG9vbHNldCoqDQoNClRoZSBgbWxyYCBjYW1wIGhhcyBhIGxhcmdlIHN1aXRlIG9mIHJlbGF0ZWQgdG9vbHMgZm9yIGRlZmluaW5nLCBydW5uaW5nLCB0dW5pbmcgYW5kIGV2YWx1YXRpbmcgTUwgbW9kZWxzLiANCg0KKipUaGUgYGNhcmV0YCBUb29sc2V0KioNCg0KVGhlIGBjYXJldGAgY2FtcCBmb2xsb3dzIHRoZSBtb2RlbCBkZWZpbml0aW9uIGFuZCBsb2dpYyB1c2VkIHRodXMgZmFyLCAqdmlkZSBzdXByYSouDQoNCi0gVGhlIGBjYXJldGAgdG9vbHMuDQogICANCkFzIGJlZm9yZSwgZGVmaW5lIGEgZnVuY3Rpb24gdG8gYmUgb3B0aW1pemVkLiBJJ20gZ29pbmcgdG8gdXNlIHRoZSBzYW1lIGRlZmluaXRpb24gYXMgdGhlIG9uZSB1c2VkIGZvciB0aGUgcGFydGljbGUgc3dhcm0gb3B0aW1pemF0aW9uIGFuZCBtb2RpZnkgaXQgdG8gcmV0dXJuIHRoZSBSTVNFIGFuZCB0aGUgY3Jvc3MtdmFsaWRhdGVkIHByZWRpdGlvbnMsIGFzIHJlcXVpcmVkIGJ5IGByQmF5ZXNpYW5PcHRpbWl6YXRpb25gLg0KDQojIyMgQk8gLSBDcmVhdGUgVGhlIEZ1bmN0aW9uIEZvciBBc3Nlc3NpbmcgU29sdXRpb25zDQoNCmBgYHtyLCBldmFsID0gVFJVRX0NCiMgQ3JlYXRlIGN1c3RvbSBmdW5jdGlvbiBmb3IgYXNzZXNzaW5nIHNvbHV0aW9ucw0KIyB0ZXN0IHRoZSBmdW5jdGlvbiB3aXRoDQojR0EgcmVzdWx0czogDQojSXRlcmF0aW9ucyAgICAgICAgICAgICA9IDEwIA0KI0ZpdG5lc3MgZnVuY3Rpb24gdmFsdWUgPSAtNC40NjI0NDcgDQojU29sdXRpb24gPSANCiMgICAgICAgICAgIHgxICAgICAgIHgyICAgICAgICAgeDMgICAgICAgeDQNCiNbMSxdIDM3My43ODI2IDEuMTI3MTQxIC0wLjM0OTgxNjcgMC4yMzA1NTgNCiN4IDwtIGxpc3QoeDEgPSAzNzMuNzgyNiwgeDIgPSAxLjEyNzE0MSwgeDMgPSAtMC4zNDk4MTY3LCB4NCA9IDAuMjMwNTU4KQ0KIyBlbGFwc2VkID0gMTkuMTkJUm91bmQgPSA1Nwl4MSA9IDYzNS4wMDAwCXgyID0gMy4wMDAwCXgzID0gLTIuMjcwOQl4NCA9IDEuMDAwMAlWYWx1ZSA9IC00LjMyOTggDQojZXZhbF9mdW5jdGlvbl9YR0Jvb3N0X0xpbmVhcih4MSA9IDYzNSwgeDIgPSAzLCB4MyA9IC0yLjI3MDksIHg0ID0gMS4wMCwgdHJhaW5fc2V0dGluZ3MgPSB0cmFpbl9jb250cm9sKQ0KIyByZXR1cm5zIFsxXSBbMV0gLTQuNjI1NDE5DQoNCmV2YWxfZnVuY3Rpb25fWEdCb29zdF9MaW5lYXIgPC0gZnVuY3Rpb24oeDEsIHgyLCB4MywgeDQsIHRyYWluX3NldHRpbmdzKSB7DQoNCiAgIyAgc3VwcHJlc3NXYXJuaW5ncygNCiAgIyBDcmVhdGUgZGF0YWZyYW1lIHdpdGggcHJvcG9ydGlvbiBvZiBlYWNoIHNvbGlkIGNvbXBvbmVudA0KICBYR0Jvb3N0X0xpbmVhcl9tb2RlbCA8LSBjYXJldDo6dHJhaW4oDQogICAgU3RyZW5ndGggfi4sIA0KICAgIGRhdGEgPSB0cmFpbi5kYXRhLA0KICAgIG1ldGhvZCA9ICJ4Z2JMaW5lYXIiLA0KICAgIHRyQ29udHJvbCA9IHRyYWluX2NvbnRyb2wsDQogICAgdmVyYm9zZSA9IEZBTFNFLCANCiAgICBzaWxlbnQgPSAxLA0KICAgIHR1bmVHcmlkID0gZXhwYW5kLmdyaWQoDQogICAgICBucm91bmRzID0gcm91bmQoeDEpLCAjIG51bWJlciBvZiBib29zdGluZyBpdGVyYXRpb25zDQogICAgICBldGEgPSAxMF54MiwgIyBsZWFybmluZyByYXRlLCBsb3cgdmFsdWUgbWVhbnMgbW9kZWwgaXMgbW9yZSByb2J1c3QgdG8gb3ZlcmZpdHRpbmcNCiAgICAgIGFscGhhID0gMTBeeDMsICMgTDEgUmVndWxhcml6YXRpb24gKGVxdWl2YWxlbnQgdG8gTGFzc28gUmVncmVzc2lvbikgb24gd2VpZ2h0cw0KICAgICAgbGFtYmRhID0gMTBeeDQgIyBMMiBSZWd1bGFyaXphdGlvbiAoZXF1aXZhbGVudCB0byByaWRnZSBSZWdyZXNzaW9uKSBvbiB3ZWlnaHRzDQogICAgKQ0KICApDQogIHJldHVybihsaXN0KFNjb3JlID0gLVhHQm9vc3RfTGluZWFyX21vZGVsJHJlc3VsdHMkUk1TRSwgUHJlZCA9IDApKQ0KIyAgICByZXR1cm4obGlzdChTY29yZSA9IFhHQm9vc3RfTGluZWFyX21vZGVsJHJlc3VsdHMkUk1TRSwgUHJlZCA9IFhHQm9vc3RfTGluZWFyX21vZGVsJHByZWQpKQ0KfQ0KYGBgDQoNCiMjIyBCTyAtIENyZWF0ZSBBbiBJbml0aWFsaXphdGlvbiBHcmlkIEJhc2VkIE9uIFRoZSBHcmlkIFNlYXJjaA0KDQpXZSB3YW50IHRvIGluY2x1ZGUgdGhlIGJlc3QgMzAgcG9pbnRzIGZyb20gdGhlIGdyaWQgc2VhcmNoIGFuZCBhdWdtZW50IHRob3NlIHdpdGggMjAgbW9yZSByYW5kb20gcG9pbnRzIHdpdGhpbiB0aGUgc2FtcGxlIHNwYWNlLg0KDQpgYGB7cn0NCmluaXRfZ3JpZF9kdCA8LSBHU19YR0Jvb3N0X0xpbmVhcl9tb2RlbCRyZXN1bHRzICU+JSANCiAgYXJyYW5nZShSTVNFKSAlPiUNCiAgdW5pcXVlKCkgJT4lDQogIC5bMToyMCxdICU+JSANCiAgc2VsZWN0KG5yb3VuZHMsIGV0YSwgbGFtYmRhLCBhbHBoYSwgUk1TRSkgJT4lIA0KICBtdXRhdGUoeDEgPSBucm91bmRzKSAlPiUNCiAgbXV0YXRlKHgyID0gbG9nMTAoZXRhKSkgJT4lDQogIG11dGF0ZSh4MyA9IGxvZzEwKGFscGhhKSkgJT4lDQogIG11dGF0ZSh4NCA9IGxvZzEwKGxhbWJkYSkpICU+JQ0KICBtdXRhdGUoVmFsdWUgPSAtUk1TRSkgJT4lDQogIC5bLDY6MTBdDQpgYGANCg0KIyMjIEJPIC0gUnVuIHRoZSBvcHRpbWl6YXRpb24NCg0KYGBge3IsIGV2YWwgPSBUUlVFfQ0KQk9fVDAgPC0gU3lzLnRpbWUoKQ0KY2x1c3RlciA8LSBtYWtlQ2x1c3RlcihkZXRlY3RDb3JlcygpIC0gMSkgIyBudW1iZXIgb2YgY29yZXMsIGxlYXZlIDEgY29yZSBmb3IgT1MNCnJlZ2lzdGVyRG9QYXJhbGxlbChjbHVzdGVyKSAjIHJlZ2lzdGVyIHRoZSBwYXJhbGxlbCBwcm9jZXNzaW5nDQoNCnNldC5zZWVkKDEpDQojIERlZmluZSBtaW5pbXVtIGFuZCBtYXhpbXVtIHZhbHVlcyBmb3IgZWFjaCBpbnB1dA0KDQojeA0KI3RyYWluX2NvbnRyb2wNCkJPX1hHQm9vc3RfTGluZWFyX21vZGVsIDwtIEJheWVzaWFuT3B0aW1pemF0aW9uKGV2YWxfZnVuY3Rpb25fWEdCb29zdF9MaW5lYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvdW5kcyA9IGxpc3QoeDEgPSBjKDEwTCwxMDAwTCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeDIgPSBjKC01LDMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHgzID0gYygtMywxKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4NCA9IGMoLTMsMSkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbml0X2dyaWRfZHQgPSBpbml0X2dyaWRfZHQsIGluaXRfcG9pbnRzID0gMjEsIG5faXRlciA9IDMwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY3EgPSAidWNiIiwga2FwcGEgPSAyLjU3NiwgZXBzID0gMC4wLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gVFJVRSkNCnN0b3BDbHVzdGVyKGNsdXN0ZXIpICMgc2h1dCBkb3duIHRoZSBjbHVzdGVyIA0KcmVnaXN0ZXJEb1NFUSgpICMgIGZvcmNlIFIgdG8gcmV0dXJuIHRvIHNpbmdsZSB0aHJlYWRlZCBwcm9jZXNzaW5nDQpCT19UMSA8LSBTeXMudGltZSgpDQpCT19UMSAtIEJPX1QwDQoNCnNhdmVSRFMob2JqZWN0ID0gQk9fWEdCb29zdF9MaW5lYXJfbW9kZWwsIGZpbGUgPSBwYXN0ZTAoIk1vZGVscy9CT19YR0Jvb3N0X0xpbmVhcl9tb2RlbF8iLCBzdHJpbmdyOjpzdHJfcmVtb3ZlX2FsbChTeXMudGltZSgpLCBwYXR0ZXJuID0gIjoiKSwiLnJkcyIpKQ0Kc2F2ZVJEUyhvYmplY3QgPSBCT19YR0Jvb3N0X0xpbmVhcl9tb2RlbCRmaW5hbE1vZGVsLCBmaWxlID0gcGFzdGUwKCJNb2RlbHMvQk9fWEdCb29zdF9MaW5lYXJfbW9kZWxfIiwgY2xhc3MoQk9fWEdCb29zdF9MaW5lYXJfbW9kZWwkZmluYWxNb2RlbClbMV0sICJfIiwgc3RyaW5ncjo6c3RyX3JlbW92ZV9hbGwoU3lzLnRpbWUoKSwgcGF0dGVybiA9ICI6IiksIi5yZHMiKSkNCmBgYA0KDQojIyMgQk8gLSBQbG90IHRoZSBSZXN1bHRzDQoNCmBgYHtyLCBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD04fQ0KZGF0YV9wb2ludHMgPC0gQk9fWEdCb29zdF9MaW5lYXJfbW9kZWwkSGlzdG9yeQ0KZGF0YV9wb2ludHMkUm91bmRbMToyMF0gPC0gIkdyaWQgU2VhcmNoIFByaW1pbmciIA0KZGF0YV9wb2ludHMkUm91bmRbMjE6NDFdIDwtICJBY3F1aXNpdGlvbiBTYW1wbGluZyINCmRhdGFfcG9pbnRzJFJvdW5kWzQyOjcxXSA8LSAiQmF5ZXNpYW4gT3B0aW1pemluZyINCmRhdGFfcG9pbnRzJFZhbHVlIDwtIGRhdGFfcG9pbnRzJFZhbHVlICogLTEuMA0KY29sbmFtZXMoZGF0YV9wb2ludHMpIDwtIGMoIk9wdGltaXphdGlvbiBQaGFzZSIsICJucm91bmRzIiwgImV0YSIsICJhbHBoYSIsICJsYW1iZGEiLCAiUk1TRSIpDQoNCmRhdGFfcG9pbnRzICU+JQ0KICBwaXZvdF9sb25nZXIoY29scyA9IGMoIm5yb3VuZHMiLCAiZXRhIiwgImFscGhhIiwgImxhbWJkYSIsICJSTVNFIikpICU+JQ0KICBnZ3Bsb3QoYWVzKHkgPSB2YWx1ZSwgeCA9IHNlcV9hbG9uZyhgT3B0aW1pemF0aW9uIFBoYXNlYCksIGNvbCA9IGBPcHRpbWl6YXRpb24gUGhhc2VgKSkgKw0KICBnZW9tX2xpbmUoKSArDQogIGZhY2V0X3dyYXAofm5hbWUsIHNjYWxlcyA9ICJmcmVlX3kiLCBuY29sID0gMykgKw0KICAgIHNjYWxlX3hfY29udGludW91cyhuYW1lID0gIk9wdGltaXphdGlvbiBQaGFzZSIpICsNCiAgbGFicyh0aXRsZSA9ICJCYXllc2lhbiBPcHRpbWl6YXRpb24gV2l0aCBQcmltaW5nIikgKw0KICAgIHRoZW1lKGF4aXMudGl0bGUueD1lbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobmFtZSA9ICIiKQ0KYGBgDQoNCiMjIyBCTyAtIFRlc3QgVGhlIE1vZGVsIHdpdGggT3B0aW1pemVkIEJPIFNldHRpbmdzDQoNCmBgYHtyfQ0KIyBHcmlkIG9mIG9wdGltYWwgaHlwZXJwYXJhbWV0ZXIgdmFsdWVzDQojQk9fWEdCb29zdF9MaW5lYXJfZ3JpZA0KI1JvdW5kID0gNTQJeDEgPSAzOTAuMDAwMAl4MiA9IC0wLjU3NTcJeDMgPSAtMS42NjQ5CXg0ID0gMC45NzA3CVZhbHVlID0gLTQuNDMzNiANCiNCT19YR0Jvb3N0X0xpbmVhcl9ncmlkIDwtIGV4cGFuZC5ncmlkKA0KIyAgbnJvdW5kcyA9IDM5MCwgICMgbnVtYmVyIG9mIGJvb3N0aW5nIGl0ZXJhdGlvbnMNCiMgIGxhbWJkYSA9IDEwXjAuOTcwNywgIyBMMSBSZWd1bGFyaXphdGlvbiAoTGFzc28gUmVncmVzc2lvbikNCiMgIGFscGhhID0gMTBeLTEuNjY0OSwgIyBMMiBSZWd1bGFyaXphdGlvbiAoUmlkZ2UgUmVncmVzc2lvbikNCiMgIGV0YSA9IDEwXi0wLjU3NTdeMTAgIyBsZWFybmluZyByYXRlLCBsb3cgdmFsdWUgbWVhbnMgbW9kZWwgaXMgbW9yZSByb2J1c3QgdG8gb3ZlcmZpdHRpbmcNCiMpDQoNCg0KQk9fWEdCb29zdF9MaW5lYXJfZ3JpZCA8LSBleHBhbmQuZ3JpZCgNCiAgbnJvdW5kcyA9IHJvdW5kKEJPX1hHQm9vc3RfTGluZWFyX21vZGVsJEJlc3RfUGFyWzFdKSwgICMgbnVtYmVyIG9mIGJvb3N0aW5nIGl0ZXJhdGlvbnMNCiAgZXRhID0gMTBeQk9fWEdCb29zdF9MaW5lYXJfbW9kZWwkQmVzdF9QYXJbMl0sICMgbGVhcm5pbmcgcmF0ZSwgbG93IHZhbHVlIG1lYW5zIG1vZGVsIGlzIG1vcmUgcm9idXN0IHRvIG92ZXJmaXR0aW5nDQogIGFscGhhID0gMTBeQk9fWEdCb29zdF9MaW5lYXJfbW9kZWwkQmVzdF9QYXJbM10sICMgTDIgUmVndWxhcml6YXRpb24gKFJpZGdlIFJlZ3Jlc3Npb24pDQogIGxhbWJkYSA9IDEwXkJPX1hHQm9vc3RfTGluZWFyX21vZGVsJEJlc3RfUGFyWzRdICMgTDEgUmVndWxhcml6YXRpb24gKExhc3NvIFJlZ3Jlc3Npb24pDQopDQoNCnRpYygpDQpjbHVzdGVyIDwtIG1ha2VDbHVzdGVyKGRldGVjdENvcmVzKCkgLSAxKSAjIG51bWJlciBvZiBjb3JlcywgY29udmVudGlvbiB0byBsZWF2ZSAxIGNvcmUgZm9yIE9TDQpyZWdpc3RlckRvUGFyYWxsZWwoY2x1c3RlcikgIyByZWdpc3RlciB0aGUgcGFyYWxsZWwgcHJvY2Vzc2luZw0KDQpzZXQuc2VlZCgxKQ0KIyBUcmFpbiBtb2RlbCB3aXRoIG9wdGltYWwgdmFsdWVzDQojbW9kZWxMb29rdXAobW9kZWwgPSAieGdiTGluZWFyIikNCkJPX1hHQm9vc3RfTGluZWFyX21vZGVsX2ZpbiA8LSBjYXJldDo6dHJhaW4oDQogIFN0cmVuZ3RoIH4uLCANCiAgZGF0YSA9IHRyYWluLmRhdGEsIA0KICBtZXRob2QgPSAieGdiTGluZWFyIiwNCiAgdHJDb250cm9sID0gdHJhaW5fY29udHJvbCwNCiAgdmVyYm9zZSA9IEYsIG1ldHJpYyA9ICJSTVNFIiwgbWF4aW1pemUgPSBGQUxTRSwNCiAgc2lsZW50ID0gMSwNCiAgdHVuZUdyaWQgPSBCT19YR0Jvb3N0X0xpbmVhcl9ncmlkDQopDQoNCnN0b3BDbHVzdGVyKGNsdXN0ZXIpICMgc2h1dCBkb3duIHRoZSBjbHVzdGVyIA0KcmVnaXN0ZXJEb1NFUSgpICMgIGZvcmNlIFIgdG8gcmV0dXJuIHRvIHNpbmdsZSB0aHJlYWRlZCBwcm9jZXNzaW5nDQp0b2MoKQ0KDQpCT19YR0Jvb3N0X0xpbmVhcl9tb2RlbF9maW4NCg0Kc2F2ZVJEUyhvYmplY3QgPSBCT19YR0Jvb3N0X0xpbmVhcl9tb2RlbF9maW4sIGZpbGUgPSBwYXN0ZTAoIk1vZGVscy9CT19YR0Jvb3N0X0xpbmVhcl9tb2RlbF9maW4iLCBzdHJpbmdyOjpzdHJfcmVtb3ZlX2FsbChTeXMudGltZSgpLCBwYXR0ZXJuID0gIjoiKSwiLnJkcyIpKQ0KYGBgDQoNCg0KDQoNCg0KDQojIFN1bW1hcnkgb2YgQWxsIFRyYWluaW5nIFJ1bnMNCg0KYGBge3J9DQojIENyZWF0ZSBzdW1tYXJ5IHRhYmxlDQpTdW1tYXJ5X1RhYmxlX1RyYWluaW5nIDwtIGJpbmRfcm93cygNCiAgR1NfWEdCb29zdF9MaW5lYXJfbW9kZWxfZmluJHJlc3VsdHMgJT4lIGFycmFuZ2UoUk1TRSkgJT4lIC5bMSxdICU+JSBzZWxlY3QoUk1TRSwgTUFFLCBSc3F1YXJlZCwgbnJvdW5kcywgZXRhLCBsYW1iZGEsIGFscGhhKSAlPiUgcm91bmQoNSksDQogIFJTX1hHQm9vc3RfTGluZWFyX21vZGVsX2ZpbiRyZXN1bHRzICU+JSBhcnJhbmdlKFJNU0UpICU+JSAuWzEsXSAlPiUgc2VsZWN0KFJNU0UsIE1BRSwgUnNxdWFyZWQsIG5yb3VuZHMsIGV0YSwgbGFtYmRhLCBhbHBoYSkgJT4lIHJvdW5kKDUpLA0KICBHQV9YR0Jvb3N0X0xpbmVhcl9tb2RlbF9maW4kcmVzdWx0cyAlPiUgYXJyYW5nZShSTVNFKSAlPiUgLlsxLF0gJT4lIHNlbGVjdChSTVNFLCBNQUUsIFJzcXVhcmVkLCBucm91bmRzLCBldGEsIGxhbWJkYSwgYWxwaGEpICU+JSByb3VuZCg1KSwNCiAgREVfWEdCb29zdF9MaW5lYXJfbW9kZWxfZmluJHJlc3VsdHMgJT4lIGFycmFuZ2UoUk1TRSkgJT4lIC5bMSxdICU+JSBzZWxlY3QoUk1TRSwgTUFFLCBSc3F1YXJlZCwgbnJvdW5kcywgZXRhLCBsYW1iZGEsIGFscGhhKSAlPiUgcm91bmQoNSksDQogIFBTT19YR0Jvb3N0X0xpbmVhcl9tb2RlbF9maW4kcmVzdWx0cyAlPiUgYXJyYW5nZShSTVNFKSAlPiUgLlsxLF0gJT4lIHNlbGVjdChSTVNFLCBNQUUsIFJzcXVhcmVkLCBucm91bmRzLCBldGEsIGxhbWJkYSwgYWxwaGEpICU+JSByb3VuZCg1KSwNCiAgQk9fWEdCb29zdF9MaW5lYXJfbW9kZWxfZmluJHJlc3VsdHMgJT4lIGFycmFuZ2UoUk1TRSkgJT4lIC5bMSxdICU+JSBzZWxlY3QoUk1TRSwgTUFFLCBSc3F1YXJlZCwgbnJvdW5kcywgZXRhLCBsYW1iZGEsIGFscGhhKSAlPiUgcm91bmQoNSkpDQoNClN1bW1hcnlfVGFibGVfVHJhaW5pbmcgPC0gU3VtbWFyeV9UYWJsZV9UcmFpbmluZyAlPiUgDQogIGFkZF9jb2x1bW4oTWV0aG9kID0gYygiR3JpZCBTZWFyY2giLCAiQWRhcHRpdmUgUmFuZG9tIFNlYXJjaCIsICJHZW5ldGljIEFsZ29yaXRobSIsICJEaWZmZXJlbnRpYWwgRXZvbHV0aW9uIiwgIlBhcnRpY2xlIFN3YXJtIE9wdGltaXphdGlvbiIsICJCYXllc2lhbiBPcHRpbWl6YXRpb24iKSwgLmJlZm9yZSA9IDEpICU+JSANCiAgYWRkX2NvbHVtbihgUHJvY2Vzc2luZyBUaW1lYCA9IHJvdW5kKGMoR1NfVDEtR1NfVDAsIFJTX1QxLVJTX1QwLCBHQV9UMS1HQV9UMCwgREVfVDEtREVfVDAsIFBTT19UMS1QU09fVDAsIEJPX1QxLSBCT19UMCksMCkpDQoNCiNTdW1tYXJ5X1RhYmxlX1RyYWluaW5nIDwtIFN1bW1hcnlfVGFibGVfVHJhaW5pbmcgJT4lIA0KIyAgYWRkX2NvbHVtbihNZXRob2QgPSBjKCJHcmlkIFNlYXJjaCIsICJSYW5kb20gU2VhcmNoIiwgIkdlbmV0aWMgQWxnb3JpdGhtIiwgIkRpZmZlcmVudGlhbCBFdm9sdXRpb24iLCAiUGFydGljbGUgI1N3YXJtIE9wdGltaXphdGlvbiIpLCAuYmVmb3JlID0gMSkNCg0KIyBQcmludCB0YWJsZQ0KU3VtbWFyeV9UYWJsZV9UcmFpbmluZyAlPiUgDQogIGthYmxlKGFsaWduID0gImMiLCBjYXB0aW9uID0gIlRyYWluaW5nIFNldCBTdGF0aXN0aWNzIGFuZCBIeXBlcnBhcmFtZXRlciBWYWx1ZXMgb2YgWEdCb29zdCBNb2RlbHMuIikgJT4lIA0KICBrYWJsZUV4dHJhOjprYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiLCAicmVzcG9uc2l2ZSIpLCBmdWxsX3dpZHRoID0gVCwgcG9zaXRpb24gPSAiY2VudGVyIikgJT4lDQogIGthYmxlRXh0cmE6OmZvb3Rub3RlKGdlbmVyYWwgPSBwYXN0ZTAoIk5vdGU6XG5TdW1tYXJ5IHN0YXRpc3RpY3Mgb2J0YWluZWQgdXNpbmcgIiwgQ1ZfZm9sZHMsICItZm9sZCBjcm9zcyB2YWxpZGF0aW9uIHJlcGVhdGVkICIsIENWX3JlcGVhdHMsICIgdGltZXMuIiwiXG5HcmlkIGFuZCBSYW5kb20gU2VhcmNoICBwZXJmb3JtZWQgd2l0aCBhZGFwdGl2ZSByZXNhbXBsaW5nLiIpLCBnZW5lcmFsX3RpdGxlID0gIlxuICIpDQpgYGANCg0KIyBQZXJmb3JtYW5jZSBPbiBUZXN0IFNldA0KDQpgYGB7cn0NCiNDdXN0b20gZnVuY3Rpb25zIHRvIHBsb3Qgb2JzZXJ2ZWQsIHByZWRpY3RlZCBhbmQgcmVzaWR1YWwgdmFsdWVzIGZvciBlYWNoIG1ldGhvZA0KbGlicmFyeShnZ3Bsb3QyLCBxdWlldGx5ID0gVCwgdmVyYm9zZSA9IEYpDQoNCiMgRnVuY3Rpb24gdG8gcGxvdCBvYnNlcnZlZCB2cyBwcmVkaWN0ZWQgdmFsdWVzDQpwcmVkaWN0ZWRfb2JzZXJ2ZWRfcGxvdCA8LSBmdW5jdGlvbihwcmVkaWN0ZWRfdmFsLCBvYnNlcnZlZF92YWwsIHJlc2lkdWFsX3ZhbCwgbW9kZWxfbmFtZSA9ICIiLCBSX3NxdWFyZWQsIC4uLikgew0KICANCiAgcGxvdCA8LSBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4ID0gcHJlZGljdGVkX3ZhbCwgeSA9IG9ic2VydmVkX3ZhbCwgY29sID0gYWJzKHJlc2lkdWFsX3ZhbCkpKSArDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjksIHNpemUgPSAyKSArDQogIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDAsIHNsb3BlID0gMSkgKw0KICAgICMgZmFjZXRfd3JhcCh+KSArDQogICAgbGFicyh0aXRsZSA9IHBhc3RlMChtb2RlbF9uYW1lLCAiXG5QcmVkaWN0ZWQgdnMgT2JzZXJ2ZWQ6IFRlc3QgU2V0IiksDQogICAgICAgICBzdWJ0aXRsZSA9IHBhc3RlMCgiUi1zcXVhcmVkOiAiLCBSX3NxdWFyZWQpLA0KICAgICAgICAgeCA9ICJQcmVkaWN0ZWQiLA0KICAgICAgICAgeSA9ICJPYnNlcnZlZCIsDQogICAgICAgICBjb2wgPSAiQWJzb2x1dGUgRGV2aWF0aW9uIikgKw0KICB0aGVtZV9idygpICsNCiAgdGhlbWUoYXNwZWN0LnJhdGlvID0gMC45LCBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsIGZhY2U9ImJvbGQiKSwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpLCBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTIsIGZhY2U9ImJvbGQiKSwgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMCwgZmFjZT0iYm9sZCIpLCBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDApLCBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsNCiAgIyBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSArDQogICMgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkgKyANCiAgY29vcmRfZXF1YWwoKSArIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYyhkaXJlY3Rpb24gPSAtMSkNCg0KICByZXR1cm4gKHBsb3QpDQp9DQoNCiMgRnVuY3Rpb24gdG8gcGxvdCByZXNpZHVhbHMNCnJlc2lkdWFsc19wbG90IDwtIGZ1bmN0aW9uKHByZWRpY3RlZF92YWwsIHJlc2lkdWFsX3ZhbCwgbW9kZWxfbmFtZSA9ICIiLCBNQUUsIFJNU0UsIC4uLikgew0KDQogIHBsb3QgPC0gZ2dwbG90KG1hcHBpbmcgPSBhZXMoeCA9IHByZWRpY3RlZF92YWwsIHkgPSByZXNpZHVhbF92YWwsIGNvbCA9IGFicyhyZXNpZHVhbF92YWwpKSkgKw0KICBnZW9tX3BvaW50KGFscGhhID0gMC45LCBzaXplID0gMikgKw0KICBnZW9tX2FibGluZShpbnRlcmNlcHQgPSAwLCBzbG9wZSA9IDApICsNCiAgICAjIGZhY2V0X3dyYXAofikgKw0KICAgIGxhYnMoDQogICAgICAgdGl0bGUgPSBwYXN0ZTAobW9kZWxfbmFtZSwgIlxuUmVzaWR1YWxzOiBUZXN0IFNldCIpLA0KICAgICAgIHN1YnRpdGxlID0gcGFzdGUwKCJSTVNFOiAiLCBSTVNFLCAiLCBNQUU6ICIsIHJvdW5kKE1BRSwgMykpLA0KICAgICAgIHggPSAiUHJlZGljdGVkIiwNCiAgICAgICB5ID0gIlJlc2lkdWFsIiwNCiAgICAgICBjb2wgPSAiQWJzb2x1dGUgRGV2aWF0aW9uIg0KICAgICAgICkgKw0KICB0aGVtZV9idygpICsNCiAgdGhlbWUoYXNwZWN0LnJhdGlvID0gMC45LCBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsIGZhY2U9ImJvbGQiKSwgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpLCBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTIsIGZhY2U9ImJvbGQiKSwgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMCwgZmFjZT0iYm9sZCIpLCBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDApLCBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsNCiAgIyBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSArDQogICMgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkgKw0KICBjb29yZF9lcXVhbCgpICsgc2NhbGVfY29sb3JfdmlyaWRpc19jKGRpcmVjdGlvbiA9IC0xKQ0KDQogIHJldHVybiAocGxvdCkNCn0NCmBgYA0KDQojIyMgR1MgLSBSZXNpZHVhbCBQbG90cw0KDQpgYGB7cn0NCiMjIyBHcmlkIFNlYXJjaCAoR1MpDQoNCiMgTWFrZSBwcmVkaWN0aW9ucyBvbiB0ZXN0IHNldA0KdGVzdC5kYXRhJFhHQm9vc3RfTGluZWFyX0dTIDwtIHByZWRpY3QoR1NfWEdCb29zdF9MaW5lYXJfbW9kZWxfZmluLCB0ZXN0LmRhdGEpDQojIENhbGN1bGF0ZSBSZXNpZHVhbHMgb24gdGVzdCBzZXQNCnRlc3QuZGF0YSRYR0Jvb3N0X0xpbmVhcl9HU19yZXNpZHVhbCA8LSB0ZXN0LmRhdGEkU3RyZW5ndGggLSB0ZXN0LmRhdGEkWEdCb29zdF9MaW5lYXJfR1MNCg0KIyBDYWxjdWxhdGUgdGVzdCBzZXQgUi1zcXVhcmVkLCBSTVNFLCBNQUUNClJfc3F1YXJlZCA8LSByb3VuZChjb3IodGVzdC5kYXRhJFhHQm9vc3RfTGluZWFyX0dTLCB0ZXN0LmRhdGEkU3RyZW5ndGgpLCA0KQ0KUk1TRSA8LSBzaWduaWYoUk1TRShwcmVkID0gdGVzdC5kYXRhJFhHQm9vc3RfTGluZWFyX0dTLCBvYnMgPSB0ZXN0LmRhdGEkU3RyZW5ndGgsIG5hLnJtID0gVCksIDYpDQpNQUUgPC0gc2lnbmlmKE1BRShwcmVkID0gdGVzdC5kYXRhJFhHQm9vc3RfTGluZWFyX0dTLCBvYnMgPSB0ZXN0LmRhdGEkU3RyZW5ndGgpLCA2KQ0KDQpHU190ZXN0LmRhdGFfU3RhdGlzdGljcyA8LSBjKFJNU0UsIE1BRSwgUl9zcXVhcmVkKQ0KDQojIFBsb3QgcHJlZGljdGVkIHZzIG9ic2VydmVkIHZhbHVlcyBhbmQgcmVzaWR1YWxzDQpYR0Jvb3N0X0xpbmVhcl9HU19wcmVkX29icyA8LSBwcmVkaWN0ZWRfb2JzZXJ2ZWRfcGxvdChwcmVkaWN0ZWRfdmFsID0gdGVzdC5kYXRhJFhHQm9vc3RfTGluZWFyX0dTLCBvYnNlcnZlZF92YWwgPSB0ZXN0LmRhdGEkU3RyZW5ndGgsIHJlc2lkdWFsX3ZhbCA9IHRlc3QuZGF0YSRYR0Jvb3N0X0xpbmVhcl9HU19yZXNpZHVhbCwgUl9zcXVhcmVkID0gUl9zcXVhcmVkLCBtb2RlbF9uYW1lID0gIkdyaWQgU2VhcmNoIikNClhHQm9vc3RfTGluZWFyX0dTX3Jlc2lkdWFscyA8LSByZXNpZHVhbHNfcGxvdChwcmVkaWN0ZWRfdmFsID0gdGVzdC5kYXRhJFhHQm9vc3RfTGluZWFyX0dTLCBvYnNlcnZlZF92YWwgPSB0ZXN0LmRhdGEkU3RyZW5ndGgsIHJlc2lkdWFsX3ZhbCA9IHRlc3QuZGF0YSRYR0Jvb3N0X0xpbmVhcl9HU19yZXNpZHVhbCwgTUFFID0gTUFFLCBSTVNFID0gUk1TRSwgbW9kZWxfbmFtZSA9ICJHcmlkIFNlYXJjaCIpDQpncmlkRXh0cmE6OmdyaWQuYXJyYW5nZShYR0Jvb3N0X0xpbmVhcl9HU19wcmVkX29icywgWEdCb29zdF9MaW5lYXJfR1NfcmVzaWR1YWxzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDIpDQpgYGANCg0KIyMjIFJTIC0gUmVzaWR1YWwgUGxvdHMNCg0KYGBge3J9DQojIE1ha2UgcHJlZGljdGlvbnMgb24gdGVzdCBzZXQNCnRlc3QuZGF0YSRYR0Jvb3N0X0xpbmVhcl9SUyA8LSBwcmVkaWN0KFJTX1hHQm9vc3RfTGluZWFyX21vZGVsX2ZpbiwgdGVzdC5kYXRhKQ0KIyBDYWxjdWxhdGUgUmVzaWR1YWxzIG9uIHRlc3Qgc2V0DQp0ZXN0LmRhdGEkWEdCb29zdF9MaW5lYXJfUlNfcmVzaWR1YWwgPC0gdGVzdC5kYXRhJFN0cmVuZ3RoIC0gdGVzdC5kYXRhJFhHQm9vc3RfTGluZWFyX1JTDQoNCiMgQ2FsY3VsYXRlIHRlc3Qgc2V0IFItc3F1YXJlZCwgUk1TRSwgTUFFDQpSX3NxdWFyZWQgPC0gcm91bmQoY29yKHRlc3QuZGF0YSRYR0Jvb3N0X0xpbmVhcl9SUywgdGVzdC5kYXRhJFN0cmVuZ3RoKSwgNCkNClJNU0UgPC0gc2lnbmlmKFJNU0UocHJlZCA9IHRlc3QuZGF0YSRYR0Jvb3N0X0xpbmVhcl9SUywgb2JzID0gdGVzdC5kYXRhJFN0cmVuZ3RoLCBuYS5ybSA9IFQpLCA2KQ0KTUFFIDwtIHNpZ25pZihNQUUocHJlZCA9IHRlc3QuZGF0YSRYR0Jvb3N0X0xpbmVhcl9SUywgb2JzID0gdGVzdC5kYXRhJFN0cmVuZ3RoKSwgNikNCg0KUlNfdGVzdC5kYXRhX1N0YXRpc3RpY3MgPC0gYyhSTVNFLCBNQUUsIFJfc3F1YXJlZCkNCg0KIyBQbG90IHByZWRpY3RlZCB2cyBvYnNlcnZlZCB2YWx1ZXMgYW5kIHJlc2lkdWFscw0KWEdCb29zdF9MaW5lYXJfUlNfcHJlZF9vYnMgPC0gcHJlZGljdGVkX29ic2VydmVkX3Bsb3QocHJlZGljdGVkX3ZhbCA9IHRlc3QuZGF0YSRYR0Jvb3N0X0xpbmVhcl9SUywgb2JzZXJ2ZWRfdmFsID0gdGVzdC5kYXRhJFN0cmVuZ3RoLCByZXNpZHVhbF92YWwgPSB0ZXN0LmRhdGEkWEdCb29zdF9MaW5lYXJfUlNfcmVzaWR1YWwsIFJfc3F1YXJlZCA9IFJfc3F1YXJlZCwgbW9kZWxfbmFtZSA9ICJSYW5kb20gU2VhY2giKQ0KWEdCb29zdF9MaW5lYXJfUlNfcmVzaWR1YWxzIDwtIHJlc2lkdWFsc19wbG90KHByZWRpY3RlZF92YWwgPSB0ZXN0LmRhdGEkWEdCb29zdF9MaW5lYXJfUlMsIG9ic2VydmVkX3ZhbCA9IHRlc3QuZGF0YSRTdHJlbmd0aCwgcmVzaWR1YWxfdmFsID0gdGVzdC5kYXRhJFhHQm9vc3RfTGluZWFyX1JTX3Jlc2lkdWFsLCBNQUUgPSBNQUUsIFJNU0UgPSBSTVNFLCBtb2RlbF9uYW1lID0gIlJhbmRvbSBTZWFjaCIpDQpncmlkRXh0cmE6OmdyaWQuYXJyYW5nZShYR0Jvb3N0X0xpbmVhcl9SU19wcmVkX29icywgWEdCb29zdF9MaW5lYXJfUlNfcmVzaWR1YWxzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDIpDQpgYGANCg0KIyMjIEdBIC0gUmVzaWR1YWwgUGxvdHMNCg0KYGBge3J9DQojIyMgR2VuZXRpYyBBbGdvcml0aG0gKEdBKQ0KDQojIE1ha2UgcHJlZGljdGlvbnMgb24gdGVzdCBzZXQNCnRlc3QuZGF0YSRYR0Jvb3N0X0xpbmVhcl9HQSA8LSBwcmVkaWN0KEdBX1hHQm9vc3RfTGluZWFyX21vZGVsX2ZpbiwgdGVzdC5kYXRhKQ0KIyBDYWxjdWxhdGUgUmVzaWR1YWxzIG9uIHRlc3Qgc2V0DQp0ZXN0LmRhdGEkWEdCb29zdF9MaW5lYXJfR0FfcmVzaWR1YWwgPC0gdGVzdC5kYXRhJFN0cmVuZ3RoIC0gdGVzdC5kYXRhJFhHQm9vc3RfTGluZWFyX0dBDQoNCiMgQ2FsY3VsYXRlIHRlc3Qgc2V0IFItc3F1YXJlZCwgUk1TRSwgTUFFDQpSX3NxdWFyZWQgPC0gcm91bmQoY29yKHRlc3QuZGF0YSRYR0Jvb3N0X0xpbmVhcl9HQSwgdGVzdC5kYXRhJFN0cmVuZ3RoKSwgNCkNClJNU0UgPC0gc2lnbmlmKFJNU0UocHJlZCA9IHRlc3QuZGF0YSRYR0Jvb3N0X0xpbmVhcl9HQSwgb2JzID0gdGVzdC5kYXRhJFN0cmVuZ3RoLCBuYS5ybSA9IFQpLCA2KQ0KTUFFIDwtIHNpZ25pZihNQUUocHJlZCA9IHRlc3QuZGF0YSRYR0Jvb3N0X0xpbmVhcl9HQSwgb2JzID0gdGVzdC5kYXRhJFN0cmVuZ3RoKSwgNikNCg0KR0FfdGVzdC5kYXRhX1N0YXRpc3RpY3MgPC0gYyhSTVNFLCBNQUUsIFJfc3F1YXJlZCkNCg0KIyBQbG90IHByZWRpY3RlZCB2cyBvYnNlcnZlZCB2YWx1ZXMgYW5kIHJlc2lkdWFscw0KWEdCb29zdF9MaW5lYXJfR0FfcHJlZF9vYnMgPC0gcHJlZGljdGVkX29ic2VydmVkX3Bsb3QocHJlZGljdGVkX3ZhbCA9IHRlc3QuZGF0YSRYR0Jvb3N0X0xpbmVhcl9HQSwgb2JzZXJ2ZWRfdmFsID0gdGVzdC5kYXRhJFN0cmVuZ3RoLCByZXNpZHVhbF92YWwgPSB0ZXN0LmRhdGEkWEdCb29zdF9MaW5lYXJfR0FfcmVzaWR1YWwsIFJfc3F1YXJlZCA9IFJfc3F1YXJlZCwgbW9kZWxfbmFtZSA9ICJHZW5ldGljIEFsZ29yaXRobSIpDQpYR0Jvb3N0X0xpbmVhcl9HQV9yZXNpZHVhbHMgPC0gcmVzaWR1YWxzX3Bsb3QocHJlZGljdGVkX3ZhbCA9IHRlc3QuZGF0YSRYR0Jvb3N0X0xpbmVhcl9HQSwgb2JzZXJ2ZWRfdmFsID0gdGVzdC5kYXRhJFN0cmVuZ3RoLCByZXNpZHVhbF92YWwgPSB0ZXN0LmRhdGEkWEdCb29zdF9MaW5lYXJfR0FfcmVzaWR1YWwsIE1BRSA9IE1BRSwgUk1TRSA9IFJNU0UsIG1vZGVsX25hbWUgPSAiR2VuZXRpYyBBbGdvcml0aG0iKQ0KZ3JpZEV4dHJhOjpncmlkLmFycmFuZ2UoWEdCb29zdF9MaW5lYXJfR0FfcHJlZF9vYnMsIFhHQm9vc3RfTGluZWFyX0dBX3Jlc2lkdWFscywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAyKQ0KDQpgYGANCg0KIyMjIERFIC0gUmVzaWR1YWwgUGxvdHMNCg0KYGBge3J9DQojIyMgRGlmZmVyZW50aWFsIGV2b2x1dGlvbiAoREUpDQoNCiMgTWFrZSBwcmVkaWN0aW9ucyBvbiB0ZXN0IHNldA0KdGVzdC5kYXRhJFhHQm9vc3RfTGluZWFyX0RFIDwtIHByZWRpY3QoREVfWEdCb29zdF9MaW5lYXJfbW9kZWxfZmluLCB0ZXN0LmRhdGEpDQojIENhbGN1bGF0ZSBSZXNpZHVhbHMgb24gdGVzdCBzZXQNCnRlc3QuZGF0YSRYR0Jvb3N0X0xpbmVhcl9ERV9yZXNpZHVhbCA8LSB0ZXN0LmRhdGEkU3RyZW5ndGggLSB0ZXN0LmRhdGEkWEdCb29zdF9MaW5lYXJfREUNCg0KIyBDYWxjdWxhdGUgdGVzdCBzZXQgUi1zcXVhcmVkLCBSTVNFLCBNQUUNClJfc3F1YXJlZCA8LSByb3VuZChjb3IodGVzdC5kYXRhJFhHQm9vc3RfTGluZWFyX0RFLCB0ZXN0LmRhdGEkU3RyZW5ndGgpLCA0KQ0KUk1TRSA8LSBzaWduaWYoUk1TRShwcmVkID0gdGVzdC5kYXRhJFhHQm9vc3RfTGluZWFyX0RFLCBvYnMgPSB0ZXN0LmRhdGEkU3RyZW5ndGgsIG5hLnJtID0gVCksIDYpDQpNQUUgPC0gc2lnbmlmKE1BRShwcmVkID0gdGVzdC5kYXRhJFhHQm9vc3RfTGluZWFyX0RFLCBvYnMgPSB0ZXN0LmRhdGEkU3RyZW5ndGgpLCA2KQ0KDQpERV90ZXN0LmRhdGFfU3RhdGlzdGljcyA8LSBjKFJNU0UsIE1BRSwgUl9zcXVhcmVkKQ0KDQojIFBsb3QgcHJlZGljdGVkIHZzIG9ic2VydmVkIHZhbHVlcyBhbmQgcmVzaWR1YWxzDQpYR0Jvb3N0X0xpbmVhcl9ERV9wcmVkX29icyA8LSBwcmVkaWN0ZWRfb2JzZXJ2ZWRfcGxvdChwcmVkaWN0ZWRfdmFsID0gdGVzdC5kYXRhJFhHQm9vc3RfTGluZWFyX0RFLCBvYnNlcnZlZF92YWwgPSB0ZXN0LmRhdGEkU3RyZW5ndGgsIHJlc2lkdWFsX3ZhbCA9IHRlc3QuZGF0YSRYR0Jvb3N0X0xpbmVhcl9ERV9yZXNpZHVhbCwgUl9zcXVhcmVkID0gUl9zcXVhcmVkLCBtb2RlbF9uYW1lID0gIkRpZmZlcmVudGlhbCBFdm9sdXRpb24iKQ0KWEdCb29zdF9MaW5lYXJfREVfcmVzaWR1YWxzIDwtIHJlc2lkdWFsc19wbG90KHByZWRpY3RlZF92YWwgPSB0ZXN0LmRhdGEkWEdCb29zdF9MaW5lYXJfREUsIG9ic2VydmVkX3ZhbCA9IHRlc3QuZGF0YSRTdHJlbmd0aCwgcmVzaWR1YWxfdmFsID0gdGVzdC5kYXRhJFhHQm9vc3RfTGluZWFyX0RFX3Jlc2lkdWFsLCBNQUUgPSBNQUUsIFJNU0UgPSBSTVNFLCBtb2RlbF9uYW1lID0gIkRpZmZlcmVudGlhbCBFdm9sdXRpb24iKQ0KZ3JpZEV4dHJhOjpncmlkLmFycmFuZ2UoWEdCb29zdF9MaW5lYXJfREVfcHJlZF9vYnMsIFhHQm9vc3RfTGluZWFyX0RFX3Jlc2lkdWFscywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAyKQ0KDQpgYGANCg0KIyMjIFBTTyAtIFJlc2lkdWFsIFBsb3RzDQoNCmBgYHtyfQ0KIyMjIFBhcnRpY2xlIFN3YXJtIE9wdGltaXphdGlvbiAoUFNPKQ0KDQojIE1ha2UgcHJlZGljdGlvbnMgb24gdGVzdCBzZXQNCnRlc3QuZGF0YSRYR0Jvb3N0X0xpbmVhcl9QU08gPC0gcHJlZGljdChQU09fWEdCb29zdF9MaW5lYXJfbW9kZWxfZmluLCB0ZXN0LmRhdGEpDQojIENhbGN1bGF0ZSBSZXNpZHVhbHMgb24gdGVzdCBzZXQNCnRlc3QuZGF0YSRYR0Jvb3N0X0xpbmVhcl9QU09fcmVzaWR1YWwgPC0gdGVzdC5kYXRhJFN0cmVuZ3RoIC0gdGVzdC5kYXRhJFhHQm9vc3RfTGluZWFyX1BTTw0KDQojIENhbGN1bGF0ZSB0ZXN0IHNldCBSLXNxdWFyZWQsIFJNU0UsIE1BRQ0KUl9zcXVhcmVkIDwtIHJvdW5kKGNvcih0ZXN0LmRhdGEkWEdCb29zdF9MaW5lYXJfUFNPLCB0ZXN0LmRhdGEkU3RyZW5ndGgpLCA0KQ0KUk1TRSA8LSBzaWduaWYoUk1TRShwcmVkID0gdGVzdC5kYXRhJFhHQm9vc3RfTGluZWFyX1BTTywgb2JzID0gdGVzdC5kYXRhJFN0cmVuZ3RoLCBuYS5ybSA9IFQpLCA2KQ0KTUFFIDwtIHNpZ25pZihNQUUocHJlZCA9IHRlc3QuZGF0YSRYR0Jvb3N0X0xpbmVhcl9QU08sIG9icyA9IHRlc3QuZGF0YSRTdHJlbmd0aCksIDYpDQoNClBTT190ZXN0LmRhdGFfU3RhdGlzdGljcyA8LSBjKFJNU0UsIE1BRSwgUl9zcXVhcmVkKQ0KDQojIFBsb3QgcHJlZGljdGVkIHZzIG9ic2VydmVkIHZhbHVlcyBhbmQgcmVzaWR1YWxzDQpYR0Jvb3N0X0xpbmVhcl9QU09fcHJlZF9vYnMgPC0gcHJlZGljdGVkX29ic2VydmVkX3Bsb3QocHJlZGljdGVkX3ZhbCA9IHRlc3QuZGF0YSRYR0Jvb3N0X0xpbmVhcl9QU08sIG9ic2VydmVkX3ZhbCA9IHRlc3QuZGF0YSRTdHJlbmd0aCwgcmVzaWR1YWxfdmFsID0gdGVzdC5kYXRhJFhHQm9vc3RfTGluZWFyX1BTT19yZXNpZHVhbCwgUl9zcXVhcmVkID0gUl9zcXVhcmVkLCBtb2RlbF9uYW1lID0gIlBhcnRpY2xlIFN3YXJtIE9wdGltaXNhdGlvbiIpDQpYR0Jvb3N0X0xpbmVhcl9QU09fcmVzaWR1YWxzIDwtIHJlc2lkdWFsc19wbG90KHByZWRpY3RlZF92YWwgPSB0ZXN0LmRhdGEkWEdCb29zdF9MaW5lYXJfUFNPLCBvYnNlcnZlZF92YWwgPSB0ZXN0LmRhdGEkU3RyZW5ndGgsIHJlc2lkdWFsX3ZhbCA9IHRlc3QuZGF0YSRYR0Jvb3N0X0xpbmVhcl9QU09fcmVzaWR1YWwsIE1BRSA9IE1BRSwgUk1TRSA9IFJNU0UsIG1vZGVsX25hbWUgPSAiUGFydGljbGUgU3dhcm0gT3B0aW1pc2F0aW9uIikNCmdyaWRFeHRyYTo6Z3JpZC5hcnJhbmdlKFhHQm9vc3RfTGluZWFyX1BTT19wcmVkX29icywgWEdCb29zdF9MaW5lYXJfUFNPX3Jlc2lkdWFscywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAyKQ0KDQpgYGANCg0KIyMjIEJPIC0gUmVzaWR1YWwgUGxvdHMNCg0KYGBge3J9DQojIyMgQmF5ZXNpYW4gT3B0aW1pemF0aW9uKQ0KDQojIE1ha2UgcHJlZGljdGlvbnMgb24gdGVzdCBzZXQNCnRlc3QuZGF0YSRYR0Jvb3N0X0xpbmVhcl9CTyA8LSBwcmVkaWN0KEJPX1hHQm9vc3RfTGluZWFyX21vZGVsX2ZpbiwgdGVzdC5kYXRhKQ0KIyBDYWxjdWxhdGUgUmVzaWR1YWxzIG9uIHRlc3Qgc2V0DQp0ZXN0LmRhdGEkWEdCb29zdF9MaW5lYXJfQk9fcmVzaWR1YWwgPC0gdGVzdC5kYXRhJFN0cmVuZ3RoIC0gdGVzdC5kYXRhJFhHQm9vc3RfTGluZWFyX0JPDQoNCiMgQ2FsY3VsYXRlIHRlc3Qgc2V0IFItc3F1YXJlZCwgUk1TRSwgTUFFDQpSX3NxdWFyZWQgPC0gcm91bmQoY29yKHRlc3QuZGF0YSRYR0Jvb3N0X0xpbmVhcl9CTywgdGVzdC5kYXRhJFN0cmVuZ3RoKSwgNCkNClJNU0UgPC0gc2lnbmlmKFJNU0UocHJlZCA9IHRlc3QuZGF0YSRYR0Jvb3N0X0xpbmVhcl9CTywgb2JzID0gdGVzdC5kYXRhJFN0cmVuZ3RoLCBuYS5ybSA9IFQpLCA2KQ0KTUFFIDwtIHNpZ25pZihNQUUocHJlZCA9IHRlc3QuZGF0YSRYR0Jvb3N0X0xpbmVhcl9CTywgb2JzID0gdGVzdC5kYXRhJFN0cmVuZ3RoKSwgNikNCg0KQk9fdGVzdC5kYXRhX1N0YXRpc3RpY3MgPC0gYyhSTVNFLCBNQUUsIFJfc3F1YXJlZCkNCg0KIyBQbG90IHByZWRpY3RlZCB2cyBvYnNlcnZlZCB2YWx1ZXMgYW5kIHJlc2lkdWFscw0KWEdCb29zdF9MaW5lYXJfQk9fcHJlZF9vYnMgPC0gcHJlZGljdGVkX29ic2VydmVkX3Bsb3QocHJlZGljdGVkX3ZhbCA9IHRlc3QuZGF0YSRYR0Jvb3N0X0xpbmVhcl9CTywgb2JzZXJ2ZWRfdmFsID0gdGVzdC5kYXRhJFN0cmVuZ3RoLCByZXNpZHVhbF92YWwgPSB0ZXN0LmRhdGEkWEdCb29zdF9MaW5lYXJfQk9fcmVzaWR1YWwsIFJfc3F1YXJlZCA9IFJfc3F1YXJlZCwgbW9kZWxfbmFtZSA9ICJCYXllc2lhbiBPcHRpbWl6YXRpb24iKQ0KWEdCb29zdF9MaW5lYXJfQk9fcmVzaWR1YWxzIDwtIHJlc2lkdWFsc19wbG90KHByZWRpY3RlZF92YWwgPSB0ZXN0LmRhdGEkWEdCb29zdF9MaW5lYXJfQk8sIG9ic2VydmVkX3ZhbCA9IHRlc3QuZGF0YSRTdHJlbmd0aCwgcmVzaWR1YWxfdmFsID0gdGVzdC5kYXRhJFhHQm9vc3RfTGluZWFyX0JPX3Jlc2lkdWFsLCBNQUUgPSBNQUUsIFJNU0UgPSBSTVNFLCBtb2RlbF9uYW1lID0gIkJheWVzaWFuIE9wdGltaXphdGlvbiIpDQpncmlkRXh0cmE6OmdyaWQuYXJyYW5nZShYR0Jvb3N0X0xpbmVhcl9CT19wcmVkX29icywgWEdCb29zdF9MaW5lYXJfQk9fcmVzaWR1YWxzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDIpDQoNCmBgYA0KDQojIyMgQ3JlYXRlIFN1bW1hcnkgVGFibGUNCg0KYGBge3J9DQojIENyZWF0ZSBzdW1tYXJ5IHRhYmxlDQpTdW1tYXJ5X1RhYmxlX1Rlc3QgPC0gcmJpbmQoDQogIEdTX3Rlc3QuZGF0YV9TdGF0aXN0aWNzLA0KICBSU190ZXN0LmRhdGFfU3RhdGlzdGljcywNCiAgR0FfdGVzdC5kYXRhX1N0YXRpc3RpY3MsDQogIERFX3Rlc3QuZGF0YV9TdGF0aXN0aWNzLA0KICBQU09fdGVzdC5kYXRhX1N0YXRpc3RpY3MsIA0KICBCT190ZXN0LmRhdGFfU3RhdGlzdGljcywNCiAgZGVwYXJzZS5sZXZlbCA9IDAgDQogICkgJT4lIGRhdGEuZnJhbWUoKQ0KDQpjb2xuYW1lcyhTdW1tYXJ5X1RhYmxlX1Rlc3QpIDwtIGMoIlJNU0UiLCAiTUFFIiwgIlItc3F1YXJlZCIpDQpTdW1tYXJ5X1RhYmxlX1Rlc3QgPC0gU3VtbWFyeV9UYWJsZV9UZXN0ICU+JSBhZGRfY29sdW1uKE1ldGhvZCA9IGMoIkdyaWQgU2VhcmNoIiwgIlJhbmRvbSBTZWFyY2giLCAiR2VuZXRpYyBBbGdvcml0aG0iLCAiRGlmZmVyZW50aWFsIEV2b2x1dGlvbiIsICJQYXJ0aWNsZSBTd2FybSBPcHRpbWl6YXRpb24iLCAiQmF5ZXNpYW4gT3B0aW1pemF0aW9uIiksIC5iZWZvcmUgPSAxKQ0KDQojIFByaW50IHRhYmxlDQpTdW1tYXJ5X1RhYmxlX1Rlc3QgJT4lIA0KICBrYWJsZShhbGlnbiA9ICJjIiwgY2FwdGlvbiA9ICJUZXN0IFNldCBTdGF0aXN0aWNzIG9mIFhHQm9vc3QgTW9kZWxzLiIpICU+JSANCiAga2FibGVFeHRyYTo6a2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIiwgInJlc3BvbnNpdmUiKSwgZnVsbF93aWR0aCA9IFQsIHBvc2l0aW9uID0gImNlbnRlciIpICU+JQ0KICBrYWJsZUV4dHJhOjpmb290bm90ZShnZW5lcmFsID0gcGFzdGUwKCIiKSwgZ2VuZXJhbF90aXRsZSA9ICJcbiAiKQ0KYGBgDQoNCmBgYHtyfQ0KI2cgPC0gZ3JpZEV4dHJhOjpncmlkLmFycmFuZ2UoWEdCb29zdF9MaW5lYXJfR1NfcHJlZF9vYnMsIFhHQm9vc3RfTGluZWFyX0dTX3Jlc2lkdWFscywgDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICBYR0Jvb3N0X0xpbmVhcl9SU19wcmVkX29icywgWEdCb29zdF9MaW5lYXJfUlNfcmVzaWR1YWxzLCANCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFhHQm9vc3RfTGluZWFyX0dBX3ByZWRfb2JzLCBYR0Jvb3N0X0xpbmVhcl9HQV9yZXNpZHVhbHMsIA0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgWEdCb29zdF9MaW5lYXJfREVfcHJlZF9vYnMsIFhHQm9vc3RfTGluZWFyX0RFX3Jlc2lkdWFscywgDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICBYR0Jvb3N0X0xpbmVhcl9QU09fcHJlZF9vYnMsIFhHQm9vc3RfTGluZWFyX1BTT19yZXNpZHVhbHMsIA0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgWEdCb29zdF9MaW5lYXJfQk9fcHJlZF9vYnMsIFhHQm9vc3RfTGluZWFyX0JPX3Jlc2lkdWFscywNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAyKQ0KYGBgDQoNCiMgU3VtbWFyeQ0KDQpUaGUgQmF5ZXNpYW4gYXBwcm91Y2ggd2l0aCBwcmltZWQgdmFsdWVzIGlzIHN1cGVyaW9yIHRvIGFsbCBvdGhlciBhcHByb2FjaGVzIGluIHRlcm1zIG9mIGFjY3VyYWN5IGFuZCBjb21wdXRpbmcgcmVzb3VyY2VzLg0KDQo=