Required packages
library(readxl)
library(tidyr)
library(dplyr)
library(editrules)
library(outliers)
library(MVN)
Executive Summary
The datasets of regional population by gender and age in 2018-2019 were obtained from Australian Bureau of Statistics to gain more insights about gender ratio in regional areas in Victoria and how their population changed from 2018 to 2019.
The first two datasets were imported as xlsx. files for the population estimates by sex across Local Government Areas (LGA) in 2018 and filtered for Victorian region. The final dataset described the total population estimates across LGA in Victoria in 2018-2019. All of the imported datasets were then joined using LGA as key variables and checked for data structure. Data conversion was taken from character to numeric values. The merged dataset was untidy because column headers were not variables so that tidying data was carried out for gender columns with the estimated number of residents as values. Two new variables were created with mutate function to determine the population ratio by sex and the population growth between 2018-2019 for LGAs.
The tidy dataset was then scanned for missing values and special values for all numeric values. The obvious errors of numeric data were also scanned for the total population of 2018 and 2019 to ensure that there were no negative values in the variables. The outliers were detected for following variables: Estimated residents, Population ratio and Growth rate using boxplot. The location of these outliers was identified using z.scores method for univariate data. The data from total population of 2018 and 2019 was scanned for outliers as multivariate data using Mahalanobis distance approach and visualised by Chi-square Q-Q plot. Following this, since the outliers were decided not to eliminate from the dataset, data transformation was taken for these two variables using \(ln\) transformation to reduce the right skewness in the distributions. The final dataset was ready for further statistical analysis.
Data
First dataset
The Population Estimates by Age and Sex, Local Government Areas (ASGS 2018), 2018 .xls was collected from Australian Bureau of Statistics at https://www.abs.gov.au/AUSSTATS/abs@.nsf/DetailsPage/3235.02018?OpenDocument&fbclid=IwAR0JOzaSa6clO2HYae-2ZbsdXZjNBuk5XK-Z5YEM0NhCuoCjW-fp8IkGbtQ, which measured the estimate of the residental population in Australia by age and gender corresponding to State and Local Government Areas at 30 June 2018.
The original dataset #1 was firstly imported with 7 skipped rows due to invalid headers and stored as pop_female for sheet named “Table 2”.
Since the study focused on total population by gender in Victoria, the S/T code under ASGS 2018 for Victoria (S/T code = 2) was filtered from the original dataset using filter().
The column names of vic_pop_female were then renamed using colnames().
Since the study would not consider the number of residents under Age group categories, only Total Female population per LGA was selected from vic_pop_female using select() and assigned into new object called data_female.
The data_female now contained four main variables:
S/T code [categorical]: State/Territory code
S/T name [character]: State/Territory name
LGA code [categorical]: code of Local Government Areas per State e.g 20110 for Alpine (S)
LGA Name [character]: name of Local Government Areas per State e.g Alpine
Total Female population [numeric]: the total of female residents from all age groups by LGA
pop_female <- read_excel("Population Estimates by Age and Sex, Local Government Areas (ASGS 2018), 2018 .xls", sheet = "Table 2", skip = 7)
New names:
* `` -> ...2
* `` -> ...3
* `` -> ...4
vic_pop_female <- pop_female %>% filter(`ASGS 2018` == 2)
colnames(vic_pop_female) <- c("S/T code", "S/T name", "LGA code", "LGA name", "Age 0-4", "Age 5-9", "Age 10-14", "Age 15-19", "Age 20-24", "Age 25-29", "Age 30-34", "Age 35-39", "Age 40-44", "Age 45-49", "Age 50-54", "Age 55-59", "Age 60-64", "Age 65-69", "Age 70-74", "Age 75-79", "Age 80-84", "Age 85 and over", "Total Female population")
data_female <- vic_pop_female %>% select(`S/T code` , `S/T name`, `LGA code`, `LGA name`, `Total Female population`)
head(data_female)
Second dataset
The pop_male was also imported from Population Estimates by Age and Sex, Local Government Areas (ASGS 2018), 2018 .xls with sheet named “Table 1”.
Since the study focused on total population by gender in Victoria, the S/T code under ASGS 2018 for Victoria (S/T code = 2) was also filtered from pop_male using filter().
The column names of vic_pop_male were also renamed using colnames().
Since the study would not consider the number of residents under Age group categories, only Total Male population per LGA was selected from vic_pop_male using select() and assigned into new object called data_male.
The data_female now contained four main variables:
S/T code [categorical]: State/Territory code
S/T name [character]: State/Territory name
LGA code [categorical]: code of Local Government Areas per State e.g 20110 for Alpine (S)
LGA Name [character]: name of Local Government Areas per State e.g Alpine
Total Male population [numeric]: the total of female residents from all age groups by LGA
pop_male <- read_excel("Population Estimates by Age and Sex, Local Government Areas (ASGS 2018), 2018 .xls", sheet = "Table 1", skip = 7)
New names:
* `` -> ...2
* `` -> ...3
* `` -> ...4
vic_pop_male <- pop_male %>% filter(`ASGS 2018` == 2)
colnames(vic_pop_male) <- c("S/T code", "S/T name", "LGA code", "LGA name", "Age 0-4", "Age 5-9", "Age 10-14", "Age 15-19", "Age 20-24", "Age 25-29", "Age 30-34", "Age 35-39", "Age 40-44", "Age 45-49", "Age 50-54", "Age 55-59", "Age 60-64", "Age 65-69", "Age 70-74", "Age 75-79", "Age 80-84", "Age 85 and over", "Total Male population")
data_male <- vic_pop_male %>% select(`S/T code` , `S/T name`, `LGA code`, `LGA name`, `Total Male population`)
head(data_male)
Third dataset
The Population Estimates by Local Government Area, 2018 to 2019 .xls was also obtained from Australian Bureau of Statistics at https://www.abs.gov.au/AUSSTATS/abs@.nsf/DetailsPage/3218.02018-19?OpenDocument&fbclid=IwAR205_G_WwqXHZDy0SJxsXfJX_SbSNN4owAo_uYnsQ1ecqmhMsuTpaJ4xVw, which indicated the total population for 2018 and 2019 as well as proportion for different components of population change (natural increase, net overseas migration, net internal migration) by LGA across States.
The original dataset #2 was firstly imported with sheet named “Table 2” (Victoria) and 6 skipped rows due to invalid headers and stored as pop_vic.
The total population of Victoria by LGA in 2018 and 2019 were selected from the original dataset pop_vic using select() and assigned into new object new_pop_vicfor later merging datasets.
The column names of new_pop_vic was renamed and now includes three variables:
LGA code [categorical]: code of Local Government Areas in Victoria
LGA name[characer]: name of Local Government Areas in Victoria
2018[numeric]: total population in 2018 by lGA
2019[numeric]: total population in 2019 by lGA
pop_vic <- read_excel("Population Estimates by Local Government Area, 2018 to 2019 .xls", sheet = "Table 2", skip = 6)
New names:
* `` -> ...1
* `` -> ...2
* `` -> ...5
* `` -> ...7
* `` -> ...8
* … and 1 more problem
new_pop_vic <- pop_vic %>% select (c(1,2,3,4))
colnames(new_pop_vic) <- c("LGA code", "LGA name", "Total_2018", "Total_2019")
head(new_pop_vic)
NA
Merging datasets
The data_female and data_male were firstly merged using inner_join which used S/T code, S/T name,LGA code and LGA name as key variables and stored as data_gender.
Data_gender described the total population by gender across Local Government Areas in Victoria by 2018.
data_gender <- inner_join(data_female, data_male,by = c("S/T code", "S/T name", "LGA code", "LGA name"))
head(data_gender)
The final dataset pop_vic_gender was then created by merging data_gender and new_pop_vic using inner_join which used both LGA code and LGA name as key variables.
The final dataset now includes 8 variables:
S/T code [categorical]: State/Territory code
S/T name [character]: State/Territory name
LGA code [categorical]: code of Local Government Areas per State e.g 20110 for Alpine (S)
LGA Name [character]: name of Local Government Areas per State e.g Alpine
Total Female population [numeric]: the total of female residents by LGA
Total Male population [numeric]: the total of male residents by LGA
Total_2018[numeric]: total population in 2018 by lGA
Total_2019[numeric]: total population in 2019 by lGA
pop_vic_gender <- inner_join(data_gender, new_pop_vic, by = c("LGA code", "LGA name"))
head(pop_vic_gender)
Understand
The dimension of the dataset was checked using dim(), which resulted at 80 observations and 8 variables.
The structure of pop_vic_gender showed that all variables were in character type. Therefore, the conversion to numeric data type and factor were needed.
- The conversion of multiple columns to numeric data type was done by using
sapply with as.numeric.
- The conversion of
LGA code to factor variable was done by using as.factor without ordered.
dim(pop_vic_gender)
[1] 80 8
str(pop_vic_gender)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame': 80 obs. of 8 variables:
$ S/T code : chr "2" "2" "2" "2" ...
$ S/T name : chr "Victoria" "Victoria" "Victoria" "Victoria" ...
$ LGA code : chr "20110" "20260" "20570" "20660" ...
$ LGA name : chr "Alpine (S)" "Ararat (RC)" "Ballarat (C)" "Banyule (C)" ...
$ Total Female population: chr "6391" "5468" "55293" "66536" ...
$ Total Male population : chr "6339" "6327" "52032" "63701" ...
$ Total_2018 : chr "12730" "11795" "107324" "130250" ...
$ Total_2019 : chr "12814" "11845" "109505" "131631" ...
col.num <- c("S/T code", "Total Female population", "Total Male population", "Total_2018", "Total_2019")
pop_vic_gender[col.num] <- sapply(pop_vic_gender[col.num],as.numeric)
pop_vic_gender$`LGA code` <- as.factor(pop_vic_gender$`LGA code`)
str(pop_vic_gender)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame': 80 obs. of 8 variables:
$ S/T code : num 2 2 2 2 2 2 2 2 2 2 ...
$ S/T name : chr "Victoria" "Victoria" "Victoria" "Victoria" ...
$ LGA code : Factor w/ 80 levels "20110","20260",..: 1 2 3 4 5 6 7 8 9 10 ...
$ LGA name : chr "Alpine (S)" "Ararat (RC)" "Ballarat (C)" "Banyule (C)" ...
$ Total Female population: num 6391 5468 55293 66536 18021 ...
$ Total Male population : num 6339 6327 52032 63701 17306 ...
$ Total_2018 : num 12730 11795 107324 130250 35326 ...
$ Total_2019 : num 12814 11845 109505 131631 36320 ...
Tidy & Manipulate Data I
The pop_vic_gender dataset was untidy because Total Female population and Total Male population as column headers were not variables.
gather() was used to gather female and male columns into one single column named Gender and stored the values under Estimated residents column.
Gender was then check whether it was a factor variable using is.factor().
- Since the variable was not a factor, the conversion from character to factor was taken by using
as.factor.
- The levels of
Gender was classified using factor with labels.
Estimated residents showed the number of residents by gender for each Local Government Areas on Victoria by 2018.
A tidy dataset was then stored as tidy_pop_gender.
- The columns of the tidy dataset were rearranged with
Gender and Estimated residents before Total_2018 and Total_2019.
tidy_pop_gender <- pop_vic_gender %>% gather(`Total Female population`, `Total Male population`, key = "Gender", value = "Estimated residents")
head(tidy_pop_gender)
is.factor(tidy_pop_gender$Gender)
[1] FALSE
tidy_pop_gender$Gender <- as.factor(tidy_pop_gender$Gender)
tidy_pop_gender$Gender<- factor(tidy_pop_gender$Gender, level = c("Total Female population", "Total Male population"), labels = c("female", "male"))
tidy_pop_gender <- tidy_pop_gender[ , c(1,2,3,4,7,8,5,6)]
head(tidy_pop_gender)
Tidy & Manipulate Data II
The Population ratio was created to estimate the proportion of female and male residents by total population per Local Government Areas in Victoria by 2018.
Population ratio calculated by dividing the Estimated residents with total population in 2018 and converting into proportions.
The ratio indicated that there were higher mean proportions of female residents across LGA in Victoria by 2018 using group_by() and summarise().
The Growth rate was also mutated to determine the growth rate of population between 2018 and 2019 for every Local Government Areas in Victoria.
Growth rate = \(\frac{Present value - Past value}{Past value}*100\)
- This growth rate value would be useful for predicting future population in different LGAs using an exponential growth model.
new_pop <- tidy_pop_gender %>% mutate("Population ratio" = round((`Estimated residents`/`Total_2018`)*100, 2), "Growth rate" = ((`Total_2019` - `Total_2018`)/`Total_2018`)*100)
head(new_pop)
new_pop %>% group_by(`Gender`) %>% summarise(avergage = mean(`Population ratio`, na.rm = TRUE))
Scan I
Scan for missing values
The missing values (NA) were scanned for all numeric values and output as the total number of missing values for each column using sum(is.na()).
The sapply() was used to apply sum(is.na()) in multiple columns for scanning.
There is no NA values detected in the dataset new_pop.
sapply(new_pop, function(x) sum(is.na(x)))
S/T code S/T name LGA code LGA name
0 0 0 0
Gender Estimated residents Total_2018 Total_2019
0 0 0 0
Population ratio Growth rate
0 0
Scan for special values
The is.special function is created to check for special values that are either infinite values or Not a Number values (nan) in the dataset.
The special values were scanned for all numeric data in new_pop dataset and the output as the total number of special values for each columns using sum(is.special()).
The sapply() was also used to apply sum(is.special()) in multiple columns for scanning special values.
There is no special value detected in the dataset.
is.special <- function(x){
if (is.numeric(x)) (is.infinite(x) | is.nan(x))
}
sapply(new_pop, function(x) sum(is.special(x)))
S/T code S/T name LGA code LGA name
0 0 0 0
Gender Estimated residents Total_2018 Total_2019
0 0 0 0
Population ratio Growth rate
0 0
Scan for obvivous errors
The data inconsistencies were checked for the dataset by generating a rule for numeric data. The rule is no negative numeric values in the total population of 2018 and 2019.
The rule was created using editset() and assigned it into rule.
The rule was then applied to the dataset using violatedEdits() to output logical values where TRUE is where inconsistencies are existed.
- The output turned out to have no data inconsistencies in the dataset.
rule <- editset(c("Total_2018 > 0", "Total_2019 > 0"))
rule
Edit set:
num1 : 0 < Total_2018
num2 : 0 < Total_2019
violatedEdits(rule, new_pop)
edit
record num1 num2
1 FALSE FALSE
2 FALSE FALSE
3 FALSE FALSE
4 FALSE FALSE
5 FALSE FALSE
6 FALSE FALSE
7 FALSE FALSE
8 FALSE FALSE
9 FALSE FALSE
10 FALSE FALSE
11 FALSE FALSE
12 FALSE FALSE
13 FALSE FALSE
14 FALSE FALSE
15 FALSE FALSE
16 FALSE FALSE
17 FALSE FALSE
18 FALSE FALSE
19 FALSE FALSE
20 FALSE FALSE
21 FALSE FALSE
22 FALSE FALSE
23 FALSE FALSE
24 FALSE FALSE
25 FALSE FALSE
26 FALSE FALSE
27 FALSE FALSE
28 FALSE FALSE
29 FALSE FALSE
30 FALSE FALSE
31 FALSE FALSE
32 FALSE FALSE
33 FALSE FALSE
34 FALSE FALSE
35 FALSE FALSE
36 FALSE FALSE
37 FALSE FALSE
38 FALSE FALSE
39 FALSE FALSE
40 FALSE FALSE
41 FALSE FALSE
42 FALSE FALSE
43 FALSE FALSE
44 FALSE FALSE
45 FALSE FALSE
46 FALSE FALSE
47 FALSE FALSE
48 FALSE FALSE
49 FALSE FALSE
50 FALSE FALSE
51 FALSE FALSE
52 FALSE FALSE
53 FALSE FALSE
54 FALSE FALSE
55 FALSE FALSE
56 FALSE FALSE
57 FALSE FALSE
58 FALSE FALSE
59 FALSE FALSE
60 FALSE FALSE
61 FALSE FALSE
62 FALSE FALSE
63 FALSE FALSE
64 FALSE FALSE
65 FALSE FALSE
66 FALSE FALSE
67 FALSE FALSE
68 FALSE FALSE
69 FALSE FALSE
70 FALSE FALSE
71 FALSE FALSE
72 FALSE FALSE
73 FALSE FALSE
74 FALSE FALSE
75 FALSE FALSE
76 FALSE FALSE
77 FALSE FALSE
78 FALSE FALSE
79 FALSE FALSE
80 FALSE FALSE
81 FALSE FALSE
82 FALSE FALSE
83 FALSE FALSE
84 FALSE FALSE
85 FALSE FALSE
86 FALSE FALSE
87 FALSE FALSE
88 FALSE FALSE
89 FALSE FALSE
90 FALSE FALSE
91 FALSE FALSE
92 FALSE FALSE
93 FALSE FALSE
94 FALSE FALSE
95 FALSE FALSE
96 FALSE FALSE
97 FALSE FALSE
98 FALSE FALSE
99 FALSE FALSE
100 FALSE FALSE
101 FALSE FALSE
102 FALSE FALSE
103 FALSE FALSE
104 FALSE FALSE
105 FALSE FALSE
106 FALSE FALSE
107 FALSE FALSE
108 FALSE FALSE
109 FALSE FALSE
110 FALSE FALSE
111 FALSE FALSE
112 FALSE FALSE
113 FALSE FALSE
114 FALSE FALSE
115 FALSE FALSE
116 FALSE FALSE
117 FALSE FALSE
118 FALSE FALSE
119 FALSE FALSE
120 FALSE FALSE
121 FALSE FALSE
122 FALSE FALSE
123 FALSE FALSE
124 FALSE FALSE
125 FALSE FALSE
126 FALSE FALSE
127 FALSE FALSE
128 FALSE FALSE
129 FALSE FALSE
130 FALSE FALSE
131 FALSE FALSE
132 FALSE FALSE
133 FALSE FALSE
134 FALSE FALSE
135 FALSE FALSE
136 FALSE FALSE
137 FALSE FALSE
138 FALSE FALSE
139 FALSE FALSE
140 FALSE FALSE
141 FALSE FALSE
142 FALSE FALSE
143 FALSE FALSE
144 FALSE FALSE
145 FALSE FALSE
146 FALSE FALSE
147 FALSE FALSE
148 FALSE FALSE
149 FALSE FALSE
150 FALSE FALSE
151 FALSE FALSE
152 FALSE FALSE
153 FALSE FALSE
154 FALSE FALSE
155 FALSE FALSE
156 FALSE FALSE
157 FALSE FALSE
158 FALSE FALSE
159 FALSE FALSE
160 FALSE FALSE
Scan II
Scan for number and proportions of residents by gender
Boxplot was used to scan numeric values from Estimated residents and Population ratio columns for any potential outliers in the dataset.
There were two outliers recorded in the boxplot of Estimated residents which responded for more than 150,000 residents across LGAs in Victoria.
The outliers were then detected by Z-score method using scores(type = "z").
The summary of z scores showed that the minimum z-score is -1.0408 and the maximum is 3.395.
Since the absolute values of z score greater than 3 are considered as outliers, which(abs(z.scores)>3) was used to identify the location of outliers.
- The observation in row 14 and 94 were considered as outliers.
- It highlighted that the LGA named Casey in Victoria had the most outstanding population which is more 150,000 residents by gender living in the area.
- Since this output might be interesting for future questions, these outliers would not be eliminated.
boxplot(new_pop$`Estimated residents`, main="Number of residents in Victoria (2018)", ylab = "Residents")

z.scores <- new_pop$`Estimated residents` %>% scores(type = "z")
z.scores %>% summary()
Min. 1st Qu. Median Mean 3rd Qu. Max.
-1.0408 -0.8383 -0.4571 0.0000 0.7009 3.3958
which(abs(z.scores) >3 )
[1] 14 94
new_pop[c(14,94), ]
length (which( abs(z.scores) >3 ))
[1] 2
There were four outliers recorded in the boxplot of Population ratio which was ranging from either more than 52% or less than 48% of residents living across LGAs.
The outliers were then detected by Z-score method using scores(type = "z").
The summary of z scores showed that the minimum z-score2 is -4.6315 and the maximum is 4.638060.
Since the absolute values of z score greater than 3 are considered as outliers, which(abs(z.scores)>3) was used to identify the location of outliers.
- The observation in row 80 and 160 were considered as outliers.
- It highlighted that the LGA named Unicorporated in Victoria which had the proportions of female residents lower than 48% and the proportions of male residents higher than 52%.
- Unicorpotated Vic are areas without local gorvernment (Travel Victoria) at https://www.travelvictoria.com.au/victoria/localgovernment/.
- Since these outliers are also meaningful, they would also not be eliminated from the dataset.
boxplot(new_pop$`Population ratio`, main="Proportions of residents in Victoria (2018)", ylab = "percentage")

z.scores2 <- new_pop$`Population ratio` %>% scores(type = "z")
z.scores2 %>% summary()
Min. 1st Qu. Median Mean 3rd Qu. Max.
-4.631539 -0.594046 0.003261 0.000000 0.593007 4.638060
which(abs(z.scores2) >3)
[1] 80 160
new_pop[c(80,160), ]
Scan for total population in 2018 and 2019
The total population in 2018 and 2019 across LGAs were subsetted from the dataset for scanning for multivariate data.
The Mahalanobis distance was used to detect multivariate outliers for the subset pop_sub dataset using mvn().
According to Chi-square Q-Q plot, there are 72 outliers dectected in the subset. These outliers would then be handled by transforming values.
pop_sub <- new_pop %>% select(`Total_2018`, `Total_2019`)
results <- mvn(data = pop_sub, multivariateOutlierMethod = "quan", showOutliers = TRUE)

The location of outliers were shown below:
results$multivariateOutliers
Boxplot was used to scan numeric values for Growth rate for any potential outliers in the dataset.
There were four outliers recorded in the boxplot of Estimated residents which indicated the growth rate of more than 4.0.
The outliers were then detected by Z-score method using scores(type = "z").
The summary of z scores showed that the minimum z-score is -1.7945 and the maximum is 3.1031.
Since the absolute values of z score greater than 3 are considered as outliers, which(abs(z.scores)>3) was used to identify the location of outliers.
- The observation in row 76 and 156 were considered as outliers.
- It highlighted that the LGA named Wyndham in Victoria had the highest growth rate of population from 2018 to 2019.
- Since this output could bring interesting story for future analysis, these outliers would not be eliminated.
boxplot(new_pop$`Growth rate`, main = "Growth rate of LGAs in Victoria between 2018 and 2019")

z.scores3 <- new_pop$`Growth rate` %>% scores(type = "z")
z.scores3 %>% summary()
Min. 1st Qu. Median Mean 3rd Qu. Max.
-1.7945 -0.6311 -0.1422 0.0000 0.4218 3.1031
which(abs(z.scores3) >3 )
[1] 76 156
new_pop[c(76,156), ]
References
Australian Bureau of Statistics 2019, Population Estimates by Age and Sex, Local Government Areas (ASGS 2018), 2018, Australia’s statistic datasets, data file, Australian Government, Australian Bureau of Statistics, Melbourne, viewed 20 May 2020, https://www.abs.gov.au/AUSSTATS/abs@.nsf/DetailsPage/3235.02018?OpenDocument.
Australian Bureau of Statistics 2019, Population Estimates by Local Government Area, 2018 to 2019 , Australia’s statistic datasets, data file, Australian Government, Australian Bureau of Statistics, Melbourne, viewed 20 May 2020, https://www.abs.gov.au/AUSSTATS/abs@.nsf/DetailsPage/3218.02018-19?OpenDocument&fbclid=IwAR205_G_WwqXHZDy0SJxsXfJX_SbSNN4owAo_uYnsQ1ecqmhMsuTpaJ4xVw.
Parker, B 2002, Planning Analysis: Calculating Growth Rates, University of Oregon, viewed 30 May 2020, https://pages.uoregon.edu/rgp/PPPM613/class8a.htm#:~:text=The%20annual%20percentage%20growth%20rate,N%2C%20the%20number%20of%20years.&text=In%201980%2C%20the%20population%20in%20Lane%20County%20was%20250%2C000.
Travel Victoria 2020, Local Government Areas, Travel Victoria, viewed 30 May 2020, https://www.travelvictoria.com.au/victoria/localgovernment/.
LS0tCnRpdGxlOiAiTUFUSDIzNDkgU2VtZXN0ZXIgMSwgMjAyMCIKYXV0aG9yOiAiVGhhbmggTmdvYyBNYWkgVHJhbiBhbmQgUzM4MzUzOTkiCnN1YnRpdGxlOiBBc3NpZ25tZW50IDIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OgogICAgZGZfcHJpbnQ6IHBhZ2VkCi0tLQoKIyMgUmVxdWlyZWQgcGFja2FnZXMgCgpgYGB7cn0KbGlicmFyeShyZWFkeGwpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZWRpdHJ1bGVzKQpsaWJyYXJ5KG91dGxpZXJzKQpsaWJyYXJ5KE1WTikKYGBgCgoKIyMgRXhlY3V0aXZlIFN1bW1hcnkgCgpUaGUgZGF0YXNldHMgb2YgcmVnaW9uYWwgcG9wdWxhdGlvbiBieSBnZW5kZXIgYW5kIGFnZSBpbiAyMDE4LTIwMTkgd2VyZSBvYnRhaW5lZCBmcm9tIEF1c3RyYWxpYW4gQnVyZWF1IG9mIFN0YXRpc3RpY3MgdG8gZ2FpbiBtb3JlIGluc2lnaHRzIGFib3V0IGdlbmRlciByYXRpbyBpbiByZWdpb25hbCBhcmVhcyBpbiBWaWN0b3JpYSBhbmQgaG93IHRoZWlyIHBvcHVsYXRpb24gY2hhbmdlZCBmcm9tIDIwMTggdG8gMjAxOS4KClRoZSBmaXJzdCB0d28gZGF0YXNldHMgd2VyZSBpbXBvcnRlZCBhcyB4bHN4LiBmaWxlcyBmb3IgdGhlIHBvcHVsYXRpb24gZXN0aW1hdGVzIGJ5IHNleCBhY3Jvc3MgTG9jYWwgR292ZXJubWVudCBBcmVhcyAoTEdBKSBpbiAyMDE4IGFuZCBmaWx0ZXJlZCBmb3IgVmljdG9yaWFuIHJlZ2lvbi4gVGhlIGZpbmFsIGRhdGFzZXQgZGVzY3JpYmVkIHRoZSB0b3RhbCBwb3B1bGF0aW9uIGVzdGltYXRlcyBhY3Jvc3MgTEdBIGluIFZpY3RvcmlhIGluIDIwMTgtMjAxOS4gQWxsIG9mIHRoZSBpbXBvcnRlZCBkYXRhc2V0cyB3ZXJlIHRoZW4gam9pbmVkIHVzaW5nIExHQSBhcyBrZXkgdmFyaWFibGVzIGFuZCBjaGVja2VkIGZvciBkYXRhIHN0cnVjdHVyZS4gRGF0YSBjb252ZXJzaW9uIHdhcyB0YWtlbiBmcm9tIGNoYXJhY3RlciB0byBudW1lcmljIHZhbHVlcy4gVGhlIG1lcmdlZCBkYXRhc2V0IHdhcyB1bnRpZHkgYmVjYXVzZSBjb2x1bW4gaGVhZGVycyB3ZXJlIG5vdCB2YXJpYWJsZXMgc28gdGhhdCB0aWR5aW5nIGRhdGEgd2FzIGNhcnJpZWQgb3V0IGZvciBnZW5kZXIgY29sdW1ucyB3aXRoIHRoZSBlc3RpbWF0ZWQgbnVtYmVyIG9mIHJlc2lkZW50cyBhcyB2YWx1ZXMuICBUd28gbmV3IHZhcmlhYmxlcyB3ZXJlIGNyZWF0ZWQgd2l0aCBtdXRhdGUgZnVuY3Rpb24gdG8gZGV0ZXJtaW5lIHRoZSBwb3B1bGF0aW9uIHJhdGlvIGJ5IHNleCBhbmQgdGhlIHBvcHVsYXRpb24gZ3Jvd3RoIGJldHdlZW4gMjAxOC0yMDE5IGZvciBMR0FzLiAKClRoZSB0aWR5IGRhdGFzZXQgd2FzIHRoZW4gc2Nhbm5lZCBmb3IgbWlzc2luZyB2YWx1ZXMgYW5kIHNwZWNpYWwgdmFsdWVzIGZvciBhbGwgbnVtZXJpYyB2YWx1ZXMuIFRoZSBvYnZpb3VzIGVycm9ycyBvZiBudW1lcmljIGRhdGEgd2VyZSBhbHNvIHNjYW5uZWQgZm9yIHRoZSB0b3RhbCBwb3B1bGF0aW9uIG9mIDIwMTggYW5kIDIwMTkgdG8gZW5zdXJlIHRoYXQgdGhlcmUgd2VyZSBubyBuZWdhdGl2ZSB2YWx1ZXMgaW4gdGhlIHZhcmlhYmxlcy4gVGhlIG91dGxpZXJzIHdlcmUgZGV0ZWN0ZWQgZm9yIGZvbGxvd2luZyB2YXJpYWJsZXM6IEVzdGltYXRlZCByZXNpZGVudHMsIFBvcHVsYXRpb24gcmF0aW8gYW5kIEdyb3d0aCByYXRlIHVzaW5nIGJveHBsb3QuIFRoZSBsb2NhdGlvbiBvZiB0aGVzZSBvdXRsaWVycyB3YXMgaWRlbnRpZmllZCB1c2luZyB6LnNjb3JlcyBtZXRob2QgZm9yIHVuaXZhcmlhdGUgZGF0YS4gVGhlIGRhdGEgZnJvbSB0b3RhbCBwb3B1bGF0aW9uIG9mIDIwMTggYW5kIDIwMTkgd2FzIHNjYW5uZWQgZm9yIG91dGxpZXJzIGFzIG11bHRpdmFyaWF0ZSBkYXRhIHVzaW5nIE1haGFsYW5vYmlzIGRpc3RhbmNlIGFwcHJvYWNoIGFuZCB2aXN1YWxpc2VkIGJ5IENoaS1zcXVhcmUgUS1RIHBsb3QuIEZvbGxvd2luZyB0aGlzLCBzaW5jZSB0aGUgb3V0bGllcnMgd2VyZSBkZWNpZGVkIG5vdCB0byBlbGltaW5hdGUgZnJvbSB0aGUgZGF0YXNldCwgZGF0YSB0cmFuc2Zvcm1hdGlvbiB3YXMgdGFrZW4gZm9yIHRoZXNlIHR3byB2YXJpYWJsZXMgdXNpbmcgJGxuJCB0cmFuc2Zvcm1hdGlvbiB0byByZWR1Y2UgdGhlIHJpZ2h0IHNrZXduZXNzIGluIHRoZSBkaXN0cmlidXRpb25zLiBUaGUgZmluYWwgZGF0YXNldCB3YXMgcmVhZHkgZm9yIGZ1cnRoZXIgc3RhdGlzdGljYWwgYW5hbHlzaXMuIAoKCiMjIERhdGEgCgojIyMgRmlyc3QgZGF0YXNldAoKVGhlIFBvcHVsYXRpb24gRXN0aW1hdGVzIGJ5IEFnZSBhbmQgU2V4LCBMb2NhbCBHb3Zlcm5tZW50IEFyZWFzIChBU0dTIDIwMTgpLCAyMDE4IC54bHMgd2FzIGNvbGxlY3RlZCBmcm9tIEF1c3RyYWxpYW4gQnVyZWF1IG9mIFN0YXRpc3RpY3MgYXQgaHR0cHM6Ly93d3cuYWJzLmdvdi5hdS9BVVNTVEFUUy9hYnNALm5zZi9EZXRhaWxzUGFnZS8zMjM1LjAyMDE4P09wZW5Eb2N1bWVudCZmYmNsaWQ9SXdBUjBKT3phU2E2Y2xPMkhZYWUtMlpic2RYWmpOQnVrNVhLLVo1WUVNME5oQ3VvQ2pXLWZwOElrR2J0USwgd2hpY2ggbWVhc3VyZWQgdGhlIGVzdGltYXRlIG9mIHRoZSByZXNpZGVudGFsIHBvcHVsYXRpb24gaW4gQXVzdHJhbGlhIGJ5IGFnZSBhbmQgZ2VuZGVyIGNvcnJlc3BvbmRpbmcgdG8gU3RhdGUgYW5kIExvY2FsIEdvdmVybm1lbnQgQXJlYXMgYXQgMzAgSnVuZSAyMDE4LgoKVGhlIG9yaWdpbmFsIGRhdGFzZXQgIzEgd2FzIGZpcnN0bHkgaW1wb3J0ZWQgd2l0aCA3IHNraXBwZWQgcm93cyBkdWUgdG8gaW52YWxpZCBoZWFkZXJzIGFuZCBzdG9yZWQgYXMgYHBvcF9mZW1hbGVgIGZvciBzaGVldCBuYW1lZCAiVGFibGUgMiIuICAKClNpbmNlIHRoZSBzdHVkeSBmb2N1c2VkIG9uIHRvdGFsIHBvcHVsYXRpb24gYnkgZ2VuZGVyIGluIFZpY3RvcmlhLCB0aGUgUy9UIGNvZGUgdW5kZXIgYEFTR1MgMjAxOGAgZm9yIFZpY3RvcmlhIChTL1QgY29kZSA9IDIpIHdhcyBmaWx0ZXJlZCBmcm9tIHRoZSBvcmlnaW5hbCBkYXRhc2V0IHVzaW5nIGBmaWx0ZXIoKWAuIAoKVGhlIGNvbHVtbiBuYW1lcyBvZiBgdmljX3BvcF9mZW1hbGVgIHdlcmUgdGhlbiByZW5hbWVkIHVzaW5nIGBjb2xuYW1lcygpYC4KClNpbmNlIHRoZSBzdHVkeSB3b3VsZCBub3QgY29uc2lkZXIgdGhlIG51bWJlciBvZiByZXNpZGVudHMgdW5kZXIgQWdlIGdyb3VwIGNhdGVnb3JpZXMsIG9ubHkgYFRvdGFsIEZlbWFsZSBwb3B1bGF0aW9uYCBwZXIgTEdBICB3YXMgc2VsZWN0ZWQgZnJvbSBgdmljX3BvcF9mZW1hbGVgIHVzaW5nIGBzZWxlY3QoKWAgYW5kIGFzc2lnbmVkIGludG8gbmV3IG9iamVjdCBjYWxsZWQgYGRhdGFfZmVtYWxlYC4gCgpUaGUgYGRhdGFfZmVtYWxlYCBub3cgY29udGFpbmVkIGZvdXIgbWFpbiB2YXJpYWJsZXM6CgoqIGBTL1QgY29kZWAgW2NhdGVnb3JpY2FsXTogU3RhdGUvVGVycml0b3J5IGNvZGUgCiogYFMvVCBuYW1lYCBbY2hhcmFjdGVyXTogU3RhdGUvVGVycml0b3J5IG5hbWUKKiBgTEdBIGNvZGVgIFtjYXRlZ29yaWNhbF06IGNvZGUgb2YgTG9jYWwgR292ZXJubWVudCBBcmVhcyBwZXIgU3RhdGUgZS5nIDIwMTEwIGZvciBBbHBpbmUgKFMpCiogYExHQSBOYW1lYCBbY2hhcmFjdGVyXTogbmFtZSBvZiBMb2NhbCBHb3Zlcm5tZW50IEFyZWFzIHBlciBTdGF0ZSBlLmcgQWxwaW5lCiogYFRvdGFsIEZlbWFsZSBwb3B1bGF0aW9uYCBbbnVtZXJpY106IHRoZSB0b3RhbCBvZiBmZW1hbGUgcmVzaWRlbnRzIGZyb20gYWxsIGFnZSBncm91cHMgYnkgTEdBIAoKYGBge3J9CnBvcF9mZW1hbGUgPC0gcmVhZF9leGNlbCgiUG9wdWxhdGlvbiBFc3RpbWF0ZXMgYnkgQWdlIGFuZCBTZXgsIExvY2FsIEdvdmVybm1lbnQgQXJlYXMgKEFTR1MgMjAxOCksIDIwMTggLnhscyIsIHNoZWV0ID0gIlRhYmxlIDIiLCBza2lwID0gNykKdmljX3BvcF9mZW1hbGUgPC0gcG9wX2ZlbWFsZSAlPiUgZmlsdGVyKGBBU0dTIDIwMThgID09IDIpIApjb2xuYW1lcyh2aWNfcG9wX2ZlbWFsZSkgPC0gYygiUy9UIGNvZGUiLCAiUy9UIG5hbWUiLCAiTEdBIGNvZGUiLCAiTEdBIG5hbWUiLCAiQWdlIDAtNCIsICJBZ2UgNS05IiwgIkFnZSAxMC0xNCIsICJBZ2UgMTUtMTkiLCAiQWdlIDIwLTI0IiwgIkFnZSAyNS0yOSIsICJBZ2UgMzAtMzQiLCAiQWdlIDM1LTM5IiwgIkFnZSA0MC00NCIsICJBZ2UgNDUtNDkiLCAiQWdlIDUwLTU0IiwgIkFnZSA1NS01OSIsICJBZ2UgNjAtNjQiLCAiQWdlIDY1LTY5IiwgIkFnZSA3MC03NCIsICJBZ2UgNzUtNzkiLCAiQWdlIDgwLTg0IiwgIkFnZSA4NSBhbmQgb3ZlciIsICJUb3RhbCBGZW1hbGUgcG9wdWxhdGlvbiIpCmBgYAoKCmBgYHtyfQpkYXRhX2ZlbWFsZSA8LSB2aWNfcG9wX2ZlbWFsZSAlPiUgc2VsZWN0KGBTL1QgY29kZWAgLCBgUy9UIG5hbWVgLCBgTEdBIGNvZGVgLCBgTEdBIG5hbWVgLCBgVG90YWwgRmVtYWxlIHBvcHVsYXRpb25gKQpoZWFkKGRhdGFfZmVtYWxlKQpgYGAKCgojIyMgU2Vjb25kIGRhdGFzZXQgCgpUaGUgYHBvcF9tYWxlYCB3YXMgYWxzbyBpbXBvcnRlZCBmcm9tIFBvcHVsYXRpb24gRXN0aW1hdGVzIGJ5IEFnZSBhbmQgU2V4LCBMb2NhbCBHb3Zlcm5tZW50IEFyZWFzIChBU0dTIDIwMTgpLCAyMDE4IC54bHMgd2l0aCBzaGVldCBuYW1lZCAiVGFibGUgMSIuIAoKU2luY2UgdGhlIHN0dWR5IGZvY3VzZWQgb24gdG90YWwgcG9wdWxhdGlvbiBieSBnZW5kZXIgaW4gVmljdG9yaWEsIHRoZSBTL1QgY29kZSB1bmRlciBgQVNHUyAyMDE4YCBmb3IgVmljdG9yaWEgKFMvVCBjb2RlID0gMikgd2FzIGFsc28gZmlsdGVyZWQgZnJvbSBgcG9wX21hbGVgIHVzaW5nIGBmaWx0ZXIoKWAuIAoKVGhlIGNvbHVtbiBuYW1lcyBvZiBgdmljX3BvcF9tYWxlYCB3ZXJlIGFsc28gcmVuYW1lZCB1c2luZyBgY29sbmFtZXMoKWAuCgpTaW5jZSB0aGUgc3R1ZHkgd291bGQgbm90IGNvbnNpZGVyIHRoZSBudW1iZXIgb2YgcmVzaWRlbnRzIHVuZGVyIEFnZSBncm91cCBjYXRlZ29yaWVzLCBvbmx5IGBUb3RhbCBNYWxlIHBvcHVsYXRpb25gIHBlciBMR0EgIHdhcyBzZWxlY3RlZCBmcm9tIGB2aWNfcG9wX21hbGVgIHVzaW5nIGBzZWxlY3QoKWAgYW5kIGFzc2lnbmVkIGludG8gbmV3IG9iamVjdCBjYWxsZWQgYGRhdGFfbWFsZWAuIAoKVGhlIGBkYXRhX2ZlbWFsZWAgbm93IGNvbnRhaW5lZCBmb3VyIG1haW4gdmFyaWFibGVzOgoKKiBgUy9UIGNvZGVgIFtjYXRlZ29yaWNhbF06IFN0YXRlL1RlcnJpdG9yeSBjb2RlIAoqIGBTL1QgbmFtZWAgW2NoYXJhY3Rlcl06IFN0YXRlL1RlcnJpdG9yeSBuYW1lCiogYExHQSBjb2RlYCBbY2F0ZWdvcmljYWxdOiBjb2RlIG9mIExvY2FsIEdvdmVybm1lbnQgQXJlYXMgcGVyIFN0YXRlIGUuZyAyMDExMCBmb3IgQWxwaW5lIChTKQoqIGBMR0EgTmFtZWAgW2NoYXJhY3Rlcl06IG5hbWUgb2YgTG9jYWwgR292ZXJubWVudCBBcmVhcyBwZXIgU3RhdGUgZS5nIEFscGluZQoqIGBUb3RhbCBNYWxlIHBvcHVsYXRpb25gIFtudW1lcmljXTogdGhlIHRvdGFsIG9mIGZlbWFsZSByZXNpZGVudHMgZnJvbSBhbGwgYWdlIGdyb3VwcyBieSBMR0EgCgpgYGB7cn0KcG9wX21hbGUgPC0gcmVhZF9leGNlbCgiUG9wdWxhdGlvbiBFc3RpbWF0ZXMgYnkgQWdlIGFuZCBTZXgsIExvY2FsIEdvdmVybm1lbnQgQXJlYXMgKEFTR1MgMjAxOCksIDIwMTggLnhscyIsIHNoZWV0ID0gIlRhYmxlIDEiLCBza2lwID0gNykKdmljX3BvcF9tYWxlIDwtIHBvcF9tYWxlICU+JSBmaWx0ZXIoYEFTR1MgMjAxOGAgPT0gMikgCmNvbG5hbWVzKHZpY19wb3BfbWFsZSkgPC0gYygiUy9UIGNvZGUiLCAiUy9UIG5hbWUiLCAiTEdBIGNvZGUiLCAiTEdBIG5hbWUiLCAiQWdlIDAtNCIsICJBZ2UgNS05IiwgIkFnZSAxMC0xNCIsICJBZ2UgMTUtMTkiLCAiQWdlIDIwLTI0IiwgIkFnZSAyNS0yOSIsICJBZ2UgMzAtMzQiLCAiQWdlIDM1LTM5IiwgIkFnZSA0MC00NCIsICJBZ2UgNDUtNDkiLCAiQWdlIDUwLTU0IiwgIkFnZSA1NS01OSIsICJBZ2UgNjAtNjQiLCAiQWdlIDY1LTY5IiwgIkFnZSA3MC03NCIsICJBZ2UgNzUtNzkiLCAiQWdlIDgwLTg0IiwgIkFnZSA4NSBhbmQgb3ZlciIsICJUb3RhbCBNYWxlIHBvcHVsYXRpb24iKQpgYGAKCgpgYGB7cn0KZGF0YV9tYWxlIDwtIHZpY19wb3BfbWFsZSAlPiUgc2VsZWN0KGBTL1QgY29kZWAgLCBgUy9UIG5hbWVgLCBgTEdBIGNvZGVgLCBgTEdBIG5hbWVgLCBgVG90YWwgTWFsZSBwb3B1bGF0aW9uYCkKaGVhZChkYXRhX21hbGUpCmBgYAoKIyMjIFRoaXJkIGRhdGFzZXQKClRoZSBQb3B1bGF0aW9uIEVzdGltYXRlcyBieSBMb2NhbCBHb3Zlcm5tZW50IEFyZWEsIDIwMTggdG8gMjAxOSAueGxzIHdhcyBhbHNvIG9idGFpbmVkIGZyb20gQXVzdHJhbGlhbiBCdXJlYXUgb2YgU3RhdGlzdGljcyBhdCBodHRwczovL3d3dy5hYnMuZ292LmF1L0FVU1NUQVRTL2Fic0AubnNmL0RldGFpbHNQYWdlLzMyMTguMDIwMTgtMTk/T3BlbkRvY3VtZW50JmZiY2xpZD1Jd0FSMjA1X0dfV3dxWEhaRHkwU0p4c1hmSlhfU2JTTk40b3dBb191WW5zUTFlY3FtaE1zdVRwYUo0eFZ3LCB3aGljaCBpbmRpY2F0ZWQgdGhlIHRvdGFsIHBvcHVsYXRpb24gZm9yIDIwMTggYW5kIDIwMTkgYXMgd2VsbCBhcyBwcm9wb3J0aW9uIGZvciBkaWZmZXJlbnQgY29tcG9uZW50cyBvZiBwb3B1bGF0aW9uIGNoYW5nZSAobmF0dXJhbCBpbmNyZWFzZSwgbmV0IG92ZXJzZWFzIG1pZ3JhdGlvbiwgbmV0IGludGVybmFsIG1pZ3JhdGlvbikgYnkgTEdBIGFjcm9zcyBTdGF0ZXMuCgpUaGUgb3JpZ2luYWwgZGF0YXNldCAjMiB3YXMgZmlyc3RseSBpbXBvcnRlZCB3aXRoIHNoZWV0IG5hbWVkICJUYWJsZSAyIiAoVmljdG9yaWEpIGFuZCA2IHNraXBwZWQgcm93cyBkdWUgdG8gaW52YWxpZCBoZWFkZXJzIGFuZCBzdG9yZWQgYXMgYHBvcF92aWNgLgoKVGhlIHRvdGFsIHBvcHVsYXRpb24gb2YgVmljdG9yaWEgYnkgTEdBIGluIDIwMTggYW5kIDIwMTkgd2VyZSBzZWxlY3RlZCBmcm9tIHRoZSBvcmlnaW5hbCBkYXRhc2V0IGBwb3BfdmljYCB1c2luZyBgc2VsZWN0KClgIGFuZCBhc3NpZ25lZCBpbnRvIG5ldyBvYmplY3QgYG5ld19wb3BfdmljYGZvciBsYXRlciBtZXJnaW5nIGRhdGFzZXRzLgoKVGhlIGNvbHVtbiBuYW1lcyBvZiBgbmV3X3BvcF92aWNgIHdhcyByZW5hbWVkIGFuZCBub3cgaW5jbHVkZXMgdGhyZWUgdmFyaWFibGVzOgoKKiBgTEdBIGNvZGVgIFtjYXRlZ29yaWNhbF06IGNvZGUgb2YgTG9jYWwgR292ZXJubWVudCBBcmVhcyBpbiBWaWN0b3JpYQoqIGBMR0EgbmFtZWBbY2hhcmFjZXJdOiBuYW1lIG9mIExvY2FsIEdvdmVybm1lbnQgQXJlYXMgaW4gVmljdG9yaWEKKiBgMjAxOGBbbnVtZXJpY106IHRvdGFsIHBvcHVsYXRpb24gaW4gMjAxOCBieSBsR0EKKiBgMjAxOWBbbnVtZXJpY106IHRvdGFsIHBvcHVsYXRpb24gaW4gMjAxOSBieSBsR0EKCgpgYGB7cn0KcG9wX3ZpYyA8LSByZWFkX2V4Y2VsKCJQb3B1bGF0aW9uIEVzdGltYXRlcyBieSBMb2NhbCBHb3Zlcm5tZW50IEFyZWEsIDIwMTggdG8gMjAxOSAueGxzIiwgc2hlZXQgPSAiVGFibGUgMiIsIHNraXAgPSA2KQpuZXdfcG9wX3ZpYyA8LSBwb3BfdmljICU+JSBzZWxlY3QgKGMoMSwyLDMsNCkpIApjb2xuYW1lcyhuZXdfcG9wX3ZpYykgPC0gYygiTEdBIGNvZGUiLCAiTEdBIG5hbWUiLCAiVG90YWxfMjAxOCIsICJUb3RhbF8yMDE5IikKaGVhZChuZXdfcG9wX3ZpYykKCmBgYAoKCiMjIyBNZXJnaW5nIGRhdGFzZXRzCgpUaGUgYGRhdGFfZmVtYWxlYCBhbmQgYGRhdGFfbWFsZWAgd2VyZSBmaXJzdGx5IG1lcmdlZCB1c2luZyBgaW5uZXJfam9pbmAgd2hpY2ggdXNlZCBgUy9UIGNvZGVgLCBgUy9UIG5hbWVgLGBMR0EgY29kZWAgYW5kIGBMR0EgbmFtZWAgYXMga2V5IHZhcmlhYmxlcyBhbmQgc3RvcmVkIGFzIGBkYXRhX2dlbmRlcmAuCgoqIGBEYXRhX2dlbmRlcmAgZGVzY3JpYmVkIHRoZSB0b3RhbCBwb3B1bGF0aW9uIGJ5IGdlbmRlciBhY3Jvc3MgTG9jYWwgR292ZXJubWVudCBBcmVhcyBpbiBWaWN0b3JpYSBieSAyMDE4LgoKYGBge3J9CmRhdGFfZ2VuZGVyIDwtIGlubmVyX2pvaW4oZGF0YV9mZW1hbGUsIGRhdGFfbWFsZSxieSA9IGMoIlMvVCBjb2RlIiwgIlMvVCBuYW1lIiwgIkxHQSBjb2RlIiwgIkxHQSBuYW1lIikpCmhlYWQoZGF0YV9nZW5kZXIpCmBgYAoKVGhlIGZpbmFsIGRhdGFzZXQgYHBvcF92aWNfZ2VuZGVyYCB3YXMgdGhlbiBjcmVhdGVkIGJ5IG1lcmdpbmcgYGRhdGFfZ2VuZGVyYCBhbmQgYG5ld19wb3BfdmljYCB1c2luZyBgaW5uZXJfam9pbmAgd2hpY2ggdXNlZCBib3RoIGBMR0EgY29kZWAgYW5kIGBMR0EgbmFtZWAgYXMga2V5IHZhcmlhYmxlcy4gCgpUaGUgZmluYWwgZGF0YXNldCBub3cgaW5jbHVkZXMgOCB2YXJpYWJsZXM6CgoqIGBTL1QgY29kZWAgW2NhdGVnb3JpY2FsXTogU3RhdGUvVGVycml0b3J5IGNvZGUgCiogYFMvVCBuYW1lYCBbY2hhcmFjdGVyXTogU3RhdGUvVGVycml0b3J5IG5hbWUKKiBgTEdBIGNvZGVgIFtjYXRlZ29yaWNhbF06IGNvZGUgb2YgTG9jYWwgR292ZXJubWVudCBBcmVhcyBwZXIgU3RhdGUgZS5nIDIwMTEwIGZvciBBbHBpbmUgKFMpCiogYExHQSBOYW1lYCBbY2hhcmFjdGVyXTogbmFtZSBvZiBMb2NhbCBHb3Zlcm5tZW50IEFyZWFzIHBlciBTdGF0ZSBlLmcgQWxwaW5lCiogYFRvdGFsIEZlbWFsZSBwb3B1bGF0aW9uYCBbbnVtZXJpY106IHRoZSB0b3RhbCBvZiBmZW1hbGUgcmVzaWRlbnRzIGJ5IExHQQoqIGBUb3RhbCBNYWxlIHBvcHVsYXRpb25gIFtudW1lcmljXTogdGhlIHRvdGFsIG9mIG1hbGUgcmVzaWRlbnRzIGJ5IExHQQoqIGBUb3RhbF8yMDE4YFtudW1lcmljXTogdG90YWwgcG9wdWxhdGlvbiBpbiAyMDE4IGJ5IGxHQQoqIGBUb3RhbF8yMDE5YFtudW1lcmljXTogdG90YWwgcG9wdWxhdGlvbiBpbiAyMDE5IGJ5IGxHQQoKYGBge3J9CnBvcF92aWNfZ2VuZGVyIDwtIGlubmVyX2pvaW4oZGF0YV9nZW5kZXIsIG5ld19wb3BfdmljLCBieSA9IGMoIkxHQSBjb2RlIiwgIkxHQSBuYW1lIikpCmhlYWQocG9wX3ZpY19nZW5kZXIpCmBgYAoKIyMgVW5kZXJzdGFuZCAKClRoZSBkaW1lbnNpb24gb2YgdGhlIGRhdGFzZXQgd2FzIGNoZWNrZWQgdXNpbmcgYGRpbSgpYCwgd2hpY2ggcmVzdWx0ZWQgYXQgODAgb2JzZXJ2YXRpb25zIGFuZCA4IHZhcmlhYmxlcy4KClRoZSBzdHJ1Y3R1cmUgb2YgYHBvcF92aWNfZ2VuZGVyYCBzaG93ZWQgdGhhdCBhbGwgdmFyaWFibGVzIHdlcmUgaW4gY2hhcmFjdGVyIHR5cGUuIFRoZXJlZm9yZSwgdGhlIGNvbnZlcnNpb24gdG8gbnVtZXJpYyBkYXRhIHR5cGUgYW5kIGZhY3RvciB3ZXJlIG5lZWRlZC4KCiogVGhlIGNvbnZlcnNpb24gb2YgbXVsdGlwbGUgY29sdW1ucyB0byBudW1lcmljIGRhdGEgdHlwZSB3YXMgZG9uZSBieSB1c2luZyBgc2FwcGx5YCB3aXRoIGBhcy5udW1lcmljYC4KKiBUaGUgY29udmVyc2lvbiBvZiBgTEdBIGNvZGVgIHRvIGZhY3RvciB2YXJpYWJsZSB3YXMgZG9uZSBieSB1c2luZyBgYXMuZmFjdG9yYCB3aXRob3V0IG9yZGVyZWQuCgoKYGBge3J9CmRpbShwb3BfdmljX2dlbmRlcikKc3RyKHBvcF92aWNfZ2VuZGVyKQoKY29sLm51bSA8LSBjKCJTL1QgY29kZSIsICJUb3RhbCBGZW1hbGUgcG9wdWxhdGlvbiIsICJUb3RhbCBNYWxlIHBvcHVsYXRpb24iLCAiVG90YWxfMjAxOCIsICJUb3RhbF8yMDE5IikKcG9wX3ZpY19nZW5kZXJbY29sLm51bV0gPC0gc2FwcGx5KHBvcF92aWNfZ2VuZGVyW2NvbC5udW1dLGFzLm51bWVyaWMpCnBvcF92aWNfZ2VuZGVyJGBMR0EgY29kZWAgPC0gYXMuZmFjdG9yKHBvcF92aWNfZ2VuZGVyJGBMR0EgY29kZWApCmBgYAoKCmBgYHtyfQpzdHIocG9wX3ZpY19nZW5kZXIpCgpgYGAKCgojIwlUaWR5ICYgTWFuaXB1bGF0ZSBEYXRhIEkgCgpUaGUgYHBvcF92aWNfZ2VuZGVyYCBkYXRhc2V0IHdhcyB1bnRpZHkgYmVjYXVzZSBgVG90YWwgRmVtYWxlIHBvcHVsYXRpb25gIGFuZCBgVG90YWwgTWFsZSBwb3B1bGF0aW9uYCBhcyBjb2x1bW4gaGVhZGVycyB3ZXJlIG5vdCB2YXJpYWJsZXMuIAoKYGdhdGhlcigpYCB3YXMgdXNlZCB0byBnYXRoZXIgZmVtYWxlIGFuZCBtYWxlIGNvbHVtbnMgaW50byBvbmUgc2luZ2xlIGNvbHVtbiBuYW1lZCBgR2VuZGVyYCBhbmQgc3RvcmVkIHRoZSB2YWx1ZXMgdW5kZXIgYEVzdGltYXRlZCByZXNpZGVudHNgIGNvbHVtbi4KCiogYEdlbmRlcmAgd2FzIHRoZW4gY2hlY2sgd2hldGhlciBpdCB3YXMgYSBmYWN0b3IgdmFyaWFibGUgdXNpbmcgYGlzLmZhY3RvcigpYC4KICAgICsgU2luY2UgdGhlIHZhcmlhYmxlIHdhcyBub3QgYSBmYWN0b3IsIHRoZSBjb252ZXJzaW9uIGZyb20gY2hhcmFjdGVyIHRvIGZhY3RvciB3YXMgdGFrZW4gYnkgdXNpbmcgYGFzLmZhY3RvcmAuCiAgICArIFRoZSBsZXZlbHMgb2YgYEdlbmRlcmAgd2FzIGNsYXNzaWZpZWQgdXNpbmcgYGZhY3RvcmAgd2l0aCBsYWJlbHMuCgoqIGBFc3RpbWF0ZWQgcmVzaWRlbnRzYCBzaG93ZWQgdGhlIG51bWJlciBvZiByZXNpZGVudHMgYnkgZ2VuZGVyIGZvciBlYWNoIExvY2FsIEdvdmVybm1lbnQgQXJlYXMgb24gVmljdG9yaWEgYnkgMjAxOC4gCgpBIHRpZHkgZGF0YXNldCB3YXMgdGhlbiBzdG9yZWQgYXMgYHRpZHlfcG9wX2dlbmRlcmAuCgoqIFRoZSBjb2x1bW5zIG9mIHRoZSB0aWR5IGRhdGFzZXQgd2VyZSByZWFycmFuZ2VkIHdpdGggYEdlbmRlcmAgYW5kIGBFc3RpbWF0ZWQgcmVzaWRlbnRzYCBiZWZvcmUgYFRvdGFsXzIwMThgIGFuZCBgVG90YWxfMjAxOWAuCgoKCmBgYHtyfQp0aWR5X3BvcF9nZW5kZXIgPC0gcG9wX3ZpY19nZW5kZXIgJT4lIGdhdGhlcihgVG90YWwgRmVtYWxlIHBvcHVsYXRpb25gLCBgVG90YWwgTWFsZSBwb3B1bGF0aW9uYCwgIGtleSA9ICJHZW5kZXIiLCB2YWx1ZSA9ICJFc3RpbWF0ZWQgcmVzaWRlbnRzIikKaGVhZCh0aWR5X3BvcF9nZW5kZXIpCmBgYAoKCmBgYHtyfQppcy5mYWN0b3IodGlkeV9wb3BfZ2VuZGVyJEdlbmRlcikKdGlkeV9wb3BfZ2VuZGVyJEdlbmRlciA8LSBhcy5mYWN0b3IodGlkeV9wb3BfZ2VuZGVyJEdlbmRlcikKdGlkeV9wb3BfZ2VuZGVyJEdlbmRlcjwtIGZhY3Rvcih0aWR5X3BvcF9nZW5kZXIkR2VuZGVyLCBsZXZlbCA9IGMoIlRvdGFsIEZlbWFsZSBwb3B1bGF0aW9uIiwgIlRvdGFsIE1hbGUgcG9wdWxhdGlvbiIpLCBsYWJlbHMgPSBjKCJmZW1hbGUiLCAibWFsZSIpKQpgYGAKCgpgYGB7cn0KdGlkeV9wb3BfZ2VuZGVyIDwtIHRpZHlfcG9wX2dlbmRlclsgLCBjKDEsMiwzLDQsNyw4LDUsNildCmBgYAoKYGBge3J9CmhlYWQodGlkeV9wb3BfZ2VuZGVyKQpgYGAKCiMjCVRpZHkgJiBNYW5pcHVsYXRlIERhdGEgSUkgCgpUaGUgYFBvcHVsYXRpb24gcmF0aW9gIHdhcyBjcmVhdGVkIHRvIGVzdGltYXRlIHRoZSBwcm9wb3J0aW9uIG9mIGZlbWFsZSBhbmQgbWFsZSByZXNpZGVudHMgYnkgdG90YWwgcG9wdWxhdGlvbiBwZXIgTG9jYWwgR292ZXJubWVudCBBcmVhcyBpbiBWaWN0b3JpYSBieSAyMDE4LiAKCiogUG9wdWxhdGlvbiByYXRpbyBjYWxjdWxhdGVkIGJ5IGRpdmlkaW5nIHRoZSBgRXN0aW1hdGVkIHJlc2lkZW50c2Agd2l0aCB0b3RhbCBwb3B1bGF0aW9uIGluIGAyMDE4YCBhbmQgY29udmVydGluZyBpbnRvIHByb3BvcnRpb25zLgoKKiBUaGUgcmF0aW8gaW5kaWNhdGVkIHRoYXQgdGhlcmUgd2VyZSBoaWdoZXIgbWVhbiBwcm9wb3J0aW9ucyBvZiBmZW1hbGUgcmVzaWRlbnRzIGFjcm9zcyBMR0EgaW4gVmljdG9yaWEgYnkgMjAxOCB1c2luZyBgZ3JvdXBfYnkoKWAgYW5kIGBzdW1tYXJpc2UoKWAuIAoKVGhlIGBHcm93dGggcmF0ZWAgd2FzIGFsc28gbXV0YXRlZCB0byBkZXRlcm1pbmUgdGhlIGdyb3d0aCByYXRlIG9mIHBvcHVsYXRpb24gYmV0d2VlbiAyMDE4IGFuZCAyMDE5IGZvciBldmVyeSBMb2NhbCBHb3Zlcm5tZW50IEFyZWFzIGluIFZpY3RvcmlhLgoKKiBHcm93dGggcmF0ZSBjYWxjdWxhdGVkIGJ5IGZvbGxvd2luZyB3aXRoIHRoZSBlcXVhdGlvbiBzb3VyY2VkIGZyb20gW1VuaXZlcnNpdHkgb2YgT3JlZ29uXShodHRwczovL3BhZ2VzLnVvcmVnb24uZWR1L3JncC9QUFBNNjEzL2NsYXNzOGEuaHRtIzp+OnRleHQ9VGhlJTIwYW5udWFsJTIwcGVyY2VudGFnZSUyMGdyb3d0aCUyMHJhdGUsTiUyQyUyMHRoZSUyMG51bWJlciUyMG9mJTIweWVhcnMuJnRleHQ9SW4lMjAxOTgwJTJDJTIwdGhlJTIwcG9wdWxhdGlvbiUyMGluJTIwTGFuZSUyMENvdW50eSUyMHdhcyUyMDI1MCUyQzAwMCkuCgo8Y2VudGVyPiBHcm93dGggcmF0ZSA9ICRcZnJhY3tQcmVzZW50IHZhbHVlIC0gUGFzdCB2YWx1ZX17UGFzdCB2YWx1ZX0qMTAwJCAKPC9jZW50ZXI+CgoKKiBUaGlzIGdyb3d0aCByYXRlIHZhbHVlIHdvdWxkIGJlIHVzZWZ1bCBmb3IgcHJlZGljdGluZyBmdXR1cmUgcG9wdWxhdGlvbiBpbiBkaWZmZXJlbnQgTEdBcyB1c2luZyBhbiBleHBvbmVudGlhbCBncm93dGggbW9kZWwuCgpgYGB7ciBlY2hvPVRSVUV9Cm5ld19wb3AgPC0gdGlkeV9wb3BfZ2VuZGVyICU+JSBtdXRhdGUoIlBvcHVsYXRpb24gcmF0aW8iID0gcm91bmQoKGBFc3RpbWF0ZWQgcmVzaWRlbnRzYC9gVG90YWxfMjAxOGApKjEwMCwgMiksICJHcm93dGggcmF0ZSIgPSAoKGBUb3RhbF8yMDE5YCAtIGBUb3RhbF8yMDE4YCkvYFRvdGFsXzIwMThgKSoxMDApCmhlYWQobmV3X3BvcCkKYGBgCgoKYGBge3IgZWNobz1UUlVFfQpuZXdfcG9wICU+JSBncm91cF9ieShgR2VuZGVyYCkgJT4lIHN1bW1hcmlzZShhdmVyZ2FnZSA9IG1lYW4oYFBvcHVsYXRpb24gcmF0aW9gLCBuYS5ybSA9IFRSVUUpKQpgYGAKCgojIwlTY2FuIEkgCgojIyMgU2NhbiBmb3IgbWlzc2luZyB2YWx1ZXMKClRoZSBtaXNzaW5nIHZhbHVlcyAoTkEpIHdlcmUgc2Nhbm5lZCBmb3IgYWxsIG51bWVyaWMgdmFsdWVzIGFuZCBvdXRwdXQgYXMgdGhlIHRvdGFsIG51bWJlciBvZiBtaXNzaW5nIHZhbHVlcyBmb3IgZWFjaCBjb2x1bW4gdXNpbmcgYHN1bShpcy5uYSgpKWAuIAoKVGhlIGBzYXBwbHkoKWAgd2FzIHVzZWQgdG8gYXBwbHkgYHN1bShpcy5uYSgpKWAgaW4gbXVsdGlwbGUgY29sdW1ucyBmb3Igc2Nhbm5pbmcuCgpUaGVyZSBpcyBubyBOQSB2YWx1ZXMgZGV0ZWN0ZWQgaW4gdGhlIGRhdGFzZXQgYG5ld19wb3BgLiAKCmBgYHtyfQpzYXBwbHkobmV3X3BvcCwgZnVuY3Rpb24oeCkgc3VtKGlzLm5hKHgpKSkKYGBgCgojIyMgU2NhbiBmb3Igc3BlY2lhbCB2YWx1ZXMKClRoZSBgaXMuc3BlY2lhbGAgZnVuY3Rpb24gaXMgY3JlYXRlZCB0byBjaGVjayBmb3Igc3BlY2lhbCB2YWx1ZXMgdGhhdCBhcmUgZWl0aGVyIGluZmluaXRlIHZhbHVlcyBvciBOb3QgYSBOdW1iZXIgdmFsdWVzIChuYW4pIGluIHRoZSBkYXRhc2V0LgoKVGhlIHNwZWNpYWwgdmFsdWVzIHdlcmUgc2Nhbm5lZCBmb3IgYWxsIG51bWVyaWMgZGF0YSBpbiBgbmV3X3BvcGAgZGF0YXNldCBhbmQgdGhlIG91dHB1dCBhcyB0aGUgdG90YWwgbnVtYmVyIG9mIHNwZWNpYWwgdmFsdWVzIGZvciBlYWNoIGNvbHVtbnMgdXNpbmcgYHN1bShpcy5zcGVjaWFsKCkpYC4KClRoZSBgc2FwcGx5KClgIHdhcyBhbHNvIHVzZWQgdG8gYXBwbHkgYHN1bShpcy5zcGVjaWFsKCkpYCBpbiBtdWx0aXBsZSBjb2x1bW5zIGZvciBzY2FubmluZyBzcGVjaWFsIHZhbHVlcy4KClRoZXJlIGlzIG5vIHNwZWNpYWwgdmFsdWUgZGV0ZWN0ZWQgaW4gdGhlIGRhdGFzZXQuIAoKCmBgYHtyfQppcy5zcGVjaWFsIDwtIGZ1bmN0aW9uKHgpewppZiAoaXMubnVtZXJpYyh4KSkgKGlzLmluZmluaXRlKHgpIHwgaXMubmFuKHgpKQp9CmBgYAoKCmBgYHtyfQpzYXBwbHkobmV3X3BvcCwgZnVuY3Rpb24oeCkgc3VtKGlzLnNwZWNpYWwoeCkpKQpgYGAKCiMjIyBTY2FuIGZvciBvYnZpdm91cyBlcnJvcnMKClRoZSBkYXRhIGluY29uc2lzdGVuY2llcyB3ZXJlIGNoZWNrZWQgZm9yIHRoZSBkYXRhc2V0IGJ5IGdlbmVyYXRpbmcgYSBydWxlIGZvciBudW1lcmljIGRhdGEuIFRoZSBydWxlIGlzIG5vIG5lZ2F0aXZlIG51bWVyaWMgdmFsdWVzIGluIHRoZSB0b3RhbCBwb3B1bGF0aW9uIG9mIDIwMTggYW5kIDIwMTkuCgpUaGUgcnVsZSB3YXMgY3JlYXRlZCB1c2luZyBgZWRpdHNldCgpYCBhbmQgYXNzaWduZWQgaXQgaW50byBgcnVsZWAuCgpUaGUgcnVsZSB3YXMgdGhlbiBhcHBsaWVkIHRvIHRoZSBkYXRhc2V0IHVzaW5nIGB2aW9sYXRlZEVkaXRzKClgIHRvIG91dHB1dCBsb2dpY2FsIHZhbHVlcyB3aGVyZSBUUlVFIGlzIHdoZXJlIGluY29uc2lzdGVuY2llcyBhcmUgZXhpc3RlZC4KCiogVGhlIG91dHB1dCB0dXJuZWQgb3V0IHRvIGhhdmUgbm8gZGF0YSBpbmNvbnNpc3RlbmNpZXMgaW4gdGhlIGRhdGFzZXQuIApgYGB7cn0KcnVsZSA8LSBlZGl0c2V0KGMoIlRvdGFsXzIwMTggPiAwIiwgIlRvdGFsXzIwMTkgPiAwIikpCnJ1bGUKYGBgCmBgYHtyfQp2aW9sYXRlZEVkaXRzKHJ1bGUsIG5ld19wb3ApIApgYGAKCgojIwlTY2FuIElJCgojIyMgIFNjYW4gZm9yIG51bWJlciBhbmQgcHJvcG9ydGlvbnMgb2YgcmVzaWRlbnRzIGJ5IGdlbmRlciAKCmBCb3hwbG90YCB3YXMgdXNlZCB0byBzY2FuIG51bWVyaWMgdmFsdWVzIGZyb20gYEVzdGltYXRlZCByZXNpZGVudHNgIGFuZCBgUG9wdWxhdGlvbiByYXRpb2AgY29sdW1ucyBmb3IgYW55IHBvdGVudGlhbCBvdXRsaWVycyBpbiB0aGUgZGF0YXNldC4KClRoZXJlIHdlcmUgdHdvIG91dGxpZXJzIHJlY29yZGVkIGluIHRoZSBib3hwbG90IG9mIGBFc3RpbWF0ZWQgcmVzaWRlbnRzYCB3aGljaCByZXNwb25kZWQgZm9yIG1vcmUgdGhhbiAxNTAsMDAwIHJlc2lkZW50cyBhY3Jvc3MgTEdBcyBpbiBWaWN0b3JpYS4KClRoZSBvdXRsaWVycyB3ZXJlIHRoZW4gZGV0ZWN0ZWQgYnkgWi1zY29yZSBtZXRob2QgdXNpbmcgYHNjb3Jlcyh0eXBlID0gInoiKWAuCgpUaGUgc3VtbWFyeSBvZiB6IHNjb3JlcyBzaG93ZWQgdGhhdCB0aGUgbWluaW11bSB6LXNjb3JlIGlzIC0xLjA0MDggYW5kIHRoZSBtYXhpbXVtIGlzIDMuMzk1LgoKU2luY2UgdGhlIGFic29sdXRlIHZhbHVlcyBvZiB6IHNjb3JlIGdyZWF0ZXIgdGhhbiAzIGFyZSBjb25zaWRlcmVkIGFzIG91dGxpZXJzLCBgd2hpY2goYWJzKHouc2NvcmVzKT4zKWAgd2FzIHVzZWQgdG8gaWRlbnRpZnkgdGhlIGxvY2F0aW9uIG9mIG91dGxpZXJzLgoKKiBUaGUgb2JzZXJ2YXRpb24gaW4gcm93IDE0IGFuZCA5NCB3ZXJlIGNvbnNpZGVyZWQgYXMgb3V0bGllcnMuCiogSXQgaGlnaGxpZ2h0ZWQgdGhhdCB0aGUgTEdBIG5hbWVkIENhc2V5IGluIFZpY3RvcmlhIGhhZCB0aGUgbW9zdCBvdXRzdGFuZGluZyBwb3B1bGF0aW9uIHdoaWNoIGlzIG1vcmUgMTUwLDAwMCByZXNpZGVudHMgYnkgZ2VuZGVyIGxpdmluZyBpbiB0aGUgYXJlYS4KKiBTaW5jZSB0aGlzIG91dHB1dCBtaWdodCBiZSBpbnRlcmVzdGluZyBmb3IgZnV0dXJlIHF1ZXN0aW9ucywgdGhlc2Ugb3V0bGllcnMgd291bGQgbm90IGJlIGVsaW1pbmF0ZWQuCiAgICAKYGBge3IsIGZpZy53aWR0aD0gN30KYm94cGxvdChuZXdfcG9wJGBFc3RpbWF0ZWQgcmVzaWRlbnRzYCwgbWFpbj0iTnVtYmVyIG9mIHJlc2lkZW50cyBpbiBWaWN0b3JpYSAoMjAxOCkiLCB5bGFiID0gIlJlc2lkZW50cyIpCmBgYAoKCmBgYHtyfQp6LnNjb3JlcyA8LSBuZXdfcG9wJGBFc3RpbWF0ZWQgcmVzaWRlbnRzYCAlPiUgIHNjb3Jlcyh0eXBlID0gInoiKQp6LnNjb3JlcyAlPiUgc3VtbWFyeSgpCmBgYAoKYGBge3J9CndoaWNoKGFicyh6LnNjb3JlcykgPjMgKQpuZXdfcG9wW2MoMTQsOTQpLCBdCmBgYAoKCmBgYHtyfQpsZW5ndGggKHdoaWNoKCBhYnMoei5zY29yZXMpID4zICkpCmBgYAoKClRoZXJlIHdlcmUgZm91ciBvdXRsaWVycyByZWNvcmRlZCBpbiB0aGUgYm94cGxvdCBvZiBgUG9wdWxhdGlvbiByYXRpb2Agd2hpY2ggd2FzIHJhbmdpbmcgZnJvbSBlaXRoZXIgbW9yZSB0aGFuIDUyJSBvciBsZXNzIHRoYW4gNDglIG9mIHJlc2lkZW50cyBsaXZpbmcgYWNyb3NzIExHQXMuIAoKVGhlIG91dGxpZXJzIHdlcmUgdGhlbiBkZXRlY3RlZCBieSBaLXNjb3JlIG1ldGhvZCB1c2luZyBgc2NvcmVzKHR5cGUgPSAieiIpYC4KClRoZSBzdW1tYXJ5IG9mIHogc2NvcmVzIHNob3dlZCB0aGF0IHRoZSBtaW5pbXVtIHotc2NvcmUyIGlzIC00LjYzMTUgYW5kIHRoZSBtYXhpbXVtIGlzIDQuNjM4MDYwLgoKU2luY2UgdGhlIGFic29sdXRlIHZhbHVlcyBvZiB6IHNjb3JlIGdyZWF0ZXIgdGhhbiAzIGFyZSBjb25zaWRlcmVkIGFzIG91dGxpZXJzLCBgd2hpY2goYWJzKHouc2NvcmVzKT4zKWAgd2FzIHVzZWQgdG8gaWRlbnRpZnkgdGhlIGxvY2F0aW9uIG9mIG91dGxpZXJzLgoKKiBUaGUgb2JzZXJ2YXRpb24gaW4gcm93IDgwIGFuZCAxNjAgd2VyZSBjb25zaWRlcmVkIGFzIG91dGxpZXJzLgoqIEl0IGhpZ2hsaWdodGVkIHRoYXQgdGhlIExHQSBuYW1lZCBVbmljb3Jwb3JhdGVkIGluIFZpY3RvcmlhIHdoaWNoIGhhZCB0aGUgcHJvcG9ydGlvbnMgb2YgZmVtYWxlIHJlc2lkZW50cyBsb3dlciB0aGFuIDQ4JSBhbmQgdGhlIHByb3BvcnRpb25zIG9mIG1hbGUgcmVzaWRlbnRzIGhpZ2hlciB0aGFuIDUyJS4KKiBVbmljb3Jwb3RhdGVkIFZpYyBhcmUgYXJlYXMgd2l0aG91dCBsb2NhbCBnb3J2ZXJubWVudCAoVHJhdmVsIFZpY3RvcmlhKSBhdCAgaHR0cHM6Ly93d3cudHJhdmVsdmljdG9yaWEuY29tLmF1L3ZpY3RvcmlhL2xvY2FsZ292ZXJubWVudC8uCiogU2luY2UgdGhlc2Ugb3V0bGllcnMgYXJlIGFsc28gbWVhbmluZ2Z1bCwgdGhleSB3b3VsZCBhbHNvIG5vdCBiZSBlbGltaW5hdGVkIGZyb20gdGhlIGRhdGFzZXQuCgpgYGB7cn0KYm94cGxvdChuZXdfcG9wJGBQb3B1bGF0aW9uIHJhdGlvYCwgbWFpbj0iUHJvcG9ydGlvbnMgb2YgcmVzaWRlbnRzIGluIFZpY3RvcmlhICgyMDE4KSIsIHlsYWIgPSAicGVyY2VudGFnZSIpCmBgYAoKCmBgYHtyfQp6LnNjb3JlczIgPC0gbmV3X3BvcCRgUG9wdWxhdGlvbiByYXRpb2AgJT4lICBzY29yZXModHlwZSA9ICJ6IikKei5zY29yZXMyICU+JSBzdW1tYXJ5KCkKYGBgCgoKYGBge3J9CndoaWNoKGFicyh6LnNjb3JlczIpID4zKQpgYGAKYGBge3J9Cm5ld19wb3BbYyg4MCwxNjApLCBdCmBgYAoKIyMjIFNjYW4gZm9yIHRvdGFsIHBvcHVsYXRpb24gaW4gMjAxOCBhbmQgMjAxOQoKVGhlIHRvdGFsIHBvcHVsYXRpb24gaW4gMjAxOCBhbmQgMjAxOSBhY3Jvc3MgTEdBcyB3ZXJlIHN1YnNldHRlZCBmcm9tIHRoZSBkYXRhc2V0IGZvciBzY2FubmluZyBmb3IgbXVsdGl2YXJpYXRlIGRhdGEuIAoKVGhlIE1haGFsYW5vYmlzIGRpc3RhbmNlIHdhcyB1c2VkIHRvIGRldGVjdCBtdWx0aXZhcmlhdGUgb3V0bGllcnMgZm9yIHRoZSBzdWJzZXQgYHBvcF9zdWJgIGRhdGFzZXQgdXNpbmcgYG12bigpYC4KCkFjY29yZGluZyB0byBDaGktc3F1YXJlIFEtUSBwbG90LCB0aGVyZSBhcmUgNzIgb3V0bGllcnMgZGVjdGVjdGVkIGluIHRoZSBzdWJzZXQuIFRoZXNlIG91dGxpZXJzIHdvdWxkIHRoZW4gYmUgaGFuZGxlZCBieSB0cmFuc2Zvcm1pbmcgdmFsdWVzLgoKYGBge3J9CnBvcF9zdWIgPC0gbmV3X3BvcCAlPiUgc2VsZWN0KGBUb3RhbF8yMDE4YCwgYFRvdGFsXzIwMTlgKQpyZXN1bHRzIDwtIG12bihkYXRhID0gcG9wX3N1YiwgbXVsdGl2YXJpYXRlT3V0bGllck1ldGhvZCA9ICJxdWFuIiwgc2hvd091dGxpZXJzID0gVFJVRSkKYGBgCgpUaGUgbG9jYXRpb24gb2Ygb3V0bGllcnMgd2VyZSBzaG93biBiZWxvdzoKCmBgYHtyfQpyZXN1bHRzJG11bHRpdmFyaWF0ZU91dGxpZXJzCmBgYAoKCmBCb3hwbG90YCB3YXMgdXNlZCB0byBzY2FuIG51bWVyaWMgdmFsdWVzIGZvciBgR3Jvd3RoIHJhdGVgIGZvciBhbnkgcG90ZW50aWFsIG91dGxpZXJzIGluIHRoZSBkYXRhc2V0LgoKVGhlcmUgd2VyZSBmb3VyIG91dGxpZXJzIHJlY29yZGVkIGluIHRoZSBib3hwbG90IG9mIGBFc3RpbWF0ZWQgcmVzaWRlbnRzYCB3aGljaCBpbmRpY2F0ZWQgdGhlIGdyb3d0aCByYXRlIG9mIG1vcmUgdGhhbiA0LjAuCgpUaGUgb3V0bGllcnMgd2VyZSB0aGVuIGRldGVjdGVkIGJ5IFotc2NvcmUgbWV0aG9kIHVzaW5nIGBzY29yZXModHlwZSA9ICJ6IilgLgoKVGhlIHN1bW1hcnkgb2YgeiBzY29yZXMgc2hvd2VkIHRoYXQgdGhlIG1pbmltdW0gei1zY29yZSBpcyAtMS43OTQ1IGFuZCB0aGUgbWF4aW11bSBpcyAzLjEwMzEuCgpTaW5jZSB0aGUgYWJzb2x1dGUgdmFsdWVzIG9mIHogc2NvcmUgZ3JlYXRlciB0aGFuIDMgYXJlIGNvbnNpZGVyZWQgYXMgb3V0bGllcnMsIGB3aGljaChhYnMoei5zY29yZXMpPjMpYCB3YXMgdXNlZCB0byBpZGVudGlmeSB0aGUgbG9jYXRpb24gb2Ygb3V0bGllcnMuCgoqIFRoZSBvYnNlcnZhdGlvbiBpbiByb3cgNzYgYW5kIDE1NiB3ZXJlIGNvbnNpZGVyZWQgYXMgb3V0bGllcnMuCiogSXQgaGlnaGxpZ2h0ZWQgdGhhdCB0aGUgTEdBIG5hbWVkIFd5bmRoYW0gaW4gVmljdG9yaWEgaGFkIHRoZSBoaWdoZXN0IGdyb3d0aCByYXRlIG9mIHBvcHVsYXRpb24gZnJvbSAyMDE4IHRvIDIwMTkuCiogU2luY2UgdGhpcyBvdXRwdXQgY291bGQgYnJpbmcgaW50ZXJlc3Rpbmcgc3RvcnkgZm9yIGZ1dHVyZSBhbmFseXNpcywgdGhlc2Ugb3V0bGllcnMgd291bGQgbm90IGJlIGVsaW1pbmF0ZWQuCgpgYGB7cn0KYm94cGxvdChuZXdfcG9wJGBHcm93dGggcmF0ZWAsIG1haW4gPSAiR3Jvd3RoIHJhdGUgb2YgTEdBcyBpbiBWaWN0b3JpYSBiZXR3ZWVuIDIwMTggYW5kIDIwMTkiKQpgYGAKCmBgYHtyfQp6LnNjb3JlczMgPC0gbmV3X3BvcCRgR3Jvd3RoIHJhdGVgICU+JSAgc2NvcmVzKHR5cGUgPSAieiIpCnouc2NvcmVzMyAlPiUgc3VtbWFyeSgpCmBgYAoKYGBge3J9CndoaWNoKGFicyh6LnNjb3JlczMpID4zICkKbmV3X3BvcFtjKDc2LDE1NiksIF0KYGBgCgoKIyMJVHJhbnNmb3JtIAoKVGhlIGRhdGEgZGlzdHJpYnV0aW9uIHdhcyBjaGVja2VkIGZvciBib3RoIGBUb3RhbF8yMDE4YCBhbmQgYFRvdGFsXzIwMTlgIHVzaW5nIGBoaXN0KClgLgoKQm90aCBvZiB0aGUgZGlzdHJpYnV0aW9ucyBzaG93ZWQgaGlnaCByaWdodCBza2V3bmVzcyBpbiB0aGUgdmFyaWFibGVzLiBUaGVyZWZvcmUsICRsbiQgdHJhbnNmb3JtYXRpb24gd2FzIHRha2VuIGludG8gZGF0YSB0cmFuc2Zvcm1hdGlvbiB0byByZWR1Y2UgdGhlIHNrZXduZXNzIHVzaW5nIGBsb2coKWAuIAoKCmBgYHtyfQpoaXN0KG5ld19wb3AkVG90YWxfMjAxOCwgbWFpbiA9ICJUb3RhbCBwb3B1bGF0aW9uIGluIDIwMTgiKQpgYGAKCgpgYGB7cn0KaGlzdChuZXdfcG9wJFRvdGFsXzIwMTksIG1haW4gPSAiVG90YWwgcG9wdWxhdGlvbiBpbiAyMDE5IikKYGBgCgpUaGUgZGlzdHJpYnV0aW9uIGZvciBgVG90YWxfMjAxOGAgYW5kIGBUb3RhbF8yMDE5YCBhZnRlciAkbG4kIHRyYW5zZm9ybWF0aW9uOgoKKiBUaGUgZGlzdHJpYnV0aW9uIGZvciB0d28gdmFyaWFibGVzIHdlcmUgbW9yZSBzeW1tZXRyaWNhbCBhZnRlciBkYXRhIHRyYW5zZm9ybWF0aW9uLgoKYGBge3J9CmxvZ18yMDE4IDwtIGxvZyhuZXdfcG9wJFRvdGFsXzIwMTgpCmhpc3QobG9nXzIwMTgsIG1haW4gPSAiTG9nIHBvcHVsYXRpb24gaW4gMjAxOCIpCmBgYAoKYGBge3J9CmxvZ18yMDE5IDwtIGxvZyhuZXdfcG9wJFRvdGFsXzIwMTkpCmhpc3QobG9nXzIwMTksIG1haW4gPSAiTG9nIHBvcHVsYXRpb24gaW4gMjAxOSIpCmBgYAoKIyMgUmVmZXJlbmNlcwoKQXVzdHJhbGlhbiBCdXJlYXUgb2YgU3RhdGlzdGljcyAyMDE5LCAqUG9wdWxhdGlvbiBFc3RpbWF0ZXMgYnkgQWdlIGFuZCBTZXgsIExvY2FsIEdvdmVybm1lbnQgQXJlYXMgKEFTR1MgMjAxOCksIDIwMTgqLCAgQXVzdHJhbGlhJ3Mgc3RhdGlzdGljIGRhdGFzZXRzLCBkYXRhIGZpbGUsIEF1c3RyYWxpYW4gR292ZXJubWVudCwgQXVzdHJhbGlhbiBCdXJlYXUgb2YgU3RhdGlzdGljcywgTWVsYm91cm5lLCB2aWV3ZWQgMjAgTWF5IDIwMjAsIDxodHRwczovL3d3dy5hYnMuZ292LmF1L0FVU1NUQVRTL2Fic0AubnNmL0RldGFpbHNQYWdlLzMyMzUuMDIwMTg/T3BlbkRvY3VtZW50Pi4gCgpBdXN0cmFsaWFuIEJ1cmVhdSBvZiBTdGF0aXN0aWNzIDIwMTksICpQb3B1bGF0aW9uIEVzdGltYXRlcyBieSBMb2NhbCBHb3Zlcm5tZW50IEFyZWEsIDIwMTggdG8gMjAxOSAqLCAgQXVzdHJhbGlhJ3Mgc3RhdGlzdGljIGRhdGFzZXRzLCBkYXRhIGZpbGUsIEF1c3RyYWxpYW4gR292ZXJubWVudCwgQXVzdHJhbGlhbiBCdXJlYXUgb2YgU3RhdGlzdGljcywgTWVsYm91cm5lLCB2aWV3ZWQgMjAgTWF5IDIwMjAsIDxodHRwczovL3d3dy5hYnMuZ292LmF1L0FVU1NUQVRTL2Fic0AubnNmL0RldGFpbHNQYWdlLzMyMTguMDIwMTgtMTk/T3BlbkRvY3VtZW50JmZiY2xpZD1Jd0FSMjA1X0dfV3dxWEhaRHkwU0p4c1hmSlhfU2JTTk40b3dBb191WW5zUTFlY3FtaE1zdVRwYUo0eFZ3Pi4gCgpQYXJrZXIsIEIgMjAwMiwgKlBsYW5uaW5nIEFuYWx5c2lzOiBDYWxjdWxhdGluZyBHcm93dGggUmF0ZXMqLCBVbml2ZXJzaXR5IG9mIE9yZWdvbiwgdmlld2VkIDMwIE1heSAyMDIwLCA8aHR0cHM6Ly9wYWdlcy51b3JlZ29uLmVkdS9yZ3AvUFBQTTYxMy9jbGFzczhhLmh0bSM6fjp0ZXh0PVRoZSUyMGFubnVhbCUyMHBlcmNlbnRhZ2UlMjBncm93dGglMjByYXRlLE4lMkMlMjB0aGUlMjBudW1iZXIlMjBvZiUyMHllYXJzLiZ0ZXh0PUluJTIwMTk4MCUyQyUyMHRoZSUyMHBvcHVsYXRpb24lMjBpbiUyMExhbmUlMjBDb3VudHklMjB3YXMlMjAyNTAlMkMwMDA+LiAKClRyYXZlbCBWaWN0b3JpYSAyMDIwLCAqTG9jYWwgR292ZXJubWVudCBBcmVhcyosIFRyYXZlbCBWaWN0b3JpYSwgdmlld2VkIDMwIE1heSAyMDIwLCA8aHR0cHM6Ly93d3cudHJhdmVsdmljdG9yaWEuY29tLmF1L3ZpY3RvcmlhL2xvY2FsZ292ZXJubWVudC8+LiAKCjxicj4KPGJyPgo=