Introduction
In this project we will be looking at binary predictive modeling
using the logistic regression model. We will look to see if we need to
transform any variables and do cross validation before finding our final
model. We want to look at wins as our response variable and want to look
at what betting odds factor helps with that.
Data and Variable
Descriptions
This data set is on the NBA game betting odds and outcomes of the
2014-2015 Season. There is 1230 observations and 17 variables. The
variables in this data set are
- Datenum (categorical)- This is the amount of days since January 1,
1960
- Team (categorical)- Where the home team is from
- OppTeam (categorical)- Where the away team is from
- TeamPts (numerical)- Home team points scored
- OppPts (numerical)- Away team points scored
- Wins (binary response)- If the home team won (1 means they won, 0
means they lost)
- TeamCov (binary response) - If the home team covered the spread (1
means they covered, 0 means a “push”, and -1 means they didn’t
cover)
- TeamSprd (numerical)- The Vegas point spread for the home team
- OvrUndr (numerical)- The over/under Vegas line for the total points
in the game
- TeamDiff (numerical)- Home Points minus Away Points
- TotalPts (numerical)- Home Points plus Away Points
We only used a certain number of these variables like TeamPts,
OppPts, TeamWin, TeamSprd, and OvrUndr due to my past experiences. The
other variables were either not important for this project or they were
a combination of others.
Research
Question
The objective of this case study is to build a logistic regression
model to predict wins using various risk factors associated with the
game.
Exploratory
Analysis
We first make the following pairwise scatter plots to inspect the
potential issues with predictor variables.

Looking at the scatter plots we can see that none look skewed and are
all unimodal besides our binary response variable which is team wins.
This means that we do not need to transform any of our predictor
variables.
Standizing Numerical
Predictor Variables
Since this is a predictive model, we don’t worry about the
interpretation of the coefficients. The objective is to identify a model
that has the best predictive performance.
Data Split - Training
and Testing Data
We randomly split the data into two subsets. 80% of the data will be
used as training data. We will use the training data to search the
candidate models, validate them and identify the final model using the
cross-validation method. The 20% of the hold-up sample will be used for
assessing the performance of the final model.
Best Model
Identification
In the past modules, we introduced full and reduced models to set up
the scope for searching for the final model. In this case study, we use
the full, reduced, and final models obtained based on the step-wise
variable selection as the three candidate models.
Cross-Validation
for Model Identification
Since our training data is relatively small, I will use 5-fold
cross-validation to ensure the validation data set has enough diabetes
cases.
Average of prediction errors of candidate models
| 1 |
1 |
1 |
The average predictive errors of both model 1 and model 2 are the
same. Since model 2 is simpler than model 1, we choose model 2 as the
final predictive model. This selection of the final model is based on
the cut-off probability 0.5.
Final Model
Reporting
The previous cross-validation procedure identified the best model
with pre-selected cut-off 0.5. The actual accuracy of the final model is
given by
The actual accuracy of the final model
| 1 |
Looking at these results, it tells us that this model has a 100%
accuracy of predicting the outcome in the final model. This seems
correct because how many points you score affects the outcome of the
game greatly and how mnay points you can hold your opponent too.
Conclusion
In this project we were trying to make a model that predicts wins.
The final result for the accuracy of our final model was 100%. An
accuracy of 100% shows that the model is identifying if an observation
falls into win (1) or loss (0) for 100% of the time.
LS0tCnRpdGxlOiAiV2hhdCBpbmZsdWVuY2VzIHdpbm5pbmcgaW4gdGhlIE5CQT8iCmF1dGhvcjogIlJ5YW4gTGVibyIKZGF0ZTogIjIwMjQtMTAtMjMiCm91dHB1dDogCiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDQKICAgIHRvY19mbG9hdDogeWVzCiAgICBmaWdfd2lkdGg6IDQKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgY29kZV9kb3dubG9hZDogeWVzCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMKICAgIHRoZW1lOiBsdW1lbgogIHdvcmRfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA0CiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICBrZWVwX21kOiB5ZXMKICBwZGZfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA0CiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgZmlnX3dpZHRoOiAzCiAgICBmaWdfaGVpZ2h0OiAzCmVkaXRvcl9vcHRpb25zOgogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKc2x3YXlzX2FsbG93X2h0bWw6IHRydWUKLS0tCgpgYGB7PWh0bWx9Cgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgoKLyogQ2FzY2FkaW5nIFN0eWxlIFNoZWV0cyAoQ1NTKSBpcyBhIHN0eWxlc2hlZXQgbGFuZ3VhZ2UgdXNlZCB0byBkZXNjcmliZSB0aGUgcHJlc2VudGF0aW9uIG9mIGEgZG9jdW1lbnQgd3JpdHRlbiBpbiBIVE1MIG9yIFhNTC4gaXQgaXMgYSBzaW1wbGUgbWVjaGFuaXNtIGZvciBhZGRpbmcgc3R5bGUgKGUuZy4sIGZvbnRzLCBjb2xvcnMsIHNwYWNpbmcpIHRvIFdlYiBkb2N1bWVudHMuICovCgpoMS50aXRsZSB7ICAvKiBUaXRsZSAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgdGhlIHJlcG9ydCB0aXRsZSAqLwogIGZvbnQtc2l6ZTogMjRweDsKICBjb2xvcjogRGFya1JlZDsKICB0ZXh0LWFsaWduOiBjZW50ZXI7CiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOwp9Cmg0LmF1dGhvciB7IC8qIEhlYWRlciA0IC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgYXV0aG9ycyAgKi8KICBmb250LXNpemU6IDIwcHg7CiAgZm9udC1mYW1pbHk6IHN5c3RlbS11aTsKICBjb2xvcjogRGFya1JlZDsKICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KaDQuZGF0ZSB7IC8qIEhlYWRlciA0IC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgdGhlIGRhdGUgICovCiAgZm9udC1zaXplOiAxOHB4OwogIGZvbnQtZmFtaWx5OiBzeXN0ZW0tdWk7CiAgY29sb3I6IERhcmtCbHVlOwogIHRleHQtYWxpZ246IGNlbnRlcjsKfQpoMSB7IC8qIEhlYWRlciAxIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgbGV2ZWwgMSBzZWN0aW9uIHRpdGxlICAqLwogICAgZm9udC1zaXplOiAyMnB4OwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogbmF2eTsKICAgIHRleHQtYWxpZ246IGNlbnRlcjsKfQpoMiB7IC8qIEhlYWRlciAyIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgbGV2ZWwgMiBzZWN0aW9uIHRpdGxlICovCiAgICBmb250LXNpemU6IDIwcHg7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBuYXZ5OwogICAgdGV4dC1hbGlnbjogbGVmdDsKfQoKaDMgeyAvKiBIZWFkZXIgMyAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgbGV2ZWwgMyBzZWN0aW9uIHRpdGxlICAqLwogICAgZm9udC1zaXplOiAxOHB4OwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogbmF2eTsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KCmg0IHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIG9mIGxldmVsIDQgc2VjdGlvbiB0aXRsZSAgKi8KICAgIGZvbnQtc2l6ZTogMThweDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IGRhcmtyZWQ7CiAgICB0ZXh0LWFsaWduOiBsZWZ0Owp9Cgpib2R5IHsgYmFja2dyb3VuZC1jb2xvcjp3aGl0ZTsgfQoKLmhpZ2hsaWdodG1lIHsgYmFja2dyb3VuZC1jb2xvcjp5ZWxsb3c7IH0KCnAgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9Cgo8L3N0eWxlPgpgYGAKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CgppZiAoIXJlcXVpcmUoImtuaXRyIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQogICBsaWJyYXJ5KGtuaXRyKQp9CmlmICghcmVxdWlyZSgibGVhZmxldCIpKSB7CiAgIGluc3RhbGwucGFja2FnZXMoImxlYWZsZXQiKQogICBsaWJyYXJ5KGxlYWZsZXQpCn0KaWYgKCFyZXF1aXJlKCJFbnZTdGF0cyIpKSB7CiAgIGluc3RhbGwucGFja2FnZXMoIkVudlN0YXRzIikKICAgbGlicmFyeShFbnZTdGF0cykKfQppZiAoIXJlcXVpcmUoIk1BU1MiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJNQVNTIikKICAgbGlicmFyeShNQVNTKQp9CmlmICghcmVxdWlyZSgicGh5dG9vbHMiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJwaHl0b29scyIpCiAgIGxpYnJhcnkocGh5dG9vbHMpCn0KaWYgKCFyZXF1aXJlKCJ0aWR5dmVyc2UiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQogICBsaWJyYXJ5KHRpZHl2ZXJzZSkKfQppZiAoIXJlcXVpcmUoIm1sYmVuY2giKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJtbGJlbmNoIikKICAgbGlicmFyeShtbGJlbmNoKQp9CmlmICghcmVxdWlyZSgicGFuZGVyIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygicGFuZGVyIikKICAgbGlicmFyeShwYW5kZXIpCn0KaWYgKCFyZXF1aXJlKCJwUk9DIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygicFJPQyIpCiAgIGxpYnJhcnkocFJPQykKfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IEZBTFNFLCAgCiAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwgIAogICAgICAgICAgICAgICAgICAgcmVzdWx0cyA9IFRSVUUsICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgY29tbWVudCA9IEZBTFNFICAKICAgICAgICAgICAgICAgICAgICAgICkgICAKYGBgCgoKYGBge3J9CmJldHMgPC0gcmVhZC5jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9SeWFuTGViby9TVEEtMzIxL3JlZnMvaGVhZHMvbWFpbi9Qcm9qZWN0JTIwMiUyMERhdGEiLCBoZWFkZXIgPSBUUlVFKQp3aW5zPC0gYmV0cyRUZWFtV2luCm5ld19kYXRhIDwtIGJldHMgJT4lCiAgc2VsZWN0KC1PVCwgLVRlYW0sIC1PcHBUZWFtLCAtRGF0ZW51bSwgLURhdGVzbGFzaCwgLUhvbWUsIC1UZWFtQ292LCAtT1VDb3YsIC1UZWFtX2lkLCAtT3BwVGVhbV9pZCwtVGVhbURpZmYsIC1Ub3RhbFB0cykKYGBgCgojIEludHJvZHVjdGlvbgpJbiB0aGlzIHByb2plY3Qgd2Ugd2lsbCBiZSBsb29raW5nIGF0IGJpbmFyeSBwcmVkaWN0aXZlIG1vZGVsaW5nIHVzaW5nIHRoZSBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsLiBXZSB3aWxsIGxvb2sgdG8gc2VlIGlmIHdlIG5lZWQgdG8gdHJhbnNmb3JtIGFueSB2YXJpYWJsZXMgYW5kIGRvIGNyb3NzIHZhbGlkYXRpb24gYmVmb3JlIGZpbmRpbmcgb3VyIGZpbmFsIG1vZGVsLiBXZSB3YW50IHRvIGxvb2sgYXQgd2lucyBhcyBvdXIgcmVzcG9uc2UgdmFyaWFibGUgYW5kIHdhbnQgdG8gbG9vayBhdCB3aGF0IGJldHRpbmcgb2RkcyBmYWN0b3IgaGVscHMgd2l0aCB0aGF0LiAKCiMjIERhdGEgYW5kIFZhcmlhYmxlIERlc2NyaXB0aW9ucwoKVGhpcyBkYXRhIHNldCBpcyBvbiB0aGUgTkJBIGdhbWUgYmV0dGluZyBvZGRzIGFuZCBvdXRjb21lcyBvZiB0aGUgMjAxNC0yMDE1IFNlYXNvbi4gVGhlcmUgaXMgMTIzMCBvYnNlcnZhdGlvbnMgYW5kIDE3IHZhcmlhYmxlcy4gVGhlIHZhcmlhYmxlcyBpbiB0aGlzIGRhdGEgc2V0IGFyZSAKCiogRGF0ZW51bSAoY2F0ZWdvcmljYWwpLSBUaGlzIGlzIHRoZSBhbW91bnQgb2YgZGF5cyBzaW5jZSBKYW51YXJ5IDEsIDE5NjAKKiBUZWFtIChjYXRlZ29yaWNhbCktIFdoZXJlIHRoZSBob21lIHRlYW0gaXMgZnJvbQoqIE9wcFRlYW0gKGNhdGVnb3JpY2FsKS0gV2hlcmUgdGhlIGF3YXkgdGVhbSBpcyBmcm9tCiogVGVhbVB0cyAobnVtZXJpY2FsKS0gSG9tZSB0ZWFtIHBvaW50cyBzY29yZWQKKiBPcHBQdHMgKG51bWVyaWNhbCktIEF3YXkgdGVhbSBwb2ludHMgc2NvcmVkCiogV2lucyAoYmluYXJ5IHJlc3BvbnNlKS0gSWYgdGhlIGhvbWUgdGVhbSB3b24gKDEgbWVhbnMgdGhleSB3b24sIDAgbWVhbnMgdGhleSBsb3N0KQoqIFRlYW1Db3YgKGJpbmFyeSByZXNwb25zZSkgLSBJZiB0aGUgaG9tZSB0ZWFtIGNvdmVyZWQgdGhlIHNwcmVhZCAoMSBtZWFucyB0aGV5IGNvdmVyZWQsIDAgbWVhbnMgYSAicHVzaCIsIGFuZCAtMSBtZWFucyB0aGV5IGRpZG4ndCBjb3ZlcikKKiBUZWFtU3ByZCAobnVtZXJpY2FsKS0gVGhlIFZlZ2FzIHBvaW50IHNwcmVhZCBmb3IgdGhlIGhvbWUgdGVhbQoqIE92clVuZHIgKG51bWVyaWNhbCktIFRoZSBvdmVyL3VuZGVyIFZlZ2FzIGxpbmUgZm9yIHRoZSB0b3RhbCBwb2ludHMgaW4gdGhlIGdhbWUKKiBUZWFtRGlmZiAobnVtZXJpY2FsKS0gSG9tZSBQb2ludHMgbWludXMgQXdheSBQb2ludHMKKiBUb3RhbFB0cyAobnVtZXJpY2FsKS0gSG9tZSBQb2ludHMgcGx1cyBBd2F5IFBvaW50cwoKV2Ugb25seSB1c2VkIGEgY2VydGFpbiBudW1iZXIgb2YgdGhlc2UgdmFyaWFibGVzIGxpa2UgVGVhbVB0cywgT3BwUHRzLCBUZWFtV2luLCBUZWFtU3ByZCwgYW5kIE92clVuZHIgZHVlIHRvIG15IHBhc3QgZXhwZXJpZW5jZXMuIFRoZSBvdGhlciB2YXJpYWJsZXMgd2VyZSBlaXRoZXIgbm90IGltcG9ydGFudCBmb3IgdGhpcyBwcm9qZWN0IG9yIHRoZXkgd2VyZSBhIGNvbWJpbmF0aW9uIG9mIG90aGVycy4KCiMjIFJlc2VhcmNoIFF1ZXN0aW9uClRoZSBvYmplY3RpdmUgb2YgdGhpcyBjYXNlIHN0dWR5IGlzIHRvIGJ1aWxkIGEgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbCB0byBwcmVkaWN0IHdpbnMgdXNpbmcgdmFyaW91cyByaXNrIGZhY3RvcnMgYXNzb2NpYXRlZCB3aXRoIHRoZSBnYW1lLgoKIyBFeHBsb3JhdG9yeSBBbmFseXNpcwoKV2UgZmlyc3QgbWFrZSB0aGUgZm9sbG93aW5nIHBhaXJ3aXNlIHNjYXR0ZXIgcGxvdHMgdG8gaW5zcGVjdCB0aGUgcG90ZW50aWFsIGlzc3VlcyB3aXRoIHByZWRpY3RvciB2YXJpYWJsZXMuCgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTd9CmxpYnJhcnkocHN5Y2gpCnBhaXJzLnBhbmVscyhuZXdfZGF0YVssLTldLCAKICAgICAgICAgICAgIG1ldGhvZCA9ICJwZWFyc29uIiwgCiAgICAgICAgICAgICBoaXN0LmNvbCA9ICIjMDBBRkJCIiwKICAgICAgICAgICAgIGRlbnNpdHkgPSBUUlVFLCAgCiAgICAgICAgICAgICBlbGxpcHNlcyA9IFRSVUUgCiAgICAgICAgICAgICApCmBgYAoKTG9va2luZyBhdCB0aGUgc2NhdHRlciBwbG90cyB3ZSBjYW4gc2VlIHRoYXQgbm9uZSBsb29rIHNrZXdlZCBhbmQgYXJlIGFsbCB1bmltb2RhbCBiZXNpZGVzIG91ciBiaW5hcnkgcmVzcG9uc2UgdmFyaWFibGUgd2hpY2ggaXMgdGVhbSB3aW5zLiBUaGlzIG1lYW5zIHRoYXQgd2UgZG8gbm90IG5lZWQgdG8gdHJhbnNmb3JtIGFueSBvZiBvdXIgcHJlZGljdG9yIHZhcmlhYmxlcy4gCgojIyBTdGFuZGl6aW5nIE51bWVyaWNhbCBQcmVkaWN0b3IgVmFyaWFibGVzCgpTaW5jZSB0aGlzIGlzIGEgcHJlZGljdGl2ZSBtb2RlbCwgd2UgZG9uJ3Qgd29ycnkgYWJvdXQgdGhlIGludGVycHJldGF0aW9uIG9mIHRoZSBjb2VmZmljaWVudHMuIFRoZSBvYmplY3RpdmUgaXMgdG8gaWRlbnRpZnkgYSBtb2RlbCB0aGF0IGhhcyB0aGUgYmVzdCBwcmVkaWN0aXZlIHBlcmZvcm1hbmNlLgoKYGBge3J9CgpuZXdfZGF0YSRzZC5UZWFtUHRzID0gKG5ld19kYXRhJFRlYW1QdHMtbWVhbihuZXdfZGF0YSRUZWFtUHRzKSkvc2QobmV3X2RhdGEkVGVhbVB0cykKbmV3X2RhdGEkc2QuT3BwUHRzID0gKG5ld19kYXRhJE9wcFB0cy1tZWFuKG5ld19kYXRhJE9wcFB0cykpL3NkKG5ld19kYXRhJE9wcFB0cykKbmV3X2RhdGEkc2QuVGVhbVNwcmQgPSAobmV3X2RhdGEkVGVhbVNwcmQtbWVhbihuZXdfZGF0YSRUZWFtU3ByZCkpL3NkKG5ld19kYXRhJFRlYW1TcHJkKQpuZXdfZGF0YSRzZC5PdnJVbmRyID0gKG5ld19kYXRhJE92clVuZHItbWVhbihuZXdfZGF0YSRPdnJVbmRyKSkvc2QobmV3X2RhdGEkT3ZyVW5kcikKCnNkLm5ld19kYXRhID0gbmV3X2RhdGFbLCAtYygxOjIsNDo1KV0KYGBgCgoKIyMgRGF0YSBTcGxpdCAtIFRyYWluaW5nIGFuZCBUZXN0aW5nIERhdGEKCldlIHJhbmRvbWx5IHNwbGl0IHRoZSBkYXRhIGludG8gdHdvIHN1YnNldHMuIDgwJSBvZiB0aGUgZGF0YSB3aWxsIGJlIHVzZWQgYXMgdHJhaW5pbmcgZGF0YS4gV2Ugd2lsbCB1c2UgdGhlIHRyYWluaW5nIGRhdGEgdG8gc2VhcmNoIHRoZSBjYW5kaWRhdGUgbW9kZWxzLCB2YWxpZGF0ZSB0aGVtIGFuZCBpZGVudGlmeSB0aGUgZmluYWwgbW9kZWwgdXNpbmcgdGhlIGNyb3NzLXZhbGlkYXRpb24gbWV0aG9kLiBUaGUgMjAlIG9mIHRoZSBob2xkLXVwIHNhbXBsZSB3aWxsIGJlIHVzZWQgZm9yIGFzc2Vzc2luZyB0aGUgcGVyZm9ybWFuY2Ugb2YgdGhlIGZpbmFsIG1vZGVsLgoKYGBge3J9CgpuIDwtIGRpbShzZC5uZXdfZGF0YSlbMV0KdHJhaW4ubiA8LSByb3VuZCgwLjgqbikKdHJhaW4uaWQgPC0gc2FtcGxlKDE6biwgdHJhaW4ubiwgcmVwbGFjZSA9IEZBTFNFKQoKdHJhaW4gPC0gc2QubmV3X2RhdGFbdHJhaW4uaWQsIF0KdGVzdCA8LSBzZC5uZXdfZGF0YVstdHJhaW4uaWQsIF0KCmBgYAoKCiMjIEJlc3QgTW9kZWwgSWRlbnRpZmljYXRpb24KCkluIHRoZSBwYXN0IG1vZHVsZXMsIHdlIGludHJvZHVjZWQgZnVsbCBhbmQgcmVkdWNlZCBtb2RlbHMgdG8gc2V0IHVwIHRoZSBzY29wZSBmb3Igc2VhcmNoaW5nIGZvciB0aGUgZmluYWwgbW9kZWwuIEluIHRoaXMgY2FzZSBzdHVkeSwgd2UgdXNlIHRoZSBmdWxsLCByZWR1Y2VkLCBhbmQgZmluYWwgbW9kZWxzIG9idGFpbmVkIGJhc2VkIG9uIHRoZSBzdGVwLXdpc2UgdmFyaWFibGUgc2VsZWN0aW9uIGFzIHRoZSB0aHJlZSBjYW5kaWRhdGUgbW9kZWxzLgoKIyMjIENyb3NzLVZhbGlkYXRpb24gZm9yIE1vZGVsIElkZW50aWZpY2F0aW9uCgpTaW5jZSBvdXIgdHJhaW5pbmcgZGF0YSBpcyByZWxhdGl2ZWx5IHNtYWxsLCBJIHdpbGwgdXNlIDUtZm9sZCBjcm9zcy12YWxpZGF0aW9uIHRvIGVuc3VyZSB0aGUgdmFsaWRhdGlvbiBkYXRhIHNldCBoYXMgZW5vdWdoIGRpYWJldGVzIGNhc2VzLgoKYGBge3J9CgprPTUKZm9sZC5zaXplID0gZmxvb3IoZGltKHRyYWluKVsxXS9rKQoKUEUxID0gcmVwKDAsNSkKUEUyID0gcmVwKDAsNSkKUEUzID0gcmVwKDAsNSkKZm9yKGkgaW4gMTprKXsKCiAgdmFsaWQuaWQgPSAoZm9sZC5zaXplKihpLTEpKzEpOihmb2xkLnNpemUqaSkKICB2YWxpZCA9IHRyYWluW3ZhbGlkLmlkLCBdCiAgdHJhaW4uZGF0ID0gdHJhaW5bLXZhbGlkLmlkLF0KICAKCiAgY2FuZGlkYXRlMDEgPSBnbG0oVGVhbVdpbiB+c2QuVGVhbVB0cytzZC5PcHBQdHMrc2QuVGVhbVNwcmQrc2QuT3ZyVW5kciwgCiAgICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gYmlub21pYWwobGluayA9ICJsb2dpdCIpLAogICAgICAgICAgICAgICAgICAgIGRhdGEgPSB0cmFpbi5kYXQpICAKCiAgY2FuZGlkYXRlMDMgPSBnbG0oVGVhbVdpbiB+IHNkLlRlYW1QdHMrc2QuT3BwUHRzLCAKICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IiksICAKICAgICAgICAgICAgICAgICAgICBkYXRhID0gdHJhaW4uZGF0KSAKCiAgIGNhbmRpZGF0ZTAyID0gc3RlcEFJQyhjYW5kaWRhdGUwMSwgCiAgICAgICAgICAgICAgICAgICAgICBzY29wZSA9IGxpc3QobG93ZXI9Zm9ybXVsYShjYW5kaWRhdGUwMyksdXBwZXI9Zm9ybXVsYShjYW5kaWRhdGUwMSkpLAogICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImZvcndhcmQiLCAgIAogICAgICAgICAgICAgICAgICAgICAgdHJhY2UgPSAwICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgKQogCiAgIHByZWQwMSA9IHByZWRpY3QoY2FuZGlkYXRlMDEsIG5ld2RhdGEgPSB2YWxpZCwgdHlwZT0icmVzcG9uc2UiKQogICBwcmVkMDIgPSBwcmVkaWN0KGNhbmRpZGF0ZTAyLCBuZXdkYXRhID0gdmFsaWQsIHR5cGU9InJlc3BvbnNlIikKICAgcHJlZDAzID0gcHJlZGljdChjYW5kaWRhdGUwMywgbmV3ZGF0YSA9IHZhbGlkLCB0eXBlPSJyZXNwb25zZSIpCiAgIAogICBwcmUub3V0Y29tZTAxID0gaWZlbHNlKGFzLnZlY3RvcihwcmVkMDEpID4gMC41LCAxLCAwKQogICBwcmUub3V0Y29tZTAyID0gaWZlbHNlKGFzLnZlY3RvcihwcmVkMDIpID4gMC41LCAxLCAwKQogICBwcmUub3V0Y29tZTAzID0gaWZlbHNlKGFzLnZlY3RvcihwcmVkMDMpID4gMC41LCAxLCAwKQogICAKICAgUEUxW2ldID0gc3VtKHByZS5vdXRjb21lMDEgPT0gdmFsaWQkVGVhbVdpbiApL2xlbmd0aChwcmVkMDEpCiAgIFBFMltpXSA9IHN1bShwcmUub3V0Y29tZTAyID09IHZhbGlkJFRlYW1XaW4gKS9sZW5ndGgocHJlZDAyKQogICBQRTNbaV0gPSBzdW0ocHJlLm91dGNvbWUwMiA9PSB2YWxpZCRUZWFtV2luICkvbGVuZ3RoKHByZWQwMykKfQphdmcucGUgPSBjYmluZChQRTEgPSBtZWFuKFBFMSksIFBFMiA9IG1lYW4oUEUyKSwgUEUzID0gbWVhbihQRTMpKQprYWJsZShhdmcucGUsIGNhcHRpb24gPSAiQXZlcmFnZSBvZiBwcmVkaWN0aW9uIGVycm9ycyBvZiBjYW5kaWRhdGUgbW9kZWxzIikKCmBgYAoKVGhlIGF2ZXJhZ2UgcHJlZGljdGl2ZSBlcnJvcnMgb2YgYm90aCBtb2RlbCAxIGFuZCBtb2RlbCAyIGFyZSB0aGUgc2FtZS4gU2luY2UgbW9kZWwgMiBpcyBzaW1wbGVyIHRoYW4gbW9kZWwgMSwgd2UgY2hvb3NlIG1vZGVsIDIgYXMgdGhlIGZpbmFsIHByZWRpY3RpdmUgbW9kZWwuIFRoaXMgc2VsZWN0aW9uIG9mIHRoZSBmaW5hbCBtb2RlbCBpcyBiYXNlZCBvbiB0aGUgY3V0LW9mZiBwcm9iYWJpbGl0eSAwLjUuCgoKIyMjIEZpbmFsIE1vZGVsIFJlcG9ydGluZwoKVGhlIHByZXZpb3VzIGNyb3NzLXZhbGlkYXRpb24gcHJvY2VkdXJlIGlkZW50aWZpZWQgdGhlIGJlc3QgbW9kZWwgd2l0aCBwcmUtc2VsZWN0ZWQgY3V0LW9mZiAwLjUuIFRoZSBhY3R1YWwgYWNjdXJhY3kgb2YgdGhlIGZpbmFsIG1vZGVsIGlzIGdpdmVuIGJ5CgpgYGB7cn0KcHJlZDAyID0gcHJlZGljdChjYW5kaWRhdGUwMiwgbmV3ZGF0YSA9IHRlc3QsIHR5cGU9InJlc3BvbnNlIikKcHJlZDAyLm91dGNvbWUgPSBpZmVsc2UoYXMudmVjdG9yKHByZWQwMik+MC41LCAxLCAwKQoKYWNjdXJhY3kgPSBzdW0ocHJlZDAyLm91dGNvbWUgPT0gdGVzdCRUZWFtV2luKS9sZW5ndGgocHJlZDAyKQprYWJsZShhY2N1cmFjeSwgY2FwdGlvbj0iVGhlIGFjdHVhbCBhY2N1cmFjeSBvZiB0aGUgZmluYWwgbW9kZWwiKQoKCmBgYAoKTG9va2luZyBhdCB0aGVzZSByZXN1bHRzLCBpdCB0ZWxscyB1cyB0aGF0IHRoaXMgbW9kZWwgaGFzIGEgMTAwJSBhY2N1cmFjeSBvZiBwcmVkaWN0aW5nIHRoZSBvdXRjb21lIGluIHRoZSBmaW5hbCBtb2RlbC4gVGhpcyBzZWVtcyBjb3JyZWN0IGJlY2F1c2UgaG93IG1hbnkgcG9pbnRzIHlvdSBzY29yZSBhZmZlY3RzIHRoZSBvdXRjb21lIG9mIHRoZSBnYW1lIGdyZWF0bHkgYW5kIGhvdyBtbmF5IHBvaW50cyB5b3UgY2FuIGhvbGQgeW91ciBvcHBvbmVudCB0b28uIAoKCiMgQ29uY2x1c2lvbgoKSW4gdGhpcyBwcm9qZWN0IHdlIHdlcmUgdHJ5aW5nIHRvIG1ha2UgYSBtb2RlbCB0aGF0IHByZWRpY3RzIHdpbnMuIFRoZSBmaW5hbCByZXN1bHQgZm9yIHRoZSBhY2N1cmFjeSBvZiBvdXIgZmluYWwgbW9kZWwgd2FzIDEwMCUuIEFuIGFjY3VyYWN5IG9mIDEwMCUgc2hvd3MgdGhhdCB0aGUgbW9kZWwgaXMgaWRlbnRpZnlpbmcgaWYgYW4gb2JzZXJ2YXRpb24gZmFsbHMgaW50byB3aW4gKDEpIG9yIGxvc3MgKDApIGZvciAxMDAlIG9mIHRoZSB0aW1lLiAKCg==