Required packages

Load packages

library(readr) # Useful for importing data
library(readxl)
library(foreign) # Useful for importing SPSS, SAS, STATA etc. data files
library(gdata)
library(rvest) # Useful for scraping HTML data
library(dplyr)
library(tidyr)
library(deductive)
library(deducorrect)
library(editrules)
library(validate)
library(Hmisc)
library(forecast)
library(stringr)
library(lubridate)
library(car)
library(outliers)
library(MVN)
library(infotheo)
library(MASS)
library(caret)
library(mlr)
library(ggplot2)
library(knitr) # Useful for creating nice tables

Executive Summary

In economics, the Gini coefficient (/ˈdʒiːni/ JEE-nee), sometimes called the Gini index or Gini ratio, is a measure of statistical dispersion intended to represent the income or wealth distribution of a nation’s residents, and is the most commonly used measurement of inequality.
I decided to analyse what level of inequality exists in the family immigration stream for Australia. I obtained the immigration data from data.gov.au and the gini coefficient data from World bank.
Firstly, I joined the gini data with the gini metadata to form a gini dataset and I filtered it for the last 10 years. I then converted it to a long format, immigration data was also converted to long format to enable join. I adjusted the country names as they were inconsistent across the datasets.I imputed any missing values with a group average and analysed the immigration counts against the gini coefficients for different countries in the top 15 for family immigration stream.

Data

The datasets are open source and have been downloaded from teh following locations.
1. Australian Migration Statistics, 2009-2019 from data.gov.au

https://data.gov.au/dataset/ds-dga-dba45e7c-81f4-44aa-9d82-1b9a0a121017/distribution/dist-dga-afbf44d6-080b-48d1-bffb-093887ce9a65/details?q=
This data is in excel format and contains data in several worksheets. For this analysis, I chose to analyse “All other Family stream outcome and Child outcome visas—top 15 citizenship countries, Parent, Other Family and Child visas, 2009–10 to 2018–19” in worksheet “1.10”. Data is in a cross tab format, with Countries as column headers and yearwise migration numbers in rows.
2. GINI index (World Bank estimate)
https://data.worldbank.org/indicator/SI.POV.GINI
The data is downlaoded as a zip file, which contains two csv files inside, one with gini index for most countries in the world, from 1960 to 2018. A separate CSV file provides additional information for the countries, like region and income group.
The aim of the this analysis is to combine the GINI index data with the family stream migration data for the top 15 countries in Australia for 2009-2019, to understand, if GINI index is correlated with family migration.

Set working directory

#setwd('/Users/Sid/Desktop/RMIT/MATH2349/ass2/data') #set working directory to the path where datafile was saved
immigration_all_file <- "migration_trends_statistical_package_2018_19.xlsx"
gini_file <- "API_SI.POV.GINI_DS2_en_csv_v2_1120931.csv"
gini_metadata_file <- "Metadata_Country_API_SI.POV.GINI_DS2_en_csv_v2_1120931.csv"
immigration_all <- read_excel(immigration_all_file, range = "1.10!B6:S16")
head(immigration_all)

Read gini data

gini <- read_csv(gini_file, skip =4) # Gini Index data - skip 4 rows as these are not required
Missing column names filled in: 'X65' [65]Parsed with column specification:
cols(
  .default = col_double(),
  `Country Name` = col_character(),
  `Country Code` = col_character(),
  `Indicator Name` = col_character(),
  `Indicator Code` = col_character(),
  `1960` = col_logical(),
  `1961` = col_logical(),
  `1962` = col_logical(),
  `1963` = col_logical(),
  `1964` = col_logical(),
  `1965` = col_logical(),
  `1966` = col_logical(),
  `1968` = col_logical(),
  `1970` = col_logical(),
  `1972` = col_logical(),
  `1973` = col_logical(),
  `1976` = col_logical(),
  `1977` = col_logical(),
  `2019` = col_logical(),
  X65 = col_logical()
)
See spec(...) for full column specifications.
head(gini)

Read gini metadata

gini_meta <- read_csv(gini_metadata_file) # Gini metadata file providing information about the countries
Missing column names filled in: 'X6' [6]Parsed with column specification:
cols(
  `Country Code` = col_character(),
  Region = col_character(),
  IncomeGroup = col_character(),
  SpecialNotes = col_character(),
  TableName = col_character(),
  X6 = col_logical()
)
head(gini_meta)

Tidy & Manipulate Data I

Observations for the datasets.
1. Immigration data - UNTIDY, because columns are not variables, rather they are values for a country variable.
10 observations of 18 variables
2. gini index dataset has lots of missing data.
3. gini metadata dataset also has some missing data.
I will first convert the year columns for immigration data by splitting the column and then convert to a tidy dataset using the “separate” function in tidyr. I will also drop “New Zealand2”,“Other3”,“Total” columns as they are either summary columns or have missing data.

#Change the country names to make it consistent with both datasets.
names(immigration_all)[names(immigration_all)=="People's Republic of China"] <- "China"
names(immigration_all)[names(immigration_all)=="Hong Kong1"] <- "Hong Kong SAR, China"
names(immigration_all)[names(immigration_all)=="United States of America"] <- "United States"
names(immigration_all)[names(immigration_all)=="Iran"] <- "Iran, Islamic Rep."
immigration_all <- tidyr::separate(immigration_all,Year, c("Year", "Discard"))
immigration_all <- immigration_all[ , -which(names(immigration_all) %in% c("New Zealand2","Other3","Total","Discard"))]
immigration_subset <- gather(data =immigration_all, key = "country_name", "immi_count",2:15)

Immigration subset is now in long format with 140 observations across 3 variables

head(immigration_subset)

Firstly, the datasets will be subset to choose important variables and then joined.

#change variable names to remove spaces and to enable easy join
names(gini)[names(gini)=="Country Code"] <- "country_code"
names(gini)[names(gini)=="Country Name"] <- "country_name"
names(gini_meta)[names(gini_meta)=="Country Code"] <- "country_code"
gini_all <- gini %>% left_join(gini_meta, by = "country_code") # Use a left join to select metadata for all available countries

Subset the gini dataset to chose the variables of interest. I’m only interest in years 2009 - 2018. I laso choose region, income group and country information

colnames <- c("country_name","country_code","2009","2010","2011","2012","2013","2014","2015","2016","2017","2018","2019","Region","IncomeGroup")
gini_all <- gini_all[colnames]

Summary of the joined gini dataset

summary(gini_all)
 country_name       country_code            2009            2010            2011            2012            2013            2014      
 Length:264         Length:264         Min.   :24.80   Min.   :24.80   Min.   :24.60   Min.   :24.70   Min.   :24.60   Min.   :24.00  
 Class :character   Class :character   1st Qu.:31.20   1st Qu.:30.40   1st Qu.:30.23   1st Qu.:29.55   1st Qu.:30.77   1st Qu.:31.12  
 Mode  :character   Mode  :character   Median :35.40   Median :34.10   Median :34.15   Median :35.60   Median :36.20   Median :35.15  
                                       Mean   :37.58   Mean   :36.54   Mean   :36.20   Mean   :36.45   Mean   :36.54   Mean   :36.65  
                                       3rd Qu.:44.10   3rd Qu.:41.35   3rd Qu.:42.33   3rd Qu.:41.25   3rd Qu.:40.92   3rd Qu.:40.90  
                                       Max.   :61.00   Max.   :63.40   Max.   :56.20   Max.   :56.10   Max.   :52.80   Max.   :63.00  
                                       NA's   :187     NA's   :181     NA's   :188     NA's   :185     NA's   :188     NA's   :184    
      2015            2016            2017            2018         2019            Region          IncomeGroup       
 Min.   :25.40   Min.   :24.80   Min.   :24.20   Min.   :25.20   Mode:logical   Length:264         Length:264        
 1st Qu.:31.55   1st Qu.:31.12   1st Qu.:29.88   1st Qu.:35.70   NA's:264       Class :character   Class :character  
 Median :35.75   Median :35.10   Median :35.75   Median :40.55                  Mode  :character   Mode  :character  
 Mean   :36.81   Mean   :36.38   Mean   :36.17   Mean   :40.17                                                       
 3rd Qu.:41.12   3rd Qu.:41.52   3rd Qu.:41.10   3rd Qu.:45.60                                                       
 Max.   :59.10   Max.   :54.60   Max.   :56.30   Max.   :53.90                                                       
 NA's   :184     NA's   :188     NA's   :198     NA's   :236                                                         

As can be seen gini data is missing for most countries and years. These will be imputed later.

#Convert factor columns to factor
factor_cols <- c("country_code","Region")
gini_all[factor_cols] <- lapply(gini_all[factor_cols]  , factor)
gini_all$IncomeGroup <- factor(gini_all$IncomeGroup, levels = c("High income","Upper middle income","Lower middle income", "Low income")) # Ordered factor

Convert dataset to long format.

#gini_all is also an untidy dataset as year values are in column headers. Convert to long format to enable join.
gini_long <- gather(data =gini_all, key = "Year", "gini",3:13)

#Join immigration data to gini data
immi_gini <- left_join(immigration_subset, gini_long)
Joining, by = c("Year", "country_name")
factor_cols <- c("Year")
immi_gini[factor_cols] <- lapply(immi_gini[factor_cols]  , factor)

Understand

The joined dataset is as follows.

head(immi_gini)

Symmary of the processed dataset.

summary(immi_gini)
      Year    country_name         immi_count      country_code                        Region                IncomeGroup      gini      
 2009   :14   Length:140         Min.   :  54.0   CHN    :10    East Asia & Pacific       :70   High income        :30   Min.   :29.80  
 2010   :14   Class :character   1st Qu.: 170.8   GBR    :10    Europe & Central Asia     :10   Upper middle income:60   1st Qu.:36.10  
 2011   :14   Mode  :character   Median : 280.0   HKG    :10    Latin America & Caribbean : 0   Lower middle income:50   Median :39.10  
 2012   :14                      Mean   : 723.6   IDN    :10    Middle East & North Africa:10   Low income         : 0   Mean   :39.03  
 2013   :14                      3rd Qu.: 717.8   IND    :10    North America             :10                            3rd Qu.:41.00  
 2014   :14                      Max.   :5561.0   IRN    :10    South Asia                :30                            Max.   :63.40  
 (Other):56                                       (Other):80    Sub-Saharan Africa        :10                            NA's   :74     

As can be seen , I now have a dataframe with four factor variables (Year, Country_code, Region,IncomeGroup), two numeric(Immi_count, gini) and one character(Country_name) variable.

Scan I

Firstly, I check for any special values in the numeric variables.

# Check Immi_count variable for special values
is.finite(immi_gini$immi_count)
  [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
 [28] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
 [55] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
 [82] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[109] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[136] TRUE TRUE TRUE TRUE TRUE
is.infinite(immi_gini$immi_count)
  [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [24] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [47] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [70] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [93] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[116] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[139] FALSE FALSE
is.nan(immi_gini$immi_count)
  [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [24] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [47] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [70] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [93] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[116] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[139] FALSE FALSE

No special values or NaN values in the immigration count variable.

# Check Immi_count variable for special values
is.finite(immi_gini$gini)
  [1] FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE FALSE  TRUE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE FALSE
 [24]  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE  TRUE FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
 [47]  TRUE  TRUE FALSE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE FALSE
 [70] FALSE FALSE  TRUE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE
 [93] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE FALSE FALSE  TRUE  TRUE FALSE  TRUE
[116] FALSE  TRUE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE
[139]  TRUE FALSE
is.infinite(immi_gini$gini)
  [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [24] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [47] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [70] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [93] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[116] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[139] FALSE FALSE
is.nan(immi_gini$gini)
  [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [24] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [47] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [70] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [93] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[116] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[139] FALSE FALSE

No infinite values or NaN values, but there are NAs in the gini variable.

na_val <- sapply(immi_gini, function(x) sum(is.na(x))) #Check for NA values in the whole data frame
na_val
        Year country_name   immi_count country_code       Region  IncomeGroup         gini 
           0            0            0            0            0            0           74 
#Impute missing gini scores as average for the country
immi_gini$gini<- round(ave(immi_gini$gini,immi_gini$country_code,FUN=function(x) ifelse(is.na(x), mean(x,na.rm=TRUE), x)),2)
na_val <- sapply(immi_gini, function(x) sum(is.na(x)))
na_val
        Year country_name   immi_count country_code       Region  IncomeGroup         gini 
           0            0            0            0            0            0           10 
#I still have 10 missing values, which are for Hong Kong. As Hong Kong is a part of China, I impute the GINI values as a mean of China gini scores
immi_gini[which(immi_gini$country_code == "HKG"),]$gini <- Hmisc::impute(immi_gini[which(immi_gini$country_code == "CHN"),]$gini, fun = mean) 
na_val <- sapply(immi_gini, function(x) sum(is.na(x)))
na_val
        Year country_name   immi_count country_code       Region  IncomeGroup         gini 
           0            0            0            0            0            0            0 

The dataset is clean now.

Scan II

I now scan the numeric variables for outliers.

#outlier Detection using z-scores for immigration count
z_immig.scores <- immi_gini$immi_count %>%  scores(type = "z")
z_immig.scores %>% summary()
     Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
-0.553152 -0.456701 -0.366447  0.000000 -0.004809  3.996336 

Immigration numbers vary per year and there can be occurences where a particular country has a disproportionate value for immigration. Hence I chose not to discard this value.

immi_gini[ which( abs(z_immig.scores) >3 ) ,]$country_name
[1] "China" "China" "China" "China" "China" "China" "China" "China" "China"

China is represented disproportionately when it comes to immigration numbers in the family stream, when compared to other countries in top 15.

immi_gini$immi_count %>%  boxplot(main="Box Plot of Immigration Count", ylab="Immigration numbers", col = "Blue")

It can be seen that certain most of the countries within top 15 are sending less than 1000 persons to Australia per year, however, some countries have high immigration numbers. This is expected, hence I do not remove any values.

#outlier Detection using z-scores for gini
z.scores <- immi_gini$gini %>%  scores(type = "z")
z.scores %>% summary()
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
-1.4787 -0.4906 -0.1497  0.0000  0.1499  3.1488 
which( abs(z.scores) >3 )
 [1] 71 72 73 74 75 76 77 78 79 80
immi_gini[ which( abs(z.scores) >3 ) ,]$country_name
 [1] "South Africa" "South Africa" "South Africa" "South Africa" "South Africa" "South Africa" "South Africa" "South Africa" "South Africa"
[10] "South Africa"

Gini scores show an even spread, however, South Africa has a higher level of inequality amongst the top 15 countries in teh family migration stream.

Tidy & Manipulate Data II

Using mutate, create a new variable that is the average for the country.

z_gini <- immi_gini

z_gini$country_average_gini <- z_gini %>%
    group_by(country_code) %>%
    mutate(
        gini_mean = mean(gini)
    ) %>% ungroup %>% dplyr::select(gini_mean) %>% round(2)

This column can be used to compare how the immigration numbers are tracking against the mean gini coefficient, in each country, so we can analyse how immigration numbers are being affected by a change in the inequality score.

Transform

I scale and center the gini coefficient so that the trends in inequality can be easily identified. I then create a histogram and box plot to visualise the distribution.

# This is the R chunk for the Transform Section
z_gini$scaled_gini <- scale(z_gini$country_average_gini, center = TRUE, scale = TRUE)
hist(z_gini$scaled_gini,main = "Inequality trend for family migration for top 15 countries")

As can be seen, the inequality in the top 15 countries in the family immigration stream is generally declining. However, there is as slight increase in some countries, and South Africa has a high level of inequality and bucks the trend when compared to other countries.

##References

  1. How to import R data from excel sheet with multiple worksheets. Last accessed 6th June 2020.
    https://stackoverflow.com/questions/12945687/read-all-worksheets-in-an-excel-workbook-into-an-r-list-with-data-frames

  2. https://en.wikipedia.org/wiki/Gini_coefficient Last accessed 7th June 2020.
    In economics, the Gini coefficient (/ˈdʒiːni/ JEE-nee), sometimes called the Gini index or Gini ratio, is a measure of statistical dispersion intended to represent the income or wealth distribution of a nation’s residents, and is the most commonly used measurement of inequality. A Gini index value above 50 is considered high; countries including Brazil, Colombia, South Africa, Botswana, and Honduras can be found in this category. A Gini index value of 30 or above is considered medium; countries including Vietnam, Mexico, the United States, Argentina, Russia, and Uruguay can be found in this category. A Gini index value lower than 30 is considered low; countries including Austria, Germany, Denmark, Norway, Poland, Slovenia, Sweden, and Ukraine can be found in this category




LS0tCnRpdGxlOiAiTUFUSDIzNDkgU2VtZXN0ZXIgMSwgMjAyMCIKYXV0aG9yOiAiU0lESEFSVEggRGhhbmFuamF5YW4gczM4MDc5ODciCnN1YnRpdGxlOiBBc3NpZ25tZW50IDIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKLS0tCgojIyBSZXF1aXJlZCBwYWNrYWdlcyAKTG9hZCBwYWNrYWdlczxicj4KYGBge3J9CmxpYnJhcnkocmVhZHIpICMgVXNlZnVsIGZvciBpbXBvcnRpbmcgZGF0YQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShmb3JlaWduKSAjIFVzZWZ1bCBmb3IgaW1wb3J0aW5nIFNQU1MsIFNBUywgU1RBVEEgZXRjLiBkYXRhIGZpbGVzCmxpYnJhcnkoZ2RhdGEpCmxpYnJhcnkocnZlc3QpICMgVXNlZnVsIGZvciBzY3JhcGluZyBIVE1MIGRhdGEKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5cikKbGlicmFyeShkZWR1Y3RpdmUpCmxpYnJhcnkoZGVkdWNvcnJlY3QpCmxpYnJhcnkoZWRpdHJ1bGVzKQpsaWJyYXJ5KHZhbGlkYXRlKQpsaWJyYXJ5KEhtaXNjKQpsaWJyYXJ5KGZvcmVjYXN0KQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KGNhcikKbGlicmFyeShvdXRsaWVycykKbGlicmFyeShNVk4pCmxpYnJhcnkoaW5mb3RoZW8pCmxpYnJhcnkoTUFTUykKbGlicmFyeShjYXJldCkKbGlicmFyeShtbHIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShrbml0cikgIyBVc2VmdWwgZm9yIGNyZWF0aW5nIG5pY2UgdGFibGVzCmBgYAojIyBFeGVjdXRpdmUgU3VtbWFyeSAKCkluIGVjb25vbWljcywgdGhlIEdpbmkgY29lZmZpY2llbnQgKC/LiGTKkmnLkG5pLyBKRUUtbmVlKSwgc29tZXRpbWVzIGNhbGxlZCB0aGUgR2luaSBpbmRleCBvciBHaW5pIHJhdGlvLCBpcyBhIG1lYXN1cmUgb2Ygc3RhdGlzdGljYWwgZGlzcGVyc2lvbiBpbnRlbmRlZCB0byByZXByZXNlbnQgdGhlIGluY29tZSBvciB3ZWFsdGggZGlzdHJpYnV0aW9uIG9mIGEgbmF0aW9uJ3MgcmVzaWRlbnRzLCBhbmQgaXMgdGhlIG1vc3QgY29tbW9ubHkgdXNlZCBtZWFzdXJlbWVudCBvZiBpbmVxdWFsaXR5Ljxicj4KSSBkZWNpZGVkIHRvIGFuYWx5c2Ugd2hhdCBsZXZlbCBvZiBpbmVxdWFsaXR5IGV4aXN0cyBpbiB0aGUgZmFtaWx5IGltbWlncmF0aW9uIHN0cmVhbSBmb3IgQXVzdHJhbGlhLiBJIG9idGFpbmVkIHRoZSBpbW1pZ3JhdGlvbiBkYXRhIGZyb20gZGF0YS5nb3YuYXUgYW5kIHRoZSBnaW5pIGNvZWZmaWNpZW50IGRhdGEgZnJvbSBXb3JsZCBiYW5rLiA8YnI+CkZpcnN0bHksIEkgam9pbmVkIHRoZSBnaW5pIGRhdGEgd2l0aCB0aGUgZ2luaSBtZXRhZGF0YSB0byBmb3JtIGEgZ2luaSBkYXRhc2V0IGFuZCBJIGZpbHRlcmVkIGl0IGZvciB0aGUgbGFzdCAxMCB5ZWFycy4gSSB0aGVuIGNvbnZlcnRlZCBpdCB0byBhIGxvbmcgZm9ybWF0LCBpbW1pZ3JhdGlvbiBkYXRhIHdhcyBhbHNvIGNvbnZlcnRlZCB0byBsb25nIGZvcm1hdCB0byBlbmFibGUgam9pbi4gSSBhZGp1c3RlZCB0aGUgY291bnRyeSBuYW1lcyBhcyB0aGV5IHdlcmUgaW5jb25zaXN0ZW50IGFjcm9zcyB0aGUgZGF0YXNldHMuSSBpbXB1dGVkIGFueSBtaXNzaW5nIHZhbHVlcyB3aXRoIGEgZ3JvdXAgYXZlcmFnZSBhbmQgYW5hbHlzZWQgdGhlIGltbWlncmF0aW9uIGNvdW50cyBhZ2FpbnN0IHRoZSBnaW5pIGNvZWZmaWNpZW50cyBmb3IgZGlmZmVyZW50IGNvdW50cmllcyBpbiB0aGUgdG9wIDE1IGZvciBmYW1pbHkgaW1taWdyYXRpb24gc3RyZWFtLiA8YnI+CgojIyBEYXRhIApUaGUgZGF0YXNldHMgYXJlIG9wZW4gc291cmNlIGFuZCBoYXZlIGJlZW4gZG93bmxvYWRlZCBmcm9tIHRlaCBmb2xsb3dpbmcgbG9jYXRpb25zLjxicj4KMS4gQXVzdHJhbGlhbiBNaWdyYXRpb24gU3RhdGlzdGljcywgMjAwOS0yMDE5IGZyb20gZGF0YS5nb3YuYXU8YnI+ICAKaHR0cHM6Ly9kYXRhLmdvdi5hdS9kYXRhc2V0L2RzLWRnYS1kYmE0NWU3Yy04MWY0LTQ0YWEtOWQ4Mi0xYjlhMGExMjEwMTcvZGlzdHJpYnV0aW9uL2Rpc3QtZGdhLWFmYmY0NGQ2LTA4MGItNDhkMS1iZmZiLTA5Mzg4N2NlOWE2NS9kZXRhaWxzP3E9IDxicj4KVGhpcyBkYXRhIGlzIGluIGV4Y2VsIGZvcm1hdCBhbmQgY29udGFpbnMgZGF0YSBpbiBzZXZlcmFsIHdvcmtzaGVldHMuIEZvciB0aGlzIGFuYWx5c2lzLCBJIGNob3NlIHRvIGFuYWx5c2UgIkFsbCBvdGhlciBGYW1pbHkgc3RyZWFtIG91dGNvbWUgYW5kIENoaWxkIG91dGNvbWUgdmlzYXPigJR0b3AgMTUgY2l0aXplbnNoaXAgY291bnRyaWVzLCBQYXJlbnQsIE90aGVyIEZhbWlseSBhbmQgQ2hpbGQgdmlzYXMsIDIwMDnigJMxMCB0byAyMDE44oCTMTkiIGluIHdvcmtzaGVldCAiMS4xMCIuIERhdGEgaXMgaW4gYSBjcm9zcyB0YWIgZm9ybWF0LCB3aXRoIENvdW50cmllcyBhcyBjb2x1bW4gaGVhZGVycyBhbmQgeWVhcndpc2UgbWlncmF0aW9uIG51bWJlcnMgaW4gcm93cy48YnI+CjIuIEdJTkkgaW5kZXggKFdvcmxkIEJhbmsgZXN0aW1hdGUpPGJyPgpodHRwczovL2RhdGEud29ybGRiYW5rLm9yZy9pbmRpY2F0b3IvU0kuUE9WLkdJTkk8YnI+ClRoZSBkYXRhIGlzIGRvd25sYW9kZWQgYXMgYSB6aXAgZmlsZSwgd2hpY2ggY29udGFpbnMgdHdvIGNzdiBmaWxlcyBpbnNpZGUsIG9uZSB3aXRoIGdpbmkgaW5kZXggZm9yIG1vc3QgY291bnRyaWVzIGluIHRoZSB3b3JsZCwgZnJvbSAxOTYwIHRvIDIwMTguIEEgc2VwYXJhdGUgQ1NWIGZpbGUgcHJvdmlkZXMgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiBmb3IgdGhlIGNvdW50cmllcywgbGlrZSByZWdpb24gYW5kIGluY29tZSBncm91cC4gPGJyPgpUaGUgYWltIG9mIHRoZSB0aGlzIGFuYWx5c2lzIGlzIHRvIGNvbWJpbmUgdGhlIEdJTkkgaW5kZXggZGF0YSB3aXRoIHRoZSBmYW1pbHkgc3RyZWFtIG1pZ3JhdGlvbiBkYXRhIGZvciB0aGUgdG9wIDE1IGNvdW50cmllcyBpbiBBdXN0cmFsaWEgZm9yIDIwMDktMjAxOSwgdG8gdW5kZXJzdGFuZCwgaWYgR0lOSSBpbmRleCBpcyBjb3JyZWxhdGVkIHdpdGggZmFtaWx5IG1pZ3JhdGlvbi48YnI+CmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFLCBjYWNoZSA9VFJVRX0KcmVxdWlyZSgia25pdHIiKQojIyBzZXR0aW5nIHdvcmtpbmcgZGlyZWN0b3J5Cm9wdHNfa25pdCRzZXQocm9vdC5kaXIgPSAnfi9EZXNrdG9wL1JNSVQvTUFUSDIzNDkvYXNzMi9kYXRhJykKYGBgClNldCB3b3JraW5nIGRpcmVjdG9yeQpgYGB7ciBlY2hvPVRSVUV9CiNzZXR3ZCgnL1VzZXJzL1NpZC9EZXNrdG9wL1JNSVQvTUFUSDIzNDkvYXNzMi9kYXRhJykgI3NldCB3b3JraW5nIGRpcmVjdG9yeSB0byB0aGUgcGF0aCB3aGVyZSBkYXRhZmlsZSB3YXMgc2F2ZWQKaW1taWdyYXRpb25fYWxsX2ZpbGUgPC0gIm1pZ3JhdGlvbl90cmVuZHNfc3RhdGlzdGljYWxfcGFja2FnZV8yMDE4XzE5Lnhsc3giCmdpbmlfZmlsZSA8LSAiQVBJX1NJLlBPVi5HSU5JX0RTMl9lbl9jc3ZfdjJfMTEyMDkzMS5jc3YiCmdpbmlfbWV0YWRhdGFfZmlsZSA8LSAiTWV0YWRhdGFfQ291bnRyeV9BUElfU0kuUE9WLkdJTklfRFMyX2VuX2Nzdl92Ml8xMTIwOTMxLmNzdiIKaW1taWdyYXRpb25fYWxsIDwtIHJlYWRfZXhjZWwoaW1taWdyYXRpb25fYWxsX2ZpbGUsIHJhbmdlID0gIjEuMTAhQjY6UzE2IikKaGVhZChpbW1pZ3JhdGlvbl9hbGwpCmBgYApSZWFkIGdpbmkgZGF0YTxicj4KYGBge3IgZWNobz1UUlVFfQpnaW5pIDwtIHJlYWRfY3N2KGdpbmlfZmlsZSwgc2tpcCA9NCkgIyBHaW5pIEluZGV4IGRhdGEgLSBza2lwIDQgcm93cyBhcyB0aGVzZSBhcmUgbm90IHJlcXVpcmVkCmhlYWQoZ2luaSkKYGBgClJlYWQgZ2luaSBtZXRhZGF0YTxicj4KYGBge3IgZWNobz1UUlVFfQpnaW5pX21ldGEgPC0gcmVhZF9jc3YoZ2luaV9tZXRhZGF0YV9maWxlKSAjIEdpbmkgbWV0YWRhdGEgZmlsZSBwcm92aWRpbmcgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGNvdW50cmllcwpoZWFkKGdpbmlfbWV0YSkKYGBgCiMjCVRpZHkgJiBNYW5pcHVsYXRlIERhdGEgSSAKT2JzZXJ2YXRpb25zIGZvciB0aGUgZGF0YXNldHMuPGJyPgoxLiBJbW1pZ3JhdGlvbiBkYXRhIC0gVU5USURZLCAgYmVjYXVzZSBjb2x1bW5zIGFyZSBub3QgdmFyaWFibGVzLCByYXRoZXIgdGhleSBhcmUgdmFsdWVzIGZvciBhIGNvdW50cnkgdmFyaWFibGUuPGJyPgogIDEwIG9ic2VydmF0aW9ucyBvZiAxOCB2YXJpYWJsZXM8YnI+CjIuIGdpbmkgaW5kZXggZGF0YXNldCBoYXMgbG90cyBvZiBtaXNzaW5nIGRhdGEuPGJyPgozLiBnaW5pIG1ldGFkYXRhIGRhdGFzZXQgYWxzbyBoYXMgc29tZSBtaXNzaW5nIGRhdGEuPGJyPgpJIHdpbGwgZmlyc3QgY29udmVydCB0aGUgeWVhciBjb2x1bW5zIGZvciBpbW1pZ3JhdGlvbiBkYXRhIGJ5IHNwbGl0dGluZyB0aGUgY29sdW1uIGFuZCB0aGVuIGNvbnZlcnQgdG8gYSB0aWR5IGRhdGFzZXQgdXNpbmcgdGhlICJzZXBhcmF0ZSIgZnVuY3Rpb24gaW4gdGlkeXIuIEkgd2lsbCBhbHNvIGRyb3AgIk5ldyBaZWFsYW5kMiIsIk90aGVyMyIsIlRvdGFsIiBjb2x1bW5zIGFzIHRoZXkgYXJlIGVpdGhlciBzdW1tYXJ5IGNvbHVtbnMgb3IgaGF2ZSBtaXNzaW5nIGRhdGEuPGJyPgpgYGB7ciBlY2hvPVRSVUV9CiNDaGFuZ2UgdGhlIGNvdW50cnkgbmFtZXMgdG8gbWFrZSBpdCBjb25zaXN0ZW50IHdpdGggYm90aCBkYXRhc2V0cy4KbmFtZXMoaW1taWdyYXRpb25fYWxsKVtuYW1lcyhpbW1pZ3JhdGlvbl9hbGwpPT0iUGVvcGxlJ3MgUmVwdWJsaWMgb2YgQ2hpbmEiXSA8LSAiQ2hpbmEiCm5hbWVzKGltbWlncmF0aW9uX2FsbClbbmFtZXMoaW1taWdyYXRpb25fYWxsKT09IkhvbmcgS29uZzEiXSA8LSAiSG9uZyBLb25nIFNBUiwgQ2hpbmEiCm5hbWVzKGltbWlncmF0aW9uX2FsbClbbmFtZXMoaW1taWdyYXRpb25fYWxsKT09IlVuaXRlZCBTdGF0ZXMgb2YgQW1lcmljYSJdIDwtICJVbml0ZWQgU3RhdGVzIgpuYW1lcyhpbW1pZ3JhdGlvbl9hbGwpW25hbWVzKGltbWlncmF0aW9uX2FsbCk9PSJJcmFuIl0gPC0gIklyYW4sIElzbGFtaWMgUmVwLiIKaW1taWdyYXRpb25fYWxsIDwtIHRpZHlyOjpzZXBhcmF0ZShpbW1pZ3JhdGlvbl9hbGwsWWVhciwgYygiWWVhciIsICJEaXNjYXJkIikpCmltbWlncmF0aW9uX2FsbCA8LSBpbW1pZ3JhdGlvbl9hbGxbICwgLXdoaWNoKG5hbWVzKGltbWlncmF0aW9uX2FsbCkgJWluJSBjKCJOZXcgWmVhbGFuZDIiLCJPdGhlcjMiLCJUb3RhbCIsIkRpc2NhcmQiKSldCmltbWlncmF0aW9uX3N1YnNldCA8LSBnYXRoZXIoZGF0YSA9aW1taWdyYXRpb25fYWxsLCBrZXkgPSAiY291bnRyeV9uYW1lIiwgImltbWlfY291bnQiLDI6MTUpCmBgYApJbW1pZ3JhdGlvbiBzdWJzZXQgaXMgbm93IGluIGxvbmcgZm9ybWF0IHdpdGggMTQwIG9ic2VydmF0aW9ucyBhY3Jvc3MgMyB2YXJpYWJsZXM8YnI+CmBgYHtyIGVjaG89VFJVRX0KaGVhZChpbW1pZ3JhdGlvbl9zdWJzZXQpCmBgYApGaXJzdGx5LCB0aGUgZGF0YXNldHMgd2lsbCBiZSBzdWJzZXQgdG8gY2hvb3NlIGltcG9ydGFudCB2YXJpYWJsZXMgYW5kIHRoZW4gam9pbmVkLiA8YnI+CmBgYHtyIGVjaG89VFJVRX0KI2NoYW5nZSB2YXJpYWJsZSBuYW1lcyB0byByZW1vdmUgc3BhY2VzIGFuZCB0byBlbmFibGUgZWFzeSBqb2luCm5hbWVzKGdpbmkpW25hbWVzKGdpbmkpPT0iQ291bnRyeSBDb2RlIl0gPC0gImNvdW50cnlfY29kZSIKbmFtZXMoZ2luaSlbbmFtZXMoZ2luaSk9PSJDb3VudHJ5IE5hbWUiXSA8LSAiY291bnRyeV9uYW1lIgpuYW1lcyhnaW5pX21ldGEpW25hbWVzKGdpbmlfbWV0YSk9PSJDb3VudHJ5IENvZGUiXSA8LSAiY291bnRyeV9jb2RlIgpnaW5pX2FsbCA8LSBnaW5pICU+JSBsZWZ0X2pvaW4oZ2luaV9tZXRhLCBieSA9ICJjb3VudHJ5X2NvZGUiKSAjIFVzZSBhIGxlZnQgam9pbiB0byBzZWxlY3QgbWV0YWRhdGEgZm9yIGFsbCBhdmFpbGFibGUgY291bnRyaWVzCmBgYApTdWJzZXQgdGhlIGdpbmkgZGF0YXNldCB0byBjaG9zZSB0aGUgdmFyaWFibGVzIG9mIGludGVyZXN0LiBJJ20gb25seSBpbnRlcmVzdCBpbiB5ZWFycyAyMDA5IC0gMjAxOC4gSSBsYXNvIGNob29zZSByZWdpb24sIGluY29tZSBncm91cCBhbmQgY291bnRyeSBpbmZvcm1hdGlvbjxicj4KYGBge3IgZWNobz1UUlVFfQpjb2xuYW1lcyA8LSBjKCJjb3VudHJ5X25hbWUiLCJjb3VudHJ5X2NvZGUiLCIyMDA5IiwiMjAxMCIsIjIwMTEiLCIyMDEyIiwiMjAxMyIsIjIwMTQiLCIyMDE1IiwiMjAxNiIsIjIwMTciLCIyMDE4IiwiMjAxOSIsIlJlZ2lvbiIsIkluY29tZUdyb3VwIikKZ2luaV9hbGwgPC0gZ2luaV9hbGxbY29sbmFtZXNdCmBgYApTdW1tYXJ5IG9mIHRoZSBqb2luZWQgZ2luaSBkYXRhc2V0PGJyPgpgYGB7ciBlY2hvPVRSVUV9CnN1bW1hcnkoZ2luaV9hbGwpCmBgYApBcyBjYW4gYmUgc2VlbiBnaW5pIGRhdGEgaXMgbWlzc2luZyBmb3IgbW9zdCBjb3VudHJpZXMgYW5kIHllYXJzLiBUaGVzZSB3aWxsIGJlIGltcHV0ZWQgbGF0ZXIuPGJyPgpgYGB7ciBlY2hvPVRSVUV9CiNDb252ZXJ0IGZhY3RvciBjb2x1bW5zIHRvIGZhY3RvcgpmYWN0b3JfY29scyA8LSBjKCJjb3VudHJ5X2NvZGUiLCJSZWdpb24iKQpnaW5pX2FsbFtmYWN0b3JfY29sc10gPC0gbGFwcGx5KGdpbmlfYWxsW2ZhY3Rvcl9jb2xzXSAgLCBmYWN0b3IpCmdpbmlfYWxsJEluY29tZUdyb3VwIDwtIGZhY3RvcihnaW5pX2FsbCRJbmNvbWVHcm91cCwgbGV2ZWxzID0gYygiSGlnaCBpbmNvbWUiLCJVcHBlciBtaWRkbGUgaW5jb21lIiwiTG93ZXIgbWlkZGxlIGluY29tZSIsICJMb3cgaW5jb21lIikpICMgT3JkZXJlZCBmYWN0b3IKYGBgCkNvbnZlcnQgZGF0YXNldCB0byBsb25nIGZvcm1hdC48YnI+CmBgYHtyIGVjaG89VFJVRX0KI2dpbmlfYWxsIGlzIGFsc28gYW4gdW50aWR5IGRhdGFzZXQgYXMgeWVhciB2YWx1ZXMgYXJlIGluIGNvbHVtbiBoZWFkZXJzLiBDb252ZXJ0IHRvIGxvbmcgZm9ybWF0IHRvIGVuYWJsZSBqb2luLgpnaW5pX2xvbmcgPC0gZ2F0aGVyKGRhdGEgPWdpbmlfYWxsLCBrZXkgPSAiWWVhciIsICJnaW5pIiwzOjEzKQoKI0pvaW4gaW1taWdyYXRpb24gZGF0YSB0byBnaW5pIGRhdGEKaW1taV9naW5pIDwtIGxlZnRfam9pbihpbW1pZ3JhdGlvbl9zdWJzZXQsIGdpbmlfbG9uZykKZmFjdG9yX2NvbHMgPC0gYygiWWVhciIpCmltbWlfZ2luaVtmYWN0b3JfY29sc10gPC0gbGFwcGx5KGltbWlfZ2luaVtmYWN0b3JfY29sc10gICwgZmFjdG9yKQpgYGAKIyMgVW5kZXJzdGFuZCAKVGhlIGpvaW5lZCBkYXRhc2V0IGlzIGFzIGZvbGxvd3MuCmBgYHtyIGVjaG89VFJVRX0KaGVhZChpbW1pX2dpbmkpCmBgYApTeW1tYXJ5IG9mIHRoZSBwcm9jZXNzZWQgZGF0YXNldC48YnI+CmBgYHtyIGVjaG89VFJVRX0Kc3VtbWFyeShpbW1pX2dpbmkpCmBgYApBcyBjYW4gYmUgc2VlbiAsIEkgbm93IGhhdmUgYSBkYXRhZnJhbWUgd2l0aCBmb3VyIGZhY3RvciB2YXJpYWJsZXMgKFllYXIsIENvdW50cnlfY29kZSwgUmVnaW9uLEluY29tZUdyb3VwKSwgdHdvIG51bWVyaWMoSW1taV9jb3VudCwgZ2luaSkgYW5kIG9uZSBjaGFyYWN0ZXIoQ291bnRyeV9uYW1lKSB2YXJpYWJsZS48YnI+CgojIwlTY2FuIEkgCgpGaXJzdGx5LCBJIGNoZWNrIGZvciBhbnkgc3BlY2lhbCB2YWx1ZXMgaW4gdGhlIG51bWVyaWMgdmFyaWFibGVzLjxicj4KYGBge3IgZWNobz1UUlVFfQojIENoZWNrIEltbWlfY291bnQgdmFyaWFibGUgZm9yIHNwZWNpYWwgdmFsdWVzCmlzLmZpbml0ZShpbW1pX2dpbmkkaW1taV9jb3VudCkKaXMuaW5maW5pdGUoaW1taV9naW5pJGltbWlfY291bnQpCmlzLm5hbihpbW1pX2dpbmkkaW1taV9jb3VudCkKYGBgCk5vIHNwZWNpYWwgdmFsdWVzIG9yIE5hTiB2YWx1ZXMgaW4gdGhlIGltbWlncmF0aW9uIGNvdW50IHZhcmlhYmxlLjxicj4KYGBge3IgZWNobz1UUlVFfQojIENoZWNrIEltbWlfY291bnQgdmFyaWFibGUgZm9yIHNwZWNpYWwgdmFsdWVzCmlzLmZpbml0ZShpbW1pX2dpbmkkZ2luaSkKaXMuaW5maW5pdGUoaW1taV9naW5pJGdpbmkpCmlzLm5hbihpbW1pX2dpbmkkZ2luaSkKYGBgCk5vIGluZmluaXRlIHZhbHVlcyBvciBOYU4gdmFsdWVzLCBidXQgdGhlcmUgYXJlIE5BcyBpbiB0aGUgZ2luaSB2YXJpYWJsZS48YnI+CmBgYHtyIGVjaG89VFJVRX0KbmFfdmFsIDwtIHNhcHBseShpbW1pX2dpbmksIGZ1bmN0aW9uKHgpIHN1bShpcy5uYSh4KSkpICNDaGVjayBmb3IgTkEgdmFsdWVzIGluIHRoZSB3aG9sZSBkYXRhIGZyYW1lCm5hX3ZhbApgYGAKCmBgYHtyIGVjaG89VFJVRX0KI0ltcHV0ZSBtaXNzaW5nIGdpbmkgc2NvcmVzIGFzIGF2ZXJhZ2UgZm9yIHRoZSBjb3VudHJ5CmltbWlfZ2luaSRnaW5pPC0gcm91bmQoYXZlKGltbWlfZ2luaSRnaW5pLGltbWlfZ2luaSRjb3VudHJ5X2NvZGUsRlVOPWZ1bmN0aW9uKHgpIGlmZWxzZShpcy5uYSh4KSwgbWVhbih4LG5hLnJtPVRSVUUpLCB4KSksMikKbmFfdmFsIDwtIHNhcHBseShpbW1pX2dpbmksIGZ1bmN0aW9uKHgpIHN1bShpcy5uYSh4KSkpCm5hX3ZhbApgYGAKYGBge3IgZWNobz1UUlVFfQojSSBzdGlsbCBoYXZlIDEwIG1pc3NpbmcgdmFsdWVzLCB3aGljaCBhcmUgZm9yIEhvbmcgS29uZy4gQXMgSG9uZyBLb25nIGlzIGEgcGFydCBvZiBDaGluYSwgSSBpbXB1dGUgdGhlIEdJTkkgdmFsdWVzIGFzIGEgbWVhbiBvZiBDaGluYSBnaW5pIHNjb3JlcwppbW1pX2dpbmlbd2hpY2goaW1taV9naW5pJGNvdW50cnlfY29kZSA9PSAiSEtHIiksXSRnaW5pIDwtIEhtaXNjOjppbXB1dGUoaW1taV9naW5pW3doaWNoKGltbWlfZ2luaSRjb3VudHJ5X2NvZGUgPT0gIkNITiIpLF0kZ2luaSwgZnVuID0gbWVhbikgCm5hX3ZhbCA8LSBzYXBwbHkoaW1taV9naW5pLCBmdW5jdGlvbih4KSBzdW0oaXMubmEoeCkpKQpuYV92YWwKYGBgClRoZSBkYXRhc2V0IGlzIGNsZWFuIG5vdy48YnI+CgojIwlTY2FuIElJCgpJIG5vdyBzY2FuIHRoZSBudW1lcmljIHZhcmlhYmxlcyBmb3Igb3V0bGllcnMuPGJyPgpgYGB7ciBlY2hvPVRSVUV9CiNvdXRsaWVyIERldGVjdGlvbiB1c2luZyB6LXNjb3JlcyBmb3IgaW1taWdyYXRpb24gY291bnQKel9pbW1pZy5zY29yZXMgPC0gaW1taV9naW5pJGltbWlfY291bnQgJT4lICBzY29yZXModHlwZSA9ICJ6IikKel9pbW1pZy5zY29yZXMgJT4lIHN1bW1hcnkoKQpgYGAKSW1taWdyYXRpb24gbnVtYmVycyB2YXJ5IHBlciB5ZWFyIGFuZCB0aGVyZSBjYW4gYmUgb2NjdXJlbmNlcyB3aGVyZSBhIHBhcnRpY3VsYXIgY291bnRyeSBoYXMgYSBkaXNwcm9wb3J0aW9uYXRlIHZhbHVlIGZvciBpbW1pZ3JhdGlvbi4gSGVuY2UgSSBjaG9zZSBub3QgdG8gZGlzY2FyZCB0aGlzIHZhbHVlLjxicj4KYGBge3IgZWNobz1UUlVFfQppbW1pX2dpbmlbIHdoaWNoKCBhYnMoel9pbW1pZy5zY29yZXMpID4zICkgLF0kY291bnRyeV9uYW1lCmBgYApDaGluYSBpcyByZXByZXNlbnRlZCBkaXNwcm9wb3J0aW9uYXRlbHkgd2hlbiBpdCBjb21lcyB0byBpbW1pZ3JhdGlvbiBudW1iZXJzIGluIHRoZSBmYW1pbHkgc3RyZWFtLCB3aGVuIGNvbXBhcmVkIHRvIG90aGVyIGNvdW50cmllcyBpbiB0b3AgMTUuPGJyPgpgYGB7ciBlY2hvPVRSVUV9CmltbWlfZ2luaSRpbW1pX2NvdW50ICU+JSAgYm94cGxvdChtYWluPSJCb3ggUGxvdCBvZiBJbW1pZ3JhdGlvbiBDb3VudCIsIHlsYWI9IkltbWlncmF0aW9uIG51bWJlcnMiLCBjb2wgPSAiQmx1ZSIpCmBgYApJdCBjYW4gYmUgc2VlbiB0aGF0IGNlcnRhaW4gbW9zdCBvZiB0aGUgY291bnRyaWVzIHdpdGhpbiB0b3AgMTUgYXJlIHNlbmRpbmcgbGVzcyB0aGFuIDEwMDAgcGVyc29ucyB0byBBdXN0cmFsaWEgcGVyIHllYXIsIGhvd2V2ZXIsIHNvbWUgY291bnRyaWVzIGhhdmUgaGlnaCBpbW1pZ3JhdGlvbiBudW1iZXJzLiBUaGlzIGlzIGV4cGVjdGVkLCBoZW5jZSBJIGRvIG5vdCByZW1vdmUgYW55IHZhbHVlcy48YnI+CmBgYHtyIGVjaG89VFJVRX0KI291dGxpZXIgRGV0ZWN0aW9uIHVzaW5nIHotc2NvcmVzIGZvciBnaW5pCnouc2NvcmVzIDwtIGltbWlfZ2luaSRnaW5pICU+JSAgc2NvcmVzKHR5cGUgPSAieiIpCnouc2NvcmVzICU+JSBzdW1tYXJ5KCkKYGBgCmBgYHtyIGVjaG89VFJVRX0Kd2hpY2goIGFicyh6LnNjb3JlcykgPjMgKQppbW1pX2dpbmlbIHdoaWNoKCBhYnMoei5zY29yZXMpID4zICkgLF0kY291bnRyeV9uYW1lCmBgYApHaW5pIHNjb3JlcyBzaG93IGFuIGV2ZW4gc3ByZWFkLCBob3dldmVyLCBTb3V0aCBBZnJpY2EgaGFzIGEgaGlnaGVyIGxldmVsIG9mIGluZXF1YWxpdHkgYW1vbmdzdCB0aGUgdG9wIDE1IGNvdW50cmllcyBpbiB0ZWggZmFtaWx5IG1pZ3JhdGlvbiBzdHJlYW0uPGJyPgoKCiMjCVRpZHkgJiBNYW5pcHVsYXRlIERhdGEgSUkgCgpVc2luZyBtdXRhdGUsIGNyZWF0ZSBhIG5ldyB2YXJpYWJsZSB0aGF0IGlzIHRoZSBhdmVyYWdlIGZvciB0aGUgY291bnRyeS4KYGBge3IgZWNobz1UUlVFfQp6X2dpbmkgPC0gaW1taV9naW5pCgp6X2dpbmkkY291bnRyeV9hdmVyYWdlX2dpbmkgPC0gel9naW5pICU+JQogICAgZ3JvdXBfYnkoY291bnRyeV9jb2RlKSAlPiUKICAgIG11dGF0ZSgKICAgICAgICBnaW5pX21lYW4gPSBtZWFuKGdpbmkpCiAgICApICU+JSB1bmdyb3VwICU+JSBkcGx5cjo6c2VsZWN0KGdpbmlfbWVhbikgJT4lIHJvdW5kKDIpCmBgYApUaGlzIGNvbHVtbiBjYW4gYmUgdXNlZCB0byBjb21wYXJlIGhvdyB0aGUgaW1taWdyYXRpb24gbnVtYmVycyBhcmUgdHJhY2tpbmcgYWdhaW5zdCB0aGUgbWVhbiBnaW5pIGNvZWZmaWNpZW50LCBpbiBlYWNoIGNvdW50cnksIHNvIHdlIGNhbiBhbmFseXNlIGhvdyBpbW1pZ3JhdGlvbiBudW1iZXJzIGFyZSBiZWluZyBhZmZlY3RlZCBieSBhIGNoYW5nZSBpbiB0aGUgaW5lcXVhbGl0eSBzY29yZS48YnI+CgojIwlUcmFuc2Zvcm0gCgpJIHNjYWxlIGFuZCBjZW50ZXIgdGhlIGdpbmkgY29lZmZpY2llbnQgc28gdGhhdCB0aGUgdHJlbmRzIGluIGluZXF1YWxpdHkgY2FuIGJlIGVhc2lseSBpZGVudGlmaWVkLiBJIHRoZW4gY3JlYXRlIGEgaGlzdG9ncmFtIGFuZCBib3ggcGxvdCB0byB2aXN1YWxpc2UgdGhlIGRpc3RyaWJ1dGlvbi48YnI+CmBgYHtyIGVjaG89VFJVRX0Kel9naW5pJHNjYWxlZF9naW5pIDwtIHNjYWxlKHpfZ2luaSRjb3VudHJ5X2F2ZXJhZ2VfZ2luaSwgY2VudGVyID0gVFJVRSwgc2NhbGUgPSBUUlVFKQpoaXN0KHpfZ2luaSRzY2FsZWRfZ2luaSxtYWluID0gIkluZXF1YWxpdHkgdHJlbmQgZm9yIGZhbWlseSBtaWdyYXRpb24gZm9yIHRvcCAxNSBjb3VudHJpZXMiKQpgYGAKCkFzIGNhbiBiZSBzZWVuLCB0aGUgaW5lcXVhbGl0eSBpbiB0aGUgdG9wIDE1IGNvdW50cmllcyBpbiB0aGUgZmFtaWx5IGltbWlncmF0aW9uIHN0cmVhbSBpcyBnZW5lcmFsbHkgZGVjbGluaW5nLiBIb3dldmVyLCB0aGVyZSBpcyBhcyBzbGlnaHQgaW5jcmVhc2UgaW4gc29tZSBjb3VudHJpZXMsIGFuZCBTb3V0aCBBZnJpY2EgaGFzIGEgaGlnaCBsZXZlbCBvZiBpbmVxdWFsaXR5IGFuZCBidWNrcyB0aGUgdHJlbmQgd2hlbiBjb21wYXJlZCB0byBvdGhlciBjb3VudHJpZXMuCgojI1JlZmVyZW5jZXMgPGJyPgoKMS4gSG93IHRvIGltcG9ydCBSIGRhdGEgZnJvbSBleGNlbCBzaGVldCB3aXRoIG11bHRpcGxlIHdvcmtzaGVldHMuIExhc3QgYWNjZXNzZWQgNnRoIEp1bmUgMjAyMC4gPGJyPgpodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8xMjk0NTY4Ny9yZWFkLWFsbC13b3Jrc2hlZXRzLWluLWFuLWV4Y2VsLXdvcmtib29rLWludG8tYW4tci1saXN0LXdpdGgtZGF0YS1mcmFtZXMgPGJyPgoKMi4gaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvR2luaV9jb2VmZmljaWVudCAgTGFzdCBhY2Nlc3NlZCA3dGggSnVuZSAyMDIwLiA8YnI+CiAgSW4gZWNvbm9taWNzLCB0aGUgR2luaSBjb2VmZmljaWVudCAoL8uIZMqSacuQbmkvIEpFRS1uZWUpLCBzb21ldGltZXMgY2FsbGVkIHRoZSBHaW5pIGluZGV4IG9yIEdpbmkgcmF0aW8sIGlzIGEgbWVhc3VyZSBvZiBzdGF0aXN0aWNhbCBkaXNwZXJzaW9uIGludGVuZGVkIHRvIHJlcHJlc2VudCB0aGUgaW5jb21lIG9yIHdlYWx0aCBkaXN0cmlidXRpb24gb2YgYSBuYXRpb24ncyByZXNpZGVudHMsIGFuZCBpcyB0aGUgbW9zdCBjb21tb25seSB1c2VkIG1lYXN1cmVtZW50IG9mIGluZXF1YWxpdHkuCkEgR2luaSBpbmRleCB2YWx1ZSBhYm92ZSA1MCBpcyBjb25zaWRlcmVkIGhpZ2g7IGNvdW50cmllcyBpbmNsdWRpbmcgQnJhemlsLCBDb2xvbWJpYSwgU291dGggQWZyaWNhLCBCb3Rzd2FuYSwgYW5kIEhvbmR1cmFzIGNhbiBiZSBmb3VuZCBpbiB0aGlzIGNhdGVnb3J5LiBBIEdpbmkgaW5kZXggdmFsdWUgb2YgMzAgb3IgYWJvdmUgaXMgY29uc2lkZXJlZCBtZWRpdW07IGNvdW50cmllcyBpbmNsdWRpbmcgVmlldG5hbSwgTWV4aWNvLCB0aGUgVW5pdGVkIFN0YXRlcywgQXJnZW50aW5hLCBSdXNzaWEsIGFuZCBVcnVndWF5IGNhbiBiZSBmb3VuZCBpbiB0aGlzIGNhdGVnb3J5LiBBIEdpbmkgaW5kZXggdmFsdWUgbG93ZXIgdGhhbiAzMCBpcyBjb25zaWRlcmVkIGxvdzsgY291bnRyaWVzIGluY2x1ZGluZyBBdXN0cmlhLCBHZXJtYW55LCBEZW5tYXJrLCBOb3J3YXksIFBvbGFuZCwgU2xvdmVuaWEsIFN3ZWRlbiwgYW5kIFVrcmFpbmUgY2FuIGJlIGZvdW5kIGluIHRoaXMgY2F0ZWdvcnkKCgo8YnI+Cjxicj4KPGJyPgo=