Required packages

library(readr)
library(dplyr)
library(tidyr)
library(gdata)
library(rvest)
library(knitr)
library(outliers)
library(datasets)
library(lubridate)
library(ggplot2)
library(forecast)

Executive Summary

The GDP is a measure to gauge the health of an economy and represents total value of goods and services produced in an economy. The aim of this assignment to analyse the GDP by country and pre-process data by using the knowledge acquired throughout data pre-processing module.

The two dataset used for the purpose of this assignment about the GDP of the countries around the world which was obtained from the World Bank Data. The data sets GDP.csv and CountryInfo.csv was read using the readr and merged using left_join. After that, a detail check of data structure and attributes were done for each data frames. Some variables were in numerical, character. Some of the variables were changed as ordered or unordered factors. Since the GDP data frame does not conform the tidy principles, I have converted it to tidy format by using gather function to keep all the year variables in one column. Followed by that, a a new variable called GDP growth rate for 2015 – 2016 was created using mutate function to show the growth rates of GDP for each country for respective years.

There were a few countries which did not report statistics to World Bank and therefore it was missing in the data frame. Missing values were imputed using the average GDP for the respective countries. After replacing missing values with average GDP, outliers were checked using z-scores method and found out that two countries which are largest economies stands out all the other and may affect the results if it were not removed. Therefore, those three countries were removed before further analysis. Since the data was skewed to right, it was transformed using logarithm function to normalise that data.

Data

The data used in this assignment was obtained from the World Bank Data Library and can be accessed from the link https://databank.worldbank.org/data/source/world-development-indicators. There are three data sets, GDP, Revenue and countryInfo. All three data sets were merged to analyse indicators based on GDP, revenue and by country.

GDP <- read_csv("D:/Analytics/Semester 1/Data Preprocessing/Assignment 3/GDP/GDP.csv")
Parsed with column specification:
cols(
  .default = col_double(),
  `Country Name` = col_character(),
  `Country Code` = col_character(),
  `Indicator Name` = col_character(),
  `Indicator Code` = col_character()
)
See spec(...) for full column specifications.
CountryInfo <- read_csv("GDP/Metadata_Country_API_NY.GDP.MKTP.CD_DS2_en_csv_v2_10576830.csv")
Missing column names filled in: 'X6' [6]Parsed with column specification:
cols(
  `Country Code` = col_character(),
  Region = col_character(),
  IncomeGroup = col_character(),
  SpecialNotes = col_character(),
  TableName = col_character(),
  X6 = col_logical()
)

Gross Domestic Product (GDP)

GDP represents global output and has GDP for 264 countries from 2000 to 2017.

Varibales

Country Name : Name of the country

Country Code : Code give to the country by World Bank

Indicator Name : Name of the indicator, in this case GDP

Indicator Code_ : Unique code to identify indicator

The table also has total GDP by country from 2000 to 2017

head(GDP)

Country Info

Varibales

Country Code : Code give to the country by World Bank

Region : Geographical regions for countries that represents a a group of countries

IncomeGroup : Income groups from hihg income to

TableName : Name of the country

head(CountryInfo)

Merging data sets

GDPCombined <- GDP %>% left_join(CountryInfo, by="Country Code")

head(GDPCombined)

Understand

In this section I have checked structre of the data sets using str() function. The str() functions checks the structure such dimension, column names type of variables etc.

In the GDP data set, Country Name, Country Code, Indicator Name, Indicator Code are qualitative variables. Meanwhile, GDP for the years 2010 to 2017 are continous quantitative variables.

str(GDP)
Classes ‘spec_tbl_df’, ‘tbl_df’, ‘tbl’ and 'data.frame':    264 obs. of  22 variables:
 $ Country Name  : chr  "Aruba" "Afghanistan" "Angola" "Albania" ...
 $ Country Code  : chr  "ABW" "AFG" "AGO" "ALB" ...
 $ Indicator Name: chr  "GDP (current US$)" "GDP (current US$)" "GDP (current US$)" "GDP (current US$)" ...
 $ Indicator Code: chr  "NY.GDP.MKTP.CD" "NY.GDP.MKTP.CD" "NY.GDP.MKTP.CD" "NY.GDP.MKTP.CD" ...
 $ 2000          : num  1.87e+09 NA 9.13e+09 3.48e+09 1.43e+09 ...
 $ 2001          : num  1.92e+09 NA 8.94e+09 3.92e+09 1.50e+09 ...
 $ 2002          : num  1.94e+09 4.06e+09 1.53e+10 4.35e+09 1.73e+09 ...
 $ 2003          : num  2.02e+09 4.52e+09 1.78e+10 5.61e+09 2.40e+09 ...
 $ 2004          : num  2.23e+09 5.23e+09 2.36e+10 7.18e+09 2.94e+09 ...
 $ 2005          : num  2.33e+09 6.21e+09 3.70e+10 8.05e+09 3.26e+09 ...
 $ 2006          : num  2.42e+09 6.97e+09 5.24e+10 8.90e+09 3.54e+09 ...
 $ 2007          : num  2.62e+09 9.75e+09 6.53e+10 1.07e+10 4.02e+09 ...
 $ 2008          : num  2.75e+09 1.01e+10 8.85e+10 1.29e+10 4.01e+09 ...
 $ 2009          : num  2.50e+09 1.24e+10 7.03e+10 1.20e+10 3.66e+09 ...
 $ 2010          : num  2.39e+09 1.59e+10 8.38e+10 1.19e+10 3.36e+09 ...
 $ 2011          : num  2.55e+09 1.78e+10 1.12e+11 1.29e+10 3.44e+09 ...
 $ 2012          : num  2.53e+09 1.99e+10 1.28e+11 1.23e+10 3.16e+09 ...
 $ 2013          : num  2.58e+09 2.06e+10 1.37e+11 1.28e+10 3.28e+09 ...
 $ 2014          : num  2.65e+09 2.05e+10 1.46e+11 1.32e+10 3.35e+09 ...
 $ 2015          : num  2.69e+09 1.99e+10 1.16e+11 1.14e+10 2.81e+09 ...
 $ 2016          : num  2.65e+09 1.90e+10 1.01e+11 1.19e+10 2.88e+09 ...
 $ 2017          : num  2.70e+09 1.95e+10 1.22e+11 1.30e+10 3.01e+09 ...
 - attr(*, "spec")=
  .. cols(
  ..   `Country Name` = col_character(),
  ..   `Country Code` = col_character(),
  ..   `Indicator Name` = col_character(),
  ..   `Indicator Code` = col_character(),
  ..   `2000` = col_double(),
  ..   `2001` = col_double(),
  ..   `2002` = col_double(),
  ..   `2003` = col_double(),
  ..   `2004` = col_double(),
  ..   `2005` = col_double(),
  ..   `2006` = col_double(),
  ..   `2007` = col_double(),
  ..   `2008` = col_double(),
  ..   `2009` = col_double(),
  ..   `2010` = col_double(),
  ..   `2011` = col_double(),
  ..   `2012` = col_double(),
  ..   `2013` = col_double(),
  ..   `2014` = col_double(),
  ..   `2015` = col_double(),
  ..   `2016` = col_double(),
  ..   `2017` = col_double()
  .. )

In the county information data set, Income group is an ordinal qualitative variable which can be ordered based on the income level. The region is a multinominal qualitative variable.

str(CountryInfo)
Classes ‘spec_tbl_df’, ‘tbl_df’, ‘tbl’ and 'data.frame':    263 obs. of  6 variables:
 $ Country Code: chr  "ABW" "AFG" "AGO" "ALB" ...
 $ Region      : chr  "Latin America & Caribbean" "South Asia" "Sub-Saharan Africa" "Europe & Central Asia" ...
 $ IncomeGroup : chr  "High income" "Low income" "Lower middle income" "Upper middle income" ...
 $ SpecialNotes: chr  "Central Bureau of Statistics and Central Bank of Aruba ; Source of population estimates: UN Population Division"| __truncated__ "Central Statistics Organization; World Bank staff estimates ; Source of population estimates: UN Population Div"| __truncated__ "IMF ; Source of population estimates: UN Population Division's World Population Prospects 2019 PROVISIONAL esti"| __truncated__ "Albanian Institute of Statistics ; Source of population estimates: Institute of Statistics, Eurostat" ...
 $ TableName   : chr  "Aruba" "Afghanistan" "Angola" "Albania" ...
 $ X6          : logi  NA NA NA NA NA NA ...
 - attr(*, "spec")=
  .. cols(
  ..   `Country Code` = col_character(),
  ..   Region = col_character(),
  ..   IncomeGroup = col_character(),
  ..   SpecialNotes = col_character(),
  ..   TableName = col_character(),
  ..   X6 = col_logical()
  .. )
class(GDP)
[1] "spec_tbl_df" "tbl_df"      "tbl"         "data.frame" 
class(CountryInfo)
[1] "spec_tbl_df" "tbl_df"      "tbl"         "data.frame" 

Check for attributes in data

## attributes of GDP data frame
attributes(GDP)
$names
 [1] "Country Name"   "Country Code"   "Indicator Name" "Indicator Code" "2000"           "2001"          
 [7] "2002"           "2003"           "2004"           "2005"           "2006"           "2007"          
[13] "2008"           "2009"           "2010"           "2011"           "2012"           "2013"          
[19] "2014"           "2015"           "2016"           "2017"          

$class
[1] "spec_tbl_df" "tbl_df"      "tbl"         "data.frame" 

$row.names
  [1]   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29
 [30]  30  31  32  33  34  35  36  37  38  39  40  41  42  43  44  45  46  47  48  49  50  51  52  53  54  55  56  57  58
 [59]  59  60  61  62  63  64  65  66  67  68  69  70  71  72  73  74  75  76  77  78  79  80  81  82  83  84  85  86  87
 [88]  88  89  90  91  92  93  94  95  96  97  98  99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
[117] 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
[146] 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
[175] 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
[204] 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
[233] 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
[262] 262 263 264

$spec
cols(
  `Country Name` = col_character(),
  `Country Code` = col_character(),
  `Indicator Name` = col_character(),
  `Indicator Code` = col_character(),
  `2000` = col_double(),
  `2001` = col_double(),
  `2002` = col_double(),
  `2003` = col_double(),
  `2004` = col_double(),
  `2005` = col_double(),
  `2006` = col_double(),
  `2007` = col_double(),
  `2008` = col_double(),
  `2009` = col_double(),
  `2010` = col_double(),
  `2011` = col_double(),
  `2012` = col_double(),
  `2013` = col_double(),
  `2014` = col_double(),
  `2015` = col_double(),
  `2016` = col_double(),
  `2017` = col_double()
)
## atrributes of country information
attributes(CountryInfo)
$names
[1] "Country Code" "Region"       "IncomeGroup"  "SpecialNotes" "TableName"    "X6"          

$class
[1] "spec_tbl_df" "tbl_df"      "tbl"         "data.frame" 

$row.names
  [1]   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29
 [30]  30  31  32  33  34  35  36  37  38  39  40  41  42  43  44  45  46  47  48  49  50  51  52  53  54  55  56  57  58
 [59]  59  60  61  62  63  64  65  66  67  68  69  70  71  72  73  74  75  76  77  78  79  80  81  82  83  84  85  86  87
 [88]  88  89  90  91  92  93  94  95  96  97  98  99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
[117] 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
[146] 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
[175] 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
[204] 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
[233] 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
[262] 262 263

$spec
cols(
  `Country Code` = col_character(),
  Region = col_character(),
  IncomeGroup = col_character(),
  SpecialNotes = col_character(),
  TableName = col_character(),
  X6 = col_logical()
)

Data conversions

After checking structure of the data, it was obvious that some varables has to be convered as a factor. Income Group and Region which are in character seems more appropriate if they are as factor. Hence they were converted as factors.

## converting income group as an ordered factor
GDPCombined$IncomeGroup <- factor(GDPCombined$IncomeGroup,
                                        levels=c('Low income',
                                                 'Lower middle income',
                                                 'Upper middle income',
                                                 'High income'),
                                        labels = c('Low',
                                                   'Lower middle',
                                                   'Upper middle',
                                                   'High'),
                                        ordered=TRUE)
## converting region as a factor
GDPCombined$Region <- factor(GDPCombined$Region,
                             levels=c('Latin America & Caribbean',
                                           'South Asia',
                                           'Sub-Saharan Africa',
                                           'Europe & Central Asia',
                                           'Middle East & North Africa',
                                           'East Asia & Pacific',
                                           'North America'))
str(GDPCombined)
Classes ‘spec_tbl_df’, ‘tbl_df’, ‘tbl’ and 'data.frame':    264 obs. of  27 variables:
 $ Country Name  : chr  "Aruba" "Afghanistan" "Angola" "Albania" ...
 $ Country Code  : chr  "ABW" "AFG" "AGO" "ALB" ...
 $ Indicator Name: chr  "GDP (current US$)" "GDP (current US$)" "GDP (current US$)" "GDP (current US$)" ...
 $ Indicator Code: chr  "NY.GDP.MKTP.CD" "NY.GDP.MKTP.CD" "NY.GDP.MKTP.CD" "NY.GDP.MKTP.CD" ...
 $ 2000          : num  1.87e+09 NA 9.13e+09 3.48e+09 1.43e+09 ...
 $ 2001          : num  1.92e+09 NA 8.94e+09 3.92e+09 1.50e+09 ...
 $ 2002          : num  1.94e+09 4.06e+09 1.53e+10 4.35e+09 1.73e+09 ...
 $ 2003          : num  2.02e+09 4.52e+09 1.78e+10 5.61e+09 2.40e+09 ...
 $ 2004          : num  2.23e+09 5.23e+09 2.36e+10 7.18e+09 2.94e+09 ...
 $ 2005          : num  2.33e+09 6.21e+09 3.70e+10 8.05e+09 3.26e+09 ...
 $ 2006          : num  2.42e+09 6.97e+09 5.24e+10 8.90e+09 3.54e+09 ...
 $ 2007          : num  2.62e+09 9.75e+09 6.53e+10 1.07e+10 4.02e+09 ...
 $ 2008          : num  2.75e+09 1.01e+10 8.85e+10 1.29e+10 4.01e+09 ...
 $ 2009          : num  2.50e+09 1.24e+10 7.03e+10 1.20e+10 3.66e+09 ...
 $ 2010          : num  2.39e+09 1.59e+10 8.38e+10 1.19e+10 3.36e+09 ...
 $ 2011          : num  2.55e+09 1.78e+10 1.12e+11 1.29e+10 3.44e+09 ...
 $ 2012          : num  2.53e+09 1.99e+10 1.28e+11 1.23e+10 3.16e+09 ...
 $ 2013          : num  2.58e+09 2.06e+10 1.37e+11 1.28e+10 3.28e+09 ...
 $ 2014          : num  2.65e+09 2.05e+10 1.46e+11 1.32e+10 3.35e+09 ...
 $ 2015          : num  2.69e+09 1.99e+10 1.16e+11 1.14e+10 2.81e+09 ...
 $ 2016          : num  2.65e+09 1.90e+10 1.01e+11 1.19e+10 2.88e+09 ...
 $ 2017          : num  2.70e+09 1.95e+10 1.22e+11 1.30e+10 3.01e+09 ...
 $ Region        : chr  "Latin America & Caribbean" "South Asia" "Sub-Saharan Africa" "Europe & Central Asia" ...
 $ IncomeGroup   : chr  "High income" "Low income" "Lower middle income" "Upper middle income" ...
 $ SpecialNotes  : chr  "Central Bureau of Statistics and Central Bank of Aruba ; Source of population estimates: UN Population Division"| __truncated__ "Central Statistics Organization; World Bank staff estimates ; Source of population estimates: UN Population Div"| __truncated__ "IMF ; Source of population estimates: UN Population Division's World Population Prospects 2019 PROVISIONAL esti"| __truncated__ "Albanian Institute of Statistics ; Source of population estimates: Institute of Statistics, Eurostat" ...
 $ TableName     : chr  "Aruba" "Afghanistan" "Angola" "Albania" ...
 $ X6            : logi  NA NA NA NA NA NA ...

Tidy & Manipulate Data I

As a first step I have excluded the variables which are not necessary for the data manipulation.

The data set does not confom Hadley Wickham’s Tidy Data Principles as the years are spread across many columns which should be in one column. Therefore, I have used gather() function to transform the data from wide to long format to make it tidy.

## Excluding unwanted variables
GDPCombined_clean <- GDPCombined %>% select(-`Indicator Name`, -`Indicator Code`, -SpecialNotes, -TableName, -X6)
GDPCombined_clean
NA
## Tranformation of data using gather function
GDPCombined_tidy1 <- GDPCombined_clean%>% gather(key = "YEAR", value = "GDP", 3:20)
GDPCombined_tidy1
NA
NA

Tidy & Manipulate Data II

GDP Growth rate for 2015 to 2017 was calculated by creating an addition column for GDP growth rate for each country. In order to do this, I created a new data set by filtering 2015, 2016 and 2017.

# Filter observation for 2015, 2016 & 2017 

GDP2015_2017 <- GDPCombined_tidy1 %>% filter(YEAR==2014|YEAR==2015|YEAR==2017|YEAR==2016)

# Calculate GDP growth for 2015, 2016 and 2017
GDPGrowthRates<- GDPCombined_tidy1 %>% filter(YEAR==2014|YEAR==2015|YEAR==2017|YEAR==2016) %>%
  group_by(`Country Name`) %>% mutate(GrowthRates = 
                                      ((GDP/lag(GDP) - 1) * 100))

GDPGrowthRates %>% filter(YEAR==2015|YEAR==2017|YEAR==2016)
NA

Scan I

Scanning for missing values

As a first step I have calculated total missing values for GDP by country.

## Total missing values by country
GDPScan1 <- GDPCombined_tidy1 %>% group_by(`Country Name`) %>% summarise(GDP_NA=sum(is.na(GDP)))

GDPScan1

After that, missing values of GDP are replaced with average GDP with respective country averages. For this, I have first calculated averages GDP for each country by removing missing values.

## Average GDP by country
GDPCombined_tidy1 %>% group_by(`Country Name`) %>% summarise(Average=mean(GDP, na.rm = TRUE))
NA

Missing values are then replaced with averages using impute function which is created to impute missing data, and saved it as GDPScan1_imputed

## Imputing missing values in the GDP column with the mean values of each country.

GDPScan1_imputed <- GDPCombined_tidy1

GDPScan1_imputed$GDP[is.na(GDPScan1_imputed$GDP)] <- ave(GDPScan1_imputed$GDP, GDPScan1_imputed$`Country Name`, FUN = function(x)mean(x, na.rm = TRUE))[is.na(GDPScan1_imputed$GDP)]

GDPScan1_imputed
NA

After that a check on each variable is done for missing values again to make sure if there are no missing values after imputation.

## Checking if there is any missing variable in country name
GDPScan1_imputed %>% subset(is.na(`Country Name`))
## Checking if there is any missing variable in country code
GDPScan1_imputed %>% subset(is.na(`Country Code`))
## Checking if there is any missing variable in Year
GDPScan1_imputed %>% subset(is.na(YEAR))
## Checking if there is any missing variable in GDP
GDPScan1_imputed %>% subset(is.na(GDP))
## Checking if there is any missing variable in Income Group
GDPScan1_imputed %>% subset(is.na(IncomeGroup))
## Checking if there is any missing variable in Region
GDPScan1_imputed %>% subset(is.na(Region))

After checking for missing values, a new data frame is created with complete cases.

GDP_clean <- GDPScan1_imputed
GDP_clean
sum(is.na(GDP_clean$GDP))
[1] 144

Check for special values

After checking for missing values, I have then checked the variables for special values

## a function to check for special values
is.special<- function(x){ 
  if(is.numeric(x)) !is.finite(x) else is.na(x) 
  } 
is.special<- function(x){
  if(is.numeric(x)) !is.finite(x) 
}

## check for special values in GDP using is.special function 
SpecialValues <- sapply(GDP_clean$GDP, is.special)

#Count the number of special values
length(SpecialValues[SpecialValues=="TRUE"])
[1] 144

There are 144 special characters which mostly comes from the coutries where there are no data at all and hence no mean value was estimated. These rows were excluded using completed cases function below.

## check the whole data frame for missing values
GDP_clean[!complete.cases(GDP_clean),]
NA

The cleaned data frame (GDP_Clean) does not have any missing or special values now and can be using for further analysis.

Scan II

Check for outliers

In order to check for outliers, I have used z-scores method. z-score is a distance based method and a value is treated as an outlier if the absolute value of z-score is greater than 3.

z.scores <- GDP_clean$GDP[!is.na(GDP_clean$GDP)] %>% scores(type = "z")

summary(z.scores)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
-0.2958 -0.2949 -0.2900  0.0000 -0.2360  8.8657 

The minimum z-score is -0.2958 and the maximum is 8.8657. In order to check the location of the z-scores whose absoluet value is greater than 3, I have used which() function

## Saving outliers entries as a separate data frame
Outliers <- GDP_2017_imputed[which(abs(z.scores)>3),]

## Outliers by country
Outliers %>% count(`Country Name`)
NA

Six countries are treated as outliers as it exceed maximum threshold under z-scores and those countries will be removed from further analysis.

## Saving outliers entries as a separate data frame
GDP_clean_outlierexc <- GDP_2017_imputed %>% filter(`Country Name` !="Guam", `Country Name` !="Hungary", `Country Name` !="Korea, Dem. People<U+0092>s Rep.", `Country Name` !="Liechtenstein",  `Country Name` !="Norway",  `Country Name` !="United States",)

GDP_clean_outlierexc
NA

Transform

In this section I have used GDP as the variable for transformation. Prior to transformation, a histogram was drawn to check the skewness of the data.

Apply an appropriate transformation for at least one of the variables. In addition to the R codes and outputs, explain everything that you do in this step. In this step, you should fulfil the minimum requirement #9.

## Histogram of GDP
par(mfrow = c(1,2))

hist(GDP_clean_outlierexc$GDP, main = "Histogram for GDP" , xlab = "GDP")

GDP_log <- log(GDP_clean_outlierexc$GDP)

hist(GDP_log)

The histogram (right) shows that the data are skewed to right. Moreover, as the values are very high, the numbers does not show properly. Hence, to tranform it to normal, I have used logarithmic transformation to get rid of right skewness which can be seen from the left histogram



LS0tDQp0aXRsZTogIkFuIGFwcHJvYWNoIHRvIHByZXByb2Nlc3MgZGF0YSBvbiBHRFAgYnkgY291bnRyeSINCmF1dGhvcjogIk11YmFhaCBNb2hhbWVkIChTMzY0Njk2MykiDQpzdWJ0aXRsZTogQXNzaWdubWVudCAzDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBkZl9wcmludDogcGFnZWQNCi0tLQ0KDQojIyBSZXF1aXJlZCBwYWNrYWdlcyANCg0KDQpgYGB7cn0NCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkoZ2RhdGEpDQpsaWJyYXJ5KHJ2ZXN0KQ0KbGlicmFyeShrbml0cikNCmxpYnJhcnkob3V0bGllcnMpDQpsaWJyYXJ5KGRhdGFzZXRzKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGZvcmVjYXN0KQ0KDQpgYGANCg0KDQojIyBFeGVjdXRpdmUgU3VtbWFyeSANCg0KDQpUaGUgR0RQIGlzIGEgbWVhc3VyZSB0byBnYXVnZSB0aGUgaGVhbHRoIG9mIGFuIGVjb25vbXkgYW5kIHJlcHJlc2VudHMgdG90YWwgdmFsdWUgb2YgZ29vZHMgYW5kIHNlcnZpY2VzIHByb2R1Y2VkIGluIGFuIGVjb25vbXkuIFRoZSBhaW0gb2YgdGhpcyBhc3NpZ25tZW50IHRvIGFuYWx5c2UgdGhlIEdEUCBieSBjb3VudHJ5IGFuZCBwcmUtcHJvY2VzcyBkYXRhIGJ5IHVzaW5nIHRoZSBrbm93bGVkZ2UgYWNxdWlyZWQgdGhyb3VnaG91dCBkYXRhIHByZS1wcm9jZXNzaW5nIG1vZHVsZS4NCg0KVGhlIHR3byBkYXRhc2V0IHVzZWQgZm9yIHRoZSBwdXJwb3NlIG9mIHRoaXMgYXNzaWdubWVudCBhYm91dCB0aGUgR0RQIG9mIHRoZSBjb3VudHJpZXMgYXJvdW5kIHRoZSB3b3JsZCB3aGljaCB3YXMgb2J0YWluZWQgZnJvbSB0aGUgV29ybGQgQmFuayBEYXRhLiBUaGUgZGF0YSBzZXRzIEdEUC5jc3YgYW5kIENvdW50cnlJbmZvLmNzdiB3YXMgcmVhZCB1c2luZyB0aGUgcmVhZHIgYW5kIG1lcmdlZCB1c2luZyBsZWZ0X2pvaW4uIA0KQWZ0ZXIgdGhhdCwgYSBkZXRhaWwgY2hlY2sgb2YgZGF0YSBzdHJ1Y3R1cmUgYW5kIGF0dHJpYnV0ZXMgd2VyZSBkb25lIGZvciBlYWNoIGRhdGEgZnJhbWVzLiBTb21lIHZhcmlhYmxlcyB3ZXJlIGluIG51bWVyaWNhbCwgY2hhcmFjdGVyLiBTb21lIG9mIHRoZSB2YXJpYWJsZXMgd2VyZSBjaGFuZ2VkIGFzIG9yZGVyZWQgb3IgdW5vcmRlcmVkIGZhY3RvcnMuIFNpbmNlIHRoZSBHRFAgZGF0YSBmcmFtZSBkb2VzIG5vdCBjb25mb3JtIHRoZSB0aWR5IHByaW5jaXBsZXMsIEkgaGF2ZSBjb252ZXJ0ZWQgaXQgdG8gdGlkeSBmb3JtYXQgYnkgdXNpbmcgZ2F0aGVyIGZ1bmN0aW9uIHRvIGtlZXAgYWxsIHRoZSB5ZWFyIHZhcmlhYmxlcyBpbiBvbmUgY29sdW1uLiBGb2xsb3dlZCBieSB0aGF0LCBhIGEgbmV3IHZhcmlhYmxlIGNhbGxlZCBHRFAgZ3Jvd3RoIHJhdGUgZm9yIDIwMTUg4oCTIDIwMTYgd2FzIGNyZWF0ZWQgdXNpbmcgbXV0YXRlIGZ1bmN0aW9uIHRvIHNob3cgdGhlIGdyb3d0aCByYXRlcyBvZiBHRFAgZm9yIGVhY2ggY291bnRyeSBmb3IgcmVzcGVjdGl2ZSB5ZWFycy4NCg0KVGhlcmUgd2VyZSBhIGZldyBjb3VudHJpZXMgd2hpY2ggZGlkIG5vdCByZXBvcnQgc3RhdGlzdGljcyB0byBXb3JsZCBCYW5rIGFuZCB0aGVyZWZvcmUgaXQgd2FzIG1pc3NpbmcgaW4gdGhlIGRhdGEgZnJhbWUuIE1pc3NpbmcgdmFsdWVzIHdlcmUgaW1wdXRlZCB1c2luZyB0aGUgYXZlcmFnZSBHRFAgZm9yIHRoZSByZXNwZWN0aXZlIGNvdW50cmllcy4gQWZ0ZXIgcmVwbGFjaW5nIG1pc3NpbmcgdmFsdWVzIHdpdGggYXZlcmFnZSBHRFAsIG91dGxpZXJzIHdlcmUgY2hlY2tlZCB1c2luZyB6LXNjb3JlcyBtZXRob2QgYW5kIGZvdW5kIG91dCB0aGF0IHR3byBjb3VudHJpZXMgd2hpY2ggYXJlIGxhcmdlc3QgZWNvbm9taWVzIHN0YW5kcyBvdXQgYWxsIHRoZSBvdGhlciBhbmQgbWF5IGFmZmVjdCB0aGUgcmVzdWx0cyBpZiBpdCB3ZXJlIG5vdCByZW1vdmVkLiBUaGVyZWZvcmUsIHRob3NlIHRocmVlIGNvdW50cmllcyB3ZXJlIHJlbW92ZWQgYmVmb3JlIGZ1cnRoZXIgYW5hbHlzaXMuIFNpbmNlIHRoZSBkYXRhIHdhcyBza2V3ZWQgdG8gcmlnaHQsIGl0IHdhcyB0cmFuc2Zvcm1lZCB1c2luZyBsb2dhcml0aG0gZnVuY3Rpb24gdG8gbm9ybWFsaXNlIHRoYXQgZGF0YS4gDQoNCg0KDQojIyBEYXRhDQoNClRoZSBkYXRhIHVzZWQgaW4gdGhpcyBhc3NpZ25tZW50IHdhcyBvYnRhaW5lZCBmcm9tIHRoZSBXb3JsZCBCYW5rIERhdGEgTGlicmFyeSBhbmQgY2FuIGJlIGFjY2Vzc2VkIGZyb20gdGhlIGxpbmsgaHR0cHM6Ly9kYXRhYmFuay53b3JsZGJhbmsub3JnL2RhdGEvc291cmNlL3dvcmxkLWRldmVsb3BtZW50LWluZGljYXRvcnMuIFRoZXJlIGFyZSB0aHJlZSBkYXRhIHNldHMsIEdEUCwgUmV2ZW51ZSBhbmQgY291bnRyeUluZm8uIEFsbCB0aHJlZSBkYXRhIHNldHMgd2VyZSBtZXJnZWQgdG8gYW5hbHlzZSBpbmRpY2F0b3JzIGJhc2VkIG9uIEdEUCwgcmV2ZW51ZSBhbmQgYnkgY291bnRyeS4gDQoNCg0KYGBge3J9DQpHRFAgPC0gcmVhZF9jc3YoIkQ6L0FuYWx5dGljcy9TZW1lc3RlciAxL0RhdGEgUHJlcHJvY2Vzc2luZy9Bc3NpZ25tZW50IDMvR0RQL0dEUC5jc3YiKQ0KDQpDb3VudHJ5SW5mbyA8LSByZWFkX2NzdigiR0RQL01ldGFkYXRhX0NvdW50cnlfQVBJX05ZLkdEUC5NS1RQLkNEX0RTMl9lbl9jc3ZfdjJfMTA1NzY4MzAuY3N2IikNCmBgYA0KDQoNCiMjIyMgR3Jvc3MgRG9tZXN0aWMgUHJvZHVjdCAoR0RQKQ0KDQpHRFAgcmVwcmVzZW50cyBnbG9iYWwgb3V0cHV0IGFuZCBoYXMgR0RQIGZvciAyNjQgY291bnRyaWVzIGZyb20gMjAwMCB0byAyMDE3Lg0KDQoqKlZhcmliYWxlcyoqDQoNCioqX0NvdW50cnkgTmFtZV8qKiA6IE5hbWUgb2YgdGhlIGNvdW50cnkNCg0KKipfQ291bnRyeSBDb2RlXyoqIDogQ29kZSBnaXZlIHRvIHRoZSBjb3VudHJ5IGJ5IFdvcmxkIEJhbmsNCg0KKipfSW5kaWNhdG9yIE5hbWVfKiogOiBOYW1lIG9mIHRoZSBpbmRpY2F0b3IsIGluIHRoaXMgY2FzZSBHRFANCg0KKipJbmRpY2F0b3IgQ29kZV8qKiA6IFVuaXF1ZSBjb2RlIHRvIGlkZW50aWZ5IGluZGljYXRvcg0KDQpUaGUgdGFibGUgYWxzbyBoYXMgdG90YWwgR0RQIGJ5IGNvdW50cnkgZnJvbSAyMDAwIHRvIDIwMTcNCg0KDQpgYGB7cn0NCmhlYWQoR0RQKQ0KYGBgDQoNCg0KIyMjIyBDb3VudHJ5IEluZm8NCg0KKipWYXJpYmFsZXMqKg0KDQoqKl9Db3VudHJ5IENvZGVfKiogOiBDb2RlIGdpdmUgdG8gdGhlIGNvdW50cnkgYnkgV29ybGQgQmFuaw0KDQoqKl9SZWdpb25fKiogOiBHZW9ncmFwaGljYWwgcmVnaW9ucyBmb3IgY291bnRyaWVzIHRoYXQgcmVwcmVzZW50cyBhIGEgZ3JvdXAgb2YgY291bnRyaWVzDQoNCioqX0luY29tZUdyb3VwXyoqIDogSW5jb21lIGdyb3VwcyBmcm9tIGhpaGcgaW5jb21lIHRvDQoNCioqX1RhYmxlTmFtZV8qKiA6IE5hbWUgb2YgdGhlIGNvdW50cnkNCg0KYGBge3J9DQpoZWFkKENvdW50cnlJbmZvKQ0KYGBgDQoNCiMjIyMgTWVyZ2luZyBkYXRhIHNldHMNCg0KDQpgYGB7cn0NCkdEUENvbWJpbmVkIDwtIEdEUCAlPiUgbGVmdF9qb2luKENvdW50cnlJbmZvLCBieT0iQ291bnRyeSBDb2RlIikNCg0KaGVhZChHRFBDb21iaW5lZCkNCmBgYA0KDQojIyBVbmRlcnN0YW5kIA0KDQpJbiB0aGlzIHNlY3Rpb24gSSBoYXZlIGNoZWNrZWQgc3RydWN0cmUgb2YgdGhlIGRhdGEgc2V0cyB1c2luZyBzdHIoKSBmdW5jdGlvbi4gVGhlIHN0cigpIGZ1bmN0aW9ucyBjaGVja3MgdGhlIHN0cnVjdHVyZSBzdWNoIGRpbWVuc2lvbiwgY29sdW1uIG5hbWVzIHR5cGUgb2YgdmFyaWFibGVzIGV0Yy4NCg0KSW4gdGhlIEdEUCBkYXRhIHNldCwgQ291bnRyeSBOYW1lLCBDb3VudHJ5IENvZGUsIEluZGljYXRvciBOYW1lLCBJbmRpY2F0b3IgQ29kZSBhcmUgcXVhbGl0YXRpdmUgdmFyaWFibGVzLiBNZWFud2hpbGUsIEdEUCBmb3IgdGhlIHllYXJzIDIwMTAgdG8gMjAxNyBhcmUgY29udGlub3VzIHF1YW50aXRhdGl2ZSB2YXJpYWJsZXMuDQoNCmBgYHtyfQ0Kc3RyKEdEUCkNCmBgYA0KDQpJbiB0aGUgY291bnR5IGluZm9ybWF0aW9uIGRhdGEgc2V0LCBJbmNvbWUgZ3JvdXAgaXMgYW4gb3JkaW5hbCBxdWFsaXRhdGl2ZSB2YXJpYWJsZSB3aGljaCBjYW4gYmUgb3JkZXJlZCBiYXNlZCBvbiB0aGUgaW5jb21lIGxldmVsLiBUaGUgcmVnaW9uIGlzIGEgbXVsdGlub21pbmFsIHF1YWxpdGF0aXZlIHZhcmlhYmxlLg0KDQoNCmBgYHtyfQ0Kc3RyKENvdW50cnlJbmZvKQ0KYGBgDQoNCg0KYGBge3J9DQpjbGFzcyhHRFApDQpgYGANCg0KDQpgYGB7cn0NCmNsYXNzKENvdW50cnlJbmZvKQ0KYGBgDQoNCiMjIyMgQ2hlY2sgZm9yIGF0dHJpYnV0ZXMgaW4gZGF0YQ0KDQpgYGB7cn0NCiMjIGF0dHJpYnV0ZXMgb2YgR0RQIGRhdGEgZnJhbWUNCmF0dHJpYnV0ZXMoR0RQKQ0KYGBgDQoNCmBgYHtyfQ0KIyMgYXRycmlidXRlcyBvZiBjb3VudHJ5IGluZm9ybWF0aW9uDQphdHRyaWJ1dGVzKENvdW50cnlJbmZvKQ0KYGBgDQoNCg0KDQojIyMjIERhdGEgY29udmVyc2lvbnMNCg0KQWZ0ZXIgY2hlY2tpbmcgc3RydWN0dXJlIG9mIHRoZSBkYXRhLCBpdCB3YXMgb2J2aW91cyB0aGF0IHNvbWUgdmFyYWJsZXMgaGFzIHRvIGJlIGNvbnZlcmVkIGFzIGEgZmFjdG9yLiBJbmNvbWUgR3JvdXAgYW5kIFJlZ2lvbiB3aGljaCBhcmUgaW4gY2hhcmFjdGVyIHNlZW1zIG1vcmUgYXBwcm9wcmlhdGUgaWYgdGhleSBhcmUgYXMgZmFjdG9yLiBIZW5jZSB0aGV5IHdlcmUgY29udmVydGVkIGFzIGZhY3RvcnMuDQoNCg0KYGBge3J9DQojIyBjb252ZXJ0aW5nIGluY29tZSBncm91cCBhcyBhbiBvcmRlcmVkIGZhY3Rvcg0KR0RQQ29tYmluZWQkSW5jb21lR3JvdXAgPC0gZmFjdG9yKEdEUENvbWJpbmVkJEluY29tZUdyb3VwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscz1jKCdMb3cgaW5jb21lJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnTG93ZXIgbWlkZGxlIGluY29tZScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1VwcGVyIG1pZGRsZSBpbmNvbWUnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdIaWdoIGluY29tZScpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoJ0xvdycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnTG93ZXIgbWlkZGxlJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdVcHBlciBtaWRkbGUnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0hpZ2gnKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmRlcmVkPVRSVUUpDQpgYGANCg0KYGBge3J9DQojIyBjb252ZXJ0aW5nIHJlZ2lvbiBhcyBhIGZhY3Rvcg0KR0RQQ29tYmluZWQkUmVnaW9uIDwtIGZhY3RvcihHRFBDb21iaW5lZCRSZWdpb24sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscz1jKCdMYXRpbiBBbWVyaWNhICYgQ2FyaWJiZWFuJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnU291dGggQXNpYScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1N1Yi1TYWhhcmFuIEFmcmljYScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0V1cm9wZSAmIENlbnRyYWwgQXNpYScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ01pZGRsZSBFYXN0ICYgTm9ydGggQWZyaWNhJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnRWFzdCBBc2lhICYgUGFjaWZpYycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ05vcnRoIEFtZXJpY2EnKSkNCg0KYGBgDQoNCg0KYGBge3J9DQojIyBDaGVjayBmb3Igc3RydWN0dXJlIGFmdGVyIGNvbnZlcnRpbmcNCnN0cihHRFBDb21iaW5lZCkNCmBgYA0KDQoNCiMjCVRpZHkgJiBNYW5pcHVsYXRlIERhdGEgSQ0KDQpBcyBhIGZpcnN0IHN0ZXAgSSBoYXZlIGV4Y2x1ZGVkIHRoZSB2YXJpYWJsZXMgd2hpY2ggYXJlIG5vdCBuZWNlc3NhcnkgZm9yIHRoZSBkYXRhIG1hbmlwdWxhdGlvbi4gDQoNClRoZSBkYXRhIHNldCBkb2VzIG5vdCBjb25mb20gSGFkbGV5IFdpY2toYW0ncyBUaWR5IERhdGEgUHJpbmNpcGxlcyBhcyB0aGUgeWVhcnMgYXJlIHNwcmVhZCBhY3Jvc3MgbWFueSBjb2x1bW5zIHdoaWNoIHNob3VsZCBiZSBpbiBvbmUgY29sdW1uLiBUaGVyZWZvcmUsIEkgaGF2ZSB1c2VkIGdhdGhlcigpIGZ1bmN0aW9uIHRvIHRyYW5zZm9ybSB0aGUgZGF0YSBmcm9tIHdpZGUgdG8gbG9uZyBmb3JtYXQgdG8gbWFrZSBpdCB0aWR5Lg0KDQpgYGB7cn0NCiMjIEV4Y2x1ZGluZyB1bndhbnRlZCB2YXJpYWJsZXMNCkdEUENvbWJpbmVkX2NsZWFuIDwtIEdEUENvbWJpbmVkICU+JSBzZWxlY3QoLWBJbmRpY2F0b3IgTmFtZWAsIC1gSW5kaWNhdG9yIENvZGVgLCAtU3BlY2lhbE5vdGVzLCAtVGFibGVOYW1lLCAtWDYpDQpHRFBDb21iaW5lZF9jbGVhbg0KDQpgYGANCg0KYGBge3J9DQojIyBUcmFuZm9ybWF0aW9uIG9mIGRhdGEgdXNpbmcgZ2F0aGVyIGZ1bmN0aW9uDQpHRFBDb21iaW5lZF90aWR5MSA8LSBHRFBDb21iaW5lZF9jbGVhbiU+JSBnYXRoZXIoa2V5ID0gIllFQVIiLCB2YWx1ZSA9ICJHRFAiLCAzOjIwKQ0KR0RQQ29tYmluZWRfdGlkeTENCg0KDQpgYGANCg0KDQojIwlUaWR5ICYgTWFuaXB1bGF0ZSBEYXRhIElJDQoNCkdEUCBHcm93dGggcmF0ZSBmb3IgMjAxNSB0byAyMDE3IHdhcyBjYWxjdWxhdGVkIGJ5IGNyZWF0aW5nIGFuIGFkZGl0aW9uIGNvbHVtbiBmb3IgR0RQIGdyb3d0aCByYXRlIGZvciBlYWNoIGNvdW50cnkuIEluIG9yZGVyIHRvIGRvIHRoaXMsIEkgY3JlYXRlZCBhIG5ldyBkYXRhIHNldCBieSBmaWx0ZXJpbmcgMjAxNSwgMjAxNiBhbmQgMjAxNy4NCg0KDQpgYGB7cn0NCiMgRmlsdGVyIG9ic2VydmF0aW9uIGZvciAyMDE1LCAyMDE2ICYgMjAxNyANCg0KR0RQMjAxNV8yMDE3IDwtIEdEUENvbWJpbmVkX3RpZHkxICU+JSBmaWx0ZXIoWUVBUj09MjAxNHxZRUFSPT0yMDE1fFlFQVI9PTIwMTd8WUVBUj09MjAxNikNCg0KIyBDYWxjdWxhdGUgR0RQIGdyb3d0aCBmb3IgMjAxNSwgMjAxNiBhbmQgMjAxNw0KR0RQR3Jvd3RoUmF0ZXM8LSBHRFBDb21iaW5lZF90aWR5MSAlPiUgZmlsdGVyKFlFQVI9PTIwMTR8WUVBUj09MjAxNXxZRUFSPT0yMDE3fFlFQVI9PTIwMTYpICU+JQ0KICBncm91cF9ieShgQ291bnRyeSBOYW1lYCkgJT4lIG11dGF0ZShHcm93dGhSYXRlcyA9IA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoKEdEUC9sYWcoR0RQKSAtIDEpICogMTAwKSkNCg0KR0RQR3Jvd3RoUmF0ZXMgJT4lIGZpbHRlcihZRUFSPT0yMDE1fFlFQVI9PTIwMTd8WUVBUj09MjAxNikNCg0KYGBgDQoNCg0KIyMJU2NhbiBJIA0KDQojIyMjIFNjYW5uaW5nIGZvciBtaXNzaW5nIHZhbHVlcw0KDQpBcyBhIGZpcnN0IHN0ZXAgSSBoYXZlIGNhbGN1bGF0ZWQgdG90YWwgbWlzc2luZyB2YWx1ZXMgZm9yIEdEUCBieSBjb3VudHJ5LiANCg0KYGBge3J9DQojIyBUb3RhbCBtaXNzaW5nIHZhbHVlcyBieSBjb3VudHJ5DQpHRFBTY2FuMSA8LSBHRFBDb21iaW5lZF90aWR5MSAlPiUgZ3JvdXBfYnkoYENvdW50cnkgTmFtZWApICU+JSBzdW1tYXJpc2UoR0RQX05BPXN1bShpcy5uYShHRFApKSkNCg0KR0RQU2NhbjENCmBgYA0KDQpBZnRlciB0aGF0LCBtaXNzaW5nIHZhbHVlcyBvZiBHRFAgYXJlIHJlcGxhY2VkIHdpdGggYXZlcmFnZSBHRFAgd2l0aCByZXNwZWN0aXZlIGNvdW50cnkgYXZlcmFnZXMuDQpGb3IgdGhpcywgSSBoYXZlIGZpcnN0IGNhbGN1bGF0ZWQgYXZlcmFnZXMgR0RQIGZvciBlYWNoIGNvdW50cnkgYnkgcmVtb3ZpbmcgbWlzc2luZyB2YWx1ZXMuDQoNCg0KYGBge3J9DQojIyBBdmVyYWdlIEdEUCBieSBjb3VudHJ5DQpHRFBDb21iaW5lZF90aWR5MSAlPiUgZ3JvdXBfYnkoYENvdW50cnkgTmFtZWApICU+JSBzdW1tYXJpc2UoQXZlcmFnZT1tZWFuKEdEUCwgbmEucm0gPSBUUlVFKSkNCmBgYA0KDQpNaXNzaW5nIHZhbHVlcyBhcmUgdGhlbiByZXBsYWNlZCB3aXRoIGF2ZXJhZ2VzIHVzaW5nIGltcHV0ZSBmdW5jdGlvbiB3aGljaCBpcyBjcmVhdGVkIHRvIGltcHV0ZSBtaXNzaW5nDQpkYXRhLCBhbmQgc2F2ZWQgaXQgYXMgKipHRFBTY2FuMV9pbXB1dGVkKioNCg0KYGBge3J9DQojIyBJbXB1dGluZyBtaXNzaW5nIHZhbHVlcyBpbiB0aGUgR0RQIGNvbHVtbiB3aXRoIHRoZSBtZWFuIHZhbHVlcyBvZiBlYWNoIGNvdW50cnkuDQoNCkdEUFNjYW4xX2ltcHV0ZWQgPC0gR0RQQ29tYmluZWRfdGlkeTENCg0KR0RQU2NhbjFfaW1wdXRlZCRHRFBbaXMubmEoR0RQU2NhbjFfaW1wdXRlZCRHRFApXSA8LSBhdmUoR0RQU2NhbjFfaW1wdXRlZCRHRFAsIEdEUFNjYW4xX2ltcHV0ZWQkYENvdW50cnkgTmFtZWAsIEZVTiA9IGZ1bmN0aW9uKHgpbWVhbih4LCBuYS5ybSA9IFRSVUUpKVtpcy5uYShHRFBTY2FuMV9pbXB1dGVkJEdEUCldDQoNCkdEUFNjYW4xX2ltcHV0ZWQNCg0KYGBgDQoNCkFmdGVyIHRoYXQgYSBjaGVjayBvbiBlYWNoIHZhcmlhYmxlIGlzIGRvbmUgZm9yIG1pc3NpbmcgdmFsdWVzIGFnYWluIHRvIG1ha2Ugc3VyZSBpZiB0aGVyZSBhcmUgbm8gbWlzc2luZyB2YWx1ZXMgYWZ0ZXIgaW1wdXRhdGlvbi4NCg0KYGBge3J9DQojIyBDaGVja2luZyBpZiB0aGVyZSBpcyBhbnkgbWlzc2luZyB2YXJpYWJsZSBpbiBjb3VudHJ5IG5hbWUNCkdEUFNjYW4xX2ltcHV0ZWQgJT4lIHN1YnNldChpcy5uYShgQ291bnRyeSBOYW1lYCkpDQpgYGANCmBgYHtyfQ0KIyMgQ2hlY2tpbmcgaWYgdGhlcmUgaXMgYW55IG1pc3NpbmcgdmFyaWFibGUgaW4gY291bnRyeSBjb2RlDQpHRFBTY2FuMV9pbXB1dGVkICU+JSBzdWJzZXQoaXMubmEoYENvdW50cnkgQ29kZWApKQ0KYGBgDQoNCmBgYHtyfQ0KIyMgQ2hlY2tpbmcgaWYgdGhlcmUgaXMgYW55IG1pc3NpbmcgdmFyaWFibGUgaW4gWWVhcg0KR0RQU2NhbjFfaW1wdXRlZCAlPiUgc3Vic2V0KGlzLm5hKFlFQVIpKQ0KYGBgDQoNCmBgYHtyfQ0KIyMgQ2hlY2tpbmcgaWYgdGhlcmUgaXMgYW55IG1pc3NpbmcgdmFyaWFibGUgaW4gR0RQDQpHRFBTY2FuMV9pbXB1dGVkICU+JSBzdWJzZXQoaXMubmEoR0RQKSkNCmBgYA0KDQpgYGB7cn0NCiMjIENoZWNraW5nIGlmIHRoZXJlIGlzIGFueSBtaXNzaW5nIHZhcmlhYmxlIGluIEluY29tZSBHcm91cA0KR0RQU2NhbjFfaW1wdXRlZCAlPiUgc3Vic2V0KGlzLm5hKEluY29tZUdyb3VwKSkNCmBgYA0KDQoNCg0KYGBge3J9DQojIyBDaGVja2luZyBpZiB0aGVyZSBpcyBhbnkgbWlzc2luZyB2YXJpYWJsZSBpbiBSZWdpb24NCkdEUFNjYW4xX2ltcHV0ZWQgJT4lIHN1YnNldChpcy5uYShSZWdpb24pKQ0KYGBgDQoNCkFmdGVyIGNoZWNraW5nIGZvciBtaXNzaW5nIHZhbHVlcywgYSBuZXcgZGF0YSBmcmFtZSBpcyBjcmVhdGVkIHdpdGggY29tcGxldGUgY2FzZXMuDQoNCmBgYHtyfQ0KR0RQX2NsZWFuIDwtIEdEUFNjYW4xX2ltcHV0ZWQNCkdEUF9jbGVhbg0KYGBgDQoNCg0KYGBge3J9DQpzdW0oaXMubmEoR0RQX2NsZWFuJEdEUCkpDQoNCmBgYA0KDQojIyMjIENoZWNrIGZvciBzcGVjaWFsIHZhbHVlcw0KDQpBZnRlciBjaGVja2luZyBmb3IgbWlzc2luZyB2YWx1ZXMsIEkgaGF2ZSB0aGVuIGNoZWNrZWQgdGhlIHZhcmlhYmxlcyBmb3Igc3BlY2lhbCB2YWx1ZXMNCg0KYGBge3J9DQojIyBhIGZ1bmN0aW9uIHRvIGNoZWNrIGZvciBzcGVjaWFsIHZhbHVlcw0KaXMuc3BlY2lhbDwtIGZ1bmN0aW9uKHgpeyANCiAgaWYoaXMubnVtZXJpYyh4KSkgIWlzLmZpbml0ZSh4KSBlbHNlIGlzLm5hKHgpIA0KICB9IA0KaXMuc3BlY2lhbDwtIGZ1bmN0aW9uKHgpew0KICBpZihpcy5udW1lcmljKHgpKSAhaXMuZmluaXRlKHgpIA0KfQ0KDQojIyBjaGVjayBmb3Igc3BlY2lhbCB2YWx1ZXMgaW4gR0RQIHVzaW5nIGlzLnNwZWNpYWwgZnVuY3Rpb24gDQpTcGVjaWFsVmFsdWVzIDwtIHNhcHBseShHRFBfY2xlYW4kR0RQLCBpcy5zcGVjaWFsKQ0KDQojQ291bnQgdGhlIG51bWJlciBvZiBzcGVjaWFsIHZhbHVlcw0KbGVuZ3RoKFNwZWNpYWxWYWx1ZXNbU3BlY2lhbFZhbHVlcz09IlRSVUUiXSkNCmBgYA0KDQpUaGVyZSBhcmUgMTQ0IHNwZWNpYWwgY2hhcmFjdGVycyB3aGljaCBtb3N0bHkgY29tZXMgZnJvbSB0aGUgY291dHJpZXMgd2hlcmUgdGhlcmUgYXJlIG5vIGRhdGEgYXQgYWxsIGFuZCBoZW5jZSBubyBtZWFuIHZhbHVlIHdhcyBlc3RpbWF0ZWQuIFRoZXNlIHJvd3Mgd2VyZSBleGNsdWRlZCB1c2luZyBjb21wbGV0ZWQgY2FzZXMgZnVuY3Rpb24gYmVsb3cuDQoNCg0KYGBge3J9DQojIyBjaGVjayB0aGUgd2hvbGUgZGF0YSBmcmFtZSBmb3IgbWlzc2luZyB2YWx1ZXMNCkdEUF9jbGVhblshY29tcGxldGUuY2FzZXMoR0RQX2NsZWFuKSxdDQoNCmBgYA0KDQpUaGUgY2xlYW5lZCBkYXRhIGZyYW1lICoqKEdEUF9DbGVhbikqKiBkb2VzIG5vdCBoYXZlIGFueSBtaXNzaW5nIG9yIHNwZWNpYWwgdmFsdWVzIG5vdyBhbmQgY2FuIGJlIHVzaW5nIGZvciBmdXJ0aGVyIGFuYWx5c2lzLg0KDQojIwlTY2FuIElJDQoNCiMjIyMgQ2hlY2sgZm9yIG91dGxpZXJzDQoNCkluIG9yZGVyIHRvIGNoZWNrIGZvciBvdXRsaWVycywgSSBoYXZlIHVzZWQgei1zY29yZXMgbWV0aG9kLiB6LXNjb3JlIGlzIGEgZGlzdGFuY2UgYmFzZWQgbWV0aG9kIGFuZCBhIHZhbHVlIGlzIHRyZWF0ZWQgYXMgYW4gb3V0bGllciBpZiB0aGUgYWJzb2x1dGUgdmFsdWUgb2Ygei1zY29yZSBpcyBncmVhdGVyIHRoYW4gMy4NCg0KYGBge3J9DQp6LnNjb3JlcyA8LSBHRFBfY2xlYW4kR0RQWyFpcy5uYShHRFBfY2xlYW4kR0RQKV0gJT4lIHNjb3Jlcyh0eXBlID0gInoiKQ0KDQpzdW1tYXJ5KHouc2NvcmVzKQ0KDQoNCmBgYA0KDQpUaGUgbWluaW11bSB6LXNjb3JlIGlzIC0wLjI5NTggYW5kIHRoZSBtYXhpbXVtIGlzIDguODY1Ny4gSW4gb3JkZXIgdG8gY2hlY2sgdGhlIGxvY2F0aW9uIG9mIHRoZSB6LXNjb3JlcyB3aG9zZSBhYnNvbHVldCB2YWx1ZSBpcyBncmVhdGVyIHRoYW4gMywgSSBoYXZlIHVzZWQgd2hpY2goKSBmdW5jdGlvbg0KDQpgYGB7cn0NCiMjIFNhdmluZyBvdXRsaWVycyBlbnRyaWVzIGFzIGEgc2VwYXJhdGUgZGF0YSBmcmFtZQ0KT3V0bGllcnMgPC0gR0RQXzIwMTdfaW1wdXRlZFt3aGljaChhYnMoei5zY29yZXMpPjMpLF0NCg0KIyMgT3V0bGllcnMgYnkgY291bnRyeQ0KT3V0bGllcnMgJT4lIGNvdW50KGBDb3VudHJ5IE5hbWVgKQ0KDQpgYGANCg0KDQpTaXggY291bnRyaWVzIGFyZSB0cmVhdGVkIGFzIG91dGxpZXJzIGFzIGl0IGV4Y2VlZCBtYXhpbXVtIHRocmVzaG9sZCB1bmRlciB6LXNjb3JlcyBhbmQgdGhvc2UgY291bnRyaWVzIHdpbGwgYmUgcmVtb3ZlZCBmcm9tIGZ1cnRoZXIgYW5hbHlzaXMuDQoNCmBgYHtyfQ0KIyMgUmVtb3Zpbmcgb3V0bGllcnMNCkdEUF9jbGVhbl9vdXRsaWVyZXhjIDwtIEdEUF8yMDE3X2ltcHV0ZWQgJT4lIGZpbHRlcihgQ291bnRyeSBOYW1lYCAhPSJHdWFtIiwgYENvdW50cnkgTmFtZWAgIT0iSHVuZ2FyeSIsIGBDb3VudHJ5IE5hbWVgICE9IktvcmVhLCBEZW0uIFBlb3BsZTxVKzAwOTI+cyBSZXAuIiwgYENvdW50cnkgTmFtZWAgIT0iTGllY2h0ZW5zdGVpbiIsICBgQ291bnRyeSBOYW1lYCAhPSJOb3J3YXkiLCAgYENvdW50cnkgTmFtZWAgIT0iVW5pdGVkIFN0YXRlcyIsKQ0KDQpHRFBfY2xlYW5fb3V0bGllcmV4Yw0KDQpgYGANCg0KDQoNCiMjCVRyYW5zZm9ybSANCg0KSW4gdGhpcyBzZWN0aW9uIEkgaGF2ZSB1c2VkIEdEUCBhcyB0aGUgdmFyaWFibGUgZm9yIHRyYW5zZm9ybWF0aW9uLiBQcmlvciB0byB0cmFuc2Zvcm1hdGlvbiwgYSBoaXN0b2dyYW0gd2FzIGRyYXduIHRvIGNoZWNrIHRoZSBza2V3bmVzcyBvZiB0aGUgZGF0YS4NCg0KQXBwbHkgYW4gYXBwcm9wcmlhdGUgdHJhbnNmb3JtYXRpb24gZm9yIGF0IGxlYXN0IG9uZSBvZiB0aGUgdmFyaWFibGVzLiBJbiBhZGRpdGlvbiB0byB0aGUgUiBjb2RlcyBhbmQgb3V0cHV0cywgZXhwbGFpbiBldmVyeXRoaW5nIHRoYXQgeW91IGRvIGluIHRoaXMgc3RlcC4gSW4gdGhpcyBzdGVwLCB5b3Ugc2hvdWxkIGZ1bGZpbCB0aGUgbWluaW11bSByZXF1aXJlbWVudCAjOS4NCg0KYGBge3J9DQojIyBIaXN0b2dyYW0gb2YgR0RQDQpwYXIobWZyb3cgPSBjKDEsMikpDQoNCmhpc3QoR0RQX2NsZWFuX291dGxpZXJleGMkR0RQLCBtYWluID0gIkhpc3RvZ3JhbSBmb3IgR0RQIiAsIHhsYWIgPSAiR0RQIikNCg0KR0RQX2xvZyA8LSBsb2coR0RQX2NsZWFuX291dGxpZXJleGMkR0RQKQ0KDQpoaXN0KEdEUF9sb2cpDQoNCmBgYA0KDQpUaGUgaGlzdG9ncmFtIChyaWdodCkgc2hvd3MgdGhhdCB0aGUgZGF0YSBhcmUgc2tld2VkIHRvIHJpZ2h0LiBNb3Jlb3ZlciwgYXMgdGhlIHZhbHVlcyBhcmUgdmVyeSBoaWdoLCB0aGUgbnVtYmVycyBkb2VzIG5vdCBzaG93IHByb3Blcmx5LiBIZW5jZSwgdG8gdHJhbmZvcm0gaXQgdG8gbm9ybWFsLCBJIGhhdmUgdXNlZCBsb2dhcml0aG1pYyB0cmFuc2Zvcm1hdGlvbiB0byBnZXQgcmlkIG9mIHJpZ2h0IHNrZXduZXNzIHdoaWNoIGNhbiBiZSBzZWVuIGZyb20gdGhlIGxlZnQgaGlzdG9ncmFtIA0KDQoNCg0KDQoNCg0KDQo8YnI+DQo8YnI+DQo=