This is part of a series of pages related to EPL Away Wins:

After the exploratory data analysis, we will now investigate modelling for EPL data (using tidymodels). The available data set contains 6508 matches. We will remove the latest 20% of matches for use in assessing performance as a test set. Here are the first 10 rows of the data.

We will remove rows with missing data from selected features. We lose 2% of the data by removing missing rows.

Feature Creation

We create new features for Summed Features, i.e. sum of the last 4 shots on target, corners, fouls, goals scored, goals conceded for the Home team, Away team and their opponents.

Take out Test Data

We remove the final 20% of results to act as the test data. We also randomly define the stratified 5-fold crossvalidation splits for the training data.

Training data rows = 5114 
Proportion of Away Wins = 0.279 

Set up Pre-treatment Recipes

Firstly, we define the variables and model formula.

We have a formula of [AwayWin ~ sum_HST + sum_HC + sum_HGS + sum_HGC + sum_AST + sum_AC + sum_AF + sum_AGS + sum_AGC + sum_HoppST + sum_HoppC + sum_AoppST + sum_AoppC + winpc_H + winpc_A + top6_perfH + top6_perfA + Dist + Date + HomeFin1 + HomeFin2 + AwayFin1 + AwayFin2].

Then we define the pretreatment recipes. This includes removing correlated numeric variables, normalizing all numeric variables and turning categorical variables into dummy variables. As well as Month, we will create dummies for Day of Week.

recipe <-
  train %>%
  recipe(formula) %>%
  step_corr(all_numeric()) %>%
  step_normalize(all_numeric()) %>%
  step_date(Date, features = c("dow", "month")) %>%
  step_rm(Date) %>%
  step_dummy(Date_dow, Date_month)

What does the subsequent training frame look like?

Feature Importance

To estimate the relative importance of the features, we fit an unoptimised random forest model to the training data and determine variable importance from the model.

We can see that all the Date variables have relatively little importance when predicting Away wins. We will remove the Date variables going forward.

Generalized Linear Model

We will create a tuning workflow in order to optimise hyperparameters for our logistic regression model. As explained above, we will first redefine our pretreatment recipe to remove the Date features.

recipe <-
  train %>%
  recipe(formula) %>%
  step_corr(all_numeric()) %>%
  step_normalize(all_numeric()) %>%
  step_rm(Date)

We will be optimising mixture and penalty values for our glmnet model, using crossvalidation results of our training data. AUC for the ROC curve and accuracy metrics will be evaluated for each set of predictions.

model_glm <- 
  logistic_reg(penalty = tune(), mixture = tune()) %>% 
  set_engine("glmnet")

grid_glm <- 
  grid_max_entropy(
    penalty(range = c(0.001, 0.1), trans = NULL),
    mixture(range = c(0, 1)),
    size = 30)

my_metrics <- metric_set(roc_auc, accuracy)

After crossvalidating for a range of mixture and penalty values, let’s plot values of ROC AUC and list the best models.

Now let’s look at the accuracy metrics.

We see some differences between the models. Lower mixture and penalty values seem to give more consistently high AUC results. To obtain the most general model, it is better to choose a higher penalty value that gives a performance similar to the best performance. In terms of AUC, a penalty of around 0.03 would seem to be suitable. Now we will choose values of mixture = 0.3 and penalty = 0.03, train a model using the training data and fit the model to the test data. How does the ROC curve look for the test set and what is the AUC of the fit?

AUC value for best model is 0.756412

Potential Betting Strategies

There are two options for betting on matches, either Bet the Away win (predict it will happen) or Lay the Away win (predict it won’t happen).

Betting Probability Limits

One strategy for betting is to define a betting limit, where bets are placed when the predicted probability of success is greater than the defined limit. If we look at the test data, we can see what the outcome would have been if we had used a particular betting limit for this data. Note that there is no guarantee at all that the same outcome would be achieved for future data.

Away Win Bets

Looking at a range of betting limits for Away Win Bets gives the following results for the test set.

For example, if we had used a prediction limit of 0.55, we would have made 86 bets with resulting precision of 79% correct and a total profit of 9.38 with a one dollar stake per bet. Total stake would have been 86, so profit ratio would have been 10.9% of total stake.

For this data, the best profit would have been made with a betting limit of 0.56 (profit 16.8% of stake).

Away Win Lays

Looking at a range of betting limits for Away Win Lays gives the following results for the test set. Note that historic Lay odds are not generally available, so a correction has been made to the average Away win odds Lay odds (e.g. those available at Betfair) are generally higher than the average Away win odds.

A limit of 0.91 would have given profit of 49.97 from 64 bets with a precision of 98% correct. The total required stake for this profit would have been 1417, so profit ratio would have been 3.5%.

Prediction to Odds Probability Ratio

If we calculate the probability of the result implied by the betting odds and compare with the probability determined by the model, we can examine the ratio of model probability / implied odds probability. This has the potential to show where we may have an advantage over the bookmaker odds.

Away Win Bets

Let’s have a look at how the ratio of my prediction / implied bet probability affects the Bet metrics.

For this data, if we had used a ratio limit of 1.8, we would have made 75 bets for a profit of 36.73, with a precision of 11%. So a total stake of 75 and profit ratio of 49%.

Away Win Lays

Let’s have a look at how the ratio of my prediction / implied lay probability affects the Lay metrics.

if we had used a ratio limit of 1.00, we would have made 593 bets for a profit of 61.35, with a precision of 59% correct. This would have required a total stake of 1017 and profit ratio of 6.0%.


End

LS0tDQp0aXRsZTogIkVQTCBEYXRhIE1vZGVsbGluZyBmb3IgQXdheSBXaW4gQmV0cyBhbmQgTGF5cyB1c2luZyBMb2dpc3RpYyBSZWdyZXNzaW9uIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KVGhpcyBpcyBwYXJ0IG9mIGEgc2VyaWVzIG9mIHBhZ2VzIHJlbGF0ZWQgdG8gRVBMIEF3YXkgV2luczogIA0KDQoqIFtFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzXShodHRwczovL3JwdWJzLmNvbS9HYXJldGhDaGFkL0VQTF9FREEpDQoqIERhdGEgTW9kZWxsaW5nICh0aGlzIHBhZ2UpDQoqIFtCZXR0aW5nIFN0cmF0ZWdpZXNdKGh0dHBzOi8vcnB1YnMuY29tL0dhcmV0aENoYWQvRVBMX3N0cmF0ZWd5KQ0KDQoNCkFmdGVyIHRoZSBleHBsb3JhdG9yeSBkYXRhIGFuYWx5c2lzLCB3ZSB3aWxsIG5vdyBpbnZlc3RpZ2F0ZSBtb2RlbGxpbmcgZm9yIEVQTCBkYXRhICh1c2luZyB0aWR5bW9kZWxzKS4gVGhlIGF2YWlsYWJsZSBkYXRhIHNldCBjb250YWlucyA2NTA4IG1hdGNoZXMuIFdlIHdpbGwgcmVtb3ZlIHRoZSBsYXRlc3QgMjAlIG9mIG1hdGNoZXMgZm9yIHVzZSBpbiBhc3Nlc3NpbmcgcGVyZm9ybWFuY2UgYXMgYSB0ZXN0IHNldC4gSGVyZSBhcmUgdGhlIGZpcnN0IDEwIHJvd3Mgb2YgdGhlIGRhdGEuICANCg0KYGBge3IgSW5pdGlhbGlzZSBhbmQgTG9hZCBEYXRhLCBpbmNsdWRlPUZBTFNFfQ0Kcm0obGlzdCA9IGxzKCkpDQoNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeSh0aWR5bW9kZWxzKQ0KbGlicmFyeSh0dW5lKQ0KbGlicmFyeSh3b3JrZmxvd3MpDQoNCm9wdGlvbnModGlkeW1vZGVscy5kYXJrID0gVFJVRSkNCg0KbG9hZChoZXJlOjpoZXJlKCJkYXRhL2ludGVyaW0vRW5fZmVhdHVyZXMuUkRhdGEiKSkNCg0Kb3JpZ19yb3dzIDwtIG5yb3coRW5fZmVhdHVyZXMpDQpFbl9mZWF0dXJlcyA8LSBFbl9mZWF0dXJlcyAlPiUNCiAgZmlsdGVyKGlzLm5hKHRvcDZfcGVyZkgpID09IEZBTFNFLA0KICAgICAgICAgaXMubmEodG9wNl9wZXJmQSkgPT0gRkFMU0UpDQoNCiMgdmFsX3NldCA8LSBFbl9mZWF0dXJlc1s2MDAxOjY1MDgsIF0NCiMgRW5fZmVhdHVyZXMgPC0gRW5fZmVhdHVyZXNbMTo2MDAwLCBdDQoNCmBgYA0KDQpgYGB7ciBGdW5jdGlvbnMsIGluY2x1ZGU9RkFMU0V9DQphZGRfZmVhdHVyZXMgPC0gZnVuY3Rpb24oZGYpew0KICANCiAgIyBhZGQgRGlzdCA8NTAgYW5kID4zMTANCiAgIyBkZiA8LSBkZiAlPiUNCiAgIyAgIG11dGF0ZShEaXN0XzUwID0gYXMubnVtZXJpYyhEaXN0IDwgNTApLCANCiAgIyAgICAgICAgICBEaXN0XzMxMCA9IGFzLm51bWVyaWMoRGlzdCA+IDMxMCkpDQogIA0KICAjIHN1bW1lZCBmZWF0dXJlcw0KICBkZiA8LSBkZiAlPiUNCiAgICBtdXRhdGUoc3VtX0hTVCA9IExhc3RIU1QxICsgTGFzdEhTVDIgKyBMYXN0SFNUMyArIExhc3RIU1Q0LA0KICAgICAgICAgICBzdW1fSEMgPSBMYXN0SEMxICsgTGFzdEhDMiArIExhc3RIQzMgKyBMYXN0SEM0LA0KICAgICAgICAgICBzdW1fSEYgPSBMYXN0SEYxICsgTGFzdEhGMiArIExhc3RIRjMgKyBMYXN0SEY0LA0KICAgICAgICAgICBzdW1fSEdTID0gTGFzdEhHUzEgKyBMYXN0SEdTMiArIExhc3RIR1MzICsgTGFzdEhHUzQsDQogICAgICAgICAgIHN1bV9IR0MgPSBMYXN0SEdDMSArIExhc3RIR0MyICsgTGFzdEhHQzMgKyBMYXN0SEdDNCwNCiAgICAgICAgICAgc3VtX0FTVCA9IExhc3RBU1QxICsgTGFzdEFTVDIgKyBMYXN0QVNUMyArIExhc3RBU1Q0LA0KICAgICAgICAgICBzdW1fQUMgPSBMYXN0QUMxICsgTGFzdEFDMiArIExhc3RBQzMgKyBMYXN0QUM0LA0KICAgICAgICAgICBzdW1fQUYgPSBMYXN0QUYxICsgTGFzdEFGMiArIExhc3RBRjMgKyBMYXN0QUY0LA0KICAgICAgICAgICBzdW1fQUdTID0gTGFzdEFHUzEgKyBMYXN0QUdTMiArIExhc3RBR1MzICsgTGFzdEFHUzQsDQogICAgICAgICAgIHN1bV9BR0MgPSBMYXN0QUdDMSArIExhc3RBR0MyICsgTGFzdEFHQzMgKyBMYXN0QUdDNCwNCiAgICAgICAgICAgc3VtX0hvcHBTVCA9IExhc3RIb3BwU1QxICsgTGFzdEhvcHBTVDIgKyBMYXN0SG9wcFNUMyArIExhc3RIb3BwU1Q0LA0KICAgICAgICAgICBzdW1fSG9wcEMgPSBMYXN0SG9wcEMxICsgTGFzdEhvcHBDMiArIExhc3RIb3BwQzMgKyBMYXN0SG9wcEM0LA0KICAgICAgICAgICBzdW1fSG9wcEYgPSBMYXN0SG9wcEYxICsgTGFzdEhvcHBGMiArIExhc3RIb3BwRjMgKyBMYXN0SG9wcEY0LA0KICAgICAgICAgICBzdW1fQW9wcFNUID0gTGFzdEFvcHBTVDEgKyBMYXN0QW9wcFNUMiArIExhc3RBb3BwU1QzICsgTGFzdEFvcHBTVDQsDQogICAgICAgICAgIHN1bV9Bb3BwQyA9IExhc3RBb3BwQzEgKyBMYXN0QW9wcEMyICsgTGFzdEFvcHBDMyArIExhc3RBb3BwQzQsDQogICAgICAgICAgIHN1bV9Bb3BwRiA9IExhc3RBb3BwRjEgKyBMYXN0QW9wcEYyICsgTGFzdEFvcHBGMyArIExhc3RBb3BwRjQpDQogIA0KICByZXR1cm4oZGYpDQp9DQoNCm1ldHJpY3NfcGxvdCA8LSBmdW5jdGlvbihtb2RlbF9maXQsIG1ldHJpYyl7DQogIA0KICBkYXRhIDwtIG1vZGVsX2ZpdCQubWV0cmljcw0KICBwYXJhbXMgPC0gbmFtZXMoZGF0YVtbMV1dKVshKG5hbWVzKGRhdGFbWzFdXSkgJWluJSBuYW1lcyhkYXRhW1sxXV0pW2dyZXAoIl5cXC4iLCBuYW1lcyhkYXRhW1sxXV0pKV0pXQ0KICANCiAgZml0X21ldHJpY3MgPC0gdW5pcXVlKGRhdGFbWzFdXSQubWV0cmljKQ0KICANCiAgaWYgKCEobWV0cmljICVpbiUgZml0X21ldHJpY3MpKXsNCiAgICByZXR1cm4oIm5vIG1ldHJpYyBieSB0aGF0IG5hbWUiKQ0KICB9DQogIA0KICBtZWFuX2RhdGEgPC0gZGF0YVtbMV1dICU+JSBzZWxlY3QoLS5lc3RpbWF0ZSkNCiAgDQogIG1lYW5fZGF0YSQuZXN0aW1hdGUgPC0gZGF0YSAlPiUNCiAgICBtYXAoIi5lc3RpbWF0ZSIpICU+JQ0KICAgIHBtYXAoLmYgPSBtZWFuKSAlPiUNCiAgICB1bmxpc3QoKQ0KICANCiAgcGxvdF9kYXRhIDwtIG1lYW5fZGF0YSAlPiUNCiAgICBmaWx0ZXIoLm1ldHJpYyA9PSBtZXRyaWMpICU+JQ0KICAgIHBpdm90X2xvbmdlcihjb2xzID0gYWxsX29mKHBhcmFtcyksIG5hbWVzX3RvID0gInBhcmFtIiwgdmFsdWVzX3RvID0gInZhbHVlIikNCiAgDQogIHBsb3QgPC0gZ2dwbG90KHBsb3RfZGF0YSwgYWVzKHZhbHVlLCAuZXN0aW1hdGUpKSArIGdlb21fcG9pbnQoKSArDQogICAgdGhlbWVfYncoKSArIGZhY2V0X3dyYXAofiBwYXJhbSwgc2NhbGVzID0gImZyZWVfeCIpICsgbGFicyh5ID0gbWV0cmljKQ0KICANCiAgcmV0dXJuKHBsb3QpDQp9DQoNCg0KYGBgDQoNCmBgYHtyIGVjaG89RkFMU0V9DQpoZWFkKEVuX2ZlYXR1cmVzICU+JSBzZWxlY3QoSG9tZVRlYW0sIEF3YXlUZWFtLCBEYXRlLCBGVEhHLCBGVEFHLCBIUywgSFNULCBIRiwgSEMsIEhZLCBBUywgQVNULCBBRiwgQUMsIEFZKSwgMTApDQpgYGANCg0KV2Ugd2lsbCByZW1vdmUgcm93cyB3aXRoIG1pc3NpbmcgZGF0YSBmcm9tIHNlbGVjdGVkIGZlYXR1cmVzLiBXZSBsb3NlIGByIHJvdW5kKCgoMSAtIChucm93KEVuX2ZlYXR1cmVzKSAvIG9yaWdfcm93cykpICogMTAwKSwgMClgJSBvZiB0aGUgZGF0YSBieSByZW1vdmluZyBtaXNzaW5nIHJvd3MuICANCg0KIyMgPHNwYW4gc3R5bGU9ImNvbG9yOnRlYWw7Ij5GZWF0dXJlIENyZWF0aW9uPC9zcGFuPiAgDQoNCldlIGNyZWF0ZSBuZXcgZmVhdHVyZXMgZm9yICoqU3VtbWVkIEZlYXR1cmVzKiosIGkuZS4gc3VtIG9mIHRoZSBsYXN0IDQgc2hvdHMgb24gdGFyZ2V0LCBjb3JuZXJzLCBmb3VscywgZ29hbHMgc2NvcmVkLCBnb2FscyBjb25jZWRlZCBmb3IgdGhlIEhvbWUgdGVhbSwgQXdheSB0ZWFtIGFuZCB0aGVpciBvcHBvbmVudHMuICANCg0KDQpgYGB7ciBGaWx0ZXIgYW5kIE5ldyBGZWF0dXJlcywgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCkVuX2ZlYXR1cmVzIDwtIEVuX2ZlYXR1cmVzICU+JQ0KICBtdXRhdGUoU2Vhc29uID0gaW5kZXggJS8lIDEwMDAsDQogICAgICAgICBBd2F5V2luID0gYXMuZmFjdG9yKEF3YXlXaW4pKQ0KDQpFbl9mZWF0dXJlcyA8LSBhZGRfZmVhdHVyZXMoRW5fZmVhdHVyZXMpDQoNCmBgYA0KDQojIyA8c3BhbiBzdHlsZT0iY29sb3I6dGVhbDsiPlRha2Ugb3V0IFRlc3QgRGF0YTwvc3Bhbj4gIA0KDQpXZSByZW1vdmUgdGhlIGZpbmFsIDIwJSBvZiByZXN1bHRzIHRvIGFjdCBhcyB0aGUgdGVzdCBkYXRhLiBXZSBhbHNvIHJhbmRvbWx5IGRlZmluZSB0aGUgc3RyYXRpZmllZCA1LWZvbGQgY3Jvc3N2YWxpZGF0aW9uIHNwbGl0cyBmb3IgdGhlIHRyYWluaW5nIGRhdGEuICAgIA0KDQpgYGB7ciBSZW1vdmUgVGVzdCBTZXRzLCBlY2hvPUZBTFNFfQ0KdGltZV9zcGxpdCA8LSBFbl9mZWF0dXJlcyAlPiUNCiAgaW5pdGlhbF90aW1lX3NwbGl0KHByb3AgPSA0LzUsIGxhZyA9IDApDQoNCnRlc3QgPC0gdGVzdGluZyh0aW1lX3NwbGl0KQ0KdHJhaW4gPC0gdHJhaW5pbmcodGltZV9zcGxpdCkNCmN2IDwtIHZmb2xkX2N2KHRyYWluLCB2ID0gNSwgc3RyYXRhID0gIkF3YXlXaW4iKQ0KDQpjYXQoIlRyYWluaW5nIGRhdGEgcm93cyA9IiwgbnJvdyh0cmFpbiksICJcbiIpDQpjYXQoIlByb3BvcnRpb24gb2YgQXdheSBXaW5zID0iLCByb3VuZChtZWFuKGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHRyYWluJEF3YXlXaW4pKSksIDMpLCAiXG4iKQ0KDQpgYGANCg0KDQojIyA8c3BhbiBzdHlsZT0iY29sb3I6dGVhbDsiPlNldCB1cCBQcmUtdHJlYXRtZW50IFJlY2lwZXM8L3NwYW4+ICANCg0KRmlyc3RseSwgd2UgZGVmaW5lIHRoZSB2YXJpYWJsZXMgYW5kIG1vZGVsIGZvcm11bGEuICANCg0KYGBge3IgSW5jbHVkZWQgVmFyaWFibGVzLCBpbmNsdWRlPUZBTFNFfQ0KDQp2YXJfc2V0XzEgPC0gYygic3VtX0hTVCIsICJzdW1fSEMiLCAic3VtX0hHUyIsICJzdW1fSEdDIiwgInN1bV9BU1QiLCAic3VtX0FDIiwgInN1bV9BRiIsICJzdW1fQUdTIiwgInN1bV9BR0MiKQ0KDQp2YXJfc2V0XzIgPC0gYygic3VtX0hvcHBTVCIsICJzdW1fSG9wcEMiLCAic3VtX0FvcHBTVCIsICJzdW1fQW9wcEMiKQ0KDQp2YXJfc2V0XzMgPC0gYygid2lucGNfSCIsICJ3aW5wY19BIiwgInRvcDZfcGVyZkgiLCAidG9wNl9wZXJmQSIsICJEaXN0IiwgIkRhdGUiLCAiSG9tZUZpbjEiLCAiSG9tZUZpbjIiLCAiQXdheUZpbjEiLCANCiAgICAgICAgICAgICAgICJBd2F5RmluMiIpDQoNCnZhcl9zZXQgPC0gYyh2YXJfc2V0XzEsIHZhcl9zZXRfMiwgdmFyX3NldF8zKQ0KDQpmb3JtdWxhIDwtIGFzLmZvcm11bGEocGFzdGUoIkF3YXlXaW4iLCBwYXN0ZSh2YXJfc2V0LCBjb2xsYXBzZSA9ICIgKyAiKSwgc2VwID0gIiB+ICIpKQ0KDQpgYGANCg0KV2UgaGF2ZSBhIGZvcm11bGEgb2YgW2ByIHBhc3RlKCJBd2F5V2luIiwgcGFzdGUodmFyX3NldCwgY29sbGFwc2UgPSAiICsgIiksIHNlcCA9ICIgfiAiKWBdLiAgDQoNClRoZW4gd2UgZGVmaW5lIHRoZSBwcmV0cmVhdG1lbnQgcmVjaXBlcy4gIFRoaXMgaW5jbHVkZXMgcmVtb3ZpbmcgY29ycmVsYXRlZCBudW1lcmljIHZhcmlhYmxlcywgbm9ybWFsaXppbmcgYWxsIG51bWVyaWMgdmFyaWFibGVzIGFuZCB0dXJuaW5nIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyBpbnRvIGR1bW15IHZhcmlhYmxlcy4gQXMgd2VsbCBhcyBNb250aCwgd2Ugd2lsbCBjcmVhdGUgZHVtbWllcyBmb3IgRGF5IG9mIFdlZWsuICANCg0KYGBge3IgUHJldHJlYXQgMX0NCnJlY2lwZSA8LQ0KICB0cmFpbiAlPiUNCiAgcmVjaXBlKGZvcm11bGEpICU+JQ0KICBzdGVwX2NvcnIoYWxsX251bWVyaWMoKSkgJT4lDQogIHN0ZXBfbm9ybWFsaXplKGFsbF9udW1lcmljKCkpICU+JQ0KICBzdGVwX2RhdGUoRGF0ZSwgZmVhdHVyZXMgPSBjKCJkb3ciLCAibW9udGgiKSkgJT4lDQogIHN0ZXBfcm0oRGF0ZSkgJT4lDQogIHN0ZXBfZHVtbXkoRGF0ZV9kb3csIERhdGVfbW9udGgpDQoNCmBgYA0KDQpXaGF0IGRvZXMgdGhlIHN1YnNlcXVlbnQgdHJhaW5pbmcgZnJhbWUgbG9vayBsaWtlPyAgDQoNCg0KYGBge3IgZWNobz1GQUxTRX0NCnRyYWluX3ByZXAgPC0gcmVjaXBlICU+JSBwcmVwKCkgJT4lIGp1aWNlKCkNCmhlYWQodHJhaW5fcHJlcCwgMTApDQpgYGANCg0KIyMgPHNwYW4gc3R5bGU9ImNvbG9yOnRlYWw7Ij5GZWF0dXJlIEltcG9ydGFuY2U8L3NwYW4+ICANCg0KVG8gZXN0aW1hdGUgdGhlIHJlbGF0aXZlIGltcG9ydGFuY2Ugb2YgdGhlIGZlYXR1cmVzLCB3ZSBmaXQgYW4gdW5vcHRpbWlzZWQgcmFuZG9tIGZvcmVzdCBtb2RlbCB0byB0aGUgdHJhaW5pbmcgZGF0YSBhbmQgZGV0ZXJtaW5lIHZhcmlhYmxlIGltcG9ydGFuY2UgZnJvbSB0aGUgbW9kZWwuICANCg0KYGBge3IgVmFyaWFibGUgSW1wb3J0YW5jZSwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCnNpbXBsZV9yZl9tb2RlbCA8LSANCiAgcmFuZF9mb3Jlc3QodHJlZXMgPSAyMDApICU+JSANCiAgc2V0X2VuZ2luZSgicmFuZ2VyIiwgaW1wb3J0YW5jZSA9ICJpbXB1cml0eSIpICU+JSANCiAgc2V0X21vZGUoImNsYXNzaWZpY2F0aW9uIikNCg0KcmZfbW9kZWxfZml0IDwtIHNpbXBsZV9yZl9tb2RlbCAlPiUNCiAgZml0KEF3YXlXaW4gfiAuLCBkYXRhID0gdHJhaW5fcHJlcCkNCg0KaW1wX3Rlcm1zIDwtIHJmX21vZGVsX2ZpdCRmaXQkdmFyaWFibGUuaW1wb3J0YW5jZQ0KDQppbXBfcGxvdF9kZiA8LSBkYXRhLmZyYW1lKHZhcmlhYmxlID0gbmFtZXMoaW1wX3Rlcm1zKSwgaW1wb3J0YW5jZSA9IGltcF90ZXJtcykNCmltcF9wbG90X2RmJHZhcmlhYmxlIDwtIGFzLmNoYXJhY3RlcihpbXBfcGxvdF9kZiR2YXJpYWJsZSkNCg0KaW1wX3Bsb3QgPC0gZ2dwbG90KGltcF9wbG90X2RmLCBhZXModmFyaWFibGUsIGltcG9ydGFuY2UpKSArIGdlb21fcG9pbnQoKSArIGNvb3JkX2ZsaXAoKSArDQogIHRoZW1lX2J3KCkgKyBnZ3RpdGxlKCJSZWxhdGl2ZSBJbXBvcnRhbmNlIG9mIFZhcmlhYmxlcyBmcm9tIFNpbXBsZSBSYW5kb20gRm9yZXN0IE1vZGVsIikNCmdnc2F2ZShoZXJlOjpoZXJlKCJwbG90cy9pbXBfcGxvdC5wbmciKSwgZHBpID0gMjAwKQ0KDQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJwbG90cy9pbXBfcGxvdC5wbmciKSkNCmBgYA0KDQpXZSBjYW4gc2VlIHRoYXQgYWxsIHRoZSBEYXRlIHZhcmlhYmxlcyBoYXZlIHJlbGF0aXZlbHkgbGl0dGxlIGltcG9ydGFuY2Ugd2hlbiBwcmVkaWN0aW5nIEF3YXkgd2lucy4gV2Ugd2lsbCByZW1vdmUgdGhlIERhdGUgdmFyaWFibGVzIGdvaW5nIGZvcndhcmQuICANCg0KIyMgPHNwYW4gc3R5bGU9ImNvbG9yOnRlYWw7Ij5HZW5lcmFsaXplZCBMaW5lYXIgTW9kZWw8L3NwYW4+ICANCg0KV2Ugd2lsbCBjcmVhdGUgYSB0dW5pbmcgd29ya2Zsb3cgaW4gb3JkZXIgdG8gb3B0aW1pc2UgaHlwZXJwYXJhbWV0ZXJzIGZvciBvdXIgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbC4gQXMgZXhwbGFpbmVkIGFib3ZlLCB3ZSB3aWxsIGZpcnN0IHJlZGVmaW5lIG91ciBwcmV0cmVhdG1lbnQgcmVjaXBlIHRvIHJlbW92ZSB0aGUgRGF0ZSBmZWF0dXJlcy4gIA0KDQpgYGB7ciBQcmV0cmVhdCAyfQ0KcmVjaXBlIDwtDQogIHRyYWluICU+JQ0KICByZWNpcGUoZm9ybXVsYSkgJT4lDQogIHN0ZXBfY29ycihhbGxfbnVtZXJpYygpKSAlPiUNCiAgc3RlcF9ub3JtYWxpemUoYWxsX251bWVyaWMoKSkgJT4lDQogIHN0ZXBfcm0oRGF0ZSkNCg0KYGBgDQoNCldlIHdpbGwgYmUgb3B0aW1pc2luZyAqKm1peHR1cmUqKiBhbmQgKipwZW5hbHR5KiogdmFsdWVzIGZvciBvdXIgZ2xtbmV0IG1vZGVsLCB1c2luZyBjcm9zc3ZhbGlkYXRpb24gcmVzdWx0cyBvZiBvdXIgdHJhaW5pbmcgZGF0YS4gQVVDIGZvciB0aGUgUk9DIGN1cnZlIGFuZCBhY2N1cmFjeSBtZXRyaWNzIHdpbGwgYmUgZXZhbHVhdGVkIGZvciBlYWNoIHNldCBvZiBwcmVkaWN0aW9ucy4gIA0KDQpgYGB7ciBXb3JrZmxvdyBHTE19DQptb2RlbF9nbG0gPC0gDQogIGxvZ2lzdGljX3JlZyhwZW5hbHR5ID0gdHVuZSgpLCBtaXh0dXJlID0gdHVuZSgpKSAlPiUgDQogIHNldF9lbmdpbmUoImdsbW5ldCIpDQoNCmdyaWRfZ2xtIDwtIA0KICBncmlkX21heF9lbnRyb3B5KA0KICAgIHBlbmFsdHkocmFuZ2UgPSBjKDAuMDAxLCAwLjEpLCB0cmFucyA9IE5VTEwpLA0KICAgIG1peHR1cmUocmFuZ2UgPSBjKDAsIDEpKSwNCiAgICBzaXplID0gMzApDQoNCm15X21ldHJpY3MgPC0gbWV0cmljX3NldChyb2NfYXVjLCBhY2N1cmFjeSkNCg0KYGBgDQoNCg0KYGBge3IgVHVuZSBHTE0sIGluY2x1ZGU9RkFMU0V9DQp3b3JrZmxvd19nbG0gPC0gDQogIHdvcmtmbG93KCkgJT4lIA0KICBhZGRfcmVjaXBlKHJlY2lwZSkgJT4lDQogIGFkZF9tb2RlbChtb2RlbF9nbG0pDQoNCmdsbV9maXQgPC0gdHVuZV9ncmlkKA0KICB3b3JrZmxvd19nbG0sDQogIHJlc2FtcGxlcyA9IGN2LA0KICBncmlkID0gZ3JpZF9nbG0sDQogIG1ldHJpY3MgPSBteV9tZXRyaWNzLA0KICBjb250cm9sID0gY29udHJvbF9ncmlkKHZlcmJvc2UgPSBUUlVFKQ0KKQ0KYGBgDQoNCkFmdGVyIGNyb3NzdmFsaWRhdGluZyBmb3IgYSByYW5nZSBvZiAqKm1peHR1cmUqKiBhbmQgKipwZW5hbHR5KiogdmFsdWVzLCBsZXQncyBwbG90IHZhbHVlcyBvZiBST0MgQVVDIGFuZCBsaXN0IHRoZSBiZXN0IG1vZGVscy4NCg0KYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCnJvY19wbG90IDwtIG1ldHJpY3NfcGxvdChnbG1fZml0LCBtZXRyaWMgPSAicm9jX2F1YyIpDQpnZ3NhdmUoaGVyZTo6aGVyZSgicGxvdHMvcGxvdF8xLnBuZyIpLCBoZWlnaHQgPSA1LCBkcGkgPSAyMDApDQoNCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoInBsb3RzL3Bsb3RfMS5wbmciKSkNCg0Kc2hvd19iZXN0KGdsbV9maXQsIG1ldHJpYyA9ICJyb2NfYXVjIikNCg0KYGBgDQoNCk5vdyBsZXQncyBsb29rIGF0IHRoZSBhY2N1cmFjeSBtZXRyaWNzLiAgDQoNCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQphY2NfcGxvdCA8LSBtZXRyaWNzX3Bsb3QoZ2xtX2ZpdCwgbWV0cmljID0gImFjY3VyYWN5IikNCmdnc2F2ZShoZXJlOjpoZXJlKCJwbG90cy9wbG90XzIucG5nIiksIGhlaWdodCA9IDUsIGRwaSA9IDIwMCkNCg0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgicGxvdHMvcGxvdF8yLnBuZyIpKQ0Kc2hvd19iZXN0KGdsbV9maXQsIG1ldHJpYyA9ICJhY2N1cmFjeSIpDQoNCmBgYA0KDQpXZSBzZWUgc29tZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZSBtb2RlbHMuIExvd2VyICoqbWl4dHVyZSoqIGFuZCAqKnBlbmFsdHkqKiB2YWx1ZXMgc2VlbSB0byBnaXZlIG1vcmUgY29uc2lzdGVudGx5IGhpZ2ggQVVDIHJlc3VsdHMuIFRvIG9idGFpbiB0aGUgbW9zdCBnZW5lcmFsIG1vZGVsLCBpdCBpcyBiZXR0ZXIgdG8gY2hvb3NlIGEgaGlnaGVyIHBlbmFsdHkgdmFsdWUgdGhhdCBnaXZlcyBhIHBlcmZvcm1hbmNlIHNpbWlsYXIgdG8gdGhlIGJlc3QgcGVyZm9ybWFuY2UuIEluIHRlcm1zIG9mIEFVQywgYSBwZW5hbHR5IG9mIGFyb3VuZCAwLjAzIHdvdWxkIHNlZW0gdG8gYmUgc3VpdGFibGUuIE5vdyB3ZSB3aWxsIGNob29zZSB2YWx1ZXMgb2YgbWl4dHVyZSA9IDAuMyBhbmQgcGVuYWx0eSA9IDAuMDMsIHRyYWluIGEgbW9kZWwgdXNpbmcgdGhlIHRyYWluaW5nIGRhdGEgYW5kIGZpdCB0aGUgbW9kZWwgdG8gdGhlIHRlc3QgZGF0YS4gSG93IGRvZXMgdGhlIFJPQyBjdXJ2ZSBsb29rIGZvciB0aGUgdGVzdCBzZXQgYW5kIHdoYXQgaXMgdGhlIEFVQyBvZiB0aGUgZml0PyAgDQoNCg0KYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCnR1bmVkX2dsbSA8LQ0KICB3b3JrZmxvd19nbG0gJT4lIA0KICAjIGZpbmFsaXplX3dvcmtmbG93KHNlbGVjdF9iZXN0KGdsbV9maXQsIG1ldHJpYyA9ICJyb2NfYXVjIikpICU+JSANCiAgZmluYWxpemVfd29ya2Zsb3codGliYmxlKHBlbmFsdHkgPSAwLjAzLCBtaXh0dXJlID0gMC4zKSkgJT4lIA0KICBmaXQoZGF0YSA9IHRyYWluKQ0KDQpwcmVkX2dsbSA8LSBwcmVkaWN0KHR1bmVkX2dsbSwgdGVzdCwgdHlwZSA9ICJwcm9iIikgJT4lDQogIGJpbmRfY29scyhwcmVkaWN0KHR1bmVkX2dsbSwgdGVzdCkpICU+JQ0KICBiaW5kX2NvbHModGVzdCAlPiUgc2VsZWN0KEF3YXlXaW4sIGluZGV4LCBCYkF2QSkpDQoNCm1ldHJpY3NfZ2xtIDwtIHByZWRfZ2xtICU+JQ0KICBtZXRyaWNzKHRydXRoID0gQXdheVdpbiwgZXN0aW1hdGUgPSAucHJlZF9jbGFzcywgLnByZWRfMSkNCg0Kcm9jX3Jlc3VsdHMgPC0gcHJlZF9nbG0gJT4lIA0KICByb2NfY3VydmUodHJ1dGggPSBBd2F5V2luLCAucHJlZF8xKSAlPiUNCiAgbXV0YXRlKGZhbHNlX3BvcyA9IDEgLSBzcGVjaWZpY2l0eSkNCg0Kcm9jX3Bsb3QgPC0gZ2dwbG90KHJvY19yZXN1bHRzLCBhZXMoZmFsc2VfcG9zLCBzZW5zaXRpdml0eSkpICsgZ2VvbV9wb2ludChzaXplID0gMC41KSArDQogIHRoZW1lX2J3KCkgKyBnZ3RpdGxlKCJST0MgQ3VydmUgZm9yIFRlc3QgRGF0YSIpICsgbGFicyh4ID0gIjEgLSBzcGVjaWZpY2l0eSIpICsNCiAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gYygwLCAwKSwgc2xvcGUgPSAxLCBsaW5ldHlwZSA9IDIpDQpnZ3NhdmUoaGVyZTo6aGVyZSgicGxvdHMvcGxvdF8zLnBuZyIpLCBoZWlnaHQgPSA1LCB3aWR0aCA9IDUpDQoNCmNhdCgiQVVDIHZhbHVlIGZvciBiZXN0IG1vZGVsIGlzIiwgbWV0cmljc19nbG0kLmVzdGltYXRlW3doaWNoKG1ldHJpY3NfZ2xtJC5tZXRyaWMgPT0gInJvY19hdWMiKV0pDQoNCmBgYA0KPHAgYWxpZ249ImNlbnRlciI+DQohW10oRDovRG9jdW1lbnRzL3dvcmsvRm9vdGJhbGwvcGxvdHMvcGxvdF8zLnBuZyl7d2lkdGg9NTAwcHh9DQo8L3A+DQoNCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjp0ZWFsOyI+UG90ZW50aWFsIEJldHRpbmcgU3RyYXRlZ2llczwvc3Bhbj4gIA0KDQpUaGVyZSBhcmUgdHdvIG9wdGlvbnMgZm9yIGJldHRpbmcgb24gbWF0Y2hlcywgZWl0aGVyICpCZXQqIHRoZSBBd2F5IHdpbiAocHJlZGljdCBpdCB3aWxsIGhhcHBlbikgb3IgKkxheSogdGhlIEF3YXkgd2luIChwcmVkaWN0IGl0IHdvbid0IGhhcHBlbikuICANCg0KIyMjIDxzcGFuIHN0eWxlPSJjb2xvcjpzdGVlbGJsdWU7Ij5CZXR0aW5nIFByb2JhYmlsaXR5IExpbWl0czwvc3Bhbj4gIA0KDQpPbmUgc3RyYXRlZ3kgZm9yIGJldHRpbmcgaXMgdG8gZGVmaW5lIGEgYmV0dGluZyBsaW1pdCwgd2hlcmUgYmV0cyBhcmUgcGxhY2VkIHdoZW4gdGhlIHByZWRpY3RlZCBwcm9iYWJpbGl0eSBvZiBzdWNjZXNzIGlzIGdyZWF0ZXIgdGhhbiB0aGUgZGVmaW5lZCBsaW1pdC4gSWYgd2UgbG9vayBhdCB0aGUgdGVzdCBkYXRhLCB3ZSBjYW4gc2VlIHdoYXQgdGhlIG91dGNvbWUgd291bGQgaGF2ZSBiZWVuIGlmIHdlIGhhZCB1c2VkIGEgcGFydGljdWxhciBiZXR0aW5nIGxpbWl0IGZvciB0aGlzIGRhdGEuICBOb3RlIHRoYXQgdGhlcmUgaXMgbm8gZ3VhcmFudGVlIGF0IGFsbCB0aGF0IHRoZSBzYW1lIG91dGNvbWUgd291bGQgYmUgYWNoaWV2ZWQgZm9yIGZ1dHVyZSBkYXRhLiAgDQoNCioqQXdheSBXaW4gQmV0cyoqIA0KDQpMb29raW5nIGF0IGEgcmFuZ2Ugb2YgYmV0dGluZyBsaW1pdHMgZm9yIEF3YXkgV2luIEJldHMgZ2l2ZXMgdGhlIGZvbGxvd2luZyByZXN1bHRzIGZvciB0aGUgdGVzdCBzZXQuICANCg0KYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCnByZWRfZ2xtX3N1bW1hcnkgPC0gcHJlZF9nbG0gJT4lDQogIG11dGF0ZShBd2F5V2luID0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoQXdheVdpbikpLA0KICAgICAgICAgQXdheUxheU9kZHMgPSAoKChCYkF2QSBeIDIpICogMC4wMDUwNTg3KSArIChCYkF2QSAqIDEuMTgyODQ3NSkgLSAwLjM3ODc2NzEpLA0KICAgICAgICAgYmV0X3N0YWtlID0gMSwNCiAgICAgICAgIGltcGxfcHJvYl9iZXQgPSAxIC8gQmJBdkEsDQogICAgICAgICBiZXRfcHJvYl9yYXRpbyA9IC5wcmVkXzEgLyBpbXBsX3Byb2JfYmV0LCANCiAgICAgICAgIGxheV9zdGFrZSA9IEF3YXlMYXlPZGRzIC0gMSwNCiAgICAgICAgIGltcGxfcHJvYl9sYXkgPSAxIC8gQXdheUxheU9kZHMsDQogICAgICAgICBpbXBsX2xheSA9IDEgLSBpbXBsX3Byb2JfbGF5LA0KICAgICAgICAgbGF5X3Byb2JfcmF0aW8gPSAucHJlZF8wIC8gaW1wbF9sYXksIA0KICAgICAgICAgYmV0X3Byb2ZpdCA9IChBd2F5V2luICogKEJiQXZBIC0gMSkpIC0gKDEgLSBBd2F5V2luKSwgDQogICAgICAgICBsYXlfcHJvZml0ID0gKCgxIC0gQXdheVdpbikgKiAwLjk1KSAtIChBd2F5V2luICogKEF3YXlMYXlPZGRzIC0gMSkpKQ0KDQpnbG1fYmV0c19zdW1tYXJ5IDwtIHByZWRfZ2xtX3N1bW1hcnkgJT4lDQogIGFycmFuZ2UoLS5wcmVkXzEpICU+JQ0KICBtdXRhdGUodG90YWxfY29ycmVjdCA9IGN1bXN1bShBd2F5V2luKSwNCiAgICAgICAgIHRvdGFsX2JldHMgPSBzZXFfbGVuKG5yb3cocHJlZF9nbG0pKSwNCiAgICAgICAgIGN1bV9wcmVjaXNpb24gPSB0b3RhbF9jb3JyZWN0IC8gdG90YWxfYmV0cywNCiAgICAgICAgIGN1bV9wcm9maXQgPSBjdW1zdW0oYmV0X3Byb2ZpdCksDQogICAgICAgICBjdW1fc3Rha2UgPSBjdW1zdW0oYmV0X3N0YWtlKSwNCiAgICAgICAgIHByb2ZfcGVyX2JldCA9IGN1bV9wcm9maXQgLyB0b3RhbF9iZXRzKQ0KDQpnbG1fbGF5c19zdW1tYXJ5IDwtIHByZWRfZ2xtX3N1bW1hcnkgJT4lDQogIGFycmFuZ2UoLS5wcmVkXzApICU+JQ0KICBtdXRhdGUodG90YWxfY29ycmVjdCA9IGN1bXN1bSgxIC0gQXdheVdpbiksDQogICAgICAgICB0b3RhbF9iZXRzID0gc2VxX2xlbihucm93KHByZWRfZ2xtKSksDQogICAgICAgICBjdW1fcHJlY2lzaW9uID0gdG90YWxfY29ycmVjdCAvIHRvdGFsX2JldHMsDQogICAgICAgICBjdW1fcHJvZml0ID0gY3Vtc3VtKGxheV9wcm9maXQpLA0KICAgICAgICAgY3VtX3N0YWtlID0gY3Vtc3VtKGxheV9zdGFrZSksDQogICAgICAgICBwcm9mX3Blcl9iZXQgPSBjdW1fcHJvZml0IC8gdG90YWxfYmV0cykNCg0KYmFzZV9sYXlzX3N1bW1hcnkgPC0gcHJlZF9nbG1fc3VtbWFyeSAlPiUNCiAgYXJyYW5nZSgtaW1wbF9sYXkpICU+JQ0KICBtdXRhdGUodG90YWxfY29ycmVjdCA9IGN1bXN1bSgxIC0gQXdheVdpbiksDQogICAgICAgICB0b3RhbF9iZXRzID0gc2VxX2xlbihucm93KHByZWRfZ2xtKSksDQogICAgICAgICBjdW1fcHJlY2lzaW9uID0gdG90YWxfY29ycmVjdCAvIHRvdGFsX2JldHMsDQogICAgICAgICBjdW1fcHJvZml0ID0gY3Vtc3VtKGxheV9wcm9maXQpLA0KICAgICAgICAgcHJvZl9wZXJfYmV0ID0gY3VtX3Byb2ZpdCAvIHRvdGFsX2JldHMpDQoNCg0KZ2xtX2JldHNfcGxvdF9kZiA8LSBnbG1fYmV0c19zdW1tYXJ5ICU+JQ0KICBwaXZvdF9sb25nZXIoY29scyA9IGModG90YWxfYmV0cywgY3VtX3ByZWNpc2lvbiwgY3VtX3Byb2ZpdCwgcHJvZl9wZXJfYmV0KSwgbmFtZXNfdG8gPSAibWV0cmljIiwgdmFsdWVzX3RvID0gInZhbHVlIikNCg0KZ2xtX2xheXNfcGxvdF9kZiA8LSBnbG1fbGF5c19zdW1tYXJ5ICU+JQ0KICBwaXZvdF9sb25nZXIoY29scyA9IGModG90YWxfYmV0cywgY3VtX3ByZWNpc2lvbiwgY3VtX3Byb2ZpdCwgcHJvZl9wZXJfYmV0KSwgbmFtZXNfdG8gPSAibWV0cmljIiwgdmFsdWVzX3RvID0gInZhbHVlIikNCg0KYmFzZV9sYXlzX3Bsb3RfZGYgPC0gYmFzZV9sYXlzX3N1bW1hcnkgJT4lDQogIHBpdm90X2xvbmdlcihjb2xzID0gYyh0b3RhbF9iZXRzLCBjdW1fcHJlY2lzaW9uLCBjdW1fcHJvZml0LCBwcm9mX3Blcl9iZXQpLCBuYW1lc190byA9ICJtZXRyaWMiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKQ0KDQoNCmBgYA0KDQpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KDQpnbG1fYmV0c19wbG90IDwtIGdncGxvdChnbG1fYmV0c19wbG90X2RmLCBhZXMoLnByZWRfMSwgdmFsdWUpKSArIGdlb21fcG9pbnQoc2l6ZSA9IDEpICsgDQogIGZhY2V0X3dyYXAofiBtZXRyaWMsIHNjYWxlcyA9ICJmcmVlIikgKyB0aGVtZV9idygpICsgZ2d0aXRsZSgiQmV0dGluZyBMaW1pdCBmb3IgQmV0czogTG9naXN0aWMgUmVncmVzc2lvbiIpICsgDQogIGxhYnMoeCA9ICJCZXR0aW5nIExpbWl0IikNCmdnc2F2ZShoZXJlOjpoZXJlKCJwbG90cy9wbG90XzQucG5nIiksIGRwaSA9IDIwMCkNCg0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgicGxvdHMvcGxvdF80LnBuZyIpKQ0KDQpgYGANCg0KRm9yIGV4YW1wbGUsIGlmIHdlIGhhZCB1c2VkIGEgcHJlZGljdGlvbiBsaW1pdCBvZiAwLjU1LCB3ZSB3b3VsZCBoYXZlIG1hZGUgODYgYmV0cyB3aXRoIHJlc3VsdGluZyBwcmVjaXNpb24gb2YgNzklIGNvcnJlY3QgYW5kIGEgdG90YWwgcHJvZml0IG9mIDkuMzggd2l0aCBhIG9uZSBkb2xsYXIgc3Rha2UgcGVyIGJldC4gVG90YWwgc3Rha2Ugd291bGQgaGF2ZSBiZWVuIDg2LCBzbyBwcm9maXQgcmF0aW8gd291bGQgaGF2ZSBiZWVuIDEwLjklIG9mIHRvdGFsIHN0YWtlLiAgDQoNCkZvciB0aGlzIGRhdGEsIHRoZSBiZXN0IHByb2ZpdCB3b3VsZCBoYXZlIGJlZW4gbWFkZSB3aXRoIGEgYmV0dGluZyBsaW1pdCBvZiAwLjU2IChwcm9maXQgMTYuOCUgb2Ygc3Rha2UpLiAgDQoNCg0KKipBd2F5IFdpbiBMYXlzKiogIA0KDQpMb29raW5nIGF0IGEgcmFuZ2Ugb2YgYmV0dGluZyBsaW1pdHMgZm9yIEF3YXkgV2luIExheXMgZ2l2ZXMgdGhlIGZvbGxvd2luZyByZXN1bHRzIGZvciB0aGUgdGVzdCBzZXQuIE5vdGUgdGhhdCBoaXN0b3JpYyBMYXkgb2RkcyBhcmUgbm90IGdlbmVyYWxseSBhdmFpbGFibGUsIHNvIGEgY29ycmVjdGlvbiBoYXMgYmVlbiBtYWRlIHRvIHRoZSBhdmVyYWdlIEF3YXkgd2luIG9kZHMgTGF5IG9kZHMgKGUuZy4gdGhvc2UgYXZhaWxhYmxlIGF0IEJldGZhaXIpIGFyZSBnZW5lcmFsbHkgaGlnaGVyIHRoYW4gdGhlIGF2ZXJhZ2UgQXdheSB3aW4gb2Rkcy4gIA0KDQpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KZ2xtX2xheXNfcGxvdCA8LSBnZ3Bsb3QoZ2xtX2xheXNfcGxvdF9kZiwgYWVzKC5wcmVkXzAsIHZhbHVlKSkgKyBnZW9tX3BvaW50KHNpemUgPSAxKSArIA0KICBmYWNldF93cmFwKH4gbWV0cmljLCBzY2FsZXMgPSAiZnJlZSIpICsgdGhlbWVfYncoKSArIGdndGl0bGUoIkJldHRpbmcgTGltaXQgZm9yIExheXM6IExvZ2lzdGljIFJlZ3Jlc3Npb24iKSArDQogIGxhYnMoeCA9ICJCZXR0aW5nIExpbWl0IikNCmdnc2F2ZShoZXJlOjpoZXJlKCJwbG90cy9wbG90XzUucG5nIiksIGRwaSA9IDIwMCkNCg0KIyBiYXNlX2xheXNfcGxvdCA8LSBnZ3Bsb3QoYmFzZV9sYXlzX3Bsb3RfZGYsIGFlcyhpbXBsX2xheSwgdmFsdWUpKSArIGdlb21fcG9pbnQoc2l6ZSA9IDEpICsgDQojICAgZmFjZXRfd3JhcCh+IG1ldHJpYywgc2NhbGVzID0gImZyZWUiKSArIHRoZW1lX2J3KCkgKyBnZ3RpdGxlKCJQcmVkaWN0aW9uIExpbWl0IGZvciBMYXlzOiBVc2luZyBPZGRzIE9ubHkiKQ0KIyBnZ3NhdmUoaGVyZTo6aGVyZSgicGxvdHMvcGxvdF8zLnBuZyIpLCBkcGkgPSA2MDApDQoNCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoInBsb3RzL3Bsb3RfNS5wbmciKSkNCiMga25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgicGxvdHMvcGxvdF8zLnBuZyIpKQ0KDQpgYGANCg0KQSBsaW1pdCBvZiAwLjkxIHdvdWxkIGhhdmUgZ2l2ZW4gcHJvZml0IG9mIDQ5Ljk3IGZyb20gNjQgYmV0cyB3aXRoIGEgcHJlY2lzaW9uIG9mIDk4JSBjb3JyZWN0LiAgVGhlIHRvdGFsIHJlcXVpcmVkIHN0YWtlIGZvciB0aGlzIHByb2ZpdCB3b3VsZCBoYXZlIGJlZW4gMTQxNywgc28gcHJvZml0IHJhdGlvIHdvdWxkIGhhdmUgYmVlbiAzLjUlLg0KDQojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOnN0ZWVsYmx1ZTsiPlByZWRpY3Rpb24gdG8gT2RkcyBQcm9iYWJpbGl0eSBSYXRpbzwvc3Bhbj4gIA0KDQpJZiB3ZSBjYWxjdWxhdGUgdGhlIHByb2JhYmlsaXR5IG9mIHRoZSByZXN1bHQgaW1wbGllZCBieSB0aGUgYmV0dGluZyBvZGRzIGFuZCBjb21wYXJlIHdpdGggdGhlIHByb2JhYmlsaXR5IGRldGVybWluZWQgYnkgdGhlIG1vZGVsLCB3ZSBjYW4gZXhhbWluZSB0aGUgcmF0aW8gb2YgbW9kZWwgcHJvYmFiaWxpdHkgLyBpbXBsaWVkIG9kZHMgcHJvYmFiaWxpdHkuIFRoaXMgaGFzIHRoZSBwb3RlbnRpYWwgdG8gc2hvdyB3aGVyZSB3ZSBtYXkgaGF2ZSBhbiBhZHZhbnRhZ2Ugb3ZlciB0aGUgYm9va21ha2VyIG9kZHMuICANCg0KKipBd2F5IFdpbiBCZXRzKiogIA0KDQpMZXQncyBoYXZlIGEgbG9vayBhdCBob3cgdGhlIHJhdGlvIG9mIG15IHByZWRpY3Rpb24gLyBpbXBsaWVkIGJldCBwcm9iYWJpbGl0eSBhZmZlY3RzIHRoZSBCZXQgbWV0cmljcy4NCg0KYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCg0KcmF0aW9fYmV0c19zdW1tYXJ5IDwtIHByZWRfZ2xtX3N1bW1hcnkgJT4lDQogIGFycmFuZ2UoLWJldF9wcm9iX3JhdGlvKSAlPiUNCiAgbXV0YXRlKHRvdGFsX2NvcnJlY3QgPSBjdW1zdW0oQXdheVdpbiksDQogICAgICAgICB0b3RhbF9iZXRzID0gc2VxX2xlbihucm93KHByZWRfZ2xtKSksDQogICAgICAgICBjdW1fcHJlY2lzaW9uID0gdG90YWxfY29ycmVjdCAvIHRvdGFsX2JldHMsDQogICAgICAgICBjdW1fcHJvZml0ID0gY3Vtc3VtKGJldF9wcm9maXQpLA0KICAgICAgICAgcHJvZl9wZXJfYmV0ID0gY3VtX3Byb2ZpdCAvIHRvdGFsX2JldHMpDQoNCnJhdGlvX2JldHNfcGxvdF9kZiA8LSByYXRpb19iZXRzX3N1bW1hcnkgJT4lDQogIHBpdm90X2xvbmdlcihjb2xzID0gYyh0b3RhbF9iZXRzLCBjdW1fcHJlY2lzaW9uLCBjdW1fcHJvZml0LCBwcm9mX3Blcl9iZXQpLCBuYW1lc190byA9ICJtZXRyaWMiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKQ0KDQpyYXRpb19iZXRzX3Bsb3QgPC0gZ2dwbG90KHJhdGlvX2JldHNfcGxvdF9kZiwgYWVzKGJldF9wcm9iX3JhdGlvLCB2YWx1ZSkpICsgZ2VvbV9wb2ludChzaXplID0gMSkgKyANCiAgZmFjZXRfd3JhcCh+IG1ldHJpYywgc2NhbGVzID0gImZyZWUiKSArIHRoZW1lX2J3KCkgKyB4bGltKDAsIDQpICsgDQogIGdndGl0bGUoIlByb2JhYmlsaXR5IFJhdGlvIExpbWl0IGZvciBCZXRzOiBMb2dpc3RpYyBSZWdyZXNzaW9uIikgKyBsYWJzKHggPSAiUHJvYmFiaWxpdHkgUmF0aW8iKQ0KZ2dzYXZlKGhlcmU6OmhlcmUoInBsb3RzL3Bsb3RfNi5wbmciKSwgZHBpID0gMjAwKQ0KDQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJwbG90cy9wbG90XzYucG5nIikpDQoNCmBgYA0KDQpGb3IgdGhpcyBkYXRhLCBpZiB3ZSBoYWQgdXNlZCBhIHJhdGlvIGxpbWl0IG9mIDEuOCwgd2Ugd291bGQgaGF2ZSBtYWRlIDc1IGJldHMgZm9yIGEgcHJvZml0IG9mIDM2LjczLCB3aXRoIGEgcHJlY2lzaW9uIG9mIDExJS4gU28gYSB0b3RhbCBzdGFrZSBvZiA3NSBhbmQgcHJvZml0IHJhdGlvIG9mIDQ5JS4gIA0KDQoqKkF3YXkgV2luIExheXMqKiAgDQoNCkxldCdzIGhhdmUgYSBsb29rIGF0IGhvdyB0aGUgcmF0aW8gb2YgbXkgcHJlZGljdGlvbiAvIGltcGxpZWQgbGF5IHByb2JhYmlsaXR5IGFmZmVjdHMgdGhlIExheSBtZXRyaWNzLg0KDQpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KDQpyYXRpb19sYXlzX3N1bW1hcnkgPC0gcHJlZF9nbG1fc3VtbWFyeSAlPiUNCiAgYXJyYW5nZSgtbGF5X3Byb2JfcmF0aW8pICU+JQ0KICBtdXRhdGUodG90YWxfY29ycmVjdCA9IGN1bXN1bSgxIC0gQXdheVdpbiksDQogICAgICAgICB0b3RhbF9iZXRzID0gc2VxX2xlbihucm93KHByZWRfZ2xtKSksDQogICAgICAgICBjdW1fcHJlY2lzaW9uID0gdG90YWxfY29ycmVjdCAvIHRvdGFsX2JldHMsDQogICAgICAgICBjdW1fcHJvZml0ID0gY3Vtc3VtKGxheV9wcm9maXQpLA0KICAgICAgICAgY3VtX3N0YWtlID0gY3Vtc3VtKGxheV9zdGFrZSksDQogICAgICAgICBwcm9mX3Blcl9iZXQgPSBjdW1fcHJvZml0IC8gdG90YWxfYmV0cykNCg0KcmF0aW9fbGF5c19wbG90X2RmIDwtIHJhdGlvX2xheXNfc3VtbWFyeSAlPiUNCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKHRvdGFsX2JldHMsIGN1bV9wcmVjaXNpb24sIGN1bV9wcm9maXQsIHByb2ZfcGVyX2JldCksIG5hbWVzX3RvID0gIm1ldHJpYyIsIHZhbHVlc190byA9ICJ2YWx1ZSIpDQoNCnJhdGlvX2xheXNfcGxvdCA8LSBnZ3Bsb3QocmF0aW9fbGF5c19wbG90X2RmLCBhZXMobGF5X3Byb2JfcmF0aW8sIHZhbHVlKSkgKyBnZW9tX3BvaW50KHNpemUgPSAxKSArIA0KICBmYWNldF93cmFwKH4gbWV0cmljLCBzY2FsZXMgPSAiZnJlZSIpICsgdGhlbWVfYncoKSArIHhsaW0oMCwgNCkgKyANCiAgZ2d0aXRsZSgiUHJvYmFiaWxpdHkgUmF0aW8gTGltaXQgZm9yIExheXM6IExvZ2lzdGljIFJlZ3Jlc3Npb24iKSArIGxhYnMoeCA9ICJQcm9iYWJpbGl0eSBSYXRpbyIpDQpnZ3NhdmUoaGVyZTo6aGVyZSgicGxvdHMvcGxvdF83LnBuZyIpLCBkcGkgPSAyMDApDQoNCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoInBsb3RzL3Bsb3RfNy5wbmciKSkNCg0KYGBgDQoNCmlmIHdlIGhhZCB1c2VkIGEgcmF0aW8gbGltaXQgb2YgMS4wMCwgd2Ugd291bGQgaGF2ZSBtYWRlIDU5MyBiZXRzIGZvciBhIHByb2ZpdCBvZiA2MS4zNSwgd2l0aCBhIHByZWNpc2lvbiBvZiA1OSUgY29ycmVjdC4gVGhpcyB3b3VsZCBoYXZlIHJlcXVpcmVkIGEgdG90YWwgc3Rha2Ugb2YgMTAxNyBhbmQgcHJvZml0IHJhdGlvIG9mIDYuMCUuICANCg0KDQoqKioNCg0KRW5kDQoNCg0K