Required packages

Below packages are installed and loaded as these packages contain many of the functions that will be used in this assignment.

#To load the necessary packages
library(readr)
library(magrittr)
library(tidyr)
library(dplyr)
library(car)
library(forecast)

Executive Summary

Data preprocessing involves steps undertaken in transforming raw data into an understandable format. The chosen datasets depict the happiness score along with few other parameters such as Happiness Rank, Health Life Expectancy Rate and GDP Per Capita income of countries around the world for the years 2016 and 2017. Our goal is to compare the prosperity in these nations from 2016 to 2017.

In the process of achieving the above, we joined the two datasets by country. To obtain the training dataset, the joined dataset contained columns that had observations which were out of our interests. Hence, we selected variables - Country, Happiness_Rank_2017, Happiness_Score_2017, Happiness_Rank_2016, Happiness_Score_2016, GDP_Per_Capita_2017, GDP_Per_Capita_2016, Health_Life_Expectancy. Further steps taken are as below:

Data

The World Happiness Report is a landmark survey of the state of global happiness. Both the datasets were downloaded from https://www.kaggle.com/unsdsn/world-happiness. The datasets review the state of happiness in the world for the 2016 and 2017.

2016.csv

  1. Country : Name of the country.
  2. Region : Region the country belongs to.
  3. Happiness Rank : Rank of the country based on the Happiness Score.
  4. Happiness Score : A metric measured in 2016 by asking the sampled people the question: “How would you rate your happiness on a scale of 0 to 10 where 10 is the happiest”.
  5. Lower Confidence Interval : Lower Confidence Interval of the Happiness Score.
  6. Upper Confidence Interval : Upper Confidence Interval of the Happiness Score.
  7. Economy (GDP per Capita) : The extent to which GDP contributes to the calculation of the Happiness Score.
  8. Family : The extent to which Family contributes to the calculation of the Happiness Score.
  9. Health (Life Expectancy) : The extent to which Life expectancy contributed to the calculation of the Happiness Score.
  10. Freedom : The extent to which Freedom contributed to the calculation of the Happiness Score.
  11. Trust (Government Corruption) : The extent to which Perception of Corruption contributes to Happiness Score.
  12. Generosity : The extent to which Generosity contributed to the calculation of the Happiness Score.
  13. Dystopia Residual : The extent to which Dystopia Residual contributed to the calculation of the Happiness Score.

2017.csv

  1. Country : Name of the country.
  2. Happiness.Rank : Rank of the country based on the Happiness Score.
  3. Happiness.Score : A metric measured in 2016 by asking the sampled people the question: “How would you rate your happiness on a scale of 0 to 10 where 10 is the happiest”.
  4. Whisker.high : Highest reading of Whisker.
  5. Whisker.low : Lowest reading of Whisker.
  6. Economy..GDP.per.Capita. : The extent to which GDP contributes to the calculation of the Happiness Score.
  7. Freedom : The extent to which Freedom contributed to the calculation of the Happiness Score.
  8. Family : The extent to which Family contributes to the calculation of the Happiness Score.
  9. Generosity : The extent to which Generosity contributed to the calculation of the Happiness Score.
  10. Trust..Government.Corruption. : The extent to which Perception of Corruption contributes to Happiness Score.
  11. Dystopia.Residual : The extent to which Dystopia Residual contributed to the calculation of the Happiness Score.

We used select function to fetch the variables of our interest. We included Country, Happiness.Rank, Happiness.Score, Happiness Rank, Happiness Score, Economy..GDP.per.Capita. ,Economy (GDP per Capita), Health..Life.Expectancy.

#To read the .csv file
happy2017 <- read_csv("2017.csv")
Parsed with column specification:
cols(
  Country = col_character(),
  Happiness.Rank = col_double(),
  Happiness.Score = col_double(),
  Whisker.high = col_double(),
  Whisker.low = col_double(),
  Economy..GDP.per.Capita. = col_double(),
  Family = col_double(),
  Health..Life.Expectancy. = col_double(),
  Freedom = col_double(),
  Generosity = col_double(),
  Trust..Government.Corruption. = col_double(),
  Dystopia.Residual = col_double()
)
happy2016 <- read_csv("2016.csv")
Parsed with column specification:
cols(
  Country = col_character(),
  Region = col_character(),
  `Happiness Rank` = col_double(),
  `Happiness Score` = col_double(),
  `Lower Confidence Interval` = col_double(),
  `Upper Confidence Interval` = col_double(),
  `Economy (GDP per Capita)` = col_double(),
  Family = col_double(),
  `Health (Life Expectancy)` = col_double(),
  Freedom = col_double(),
  `Trust (Government Corruption)` = col_double(),
  Generosity = col_double(),
  `Dystopia Residual` = col_double()
)
country_combined2017_16 <- left_join(happy2017,happy2016, by = "Country")
happiness_comparision <-country_combined2017_16 %>% select(Country, Happiness.Rank,Happiness.Score,`Happiness Rank`,`Happiness Score`,Economy..GDP.per.Capita.,`Economy (GDP per Capita)`,Health..Life.Expectancy.)
print(happiness_comparision)

Understand

We renamed the names of the varaibles to increase the readability using colnames function. The str function gives the structure of the data frame and information about the type of the variables.

Furthermore, we performed type conversion of Health_Life_Expectancy, Happiness_Rank_2017, and Happiness_Rank_2016 from numeric to ordered factor. The factor function is used with ordered = “TRUE”.

Rest of the other variables are of numeric type.

#To change the name of variables
colnames(happiness_comparision)[2] <- "Happiness_Rank_2017"
colnames(happiness_comparision)[3] <- "Happiness_Score_2017"
colnames(happiness_comparision)[4] <- "Happiness_Rank_2016"
colnames(happiness_comparision)[5] <- "Happiness_Score_2016"
colnames(happiness_comparision)[6] <- "GDP_Per_Capita_2017"
colnames(happiness_comparision)[7] <- "GDP_Per_Capita_2016"
colnames(happiness_comparision)[8] <- "Health_Life_Expectancy"

str(happiness_comparision)
Classes ‘spec_tbl_df’, ‘tbl_df’, ‘tbl’ and 'data.frame':    155 obs. of  8 variables:
 $ Country               : chr  "Norway" "Denmark" "Iceland" "Switzerland" ...
 $ Happiness_Rank_2017   : num  1 2 3 4 5 6 7 8 9 10 ...
 $ Happiness_Score_2017  : num  7.54 7.52 7.5 7.49 7.47 ...
 $ Happiness_Rank_2016   : num  4 1 3 2 5 7 6 8 10 9 ...
 $ Happiness_Score_2016  : num  7.5 7.53 7.5 7.51 7.41 ...
 $ GDP_Per_Capita_2017   : num  1.62 1.48 1.48 1.56 1.44 ...
 $ GDP_Per_Capita_2016   : num  1.58 1.44 1.43 1.53 1.41 ...
 $ Health_Life_Expectancy: num  0.797 0.793 0.834 0.858 0.809 ...
happiness_comparision$Health_Life_Expectancy <- happiness_comparision$Health_Life_Expectancy*100
breaks <- c(0,20,40,60,80,100)
happiness_comparision$Health_Life_Expectancy <- happiness_comparision$Health_Life_Expectancy %>% cut(breaks = breaks, include.lowest = TRUE)
levels(happiness_comparision$Health_Life_Expectancy)
[1] "[0,20]"   "(20,40]"  "(40,60]"  "(60,80]"  "(80,100]"
happiness_comparision$Health_Life_Expectancy <- happiness_comparision$Health_Life_Expectancy %>% factor(levels = c("[0,20]", "(20,40]" , "(40,60]" , "(60,80]" , "(80,100]"), labels = c("<=20","21-40","41-60","61-80",">80"), ordered = TRUE)
levels(happiness_comparision$Health_Life_Expectancy)
[1] "<=20"  "21-40" "41-60" "61-80" ">80"  
class(happiness_comparision$Health_Life_Expectancy)
[1] "ordered" "factor" 
happiness_comparision$Happiness_Rank_2017 <- happiness_comparision$Happiness_Rank_2017 %>% factor(ordered = TRUE)
levels(happiness_comparision$Happiness_Rank_2017)
  [1] "1"   "2"   "3"   "4"   "5"   "6"   "7"   "8"   "9"   "10"  "11"  "12"  "13"  "14" 
 [15] "15"  "16"  "17"  "18"  "19"  "20"  "21"  "22"  "23"  "24"  "25"  "26"  "27"  "28" 
 [29] "29"  "30"  "31"  "32"  "33"  "34"  "35"  "36"  "37"  "38"  "39"  "40"  "41"  "42" 
 [43] "43"  "44"  "45"  "46"  "47"  "48"  "49"  "50"  "51"  "52"  "53"  "54"  "55"  "56" 
 [57] "57"  "58"  "59"  "60"  "61"  "62"  "63"  "64"  "65"  "66"  "67"  "68"  "69"  "70" 
 [71] "71"  "72"  "73"  "74"  "75"  "76"  "77"  "78"  "79"  "80"  "81"  "82"  "83"  "84" 
 [85] "85"  "86"  "87"  "88"  "89"  "90"  "91"  "92"  "93"  "94"  "95"  "96"  "97"  "98" 
 [99] "99"  "100" "101" "102" "103" "104" "105" "106" "107" "108" "109" "110" "111" "112"
[113] "113" "114" "115" "116" "117" "118" "119" "120" "121" "122" "123" "124" "125" "126"
[127] "127" "128" "129" "130" "131" "132" "133" "134" "135" "136" "137" "138" "139" "140"
[141] "141" "142" "143" "144" "145" "146" "147" "148" "149" "150" "151" "152" "153" "154"
[155] "155"
class(happiness_comparision$Happiness_Rank_2017)
[1] "ordered" "factor" 
happiness_comparision$Happiness_Rank_2016 <- happiness_comparision$Happiness_Rank_2016 %>% factor(ordered = TRUE)
levels(happiness_comparision$Happiness_Rank_2016)
  [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" 
 [29] "30"  "31"  "32"  "33"  "34"  "36"  "37"  "38"  "39"  "41"  "42"  "43"  "44"  "45" 
 [43] "46"  "47"  "48"  "49"  "50"  "51"  "52"  "53"  "54"  "55"  "56"  "57"  "59"  "60" 
 [57] "61"  "62"  "63"  "64"  "65"  "66"  "67"  "68"  "69"  "70"  "71"  "72"  "73"  "74" 
 [71] "76"  "77"  "78"  "79"  "80"  "81"  "82"  "83"  "84"  "85"  "86"  "87"  "88"  "89" 
 [85] "90"  "91"  "92"  "93"  "94"  "95"  "96"  "98"  "99"  "100" "101" "103" "104" "105"
 [99] "106" "107" "108" "109" "110" "111" "112" "113" "114" "115" "116" "117" "118" "119"
[113] "120" "121" "122" "123" "124" "125" "126" "127" "128" "129" "130" "131" "132" "133"
[127] "134" "135" "136" "137" "139" "140" "141" "142" "143" "144" "145" "147" "148" "149"
[141] "150" "151" "152" "153" "154" "155" "156" "157"
class(happiness_comparision$Happiness_Rank_2016)
[1] "ordered" "factor" 
class(happiness_comparision$Country)
[1] "character"
class(happiness_comparision$Happiness_Score_2017)
[1] "numeric"
class(happiness_comparision$Happiness_Score_2016)
[1] "numeric"
class(happiness_comparision$GDP_Per_Capita_2017)
[1] "numeric"
class(happiness_comparision$GDP_Per_Capita_2016)
[1] "numeric"

Tidy & Manipulate Data I

According to the three interrelated rules which make a dataset tidy (Hadley Wickham and Grolemund (2016)). In tidy data:

Our dataset obeys all the above mentioned principles. Sample of first 10 rows is displayed using the print() function to show the dataset is tidy.

print(happiness_comparision[ , (1:4)])
print(happiness_comparision[ , -(1:4)])
dim(happiness_comparision)
[1] 155   8

Tidy & Manipulate Data II

We have created a new variable Diff_In_Happiness which is the absolute difference between the happiness scores of 2017 and 2016 by using mutate function.

#To create a new variable
happiness_comparision <- happiness_comparision %>% mutate(Diff_In_Happiness = abs(Happiness_Score_2017 - Happiness_Score_2016))

print(happiness_comparision[ , c(1,3,5,9)])
dim(happiness_comparision)
[1] 155   9

Scan I

To scan the missing values, inconsistencies and obvious errors, we made use of is.na, is.infinite, is.nan functions. We observed that there are 20 missing values and no special values.

The missing value percentage was found out to be 1.433692% (20 out of 1395 values). Since the percentage of missing values is less than 5%, we decided to omit these missing values using na.omit to proceed further. In fact, the omitted 5 rows were the countries that were present in the 2017 dataset but not in 2016.

#To find sum of missing values
sum(is.na(happiness_comparision))
[1] 20
#To find sum of infinite values
sum(sapply(happiness_comparision, is.infinite))
[1] 0
#To find sum of not a number(NAN) values
sum(sapply(happiness_comparision, is.nan))
[1] 0
Total_value <- nrow(happiness_comparision) * ncol(happiness_comparision)
NA_Percentage <- sum(is.na(happiness_comparision)) * 100 / Total_value
NA_Percentage
[1] 1.433692
happiness_comparision <- na.omit(happiness_comparision)
sum(is.na(happiness_comparision))
[1] 0
dim(happiness_comparision)
[1] 150   9

Scan II

We have used Boxplot function to check if there are any outliers in the numeric variables. From Figure-5, We can see that Diff_In_Happiness variable has outliers. We successfully handled these outliers by capping them with nearest quantile value. Figure-6 shows that there are no outliers in Diff_In_Happiness after capping.

#To visualize outliers
Boxplot(happiness_comparision$Happiness_Score_2016)

Figure - 1

Boxplot(happiness_comparision$Happiness_Score_2017)

Figure - 2

Boxplot(happiness_comparision$GDP_Per_Capita_2016)

Figure - 3

Boxplot(happiness_comparision$GDP_Per_Capita_2017)

Figure - 4

Boxplot(happiness_comparision$Diff_In_Happiness)
[1]  52  80 103 137 141

Figure - 5

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

happiness_comparision$Diff_In_Happiness <- happiness_comparision$Diff_In_Happiness %>% cap()
Boxplot(happiness_comparision$Diff_In_Happiness)

Figure - 6

Transform

In order to decrease the skewness (shown in the Figure-7) and convert the distribution into a normal distribution of the variable Happiness_Score_2016, we used BoxCox tranformation. The resultant distribution (shown in the Figure-8) showed right skewness and hence we applied square root transformation on boxcox_Happiness_Score_2016 to obtain normal distribution (shown in the Figure-9). BoxCox and sqrt functions are made use for the purpose of transformation. hist function is used to visualize the distribution.

Even from the summary function, we can infer that “mean” and “median” values are almost equal. Difference between these values is less than 0.5(0.031). Hence the distribution is normal.

Now, the variable Tranformed_Happiness_Score_2016 is normally distributed.

#To visualize distribution
hist(happiness_comparision$Happiness_Score_2016)

Figure - 7

happiness_comparision$boxcox_Happiness_Score_2016 <- BoxCox(happiness_comparision$`Happiness_Score_2016`,lambda = "auto")
hist(happiness_comparision$boxcox_Happiness_Score_2016)

Figure - 8

happiness_comparision$Tranformed_Happiness_Score_2016 <- sqrt(happiness_comparision$boxcox_Happiness_Score_2016)
hist(happiness_comparision$Tranformed_Happiness_Score_2016)

Figure - 9

summary(happiness_comparision$Tranformed_Happiness_Score_2016)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  1.829   2.798   3.364   3.395   3.927   4.699 

Reference

LS0tCnRpdGxlOiAiTUFUSDIzNDkgU2VtZXN0ZXIgMiwgMjAxOSIKYXV0aG9yOiAiU3VtdWtoYSBWZW5rYXRlc2hhIE11cnRoeSAoczM3OTc4NjYpIDxici8+QW5pbGt1bWFyIExpbmdhcmFqIEJpcmFkYXIgKHMzNzk4MDI0KSA8YnIvPiBBbW9naGEgQW1hcmVzaCAoczM3ODkxNjApIgpzdWJ0aXRsZTogQXNzaWdubWVudCAzCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0Ci0tLQoKIyMgUmVxdWlyZWQgcGFja2FnZXMgCkJlbG93IHBhY2thZ2VzIGFyZSBpbnN0YWxsZWQgYW5kIGxvYWRlZCBhcyB0aGVzZSBwYWNrYWdlcyBjb250YWluIG1hbnkgb2YgdGhlIGZ1bmN0aW9ucyB0aGF0IHdpbGwgYmUgdXNlZCBpbiB0aGlzIGFzc2lnbm1lbnQuCmBgYHtyfQojVG8gbG9hZCB0aGUgbmVjZXNzYXJ5IHBhY2thZ2VzCmxpYnJhcnkocmVhZHIpCmxpYnJhcnkobWFncml0dHIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoY2FyKQpsaWJyYXJ5KGZvcmVjYXN0KQpgYGAKCiMjIEV4ZWN1dGl2ZSBTdW1tYXJ5IAoqRGF0YSBwcmVwcm9jZXNzaW5nKiBpbnZvbHZlcyBzdGVwcyB1bmRlcnRha2VuIGluIHRyYW5zZm9ybWluZyByYXcgZGF0YSBpbnRvIGFuIHVuZGVyc3RhbmRhYmxlIGZvcm1hdC4gVGhlIGNob3NlbiBkYXRhc2V0cyBkZXBpY3QgdGhlIGhhcHBpbmVzcyBzY29yZSBhbG9uZyB3aXRoIGZldyBvdGhlciBwYXJhbWV0ZXJzIHN1Y2ggYXMgSGFwcGluZXNzIFJhbmssIEhlYWx0aCBMaWZlIEV4cGVjdGFuY3kgUmF0ZSBhbmQgR0RQIFBlciBDYXBpdGEgaW5jb21lIG9mIGNvdW50cmllcyBhcm91bmQgdGhlIHdvcmxkIGZvciB0aGUgeWVhcnMgMjAxNiBhbmQgMjAxNy4gT3VyIGdvYWwgaXMgdG8gY29tcGFyZSB0aGUgcHJvc3Blcml0eSBpbiB0aGVzZSBuYXRpb25zIGZyb20gMjAxNiB0byAyMDE3LgoKSW4gdGhlIHByb2Nlc3Mgb2YgYWNoaWV2aW5nIHRoZSBhYm92ZSwgd2Ugam9pbmVkIHRoZSB0d28gZGF0YXNldHMgYnkgY291bnRyeS4gVG8gb2J0YWluIHRoZSB0cmFpbmluZyBkYXRhc2V0LCB0aGUgam9pbmVkIGRhdGFzZXQgY29udGFpbmVkIGNvbHVtbnMgdGhhdCBoYWQgb2JzZXJ2YXRpb25zIHdoaWNoIHdlcmUgb3V0IG9mIG91ciBpbnRlcmVzdHMuIEhlbmNlLCB3ZSBzZWxlY3RlZCB2YXJpYWJsZXMgLSBgQ291bnRyeWAsIGBIYXBwaW5lc3NfUmFua18yMDE3YCwgYEhhcHBpbmVzc19TY29yZV8yMDE3YCwgYEhhcHBpbmVzc19SYW5rXzIwMTZgLCBgSGFwcGluZXNzX1Njb3JlXzIwMTZgLCBgR0RQX1Blcl9DYXBpdGFfMjAxN2AsIGBHRFBfUGVyX0NhcGl0YV8yMDE2YCwgYEhlYWx0aF9MaWZlX0V4cGVjdGFuY3lgLiBGdXJ0aGVyIHN0ZXBzIHRha2VuIGFyZSBhcyBiZWxvdzoKICAKICAqIEFzIGEgcGFydCBvZiB0aWR5aW5nIHRoZSBkYXRhc2V0LCB3ZSBzdGFydGVkIGZyb20gcmVuYW1pbmcgdGhlIHZhcmlhYmxlcy4gIAogICogVGhlIGRhdGF0eXBlIG9mIGZldyB2YXJpYWJsZXMgc3VjaCBhcyBgSGFwcGluZXNzX1JhbmtfMjAxNmAgYW5kIGBIYXBwaW5lc3NfUmFua18yMDE3YCB3YXMgY29udmVydGVkIHRvIGFuIG9yZGVyZWQgZmFjdG9yLiBUaGUgdmFyaWFibGUgYEhlYWx0aF9MaWZlX0V4cGVjdGFuY3lgIHdoaWNoIHJlcHJlc2VudGVkIHBlcmNlbnRhZ2UgdmFsdWVzIHdhcyBjb252ZXJ0ZWQgZnJvbSBkZWNpbWFsIHRvIHBlcmNlbnRhZ2UgYW5kIHRoZW4gZ3JvdXBlZCBhcyBhbiBvcmRlcmVkIGZhY3RvciBmb3IgYmV0dGVyIHVuZGVyc3RhbmRpbmcuIFRodXMsIGVuY29kaW5nIGNhdGVnb3JpY2FsIHZhbHVlcy4gIAogICogSW4gb3JkZXIgdG8gY29tcGFyZSB0aGUgZGF0YSBmcm9tIDIwMTYgYW5kIDIwMTcsIHdlIGNyZWF0ZWQgYSBuZXcgY29sdW1uIGBEaWZmX0luX0hhcHBpbmVzc2AgdGhhdCBnYXZlIHVzIHRoZSBhYnNvbHV0ZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIEhhcHBpbmVzcyBTY29yZSBpbiB0aGUgY291cnNlIG9mIHR3byB5ZWFycy4gIAogICogQmVmb3JlIGRlcml2aW5nIHRoZSBjb25jbHVzaW9ucyBvdXQgb2Ygb3VyIGRhdGFzZXQsIHRha2luZyBjYXJlIG9mIG1pc3NpbmcgRGF0YSBmcm9tIHRoZSBkYXRhc2V0IGlzIGNydWNpYWwuIFRoZSBwZXJjZW50YWdlIG9mIG1pc3NpbmcgdmFsdWVzIGluIG91ciBkYXRhc2V0IHdhcyBjYWxjdWxhdGVkIGFuZCB3YXMgZm91bmQgdG8gYmUgbGVzcyB0aGFuIDUlLiBIZW5jZSBvbWl0dGluZyB0aGVzZSByb3dzIGRpZCBub3QgbWFrZSBhbnkgaW1wYWN0IG9uIHRoZSBhbmFseXNpcy4gIAogICogSGFuZGxpbmcgb3V0bGllcnMgaXMgYWxzbyBhbiBpbXBvcnRhbnQgc3RlcCBpbiBkYXRhIHByZXByb2Nlc3NpbmcuIEFsbCB0aGUgbnVtZXJpYyB2YXJpYWJsZXMgZXhjZXB0IGBIYXBwaW5lc3NfUmFua18yMDE2YCBoYWQgbm8gb3V0bGllcnMuIE91dGxpZXJzIGluIGBIYXBwaW5lc3NfUmFua18yMDE2YCB3ZXJlIGhhbmRsZWQgYnkgY2FwcGluZyB0aGVtIHdpdGggdGhlIG5lYXJlc3QgcXVhbnRpbGUgdmFsdWUuICAKICAqIEFsbW9zdCBhbGwgbnVtZXJpY2FsIHZhcmlhYmxlcyB3ZXJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIGJ1dCBgSGFwcGluZXNzX1JhbmtfMjAxNmAgc2hvd2VkIHNrZXduZXNzLiBXZSB1c2VkIEJveENveCBhbmQgc3F1YXJlIHJvb3QgdHJhbnNmb3JtYXRpb24gbWV0aG9kIG9uIHRoZSB2YXJpYWJsZSBhbmQgdHJhbnNmb3JtZWQgdGhlIHZhcmlhYmxlIHRvIGJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLgoKIyMgRGF0YSAKVGhlIFdvcmxkIEhhcHBpbmVzcyBSZXBvcnQgaXMgYSBsYW5kbWFyayBzdXJ2ZXkgb2YgdGhlIHN0YXRlIG9mIGdsb2JhbCBoYXBwaW5lc3MuIEJvdGggdGhlIGRhdGFzZXRzIHdlcmUgZG93bmxvYWRlZCBmcm9tIGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vdW5zZHNuL3dvcmxkLWhhcHBpbmVzcy4gVGhlIGRhdGFzZXRzIHJldmlldyB0aGUgc3RhdGUgb2YgaGFwcGluZXNzIGluIHRoZSB3b3JsZCBmb3IgdGhlIDIwMTYgYW5kIDIwMTcuCgo8dT4qKjIwMTYuY3N2KiogIDwvdT4gIAogIAogIDEuICoqQ291bnRyeSoqIDogTmFtZSBvZiB0aGUgY291bnRyeS4gIAoyLiAqKlJlZ2lvbioqIDogUmVnaW9uIHRoZSBjb3VudHJ5IGJlbG9uZ3MgdG8uICAKMy4gKipIYXBwaW5lc3MgUmFuayoqIDogUmFuayBvZiB0aGUgY291bnRyeSBiYXNlZCBvbiB0aGUgSGFwcGluZXNzIFNjb3JlLiAgCjQuICoqSGFwcGluZXNzIFNjb3JlKiogOiBBIG1ldHJpYyBtZWFzdXJlZCBpbiAyMDE2IGJ5IGFza2luZyB0aGUgc2FtcGxlZCBwZW9wbGUgdGhlIHF1ZXN0aW9uOiAiSG93IHdvdWxkIHlvdSByYXRlIHlvdXIgaGFwcGluZXNzIG9uIGEgc2NhbGUgb2YgMCB0byAxMCB3aGVyZSAxMCBpcyB0aGUgaGFwcGllc3QiLiAgCjUuICoqTG93ZXIgQ29uZmlkZW5jZSBJbnRlcnZhbCoqIDogTG93ZXIgQ29uZmlkZW5jZSBJbnRlcnZhbCBvZiB0aGUgSGFwcGluZXNzIFNjb3JlLiAgCjYuICoqVXBwZXIgQ29uZmlkZW5jZSBJbnRlcnZhbCoqIDogVXBwZXIgQ29uZmlkZW5jZSBJbnRlcnZhbCBvZiB0aGUgSGFwcGluZXNzIFNjb3JlLiAgCjcuICoqRWNvbm9teSAoR0RQIHBlciBDYXBpdGEpKiogOiBUaGUgZXh0ZW50IHRvIHdoaWNoIEdEUCBjb250cmlidXRlcyB0byB0aGUgY2FsY3VsYXRpb24gb2YgdGhlIEhhcHBpbmVzcyBTY29yZS4gIAo4LiAqKkZhbWlseSoqIDogVGhlIGV4dGVudCB0byB3aGljaCBGYW1pbHkgY29udHJpYnV0ZXMgdG8gdGhlIGNhbGN1bGF0aW9uIG9mIHRoZSBIYXBwaW5lc3MgU2NvcmUuICAKOS4gKipIZWFsdGggKExpZmUgRXhwZWN0YW5jeSkqKiA6IFRoZSBleHRlbnQgdG8gd2hpY2ggTGlmZSBleHBlY3RhbmN5IGNvbnRyaWJ1dGVkIHRvIHRoZSBjYWxjdWxhdGlvbiBvZiB0aGUgSGFwcGluZXNzIFNjb3JlLiAgCjEwLiAqKkZyZWVkb20qKiA6IFRoZSBleHRlbnQgdG8gd2hpY2ggRnJlZWRvbSBjb250cmlidXRlZCB0byB0aGUgY2FsY3VsYXRpb24gb2YgdGhlIEhhcHBpbmVzcyBTY29yZS4gIAoxMS4gKipUcnVzdCAoR292ZXJubWVudCBDb3JydXB0aW9uKSoqIDogVGhlIGV4dGVudCB0byB3aGljaCBQZXJjZXB0aW9uIG9mIENvcnJ1cHRpb24gY29udHJpYnV0ZXMgdG8gSGFwcGluZXNzIFNjb3JlLiAgCjEyLiAqKkdlbmVyb3NpdHkqKiA6IFRoZSBleHRlbnQgdG8gd2hpY2ggR2VuZXJvc2l0eSBjb250cmlidXRlZCB0byB0aGUgY2FsY3VsYXRpb24gb2YgdGhlIEhhcHBpbmVzcyBTY29yZS4gIAoxMy4gKipEeXN0b3BpYSBSZXNpZHVhbCoqIDogVGhlIGV4dGVudCB0byB3aGljaCBEeXN0b3BpYSBSZXNpZHVhbCBjb250cmlidXRlZCB0byB0aGUgY2FsY3VsYXRpb24gb2YgdGhlIEhhcHBpbmVzcyBTY29yZS4gIAoKPHU+KioyMDE3LmNzdioqIDwvdT4gIAogIAogIDEuICoqQ291bnRyeSoqIDogTmFtZSBvZiB0aGUgY291bnRyeS4gIAoyLiAqKkhhcHBpbmVzcy5SYW5rKiogOiBSYW5rIG9mIHRoZSBjb3VudHJ5IGJhc2VkIG9uIHRoZSBIYXBwaW5lc3MgU2NvcmUuICAKMy4gKipIYXBwaW5lc3MuU2NvcmUqKiA6IEEgbWV0cmljIG1lYXN1cmVkIGluIDIwMTYgYnkgYXNraW5nIHRoZSBzYW1wbGVkIHBlb3BsZSB0aGUgcXVlc3Rpb246ICJIb3cgd291bGQgeW91IHJhdGUgeW91ciBoYXBwaW5lc3Mgb24gYSBzY2FsZSBvZiAwIHRvIDEwIHdoZXJlIDEwIGlzIHRoZSBoYXBwaWVzdCIuICAKNC4gKipXaGlza2VyLmhpZ2gqKiA6IEhpZ2hlc3QgcmVhZGluZyBvZiBXaGlza2VyLiAgCjUuICoqV2hpc2tlci5sb3cqKiA6IExvd2VzdCByZWFkaW5nIG9mIFdoaXNrZXIuICAKNi4gKipFY29ub215Li5HRFAucGVyLkNhcGl0YS4qKiA6IFRoZSBleHRlbnQgdG8gd2hpY2ggR0RQIGNvbnRyaWJ1dGVzIHRvIHRoZSBjYWxjdWxhdGlvbiBvZiB0aGUgSGFwcGluZXNzIFNjb3JlLiAgCjcuICoqRnJlZWRvbSoqIDogVGhlIGV4dGVudCB0byB3aGljaCBGcmVlZG9tIGNvbnRyaWJ1dGVkIHRvIHRoZSBjYWxjdWxhdGlvbiBvZiB0aGUgSGFwcGluZXNzIFNjb3JlLiAgCjguICoqRmFtaWx5KiogOiBUaGUgZXh0ZW50IHRvIHdoaWNoIEZhbWlseSBjb250cmlidXRlcyB0byB0aGUgY2FsY3VsYXRpb24gb2YgdGhlIEhhcHBpbmVzcyBTY29yZS4gIAo5LiAqKkdlbmVyb3NpdHkqKiA6IFRoZSBleHRlbnQgdG8gd2hpY2ggR2VuZXJvc2l0eSBjb250cmlidXRlZCB0byB0aGUgY2FsY3VsYXRpb24gb2YgdGhlIEhhcHBpbmVzcyBTY29yZS4gIAoxMC4gKipUcnVzdC4uR292ZXJubWVudC5Db3JydXB0aW9uLioqIDogVGhlIGV4dGVudCB0byB3aGljaCBQZXJjZXB0aW9uIG9mIENvcnJ1cHRpb24gY29udHJpYnV0ZXMgdG8gSGFwcGluZXNzIFNjb3JlLiAgCjExLiAqKkR5c3RvcGlhLlJlc2lkdWFsKiogOiBUaGUgZXh0ZW50IHRvIHdoaWNoIER5c3RvcGlhIFJlc2lkdWFsIGNvbnRyaWJ1dGVkIHRvIHRoZSBjYWxjdWxhdGlvbiBvZiB0aGUgSGFwcGluZXNzIFNjb3JlLiAgCgpXZSB1c2VkICoqKnNlbGVjdCoqKiBmdW5jdGlvbiB0byBmZXRjaCB0aGUgdmFyaWFibGVzIG9mIG91ciBpbnRlcmVzdC4gV2UgaW5jbHVkZWQgYENvdW50cnlgLCBgSGFwcGluZXNzLlJhbmtgLCBgSGFwcGluZXNzLlNjb3JlYCwgYEhhcHBpbmVzcyBSYW5rYCwgYEhhcHBpbmVzcyBTY29yZWAsIGBFY29ub215Li5HRFAucGVyLkNhcGl0YS5gICxgRWNvbm9teSAoR0RQIHBlciBDYXBpdGEpYCwgYEhlYWx0aC4uTGlmZS5FeHBlY3RhbmN5YC4KCmBgYHtyfQojVG8gcmVhZCB0aGUgLmNzdiBmaWxlCmhhcHB5MjAxNyA8LSByZWFkX2NzdigiMjAxNy5jc3YiKQpoYXBweTIwMTYgPC0gcmVhZF9jc3YoIjIwMTYuY3N2IikKY291bnRyeV9jb21iaW5lZDIwMTdfMTYgPC0gbGVmdF9qb2luKGhhcHB5MjAxNyxoYXBweTIwMTYsIGJ5ID0gIkNvdW50cnkiKQpoYXBwaW5lc3NfY29tcGFyaXNpb24gPC1jb3VudHJ5X2NvbWJpbmVkMjAxN18xNiAlPiUgc2VsZWN0KENvdW50cnksIEhhcHBpbmVzcy5SYW5rLEhhcHBpbmVzcy5TY29yZSxgSGFwcGluZXNzIFJhbmtgLGBIYXBwaW5lc3MgU2NvcmVgLEVjb25vbXkuLkdEUC5wZXIuQ2FwaXRhLixgRWNvbm9teSAoR0RQIHBlciBDYXBpdGEpYCxIZWFsdGguLkxpZmUuRXhwZWN0YW5jeS4pCnByaW50KGhhcHBpbmVzc19jb21wYXJpc2lvbikKYGBgCgojIyBVbmRlcnN0YW5kCldlIHJlbmFtZWQgdGhlIG5hbWVzIG9mIHRoZSB2YXJhaWJsZXMgdG8gaW5jcmVhc2UgdGhlIHJlYWRhYmlsaXR5IHVzaW5nICoqKmNvbG5hbWVzKioqIGZ1bmN0aW9uLiBUaGUgKioqc3RyKioqIGZ1bmN0aW9uIGdpdmVzIHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIGRhdGEgZnJhbWUgYW5kIGluZm9ybWF0aW9uIGFib3V0IHRoZSB0eXBlIG9mIHRoZSB2YXJpYWJsZXMuCgpGdXJ0aGVybW9yZSwgd2UgcGVyZm9ybWVkIHR5cGUgY29udmVyc2lvbiBvZiBgSGVhbHRoX0xpZmVfRXhwZWN0YW5jeWAsIGBIYXBwaW5lc3NfUmFua18yMDE3YCwgYW5kIGBIYXBwaW5lc3NfUmFua18yMDE2YCBmcm9tIG51bWVyaWMgdG8gb3JkZXJlZCBmYWN0b3IuIFRoZSAqKipmYWN0b3IqKiogZnVuY3Rpb24gaXMgdXNlZCB3aXRoIG9yZGVyZWQgPSAiVFJVRSIuCgpSZXN0IG9mIHRoZSBvdGhlciB2YXJpYWJsZXMgYXJlIG9mIG51bWVyaWMgdHlwZS4KYGBge3J9CiNUbyBjaGFuZ2UgdGhlIG5hbWUgb2YgdmFyaWFibGVzCmNvbG5hbWVzKGhhcHBpbmVzc19jb21wYXJpc2lvbilbMl0gPC0gIkhhcHBpbmVzc19SYW5rXzIwMTciCmNvbG5hbWVzKGhhcHBpbmVzc19jb21wYXJpc2lvbilbM10gPC0gIkhhcHBpbmVzc19TY29yZV8yMDE3Igpjb2xuYW1lcyhoYXBwaW5lc3NfY29tcGFyaXNpb24pWzRdIDwtICJIYXBwaW5lc3NfUmFua18yMDE2Igpjb2xuYW1lcyhoYXBwaW5lc3NfY29tcGFyaXNpb24pWzVdIDwtICJIYXBwaW5lc3NfU2NvcmVfMjAxNiIKY29sbmFtZXMoaGFwcGluZXNzX2NvbXBhcmlzaW9uKVs2XSA8LSAiR0RQX1Blcl9DYXBpdGFfMjAxNyIKY29sbmFtZXMoaGFwcGluZXNzX2NvbXBhcmlzaW9uKVs3XSA8LSAiR0RQX1Blcl9DYXBpdGFfMjAxNiIKY29sbmFtZXMoaGFwcGluZXNzX2NvbXBhcmlzaW9uKVs4XSA8LSAiSGVhbHRoX0xpZmVfRXhwZWN0YW5jeSIKCnN0cihoYXBwaW5lc3NfY29tcGFyaXNpb24pCgpoYXBwaW5lc3NfY29tcGFyaXNpb24kSGVhbHRoX0xpZmVfRXhwZWN0YW5jeSA8LSBoYXBwaW5lc3NfY29tcGFyaXNpb24kSGVhbHRoX0xpZmVfRXhwZWN0YW5jeSoxMDAKYnJlYWtzIDwtIGMoMCwyMCw0MCw2MCw4MCwxMDApCmhhcHBpbmVzc19jb21wYXJpc2lvbiRIZWFsdGhfTGlmZV9FeHBlY3RhbmN5IDwtIGhhcHBpbmVzc19jb21wYXJpc2lvbiRIZWFsdGhfTGlmZV9FeHBlY3RhbmN5ICU+JSBjdXQoYnJlYWtzID0gYnJlYWtzLCBpbmNsdWRlLmxvd2VzdCA9IFRSVUUpCmxldmVscyhoYXBwaW5lc3NfY29tcGFyaXNpb24kSGVhbHRoX0xpZmVfRXhwZWN0YW5jeSkKaGFwcGluZXNzX2NvbXBhcmlzaW9uJEhlYWx0aF9MaWZlX0V4cGVjdGFuY3kgPC0gaGFwcGluZXNzX2NvbXBhcmlzaW9uJEhlYWx0aF9MaWZlX0V4cGVjdGFuY3kgJT4lIGZhY3RvcihsZXZlbHMgPSBjKCJbMCwyMF0iLCAiKDIwLDQwXSIgLCAiKDQwLDYwXSIgLCAiKDYwLDgwXSIgLCAiKDgwLDEwMF0iKSwgbGFiZWxzID0gYygiPD0yMCIsIjIxLTQwIiwiNDEtNjAiLCI2MS04MCIsIj44MCIpLCBvcmRlcmVkID0gVFJVRSkKbGV2ZWxzKGhhcHBpbmVzc19jb21wYXJpc2lvbiRIZWFsdGhfTGlmZV9FeHBlY3RhbmN5KQpjbGFzcyhoYXBwaW5lc3NfY29tcGFyaXNpb24kSGVhbHRoX0xpZmVfRXhwZWN0YW5jeSkKCmhhcHBpbmVzc19jb21wYXJpc2lvbiRIYXBwaW5lc3NfUmFua18yMDE3IDwtIGhhcHBpbmVzc19jb21wYXJpc2lvbiRIYXBwaW5lc3NfUmFua18yMDE3ICU+JSBmYWN0b3Iob3JkZXJlZCA9IFRSVUUpCmxldmVscyhoYXBwaW5lc3NfY29tcGFyaXNpb24kSGFwcGluZXNzX1JhbmtfMjAxNykKY2xhc3MoaGFwcGluZXNzX2NvbXBhcmlzaW9uJEhhcHBpbmVzc19SYW5rXzIwMTcpCgpoYXBwaW5lc3NfY29tcGFyaXNpb24kSGFwcGluZXNzX1JhbmtfMjAxNiA8LSBoYXBwaW5lc3NfY29tcGFyaXNpb24kSGFwcGluZXNzX1JhbmtfMjAxNiAlPiUgZmFjdG9yKG9yZGVyZWQgPSBUUlVFKQpsZXZlbHMoaGFwcGluZXNzX2NvbXBhcmlzaW9uJEhhcHBpbmVzc19SYW5rXzIwMTYpCmNsYXNzKGhhcHBpbmVzc19jb21wYXJpc2lvbiRIYXBwaW5lc3NfUmFua18yMDE2KQoKY2xhc3MoaGFwcGluZXNzX2NvbXBhcmlzaW9uJENvdW50cnkpCmNsYXNzKGhhcHBpbmVzc19jb21wYXJpc2lvbiRIYXBwaW5lc3NfU2NvcmVfMjAxNykKY2xhc3MoaGFwcGluZXNzX2NvbXBhcmlzaW9uJEhhcHBpbmVzc19TY29yZV8yMDE2KQpjbGFzcyhoYXBwaW5lc3NfY29tcGFyaXNpb24kR0RQX1Blcl9DYXBpdGFfMjAxNykKY2xhc3MoaGFwcGluZXNzX2NvbXBhcmlzaW9uJEdEUF9QZXJfQ2FwaXRhXzIwMTYpCmBgYAoKIyMJVGlkeSAmIE1hbmlwdWxhdGUgRGF0YSBJCkFjY29yZGluZyB0byB0aGUgdGhyZWUgaW50ZXJyZWxhdGVkIHJ1bGVzIHdoaWNoIG1ha2UgYSBkYXRhc2V0IHRpZHkgKEhhZGxleSBXaWNraGFtIGFuZCBHcm9sZW11bmQgKDIwMTYpKS4gSW4gdGlkeSBkYXRhOiAgCiAgCiAgKiBFYWNoIHZhcmlhYmxlIG11c3QgaGF2ZSBpdHMgb3duIGNvbHVtbi4gIAogICogRWFjaCBvYnNlcnZhdGlvbiBtdXN0IGhhdmUgaXRzIG93biByb3cuICAKICAqIEVhY2ggdmFsdWUgbXVzdCBoYXZlIGl0cyBvd24gY2VsbC4gIAogIApPdXIgZGF0YXNldCBvYmV5cyBhbGwgdGhlIGFib3ZlIG1lbnRpb25lZCBwcmluY2lwbGVzLiBTYW1wbGUgb2YgZmlyc3QgMTAgcm93cyBpcyBkaXNwbGF5ZWQgdXNpbmcgdGhlIHByaW50KCkgZnVuY3Rpb24gdG8gc2hvdyB0aGUgZGF0YXNldCBpcyB0aWR5LgoKYGBge3J9CnByaW50KGhhcHBpbmVzc19jb21wYXJpc2lvblsgLCAoMTo0KV0pCnByaW50KGhhcHBpbmVzc19jb21wYXJpc2lvblsgLCAtKDE6NCldKQpkaW0oaGFwcGluZXNzX2NvbXBhcmlzaW9uKQpgYGAKCiMjCVRpZHkgJiBNYW5pcHVsYXRlIERhdGEgSUkgCldlIGhhdmUgY3JlYXRlZCBhIG5ldyB2YXJpYWJsZSBgRGlmZl9Jbl9IYXBwaW5lc3NgIHdoaWNoIGlzIHRoZSBhYnNvbHV0ZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIGhhcHBpbmVzcyBzY29yZXMgb2YgMjAxNyBhbmQgMjAxNiBieSB1c2luZyAqKiptdXRhdGUqKiogZnVuY3Rpb24uCgpgYGB7cn0KI1RvIGNyZWF0ZSBhIG5ldyB2YXJpYWJsZQpoYXBwaW5lc3NfY29tcGFyaXNpb24gPC0gaGFwcGluZXNzX2NvbXBhcmlzaW9uICU+JSBtdXRhdGUoRGlmZl9Jbl9IYXBwaW5lc3MgPSBhYnMoSGFwcGluZXNzX1Njb3JlXzIwMTcgLSBIYXBwaW5lc3NfU2NvcmVfMjAxNikpCgpwcmludChoYXBwaW5lc3NfY29tcGFyaXNpb25bICwgYygxLDMsNSw5KV0pCmRpbShoYXBwaW5lc3NfY29tcGFyaXNpb24pCmBgYAoKIyMJU2NhbiBJIApUbyBzY2FuIHRoZSBtaXNzaW5nIHZhbHVlcywgaW5jb25zaXN0ZW5jaWVzIGFuZCBvYnZpb3VzIGVycm9ycywgd2UgbWFkZSB1c2Ugb2YgKioqaXMubmEqKiosICoqKmlzLmluZmluaXRlKioqLCAqKippcy5uYW4qKiogZnVuY3Rpb25zLiBXZSBvYnNlcnZlZCB0aGF0IHRoZXJlIGFyZSAyMCBtaXNzaW5nIHZhbHVlcyBhbmQgbm8gc3BlY2lhbCB2YWx1ZXMuIAoKVGhlIG1pc3NpbmcgdmFsdWUgcGVyY2VudGFnZSB3YXMgZm91bmQgb3V0IHRvIGJlIDEuNDMzNjkyJSAoMjAgb3V0IG9mIDEzOTUgdmFsdWVzKS4gU2luY2UgdGhlIHBlcmNlbnRhZ2Ugb2YgbWlzc2luZyB2YWx1ZXMgaXMgbGVzcyB0aGFuIDUlLCB3ZSBkZWNpZGVkIHRvIG9taXQgdGhlc2UgbWlzc2luZyB2YWx1ZXMgdXNpbmcgKioqbmEub21pdCoqKiB0byBwcm9jZWVkIGZ1cnRoZXIuIEluIGZhY3QsIHRoZSBvbWl0dGVkIDUgcm93cyB3ZXJlIHRoZSBjb3VudHJpZXMgdGhhdCB3ZXJlIHByZXNlbnQgaW4gdGhlIDIwMTcgZGF0YXNldCBidXQgbm90IGluIDIwMTYuCgpgYGB7cn0KI1RvIGZpbmQgc3VtIG9mIG1pc3NpbmcgdmFsdWVzCnN1bShpcy5uYShoYXBwaW5lc3NfY29tcGFyaXNpb24pKQojVG8gZmluZCBzdW0gb2YgaW5maW5pdGUgdmFsdWVzCnN1bShzYXBwbHkoaGFwcGluZXNzX2NvbXBhcmlzaW9uLCBpcy5pbmZpbml0ZSkpCiNUbyBmaW5kIHN1bSBvZiBub3QgYSBudW1iZXIoTkFOKSB2YWx1ZXMKc3VtKHNhcHBseShoYXBwaW5lc3NfY29tcGFyaXNpb24sIGlzLm5hbikpCgpUb3RhbF92YWx1ZSA8LSBucm93KGhhcHBpbmVzc19jb21wYXJpc2lvbikgKiBuY29sKGhhcHBpbmVzc19jb21wYXJpc2lvbikKTkFfUGVyY2VudGFnZSA8LSBzdW0oaXMubmEoaGFwcGluZXNzX2NvbXBhcmlzaW9uKSkgKiAxMDAgLyBUb3RhbF92YWx1ZQpOQV9QZXJjZW50YWdlCgpoYXBwaW5lc3NfY29tcGFyaXNpb24gPC0gbmEub21pdChoYXBwaW5lc3NfY29tcGFyaXNpb24pCnN1bShpcy5uYShoYXBwaW5lc3NfY29tcGFyaXNpb24pKQpkaW0oaGFwcGluZXNzX2NvbXBhcmlzaW9uKQpgYGAKCiMjCVNjYW4gSUkKV2UgaGF2ZSB1c2VkICoqKkJveHBsb3QqKiogZnVuY3Rpb24gdG8gY2hlY2sgaWYgdGhlcmUgYXJlIGFueSBvdXRsaWVycyBpbiB0aGUgbnVtZXJpYyB2YXJpYWJsZXMuIEZyb20gKipGaWd1cmUtNSoqLCBXZSBjYW4gc2VlIHRoYXQgYERpZmZfSW5fSGFwcGluZXNzYCB2YXJpYWJsZSBoYXMgb3V0bGllcnMuIFdlIHN1Y2Nlc3NmdWxseSBoYW5kbGVkIHRoZXNlIG91dGxpZXJzIGJ5IGNhcHBpbmcgdGhlbSB3aXRoIG5lYXJlc3QgcXVhbnRpbGUgdmFsdWUuICoqRmlndXJlLTYqKiBzaG93cyB0aGF0IHRoZXJlIGFyZSBubyBvdXRsaWVycyBpbiBgRGlmZl9Jbl9IYXBwaW5lc3NgIGFmdGVyIGNhcHBpbmcuCgpgYGB7cn0KI1RvIHZpc3VhbGl6ZSBvdXRsaWVycwpCb3hwbG90KGhhcHBpbmVzc19jb21wYXJpc2lvbiRIYXBwaW5lc3NfU2NvcmVfMjAxNikKYGBgCjxjZW50ZXI+PGg0PkZpZ3VyZSAtIDE8L2g0PjwvY2VudGVyPgpgYGB7cn0KQm94cGxvdChoYXBwaW5lc3NfY29tcGFyaXNpb24kSGFwcGluZXNzX1Njb3JlXzIwMTcpCmBgYAo8Y2VudGVyPjxoND5GaWd1cmUgLSAyPC9oND48L2NlbnRlcj4KYGBge3J9CkJveHBsb3QoaGFwcGluZXNzX2NvbXBhcmlzaW9uJEdEUF9QZXJfQ2FwaXRhXzIwMTYpCmBgYAo8Y2VudGVyPjxoND5GaWd1cmUgLSAzPC9oND48L2NlbnRlcj4KYGBge3J9CkJveHBsb3QoaGFwcGluZXNzX2NvbXBhcmlzaW9uJEdEUF9QZXJfQ2FwaXRhXzIwMTcpCmBgYAo8Y2VudGVyPjxoND5GaWd1cmUgLSA0PC9oND48L2NlbnRlcj4KYGBge3J9CkJveHBsb3QoaGFwcGluZXNzX2NvbXBhcmlzaW9uJERpZmZfSW5fSGFwcGluZXNzKQpgYGAKPGNlbnRlcj48aDQ+RmlndXJlIC0gNTwvaDQ+PC9jZW50ZXI+CmBgYHtyfQpjYXAgPC0gZnVuY3Rpb24oeCl7CiAgcXVhbnRpbGVzIDwtIHF1YW50aWxlKCB4LCBjKC4wNSwgMC4yNSwgMC43NSwgLjk1ICkgKQogIHhbIHggPCBxdWFudGlsZXNbMl0gLSAxLjUqSVFSKHgpIF0gPC0gcXVhbnRpbGVzWzFdCiAgeFsgeCA+IHF1YW50aWxlc1szXSArIDEuNSpJUVIoeCkgXSA8LSBxdWFudGlsZXNbNF0KICB4Cn0KCmhhcHBpbmVzc19jb21wYXJpc2lvbiREaWZmX0luX0hhcHBpbmVzcyA8LSBoYXBwaW5lc3NfY29tcGFyaXNpb24kRGlmZl9Jbl9IYXBwaW5lc3MgJT4lIGNhcCgpCkJveHBsb3QoaGFwcGluZXNzX2NvbXBhcmlzaW9uJERpZmZfSW5fSGFwcGluZXNzKQpgYGAKPGNlbnRlcj48aDQ+RmlndXJlIC0gNjwvaDQ+PC9jZW50ZXI+CiMjCVRyYW5zZm9ybSAKSW4gb3JkZXIgdG8gZGVjcmVhc2UgdGhlIHNrZXduZXNzIChzaG93biBpbiB0aGUgKipGaWd1cmUtNyoqKSBhbmQgY29udmVydCB0aGUgZGlzdHJpYnV0aW9uIGludG8gYSBub3JtYWwgZGlzdHJpYnV0aW9uIG9mIHRoZSB2YXJpYWJsZSBgSGFwcGluZXNzX1Njb3JlXzIwMTZgLCB3ZSB1c2VkIEJveENveCB0cmFuZm9ybWF0aW9uLiBUaGUgcmVzdWx0YW50IGRpc3RyaWJ1dGlvbiAoc2hvd24gaW4gdGhlICoqRmlndXJlLTgqKikgc2hvd2VkIHJpZ2h0IHNrZXduZXNzIGFuZCBoZW5jZSB3ZSBhcHBsaWVkIHNxdWFyZSByb290IHRyYW5zZm9ybWF0aW9uIG9uIGBib3hjb3hfSGFwcGluZXNzX1Njb3JlXzIwMTZgIHRvIG9idGFpbiBub3JtYWwgZGlzdHJpYnV0aW9uIChzaG93biBpbiB0aGUgKipGaWd1cmUtOSoqKS4gKioqQm94Q294KioqIGFuZCAqKipzcXJ0KioqIGZ1bmN0aW9ucyBhcmUgbWFkZSB1c2UgZm9yIHRoZSBwdXJwb3NlIG9mIHRyYW5zZm9ybWF0aW9uLiAqKipoaXN0KioqIGZ1bmN0aW9uIGlzIHVzZWQgdG8gdmlzdWFsaXplIHRoZSBkaXN0cmlidXRpb24uCgpFdmVuIGZyb20gdGhlICoqKnN1bW1hcnkqKiogZnVuY3Rpb24sIHdlIGNhbiBpbmZlciB0aGF0ICJtZWFuIiBhbmQgIm1lZGlhbiIgdmFsdWVzIGFyZSBhbG1vc3QgZXF1YWwuIERpZmZlcmVuY2UgYmV0d2VlbiB0aGVzZSB2YWx1ZXMgaXMgbGVzcyB0aGFuIDAuNSgwLjAzMSkuIEhlbmNlIHRoZSBkaXN0cmlidXRpb24gaXMgbm9ybWFsLgoKTm93LCB0aGUgdmFyaWFibGUgYFRyYW5mb3JtZWRfSGFwcGluZXNzX1Njb3JlXzIwMTZgIGlzIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLgoKYGBge3J9CiNUbyB2aXN1YWxpemUgZGlzdHJpYnV0aW9uCmhpc3QoaGFwcGluZXNzX2NvbXBhcmlzaW9uJEhhcHBpbmVzc19TY29yZV8yMDE2KQpgYGAKPGNlbnRlcj48aDQ+RmlndXJlIC0gNzwvaDQ+PC9jZW50ZXI+CmBgYHtyfQpoYXBwaW5lc3NfY29tcGFyaXNpb24kYm94Y294X0hhcHBpbmVzc19TY29yZV8yMDE2IDwtIEJveENveChoYXBwaW5lc3NfY29tcGFyaXNpb24kYEhhcHBpbmVzc19TY29yZV8yMDE2YCxsYW1iZGEgPSAiYXV0byIpCmBgYApgYGB7cn0KaGlzdChoYXBwaW5lc3NfY29tcGFyaXNpb24kYm94Y294X0hhcHBpbmVzc19TY29yZV8yMDE2KQpgYGAKPGNlbnRlcj48aDQ+RmlndXJlIC0gODwvaDQ+PC9jZW50ZXI+CmBgYHtyfQpoYXBwaW5lc3NfY29tcGFyaXNpb24kVHJhbmZvcm1lZF9IYXBwaW5lc3NfU2NvcmVfMjAxNiA8LSBzcXJ0KGhhcHBpbmVzc19jb21wYXJpc2lvbiRib3hjb3hfSGFwcGluZXNzX1Njb3JlXzIwMTYpCmhpc3QoaGFwcGluZXNzX2NvbXBhcmlzaW9uJFRyYW5mb3JtZWRfSGFwcGluZXNzX1Njb3JlXzIwMTYpCmBgYAo8Y2VudGVyPjxoND5GaWd1cmUgLSA5PC9oND48L2NlbnRlcj4KYGBge3J9CnN1bW1hcnkoaGFwcGluZXNzX2NvbXBhcmlzaW9uJFRyYW5mb3JtZWRfSGFwcGluZXNzX1Njb3JlXzIwMTYpCmBgYAojIyBSZWZlcmVuY2UKKiBXaWNraGFtLCBIYWRsZXksIGFuZCBHYXJyZXR0IEdyb2xlbXVuZC4gMjAxNi4gUiBmb3IgRGF0YSBTY2llbmNlOiBJbXBvcnQsIFRpZHksIFRyYW5zZm9ybSwgVmlzdWFsaXplLCBhbmQgTW9kZWwgRGF0YS4g4oCcIE/igJlSZWlsbHkgTWVkaWEsIEluYy7igJ0=