Required packages
# Load required packages
library(readr)
library(tidyr)
library(dplyr)
library(stringr)
library(outliers)
library(ggplot2)
library(forecast)
Custom functions
- is.special returns TRUE if x is either an infinite value or not a number, FALSE otherwise.
- is.specialorNA returns TRUE if x is either an infinite value, not a number or a missing value, FALSE otherwise.
is.special <- function(x){
if (is.numeric(x)) (is.infinite(x) | is.nan(x))
}
is.specialorNA <- function(x){
if (is.numeric(x)) (is.infinite(x) | is.nan(x) | is.na(x))
}
Executive Summary
Data for analysis of Carbon emissions from nations across the years 1995 to 2016, along with nations vulnerability to climate change, was prepared.
3 datasets from two sources were obtained and imported for preparation: Emissions from CDIAC; NDGain (Vulnerability) and Population from NDGAI.
The country names from the datasets were cleaned up / standardised in preparation for the merge of sets. Country name is a join column.
Subsetting of data was conducted: Ony those countries with complete set of NDGain indices were considered. And Data for years 1995 to 2016 were considered.
Datasets for NDGain and population were made into tidy datasets.
All 3 datasets were merged.
The resulting dataset was inspected to understand the structure , datatypes, and the necessary conversions to factors, numeric datatypes were conducted.
New variable included: All emissions total, using total carbon emissions and bunker fuel emissions.
Scanning and dealing with missing values, special values, errors.
Scanning and dealing with outliers.
Transformation of total carbon emissions (tot_co2_emi) and population (Population) distributions to normal distributions.
Data
Source descriptions
Carbon emissions data (nation.1751_2016.csv) from Carbon Dioxide Information Analysis Center
Dataset of different carbon emissions by countries across the years with the following variables.
Nation - name of country to which emissions pertain to.
Year - year in which emissions occurred.
tot_co2_emi - Total CO2 emissions from fossil-fuels (solid, liquid, gas,flaring) and cement production. In thousand metric tons of C.
solid_cons - Emissions from solid fuel consumption.
liquid_cons - Emissions from liquid fuel consumption.
gas_cons - Emissions from gas fuel consumption.
cement_prod - Emissions from cement production.
gas_flare - Emissions from gas flaring.
cap_co2_emi - Per capita CO2 emissions (metric tons of carbon).
bunker_cons - Emissions from bunker fuels (not included in the totals). Emissions from fuel used for international aviation and maritime transport. Convention and protocol dictate these emissions are not included in national totals (tot_co2_emi).
NDGain Index data (gain.csv) from the Notre Dame Global Adaptation Initiative
Data set of NDGain index (vulnerability to climate change) for each country across the years, with the following variables.
This index is based on numerous (quantitative) indicators eg economic and governance readiness to adapt to change , and exposure to negative impacts.
The smaller the index, the more vulnerable to climate change is the nation.
ISO3 - 3 character ISO 3166 coding of country.
Name - Name of country to which the NDGain Index pertains to.
1995 - NDGain index for year 1995.
Indices for subsequent years, through to 2018, are provided as seperate variables.
Population data (input.csv) from the Notre Dame Global Adaptation Initiative
Data set of human population for each country across the years, with the following variables.
ISO3 - 3 character ISO 3166 coding of country.
Name - Name of country to which the population pertains to.
1995 - population for year 1995.
Population for subsequent years, through to 2018, are provided as seperate variables.
Tidy & Manipulate Data I
The NDGain dataset (gain) is not tidy as it has values for variable year as column names (1995, 1996 …). And the observations for each year are on one row. The year needs to be along a column , and each observation on a seperate row.
The same applies to the population dataset (pop): values for variable year as column names (1995, 1996 …). And the observations for each year are on one row. The year needs to be along a column , and each observation on a seperate row.
To make the datasets tidy the following steps are conducted.
- Make the data set longer using pivot_longer() where the years 1995, 1996 etc are moved to column “Year”, and the values to column “NDGain” for gain , “Population” for population.
#Make gain dataset tidy
gain_tidy <- gain_nation %>% pivot_longer(cols = -(1:2), names_to = "Year", values_to = "NDGain")
#Convert Year to integer
gain_tidy$Year <- as.integer(gain_tidy$Year)
#Make population dataset tidy
pop_tidy <- pop %>% pivot_longer(cols = -(1), names_to = "Year", values_to = "Population")
#Convert Year to integer
pop_tidy$Year <- as.integer(pop_tidy$Year)
# Show tidy gain dataset
head(gain_tidy)
# Show tidy population dataset
head(pop_tidy)
Merge data sets
The gain and population data sets are then merged together (gain_tidy) by ISO3 and Year.
The final dataset (emigain) is the result of the merge of the tidy gain dataset(gain_tidy) and emissions dataset(c_emi_nation) by Nation/Name and Year.
#left join gain and population sets together on ISO3 and Year
gain_tidy <- gain_tidy %>% left_join(pop_tidy, by = c("ISO3" = "ISO3", "Year" = "Year"))
#merge gain and emissions datasets together
emigain <- gain_tidy %>% inner_join(c_emi_nation , by = c("Name" = "Nation", "Year" = "Year") )
Understand
The emigain dataset is a dataframe of dimension 3887 x 13 (13 variables, 3887 observations).
Variables, their data type and any type conversions are as follows.
- ISO3: character datatype. Will be converted to factor. Country is categorical.
- Name: character datatype. Will be converted to factor. Country is categorical.
- Year: numeric datatype. Will be converted to ordered factor. Year is ordinal.
- NDGain: numeric datatype. No conversion.
- Population: numeric datatype. No conversion.
- tot_co2_emi: numeric datatype. No conversion.
- solid_cons: numeric datatype. No conversion.
- liquid_cons: numeric datatype. No conversion.
- gas_cons: numeric datatype. No conversion.
- cement_prod: numeric datatype. No conversion.
- gas_flare: character datatype. Will be converted to numeric(double) datatype. This is an emissions variable so continuous/rational.
- cap_co2_emi: character datatype. Will be converted to numeric(double) datatype. This is an emissions variable so continuous/rational.
- bunker_cons: numeric datatype. No conversion.
# Understand the data and structure
emigain %>% str()
tibble [3,887 x 13] (S3: tbl_df/tbl/data.frame)
$ ISO3 : chr [1:3887] "AFG" "AFG" "AFG" "AFG" ...
$ Name : chr [1:3887] "AFGHANISTAN" "AFGHANISTAN" "AFGHANISTAN" "AFGHANISTAN" ...
$ Year : num [1:3887] 1995 1996 1997 1998 1999 ...
$ NDGain : num [1:3887] 34.3 34.3 34.3 34.5 34.5 ...
$ Population : num [1:3887] 18110657 18853437 19357126 19737765 20170844 ...
$ tot_co2_emi: num [1:3887] 339 321 299 284 224 211 223 292 331 250 ...
$ solid_cons : num [1:3887] 4 2 1 1 1 1 19 15 25 25 ...
$ liquid_cons: num [1:3887] 225 213 198 188 135 136 134 120 169 153 ...
$ gas_cons : num [1:3887] 88 84 77 72 66 61 57 149 127 62 ...
$ cement_prod: num [1:3887] 16 16 16 16 16 7 7 8 10 10 ...
$ gas_flare : chr [1:3887] "6" "6" "6" "6" ...
$ cap_co2_emi: chr [1:3887] "0.02" "0.02" "0.02" "0.01" ...
$ bunker_cons: num [1:3887] 4 4 4 4 4 4 4 4 7 9 ...
The conversion to factor is done via the factor() function. No labelling is required this time.
For the ordered factor (Year), the factor() function is used along with parameters levels = [vector of ordered years] and ordered=TRUE.
The conversion of the two emissions (gas_flare, cap_co2_emi) from character to numeric double is completed using the conversion function as.double().
#ISO3 as factor
emigain$ISO3 <- emigain$ISO3 %>% factor()
#Name as factor
emigain$Name <- emigain$Name %>% factor()
#Name as factor
emigain$Name <- emigain$Name %>% factor()
#Year as order factor
#emigain$Year %>% unique()
emigain$Year <- emigain$Year %>% factor(levels = c(1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016), ordered = TRUE)
#gas_flare & cap_co2_emi
emigain$gas_flare <- emigain$gas_flare %>% as.double()
emigain$cap_co2_emi <- emigain$cap_co2_emi %>% as.double()
NAs introduced by coercion
After the necessary conversions, inspecting the resulting data types below show the 3 factors, one ordered, and all emission variables are numeric.
emigain %>% str()
tibble [3,887 x 13] (S3: tbl_df/tbl/data.frame)
$ ISO3 : Factor w/ 178 levels "AFG","AGO","ALB",..: 1 1 1 1 1 1 1 1 1 1 ...
$ Name : Factor w/ 178 levels "AFGHANISTAN",..: 1 1 1 1 1 1 1 1 1 1 ...
$ Year : Ord.factor w/ 22 levels "1995"<"1996"<..: 1 2 3 4 5 6 7 8 9 10 ...
$ NDGain : num [1:3887] 34.3 34.3 34.3 34.5 34.5 ...
$ Population : num [1:3887] 18110657 18853437 19357126 19737765 20170844 ...
$ tot_co2_emi: num [1:3887] 339 321 299 284 224 211 223 292 331 250 ...
$ solid_cons : num [1:3887] 4 2 1 1 1 1 19 15 25 25 ...
$ liquid_cons: num [1:3887] 225 213 198 188 135 136 134 120 169 153 ...
$ gas_cons : num [1:3887] 88 84 77 72 66 61 57 149 127 62 ...
$ cement_prod: num [1:3887] 16 16 16 16 16 7 7 8 10 10 ...
$ gas_flare : num [1:3887] 6 6 6 6 6 6 6 0 0 0 ...
$ cap_co2_emi: num [1:3887] 0.02 0.02 0.02 0.01 0.01 0.01 0.01 0.01 0.01 0.01 ...
$ bunker_cons: num [1:3887] 4 4 4 4 4 4 4 4 7 9 ...
Tidy & Manipulate Data II
Addition of variable all_co2_emi
This variable is the total of ALL emissions, including those from bunker(international aviation and maritime) fuel.
Long standing convention/protocol states that bunker emissions are excluded from nation reporting. Historically hard to attribute to country. Source country? Desintation? etc.
It’s handy to have this variable as it gives a better picture of emissions. Why exclude another source of carbon emissions?
As total emissions (tot_co2_emi) is provided, add bunker emissions to this.
all_co2_emi = tot_co2_emi + bunker_cons
The variable is inclued in the emigain dataset via the mutate function, where it is derived using the indicated formula.
#Add all_co2_emi variable - total co2 emissions + bunker emissions.
emigain <- emigain %>% mutate(
all_co2_emi = tot_co2_emi + bunker_cons
)
#Inspect variable structure
emigain$all_co2_emi %>% str()
num [1:3887] 343 325 303 288 228 215 227 296 338 259 ...
Scan I
Scanning and dealing with missing values, special values, errors
Missing values either through merging of datasets (Population) or as literals ‘.’ , ‘..’ were standardised to R’s NA.
gas_flare/cap_co2_emi conversion to numeric coerced the ‘.’/‘..’ to NA.
Complete cases in emigain, across numeric variables (4:14), were examined. ISO3/Name/Year (1:3) were ignored as they are join columns.
Column counts of missing values reveal that missing values are confined to Population and cap_co2_emi.
Verifying the records where there are missing values for either Population or cap_co2_emi, show that they can easily be imputed.
Impute using formula ‘carbon emission per capita’ = ‘total carbon emission’ x 1000 / population
cap_co2_emi = tot_co2_emi x 1000 / Population
Scan for missing values
Summary of missing values show
#Get incomplete cases to check against post impute
emigain_notc2 <- emigain[!complete.cases(emigain[, 4:14]),]
#Scan for NAs in data set
colSums(is.na(emigain))
ISO3 Name Year NDGain Population tot_co2_emi solid_cons liquid_cons gas_cons cement_prod gas_flare cap_co2_emi bunker_cons
0 0 0 0 22 0 0 0 0 0 0 17 0
all_co2_emi
0
Show samples of records with missing values
#Check Population NAs
emigain[is.na(emigain$Population),] %>% head(5)
#Check cap_co2_emi NAs
emigain[is.na(emigain$cap_co2_emi),] %>% head(5)
NA
Impute missing values
Impute missing population and per capita emission based on formula above.
Checking imputation by looking up results against incomplete case dataset (emigain_notc2) show that the imputations are correct.
#Impute missing population
emigain$Population[is.na(emigain$Population)] <- emigain$tot_co2_emi[is.na(emigain$Population)] * 1000 / emigain$cap_co2_emi[is.na(emigain$Population)]
#Impute missing per capita emission
emigain$cap_co2_emi[is.na(emigain$cap_co2_emi)] <- round(emigain$tot_co2_emi[is.na(emigain$cap_co2_emi)] * 1000/ emigain$Population[is.na(emigain$cap_co2_emi)], 2)
#Check imputations
emigain_notc2 %>% inner_join(select(emigain, Year, Name, Population, cap_co2_emi), by = c("Year", "Name"))
NA
Scan for special values and errors
Special values (NaN , Inf) in emigain are scanned for, revealing none. Via applying the is.special() function across the columns.
Errors (negative emissions, non positive NDGain/Population) are scanned for, revealing none. Via applying comparison operators against relevant subsets.
#Check for special values
sapply(emigain, function(x) sum(is.special(x)))
ISO3 Name Year NDGain Population tot_co2_emi solid_cons liquid_cons gas_cons cement_prod gas_flare cap_co2_emi bunker_cons
0 0 0 0 0 0 0 0 0 0 0 0 0
all_co2_emi
0
#Check for negative emissions
colSums(emigain[, -(1:5)] < 0, na.rm = TRUE)
tot_co2_emi solid_cons liquid_cons gas_cons cement_prod gas_flare cap_co2_emi bunker_cons all_co2_emi
0 0 0 0 0 0 0 0 0
#Check for non positive NDGain or Population
colSums(emigain[, (4:5)] < 0, na.rm = TRUE)
NDGain Population
0 0
Scan II
Approach & Summary
Univariate outlier detection is used on each NDGain , Population and the 9 emission variables.
This was decided as the emissions don’t share special relationships with each other and all the variables can be treated individually.
z-scores are applied across each variable. Outliers are flagged as those values with |z-score| > 3.
NDGain has no outliers flagged. The other variables eg. Population (44 flaged) , tot_co2_emi (47) do have outliers flagged.
Further inspection shows that the population for China and India are indeed valid values.
Likewise, total emission and other emissions from China, India and USA are legitimate values.
The distribution for these variables above are extremely positively skewed. These “outliers” are so far from the next set of observations in the same quartile.
Therefore the suggested outliers will be left alone - no transformation nor imputation.
Outlier summary
The z-scores across each of the numeric variables (column 4 to 14) will be established via applying the scores(type = “z”) function using function lapply().
Summary of outliers using the scores (|z-score| > 3)
00 NDGain
44 Population
47 tot_co2_emi
49 solid_cons
48 liquid_cons
45 gas_cons
22 cement_prod
88 gas_flare
78 cap_co2_emi
69 bunker_cons
46 all_co2_emi
# Get z-score for each numeric variable. Score() function with type= "z"
z_scores <- emigain[, (4:14)] %>% lapply(FUN = function(x) scores(x, type= "z")) %>% as.data.frame()
# Outlier summary
colSums(abs(z_scores) > 3)
NDGain Population tot_co2_emi solid_cons liquid_cons gas_cons cement_prod gas_flare cap_co2_emi bunker_cons all_co2_emi
0 44 47 49 48 45 22 88 78 69 46
Outlier inspection
Closer inspection of the Population outliers show that the populations are those for China and India. These are all valid. Confirmed these via the internet.
emigain[abs(z_scores$Population) > 3, ] %>% group_by(ISO3, Name) %>% slice_head(n=2)
NA
Closer inspection of the tot_co2_emi outliers show that the total emissions are those for China, India and USA. These are all valid. Confirmed these via the internet.
emigain[abs(z_scores$tot_co2_emi) > 3, ] %>% group_by(ISO3, Name) %>% slice_head(n=2)
NA
Closer inspection of the solid_cons outliers show that these emissions are those for China, India and USA. These are all valid. Confirmed these via the internet.
emigain[abs(z_scores$solid_cons) > 3, ] %>% group_by(ISO3, Name) %>% slice_head(n=2)
NA
Closer inspection of the liquid_cons outliers show that these emissions are those for China, India, Japan and USA. These are all valid. Confirmed these via the internet.
emigain[abs(z_scores$liquid_cons) > 3, ] %>% group_by(ISO3, Name) %>% slice_head(n=2)
NA
Closer inspection of the gas_cons outliers show that these emissions are those for China, Russia and USA. These are all valid. Confirmed these via the internet.
emigain[abs(z_scores$gas_cons) > 3, ] %>% group_by(ISO3, Name) %>% slice_head(n=2)
NA
Closer inspection of the cement_prod outliers show that these emissions are those for China. These are all valid. Confirmed these via the internet.
emigain[abs(z_scores$cement_prod) > 3, ] %>% group_by(ISO3, Name) %>% slice_head(n=2)
NA
Closer inspection of the gas_flare outliers show that these emissions all valid. Confirmed these via the internet.
emigain[abs(z_scores$gas_flare) > 3, ] %>% group_by(ISO3, Name) %>% slice_head(n=2)
NA
Closer inspection of the cap_co2_emi outliers show that these per capita emissions are valid. Confirmed these via the internet.
emigain[abs(z_scores$cap_co2_emi) > 3, ] %>% group_by(ISO3, Name) %>% slice_head(n=2)
NA
Closer inspection of the bunker_cons outliers show that these emissions are all valid. Confirmed these via the internet.
emigain[abs(z_scores$bunker_cons) > 3, ] %>% group_by(ISO3, Name) %>% slice_head(n=2)
NA
NA
Closer inspection of the all_co2_emi outliers show that these emissions are those for China, India and USA. These are all valid. They would follow the total emissions above.
emigain[abs(z_scores$all_co2_emi) > 3, ] %>% group_by(ISO3, Name) %>% slice_head(n=2)
NA
LS0tDQp0aXRsZTogIkRhdGEgd3JhbmdsaW5nIG9mIENhcmJvbiBlbWlzc2lvbnMgZGF0YSINCmF1dGhvcjogIktldmluIEt1ZWsgKHMzODM1MTUyKSINCnN1YnRpdGxlOiBNQVRIMjM0OSBEYXRhIFdyYW5nbGluZyBBc3NpZ25tZW50IDINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdA0KICBodG1sX2RvY3VtZW50Og0KICAgIGRmX3ByaW50OiBwYWdlZA0KICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQNCi0tLQ0KDQoNCiMjIFJlcXVpcmVkIHBhY2thZ2VzIA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFfQ0KIyBMb2FkIHJlcXVpcmVkIHBhY2thZ2VzDQoNCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KHRpZHlyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoc3RyaW5ncikNCmxpYnJhcnkob3V0bGllcnMpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGZvcmVjYXN0KQ0KDQpgYGANCg0KKipDdXN0b20gZnVuY3Rpb25zKioNCg0KKiBpcy5zcGVjaWFsIHJldHVybnMgVFJVRSBpZiB4IGlzIGVpdGhlciBhbiBpbmZpbml0ZSB2YWx1ZSBvciBub3QgYSBudW1iZXIsIEZBTFNFIG90aGVyd2lzZS4NCiogaXMuc3BlY2lhbG9yTkEgcmV0dXJucyBUUlVFIGlmIHggaXMgZWl0aGVyIGFuIGluZmluaXRlIHZhbHVlLCBub3QgYSBudW1iZXIgb3IgYSBtaXNzaW5nIHZhbHVlLCBGQUxTRSBvdGhlcndpc2UuDQoNCmBgYHtyfQ0KDQppcy5zcGVjaWFsIDwtIGZ1bmN0aW9uKHgpew0KaWYgKGlzLm51bWVyaWMoeCkpIChpcy5pbmZpbml0ZSh4KSB8IGlzLm5hbih4KSkNCn0NCg0KaXMuc3BlY2lhbG9yTkEgPC0gZnVuY3Rpb24oeCl7DQppZiAoaXMubnVtZXJpYyh4KSkgKGlzLmluZmluaXRlKHgpIHwgaXMubmFuKHgpIHwgaXMubmEoeCkpDQp9DQoNCmBgYA0KDQoNCiMjIEV4ZWN1dGl2ZSBTdW1tYXJ5IA0KDQpEYXRhIGZvciBhbmFseXNpcyBvZiBDYXJib24gZW1pc3Npb25zIGZyb20gbmF0aW9ucyBhY3Jvc3MgdGhlIHllYXJzIDE5OTUgdG8gMjAxNiwgYWxvbmcgd2l0aCBuYXRpb25zIHZ1bG5lcmFiaWxpdHkgdG8gY2xpbWF0ZSBjaGFuZ2UsIHdhcyBwcmVwYXJlZC4NCg0KKiAzIGRhdGFzZXRzIGZyb20gdHdvIHNvdXJjZXMgd2VyZSBvYnRhaW5lZCBhbmQgaW1wb3J0ZWQgZm9yIHByZXBhcmF0aW9uOiBFbWlzc2lvbnMgZnJvbSBDRElBQzsgTkRHYWluIChWdWxuZXJhYmlsaXR5KSBhbmQgUG9wdWxhdGlvbiBmcm9tIE5ER0FJLg0KDQoqIFRoZSBjb3VudHJ5IG5hbWVzIGZyb20gdGhlIGRhdGFzZXRzIHdlcmUgY2xlYW5lZCB1cCAvIHN0YW5kYXJkaXNlZCBpbiBwcmVwYXJhdGlvbiBmb3IgdGhlIG1lcmdlIG9mIHNldHMuICBDb3VudHJ5IG5hbWUgaXMgYSBqb2luIGNvbHVtbi4NCg0KKiBTdWJzZXR0aW5nIG9mIGRhdGEgd2FzIGNvbmR1Y3RlZDogT255IHRob3NlIGNvdW50cmllcyB3aXRoIGNvbXBsZXRlIHNldCBvZiBOREdhaW4gaW5kaWNlcyB3ZXJlIGNvbnNpZGVyZWQuICBBbmQgRGF0YSBmb3IgeWVhcnMgMTk5NSB0byAyMDE2IHdlcmUgY29uc2lkZXJlZC4NCg0KKiBEYXRhc2V0cyBmb3IgTkRHYWluIGFuZCBwb3B1bGF0aW9uIHdlcmUgbWFkZSBpbnRvIHRpZHkgZGF0YXNldHMuDQoNCiogQWxsIDMgZGF0YXNldHMgd2VyZSBtZXJnZWQuDQoNCiogVGhlIHJlc3VsdGluZyBkYXRhc2V0IHdhcyBpbnNwZWN0ZWQgdG8gdW5kZXJzdGFuZCB0aGUgc3RydWN0dXJlICwgZGF0YXR5cGVzLCBhbmQgdGhlIG5lY2Vzc2FyeSBjb252ZXJzaW9ucyB0byBmYWN0b3JzLCBudW1lcmljIGRhdGF0eXBlcyB3ZXJlIGNvbmR1Y3RlZC4NCg0KKiBOZXcgdmFyaWFibGUgaW5jbHVkZWQ6IEFsbCBlbWlzc2lvbnMgdG90YWwsIHVzaW5nIHRvdGFsIGNhcmJvbiBlbWlzc2lvbnMgYW5kIGJ1bmtlciBmdWVsIGVtaXNzaW9ucy4NCg0KKiBTY2FubmluZyBhbmQgZGVhbGluZyB3aXRoIG1pc3NpbmcgdmFsdWVzLCBzcGVjaWFsIHZhbHVlcywgZXJyb3JzLg0KDQoqIFNjYW5uaW5nIGFuZCBkZWFsaW5nIHdpdGggb3V0bGllcnMuDQoNCiogVHJhbnNmb3JtYXRpb24gb2YgdG90YWwgY2FyYm9uIGVtaXNzaW9ucyAodG90X2NvMl9lbWkpIGFuZCBwb3B1bGF0aW9uIChQb3B1bGF0aW9uKSBkaXN0cmlidXRpb25zIHRvIG5vcm1hbCBkaXN0cmlidXRpb25zLg0KDQoNCiMjIERhdGEgDQoNCiMjIyBTb3VyY2UgZGVzY3JpcHRpb25zDQoNCioqQ2FyYm9uIGVtaXNzaW9ucyBkYXRhIChuYXRpb24uMTc1MV8yMDE2LmNzdikgZnJvbSBDYXJib24gRGlveGlkZSBJbmZvcm1hdGlvbiBBbmFseXNpcyBDZW50ZXIqKg0KDQpEYXRhc2V0IG9mIGRpZmZlcmVudCBjYXJib24gZW1pc3Npb25zIGJ5IGNvdW50cmllcyBhY3Jvc3MgdGhlIHllYXJzIHdpdGggdGhlIGZvbGxvd2luZyB2YXJpYWJsZXMuDQoNCioqKk5hdGlvbioqKiAtIG5hbWUgb2YgY291bnRyeSB0byB3aGljaCBlbWlzc2lvbnMgcGVydGFpbiB0by4NCg0KKioqWWVhcioqKiAtIHllYXIgaW4gd2hpY2ggZW1pc3Npb25zIG9jY3VycmVkLg0KDQoqKip0b3RfY28yX2VtaSoqKiAtIFRvdGFsIENPMiBlbWlzc2lvbnMgZnJvbSBmb3NzaWwtZnVlbHMgKHNvbGlkLCBsaXF1aWQsIGdhcyxmbGFyaW5nKSBhbmQgY2VtZW50IHByb2R1Y3Rpb24uIEluIHRob3VzYW5kIG1ldHJpYyB0b25zIG9mIEMuDQoNCioqKnNvbGlkX2NvbnMqKiogLSBFbWlzc2lvbnMgZnJvbSBzb2xpZCBmdWVsIGNvbnN1bXB0aW9uLg0KDQoqKipsaXF1aWRfY29ucyoqKiAtIEVtaXNzaW9ucyBmcm9tIGxpcXVpZCBmdWVsIGNvbnN1bXB0aW9uLg0KDQoqKipnYXNfY29ucyoqKiAtIEVtaXNzaW9ucyBmcm9tIGdhcyBmdWVsIGNvbnN1bXB0aW9uLg0KDQoqKipjZW1lbnRfcHJvZCoqKiAtIEVtaXNzaW9ucyBmcm9tIGNlbWVudCBwcm9kdWN0aW9uLg0KDQoqKipnYXNfZmxhcmUqKiogLSBFbWlzc2lvbnMgZnJvbSBnYXMgZmxhcmluZy4NCg0KKioqY2FwX2NvMl9lbWkqKiogLSBQZXIgY2FwaXRhIENPMiBlbWlzc2lvbnMgKG1ldHJpYyB0b25zIG9mIGNhcmJvbikuDQoNCioqKmJ1bmtlcl9jb25zKioqIC0gRW1pc3Npb25zIGZyb20gYnVua2VyIGZ1ZWxzIChub3QgaW5jbHVkZWQgaW4gdGhlIHRvdGFscykuIEVtaXNzaW9ucyBmcm9tIGZ1ZWwgdXNlZCBmb3IgaW50ZXJuYXRpb25hbCBhdmlhdGlvbiBhbmQgbWFyaXRpbWUgdHJhbnNwb3J0LiAgQ29udmVudGlvbiBhbmQgcHJvdG9jb2wgZGljdGF0ZSB0aGVzZSBlbWlzc2lvbnMgYXJlIG5vdCBpbmNsdWRlZCBpbiBuYXRpb25hbCB0b3RhbHMgKHRvdF9jbzJfZW1pKS4NCg0KDQo8YnI+DQoqKk5ER2FpbiBJbmRleCBkYXRhIChnYWluLmNzdikgZnJvbSB0aGUgTm90cmUgRGFtZSBHbG9iYWwgQWRhcHRhdGlvbiBJbml0aWF0aXZlKioNCg0KRGF0YSBzZXQgb2YgTkRHYWluIGluZGV4ICh2dWxuZXJhYmlsaXR5IHRvIGNsaW1hdGUgY2hhbmdlKSBmb3IgZWFjaCBjb3VudHJ5IGFjcm9zcyB0aGUgeWVhcnMsIHdpdGggdGhlIGZvbGxvd2luZyB2YXJpYWJsZXMuDQoNClRoaXMgaW5kZXggaXMgYmFzZWQgb24gbnVtZXJvdXMgKHF1YW50aXRhdGl2ZSkgaW5kaWNhdG9ycyBlZyBlY29ub21pYyBhbmQgZ292ZXJuYW5jZSByZWFkaW5lc3MgdG8gYWRhcHQgdG8gY2hhbmdlICwgYW5kIGV4cG9zdXJlIHRvIG5lZ2F0aXZlIGltcGFjdHMuDQoNClRoZSBzbWFsbGVyIHRoZSBpbmRleCwgdGhlIG1vcmUgdnVsbmVyYWJsZSB0byBjbGltYXRlIGNoYW5nZSBpcyB0aGUgbmF0aW9uLg0KDQoqKipJU08zKioqIC0gMyBjaGFyYWN0ZXIgSVNPIDMxNjYgY29kaW5nIG9mIGNvdW50cnkuDQoNCioqKk5hbWUqKiogLSBOYW1lIG9mIGNvdW50cnkgdG8gd2hpY2ggdGhlIE5ER2FpbiBJbmRleCBwZXJ0YWlucyB0by4NCg0KKioqMTk5NSoqKiAtIE5ER2FpbiBpbmRleCBmb3IgeWVhciAxOTk1Lg0KDQpJbmRpY2VzIGZvciBzdWJzZXF1ZW50IHllYXJzLCB0aHJvdWdoIHRvIDIwMTgsIGFyZSBwcm92aWRlZCBhcyBzZXBlcmF0ZSB2YXJpYWJsZXMuDQoNCg0KPGJyPg0KKipQb3B1bGF0aW9uIGRhdGEgKGlucHV0LmNzdikgZnJvbSB0aGUgTm90cmUgRGFtZSBHbG9iYWwgQWRhcHRhdGlvbiBJbml0aWF0aXZlKioNCg0KRGF0YSBzZXQgb2YgaHVtYW4gcG9wdWxhdGlvbiBmb3IgZWFjaCBjb3VudHJ5IGFjcm9zcyB0aGUgeWVhcnMsIHdpdGggdGhlIGZvbGxvd2luZyB2YXJpYWJsZXMuDQoNCioqKklTTzMqKiogLSAzIGNoYXJhY3RlciBJU08gMzE2NiBjb2Rpbmcgb2YgY291bnRyeS4NCg0KKioqTmFtZSoqKiAtIE5hbWUgb2YgY291bnRyeSB0byB3aGljaCB0aGUgcG9wdWxhdGlvbiBwZXJ0YWlucyB0by4NCg0KKioqMTk5NSoqKiAtIHBvcHVsYXRpb24gZm9yIHllYXIgMTk5NS4NCg0KUG9wdWxhdGlvbiBmb3Igc3Vic2VxdWVudCB5ZWFycywgdGhyb3VnaCB0byAyMDE4LCBhcmUgcHJvdmlkZWQgYXMgc2VwZXJhdGUgdmFyaWFibGVzLg0KDQo8YnI+DQoNCiMjIyBFeHRyYWN0IFN0ZXBzDQpUaGUgdGhyZWUgZGF0YSBzZXRzIGFyZSByZWFkIGluIHZpYSByZWFkcjo6cmVhZF9jc3YgZnVuY3Rpb24uDQoNClRoZSB2YXJpYWJsZXMgZm9yIGNhcmJvbiBlbWlzc2lvbnMgYXJlIG5hbWVkIGFwcHJvcHJpYXRlbHkuICBUaGV5IGFyZSBlYWNoIHRvbyBsb25nIGZvciBhbmFseXNpcy4NCg0KYGBge3J9DQojU291cmNlIGRhdGENCg0KIyBDYXJib24gRGlveGlkZSBJbmZvcm1hdGlvbiBBbmFseXNpcyBDZW50ZXIgYXQgQXBwYWxhY2hpYW4gU3RhdGUgVW5pdmVyc2l0eSwgQm9vbmUgTm9ydGggQ2Fyb2xpbmEsIGh0dHBzOi8vZW5lcmd5LmFwcHN0YXRlL0NESUFDLg0KY19lbWlzc2lvbnMgPC0gcmVhZF9jc3YoIm5hdGlvbi4xNzUxXzIwMTYuY3N2Iiwgc2tpcCA9IDQpDQoNCiMgTm90cmUgRGFtZSBHbG9iYWwgQWRhcHRhdGlvbiBJbml0aWF0aXZlLCBVbml2ZXJzaXR5IG9mIE5vdHJlIERhbWUsICBodHRwczovL2dhaW4ubmQuZWR1L291ci13b3JrL2NvdW50cnktaW5kZXgvcmFua2luZ3MvDQpnYWluIDwtIHJlYWRfY3N2KCJyZXNvdXJjZXNfMjAyMF8wNF8wNV8xOWgwOS9yZXNvdXJjZXMvZ2Fpbi9nYWluLmNzdiIpDQoNCiMgTm90cmUgRGFtZSBHbG9iYWwgQWRhcHRhdGlvbiBJbml0aWF0aXZlLCBVbml2ZXJzaXR5IG9mIE5vdHJlIERhbWUsICBodHRwczovL2dhaW4ubmQuZWR1L291ci13b3JrL2NvdW50cnktaW5kZXgvcmFua2luZ3MvDQojIEdldCBwb3B1bGF0aW9uIGRhdGEgZm9yIGlucHV0aW5nIG1pc3NpbmcgQ08yIGVtaXNzaW9uIHBlciBjYXBpdGEgDQpwb3AgPC0gcmVhZF9jc3YoInJlc291cmNlc18yMDIwXzA0XzA1XzE5aDA5L3Jlc291cmNlcy9pbmRpY2F0b3JzL3BvcC9pbnB1dC5jc3YiKSAlPiUgc2VsZWN0KC0oMikpDQoNCg0KI1JlbmFtaW5nIGVtaXNzaW9uIHZhcmlhYmxlcyBhcHByb3ByaWF0ZWx5DQpuYW1lcyhjX2VtaXNzaW9ucylbbmFtZXMoY19lbWlzc2lvbnMpPT0gIlRvdGFsIENPMiBlbWlzc2lvbnMgZnJvbSBmb3NzaWwtZnVlbHMgYW5kIGNlbWVudCBwcm9kdWN0aW9uICh0aG91c2FuZCBtZXRyaWMgdG9ucyBvZiBDKSJdIDwtICJ0b3RfY28yX2VtaSINCm5hbWVzKGNfZW1pc3Npb25zKVtuYW1lcyhjX2VtaXNzaW9ucyk9PSAiRW1pc3Npb25zIGZyb20gc29saWQgZnVlbCBjb25zdW1wdGlvbiJdIDwtICJzb2xpZF9jb25zIg0KbmFtZXMoY19lbWlzc2lvbnMpW25hbWVzKGNfZW1pc3Npb25zKT09ICJFbWlzc2lvbnMgZnJvbSBsaXF1aWQgZnVlbCBjb25zdW1wdGlvbiJdIDwtICJsaXF1aWRfY29ucyINCm5hbWVzKGNfZW1pc3Npb25zKVtuYW1lcyhjX2VtaXNzaW9ucyk9PSAiRW1pc3Npb25zIGZyb20gZ2FzIGZ1ZWwgY29uc3VtcHRpb24iXSA8LSAiZ2FzX2NvbnMiDQpuYW1lcyhjX2VtaXNzaW9ucylbbmFtZXMoY19lbWlzc2lvbnMpPT0gIkVtaXNzaW9ucyBmcm9tIGNlbWVudCBwcm9kdWN0aW9uIl0gPC0gImNlbWVudF9wcm9kIg0KbmFtZXMoY19lbWlzc2lvbnMpW25hbWVzKGNfZW1pc3Npb25zKT09ICJFbWlzc2lvbnMgZnJvbSBnYXMgZmxhcmluZyJdIDwtICJnYXNfZmxhcmUiDQpuYW1lcyhjX2VtaXNzaW9ucylbbmFtZXMoY19lbWlzc2lvbnMpPT0gIlBlciBjYXBpdGEgQ08yIGVtaXNzaW9ucyAobWV0cmljIHRvbnMgb2YgY2FyYm9uKSJdIDwtICJjYXBfY28yX2VtaSINCm5hbWVzKGNfZW1pc3Npb25zKVtuYW1lcyhjX2VtaXNzaW9ucyk9PSAiRW1pc3Npb25zIGZyb20gYnVua2VyIGZ1ZWxzIChub3QgaW5jbHVkZWQgaW4gdGhlIHRvdGFscykiXSA8LSAiYnVua2VyX2NvbnMiDQoNCiNTYW1wbGUgZW1pc3Npb25zIGRhdGENCmNfZW1pc3Npb25zICU+JSBoZWFkKCkNCg0KI1NhbXBsZSBOREdhaW4gZGF0YQ0KZ2FpbiAlPiUgaGVhZCgpDQoNCiNTYW1wbGUgcG9wdWxhdGlvbiBkYXRhDQpwb3AgJT4lIGhlYWQoKQ0KDQpgYGANCg0KIyMjIEV4dHJhY3QgU3RlcHMgKGNvbnRpbnVlZCkNCg0KQ2xlYW4gdXAgYW5kIHN0YW5kYXJkaXNlIGpvaW4gY29sdW1uIE5hdGlvbi9OYW1lIGluIGJvdGggc291cmNlIGRhdGEgc2V0cyBjX2VtaXNzaW9ucyBhbmQgZ2Fpbg0KDQoqIENhcGl0YWxpc2UNCiogU3RhbmRhcmRpc2UgZWcuICdBTkQnIHRvICcmJywgc2hvcnRlbmluZyBvZiBuYW1lIGV0Yy4NCg0KYGBge3J9DQojIENsZWFuIHVwIC8gc3RhbmRhcmRpc2Ugam9pbiBjb2x1bW4gTmF0aW9uDQpjX2VtaV9uYXRpb24gPC0gY19lbWlzc2lvbnMgJT4lIA0KICBtdXRhdGUoDQogICAgTmF0aW9uID0gc3RyX3JlcGxhY2VfYWxsKE5hdGlvbiwgIGMoIiBBTkQgIiA9ICIgJiAiLCAiIFxcKC4qXFwpIiA9ICIiLCAiVU5JVEVEIFNUQVRFUyBPRiBBTUVSSUNBIiA9ICJVTklURUQgU1RBVEVTIiwgIkRFTU9DUkFUSUMgUkVQVUJMSUMgT0YgVEhFIENPTkdPIiA9ICJaQUlSRSIsIkNPVEUgRCBJVk9JUkUiID0gIkNPVEUgRCdJVk9JUkUiLCAiQlJVTkVJIERBUlVTU0FMQU0iPSAiQlJVTkVJIiwgIlJFUFVCTElDIE9GICIgPSAiIiwgIklTTEFNSUMgSVJBTiIgPSAiSVJBTiIsICJVTklURUQgVEFOWkFOSUEiID0gIlRBTlpBTklBIiwgIkxBTyBQRU9QTEUgUyBERU1PQ1JBVElDIFJFUFVCTElDIiA9ICJMQU8gUEVPUExFJ1MgREVNT0NSQVRJQyBSRVBVQkxJQyIsICJQTFVSSU5BVElPTkFMIFNUQVRFIE9GIEJPTElWSUEiID0gIkJPTElWSUEiLCAiR1VJTkVBIEJJU1NBVSIgPSAiR1VJTkVBLUJJU1NBVSIsICJSVVNTSUFOIEZFREVSQVRJT04iID0gIlJVU1NJQSIpKQ0KICApDQoNCiMgY2xlYW4gam9pbiBjb2x1bW4NCmdhaW5fbmF0aW9uIDwtIGdhaW4gJT4lDQogICAgICAgICAgICAgIG11dGF0ZSgNCiAgICAgICAgICAgICAgICBOYW1lID0gdG91cHBlcihOYW1lKSAlPiUgc3RyX3JlcGxhY2VfYWxsKGMoIiBBTkQgIiA9ICIgJiAiLCIsIFJFUFVCTElDIE9GIiA9ICIiLCAiLCBCT0xJVkFSSUFOIFJFUFVCTElDIE8iID0gIiIsICJCUlVORUkgREFSVVNTQUxBTSI9ICJCUlVORUkiLCAiLCBVTklURUQgUkVQVUJMSUMgT0YiID0gIiIsICIsIElTTEFNSUMgUkVQVUJMSUMgT0YiID0gIiIsICJDT05HTywgVEhFIERFTU9DUkFUSUMgUkVQVUJMSUMgTyIgPSAiWkFJUkUiLCAiLCBQTFVSSU5BVElPTkFMIFNUQVRFIE9GIiA9ICIiLCAiUlVTU0lBTiBGRURFUkFUSU9OIiA9ICJSVVNTSUEiKSkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgKQ0KDQpgYGANCg0KKipTdWJzZXR0aW5nKioNCg0KKiBPbmx5IHRob3NlIHJlY29yZHMgZnJvbSBnYWluKGdhaW5fbmF0aW9uKSB0aGF0IGhhdmUgbm8gbWlzc2luZyB2YWx1ZXMgKGNvbXBsZXRlIGNhc2VzKSB3aWxsIGJlIGNvbnNpZGVyZWQuICBBbGwgaW5jb21wbGV0ZSBjYXNlcyBoYXZlIG5vIE5ER2FpbiBpbmRleCBmb3IgYW55IHllYXIuDQoqIFN1YnNldCBOREdhaW5zIDE5OTUgLSAyMDE2LiAgRW1pc3Npb25zIGRhdGFzZXQgZ28gYXMgZmFyIGFzIDIwMTYuDQoNCmBgYHtyfQ0KIyBTY2FuIGZvciBpbmNvbXBsZXRlIGNhc2VzDQpnYWluX25vdGNvbXBsZXRlIDwtIGdhaW5fbmF0aW9uWyFjb21wbGV0ZS5jYXNlcyhnYWluX25hdGlvbiksXQ0KDQojIEFsbCBpbmNvbXBsZXRlIGNhc2VzIGhhdmUgbm8gaW5kZXggZm9yIGFueSB5ZWFyDQpnYWluX25vdGNvbXBsZXRlICU+JSBoZWFkKCkNCg0KIyBTdWJzZXQgZ2FpbiBkYXRhIHRvIDE5OTUgLSAyMDE2DQpnYWluX25hdGlvbiA8LSBnYWluX25hdGlvbltjb21wbGV0ZS5jYXNlcyhnYWluX25hdGlvbiksXSAlPiUgc2VsZWN0KDE6MjQpDQoNCmBgYA0KDQojIwlUaWR5ICYgTWFuaXB1bGF0ZSBEYXRhIEkgDQoNClRoZSBOREdhaW4gZGF0YXNldCAoZ2FpbikgaXMgbm90IHRpZHkgYXMgaXQgaGFzIHZhbHVlcyBmb3IgdmFyaWFibGUgeWVhciBhcyBjb2x1bW4gbmFtZXMgKDE5OTUsIDE5OTYgLi4uKS4gQW5kIHRoZSBvYnNlcnZhdGlvbnMgZm9yIGVhY2ggeWVhciBhcmUgb24gb25lIHJvdy4gIFRoZSB5ZWFyIG5lZWRzIHRvIGJlIGFsb25nIGEgY29sdW1uICwgYW5kIGVhY2ggb2JzZXJ2YXRpb24gb24gYSBzZXBlcmF0ZSByb3cuDQoNClRoZSBzYW1lIGFwcGxpZXMgdG8gdGhlIHBvcHVsYXRpb24gZGF0YXNldCAocG9wKTogdmFsdWVzIGZvciB2YXJpYWJsZSB5ZWFyIGFzIGNvbHVtbiBuYW1lcyAoMTk5NSwgMTk5NiAuLi4pLiBBbmQgdGhlIG9ic2VydmF0aW9ucyBmb3IgZWFjaCB5ZWFyIGFyZSBvbiBvbmUgcm93LiAgVGhlIHllYXIgbmVlZHMgdG8gYmUgYWxvbmcgYSBjb2x1bW4gLCBhbmQgZWFjaCBvYnNlcnZhdGlvbiBvbiBhIHNlcGVyYXRlIHJvdy4NCg0KVG8gbWFrZSB0aGUgZGF0YXNldHMgdGlkeSB0aGUgZm9sbG93aW5nIHN0ZXBzIGFyZSBjb25kdWN0ZWQuDQoNCiogTWFrZSB0aGUgZGF0YSBzZXQgbG9uZ2VyIHVzaW5nIHBpdm90X2xvbmdlcigpIHdoZXJlIHRoZSB5ZWFycyAxOTk1LCAxOTk2IGV0YyBhcmUgbW92ZWQgdG8gY29sdW1uICJZZWFyIiwgYW5kIHRoZSB2YWx1ZXMgdG8gY29sdW1uICJOREdhaW4iIGZvciBnYWluICwgIlBvcHVsYXRpb24iIGZvciBwb3B1bGF0aW9uLg0KDQpgYGB7cn0NCiNNYWtlIGdhaW4gZGF0YXNldCB0aWR5DQpnYWluX3RpZHkgPC0gZ2Fpbl9uYXRpb24gJT4lIHBpdm90X2xvbmdlcihjb2xzID0gLSgxOjIpLCBuYW1lc190byA9ICJZZWFyIiwgIHZhbHVlc190byA9ICJOREdhaW4iKQ0KI0NvbnZlcnQgWWVhciB0byBpbnRlZ2VyDQpnYWluX3RpZHkkWWVhciA8LSBhcy5pbnRlZ2VyKGdhaW5fdGlkeSRZZWFyKQ0KDQojTWFrZSBwb3B1bGF0aW9uIGRhdGFzZXQgdGlkeQ0KcG9wX3RpZHkgPC0gcG9wICU+JSBwaXZvdF9sb25nZXIoY29scyA9IC0oMSksIG5hbWVzX3RvID0gIlllYXIiLCAgdmFsdWVzX3RvID0gIlBvcHVsYXRpb24iKQ0KI0NvbnZlcnQgWWVhciB0byBpbnRlZ2VyDQpwb3BfdGlkeSRZZWFyIDwtIGFzLmludGVnZXIocG9wX3RpZHkkWWVhcikNCg0KIyBTaG93IHRpZHkgZ2FpbiBkYXRhc2V0DQpoZWFkKGdhaW5fdGlkeSkNCg0KIyBTaG93IHRpZHkgcG9wdWxhdGlvbiBkYXRhc2V0DQpoZWFkKHBvcF90aWR5KQ0KYGBgDQoNCiMjIyBNZXJnZSBkYXRhIHNldHMNClRoZSBnYWluIGFuZCBwb3B1bGF0aW9uIGRhdGEgc2V0cyBhcmUgdGhlbiBtZXJnZWQgdG9nZXRoZXIgKGdhaW5fdGlkeSkgYnkgSVNPMyBhbmQgWWVhci4NCg0KVGhlIGZpbmFsIGRhdGFzZXQgKGVtaWdhaW4pIGlzIHRoZSByZXN1bHQgb2YgdGhlIG1lcmdlIG9mIHRoZSB0aWR5IGdhaW4gZGF0YXNldChnYWluX3RpZHkpIGFuZCBlbWlzc2lvbnMgZGF0YXNldChjX2VtaV9uYXRpb24pIGJ5IE5hdGlvbi9OYW1lIGFuZCBZZWFyLg0KYGBge3J9DQojbGVmdCBqb2luIGdhaW4gYW5kIHBvcHVsYXRpb24gc2V0cyB0b2dldGhlciBvbiBJU08zIGFuZCBZZWFyDQpnYWluX3RpZHkgPC0gZ2Fpbl90aWR5ICU+JSBsZWZ0X2pvaW4ocG9wX3RpZHksIGJ5ID0gYygiSVNPMyIgPSAiSVNPMyIsICJZZWFyIiA9ICJZZWFyIikpDQoNCiNtZXJnZSBnYWluIGFuZCBlbWlzc2lvbnMgZGF0YXNldHMgdG9nZXRoZXINCmVtaWdhaW4gPC0gZ2Fpbl90aWR5ICU+JSBpbm5lcl9qb2luKGNfZW1pX25hdGlvbiAsIGJ5ID0gYygiTmFtZSIgPSAiTmF0aW9uIiwgIlllYXIiID0gIlllYXIiKSApDQoNCmBgYA0KDQoNCiMjIFVuZGVyc3RhbmQgDQoNClRoZSAqKiplbWlnYWluKioqIGRhdGFzZXQgaXMgYSBkYXRhZnJhbWUgb2YgZGltZW5zaW9uIDM4ODcgeCAxMyAoMTMgdmFyaWFibGVzLCAzODg3IG9ic2VydmF0aW9ucykuDQoNClZhcmlhYmxlcywgdGhlaXIgZGF0YSB0eXBlIGFuZCBhbnkgdHlwZSBjb252ZXJzaW9ucyBhcmUgYXMgZm9sbG93cy4NCg0KKiAqSVNPMyo6IGNoYXJhY3RlciBkYXRhdHlwZS4gV2lsbCBiZSBjb252ZXJ0ZWQgdG8gZmFjdG9yLiAgQ291bnRyeSBpcyBjYXRlZ29yaWNhbC4NCiogKk5hbWUqOiBjaGFyYWN0ZXIgZGF0YXR5cGUuIFdpbGwgYmUgY29udmVydGVkIHRvIGZhY3Rvci4gIENvdW50cnkgaXMgY2F0ZWdvcmljYWwuDQoqICpZZWFyKjogbnVtZXJpYyBkYXRhdHlwZS4gV2lsbCBiZSBjb252ZXJ0ZWQgdG8gb3JkZXJlZCBmYWN0b3IuICBZZWFyIGlzIG9yZGluYWwuDQoqICpOREdhaW4qOiBudW1lcmljIGRhdGF0eXBlLiBObyBjb252ZXJzaW9uLg0KKiAqUG9wdWxhdGlvbio6IG51bWVyaWMgZGF0YXR5cGUuIE5vIGNvbnZlcnNpb24uDQoqICp0b3RfY28yX2VtaSo6IG51bWVyaWMgZGF0YXR5cGUuIE5vIGNvbnZlcnNpb24uDQoqICpzb2xpZF9jb25zKjogbnVtZXJpYyBkYXRhdHlwZS4gTm8gY29udmVyc2lvbi4NCiogKmxpcXVpZF9jb25zKjogbnVtZXJpYyBkYXRhdHlwZS4gTm8gY29udmVyc2lvbi4NCiogKmdhc19jb25zKjogbnVtZXJpYyBkYXRhdHlwZS4gTm8gY29udmVyc2lvbi4NCiogKmNlbWVudF9wcm9kKjogbnVtZXJpYyBkYXRhdHlwZS4gTm8gY29udmVyc2lvbi4NCiogKmdhc19mbGFyZSo6IGNoYXJhY3RlciBkYXRhdHlwZS4gV2lsbCBiZSBjb252ZXJ0ZWQgdG8gbnVtZXJpYyhkb3VibGUpIGRhdGF0eXBlLiAgVGhpcyBpcyBhbiBlbWlzc2lvbnMgdmFyaWFibGUgc28gY29udGludW91cy9yYXRpb25hbC4NCiogKmNhcF9jbzJfZW1pKjogY2hhcmFjdGVyIGRhdGF0eXBlLiBXaWxsIGJlIGNvbnZlcnRlZCB0byBudW1lcmljKGRvdWJsZSkgZGF0YXR5cGUuICBUaGlzIGlzIGFuIGVtaXNzaW9ucyB2YXJpYWJsZSBzbyBjb250aW51b3VzL3JhdGlvbmFsLg0KKiAqYnVua2VyX2NvbnMqOiBudW1lcmljIGRhdGF0eXBlLiBObyBjb252ZXJzaW9uLg0KDQpgYGB7cn0NCiMgVW5kZXJzdGFuZCB0aGUgZGF0YSBhbmQgc3RydWN0dXJlDQplbWlnYWluICU+JSBzdHIoKQ0KDQpgYGANCg0KPGJyPg0KDQpUaGUgY29udmVyc2lvbiB0byBmYWN0b3IgaXMgZG9uZSB2aWEgdGhlIGZhY3RvcigpIGZ1bmN0aW9uLiAgTm8gbGFiZWxsaW5nIGlzIHJlcXVpcmVkIHRoaXMgdGltZS4NCg0KRm9yIHRoZSBvcmRlcmVkIGZhY3RvciAoWWVhciksIHRoZSBmYWN0b3IoKSBmdW5jdGlvbiBpcyB1c2VkIGFsb25nIHdpdGggcGFyYW1ldGVycyAqbGV2ZWxzID0gW3ZlY3RvciBvZiBvcmRlcmVkIHllYXJzXSAqIGFuZCAqb3JkZXJlZD1UUlVFKi4NCg0KVGhlIGNvbnZlcnNpb24gb2YgdGhlIHR3byBlbWlzc2lvbnMgKCpnYXNfZmxhcmUqLCAqY2FwX2NvMl9lbWkqKSBmcm9tIGNoYXJhY3RlciB0byBudW1lcmljIGRvdWJsZSBpcyBjb21wbGV0ZWQgdXNpbmcgdGhlIGNvbnZlcnNpb24gZnVuY3Rpb24gYXMuZG91YmxlKCkuDQoNCmBgYHtyfQ0KI0lTTzMgYXMgZmFjdG9yDQplbWlnYWluJElTTzMgPC0gZW1pZ2FpbiRJU08zICU+JSBmYWN0b3IoKQ0KDQojTmFtZSBhcyBmYWN0b3INCmVtaWdhaW4kTmFtZSA8LSBlbWlnYWluJE5hbWUgJT4lIGZhY3RvcigpDQoNCiNOYW1lIGFzIGZhY3Rvcg0KZW1pZ2FpbiROYW1lIDwtIGVtaWdhaW4kTmFtZSAlPiUgZmFjdG9yKCkNCg0KI1llYXIgYXMgb3JkZXIgZmFjdG9yDQojZW1pZ2FpbiRZZWFyICU+JSB1bmlxdWUoKSANCg0KZW1pZ2FpbiRZZWFyIDwtIGVtaWdhaW4kWWVhciAlPiUgZmFjdG9yKGxldmVscyA9IGMoMTk5NSwgMTk5NiwgMTk5NywgMTk5OCwgMTk5OSwgMjAwMCwgMjAwMSwgMjAwMiwgMjAwMywgMjAwNCwgMjAwNSwgMjAwNiwgMjAwNywgMjAwOCwgMjAwOSwgMjAxMCwgMjAxMSwgMjAxMiwgMjAxMywgMjAxNCwgMjAxNSwgMjAxNiksIG9yZGVyZWQgPSBUUlVFKQ0KDQojZ2FzX2ZsYXJlICYgY2FwX2NvMl9lbWkNCmVtaWdhaW4kZ2FzX2ZsYXJlIDwtIGVtaWdhaW4kZ2FzX2ZsYXJlICU+JSBhcy5kb3VibGUoKQ0KZW1pZ2FpbiRjYXBfY28yX2VtaSA8LSBlbWlnYWluJGNhcF9jbzJfZW1pICU+JSBhcy5kb3VibGUoKQ0KDQpgYGANCg0KPGJyPg0KQWZ0ZXIgdGhlIG5lY2Vzc2FyeSBjb252ZXJzaW9ucywgaW5zcGVjdGluZyB0aGUgcmVzdWx0aW5nIGRhdGEgdHlwZXMgYmVsb3cgc2hvdyB0aGUgMyBmYWN0b3JzLCBvbmUgb3JkZXJlZCwgYW5kIGFsbCBlbWlzc2lvbiB2YXJpYWJsZXMgYXJlIG51bWVyaWMuDQpgYGB7cn0NCmVtaWdhaW4gJT4lIHN0cigpDQoNCmBgYA0KDQoNCiMjCVRpZHkgJiBNYW5pcHVsYXRlIERhdGEgSUkgDQoNCkFkZGl0aW9uIG9mIHZhcmlhYmxlICoqKmFsbF9jbzJfZW1pKioqDQoNCiogVGhpcyB2YXJpYWJsZSBpcyB0aGUgdG90YWwgb2YgQUxMIGVtaXNzaW9ucywgaW5jbHVkaW5nIHRob3NlIGZyb20gYnVua2VyKGludGVybmF0aW9uYWwgYXZpYXRpb24gYW5kIG1hcml0aW1lKSBmdWVsLiAgDQoNCiogTG9uZyBzdGFuZGluZyBjb252ZW50aW9uL3Byb3RvY29sIHN0YXRlcyB0aGF0IGJ1bmtlciBlbWlzc2lvbnMgYXJlIGV4Y2x1ZGVkIGZyb20gbmF0aW9uIHJlcG9ydGluZy4gSGlzdG9yaWNhbGx5IGhhcmQgdG8gYXR0cmlidXRlIHRvIGNvdW50cnkuICBTb3VyY2UgY291bnRyeT8gRGVzaW50YXRpb24/IGV0Yy4NCg0KKiBJdCdzIGhhbmR5IHRvIGhhdmUgdGhpcyB2YXJpYWJsZSBhcyBpdCBnaXZlcyBhIGJldHRlciBwaWN0dXJlIG9mIGVtaXNzaW9ucy4gV2h5IGV4Y2x1ZGUgYW5vdGhlciBzb3VyY2Ugb2YgY2FyYm9uIGVtaXNzaW9ucz8NCg0KKiBBcyB0b3RhbCBlbWlzc2lvbnMgKHRvdF9jbzJfZW1pKSBpcyBwcm92aWRlZCwgYWRkIGJ1bmtlciBlbWlzc2lvbnMgdG8gdGhpcy4NCg0KKiBhbGxfY28yX2VtaSA9IHRvdF9jbzJfZW1pICsgYnVua2VyX2NvbnMNCg0KVGhlIHZhcmlhYmxlIGlzIGluY2x1ZWQgaW4gdGhlIGVtaWdhaW4gZGF0YXNldCB2aWEgdGhlIG11dGF0ZSBmdW5jdGlvbiwgd2hlcmUgaXQgaXMgZGVyaXZlZCB1c2luZyB0aGUgaW5kaWNhdGVkIGZvcm11bGEuDQoNCmBgYHtyfQ0KI0FkZCBhbGxfY28yX2VtaSB2YXJpYWJsZSAtIHRvdGFsIGNvMiBlbWlzc2lvbnMgKyBidW5rZXIgZW1pc3Npb25zLg0KDQplbWlnYWluIDwtIGVtaWdhaW4gJT4lIG11dGF0ZSgNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsbF9jbzJfZW1pID0gdG90X2NvMl9lbWkgKyBidW5rZXJfY29ucyAgDQogICAgICAgICAgICAgICAgICAgICAgKQ0KDQojSW5zcGVjdCB2YXJpYWJsZSBzdHJ1Y3R1cmUNCmVtaWdhaW4kYWxsX2NvMl9lbWkgJT4lIHN0cigpDQpgYGANCg0KIyMJU2NhbiBJIA0KDQojIyMgU2Nhbm5pbmcgYW5kIGRlYWxpbmcgd2l0aCBtaXNzaW5nIHZhbHVlcywgc3BlY2lhbCB2YWx1ZXMsIGVycm9ycw0KDQoqIE1pc3NpbmcgdmFsdWVzIGVpdGhlciB0aHJvdWdoIG1lcmdpbmcgb2YgZGF0YXNldHMgKFBvcHVsYXRpb24pIG9yIGFzIGxpdGVyYWxzICcuJyAsICcuLicgd2VyZSBzdGFuZGFyZGlzZWQgdG8gUidzIE5BLiAgDQoNCiogKmdhc19mbGFyZSovKmNhcF9jbzJfZW1pKiBjb252ZXJzaW9uIHRvIG51bWVyaWMgY29lcmNlZCB0aGUgJy4nLycuLicgdG8gTkEuDQoNCiogQ29tcGxldGUgY2FzZXMgaW4gZW1pZ2FpbiwgYWNyb3NzIG51bWVyaWMgdmFyaWFibGVzICg0OjE0KSwgd2VyZSBleGFtaW5lZC4gSVNPMy9OYW1lL1llYXIgKDE6Mykgd2VyZSBpZ25vcmVkIGFzIHRoZXkgYXJlIGpvaW4gY29sdW1ucy4NCg0KKiBDb2x1bW4gY291bnRzIG9mIG1pc3NpbmcgdmFsdWVzIHJldmVhbCB0aGF0IG1pc3NpbmcgdmFsdWVzIGFyZSBjb25maW5lZCB0byAqUG9wdWxhdGlvbiogYW5kICpjYXBfY28yX2VtaSouDQoNCiogVmVyaWZ5aW5nIHRoZSByZWNvcmRzIHdoZXJlIHRoZXJlIGFyZSBtaXNzaW5nIHZhbHVlcyBmb3IgZWl0aGVyICpQb3B1bGF0aW9uKiBvciAqY2FwX2NvMl9lbWkqLCBzaG93IHRoYXQgdGhleSBjYW4gZWFzaWx5IGJlIGltcHV0ZWQuDQoNCiogSW1wdXRlIHVzaW5nIGZvcm11bGEgJ2NhcmJvbiBlbWlzc2lvbiBwZXIgY2FwaXRhJyA9ICd0b3RhbCBjYXJib24gZW1pc3Npb24nIHggMTAwMCAvIHBvcHVsYXRpb24NCg0KPiAqY2FwX2NvMl9lbWkqID0gKnRvdF9jbzJfZW1pKiB4IDEwMDAgLyAqUG9wdWxhdGlvbioNCg0KDQpgYGB7ciBpbmNsdWRlPUZBTFNFfQ0KdCA8LSBlbWlnYWluDQoNCmBgYA0KDQo8YnI+DQoNCiMjIyBTY2FuIGZvciBtaXNzaW5nIHZhbHVlcw0KDQpTdW1tYXJ5IG9mIG1pc3NpbmcgdmFsdWVzIHNob3cNCg0KKiAyMiBtaXNzaW5nIGluIFBvcHVsYXRpb24NCg0KKiAxNyBtaXNzaW5nIGluIGNhcF9jbzJfZW1pIA0KYGBge3J9DQojR2V0IGluY29tcGxldGUgY2FzZXMgdG8gY2hlY2sgYWdhaW5zdCBwb3N0IGltcHV0ZQ0KZW1pZ2Fpbl9ub3RjMiA8LSBlbWlnYWluWyFjb21wbGV0ZS5jYXNlcyhlbWlnYWluWywgNDoxNF0pLF0NCg0KI1NjYW4gZm9yIE5BcyBpbiBkYXRhIHNldA0KY29sU3Vtcyhpcy5uYShlbWlnYWluKSkNCg0KYGBgDQoNClNob3cgc2FtcGxlcyBvZiByZWNvcmRzIHdpdGggbWlzc2luZyB2YWx1ZXMNCmBgYHtyfQ0KI0NoZWNrIFBvcHVsYXRpb24gTkFzDQplbWlnYWluW2lzLm5hKGVtaWdhaW4kUG9wdWxhdGlvbiksXSAgJT4lIGhlYWQoNSkNCg0KI0NoZWNrIGNhcF9jbzJfZW1pIE5Bcw0KZW1pZ2Fpbltpcy5uYShlbWlnYWluJGNhcF9jbzJfZW1pKSxdICU+JSBoZWFkKDUpDQoNCmBgYA0KDQojIyMgSW1wdXRlIG1pc3NpbmcgdmFsdWVzDQoNCiogSW1wdXRlIG1pc3NpbmcgcG9wdWxhdGlvbiBhbmQgcGVyIGNhcGl0YSBlbWlzc2lvbiBiYXNlZCBvbiBmb3JtdWxhIGFib3ZlLg0KDQoqIENoZWNraW5nIGltcHV0YXRpb24gYnkgbG9va2luZyB1cCByZXN1bHRzIGFnYWluc3QgaW5jb21wbGV0ZSBjYXNlIGRhdGFzZXQgKGVtaWdhaW5fbm90YzIpIHNob3cgdGhhdCB0aGUgaW1wdXRhdGlvbnMgYXJlIGNvcnJlY3QuDQoNCmBgYHtyfQ0KI0ltcHV0ZSBtaXNzaW5nIHBvcHVsYXRpb24NCmVtaWdhaW4kUG9wdWxhdGlvbltpcy5uYShlbWlnYWluJFBvcHVsYXRpb24pXSA8LSBlbWlnYWluJHRvdF9jbzJfZW1pW2lzLm5hKGVtaWdhaW4kUG9wdWxhdGlvbildICogMTAwMCAvICBlbWlnYWluJGNhcF9jbzJfZW1pW2lzLm5hKGVtaWdhaW4kUG9wdWxhdGlvbildDQoNCiNJbXB1dGUgbWlzc2luZyBwZXIgY2FwaXRhIGVtaXNzaW9uDQplbWlnYWluJGNhcF9jbzJfZW1pW2lzLm5hKGVtaWdhaW4kY2FwX2NvMl9lbWkpXSA8LSByb3VuZChlbWlnYWluJHRvdF9jbzJfZW1pW2lzLm5hKGVtaWdhaW4kY2FwX2NvMl9lbWkpXSAqIDEwMDAvICBlbWlnYWluJFBvcHVsYXRpb25baXMubmEoZW1pZ2FpbiRjYXBfY28yX2VtaSldLCAyKQ0KDQojQ2hlY2sgaW1wdXRhdGlvbnMNCmVtaWdhaW5fbm90YzIgJT4lIGlubmVyX2pvaW4oc2VsZWN0KGVtaWdhaW4sIFllYXIsIE5hbWUsIFBvcHVsYXRpb24sIGNhcF9jbzJfZW1pKSwgYnkgPSBjKCJZZWFyIiwgIk5hbWUiKSkNCg0KYGBgDQoNCiMjIyBTY2FuIGZvciBzcGVjaWFsIHZhbHVlcyBhbmQgZXJyb3JzDQoNCiogU3BlY2lhbCB2YWx1ZXMgKE5hTiAsIEluZikgaW4gZW1pZ2FpbiBhcmUgc2Nhbm5lZCBmb3IsIHJldmVhbGluZyBub25lLiAgVmlhIGFwcGx5aW5nIHRoZSBpcy5zcGVjaWFsKCkgZnVuY3Rpb24gYWNyb3NzIHRoZSBjb2x1bW5zLg0KDQoqIEVycm9ycyAobmVnYXRpdmUgZW1pc3Npb25zLCBub24gcG9zaXRpdmUgTkRHYWluL1BvcHVsYXRpb24pIGFyZSBzY2FubmVkIGZvciwgcmV2ZWFsaW5nIG5vbmUuICBWaWEgYXBwbHlpbmcgY29tcGFyaXNvbiBvcGVyYXRvcnMgYWdhaW5zdCByZWxldmFudCBzdWJzZXRzLg0KYGBge3J9DQojQ2hlY2sgZm9yIHNwZWNpYWwgdmFsdWVzDQpzYXBwbHkoZW1pZ2FpbiwgZnVuY3Rpb24oeCkgc3VtKGlzLnNwZWNpYWwoeCkpKQ0KDQojQ2hlY2sgZm9yIG5lZ2F0aXZlIGVtaXNzaW9ucw0KY29sU3VtcyhlbWlnYWluWywgLSgxOjUpXSA8IDAsIG5hLnJtID0gVFJVRSkNCg0KI0NoZWNrIGZvciBub24gcG9zaXRpdmUgTkRHYWluIG9yIFBvcHVsYXRpb24NCmNvbFN1bXMoZW1pZ2FpblssICg0OjUpXSA8IDAsIG5hLnJtID0gVFJVRSkNCmBgYA0KDQpgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQ0KZW1pZ2FpbltlbWlnYWluJElTTzMgJWluJSBjKCdTRE4nLCAnTUtEJyksIF0NCnNldGRpZmYodCwgZW1pZ2FpbikNCg0KI2xpYnJhcnkoZGVkdWN0aXZlKQ0KI2xpYnJhcnkodmFsaWRhdGUpDQojIHRlc3RpbmcgYW5vdGhlciBpbXB1dGUgbWV0aG9kIHRoYXQgZG9lc250IHdvcmsNCnJ1bGVzIDwtIHZhbGlkYXRvcihjYXAgPSB0b3RfY28yX2VtaSAqIDEwMDAvIHBvcHVsYXRpb24gID09IGNhcF9jbzJfZW1pICkNCnJ1bGVzDQojIFVzZSBpbXB1dGVfbHIgZnVuY3Rpb24NCg0KaW1wdXRlZF9kZiA8LSBpbXB1dGVfbHIoZW1pZ2FpbixydWxlcykNCg0KaW1wdXRlZF9kZltpbXB1dGVkX2RmJElTTzMgJWluJSBjKCdNS0QnLCAnU0ROJyksXQ0KDQoNCmBgYA0KDQojIwlTY2FuIElJDQoNCiMjIyBBcHByb2FjaCAmIFN1bW1hcnkNCg0KKiBVbml2YXJpYXRlIG91dGxpZXIgZGV0ZWN0aW9uIGlzIHVzZWQgb24gZWFjaCBOREdhaW4gLCBQb3B1bGF0aW9uIGFuZCB0aGUgOSBlbWlzc2lvbiB2YXJpYWJsZXMuDQoNCiogVGhpcyB3YXMgZGVjaWRlZCBhcyB0aGUgZW1pc3Npb25zIGRvbid0IHNoYXJlIHNwZWNpYWwgcmVsYXRpb25zaGlwcyB3aXRoIGVhY2ggb3RoZXIgYW5kIGFsbCB0aGUgdmFyaWFibGVzIGNhbiBiZSB0cmVhdGVkIGluZGl2aWR1YWxseS4NCg0KKiB6LXNjb3JlcyBhcmUgYXBwbGllZCBhY3Jvc3MgZWFjaCB2YXJpYWJsZS4gIE91dGxpZXJzIGFyZSBmbGFnZ2VkIGFzIHRob3NlIHZhbHVlcyB3aXRoIHx6LXNjb3JlfCA+IDMuDQoNCiogKk5ER2FpbiogaGFzIG5vIG91dGxpZXJzIGZsYWdnZWQuICBUaGUgb3RoZXIgdmFyaWFibGVzIGVnLiAqUG9wdWxhdGlvbiogKDQ0IGZsYWdlZCkgLCAqdG90X2NvMl9lbWkqICg0NykgZG8gaGF2ZSBvdXRsaWVycyBmbGFnZ2VkLg0KDQoqIEZ1cnRoZXIgaW5zcGVjdGlvbiBzaG93cyB0aGF0IHRoZSBwb3B1bGF0aW9uIGZvciBDaGluYSBhbmQgSW5kaWEgYXJlIGluZGVlZCB2YWxpZCB2YWx1ZXMuDQoNCiogTGlrZXdpc2UsIHRvdGFsIGVtaXNzaW9uIGFuZCBvdGhlciBlbWlzc2lvbnMgZnJvbSBDaGluYSwgSW5kaWEgYW5kIFVTQSBhcmUgbGVnaXRpbWF0ZSB2YWx1ZXMuDQoNCiogVGhlIGRpc3RyaWJ1dGlvbiBmb3IgdGhlc2UgdmFyaWFibGVzIGFib3ZlIGFyZSBleHRyZW1lbHkgcG9zaXRpdmVseSBza2V3ZWQuICBUaGVzZSAib3V0bGllcnMiIGFyZSBzbyBmYXIgZnJvbSB0aGUgbmV4dCBzZXQgb2Ygb2JzZXJ2YXRpb25zIGluIHRoZSBzYW1lIHF1YXJ0aWxlLg0KDQoqIFRoZXJlZm9yZSB0aGUgc3VnZ2VzdGVkIG91dGxpZXJzIHdpbGwgYmUgbGVmdCBhbG9uZSAtIG5vIHRyYW5zZm9ybWF0aW9uIG5vciBpbXB1dGF0aW9uLg0KDQpgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQ0KbGlicmFyeShNVk4pDQoNCmVtaWdhaW5fc3ViIDwtIGVtaWdhaW5bLCAtKDE6NSldDQoNCnJlc3VsdHMgPC0gbXZuKGRhdGEgPSBlbWlnYWluX3N1YiwgbXVsdGl2YXJpYXRlT3V0bGllck1ldGhvZCA9ICJxdWFuIiwgc2hvd091dGxpZXJzID0gVFJVRSwgc2hvd05ld0RhdGEgPSBUUlVFKQ0KDQpyZXN1bHRzJG11bHRpdmFyaWF0ZU91dGxpZXJzDQpyZXN1bHRzJG5ld0RhdGENCg0KYGBgDQoNCiMjIyBPdXRsaWVyIHN1bW1hcnkNCg0KVGhlIHotc2NvcmVzIGFjcm9zcyBlYWNoIG9mIHRoZSBudW1lcmljIHZhcmlhYmxlcyAoY29sdW1uIDQgdG8gMTQpIHdpbGwgYmUgZXN0YWJsaXNoZWQgdmlhIGFwcGx5aW5nIHRoZSBzY29yZXModHlwZSA9ICJ6IikgZnVuY3Rpb24gdXNpbmcgZnVuY3Rpb24gbGFwcGx5KCkuDQoNCioqU3VtbWFyeSBvZiBvdXRsaWVycyB1c2luZyB0aGUgc2NvcmVzICh8ei1zY29yZXwgPiAzKSoqDQoNCjAwIE5ER2FpbiAgDQoNCjQ0IFBvcHVsYXRpb24gDQoNCjQ3IHRvdF9jbzJfZW1pICANCg0KNDkgc29saWRfY29ucyANCg0KNDggbGlxdWlkX2NvbnMgICAgDQoNCjQ1IGdhc19jb25zIA0KDQoyMiBjZW1lbnRfcHJvZA0KDQo4OCBnYXNfZmxhcmUgDQoNCjc4IGNhcF9jbzJfZW1pIA0KDQo2OSBidW5rZXJfY29ucyANCg0KNDYgYWxsX2NvMl9lbWkgDQoNCmBgYHtyfQ0KIyBHZXQgei1zY29yZSBmb3IgZWFjaCBudW1lcmljIHZhcmlhYmxlLiAgU2NvcmUoKSBmdW5jdGlvbiB3aXRoIHR5cGU9ICJ6Ig0Kel9zY29yZXMgPC0gZW1pZ2FpblssICg0OjE0KV0gJT4lIGxhcHBseShGVU4gPSBmdW5jdGlvbih4KSBzY29yZXMoeCwgdHlwZT0gInoiKSkgJT4lIGFzLmRhdGEuZnJhbWUoKQ0KDQojIE91dGxpZXIgc3VtbWFyeQ0KY29sU3VtcyhhYnMoel9zY29yZXMpID4gMykgDQoNCmBgYA0KDQojIyMgT3V0bGllciBpbnNwZWN0aW9uDQoNCkNsb3NlciBpbnNwZWN0aW9uIG9mIHRoZSBQb3B1bGF0aW9uIG91dGxpZXJzIHNob3cgdGhhdCB0aGUgcG9wdWxhdGlvbnMgYXJlIHRob3NlIGZvciBDaGluYSBhbmQgSW5kaWEuICBUaGVzZSBhcmUgYWxsIHZhbGlkLiAgQ29uZmlybWVkIHRoZXNlIHZpYSB0aGUgaW50ZXJuZXQuDQoNCmBgYHtyfQ0KZW1pZ2FpblthYnMoel9zY29yZXMkUG9wdWxhdGlvbikgPiAzLCBdICU+JSBncm91cF9ieShJU08zLCBOYW1lKSAlPiUgc2xpY2VfaGVhZChuPTIpDQoNCmBgYA0KDQpDbG9zZXIgaW5zcGVjdGlvbiBvZiB0aGUgdG90X2NvMl9lbWkgb3V0bGllcnMgc2hvdyB0aGF0IHRoZSB0b3RhbCBlbWlzc2lvbnMgYXJlIHRob3NlIGZvciBDaGluYSwgSW5kaWEgYW5kIFVTQS4gIFRoZXNlIGFyZSBhbGwgdmFsaWQuICBDb25maXJtZWQgdGhlc2UgdmlhIHRoZSBpbnRlcm5ldC4NCg0KYGBge3J9DQplbWlnYWluW2Ficyh6X3Njb3JlcyR0b3RfY28yX2VtaSkgPiAzLCBdICU+JSBncm91cF9ieShJU08zLCBOYW1lKSAlPiUgc2xpY2VfaGVhZChuPTIpDQoNCmBgYA0KDQpDbG9zZXIgaW5zcGVjdGlvbiBvZiB0aGUgc29saWRfY29ucyBvdXRsaWVycyBzaG93IHRoYXQgdGhlc2UgZW1pc3Npb25zIGFyZSB0aG9zZSBmb3IgQ2hpbmEsIEluZGlhIGFuZCBVU0EuICBUaGVzZSBhcmUgYWxsIHZhbGlkLiAgQ29uZmlybWVkIHRoZXNlIHZpYSB0aGUgaW50ZXJuZXQuDQoNCmBgYHtyfQ0KZW1pZ2FpblthYnMoel9zY29yZXMkc29saWRfY29ucykgPiAzLCBdICU+JSBncm91cF9ieShJU08zLCBOYW1lKSAlPiUgc2xpY2VfaGVhZChuPTIpDQoNCmBgYA0KDQpDbG9zZXIgaW5zcGVjdGlvbiBvZiB0aGUgbGlxdWlkX2NvbnMgb3V0bGllcnMgc2hvdyB0aGF0IHRoZXNlIGVtaXNzaW9ucyBhcmUgdGhvc2UgZm9yIENoaW5hLCBJbmRpYSwgSmFwYW4gYW5kIFVTQS4gIFRoZXNlIGFyZSBhbGwgdmFsaWQuICBDb25maXJtZWQgdGhlc2UgdmlhIHRoZSBpbnRlcm5ldC4NCg0KYGBge3J9DQplbWlnYWluW2Ficyh6X3Njb3JlcyRsaXF1aWRfY29ucykgPiAzLCBdICU+JSBncm91cF9ieShJU08zLCBOYW1lKSAlPiUgc2xpY2VfaGVhZChuPTIpDQoNCmBgYA0KDQpDbG9zZXIgaW5zcGVjdGlvbiBvZiB0aGUgZ2FzX2NvbnMgb3V0bGllcnMgc2hvdyB0aGF0IHRoZXNlIGVtaXNzaW9ucyBhcmUgdGhvc2UgZm9yIENoaW5hLCBSdXNzaWEgYW5kIFVTQS4gIFRoZXNlIGFyZSBhbGwgdmFsaWQuICBDb25maXJtZWQgdGhlc2UgdmlhIHRoZSBpbnRlcm5ldC4NCg0KYGBge3J9DQplbWlnYWluW2Ficyh6X3Njb3JlcyRnYXNfY29ucykgPiAzLCBdICU+JSBncm91cF9ieShJU08zLCBOYW1lKSAlPiUgc2xpY2VfaGVhZChuPTIpDQoNCmBgYA0KDQpDbG9zZXIgaW5zcGVjdGlvbiBvZiB0aGUgY2VtZW50X3Byb2Qgb3V0bGllcnMgc2hvdyB0aGF0IHRoZXNlIGVtaXNzaW9ucyBhcmUgdGhvc2UgZm9yIENoaW5hLiAgVGhlc2UgYXJlIGFsbCB2YWxpZC4gIENvbmZpcm1lZCB0aGVzZSB2aWEgdGhlIGludGVybmV0Lg0KDQpgYGB7cn0NCmVtaWdhaW5bYWJzKHpfc2NvcmVzJGNlbWVudF9wcm9kKSA+IDMsIF0gJT4lIGdyb3VwX2J5KElTTzMsIE5hbWUpICU+JSBzbGljZV9oZWFkKG49MikNCg0KYGBgDQoNCkNsb3NlciBpbnNwZWN0aW9uIG9mIHRoZSBnYXNfZmxhcmUgb3V0bGllcnMgc2hvdyB0aGF0IHRoZXNlIGVtaXNzaW9ucyBhbGwgdmFsaWQuICBDb25maXJtZWQgdGhlc2UgdmlhIHRoZSBpbnRlcm5ldC4NCg0KYGBge3J9DQplbWlnYWluW2Ficyh6X3Njb3JlcyRnYXNfZmxhcmUpID4gMywgXSAlPiUgZ3JvdXBfYnkoSVNPMywgTmFtZSkgJT4lIHNsaWNlX2hlYWQobj0yKQ0KDQpgYGANCg0KQ2xvc2VyIGluc3BlY3Rpb24gb2YgdGhlIGNhcF9jbzJfZW1pIG91dGxpZXJzIHNob3cgdGhhdCB0aGVzZSBwZXIgY2FwaXRhIGVtaXNzaW9ucyBhcmUgdmFsaWQuICBDb25maXJtZWQgdGhlc2UgdmlhIHRoZSBpbnRlcm5ldC4NCg0KYGBge3J9DQplbWlnYWluW2Ficyh6X3Njb3JlcyRjYXBfY28yX2VtaSkgPiAzLCBdICU+JSBncm91cF9ieShJU08zLCBOYW1lKSAlPiUgc2xpY2VfaGVhZChuPTIpDQoNCmBgYA0KDQpDbG9zZXIgaW5zcGVjdGlvbiBvZiB0aGUgYnVua2VyX2NvbnMgb3V0bGllcnMgc2hvdyB0aGF0IHRoZXNlIGVtaXNzaW9ucyBhcmUgYWxsIHZhbGlkLiAgQ29uZmlybWVkIHRoZXNlIHZpYSB0aGUgaW50ZXJuZXQuDQoNCmBgYHtyfQ0KZW1pZ2FpblthYnMoel9zY29yZXMkYnVua2VyX2NvbnMpID4gMywgXSAlPiUgZ3JvdXBfYnkoSVNPMywgTmFtZSkgJT4lIHNsaWNlX2hlYWQobj0yKQ0KDQoNCmBgYA0KDQpDbG9zZXIgaW5zcGVjdGlvbiBvZiB0aGUgYWxsX2NvMl9lbWkgb3V0bGllcnMgc2hvdyB0aGF0IHRoZXNlIGVtaXNzaW9ucyBhcmUgdGhvc2UgZm9yIENoaW5hLCBJbmRpYSBhbmQgVVNBLiAgVGhlc2UgYXJlIGFsbCB2YWxpZC4gVGhleSB3b3VsZCBmb2xsb3cgdGhlIHRvdGFsIGVtaXNzaW9ucyBhYm92ZS4NCg0KYGBge3J9DQplbWlnYWluW2Ficyh6X3Njb3JlcyRhbGxfY28yX2VtaSkgPiAzLCBdICU+JSBncm91cF9ieShJU08zLCBOYW1lKSAlPiUgc2xpY2VfaGVhZChuPTIpDQoNCmBgYA0KDQoNCiMjCVRyYW5zZm9ybSANCg0KIyMjIEFwcHJvYWNoICYgU3VtbWFyeQ0KDQpUaGUgdG90YWwgY2FyYm9uIGVtaXNzaW9ucyAodG90X2NvMl9lbWkpIGFuZCBwb3B1bGF0aW9uIChQb3B1bGF0aW9uKSBkaXN0cmlidXRpb25zIGFyZSBib3RoIGhlYXZpbHkgcmlnaHQgc2tld2VkLg0KDQpUcmFuc2Zvcm1hdGlvbnMgYXJlIGFwcGxpZWQgdG8gbW92ZSB0aGVtIHRvIG5vcm1hbCBkaXN0cmlidXRpb25zLiAgdG90X2NvMl9lbWkudCBhbmQgUG9wdWxhdGlvbi50IHJlc3BlY3RpdmVseS4NCg0KR2l2ZW4gdGhhdCB0aGV5IGFyZSByaWdodCBza2V3ZWQsIG1hdGhlbWF0aWNhbCBmdW5jdGlvbnMgbG9nKCksIGxvZzEwKCksIHNxcnQoKSBhcmUgYXBwbGllZC4gDQoNClRoZSByZXN1bHRpbmcgZGlzdHJpYnV0aW9ucyBhcmUgdmVyaWZpZWQgdXNpbmcgaGlzdG9ncmFtIHBsb3RzLiBBdCBsZWFzdCBvbmUgb2YgdGhlIGZ1bmN0aW9ucyBpcyBjb25zaWRlcmVkIHN1aXRhYmxlIGZvciB0aGUgdHJhbnNmb3JtYXRpb24sIGllLiBjbG9zZXN0IHRvIG5vcm1hbC4gIFNvIHRoZXJlIGlzIG5vIG5lZWQgdG8gZXhwbG9yZSBlbHNld2hlcmUgZm9yIG90aGVyIG1ldGhvZHMuDQoNClRoZSBCb3ggQ294IHRyYW5zZm9ybWF0b24gaXMgdXNlZCwgdXNpbmcgZm9yZWNhc3Q6OkJveENveC5sYW1iZGEgdG8gd29yayBvdXQgdGhlIGJlc3QgbGFtYmRhLCBhbmQgdGhlbiBCb3hDb3goKSB0byBwZXJmb3JtIHRoZSB0cmFuc2Zvcm1hdGlvbi4gICBUaGlzIGlzIHRvIGRpc2NvdmVyIGFsdGVybmF0aXZlIG1ldGhvZHMuDQoNCg0KIyMjIFRvdGFsIENPMiBlbWlzc2lvbnMgdHJhbnNmb3JtYXRpb24NCg0KKiBCZXN0IHRyYW5zZm9ybWF0aW9uIGZ1bmN0aW9uIGlzIGxvZzEwKCkNCg0KKiBCb3hDb3ggbGFtYmRhIGlzIDANCg0KYGBge3J9DQojdG90YWwgZW1pc3Npb25zIGRpc3RyaWJ1dGlvbiBpcyBoZWF2aWx5IHJpZ2h0IHNrZXdlZA0KZW1pZ2FpbiR0b3RfY28yX2VtaSAlPiUgaGlzdChtYWluID0gInRvdF9jbzJfZW1pIiwgYnJlYWtzPSAxMDApDQoNCiN0cnkgdHJhbnNmb3JtYXRpb25zDQplbWlnYWluJHRvdF9jbzJfZW1pICU+JSBsb2coKSAlPiUgaGlzdChtYWluID0gImxvZyh0b3RfY28yX2VtaSkiKQ0KZW1pZ2FpbiR0b3RfY28yX2VtaSAlPiUgbG9nMTAoKSAlPiUgaGlzdChtYWluID0gImxvZzEwKHRvdF9jbzJfZW1pKSIpICNiZXN0DQplbWlnYWluJHRvdF9jbzJfZW1pICU+JSBzcXJ0KCkgJT4lIGhpc3QobWFpbiA9ICJzcXJ0KHRvdF9jbzJfZW1pKSIpDQoNCiNnZXQgYmVzdCBsYW1iZGEgLCB0aGVuIGFwcGx5IHRvIHRyYW5zZm9ybWF0aW9uDQplbWlnYWluJHRvdF9jbzJfZW1pICU+JSBCb3hDb3gubGFtYmRhKG1ldGhvZCA9ICJsb2dsaWsiLCBsb3dlciA9IC0zLCB1cHBlciA9IDMpDQplbWlnYWluJHRvdF9jbzJfZW1pICU+JSBCb3hDb3gobGFtYmRhID0gMCkgJT4lIGhpc3QobWFpbiA9ICJCb3hDb3godG90X2NvMl9lbWkpIikNCg0KI2FwcGx5IGJlc3QgdHJhbnNmb3JtYXRpb24NCmVtaWdhaW4kdG90X2NvMl9lbWkudCA8LSBlbWlnYWluJHRvdF9jbzJfZW1pICU+JSBsb2cxMCgpDQpgYGANCg0KIyMjIFBvcHVsYXRpb24gdHJhbnNmb3JtYXRpb24NCg0KKiBCZXN0IHRyYW5zZm9ybWF0aW9uIGZ1bmN0aW9uIGlzIGxvZygpDQoNCiogQm94Q294IGxhbWJkYSBpcyAwLjA1DQpgYGB7cn0NCiNwb3B1bGF0aW9uIGRpc3RyaWJ1dGlvbiBpcyBoZWF2aWx5IHJpZ2h0IHNrZXdlZA0KZW1pZ2FpbiRQb3B1bGF0aW9uICU+JSBoaXN0KG1haW4gPSAiUG9wdWxhdGlvbiIpDQoNCiN0cnkgdHJhbnNmb3JtYXRpb25zDQplbWlnYWluJFBvcHVsYXRpb24gJT4lIGxvZygpICU+JSBoaXN0KG1haW4gPSAibG9nKFBvcHVsYXRpb24pIikgI2Jlc3QNCmVtaWdhaW4kUG9wdWxhdGlvbiAlPiUgbG9nMTAoKSAlPiUgaGlzdChtYWluID0gImxvZzEwKFBvcHVsYXRpb24pIikNCmVtaWdhaW4kUG9wdWxhdGlvbiAlPiUgc3FydCgpICU+JSBoaXN0KG1haW4gPSAic3FydChQb3B1bGF0aW9uKSIpDQoNCiNnZXQgYmVzdCBsYW1iZGEgLCB0aGVuIGFwcGx5IHRvIHRyYW5zZm9ybWF0aW9uDQplbWlnYWluJFBvcHVsYXRpb24gJT4lIEJveENveC5sYW1iZGEobWV0aG9kID0gImxvZ2xpayIsIGxvd2VyID0gLTMsIHVwcGVyID0gMykNCmVtaWdhaW4kUG9wdWxhdGlvbiAlPiUgQm94Q294KGxhbWJkYSA9IDAuMDUpICU+JSBoaXN0KG1haW4gPSAiQm94Q294KFBvcHVsYXRpb24pIikNCg0KI2FwcGx5IGJlc3QgdHJhbnNmb3JtYXRpb24NCmVtaWdhaW4kUG9wdWxhdGlvbi50IDwtIGVtaWdhaW4kUG9wdWxhdGlvbiAlPiUgbG9nKCkNCg0KYGBgDQoNClZpZXcgdHJhbnNmb3JtYXRpb25zICp0b3RfY28yX2VtaS50KiBhbmQgKlBvcHVsYXRpb24udCoNCg0KYGBge3J9DQplbWlnYWluICU+JSBoZWFkKCkNCg0KYGBgDQoNCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9DQojTkRHYWluIGRpc3RyaWJ1dGlvbiBpcyBtaWxkbHkgcmlnaHQgc2tld2VkDQplbWlnYWluJE5ER2FpbiAlPiUgaGlzdCgpDQoNCiN0cnkgdHJhbnNmb3JtYXRpb25zDQplbWlnYWluJE5ER2FpbiAlPiUgbG9nKCkgJT4lIGhpc3QoKQ0KZW1pZ2FpbiROREdhaW4gJT4lIGxvZzEwKCkgJT4lIGhpc3QoKSAjYmVzdA0KZW1pZ2FpbiROREdhaW4gJT4lIHNxcnQoKSAlPiUgaGlzdCgpDQoNCmVtaWdhaW4kTkRHYWluICU+JSBCb3hDb3gubGFtYmRhKG1ldGhvZCA9ICJndWVycmVybyIsIGxvd2VyID0gLTMsIHVwcGVyID0gMykNCmVtaWdhaW4kTkRHYWluICU+JSBCb3hDb3gubGFtYmRhKG1ldGhvZCA9ICJsb2dsaWsiLCBsb3dlciA9IC0zLCB1cHBlciA9IDMpDQplbWlnYWluJE5ER2FpbiAlPiUgQm94Q294KGxhbWJkYSA9IC0wLjI1KSAlPiUgaGlzdCgpDQoNCnFwbG90KHg9TkRHYWluLCB5PXRvdF9jbzJfZW1pLCBkYXRhPWVtaWdhaW4sIGdlb20gPSAicG9pbnQiKQ0KDQpxcGxvdCh4PWxvZzEwKE5ER2FpbiksIHk9bG9nMTAodG90X2NvMl9lbWkpLCBkYXRhPWVtaWdhaW4sIGdlb20gPSAicG9pbnQiKQ0KDQpxcGxvdCh4PVBvcHVsYXRpb24sIHk9dG90X2NvMl9lbWksIGRhdGE9ZW1pZ2FpbiwgZ2VvbSA9ICJwb2ludCIpDQoNCnFwbG90KHg9bG9nKFBvcHVsYXRpb24pLCB5PWxvZzEwKHRvdF9jbzJfZW1pKSwgZGF0YT1lbWlnYWluLCBnZW9tID0gInBvaW50IikNCmBgYA0KDQoNCiMjIyBEYXRhIFJlZmVyZW5jZQ0KDQoqIEQuIEdpbGZpbGxhbiwgRy4gTWFybGFuZCwgVC4gQm9kZW4sIGFuZCBSLiAgQW5kcmVzLiAoMjAxOSkuICpHbG9iYWwsIFJlZ2lvbmFsLCBhbmQgTmF0aW9uYWwgRm9zc2lsLUZ1ZWwgQ08yIEVtaXNzaW9uczogMTc1MS0yMDE2KiBbY3N2IGZpbGUgbmF0aW9uLjE3NTFfMjAxNi5jc3ZdLiBodHRwczovL2VuZXJneS5hcHBzdGF0ZS5lZHUvcmVzZWFyY2gvd29yay1hcmVhcy9jZGlhYy1hcHBzdGF0ZQ0KKiBVbml2ZXJzaXR5IG9mIE5vdHJlIERhbWUsIE5vdHJlIERhbWUgR2xvYmFsIEFkYXB0YXRpb24gSW5pdGlhdGl2ZS4oMjAyMCkuICpORC1HQUlOIENvdW50cnkgSW5kZXgqLiBodHRwczovL2dhaW4ubmQuZWR1L291ci13b3JrL2NvdW50cnktaW5kZXgvcmFua2luZ3MvDQoNCg0KPGJyPg0KPGJyPg0K