Required packages

# This is the R chunk for the required packages
library(fitzRoy)
library(readr)
library(dplyr)
library(tidyr)
library(lubridate)
library(editrules)

Executive Summary

In this assignment I sought to combine data on the Australian Football League or AFL from the website AFL Tables with rainfall data from the Bureau of Meteorology.

Specifically, I narrowed the focus to AFL matches played at the MCG since rainfall data from the BOM’s Olympic Park weather station, near the MCG, became available on June 2 2013, through to the conclusion of the 2019 AFL season.

I combined these two datasets based on the date variable, which is present in both the AFL data and the BOM rainfall data.

I converted some variables in the resulting dataset to factor type as appropriate and created new variables recording the accuracy and total score of the relevant AFL matches.

I also created a second dataset on the umpiring of AFL matches. This data arrived in an untidy format and it was necessary to tidy it for this purpose.

Both datasets were checked for missing and special values, impossible values or obvious errors, and outliers. No significant issues were uncovered.

This report also contains a demonstration of how the ‘Attendance’ variable could be re-scaled for analysis.

Data

Data was obtained from two seperate sources: AFL Tables, and the Bureau of Meteorology.

AFL Tables data is best obtained through use of the fitzRoy package’s get_afltables_stats function. I specified the upper and lower date limits for data collection.

This produces the following variables:

Some of these variables are player-specific and unique on each line, and same are match-specific and repeated for each instance of a player in that match. Since I wished to use match data only, I used the dplyr select function to select only match data, and then used the distinct function to remove the redundant observations.

I then filtered the data to only include matches played at the MCG.

BOM data can be downloaded directly from the BOM website, where it comes as a csv. I read it into R using readr’s read_csv function.

This data has the following variables:

Although data collection at the site only began on June 2, 2013, this dataset contains observations for all days in 2013. As such, I used the complete cases function to remove observations with empty values from the dataset.

I renamed the variables in this dataset for ease of use, and then created a new variable using the dplyr and lubridate packages to combine the Year, Month and Day variables into a single date variable.

This was necessary in order to combine the weather data with the AFL data, which also contains a Date variable. I subsetted the weather data down to two variables - Date and Rainfall - and then used the dplyr left_join function to add the rainfall data to the afl dataset.

The use of left_join insures that only weather data observations with a matching date are brought into the AFL dataset - inner_join would also have been appropriate.

# Loading AFL data
afl <- get_afltables_stats(start_date = '2013-06-02', end_date = '2020-01-01')

head(afl)

# Cleaning AFL data
afl <- afl %>% select(Season:Home.team, HQ4G:Away.team, AQ4G:Away.score, Umpire.1:Umpire.4)
afl <- afl %>% distinct()
afl <- afl %>% filter(Venue == 'M.C.G.')

# Loading weather data
weather <- read_csv('weather.csv')
Parsed with column specification:
cols(
  `Product code` = col_character(),
  `Bureau of Meteorology station number` = col_character(),
  Year = col_double(),
  Month = col_character(),
  Day = col_character(),
  `Rainfall amount (millimetres)` = col_double(),
  `Period over which rainfall was measured (days)` = col_double(),
  Quality = col_character()
)
head(weather)

# Cleaning weather data
weather <- weather[complete.cases(weather), ]
colnames(weather) <- c('ProductCode', 'Station', 'Year', 'Month', 'Day', 'Rainfall', 'Period', 'Quality')
weather <- weather %>% mutate(Date = make_date(Year, Month, Day))
weather <- weather %>% select(Date, Rainfall)

# Joining datasets
afl <- afl %>% left_join(weather, by = "Date")

head(afl)

Understand

I used the str function to look at the structure of the combined AFL dataset.

I identified five variables in need of conversion to factor type - Season, Round, Venue, Home.team and Away.team.

I passed these variables into the table function to check for the possibility of typos in the values which might need to be corrected before converting the datatype, or NA values. There were no instances present for either of these possible issues.

I converted these variables to factor type. For the Round variable, I defined a specific vector of labels, as this variable contains a mix of numeric and alphabetic data, and would not be appropriately ordered by standard alphabetic order. However as these rounds are not numerically “greater” than each other I did not set Ordered = TRUE.

A second check of the structure of the dataset shows the successful datatype conversions. All other variables in this dataset have an appropriate datatype.

# Checking data structure
str(afl)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   328 obs. of  19 variables:
 $ Season          : num  2013 2013 2014 2014 2015 ...
 $ Round           : chr  "12" "16" "10" "18" ...
 $ Date            : Date, format: "2013-06-15" "2013-07-12" "2014-05-25" ...
 $ Local.start.time: int  1340 1950 1640 1640 1340 1920 1950 1950 1520 1310 ...
 $ Venue           : chr  "M.C.G." "M.C.G." "M.C.G." "M.C.G." ...
 $ Attendance      : int  43615 54790 32419 41486 32035 60872 70879 45781 29133 32430 ...
 $ Home.team       : chr  "Richmond" "Collingwood" "Carlton" "Collingwood" ...
 $ HQ4G            : int  16 17 12 12 14 16 21 17 15 7 ...
 $ HQ4B            : int  14 9 9 10 6 13 9 10 8 5 ...
 $ Home.score      : int  110 111 81 82 90 109 135 112 98 47 ...
 $ Away.team       : chr  "Adelaide" "Adelaide" "Adelaide" "Adelaide" ...
 $ AQ4G            : int  10 12 10 14 14 14 8 17 18 16 ...
 $ AQ4B            : int  12 12 16 14 15 18 13 7 12 11 ...
 $ Away.score      : int  72 84 76 98 99 102 61 109 120 107 ...
 $ Umpire.1        : chr  "Dean Margetts" "Stephen McBurney" "Matthew Leppard" "Luke Farmer" ...
 $ Umpire.2        : chr  "Shane Stewart" "Matt Stevic" "Sam Hay" "Matt Stevic" ...
 $ Umpire.3        : chr  "Simon Meredith" "Shane Stewart" "Simon Meredith" "Jason Armstrong" ...
 $ Umpire.4        : chr  "" "" "" "" ...
 $ Rainfall        : num  0 0 0.6 1.4 0.2 0 0 21.6 0 0 ...
# Checking for typos and NA values
afl$Season %>% table(useNA = "ifany")
.
2013 2014 2015 2016 2017 2018 2019 
  28   50   49   50   50   51   50 
afl$Round %>% table(useNA = "ifany")
.
 1 10 11 12 13 14 15 16 17 18 19  2 20 21 22 23  3  4  5  6  7  8  9 EF GF PF QF SF 
15 11 11 11  8 13 14 11 12 11 13 14 15 14 15 14 14 12 17 12 13 12 12  6  7  7  6  8 
afl$Venue %>% table(useNA = "ifany")
.
M.C.G. 
   328 
afl$Home.team %>% table(useNA = "ifany")
.
        Adelaide          Carlton      Collingwood         Essendon          Geelong 
               1               36               62               26               18 
        Hawthorn        Melbourne  North Melbourne    Port Adelaide         Richmond 
              48               57                3                1               70 
        St Kilda           Sydney       West Coast Western Bulldogs 
               2                1                1                2 
afl$Away.team %>% table(useNA = "ifany")
.
              Adelaide         Brisbane Lions                Carlton            Collingwood 
                    16                     11                     19                     36 
              Essendon              Fremantle                Geelong             Gold Coast 
                    24                     14                     26                      8 
Greater Western Sydney               Hawthorn              Melbourne        North Melbourne 
                    17                     26                     22                     10 
         Port Adelaide               Richmond               St Kilda                 Sydney 
                    12                     24                     14                     20 
            West Coast       Western Bulldogs 
                    16                     13 
# Converting variables to factor type
afl$Season <- as.factor(afl$Season)
afl$Round <- factor(afl$Round, levels = c("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "QF", "EF", "SF", "PF", "GF"))
afl$Venue <- as.factor(afl$Venue)
afl$Home.team <- as.factor(afl$Home.team)
afl$Away.team <- as.factor(afl$Away.team)

# Confiriming successful conversions
str(afl)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   328 obs. of  19 variables:
 $ Season          : Factor w/ 7 levels "2013","2014",..: 1 1 2 2 3 3 3 4 4 4 ...
 $ Round           : Factor w/ 28 levels "1","2","3","4",..: 12 16 10 18 10 25 26 5 15 16 ...
 $ Date            : Date, format: "2013-06-15" "2013-07-12" "2014-05-25" ...
 $ Local.start.time: int  1340 1950 1640 1640 1340 1920 1950 1950 1520 1310 ...
 $ Venue           : Factor w/ 1 level "M.C.G.": 1 1 1 1 1 1 1 1 1 1 ...
 $ Attendance      : int  43615 54790 32419 41486 32035 60872 70879 45781 29133 32430 ...
 $ Home.team       : Factor w/ 14 levels "Adelaide","Carlton",..: 10 3 2 3 2 1 6 6 7 2 ...
 $ HQ4G            : int  16 17 12 12 14 16 21 17 15 7 ...
 $ HQ4B            : int  14 9 9 10 6 13 9 10 8 5 ...
 $ Home.score      : int  110 111 81 82 90 109 135 112 98 47 ...
 $ Away.team       : Factor w/ 18 levels "Adelaide","Brisbane Lions",..: 1 1 1 1 1 18 1 1 1 1 ...
 $ AQ4G            : int  10 12 10 14 14 14 8 17 18 16 ...
 $ AQ4B            : int  12 12 16 14 15 18 13 7 12 11 ...
 $ Away.score      : int  72 84 76 98 99 102 61 109 120 107 ...
 $ Umpire.1        : chr  "Dean Margetts" "Stephen McBurney" "Matthew Leppard" "Luke Farmer" ...
 $ Umpire.2        : chr  "Shane Stewart" "Matt Stevic" "Sam Hay" "Matt Stevic" ...
 $ Umpire.3        : chr  "Simon Meredith" "Shane Stewart" "Simon Meredith" "Jason Armstrong" ...
 $ Umpire.4        : chr  "" "" "" "" ...
 $ Rainfall        : num  0 0 0.6 1.4 0.2 0 0 21.6 0 0 ...

Tidy & Manipulate Data I

In this dataset, there are four variables dedicated to recording the umpires who officiated the relevant AFL match - Umpire.1, Umpire.2, Umpire.3 and Umpire.4. Each match has at least three umpires and some matches have a fouth umpire.

In AFL matches, there is no distinction made between a “first” or “second” umpire - the numbering here is used only to keep all umpire information contained to a single row. This is untidy as there are four columns used to record a single variable.

To tidy this data, I decided to split it off into a seperate dataset, umpires. This was done using the dplyr select function. I then used the tidyr gather function to convert the data to long format, creating a row for each indiviudal umpire.

This is combined with information on the match they umpired - in a relational database, this infomration could be condensed down to a single unique indentifier for each match which would be shared with the original dataset.

I removed the key variable created by the gather function as this provides no useful information. I used complete_cases to remove observations where there was no value in the umpire variable (due to many observations of Umpire.4 being blank).

With this data successfully tidied in a seperate dataset, I removed it from the main AFL dataset.

# Subsetting umpire data
umpires <- afl %>% select(Season:Date, Venue, Home.team, Away.team, Umpire.1:Umpire.4)

# Converting to long format
umpires <- umpires %>% gather(`Umpire.1`, `Umpire.2`, `Umpire.3`, `Umpire.4`, key = 'No', value = 'Umpire')

# Removing unnecessary key variable
umpires <- umpires %>% select(Season:Away.team, Umpire)

# Removing incomplete observations
umpires <- umpires[complete.cases(umpires), ]

head(umpires)

# Removing umpire data from original dataset
afl <- afl %>% select(Season:Away.score, Rainfall)

head(afl)

Tidy & Manipulate Data II

In an earlier step the dplyr mutate function was combined with the lubridate make_date function to create an additional variable. However, there are other possible instances where this would be a relevant task in this dataset.

I used mutate to create a new variable in the AFL dataset called Total.score, which combines the existing variables Home.score and Away.score, thus tracking the combined number of points scored in a match.

I also created an additional variable called Accuracy. This records what propotion of the combined total of scoring shots from the match (the combined total of HQ4G, AQ4G, HQ4B, and AQ4B) were goals (the combined total of HQ4G and AQ4G).

# Adding Total.score variable
afl <- afl %>% mutate(Total.score = Home.score+Away.score)

# Adding Accuracy variable
afl <- afl %>% mutate(Accuracy = (HQ4G+AQ4G)/(HQ4G+AQ4G+HQ4B+AQ4B))

head(afl)

Scan I

I put the two datasets, AFL and Umpires, through the is.na, is.infinite and is.nan functions to check for the presence of missing or special values. Neither is present in any of the variables in these two datasets.

I used the editrules package to define some rules to check the variables for obvious errors. These rules were: checking that the Local.start.time for each match was between noon and 10pm, checking that the crowd at a match was not a negative value nor an impossibly high amount, checking that the home and away scores reflected the expected total of six points per goal and one point per behind and that neither was greater than an impossibly high value, and checking that rainfall was never negative nor above an impossibly high value.

I then used the violatedEdits function to check if any observations breaked these set rules. There were no instances of broken rules.

# Checking for missing values
afl %>% is.na() %>% sum()
[1] 0
umpires %>% is.na() %>% sum()
[1] 0
# Checking for special values
afl %>% sapply(is.infinite) %>% sum()
[1] 0
umpires %>% sapply(is.infinite) %>% sum()
[1] 0
afl %>% sapply(is.nan) %>% sum()
[1] 0
umpires %>% sapply(is.nan) %>% sum()
[1] 0
# Defining variables rules
TimeRule <- editset(c("Local.start.time >= 1200", "Local.start.time <= 2200"))
CrowdRule <- editset(c("Attendance >= 0", "Attendance <= 150000"))
ScoreRule <- editset(c("Home.score == HQ4G * 6 + HQ4B", "Away.score == AQ4G * 6 + AQ4B", "Home.score <= 300", "Away.score <= 300"))
RainRule <- editset(c("Rainfall >= 0", "Rainfall <= 1000"))
Rules <- (c(TimeRule, CrowdRule, ScoreRule, RainRule))

# Checking for broken rules
violatedEdits(Rules, afl) %>% sum()
[1] 0

Scan II

To check the numerical variables for outliers, I created a series of boxplots for each numerical value.

The HQ4G, HQ4B, AQ4G, AQ4B, Home.score, Away.score and Accuracy variables all reported between 1-3 outliers, all at the high end of the boxplot.

I checked the highest values in these variables against an independent record of the data to ensure they were not incorrect values, which I can confirm they are not. As such, I decided to keep them as they are in the dataset.

The Rainfall data has a large number of outliers. This is due to this data being heavily right skewed - the majority of observations of this variable are 0.0, and as such many observations are considered outliers.

This is primarily an illustration of the skewedness of this dataset, as such, I decided to retain the values as they are.

I also checked three likely relationships of interest for bivariate outliers, creating scatter plots that each use Rainfall on the x axis and use Accuracy, Total.score and Attendance on the three y axes respectively.

These plots also show how the vast majority of rainfall data is at or near a zero value. There do not appear to be any bivariate outliers (or correlation) on the Accuracy or Total.score plots.

The attendance variable does show more evidence of a possible relationship and some potential outliers, but the data for high values of rainfall is too sparse to be confident that this is the case.

# Checking single variables for outliers
afl$Attendance %>% boxplot(main="Box Plot of MCG Crowds", ylab="Crowd")

afl$HQ4G %>% boxplot(main="Box Plot of HQ4G", ylab="HQ4G")

afl$HQ4B %>% boxplot(main="Box Plot of HQ4B", ylab="HQ4B")

afl$AQ4G %>% boxplot(main="Box Plot of AQ4G", ylab="AQ4G")

afl$AQ4B %>% boxplot(main="Box Plot of AQ4B", ylab="AQ4B")

afl$Home.score %>% boxplot(main="Box Plot of Home Score", ylab="Home Score")

afl$Away.score %>% boxplot(main="Box Plot of Away Score", ylab="Away Score")

afl$Total.score %>% boxplot(main="Box Plot of Total Score", ylab="Total Score")

afl$Rainfall %>% boxplot(main="Box Plot of Rainfall", ylab="Rainfall")

afl$Accuracy %>% boxplot(main="Box Plot of Accuracy", ylab="Accuracy")


#Checking for bivariate outliers
afl %>% plot(Accuracy ~ Rainfall, data =., ylab = "Accuracy", xlab = "Rainfall", main = "Accuracy by Rainfall")

afl %>% plot(Total.score ~ Rainfall, data =., ylab = "Total Score", xlab = "Rainfall", main = "Total Score by Rainfall")

afl %>% plot(Attendance ~ Rainfall, data =., ylab = "Attendance", xlab = "Rainfall", main = "Attendance by Rainfall")

Transform

The attendance variable has a large range, containing both observations below 10,000 and greater than 100,000 in the dataset. As such, for some analysis it might be valuable to transform this variable.

To demonstrated this I chose to use the baseR scale function to convert each observation in the variable to a Z-score, representing the number of standard deviations that the value sits away from the variable mean.

A summary of the new variable (in this case saved as a seperate object, zAttendance), shows that the mean of the variable is now 0, as we would expect following a conversion of this type.

# Transfomring attendance variable to z-scores
zAttendance <- scale(afl$Attendance, center = TRUE, scale = TRUE)

zAttendance %>% summary()
       V1          
 Min.   :-1.94272  
 1st Qu.:-0.79158  
 Median :-0.08648  
 Mean   : 0.00000  
 3rd Qu.: 0.72797  
 Max.   : 2.29240  



LS0tDQp0aXRsZTogIk1BVEgyMzQ5IFNlbWVzdGVyIDEsIDIwMjAiDQphdXRob3I6ICJKb3NodWEgRWxsaW90dCBzMzg1MzIyMCINCnN1YnRpdGxlOiBBc3NpZ25tZW50IDINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdA0KLS0tDQoNCiMjIFJlcXVpcmVkIHBhY2thZ2VzIA0KDQpgYGB7cn0NCiMgVGhpcyBpcyB0aGUgUiBjaHVuayBmb3IgdGhlIHJlcXVpcmVkIHBhY2thZ2VzDQpsaWJyYXJ5KGZpdHpSb3kpDQpsaWJyYXJ5KHJlYWRyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkoZWRpdHJ1bGVzKQ0KYGBgDQoNCiMjIEV4ZWN1dGl2ZSBTdW1tYXJ5IA0KSW4gdGhpcyBhc3NpZ25tZW50IEkgc291Z2h0IHRvIGNvbWJpbmUgZGF0YSBvbiB0aGUgQXVzdHJhbGlhbiBGb290YmFsbCBMZWFndWUgb3IgQUZMIGZyb20gdGhlIHdlYnNpdGUgQUZMIFRhYmxlcyB3aXRoIHJhaW5mYWxsIGRhdGEgZnJvbSB0aGUgQnVyZWF1IG9mIE1ldGVvcm9sb2d5Lg0KDQpTcGVjaWZpY2FsbHksIEkgbmFycm93ZWQgdGhlIGZvY3VzIHRvIEFGTCBtYXRjaGVzIHBsYXllZCBhdCB0aGUgTUNHIHNpbmNlIHJhaW5mYWxsIGRhdGEgZnJvbSB0aGUgQk9NJ3MgT2x5bXBpYyBQYXJrIHdlYXRoZXIgc3RhdGlvbiwgbmVhciB0aGUgTUNHLCBiZWNhbWUgYXZhaWxhYmxlIG9uIEp1bmUgMiAyMDEzLCB0aHJvdWdoIHRvIHRoZSBjb25jbHVzaW9uIG9mIHRoZSAyMDE5IEFGTCBzZWFzb24uDQoNCkkgY29tYmluZWQgdGhlc2UgdHdvIGRhdGFzZXRzIGJhc2VkIG9uIHRoZSBkYXRlIHZhcmlhYmxlLCB3aGljaCBpcyBwcmVzZW50IGluIGJvdGggdGhlIEFGTCBkYXRhIGFuZCB0aGUgQk9NIHJhaW5mYWxsIGRhdGEuDQoNCkkgY29udmVydGVkIHNvbWUgdmFyaWFibGVzIGluIHRoZSByZXN1bHRpbmcgZGF0YXNldCB0byBmYWN0b3IgdHlwZSBhcyBhcHByb3ByaWF0ZSBhbmQgY3JlYXRlZCBuZXcgdmFyaWFibGVzIHJlY29yZGluZyB0aGUgYWNjdXJhY3kgYW5kIHRvdGFsIHNjb3JlIG9mIHRoZSByZWxldmFudCBBRkwgbWF0Y2hlcy4NCg0KSSBhbHNvIGNyZWF0ZWQgYSBzZWNvbmQgZGF0YXNldCBvbiB0aGUgdW1waXJpbmcgb2YgQUZMIG1hdGNoZXMuIFRoaXMgZGF0YSBhcnJpdmVkIGluIGFuIHVudGlkeSBmb3JtYXQgYW5kIGl0IHdhcyBuZWNlc3NhcnkgdG8gdGlkeSBpdCBmb3IgdGhpcyBwdXJwb3NlLg0KDQpCb3RoIGRhdGFzZXRzIHdlcmUgY2hlY2tlZCBmb3IgbWlzc2luZyBhbmQgc3BlY2lhbCB2YWx1ZXMsIGltcG9zc2libGUgdmFsdWVzIG9yIG9idmlvdXMgZXJyb3JzLCBhbmQgb3V0bGllcnMuIE5vIHNpZ25pZmljYW50IGlzc3VlcyB3ZXJlIHVuY292ZXJlZC4NCg0KVGhpcyByZXBvcnQgYWxzbyBjb250YWlucyBhIGRlbW9uc3RyYXRpb24gb2YgaG93IHRoZSAnQXR0ZW5kYW5jZScgdmFyaWFibGUgY291bGQgYmUgcmUtc2NhbGVkIGZvciBhbmFseXNpcy4NCg0KIyMgRGF0YSANCkRhdGEgd2FzIG9idGFpbmVkIGZyb20gdHdvIHNlcGVyYXRlIHNvdXJjZXM6IEFGTCBUYWJsZXMsIGFuZCB0aGUgQnVyZWF1IG9mIE1ldGVvcm9sb2d5Lg0KDQpBRkwgVGFibGVzIGRhdGEgaXMgYmVzdCBvYnRhaW5lZCB0aHJvdWdoIHVzZSBvZiB0aGUgZml0elJveSBwYWNrYWdlJ3MgZ2V0X2FmbHRhYmxlc19zdGF0cyBmdW5jdGlvbi4gSSBzcGVjaWZpZWQgdGhlIHVwcGVyIGFuZCBsb3dlciBkYXRlIGxpbWl0cyBmb3IgZGF0YSBjb2xsZWN0aW9uLg0KDQpUaGlzIHByb2R1Y2VzIHRoZSBmb2xsb3dpbmcgdmFyaWFibGVzOiANCg0KLSBTZWFzb24gLSBUaGUgQUZMIHNlYXNvbiB0aGUgbWF0Y2ggd2FzIHBsYXllZCBpbg0KLSBSb3VuZCAtIFRoZSByb3VuZCBvZiB0aGUgc2Vhc29uIHRoZSBtYXRjaCB3YXMgcGxheWVkIGluDQotIERhdGUgLSBUaGUgZGF0ZSB0aGUgbWF0Y2ggd2FzIHBsYXllZCBvbg0KLSBMb2NhbC5zdGFydC50aW1lIC0gVGhlIHRpbWUgdGhlIG1hdGNoIHdhcyBwbGF5ZWQsIGFzIHBlciBsb2NhbCB0aW1lIHpvbmUNCi0gVmVudWUgLSBUaGUgbG9jYXRpb24gdGhlIG1hdGNoIHdhcyBwbGF5ZWQNCi0gQXR0ZW5kYW5jZSAtIFRoZSByZWNvcmRlZCBjcm93ZCBhdCB0aGUgbWF0Y2gNCi0gSG9tZS50ZWFtIC0gdGhlIEFGTCBzaWRlIGxpc3RlZCBhcyB0aGUgaG9tZSBzaWRlIGZvciB0aGUgbWF0Y2gNCi0gSFExRyAtIFRoZSBudW1iZXIgb2YgZ29hbHMga2lja2VkIGJ5IHRoZSBob21lIHNpZGUgYXQgdGhlIGVuZCBvZiB0aGUgZmlyc3QgcXVhcnRlcg0KLSBIUTFCIC0gVGhlIG51bWJlciBvZiBiZWhpbmRzIGtpY2tlZCBieSB0aGUgaG9tZSBzaWRlIGF0IHRoZSBlbmQgb2YgdGhlIGZpcnN0IHF1YXJ0ZXINCi0gSFEyRyAtIFRoZSBudW1iZXIgb2YgZ29hbHMga2lja2VkIGJ5IHRoZSBob21lIHNpZGUgYXQgdGhlIGVuZCBvZiB0aGUgc2Vjb25kIHF1YXJ0ZXINCi0gSFEyQiAtIFRoZSBudW1iZXIgb2YgYmVoaW5kcyBraWNrZWQgYnkgdGhlIGhvbWUgc2lkZSBhdCB0aGUgZW5kIG9mIHRoZSBzZWNvbmQgcXVhcnRlcg0KLSBIUTNHIC0gVGhlIG51bWJlciBvZiBnb2FscyBraWNrZWQgYnkgdGhlIGhvbWUgc2lkZSBhdCB0aGUgZW5kIG9mIHRoZSB0aGlyZCBxdWFydGVyDQotIEhRM0IgLSBUaGUgbnVtYmVyIG9mIGJlaGluZHMga2lja2VkIGJ5IHRoZSBob21lIHNpZGUgYXQgdGhlIGVuZCBvZiB0aGUgdGhpcmQgcXVhcnRlcg0KLSBIUTRHIC0gVGhlIG51bWJlciBvZiBnb2Fsc3Mga2lja2VkIGJ5IHRoZSBob21lIHNpZGUgYXQgdGhlIGVuZCBvZiB0aGUgZm91cnRoIHF1YXJ0ZXINCi0gSFE0QiAtIFRoZSBudW1iZXIgb2YgYmVoaW5kcyBraWNrZWQgYnkgdGhlIGhvbWUgc2lkZSBhdCB0aGUgZW5kIG9mIHRoZSBmb3VydGggcXVhcnRlcg0KLSBIb21lLnNjb3JlIC0gVGhlIHRvdGFsIHNjb3JlIG9mIHRoZSBob21lIHNpZGUgYXQgdGhlIGVuZCBvZiB0aGUgbWF0Y2gNCi0gQXdheS50ZWFtIC0gVGhlIEFGTCBzaWRlIGxpc3RlZCBhcyB0aGUgYXdheSBzaWRlIGZvciB0aGUgbWF0Y2gNCi0gSFExRyAtIFRoZSBudW1iZXIgb2YgZ29hbHMga2lja2VkIGJ5IHRoZSBhd2F5IHNpZGUgYXQgdGhlIGVuZCBvZiB0aGUgZmlyc3QgcXVhcnRlcg0KLSBIUTFCIC0gVGhlIG51bWJlciBvZiBiZWhpbmRzIGtpY2tlZCBieSB0aGUgYXdheSBzaWRlIGF0IHRoZSBlbmQgb2YgdGhlIGZpcnN0IHF1YXJ0ZXINCi0gSFEyRyAtIFRoZSBudW1iZXIgb2YgZ29hbHMga2lja2VkIGJ5IHRoZSBhd2F5IHNpZGUgYXQgdGhlIGVuZCBvZiB0aGUgc2Vjb25kIHF1YXJ0ZXINCi0gSFEyQiAtIFRoZSBudW1iZXIgb2YgYmVoaW5kcyBraWNrZWQgYnkgdGhlIGF3YXkgc2lkZSBhdCB0aGUgZW5kIG9mIHRoZSBzZWNvbmQgcXVhcnRlcg0KLSBIUTNHIC0gVGhlIG51bWJlciBvZiBnb2FscyBraWNrZWQgYnkgdGhlIGF3YXkgc2lkZSBhdCB0aGUgZW5kIG9mIHRoZSB0aGlyZCBxdWFydGVyDQotIEhRM0IgLSBUaGUgbnVtYmVyIG9mIGJlaGluZHMga2lja2VkIGJ5IHRoZSBhd2F5IHNpZGUgYXQgdGhlIGVuZCBvZiB0aGUgdGhpcmQgcXVhcnRlcg0KLSBIUTRHIC0gVGhlIG51bWJlciBvZiBnb2Fsc3Mga2lja2VkIGJ5IHRoZSBhd2F5IHNpZGUgYXQgdGhlIGVuZCBvZiB0aGUgZm91cnRoIHF1YXJ0ZXINCi0gSFE0QiAtIFRoZSBudW1iZXIgb2YgYmVoaW5kcyBraWNrZWQgYnkgdGhlIGF3YXkgc2lkZSBhdCB0aGUgZW5kIG9mIHRoZSBmb3VydGggcXVhcnRlcg0KLSBBd2F5LnNjb3JlIC0gVGhlIHRvdGFsIHNjb3JlIG9mIHRoZSBhd2F5IHNpZGUgYXQgdGhlIGVuZCBvZiB0aGUgbWF0Y2gNCi0gRmlyc3QubmFtZSAtIFRoZSBmaXJzdCBuYW1lIG9mIHRoZSBwbGF5ZXINCi0gU3VybmFtZSAtIFRoZSBzdXJuYW1lIG9mIHRoZSBwbGF5ZXINCi0gSUQgLSBBIHVuaXF1ZSBpZGVudGlmaWVyIGZvciBlYWNoIHBsYXllcg0KLSBKdW1wZXIuTm8uIC0gVGhlIG51bWJlciB3b3JuIGJ5IHRoZSBwbGF5ZXINCi0gUGxheWluZy5mb3IgLSBUaGUgQUZMIGNsdWIgdGhlIHBsYXllciByZXByZXNlbnRzDQotIEtpY2tzIC0gVGhlIG51bWJlciBvZiBraWNrcyByZWNvcmRlZCBieSB0aGUgcGxheWVyDQotIE1hcmtzIC0gVGhlIG51bWJlciBvZiBtYXJrcyByZWNvcmRlZCBieSB0aGUgcGxheWVyDQotIEhhbmRiYWxscyAtIFRoZSBudW1iZXIgb2YgaGFuZGJhbGxzIHJlY29yZGVkIGJ5IHRoZSBwbGF5ZXINCi0gR29hbHMgLSBUaGUgbnVtYmVyIG9mIGdvYWxzIHJlY29yZGVkIGJ5IHRoZSBwbGF5ZXINCi0gQmVoaW5kcyAtIFRoZSBudW1iZXIgb2YgYmVoaW5kcyByZWNvcmRlZCBieSB0aGUgcGxheWVyDQotIEhpdC5vdXRzIC0gVGhlIG51bWJlciBvZiBoaXQgb3V0cyByZWNvcmRlZCBieSB0aGUgcGxheWVyDQotIFRhY2tsZXMgLSBUaGUgbnVtYmVyIG9mIHRhY2tsZXMgcmVjb3JkZWQgYnkgdGhlIHBsYXllcg0KLSBSZWJvdW5kcyAtIFRoZSBudW1iZXIgb2YgcmVib3VuZHMgcmVjb3JkZWQgYnkgdGhlIHBsYXllcg0KLSBJbnNpZGUuNTBzIC0gVGhlIG51bWJlciBvZiBpbnNpZGUgNTBzIHJlY29yZGVkIGJ5IHRoZSBwbGF5ZXINCi0gQ2xlYXJhbmNlcyAtIFRoZSBudW1iZXIgb2YgY2xlYXJhbmNlcyByZWNvcmRlZCBieSB0aGUgcGxheWVyDQotIENsYW5nZXJzIC0gVGhlIG51bWJlciBvZiBjbGFuZ2VycyByZWNvcmRlZCBieSB0aGUgcGxheWVyDQotIEZyZWVzLkZvciAtIFRoZSBudW1iZXIgb2YgZnJlZSBraWNrcyBmb3IgcmVjb3JkZWQgYnkgdGhlIHBsYXllcg0KLSBGcmVlLkFnYWluc3QgLSBUaGUgbnVtYmVyIG9mIGZyZWUga2lja3MgYWdhaW5zdCByZWNvcmRlZCBieSB0aGUgcGxheWVyDQotIEJyb3dubG93LlZvdGVzIC0gVGhlIG51bWJlciBvZiBCcm93bmxvdyBWb3RlcyByZWNvcmRlZCBieSB0aGUgcGxheWVyDQotIENvbnRlc3RlZC5Qb3NzZXNzaW9ucyAtIFRoZSBudW1iZXIgb2YgY29udGVzdGVkIHBvc3Nlc3Npb25zIHJlY29yZGVkIGJ5IHRoZSBwbGF5ZXINCi0gVW5jb250ZXN0ZWQuUG9zc2Vzc2lvbnMgLSBUaGUgbnVtYmVyIG9mIHVuY29udGVzdGVkIHBvc3Nlc3Npb25zIHJlY29yZGVkIGJ5IHRoZSBwbGF5ZXINCi0gQ29udGVzdGVkLk1hcmtzIC0gVGhlIG51bWJlciBvZiBjb250ZXN0ZWQgbWFya3MgcmVjb3JkZWQgYnkgdGhlIHBsYXllcg0KLSBNYXJrcy5JbnNpZGUuNTAgLSBUaGUgbnVtYmVyIG9mIG1hcmtzIGluc2lkZSA1MCByZWNvcmRlZCBieSB0aGUgcGxheWVyDQotIE9uZS5QZXJjZW50ZXJzIC0gVGhlIG51bWJlciBvZiBvbmUtcGVyY2VudGVycyByZWNvcmRlZCBieSB0aGUgcGxheWVyDQotIEJvdW5jZXMgLSBUaGUgbnVtYmVyIG9mIGJvdW5jZXMgcmVjb3JkZWQgYnkgdGhlIHBsYXllcg0KLSBHb2FsLkFzc2lzdHMgLSBUaGUgbnVtYmVyIG9mIGdvYWwgYXNzaXN0cyByZWNvcmRlZCBieSB0aGUgcGxheWVyDQotIFRpbWUub24uR3JvdW5kIC0gVGhlIHBlcmNlbnRhZ2Ugb2YgbWF0Y2ggdGltZSB0aGUgcGxheWVyIHNwZW50IG9uIGdyb3VuZA0KLSBTdWJzdGl0dXRlIC0gV2hldGhlciBvciBub3QgdGhlIHBsYXllciB3YXMgaW52b2x2ZWQgaW4gYSBzdWJzdGl0dXRpb24NCi0gVW1waXJlLjEgLSBUaGUgZmlyc3QgdW1waXJlIGFzc2lnbmVkIHRvIHRoZSBtYXRjaCwgcmFua2VkIGFscGhhYmV0aWNhbGx5IGJ5IHN1cm5hbWUNCi0gVW1waXJlLjIgLSBUaGUgc2Vjb25kIHVtcGlyZSBhc3NpZ25lZCB0byB0aGUgbWF0Y2gsIHJhbmtlZCBhbHBoYWJldGljYWxseSBieSBzdXJuYW1lDQotIFVtcGlyZS4zIC0gVGhlIHRoaXJkIHVtcGlyZSBhc3NpZ25lZCB0byB0aGUgbWF0Y2gsIHJhbmtlZCBhbHBoYWJldGljYWxseSBieSBzdXJuYW1lDQotIFVtcGlyZS40IC0gVGhlIGZvdXJ0aCB1bXBpcmUgYXNzaWduZWQgdG8gdGhlIG1hdGNoLCByYW5rZWQgYWxwaGFiZXRpY2FsbHkgYnkgc3VybmFtZQ0KLSBncm91cF9pZCAtIEEgdW5pcXVlIGlkZW50aWZpZXIgZm9yIGVhY2ggcG9zc2libGUgY29tYmluYXRpb24gb2YgdW1waXJlcw0KDQpTb21lIG9mIHRoZXNlIHZhcmlhYmxlcyBhcmUgcGxheWVyLXNwZWNpZmljIGFuZCB1bmlxdWUgb24gZWFjaCBsaW5lLCBhbmQgc2FtZSBhcmUgbWF0Y2gtc3BlY2lmaWMgYW5kIHJlcGVhdGVkIGZvciBlYWNoIGluc3RhbmNlIG9mIGEgcGxheWVyIGluIHRoYXQgbWF0Y2guIFNpbmNlIEkgd2lzaGVkIHRvIHVzZSBtYXRjaCBkYXRhIG9ubHksIEkgdXNlZCB0aGUgZHBseXIgc2VsZWN0IGZ1bmN0aW9uIHRvIHNlbGVjdCBvbmx5IG1hdGNoIGRhdGEsIGFuZCB0aGVuIHVzZWQgdGhlIGRpc3RpbmN0IGZ1bmN0aW9uIHRvIHJlbW92ZSB0aGUgcmVkdW5kYW50IG9ic2VydmF0aW9ucy4NCg0KSSB0aGVuIGZpbHRlcmVkIHRoZSBkYXRhIHRvIG9ubHkgaW5jbHVkZSBtYXRjaGVzIHBsYXllZCBhdCB0aGUgTUNHLg0KDQpCT00gZGF0YSBjYW4gYmUgZG93bmxvYWRlZCBkaXJlY3RseSBmcm9tIHRoZSBCT00gd2Vic2l0ZSwgd2hlcmUgaXQgY29tZXMgYXMgYSBjc3YuIEkgcmVhZCBpdCBpbnRvIFIgdXNpbmcgcmVhZHIncyByZWFkX2NzdiBmdW5jdGlvbi4NCg0KVGhpcyBkYXRhIGhhcyB0aGUgZm9sbG93aW5nIHZhcmlhYmxlczoNCg0KLSBQcm9kdWN0IGNvZGUgLSBBIGxhYmVsIGZvciB0aGUgZGF0YXNldA0KLSBCdXJlYXUgb2YgTWV0ZW9yb2xvZ3kgc3RhdGlvbiBudW1iZXIgLSBBIHVuaXF1ZSBpZGVudGlmaWVyIGZvciBpbmRpdmlkdWFsIHdlYXRoZXIgc3RhdGlvbnMNCi0gWWVhciAtIFRoZSB5ZWFyIHRoZSBkYXRhIHdhcyByZWNvcmRlZCBpbg0KLSBNb250aCAtIFRoZSBtb250aCB0aGUgZGF0YSB3YXMgcmVjb3JkZWQgaW4NCi0gRGF5IC0gVGhlIGRheSB0aGUgZGF0YSB3YXMgcmVjb3JkZWQgb24NCi0gUmFpbmZhbGwgYW1vdW50IChtaWxsaW1ldHJlcykgLSBUaGUgYW1vdW50IG9mIHJhaW5mYWxsIG1lYXN1cmVkLCBpbiBtaWxsaW1ldHJlcw0KLSBQZXJpb2Qgb3ZlciB3aGljaCByYWluZmFsbCB3YXMgbWVhc3VyZWQgKGRheXMpIC0gVGhlIGxlbmd0aCwgaW4gZGF5cywgb2YgdGhlIHBlcmlvZCB0aGUgZGF0YSByZXByZXNlbnRzDQotIFF1YWxpdHkgLSBBbiBjYXRlZ29yaXNhdGlvbiBvZiB0aGUgcXVhbGl0eSBvZiB0aGUgbWVhc3VyZW1lbnQNCg0KQWx0aG91Z2ggZGF0YSBjb2xsZWN0aW9uIGF0IHRoZSBzaXRlIG9ubHkgYmVnYW4gb24gSnVuZSAyLCAyMDEzLCB0aGlzIGRhdGFzZXQgY29udGFpbnMgb2JzZXJ2YXRpb25zIGZvciBhbGwgZGF5cyBpbiAyMDEzLiBBcyBzdWNoLCBJIHVzZWQgdGhlIGNvbXBsZXRlIGNhc2VzIGZ1bmN0aW9uIHRvIHJlbW92ZSBvYnNlcnZhdGlvbnMgd2l0aCBlbXB0eSB2YWx1ZXMgZnJvbSB0aGUgZGF0YXNldC4NCg0KSSByZW5hbWVkIHRoZSB2YXJpYWJsZXMgaW4gdGhpcyBkYXRhc2V0IGZvciBlYXNlIG9mIHVzZSwgYW5kIHRoZW4gY3JlYXRlZCBhIG5ldyB2YXJpYWJsZSB1c2luZyB0aGUgZHBseXIgYW5kIGx1YnJpZGF0ZSBwYWNrYWdlcyB0byBjb21iaW5lIHRoZSBZZWFyLCBNb250aCBhbmQgRGF5IHZhcmlhYmxlcyBpbnRvIGEgc2luZ2xlIGRhdGUgdmFyaWFibGUuDQoNClRoaXMgd2FzIG5lY2Vzc2FyeSBpbiBvcmRlciB0byBjb21iaW5lIHRoZSB3ZWF0aGVyIGRhdGEgd2l0aCB0aGUgQUZMIGRhdGEsIHdoaWNoIGFsc28gY29udGFpbnMgYSBEYXRlIHZhcmlhYmxlLiBJIHN1YnNldHRlZCB0aGUgd2VhdGhlciBkYXRhIGRvd24gdG8gdHdvIHZhcmlhYmxlcyAtIERhdGUgYW5kIFJhaW5mYWxsIC0gYW5kIHRoZW4gdXNlZCB0aGUgZHBseXIgbGVmdF9qb2luIGZ1bmN0aW9uIHRvIGFkZCB0aGUgcmFpbmZhbGwgZGF0YSB0byB0aGUgYWZsIGRhdGFzZXQuIA0KDQpUaGUgdXNlIG9mIGxlZnRfam9pbiBpbnN1cmVzIHRoYXQgb25seSB3ZWF0aGVyIGRhdGEgb2JzZXJ2YXRpb25zIHdpdGggYSBtYXRjaGluZyBkYXRlIGFyZSBicm91Z2h0IGludG8gdGhlIEFGTCBkYXRhc2V0IC0gaW5uZXJfam9pbiB3b3VsZCBhbHNvIGhhdmUgYmVlbiBhcHByb3ByaWF0ZS4gDQoNCmBgYHtyLCByZXN1bHRzPSdoaWRlJ30NCiMgTG9hZGluZyBBRkwgZGF0YQ0KYWZsIDwtIGdldF9hZmx0YWJsZXNfc3RhdHMoc3RhcnRfZGF0ZSA9ICcyMDEzLTA2LTAyJywgZW5kX2RhdGUgPSAnMjAyMC0wMS0wMScpDQpgYGANCmBgYHtyfQ0KDQpoZWFkKGFmbCkNCg0KIyBDbGVhbmluZyBBRkwgZGF0YQ0KYWZsIDwtIGFmbCAlPiUgc2VsZWN0KFNlYXNvbjpIb21lLnRlYW0sIEhRNEc6QXdheS50ZWFtLCBBUTRHOkF3YXkuc2NvcmUsIFVtcGlyZS4xOlVtcGlyZS40KQ0KYWZsIDwtIGFmbCAlPiUgZGlzdGluY3QoKQ0KYWZsIDwtIGFmbCAlPiUgZmlsdGVyKFZlbnVlID09ICdNLkMuRy4nKQ0KDQojIExvYWRpbmcgd2VhdGhlciBkYXRhDQp3ZWF0aGVyIDwtIHJlYWRfY3N2KCd3ZWF0aGVyLmNzdicpDQoNCmhlYWQod2VhdGhlcikNCg0KIyBDbGVhbmluZyB3ZWF0aGVyIGRhdGENCndlYXRoZXIgPC0gd2VhdGhlcltjb21wbGV0ZS5jYXNlcyh3ZWF0aGVyKSwgXQ0KY29sbmFtZXMod2VhdGhlcikgPC0gYygnUHJvZHVjdENvZGUnLCAnU3RhdGlvbicsICdZZWFyJywgJ01vbnRoJywgJ0RheScsICdSYWluZmFsbCcsICdQZXJpb2QnLCAnUXVhbGl0eScpDQp3ZWF0aGVyIDwtIHdlYXRoZXIgJT4lIG11dGF0ZShEYXRlID0gbWFrZV9kYXRlKFllYXIsIE1vbnRoLCBEYXkpKQ0Kd2VhdGhlciA8LSB3ZWF0aGVyICU+JSBzZWxlY3QoRGF0ZSwgUmFpbmZhbGwpDQoNCiMgSm9pbmluZyBkYXRhc2V0cw0KYWZsIDwtIGFmbCAlPiUgbGVmdF9qb2luKHdlYXRoZXIsIGJ5ID0gIkRhdGUiKQ0KDQpoZWFkKGFmbCkNCmBgYA0KDQojIyBVbmRlcnN0YW5kIA0KSSB1c2VkIHRoZSBzdHIgZnVuY3Rpb24gdG8gbG9vayBhdCB0aGUgc3RydWN0dXJlIG9mIHRoZSBjb21iaW5lZCBBRkwgZGF0YXNldC4gDQoNCkkgaWRlbnRpZmllZCBmaXZlIHZhcmlhYmxlcyBpbiBuZWVkIG9mIGNvbnZlcnNpb24gdG8gZmFjdG9yIHR5cGUgLSBTZWFzb24sIFJvdW5kLCBWZW51ZSwgSG9tZS50ZWFtIGFuZCBBd2F5LnRlYW0uIA0KDQpJIHBhc3NlZCB0aGVzZSB2YXJpYWJsZXMgaW50byB0aGUgdGFibGUgZnVuY3Rpb24gdG8gY2hlY2sgZm9yIHRoZSBwb3NzaWJpbGl0eSBvZiB0eXBvcyBpbiB0aGUgdmFsdWVzIHdoaWNoIG1pZ2h0IG5lZWQgdG8gYmUgY29ycmVjdGVkIGJlZm9yZSBjb252ZXJ0aW5nIHRoZSBkYXRhdHlwZSwgb3IgTkEgdmFsdWVzLiBUaGVyZSB3ZXJlIG5vIGluc3RhbmNlcyBwcmVzZW50IGZvciBlaXRoZXIgb2YgdGhlc2UgcG9zc2libGUgaXNzdWVzLg0KDQpJIGNvbnZlcnRlZCB0aGVzZSB2YXJpYWJsZXMgdG8gZmFjdG9yIHR5cGUuIEZvciB0aGUgUm91bmQgdmFyaWFibGUsIEkgZGVmaW5lZCBhIHNwZWNpZmljIHZlY3RvciBvZiBsYWJlbHMsIGFzIHRoaXMgdmFyaWFibGUgY29udGFpbnMgYSBtaXggb2YgbnVtZXJpYyBhbmQgYWxwaGFiZXRpYyBkYXRhLCBhbmQgd291bGQgbm90IGJlIGFwcHJvcHJpYXRlbHkgb3JkZXJlZCBieSBzdGFuZGFyZCBhbHBoYWJldGljIG9yZGVyLiBIb3dldmVyIGFzIHRoZXNlIHJvdW5kcyBhcmUgbm90IG51bWVyaWNhbGx5ICJncmVhdGVyIiB0aGFuIGVhY2ggb3RoZXIgSSBkaWQgbm90IHNldCBPcmRlcmVkID0gVFJVRS4NCg0KQSBzZWNvbmQgY2hlY2sgb2YgdGhlIHN0cnVjdHVyZSBvZiB0aGUgZGF0YXNldCBzaG93cyB0aGUgc3VjY2Vzc2Z1bCBkYXRhdHlwZSBjb252ZXJzaW9ucy4gQWxsIG90aGVyIHZhcmlhYmxlcyBpbiB0aGlzIGRhdGFzZXQgaGF2ZSBhbiBhcHByb3ByaWF0ZSBkYXRhdHlwZS4NCg0KYGBge3J9DQojIENoZWNraW5nIGRhdGEgc3RydWN0dXJlDQpzdHIoYWZsKQ0KDQojIENoZWNraW5nIGZvciB0eXBvcyBhbmQgTkEgdmFsdWVzDQphZmwkU2Vhc29uICU+JSB0YWJsZSh1c2VOQSA9ICJpZmFueSIpDQphZmwkUm91bmQgJT4lIHRhYmxlKHVzZU5BID0gImlmYW55IikNCmFmbCRWZW51ZSAlPiUgdGFibGUodXNlTkEgPSAiaWZhbnkiKQ0KYWZsJEhvbWUudGVhbSAlPiUgdGFibGUodXNlTkEgPSAiaWZhbnkiKQ0KYWZsJEF3YXkudGVhbSAlPiUgdGFibGUodXNlTkEgPSAiaWZhbnkiKQ0KDQojIENvbnZlcnRpbmcgdmFyaWFibGVzIHRvIGZhY3RvciB0eXBlDQphZmwkU2Vhc29uIDwtIGFzLmZhY3RvcihhZmwkU2Vhc29uKQ0KYWZsJFJvdW5kIDwtIGZhY3RvcihhZmwkUm91bmQsIGxldmVscyA9IGMoIjEiLCAiMiIsICIzIiwgIjQiLCAiNSIsICI2IiwgIjciLCAiOCIsICI5IiwgIjEwIiwgIjExIiwgIjEyIiwgIjEzIiwgIjE0IiwgIjE1IiwgIjE2IiwgIjE3IiwgIjE4IiwgIjE5IiwgIjIwIiwgIjIxIiwgIjIyIiwgIjIzIiwgIlFGIiwgIkVGIiwgIlNGIiwgIlBGIiwgIkdGIikpDQphZmwkVmVudWUgPC0gYXMuZmFjdG9yKGFmbCRWZW51ZSkNCmFmbCRIb21lLnRlYW0gPC0gYXMuZmFjdG9yKGFmbCRIb21lLnRlYW0pDQphZmwkQXdheS50ZWFtIDwtIGFzLmZhY3RvcihhZmwkQXdheS50ZWFtKQ0KDQojIENvbmZpcmltaW5nIHN1Y2Nlc3NmdWwgY29udmVyc2lvbnMNCnN0cihhZmwpDQpgYGANCg0KIyMJVGlkeSAmIE1hbmlwdWxhdGUgRGF0YSBJIA0KSW4gdGhpcyBkYXRhc2V0LCB0aGVyZSBhcmUgZm91ciB2YXJpYWJsZXMgZGVkaWNhdGVkIHRvIHJlY29yZGluZyB0aGUgdW1waXJlcyB3aG8gb2ZmaWNpYXRlZCB0aGUgcmVsZXZhbnQgQUZMIG1hdGNoIC0gVW1waXJlLjEsIFVtcGlyZS4yLCBVbXBpcmUuMyBhbmQgVW1waXJlLjQuIEVhY2ggbWF0Y2ggaGFzIGF0IGxlYXN0IHRocmVlIHVtcGlyZXMgYW5kIHNvbWUgbWF0Y2hlcyBoYXZlIGEgZm91dGggdW1waXJlLg0KDQpJbiBBRkwgbWF0Y2hlcywgdGhlcmUgaXMgbm8gZGlzdGluY3Rpb24gbWFkZSBiZXR3ZWVuIGEgImZpcnN0IiBvciAic2Vjb25kIiB1bXBpcmUgLSB0aGUgbnVtYmVyaW5nIGhlcmUgaXMgdXNlZCBvbmx5IHRvIGtlZXAgYWxsIHVtcGlyZSBpbmZvcm1hdGlvbiBjb250YWluZWQgdG8gYSBzaW5nbGUgcm93LiBUaGlzIGlzIHVudGlkeSBhcyB0aGVyZSBhcmUgZm91ciBjb2x1bW5zIHVzZWQgdG8gcmVjb3JkIGEgc2luZ2xlIHZhcmlhYmxlLg0KDQpUbyB0aWR5IHRoaXMgZGF0YSwgSSBkZWNpZGVkIHRvIHNwbGl0IGl0IG9mZiBpbnRvIGEgc2VwZXJhdGUgZGF0YXNldCwgdW1waXJlcy4gVGhpcyB3YXMgZG9uZSB1c2luZyB0aGUgZHBseXIgc2VsZWN0IGZ1bmN0aW9uLiBJIHRoZW4gdXNlZCB0aGUgdGlkeXIgZ2F0aGVyIGZ1bmN0aW9uIHRvIGNvbnZlcnQgdGhlIGRhdGEgdG8gbG9uZyBmb3JtYXQsIGNyZWF0aW5nIGEgcm93IGZvciBlYWNoIGluZGl2aXVkYWwgdW1waXJlLiANCg0KVGhpcyBpcyBjb21iaW5lZCB3aXRoIGluZm9ybWF0aW9uIG9uIHRoZSBtYXRjaCB0aGV5IHVtcGlyZWQgLSBpbiBhIHJlbGF0aW9uYWwgZGF0YWJhc2UsIHRoaXMgaW5mb21yYXRpb24gY291bGQgYmUgY29uZGVuc2VkIGRvd24gdG8gYSBzaW5nbGUgdW5pcXVlIGluZGVudGlmaWVyIGZvciBlYWNoIG1hdGNoIHdoaWNoIHdvdWxkIGJlIHNoYXJlZCB3aXRoIHRoZSBvcmlnaW5hbCBkYXRhc2V0Lg0KDQpJIHJlbW92ZWQgdGhlIGtleSB2YXJpYWJsZSBjcmVhdGVkIGJ5IHRoZSBnYXRoZXIgZnVuY3Rpb24gYXMgdGhpcyBwcm92aWRlcyBubyB1c2VmdWwgaW5mb3JtYXRpb24uIEkgdXNlZCBjb21wbGV0ZV9jYXNlcyB0byByZW1vdmUgb2JzZXJ2YXRpb25zIHdoZXJlIHRoZXJlIHdhcyBubyB2YWx1ZSBpbiB0aGUgdW1waXJlIHZhcmlhYmxlIChkdWUgdG8gbWFueSBvYnNlcnZhdGlvbnMgb2YgVW1waXJlLjQgYmVpbmcgYmxhbmspLg0KDQpXaXRoIHRoaXMgZGF0YSBzdWNjZXNzZnVsbHkgdGlkaWVkIGluIGEgc2VwZXJhdGUgZGF0YXNldCwgSSByZW1vdmVkIGl0IGZyb20gdGhlIG1haW4gQUZMIGRhdGFzZXQuDQoNCmBgYHtyfQ0KIyBTdWJzZXR0aW5nIHVtcGlyZSBkYXRhDQp1bXBpcmVzIDwtIGFmbCAlPiUgc2VsZWN0KFNlYXNvbjpEYXRlLCBWZW51ZSwgSG9tZS50ZWFtLCBBd2F5LnRlYW0sIFVtcGlyZS4xOlVtcGlyZS40KQ0KDQojIENvbnZlcnRpbmcgdG8gbG9uZyBmb3JtYXQNCnVtcGlyZXMgPC0gdW1waXJlcyAlPiUgZ2F0aGVyKGBVbXBpcmUuMWAsIGBVbXBpcmUuMmAsIGBVbXBpcmUuM2AsIGBVbXBpcmUuNGAsIGtleSA9ICdObycsIHZhbHVlID0gJ1VtcGlyZScpDQoNCiMgUmVtb3ZpbmcgdW5uZWNlc3Nhcnkga2V5IHZhcmlhYmxlDQp1bXBpcmVzIDwtIHVtcGlyZXMgJT4lIHNlbGVjdChTZWFzb246QXdheS50ZWFtLCBVbXBpcmUpDQoNCiMgUmVtb3ZpbmcgaW5jb21wbGV0ZSBvYnNlcnZhdGlvbnMNCnVtcGlyZXMgPC0gdW1waXJlc1tjb21wbGV0ZS5jYXNlcyh1bXBpcmVzKSwgXQ0KDQpoZWFkKHVtcGlyZXMpDQoNCiMgUmVtb3ZpbmcgdW1waXJlIGRhdGEgZnJvbSBvcmlnaW5hbCBkYXRhc2V0DQphZmwgPC0gYWZsICU+JSBzZWxlY3QoU2Vhc29uOkF3YXkuc2NvcmUsIFJhaW5mYWxsKQ0KDQpoZWFkKGFmbCkNCmBgYA0KDQojIwlUaWR5ICYgTWFuaXB1bGF0ZSBEYXRhIElJIA0KSW4gYW4gZWFybGllciBzdGVwIHRoZSBkcGx5ciBtdXRhdGUgZnVuY3Rpb24gd2FzIGNvbWJpbmVkIHdpdGggdGhlIGx1YnJpZGF0ZSBtYWtlX2RhdGUgZnVuY3Rpb24gdG8gY3JlYXRlIGFuIGFkZGl0aW9uYWwgdmFyaWFibGUuIEhvd2V2ZXIsIHRoZXJlIGFyZSBvdGhlciBwb3NzaWJsZSBpbnN0YW5jZXMgd2hlcmUgdGhpcyB3b3VsZCBiZSBhIHJlbGV2YW50IHRhc2sgaW4gdGhpcyBkYXRhc2V0Lg0KDQpJIHVzZWQgbXV0YXRlIHRvIGNyZWF0ZSBhIG5ldyB2YXJpYWJsZSBpbiB0aGUgQUZMIGRhdGFzZXQgY2FsbGVkIFRvdGFsLnNjb3JlLCB3aGljaCBjb21iaW5lcyB0aGUgZXhpc3RpbmcgdmFyaWFibGVzIEhvbWUuc2NvcmUgYW5kIEF3YXkuc2NvcmUsIHRodXMgdHJhY2tpbmcgdGhlIGNvbWJpbmVkIG51bWJlciBvZiBwb2ludHMgc2NvcmVkIGluIGEgbWF0Y2guDQoNCkkgYWxzbyBjcmVhdGVkIGFuIGFkZGl0aW9uYWwgdmFyaWFibGUgY2FsbGVkIEFjY3VyYWN5LiBUaGlzIHJlY29yZHMgd2hhdCBwcm9wb3Rpb24gb2YgdGhlIGNvbWJpbmVkIHRvdGFsIG9mIHNjb3Jpbmcgc2hvdHMgZnJvbSB0aGUgbWF0Y2ggKHRoZSBjb21iaW5lZCB0b3RhbCBvZiBIUTRHLCBBUTRHLCBIUTRCLCBhbmQgQVE0Qikgd2VyZSBnb2FscyAodGhlIGNvbWJpbmVkIHRvdGFsIG9mIEhRNEcgYW5kIEFRNEcpLg0KDQpgYGB7cn0NCiMgQWRkaW5nIFRvdGFsLnNjb3JlIHZhcmlhYmxlDQphZmwgPC0gYWZsICU+JSBtdXRhdGUoVG90YWwuc2NvcmUgPSBIb21lLnNjb3JlK0F3YXkuc2NvcmUpDQoNCiMgQWRkaW5nIEFjY3VyYWN5IHZhcmlhYmxlDQphZmwgPC0gYWZsICU+JSBtdXRhdGUoQWNjdXJhY3kgPSAoSFE0RytBUTRHKS8oSFE0RytBUTRHK0hRNEIrQVE0QikpDQoNCmhlYWQoYWZsKQ0KYGBgDQoNCiMjCVNjYW4gSSANCkkgcHV0IHRoZSB0d28gZGF0YXNldHMsIEFGTCBhbmQgVW1waXJlcywgdGhyb3VnaCB0aGUgaXMubmEsIGlzLmluZmluaXRlIGFuZCBpcy5uYW4gZnVuY3Rpb25zIHRvIGNoZWNrIGZvciB0aGUgcHJlc2VuY2Ugb2YgbWlzc2luZyBvciBzcGVjaWFsIHZhbHVlcy4gTmVpdGhlciBpcyBwcmVzZW50IGluIGFueSBvZiB0aGUgdmFyaWFibGVzIGluIHRoZXNlIHR3byBkYXRhc2V0cy4NCg0KSSB1c2VkIHRoZSBlZGl0cnVsZXMgcGFja2FnZSB0byBkZWZpbmUgc29tZSBydWxlcyB0byBjaGVjayB0aGUgdmFyaWFibGVzIGZvciBvYnZpb3VzIGVycm9ycy4gVGhlc2UgcnVsZXMgd2VyZTogY2hlY2tpbmcgdGhhdCB0aGUgTG9jYWwuc3RhcnQudGltZSBmb3IgZWFjaCBtYXRjaCB3YXMgYmV0d2VlbiBub29uIGFuZCAxMHBtLCBjaGVja2luZyB0aGF0IHRoZSBjcm93ZCBhdCBhIG1hdGNoIHdhcyBub3QgYSBuZWdhdGl2ZSB2YWx1ZSBub3IgYW4gaW1wb3NzaWJseSBoaWdoIGFtb3VudCwgY2hlY2tpbmcgdGhhdCB0aGUgaG9tZSBhbmQgYXdheSBzY29yZXMgcmVmbGVjdGVkIHRoZSBleHBlY3RlZCB0b3RhbCBvZiBzaXggcG9pbnRzIHBlciBnb2FsIGFuZCBvbmUgcG9pbnQgcGVyIGJlaGluZCBhbmQgdGhhdCBuZWl0aGVyIHdhcyBncmVhdGVyIHRoYW4gYW4gaW1wb3NzaWJseSBoaWdoIHZhbHVlLCBhbmQgY2hlY2tpbmcgdGhhdCByYWluZmFsbCB3YXMgbmV2ZXIgbmVnYXRpdmUgbm9yIGFib3ZlIGFuIGltcG9zc2libHkgaGlnaCB2YWx1ZS4NCg0KSSB0aGVuIHVzZWQgdGhlIHZpb2xhdGVkRWRpdHMgZnVuY3Rpb24gdG8gY2hlY2sgaWYgYW55IG9ic2VydmF0aW9ucyBicmVha2VkIHRoZXNlIHNldCBydWxlcy4gVGhlcmUgd2VyZSBubyBpbnN0YW5jZXMgb2YgYnJva2VuIHJ1bGVzLg0KDQpgYGB7cn0NCiMgQ2hlY2tpbmcgZm9yIG1pc3NpbmcgdmFsdWVzDQphZmwgJT4lIGlzLm5hKCkgJT4lIHN1bSgpDQp1bXBpcmVzICU+JSBpcy5uYSgpICU+JSBzdW0oKQ0KDQojIENoZWNraW5nIGZvciBzcGVjaWFsIHZhbHVlcw0KYWZsICU+JSBzYXBwbHkoaXMuaW5maW5pdGUpICU+JSBzdW0oKQ0KdW1waXJlcyAlPiUgc2FwcGx5KGlzLmluZmluaXRlKSAlPiUgc3VtKCkNCmFmbCAlPiUgc2FwcGx5KGlzLm5hbikgJT4lIHN1bSgpDQp1bXBpcmVzICU+JSBzYXBwbHkoaXMubmFuKSAlPiUgc3VtKCkNCg0KIyBEZWZpbmluZyB2YXJpYWJsZXMgcnVsZXMNClRpbWVSdWxlIDwtIGVkaXRzZXQoYygiTG9jYWwuc3RhcnQudGltZSA+PSAxMjAwIiwgIkxvY2FsLnN0YXJ0LnRpbWUgPD0gMjIwMCIpKQ0KQ3Jvd2RSdWxlIDwtIGVkaXRzZXQoYygiQXR0ZW5kYW5jZSA+PSAwIiwgIkF0dGVuZGFuY2UgPD0gMTUwMDAwIikpDQpTY29yZVJ1bGUgPC0gZWRpdHNldChjKCJIb21lLnNjb3JlID09IEhRNEcgKiA2ICsgSFE0QiIsICJBd2F5LnNjb3JlID09IEFRNEcgKiA2ICsgQVE0QiIsICJIb21lLnNjb3JlIDw9IDMwMCIsICJBd2F5LnNjb3JlIDw9IDMwMCIpKQ0KUmFpblJ1bGUgPC0gZWRpdHNldChjKCJSYWluZmFsbCA+PSAwIiwgIlJhaW5mYWxsIDw9IDEwMDAiKSkNClJ1bGVzIDwtIChjKFRpbWVSdWxlLCBDcm93ZFJ1bGUsIFNjb3JlUnVsZSwgUmFpblJ1bGUpKQ0KDQojIENoZWNraW5nIGZvciBicm9rZW4gcnVsZXMNCnZpb2xhdGVkRWRpdHMoUnVsZXMsIGFmbCkgJT4lIHN1bSgpDQpgYGANCg0KIyMJU2NhbiBJSQ0KVG8gY2hlY2sgdGhlIG51bWVyaWNhbCB2YXJpYWJsZXMgZm9yIG91dGxpZXJzLCBJIGNyZWF0ZWQgYSBzZXJpZXMgb2YgYm94cGxvdHMgZm9yIGVhY2ggbnVtZXJpY2FsIHZhbHVlLg0KDQpUaGUgSFE0RywgSFE0QiwgQVE0RywgQVE0QiwgSG9tZS5zY29yZSwgQXdheS5zY29yZSBhbmQgQWNjdXJhY3kgdmFyaWFibGVzIGFsbCByZXBvcnRlZCBiZXR3ZWVuIDEtMyBvdXRsaWVycywgYWxsIGF0IHRoZSBoaWdoIGVuZCBvZiB0aGUgYm94cGxvdC4gDQoNCkkgY2hlY2tlZCB0aGUgaGlnaGVzdCB2YWx1ZXMgaW4gdGhlc2UgdmFyaWFibGVzIGFnYWluc3QgYW4gaW5kZXBlbmRlbnQgcmVjb3JkIG9mIHRoZSBkYXRhIHRvIGVuc3VyZSB0aGV5IHdlcmUgbm90IGluY29ycmVjdCB2YWx1ZXMsIHdoaWNoIEkgY2FuIGNvbmZpcm0gdGhleSBhcmUgbm90LiBBcyBzdWNoLCBJIGRlY2lkZWQgdG8ga2VlcCB0aGVtIGFzIHRoZXkgYXJlIGluIHRoZSBkYXRhc2V0Lg0KDQpUaGUgUmFpbmZhbGwgZGF0YSBoYXMgYSBsYXJnZSBudW1iZXIgb2Ygb3V0bGllcnMuIFRoaXMgaXMgZHVlIHRvIHRoaXMgZGF0YSBiZWluZyBoZWF2aWx5IHJpZ2h0IHNrZXdlZCAtIHRoZSBtYWpvcml0eSBvZiBvYnNlcnZhdGlvbnMgb2YgdGhpcyB2YXJpYWJsZSBhcmUgMC4wLCBhbmQgYXMgc3VjaCBtYW55IG9ic2VydmF0aW9ucyBhcmUgY29uc2lkZXJlZCBvdXRsaWVycy4gDQoNClRoaXMgaXMgcHJpbWFyaWx5IGFuIGlsbHVzdHJhdGlvbiBvZiB0aGUgc2tld2VkbmVzcyBvZiB0aGlzIGRhdGFzZXQsIGFzIHN1Y2gsIEkgZGVjaWRlZCB0byByZXRhaW4gdGhlIHZhbHVlcyBhcyB0aGV5IGFyZS4NCg0KSSBhbHNvIGNoZWNrZWQgdGhyZWUgbGlrZWx5IHJlbGF0aW9uc2hpcHMgb2YgaW50ZXJlc3QgZm9yIGJpdmFyaWF0ZSBvdXRsaWVycywgY3JlYXRpbmcgc2NhdHRlciBwbG90cyB0aGF0IGVhY2ggdXNlIFJhaW5mYWxsIG9uIHRoZSB4IGF4aXMgYW5kIHVzZSBBY2N1cmFjeSwgVG90YWwuc2NvcmUgYW5kIEF0dGVuZGFuY2Ugb24gdGhlIHRocmVlIHkgYXhlcyByZXNwZWN0aXZlbHkuDQoNClRoZXNlIHBsb3RzIGFsc28gc2hvdyBob3cgdGhlIHZhc3QgbWFqb3JpdHkgb2YgcmFpbmZhbGwgZGF0YSBpcyBhdCBvciBuZWFyIGEgemVybyB2YWx1ZS4gVGhlcmUgZG8gbm90IGFwcGVhciB0byBiZSBhbnkgYml2YXJpYXRlIG91dGxpZXJzIChvciBjb3JyZWxhdGlvbikgb24gdGhlIEFjY3VyYWN5IG9yIFRvdGFsLnNjb3JlIHBsb3RzLiANCg0KVGhlIGF0dGVuZGFuY2UgdmFyaWFibGUgZG9lcyBzaG93IG1vcmUgZXZpZGVuY2Ugb2YgYSBwb3NzaWJsZSByZWxhdGlvbnNoaXAgYW5kIHNvbWUgcG90ZW50aWFsIG91dGxpZXJzLCBidXQgdGhlIGRhdGEgZm9yIGhpZ2ggdmFsdWVzIG9mIHJhaW5mYWxsIGlzIHRvbyBzcGFyc2UgdG8gYmUgY29uZmlkZW50IHRoYXQgdGhpcyBpcyB0aGUgY2FzZS4NCg0KYGBge3J9DQojIENoZWNraW5nIHNpbmdsZSB2YXJpYWJsZXMgZm9yIG91dGxpZXJzDQphZmwkQXR0ZW5kYW5jZSAlPiUgYm94cGxvdChtYWluPSJCb3ggUGxvdCBvZiBNQ0cgQ3Jvd2RzIiwgeWxhYj0iQ3Jvd2QiKQ0KYWZsJEhRNEcgJT4lIGJveHBsb3QobWFpbj0iQm94IFBsb3Qgb2YgSFE0RyIsIHlsYWI9IkhRNEciKQ0KYWZsJEhRNEIgJT4lIGJveHBsb3QobWFpbj0iQm94IFBsb3Qgb2YgSFE0QiIsIHlsYWI9IkhRNEIiKQ0KYWZsJEFRNEcgJT4lIGJveHBsb3QobWFpbj0iQm94IFBsb3Qgb2YgQVE0RyIsIHlsYWI9IkFRNEciKQ0KYWZsJEFRNEIgJT4lIGJveHBsb3QobWFpbj0iQm94IFBsb3Qgb2YgQVE0QiIsIHlsYWI9IkFRNEIiKQ0KYWZsJEhvbWUuc2NvcmUgJT4lIGJveHBsb3QobWFpbj0iQm94IFBsb3Qgb2YgSG9tZSBTY29yZSIsIHlsYWI9IkhvbWUgU2NvcmUiKQ0KYWZsJEF3YXkuc2NvcmUgJT4lIGJveHBsb3QobWFpbj0iQm94IFBsb3Qgb2YgQXdheSBTY29yZSIsIHlsYWI9IkF3YXkgU2NvcmUiKQ0KYWZsJFRvdGFsLnNjb3JlICU+JSBib3hwbG90KG1haW49IkJveCBQbG90IG9mIFRvdGFsIFNjb3JlIiwgeWxhYj0iVG90YWwgU2NvcmUiKQ0KYWZsJFJhaW5mYWxsICU+JSBib3hwbG90KG1haW49IkJveCBQbG90IG9mIFJhaW5mYWxsIiwgeWxhYj0iUmFpbmZhbGwiKQ0KYWZsJEFjY3VyYWN5ICU+JSBib3hwbG90KG1haW49IkJveCBQbG90IG9mIEFjY3VyYWN5IiwgeWxhYj0iQWNjdXJhY3kiKQ0KDQojQ2hlY2tpbmcgZm9yIGJpdmFyaWF0ZSBvdXRsaWVycw0KYWZsICU+JSBwbG90KEFjY3VyYWN5IH4gUmFpbmZhbGwsIGRhdGEgPS4sIHlsYWIgPSAiQWNjdXJhY3kiLCB4bGFiID0gIlJhaW5mYWxsIiwgbWFpbiA9ICJBY2N1cmFjeSBieSBSYWluZmFsbCIpDQphZmwgJT4lIHBsb3QoVG90YWwuc2NvcmUgfiBSYWluZmFsbCwgZGF0YSA9LiwgeWxhYiA9ICJUb3RhbCBTY29yZSIsIHhsYWIgPSAiUmFpbmZhbGwiLCBtYWluID0gIlRvdGFsIFNjb3JlIGJ5IFJhaW5mYWxsIikNCmFmbCAlPiUgcGxvdChBdHRlbmRhbmNlIH4gUmFpbmZhbGwsIGRhdGEgPS4sIHlsYWIgPSAiQXR0ZW5kYW5jZSIsIHhsYWIgPSAiUmFpbmZhbGwiLCBtYWluID0gIkF0dGVuZGFuY2UgYnkgUmFpbmZhbGwiKQ0KYGBgDQoNCiMjCVRyYW5zZm9ybSANClRoZSBhdHRlbmRhbmNlIHZhcmlhYmxlIGhhcyBhIGxhcmdlIHJhbmdlLCBjb250YWluaW5nIGJvdGggb2JzZXJ2YXRpb25zIGJlbG93IDEwLDAwMCBhbmQgZ3JlYXRlciB0aGFuIDEwMCwwMDAgaW4gdGhlIGRhdGFzZXQuIEFzIHN1Y2gsIGZvciBzb21lIGFuYWx5c2lzIGl0IG1pZ2h0IGJlIHZhbHVhYmxlIHRvIHRyYW5zZm9ybSB0aGlzIHZhcmlhYmxlLg0KDQpUbyBkZW1vbnN0cmF0ZWQgdGhpcyBJIGNob3NlIHRvIHVzZSB0aGUgYmFzZVIgc2NhbGUgZnVuY3Rpb24gdG8gY29udmVydCBlYWNoIG9ic2VydmF0aW9uIGluIHRoZSB2YXJpYWJsZSB0byBhIFotc2NvcmUsIHJlcHJlc2VudGluZyB0aGUgbnVtYmVyIG9mIHN0YW5kYXJkIGRldmlhdGlvbnMgdGhhdCB0aGUgdmFsdWUgc2l0cyBhd2F5IGZyb20gdGhlIHZhcmlhYmxlIG1lYW4uDQoNCkEgc3VtbWFyeSBvZiB0aGUgbmV3IHZhcmlhYmxlIChpbiB0aGlzIGNhc2Ugc2F2ZWQgYXMgYSBzZXBlcmF0ZSBvYmplY3QsIHpBdHRlbmRhbmNlKSwgc2hvd3MgdGhhdCB0aGUgbWVhbiBvZiB0aGUgdmFyaWFibGUgaXMgbm93IDAsIGFzIHdlIHdvdWxkIGV4cGVjdCBmb2xsb3dpbmcgYSBjb252ZXJzaW9uIG9mIHRoaXMgdHlwZS4NCg0KYGBge3J9DQojIFRyYW5zZm9tcmluZyBhdHRlbmRhbmNlIHZhcmlhYmxlIHRvIHotc2NvcmVzDQp6QXR0ZW5kYW5jZSA8LSBzY2FsZShhZmwkQXR0ZW5kYW5jZSwgY2VudGVyID0gVFJVRSwgc2NhbGUgPSBUUlVFKQ0KDQp6QXR0ZW5kYW5jZSAlPiUgc3VtbWFyeSgpDQoNCmBgYA0KDQo8YnI+DQo8YnI+DQo=