Methodology
As what we’re interested in is a team’s overall performance and the data set that we’re looking at is structured in terms of each individual player’s performance, our first hurdle we had to jump over was getting the data set into a more workable form for what we’ve set out to achieve.
The first thing we did was deleted columns we deemed would be necessary going forward in our analysis; the obvious candidates to go were ‘Player’ and ‘Percent Played’ as they’d be useless once we combined everything to be in terms of any teams not players. However, slightly less obvious variables that we removed were ‘FreesAgainst’ and ‘Uncontested Possessions.’ We did this is because our once one teams statistics are put against another teams statistics for comparison one team’s ‘FreesFor’ would be exactly the same as the opposing team, and vise versa (same thing for Contested vs Uncontested Possessions). So, to prevent future problems and clutter we deleted these four columns completely from our data set.
AFL <- AFLstats
AFL <- AFL[c(1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,25,27,28,29,30,31)]
#colnames(AFL)
The next logical step in our methodology was to actually split our data set into the different teams total games as that’s what we’re most interested in, how well one team would perform against any other.
all_teams <- unique(as.character(AFL$Team))
ad <- AFL[AFL$Team == all_teams[1],]
bl <- AFL[AFL$Team == all_teams[2],]
clt <- AFL[AFL$Team == all_teams[3],]
clwd <- AFL[AFL$Team == all_teams[4],]
esdn <- AFL[AFL$Team == all_teams[5],]
fd <- AFL[AFL$Team == all_teams[6],]
glng <- AFL[AFL$Team == all_teams[7],]
gc <- AFL[AFL$Team == all_teams[8],]
gws <- AFL[AFL$Team == all_teams[9],]
ht <- AFL[AFL$Team == all_teams[10],]
mlb <- AFL[AFL$Team == all_teams[11],]
nmlb <- AFL[AFL$Team == all_teams[12],]
pad <- AFL[AFL$Team == all_teams[13],]
rmd <- AFL[AFL$Team == all_teams[14],]
sk <- AFL[AFL$Team == all_teams[15],]
syd <- AFL[AFL$Team == all_teams[16],]
wc <- AFL[AFL$Team == all_teams[17],]
wb <- AFL[AFL$Team == all_teams[18],]
After this had been done we still faced the problem that our data is in terms of rows of player statistics, and not rows of total game statistics. Through rigorous trial and error we created a nice, neat function which cleans all the data by wrangling it into the form we want it to be in (total statistics for any given game). It is also important to note that only five of the total games in the data set resulted in a draw (shown below), so in an effort so simplify our the data we decided it would be best to just remove these cases (this occurs within the cleaning function).
# players which were part of a tie game / number of players in team / number of teams in a match
nrow(AFL[AFL$WinLoss == "D",]) / 22 / 2
[1] 5
This is the function which ‘cleans’ our data. It essential takes the first nine columns and takes one copy of the information there as it’s unique to each match. The remaining columns are player statistics so they are just summed together with all the other similar variables within any match to get the data into the form we want it to be in. As mentioned before, the games that were tied were removed from the data set in this step.
cleanAFLdata <- function(team){
library(plyr)
team_stats <- ddply(team, .(Date), numcolwise(sum))
team_stats <- team_stats[c(1,5:23)]
team_keep <- team[match(unique(team$Date), team$Date),]
team_keep <- team_keep[1:9]
team_clean <- merge(team_keep, team_stats)
team_clean <- team_clean[team_clean$WinLoss != "D",]
team_clean$WinLoss <- droplevels(team_clean$WinLoss)
levels(team_clean$WinLoss)[levels(team_clean$WinLoss)=="L"] <- 0
levels(team_clean$WinLoss)[levels(team_clean$WinLoss)=="W"] <- 1
team_clean$WinLoss <- factor(team_clean$WinLoss)
return(team_clean)
}
ad_clean <- cleanAFLdata(ad)
bl_clean <- cleanAFLdata(bl)
clt_clean <- cleanAFLdata(clt)
clwd_clean <- cleanAFLdata(clwd)
esdn_clean <- cleanAFLdata(esdn)
fd_clean <- cleanAFLdata(fd)
glng_clean <- cleanAFLdata(glng)
gc_clean <- cleanAFLdata(gc)
gws_clean <- cleanAFLdata(gws)
ht_clean <- cleanAFLdata(ht)
mlb_clean <- cleanAFLdata(mlb)
nmlb_clean <- cleanAFLdata(nmlb)
pad_clean <- cleanAFLdata(pad)
rmd_clean <- cleanAFLdata(rmd)
sk_clean <- cleanAFLdata(sk)
syd_clean <- cleanAFLdata(syd)
wc_clean <- cleanAFLdata(wc)
wb_clean <- cleanAFLdata(wb)
After going through all this effort to split the data to be in terms of separate teams it actually meant that for each team we only had a very small set of data points. This made any prediction models for each individual team impossible as the training set (2012 - 2015) only had roughly 100 rows and our test set (2016) only had about 25 rows; which R didn’t think was enough data for the predictive models we wanted to do. So we ended up just combining everything back into one nice big data set (after being cleaned).
AFL_clean <- rbind(ad_clean, bl_clean, clt_clean, clwd_clean, esdn_clean, fd_clean, glng_clean,
gc_clean, gws_clean, ht_clean, mlb_clean, nmlb_clean, pad_clean, rmd_clean,
sk_clean, syd_clean, wc_clean, wb_clean)
#length(unique(AFL_clean$Team))
Once our data was once again in one big, combined data frame we decided (and R accepted our decision) it was finally time to successfully split our data into a separate training and test set. It made sense for our training set to be all the games in 2012 - 2015 (inclusive) and then our test set to be just the matches played in the latest (in our data set) 2016 season. This made sense as our goal is to predict the current (2017) matches so having our test set being the closest to that as possible meant our predictive models would (in theory) ‘tune’ our model to be as accurate for the current season as we could hope for.
AFL.test <- AFL_clean[AFL_clean$Season == 2016,]
#head(AFL.test)
AFL.train <- AFL_clean[AFL_clean$Season != 2016,]
#head(AFL.train)
Next we decided to do a little exploratory analysis of our training set, this was to make sure everything makes logical sense (check we haven’t made an error during our cleaning process), and just to explore the data and see if we can find anything interesting.
plot(AFL.train$WinLoss, AFL.train$Disposals)

plot(AFL.train$WinLoss, AFL.train$Inside50s)

plot(AFL.train$WinLoss, AFL.train$Clearances)

From these few plots we can see that our data looks to be intact, as we actually got given functional box plots as outputs. And more importantly it seems that at least some of these variables have some sort of a correlation with teams who’ve won (1) and teams who’ve lost (0). This meant that some of our variables might be strong candidates in being able to assistance us in predicting the outcomes of future games.
As a second measure to this process we created a correlation coefficient histogram matrix with all of our variables to see if anything had a particularly strong correlation with our ‘WinLoss’ variable.
source("PairsWithHist.R")
pairs(AFL_clean, lower.panel = panel.pts, upper.panel = panel.cor, diag.panel = panel.hist)
Our next step was to actually begin preparing to make some predictive models; which wasn’t just as simple as fitting a model with all the variables and then fitting another model with none, and then running forward selection between the two (although that was one step within the process). After some trial and error and thought into what we were actually doing some things became clear; we had too many variables and some variables just didn’t make sense being in our model(s).
To reduce our total amount of variables we first removed all the categorical explanatory variables. Our reason for doing this is that each level of a factor variable within a predictive model becomes its own variable, not just the one factor variable itself. For example, by including the factor variable ‘Venue’ we are introducing is 19 new explanatory variables into our model, not simply just venue.
The next problem was that the ‘Margin’ variable was a perfect predictor of whether a team would win or lose. If the margin for a game was greater than zero the team had won, if the margin was negative then the team had lost. By including this in our model it would have had such a strong correlation that all the other variables, which are arguably more useful for our overall goal, would be lost as noise; so we had to remove it.
Variables like ‘Score’ and ‘Goals’ were in a similar sort of boat because teams who win are always going to have a higher score, because that’s how you win the game. This is such a basic premise that it really made no sense to include in our model as it was just adding noise. And the last set of variables we didn’t include in our model were ‘Handballs’ and ‘Kicks’ as they are just subsets of the ‘Disposal’ variable, making it pointless to include all three within our model.
After all of these ‘types’ of variables were excluded from our model we were left with what we with the majority of the integer match statistics like ‘Disposals,’ ‘Inside50s,’ ‘Clangers,’ etc.
# just 'numerical' variables
AFL.glm.num <- glm(WinLoss ~ Disposals + Marks + Behinds + Inside50s + Clearances + Clangers + ContendedPossessions + ContestedMarks + MarksInside50,
data = AFL.train, family = binomial(logit))
Then we set up a model with no explanatory variables.
AFL.glm.0 <- glm(WinLoss ~ 1, data = AFL.train, family = binomial(logit))
And finally we compared these two models to find the optimal set of variables we should be including in our final model. Which by looking at the summary below you might have noticed left us with seven explanatory variables in our final model; removing ‘ContestedMarks’ and ‘Behinds’ as forward selection didn’t find them relevant.
All the variables left in the model also have very small p-values which is always a good sign that they could be highly correlated to the response variable (winning a match).
AFL.glm.fwd <- step(AFL.glm.0, scope = formula(AFL.glm.num), direction = "forward", trace = 0)
summary(AFL.glm.fwd)
Call:
glm(formula = WinLoss ~ Inside50s + Marks + ContendedPossessions +
MarksInside50 + Clangers + Clearances + Disposals, family = binomial(logit),
data = AFL.train)
Deviance Residuals:
Min 1Q Median 3Q Max
-2.69869 -0.70594 -0.01347 0.69685 2.59537
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) -17.993850 1.172142 -15.351 < 2e-16 ***
Inside50s 0.067637 0.010162 6.656 2.82e-11 ***
Marks 0.040351 0.005638 7.157 8.24e-13 ***
ContendedPossessions 0.047621 0.006556 7.264 3.77e-13 ***
MarksInside50 0.158085 0.019926 7.933 2.13e-15 ***
Clangers -0.031204 0.009413 -3.315 0.000917 ***
Clearances 0.034660 0.012002 2.888 0.003878 **
Disposals 0.007527 0.002734 2.753 0.005898 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 2279.1 on 1643 degrees of freedom
Residual deviance: 1463.4 on 1636 degrees of freedom
AIC: 1479.4
Number of Fisher Scoring iterations: 5
Analysis
Logistic Regression
The first predictive model that we decided to implement was a Logistic Regression model, with ‘WinLoss’ being our response variable, obviously with a ‘1’ (winning game) being the preferred outcome.
AFL.all.pred <- predict(AFL.glm.fwd, newdata = AFL.test, type = "response")
#head(AFL.all.pred)
After the model had made its predictions using our test data to ‘tune’ it, we had to compare these predictions to the actual true, predicted outcomes for 2016. The most efficient way of going about this was to create a confusion matrix of our predicted results against the true results, this gives us an idea of how accurate our model actually is.
AFL.all.pred.class <- rep(0, length(AFL.all.pred))
AFL.all.pred.class[AFL.all.pred > 0.75] <- 1
table(AFL.all.pred.class, AFL.test$WinLoss)
AFL.all.pred.class 0 1
0 188 75
1 19 132
(188+132)/(188+75+19+132)
[1] 0.7729469
From this confusion matrix we can see that about 77% of our predictions were correct when we used a cut-off value of 0.75. This means that any game predicted by our model that has above a 75% chance of winning will only then be classified as a ‘sure win.’ This cut-off seems like a fair assumption because, assuming the model actually worked in the way we wanted it to, every four games you placed a bet on you’d only lose one of those four. And when you factor in even some average odds you’d almost always come out profitable by a long shot if that was the case.
This model has a pretty reasonable success rate even when this high cut-off is put in place however, it suffers from the same ‘problem’ that all our other predictive models do (discussed after all the predictive models have been ‘showcased’).
K-Nearest Neighbours
After our Logistic Regression model came out as such a success we decided that the next best step would be to try a K-Nearest Neighbors model to see if it’s more or less accurate when compared to our previous predictive model.
library(class)
AFL.knn.pred <- knn(AFL.train[,c("Disposals", "Marks", "Inside50s", "Clearances", "Clangers", "ContendedPossessions", "MarksInside50")], AFL.test[,c("Disposals", "Marks", "Inside50s", "Clearances", "Clangers", "ContendedPossessions", "MarksInside50")], AFL.train$WinLoss,
k = 3)
table(AFL.knn.pred, AFL.test$WinLoss)
AFL.knn.pred 0 1
0 139 39
1 68 168
(139+167)/(139+40+68+167)
[1] 0.7391304
And, perhaps unsurprisingly, the K-Nearest Neighbors model resulted in a predicted probability which is only roughly 4% behind the Logistic Regression model. This shows again that our models are consistently predicting at a much better rate then a 50/50 guess. However, this model uses the same set of variables and thus suffers from the same problem as the previous.
Decision Tree(s)
We’d done a Logistic Regression and a K-Nearest Neighbors model, so it really only made sense to finish the trio by attempting to create a Decision Tree or Many Forests model.
library(rpart)
AFL.num.tree <- rpart(WinLoss ~ Disposals + Marks + Behinds + Inside50s + Clearances + Clangers + ContendedPossessions + ContestedMarks + MarksInside50,
AFL_clean)
AFL.num.tree.pred = predict(AFL.num.tree, AFL.test)
AFL.num.tree.pred <- AFL.num.tree.pred[,2]
#head(AFL.num.tree.pred)
AFL.num.tree.class <- rep(0, length(AFL.num.tree.pred))
AFL.num.tree.class[AFL.num.tree.pred > 0.75] <- 1
table(AFL.num.tree.class, AFL.test$WinLoss)
AFL.num.tree.class 0 1
0 172 70
1 35 137
(172 + 137)/(172+70+35+137)
[1] 0.7463768
To our surprise the Many Forests model actually predicted with an almost identical success rate as the K-Nearest Neighbors model did. I guess this just shows that our variables must have quite even splits with respect to wins and losses. Again, this model suffers from the same problem as the previous two.
However, this model wasn’t as useless as the previous two models because we can actually visualize the different splits that the Decision Tree uses which gives us valuable insight into how different combinations of variables interact to either improve your chances of winning or hurt them.
library(rpart.plot)
library(randomForest)
library(partykit)
plot(as.party(AFL.num.tree))
The Decision Tree diagram is one of the more valuable things to come out of the analysis with respect to our goal to predict the outcome of future games. By just following the right most path of the diagram we can see that more Inside50s paired with more MarksInside50 is a ‘recipe’ for a very high chance of winning; which seems quite obvious. By following the left most path we can see the complete opposite, fewer Inside50s paired with fewer MarksInside50 results more often then not in a lower chance of winning; which again seems quite obvious.
This diagram only really starts to get interesting when you look at the combinations of the many different variables. For example if a team isn’t getting a lot of Inside50s but is getting a lot of MarksInside50, and then also the team has a decent amount of Marks overall then they suddenly have a much better chance at winning.
This diagram might be especially useful for something like half-time betting. If two teams are almost neck to neck at half-time but then one team is following one of these ‘paths’ that lead to a higher proportion of wins then it might be in your best interest to bet on that team over their opposition. In no way is it a perfect set of paths that lead to victory for a team however, using it is certainly a little more useful then blindly picking one team or the other.
The Problem
Perhaps a little foresight into what our models are actually doing would’ve been useful and saved us a lot of sort of wasted time. The problem with all our ‘predictive’ models is that they’re not actually really predicting anything useful. All they are doing is classifying a game as either a win or a loss using given the post-game statistics for a team. Statistics which can only be collected once a game has finished, not before a game has been played which was the whole ‘problem’ we set out to solve.
This makes our models sort of useless compared to the way we’d imaged them but not completely useless. The fact that they could predict three out of every four games correct with just the variables we gave them to work with reinforces the fact that some sort of correlation exists between those variables and a team winning a game. To actually solve our problem it might have been a lot more useful to be looking at quarter-time or half-time teams statistics and then seeing how those relate to a win or a loss.
Plotting
After our ‘predictive’ models really didn’t help us with what we wanted to achieve we had to take a step back and think about a more specific way of analyzing the data which actually somewhat helps in predicting the outcomes of future matches. We thought of two main things that we were curious to look into:
- How often are individual teams winning & losing within our data set, and how does this compare to their performance in the current 2017 season?
The first thing we needed to do was separate the total wins and loses with respect to each team throughout the whole data set. Then we put them into descending order because that’s how we intended them to be shown within our plots we planned on making.
table_all <- table(AFL_clean$Team, AFL_clean$WinLoss)
all_freq <- as.data.frame.matrix(table_all)
all_freq <- all_freq[order(all_freq$`1`, decreasing = TRUE),]
#all_freq
This wasn’t the end of the story though. Simply graphing each team’s total frequency of wins and losses and then ordering them by number of wins would be completely unfair. Some teams have just played more games than other teams which means they’d by default probably have more wins because they’ve simply played more games. Thus, to show them fairly next to each other we have to get them in terms of their win/loss percentage or proportion. That is, out of all the games they’ve played what fraction of them did they win, and what fraction did they lose?
win_perc <- all_freq$`1` / (all_freq$`0` + all_freq$`1`)
loss_perc <- 1 - win_perc
all_perc <- cbind(all_freq, loss_perc, win_perc)
all_perc <- all_perc[3:4]
colnames(all_perc) <- c("Loss Percentage", "Win Percentage")
#all_perc
all_perc_decr <- all_perc[order(all_perc$`Win Percentage`, decreasing = TRUE),]
#all_perc_decr
mosaicplot(all_perc_decr, col=c(rgb(215/255,25/255,28/255),rgb(166/255,217/255,106/255)), main = "Total Win vs Loss Percentage for each team (2012-2016) [Descending Order]", cex.axis = 1.2)

Here we’ve just split the above plot in half so it’s easier to see and what we’ve done is compared the rank of the teams in our descending win percentage plot from the 2012 - 2016 data against the current 2017 ladder positions (as of 31-05-2017). A green dot next to a team represents them being in the same half of both the 2017 ladder and our 2012 - 2016 descending win percentage rankings. As you might have noticed we by doing this we only managed to place just over half of the teams in their correct halves, 56% to be exact. However, quite a few of the teams are only off by a one or two positions, and the seasons not finished yet so there’s always room for the teams to do the natural thing and converge on their relative historical rankings.
Not to mention this season of AFL has just been particularly unpredictable; teams who’ve generally been on top have fallen and teams who’ve generally been at the bottom have started to rise. Just look at GWS; from 2012 - 2016 they have the fourth lowest win percentage yet they’re currently second on the ladder. This probably comes down to them being a young team and each year their players are getting exponentially more experienced and playing better as a result, but it’s interesting nonetheless.
- Are certain teams winning a lot more often at certain venues, and does this have anything to do with how much experience they have playing at these venues?
To answer these questions we first had to determine which venues all of the teams have played at so we have a decent sample size of matches to work with, and to make sure each team is represented within each venue’s analysis. To do this we plotted our score variable for each team filtered by each different venue we have in our data set.
library(lattice)
barchart(AFL_clean$Score ~ AFL_clean$Team | AFL_clean$Venue)

Using this plot and comparing the total amount of games played at each venue we narrowed the venues we wanted to look at down to Subiaco, Adelaide Oval, M.C.G, S.C.G and The Gabba. These locations were also picked as they’re the most popular venues for Perth, Adelaide, Melbourne, Sydney and Brisbane respectively; meaning if there’s any correlation between the teams playing on their home ground we should be able to see it across all the main venues.
To do this we had to extract the wins and losses that each team has had when only looking at a specific venue.
venueFilter <- function(venue){
AFL_venue <- AFL_clean[AFL_clean$Venue == venue,]
venue_table <- table(AFL_venue$Team, AFL_venue$WinLoss)
venue_df <- as.data.frame.matrix(venue_table)
venue_freq <- venue_df[order(venue_df$`1`, decreasing = TRUE),]
win_perc <- venue_freq$`1` / (venue_freq$`0` + venue_freq$`1`)
loss_perc <- 1 - win_perc
all_perc <- cbind(venue_freq, loss_perc, win_perc)
all_perc <- all_perc[3:4]
colnames(all_perc) <- c("Loss Percentage", "Win Percentage")
#all_perc
team_total <- (venue_freq$`0` + venue_freq$`1`)
game_totals <- sum(team_total)
team_proportion <- team_total / game_totals
venue_freq <- cbind(venue_freq, team_proportion)
#venue_freq
all_venue <- cbind(venue_freq, all_perc)
all_venue <- all_venue[order(all_venue$`Win Percentage`, decreasing = TRUE),]
return(all_venue)
}
subiaco <- venueFilter("Subiaco")
syd.showground <- venueFilter("Sydney Showground")
gabba <- venueFilter("Gabba")
mcg <- venueFilter("M.C.G.")
scg <- venueFilter("S.C.G.")
adl.oval <- venueFilter("Adelaide Oval")
carrara <- venueFilter("Carrara")
docklands <- venueFilter("Docklands")
ftbl.park <- venueFilter("Football Park")
I’ve just included the code for only looking at The Gabba but every single plot was made using the same code and just replacing the venue with whichever one you were interested in.
library(ggplot2)
gabba.tprop <- gabba[3]
bp <- ggplot(gabba.tprop, aes(x="", y=team_proportion, fill=row.names(gabba.tprop)) ) + geom_bar(width = 1, stat = "identity") + scale_fill_manual(values=c("#999999", "#E69F00", "#56B4E9", "#8fc0a0", "#cc9b5b", "#71529b", "#7bf68d", "#96270f", "#1e46be", "#b60edc", "#678dbd", "#4eb20b", "#5f37e5", "#02339b", "#a7a4df", "#2b681e", "#2c3f7c", "#d9ed8f"))
bp

pie <- bp + coord_polar("y", start=0)
pie

gabba.wperc <- gabba[4:5]
#subiaco.wperc
mosaicplot(gabba.wperc, col=c(rgb(215/255,25/255,28/255),rgb(166/255,217/255,106/255)), main = "Total Win vs Loss Percentage for each team at Subiaco Oval (2012-2016) [Descending Order]", cex.axis = 1.2)

So you don’t have to look at the same code ten times and squint trying to look at the downsized R-output I’ve just included the slides I made from the power point, but like I said before it was all made using the exact same code above.
Subiaco
Subiaco is the home ground of Fremantle and West Coast and as seen on the first plot they’re also in the top two places for win percentage when just looking at games played at Subiaco. The second plot shows the fraction of games that each individual team has played at Subiaco and by no surprise Fremantle and West Coast together make up about 60% of the games. This leaves the other 16 teams to share the remaining 40% of games between themselves, which equates to about six games each.
After looking at these plots it makes a lot more sense that Fremantle and West Coast are topping the win percentage at Subiaco because they’re so disproportionately represented at the venue. Not to mention that all the other teams have to fly quite a distance to get to Subiaco, this probably contributes heavily to the fact that the majority of the teams have less than a 50% win rate.
Relating back to our goal of predicting future outcomes of games, this gives us some very useful information. When Brisbane, Collingwood, Melbourne or St Kilda are playing at Subiaco it’s probably a good idea to bet against them, especially if they’re up against Fremantle or West Coast.

Adelaide Oval
Looking at Adelaide Oval we see a similar trend with the home teams, Adelaide and Port Adelaide, together making up about 60% of the total games played on their home turf. Similarily, this leaves the other 16 teams to share the remaining 40% of games, but this time that only equates to about four games each (as less games have been played at Adelaide Oval compared to Subiaco).
When we look at the win percentages there’s definitely some improvement as Port Adelaide have moved from overall being ranked 10th to being ranked 6th however, Adelaide has stayed stagnant in the same position. Interestingly we also have a couple different teams dominating the top positions and a couple more teams having not ever one a game at the venue.
Using this information we could say that if Port Adelaide is playing a team that’s on par with them, but they’re playing at Adelaide Oval, then they might just have that extra edge from the home advantage and come out on top. We see Brisbane, Collingwood and St Kilda being repeated on the bottom of the list with no wins what so ever, again, making your chances of winning when betting against them (if they’re playing at Subiaco or Adelaide Oval) that much better.

M.C.G.
The M.C.G is a much more popular venue with a total of 500 games played at it, which is more games than Subiaco and Adelaide Oval combined. It’s also in Melbourne which is within a couple hours drive of over half the AFL teams. These factors contribute the the M.C.G having a much more even spread of team’s total games played at the venue, as seen on the second plot each close-by team holds about 5% - 10% of the games instead of 30%.
However, even with the spread being a lot more even and no team(s) being extremelly disproportionately represented, we still see this trend of the surrounding, close-by teams playing better. Every single on of the close-by teams has either held their position or improving dramatically, with the Western Bulldogs climbing nearly half of the ranks. However, we still see Brisbane in the bottom few ranks adding to the pile of evidence that you should probably always bet against them if they’re playing an away game.

S.C.G.
The S.C.G has the smallest amount of games played at is compared to all the other venues we’re looking at, only 90 games it total which is less than 1/5th of the total games played at the S.C.G. This sort of explains the extreme dispoportionality that we see at the venue, with Sydney having played about half of all the games played there. Interestingly though GWS plays just about as often as an away team despite them being situated quite close by to the venue.
The win percentages are quite skewed here due to the small amount of games that have been played there by away teams, each team has only played about two or three games. This makes it hard to get any useful information from the win percentage plot however, it has to be noted that Brisbane has no wins again despite actually being roughly one of the closest away teams to the venue.

The Gabba
Looking at The Gabba we can fully confirm that things really aren’t looking too great for Brisbane. Despite it being their home ground and then having played about 50% of the total games at the venue they are still very close to the bottom of the ranks. Again it is strange how Gold Coast is within an hours drive of The Gabba yet they still play there as often as an away team.
The Gabba doesn’t have many more games played at it than the S.C.G however, it’s interesting that the skew is sort of in the completely opposite direction, with nearly half the teams having a (or close to a) 100% win rate. This makes sense when you consider that most of the teams would be facing up against the home team, Brisbane, who we’ve already established probably aren’t the best team to be putting your money on.

Appendix
AFLstats <- read.csv("stats.csv")
AFL <- AFLstats
AFL <- AFL[c(1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,25,27,28,29,30,31)]
colnames(AFL)
sum_names <- colnames(AFL)[10:28]
sum_names
all_teams <- unique(as.character(AFL$Team))
ad <- AFL[AFL$Team == all_teams[1],]
bl <- AFL[AFL$Team == all_teams[2],]
clt <- AFL[AFL$Team == all_teams[3],]
clwd <- AFL[AFL$Team == all_teams[4],]
esdn <- AFL[AFL$Team == all_teams[5],]
fd <- AFL[AFL$Team == all_teams[6],]
glng <- AFL[AFL$Team == all_teams[7],]
gc <- AFL[AFL$Team == all_teams[8],]
gws <- AFL[AFL$Team == all_teams[9],]
ht <- AFL[AFL$Team == all_teams[10],]
mlb <- AFL[AFL$Team == all_teams[11],]
nmlb <- AFL[AFL$Team == all_teams[12],]
pad <- AFL[AFL$Team == all_teams[13],]
rmd <- AFL[AFL$Team == all_teams[14],]
sk <- AFL[AFL$Team == all_teams[15],]
syd <- AFL[AFL$Team == all_teams[16],]
wc <- AFL[AFL$Team == all_teams[17],]
wb <- AFL[AFL$Team == all_teams[18],]
cleanAFLdata <- function(team){
library(plyr)
team_stats <- ddply(team, .(Date), numcolwise(sum))
team_stats <- team_stats[c(1,5:23)]
team_keep <- team[match(unique(team$Date), team$Date),]
team_keep <- team_keep[1:9]
team_clean <- merge(team_keep, team_stats)
team_clean <- team_clean[team_clean$WinLoss != "D",]
team_clean$WinLoss <- droplevels(team_clean$WinLoss)
levels(team_clean$WinLoss)[levels(team_clean$WinLoss)=="L"] <- 0
levels(team_clean$WinLoss)[levels(team_clean$WinLoss)=="W"] <- 1
team_clean$WinLoss <- factor(team_clean$WinLoss)
return(team_clean)
}
syd_clean <- cleanAFLdata(syd)
head(syd_clean)
ad_clean <- cleanAFLdata(ad)
bl_clean <- cleanAFLdata(bl)
clt_clean <- cleanAFLdata(clt)
clwd_clean <- cleanAFLdata(clwd)
esdn_clean <- cleanAFLdata(esdn)
fd_clean <- cleanAFLdata(fd)
glng_clean <- cleanAFLdata(glng)
gc_clean <- cleanAFLdata(gc)
gws_clean <- cleanAFLdata(gws)
ht_clean <- cleanAFLdata(ht)
mlb_clean <- cleanAFLdata(mlb)
nmlb_clean <- cleanAFLdata(nmlb)
pad_clean <- cleanAFLdata(pad)
rmd_clean <- cleanAFLdata(rmd)
sk_clean <- cleanAFLdata(sk)
syd_clean <- cleanAFLdata(syd)
wc_clean <- cleanAFLdata(wc)
wb_clean <- cleanAFLdata(wb)
AFL_clean <- rbind(ad_clean, bl_clean, clt_clean, clwd_clean, esdn_clean, fd_clean, glng_clean,
gc_clean, gws_clean, ht_clean, mlb_clean, nmlb_clean, pad_clean, rmd_clean,
sk_clean, syd_clean, wc_clean, wb_clean)
length(unique(AFL_clean$Team))
AFL.test <- AFL_clean[AFL_clean$Season == 2016,]
head(AFL.test)
AFL.train <- AFL_clean[AFL_clean$Season != 2016,]
head(AFL.train)
plot(AFL.train$WinLoss, AFL.train$Disposals)
library(ggplot2)
qplot(WinLoss, Disposals, data = AFL.train)
source("PairsWithHist.R")
pairs(AFL_clean, lower.panel = panel.pts, upper.panel = panel.cor, diag.panel = panel.hist)
# just 'numerical' variables
AFL.glm.num <- glm(WinLoss ~ Disposals + Marks + Behinds + Inside50s + Clearances + Clangers + ContendedPossessions + ContestedMarks + MarksInside50,
data = AFL.train, family = binomial(logit))
# 'all' variables (Margin excluded because too perfect)
AFL.glm.all <- glm(WinLoss ~ Score + Opposition + Venue + Disposals + Marks + Goals + Behinds + Hitouts + Tackles + Rebound50s + Inside50s + Clearances + Clangers + FreesFor + ContendedPossessions + ContestedMarks + MarksInside50 + OnePercenters + Bounces+GoalAssists,
data = AFL.train, family = binomial)
#summary(AFL.glm.all)
AFL.glm.0 <- glm(WinLoss ~ 1, data = AFL.train, family = binomial(logit))
AFL.glm.fwd <- step(AFL.glm.0, scope = formula(AFL.glm.num), direction = "forward", trace = 0)
summary(AFL.glm.fwd)
AFL.all.pred <- predict(AFL.glm.fwd, newdata = AFL.test, type = "response")
head(AFL.all.pred)
AFL.all.pred.class <- rep(0, length(AFL.all.pred))
AFL.all.pred.class[AFL.all.pred > 0.75] <- 1
table(AFL.all.pred.class, AFL.test$WinLoss)
(188+132)/(188+75+19+132)
library(rpart)
AFL.tree <- rpart(WinLoss ~ Opposition + Venue + Disposals + Marks + Goals + Behinds + Hitouts + Tackles + Rebound50s + Inside50s + Clearances + Clangers + FreesFor + ContendedPossessions + ContestedMarks + MarksInside50 + OnePercenters + Bounces + GoalAssists,
AFL_clean)
#summary(AFL.tree)
library(rpart)
AFL.num.tree <- rpart(WinLoss ~ Disposals + Marks + Behinds + Inside50s + Clearances + Clangers + ContendedPossessions + ContestedMarks + MarksInside50,
AFL_clean)
AFL.num.tree.pred = predict(AFL.num.tree, AFL.test)
AFL.num.tree.pred <- AFL.num.tree.pred[,2]
head(AFL.num.tree.pred)
AFL.num.tree.class <- rep(0, length(AFL.num.tree.pred))
AFL.num.tree.class[AFL.num.tree.pred > 0.75] <- 1
table(AFL.num.tree.class, AFL.test$WinLoss)
(172 + 137)/(172+70+35+137)
library(rpart.plot)
library(randomForest)
library(partykit)
plot(as.party(AFL.tree))
library(rpart)
AFL.teams <- rpart(WinLoss ~ Team + Opposition,
AFL_clean)
library(rpart.plot)
library(randomForest)
library(partykit)
plot(as.party(AFL.teams))
library(rpart)
AFL.venue <- rpart(WinLoss ~ Team + Venue,
AFL_clean)
library(rpart.plot)
library(randomForest)
library(partykit)
plot(as.party(AFL.venue))
library(rpart.plot)
library(randomForest)
library(partykit)
plot(as.party(AFL.num.tree))
library(class)
AFL.knn.pred <- knn(AFL.train[,c("Disposals", "Marks", "Behinds", "Inside50s", "Clearances", "Clangers", "ContendedPossessions", "ContestedMarks", "MarksInside50")], AFL.test[,c("Disposals", "Marks", "Behinds", "Inside50s", "Clearances", "Clangers", "ContendedPossessions", "ContestedMarks", "MarksInside50")], AFL.train$WinLoss,
k = 3)
table(AFL.knn.pred, AFL.test$WinLoss)
(143+168)/(143+39+64+168)
unique(AFL_clean$Venue)
nrow(AFL_clean[AFL_clean$Venue == "Traeger Park",])
table(AFL_clean$Venue)
table_all <- table(AFL_clean$Team, AFL_clean$WinLoss) # wins and losses for each team
# creating tables of each team and thier wins/losses against opposition
table_ad <- table(ad_clean$Opposition, ad_clean$WinLoss)
table_wc <- table(wc_clean$Opposition, wc_clean$WinLoss)
table_bl <- table(bl_clean$Opposition, bl_clean$WinLoss)
table_clt <- table(clt_clean$Opposition, clt_clean$WinLoss)
table_clwd <- table(clwd_clean$Opposition, clwd_clean$WinLoss)
table_esdn <- table(esdn_clean$Opposition, esdn_clean$WinLoss)
table_fd <- table(fd_clean$Opposition, fd_clean$WinLoss)
table_gc <- table(gc_clean$Opposition, gc_clean$WinLoss)
table_glng <- table(glng_clean$Opposition, glng_clean$WinLoss)
table_gws <- table(gws_clean$Opposition, gws_clean$WinLoss)
# Plotting Mosaics
library(vcd)
mosaicplot(table_all, col=c("red","darkgreen"), main = "Wins&Losses against each team (2012-2016)", xlab = "Team", ylab = "Win or loss")
mosaicplot(table_wc, col=c("red","darkgreen"),main = "West Coast and their wins and losses against each team (2012-2016)", xlab = "Team", ylab = "Win or loss")
mosaicplot(table_ad, col=c("red","darkgreen"), main = "Adelaide and their wins and losses against each team (2012-2016)", xlab = "Team", ylab = "Win or loss")
mosaicplot(table_bl, col=c("red","darkgreen"),main = "Brisbane Lions and their wins and losses against each team (2012-2016)", xlab = "Team", ylab = "Win or loss")
mosaicplot(table_clt, col=c("red","darkgreen"),main = "Carlton and their wins and losses against each team (2012-2016)", xlab = "Team", ylab = "Win or loss")
mosaicplot(table_clwd, col=c("red","darkgreen"),main = "Collingwood and their wins and losses against each team (2012-2016)", xlab = "Team", ylab = "Win or loss")
all_freq <- as.data.frame.matrix(table_all)
all_freq <- all_freq[order(all_freq$`1`, decreasing = TRUE),]
all_freq
mosaicplot(all_freq, col=c("red","darkgreen"), main = "Win vs Loss Frequency for each team (2012-2016)", cex.axis = 1.2)
win_perc <- all_freq$`1` / (all_freq$`0` + all_freq$`1`)
loss_perc <- 1 - win_perc
all_perc <- cbind(all_freq, loss_perc, win_perc)
all_perc <- all_perc[3:4]
colnames(all_perc) <- c("Loss Percentage", "Win Percentage")
all_perc
mosaicplot(all_perc, col=c("red","darkgreen"), main = "Win vs Loss Percentage for each team (2012-2016)", cex.axis = 1.2)
all_perc_decr <- all_perc[order(all_perc$`Win Percentage`, decreasing = TRUE),]
all_perc_decr
mosaicplot(all_perc_decr, col=c(rgb(215/255,25/255,28/255),rgb(166/255,217/255,106/255)), main = "Total Win vs Loss Percentage for each team (2012-2016) [Descending Order]", cex.axis = 1.2)
library(lattice)
barchart(AFL_clean$Score ~ AFL_clean$Team | AFL_clean$Venue)
venueFilter <- function(venue){
AFL_venue <- AFL_clean[AFL_clean$Venue == venue,]
venue_table <- table(AFL_venue$Team, AFL_venue$WinLoss)
venue_df <- as.data.frame.matrix(venue_table)
venue_freq <- venue_df[order(venue_df$`1`, decreasing = TRUE),]
win_perc <- venue_freq$`1` / (venue_freq$`0` + venue_freq$`1`)
loss_perc <- 1 - win_perc
all_perc <- cbind(venue_freq, loss_perc, win_perc)
all_perc <- all_perc[3:4]
colnames(all_perc) <- c("Loss Percentage", "Win Percentage")
#all_perc
team_total <- (venue_freq$`0` + venue_freq$`1`)
game_totals <- sum(team_total)
team_proportion <- team_total / game_totals
venue_freq <- cbind(venue_freq, team_proportion)
#venue_freq
all_venue <- cbind(venue_freq, all_perc)
all_venue <- all_venue[order(all_venue$`Win Percentage`, decreasing = TRUE),]
return(all_venue)
}
subiaco <- venueFilter("Subiaco")
syd.showground <- venueFilter("Sydney Showground")
gabba <- venueFilter("Gabba")
mcg <- venueFilter("M.C.G.")
scg <- venueFilter("S.C.G.")
adl.oval <- venueFilter("Adelaide Oval")
carrara <- venueFilter("Carrara")
docklands <- venueFilter("Docklands")
ftbl.park <- venueFilter("Football Park")
sum(gabba[1] + gabba[2])
gabba
library(ggplot2)
gabba.tprop <- gabba[3]
bp <- ggplot(gabba.tprop, aes(x="", y=team_proportion, fill=row.names(gabba.tprop)) ) + geom_bar(width = 1, stat = "identity") + scale_fill_manual(values=c("#999999", "#E69F00", "#56B4E9", "#8fc0a0", "#cc9b5b", "#71529b", "#7bf68d", "#96270f", "#1e46be", "#b60edc", "#678dbd", "#4eb20b", "#5f37e5", "#02339b", "#a7a4df", "#2b681e", "#2c3f7c", "#d9ed8f"))
bp
pie <- bp + coord_polar("y", start=0)
pie
gabba.wperc <- gabba[4:5]
#subiaco.wperc
mosaicplot(gabba.wperc, col=c(rgb(215/255,25/255,28/255),rgb(166/255,217/255,106/255)), main = "Total Win vs Loss Percentage for each team at Subiaco Oval (2012-2016) [Descending Order]", cex.axis = 1.2)
LS0tCnRpdGxlOiAiQUZMIFByb2plY3QgUmVwb3J0IgphdXRob3I6ICJUcm95IEVuZ2VsaGFyZHQgJiBBZGFtIEhhcnRtYW5uIgpvdXRwdXQ6CiAgd29yZF9kb2N1bWVudDogZGVmYXVsdAogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKLS0tCioqKgoKMS4gVGhpcyBhc3NpZ25tZW50IGlzIG15L291ciBvd24gb3JpZ2luYWwgd29yaywgZXhjZXB0IHdoZXJlIEkvd2UgaGF2ZSBhcHByb3ByaWF0ZWx5IGNpdGVkIHRoZSBvcmlnaW5hbCBzb3VyY2UgKGFwcHJvcHJpYXRlIGNpdGF0aW9uIG9mIG9yaWdpbmFsIHdvcmsgd2lsbCB2YXJ5IGZyb20gZGlzY2lwbGluZSB0byBkaXNjaXBsaW5lKS4KMi4gVGhpcyBhc3NpZ25tZW50IGhhcyBub3QgcHJldmlvdXNseSBiZWVuIHN1Ym1pdHRlZCBpbiBhbnkgZm9ybSBmb3IgdGhpcyBvciBhbnkgb3RoZXIgdW5pdCwgZGVncmVlIG9yIGRpcGxvbWEgYXQgYW55IHVuaXZlcnNpdHkgb3Igb3RoZXIgaW5zdGl0dXRlIG9mIHRlcnRpYXJ5IGVkdWNhdGlvbi4KMy4gSS93ZSBhY2tub3dsZWRnZSB0aGF0IGl0IGlzIG15IHJlc3BvbnNpYmlsaXR5IHRvIGNoZWNrIHRoYXQgdGhlIGZpbGUgSS93ZSBoYXZlIHN1Ym1pdHRlZCBpczogYSkgcmVhZGFibGUsIGIpIHRoZSBjb3JyZWN0IGZpbGUgYW5kIGMpIGZ1bGx5IGNvbXBsZXRlLgoKKioqCgojIyBfX0ludHJvZHVjdGlvbl9fCgpUaGUgQUZMIChBdXN0cmFsaWFuIEZvb3RiYWxsIExlYWd1ZSkgaXMgdGhlIGhpZ2hlc3QgbGVhZ3VlIHRoYXQgZXhpc3RzIGZvciBhIHBvcHVsYXIgc3BvcnQgd2l0aGluIEF1c3RyYWxpYSwgY2FsbGVkIGZvb3RiYWxsIChzb21ldGltZXMgJ2Zvb3R5JyBvciAnb3p6aWUgcnVsZXMnKS4gTGlrZSBtb3N0IHNwb3J0cyB0aGF0IGFyZSBwb3B1bGFyIGFyb3VuZCB0aGUgZ2xvYmUsIGEgbHVkaWNyb3VzIGJldHRpbmcgaW5kdXN0cnkgZXhpc3RzIGFyb3VuZCB0aGUgQUZMIHdoZXJlIHlvdSdyZSByZXdhcmRlZCBmb3IgcGlja2luZyB0aGUgd2lubmluZyB0ZWFtKHMpLCBhbmQgbm90LXNvLXJld2FyZGVkIGlmIHlvdSBoYXBwZW4gdG8gcGljayB0aGUgbG9zaW5nIHRlYW0ocykuIFRoZSBBRkwsIGFuZCB0aGlzIGJldHRpbmcgZXRob3MsIGlzIHNvbWV3aGF0IGluZ3JhaW5lZCBpbnRvIEF1c3RyYWxpYW4gY3VsdHVyZSB0byB0aGUgcG9pbnQgdGhhdCBpdCdzIGNvbW1vbiBwbGFjZSBmb3IgZ3JvdXBzIG9mIGZyaWVuZHMvY29sbGVhZ3VlcyB0byBhbGwgcGl0Y2ggaW4gYW5kIHJ1biBhICd0aXBwaW5nIGNvbXBldGl0aW9uLicgQSBjb21wZXRpdGlvbiB3aGVyZSBlYWNoIHBhcnRpY2lwYW50IGlzIHJhbmtlZCBieSB0aGUgYW1vdW50IG9mIHdpbnMgdGhhdCB0aGV5IGNhbiBzdWNjZXNzZnVsbHkgcHJlZGljdCBkdXJpbmcgYSBzZWFzb24gb2YgZm9vdGJhbGwsIGFuZCBpcyByZXdhcmRlZCBhY2NvcmRpbmcgdG8gdGhlaXIgaW5kaXZpZHVhbCByYW5rcy4gT2YgY291cnNlLCB3aGVyZSB0aGVyZSBhcmUgcmV3YXJkcyB0byBiZSByZWFwZWQgdGhlcmUncyBtb3JlIG9mdGVuIHRoYW4gbm90IGEgZ3JvdXAgb2YgZGV0ZXJtaW5lZCBwZW9wbGUsIHVzaW5nIGFsbCBtZWFucyBwb3NzaWJsZSwgaW4gb3JkZXIgdG8gZ3JhYiB0aGUgYmlnZ2VzdCBwaWVjZSBvZiB0aGUgcGllLiBXZSBkZWNpZGVkIHRoYXQsIGFybWVkIHdpdGggYSBzZW1lc3RlcidzIGtub3dsZWRnZSBvZiBEYXRhIFNjaWVuY2UgYXMgb3VyIHRvb2xzLCBpdCB3b3VsZCBiZSBpbiBvdXIgYmVzdCBpbnRlcmVzdCB0byBqb2luIHRoaXMgZ3JvdXAgYW5kIHRlc3Qgb3VyIGx1Y2sgYXQgZ3JhYmJpbmcgYSBwaWVjZSBvZiB0aGUgcGllLgoKVGhpcyByZXBvcnQgb3V0bGluZXMgb2YgYWxsIHRoZSBuZWNlc3Nhcnkgc3RlcHMgd2UgdG9vayB0byB0cnkgJ3NlY3VyZSB0aGlzIHBpZWNlIG9mIHRoZSBwaWU7JyB0aGF0IGlzLCBwcmVkaWN0IHRoYXQgd2hlbiBhbnkgZ2l2ZW4gQUZMIG1hdGNoIGlzIHBsYXllZCB3aGljaCB0ZWFtIHdvdWxkIGJlIG1vcmUgbGlrZWx5IHRvIHdpbi4KCkR1cmluZyB0aGUgcmVwb3J0IHdlJ2xsIGV4cGxvcmU6ICAKCiogV2hlcmUgdGhlIGRhdGEgY29tZXMgZnJvbSwgYW5kIHdoYXQgaXQgYWN0dWFsbHkgcmVwcmVzZW50cwoqIFRoZSBzdGVwcyB3ZSB0b29rIGluIGNsZWFuaW5nIG91ciBkYXRhLCB3cmFuZ2xpbmcgaXQgaW50byAncHJvcGVyJyBmb3JtLCBhbmQgZGVhbGluZyB3aXRoIGFueSBwb3NzaWJsZSB1bmRlcmx5aW5nIGFzc3VtcHRpb25zCiogVGhlIG1hbnkgZGlmZmVyZW50IHdheXMgd2Ugd2VudCBhYm91dCBhbmFseXppbmcgb3VyIGRhdGEgdG8gdHJ5IGdldCB0aGUgbW9zdCBhY2N1cmF0ZSBwcmVkaWN0aW9uIGZvciB0aGUgd2lubmluZyB0ZWFtCiogQSBzdW1tYXJ5IG9mIGhvdyB3ZWxsIG91ciBhbmFseXNpcyBoZWxwZWQgdXMgaW4gcmVhY2hpbmcgdGhlIGdvYWwgd2Ugc2V0IG91dCB0byBhY2hpZXZlLCBwbHVzIGEgZGlzY3Vzc2lvbiBvbiB0aGUgbWFueSBkcmF3YmFja3Mgd2UgbWV0IGFuZCBpbXByb3ZlbWVudHMgd2UgY291bGQgbWFrZQoKKioqCgojIyBfX0Rlc2NyaXB0aW9uIG9mIERhdGEgYW5kIE1ldGhvZHNfXwojIyMgVGhlIERhdGEKCi0gUHJlc2VudHMgYSBjbGVhciwgY29uY2lzZSBkZXNjcmlwdGlvbiBvZiB0aGUgZGF0YSwgc291cmNlcywgYW5kIHN0YXRpc3RpY2FsIG1ldGhvZHMgdXNlZCBpbiB0aGUgcmVwb3J0ICAKLSBJbXBvcnRhbnQgYXNwZWN0cyBvZiBkYXRhIHNldCBhcmUgY2xlYXJseSBleHBsYWluZWQgIAotIFN1bW1hcnkgdGFibGVzIChpZiBwcmVzZW50ZWQpIGFyZSB1bmRlcnN0YW5kYWJsZSBhbmQgc2VsZi0gY29udGFpbmVkICAKClRoZSBkYXRhIHRoYXQgd2UgdXNlZCB0byBnbyBhYm91dCB0aGlzIHByZWRpY3Rpb24gaXMgYSBkYXRhIHNldCB0aGF0IHdhcyByZXRyaWV2ZWQgZnJvbSBbS2FnZ2xlXShodHRwczovL3d3dy5rYWdnbGUuY29tKSAoW0FGTCBEYXRhc2V0XShodHRwOi8vd3d3LmthZ2dsZS5jb20vc3RvbmV5NzEvYWZsc3RhdHMvdmVyc2lvbi8xKSkuIFdoaWNoIGlzIGFjdHVhbGx5IGp1c3QgYW4gYWdncmVnYXRlZCBjb2xsZWN0aW9uIChhcyBhIC5jc3YgZmlsZSkgb2YgYWxsIHRoZSBwbGF5ZXIgZGF0YSBhdmFpbGFibGUgZnJvbSB0aGUgW0FGTCBUYWJsZXNdKGh0dHA6Ly9hZmx0YWJsZXMuY29tL2FmbC9hZmxfaW5kZXguaHRtbCkgd2Vic2l0ZTsgZnJvbSBBRkwgc2Vhc29ucyAyMDEyIC0gMjAxNiAoaW5jbHVzaXZlKS4gVGhlIGRhdGEgc2V0IGhhcyBiZWVuIGFuYWx5c2VkIG9uY2UgYmVmb3JlIGJ5IHRoZSBhdXRob3IvdXBsb2FkZXIgb2YgdGhlIGRhdGEsIChbTWljaGVhbFN0b25lXShodHRwczovL3d3dy5rYWdnbGUuY29tL3N0b25leTcxL21vc3QtaW5mbHVlbnRpYWwtcGxheWVycy1pbi10aGUtYWZsL2NvZGUpLiBIZSBleHBsb3JlZCBoaXMgZGF0YSBhbmQgbW9kZWxlZCBpdCBhY2NvcmRpbmdseSBpbiBhbiBlZmZvcnQgdG8gdHJ5IGZpbmQgdGhlICdtb3N0IGluZmx1ZW50aWFsJyBwbGF5ZXIgaW4gdGhlIEFGTCBmcm9tIHNlYXNvbnMgMjAxMiAtIDIwMTYuCgpgYGB7cn0KQUZMc3RhdHMgPC0gcmVhZC5jc3YoInN0YXRzLmNzdiIpCmBgYAoKT2YgY291cnNlIHdoZW4gd2UgYXJlIGFuYWx5emluZyB0aGlzIGRhdGEgc2V0IHdlIGFyZSBtYWtpbmcgdGhlIGFzc3VtcHRpb24gdGhhdCBNaWNoZWFsU3RvbmUsIHRoZSBhdXRob3Igb2YgdGhlIGRhdGEgc2V0LCBoYXMgbWFkZSBubyBlcnJvcnMgd2hpbHN0IGNvbGxlY3RpbmcgYWxsIHRoaXMgZGF0YSBhbmQgbWVyZ2luZyBpdCB0b2dldGhlci4gU2VlaW5nIGFzIHRoZSBkYXRhIGhhcyBubyBtaXNzaW5nIHZhbHVlcyAoc2VlbiBpbiB0aGUgcGxvdChzKSBiZWxvdykgYW5kIGR1cmluZyBvdXIgYW5hbHlzaXMgd2Ugd2VyZSBsZWFkIHRvIHJlYXNvbmFibGUsIGxvZ2ljYWwgb3V0Y29tZXM7IGl0IHNlZW1zIGxpa2UgdGhpcyBpcyBhIGZhaXIgYXNzdW1wdGlvbiB0byBtYWtlLgoKYGBge3J9CnJlcXVpcmUoSG1pc2MpCnBsb3QoZGVzY3JpYmUoQUZMc3RhdHMpKQpgYGAKClRoZSBkYXRhIHNldCBoYXMgKio0NTQ5NiByb3dzKiogYW5kICoqMzIgY29sdW1ucyoqLiBFYWNoIHJvdyByZXByZXNlbnRzIGEgcGxheWVyJ3MgcGVyZm9ybWFuY2Ugd2l0aGluIGFuIEFGTCBtYXRjaCBiZXR3ZWVuIDIwMTIgYW5kIDIwMTY7IGluY2x1ZGluZyBpbmZvcm1hdGlvbiBhYm91dCB3aGljaCByb3VuZCB0aGUgZ2FtZSBpbiBxdWVzdGlvbiB3YXMsIGlmIHRoZSB0ZWFtIG9uZSBvciBsb3N0IGFuZCBhIGJ1bmNoIG9mIG51bWVyaWNhbCBzdGF0aXN0aWNzIHJlbGF0aW5nIHRvIHRoZSBpbmRpdmlkdWFsIHBlcmZvcm1hbmNlOyBnaXZpbmcgdXMgYSB0b3RhbCBvZiBwb3RlbnRpYWxseSAzMiBkaWZmZXJlbnQgdmFyaWFibGVzIHRvIHdvcmsgd2l0aCBmb3IgZWFjaCBpbmRpdmlkdWFsIHBsYXllci4gIAoKSGVyZSdzIGEgcXVpY2sgcGVlayBhdCB0aGUgZmlyc3Qgc2l4IHJvd3Mgb2Ygb3VyIGRhdGEgc2V0LiBIZXJlIHdlIGNhbiBzZWUgdGhhdCB3ZSdyZSBsb29raW5nIGF0IEFkZWxhaWRlJ3MgZmlyc3QgZ2FtZSBpbiB0aGUgMjAxNiBzZWFzb24sIHdoZXJlIHRoZXkgcGxheWVkIGFnYWluc3QgTm9ydGggTWVsYm91cm5lIGF0IHRoZSBEb2NrbGFuZHMgc3RhZGl1bSBhbmQgbG9zdC4gVGhlIG1ham9yaXR5IG9mIHRoZSBpbmZvcm1hdGlvbiBsZWZ0IGluIHRoZXNlIHJvd3MganVzdCBhc3NpZ25zIGFuIGludGVnZXIgbnVtYmVyIHRvIGEgc3BlY2lmaWMgZ2FtZSBzdGF0aXN0aWMsIGluZGljYXRpbmcgaG93IG1hbnkgdGltZXMgYSBwbGF5ZXIgbWFuYWdlZCB0byBtZWV0IHRoZSBjb25kaXRpb24gb2YgdGhhdCBzdGF0aXN0aWMuIFRoaXMgaXMgdXNlZnVsIGluIGdpdmluZyB1cyBhbiBpbmRpY2F0aW9uIG9mIGhvdyB3ZWxsIG9uZSBwbGF5ZXIgbWlnaHQgaGF2ZSBiZWVuIHBsYXlpbmcgaW4gYSBjZXJ0YWluIGdhbWUgd2l0aCByZXNwZWN0IHRvIGFub3RoZXIgcGxheWluZyAoY29tcGFyaW5nIG9ubHkgdGhlIHZhcmlhYmxlcyB3ZSBoYXZlIHRvIHdvcmsgd2l0aCBvZiBjb3Vyc2UpLgoKYGBge3J9CkFGTHN0YXRzWzE6NSwxOjhdCmBgYAoKCkJlbG93IGlzIGFuIG91dGxpbmUgb2YgdGhlc2UgZGlmZmVyZW50IHZhcmlhYmxlcy4gQXMgeW91IGNhbiBzZWUgd2UgaGF2ZSBzZXZlbiAnY2F0ZWdvcmljYWwgdmFyaWFibGVzJyAoc29tZSBzaG91bGQgcHJvYmFibHkganVzdCBiZSBjaGFyYWN0ZXIgdmFyaWFibGVzIGxpa2UgJ1BsYXllcicpLCBhbmQgdGhlIHJlc3QgYXJlIGp1c3QgcXVhbnRpdGF0aXZlIHZhcmlhYmxlcyAoYWxsIGluIGludGVnZXIgZm9ybSkuCgpgYGB7cn0Kc3RyKEFGTHN0YXRzKQpgYGAKCkl0J3MgaW1wb3J0IHRvIHVuZGVyc3RhbmQgYWxsIG91ciB2YXJpYWJsZXMgYmVmb3JlIHdlIGFjdHVhbGx5IGdldCBpbnRvIG1hbmlwdWxhdGluZyB0aGUgZGF0YTsgdG8gbWFrZSBzdXJlIHdlJ3JlIG5vdCBkZXN0cm95aW5nIHRoZSBpbnRlZ3JpdHkgb2Ygb3VyIGRhdGEgYXMgd2UgY2Fycnkgb3V0IG91ciBhbmFseXNpcy4gSW4gc2F5aW5nIHRoYXQsIG1vc3Qgb2YgdGhlIHZhcmlhYmxlcyBhcmUgcHJldHR5IHNlbGYgZXhwbGFuYXRvcnk7IGV2ZW4gdG8gc29tZW9uZSB3aG8gb25seSBoYXMgYSB2ZXJ5IGJhc2ljIGtub3dsZWRnZSBvZiBBRkwuIEhvd2V2ZXIsIHRoZXJlJ3MgY2VydGFpbmx5IHNvbWUgJ3NsYW5nJyB0ZXJtaW5vbG9neSB3aGljaCBtaWdodCBuZWVkIHRvIGJlIGNsZWFyZWQgdXA6CgoqIEJlaGluZHMgLSB3aGVuIHRoZSBiYWxsIGlzIHRvdWNoZWQgZWl0aGVyIGJ5IGFub3RoZXIgcGxheWVyIG9yIGJ5IHRoZSBnb2FsIHBvc3QgYnV0IHN0aWxsIHBhc3NlcyBvdmVyIHRoZSBnb2FsIGxpbmU7IG9yIHNpbXBseSB0aGUgYmFsbCBwYXNzZXMgb3ZlciB0aGUgYmVoaW5kIGxpbmUgKG1vcmUgaW5mb3JtYXRpb24gW2hlcmVdKGh0dHA6Ly93d3cuYWZscnVsZXMuY29tLmF1L2FmbC1nYW1lLXJ1bGVzL3BhcnQtZC1wcmUtbWF0Y2gtcHJvdmlzaW9ucy9hZmwtcnVsZXMtc2NvcmluZy1nb2Fscy1iZWhpbmRzLykpCiogSGl0b3V0cyAtIHdoZW4gYSBwbGF5ZXIgc3VjY2Vzc2Z1bGx5IGtub2NrcyB0aGUgYmFsbCBvdXQgb2YgYSBydWNrIAoqIFJ1Y2sgLSBhIHJ1Y2sgb2NjdXJzIGdlbmVyYWxseSBhZnRlciBhIGdvYWwgaXMgc2NvcmVkLCBwbGF5IGlzIGNlYXNlZCBhZnRlciBhIHN0YXRpYyB0YWNrbGUgb3IgdGhlIGJhbGwgZXhpdHMgdGhlIGZpZWxkIGxpbmVzOyB0byByZXNldCB0aGUgcGxheSBhIHJlZmVyZWUgd2lsbCBlaXRoZXIgYm91bmNlIHRoZSBiYWxsIHVwLCBvciB0aHJvdyB0aGUgYmFsbCBpbiBmcm9tIHRoZSBzaWRlbGluZSBhbmQgdGhlIG9wcG9zaW5nIHRlYW1zIHdpdGggY29udGVzdCB0byBoaXQgdGhlIGJhbGwgaW50byBwbGF5CiogUmVib3VuZDUwcyAtIHdoZW4gdGhlIGJhbGwgZXhpdHMgdGhlIHRlYW1zIGRlZmVuc2l2ZSA1MCBhcmVhICh0aGVpciBvd24gNTAgYXJlYSkKKiBDbGFuZ2VycyAtIGEgZ2VuZXJhbCB0dXJuIGdpdmVuIHRvIGEgcGxheWVyJ3Mgc21hbGwgZXJyb3Igd2hpY2ggcmVzdWx0cyBpbiBhIHR1cm4tb3ZlciBvZiB0aGUgYmFsbCAobW9yZSBpbmZvcm1hdGlvbiBbaGVyZV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQ2xhbmdlcl8oQXVzdHJhbGlhbl9ydWxlc19mb290YmFsbCkpKQoqIE9uZVBlcmNlbnRlcnMgLSBhcyB0aGUgbmFtZSBhbGx1ZGVzIHRvLCB0aGlzIGlzIGEgdGVybSBnaXZlbiB0byBjb2xsZWN0aW9uIG9mIHJhcmUgYWN0aW9ucyB3aXRoaW4gQUZMIHdoaWNoIGJlbmVmaXQgdGhlIHRlYW1zIHBsYXk7IGluY2x1ZGluZyBrbm9jay1vbnMsIHNwb2lscywgc21vdGhlcnMgYW5kIHNoZXBhcmRzIChtb3JlIGluZm9ybWF0aW9uIFtoZXJlXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9PbmVfcGVyY2VudGVyXyhBdXN0cmFsaWFuX3J1bGVzX2Zvb3RiYWxsKSkpICAKCiMjIyBPdXIgbWV0aG9kcwoKV2hlbiB0YWtpbmcgYSBjbG9zZXIgbG9vayBhdCB0aGUgcHJvYmxlbSB3ZSBhcmUgb3V0IHRvIHNvbHZlLCBwcmVkaWN0aW5nIHdoaWNoIHRlYW0gaXMgbW9yZSBsaWtlbHkgdG8gd2luIGluIGFueSBnaXZlbiBBRkwgbWF0Y2gsIGl0IHNlZW1zIGxpa2UgcXVpdGUgYSBzaW1wbGUgY2xhc3NpZmljYXRpb24gcHJvYmxlbS4gV2Ugd2FudCB0byBiZSBhYmxlIHRvIGNsYXNzaWZ5IG9uZSB0ZWFtIGFzIHdpbm5pbmcgYW5kIG9uZSB0ZWFtIGFzIGxvc2luZywgYmFzZWQgdXBvbiBhbiBhc3NpZ25lZCBjaGFuY2Ugb2Ygd2lubmluZy4gVGhlIGNoYW5jZSB3aW5uaW5nIHdvdWxkIG9wdGltYWxseSBiZSBkZXRlcm1pbmVkIGJ5IGEgc3Vic2V0IG9mIHJlbGV2YW50IHZhcmlhYmxlcyBwaWNrZWQgZnJvbSB0aGUgMzIgd2UgaGF2ZSBhdmFpbGFibGUgd2l0aGluIHRoaXMgZGF0YSBzZXQuIFdpdGggdGhpcyBpbiBtaW5kIGl0IHNlZW1zIHRoYXQgcHJlZGljdGl2ZSBtb2RlbHMgbGlrZSAqKkxvZ2lzdGljIFJlZ3Jlc3Npb24qKiwgKipLLU5lYXJlc3QgTmVpZ2hib3VycyoqIGFuZCAqKkRlY2lzaW9uIFRyZWUvTWFueSBGb3Jlc3RzKiogd291bGQgYmUgcGVyZmVjdCBjYW5kaWRhdGVzIGZvciBoZWxwaW5nIHVzIHNvbHZlIG91ciBwcm9ibGVtLCBhcyB0aGV5IGVpdGhlciBkZXNpZ25lZCBmb3IgKG9yIGp1c3QgZ29vZCBmb3IpIGFzc2lnbmluZyBwcmVkaWN0aXZlIHByb2JhYmlsaXRpZXMgZm9yIHNpbXBsZSwgYmluYXJ5IGNsYXNzaWZpY2F0aW9uIHZhcmlhYmxlcy4gSG93ZXZlciwgd2Ugd2lsbCBleHBsb3JlIGhvdyBoZWxwZnVsIHRoZXNlIHRvb2xzICphY3R1YWxseSogYXJlIGluIGhlbHBpbmcgdXMgYWNoaWV2ZSBvdXIgZ29hbCBpbiB0aGUgbGF0ZXIgcGFydHMgb2YgdGhpcyByZXBvcnQuCgpBIHN1cnByaXNpbmdseSBtb3JlIGVmZmVjdGl2ZSBtZXRob2QgZm9yICpzb2x2aW5nKiBvdXIgcHJlZGljdGlvbiBwcm9ibGVtIGlzIHNpbXBseSB3cmFuZ2xpbmcgcGFydHMgb2YgdGhlIGRhdGEgc2V0IHRoYXQgd2Ugd2FudCB0byBsb29rIGF0IGludG8gYSB3b3JrYWJsZSBmb3JtLCBhbmQgdGhlbiB2aXN1YWxpemluZyB0aGVzZSBwYXJ0cyB0aHJvdWdoIHZhcmlvdXMgcGxvdHMuIFRoZSBhZHZhbnRhZ2UgdGhhdCB0aGlzIG1ldGhvZCBoYXMgb3ZlciB0aGUgbW9yZSBjb21wbGV4IHByZWRpY3RpdmUgbW9kZWxzIGlzIHRoYXQgcGxvdHMgbWFrZSBpdCBtdWNoIGVhc2llciB0byBjb21wcmVoZW5kIGEgc2ltcGxlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGEgc2VsZWN0IGZldyB2YXJpYWJsZXMuIFRoaXMgbWFrZXMgaXQgbW9yZSBlZmZpY2llbnQgZm9yIHVzIHRvIHVuZGVyc3RhbmQgKGFuZCBjb21tdW5pY2F0ZSkgdGhlIHN0cm9uZyAob3Igd2VhaykgY29ycmVsYXRpb25zIHRoYXQgd2UgaGF2ZSBjb21lIGFjcm9zcyB3aXRoaW4gb3VyIGRhdGEgc2V0LiBXaGVuIGNvbXBhcmluZyB0aGlzIHRvIHRoZSBtb3JlIGNvbXBsaWNhdGVkIHByZWRpY3RpdmUgbW9kZWxzIGl0J3MgY2xlYXIgdGhhdCB0aGV5IGJvdGggaGF2ZSB0aGVpciBwbGFjZSB3aXRoaW4gYW55IGFuYWx5c2lzLiBIb3dldmVyLCBhcyB3ZSBkaXNjb3ZlciBsYXRlciBpbiBvdXIgcHJvY2VzcyBpdCdzIGNsZWFyIHRoYXQgb25lICdzZXQnIG9mIG1ldGhvZHMgd29ya2VkIGJldHRlciB0aGFuIHRoZSBvdGhlci4KCioqKgoKIyMgX19NZXRob2RvbG9neV9fCgpBcyB3aGF0IHdlJ3JlIGludGVyZXN0ZWQgaW4gaXMgYSB0ZWFtJ3Mgb3ZlcmFsbCBwZXJmb3JtYW5jZSBhbmQgdGhlIGRhdGEgc2V0IHRoYXQgd2UncmUgbG9va2luZyBhdCBpcyBzdHJ1Y3R1cmVkIGluIHRlcm1zIG9mIGVhY2ggaW5kaXZpZHVhbCBwbGF5ZXIncyBwZXJmb3JtYW5jZSwgb3VyIGZpcnN0IGh1cmRsZSB3ZSBoYWQgdG8ganVtcCBvdmVyIHdhcyBnZXR0aW5nIHRoZSBkYXRhIHNldCBpbnRvIGEgbW9yZSB3b3JrYWJsZSBmb3JtIGZvciB3aGF0IHdlJ3ZlIHNldCBvdXQgdG8gYWNoaWV2ZS4KClRoZSBmaXJzdCB0aGluZyB3ZSBkaWQgd2FzIGRlbGV0ZWQgY29sdW1ucyB3ZSBkZWVtZWQgd291bGQgYmUgbmVjZXNzYXJ5IGdvaW5nIGZvcndhcmQgaW4gb3VyIGFuYWx5c2lzOyB0aGUgb2J2aW91cyBjYW5kaWRhdGVzIHRvIGdvIHdlcmUgJ1BsYXllcicgYW5kICdQZXJjZW50IFBsYXllZCcgYXMgdGhleSdkIGJlIHVzZWxlc3Mgb25jZSB3ZSBjb21iaW5lZCBldmVyeXRoaW5nIHRvIGJlIGluIHRlcm1zIG9mIGFueSB0ZWFtcyBub3QgcGxheWVycy4gSG93ZXZlciwgc2xpZ2h0bHkgbGVzcyBvYnZpb3VzIHZhcmlhYmxlcyB0aGF0IHdlIHJlbW92ZWQgd2VyZSAnRnJlZXNBZ2FpbnN0JyBhbmQgJ1VuY29udGVzdGVkIFBvc3Nlc3Npb25zLicgV2UgZGlkIHRoaXMgaXMgYmVjYXVzZSBvdXIgb25jZSBvbmUgdGVhbXMgc3RhdGlzdGljcyBhcmUgcHV0IGFnYWluc3QgYW5vdGhlciB0ZWFtcyBzdGF0aXN0aWNzIGZvciBjb21wYXJpc29uIG9uZSB0ZWFtJ3MgJ0ZyZWVzRm9yJyB3b3VsZCBiZSBleGFjdGx5IHRoZSBzYW1lIGFzIHRoZSBvcHBvc2luZyB0ZWFtLCBhbmQgdmlzZSB2ZXJzYSAoc2FtZSB0aGluZyBmb3IgQ29udGVzdGVkIHZzIFVuY29udGVzdGVkIFBvc3Nlc3Npb25zKS4gU28sIHRvIHByZXZlbnQgZnV0dXJlIHByb2JsZW1zIGFuZCBjbHV0dGVyIHdlIGRlbGV0ZWQgdGhlc2UgZm91ciBjb2x1bW5zIGNvbXBsZXRlbHkgZnJvbSBvdXIgZGF0YSBzZXQuCgpgYGB7cn0KQUZMIDwtIEFGTHN0YXRzCkFGTCA8LSBBRkxbYygxLDMsNCw1LDYsNyw4LDksMTAsMTEsMTIsMTMsMTQsMTUsMTYsMTcsMTgsMTksMjAsMjEsMjIsMjMsMjUsMjcsMjgsMjksMzAsMzEpXQojY29sbmFtZXMoQUZMKQpgYGAKClRoZSBuZXh0IGxvZ2ljYWwgc3RlcCBpbiBvdXIgbWV0aG9kb2xvZ3kgd2FzIHRvIGFjdHVhbGx5IHNwbGl0IG91ciBkYXRhIHNldCBpbnRvIHRoZSBkaWZmZXJlbnQgdGVhbXMgdG90YWwgZ2FtZXMgYXMgdGhhdCdzIHdoYXQgd2UncmUgbW9zdCBpbnRlcmVzdGVkIGluLCBob3cgd2VsbCBvbmUgdGVhbSB3b3VsZCBwZXJmb3JtIGFnYWluc3QgYW55IG90aGVyLgoKYGBge3J9CmFsbF90ZWFtcyA8LSB1bmlxdWUoYXMuY2hhcmFjdGVyKEFGTCRUZWFtKSkKCmFkIDwtIEFGTFtBRkwkVGVhbSA9PSBhbGxfdGVhbXNbMV0sXQpibCA8LSBBRkxbQUZMJFRlYW0gPT0gYWxsX3RlYW1zWzJdLF0KY2x0IDwtIEFGTFtBRkwkVGVhbSA9PSBhbGxfdGVhbXNbM10sXQpjbHdkIDwtIEFGTFtBRkwkVGVhbSA9PSBhbGxfdGVhbXNbNF0sXQplc2RuIDwtIEFGTFtBRkwkVGVhbSA9PSBhbGxfdGVhbXNbNV0sXQpmZCA8LSBBRkxbQUZMJFRlYW0gPT0gYWxsX3RlYW1zWzZdLF0KZ2xuZyA8LSBBRkxbQUZMJFRlYW0gPT0gYWxsX3RlYW1zWzddLF0KZ2MgPC0gQUZMW0FGTCRUZWFtID09IGFsbF90ZWFtc1s4XSxdCmd3cyA8LSBBRkxbQUZMJFRlYW0gPT0gYWxsX3RlYW1zWzldLF0KaHQgPC0gQUZMW0FGTCRUZWFtID09IGFsbF90ZWFtc1sxMF0sXQptbGIgPC0gQUZMW0FGTCRUZWFtID09IGFsbF90ZWFtc1sxMV0sXQpubWxiIDwtIEFGTFtBRkwkVGVhbSA9PSBhbGxfdGVhbXNbMTJdLF0KcGFkIDwtIEFGTFtBRkwkVGVhbSA9PSBhbGxfdGVhbXNbMTNdLF0Kcm1kIDwtIEFGTFtBRkwkVGVhbSA9PSBhbGxfdGVhbXNbMTRdLF0Kc2sgPC0gQUZMW0FGTCRUZWFtID09IGFsbF90ZWFtc1sxNV0sXQpzeWQgPC0gQUZMW0FGTCRUZWFtID09IGFsbF90ZWFtc1sxNl0sXQp3YyA8LSBBRkxbQUZMJFRlYW0gPT0gYWxsX3RlYW1zWzE3XSxdCndiIDwtIEFGTFtBRkwkVGVhbSA9PSBhbGxfdGVhbXNbMThdLF0KYGBgCgpBZnRlciB0aGlzIGhhZCBiZWVuIGRvbmUgd2Ugc3RpbGwgZmFjZWQgdGhlIHByb2JsZW0gdGhhdCBvdXIgZGF0YSBpcyBpbiB0ZXJtcyBvZiByb3dzIG9mIHBsYXllciBzdGF0aXN0aWNzLCBhbmQgbm90IHJvd3Mgb2YgdG90YWwgZ2FtZSBzdGF0aXN0aWNzLiBUaHJvdWdoIHJpZ29yb3VzIHRyaWFsIGFuZCBlcnJvciB3ZSBjcmVhdGVkIGEgbmljZSwgbmVhdCBmdW5jdGlvbiB3aGljaCBjbGVhbnMgYWxsIHRoZSBkYXRhIGJ5IHdyYW5nbGluZyBpdCBpbnRvIHRoZSBmb3JtIHdlIHdhbnQgaXQgdG8gYmUgaW4gKHRvdGFsIHN0YXRpc3RpY3MgZm9yIGFueSBnaXZlbiBnYW1lKS4gSXQgaXMgYWxzbyBpbXBvcnRhbnQgdG8gbm90ZSB0aGF0IG9ubHkgZml2ZSBvZiB0aGUgdG90YWwgZ2FtZXMgaW4gdGhlIGRhdGEgc2V0IHJlc3VsdGVkIGluIGEgZHJhdyAoc2hvd24gYmVsb3cpLCBzbyBpbiBhbiBlZmZvcnQgc28gc2ltcGxpZnkgb3VyIHRoZSBkYXRhIHdlIGRlY2lkZWQgaXQgd291bGQgYmUgYmVzdCB0byBqdXN0IHJlbW92ZSB0aGVzZSBjYXNlcyAodGhpcyBvY2N1cnMgd2l0aGluIHRoZSBjbGVhbmluZyBmdW5jdGlvbikuCgpgYGB7cn0KIyBwbGF5ZXJzIHdoaWNoIHdlcmUgcGFydCBvZiBhIHRpZSBnYW1lIC8gbnVtYmVyIG9mIHBsYXllcnMgaW4gdGVhbSAvIG51bWJlciBvZiB0ZWFtcyBpbiBhIG1hdGNoCm5yb3coQUZMW0FGTCRXaW5Mb3NzID09ICJEIixdKSAvIDIyIC8gMgpgYGAKClRoaXMgaXMgdGhlIGZ1bmN0aW9uIHdoaWNoICdjbGVhbnMnIG91ciBkYXRhLiBJdCBlc3NlbnRpYWwgdGFrZXMgdGhlIGZpcnN0IG5pbmUgY29sdW1ucyBhbmQgdGFrZXMgb25lIGNvcHkgb2YgdGhlIGluZm9ybWF0aW9uIHRoZXJlIGFzIGl0J3MgdW5pcXVlIHRvIGVhY2ggbWF0Y2guIFRoZSByZW1haW5pbmcgY29sdW1ucyBhcmUgcGxheWVyIHN0YXRpc3RpY3Mgc28gdGhleSBhcmUganVzdCBzdW1tZWQgdG9nZXRoZXIgd2l0aCBhbGwgdGhlIG90aGVyIHNpbWlsYXIgdmFyaWFibGVzIHdpdGhpbiBhbnkgbWF0Y2ggdG8gZ2V0IHRoZSBkYXRhIGludG8gdGhlIGZvcm0gd2Ugd2FudCBpdCB0byBiZSBpbi4gQXMgbWVudGlvbmVkIGJlZm9yZSwgdGhlIGdhbWVzIHRoYXQgd2VyZSB0aWVkIHdlcmUgcmVtb3ZlZCBmcm9tIHRoZSBkYXRhIHNldCBpbiB0aGlzIHN0ZXAuCgpgYGB7cn0KY2xlYW5BRkxkYXRhIDwtIGZ1bmN0aW9uKHRlYW0pewogIAogIGxpYnJhcnkocGx5cikKICB0ZWFtX3N0YXRzIDwtIGRkcGx5KHRlYW0sIC4oRGF0ZSksIG51bWNvbHdpc2Uoc3VtKSkKICB0ZWFtX3N0YXRzIDwtIHRlYW1fc3RhdHNbYygxLDU6MjMpXQogIHRlYW1fa2VlcCA8LSB0ZWFtW21hdGNoKHVuaXF1ZSh0ZWFtJERhdGUpLCB0ZWFtJERhdGUpLF0KICB0ZWFtX2tlZXAgPC0gdGVhbV9rZWVwWzE6OV0KICB0ZWFtX2NsZWFuIDwtIG1lcmdlKHRlYW1fa2VlcCwgdGVhbV9zdGF0cykKICB0ZWFtX2NsZWFuIDwtIHRlYW1fY2xlYW5bdGVhbV9jbGVhbiRXaW5Mb3NzICE9ICJEIixdCiAgdGVhbV9jbGVhbiRXaW5Mb3NzIDwtIGRyb3BsZXZlbHModGVhbV9jbGVhbiRXaW5Mb3NzKQogIGxldmVscyh0ZWFtX2NsZWFuJFdpbkxvc3MpW2xldmVscyh0ZWFtX2NsZWFuJFdpbkxvc3MpPT0iTCJdIDwtIDAKICBsZXZlbHModGVhbV9jbGVhbiRXaW5Mb3NzKVtsZXZlbHModGVhbV9jbGVhbiRXaW5Mb3NzKT09IlciXSA8LSAxCiAgdGVhbV9jbGVhbiRXaW5Mb3NzIDwtIGZhY3Rvcih0ZWFtX2NsZWFuJFdpbkxvc3MpCiAgCiAgcmV0dXJuKHRlYW1fY2xlYW4pCiAgCn0KYGBgCgpgYGB7cn0KYWRfY2xlYW4gPC0gY2xlYW5BRkxkYXRhKGFkKQpibF9jbGVhbiA8LSBjbGVhbkFGTGRhdGEoYmwpCmNsdF9jbGVhbiA8LSBjbGVhbkFGTGRhdGEoY2x0KQpjbHdkX2NsZWFuIDwtIGNsZWFuQUZMZGF0YShjbHdkKQplc2RuX2NsZWFuIDwtIGNsZWFuQUZMZGF0YShlc2RuKQpmZF9jbGVhbiA8LSBjbGVhbkFGTGRhdGEoZmQpCmdsbmdfY2xlYW4gPC0gY2xlYW5BRkxkYXRhKGdsbmcpCmdjX2NsZWFuIDwtIGNsZWFuQUZMZGF0YShnYykKZ3dzX2NsZWFuIDwtIGNsZWFuQUZMZGF0YShnd3MpCmh0X2NsZWFuIDwtIGNsZWFuQUZMZGF0YShodCkKbWxiX2NsZWFuIDwtIGNsZWFuQUZMZGF0YShtbGIpCm5tbGJfY2xlYW4gPC0gY2xlYW5BRkxkYXRhKG5tbGIpCnBhZF9jbGVhbiA8LSBjbGVhbkFGTGRhdGEocGFkKQpybWRfY2xlYW4gPC0gY2xlYW5BRkxkYXRhKHJtZCkKc2tfY2xlYW4gPC0gY2xlYW5BRkxkYXRhKHNrKQpzeWRfY2xlYW4gPC0gY2xlYW5BRkxkYXRhKHN5ZCkKd2NfY2xlYW4gPC0gY2xlYW5BRkxkYXRhKHdjKQp3Yl9jbGVhbiA8LSBjbGVhbkFGTGRhdGEod2IpCmBgYAoKQWZ0ZXIgZ29pbmcgdGhyb3VnaCBhbGwgdGhpcyBlZmZvcnQgdG8gc3BsaXQgdGhlIGRhdGEgdG8gYmUgaW4gdGVybXMgb2Ygc2VwYXJhdGUgdGVhbXMgaXQgYWN0dWFsbHkgbWVhbnQgdGhhdCBmb3IgZWFjaCB0ZWFtIHdlIG9ubHkgaGFkIGEgdmVyeSBzbWFsbCBzZXQgb2YgZGF0YSBwb2ludHMuIFRoaXMgbWFkZSBhbnkgcHJlZGljdGlvbiBtb2RlbHMgZm9yIGVhY2ggaW5kaXZpZHVhbCB0ZWFtIGltcG9zc2libGUgYXMgdGhlIHRyYWluaW5nIHNldCAoMjAxMiAtIDIwMTUpIG9ubHkgaGFkIHJvdWdobHkgMTAwIHJvd3MgYW5kIG91ciB0ZXN0IHNldCAoMjAxNikgb25seSBoYWQgYWJvdXQgMjUgcm93czsgd2hpY2ggUiBkaWRuJ3QgdGhpbmsgd2FzIGVub3VnaCBkYXRhIGZvciB0aGUgcHJlZGljdGl2ZSBtb2RlbHMgd2Ugd2FudGVkIHRvIGRvLiBTbyB3ZSBlbmRlZCB1cCBqdXN0IGNvbWJpbmluZyBldmVyeXRoaW5nIGJhY2sgaW50byBvbmUgbmljZSBiaWcgZGF0YSBzZXQgKGFmdGVyIGJlaW5nIGNsZWFuZWQpLgoKYGBge3J9CkFGTF9jbGVhbiA8LSByYmluZChhZF9jbGVhbiwgYmxfY2xlYW4sIGNsdF9jbGVhbiwgY2x3ZF9jbGVhbiwgZXNkbl9jbGVhbiwgZmRfY2xlYW4sIGdsbmdfY2xlYW4sIAogICAgICAgICAgICAgICAgICAgZ2NfY2xlYW4sIGd3c19jbGVhbiwgaHRfY2xlYW4sIG1sYl9jbGVhbiwgbm1sYl9jbGVhbiwgcGFkX2NsZWFuLCBybWRfY2xlYW4sCiAgICAgICAgICAgICAgICAgICBza19jbGVhbiwgc3lkX2NsZWFuLCB3Y19jbGVhbiwgd2JfY2xlYW4pCiNsZW5ndGgodW5pcXVlKEFGTF9jbGVhbiRUZWFtKSkKYGBgCgpPbmNlIG91ciBkYXRhIHdhcyAqb25jZSBhZ2FpbiogaW4gb25lIGJpZywgY29tYmluZWQgZGF0YSBmcmFtZSB3ZSBkZWNpZGVkIChhbmQgUiBhY2NlcHRlZCBvdXIgZGVjaXNpb24pIGl0IHdhcyBmaW5hbGx5IHRpbWUgdG8gc3VjY2Vzc2Z1bGx5IHNwbGl0IG91ciBkYXRhIGludG8gYSBzZXBhcmF0ZSB0cmFpbmluZyBhbmQgdGVzdCBzZXQuIEl0IG1hZGUgc2Vuc2UgZm9yIG91ciB0cmFpbmluZyBzZXQgdG8gYmUgYWxsIHRoZSBnYW1lcyBpbiAyMDEyIC0gMjAxNSAoaW5jbHVzaXZlKSBhbmQgdGhlbiBvdXIgdGVzdCBzZXQgdG8gYmUganVzdCB0aGUgbWF0Y2hlcyBwbGF5ZWQgaW4gdGhlIGxhdGVzdCAoaW4gb3VyIGRhdGEgc2V0KSAyMDE2IHNlYXNvbi4gVGhpcyBtYWRlIHNlbnNlIGFzIG91ciBnb2FsIGlzIHRvIHByZWRpY3QgdGhlIGN1cnJlbnQgKDIwMTcpIG1hdGNoZXMgc28gaGF2aW5nIG91ciB0ZXN0IHNldCBiZWluZyB0aGUgY2xvc2VzdCB0byB0aGF0IGFzIHBvc3NpYmxlIG1lYW50IG91ciBwcmVkaWN0aXZlIG1vZGVscyB3b3VsZCAoaW4gdGhlb3J5KSAndHVuZScgb3VyIG1vZGVsIHRvIGJlIGFzIGFjY3VyYXRlIGZvciB0aGUgY3VycmVudCBzZWFzb24gYXMgd2UgY291bGQgaG9wZSBmb3IuCgpgYGB7cn0KQUZMLnRlc3QgPC0gQUZMX2NsZWFuW0FGTF9jbGVhbiRTZWFzb24gPT0gMjAxNixdCiNoZWFkKEFGTC50ZXN0KQpBRkwudHJhaW4gPC0gQUZMX2NsZWFuW0FGTF9jbGVhbiRTZWFzb24gIT0gMjAxNixdCiNoZWFkKEFGTC50cmFpbikKYGBgCgpOZXh0IHdlIGRlY2lkZWQgdG8gZG8gYSBsaXR0bGUgZXhwbG9yYXRvcnkgYW5hbHlzaXMgb2Ygb3VyIHRyYWluaW5nIHNldCwgdGhpcyB3YXMgdG8gbWFrZSBzdXJlIGV2ZXJ5dGhpbmcgbWFrZXMgbG9naWNhbCBzZW5zZSAoY2hlY2sgd2UgaGF2ZW4ndCBtYWRlIGFuIGVycm9yIGR1cmluZyBvdXIgY2xlYW5pbmcgcHJvY2VzcyksIGFuZCBqdXN0IHRvIGV4cGxvcmUgdGhlIGRhdGEgYW5kIHNlZSBpZiB3ZSBjYW4gZmluZCBhbnl0aGluZyBpbnRlcmVzdGluZy4KCmBgYHtyfQpwbG90KEFGTC50cmFpbiRXaW5Mb3NzLCBBRkwudHJhaW4kRGlzcG9zYWxzKQpgYGAKCmBgYHtyfQpwbG90KEFGTC50cmFpbiRXaW5Mb3NzLCBBRkwudHJhaW4kSW5zaWRlNTBzKQpgYGAKCmBgYHtyfQpwbG90KEFGTC50cmFpbiRXaW5Mb3NzLCBBRkwudHJhaW4kQ2xlYXJhbmNlcykKYGBgCgpGcm9tIHRoZXNlIGZldyBwbG90cyB3ZSBjYW4gc2VlIHRoYXQgb3VyIGRhdGEgbG9va3MgdG8gYmUgaW50YWN0LCBhcyB3ZSBhY3R1YWxseSBnb3QgZ2l2ZW4gZnVuY3Rpb25hbCBib3ggcGxvdHMgYXMgb3V0cHV0cy4gQW5kIG1vcmUgaW1wb3J0YW50bHkgaXQgc2VlbXMgdGhhdCBhdCBsZWFzdCBzb21lIG9mIHRoZXNlIHZhcmlhYmxlcyBoYXZlIHNvbWUgc29ydCBvZiBhIGNvcnJlbGF0aW9uIHdpdGggdGVhbXMgd2hvJ3ZlIHdvbiAoMSkgYW5kIHRlYW1zIHdobyd2ZSBsb3N0ICgwKS4gVGhpcyBtZWFudCB0aGF0IHNvbWUgb2Ygb3VyIHZhcmlhYmxlcyBtaWdodCBiZSBzdHJvbmcgY2FuZGlkYXRlcyBpbiBiZWluZyBhYmxlIHRvIGFzc2lzdGFuY2UgdXMgaW4gcHJlZGljdGluZyB0aGUgb3V0Y29tZXMgb2YgZnV0dXJlIGdhbWVzLgoKQXMgYSBzZWNvbmQgbWVhc3VyZSB0byB0aGlzIHByb2Nlc3Mgd2UgY3JlYXRlZCBhIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50IGhpc3RvZ3JhbSBtYXRyaXggd2l0aCBhbGwgb2Ygb3VyIHZhcmlhYmxlcyB0byBzZWUgaWYgYW55dGhpbmcgaGFkIGEgcGFydGljdWxhcmx5IHN0cm9uZyBjb3JyZWxhdGlvbiB3aXRoIG91ciAnV2luTG9zcycgdmFyaWFibGUuCgpgYGB7ciAwMDAxLCBmaWcud2lkdGg9MTUsIGZpZy5oZWlnaHQ9MTIsIGV2YWw9RkFMU0V9CnNvdXJjZSgiUGFpcnNXaXRoSGlzdC5SIikKcGFpcnMoQUZMX2NsZWFuLCBsb3dlci5wYW5lbCA9IHBhbmVsLnB0cywgdXBwZXIucGFuZWwgPSBwYW5lbC5jb3IsIGRpYWcucGFuZWwgPSBwYW5lbC5oaXN0KQpgYGAKCk91ciBuZXh0IHN0ZXAgd2FzIHRvIGFjdHVhbGx5IGJlZ2luIHByZXBhcmluZyB0byBtYWtlIHNvbWUgcHJlZGljdGl2ZSBtb2RlbHM7IHdoaWNoIHdhc24ndCBqdXN0IGFzIHNpbXBsZSBhcyBmaXR0aW5nIGEgbW9kZWwgd2l0aCBhbGwgdGhlIHZhcmlhYmxlcyBhbmQgdGhlbiBmaXR0aW5nIGFub3RoZXIgbW9kZWwgd2l0aCBub25lLCBhbmQgdGhlbiBydW5uaW5nIGZvcndhcmQgc2VsZWN0aW9uIGJldHdlZW4gdGhlIHR3byAoYWx0aG91Z2ggdGhhdCB3YXMgKm9uZSogc3RlcCB3aXRoaW4gdGhlIHByb2Nlc3MpLiBBZnRlciBzb21lIHRyaWFsIGFuZCBlcnJvciBhbmQgdGhvdWdodCBpbnRvIHdoYXQgd2Ugd2VyZSBhY3R1YWxseSBkb2luZyBzb21lIHRoaW5ncyBiZWNhbWUgY2xlYXI7IHdlIGhhZCB0b28gbWFueSB2YXJpYWJsZXMgYW5kIHNvbWUgdmFyaWFibGVzIGp1c3QgZGlkbid0IG1ha2Ugc2Vuc2UgYmVpbmcgaW4gb3VyIG1vZGVsKHMpLgoKVG8gcmVkdWNlIG91ciB0b3RhbCBhbW91bnQgb2YgdmFyaWFibGVzIHdlIGZpcnN0IHJlbW92ZWQgYWxsIHRoZSBjYXRlZ29yaWNhbCBleHBsYW5hdG9yeSB2YXJpYWJsZXMuIE91ciByZWFzb24gZm9yIGRvaW5nIHRoaXMgaXMgdGhhdCBlYWNoIGxldmVsIG9mIGEgZmFjdG9yIHZhcmlhYmxlIHdpdGhpbiBhIHByZWRpY3RpdmUgbW9kZWwgYmVjb21lcyBpdHMgb3duIHZhcmlhYmxlLCAqbm90KiBqdXN0IHRoZSBvbmUgZmFjdG9yIHZhcmlhYmxlIGl0c2VsZi4gRm9yIGV4YW1wbGUsIGJ5IGluY2x1ZGluZyB0aGUgZmFjdG9yIHZhcmlhYmxlICdWZW51ZScgd2UgYXJlIGludHJvZHVjaW5nIGlzIDE5IG5ldyBleHBsYW5hdG9yeSB2YXJpYWJsZXMgaW50byBvdXIgbW9kZWwsIG5vdCBzaW1wbHkganVzdCB2ZW51ZS4KClRoZSBuZXh0IHByb2JsZW0gd2FzIHRoYXQgdGhlICdNYXJnaW4nIHZhcmlhYmxlIHdhcyBhICoqcGVyZmVjdCoqIHByZWRpY3RvciBvZiB3aGV0aGVyIGEgdGVhbSB3b3VsZCB3aW4gb3IgbG9zZS4gSWYgdGhlIG1hcmdpbiBmb3IgYSBnYW1lIHdhcyBncmVhdGVyIHRoYW4gemVybyB0aGUgdGVhbSBoYWQgd29uLCBpZiB0aGUgbWFyZ2luIHdhcyBuZWdhdGl2ZSB0aGVuIHRoZSB0ZWFtIGhhZCBsb3N0LiBCeSBpbmNsdWRpbmcgdGhpcyBpbiBvdXIgbW9kZWwgaXQgd291bGQgaGF2ZSBoYWQgc3VjaCBhIHN0cm9uZyBjb3JyZWxhdGlvbiB0aGF0IGFsbCB0aGUgb3RoZXIgdmFyaWFibGVzLCB3aGljaCBhcmUgYXJndWFibHkgbW9yZSB1c2VmdWwgZm9yIG91ciBvdmVyYWxsIGdvYWwsIHdvdWxkIGJlIGxvc3QgYXMgbm9pc2U7IHNvIHdlIGhhZCB0byByZW1vdmUgaXQuCgpWYXJpYWJsZXMgbGlrZSAnU2NvcmUnIGFuZCAnR29hbHMnIHdlcmUgaW4gYSBzaW1pbGFyIHNvcnQgb2YgYm9hdCBiZWNhdXNlIHRlYW1zIHdobyB3aW4gYXJlIGFsd2F5cyBnb2luZyB0byBoYXZlIGEgaGlnaGVyIHNjb3JlLCBiZWNhdXNlIHRoYXQncyBob3cgeW91IHdpbiB0aGUgZ2FtZS4gVGhpcyBpcyBzdWNoIGEgYmFzaWMgcHJlbWlzZSB0aGF0IGl0IHJlYWxseSBtYWRlIG5vIHNlbnNlIHRvIGluY2x1ZGUgaW4gb3VyIG1vZGVsIGFzIGl0IHdhcyBqdXN0IGFkZGluZyBub2lzZS4gQW5kIHRoZSBsYXN0IHNldCBvZiB2YXJpYWJsZXMgd2UgZGlkbid0IGluY2x1ZGUgaW4gb3VyIG1vZGVsIHdlcmUgJ0hhbmRiYWxscycgYW5kICdLaWNrcycgYXMgdGhleSBhcmUganVzdCBzdWJzZXRzIG9mIHRoZSAnRGlzcG9zYWwnIHZhcmlhYmxlLCBtYWtpbmcgaXQgcG9pbnRsZXNzIHRvIGluY2x1ZGUgYWxsIHRocmVlIHdpdGhpbiBvdXIgbW9kZWwuCgpBZnRlciBhbGwgb2YgdGhlc2UgJ3R5cGVzJyBvZiB2YXJpYWJsZXMgd2VyZSBleGNsdWRlZCBmcm9tIG91ciBtb2RlbCB3ZSB3ZXJlIGxlZnQgd2l0aCB3aGF0IHdlIHdpdGggdGhlIG1ham9yaXR5IG9mIHRoZSBpbnRlZ2VyIG1hdGNoIHN0YXRpc3RpY3MgbGlrZSAnRGlzcG9zYWxzLCcgJ0luc2lkZTUwcywnICdDbGFuZ2VycywnIGV0Yy4KCmBgYHtyfQojIGp1c3QgJ251bWVyaWNhbCcgdmFyaWFibGVzCkFGTC5nbG0ubnVtIDwtIGdsbShXaW5Mb3NzIH4gIERpc3Bvc2FscyArIE1hcmtzICsgQmVoaW5kcyArIEluc2lkZTUwcyArIENsZWFyYW5jZXMgKyBDbGFuZ2VycyArIENvbnRlbmRlZFBvc3Nlc3Npb25zICsgQ29udGVzdGVkTWFya3MgKyBNYXJrc0luc2lkZTUwLCAKICAgICAgICAgICAgICAgICAgZGF0YSA9IEFGTC50cmFpbiwgZmFtaWx5ID0gYmlub21pYWwobG9naXQpKQpgYGAKClRoZW4gd2Ugc2V0IHVwIGEgbW9kZWwgd2l0aCAqbm8qIGV4cGxhbmF0b3J5IHZhcmlhYmxlcy4KCmBgYHtyfQpBRkwuZ2xtLjAgPC0gZ2xtKFdpbkxvc3MgfiAxLCBkYXRhID0gQUZMLnRyYWluLCBmYW1pbHkgPSBiaW5vbWlhbChsb2dpdCkpCmBgYAoKQW5kIGZpbmFsbHkgd2UgY29tcGFyZWQgdGhlc2UgdHdvIG1vZGVscyB0byBmaW5kIHRoZSBvcHRpbWFsIHNldCBvZiB2YXJpYWJsZXMgd2Ugc2hvdWxkIGJlIGluY2x1ZGluZyBpbiBvdXIgZmluYWwgbW9kZWwuIFdoaWNoIGJ5IGxvb2tpbmcgYXQgdGhlIHN1bW1hcnkgYmVsb3cgeW91IG1pZ2h0IGhhdmUgbm90aWNlZCBsZWZ0IHVzIHdpdGggc2V2ZW4gZXhwbGFuYXRvcnkgdmFyaWFibGVzIGluIG91ciBmaW5hbCBtb2RlbDsgcmVtb3ZpbmcgJ0NvbnRlc3RlZE1hcmtzJyBhbmQgJ0JlaGluZHMnIGFzIGZvcndhcmQgc2VsZWN0aW9uIGRpZG4ndCBmaW5kIHRoZW0gcmVsZXZhbnQuCgpBbGwgdGhlIHZhcmlhYmxlcyBsZWZ0IGluIHRoZSBtb2RlbCBhbHNvIGhhdmUgdmVyeSBzbWFsbCBwLXZhbHVlcyB3aGljaCBpcyBhbHdheXMgYSBnb29kIHNpZ24gdGhhdCB0aGV5ICpjb3VsZCogYmUgaGlnaGx5IGNvcnJlbGF0ZWQgdG8gdGhlIHJlc3BvbnNlIHZhcmlhYmxlICh3aW5uaW5nIGEgbWF0Y2gpLgoKYGBge3J9CkFGTC5nbG0uZndkIDwtIHN0ZXAoQUZMLmdsbS4wLCBzY29wZSA9IGZvcm11bGEoQUZMLmdsbS5udW0pLCBkaXJlY3Rpb24gPSAiZm9yd2FyZCIsIHRyYWNlID0gMCkKc3VtbWFyeShBRkwuZ2xtLmZ3ZCkKYGBgCgoqKioKCiMjIF9fQW5hbHlzaXNfXwojIyMgTG9naXN0aWMgUmVncmVzc2lvbgoKVGhlIGZpcnN0IHByZWRpY3RpdmUgbW9kZWwgdGhhdCB3ZSBkZWNpZGVkIHRvIGltcGxlbWVudCB3YXMgYSBMb2dpc3RpYyBSZWdyZXNzaW9uIG1vZGVsLCB3aXRoICdXaW5Mb3NzJyBiZWluZyBvdXIgcmVzcG9uc2UgdmFyaWFibGUsIG9idmlvdXNseSB3aXRoIGEgJzEnICh3aW5uaW5nIGdhbWUpIGJlaW5nIHRoZSBwcmVmZXJyZWQgb3V0Y29tZS4KCmBgYHtyfQpBRkwuYWxsLnByZWQgPC0gcHJlZGljdChBRkwuZ2xtLmZ3ZCwgbmV3ZGF0YSA9IEFGTC50ZXN0LCB0eXBlID0gInJlc3BvbnNlIikKI2hlYWQoQUZMLmFsbC5wcmVkKQpgYGAKCkFmdGVyIHRoZSBtb2RlbCBoYWQgbWFkZSBpdHMgcHJlZGljdGlvbnMgdXNpbmcgb3VyIHRlc3QgZGF0YSB0byAndHVuZScgaXQsIHdlIGhhZCB0byBjb21wYXJlIHRoZXNlIHByZWRpY3Rpb25zIHRvIHRoZSBhY3R1YWwgdHJ1ZSwgcHJlZGljdGVkIG91dGNvbWVzIGZvciAyMDE2LiBUaGUgbW9zdCBlZmZpY2llbnQgd2F5IG9mIGdvaW5nIGFib3V0IHRoaXMgd2FzIHRvIGNyZWF0ZSBhIGNvbmZ1c2lvbiBtYXRyaXggb2Ygb3VyIHByZWRpY3RlZCByZXN1bHRzIGFnYWluc3QgdGhlIHRydWUgcmVzdWx0cywgdGhpcyBnaXZlcyB1cyBhbiBpZGVhIG9mIGhvdyBhY2N1cmF0ZSBvdXIgbW9kZWwgYWN0dWFsbHkgaXMuCgpgYGB7cn0KQUZMLmFsbC5wcmVkLmNsYXNzIDwtIHJlcCgwLCBsZW5ndGgoQUZMLmFsbC5wcmVkKSkKQUZMLmFsbC5wcmVkLmNsYXNzW0FGTC5hbGwucHJlZCA+IDAuNzVdIDwtIDEKdGFibGUoQUZMLmFsbC5wcmVkLmNsYXNzLCBBRkwudGVzdCRXaW5Mb3NzKQpgYGAKYGBge3J9CigxODgrMTMyKS8oMTg4Kzc1KzE5KzEzMikKYGBgCgpGcm9tIHRoaXMgY29uZnVzaW9uIG1hdHJpeCB3ZSBjYW4gc2VlIHRoYXQgYWJvdXQgNzclIG9mIG91ciBwcmVkaWN0aW9ucyB3ZXJlIGNvcnJlY3Qgd2hlbiB3ZSB1c2VkIGEgY3V0LW9mZiB2YWx1ZSBvZiAwLjc1LiBUaGlzIG1lYW5zIHRoYXQgYW55IGdhbWUgcHJlZGljdGVkIGJ5IG91ciBtb2RlbCB0aGF0IGhhcyBhYm92ZSBhIDc1JSBjaGFuY2Ugb2Ygd2lubmluZyB3aWxsIG9ubHkgdGhlbiBiZSBjbGFzc2lmaWVkIGFzIGEgJ3N1cmUgd2luLicgVGhpcyBjdXQtb2ZmIHNlZW1zIGxpa2UgYSBmYWlyIGFzc3VtcHRpb24gYmVjYXVzZSwgYXNzdW1pbmcgdGhlIG1vZGVsIGFjdHVhbGx5IHdvcmtlZCBpbiB0aGUgd2F5IHdlIHdhbnRlZCBpdCB0bywgZXZlcnkgZm91ciBnYW1lcyB5b3UgcGxhY2VkIGEgYmV0IG9uIHlvdSdkIG9ubHkgbG9zZSBvbmUgb2YgdGhvc2UgZm91ci4gQW5kIHdoZW4geW91IGZhY3RvciBpbiBldmVuIHNvbWUgYXZlcmFnZSBvZGRzIHlvdSdkIGFsbW9zdCBhbHdheXMgY29tZSBvdXQgcHJvZml0YWJsZSBieSBhIGxvbmcgc2hvdCBpZiB0aGF0IHdhcyB0aGUgY2FzZS4KClRoaXMgbW9kZWwgaGFzIGEgcHJldHR5IHJlYXNvbmFibGUgc3VjY2VzcyByYXRlIGV2ZW4gd2hlbiB0aGlzIGhpZ2ggY3V0LW9mZiBpcyBwdXQgaW4gcGxhY2UgaG93ZXZlciwgaXQgc3VmZmVycyBmcm9tIHRoZSBzYW1lICdwcm9ibGVtJyB0aGF0IGFsbCBvdXIgb3RoZXIgcHJlZGljdGl2ZSBtb2RlbHMgZG8gKGRpc2N1c3NlZCBhZnRlciBhbGwgdGhlIHByZWRpY3RpdmUgbW9kZWxzIGhhdmUgYmVlbiAnc2hvd2Nhc2VkJykuCgojIyMgSy1OZWFyZXN0IE5laWdoYm91cnMKCkFmdGVyIG91ciBMb2dpc3RpYyBSZWdyZXNzaW9uIG1vZGVsIGNhbWUgb3V0IGFzIHN1Y2ggYSBzdWNjZXNzIHdlIGRlY2lkZWQgdGhhdCB0aGUgbmV4dCBiZXN0IHN0ZXAgd291bGQgYmUgdG8gdHJ5IGEgSy1OZWFyZXN0IE5laWdoYm9ycyBtb2RlbCB0byBzZWUgaWYgaXQncyBtb3JlIG9yIGxlc3MgYWNjdXJhdGUgd2hlbiBjb21wYXJlZCB0byBvdXIgcHJldmlvdXMgcHJlZGljdGl2ZSBtb2RlbC4KCmBgYHtyfQpsaWJyYXJ5KGNsYXNzKQpBRkwua25uLnByZWQgPC0ga25uKEFGTC50cmFpblssYygiRGlzcG9zYWxzIiwgIk1hcmtzIiwgIkluc2lkZTUwcyIsICJDbGVhcmFuY2VzIiwgIkNsYW5nZXJzIiwgIkNvbnRlbmRlZFBvc3Nlc3Npb25zIiwgIk1hcmtzSW5zaWRlNTAiKV0sIEFGTC50ZXN0WyxjKCJEaXNwb3NhbHMiLCAiTWFya3MiLCAiSW5zaWRlNTBzIiwgIkNsZWFyYW5jZXMiLCAiQ2xhbmdlcnMiLCAiQ29udGVuZGVkUG9zc2Vzc2lvbnMiLCAiTWFya3NJbnNpZGU1MCIpXSwgQUZMLnRyYWluJFdpbkxvc3MsIAogICAgayA9IDMpCnRhYmxlKEFGTC5rbm4ucHJlZCwgQUZMLnRlc3QkV2luTG9zcykKYGBgCmBgYHtyfQooMTM5KzE2NykvKDEzOSs0MCs2OCsxNjcpCmBgYAoKQW5kLCBwZXJoYXBzIHVuc3VycHJpc2luZ2x5LCB0aGUgSy1OZWFyZXN0IE5laWdoYm9ycyBtb2RlbCByZXN1bHRlZCBpbiBhIHByZWRpY3RlZCBwcm9iYWJpbGl0eSB3aGljaCBpcyBvbmx5IHJvdWdobHkgNCUgYmVoaW5kIHRoZSBMb2dpc3RpYyBSZWdyZXNzaW9uIG1vZGVsLiBUaGlzIHNob3dzIGFnYWluIHRoYXQgb3VyIG1vZGVscyBhcmUgY29uc2lzdGVudGx5IHByZWRpY3RpbmcgYXQgYSBtdWNoIGJldHRlciByYXRlIHRoZW4gYSA1MC81MCBndWVzcy4gSG93ZXZlciwgdGhpcyBtb2RlbCB1c2VzIHRoZSBzYW1lIHNldCBvZiB2YXJpYWJsZXMgYW5kIHRodXMgc3VmZmVycyBmcm9tIHRoZSBzYW1lIHByb2JsZW0gYXMgdGhlIHByZXZpb3VzLgoKIyMjIERlY2lzaW9uIFRyZWUocykKCldlJ2QgZG9uZSBhIExvZ2lzdGljIFJlZ3Jlc3Npb24gYW5kIGEgSy1OZWFyZXN0IE5laWdoYm9ycyBtb2RlbCwgc28gaXQgcmVhbGx5IG9ubHkgbWFkZSBzZW5zZSB0byBmaW5pc2ggdGhlIHRyaW8gYnkgYXR0ZW1wdGluZyB0byBjcmVhdGUgYSBEZWNpc2lvbiBUcmVlIG9yIE1hbnkgRm9yZXN0cyBtb2RlbC4KCmBgYHtyfQpsaWJyYXJ5KHJwYXJ0KQpBRkwubnVtLnRyZWUgPC0gcnBhcnQoV2luTG9zcyB+ICBEaXNwb3NhbHMgKyBNYXJrcyArIEJlaGluZHMgKyBJbnNpZGU1MHMgKyBDbGVhcmFuY2VzICsgQ2xhbmdlcnMgKyBDb250ZW5kZWRQb3NzZXNzaW9ucyArIENvbnRlc3RlZE1hcmtzICsgTWFya3NJbnNpZGU1MCwgCiAgICAgICAgICAgICAgICAgIEFGTF9jbGVhbikKYGBgCgpgYGB7cn0KQUZMLm51bS50cmVlLnByZWQgPSBwcmVkaWN0KEFGTC5udW0udHJlZSwgQUZMLnRlc3QpCkFGTC5udW0udHJlZS5wcmVkIDwtIEFGTC5udW0udHJlZS5wcmVkWywyXQojaGVhZChBRkwubnVtLnRyZWUucHJlZCkKYGBgCgpgYGB7cn0KQUZMLm51bS50cmVlLmNsYXNzIDwtIHJlcCgwLCBsZW5ndGgoQUZMLm51bS50cmVlLnByZWQpKQpBRkwubnVtLnRyZWUuY2xhc3NbQUZMLm51bS50cmVlLnByZWQgPiAwLjc1XSA8LSAxCnRhYmxlKEFGTC5udW0udHJlZS5jbGFzcywgQUZMLnRlc3QkV2luTG9zcykKYGBgCmBgYHtyfQooMTcyICsgMTM3KS8oMTcyKzcwKzM1KzEzNykKYGBgCgpUbyBvdXIgc3VycHJpc2UgdGhlIE1hbnkgRm9yZXN0cyBtb2RlbCBhY3R1YWxseSBwcmVkaWN0ZWQgd2l0aCBhbiBhbG1vc3QgaWRlbnRpY2FsIHN1Y2Nlc3MgcmF0ZSBhcyB0aGUgSy1OZWFyZXN0IE5laWdoYm9ycyBtb2RlbCBkaWQuIEkgZ3Vlc3MgdGhpcyBqdXN0IHNob3dzIHRoYXQgb3VyIHZhcmlhYmxlcyBtdXN0IGhhdmUgcXVpdGUgZXZlbiBzcGxpdHMgd2l0aCByZXNwZWN0IHRvIHdpbnMgYW5kIGxvc3Nlcy4gQWdhaW4sIHRoaXMgbW9kZWwgc3VmZmVycyBmcm9tIHRoZSBzYW1lIHByb2JsZW0gYXMgdGhlIHByZXZpb3VzIHR3by4KCkhvd2V2ZXIsIHRoaXMgbW9kZWwgd2Fzbid0IGFzIHVzZWxlc3MgYXMgdGhlIHByZXZpb3VzIHR3byBtb2RlbHMgYmVjYXVzZSB3ZSBjYW4gYWN0dWFsbHkgdmlzdWFsaXplIHRoZSBkaWZmZXJlbnQgc3BsaXRzIHRoYXQgdGhlIERlY2lzaW9uIFRyZWUgdXNlcyB3aGljaCBnaXZlcyB1cyB2YWx1YWJsZSBpbnNpZ2h0IGludG8gaG93IGRpZmZlcmVudCBjb21iaW5hdGlvbnMgb2YgdmFyaWFibGVzIGludGVyYWN0IHRvIGVpdGhlciBpbXByb3ZlIHlvdXIgY2hhbmNlcyBvZiB3aW5uaW5nIG9yIGh1cnQgdGhlbS4KCmBgYHtyIDAwMDIsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD03LCBldmFsPUZBTFNFfQpsaWJyYXJ5KHJwYXJ0LnBsb3QpCmxpYnJhcnkocmFuZG9tRm9yZXN0KQpsaWJyYXJ5KHBhcnR5a2l0KQpwbG90KGFzLnBhcnR5KEFGTC5udW0udHJlZSkpCmBgYAoKVGhlIERlY2lzaW9uIFRyZWUgZGlhZ3JhbSBpcyBvbmUgb2YgdGhlIG1vcmUgdmFsdWFibGUgdGhpbmdzIHRvIGNvbWUgb3V0IG9mIHRoZSBhbmFseXNpcyB3aXRoIHJlc3BlY3QgdG8gb3VyIGdvYWwgdG8gcHJlZGljdCB0aGUgb3V0Y29tZSBvZiBmdXR1cmUgZ2FtZXMuIEJ5IGp1c3QgZm9sbG93aW5nIHRoZSByaWdodCBtb3N0IHBhdGggb2YgdGhlIGRpYWdyYW0gd2UgY2FuIHNlZSB0aGF0IG1vcmUgSW5zaWRlNTBzIHBhaXJlZCB3aXRoIG1vcmUgTWFya3NJbnNpZGU1MCBpcyBhICdyZWNpcGUnIGZvciBhIHZlcnkgaGlnaCBjaGFuY2Ugb2Ygd2lubmluZzsgd2hpY2ggc2VlbXMgcXVpdGUgb2J2aW91cy4gQnkgZm9sbG93aW5nIHRoZSBsZWZ0IG1vc3QgcGF0aCB3ZSBjYW4gc2VlIHRoZSBjb21wbGV0ZSBvcHBvc2l0ZSwgZmV3ZXIgSW5zaWRlNTBzIHBhaXJlZCB3aXRoIGZld2VyIE1hcmtzSW5zaWRlNTAgcmVzdWx0cyBtb3JlIG9mdGVuIHRoZW4gbm90IGluIGEgbG93ZXIgY2hhbmNlIG9mIHdpbm5pbmc7IHdoaWNoIGFnYWluIHNlZW1zIHF1aXRlIG9idmlvdXMuCgpUaGlzIGRpYWdyYW0gb25seSByZWFsbHkgc3RhcnRzIHRvIGdldCBpbnRlcmVzdGluZyB3aGVuIHlvdSBsb29rIGF0IHRoZSBjb21iaW5hdGlvbnMgb2YgdGhlIG1hbnkgZGlmZmVyZW50IHZhcmlhYmxlcy4gRm9yIGV4YW1wbGUgaWYgYSB0ZWFtIGlzbid0IGdldHRpbmcgYSBsb3Qgb2YgSW5zaWRlNTBzIGJ1dCBpcyBnZXR0aW5nIGEgbG90IG9mIE1hcmtzSW5zaWRlNTAsIGFuZCB0aGVuIGFsc28gdGhlIHRlYW0gaGFzIGEgZGVjZW50IGFtb3VudCBvZiBNYXJrcyBvdmVyYWxsIHRoZW4gdGhleSBzdWRkZW5seSBoYXZlIGEgbXVjaCBiZXR0ZXIgY2hhbmNlIGF0IHdpbm5pbmcuCgpUaGlzIGRpYWdyYW0gbWlnaHQgYmUgZXNwZWNpYWxseSB1c2VmdWwgZm9yIHNvbWV0aGluZyBsaWtlIGhhbGYtdGltZSBiZXR0aW5nLiBJZiB0d28gdGVhbXMgYXJlIGFsbW9zdCBuZWNrIHRvIG5lY2sgYXQgaGFsZi10aW1lIGJ1dCB0aGVuIG9uZSB0ZWFtIGlzIGZvbGxvd2luZyBvbmUgb2YgdGhlc2UgJ3BhdGhzJyB0aGF0IGxlYWQgdG8gYSBoaWdoZXIgcHJvcG9ydGlvbiBvZiB3aW5zIHRoZW4gaXQgbWlnaHQgYmUgaW4geW91ciBiZXN0IGludGVyZXN0IHRvIGJldCBvbiB0aGF0IHRlYW0gb3ZlciB0aGVpciBvcHBvc2l0aW9uLiBJbiBubyB3YXkgaXMgaXQgYSBwZXJmZWN0IHNldCBvZiBwYXRocyB0aGF0IGxlYWQgdG8gdmljdG9yeSBmb3IgYSB0ZWFtIGhvd2V2ZXIsIHVzaW5nIGl0IGlzIGNlcnRhaW5seSBhIGxpdHRsZSBtb3JlIHVzZWZ1bCB0aGVuIGJsaW5kbHkgcGlja2luZyBvbmUgdGVhbSBvciB0aGUgb3RoZXIuCgojIyMgVGhlIFByb2JsZW0KClBlcmhhcHMgYSBsaXR0bGUgZm9yZXNpZ2h0IGludG8gd2hhdCBvdXIgbW9kZWxzIGFyZSBhY3R1YWxseSBkb2luZyB3b3VsZCd2ZSBiZWVuIHVzZWZ1bCBhbmQgc2F2ZWQgdXMgYSBsb3Qgb2YgKnNvcnQgb2YqIHdhc3RlZCB0aW1lLiBUaGUgcHJvYmxlbSB3aXRoIGFsbCBvdXIgJ3ByZWRpY3RpdmUnIG1vZGVscyBpcyB0aGF0IHRoZXkncmUgbm90IGFjdHVhbGx5IHJlYWxseSBwcmVkaWN0aW5nIGFueXRoaW5nIHVzZWZ1bC4gQWxsIHRoZXkgYXJlIGRvaW5nIGlzIGNsYXNzaWZ5aW5nIGEgZ2FtZSBhcyBlaXRoZXIgYSB3aW4gb3IgYSBsb3NzIHVzaW5nIGdpdmVuIHRoZSAqKnBvc3QtZ2FtZSBzdGF0aXN0aWNzKiogZm9yIGEgdGVhbS4gU3RhdGlzdGljcyB3aGljaCBjYW4gb25seSBiZSBjb2xsZWN0ZWQgb25jZSBhIGdhbWUgaGFzIGZpbmlzaGVkLCBub3QgYmVmb3JlIGEgZ2FtZSBoYXMgYmVlbiBwbGF5ZWQgd2hpY2ggd2FzIHRoZSB3aG9sZSAncHJvYmxlbScgd2Ugc2V0IG91dCB0byBzb2x2ZS4KClRoaXMgbWFrZXMgb3VyIG1vZGVscyBzb3J0IG9mIHVzZWxlc3MgY29tcGFyZWQgdG8gdGhlIHdheSB3ZSdkIGltYWdlZCB0aGVtIGJ1dCBub3QgKmNvbXBsZXRlbHkqIHVzZWxlc3MuIFRoZSBmYWN0IHRoYXQgdGhleSBjb3VsZCBwcmVkaWN0IHRocmVlIG91dCBvZiBldmVyeSBmb3VyIGdhbWVzIGNvcnJlY3Qgd2l0aCBqdXN0IHRoZSB2YXJpYWJsZXMgd2UgZ2F2ZSB0aGVtIHRvIHdvcmsgd2l0aCByZWluZm9yY2VzIHRoZSBmYWN0IHRoYXQgKipzb21lIHNvcnQqKiBvZiBjb3JyZWxhdGlvbiBleGlzdHMgYmV0d2VlbiB0aG9zZSB2YXJpYWJsZXMgYW5kIGEgdGVhbSB3aW5uaW5nIGEgZ2FtZS4gVG8gYWN0dWFsbHkgc29sdmUgb3VyIHByb2JsZW0gaXQgbWlnaHQgaGF2ZSBiZWVuIGEgbG90IG1vcmUgdXNlZnVsIHRvIGJlIGxvb2tpbmcgYXQgcXVhcnRlci10aW1lIG9yIGhhbGYtdGltZSB0ZWFtcyBzdGF0aXN0aWNzIGFuZCB0aGVuIHNlZWluZyBob3cgKnRob3NlKiByZWxhdGUgdG8gYSB3aW4gb3IgYSBsb3NzLiAKCiMjIyBQbG90dGluZwoKQWZ0ZXIgb3VyICdwcmVkaWN0aXZlJyBtb2RlbHMgcmVhbGx5IGRpZG4ndCBoZWxwIHVzIHdpdGggd2hhdCB3ZSB3YW50ZWQgdG8gYWNoaWV2ZSB3ZSBoYWQgdG8gdGFrZSBhIHN0ZXAgYmFjayBhbmQgdGhpbmsgYWJvdXQgYSBtb3JlIHNwZWNpZmljIHdheSBvZiBhbmFseXppbmcgdGhlIGRhdGEgKip3aGljaCBhY3R1YWxseSBzb21ld2hhdCBoZWxwcyBpbiBwcmVkaWN0aW5nIHRoZSBvdXRjb21lcyBvZiBmdXR1cmUgbWF0Y2hlcyoqLiBXZSB0aG91Z2h0IG9mICp0d28qIG1haW4gdGhpbmdzIHRoYXQgd2Ugd2VyZSBjdXJpb3VzIHRvIGxvb2sgaW50bzoKCjEuIEhvdyBvZnRlbiBhcmUgaW5kaXZpZHVhbCB0ZWFtcyB3aW5uaW5nICYgbG9zaW5nIHdpdGhpbiBvdXIgZGF0YSBzZXQsIGFuZCBob3cgZG9lcyB0aGlzIGNvbXBhcmUgdG8gdGhlaXIgcGVyZm9ybWFuY2UgaW4gdGhlIGN1cnJlbnQgMjAxNyBzZWFzb24/ICAKClRoZSBmaXJzdCB0aGluZyB3ZSBuZWVkZWQgdG8gZG8gd2FzIHNlcGFyYXRlIHRoZSB0b3RhbCB3aW5zIGFuZCBsb3NlcyB3aXRoIHJlc3BlY3QgdG8gZWFjaCB0ZWFtIHRocm91Z2hvdXQgdGhlIHdob2xlIGRhdGEgc2V0LiBUaGVuIHdlIHB1dCB0aGVtIGludG8gZGVzY2VuZGluZyBvcmRlciBiZWNhdXNlIHRoYXQncyBob3cgd2UgaW50ZW5kZWQgdGhlbSB0byBiZSBzaG93biB3aXRoaW4gb3VyIHBsb3RzIHdlIHBsYW5uZWQgb24gbWFraW5nLgoKYGBge3J9CnRhYmxlX2FsbCA8LSB0YWJsZShBRkxfY2xlYW4kVGVhbSwgQUZMX2NsZWFuJFdpbkxvc3MpCgphbGxfZnJlcSA8LSBhcy5kYXRhLmZyYW1lLm1hdHJpeCh0YWJsZV9hbGwpCmFsbF9mcmVxIDwtIGFsbF9mcmVxW29yZGVyKGFsbF9mcmVxJGAxYCwgZGVjcmVhc2luZyA9IFRSVUUpLF0KI2FsbF9mcmVxCmBgYAoKVGhpcyB3YXNuJ3QgdGhlIGVuZCBvZiB0aGUgc3RvcnkgdGhvdWdoLiBTaW1wbHkgZ3JhcGhpbmcgZWFjaCB0ZWFtJ3MgdG90YWwgZnJlcXVlbmN5IG9mIHdpbnMgYW5kIGxvc3NlcyBhbmQgdGhlbiBvcmRlcmluZyB0aGVtIGJ5IG51bWJlciBvZiB3aW5zIHdvdWxkIGJlIGNvbXBsZXRlbHkgdW5mYWlyLiBTb21lIHRlYW1zIGhhdmUganVzdCBwbGF5ZWQgbW9yZSBnYW1lcyB0aGFuIG90aGVyIHRlYW1zIHdoaWNoIG1lYW5zIHRoZXknZCBieSBkZWZhdWx0IHByb2JhYmx5IGhhdmUgbW9yZSB3aW5zIGJlY2F1c2UgdGhleSd2ZSBzaW1wbHkgcGxheWVkIG1vcmUgZ2FtZXMuIFRodXMsIHRvIHNob3cgdGhlbSBmYWlybHkgbmV4dCB0byBlYWNoIG90aGVyIHdlIGhhdmUgdG8gZ2V0IHRoZW0gaW4gdGVybXMgb2YgdGhlaXIgd2luL2xvc3MgcGVyY2VudGFnZSBvciBwcm9wb3J0aW9uLiBUaGF0IGlzLCBvdXQgb2YgYWxsIHRoZSBnYW1lcyB0aGV5J3ZlIHBsYXllZCB3aGF0IGZyYWN0aW9uIG9mIHRoZW0gZGlkIHRoZXkgd2luLCBhbmQgd2hhdCBmcmFjdGlvbiBkaWQgdGhleSBsb3NlPwoKYGBge3J9Cndpbl9wZXJjIDwtIGFsbF9mcmVxJGAxYCAvIChhbGxfZnJlcSRgMGAgKyBhbGxfZnJlcSRgMWApCmxvc3NfcGVyYyA8LSAxIC0gd2luX3BlcmMKYWxsX3BlcmMgPC0gY2JpbmQoYWxsX2ZyZXEsIGxvc3NfcGVyYywgd2luX3BlcmMpCmFsbF9wZXJjIDwtIGFsbF9wZXJjWzM6NF0KY29sbmFtZXMoYWxsX3BlcmMpIDwtIGMoIkxvc3MgUGVyY2VudGFnZSIsICJXaW4gUGVyY2VudGFnZSIpCiNhbGxfcGVyYwoKYWxsX3BlcmNfZGVjciA8LSBhbGxfcGVyY1tvcmRlcihhbGxfcGVyYyRgV2luIFBlcmNlbnRhZ2VgLCBkZWNyZWFzaW5nID0gVFJVRSksXQojYWxsX3BlcmNfZGVjcgpgYGAKCmBgYHtyIHQ4LCBmaWcud2lkdGg9MjUsIGZpZy5oZWlnaHQ9Nn0KbW9zYWljcGxvdChhbGxfcGVyY19kZWNyLCBjb2w9YyhyZ2IoMjE1LzI1NSwyNS8yNTUsMjgvMjU1KSxyZ2IoMTY2LzI1NSwyMTcvMjU1LDEwNi8yNTUpKSwgbWFpbiA9ICJUb3RhbCBXaW4gdnMgTG9zcyBQZXJjZW50YWdlIGZvciBlYWNoIHRlYW0gKDIwMTItMjAxNikgW0Rlc2NlbmRpbmcgT3JkZXJdIiwgY2V4LmF4aXMgPSAxLjIpCmBgYAoKSGVyZSB3ZSd2ZSBqdXN0IHNwbGl0IHRoZSBhYm92ZSBwbG90IGluIGhhbGYgc28gaXQncyBlYXNpZXIgdG8gc2VlIGFuZCB3aGF0IHdlJ3ZlIGRvbmUgaXMgY29tcGFyZWQgdGhlIHJhbmsgb2YgdGhlIHRlYW1zIGluIG91ciBkZXNjZW5kaW5nIHdpbiBwZXJjZW50YWdlIHBsb3QgZnJvbSB0aGUgMjAxMiAtIDIwMTYgZGF0YSBhZ2FpbnN0IHRoZSBjdXJyZW50IDIwMTcgbGFkZGVyIHBvc2l0aW9ucyAoYXMgb2YgMzEtMDUtMjAxNykuIEEgZ3JlZW4gZG90IG5leHQgdG8gYSB0ZWFtIHJlcHJlc2VudHMgdGhlbSBiZWluZyBpbiB0aGUgc2FtZSBoYWxmIG9mIGJvdGggdGhlIDIwMTcgbGFkZGVyIGFuZCBvdXIgMjAxMiAtIDIwMTYgZGVzY2VuZGluZyB3aW4gcGVyY2VudGFnZSByYW5raW5ncy4gQXMgeW91IG1pZ2h0IGhhdmUgbm90aWNlZCB3ZSBieSBkb2luZyB0aGlzIHdlIG9ubHkgbWFuYWdlZCB0byBwbGFjZSBqdXN0IG92ZXIgaGFsZiBvZiB0aGUgdGVhbXMgaW4gdGhlaXIgY29ycmVjdCBoYWx2ZXMsIDU2JSB0byBiZSBleGFjdC4gSG93ZXZlciwgcXVpdGUgYSBmZXcgb2YgdGhlIHRlYW1zIGFyZSBvbmx5IG9mZiBieSBhIG9uZSBvciB0d28gcG9zaXRpb25zLCBhbmQgdGhlIHNlYXNvbnMgbm90IGZpbmlzaGVkIHlldCBzbyB0aGVyZSdzIGFsd2F5cyByb29tIGZvciB0aGUgdGVhbXMgdG8gZG8gdGhlIG5hdHVyYWwgdGhpbmcgYW5kIGNvbnZlcmdlIG9uIHRoZWlyIHJlbGF0aXZlIGhpc3RvcmljYWwgcmFua2luZ3MuCgpOb3QgdG8gbWVudGlvbiB0aGlzIHNlYXNvbiBvZiBBRkwgaGFzIGp1c3QgYmVlbiBwYXJ0aWN1bGFybHkgdW5wcmVkaWN0YWJsZTsgdGVhbXMgd2hvJ3ZlIGdlbmVyYWxseSBiZWVuIG9uIHRvcCBoYXZlIGZhbGxlbiBhbmQgdGVhbXMgd2hvJ3ZlIGdlbmVyYWxseSBiZWVuIGF0IHRoZSBib3R0b20gaGF2ZSBzdGFydGVkIHRvIHJpc2UuIEp1c3QgbG9vayBhdCBHV1M7IGZyb20gMjAxMiAtIDIwMTYgdGhleSBoYXZlIHRoZSBmb3VydGggbG93ZXN0IHdpbiBwZXJjZW50YWdlIHlldCB0aGV5J3JlIGN1cnJlbnRseSBzZWNvbmQgb24gdGhlIGxhZGRlci4gVGhpcyBwcm9iYWJseSBjb21lcyBkb3duIHRvIHRoZW0gYmVpbmcgYSB5b3VuZyB0ZWFtIGFuZCBlYWNoIHllYXIgdGhlaXIgcGxheWVycyBhcmUgZ2V0dGluZyBleHBvbmVudGlhbGx5IG1vcmUgZXhwZXJpZW5jZWQgYW5kIHBsYXlpbmcgYmV0dGVyIGFzIGEgcmVzdWx0LCBidXQgaXQncyBpbnRlcmVzdGluZyBub25ldGhlbGVzcy4gCgohWyoqVGVhbSBXaW4gUGVyY2VudGFnZSB2cyAyMDE3IExhZGRlcioqXShhbGwucG5nKQoKCjIuIEFyZSBjZXJ0YWluIHRlYW1zIHdpbm5pbmcgYSBsb3QgbW9yZSBvZnRlbiBhdCBjZXJ0YWluIHZlbnVlcywgYW5kIGRvZXMgdGhpcyBoYXZlIGFueXRoaW5nIHRvIGRvIHdpdGggaG93IG11Y2ggZXhwZXJpZW5jZSB0aGV5IGhhdmUgcGxheWluZyBhdCB0aGVzZSB2ZW51ZXM/CgpUbyBhbnN3ZXIgdGhlc2UgcXVlc3Rpb25zIHdlIGZpcnN0IGhhZCB0byBkZXRlcm1pbmUgd2hpY2ggdmVudWVzIGFsbCBvZiB0aGUgdGVhbXMgaGF2ZSBwbGF5ZWQgYXQgc28gd2UgaGF2ZSBhIGRlY2VudCBzYW1wbGUgc2l6ZSBvZiBtYXRjaGVzIHRvIHdvcmsgd2l0aCwgYW5kIHRvIG1ha2Ugc3VyZSBlYWNoIHRlYW0gaXMgcmVwcmVzZW50ZWQgd2l0aGluIGVhY2ggdmVudWUncyBhbmFseXNpcy4gVG8gZG8gdGhpcyB3ZSBwbG90dGVkIG91ciBzY29yZSB2YXJpYWJsZSBmb3IgZWFjaCB0ZWFtIGZpbHRlcmVkIGJ5IGVhY2ggZGlmZmVyZW50IHZlbnVlIHdlIGhhdmUgaW4gb3VyIGRhdGEgc2V0LgoKYGBge3J9CmxpYnJhcnkobGF0dGljZSkKYmFyY2hhcnQoQUZMX2NsZWFuJFNjb3JlIH4gQUZMX2NsZWFuJFRlYW0gfCBBRkxfY2xlYW4kVmVudWUpCmBgYAoKVXNpbmcgdGhpcyBwbG90IGFuZCBjb21wYXJpbmcgdGhlIHRvdGFsIGFtb3VudCBvZiBnYW1lcyBwbGF5ZWQgYXQgZWFjaCB2ZW51ZSB3ZSBuYXJyb3dlZCB0aGUgdmVudWVzIHdlIHdhbnRlZCB0byBsb29rIGF0IGRvd24gdG8gU3ViaWFjbywgQWRlbGFpZGUgT3ZhbCwgTS5DLkcsIFMuQy5HIGFuZCBUaGUgR2FiYmEuIFRoZXNlIGxvY2F0aW9ucyB3ZXJlIGFsc28gcGlja2VkIGFzIHRoZXkncmUgdGhlIG1vc3QgcG9wdWxhciB2ZW51ZXMgZm9yIFBlcnRoLCBBZGVsYWlkZSwgTWVsYm91cm5lLCBTeWRuZXkgYW5kIEJyaXNiYW5lIHJlc3BlY3RpdmVseTsgbWVhbmluZyBpZiB0aGVyZSdzIGFueSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSB0ZWFtcyBwbGF5aW5nIG9uIHRoZWlyIGhvbWUgZ3JvdW5kIHdlIHNob3VsZCBiZSBhYmxlIHRvIHNlZSBpdCBhY3Jvc3MgYWxsIHRoZSBtYWluIHZlbnVlcy4KClRvIGRvIHRoaXMgd2UgaGFkIHRvIGV4dHJhY3QgdGhlIHdpbnMgYW5kIGxvc3NlcyB0aGF0IGVhY2ggdGVhbSBoYXMgaGFkIHdoZW4gb25seSBsb29raW5nIGF0IGEgc3BlY2lmaWMgdmVudWUuCgpgYGB7cn0KdmVudWVGaWx0ZXIgPC0gZnVuY3Rpb24odmVudWUpewogIAogIEFGTF92ZW51ZSA8LSBBRkxfY2xlYW5bQUZMX2NsZWFuJFZlbnVlID09IHZlbnVlLF0KICB2ZW51ZV90YWJsZSA8LSB0YWJsZShBRkxfdmVudWUkVGVhbSwgQUZMX3ZlbnVlJFdpbkxvc3MpCiAgdmVudWVfZGYgPC0gYXMuZGF0YS5mcmFtZS5tYXRyaXgodmVudWVfdGFibGUpCiAgdmVudWVfZnJlcSA8LSB2ZW51ZV9kZltvcmRlcih2ZW51ZV9kZiRgMWAsIGRlY3JlYXNpbmcgPSBUUlVFKSxdCiAgCiAgd2luX3BlcmMgPC0gdmVudWVfZnJlcSRgMWAgLyAodmVudWVfZnJlcSRgMGAgKyB2ZW51ZV9mcmVxJGAxYCkKICBsb3NzX3BlcmMgPC0gMSAtIHdpbl9wZXJjCiAgYWxsX3BlcmMgPC0gY2JpbmQodmVudWVfZnJlcSwgbG9zc19wZXJjLCB3aW5fcGVyYykKICBhbGxfcGVyYyA8LSBhbGxfcGVyY1szOjRdCiAgY29sbmFtZXMoYWxsX3BlcmMpIDwtIGMoIkxvc3MgUGVyY2VudGFnZSIsICJXaW4gUGVyY2VudGFnZSIpCiAgI2FsbF9wZXJjCiAgCiAgdGVhbV90b3RhbCA8LSAodmVudWVfZnJlcSRgMGAgKyB2ZW51ZV9mcmVxJGAxYCkKICBnYW1lX3RvdGFscyA8LSBzdW0odGVhbV90b3RhbCkKICB0ZWFtX3Byb3BvcnRpb24gPC0gdGVhbV90b3RhbCAvIGdhbWVfdG90YWxzCiAgdmVudWVfZnJlcSA8LSBjYmluZCh2ZW51ZV9mcmVxLCB0ZWFtX3Byb3BvcnRpb24pCiAgI3ZlbnVlX2ZyZXEKICAKICBhbGxfdmVudWUgPC0gY2JpbmQodmVudWVfZnJlcSwgYWxsX3BlcmMpCiAgYWxsX3ZlbnVlIDwtIGFsbF92ZW51ZVtvcmRlcihhbGxfdmVudWUkYFdpbiBQZXJjZW50YWdlYCwgZGVjcmVhc2luZyA9IFRSVUUpLF0KICByZXR1cm4oYWxsX3ZlbnVlKQoKfQpgYGAKCmBgYHtyfQpzdWJpYWNvIDwtIHZlbnVlRmlsdGVyKCJTdWJpYWNvIikKc3lkLnNob3dncm91bmQgPC0gdmVudWVGaWx0ZXIoIlN5ZG5leSBTaG93Z3JvdW5kIikKZ2FiYmEgPC0gdmVudWVGaWx0ZXIoIkdhYmJhIikKbWNnIDwtIHZlbnVlRmlsdGVyKCJNLkMuRy4iKQpzY2cgPC0gdmVudWVGaWx0ZXIoIlMuQy5HLiIpCmFkbC5vdmFsIDwtIHZlbnVlRmlsdGVyKCJBZGVsYWlkZSBPdmFsIikKY2FycmFyYSA8LSB2ZW51ZUZpbHRlcigiQ2FycmFyYSIpCmRvY2tsYW5kcyA8LSB2ZW51ZUZpbHRlcigiRG9ja2xhbmRzIikKZnRibC5wYXJrIDwtIHZlbnVlRmlsdGVyKCJGb290YmFsbCBQYXJrIikKYGBgCgpJJ3ZlIGp1c3QgaW5jbHVkZWQgdGhlIGNvZGUgZm9yIG9ubHkgbG9va2luZyBhdCBUaGUgR2FiYmEgYnV0IGV2ZXJ5IHNpbmdsZSBwbG90IHdhcyBtYWRlIHVzaW5nIHRoZSBzYW1lIGNvZGUgYW5kIGp1c3QgcmVwbGFjaW5nIHRoZSB2ZW51ZSB3aXRoIHdoaWNoZXZlciBvbmUgeW91IHdlcmUgaW50ZXJlc3RlZCBpbi4gCgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQoKZ2FiYmEudHByb3AgPC0gZ2FiYmFbM10KYnAgPC0gZ2dwbG90KGdhYmJhLnRwcm9wLCBhZXMoeD0iIiwgeT10ZWFtX3Byb3BvcnRpb24sIGZpbGw9cm93Lm5hbWVzKGdhYmJhLnRwcm9wKSkgKSArIGdlb21fYmFyKHdpZHRoID0gMSwgc3RhdCA9ICJpZGVudGl0eSIpICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIiM5OTk5OTkiLCAiI0U2OUYwMCIsICIjNTZCNEU5IiwgIiM4ZmMwYTAiLCAiI2NjOWI1YiIsICIjNzE1MjliIiwgIiM3YmY2OGQiLCAiIzk2MjcwZiIsICIjMWU0NmJlIiwgIiNiNjBlZGMiLCAiIzY3OGRiZCIsICIjNGViMjBiIiwgIiM1ZjM3ZTUiLCAiIzAyMzM5YiIsICIjYTdhNGRmIiwgIiMyYjY4MWUiLCAiIzJjM2Y3YyIsICIjZDllZDhmIikpCmJwCgpwaWUgPC0gYnAgKyBjb29yZF9wb2xhcigieSIsIHN0YXJ0PTApCnBpZQpgYGAKCmBgYHtyIHQ5LCBmaWcud2lkdGg9MjgsIGZpZy5oZWlnaHQ9Nn0KZ2FiYmEud3BlcmMgPC0gZ2FiYmFbNDo1XQojc3ViaWFjby53cGVyYwoKbW9zYWljcGxvdChnYWJiYS53cGVyYywgY29sPWMocmdiKDIxNS8yNTUsMjUvMjU1LDI4LzI1NSkscmdiKDE2Ni8yNTUsMjE3LzI1NSwxMDYvMjU1KSksIG1haW4gPSAiVG90YWwgV2luIHZzIExvc3MgUGVyY2VudGFnZSBmb3IgZWFjaCB0ZWFtIGF0IFN1YmlhY28gT3ZhbCAoMjAxMi0yMDE2KSBbRGVzY2VuZGluZyBPcmRlcl0iLCBjZXguYXhpcyA9IDEuMikKYGBgCgpTbyB5b3UgZG9uJ3QgaGF2ZSB0byBsb29rIGF0IHRoZSBzYW1lIGNvZGUgdGVuIHRpbWVzIGFuZCBzcXVpbnQgdHJ5aW5nIHRvIGxvb2sgYXQgdGhlIGRvd25zaXplZCBSLW91dHB1dCBJJ3ZlIGp1c3QgaW5jbHVkZWQgdGhlIHNsaWRlcyBJIG1hZGUgZnJvbSB0aGUgcG93ZXIgcG9pbnQsIGJ1dCBsaWtlIEkgc2FpZCBiZWZvcmUgaXQgd2FzIGFsbCBtYWRlIHVzaW5nIHRoZSBleGFjdCBzYW1lIGNvZGUgYWJvdmUuCiAgCiMjIyMgU3ViaWFjbwoKU3ViaWFjbyBpcyB0aGUgaG9tZSBncm91bmQgb2YgRnJlbWFudGxlIGFuZCBXZXN0IENvYXN0IGFuZCBhcyBzZWVuIG9uIHRoZSBmaXJzdCBwbG90IHRoZXkncmUgYWxzbyBpbiB0aGUgdG9wIHR3byBwbGFjZXMgZm9yIHdpbiBwZXJjZW50YWdlIHdoZW4ganVzdCBsb29raW5nIGF0IGdhbWVzIHBsYXllZCBhdCBTdWJpYWNvLiBUaGUgc2Vjb25kIHBsb3Qgc2hvd3MgdGhlIGZyYWN0aW9uIG9mIGdhbWVzIHRoYXQgZWFjaCBpbmRpdmlkdWFsIHRlYW0gaGFzIHBsYXllZCBhdCBTdWJpYWNvIGFuZCBieSBubyBzdXJwcmlzZSBGcmVtYW50bGUgYW5kIFdlc3QgQ29hc3QgdG9nZXRoZXIgbWFrZSB1cCBhYm91dCA2MCUgb2YgdGhlIGdhbWVzLiBUaGlzIGxlYXZlcyB0aGUgb3RoZXIgMTYgdGVhbXMgdG8gc2hhcmUgdGhlIHJlbWFpbmluZyA0MCUgb2YgZ2FtZXMgYmV0d2VlbiB0aGVtc2VsdmVzLCB3aGljaCBlcXVhdGVzIHRvIGFib3V0IHNpeCBnYW1lcyBlYWNoLgoKQWZ0ZXIgbG9va2luZyBhdCB0aGVzZSBwbG90cyBpdCBtYWtlcyBhIGxvdCBtb3JlIHNlbnNlIHRoYXQgRnJlbWFudGxlIGFuZCBXZXN0IENvYXN0IGFyZSB0b3BwaW5nIHRoZSB3aW4gcGVyY2VudGFnZSBhdCBTdWJpYWNvIGJlY2F1c2UgdGhleSdyZSBzbyBkaXNwcm9wb3J0aW9uYXRlbHkgcmVwcmVzZW50ZWQgYXQgdGhlIHZlbnVlLiBOb3QgdG8gbWVudGlvbiB0aGF0IGFsbCB0aGUgb3RoZXIgdGVhbXMgaGF2ZSB0byBmbHkgcXVpdGUgYSBkaXN0YW5jZSB0byBnZXQgdG8gU3ViaWFjbywgdGhpcyBwcm9iYWJseSBjb250cmlidXRlcyBoZWF2aWx5IHRvIHRoZSBmYWN0IHRoYXQgdGhlIG1ham9yaXR5IG9mIHRoZSB0ZWFtcyBoYXZlIGxlc3MgdGhhbiBhIDUwJSB3aW4gcmF0ZS4KClJlbGF0aW5nIGJhY2sgdG8gb3VyIGdvYWwgb2YgcHJlZGljdGluZyBmdXR1cmUgb3V0Y29tZXMgb2YgZ2FtZXMsIHRoaXMgZ2l2ZXMgdXMgc29tZSB2ZXJ5IHVzZWZ1bCBpbmZvcm1hdGlvbi4gV2hlbiBCcmlzYmFuZSwgQ29sbGluZ3dvb2QsIE1lbGJvdXJuZSBvciBTdCBLaWxkYSBhcmUgcGxheWluZyBhdCBTdWJpYWNvIGl0J3MgcHJvYmFibHkgYSBnb29kIGlkZWEgdG8gYmV0IGFnYWluc3QgdGhlbSwgZXNwZWNpYWxseSBpZiB0aGV5J3JlIHVwIGFnYWluc3QgRnJlbWFudGxlIG9yIFdlc3QgQ29hc3QuCgohW10oc3ViaWFjb18yLnBuZykKIVtdKHN1YmlhY29fMy5wbmcpCgojIyMjIEFkZWxhaWRlIE92YWwKCkxvb2tpbmcgYXQgQWRlbGFpZGUgT3ZhbCB3ZSBzZWUgYSBzaW1pbGFyIHRyZW5kIHdpdGggdGhlIGhvbWUgdGVhbXMsIEFkZWxhaWRlIGFuZCBQb3J0IEFkZWxhaWRlLCB0b2dldGhlciBtYWtpbmcgdXAgYWJvdXQgNjAlIG9mIHRoZSB0b3RhbCBnYW1lcyBwbGF5ZWQgb24gdGhlaXIgaG9tZSB0dXJmLiBTaW1pbGFyaWx5LCB0aGlzIGxlYXZlcyB0aGUgb3RoZXIgMTYgdGVhbXMgdG8gc2hhcmUgdGhlIHJlbWFpbmluZyA0MCUgb2YgZ2FtZXMsIGJ1dCB0aGlzIHRpbWUgdGhhdCBvbmx5IGVxdWF0ZXMgdG8gYWJvdXQgZm91ciBnYW1lcyBlYWNoIChhcyBsZXNzIGdhbWVzIGhhdmUgYmVlbiBwbGF5ZWQgYXQgQWRlbGFpZGUgT3ZhbCBjb21wYXJlZCB0byBTdWJpYWNvKS4KCldoZW4gd2UgbG9vayBhdCB0aGUgd2luIHBlcmNlbnRhZ2VzIHRoZXJlJ3MgZGVmaW5pdGVseSBzb21lIGltcHJvdmVtZW50IGFzIFBvcnQgQWRlbGFpZGUgaGF2ZSBtb3ZlZCBmcm9tIG92ZXJhbGwgYmVpbmcgcmFua2VkIDEwdGggdG8gYmVpbmcgcmFua2VkIDZ0aCBob3dldmVyLCBBZGVsYWlkZSBoYXMgc3RheWVkIHN0YWduYW50IGluIHRoZSBzYW1lIHBvc2l0aW9uLiBJbnRlcmVzdGluZ2x5IHdlIGFsc28gaGF2ZSBhIGNvdXBsZSBkaWZmZXJlbnQgdGVhbXMgZG9taW5hdGluZyB0aGUgdG9wIHBvc2l0aW9ucyBhbmQgYSBjb3VwbGUgbW9yZSB0ZWFtcyBoYXZpbmcgbm90IGV2ZXIgb25lIGEgZ2FtZSBhdCB0aGUgdmVudWUuCgpVc2luZyB0aGlzIGluZm9ybWF0aW9uIHdlIGNvdWxkIHNheSB0aGF0IGlmIFBvcnQgQWRlbGFpZGUgaXMgcGxheWluZyBhIHRlYW0gdGhhdCdzIG9uIHBhciB3aXRoIHRoZW0sIGJ1dCB0aGV5J3JlIHBsYXlpbmcgYXQgQWRlbGFpZGUgT3ZhbCwgdGhlbiB0aGV5IG1pZ2h0IGp1c3QgaGF2ZSB0aGF0IGV4dHJhIGVkZ2UgZnJvbSB0aGUgaG9tZSBhZHZhbnRhZ2UgYW5kIGNvbWUgb3V0IG9uIHRvcC4gV2Ugc2VlIEJyaXNiYW5lLCBDb2xsaW5nd29vZCBhbmQgU3QgS2lsZGEgYmVpbmcgcmVwZWF0ZWQgb24gdGhlIGJvdHRvbSBvZiB0aGUgbGlzdCB3aXRoIG5vIHdpbnMgd2hhdCBzbyBldmVyLCBhZ2FpbiwgbWFraW5nIHlvdXIgY2hhbmNlcyBvZiB3aW5uaW5nIHdoZW4gYmV0dGluZyBhZ2FpbnN0IHRoZW0gKGlmIHRoZXkncmUgcGxheWluZyBhdCBTdWJpYWNvIG9yIEFkZWxhaWRlIE92YWwpIHRoYXQgbXVjaCBiZXR0ZXIuCgohW10oYWRsZG92bF8yLnBuZykKIVtdKGFkbGRvdmxfMy5wbmcpCgojIyMjIE0uQy5HLgoKVGhlIE0uQy5HIGlzIGEgbXVjaCBtb3JlIHBvcHVsYXIgdmVudWUgd2l0aCBhIHRvdGFsIG9mIDUwMCBnYW1lcyBwbGF5ZWQgYXQgaXQsIHdoaWNoIGlzIG1vcmUgZ2FtZXMgdGhhbiBTdWJpYWNvIGFuZCBBZGVsYWlkZSBPdmFsIGNvbWJpbmVkLiBJdCdzIGFsc28gaW4gTWVsYm91cm5lIHdoaWNoIGlzIHdpdGhpbiBhIGNvdXBsZSBob3VycyBkcml2ZSBvZiBvdmVyIGhhbGYgdGhlIEFGTCB0ZWFtcy4gVGhlc2UgZmFjdG9ycyBjb250cmlidXRlIHRoZSB0aGUgTS5DLkcgaGF2aW5nIGEgbXVjaCBtb3JlIGV2ZW4gc3ByZWFkIG9mIHRlYW0ncyB0b3RhbCBnYW1lcyBwbGF5ZWQgYXQgdGhlIHZlbnVlLCBhcyBzZWVuIG9uIHRoZSBzZWNvbmQgcGxvdCBlYWNoIGNsb3NlLWJ5IHRlYW0gaG9sZHMgYWJvdXQgNSUgLSAxMCUgb2YgdGhlIGdhbWVzIGluc3RlYWQgb2YgMzAlLgoKSG93ZXZlciwgZXZlbiB3aXRoIHRoZSBzcHJlYWQgYmVpbmcgYSBsb3QgbW9yZSBldmVuIGFuZCBubyB0ZWFtKHMpIGJlaW5nICpleHRyZW1lbGx5KiBkaXNwcm9wb3J0aW9uYXRlbHkgcmVwcmVzZW50ZWQsICoqd2Ugc3RpbGwqKiBzZWUgdGhpcyB0cmVuZCBvZiB0aGUgc3Vycm91bmRpbmcsIGNsb3NlLWJ5IHRlYW1zIHBsYXlpbmcgYmV0dGVyLiBFdmVyeSBzaW5nbGUgb24gb2YgdGhlIGNsb3NlLWJ5IHRlYW1zIGhhcyBlaXRoZXIgaGVsZCB0aGVpciBwb3NpdGlvbiBvciBpbXByb3ZpbmcgZHJhbWF0aWNhbGx5LCB3aXRoIHRoZSBXZXN0ZXJuIEJ1bGxkb2dzIGNsaW1iaW5nIG5lYXJseSBoYWxmIG9mIHRoZSByYW5rcy4gSG93ZXZlciwgd2Ugc3RpbGwgc2VlIEJyaXNiYW5lIGluIHRoZSBib3R0b20gZmV3IHJhbmtzIGFkZGluZyB0byB0aGUgcGlsZSBvZiBldmlkZW5jZSB0aGF0IHlvdSBzaG91bGQgcHJvYmFibHkgYWx3YXlzIGJldCBhZ2FpbnN0IHRoZW0gaWYgdGhleSdyZSBwbGF5aW5nIGFuIGF3YXkgZ2FtZS4KCiFbXShtY2dfMi5wbmcpCiFbXShtY2dfMy5wbmcpCgojIyMjIFMuQy5HLgoKVGhlIFMuQy5HIGhhcyB0aGUgc21hbGxlc3QgYW1vdW50IG9mIGdhbWVzIHBsYXllZCBhdCBpcyBjb21wYXJlZCB0byBhbGwgdGhlIG90aGVyIHZlbnVlcyB3ZSdyZSBsb29raW5nIGF0LCBvbmx5IDkwIGdhbWVzIGl0IHRvdGFsIHdoaWNoIGlzIGxlc3MgdGhhbiAxLzV0aCBvZiB0aGUgdG90YWwgZ2FtZXMgcGxheWVkIGF0IHRoZSBTLkMuRy4gVGhpcyBzb3J0IG9mIGV4cGxhaW5zIHRoZSAqKmV4dHJlbWUgZGlzcG9wb3J0aW9uYWxpdHkqKiB0aGF0IHdlIHNlZSBhdCB0aGUgdmVudWUsIHdpdGggU3lkbmV5IGhhdmluZyBwbGF5ZWQgYWJvdXQgKipoYWxmKiogb2YgYWxsIHRoZSBnYW1lcyBwbGF5ZWQgdGhlcmUuIEludGVyZXN0aW5nbHkgdGhvdWdoIEdXUyBwbGF5cyBqdXN0IGFib3V0IGFzIG9mdGVuIGFzIGFuIGF3YXkgdGVhbSBkZXNwaXRlIHRoZW0gYmVpbmcgc2l0dWF0ZWQgcXVpdGUgY2xvc2UgYnkgdG8gdGhlIHZlbnVlLiAKClRoZSB3aW4gcGVyY2VudGFnZXMgYXJlIHF1aXRlIHNrZXdlZCBoZXJlIGR1ZSB0byB0aGUgc21hbGwgYW1vdW50IG9mIGdhbWVzIHRoYXQgaGF2ZSBiZWVuIHBsYXllZCB0aGVyZSBieSBhd2F5IHRlYW1zLCBlYWNoIHRlYW0gaGFzIG9ubHkgcGxheWVkIGFib3V0IHR3byBvciB0aHJlZSBnYW1lcy4gVGhpcyBtYWtlcyBpdCBoYXJkIHRvIGdldCBhbnkgdXNlZnVsIGluZm9ybWF0aW9uIGZyb20gdGhlIHdpbiBwZXJjZW50YWdlIHBsb3QgaG93ZXZlciwgaXQgaGFzIHRvIGJlIG5vdGVkIHRoYXQgQnJpc2JhbmUgaGFzIG5vIHdpbnMgYWdhaW4gZGVzcGl0ZSBhY3R1YWxseSBiZWluZyByb3VnaGx5IG9uZSBvZiB0aGUgY2xvc2VzdCBhd2F5IHRlYW1zIHRvIHRoZSB2ZW51ZS4KCiFbXShzY2dfMi5wbmcpCiFbXShzY2dfMy5wbmcpCgojIyMjIFRoZSBHYWJiYQoKTG9va2luZyBhdCBUaGUgR2FiYmEgd2UgY2FuIGZ1bGx5IGNvbmZpcm0gdGhhdCB0aGluZ3MgcmVhbGx5IGFyZW4ndCBsb29raW5nIHRvbyBncmVhdCBmb3IgQnJpc2JhbmUuIERlc3BpdGUgaXQgYmVpbmcgdGhlaXIgaG9tZSBncm91bmQgYW5kIHRoZW4gaGF2aW5nIHBsYXllZCBhYm91dCA1MCUgb2YgdGhlIHRvdGFsIGdhbWVzIGF0IHRoZSB2ZW51ZSB0aGV5IGFyZSBzdGlsbCB2ZXJ5IGNsb3NlIHRvIHRoZSBib3R0b20gb2YgdGhlIHJhbmtzLiBBZ2FpbiBpdCBpcyBzdHJhbmdlIGhvdyBHb2xkIENvYXN0IGlzIHdpdGhpbiBhbiBob3VycyBkcml2ZSBvZiBUaGUgR2FiYmEgeWV0IHRoZXkgc3RpbGwgcGxheSB0aGVyZSBhcyBvZnRlbiBhcyBhbiBhd2F5IHRlYW0uCgpUaGUgR2FiYmEgZG9lc24ndCBoYXZlIG1hbnkgbW9yZSBnYW1lcyBwbGF5ZWQgYXQgaXQgdGhhbiB0aGUgUy5DLkcgaG93ZXZlciwgaXQncyBpbnRlcmVzdGluZyB0aGF0IHRoZSBza2V3IGlzIHNvcnQgb2YgaW4gdGhlIGNvbXBsZXRlbHkgb3Bwb3NpdGUgZGlyZWN0aW9uLCB3aXRoIG5lYXJseSBoYWxmIHRoZSB0ZWFtcyBoYXZpbmcgYSAob3IgY2xvc2UgdG8gYSkgMTAwJSB3aW4gcmF0ZS4gVGhpcyBtYWtlcyBzZW5zZSB3aGVuIHlvdSBjb25zaWRlciB0aGF0IG1vc3Qgb2YgdGhlIHRlYW1zIHdvdWxkIGJlIGZhY2luZyB1cCBhZ2FpbnN0IHRoZSBob21lIHRlYW0sIEJyaXNiYW5lLCB3aG8gd2UndmUgYWxyZWFkeSBlc3RhYmxpc2hlZCBwcm9iYWJseSBhcmVuJ3QgdGhlIGJlc3QgdGVhbSB0byBiZSBwdXR0aW5nIHlvdXIgbW9uZXkgb24uCgohW10oZ2FiYmFfMi5wbmcpCiFbXShnYWJiYV8zLnBuZykKCioqKgoKIyMgX19Db25jbHVzaW9uc19fCgpXZSBzZXQgb3V0IHRvIGFjaGlldmUgcXVpdGUgYW4gYW1iaXRpb3VzIGdvYWw7IGNyZWF0ZSBzb21lIHNvcnQgb2YgcmVhbGx5IGludGVsbGlnZW50IHN0YXRpc3RpY2FsIG1vZGVsIGZvciBwcmVkaWN0aW5nIHdobyBtaWdodCB3aW4gYW55IGdpdmVuIEFGTCBtYXRjaC4gVW5mb3J0dW5hdGVseSwgd2UgZGlkbid0IHJlYWxseSBjb21lIGNsb3NlIHRvIGNyZWF0aW5nIHRoaXMgcGVyZmVjdCBtb2RlbCB3ZSBkcmVhbWVkIG9mIGhvd2V2ZXIsIG91ciBhbmFseXNpcyBhcyBhIHdob2xlIHdhcyBubyB3aGVyZSBuZWFyIHVzZWxlc3MsIGV2ZW4gY29uc2lkZXJpbmcgd2hhdCB3ZSBzZXQgb3V0IHRvIGFjaGlldmUuCgpPdXIgcHJlZGljdGl2ZSBtb2RlbHMgdGhlbXNlbHZlcyB3ZXJlIHByZXR0eSB1c2VsZXNzIGFzIHRoZXkgcmVxdWlyZSBhIGdhbWUgdG8gaGF2ZSBhbHJlYWR5IGZpbmlzaGVkIHRvIGFjdHVhbGx5IGNsYXNzaWZ5IHRoZSBnYW1lIHdpdGggc29tZSBzdWNjZXNzLiBIb3dldmVyLCB0aGV5J3ZlIHNob3duIHRoYXQgdGhlIGV4cGxhbmF0b3J5IHZhcmlhYmxlcyB0aGV5IGNvbnRhaW4gbXVzdCBoYXZlIHNvbWUgc29ydCBvZiBzaWduaWZpY2FudCBpbXBhY3Qgb24gd2hldGhlciBhIHRlYW0gd2lsbCB3aW4gb3IgbG9zZS4gV2UgYWxzbyBtYW5hZ2VkIHRvIGdldCB0aGF0IHF1aXRlIGluc2lnaHRmdWwgdHJlZSBkaWFncmFtIG91dCBvZiBvbmUgb2Ygb3VyIHByZWRpY3RpdmUgbW9kZWxzIHdoaWNoIGlzIHVzZWZ1bCBmb3IgZGV0ZXJtaW5pbmcgd2hhdCBjb21iaW5hdGlvbnMgb2YgJ2JlaGF2aW9ycycgd2l0aGluIGFuIEFGTCBnYW1lIGFyZSBtb3JlIGxpa2VseSB0byBsZWFkIHRvIGEgdGVhbSB3aW5uaW5nLgoKVWx0aW1hdGVseSwgdGhlIG1hbnksICptYW55KiBwbG90cyB0aGF0IHdlIGNyZWF0ZWQgYmFzZWQgYXJvdW5kIHRoZSB2YXJpb3VzIGRpZmZlcmVudCB2ZW51ZXMgYXJlIHNvbWUgb2YgdGhlIG1vc3QgdXNlZnVsIHBhcnRzIG9mIHRoZSBhbmFseXNpcyB3aXRoIHJlc3BlY3QgdG8gb3VyIGFjdHVhbCBnb2FsLiBXaGVuZXZlciB0d28gdGVhbXMgYXJlIHBsYXlpbmcgYXQgYW55IG9uZSBvZiB0aG9zZSB2ZW51ZXMgd2UgY2FuIGdsYW5jZSBvdmVyIGF0IG91ciBwbG90cyBhbmQgaGF2ZSBxdWl0ZSBhIGdvb2Qgb3ZlcnZpZXcgb2YgaG93IHdlbGwgZWFjaCB0ZWFtIHBsYXlzIHJlbGF0aXZlIHRvIG9uZSBhbm90aGVyLiBJdCdzIG5vdGhpbmcgY2xvc2UgdG8gcHJlZGljdGluZyBhbnkgdGVhbSB3aWxsIHdpbiB3aXRoIDk1JSBjb25maWRlbmNlIGJ1dCBpdCdzIGRlZmluaXRlbHkgdXNlZnVsIGluZm9ybWF0aW9uLCBhbmQgcHJvdmlkZXMgYXQgbGVhc3QgKmEgbGl0dGxlIGJpdCogb2YgYW4gYWR2YW50YWdlIGNvbXBhcmVkIHRvIGdvaW5nIGludG8gdGhlIGJldCBjb21wbGV0ZWx5IGJsaW5kLgoKSSB0aGluayB0aGF0IHdlJ3JlIGhlbGQgYmFjayBhIGxpdHRsZSBiaXQgYnkgb3VyIGRhdGEsIHdlIG9ubHkgaGF2ZSB0aGUgc3RhdGlzdGljcyBmb3IgYWZ0ZXIgYSBnYW1lIGhhcyBiZWVuIHBsYXllZC4gSWYgd2UgaGFkIGFjY2VzcyB0byBzb21lIHNvcnQgb2YgJ3JlYWwtdGltZScgZGF0YSwgd2hlcmUgd2UgY291bGQgc2VlIGEgbGlzdCBvZiB0aGVzZSBzdGF0aXN0aWNzIGF0IGNlcnRhaW4gdGltZXMgd2l0aGluIHRoZSBnYW1lIEkgdGhpbmsgaXQgd291bGQgYmUgbXVjaCBtb3JlIHZhbHVhYmxlIHRvIHdoYXQgd2Ugd2FudGVkIHRvIGFjaGlldmUgKEkgc3VzcGVjdCB0aGF0J3MgaG93IGJpZyBiZXR0aW5nIGNvbXBhbmllcyBtdXN0IGRvIGl0KS4gTWF5YmUgdGhlcmUncyBzb21lIHNvcnQgb2YgYSB0cmVuZCByaWdodCBiZWZvcmUgYSB0ZWFtIGlzIGFib3V0IHRvIG1ha2UgYSBjb21lYmFjayB0aGF0IHlvdSBjb3VsZCBwaWNrIG91dD8gSG93ZXZlciwgaXQgd291bGQgb25seSByZWFsbHkgYmUgcGxhdXNpYmxlIGlmIHlvdSBoYWQgdGhlIG1hdGNoIGRhdGEgb3ZlciB0aW1lLgoKSSB0aGluayB0aGF0IHRvIGltcHJvdmUgb3VyIHByb2plY3Qgd2Ugc2hvdWxkIGhhdmUgZGVmaW5pdGVseSBoYWQgYSBtb3JlIGluIGRlcHRoIHBsYW5uaW5nIHByb2Nlc3MgYW5kIGFwcHJvYWNoZWQgdGhlIGRhdGEgc2V0IGFmdGVyIGhhdmluZyBhIHZlcnkgY2xlYXIsIGNvbmNpc2UgZ29hbCBvZiB3aGF0IG5lZWRzIHRvIGdldCBkb25lIGluIG1pbmQuCgpPdmVyYWxsLCB3ZSd2ZSBjb21lIG91dCB3aXRoIHNvbWUgdXNlZnVsIHJlc291cmNlcyBmb3IgYXNzaXN0aW5nIGluIHByZWRpY3RpbmcgYSB3aW5uaW5nIHRlYW0gYW5kIGNsaW1iZWQgYSBtb3VudGFpbiBvZiBSLWNvZGUgYWxvbmcgdGhlIHdheSAtIHNvIEknZCBzYXkgaXQgd2FzIGEgc3VjY2Vzcy4KCioqKgoqKioKCiMjIF9fQXBwZW5kaXhfXwoKYGBge3J9CkFGTHN0YXRzIDwtIHJlYWQuY3N2KCJzdGF0cy5jc3YiKQpgYGAKCgpgYGB7cn0KQUZMIDwtIEFGTHN0YXRzCkFGTCA8LSBBRkxbYygxLDMsNCw1LDYsNyw4LDksMTAsMTEsMTIsMTMsMTQsMTUsMTYsMTcsMTgsMTksMjAsMjEsMjIsMjMsMjUsMjcsMjgsMjksMzAsMzEpXQpjb2xuYW1lcyhBRkwpCmBgYAoKYGBge3J9CnN1bV9uYW1lcyA8LSBjb2xuYW1lcyhBRkwpWzEwOjI4XQpzdW1fbmFtZXMKYGBgCgpgYGB7cn0KYWxsX3RlYW1zIDwtIHVuaXF1ZShhcy5jaGFyYWN0ZXIoQUZMJFRlYW0pKQpgYGAKCgpgYGB7cn0KYWQgPC0gQUZMW0FGTCRUZWFtID09IGFsbF90ZWFtc1sxXSxdCmJsIDwtIEFGTFtBRkwkVGVhbSA9PSBhbGxfdGVhbXNbMl0sXQpjbHQgPC0gQUZMW0FGTCRUZWFtID09IGFsbF90ZWFtc1szXSxdCmNsd2QgPC0gQUZMW0FGTCRUZWFtID09IGFsbF90ZWFtc1s0XSxdCmVzZG4gPC0gQUZMW0FGTCRUZWFtID09IGFsbF90ZWFtc1s1XSxdCmZkIDwtIEFGTFtBRkwkVGVhbSA9PSBhbGxfdGVhbXNbNl0sXQpnbG5nIDwtIEFGTFtBRkwkVGVhbSA9PSBhbGxfdGVhbXNbN10sXQpnYyA8LSBBRkxbQUZMJFRlYW0gPT0gYWxsX3RlYW1zWzhdLF0KZ3dzIDwtIEFGTFtBRkwkVGVhbSA9PSBhbGxfdGVhbXNbOV0sXQpodCA8LSBBRkxbQUZMJFRlYW0gPT0gYWxsX3RlYW1zWzEwXSxdCm1sYiA8LSBBRkxbQUZMJFRlYW0gPT0gYWxsX3RlYW1zWzExXSxdCm5tbGIgPC0gQUZMW0FGTCRUZWFtID09IGFsbF90ZWFtc1sxMl0sXQpwYWQgPC0gQUZMW0FGTCRUZWFtID09IGFsbF90ZWFtc1sxM10sXQpybWQgPC0gQUZMW0FGTCRUZWFtID09IGFsbF90ZWFtc1sxNF0sXQpzayA8LSBBRkxbQUZMJFRlYW0gPT0gYWxsX3RlYW1zWzE1XSxdCnN5ZCA8LSBBRkxbQUZMJFRlYW0gPT0gYWxsX3RlYW1zWzE2XSxdCndjIDwtIEFGTFtBRkwkVGVhbSA9PSBhbGxfdGVhbXNbMTddLF0Kd2IgPC0gQUZMW0FGTCRUZWFtID09IGFsbF90ZWFtc1sxOF0sXQpgYGAKCgpgYGB7cn0KY2xlYW5BRkxkYXRhIDwtIGZ1bmN0aW9uKHRlYW0pewogIAogIGxpYnJhcnkocGx5cikKICB0ZWFtX3N0YXRzIDwtIGRkcGx5KHRlYW0sIC4oRGF0ZSksIG51bWNvbHdpc2Uoc3VtKSkKICB0ZWFtX3N0YXRzIDwtIHRlYW1fc3RhdHNbYygxLDU6MjMpXQogIHRlYW1fa2VlcCA8LSB0ZWFtW21hdGNoKHVuaXF1ZSh0ZWFtJERhdGUpLCB0ZWFtJERhdGUpLF0KICB0ZWFtX2tlZXAgPC0gdGVhbV9rZWVwWzE6OV0KICB0ZWFtX2NsZWFuIDwtIG1lcmdlKHRlYW1fa2VlcCwgdGVhbV9zdGF0cykKICB0ZWFtX2NsZWFuIDwtIHRlYW1fY2xlYW5bdGVhbV9jbGVhbiRXaW5Mb3NzICE9ICJEIixdCiAgdGVhbV9jbGVhbiRXaW5Mb3NzIDwtIGRyb3BsZXZlbHModGVhbV9jbGVhbiRXaW5Mb3NzKQogIGxldmVscyh0ZWFtX2NsZWFuJFdpbkxvc3MpW2xldmVscyh0ZWFtX2NsZWFuJFdpbkxvc3MpPT0iTCJdIDwtIDAKICBsZXZlbHModGVhbV9jbGVhbiRXaW5Mb3NzKVtsZXZlbHModGVhbV9jbGVhbiRXaW5Mb3NzKT09IlciXSA8LSAxCiAgdGVhbV9jbGVhbiRXaW5Mb3NzIDwtIGZhY3Rvcih0ZWFtX2NsZWFuJFdpbkxvc3MpCiAgCiAgcmV0dXJuKHRlYW1fY2xlYW4pCiAgCn0KYGBgCgpgYGB7cn0Kc3lkX2NsZWFuIDwtIGNsZWFuQUZMZGF0YShzeWQpCmhlYWQoc3lkX2NsZWFuKQpgYGAKCgpgYGB7cn0KYWRfY2xlYW4gPC0gY2xlYW5BRkxkYXRhKGFkKQpibF9jbGVhbiA8LSBjbGVhbkFGTGRhdGEoYmwpCmNsdF9jbGVhbiA8LSBjbGVhbkFGTGRhdGEoY2x0KQpjbHdkX2NsZWFuIDwtIGNsZWFuQUZMZGF0YShjbHdkKQplc2RuX2NsZWFuIDwtIGNsZWFuQUZMZGF0YShlc2RuKQpmZF9jbGVhbiA8LSBjbGVhbkFGTGRhdGEoZmQpCmdsbmdfY2xlYW4gPC0gY2xlYW5BRkxkYXRhKGdsbmcpCmdjX2NsZWFuIDwtIGNsZWFuQUZMZGF0YShnYykKZ3dzX2NsZWFuIDwtIGNsZWFuQUZMZGF0YShnd3MpCmh0X2NsZWFuIDwtIGNsZWFuQUZMZGF0YShodCkKbWxiX2NsZWFuIDwtIGNsZWFuQUZMZGF0YShtbGIpCm5tbGJfY2xlYW4gPC0gY2xlYW5BRkxkYXRhKG5tbGIpCnBhZF9jbGVhbiA8LSBjbGVhbkFGTGRhdGEocGFkKQpybWRfY2xlYW4gPC0gY2xlYW5BRkxkYXRhKHJtZCkKc2tfY2xlYW4gPC0gY2xlYW5BRkxkYXRhKHNrKQpzeWRfY2xlYW4gPC0gY2xlYW5BRkxkYXRhKHN5ZCkKd2NfY2xlYW4gPC0gY2xlYW5BRkxkYXRhKHdjKQp3Yl9jbGVhbiA8LSBjbGVhbkFGTGRhdGEod2IpCmBgYAoKYGBge3J9CkFGTF9jbGVhbiA8LSByYmluZChhZF9jbGVhbiwgYmxfY2xlYW4sIGNsdF9jbGVhbiwgY2x3ZF9jbGVhbiwgZXNkbl9jbGVhbiwgZmRfY2xlYW4sIGdsbmdfY2xlYW4sIAogICAgICAgICAgICAgICAgICAgZ2NfY2xlYW4sIGd3c19jbGVhbiwgaHRfY2xlYW4sIG1sYl9jbGVhbiwgbm1sYl9jbGVhbiwgcGFkX2NsZWFuLCBybWRfY2xlYW4sCiAgICAgICAgICAgICAgICAgICBza19jbGVhbiwgc3lkX2NsZWFuLCB3Y19jbGVhbiwgd2JfY2xlYW4pCmxlbmd0aCh1bmlxdWUoQUZMX2NsZWFuJFRlYW0pKQpgYGAKCgpgYGB7cn0KQUZMLnRlc3QgPC0gQUZMX2NsZWFuW0FGTF9jbGVhbiRTZWFzb24gPT0gMjAxNixdCmhlYWQoQUZMLnRlc3QpCkFGTC50cmFpbiA8LSBBRkxfY2xlYW5bQUZMX2NsZWFuJFNlYXNvbiAhPSAyMDE2LF0KaGVhZChBRkwudHJhaW4pCmBgYAoKYGBge3J9CnBsb3QoQUZMLnRyYWluJFdpbkxvc3MsIEFGTC50cmFpbiREaXNwb3NhbHMpCmBgYAoKYGBge3J9CmxpYnJhcnkoZ2dwbG90MikKcXBsb3QoV2luTG9zcywgRGlzcG9zYWxzLCBkYXRhID0gQUZMLnRyYWluKQpgYGAKCmBgYHtyIHRlc3QyLCBmaWcud2lkdGg9MTUsIGZpZy5oZWlnaHQ9MTIsIGV2YWw9RkFMU0V9CnNvdXJjZSgiUGFpcnNXaXRoSGlzdC5SIikKcGFpcnMoQUZMX2NsZWFuLCBsb3dlci5wYW5lbCA9IHBhbmVsLnB0cywgdXBwZXIucGFuZWwgPSBwYW5lbC5jb3IsIGRpYWcucGFuZWwgPSBwYW5lbC5oaXN0KQpgYGAKCgpgYGB7cn0KIyBqdXN0ICdudW1lcmljYWwnIHZhcmlhYmxlcwpBRkwuZ2xtLm51bSA8LSBnbG0oV2luTG9zcyB+ICBEaXNwb3NhbHMgKyBNYXJrcyArIEJlaGluZHMgKyBJbnNpZGU1MHMgKyBDbGVhcmFuY2VzICsgQ2xhbmdlcnMgKyBDb250ZW5kZWRQb3NzZXNzaW9ucyArIENvbnRlc3RlZE1hcmtzICsgTWFya3NJbnNpZGU1MCwgCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBBRkwudHJhaW4sIGZhbWlseSA9IGJpbm9taWFsKGxvZ2l0KSkKYGBgCgpgYGB7cn0KIyAnYWxsJyB2YXJpYWJsZXMgKE1hcmdpbiBleGNsdWRlZCBiZWNhdXNlIHRvbyBwZXJmZWN0KQpBRkwuZ2xtLmFsbCA8LSBnbG0oV2luTG9zcyB+ICBTY29yZSArIE9wcG9zaXRpb24gKyBWZW51ZSArIERpc3Bvc2FscyArIE1hcmtzICsgR29hbHMgKyBCZWhpbmRzICsgSGl0b3V0cyArIFRhY2tsZXMgKyBSZWJvdW5kNTBzICsgSW5zaWRlNTBzICsgQ2xlYXJhbmNlcyArIENsYW5nZXJzICsgRnJlZXNGb3IgKyBDb250ZW5kZWRQb3NzZXNzaW9ucyArIENvbnRlc3RlZE1hcmtzICsgTWFya3NJbnNpZGU1MCArIE9uZVBlcmNlbnRlcnMgKyBCb3VuY2VzK0dvYWxBc3Npc3RzLCAKICAgICAgICAgICAgICAgICAgZGF0YSA9IEFGTC50cmFpbiwgZmFtaWx5ID0gYmlub21pYWwpCiNzdW1tYXJ5KEFGTC5nbG0uYWxsKQpgYGAKCgpgYGB7cn0KQUZMLmdsbS4wIDwtIGdsbShXaW5Mb3NzIH4gMSwgZGF0YSA9IEFGTC50cmFpbiwgZmFtaWx5ID0gYmlub21pYWwobG9naXQpKQpgYGAKCmBgYHtyfQpBRkwuZ2xtLmZ3ZCA8LSBzdGVwKEFGTC5nbG0uMCwgc2NvcGUgPSBmb3JtdWxhKEFGTC5nbG0ubnVtKSwgZGlyZWN0aW9uID0gImZvcndhcmQiLCB0cmFjZSA9IDApCnN1bW1hcnkoQUZMLmdsbS5md2QpCmBgYAoKYGBge3J9CkFGTC5hbGwucHJlZCA8LSBwcmVkaWN0KEFGTC5nbG0uZndkLCBuZXdkYXRhID0gQUZMLnRlc3QsIHR5cGUgPSAicmVzcG9uc2UiKQpoZWFkKEFGTC5hbGwucHJlZCkKYGBgCgpgYGB7cn0KQUZMLmFsbC5wcmVkLmNsYXNzIDwtIHJlcCgwLCBsZW5ndGgoQUZMLmFsbC5wcmVkKSkKQUZMLmFsbC5wcmVkLmNsYXNzW0FGTC5hbGwucHJlZCA+IDAuNzVdIDwtIDEKdGFibGUoQUZMLmFsbC5wcmVkLmNsYXNzLCBBRkwudGVzdCRXaW5Mb3NzKQpgYGAKCmBgYHtyfQooMTg4KzEzMikvKDE4OCs3NSsxOSsxMzIpCmBgYAoKYGBge3J9CmxpYnJhcnkocnBhcnQpCkFGTC50cmVlIDwtIHJwYXJ0KFdpbkxvc3MgfiAgT3Bwb3NpdGlvbiArIFZlbnVlICsgRGlzcG9zYWxzICsgTWFya3MgKyBHb2FscyArIEJlaGluZHMgKyBIaXRvdXRzICsgVGFja2xlcyArIFJlYm91bmQ1MHMgKyBJbnNpZGU1MHMgKyBDbGVhcmFuY2VzICsgQ2xhbmdlcnMgKyBGcmVlc0ZvciArIENvbnRlbmRlZFBvc3Nlc3Npb25zICsgQ29udGVzdGVkTWFya3MgKyBNYXJrc0luc2lkZTUwICsgT25lUGVyY2VudGVycyArIEJvdW5jZXMgKyBHb2FsQXNzaXN0cywgCiAgICAgICAgICAgICAgICAgIEFGTF9jbGVhbikKI3N1bW1hcnkoQUZMLnRyZWUpCmBgYAoKYGBge3J9CmxpYnJhcnkocnBhcnQpCkFGTC5udW0udHJlZSA8LSBycGFydChXaW5Mb3NzIH4gIERpc3Bvc2FscyArIE1hcmtzICsgQmVoaW5kcyArIEluc2lkZTUwcyArIENsZWFyYW5jZXMgKyBDbGFuZ2VycyArIENvbnRlbmRlZFBvc3Nlc3Npb25zICsgQ29udGVzdGVkTWFya3MgKyBNYXJrc0luc2lkZTUwLCAKICAgICAgICAgICAgICAgICAgQUZMX2NsZWFuKQpgYGAKCgpgYGB7cn0KQUZMLm51bS50cmVlLnByZWQgPSBwcmVkaWN0KEFGTC5udW0udHJlZSwgQUZMLnRlc3QpCkFGTC5udW0udHJlZS5wcmVkIDwtIEFGTC5udW0udHJlZS5wcmVkWywyXQpoZWFkKEFGTC5udW0udHJlZS5wcmVkKQpgYGAKCmBgYHtyfQpBRkwubnVtLnRyZWUuY2xhc3MgPC0gcmVwKDAsIGxlbmd0aChBRkwubnVtLnRyZWUucHJlZCkpCkFGTC5udW0udHJlZS5jbGFzc1tBRkwubnVtLnRyZWUucHJlZCA+IDAuNzVdIDwtIDEKdGFibGUoQUZMLm51bS50cmVlLmNsYXNzLCBBRkwudGVzdCRXaW5Mb3NzKQpgYGAKCmBgYHtyfQooMTcyICsgMTM3KS8oMTcyKzcwKzM1KzEzNykKYGBgCgoKYGBge3IgdGVzdDMsIGZpZy53aWR0aD0yMCwgZmlnLmhlaWdodD0xMiwgZXZhbD1GQUxTRX0KbGlicmFyeShycGFydC5wbG90KQpsaWJyYXJ5KHJhbmRvbUZvcmVzdCkKbGlicmFyeShwYXJ0eWtpdCkKcGxvdChhcy5wYXJ0eShBRkwudHJlZSkpCmBgYAoKYGBge3J9CmxpYnJhcnkocnBhcnQpCkFGTC50ZWFtcyA8LSBycGFydChXaW5Mb3NzIH4gIFRlYW0gKyBPcHBvc2l0aW9uLAogICAgICAgICAgICAgICAgICBBRkxfY2xlYW4pCmBgYAoKYGBge3IgdGVzdDQsIGZpZy53aWR0aD02MCwgZmlnLmhlaWdodD0yMCwgZXZhbD1GQUxTRX0KbGlicmFyeShycGFydC5wbG90KQpsaWJyYXJ5KHJhbmRvbUZvcmVzdCkKbGlicmFyeShwYXJ0eWtpdCkKcGxvdChhcy5wYXJ0eShBRkwudGVhbXMpKQpgYGAKCmBgYHtyfQpsaWJyYXJ5KHJwYXJ0KQpBRkwudmVudWUgPC0gcnBhcnQoV2luTG9zcyB+ICBUZWFtICsgVmVudWUsCiAgICAgICAgICAgICAgICAgIEFGTF9jbGVhbikKYGBgCgpgYGB7ciB0ZXN0NSwgZmlnLndpZHRoPTUwLCBmaWcuaGVpZ2h0PTIwLCBldmFsPUZBTFNFfQpsaWJyYXJ5KHJwYXJ0LnBsb3QpCmxpYnJhcnkocmFuZG9tRm9yZXN0KQpsaWJyYXJ5KHBhcnR5a2l0KQpwbG90KGFzLnBhcnR5KEFGTC52ZW51ZSkpCmBgYAoKYGBge3IgMDAwMDIsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD03LCBldmFsPUZBTFNFfQpsaWJyYXJ5KHJwYXJ0LnBsb3QpCmxpYnJhcnkocmFuZG9tRm9yZXN0KQpsaWJyYXJ5KHBhcnR5a2l0KQpwbG90KGFzLnBhcnR5KEFGTC5udW0udHJlZSkpCmBgYAoKYGBge3J9CmxpYnJhcnkoY2xhc3MpCkFGTC5rbm4ucHJlZCA8LSBrbm4oQUZMLnRyYWluWyxjKCJEaXNwb3NhbHMiLCAiTWFya3MiLCAiQmVoaW5kcyIsICJJbnNpZGU1MHMiLCAiQ2xlYXJhbmNlcyIsICJDbGFuZ2VycyIsICJDb250ZW5kZWRQb3NzZXNzaW9ucyIsICJDb250ZXN0ZWRNYXJrcyIsICJNYXJrc0luc2lkZTUwIildLCBBRkwudGVzdFssYygiRGlzcG9zYWxzIiwgIk1hcmtzIiwgIkJlaGluZHMiLCAiSW5zaWRlNTBzIiwgIkNsZWFyYW5jZXMiLCAiQ2xhbmdlcnMiLCAiQ29udGVuZGVkUG9zc2Vzc2lvbnMiLCAiQ29udGVzdGVkTWFya3MiLCAiTWFya3NJbnNpZGU1MCIpXSwgQUZMLnRyYWluJFdpbkxvc3MsIAogICAgayA9IDMpCnRhYmxlKEFGTC5rbm4ucHJlZCwgQUZMLnRlc3QkV2luTG9zcykKYGBgCgpgYGB7cn0KKDE0MysxNjgpLygxNDMrMzkrNjQrMTY4KQpgYGAKCmBgYHtyfQp1bmlxdWUoQUZMX2NsZWFuJFZlbnVlKQpucm93KEFGTF9jbGVhbltBRkxfY2xlYW4kVmVudWUgPT0gIlRyYWVnZXIgUGFyayIsXSkKYGBgCgpgYGB7cn0KdGFibGUoQUZMX2NsZWFuJFZlbnVlKQpgYGAKCgpgYGB7cn0KdGFibGVfYWxsIDwtIHRhYmxlKEFGTF9jbGVhbiRUZWFtLCBBRkxfY2xlYW4kV2luTG9zcykgICMgd2lucyBhbmQgbG9zc2VzIGZvciBlYWNoIHRlYW0KCiMgY3JlYXRpbmcgdGFibGVzIG9mIGVhY2ggdGVhbSBhbmQgdGhpZXIgd2lucy9sb3NzZXMgYWdhaW5zdCBvcHBvc2l0aW9uCnRhYmxlX2FkIDwtIHRhYmxlKGFkX2NsZWFuJE9wcG9zaXRpb24sIGFkX2NsZWFuJFdpbkxvc3MpCnRhYmxlX3djIDwtIHRhYmxlKHdjX2NsZWFuJE9wcG9zaXRpb24sIHdjX2NsZWFuJFdpbkxvc3MpCnRhYmxlX2JsIDwtIHRhYmxlKGJsX2NsZWFuJE9wcG9zaXRpb24sIGJsX2NsZWFuJFdpbkxvc3MpCnRhYmxlX2NsdCA8LSB0YWJsZShjbHRfY2xlYW4kT3Bwb3NpdGlvbiwgY2x0X2NsZWFuJFdpbkxvc3MpCnRhYmxlX2Nsd2QgPC0gdGFibGUoY2x3ZF9jbGVhbiRPcHBvc2l0aW9uLCBjbHdkX2NsZWFuJFdpbkxvc3MpCnRhYmxlX2VzZG4gPC0gdGFibGUoZXNkbl9jbGVhbiRPcHBvc2l0aW9uLCBlc2RuX2NsZWFuJFdpbkxvc3MpCnRhYmxlX2ZkIDwtIHRhYmxlKGZkX2NsZWFuJE9wcG9zaXRpb24sIGZkX2NsZWFuJFdpbkxvc3MpCnRhYmxlX2djIDwtIHRhYmxlKGdjX2NsZWFuJE9wcG9zaXRpb24sIGdjX2NsZWFuJFdpbkxvc3MpCnRhYmxlX2dsbmcgPC0gdGFibGUoZ2xuZ19jbGVhbiRPcHBvc2l0aW9uLCBnbG5nX2NsZWFuJFdpbkxvc3MpCnRhYmxlX2d3cyA8LSB0YWJsZShnd3NfY2xlYW4kT3Bwb3NpdGlvbiwgZ3dzX2NsZWFuJFdpbkxvc3MpCmBgYAoKCmBgYHtyIHQsIGZpZy53aWR0aD0yNSwgZmlnLmhlaWdodD0xMCwgZXZhbD1GQUxTRX0KIyBQbG90dGluZyBNb3NhaWNzCgpsaWJyYXJ5KHZjZCkKCm1vc2FpY3Bsb3QodGFibGVfYWxsLCBjb2w9YygicmVkIiwiZGFya2dyZWVuIiksIG1haW4gPSAiV2lucyZMb3NzZXMgYWdhaW5zdCBlYWNoIHRlYW0gKDIwMTItMjAxNikiLCB4bGFiID0gIlRlYW0iLCB5bGFiID0gIldpbiBvciBsb3NzIikKCm1vc2FpY3Bsb3QodGFibGVfd2MsIGNvbD1jKCJyZWQiLCJkYXJrZ3JlZW4iKSxtYWluID0gIldlc3QgQ29hc3QgYW5kIHRoZWlyIHdpbnMgYW5kIGxvc3NlcyBhZ2FpbnN0IGVhY2ggdGVhbSAoMjAxMi0yMDE2KSIsICB4bGFiID0gIlRlYW0iLCB5bGFiID0gIldpbiBvciBsb3NzIikKCm1vc2FpY3Bsb3QodGFibGVfYWQsIGNvbD1jKCJyZWQiLCJkYXJrZ3JlZW4iKSwgbWFpbiA9ICJBZGVsYWlkZSBhbmQgdGhlaXIgd2lucyBhbmQgbG9zc2VzIGFnYWluc3QgZWFjaCB0ZWFtICgyMDEyLTIwMTYpIiwgIHhsYWIgPSAiVGVhbSIsIHlsYWIgPSAiV2luIG9yIGxvc3MiKQoKbW9zYWljcGxvdCh0YWJsZV9ibCwgY29sPWMoInJlZCIsImRhcmtncmVlbiIpLG1haW4gPSAiQnJpc2JhbmUgTGlvbnMgYW5kIHRoZWlyIHdpbnMgYW5kIGxvc3NlcyBhZ2FpbnN0IGVhY2ggdGVhbSAoMjAxMi0yMDE2KSIsICB4bGFiID0gIlRlYW0iLCB5bGFiID0gIldpbiBvciBsb3NzIikKCm1vc2FpY3Bsb3QodGFibGVfY2x0LCBjb2w9YygicmVkIiwiZGFya2dyZWVuIiksbWFpbiA9ICJDYXJsdG9uIGFuZCB0aGVpciB3aW5zIGFuZCBsb3NzZXMgYWdhaW5zdCBlYWNoIHRlYW0gKDIwMTItMjAxNikiLCAgeGxhYiA9ICJUZWFtIiwgeWxhYiA9ICJXaW4gb3IgbG9zcyIpCgptb3NhaWNwbG90KHRhYmxlX2Nsd2QsIGNvbD1jKCJyZWQiLCJkYXJrZ3JlZW4iKSxtYWluID0gIkNvbGxpbmd3b29kIGFuZCB0aGVpciB3aW5zIGFuZCBsb3NzZXMgYWdhaW5zdCBlYWNoIHRlYW0gKDIwMTItMjAxNikiLCAgeGxhYiA9ICJUZWFtIiwgeWxhYiA9ICJXaW4gb3IgbG9zcyIpCmBgYAoKCmBgYHtyfQphbGxfZnJlcSA8LSBhcy5kYXRhLmZyYW1lLm1hdHJpeCh0YWJsZV9hbGwpCmFsbF9mcmVxIDwtIGFsbF9mcmVxW29yZGVyKGFsbF9mcmVxJGAxYCwgZGVjcmVhc2luZyA9IFRSVUUpLF0KYWxsX2ZyZXEKYGBgCgpgYGB7ciB0NiwgZmlnLndpZHRoPTIwLCBmaWcuaGVpZ2h0PTh9Cm1vc2FpY3Bsb3QoYWxsX2ZyZXEsIGNvbD1jKCJyZWQiLCJkYXJrZ3JlZW4iKSwgbWFpbiA9ICJXaW4gdnMgTG9zcyBGcmVxdWVuY3kgZm9yIGVhY2ggdGVhbSAoMjAxMi0yMDE2KSIsIGNleC5heGlzID0gMS4yKQpgYGAKCmBgYHtyfQp3aW5fcGVyYyA8LSBhbGxfZnJlcSRgMWAgLyAoYWxsX2ZyZXEkYDBgICsgYWxsX2ZyZXEkYDFgKQpsb3NzX3BlcmMgPC0gMSAtIHdpbl9wZXJjCmFsbF9wZXJjIDwtIGNiaW5kKGFsbF9mcmVxLCBsb3NzX3BlcmMsIHdpbl9wZXJjKQphbGxfcGVyYyA8LSBhbGxfcGVyY1szOjRdCmNvbG5hbWVzKGFsbF9wZXJjKSA8LSBjKCJMb3NzIFBlcmNlbnRhZ2UiLCAiV2luIFBlcmNlbnRhZ2UiKQphbGxfcGVyYwpgYGAKCgpgYGB7ciB0NywgZmlnLndpZHRoPTIwLCBmaWcuaGVpZ2h0PTh9Cm1vc2FpY3Bsb3QoYWxsX3BlcmMsIGNvbD1jKCJyZWQiLCJkYXJrZ3JlZW4iKSwgbWFpbiA9ICJXaW4gdnMgTG9zcyBQZXJjZW50YWdlIGZvciBlYWNoIHRlYW0gKDIwMTItMjAxNikiLCBjZXguYXhpcyA9IDEuMikKYGBgCgpgYGB7cn0KYWxsX3BlcmNfZGVjciA8LSBhbGxfcGVyY1tvcmRlcihhbGxfcGVyYyRgV2luIFBlcmNlbnRhZ2VgLCBkZWNyZWFzaW5nID0gVFJVRSksXQphbGxfcGVyY19kZWNyCmBgYAoKCgpgYGB7ciAwMDA0LCBmaWcud2lkdGg9MjUsIGZpZy5oZWlnaHQ9Nn0KbW9zYWljcGxvdChhbGxfcGVyY19kZWNyLCBjb2w9YyhyZ2IoMjE1LzI1NSwyNS8yNTUsMjgvMjU1KSxyZ2IoMTY2LzI1NSwyMTcvMjU1LDEwNi8yNTUpKSwgbWFpbiA9ICJUb3RhbCBXaW4gdnMgTG9zcyBQZXJjZW50YWdlIGZvciBlYWNoIHRlYW0gKDIwMTItMjAxNikgW0Rlc2NlbmRpbmcgT3JkZXJdIiwgY2V4LmF4aXMgPSAxLjIpCmBgYAoKYGBge3J9CmxpYnJhcnkobGF0dGljZSkKYmFyY2hhcnQoQUZMX2NsZWFuJFNjb3JlIH4gQUZMX2NsZWFuJFRlYW0gfCBBRkxfY2xlYW4kVmVudWUpCmBgYAoKYGBge3J9CnZlbnVlRmlsdGVyIDwtIGZ1bmN0aW9uKHZlbnVlKXsKICAKICBBRkxfdmVudWUgPC0gQUZMX2NsZWFuW0FGTF9jbGVhbiRWZW51ZSA9PSB2ZW51ZSxdCiAgdmVudWVfdGFibGUgPC0gdGFibGUoQUZMX3ZlbnVlJFRlYW0sIEFGTF92ZW51ZSRXaW5Mb3NzKQogIHZlbnVlX2RmIDwtIGFzLmRhdGEuZnJhbWUubWF0cml4KHZlbnVlX3RhYmxlKQogIHZlbnVlX2ZyZXEgPC0gdmVudWVfZGZbb3JkZXIodmVudWVfZGYkYDFgLCBkZWNyZWFzaW5nID0gVFJVRSksXQogIAogIHdpbl9wZXJjIDwtIHZlbnVlX2ZyZXEkYDFgIC8gKHZlbnVlX2ZyZXEkYDBgICsgdmVudWVfZnJlcSRgMWApCiAgbG9zc19wZXJjIDwtIDEgLSB3aW5fcGVyYwogIGFsbF9wZXJjIDwtIGNiaW5kKHZlbnVlX2ZyZXEsIGxvc3NfcGVyYywgd2luX3BlcmMpCiAgYWxsX3BlcmMgPC0gYWxsX3BlcmNbMzo0XQogIGNvbG5hbWVzKGFsbF9wZXJjKSA8LSBjKCJMb3NzIFBlcmNlbnRhZ2UiLCAiV2luIFBlcmNlbnRhZ2UiKQogICNhbGxfcGVyYwogIAogIHRlYW1fdG90YWwgPC0gKHZlbnVlX2ZyZXEkYDBgICsgdmVudWVfZnJlcSRgMWApCiAgZ2FtZV90b3RhbHMgPC0gc3VtKHRlYW1fdG90YWwpCiAgdGVhbV9wcm9wb3J0aW9uIDwtIHRlYW1fdG90YWwgLyBnYW1lX3RvdGFscwogIHZlbnVlX2ZyZXEgPC0gY2JpbmQodmVudWVfZnJlcSwgdGVhbV9wcm9wb3J0aW9uKQogICN2ZW51ZV9mcmVxCiAgCiAgYWxsX3ZlbnVlIDwtIGNiaW5kKHZlbnVlX2ZyZXEsIGFsbF9wZXJjKQogIGFsbF92ZW51ZSA8LSBhbGxfdmVudWVbb3JkZXIoYWxsX3ZlbnVlJGBXaW4gUGVyY2VudGFnZWAsIGRlY3JlYXNpbmcgPSBUUlVFKSxdCiAgcmV0dXJuKGFsbF92ZW51ZSkKCn0KYGBgCgpgYGB7cn0Kc3ViaWFjbyA8LSB2ZW51ZUZpbHRlcigiU3ViaWFjbyIpCnN5ZC5zaG93Z3JvdW5kIDwtIHZlbnVlRmlsdGVyKCJTeWRuZXkgU2hvd2dyb3VuZCIpCmdhYmJhIDwtIHZlbnVlRmlsdGVyKCJHYWJiYSIpCm1jZyA8LSB2ZW51ZUZpbHRlcigiTS5DLkcuIikKc2NnIDwtIHZlbnVlRmlsdGVyKCJTLkMuRy4iKQphZGwub3ZhbCA8LSB2ZW51ZUZpbHRlcigiQWRlbGFpZGUgT3ZhbCIpCmNhcnJhcmEgPC0gdmVudWVGaWx0ZXIoIkNhcnJhcmEiKQpkb2NrbGFuZHMgPC0gdmVudWVGaWx0ZXIoIkRvY2tsYW5kcyIpCmZ0YmwucGFyayA8LSB2ZW51ZUZpbHRlcigiRm9vdGJhbGwgUGFyayIpCmBgYAoKYGBge3J9CnN1bShnYWJiYVsxXSArIGdhYmJhWzJdKQpnYWJiYQpgYGAKCgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQoKZ2FiYmEudHByb3AgPC0gZ2FiYmFbM10KYnAgPC0gZ2dwbG90KGdhYmJhLnRwcm9wLCBhZXMoeD0iIiwgeT10ZWFtX3Byb3BvcnRpb24sIGZpbGw9cm93Lm5hbWVzKGdhYmJhLnRwcm9wKSkgKSArIGdlb21fYmFyKHdpZHRoID0gMSwgc3RhdCA9ICJpZGVudGl0eSIpICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIiM5OTk5OTkiLCAiI0U2OUYwMCIsICIjNTZCNEU5IiwgIiM4ZmMwYTAiLCAiI2NjOWI1YiIsICIjNzE1MjliIiwgIiM3YmY2OGQiLCAiIzk2MjcwZiIsICIjMWU0NmJlIiwgIiNiNjBlZGMiLCAiIzY3OGRiZCIsICIjNGViMjBiIiwgIiM1ZjM3ZTUiLCAiIzAyMzM5YiIsICIjYTdhNGRmIiwgIiMyYjY4MWUiLCAiIzJjM2Y3YyIsICIjZDllZDhmIikpCmJwCgpwaWUgPC0gYnAgKyBjb29yZF9wb2xhcigieSIsIHN0YXJ0PTApCnBpZQpgYGAKCmBgYHtyIDAwMDMsIGZpZy53aWR0aD0yOCwgZmlnLmhlaWdodD02fQpnYWJiYS53cGVyYyA8LSBnYWJiYVs0OjVdCiNzdWJpYWNvLndwZXJjCgptb3NhaWNwbG90KGdhYmJhLndwZXJjLCBjb2w9YyhyZ2IoMjE1LzI1NSwyNS8yNTUsMjgvMjU1KSxyZ2IoMTY2LzI1NSwyMTcvMjU1LDEwNi8yNTUpKSwgbWFpbiA9ICJUb3RhbCBXaW4gdnMgTG9zcyBQZXJjZW50YWdlIGZvciBlYWNoIHRlYW0gYXQgU3ViaWFjbyBPdmFsICgyMDEyLTIwMTYpIFtEZXNjZW5kaW5nIE9yZGVyXSIsIGNleC5heGlzID0gMS4yKQpgYGAKCgoqKio=