1 Introduction and Background

The dataset I am using for my analysis is an extensive collection of metrics for every NBA player’s game-by-game performance across the 2022-2023 playoff season. It was published on the open-source data science platform Kaggle (link can be found in references section below). The original source for the data’s accuracy can be confirmed at Basketball-reference.com, a well-established database for enthusiasts of the sport. All statistical analysis will be conducted via the programming language R.

As for the dataset’s contents, it is composed of all 217 players who played some amount of time in the 2022-2023 postseason. It contained 30 variables, however only 10 played a role in my analysis, so I created a reduced dataset which only contained the information pertinent to my research question. An explanation and breakdown of the names and data types for the variables used in my analysis is below:

  • “Player” = player’s name = character

  • “Pos” = player’s position on the court or in starting lineup = character

  • “Tm” = team player plays for = character

  • “Age” = player’s age = integer

  • “PTS” = player’s points per game average = double

  • “AST” = player’s assists per game average = double

  • “TRB” = player’s rebounds per game average = double

  • “STL” = player’s steals per game average = double

  • “BLK” = player’s blocks per game average = double

  • “MP” = player’s minutes per game average = double

Using this dataset, I will be exploring the relationship that a player’s impact on the game (measured via their average points, rebounds, assists, steals and blocks) and circumstance (age, position and team playing for) has on their playing time (measured by per minute averages). I will refer to the five primary metrics of productivity (points, rebounds, assists, steals and blocks) as the “five standard statistics” of basketball.

I have previously analyzed this dataset and found there to be a strong, positive and simply linear relationship between a player’s average scoring output and his average playing time. Through linear regression modeling and bootstrap sampling, I came to the conclusion that for every additional point a player averages, his playing time increases by about 1.4 minutes per game. And more broadly, I can say that a scoring increase of one point per game will result in an increase of about 1.3 to 1.55 extra minutes per game 95% of the time.

While I initially chose to focus in on the correlation between points per game and minutes per game due to the overwhelming evidence that a significant relationship between the two existed (available in references for further detail), I now plan to expand upon the foundings of my previous reporting. I will create multi-variate models to determine how changes in a player’s other metrics, as well as their age, position and team situation impact their average amount of playing time.

Given the sufficient size of my dataset, over 200 players from the 16 teams which participated in the postseason, and the reliability of its sourcing, I am confident that I will be able to come to empirically justified conclusions.

2 Multiple Linear Regression (MLR) Approach

The first modeling strategy I employed to understand what factors correlated with an NBA player’s average playing time was a multiple linear regression approach. Setting minutes played as my response and my dataset’s other six quantitative variables as the predictors, I ran a linear model which we will refer to as the “Base Regression Model.”

2.1 Base Model

The findings of this regression model were definitive. It reported that per-game averages in the points, rebounds and steals categories absolutely had a statistically significant correlation with how much playing time a player got. Alternatively, it was found that not only did a player’s age and per-game averages in blocks and assists not have a correlatory impact on his playing time, but it was not particularly close, especially for assists and blocks per game.

All that being said, I did not want to draw a definitive conclusion solely from this base regression model, so I performed variable screening and investigated for other noticeable weaknesses in the model’s efficiency.

Base_Regression_Model = lm(MP ~ Age + PTS + AST + TRB + STL + BLK, data = Reduced_Playoff_Data)
summary(Base_Regression_Model)
 # Base model: (p < 2.2e-16, F = 241.7 (6, 210) Adjusted R^2 = 0.8699
 # Significant variables per base model:
  # PTS, TRB, STL, 
  # PTS -> intercept = 0.84028, p < 2e-16
  # TRB -> intercept = 1.20050, p = 1.50e-11
  # STL -> intercept = 5.80856, p = 1.74e-08
kable(summary(Base_Regression_Model)$coef, digits = 4, align = 'c', caption ="Coefficients for the Base Regression Model")
Coefficients for the Base Regression Model
Estimate Std. Error t value Pr(>|t|)
(Intercept) 2.2897 2.0721 1.1050 0.2704
Age 0.1002 0.0752 1.3312 0.1846
PTS 0.8403 0.0806 10.4226 0.0000
AST -0.0107 0.2951 -0.0363 0.9711
TRB 1.2005 0.1681 7.1400 0.0000
STL 5.8086 0.9906 5.8636 0.0000
BLK -0.0235 0.9071 -0.0259 0.9794

2.2 Stepwise Regression Models

Via R, I performed three types of model modification; forward selection, backward selection and stepwise selection. Forward selection consists of there being no predictors in the model, and then the most contributive predictors being iteratively added until there is no more statistically significant improvement to be made. Backward selection takes the opposite approach, beginning with a complete linear model (our base model in this case), and iteratively removing the least contributive predictors until all that are left are statistically significant. Lastly, stepwise selection uses a process that combines elements of both. This process was done to simplify our regression model and avoid the risk of overfitting that comes with a higher amount of predictor variables.

All three processes resulted in the same end model; all listing PTS, TRB and STL as the predictors which had a significant impact on a player’s given minutes per game. All three models also cited a significantly strong coefficient of determination, expressing that about 87% of variation in a player’s minutes per game comes from his metrics in those three categories (points, rebounds and steals).

# Main takeaway: P value, F stat and adjusted R^2 for total models were identical for all three stepwise regression models, this is not very surprising due to how strong the p values were in the original base model.
# All three models also confirm our original model's findings which are that points, rebounds and assists have a significant relationship with a player's average minutes per game. All three models list the same intercepts and p values for all three of those variables, as well as the same intercept for the model of 4.95295 (p < 2e-16).


# Build a null (intercept-only) model using the same data and response
Null_Model = lm(MP ~ 1, data = Reduced_Playoff_Data)

Full_Model = Base_Regression_Model

# 1) Forward Selection
  # Forward Model: (p < 2.2e-16, F = 485.5 (3, 213), adjusted R^2 = 0.8706)
  # Significant variables per Forward Selection model:
    # PTS, TRB, STL
    # PTS -> intercept = 0.83937, p < 2e-16
    # TRB -> intercept = 1.20058, p = 1.15e-14
    # STL -> intercept = 5.85402, p = 3.49e-10

  Forward_Model = step(
    object = Null_Model,
    scope = list(lower = formula(Null_Model), upper = formula(Full_Model)),
    direction = "forward",
    trace = 1
  )
  summary(Forward_Model)

# 2) Backward Selection
  # Backward Model: (p < 2.2e-16, F = 485.5 (3, 213), adjusted R^2 = 0.8706)
  # Significant variables per Backward Selection model:
    # PTS, TRB, STL
    # PTS -> intercept = 0.83937, p < 2e-16
    # TRB -> intercept = 1.20058, p = 1.15e-14
    # STL -> intercept = 5.85402, p = 3.49e-10
  Backward_Model = step(
    object = Full_Model,
    direction = "backward",
    trace = 1
  )
  summary(Backward_Model)
  
  
# 3) Stepwise Selection
  # Stepwise Model: (p < 2.2e-16, F = 485.5 (3, 213), adjusted R^2 = 0.8706)
  # Significant variables per Stepwise Selection model:
    # PTS, TRB, STL
    # PTS -> intercept = 0.83937, p < 2e-16
    # TRB -> intercept = 1.20058, p = 1.15e-14
    # STL -> intercept = 5.85402, p = 3.49e-10
  Stepwise_Model = step(
    object = Null_Model,
    scope = list(lower = formula(Null_Model), upper = formula(Full_Model)),
    direction = "both",
    trace = 1
  )
  summary(Stepwise_Model)
(kable(summary(Forward_Model)$coef, digits = 5, caption ="Coefficients for all Three Stepwise Regression Models"))
Coefficients for all Three Stepwise Regression Models
Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.95295 0.51403 9.63559 0
PTS 0.83937 0.06584 12.74912 0
TRB 1.20058 0.14456 8.30534 0
STL 5.85402 0.88897 6.58518 0

2.3 Correlation Concerns (Base Model)

To ensure that multicollinearity was not a harmful factor in the base model, and hence also the stepwise model(s), I investigated using a correlation matrix and a VIF bar graph.

As per the correlation matrix, there is a strong correlation between AST and PTS (r ~ 0.819). However, assists per game do not report to be a significant statistic relevant to predicting a player’s given playing time in any of our regression models, therefore any theoretical threat of multicollinearity posed by assists per game is not realized.

Looking at the VIF (variance inflation factor) chart, the only potential concern at face value appears to be that of points per game, which is hovering slighly above a value of 4. Given that the only other variables in all of our models that were deemed significant (total rebounds and steals per game) are both rated below a value of 3, we can reasonably assess that an out-of-control coefficient variance is not a great concern.

ggpairs(Quantitative_Predictor_Variables, title = "Correlation Matrix for Age and Player Stats") + theme(plot.title = element_text(hjust = 0.5))

barplot(vif(Base_Regression_Model), main = "VIF Values", horiz = FALSE, col = "steelblue")

2.4 Further Residual Analysis (Base Model)

Given that there was no major multicollinearity issues present in our base model, I then moved forward and performed residual analysis on both the base model (seen below) and the stepwise model. Since a more parsimonious model is more ideal for prediction and estimation, moving forward I will be utilizing the stepwise model to draw ultimate takeaways and conclusions.

# Histogram
Base_Model_Residuals = resid(Base_Regression_Model)
Base_Model_Predicted_Values = predict(Base_Regression_Model)
hist(Base_Model_Residuals,
     main = "Base Model Errors",
     xlab = "Model Residuals")

# Scatterplot
plot(Base_Model_Predicted_Values, Base_Model_Residuals,
     main = "Base Model - Residual Analysis Scatterplot",
     xlab = "Predicted minutes per game",
     ylab = "Model Error (mins per game)")
abline(h=0)

# Residual Mean Calculation
mean(Base_Model_Residuals)

# QQ Plot 
qqnorm(Base_Model_Residuals, main = "QQ Residuals", ylab = "Standardized Residuals")
qqline(Base_Model_Residuals)

# Scale-Location Plot
plot(Base_Regression_Model, which = 3)

# Residuals-Leverage Plot
plot(Base_Regression_Model, which = 5)

2.5 Further Residual Analysis (Stepwise Models)

The findings of our residual analysis are not great. The residuals do not appear normally distributed, as per the histogram and QQ plot, nor do they appear to have a constant variance, as per the scatterplot and scale-location plot. The residual-leverage plot also appears to show anywhere from 2 to 5 observations that are both high leverage and high residual, which can significantly impact a model’s efficacy.

# Histogram
Forward_Model_Residuals = resid(Forward_Model)
Forward_Model_Predicted_Values = predict(Forward_Model)
hist(Forward_Model_Residuals,
     main = "Stepwise Models Errors",
     xlab = "Model Residuals")

# Scatterplot
plot(Forward_Model_Predicted_Values, Forward_Model_Residuals,
     main = "Stepwise Models - Residual Analysis Scatterplot",
     xlab = "Predicted minutes per game",
     ylab = "Model Error (mins per game)")
abline(h=0)

# Residual Mean Calculation
mean(Forward_Model_Residuals)

# QQ Plot 
qqnorm(Forward_Model_Residuals, main = "QQ Residuals", ylab = "Standardized Residuals")
qqline(Forward_Model_Residuals)

# Scale-Location Plot
plot(Forward_Model, which = 3)

# Residuals-Leverage Plot
plot(Forward_Model, which = 5)

2.6 MLR analysis with Box-Cox transformation

Given the results of the residual analysis on my stepwise model, I then performed a box-cox transformation of my model, with a lamba value of 1.05, to help mitigate the errors that inconsistent residual variance and lack of normal distribution might bring. The results were once again definitive, and in alignment with the base model and the pre-transformation stepwise models; that being that points per game, rebounds per game and steals per game were ALL highly significant factors in estimating a player’s minutes per game.

 # Had 1 observation where our response variable MP was = 0, which does not work with Box-Cox transformation.
library(MASS)

Reduced_Playoff_Data2 = Reduced_Playoff_Data[Reduced_Playoff_Data$MP > 0, ]

Forward_Model2 = lm(MP ~ PTS + TRB + STL, data = Reduced_Playoff_Data2)

Boxcox = boxcox(Forward_Model2, lambda = seq(-2, 2, 0.1))

lambda = 1.05

# Modify MP variable in dataset with lamba transformation
Reduced_Playoff_Data2$MP_bc = if (lambda == 0) {
  log(Reduced_Playoff_Data2$MP)
} else {
  (Reduced_Playoff_Data2$MP^lambda - 1) / lambda
}

BoxCox_Model = lm(MP ~ PTS + TRB + STL, data = Reduced_Playoff_Data2)
summary(BoxCox_Model)
(kable(summary(Forward_Model)$coef, digits = 5, caption ="Coefficients for Box-Cox Transformed Stepwise Model"))
Coefficients for Box-Cox Transformed Stepwise Model
Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.95295 0.51403 9.63559 0
PTS 0.83937 0.06584 12.74912 0
TRB 1.20058 0.14456 8.30534 0
STL 5.85402 0.88897 6.58518 0

3 Analysis of Variance (ANOVA) Model

To determine whether or not there was a correlation between a player’s position on the court and team (our qualitative predictor variables) and his playing time, I performed an ANOVA test. The findings can be seen below and are definitive in suggesting that neither one of those circumstantial factors has a significant relationship with a player’s minutes per game.

ANOVA_model = aov(MP ~ Pos * Tm, data = Reduced_Playoff_Data)
summary(ANOVA_model)
ANOVA_Summary_Table = summary(ANOVA_model)[[1]]

# Print as markdown table
kable(ANOVA_Summary_Table, digits = 4, caption = "ANOVA Table: MP ~ Pos * Tm")
ANOVA Table: MP ~ Pos * Tm
Df Sum Sq Mean Sq F value Pr(>F)
Pos 4 570.5512 142.6378 0.6560 0.6236
Tm 15 628.6916 41.9128 0.1928 0.9996
Pos:Tm 60 6748.6587 112.4776 0.5173 0.9977
Residuals 137 29787.6867 217.4284 NA NA

3.1 Checking ANOVA Model Assumptions

Despite the findings of my ANOVA model being quite strong, I still wanted to review the data to ensure that no fundamental assumptions for proper ANOVA modeling were violated. The results of that review were mixed.

I performed a series of Shapiro Wilk tests to determine if players’ recorded minutes per game were normally distributed when grouping these observations, first by team and then by position. Regarding teams, five of the sixteen did not give their players a normally distributed amount of playing time. Those teams would be the Nets, Cavaliers, Nuggets, Lakers and Sixers. And when grouped by position, the data showed that playing time was certainly not distributed in a normal manner.

As for the ANOVA condition of variance equality, there was overwhelming evidence that the variance of minutes per game was equal across both teams and positions.

by(MP, Tm, shapiro.test)
by(MP, Pos, shapiro.test)

bartlett.test(MP ~ Tm, data = Reduced_Playoff_Data)
bartlett.test(MP ~ Pos, data = Reduced_Playoff_Data)

3.2 Kruskal-Wallis-H Test

Given the mixed results of my ANOVA assumption check, I chose to perform a nonparametric Kruskal-Wallis-H Test in order to ensure the validity of my ANOVA model’s findings that a player’s team and position status do not play a significant role in his playing time. The findings of the Kruskal-Wallis-H Test were in alignment with the ANOVA model’s results, reporting neither as a significant factor in predicting a player’s minutes per game.

kruskal.test(MP ~ Tm, data = Reduced_Playoff_Data)

    Kruskal-Wallis rank sum test

data:  MP by Tm
Kruskal-Wallis chi-squared = 4.1147, df = 15, p-value = 0.9973
kruskal.test(MP ~ Pos, data = Reduced_Playoff_Data)

    Kruskal-Wallis rank sum test

data:  MP by Pos
Kruskal-Wallis chi-squared = 3.6124, df = 4, p-value = 0.461

4 Conclusion

Ultimately, the findings of today’s analysis can be summarized by the statement that there is a great deal of evidence that scoring, rebounding and stealing plays a role in how much playing time an NBA player receives in the postseason. While alternatively, there is practically no statistical evidence that a player’s assists’ average, age, position on the court or team have such a relationship with minutes played. While there was some slight variation between the base model, pre-transformation stepwise model and post-transformation stepwise model, it is safe to estimate the following. For every additional point per game averaged, a player will receive an additional 0.84 minutes of playing time. He may also receive an additional 1.2 minutes per game for a one unit increase in rebounding average, and a boost of 5.8 minutes per game for every additional steal averaged per game.

LS0tCnRpdGxlOiAiSG93IGFuIE5CQSBQbGF5ZXIncyBQbGF5c3R5bGUgYW5kIENpcmN1bXN0YW5jZSBBZmZlY3QgaGlzIFBsYXlpbmcgVGltZSIKYXV0aG9yOiAiQ2hyaXMgQmFobSIKZGF0ZTogIjIwMjUtMDktMjIiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogdHJ1ZQogICAgICBzbW9vdGhfc2Nyb2xsOiB0cnVlCiAgICB0b2NfZGVwdGg6IDQKICAgIGZpZ193aWR0aDogNgogICAgZmlnX2hlaWdodDogNAogICAgZmlnX2NhcHRpb246IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICB0aGVtZTogbHVtZW4KICAgIGhpZ2hsaWdodDogdGFuZ28KICBwZGZfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogNAogICAgZmlnX2NhcHRpb246IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogIHdvcmRfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogNAotLS0KCmBgYHtjc3MsIGVjaG8gPSBGQUxTRX0KZGl2I1RPQyBsaSB7ICAgICAvKiB0YWJsZSBvZiBjb250ZW50ICAqLwogICAgbGlzdC1zdHlsZTp1cHBlci1yb21hbjsKICAgIGJhY2tncm91bmQtaW1hZ2U6bm9uZTsKICAgIGJhY2tncm91bmQtcmVwZWF0Om5vbmU7CiAgICBiYWNrZ3JvdW5kLXBvc2l0aW9uOjA7Cn0KCmgxLnRpdGxlIHsgICAgLyogbGV2ZWwgMSBoZWFkZXIgb2YgdGl0bGUgICovCiAgZm9udC1zaXplOiAyNHB4OwogIGZvbnQtd2VpZ2h0OiBib2xkOwogIGNvbG9yOiBEYXJrUmVkOwogIHRleHQtYWxpZ246IGNlbnRlcjsKfQoKaDQuYXV0aG9yIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICBmb250LXNpemU6IDE4cHg7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgY29sb3I6IERhcmtSZWQ7CiAgdGV4dC1hbGlnbjogY2VudGVyOwp9CgpoNC5kYXRlIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICBmb250LXNpemU6IDE4cHg7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgY29sb3I6IERhcmtCbHVlOwogIHRleHQtYWxpZ246IGNlbnRlcjsKfQoKaDEgeyAvKiBIZWFkZXIgMSAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogICAgZm9udC1zaXplOiAyMHB4OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBkYXJrcmVkOwogICAgdGV4dC1hbGlnbjogY2VudGVyOwp9CgpoMiB7IC8qIEhlYWRlciAyIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgICBmb250LXNpemU6IDE4cHg7CiAgICBmb250LXdlaWdodDogYm9sZDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IG5hdnk7CiAgICB0ZXh0LWFsaWduOiBsZWZ0Owp9CgpoMyB7IC8qIEhlYWRlciAzIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgICBmb250LXNpemU6IDE2cHg7CiAgICBmb250LXdlaWdodDogYm9sZDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IG5hdnk7CiAgICB0ZXh0LWFsaWduOiBsZWZ0Owp9CgpoNCB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgICBmb250LXNpemU6IDE0cHg7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBkYXJrcmVkOwogICAgdGV4dC1hbGlnbjogbGVmdDsKfQoKLyogQWRkIGRvdHMgYWZ0ZXIgbnVtYmVyZWQgaGVhZGVycyAqLwouaGVhZGVyLXNlY3Rpb24tbnVtYmVyOjphZnRlciB7CiAgY29udGVudDogIi4iOwp9CmBgYAoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CiMgY29kZSBjaHVuayBzcGVjaWZpZXMgd2hldGhlciB0aGUgUiBjb2RlLCB3YXJuaW5ncywgYW5kIG91dHB1dCAKIyB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBvdXRwdXQgZmlsZXMuCgppZiAoIXJlcXVpcmUoImtuaXRyIikpIHsgICAgICAgICAgICAgICAgICAgICAgIyB1c2UgY29uZGl0aW9uYWwgc3RhdGVtZW50IHRvIGRldGVjdAogICBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpICAgICAgICAgICAgICAgICAgIyB3aGV0aGVyIGEgcGFja2FnZSB3YXMgaW5zdGFsbGVkIGluCiAgIGxpYnJhcnkoa25pdHIpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHlvdXIgbWFjaGluZS4gSWYgbm90LCBpbnN0YWxsIGl0IGFuZAp9ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBsb2FkIGl0IHRvIHRoZSB3b3JraW5nIGRpcmVjdG9yeS4KCmlmICghcmVxdWlyZSh0aWR5dmVyc2UpKSB7bGlicmFyeSh0aWR5dnNlcnNlKX0gCgppZiAoIXJlcXVpcmUoR0dhbGx5KSkge2xpYnJhcnkoR0dhbGx5KX0gCgppZiAoIXJlcXVpcmUoa2FibGVFeHRyYSkpIHtsaWJyYXJ5KGthYmxlRXh0cmEpfSAKCmlmICghcmVxdWlyZShnZ3Bsb3QyKSkge2xpYnJhcnkoZ2dwbG90Mil9IAoKaWYgKCFyZXF1aXJlKGNhcikpIHtsaWJyYXJ5KGNhcil9IAoKaWYgKCFyZXF1aXJlKGRwbHlyKSkge2xpYnJhcnkoZHBseXIpfSAKCmlmICghcmVxdWlyZSgic2NhbGVzIikpIHsKaW5zdGFsbC5wYWNrYWdlcygic2NhbGVzIikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCmxpYnJhcnkoInNjYWxlcyIpIAp9Cgprbml0cjo6b3B0c19jaHVuayRzZXQoCgllY2hvID0gVFJVRSwKCW1lc3NhZ2UgPSBGQUxTRSwKCXdhcm5pbmcgPSBGQUxTRSwKCWNvbW1lbnQgPSBOQSwKCXJlc3VsdHMgPSBUUlVFCikKICAgCmBgYAoKIyMgSW50cm9kdWN0aW9uIGFuZCBCYWNrZ3JvdW5kClRoZSBkYXRhc2V0IEkgYW0gdXNpbmcgZm9yIG15IGFuYWx5c2lzIGlzIGFuIGV4dGVuc2l2ZSBjb2xsZWN0aW9uIG9mIG1ldHJpY3MgZm9yIGV2ZXJ5IE5CQSBwbGF5ZXIncyBnYW1lLWJ5LWdhbWUgcGVyZm9ybWFuY2UgYWNyb3NzIHRoZSAyMDIyLTIwMjMgcGxheW9mZiBzZWFzb24uIEl0IHdhcyBwdWJsaXNoZWQgb24gdGhlIG9wZW4tc291cmNlIGRhdGEgc2NpZW5jZSBwbGF0Zm9ybSBLYWdnbGUgKGxpbmsgY2FuIGJlIGZvdW5kIGluIHJlZmVyZW5jZXMgc2VjdGlvbiBiZWxvdykuIFRoZSBvcmlnaW5hbCBzb3VyY2UgZm9yIHRoZSBkYXRhJ3MgYWNjdXJhY3kgY2FuIGJlIGNvbmZpcm1lZCBhdCBCYXNrZXRiYWxsLXJlZmVyZW5jZS5jb20sIGEgd2VsbC1lc3RhYmxpc2hlZCBkYXRhYmFzZSBmb3IgZW50aHVzaWFzdHMgb2YgdGhlIHNwb3J0LiBBbGwgc3RhdGlzdGljYWwgYW5hbHlzaXMgd2lsbCBiZSBjb25kdWN0ZWQgdmlhIHRoZSBwcm9ncmFtbWluZyBsYW5ndWFnZSBSLgoKQXMgZm9yIHRoZSBkYXRhc2V0J3MgY29udGVudHMsIGl0IGlzIGNvbXBvc2VkIG9mIGFsbCAyMTcgcGxheWVycyB3aG8gcGxheWVkIHNvbWUgYW1vdW50IG9mIHRpbWUgaW4gdGhlIDIwMjItMjAyMyBwb3N0c2Vhc29uLiBJdCBjb250YWluZWQgMzAgdmFyaWFibGVzLCBob3dldmVyIG9ubHkgMTAgcGxheWVkIGEgcm9sZSBpbiBteSBhbmFseXNpcywgc28gSSBjcmVhdGVkIGEgcmVkdWNlZCBkYXRhc2V0IHdoaWNoIG9ubHkgY29udGFpbmVkIHRoZSBpbmZvcm1hdGlvbiBwZXJ0aW5lbnQgdG8gbXkgcmVzZWFyY2ggcXVlc3Rpb24uIEFuIGV4cGxhbmF0aW9uIGFuZCBicmVha2Rvd24gb2YgdGhlIG5hbWVzIGFuZCBkYXRhIHR5cGVzIGZvciB0aGUgdmFyaWFibGVzIHVzZWQgaW4gbXkgYW5hbHlzaXMgaXMgYmVsb3c6CgotICAgIlBsYXllciIgPSBwbGF5ZXIncyBuYW1lID0gY2hhcmFjdGVyCgotICAgIlBvcyIgPSBwbGF5ZXIncyBwb3NpdGlvbiBvbiB0aGUgY291cnQgb3IgaW4gc3RhcnRpbmcgbGluZXVwID0gY2hhcmFjdGVyCgotICAgIlRtIiA9IHRlYW0gcGxheWVyIHBsYXlzIGZvciA9IGNoYXJhY3RlcgoKLSAgICJBZ2UiID0gcGxheWVyJ3MgYWdlID0gaW50ZWdlcgoKLSAgICJQVFMiID0gcGxheWVyJ3MgcG9pbnRzIHBlciBnYW1lIGF2ZXJhZ2UgPSBkb3VibGUKCi0gICAiQVNUIiA9IHBsYXllcidzIGFzc2lzdHMgcGVyIGdhbWUgYXZlcmFnZSA9IGRvdWJsZQoKLSAgICJUUkIiID0gcGxheWVyJ3MgcmVib3VuZHMgcGVyIGdhbWUgYXZlcmFnZSA9IGRvdWJsZQoKLSAgICJTVEwiID0gcGxheWVyJ3Mgc3RlYWxzIHBlciBnYW1lIGF2ZXJhZ2UgPSBkb3VibGUKCi0gICAiQkxLIiA9IHBsYXllcidzIGJsb2NrcyBwZXIgZ2FtZSBhdmVyYWdlID0gZG91YmxlCgotICAgIk1QIiA9IHBsYXllcidzIG1pbnV0ZXMgcGVyIGdhbWUgYXZlcmFnZSA9IGRvdWJsZQoKVXNpbmcgdGhpcyBkYXRhc2V0LCBJIHdpbGwgYmUgZXhwbG9yaW5nIHRoZSByZWxhdGlvbnNoaXAgdGhhdCBhIHBsYXllcidzIGltcGFjdCBvbiB0aGUgZ2FtZSAobWVhc3VyZWQgdmlhIHRoZWlyIGF2ZXJhZ2UgcG9pbnRzLCByZWJvdW5kcywgYXNzaXN0cywgc3RlYWxzIGFuZCBibG9ja3MpIGFuZCBjaXJjdW1zdGFuY2UgKGFnZSwgcG9zaXRpb24gYW5kIHRlYW0gcGxheWluZyBmb3IpIGhhcyBvbiB0aGVpciBwbGF5aW5nIHRpbWUgKG1lYXN1cmVkIGJ5IHBlciBtaW51dGUgYXZlcmFnZXMpLiBJIHdpbGwgcmVmZXIgdG8gdGhlIGZpdmUgcHJpbWFyeSBtZXRyaWNzIG9mIHByb2R1Y3Rpdml0eSAocG9pbnRzLCByZWJvdW5kcywgYXNzaXN0cywgc3RlYWxzIGFuZCBibG9ja3MpIGFzIHRoZSAiZml2ZSBzdGFuZGFyZCBzdGF0aXN0aWNzIiBvZiBiYXNrZXRiYWxsLgoKSSBoYXZlIHByZXZpb3VzbHkgYW5hbHl6ZWQgdGhpcyBkYXRhc2V0IGFuZCBmb3VuZCB0aGVyZSB0byBiZSBhIHN0cm9uZywgcG9zaXRpdmUgYW5kIHNpbXBseSBsaW5lYXIgcmVsYXRpb25zaGlwIGJldHdlZW4gYSBwbGF5ZXIncyBhdmVyYWdlIHNjb3Jpbmcgb3V0cHV0IGFuZCBoaXMgYXZlcmFnZSBwbGF5aW5nIHRpbWUuIFRocm91Z2ggbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWxpbmcgYW5kIGJvb3RzdHJhcCBzYW1wbGluZywgSSBjYW1lIHRvIHRoZSBjb25jbHVzaW9uIHRoYXQgZm9yIGV2ZXJ5IGFkZGl0aW9uYWwgcG9pbnQgYSBwbGF5ZXIgYXZlcmFnZXMsIGhpcyBwbGF5aW5nIHRpbWUgaW5jcmVhc2VzIGJ5IGFib3V0IDEuNCBtaW51dGVzIHBlciBnYW1lLiBBbmQgbW9yZSBicm9hZGx5LCBJIGNhbiBzYXkgdGhhdCBhIHNjb3JpbmcgaW5jcmVhc2Ugb2Ygb25lIHBvaW50IHBlciBnYW1lIHdpbGwgcmVzdWx0IGluIGFuIGluY3JlYXNlIG9mIGFib3V0IDEuMyB0byAxLjU1IGV4dHJhIG1pbnV0ZXMgcGVyIGdhbWUgOTUlIG9mIHRoZSB0aW1lLgoKV2hpbGUgSSBpbml0aWFsbHkgY2hvc2UgdG8gZm9jdXMgaW4gb24gdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gcG9pbnRzIHBlciBnYW1lIGFuZCBtaW51dGVzIHBlciBnYW1lIGR1ZSB0byB0aGUgb3ZlcndoZWxtaW5nIGV2aWRlbmNlIHRoYXQgYSBzaWduaWZpY2FudCByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgdHdvIGV4aXN0ZWQgKGF2YWlsYWJsZSBpbiByZWZlcmVuY2VzIGZvciBmdXJ0aGVyIGRldGFpbCksIEkgbm93IHBsYW4gdG8gZXhwYW5kIHVwb24gdGhlIGZvdW5kaW5ncyBvZiBteSBwcmV2aW91cyByZXBvcnRpbmcuIEkgd2lsbCBjcmVhdGUgbXVsdGktdmFyaWF0ZSBtb2RlbHMgdG8gZGV0ZXJtaW5lIGhvdyBjaGFuZ2VzIGluIGEgcGxheWVyJ3Mgb3RoZXIgbWV0cmljcywgYXMgd2VsbCBhcyB0aGVpciBhZ2UsIHBvc2l0aW9uIGFuZCB0ZWFtIHNpdHVhdGlvbiBpbXBhY3QgdGhlaXIgYXZlcmFnZSBhbW91bnQgb2YgcGxheWluZyB0aW1lLgoKR2l2ZW4gdGhlIHN1ZmZpY2llbnQgc2l6ZSBvZiBteSBkYXRhc2V0LCBvdmVyIDIwMCBwbGF5ZXJzIGZyb20gdGhlIDE2IHRlYW1zIHdoaWNoIHBhcnRpY2lwYXRlZCBpbiB0aGUgcG9zdHNlYXNvbiwgYW5kIHRoZSByZWxpYWJpbGl0eSBvZiBpdHMgc291cmNpbmcsIEkgYW0gY29uZmlkZW50IHRoYXQgSSB3aWxsIGJlIGFibGUgdG8gY29tZSB0byBlbXBpcmljYWxseSBqdXN0aWZpZWQgY29uY2x1c2lvbnMuCmBgYHtyIERhdGFfUmVhZF9pbl9hbmRfQ2xlYW5pbmcsIGluY2x1ZGU9RkFMU0V9CgpEYXRhX1VybCA9ICJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vQ2hyaXNCMjMyMy9TVEEzMjEvbWFpbi9QbGF5b2ZmX0RhdGEuY3N2IgpGdWxsX1BsYXlvZmZfRGF0YSA9IHJlYWRfZGVsaW0oRGF0YV9VcmwsIGRlbGltID0gIjsiLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKQpnbGltcHNlKEZ1bGxfUGxheW9mZl9EYXRhKQoKUmVkdWNlZF9QbGF5b2ZmX0RhdGEgPSBGdWxsX1BsYXlvZmZfRGF0YSAlPiUgZHBseXI6OnNlbGVjdChQbGF5ZXIsIFBvcywgVG0sIEFnZSwgUFRTLCBBU1QsIFRSQiwgU1RMLCBCTEssIE1QKQpnbGltcHNlKFJlZHVjZWRfUGxheW9mZl9EYXRhKQoKCgpQbGF5ZXIgPSBSZWR1Y2VkX1BsYXlvZmZfRGF0YSRQbGF5ZXIKUG9zID0gUmVkdWNlZF9QbGF5b2ZmX0RhdGEkUG9zClRtID0gUmVkdWNlZF9QbGF5b2ZmX0RhdGEkVG0KQWdlID0gUmVkdWNlZF9QbGF5b2ZmX0RhdGEkQWdlClBUUyA9IFJlZHVjZWRfUGxheW9mZl9EYXRhJFBUUwpBU1QgPSBSZWR1Y2VkX1BsYXlvZmZfRGF0YSRBU1QKVFJCID0gUmVkdWNlZF9QbGF5b2ZmX0RhdGEkVFJCClNUTCA9IFJlZHVjZWRfUGxheW9mZl9EYXRhJFNUTApCTEsgPSBSZWR1Y2VkX1BsYXlvZmZfRGF0YSRCTEsKTVAgPSBSZWR1Y2VkX1BsYXlvZmZfRGF0YSRNUAoKUXVhbnRpdGF0aXZlX1ByZWRpY3Rvcl9WYXJpYWJsZXMgPSBSZWR1Y2VkX1BsYXlvZmZfRGF0YVtjKCJBZ2UiLCAiUFRTIiwgIkFTVCIsICJUUkIiLCAiU1RMIiwgIkJMSyIpXQoKQ2F0ZWdvcmljYWxfUHJlZGljdG9yX1ZhcmlhYmxlcyA9IFJlZHVjZWRfUGxheW9mZl9EYXRhW2MoIlBvcyIsICJUbSIpXQoKIyBRdWFudGl0YXRpdmUgUHJlZGljdG9yOiBBZ2UsIFBUUywgQVNULCBUUkIsIFNUTCwgQkxLCiMgQ2F0ZWdvcmljYWwgUHJlZGljdG9yOiBQb3MsIFRtCgpBbGxfUHJlZGljdG9yX1ZhcmlhYmxlcyA9IGNiaW5kKFF1YW50aXRhdGl2ZV9QcmVkaWN0b3JfVmFyaWFibGVzLCBDYXRlZ29yaWNhbF9QcmVkaWN0b3JfVmFyaWFibGVzKQoKYGBgCgojIyBNdWx0aXBsZSBMaW5lYXIgUmVncmVzc2lvbiAoTUxSKSBBcHByb2FjaApUaGUgZmlyc3QgbW9kZWxpbmcgc3RyYXRlZ3kgSSBlbXBsb3llZCB0byB1bmRlcnN0YW5kIHdoYXQgZmFjdG9ycyBjb3JyZWxhdGVkIHdpdGggYW4gTkJBIHBsYXllcidzIGF2ZXJhZ2UgcGxheWluZyB0aW1lIHdhcyBhIG11bHRpcGxlIGxpbmVhciByZWdyZXNzaW9uIGFwcHJvYWNoLiBTZXR0aW5nIG1pbnV0ZXMgcGxheWVkIGFzIG15IHJlc3BvbnNlIGFuZCBteSBkYXRhc2V0J3Mgb3RoZXIgc2l4IHF1YW50aXRhdGl2ZSB2YXJpYWJsZXMgYXMgdGhlIHByZWRpY3RvcnMsIEkgcmFuIGEgbGluZWFyIG1vZGVsIHdoaWNoIHdlIHdpbGwgcmVmZXIgdG8gYXMgdGhlICJCYXNlIFJlZ3Jlc3Npb24gTW9kZWwuIgoKIyMjIEJhc2UgTW9kZWwKVGhlIGZpbmRpbmdzIG9mIHRoaXMgcmVncmVzc2lvbiBtb2RlbCB3ZXJlIGRlZmluaXRpdmUuIEl0IHJlcG9ydGVkIHRoYXQgcGVyLWdhbWUgYXZlcmFnZXMgaW4gdGhlIHBvaW50cywgcmVib3VuZHMgYW5kIHN0ZWFscyBjYXRlZ29yaWVzIGFic29sdXRlbHkgaGFkIGEgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBjb3JyZWxhdGlvbiB3aXRoIGhvdyBtdWNoIHBsYXlpbmcgdGltZSBhIHBsYXllciBnb3QuIEFsdGVybmF0aXZlbHksIGl0IHdhcyBmb3VuZCB0aGF0IG5vdCBvbmx5IGRpZCBhIHBsYXllcidzIGFnZSBhbmQgcGVyLWdhbWUgYXZlcmFnZXMgaW4gYmxvY2tzIGFuZCBhc3Npc3RzIG5vdCBoYXZlIGEgY29ycmVsYXRvcnkgaW1wYWN0IG9uIGhpcyBwbGF5aW5nIHRpbWUsIGJ1dCBpdCB3YXMgbm90IHBhcnRpY3VsYXJseSBjbG9zZSwgZXNwZWNpYWxseSBmb3IgYXNzaXN0cyBhbmQgYmxvY2tzIHBlciBnYW1lLgoKQWxsIHRoYXQgYmVpbmcgc2FpZCwgSSBkaWQgbm90IHdhbnQgdG8gZHJhdyBhIGRlZmluaXRpdmUgY29uY2x1c2lvbiBzb2xlbHkgZnJvbSB0aGlzIGJhc2UgcmVncmVzc2lvbiBtb2RlbCwgc28gSSBwZXJmb3JtZWQgdmFyaWFibGUgc2NyZWVuaW5nIGFuZCBpbnZlc3RpZ2F0ZWQgZm9yIG90aGVyIG5vdGljZWFibGUgd2Vha25lc3NlcyBpbiB0aGUgbW9kZWwncyBlZmZpY2llbmN5LgoKYGBge3IgQmFzZSBNb2RlbCBCdWlsZGluZywgcmVzdWx0cz0naGlkZSd9CkJhc2VfUmVncmVzc2lvbl9Nb2RlbCA9IGxtKE1QIH4gQWdlICsgUFRTICsgQVNUICsgVFJCICsgU1RMICsgQkxLLCBkYXRhID0gUmVkdWNlZF9QbGF5b2ZmX0RhdGEpCnN1bW1hcnkoQmFzZV9SZWdyZXNzaW9uX01vZGVsKQogIyBCYXNlIG1vZGVsOiAocCA8IDIuMmUtMTYsIEYgPSAyNDEuNyAoNiwgMjEwKSBBZGp1c3RlZCBSXjIgPSAwLjg2OTkKICMgU2lnbmlmaWNhbnQgdmFyaWFibGVzIHBlciBiYXNlIG1vZGVsOgogICMgUFRTLCBUUkIsIFNUTCwgCiAgIyBQVFMgLT4gaW50ZXJjZXB0ID0gMC44NDAyOCwgcCA8IDJlLTE2CiAgIyBUUkIgLT4gaW50ZXJjZXB0ID0gMS4yMDA1MCwgcCA9IDEuNTBlLTExCiAgIyBTVEwgLT4gaW50ZXJjZXB0ID0gNS44MDg1NiwgcCA9IDEuNzRlLTA4CgpgYGAKCmBgYHtyfQprYWJsZShzdW1tYXJ5KEJhc2VfUmVncmVzc2lvbl9Nb2RlbCkkY29lZiwgZGlnaXRzID0gNCwgYWxpZ24gPSAnYycsIGNhcHRpb24gPSJDb2VmZmljaWVudHMgZm9yIHRoZSBCYXNlIFJlZ3Jlc3Npb24gTW9kZWwiKQoKYGBgCgojIyMgU3RlcHdpc2UgUmVncmVzc2lvbiBNb2RlbHMKVmlhIFIsIEkgcGVyZm9ybWVkIHRocmVlIHR5cGVzIG9mIG1vZGVsIG1vZGlmaWNhdGlvbjsgZm9yd2FyZCBzZWxlY3Rpb24sIGJhY2t3YXJkIHNlbGVjdGlvbiBhbmQgc3RlcHdpc2Ugc2VsZWN0aW9uLiBGb3J3YXJkIHNlbGVjdGlvbiBjb25zaXN0cyBvZiB0aGVyZSBiZWluZyBubyBwcmVkaWN0b3JzIGluIHRoZSBtb2RlbCwgYW5kIHRoZW4gdGhlIG1vc3QgY29udHJpYnV0aXZlIHByZWRpY3RvcnMgYmVpbmcgaXRlcmF0aXZlbHkgYWRkZWQgdW50aWwgdGhlcmUgaXMgbm8gbW9yZSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGltcHJvdmVtZW50IHRvIGJlIG1hZGUuIEJhY2t3YXJkIHNlbGVjdGlvbiB0YWtlcyB0aGUgb3Bwb3NpdGUgYXBwcm9hY2gsIGJlZ2lubmluZyB3aXRoIGEgY29tcGxldGUgbGluZWFyIG1vZGVsIChvdXIgYmFzZSBtb2RlbCBpbiB0aGlzIGNhc2UpLCBhbmQgaXRlcmF0aXZlbHkgcmVtb3ZpbmcgdGhlIGxlYXN0IGNvbnRyaWJ1dGl2ZSBwcmVkaWN0b3JzIHVudGlsIGFsbCB0aGF0IGFyZSBsZWZ0IGFyZSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LiBMYXN0bHksIHN0ZXB3aXNlIHNlbGVjdGlvbiB1c2VzIGEgcHJvY2VzcyB0aGF0IGNvbWJpbmVzIGVsZW1lbnRzIG9mIGJvdGguIFRoaXMgcHJvY2VzcyB3YXMgZG9uZSB0byBzaW1wbGlmeSBvdXIgcmVncmVzc2lvbiBtb2RlbCBhbmQgYXZvaWQgdGhlIHJpc2sgb2Ygb3ZlcmZpdHRpbmcgdGhhdCBjb21lcyB3aXRoIGEgaGlnaGVyIGFtb3VudCBvZiBwcmVkaWN0b3IgdmFyaWFibGVzLgoKQWxsIHRocmVlIHByb2Nlc3NlcyByZXN1bHRlZCBpbiB0aGUgc2FtZSBlbmQgbW9kZWw7IGFsbCBsaXN0aW5nIFBUUywgVFJCIGFuZCBTVEwgYXMgdGhlIHByZWRpY3RvcnMgd2hpY2ggaGFkIGEgc2lnbmlmaWNhbnQgaW1wYWN0IG9uIGEgcGxheWVyJ3MgZ2l2ZW4gbWludXRlcyBwZXIgZ2FtZS4gQWxsIHRocmVlIG1vZGVscyBhbHNvIGNpdGVkIGEgc2lnbmlmaWNhbnRseSBzdHJvbmcgY29lZmZpY2llbnQgb2YgZGV0ZXJtaW5hdGlvbiwgZXhwcmVzc2luZyB0aGF0IGFib3V0IDg3JSBvZiB2YXJpYXRpb24gaW4gYSBwbGF5ZXIncyBtaW51dGVzIHBlciBnYW1lIGNvbWVzIGZyb20gaGlzIG1ldHJpY3MgaW4gdGhvc2UgdGhyZWUgY2F0ZWdvcmllcyAocG9pbnRzLCByZWJvdW5kcyBhbmQgc3RlYWxzKS4KCmBgYHtyIFN0ZXB3aXNlIFJlZ3Jlc3Npb24gQnVpbGRpbmcsIHJlc3VsdHM9J2hpZGUnfQojIE1haW4gdGFrZWF3YXk6IFAgdmFsdWUsIEYgc3RhdCBhbmQgYWRqdXN0ZWQgUl4yIGZvciB0b3RhbCBtb2RlbHMgd2VyZSBpZGVudGljYWwgZm9yIGFsbCB0aHJlZSBzdGVwd2lzZSByZWdyZXNzaW9uIG1vZGVscywgdGhpcyBpcyBub3QgdmVyeSBzdXJwcmlzaW5nIGR1ZSB0byBob3cgc3Ryb25nIHRoZSBwIHZhbHVlcyB3ZXJlIGluIHRoZSBvcmlnaW5hbCBiYXNlIG1vZGVsLgojIEFsbCB0aHJlZSBtb2RlbHMgYWxzbyBjb25maXJtIG91ciBvcmlnaW5hbCBtb2RlbCdzIGZpbmRpbmdzIHdoaWNoIGFyZSB0aGF0IHBvaW50cywgcmVib3VuZHMgYW5kIGFzc2lzdHMgaGF2ZSBhIHNpZ25pZmljYW50IHJlbGF0aW9uc2hpcCB3aXRoIGEgcGxheWVyJ3MgYXZlcmFnZSBtaW51dGVzIHBlciBnYW1lLiBBbGwgdGhyZWUgbW9kZWxzIGxpc3QgdGhlIHNhbWUgaW50ZXJjZXB0cyBhbmQgcCB2YWx1ZXMgZm9yIGFsbCB0aHJlZSBvZiB0aG9zZSB2YXJpYWJsZXMsIGFzIHdlbGwgYXMgdGhlIHNhbWUgaW50ZXJjZXB0IGZvciB0aGUgbW9kZWwgb2YgNC45NTI5NSAocCA8IDJlLTE2KS4KCgojIEJ1aWxkIGEgbnVsbCAoaW50ZXJjZXB0LW9ubHkpIG1vZGVsIHVzaW5nIHRoZSBzYW1lIGRhdGEgYW5kIHJlc3BvbnNlCk51bGxfTW9kZWwgPSBsbShNUCB+IDEsIGRhdGEgPSBSZWR1Y2VkX1BsYXlvZmZfRGF0YSkKCkZ1bGxfTW9kZWwgPSBCYXNlX1JlZ3Jlc3Npb25fTW9kZWwKCiMgMSkgRm9yd2FyZCBTZWxlY3Rpb24KICAjIEZvcndhcmQgTW9kZWw6IChwIDwgMi4yZS0xNiwgRiA9IDQ4NS41ICgzLCAyMTMpLCBhZGp1c3RlZCBSXjIgPSAwLjg3MDYpCiAgIyBTaWduaWZpY2FudCB2YXJpYWJsZXMgcGVyIEZvcndhcmQgU2VsZWN0aW9uIG1vZGVsOgogICAgIyBQVFMsIFRSQiwgU1RMCiAgICAjIFBUUyAtPiBpbnRlcmNlcHQgPSAwLjgzOTM3LCBwIDwgMmUtMTYKICAgICMgVFJCIC0+IGludGVyY2VwdCA9IDEuMjAwNTgsIHAgPSAxLjE1ZS0xNAogICAgIyBTVEwgLT4gaW50ZXJjZXB0ID0gNS44NTQwMiwgcCA9IDMuNDllLTEwCgogIEZvcndhcmRfTW9kZWwgPSBzdGVwKAogICAgb2JqZWN0ID0gTnVsbF9Nb2RlbCwKICAgIHNjb3BlID0gbGlzdChsb3dlciA9IGZvcm11bGEoTnVsbF9Nb2RlbCksIHVwcGVyID0gZm9ybXVsYShGdWxsX01vZGVsKSksCiAgICBkaXJlY3Rpb24gPSAiZm9yd2FyZCIsCiAgICB0cmFjZSA9IDEKICApCiAgc3VtbWFyeShGb3J3YXJkX01vZGVsKQoKIyAyKSBCYWNrd2FyZCBTZWxlY3Rpb24KICAjIEJhY2t3YXJkIE1vZGVsOiAocCA8IDIuMmUtMTYsIEYgPSA0ODUuNSAoMywgMjEzKSwgYWRqdXN0ZWQgUl4yID0gMC44NzA2KQogICMgU2lnbmlmaWNhbnQgdmFyaWFibGVzIHBlciBCYWNrd2FyZCBTZWxlY3Rpb24gbW9kZWw6CiAgICAjIFBUUywgVFJCLCBTVEwKICAgICMgUFRTIC0+IGludGVyY2VwdCA9IDAuODM5MzcsIHAgPCAyZS0xNgogICAgIyBUUkIgLT4gaW50ZXJjZXB0ID0gMS4yMDA1OCwgcCA9IDEuMTVlLTE0CiAgICAjIFNUTCAtPiBpbnRlcmNlcHQgPSA1Ljg1NDAyLCBwID0gMy40OWUtMTAKICBCYWNrd2FyZF9Nb2RlbCA9IHN0ZXAoCiAgICBvYmplY3QgPSBGdWxsX01vZGVsLAogICAgZGlyZWN0aW9uID0gImJhY2t3YXJkIiwKICAgIHRyYWNlID0gMQogICkKICBzdW1tYXJ5KEJhY2t3YXJkX01vZGVsKQogIAogIAojIDMpIFN0ZXB3aXNlIFNlbGVjdGlvbgogICMgU3RlcHdpc2UgTW9kZWw6IChwIDwgMi4yZS0xNiwgRiA9IDQ4NS41ICgzLCAyMTMpLCBhZGp1c3RlZCBSXjIgPSAwLjg3MDYpCiAgIyBTaWduaWZpY2FudCB2YXJpYWJsZXMgcGVyIFN0ZXB3aXNlIFNlbGVjdGlvbiBtb2RlbDoKICAgICMgUFRTLCBUUkIsIFNUTAogICAgIyBQVFMgLT4gaW50ZXJjZXB0ID0gMC44MzkzNywgcCA8IDJlLTE2CiAgICAjIFRSQiAtPiBpbnRlcmNlcHQgPSAxLjIwMDU4LCBwID0gMS4xNWUtMTQKICAgICMgU1RMIC0+IGludGVyY2VwdCA9IDUuODU0MDIsIHAgPSAzLjQ5ZS0xMAogIFN0ZXB3aXNlX01vZGVsID0gc3RlcCgKICAgIG9iamVjdCA9IE51bGxfTW9kZWwsCiAgICBzY29wZSA9IGxpc3QobG93ZXIgPSBmb3JtdWxhKE51bGxfTW9kZWwpLCB1cHBlciA9IGZvcm11bGEoRnVsbF9Nb2RlbCkpLAogICAgZGlyZWN0aW9uID0gImJvdGgiLAogICAgdHJhY2UgPSAxCiAgKQogIHN1bW1hcnkoU3RlcHdpc2VfTW9kZWwpCiAgCmBgYAoKYGBge3J9CihrYWJsZShzdW1tYXJ5KEZvcndhcmRfTW9kZWwpJGNvZWYsIGRpZ2l0cyA9IDUsIGNhcHRpb24gPSJDb2VmZmljaWVudHMgZm9yIGFsbCBUaHJlZSBTdGVwd2lzZSBSZWdyZXNzaW9uIE1vZGVscyIpKQpgYGAKCiMjIyBDb3JyZWxhdGlvbiBDb25jZXJucyAoQmFzZSBNb2RlbCkKVG8gZW5zdXJlIHRoYXQgbXVsdGljb2xsaW5lYXJpdHkgd2FzIG5vdCBhIGhhcm1mdWwgZmFjdG9yIGluIHRoZSBiYXNlIG1vZGVsLCBhbmQgaGVuY2UgYWxzbyB0aGUgc3RlcHdpc2UgbW9kZWwocyksIEkgaW52ZXN0aWdhdGVkIHVzaW5nIGEgY29ycmVsYXRpb24gbWF0cml4IGFuZCBhIFZJRiBiYXIgZ3JhcGguIAoKQXMgcGVyIHRoZSBjb3JyZWxhdGlvbiBtYXRyaXgsIHRoZXJlIGlzIGEgc3Ryb25nIGNvcnJlbGF0aW9uIGJldHdlZW4gQVNUIGFuZCBQVFMgKHIgfiAwLjgxOSkuIEhvd2V2ZXIsIGFzc2lzdHMgcGVyIGdhbWUgZG8gbm90IHJlcG9ydCB0byBiZSBhIHNpZ25pZmljYW50IHN0YXRpc3RpYyByZWxldmFudCB0byBwcmVkaWN0aW5nIGEgcGxheWVyJ3MgZ2l2ZW4gcGxheWluZyB0aW1lIGluIGFueSBvZiBvdXIgcmVncmVzc2lvbiBtb2RlbHMsIHRoZXJlZm9yZSBhbnkgdGhlb3JldGljYWwgdGhyZWF0IG9mIG11bHRpY29sbGluZWFyaXR5IHBvc2VkIGJ5IGFzc2lzdHMgcGVyIGdhbWUgaXMgbm90IHJlYWxpemVkLgoKTG9va2luZyBhdCB0aGUgVklGICh2YXJpYW5jZSBpbmZsYXRpb24gZmFjdG9yKSBjaGFydCwgdGhlIG9ubHkgcG90ZW50aWFsIGNvbmNlcm4gYXQgZmFjZSB2YWx1ZSBhcHBlYXJzIHRvIGJlIHRoYXQgb2YgcG9pbnRzIHBlciBnYW1lLCB3aGljaCBpcyBob3ZlcmluZyBzbGlnaGx5IGFib3ZlIGEgdmFsdWUgb2YgNC4gR2l2ZW4gdGhhdCB0aGUgb25seSBvdGhlciB2YXJpYWJsZXMgaW4gYWxsIG9mIG91ciBtb2RlbHMgdGhhdCB3ZXJlIGRlZW1lZCBzaWduaWZpY2FudCAodG90YWwgcmVib3VuZHMgYW5kIHN0ZWFscyBwZXIgZ2FtZSkgYXJlIGJvdGggcmF0ZWQgYmVsb3cgYSB2YWx1ZSBvZiAzLCB3ZSBjYW4gcmVhc29uYWJseSBhc3Nlc3MgdGhhdCBhbiBvdXQtb2YtY29udHJvbCBjb2VmZmljaWVudCB2YXJpYW5jZSBpcyBub3QgYSBncmVhdCBjb25jZXJuLgpgYGB7ciBDb3JyZWxhdGlvbiBDb25jZXJucyBCYXNlIE1vZGVsLCBmaWcuYWxpZ24gPSJjZW50ZXIifQpnZ3BhaXJzKFF1YW50aXRhdGl2ZV9QcmVkaWN0b3JfVmFyaWFibGVzLCB0aXRsZSA9ICJDb3JyZWxhdGlvbiBNYXRyaXggZm9yIEFnZSBhbmQgUGxheWVyIFN0YXRzIikgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKCmJhcnBsb3QodmlmKEJhc2VfUmVncmVzc2lvbl9Nb2RlbCksIG1haW4gPSAiVklGIFZhbHVlcyIsIGhvcml6ID0gRkFMU0UsIGNvbCA9ICJzdGVlbGJsdWUiKQpgYGAKCiMjIyBGdXJ0aGVyIFJlc2lkdWFsIEFuYWx5c2lzIChCYXNlIE1vZGVsKQpHaXZlbiB0aGF0IHRoZXJlIHdhcyBubyBtYWpvciBtdWx0aWNvbGxpbmVhcml0eSBpc3N1ZXMgcHJlc2VudCBpbiBvdXIgYmFzZSBtb2RlbCwgSSB0aGVuIG1vdmVkIGZvcndhcmQgYW5kIHBlcmZvcm1lZCByZXNpZHVhbCBhbmFseXNpcyBvbiBib3RoIHRoZSBiYXNlIG1vZGVsIChzZWVuIGJlbG93KSBhbmQgdGhlIHN0ZXB3aXNlIG1vZGVsLiBTaW5jZSBhIG1vcmUgcGFyc2ltb25pb3VzIG1vZGVsIGlzIG1vcmUgaWRlYWwgZm9yIHByZWRpY3Rpb24gYW5kIGVzdGltYXRpb24sIG1vdmluZyBmb3J3YXJkIEkgd2lsbCBiZSB1dGlsaXppbmcgdGhlIHN0ZXB3aXNlIG1vZGVsIHRvIGRyYXcgdWx0aW1hdGUgdGFrZWF3YXlzIGFuZCBjb25jbHVzaW9ucy4KYGBge3IgUmVzaWR1YWwgQW5hbHlzaXMgQmFzZSwgcmVzdWx0cz0naGlkZSd9CiMgSGlzdG9ncmFtCkJhc2VfTW9kZWxfUmVzaWR1YWxzID0gcmVzaWQoQmFzZV9SZWdyZXNzaW9uX01vZGVsKQpCYXNlX01vZGVsX1ByZWRpY3RlZF9WYWx1ZXMgPSBwcmVkaWN0KEJhc2VfUmVncmVzc2lvbl9Nb2RlbCkKaGlzdChCYXNlX01vZGVsX1Jlc2lkdWFscywKICAgICBtYWluID0gIkJhc2UgTW9kZWwgRXJyb3JzIiwKICAgICB4bGFiID0gIk1vZGVsIFJlc2lkdWFscyIpCgojIFNjYXR0ZXJwbG90CnBsb3QoQmFzZV9Nb2RlbF9QcmVkaWN0ZWRfVmFsdWVzLCBCYXNlX01vZGVsX1Jlc2lkdWFscywKICAgICBtYWluID0gIkJhc2UgTW9kZWwgLSBSZXNpZHVhbCBBbmFseXNpcyBTY2F0dGVycGxvdCIsCiAgICAgeGxhYiA9ICJQcmVkaWN0ZWQgbWludXRlcyBwZXIgZ2FtZSIsCiAgICAgeWxhYiA9ICJNb2RlbCBFcnJvciAobWlucyBwZXIgZ2FtZSkiKQphYmxpbmUoaD0wKQoKIyBSZXNpZHVhbCBNZWFuIENhbGN1bGF0aW9uCm1lYW4oQmFzZV9Nb2RlbF9SZXNpZHVhbHMpCgojIFFRIFBsb3QgCnFxbm9ybShCYXNlX01vZGVsX1Jlc2lkdWFscywgbWFpbiA9ICJRUSBSZXNpZHVhbHMiLCB5bGFiID0gIlN0YW5kYXJkaXplZCBSZXNpZHVhbHMiKQpxcWxpbmUoQmFzZV9Nb2RlbF9SZXNpZHVhbHMpCgojIFNjYWxlLUxvY2F0aW9uIFBsb3QKcGxvdChCYXNlX1JlZ3Jlc3Npb25fTW9kZWwsIHdoaWNoID0gMykKCiMgUmVzaWR1YWxzLUxldmVyYWdlIFBsb3QKcGxvdChCYXNlX1JlZ3Jlc3Npb25fTW9kZWwsIHdoaWNoID0gNSkKCmBgYAoKIyMjIEZ1cnRoZXIgUmVzaWR1YWwgQW5hbHlzaXMgKFN0ZXB3aXNlIE1vZGVscykKVGhlIGZpbmRpbmdzIG9mIG91ciByZXNpZHVhbCBhbmFseXNpcyBhcmUgbm90IGdyZWF0LiBUaGUgcmVzaWR1YWxzIGRvIG5vdCBhcHBlYXIgbm9ybWFsbHkgZGlzdHJpYnV0ZWQsIGFzIHBlciB0aGUgaGlzdG9ncmFtIGFuZCBRUSBwbG90LCBub3IgZG8gdGhleSBhcHBlYXIgdG8gaGF2ZSBhIGNvbnN0YW50IHZhcmlhbmNlLCBhcyBwZXIgdGhlIHNjYXR0ZXJwbG90IGFuZCBzY2FsZS1sb2NhdGlvbiBwbG90LiBUaGUgcmVzaWR1YWwtbGV2ZXJhZ2UgcGxvdCBhbHNvIGFwcGVhcnMgdG8gc2hvdyBhbnl3aGVyZSBmcm9tIDIgdG8gNSBvYnNlcnZhdGlvbnMgdGhhdCBhcmUgYm90aCBoaWdoIGxldmVyYWdlIGFuZCBoaWdoIHJlc2lkdWFsLCB3aGljaCBjYW4gc2lnbmlmaWNhbnRseSBpbXBhY3QgYSBtb2RlbCdzIGVmZmljYWN5LiAKYGBge3IgUmVzaWR1YWwgQW5hbHlzaXMgU3RlcHdpc2UsIHJlc3VsdHM9J2hpZGUnfQojIEhpc3RvZ3JhbQpGb3J3YXJkX01vZGVsX1Jlc2lkdWFscyA9IHJlc2lkKEZvcndhcmRfTW9kZWwpCkZvcndhcmRfTW9kZWxfUHJlZGljdGVkX1ZhbHVlcyA9IHByZWRpY3QoRm9yd2FyZF9Nb2RlbCkKaGlzdChGb3J3YXJkX01vZGVsX1Jlc2lkdWFscywKICAgICBtYWluID0gIlN0ZXB3aXNlIE1vZGVscyBFcnJvcnMiLAogICAgIHhsYWIgPSAiTW9kZWwgUmVzaWR1YWxzIikKCiMgU2NhdHRlcnBsb3QKcGxvdChGb3J3YXJkX01vZGVsX1ByZWRpY3RlZF9WYWx1ZXMsIEZvcndhcmRfTW9kZWxfUmVzaWR1YWxzLAogICAgIG1haW4gPSAiU3RlcHdpc2UgTW9kZWxzIC0gUmVzaWR1YWwgQW5hbHlzaXMgU2NhdHRlcnBsb3QiLAogICAgIHhsYWIgPSAiUHJlZGljdGVkIG1pbnV0ZXMgcGVyIGdhbWUiLAogICAgIHlsYWIgPSAiTW9kZWwgRXJyb3IgKG1pbnMgcGVyIGdhbWUpIikKYWJsaW5lKGg9MCkKCiMgUmVzaWR1YWwgTWVhbiBDYWxjdWxhdGlvbgptZWFuKEZvcndhcmRfTW9kZWxfUmVzaWR1YWxzKQoKIyBRUSBQbG90IApxcW5vcm0oRm9yd2FyZF9Nb2RlbF9SZXNpZHVhbHMsIG1haW4gPSAiUVEgUmVzaWR1YWxzIiwgeWxhYiA9ICJTdGFuZGFyZGl6ZWQgUmVzaWR1YWxzIikKcXFsaW5lKEZvcndhcmRfTW9kZWxfUmVzaWR1YWxzKQoKIyBTY2FsZS1Mb2NhdGlvbiBQbG90CnBsb3QoRm9yd2FyZF9Nb2RlbCwgd2hpY2ggPSAzKQoKIyBSZXNpZHVhbHMtTGV2ZXJhZ2UgUGxvdApwbG90KEZvcndhcmRfTW9kZWwsIHdoaWNoID0gNSkKYGBgCgojIyMgTUxSIGFuYWx5c2lzIHdpdGggQm94LUNveCB0cmFuc2Zvcm1hdGlvbgpHaXZlbiB0aGUgcmVzdWx0cyBvZiB0aGUgcmVzaWR1YWwgYW5hbHlzaXMgb24gbXkgc3RlcHdpc2UgbW9kZWwsIEkgdGhlbiBwZXJmb3JtZWQgYSBib3gtY294IHRyYW5zZm9ybWF0aW9uIG9mIG15IG1vZGVsLCB3aXRoIGEgbGFtYmEgdmFsdWUgb2YgMS4wNSwgdG8gaGVscCBtaXRpZ2F0ZSB0aGUgZXJyb3JzIHRoYXQgaW5jb25zaXN0ZW50IHJlc2lkdWFsIHZhcmlhbmNlIGFuZCBsYWNrIG9mIG5vcm1hbCBkaXN0cmlidXRpb24gbWlnaHQgYnJpbmcuIFRoZSByZXN1bHRzIHdlcmUgb25jZSBhZ2FpbiBkZWZpbml0aXZlLCBhbmQgaW4gYWxpZ25tZW50IHdpdGggdGhlIGJhc2UgbW9kZWwgYW5kIHRoZSBwcmUtdHJhbnNmb3JtYXRpb24gc3RlcHdpc2UgbW9kZWxzOyB0aGF0IGJlaW5nIHRoYXQgcG9pbnRzIHBlciBnYW1lLCByZWJvdW5kcyBwZXIgZ2FtZSBhbmQgc3RlYWxzIHBlciBnYW1lIHdlcmUgQUxMIGhpZ2hseSBzaWduaWZpY2FudCBmYWN0b3JzIGluIGVzdGltYXRpbmcgYSBwbGF5ZXIncyBtaW51dGVzIHBlciBnYW1lLgpgYGB7ciBCb3hjb3gsIHJlc3VsdHM9J2hpZGUnfQogIyBIYWQgMSBvYnNlcnZhdGlvbiB3aGVyZSBvdXIgcmVzcG9uc2UgdmFyaWFibGUgTVAgd2FzID0gMCwgd2hpY2ggZG9lcyBub3Qgd29yayB3aXRoIEJveC1Db3ggdHJhbnNmb3JtYXRpb24uCmxpYnJhcnkoTUFTUykKClJlZHVjZWRfUGxheW9mZl9EYXRhMiA9IFJlZHVjZWRfUGxheW9mZl9EYXRhW1JlZHVjZWRfUGxheW9mZl9EYXRhJE1QID4gMCwgXQoKRm9yd2FyZF9Nb2RlbDIgPSBsbShNUCB+IFBUUyArIFRSQiArIFNUTCwgZGF0YSA9IFJlZHVjZWRfUGxheW9mZl9EYXRhMikKCkJveGNveCA9IGJveGNveChGb3J3YXJkX01vZGVsMiwgbGFtYmRhID0gc2VxKC0yLCAyLCAwLjEpKQpsYW1iZGEgPSAxLjA1CgojIE1vZGlmeSBNUCB2YXJpYWJsZSBpbiBkYXRhc2V0IHdpdGggbGFtYmEgdHJhbnNmb3JtYXRpb24KUmVkdWNlZF9QbGF5b2ZmX0RhdGEyJE1QX2JjID0gaWYgKGxhbWJkYSA9PSAwKSB7CiAgbG9nKFJlZHVjZWRfUGxheW9mZl9EYXRhMiRNUCkKfSBlbHNlIHsKICAoUmVkdWNlZF9QbGF5b2ZmX0RhdGEyJE1QXmxhbWJkYSAtIDEpIC8gbGFtYmRhCn0KCkJveENveF9Nb2RlbCA9IGxtKE1QIH4gUFRTICsgVFJCICsgU1RMLCBkYXRhID0gUmVkdWNlZF9QbGF5b2ZmX0RhdGEyKQpzdW1tYXJ5KEJveENveF9Nb2RlbCkKYGBgCgpgYGB7cn0KKGthYmxlKHN1bW1hcnkoRm9yd2FyZF9Nb2RlbCkkY29lZiwgZGlnaXRzID0gNSwgY2FwdGlvbiA9IkNvZWZmaWNpZW50cyBmb3IgQm94LUNveCBUcmFuc2Zvcm1lZCBTdGVwd2lzZSBNb2RlbCIpKQpgYGAKIyMgQW5hbHlzaXMgb2YgVmFyaWFuY2UgKEFOT1ZBKSBNb2RlbApUbyBkZXRlcm1pbmUgd2hldGhlciBvciBub3QgdGhlcmUgd2FzIGEgY29ycmVsYXRpb24gYmV0d2VlbiBhIHBsYXllcidzIHBvc2l0aW9uIG9uIHRoZSBjb3VydCBhbmQgdGVhbSAob3VyIHF1YWxpdGF0aXZlIHByZWRpY3RvciB2YXJpYWJsZXMpIGFuZCBoaXMgcGxheWluZyB0aW1lLCBJIHBlcmZvcm1lZCBhbiBBTk9WQSB0ZXN0LiBUaGUgZmluZGluZ3MgY2FuIGJlIHNlZW4gYmVsb3cgYW5kIGFyZSBkZWZpbml0aXZlIGluIHN1Z2dlc3RpbmcgdGhhdCBuZWl0aGVyIG9uZSBvZiB0aG9zZSBjaXJjdW1zdGFudGlhbCBmYWN0b3JzIGhhcyBhIHNpZ25pZmljYW50IHJlbGF0aW9uc2hpcCB3aXRoIGEgcGxheWVyJ3MgbWludXRlcyBwZXIgZ2FtZS4KCmBgYHtyLCByZXN1bHRzPSdoaWRlJ30KQU5PVkFfbW9kZWwgPSBhb3YoTVAgfiBQb3MgKiBUbSwgZGF0YSA9IFJlZHVjZWRfUGxheW9mZl9EYXRhKQpzdW1tYXJ5KEFOT1ZBX21vZGVsKQpgYGAKCmBgYHtyfQpBTk9WQV9TdW1tYXJ5X1RhYmxlID0gc3VtbWFyeShBTk9WQV9tb2RlbClbWzFdXQoKIyBQcmludCBhcyBtYXJrZG93biB0YWJsZQprYWJsZShBTk9WQV9TdW1tYXJ5X1RhYmxlLCBkaWdpdHMgPSA0LCBjYXB0aW9uID0gIkFOT1ZBIFRhYmxlOiBNUCB+IFBvcyAqIFRtIikKYGBgCgojIyMgQ2hlY2tpbmcgQU5PVkEgTW9kZWwgQXNzdW1wdGlvbnMKRGVzcGl0ZSB0aGUgZmluZGluZ3Mgb2YgbXkgQU5PVkEgbW9kZWwgYmVpbmcgcXVpdGUgc3Ryb25nLCBJIHN0aWxsIHdhbnRlZCB0byByZXZpZXcgdGhlIGRhdGEgdG8gZW5zdXJlIHRoYXQgbm8gZnVuZGFtZW50YWwgYXNzdW1wdGlvbnMgZm9yIHByb3BlciBBTk9WQSBtb2RlbGluZyB3ZXJlIHZpb2xhdGVkLiBUaGUgcmVzdWx0cyBvZiB0aGF0IHJldmlldyB3ZXJlIG1peGVkLiAKCkkgcGVyZm9ybWVkIGEgc2VyaWVzIG9mIFNoYXBpcm8gV2lsayB0ZXN0cyB0byBkZXRlcm1pbmUgaWYgcGxheWVycycgcmVjb3JkZWQgbWludXRlcyBwZXIgZ2FtZSB3ZXJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIHdoZW4gZ3JvdXBpbmcgdGhlc2Ugb2JzZXJ2YXRpb25zLCBmaXJzdCBieSB0ZWFtIGFuZCB0aGVuIGJ5IHBvc2l0aW9uLiBSZWdhcmRpbmcgdGVhbXMsIGZpdmUgb2YgdGhlIHNpeHRlZW4gZGlkIG5vdCBnaXZlIHRoZWlyIHBsYXllcnMgYSBub3JtYWxseSBkaXN0cmlidXRlZCBhbW91bnQgb2YgcGxheWluZyB0aW1lLiBUaG9zZSB0ZWFtcyB3b3VsZCBiZSB0aGUgTmV0cywgQ2F2YWxpZXJzLCBOdWdnZXRzLCBMYWtlcnMgYW5kIFNpeGVycy4gQW5kIHdoZW4gZ3JvdXBlZCBieSBwb3NpdGlvbiwgdGhlIGRhdGEgc2hvd2VkIHRoYXQgcGxheWluZyB0aW1lIHdhcyBjZXJ0YWlubHkgbm90IGRpc3RyaWJ1dGVkIGluIGEgbm9ybWFsIG1hbm5lci4KCkFzIGZvciB0aGUgQU5PVkEgY29uZGl0aW9uIG9mIHZhcmlhbmNlIGVxdWFsaXR5LCB0aGVyZSB3YXMgb3ZlcndoZWxtaW5nIGV2aWRlbmNlIHRoYXQgdGhlIHZhcmlhbmNlIG9mIG1pbnV0ZXMgcGVyIGdhbWUgd2FzIGVxdWFsIGFjcm9zcyBib3RoIHRlYW1zIGFuZCBwb3NpdGlvbnMuCmBgYHtyLCByZXN1bHRzPSdoaWRlJ30KYnkoTVAsIFRtLCBzaGFwaXJvLnRlc3QpCmJ5KE1QLCBQb3MsIHNoYXBpcm8udGVzdCkKCmJhcnRsZXR0LnRlc3QoTVAgfiBUbSwgZGF0YSA9IFJlZHVjZWRfUGxheW9mZl9EYXRhKQpiYXJ0bGV0dC50ZXN0KE1QIH4gUG9zLCBkYXRhID0gUmVkdWNlZF9QbGF5b2ZmX0RhdGEpCmBgYAoKIyMjIEtydXNrYWwtV2FsbGlzLUggVGVzdApHaXZlbiB0aGUgbWl4ZWQgcmVzdWx0cyBvZiBteSBBTk9WQSBhc3N1bXB0aW9uIGNoZWNrLCBJIGNob3NlIHRvIHBlcmZvcm0gYSBub25wYXJhbWV0cmljIEtydXNrYWwtV2FsbGlzLUggVGVzdCBpbiBvcmRlciB0byBlbnN1cmUgdGhlIHZhbGlkaXR5IG9mIG15IEFOT1ZBIG1vZGVsJ3MgZmluZGluZ3MgdGhhdCBhIHBsYXllcidzIHRlYW0gYW5kIHBvc2l0aW9uIHN0YXR1cyBkbyBub3QgcGxheSBhIHNpZ25pZmljYW50IHJvbGUgaW4gaGlzIHBsYXlpbmcgdGltZS4gVGhlIGZpbmRpbmdzIG9mIHRoZSBLcnVza2FsLVdhbGxpcy1IIFRlc3Qgd2VyZSBpbiBhbGlnbm1lbnQgd2l0aCB0aGUgQU5PVkEgbW9kZWwncyByZXN1bHRzLCByZXBvcnRpbmcgbmVpdGhlciBhcyBhIHNpZ25pZmljYW50IGZhY3RvciBpbiBwcmVkaWN0aW5nIGEgcGxheWVyJ3MgbWludXRlcyBwZXIgZ2FtZS4KYGBge3J9CmtydXNrYWwudGVzdChNUCB+IFRtLCBkYXRhID0gUmVkdWNlZF9QbGF5b2ZmX0RhdGEpCmtydXNrYWwudGVzdChNUCB+IFBvcywgZGF0YSA9IFJlZHVjZWRfUGxheW9mZl9EYXRhKQpgYGAKCiMjIENvbmNsdXNpb24KVWx0aW1hdGVseSwgdGhlIGZpbmRpbmdzIG9mIHRvZGF5J3MgYW5hbHlzaXMgY2FuIGJlIHN1bW1hcml6ZWQgYnkgdGhlIHN0YXRlbWVudCB0aGF0IHRoZXJlIGlzIGEgZ3JlYXQgZGVhbCBvZiBldmlkZW5jZSB0aGF0IHNjb3JpbmcsIHJlYm91bmRpbmcgYW5kIHN0ZWFsaW5nIHBsYXlzIGEgcm9sZSBpbiBob3cgbXVjaCBwbGF5aW5nIHRpbWUgYW4gTkJBIHBsYXllciByZWNlaXZlcyBpbiB0aGUgcG9zdHNlYXNvbi4gV2hpbGUgYWx0ZXJuYXRpdmVseSwgdGhlcmUgaXMgcHJhY3RpY2FsbHkgbm8gc3RhdGlzdGljYWwgZXZpZGVuY2UgdGhhdCBhIHBsYXllcidzIGFzc2lzdHMnIGF2ZXJhZ2UsIGFnZSwgcG9zaXRpb24gb24gdGhlIGNvdXJ0IG9yIHRlYW0gaGF2ZSBzdWNoIGEgcmVsYXRpb25zaGlwIHdpdGggbWludXRlcyBwbGF5ZWQuIFdoaWxlIHRoZXJlIHdhcyBzb21lIHNsaWdodCB2YXJpYXRpb24gYmV0d2VlbiB0aGUgYmFzZSBtb2RlbCwgcHJlLXRyYW5zZm9ybWF0aW9uIHN0ZXB3aXNlIG1vZGVsIGFuZCBwb3N0LXRyYW5zZm9ybWF0aW9uIHN0ZXB3aXNlIG1vZGVsLCBpdCBpcyBzYWZlIHRvIGVzdGltYXRlIHRoZSBmb2xsb3dpbmcuIEZvciBldmVyeSBhZGRpdGlvbmFsIHBvaW50IHBlciBnYW1lIGF2ZXJhZ2VkLCBhIHBsYXllciB3aWxsIHJlY2VpdmUgYW4gYWRkaXRpb25hbCAwLjg0IG1pbnV0ZXMgb2YgcGxheWluZyB0aW1lLiBIZSBtYXkgYWxzbyByZWNlaXZlIGFuIGFkZGl0aW9uYWwgMS4yIG1pbnV0ZXMgcGVyIGdhbWUgZm9yIGEgb25lIHVuaXQgaW5jcmVhc2UgaW4gcmVib3VuZGluZyBhdmVyYWdlLCBhbmQgYSBib29zdCBvZiA1LjggbWludXRlcyBwZXIgZ2FtZSBmb3IgZXZlcnkgYWRkaXRpb25hbCBzdGVhbCBhdmVyYWdlZCBwZXIgZ2FtZS4KCiMjIFJlZmVyZW5jZXM6Ck9yaWdpbmFsIERhdGFzZXQgU291cmNlOiA8aHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9kYXRhc2V0cy92aXZvdmluY28vMjAyMjIwMjMtbmJhLXBsYXllci1zdGF0cy1yZWd1bGFyPgoKRGF0YXNldCBEb3dubG9hZCBMaW5rIHZpYSBHaXRodWI6Cmh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9DaHJpc0IyMzIzL1NUQTMyMS9tYWluL1BsYXlvZmZfRGF0YS5jc3YgCgpNeSBQcmV2aW91cyBBbmFseXNpczogaHR0cHM6Ly9ycHVicy5jb20vQ2hyaXNfQmFobS8xMzQ0NDY4