Submission Steps:

Required packages

# This is the R chunk for the required packages
library(readr)
library(dplyr)
Registered S3 method overwritten by 'dplyr':
  method           from
  print.rowwise_df     

Attaching package: 㤼㸱dplyr㤼㸲

The following objects are masked from 㤼㸱package:stats㤼㸲:

    filter, lag

The following objects are masked from 㤼㸱package:base㤼㸲:

    intersect, setdiff, setequal, union
library(outliers)
library(outliers)
library(tidyr)
library(readxl)
library(Hmisc)
Loading required package: lattice
Loading required package: survival
Loading required package: Formula
Loading required package: ggplot2
Registered S3 methods overwritten by 'htmltools':
  method               from         
  print.html           tools:rstudio
  print.shiny.tag      tools:rstudio
  print.shiny.tag.list tools:rstudio
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     

Attaching package: 㤼㸱Hmisc㤼㸲

The following objects are masked from 㤼㸱package:dplyr㤼㸲:

    src, summarize

The following objects are masked from 㤼㸱package:base㤼㸲:

    format.pval, units
library(dplyr)
install.packages("forecast")
WARNING: Rtools is required to build R packages but is not currently installed. Please download and install the appropriate version of Rtools before proceeding:

https://cran.rstudio.com/bin/windows/Rtools/
Installing package into 㤼㸱C:/Users/thyagu/Documents/R/win-library/3.6㤼㸲
(as 㤼㸱lib㤼㸲 is unspecified)
trying URL 'https://cran.rstudio.com/bin/windows/contrib/3.6/forecast_8.13.zip'
Content type 'application/zip' length 2366760 bytes (2.3 MB)
downloaded 2.3 MB
package ‘forecast’ successfully unpacked and MD5 sums checked
Warning in install.packages :
  cannot remove prior installation of package ‘forecast’
Warning in install.packages :
  problem copying C:\Users\thyagu\Documents\R\win-library\3.6\00LOCK\forecast\libs\x64\forecast.dll to C:\Users\thyagu\Documents\R\win-library\3.6\forecast\libs\x64\forecast.dll: Permission denied
Warning in install.packages :
  restored ‘forecast’

The downloaded binary packages are in
    C:\Users\thyagu\AppData\Local\Temp\Rtmpmu9eqA\downloaded_packages
library(forecast)
Registered S3 method overwritten by 'quantmod':
  method            from
  as.zoo.data.frame zoo 

Executive Summary

The aim of this task is to wrangle a real world dataset using tidyR principles,using all data wrangling tasks starting from preprocessing,finding outliers,imputing missing values and to transform skewed data The data is a collection of IPL related stats from 2008-2019(IPL is a league of cricket )and our primary aim here is to perform data wrangling tasks to this dataset (URL:https://www.kaggle.com/ramjidoolla/ipl-data-set) 1) Two datasets were taken and merged as required 2)The dataset’s goal is to predict the winner but for us the main task is to wrangle the data and get ready for modelling 3)Untidying the tidy dataset in hand 4)Mutate a couple of variables from the given data (strike rate and extras per match) and focus on those variables 5)Scan and handle missing values 6)Scan for outliers 7)Tranbsform skewed data if any

Data

Even though the URL has 6 files ,we focus only on 2 files namely matches.csv and deliveries.csv 1) Matches.csv contains every match details 2)deliveries.csv contains ball by ball details of every match from 2008-2019 Since we are focussing mostly on finding new insights like strike rate and extras per match by mutating,I have taken only these 2 files from the URL 3)Use full join since we need both files data to explore and wrangle 4)179078 records and 38 variables in total after merging

# Importing matches.csv data
match_data <- read_csv("C:/Users/thyagu/Desktop/Final ipl/matches.csv")
Parsed with column specification:
cols(
  id = col_double(),
  Season = col_character(),
  city = col_character(),
  date = col_character(),
  team1 = col_character(),
  team2 = col_character(),
  toss_winner = col_character(),
  toss_decision = col_character(),
  result = col_character(),
  dl_applied = col_double(),
  winner = col_character(),
  win_by_runs = col_double(),
  win_by_wickets = col_double(),
  player_of_match = col_character(),
  venue = col_character(),
  umpire1 = col_character(),
  umpire2 = col_character(),
  umpire3 = col_character()
)
#Reading deliveries dataset:
deliveries_data <- read_csv("C:/Users/thyagu/Desktop/Final ipl/deliveries.csv")
Parsed with column specification:
cols(
  .default = col_double(),
  batting_team = col_character(),
  bowling_team = col_character(),
  batsman = col_character(),
  non_striker = col_character(),
  bowler = col_character(),
  player_dismissed = col_character(),
  dismissal_kind = col_character(),
  fielder = col_character()
)
See spec(...) for full column specifications.
#Merging datasets
#To merge datasets,the key should be the same. Here the key is match_id which is given as id in our match_data. We will rename this and then merge

names(match_data)[names(match_data) == "id"] <- "match_id"

joined_data <- full_join(match_data,deliveries_data,by = "match_id")

head(joined_data)
NA

Understand

Main task here is to get full understanding of the data and datatypes using glimpse and converting the data types wherever necessary

#getting a glimpse of merged data 
glimpse(joined_data)
Observations: 179,078
Variables: 38
$ match_id         <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
$ Season           <chr> "IPL-2017", "IPL-2017", "IPL-2017", "IPL-2017...
$ city             <chr> "Hyderabad", "Hyderabad", "Hyderabad", "Hyder...
$ date             <chr> "05-04-2017", "05-04-2017", "05-04-2017", "05...
$ team1            <chr> "Sunrisers Hyderabad", "Sunrisers Hyderabad",...
$ team2            <chr> "Royal Challengers Bangalore", "Royal Challen...
$ toss_winner      <chr> "Royal Challengers Bangalore", "Royal Challen...
$ toss_decision    <chr> "field", "field", "field", "field", "field", ...
$ result           <chr> "normal", "normal", "normal", "normal", "norm...
$ dl_applied       <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...
$ winner           <chr> "Sunrisers Hyderabad", "Sunrisers Hyderabad",...
$ win_by_runs      <dbl> 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 3...
$ win_by_wickets   <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...
$ player_of_match  <chr> "Yuvraj Singh", "Yuvraj Singh", "Yuvraj Singh...
$ venue            <chr> "Rajiv Gandhi International Stadium, Uppal", ...
$ umpire1          <chr> "AY Dandekar", "AY Dandekar", "AY Dandekar", ...
$ umpire2          <chr> "NJ Llong", "NJ Llong", "NJ Llong", "NJ Llong...
$ umpire3          <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N...
$ inning           <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
$ batting_team     <chr> "Sunrisers Hyderabad", "Sunrisers Hyderabad",...
$ bowling_team     <chr> "Royal Challengers Bangalore", "Royal Challen...
$ over             <dbl> 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, ...
$ ball             <dbl> 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, 1, ...
$ batsman          <chr> "DA Warner", "DA Warner", "DA Warner", "DA Wa...
$ non_striker      <chr> "S Dhawan", "S Dhawan", "S Dhawan", "S Dhawan...
$ bowler           <chr> "TS Mills", "TS Mills", "TS Mills", "TS Mills...
$ is_super_over    <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...
$ wide_runs        <dbl> 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...
$ bye_runs         <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...
$ legbye_runs      <dbl> 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, ...
$ noball_runs      <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, ...
$ penalty_runs     <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...
$ batsman_runs     <dbl> 0, 0, 4, 0, 0, 0, 0, 1, 4, 0, 6, 0, 0, 4, 1, ...
$ extra_runs       <dbl> 0, 0, 0, 0, 2, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, ...
$ total_runs       <dbl> 0, 0, 4, 0, 2, 0, 1, 1, 4, 1, 6, 0, 0, 4, 1, ...
$ player_dismissed <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, "...
$ dismissal_kind   <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, "...
$ fielder          <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, "...

#Changing Data types wherever needed

#Factors:

#Factorising
joined_data$Season <- joined_data$Season %>% factor(levels = c("IPL-2008",
"IPL-2009","IPL-2010","IPL-2011","IPL-2012", "IPL-2013", "IPL-2014", "IPL-2015","IPL-2016", "IPL-2017", "IPL-2018", "IPL-2019"),labels = c("IPL-2008", "IPL-2009", "IPL-2010", "IPL-2011","IPL-2012", "IPL-2013", "IPL-2014", "IPL-2015","IPL-2016", "IPL-2017", "IPL-2018", "IPL-2019"),ordered = TRUE)
joined_data$team1 <- joined_data$team1 %>% as.factor()
joined_data$team2 <- joined_data$team2 %>% as.factor()
joined_data$toss_winner <- joined_data$toss_winner %>% as.factor()
joined_data$winner <- joined_data$winner %>% as.factor()
joined_data$toss_decision <- joined_data$toss_decision %>% as.factor()
joined_data$result <- joined_data$result %>% as.factor()
joined_data$dl_applied <- joined_data$dl_applied %>% as.factor()
joined_data$over <- joined_data$over %>% as.factor()
joined_data$is_super_over  <- joined_data$is_super_over %>% as.factor()
joined_data$dismissal_kind <- joined_data$dismissal_kind %>% as.factor()
joined_data$city <- joined_data$city %>% as.factor()
#as.Date to change to Date format
joined_data$date <- as.Date(joined_data$date)
head(joined_data)
#Checking structure of data
str(joined_data)
Classes ‘spec_tbl_df’, ‘tbl_df’, ‘tbl’ and 'data.frame':    179078 obs. of  38 variables:
 $ match_id        : num  1 1 1 1 1 1 1 1 1 1 ...
 $ Season          : Ord.factor w/ 12 levels "IPL-2008"<"IPL-2009"<..: 10 10 10 10 10 10 10 10 10 10 ...
 $ city            : Factor w/ 32 levels "Abu Dhabi","Ahmedabad",..: 15 15 15 15 15 15 15 15 15 15 ...
 $ date            : Date, format: "0005-04-20" "0005-04-20" ...
 $ team1           : Factor w/ 15 levels "Chennai Super Kings",..: 15 15 15 15 15 15 15 15 15 15 ...
 $ team2           : Factor w/ 15 levels "Chennai Super Kings",..: 14 14 14 14 14 14 14 14 14 14 ...
 $ toss_winner     : Factor w/ 15 levels "Chennai Super Kings",..: 14 14 14 14 14 14 14 14 14 14 ...
 $ toss_decision   : Factor w/ 2 levels "bat","field": 2 2 2 2 2 2 2 2 2 2 ...
 $ result          : Factor w/ 3 levels "no result","normal",..: 2 2 2 2 2 2 2 2 2 2 ...
 $ dl_applied      : Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 1 1 1 ...
 $ winner          : Factor w/ 15 levels "Chennai Super Kings",..: 15 15 15 15 15 15 15 15 15 15 ...
 $ win_by_runs     : num  35 35 35 35 35 35 35 35 35 35 ...
 $ win_by_wickets  : num  0 0 0 0 0 0 0 0 0 0 ...
 $ player_of_match : chr  "Yuvraj Singh" "Yuvraj Singh" "Yuvraj Singh" "Yuvraj Singh" ...
 $ venue           : chr  "Rajiv Gandhi International Stadium, Uppal" "Rajiv Gandhi International Stadium, Uppal" "Rajiv Gandhi International Stadium, Uppal" "Rajiv Gandhi International Stadium, Uppal" ...
 $ umpire1         : chr  "AY Dandekar" "AY Dandekar" "AY Dandekar" "AY Dandekar" ...
 $ umpire2         : chr  "NJ Llong" "NJ Llong" "NJ Llong" "NJ Llong" ...
 $ umpire3         : chr  NA NA NA NA ...
 $ inning          : num  1 1 1 1 1 1 1 1 1 1 ...
 $ batting_team    : chr  "Sunrisers Hyderabad" "Sunrisers Hyderabad" "Sunrisers Hyderabad" "Sunrisers Hyderabad" ...
 $ bowling_team    : chr  "Royal Challengers Bangalore" "Royal Challengers Bangalore" "Royal Challengers Bangalore" "Royal Challengers Bangalore" ...
 $ over            : Factor w/ 20 levels "1","2","3","4",..: 1 1 1 1 1 1 1 2 2 2 ...
 $ ball            : num  1 2 3 4 5 6 7 1 2 3 ...
 $ batsman         : chr  "DA Warner" "DA Warner" "DA Warner" "DA Warner" ...
 $ non_striker     : chr  "S Dhawan" "S Dhawan" "S Dhawan" "S Dhawan" ...
 $ bowler          : chr  "TS Mills" "TS Mills" "TS Mills" "TS Mills" ...
 $ is_super_over   : Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 1 1 1 ...
 $ wide_runs       : num  0 0 0 0 2 0 0 0 0 0 ...
 $ bye_runs        : num  0 0 0 0 0 0 0 0 0 0 ...
 $ legbye_runs     : num  0 0 0 0 0 0 1 0 0 0 ...
 $ noball_runs     : num  0 0 0 0 0 0 0 0 0 1 ...
 $ penalty_runs    : num  0 0 0 0 0 0 0 0 0 0 ...
 $ batsman_runs    : num  0 0 4 0 0 0 0 1 4 0 ...
 $ extra_runs      : num  0 0 0 0 2 0 1 0 0 1 ...
 $ total_runs      : num  0 0 4 0 2 0 1 1 4 1 ...
 $ player_dismissed: chr  NA NA NA NA ...
 $ dismissal_kind  : Factor w/ 9 levels "bowled","caught",..: NA NA NA NA NA NA NA NA NA NA ...
 $ fielder         : chr  NA NA NA NA ...










#```{r}
# This is the R chunk for the Tidy & Manipulate Data II 

Tidy & Manipulate Data I

Here we check for tidyR principles .Redundant variable names, datatypes conversion,ordering of data, making sure each variable has its own row are all part of tidying. The win_by_runs and win_by_wickets columns were tidied up using gather because the team on a particular match day can win only by runs or by wickets,cant be both. So i split using gather function

joined_data <- joined_data %>% gather(win_by_runs, win_by_wickets, key = "win_by",value = "count")
head(joined_data)

Tidy & Manipulate Data II

Mutate function was used to create 2 new variables. 1)Strike rate calculation 2) Extras per match calculation

joined_data <- joined_data %>% group_by(batsman) %>% mutate(batsman_totalrun = sum(total_runs), strike_rate = mean(batsman_runs) * 100)
head(joined_data)
joined_data <- joined_data %>% group_by(bowling_team,Season,date) %>% mutate(extras = sum(extra_runs))
head(joined_data)
NA

Scan I

Missing values were checked using colsums and replaced using mode and other respective data

colSums(is.na(joined_data))
        match_id           Season             city             date 
               0                0             3400                0 
           team1            team2      toss_winner    toss_decision 
               0                0                0                0 
          result       dl_applied           winner  player_of_match 
               0                0              744              744 
           venue          umpire1          umpire2          umpire3 
               0             1000             1000           301424 
          inning     batting_team     bowling_team             over 
               0                0                0                0 
            ball          batsman      non_striker           bowler 
               0                0                0                0 
   is_super_over        wide_runs         bye_runs      legbye_runs 
               0                0                0                0 
     noball_runs     penalty_runs     batsman_runs       extra_runs 
               0                0                0                0 
      total_runs player_dismissed   dismissal_kind          fielder 
               0           340488           340488           345260 
          win_by            count batsman_totalrun      strike_rate 
               0                0                0                0 
          extras 
               0 
#Imputing missing values
joined_data$city <-impute(joined_data$city, fun = mode)
joined_data$toss_decision <-impute(joined_data$toss_decision, fun = mode)
joined_data$dismissal_kind <-impute(joined_data$dismissal_kind, fun = mode)
joined_data$dismissal_kind <- impute(joined_data$dismissal_kind , fun = mode )
joined_data$player_of_match [is.na(joined_data$player_of_match)] <- "No"
joined_data$winner [is.na(joined_data$winner)] <- "No"
invalid factor level, NA generated
joined_data$umpire1 [is.na(joined_data$umpire1)] <- "No data"
joined_data$umpire2 [is.na(joined_data$umpire2)] <- "No data"
joined_data$umpire3 [is.na(joined_data$umpire3)] <- "No data"
joined_data$player_dismissed [is.na(joined_data$player_dismissed)] <- "No"
joined_data$fielder [is.na(joined_data$fielder)] <- "Not caught"
colSums(is.na(joined_data))
        match_id           Season             city             date 
               0                0                0                0 
           team1            team2      toss_winner    toss_decision 
               0                0                0                0 
          result       dl_applied           winner  player_of_match 
               0                0              744                0 
           venue          umpire1          umpire2          umpire3 
               0                0                0                0 
          inning     batting_team     bowling_team             over 
               0                0                0                0 
            ball          batsman      non_striker           bowler 
               0                0                0                0 
   is_super_over        wide_runs         bye_runs      legbye_runs 
               0                0                0                0 
     noball_runs     penalty_runs     batsman_runs       extra_runs 
               0                0                0                0 
      total_runs player_dismissed   dismissal_kind          fielder 
               0                0                0                0 
          win_by            count batsman_totalrun      strike_rate 
               0                0                0                0 
          extras 
               0 
#checking for special values
is.special <- function(x){
if (is.numeric(x)) (is.infinite(x) | is.nan(x))
}

sapply(joined_data, function(x) sum( is.special(x)))
        match_id           Season             city             date 
               0                0                0                0 
           team1            team2      toss_winner    toss_decision 
               0                0                0                0 
          result       dl_applied           winner  player_of_match 
               0                0                0                0 
           venue          umpire1          umpire2          umpire3 
               0                0                0                0 
          inning     batting_team     bowling_team             over 
               0                0                0                0 
            ball          batsman      non_striker           bowler 
               0                0                0                0 
   is_super_over        wide_runs         bye_runs      legbye_runs 
               0                0                0                0 
     noball_runs     penalty_runs     batsman_runs       extra_runs 
               0                0                0                0 
      total_runs player_dismissed   dismissal_kind          fielder 
               0                0                0                0 
          win_by            count batsman_totalrun      strike_rate 
               0                0                0                0 
          extras 
               0 
colSums(is.na(joined_data))
        match_id           Season             city             date 
               0                0                0                0 
           team1            team2      toss_winner    toss_decision 
               0                0                0                0 
          result       dl_applied           winner  player_of_match 
               0                0              744                0 
           venue          umpire1          umpire2          umpire3 
               0                0                0                0 
          inning     batting_team     bowling_team             over 
               0                0                0                0 
            ball          batsman      non_striker           bowler 
               0                0                0                0 
   is_super_over        wide_runs         bye_runs      legbye_runs 
               0                0                0                0 
     noball_runs     penalty_runs     batsman_runs       extra_runs 
               0                0                0                0 
      total_runs player_dismissed   dismissal_kind          fielder 
               0                0                0                0 
          win_by            count batsman_totalrun      strike_rate 
               0                0                0                0 
          extras 
               0 

##Scan II Checking for outliers for strike rate,extras using boxplot since these are our variables of focus

#boxplot for strike rate
joined_data$strike_rate %>% boxplot(main = "Boxplot for strike rate of batsman",
                                                  ylab = "Per 100 balls")

#boxplot for batsman_total run
joined_data$batsman_totalrun %>% boxplot(main = "Boxplot for total runs by batsman",
                                                  ylab = "runs by batsman in total")

#boxplot for extras bowled
joined_data$extras %>% boxplot(main = "Boxplot for extra runs given",
                                                  ylab = "extra runs in match")

head(joined_data)
#using zscores to eliminate outliers but it did not work after a glimpse of changed data. So went for capping
z.scores <- joined_data$strike_rate %>%  scores(type = "z")
joined_clean1<- joined_data$strike_rate[ - which( abs(z.scores) >3 )]
#boxplot for strike rate
joined_data$strike_rate %>% boxplot(main = "Boxplot for strike rate of batsman",
                                                  ylab = "Per 100 balls")

#Capping these 2 variables alone since outliers were present
capping <- 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
}


#capping the outliers present for home_win_percentage and away_win_percentage
joined_data$batsman_runs <- joined_data$batsman_runs %>% capping()
joined_data$extra_runs <- joined_data$extra_runs %>% capping()
joined_data <- joined_data %>% group_by(batsman) %>% mutate(batsman_totalrun = sum(total_runs), strike_rate = mean(batsman_runs) * 100)
joined_data <- joined_data %>% group_by(bowling_team,Season,date) %>% mutate(extras = sum(extra_runs))
head(joined_data)
NA

Transform

Using all transformation techniques for strike rate and extras. Min_max turned out to be the best

hist(joined_data$strike_rate)

hist(joined_data$extras)

hist(joined_data$batsman_totalrun)

log_strike <- log10(joined_data$strike_rate)
hist(log_strike)

log_strike <- log(joined_data$strike_rate)
hist(log_strike)

sqrt_strike <- sqrt(joined_data$strike_rate)
hist(sqrt_strike)

minMaxMethod <- function(x) {
  (x-min(x)) / (max(x) - min(x))
}

#transforming the variable home_away_win_ratio using min-max transformation
joined_data$strike_rate <- joined_data$strike_rate %>% minMaxMethod()
hist(joined_data$strike_rate)

LS0tDQp0aXRsZTogIk1BVEgyMzQ5IERhdGEgV3JhbmdsaW5nIg0KYXV0aG9yOiAiVGh5YWdhcmFqYW4gVmlzd2VzYW4oczM4MjIxNjcpIg0Kc3VidGl0bGU6IEFzc2lnbm1lbnQgMg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOiBkZWZhdWx0DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogIHBkZl9kb2N1bWVudDogZGVmYXVsdA0KLS0tDQoNCiMjIFN1Ym1pc3Npb24gU3RlcHM6DQoNCg0KIyMgUmVxdWlyZWQgcGFja2FnZXMgDQoNCg0KDQpgYGB7cn0NCiMgVGhpcyBpcyB0aGUgUiBjaHVuayBmb3IgdGhlIHJlcXVpcmVkIHBhY2thZ2VzDQpsaWJyYXJ5KHJlYWRyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkob3V0bGllcnMpDQpsaWJyYXJ5KG91dGxpZXJzKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShIbWlzYykNCmxpYnJhcnkoZHBseXIpDQppbnN0YWxsLnBhY2thZ2VzKCJmb3JlY2FzdCIpDQpsaWJyYXJ5KGZvcmVjYXN0KQ0KYGBgDQoNCg0KIyMgRXhlY3V0aXZlIFN1bW1hcnkgDQoNClRoZSBhaW0gb2YgdGhpcyB0YXNrIGlzIHRvIHdyYW5nbGUgYSByZWFsIHdvcmxkIGRhdGFzZXQgdXNpbmcgdGlkeVIgcHJpbmNpcGxlcyx1c2luZyBhbGwgZGF0YSB3cmFuZ2xpbmcgdGFza3Mgc3RhcnRpbmcgZnJvbSBwcmVwcm9jZXNzaW5nLGZpbmRpbmcgb3V0bGllcnMsaW1wdXRpbmcgbWlzc2luZyB2YWx1ZXMgYW5kIHRvIHRyYW5zZm9ybSBza2V3ZWQgZGF0YSANClRoZSBkYXRhIGlzIGEgY29sbGVjdGlvbiBvZiBJUEwgcmVsYXRlZCBzdGF0cyBmcm9tIDIwMDgtMjAxOShJUEwgaXMgYSBsZWFndWUgb2YgY3JpY2tldCApYW5kIG91ciBwcmltYXJ5IGFpbSBoZXJlIGlzIHRvIHBlcmZvcm0gZGF0YSB3cmFuZ2xpbmcgdGFza3MgdG8gdGhpcyBkYXRhc2V0IChVUkw6aHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9yYW1qaWRvb2xsYS9pcGwtZGF0YS1zZXQpDQoxKSBUd28gZGF0YXNldHMgd2VyZSB0YWtlbiBhbmQgbWVyZ2VkIGFzIHJlcXVpcmVkDQoyKVRoZSBkYXRhc2V0J3MgZ29hbCBpcyB0byBwcmVkaWN0IHRoZSB3aW5uZXIgYnV0IGZvciB1cyB0aGUgbWFpbiB0YXNrIGlzIHRvIHdyYW5nbGUgdGhlIGRhdGEgYW5kIGdldCByZWFkeSBmb3IgbW9kZWxsaW5nDQozKVVudGlkeWluZyB0aGUgdGlkeSBkYXRhc2V0IGluIGhhbmQNCjQpTXV0YXRlIGEgY291cGxlIG9mIHZhcmlhYmxlcyBmcm9tIHRoZSBnaXZlbiBkYXRhIChzdHJpa2UgcmF0ZSBhbmQgZXh0cmFzIHBlciBtYXRjaCkgYW5kIGZvY3VzIG9uIHRob3NlIHZhcmlhYmxlcw0KNSlTY2FuIGFuZCBoYW5kbGUgbWlzc2luZyB2YWx1ZXMNCjYpU2NhbiBmb3Igb3V0bGllcnMNCjcpVHJhbmJzZm9ybSBza2V3ZWQgZGF0YSBpZiBhbnkNCg0KDQojIyBEYXRhIA0KDQpFdmVuIHRob3VnaCB0aGUgVVJMIGhhcyA2IGZpbGVzICx3ZSBmb2N1cyBvbmx5IG9uIDIgZmlsZXMgbmFtZWx5IG1hdGNoZXMuY3N2IGFuZCBkZWxpdmVyaWVzLmNzdg0KMSkgTWF0Y2hlcy5jc3YgY29udGFpbnMgZXZlcnkgbWF0Y2ggZGV0YWlscw0KMilkZWxpdmVyaWVzLmNzdiBjb250YWlucyBiYWxsIGJ5IGJhbGwgZGV0YWlscyBvZiBldmVyeSBtYXRjaCBmcm9tIDIwMDgtMjAxOQ0KU2luY2Ugd2UgYXJlIGZvY3Vzc2luZyBtb3N0bHkgb24gZmluZGluZyBuZXcgaW5zaWdodHMgbGlrZSBzdHJpa2UgcmF0ZSBhbmQgZXh0cmFzIHBlciBtYXRjaCBieSBtdXRhdGluZyxJIGhhdmUgdGFrZW4gb25seSB0aGVzZSAyIGZpbGVzIGZyb20gdGhlIFVSTA0KMylVc2UgZnVsbCBqb2luIHNpbmNlIHdlIG5lZWQgYm90aCBmaWxlcyBkYXRhIHRvIGV4cGxvcmUgYW5kIHdyYW5nbGUNCjQpMTc5MDc4IHJlY29yZHMgYW5kIDM4IHZhcmlhYmxlcyBpbiB0b3RhbCBhZnRlciBtZXJnaW5nDQoNCg0KYGBge3J9DQojIEltcG9ydGluZyBtYXRjaGVzLmNzdiBkYXRhDQptYXRjaF9kYXRhIDwtIHJlYWRfY3N2KCJDOi9Vc2Vycy90aHlhZ3UvRGVza3RvcC9GaW5hbCBpcGwvbWF0Y2hlcy5jc3YiKQ0KDQoNCmBgYA0KYGBge3J9DQojUmVhZGluZyBkZWxpdmVyaWVzIGRhdGFzZXQ6DQpkZWxpdmVyaWVzX2RhdGEgPC0gcmVhZF9jc3YoIkM6L1VzZXJzL3RoeWFndS9EZXNrdG9wL0ZpbmFsIGlwbC9kZWxpdmVyaWVzLmNzdiIpDQpgYGANCg0KYGBge3J9DQojTWVyZ2luZyBkYXRhc2V0cw0KI1RvIG1lcmdlIGRhdGFzZXRzLHRoZSBrZXkgc2hvdWxkIGJlIHRoZSBzYW1lLiBIZXJlIHRoZSBrZXkgaXMgbWF0Y2hfaWQgd2hpY2ggaXMgZ2l2ZW4gYXMgaWQgaW4gb3VyIG1hdGNoX2RhdGEuIFdlIHdpbGwgcmVuYW1lIHRoaXMgYW5kIHRoZW4gbWVyZ2UNCg0KbmFtZXMobWF0Y2hfZGF0YSlbbmFtZXMobWF0Y2hfZGF0YSkgPT0gImlkIl0gPC0gIm1hdGNoX2lkIg0KDQpqb2luZWRfZGF0YSA8LSBmdWxsX2pvaW4obWF0Y2hfZGF0YSxkZWxpdmVyaWVzX2RhdGEsYnkgPSAibWF0Y2hfaWQiKQ0KDQpoZWFkKGpvaW5lZF9kYXRhKQ0KDQpgYGANCg0KDQoNCg0KDQoNCiMjIFVuZGVyc3RhbmQgDQpNYWluIHRhc2sgaGVyZSBpcyB0byBnZXQgZnVsbCB1bmRlcnN0YW5kaW5nIG9mIHRoZSBkYXRhIGFuZCBkYXRhdHlwZXMgdXNpbmcgZ2xpbXBzZSBhbmQgY29udmVydGluZyB0aGUgZGF0YSB0eXBlcyB3aGVyZXZlciBuZWNlc3NhcnkNCg0KDQpgYGB7cn0NCiNnZXR0aW5nIGEgZ2xpbXBzZSBvZiBtZXJnZWQgZGF0YSANCmdsaW1wc2Uoam9pbmVkX2RhdGEpDQpgYGANCg0KI0NoYW5naW5nIERhdGEgdHlwZXMgd2hlcmV2ZXIgbmVlZGVkDQoNCiNGYWN0b3JzOg0KDQoNCmBgYHtyfQ0KI0ZhY3RvcmlzaW5nDQpqb2luZWRfZGF0YSRTZWFzb24gPC0gam9pbmVkX2RhdGEkU2Vhc29uICU+JSBmYWN0b3IobGV2ZWxzID0gYygiSVBMLTIwMDgiLA0KIklQTC0yMDA5IiwiSVBMLTIwMTAiLCJJUEwtMjAxMSIsIklQTC0yMDEyIiwgIklQTC0yMDEzIiwgIklQTC0yMDE0IiwgIklQTC0yMDE1IiwiSVBMLTIwMTYiLCAiSVBMLTIwMTciLCAiSVBMLTIwMTgiLCAiSVBMLTIwMTkiKSxsYWJlbHMgPSBjKCJJUEwtMjAwOCIsICJJUEwtMjAwOSIsICJJUEwtMjAxMCIsICJJUEwtMjAxMSIsIklQTC0yMDEyIiwgIklQTC0yMDEzIiwgIklQTC0yMDE0IiwgIklQTC0yMDE1IiwiSVBMLTIwMTYiLCAiSVBMLTIwMTciLCAiSVBMLTIwMTgiLCAiSVBMLTIwMTkiKSxvcmRlcmVkID0gVFJVRSkNCmpvaW5lZF9kYXRhJHRlYW0xIDwtIGpvaW5lZF9kYXRhJHRlYW0xICU+JSBhcy5mYWN0b3IoKQ0Kam9pbmVkX2RhdGEkdGVhbTIgPC0gam9pbmVkX2RhdGEkdGVhbTIgJT4lIGFzLmZhY3RvcigpDQpqb2luZWRfZGF0YSR0b3NzX3dpbm5lciA8LSBqb2luZWRfZGF0YSR0b3NzX3dpbm5lciAlPiUgYXMuZmFjdG9yKCkNCmpvaW5lZF9kYXRhJHdpbm5lciA8LSBqb2luZWRfZGF0YSR3aW5uZXIgJT4lIGFzLmZhY3RvcigpDQpqb2luZWRfZGF0YSR0b3NzX2RlY2lzaW9uIDwtIGpvaW5lZF9kYXRhJHRvc3NfZGVjaXNpb24gJT4lIGFzLmZhY3RvcigpDQpqb2luZWRfZGF0YSRyZXN1bHQgPC0gam9pbmVkX2RhdGEkcmVzdWx0ICU+JSBhcy5mYWN0b3IoKQ0Kam9pbmVkX2RhdGEkZGxfYXBwbGllZCA8LSBqb2luZWRfZGF0YSRkbF9hcHBsaWVkICU+JSBhcy5mYWN0b3IoKQ0Kam9pbmVkX2RhdGEkb3ZlciA8LSBqb2luZWRfZGF0YSRvdmVyICU+JSBhcy5mYWN0b3IoKQ0Kam9pbmVkX2RhdGEkaXNfc3VwZXJfb3ZlciAgPC0gam9pbmVkX2RhdGEkaXNfc3VwZXJfb3ZlciAlPiUgYXMuZmFjdG9yKCkNCmpvaW5lZF9kYXRhJGRpc21pc3NhbF9raW5kIDwtIGpvaW5lZF9kYXRhJGRpc21pc3NhbF9raW5kICU+JSBhcy5mYWN0b3IoKQ0Kam9pbmVkX2RhdGEkY2l0eSA8LSBqb2luZWRfZGF0YSRjaXR5ICU+JSBhcy5mYWN0b3IoKQ0KYGBgDQpgYGB7cn0NCiNhcy5EYXRlIHRvIGNoYW5nZSB0byBEYXRlIGZvcm1hdA0Kam9pbmVkX2RhdGEkZGF0ZSA8LSBhcy5EYXRlKGpvaW5lZF9kYXRhJGRhdGUpDQpgYGANCmBgYHtyfQ0KaGVhZChqb2luZWRfZGF0YSkNCmBgYA0KYGBge3J9DQojQ2hlY2tpbmcgc3RydWN0dXJlIG9mIGRhdGENCnN0cihqb2luZWRfZGF0YSkNCmBgYA0KDQoNCg0KYGBge3J9DQoNCg0KDQoNCg0KDQoNCg0KDQoNCiNgYGB7cn0NCiMgVGhpcyBpcyB0aGUgUiBjaHVuayBmb3IgdGhlIFRpZHkgJiBNYW5pcHVsYXRlIERhdGEgSUkgDQoNCmBgYA0KIyMgVGlkeSAmIE1hbmlwdWxhdGUgRGF0YSBJDQoNCkhlcmUgd2UgY2hlY2sgZm9yIHRpZHlSIHByaW5jaXBsZXMgLlJlZHVuZGFudCB2YXJpYWJsZSBuYW1lcywgZGF0YXR5cGVzIGNvbnZlcnNpb24sb3JkZXJpbmcgb2YgZGF0YSwgbWFraW5nIHN1cmUgZWFjaCB2YXJpYWJsZSBoYXMgaXRzIG93biByb3cgYXJlIGFsbCBwYXJ0IG9mIHRpZHlpbmcuIFRoZSB3aW5fYnlfcnVucyBhbmQgd2luX2J5X3dpY2tldHMgY29sdW1ucyB3ZXJlIHRpZGllZCB1cCB1c2luZyBnYXRoZXIgYmVjYXVzZSB0aGUgdGVhbSBvbiBhIHBhcnRpY3VsYXIgbWF0Y2ggZGF5IGNhbiB3aW4gb25seSBieSBydW5zIG9yIGJ5IHdpY2tldHMsY2FudCBiZSBib3RoLiBTbyBpIHNwbGl0IHVzaW5nIGdhdGhlciBmdW5jdGlvbg0KYGBge3J9DQpqb2luZWRfZGF0YSA8LSBqb2luZWRfZGF0YSAlPiUgZ2F0aGVyKHdpbl9ieV9ydW5zLCB3aW5fYnlfd2lja2V0cywga2V5ID0gIndpbl9ieSIsdmFsdWUgPSAiY291bnQiKQ0KYGBgDQpgYGB7cn0NCmhlYWQoam9pbmVkX2RhdGEpDQpgYGANCiMjIFRpZHkgJiBNYW5pcHVsYXRlIERhdGEgSUkNCk11dGF0ZSBmdW5jdGlvbiB3YXMgdXNlZCB0byBjcmVhdGUgMiBuZXcgdmFyaWFibGVzLg0KMSlTdHJpa2UgcmF0ZSBjYWxjdWxhdGlvbg0KMikgRXh0cmFzIHBlciBtYXRjaCBjYWxjdWxhdGlvbg0KDQpgYGB7cn0NCmpvaW5lZF9kYXRhIDwtIGpvaW5lZF9kYXRhICU+JSBncm91cF9ieShiYXRzbWFuKSAlPiUgbXV0YXRlKGJhdHNtYW5fdG90YWxydW4gPSBzdW0odG90YWxfcnVucyksIHN0cmlrZV9yYXRlID0gbWVhbihiYXRzbWFuX3J1bnMpICogMTAwKQ0KYGBgDQpgYGB7cn0NCmhlYWQoam9pbmVkX2RhdGEpDQpgYGANCmBgYHtyfQ0Kam9pbmVkX2RhdGEgPC0gam9pbmVkX2RhdGEgJT4lIGdyb3VwX2J5KGJvd2xpbmdfdGVhbSxTZWFzb24sZGF0ZSkgJT4lIG11dGF0ZShleHRyYXMgPSBzdW0oZXh0cmFfcnVucykpDQpoZWFkKGpvaW5lZF9kYXRhKQ0KDQpgYGANCg0KDQoNCiMjCVNjYW4gSSANCg0KTWlzc2luZyB2YWx1ZXMgd2VyZSBjaGVja2VkIHVzaW5nIGNvbHN1bXMgYW5kIHJlcGxhY2VkIHVzaW5nIG1vZGUgYW5kIG90aGVyIHJlc3BlY3RpdmUgZGF0YQ0KDQoNCmBgYHtyfQ0KY29sU3Vtcyhpcy5uYShqb2luZWRfZGF0YSkpDQoNCmBgYA0KDQpgYGB7cn0NCiNJbXB1dGluZyBtaXNzaW5nIHZhbHVlcw0Kam9pbmVkX2RhdGEkY2l0eSA8LWltcHV0ZShqb2luZWRfZGF0YSRjaXR5LCBmdW4gPSBtb2RlKQ0Kam9pbmVkX2RhdGEkdG9zc19kZWNpc2lvbiA8LWltcHV0ZShqb2luZWRfZGF0YSR0b3NzX2RlY2lzaW9uLCBmdW4gPSBtb2RlKQ0Kam9pbmVkX2RhdGEkZGlzbWlzc2FsX2tpbmQgPC1pbXB1dGUoam9pbmVkX2RhdGEkZGlzbWlzc2FsX2tpbmQsIGZ1biA9IG1vZGUpDQpqb2luZWRfZGF0YSRkaXNtaXNzYWxfa2luZCA8LSBpbXB1dGUoam9pbmVkX2RhdGEkZGlzbWlzc2FsX2tpbmQgLCBmdW4gPSBtb2RlICkNCmpvaW5lZF9kYXRhJHBsYXllcl9vZl9tYXRjaCBbaXMubmEoam9pbmVkX2RhdGEkcGxheWVyX29mX21hdGNoKV0gPC0gIk5vIg0Kam9pbmVkX2RhdGEkd2lubmVyIFtpcy5uYShqb2luZWRfZGF0YSR3aW5uZXIpXSA8LSAiTm8iDQpqb2luZWRfZGF0YSR1bXBpcmUxIFtpcy5uYShqb2luZWRfZGF0YSR1bXBpcmUxKV0gPC0gIk5vIGRhdGEiDQpqb2luZWRfZGF0YSR1bXBpcmUyIFtpcy5uYShqb2luZWRfZGF0YSR1bXBpcmUyKV0gPC0gIk5vIGRhdGEiDQpqb2luZWRfZGF0YSR1bXBpcmUzIFtpcy5uYShqb2luZWRfZGF0YSR1bXBpcmUzKV0gPC0gIk5vIGRhdGEiDQpqb2luZWRfZGF0YSRwbGF5ZXJfZGlzbWlzc2VkIFtpcy5uYShqb2luZWRfZGF0YSRwbGF5ZXJfZGlzbWlzc2VkKV0gPC0gIk5vIg0Kam9pbmVkX2RhdGEkZmllbGRlciBbaXMubmEoam9pbmVkX2RhdGEkZmllbGRlcildIDwtICJOb3QgY2F1Z2h0Ig0KY29sU3Vtcyhpcy5uYShqb2luZWRfZGF0YSkpDQpgYGANCmBgYHtyfQ0KI2NoZWNraW5nIGZvciBzcGVjaWFsIHZhbHVlcw0KaXMuc3BlY2lhbCA8LSBmdW5jdGlvbih4KXsNCmlmIChpcy5udW1lcmljKHgpKSAoaXMuaW5maW5pdGUoeCkgfCBpcy5uYW4oeCkpDQp9DQoNCnNhcHBseShqb2luZWRfZGF0YSwgZnVuY3Rpb24oeCkgc3VtKCBpcy5zcGVjaWFsKHgpKSkNCmNvbFN1bXMoaXMubmEoam9pbmVkX2RhdGEpKQ0KYGBgDQoNCiMjU2NhbiBJSQ0KQ2hlY2tpbmcgZm9yIG91dGxpZXJzIGZvciBzdHJpa2UgcmF0ZSxleHRyYXMgdXNpbmcgYm94cGxvdCBzaW5jZSB0aGVzZSBhcmUgb3VyIHZhcmlhYmxlcyBvZiBmb2N1cw0KYGBge3J9DQojYm94cGxvdCBmb3Igc3RyaWtlIHJhdGUNCmpvaW5lZF9kYXRhJHN0cmlrZV9yYXRlICU+JSBib3hwbG90KG1haW4gPSAiQm94cGxvdCBmb3Igc3RyaWtlIHJhdGUgb2YgYmF0c21hbiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlsYWIgPSAiUGVyIDEwMCBiYWxscyIpDQpgYGANCg0KYGBge3J9DQojYm94cGxvdCBmb3IgYmF0c21hbl90b3RhbCBydW4NCmpvaW5lZF9kYXRhJGJhdHNtYW5fdG90YWxydW4gJT4lIGJveHBsb3QobWFpbiA9ICJCb3hwbG90IGZvciB0b3RhbCBydW5zIGJ5IGJhdHNtYW4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bGFiID0gInJ1bnMgYnkgYmF0c21hbiBpbiB0b3RhbCIpDQpgYGANCmBgYHtyfQ0KI2JveHBsb3QgZm9yIGV4dHJhcyBib3dsZWQNCmpvaW5lZF9kYXRhJGV4dHJhcyAlPiUgYm94cGxvdChtYWluID0gIkJveHBsb3QgZm9yIGV4dHJhIHJ1bnMgZ2l2ZW4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bGFiID0gImV4dHJhIHJ1bnMgaW4gbWF0Y2giKQ0KYGBgDQpgYGB7cn0NCmhlYWQoam9pbmVkX2RhdGEpDQpgYGANCg0KYGBge3J9DQojdXNpbmcgenNjb3JlcyB0byBlbGltaW5hdGUgb3V0bGllcnMgYnV0IGl0IGRpZCBub3Qgd29yayBhZnRlciBhIGdsaW1wc2Ugb2YgY2hhbmdlZCBkYXRhLiBTbyB3ZW50IGZvciBjYXBwaW5nDQp6LnNjb3JlcyA8LSBqb2luZWRfZGF0YSRzdHJpa2VfcmF0ZSAlPiUgIHNjb3Jlcyh0eXBlID0gInoiKQ0Kam9pbmVkX2NsZWFuMTwtIGpvaW5lZF9kYXRhJHN0cmlrZV9yYXRlWyAtIHdoaWNoKCBhYnMoei5zY29yZXMpID4zICldDQoNCmBgYA0KYGBge3J9DQojYm94cGxvdCBmb3Igc3RyaWtlIHJhdGUNCmpvaW5lZF9kYXRhJHN0cmlrZV9yYXRlICU+JSBib3hwbG90KG1haW4gPSAiQm94cGxvdCBmb3Igc3RyaWtlIHJhdGUgb2YgYmF0c21hbiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlsYWIgPSAiUGVyIDEwMCBiYWxscyIpDQpgYGANCg0KYGBge3J9DQojQ2FwcGluZyB0aGVzZSAyIHZhcmlhYmxlcyBhbG9uZSBzaW5jZSBvdXRsaWVycyB3ZXJlIHByZXNlbnQNCmNhcHBpbmcgPC0gZnVuY3Rpb24oeCl7DQogIHF1YW50aWxlcyA8LSBxdWFudGlsZSggeCwgYyguMDUsIDAuMjUsIDAuNzUsIC45NSApICkNCiAgeFsgeCA8IHF1YW50aWxlc1syXSAtIDEuNSpJUVIoeCkgXSA8LSBxdWFudGlsZXNbMV0NCiAgeFsgeCA+IHF1YW50aWxlc1szXSArIDEuNSpJUVIoeCkgXSA8LSBxdWFudGlsZXNbNF0NCiAgeA0KfQ0KDQoNCiNjYXBwaW5nIHRoZSBvdXRsaWVycyBwcmVzZW50IGZvciBob21lX3dpbl9wZXJjZW50YWdlIGFuZCBhd2F5X3dpbl9wZXJjZW50YWdlDQpqb2luZWRfZGF0YSRiYXRzbWFuX3J1bnMgPC0gam9pbmVkX2RhdGEkYmF0c21hbl9ydW5zICU+JSBjYXBwaW5nKCkNCmpvaW5lZF9kYXRhJGV4dHJhX3J1bnMgPC0gam9pbmVkX2RhdGEkZXh0cmFfcnVucyAlPiUgY2FwcGluZygpDQoNCg0KYGBgDQoNCg0KYGBge3J9DQpqb2luZWRfZGF0YSA8LSBqb2luZWRfZGF0YSAlPiUgZ3JvdXBfYnkoYmF0c21hbikgJT4lIG11dGF0ZShiYXRzbWFuX3RvdGFscnVuID0gc3VtKHRvdGFsX3J1bnMpLCBzdHJpa2VfcmF0ZSA9IG1lYW4oYmF0c21hbl9ydW5zKSAqIDEwMCkNCmpvaW5lZF9kYXRhIDwtIGpvaW5lZF9kYXRhICU+JSBncm91cF9ieShib3dsaW5nX3RlYW0sU2Vhc29uLGRhdGUpICU+JSBtdXRhdGUoZXh0cmFzID0gc3VtKGV4dHJhX3J1bnMpKQ0KaGVhZChqb2luZWRfZGF0YSkNCg0KYGBgDQoNCg0KDQoNCg0KDQojIwlUcmFuc2Zvcm0gDQoNClVzaW5nIGFsbCB0cmFuc2Zvcm1hdGlvbiB0ZWNobmlxdWVzIGZvciBzdHJpa2UgcmF0ZSBhbmQgZXh0cmFzLiBNaW5fbWF4IHR1cm5lZCBvdXQgdG8gYmUgdGhlIGJlc3QNCg0KDQpgYGB7cn0NCmhpc3Qoam9pbmVkX2RhdGEkc3RyaWtlX3JhdGUpDQpgYGANCmBgYHtyfQ0KaGlzdChqb2luZWRfZGF0YSRleHRyYXMpDQpgYGANCmBgYHtyfQ0KaGlzdChqb2luZWRfZGF0YSRiYXRzbWFuX3RvdGFscnVuKQ0KYGBgDQoNCmBgYHtyfQ0KbG9nX3N0cmlrZSA8LSBsb2cxMChqb2luZWRfZGF0YSRzdHJpa2VfcmF0ZSkNCmhpc3QobG9nX3N0cmlrZSkNCmBgYA0KYGBge3J9DQpsb2dfc3RyaWtlIDwtIGxvZyhqb2luZWRfZGF0YSRzdHJpa2VfcmF0ZSkNCmhpc3QobG9nX3N0cmlrZSkNCmBgYA0KYGBge3J9DQpzcXJ0X3N0cmlrZSA8LSBzcXJ0KGpvaW5lZF9kYXRhJHN0cmlrZV9yYXRlKQ0KaGlzdChzcXJ0X3N0cmlrZSkNCmBgYA0KDQpgYGB7cn0NCm1pbk1heE1ldGhvZCA8LSBmdW5jdGlvbih4KSB7DQogICh4LW1pbih4KSkgLyAobWF4KHgpIC0gbWluKHgpKQ0KfQ0KDQojdHJhbnNmb3JtaW5nIHRoZSB2YXJpYWJsZSBob21lX2F3YXlfd2luX3JhdGlvIHVzaW5nIG1pbi1tYXggdHJhbnNmb3JtYXRpb24NCmpvaW5lZF9kYXRhJHN0cmlrZV9yYXRlIDwtIGpvaW5lZF9kYXRhJHN0cmlrZV9yYXRlICU+JSBtaW5NYXhNZXRob2QoKQ0KaGlzdChqb2luZWRfZGF0YSRzdHJpa2VfcmF0ZSkNCmBgYA0KDQoNCg==