Game Score Introduction

The 2022-2023 PHF formally kicked off its season last weekend and, in a desire to produce more PHF analytics content, I began working on automated Game Score by Player reports for each team and player. Game Score is an idea that’s been around for a while in the PHF/NWHL, dating back to work from Shawn Ferris in 2018 and Mike Murphy in 2019.

As I perused the boxscores from the opening weekend games, I noticed that there was more data available than I expected, including goals, assists, shots (on goal, blocked, etc), blocks, penalty minutes, faceoffs, and even giveaways/takeaways. With this relative wealth of data, I wanted to A) re-work game score and B) make pretty charts!

I took a similar path to Mike and Shawn for this version of game score, essentially taking those aforementioned events and taking their occurence relative to goals. For example, there were 334 goals in the PHF in 2022 and there were 3604 shots_on_goal, which results in a shots_on_goal weight of 0.095. That process is repeated for all those stats, with some (giveaways, penalty minutes, shots blocked) being given a negative weight because they are “bad” events. With Game Score, a higher number is better and it is intended to be roughly on the same scale as points on a player basis.

The data for this project fastRhockey, which I created to make PHF data easily available. The charts have been automated using a BATCH script in conjunction with R to automate finding the games for the day and tweeting out the resulting graphics.


Game Score Weights

The weights for Game Score are split into four components: Offense, Defense, Faceoff, Penalty. In the table below, you can view the weights for the 22-23 season, as well as the component that each stat falls into.

With these weights, you can run a players boxscore data through a function that uses these weights multiplied against their count data to produce their game score. It’s a very quick and repeatable process and easily automated postgame.

Once Game Score has been calculated, it’s time for pretty plots to be created! You can find all the reports from this weekend here, but I’ll walk through the report for the Minnesota Whitecaps in their 2-3 loss to the Toronto Six.


Example

There’s a lot going on here, so let’s walk through it step-by-step. The players are sorted by total game score, so the players with the highest total are at the top (Jonna Albers) and the lowest is at the bottom (Sydney Baldwin). Each player’s actual game score is then positioned as text next to their bars, indicating their overall game score value.

What’s really fun about this chart is that I break the combined game score into its components to represent HOW a player arrived at their total value for a game. Did they have a stellar offensive game? Did they play defense incredibly well? Was their value boosted by a crazy faceoff game? Did they tank their value by spending a ton of time in the penalty box? All those questions are answerable with this report.

Let’s take Liz Schepers since she did a little bit of everything in this game.

Her overall Game Score was +0.46, but how did she get there? Well, she provided a TON of value offensively AND defensively, accruing +1.19 oGS and +0.42 dGS thanks to scoring one goal, taking two shots on goal, and blocking one shot. She did not record a takeaway, a giveaway (which is how a lot of skaters lose value) or have a shot blocked. On offense and defense, her only contributions were positive.

Alas, that trend did not hold true on fGS or pGS. Schepers went won five faceoffs and lost nine on Sunday; given that a faceoff win and faceoff loss are roughly equal value, she essentially gets dinged for losing four faceoffs, which comes out to -0.42, wiping out her defensive contributions in one fell swoop. She additionally spent two minutes in the penalty box thanks to a Holding infraction, further hurting her overall contribution.

All in all, Schepers was clearly the most hurt by the penalty minutes that she took. She made a ton of offensive and defensive contributions, but she probably shouldn’t take 14 faceoffs for the Whitecaps moving forward, though their other main option, Ashleigh Brykaliuk, who took 23, won 12 and lost 11 (as an aside, the only stats that Brykaliuk recorded was that faceoff record so maybe she’s supposed to be their faceoff expert?).

Additionally, the chart includes a player’s Shots on Goal (SOG), Giveaways (Gv), and Takeaways (Tk) from that game on the right-hand side, as almost a “triple-slash line” for players, just to give a quick overview at some more process-based stats, rather than points or something (in reality, I included those because I needed something on that side to center titles/legends/etc because I couldn’t center them otherwise…).


Next Steps

The main goal of this writeup and v1 of this updated Game Score is to get something out there. It is by no means perfect and has a lot of revisions already in the work.

First, I plan to move giveaways into the oGS component. I originally had it in dGS to balance out takeaways, but it makes so much more sense in oGS.

Additionally, I need to do much more detailed exploration of how penalty and shots_blocked should be assigned and what weight they deserve. Both are inherently negative events, but I think that they may be too heavily weighted in the current configuration. On the penalty end, I think there may be some sort of scaled penalty weight I can create, where just a minute or two of penalty time isn’t terribly punishing, but ten to fifteen (or ejected) has a much larger effect. It’s one of those things that having Time on Ice (TOI) data for would be a huge help, but beggars can’t be choosers.

For shots_blocked, I am interested in doing some research to see if shot on goal rates spike shortly after a blocked shot, like if the richochet provides more offensive opportunities. If so, it’s possible that A) shots blocked should have a POSITIVE rate or B) that they should at least be less impactful.

Furthermore, I hope to be able to explore some different methods of deriving Game Score and its weights, specifically as to whether some sort of regression approach to deriving weights. There are a few ideas percolating and floating around in my head and we will certainly see which of them make it to paper.

And, of course, because this is the PHF, we are at the mercy of the scorekeepers for each team and game to properly record the events for each game. I’ll be trying to keep an eye on if there are any specific discrepancies that are consistent across a specific home arena, but we will make do.


What About Goalies

Well, goalies are weird. And, with the quality/type of data we have available for the PHF, there’s not a whole lot to do. I’m not implementing a new box score approach because I think Mike’s goalie game score (Goalie Game Score = (.15*SV) – GA) is already pretty good. Personally, I am working on a few new ideas re: measuring goalies, but they’re not finished yet, so you’ll have to stay on the edge of your seat until I get there.

LS0tDQp0aXRsZTogIlBIRiBHYW1lIFNjb3JlIHYxIg0KYXV0aG9yOiAiQmVuIEhvd2VsbCINCmRhdGU6ICIxMS84LzIwMjIiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgaGlnaGxpZ2h0ZXI6IG51bGwNCiAgICB0aGVtZTogImZsYXRseSINCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFDQogICAgIyB0b2M6IHRydWUNCiAgICAjIHRvY19mbG9hdDogdHJ1ZQ0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgIGZpZy5hbGlnbiA9ICJjZW50ZXIiKQ0KDQojIGxpYnJhcnkodHdlZXRybWQpDQpgYGANCg0KKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqDQoNCiMgR2FtZSBTY29yZSBJbnRyb2R1Y3Rpb24NCg0KVGhlIDIwMjItMjAyMyBQSEYgZm9ybWFsbHkga2lja2VkIG9mZiBpdHMgc2Vhc29uIGxhc3Qgd2Vla2VuZCBhbmQsIGluIGEgZGVzaXJlIHRvIHByb2R1Y2UgbW9yZSBQSEYgYW5hbHl0aWNzIGNvbnRlbnQsIEkgYmVnYW4gd29ya2luZyBvbiBhdXRvbWF0ZWQgR2FtZSBTY29yZSBieSBQbGF5ZXIgcmVwb3J0cyBmb3IgZWFjaCB0ZWFtIGFuZCBwbGF5ZXIuIEdhbWUgU2NvcmUgaXMgYW4gaWRlYSB0aGF0J3MgYmVlbiBhcm91bmQgZm9yIGEgd2hpbGUgaW4gdGhlIFBIRi9OV0hMLCBkYXRpbmcgYmFjayB0byB3b3JrIGZyb20gW1NoYXduIEZlcnJpc10oaHR0cHM6Ly9ob2NrZXktZ3JhcGhzLmNvbS8yMDE4LzAzLzIyL2FuLWludHJvZHVjdGlvbi10by1ud2hsLWdhbWUtc2NvcmUvKSBpbiAyMDE4IGFuZCBbTWlrZSBNdXJwaHldKGh0dHBzOi8vaG9ja2V5LWdyYXBocy5jb20vMjAxOS8wOC8yMS9yZXZpc2l0aW5nLW53aGwtZ2FtZS1zY29yZS8pIGluIDIwMTkuICAgICAgICAgICAgICAgICAgICAgDQoNCkFzIEkgcGVydXNlZCB0aGUgYm94c2NvcmVzIGZyb20gdGhlIG9wZW5pbmcgd2Vla2VuZCBnYW1lcywgSSBub3RpY2VkIHRoYXQgdGhlcmUgd2FzIG1vcmUgZGF0YSBhdmFpbGFibGUgdGhhbiBJIGV4cGVjdGVkLCBpbmNsdWRpbmcgZ29hbHMsIGFzc2lzdHMsIHNob3RzIChvbiBnb2FsLCBibG9ja2VkLCBldGMpLCBibG9ja3MsIHBlbmFsdHkgbWludXRlcywgZmFjZW9mZnMsIGFuZCBldmVuIGdpdmVhd2F5cy90YWtlYXdheXMuIFdpdGggdGhpcyByZWxhdGl2ZSB3ZWFsdGggb2YgZGF0YSwgSSB3YW50ZWQgdG8gQSkgcmUtd29yayBnYW1lIHNjb3JlIGFuZCBCKSBtYWtlIHByZXR0eSBjaGFydHMhICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQoNCkkgdG9vayBhIHNpbWlsYXIgcGF0aCB0byBNaWtlIGFuZCBTaGF3biBmb3IgdGhpcyB2ZXJzaW9uIG9mIGdhbWUgc2NvcmUsIGVzc2VudGlhbGx5IHRha2luZyB0aG9zZSBhZm9yZW1lbnRpb25lZCBldmVudHMgYW5kIHRha2luZyB0aGVpciBvY2N1cmVuY2UgcmVsYXRpdmUgdG8gZ29hbHMuIEZvciBleGFtcGxlLCB0aGVyZSB3ZXJlIDMzNCBgZ29hbHNgIGluIHRoZSBQSEYgaW4gMjAyMiBhbmQgdGhlcmUgd2VyZSAzNjA0IGBzaG90c19vbl9nb2FsYCwgd2hpY2ggcmVzdWx0cyBpbiBhIGBzaG90c19vbl9nb2FsYCB3ZWlnaHQgb2YgMC4wOTUuIFRoYXQgcHJvY2VzcyBpcyByZXBlYXRlZCBmb3IgYWxsIHRob3NlIHN0YXRzLCB3aXRoIHNvbWUgKGdpdmVhd2F5cywgcGVuYWx0eSBtaW51dGVzLCBzaG90cyBibG9ja2VkKSBiZWluZyBnaXZlbiBhIG5lZ2F0aXZlIHdlaWdodCBiZWNhdXNlIHRoZXkgYXJlICJiYWQiIGV2ZW50cy4gV2l0aCBHYW1lIFNjb3JlLCBhIGhpZ2hlciBudW1iZXIgaXMgYmV0dGVyIGFuZCBpdCBpcyBpbnRlbmRlZCB0byBiZSByb3VnaGx5IG9uIHRoZSBzYW1lIHNjYWxlIGFzIHBvaW50cyBvbiBhIHBsYXllciBiYXNpcy4gICAgICAgICAgICAgICAgICAgDQoNClRoZSBkYXRhIGZvciB0aGlzIHByb2plY3QgW2Zhc3RSaG9ja2V5XShodHRwczovL2Zhc3RyaG9ja2V5LnNwb3J0c2RhdGF2ZXJzZS5vcmcvKSwgd2hpY2ggSSBjcmVhdGVkIHRvIG1ha2UgUEhGIGRhdGEgZWFzaWx5IGF2YWlsYWJsZS4gVGhlIGNoYXJ0cyBoYXZlIGJlZW4gYXV0b21hdGVkIHVzaW5nIGEgQkFUQ0ggc2NyaXB0IGluIGNvbmp1bmN0aW9uIHdpdGggUiB0byBhdXRvbWF0ZSBmaW5kaW5nIHRoZSBnYW1lcyBmb3IgdGhlIGRheSBhbmQgdHdlZXRpbmcgb3V0IHRoZSByZXN1bHRpbmcgZ3JhcGhpY3MuICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCg0KKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqDQoNCiMgR2FtZSBTY29yZSBXZWlnaHRzDQoNClRoZSB3ZWlnaHRzIGZvciBHYW1lIFNjb3JlIGFyZSBzcGxpdCBpbnRvIGZvdXIgY29tcG9uZW50czogT2ZmZW5zZSwgRGVmZW5zZSwgRmFjZW9mZiwgUGVuYWx0eS4gSW4gdGhlIHRhYmxlIGJlbG93LCB5b3UgY2FuIHZpZXcgdGhlIHdlaWdodHMgZm9yIHRoZSAyMi0yMyBzZWFzb24sIGFzIHdlbGwgYXMgdGhlIGNvbXBvbmVudCB0aGF0IGVhY2ggc3RhdCBmYWxscyBpbnRvLiAgICAgICAgICAgICAgICAgICAgICAgICAgDQoNCmBgYHtyfQ0KIyB0d2VldF9lbWJlZCgiaHR0cHM6Ly90d2l0dGVyLmNvbS9iZW5ob3dlbGw3MS9zdGF0dXMvMTU4OTgxODMyMDEzMTU4ODA5Nz9zPTIwJnQ9TVhYd3piUkRiNFJ1anNkRHkyc1NGUSIsIGFsaWduID0gImNlbnRlciIpDQpgYGANCg0KYGBge3J9DQpyZXF1aXJlKHRpZHl2ZXJzZSkNCmxpYnJhcnkocmVhY3RhYmxlKQ0KbGlicmFyeShyZWFjdGFibGVmbXRyKQ0KDQpkZiA8LSByb3VuZChyZWFkLmNzdigid2VpZ2h0cy5jc3YiKSwgMykNCg0KZGYgJT4lDQogIGRwbHlyOjpzZWxlY3QoYXNzaXN0c193ZWlnaHQsIHNob3RzX29uX2dvYWxfd2VpZ2h0LCBzaG90c19ibG9ja2VkX3dlaWdodCwNCiAgICAgICAgICAgICAgICBibG9ja3Nfd2VpZ2h0LCB0YWtlYXdheXNfd2VpZ2h0LCBnaXZlYXdheXNfd2VpZ2h0LCANCiAgICAgICAgICAgICAgICBmYWNlb2Zmc193b25fd2VpZ2h0LCBmYWNlb2Zmc19sb3N0X3dlaWdodCwgDQogICAgICAgICAgICAgICAgcGVuYWx0eV9taW51dGVzX3dlaWdodCkgJT4lDQogIGRwbHlyOjptdXRhdGUoc2hvdHNfYmxvY2tlZF93ZWlnaHQgPSAtc2hvdHNfYmxvY2tlZF93ZWlnaHQsDQogICAgICAgICAgICAgICAgZ2l2ZWF3YXlzX3dlaWdodCA9IC1naXZlYXdheXNfd2VpZ2h0LA0KICAgICAgICAgICAgICAgIGZhY2VvZmZzX2xvc3Rfd2VpZ2h0ID0gLWZhY2VvZmZzX2xvc3Rfd2VpZ2h0LA0KICAgICAgICAgICAgICAgIHBlbmFsdHlfbWludXRlc193ZWlnaHQgPSAtcGVuYWx0eV9taW51dGVzX3dlaWdodCkgJT4lDQogICMgaGVhZCg4KSAlPiUNCiAgcmVhY3RhYmxlKGRlZmF1bHRQYWdlU2l6ZSA9IDI1LA0KICAgICAgICAgICAgc3RyaXBlZCA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgI2JvcmRlcmVkID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICBkZWZhdWx0Q29sRGVmID0gY29sRGVmKA0KICAgICAgICAgICAgICAgICAgICAgICAgICBhbGlnbiA9ICJjZW50ZXIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBtaW5XaWR0aCA9IDEwMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyQ2xhc3MgPSAiaGVhZGVyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgc29ydE5BTGFzdCA9IFRSVUUsIGhlYWRlclN0eWxlID0gbGlzdChmb250V2VpZ2h0ID0gNzAwKQ0KICAgICAgICAgICAgICAgICAgICAgICksDQogICAgICAgICAgICAgICAgICAgICAgdGhlbWUgPSByZWFjdGFibGVUaGVtZSgNCiAgICAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyU3R5bGUgPSBsaXN0KA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiY6aG92ZXJbYXJpYS1zb3J0XSIgPSBsaXN0KGJhY2tncm91bmQgPSAiaHNsKDAsIDAlLCA5NiUpIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiJlthcmlhLXNvcnQ9J2FzY2VuZGluZyddLCAmW2FyaWEtc29ydD0nZGVzY2VuZGluZyddIiA9IGxpc3QoYmFja2dyb3VuZCA9ICJoc2woMCwgMCUsIDk2JSkiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvcmRlckNvbG9yID0gIiM1NTUiDQogICAgICAgICAgICAgICAgICAgICAgICAgICksDQogICAgICAgICAgICAgICAgICAgICAgICAgIGJvcmRlckNvbG9yID0gIiNkZmUyZTUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpcGVkQ29sb3IgPSAiI2Y2ZjhmYSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGhpZ2hsaWdodENvbG9yID0gIiNmMGY1ZjkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBjZWxsUGFkZGluZyA9ICI4cHggMTJweCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHN0eWxlID0gbGlzdChmb250RmFtaWx5ID0gIi1hcHBsZS1zeXN0ZW0sIEJsaW5rTWFjU3lzdGVtRm9udCwgU2Vnb2UgVUksIEhlbHZldGljYSwgQXJpYWwsIHNhbnMtc2VyaWYiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2VhcmNoSW5wdXRTdHlsZSA9IGxpc3Qod2lkdGggPSAiMTAwJSIpDQogICAgICAgICAgICAgICAgICAgICAgKSwNCiAgICAgICAgICAgIGNvbHVtbnMgPSBsaXN0KA0KICAgICAgICAgICAgICAjIGdvYWxzX3dlaWdodCA9IGNvbERlZigNCiAgICAgICAgICAgICAgIyAgIG5hbWUgPSAid0dvYWwiDQogICAgICAgICAgICAgICMgKSwNCiAgICAgICAgICAgICAgYXNzaXN0c193ZWlnaHQgPSBjb2xEZWYoDQogICAgICAgICAgICAgICAgbmFtZSA9ICJ3QXNzaXN0cyINCiAgICAgICAgICAgICAgKSwNCiAgICAgICAgICAgICAgc2hvdHNfb25fZ29hbF93ZWlnaHQgPSBjb2xEZWYoDQogICAgICAgICAgICAgICAgbmFtZSA9ICJ3U09HIg0KICAgICAgICAgICAgICApLA0KICAgICAgICAgICAgICBnaXZlYXdheXNfd2VpZ2h0ID0gY29sRGVmKA0KICAgICAgICAgICAgICAgIG5hbWUgPSAid0d2QSINCiAgICAgICAgICAgICAgKSwNCiAgICAgICAgICAgICAgc2hvdHNfYmxvY2tlZF93ZWlnaHQgPSBjb2xEZWYoDQogICAgICAgICAgICAgICAgbmFtZSA9ICJ3U2hCbGsiDQogICAgICAgICAgICAgICksDQogICAgICAgICAgICAgIGJsb2Nrc193ZWlnaHQgPSBjb2xEZWYoDQogICAgICAgICAgICAgICAgbmFtZSA9ICJ3QmxvY2tzIg0KICAgICAgICAgICAgICApLA0KICAgICAgICAgICAgICB0YWtlYXdheXNfd2VpZ2h0ID0gY29sRGVmKA0KICAgICAgICAgICAgICAgIG5hbWUgPSAid1RrQSINCiAgICAgICAgICAgICAgKSwNCiAgICAgICAgICAgICAgZmFjZW9mZnNfd29uX3dlaWdodCA9IGNvbERlZigNCiAgICAgICAgICAgICAgICBuYW1lID0gIndGVyINCiAgICAgICAgICAgICAgKSwNCiAgICAgICAgICAgICAgZmFjZW9mZnNfbG9zdF93ZWlnaHQgPSBjb2xEZWYoDQogICAgICAgICAgICAgICAgbmFtZSA9ICJ3RkwiDQogICAgICAgICAgICAgICksDQogICAgICAgICAgICAgIHBlbmFsdHlfbWludXRlc193ZWlnaHQgPSBjb2xEZWYoDQogICAgICAgICAgICAgICAgbmFtZSA9ICJ3UGVuIg0KICAgICAgICAgICAgICApDQogICAgICAgICAgICApLA0KICAgICAgICAgICAgY29sdW1uR3JvdXBzID0gbGlzdCgNCiAgICAgICAgICAgICAgY29sR3JvdXAobmFtZSA9ICJPZmZlbnNlIChvR1MpIiwgY29sdW1ucyA9IGMoImFzc2lzdHNfd2VpZ2h0IiwgInNob3RzX29uX2dvYWxfd2VpZ2h0IiwgInNob3RzX2Jsb2NrZWRfd2VpZ2h0IikpLA0KICAgICAgICAgICAgICBjb2xHcm91cChuYW1lID0gIkRlZmVuc2UgKGRHUykiLCBjb2x1bW5zID0gYygiYmxvY2tzX3dlaWdodCIsICJ0YWtlYXdheXNfd2VpZ2h0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdpdmVhd2F5c193ZWlnaHQiKSksDQogICAgICAgICAgICAgIGNvbEdyb3VwKG5hbWUgPSAiRmFjZW9mZiAoZkdTKSIsIGNvbHVtbnMgPSBjKCJmYWNlb2Zmc193b25fd2VpZ2h0IiwgImZhY2VvZmZzX2xvc3Rfd2VpZ2h0IikpLA0KICAgICAgICAgICAgICBjb2xHcm91cChuYW1lID0gIlBlbmFsdHkgKHBHUykiLCBjb2x1bW5zID0gYygicGVuYWx0eV9taW51dGVzX3dlaWdodCIpKQ0KICAgICAgICAgICAgKSkgDQpgYGANCg0KV2l0aCB0aGVzZSB3ZWlnaHRzLCB5b3UgY2FuIHJ1biBhIHBsYXllcnMgYm94c2NvcmUgZGF0YSB0aHJvdWdoIGEgZnVuY3Rpb24gdGhhdCB1c2VzIHRoZXNlIHdlaWdodHMgbXVsdGlwbGllZCBhZ2FpbnN0IHRoZWlyIGNvdW50IGRhdGEgdG8gcHJvZHVjZSB0aGVpciBnYW1lIHNjb3JlLiBJdCdzIGEgdmVyeSBxdWljayBhbmQgcmVwZWF0YWJsZSBwcm9jZXNzIGFuZCBlYXNpbHkgYXV0b21hdGVkIHBvc3RnYW1lLiAgICAgICAgICAgICAgICAgICANCg0KT25jZSBgR2FtZSBTY29yZWAgaGFzIGJlZW4gY2FsY3VsYXRlZCwgaXQncyB0aW1lIGZvciBwcmV0dHkgcGxvdHMgdG8gYmUgY3JlYXRlZCEgWW91IGNhbiBmaW5kIGFsbCB0aGUgcmVwb3J0cyBmcm9tIHRoaXMgd2Vla2VuZCBbaGVyZV0oaHR0cHM6Ly90d2l0dGVyLmNvbS9iZW5ob3dlbGw3MS9zdGF0dXMvMTU4OTgxODMyMDEzMTU4ODA5Nz9zPTIwJnQ9TVhYd3piUkRiNFJ1anNkRHkyc1NGUSksIGJ1dCBJJ2xsIHdhbGsgdGhyb3VnaCB0aGUgcmVwb3J0IGZvciB0aGUgTWlubmVzb3RhIFdoaXRlY2FwcyBpbiB0aGVpciAyLTMgbG9zcyB0byB0aGUgVG9yb250byBTaXguICAgICAgICAgICAgICAgICAgDQoNCioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0KDQojIEV4YW1wbGUNCg0KIVtdKE1pbm5lc290YSBXaGl0ZWNhcHNfZ2FtZV9zY29yZS5wbmcpDQoNClRoZXJlJ3MgYSBsb3QgZ29pbmcgb24gaGVyZSwgc28gbGV0J3Mgd2FsayB0aHJvdWdoIGl0IHN0ZXAtYnktc3RlcC4gVGhlIHBsYXllcnMgYXJlIHNvcnRlZCBieSB0b3RhbCBnYW1lIHNjb3JlLCBzbyB0aGUgcGxheWVycyB3aXRoIHRoZSBoaWdoZXN0IHRvdGFsIGFyZSBhdCB0aGUgdG9wIChKb25uYSBBbGJlcnMpIGFuZCB0aGUgbG93ZXN0IGlzIGF0IHRoZSBib3R0b20gKFN5ZG5leSBCYWxkd2luKS4gRWFjaCBwbGF5ZXIncyBhY3R1YWwgZ2FtZSBzY29yZSBpcyB0aGVuIHBvc2l0aW9uZWQgYXMgdGV4dCBuZXh0IHRvIHRoZWlyIGJhcnMsIGluZGljYXRpbmcgdGhlaXIgb3ZlcmFsbCBnYW1lIHNjb3JlIHZhbHVlLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KDQpXaGF0J3MgcmVhbGx5IGZ1biBhYm91dCB0aGlzIGNoYXJ0IGlzIHRoYXQgSSBicmVhayB0aGUgY29tYmluZWQgZ2FtZSBzY29yZSBpbnRvIGl0cyBjb21wb25lbnRzIHRvIHJlcHJlc2VudCBIT1cgYSBwbGF5ZXIgYXJyaXZlZCBhdCB0aGVpciB0b3RhbCB2YWx1ZSBmb3IgYSBnYW1lLiBEaWQgdGhleSBoYXZlIGEgc3RlbGxhciBvZmZlbnNpdmUgZ2FtZT8gRGlkIHRoZXkgcGxheSBkZWZlbnNlIGluY3JlZGlibHkgd2VsbD8gV2FzIHRoZWlyIHZhbHVlIGJvb3N0ZWQgYnkgYSBjcmF6eSBmYWNlb2ZmIGdhbWU/IERpZCB0aGV5IHRhbmsgdGhlaXIgdmFsdWUgYnkgc3BlbmRpbmcgYSB0b24gb2YgdGltZSBpbiB0aGUgcGVuYWx0eSBib3g/IEFsbCB0aG9zZSBxdWVzdGlvbnMgYXJlIGFuc3dlcmFibGUgd2l0aCB0aGlzIHJlcG9ydC4gICAgICAgICAgICAgICAgICAgICAgICANCg0KYGBge3J9DQpkYXRhLmZyYW1lKA0KICAicGxheWVyIiA9IGMoIkxpeiBTY2hlcGVycyIpLA0KICAiZ2FtZV9zY29yZSIgPSBjKDAuNDYpLA0KICAib2dzIiA9IGMoMS4xOSksDQogICJkZ3MiID0gYygwLjQyKSwNCiAgImZncyIgPSBjKC0wLjQyKSwNCiAgInBncyIgPSBjKC0wLjcyKQ0KKSAlPiUNCiAgcmVhY3RhYmxlKGRlZmF1bHRQYWdlU2l6ZSA9IDI1LA0KICAgICAgICAgICAgc3RyaXBlZCA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgI2JvcmRlcmVkID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICBkZWZhdWx0Q29sRGVmID0gY29sRGVmKA0KICAgICAgICAgICAgICAgICAgICAgICAgICBhbGlnbiA9ICJjZW50ZXIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBtaW5XaWR0aCA9IDEwMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyQ2xhc3MgPSAiaGVhZGVyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgc29ydE5BTGFzdCA9IFRSVUUsIGhlYWRlclN0eWxlID0gbGlzdChmb250V2VpZ2h0ID0gNzAwKQ0KICAgICAgICAgICAgICAgICAgICAgICksDQogICAgICAgICAgICAgICAgICAgICAgdGhlbWUgPSByZWFjdGFibGVUaGVtZSgNCiAgICAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyU3R5bGUgPSBsaXN0KA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiY6aG92ZXJbYXJpYS1zb3J0XSIgPSBsaXN0KGJhY2tncm91bmQgPSAiaHNsKDAsIDAlLCA5NiUpIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiJlthcmlhLXNvcnQ9J2FzY2VuZGluZyddLCAmW2FyaWEtc29ydD0nZGVzY2VuZGluZyddIiA9IGxpc3QoYmFja2dyb3VuZCA9ICJoc2woMCwgMCUsIDk2JSkiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvcmRlckNvbG9yID0gIiM1NTUiDQogICAgICAgICAgICAgICAgICAgICAgICAgICksDQogICAgICAgICAgICAgICAgICAgICAgICAgIGJvcmRlckNvbG9yID0gIiNkZmUyZTUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpcGVkQ29sb3IgPSAiI2Y2ZjhmYSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGhpZ2hsaWdodENvbG9yID0gIiNmMGY1ZjkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBjZWxsUGFkZGluZyA9ICI4cHggMTJweCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHN0eWxlID0gbGlzdChmb250RmFtaWx5ID0gIi1hcHBsZS1zeXN0ZW0sIEJsaW5rTWFjU3lzdGVtRm9udCwgU2Vnb2UgVUksIEhlbHZldGljYSwgQXJpYWwsIHNhbnMtc2VyaWYiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2VhcmNoSW5wdXRTdHlsZSA9IGxpc3Qod2lkdGggPSAiMTAwJSIpDQogICAgICAgICAgICAgICAgICAgICAgKSwNCiAgICAgICAgICAgIGNvbHVtbnMgPSBsaXN0KA0KICAgICAgICAgICAgICAjIGdvYWxzX3dlaWdodCA9IGNvbERlZigNCiAgICAgICAgICAgICAgIyAgIG5hbWUgPSAid0dvYWwiDQogICAgICAgICAgICAgICMgKSwNCiAgICAgICAgICAgICAgcGxheWVyID0gY29sRGVmKA0KICAgICAgICAgICAgICAgIG5hbWUgPSAiUGxheWVyIg0KICAgICAgICAgICAgICApLA0KICAgICAgICAgICAgICBnYW1lX3Njb3JlID0gY29sRGVmKA0KICAgICAgICAgICAgICAgIG5hbWUgPSAiR2FtZSBTY29yZSINCiAgICAgICAgICAgICAgKSwNCiAgICAgICAgICAgICAgb2dzID0gY29sRGVmKA0KICAgICAgICAgICAgICAgIG5hbWUgPSAib0dTIg0KICAgICAgICAgICAgICApLA0KICAgICAgICAgICAgICBkZ3MgPSBjb2xEZWYoDQogICAgICAgICAgICAgICAgbmFtZSA9ICJkR1MiDQogICAgICAgICAgICAgICksDQogICAgICAgICAgICAgIGZncyA9IGNvbERlZigNCiAgICAgICAgICAgICAgICBuYW1lID0gImZHUyINCiAgICAgICAgICAgICAgKSwNCiAgICAgICAgICAgICAgcGdzID0gY29sRGVmKA0KICAgICAgICAgICAgICAgIG5hbWUgPSAicEdTIg0KICAgICAgICAgICAgICApDQogICAgICAgICAgICApKSANCmBgYA0KDQpMZXQncyB0YWtlIExpeiBTY2hlcGVycyBzaW5jZSBzaGUgZGlkIGEgbGl0dGxlIGJpdCBvZiBldmVyeXRoaW5nIGluIHRoaXMgZ2FtZS4gICAgICAgICAgICAgICAgICAgICAgICAgICAgDQoNCkhlciBvdmVyYWxsIEdhbWUgU2NvcmUgd2FzICswLjQ2LCBidXQgaG93IGRpZCBzaGUgZ2V0IHRoZXJlPyBXZWxsLCBzaGUgcHJvdmlkZWQgYSBUT04gb2YgdmFsdWUgb2ZmZW5zaXZlbHkgQU5EIGRlZmVuc2l2ZWx5LCBhY2NydWluZyArMS4xOSBvR1MgYW5kICswLjQyIGRHUyB0aGFua3MgdG8gc2NvcmluZyBvbmUgZ29hbCwgdGFraW5nIHR3byBzaG90cyBvbiBnb2FsLCBhbmQgYmxvY2tpbmcgb25lIHNob3QuIFNoZSBkaWQgbm90IHJlY29yZCBhIHRha2Vhd2F5LCBhIGdpdmVhd2F5ICh3aGljaCBpcyBob3cgYSBsb3Qgb2Ygc2thdGVycyBsb3NlIHZhbHVlKSBvciBoYXZlIGEgc2hvdCBibG9ja2VkLiBPbiBvZmZlbnNlIGFuZCBkZWZlbnNlLCBoZXIgb25seSBjb250cmlidXRpb25zIHdlcmUgcG9zaXRpdmUuICAgICAgICAgICAgICAgICAgICAgICAgICANCg0KQWxhcywgdGhhdCB0cmVuZCBkaWQgbm90IGhvbGQgdHJ1ZSBvbiBmR1Mgb3IgcEdTLiBTY2hlcGVycyB3ZW50IHdvbiBmaXZlIGZhY2VvZmZzIGFuZCBsb3N0IG5pbmUgb24gU3VuZGF5OyBnaXZlbiB0aGF0IGEgZmFjZW9mZiB3aW4gYW5kIGZhY2VvZmYgbG9zcyBhcmUgcm91Z2hseSBlcXVhbCB2YWx1ZSwgc2hlIGVzc2VudGlhbGx5IGdldHMgZGluZ2VkIGZvciBsb3NpbmcgZm91ciBmYWNlb2Zmcywgd2hpY2ggY29tZXMgb3V0IHRvIC0wLjQyLCB3aXBpbmcgb3V0IGhlciBkZWZlbnNpdmUgY29udHJpYnV0aW9ucyBpbiBvbmUgZmVsbCBzd29vcC4gU2hlIGFkZGl0aW9uYWxseSBzcGVudCB0d28gbWludXRlcyBpbiB0aGUgcGVuYWx0eSBib3ggdGhhbmtzIHRvIGEgSG9sZGluZyBpbmZyYWN0aW9uLCBmdXJ0aGVyIGh1cnRpbmcgaGVyIG92ZXJhbGwgY29udHJpYnV0aW9uLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQoNCkFsbCBpbiBhbGwsIFNjaGVwZXJzIHdhcyBjbGVhcmx5IHRoZSBtb3N0IGh1cnQgYnkgdGhlIHBlbmFsdHkgbWludXRlcyB0aGF0IHNoZSB0b29rLiBTaGUgbWFkZSBhIHRvbiBvZiBvZmZlbnNpdmUgYW5kIGRlZmVuc2l2ZSBjb250cmlidXRpb25zLCBidXQgc2hlIHByb2JhYmx5IHNob3VsZG4ndCB0YWtlIDE0IGZhY2VvZmZzIGZvciB0aGUgV2hpdGVjYXBzIG1vdmluZyBmb3J3YXJkLCB0aG91Z2ggdGhlaXIgb3RoZXIgbWFpbiBvcHRpb24sIEFzaGxlaWdoIEJyeWthbGl1aywgd2hvIHRvb2sgMjMsIHdvbiAxMiBhbmQgbG9zdCAxMSAoYXMgYW4gYXNpZGUsIHRoZSBvbmx5IHN0YXRzIHRoYXQgQnJ5a2FsaXVrIHJlY29yZGVkIHdhcyB0aGF0IGZhY2VvZmYgcmVjb3JkIHNvIG1heWJlIHNoZSdzIHN1cHBvc2VkIHRvIGJlIHRoZWlyIGZhY2VvZmYgZXhwZXJ0PykuICAgICAgICAgICAgDQoNCkFkZGl0aW9uYWxseSwgdGhlIGNoYXJ0IGluY2x1ZGVzIGEgcGxheWVyJ3MgU2hvdHMgb24gR29hbCAoU09HKSwgR2l2ZWF3YXlzIChHdiksIGFuZCBUYWtlYXdheXMgKFRrKSBmcm9tIHRoYXQgZ2FtZSBvbiB0aGUgcmlnaHQtaGFuZCBzaWRlLCBhcyBhbG1vc3QgYSAidHJpcGxlLXNsYXNoIGxpbmUiIGZvciBwbGF5ZXJzLCBqdXN0IHRvIGdpdmUgYSBxdWljayBvdmVydmlldyBhdCBzb21lIG1vcmUgcHJvY2Vzcy1iYXNlZCBzdGF0cywgcmF0aGVyIHRoYW4gcG9pbnRzIG9yIHNvbWV0aGluZyAoaW4gcmVhbGl0eSwgSSBpbmNsdWRlZCB0aG9zZSBiZWNhdXNlIEkgbmVlZGVkIHNvbWV0aGluZyBvbiB0aGF0IHNpZGUgdG8gY2VudGVyIHRpdGxlcy9sZWdlbmRzL2V0YyBiZWNhdXNlIEkgY291bGRuJ3QgY2VudGVyIHRoZW0gb3RoZXJ3aXNlLi4uKS4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCg0KKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqDQoNCiMgTmV4dCBTdGVwcw0KDQpUaGUgbWFpbiBnb2FsIG9mIHRoaXMgd3JpdGV1cCBhbmQgdjEgb2YgdGhpcyB1cGRhdGVkIEdhbWUgU2NvcmUgaXMgdG8gZ2V0IHNvbWV0aGluZyBvdXQgdGhlcmUuIEl0IGlzIGJ5IG5vIG1lYW5zIHBlcmZlY3QgYW5kIGhhcyBhIGxvdCBvZiByZXZpc2lvbnMgYWxyZWFkeSBpbiB0aGUgd29yay4gICAgICAgICAgICAgICAgICAgDQoNCkZpcnN0LCBJIHBsYW4gdG8gbW92ZSBgZ2l2ZWF3YXlzYCBpbnRvIHRoZSBgb0dTYCBjb21wb25lbnQuIEkgb3JpZ2luYWxseSBoYWQgaXQgaW4gYGRHU2AgdG8gYmFsYW5jZSBvdXQgYHRha2Vhd2F5c2AsIGJ1dCBpdCBtYWtlcyBzbyBtdWNoIG1vcmUgc2Vuc2UgaW4gYG9HU2AuICAgICAgICAgICAgICAgICAgICAgIA0KDQpBZGRpdGlvbmFsbHksIEkgbmVlZCB0byBkbyBtdWNoIG1vcmUgZGV0YWlsZWQgZXhwbG9yYXRpb24gb2YgaG93IGBwZW5hbHR5YCBhbmQgYHNob3RzX2Jsb2NrZWRgIHNob3VsZCBiZSBhc3NpZ25lZCBhbmQgd2hhdCB3ZWlnaHQgdGhleSBkZXNlcnZlLiBCb3RoIGFyZSBpbmhlcmVudGx5IG5lZ2F0aXZlIGV2ZW50cywgYnV0IEkgdGhpbmsgdGhhdCB0aGV5IG1heSBiZSB0b28gaGVhdmlseSB3ZWlnaHRlZCBpbiB0aGUgY3VycmVudCBjb25maWd1cmF0aW9uLiBPbiB0aGUgcGVuYWx0eSBlbmQsIEkgdGhpbmsgdGhlcmUgbWF5IGJlIHNvbWUgc29ydCBvZiBzY2FsZWQgcGVuYWx0eSB3ZWlnaHQgSSBjYW4gY3JlYXRlLCB3aGVyZSBqdXN0IGEgbWludXRlIG9yIHR3byBvZiBwZW5hbHR5IHRpbWUgaXNuJ3QgdGVycmlibHkgcHVuaXNoaW5nLCBidXQgdGVuIHRvIGZpZnRlZW4gKG9yIGVqZWN0ZWQpIGhhcyBhIG11Y2ggbGFyZ2VyIGVmZmVjdC4gSXQncyBvbmUgb2YgdGhvc2UgdGhpbmdzIHRoYXQgaGF2aW5nIFRpbWUgb24gSWNlIChUT0kpIGRhdGEgZm9yIHdvdWxkIGJlIGEgaHVnZSBoZWxwLCBidXQgYmVnZ2FycyBjYW4ndCBiZSBjaG9vc2Vycy4gICAgICAgICAgICAgICAgICAgICAgICAgDQoNCkZvciBgc2hvdHNfYmxvY2tlZGAsIEkgYW0gaW50ZXJlc3RlZCBpbiBkb2luZyBzb21lIHJlc2VhcmNoIHRvIHNlZSBpZiBzaG90IG9uIGdvYWwgcmF0ZXMgc3Bpa2Ugc2hvcnRseSBhZnRlciBhIGJsb2NrZWQgc2hvdCwgbGlrZSBpZiB0aGUgcmljaG9jaGV0IHByb3ZpZGVzIG1vcmUgb2ZmZW5zaXZlIG9wcG9ydHVuaXRpZXMuIElmIHNvLCBpdCdzIHBvc3NpYmxlIHRoYXQgQSkgc2hvdHMgYmxvY2tlZCBzaG91bGQgaGF2ZSBhIFBPU0lUSVZFIHJhdGUgb3IgQikgdGhhdCB0aGV5IHNob3VsZCBhdCBsZWFzdCBiZSBsZXNzIGltcGFjdGZ1bC4gICAgICAgICAgICAgIA0KDQpGdXJ0aGVybW9yZSwgSSBob3BlIHRvIGJlIGFibGUgdG8gZXhwbG9yZSBzb21lIGRpZmZlcmVudCBtZXRob2RzIG9mIGRlcml2aW5nIEdhbWUgU2NvcmUgYW5kIGl0cyB3ZWlnaHRzLCBzcGVjaWZpY2FsbHkgYXMgdG8gd2hldGhlciBzb21lIHNvcnQgb2YgcmVncmVzc2lvbiBhcHByb2FjaCB0byBkZXJpdmluZyB3ZWlnaHRzLiBUaGVyZSBhcmUgYSBmZXcgaWRlYXMgcGVyY29sYXRpbmcgYW5kIGZsb2F0aW5nIGFyb3VuZCBpbiBteSBoZWFkIGFuZCB3ZSB3aWxsIGNlcnRhaW5seSBzZWUgd2hpY2ggb2YgdGhlbSBtYWtlIGl0IHRvIHBhcGVyLiAgICAgICAgICAgICAgIA0KDQpBbmQsIG9mIGNvdXJzZSwgYmVjYXVzZSB0aGlzIGlzIHRoZSBQSEYsIHdlIGFyZSBhdCB0aGUgbWVyY3kgb2YgdGhlIHNjb3Jla2VlcGVycyBmb3IgZWFjaCB0ZWFtIGFuZCBnYW1lIHRvIHByb3Blcmx5IHJlY29yZCB0aGUgZXZlbnRzIGZvciBlYWNoIGdhbWUuIEknbGwgYmUgdHJ5aW5nIHRvIGtlZXAgYW4gZXllIG9uIGlmIHRoZXJlIGFyZSBhbnkgc3BlY2lmaWMgZGlzY3JlcGFuY2llcyB0aGF0IGFyZSBjb25zaXN0ZW50IGFjcm9zcyBhIHNwZWNpZmljIGhvbWUgYXJlbmEsIGJ1dCB3ZSB3aWxsIG1ha2UgZG8uICAgICAgICAgICAgICAgDQoNCioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0KDQojIFdoYXQgQWJvdXQgR29hbGllcyAgICAgICAgICAgICAgICAgICAgICAgICAgICANCg0KV2VsbCwgZ29hbGllcyBhcmUgd2VpcmQuIEFuZCwgd2l0aCB0aGUgcXVhbGl0eS90eXBlIG9mIGRhdGEgd2UgaGF2ZSBhdmFpbGFibGUgZm9yIHRoZSBQSEYsIHRoZXJlJ3Mgbm90IGEgd2hvbGUgbG90IHRvIGRvLiBJJ20gbm90IGltcGxlbWVudGluZyBhIG5ldyBib3ggc2NvcmUgYXBwcm9hY2ggYmVjYXVzZSBJIHRoaW5rIE1pa2UncyBnb2FsaWUgZ2FtZSBzY29yZSAoYEdvYWxpZSBHYW1lIFNjb3JlID0gKC4xNSpTVikg4oCTIEdBYCkgaXMgYWxyZWFkeSBwcmV0dHkgZ29vZC4gUGVyc29uYWxseSwgSSBhbSB3b3JraW5nIG9uIGEgZmV3IG5ldyBpZGVhcyByZTogbWVhc3VyaW5nIGdvYWxpZXMsIGJ1dCB0aGV5J3JlIG5vdCBmaW5pc2hlZCB5ZXQsIHNvIHlvdSdsbCBoYXZlIHRvIHN0YXkgb24gdGhlIGVkZ2Ugb2YgeW91ciBzZWF0IHVudGlsIEkgZ2V0IHRoZXJlLiAgICAgICAgICAgICAgICAgICAgIA0K