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:
- As a part of tidying the dataset, we started from renaming the variables.
- The datatype of few variables such as
Happiness_Rank_2016 and Happiness_Rank_2017 was converted to an ordered factor. The variable Health_Life_Expectancy which represented percentage values was converted from decimal to percentage and then grouped as an ordered factor for better understanding. Thus, encoding categorical values.
- In order to compare the data from 2016 and 2017, we created a new column
Diff_In_Happiness that gave us the absolute difference between the Happiness Score in the course of two years.
- Before deriving the conclusions out of our dataset, taking care of missing Data from the dataset is crucial. The percentage of missing values in our dataset was calculated and was found to be less than 5%. Hence omitting these rows did not make any impact on the analysis.
- Handling outliers is also an important step in data preprocessing. All the numeric variables except
Happiness_Rank_2016 had no outliers. Outliers in Happiness_Rank_2016 were handled by capping them with the nearest quantile value.
- Almost all numerical variables were normally distributed but
Happiness_Rank_2016 showed skewness. We used BoxCox and square root transformation method on the variable and transformed the variable to be normally distributed.
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
- Country : Name of the country.
- Region : Region the country belongs to.
- Happiness Rank : Rank of the country based on the Happiness Score.
- 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”.
- Lower Confidence Interval : Lower Confidence Interval of the Happiness Score.
- Upper Confidence Interval : Upper Confidence Interval of the Happiness Score.
- Economy (GDP per Capita) : The extent to which GDP contributes to the calculation of the Happiness Score.
- Family : The extent to which Family contributes to the calculation of the Happiness Score.
- Health (Life Expectancy) : The extent to which Life expectancy contributed to the calculation of the Happiness Score.
- Freedom : The extent to which Freedom contributed to the calculation of the Happiness Score.
- Trust (Government Corruption) : The extent to which Perception of Corruption contributes to Happiness Score.
- Generosity : The extent to which Generosity contributed to the calculation of the Happiness Score.
- Dystopia Residual : The extent to which Dystopia Residual contributed to the calculation of the Happiness Score.
2017.csv
- Country : Name of the country.
- Happiness.Rank : Rank of the country based on the Happiness Score.
- 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”.
- Whisker.high : Highest reading of Whisker.
- Whisker.low : Lowest reading of Whisker.
- Economy..GDP.per.Capita. : The extent to which GDP contributes to the calculation of the Happiness Score.
- Freedom : The extent to which Freedom contributed to the calculation of the Happiness Score.
- Family : The extent to which Family contributes to the calculation of the Happiness Score.
- Generosity : The extent to which Generosity contributed to the calculation of the Happiness Score.
- Trust..Government.Corruption. : The extent to which Perception of Corruption contributes to Happiness Score.
- 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 = [31mcol_character()[39m,
Happiness.Rank = [32mcol_double()[39m,
Happiness.Score = [32mcol_double()[39m,
Whisker.high = [32mcol_double()[39m,
Whisker.low = [32mcol_double()[39m,
Economy..GDP.per.Capita. = [32mcol_double()[39m,
Family = [32mcol_double()[39m,
Health..Life.Expectancy. = [32mcol_double()[39m,
Freedom = [32mcol_double()[39m,
Generosity = [32mcol_double()[39m,
Trust..Government.Corruption. = [32mcol_double()[39m,
Dystopia.Residual = [32mcol_double()[39m
)
happy2016 <- read_csv("2016.csv")
Parsed with column specification:
cols(
Country = [31mcol_character()[39m,
Region = [31mcol_character()[39m,
`Happiness Rank` = [32mcol_double()[39m,
`Happiness Score` = [32mcol_double()[39m,
`Lower Confidence Interval` = [32mcol_double()[39m,
`Upper Confidence Interval` = [32mcol_double()[39m,
`Economy (GDP per Capita)` = [32mcol_double()[39m,
Family = [32mcol_double()[39m,
`Health (Life Expectancy)` = [32mcol_double()[39m,
Freedom = [32mcol_double()[39m,
`Trust (Government Corruption)` = [32mcol_double()[39m,
Generosity = [32mcol_double()[39m,
`Dystopia Residual` = [32mcol_double()[39m
)
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:
- Each variable must have its own column.
- Each observation must have its own row.
- Each value must have its own cell.
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
Reference
- Wickham, Hadley, and Garrett Grolemund. 2016. R for Data Science: Import, Tidy, Transform, Visualize, and Model Data. “ O’Reilly Media, Inc.”
LS0tCnRpdGxlOiAiTUFUSDIzNDkgU2VtZXN0ZXIgMiwgMjAxOSIKYXV0aG9yOiAiU3VtdWtoYSBWZW5rYXRlc2hhIE11cnRoeSAoczM3OTc4NjYpIDxici8+QW5pbGt1bWFyIExpbmdhcmFqIEJpcmFkYXIgKHMzNzk4MDI0KSA8YnIvPiBBbW9naGEgQW1hcmVzaCAoczM3ODkxNjApIgpzdWJ0aXRsZTogQXNzaWdubWVudCAzCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0Ci0tLQoKIyMgUmVxdWlyZWQgcGFja2FnZXMgCkJlbG93IHBhY2thZ2VzIGFyZSBpbnN0YWxsZWQgYW5kIGxvYWRlZCBhcyB0aGVzZSBwYWNrYWdlcyBjb250YWluIG1hbnkgb2YgdGhlIGZ1bmN0aW9ucyB0aGF0IHdpbGwgYmUgdXNlZCBpbiB0aGlzIGFzc2lnbm1lbnQuCmBgYHtyfQojVG8gbG9hZCB0aGUgbmVjZXNzYXJ5IHBhY2thZ2VzCmxpYnJhcnkocmVhZHIpCmxpYnJhcnkobWFncml0dHIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoY2FyKQpsaWJyYXJ5KGZvcmVjYXN0KQpgYGAKCiMjIEV4ZWN1dGl2ZSBTdW1tYXJ5IAoqRGF0YSBwcmVwcm9jZXNzaW5nKiBpbnZvbHZlcyBzdGVwcyB1bmRlcnRha2VuIGluIHRyYW5zZm9ybWluZyByYXcgZGF0YSBpbnRvIGFuIHVuZGVyc3RhbmRhYmxlIGZvcm1hdC4gVGhlIGNob3NlbiBkYXRhc2V0cyBkZXBpY3QgdGhlIGhhcHBpbmVzcyBzY29yZSBhbG9uZyB3aXRoIGZldyBvdGhlciBwYXJhbWV0ZXJzIHN1Y2ggYXMgSGFwcGluZXNzIFJhbmssIEhlYWx0aCBMaWZlIEV4cGVjdGFuY3kgUmF0ZSBhbmQgR0RQIFBlciBDYXBpdGEgaW5jb21lIG9mIGNvdW50cmllcyBhcm91bmQgdGhlIHdvcmxkIGZvciB0aGUgeWVhcnMgMjAxNiBhbmQgMjAxNy4gT3VyIGdvYWwgaXMgdG8gY29tcGFyZSB0aGUgcHJvc3Blcml0eSBpbiB0aGVzZSBuYXRpb25zIGZyb20gMjAxNiB0byAyMDE3LgoKSW4gdGhlIHByb2Nlc3Mgb2YgYWNoaWV2aW5nIHRoZSBhYm92ZSwgd2Ugam9pbmVkIHRoZSB0d28gZGF0YXNldHMgYnkgY291bnRyeS4gVG8gb2J0YWluIHRoZSB0cmFpbmluZyBkYXRhc2V0LCB0aGUgam9pbmVkIGRhdGFzZXQgY29udGFpbmVkIGNvbHVtbnMgdGhhdCBoYWQgb2JzZXJ2YXRpb25zIHdoaWNoIHdlcmUgb3V0IG9mIG91ciBpbnRlcmVzdHMuIEhlbmNlLCB3ZSBzZWxlY3RlZCB2YXJpYWJsZXMgLSBgQ291bnRyeWAsIGBIYXBwaW5lc3NfUmFua18yMDE3YCwgYEhhcHBpbmVzc19TY29yZV8yMDE3YCwgYEhhcHBpbmVzc19SYW5rXzIwMTZgLCBgSGFwcGluZXNzX1Njb3JlXzIwMTZgLCBgR0RQX1Blcl9DYXBpdGFfMjAxN2AsIGBHRFBfUGVyX0NhcGl0YV8yMDE2YCwgYEhlYWx0aF9MaWZlX0V4cGVjdGFuY3lgLiBGdXJ0aGVyIHN0ZXBzIHRha2VuIGFyZSBhcyBiZWxvdzoKICAKICAqIEFzIGEgcGFydCBvZiB0aWR5aW5nIHRoZSBkYXRhc2V0LCB3ZSBzdGFydGVkIGZyb20gcmVuYW1pbmcgdGhlIHZhcmlhYmxlcy4gIAogICogVGhlIGRhdGF0eXBlIG9mIGZldyB2YXJpYWJsZXMgc3VjaCBhcyBgSGFwcGluZXNzX1JhbmtfMjAxNmAgYW5kIGBIYXBwaW5lc3NfUmFua18yMDE3YCB3YXMgY29udmVydGVkIHRvIGFuIG9yZGVyZWQgZmFjdG9yLiBUaGUgdmFyaWFibGUgYEhlYWx0aF9MaWZlX0V4cGVjdGFuY3lgIHdoaWNoIHJlcHJlc2VudGVkIHBlcmNlbnRhZ2UgdmFsdWVzIHdhcyBjb252ZXJ0ZWQgZnJvbSBkZWNpbWFsIHRvIHBlcmNlbnRhZ2UgYW5kIHRoZW4gZ3JvdXBlZCBhcyBhbiBvcmRlcmVkIGZhY3RvciBmb3IgYmV0dGVyIHVuZGVyc3RhbmRpbmcuIFRodXMsIGVuY29kaW5nIGNhdGVnb3JpY2FsIHZhbHVlcy4gIAogICogSW4gb3JkZXIgdG8gY29tcGFyZSB0aGUgZGF0YSBmcm9tIDIwMTYgYW5kIDIwMTcsIHdlIGNyZWF0ZWQgYSBuZXcgY29sdW1uIGBEaWZmX0luX0hhcHBpbmVzc2AgdGhhdCBnYXZlIHVzIHRoZSBhYnNvbHV0ZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIEhhcHBpbmVzcyBTY29yZSBpbiB0aGUgY291cnNlIG9mIHR3byB5ZWFycy4gIAogICogQmVmb3JlIGRlcml2aW5nIHRoZSBjb25jbHVzaW9ucyBvdXQgb2Ygb3VyIGRhdGFzZXQsIHRha2luZyBjYXJlIG9mIG1pc3NpbmcgRGF0YSBmcm9tIHRoZSBkYXRhc2V0IGlzIGNydWNpYWwuIFRoZSBwZXJjZW50YWdlIG9mIG1pc3NpbmcgdmFsdWVzIGluIG91ciBkYXRhc2V0IHdhcyBjYWxjdWxhdGVkIGFuZCB3YXMgZm91bmQgdG8gYmUgbGVzcyB0aGFuIDUlLiBIZW5jZSBvbWl0dGluZyB0aGVzZSByb3dzIGRpZCBub3QgbWFrZSBhbnkgaW1wYWN0IG9uIHRoZSBhbmFseXNpcy4gIAogICogSGFuZGxpbmcgb3V0bGllcnMgaXMgYWxzbyBhbiBpbXBvcnRhbnQgc3RlcCBpbiBkYXRhIHByZXByb2Nlc3NpbmcuIEFsbCB0aGUgbnVtZXJpYyB2YXJpYWJsZXMgZXhjZXB0IGBIYXBwaW5lc3NfUmFua18yMDE2YCBoYWQgbm8gb3V0bGllcnMuIE91dGxpZXJzIGluIGBIYXBwaW5lc3NfUmFua18yMDE2YCB3ZXJlIGhhbmRsZWQgYnkgY2FwcGluZyB0aGVtIHdpdGggdGhlIG5lYXJlc3QgcXVhbnRpbGUgdmFsdWUuICAKICAqIEFsbW9zdCBhbGwgbnVtZXJpY2FsIHZhcmlhYmxlcyB3ZXJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIGJ1dCBgSGFwcGluZXNzX1JhbmtfMjAxNmAgc2hvd2VkIHNrZXduZXNzLiBXZSB1c2VkIEJveENveCBhbmQgc3F1YXJlIHJvb3QgdHJhbnNmb3JtYXRpb24gbWV0aG9kIG9uIHRoZSB2YXJpYWJsZSBhbmQgdHJhbnNmb3JtZWQgdGhlIHZhcmlhYmxlIHRvIGJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLgoKIyMgRGF0YSAKVGhlIFdvcmxkIEhhcHBpbmVzcyBSZXBvcnQgaXMgYSBsYW5kbWFyayBzdXJ2ZXkgb2YgdGhlIHN0YXRlIG9mIGdsb2JhbCBoYXBwaW5lc3MuIEJvdGggdGhlIGRhdGFzZXRzIHdlcmUgZG93bmxvYWRlZCBmcm9tIGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vdW5zZHNuL3dvcmxkLWhhcHBpbmVzcy4gVGhlIGRhdGFzZXRzIHJldmlldyB0aGUgc3RhdGUgb2YgaGFwcGluZXNzIGluIHRoZSB3b3JsZCBmb3IgdGhlIDIwMTYgYW5kIDIwMTcuCgo8dT4qKjIwMTYuY3N2KiogIDwvdT4gIAogIAogIDEuICoqQ291bnRyeSoqIDogTmFtZSBvZiB0aGUgY291bnRyeS4gIAoyLiAqKlJlZ2lvbioqIDogUmVnaW9uIHRoZSBjb3VudHJ5IGJlbG9uZ3MgdG8uICAKMy4gKipIYXBwaW5lc3MgUmFuayoqIDogUmFuayBvZiB0aGUgY291bnRyeSBiYXNlZCBvbiB0aGUgSGFwcGluZXNzIFNjb3JlLiAgCjQuICoqSGFwcGluZXNzIFNjb3JlKiogOiBBIG1ldHJpYyBtZWFzdXJlZCBpbiAyMDE2IGJ5IGFza2luZyB0aGUgc2FtcGxlZCBwZW9wbGUgdGhlIHF1ZXN0aW9uOiAiSG93IHdvdWxkIHlvdSByYXRlIHlvdXIgaGFwcGluZXNzIG9uIGEgc2NhbGUgb2YgMCB0byAxMCB3aGVyZSAxMCBpcyB0aGUgaGFwcGllc3QiLiAgCjUuICoqTG93ZXIgQ29uZmlkZW5jZSBJbnRlcnZhbCoqIDogTG93ZXIgQ29uZmlkZW5jZSBJbnRlcnZhbCBvZiB0aGUgSGFwcGluZXNzIFNjb3JlLiAgCjYuICoqVXBwZXIgQ29uZmlkZW5jZSBJbnRlcnZhbCoqIDogVXBwZXIgQ29uZmlkZW5jZSBJbnRlcnZhbCBvZiB0aGUgSGFwcGluZXNzIFNjb3JlLiAgCjcuICoqRWNvbm9teSAoR0RQIHBlciBDYXBpdGEpKiogOiBUaGUgZXh0ZW50IHRvIHdoaWNoIEdEUCBjb250cmlidXRlcyB0byB0aGUgY2FsY3VsYXRpb24gb2YgdGhlIEhhcHBpbmVzcyBTY29yZS4gIAo4LiAqKkZhbWlseSoqIDogVGhlIGV4dGVudCB0byB3aGljaCBGYW1pbHkgY29udHJpYnV0ZXMgdG8gdGhlIGNhbGN1bGF0aW9uIG9mIHRoZSBIYXBwaW5lc3MgU2NvcmUuICAKOS4gKipIZWFsdGggKExpZmUgRXhwZWN0YW5jeSkqKiA6IFRoZSBleHRlbnQgdG8gd2hpY2ggTGlmZSBleHBlY3RhbmN5IGNvbnRyaWJ1dGVkIHRvIHRoZSBjYWxjdWxhdGlvbiBvZiB0aGUgSGFwcGluZXNzIFNjb3JlLiAgCjEwLiAqKkZyZWVkb20qKiA6IFRoZSBleHRlbnQgdG8gd2hpY2ggRnJlZWRvbSBjb250cmlidXRlZCB0byB0aGUgY2FsY3VsYXRpb24gb2YgdGhlIEhhcHBpbmVzcyBTY29yZS4gIAoxMS4gKipUcnVzdCAoR292ZXJubWVudCBDb3JydXB0aW9uKSoqIDogVGhlIGV4dGVudCB0byB3aGljaCBQZXJjZXB0aW9uIG9mIENvcnJ1cHRpb24gY29udHJpYnV0ZXMgdG8gSGFwcGluZXNzIFNjb3JlLiAgCjEyLiAqKkdlbmVyb3NpdHkqKiA6IFRoZSBleHRlbnQgdG8gd2hpY2ggR2VuZXJvc2l0eSBjb250cmlidXRlZCB0byB0aGUgY2FsY3VsYXRpb24gb2YgdGhlIEhhcHBpbmVzcyBTY29yZS4gIAoxMy4gKipEeXN0b3BpYSBSZXNpZHVhbCoqIDogVGhlIGV4dGVudCB0byB3aGljaCBEeXN0b3BpYSBSZXNpZHVhbCBjb250cmlidXRlZCB0byB0aGUgY2FsY3VsYXRpb24gb2YgdGhlIEhhcHBpbmVzcyBTY29yZS4gIAoKPHU+KioyMDE3LmNzdioqIDwvdT4gIAogIAogIDEuICoqQ291bnRyeSoqIDogTmFtZSBvZiB0aGUgY291bnRyeS4gIAoyLiAqKkhhcHBpbmVzcy5SYW5rKiogOiBSYW5rIG9mIHRoZSBjb3VudHJ5IGJhc2VkIG9uIHRoZSBIYXBwaW5lc3MgU2NvcmUuICAKMy4gKipIYXBwaW5lc3MuU2NvcmUqKiA6IEEgbWV0cmljIG1lYXN1cmVkIGluIDIwMTYgYnkgYXNraW5nIHRoZSBzYW1wbGVkIHBlb3BsZSB0aGUgcXVlc3Rpb246ICJIb3cgd291bGQgeW91IHJhdGUgeW91ciBoYXBwaW5lc3Mgb24gYSBzY2FsZSBvZiAwIHRvIDEwIHdoZXJlIDEwIGlzIHRoZSBoYXBwaWVzdCIuICAKNC4gKipXaGlza2VyLmhpZ2gqKiA6IEhpZ2hlc3QgcmVhZGluZyBvZiBXaGlza2VyLiAgCjUuICoqV2hpc2tlci5sb3cqKiA6IExvd2VzdCByZWFkaW5nIG9mIFdoaXNrZXIuICAKNi4gKipFY29ub215Li5HRFAucGVyLkNhcGl0YS4qKiA6IFRoZSBleHRlbnQgdG8gd2hpY2ggR0RQIGNvbnRyaWJ1dGVzIHRvIHRoZSBjYWxjdWxhdGlvbiBvZiB0aGUgSGFwcGluZXNzIFNjb3JlLiAgCjcuICoqRnJlZWRvbSoqIDogVGhlIGV4dGVudCB0byB3aGljaCBGcmVlZG9tIGNvbnRyaWJ1dGVkIHRvIHRoZSBjYWxjdWxhdGlvbiBvZiB0aGUgSGFwcGluZXNzIFNjb3JlLiAgCjguICoqRmFtaWx5KiogOiBUaGUgZXh0ZW50IHRvIHdoaWNoIEZhbWlseSBjb250cmlidXRlcyB0byB0aGUgY2FsY3VsYXRpb24gb2YgdGhlIEhhcHBpbmVzcyBTY29yZS4gIAo5LiAqKkdlbmVyb3NpdHkqKiA6IFRoZSBleHRlbnQgdG8gd2hpY2ggR2VuZXJvc2l0eSBjb250cmlidXRlZCB0byB0aGUgY2FsY3VsYXRpb24gb2YgdGhlIEhhcHBpbmVzcyBTY29yZS4gIAoxMC4gKipUcnVzdC4uR292ZXJubWVudC5Db3JydXB0aW9uLioqIDogVGhlIGV4dGVudCB0byB3aGljaCBQZXJjZXB0aW9uIG9mIENvcnJ1cHRpb24gY29udHJpYnV0ZXMgdG8gSGFwcGluZXNzIFNjb3JlLiAgCjExLiAqKkR5c3RvcGlhLlJlc2lkdWFsKiogOiBUaGUgZXh0ZW50IHRvIHdoaWNoIER5c3RvcGlhIFJlc2lkdWFsIGNvbnRyaWJ1dGVkIHRvIHRoZSBjYWxjdWxhdGlvbiBvZiB0aGUgSGFwcGluZXNzIFNjb3JlLiAgCgpXZSB1c2VkICoqKnNlbGVjdCoqKiBmdW5jdGlvbiB0byBmZXRjaCB0aGUgdmFyaWFibGVzIG9mIG91ciBpbnRlcmVzdC4gV2UgaW5jbHVkZWQgYENvdW50cnlgLCBgSGFwcGluZXNzLlJhbmtgLCBgSGFwcGluZXNzLlNjb3JlYCwgYEhhcHBpbmVzcyBSYW5rYCwgYEhhcHBpbmVzcyBTY29yZWAsIGBFY29ub215Li5HRFAucGVyLkNhcGl0YS5gICxgRWNvbm9teSAoR0RQIHBlciBDYXBpdGEpYCwgYEhlYWx0aC4uTGlmZS5FeHBlY3RhbmN5YC4KCmBgYHtyfQojVG8gcmVhZCB0aGUgLmNzdiBmaWxlCmhhcHB5MjAxNyA8LSByZWFkX2NzdigiMjAxNy5jc3YiKQpoYXBweTIwMTYgPC0gcmVhZF9jc3YoIjIwMTYuY3N2IikKY291bnRyeV9jb21iaW5lZDIwMTdfMTYgPC0gbGVmdF9qb2luKGhhcHB5MjAxNyxoYXBweTIwMTYsIGJ5ID0gIkNvdW50cnkiKQpoYXBwaW5lc3NfY29tcGFyaXNpb24gPC1jb3VudHJ5X2NvbWJpbmVkMjAxN18xNiAlPiUgc2VsZWN0KENvdW50cnksIEhhcHBpbmVzcy5SYW5rLEhhcHBpbmVzcy5TY29yZSxgSGFwcGluZXNzIFJhbmtgLGBIYXBwaW5lc3MgU2NvcmVgLEVjb25vbXkuLkdEUC5wZXIuQ2FwaXRhLixgRWNvbm9teSAoR0RQIHBlciBDYXBpdGEpYCxIZWFsdGguLkxpZmUuRXhwZWN0YW5jeS4pCnByaW50KGhhcHBpbmVzc19jb21wYXJpc2lvbikKYGBgCgojIyBVbmRlcnN0YW5kCldlIHJlbmFtZWQgdGhlIG5hbWVzIG9mIHRoZSB2YXJhaWJsZXMgdG8gaW5jcmVhc2UgdGhlIHJlYWRhYmlsaXR5IHVzaW5nICoqKmNvbG5hbWVzKioqIGZ1bmN0aW9uLiBUaGUgKioqc3RyKioqIGZ1bmN0aW9uIGdpdmVzIHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIGRhdGEgZnJhbWUgYW5kIGluZm9ybWF0aW9uIGFib3V0IHRoZSB0eXBlIG9mIHRoZSB2YXJpYWJsZXMuCgpGdXJ0aGVybW9yZSwgd2UgcGVyZm9ybWVkIHR5cGUgY29udmVyc2lvbiBvZiBgSGVhbHRoX0xpZmVfRXhwZWN0YW5jeWAsIGBIYXBwaW5lc3NfUmFua18yMDE3YCwgYW5kIGBIYXBwaW5lc3NfUmFua18yMDE2YCBmcm9tIG51bWVyaWMgdG8gb3JkZXJlZCBmYWN0b3IuIFRoZSAqKipmYWN0b3IqKiogZnVuY3Rpb24gaXMgdXNlZCB3aXRoIG9yZGVyZWQgPSAiVFJVRSIuCgpSZXN0IG9mIHRoZSBvdGhlciB2YXJpYWJsZXMgYXJlIG9mIG51bWVyaWMgdHlwZS4KYGBge3J9CiNUbyBjaGFuZ2UgdGhlIG5hbWUgb2YgdmFyaWFibGVzCmNvbG5hbWVzKGhhcHBpbmVzc19jb21wYXJpc2lvbilbMl0gPC0gIkhhcHBpbmVzc19SYW5rXzIwMTciCmNvbG5hbWVzKGhhcHBpbmVzc19jb21wYXJpc2lvbilbM10gPC0gIkhhcHBpbmVzc19TY29yZV8yMDE3Igpjb2xuYW1lcyhoYXBwaW5lc3NfY29tcGFyaXNpb24pWzRdIDwtICJIYXBwaW5lc3NfUmFua18yMDE2Igpjb2xuYW1lcyhoYXBwaW5lc3NfY29tcGFyaXNpb24pWzVdIDwtICJIYXBwaW5lc3NfU2NvcmVfMjAxNiIKY29sbmFtZXMoaGFwcGluZXNzX2NvbXBhcmlzaW9uKVs2XSA8LSAiR0RQX1Blcl9DYXBpdGFfMjAxNyIKY29sbmFtZXMoaGFwcGluZXNzX2NvbXBhcmlzaW9uKVs3XSA8LSAiR0RQX1Blcl9DYXBpdGFfMjAxNiIKY29sbmFtZXMoaGFwcGluZXNzX2NvbXBhcmlzaW9uKVs4XSA8LSAiSGVhbHRoX0xpZmVfRXhwZWN0YW5jeSIKCnN0cihoYXBwaW5lc3NfY29tcGFyaXNpb24pCgpoYXBwaW5lc3NfY29tcGFyaXNpb24kSGVhbHRoX0xpZmVfRXhwZWN0YW5jeSA8LSBoYXBwaW5lc3NfY29tcGFyaXNpb24kSGVhbHRoX0xpZmVfRXhwZWN0YW5jeSoxMDAKYnJlYWtzIDwtIGMoMCwyMCw0MCw2MCw4MCwxMDApCmhhcHBpbmVzc19jb21wYXJpc2lvbiRIZWFsdGhfTGlmZV9FeHBlY3RhbmN5IDwtIGhhcHBpbmVzc19jb21wYXJpc2lvbiRIZWFsdGhfTGlmZV9FeHBlY3RhbmN5ICU+JSBjdXQoYnJlYWtzID0gYnJlYWtzLCBpbmNsdWRlLmxvd2VzdCA9IFRSVUUpCmxldmVscyhoYXBwaW5lc3NfY29tcGFyaXNpb24kSGVhbHRoX0xpZmVfRXhwZWN0YW5jeSkKaGFwcGluZXNzX2NvbXBhcmlzaW9uJEhlYWx0aF9MaWZlX0V4cGVjdGFuY3kgPC0gaGFwcGluZXNzX2NvbXBhcmlzaW9uJEhlYWx0aF9MaWZlX0V4cGVjdGFuY3kgJT4lIGZhY3RvcihsZXZlbHMgPSBjKCJbMCwyMF0iLCAiKDIwLDQwXSIgLCAiKDQwLDYwXSIgLCAiKDYwLDgwXSIgLCAiKDgwLDEwMF0iKSwgbGFiZWxzID0gYygiPD0yMCIsIjIxLTQwIiwiNDEtNjAiLCI2MS04MCIsIj44MCIpLCBvcmRlcmVkID0gVFJVRSkKbGV2ZWxzKGhhcHBpbmVzc19jb21wYXJpc2lvbiRIZWFsdGhfTGlmZV9FeHBlY3RhbmN5KQpjbGFzcyhoYXBwaW5lc3NfY29tcGFyaXNpb24kSGVhbHRoX0xpZmVfRXhwZWN0YW5jeSkKCmhhcHBpbmVzc19jb21wYXJpc2lvbiRIYXBwaW5lc3NfUmFua18yMDE3IDwtIGhhcHBpbmVzc19jb21wYXJpc2lvbiRIYXBwaW5lc3NfUmFua18yMDE3ICU+JSBmYWN0b3Iob3JkZXJlZCA9IFRSVUUpCmxldmVscyhoYXBwaW5lc3NfY29tcGFyaXNpb24kSGFwcGluZXNzX1JhbmtfMjAxNykKY2xhc3MoaGFwcGluZXNzX2NvbXBhcmlzaW9uJEhhcHBpbmVzc19SYW5rXzIwMTcpCgpoYXBwaW5lc3NfY29tcGFyaXNpb24kSGFwcGluZXNzX1JhbmtfMjAxNiA8LSBoYXBwaW5lc3NfY29tcGFyaXNpb24kSGFwcGluZXNzX1JhbmtfMjAxNiAlPiUgZmFjdG9yKG9yZGVyZWQgPSBUUlVFKQpsZXZlbHMoaGFwcGluZXNzX2NvbXBhcmlzaW9uJEhhcHBpbmVzc19SYW5rXzIwMTYpCmNsYXNzKGhhcHBpbmVzc19jb21wYXJpc2lvbiRIYXBwaW5lc3NfUmFua18yMDE2KQoKY2xhc3MoaGFwcGluZXNzX2NvbXBhcmlzaW9uJENvdW50cnkpCmNsYXNzKGhhcHBpbmVzc19jb21wYXJpc2lvbiRIYXBwaW5lc3NfU2NvcmVfMjAxNykKY2xhc3MoaGFwcGluZXNzX2NvbXBhcmlzaW9uJEhhcHBpbmVzc19TY29yZV8yMDE2KQpjbGFzcyhoYXBwaW5lc3NfY29tcGFyaXNpb24kR0RQX1Blcl9DYXBpdGFfMjAxNykKY2xhc3MoaGFwcGluZXNzX2NvbXBhcmlzaW9uJEdEUF9QZXJfQ2FwaXRhXzIwMTYpCmBgYAoKIyMJVGlkeSAmIE1hbmlwdWxhdGUgRGF0YSBJCkFjY29yZGluZyB0byB0aGUgdGhyZWUgaW50ZXJyZWxhdGVkIHJ1bGVzIHdoaWNoIG1ha2UgYSBkYXRhc2V0IHRpZHkgKEhhZGxleSBXaWNraGFtIGFuZCBHcm9sZW11bmQgKDIwMTYpKS4gSW4gdGlkeSBkYXRhOiAgCiAgCiAgKiBFYWNoIHZhcmlhYmxlIG11c3QgaGF2ZSBpdHMgb3duIGNvbHVtbi4gIAogICogRWFjaCBvYnNlcnZhdGlvbiBtdXN0IGhhdmUgaXRzIG93biByb3cuICAKICAqIEVhY2ggdmFsdWUgbXVzdCBoYXZlIGl0cyBvd24gY2VsbC4gIAogIApPdXIgZGF0YXNldCBvYmV5cyBhbGwgdGhlIGFib3ZlIG1lbnRpb25lZCBwcmluY2lwbGVzLiBTYW1wbGUgb2YgZmlyc3QgMTAgcm93cyBpcyBkaXNwbGF5ZWQgdXNpbmcgdGhlIHByaW50KCkgZnVuY3Rpb24gdG8gc2hvdyB0aGUgZGF0YXNldCBpcyB0aWR5LgoKYGBge3J9CnByaW50KGhhcHBpbmVzc19jb21wYXJpc2lvblsgLCAoMTo0KV0pCnByaW50KGhhcHBpbmVzc19jb21wYXJpc2lvblsgLCAtKDE6NCldKQpkaW0oaGFwcGluZXNzX2NvbXBhcmlzaW9uKQpgYGAKCiMjCVRpZHkgJiBNYW5pcHVsYXRlIERhdGEgSUkgCldlIGhhdmUgY3JlYXRlZCBhIG5ldyB2YXJpYWJsZSBgRGlmZl9Jbl9IYXBwaW5lc3NgIHdoaWNoIGlzIHRoZSBhYnNvbHV0ZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIGhhcHBpbmVzcyBzY29yZXMgb2YgMjAxNyBhbmQgMjAxNiBieSB1c2luZyAqKiptdXRhdGUqKiogZnVuY3Rpb24uCgpgYGB7cn0KI1RvIGNyZWF0ZSBhIG5ldyB2YXJpYWJsZQpoYXBwaW5lc3NfY29tcGFyaXNpb24gPC0gaGFwcGluZXNzX2NvbXBhcmlzaW9uICU+JSBtdXRhdGUoRGlmZl9Jbl9IYXBwaW5lc3MgPSBhYnMoSGFwcGluZXNzX1Njb3JlXzIwMTcgLSBIYXBwaW5lc3NfU2NvcmVfMjAxNikpCgpwcmludChoYXBwaW5lc3NfY29tcGFyaXNpb25bICwgYygxLDMsNSw5KV0pCmRpbShoYXBwaW5lc3NfY29tcGFyaXNpb24pCmBgYAoKIyMJU2NhbiBJIApUbyBzY2FuIHRoZSBtaXNzaW5nIHZhbHVlcywgaW5jb25zaXN0ZW5jaWVzIGFuZCBvYnZpb3VzIGVycm9ycywgd2UgbWFkZSB1c2Ugb2YgKioqaXMubmEqKiosICoqKmlzLmluZmluaXRlKioqLCAqKippcy5uYW4qKiogZnVuY3Rpb25zLiBXZSBvYnNlcnZlZCB0aGF0IHRoZXJlIGFyZSAyMCBtaXNzaW5nIHZhbHVlcyBhbmQgbm8gc3BlY2lhbCB2YWx1ZXMuIAoKVGhlIG1pc3NpbmcgdmFsdWUgcGVyY2VudGFnZSB3YXMgZm91bmQgb3V0IHRvIGJlIDEuNDMzNjkyJSAoMjAgb3V0IG9mIDEzOTUgdmFsdWVzKS4gU2luY2UgdGhlIHBlcmNlbnRhZ2Ugb2YgbWlzc2luZyB2YWx1ZXMgaXMgbGVzcyB0aGFuIDUlLCB3ZSBkZWNpZGVkIHRvIG9taXQgdGhlc2UgbWlzc2luZyB2YWx1ZXMgdXNpbmcgKioqbmEub21pdCoqKiB0byBwcm9jZWVkIGZ1cnRoZXIuIEluIGZhY3QsIHRoZSBvbWl0dGVkIDUgcm93cyB3ZXJlIHRoZSBjb3VudHJpZXMgdGhhdCB3ZXJlIHByZXNlbnQgaW4gdGhlIDIwMTcgZGF0YXNldCBidXQgbm90IGluIDIwMTYuCgpgYGB7cn0KI1RvIGZpbmQgc3VtIG9mIG1pc3NpbmcgdmFsdWVzCnN1bShpcy5uYShoYXBwaW5lc3NfY29tcGFyaXNpb24pKQojVG8gZmluZCBzdW0gb2YgaW5maW5pdGUgdmFsdWVzCnN1bShzYXBwbHkoaGFwcGluZXNzX2NvbXBhcmlzaW9uLCBpcy5pbmZpbml0ZSkpCiNUbyBmaW5kIHN1bSBvZiBub3QgYSBudW1iZXIoTkFOKSB2YWx1ZXMKc3VtKHNhcHBseShoYXBwaW5lc3NfY29tcGFyaXNpb24sIGlzLm5hbikpCgpUb3RhbF92YWx1ZSA8LSBucm93KGhhcHBpbmVzc19jb21wYXJpc2lvbikgKiBuY29sKGhhcHBpbmVzc19jb21wYXJpc2lvbikKTkFfUGVyY2VudGFnZSA8LSBzdW0oaXMubmEoaGFwcGluZXNzX2NvbXBhcmlzaW9uKSkgKiAxMDAgLyBUb3RhbF92YWx1ZQpOQV9QZXJjZW50YWdlCgpoYXBwaW5lc3NfY29tcGFyaXNpb24gPC0gbmEub21pdChoYXBwaW5lc3NfY29tcGFyaXNpb24pCnN1bShpcy5uYShoYXBwaW5lc3NfY29tcGFyaXNpb24pKQpkaW0oaGFwcGluZXNzX2NvbXBhcmlzaW9uKQpgYGAKCiMjCVNjYW4gSUkKV2UgaGF2ZSB1c2VkICoqKkJveHBsb3QqKiogZnVuY3Rpb24gdG8gY2hlY2sgaWYgdGhlcmUgYXJlIGFueSBvdXRsaWVycyBpbiB0aGUgbnVtZXJpYyB2YXJpYWJsZXMuIEZyb20gKipGaWd1cmUtNSoqLCBXZSBjYW4gc2VlIHRoYXQgYERpZmZfSW5fSGFwcGluZXNzYCB2YXJpYWJsZSBoYXMgb3V0bGllcnMuIFdlIHN1Y2Nlc3NmdWxseSBoYW5kbGVkIHRoZXNlIG91dGxpZXJzIGJ5IGNhcHBpbmcgdGhlbSB3aXRoIG5lYXJlc3QgcXVhbnRpbGUgdmFsdWUuICoqRmlndXJlLTYqKiBzaG93cyB0aGF0IHRoZXJlIGFyZSBubyBvdXRsaWVycyBpbiBgRGlmZl9Jbl9IYXBwaW5lc3NgIGFmdGVyIGNhcHBpbmcuCgpgYGB7cn0KI1RvIHZpc3VhbGl6ZSBvdXRsaWVycwpCb3hwbG90KGhhcHBpbmVzc19jb21wYXJpc2lvbiRIYXBwaW5lc3NfU2NvcmVfMjAxNikKYGBgCjxjZW50ZXI+PGg0PkZpZ3VyZSAtIDE8L2g0PjwvY2VudGVyPgpgYGB7cn0KQm94cGxvdChoYXBwaW5lc3NfY29tcGFyaXNpb24kSGFwcGluZXNzX1Njb3JlXzIwMTcpCmBgYAo8Y2VudGVyPjxoND5GaWd1cmUgLSAyPC9oND48L2NlbnRlcj4KYGBge3J9CkJveHBsb3QoaGFwcGluZXNzX2NvbXBhcmlzaW9uJEdEUF9QZXJfQ2FwaXRhXzIwMTYpCmBgYAo8Y2VudGVyPjxoND5GaWd1cmUgLSAzPC9oND48L2NlbnRlcj4KYGBge3J9CkJveHBsb3QoaGFwcGluZXNzX2NvbXBhcmlzaW9uJEdEUF9QZXJfQ2FwaXRhXzIwMTcpCmBgYAo8Y2VudGVyPjxoND5GaWd1cmUgLSA0PC9oND48L2NlbnRlcj4KYGBge3J9CkJveHBsb3QoaGFwcGluZXNzX2NvbXBhcmlzaW9uJERpZmZfSW5fSGFwcGluZXNzKQpgYGAKPGNlbnRlcj48aDQ+RmlndXJlIC0gNTwvaDQ+PC9jZW50ZXI+CmBgYHtyfQpjYXAgPC0gZnVuY3Rpb24oeCl7CiAgcXVhbnRpbGVzIDwtIHF1YW50aWxlKCB4LCBjKC4wNSwgMC4yNSwgMC43NSwgLjk1ICkgKQogIHhbIHggPCBxdWFudGlsZXNbMl0gLSAxLjUqSVFSKHgpIF0gPC0gcXVhbnRpbGVzWzFdCiAgeFsgeCA+IHF1YW50aWxlc1szXSArIDEuNSpJUVIoeCkgXSA8LSBxdWFudGlsZXNbNF0KICB4Cn0KCmhhcHBpbmVzc19jb21wYXJpc2lvbiREaWZmX0luX0hhcHBpbmVzcyA8LSBoYXBwaW5lc3NfY29tcGFyaXNpb24kRGlmZl9Jbl9IYXBwaW5lc3MgJT4lIGNhcCgpCkJveHBsb3QoaGFwcGluZXNzX2NvbXBhcmlzaW9uJERpZmZfSW5fSGFwcGluZXNzKQpgYGAKPGNlbnRlcj48aDQ+RmlndXJlIC0gNjwvaDQ+PC9jZW50ZXI+CiMjCVRyYW5zZm9ybSAKSW4gb3JkZXIgdG8gZGVjcmVhc2UgdGhlIHNrZXduZXNzIChzaG93biBpbiB0aGUgKipGaWd1cmUtNyoqKSBhbmQgY29udmVydCB0aGUgZGlzdHJpYnV0aW9uIGludG8gYSBub3JtYWwgZGlzdHJpYnV0aW9uIG9mIHRoZSB2YXJpYWJsZSBgSGFwcGluZXNzX1Njb3JlXzIwMTZgLCB3ZSB1c2VkIEJveENveCB0cmFuZm9ybWF0aW9uLiBUaGUgcmVzdWx0YW50IGRpc3RyaWJ1dGlvbiAoc2hvd24gaW4gdGhlICoqRmlndXJlLTgqKikgc2hvd2VkIHJpZ2h0IHNrZXduZXNzIGFuZCBoZW5jZSB3ZSBhcHBsaWVkIHNxdWFyZSByb290IHRyYW5zZm9ybWF0aW9uIG9uIGBib3hjb3hfSGFwcGluZXNzX1Njb3JlXzIwMTZgIHRvIG9idGFpbiBub3JtYWwgZGlzdHJpYnV0aW9uIChzaG93biBpbiB0aGUgKipGaWd1cmUtOSoqKS4gKioqQm94Q294KioqIGFuZCAqKipzcXJ0KioqIGZ1bmN0aW9ucyBhcmUgbWFkZSB1c2UgZm9yIHRoZSBwdXJwb3NlIG9mIHRyYW5zZm9ybWF0aW9uLiAqKipoaXN0KioqIGZ1bmN0aW9uIGlzIHVzZWQgdG8gdmlzdWFsaXplIHRoZSBkaXN0cmlidXRpb24uCgpFdmVuIGZyb20gdGhlICoqKnN1bW1hcnkqKiogZnVuY3Rpb24sIHdlIGNhbiBpbmZlciB0aGF0ICJtZWFuIiBhbmQgIm1lZGlhbiIgdmFsdWVzIGFyZSBhbG1vc3QgZXF1YWwuIERpZmZlcmVuY2UgYmV0d2VlbiB0aGVzZSB2YWx1ZXMgaXMgbGVzcyB0aGFuIDAuNSgwLjAzMSkuIEhlbmNlIHRoZSBkaXN0cmlidXRpb24gaXMgbm9ybWFsLgoKTm93LCB0aGUgdmFyaWFibGUgYFRyYW5mb3JtZWRfSGFwcGluZXNzX1Njb3JlXzIwMTZgIGlzIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLgoKYGBge3J9CiNUbyB2aXN1YWxpemUgZGlzdHJpYnV0aW9uCmhpc3QoaGFwcGluZXNzX2NvbXBhcmlzaW9uJEhhcHBpbmVzc19TY29yZV8yMDE2KQpgYGAKPGNlbnRlcj48aDQ+RmlndXJlIC0gNzwvaDQ+PC9jZW50ZXI+CmBgYHtyfQpoYXBwaW5lc3NfY29tcGFyaXNpb24kYm94Y294X0hhcHBpbmVzc19TY29yZV8yMDE2IDwtIEJveENveChoYXBwaW5lc3NfY29tcGFyaXNpb24kYEhhcHBpbmVzc19TY29yZV8yMDE2YCxsYW1iZGEgPSAiYXV0byIpCmBgYApgYGB7cn0KaGlzdChoYXBwaW5lc3NfY29tcGFyaXNpb24kYm94Y294X0hhcHBpbmVzc19TY29yZV8yMDE2KQpgYGAKPGNlbnRlcj48aDQ+RmlndXJlIC0gODwvaDQ+PC9jZW50ZXI+CmBgYHtyfQpoYXBwaW5lc3NfY29tcGFyaXNpb24kVHJhbmZvcm1lZF9IYXBwaW5lc3NfU2NvcmVfMjAxNiA8LSBzcXJ0KGhhcHBpbmVzc19jb21wYXJpc2lvbiRib3hjb3hfSGFwcGluZXNzX1Njb3JlXzIwMTYpCmhpc3QoaGFwcGluZXNzX2NvbXBhcmlzaW9uJFRyYW5mb3JtZWRfSGFwcGluZXNzX1Njb3JlXzIwMTYpCmBgYAo8Y2VudGVyPjxoND5GaWd1cmUgLSA5PC9oND48L2NlbnRlcj4KYGBge3J9CnN1bW1hcnkoaGFwcGluZXNzX2NvbXBhcmlzaW9uJFRyYW5mb3JtZWRfSGFwcGluZXNzX1Njb3JlXzIwMTYpCmBgYAojIyBSZWZlcmVuY2UKKiBXaWNraGFtLCBIYWRsZXksIGFuZCBHYXJyZXR0IEdyb2xlbXVuZC4gMjAxNi4gUiBmb3IgRGF0YSBTY2llbmNlOiBJbXBvcnQsIFRpZHksIFRyYW5zZm9ybSwgVmlzdWFsaXplLCBhbmQgTW9kZWwgRGF0YS4g4oCcIE/igJlSZWlsbHkgTWVkaWEsIEluYy7igJ0=