Required packages

Provide the packages required to reproduce the report. Make sure you fulfilled the minimum requirement #10.

library(readr)
library(foreign)
library(gdata)
library(rvest)
library(dplyr)
library(tidyr)
library(deductive)
library(deducorrect)
library(editrules)
library(validate)
library(Hmisc)
library(forecast)
library(outliers)
library(stringr)
library(lubridate)
library(MASS)
library(mlr)
library(ggplot2)

1. Executive Summary

The data set used in this report consists of two, one is the level of consumption of alcohol in each country (including three types of alcohol), and the other is the World Happiness Index (and contains the macro indices of various countries). The purpose of this report is to understand the relationship between national consumption of alcohol and happiness index and macro data. The entire report contains the main 7 parts. The first two parts mainly describes the composition of the two data sets and imports the data into R. The third part is to process the two data sets separately and change the data format, Reach the most clean. The fourth part is to combine the two processed data sets together, then to tidy it to be clean. Also, to use mutate() to add and create one new variable. At the same time, missing values and inconsistent queries are also executed in next section. The sixth part is the scanning of outliers. Use z.scores to find out the outliers, then use the average of the variables to replace the outliers for the purpose of remove outliters without produce missing value. In the last part, we selected the family variables for data conversion.

2. Data

This report contains two data sets: “World Happiness Report” and “Alcohol consumption by country”.

2.1 Read/Import Data

  • For import data set, the function read_csv() was used. Because function read_csv() can import the “.csv”, and readr package are around 10x faster than the base R functions.

  • Then I import 2016.csv with read_csv() to hp, it is the happyness data set.
  • Then I import drinks.csv with read_csv() to al, it is the alcohol consumption data set.

hp <- read_csv("2016.csv")
al <- read_csv("drinks.csv")

2.2 Show the tables of to data sets

  • World Happiness table
head(hp)
  • Alcohol consumption table
head(al)

3. Understand

3.1 Alcohol consumption by country

The Alcohol Consumption Report is about the amount of alcohol consumed in different countries, published in 2016. It contains 193 countries and regions, and the types of alcohol investigated are three, beer, spirit and wine.

The six variables were shown below, and the country and continental variables are character variables, and the other variables are numeric variables. In the subsequent processing, the continent variable is converted into factor variables for convenience, to labelled main areas.

  • Country: Name of the country.

  • Beer_servings: Liters ( per capita ) of beer consumption.

  • Spirit_servings: Liters ( per capita ) of spirit consumption.

  • Wine_servings: Liters ( per capita ) of wine consumption.

  • total_litres_of_pure_alcohol: Total litres of pure alcohol.

  • Continent: The continent where the country is located.

This data set was downloaded from with “.zip”. The detail of the downlord website is shown as below.
  • UPL:

3.2 World Happiness Report

The World Happiness Report is a landmark survey of global happiness. Surveys of happiness-related indices in more than 150 countries. It is published at the United Nations Celebration of International Happiness Day every year, for accurate use in conjunction with the Alcohol Consumption Dataset, the 2016 data set was used. It contains 157 countries and regions.Also, 13 variables were contained (The country and region are character variables, and the other 11 variables are numeric variables. In the subsequent processing, the region variable is converted into factor variables for convenience, to labelled main areas. The happiness rank is a numeric variable in the data set, but in reality it is a factor variable. It will be converted in subsequent operations.), which are:

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

This data set was downloaded from with “.zip”. The detail of the downlord website is shown as below.
  • UPL:

4. Tidy & Manipulate Data I

Before combining the two data sets, in order to facilitate the subsequent data processing, we need to modify the two data accordingly.

4.1 Modify the happiness data set

# Step 1: Modify the region and happiness rank variables from a character
# variable to a factor variable

hp$Region <- factor(hp$Region)
hp$`Happiness Rank` <- factor(hp$`Happiness Rank`)
class(hp$Region)
[1] "factor"
class(hp$`Happiness Rank` )
[1] "factor"
head(hp)
# Step 2: Modify the format of the country name, modify the format and remove
# punctuation, and standardize the country name so that the two data sets can be
# successfully combined.

hp$Country <- hp$Country %>% str_replace_all(pattern = "[:punct:]", replacement = "")

4.2 Modify the alcohol consumption data set

# Step 1: Modify the name of the dataset variable, which is easy to view and use.
colnames(al) <- c("Country", "Beer", "Spirit", "Wine", "Total pure alcohol", "Continent")
head(al)
# Step 2: Modify the Continent variable from a character variable to a factor variable

al$Continent <- factor(al$Continent)
class(al$Continent)
[1] "factor"
head(al)
# Step 3: Modify the format of the country name, modify the format, and remove
# punctuation to ensure that the name format is the same as the country name 
# format in the Happiness data set.

# Change all "&" symbols to "and" 
al$Country <- al$Country %>% str_replace_all(pattern = "&", replacement = "") 

# Remove all punctuation
al$Country <- al$Country %>% str_replace_all(pattern = "[:punct:]", 
                                             replacement = "") 

# Change the only country abbreviation to full name
al$Country <- al$Country %>% str_replace_all(pattern = "USA", 
                                             replacement = "United States") 

5. Tidy & Manipulate Data II

After the previous step, the two data sets have met the requirements before the combination, and then the two data sets need to be combined and tidyed.

5.1 Combination

Here, inner_join() is used for combination, on the grounds that although the two countries surveyed have more than 150 countries, the countries surveyed are still different. So for data integrity, we use inner_join() (keyword is country) to exclude countries and their associated data that are not included in the two data sets at the same time, saving only the countries and their associated data contained in both data sets. Then get the new data set “hpal”.

hpal <- inner_join(hp,al,by="Country")
head(hpal)

5.2 Tidy

5.2.1 Delete duplicate variable

By observing the dataset, we found that the geographical locations contained in the region and continent variables are similar (the information contained in the continent is the six major continents on the planet, and the region is more specific), so in order to avoid data duplication we do not need continental variables to delete continent variables.

hpal <- subset(hpal,,-c(Continent))
head(hpal)

5.2.2

In order to more closely observe the relationship between the three alcohol consumption (beer, spirit and wine) and the happiness score, we create a new variable, which is the total of three alcohol consumption.

hpal <- hpal %>% mutate(`Sum of alcohol` = Beer + Spirit + Wine)
head(hpal)
  • Show the new variable about Country, Happiness Rank, Happiness Score and Sum of alcohol.
hpalsubset<-subset(hpal,,c("Country", "Happiness Rank", "Happiness Score", "Sum of alcohol"))
head(hpalsubset)

6. Scan I

Scan the data for missing values, inconsistencies and obvious errors.

6.1 Mssing values

Use is.na() to judge the entire data set to determine if there are missing values. Then use sum() to show how many missing values are in total.

sum(is.na(hpal))
[1] 0

According to the results, the total number of missing values for the entire data set is zero, so there are no missing values.

6.2 Inconsistencies or Special Values

is.special <- function(x){
if (is.numeric(x)) (is.infinite(x) | is.nan(x))
}
sapply(hpal, is.special)%>% summary()
                              Length Class  Mode   
Country                         0    -none- NULL   
Region                          0    -none- NULL   
Happiness Rank                  0    -none- NULL   
Happiness Score               143    -none- logical
Lower Confidence Interval     143    -none- logical
Upper Confidence Interval     143    -none- logical
Economy (GDP per Capita)      143    -none- logical
Family                        143    -none- logical
Health (Life Expectancy)      143    -none- logical
Freedom                       143    -none- logical
Trust (Government Corruption) 143    -none- logical
Generosity                    143    -none- logical
Dystopia Residual             143    -none- logical
Beer                          143    -none- logical
Spirit                        143    -none- logical
Wine                          143    -none- logical
Total pure alcohol            143    -none- logical
Sum of alcohol                143    -none- logical

The results above show that, there no further inconsistencies or special values in the data set of ‘hpal’ for each variable.

7. Scan II

Scan the numeric data for outliers. And use z.scores to display outliers and which() lengyh() to calculate the number of outliers Because the content contained in the country and region variables is the country name and the region name, there is no need to look for outliers. In same reason, happiness rank is only rank by number, so there is no need to find outliers.

7.1 Find outliers by z.scores

Calculate z scores for each variable (exclude country,region and happiness rank variables) and then look for outliers. If z.scores is greater than 3, it is considered an outlier.

z.scores1 <-  scores(hpal[,4],type = "z")
z.scores2 <-  scores(hpal[,5],type = "z")
z.scores3 <-  scores(hpal[,6],type = "z")
z.scores4 <-  scores(hpal[,7],type = "z")
z.scores5 <-  scores(hpal[,8],type = "z")
z.scores6 <-  scores(hpal[,9],type = "z")
z.scores7 <-  scores(hpal[,10],type = "z")
z.scores8 <-  scores(hpal[,11],type = "z")
z.scores9 <-  scores(hpal[,12],type = "z")
z.scores10 <-  scores(hpal[,13],type = "z")
z.scores11 <-  scores(hpal[,14],type = "z")
z.scores12 <-  scores(hpal[,15],type = "z")
z.scores13 <-  scores(hpal[,16],type = "z")
z.scores14 <-  scores(hpal[,17],type = "z")
z.scores15 <-  scores(hpal[,18],type = "z")

length(which( abs(z.scores1) >3 ))
[1] 0
length(which( abs(z.scores2) >3 ))
[1] 0
length(which( abs(z.scores3) >3 ))
[1] 0
length(which( abs(z.scores4) >3 ))
[1] 0
length(which( abs(z.scores5) >3 ))
[1] 0
length(which( abs(z.scores6) >3 ))
[1] 0
length(which( abs(z.scores7) >3 ))
[1] 0
length(which( abs(z.scores8) >3 ))
[1] 2
length(which( abs(z.scores9) >3 ))
[1] 1
length(which( abs(z.scores10) >3 ))
[1] 0
length(which( abs(z.scores11) >3 ))
[1] 0
length(which( abs(z.scores12) >3 ))
[1] 2
length(which( abs(z.scores13) >3 ))
[1] 2
length(which( abs(z.scores14) >3 ))
[1] 0
length(which( abs(z.scores15) >3 ))
[1] 0

As can be seen from the above calculations, Trust (Government Corruption), Generosity, Spirit and Wine variables has outliers, the number of outliers are 2, 1, 2 and 2 repectively.

7.2 Imputing outlier

We can also impute outliers. We can use mean or median imputation methods to replace outliers. And before Imputing we should check whether the outlier is a result of data entry/processing error. But for this case, the data set have be check at front part.

A<-hpal$`Trust (Government Corruption)`[ 
  which( abs(z.scores8) >3 )]<- mean(hpal$`Trust (Government Corruption)`, 
                                     na.rm = TRUE) 
B<-hpal$Generosity[ which( abs(z.scores9) >3 )] <- mean(hpal$Generosity[
  - which( abs(z.scores9) >3 )], na.rm = TRUE) 
C<-hpal$Spirit[ which( abs(z.scores12) >3 )] <- mean(hpal$Spirit, 
                                                     na.rm = TRUE) 
D<-hpal$Wine[ which( abs(z.scores13) >3 )] <- mean(hpal$Wine, na.rm = TRUE)
length(which( abs(scores(A,type = "z")) >3 ))
[1] 0
length(which( abs(scores(B,type = "z")) >3 ))
[1] 0
length(which( abs(scores(C,type = "z")) >3 ))
[1] 0
length(which( abs(scores(D,type = "z")) >3 ))
[1] 0

After the imputing, we have imputing all the outliers as above shown.

8. Transform

As the main observation object of ours, we have selected the Family variable as the target of data transform. First we use hist() to observe the distribution of the data.

hist(hpal$Family)

It can be seen that the distribution of the Family has a tendency to be left skewness. So we consider use square transformation.

x1<-hpal$Family
x1^2 %>% hist()

According to the figure shown, the conversion was not prefectly successful, so we re-selected the method to transform. We consider BoxCox transform.

BoxCox(x1,lambda = "auto") %>% hist()

As shown in the figure above, the distribution of Family variable is very close to the normal distribution, so we consider the transformation to be successful.



LS0tDQp0aXRsZTogIk1BVEgyMzQ5IFNlbWVzdGVyIDEsIDIwMTkiDQphdXRob3I6ICJCZWluYW4gWHUsIHMzNzc3OTM3Ig0Kc3VidGl0bGU6IEFzc2lnbm1lbnQgMw0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOiBkZWZhdWx0DQotLS0NCg0KDQojIyBSZXF1aXJlZCBwYWNrYWdlcyANCg0KDQpQcm92aWRlIHRoZSBwYWNrYWdlcyByZXF1aXJlZCB0byByZXByb2R1Y2UgdGhlIHJlcG9ydC4gTWFrZSBzdXJlIHlvdSBmdWxmaWxsZWQgdGhlIG1pbmltdW0gcmVxdWlyZW1lbnQgIzEwLg0KDQpgYGB7ciwgZWNobyA9IFRSVUUsIHdhcm5pbmdzID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQpsaWJyYXJ5KHJlYWRyKQ0KbGlicmFyeShmb3JlaWduKQ0KbGlicmFyeShnZGF0YSkNCmxpYnJhcnkocnZlc3QpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkoZGVkdWN0aXZlKQ0KbGlicmFyeShkZWR1Y29ycmVjdCkNCmxpYnJhcnkoZWRpdHJ1bGVzKQ0KbGlicmFyeSh2YWxpZGF0ZSkNCmxpYnJhcnkoSG1pc2MpDQpsaWJyYXJ5KGZvcmVjYXN0KQ0KbGlicmFyeShvdXRsaWVycykNCmxpYnJhcnkoc3RyaW5ncikNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShNQVNTKQ0KbGlicmFyeShtbHIpDQpsaWJyYXJ5KGdncGxvdDIpDQoNCg0KDQpgYGANCg0KDQojIyAxLiBFeGVjdXRpdmUgU3VtbWFyeSANCg0KDQoNClRoZSBkYXRhIHNldCB1c2VkIGluIHRoaXMgcmVwb3J0IGNvbnNpc3RzIG9mIHR3bywgb25lIGlzIHRoZSBsZXZlbCBvZiBjb25zdW1wdGlvbiBvZiBhbGNvaG9sIGluIGVhY2ggY291bnRyeSAoaW5jbHVkaW5nIHRocmVlIHR5cGVzIG9mIGFsY29ob2wpLCBhbmQgdGhlIG90aGVyIGlzIHRoZSBXb3JsZCBIYXBwaW5lc3MgSW5kZXggKGFuZCBjb250YWlucyB0aGUgbWFjcm8gaW5kaWNlcyBvZiB2YXJpb3VzIGNvdW50cmllcykuIFRoZSBwdXJwb3NlIG9mIHRoaXMgcmVwb3J0IGlzIHRvIHVuZGVyc3RhbmQgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIG5hdGlvbmFsIGNvbnN1bXB0aW9uIG9mIGFsY29ob2wgYW5kIGhhcHBpbmVzcyBpbmRleCBhbmQgbWFjcm8gZGF0YS4gVGhlIGVudGlyZSByZXBvcnQgY29udGFpbnMgdGhlIG1haW4gNyBwYXJ0cy4gVGhlIGZpcnN0IHR3byBwYXJ0cyBtYWlubHkgZGVzY3JpYmVzIHRoZSBjb21wb3NpdGlvbiBvZiB0aGUgdHdvIGRhdGEgc2V0cyBhbmQgaW1wb3J0cyB0aGUgZGF0YSBpbnRvIFIuIFRoZSB0aGlyZCBwYXJ0IGlzIHRvIHByb2Nlc3MgdGhlIHR3byBkYXRhIHNldHMgc2VwYXJhdGVseSBhbmQgY2hhbmdlIHRoZSBkYXRhIGZvcm1hdCwgUmVhY2ggdGhlIG1vc3QgY2xlYW4uIFRoZSBmb3VydGggcGFydCBpcyB0byBjb21iaW5lIHRoZSB0d28gcHJvY2Vzc2VkIGRhdGEgc2V0cyB0b2dldGhlciwgdGhlbiB0byB0aWR5IGl0IHRvIGJlIGNsZWFuLiBBbHNvLCB0byB1c2UgYG11dGF0ZSgpYCB0byBhZGQgYW5kIGNyZWF0ZSBvbmUgbmV3IHZhcmlhYmxlLiBBdCB0aGUgc2FtZSB0aW1lLCBtaXNzaW5nIHZhbHVlcyBhbmQgaW5jb25zaXN0ZW50IHF1ZXJpZXMgYXJlIGFsc28gZXhlY3V0ZWQgaW4gbmV4dCBzZWN0aW9uLiBUaGUgc2l4dGggcGFydCBpcyB0aGUgc2Nhbm5pbmcgb2Ygb3V0bGllcnMuIFVzZSBgei5zY29yZXNgIHRvIGZpbmQgb3V0IHRoZSBvdXRsaWVycywgdGhlbiB1c2UgdGhlIGF2ZXJhZ2Ugb2YgdGhlIHZhcmlhYmxlcyB0byByZXBsYWNlIHRoZSBvdXRsaWVycyBmb3IgdGhlIHB1cnBvc2Ugb2YgcmVtb3ZlIG91dGxpdGVycyB3aXRob3V0IHByb2R1Y2UgbWlzc2luZyB2YWx1ZS4gSW4gdGhlIGxhc3QgcGFydCwgd2Ugc2VsZWN0ZWQgdGhlIGZhbWlseSB2YXJpYWJsZXMgZm9yIGRhdGEgY29udmVyc2lvbi4NCg0KDQojIyAyLiBEYXRhIA0KDQpUaGlzIHJlcG9ydCBjb250YWlucyB0d28gZGF0YSBzZXRzOiAiV29ybGQgSGFwcGluZXNzIFJlcG9ydCIgYW5kICJBbGNvaG9sIGNvbnN1bXB0aW9uIGJ5IGNvdW50cnkiLg0KDQojIyMgMi4xIFJlYWQvSW1wb3J0IERhdGENCg0KKiBGb3IgaW1wb3J0IGRhdGEgc2V0LCB0aGUgZnVuY3Rpb24gYHJlYWRfY3N2KClgIHdhcyB1c2VkLiBCZWNhdXNlIGZ1bmN0aW9uIGByZWFkX2NzdigpYCBjYW4gaW1wb3J0IHRoZSAiLmNzdiIsIGFuZCBgcmVhZHJgIHBhY2thZ2UgYXJlIGFyb3VuZCAxMHggZmFzdGVyIHRoYW4gdGhlIGJhc2UgUiBmdW5jdGlvbnMuDQoNCiogVGhlbiBJIGltcG9ydCAqMjAxNi5jc3YqIHdpdGggYHJlYWRfY3N2KClgIHRvICpocCosIGl0IGlzIHRoZSBoYXBweW5lc3MgZGF0YSBzZXQuDQoqIFRoZW4gSSBpbXBvcnQgKmRyaW5rcy5jc3YqIHdpdGggYHJlYWRfY3N2KClgIHRvICphbCosIGl0IGlzIHRoZSBhbGNvaG9sIGNvbnN1bXB0aW9uIGRhdGEgc2V0Lg0KDQoNCmBgYHtyLCBlY2hvID0gVFJVRSwgd2FybmluZ3MgPSBGQUxTRSwgbWVzc2FnZT1GQUxTRX0NCmhwIDwtIHJlYWRfY3N2KCIyMDE2LmNzdiIpDQphbCA8LSByZWFkX2NzdigiZHJpbmtzLmNzdiIpDQpgYGANCiMjIyAyLjIgU2hvdyB0aGUgdGFibGVzIG9mIHRvIGRhdGEgc2V0cw0KDQorIFdvcmxkIEhhcHBpbmVzcyB0YWJsZQ0KDQpgYGB7ciwgZWNobyA9IFRSVUUsIHdhcm5pbmdzID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQpoZWFkKGhwKQ0KYGBgDQoNCisgQWxjb2hvbCBjb25zdW1wdGlvbiB0YWJsZQ0KDQpgYGB7ciwgZWNobyA9IFRSVUUsIHdhcm5pbmdzID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQpoZWFkKGFsKQ0KYGBgDQoNCiMjIDMuIFVuZGVyc3RhbmQgDQoNCiMjIyAzLjEgQWxjb2hvbCBjb25zdW1wdGlvbiBieSBjb3VudHJ5DQoNClRoZSBBbGNvaG9sIENvbnN1bXB0aW9uIFJlcG9ydCBpcyBhYm91dCB0aGUgYW1vdW50IG9mIGFsY29ob2wgY29uc3VtZWQgaW4gZGlmZmVyZW50IGNvdW50cmllcywgcHVibGlzaGVkIGluIDIwMTYuIEl0IGNvbnRhaW5zIDE5MyBjb3VudHJpZXMgYW5kIHJlZ2lvbnMsIGFuZCB0aGUgdHlwZXMgb2YgYWxjb2hvbCBpbnZlc3RpZ2F0ZWQgYXJlIHRocmVlLCBiZWVyLCBzcGlyaXQgYW5kIHdpbmUuDQoNClRoZSBzaXggdmFyaWFibGVzIHdlcmUgc2hvd24gYmVsb3csIGFuZCB0aGUgY291bnRyeSBhbmQgY29udGluZW50YWwgdmFyaWFibGVzIGFyZSBjaGFyYWN0ZXIgdmFyaWFibGVzLCBhbmQgdGhlIG90aGVyIHZhcmlhYmxlcyBhcmUgbnVtZXJpYyB2YXJpYWJsZXMuIEluIHRoZSBzdWJzZXF1ZW50IHByb2Nlc3NpbmcsIHRoZSBjb250aW5lbnQgdmFyaWFibGUgaXMgY29udmVydGVkIGludG8gZmFjdG9yIHZhcmlhYmxlcyBmb3IgY29udmVuaWVuY2UsIHRvIGxhYmVsbGVkIG1haW4gYXJlYXMuDQoNCiAgICsgKipDb3VudHJ5Kio6IE5hbWUgb2YgdGhlIGNvdW50cnkuDQoNCiAgICsgKipCZWVyX3NlcnZpbmdzKio6IExpdGVycyAoIHBlciBjYXBpdGEgKSBvZiBiZWVyIGNvbnN1bXB0aW9uLg0KDQogICArICoqU3Bpcml0X3NlcnZpbmdzKio6IExpdGVycyAoIHBlciBjYXBpdGEgKSBvZiBzcGlyaXQgY29uc3VtcHRpb24uDQoNCiAgICsgKipXaW5lX3NlcnZpbmdzKio6IExpdGVycyAoIHBlciBjYXBpdGEgKSBvZiB3aW5lIGNvbnN1bXB0aW9uLg0KDQogICArICoqdG90YWxfbGl0cmVzX29mX3B1cmVfYWxjb2hvbCoqOiBUb3RhbCBsaXRyZXMgb2YgcHVyZSBhbGNvaG9sLg0KDQogICArICoqQ29udGluZW50Kio6IFRoZSBjb250aW5lbnQgd2hlcmUgdGhlIGNvdW50cnkgaXMgbG9jYXRlZC4NCiAgIA0KIyMjIyMgVGhpcyBkYXRhIHNldCB3YXMgZG93bmxvYWRlZCBmcm9tIFx0ZXh0Y29sb3J7Ymx1ZX17d3d3LmthZ2dsZS5jb219IHdpdGggIi56aXAiLiBUaGUgZGV0YWlsIG9mIHRoZSBkb3dubG9yZCB3ZWJzaXRlIGlzIHNob3duIGFzIGJlbG93LiANCg0KDQogICsgVVBMOiBcdGV4dGNvbG9ye2JsdWV9e2h0dHBzOi8vd3d3LmthZ2dsZS5jb20vanVzdG1hcmtoYW0vYWxjb2hvbC1jb25zdW1wdGlvbi1ieS1jb3VudHJ5L2Rvd25sb2Fkcy9hbGNvaG9sLWNvbnN1bXB0aW9uLWJ5LWNvdW50cnkuemlwLzF9DQoNCg0KIyMjIyAzLjIgV29ybGQgSGFwcGluZXNzIFJlcG9ydA0KDQpUaGUgV29ybGQgSGFwcGluZXNzIFJlcG9ydCBpcyBhIGxhbmRtYXJrIHN1cnZleSBvZiBnbG9iYWwgaGFwcGluZXNzLiBTdXJ2ZXlzIG9mIGhhcHBpbmVzcy1yZWxhdGVkIGluZGljZXMgaW4gbW9yZSB0aGFuIDE1MCBjb3VudHJpZXMuIEl0IGlzIHB1Ymxpc2hlZCBhdCB0aGUgVW5pdGVkIE5hdGlvbnMgQ2VsZWJyYXRpb24gb2YgSW50ZXJuYXRpb25hbCBIYXBwaW5lc3MgRGF5IGV2ZXJ5IHllYXIsIGZvciBhY2N1cmF0ZSB1c2UgaW4gY29uanVuY3Rpb24gd2l0aCB0aGUgQWxjb2hvbCBDb25zdW1wdGlvbiBEYXRhc2V0LCB0aGUgMjAxNiBkYXRhIHNldCB3YXMgdXNlZC4gSXQgY29udGFpbnMgMTU3IGNvdW50cmllcyBhbmQgcmVnaW9ucy5BbHNvLCAxMyB2YXJpYWJsZXMgd2VyZSBjb250YWluZWQgKFRoZSBjb3VudHJ5IGFuZCByZWdpb24gYXJlIGNoYXJhY3RlciB2YXJpYWJsZXMsIGFuZCB0aGUgb3RoZXIgMTEgdmFyaWFibGVzIGFyZSBudW1lcmljIHZhcmlhYmxlcy4gSW4gdGhlIHN1YnNlcXVlbnQgcHJvY2Vzc2luZywgdGhlIHJlZ2lvbiB2YXJpYWJsZSBpcyBjb252ZXJ0ZWQgaW50byBmYWN0b3IgdmFyaWFibGVzIGZvciBjb252ZW5pZW5jZSwgdG8gbGFiZWxsZWQgbWFpbiBhcmVhcy4gVGhlIGhhcHBpbmVzcyByYW5rIGlzIGEgbnVtZXJpYyB2YXJpYWJsZSBpbiB0aGUgZGF0YSBzZXQsIGJ1dCBpbiByZWFsaXR5IGl0IGlzIGEgZmFjdG9yIHZhcmlhYmxlLiBJdCB3aWxsIGJlIGNvbnZlcnRlZCBpbiBzdWJzZXF1ZW50IG9wZXJhdGlvbnMuKSwgd2hpY2ggYXJlOg0KDQogICArICoqQ291bnRyeSoqOiBOYW1lIG9mIHRoZSBjb3VudHJ5Lg0KDQogICArICoqUmVnaW9uKio6IFJlZ2lvbiB0aGUgY291bnRyeSBiZWxvbmdzIHRvLg0KDQogICArICoqSGFwcGluZXNzIFJhbmsqKjogUmFuayBvZiB0aGUgY291bnRyeSBiYXNlZCBvbiB0aGUgSGFwcGluZXNzIFNjb3JlLg0KDQogICArICoqSGFwcGluZXNzIFNjb3JlKio6IEEgbWV0cmljIG1lYXN1cmVkIGluIDIwMTYgYnkgYXNraW5nIHRoZSBzYW1wbGVkIHBlb3BsZSB0aGUgcXVlc3Rpb246ICJIb3cgd291bGQgeW91IHJhdGUgeW91ciBoYXBwaW5lc3Mgb24gYSBzY2FsZSBvZiAwIHRvIDEwIHdoZXJlIDEwIGlzIHRoZSBoYXBwaWVzdCIuDQoNCiAgICsgKipMb3dlciBDb25maWRlbmNlIEludGVydmFsKio6IExvd2VyIENvbmZpZGVuY2UgSW50ZXJ2YWwgb2YgdGhlIEhhcHBpbmVzcyBTY29yZS4NCg0KICAgKyAqKlVwcGVyIENvbmZpZGVuY2UgSW50ZXJ2YWwqKjogVXBwZXIgQ29uZmlkZW5jZSBJbnRlcnZhbCBvZiB0aGUgSGFwcGluZXNzIFNjb3JlLg0KDQogICArICoqRWNvbm9teSAoR0RQIHBlciBDYXBpdGEpKio6IFRoZSBleHRlbnQgdG8gd2hpY2ggR0RQIGNvbnRyaWJ1dGVzIHRvIHRoZSBjYWxjdWxhdGlvbiBvZiB0aGUgSGFwcGluZXNzIFNjb3JlLg0KDQogICArICoqRmFtaWx5Kio6IFRoZSBleHRlbnQgdG8gd2hpY2ggRmFtaWx5IGNvbnRyaWJ1dGVzIHRvIHRoZSBjYWxjdWxhdGlvbiBvZiB0aGUgSGFwcGluZXNzIFNjb3JlLg0KDQogICArICoqSGVhbHRoIChMaWZlIEV4cGVjdGFuY3kpKio6IFRoZSBleHRlbnQgdG8gd2hpY2ggTGlmZSBleHBlY3RhbmN5IGNvbnRyaWJ1dGVkIHRvIHRoZSBjYWxjdWxhdGlvbiBvZiB0aGUgSGFwcGluZXNzIFNjb3JlLg0KDQogICArICoqRnJlZWRvbSoqOlRoZSBleHRlbnQgdG8gd2hpY2ggRnJlZWRvbSBjb250cmlidXRlZCB0byB0aGUgY2FsY3VsYXRpb24gb2YgdGhlIEhhcHBpbmVzcyBTY29yZS4NCg0KICAgKyAqKlRydXN0IChHb3Zlcm5tZW50IENvcnJ1cHRpb24pKio6IFRoZSBleHRlbnQgdG8gd2hpY2ggUGVyY2VwdGlvbiBvZiBDb3JydXB0aW9uIGNvbnRyaWJ1dGVzIHRvIEhhcHBpbmVzcyBTY29yZS4NCg0KICAgKyAqKkdlbmVyb3NpdHkqKjogVGhlIGV4dGVudCB0byB3aGljaCBHZW5lcm9zaXR5IGNvbnRyaWJ1dGVkIHRvIHRoZSBjYWxjdWxhdGlvbiBvZiB0aGUgSGFwcGluZXNzIFNjb3JlLg0KDQogICArICoqRHlzdG9waWEgUmVzaWR1YWwqKjogVGhlIGV4dGVudCB0byB3aGljaCBEeXN0b3BpYSBSZXNpZHVhbCBjb250cmlidXRlZCB0byB0aGUgY2FsY3VsYXRpb24gb2YgdGhlIEhhcHBpbmVzcyBTY29yZS4NCg0KIyMjIyMgVGhpcyBkYXRhIHNldCB3YXMgZG93bmxvYWRlZCBmcm9tIFx0ZXh0Y29sb3J7Ymx1ZX17d3d3LmthZ2dsZS5jb219IHdpdGggIi56aXAiLiBUaGUgZGV0YWlsIG9mIHRoZSBkb3dubG9yZCB3ZWJzaXRlIGlzIHNob3duIGFzIGJlbG93LiANCg0KICAgKyBVUEw6IFx0ZXh0Y29sb3J7Ymx1ZX17aHR0cHM6Ly93d3cua2FnZ2xlLmNvbS91bnNkc24vd29ybGQtaGFwcGluZXNzL2Rvd25sb2Fkcy93b3JsZC1oYXBwaW5lc3MtcmVwb3J0LnppcC8yfQ0KDQoNCiMjCTQuIFRpZHkgJiBNYW5pcHVsYXRlIERhdGEgSSANCg0KQmVmb3JlIGNvbWJpbmluZyB0aGUgdHdvIGRhdGEgc2V0cywgaW4gb3JkZXIgdG8gZmFjaWxpdGF0ZSB0aGUgc3Vic2VxdWVudCBkYXRhIHByb2Nlc3NpbmcsIHdlIG5lZWQgdG8gbW9kaWZ5IHRoZSB0d28gZGF0YSBhY2NvcmRpbmdseS4NCg0KIyMjIDQuMSBNb2RpZnkgdGhlIGhhcHBpbmVzcyBkYXRhIHNldA0KDQpgYGB7ciwgZWNobyA9IFRSVUUsIHdhcm5pbmdzID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQojIFN0ZXAgMTogTW9kaWZ5IHRoZSByZWdpb24gYW5kIGhhcHBpbmVzcyByYW5rIHZhcmlhYmxlcyBmcm9tIGEgY2hhcmFjdGVyDQojIHZhcmlhYmxlIHRvIGEgZmFjdG9yIHZhcmlhYmxlDQoNCmhwJFJlZ2lvbiA8LSBmYWN0b3IoaHAkUmVnaW9uKQ0KaHAkYEhhcHBpbmVzcyBSYW5rYCA8LSBmYWN0b3IoaHAkYEhhcHBpbmVzcyBSYW5rYCkNCmNsYXNzKGhwJFJlZ2lvbikNCmNsYXNzKGhwJGBIYXBwaW5lc3MgUmFua2AgKQ0KaGVhZChocCkNCiMgU3RlcCAyOiBNb2RpZnkgdGhlIGZvcm1hdCBvZiB0aGUgY291bnRyeSBuYW1lLCBtb2RpZnkgdGhlIGZvcm1hdCBhbmQgcmVtb3ZlDQojIHB1bmN0dWF0aW9uLCBhbmQgc3RhbmRhcmRpemUgdGhlIGNvdW50cnkgbmFtZSBzbyB0aGF0IHRoZSB0d28gZGF0YSBzZXRzIGNhbiBiZQ0KIyBzdWNjZXNzZnVsbHkgY29tYmluZWQuDQoNCmhwJENvdW50cnkgPC0gaHAkQ291bnRyeSAlPiUgc3RyX3JlcGxhY2VfYWxsKHBhdHRlcm4gPSAiWzpwdW5jdDpdIiwgcmVwbGFjZW1lbnQgPSAiIikNCmBgYA0KDQojIyMgNC4yIE1vZGlmeSB0aGUgYWxjb2hvbCBjb25zdW1wdGlvbiBkYXRhIHNldA0KDQpgYGB7ciwgZWNobyA9IFRSVUUsIHdhcm5pbmdzID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQojIFN0ZXAgMTogTW9kaWZ5IHRoZSBuYW1lIG9mIHRoZSBkYXRhc2V0IHZhcmlhYmxlLCB3aGljaCBpcyBlYXN5IHRvIHZpZXcgYW5kIHVzZS4NCmNvbG5hbWVzKGFsKSA8LSBjKCJDb3VudHJ5IiwgIkJlZXIiLCAiU3Bpcml0IiwgIldpbmUiLCAiVG90YWwgcHVyZSBhbGNvaG9sIiwgIkNvbnRpbmVudCIpDQpoZWFkKGFsKQ0KYGBgDQoNCmBgYHtyLCBlY2hvID0gVFJVRSwgd2FybmluZ3MgPSBGQUxTRSwgbWVzc2FnZT1GQUxTRX0NCiMgU3RlcCAyOiBNb2RpZnkgdGhlIENvbnRpbmVudCB2YXJpYWJsZSBmcm9tIGEgY2hhcmFjdGVyIHZhcmlhYmxlIHRvIGEgZmFjdG9yIHZhcmlhYmxlDQoNCmFsJENvbnRpbmVudCA8LSBmYWN0b3IoYWwkQ29udGluZW50KQ0KY2xhc3MoYWwkQ29udGluZW50KQ0KaGVhZChhbCkNCmBgYA0KDQpgYGB7ciwgZWNobyA9IFRSVUUsIHdhcm5pbmdzID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQojIFN0ZXAgMzogTW9kaWZ5IHRoZSBmb3JtYXQgb2YgdGhlIGNvdW50cnkgbmFtZSwgbW9kaWZ5IHRoZSBmb3JtYXQsIGFuZCByZW1vdmUNCiMgcHVuY3R1YXRpb24gdG8gZW5zdXJlIHRoYXQgdGhlIG5hbWUgZm9ybWF0IGlzIHRoZSBzYW1lIGFzIHRoZSBjb3VudHJ5IG5hbWUgDQojIGZvcm1hdCBpbiB0aGUgSGFwcGluZXNzIGRhdGEgc2V0Lg0KDQojIENoYW5nZSBhbGwgIiYiIHN5bWJvbHMgdG8gImFuZCIgDQphbCRDb3VudHJ5IDwtIGFsJENvdW50cnkgJT4lIHN0cl9yZXBsYWNlX2FsbChwYXR0ZXJuID0gIiYiLCByZXBsYWNlbWVudCA9ICIiKSANCg0KIyBSZW1vdmUgYWxsIHB1bmN0dWF0aW9uDQphbCRDb3VudHJ5IDwtIGFsJENvdW50cnkgJT4lIHN0cl9yZXBsYWNlX2FsbChwYXR0ZXJuID0gIls6cHVuY3Q6XSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwbGFjZW1lbnQgPSAiIikgDQoNCiMgQ2hhbmdlIHRoZSBvbmx5IGNvdW50cnkgYWJicmV2aWF0aW9uIHRvIGZ1bGwgbmFtZQ0KYWwkQ291bnRyeSA8LSBhbCRDb3VudHJ5ICU+JSBzdHJfcmVwbGFjZV9hbGwocGF0dGVybiA9ICJVU0EiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gIlVuaXRlZCBTdGF0ZXMiKSANCmBgYA0KDQoNCg0KIyMgNS4gVGlkeSAmIE1hbmlwdWxhdGUgRGF0YSBJSSANCg0KDQpBZnRlciB0aGUgcHJldmlvdXMgc3RlcCwgdGhlIHR3byBkYXRhIHNldHMgaGF2ZSBtZXQgdGhlIHJlcXVpcmVtZW50cyBiZWZvcmUgdGhlIGNvbWJpbmF0aW9uLCBhbmQgdGhlbiB0aGUgdHdvIGRhdGEgc2V0cyBuZWVkIHRvIGJlIGNvbWJpbmVkIGFuZCB0aWR5ZWQuDQoNCiMjIyA1LjEgQ29tYmluYXRpb24NCg0KSGVyZSwgYGlubmVyX2pvaW4oKWAgaXMgdXNlZCBmb3IgY29tYmluYXRpb24sIG9uIHRoZSBncm91bmRzIHRoYXQgYWx0aG91Z2ggdGhlIHR3byBjb3VudHJpZXMgc3VydmV5ZWQgaGF2ZSBtb3JlIHRoYW4gMTUwIGNvdW50cmllcywgdGhlIGNvdW50cmllcyBzdXJ2ZXllZCBhcmUgc3RpbGwgZGlmZmVyZW50LiBTbyBmb3IgZGF0YSBpbnRlZ3JpdHksIHdlIHVzZSBgaW5uZXJfam9pbigpYCAoa2V5d29yZCBpcyBjb3VudHJ5KSB0byBleGNsdWRlIGNvdW50cmllcyBhbmQgdGhlaXIgYXNzb2NpYXRlZCBkYXRhIHRoYXQgYXJlIG5vdCBpbmNsdWRlZCBpbiB0aGUgdHdvIGRhdGEgc2V0cyBhdCB0aGUgc2FtZSB0aW1lLCBzYXZpbmcgb25seSB0aGUgY291bnRyaWVzIGFuZCB0aGVpciBhc3NvY2lhdGVkIGRhdGEgY29udGFpbmVkIGluIGJvdGggZGF0YSBzZXRzLiBUaGVuIGdldCB0aGUgbmV3IGRhdGEgc2V0ICJocGFsIi4NCg0KYGBge3IsIGVjaG8gPSBUUlVFLCB3YXJuaW5ncyA9IEZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KaHBhbCA8LSBpbm5lcl9qb2luKGhwLGFsLGJ5PSJDb3VudHJ5IikNCmhlYWQoaHBhbCkNCmBgYA0KDQojIyMgNS4yIFRpZHkNCg0KIyMjIyA1LjIuMSBEZWxldGUgZHVwbGljYXRlIHZhcmlhYmxlDQoNCkJ5IG9ic2VydmluZyB0aGUgZGF0YXNldCwgd2UgZm91bmQgdGhhdCB0aGUgZ2VvZ3JhcGhpY2FsIGxvY2F0aW9ucyBjb250YWluZWQgaW4gdGhlIHJlZ2lvbiBhbmQgY29udGluZW50IHZhcmlhYmxlcyBhcmUgc2ltaWxhciAodGhlIGluZm9ybWF0aW9uIGNvbnRhaW5lZCBpbiB0aGUgY29udGluZW50IGlzIHRoZSBzaXggbWFqb3IgY29udGluZW50cyBvbiB0aGUgcGxhbmV0LCBhbmQgdGhlIHJlZ2lvbiBpcyBtb3JlIHNwZWNpZmljKSwgc28gaW4gb3JkZXIgdG8gYXZvaWQgZGF0YSBkdXBsaWNhdGlvbiB3ZSBkbyBub3QgbmVlZCBjb250aW5lbnRhbCB2YXJpYWJsZXMgdG8gZGVsZXRlIGNvbnRpbmVudCB2YXJpYWJsZXMuIA0KDQpgYGB7ciwgZWNobyA9IFRSVUUsIHdhcm5pbmdzID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQpocGFsIDwtIHN1YnNldChocGFsLCwtYyhDb250aW5lbnQpKQ0KaGVhZChocGFsKQ0KYGBgDQoNCiMjIyMgNS4yLjIgDQoNCkluIG9yZGVyIHRvIG1vcmUgY2xvc2VseSBvYnNlcnZlIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgdGhyZWUgYWxjb2hvbCBjb25zdW1wdGlvbiAoYmVlciwgc3Bpcml0IGFuZCB3aW5lKSBhbmQgdGhlIGhhcHBpbmVzcyBzY29yZSwgd2UgY3JlYXRlIGEgbmV3IHZhcmlhYmxlLCB3aGljaCBpcyB0aGUgdG90YWwgb2YgdGhyZWUgYWxjb2hvbCBjb25zdW1wdGlvbi4NCg0KYGBge3IsIGVjaG8gPSBUUlVFLCB3YXJuaW5ncyA9IEZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KaHBhbCA8LSBocGFsICU+JSBtdXRhdGUoYFN1bSBvZiBhbGNvaG9sYCA9IEJlZXIgKyBTcGlyaXQgKyBXaW5lKQ0KaGVhZChocGFsKQ0KYGBgDQoNCisgU2hvdyB0aGUgbmV3IHZhcmlhYmxlIGFib3V0IENvdW50cnksIEhhcHBpbmVzcyBSYW5rLCBIYXBwaW5lc3MgU2NvcmUgYW5kIFN1bSBvZiBhbGNvaG9sLg0KDQpgYGB7ciwgZWNobyA9IFRSVUUsIHdhcm5pbmdzID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQpocGFsc3Vic2V0PC1zdWJzZXQoaHBhbCwsYygiQ291bnRyeSIsICJIYXBwaW5lc3MgUmFuayIsICJIYXBwaW5lc3MgU2NvcmUiLCAiU3VtIG9mIGFsY29ob2wiKSkNCmhlYWQoaHBhbHN1YnNldCkNCmBgYA0KDQoNCiMjCTYuIFNjYW4gSSANCg0KU2NhbiB0aGUgZGF0YSBmb3IgbWlzc2luZyB2YWx1ZXMsIGluY29uc2lzdGVuY2llcyBhbmQgb2J2aW91cyBlcnJvcnMuDQoNCiMjIyA2LjEgTXNzaW5nIHZhbHVlcw0KDQpVc2UgYGlzLm5hKClgIHRvIGp1ZGdlIHRoZSBlbnRpcmUgZGF0YSBzZXQgdG8gZGV0ZXJtaW5lIGlmIHRoZXJlIGFyZSBtaXNzaW5nIHZhbHVlcy4gVGhlbiB1c2UgYHN1bSgpYCB0byBzaG93IGhvdyBtYW55IG1pc3NpbmcgdmFsdWVzIGFyZSBpbiB0b3RhbC4NCg0KYGBge3J9DQpzdW0oaXMubmEoaHBhbCkpDQpgYGANCg0KQWNjb3JkaW5nIHRvIHRoZSByZXN1bHRzLCB0aGUgdG90YWwgbnVtYmVyIG9mIG1pc3NpbmcgdmFsdWVzIGZvciB0aGUgZW50aXJlIGRhdGEgc2V0IGlzIHplcm8sIHNvIHRoZXJlIGFyZSBubyBtaXNzaW5nIHZhbHVlcy4NCg0KDQojIyMgNi4yIEluY29uc2lzdGVuY2llcyBvciBTcGVjaWFsIFZhbHVlcw0KDQpgYGB7cn0NCmlzLnNwZWNpYWwgPC0gZnVuY3Rpb24oeCl7DQppZiAoaXMubnVtZXJpYyh4KSkgKGlzLmluZmluaXRlKHgpIHwgaXMubmFuKHgpKQ0KfQ0Kc2FwcGx5KGhwYWwsIGlzLnNwZWNpYWwpJT4lIHN1bW1hcnkoKQ0KDQpgYGANCg0KVGhlIHJlc3VsdHMgYWJvdmUgc2hvdyB0aGF0LCB0aGVyZSBubyBmdXJ0aGVyIGluY29uc2lzdGVuY2llcyBvciBzcGVjaWFsIHZhbHVlcyBpbiB0aGUgZGF0YSBzZXQgb2YgJ2hwYWwnIGZvciBlYWNoIHZhcmlhYmxlLiANCg0KDQoNCg0KDQojIwk3LiBTY2FuIElJDQoNClNjYW4gdGhlIG51bWVyaWMgZGF0YSBmb3Igb3V0bGllcnMuIEFuZCB1c2UgYHouc2NvcmVzYCB0byBkaXNwbGF5IG91dGxpZXJzIGFuZCBgd2hpY2goKWAgYGxlbmd5aCgpYCB0byBjYWxjdWxhdGUgdGhlIG51bWJlciBvZiBvdXRsaWVycyBCZWNhdXNlIHRoZSBjb250ZW50IGNvbnRhaW5lZCBpbiB0aGUgY291bnRyeSBhbmQgcmVnaW9uIHZhcmlhYmxlcyBpcyB0aGUgY291bnRyeSBuYW1lIGFuZCB0aGUgcmVnaW9uIG5hbWUsIHRoZXJlIGlzIG5vIG5lZWQgdG8gbG9vayBmb3Igb3V0bGllcnMuIEluIHNhbWUgcmVhc29uLCBoYXBwaW5lc3MgcmFuayBpcyBvbmx5IHJhbmsgYnkgbnVtYmVyLCBzbyB0aGVyZSBpcyBubyBuZWVkIHRvIGZpbmQgb3V0bGllcnMuDQoNCg0KIyMjIyA3LjEgRmluZCBvdXRsaWVycyBieSB6LnNjb3Jlcw0KDQpDYWxjdWxhdGUgeiBzY29yZXMgZm9yIGVhY2ggdmFyaWFibGUgKGV4Y2x1ZGUgY291bnRyeSxyZWdpb24gYW5kIGhhcHBpbmVzcyByYW5rIHZhcmlhYmxlcykgYW5kIHRoZW4gbG9vayBmb3Igb3V0bGllcnMuIElmIHouc2NvcmVzIGlzIGdyZWF0ZXIgdGhhbiAzLCBpdCBpcyBjb25zaWRlcmVkIGFuIG91dGxpZXIuDQoNCmBgYHtyLCBlY2hvID0gVFJVRSwgd2FybmluZ3MgPSBGQUxTRSwgbWVzc2FnZT1GQUxTRX0NCnouc2NvcmVzMSA8LSAgc2NvcmVzKGhwYWxbLDRdLHR5cGUgPSAieiIpDQp6LnNjb3JlczIgPC0gIHNjb3JlcyhocGFsWyw1XSx0eXBlID0gInoiKQ0Kei5zY29yZXMzIDwtICBzY29yZXMoaHBhbFssNl0sdHlwZSA9ICJ6IikNCnouc2NvcmVzNCA8LSAgc2NvcmVzKGhwYWxbLDddLHR5cGUgPSAieiIpDQp6LnNjb3JlczUgPC0gIHNjb3JlcyhocGFsWyw4XSx0eXBlID0gInoiKQ0Kei5zY29yZXM2IDwtICBzY29yZXMoaHBhbFssOV0sdHlwZSA9ICJ6IikNCnouc2NvcmVzNyA8LSAgc2NvcmVzKGhwYWxbLDEwXSx0eXBlID0gInoiKQ0Kei5zY29yZXM4IDwtICBzY29yZXMoaHBhbFssMTFdLHR5cGUgPSAieiIpDQp6LnNjb3JlczkgPC0gIHNjb3JlcyhocGFsWywxMl0sdHlwZSA9ICJ6IikNCnouc2NvcmVzMTAgPC0gIHNjb3JlcyhocGFsWywxM10sdHlwZSA9ICJ6IikNCnouc2NvcmVzMTEgPC0gIHNjb3JlcyhocGFsWywxNF0sdHlwZSA9ICJ6IikNCnouc2NvcmVzMTIgPC0gIHNjb3JlcyhocGFsWywxNV0sdHlwZSA9ICJ6IikNCnouc2NvcmVzMTMgPC0gIHNjb3JlcyhocGFsWywxNl0sdHlwZSA9ICJ6IikNCnouc2NvcmVzMTQgPC0gIHNjb3JlcyhocGFsWywxN10sdHlwZSA9ICJ6IikNCnouc2NvcmVzMTUgPC0gIHNjb3JlcyhocGFsWywxOF0sdHlwZSA9ICJ6IikNCg0KbGVuZ3RoKHdoaWNoKCBhYnMoei5zY29yZXMxKSA+MyApKQ0KbGVuZ3RoKHdoaWNoKCBhYnMoei5zY29yZXMyKSA+MyApKQ0KbGVuZ3RoKHdoaWNoKCBhYnMoei5zY29yZXMzKSA+MyApKQ0KbGVuZ3RoKHdoaWNoKCBhYnMoei5zY29yZXM0KSA+MyApKQ0KbGVuZ3RoKHdoaWNoKCBhYnMoei5zY29yZXM1KSA+MyApKQ0KbGVuZ3RoKHdoaWNoKCBhYnMoei5zY29yZXM2KSA+MyApKQ0KbGVuZ3RoKHdoaWNoKCBhYnMoei5zY29yZXM3KSA+MyApKQ0KbGVuZ3RoKHdoaWNoKCBhYnMoei5zY29yZXM4KSA+MyApKQ0KbGVuZ3RoKHdoaWNoKCBhYnMoei5zY29yZXM5KSA+MyApKQ0KbGVuZ3RoKHdoaWNoKCBhYnMoei5zY29yZXMxMCkgPjMgKSkNCmxlbmd0aCh3aGljaCggYWJzKHouc2NvcmVzMTEpID4zICkpDQpsZW5ndGgod2hpY2goIGFicyh6LnNjb3JlczEyKSA+MyApKQ0KbGVuZ3RoKHdoaWNoKCBhYnMoei5zY29yZXMxMykgPjMgKSkNCmxlbmd0aCh3aGljaCggYWJzKHouc2NvcmVzMTQpID4zICkpDQpsZW5ndGgod2hpY2goIGFicyh6LnNjb3JlczE1KSA+MyApKQ0KYGBgDQpBcyBjYW4gYmUgc2VlbiBmcm9tIHRoZSBhYm92ZSBjYWxjdWxhdGlvbnMsIFRydXN0IChHb3Zlcm5tZW50IENvcnJ1cHRpb24pLCBHZW5lcm9zaXR5LCBTcGlyaXQgYW5kIFdpbmUgdmFyaWFibGVzIGhhcyBvdXRsaWVycywgdGhlIG51bWJlciBvZiBvdXRsaWVycyBhcmUgMiwgMSwgMiBhbmQgMiByZXBlY3RpdmVseS4NCg0KDQojIyMjIDcuMiBJbXB1dGluZyBvdXRsaWVyDQoNCldlIGNhbiBhbHNvIGltcHV0ZSBvdXRsaWVycy4gV2UgY2FuIHVzZSBtZWFuIG9yIG1lZGlhbiBpbXB1dGF0aW9uIG1ldGhvZHMgdG8gcmVwbGFjZSBvdXRsaWVycy4gQW5kIGJlZm9yZSBJbXB1dGluZyB3ZSBzaG91bGQgY2hlY2sgd2hldGhlciB0aGUgb3V0bGllciBpcyBhIHJlc3VsdCBvZiBkYXRhIGVudHJ5L3Byb2Nlc3NpbmcgZXJyb3IuIEJ1dCBmb3IgdGhpcyBjYXNlLCB0aGUgZGF0YSBzZXQgaGF2ZSBiZSBjaGVjayBhdCBmcm9udCBwYXJ0Lg0KDQpgYGB7cn0NCkE8LWhwYWwkYFRydXN0IChHb3Zlcm5tZW50IENvcnJ1cHRpb24pYFsgDQogIHdoaWNoKCBhYnMoei5zY29yZXM4KSA+MyApXTwtIG1lYW4oaHBhbCRgVHJ1c3QgKEdvdmVybm1lbnQgQ29ycnVwdGlvbilgLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpIA0KQjwtaHBhbCRHZW5lcm9zaXR5WyB3aGljaCggYWJzKHouc2NvcmVzOSkgPjMgKV0gPC0gbWVhbihocGFsJEdlbmVyb3NpdHlbDQogIC0gd2hpY2goIGFicyh6LnNjb3JlczkpID4zICldLCBuYS5ybSA9IFRSVUUpIA0KQzwtaHBhbCRTcGlyaXRbIHdoaWNoKCBhYnMoei5zY29yZXMxMikgPjMgKV0gPC0gbWVhbihocGFsJFNwaXJpdCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSkgDQpEPC1ocGFsJFdpbmVbIHdoaWNoKCBhYnMoei5zY29yZXMxMykgPjMgKV0gPC0gbWVhbihocGFsJFdpbmUsIG5hLnJtID0gVFJVRSkNCmxlbmd0aCh3aGljaCggYWJzKHNjb3JlcyhBLHR5cGUgPSAieiIpKSA+MyApKQ0KbGVuZ3RoKHdoaWNoKCBhYnMoc2NvcmVzKEIsdHlwZSA9ICJ6IikpID4zICkpDQpsZW5ndGgod2hpY2goIGFicyhzY29yZXMoQyx0eXBlID0gInoiKSkgPjMgKSkNCmxlbmd0aCh3aGljaCggYWJzKHNjb3JlcyhELHR5cGUgPSAieiIpKSA+MyApKQ0KYGBgDQoNCkFmdGVyIHRoZSBpbXB1dGluZywgd2UgaGF2ZSBpbXB1dGluZyBhbGwgdGhlIG91dGxpZXJzIGFzIGFib3ZlIHNob3duLg0KDQoNCg0KIyMJOC4gVHJhbnNmb3JtIA0KDQoNCkFzIHRoZSBtYWluIG9ic2VydmF0aW9uIG9iamVjdCBvZiBvdXJzLCB3ZSBoYXZlIHNlbGVjdGVkIHRoZSBGYW1pbHkgdmFyaWFibGUgYXMgdGhlIHRhcmdldCBvZiBkYXRhIHRyYW5zZm9ybS4gRmlyc3Qgd2UgdXNlIGBoaXN0KClgIHRvIG9ic2VydmUgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgZGF0YS4NCg0KYGBge3J9DQpoaXN0KGhwYWwkRmFtaWx5KQ0KYGBgDQoNCkl0IGNhbiBiZSBzZWVuIHRoYXQgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgRmFtaWx5IGhhcyBhIHRlbmRlbmN5IHRvIGJlIGxlZnQgc2tld25lc3MuIFNvIHdlIGNvbnNpZGVyIHVzZSBzcXVhcmUgdHJhbnNmb3JtYXRpb24uDQoNCmBgYHtyfQ0KeDE8LWhwYWwkRmFtaWx5DQp4MV4yICU+JSBoaXN0KCkNCg0KYGBgDQoNCkFjY29yZGluZyB0byB0aGUgZmlndXJlIHNob3duLCB0aGUgY29udmVyc2lvbiB3YXMgbm90IHByZWZlY3RseSBzdWNjZXNzZnVsLCBzbyB3ZSByZS1zZWxlY3RlZCB0aGUgbWV0aG9kIHRvIHRyYW5zZm9ybS4gV2UgY29uc2lkZXIgQm94Q294IHRyYW5zZm9ybS4NCg0KDQpgYGB7cn0NCkJveENveCh4MSxsYW1iZGEgPSAiYXV0byIpICU+JSBoaXN0KCkNCg0KYGBgDQoNCkFzIHNob3duIGluIHRoZSBmaWd1cmUgYWJvdmUsIHRoZSBkaXN0cmlidXRpb24gb2YgRmFtaWx5IHZhcmlhYmxlIGlzIHZlcnkgY2xvc2UgdG8gdGhlIG5vcm1hbCBkaXN0cmlidXRpb24sIHNvIHdlIGNvbnNpZGVyIHRoZSB0cmFuc2Zvcm1hdGlvbiB0byBiZSBzdWNjZXNzZnVsLg0KDQo8YnI+DQo8YnI+DQo=