1 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.


2 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.

2.1 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 ...


2.2 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 ...


2.3 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 ...


2.4 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" ...



3 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.


3.1 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 ...


3.2 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 ...


3.3 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.



4 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.



5 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