Required packages

library(readr) 
library(readxl)
library(foreign)
library(gdata)
library(dplyr)
library(tidyr)
library(ggplot2)
library(knitr)

Executive Summary

Data preprocessing is a vital aspect of readying any data for further analysis. Here, two data sets with data on the Olympic Games were used to demonstrate the steps of data wrangling. The first step was to locate suitable data and read it into R. Next, the data had to be understood by checking for variable type and structure. Then, it was tidied and manipulated via gathering and separating of columns to ready the two data sets for merging. After merging, the data set was scanned for missing values and outliers, as well manipulated further in the form of mutating columns. Lastly, some variables were transformed to reduce skewness. Now, the data is ready for exploration and analysis.

Data

The first data set looks at various data from all previous Summer Olympic Games. The URL is https://www.sportsvizsunday.com/olympics-winter-olympics, taken from the Sports Viz Sundays website. It includes multiple excel sheets on world record times, host cities, all-time medals by country, and sport history. The particular data set explored in this assignment is about Host Cities of Summer Olympics. There are 12 variables, listed below:

This data set was read into R using readxl package:

games <- read_xlsx("Olympics.xlsx", sheet = "Host Cities of Summer Olympics")
print.data.frame(head(games))
  Games Year                     Host                        Opened by                 Dates Nations Competitors: Total Competitors: Men
1     I 1896           Athens, Greece                    King George I            6–15 April      14                241              241
2    II 1900            Paris, France                              N/A   14 May – 28 October      24                997              975
3   III 1904 St. Louis, United States Former Governor David R. Francis  1 July – 23 November      12                651              645
4    IV 1908   London, United Kingdom                  King Edward VII 27 April – 31 October      22               2008             1971
5     V 1912        Stockholm, Sweden                    King Gustaf V             6–22 July      28               2407             2359
6    VI 1916          Berlin, Germany                             <NA>                  <NA>      NA                 NA               NA
  Competitors: Women Sports Events                                           Notes
1                  0      9     43                                            <NA>
2                 22     19     85                                            <NA>
3                  6     16     94                                            <NA>
4                 37     22    110                                            <NA>
5                 48     14    102                                            <NA>
6                 NA     NA     NA Awarded to Berlin, cancelled due to World War I

Irrelevant variables, Opened by, Dates, and Notes were immediately dropped as they will not be needed for any of the upcoming pre-processing.

#Drop irrelevant variables
games1 <- games[-c(4,5,12)]

The second data set looks at the out-turn of sports-related costs of each Summer and Winter Olympic Games. The data set was found on data.world and is taken from a 2016 Oxford Olympics study. The URL is https://data.world/sports/olympics. The 7 variables are as follows:

This data set was read into R using Readr package:

costs <- read_csv("outturn sports-related costs of the Olympic Games .csv")
Parsed with column specification:
cols(
  Games = col_character(),
  Year = col_double(),
  Country = col_character(),
  Type = col_character(),
  Events = col_double(),
  Athletes = col_double(),
  `Cost, Billion USD` = col_character()
)
print.data.frame(head(costs))
        Games Year      Country   Type Events Athletes Cost, Billion USD
1        Rome 1960        Italy Summer    150     5338               n/a
2       Tokyo 1964        Japan Summer    163     5152             0.282
3 Mexico City 1968       Mexico Summer    172     5516             n/a**
4      Munich 1972      Germany Summer    195     7234             1.009
5    Montreal 1976       Canada Summer    198     6048             6.093
6      Moscow 1980 Soviet Union Summer    203     5179             6.331

Understand I

Names of some columns were changed with dplyr (Kassambara n.d.) to simplify further pre-processing steps:

# changing column names in games data set
games1 <- games1 %>% rename(
  Number = Games,
  Male = `Competitors: Men`,
  Female = `Competitors: Women`,
  'Total Competitors' = `Competitors: Total`
)

# changing column names in costs data set
costs <- costs %>% rename(
  City = Games,
  'Cost in Billions (USD)' = `Cost, Billion USD`
)

Tidy & Manipulate Data I

The tidy data principles that each observation forms a row, each variable forms a column, and each value has its own cell (Wickham, 2014) are violated in the games data set, making it untidy. Firstly, the variable about number of competitors is split into men and women columns. Secondly, the host column has two variables in it: city and country.

# Tidy competitor columns so gender forms one column and number of competitors forms another
games2 <- games1 %>% gather('Male', 'Female', key = "Gender", value = "No. of Competitors") 

# Tidy host column to separate into city and country
games3 <- games2 %>% separate_('Host', into = c("City", "Country"), sep = ",")

# Rearrange columns
colnames(games3)
 [1] "Number"             "Year"               "City"               "Country"            "Nations"            "Total Competitors" 
 [7] "Sports"             "Events"             "Gender"             "No. of Competitors"
games3 <- games3[,c(1,2,3,4,5,9,10,6,7,8)]
colnames(games3) 
 [1] "Number"             "Year"               "City"               "Country"            "Nations"            "Gender"            
 [7] "No. of Competitors" "Total Competitors"  "Sports"             "Events"            

The costs data set is already in a tidy format, so does not need any reshaping.

Understand II

The structure of games data set was checked as shown below and data type conversions made:

# Check structure of games3
str(games3)
tibble [68 x 10] (S3: tbl_df/tbl/data.frame)
 $ Number            : chr [1:68] "I" "II" "III" "IV" ...
 $ Year              : num [1:68] 1896 1900 1904 1908 1912 ...
 $ City              : chr [1:68] "Athens" "Paris" "St. Louis" "London" ...
 $ Country           : chr [1:68] " Greece" " France" " United States" " United Kingdom" ...
 $ Nations           : num [1:68] 14 24 12 22 28 NA 29 44 46 37 ...
 $ Gender            : chr [1:68] "Male" "Male" "Male" "Male" ...
 $ No. of Competitors: num [1:68] 241 975 645 1971 2359 ...
 $ Total Competitors : num [1:68] 241 997 651 2008 2407 ...
 $ Sports            : num [1:68] 9 19 16 22 14 NA 22 17 14 14 ...
 $ Events            : num [1:68] 43 85 94 110 102 NA 156 126 109 117 ...
# Convert Gender to factor variable
games3$Gender <- games3$Gender %>% factor(levels = c("Male", "Female"))
class(games3$Gender)
[1] "factor"
levels(games3$Gender)
[1] "Male"   "Female"
# Convert Year to character variable
games3$Year<- as.character(games3$Year)
class(games3$Year)
[1] "character"
# Arranged by Year
games3 %>% arrange(Year)

The structure of costs data set was checked as shown below and data type conversions made:

# Check structure of costs
str(costs)
tibble [30 x 7] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
 $ City                  : chr [1:30] "Rome" "Tokyo" "Mexico City" "Munich" ...
 $ Year                  : num [1:30] 1960 1964 1968 1972 1976 ...
 $ Country               : chr [1:30] "Italy" "Japan" "Mexico" "Germany" ...
 $ Type                  : chr [1:30] "Summer" "Summer" "Summer" "Summer" ...
 $ Events                : num [1:30] 150 163 172 195 198 203 221 237 257 271 ...
 $ Athletes              : num [1:30] 5338 5152 5516 7234 6048 ...
 $ Cost in Billions (USD): chr [1:30] "n/a" "0.282" "n/a**" "1.009" ...
 - attr(*, "spec")=
  .. cols(
  ..   Games = col_character(),
  ..   Year = col_double(),
  ..   Country = col_character(),
  ..   Type = col_character(),
  ..   Events = col_double(),
  ..   Athletes = col_double(),
  ..   `Cost, Billion USD` = col_character()
  .. )
# Convert Year to character variable
costs$Year<- as.character(costs$Year)
class(costs$Year)
[1] "character"
# Convert Type to factor variable
costs$Type <- costs$Type %>% factor(levels = c("Summer", "Winter"))
class(costs$Type)
[1] "factor"
levels(costs$Type)
[1] "Summer" "Winter"
# Convert Cost in Billions (USD) to numeric variable
costs$`Cost in Billions (USD)` <- as.double(costs$`Cost in Billions (USD)`)
NAs introduced by coercion
class(costs$`Cost in Billions (USD)`)
[1] "numeric"
str(costs)
tibble [30 x 7] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
 $ City                  : chr [1:30] "Rome" "Tokyo" "Mexico City" "Munich" ...
 $ Year                  : chr [1:30] "1960" "1964" "1968" "1972" ...
 $ Country               : chr [1:30] "Italy" "Japan" "Mexico" "Germany" ...
 $ Type                  : Factor w/ 2 levels "Summer","Winter": 1 1 1 1 1 1 1 1 1 1 ...
 $ Events                : num [1:30] 150 163 172 195 198 203 221 237 257 271 ...
 $ Athletes              : num [1:30] 5338 5152 5516 7234 6048 ...
 $ Cost in Billions (USD): num [1:30] NA 0.282 NA 1.009 6.093 ...
 - attr(*, "spec")=
  .. cols(
  ..   Games = col_character(),
  ..   Year = col_double(),
  ..   Country = col_character(),
  ..   Type = col_character(),
  ..   Events = col_double(),
  ..   Athletes = col_double(),
  ..   `Cost, Billion USD` = col_character()
  .. )

As the games data set only deals with Summer Olympic Games, the costs data set was filtered to only include observations about Summer Olympics:

costs1 <- costs %>% filter(Type == 'Summer')
head(costs1)

Remove Gender and No. of Competitors variables from games data set as they will not be needed

games4 <- games3[-c(6,7)]
games4 <- distinct(games4)
head(games4)

Renamed observation, West Germany, in games data set to match name in costs data set:

games4[20, "Country"] <- "Germany"

Merge Data Sets

The two data sets, games and costs, were merged on the common Year variable using left_join to keep all observations in games and add the matching rows in costs.

olympic <- left_join(games4, costs1, by = "Year")
print.data.frame(head(olympic))
  Number Year    City.x       Country.x Nations Total Competitors Sports Events.x City.y Country.y Type Events.y Athletes
1      I 1896    Athens          Greece      14               241      9       43   <NA>      <NA> <NA>       NA       NA
2     II 1900     Paris          France      24               997     19       85   <NA>      <NA> <NA>       NA       NA
3    III 1904 St. Louis   United States      12               651     16       94   <NA>      <NA> <NA>       NA       NA
4     IV 1908    London  United Kingdom      22              2008     22      110   <NA>      <NA> <NA>       NA       NA
5      V 1912 Stockholm          Sweden      28              2407     14      102   <NA>      <NA> <NA>       NA       NA
6     VI 1916    Berlin         Germany      NA                NA     NA       NA   <NA>      <NA> <NA>       NA       NA
  Cost in Billions (USD)
1                     NA
2                     NA
3                     NA
4                     NA
5                     NA
6                     NA

Scan I

Scanned for missing values in data set per column and row. Then, narrowed search to Cost in Billions (USD) column and removed all observations that are missing a value in this column. This column will be needed for later tasks, so it is important that there is a value here. Lastly, checked that all observation were not missing any values.

# Scanning for missing values per column
colSums(is.na(olympic))
                Number                   Year                 City.x              Country.x                Nations      Total Competitors 
                     0                      0                      2                      2                      6                      6 
                Sports               Events.x                 City.y              Country.y                   Type               Events.y 
                     5                      5                     19                     19                     19                     19 
              Athletes Cost in Billions (USD) 
                    19                     22 
# Scanning for missing values per row
rowSums(is.na(olympic))
 [1]  6  6  6  6  6 10  6  6  6  6  6 10 10  6  6  6  1  0  1  0  0  0  0  1  0  0  0  0  0  0  0  8 12 12
# Searching for observations with a missing cost data
is.na(olympic$`Cost in Billions (USD)`)
 [1]  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE  TRUE FALSE FALSE FALSE
[23] FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE
# Create vector of all rows that are missing a value in the 'Cost in Billions (USD)' column
nocost <- which(is.na(olympic$`Cost in Billions (USD)`))
nocost
 [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 19 24 32 33 34
# Deleting all observations without cost data
olympic1 <- olympic[-nocost,]
print.data.frame(head(olympic1))
  Number Year      City.x      Country.x Nations Total Competitors Sports Events.x      City.y     Country.y   Type Events.y Athletes
1  XVIII 1964       Tokyo          Japan      93              5151     19      163       Tokyo         Japan Summer      163     5152
2     XX 1972      Munich        Germany     121              7134     21      195      Munich       Germany Summer      195     7234
3    XXI 1976    Montreal         Canada      92              6084     21      198    Montreal        Canada Summer      198     6048
4   XXII 1980      Moscow   Soviet Union      80              5179     21      203      Moscow  Soviet Union Summer      203     5179
5  XXIII 1984 Los Angeles  United States     140              6829     21      221 Los Angeles United States Summer      221     6829
6    XXV 1992   Barcelona          Spain     169              9356     25      257   Barcelona         Spain Summer      257     9356
  Cost in Billions (USD)
1                  0.282
2                  1.009
3                  6.093
4                  6.331
5                  0.719
6                  9.687
# Checking for any incomplete rows
complete.cases(olympic1)
 [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE

Of the two merged data sets, one had data for Olympic Games from 1896-2028 and the other had data only from Olympic Games from 1960-2016. Information about costs of running the Olympics is only found in the data set from 1960-2016. Therefore, all observations without values in the ‘Cost in Billions (USD)’ column were deleted as they either don’t have sufficient data on them (1896-1956) or they have not occurred yet (2020-2028). This leaves a data set with no missing values.

Tidy & Manipulate Data II

Two columns, ‘Athletes’ and ‘Total Competitors’, represent the same variable, but have slightly different values for some observations. To combat this, a new column was created with the average of the two aforementioned columns and the previous two columns dropped.

olympic2 <- mutate(olympic1, "Total Athletes" = (Athletes + `Total Competitors`)/2, Athletes = NULL, `Total Competitors` = NULL)
print.data.frame(head(olympic2))
  Number Year      City.x      Country.x Nations Sports Events.x      City.y     Country.y   Type Events.y Cost in Billions (USD)
1  XVIII 1964       Tokyo          Japan      93     19      163       Tokyo         Japan Summer      163                  0.282
2     XX 1972      Munich        Germany     121     21      195      Munich       Germany Summer      195                  1.009
3    XXI 1976    Montreal         Canada      92     21      198    Montreal        Canada Summer      198                  6.093
4   XXII 1980      Moscow   Soviet Union      80     21      203      Moscow  Soviet Union Summer      203                  6.331
5  XXIII 1984 Los Angeles  United States     140     21      221 Los Angeles United States Summer      221                  0.719
6    XXV 1992   Barcelona          Spain     169     25      257   Barcelona         Spain Summer      257                  9.687
  Total Athletes
1         5151.5
2         7184.0
3         6066.0
4         5179.0
5         6829.0
6         9356.0

The Events, City, and Country columns are all duplicated from when the datasets were merged, so the duplicates were removed.

olympic3 <- olympic2[-c(8,9,11)]
head(olympic3)

# Renaming columns to eliminate '.x' in the name
olympic3 <- olympic3 %>% rename(
  City = City.x,
  Country = Country.x,
  Events = Events.x)

The Athlete and Cost in Billions (USD) columns were mutated to created a new column, Cost per Athlete.

olympic4 <- mutate(olympic3, "Cost per Athlete" = `Cost in Billions (USD)` / `Total Athletes`)
print.data.frame(head(olympic4))
  Number Year        City        Country Nations Sports Events   Type Cost in Billions (USD) Total Athletes Cost per Athlete
1  XVIII 1964       Tokyo          Japan      93     19    163 Summer                  0.282         5151.5     5.474134e-05
2     XX 1972      Munich        Germany     121     21    195 Summer                  1.009         7184.0     1.404510e-04
3    XXI 1976    Montreal         Canada      92     21    198 Summer                  6.093         6066.0     1.004451e-03
4   XXII 1980      Moscow   Soviet Union      80     21    203 Summer                  6.331         5179.0     1.222437e-03
5  XXIII 1984 Los Angeles  United States     140     21    221 Summer                  0.719         6829.0     1.052863e-04
6    XXV 1992   Barcelona          Spain     169     25    257 Summer                  9.687         9356.0     1.035378e-03
# Convert units of Cost per Athlete column into millions
olympic4$`Cost per Athlete in Millions (USD)` <- olympic4$`Cost per Athlete`*1000

# Remove original Cost per Athlete column
olympic5 <- olympic4[-11]
print.data.frame(head(olympic5))
  Number Year        City        Country Nations Sports Events   Type Cost in Billions (USD) Total Athletes
1  XVIII 1964       Tokyo          Japan      93     19    163 Summer                  0.282         5151.5
2     XX 1972      Munich        Germany     121     21    195 Summer                  1.009         7184.0
3    XXI 1976    Montreal         Canada      92     21    198 Summer                  6.093         6066.0
4   XXII 1980      Moscow   Soviet Union      80     21    203 Summer                  6.331         5179.0
5  XXIII 1984 Los Angeles  United States     140     21    221 Summer                  0.719         6829.0
6    XXV 1992   Barcelona          Spain     169     25    257 Summer                  9.687         9356.0
  Cost per Athlete in Millions (USD)
1                         0.05474134
2                         0.14045100
3                         1.00445104
4                         1.22243676
5                         0.10528628
6                         1.03537837

Scan II

By viewing the data set, the most obvious location for any outliers would be the ‘Cost in Billions (USD)’ column. A summary of the column shows a difference between median and mean, as well as a maximum value (14.957) quite far outside the Q3 (6.451). Other variables were also checked for outliers. To deal with the outlier in the Cost in Billions (USD) column, the capping method was used to replace the outlier with the 95th percentile value (Dolgun, 2020).

# Summary of cost in billions
summary(olympic5$`Cost in Billions (USD)`)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.282   2.459   4.792   5.213   6.451  14.957 
# Searching for outliers in cost in billions
olympic5$`Cost in Billions (USD)` %>% boxplot(main = "Boxplot of Cost in Billions (USD)", ylab = "Billions (USD)")


# Searching for outliers in cost per athlete
olympic5$`Cost per Athlete in Millions (USD)` %>% boxplot(main = "Boxplot of Cost per Athlete (USD)", ylab = "Millions (USD)")


# Creating function for capping
cap <- function(x){
    quantiles <- quantile( x, c(.05, 0.25, 0.75, .95 ) )
    x[ x < quantiles[2] - 1.5*IQR(x) ] <- quantiles[1]
    x[ x > quantiles[3] + 1.5*IQR(x) ] <- quantiles[4]
    x
}

olympic5$`Cost in Billions (USD)` <- olympic5$`Cost in Billions (USD)` %>% cap()

# Checking that outlier is gone
olympic5$`Cost in Billions (USD)` %>% boxplot(main = "Boxplot of Cost in Billions (USD)", ylab = "Billions (USD)")

Transform

A transformation was applied to the Cost in Billions (USD) column in attempt to normalise it. Several transformation were trialled and the most relevant one was the square root transformation. A histogram was then used to display the transformation.

The Cost per Athlete in Millions (USD) column produced a right-skewed histogram, so a square root transformation was applied to normalise it.

# histogram of Cost in Billions (USD) column
olympic5$`Cost in Billions (USD)`%>% histogram(breaks = 10, main = "Histogram of Cost in Billions (USD)")


# Log e transformation
log(olympic5$`Cost in Billions (USD)`)%>% histogram(breaks = 10)


# Reciprocal square transformation
olympic5$`Cost in Billions (USD)`^(-2)%>% histogram(breaks = 10)


# Square root transformation 
olympic5$`Cost in Billions (USD)`^(1/2)%>% histogram(breaks = 10, main = "Sqaure Root of Cost in Billions (USD)")


# Square transformation
olympic5$`Cost in Billions (USD)`^(2)%>% histogram(breaks = 10)


# Histogram of Cost per Athlete in Millions (USD)
olympic5$`Cost per Athlete in Millions (USD)` %>% histogram(breaks = 10, main = "Histogram of Cost per Athlete in Millions (USD)")


# Square root of Cost per Athlete in Millions (USD)
sqrt(olympic5$`Cost per Athlete in Millions (USD)`) %>% histogram(breaks = 10, main = "Square Root Histogram of Cost per Athlete in Millions (USD)")

References

Dolgun, A 2020 ‘Scan: Outliers’, module notes, MATH2349, RMIT University, viewed 17 October 2020, http://rare-phoenix-161610.appspot.com/secured/Module_06.html#capping_(aka_winsorising)

Kassambara, A n.d.Rename Data Frame Columns in R, Datanovia, viewed 18 October 2020, https://www.datanovia.com/en/lessons/rename-data-frame-columns-in-r/

Wickham, H 2014 ‘Tidy Data,’ Journal of Statistical Software, vol. 59 issue 10.

LS0tDQp0aXRsZTogIk1BVEgyMzQ5IERhdGEgV3JhbmdsaW5nIg0KYXV0aG9yOiAiS2xhcmEgVmlja292IFMzODczMzE1Ig0Kc3VidGl0bGU6IEFzc2lnbm1lbnQgMg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOiBkZWZhdWx0DQogIHBkZl9kb2N1bWVudDogZGVmYXVsdA0KLS0tDQoNCg0KIyMgUmVxdWlyZWQgcGFja2FnZXMgDQoNCg0KYGBge3IgbWVzc2FnZT1GQUxTRX0NCmxpYnJhcnkocmVhZHIpIA0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGZvcmVpZ24pDQpsaWJyYXJ5KGdkYXRhKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGtuaXRyKQ0KYGBgDQoNCiMjIEV4ZWN1dGl2ZSBTdW1tYXJ5IA0KDQpEYXRhIHByZXByb2Nlc3NpbmcgaXMgYSB2aXRhbCBhc3BlY3Qgb2YgcmVhZHlpbmcgYW55IGRhdGEgZm9yIGZ1cnRoZXIgYW5hbHlzaXMuIEhlcmUsIHR3byBkYXRhIHNldHMgd2l0aCBkYXRhIG9uIHRoZSBPbHltcGljIEdhbWVzIHdlcmUgdXNlZCB0byBkZW1vbnN0cmF0ZSB0aGUgc3RlcHMgb2YgZGF0YSB3cmFuZ2xpbmcuIFRoZSBmaXJzdCBzdGVwIHdhcyB0byBsb2NhdGUgc3VpdGFibGUgZGF0YSBhbmQgcmVhZCBpdCBpbnRvIFIuIE5leHQsIHRoZSBkYXRhIGhhZCB0byBiZSB1bmRlcnN0b29kIGJ5IGNoZWNraW5nIGZvciB2YXJpYWJsZSB0eXBlIGFuZCBzdHJ1Y3R1cmUuIFRoZW4sIGl0IHdhcyB0aWRpZWQgYW5kIG1hbmlwdWxhdGVkIHZpYSBnYXRoZXJpbmcgYW5kIHNlcGFyYXRpbmcgb2YgY29sdW1ucyB0byByZWFkeSB0aGUgdHdvIGRhdGEgc2V0cyBmb3IgbWVyZ2luZy4gQWZ0ZXIgbWVyZ2luZywgdGhlIGRhdGEgc2V0IHdhcyBzY2FubmVkIGZvciBtaXNzaW5nIHZhbHVlcyBhbmQgb3V0bGllcnMsIGFzIHdlbGwgbWFuaXB1bGF0ZWQgZnVydGhlciBpbiB0aGUgZm9ybSBvZiBtdXRhdGluZyBjb2x1bW5zLiBMYXN0bHksIHNvbWUgdmFyaWFibGVzIHdlcmUgdHJhbnNmb3JtZWQgdG8gcmVkdWNlIHNrZXduZXNzLiBOb3csIHRoZSBkYXRhIGlzIHJlYWR5IGZvciBleHBsb3JhdGlvbiBhbmQgYW5hbHlzaXMuDQoNCiMjIERhdGEgDQoNClRoZSBmaXJzdCBkYXRhIHNldCBsb29rcyBhdCB2YXJpb3VzIGRhdGEgZnJvbSBhbGwgcHJldmlvdXMgU3VtbWVyIE9seW1waWMgR2FtZXMuIFRoZSBVUkwgaXMgaHR0cHM6Ly93d3cuc3BvcnRzdml6c3VuZGF5LmNvbS9vbHltcGljcy13aW50ZXItb2x5bXBpY3MsIHRha2VuIGZyb20gdGhlIFNwb3J0cyBWaXogU3VuZGF5cyB3ZWJzaXRlLiBJdCBpbmNsdWRlcyBtdWx0aXBsZSBleGNlbCBzaGVldHMgb24gd29ybGQgcmVjb3JkIHRpbWVzLCBob3N0IGNpdGllcywgYWxsLXRpbWUgbWVkYWxzIGJ5IGNvdW50cnksIGFuZCBzcG9ydCBoaXN0b3J5LiBUaGUgcGFydGljdWxhciBkYXRhIHNldCBleHBsb3JlZCBpbiB0aGlzIGFzc2lnbm1lbnQgaXMgYWJvdXQgSG9zdCBDaXRpZXMgb2YgU3VtbWVyIE9seW1waWNzLiBUaGVyZSBhcmUgMTIgdmFyaWFibGVzLCBsaXN0ZWQgYmVsb3c6DQoNCi0gR2FtZXM6IFJvbWFuIG51bWVyYWwgaW5kaWNhdGluZyB0aGUgaXRlcmF0aW9uIG9mIHRoZSBPbHltcGljcy4NCi0gWWVhcjogeWVhciBvZiBvY2N1cnJlbmNlLg0KLSBIb3N0OiBob3N0IGNpdHkgYW5kIGNvdW50cnkuDQotIE9wZW5lZCBieTogcG9saXRpY2FsIGZpZ3VyZSB3aG8gb3BlbmVkIHRoZSBHYW1lcy4gVGhpcyB2YXJpYWJsZSB3aWxsIGJlIGRyb3BwZWQgZHVlIHRvIGlycmVsZXZhbmNlLiAgDQotIERhdGVzOiBzdGFydCBhbmQgZW5kIGRheSBhbmQgbW9udGguIFRoaXMgdmFyaWFibGUgd2lsbCBiZSBkcm9wcGVkIGR1ZSB0byBpcnJlbGV2YW5jZS4NCi0gTmF0aW9uczogbnVtYmVyIG9mIHBhcnRpY2lwYXRpbmcgbmF0aW9ucy4NCi0gQ29tcGV0aXRvcnM6IFRvdGFsOiB0b3RhbCBjb21wZXRpdG9ycy4NCi0gQ29tcGV0aXRvcnM6IE1lbjogbnVtYmVyIG9mIG1hbGUgY29tcGV0aXRvcnMuDQotIENvbXBldGl0b3JzOiBXb21lbjogbnVtYmVyIG9mIGZlbWFsZSBjb21wZXRpdG9ycy4gDQotIFNwb3J0czogbnVtYmVyIG9mIHNwb3J0cy4NCi0gRXZlbnRzOiBudW1iZXIgb2YgaW5kaXZpZHVhbCBldmVudHMuDQotIE5vdGVzOiBhZGRpdGlvbmFsIG5vdGVzLiBUaGlzIHZhcmlhYmxlIHdpbGwgYmUgZHJvcHBlZCBkdWUgdG8gaXJyZWxldmFuY2UuDQoNClRoaXMgZGF0YSBzZXQgd2FzIHJlYWQgaW50byBSIHVzaW5nIHJlYWR4bCBwYWNrYWdlOg0KYGBge3IgaW5jbHVkZT1UUlVFfQ0KZ2FtZXMgPC0gcmVhZF94bHN4KCJPbHltcGljcy54bHN4Iiwgc2hlZXQgPSAiSG9zdCBDaXRpZXMgb2YgU3VtbWVyIE9seW1waWNzIikNCnByaW50LmRhdGEuZnJhbWUoaGVhZChnYW1lcykpDQpgYGANCg0KSXJyZWxldmFudCB2YXJpYWJsZXMsIE9wZW5lZCBieSwgRGF0ZXMsIGFuZCBOb3RlcyB3ZXJlIGltbWVkaWF0ZWx5IGRyb3BwZWQgYXMgdGhleSB3aWxsIG5vdCBiZSBuZWVkZWQgZm9yIGFueSBvZiB0aGUgdXBjb21pbmcgcHJlLXByb2Nlc3NpbmcuDQpgYGB7cn0NCiNEcm9wIGlycmVsZXZhbnQgdmFyaWFibGVzDQpnYW1lczEgPC0gZ2FtZXNbLWMoNCw1LDEyKV0NCmBgYA0KVGhlIHNlY29uZCBkYXRhIHNldCBsb29rcyBhdCB0aGUgb3V0LXR1cm4gb2Ygc3BvcnRzLXJlbGF0ZWQgY29zdHMgb2YgZWFjaCBTdW1tZXIgYW5kIFdpbnRlciBPbHltcGljIEdhbWVzLiBUaGUgZGF0YSBzZXQgd2FzIGZvdW5kIG9uIGRhdGEud29ybGQgYW5kIGlzIHRha2VuIGZyb20gYSAyMDE2IE94Zm9yZCBPbHltcGljcyBzdHVkeS4gVGhlIFVSTCBpcyBodHRwczovL2RhdGEud29ybGQvc3BvcnRzL29seW1waWNzLiBUaGUgNyB2YXJpYWJsZXMgYXJlIGFzIGZvbGxvd3M6DQoNCi0gR2FtZXM6IGhvc3QgY2l0eSANCi0gWWVhcjogeWVhciBvZiBvY2N1cnJlbmNlDQotIENvdW50cnk6IGhvc3QgY291bnRyeQ0KLSBUeXBlOiBzdW1tZXIgb3Igd2ludGVyIE9seW1waWNzDQotIEV2ZW50czogdG90YWwgbnVtYmVyIG9mIGV2ZW50cw0KLSBBdGhsZXRlczogdG90YWwgbnVtYmVyIG9mIGF0aGxldGVzDQotIENvc3QsIEJpbGxpb24gVVNEOiBjb3N0IHRvIHJ1biB0aGUgT2x5bXBpY3MgaW4gVVNEIGJpbGxpb25zDQoNClRoaXMgZGF0YSBzZXQgd2FzIHJlYWQgaW50byBSIHVzaW5nIFJlYWRyIHBhY2thZ2U6DQpgYGB7ciBpbmNsdWRlPVRSVUV9DQpjb3N0cyA8LSByZWFkX2Nzdigib3V0dHVybiBzcG9ydHMtcmVsYXRlZCBjb3N0cyBvZiB0aGUgT2x5bXBpYyBHYW1lcyAuY3N2IikNCnByaW50LmRhdGEuZnJhbWUoaGVhZChjb3N0cykpDQpgYGANCg0KIyMgVW5kZXJzdGFuZCBJDQoNCk5hbWVzIG9mIHNvbWUgY29sdW1ucyB3ZXJlIGNoYW5nZWQgd2l0aCBkcGx5ciAoS2Fzc2FtYmFyYSBuLmQuKSB0byBzaW1wbGlmeSBmdXJ0aGVyIHByZS1wcm9jZXNzaW5nIHN0ZXBzOg0KYGBge3J9DQojIGNoYW5naW5nIGNvbHVtbiBuYW1lcyBpbiBnYW1lcyBkYXRhIHNldA0KZ2FtZXMxIDwtIGdhbWVzMSAlPiUgcmVuYW1lKA0KICBOdW1iZXIgPSBHYW1lcywNCiAgTWFsZSA9IGBDb21wZXRpdG9yczogTWVuYCwNCiAgRmVtYWxlID0gYENvbXBldGl0b3JzOiBXb21lbmAsDQogICdUb3RhbCBDb21wZXRpdG9ycycgPSBgQ29tcGV0aXRvcnM6IFRvdGFsYA0KKQ0KDQojIGNoYW5naW5nIGNvbHVtbiBuYW1lcyBpbiBjb3N0cyBkYXRhIHNldA0KY29zdHMgPC0gY29zdHMgJT4lIHJlbmFtZSgNCiAgQ2l0eSA9IEdhbWVzLA0KICAnQ29zdCBpbiBCaWxsaW9ucyAoVVNEKScgPSBgQ29zdCwgQmlsbGlvbiBVU0RgDQopDQpgYGANCg0KIyMJVGlkeSAmIE1hbmlwdWxhdGUgRGF0YSBJIA0KDQpUaGUgdGlkeSBkYXRhIHByaW5jaXBsZXMgdGhhdCBlYWNoIG9ic2VydmF0aW9uIGZvcm1zIGEgcm93LCBlYWNoIHZhcmlhYmxlIGZvcm1zIGEgY29sdW1uLCBhbmQgZWFjaCB2YWx1ZSBoYXMgaXRzIG93biBjZWxsIChXaWNraGFtLCAyMDE0KSBhcmUgdmlvbGF0ZWQgaW4gdGhlIGdhbWVzIGRhdGEgc2V0LCBtYWtpbmcgaXQgdW50aWR5LiBGaXJzdGx5LCB0aGUgdmFyaWFibGUgYWJvdXQgbnVtYmVyIG9mIGNvbXBldGl0b3JzIGlzIHNwbGl0IGludG8gbWVuIGFuZCB3b21lbiBjb2x1bW5zLiBTZWNvbmRseSwgdGhlIGhvc3QgY29sdW1uIGhhcyB0d28gdmFyaWFibGVzIGluIGl0OiBjaXR5IGFuZCBjb3VudHJ5LiANCmBgYHtyfQ0KIyBUaWR5IGNvbXBldGl0b3IgY29sdW1ucyBzbyBnZW5kZXIgZm9ybXMgb25lIGNvbHVtbiBhbmQgbnVtYmVyIG9mIGNvbXBldGl0b3JzIGZvcm1zIGFub3RoZXINCmdhbWVzMiA8LSBnYW1lczEgJT4lIGdhdGhlcignTWFsZScsICdGZW1hbGUnLCBrZXkgPSAiR2VuZGVyIiwgdmFsdWUgPSAiTm8uIG9mIENvbXBldGl0b3JzIikgDQoNCiMgVGlkeSBob3N0IGNvbHVtbiB0byBzZXBhcmF0ZSBpbnRvIGNpdHkgYW5kIGNvdW50cnkNCmdhbWVzMyA8LSBnYW1lczIgJT4lIHNlcGFyYXRlXygnSG9zdCcsIGludG8gPSBjKCJDaXR5IiwgIkNvdW50cnkiKSwgc2VwID0gIiwiKQ0KDQojIFJlYXJyYW5nZSBjb2x1bW5zDQpjb2xuYW1lcyhnYW1lczMpDQpnYW1lczMgPC0gZ2FtZXMzWyxjKDEsMiwzLDQsNSw5LDEwLDYsNyw4KV0NCmNvbG5hbWVzKGdhbWVzMykgDQpgYGANClRoZSBjb3N0cyBkYXRhIHNldCBpcyBhbHJlYWR5IGluIGEgdGlkeSBmb3JtYXQsIHNvIGRvZXMgbm90IG5lZWQgYW55IHJlc2hhcGluZy4NCg0KIyMJVW5kZXJzdGFuZCBJSSANClRoZSBzdHJ1Y3R1cmUgb2YgZ2FtZXMgZGF0YSBzZXQgd2FzIGNoZWNrZWQgYXMgc2hvd24gYmVsb3cgYW5kIGRhdGEgdHlwZSBjb252ZXJzaW9ucyBtYWRlOg0KYGBge3J9DQojIENoZWNrIHN0cnVjdHVyZSBvZiBnYW1lczMNCnN0cihnYW1lczMpDQoNCiMgQ29udmVydCBHZW5kZXIgdG8gZmFjdG9yIHZhcmlhYmxlDQpnYW1lczMkR2VuZGVyIDwtIGdhbWVzMyRHZW5kZXIgJT4lIGZhY3RvcihsZXZlbHMgPSBjKCJNYWxlIiwgIkZlbWFsZSIpKQ0KY2xhc3MoZ2FtZXMzJEdlbmRlcikNCmxldmVscyhnYW1lczMkR2VuZGVyKQ0KDQojIENvbnZlcnQgWWVhciB0byBjaGFyYWN0ZXIgdmFyaWFibGUNCmdhbWVzMyRZZWFyPC0gYXMuY2hhcmFjdGVyKGdhbWVzMyRZZWFyKQ0KY2xhc3MoZ2FtZXMzJFllYXIpDQoNCiMgQXJyYW5nZWQgYnkgWWVhcg0KZ2FtZXMzICU+JSBhcnJhbmdlKFllYXIpDQpgYGANClRoZSBzdHJ1Y3R1cmUgb2YgY29zdHMgZGF0YSBzZXQgd2FzIGNoZWNrZWQgYXMgc2hvd24gYmVsb3cgYW5kIGRhdGEgdHlwZSBjb252ZXJzaW9ucyBtYWRlOg0KYGBge3J9DQojIENoZWNrIHN0cnVjdHVyZSBvZiBjb3N0cw0Kc3RyKGNvc3RzKQ0KDQojIENvbnZlcnQgWWVhciB0byBjaGFyYWN0ZXIgdmFyaWFibGUNCmNvc3RzJFllYXI8LSBhcy5jaGFyYWN0ZXIoY29zdHMkWWVhcikNCmNsYXNzKGNvc3RzJFllYXIpDQoNCiMgQ29udmVydCBUeXBlIHRvIGZhY3RvciB2YXJpYWJsZQ0KY29zdHMkVHlwZSA8LSBjb3N0cyRUeXBlICU+JSBmYWN0b3IobGV2ZWxzID0gYygiU3VtbWVyIiwgIldpbnRlciIpKQ0KY2xhc3MoY29zdHMkVHlwZSkNCmxldmVscyhjb3N0cyRUeXBlKQ0KDQojIENvbnZlcnQgQ29zdCBpbiBCaWxsaW9ucyAoVVNEKSB0byBudW1lcmljIHZhcmlhYmxlDQpjb3N0cyRgQ29zdCBpbiBCaWxsaW9ucyAoVVNEKWAgPC0gYXMuZG91YmxlKGNvc3RzJGBDb3N0IGluIEJpbGxpb25zIChVU0QpYCkNCmNsYXNzKGNvc3RzJGBDb3N0IGluIEJpbGxpb25zIChVU0QpYCkNCg0Kc3RyKGNvc3RzKQ0KYGBgDQpBcyB0aGUgZ2FtZXMgZGF0YSBzZXQgb25seSBkZWFscyB3aXRoIFN1bW1lciBPbHltcGljIEdhbWVzLCB0aGUgY29zdHMgZGF0YSBzZXQgd2FzIGZpbHRlcmVkIHRvIG9ubHkgaW5jbHVkZSBvYnNlcnZhdGlvbnMgYWJvdXQgU3VtbWVyIE9seW1waWNzOg0KYGBge3IgZWNobz1UUlVFfQ0KY29zdHMxIDwtIGNvc3RzICU+JSBmaWx0ZXIoVHlwZSA9PSAnU3VtbWVyJykNCmhlYWQoY29zdHMxKQ0KYGBgDQpSZW1vdmUgR2VuZGVyIGFuZCBOby4gb2YgQ29tcGV0aXRvcnMgdmFyaWFibGVzIGZyb20gZ2FtZXMgZGF0YSBzZXQgYXMgdGhleSB3aWxsIG5vdCBiZSBuZWVkZWQNCmBgYHtyIGVjaG89VFJVRX0NCmdhbWVzNCA8LSBnYW1lczNbLWMoNiw3KV0NCmdhbWVzNCA8LSBkaXN0aW5jdChnYW1lczQpDQpoZWFkKGdhbWVzNCkNCmBgYA0KUmVuYW1lZCBvYnNlcnZhdGlvbiwgV2VzdCBHZXJtYW55LCBpbiBnYW1lcyBkYXRhIHNldCB0byBtYXRjaCBuYW1lIGluIGNvc3RzIGRhdGEgc2V0Og0KYGBge3J9DQpnYW1lczRbMjAsICJDb3VudHJ5Il0gPC0gIkdlcm1hbnkiDQpgYGANCg0KIyMJTWVyZ2UgRGF0YSBTZXRzDQoNClRoZSB0d28gZGF0YSBzZXRzLCBnYW1lcyBhbmQgY29zdHMsIHdlcmUgbWVyZ2VkIG9uIHRoZSBjb21tb24gWWVhciB2YXJpYWJsZSB1c2luZyBsZWZ0X2pvaW4gdG8ga2VlcCBhbGwgb2JzZXJ2YXRpb25zIGluIGdhbWVzIGFuZCBhZGQgdGhlIG1hdGNoaW5nIHJvd3MgaW4gY29zdHMuDQpgYGB7cn0NCm9seW1waWMgPC0gbGVmdF9qb2luKGdhbWVzNCwgY29zdHMxLCBieSA9ICJZZWFyIikNCnByaW50LmRhdGEuZnJhbWUoaGVhZChvbHltcGljKSkNCmBgYA0KIyMJU2NhbiBJIA0KDQpTY2FubmVkIGZvciBtaXNzaW5nIHZhbHVlcyBpbiBkYXRhIHNldCBwZXIgY29sdW1uIGFuZCByb3cuIFRoZW4sIG5hcnJvd2VkIHNlYXJjaCB0byBDb3N0IGluIEJpbGxpb25zIChVU0QpIGNvbHVtbiBhbmQgcmVtb3ZlZCBhbGwgb2JzZXJ2YXRpb25zIHRoYXQgYXJlIG1pc3NpbmcgYSB2YWx1ZSBpbiB0aGlzIGNvbHVtbi4gVGhpcyBjb2x1bW4gd2lsbCBiZSBuZWVkZWQgZm9yIGxhdGVyIHRhc2tzLCBzbyBpdCBpcyBpbXBvcnRhbnQgdGhhdCB0aGVyZSBpcyBhIHZhbHVlIGhlcmUuIExhc3RseSwgY2hlY2tlZCB0aGF0IGFsbCBvYnNlcnZhdGlvbiB3ZXJlIG5vdCBtaXNzaW5nIGFueSB2YWx1ZXMuDQpgYGB7cn0NCiMgU2Nhbm5pbmcgZm9yIG1pc3NpbmcgdmFsdWVzIHBlciBjb2x1bW4NCmNvbFN1bXMoaXMubmEob2x5bXBpYykpDQoNCiMgU2Nhbm5pbmcgZm9yIG1pc3NpbmcgdmFsdWVzIHBlciByb3cNCnJvd1N1bXMoaXMubmEob2x5bXBpYykpDQoNCiMgU2VhcmNoaW5nIGZvciBvYnNlcnZhdGlvbnMgd2l0aCBhIG1pc3NpbmcgY29zdCBkYXRhDQppcy5uYShvbHltcGljJGBDb3N0IGluIEJpbGxpb25zIChVU0QpYCkNCg0KIyBDcmVhdGUgdmVjdG9yIG9mIGFsbCByb3dzIHRoYXQgYXJlIG1pc3NpbmcgYSB2YWx1ZSBpbiB0aGUgJ0Nvc3QgaW4gQmlsbGlvbnMgKFVTRCknIGNvbHVtbg0Kbm9jb3N0IDwtIHdoaWNoKGlzLm5hKG9seW1waWMkYENvc3QgaW4gQmlsbGlvbnMgKFVTRClgKSkNCm5vY29zdA0KDQojIERlbGV0aW5nIGFsbCBvYnNlcnZhdGlvbnMgd2l0aG91dCBjb3N0IGRhdGENCm9seW1waWMxIDwtIG9seW1waWNbLW5vY29zdCxdDQpwcmludC5kYXRhLmZyYW1lKGhlYWQob2x5bXBpYzEpKQ0KDQojIENoZWNraW5nIGZvciBhbnkgaW5jb21wbGV0ZSByb3dzDQpjb21wbGV0ZS5jYXNlcyhvbHltcGljMSkNCmBgYA0KT2YgdGhlIHR3byBtZXJnZWQgZGF0YSBzZXRzLCBvbmUgaGFkIGRhdGEgZm9yIE9seW1waWMgR2FtZXMgZnJvbSAxODk2LTIwMjggYW5kIHRoZSBvdGhlciBoYWQgZGF0YSBvbmx5IGZyb20gT2x5bXBpYyBHYW1lcyBmcm9tIDE5NjAtMjAxNi4gSW5mb3JtYXRpb24gYWJvdXQgY29zdHMgb2YgcnVubmluZyB0aGUgT2x5bXBpY3MgaXMgb25seSBmb3VuZCBpbiB0aGUgZGF0YSBzZXQgZnJvbSAxOTYwLTIwMTYuIFRoZXJlZm9yZSwgYWxsIG9ic2VydmF0aW9ucyB3aXRob3V0IHZhbHVlcyBpbiB0aGUgJ0Nvc3QgaW4gQmlsbGlvbnMgKFVTRCknIGNvbHVtbiB3ZXJlIGRlbGV0ZWQgYXMgdGhleSBlaXRoZXIgZG9uJ3QgaGF2ZSBzdWZmaWNpZW50IGRhdGEgb24gdGhlbSAoMTg5Ni0xOTU2KSBvciB0aGV5IGhhdmUgbm90IG9jY3VycmVkIHlldCAoMjAyMC0yMDI4KS4gVGhpcyBsZWF2ZXMgYSBkYXRhIHNldCB3aXRoIG5vIG1pc3NpbmcgdmFsdWVzLg0KDQojIwlUaWR5ICYgTWFuaXB1bGF0ZSBEYXRhIElJIA0KDQpUd28gY29sdW1ucywgJ0F0aGxldGVzJyBhbmQgJ1RvdGFsIENvbXBldGl0b3JzJywgcmVwcmVzZW50IHRoZSBzYW1lIHZhcmlhYmxlLCBidXQgaGF2ZSBzbGlnaHRseSBkaWZmZXJlbnQgdmFsdWVzIGZvciBzb21lIG9ic2VydmF0aW9ucy4gVG8gY29tYmF0IHRoaXMsIGEgbmV3IGNvbHVtbiB3YXMgY3JlYXRlZCB3aXRoIHRoZSBhdmVyYWdlIG9mIHRoZSB0d28gYWZvcmVtZW50aW9uZWQgY29sdW1ucyBhbmQgdGhlIHByZXZpb3VzIHR3byBjb2x1bW5zIGRyb3BwZWQuDQpgYGB7cn0NCm9seW1waWMyIDwtIG11dGF0ZShvbHltcGljMSwgIlRvdGFsIEF0aGxldGVzIiA9IChBdGhsZXRlcyArIGBUb3RhbCBDb21wZXRpdG9yc2ApLzIsIEF0aGxldGVzID0gTlVMTCwgYFRvdGFsIENvbXBldGl0b3JzYCA9IE5VTEwpDQpwcmludC5kYXRhLmZyYW1lKGhlYWQob2x5bXBpYzIpKQ0KYGBgDQpUaGUgRXZlbnRzLCBDaXR5LCBhbmQgQ291bnRyeSBjb2x1bW5zIGFyZSBhbGwgZHVwbGljYXRlZCBmcm9tIHdoZW4gdGhlIGRhdGFzZXRzIHdlcmUgbWVyZ2VkLCBzbyB0aGUgZHVwbGljYXRlcyB3ZXJlIHJlbW92ZWQuDQpgYGB7cn0NCm9seW1waWMzIDwtIG9seW1waWMyWy1jKDgsOSwxMSldDQpoZWFkKG9seW1waWMzKQ0KDQojIFJlbmFtaW5nIGNvbHVtbnMgdG8gZWxpbWluYXRlICcueCcgaW4gdGhlIG5hbWUNCm9seW1waWMzIDwtIG9seW1waWMzICU+JSByZW5hbWUoDQogIENpdHkgPSBDaXR5LngsDQogIENvdW50cnkgPSBDb3VudHJ5LngsDQogIEV2ZW50cyA9IEV2ZW50cy54KQ0KYGBgDQpUaGUgQXRobGV0ZSBhbmQgQ29zdCBpbiBCaWxsaW9ucyAoVVNEKSBjb2x1bW5zIHdlcmUgbXV0YXRlZCB0byBjcmVhdGVkIGEgbmV3IGNvbHVtbiwgQ29zdCBwZXIgQXRobGV0ZS4NCmBgYHtyfQ0Kb2x5bXBpYzQgPC0gbXV0YXRlKG9seW1waWMzLCAiQ29zdCBwZXIgQXRobGV0ZSIgPSBgQ29zdCBpbiBCaWxsaW9ucyAoVVNEKWAgLyBgVG90YWwgQXRobGV0ZXNgKQ0KcHJpbnQuZGF0YS5mcmFtZShoZWFkKG9seW1waWM0KSkNCg0KIyBDb252ZXJ0IHVuaXRzIG9mIENvc3QgcGVyIEF0aGxldGUgY29sdW1uIGludG8gbWlsbGlvbnMNCm9seW1waWM0JGBDb3N0IHBlciBBdGhsZXRlIGluIE1pbGxpb25zIChVU0QpYCA8LSBvbHltcGljNCRgQ29zdCBwZXIgQXRobGV0ZWAqMTAwMA0KDQojIFJlbW92ZSBvcmlnaW5hbCBDb3N0IHBlciBBdGhsZXRlIGNvbHVtbg0Kb2x5bXBpYzUgPC0gb2x5bXBpYzRbLTExXQ0KcHJpbnQuZGF0YS5mcmFtZShoZWFkKG9seW1waWM1KSkNCmBgYA0KDQojIwlTY2FuIElJDQoNCkJ5IHZpZXdpbmcgdGhlIGRhdGEgc2V0LCB0aGUgbW9zdCBvYnZpb3VzIGxvY2F0aW9uIGZvciBhbnkgb3V0bGllcnMgd291bGQgYmUgdGhlICdDb3N0IGluIEJpbGxpb25zIChVU0QpJyBjb2x1bW4uIEEgc3VtbWFyeSBvZiB0aGUgY29sdW1uIHNob3dzIGEgZGlmZmVyZW5jZSBiZXR3ZWVuIG1lZGlhbiBhbmQgbWVhbiwgYXMgd2VsbCBhcyBhIG1heGltdW0gdmFsdWUgKDE0Ljk1NykgcXVpdGUgZmFyIG91dHNpZGUgdGhlIFEzICg2LjQ1MSkuIE90aGVyIHZhcmlhYmxlcyB3ZXJlIGFsc28gY2hlY2tlZCBmb3Igb3V0bGllcnMuIFRvIGRlYWwgd2l0aCB0aGUgb3V0bGllciBpbiB0aGUgQ29zdCBpbiBCaWxsaW9ucyAoVVNEKSBjb2x1bW4sIHRoZSBjYXBwaW5nIG1ldGhvZCB3YXMgdXNlZCB0byByZXBsYWNlIHRoZSBvdXRsaWVyIHdpdGggdGhlIDk1dGggcGVyY2VudGlsZSB2YWx1ZSAoRG9sZ3VuLCAyMDIwKS4NCg0KYGBge3J9DQojIFN1bW1hcnkgb2YgY29zdCBpbiBiaWxsaW9ucw0Kc3VtbWFyeShvbHltcGljNSRgQ29zdCBpbiBCaWxsaW9ucyAoVVNEKWApDQoNCiMgU2VhcmNoaW5nIGZvciBvdXRsaWVycyBpbiBjb3N0IGluIGJpbGxpb25zDQpvbHltcGljNSRgQ29zdCBpbiBCaWxsaW9ucyAoVVNEKWAgJT4lIGJveHBsb3QobWFpbiA9ICJCb3hwbG90IG9mIENvc3QgaW4gQmlsbGlvbnMgKFVTRCkiLCB5bGFiID0gIkJpbGxpb25zIChVU0QpIikNCg0KIyBTZWFyY2hpbmcgZm9yIG91dGxpZXJzIGluIGNvc3QgcGVyIGF0aGxldGUNCm9seW1waWM1JGBDb3N0IHBlciBBdGhsZXRlIGluIE1pbGxpb25zIChVU0QpYCAlPiUgYm94cGxvdChtYWluID0gIkJveHBsb3Qgb2YgQ29zdCBwZXIgQXRobGV0ZSAoVVNEKSIsIHlsYWIgPSAiTWlsbGlvbnMgKFVTRCkiKQ0KDQojIENyZWF0aW5nIGZ1bmN0aW9uIGZvciBjYXBwaW5nDQpjYXAgPC0gZnVuY3Rpb24oeCl7DQogICAgcXVhbnRpbGVzIDwtIHF1YW50aWxlKCB4LCBjKC4wNSwgMC4yNSwgMC43NSwgLjk1ICkgKQ0KICAgIHhbIHggPCBxdWFudGlsZXNbMl0gLSAxLjUqSVFSKHgpIF0gPC0gcXVhbnRpbGVzWzFdDQogICAgeFsgeCA+IHF1YW50aWxlc1szXSArIDEuNSpJUVIoeCkgXSA8LSBxdWFudGlsZXNbNF0NCiAgICB4DQp9DQoNCm9seW1waWM1JGBDb3N0IGluIEJpbGxpb25zIChVU0QpYCA8LSBvbHltcGljNSRgQ29zdCBpbiBCaWxsaW9ucyAoVVNEKWAgJT4lIGNhcCgpDQoNCiMgQ2hlY2tpbmcgdGhhdCBvdXRsaWVyIGlzIGdvbmUNCm9seW1waWM1JGBDb3N0IGluIEJpbGxpb25zIChVU0QpYCAlPiUgYm94cGxvdChtYWluID0gIkJveHBsb3Qgb2YgQ29zdCBpbiBCaWxsaW9ucyAoVVNEKSIsIHlsYWIgPSAiQmlsbGlvbnMgKFVTRCkiKQ0KDQpgYGANCg0KDQojIwlUcmFuc2Zvcm0gDQoNCkEgdHJhbnNmb3JtYXRpb24gd2FzIGFwcGxpZWQgdG8gdGhlIENvc3QgaW4gQmlsbGlvbnMgKFVTRCkgY29sdW1uIGluIGF0dGVtcHQgdG8gbm9ybWFsaXNlIGl0LiBTZXZlcmFsIHRyYW5zZm9ybWF0aW9uIHdlcmUgdHJpYWxsZWQgYW5kIHRoZSBtb3N0IHJlbGV2YW50IG9uZSB3YXMgdGhlIHNxdWFyZSByb290IHRyYW5zZm9ybWF0aW9uLiBBIGhpc3RvZ3JhbSB3YXMgdGhlbiB1c2VkIHRvIGRpc3BsYXkgdGhlIHRyYW5zZm9ybWF0aW9uLg0KDQpUaGUgQ29zdCBwZXIgQXRobGV0ZSBpbiBNaWxsaW9ucyAoVVNEKSBjb2x1bW4gcHJvZHVjZWQgYSByaWdodC1za2V3ZWQgaGlzdG9ncmFtLCBzbyBhIHNxdWFyZSByb290IHRyYW5zZm9ybWF0aW9uIHdhcyBhcHBsaWVkIHRvIG5vcm1hbGlzZSBpdC4NCmBgYHtyfQ0KIyBoaXN0b2dyYW0gb2YgQ29zdCBpbiBCaWxsaW9ucyAoVVNEKSBjb2x1bW4NCm9seW1waWM1JGBDb3N0IGluIEJpbGxpb25zIChVU0QpYCU+JSBoaXN0b2dyYW0oYnJlYWtzID0gMTAsIG1haW4gPSAiSGlzdG9ncmFtIG9mIENvc3QgaW4gQmlsbGlvbnMgKFVTRCkiKQ0KDQojIExvZyBlIHRyYW5zZm9ybWF0aW9uDQpsb2cob2x5bXBpYzUkYENvc3QgaW4gQmlsbGlvbnMgKFVTRClgKSU+JSBoaXN0b2dyYW0oYnJlYWtzID0gMTApDQoNCiMgUmVjaXByb2NhbCBzcXVhcmUgdHJhbnNmb3JtYXRpb24NCm9seW1waWM1JGBDb3N0IGluIEJpbGxpb25zIChVU0QpYF4oLTIpJT4lIGhpc3RvZ3JhbShicmVha3MgPSAxMCkNCg0KIyBTcXVhcmUgcm9vdCB0cmFuc2Zvcm1hdGlvbiANCm9seW1waWM1JGBDb3N0IGluIEJpbGxpb25zIChVU0QpYF4oMS8yKSU+JSBoaXN0b2dyYW0oYnJlYWtzID0gMTAsIG1haW4gPSAiU3FhdXJlIFJvb3Qgb2YgQ29zdCBpbiBCaWxsaW9ucyAoVVNEKSIpDQoNCiMgU3F1YXJlIHRyYW5zZm9ybWF0aW9uDQpvbHltcGljNSRgQ29zdCBpbiBCaWxsaW9ucyAoVVNEKWBeKDIpJT4lIGhpc3RvZ3JhbShicmVha3MgPSAxMCkNCg0KIyBIaXN0b2dyYW0gb2YgQ29zdCBwZXIgQXRobGV0ZSBpbiBNaWxsaW9ucyAoVVNEKQ0Kb2x5bXBpYzUkYENvc3QgcGVyIEF0aGxldGUgaW4gTWlsbGlvbnMgKFVTRClgICU+JSBoaXN0b2dyYW0oYnJlYWtzID0gMTAsIG1haW4gPSAiSGlzdG9ncmFtIG9mIENvc3QgcGVyIEF0aGxldGUgaW4gTWlsbGlvbnMgKFVTRCkiKQ0KDQojIFNxdWFyZSByb290IG9mIENvc3QgcGVyIEF0aGxldGUgaW4gTWlsbGlvbnMgKFVTRCkNCnNxcnQob2x5bXBpYzUkYENvc3QgcGVyIEF0aGxldGUgaW4gTWlsbGlvbnMgKFVTRClgKSAlPiUgaGlzdG9ncmFtKGJyZWFrcyA9IDEwLCBtYWluID0gIlNxdWFyZSBSb290IEhpc3RvZ3JhbSBvZiBDb3N0IHBlciBBdGhsZXRlIGluIE1pbGxpb25zIChVU0QpIikNCg0KYGBgDQojIyMgUmVmZXJlbmNlcw0KDQpEb2xndW4sIEEgMjAyMCAnU2NhbjogT3V0bGllcnMnLCBtb2R1bGUgbm90ZXMsIE1BVEgyMzQ5LCBSTUlUIFVuaXZlcnNpdHksIHZpZXdlZCAxNyBPY3RvYmVyIDIwMjAsIDxodHRwOi8vcmFyZS1waG9lbml4LTE2MTYxMC5hcHBzcG90LmNvbS9zZWN1cmVkL01vZHVsZV8wNi5odG1sI2NhcHBpbmdfKGFrYV93aW5zb3Jpc2luZyk+DQoNCkthc3NhbWJhcmEsIEEgbi5kLipSZW5hbWUgRGF0YSBGcmFtZSBDb2x1bW5zIGluIFIqLCBEYXRhbm92aWEsIHZpZXdlZCAxOCBPY3RvYmVyIDIwMjAsIDxodHRwczovL3d3dy5kYXRhbm92aWEuY29tL2VuL2xlc3NvbnMvcmVuYW1lLWRhdGEtZnJhbWUtY29sdW1ucy1pbi1yLz4NCg0KV2lja2hhbSwgSCAyMDE0ICdUaWR5IERhdGEsJyAqSm91cm5hbCBvZiBTdGF0aXN0aWNhbCBTb2Z0d2FyZSosIHZvbC4gNTkgaXNzdWUgMTAuDQo8YnI+DQo8YnI+DQo=