Introduction

In 1977 the idea of applying statistical analysis to American professional sports was popularized with Bill James and the introduction of Sabermetrics. However, professional sports tend to be very conservative and slow to change and you still see articles and comments from players and coaches on how their favored sport can not be boiled down to just data. Baseball began to explore the use of metrics in the 1990’s and early 2000’s and over the last 10 years we have slowly seen the NFL, NBA, HNL, and Professional Soccer Leagues begin to explore the application of data analytics in their own sports. In this project we will apply the tools that we have learned this semester to build a recommender system for NFL play calling.

My interest in this topic is of a personal nature. I have spent 13 of the last 15 years as a high school football coach and spent 3 years as an offensive coordinator and play caller. Currently calling plays in football is based on a mixture of hours of video work, trying to find tendencies and weaknesses in the opponents defense and an intuition of how your opponent will adjust throughout the game. You will also often take the time during the week to script the first 10 to 15 plays to get a feel for how a team will adjust to you. This leads to the production of the massive, although not nearly as large in high school, play calling cards with everything that you think that will work for any given situation. The idea for this recommender is to provide a type of play and a direction to run the play in. For example we would like to indicate that it’s first and 10

Data

For this project we will be using the play by play data for 2013 through 2016 seasons sourced from NFL Savant. The data is contained in a series of 4 csv files broken down by year. Lets load in one of the files and see what we have in the data.

pbp_2016 <- read.csv("../data/nfl/pbp-2016.csv")
head(pbp_2016)

We can see that the play-by-play data contains the following variables which may be of interest in our recommender:

Description of the Recommender System

We can see from the previous section that there are a number of variables in the data set and some of which can be useful to our recommender and some which will not be. Our plan is to take the down and distance information, either with actual distance or broken into short, medium, and long and recommend the play, play type and direction, that results in the most yards. Given that pass plays routinely gain more yards then runs we will recommend the best 3 passes and best 3 runs in that situation. While it would be nice to provide more information about what play to call this is not included in our data and varies on a team-by-team basis. We also will use the past 4 years of data to help provide enough data to avoid cold start issues.

Given that each team is a unique entity, there is no reason to believe that information about what is successful for the New England Patriots will be the same thing that is successful for the Carolina Panthers. Therefore our recommender system will be based on a single team’s play-by-play data. However we will also compute the recommendations for all teams to see if they are informative to the recommender. We will also implement this recommender for a single NFL team and investigate the feasibility of implementing for all teams.

We also recognize that some plays work better in some parts of the field then others so we would like to incorporate the field position into the data. We are concerned that this may make matrix to sparse eve with 4 years data so we will may end up binning distances together into categories like “Red Zone”, inside opponents 20 yard line, or “Backed Up”, inside our own 20. We also plan to look at some of our other variables to see if they may help us to provide a high quality recommendation.

Implementation Plan

To implement this project we will need to implement the following tasks;

  1. Combine the data from the 2013-2016 seasons.
  2. Clean and augment the data to include our “user” variables of down and distance combinations. Our “item” variables will be the play type and play direction.
  3. Play distance will be our metric
  4. Pick a team to be
  5. Use a Spark implementation to perform ALS (best performing method from the semester and can be implemented in spark)
  6. Build our recommender using the prediction matrix for our team, the prediction matrix for all teams, any other interesting variables that we find or create
  7. Evaluate the recommendation system.
LS0tDQp0aXRsZTogJ0RBVEE2NDMgLSBGaW5hbCBQcm9qZWN0IFByb3Bvc2FsOiBSZWNvbW1lbmRpbmcgUGxheXMgaW4gdGhlIE5GTCcNCmF1dGhvcjogIkVyaWsgTnlsYW5kZXIiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCi0tLQ0KDQojIyBJbnRyb2R1Y3Rpb24NCkluIDE5NzcgdGhlIGlkZWEgb2YgYXBwbHlpbmcgc3RhdGlzdGljYWwgYW5hbHlzaXMgdG8gQW1lcmljYW4gcHJvZmVzc2lvbmFsIHNwb3J0cyB3YXMgcG9wdWxhcml6ZWQgd2l0aCBCaWxsIEphbWVzIGFuZCB0aGUgaW50cm9kdWN0aW9uIG9mIFtTYWJlcm1ldHJpY3NdKGh0dHA6Ly9zYWJyLm9yZy9zYWJlcm1ldHJpY3MpLiBIb3dldmVyLCBwcm9mZXNzaW9uYWwgc3BvcnRzIHRlbmQgdG8gYmUgdmVyeSBjb25zZXJ2YXRpdmUgYW5kIHNsb3cgdG8gY2hhbmdlIGFuZCB5b3Ugc3RpbGwgc2VlIGFydGljbGVzIGFuZCBjb21tZW50cyBmcm9tIHBsYXllcnMgYW5kIGNvYWNoZXMgb24gaG93IHRoZWlyIGZhdm9yZWQgc3BvcnQgY2FuIG5vdCBiZSBib2lsZWQgZG93biB0byBqdXN0IGRhdGEuIEJhc2ViYWxsIGJlZ2FuIHRvIGV4cGxvcmUgdGhlIHVzZSBvZiBtZXRyaWNzIGluIHRoZSAxOTkwJ3MgYW5kIGVhcmx5IDIwMDAncyBhbmQgb3ZlciB0aGUgbGFzdCAxMCB5ZWFycyB3ZSBoYXZlIHNsb3dseSBzZWVuIHRoZSBORkwsIE5CQSwgSE5MLCBhbmQgUHJvZmVzc2lvbmFsIFNvY2NlciBMZWFndWVzIGJlZ2luIHRvIGV4cGxvcmUgdGhlIGFwcGxpY2F0aW9uIG9mIGRhdGEgYW5hbHl0aWNzIGluIHRoZWlyIG93biBzcG9ydHMuIEluIHRoaXMgcHJvamVjdCB3ZSB3aWxsIGFwcGx5IHRoZSB0b29scyB0aGF0IHdlIGhhdmUgbGVhcm5lZCB0aGlzIHNlbWVzdGVyIHRvIGJ1aWxkIGEgcmVjb21tZW5kZXIgc3lzdGVtIGZvciBORkwgcGxheSBjYWxsaW5nLiANCg0KTXkgaW50ZXJlc3QgaW4gdGhpcyB0b3BpYyBpcyBvZiBhIHBlcnNvbmFsIG5hdHVyZS4gSSBoYXZlIHNwZW50IDEzIG9mIHRoZSBsYXN0IDE1IHllYXJzIGFzIGEgaGlnaCBzY2hvb2wgZm9vdGJhbGwgY29hY2ggYW5kIHNwZW50IDMgeWVhcnMgYXMgYW4gb2ZmZW5zaXZlIGNvb3JkaW5hdG9yIGFuZCBwbGF5IGNhbGxlci4gQ3VycmVudGx5IGNhbGxpbmcgcGxheXMgaW4gZm9vdGJhbGwgaXMgYmFzZWQgb24gYSBtaXh0dXJlIG9mIGhvdXJzIG9mIHZpZGVvIHdvcmssIHRyeWluZyB0byBmaW5kIHRlbmRlbmNpZXMgYW5kIHdlYWtuZXNzZXMgaW4gdGhlIG9wcG9uZW50cyBkZWZlbnNlIGFuZCBhbiBpbnR1aXRpb24gb2YgaG93IHlvdXIgb3Bwb25lbnQgd2lsbCBhZGp1c3QgdGhyb3VnaG91dCB0aGUgZ2FtZS4gWW91IHdpbGwgYWxzbyBvZnRlbiB0YWtlIHRoZSB0aW1lIGR1cmluZyB0aGUgd2VlayB0byBzY3JpcHQgdGhlIGZpcnN0IDEwIHRvIDE1IHBsYXlzIHRvIGdldCBhIGZlZWwgZm9yIGhvdyBhIHRlYW0gd2lsbCBhZGp1c3QgdG8geW91LiBUaGlzIGxlYWRzIHRvIHRoZSBwcm9kdWN0aW9uIG9mIHRoZSBtYXNzaXZlLCBhbHRob3VnaCBub3QgbmVhcmx5IGFzIGxhcmdlIGluIGhpZ2ggc2Nob29sLCBwbGF5IGNhbGxpbmcgY2FyZHMgd2l0aCBldmVyeXRoaW5nIHRoYXQgeW91IHRoaW5rIHRoYXQgd2lsbCB3b3JrIGZvciBhbnkgZ2l2ZW4gc2l0dWF0aW9uLiBUaGUgaWRlYSBmb3IgdGhpcyByZWNvbW1lbmRlciBpcyB0byBwcm92aWRlIGEgdHlwZSBvZiBwbGF5IGFuZCBhIGRpcmVjdGlvbiB0byBydW4gdGhlIHBsYXkgaW4uIEZvciBleGFtcGxlIHdlIHdvdWxkIGxpa2UgdG8gaW5kaWNhdGUgdGhhdCBpdCdzIGZpcnN0IGFuZCAxMCANCg0KIyMgRGF0YQ0KRm9yIHRoaXMgcHJvamVjdCB3ZSB3aWxsIGJlIHVzaW5nIHRoZSBwbGF5IGJ5IHBsYXkgZGF0YSBmb3IgMjAxMyB0aHJvdWdoIDIwMTYgc2Vhc29ucyBzb3VyY2VkIGZyb20gW05GTCBTYXZhbnRdKGh0dHA6Ly9uZmxzYXZhbnQuY29tL2Fib3V0LnBocCkuIFRoZSBkYXRhIGlzIGNvbnRhaW5lZCBpbiBhIHNlcmllcyBvZiA0IGNzdiBmaWxlcyBicm9rZW4gZG93biBieSB5ZWFyLiBMZXRzIGxvYWQgaW4gb25lIG9mIHRoZSBmaWxlcyBhbmQgc2VlIHdoYXQgd2UgaGF2ZSBpbiB0aGUgZGF0YS4NCg0KYGBge1J9DQpwYnBfMjAxNiA8LSByZWFkLmNzdigiLi4vZGF0YS9uZmwvcGJwLTIwMTYuY3N2IikNCmhlYWQocGJwXzIwMTYpDQpgYGANCg0KV2UgY2FuIHNlZSB0aGF0IHRoZSBwbGF5LWJ5LXBsYXkgZGF0YSBjb250YWlucyB0aGUgZm9sbG93aW5nIHZhcmlhYmxlcyB3aGljaCBtYXkgYmUgb2YgaW50ZXJlc3QgaW4gb3VyIHJlY29tbWVuZGVyOiAgDQoNCiAgKiBHYW1lSWQgLSBUaGlzIGlzIGEgdW5pcXVlIGlkZW50aWZpZXIgZm9yIGVhY2ggZ2FtZSB0aGF0IGNvbnNpc3RzIG9mIHRoZSBkYXRlIHRoZSBnYW1lIHdhcyBwbGF5ZWQgYW5kIG51bWJlcg0KICAqIEdhbWVEYXRlIC0gVGhlIGRhdGUgaW4geWVhciBtb250aCBkYXkgZm9ybWF0DQogICogUXVhcnRlciAtIFZhbHVlIGZyb20gMS00IGluZGljYXRpbmcgdGhlIHF1YXJ0ZXIgb2YgcGxheQ0KICAqIE1pbnV0ZSAtIFRoZSBudW1iZXIgb2YgbWludXRlcyBsZWZ0IGluIHRoZSBxdWFydGVyDQogICogU2Vjb25kIC0gVGhlIG51bWJlciBvZiBzZWNvbmRzIGxlZnQgaW4gdGhlIHF1YXJ0ZXINCiAgKiBPZmZlbnNlVGVhbSAtIEFiYnJldmlhdGlvbiBmb3IgdGhlIHRlYW0gb24gb2ZmZW5zZQ0KICAqIERlZmVuc2VUZWFtIC0gQWJicmV2aWF0aW9uIGZvciB0aGUgdGVhbSBvbiBkZWZlbnNlDQogICogRG93biAtIDAtNCwgMS00IGFyZSAxc3QgdGhyb3VnaCA0dGggZG93biwgMCBpcyB1c2VkIHRvIGluZGljYXRlIGEgdGltZW91dCBvciBraWNrb2ZmDQogICogVG9HbyAtIFRoZSBudW1iZXIgb2YgeWFyZHMgbGVmdCBmb3IgYSBmaXJzdCBkb3duDQogICogWWFyZExpbmUgLSAwLTEwMCwgMCBpbmRpY2F0ZXMgdGhlIG9mZmVuc2l2ZSB0ZWFtcyBnb2FsIGxpbmUgYW5kIDEwMCB0aGUgbGluZSBkZWZlbnNpdmUgdGVhbXMgZ29hbCBsaW5lDQogICogU2VyaWVzRmlyc3REb3duIC0gMCBvciAxLCBCaW5hcnkgdmFsdWUgaW5kaWNhdGluZyBpZiB0aGUgcGxheSByZXN1bHRlZCBpbiBhIGZpcnN0IGRvd24NCiAgKiBOZXh0U2NvcmUgLSBJdCBpcyBhbHdheXMgemVybw0KICAqIERlc2NyaXB0aW9uIC0gQmFzaWMgRGVzY3JpcHRpb24gb2YgdGhlIHBsYXkNCiAgKiBUZWFtV2luIC0gSXQgaXMgYWx3YXlzIHplcm8gdG9vDQogICogU2Vhc29uWWVhciAtIFRoZSB5ZWFyDQogICogWWFyZHMgLSBUaGUgbnVtYmVyIG9mIHlhcmRzIGdhaW5lZA0KICAqIEZvcm1hdGlvbiAtIEJhc2ljIG9mZmVuc2l2ZSBmb3JtYXRpb24NCiAgKiBQbGF5VHlwZSAtIENhdGVnb3JpY2FsIHZhcmlhYmxlIHRoYXQgZXhwbGFpbnMgdGhlIHR5cGUgb2YgcGxheSAtIFBhc3MsIFJ1biwgUHVudCwgVGltZW91dCwgZXRjLg0KICAqIElzUnVzaCAtIDAgb3IgMSwgQmluYXJ5IHZhcmlhYmxlIDEgaW5kaWNhdGVzIHRoYXQgdGhlIHBsYXkgd2FzIGEgcnVuDQogICogSXNQYXNzIC0gMCBvciAxLCBCaW5hcnkgdmFyaWFibGUgMSBpbmRpY2F0ZXMgdGhhdCB0aGUgcGxheSB3YXMgYSBwYXNzDQogICogSXNJbmNvbXBsZXRlIC0gMCBvciAxLCBCaW5hcnkgdmFyaWFibGUgMSBpbmRpY2F0ZXMgdGhhdCB0aGUgcGxheSB3YXMgDQogICogSXNUb3VjaGRvd24gLSAwIG9yIDEsIEJpbmFyeSB2YXJpYWJsZSAxIGluZGljYXRlcyB0aGF0IGEgdG91Y2hkb3duIHdhcyBzY29yZWQNCiAgKiBQYXNzVHlwZSAtIENhdGVnb3JpY2FsIHZhcmlhYmxlIHRoYXQgaW5kaWNhdGVzIHRoZSBwYXNzIHR5cGUgKHNob3J0LCBtZWRpdW0sIGxvbmcpIGFuZCB0aGUgcGFzcyBkaXJlY3Rpb24gKHJpZ2h0LCBtaWRkbGUsIGxlZnQpDQogICogSXNTYWNrIC0gMCBvciAxLCBCaW5hcnkgdmFyaWFibGUgdGhhdCBpbmRpY2F0ZXMgaWYgdGhlcmUgd2FzIGEgc2Fjaw0KICAqIElzQ2hhbGxlbmdlIC0gMCBvciAxLCAxIGluZGljYXRlcyB0aGF0IHRoZSBwbGF5IGNoYWxsZW5nZWQNCiAgKiBJc0NoYWxsZW5nZVJldmVyc2VkIC0gMCBvciAxLCAxIGluZGljYXRlcyB0aGF0IHRoZSBjYWxsIHdhcyByZXZlcnNlZA0KICAqIENoYWxsZW5nZXIgLSBXaGljaCB0ZWFtIGNoYWxsZW5nZWQNCiAgKiBJc01lYXN1cm1lbnQgLSAwIG9yIDEsIDEgaW5kaWNhdGVzIHRoYXQgdGhlcmUgd2FzIGEgbWVhc3VyZW1lbnQNCiAgKiBJc0ludGVyY2VwdGlvbiAtIDAgb3IgMSwgMSBpbmRpY2F0ZXMgdGhhdCB0aGVyZSB3YXMgYW4gaW50ZXJjZXB0aW9uIG9uIHRoZSBwbGF5DQogICogSXNGdW1ibGUgLSAwIG9yIDEsIDEgaW5kaWNhdGVzIHRoYXQgdGhlcmUgd2FzIGEgZnVtYmxlIG9uIHRoZSBwbGF5DQogICogSXNQZW5hbHR5IC0gMCBvciAxLCAxIGluZGljYXRlcyB0aGF0IHRoZXJlIHdhcyBhIHBlbmFsdHkgb24gdGhlIHBsYXkNCiAgKiBJc1R3b1BvaW50Q29udmVyc2lvbiAtIDAgb3IgMSwgMSBpbmRpY2F0ZXMgdGhhdCB0aGVyZSB3YXMgYSAyIHBvaW50IGNvbnZlcnNpb24NCiAgKiBJc1R3b1BvaW50Q29udmVyc2lvblN1Y2Nlc3NmdWwgLSAwIG9yIDEsIDEgaW5kaWNhdGVzIHRoYXQgdGhlIDIgcG9pbnQgY29udmVyc2lvbiB3b3JrZWQNCiAgKiBZYXJkTGluZUZpeGVkIC0gVGhpcyBpcyBhIHZhcmlhYmxlIHRoYXQgY2hhbmdlcyB0aGUgeWFyZCBsaW5lIHRvIHJlcHJlc2VudCB3aGF0IGlzIHNlZSBvbiB0aGUgZmllbGQgc28gNDAgaW4gdGhpcyBkYXRhIGNvdWxkIGJlIHRoZSBvZmZlbnNlJ3MgNDAgb3IgdGhlIGRlZmVuc2UncyA0MC4NCiAgKiBZYXJkTGluZURpcmVjdGlvbiAtIE9XTiBvciBPUFAsIHZhcmlhYmxlIHRoYXQgcHJvdmlkZWQgaW5mb3JtYXRpb24gZm9yIHRoZSBpbnRlcnByZXRhdGlvbiBvZiB0aGUgcHJldmlvdXMgdmFyaWFibGUNCiAgKiBUaGUgcmVtYWluaW5nIHZhcmlhYmxlcyBhcmUgcmVsYXRlZCB0byBwZW5hbHRpZXMNCiAgDQogIA0KIyMgRGVzY3JpcHRpb24gb2YgdGhlIFJlY29tbWVuZGVyIFN5c3RlbQ0KV2UgY2FuIHNlZSBmcm9tIHRoZSBwcmV2aW91cyBzZWN0aW9uIHRoYXQgdGhlcmUgYXJlIGEgbnVtYmVyIG9mIHZhcmlhYmxlcyBpbiB0aGUgZGF0YSBzZXQgYW5kIHNvbWUgb2Ygd2hpY2ggY2FuIGJlIHVzZWZ1bCB0byBvdXIgcmVjb21tZW5kZXIgYW5kIHNvbWUgd2hpY2ggd2lsbCBub3QgYmUuIE91ciBwbGFuIGlzIHRvIHRha2UgdGhlIGRvd24gYW5kIGRpc3RhbmNlIGluZm9ybWF0aW9uLCBlaXRoZXIgd2l0aCBhY3R1YWwgZGlzdGFuY2Ugb3IgYnJva2VuIGludG8gc2hvcnQsIG1lZGl1bSwgYW5kIGxvbmcgYW5kIHJlY29tbWVuZCB0aGUgcGxheSwgcGxheSB0eXBlIGFuZCBkaXJlY3Rpb24sIHRoYXQgcmVzdWx0cyBpbiB0aGUgbW9zdCB5YXJkcy4gR2l2ZW4gdGhhdCBwYXNzIHBsYXlzIHJvdXRpbmVseSBnYWluIG1vcmUgeWFyZHMgdGhlbiBydW5zIHdlIHdpbGwgcmVjb21tZW5kIHRoZSBiZXN0IDMgcGFzc2VzIGFuZCBiZXN0IDMgcnVucyBpbiB0aGF0IHNpdHVhdGlvbi4gV2hpbGUgaXQgd291bGQgYmUgbmljZSB0byBwcm92aWRlIG1vcmUgaW5mb3JtYXRpb24gYWJvdXQgd2hhdCBwbGF5IHRvIGNhbGwgdGhpcyBpcyBub3QgaW5jbHVkZWQgaW4gb3VyIGRhdGEgYW5kIHZhcmllcyBvbiBhIHRlYW0tYnktdGVhbSBiYXNpcy4gV2UgYWxzbyB3aWxsIHVzZSB0aGUgcGFzdCA0IHllYXJzIG9mIGRhdGEgdG8gaGVscCBwcm92aWRlIGVub3VnaCBkYXRhIHRvIGF2b2lkIGNvbGQgc3RhcnQgaXNzdWVzLiANCg0KR2l2ZW4gdGhhdCBlYWNoIHRlYW0gaXMgYSB1bmlxdWUgZW50aXR5LCB0aGVyZSBpcyBubyByZWFzb24gdG8gYmVsaWV2ZSB0aGF0IGluZm9ybWF0aW9uIGFib3V0IHdoYXQgaXMgc3VjY2Vzc2Z1bCBmb3IgdGhlIE5ldyBFbmdsYW5kIFBhdHJpb3RzIHdpbGwgYmUgdGhlIHNhbWUgdGhpbmcgdGhhdCBpcyBzdWNjZXNzZnVsIGZvciB0aGUgQ2Fyb2xpbmEgUGFudGhlcnMuIFRoZXJlZm9yZSBvdXIgcmVjb21tZW5kZXIgc3lzdGVtIHdpbGwgYmUgYmFzZWQgb24gYSBzaW5nbGUgdGVhbSdzIHBsYXktYnktcGxheSBkYXRhLiBIb3dldmVyIHdlIHdpbGwgYWxzbyBjb21wdXRlIHRoZSByZWNvbW1lbmRhdGlvbnMgZm9yIGFsbCB0ZWFtcyB0byBzZWUgaWYgdGhleSBhcmUgaW5mb3JtYXRpdmUgdG8gdGhlIHJlY29tbWVuZGVyLiBXZSB3aWxsIGFsc28gaW1wbGVtZW50IHRoaXMgcmVjb21tZW5kZXIgZm9yIGEgc2luZ2xlIE5GTCB0ZWFtIGFuZCBpbnZlc3RpZ2F0ZSB0aGUgZmVhc2liaWxpdHkgb2YgaW1wbGVtZW50aW5nIGZvciBhbGwgdGVhbXMuDQoNCldlIGFsc28gcmVjb2duaXplIHRoYXQgc29tZSBwbGF5cyB3b3JrIGJldHRlciBpbiBzb21lIHBhcnRzIG9mIHRoZSBmaWVsZCB0aGVuIG90aGVycyBzbyB3ZSB3b3VsZCBsaWtlIHRvIGluY29ycG9yYXRlIHRoZSBmaWVsZCBwb3NpdGlvbiBpbnRvIHRoZSBkYXRhLiBXZSBhcmUgY29uY2VybmVkIHRoYXQgdGhpcyBtYXkgbWFrZSBtYXRyaXggdG8gc3BhcnNlIGV2ZSB3aXRoIDQgeWVhcnMgZGF0YSBzbyB3ZSB3aWxsIG1heSBlbmQgdXAgYmlubmluZyBkaXN0YW5jZXMgdG9nZXRoZXIgaW50byBjYXRlZ29yaWVzIGxpa2UgIlJlZCBab25lIiwgaW5zaWRlIG9wcG9uZW50cyAyMCB5YXJkIGxpbmUsIG9yICJCYWNrZWQgVXAiLCBpbnNpZGUgb3VyIG93biAyMC4gV2UgYWxzbyBwbGFuIHRvIGxvb2sgYXQgc29tZSBvZiBvdXIgb3RoZXIgdmFyaWFibGVzIHRvIHNlZSBpZiB0aGV5IG1heSBoZWxwIHVzIHRvIHByb3ZpZGUgYSBoaWdoIHF1YWxpdHkgcmVjb21tZW5kYXRpb24uDQoNCg0KIyMgSW1wbGVtZW50YXRpb24gUGxhbg0KVG8gaW1wbGVtZW50IHRoaXMgcHJvamVjdCB3ZSB3aWxsIG5lZWQgdG8gaW1wbGVtZW50IHRoZSBmb2xsb3dpbmcgdGFza3M7ICANCg0KICAxKSBDb21iaW5lIHRoZSBkYXRhIGZyb20gdGhlIDIwMTMtMjAxNiBzZWFzb25zLg0KICAyKSBDbGVhbiBhbmQgYXVnbWVudCB0aGUgZGF0YSB0byBpbmNsdWRlIG91ciAidXNlciIgdmFyaWFibGVzIG9mIGRvd24gYW5kIGRpc3RhbmNlIGNvbWJpbmF0aW9ucy4gT3VyICJpdGVtIiB2YXJpYWJsZXMgd2lsbCBiZSB0aGUgcGxheSB0eXBlIGFuZCBwbGF5IGRpcmVjdGlvbi4NCiAgMykgUGxheSBkaXN0YW5jZSB3aWxsIGJlIG91ciBtZXRyaWMNCiAgNCkgUGljayBhIHRlYW0gdG8gYmUgDQogIDQpIFVzZSBhIFNwYXJrIGltcGxlbWVudGF0aW9uIHRvIHBlcmZvcm0gQUxTIChiZXN0IHBlcmZvcm1pbmcgbWV0aG9kIGZyb20gdGhlIHNlbWVzdGVyIGFuZCBjYW4gYmUgaW1wbGVtZW50ZWQgaW4gc3BhcmspDQogIDUpIEJ1aWxkIG91ciByZWNvbW1lbmRlciB1c2luZyB0aGUgcHJlZGljdGlvbiBtYXRyaXggZm9yIG91ciB0ZWFtLCB0aGUgcHJlZGljdGlvbiBtYXRyaXggZm9yIGFsbCB0ZWFtcywgYW55IG90aGVyIGludGVyZXN0aW5nIHZhcmlhYmxlcyB0aGF0IHdlIGZpbmQgb3IgY3JlYXRlDQogIDYpIEV2YWx1YXRlIHRoZSByZWNvbW1lbmRhdGlvbiBzeXN0ZW0uDQoNCg==