I initially presented my NWHL Aging Curve work at the 2021 WHKYHAC conference, and below is a write-up of my analysis/results. You can view my presentation here.

If you’re just here to check out the 2022 NWHL Game Score Projections, scroll down to the bottom of this article to check them out! If you’re interested in the analysis and process, keep reading, and you’ll get there eventually!

Aging in sport is a complicated question, but one of the most important ones that we can try to answer or, at the very least, find patterns amongst players. Whether one is working for a team trying to determine who to acquire or a fantasy hockey player looking at who you want on your team next season, having an idea of how their performance may change is super important!

In the world of men’s sports, there has been plenty of work surrounding aging curves in most of the major men’s leagues (MLB, NBA, NHL). However, aging curves in women’s sports have remained relatively unexplored, though there have been two notable aging curves projects in women’s hockey, with Carleen Markey’s Canadian Women’s Hockey League (CWHL) project and Mike Murphy’s NCAA D1 project.

The question of aging and its role in projecting performance has interested me for a while, so I decided to work on a project focused on evaluating aging curves in the National Women’s Hockey League (NWHL) for the 2021 WHKYHAC Conference. Below is a write-up of my process and analysis, as well as some of the code I wrote.


Where Do We Start?

The first question that needs answering is simple: what metric are we going to use to evaluate players?

There are a few different options. Carlie’s CWHL project used Offensive Point Shares, while Mike’s used his revamped Game Score to evaluate NCAA skaters. Another option would be to use point totals (goals + assists), but I opted to follow Mike’s footsteps and use Game Score per Game (GS/G) to evaluate NWHL skaters.

Game Score essentially weights events on the ice by how frequently they occur relative to a goal being scored. You can (and definitely should) read the linked article for more on Game Score, but I’ve included the NWHL formula below.

\[Game Score = G + (.9*A1) + (.66*A2) + (.1*SOG) + (.11 * FOW) - (.11 * FOL) - (.15 * PENT)\]

There are a lot of reasons to use game score, notably that it is really really hard for a player to put up a high game score without playing time or actually being a good player. For most of this project, I will use GS/G relative to average (z-scores) to evaluate player performance, unless otherwise noted.

Next up: since this is women’s sports analytics, things are never easy, especially with an aging curve project that relies on players having multiple seasons of play strung together. Unfortunately, that’s not something we have the luxury of with the NWHL.

The league has only been around since 2015-2016, and the years since then have not necessarily been…smooth, to put it mildly. We see the effect of that turbulence when we look at how many consecutive seasons have been strung together by NWHL skaters.

Seasons Played # of Players
1 170
2 66
3 52
4 15
5 6
6 5

Of the 314 player seasons that we have (not including 2020-2021 for now), we see that nearly 55% of all players in the NWHL have only played one season in the league. And there are very very few players who played at least four years in the NWHL.

Furthermore, an additional complicating factor is that most of the games played in NWHL history have been played by players in the 22-26-year-old range. Players rarely play into their 30s due to a multitude of factors, most of which revolve around low salaries. That makes evaluating performance as a function of age kinda tough!

These are some things that we’ll need to keep in mind as we move forward with our aging curve analysis. But now that I’ve covered some of the complicating factors, it’s time to move forward with the analysis.


Delta Method

There are a few ways to go about measuring the effect of aging on GS/G.

The first is the simplest and perhaps the most intuitive: the delta method, which Carlie and Mike used in their projects.

The delta method pairs back-to-back seasons for a player and looks at their change in performance from age to age (here, I used true GS/G to evaluate the changes, rather than the aforementioned z-scores). Once enough seasons were paired, I averaged the change in performance for each age bucket (i.e. 21-22, 24-25, 30-31, etc). String them all together, and we have the average change by age, as illustrated below!

The age buckets from about 23-28 are the groups where players tend to consistently maintain performance (or, in some cases, increase it). While there are age buckets at 30+ that show increases in performances, the dark red dots indicate how few games played in those age buckets.

This is not an ideal method of analysis for the NWHL given the limited dataset, but I wanted to touch on the delta method to build on previous women’s hockey aging analyses.


One-and-Done Players vs Survivors

The main weakness of the delta method is that you end up throwing out players who only played one season in their career, as well as the last season of a player’s career since they don’t have an additional season to pair with.

Presumably, there’s a difference between the players who only play for one season before failing to return to the NWHL and the players who receive another shot in the league. Since the delta method doesn’t account for players who fail to “survive”, I wanted to directly compare one-and-done and surviving players to see if that difference played out.

Turns out there is a difference!

Type of Player Seasons Total GP Avg GP Game Score vs Avg
Survivors 144 2051 14.2 0.256
One-and-done 124 1361 11.0 -0.281

Players who make it to a second NWHL season played more as a rookie AND played better than average. Since the one-and-done players aren’t included in the delta method, the method likely overrates the quality of player in the league.

This also shows how important it is for a rookie to produce immediately in the NWHL. Unfortunately, teams don’t necessarily have the money or the time to let young players develop, so the only players who make it to year two are the strong performers.

(I think it’s worth noting that if an NWHL rookie doesn’t get to play, they may be more likely to jump back to a different league, potentially one closer to their home country if they hail from outside North America. While I think this is interesting, I won’t be digging any deeper as that is not the focus of this project. Back to the aging curve analysis!)

The graph above looks at GS/G relative to average in a player’s rookie year, broken down by age. At nearly every single instance, survivors played better than one-and-done players; the few instances where they didn’t are more a result of outliers and the sparse NWHL dataset than a concrete trend.


Regression Methods

Moving on from the delta method, I applied two modeling and regression techniques to visualize the aging curve difference.

I started with a simple linear regression that looks at the relationship between age and game score. It’s a model that performs well by certain metrics, notably with a 0.581 R-squared, while age has a coefficient of -0.06, indicating that every year increase in age should correspond with a slight drop in GS/G relative to average. However, the straight decline in GS/G isn’t much of a curve and doesn’t make too much sense (though the premise of young players > older players is a simple and defensible one).

lr <- lm(game_score_game ~ age_in_season, data = nwhl)

The second method that I tested out uses a Generalized Additive Model (GAM), which produces a curved instance of GS/G relative to age. The GAM produces a curve that starts slightly below average in a player’s early 20s before peaking around 24-26 years of age. After that peak, performance decreases as a player ages, an effect that becomes more pronounced the older a player is.

gam_model <- gam(game_score_game ~ I(age_in_season ^ 2) + age_in_season, 
                 data = nwhl, weights = gp)

If you look closely at the formulas above, you may notice that the linear model does not contain a squared age term while the GAM does. It is possible to run a linear model with the same squared term, however running the linear model with a squared term will produce a curve that is symmetric on both sides, while the GAM does not have that issue. As you see on the graph below, the curve is not symmetric on each side, as the old-age decline is sharper than the young-age increase.

The last line on the graph (in the blue) is a smoothed plot of the weighted average of GS/G (relative to average) at each age.

The modeled curve contradicts some of the findings from Carlie and Mike’s projects found, which indicated that the performance of women’s hockey players tended to peak early in their career, around ages 21-22. With Mike’s NCAA D1 project, that makes sense given that most players tend to age out of college by age 22.

Carlie’s findings were a little more interesting since the CWHL dataset that she used contained players of all ages from 15 to 42. However, as with the NWHL, player movement out of the CWHL was augmented by players sometimes leaving the league before the point where their performance dictated it due to the lower salaries, etc. While the above curve is different from the CWHL aging patterns, the NWHL curve is much more reminiscent of the typical sports aging curve.

Now, while that is reassuring in one sense, it’s important to remember that women’s sports and hockey are different from their male counterparts. The goal here is not to produce an aging pattern that mimics the NHL patterns but to produce an accurate representation of aging in the NWHL.

Despite the complications facing NWHL aging analysis, I believe I’ve accomplished that, or at least taken a step forward towards understanding how NWHL skaters age.


MARCEL Projections

I had planned to wrap my project up after exploring the linear and GAM regression approaches. However, I couldn’t resist applying the aging curves in a concrete fashion.

Enter NWHL MARCEL Projections for the 2021-2022 season.

MARCEL projections were first introduced in 2004 by Tom Tango to provide a straightforward way to project future MLB production and have begun to trickle in hockey (that link is super helpful).

MARCEL projections are straightforward and relatively simple. They essentially weigh a player’s past performance by their most recent seasons, regress their performance to league average (based on playing time), and, finally, apply an aging adjustment.

The first step is to determine what the relationship is between a player’s performance and their performance in their last 1, 2, and 3 seasons. Looking at those correlations provides us with the weights we use for those seasons.

However, we don’t have the NWHL data to produce those weights due to the overall lack of consecutive data. However, the aforementioned CWHL data that Carlie used IS available. While it’s not ideal to use one league to determine weights for a different league, the CWHL and NWHL had quite an overlap in their player pools and similar talent levels. Given the overall constraints, it is what it is.

But there’s a problem!

We don’t have Game Score for the CWHL, so how do we evaluate the relationship between Year N-1, N-2, and N-3 Game Score and current Game Score? Fortunately, there’s a strong relationship between goals, assists, and GS in the NWHL, so I decided to model CWHL game score using that NWHL relationship.

Running a simple linear model with GS as a function of goals and assists returns a stellar adjusted R-squared of 0.965. I then took a random sample of 578 CWHL game score seasons (to match the NWHL total) and compared their distributions to see if things made sense.

The above graph indicates that the distribution of my modeled CWHL game score makes sense. Unsurprisingly, the CWHL Game Scores are more concentrated around average and don’t predict as many scores in the 0.75-1.5 range (tbh, there’s that bump at ~ 2 GS/G, and I have no clue why, but I don’t think it’s a problem). Now that I’ve determined that my modeled CWHL Game Score is not too outlandish, I can move forward with the MARCEL work.

Effect N-1 GS N-2 GS N-3 GS Total
Game Score Per Game 0.62 0.29 0.2 1.12

A player’s most recent season plays the biggest part in predicting their future performance. And performance in seasons N-2 and N-3 matter in decreasing order. So, how does one turn this into a MARCEL projection?

Let’s take McKenna Brand of the Boston Pride as an example. Below are her stats from her last three seasons, as well as how many games she played in each season (just a reminder that I scaled up her 2020-2021 from 7 games to 24 games and that’s her N-1 season).

Season N-1
Season N-2
Season N-3
Player Age In Next Season MARCEL N-1 GS/G N-1 GP N-2 GS/G N-2 GP N-3 GS/G N-3 GP
McKenna Brand 25 1.39 1.19 24 1.9 24 1.25 16

Here’s how I derived an initial MARCEL projection with the given weights:

\[ MARCEL = ((1.19 * 0.62) + (1.9 * 0.29) + (1.25 * 0.2)) / 1.11 \]

The formula produces a projected game score of 1.39, partway between Brand’s GS/G in 2020-2021 and 2019-2020. Passes the smell test! But there’s still more we can do to further this projection.

Step 2 (or technically like step 6 at this point if we’re being honest, but is anyone really counting?) is to regress projected performance to average GS/G to ensure that we don’t overrate outlier seasons. To do that, I assume the projected 1.39 GS/G comes over 24 games and then add about 3 (actually 2.94) games worth of league average play (a 0.59 GS/G). We determine the average games to add by comparing the true average GS/G, and the initial predicted GS/G (since that has no regression to the mean yet), and how they relate to the average games played.

In the equation below, 17.32 is the average games played, while 0.855 comes from a comparison of actual and predicted GS/G. While the true average GS/G in 2021 was 0.59, the average predicted GS/G is 0.69 (or 85.5% of that predicted performance).

\[ Games = avgGP * ((1 - difference) / difference) \] \[ Games = 17.32 * ((1 - 0.855) / 0.855) \]

Solve that, and it comes out to 2.94 games of average production to add. The formula below represents adding in the games of average production, resulting in a regressed projection of 1.30 for McKenna Brand.

\[ Regressed = ((1.39 * 24) + (2.94 * 0.59)) / (24 + 2.94) \]

Last but not least, we add in a simple aging effect. Taking the GAM curve that I produced earlier, I paired back-to-back ages together to figure out what the effect of increasing age had on GS/G. For example, since McKenna Brand is going from 24 to 25 years old, we’d expect her GS/G to increase by 0.015 (small differences, but hey, it is what it is).

All told, McKenna Brand’s final projected GS/G comes out to 1.31, the third-highest mark behind Mikyla Grant-Mentis and Brand’s teammate, Jillian Dempsey.

Brand made a good example here because she’s played three seasons in a row in the NWHL. But not every player has played that many seasons. For players with two years of NWHL play (think Mikyla Grant-Mentis), the system takes just her two seasons into consideration, weighting by the same weights as earlier (N-1 as 0.62 and N-2 as 0.29, all over 0.91).

For players with just one season, I add a “second” season to their line. The fake season is their year of play heavily regressed to average with a negative factor applied based on their season of play. The negative factor is intended to keep the system from overrating players whose single season was poor in just a couple of games (when regressing to average, it would pull those seasons too close to average).

The names that populate the top of the board are the ones that we’d expect. The reigning MVP, Mikyla Grant-Mentis, tops the projections with her game score of 1.91 (though, to be honest, I bet she outperforms that). Stalwart superstar Jillian Dempsey comes in second place at 1.65, then McKenna Brand, followed by their Boston Pride teammate Christina Putigna and her 1.29 prediction.

However, the system isn’t buying strong seasons from a few players, notably Nina Rogers, Emma Woods, and Brooke Boquist, though I’d probably disagree with the system on them. They are all in that 24-26 sweet spot and (for Woods and Boquist) have 1 season played, resulting in their “fake second season” that is heavily regressed to league average. Given that they produce so well in their rookie season and are in their prime, I’d bet on their performance maintaining its 2021 level or even improving.

The model does penalize players like Alyssa Wohlfeiler (entering her age-32 season), projecting her for a -0.20 decrease in Game Score/Game, the eighth-largest drop in the league. On the flip side, Allie Thunstrom (entering her age-33 season) is expected to rebound from a tough 0.09 GS/G in 2021 and return to being an above-average skater.

A lot is going on in these projections and I would recommend checking them out in the table below and seeing what sticks out to you!

Aging in sport, especially women’s sports, is a hard problem to attack despite the analysis that understanding aging facilitates. Hopefully, through my presentation and writeup, I’ve helped provide a framework to view aging using the delta and regression methods, building on previously completed work in the women’s hockey sphere.


2022 NWHL Projected Game Scores


LS0tDQp0aXRsZTogIkFnaW5nIEN1cnZlcyBpbiB0aGUgTldITCINCmF1dGhvcjogIkJlbiBIb3dlbGwiDQpkYXRlOiAiNy8xMi8yMDIxIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGhpZ2hsaWdodGVyOiBudWxsDQogICAgdGhlbWU6ICJmbGF0bHkiDQogICAgY29kZV9kb3dubG9hZDogVFJVRQ0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBGQUxTRSwgaW5jbHVkZSA9IEZBTFNFLCBmaWcuYWxpZ24gPSAiY2VudGVyIiwNCiAgICAgICAgICAgICAgICAgICAgICBmaWcud2lkdGggPSA3LCBmaWcuaGVpZ2h0ID0gNSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UpDQpgYGANCiAgICAgICANCioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0KICAgICAgICAgICANCmBgYHtyfQ0KbGlicmFyeShwYWNtYW4pDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShrYWJsZUV4dHJhKQ0KbGlicmFyeShyZWFjdGFibGUpDQoNCnBhY21hbjo6cF9sb2FkKHRpZHl2ZXJzZSwgZ2d0aGVtZXMsDQogICAgICAgICAgICAgICBtZ2N2LCByYWRpYW50LmRhdGEsIGRvRnV0dXJlLCBmdXR1cmUuYXBwbHksIGphbml0b3IpDQojbG9hZCBpbiBsaWJyYXJpZXMgdGhhdCB3ZSdsbCB1c2UgZm9yIHRoaXMgYW5hbHlzaXMNCmBgYA0KDQpgYGB7cn0NCmRmIDwtIHJlYWQuY3N2KCJzdXJ2aXZlLmNzdiIpDQoNCiN3ZSdyZSBsb2FkaW5nIGluIHRoZSBOV0hMIGRhdGEgZnJvbSBUaGVpckhvY2tleUNvdW50cyBoZXJlDQpud2hsIDwtIHJlYWQuY3N2KCJud2hsX2RhdGEuY3N2IikgJT4lDQogIG11dGF0ZShMZWFndWUgPSAiTldITCIpICU+JQ0KICBjbGVhbl9uYW1lcygpICU+JQ0KICAjdGhpcyBpcyBqdXN0IHdoZXJlIEkgYWRkIG9uIGFsbCB0aGUgbmVjZXNzYXJ5IGNvbHVtbnMgdG8gbWFrZSBpdCBwb3NzaWJsZSB0byBiaW5kDQogICN0aGUgTldITCBkYXRhIHdpdGggdGhlIENXSEwgZGF0YQ0KICAjYW4gaW5pdGlhbCB2ZXJzaW9uIG9mIHRoZSBwcm9qZWN0IGxvb2tlZCBhdCBib3RoIGxlYWd1ZXMsIGJ1dCBJIGRpZG4ndCBlbmQgdXAgZG9pbmcgc28NCiAgbXV0YXRlKHBvcyA9IHAsIHNoX28gPSBOQSwgdyA9IE5BLCBsID0gTkEsIGdhID0gTkEsIGdhYSA9IE5BLCANCiAgICAgICAgIGVuYSA9IE5BLCBzYSA9IE5BLCBzcCA9IE5BLCBtaW4gPSBOQSwgc2hnID0gTkEsIGd3ZyA9IE5BLCBhID0gYTEgKyBhMiwgDQogICAgICAgICBwdHMgPSBhICsgZywgcHBnID0gcHRzIC8gZ3AsIHNlYyA9IE5BLCB0ID0gTkEsIHNlYXNvbl90eXBlID0gTkEsIA0KICAgICAgICAgcGxheWVyX2lkID0gTkEsIHBtID0gTkEpICU+JQ0KICBkcGx5cjo6c2VsZWN0KC1wKSAlPiUNCiAgbXV0YXRlKHRtZ21zID0gaWZlbHNlKHRlYW0gPT0gIkJPUyIsIDcsIA0KICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHRlYW0gPT0gIkJVRiIsIDYsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UodGVhbSA9PSAiQ1RXIiwgNCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UodGVhbSA9PSAiTUVUIiwgMywgaWZlbHNlKHRlYW0gPT0gIk1JTiIsIDQsIDYpKSkpKSwNCiAgICBncCA9IGlmZWxzZShzdGFydF95ZWFyICVpbiUgYygyMDIwKSwgcm91bmQoKGdwIC8gdG1nbXMpICogMjQpLCBncCkpDQogICNhZGRpbmcgaW4gdGhlIGFkanVzdGVkIGdhbWVzIGZvciB0aGUgMjAyMSBzZWFzb24NCiAgI3NpbmNlIDIwMjEgd2FzIHZlcnkgc2hvcnQsIHdlIHdhbnQgdG8gc2NhbGUgdXAgdG8gYSBmdWxsIHNlYXNvbnMgd29ydGggb2YgZ2FtZXMgDQogICNqdXN0IHNvIHRoYXQgd2UgZG9uJ3QgZ2V0IGFueSB3ZWlyZCB3ZWlnaHRpbmcgaW4gb3VyIHdlaWdodGVkIGF2ZXJhZ2VzDQoNCiMgQ1dITCBkYXRhIGxvYWQgaW4NCmN3aGxfYWxsIDwtIHJlYWQuY3N2KCJjd2hsX2RhdGEuY3N2IikgJT4lDQogIG11dGF0ZShMZWFndWUgPSAiQ1dITCIpDQoNCmN3aGwgPC0gY3dobF9hbGwgJT4lDQogIGNsZWFuX25hbWVzKCkgJT4lDQogIGRwbHlyOjpzZWxlY3QoLWModG91cm5hbWVudF9pZCwgdGVhbV9hd2FyZCwgcm9va2llKSkgJT4lDQogIHNlcGFyYXRlKHNlYXNvbiwgaW50byA9IGMoInN0YXJ0X3llYXIiLCAiZW5kX3llYXIiKSwgc2VwID0gIi0iLCByZW1vdmUgPSBGQUxTRSkgJT4lDQogIGZpbHRlcihzZWFzb25fdHlwZSA9PSAiUmVndWxhciBTZWFzb24iKSAlPiUNCiAgI29idmlvdXNseSB3ZSBqdXN0IHdhbnQgcmVndWxhciBzZWFzb24gZ2FtZXMNCiAgbXV0YXRlKHRlYW0gPSB0ZWFtX2lkLA0KICAgICAgICAgcGxheWVyID0gcGxheWVyX2lkLCBkb2IgPSBOQSwgDQogICAgICAgICBhZ2VfaW5fc2Vhc29uID0gYWdlLA0KICAgICAgICAgYTEgPSBOQSwgYTIgPSBOQSwgc29nID0gTkEsIGZvdyA9IE5BLCBmb2wgPSBOQSwgcGVuX3QgPSBOQSkgJT4lDQogIGRwbHlyOjpzZWxlY3QoLWModGVhbV9pZCwgYWdlKSkNCmBgYA0KDQpgYGB7cn0NCiNtb2RlbGluZyBDV0hMIGdhbWUgc2NvcmUgZm9yIHdlaWdodHMgdG8gYmUgdXNlZCBpbiBldmVudHVhbCBNQVJDRUwgcHJvamVjdGlvbnMNCnNldC5zZWVkKDExMSkNCiNnb25uYSBtb2RlbCBnYW1lIHNjb3JlIHBlciBnYW1lIGFzIGEgZnVuY3Rpb24gb2YgZ29hbHMgYW5kIGFzc2lzdHMNCmdzX21vZCA8LSBsbShnYW1lX3Njb3JlIH4gZyArIGEsIGRhdGEgPSBud2hsKQ0KI3Zlcnkgc3Ryb25nIHBlcmZvcm1hbmNlIGluIG1vZGVsaW5nIG92ZXJhbGwgZ2FtZSBzY29yZSBvZmYgdG90YWwgZ29hbHMvYXNzaXN0cw0Kc3VtbWFyeShnc19tb2QpDQojci1zcXVhcmVkIG9mIDAuOTY1MiBpcyBleGNlbGxlbnQNCmBgYA0KDQpgYGB7ciwgaW5jbHVkZT1UUlVFfQ0KY3dobCRnYW1lX3Njb3JlIDwtIHByZWRpY3QoZ3NfbW9kLCBuZXdkYXRhID0gY3dobCkNCg0KY3dobCA8LSBjd2hsICU+JQ0KICBtdXRhdGUoZ2FtZV9zY29yZV9nYW1lID0gZ2FtZV9zY29yZSAvIGdwKSAlPiUNCiAgZHBseXI6OnNlbGVjdChwbGF5ZXIsIGFnZV9pbl9zZWFzb24sIGxlYWd1ZSwgdGVhbSwgc2Vhc29uLCBzdGFydF95ZWFyLCBlbmRfeWVhciwgDQogICAgICAgICAgICAgICAgZ3AsIGcsIGEsIGdhbWVfc2NvcmUsIGdhbWVfc2NvcmVfZ2FtZSkNCg0KbndobCA8LSBud2hsICU+JQ0KICBkcGx5cjo6c2VsZWN0KHBsYXllciwgYWdlX2luX3NlYXNvbiwgbGVhZ3VlLCB0ZWFtLCBzZWFzb24sIHN0YXJ0X3llYXIsIGVuZF95ZWFyLCANCiAgICAgICAgICAgICAgICBncCwgZywgYSwgZ2FtZV9zY29yZSwgZ2FtZV9zY29yZV9nYW1lKQ0KDQpnc19ncmFwaCA8LSBjd2hsICU+JQ0KICBmaWx0ZXIoZ2FtZV9zY29yZV9nYW1lIDwgMy41KSAlPiUNCiAgc2xpY2Vfc2FtcGxlKG4gPSA1NzgpICU+JQ0KICByYmluZChud2hsKSAlPiUNCiAgZ2dwbG90KCkgKw0KICBnZW9tX2RlbnNpdHkoYWVzKHggPSBnYW1lX3Njb3JlX2dhbWUsIGZpbGwgPSBsZWFndWUpLCBhbHBoYSA9IDAuNikgKw0KICBsYWJzKHRpdGxlID0gIkNvbXBhcmluZyBEaXN0cmlidXRpb25zIG9mIEdhbWUgU2NvcmUgYnkgTGVhZ3VlIiwgIA0KICAgICAgIGNhcHRpb24gPSAiQGJlbmhvd2VsbDcxIG9uIFR3aXR0ZXIgfCBiZW5ob3dlbGw3MS5jb20iLCBmaWxsID0gIkxlYWd1ZSIsDQogICAgICAgeCA9ICJHYW1lIFNjb3JlIFBlciBHYW1lIiwNCiAgICAgICB5ID0gIkZyZXF1ZW5jeSIpICsNCiAgI2dlb21fdmxpbmUoeGludGVyY2VwdCA9IHdlaWdodGVkLm1lYW4oeCA9IGdhbWVfc2NvcmVfZ2FtZSwgdyA9IGdwKSkgKw0KICBzY2FsZV9maWxsX2NvbG9yYmxpbmQoKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxNiwgZmFjZSA9ICJib2xkIiksDQogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJpdGFsaWMiKSwNCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwNCiAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgxLjUsICdsaW5lcycpKQ0KYGBgDQoNCmBgYHtyfQ0KIyBkZXRlcm1pbmluZyB3ZWlnaHRzIGZvciBlYWNoIHNlYXNvbiBvZiBwbGF5DQp0aHJlZV95ZWFyIDwtIGN3aGwgJT4lDQogIGdyb3VwX2J5KHBsYXllcikgJT4lDQogIGFycmFuZ2UocGxheWVyLCBzZWFzb24pICU+JQ0KICBtdXRhdGUoeXJzID0gbigpLA0KICAgICAgICAgbjFfeWVhciA9IGxhZyhzdGFydF95ZWFyLCAxKSwNCiAgICAgICAgIG4xX2dtc2NvcmUgPSBsYWcoZ2FtZV9zY29yZV9nYW1lLCAxKSwNCiAgICAgICAgIG4xX2dwID0gbGFnKGdwLCAxKSwNCiAgICAgICAgIG4yX3llYXIgPSBsYWcoc3RhcnRfeWVhciwgMiksDQogICAgICAgICBuMl9nbXNjb3JlID0gbGFnKGdhbWVfc2NvcmVfZ2FtZSwgMiksDQogICAgICAgICBuMl9ncCA9IGxhZyhncCwgMiksDQogICAgICAgICBuM195ZWFyID0gbGFnKHN0YXJ0X3llYXIsIDMpLA0KICAgICAgICAgbjNfZ21zY29yZSA9IGxhZyhnYW1lX3Njb3JlX2dhbWUsIDMpLA0KICAgICAgICAgbjNfZ3AgPSBsYWcoZ3AsIDMpKQ0KDQp3ZWlnaHRzIDwtIHRocmVlX3llYXIgJT4lIA0KICBmaWx0ZXJfYXQodmFycyhnYW1lX3Njb3JlX2dhbWUsIG4xX2dtc2NvcmUsIG4yX2dtc2NvcmUsIG4zX2dtc2NvcmUpLCBhbGxfdmFycyghaXMuaW5maW5pdGUoLikpKSAlPiUNCiAgZmlsdGVyKCEgaXMubmEobjNfZ21zY29yZSkgJiAhIGlzLm5hKGdhbWVfc2NvcmVfZ2FtZSkgJiAhIGlzLm5hKG4yX2dtc2NvcmUpICYgISBpcy5uYShuMV9nbXNjb3JlKSkgJT4lDQogIGRwbHlyOjpzZWxlY3QocGxheWVyLCBhZ2VfaW5fc2Vhc29uLCBzdGFydF95ZWFyLCBncCwgZywgYSwgZ2FtZV9zY29yZTpuM19ncCkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgZHBseXI6OnNlbGVjdChuMV9nbXNjb3JlLCBuMl9nbXNjb3JlLCBuM19nbXNjb3JlLCBnYW1lX3Njb3JlX2dhbWUpICU+JQ0KICBjb3IoKSAlPiUgDQogIGFzLmRhdGEuZnJhbWUoKSAlPiUNCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJlZmZlY3QiKSAlPiUNCiAgZmlsdGVyKGVmZmVjdCA9PSAiZ2FtZV9zY29yZV9nYW1lIikgJT4lDQogIG11dGF0ZShvdmVyYWxsID0gbjFfZ21zY29yZSArIG4yX2dtc2NvcmUgKyBuM19nbXNjb3JlKQ0KDQp5MSA8LSB3ZWlnaHRzJG4xX2dtc2NvcmUNCnkyIDwtIHdlaWdodHMkbjJfZ21zY29yZQ0KeTMgPC0gd2VpZ2h0cyRuM19nbXNjb3JlDQpvdnIgPC0gd2VpZ2h0cyRvdmVyYWxsDQpgYGANCg0KYGBge3J9DQojIGF2ZyBHUy9HIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24gc28gd2UgY2FuIGNvbnZlcnQgdG8gei1zY29yZXMNCm1uMyA8LSBud2hsICU+JQ0KICBzdW1tYXJpc2UobWVhbl9nbXNjb3JlID0gd2VpZ2h0ZWQubWVhbihnYW1lX3Njb3JlX2dhbWUsIGdwLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgc2RfZ21zY29yZSA9IHdlaWdodGVkLnNkKGdhbWVfc2NvcmVfZ2FtZSwgZ3AsIG5hLnJtID0gVFJVRSkpDQoNCmF2Z19nbXNjb3JlIDwtIHJvdW5kKG1uMyRtZWFuX2dtc2NvcmUsIGRpZ2l0cyA9IDMpDQpzZF9nbXNjb3JlIDwtIHJvdW5kKG1uMyRzZF9nbXNjb3JlLCBkaWdpdHMgPSAzKQ0KI2F2ZXJhZ2UgbndobCBnYW1lIHNjb3JlIHBlciBnYW1lIGlzIGFib3V0IDAuNjM0DQoNCm53aGwgPC0gbndobCAlPiUNCiAgbXV0YXRlKGdtc2NvcmVfeiA9ICgoZ2FtZV9zY29yZV9nYW1lIC0gYXZnX2dtc2NvcmUpIC8gKHNkX2dtc2NvcmUpKSkNCiNsb29raW5nIGF0IGF2ZXJhZ2UgZ2FtZSBzY29yZSBhbmQgZ2FtZSBzY29yZSByZWxhdGl2ZSB0byBhdmVyYWdlIGF0IGVhY2ggYWdlDQpkYXRhIDwtIG53aGwgJT4lIA0KICBmaWx0ZXIoISBpcy5uYShhZ2VfaW5fc2Vhc29uKSAmICEgaXMubmEoZ2FtZV9zY29yZV9nYW1lKSkgJT4lDQogIGdyb3VwX2J5KGFnZV9pbl9zZWFzb24pICU+JQ0KICBzdW1tYXJpc2Uoc2Vhc29ucyA9IG4oKSwNCiAgICAgICAgICAgIGdtX3Njb3JlX2dhbWUgPSB3ZWlnaHRlZC5tZWFuKGdhbWVfc2NvcmVfZ2FtZSwgZ3AsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICB6X3Njb3JlID0gd2VpZ2h0ZWQubWVhbihnbXNjb3JlX3osIGdwLCBuYS5ybSA9IFRSVUUpKQ0KYGBgDQoNCmBgYHtyfQ0KI1NpbXBsZSBMaW5lYXIgTW9kZWwNCmdzX2xtIDwtIGxtKHpfc2NvcmUgfiBhZ2VfaW5fc2Vhc29uLCBkYXRhID0gZGF0YSkNCnN1bW1hcnkoZ3NfbG0pDQoNCiNHQU0gTW9kZWwNCiN3ZWlnaHRlZCBieSBnYW1lcyBwbGF5ZWQgaW4gYSBzZWFzb24gdG8gYWNjb3VudCBmb3IgcGxheWVycyB3aG8gcGxheWVkIGEgbG90DQpnc19nYW0gPC0gZ2FtKGdtc2NvcmVfeiB+IEkoYWdlX2luX3NlYXNvbiBeIDIpICsgYWdlX2luX3NlYXNvbiwgZGF0YSA9IG53aGwsIHdlaWdodHMgPSBncCkNCnN1bW1hcnkoZ3NfZ2FtKQ0KDQojYWRkaW5nIHByZWRpY3Rpb25zDQpkYXRhJGdzX2xtIDwtIHByZWRpY3QoZ3NfbG0sIG5ld2RhdGEgPSBkYXRhKQ0KZGF0YSRnc19nYW0gPC0gcHJlZGljdChnc19nYW0sIG5ld2RhdGEgPSBkYXRhKQ0KYGBgDQoNCmBgYHtyLCBpbmNsdWRlPVRSVUV9DQpuIDwtIG53aGwgJT4lDQogIGdyb3VwX2J5KGFnZV9pbl9zZWFzb24pICU+JQ0KICBzdW1tYXJpc2UoU2Vhc29ucyA9IG4oKSkNCg0Kc2Vhc29ucyA8LSBud2hsICU+JQ0KICBnZ3Bsb3QoKSArDQogIGdlb21fYmFyKGFlcyh4ID0gYWdlX2luX3NlYXNvbiksIGNvbG9yID0gImJsYWNrIiwgZmlsbCA9ICJibGFjayIpICsNCiAgZ2VvbV9zbW9vdGgoZGF0YSA9IG4sIGFlcyh4ID0gYWdlX2luX3NlYXNvbiwgeSA9IFNlYXNvbnMpLCBjb2xvciA9ICJmb3Jlc3RncmVlbiIsIA0KICAgICAgICAgICAgICBsZXZlbCA9IDAuMSwgc2l6ZSA9IDIpICsNCiAgbGFicyh0aXRsZSA9ICJHYW1lcyBQbGF5ZWQgQWdlIGluIHRoZSBOV0hMIiwNCiAgICAgICB5ID0gIlNlYXNvbnMgUGxheWVkIiwgeCA9ICJBZ2UgaW4gU2Vhc29uIiwgIA0KICAgICAgIGNhcHRpb24gPSAiQGJlbmhvd2VsbDcxIG9uIFR3aXR0ZXIgfCBiZW5ob3dlbGw3MS5jb20iKSArIA0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLCBzaXplID0gMTYpLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiaXRhbGljIiksDQogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksDQogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMS41LCAnbGluZXMnKSkNCmBgYA0KDQpgYGB7ciwgaW5jbHVkZT1UUlVFfQ0KcmVncmVncyA8LSBkYXRhICU+JQ0KICBnZ3Bsb3QoKSArDQogIHNjYWxlX2NvbG9yX2NvbG9yYmxpbmQoKSArDQogIGdlb21fc21vb3RoKGFlcyh4ID0gYWdlX2luX3NlYXNvbiwgeSA9IHpfc2NvcmUsIGNvbG9yID0gIldlaWdodGVkIEdTL0ciKSwgbGV2ZWwgPSAwLjQwLA0KICAgICAgICAgICAgICBzaXplID0gMikgKw0KICBnZW9tX3Ntb290aChhZXMoeCA9IGFnZV9pbl9zZWFzb24sIHkgPSBnc19nYW0sIGNvbG9yID0gIkdBTSBDdXJ2ZSIpLCBsZXZlbCA9IDAuNCwNCiAgICAgICAgICAgICAgc2l6ZSA9IDIpICsNCiAgZ2VvbV9zbW9vdGgoYWVzKHggPSBhZ2VfaW5fc2Vhc29uLCB5ID0gZ3NfbG0sIGNvbG9yID0gIkxNIEN1cnZlIiksIGxldmVsID0gMC40LA0KICAgICAgICAgICAgICBzaXplID0gMikgKw0KICBsYWJzKHRpdGxlID0gIlZpc3VhbGl6aW5nIE5XSEwgR2FtZSBTY29yZSBBZ2luZyBDdXJ2ZXMiLA0KICAgICAgIHggPSAiQWdlIiwgeSA9ICJHYW1lIFNjb3JlIFJlbGF0aXZlIHRvIEF2ZXJhZ2UiLA0KICAgICAgIHN1YnRpdGxlID0gIlBsYXllcnMgbG9vayB0byBwZWFrIGFyb3VuZCAyNC0yNiB5ZWFycyBvZiBhZ2UiLCAgDQogICAgICAgY2FwdGlvbiA9ICJAYmVuaG93ZWxsNzEgb24gVHdpdHRlciB8IGJlbmhvd2VsbDcxLmNvbSIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTUsIGZhY2UgPSAiYm9sZCIpLA0KICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTIsIGZhY2UgPSAiaXRhbGljIiksDQogICAgICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJpdGFsaWMiKSwNCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwNCiAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgxLjUsICdsaW5lcycpKQ0KYGBgDQoNCmBgYHtyfQ0Kc3VyIDwtIGRmICU+JQ0KICBrbml0cjo6a2FibGUoY29sLm5hbWVzID0gYygiVHlwZSBvZiBQbGF5ZXIiLCAiU2Vhc29ucyIsICJUb3RhbCBHUCIsICJBdmcgR1AiLCAiR2FtZSBTY29yZSB2cyBBdmciKSwgDQogICAgICAgICAgICAgICBhbGlnbiA9ICJjY2NjYyIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGQUxTRSwgYygic3RyaXBlZCIsICJob3ZlciIpKQ0KYGBgDQoNCmBgYHtyLCBpbmNsdWRlPVRSVUV9DQpud2hsZGYgPC0gbndobCAlPiUNCiAgZHBseXI6OnNlbGVjdChwbGF5ZXI6Z2FtZV9zY29yZV9nYW1lLCBnbXNjb3JlX3opICU+JQ0KICBncm91cF9ieShwbGF5ZXIpICU+JQ0KICBhcnJhbmdlKHBsYXllciwgc3RhcnRfeWVhcikgJT4lDQogIG11dGF0ZShzZWFzb25zID0gbigpLA0KICAgICAgICAgc2Vhc29uX29yZGVyID0gcm93X251bWJlcigpLA0KICAgICAgICAgdHlwZSA9IGlmZWxzZShzZWFzb25zID09IDEsICJPbmUtWWVhciIsICJTdXJ2aXZvcnMiKSkgDQoNCnN1cnZpdmUgPC0gbndobGRmICU+JQ0KICBmaWx0ZXIoc2Vhc29uX29yZGVyID09IDEgJiBzdGFydF95ZWFyICE9IDIwMjApICU+JQ0KICBncm91cF9ieSh0eXBlLCBhZ2VfaW5fc2Vhc29uKSAlPiUNCiAgc3VtbWFyaXNlKHNlYXNvbnMgPSBuKCksDQogICAgICAgICAgICBncF90b3QgPSBzdW0oZ3AsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICB6Z3MgPSByb3VuZCh3ZWlnaHRlZC5tZWFuKGdtc2NvcmVfeiwgZ3AsIG5hLnJtID0gVFJVRSksIGRpZ2l0cyA9IDMpKSAlPiUNCiAgbXV0YXRlKGF2Z19ncCA9IHJvdW5kKGdwX3RvdCAvIHNlYXNvbnMsIGRpZ2l0cyA9IDEpKSAlPiUNCiAgZmlsdGVyKCEgaXMubmEoYWdlX2luX3NlYXNvbikpICU+JQ0KICBnZ3Bsb3QoKSArDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gInNreWJsdWUyIiwgc2l6ZSA9IDEuNSkgKw0KICBnZW9tX3Ntb290aChhZXMoeCA9IGFnZV9pbl9zZWFzb24sIHkgPSB6Z3MsIGNvbG9yID0gdHlwZSksIHNpemUgPSAyLCBsZXZlbCA9IDAuNCkgKw0KICBnZW9tX3BvaW50KGFlcyh4ID0gYWdlX2luX3NlYXNvbiwgeSA9IHpncywgY29sb3IgPSB0eXBlKSwgc2l6ZSA9IDMpICsNCiAgI2dlb21fbGluZShhZXMoeCA9IGFnZV9pbl9zZWFzb24sIHkgPSB6Z3MsIGNvbG9yID0gdHlwZSksIHNpemUgPSAxKSArDQogIGxhYnMoY29sb3IgPSAiUGxheWVyIFR5cGUiLCB4ID0gIkFnZSBJbiBGaXJzdCBTZWFzb24iLCB5ID0gIkdhbWUgU2NvcmUgdnMgQXZlcmFnZSIsDQogICAgICAgdGl0bGUgPSAiQ29tcGFyaW5nIEdhbWUgU2NvcmUgaW4gUm9va2llIFNlYXNvblxuRm9yIE9uZS1hbmQtRG9uZXMgYW5kIFN1cnZpdmluZyBQbGF5ZXJzIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJTdXJ2aXZvcnMgcGxheSBiZXR0ZXIgYXQgbmVhcmx5IGFsbCBhZ2VzIiwgIA0KICAgICAgIGNhcHRpb24gPSAiQGJlbmhvd2VsbDcxIG9uIFR3aXR0ZXIgfCBiZW5ob3dlbGw3MS5jb20iKSArDQogIHNjYWxlX2NvbG9yX2NvbG9yYmxpbmQoKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxNiwgZmFjZSA9ICJib2xkIiksDQogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxMiwgZmFjZSA9ICJpdGFsaWMiKSwNCiAgICAgICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gIml0YWxpYyIpLA0KICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLA0KICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDEuNSwgJ2xpbmVzJykpDQpgYGANCg0KYGBge3J9DQpkYXRhIDwtIGRhdGEgJT4lDQogIG11dGF0ZShuZXh0X2FnZSA9IGFnZV9pbl9zZWFzb24gKyAxKQ0KDQpuZXh0X3NlYXNvbiA8LSBkYXRhICU+JQ0KICBkcGx5cjo6c2VsZWN0KGFnZV9pbl9zZWFzb24sIGdzX2dhbSkgJT4lDQogIHJlbmFtZSgibmV4dF9hZ2UiID0gImFnZV9pbl9zZWFzb24iLA0KICAgICAgICAgIm5leHRfZ3MiID0gImdzX2dhbSIpDQoNCmRhdGEgPC0gcmlnaHRfam9pbihkYXRhLCBuZXh0X3NlYXNvbiwgYnkgPSAibmV4dF9hZ2UiKQ0KDQpkYXRhIDwtIGRhdGEgJT4lDQogIG11dGF0ZShjaGFuZ2UgPSBuZXh0X2dzIC0gZ3NfZ2FtKSAlPiUNCiAgZHBseXI6OnNlbGVjdChuZXh0X2FnZSwgY2hhbmdlKSAlPiUgDQogIGZpbHRlcighIGlzLm5hKGNoYW5nZSkpDQoNCmF2ZyA8LSBud2hsZGYgJT4lDQogIGdyb3VwX2J5KGFnZV9pbl9zZWFzb24pICU+JQ0KICBzdW1tYXJpc2UoYXZnID0gd2VpZ2h0ZWQubWVhbihnYW1lX3Njb3JlX2dhbWUsIGdwLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgZ3AyID0gbWVhbihncCwgbmEucm0gPSBUUlVFKSkgJT4lDQogIGZpbHRlcighIGlzLm5hKGFnZV9pbl9zZWFzb24pKQ0KDQptbl9ncyA8LSB3ZWlnaHRlZC5tZWFuKG53aGxkZiRnYW1lX3Njb3JlX2dhbWUsIG53aGxkZiRncCwgbmEucm0gPSBUUlVFKQ0Kc2FtX2dwIDwtIDIuOTQNCg0KZGYgPC0gbndobGRmICU+JQ0KICBkcGx5cjo6c2VsZWN0KHBsYXllciwgZW5kX3llYXIsIGFnZV9pbl9zZWFzb24sIGdwLCANCiAgICAgICAgICAgICAgICBnYW1lX3Njb3JlX2dhbWUsIHNlYXNvbnMsIHNlYXNvbl9vcmRlcikgJT4lDQogIGdyb3VwX2J5KHBsYXllcikgJT4lDQogIG11dGF0ZShuZXh0X2FnZSA9IGFnZV9pbl9zZWFzb24gKyAxLA0KICAgICAgICAgbWF4X3llYXIgPSBtYXgoZW5kX3llYXIpLA0KICAgICAgICAgeWVhcl9yZWxhdGl2ZSA9IG1heF95ZWFyIC0gZW5kX3llYXIgKyAxKSAlPiUNCiAgZmlsdGVyKGVuZF95ZWFyICVpbiUgYygyMDIxLCAyMDIwLCAyMDE5KSkgJT4lDQogIGdyb3VwX2J5KHBsYXllcikgJT4lIA0KICBhcnJhbmdlKHBsYXllciwgZGVzYyhlbmRfeWVhcikpICU+JQ0KICBtdXRhdGUobjFfZ3MgPSBsZWFkKGdhbWVfc2NvcmVfZ2FtZSksDQogICAgICAgICBuMl9ncyA9IGxlYWQoZ2FtZV9zY29yZV9nYW1lLCAyKSwNCiAgICAgICAgIG4xX2dwID0gbGVhZChncCksDQogICAgICAgICBuMl9ncCA9IGxlYWQoZ3AsIDIpKSAlPiUNCiAgZHBseXI6OnNlbGVjdChwbGF5ZXIsIG5leHRfYWdlLCBnYW1lX3Njb3JlX2dhbWUsIA0KICAgICAgICAgICAgICAgIG4xX2dzLCBuMl9ncywgZ3AsIG4xX2dwLCBuMl9ncCkgJT4lDQogIG11dGF0ZSh0d29feXIgPSBuZXh0X2FnZSAtIDIpICU+JQ0KICByaWdodF9qb2luKGF2ZywgYnkgPSBjKCJ0d29feXIiID0gImFnZV9pbl9zZWFzb24iKSkgJT4lDQogIGdyb3VwX2J5KHBsYXllcikgJT4lDQogIGZpbHRlcihuZXh0X2FnZSA9PSBtYXgobmV4dF9hZ2UpKSAlPiUNCiAgZmlsdGVyKCEgaXMubmEoZ2FtZV9zY29yZV9nYW1lKSkgJT4lDQogIHJpZ2h0X2pvaW4oZGF0YSwgYnkgPSBjKCJuZXh0X2FnZSIpKSAlPiUNCiAgI3RoZSBjaGFuZ2UgdGhhdCB3ZSdyZSBhZGRpbmcgdG8gdGhpcyBkYXRhZnJhbWUgaXMgdGhlIGFnaW5nIGVmZmVjdCB0aGF0DQogICN3ZSBhZGQgaW4gdG8gdGhlIHByZWRpY3Rpb24gdG8gYWNjb3VudCBmb3IgdGhlIGFnaW5nIHVwIG9yIGRvd24NCiAgbXV0YXRlKGFkal9hdmcgPSAoKGF2ZyAqIGdwMikgKyAoYXZnX2dtc2NvcmUgKiBzYW1fZ3ApICsgDQogICAgICAgICAgICAgICAgICAgICAgKChnYW1lX3Njb3JlX2dhbWUgLyAyKSAqIGdwMikpIC8gKGdwMiArIHNhbV9ncCArIGdwMiksDQogICAgICAgICB0ZXN0ID0gKChhdmcgKiBncDIpICsgKGF2Z19nbXNjb3JlICogc2FtX2dwKSkgLyAoZ3AyICsgc2FtX2dwKSwNCiAgICAgICAgIG4xX2dzID0gaWZlbHNlKGlzLm5hKG4xX2dzKSwgYWRqX2F2ZywgbjFfZ3MpKSAlPiUNCiAgI3R1cm5zIG91dCB0aGF0IHRoZSBkZWZhdWx0IHRoYXQgd2UgcHV0IGl0IGluaXRpYWxseSB3YXMgDQogICNXQVlZWVlZIG92ZXJlc3RpbWF0aW5nIHRoaW5ncyBmb3IgcGxheWVycyB3aG8gaGFkIG9ubHkgMSBzZWFzb24gb2YgcGxheQ0KICAjc28gSSBhZGRlZCBpbiB0aGVpciBnYW1lX3Njb3JlX2dhbWUgaW4gdGhlaXIgb25seSBzZWFzb24gDQogICNoYWx2ZWQgdG8gY29udGludWUgdG8gcmVncmVzcyBpdCwgYmMgZGlkbid0IHdhbnQgdG8gZ2l2ZSB0b28gbXVjaCBjcmVkaXQgdG8gYW55b25lDQogICN3aXRoIGp1c3Qgb25lIHNlYXNvbiBvZiBwbGF5DQogIGRwbHlyOjpzZWxlY3QocGxheWVyLCBuZXh0X2FnZSwgZ2FtZV9zY29yZV9nYW1lLCANCiAgICAgICAgICAgICAgICBuMV9ncywgbjJfZ3MsIGdwLCBuMV9ncCwgbjJfZ3AsIGdwMiwgY2hhbmdlKSAlPiUNCiAgbXV0YXRlKHByZWRpY3Rpb24gPSBpZmVsc2UoISBpcy5uYShuMl9ncyksDQogICAgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiAgICAjZm9yIHBsYXllcnMgd2l0aCBvbmx5IDIgc2Vhc29ucyBvZiBwbGF5LCB3ZSBkb24ndCBhZGQgYSB0aGlyZCByZWdyZXNzZWQgc2Vhc29uIEdTL0cNCiAgICAjaWYgdGhlIHBsYXllciBoYWQgYSB0aGlyZCB5ZWFyLCB3ZSB1c2UgdGhhdA0KICAgICgoZ2FtZV9zY29yZV9nYW1lICogeTEpICsgKG4xX2dzICogeTIpICsgKG4yX2dzICogeTMpKSAvIChvdnIpLCANCiAgICAoKGdhbWVfc2NvcmVfZ2FtZSAqIHkxKSArIChuMV9ncyAqIHkyKSkgLyAob3ZyIC0geTMpKSwNCiAgcmVncmVzc2VkX3ByZWQgPSAoKGdwICogcHJlZGljdGlvbikgKyAoc2FtX2dwICogYXZnX2dtc2NvcmUpKSAvIChncCArIHNhbV9ncCksDQogIGFnZV9wcmVkID0gcmVncmVzc2VkX3ByZWQgKyBjaGFuZ2UpDQoNCmV4MSA8LSBkZg0KDQpkZiA8LSBkZiAlPiUNCiAgZHBseXI6OnNlbGVjdChwbGF5ZXIsIG5leHRfYWdlLCBncCwgZ2FtZV9zY29yZV9nYW1lLCANCiAgICAgICAgICAgICAgICBhZ2VfcHJlZCwgcmVncmVzc2VkX3ByZWQpICU+JQ0KICBtdXRhdGUoY2hhbmdlX3ByZWQgPSBhZ2VfcHJlZCAtIGdhbWVfc2NvcmVfZ2FtZSkNCiAgI2FnZSBwcmVkIGlzIHRoZSBtYWluIHByZWRpY3Rpb24NCiAgI25lZWQgdG8gZmlndXJlIG91dCBhIGJldHRlciB3YXkgdG8gYWNjb3VudCBmb3IgdGhpbmdzIGZvciBwbGF5ZXJzIHdpdGggMSBHUA0KICAjYmMgdGhhdCBnZXQncyByZWdyZXNzZWQgdG9vIGZhciB0b3dhcmRzIGF2ZXJhZ2UgDQoNCnNtYWxsIDwtIG53aGxkZiAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBmaWx0ZXIoZ3AgPiAwICYgZ3AgPD0gNSkgJT4lDQogIHN1bW1hcmlzZSh0b3RhbCA9IG4oKSwNCiAgICAgICAgICAgIGdwcyA9IHN1bShncCksDQogICAgICAgICAgICBhdmcgPSB3ZWlnaHRlZC5tZWFuKGdhbWVfc2NvcmVfZ2FtZSwgZ3ApKSAlPiUNCiAgbXV0YXRlKGF2Z19nbXMgPSByb3VuZChncHMgLyB0b3RhbCwgZGlnaXRzID0gMSkpDQoNCmdtcyA8LSBzbWFsbCRhdmdfZ21zDQpzbWFsbF9nbXMgPC0gc21hbGwkYXZnDQoNCmdtIDwtIG53aGxkZiAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBmaWx0ZXIoZ3AgPiAwKSAlPiUNCiAgZ3JvdXBfYnkoZ3ApICU+JQ0KICBzdW1tYXJpc2UodG90YWwgPSBuKCksDQogICAgICAgICAgICBncHMgPSBzdW0oZ3ApLA0KICAgICAgICAgICAgYXZnID0gd2VpZ2h0ZWQubWVhbihnYW1lX3Njb3JlX2dhbWUsIGdwKSkNCg0KbW9kIDwtIGdhbShhdmcgfiAoZ3ApXjIgKyBncCwgZGF0YSA9IGdtKQ0KZ20kc21vb3RoIDwtIHByZWRpY3QobW9kLCBuZXdkYXRhID0gZ20pDQoNCmdtIDwtIGdtICU+JSBkcGx5cjo6c2VsZWN0KGdwLCBzbW9vdGgpDQoNCmRmIDwtIGRmICU+JQ0KICBsZWZ0X2pvaW4oZ20sIGJ5ID0gImdwIikgJT4lDQogIG11dGF0ZSh1cGRhdGVkX3ByZWQgPSBpZmVsc2UoZ3AgPiA1LCBhZ2VfcHJlZCwNCiAgICAoKGdwICogZ2FtZV9zY29yZV9nYW1lKSArIChzbWFsbF9nbXMgKiBnbXMpICsgKHNtb290aCAqIGdwKSkgLyAoZ3AgKyBnbXMgKyBncCkpLA0KICAgICN0aGUgTUFSQ0VMIHByZWRpY3Rpb24gaXMgb3VyIGZpbmFsIG9uZQ0KICAgICNzbywgZm9yIHBsYXllcidzIHdpdGggZmV3ZXIgdGhhbiA1IGdhbWVzIHBsYXllZCwgd2UgYWRkIG9uIGEgZmV3IGdhbWVzIHdvcnRoIG9mIHBsYXkNCiAgICAjYmFzZWQgb24gdGhlIGF2ZyBHUy9HIGZvciBwbGF5ZXJzIHcvIGxlc3MgdGhhbiA1IEdQDQogICAgbWFyY2VsX3ByZWRpY3Rpb24gPSBpZmVsc2UoZ3AgPiA1LCBhZ2VfcHJlZCwNCiAgICAoKGdwICogZ2FtZV9zY29yZV9nYW1lKSArIChzbWFsbF9nbXMgKiBnbXMpKSAvIChncCArIGdtcykpKSANCiAgICAjKGl0J3Mgd29ydGggbm90aW5nIHRoYXQgd2hlbiB5b3UgbG9vayBhdCB0aGUgdGFibGUgb2YgcmVzdWx0cykgDQogICAgI2l0IHdpbGwgYXBwZWFyIGFzIGlmIHRoZXJlJ3Mgbm8gcGxheWVyJ3Mgdy8gbGVzcyB0aGFuIDUgR1AgYmMgSSBzY2FsZWQgdXAgZnJvbSB0aGUgbG93IDIwMjEgR1AgDQogICAgI3RvIHRoZSBlcXVpdmFsZW50IG9mIHdoYXRldmVyIHBlcmNlbnRhZ2Ugb2YgMjQgZ2FtZXMgKGEgZnVsbCBOV0hMIHNlYXNvbikNCg0KZXggPC0gZGYgDQoNCmRmIDwtIGRmICU+JQ0KICBkcGx5cjo6c2VsZWN0KHBsYXllcjphZ2VfcHJlZCwgbWFyY2VsX3ByZWRpY3Rpb24pICU+JQ0KICBtdXRhdGUoYWdlX3ByZWQgPSByb3VuZChhZ2VfcHJlZCwgZGlnaXRzID0gMiksDQogICAgICAgICBtYXJjZWxfcHJlZGljdGlvbiA9IHJvdW5kKG1hcmNlbF9wcmVkaWN0aW9uLCBkaWdpdHMgPSAyKSkNCiNJIGxpa2UgaG93IHRoZXNlIGxvb2sNCiN0aGV5IGtlZXAgdGhlIGFnZV9wcmVkIGZvciBwbGF5ZXJzIHdpdGggYSBsb3Qgb2YgR1AsIGJ1dCBkb24ndCBvdmVycHJlZGljdCB0aGUgcGxheWVycyB3aG8gaGF2ZW4ndCBwbGF5ZWQgdmVyeSBtdWNoDQoNCnJlY2VudCA8LSBud2hsICU+JQ0KICBmaWx0ZXIoZW5kX3llYXIgPT0gMjAyMSkNCg0KcmVzdWx0cyA8LSBkZiAlPiUNCiAgZmlsdGVyKHBsYXllciAlaW4lIHJlY2VudCRwbGF5ZXIpDQpgYGANCg0KYGBge3J9DQpwbGF5IDwtIG53aGxkZiAlPiUgDQogIGRwbHlyOjpzZWxlY3QocGxheWVyLCBzZWFzb25zKSAlPiUNCiAgZGlzdGluY3QocGxheWVyLCBzZWFzb25zKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBjb3VudChzZWFzb25zKQ0KDQp0YWIgPC0gcGxheSAlPiUNCiAga25pdHI6OmthYmxlKGNvbC5uYW1lcyA9IGMoIlNlYXNvbnMgUGxheWVkIiwgIiMgb2YgUGxheWVycyIpLCBhbGlnbiA9ICJjYyIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGQUxTRSwgYygic3RyaXBlZCIsICJob3ZlciIpKQ0KYGBgDQoNCipJIGluaXRpYWxseSBwcmVzZW50ZWQgbXkgTldITCBBZ2luZyBDdXJ2ZSB3b3JrIGF0IHRoZSAyMDIxIFdIS1lIQUMgY29uZmVyZW5jZSwgYW5kIGJlbG93IGlzIGEgd3JpdGUtdXAgb2YgbXkgYW5hbHlzaXMvcmVzdWx0cy4gWW91IGNhbiB2aWV3IG15IHByZXNlbnRhdGlvbiBbaGVyZV0oaHR0cHM6Ly95b3V0dS5iZS91OUtjeF9WZXNkZykuKg0KDQoqSWYgeW91J3JlIGp1c3QgaGVyZSB0byBjaGVjayBvdXQgdGhlIDIwMjIgTldITCBHYW1lIFNjb3JlIFByb2plY3Rpb25zLCBzY3JvbGwgZG93biB0byB0aGUgYm90dG9tIG9mIHRoaXMgYXJ0aWNsZSB0byBjaGVjayB0aGVtIG91dCEgSWYgeW91J3JlIGludGVyZXN0ZWQgaW4gdGhlIGFuYWx5c2lzIGFuZCBwcm9jZXNzLCBrZWVwIHJlYWRpbmcsIGFuZCB5b3UnbGwgZ2V0IHRoZXJlIGV2ZW50dWFsbHkhKg0KDQpBZ2luZyBpbiBzcG9ydCBpcyBhIGNvbXBsaWNhdGVkIHF1ZXN0aW9uLCBidXQgb25lIG9mIHRoZSBtb3N0IGltcG9ydGFudCBvbmVzIHRoYXQgd2UgY2FuIHRyeSB0byBhbnN3ZXIgb3IsIGF0IHRoZSB2ZXJ5IGxlYXN0LCBmaW5kIHBhdHRlcm5zIGFtb25nc3QgcGxheWVycy4gV2hldGhlciBvbmUgaXMgd29ya2luZyBmb3IgYSB0ZWFtIHRyeWluZyB0byBkZXRlcm1pbmUgd2hvIHRvIGFjcXVpcmUgb3IgYSBmYW50YXN5IGhvY2tleSBwbGF5ZXIgbG9va2luZyBhdCB3aG8geW91IHdhbnQgb24geW91ciB0ZWFtIG5leHQgc2Vhc29uLCBoYXZpbmcgYW4gaWRlYSBvZiBob3cgdGhlaXIgcGVyZm9ybWFuY2UgbWF5IGNoYW5nZSBpcyBzdXBlciBpbXBvcnRhbnQhICAgICAgICAgICAgICAgICAgICAgIA0KDQpJbiB0aGUgd29ybGQgb2YgbWVuJ3Mgc3BvcnRzLCB0aGVyZSBoYXMgYmVlbiBwbGVudHkgb2Ygd29yayBzdXJyb3VuZGluZyBhZ2luZyBjdXJ2ZXMgaW4gbW9zdCBvZiB0aGUgbWFqb3IgbWVuJ3MgbGVhZ3VlcyAoW01MQl0oaHR0cHM6Ly93d3cuYmFzZWJhbGxwcm9zcGVjdHVzLmNvbS9uZXdzL2FydGljbGUvNTk5NzIvdGhlLWRlbHRhLW1ldGhvZC1yZXZpc2l0ZWQvKSwgW05CQV0oaHR0cHM6Ly9saW5rLnNwcmluZ2VyLmNvbS9hcnRpY2xlLzEwLjM3NTgvczEzNDI4LTAxOC0xMTgzLTgpLCBbTkhMXShodHRwczovL2hvY2tleS1ncmFwaHMuY29tLzIwMTcvMDMvMjMvYS1uZXctbG9vay1hdC1hZ2luZy1jdXJ2ZXMtZm9yLW5obC1za2F0ZXJzLXBhcnQtMS8pKS4gSG93ZXZlciwgYWdpbmcgY3VydmVzIGluIHdvbWVuJ3Mgc3BvcnRzIGhhdmUgcmVtYWluZWQgcmVsYXRpdmVseSB1bmV4cGxvcmVkLCB0aG91Z2ggdGhlcmUgaGF2ZSBiZWVuIHR3byBub3RhYmxlIGFnaW5nIGN1cnZlcyBwcm9qZWN0cyBpbiB3b21lbidzIGhvY2tleSwgd2l0aCBbQ2FybGVlbiBNYXJrZXknc10oaHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vcHJlc2VudGF0aW9uL2QvMUVqMGJfZ1NnaDVSOTNURTlsOWdOQkg2Mm1lVjBBRWlmdnFJMks1ZGcxRkUvZWRpdCNzbGlkZT1pZC5wKSBDYW5hZGlhbiBXb21lbidzIEhvY2tleSBMZWFndWUgKENXSEwpIHByb2plY3QgYW5kIFtNaWtlIE11cnBoeSdzIE5DQUEgRDFdKGh0dHBzOi8vaG9ja2V5LWdyYXBocy5jb20vMjAyMC8wNi8yNS9leGFtaW5pbmctcGxheWVyLWRldmVsb3BtZW50LWluLW5jYWEtZGktd29tZW5zLWhvY2tleS13aXRoLWdhbWUtc2NvcmUtcHQtMS8pIHByb2plY3QuICAgICAgICAgICAgICAgICANCg0KVGhlIHF1ZXN0aW9uIG9mIGFnaW5nIGFuZCBpdHMgcm9sZSBpbiBwcm9qZWN0aW5nIHBlcmZvcm1hbmNlIGhhcyBpbnRlcmVzdGVkIG1lIGZvciBhIHdoaWxlLCBzbyBJIGRlY2lkZWQgdG8gd29yayBvbiBhIHByb2plY3QgZm9jdXNlZCBvbiBldmFsdWF0aW5nIGFnaW5nIGN1cnZlcyBpbiB0aGUgTmF0aW9uYWwgV29tZW4ncyBIb2NrZXkgTGVhZ3VlIChOV0hMKSBmb3IgdGhlIFsyMDIxIFdIS1lIQUMgQ29uZmVyZW5jZV0oaHR0cHM6Ly93d3cud2hreWhhYy5jb20vKS4gQmVsb3cgaXMgYSB3cml0ZS11cCBvZiBteSBwcm9jZXNzIGFuZCBhbmFseXNpcywgYXMgd2VsbCBhcyBzb21lIG9mIHRoZSBjb2RlIEkgd3JvdGUuDQoNCioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0KDQojIFdoZXJlIERvIFdlIFN0YXJ0Pw0KDQpUaGUgZmlyc3QgcXVlc3Rpb24gdGhhdCBuZWVkcyBhbnN3ZXJpbmcgaXMgc2ltcGxlOiB3aGF0IG1ldHJpYyBhcmUgd2UgZ29pbmcgdG8gdXNlIHRvIGV2YWx1YXRlIHBsYXllcnM/ICAgICAgICAgDQoNClRoZXJlIGFyZSBhIGZldyBkaWZmZXJlbnQgb3B0aW9ucy4gQ2FybGllJ3MgQ1dITCBwcm9qZWN0IHVzZWQgW09mZmVuc2l2ZSBQb2ludCBTaGFyZXNdKGh0dHBzOi8vd3d3LmhvY2tleS1yZWZlcmVuY2UuY29tL2Fib3V0L3BvaW50X3NoYXJlcy5odG1sKSwgd2hpbGUgTWlrZSdzIHVzZWQgaGlzIHJldmFtcGVkIFtHYW1lIFNjb3JlXShodHRwczovL2hvY2tleS1ncmFwaHMuY29tLzIwMTkvMDgvMjEvcmV2aXNpdGluZy1ud2hsLWdhbWUtc2NvcmUvKSB0byBldmFsdWF0ZSBOQ0FBIHNrYXRlcnMuIEFub3RoZXIgb3B0aW9uIHdvdWxkIGJlIHRvIHVzZSBwb2ludCB0b3RhbHMgKGdvYWxzICsgYXNzaXN0cyksIGJ1dCBJIG9wdGVkIHRvIGZvbGxvdyBNaWtlJ3MgZm9vdHN0ZXBzIGFuZCB1c2UgR2FtZSBTY29yZSBwZXIgR2FtZSAoR1MvRykgdG8gZXZhbHVhdGUgTldITCBza2F0ZXJzLiAgICAgICAgICAgICAgICAgICAgICANCg0KW0dhbWUgU2NvcmVdKGh0dHBzOi8vaG9ja2V5LWdyYXBocy5jb20vMjAxOS8wOC8yMS9yZXZpc2l0aW5nLW53aGwtZ2FtZS1zY29yZS8pIGVzc2VudGlhbGx5IHdlaWdodHMgZXZlbnRzIG9uIHRoZSBpY2UgYnkgaG93IGZyZXF1ZW50bHkgdGhleSBvY2N1ciByZWxhdGl2ZSB0byBhIGdvYWwgYmVpbmcgc2NvcmVkLiBZb3UgY2FuIChhbmQgZGVmaW5pdGVseSBzaG91bGQpIHJlYWQgdGhlIGxpbmtlZCBhcnRpY2xlIGZvciBtb3JlIG9uIEdhbWUgU2NvcmUsIGJ1dCBJJ3ZlIGluY2x1ZGVkIHRoZSBOV0hMIGZvcm11bGEgYmVsb3cuIA0KDQokJEdhbWUgU2NvcmUgPSBHICsgKC45KkExKSArICguNjYqQTIpICsgKC4xKlNPRykgKyAgICAgICAgICAgICAgICAgICANCiguMTEgKiBGT1cpIC0gKC4xMSAqIEZPTCkgLSAoLjE1ICogUEVOVCkkJA0KDQpUaGVyZSBhcmUgYSBsb3Qgb2YgcmVhc29ucyB0byB1c2UgZ2FtZSBzY29yZSwgbm90YWJseSB0aGF0IGl0IGlzICpyZWFsbHkgcmVhbGx5KiBoYXJkIGZvciBhIHBsYXllciB0byBwdXQgdXAgYSBoaWdoIGdhbWUgc2NvcmUgd2l0aG91dCBwbGF5aW5nIHRpbWUgb3IgKmFjdHVhbGx5KiBiZWluZyBhIGdvb2QgcGxheWVyLiBGb3IgbW9zdCBvZiB0aGlzIHByb2plY3QsIEkgd2lsbCB1c2UgR1MvRyByZWxhdGl2ZSB0byBhdmVyYWdlICh6LXNjb3JlcykgdG8gZXZhbHVhdGUgcGxheWVyIHBlcmZvcm1hbmNlLCB1bmxlc3Mgb3RoZXJ3aXNlIG5vdGVkLiAgICAgICAgICANCg0KTmV4dCB1cDogc2luY2UgdGhpcyBpcyB3b21lbidzIHNwb3J0cyBhbmFseXRpY3MsIHRoaW5ncyBhcmUgbmV2ZXIgZWFzeSwgZXNwZWNpYWxseSB3aXRoIGFuIGFnaW5nIGN1cnZlIHByb2plY3QgdGhhdCByZWxpZXMgb24gcGxheWVycyBoYXZpbmcgbXVsdGlwbGUgc2Vhc29ucyBvZiBwbGF5IHN0cnVuZyB0b2dldGhlci4gVW5mb3J0dW5hdGVseSwgdGhhdCdzIG5vdCBzb21ldGhpbmcgd2UgaGF2ZSB0aGUgbHV4dXJ5IG9mIHdpdGggdGhlIE5XSEwuICAgICAgICAgICAgICAgIA0KDQpUaGUgbGVhZ3VlIGhhcyBvbmx5IGJlZW4gYXJvdW5kIHNpbmNlIDIwMTUtMjAxNiwgYW5kIHRoZSB5ZWFycyBzaW5jZSB0aGVuIGhhdmUgbm90IG5lY2Vzc2FyaWx5IGJlZW4uLi5zbW9vdGgsIHRvIHB1dCBpdCBtaWxkbHkuIFdlIHNlZSB0aGUgZWZmZWN0IG9mIHRoYXQgdHVyYnVsZW5jZSB3aGVuIHdlIGxvb2sgYXQgaG93IG1hbnkgY29uc2VjdXRpdmUgc2Vhc29ucyBoYXZlIGJlZW4gc3RydW5nIHRvZ2V0aGVyIGJ5IE5XSEwgc2thdGVycy4gICAgICAgICAgICAgICAgICANCg0KYGBge3IsIGluY2x1ZGU9VFJVRX0NCnRhYg0KYGBgDQoNCk9mIHRoZSAzMTQgcGxheWVyIHNlYXNvbnMgdGhhdCB3ZSBoYXZlIChub3QgaW5jbHVkaW5nIDIwMjAtMjAyMSBmb3Igbm93KSwgd2Ugc2VlIHRoYXQgbmVhcmx5IDU1JSBvZiBhbGwgcGxheWVycyBpbiB0aGUgTldITCBoYXZlIG9ubHkgcGxheWVkIG9uZSBzZWFzb24gaW4gdGhlIGxlYWd1ZS4gQW5kIHRoZXJlIGFyZSB2ZXJ5IHZlcnkgZmV3IHBsYXllcnMgd2hvIHBsYXllZCBhdCBsZWFzdCBmb3VyIHllYXJzIGluIHRoZSBOV0hMLg0KDQpGdXJ0aGVybW9yZSwgYW4gYWRkaXRpb25hbCBjb21wbGljYXRpbmcgZmFjdG9yIGlzIHRoYXQgbW9zdCBvZiB0aGUgZ2FtZXMgcGxheWVkIGluIE5XSEwgaGlzdG9yeSBoYXZlIGJlZW4gcGxheWVkIGJ5IHBsYXllcnMgaW4gdGhlIDIyLTI2LXllYXItb2xkIHJhbmdlLiBQbGF5ZXJzIHJhcmVseSBwbGF5IGludG8gdGhlaXIgMzBzIGR1ZSB0byBhIG11bHRpdHVkZSBvZiBmYWN0b3JzLCBtb3N0IG9mIHdoaWNoIHJldm9sdmUgYXJvdW5kIGxvdyBzYWxhcmllcy4gVGhhdCBtYWtlcyBldmFsdWF0aW5nIHBlcmZvcm1hbmNlIGFzIGEgZnVuY3Rpb24gb2YgYWdlIGtpbmRhIHRvdWdoIQ0KDQpgYGB7ciwgaW5jbHVkZT1UUlVFfQ0Kc2Vhc29ucw0KYGBgDQoNClRoZXNlIGFyZSBzb21lIHRoaW5ncyB0aGF0IHdlJ2xsIG5lZWQgdG8ga2VlcCBpbiBtaW5kIGFzIHdlIG1vdmUgZm9yd2FyZCB3aXRoIG91ciBhZ2luZyBjdXJ2ZSBhbmFseXNpcy4gQnV0IG5vdyB0aGF0IEkndmUgY292ZXJlZCBzb21lIG9mIHRoZSBjb21wbGljYXRpbmcgZmFjdG9ycywgaXQncyB0aW1lIHRvIG1vdmUgZm9yd2FyZCB3aXRoIHRoZSBhbmFseXNpcy4NCg0KKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqDQoNCiMgRGVsdGEgTWV0aG9kDQoNClRoZXJlIGFyZSBhIGZldyB3YXlzIHRvIGdvIGFib3V0IG1lYXN1cmluZyB0aGUgZWZmZWN0IG9mIGFnaW5nIG9uIEdTL0cuICAgICAgIA0KDQpUaGUgZmlyc3QgaXMgdGhlIHNpbXBsZXN0IGFuZCBwZXJoYXBzIHRoZSBtb3N0IGludHVpdGl2ZTogdGhlIGRlbHRhIG1ldGhvZCwgd2hpY2ggQ2FybGllIGFuZCBNaWtlIHVzZWQgaW4gdGhlaXIgcHJvamVjdHMuICAgICAgICAgICAgIA0KDQpUaGUgZGVsdGEgbWV0aG9kIHBhaXJzIGJhY2stdG8tYmFjayBzZWFzb25zIGZvciBhIHBsYXllciBhbmQgbG9va3MgYXQgdGhlaXIgY2hhbmdlIGluIHBlcmZvcm1hbmNlIGZyb20gYWdlIHRvIGFnZSAoaGVyZSwgSSB1c2VkIHRydWUgR1MvRyB0byBldmFsdWF0ZSB0aGUgY2hhbmdlcywgcmF0aGVyIHRoYW4gdGhlIGFmb3JlbWVudGlvbmVkIHotc2NvcmVzKS4gT25jZSBlbm91Z2ggc2Vhc29ucyB3ZXJlIHBhaXJlZCwgSSBhdmVyYWdlZCB0aGUgY2hhbmdlIGluIHBlcmZvcm1hbmNlIGZvciBlYWNoIGFnZSBidWNrZXQgKGkuZS4gMjEtMjIsIDI0LTI1LCAzMC0zMSwgZXRjKS4gU3RyaW5nIHRoZW0gYWxsIHRvZ2V0aGVyLCBhbmQgd2UgaGF2ZSB0aGUgYXZlcmFnZSBjaGFuZ2UgYnkgYWdlLCBhcyBpbGx1c3RyYXRlZCBiZWxvdyENCg0KPGNlbnRlcj4NCg0KIVtdKGRlbHRhMi5wbmcpDQoNCjwvY2VudGVyPg0KDQpUaGUgYWdlIGJ1Y2tldHMgZnJvbSBhYm91dCAyMy0yOCBhcmUgdGhlIGdyb3VwcyB3aGVyZSBwbGF5ZXJzIHRlbmQgdG8gY29uc2lzdGVudGx5IG1haW50YWluIHBlcmZvcm1hbmNlIChvciwgaW4gc29tZSBjYXNlcywgaW5jcmVhc2UgaXQpLiBXaGlsZSB0aGVyZSBhcmUgYWdlIGJ1Y2tldHMgYXQgMzArIHRoYXQgc2hvdyBpbmNyZWFzZXMgaW4gcGVyZm9ybWFuY2VzLCB0aGUgZGFyayByZWQgZG90cyBpbmRpY2F0ZSBob3cgZmV3IGdhbWVzIHBsYXllZCBpbiB0aG9zZSBhZ2UgYnVja2V0cy4gICAgICAgICAgICAgICAgICAgDQoNClRoaXMgaXMgbm90IGFuIGlkZWFsIG1ldGhvZCBvZiBhbmFseXNpcyBmb3IgdGhlIE5XSEwgZ2l2ZW4gdGhlIGxpbWl0ZWQgZGF0YXNldCwgYnV0IEkgd2FudGVkIHRvIHRvdWNoIG9uIHRoZSBkZWx0YSBtZXRob2QgdG8gYnVpbGQgb24gcHJldmlvdXMgd29tZW4ncyBob2NrZXkgYWdpbmcgYW5hbHlzZXMuICAgICAgICAgICAgICANCg0KKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqDQoNCiMgT25lLWFuZC1Eb25lIFBsYXllcnMgdnMgU3Vydml2b3JzDQoNClRoZSBtYWluIHdlYWtuZXNzIG9mIHRoZSBkZWx0YSBtZXRob2QgaXMgdGhhdCB5b3UgZW5kIHVwIHRocm93aW5nIG91dCBwbGF5ZXJzIHdobyBvbmx5IHBsYXllZCBvbmUgc2Vhc29uIGluIHRoZWlyIGNhcmVlciwgYXMgd2VsbCBhcyB0aGUgbGFzdCBzZWFzb24gb2YgYSBwbGF5ZXIncyBjYXJlZXIgc2luY2UgdGhleSBkb24ndCBoYXZlIGFuIGFkZGl0aW9uYWwgc2Vhc29uIHRvIHBhaXIgd2l0aC4gICAgICAgICAgICAgICANCg0KUHJlc3VtYWJseSwgdGhlcmUncyBhIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgcGxheWVycyB3aG8gb25seSBwbGF5IGZvciBvbmUgc2Vhc29uIGJlZm9yZSBmYWlsaW5nIHRvIHJldHVybiB0byB0aGUgTldITCBhbmQgdGhlIHBsYXllcnMgd2hvIHJlY2VpdmUgYW5vdGhlciBzaG90IGluIHRoZSBsZWFndWUuIFNpbmNlIHRoZSBkZWx0YSBtZXRob2QgZG9lc24ndCBhY2NvdW50IGZvciBwbGF5ZXJzIHdobyBmYWlsIHRvICJzdXJ2aXZlIiwgSSB3YW50ZWQgdG8gZGlyZWN0bHkgY29tcGFyZSBvbmUtYW5kLWRvbmUgYW5kIHN1cnZpdmluZyBwbGF5ZXJzIHRvIHNlZSBpZiB0aGF0IGRpZmZlcmVuY2UgcGxheWVkIG91dC4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCg0KVHVybnMgb3V0IHRoZXJlIGlzIGEgZGlmZmVyZW5jZSENCg0KYGBge3IsIGluY2x1ZGU9VFJVRX0NCnN1cg0KYGBgDQoNClBsYXllcnMgd2hvIG1ha2UgaXQgdG8gYSBzZWNvbmQgTldITCBzZWFzb24gcGxheWVkIG1vcmUgYXMgYSByb29raWUgQU5EIHBsYXllZCBiZXR0ZXIgdGhhbiBhdmVyYWdlLiBTaW5jZSB0aGUgb25lLWFuZC1kb25lIHBsYXllcnMgYXJlbid0IGluY2x1ZGVkIGluIHRoZSBkZWx0YSBtZXRob2QsIHRoZSBtZXRob2QgbGlrZWx5IG92ZXJyYXRlcyB0aGUgcXVhbGl0eSBvZiBwbGF5ZXIgaW4gdGhlIGxlYWd1ZS4gICAgICAgICAgICANCg0KVGhpcyBhbHNvIHNob3dzIGhvdyBpbXBvcnRhbnQgaXQgaXMgZm9yIGEgcm9va2llIHRvIHByb2R1Y2UgaW1tZWRpYXRlbHkgaW4gdGhlIE5XSEwuIFVuZm9ydHVuYXRlbHksIHRlYW1zIGRvbid0IG5lY2Vzc2FyaWx5IGhhdmUgdGhlIG1vbmV5IG9yIHRoZSB0aW1lIHRvIGxldCB5b3VuZyBwbGF5ZXJzIGRldmVsb3AsIHNvIHRoZSBvbmx5IHBsYXllcnMgd2hvIG1ha2UgaXQgdG8geWVhciB0d28gYXJlIHRoZSBzdHJvbmcgcGVyZm9ybWVycy4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KDQoqKEkgdGhpbmsgaXQncyB3b3J0aCBub3RpbmcgdGhhdCBpZiBhbiBOV0hMIHJvb2tpZSBkb2Vzbid0IGdldCB0byBwbGF5LCB0aGV5IG1heSBiZSBtb3JlIGxpa2VseSB0byBqdW1wIGJhY2sgdG8gYSBkaWZmZXJlbnQgbGVhZ3VlLCBwb3RlbnRpYWxseSBvbmUgY2xvc2VyIHRvIHRoZWlyIGhvbWUgY291bnRyeSBpZiB0aGV5IGhhaWwgZnJvbSBvdXRzaWRlIE5vcnRoIEFtZXJpY2EuIFdoaWxlIEkgdGhpbmsgdGhpcyBpcyBpbnRlcmVzdGluZywgSSB3b24ndCBiZSBkaWdnaW5nIGFueSBkZWVwZXIgYXMgdGhhdCBpcyBub3QgdGhlIGZvY3VzIG9mIHRoaXMgcHJvamVjdC4gQmFjayB0byB0aGUgYWdpbmcgY3VydmUgYW5hbHlzaXMhKSogICAgICAgICAgICAgDQoNCmBgYHtyLCBpbmNsdWRlPVRSVUV9DQpzdXJ2aXZlDQpgYGANCg0KVGhlIGdyYXBoIGFib3ZlIGxvb2tzIGF0IEdTL0cgcmVsYXRpdmUgdG8gYXZlcmFnZSBpbiBhIHBsYXllcidzIHJvb2tpZSB5ZWFyLCBicm9rZW4gZG93biBieSBhZ2UuIEF0IG5lYXJseSBldmVyeSBzaW5nbGUgaW5zdGFuY2UsIHN1cnZpdm9ycyBwbGF5ZWQgYmV0dGVyIHRoYW4gb25lLWFuZC1kb25lIHBsYXllcnM7IHRoZSBmZXcgaW5zdGFuY2VzIHdoZXJlIHRoZXkgZGlkbid0IGFyZSBtb3JlIGEgcmVzdWx0IG9mIG91dGxpZXJzIGFuZCB0aGUgc3BhcnNlIE5XSEwgZGF0YXNldCB0aGFuIGEgY29uY3JldGUgdHJlbmQuDQoNCioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0KDQojIFJlZ3Jlc3Npb24gTWV0aG9kcw0KDQpNb3Zpbmcgb24gZnJvbSB0aGUgZGVsdGEgbWV0aG9kLCBJIGFwcGxpZWQgdHdvIG1vZGVsaW5nIGFuZCByZWdyZXNzaW9uIHRlY2huaXF1ZXMgdG8gdmlzdWFsaXplIHRoZSBhZ2luZyBjdXJ2ZSBkaWZmZXJlbmNlLiAgICAgICAgICAgICAgICAgICANCg0KSSBzdGFydGVkIHdpdGggYSBzaW1wbGUgbGluZWFyIHJlZ3Jlc3Npb24gdGhhdCBsb29rcyBhdCB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gYWdlIGFuZCBnYW1lIHNjb3JlLiBJdCdzIGEgbW9kZWwgdGhhdCBwZXJmb3JtcyB3ZWxsIGJ5IGNlcnRhaW4gbWV0cmljcywgbm90YWJseSB3aXRoIGEgMC41ODEgUi1zcXVhcmVkLCB3aGlsZSBhZ2UgaGFzIGEgY29lZmZpY2llbnQgb2YgLTAuMDYsIGluZGljYXRpbmcgdGhhdCBldmVyeSB5ZWFyIGluY3JlYXNlIGluIGFnZSBzaG91bGQgY29ycmVzcG9uZCB3aXRoIGEgc2xpZ2h0IGRyb3AgaW4gR1MvRyByZWxhdGl2ZSB0byBhdmVyYWdlLiBIb3dldmVyLCB0aGUgc3RyYWlnaHQgZGVjbGluZSBpbiBHUy9HIGlzbid0IG11Y2ggb2YgYSBjdXJ2ZSBhbmQgZG9lc24ndCBtYWtlIHRvbyBtdWNoIHNlbnNlICh0aG91Z2ggdGhlIHByZW1pc2Ugb2YgeW91bmcgcGxheWVycyA+IG9sZGVyIHBsYXllcnMgaXMgYSBzaW1wbGUgYW5kIGRlZmVuc2libGUgb25lKS4NCg0KYGBge3IsIGVjaG89VFJVRSwgZXZhbD1GQUxTRSwgaW5jbHVkZT1UUlVFfQ0KbHIgPC0gbG0oZ2FtZV9zY29yZV9nYW1lIH4gYWdlX2luX3NlYXNvbiwgZGF0YSA9IG53aGwpDQpgYGANCg0KVGhlIHNlY29uZCBtZXRob2QgdGhhdCBJIHRlc3RlZCBvdXQgdXNlcyBhIEdlbmVyYWxpemVkIEFkZGl0aXZlIE1vZGVsIChHQU0pLCB3aGljaCBwcm9kdWNlcyBhIGN1cnZlZCBpbnN0YW5jZSBvZiBHUy9HIHJlbGF0aXZlIHRvIGFnZS4gVGhlIEdBTSBwcm9kdWNlcyBhIGN1cnZlIHRoYXQgc3RhcnRzIHNsaWdodGx5IGJlbG93IGF2ZXJhZ2UgaW4gYSBwbGF5ZXIncyBlYXJseSAyMHMgYmVmb3JlIHBlYWtpbmcgYXJvdW5kIDI0LTI2IHllYXJzIG9mIGFnZS4gQWZ0ZXIgdGhhdCBwZWFrLCBwZXJmb3JtYW5jZSBkZWNyZWFzZXMgYXMgYSBwbGF5ZXIgYWdlcywgYW4gZWZmZWN0IHRoYXQgYmVjb21lcyBtb3JlIHByb25vdW5jZWQgdGhlIG9sZGVyIGEgcGxheWVyIGlzLiAgICAgICAgICAgICAgDQoNCmBgYHtyLCBlY2hvPVRSVUUsIGV2YWw9RkFMU0UsIGluY2x1ZGU9VFJVRX0NCmdhbV9tb2RlbCA8LSBnYW0oZ2FtZV9zY29yZV9nYW1lIH4gSShhZ2VfaW5fc2Vhc29uIF4gMikgKyBhZ2VfaW5fc2Vhc29uLCANCiAgICAgICAgICAgICAgICAgZGF0YSA9IG53aGwsIHdlaWdodHMgPSBncCkNCmBgYA0KDQpJZiB5b3UgbG9vayBjbG9zZWx5IGF0IHRoZSBmb3JtdWxhcyBhYm92ZSwgeW91IG1heSBub3RpY2UgdGhhdCB0aGUgbGluZWFyIG1vZGVsIGRvZXMgbm90IGNvbnRhaW4gYSBzcXVhcmVkIGFnZSB0ZXJtIHdoaWxlIHRoZSBHQU0gZG9lcy4gSXQgaXMgcG9zc2libGUgdG8gcnVuIGEgbGluZWFyIG1vZGVsIHdpdGggdGhlIHNhbWUgc3F1YXJlZCB0ZXJtLCBob3dldmVyIHJ1bm5pbmcgdGhlIGxpbmVhciBtb2RlbCB3aXRoIGEgc3F1YXJlZCB0ZXJtIHdpbGwgcHJvZHVjZSBhIGN1cnZlIHRoYXQgaXMgc3ltbWV0cmljIG9uIGJvdGggc2lkZXMsIHdoaWxlIHRoZSBHQU0gZG9lcyBub3QgaGF2ZSB0aGF0IGlzc3VlLiBBcyB5b3Ugc2VlIG9uIHRoZSBncmFwaCBiZWxvdywgdGhlIGN1cnZlIGlzIG5vdCBzeW1tZXRyaWMgb24gZWFjaCBzaWRlLCBhcyB0aGUgb2xkLWFnZSBkZWNsaW5lIGlzIHNoYXJwZXIgdGhhbiB0aGUgeW91bmctYWdlIGluY3JlYXNlLiAgICAgICAgICAgICAgIA0KDQpUaGUgbGFzdCBsaW5lIG9uIHRoZSBncmFwaCAoaW4gdGhlIGJsdWUpIGlzIGEgc21vb3RoZWQgcGxvdCBvZiB0aGUgd2VpZ2h0ZWQgYXZlcmFnZSBvZiBHUy9HIChyZWxhdGl2ZSB0byBhdmVyYWdlKSBhdCBlYWNoIGFnZS4NCg0KYGBge3IsIGluY2x1ZGU9VFJVRX0NCnJlZ3JlZ3MNCmBgYA0KDQpUaGUgbW9kZWxlZCBjdXJ2ZSBjb250cmFkaWN0cyBzb21lIG9mIHRoZSBmaW5kaW5ncyBmcm9tIENhcmxpZSBhbmQgTWlrZSdzIHByb2plY3RzIGZvdW5kLCB3aGljaCBpbmRpY2F0ZWQgdGhhdCB0aGUgcGVyZm9ybWFuY2Ugb2Ygd29tZW4ncyBob2NrZXkgcGxheWVycyB0ZW5kZWQgdG8gcGVhayBlYXJseSBpbiB0aGVpciBjYXJlZXIsIGFyb3VuZCBhZ2VzIDIxLTIyLiBXaXRoIE1pa2UncyBOQ0FBIEQxIHByb2plY3QsIHRoYXQgbWFrZXMgc2Vuc2UgZ2l2ZW4gdGhhdCBtb3N0IHBsYXllcnMgdGVuZCB0byBhZ2Ugb3V0IG9mIGNvbGxlZ2UgYnkgYWdlIDIyLiAgICAgICAgICAgIA0KDQpDYXJsaWUncyBmaW5kaW5ncyB3ZXJlIGEgbGl0dGxlIG1vcmUgaW50ZXJlc3Rpbmcgc2luY2UgdGhlIENXSEwgZGF0YXNldCB0aGF0IHNoZSB1c2VkIGNvbnRhaW5lZCBwbGF5ZXJzIG9mIGFsbCBhZ2VzIGZyb20gMTUgdG8gNDIuIEhvd2V2ZXIsIGFzIHdpdGggdGhlIE5XSEwsIHBsYXllciBtb3ZlbWVudCBvdXQgb2YgdGhlIENXSEwgd2FzIGF1Z21lbnRlZCBieSBwbGF5ZXJzIHNvbWV0aW1lcyBsZWF2aW5nIHRoZSBsZWFndWUgYmVmb3JlIHRoZSBwb2ludCB3aGVyZSB0aGVpciBwZXJmb3JtYW5jZSBkaWN0YXRlZCBpdCBkdWUgdG8gdGhlIGxvd2VyIHNhbGFyaWVzLCBldGMuIFdoaWxlIHRoZSBhYm92ZSBjdXJ2ZSBpcyBkaWZmZXJlbnQgZnJvbSB0aGUgQ1dITCBhZ2luZyBwYXR0ZXJucywgdGhlIE5XSEwgY3VydmUgaXMgbXVjaCBtb3JlIHJlbWluaXNjZW50IG9mIHRoZSB0eXBpY2FsIHNwb3J0cyBhZ2luZyBjdXJ2ZS4gICAgICAgICAgICAgDQoNCk5vdywgd2hpbGUgdGhhdCBpcyByZWFzc3VyaW5nIGluIG9uZSBzZW5zZSwgaXQncyBpbXBvcnRhbnQgdG8gcmVtZW1iZXIgdGhhdCB3b21lbidzIHNwb3J0cyBhbmQgaG9ja2V5IGFyZSBkaWZmZXJlbnQgZnJvbSB0aGVpciBtYWxlIGNvdW50ZXJwYXJ0cy4gVGhlIGdvYWwgaGVyZSBpcyBub3QgdG8gcHJvZHVjZSBhbiBhZ2luZyBwYXR0ZXJuIHRoYXQgbWltaWNzIHRoZSBOSEwgcGF0dGVybnMgYnV0IHRvIHByb2R1Y2UgYW4gYWNjdXJhdGUgcmVwcmVzZW50YXRpb24gb2YgYWdpbmcgaW4gdGhlIE5XSEwuICAgICAgICAgICANCg0KRGVzcGl0ZSB0aGUgY29tcGxpY2F0aW9ucyBmYWNpbmcgTldITCBhZ2luZyBhbmFseXNpcywgSSBiZWxpZXZlIEkndmUgYWNjb21wbGlzaGVkIHRoYXQsIG9yIGF0IGxlYXN0IHRha2VuIGEgc3RlcCBmb3J3YXJkIHRvd2FyZHMgdW5kZXJzdGFuZGluZyBob3cgTldITCBza2F0ZXJzIGFnZS4gDQoNCioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0KDQojIE1BUkNFTCBQcm9qZWN0aW9ucw0KDQpJIGhhZCBwbGFubmVkIHRvIHdyYXAgbXkgcHJvamVjdCB1cCBhZnRlciBleHBsb3JpbmcgdGhlIGxpbmVhciBhbmQgR0FNIHJlZ3Jlc3Npb24gYXBwcm9hY2hlcy4gSG93ZXZlciwgSSBjb3VsZG4ndCByZXNpc3QgYXBwbHlpbmcgdGhlIGFnaW5nIGN1cnZlcyBpbiBhIGNvbmNyZXRlIGZhc2hpb24uICAgICAgICAgICAgIA0KDQpFbnRlciBOV0hMIE1BUkNFTCBQcm9qZWN0aW9ucyBmb3IgdGhlIDIwMjEtMjAyMiBzZWFzb24uICAgICAgICAgICAgICAgICANCg0KTUFSQ0VMIHByb2plY3Rpb25zIHdlcmUgZmlyc3QgaW50cm9kdWNlZCBpbiBbMjAwNCBieSBUb20gVGFuZ29dKGh0dHA6Ly93d3cudGFuZ290aWdlci5uZXQvYXJjaGl2ZXMvc3R1ZDAzNDYuc2h0bWwpIHRvIHByb3ZpZGUgYSBzdHJhaWdodGZvcndhcmQgd2F5IHRvIHByb2plY3QgZnV0dXJlIE1MQiBwcm9kdWN0aW9uIGFuZCBoYXZlIGJlZ3VuIHRvIHRyaWNrbGUgaW4gW2hvY2tleV0oaHR0cHM6Ly9vd250aGVwdWNrLndvcmRwcmVzcy5jb20vMjAxNS8wOS8wNS91c2luZy1tYXJjZWxzLXRvLWZvcmVjYXN0LXBsYXllci1wZXJmb3JtYW5jZS1pbi1ob2NrZXkvKSAodGhhdCBsaW5rIGlzIHN1cGVyIGhlbHBmdWwpLiAgICAgICAgICAgICAgICAgICAgICAgIA0KDQpNQVJDRUwgcHJvamVjdGlvbnMgYXJlIHN0cmFpZ2h0Zm9yd2FyZCBhbmQgcmVsYXRpdmVseSBzaW1wbGUuIFRoZXkgZXNzZW50aWFsbHkgd2VpZ2ggYSBwbGF5ZXIncyBwYXN0IHBlcmZvcm1hbmNlIGJ5IHRoZWlyIG1vc3QgcmVjZW50IHNlYXNvbnMsIHJlZ3Jlc3MgdGhlaXIgcGVyZm9ybWFuY2UgdG8gbGVhZ3VlIGF2ZXJhZ2UgKGJhc2VkIG9uIHBsYXlpbmcgdGltZSksIGFuZCwgZmluYWxseSwgYXBwbHkgYW4gYWdpbmcgYWRqdXN0bWVudC4gICAgICAgICAgICAgICAgICAgIA0KDQpUaGUgZmlyc3Qgc3RlcCBpcyB0byBkZXRlcm1pbmUgd2hhdCB0aGUgcmVsYXRpb25zaGlwIGlzIGJldHdlZW4gYSBwbGF5ZXIncyBwZXJmb3JtYW5jZSBhbmQgdGhlaXIgcGVyZm9ybWFuY2UgaW4gdGhlaXIgbGFzdCAxLCAyLCBhbmQgMyBzZWFzb25zLiBMb29raW5nIGF0IHRob3NlIGNvcnJlbGF0aW9ucyBwcm92aWRlcyB1cyB3aXRoIHRoZSB3ZWlnaHRzIHdlIHVzZSBmb3IgdGhvc2Ugc2Vhc29ucy4gICAgICAgICAgICAgICAgICAgICAgICAgIA0KDQpIb3dldmVyLCB3ZSBkb24ndCBoYXZlIHRoZSBOV0hMIGRhdGEgdG8gcHJvZHVjZSB0aG9zZSB3ZWlnaHRzIGR1ZSB0byB0aGUgb3ZlcmFsbCBsYWNrIG9mIGNvbnNlY3V0aXZlIGRhdGEuIEhvd2V2ZXIsIHRoZSBhZm9yZW1lbnRpb25lZCBDV0hMIGRhdGEgdGhhdCBDYXJsaWUgdXNlZCAqSVMqIGF2YWlsYWJsZS4gV2hpbGUgaXQncyBub3QgaWRlYWwgdG8gdXNlIG9uZSBsZWFndWUgdG8gZGV0ZXJtaW5lIHdlaWdodHMgZm9yIGEgZGlmZmVyZW50IGxlYWd1ZSwgdGhlIENXSEwgYW5kIE5XSEwgaGFkIHF1aXRlIGFuIG92ZXJsYXAgaW4gdGhlaXIgcGxheWVyIHBvb2xzIGFuZCBzaW1pbGFyIHRhbGVudCBsZXZlbHMuIEdpdmVuIHRoZSBvdmVyYWxsIGNvbnN0cmFpbnRzLCBpdCBpcyB3aGF0IGl0IGlzLiAgICAgICAgDQoNCkJ1dCB0aGVyZSdzIGEgcHJvYmxlbSEgICAgICAgICAgICAgIA0KDQpXZSBkb24ndCBoYXZlIEdhbWUgU2NvcmUgZm9yIHRoZSBDV0hMLCBzbyBob3cgZG8gd2UgZXZhbHVhdGUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIFllYXIgTi0xLCBOLTIsIGFuZCBOLTMgR2FtZSBTY29yZSBhbmQgY3VycmVudCBHYW1lIFNjb3JlPyBGb3J0dW5hdGVseSwgdGhlcmUncyBhIHN0cm9uZyByZWxhdGlvbnNoaXAgYmV0d2VlbiBnb2FscywgYXNzaXN0cywgYW5kIEdTIGluIHRoZSBOV0hMLCBzbyBJIGRlY2lkZWQgdG8gbW9kZWwgQ1dITCBnYW1lIHNjb3JlIHVzaW5nIHRoYXQgTldITCByZWxhdGlvbnNoaXAuICAgICAgICAgICAgICAgICAgDQoNClJ1bm5pbmcgYSBzaW1wbGUgbGluZWFyIG1vZGVsIHdpdGggR1MgYXMgYSBmdW5jdGlvbiBvZiBnb2FscyBhbmQgYXNzaXN0cyByZXR1cm5zIGEgc3RlbGxhciBhZGp1c3RlZCBSLXNxdWFyZWQgb2YgMC45NjUuIEkgdGhlbiB0b29rIGEgcmFuZG9tIHNhbXBsZSBvZiA1NzggQ1dITCBnYW1lIHNjb3JlIHNlYXNvbnMgKHRvIG1hdGNoIHRoZSBOV0hMIHRvdGFsKSBhbmQgY29tcGFyZWQgdGhlaXIgZGlzdHJpYnV0aW9ucyB0byBzZWUgaWYgdGhpbmdzIG1hZGUgc2Vuc2UuICAgICAgICAgICAgDQoNCmBgYHtyLCBpbmNsdWRlPVRSVUV9DQpnc19ncmFwaA0KYGBgDQoNClRoZSBhYm92ZSBncmFwaCBpbmRpY2F0ZXMgdGhhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIG15IG1vZGVsZWQgQ1dITCBnYW1lIHNjb3JlIG1ha2VzIHNlbnNlLiBVbnN1cnByaXNpbmdseSwgdGhlIENXSEwgR2FtZSBTY29yZXMgYXJlIG1vcmUgY29uY2VudHJhdGVkIGFyb3VuZCBhdmVyYWdlIGFuZCBkb24ndCBwcmVkaWN0IGFzIG1hbnkgc2NvcmVzIGluIHRoZSAwLjc1LTEuNSByYW5nZSAodGJoLCB0aGVyZSdzIHRoYXQgYnVtcCBhdCB+IDIgR1MvRywgYW5kIEkgaGF2ZSBubyBjbHVlIHdoeSwgYnV0IEkgZG9uJ3QgdGhpbmsgaXQncyBhIHByb2JsZW0pLiBOb3cgdGhhdCBJJ3ZlIGRldGVybWluZWQgdGhhdCBteSBtb2RlbGVkIENXSEwgR2FtZSBTY29yZSBpcyBub3QgdG9vIG91dGxhbmRpc2gsIEkgY2FuIG1vdmUgZm9yd2FyZCB3aXRoIHRoZSBNQVJDRUwgd29yay4gICAgICAgICAgICAgDQoNCmBgYHtyfQ0Kd2VpIDwtIHdlaWdodHMgJT4lDQogIGRwbHlyOjpzZWxlY3QoZWZmZWN0LCBuMV9nbXNjb3JlLCBuMl9nbXNjb3JlLCBuM19nbXNjb3JlLCBvdmVyYWxsKSAlPiUNCiAgbXV0YXRlKG4xX2dtc2NvcmUgPSByb3VuZChuMV9nbXNjb3JlLCBkaWdpdHMgPSAyKSwNCiAgICAgICAgIG4yX2dtc2NvcmUgPSByb3VuZChuMl9nbXNjb3JlLCBkaWdpdHMgPSAyKSwNCiAgICAgICAgIG4zX2dtc2NvcmUgPSByb3VuZChuM19nbXNjb3JlLCBkaWdpdHMgPSAyKSwNCiAgICAgICAgIGVmZmVjdCA9ICJHYW1lIFNjb3JlIFBlciBHYW1lIiwNCiAgICAgICAgIG92ZXJhbGwgPSByb3VuZChvdmVyYWxsLCBkaWdpdHMgPSAyKSkgJT4lDQogIGtuaXRyOjprYWJsZShjb2wubmFtZXMgPSBjKCJFZmZlY3QiLCAiTi0xIEdTIiwgIk4tMiBHUyIsICJOLTMgR1MiLCAiVG90YWwiKSwgYWxpZ24gPSAiY2NjY2MiKSAlPiUNCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRkFMU0UsIGMoInN0cmlwZWQiLCAiaG92ZXIiKSkNCmBgYA0KDQpgYGB7ciwgaW5jbHVkZT1UUlVFfQ0Kd2VpDQpgYGANCg0KQSBwbGF5ZXIncyBtb3N0IHJlY2VudCBzZWFzb24gcGxheXMgdGhlIGJpZ2dlc3QgcGFydCBpbiBwcmVkaWN0aW5nIHRoZWlyIGZ1dHVyZSBwZXJmb3JtYW5jZS4gQW5kIHBlcmZvcm1hbmNlIGluIHNlYXNvbnMgTi0yIGFuZCBOLTMgbWF0dGVyIGluIGRlY3JlYXNpbmcgb3JkZXIuIFNvLCBob3cgZG9lcyBvbmUgdHVybiB0aGlzIGludG8gYSBNQVJDRUwgcHJvamVjdGlvbj8NCg0KTGV0J3MgdGFrZSBNY0tlbm5hIEJyYW5kIG9mIHRoZSBCb3N0b24gUHJpZGUgYXMgYW4gZXhhbXBsZS4gQmVsb3cgYXJlIGhlciBzdGF0cyBmcm9tIGhlciBsYXN0IHRocmVlIHNlYXNvbnMsIGFzIHdlbGwgYXMgaG93IG1hbnkgZ2FtZXMgc2hlIHBsYXllZCBpbiBlYWNoIHNlYXNvbiAoanVzdCBhIHJlbWluZGVyIHRoYXQgSSBzY2FsZWQgdXAgaGVyIDIwMjAtMjAyMSBmcm9tIDcgZ2FtZXMgdG8gMjQgZ2FtZXMgYW5kIHRoYXQncyBoZXIgTi0xIHNlYXNvbikuDQoNCmBgYHtyfQ0KYnJhbmQgPC0gZXgxICU+JQ0KICBmaWx0ZXIocGxheWVyID09ICJNY0tlbm5hIEJyYW5kIikgJT4lDQogIG11dGF0ZShtYXJjZWwgPSByb3VuZCgoKGdhbWVfc2NvcmVfZ2FtZSAqIHkxKSArIChuMV9ncyAqIHkyKSArIChuMl9ncyAqIHkzKSkgLyBvdnIsIGRpZ2l0cyA9IDIpKSAlPiUNCiAgZHBseXI6OnNlbGVjdChwbGF5ZXIsIG5leHRfYWdlLCBtYXJjZWwsIGdhbWVfc2NvcmVfZ2FtZSwgZ3AsIG4xX2dzLCBuMV9ncCwgbjJfZ3MsIG4yX2dwKSAlPiUNCiAga25pdHI6OmthYmxlKGNvbC5uYW1lcyA9IGMoIlBsYXllciIsICJBZ2UgSW4gTmV4dCBTZWFzb24iLCAiTUFSQ0VMIiwgIk4tMSBHUy9HIiwgIk4tMSBHUCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOLTIgR1MvRyIsICJOLTIgR1AiLCAiTi0zIEdTL0ciLCAiTi0zIEdQIiksIGFsaWduID0gImNjY2NjY2NjIikgJT4lDQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFLCBjKCJzdHJpcGVkIiwgImhvdmVyIikpICU+JQ0KICByb3dfc3BlYygwLCBpdGFsaWMgPSBUUlVFKSAlPiUNCiAgYWRkX2hlYWRlcl9hYm92ZShjKCIgIiA9IDMsICJTZWFzb24gTi0xIiA9IDIsICJTZWFzb24gTi0yIiA9IDIsICJTZWFzb24gTi0zIiA9IDIpKQ0KYGBgDQoNCmBgYHtyLCBpbmNsdWRlPVRSVUV9DQpicmFuZA0KYGBgDQoNCkhlcmUncyBob3cgSSBkZXJpdmVkIGFuIGluaXRpYWwgTUFSQ0VMIHByb2plY3Rpb24gd2l0aCB0aGUgZ2l2ZW4gd2VpZ2h0czoNCg0KJCQgTUFSQ0VMID0gKCgxLjE5ICogMC42MikgKyAoMS45ICogMC4yOSkgKyAoMS4yNSAqIDAuMikpIC8gMS4xMSAkJA0KDQpUaGUgZm9ybXVsYSBwcm9kdWNlcyBhIHByb2plY3RlZCBnYW1lIHNjb3JlIG9mIDEuMzksIHBhcnR3YXkgYmV0d2VlbiBCcmFuZCdzIEdTL0cgaW4gMjAyMC0yMDIxIGFuZCAyMDE5LTIwMjAuIFBhc3NlcyB0aGUgc21lbGwgdGVzdCEgQnV0IHRoZXJlJ3Mgc3RpbGwgbW9yZSB3ZSBjYW4gZG8gdG8gZnVydGhlciB0aGlzIHByb2plY3Rpb24uICAgICAgICAgICAgICAgICAgDQoNClN0ZXAgMiAob3IgdGVjaG5pY2FsbHkgbGlrZSBzdGVwIDYgYXQgdGhpcyBwb2ludCBpZiB3ZSdyZSBiZWluZyBob25lc3QsIGJ1dCBpcyBhbnlvbmUgKnJlYWxseSogY291bnRpbmc/KSBpcyB0byByZWdyZXNzIHByb2plY3RlZCBwZXJmb3JtYW5jZSB0byBhdmVyYWdlIEdTL0cgdG8gZW5zdXJlIHRoYXQgd2UgZG9uJ3Qgb3ZlcnJhdGUgb3V0bGllciBzZWFzb25zLiBUbyBkbyB0aGF0LCBJIGFzc3VtZSB0aGUgcHJvamVjdGVkIDEuMzkgR1MvRyBjb21lcyBvdmVyIDI0IGdhbWVzIGFuZCB0aGVuIGFkZCBhYm91dCAzIChhY3R1YWxseSAyLjk0KSBnYW1lcyB3b3J0aCBvZiBsZWFndWUgYXZlcmFnZSBwbGF5IChhIDAuNTkgR1MvRykuIFdlIGRldGVybWluZSB0aGUgYXZlcmFnZSBnYW1lcyB0byBhZGQgYnkgY29tcGFyaW5nIHRoZSB0cnVlIGF2ZXJhZ2UgR1MvRywgYW5kIHRoZSBpbml0aWFsIHByZWRpY3RlZCBHUy9HIChzaW5jZSB0aGF0IGhhcyBubyByZWdyZXNzaW9uIHRvIHRoZSBtZWFuIHlldCksIGFuZCBob3cgdGhleSByZWxhdGUgdG8gdGhlIGF2ZXJhZ2UgZ2FtZXMgcGxheWVkLiAgICAgICAgDQoNCkluIHRoZSBlcXVhdGlvbiBiZWxvdywgMTcuMzIgaXMgdGhlIGF2ZXJhZ2UgZ2FtZXMgcGxheWVkLCB3aGlsZSAwLjg1NSBjb21lcyBmcm9tIGEgY29tcGFyaXNvbiBvZiBhY3R1YWwgYW5kIHByZWRpY3RlZCBHUy9HLiBXaGlsZSB0aGUgdHJ1ZSBhdmVyYWdlIEdTL0cgaW4gMjAyMSB3YXMgMC41OSwgdGhlIGF2ZXJhZ2UgcHJlZGljdGVkIEdTL0cgaXMgMC42OSAob3IgODUuNSUgb2YgdGhhdCBwcmVkaWN0ZWQgcGVyZm9ybWFuY2UpLiAgICAgICAgICAgICAgICAgDQoNCiQkIEdhbWVzID0gYXZnR1AgKiAoKDEgLSBkaWZmZXJlbmNlKSAvIGRpZmZlcmVuY2UpICQkDQokJCBHYW1lcyA9IDE3LjMyICogKCgxIC0gMC44NTUpIC8gMC44NTUpICQkDQoNClNvbHZlIHRoYXQsIGFuZCBpdCBjb21lcyBvdXQgdG8gMi45NCBnYW1lcyBvZiBhdmVyYWdlIHByb2R1Y3Rpb24gdG8gYWRkLiBUaGUgZm9ybXVsYSBiZWxvdyByZXByZXNlbnRzIGFkZGluZyBpbiB0aGUgZ2FtZXMgb2YgYXZlcmFnZSBwcm9kdWN0aW9uLCByZXN1bHRpbmcgaW4gYSByZWdyZXNzZWQgcHJvamVjdGlvbiBvZiAxLjMwIGZvciBNY0tlbm5hIEJyYW5kLiAgICAgICAgICAgICAgICAgICANCg0KJCQgUmVncmVzc2VkID0gKCgxLjM5ICogMjQpICsgKDIuOTQgKiAwLjU5KSkgLyAoMjQgKyAyLjk0KSAkJA0KDQpMYXN0IGJ1dCBub3QgbGVhc3QsIHdlIGFkZCBpbiBhIHNpbXBsZSBhZ2luZyBlZmZlY3QuIFRha2luZyB0aGUgR0FNIGN1cnZlIHRoYXQgSSBwcm9kdWNlZCBlYXJsaWVyLCBJIHBhaXJlZCBiYWNrLXRvLWJhY2sgYWdlcyB0b2dldGhlciB0byBmaWd1cmUgb3V0IHdoYXQgdGhlIGVmZmVjdCBvZiBpbmNyZWFzaW5nIGFnZSBoYWQgb24gR1MvRy4gRm9yIGV4YW1wbGUsIHNpbmNlIE1jS2VubmEgQnJhbmQgaXMgZ29pbmcgZnJvbSAyNCB0byAyNSB5ZWFycyBvbGQsIHdlJ2QgZXhwZWN0IGhlciBHUy9HIHRvIGluY3JlYXNlIGJ5IDAuMDE1IChzbWFsbCBkaWZmZXJlbmNlcywgYnV0IGhleSwgaXQgaXMgd2hhdCBpdCBpcykuICAgICAgICAgICAgICANCg0KQWxsIHRvbGQsIE1jS2VubmEgQnJhbmQncyBmaW5hbCBwcm9qZWN0ZWQgR1MvRyBjb21lcyBvdXQgdG8gMS4zMSwgdGhlIHRoaXJkLWhpZ2hlc3QgbWFyayBiZWhpbmQgTWlreWxhIEdyYW50LU1lbnRpcyBhbmQgQnJhbmQncyB0ZWFtbWF0ZSwgSmlsbGlhbiBEZW1wc2V5LiAgICAgICAgICAgICAgIA0KDQpCcmFuZCBtYWRlIGEgZ29vZCBleGFtcGxlIGhlcmUgYmVjYXVzZSBzaGUncyBwbGF5ZWQgdGhyZWUgc2Vhc29ucyBpbiBhIHJvdyBpbiB0aGUgTldITC4gQnV0IG5vdCBldmVyeSBwbGF5ZXIgaGFzIHBsYXllZCB0aGF0IG1hbnkgc2Vhc29ucy4gRm9yIHBsYXllcnMgd2l0aCB0d28geWVhcnMgb2YgTldITCBwbGF5ICh0aGluayBNaWt5bGEgR3JhbnQtTWVudGlzKSwgdGhlIHN5c3RlbSB0YWtlcyBqdXN0IGhlciB0d28gc2Vhc29ucyBpbnRvIGNvbnNpZGVyYXRpb24sIHdlaWdodGluZyBieSB0aGUgc2FtZSB3ZWlnaHRzIGFzIGVhcmxpZXIgKE4tMSBhcyAwLjYyIGFuZCBOLTIgYXMgMC4yOSwgYWxsIG92ZXIgMC45MSkuICAgICAgICAgICANCg0KRm9yIHBsYXllcnMgd2l0aCBqdXN0IG9uZSBzZWFzb24sIEkgYWRkIGEgInNlY29uZCIgc2Vhc29uIHRvIHRoZWlyIGxpbmUuIFRoZSBmYWtlIHNlYXNvbiBpcyB0aGVpciB5ZWFyIG9mIHBsYXkgaGVhdmlseSByZWdyZXNzZWQgdG8gYXZlcmFnZSB3aXRoIGEgbmVnYXRpdmUgZmFjdG9yIGFwcGxpZWQgYmFzZWQgb24gdGhlaXIgc2Vhc29uIG9mIHBsYXkuIFRoZSBuZWdhdGl2ZSBmYWN0b3IgaXMgaW50ZW5kZWQgdG8ga2VlcCB0aGUgc3lzdGVtIGZyb20gb3ZlcnJhdGluZyBwbGF5ZXJzIHdob3NlIHNpbmdsZSBzZWFzb24gd2FzIHBvb3IgaW4ganVzdCBhIGNvdXBsZSBvZiBnYW1lcyAod2hlbiByZWdyZXNzaW5nIHRvIGF2ZXJhZ2UsIGl0IHdvdWxkIHB1bGwgdGhvc2Ugc2Vhc29ucyB0b28gY2xvc2UgdG8gYXZlcmFnZSkuICAgICAgICANCg0KVGhlIG5hbWVzIHRoYXQgcG9wdWxhdGUgdGhlIHRvcCBvZiB0aGUgYm9hcmQgYXJlIHRoZSBvbmVzIHRoYXQgd2UnZCBleHBlY3QuIFRoZSByZWlnbmluZyBNVlAsIE1pa3lsYSBHcmFudC1NZW50aXMsIHRvcHMgdGhlIHByb2plY3Rpb25zIHdpdGggaGVyIGdhbWUgc2NvcmUgb2YgMS45MSAodGhvdWdoLCB0byBiZSBob25lc3QsIEkgYmV0IHNoZSBvdXRwZXJmb3JtcyB0aGF0KS4gU3RhbHdhcnQgc3VwZXJzdGFyIEppbGxpYW4gRGVtcHNleSBjb21lcyBpbiBzZWNvbmQgcGxhY2UgYXQgMS42NSwgdGhlbiBNY0tlbm5hIEJyYW5kLCBmb2xsb3dlZCBieSB0aGVpciBCb3N0b24gUHJpZGUgdGVhbW1hdGUgQ2hyaXN0aW5hIFB1dGlnbmEgYW5kIGhlciAxLjI5IHByZWRpY3Rpb24uICAgICAgICAgICAgICAgICAgICAgDQoNCkhvd2V2ZXIsIHRoZSBzeXN0ZW0gaXNuJ3QgYnV5aW5nIHN0cm9uZyBzZWFzb25zIGZyb20gYSBmZXcgcGxheWVycywgbm90YWJseSBOaW5hIFJvZ2VycywgRW1tYSBXb29kcywgYW5kIEJyb29rZSBCb3F1aXN0LCB0aG91Z2ggSSdkIHByb2JhYmx5IGRpc2FncmVlIHdpdGggdGhlIHN5c3RlbSBvbiB0aGVtLiBUaGV5IGFyZSBhbGwgaW4gdGhhdCAyNC0yNiBzd2VldCBzcG90IGFuZCAoZm9yIFdvb2RzIGFuZCBCb3F1aXN0KSBoYXZlIDEgc2Vhc29uIHBsYXllZCwgcmVzdWx0aW5nIGluIHRoZWlyICJmYWtlIHNlY29uZCBzZWFzb24iIHRoYXQgaXMgaGVhdmlseSByZWdyZXNzZWQgdG8gbGVhZ3VlIGF2ZXJhZ2UuIEdpdmVuIHRoYXQgdGhleSBwcm9kdWNlIHNvIHdlbGwgaW4gdGhlaXIgcm9va2llIHNlYXNvbiBhbmQgYXJlIGluIHRoZWlyICpwcmltZSosIEknZCBiZXQgb24gdGhlaXIgcGVyZm9ybWFuY2UgbWFpbnRhaW5pbmcgaXRzIDIwMjEgbGV2ZWwgb3IgZXZlbiBpbXByb3ZpbmcuICAgICAgICAgICANCg0KVGhlIG1vZGVsIGRvZXMgcGVuYWxpemUgcGxheWVycyBsaWtlIEFseXNzYSBXb2hsZmVpbGVyIChlbnRlcmluZyBoZXIgYWdlLTMyIHNlYXNvbiksIHByb2plY3RpbmcgaGVyIGZvciBhIC0wLjIwIGRlY3JlYXNlIGluIEdhbWUgU2NvcmUvR2FtZSwgdGhlIGVpZ2h0aC1sYXJnZXN0IGRyb3AgaW4gdGhlIGxlYWd1ZS4gT24gdGhlIGZsaXAgc2lkZSwgQWxsaWUgVGh1bnN0cm9tIChlbnRlcmluZyBoZXIgYWdlLTMzIHNlYXNvbikgaXMgZXhwZWN0ZWQgdG8gcmVib3VuZCBmcm9tIGEgdG91Z2ggMC4wOSBHUy9HIGluIDIwMjEgYW5kIHJldHVybiB0byBiZWluZyBhbiBhYm92ZS1hdmVyYWdlIHNrYXRlci4gICAgICAgICAgICAgICANCg0KQSBsb3QgaXMgZ29pbmcgb24gaW4gdGhlc2UgcHJvamVjdGlvbnMgYW5kIEkgd291bGQgcmVjb21tZW5kIGNoZWNraW5nIHRoZW0gb3V0IGluIHRoZSB0YWJsZSBiZWxvdyBhbmQgc2VlaW5nIHdoYXQgc3RpY2tzIG91dCB0byB5b3UhICAgICAgICAgICAgIA0KDQpBZ2luZyBpbiBzcG9ydCwgZXNwZWNpYWxseSB3b21lbidzIHNwb3J0cywgaXMgYSBoYXJkIHByb2JsZW0gdG8gYXR0YWNrIGRlc3BpdGUgdGhlIGFuYWx5c2lzIHRoYXQgdW5kZXJzdGFuZGluZyBhZ2luZyBmYWNpbGl0YXRlcy4gSG9wZWZ1bGx5LCB0aHJvdWdoIG15IHByZXNlbnRhdGlvbiBhbmQgd3JpdGV1cCwgSSd2ZSBoZWxwZWQgcHJvdmlkZSBhIGZyYW1ld29yayB0byB2aWV3IGFnaW5nIHVzaW5nIHRoZSBkZWx0YSBhbmQgcmVncmVzc2lvbiBtZXRob2RzLCBidWlsZGluZyBvbiBwcmV2aW91c2x5IGNvbXBsZXRlZCB3b3JrIGluIHRoZSB3b21lbidzIGhvY2tleSBzcGhlcmUuICAgICAgICAgICAgICAgDQoNCmBgYHtyfQ0KcGxheSA8LSBud2hsZGYgJT4lDQogIGRwbHlyOjpzZWxlY3QocGxheWVyLCBzZWFzb25zKSAlPiUNCiAgZGlzdGluY3QoKQ0KDQpyZXN1bHRzIDwtIHJlc3VsdHMgJT4lIA0KICBsZWZ0X2pvaW4ocGxheSwgYnkgPSBjKCJwbGF5ZXIiKSkNCg0KcmVzdWx0cyA8LSByZXN1bHRzICU+JQ0KICBtdXRhdGUoZGlmZmVyZW5jZSA9IG1hcmNlbF9wcmVkaWN0aW9uIC0gZ2FtZV9zY29yZV9nYW1lLA0KICAgICAgICAgZDIgPSBtYXJjZWxfcHJlZGljdGlvbiAtIGFnZV9wcmVkKQ0KDQpleDEgPC0gZXgxICU+JQ0KICBsZWZ0X2pvaW4ocGxheSwgYnkgPSBjKCJwbGF5ZXIiKSkNCg0KcmVzIDwtIHJlc3VsdHMgJT4lDQogIGRwbHlyOjpzZWxlY3QocGxheWVyLCBuZXh0X2FnZSwgZ2FtZV9zY29yZV9nYW1lLCBtYXJjZWxfcHJlZGljdGlvbikNCg0KbWluIDwtIC0wLjA3DQptYXggPC0gMi4xNA0KDQptYWtlX2NvbG9yX3BhbCA8LSBmdW5jdGlvbihjb2xvcnMsIGJpYXMgPSAxKSB7DQogIGdldF9jb2xvciA8LSBjb2xvclJhbXAoY29sb3JzLCBiaWFzID0gYmlhcykNCiAgZnVuY3Rpb24oeCkgcmdiKGdldF9jb2xvcih4KSwgbWF4Q29sb3JWYWx1ZSA9IDI1NSkNCn0NCg0KY29sb3IgPC0gbWFrZV9jb2xvcl9wYWwoYygiI2M2MmYyZCIsICIjY2M3YTY0IiwgIiNmN2NlYzMiLCAiI2Y3ZTRkZiIsICIjRkZGRUZFIiwgIiM1YmUwNGYiLCAiIzM4ODIyMyIpLCBiaWFzID0gMikNCg0KdGFiIDwtIHJlcyAlPiUNCiAgbXV0YXRlKENoYW5nZSA9IHJvdW5kKG1hcmNlbF9wcmVkaWN0aW9uIC0gZ2FtZV9zY29yZV9nYW1lLCBkaWdpdHMgPSAyKSkgJT4lDQogIGFycmFuZ2UoZGVzYyhtYXJjZWxfcHJlZGljdGlvbikpICU+JQ0KICByZWFjdGFibGUocGFnaW5hdGlvbiA9IEZBTFNFLA0KICAgIGhpZ2hsaWdodCA9IFRSVUUsDQogICAgc3RyaXBlZCA9IFRSVUUsDQogICAgZGVmYXVsdENvbERlZiA9IGNvbERlZigNCiAgICBhbGlnbiA9ICJjZW50ZXIiLCBtaW5XaWR0aCA9IDI1LCBoZWFkZXJDbGFzcyA9ICJoZWFkZXIiLCBoZWFkZXJTdHlsZSA9IGxpc3QoZm9udFdlaWdodCA9IDcwMCkNCiAgKSwNCiAgY29sdW1uR3JvdXBzID0gbGlzdCgNCiAgICBjb2xHcm91cChuYW1lID0gIlBsYXllciBJbmZvIiwgY29sdW1ucyA9IGMoInBsYXllciIsICJuZXh0X2FnZSIpKSwNCiAgICBjb2xHcm91cChuYW1lID0gIlJlc3VsdHMiLCBjb2x1bW5zID0gYygiZ2FtZV9zY29yZV9nYW1lIiwgIm1hcmNlbF9wcmVkaWN0aW9uIiwgIkNoYW5nZSIpDQogICkpLA0KICB0aGVtZSA9IHJlYWN0YWJsZVRoZW1lKA0KICAgIGhlYWRlclN0eWxlID0gbGlzdCgNCiAgICAgICImOmhvdmVyW2FyaWEtc29ydF0iID0gbGlzdChiYWNrZ3JvdW5kID0gImhzbCgwLCAwJSwgOTYlKSIpLA0KICAgICAgIiZbYXJpYS1zb3J0PSdhc2NlbmRpbmcnXSwgJlthcmlhLXNvcnQ9J2Rlc2NlbmRpbmcnXSIgPSBsaXN0KGJhY2tncm91bmQgPSAiaHNsKDAsIDAlLCA5NiUpIiksDQogICAgICBib3JkZXJDb2xvciA9ICIjNTU1Ig0KICAgICkpLA0KICBjb2x1bW5zID0gbGlzdCgNCiAgICBwbGF5ZXIgPSBjb2xEZWYoDQogICAgICBuYW1lID0gIlBsYXllciIsDQogICAgICBjbGFzcyA9ICJib3JkZXItbGVmdCINCiAgICApLA0KICAgIG5leHRfYWdlID0gY29sRGVmKA0KICAgICAgbmFtZSA9ICJOZXh0IEFnZSINCiAgICApLA0KICAgIGdhbWVfc2NvcmVfZ2FtZSA9IGNvbERlZigNCiAgICAgIG5hbWUgPSAiMjAyMSBHYW1lIFNjb3JlIg0KICAgICksDQogICAgQ2hhbmdlID0gY29sRGVmKA0KICAgICAgbmFtZSA9ICJDaGFuZ2UiDQogICAgKSwNCiAgICBtYXJjZWxfcHJlZGljdGlvbiA9IGNvbERlZigNCiAgICAgIG5hbWUgPSAiTUFSQ0VMIDIwMjIgR1MvRyIsDQogICAgICBzdHlsZSA9IGZ1bmN0aW9uKHZhbHVlKSB7DQogICAgICAgIHZhbHVlDQogICAgICAgIG5vcm1hbGl6ZWQgPC0gKHZhbHVlIC0gbWluKSAvIChtYXggLSBtaW4pDQogICAgICAgICNub3JtYWxpemVkIDwtICh2YWx1ZSAtIG1pbihwaXRjaF90eXBlJFJWMTAwKSkgLyAobWF4KHBpdGNoX3R5cGUkUlYxMDApIC0gbWluKHBpdGNoX3R5cGUkUlYxMDApKQ0KICAgICAgICBjb2xvciA8LSBjb2xvcihub3JtYWxpemVkKQ0KICAgICAgICBsaXN0KGJhY2tncm91bmQgPSBjb2xvcikNCiAgICAgIH0NCiAgICApKSkNCmBgYA0KDQpgYGB7Y3NzfQ0KLnRpdGxlIHsNCiAgbWFyZ2luOiAxOHB4IDBweDsNCiAgZm9udC1zaXplOiAxNnB4Ow0KfQ0KDQouYm9yZGVyLWxlZnQgew0KICBib3JkZXItbGVmdDogMnB4IHNvbGlkICM1NTU7DQp9DQoNCi50aXRsZSBoMiB7DQogIGZvbnQtc2l6ZTogMjBweDsNCiAgZm9udC13ZWlnaHQ6IDYwMDsNCn0NCg0KLnN1YnRpdGxlIHsNCiAgbWFyZ2luOiAxOHB4IDBweDsNCiAgZm9udC1zaXplOiAzcHg7DQp9DQoNCi5zdWJ0aXRsZSBoMiB7DQogIGZvbnQtc2l6ZTogMTRweDsNCiAgI2ZvbnQtd2VpZ2h0OiAxMDA7DQp9DQoNCi8qIEFsaWduIGhlYWRlciB0ZXh0IHRvIHRoZSBib3R0b20gKi8NCi5oZWFkZXIsDQouZ3JvdXAtaGVhZGVyIHsNCiAgZGlzcGxheTogZmxleDsNCiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjsNCiAganVzdGlmeS1jb250ZW50OiBmbGV4LWVuZDsNCn0NCg0KLmhlYWRlciB7DQogIGJvcmRlci1ib3R0b20tY29sb3I6ICM1NTU7DQogIGZvbnQtc2l6ZTogMTNweDsNCiAgZm9udC13ZWlnaHQ6IDQwMDsNCiAgI3RleHQtdHJhbnNmb3JtOiB1cHBlcmNhc2U7DQp9DQoNCi8qIEhpZ2hsaWdodCBoZWFkZXJzIHdoZW4gc29ydGluZyAqLw0KLmhlYWRlcjpob3ZlciwNCi5oZWFkZXJbYXJpYS1zb3J0PSJhc2NlbmRpbmciXSwNCi5oZWFkZXJbYXJpYS1zb3J0PSJkZXNjZW5kaW5nIl0gew0KICBiYWNrZ3JvdW5kLWNvbG9yOiAjZWVlOw0KfQ0KDQouc3RhbmRpbmdzIHsNCiAgZm9udC1mYW1pbHk6IEthcmxhLCAiSGVsdmV0aWNhIE5ldWUiLCBIZWx2ZXRpY2EsIEFyaWFsLCBzYW5zLXNlcmlmOw0KICBmb250LXNpemU6IDE0cHg7DQp9DQpgYGANCg0KKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqDQoNCiMgMjAyMiBOV0hMIFByb2plY3RlZCBHYW1lIFNjb3Jlcw0KDQpgYGB7ciwgaW5jbHVkZT1UUlVFfQ0KdGFiDQpgYGANCg0KKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKio=