Introduction to the
data
In order to properly analyze the World Life Expectancy data, four
data sets were downloaded and read into rstudio. The following data was
utilized for the analysis:
- Income per person
- Life expectancy per year
- Population Size
- Country Regions
Each data set includes information that could potentially impact life
expectancy throughout the world. Ranging from 1800 to 2018 this public
domain data includes both relevant and irrelevant data for analysis.
countries.raw <- read.csv("https://nlepera.github.io/sta553/w05_ggplot/data/countries_total.csv")
income.raw <- read.csv("https://nlepera.github.io/sta553/w05_ggplot/data/income_per_person.csv")
life.raw <- read.csv("https://nlepera.github.io/sta553/w05_ggplot/data/life_expectancy_years.csv")
popu.raw <- read.csv("https://nlepera.github.io/sta553/w05_ggplot/data/population_total.csv")
Conserved across the four data sets is one common variable:
country name. Additionally, three of the four utilized data sets
share a secondary common variable, year.
Preparing the Data for
a Proper Merge
Once the raw data was loaded into rstudio, variables that were
outside of the scope of interest needed to be removed from each of the
four data frames.
Income Per Person
Data
Starting with Income per person data, the data frame required
reshaping to allow for proper merge of all four data sets and subsequent
analysis.
The data frame of raw income data (named
income.raw) was reshaped to gather
the data by year, omitting the country column. Omitting the country
column allows for multiple country entries for each year.
This process transformed the raw income data of
193 observations of
220 variables into the reshaped data
frame of income data (named income)
that includes 42267 observations of
3 variables.
All blank values were omitted from the reshaped income data
frame by setting na.rm = TRUE.
income <- income.raw %>%
gather(key = "Year",
value = "Income",
- geo,
na.rm = TRUE)
colnames(income) <- c("Country", "Year", "Income")
group_by(income, Income)
# A tibble: 42,267 × 3
# Groups: Income [2,218]
Country Year Income
<chr> <chr> <int>
1 Afghanistan X1800 603
2 Albania X1800 667
3 Algeria X1800 715
4 Andorra X1800 1200
5 Angola X1800 618
6 Antigua and Barbuda X1800 757
7 Argentina X1800 1510
8 Armenia X1800 514
9 Australia X1800 814
10 Austria X1800 1850
# ℹ 42,257 more rows
str(income)
'data.frame': 42267 obs. of 3 variables:
$ Country: chr "Afghanistan" "Albania" "Algeria" "Andorra" ...
$ Year : chr "X1800" "X1800" "X1800" "X1800" ...
$ Income : int 603 667 715 1200 618 757 1510 514 814 1850 ...
Life Expectancy
Data
Second, Life Expectancy data required reshaping to
appropriately merge the data sets for analysis.
The data frame of raw life expectancy data (named
life.raw) was reshaped to gather
the data by year, omitting the country column from the gather process.
Omitting the country column allows for multiple country entries for each
year.
This process transformed the raw life expectancy data of
187 observations of
220 variables into the reshaped data
frame of life expectancy data (named
life) that includes
40437 observations of
3 variables.
All blank values were omitted from the reshaped life
expectancy data frame by setting na.rm = TRUE.
life <- life.raw %>%
gather(key = "Year",
value = "Life_Exp",
- geo,
na.rm = TRUE)
colnames(life) <- c("Country", "Year", "Life_Exp")
group_by(life, Life_Exp)
# A tibble: 40,437 × 3
# Groups: Life_Exp [739]
Country Year Life_Exp
<chr> <chr> <dbl>
1 Afghanistan X1800 28.2
2 Albania X1800 35.4
3 Algeria X1800 28.8
4 Angola X1800 27
5 Antigua and Barbuda X1800 33.5
6 Argentina X1800 33.2
7 Armenia X1800 34
8 Australia X1800 34
9 Austria X1800 34.4
10 Azerbaijan X1800 29.2
# ℹ 40,427 more rows
str(life)
'data.frame': 40437 obs. of 3 variables:
$ Country : chr "Afghanistan" "Albania" "Algeria" "Angola" ...
$ Year : chr "X1800" "X1800" "X1800" "X1800" ...
$ Life_Exp: num 28.2 35.4 28.8 27 33.5 33.2 34 34 34.4 29.2 ...
Population Data
Third, the Population Data required reshaping as well to
appropriately merge the data sets for analysis.
The data frame of raw population data (named
popu.raw) was reshaped to gather
the data by year, omitting the country column. Omitting the country
column allows for multiple country entries for each year.
This process transformed the raw population data of
195 observations of
220 variables into the reshaped data
frame of population data (named
popu) that includes
42705 observations of
3 variables.
All blank values were omitted from the reshaped population
data frame by setting na.rm = TRUE.
popu <- popu.raw %>%
gather(key = "Year",
value = "Population",
- geo,
na.rm = TRUE)
colnames(popu) <- c("Country", "Year", "Population")
group_by(popu, Population)
# A tibble: 42,705 × 3
# Groups: Population [4,599]
Country Year Population
<chr> <chr> <int>
1 Afghanistan X1800 3280000
2 Albania X1800 410000
3 Algeria X1800 2500000
4 Andorra X1800 2650
5 Angola X1800 1570000
6 Antigua and Barbuda X1800 37000
7 Argentina X1800 534000
8 Armenia X1800 413000
9 Australia X1800 351000
10 Austria X1800 3210000
# ℹ 42,695 more rows
str(popu)
'data.frame': 42705 obs. of 3 variables:
$ Country : chr "Afghanistan" "Albania" "Algeria" "Andorra" ...
$ Year : chr "X1800" "X1800" "X1800" "X1800" ...
$ Population: int 3280000 410000 2500000 2650 1570000 37000 534000 413000 351000 3210000 ...
Country Data
Third, the Country Data required reshaping as well to
appropriately merge the data sets for analysis.
A subset of the data frame of raw country data (named
countries.raw) to remove all
variables except for the Country name and Continent.
This process transformed the raw country data of
248 observations of
11 variables into the reshaped data
frame of country data (named
countries) that includes
248 observations of
2 variables.
countries <- subset(countries.raw, select = c(name, region))
colnames(countries) <- c("Country", "Continent")
str(countries)
'data.frame': 248 obs. of 2 variables:
$ Country : chr "Afghanistan" "\xea\xf3land Islands" "Albania" "Algeria" ...
$ Continent: chr "Asia" "Europe" "Europe" "Africa" ...
Merging the Data
With all four data sets (Income Per Person Data, Life
Expectancy Data, Population Data, and Country Data)
reshaped for a clean merge, the final data set was merged in multiple
steps to ensure accuracy.
Merging Longitudinal
Data Part 1
First the following longitudinal data frames were merged into a
singular data frame (named
LifeExpIncom):
- Life Expectancy Data (reshaped)
- Income Per Person Data (reshaped)
LifeExpIncom <- inner_join(life, income, by = c("Country", "Year"))
group_by(LifeExpIncom, Life_Exp)
# A tibble: 40,437 × 4
# Groups: Life_Exp [739]
Country Year Life_Exp Income
<chr> <chr> <dbl> <int>
1 Afghanistan X1800 28.2 603
2 Albania X1800 35.4 667
3 Algeria X1800 28.8 715
4 Angola X1800 27 618
5 Antigua and Barbuda X1800 33.5 757
6 Argentina X1800 33.2 1510
7 Armenia X1800 34 514
8 Australia X1800 34 814
9 Austria X1800 34.4 1850
10 Azerbaijan X1800 29.2 775
# ℹ 40,427 more rows
In merging by both “Country” and “Year” variables the resultant data
frame LifeExpIncom includes a
single variable for Country and Year, despite both merged data frames
containing these variables.
All blank values were omitted from the merged data frame by
utilizing inner_join().
str(LifeExpIncom)
'data.frame': 40437 obs. of 4 variables:
$ Country : chr "Afghanistan" "Albania" "Algeria" "Angola" ...
$ Year : chr "X1800" "X1800" "X1800" "X1800" ...
$ Life_Exp: num 28.2 35.4 28.8 27 33.5 33.2 34 34 34.4 29.2 ...
$ Income : int 603 667 715 618 757 1510 514 814 1850 775 ...
Merging Longitudinal
Data Part 2
Second the following longitudinal data frames were merged into a
singular data frame (named
LifeIncomPopu):
- Life Expectancy and Income Data (merged data from above)
- Population Data (reshaped)
LifeIncomPopu <- inner_join( LifeExpIncom, popu, by = c("Country", "Year"))
In merging by both “Country” and “Year” variables the resultant data
frame LifeIncomPopu includes a
single variable for Country and Year, despite both merged data frames
containing these variables.
All blank values were omitted from the merged data frame by
utilizing inner_join().
str(LifeIncomPopu)
'data.frame': 40437 obs. of 5 variables:
$ Country : chr "Afghanistan" "Albania" "Algeria" "Angola" ...
$ Year : chr "X1800" "X1800" "X1800" "X1800" ...
$ Life_Exp : num 28.2 35.4 28.8 27 33.5 33.2 34 34 34.4 29.2 ...
$ Income : int 603 667 715 618 757 1510 514 814 1850 775 ...
$ Population: int 3280000 410000 2500000 1570000 37000 534000 413000 351000 3210000 880000 ...
Merging Longitudinal
Data with Categorical Data
Once all longitudinal data has been merged into a single data frame
the following data frames of both longitudinal and categorical data
frames were merged into a final data frame (named
LifeExp_Clean):
- Life Expectancy, Income, and Population Data (merged data from
above)
- Country Data (reshaped)
LifeExp_Clean <- inner_join(LifeIncomPopu, countries, by = "Country")
In merging by “Country” variable the resultant data frame
LifeExp_Clean includes a single
variable for Country , despite both merged data frames containing these
variables.
This process transformed the merged Income, Life Expectancy, and
Population data of 40437 observations
of 5 variables into the reshaped data
frame of merged Income, Life Expectancy, Population Data, and Country
Data,(named LifeExp_Clean) that
includes 37590 observations of
2 variables.
All blank values were omitted from the merged data frame by
utilizing inner_join().
str(LifeExp_Clean)
'data.frame': 37590 obs. of 6 variables:
$ Country : chr "Afghanistan" "Albania" "Algeria" "Angola" ...
$ Year : chr "X1800" "X1800" "X1800" "X1800" ...
$ Life_Exp : num 28.2 35.4 28.8 27 33.5 33.2 34 34 34.4 29.2 ...
$ Income : int 603 667 715 618 757 1510 514 814 1850 775 ...
$ Population: int 3280000 410000 2500000 1570000 37000 534000 413000 351000 3210000 880000 ...
$ Continent : chr "Asia" "Europe" "Africa" "Africa" ...
write.xlsx(LifeExp_Clean, file = "C:\\Users\\natal\\Downloads\\LifeExp_Clean.xlsx")
A copy of the above printed data file can be accessed at the
following github
link.
Pruning the Data for
Visualization Purposes
In order to properly visualize data of this scale a subset for the
year 2000 was taken (named
data2000)
data2000 <- filter(LifeExp_Clean, Year == "X2000")
str(data2000)
'data.frame': 174 obs. of 6 variables:
$ Country : chr "Afghanistan" "Albania" "Algeria" "Andorra" ...
$ Year : chr "X2000" "X2000" "X2000" "X2000" ...
$ Life_Exp : num 51.6 74.4 73.9 81.8 53.4 74.7 74.2 71.8 79.7 78.1 ...
$ Income : int 972 5470 10200 31700 3510 18800 14900 2930 35300 38800 ...
$ Population: int 20100000 3120000 31200000 65400 16400000 83600 37100000 3070000 19100000 8070000 ...
$ Continent : chr "Asia" "Europe" "Africa" "Europe" ...
write.xlsx(data2000, file = "C:\\Users\\natal\\Downloads\\data2000.xlsx")
A copy of the above printed data file can be accessed at the
following github
link.
Plotting the Data
The Prepared and Pruned data as found in
data2000 is plotted below.
ggplot(data2000)+
aes(x = Income, y = Life_Exp, color = Continent)+
geom_point(aes(size = Population, alpha = 0.5))+
geom_smooth(method ="lm", fill = NA)+
scale_color_manual(values=c('#648FFF','#785EF0', '#DC267F', '#FE6100', '#FFB000'))+
labs(x="Income Per Person ($/person/year)", y="Life Expectancy (years)", title = "Impact of Income on Average Life Expectancy", subtitle = "Controlled for both region (Continent) and population size (Population)", color="Continent", size="Population")+
guides(alpha ="none")

As illustrated above a positive correlation between Average Income
Per Person and Average Life Expectancy for all continents. Continents
with a greater range of average incomes per person demonstrate a greater
positive correlation between income and life expectancy. Income per
person range can be visualized by the length of the linear regression
lines added to the above plot. Regression lines that extend to greater x
values indicate a greater income range for the indicated Continent.
Population size is more difficult to observe with the above plot, but
there appears to be a minor negative correlation for the Asia continent
between both population size and life expectancy as well as population
size and income per person. This correlation is identified by the
clustering of larger sized points closer towards the bottom left of the
plot (lower values for both income and life expectancy).
LS0tDQp0aXRsZTogIlRoZSBSYWNlIHRvIEltbW9ydGFsaXR5OiBBbiBhbmFseXNpcyBvZiB2YXJpYWJsZXMgaW1wYWN0aW5nIGF2ZXJhZ2UgbGlmZSBleHBlY3RhbmN5Ig0KYXV0aG9yOiAiTmF0YWxpZSBMZVBlcmEiDQpkYXRlOiAiV2VzdCBDaGVzdGVyIFVuaXZlcnNpdHkgPGJyPlNUQSA1MDM6IERhdGEgVmlzdWFsaXphdGlvbiINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdG9jX2NvbGxhcHNlZDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgc21vb3RoX3Njcm9sbDogdHJ1ZQ0KICAgIHRoZW1lOiByZWFkYWJsZQ0KLS0tDQoNCmBgYHs9aHRtbH0NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoNCmRpdiNUT0MgbGkgew0KICAgIGxpc3Qtc3R5bGU6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLWNvbG9yOmxpZ2h0Z3JheTsNCiAgICBiYWNrZ3JvdW5kLWltYWdlOm5vbmU7DQogICAgYmFja2dyb3VuZC1yZXBlYXQ6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLXBvc2l0aW9uOjA7DQogICAgZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7DQogICAgY29sb3I6ICM3ODBjMGM7DQp9DQoNCi8qIG1vdXNlIG92ZXIgbGluayAqLw0KZGl2I1RPQyBhOmhvdmVyIHsNCiAgY29sb3I6IHJlZDsNCn0NCg0KLyogdW52aXNpdGVkIGxpbmsgKi8NCmRpdiNUT0MgYTpsaW5rIHsNCiAgY29sb3I6IGJsdWU7DQp9DQoNCg0KDQpoMS50aXRsZSB7DQogIGZvbnQtc2l6ZTogMjRweDsNCiAgY29sb3I6IERhcmtibHVlOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQogIGZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOw0KICBmb250LXZhcmlhbnQtY2Fwczogbm9ybWFsOw0KfQ0KaDQuYXV0aG9yIHsgDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgY29sb3I6IERhcmtSZWQ7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmg0LmRhdGUgeyANCiAgZm9udC1zaXplOiAxOHB4Ow0KICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgY29sb3I6IERhcmtCbHVlOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQpoMSB7DQogICAgZm9udC1zaXplOiAyNHB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmgyIHsNCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDMgeyANCiAgICBmb250LXNpemU6IDE1cHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDQgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQovKiB1bnZpc2l0ZWQgbGluayAqLw0KYTpsaW5rIHsNCiAgY29sb3I6IGdyZWVuOw0KfQ0KDQovKiB2aXNpdGVkIGxpbmsgKi8NCmE6dmlzaXRlZCB7DQogIGNvbG9yOiBncmVlbjsNCn0NCg0KLyogbW91c2Ugb3ZlciBsaW5rICovDQphOmhvdmVyIHsNCiAgY29sb3I6IHJlZDsNCn0NCg0KLyogc2VsZWN0ZWQgbGluayAqLw0KYTphY3RpdmUgew0KICBjb2xvcjogeWVsbG93Ow0KfQ0KDQo8L3N0eWxlPg0KYGBgDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMgY29kZSBjaHVuayBzcGVjaWZpZXMgd2hldGhlciB0aGUgUiBjb2RlLCB3YXJuaW5ncywgYW5kIG91dHB1dCANCiMgd2lsbCBiZSBpbmNsdWRlZCBpbiB0aGUgb3V0cHV0IGZpbGVzLg0Kb3B0aW9ucyhyZXBvcyA9IGxpc3QoQ1JBTj0iaHR0cDovL2NyYW4ucnN0dWRpby5jb20vIikpDQppZiAoIXJlcXVpcmUoInRpZHl2ZXJzZSIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KICAgbGlicmFyeSh0aWR5dmVyc2UpDQp9DQppZiAoIXJlcXVpcmUoImtuaXRyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikNCiAgIGxpYnJhcnkoa25pdHIpDQp9DQppZiAoIXJlcXVpcmUoImNvd3Bsb3QiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygiY293cGxvdCIpDQogICBsaWJyYXJ5KGNvd3Bsb3QpDQp9DQppZiAoIXJlcXVpcmUoImxhdGV4MmV4cCIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJsYXRleDJleHAiKQ0KICAgbGlicmFyeShsYXRleDJleHApDQp9DQppZiAoIXJlcXVpcmUoInBsb3RseSIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJwbG90bHkiKQ0KICAgbGlicmFyeShwbG90bHkpDQp9DQppZiAoIXJlcXVpcmUoImdhcG1pbmRlciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJnYXBtaW5kZXIiKQ0KICAgbGlicmFyeShnYXBtaW5kZXIpDQp9DQppZiAoIXJlcXVpcmUoInBuZyIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygicG5nIikgICAgICAgICAgICAgIyBJbnN0YWxsIHBuZyBwYWNrYWdlDQogICAgbGlicmFyeSgicG5nIikNCn0NCmlmICghcmVxdWlyZSgiUkN1cmwiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoIlJDdXJsIikgICAgICAgICAgICMgSW5zdGFsbCBSQ3VybCBwYWNrYWdlDQogICAgbGlicmFyeSgiUkN1cmwiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJjb2xvdXJwaWNrZXIiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImNvbG91cnBpY2tlciIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJjb2xvdXJwaWNrZXIiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJnaWZza2kiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImdpZnNraSIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJnaWZza2kiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJtYWdpY2siKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoIm1hZ2ljayIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJtYWdpY2siKQ0KfQ0KaWYgKCFyZXF1aXJlKCJnckRldmljZXMiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImdyRGV2aWNlcyIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJnckRldmljZXMiKQ0KfQ0KIyMjIGdncGxvdCBhbmQgZXh0ZW5zaW9ucw0KaWYgKCFyZXF1aXJlKCJnZ3Bsb3QyIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QyIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImdncGxvdDIiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJnZ2FuaW1hdGUiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImdnYW5pbWF0ZSIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJnZ2FuaW1hdGUiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJnZ3JpZGdlcyIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygiZ2dyaWRnZXMiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiZ2dyaWRnZXMiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJncmFwaGljcyIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygiZ3JhcGhpY3MiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiZ3JhcGhpY3MiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJvcGVueGxzeCIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygib3Blbnhsc3giKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgib3Blbnhsc3giKQ0KfQ0KDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwgICANCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHQgPSBUUlVFLCAgIA0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkEpDQpgYGANClwNCg0KIyBJbnRyb2R1Y3Rpb24gdG8gdGhlIGRhdGENCkluIG9yZGVyIHRvIHByb3Blcmx5IGFuYWx5emUgdGhlIFdvcmxkIExpZmUgRXhwZWN0YW5jeSBkYXRhLCBmb3VyIGRhdGEgc2V0cyB3ZXJlIGRvd25sb2FkZWQgYW5kIHJlYWQgaW50byByc3R1ZGlvLiBUaGUgZm9sbG93aW5nIGRhdGEgd2FzIHV0aWxpemVkIGZvciB0aGUgYW5hbHlzaXM6DQoNCi0gICBJbmNvbWUgcGVyIHBlcnNvbg0KLSAgIExpZmUgZXhwZWN0YW5jeSBwZXIgeWVhcg0KLSAgIFBvcHVsYXRpb24gU2l6ZQ0KLSAgIENvdW50cnkgUmVnaW9ucw0KDQpFYWNoIGRhdGEgc2V0IGluY2x1ZGVzIGluZm9ybWF0aW9uIHRoYXQgY291bGQgcG90ZW50aWFsbHkgaW1wYWN0IGxpZmUgZXhwZWN0YW5jeSB0aHJvdWdob3V0IHRoZSB3b3JsZC4gUmFuZ2luZyBmcm9tIDE4MDAgdG8gMjAxOCB0aGlzIHB1YmxpYyBkb21haW4gZGF0YSBpbmNsdWRlcyBib3RoIHJlbGV2YW50IGFuZCBpcnJlbGV2YW50IGRhdGEgZm9yIGFuYWx5c2lzLg0KDQpgYGB7cn0NCmNvdW50cmllcy5yYXcgPC0gcmVhZC5jc3YoImh0dHBzOi8vbmxlcGVyYS5naXRodWIuaW8vc3RhNTUzL3cwNV9nZ3Bsb3QvZGF0YS9jb3VudHJpZXNfdG90YWwuY3N2IikNCmluY29tZS5yYXcgPC0gcmVhZC5jc3YoImh0dHBzOi8vbmxlcGVyYS5naXRodWIuaW8vc3RhNTUzL3cwNV9nZ3Bsb3QvZGF0YS9pbmNvbWVfcGVyX3BlcnNvbi5jc3YiKQ0KbGlmZS5yYXcgPC0gcmVhZC5jc3YoImh0dHBzOi8vbmxlcGVyYS5naXRodWIuaW8vc3RhNTUzL3cwNV9nZ3Bsb3QvZGF0YS9saWZlX2V4cGVjdGFuY3lfeWVhcnMuY3N2IikNCnBvcHUucmF3IDwtIHJlYWQuY3N2KCJodHRwczovL25sZXBlcmEuZ2l0aHViLmlvL3N0YTU1My93MDVfZ2dwbG90L2RhdGEvcG9wdWxhdGlvbl90b3RhbC5jc3YiKQ0KDQpgYGANCg0KQ29uc2VydmVkIGFjcm9zcyB0aGUgZm91ciBkYXRhIHNldHMgaXMgb25lIGNvbW1vbiB2YXJpYWJsZTogPGI+Y291bnRyeSBuYW1lPC9iPi4gIEFkZGl0aW9uYWxseSwgdGhyZWUgb2YgdGhlIGZvdXIgdXRpbGl6ZWQgZGF0YSBzZXRzIHNoYXJlIGEgc2Vjb25kYXJ5IGNvbW1vbiB2YXJpYWJsZSwgPGI+eWVhcjwvYj4uIA0KDQo8YnI+DQoNCg0KIyBQcmVwYXJpbmcgdGhlIERhdGEgZm9yIGEgUHJvcGVyIE1lcmdlDQoNCk9uY2UgdGhlIHJhdyBkYXRhIHdhcyBsb2FkZWQgaW50byByc3R1ZGlvLCB2YXJpYWJsZXMgdGhhdCB3ZXJlIG91dHNpZGUgb2YgdGhlIHNjb3BlIG9mIGludGVyZXN0IG5lZWRlZCB0byBiZSByZW1vdmVkIGZyb20gZWFjaCBvZiB0aGUgZm91ciBkYXRhIGZyYW1lcy4gDQo8YnI+DQoNCg0KIyMgSW5jb21lIFBlciBQZXJzb24gRGF0YQ0KDQpTdGFydGluZyB3aXRoIDx1PkluY29tZSBwZXIgcGVyc29uPC91PiBkYXRhLCB0aGUgZGF0YSBmcmFtZSByZXF1aXJlZCByZXNoYXBpbmcgdG8gYWxsb3cgZm9yIHByb3BlciBtZXJnZSBvZiBhbGwgZm91ciBkYXRhIHNldHMgYW5kIHN1YnNlcXVlbnQgYW5hbHlzaXMuDQoNCjxicj5UaGUgZGF0YSBmcmFtZSBvZiByYXcgaW5jb21lIGRhdGEgKG5hbWVkIDxmb250IGNvbG9yID0gInB1cnBsZSI+PGk+aW5jb21lLnJhdzwvaT48L2ZvbnQ+KSB3YXMgcmVzaGFwZWQgdG8gZ2F0aGVyIHRoZSBkYXRhIGJ5IHllYXIsIG9taXR0aW5nIHRoZSBjb3VudHJ5IGNvbHVtbi4gIE9taXR0aW5nIHRoZSBjb3VudHJ5IGNvbHVtbiBhbGxvd3MgZm9yIG11bHRpcGxlIGNvdW50cnkgZW50cmllcyBmb3IgZWFjaCB5ZWFyLiAgDQoNCjxicj5UaGlzIHByb2Nlc3MgdHJhbnNmb3JtZWQgdGhlIHJhdyBpbmNvbWUgZGF0YSBvZiA8Zm9udCBjb2xvciA9ICJyZWQiPjxiPjE5MyBvYnNlcnZhdGlvbnM8L2I+PC9mb250PiBvZiA8Zm9udCBjb2xvciA9ICJyZWQiPjxiPjIyMCB2YXJpYWJsZXM8L2I+PC9mb250PiBpbnRvIHRoZSByZXNoYXBlZCBkYXRhIGZyYW1lIG9mIGluY29tZSBkYXRhIChuYW1lZCA8Zm9udCBjb2xvciA9ICJwdXJwbGUiPjxpPmluY29tZTwvaT48L2ZvbnQ+KSB0aGF0IGluY2x1ZGVzIDxmb250IGNvbG9yID0gInJlZCI+PGI+NDIyNjcgb2JzZXJ2YXRpb25zPC9iPjwvZm9udD4gb2YgPGZvbnQgY29sb3IgPSAicmVkIj48Yj4zIHZhcmlhYmxlczwvYj48L2ZvbnQ+LiANCg0KPGJyPjxiPkFsbCBibGFuayB2YWx1ZXMgd2VyZSBvbWl0dGVkIGZyb20gdGhlIHJlc2hhcGVkIGluY29tZSBkYXRhIGZyYW1lIGJ5IHNldHRpbmcgbmEucm0gPSBUUlVFLjwvYj4NCg0KYGBge3J9DQppbmNvbWUgPC0gaW5jb21lLnJhdyAlPiUgDQogIGdhdGhlcihrZXkgPSAiWWVhciIsDQogICAgICAgICB2YWx1ZSA9ICJJbmNvbWUiLA0KICAgICAgICAgLSBnZW8sDQogICAgICAgICBuYS5ybSA9IFRSVUUpDQpjb2xuYW1lcyhpbmNvbWUpIDwtIGMoIkNvdW50cnkiLCAiWWVhciIsICJJbmNvbWUiKQ0KZ3JvdXBfYnkoaW5jb21lLCBJbmNvbWUpDQpgYGANCg0KYGBge3IgZWNobyA9IFRSVUV9DQpzdHIoaW5jb21lKQ0KYGBgDQo8YnI+DQoNCg0KIyMgTGlmZSBFeHBlY3RhbmN5IERhdGENCg0KU2Vjb25kLCA8dT5MaWZlIEV4cGVjdGFuY3k8L3U+IGRhdGEgcmVxdWlyZWQgcmVzaGFwaW5nIHRvIGFwcHJvcHJpYXRlbHkgbWVyZ2UgdGhlIGRhdGEgc2V0cyBmb3IgYW5hbHlzaXMuICANCg0KPGJyPlRoZSBkYXRhIGZyYW1lIG9mIHJhdyBsaWZlIGV4cGVjdGFuY3kgZGF0YSAobmFtZWQgPGZvbnQgY29sb3IgPSAicHVycGxlIj48aT5saWZlLnJhdzwvaT48L2ZvbnQ+KSB3YXMgcmVzaGFwZWQgdG8gZ2F0aGVyIHRoZSBkYXRhIGJ5IHllYXIsIG9taXR0aW5nIHRoZSBjb3VudHJ5IGNvbHVtbiBmcm9tIHRoZSBnYXRoZXIgcHJvY2Vzcy4gIE9taXR0aW5nIHRoZSBjb3VudHJ5IGNvbHVtbiBhbGxvd3MgZm9yIG11bHRpcGxlIGNvdW50cnkgZW50cmllcyBmb3IgZWFjaCB5ZWFyLiAgDQoNCjxicj5UaGlzIHByb2Nlc3MgdHJhbnNmb3JtZWQgdGhlIHJhdyBsaWZlIGV4cGVjdGFuY3kgZGF0YSBvZiA8Zm9udCBjb2xvciA9ICJyZWQiPjxiPjE4NyBvYnNlcnZhdGlvbnM8L2I+PC9mb250PiBvZiA8Zm9udCBjb2xvciA9ICJyZWQiPjxiPjIyMCB2YXJpYWJsZXM8L2I+PC9mb250PiBpbnRvIHRoZSByZXNoYXBlZCBkYXRhIGZyYW1lIG9mIGxpZmUgZXhwZWN0YW5jeSBkYXRhIChuYW1lZCA8Zm9udCBjb2xvciA9ICJwdXJwbGUiPjxpPmxpZmU8L2k+PC9mb250PikgdGhhdCBpbmNsdWRlcyA8Zm9udCBjb2xvciA9ICJyZWQiPjxiPjQwNDM3IG9ic2VydmF0aW9uczwvYj48L2ZvbnQ+IG9mIDxmb250IGNvbG9yID0gInJlZCI+PGI+MyB2YXJpYWJsZXM8L2I+PC9mb250Pi4gDQoNCjxicj48Yj5BbGwgYmxhbmsgdmFsdWVzIHdlcmUgb21pdHRlZCBmcm9tIHRoZSByZXNoYXBlZCBsaWZlIGV4cGVjdGFuY3kgZGF0YSBmcmFtZSBieSBzZXR0aW5nIG5hLnJtID0gVFJVRS48L2I+DQoNCmBgYHtyfQ0KbGlmZSA8LSBsaWZlLnJhdyAlPiUgDQogIGdhdGhlcihrZXkgPSAiWWVhciIsDQogICAgICAgICB2YWx1ZSA9ICJMaWZlX0V4cCIsDQogICAgICAgICAtIGdlbywNCiAgICAgICAgIG5hLnJtID0gVFJVRSkNCmNvbG5hbWVzKGxpZmUpIDwtIGMoIkNvdW50cnkiLCAiWWVhciIsICJMaWZlX0V4cCIpDQpncm91cF9ieShsaWZlLCBMaWZlX0V4cCkNCmBgYA0KDQpgYGB7ciBlY2hvPVRSVUV9DQpzdHIobGlmZSkNCmBgYA0KPGJyPg0KDQoNCiMjIFBvcHVsYXRpb24gRGF0YQ0KDQpUaGlyZCwgdGhlIDxpPlBvcHVsYXRpb24gRGF0YTwvaT4gcmVxdWlyZWQgcmVzaGFwaW5nIGFzIHdlbGwgdG8gYXBwcm9wcmlhdGVseSBtZXJnZSB0aGUgZGF0YSBzZXRzIGZvciBhbmFseXNpcy4gDQoNCjxicj5UaGUgZGF0YSBmcmFtZSBvZiByYXcgcG9wdWxhdGlvbiBkYXRhIChuYW1lZCA8Zm9udCBjb2xvciA9ICJwdXJwbGUiPjxpPnBvcHUucmF3PC9pPjwvZm9udD4pIHdhcyByZXNoYXBlZCB0byBnYXRoZXIgdGhlIGRhdGEgYnkgeWVhciwgb21pdHRpbmcgdGhlIGNvdW50cnkgY29sdW1uLiAgT21pdHRpbmcgdGhlIGNvdW50cnkgY29sdW1uIGFsbG93cyBmb3IgbXVsdGlwbGUgY291bnRyeSBlbnRyaWVzIGZvciBlYWNoIHllYXIuICANCg0KPGJyPlRoaXMgcHJvY2VzcyB0cmFuc2Zvcm1lZCB0aGUgcmF3IHBvcHVsYXRpb24gZGF0YSBvZiA8Zm9udCBjb2xvciA9ICJyZWQiPjxiPjE5NSBvYnNlcnZhdGlvbnM8L2I+PC9mb250PiBvZiA8Zm9udCBjb2xvciA9ICJyZWQiPjxiPjIyMCB2YXJpYWJsZXM8L2I+PC9mb250PiBpbnRvIHRoZSByZXNoYXBlZCBkYXRhIGZyYW1lIG9mIHBvcHVsYXRpb24gZGF0YSAobmFtZWQgPGZvbnQgY29sb3IgPSAicHVycGxlIj48aT5wb3B1PC9pPjwvZm9udD4pIHRoYXQgaW5jbHVkZXMgPGZvbnQgY29sb3IgPSAicmVkIj48Yj40MjcwNSBvYnNlcnZhdGlvbnM8L2I+PC9mb250PiBvZiA8Zm9udCBjb2xvciA9ICJyZWQiPjxiPjMgdmFyaWFibGVzPC9iPjwvZm9udD4uIA0KDQo8YnI+PGI+QWxsIGJsYW5rIHZhbHVlcyB3ZXJlIG9taXR0ZWQgZnJvbSB0aGUgcmVzaGFwZWQgcG9wdWxhdGlvbiBkYXRhIGZyYW1lIGJ5IHNldHRpbmcgbmEucm0gPSBUUlVFLjwvYj4NCg0KYGBge3J9DQpwb3B1IDwtIHBvcHUucmF3ICU+JSANCiAgZ2F0aGVyKGtleSA9ICJZZWFyIiwNCiAgICAgICAgIHZhbHVlID0gIlBvcHVsYXRpb24iLA0KICAgICAgICAgLSBnZW8sDQogICAgICAgICBuYS5ybSA9IFRSVUUpDQpjb2xuYW1lcyhwb3B1KSA8LSBjKCJDb3VudHJ5IiwgIlllYXIiLCAiUG9wdWxhdGlvbiIpDQpncm91cF9ieShwb3B1LCBQb3B1bGF0aW9uKQ0KYGBgDQoNCmBgYHtyIGVjaG89VFJVRX0NCnN0cihwb3B1KQ0KYGBgDQo8YnI+DQoNCg0KIyMgQ291bnRyeSBEYXRhDQoNClRoaXJkLCB0aGUgPGk+Q291bnRyeSBEYXRhPC9pPiByZXF1aXJlZCByZXNoYXBpbmcgYXMgd2VsbCB0byBhcHByb3ByaWF0ZWx5IG1lcmdlIHRoZSBkYXRhIHNldHMgZm9yIGFuYWx5c2lzLiANCg0KPGJyPkEgc3Vic2V0IG9mIHRoZSBkYXRhIGZyYW1lIG9mIHJhdyBjb3VudHJ5IGRhdGEgKG5hbWVkIDxmb250IGNvbG9yID0gInB1cnBsZSI+PGk+Y291bnRyaWVzLnJhdzwvaT48L2ZvbnQ+KSB0byByZW1vdmUgYWxsIHZhcmlhYmxlcyBleGNlcHQgZm9yIHRoZSBDb3VudHJ5IG5hbWUgYW5kIENvbnRpbmVudC4gICAgDQoNCjxicj5UaGlzIHByb2Nlc3MgdHJhbnNmb3JtZWQgdGhlIHJhdyBjb3VudHJ5IGRhdGEgb2YgPGZvbnQgY29sb3IgPSAicmVkIj48Yj4yNDggb2JzZXJ2YXRpb25zPC9iPjwvZm9udD4gb2YgPGZvbnQgY29sb3IgPSAicmVkIj48Yj4xMSB2YXJpYWJsZXM8L2I+PC9mb250PiBpbnRvIHRoZSByZXNoYXBlZCBkYXRhIGZyYW1lIG9mIGNvdW50cnkgZGF0YSAobmFtZWQgPGZvbnQgY29sb3IgPSAicHVycGxlIj48aT5jb3VudHJpZXM8L2k+PC9mb250PikgdGhhdCBpbmNsdWRlcyA8Zm9udCBjb2xvciA9ICJyZWQiPjxiPjI0OCBvYnNlcnZhdGlvbnM8L2I+PC9mb250PiBvZiA8Zm9udCBjb2xvciA9ICJyZWQiPjxiPjIgdmFyaWFibGVzPC9iPjwvZm9udD4uIA0KDQoNCmBgYHtyfQ0KY291bnRyaWVzIDwtIHN1YnNldChjb3VudHJpZXMucmF3LCBzZWxlY3QgPSBjKG5hbWUsIHJlZ2lvbikpDQoNCmNvbG5hbWVzKGNvdW50cmllcykgPC0gYygiQ291bnRyeSIsICJDb250aW5lbnQiKQ0KYGBgDQoNCg0KYGBge3IgZWNobz1UUlVFfQ0Kc3RyKGNvdW50cmllcykNCmBgYA0KPGJyPjxicj4NCg0KDQojIE1lcmdpbmcgdGhlIERhdGENCldpdGggYWxsIGZvdXIgZGF0YSBzZXRzICg8dT5JbmNvbWUgUGVyIFBlcnNvbiBEYXRhPC91PiwgPHU+TGlmZSBFeHBlY3RhbmN5IERhdGE8L3U+LCA8dT5Qb3B1bGF0aW9uIERhdGE8L3U+LCBhbmQgPHU+Q291bnRyeSBEYXRhPC91PikgcmVzaGFwZWQgZm9yIGEgY2xlYW4gbWVyZ2UsIHRoZSBmaW5hbCBkYXRhIHNldCB3YXMgbWVyZ2VkIGluIG11bHRpcGxlIHN0ZXBzIHRvIGVuc3VyZSBhY2N1cmFjeS4gDQoNCjxicj4NCg0KDQojIyBNZXJnaW5nIExvbmdpdHVkaW5hbCBEYXRhIFBhcnQgMQ0KDQpGaXJzdCB0aGUgZm9sbG93aW5nIGxvbmdpdHVkaW5hbCBkYXRhIGZyYW1lcyB3ZXJlIG1lcmdlZCBpbnRvIGEgc2luZ3VsYXIgZGF0YSBmcmFtZSAobmFtZWQgPGZvbnQgY29sb3IgPSAicHVycGxlIj48aT4gTGlmZUV4cEluY29tPC9pPjwvZm9udD4pOg0KDQotICAgTGlmZSBFeHBlY3RhbmN5IERhdGEgKHJlc2hhcGVkKQ0KLSAgIEluY29tZSBQZXIgUGVyc29uIERhdGEgKHJlc2hhcGVkKQ0KDQoNCmBgYHtyfQ0KIExpZmVFeHBJbmNvbSA8LSBpbm5lcl9qb2luKGxpZmUsIGluY29tZSwgYnkgPSBjKCJDb3VudHJ5IiwgIlllYXIiKSkNCmdyb3VwX2J5KExpZmVFeHBJbmNvbSwgTGlmZV9FeHApDQpgYGANCg0KSW4gbWVyZ2luZyBieSBib3RoICJDb3VudHJ5IiBhbmQgIlllYXIiIHZhcmlhYmxlcyB0aGUgcmVzdWx0YW50IGRhdGEgZnJhbWUgPGZvbnQgY29sb3IgPSAicHVycGxlIj48aT4gTGlmZUV4cEluY29tPC9pPjwvZm9udD4gaW5jbHVkZXMgYSBzaW5nbGUgdmFyaWFibGUgZm9yIENvdW50cnkgYW5kIFllYXIsIGRlc3BpdGUgYm90aCBtZXJnZWQgZGF0YSBmcmFtZXMgY29udGFpbmluZyB0aGVzZSB2YXJpYWJsZXMuIA0KDQo8YnI+PGI+QWxsIGJsYW5rIHZhbHVlcyB3ZXJlIG9taXR0ZWQgZnJvbSB0aGUgbWVyZ2VkIGRhdGEgZnJhbWUgYnkgdXRpbGl6aW5nIGlubmVyX2pvaW4oKS48L2I+DQoNCmBgYHtyIGVjaG89VFJVRX0NCnN0cihMaWZlRXhwSW5jb20pDQpgYGANCg0KPGJyPg0KDQoNCiMjIE1lcmdpbmcgTG9uZ2l0dWRpbmFsIERhdGEgUGFydCAyDQpTZWNvbmQgdGhlIGZvbGxvd2luZyBsb25naXR1ZGluYWwgZGF0YSBmcmFtZXMgd2VyZSBtZXJnZWQgaW50byBhIHNpbmd1bGFyIGRhdGEgZnJhbWUgKG5hbWVkIDxmb250IGNvbG9yID0gInB1cnBsZSI+PGk+TGlmZUluY29tUG9wdTwvaT48L2ZvbnQ+KToNCg0KLSAgIExpZmUgRXhwZWN0YW5jeSBhbmQgSW5jb21lIERhdGEgKG1lcmdlZCBkYXRhIGZyb20gYWJvdmUpDQotICAgUG9wdWxhdGlvbiBEYXRhIChyZXNoYXBlZCkNCg0KDQpgYGB7cn0NCkxpZmVJbmNvbVBvcHUgPC0gaW5uZXJfam9pbiggTGlmZUV4cEluY29tLCBwb3B1LCBieSA9IGMoIkNvdW50cnkiLCAiWWVhciIpKQ0KYGBgDQoNCkluIG1lcmdpbmcgYnkgYm90aCAiQ291bnRyeSIgYW5kICJZZWFyIiB2YXJpYWJsZXMgdGhlIHJlc3VsdGFudCBkYXRhIGZyYW1lIDxmb250IGNvbG9yID0gInB1cnBsZSI+PGk+TGlmZUluY29tUG9wdTwvaT48L2ZvbnQ+IGluY2x1ZGVzIGEgc2luZ2xlIHZhcmlhYmxlIGZvciBDb3VudHJ5IGFuZCBZZWFyLCBkZXNwaXRlIGJvdGggbWVyZ2VkIGRhdGEgZnJhbWVzIGNvbnRhaW5pbmcgdGhlc2UgdmFyaWFibGVzLiANCg0KPGJyPjxiPkFsbCBibGFuayB2YWx1ZXMgd2VyZSBvbWl0dGVkIGZyb20gdGhlIG1lcmdlZCBkYXRhIGZyYW1lIGJ5IHV0aWxpemluZyBpbm5lcl9qb2luKCkuPC9iPg0KDQpgYGB7ciBlY2hvPVRSVUV9DQpzdHIoTGlmZUluY29tUG9wdSkNCmBgYA0KDQo8YnI+DQoNCg0KIyMgTWVyZ2luZyBMb25naXR1ZGluYWwgRGF0YSB3aXRoIENhdGVnb3JpY2FsIERhdGENCg0KT25jZSBhbGwgbG9uZ2l0dWRpbmFsIGRhdGEgaGFzIGJlZW4gbWVyZ2VkIGludG8gYSBzaW5nbGUgZGF0YSBmcmFtZSB0aGUgZm9sbG93aW5nIGRhdGEgZnJhbWVzIG9mIGJvdGggbG9uZ2l0dWRpbmFsIGFuZCBjYXRlZ29yaWNhbCBkYXRhIGZyYW1lcyB3ZXJlIG1lcmdlZCBpbnRvIGEgZmluYWwgZGF0YSBmcmFtZSAobmFtZWQgPGZvbnQgY29sb3IgPSAicHVycGxlIj48aT5MaWZlRXhwX0NsZWFuPC9pPjwvZm9udD4pOg0KDQotICAgTGlmZSBFeHBlY3RhbmN5LCBJbmNvbWUsIGFuZCBQb3B1bGF0aW9uIERhdGEgKG1lcmdlZCBkYXRhIGZyb20gYWJvdmUpDQotICAgQ291bnRyeSBEYXRhIChyZXNoYXBlZCkNCg0KYGBge3J9DQpMaWZlRXhwX0NsZWFuIDwtIGlubmVyX2pvaW4oTGlmZUluY29tUG9wdSwgY291bnRyaWVzLCBieSA9ICJDb3VudHJ5IikNCmBgYA0KDQpJbiBtZXJnaW5nIGJ5ICJDb3VudHJ5IiB2YXJpYWJsZSB0aGUgcmVzdWx0YW50IGRhdGEgZnJhbWUgPGZvbnQgY29sb3IgPSAicHVycGxlIj48aT5MaWZlRXhwX0NsZWFuPC9pPjwvZm9udD4gaW5jbHVkZXMgYSBzaW5nbGUgdmFyaWFibGUgZm9yIENvdW50cnkgLCBkZXNwaXRlIGJvdGggbWVyZ2VkIGRhdGEgZnJhbWVzIGNvbnRhaW5pbmcgdGhlc2UgdmFyaWFibGVzLiANCg0KPGJyPlRoaXMgcHJvY2VzcyB0cmFuc2Zvcm1lZCB0aGUgbWVyZ2VkIEluY29tZSwgTGlmZSBFeHBlY3RhbmN5LCBhbmQgUG9wdWxhdGlvbiBkYXRhIG9mIDxmb250IGNvbG9yID0gInJlZCI+PGI+NDA0Mzcgb2JzZXJ2YXRpb25zPC9iPjwvZm9udD4gb2YgPGZvbnQgY29sb3IgPSAicmVkIj48Yj41IHZhcmlhYmxlczwvYj48L2ZvbnQ+IGludG8gdGhlIHJlc2hhcGVkIGRhdGEgZnJhbWUgb2YgbWVyZ2VkIEluY29tZSwgTGlmZSBFeHBlY3RhbmN5LCBQb3B1bGF0aW9uIERhdGEsIGFuZCBDb3VudHJ5IERhdGEsKG5hbWVkIDxmb250IGNvbG9yID0gInB1cnBsZSI+PGk+TGlmZUV4cF9DbGVhbjwvaT48L2ZvbnQ+KSB0aGF0IGluY2x1ZGVzIDxmb250IGNvbG9yID0gInJlZCI+PGI+Mzc1OTAgb2JzZXJ2YXRpb25zPC9iPjwvZm9udD4gb2YgPGZvbnQgY29sb3IgPSAicmVkIj48Yj4yIHZhcmlhYmxlczwvYj48L2ZvbnQ+Lg0KDQo8YnI+PGI+QWxsIGJsYW5rIHZhbHVlcyB3ZXJlIG9taXR0ZWQgZnJvbSB0aGUgbWVyZ2VkIGRhdGEgZnJhbWUgYnkgdXRpbGl6aW5nIGlubmVyX2pvaW4oKS48L2I+DQoNCmBgYHtyIGVjaG89VFJVRX0NCnN0cihMaWZlRXhwX0NsZWFuKQ0KYGBgDQpgYGB7ciBlY2hvID0gVFJVRSwgZXZhbCA9IEZBTFNFfQ0Kd3JpdGUueGxzeChMaWZlRXhwX0NsZWFuLCBmaWxlID0gIkM6XFxVc2Vyc1xcbmF0YWxcXERvd25sb2Fkc1xcTGlmZUV4cF9DbGVhbi54bHN4IikNCmBgYA0KQSBjb3B5IG9mIHRoZSBhYm92ZSBwcmludGVkIGRhdGEgZmlsZSBjYW4gYmUgYWNjZXNzZWQgYXQgdGhlIGZvbGxvd2luZyBnaXRodWIgPGEgaHJlZj0iaHR0cHM6Ly9ubGVwZXJhLmdpdGh1Yi5pby9zdGE1NTMvdzA1X2dncGxvdC9MaWZlRXhwX0NsZWFuLnhsc3giPmxpbms8L2E+Lg0KDQo8YnI+PGJyPg0KDQoNCiMgUHJ1bmluZyB0aGUgRGF0YSBmb3IgVmlzdWFsaXphdGlvbiBQdXJwb3Nlcw0KSW4gb3JkZXIgdG8gcHJvcGVybHkgdmlzdWFsaXplIGRhdGEgb2YgdGhpcyBzY2FsZSBhIHN1YnNldCBmb3IgdGhlIHllYXIgMjAwMCB3YXMgdGFrZW4gKG5hbWVkIDxmb250IGNvbG9yID0gInB1cnBsZSI+PGk+ZGF0YTIwMDA8L2k+PC9mb250PikNCg0KYGBge3J9DQpkYXRhMjAwMCA8LSBmaWx0ZXIoTGlmZUV4cF9DbGVhbiwgWWVhciA9PSAiWDIwMDAiKQ0KYGBgDQpgYGB7ciBlY2hvPVRSVUV9DQpzdHIoZGF0YTIwMDApDQpgYGANCmBgYHtyIGVjaG8gPSBUUlVFLCBldmFsID0gRkFMU0V9DQp3cml0ZS54bHN4KGRhdGEyMDAwLCBmaWxlID0gIkM6XFxVc2Vyc1xcbmF0YWxcXERvd25sb2Fkc1xcZGF0YTIwMDAueGxzeCIpDQpgYGANCkEgY29weSBvZiB0aGUgYWJvdmUgcHJpbnRlZCBkYXRhIGZpbGUgY2FuIGJlIGFjY2Vzc2VkIGF0IHRoZSBmb2xsb3dpbmcgZ2l0aHViIDxhIGhyZWY9Imh0dHBzOi8vbmxlcGVyYS5naXRodWIuaW8vc3RhNTUzL3cwNV9nZ3Bsb3QvZGF0YTIwMDAueGxzeCI+bGluazwvYT4uDQoNCjxicj48YnI+DQoNCg0KIyBQbG90dGluZyB0aGUgRGF0YQ0KDQpUaGUgUHJlcGFyZWQgYW5kIFBydW5lZCBkYXRhIGFzIGZvdW5kIGluIDxmb250IGNvbG9yID0gInB1cnBsZSI+PGk+ZGF0YTIwMDA8L2k+PC9mb250PiBpcyBwbG90dGVkIGJlbG93LiANCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YTIwMDApKw0KICBhZXMoeCA9IEluY29tZSwgeSA9IExpZmVfRXhwLCBjb2xvciA9IENvbnRpbmVudCkrDQogIGdlb21fcG9pbnQoYWVzKHNpemUgPSBQb3B1bGF0aW9uLCBhbHBoYSA9IDAuNSkpKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSJsbSIsIGZpbGwgPSBOQSkrDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygnIzY0OEZGRicsJyM3ODVFRjAnLCAnI0RDMjY3RicsICcjRkU2MTAwJywgJyNGRkIwMDAnKSkrDQogIGxhYnMoeD0iSW5jb21lIFBlciBQZXJzb24gKCQvcGVyc29uL3llYXIpIiwgeT0iTGlmZSBFeHBlY3RhbmN5ICh5ZWFycykiLCB0aXRsZSA9ICJJbXBhY3Qgb2YgSW5jb21lIG9uIEF2ZXJhZ2UgTGlmZSBFeHBlY3RhbmN5Iiwgc3VidGl0bGUgPSAiQ29udHJvbGxlZCBmb3IgYm90aCByZWdpb24gKENvbnRpbmVudCkgYW5kIHBvcHVsYXRpb24gc2l6ZSAoUG9wdWxhdGlvbikiLCBjb2xvcj0iQ29udGluZW50Iiwgc2l6ZT0iUG9wdWxhdGlvbiIpKw0KICBndWlkZXMoYWxwaGEgPSJub25lIikNCg0KYGBgDQoNCkFzIGlsbHVzdHJhdGVkIGFib3ZlIGEgcG9zaXRpdmUgY29ycmVsYXRpb24gYmV0d2VlbiBBdmVyYWdlIEluY29tZSBQZXIgUGVyc29uIGFuZCBBdmVyYWdlIExpZmUgRXhwZWN0YW5jeSBmb3IgYWxsIGNvbnRpbmVudHMuICBDb250aW5lbnRzIHdpdGggYSBncmVhdGVyIHJhbmdlIG9mIGF2ZXJhZ2UgaW5jb21lcyBwZXIgcGVyc29uIGRlbW9uc3RyYXRlIGEgZ3JlYXRlciBwb3NpdGl2ZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIGluY29tZSBhbmQgbGlmZSBleHBlY3RhbmN5LiAgSW5jb21lIHBlciBwZXJzb24gcmFuZ2UgY2FuIGJlIHZpc3VhbGl6ZWQgYnkgdGhlIGxlbmd0aCBvZiB0aGUgbGluZWFyIHJlZ3Jlc3Npb24gbGluZXMgYWRkZWQgdG8gdGhlIGFib3ZlIHBsb3QuICBSZWdyZXNzaW9uIGxpbmVzIHRoYXQgZXh0ZW5kIHRvIGdyZWF0ZXIgeCB2YWx1ZXMgaW5kaWNhdGUgYSBncmVhdGVyIGluY29tZSByYW5nZSBmb3IgdGhlIGluZGljYXRlZCBDb250aW5lbnQuIFBvcHVsYXRpb24gc2l6ZSBpcyBtb3JlIGRpZmZpY3VsdCB0byBvYnNlcnZlIHdpdGggdGhlIGFib3ZlIHBsb3QsIGJ1dCB0aGVyZSBhcHBlYXJzIHRvIGJlIGEgbWlub3IgbmVnYXRpdmUgY29ycmVsYXRpb24gZm9yIHRoZSBBc2lhIGNvbnRpbmVudCBiZXR3ZWVuIGJvdGggcG9wdWxhdGlvbiBzaXplIGFuZCBsaWZlIGV4cGVjdGFuY3kgYXMgd2VsbCBhcyBwb3B1bGF0aW9uIHNpemUgYW5kIGluY29tZSBwZXIgcGVyc29uLiAgVGhpcyBjb3JyZWxhdGlvbiBpcyBpZGVudGlmaWVkIGJ5IHRoZSBjbHVzdGVyaW5nIG9mIGxhcmdlciBzaXplZCBwb2ludHMgY2xvc2VyIHRvd2FyZHMgdGhlIGJvdHRvbSBsZWZ0IG9mIHRoZSBwbG90IChsb3dlciB2YWx1ZXMgZm9yIGJvdGggaW5jb21lIGFuZCBsaWZlIGV4cGVjdGFuY3kpLiAgDQoNClwNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0K