the following R packages are used in this report

Required packages

library(readr)
library(readxl)
library(foreign)
library(gdata)
library(rvest)
library(dplyr)
library(tidyr)
library(deductive)
library(validate)
library(Hmisc)
library(stringr)
library(lubridate)
library(outliers)
library(MVN)
library(infotheo)
library(MASS)
library(caret)
library(knitr)
library(ggplot2)

Executive Summary

The data that we have used in this report taken from(world bank) and it include the world Population ages 65 and above between 1960 and 2018 and income classification of countries for 264 observation.TO do further data prepossessing we do the following steps.First,the two data set was imported and read in R and then merge them by using left join() function into one data set using country code as a common variable.Then, we check the structure and attribute of the data that have been merged. After that, the data type conversion has done for some variables. Then, in order to make the data in a tidy Format we first exclude some unnecessary columns then transform data set from wide to long format has been done with convert some data type. Subsequently, We used appropriate method to deal with missing values and special values.Then, outliers have been identified by z-score method and treat by capping method. The distribution of Total_population has been checked and then logarithm base e (Ln) transformation has been used to correct the normality.

Data

The data is taken from (world bank) website, the two table contain many variables and observation The first data (population) contain 63 variables they are Country Name, Country Code, Indicator Name, Indicator Code and years from 1960 to 2018 and 264 observation. And the second data (income) contain 5 variables they are Country Code, Region, IncomeGroup, Special Notes and Table Name with 263 observation.later after join them we will exclude some of them and work on the only that we are interested in which are 62 variables and their discripition as follow Country Name,which is refers to country from all the world. Country Code, which is a short code indicating the name of the country from all the world. years from 1960:2018, refers to world population ages 65 and above between 1960 and 2018. IncomeGroup, which is refers to income classification of countries from all the world. with 264 observation

setwd("~/Desktop/API_SP.POP.65UP.TO.ZS_DS2_en_csv_v2_319149 ")
The working directory was changed to /Users/a222/Desktop/API_SP.POP.65UP.TO.ZS_DS2_en_csv_v2_319149  inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
population <- read_csv("API_SP.POP.65UP.TO.ZS_DS2_en_csv_v2_319149.csv") 
Parsed with column specification:
cols(
  .default = col_double(),
  `Country Name` = col_character(),
  `Country Code` = col_character(),
  `Indicator Name` = col_character(),
  `Indicator Code` = col_character()
)
See spec(...) for full column specifications.
head(population)

income <- read_csv("Metadata_Country_API_SP.POP.65UP.TO.ZS_DS2_en_csv_v2_319149.csv")
Parsed with column specification:
cols(
  `Country Code` = col_character(),
  Region = col_character(),
  IncomeGroup = col_character(),
  SpecialNotes = col_character(),
  TableName = col_character()
)
head(income)

We have country code as a common column between Population data set and income data set, so we use country code to merge both data set into one data set by using left join() function and then apply header of total_population data to check if the merge has done as following

total_population <- population %>% left_join(income,by="Country Code")
head(total_population)
NA

Understand

The dim() and str() functions have been used to check the the dimensions and structure of the data set.

## to ckeck the  the dimensions of total_population,
dim(total_population)
[1] 264  67
##In order to check te structure of our data set we can apply this command,
str(total_population)
Classes ‘spec_tbl_df’, ‘tbl_df’, ‘tbl’ and 'data.frame':    264 obs. of  67 variables:
 $ Country Name  : chr  "Aruba" "Afghanistan" "Angola" "Albania" ...
 $ Country Code  : chr  "ABW" "AFG" "AGO" "ALB" ...
 $ Indicator Name: chr  "Population ages 65 and above (% of total population)" "Population ages 65 and above (% of total population)" "Population ages 65 and above (% of total population)" "Population ages 65 and above (% of total population)" ...
 $ Indicator Code: chr  "SP.POP.65UP.TO.ZS" "SP.POP.65UP.TO.ZS" "SP.POP.65UP.TO.ZS" "SP.POP.65UP.TO.ZS" ...
 $ 1960          : num  2.48 2.8 3.01 5.41 NA ...
 $ 1961          : num  2.58 2.81 3.05 5.39 NA ...
 $ 1962          : num  2.69 2.8 3.06 5.41 NA ...
 $ 1963          : num  2.8 2.79 3.07 5.44 NA ...
 $ 1964          : num  2.93 2.75 3.07 5.46 NA ...
 $ 1965          : num  3.08 2.71 3.06 5.46 NA ...
 $ 1966          : num  3.23 2.72 3.03 5.4 NA ...
 $ 1967          : num  3.4 2.72 2.98 5.34 NA ...
 $ 1968          : num  3.57 2.7 2.9 5.27 NA ...
 $ 1969          : num  3.78 2.67 2.77 5.22 NA ...
 $ 1970          : num  4 2.63 2.61 5.19 NA ...
 $ 1971          : num  4.36 2.64 2.64 5.18 NA ...
 $ 1972          : num  4.74 2.63 2.67 5.18 NA ...
 $ 1973          : num  5.12 2.61 2.68 5.18 NA ...
 $ 1974          : num  5.49 2.58 2.68 5.19 NA ...
 $ 1975          : num  5.86 2.55 2.67 5.2 NA ...
 $ 1976          : num  6.04 2.56 2.65 5.22 NA ...
 $ 1977          : num  6.24 2.55 2.62 5.24 NA ...
 $ 1978          : num  6.44 2.52 2.6 5.26 NA ...
 $ 1979          : num  6.65 2.49 2.58 5.28 NA ...
 $ 1980          : num  6.85 2.43 2.56 5.3 NA ...
 $ 1981          : num  6.99 2.45 2.57 5.33 NA ...
 $ 1982          : num  7.11 2.45 2.58 5.35 NA ...
 $ 1983          : num  7.19 2.41 2.58 5.37 NA ...
 $ 1984          : num  7.27 2.35 2.58 5.39 NA ...
 $ 1985          : num  7.32 2.24 2.56 5.39 NA ...
 $ 1986          : num  7.38 2.27 2.55 5.41 NA ...
 $ 1987          : num  7.46 2.29 2.52 5.41 NA ...
 $ 1988          : num  7.53 2.3 2.49 5.42 NA ...
 $ 1989          : num  7.61 2.29 2.48 5.44 NA ...
 $ 1990          : num  7.66 2.23 2.47 5.49 NA ...
 $ 1991          : num  7.39 2.24 2.48 5.65 NA ...
 $ 1992          : num  7.17 2.26 2.5 5.83 NA ...
 $ 1993          : num  7.02 2.28 2.52 6.03 NA ...
 $ 1994          : num  6.93 2.32 2.53 6.23 NA ...
 $ 1995          : num  6.91 2.37 2.54 6.43 NA ...
 $ 1996          : num  6.99 2.37 2.56 6.56 NA ...
 $ 1997          : num  7.09 2.36 2.57 6.68 NA ...
 $ 1998          : num  7.23 2.34 2.57 6.8 NA ...
 $ 1999          : num  7.39 2.32 2.57 6.92 NA ...
 $ 2000          : num  7.58 2.29 2.57 7.06 NA ...
 $ 2001          : num  7.76 2.27 2.57 7.31 NA ...
 $ 2002          : num  7.96 2.26 2.58 7.59 NA ...
 $ 2003          : num  8.17 2.24 2.57 7.89 NA ...
 $ 2004          : num  8.38 2.23 2.55 8.19 NA ...
 $ 2005          : num  8.59 2.23 2.53 8.5 NA ...
 $ 2006          : num  8.92 2.25 2.5 8.91 NA ...
 $ 2007          : num  9.23 2.27 2.47 9.32 NA ...
 $ 2008          : num  9.55 2.29 2.43 9.75 NA ...
 $ 2009          : num  9.89 2.31 2.39 10.19 NA ...
 $ 2010          : num  10.29 2.33 2.36 10.65 NA ...
 $ 2011          : num  10.58 2.35 2.35 11.01 NA ...
 $ 2012          : num  10.92 2.39 2.34 11.39 NA ...
 $ 2013          : num  11.3 2.42 2.32 11.77 NA ...
 $ 2014          : num  11.71 2.45 2.3 12.18 NA ...
 $ 2015          : num  12.14 2.48 2.28 12.63 NA ...
 $ 2016          : num  12.6 2.52 2.26 12.96 NA ...
 $ 2017          : num  13.07 2.55 2.24 13.33 NA ...
 $ 2018          : num  13.55 2.58 2.22 13.74 NA ...
 $ Region        : chr  "Latin America & Caribbean" "South Asia" "Sub-Saharan Africa" "Europe & Central Asia" ...
 $ IncomeGroup   : chr  "High income" "Low income" "Lower middle income" "Upper middle income" ...
 $ SpecialNotes  : chr  NA NA NA NA ...
 $ TableName     : chr  "Aruba" "Afghanistan" "Angola" "Albania" ...

As shown above we have 264 observation of 67 variables, it is also shows that we have numeric and character variables.

In this step we apply data type conversion to convert some character variables, they are IncomeGroup that is converted to ordered factor and label IncomeGroup by labels() function with argument ordered=TRUE and Region, Country Name, Country Code to factor.For Country Name and Country Code they will be order alphabetically.


total_population$`Country Name`<- factor(total_population$`Country Name`)

total_population$`Country Code`<- factor(total_population$`Country Code`)

total_population$Region <- factor(total_population$Region,
                                  levels=c('Latin America & Caribbean',
                                           'South Asia',
                                           'Sub-Saharan Africa',
                                           'Europe & Central Asia',
                                           'Middle East & North Africa',
                                           'East Asia & Pacific',
                                           'North America'))

total_population$IncomeGroup <- factor(total_population$IncomeGroup,
                                        levels=c('Low income',
                                                 'Lower middle income',
                                                 'Upper middle income',
                                                 'High income'),
                                        labels = c('Low',
                                                   'Lower middle',
                                                   'Upper middle',
                                                   'High'),
                                        ordered=TRUE)

To check data type conversion we can use is.factor() function and we select converted columns to see the data type and order.

is.factor(total_population$`Country Name`)
[1] TRUE
is.factor(total_population$`Country Code`)
[1] TRUE
is.factor(total_population$IncomeGroup)
[1] TRUE
is.factor(total_population$Region)
[1] TRUE
total_population[, c(1:2,64:65)]
NA

Tidy & Manipulate Data I

In order to make the data in a tidy Format we first exclude some columns that we do not need to work on them by using the following command.

total_pop <- total_population %>% dplyr::select(-(`Indicator Name`:`Indicator Code`),-(`Region`),-(`SpecialNotes`:`TableName`))
head(total_pop)
dim(total_pop)
[1] 264  62

As you can see we have multiple data type in our new data it include 62 variables and 264 observation they are Country Name,which is refers to country from all the world. Country Code, which is a short code indicating the name of the country from all the world. years from 1960:2018, refers to world population ages 65 and above between 1960 and 2018. IncomeGroup, which is refers to income classification of countries from all the world.

The data will be tidy if the following three interrelated rules are met: Every variable have its own column. Every observation have its own row. Every value have its own cell. In our case column names from 3 to 61 are values instead of variables, so to achieve that rules gather()function is used to transform data from wide to long format. In addition, convert variable(year) from double to integer is done using as.integer() function.

total_pop<- total_pop %>% 
  gather(key="Year", value ="Total_population", 3:61)


#Converting the data type of column "Year"

total_pop$Year <- as.integer(total_pop$Year)
head(total_pop)

Here we rename some colmuns name by apply the following command

total_pop <- rename(total_pop,
                    Country_Name=`Country Name`,
                    Country_Code=`Country Code`,
                    Income_Group=IncomeGroup) 

head(total_pop)

Tidy & Manipulate Data II

In order to create new variable called (Growth_2018) which is the percentage of a growth in Population ages 65 and above between 2017 and 2018 we use filter() to filter 2017 and 2018 observation, the formula shows below is used to calculate the values of Growth_2018, then the data is filtered out only for 2018.

# Filter rows with 2017 & 2018 
total_pop_2018<- total_pop %>% filter(Year==2018|Year==2017)
##Calculate populatin growth 2018
total_pop_growth_2018<- total_pop %>% filter(Year==2018|Year==2017) %>%
  group_by(Country_Code) %>% mutate(Growth_2018 = 
                                      ((Total_population/lag(Total_population) - 1) * 100)) %>% 
  filter(Year==2018) %>% dplyr::select(-(Year))  
head(total_pop_growth_2018)

Scan I

In this section, we will Scan the data for missing values, obvious errors and inconsistencies.

##To calculate the total missing value
sum(is.na(total_pop))
[1] 4256
## To sum mising value in each colmuns
colSums(is.na(total_pop))
    Country_Name     Country_Code     Income_Group             Year Total_population 
               0                0             2773                0             1483 

As you can note we have a huge number of missing value in two variables, so to deal with this problem we do several step. First, we replace missing value of Income_Group which is categorical variables with the mode as shown below. Secondly, for numerical variables Total_population, replacing missing value with mean of Total_population has been done by using this command.

Mode <- function (x, na.rm) {
    xtab <- table(x)
    xmode <- names(which(xtab == max(xtab)))
    if (length(xmode) > 1) xmode <- ">1 mode"
    return(xmode)
}

total_pop$Income_Group[is.na(total_pop$Income_Group)]<- Mode(total_pop$Income_Group, na.rm = TRUE)


total_pop$Total_population[is.na(total_pop$Total_population)] <- mean(total_pop$Total_population, na.rm = TRUE)
#To check if replacing missing value done successfuly
colSums(is.na(total_pop))
    Country_Name     Country_Code     Income_Group             Year Total_population 
               0                0                0                0                0 
sum(is.na(total_pop))
[1] 0

Here in a below codes we are going to identify the inconsistencies or special values using is.special function

#check input whether they are not infinite or NA unsing a fuction called is.special
is.special<- function(x){ 
  if(is.numeric(x)) !is.finite(x) else is.na(x) 
}
is.special<- function(x){
  if(is.numeric(x)) !is.finite(x) 
}

sum(is.special(total_pop))
[1] 0

There is no special values to deal with.

To check there is no more further missing values or inconsistencies we apply the following code

total_pop[!complete.cases(total_pop),]
total_pop

Scan II

In this section we only have Total_population as a numeric variable that needs to scan its outliers, so we are going to use box plot at the beginning to visualize the outliers, and then we will investigate the outliers by use z-score method.


total_pop$Total_population %>%  boxplot(main="Box Plot of total_pop Total_population", ylab="Total_population", col = "grey")

The box plot shows that Total_population has many outliers in the next step, z-score via scores() function has been used to extract outliers of Total_population.

z.scores <- total_pop$Total_population%>%  scores(type = "z")
# To find out about the variables
z.scores %>% summary()
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
-1.3821 -0.7359 -0.3562  0.0000  0.3128  5.2833 
# To identify  the locations of outliers in Total_population variable
which( abs(z.scores) >3 )
  [1] 10939 11203 11467 11470 11670 11731 11734 11934 11995 11998 12198 12259 12262 12462 12496 12523 12526 12726 12760 12787
 [21] 12790 12990 13024 13051 13054 13254 13288 13315 13318 13393 13484 13518 13531 13552 13579 13582 13608 13657 13686 13748
 [41] 13782 13795 13816 13843 13846 13872 13921 13950 14005 14012 14046 14059 14064 14066 14080 14090 14107 14110 14136 14185
 [61] 14214 14269 14276 14310 14313 14323 14326 14328 14330 14332 14344 14354 14371 14374 14398 14400 14449 14478 14533 14540
 [81] 14574 14577 14587 14589 14590 14592 14594 14596 14608 14618 14635 14638 14662 14664 14678 14713 14742 14797 14800 14804
[101] 14837 14838 14841 14851 14853 14854 14856 14858 14860 14872 14882 14899 14902 14926 14928 14942 14959 14977 15005 15006
[121] 15061 15064 15068 15084 15101 15102 15105 15115 15117 15118 15120 15122 15124 15136 15146 15148 15163 15166 15190 15192
[141] 15206 15223 15241 15245 15269 15270 15303 15325 15328 15332 15347 15348 15365 15366 15369 15379 15381 15382 15384 15386
[161] 15388 15392 15400 15410 15412 15427 15430 15454 15456 15470 15487 15503 15505 15509 15533 15534 15567
# To sum the  outliers according to the z-score
length (which( abs(z.scores) >3 ))
[1] 177

To treat the outliers capping method has been used to replace the outliers with the nearest neighbors which are not outliers as follow

# Define a function to cap the values outside the limits

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
}
# Take a subset of total_pop data using quantitative variables

Total_population_capped <- total_pop$Total_population %>% cap()
total_pop_sub <- total_pop %>%  dplyr::select(Total_population)

# Finde out descriptive statistics

summary(total_pop_sub)
 Total_population 
 Min.   : 0.6856  
 1st Qu.: 3.2927  
 Median : 4.8248  
 Mean   : 6.2617  
 3rd Qu.: 7.5238  
 Max.   :27.5764  
# Apply  function "cap" to a data frame

total_pop_capped <- sapply(total_pop_sub, FUN = cap)

# Check summary statistics again

summary(total_pop_capped)
 Total_population 
 Min.   : 0.6856  
 1st Qu.: 3.2927  
 Median : 4.8248  
 Mean   : 6.1667  
 3rd Qu.: 7.5238  
 Max.   :15.0069  
# To check if the  processing of  outlries has done successfully
total_pop_capped %>%  boxplot(main="Box Plot of total_pop Total_population", ylab="Total_population", col = "grey")

Transform

We used the Histogram to illustrate the distribution of the variable Total_population. it looks to be skewed to the right as you can see in the figure below. Therefore, we tried several ways to transform it. We have tried the sqrt(), BoxCox() and logarithm base e (ln). The most effective way to correct the right skewed was logarithm base e (ln) as shown in the second figure.

#Histogram of Total_population
hist(total_pop$Total_population , border="black",col="red",cex.main=0.95,cex.axis=0.7,cex.lab=0.95)

#Histogram of ln_Total_population
PT<-log(total_pop$Total_population )
hist(PT,border="black",col="red",cex.main=0.95,cex.axis=0.9,cex.lab=0.95)

LS0tCnRpdGxlOiAiTUFUSDIzNDkgU2VtZXN0ZXIgMiwgMjAxOSIKYXV0aG9yOiAiTm9yYWggQWxzaGFtbWFyaSAoMzY5MjU2OCkgLCBSYXNoYSBBc2hhcmFyaSAoMzY5MjU0OSkgLCBBc3NheWVsIEFsc3ViYWllKCAzNzQwMjg1MCkgIgpzdWJ0aXRsZTogQXNzaWdubWVudCAzCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAotLS0KdGhlIGZvbGxvd2luZyBSIHBhY2thZ2VzIGFyZSB1c2VkIGluIHRoaXMgcmVwb3J0CgojIyBSZXF1aXJlZCBwYWNrYWdlcyAKCmBgYHtyfQpsaWJyYXJ5KHJlYWRyKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShmb3JlaWduKQpsaWJyYXJ5KGdkYXRhKQpsaWJyYXJ5KHJ2ZXN0KQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KGRlZHVjdGl2ZSkKbGlicmFyeSh2YWxpZGF0ZSkKbGlicmFyeShIbWlzYykKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShvdXRsaWVycykKbGlicmFyeShNVk4pCmxpYnJhcnkoaW5mb3RoZW8pCmxpYnJhcnkoTUFTUykKbGlicmFyeShjYXJldCkKbGlicmFyeShrbml0cikKbGlicmFyeShnZ3Bsb3QyKQpgYGAKCiMjIEV4ZWN1dGl2ZSBTdW1tYXJ5IAoKVGhlIGRhdGEgdGhhdCB3ZSBoYXZlIHVzZWQgaW4gdGhpcyByZXBvcnQgdGFrZW4gZnJvbSh3b3JsZCBiYW5rKSBhbmQgaXQgaW5jbHVkZSB0aGUgd29ybGQgUG9wdWxhdGlvbiBhZ2VzIDY1IGFuZCBhYm92ZSBiZXR3ZWVuIDE5NjAgYW5kIDIwMTggYW5kIGluY29tZSBjbGFzc2lmaWNhdGlvbiBvZiBjb3VudHJpZXMgZm9yIDI2NCBvYnNlcnZhdGlvbi5UTyBkbyBmdXJ0aGVyIGRhdGEgcHJlcG9zc2Vzc2luZyB3ZSBkbyB0aGUgZm9sbG93aW5nIHN0ZXBzLkZpcnN0LHRoZSB0d28gZGF0YSBzZXQgd2FzIGltcG9ydGVkIGFuZCByZWFkIGluIFIgYW5kIHRoZW4gbWVyZ2UgdGhlbSBieSB1c2luZyBsZWZ0IGpvaW4oKSBmdW5jdGlvbiBpbnRvIG9uZSBkYXRhIHNldCB1c2luZyBjb3VudHJ5IGNvZGUgYXMgYSBjb21tb24gdmFyaWFibGUuVGhlbiwgd2UgY2hlY2sgdGhlIHN0cnVjdHVyZSBhbmQgYXR0cmlidXRlIG9mIHRoZSBkYXRhIHRoYXQgaGF2ZSBiZWVuIG1lcmdlZC4gQWZ0ZXIgdGhhdCwgdGhlIGRhdGEgdHlwZSBjb252ZXJzaW9uIGhhcyBkb25lIGZvciBzb21lIHZhcmlhYmxlcy4gVGhlbiwgaW4gb3JkZXIgdG8gbWFrZSB0aGUgZGF0YSBpbiBhIHRpZHkgRm9ybWF0IHdlIGZpcnN0IGV4Y2x1ZGUgc29tZSB1bm5lY2Vzc2FyeSBjb2x1bW5zIHRoZW4gdHJhbnNmb3JtIGRhdGEgc2V0IGZyb20gd2lkZSB0byBsb25nIGZvcm1hdCBoYXMgYmVlbiBkb25lIHdpdGggY29udmVydCBzb21lIGRhdGEgdHlwZS4gU3Vic2VxdWVudGx5LCBXZSB1c2VkIGFwcHJvcHJpYXRlIG1ldGhvZCB0byBkZWFsIHdpdGggbWlzc2luZyB2YWx1ZXMgYW5kIHNwZWNpYWwgdmFsdWVzLlRoZW4sIG91dGxpZXJzIGhhdmUgYmVlbiBpZGVudGlmaWVkIGJ5IHotc2NvcmUgbWV0aG9kIGFuZCB0cmVhdCBieSBjYXBwaW5nIG1ldGhvZC4gVGhlIGRpc3RyaWJ1dGlvbiBvZiBUb3RhbF9wb3B1bGF0aW9uIGhhcyBiZWVuIGNoZWNrZWQgYW5kIHRoZW4gbG9nYXJpdGhtIGJhc2UgZSAoTG4pIHRyYW5zZm9ybWF0aW9uIGhhcyBiZWVuIHVzZWQgdG8gY29ycmVjdCB0aGUgbm9ybWFsaXR5LgoKCiMjIERhdGEgCgpUaGUgZGF0YSBpcyB0YWtlbiBmcm9tICh3b3JsZCBiYW5rKSB3ZWJzaXRlLCB0aGUgdHdvIHRhYmxlIGNvbnRhaW4gbWFueSB2YXJpYWJsZXMgYW5kIG9ic2VydmF0aW9uClRoZSBmaXJzdCBkYXRhIChwb3B1bGF0aW9uKSBjb250YWluIDYzIHZhcmlhYmxlcyB0aGV5IGFyZSBDb3VudHJ5IE5hbWUsIENvdW50cnkgQ29kZSwgSW5kaWNhdG9yIE5hbWUsIEluZGljYXRvciBDb2RlIGFuZCAgeWVhcnMgZnJvbSAxOTYwIHRvIDIwMTggYW5kIDI2NCBvYnNlcnZhdGlvbi4gQW5kICB0aGUgc2Vjb25kIGRhdGEgKGluY29tZSkgY29udGFpbiA1IHZhcmlhYmxlcyB0aGV5IGFyZSBDb3VudHJ5IENvZGUsIFJlZ2lvbiwgSW5jb21lR3JvdXAsIFNwZWNpYWwgTm90ZXMgYW5kIFRhYmxlIE5hbWUgd2l0aCAyNjMgb2JzZXJ2YXRpb24ubGF0ZXIgYWZ0ZXIgam9pbiB0aGVtICB3ZSB3aWxsIGV4Y2x1ZGUgc29tZSBvZiB0aGVtIGFuZCB3b3JrIG9uIHRoZSBvbmx5IHRoYXQgd2UgYXJlIGludGVyZXN0ZWQgaW4gd2hpY2ggYXJlIDYyIHZhcmlhYmxlcyBhbmQgdGhlaXIgZGlzY3JpcGl0aW9uIGFzIGZvbGxvdyAKQ291bnRyeSBOYW1lLHdoaWNoIGlzICByZWZlcnMgdG8gY291bnRyeSBmcm9tIGFsbCB0aGUgd29ybGQuIApDb3VudHJ5IENvZGUsIHdoaWNoIGlzIGEgc2hvcnQgY29kZSBpbmRpY2F0aW5nIHRoZSBuYW1lIG9mIHRoZSBjb3VudHJ5IGZyb20gYWxsIHRoZSB3b3JsZC4KeWVhcnMgZnJvbSAxOTYwOjIwMTgsIHJlZmVycyB0byB3b3JsZCBwb3B1bGF0aW9uIGFnZXMgNjUgYW5kIGFib3ZlIGJldHdlZW4gMTk2MCBhbmQgMjAxOC4KSW5jb21lR3JvdXAsIHdoaWNoIGlzIHJlZmVycyB0byBpbmNvbWUgY2xhc3NpZmljYXRpb24gb2YgY291bnRyaWVzIGZyb20gYWxsIHRoZSB3b3JsZC4Kd2l0aCAyNjQgb2JzZXJ2YXRpb24gCgoKYGBge3J9CnNldHdkKCJ+L0Rlc2t0b3AvQVBJX1NQLlBPUC42NVVQLlRPLlpTX0RTMl9lbl9jc3ZfdjJfMzE5MTQ5ICIpCnBvcHVsYXRpb24gPC0gcmVhZF9jc3YoIkFQSV9TUC5QT1AuNjVVUC5UTy5aU19EUzJfZW5fY3N2X3YyXzMxOTE0OS5jc3YiKSAKaGVhZChwb3B1bGF0aW9uKQoKaW5jb21lIDwtIHJlYWRfY3N2KCJNZXRhZGF0YV9Db3VudHJ5X0FQSV9TUC5QT1AuNjVVUC5UTy5aU19EUzJfZW5fY3N2X3YyXzMxOTE0OS5jc3YiKQpoZWFkKGluY29tZSkKYGBgCgpXZSBoYXZlIGNvdW50cnkgY29kZSBhcyBhIGNvbW1vbiBjb2x1bW4gYmV0d2VlbiBQb3B1bGF0aW9uIGRhdGEgc2V0IGFuZCBpbmNvbWUgZGF0YSBzZXQsIHNvIHdlIHVzZSBjb3VudHJ5IGNvZGUgdG8gbWVyZ2UgYm90aCBkYXRhIHNldCBpbnRvIG9uZSBkYXRhIHNldCBieSB1c2luZyBsZWZ0IGpvaW4oKSBmdW5jdGlvbiBhbmQgdGhlbiBhcHBseSBoZWFkZXIgb2YgdG90YWxfcG9wdWxhdGlvbiBkYXRhIHRvIGNoZWNrIGlmIHRoZSBtZXJnZSBoYXMgZG9uZSBhcyBmb2xsb3dpbmcKCmBgYHtyfQp0b3RhbF9wb3B1bGF0aW9uIDwtIHBvcHVsYXRpb24gJT4lIGxlZnRfam9pbihpbmNvbWUsYnk9IkNvdW50cnkgQ29kZSIpCmhlYWQodG90YWxfcG9wdWxhdGlvbikKCmBgYAoKIyMgVW5kZXJzdGFuZCAKClRoZSBkaW0oKSBhbmQgc3RyKCkgZnVuY3Rpb25zIGhhdmUgYmVlbiB1c2VkICB0byBjaGVjayB0aGUgdGhlIGRpbWVuc2lvbnMgYW5kIHN0cnVjdHVyZSBvZiB0aGUgZGF0YSBzZXQuCgpgYGB7cn0KIyMgdG8gY2tlY2sgdGhlICB0aGUgZGltZW5zaW9ucyBvZiB0b3RhbF9wb3B1bGF0aW9uLApkaW0odG90YWxfcG9wdWxhdGlvbikKIyNJbiBvcmRlciB0byBjaGVjayB0ZSBzdHJ1Y3R1cmUgb2Ygb3VyIGRhdGEgc2V0IHdlIGNhbiBhcHBseSB0aGlzIGNvbW1hbmQsCnN0cih0b3RhbF9wb3B1bGF0aW9uKQpgYGAKCkFzIHNob3duIGFib3ZlIHdlIGhhdmUgMjY0IG9ic2VydmF0aW9uIG9mIDY3IHZhcmlhYmxlcywgaXQgaXMgYWxzbyBzaG93cyB0aGF0IHdlIGhhdmUgbnVtZXJpYyBhbmQgY2hhcmFjdGVyIHZhcmlhYmxlcy4KCgoKCkluIHRoaXMgc3RlcCB3ZSBhcHBseSBkYXRhIHR5cGUgY29udmVyc2lvbiB0byBjb252ZXJ0IHNvbWUgY2hhcmFjdGVyIHZhcmlhYmxlcywgdGhleSBhcmUgSW5jb21lR3JvdXAgdGhhdCBpcyBjb252ZXJ0ZWQgdG8gb3JkZXJlZCBmYWN0b3IgYW5kIGxhYmVsIEluY29tZUdyb3VwIGJ5IGxhYmVscygpIGZ1bmN0aW9uIHdpdGggYXJndW1lbnQgb3JkZXJlZD1UUlVFIGFuZCBSZWdpb24sIENvdW50cnkgTmFtZSwgQ291bnRyeSBDb2RlIHRvIGZhY3Rvci5Gb3IgQ291bnRyeSBOYW1lIGFuZCBDb3VudHJ5IENvZGUgdGhleSB3aWxsIGJlIG9yZGVyIGFscGhhYmV0aWNhbGx5LgpgYGB7cn0KCnRvdGFsX3BvcHVsYXRpb24kYENvdW50cnkgTmFtZWA8LSBmYWN0b3IodG90YWxfcG9wdWxhdGlvbiRgQ291bnRyeSBOYW1lYCkKCnRvdGFsX3BvcHVsYXRpb24kYENvdW50cnkgQ29kZWA8LSBmYWN0b3IodG90YWxfcG9wdWxhdGlvbiRgQ291bnRyeSBDb2RlYCkKCnRvdGFsX3BvcHVsYXRpb24kUmVnaW9uIDwtIGZhY3Rvcih0b3RhbF9wb3B1bGF0aW9uJFJlZ2lvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscz1jKCdMYXRpbiBBbWVyaWNhICYgQ2FyaWJiZWFuJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdTb3V0aCBBc2lhJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdTdWItU2FoYXJhbiBBZnJpY2EnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0V1cm9wZSAmIENlbnRyYWwgQXNpYScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnTWlkZGxlIEVhc3QgJiBOb3J0aCBBZnJpY2EnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0Vhc3QgQXNpYSAmIFBhY2lmaWMnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ05vcnRoIEFtZXJpY2EnKSkKCnRvdGFsX3BvcHVsYXRpb24kSW5jb21lR3JvdXAgPC0gZmFjdG9yKHRvdGFsX3BvcHVsYXRpb24kSW5jb21lR3JvdXAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHM9YygnTG93IGluY29tZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnTG93ZXIgbWlkZGxlIGluY29tZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnVXBwZXIgbWlkZGxlIGluY29tZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnSGlnaCBpbmNvbWUnKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoJ0xvdycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdMb3dlciBtaWRkbGUnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnVXBwZXIgbWlkZGxlJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0hpZ2gnKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVyZWQ9VFJVRSkKCgoKYGBgCgoKVG8gY2hlY2sgZGF0YSAgdHlwZSBjb252ZXJzaW9uIHdlIGNhbiB1c2UgaXMuZmFjdG9yKCkgZnVuY3Rpb24gYW5kIHdlIHNlbGVjdCBjb252ZXJ0ZWQgY29sdW1ucyB0byBzZWUgdGhlIGRhdGEgdHlwZSBhbmQgb3JkZXIuCmBgYHtyfQppcy5mYWN0b3IodG90YWxfcG9wdWxhdGlvbiRgQ291bnRyeSBOYW1lYCkKaXMuZmFjdG9yKHRvdGFsX3BvcHVsYXRpb24kYENvdW50cnkgQ29kZWApCmlzLmZhY3Rvcih0b3RhbF9wb3B1bGF0aW9uJEluY29tZUdyb3VwKQppcy5mYWN0b3IodG90YWxfcG9wdWxhdGlvbiRSZWdpb24pCnRvdGFsX3BvcHVsYXRpb25bLCBjKDE6Miw2NDo2NSldCgpgYGAKCiMjCVRpZHkgJiBNYW5pcHVsYXRlIERhdGEgSSAKCgpJbiBvcmRlciB0byBtYWtlIHRoZSBkYXRhIGluIGEgdGlkeSBGb3JtYXQgd2UgZmlyc3QgZXhjbHVkZSBzb21lIGNvbHVtbnMgdGhhdCB3ZSBkbyBub3QgbmVlZCB0byB3b3JrIG9uIHRoZW0gYnkgdXNpbmcgdGhlIGZvbGxvd2luZyBjb21tYW5kLgoKYGBge3J9CnRvdGFsX3BvcCA8LSB0b3RhbF9wb3B1bGF0aW9uICU+JSBkcGx5cjo6c2VsZWN0KC0oYEluZGljYXRvciBOYW1lYDpgSW5kaWNhdG9yIENvZGVgKSwtKGBSZWdpb25gKSwtKGBTcGVjaWFsTm90ZXNgOmBUYWJsZU5hbWVgKSkKaGVhZCh0b3RhbF9wb3ApCmRpbSh0b3RhbF9wb3ApCmBgYAoKQXMgeW91IGNhbiBzZWUgd2UgaGF2ZSBtdWx0aXBsZSBkYXRhIHR5cGUgaW4gb3VyIG5ldyBkYXRhIGl0IGluY2x1ZGUgNjIgdmFyaWFibGVzIGFuZCAyNjQgb2JzZXJ2YXRpb24gdGhleSBhcmUgCkNvdW50cnkgTmFtZSx3aGljaCBpcyAgcmVmZXJzIHRvIGNvdW50cnkgZnJvbSBhbGwgdGhlIHdvcmxkLiAKQ291bnRyeSBDb2RlLCB3aGljaCBpcyBhIHNob3J0IGNvZGUgaW5kaWNhdGluZyB0aGUgbmFtZSBvZiB0aGUgY291bnRyeSBmcm9tIGFsbCB0aGUgd29ybGQuCnllYXJzIGZyb20gMTk2MDoyMDE4LCByZWZlcnMgdG8gd29ybGQgcG9wdWxhdGlvbiBhZ2VzIDY1IGFuZCBhYm92ZSBiZXR3ZWVuIDE5NjAgYW5kIDIwMTguCkluY29tZUdyb3VwLCB3aGljaCBpcyByZWZlcnMgdG8gaW5jb21lIGNsYXNzaWZpY2F0aW9uIG9mIGNvdW50cmllcyBmcm9tIGFsbCB0aGUgd29ybGQuCgoKVGhlIGRhdGEgd2lsbCBiZSB0aWR5IGlmIHRoZSBmb2xsb3dpbmcgdGhyZWUgaW50ZXJyZWxhdGVkIHJ1bGVzIGFyZSBtZXQ6CkV2ZXJ5IHZhcmlhYmxlIGhhdmUgaXRzIG93biBjb2x1bW4uCkV2ZXJ5IG9ic2VydmF0aW9uIGhhdmUgaXRzIG93biByb3cuCkV2ZXJ5IHZhbHVlIGhhdmUgaXRzIG93biBjZWxsLgpJbiBvdXIgY2FzZSBjb2x1bW4gbmFtZXMgZnJvbSAzIHRvIDYxIGFyZSB2YWx1ZXMgaW5zdGVhZCBvZiB2YXJpYWJsZXMsIHNvIHRvIGFjaGlldmUgdGhhdCBydWxlcyBnYXRoZXIoKWZ1bmN0aW9uIGlzIHVzZWQgdG8gdHJhbnNmb3JtIGRhdGEgZnJvbSB3aWRlIHRvIGxvbmcgZm9ybWF0LgpJbiBhZGRpdGlvbiwgY29udmVydCB2YXJpYWJsZSh5ZWFyKSBmcm9tIGRvdWJsZSB0byBpbnRlZ2VyIGlzIGRvbmUgdXNpbmcgYXMuaW50ZWdlcigpIGZ1bmN0aW9uLgoKYGBge3J9CnRvdGFsX3BvcDwtIHRvdGFsX3BvcCAlPiUgCiAgZ2F0aGVyKGtleT0iWWVhciIsIHZhbHVlID0iVG90YWxfcG9wdWxhdGlvbiIsIDM6NjEpCgoKI0NvbnZlcnRpbmcgdGhlIGRhdGEgdHlwZSBvZiBjb2x1bW4gIlllYXIiCgp0b3RhbF9wb3AkWWVhciA8LSBhcy5pbnRlZ2VyKHRvdGFsX3BvcCRZZWFyKQpoZWFkKHRvdGFsX3BvcCkKYGBgCgpIZXJlIHdlIHJlbmFtZSBzb21lIGNvbG11bnMgbmFtZSBieSBhcHBseSB0aGUgZm9sbG93aW5nIGNvbW1hbmQKYGBge3J9CnRvdGFsX3BvcCA8LSByZW5hbWUodG90YWxfcG9wLAogICAgICAgICAgICAgICAgICAgIENvdW50cnlfTmFtZT1gQ291bnRyeSBOYW1lYCwKICAgICAgICAgICAgICAgICAgICBDb3VudHJ5X0NvZGU9YENvdW50cnkgQ29kZWAsCiAgICAgICAgICAgICAgICAgICAgSW5jb21lX0dyb3VwPUluY29tZUdyb3VwKSAKCmhlYWQodG90YWxfcG9wKQpgYGAKCiMjCVRpZHkgJiBNYW5pcHVsYXRlIERhdGEgSUkgCgpJbiBvcmRlciB0byBjcmVhdGUgbmV3IHZhcmlhYmxlIGNhbGxlZCAoR3Jvd3RoXzIwMTgpIHdoaWNoIGlzIHRoZSBwZXJjZW50YWdlIG9mIGEgZ3Jvd3RoIGluIFBvcHVsYXRpb24gYWdlcyA2NSBhbmQgYWJvdmUgYmV0d2VlbiAyMDE3IGFuZCAyMDE4IHdlIHVzZSBmaWx0ZXIoKSB0byBmaWx0ZXIgMjAxNyBhbmQgMjAxOCBvYnNlcnZhdGlvbiwgdGhlIGZvcm11bGEgc2hvd3MgYmVsb3cgaXMgdXNlZCB0byBjYWxjdWxhdGUgdGhlIHZhbHVlcyBvZiBHcm93dGhfMjAxOCwgdGhlbiB0aGUgZGF0YSBpcyBmaWx0ZXJlZCBvdXQgb25seSBmb3IgMjAxOC4KCmBgYHtyfQojIEZpbHRlciByb3dzIHdpdGggMjAxNyAmIDIwMTggCnRvdGFsX3BvcF8yMDE4PC0gdG90YWxfcG9wICU+JSBmaWx0ZXIoWWVhcj09MjAxOHxZZWFyPT0yMDE3KQojI0NhbGN1bGF0ZSBwb3B1bGF0aW4gZ3Jvd3RoIDIwMTgKdG90YWxfcG9wX2dyb3d0aF8yMDE4PC0gdG90YWxfcG9wICU+JSBmaWx0ZXIoWWVhcj09MjAxOHxZZWFyPT0yMDE3KSAlPiUKICBncm91cF9ieShDb3VudHJ5X0NvZGUpICU+JSBtdXRhdGUoR3Jvd3RoXzIwMTggPSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoKFRvdGFsX3BvcHVsYXRpb24vbGFnKFRvdGFsX3BvcHVsYXRpb24pIC0gMSkgKiAxMDApKSAlPiUgCiAgZmlsdGVyKFllYXI9PTIwMTgpICU+JSBkcGx5cjo6c2VsZWN0KC0oWWVhcikpICAKaGVhZCh0b3RhbF9wb3BfZ3Jvd3RoXzIwMTgpCmBgYAoKCiMjCVNjYW4gSSAKCkluIHRoaXMgc2VjdGlvbiwgd2Ugd2lsbCAgU2NhbiB0aGUgZGF0YSBmb3IgbWlzc2luZyB2YWx1ZXMsIG9idmlvdXMgZXJyb3JzIGFuZCAgaW5jb25zaXN0ZW5jaWVzLgoKYGBge3J9CiMjVG8gY2FsY3VsYXRlIHRoZSB0b3RhbCBtaXNzaW5nIHZhbHVlCnN1bShpcy5uYSh0b3RhbF9wb3ApKQpgYGAKCmBgYHtyfQojIyBUbyBzdW0gbWlzaW5nIHZhbHVlIGluIGVhY2ggY29sbXVucwpjb2xTdW1zKGlzLm5hKHRvdGFsX3BvcCkpCgpgYGAKCkFzIHlvdSBjYW4gbm90ZSB3ZSBoYXZlIGEgaHVnZSBudW1iZXIgb2YgbWlzc2luZyB2YWx1ZSBpbiB0d28gdmFyaWFibGVzLCBzbyB0byBkZWFsIHdpdGggdGhpcyBwcm9ibGVtIHdlIGRvIHNldmVyYWwgc3RlcC4KRmlyc3QsIHdlIHJlcGxhY2UgbWlzc2luZyB2YWx1ZSBvZiBJbmNvbWVfR3JvdXAgd2hpY2ggaXMgY2F0ZWdvcmljYWwgdmFyaWFibGVzIHdpdGggdGhlIG1vZGUgYXMgc2hvd24gYmVsb3cuIApTZWNvbmRseSwgZm9yIG51bWVyaWNhbCB2YXJpYWJsZXMgVG90YWxfcG9wdWxhdGlvbiwgcmVwbGFjaW5nICBtaXNzaW5nIHZhbHVlIHdpdGggbWVhbiBvZiBUb3RhbF9wb3B1bGF0aW9uIGhhcyBiZWVuIGRvbmUgYnkgdXNpbmcgdGhpcyBjb21tYW5kLgoKYGBge3J9Ck1vZGUgPC0gZnVuY3Rpb24gKHgsIG5hLnJtKSB7CiAgICB4dGFiIDwtIHRhYmxlKHgpCiAgICB4bW9kZSA8LSBuYW1lcyh3aGljaCh4dGFiID09IG1heCh4dGFiKSkpCiAgICBpZiAobGVuZ3RoKHhtb2RlKSA+IDEpIHhtb2RlIDwtICI+MSBtb2RlIgogICAgcmV0dXJuKHhtb2RlKQp9CgoKYGBgCgpgYGB7cn0KCnRvdGFsX3BvcCRJbmNvbWVfR3JvdXBbaXMubmEodG90YWxfcG9wJEluY29tZV9Hcm91cCldPC0gTW9kZSh0b3RhbF9wb3AkSW5jb21lX0dyb3VwLCBuYS5ybSA9IFRSVUUpCgoKdG90YWxfcG9wJFRvdGFsX3BvcHVsYXRpb25baXMubmEodG90YWxfcG9wJFRvdGFsX3BvcHVsYXRpb24pXSA8LSBtZWFuKHRvdGFsX3BvcCRUb3RhbF9wb3B1bGF0aW9uLCBuYS5ybSA9IFRSVUUpCgpgYGAKCmBgYHtyfQojVG8gY2hlY2sgaWYgcmVwbGFjaW5nIG1pc3NpbmcgdmFsdWUgZG9uZSBzdWNjZXNzZnVseQpjb2xTdW1zKGlzLm5hKHRvdGFsX3BvcCkpCnN1bShpcy5uYSh0b3RhbF9wb3ApKQpgYGAKCgpIZXJlIGluIGEgYmVsb3cgY29kZXMgd2UgYXJlIGdvaW5nICB0byBpZGVudGlmeSB0aGUgaW5jb25zaXN0ZW5jaWVzIG9yIHNwZWNpYWwgdmFsdWVzIHVzaW5nIGlzLnNwZWNpYWwgZnVuY3Rpb24KYGBge3J9CiNjaGVjayBpbnB1dCB3aGV0aGVyIHRoZXkgYXJlIG5vdCBpbmZpbml0ZSBvciBOQSB1bnNpbmcgYSBmdWN0aW9uIGNhbGxlZCBpcy5zcGVjaWFsCmlzLnNwZWNpYWw8LSBmdW5jdGlvbih4KXsgCiAgaWYoaXMubnVtZXJpYyh4KSkgIWlzLmZpbml0ZSh4KSBlbHNlIGlzLm5hKHgpIAp9CmlzLnNwZWNpYWw8LSBmdW5jdGlvbih4KXsKICBpZihpcy5udW1lcmljKHgpKSAhaXMuZmluaXRlKHgpIAp9CgpzdW0oaXMuc3BlY2lhbCh0b3RhbF9wb3ApKQoKCmBgYApUaGVyZSBpcyBubyBzcGVjaWFsIHZhbHVlcyB0byBkZWFsIHdpdGguCgoKClRvIGNoZWNrIHRoZXJlIGlzIG5vIG1vcmUgZnVydGhlciBtaXNzaW5nIHZhbHVlcyBvciBpbmNvbnNpc3RlbmNpZXMgd2UgYXBwbHkgdGhlIGZvbGxvd2luZyBjb2RlIApgYGB7cn0KdG90YWxfcG9wWyFjb21wbGV0ZS5jYXNlcyh0b3RhbF9wb3ApLF0KdG90YWxfcG9wCmBgYAoKIyMJU2NhbiBJSQoKSW4gdGhpcyBzZWN0aW9uIHdlIG9ubHkgaGF2ZSBUb3RhbF9wb3B1bGF0aW9uICBhcyBhIG51bWVyaWMgdmFyaWFibGUgdGhhdCBuZWVkcyB0byBzY2FuIGl0cyBvdXRsaWVycywgc28gd2UgYXJlIGdvaW5nIHRvIHVzZSBib3ggcGxvdCBhdCB0aGUgYmVnaW5uaW5nIHRvIHZpc3VhbGl6ZSB0aGUgb3V0bGllcnMsIGFuZCB0aGVuIHdlIHdpbGwgaW52ZXN0aWdhdGUgdGhlIG91dGxpZXJzIGJ5IHVzZSB6LXNjb3JlIG1ldGhvZC4KYGBge3J9Cgp0b3RhbF9wb3AkVG90YWxfcG9wdWxhdGlvbiAlPiUgIGJveHBsb3QobWFpbj0iQm94IFBsb3Qgb2YgdG90YWxfcG9wIFRvdGFsX3BvcHVsYXRpb24iLCB5bGFiPSJUb3RhbF9wb3B1bGF0aW9uIiwgY29sID0gImdyZXkiKQoKYGBgCgpUaGUgYm94IHBsb3Qgc2hvd3MgdGhhdCBUb3RhbF9wb3B1bGF0aW9uIGhhcyBtYW55IG91dGxpZXJzIGluIHRoZSBuZXh0IHN0ZXAsIHotc2NvcmUgdmlhIHNjb3JlcygpIGZ1bmN0aW9uIGhhcyBiZWVuIHVzZWQgdG8gZXh0cmFjdCBvdXRsaWVycyBvZiBUb3RhbF9wb3B1bGF0aW9uLgpgYGB7cn0Kei5zY29yZXMgPC0gdG90YWxfcG9wJFRvdGFsX3BvcHVsYXRpb24lPiUgIHNjb3Jlcyh0eXBlID0gInoiKQojIFRvIGZpbmQgb3V0IGFib3V0IHRoZSB2YXJpYWJsZXMKei5zY29yZXMgJT4lIHN1bW1hcnkoKQojIFRvIGlkZW50aWZ5ICB0aGUgbG9jYXRpb25zIG9mIG91dGxpZXJzIGluIFRvdGFsX3BvcHVsYXRpb24gdmFyaWFibGUKd2hpY2goIGFicyh6LnNjb3JlcykgPjMgKQojIFRvIHN1bSB0aGUgIG91dGxpZXJzIGFjY29yZGluZyB0byB0aGUgei1zY29yZQpsZW5ndGggKHdoaWNoKCBhYnMoei5zY29yZXMpID4zICkpCmBgYAoKVG8gdHJlYXQgdGhlIG91dGxpZXJzIGNhcHBpbmcgbWV0aG9kIGhhcyBiZWVuIHVzZWQgdG8gcmVwbGFjZSB0aGUgb3V0bGllcnMgd2l0aCB0aGUgbmVhcmVzdCBuZWlnaGJvcnMgd2hpY2ggYXJlIG5vdCBvdXRsaWVycyBhcyBmb2xsb3cKYGBge3J9CiMgRGVmaW5lIGEgZnVuY3Rpb24gdG8gY2FwIHRoZSB2YWx1ZXMgb3V0c2lkZSB0aGUgbGltaXRzCgpjYXAgPC0gZnVuY3Rpb24oeCl7CiAgICBxdWFudGlsZXMgPC0gcXVhbnRpbGUoIHgsIGMoLjA1LCAwLjI1LCAwLjc1LCAuOTUgKSApCiAgICB4WyB4IDwgcXVhbnRpbGVzWzJdIC0gMS41KklRUih4KSBdIDwtIHF1YW50aWxlc1sxXQogICAgeFsgeCA+IHF1YW50aWxlc1szXSArIDEuNSpJUVIoeCkgXSA8LSBxdWFudGlsZXNbNF0KICAgIHgKfQojIFRha2UgYSBzdWJzZXQgb2YgdG90YWxfcG9wIGRhdGEgdXNpbmcgcXVhbnRpdGF0aXZlIHZhcmlhYmxlcwoKVG90YWxfcG9wdWxhdGlvbl9jYXBwZWQgPC0gdG90YWxfcG9wJFRvdGFsX3BvcHVsYXRpb24gJT4lIGNhcCgpCnRvdGFsX3BvcF9zdWIgPC0gdG90YWxfcG9wICU+JSAgZHBseXI6OnNlbGVjdChUb3RhbF9wb3B1bGF0aW9uKQoKIyBGaW5kZSBvdXQgZGVzY3JpcHRpdmUgc3RhdGlzdGljcwoKc3VtbWFyeSh0b3RhbF9wb3Bfc3ViKQoKIyBBcHBseSAgZnVuY3Rpb24gImNhcCIgdG8gYSBkYXRhIGZyYW1lCgp0b3RhbF9wb3BfY2FwcGVkIDwtIHNhcHBseSh0b3RhbF9wb3Bfc3ViLCBGVU4gPSBjYXApCgojIENoZWNrIHN1bW1hcnkgc3RhdGlzdGljcyBhZ2FpbgoKc3VtbWFyeSh0b3RhbF9wb3BfY2FwcGVkKQojIFRvIGNoZWNrIGlmIHRoZSAgcHJvY2Vzc2luZyBvZiAgb3V0bHJpZXMgaGFzIGRvbmUgc3VjY2Vzc2Z1bGx5CnRvdGFsX3BvcF9jYXBwZWQgJT4lICBib3hwbG90KG1haW49IkJveCBQbG90IG9mIHRvdGFsX3BvcCBUb3RhbF9wb3B1bGF0aW9uIiwgeWxhYj0iVG90YWxfcG9wdWxhdGlvbiIsIGNvbCA9ICJncmV5IikKYGBgCgojIwlUcmFuc2Zvcm0gCldlIHVzZWQgdGhlICBIaXN0b2dyYW0gIHRvIGlsbHVzdHJhdGUgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgdmFyaWFibGUgVG90YWxfcG9wdWxhdGlvbi4gaXQgbG9va3MgdG8gYmUgIHNrZXdlZCB0byB0aGUgcmlnaHQgYXMgeW91IGNhbiBzZWUgaW4gdGhlIGZpZ3VyZSBiZWxvdy4gVGhlcmVmb3JlLCB3ZSB0cmllZCBzZXZlcmFsIHdheXMgdG8gdHJhbnNmb3JtICBpdC4gV2UgaGF2ZSAgdHJpZWQgdGhlIHNxcnQoKSwgQm94Q294KCkgIGFuZCBsb2dhcml0aG0gYmFzZSBlIChsbikuIFRoZSBtb3N0IGVmZmVjdGl2ZSB3YXkgdG8gY29ycmVjdCB0aGUgcmlnaHQgc2tld2VkIHdhcyBsb2dhcml0aG0gYmFzZSBlIChsbikgIGFzIHNob3duIGluIHRoZSBzZWNvbmQgZmlndXJlLgoKYGBge3J9CiNIaXN0b2dyYW0gb2YgVG90YWxfcG9wdWxhdGlvbgpoaXN0KHRvdGFsX3BvcCRUb3RhbF9wb3B1bGF0aW9uICwgYm9yZGVyPSJibGFjayIsY29sPSJyZWQiLGNleC5tYWluPTAuOTUsY2V4LmF4aXM9MC43LGNleC5sYWI9MC45NSkKYGBgCgoKIApgYGB7cn0KI0hpc3RvZ3JhbSBvZiBsbl9Ub3RhbF9wb3B1bGF0aW9uClBUPC1sb2codG90YWxfcG9wJFRvdGFsX3BvcHVsYXRpb24gKQpoaXN0KFBULGJvcmRlcj0iYmxhY2siLGNvbD0icmVkIixjZXgubWFpbj0wLjk1LGNleC5heGlzPTAuOSxjZXgubGFiPTAuOTUpCmBgYAoKCg==