Introduction and Data Overview

The purpose of this assignment is to predict the number of baseball games a team will win based on a data set of historic performance data and wins. First, missing data is accounted for and, where possible, null values and outliers are imputed using variable-specific regression tree models. Then four linear models are attempted using different variable selection techniques with the purpose of minimizing prediction error. Additionally, a boosted regression tree model is tested following the four linear models to attempt to improve predictive accuracy. Finally, R code is provided to score a fresh data file and make predictions for teams not included in the original sample.

Exploratory Data Analysis and Prep

Missing Data

The dataset includes information on about 2,200 basball teams between 1871 and 2006. All stats are adjusted for a 162 game season. Two variables (batters hit by pitch and baserunners caught stealing) were removed since they were more than 15% blank (Figure 0.1). For the remaining variables, null values are imputed using the variable-specific regression trees. One new variable is also added to consolidate all non-home-run hit variables into one count of bases earned from hits (hit = 1 base, double = 2 bases, etc).

Skewed Distributions and Outliers

For building an OLS linear model, we need data that is not skewed heavily by outliers or overly clustered in any one area. To remedy skew problems, we first identify outliers (1.5xIQR above or below the first and third quartile), convert those values to nulls, and impute those null values using regression trees.

Initial Correlations

One last data exploration step is to determine which variables correlate most strongly with TARGET_WINS. No variable alone explains a great deal of the variance in the data, but total_bases explains the most, followed by TEAM_PITCHING_BB and TEAM_PITCHING_HR (Figure 0.2).

Model Selection

Four OLS models will be developed for this project using different methods of variable selection: manual, backwards stepwise, bi-directional stepwise, and principal components regression. Additionally, a boosted regression tree model will be developed for comparison with the four main models. The evaluation criteria is root mean squared error (RMSE) calculated on a holdout sample of the training data. The best model will be the one that minimizes RMSE. A model that simply applies the average win count to every team has a predictive error rate of 15 games, so the model developed for this report should represent a significant improvement to be considered successful.

Simple Heuristic OLS Regression

A simple linear regression model using some of the variables that correlate with win-count includes total bases earned, fielding errors, and stolen bases. The model only explains 22% of the variance in the training data, but the model does predict an average of 81 wins with RMSE of 14 games - only one game better than applying the average model.


Call:
lm(formula = TARGET_WINS ~ total_bases + TEAM_PITCHING_BB + TEAM_PITCHING_HR, 
    data = train.train)

Residuals:
    Min      1Q  Median      3Q     Max 
-66.325  -8.940   0.743   9.029  49.221 

Coefficients:
                  Estimate Std. Error t value Pr(>|t|)    
(Intercept)       8.159602   3.383572   2.412    0.016 *  
total_bases       0.027487   0.001479  18.581  < 2e-16 ***
TEAM_PITCHING_BB -0.005120   0.003408  -1.502    0.133    
TEAM_PITCHING_HR  0.030349   0.005696   5.329 1.11e-07 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 14 on 1817 degrees of freedom
Multiple R-squared:  0.2178,    Adjusted R-squared:  0.2165 
F-statistic: 168.7 on 3 and 1817 DF,  p-value: < 2.2e-16

Backwards Variable Selection

Backwards variable selection techniques use Akaike Information Criterion (AIC) to select the model that best explains the variance in the existing data without overfitting the model. The method initially trains a model using all available variables and sequentially removes variables based on their impact on AIC. For each number of variables in a model, the backwards selection algorithm returns the best variables to include in the model. In out of sample testing, marginal improvements to RMSE diminish after 6 variables are included in the model (Figure 2.1).

Similar to the simple heuristic model, residuals appear to be normally distributed with a bit more uncertainty on the ends of the distribution of predicted values. The six-variable model predicts an average of 81 wins per team with an RSME of 13 games.

Bi-Directional Variable Selection

Bi-direcitonal techniques work similarly to backwards variable selection, but at each iteration of model building, variables can be added or removed. Again, for each number of variables in a model, the algorithm returns the best variables to include. In out of sample testing, marginal improvements to RMSE again diminish when 6 variables are included in the model (Figure 3.1).

Model residuals appear to be normally distributed with a bit more uncertainty on the ends of the distribution of predicted values. Similar to backwards variable selection, the six-variable bi-directional linear regression model predicts an average of 81 wins per team with an RSME value of 13 games.

Principal Components Regression

Principal components regression involves developing a principal components model for dimension reduction purposes and using those components that explain the bulk of the variation in the data as regressors in a linear model. Figure 4.1 illustrates the results of the principal components algorithm which concentrated roughly 80% of the variation in the data in the first three components.

The principal components regression model explained less variance with greater uncertainty than any of the other models tested (81 wins per team predicted with RMSE of 14). This is unlikely to be the ideal model for predicting outcomes.

NULL

Model Evaluation

The primary evaluation criteria for the four predictive models is root mean squared error calculated using a holdout set of 20% of the training data. Figure 5.1 shows scatter plots of predicted values and actual values for each model as well as a reference line demonstrating the pattern of a set of perfect predictions. Figure 5.2 ranks each model according to RMSE.

All of the models generally follow similar patterns in Figure 5.1. Principal components regression follows the line of perfect fit more loosely than the rest while the two stepwise models have more attractive distributions. Please find the R code for applying the model to fresh data in Appendix b.

Conclusion

In order to predict the number of wins a team will earn in a season, four OLS regression models were attempted. The first model used heuristic variable selection. The next two used variations of step-wise selection. The last model was a principal components regression model. According to RMSE calculated out of sample, the two step-wise models performed best with bi-directional step-wise variable selection producing the final winning model.

Appendices

Appendix A: Boosted Regression Tree

Regression trees are built by repeatedly partitioning the data according to regression models that minimize sum of squared error terms and averaging the results of the partitioned values. Like the other models, the regression tree predictions average 81 wins, but the root mean squared error is lower at 11 games. Residuals from the resulting model are normally distributed averaging zero, so this model shows promise for improving prediction error!

How does the boosted regression tree stack up against the other four models?

[1] 80.59166
[1] 80.79086

The pattern in Figure 6.1 is similar to that of the simple heuristic model. However, the boosted regression trees demonstrates a significant improvement in RMSE of almost two full games.

Appendix B: Applying the Model Out of Sample

The code below applies the transformations and model algorithms to implement the boosted regression tree model.

Appendix C: Analysis Code

All code for this project can be found on my github page here.

LS0tDQp0aXRsZTogIlBSRURJQ1QgNDExIC0gTW9uZXliYWxsIFByZWRpY3Rpb24gQXNzaWdubWVudCINCmF1dGhvcjogJ0pvc2ggWWF6bWFuJw0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KIyBJbnRyb2R1Y3Rpb24gYW5kIERhdGEgT3ZlcnZpZXcNClRoZSBwdXJwb3NlIG9mIHRoaXMgYXNzaWdubWVudCBpcyB0byBwcmVkaWN0IHRoZSBudW1iZXIgb2YgYmFzZWJhbGwgZ2FtZXMgYSB0ZWFtIHdpbGwgd2luIGJhc2VkIG9uIGEgZGF0YSBzZXQgb2YgaGlzdG9yaWMgcGVyZm9ybWFuY2UgZGF0YSBhbmQgd2lucy4gRmlyc3QsIG1pc3NpbmcgZGF0YSBpcyBhY2NvdW50ZWQgZm9yIGFuZCwgd2hlcmUgcG9zc2libGUsIG51bGwgdmFsdWVzIGFuZCBvdXRsaWVycyBhcmUgaW1wdXRlZCB1c2luZyB2YXJpYWJsZS1zcGVjaWZpYyByZWdyZXNzaW9uIHRyZWUgbW9kZWxzLiBUaGVuIGZvdXIgbGluZWFyIG1vZGVscyBhcmUgYXR0ZW1wdGVkIHVzaW5nIGRpZmZlcmVudCB2YXJpYWJsZSBzZWxlY3Rpb24gdGVjaG5pcXVlcyB3aXRoIHRoZSBwdXJwb3NlIG9mIG1pbmltaXppbmcgcHJlZGljdGlvbiBlcnJvci4gQWRkaXRpb25hbGx5LCBhIGJvb3N0ZWQgcmVncmVzc2lvbiB0cmVlIG1vZGVsIGlzIHRlc3RlZCBmb2xsb3dpbmcgdGhlIGZvdXIgbGluZWFyIG1vZGVscyB0byBhdHRlbXB0IHRvIGltcHJvdmUgcHJlZGljdGl2ZSBhY2N1cmFjeS4gRmluYWxseSwgYFJgIGNvZGUgaXMgcHJvdmlkZWQgdG8gc2NvcmUgYSBmcmVzaCBkYXRhIGZpbGUgYW5kIG1ha2UgcHJlZGljdGlvbnMgZm9yIHRlYW1zIG5vdCBpbmNsdWRlZCBpbiB0aGUgb3JpZ2luYWwgc2FtcGxlLiANCg0KIyMgRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcyBhbmQgUHJlcA0KIyMjIE1pc3NpbmcgRGF0YQ0KVGhlIGRhdGFzZXQgaW5jbHVkZXMgaW5mb3JtYXRpb24gb24gYWJvdXQgMiwyMDAgYmFzYmFsbCB0ZWFtcyBiZXR3ZWVuIDE4NzEgYW5kIDIwMDYuIEFsbCBzdGF0cyBhcmUgYWRqdXN0ZWQgZm9yIGEgMTYyIGdhbWUgc2Vhc29uLiBUd28gdmFyaWFibGVzIChiYXR0ZXJzIGhpdCBieSBwaXRjaCBhbmQgYmFzZXJ1bm5lcnMgY2F1Z2h0IHN0ZWFsaW5nKSB3ZXJlIHJlbW92ZWQgc2luY2UgdGhleSB3ZXJlIG1vcmUgdGhhbiAxNSUgYmxhbmsgKEZpZ3VyZSAwLjEpLiBGb3IgdGhlIHJlbWFpbmluZyB2YXJpYWJsZXMsIG51bGwgdmFsdWVzIGFyZSBpbXB1dGVkIHVzaW5nIHRoZSB2YXJpYWJsZS1zcGVjaWZpYyByZWdyZXNzaW9uIHRyZWVzLiBPbmUgbmV3IHZhcmlhYmxlIGlzIGFsc28gYWRkZWQgdG8gY29uc29saWRhdGUgYWxsIG5vbi1ob21lLXJ1biBoaXQgdmFyaWFibGVzIGludG8gb25lIGNvdW50IG9mIGJhc2VzIGVhcm5lZCBmcm9tIGhpdHMgKGhpdCA9IDEgYmFzZSwgZG91YmxlID0gMiBiYXNlcywgZXRjKS4gDQoNCmBgYHtyLCBlY2hvID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0NCnNldHdkKCdDOi9Vc2Vycy9qb3NoeS9Hb29nbGUgRHJpdmUvbm9ydGh3ZXN0ZXJuL1BSRURJQ1QtNDExL2dlbmVyYWwtZG9jcy9tb25leWJhbGwvJykNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeSh5YXp0aGVtZSkNCmxpYnJhcnkocmVzaGFwZTIpDQpsaWJyYXJ5KGdncmlkZ2VzKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShyYW5kb21Gb3Jlc3QpDQpsaWJyYXJ5KG1vbWVudHMpDQpsaWJyYXJ5KGdyaWRFeHRyYSkNCg0KdHJhaW4gPC0gcmVhZF9jc3YoJ21vbmV5YmFsbC5jc3YnKQ0KdGVzdCA8LSByZWFkX2NzdignbW9uZXliYWxsX3Rlc3QuY3N2JykNCg0KIyMgWW91ciBmaXJzdCBzdGVwIGlzIHRvIHR1cm4gb3V0bGllcnMgaW50byBudWxsIHZhbHVlcyANCiMjIFRoZW4geW91IHdhbnQgdG8gaW1wdXRlIHRob3NlIG51bGxzIHVzaW5nIGEgcmVncmVzc2lvbiB0cmVlIG1vZGVsIHdpdGggYWxsIG90aGVyIHZhcmlhYmxlcyBpbiB0aGUgZGF0YQ0KbnVsbHMgPC0gZGF0YS5mcmFtZShjb2wgPSBhcy5jaGFyYWN0ZXIoY29sbmFtZXModHJhaW4pKSwgDQogICAgICAgICAgICAgICAgICAgIHBjdF9udWxsID0gY29sU3Vtcyhpcy5uYSh0cmFpbikpKjEwMC8oY29sU3Vtcyhpcy5uYSh0cmFpbikpK2NvbFN1bXMoIWlzLm5hKHRyYWluKSkpKSU+JQ0KICBmaWx0ZXIoY29sICE9ICdJTkRFWCcpDQpudWxsX2NvdW50IDwtIGdncGxvdChudWxscywgYWVzKHggPSBjb2wsIHkgPSBwY3RfbnVsbCkpKw0KICBnZW9tX2JhcihmaWxsID0geWF6X2NvbHNbMV0sIHN0YXQgPSAnaWRlbnRpdHknKSsNCiAgY29vcmRfZmxpcCgpKw0KICBsYWJzKHRpdGxlID0gJ0ZpZ3VyZSAwLjE6IERpc3RyaWJ1dGlvbiBvZiBNaXNzaW5nIERhdGEnLA0KICAgICAgIHggPSBlbGVtZW50X2JsYW5rKCksIHkgPSAnUGVyY2VudCBvZiBJbmZvcm1hdGlvbiBNaXNzaW5nJykrDQogIHRoZW1lX3lheigpKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAxNSwgbGluZXR5cGUgPSAnZGFzaGVkJykNCg0KYWRkX3VwX2Jhc2VzIDwtIGZ1bmN0aW9uKGRmKXsNCiAgZGYkdG90YWxfYmFzZXMgPC0gZGYkVEVBTV9CQVRUSU5HX0ggKyAoMiogZGYkVEVBTV9CQVRUSU5HXzJCKSArICgzKiBkZiRURUFNX0JBVFRJTkdfM0IpICsgZGYkVEVBTV9CQVRUSU5HX0JCDQogIHJldHVybihkZiU+JWRwbHlyOjpzZWxlY3QoLVRFQU1fQkFUVElOR19ILCAtVEVBTV9CQVRUSU5HXzJCLCAtVEVBTV9CQVRUSU5HXzNCLCAtVEVBTV9CQVRUSU5HX0JCLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgUmVtb3ZlIHRoZSB2YWx1ZXMgdGhhdCBhcmUgbW9yZSB0aGFuIDE1JSBOVUxMDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgLVRFQU1fQkFUVElOR19IQlAsIC1URUFNX0JBU0VSVU5fQ1MpIyU+JQ0KICAjIFJlcGxhY2UgdGhlIHJlbWFpbmluZyBudW1lcmljIG51bGxzIHdpdGggdGhlIG1lZGlhbiB2YWx1ZSBvZiB0aGUgY29sdW1uDQogICNtdXRhdGVfaWYoaXMubnVtZXJpYywgbmEucm91Z2hmaXgpDQogICkNCn0NCnRyYWluIDwtIGFkZF91cF9iYXNlcyh0cmFpbikNCm51bGxfY291bnQNCmBgYA0KDQojIyMgU2tld2VkIERpc3RyaWJ1dGlvbnMgYW5kIE91dGxpZXJzDQpGb3IgYnVpbGRpbmcgYW4gT0xTIGxpbmVhciBtb2RlbCwgd2UgbmVlZCBkYXRhIHRoYXQgaXMgbm90IHNrZXdlZCBoZWF2aWx5IGJ5IG91dGxpZXJzIG9yIG92ZXJseSBjbHVzdGVyZWQgaW4gYW55IG9uZSBhcmVhLiBUbyByZW1lZHkgc2tldyBwcm9ibGVtcywgd2UgZmlyc3QgaWRlbnRpZnkgb3V0bGllcnMgKDEuNXhJUVIgYWJvdmUgb3IgYmVsb3cgdGhlIGZpcnN0IGFuZCB0aGlyZCBxdWFydGlsZSksIGNvbnZlcnQgdGhvc2UgdmFsdWVzIHRvIG51bGxzLCBhbmQgaW1wdXRlIHRob3NlIG51bGwgdmFsdWVzIHVzaW5nIHJlZ3Jlc3Npb24gdHJlZXMuIA0KYGBge3IsIGVjaG8gPSBGQUxTRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZSA9IEZBTFNFfQ0KY2xlYW5lZF9jb2xzIDwtIGxpc3QoKQ0KZm9yKGMgaW4gY29sbmFtZXModHJhaW5bYygtMSwtMildKSl7DQogIGNvbHVtbiA8LSB0cmFpbiU+JXNlbGVjdF8oY29sID0gYykNCiAgaXFyIDwtIHF1YW50aWxlKGNvbHVtbiRjb2wsIG5hLnJtID0gVClbNF0gLSBxdWFudGlsZShjb2x1bW4kY29sLCBuYS5ybSA9IFQpWzJdDQogIGxvdyA8LSBxdWFudGlsZShjb2x1bW4kY29sLCBuYS5ybSA9IFQpWzJdIC0gaXFyDQogIGhpZ2ggPC0gcXVhbnRpbGUoY29sdW1uJGNvbCwgbmEucm0gPSBUKVs0XSArIGlxcg0KICANCiAgdmFscyA8LSBjKCkNCiAgZm9yKGkgaW4gc2VxKDE6bnJvdyh0cmFpbikpKXsNCiAgICBpZmVsc2UoYmV0d2Vlbihjb2x1bW4kY29sW2ldLCBsb3cgLSAoMS41KmlxciksIGhpZ2ggKyAoMS41KmlxcikpLA0KICAgICAgICAgICB2YWxzW2ldIDwtIGNvbHVtbiRjb2xbaV0sIA0KICAgICAgICAgICBpZmVsc2UoaXMubmEoY29sdW1uJGNvbFtpXSksIHZhbHNbaV0gPC0gTkEsIHZhbHNbaV0gPC0gTkEpKQ0KICB9DQogIA0KICBpZmVsc2UobGVuZ3RoKHZhbHMpID09IG5yb3codHJhaW4pLA0KICAgICAgICAgY2xlYW5lZF9jb2xzW1tjXV0gPC0gdmFscywgDQogICAgICAgICBjbGVhbmVkX2NvbHNbW2NdXSA8LSBjKHZhbHMsTkEpKQ0KfQ0KDQp0cmFpbiA8LSBiaW5kX2NvbHMoSU5ERVggPSB0cmFpbiRJTkRFWCwgVEFSR0VUX1dJTlMgPSB0cmFpbiRUQVJHRVRfV0lOUywgY2xlYW5lZF9jb2xzKQ0KDQpsaWJyYXJ5KG1pY2UpDQp0ZW1wX3RyYWluIDwtIG1pY2UodHJhaW4lPiVkcGx5cjo6c2VsZWN0KC1UQVJHRVRfV0lOUywgLUlOREVYKSwgbWV0aG9kID0gJ2NhcnQnKQ0KdHJhaW4gPC0gY29tcGxldGUodGVtcF90cmFpbiwgMSklPiUNCiAgYmluZF9jb2xzKHRyYWluJT4lZHBseXI6OnNlbGVjdChUQVJHRVRfV0lOUywgSU5ERVgpKQ0KYGBgDQoNCiMjIyBJbml0aWFsIENvcnJlbGF0aW9ucw0KT25lIGxhc3QgZGF0YSBleHBsb3JhdGlvbiBzdGVwIGlzIHRvIGRldGVybWluZSB3aGljaCB2YXJpYWJsZXMgY29ycmVsYXRlIG1vc3Qgc3Ryb25nbHkgd2l0aCBgVEFSR0VUX1dJTlNgLiBObyB2YXJpYWJsZSBhbG9uZSBleHBsYWlucyBhIGdyZWF0IGRlYWwgb2YgdGhlIHZhcmlhbmNlIGluIHRoZSBkYXRhLCBidXQgYHRvdGFsX2Jhc2VzYCBleHBsYWlucyB0aGUgbW9zdCwgZm9sbG93ZWQgYnkgYFRFQU1fUElUQ0hJTkdfQkJgIGFuZCBgVEVBTV9QSVRDSElOR19IUmAgKEZpZ3VyZSAwLjIpLiANCmBgYHtyLCBlY2hvID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0NCmNvcnMgPC0gZGF0YS5mcmFtZShjb3JzID0gY29yKHRyYWluLCBtZXRob2QgPSAncGVhcnNvbicpWydUQVJHRVRfV0lOUycsXV4yLCB2YXJzID0gcm93bmFtZXMoY29yKHRyYWluKSkpDQoNCmdncGxvdChjb3JzJT4lZmlsdGVyKCF2YXJzICVpbiUgYygnVEFSR0VUX1dJTlMnLCdJTkRFWCcpKSwgDQogICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IHJlb3JkZXIodmFycyxjb3JzKSwgeSA9IGNvcnMpKSsNCiAgZ2VvbV9iYXIoc3RhdCA9ICdpZGVudGl0eScsIGZpbGwgPSB5YXpfY29sc1sxXSkrDQogIGNvb3JkX2ZsaXAoKSsNCiAgdGhlbWVfeWF6KCkrDQogIGxhYnModGl0bGUgPSAnRmlndXJlIDAuMjogQ29ycmVsYXRpb24gb2YgVmFyaWFibGVzIHdpdGggV2lucycsDQogICAgICAgeCA9IGVsZW1lbnRfYmxhbmsoKSwgeSA9ICdTcGVhcm1hbiBDb3JyZWxhdGlvbiBDb2VmZmljaWVudCcpDQpgYGANCg0KIyMgTW9kZWwgU2VsZWN0aW9uDQpGb3VyIE9MUyBtb2RlbHMgd2lsbCBiZSBkZXZlbG9wZWQgZm9yIHRoaXMgcHJvamVjdCB1c2luZyBkaWZmZXJlbnQgbWV0aG9kcyBvZiB2YXJpYWJsZSBzZWxlY3Rpb246IG1hbnVhbCwgYmFja3dhcmRzIHN0ZXB3aXNlLCBiaS1kaXJlY3Rpb25hbCBzdGVwd2lzZSwgYW5kIHByaW5jaXBhbCBjb21wb25lbnRzIHJlZ3Jlc3Npb24uIEFkZGl0aW9uYWxseSwgYSBib29zdGVkIHJlZ3Jlc3Npb24gdHJlZSBtb2RlbCB3aWxsIGJlIGRldmVsb3BlZCBmb3IgY29tcGFyaXNvbiB3aXRoIHRoZSBmb3VyIG1haW4gbW9kZWxzLiBUaGUgZXZhbHVhdGlvbiBjcml0ZXJpYSBpcyByb290IG1lYW4gc3F1YXJlZCBlcnJvciAoUk1TRSkgY2FsY3VsYXRlZCBvbiBhIGhvbGRvdXQgc2FtcGxlIG9mIHRoZSB0cmFpbmluZyBkYXRhLiBUaGUgYmVzdCBtb2RlbCB3aWxsIGJlIHRoZSBvbmUgdGhhdCBtaW5pbWl6ZXMgUk1TRS4gQSBtb2RlbCB0aGF0IHNpbXBseSBhcHBsaWVzIHRoZSBhdmVyYWdlIHdpbiBjb3VudCB0byBldmVyeSB0ZWFtIGhhcyBhIHByZWRpY3RpdmUgZXJyb3IgcmF0ZSBvZiAxNSBnYW1lcywgc28gdGhlIG1vZGVsIGRldmVsb3BlZCBmb3IgdGhpcyByZXBvcnQgc2hvdWxkIHJlcHJlc2VudCBhIHNpZ25pZmljYW50IGltcHJvdmVtZW50IHRvIGJlIGNvbnNpZGVyZWQgc3VjY2Vzc2Z1bC4NCg0KYGBge3IsIGVjaG8gPSBGQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZyA9IEZBTFNFfQ0KbWV0aG9kIDwtIGMoKQ0Kcm1zZSA8LSBjKCkNCmBgYA0KDQojIyMgU2ltcGxlIEhldXJpc3RpYyBPTFMgUmVncmVzc2lvbg0KQSBzaW1wbGUgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgdXNpbmcgc29tZSBvZiB0aGUgdmFyaWFibGVzIHRoYXQgY29ycmVsYXRlIHdpdGggd2luLWNvdW50IGluY2x1ZGVzIHRvdGFsIGJhc2VzIGVhcm5lZCwgZmllbGRpbmcgZXJyb3JzLCBhbmQgc3RvbGVuIGJhc2VzLiBUaGUgbW9kZWwgb25seSBleHBsYWlucyAyMiUgb2YgdGhlIHZhcmlhbmNlIGluIHRoZSB0cmFpbmluZyBkYXRhLCBidXQgdGhlIG1vZGVsIGRvZXMgcHJlZGljdCBhbiBhdmVyYWdlIG9mIDgxIHdpbnMgd2l0aCBSTVNFIG9mIDE0IGdhbWVzIC0gb25seSBvbmUgZ2FtZSBiZXR0ZXIgdGhhbiBhcHBseWluZyB0aGUgYXZlcmFnZSBtb2RlbC4NCmBgYHtyLCBlY2hvID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0NCm1ldGhvZFsxXSA8LSAnU2ltcGxlIEhldXJpc3RpYycNCnRyYWluLnRyYWluIDwtIHNhbXBsZV9mcmFjKHRyYWluLCAuOCkNCnRyYWluLnRlc3QgPC0gdHJhaW4lPiVmaWx0ZXIoIUlOREVYICVpbiUgdHJhaW4udHJhaW4pI1shaXMuaW5maW5pdGUocm93U3Vtcyh0cmFpbikpLCdJTkRFWCddKQ0Kc2ltcGxlX21vZCA8LSBsbShUQVJHRVRfV0lOU350b3RhbF9iYXNlcyArIFRFQU1fUElUQ0hJTkdfQkIgKyBURUFNX1BJVENISU5HX0hSLCMgKyBURUFNX1BJVENISU5HX0hSLA0KICAgICAgICAgICAgICAgICBkYXRhID0gdHJhaW4udHJhaW4pDQpzdW1tYXJ5KHNpbXBsZV9tb2QpDQpwcmVkcyA8LSBwcmVkaWN0KHNpbXBsZV9tb2QsIHRyYWluLnRlc3QsIHR5cGUgPSAncmVzcG9uc2UnKQ0Kc2ltcGxlX3ByZWRzIDwtIGRhdGEuZnJhbWUoDQogIHdpbnMgPSB0cmFpbi50ZXN0JFRBUkdFVF9XSU5TLA0KICBwcmVkcw0KICApJT4lIA0KICBtdXRhdGUocHJlZC5lcnJvciA9IHdpbnMtIHByZWRzKQ0KDQpybXNlWzFdIDwtIHNxcnQobWVhbihzaW1wbGVfcHJlZHMkcHJlZC5lcnJvcl4yLCBuYS5ybSA9IFQpKQ0KDQpyZXNpZF9wbG90X3MgPC0gZ2dwbG90KGRhdGEuZnJhbWUocmVzaWQgPSBzaW1wbGVfbW9kJHJlc2lkdWFscywNCiAgICAgICAgICAgICAgICAgIGZpdHRlZCA9IHNpbXBsZV9tb2QkZml0dGVkLnZhbHVlcyksDQogICAgICAgYWVzKHggPSBmaXR0ZWQsIHkgPSByZXNpZCkpKw0KICBnZW9tX3BvaW50KGFscGhhID0gLjUsIGNvbG9yID0geWF6X2NvbHNbM10pKw0KICB0aGVtZV95YXooKSsNCiAgbGFicyh0aXRsZSA9ICdGaWd1cmUgMS4xOiBNb2RlbCBSZXNpZHVhbHMnLA0KICAgICAgIHN1YnRpdGxlID0gJ2xtKFRBUkdFVF9XSU5TfnRvdGFsX2Jhc2VzICsgVEVBTV9GSUVMRElOR19FICsgVEVBTV9CQVNFUlVOX1NCKScsDQogICAgICAgeCA9ICdGaXR0ZWQgVmFsdWVzJywgeSA9ICdSZXNpZHVhbHMnKSsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAnZGFzaGVkJywgDQogICAgICAgICAgICAgY29sb3IgPSB5YXpfY29sc1sxXSwgc2l6ZSA9IDEpKw0KICB5bGltKC03NSw3NSkNCnJlc2lkX2hpc3RfcyA8LSBnZ3Bsb3QoZGF0YS5mcmFtZShyZXMgPSBzaW1wbGVfbW9kJHJlc2lkdWFscyksDQogICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IHJlcykpKw0KICBnZW9tX2RlbnNpdHkoZmlsbCA9IHlhel9jb2xzWzFdKSsNCiAgY29vcmRfZmxpcCgpKw0KICBsYWJzKHkgPSAnRnJlcXVlbmN5JywgeCA9ICdSZXNpZHVhbHMnLCB0aXRsZSA9ICcgJywgc3VidGl0bGUgPSAnICcpKw0KICB0aGVtZV95YXooKSsNCiAgeGxpbSgtNzUsNzUpDQpncmlkLmFycmFuZ2UoDQogIHJlc2lkX3Bsb3RfcywgcmVzaWRfaGlzdF9zLA0KICB3aWR0aHMgPSBjKDMsMSksDQogIG5yb3cgPSAxDQopDQoNCmBgYA0KDQoNCiMjIyBCYWNrd2FyZHMgVmFyaWFibGUgU2VsZWN0aW9uDQpCYWNrd2FyZHMgdmFyaWFibGUgc2VsZWN0aW9uIHRlY2huaXF1ZXMgdXNlIEFrYWlrZSBJbmZvcm1hdGlvbiBDcml0ZXJpb24gKEFJQykgdG8gc2VsZWN0IHRoZSBtb2RlbCB0aGF0IGJlc3QgZXhwbGFpbnMgdGhlIHZhcmlhbmNlIGluIHRoZSBleGlzdGluZyBkYXRhIHdpdGhvdXQgb3ZlcmZpdHRpbmcgdGhlIG1vZGVsLiBUaGUgbWV0aG9kIGluaXRpYWxseSB0cmFpbnMgYSBtb2RlbCB1c2luZyBhbGwgYXZhaWxhYmxlIHZhcmlhYmxlcyBhbmQgc2VxdWVudGlhbGx5IHJlbW92ZXMgdmFyaWFibGVzIGJhc2VkIG9uIHRoZWlyIGltcGFjdCBvbiBBSUMuIEZvciBlYWNoIG51bWJlciBvZiB2YXJpYWJsZXMgaW4gYSBtb2RlbCwgdGhlIGJhY2t3YXJkcyBzZWxlY3Rpb24gYWxnb3JpdGhtIHJldHVybnMgdGhlIGJlc3QgdmFyaWFibGVzIHRvIGluY2x1ZGUgaW4gdGhlIG1vZGVsLiBJbiBvdXQgb2Ygc2FtcGxlIHRlc3RpbmcsIG1hcmdpbmFsIGltcHJvdmVtZW50cyB0byBSTVNFIGRpbWluaXNoIGFmdGVyIDYgdmFyaWFibGVzIGFyZSBpbmNsdWRlZCBpbiB0aGUgbW9kZWwgKEZpZ3VyZSAyLjEpLg0KYGBge3IsIGVjaG8gPSBGQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZyA9IEZBTFNFfQ0KbGlicmFyeShsZWFwcykNCm1ldGhvZFsyXSA8LSAnQmFja3dhcmQgU3RlcHdpc2UnDQptb2RlbC5iYWNrIDwtIHJlZ3N1YnNldHMoVEFSR0VUX1dJTlN+LiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHRyYWluLnRyYWluLA0KICAgICAgICAgICAgICAgICAgICAgICAgIG52bWF4ID0gbmNvbCh0cmFpbi50cmFpbiktMSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gJ2JhY2t3YXJkJykNCm1vZC5zdW0gPC0gc3VtbWFyeShtb2RlbC5iYWNrKQ0KDQpybXNlX3RlbXAgPC0gYygpDQpmb3JtdWxhZSA8LSBjKCkNCmZvcihpIGluIHNlcSgxOihucm93KG1vZC5zdW0kd2hpY2gpKSkpew0KICB2YXJzIDwtIGMoKQ0KICBpZmVsc2UobW9kLnN1bSR3aGljaFtpLCBjKCd0b3RhbF9iYXNlcycpXSA9PSBULA0KICAgICAgICAgdmFyc1tsZW5ndGgodmFycykrMV0gPC0gJ3RvdGFsX2Jhc2VzJywgdmFyc1tsZW5ndGgodmFycykrMV0gPC0gJyAnKQ0KICBpZmVsc2UobW9kLnN1bSR3aGljaFtpLCBjKCdURUFNX0JBVFRJTkdfSFInKV0gPT0gVCwNCiAgICAgICAgIHZhcnNbbGVuZ3RoKHZhcnMpKzFdIDwtICdURUFNX0JBVFRJTkdfSFInLCB2YXJzW2xlbmd0aCh2YXJzKSsxXSA8LSAnICcpDQogIGlmZWxzZShtb2Quc3VtJHdoaWNoW2ksIGMoJ1RFQU1fQkFUVElOR19TTycpXSA9PSBULA0KICAgICAgICAgdmFyc1tsZW5ndGgodmFycykrMV0gPC0gJ1RFQU1fQkFUVElOR19TTycsIHZhcnNbbGVuZ3RoKHZhcnMpKzFdIDwtICcgJykNCiAgaWZlbHNlKG1vZC5zdW0kd2hpY2hbaSwgYygnVEVBTV9CQVNFUlVOX1NCJyldID09IFQsDQogICAgICAgICB2YXJzW2xlbmd0aCh2YXJzKSsxXSA8LSAnVEVBTV9CQVNFUlVOX1NCJywgdmFyc1tsZW5ndGgodmFycykrMV0gPC0gJyAnKQ0KICBpZmVsc2UobW9kLnN1bSR3aGljaFtpLCBjKCdURUFNX1BJVENISU5HX0gnKV0gPT0gVCwNCiAgICAgICAgIHZhcnNbbGVuZ3RoKHZhcnMpKzFdIDwtICdURUFNX1BJVENISU5HX0gnLCB2YXJzW2xlbmd0aCh2YXJzKSsxXSA8LSAnICcpDQogIGlmZWxzZShtb2Quc3VtJHdoaWNoW2ksIGMoJ1RFQU1fUElUQ0hJTkdfSFInKV0gPT0gVCwNCiAgICAgICAgIHZhcnNbbGVuZ3RoKHZhcnMpKzFdIDwtICdURUFNX1BJVENISU5HX0hSJyx2YXJzW2xlbmd0aCh2YXJzKSsxXSA8LSAnICcpDQogIGlmZWxzZShtb2Quc3VtJHdoaWNoW2ksIGMoJ1RFQU1fUElUQ0hJTkdfQkInKV0gPT0gVCwNCiAgICAgICAgIHZhcnNbbGVuZ3RoKHZhcnMpKzFdIDwtICdURUFNX1BJVENISU5HX0JCJywgdmFyc1tsZW5ndGgodmFycykrMV0gPC0gJyAnKQ0KICBpZmVsc2UobW9kLnN1bSR3aGljaFtpLCBjKCdURUFNX1BJVENISU5HX1NPJyldID09IFQsDQogICAgICAgICB2YXJzW2xlbmd0aCh2YXJzKSsxXSA8LSAnVEVBTV9QSVRDSElOR19TTycsIHZhcnNbbGVuZ3RoKHZhcnMpKzFdIDwtICcgJykNCiAgaWZlbHNlKG1vZC5zdW0kd2hpY2hbaSwgYygnVEVBTV9GSUVMRElOR19FJyldID09IFQsDQogICAgICAgICB2YXJzW2xlbmd0aCh2YXJzKSsxXSA8LSAnVEVBTV9GSUVMRElOR19FJywgdmFyc1tsZW5ndGgodmFycykrMV0gPC0gJyAnKQ0KICBpZmVsc2UobW9kLnN1bSR3aGljaFtpLCBjKCdURUFNX0ZJRUxESU5HX0RQJyldID09IFQsDQogICAgICAgICB2YXJzW2xlbmd0aCh2YXJzKSsxXSA8LSAnVEVBTV9GSUVMRElOR19EUCcsIHZhcnNbbGVuZ3RoKHZhcnMpKzFdIDwtICcgJykNCiAgZm9ybXVsYSA8LSBwYXJzZSh0ZXh0ID0gcGFzdGUwKCdsbShUQVJHRVRfV0lOUyB+ICcscGFzdGUodmFyc1t2YXJzICE9ICcgJ10sIGNvbGxhcHNlID0gJysnKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcsIGRhdGEgPSB0cmFpbi50cmFpblshaXMuaW5maW5pdGUocm93U3Vtcyh0cmFpbi50cmFpbikpLF0pJykpDQogIGZvcm11bGFlW2ldIDwtIGZvcm11bGENCiAgcm1zZV90ZW1wW2ldIDwtIHNxcnQoDQogICAgbWVhbigNCiAgICAgICh0cmFpbi50ZXN0JFRBUkdFVF9XSU5TIC0gcHJlZGljdCgNCiAgICAgICAgZXZhbCgNCiAgICAgICAgICBmb3JtdWxhDQogICAgICAgICAgKSwgbmV3ZGF0YSA9IHRyYWluLnRlc3RbIWlzLmluZmluaXRlKHJvd1N1bXModHJhaW4udGVzdCkpLF0NCiAgICAgICAgKSleMixuYS5ybSA9IFQpDQogICAgKQ0KfQ0KDQpnZ3Bsb3QoZGF0YS5mcmFtZShudmFycyA9IHNlcSgxOihuY29sKHRyYWluKS0xKSksIHJtc2VfdGVtcCksDQogICAgICAgYWVzKHggPSBudmFycywgeSA9IHJtc2VfdGVtcCkpKw0KICBnZW9tX3BvaW50KGNvbG9yID0geWF6X2NvbHNbMV0sIHNpemUgPSAxLjUpKw0KICBnZW9tX2xpbmUoY29sb3IgPSB5YXpfY29sc1sxXSwgbGluZXR5cGUgPSAnZGFzaGVkJykrDQogIGxhYnModGl0bGUgPSAnRmlndXJlIDIuMTogUk1TRSBCeSBOdW1iZXIgb2YgVmFyaWFibGVzIEluY2x1ZGVkJywNCiAgICAgICB4ID0gJ051bWJlciBvZiBWYXJpYWJsZXMnLA0KICAgICAgIHkgPSAnUk1TRScpKw0KICB0aGVtZV95YXooKQ0KYGBgDQoNClNpbWlsYXIgdG8gdGhlIHNpbXBsZSBoZXVyaXN0aWMgbW9kZWwsIHJlc2lkdWFscyBhcHBlYXIgdG8gYmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgd2l0aCBhIGJpdCBtb3JlIHVuY2VydGFpbnR5IG9uIHRoZSBlbmRzIG9mIHRoZSBkaXN0cmlidXRpb24gb2YgcHJlZGljdGVkIHZhbHVlcy4gVGhlIHNpeC12YXJpYWJsZSBtb2RlbCBwcmVkaWN0cyBhbiBhdmVyYWdlIG9mIDgxIHdpbnMgcGVyIHRlYW0gd2l0aCBhbiBSU01FIG9mIDEzIGdhbWVzLiAgDQpgYGB7ciwgZWNobyA9IEZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nID0gRkFMU0V9DQojIyBUaGUgYmVzdCBtb2RlbCBieSBSTVNFIGlzIHRoZSBvbmUgd2l0aCA4IHZhcmlhYmxlcw0KYmVzdF9vbHMgPC0gZXZhbChwYXJzZSh0ZXh0ID0gZm9ybXVsYWVbNl0pKQ0KDQpzdW0ubW9kLmJhY2sgPC0gc3VtbWFyeShiZXN0X29scykNCmJhY2tfcHJlZHMgPC0gZGF0YS5mcmFtZSh3aW5zID0gdHJhaW4udGVzdCRUQVJHRVRfV0lOUywgDQogICAgICAgICAgICAgICAgICAgICAgICBwcmVkcyA9IHByZWRpY3QoYmVzdF9vbHMsIG5ld2RhdGEgPSB0cmFpbi50ZXN0KSklPiUNCiAgbXV0YXRlKHByZWQuZXJyb3IgPSB3aW5zIC0gcHJlZHMpDQoNCnJtc2VbMl0gPC0gc3FydChtZWFuKGJhY2tfcHJlZHMkcHJlZC5lcnJvcl4yLCBuYS5ybSA9IFQpKQ0KDQpyZXNpZF9wbG90IDwtIGdncGxvdChkYXRhLmZyYW1lKGZpdCA9IGJlc3Rfb2xzJGZpdHRlZC52YWx1ZXMsIHJlcyA9IGJlc3Rfb2xzJHJlc2lkdWFscyksDQogICAgICAgYWVzKHggPSBmaXQsIHkgPSByZXMpKSsNCiAgZ2VvbV9wb2ludChhbHBoYSA9IC41LCBjb2xvciA9IHlhel9jb2xzWzNdKSsNCiAgbGFicyh0aXRsZSA9ICdGaWd1cmUgMi4yOiBNb2RlbCBSZXNpZHVhbHMnLA0KICAgICAgIHN1YnRpdGxlID0gJ2xtKFRBUkdFVF9XSU5TfnRvdGFsX2Jhc2VzKScsDQogICAgICAgeCA9ICdGaXR0ZWQgVmFsdWVzJywgeSA9ICdSZXNpZHVhbHMnKSsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAnZGFzaGVkJywgDQogICAgICAgICAgICAgY29sb3IgPSB5YXpfY29sc1sxXSwgc2l6ZSA9IDEpKw0KICB0aGVtZV95YXooKSsNCiAgeWxpbSgtNzUsNzUpDQoNCnJlc2lkX2hpc3QgPC0gZ2dwbG90KGRhdGEuZnJhbWUocmVzID0gYmVzdF9vbHMkcmVzaWR1YWxzKSwNCiAgICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gcmVzKSkrDQogIGdlb21fZGVuc2l0eShmaWxsID0geWF6X2NvbHNbMV0pKw0KICBjb29yZF9mbGlwKCkrDQogIGxhYnMoeSA9ICdGcmVxdWVuY3knLCB4ID0gJ1Jlc2lkdWFscycsIHRpdGxlID0gJ1xuJykrIywgc3VidGl0bGUgPSAnXG4nKSsNCiAgdGhlbWVfeWF6KCkrDQogIHhsaW0oLTc1LDc1KQ0KZ3JpZC5hcnJhbmdlKA0KICByZXNpZF9wbG90LCByZXNpZF9oaXN0LA0KICB3aWR0aHMgPSBjKDMsMSksDQogIG5yb3cgPSAxDQopDQpgYGANCg0KIyMjIEJpLURpcmVjdGlvbmFsIFZhcmlhYmxlIFNlbGVjdGlvbg0KQmktZGlyZWNpdG9uYWwgdGVjaG5pcXVlcyB3b3JrIHNpbWlsYXJseSB0byBiYWNrd2FyZHMgdmFyaWFibGUgc2VsZWN0aW9uLCBidXQgYXQgZWFjaCBpdGVyYXRpb24gb2YgbW9kZWwgYnVpbGRpbmcsIHZhcmlhYmxlcyBjYW4gYmUgYWRkZWQgb3IgcmVtb3ZlZC4gQWdhaW4sIGZvciBlYWNoIG51bWJlciBvZiB2YXJpYWJsZXMgaW4gYSBtb2RlbCwgdGhlIGFsZ29yaXRobSByZXR1cm5zIHRoZSBiZXN0IHZhcmlhYmxlcyB0byBpbmNsdWRlLiBJbiBvdXQgb2Ygc2FtcGxlIHRlc3RpbmcsIG1hcmdpbmFsIGltcHJvdmVtZW50cyB0byBSTVNFIGFnYWluIGRpbWluaXNoIHdoZW4gNiB2YXJpYWJsZXMgYXJlIGluY2x1ZGVkIGluIHRoZSBtb2RlbCAoRmlndXJlIDMuMSkuDQpgYGB7ciwgZWNobyA9IEZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nID0gRkFMU0V9DQptZXRob2RbM10gPC0gJ0JpLURpcmVjdGlvbmFsIFN0ZXB3aXNlJw0KbW9kZWwuYmkgPC0gcmVnc3Vic2V0cyhUQVJHRVRfV0lOU34uLCANCiAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gdHJhaW4udHJhaW4sIA0KICAgICAgICAgICAgICAgICAgICAgICAgIG52bWF4ID0gbmNvbCh0cmFpbi50cmFpbiktMSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gJ3NlcXJlcCcpDQptb2Quc3VtLmJpIDwtIHN1bW1hcnkobW9kZWwuYmkpDQoNCnJtc2VfdGVtcCA8LSBjKCkNCmZvcm11bGFlIDwtIGMoKQ0KZm9yKGkgaW4gc2VxKDE6KG5yb3cobW9kLnN1bSR3aGljaCkpKSl7DQogIHZhcnMgPC0gYygpDQogIGlmZWxzZShtb2Quc3VtLmJpJHdoaWNoW2ksIGMoJ3RvdGFsX2Jhc2VzJyldID09IFQsDQogICAgICAgICB2YXJzW2xlbmd0aCh2YXJzKSsxXSA8LSAndG90YWxfYmFzZXMnLCB2YXJzW2xlbmd0aCh2YXJzKSsxXSA8LSAnICcpDQogIGlmZWxzZShtb2Quc3VtLmJpJHdoaWNoW2ksIGMoJ1RFQU1fQkFUVElOR19IUicpXSA9PSBULA0KICAgICAgICAgdmFyc1tsZW5ndGgodmFycykrMV0gPC0gJ1RFQU1fQkFUVElOR19IUicsIHZhcnNbbGVuZ3RoKHZhcnMpKzFdIDwtICcgJykNCiAgaWZlbHNlKG1vZC5zdW0uYmkkd2hpY2hbaSwgYygnVEVBTV9CQVRUSU5HX1NPJyldID09IFQsDQogICAgICAgICB2YXJzW2xlbmd0aCh2YXJzKSsxXSA8LSAnVEVBTV9CQVRUSU5HX1NPJywgdmFyc1tsZW5ndGgodmFycykrMV0gPC0gJyAnKQ0KICBpZmVsc2UobW9kLnN1bS5iaSR3aGljaFtpLCBjKCdURUFNX0JBU0VSVU5fU0InKV0gPT0gVCwNCiAgICAgICAgIHZhcnNbbGVuZ3RoKHZhcnMpKzFdIDwtICdURUFNX0JBU0VSVU5fU0InLCB2YXJzW2xlbmd0aCh2YXJzKSsxXSA8LSAnICcpDQogIGlmZWxzZShtb2Quc3VtLmJpJHdoaWNoW2ksIGMoJ1RFQU1fUElUQ0hJTkdfSCcpXSA9PSBULA0KICAgICAgICAgdmFyc1tsZW5ndGgodmFycykrMV0gPC0gJ1RFQU1fUElUQ0hJTkdfSCcsIHZhcnNbbGVuZ3RoKHZhcnMpKzFdIDwtICcgJykNCiAgaWZlbHNlKG1vZC5zdW0uYmkkd2hpY2hbaSwgYygnVEVBTV9QSVRDSElOR19IUicpXSA9PSBULA0KICAgICAgICAgdmFyc1tsZW5ndGgodmFycykrMV0gPC0gJ1RFQU1fUElUQ0hJTkdfSFInLHZhcnNbbGVuZ3RoKHZhcnMpKzFdIDwtICcgJykNCiAgaWZlbHNlKG1vZC5zdW0uYmkkd2hpY2hbaSwgYygnVEVBTV9QSVRDSElOR19CQicpXSA9PSBULA0KICAgICAgICAgdmFyc1tsZW5ndGgodmFycykrMV0gPC0gJ1RFQU1fUElUQ0hJTkdfQkInLCB2YXJzW2xlbmd0aCh2YXJzKSsxXSA8LSAnICcpDQogIGlmZWxzZShtb2Quc3VtLmJpJHdoaWNoW2ksIGMoJ1RFQU1fUElUQ0hJTkdfU08nKV0gPT0gVCwNCiAgICAgICAgIHZhcnNbbGVuZ3RoKHZhcnMpKzFdIDwtICdURUFNX1BJVENISU5HX1NPJywgdmFyc1tsZW5ndGgodmFycykrMV0gPC0gJyAnKQ0KICBpZmVsc2UobW9kLnN1bS5iaSR3aGljaFtpLCBjKCdURUFNX0ZJRUxESU5HX0UnKV0gPT0gVCwNCiAgICAgICAgIHZhcnNbbGVuZ3RoKHZhcnMpKzFdIDwtICdURUFNX0ZJRUxESU5HX0UnLCB2YXJzW2xlbmd0aCh2YXJzKSsxXSA8LSAnICcpDQogIGlmZWxzZShtb2Quc3VtLmJpJHdoaWNoW2ksIGMoJ1RFQU1fRklFTERJTkdfRFAnKV0gPT0gVCwNCiAgICAgICAgIHZhcnNbbGVuZ3RoKHZhcnMpKzFdIDwtICdURUFNX0ZJRUxESU5HX0RQJywgdmFyc1tsZW5ndGgodmFycykrMV0gPC0gJyAnKQ0KICBmb3JtdWxhIDwtIHBhcnNlKHRleHQgPSBwYXN0ZTAoJ2xtKFRBUkdFVF9XSU5TIH4gJyxwYXN0ZSh2YXJzW3ZhcnMgIT0gJyAnXSwgY29sbGFwc2UgPSAnKycpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJywgZGF0YSA9IHRyYWluLnRyYWluWyFpcy5pbmZpbml0ZShyb3dTdW1zKHRyYWluLnRyYWluKSksXSknKSkNCiAgZm9ybXVsYWVbaV0gPC0gZm9ybXVsYQ0KICBybXNlX3RlbXBbaV0gPC0gc3FydCgNCiAgICBtZWFuKA0KICAgICAgKHRyYWluLnRlc3QkVEFSR0VUX1dJTlMgLSBwcmVkaWN0KA0KICAgICAgICBldmFsKA0KICAgICAgICAgIGZvcm11bGENCiAgICAgICAgICApLCBuZXdkYXRhID0gdHJhaW4udGVzdFshaXMuaW5maW5pdGUocm93U3Vtcyh0cmFpbi50ZXN0KSksXQ0KICAgICAgICApKV4yLG5hLnJtID0gVCkNCiAgICApDQp9DQoNCmdncGxvdChkYXRhLmZyYW1lKG52YXJzID0gc2VxKDE6KG5jb2wodHJhaW4pLTEpKSwgcm1zZV90ZW1wKSwNCiAgICAgICBhZXMoeCA9IG52YXJzLCB5ID0gcm1zZV90ZW1wKSkrDQogIGdlb21fcG9pbnQoY29sb3IgPSB5YXpfY29sc1sxXSwgc2l6ZSA9IDEuNSkrDQogIGdlb21fbGluZShjb2xvciA9IHlhel9jb2xzWzFdLCBsaW5ldHlwZSA9ICdkYXNoZWQnKSsNCiAgbGFicyh0aXRsZSA9ICdGaWd1cmUgMy4xOiBSTVNFIEJ5IE51bWJlciBvZiBWYXJpYWJsZXMgSW5jbHVkZWQnLA0KICAgICAgIHggPSAnTnVtYmVyIG9mIFZhcmlhYmxlcycsDQogICAgICAgeSA9ICdSTVNFJykrDQogIHRoZW1lX3lheigpDQpgYGANCg0KTW9kZWwgcmVzaWR1YWxzIGFwcGVhciB0byBiZSBub3JtYWxseSBkaXN0cmlidXRlZCB3aXRoIGEgYml0IG1vcmUgdW5jZXJ0YWludHkgb24gdGhlIGVuZHMgb2YgdGhlIGRpc3RyaWJ1dGlvbiBvZiBwcmVkaWN0ZWQgdmFsdWVzLiBTaW1pbGFyIHRvIGJhY2t3YXJkcyB2YXJpYWJsZSBzZWxlY3Rpb24sIHRoZSBzaXgtdmFyaWFibGUgYmktZGlyZWN0aW9uYWwgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgcHJlZGljdHMgYW4gYXZlcmFnZSBvZiA4MSB3aW5zIHBlciB0ZWFtIHdpdGggYW4gUlNNRSB2YWx1ZSBvZiAxMyBnYW1lcy4gIA0KYGBge3IsIGVjaG8gPSBGQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZyA9IEZBTFNFfQ0KIyMgVGhlIGJlc3QgbW9kZWwgYnkgUk1TRSBpcyB0aGUgb25lIHdpdGggOCB2YXJpYWJsZXMNCmJlc3Rfb2xzLmJvdGggPC0gZXZhbChwYXJzZSh0ZXh0ID0gZm9ybXVsYWVbNl0pKQ0KDQpzdW0ubW9kLmJvdGggPC0gc3VtbWFyeShiZXN0X29scy5ib3RoKQ0KYm90aF9wcmVkcyA8LSBkYXRhLmZyYW1lKHdpbnMgPSB0cmFpbi50ZXN0JFRBUkdFVF9XSU5TLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHByZWRzID0gcHJlZGljdChiZXN0X29scy5ib3RoLCBuZXdkYXRhID0gdHJhaW4udGVzdCkpJT4lDQogIG11dGF0ZShwcmVkLmVycm9yID0gd2lucyAtIHByZWRzKQ0KDQpyZXNpZF9wbG90IDwtIGdncGxvdChkYXRhLmZyYW1lKGZpdCA9IGJlc3Rfb2xzLmJvdGgkZml0dGVkLnZhbHVlcywgcmVzID0gYmVzdF9vbHMkcmVzaWR1YWxzKSwNCiAgICAgICBhZXMoeCA9IGZpdCwgeSA9IHJlcykpKw0KICBnZW9tX3BvaW50KGFscGhhID0gLjUsIGNvbG9yID0geWF6X2NvbHNbM10pKw0KICBsYWJzKHRpdGxlID0gJ0ZpZ3VyZSAzLjI6IE1vZGVsIFJlc2lkdWFscycsDQogICAgICAgc3VidGl0bGUgPSAnbG0oVEFSR0VUX1dJTlN+dG90YWxfYmFzZXMpJywNCiAgICAgICB4ID0gJ0ZpdHRlZCBWYWx1ZXMnLCB5ID0gJ1Jlc2lkdWFscycpKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICdkYXNoZWQnLCANCiAgICAgICAgICAgICBjb2xvciA9IHlhel9jb2xzWzFdLCBzaXplID0gMSkrDQogIHRoZW1lX3lheigpKw0KICB5bGltKC03NSw3NSkNCg0KcmVzaWRfaGlzdCA8LSBnZ3Bsb3QoZGF0YS5mcmFtZShyZXMgPSBiZXN0X29scyRyZXNpZHVhbHMpLA0KICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSByZXMpKSsNCiAgZ2VvbV9kZW5zaXR5KGZpbGwgPSB5YXpfY29sc1sxXSkrDQogIGNvb3JkX2ZsaXAoKSsNCiAgbGFicyh5ID0gJ0ZyZXF1ZW5jeScsIHggPSAnUmVzaWR1YWxzJywgdGl0bGUgPSAnXG4nKSsjLCBzdWJ0aXRsZSA9ICdcbicpKw0KICB0aGVtZV95YXooKSsNCiAgeGxpbSgtNzUsNzUpDQoNCnJtc2VbM10gPC0gc3FydChtZWFuKGJvdGhfcHJlZHMkcHJlZC5lcnJvcl4yLCBuYS5ybSA9IFQpKQ0KDQpncmlkLmFycmFuZ2UoDQogIHJlc2lkX3Bsb3QsIHJlc2lkX2hpc3QsDQogIHdpZHRocyA9IGMoMywxKSwNCiAgbnJvdyA9IDENCikNCmBgYA0KDQojIyBQcmluY2lwYWwgQ29tcG9uZW50cyBSZWdyZXNzaW9uDQpQcmluY2lwYWwgY29tcG9uZW50cyByZWdyZXNzaW9uIGludm9sdmVzIGRldmVsb3BpbmcgYSBwcmluY2lwYWwgY29tcG9uZW50cyBtb2RlbCBmb3IgZGltZW5zaW9uIHJlZHVjdGlvbiBwdXJwb3NlcyBhbmQgdXNpbmcgdGhvc2UgY29tcG9uZW50cyB0aGF0IGV4cGxhaW4gdGhlIGJ1bGsgb2YgdGhlIHZhcmlhdGlvbiBpbiB0aGUgZGF0YSBhcyByZWdyZXNzb3JzIGluIGEgbGluZWFyIG1vZGVsLiBGaWd1cmUgNC4xIGlsbHVzdHJhdGVzIHRoZSByZXN1bHRzIG9mIHRoZSBwcmluY2lwYWwgY29tcG9uZW50cyBhbGdvcml0aG0gd2hpY2ggY29uY2VudHJhdGVkIHJvdWdobHkgODAlIG9mIHRoZSB2YXJpYXRpb24gaW4gdGhlIGRhdGEgaW4gdGhlIGZpcnN0IHRocmVlIGNvbXBvbmVudHMuICANCmBgYHtyLCBlY2hvID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0NCm1ldGhvZFs0XSA8LSAnUHJpbmNpcGFsIENvbXBvbmVudHMgUmVncmVzc2lvbicNCnBjYS5tb2QgPC0gcHJpbmNvbXAodHJhaW4udHJhaW4lPiVkcGx5cjo6c2VsZWN0KC1JTkRFWCwgLVRBUkdFVF9XSU5TKSwgY29yID0gVFJVRSkNCnNjcmVlLnZhbHMgPC0gZGF0YS5mcmFtZSh2YWxzID0gKHBjYS5tb2Qkc2Rldl4yKS9zdW0ocGNhLm1vZCRzZGV2XjIpKSU+JQ0KICBtdXRhdGUoY29tcCA9IHNlcSgxLGxlbmd0aChwY2EubW9kJHNkZXYpKSwNCiAgICAgICAgIHZhcmlhbmNlLmV4cGxhaW5lZCA9IGN1bXN1bSh2YWxzKSkNCg0KZ2dwbG90KHNjcmVlLnZhbHMsIGFlcyh4ID0gY29tcCwgeSA9IHZhcmlhbmNlLmV4cGxhaW5lZCkpKw0KICBnZW9tX2xpbmUobGluZXR5cGUgPSAnZGFzaGVkJykrDQogIGdlb21fcG9pbnQoY29sb3IgPSB5YXpfY29sc1sxXSwgc2l6ZSA9IDQpKw0KICBsYWJzKHkgPSAnUHJvcG9ydGlvbiBvZiBWYXJpYW5jZSBFeHBsYWluZWQnLA0KICAgICAgIHggPSAnQ29tcG9uZW50JywNCiAgICAgICB0aXRsZSA9ICdGaWcgNC4xOiBQQ0EgU2NyZWUgUGxvdCcpKw0KICB0aGVtZV95YXooYmFzZV9zaXplID0gMTApKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAuNzUpDQpgYGANCg0KVGhlIHByaW5jaXBhbCBjb21wb25lbnRzIHJlZ3Jlc3Npb24gbW9kZWwgZXhwbGFpbmVkIGxlc3MgdmFyaWFuY2Ugd2l0aCBncmVhdGVyIHVuY2VydGFpbnR5IHRoYW4gYW55IG9mIHRoZSBvdGhlciBtb2RlbHMgdGVzdGVkICg4MSB3aW5zIHBlciB0ZWFtIHByZWRpY3RlZCB3aXRoIFJNU0Ugb2YgMTQpLiBUaGlzIGlzIHVubGlrZWx5IHRvIGJlIHRoZSBpZGVhbCBtb2RlbCBmb3IgcHJlZGljdGluZyBvdXRjb21lcy4NCmBgYHtyLCBlY2hvID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0NCnBjYS5kZi50cmFpbiA8LSBwY2EubW9kJHNjb3JlcyU+JQ0KICBkYXRhLmZyYW1lKCklPiUNCiAgYmluZF9jb2xzKHRyYWluLnRyYWluKQ0KcGNhLm1vZC52YWxpZCA8LSBwcmluY29tcCh0cmFpbi50ZXN0JT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZHBseXI6OnNlbGVjdCgtSU5ERVgsIC1UQVJHRVRfV0lOUyklPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZSgpJT4lZGF0YS5mcmFtZSgpKSRzY29yZXMlPiUNCiAgZGF0YS5mcmFtZSgpJT4lDQogIGJpbmRfY29scyh0cmFpbi50ZXN0KQ0KcGNyIDwtIGxtKFRBUkdFVF9XSU5TIH4gQ29tcC4xICsgQ29tcC4yICsgQ29tcC4zLCANCiAgICAgICAgICAgICAgICBwY2EuZGYudHJhaW4pDQpuYW1lcyhwY2EubW9kLnZhbGlkJHNjb3JlcykNCiMgc3VtbWFyeShwY3IpDQpwY3JfcHJlZHMgPC0gYmluZF9jb2xzKA0KICB0cmFpbi50ZXN0JT4lZHBseXI6OnNlbGVjdCh3aW5zID0gVEFSR0VUX1dJTlMpLCANCiAgZGF0YS5mcmFtZShwcmVkcyA9IHByZWRpY3QocGNyLCBwY2EubW9kLnZhbGlkKSkNCiAgKSU+JQ0KICBtdXRhdGUocHJlZC5lcnJvciA9IHdpbnMgLSBwcmVkcykNCg0Kcm1zZVs0XSA8LSBzcXJ0KG1lYW4ocGNyX3ByZWRzJHByZWQuZXJyb3JeMikpDQpwY3JfcGxvdCA8LSBnZ3Bsb3QocGNyX3ByZWRzLCBhZXMoeCA9IHByZWRzLCB5ID0gcHJlZC5lcnJvcikpKw0KICBnZW9tX3BvaW50KGFscGhhID0gLjUsIGNvbG9yID0geWF6X2NvbHNbM10pKw0KICBsYWJzKHRpdGxlID0gJ0ZpZ3VyZSA0LjI6IE1vZGVsIFJlc2lkdWFscycsDQogICAgICAgc3VidGl0bGUgPSAnQm9vc3RlZCBSZWdyZXNzaW9uIFRyZWUnLA0KICAgICAgIHggPSAnRml0dGVkIFZhbHVlcycsIHkgPSAnUmVzaWR1YWxzJykrDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gJ2Rhc2hlZCcsIA0KICAgICAgICAgICAgIGNvbG9yID0geWF6X2NvbHNbMV0sIHNpemUgPSAxKSsNCiAgdGhlbWVfeWF6KCkrDQogIHlsaW0oLTc1LDc1KQ0KDQpwY3JfaGlzdCA8LSBnZ3Bsb3QocGNyX3ByZWRzLCBhZXMoeCA9IHByZWQuZXJyb3IpKSsNCiAgZ2VvbV9kZW5zaXR5KGZpbGwgPSB5YXpfY29sc1sxXSkrDQogIGNvb3JkX2ZsaXAoKSsNCiAgbGFicyh5ID0gJ0ZyZXF1ZW5jeScsIHggPSAnUmVzaWR1YWxzJywgdGl0bGUgPSAnXG4nKSsjLCBzdWJ0aXRsZSA9ICdcbicpKw0KICB0aGVtZV95YXooKSsNCiAgeGxpbSgtNzUsNzUpDQoNCmdyaWQuYXJyYW5nZSgNCiAgcGNyX3Bsb3QsIHBjcl9oaXN0LA0KICB3aWR0aHMgPSBjKDMsMSksDQogIG5yb3cgPSAxDQopDQpgYGANCg0KIyMgTW9kZWwgRXZhbHVhdGlvbg0KVGhlIHByaW1hcnkgZXZhbHVhdGlvbiBjcml0ZXJpYSBmb3IgdGhlIGZvdXIgcHJlZGljdGl2ZSBtb2RlbHMgaXMgcm9vdCBtZWFuIHNxdWFyZWQgZXJyb3IgY2FsY3VsYXRlZCB1c2luZyBhIGhvbGRvdXQgc2V0IG9mIDIwJSBvZiB0aGUgdHJhaW5pbmcgZGF0YS4gRmlndXJlIDUuMSBzaG93cyBzY2F0dGVyIHBsb3RzIG9mIHByZWRpY3RlZCB2YWx1ZXMgYW5kIGFjdHVhbCB2YWx1ZXMgZm9yIGVhY2ggbW9kZWwgYXMgd2VsbCBhcyBhIHJlZmVyZW5jZSBsaW5lIGRlbW9uc3RyYXRpbmcgdGhlIHBhdHRlcm4gb2YgYSBzZXQgb2YgcGVyZmVjdCBwcmVkaWN0aW9ucy4gRmlndXJlIDUuMiByYW5rcyBlYWNoIG1vZGVsIGFjY29yZGluZyB0byBSTVNFLg0KDQpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTYsIGVjaG8gPSBGQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZyA9IEZBTFNFfQ0KYWxsX3ByZWRzIDwtIGJpbmRfcm93cygNCiAgc2ltcGxlX3ByZWRzJT4lbXV0YXRlKG1ldGhvZCA9IG1ldGhvZFsxXSksDQogIGJhY2tfcHJlZHMlPiVtdXRhdGUobWV0aG9kID0gbWV0aG9kWzJdKSwNCiAgYm90aF9wcmVkcyU+JW11dGF0ZShtZXRob2QgPSBtZXRob2RbM10pLA0KICBwY3JfcHJlZHMlPiVtdXRhdGUobWV0aG9kID0gbWV0aG9kWzRdKQ0KKQ0KDQpvb3NfdmFsaWQgPC0gZ2dwbG90KGFsbF9wcmVkcywgYWVzKHggPSBwcmVkcywgeSA9IHdpbnMpKSsNCiAgZ2VvbV9wb2ludChzaXplID0gMS41LCBjb2xvciA9IHlhel9jb2xzWzFdLCBhbHBoYSA9IC41KSsNCiAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gMCwgc2xvcGUgPSAxKSsNCiAgeGxpbSgwLDEyNSkrDQogIGZhY2V0X3dyYXAofm1ldGhvZCkrDQogIGxhYnModGl0bGUgPSAnRmlndXJlIDUuMTogT3V0IG9mIFNhbXBsZSBWYWxpZGF0aW9uIG9mIE1vZGVsIFByZWRpY3Rpb25zJywNCiAgICAgICB4ID0gJ1ByZWRpY3RlZCBWYWx1ZScsIHkgPSAnQWN0dWFsIFdpbnMgYnkgVGVhbSBhbmQgWWVhcicpKw0KICB0aGVtZV95YXooKQ0KDQpybXNlX2JhciA8LSBnZ3Bsb3QoZGF0YS5mcmFtZShtZXRob2QsIHJtc2UpLCBhZXMoeCA9IHJlb3JkZXIobWV0aG9kLCBybXNlKSwgeT0gcm1zZSkpKw0KICBnZW9tX2JhcihzdGF0ID0gJ2lkZW50aXR5JywgZmlsbCA9IHlhel9jb2xzWzFdKSsNCiAgbGFicyh5ID0gJ1JNU0UnLCB4ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgIHRpdGxlID0gJzUuMjogUk1TRSBieSBNZXRob2QnKSsNCiAgdGhlbWVfeWF6KCkrDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKQ0KDQpncmlkLmFycmFuZ2Uob29zX3ZhbGlkLCBybXNlX2JhciwgbnJvdyA9IDEsIHdpZHRocyA9IGMoMywxKSkgIA0KYGBgDQoNCkFsbCBvZiB0aGUgbW9kZWxzIGdlbmVyYWxseSBmb2xsb3cgc2ltaWxhciBwYXR0ZXJucyBpbiBGaWd1cmUgNS4xLiBQcmluY2lwYWwgY29tcG9uZW50cyByZWdyZXNzaW9uIGZvbGxvd3MgdGhlIGxpbmUgb2YgcGVyZmVjdCBmaXQgbW9yZSBsb29zZWx5IHRoYW4gdGhlIHJlc3Qgd2hpbGUgdGhlIHR3byBzdGVwd2lzZSBtb2RlbHMgaGF2ZSBtb3JlIGF0dHJhY3RpdmUgZGlzdHJpYnV0aW9ucy4gUGxlYXNlIGZpbmQgdGhlIGBSYCBjb2RlIGZvciBhcHBseWluZyB0aGUgbW9kZWwgdG8gZnJlc2ggZGF0YSBpbiBBcHBlbmRpeCBiLg0KDQojIyBDb25jbHVzaW9uDQpJbiBvcmRlciB0byBwcmVkaWN0IHRoZSBudW1iZXIgb2Ygd2lucyBhIHRlYW0gd2lsbCBlYXJuIGluIGEgc2Vhc29uLCBmb3VyIE9MUyByZWdyZXNzaW9uIG1vZGVscyB3ZXJlIGF0dGVtcHRlZC4gVGhlIGZpcnN0IG1vZGVsIHVzZWQgaGV1cmlzdGljIHZhcmlhYmxlIHNlbGVjdGlvbi4gVGhlIG5leHQgdHdvIHVzZWQgdmFyaWF0aW9ucyBvZiBzdGVwLXdpc2Ugc2VsZWN0aW9uLiBUaGUgbGFzdCBtb2RlbCB3YXMgYSBwcmluY2lwYWwgY29tcG9uZW50cyByZWdyZXNzaW9uIG1vZGVsLiBBY2NvcmRpbmcgdG8gUk1TRSBjYWxjdWxhdGVkIG91dCBvZiBzYW1wbGUsIHRoZSB0d28gc3RlcC13aXNlIG1vZGVscyBwZXJmb3JtZWQgYmVzdCB3aXRoIGJpLWRpcmVjdGlvbmFsIHN0ZXAtd2lzZSB2YXJpYWJsZSBzZWxlY3Rpb24gcHJvZHVjaW5nIHRoZSBmaW5hbCB3aW5uaW5nIG1vZGVsLiANCg0KIyBBcHBlbmRpY2VzDQojIyBBcHBlbmRpeCBBOiBCb29zdGVkIFJlZ3Jlc3Npb24gVHJlZQ0KUmVncmVzc2lvbiB0cmVlcyBhcmUgYnVpbHQgYnkgcmVwZWF0ZWRseSBwYXJ0aXRpb25pbmcgdGhlIGRhdGEgYWNjb3JkaW5nIHRvIHJlZ3Jlc3Npb24gbW9kZWxzIHRoYXQgbWluaW1pemUgc3VtIG9mIHNxdWFyZWQgZXJyb3IgdGVybXMgYW5kIGF2ZXJhZ2luZyB0aGUgcmVzdWx0cyBvZiB0aGUgcGFydGl0aW9uZWQgdmFsdWVzLiBMaWtlIHRoZSBvdGhlciBtb2RlbHMsIHRoZSByZWdyZXNzaW9uIHRyZWUgcHJlZGljdGlvbnMgYXZlcmFnZSA4MSB3aW5zLCBidXQgdGhlIHJvb3QgbWVhbiBzcXVhcmVkIGVycm9yIGlzIGxvd2VyIGF0IDExIGdhbWVzLiBSZXNpZHVhbHMgZnJvbSB0aGUgcmVzdWx0aW5nIG1vZGVsIGFyZSBub3JtYWxseSBkaXN0cmlidXRlZCBhdmVyYWdpbmcgemVybywgc28gdGhpcyBtb2RlbCBzaG93cyBwcm9taXNlIGZvciBpbXByb3ZpbmcgcHJlZGljdGlvbiBlcnJvciENCmBgYHtyLCBlY2hvID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0NCm1ldGhvZFs1XSA8LSAnUmVncmVzc2lvbiBUcmVlJw0KDQpsaWJyYXJ5KGdibSkNCmJvb3N0LndpbnMgPC0gZ2JtKFRBUkdFVF9XSU5TIH4gLiwgdHJhaW4udHJhaW4lPiVkcGx5cjo6c2VsZWN0KC1JTkRFWCksIA0KICAgICAgICAgICAgICAgICAgZGlzdHJpYnV0aW9uID0gJ2dhdXNzaWFuJywgbi50cmVlcz01MDAwLCBpbnRlcmFjdGlvbi5kZXB0aD02KQ0KDQpwcmVkcyA8LSBwcmVkaWN0KGJvb3N0LndpbnMsIHRyYWluLnRlc3QsIG4udHJlZXM9NTAwMCwgdHlwZSA9ICdyZXNwb25zZScpDQp0cmVlX3ByZWRzIDwtIGRhdGEuZnJhbWUoDQogIHdpbnMgPSB0cmFpbi50ZXN0JFRBUkdFVF9XSU5TLA0KICBwcmVkcw0KICApJT4lIA0KICBtdXRhdGUocHJlZC5lcnJvciA9IHdpbnMtIHByZWRzKQ0KDQpybXNlWzVdIDwtIHNxcnQobWVhbih0cmVlX3ByZWRzJHByZWQuZXJyb3JeMiwgbmEucm0gPSBUKSkNCg0KYm9vc3RfcGxvdCA8LSBnZ3Bsb3QodHJlZV9wcmVkcywgYWVzKHggPSBwcmVkcywgeSA9IHByZWQuZXJyb3IpKSsNCiAgZ2VvbV9wb2ludChhbHBoYSA9IC41LCBjb2xvciA9IHlhel9jb2xzWzNdKSsNCiAgbGFicyh0aXRsZSA9ICdGaWd1cmUgMy4yOiBNb2RlbCBSZXNpZHVhbHMnLA0KICAgICAgIHN1YnRpdGxlID0gJ0Jvb3N0ZWQgUmVncmVzc2lvbiBUcmVlJywNCiAgICAgICB4ID0gJ0ZpdHRlZCBWYWx1ZXMnLCB5ID0gJ1Jlc2lkdWFscycpKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICdkYXNoZWQnLCANCiAgICAgICAgICAgICBjb2xvciA9IHlhel9jb2xzWzFdLCBzaXplID0gMSkrDQogIHRoZW1lX3lheigpKw0KICB5bGltKC03NSw3NSkNCg0KYm9vc3RfaGlzdCA8LSBnZ3Bsb3QodHJlZV9wcmVkcywgYWVzKHggPSBwcmVkLmVycm9yKSkrDQogIGdlb21fZGVuc2l0eShmaWxsID0geWF6X2NvbHNbMV0pKw0KICBjb29yZF9mbGlwKCkrDQogIGxhYnMoeSA9ICdGcmVxdWVuY3knLCB4ID0gJ1Jlc2lkdWFscycsIHRpdGxlID0gJ1xuJykrIywgc3VidGl0bGUgPSAnXG4nKSsNCiAgdGhlbWVfeWF6KCkrDQogIHhsaW0oLTc1LDc1KQ0KZ3JpZC5hcnJhbmdlKA0KICBib29zdF9wbG90LCBib29zdF9oaXN0LA0KICB3aWR0aHMgPSBjKDMsMSksDQogIG5yb3cgPSAxDQopDQpgYGANCg0KSG93IGRvZXMgdGhlIGJvb3N0ZWQgcmVncmVzc2lvbiB0cmVlIHN0YWNrIHVwIGFnYWluc3QgdGhlIG90aGVyIGZvdXIgbW9kZWxzPyAgICANCg0KYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD02LCBlY2hvID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0NCmFsbF9wcmVkcyA8LSBiaW5kX3Jvd3MoDQogIHNpbXBsZV9wcmVkcyU+JW11dGF0ZShtZXRob2QgPSBtZXRob2RbMV0pLA0KICBiYWNrX3ByZWRzJT4lbXV0YXRlKG1ldGhvZCA9IG1ldGhvZFsyXSksDQogIGJvdGhfcHJlZHMlPiVtdXRhdGUobWV0aG9kID0gbWV0aG9kWzNdKSwNCiAgcGNyX3ByZWRzJT4lbXV0YXRlKG1ldGhvZCA9IG1ldGhvZFs0XSksDQogIHRyZWVfcHJlZHMlPiVtdXRhdGUobWV0aG9kID0gbWV0aG9kWzVdKQ0KKQ0KbWVhbih0cmVlX3ByZWRzJHByZWRzKQ0KbWVhbih0cmVlX3ByZWRzJHdpbnMpDQpvb3NfdmFsaWQgPC0gZ2dwbG90KGFsbF9wcmVkcywgYWVzKHggPSBwcmVkcywgeSA9IHdpbnMpKSsNCiAgZ2VvbV9wb2ludChzaXplID0gMS41LCBjb2xvciA9IHlhel9jb2xzWzFdLCBhbHBoYSA9IC41KSsNCiAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gMCwgc2xvcGUgPSAxKSsNCiAgeGxpbSgwLDEyNSkrDQogIGZhY2V0X3dyYXAofm1ldGhvZCkrDQogIGxhYnModGl0bGUgPSAnRmlndXJlIDYuMTogT3V0IG9mIFNhbXBsZSBWYWxpZGF0aW9uIG9mIE1vZGVsIFByZWRpY3Rpb25zJywNCiAgICAgICB4ID0gJ1ByZWRpY3RlZCBWYWx1ZScsIHkgPSAnQWN0dWFsIFdpbnMgYnkgVGVhbSBhbmQgWWVhcicpKw0KICB0aGVtZV95YXooKQ0KDQpybXNlX2JhciA8LSBnZ3Bsb3QoZGF0YS5mcmFtZShtZXRob2QsIHJtc2UpLCBhZXMoeCA9IHJlb3JkZXIobWV0aG9kLCBybXNlKSwgeT0gcm1zZSkpKw0KICBnZW9tX2JhcihzdGF0ID0gJ2lkZW50aXR5JywgZmlsbCA9IHlhel9jb2xzWzFdKSsNCiAgbGFicyh5ID0gJ1JNU0UnLCB4ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgIHRpdGxlID0gJzYuMjogUk1TRSBieSBNZXRob2QnKSsNCiAgdGhlbWVfeWF6KCkrDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKQ0KDQpncmlkLmFycmFuZ2Uob29zX3ZhbGlkLCBybXNlX2JhciwgbnJvdyA9IDEsIHdpZHRocyA9IGMoMywxKSkNCmBgYA0KDQpUaGUgcGF0dGVybiBpbiBGaWd1cmUgNi4xIGlzIHNpbWlsYXIgdG8gdGhhdCBvZiB0aGUgc2ltcGxlIGhldXJpc3RpYyBtb2RlbC4gSG93ZXZlciwgdGhlIGJvb3N0ZWQgcmVncmVzc2lvbiB0cmVlcyBkZW1vbnN0cmF0ZXMgYSBzaWduaWZpY2FudCBpbXByb3ZlbWVudCBpbiBSTVNFIG9mIGFsbW9zdCB0d28gZnVsbCBnYW1lcy4NCg0KIyMgQXBwZW5kaXggQjogQXBwbHlpbmcgdGhlIE1vZGVsIE91dCBvZiBTYW1wbGUNClRoZSBjb2RlIGJlbG93IGFwcGxpZXMgdGhlIHRyYW5zZm9ybWF0aW9ucyBhbmQgbW9kZWwgYWxnb3JpdGhtcyB0byBpbXBsZW1lbnQgdGhlIGJvb3N0ZWQgcmVncmVzc2lvbiB0cmVlIG1vZGVsLiANCmBgYHtyfQ0KbGlicmFyeShtaWNlKQ0KDQphcHBseV9zY29yZXMgPC0gZnVuY3Rpb24oZGYpew0KICANCiAgdGVtcF9kYXRhIDwtIGFkZF91cF9iYXNlcyhkZikNCiAgDQogIGNsZWFuZWRfY29scyA8LSBsaXN0KCkNCiAgZm9yKGMgaW4gY29sbmFtZXModGVtcF9kYXRhW2MoLTEpXSkpew0KICAgIGNvbHVtbiA8LSB0cmFpbiU+JXNlbGVjdF8oY29sID0gYykNCiAgICBpcXIgPC0gcXVhbnRpbGUoY29sdW1uJGNvbCwgbmEucm0gPSBUKVs0XSAtIHF1YW50aWxlKGNvbHVtbiRjb2wsIG5hLnJtID0gVClbMl0NCiAgICBsb3cgPC0gcXVhbnRpbGUoY29sdW1uJGNvbCwgbmEucm0gPSBUKVsyXSAtIGlxcg0KICAgIGhpZ2ggPC0gcXVhbnRpbGUoY29sdW1uJGNvbCwgbmEucm0gPSBUKVs0XSArIGlxcg0KICAgIA0KICAgIHZhbHMgPC0gYygpDQogICAgZm9yKGkgaW4gc2VxKDE6bnJvdyh0ZW1wX2RhdGEpKSl7DQogICAgICBpZmVsc2UoYmV0d2Vlbihjb2x1bW4kY29sW2ldLCBsb3cgLSAoMS41KmlxciksIGhpZ2ggKyAoMS41KmlxcikpLA0KICAgICAgICAgICAgIHZhbHNbaV0gPC0gY29sdW1uJGNvbFtpXSwgDQogICAgICAgICAgICAgaWZlbHNlKGlzLm5hKGNvbHVtbiRjb2xbaV0pLCB2YWxzW2ldIDwtIE5BLCB2YWxzW2ldIDwtIE5BKSkNCiAgICB9DQogICAgDQogICAgaWZlbHNlKGxlbmd0aCh2YWxzKSA9PSBucm93KHRlbXBfZGF0YSksDQogICAgICAgICAgIGNsZWFuZWRfY29sc1tbY11dIDwtIHZhbHMsIA0KICAgICAgICAgICBjbGVhbmVkX2NvbHNbW2NdXSA8LSBjKHZhbHMsTkEpKQ0KICB9DQoNCiAgdGVtcF9kYXRhMiA8LSBiaW5kX2NvbHMoSU5ERVggPSB0ZW1wX2RhdGEkSU5ERVgsIGNsZWFuZWRfY29scykNCiAgDQogIHRlbXBfZGF0YTMgPC0gbWljZSh0ZW1wX2RhdGEyLCBtZXRob2QgPSAnY2FydCcpDQogIHRlbXBfZGF0YTQgPC0gY29tcGxldGUodGVtcF9kYXRhMywgMSkNCiAgcHJlZHMgPC0gYmluZF9jb2xzKA0KICAgIHRlbXBfZGF0YTQsIGRhdGEuZnJhbWUoUF9UQVJHRVRfV0lOUyA9IHByZWRpY3QoYm9vc3Qud2lucywgdGVtcF9kYXRhNCwgbi50cmVlcz01MDAwLCB0eXBlID0gJ3Jlc3BvbnNlJykpDQogICAgKSU+JQ0KICAgIGRwbHlyOjpzZWxlY3QoSU5ERVgsIFBfVEFSR0VUX1dJTlMpDQogIHJldHVybihwcmVkcykNCn0NCg0KZmluYWxfcHJlZHMgPC0gYXBwbHlfc2NvcmVzKHRlc3QpICANCg0Kd3JpdGUuY3N2KHggPSBmaW5hbF9wcmVkcywgIGZpbGUgPSAneWF6bWFuX21vbmV5YmFsbF90ZXN0LmNzdicpDQpgYGANCg0KIyMgQXBwZW5kaXggQzogQW5hbHlzaXMgQ29kZQ0KQWxsIGNvZGUgZm9yIHRoaXMgcHJvamVjdCBjYW4gYmUgZm91bmQgb24gbXkgZ2l0aHViIHBhZ2UgW2hlcmVdKGh0dHBzOi8vZ2l0aHViLmNvbS9qb3NoeWF6bWFuL25vcnRod2VzdGVybi9ibG9iL21hc3Rlci9wcmVkaWN0LTQxMS9tb25leWJhbGwvbW9uZXliYWxsX2Fzc2lnbm1lbnRfY29kZS5SbWQpLg0K