Data
The original source of the data set is Cricsheet.org. The data is available in YAML format with different matches recorded in different files. This data was combined by Kaggle users and were provided in the Kaggle website for downloads. The data was provided in 3 different files, including data for team, data for the player information and match data. Click to download the Team data, Player Data and Match Data from Kaggle. The Team data contains team informations given below:
1. Team_Id - Primary key for the team table
2. Team_Name - Name of the Team
3. Team_Short_Code - Short code for each team
The Player dataset contains information given below:
1. Player_Id - Primary key for the player table
2. Player_Name - Name of the player
3. DOB - Date of Birth of the player
4. Batting_Hand - Batting Hand of the Player
5. Bowling_Skill - Type of bowling practised by the bowler
5. Country - Country of the Player
6. Is_Umpire - Person is Umpire or not
The Match dataset contains the information given below:
1. Match_Id - Primary key for Match table
2. Match_Date - Date of match
3. Season - Season of the match
4. Venue_Name - Venue of the match
5. Toss_Decision - Outcome of the Toss
6. Win_Type - Winning Type of the Match
7. Won_By - Number of runs or wickets team won the match
8. City_Name - Name of the city where is match is happening
9. Host_Country - Name of the Country Hosting the match
10. Team_1 - Name of one Team
11. Team_2 - Name of team two
12. Toss_Winner - Name of the team winning the Toss
13. Match_Winner - Name of the winning Team
14. Man_Of_The_Matc - Name of the Man of the Match player
15. DOB - Date of Birth of the man of the match player
16. Player_Country - Man of The Match player country name
17. Age - Age of the Man of the Match player
The Match dataset is the main datset where we are merging other two tables into. This dataset contains Team ID information for both the teams in the match, winning team ID, Man of the Match player ID etc which are used as the key for merging. The ER Diagram of the datasets are given below. 
Importing datasets
Team <- read_csv("Cricket/Team.csv") %>% as.data.frame()
Player <- read_csv("Cricket/Player.csv",
col_types = cols(X8 = col_skip())) %>% as.data.frame()
Match <- read_csv("Cricket/Match.csv") %>% as.data.frame()
The datasets are imported using the read_csv function as data frames. The read files are saves in to files named Team, Player, and Match. The player dataset contained an eighth column which was a null column. We removed that column using col_skip function. The head of the datsets are given below.
head(Team) # Head of Team dataset
head(Player) # Head of Player dataset
head(Match) # Head of Match dataset
Dataset Merging
The Match data set is taking data from other two data sets for filling in the informations like team names, player names etc. Left_join is used to merge the datasets. All the variables in Match dataset is kept and only few necessary variables from other datsets are merged in to Match dataset. The below code shows Match dataset and the Team dataset where Team_Id is used as the common key. This is used as the Team1 details with the team names. The column Team_Name_Id is then removed from the Match dataset.
# Taking team name for Team1 from Team table
Match <- Match %>%
left_join(select(Team, Team_Id, Team_Name),
c("Team_Name_Id" = "Team_Id")) %>%
rename(Team_1 = "Team_Name") %>%
select(-Team_Name_Id)
The code below shoes the merging of Match dataset with the Team dataset for substituting the opponent team IDs with the team names. This column is then given the name as Team_2.
# Taking team name for Team2 from Team table
Match <- Match %>%
left_join(select(Team, Team_Id, Team_Name),
c("Opponent_Team_Id" = "Team_Id")) %>%
rename(Team_2 = "Team_Name") %>%
select(-Opponent_Team_Id)
The Toss_Winner_Id is replaced with the corrosponding team names by joining Match dataset with Team dataset on Team_Id and Toss_Winner_Id. Toss_Winner_Id is then removed from the datset.
# Taking team name for Toss Winner from Team table
Match <- Match %>%
left_join(select(Team, Team_Id, Team_Name),
c("Toss_Winner_Id" = "Team_Id")) %>%
rename(Toss_Winner = "Team_Name") %>%
select(-Toss_Winner_Id)
The variable Match_Winner_Id is replaced with the corrosponding team names by joining Match dataset with Team dataset on Team_Id and Match_Winner_Id. Match_Winner_Id is then removed from the datset.
# Taking team name for Match winner from Team table
Match <- Match %>%
left_join(select(Team, Team_Id, Team_Name),
c("Match_Winner_Id" = "Team_Id")) %>%
rename(Match_Winner = "Team_Name") %>%
select(-Match_Winner_Id)
Additional Data is added to the Match dataset from the Player dataset by using left_join. The datasets are joined using the column Man_Of_The_Match_Id from the Match datset and Player_Id from the player dataset. Man_Of_The_Match_Id is replaced with the corrosposnding player names. Additional variables like player date of birth and player country are added to the dataset.
# Taking player name from player table
Match <- Match %>%
left_join(select(Player, Player_Id, Player_Name, DOB, Country),
c("Man_Of_The_Match_Id"="Player_Id")) %>%
rename(Player_Country = "Country", Man_Of_The_Match="Player_Name") %>%
select(-Man_Of_The_Match_Id)
The head of the dataset after all the merging is given below.
head(Match)
Understand the data
The structure of the Match dataset is given below.
str(Match, vec.len=2) # Structure of Match data
'data.frame': 577 obs. of 16 variables:
$ Match_Id : int 335987 335988 335989 335990 335991 ...
$ Match_Date : chr "18-Apr-08" "19-Apr-08" ...
$ Season_Id : int 1 1 1 1 1 ...
$ Venue_Name : chr "M Chinnaswamy Stadium" "Punjab Cricket Association Stadium, Mohali" ...
$ Toss_Decision : chr "field" "bat" ...
$ Win_Type : chr "by runs" "by runs" ...
$ Won_By : chr "140" "33" ...
$ City_Name : chr "Bangalore" "Chandigarh" ...
$ Host_Country : chr "India" "India" ...
$ Team_1 : chr "Royal Challengers Bangalore" "Kings XI Punjab" ...
$ Team_2 : chr "Kolkata Knight Riders" "Chennai Super Kings" ...
$ Toss_Winner : chr "Royal Challengers Bangalore" "Chennai Super Kings" ...
$ Match_Winner : chr "Kolkata Knight Riders" "Chennai Super Kings" ...
$ Man_Of_The_Match: chr "BB McCullum" "MEK Hussey" ...
$ DOB : chr "27-Sep-81" "27-May-75" ...
$ Player_Country : chr "New Zealand" "Australia" ...
There are 577 observations with 17 variables. Except Match_ID and Season_ID, all other variables are character variables. Match_Date and DOB are date variables and are represented as character here. Similarly, the variable Won_by is showing the run by which the team has won. It is an integer variable and is represent as character. Also there are some variable which should hav been factor by default.
Data Type Conversions
Now we will convert all these variables into their respective formats.
Date Conversions
The variables to be converted as date type are Match_Date and DOB. The date format given here is DD-MM-YY. So we will use the Lubridate function dmy() to covert in to date type.
colm1 <- c("Match_Date", "DOB") #Columns to be converted
Match[colm1] <- lapply(Match[colm1], dmy) # List apply the dmy() function
str(Match[colm1]) # Structure after aconversion
'data.frame': 577 obs. of 2 variables:
$ Match_Date: Date, format: "2008-04-18" ...
$ DOB : Date, format: "1981-09-27" ...
The columns has been successfully converted to date format.
Character to factor conversion
The variables to be converted as factor type are Season_Id, Toss_Decision, Win_Type, City_Name, Host_Country, Team_1, Team_2, Toss_Winner, Match_Winner, and Player_Country. These variable names are first saved as a list and then fed this in to a list apply function with factor function in it.
colm2 <- c("Season_Id", "Toss_Decision", "Win_Type", "City_Name", "Host_Country",
"Team_1", "Team_2", "Toss_Winner", "Match_Winner", "Player_Country")
Match[colm2] <- lapply(Match[colm2], factor) # Factor conversion
summary(Match[colm2]) # summary of the factor variables
Season_Id Toss_Decision Win_Type City_Name
6 : 76 bat :262 by runs :261 Mumbai : 77
5 : 74 field:315 by wickets:307 Bangalore : 58
4 : 73 No Result : 3 Kolkata : 54
3 : 60 Tie : 6 Delhi : 53
7 : 60 Chennai : 48
9 : 60 Chandigarh: 42
(Other):174 (Other) :245
Host_Country Team_1
India :500 Royal Challengers Bangalore: 78
South Africa: 57 Chennai Super Kings : 74
U.A.E : 20 Delhi Daredevils : 69
Kings XI Punjab : 65
Kolkata Knight Riders : 62
Mumbai Indians : 62
(Other) :167
Team_2 Toss_Winner
Mumbai Indians : 78 Mumbai Indians : 74
Kolkata Knight Riders : 70 Kolkata Knight Riders: 69
Kings XI Punjab : 69 Chennai Super Kings : 66
Rajasthan Royals : 66 Delhi Daredevils : 64
Delhi Daredevils : 64 Kings XI Punjab : 64
Royal Challengers Bangalore: 61 Rajasthan Royals : 63
(Other) :169 (Other) :177
Match_Winner Player_Country
Mumbai Indians : 80 India :293
Chennai Super Kings : 79 Australia :110
Royal Challengers Bangalore: 70 South Africa: 63
Kolkata Knight Riders : 68 West Indies : 53
Kings XI Punjab : 63 Sri Lanka : 24
(Other) :214 (Other) : 31
NA's : 3 NA's : 3
Charater to Integer conversion
The variable Won_By should be an interger variables as it represents runs. So we are converting them to integer by using the the following function.
Match$Won_By <- as.integer(Match$Won_By)
summary(Match$Won_By)
Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
1.00 6.00 8.00 17.35 21.00 144.00 9
The minimum run by which any team had won is 1 run and maximum run by which any team had won is 144 runs. There are 9 NA values in this column.
Factor level labelling
From the structure of the dataset it has been seen that the season is given as integers while it actually represents different game seasons. Afterwards we converted this factor to factor but the factor levels are 1 to 6. So here we are renaming the factor levels to proper season names. Also we are renaming the variable from Season_ID to Season.
summary(Match$Season_Id) #Summary of the Season_ID
1 2 3 4 5 6 7 8 9
58 57 60 73 74 76 60 59 60
colnames(Match)[3] <- "Season" # Renaming the variable Season_Id
levels(Match$Season) <- c("Season 1", "Season 2", "Season 3",
"Season 4", "Season 5", "Season 6",
"Season 7", "Season 8", "Season 9")
levels(Match$Season) # New levels of season
[1] "Season 1" "Season 2" "Season 3" "Season 4" "Season 5"
[6] "Season 6" "Season 7" "Season 8" "Season 9"
Labelling of the Seasons are successfully done here.
Tidy & Manipulate Data - I
From the summary of the dataset and the head of the dataset we have seen that each variable in our dataset is having its own column except the columns Won_by and Win_Type. No other column headers are values and variable names.
Match[6:10,c(12,5,13,6,7)]
As seen from the dataset above, if Team wins after fielding first they win by wickets. If the team wins after bating first, they win by runs. There is no match were a team win by bith runs and wickets. It is mutually exclusive. So these variabeles has to be seperated, otherwise this variable will effect in transforming and normalising procedure towards the end.
a <- max(Match$Won_By[Match$Win_Type=="by runs"]) # max value of win by runs
b <- min(Match$Won_By[Match$Win_Type=="by runs"]) # max value of win by runs
c <- max(Match$Won_By[Match$Win_Type=="by wickets"]) # max value of win by runs
d <- min(Match$Won_By[Match$Win_Type=="by wickets"]) # max value of win by runs
data.frame("Win_Type"=c("By Runs","By wickets"),
"Minimum" = c(b,d),
"Maximum" = c(a,c))
table(Match$Win_Type) # number of observations under each variable
by runs by wickets No Result Tie
261 307 3 6
The maximum value of win by wickets is 10 and maximum value of win by runs is 144. There is a big difference in the scale if these values. Also there is almost equal representation of win by runs and win by wickets in the dataset. In this case most of the values of win by runs will be classified as outliers while cheking for outliers. Also this will posses problem while standardisation of the variables. So we are going to spread the variable Won by on key = Win_type and value as Won_By. We are filling the null values produced as a result of this spread with 999. This is an impossibe value for the variable and can be used as a reference for further analysis while transforming the variables. We are not keeping it as NA as it will introduce a NA value to all the observations and analysing the other null values will become diffficult. We are also saving a copy of the variable Win_Type for future reference as this variable will be removed from the dataset after the spread operation.
table(Match$Tie, Match$`No Result`) # table of Tie column
999
999 577
The variables formed after the spread oprations are by_runs, by_wickets, Tie and No result. The last two variable are not having only 999 as values since they were factors indicating that there was no result generated in the match. So we will remove this variables from the further analysis.
Match <- Match %>% select(-c("Tie","No Result"))
After spread operation on Won_by and Win_Type there is no multiple variables which are stored in one column. Also multiple columns are not forming a single variable. Each observation in the dataset represent a unique cricket match and thus each observation is having its own row. No multiple variables are stored in any rows. Each row is unique in its representation. Also each value is having its own cell. This proves that our dataset is now conforming to the tidy data principles.
Tidy & Manipulate Data - II
Man of the Match Player’s age is calculated from the Date of birth of the Player. Mutate function is used for this purpose. The base r function as.period() is used to find the current age of the player from today’s date using today() function from Lubridate package.
Creation of calculated variable - Age
Match <- mutate(Match, Age = year(as.period(interval(Match$DOB, today()),
unit = "year")))
summary(Match$Age)
Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
21.00 31.00 34.00 34.84 38.00 49.00 3
The age of the player is successfully mutated in to the dataset. The minimum age of any player who became man of the match is 21 years and the maximum age any player who became man of the match is 49. But there are 3 NA’s in the dataset. We will look in to the missing dataset in the next section.
Scan I
The dataset is scanned for any missing values. The columns with missing values are found by combining colSums() function and is.na() function. The columns names of those columns containing the null values and other interested variables are made in to a list . This list is used to create a dataset containing the rows of the those observation which has null values. This is done by using the function complete.cases for scanning the null value containing rows.
Scanning for NULL values
Match$Win_Type <- Win_Type
colSums(is.na(Match))
Match_Id Match_Date Season
0 0 0
Venue_Name Toss_Decision City_Name
0 0 0
Host_Country Team_1 Team_2
0 0 0
Toss_Winner Match_Winner Man_Of_The_Match
0 3 3
DOB Player_Country by runs
3 3 0
by wickets Age Win_Type
0 3 0
colm3 <- c( "Match_Id", "Match_Winner", "Win_Type", "by runs", "by wickets",
"Man_Of_The_Match","Player_Country", "DOB" )
Match[!complete.cases(Match), colm3] # Rows with NA values
It is found that the columns DOB, Player_Country, Age, Man_Of_The_Match, and Match_Winner contains 3 NULL values each and the variable Won_By is shown as no result for thses three variables. In total there are 15 NULL values in the datset. Using the function complete.cases(), we were able to see the actual issue with the dataset. The DOB, Player_Country, Age, Man_Of_The_Match, and Match_Winner which are having 3 missing values each registered as No result in the Win_Type variable. This means that the match was forfeited either due to bad weather or some other situations. So no result was produced fo that matches. This makes sense for missing values in those datasets. These 3 rows can be excluded as they are very less in number.
Match[Match$Win_Type=="Tie",c(1,18,11)]
It can also be seen that for the matches which was a Tie, there was a Match winner recorded. This can be an error and can be corrected.
Match$Match_Winner <- as.character(Match$Match_Winner)
Match[Match$Win_Type=="Tie", "Match_Winner"] <- "Tie"
Match$Match_Winner <- as.factor(Match$Match_Winner)
So we added a new level to the variable Match_Winner. We converted it to a character first and then added the new level since an already declared factor will not allow addition of new factor levels in this manner. Then we converted that back to a factor using as.factor function.
Handling Null Values
Now we can impute zero values to the variables that have NA values for matches that are Tie while spreading the data. After this step we are be left with only 3 columns that have NA values. These are those matches that was forfeited due to some reasons and there was no outcome of the match. So we remove these columns as it constitute only % of the total dataset. The function na.omit is used to omit this variable from the analysis.
Match[!complete.cases(Match), colm3] # Rows with NA values
Match <- na.omit(Match) # Excluding remaining NA values from the dataset
sum(is.na(Match)) # Total number of NA values remaining in the dataset
[1] 0
After this operations the total sum of the na values in the datset is found to be zero and now we can proceed with the further steps without null values.
Checking inconsistencies
Inconsistencies in the dataframe like presence of -Inf, Inf and NaN are scanned using the following function called is.special. This fuction checks if the current value is finite ot not. A subset of numeric dataset is created from the Match dataset using the is.numeric function. Then the is.special function is applied to the entire numeric dataframe using sapply as follows.
# function for searhing the infinite, and NaN values
is.special <- function(x){
!is.finite(x)
}
# checking for the inconsistencies in the numeric values
numData <- Match[,sapply(Match, is.numeric)] # subset of numeric dataset
colSums(sapply(numData, is.special))
Match_Id by runs by wickets Age
0 0 0 0
It is found that there are no inconsistend or special values in the dataset.
Scan II - Outliers
In this step data is scanned for outliers. In Match dataset there are three numeric variables Age,by run and by wickets. Now data set have three numeric variables by runs, by wickets and age. We have to convert the 999 values in the datset back to null values for better clarity of the ouliers.
Match$`by runs`[Match$`by runs`==999] <- NA
Match$`by wickets`[Match$`by wickets`==999] <- NA
Now let’s check outliers for each of it.

The by run is having many outliers as shown by the BoxPlot. The boxplot is influenced by the low level values in the dataet. In fact these are not actual outliers and this appers to be outliers because of the low run values present in the data. Lets look the zscore values.
length (which(abs(z.scores) > 3))
[1] 4
Checking outliers using z score method. Applying z-score method it is found that there are 4 outliers in by runs method.
Next we check the by wickets variable for outliers, First we plot the BoxPlot.

There seems to be no outlier at all. So we will check the z-scores.
z.scores %>% summary()
Min. 1st Qu. Median Mean 3rd Qu. Max.
-2.9755 -0.7393 -0.1803 0.0000 0.9378 2.0559
Since the maximum z-score is 2.05 which is less than 3, there is no outlier with the Z-score as well. Next we will check for the age parameter.
# Age
Match$Age %>% boxplot(main = "Distribution of Age variable", ylab =
"Age", col = "grey")

There seems to be one variable which is shown as an outlier by the Boxplot method. We found that this came from the maximum age of 49.
unique(Match$Man_Of_The_Match[Match$Age>48])
[1] "ST Jayasuriya" "SK Warne"
We found that “ST Jayasuriya” and “SK Warne” are the players with maximum age and confirmed from Internet Source, CrickBuzz, that Sanath Jayasuriya and Shane Warne are having 49 years of age. So this is not an outlier.
length (which(abs(z.scores_Age) > 3))
[1] 0
Proving that the z-score shows there is no outliers. As the above box plots indicates by run variable is showing outliers. Where as age and by wickets is not showing any outliers in box plot.
Transform
The the numerical varianles in the datasert is checked for further proceeding with statistical analysis. As we have seen in the Outliers of all the numerical variables, there are mutually exclusive sets which are having different scaling in the datset. Also due to introduction of zero in case of null values we have to seperate this values while analysis of First we will analysis the Age variable.
# Age is almost normally distributed
hist(Match$Age,main = "Distribution of Age",xlab="Age")

The histogram is slightly skewed to the right. After numerous trial and error methods BoxCox transformation was making the data better. It is shown below.
# Box-Cox transformation
Age_box<- BoxCox(Match$Age,lambda = "auto")
hist(Age_box,
main = "Distribution of Age variable (BoxCox Transformation)",
xlab = "Age",
col = "grey")

Even though it is slightly skewed to the left the dataset has improved in its symmetry. Now lets look the variable By_runs.

by runs is hghly skewed to the right. Since log transformation is better for improving the disrtibutions with right skewness we apply log transformation to this dataset. We also add a constant 4 to the data for batter results.
By_runs <- By_runs+4
# Natural Log transformation
runs_ln <- log(By_runs)
hist(runs_ln,
main = "Distribution of Won By runs variable (Log Transformation)",
xlab = "Won by Runs",
col = "grey")

It is seen that the dataset has improved a lot in this case. Log transformation has removed the high skewness in the data. Now lets check for the wicktes data.
hist(By_wickets, main = "Distribution of Won By wickets",
xlab = "Won By Wickets")

Here the data is almost symmetrically distribted and doesnt need any more transformation.
Conclusion
The data set was in untidy format which was converted in to a tidy format according to tidy data principles. Many NA values in the data set was also handled properly by imputing and excluding some observations. Many data type conversion were necessary. Outliers in the datset were proved to be not an outlier and they were identified not influencing the distribution of the dataet as a whole. The data was transformed using log and bocox transformation methods to make the numreical variables normal. Now the dataset is ready for further data analysis techniques like regression, classification and clustering..
LS0tCnRpdGxlOiAiTUFUSDIzNDkgU2VtZXN0ZXIgMiwgMjAxOCIKYXV0aG9yOiAiQW1hbCBKb3kgKFMzNjQ0Nzk0KSAmIE51cHVyYSBTYW5qYXkgU2F3bGUgKFMzNjM5NzAzKSIKZGF0ZTogIjE0IE9jdG9iZXIgMjAxOCIKc3VidGl0bGU6IEFzc2lnbm1lbnQgMwpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAotLS0KClxuZXdwYWdlCgpcdGFibGVvZmNvbnRlbnRzCgpcbmV3cGFnZQoKIyMgUmVxdWlyZWQgcGFja2FnZXMgCgpUaGUgcGFja2FnZXMgdGhhdCBhcmUgcmVxdWlyZWQgZm9yIHRoaXMgcHJvamVjdCBhcmUgbG9hZGVkIGhlcmUuICAKYGBge3IgTGlicmFyeSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KbGlicmFyeShyZWFkcikKbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoa25pdHIpCmxpYnJhcnkob3V0bGllcnMpCmxpYnJhcnkoZm9yZWNhc3QpCmBgYAoKCiMjIEV4ZWN1dGl2ZSBTdW1tYXJ5IApUaGlzIHByb2plY3QgaXMgcGVyZm9ybWVkIHRvIGlsbHVzdHJhdGUgdGhlIGRhdGEgcHJlcHJvY2Vzc2luZyB0YXNrcyBjYXJyaWVkIG91dCBmb3IgcHJlcGFyaW5nIGEgZGF0YSByZWFkeSBmb3Igc3RhdGlzdGljYWwgdGVzdHMgYW5kIHByZWRpY3Rpb25zLiBUaGUgZGF0YSBzZXQgaW5jbHVkZWQgaW4gdGhlIHByb2plY3QgaXMgYSBjcmlja2V0IChJUEwpIGRhdGFzZXQgb2J0YWluZWQgZnJvbSBhIG9wZW4gc291cmNlIGRhdGEgd2Vic2l0ZSBjYWxsZWQgS2FnZ2xlLiBUaGUgcHVycG9zZSBvZiB0aGlzIGFuYWx5c2lzIGlzIHRvIG1ha2UgdGhlIGRhdGEgcmVhZHkgZm9yIGFuIGFuYWx5c2lzIHRoYXQgaW5jbHVkZXMgTWF0Y2ggZGV0YWlscyBhbmQgdGhlIG1hbiBvZiB0aGUgbWF0Y2ggcGxheWVyIGRldGFpbHMuIFRoZSBkYXRhc2V0IGlzIG9idGFpbmVkIGZyb20gZGlmZmVyZW50IHNvdXJjZXMgd2hpY2ggaXMgdGhlbiBtZXJnZWQgdXNpbmcgZGF0YSBqb2luaW5nIHRlY2huaXF1ZXMgaW4gdGhlIGRwbHlyIHBhY2thZ2UgaW4gUiBwcm9ncmFtLiBGaXJzdCBzdW1tYXJ5IGFuZCBzdHJ1Y3R1cmUgb2YgdGhlIGRhdGFzZXQgaXMgc3R1ZGllcyB1c2luZyByZWxldmFudCB0b29scyBhdnZhaWxhYmxlIGluIFIuIFRoZW4gdGhlcmUgaXMgRGF0YSB0eXBlIGNvdmVyc2lvbiB3aGljaCBpbmNsdWRlcyBjaGFyYWN0ZXIgdG8gZGF0ZSwgY2hhcmFjdGVyIHRvIGZhY3RvciBhbmQgY2hhcmFjdGVyIHRvIGludGVnZXIuIFRoZXJlIHdhcyBhIGZhY3RvciB3aGljaCByZXF1aXJlZCBsYWJlbGxpbmcgb2YgdGhlIGZhY3RvciBsZXZlbHMuIERhdGEgaWR5aW5nIGluY2x1ZGVzIGlkZW50aWZ5aW5nIHRoZSB2YXJpYWJsZXMgdGhhdCBkb2Vzbm90IGNvbmZvcm0gdG8gdGhlIHRpZHkgZGF0YSBwcmluY2xlIGFuZCB1c2luZyB0aGUgc3ByZWFkIGZ1bmN0aW9uIHRvIG1ha2UgaXQgdGlkeS4gQSBuZXcgdmFyaWFibGUgY2FsbGVkIFBsYXllciBhZ2Ugd2FzIGNyZWF0ZWQgZnJvbSB0aGUgZGF0ZSBvZiBiaXJ0aCBvZiB0aGUgcGxheWVyLiBUaGUgZGF0YSB3YXMgdGhlbiBzY2FubmVkIGZvciBhbnkgbnVsbCB2YWx1ZXMgYW5kIGluY29uc2lzdGVuY2llcy4gQWx0aG91Z2ggdGhlcmUgd2VyZSBubyBpbmNvbnNpc3RlbmNpZXMgaW4gdGhlIGRhdGFzZXQgdGhlcmUgd2VyZSBmZXcgbnVsbCB2YWx1ZXMgd2hpY2ggaGFzIGJlZW4gdHJlYXRlZCBpbiBhIHByb3BlciB3YXkgYW5kIGZpbm5hbHkgbWFkZSB0aGUgZGF0YSBzZXQgd2l0aG91dCBhbnkgbnVsbCB2YWx1ZXMuIFRoZW4gdGhlIGRhdGEgd2FzIHNjYW5uZWQgZm9yIG91dGxpZXJzIHVzaW5nIHR3byBkaWZmZXJlbnQgdGVjaG5pcXVlcywgQm94UGxvdCBhbmQgWi1zY29yZSBtZXRob2RzLiBUaGVyZSB3ZXJlIGZldyBvdXRsaWVyIGZvdW5kIGluIHRoZSBkYXRhc2V0IHdoaWNoIHdhcyB0aGVuIGlkZW50aWZpZWQgYXMgbm90IG91dGxpZXJzLiBEYXRhIHRyYW5zZm9ybWF0aW9uIHRlY2huaXF1ZXMgbGlrZSBsb2cgdHJhbnNmb3JtYXRpb24gYW5kIEJveENveCB0cmFuc2Zvcm1hdGlvbiB3YXMgYXBwbGllZCBvbiB0aGUgbnVtZXJpYyB2YXJpYWJsZXMgdG8gY2hhbmdlIHRoZSBzY2FsZSBvZiB2YXJpYWJsZXMgYW5kIHRvIG1ha2UgdGhlIGRpc3RyaWJ1dGlvbiBzeW1tZXRyaWMuIEZpbm5hbHkgdGhlIGRhdGEgd2FzIG5vcm1hbGx5IGRpc3RyaW51dGVkIGFuZCBoYWQgbm8gb3V0bGllcnMgb3IgTkEgdmFsdWVzIGFuZCB0aHVzIHdhcyByZWFkeSBmb3IgdGhlIGZ1cnRoZXIgYW5hbHlzaXMuCgojIyBEYXRhIApUaGUgb3JpZ2luYWwgc291cmNlIG9mIHRoZSBkYXRhIHNldCBpcyBbQ3JpY3NoZWV0Lm9yZ10oaHR0cHM6Ly9jcmljc2hlZXQub3JnL2Rvd25sb2Fkcy9pcGwuemlwKS4gVGhlIGRhdGEgaXMgYXZhaWxhYmxlIGluIFlBTUwgZm9ybWF0IHdpdGggZGlmZmVyZW50IG1hdGNoZXMgcmVjb3JkZWQgaW4gZGlmZmVyZW50IGZpbGVzLiBUaGlzIGRhdGEgd2FzIGNvbWJpbmVkIGJ5IEthZ2dsZSB1c2VycyBhbmQgd2VyZSBwcm92aWRlZCBpbiB0aGUgS2FnZ2xlIHdlYnNpdGUgZm9yIGRvd25sb2Fkcy4gVGhlIGRhdGEgd2FzIHByb3ZpZGVkIGluIDMgZGlmZmVyZW50IGZpbGVzLCBpbmNsdWRpbmcgZGF0YSBmb3IgdGVhbSwgZGF0YSBmb3IgdGhlIHBsYXllciBpbmZvcm1hdGlvbiBhbmQgbWF0Y2ggZGF0YS4gQ2xpY2sgdG8gZG93bmxvYWQgdGhlIFtUZWFtIGRhdGFdKGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vaGFyc2hhNTQ3L2luZGlhbi1wcmVtaWVyLWxlYWd1ZS1jc3YtZGF0YXNldC9kb3dubG9hZHMvVGVhbS5jc3YvMiksIFtQbGF5ZXIgRGF0YV0oaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9oYXJzaGE1NDcvaW5kaWFuLXByZW1pZXItbGVhZ3VlLWNzdi1kYXRhc2V0L2Rvd25sb2Fkcy9QbGF5ZXIuY3N2LzIpIGFuZCBbTWF0Y2ggRGF0YV0oaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9oYXJzaGE1NDcvaW5kaWFuLXByZW1pZXItbGVhZ3VlLWNzdi1kYXRhc2V0L2Rvd25sb2Fkcy9NYXRjaC5jc3YvMikgZnJvbSBLYWdnbGUuIApUaGUgVGVhbSBkYXRhIGNvbnRhaW5zIHRlYW0gaW5mb3JtYXRpb25zIGdpdmVuIGJlbG93OiAgCjEuICoqVGVhbV9JZCoqIC0gKlByaW1hcnkga2V5IGZvciB0aGUgdGVhbSB0YWJsZSogICAKMi4gKipUZWFtX05hbWUqKiAtICpOYW1lIG9mIHRoZSBUZWFtKiAgIAozLiAqKlRlYW1fU2hvcnRfQ29kZSoqIC0gKlNob3J0IGNvZGUgZm9yIGVhY2ggdGVhbSogIAoKVGhlIFBsYXllciBkYXRhc2V0IGNvbnRhaW5zIGluZm9ybWF0aW9uIGdpdmVuIGJlbG93OiAgCjEuICoqUGxheWVyX0lkKiogLSAqUHJpbWFyeSBrZXkgZm9yIHRoZSBwbGF5ZXIgdGFibGUqICAgICAgCjIuICoqUGxheWVyX05hbWUqKiAtICpOYW1lIG9mIHRoZSBwbGF5ZXIqICAgICAgCjMuICoqRE9CKiogLSAqRGF0ZSBvZiBCaXJ0aCBvZiB0aGUgcGxheWVyKiAgICAKNC4gKipCYXR0aW5nX0hhbmQqKiAtICpCYXR0aW5nIEhhbmQgb2YgdGhlIFBsYXllciogIAo1LiAqKkJvd2xpbmdfU2tpbGwqKiAtICpUeXBlIG9mIGJvd2xpbmcgcHJhY3Rpc2VkIGJ5IHRoZSBib3dsZXIqICAgICAgCjUuICoqQ291bnRyeSoqIC0gKkNvdW50cnkgb2YgdGhlIFBsYXllciogICAgCjYuICoqSXNfVW1waXJlKiogLSAqUGVyc29uIGlzIFVtcGlyZSBvciBub3QqICAgCiAgClRoZSBNYXRjaCBkYXRhc2V0IGNvbnRhaW5zIHRoZSBpbmZvcm1hdGlvbiBnaXZlbiBiZWxvdzogICAgICAgCjEuICoqTWF0Y2hfSWQqKiAtICpQcmltYXJ5IGtleSBmb3IgTWF0Y2ggdGFibGUqICAgCjIuICoqTWF0Y2hfRGF0ZSoqIC0gKkRhdGUgb2YgbWF0Y2gqICAgIAozLiAqKlNlYXNvbioqIC0gKlNlYXNvbiBvZiB0aGUgbWF0Y2gqICAgCjQuICoqVmVudWVfTmFtZSoqIC0gKlZlbnVlIG9mIHRoZSBtYXRjaCogICAgCjUuICoqVG9zc19EZWNpc2lvbioqIC0gKk91dGNvbWUgb2YgdGhlIFRvc3MqICAgIAo2LiAqKldpbl9UeXBlKiogLSAqV2lubmluZyBUeXBlIG9mIHRoZSBNYXRjaCogICAKNy4gKipXb25fQnkqKiAtICpOdW1iZXIgb2YgcnVucyBvciB3aWNrZXRzIHRlYW0gd29uIHRoZSBtYXRjaCogICAgCjguICoqQ2l0eV9OYW1lKiogLSAqTmFtZSBvZiB0aGUgY2l0eSB3aGVyZSBpcyBtYXRjaCBpcyBoYXBwZW5pbmcqICAgCjkuICoqSG9zdF9Db3VudHJ5KiogLSAqTmFtZSBvZiB0aGUgQ291bnRyeSBIb3N0aW5nIHRoZSBtYXRjaCogICAKMTAuICoqVGVhbV8xKiogLSAqTmFtZSBvZiBvbmUgVGVhbSAqICAgCjExLiAqKlRlYW1fMioqIC0gKk5hbWUgb2YgdGVhbSB0d28qICAgCjEyLiAqKlRvc3NfV2lubmVyKiogLSAqTmFtZSBvZiB0aGUgdGVhbSB3aW5uaW5nIHRoZSBUb3NzKiAgIAoxMy4gKipNYXRjaF9XaW5uZXIqKiAtICpOYW1lIG9mIHRoZSB3aW5uaW5nIFRlYW0qICAgCjE0LiAqKk1hbl9PZl9UaGVfTWF0YyoqIC0gKk5hbWUgb2YgdGhlIE1hbiBvZiB0aGUgTWF0Y2ggcGxheWVyKiAgIAoxNS4gKipET0IqKiAtICpEYXRlIG9mIEJpcnRoIG9mIHRoZSBtYW4gb2YgdGhlIG1hdGNoIHBsYXllciogICAgCjE2LiAqKlBsYXllcl9Db3VudHJ5KiogLSAqTWFuIG9mIFRoZSBNYXRjaCBwbGF5ZXIgY291bnRyeSBuYW1lKiAgIAoxNy4gKipBZ2UqKiAtICpBZ2Ugb2YgdGhlIE1hbiBvZiB0aGUgTWF0Y2ggcGxheWVyKgoKVGhlIE1hdGNoIGRhdGFzZXQgaXMgdGhlIG1haW4gZGF0c2V0IHdoZXJlIHdlIGFyZSBtZXJnaW5nIG90aGVyIHR3byB0YWJsZXMgaW50by4gVGhpcyBkYXRhc2V0IGNvbnRhaW5zIFRlYW0gSUQgaW5mb3JtYXRpb24gZm9yIGJvdGggdGhlIHRlYW1zIGluIHRoZSBtYXRjaCwgd2lubmluZyB0ZWFtIElELCBNYW4gb2YgdGhlIE1hdGNoIHBsYXllciBJRCBldGMgd2hpY2ggYXJlIHVzZWQgYXMgdGhlIGtleSBmb3IgbWVyZ2luZy4gVGhlIEVSIERpYWdyYW0gb2YgdGhlIGRhdGFzZXRzIGFyZSBnaXZlbiBiZWxvdy4gIVtFUiBEaWFncmFtXShpbWcucG5nKQoKCiMjIyBJbXBvcnRpbmcgZGF0YXNldHMKYGBge3IgRGF0YXNldHMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9ClRlYW0gPC0gcmVhZF9jc3YoIkNyaWNrZXQvVGVhbS5jc3YiKSAlPiUgYXMuZGF0YS5mcmFtZSgpCgpQbGF5ZXIgPC0gcmVhZF9jc3YoIkNyaWNrZXQvUGxheWVyLmNzdiIsIAogICAgICAgICAgICAgICAgICAgY29sX3R5cGVzID0gY29scyhYOCA9IGNvbF9za2lwKCkpKSAlPiUgYXMuZGF0YS5mcmFtZSgpCgpNYXRjaCA8LSByZWFkX2NzdigiQ3JpY2tldC9NYXRjaC5jc3YiKSAlPiUgYXMuZGF0YS5mcmFtZSgpCgpgYGAKVGhlIGRhdGFzZXRzIGFyZSBpbXBvcnRlZCB1c2luZyB0aGUgcmVhZF9jc3YgZnVuY3Rpb24gYXMgZGF0YSBmcmFtZXMuIFRoZSByZWFkIGZpbGVzIGFyZSBzYXZlcyBpbiB0byBmaWxlcyBuYW1lZCBgVGVhbWAsIGBQbGF5ZXJgLCBhbmQgYE1hdGNoYC4gVGhlIHBsYXllciBkYXRhc2V0IGNvbnRhaW5lZCBhbiBlaWdodGggY29sdW1uIHdoaWNoIHdhcyBhIG51bGwgY29sdW1uLiBXZSByZW1vdmVkIHRoYXQgY29sdW1uIHVzaW5nIGNvbF9za2lwIGZ1bmN0aW9uLiBUaGUgaGVhZCBvZiB0aGUgZGF0c2V0cyBhcmUgZ2l2ZW4gYmVsb3cuIAoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KY29sbSA8LSBjKCJJU19TdXBlcm92ZXIiLCAiSVNfUmVzdWx0IiwgCiAgICAgICAgICAiSXNfRHVja1dvcnRoTGV3aXMiLCAiRmlyc3RfVW1waXJlX0lkIiwgCiAgICAgICAgICAiU2Vjb25kX1VtcGlyZV9JZCIpCk1hdGNoIDwtIE1hdGNoWywhKGNvbG5hbWVzKE1hdGNoKSAKICAgICAgICAgICAgICAgICAgICAgICAgICVpbiUgY29sbSldICU+JSBhcy5kYXRhLmZyYW1lKCkjIERyb3BpbmcgdW53YW50ZWQgY29sdW1ucwpgYGAKYGBge3J9CmhlYWQoVGVhbSkgIyBIZWFkIG9mIFRlYW0gZGF0YXNldApoZWFkKFBsYXllcikgIyBIZWFkIG9mIFBsYXllciBkYXRhc2V0CmhlYWQoTWF0Y2gpICMgSGVhZCBvZiBNYXRjaCBkYXRhc2V0CmBgYAoKCiMjIyBEYXRhc2V0IE1lcmdpbmcKVGhlIE1hdGNoIGRhdGEgc2V0IGlzIHRha2luZyBkYXRhIGZyb20gb3RoZXIgdHdvIGRhdGEgc2V0cyBmb3IgZmlsbGluZyBpbiB0aGUgaW5mb3JtYXRpb25zIGxpa2UgdGVhbSBuYW1lcywgcGxheWVyIG5hbWVzIGV0Yy4gTGVmdF9qb2luIGlzIHVzZWQgdG8gbWVyZ2UgdGhlIGRhdGFzZXRzLiBBbGwgdGhlIHZhcmlhYmxlcyBpbiBNYXRjaCBkYXRhc2V0IGlzIGtlcHQgYW5kIG9ubHkgZmV3IG5lY2Vzc2FyeSB2YXJpYWJsZXMgZnJvbSBvdGhlciBkYXRzZXRzIGFyZSBtZXJnZWQgaW4gdG8gTWF0Y2ggZGF0YXNldC4gVGhlIGJlbG93IGNvZGUgc2hvd3MgTWF0Y2ggZGF0YXNldCBhbmQgdGhlIFRlYW0gZGF0YXNldCB3aGVyZSBgVGVhbV9JZGAgaXMgdXNlZCBhcyB0aGUgY29tbW9uIGtleS4gVGhpcyBpcyB1c2VkIGFzIHRoZSBgVGVhbTFgIGRldGFpbHMgd2l0aCB0aGUgdGVhbSBuYW1lcy4gVGhlIGNvbHVtbiBgVGVhbV9OYW1lX0lkYCBpcyB0aGVuIHJlbW92ZWQgZnJvbSB0aGUgTWF0Y2ggZGF0YXNldC4KYGBge3IgRGF0YV9tZXJnaW5nfQojIFRha2luZyB0ZWFtIG5hbWUgZm9yIFRlYW0xIGZyb20gVGVhbSB0YWJsZQpNYXRjaCA8LSBNYXRjaCAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChUZWFtLCBUZWFtX0lkLCBUZWFtX05hbWUpLCAKICAgICAgICAgICAgYygiVGVhbV9OYW1lX0lkIiA9ICJUZWFtX0lkIikpICU+JSAKICByZW5hbWUoVGVhbV8xID0gIlRlYW1fTmFtZSIpICU+JSAKICBzZWxlY3QoLVRlYW1fTmFtZV9JZCkgCmBgYApUaGUgY29kZSBiZWxvdyBzaG9lcyB0aGUgbWVyZ2luZyBvZiBNYXRjaCBkYXRhc2V0IHdpdGggdGhlIFRlYW0gZGF0YXNldCBmb3Igc3Vic3RpdHV0aW5nIHRoZSBvcHBvbmVudCB0ZWFtIElEcyB3aXRoIHRoZSB0ZWFtIG5hbWVzLiBUaGlzIGNvbHVtbiBpcyB0aGVuIGdpdmVuIHRoZSBuYW1lIGFzIGBUZWFtXzJgLiAKYGBge3IgRGF0YV9tZXJnaW5nMn0KIyBUYWtpbmcgdGVhbSBuYW1lIGZvciBUZWFtMiBmcm9tIFRlYW0gdGFibGUKTWF0Y2ggPC0gTWF0Y2ggJT4lIAogIGxlZnRfam9pbihzZWxlY3QoVGVhbSwgVGVhbV9JZCwgVGVhbV9OYW1lKSwgCiAgICAgICAgICAgIGMoIk9wcG9uZW50X1RlYW1fSWQiID0gIlRlYW1fSWQiKSkgJT4lIAogIHJlbmFtZShUZWFtXzIgPSAiVGVhbV9OYW1lIikgJT4lIAogIHNlbGVjdCgtT3Bwb25lbnRfVGVhbV9JZCkgCmBgYApUaGUgYFRvc3NfV2lubmVyX0lkYCBpcyByZXBsYWNlZCB3aXRoIHRoZSBjb3Jyb3Nwb25kaW5nIHRlYW0gbmFtZXMgYnkgam9pbmluZyBNYXRjaCBkYXRhc2V0IHdpdGggVGVhbSBkYXRhc2V0IG9uIGBUZWFtX0lkYCBhbmQgYFRvc3NfV2lubmVyX0lkYC4gVG9zc19XaW5uZXJfSWQgaXMgdGhlbiByZW1vdmVkIGZyb20gdGhlIGRhdHNldC4KYGBge3IgRGF0YV9tZXJnaW5nM30KIyBUYWtpbmcgdGVhbSBuYW1lIGZvciBUb3NzIFdpbm5lciBmcm9tIFRlYW0gdGFibGUKTWF0Y2ggPC0gTWF0Y2ggJT4lIAogIGxlZnRfam9pbihzZWxlY3QoVGVhbSwgVGVhbV9JZCwgVGVhbV9OYW1lKSwgCiAgICAgICAgICAgIGMoIlRvc3NfV2lubmVyX0lkIiA9ICJUZWFtX0lkIikpICU+JSAKICByZW5hbWUoVG9zc19XaW5uZXIgPSAiVGVhbV9OYW1lIikgJT4lIAogIHNlbGVjdCgtVG9zc19XaW5uZXJfSWQpIApgYGAKVGhlIHZhcmlhYmxlIGBNYXRjaF9XaW5uZXJfSWRgIGlzIHJlcGxhY2VkIHdpdGggdGhlIGNvcnJvc3BvbmRpbmcgdGVhbSBuYW1lcyBieSBqb2luaW5nIE1hdGNoIGRhdGFzZXQgd2l0aCBUZWFtIGRhdGFzZXQgb24gYFRlYW1fSWRgIGFuZCBgTWF0Y2hfV2lubmVyX0lkYC4gTWF0Y2hfV2lubmVyX0lkIGlzIHRoZW4gcmVtb3ZlZCBmcm9tIHRoZSBkYXRzZXQuCmBgYHtyIERhdGFfbWVyZ2luZzR9CiMgVGFraW5nIHRlYW0gbmFtZSBmb3IgTWF0Y2ggd2lubmVyIGZyb20gVGVhbSB0YWJsZQpNYXRjaCA8LSBNYXRjaCAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChUZWFtLCBUZWFtX0lkLCBUZWFtX05hbWUpLCAKICAgICAgICAgICAgYygiTWF0Y2hfV2lubmVyX0lkIiA9ICJUZWFtX0lkIikpICU+JSAKICByZW5hbWUoTWF0Y2hfV2lubmVyID0gIlRlYW1fTmFtZSIpICU+JSAKICBzZWxlY3QoLU1hdGNoX1dpbm5lcl9JZCkgCmBgYApBZGRpdGlvbmFsIERhdGEgaXMgYWRkZWQgdG8gdGhlIE1hdGNoIGRhdGFzZXQgZnJvbSB0aGUgUGxheWVyIGRhdGFzZXQgYnkgdXNpbmcgbGVmdF9qb2luLiBUaGUgZGF0YXNldHMgYXJlIGpvaW5lZCB1c2luZyB0aGUgY29sdW1uICBgTWFuX09mX1RoZV9NYXRjaF9JZGAgZnJvbSB0aGUgTWF0Y2ggZGF0c2V0IGFuZCBgUGxheWVyX0lkYCBmcm9tIHRoZSBwbGF5ZXIgZGF0YXNldC4gYE1hbl9PZl9UaGVfTWF0Y2hfSWRgIGlzIHJlcGxhY2VkIHdpdGggdGhlIGNvcnJvc3Bvc25kaW5nIHBsYXllciBuYW1lcy4gQWRkaXRpb25hbCB2YXJpYWJsZXMgbGlrZSBwbGF5ZXIgZGF0ZSBvZiBiaXJ0aCBhbmQgcGxheWVyIGNvdW50cnkgYXJlIGFkZGVkIHRvIHRoZSBkYXRhc2V0LgpgYGB7ciBEYXRhX21lcmdpbmc1fQojIFRha2luZyBwbGF5ZXIgbmFtZSBmcm9tIHBsYXllciB0YWJsZQpNYXRjaCA8LSBNYXRjaCAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChQbGF5ZXIsIFBsYXllcl9JZCwgUGxheWVyX05hbWUsIERPQiwgQ291bnRyeSksIAogICAgICAgICAgICBjKCJNYW5fT2ZfVGhlX01hdGNoX0lkIj0iUGxheWVyX0lkIikpICU+JSAKICByZW5hbWUoUGxheWVyX0NvdW50cnkgPSAiQ291bnRyeSIsIE1hbl9PZl9UaGVfTWF0Y2g9IlBsYXllcl9OYW1lIikgJT4lIAogIHNlbGVjdCgtTWFuX09mX1RoZV9NYXRjaF9JZCkgCmBgYAogVGhlIGhlYWQgb2YgdGhlIGRhdGFzZXQgYWZ0ZXIgYWxsIHRoZSBtZXJnaW5nIGlzIGdpdmVuIGJlbG93LgpgYGB7cn0KaGVhZChNYXRjaCkKYGBgCgojIyBVbmRlcnN0YW5kIHRoZSBkYXRhCgpUaGUgc3RydWN0dXJlIG9mIHRoZSBNYXRjaCBkYXRhc2V0IGlzIGdpdmVuIGJlbG93LiAKYGBge3IgdHlwZV9jb252ZXJzaW9ucywgd2FybmluZz1GQUxTRX0Kc3RyKE1hdGNoLCAgdmVjLmxlbj0yKSAjIFN0cnVjdHVyZSBvZiBNYXRjaCBkYXRhCmBgYApUaGVyZSBhcmUgNTc3IG9ic2VydmF0aW9ucyB3aXRoIDE3IHZhcmlhYmxlcy4gRXhjZXB0IGBNYXRjaF9JRGAgYW5kIGBTZWFzb25fSURgLCBhbGwgb3RoZXIgdmFyaWFibGVzIGFyZSBjaGFyYWN0ZXIgdmFyaWFibGVzLiBgTWF0Y2hfRGF0ZWAgYW5kIGBET0JgIGFyZSBkYXRlIHZhcmlhYmxlcyBhbmQgYXJlIHJlcHJlc2VudGVkIGFzIGNoYXJhY3RlciBoZXJlLiBTaW1pbGFybHksIHRoZSB2YXJpYWJsZSBgV29uX2J5YCBpcyBzaG93aW5nIHRoZSBydW4gYnkgd2hpY2ggdGhlIHRlYW0gaGFzIHdvbi4gSXQgaXMgYW4gaW50ZWdlciB2YXJpYWJsZSBhbmQgaXMgcmVwcmVzZW50IGFzIGNoYXJhY3Rlci4gQWxzbyB0aGVyZSBhcmUgc29tZSB2YXJpYWJsZSB3aGljaCBzaG91bGQgaGF2IGJlZW4gZmFjdG9yIGJ5IGRlZmF1bHQuIAoKIyMjIERhdGEgVHlwZSBDb252ZXJzaW9ucwpOb3cgd2Ugd2lsbCBjb252ZXJ0IGFsbCB0aGVzZSB2YXJpYWJsZXMgaW50byB0aGVpciByZXNwZWN0aXZlIGZvcm1hdHMuIAoKIyMjIyBEYXRlIENvbnZlcnNpb25zClRoZSB2YXJpYWJsZXMgdG8gYmUgY29udmVydGVkIGFzIGRhdGUgdHlwZSBhcmUgYE1hdGNoX0RhdGVgIGFuZCBgRE9CYC4gVGhlIGRhdGUgZm9ybWF0IGdpdmVuIGhlcmUgaXMgYERELU1NLVlZYC4gU28gd2Ugd2lsbCB1c2UgdGhlIEx1YnJpZGF0ZSBmdW5jdGlvbiBgZG15KClgIHRvIGNvdmVydCBpbiB0byBkYXRlIHR5cGUuCmBgYHtyIHR5cGVfY29udmVyc2lvbnMwLCB3YXJuaW5nPUZBTFNFfQpjb2xtMSA8LSBjKCJNYXRjaF9EYXRlIiwgIkRPQiIpICNDb2x1bW5zIHRvIGJlIGNvbnZlcnRlZApNYXRjaFtjb2xtMV0gPC0gbGFwcGx5KE1hdGNoW2NvbG0xXSwgZG15KSAjIExpc3QgYXBwbHkgdGhlIGRteSgpIGZ1bmN0aW9uCnN0cihNYXRjaFtjb2xtMV0pICMgU3RydWN0dXJlIGFmdGVyIGFjb252ZXJzaW9uCmBgYApUaGUgY29sdW1ucyBoYXMgYmVlbiBzdWNjZXNzZnVsbHkgY29udmVydGVkIHRvIGRhdGUgZm9ybWF0LiAKCiMjIyMgQ2hhcmFjdGVyIHRvIGZhY3RvciBjb252ZXJzaW9uClRoZSB2YXJpYWJsZXMgdG8gYmUgY29udmVydGVkIGFzIGZhY3RvciB0eXBlIGFyZSBgU2Vhc29uX0lkYCwgYFRvc3NfRGVjaXNpb25gLCBgV2luX1R5cGVgLCBgQ2l0eV9OYW1lYCwgYEhvc3RfQ291bnRyeWAsIGBUZWFtXzFgLCBgVGVhbV8yYCwgYFRvc3NfV2lubmVyYCwgYE1hdGNoX1dpbm5lcmAsIGFuZCBgUGxheWVyX0NvdW50cnlgLiBUaGVzZSB2YXJpYWJsZSBuYW1lcyBhcmUgZmlyc3Qgc2F2ZWQgYXMgYSBsaXN0IGFuZCB0aGVuIGZlZCB0aGlzIGluIHRvIGEgbGlzdCBhcHBseSBmdW5jdGlvbiB3aXRoIGZhY3RvciBmdW5jdGlvbiBpbiBpdC4gCmBgYHtyIHR5cGVfY29udmVyc2lvbnMxLCB3YXJuaW5nPUZBTFNFfQpjb2xtMiA8LSBjKCJTZWFzb25fSWQiLCAiVG9zc19EZWNpc2lvbiIsICJXaW5fVHlwZSIsICJDaXR5X05hbWUiLCAiSG9zdF9Db3VudHJ5IiwgCiAgICAgICAgICAgIlRlYW1fMSIsICJUZWFtXzIiLCAiVG9zc19XaW5uZXIiLCAiTWF0Y2hfV2lubmVyIiwgIlBsYXllcl9Db3VudHJ5IikKTWF0Y2hbY29sbTJdIDwtIGxhcHBseShNYXRjaFtjb2xtMl0sIGZhY3RvcikgIyBGYWN0b3IgY29udmVyc2lvbgpzdW1tYXJ5KE1hdGNoW2NvbG0yXSkgIyBzdW1tYXJ5IG9mIHRoZSBmYWN0b3IgdmFyaWFibGVzCmBgYAojIyMjIENoYXJhdGVyIHRvIEludGVnZXIgY29udmVyc2lvbgpUaGUgdmFyaWFibGUgYFdvbl9CeWAgc2hvdWxkIGJlIGFuIGludGVyZ2VyIHZhcmlhYmxlcyBhcyBpdCByZXByZXNlbnRzIHJ1bnMuIFNvIHdlIGFyZSBjb252ZXJ0aW5nIHRoZW0gdG8gaW50ZWdlciBieSB1c2luZyB0aGUgdGhlIGZvbGxvd2luZyBmdW5jdGlvbi4KYGBge3IgdHlwZV9jb252ZXJzaW9uczIsIHdhcm5pbmc9RkFMU0V9Ck1hdGNoJFdvbl9CeSA8LSBhcy5pbnRlZ2VyKE1hdGNoJFdvbl9CeSkKc3VtbWFyeShNYXRjaCRXb25fQnkpCmBgYApUaGUgbWluaW11bSBydW4gYnkgd2hpY2ggYW55IHRlYW0gaGFkIHdvbiBpcyAxIHJ1biBhbmQgbWF4aW11bSBydW4gYnkgd2hpY2ggYW55IHRlYW0gaGFkIHdvbiBpcyAxNDQgcnVucy4gVGhlcmUgYXJlIDkgTkEgdmFsdWVzIGluIHRoaXMgY29sdW1uLiAKCiMjIyBGYWN0b3IgbGV2ZWwgbGFiZWxsaW5nCkZyb20gdGhlIHN0cnVjdHVyZSBvZiB0aGUgZGF0YXNldCBpdCBoYXMgYmVlbiBzZWVuIHRoYXQgdGhlIHNlYXNvbiBpcyBnaXZlbiBhcyBpbnRlZ2VycyB3aGlsZSBpdCBhY3R1YWxseSByZXByZXNlbnRzIGRpZmZlcmVudCBnYW1lIHNlYXNvbnMuIEFmdGVyd2FyZHMgd2UgY29udmVydGVkIHRoaXMgZmFjdG9yIHRvIGZhY3RvciBidXQgdGhlIGZhY3RvciBsZXZlbHMgYXJlIDEgdG8gNi4gU28gaGVyZSB3ZSBhcmUgcmVuYW1pbmcgdGhlIGZhY3RvciBsZXZlbHMgdG8gcHJvcGVyIHNlYXNvbiBuYW1lcy4gQWxzbyB3ZSBhcmUgcmVuYW1pbmcgdGhlIHZhcmlhYmxlIGZyb20gU2Vhc29uX0lEIHRvIGBTZWFzb25gLiAKYGBge3J9CnN1bW1hcnkoTWF0Y2gkU2Vhc29uX0lkKSAjU3VtbWFyeSBvZiB0aGUgU2Vhc29uX0lECmNvbG5hbWVzKE1hdGNoKVszXSA8LSAiU2Vhc29uIiAjIFJlbmFtaW5nIHRoZSB2YXJpYWJsZSBTZWFzb25fSWQKbGV2ZWxzKE1hdGNoJFNlYXNvbikgPC0gYygiU2Vhc29uIDEiLCAiU2Vhc29uIDIiLCAiU2Vhc29uIDMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAiU2Vhc29uIDQiLCAiU2Vhc29uIDUiLCAiU2Vhc29uIDYiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAiU2Vhc29uIDciLCAiU2Vhc29uIDgiLCAiU2Vhc29uIDkiKSAKbGV2ZWxzKE1hdGNoJFNlYXNvbikgIyBOZXcgbGV2ZWxzIG9mIHNlYXNvbgpgYGAKTGFiZWxsaW5nIG9mIHRoZSBTZWFzb25zIGFyZSBzdWNjZXNzZnVsbHkgZG9uZSBoZXJlLiAKCiMJVGlkeSAmIE1hbmlwdWxhdGUgRGF0YSAtIEkgCkZyb20gdGhlIHN1bW1hcnkgb2YgdGhlIGRhdGFzZXQgYW5kIHRoZSBoZWFkIG9mIHRoZSBkYXRhc2V0IHdlIGhhdmUgc2VlbiB0aGF0IGVhY2ggdmFyaWFibGUgaW4gb3VyIGRhdGFzZXQgaXMgaGF2aW5nIGl0cyBvd24gY29sdW1uIGV4Y2VwdCB0aGUgY29sdW1ucyBgV29uX2J5YCBhbmQgYFdpbl9UeXBlYC4gTm8gb3RoZXIgY29sdW1uIGhlYWRlcnMgYXJlIHZhbHVlcyBhbmQgdmFyaWFibGUgbmFtZXMuIAoKYGBge3J9Ck1hdGNoWzY6MTAsYygxMiw1LDEzLDYsNyldCmBgYApBcyBzZWVuIGZyb20gdGhlIGRhdGFzZXQgYWJvdmUsIGlmIFRlYW0gd2lucyBhZnRlciBmaWVsZGluZyBmaXJzdCB0aGV5IHdpbiBieSB3aWNrZXRzLiBJZiB0aGUgdGVhbSB3aW5zIGFmdGVyIGJhdGluZyBmaXJzdCwgdGhleSB3aW4gYnkgcnVucy4gVGhlcmUgaXMgbm8gbWF0Y2ggd2VyZSBhIHRlYW0gd2luIGJ5IGJpdGggcnVucyBhbmQgd2lja2V0cy4gSXQgaXMgbXV0dWFsbHkgZXhjbHVzaXZlLiBTbyB0aGVzZSB2YXJpYWJlbGVzIGhhcyB0byBiZSBzZXBlcmF0ZWQsIG90aGVyd2lzZSB0aGlzIHZhcmlhYmxlIHdpbGwgZWZmZWN0IGluIHRyYW5zZm9ybWluZyBhbmQgbm9ybWFsaXNpbmcgcHJvY2VkdXJlIHRvd2FyZHMgdGhlIGVuZC4gCmBgYHtyfQphIDwtIG1heChNYXRjaCRXb25fQnlbTWF0Y2gkV2luX1R5cGU9PSJieSBydW5zIl0pICMgbWF4IHZhbHVlIG9mIHdpbiBieSBydW5zCmIgPC0gbWluKE1hdGNoJFdvbl9CeVtNYXRjaCRXaW5fVHlwZT09ImJ5IHJ1bnMiXSkgIyBtYXggdmFsdWUgb2Ygd2luIGJ5IHJ1bnMKYyA8LSBtYXgoTWF0Y2gkV29uX0J5W01hdGNoJFdpbl9UeXBlPT0iYnkgd2lja2V0cyJdKSAjIG1heCB2YWx1ZSBvZiB3aW4gYnkgcnVucwpkIDwtIG1pbihNYXRjaCRXb25fQnlbTWF0Y2gkV2luX1R5cGU9PSJieSB3aWNrZXRzIl0pICMgbWF4IHZhbHVlIG9mIHdpbiBieSBydW5zCmRhdGEuZnJhbWUoIldpbl9UeXBlIj1jKCJCeSBSdW5zIiwiQnkgd2lja2V0cyIpLAogICAgICAgICAgICJNaW5pbXVtIiA9IGMoYixkKSwKICAgICAgICAgICAiTWF4aW11bSIgPSBjKGEsYykpCnRhYmxlKE1hdGNoJFdpbl9UeXBlKSAjIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgdW5kZXIgZWFjaCB2YXJpYWJsZQpgYGAKVGhlIG1heGltdW0gdmFsdWUgb2Ygd2luIGJ5IHdpY2tldHMgaXMgMTAgYW5kIG1heGltdW0gdmFsdWUgb2Ygd2luIGJ5IHJ1bnMgaXMgMTQ0LiBUaGVyZSBpcyBhIGJpZyBkaWZmZXJlbmNlIGluIHRoZSBzY2FsZSBpZiB0aGVzZSB2YWx1ZXMuIEFsc28gdGhlcmUgaXMgYWxtb3N0IGVxdWFsIHJlcHJlc2VudGF0aW9uIG9mIHdpbiBieSBydW5zIGFuZCB3aW4gYnkgd2lja2V0cyBpbiB0aGUgZGF0YXNldC4gSW4gdGhpcyBjYXNlIG1vc3Qgb2YgdGhlIHZhbHVlcyBvZiB3aW4gYnkgcnVucyB3aWxsIGJlIGNsYXNzaWZpZWQgYXMgb3V0bGllcnMgd2hpbGUgY2hla2luZyBmb3Igb3V0bGllcnMuIEFsc28gdGhpcyB3aWxsIHBvc3NlcyBwcm9ibGVtIHdoaWxlIHN0YW5kYXJkaXNhdGlvbiBvZiB0aGUgdmFyaWFibGVzLiBTbyB3ZSBhcmUgZ29pbmcgdG8gc3ByZWFkIHRoZSB2YXJpYWJsZSBXb24gYnkgb24ga2V5ID0gV2luX3R5cGUgYW5kIHZhbHVlIGFzIFdvbl9CeS4gV2UgYXJlIGZpbGxpbmcgdGhlIG51bGwgdmFsdWVzIHByb2R1Y2VkIGFzIGEgcmVzdWx0IG9mIHRoaXMgc3ByZWFkIHdpdGggOTk5LiBUaGlzIGlzIGFuIGltcG9zc2liZSB2YWx1ZSBmb3IgdGhlIHZhcmlhYmxlIGFuZCBjYW4gYmUgdXNlZCBhcyBhIHJlZmVyZW5jZSBmb3IgZnVydGhlciBhbmFseXNpcyB3aGlsZSB0cmFuc2Zvcm1pbmcgdGhlIHZhcmlhYmxlcy4gV2UgYXJlIG5vdCBrZWVwaW5nIGl0IGFzIE5BIGFzIGl0IHdpbGwgaW50cm9kdWNlIGEgTkEgdmFsdWUgdG8gYWxsIHRoZSBvYnNlcnZhdGlvbnMgYW5kIGFuYWx5c2luZyB0aGUgb3RoZXIgbnVsbCB2YWx1ZXMgd2lsbCBiZWNvbWUgZGlmZmZpY3VsdC4gV2UgYXJlIGFsc28gc2F2aW5nIGEgY29weSBvZiB0aGUgdmFyaWFibGUgV2luX1R5cGUgZm9yIGZ1dHVyZSByZWZlcmVuY2UgYXMgdGhpcyB2YXJpYWJsZSB3aWxsIGJlIHJlbW92ZWQgZnJvbSB0aGUgZGF0YXNldCBhZnRlciB0aGUgc3ByZWFkIG9wZXJhdGlvbi4KCmBgYHtyfQpXaW5fVHlwZSA8LSBNYXRjaCRXaW5fVHlwZSAjIHNhdmluZyB0aGUgb3JpZ2luYWwgdmFyaWFibGUgZm9yIGZ1cnRoZXIgcmVmZXJlbmNlCk1hdGNoIDwtIHNwcmVhZChNYXRjaCwga2V5ID0gV2luX1R5cGUsIHZhbHVlID0gV29uX0J5LCBmaWxsID0gOTk5KQp0YWJsZShNYXRjaCRUaWUpICMgdGFibGUgb2YgVGllIGNvbHVtbgp0YWJsZShNYXRjaCRgTm8gUmVzdWx0YCkgIyBUYWJsZSBvZiBObyBSZXN1bHQgQ29sdW1uCmBgYAoKVGhlIHZhcmlhYmxlcyBmb3JtZWQgYWZ0ZXIgdGhlIHNwcmVhZCBvcHJhdGlvbnMgYXJlIGBieV9ydW5zYCwgYGJ5X3dpY2tldHNgLCBgVGllYCBhbmQgYE5vIHJlc3VsdGAuIFRoZSBsYXN0IHR3byB2YXJpYWJsZSBhcmUgbm90IGhhdmluZyBvbmx5IDk5OSBhcyB2YWx1ZXMgc2luY2UgdGhleSB3ZXJlIGZhY3RvcnMgaW5kaWNhdGluZyB0aGF0IHRoZXJlIHdhcyBubyByZXN1bHQgZ2VuZXJhdGVkIGluIHRoZSBtYXRjaC4gU28gd2Ugd2lsbCByZW1vdmUgdGhpcyB2YXJpYWJsZXMgZnJvbSB0aGUgZnVydGhlciBhbmFseXNpcy4KYGBge3J9Ck1hdGNoIDwtIE1hdGNoICU+JSBzZWxlY3QoLWMoIlRpZSIsIk5vIFJlc3VsdCIpKQpgYGAKCkFmdGVyIHNwcmVhZCBvcGVyYXRpb24gb24gYFdvbl9ieWAgYW5kIGBXaW5fVHlwZWAgdGhlcmUgaXMgbm8gbXVsdGlwbGUgdmFyaWFibGVzIHdoaWNoIGFyZSBzdG9yZWQgaW4gb25lIGNvbHVtbi4gQWxzbyBtdWx0aXBsZSBjb2x1bW5zIGFyZSBub3QgZm9ybWluZyBhIHNpbmdsZSB2YXJpYWJsZS4gRWFjaCBvYnNlcnZhdGlvbiBpbiB0aGUgZGF0YXNldCByZXByZXNlbnQgYSB1bmlxdWUgY3JpY2tldCBtYXRjaCBhbmQgdGh1cyBlYWNoIG9ic2VydmF0aW9uIGlzIGhhdmluZyBpdHMgb3duIHJvdy4gTm8gbXVsdGlwbGUgdmFyaWFibGVzIGFyZSBzdG9yZWQgaW4gYW55IHJvd3MuIEVhY2ggcm93IGlzIHVuaXF1ZSBpbiBpdHMgcmVwcmVzZW50YXRpb24uIApBbHNvIGVhY2ggdmFsdWUgaXMgaGF2aW5nIGl0cyBvd24gY2VsbC4gVGhpcyBwcm92ZXMgdGhhdCBvdXIgZGF0YXNldCBpcyBub3cgY29uZm9ybWluZyB0byB0aGUgdGlkeSBkYXRhIHByaW5jaXBsZXMuCgojIwlUaWR5ICYgTWFuaXB1bGF0ZSBEYXRhIC0gSUkgCk1hbiBvZiB0aGUgTWF0Y2ggUGxheWVyJ3MgYWdlIGlzIGNhbGN1bGF0ZWQgZnJvbSB0aGUgRGF0ZSBvZiBiaXJ0aCBvZiB0aGUgUGxheWVyLiBNdXRhdGUgZnVuY3Rpb24gaXMgdXNlZCBmb3IgdGhpcyBwdXJwb3NlLiBUaGUgYmFzZSByIGZ1bmN0aW9uIGBhcy5wZXJpb2QoKWAgaXMgdXNlZCB0byBmaW5kIHRoZSBjdXJyZW50IGFnZSBvZiB0aGUgcGxheWVyIGZyb20gdG9kYXkncyBkYXRlIHVzaW5nIHRvZGF5KCkgZnVuY3Rpb24gZnJvbSBMdWJyaWRhdGUgcGFja2FnZS4KCiMjIyBDcmVhdGlvbiBvZiBjYWxjdWxhdGVkIHZhcmlhYmxlIC0gQWdlCmBgYHtyfQpNYXRjaCA8LSBtdXRhdGUoTWF0Y2gsIEFnZSA9IHllYXIoYXMucGVyaW9kKGludGVydmFsKE1hdGNoJERPQiwgdG9kYXkoKSksCiAgICAgICAgICAgICAgICAgICAgICAgIHVuaXQgPSAieWVhciIpKSkKc3VtbWFyeShNYXRjaCRBZ2UpCmBgYApUaGUgYWdlIG9mIHRoZSBwbGF5ZXIgaXMgc3VjY2Vzc2Z1bGx5IG11dGF0ZWQgaW4gdG8gdGhlIGRhdGFzZXQuIFRoZSBtaW5pbXVtIGFnZSBvZiBhbnkgcGxheWVyIHdobyBiZWNhbWUgbWFuIG9mIHRoZSBtYXRjaCBpcyAyMSB5ZWFycyBhbmQgdGhlIG1heGltdW0gYWdlIGFueSBwbGF5ZXIgd2hvIGJlY2FtZSBtYW4gb2YgdGhlIG1hdGNoIGlzIDQ5LiBCdXQgdGhlcmUgYXJlIDMgTkEncyBpbiB0aGUgZGF0YXNldC4gV2Ugd2lsbCBsb29rIGluIHRvIHRoZSBtaXNzaW5nIGRhdGFzZXQgaW4gdGhlIG5leHQgc2VjdGlvbi4gCgojIwlTY2FuIEkgClRoZSBkYXRhc2V0IGlzIHNjYW5uZWQgZm9yIGFueSBtaXNzaW5nIHZhbHVlcy4gVGhlIGNvbHVtbnMgd2l0aCBtaXNzaW5nIHZhbHVlcyBhcmUgZm91bmQgYnkgY29tYmluaW5nIGBjb2xTdW1zKClgIGZ1bmN0aW9uIGFuZCBgaXMubmEoKWAgZnVuY3Rpb24uIFRoZSBjb2x1bW5zIG5hbWVzIG9mIHRob3NlIGNvbHVtbnMgY29udGFpbmluZyB0aGUgbnVsbCB2YWx1ZXMgYW5kIG90aGVyIGludGVyZXN0ZWQgdmFyaWFibGVzIGFyZSBtYWRlIGluIHRvIGEgbGlzdCAuIFRoaXMgbGlzdCBpcyB1c2VkIHRvIGNyZWF0ZSBhIGRhdGFzZXQgY29udGFpbmluZyB0aGUgcm93cyBvZiB0aGUgdGhvc2Ugb2JzZXJ2YXRpb24gd2hpY2ggaGFzIG51bGwgdmFsdWVzLiBUaGlzIGlzIGRvbmUgYnkgdXNpbmcgdGhlIGZ1bmN0aW9uIGNvbXBsZXRlLmNhc2VzIGZvciBzY2FubmluZyB0aGUgbnVsbCB2YWx1ZSBjb250YWluaW5nIHJvd3MuCgojIyMgU2Nhbm5pbmcgZm9yIE5VTEwgdmFsdWVzCmBgYHtyfQpNYXRjaCRXaW5fVHlwZSA8LSBXaW5fVHlwZQpjb2xTdW1zKGlzLm5hKE1hdGNoKSkKY29sbTMgPC0gYyggIk1hdGNoX0lkIiwgIk1hdGNoX1dpbm5lciIsICJXaW5fVHlwZSIsICJieSBydW5zIiwgImJ5IHdpY2tldHMiLCAKICAgICAgICAgICAgIk1hbl9PZl9UaGVfTWF0Y2giLCJQbGF5ZXJfQ291bnRyeSIsICJET0IiICApCk1hdGNoWyFjb21wbGV0ZS5jYXNlcyhNYXRjaCksIGNvbG0zXSAjIFJvd3Mgd2l0aCBOQSB2YWx1ZXMKYGBgCkl0IGlzIGZvdW5kIHRoYXQgdGhlIGNvbHVtbnMgYERPQmAsIGBQbGF5ZXJfQ291bnRyeWAsIGBBZ2VgLCBgTWFuX09mX1RoZV9NYXRjaGAsIGFuZCBgTWF0Y2hfV2lubmVyYCBjb250YWlucyAzIE5VTEwgdmFsdWVzIGVhY2ggYW5kIHRoZSB2YXJpYWJsZSBgV29uX0J5YCBpcyBzaG93biBhcyBgbm8gcmVzdWx0YCBmb3IgdGhzZXMgdGhyZWUgdmFyaWFibGVzLiBJbiB0b3RhbCB0aGVyZSBhcmUgMTUgTlVMTCB2YWx1ZXMgaW4gdGhlIGRhdHNldC4gVXNpbmcgdGhlIGZ1bmN0aW9uIGNvbXBsZXRlLmNhc2VzKCksIHdlIHdlcmUgYWJsZSB0byBzZWUgdGhlIGFjdHVhbCBpc3N1ZSB3aXRoIHRoZSBkYXRhc2V0LiBUaGUgYERPQmAsIGBQbGF5ZXJfQ291bnRyeWAsIGBBZ2VgLCBgTWFuX09mX1RoZV9NYXRjaGAsIGFuZCBgTWF0Y2hfV2lubmVyYCB3aGljaCBhcmUgaGF2aW5nIDMgbWlzc2luZyB2YWx1ZXMgZWFjaCByZWdpc3RlcmVkIGFzIE5vIHJlc3VsdCBpbiB0aGUgYFdpbl9UeXBlYCB2YXJpYWJsZS4gVGhpcyBtZWFucyB0aGF0IHRoZSBtYXRjaCB3YXMgZm9yZmVpdGVkIGVpdGhlciBkdWUgdG8gYmFkIHdlYXRoZXIgb3Igc29tZSBvdGhlciBzaXR1YXRpb25zLiBTbyBubyByZXN1bHQgd2FzIHByb2R1Y2VkIGZvIHRoYXQgbWF0Y2hlcy4gVGhpcyBtYWtlcyBzZW5zZSBmb3IgbWlzc2luZyB2YWx1ZXMgaW4gdGhvc2UgZGF0YXNldHMuIFRoZXNlIDMgcm93cyBjYW4gYmUgZXhjbHVkZWQgYXMgdGhleSBhcmUgdmVyeSBsZXNzIGluIG51bWJlci4gCgpgYGB7cn0KTWF0Y2hbTWF0Y2gkV2luX1R5cGU9PSJUaWUiLGMoMSwxOCwxMSldCmBgYApJdCBjYW4gYWxzbyBiZSBzZWVuIHRoYXQgZm9yIHRoZSBtYXRjaGVzIHdoaWNoIHdhcyBhIFRpZSwgdGhlcmUgd2FzIGEgTWF0Y2ggd2lubmVyIHJlY29yZGVkLiBUaGlzIGNhbiBiZSBhbiBlcnJvciBhbmQgY2FuIGJlIGNvcnJlY3RlZC4gCmBgYHtyfQpNYXRjaCRNYXRjaF9XaW5uZXIgPC0gYXMuY2hhcmFjdGVyKE1hdGNoJE1hdGNoX1dpbm5lcikKTWF0Y2hbTWF0Y2gkV2luX1R5cGU9PSJUaWUiLCAiTWF0Y2hfV2lubmVyIl0gPC0gIlRpZSIKTWF0Y2gkTWF0Y2hfV2lubmVyIDwtIGFzLmZhY3RvcihNYXRjaCRNYXRjaF9XaW5uZXIpCmBgYApTbyB3ZSBhZGRlZCBhIG5ldyBsZXZlbCB0byB0aGUgdmFyaWFibGUgYE1hdGNoX1dpbm5lcmAuIFdlIGNvbnZlcnRlZCBpdCB0byBhIGNoYXJhY3RlciBmaXJzdCBhbmQgdGhlbiBhZGRlZCB0aGUgbmV3IGxldmVsIHNpbmNlIGFuIGFscmVhZHkgZGVjbGFyZWQgZmFjdG9yIHdpbGwgbm90IGFsbG93IGFkZGl0aW9uIG9mIG5ldyBmYWN0b3IgbGV2ZWxzIGluIHRoaXMgbWFubmVyLiBUaGVuIHdlIGNvbnZlcnRlZCB0aGF0IGJhY2sgdG8gYSBmYWN0b3IgdXNpbmcgYXMuZmFjdG9yIGZ1bmN0aW9uLgoKIyMjIEhhbmRsaW5nIE51bGwgVmFsdWVzCk5vdyB3ZSBjYW4gaW1wdXRlIHplcm8gdmFsdWVzIHRvIHRoZSB2YXJpYWJsZXMgdGhhdCBoYXZlIE5BIHZhbHVlcyBmb3IgbWF0Y2hlcyB0aGF0IGFyZSBUaWUgd2hpbGUgc3ByZWFkaW5nIHRoZSBkYXRhLiBBZnRlciB0aGlzIHN0ZXAgd2UgYXJlIGJlIGxlZnQgd2l0aCBvbmx5IDMgY29sdW1ucyB0aGF0IGhhdmUgTkEgdmFsdWVzLiBUaGVzZSBhcmUgdGhvc2UgbWF0Y2hlcyB0aGF0IHdhcyBmb3JmZWl0ZWQgZHVlIHRvIHNvbWUgcmVhc29ucyBhbmQgdGhlcmUgd2FzIG5vIG91dGNvbWUgb2YgdGhlIG1hdGNoLiBTbyB3ZSByZW1vdmUgdGhlc2UgY29sdW1ucyBhcyBpdCBjb25zdGl0dXRlIG9ubHkgYHIgMyoxMDAvbGVuZ3RoKE1hdGNoJFdpbl9UeXBlKWAlIG9mIHRoZSB0b3RhbCBkYXRhc2V0LiBUaGUgZnVuY3Rpb24gYG5hLm9taXRgIGlzIHVzZWQgdG8gb21pdCB0aGlzIHZhcmlhYmxlIGZyb20gdGhlIGFuYWx5c2lzLgpgYGB7cn0KTWF0Y2hbIWNvbXBsZXRlLmNhc2VzKE1hdGNoKSwgY29sbTNdICMgUm93cyB3aXRoIE5BIHZhbHVlcwoKTWF0Y2ggPC0gbmEub21pdChNYXRjaCkgIyBFeGNsdWRpbmcgcmVtYWluaW5nIE5BIHZhbHVlcyBmcm9tIHRoZSBkYXRhc2V0CnN1bShpcy5uYShNYXRjaCkpICMgVG90YWwgbnVtYmVyIG9mIE5BIHZhbHVlcyByZW1haW5pbmcgaW4gdGhlIGRhdGFzZXQKYGBgCkFmdGVyIHRoaXMgb3BlcmF0aW9ucyB0aGUgdG90YWwgc3VtIG9mIHRoZSBuYSB2YWx1ZXMgaW4gdGhlIGRhdHNldCBpcyBmb3VuZCB0byBiZSB6ZXJvIGFuZCBub3cgd2UgY2FuIHByb2NlZWQgd2l0aCB0aGUgZnVydGhlciBzdGVwcyB3aXRob3V0IG51bGwgdmFsdWVzLgoKIyMjIENoZWNraW5nIGluY29uc2lzdGVuY2llcwpJbmNvbnNpc3RlbmNpZXMgaW4gdGhlIGRhdGFmcmFtZSBsaWtlIHByZXNlbmNlIG9mIC1gSW5mYCwgYEluZmAgYW5kIGBOYU5gIGFyZSBzY2FubmVkIHVzaW5nIHRoZSBmb2xsb3dpbmcgZnVuY3Rpb24gY2FsbGVkIGlzLnNwZWNpYWwuIFRoaXMgZnVjdGlvbiBjaGVja3MgaWYgdGhlIGN1cnJlbnQgdmFsdWUgaXMgZmluaXRlIG90IG5vdC4gQSBzdWJzZXQgb2YgbnVtZXJpYyBkYXRhc2V0IGlzIGNyZWF0ZWQgZnJvbSB0aGUgTWF0Y2ggZGF0YXNldCB1c2luZyB0aGUgaXMubnVtZXJpYyBmdW5jdGlvbi4gVGhlbiB0aGUgaXMuc3BlY2lhbCBmdW5jdGlvbiBpcyBhcHBsaWVkIHRvIHRoZSBlbnRpcmUgbnVtZXJpYyBkYXRhZnJhbWUgdXNpbmcgc2FwcGx5IGFzIGZvbGxvd3MuCmBgYHtyfQojIGZ1bmN0aW9uIGZvciBzZWFyaGluZyB0aGUgaW5maW5pdGUsIGFuZCBOYU4gdmFsdWVzCmlzLnNwZWNpYWwgPC0gZnVuY3Rpb24oeCl7IAogIWlzLmZpbml0ZSh4KQp9CiMgY2hlY2tpbmcgZm9yIHRoZSBpbmNvbnNpc3RlbmNpZXMgaW4gdGhlIG51bWVyaWMgdmFsdWVzCm51bURhdGEgPC0gTWF0Y2hbLHNhcHBseShNYXRjaCwgaXMubnVtZXJpYyldICMgc3Vic2V0IG9mIG51bWVyaWMgZGF0YXNldApjb2xTdW1zKHNhcHBseShudW1EYXRhLCBpcy5zcGVjaWFsKSkgCmBgYApJdCBpcyBmb3VuZCB0aGF0IHRoZXJlIGFyZSBubyBpbmNvbnNpc3RlbmQgb3Igc3BlY2lhbCB2YWx1ZXMgaW4gdGhlIGRhdGFzZXQuIAoKIyMJU2NhbiBJSSAtIE91dGxpZXJzCkluIHRoaXMgc3RlcCBkYXRhIGlzIHNjYW5uZWQgZm9yIG91dGxpZXJzLiBJbiBNYXRjaCBkYXRhc2V0IHRoZXJlIGFyZSB0aHJlZSBudW1lcmljIHZhcmlhYmxlcyBgQWdlYCxgYnkgcnVuYCBhbmQgYGJ5IHdpY2tldHNgLiBOb3cgZGF0YSBzZXQgaGF2ZSB0aHJlZSBudW1lcmljIHZhcmlhYmxlcyBgYnkgcnVuc2AsIGBieSB3aWNrZXRzYCBhbmQgYGFnZWAuIFdlIGhhdmUgdG8gY29udmVydCB0aGUgOTk5IHZhbHVlcyBpbiB0aGUgZGF0c2V0IGJhY2sgdG8gbnVsbCB2YWx1ZXMgZm9yIGJldHRlciBjbGFyaXR5IG9mIHRoZSBvdWxpZXJzLgpgYGB7cn0KTWF0Y2gkYGJ5IHJ1bnNgW01hdGNoJGBieSBydW5zYD09OTk5XSA8LSBOQQpNYXRjaCRgYnkgd2lja2V0c2BbTWF0Y2gkYGJ5IHdpY2tldHNgPT05OTldIDwtIE5BCmBgYAoKTm93IGxldCdzIGNoZWNrIG91dGxpZXJzIGZvciBlYWNoIG9mIGl0LiAKYGBge3J9CkJ5X3J1bnMgPC0gTWF0Y2gkYGJ5IHJ1bnNgICU+JSBuYS5vbWl0KCkKIyBieSBydW5zCkJ5X3J1bnMgJT4lICBib3hwbG90KG1haW4gPSAiRGlzdHJpYnV0aW9uIG9mIFdvbiBCeSBydW5zIHZhcmlhYmxlIiwgeWxhYiA9CiJXb24gQnkgUnVucyIsIGNvbCA9ICJncmV5IikgCmBgYAoKVGhlIGBieSBydW5gIGlzIGhhdmluZyBtYW55IG91dGxpZXJzIGFzIHNob3duIGJ5IHRoZSBCb3hQbG90LiBUaGUgYm94cGxvdCBpcyBpbmZsdWVuY2VkIGJ5IHRoZSBsb3cgbGV2ZWwgdmFsdWVzIGluIHRoZSBkYXRhZXQuIEluIGZhY3QgdGhlc2UgYXJlIG5vdCBhY3R1YWwgb3V0bGllcnMgYW5kIHRoaXMgYXBwZXJzIHRvIGJlIG91dGxpZXJzIGJlY2F1c2Ugb2YgdGhlIGxvdyBydW4gdmFsdWVzIHByZXNlbnQgaW4gdGhlIGRhdGEuIExldHMgbG9vayB0aGUgenNjb3JlIHZhbHVlcy4KCmBgYHtyfQojIFogc2NvcmUKei5zY29yZXMgPC0gQnlfcnVucyAlPiUgIHNjb3Jlcyh0eXBlID0gInoiKSAlPiUgbmEub21pdCgpCnouc2NvcmVzICU+JSBzdW1tYXJ5KCkKbGVuZ3RoICh3aGljaChhYnMoei5zY29yZXMpID4gMykpCmBgYApDaGVja2luZyBvdXRsaWVycyB1c2luZyB6IHNjb3JlIG1ldGhvZC4gQXBwbHlpbmcgei1zY29yZSBtZXRob2QgaXQgaXMgZm91bmQgdGhhdCB0aGVyZSBhcmUgNCBvdXRsaWVycyBpbiBgYnkgcnVuc2AgbWV0aG9kLiAKCk5leHQgd2UgY2hlY2sgdGhlIGBieSB3aWNrZXRzYCB2YXJpYWJsZSBmb3Igb3V0bGllcnMsIEZpcnN0IHdlIHBsb3QgdGhlIEJveFBsb3QuCmBgYHtyfQojIGJ5IHdpY2tldHMKQnlfd2lja2V0cyA8LSBNYXRjaCRgYnkgd2lja2V0c2AgJT4lIG5hLm9taXQoKQpCeV93aWNrZXRzICU+JSAgYm94cGxvdChtYWluID0gIkRpc3RyaWJ1dGlvbiBvZiBXb24gQnkgV2lja2V0cyB2YXJpYWJsZSIsIHlsYWIgPQoiV29uIEJ5IFdpY2tldHMiLCBjb2wgPSAiZ3JleSIpCmBgYAoKVGhlcmUgc2VlbXMgdG8gYmUgbm8gb3V0bGllciBhdCBhbGwuIFNvIHdlIHdpbGwgY2hlY2sgdGhlIHotc2NvcmVzLgpgYGB7cn0KIyBaIHNjb3JlCnouc2NvcmVzIDwtIEJ5X3dpY2tldHMgJT4lICBzY29yZXModHlwZSA9ICJ6IikKei5zY29yZXMgJT4lIHN1bW1hcnkoKQpsZW5ndGggKHdoaWNoKGFicyh6LnNjb3JlcykgPiAzKSkKYGBgClNpbmNlIHRoZSBtYXhpbXVtIHotc2NvcmUgaXMgMi4wNSB3aGljaCBpcyBsZXNzIHRoYW4gMywgdGhlcmUgaXMgbm8gb3V0bGllciB3aXRoIHRoZSBaLXNjb3JlIGFzIHdlbGwuCk5leHQgd2Ugd2lsbCBjaGVjayBmb3IgdGhlIGFnZSBwYXJhbWV0ZXIuCmBgYHtyfQojIEFnZQpNYXRjaCRBZ2UgJT4lICBib3hwbG90KG1haW4gPSAiRGlzdHJpYnV0aW9uIG9mIEFnZSB2YXJpYWJsZSIsIHlsYWIgPQoiQWdlIiwgY29sID0gImdyZXkiKQpgYGAKClRoZXJlIHNlZW1zIHRvIGJlIG9uZSB2YXJpYWJsZSB3aGljaCBpcyBzaG93biBhcyAgYW4gb3V0bGllciBieSB0aGUgQm94cGxvdCBtZXRob2QuIFdlIGZvdW5kIHRoYXQgdGhpcyBjYW1lIGZyb20gdGhlIG1heGltdW0gYWdlIG9mIDQ5LiAKYGBge3J9Cm1heChNYXRjaCRBZ2UpICMgTWF4aW11bSBhZ2UgaW4gdGhlIGRhdGFzZXQKdW5pcXVlKE1hdGNoJE1hbl9PZl9UaGVfTWF0Y2hbTWF0Y2gkQWdlPjQ4XSkgIyBwbGF5ZXJzIHdpdGggbWF4aW11bSBhZ2UKYGBgCldlIGZvdW5kIHRoYXQgIlNUIEpheWFzdXJpeWEiIGFuZCAiU0sgV2FybmUiIGFyZSB0aGUgcGxheWVycyB3aXRoIG1heGltdW0gYWdlIGFuZCBjb25maXJtZWQgZnJvbSBJbnRlcm5ldCBTb3VyY2UsIENyaWNrQnV6eiwgIHRoYXQgW1NhbmF0aCBKYXlhc3VyaXlhXShodHRwczovL3d3dy5jcmljYnV6ei5jb20vcHJvZmlsZXMvMTAyL3NhbmF0aC1qYXlhc3VyaXlhKSBhbmQgW1NoYW5lIFdhcm5lXShodHRwczovL3d3dy5jcmljYnV6ei5jb20vcHJvZmlsZXMvMTM1L3NoYW5lLXdhcm5lKSBhcmUgaGF2aW5nIDQ5IHllYXJzIG9mIGFnZS4gU28gdGhpcyBpcyBub3QgYW4gb3V0bGllci4gCgpgYGB7cn0KIyBaIHNjb3JlCnouc2NvcmVzX0FnZSA8LSBNYXRjaCRBZ2UgJT4lICBzY29yZXModHlwZSA9ICJ6IikKei5zY29yZXNfQWdlICU+JSBzdW1tYXJ5KCkKbGVuZ3RoICh3aGljaChhYnMoei5zY29yZXNfQWdlKSA+IDMpKQpgYGAKUHJvdmluZyB0aGF0IHRoZSB6LXNjb3JlIHNob3dzIHRoZXJlIGlzIG5vIG91dGxpZXJzLiBBcyB0aGUgYWJvdmUgYm94IHBsb3RzIGluZGljYXRlcyBgYnkgcnVuYCB2YXJpYWJsZSBpcyBzaG93aW5nIG91dGxpZXJzLiBXaGVyZSBhcyBgYWdlYCBhbmQgYGJ5IHdpY2tldHNgIGlzIG5vdCBzaG93aW5nIGFueSBvdXRsaWVycyBpbiBib3ggcGxvdC4KCiMjCVRyYW5zZm9ybSAKVGhlIHRoZSBudW1lcmljYWwgdmFyaWFubGVzIGluIHRoZSBkYXRhc2VydCBpcyBjaGVja2VkIGZvciBmdXJ0aGVyIHByb2NlZWRpbmcgIHdpdGggc3RhdGlzdGljYWwgYW5hbHlzaXMuIEFzIHdlIGhhdmUgc2VlbiBpbiB0aGUgT3V0bGllcnMgb2YgYWxsIHRoZSBudW1lcmljYWwgdmFyaWFibGVzLCB0aGVyZSBhcmUgbXV0dWFsbHkgZXhjbHVzaXZlIHNldHMgd2hpY2ggYXJlIGhhdmluZyBkaWZmZXJlbnQgc2NhbGluZyBpbiB0aGUgZGF0c2V0LiBBbHNvIGR1ZSB0byBpbnRyb2R1Y3Rpb24gb2YgemVybyBpbiBjYXNlIG9mIG51bGwgdmFsdWVzIHdlIGhhdmUgdG8gc2VwZXJhdGUgdGhpcyB2YWx1ZXMgd2hpbGUgYW5hbHlzaXMgb2YgCkZpcnN0IHdlIHdpbGwgYW5hbHlzaXMgdGhlIEFnZSB2YXJpYWJsZS4KYGBge3J9CiMgQWdlIGlzIGFsbW9zdCBub3JtYWxseSBkaXN0cmlidXRlZCAKaGlzdChNYXRjaCRBZ2UsbWFpbiA9ICJEaXN0cmlidXRpb24gb2YgQWdlIix4bGFiPSJBZ2UiKQpgYGAKClRoZSBoaXN0b2dyYW0gaXMgc2xpZ2h0bHkgc2tld2VkIHRvIHRoZSByaWdodC4gQWZ0ZXIgbnVtZXJvdXMgdHJpYWwgYW5kIGVycm9yIG1ldGhvZHMgQm94Q294IHRyYW5zZm9ybWF0aW9uIHdhcyBtYWtpbmcgdGhlIGRhdGEgYmV0dGVyLiBJdCBpcyBzaG93biBiZWxvdy4KYGBge3J9CiMgQm94LUNveCB0cmFuc2Zvcm1hdGlvbgpBZ2VfYm94PC0gQm94Q294KE1hdGNoJEFnZSxsYW1iZGEgPSAiYXV0byIpCmhpc3QoQWdlX2JveCwKICAgICBtYWluID0gIkRpc3RyaWJ1dGlvbiBvZiBBZ2UgdmFyaWFibGUgKEJveENveCBUcmFuc2Zvcm1hdGlvbikiLAogICAgIHhsYWIgPSAiQWdlIiwKICAgICBjb2wgPSAiZ3JleSIpCmBgYAoKRXZlbiB0aG91Z2ggaXQgaXMgc2xpZ2h0bHkgc2tld2VkIHRvIHRoZSBsZWZ0IHRoZSBkYXRhc2V0IGhhcyBpbXByb3ZlZCBpbiBpdHMgc3ltbWV0cnkuIE5vdyBsZXRzIGxvb2sgdGhlIHZhcmlhYmxlIGBCeV9ydW5zYC4KYGBge3J9Cmhpc3QoQnlfcnVucywgbWFpbiA9ICJEaXN0cmlidXRpb24gb2YgV29uIEJ5IFJ1bnMiLCB4bGFiID0gIldvbiBCeSBSdW5zIikKYGBgCgpgYnkgcnVuc2AgaXMgaGdobHkgc2tld2VkIHRvIHRoZSByaWdodC4gU2luY2UgbG9nIHRyYW5zZm9ybWF0aW9uIGlzIGJldHRlciBmb3IgaW1wcm92aW5nIHRoZSBkaXNydGlidXRpb25zIHdpdGggcmlnaHQgc2tld25lc3Mgd2UgYXBwbHkgbG9nIHRyYW5zZm9ybWF0aW9uIHRvIHRoaXMgZGF0YXNldC4gV2UgYWxzbyBhZGQgYSBjb25zdGFudCA0IHRvIHRoZSBkYXRhIGZvciBiYXR0ZXIgcmVzdWx0cy4KYGBge3J9CkJ5X3J1bnMgPC0gQnlfcnVucys0CiMgTmF0dXJhbCBMb2cgdHJhbnNmb3JtYXRpb24KcnVuc19sbiA8LSBsb2coQnlfcnVucykKaGlzdChydW5zX2xuLAogICAgIG1haW4gPSAiRGlzdHJpYnV0aW9uIG9mIFdvbiBCeSBydW5zIHZhcmlhYmxlIChMb2cgVHJhbnNmb3JtYXRpb24pIiwKICAgICB4bGFiID0gIldvbiBieSBSdW5zIiwKICAgICBjb2wgPSAiZ3JleSIpCmBgYAoKSXQgaXMgc2VlbiB0aGF0IHRoZSBkYXRhc2V0IGhhcyBpbXByb3ZlZCBhIGxvdCBpbiB0aGlzIGNhc2UuIExvZyB0cmFuc2Zvcm1hdGlvbiBoYXMgcmVtb3ZlZCB0aGUgaGlnaCBza2V3bmVzcyBpbiB0aGUgZGF0YS4gTm93IGxldHMgY2hlY2sgZm9yIHRoZSB3aWNrdGVzIGRhdGEuCgpgYGB7cn0KaGlzdChCeV93aWNrZXRzLCBtYWluID0gIkRpc3RyaWJ1dGlvbiBvZiBXb24gQnkgd2lja2V0cyIsIAogICAgIHhsYWIgPSAiV29uIEJ5IFdpY2tldHMiKQpgYGAKCkhlcmUgdGhlIGRhdGEgaXMgYWxtb3N0IHN5bW1ldHJpY2FsbHkgZGlzdHJpYnRlZCBhbmQgZG9lc250IG5lZWQgYW55IG1vcmUgdHJhbnNmb3JtYXRpb24uIAoKIyMgQ29uY2x1c2lvbgpUaGUgZGF0YSBzZXQgd2FzIGluIHVudGlkeSBmb3JtYXQgd2hpY2ggd2FzIGNvbnZlcnRlZCBpbiB0byBhIHRpZHkgZm9ybWF0IGFjY29yZGluZyB0byB0aWR5IGRhdGEgcHJpbmNpcGxlcy4gTWFueSBOQSB2YWx1ZXMgaW4gdGhlIGRhdGEgc2V0IHdhcyBhbHNvIGhhbmRsZWQgcHJvcGVybHkgYnkgaW1wdXRpbmcgYW5kIGV4Y2x1ZGluZyBzb21lIG9ic2VydmF0aW9ucy4gTWFueSBkYXRhIHR5cGUgY29udmVyc2lvbiB3ZXJlIG5lY2Vzc2FyeS4gT3V0bGllcnMgaW4gdGhlIGRhdHNldCB3ZXJlIHByb3ZlZCB0byBiZSBub3QgYW4gb3V0bGllciBhbmQgdGhleSB3ZXJlIGlkZW50aWZpZWQgbm90IGluZmx1ZW5jaW5nIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIGRhdGFldCBhcyBhIHdob2xlLiBUaGUgZGF0YSB3YXMgdHJhbnNmb3JtZWQgdXNpbmcgbG9nIGFuZCBib2NveCB0cmFuc2Zvcm1hdGlvbiBtZXRob2RzIHRvIG1ha2UgdGhlIG51bXJlaWNhbCB2YXJpYWJsZXMgbm9ybWFsLiBOb3cgdGhlIGRhdGFzZXQgaXMgcmVhZHkgZm9yIGZ1cnRoZXIgZGF0YSBhbmFseXNpcyB0ZWNobmlxdWVzIGxpa2UgcmVncmVzc2lvbiwgY2xhc3NpZmljYXRpb24gYW5kIGNsdXN0ZXJpbmcuLiAKPGJyPgo8YnI+Cg==