Welcome to the World Data Visualization Challenge Exploration Notebook! Let’s dig into how I (Jim Vallandingham) started the analysis of this data, found additional related historical data, and tried to find a story in it all.
My hope in releasing this quick analysis is to provide transparency to the final visualization, and to improve my analysis process.
Good Government Data
Let’s start with a look at the provided “what makes good government” dataset, which you can find from the challenge homepage.
My angle when looking at this data is skewed toward the idea that good government should support the well-being of the people it governs. My hypothesis is that more traditional measures of government performance and rank might be connected to this populous well-being. Meaning you don’t have to have one or the other - you can have happy people that are productive people, which in turn helps increase the power of the government.
Loading Data
First, we need to load the data. I downloaded a CSV version of the Google Doc sheet, and cleaned out the information rows. Its in the data
directory.
We will use the wonderful tidyverse collection of packages for most of this, so let’s load that now.
library(tidyverse)
[30m── [1mAttaching packages[22m ─────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.2.1 ──[39m
[30m[32m✔[30m [34mggplot2[30m 3.1.0 [32m✔[30m [34mpurrr [30m 0.2.5
[32m✔[30m [34mtibble [30m 1.4.2 [32m✔[30m [34mdplyr [30m 0.7.8
[32m✔[30m [34mtidyr [30m 0.8.2 [32m✔[30m [34mstringr[30m 1.3.1
[32m✔[30m [34mreadr [30m 1.3.1 [32m✔[30m [34mforcats[30m 0.3.0[39m
[30m── [1mConflicts[22m ────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
[31m✖[30m [34mdplyr[30m::[32mfilter()[30m masks [34mstats[30m::filter()
[31m✖[30m [34mdplyr[30m::[32mlag()[30m masks [34mstats[30m::lag()[39m
Now load the data, indicating the -
is used for missing values in the CSV.
filename <- "data/WDVP_good_gov.csv"
gov_data <- read_csv(filename, na = '-')
Missing column names filled in: 'X5' [5], 'X11' [11], 'X23' [23]Parsed with column specification:
cols(
.default = col_double(),
country = [31mcol_character()[39m,
`ISO Country code` = [31mcol_character()[39m,
population = [32mcol_number()[39m,
`surface area (Km2)` = [32mcol_number()[39m,
X5 = [33mcol_logical()[39m,
X11 = [33mcol_logical()[39m,
`GDP per capita (PPP)` = [32mcol_number()[39m,
`health expenditure per person` = [32mcol_number()[39m,
`education expenditure per person` = [32mcol_number()[39m,
X23 = [33mcol_logical()[39m
)
See spec(...) for full column specifications.
There are some spacer columns in the original Google Sheet - so we get some warnings. This is nothing to worry about though.
Metric Descriptions
Before we dive in, it might be worthwhile to talk a bit about some of the metrics this dataset contains. Some are pretty sophisticated composite values that I wanted to learn a bit more about before I charged ahead with the visualization and analysis.
GDP
First the basics: GDP. I know its used everywhere, all the time, but I wanted to get a refresher on the details.
While looking for pros/cons of GDP as a performance measure, I found an article about why the GDP sucks which lists some alternatives. Lucky for me (thanks to the foresight of the Information is Beautiful data collectors), many of these alternatives are in the government dataset we are looking at.
Below are some nice quotes from that article, summarising in plain-english what these metrics are about.
Human Development Index (HDI)
Alongside financial measures, the Human Development Index combines statistics on life expectancy, education, and income per capita to rank countries into tiers of development. Often framed in terms of whether people are able to “be” and “do” desirable things in life, HDI was developed by Pakistani economist Mahbub ul Haq and is backed by the United Nations. The higher the number, the more “developed” the country.
I like this summary of this metric tracking if people can “be” and “do” the things they want.
Happy Planet Index
This uses global data on life expectancy, experienced well-being, and ecological footprint to calculate an index that ranks countries on how many long and happy lives they produce per unit of environmental input. The higher the number, the happier the population.
Gini Coefficient
One of the biggest issues with GDP is that it ignores inequality. The Gini coefficient, invented in 1912 by Italian statistician Corrado Gini, represents the income distribution of a nation’s residents. A low number represents low inequality, while a high one indicates a major gap between the rich and poor.
And from the CIA Factbook:
Gini index measures the degree of inequality in the distribution of family income in a country. The more nearly equal a country’s income distribution, the lower its Gini index, e.g., a Scandinavian country with an index of 25. The more unequal a country’s income distribution, the higher its Gini index, e.g., a Sub-Saharan country with an index of 50. If income were distributed with perfect equality the index would be zero; if income were distributed with perfect inequality, the index would be 100.
Gross National Income (GNI)
This one is not in our dataset, but does sound interesting from its description:
GNI measures the economic output of its citizens, taking into account the globalization of modern business. It’s calculated by adding up all the income of the residents of a country, including that received from abroad. As such, it helps show the economic strength of a country’s population, rather than the country itself.
Economic Freedom
This one is not listed in the GDP alternatives site, but sounds like a very interesting measurement to look more closely at.
From the index’s site:
Economic freedom is the fundamental right of every human to control his or her own labor and property. In an economically free society, individuals are free to work, produce, consume, and invest in any way they please. In economically free societies, governments allow labor, capital, and goods to move freely, and refrain from coercion or constraint of liberty beyond the extent necessary to protect and maintain liberty itself.
Economic freedom brings greater prosperity. The Index of Economic Freedom documents the positive relationship between economic freedom and a variety of positive social and economic goals. The ideals of economic freedom are strongly associated with healthier societies, cleaner environments, greater per capita wealth, human development, democracy, and poverty elimination.
This seems like it falls right in the wheelhouse of what a “good” government can provide!
Sustainable Economic Development Assessment (SEDA)
Also not in the GDP alternatives list. This is a new metric to measure well-being.
SEDA is primarily an objective measure (combining data on outcomes, such as in health and education, with quasi-objective data, such as governance assessments). It is also a relative measure that assesses how a country performs in comparison to either the entire universe of countries or to individual peers or groups.
SEDA uses 10 dimensions, including wealth, quality of environment, and income equality to calculate a country’s score. Sounds like quite a composite number!
Exploring Data
Now we have a bit of backstory on the metrics, let’s dig more into the data itself.
First, I’ll just rename some of the columns for easier access.
gov_data$gdp_per_cap <- gov_data$`GDP per capita (PPP)`
gov_data$hdi <- gov_data$`human development index`
gov_data$seda <- gov_data$`sustainable economic development assessment (SEDA)`
gov_data$gini <- gov_data$`GINI index`
gov_data$efree <- gov_data$`overall economic freedom score`
We can also calculate a few additional metrics using the data we have, that might be useful for showing patterns.
# population density
gov_data$pop_density <- gov_data$population / gov_data$`surface area (Km2)`
# this is a suggested max population for 'small' countries
small_country_max_pop = 5000000
# we can use this threshold to create a new categorical column
gov_data$country_size <- ifelse(gov_data$population > small_country_max_pop, 'big', 'little')
gov_data$log_gdp <- log(gov_data$gdp_per_cap)
HDI
I like to use histograms to get a quick sense of what’s in a dataset, and to uncover any mistakes with importing data into R.
So let’s take a quick look at the Human Development Index (HDI) provided. We will use ggplot to visualize.
gov_data %>%
ggplot(aes(x = hdi)) +
geom_histogram(binwidth = 0.05) +
labs(title = "Distribution of HDI")
A challenge with histograms is picking good bins… I’ve used a binwidth of 0.05
just because I know the HDI should range between 0 and 1, and I wanted to see generally where there are gaps and overlaps.
The warning also indicates that there are 9 countries with no HDI data. Not too many, given the dataset contains 195 countries. Still these might be good to filter out, if we pursue HDI further.
GDP
Next, let’s take a quick look at GDP.
gov_data %>%
ggplot(aes(x = gdp_per_cap)) +
geom_histogram(bins=30) +
labs(title = "Distribution of GDP")
Ah, we see a much different distribution here! This looks a bit exponential, which is not too surprising. Let’s take a look at the countries with really big GDP per capita
gov_data %>%
filter(gdp_per_cap > 50000) %>%
arrange(-gdp_per_cap) %>%
select(country, gdp_per_cap, country_size)
We can see that most of these are ‘little’ countries - with smaller populations. As noted, these countries can skew results (and they do - just check the histogram). They are candidates to filter out if we are more concerned with telling a ‘big picture’ story.
HDI vs GDP
A scatterplot can show a relationship between two variables. Here, we can check the relationship between HDI and GDP.
gov_data %>%
ggplot(aes(x = gdp_per_cap, y = hdi, colour = country_size)) +
geom_point(size=2) +
geom_text(check_overlap = TRUE, aes(label = country), colour = '#333333', alpha = 0.7) +
labs(title = "HDI vs GDP")
I’ve colored the points by country size, so we can see the impact of these little countries again. But there is definitely a relationship here, indicating that HDI impacts GDP or vice versa.
Metric Correlations
What other relationships are there in this dataset?
Let’s jam a bunch together into a facetted scatterplot! The built in plot()
package will do this for us nicely. Below, I just filter a small subset of the data so that the relationships are still (somewhat) visable.
gov_data %>%
select(gdp_per_cap, gini, efree, `happy planet index`, hdi, seda, `unemployment (%)`) %>%
plot()
So we can see some correlations visually from these plots, let’s quantify this a bit more by plotting a correlation matrix. Using a nice tutorial as a guide, here I use the cor()
function to calculate the correlation values between these variables, then plot using corrplot
# If you don't have corrplot install with:
# install.packages("corrplot")
library(corrplot)
corrplot 0.84 loaded
gov_data %>%
select(gdp_per_cap, gini, efree, `happy planet index`, hdi, seda, `unemployment (%)`) %>%
cor(use = "complete.obs") %>%
corrplot(type = "upper", order = "hclust", tl.col = "black", tl.srt = 45)
It is not too surprising to see high correlation between SEDA, HDI, economic freedom, and GDP.
I am a bit surprised that the happy planet index is not as highly correlated with these measures as well - but perhaps that is because of the environment focus of this metric. There is not much correlation between Happy Planet and the GDP. This is unfortunate - as we can’t really make an argument for an improved environmental impact making an improved GDP - at least not at the time being.
It is also surprising that the Gini coefficient is not more negatively correlated with some of these other combo-metrics. SEDA takes inequality into account as part of its calculation so that explains why it is the most negatively correlated.
Not shown, but things don’t change too much when ‘little’ countries are removed. Try it out yourself with an additional filter()
in the code above.
While there is some negative correlation between Gini and well-being metrics like SEDA and HDI, its still pretty messy.
Here is a plot showing HDI vs Gini, with sizes of dots indicating the GDP - as that was negatively correlated as well.
gov_data %>% #filter(country_size == 'big') %>%
ggplot(aes(x = gini, y=hdi, color = country_size, size = gdp_per_cap)) +
geom_point() +
geom_text(check_overlap = TRUE, aes(label = country), color = "#333333", size = 3) +
labs(title = "HDI vs GINI")
We can see that roughly an increase in the Gini coefficient (meaning an increase in inequality) results in a decrease in the SEDA metric for well-being. This is true for GDP per capita as well. But the correlation is weak.
As an aside, we can see that we are also missing a lot of Gini scores for countries - given the warning messages.
Could still contribute to an interesting story!
Linear Regression
As a quick look at how these variables relate, let’s build a linear model that tries to predict GDP per capita from a combination of the Human Development Index, the Gini coefficient, and the Economic Freedom score. We will avoid SEDA for now, as it explicitly uses GDP-like inputs as part of its calculation.
lm_out <- lm(formula = log_gdp ~ hdi + efree + gini, data = gov_data)
summary(lm_out)
Call:
lm(formula = log_gdp ~ hdi + efree + gini, data = gov_data)
Residuals:
Min 1Q Median 3Q Max
-2.06776 -0.23198 0.00734 0.22203 3.10917
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 3.828502 0.400787 9.552 <2e-16 ***
hdi 5.935777 0.382782 15.507 <2e-16 ***
efree 0.018581 0.005700 3.260 0.0014 **
gini 0.001139 0.005427 0.210 0.8340
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.5227 on 138 degrees of freedom
(53 observations deleted due to missingness)
Multiple R-squared: 0.8111, Adjusted R-squared: 0.807
F-statistic: 197.6 on 3 and 138 DF, p-value: < 2.2e-16
So, roughly speaking, These inputs capture ~80% of the variability in the log-transformed GDP (we use the log of GDP to make that exponential relationship we saw before linear).
At this point, I started thinking about the progress of an individual country.
The comparisons we have looked at show a snap-shot of how countries are performing now, but what are the global and local trends? Where have these countries been to reach this spot? Are we moving forward with these metrics of human progress, or backwards? Is there a connection between the relative performance of a country over time and its GDP?
I wanted to find the answers to some of these questions. And to do that, I need historical data.
Historic Metric Data
Fortunately, the starting dataset provided references to the sources for all the columns of data.
Because the SEDA metric is such an amalgamation of other metrics, and because it is highly correlated with the other measurements, I chose not to pursue historical data for it.
Instead, I focused on getting historical data for HDI, economic freedom, and Gini, along with the more traditional GDP value.
Economic Freedom
The Heritage Foundation has an option to view all the historic data. Unfortunately, I couldn’t get the download button to download more than just the current year. So instead, I copied the table and pasted it into Numbers (which worked but took forever). Then saved it as a CSV.
filename <- "data/heritage_economic_freedom_score.csv"
ecfree_data <- read_csv(filename, na = "N/A")
Parsed with column specification:
cols(
name = [31mcol_character()[39m,
`index year` = [32mcol_double()[39m,
`overall score` = [32mcol_double()[39m,
`property rights` = [32mcol_double()[39m,
`government integrity` = [32mcol_double()[39m,
`judicial effectiveness` = [32mcol_double()[39m,
`tax burden` = [32mcol_double()[39m,
`government spending` = [32mcol_double()[39m,
`fiscal health` = [32mcol_double()[39m,
`business freedom` = [32mcol_double()[39m,
`labor freedom` = [32mcol_double()[39m,
`monetary freedom` = [32mcol_double()[39m,
`trade freedom` = [32mcol_double()[39m,
`investment freedom` = [32mcol_double()[39m,
`financial freedom` = [32mcol_double()[39m
)
Human Development Index (HDI)
The UN provides HDI as a CSV. I downloaded it, ensured the encoding was in UTF-8, and put it in the data directory. We can load it easily, and quickly remove all the spacer columns.
filename <- "data/Human Development Index.csv"
hdi_data <- read_csv(filename)
Missing column names filled in: 'X4' [4], 'X6' [6], 'X8' [8], 'X10' [10], 'X12' [12], 'X14' [14], 'X16' [16], 'X18' [18], 'X20' [20], 'X22' [22], 'X24' [24], 'X26' [26], 'X28' [28], 'X30' [30], 'X32' [32], 'X34' [34], 'X36' [36], 'X38' [38], 'X40' [40], 'X42' [42], 'X44' [44], 'X46' [46], 'X48' [48], 'X50' [50], 'X52' [52], 'X54' [54], 'X56' [56], 'X58' [58]Parsed with column specification:
cols(
.default = col_double(),
Country = [31mcol_character()[39m,
X4 = [33mcol_logical()[39m,
X6 = [33mcol_logical()[39m,
X8 = [33mcol_logical()[39m,
X10 = [33mcol_logical()[39m,
X12 = [33mcol_logical()[39m,
X14 = [33mcol_logical()[39m,
X16 = [33mcol_logical()[39m,
X18 = [33mcol_logical()[39m,
X20 = [33mcol_logical()[39m,
X22 = [33mcol_logical()[39m,
X24 = [33mcol_logical()[39m,
X26 = [33mcol_logical()[39m,
X28 = [33mcol_logical()[39m,
X30 = [33mcol_logical()[39m,
X32 = [33mcol_logical()[39m,
X34 = [33mcol_logical()[39m,
X36 = [33mcol_logical()[39m,
X38 = [33mcol_logical()[39m,
X40 = [33mcol_logical()[39m
# ... with 9 more columns
)
See spec(...) for full column specifications.
1 parsing failure.
row col expected actual file
190 -- 58 columns 1 columns 'data/Human Development Index.csv'
# drop X# columns. dangerous, but easy.
hdi_data <- hdi_data %>% select(-contains('X'))
The original version is in a “wide” format, we want it “long” - so we can easily join by country and year with other datasets. gather() does this nicely for us. Note the cool use of a negative one_of()
to exclude a specified set of columns, and thus include all the others.
hdi_data_long <- hdi_data %>% gather(key = "year", value = "hdi_value", -one_of("Country", "HDI Rank (2017)"))
Then, make some quick derived columns for joining.
hdi_data_long$country <- hdi_data_long$Country
hdi_data_long$year_n <- as.numeric(hdi_data_long$year)
World Bank Data
The rest of the metrics I found I could get from the World Bank.
Lucky for me, with a bit of Googling, I found t sweet sweet wbstats R package which allows you to pull down multiple WorldBank metrics via R! Super cool, and super useful. This will be a package to check out more for future projects as well.
# install with:
# install.packages('wbstats')
library(wbstats)
Using the search feature of wbstats
and the online World Bank indicators page, I found the ID’s of the metrics I wanted. Here’s how to pull down the data, with some notes:
# Metric IDs
# NY.GDP.PCAP.PP.CD = GDP per capita, PPP (current international $)
# NY.GDP.MKTP.KD.ZG = GDP growth (annual %)
# NY.GDP.PCAP.KD.ZG = GDP per capita growth (annual %)
# NY.GNP.PCAP.PP.CD = GNI per capita, PPP (current international $)
# NY.GNP.PCAP.KD.ZG = GNI per capita growth (annual %)
# SI.POV.GINI = GINI index (World Bank estimate)
# SP.POP.TOTL = population total
indicators <- c('NY.GDP.PCAP.PP.CD', 'NY.GNP.PCAP.PP.CD', 'NY.GNP.PCAP.KD.ZG', 'SI.POV.GINI', 'SP.POP.TOTL')
wb_data <- wb(country= "all", indicator = indicators, startdate = 2000, enddate = 2018, return_wide = TRUE)
You’ll note that i limited the year range to be between 2000 and 2018. This seemed like a decent enough year span to see some changes, but recent enough to be meaningful. Perhaps I should have investigated good year ranges more.
# need a numeric year for joining.
wb_data$year = as.numeric(wb_data$date)
Unfortunately, the hdi and economic freedom historical data only have country names - and not ISO codes. A huge short-sightedness if you ask me. So we have to do some tweaking to get matches across these three datasets. I’ve tweaked the names in the staring CSV files for some countries, and below we augment the world data for some others.
wb_data$country <- recode(wb_data$country,
"Yemen, Rep." = "Yemen",
"Lao PDR" = "Laos",
"Korea, Dem. People’s Rep." = "North Korea",
"Korea, Rep." = "South Korea",
"Egypt, Arab Rep." = "Egypt",
"Iran, Islamic Rep." = "Iran",
"Slovak Republic" = "Slovakia",
"Venezuela, RB" = "Venezuela",
"Hong Kong SAR, China" = "Hong Kong",
"Congo, Dem. Rep." = "Democratic Republic of Congo",
"Congo, Rep." = "Republic of Congo"
)
Region Data
Finally, I wanted a way to group these countries into higher themes. I happened upon this Github repo which includes a mapping from iso code to region name. Seemed like a good addition to me!
filename <- "data/country_regions.csv"
regions_data <- read_csv(filename)
Parsed with column specification:
cols(
name = [31mcol_character()[39m,
`alpha-2` = [31mcol_character()[39m,
`alpha-3` = [31mcol_character()[39m,
`country-code` = [31mcol_character()[39m,
`iso_3166-2` = [31mcol_character()[39m,
region = [31mcol_character()[39m,
`sub-region` = [31mcol_character()[39m,
`intermediate-region` = [31mcol_character()[39m,
`region-code` = [31mcol_character()[39m,
`sub-region-code` = [31mcol_character()[39m,
`intermediate-region-code` = [31mcol_character()[39m
)
Joining Data
Now that we have all the ingredients, let’s join them all together in a super dataframe!
There are probably better ways to do this in R, but I went with piecewise joining with left_join()
.
ecfree_hdi_data <- left_join(ecfree_data, hdi_data_long, by = c("name" = "country", "index year" = "year_n"))
ecfree_hdi_wb_data <- left_join(ecfree_hdi_data, wb_data, by = c("name" = "country", "index year" = "year"))
ecfree_hdi_wb_data <- left_join(ecfree_hdi_wb_data, regions_data, by = c("iso3c" = "alpha-3"))
So now this oddly named dataframe ecfree_hdi_wb_data
includes columns from the above sources.
Normalization
Hastily, I added even more columns to the dataset for easier access.
# renames to make accessing columns easier.
# should probably rename column directly, instead of just tacking on more columns
ecfree_hdi_wb_data$country <- ecfree_hdi_wb_data$name.x
ecfree_hdi_wb_data$year <- ecfree_hdi_wb_data$`index year`
ecfree_hdi_wb_data$hdi <- ecfree_hdi_wb_data$hdi_value
ecfree_hdi_wb_data$efree <- ecfree_hdi_wb_data$`overall score`
ecfree_hdi_wb_data$gini <- ecfree_hdi_wb_data$SI.POV.GINI
ecfree_hdi_wb_data$population <- ecfree_hdi_wb_data$SP.POP.TOTL
ecfree_hdi_wb_data$gni_per_cap <- ecfree_hdi_wb_data$NY.GNP.PCAP.PP.CD
ecfree_hdi_wb_data$gni_per_cap_percent <- ecfree_hdi_wb_data$NY.GNP.PCAP.KD.ZG
ecfree_hdi_wb_data$gdp_per_cap <- ecfree_hdi_wb_data$NY.GDP.PCAP.PP.CD
ecfree_hdi_wb_data$country_size <- ifelse(ecfree_hdi_wb_data$population > small_country_max_pop, 'big', 'little')
Data Exploration
Now we can do some exploring!
First, let’s look at just a single year, and compare HDI to GDP like we did above - to confirm the historical data isn’t radically different.
ecfree_hdi_wb_data %>% filter(year == 2017) %>%
ggplot(aes(x = gdp_per_cap, y = hdi)) +
labs(title = "GDP vs HDI") +
geom_text(check_overlap = TRUE, aes(label = country)) +
geom_point()
We can use facet_wrap()
to show the same data for a subset of the years.
ecfree_hdi_wb_data %>% filter(year > 2006) %>%
ggplot(aes(x = gdp_per_cap, y = hdi)) +
labs(title = "GDP vs HDI - 2007 - 2017") +
geom_point(alpha=0.2, size=1) +
geom_text(check_overlap = TRUE, aes(label = country), size = 2) +
facet_wrap(~ year)
Things are looking pretty good, though we note we are missing 2018 data. This is because World Bank doesn’t have this data available yet.
Let’s look at the correlations for the different metrics like we did before, but now with all these additonal time points, to ensure the connections hold.
ecfree_hdi_wb_data %>%
select(gdp_per_cap, gini, efree, hdi) %>%
cor(use = "complete.obs") %>%
corrplot(type = "upper", order = "hclust", tl.col = "black", tl.srt = 45)
Appears to be pretty similar!
Grouping by Country
I wanted to see trends in these metrics over time by country.
Here is a grouping process that uses group_by()
to summarise data by metric. There is a bit of work to do around finding the first and last values, as not all years have data for all countries.
GDP
gdp_by_country <- ecfree_hdi_wb_data %>% group_by(country) %>% summarise(
first_gdp_year = year[max(which(!is.na(gdp_per_cap)))],
last_gdp_year = year[min(which(!is.na(gdp_per_cap)))],
years_of_gdp = last_gdp_year - first_gdp_year,
first_gdp_value = gdp_per_cap[max(which(!is.na(gdp_per_cap)))],
last_gdp_value = gdp_per_cap[min(which(!is.na(gdp_per_cap)))],
gdp_change = last_gdp_value - first_gdp_value,
gdp_change_by_year = gdp_change / years_of_gdp,
avg_gdp = mean(gdp_per_cap, na.rm = TRUE)
)
gdp_by_country %>%
ggplot(aes(x = avg_gdp)) + geom_histogram(bins=30)
So almost all countries increased in GDP, which makes sense.
Gini
gini_by_country <- ecfree_hdi_wb_data %>% group_by(country) %>% summarise(
first_gini_year = year[max(which(!is.na(gini)))],
last_gini_year = year[min(which(!is.na(gini)))],
years_of_gini = last_gini_year - first_gini_year,
first_gini_value = gini[max(which(!is.na(gini)))],
last_gini_value = gini[min(which(!is.na(gini)))],
gini_change = last_gini_value - first_gini_value,
gini_change_by_year = gini_change / years_of_gini,
avg_gini = mean(gini, na.rm = TRUE)
)
gini_by_country <- gini_by_country %>% filter(years_of_gini > 1)
gini_by_country$gini_category = ifelse(gini_by_country$gini_change_by_year < 0, "more equal", "less equal")
A little more effort gets our first and last values in long format:
gini_start_end <- gini_by_country %>%
select(c(country, gini_category, first_gini_value, last_gini_value)) %>%
gather(key = "metric", value = "value", first_gini_value, last_gini_value)
Which we can visualize:
gini_start_end %>%
ggplot(aes(x = metric, y = value, group = country, colour = gini_category)) +
geom_line() +
geom_text(check_overlap = TRUE, aes(label = country), size = 4, colour = 'black') +
facet_wrap(~ gini_category)
Here I wanted to see if there were trends in gini movement, so I made a quick slopechart between the country’s first and last Gini index value. Changes don’t seem to follow any immediate pattern.
Economic Freedom
efree_by_country <- ecfree_hdi_wb_data %>% group_by(country) %>% summarise(
first_efree_year = year[max(which(!is.na(efree)))],
last_efree_year = year[min(which(!is.na(efree)))],
years_of_efree = last_efree_year - first_efree_year,
first_efree_value = efree[max(which(!is.na(efree)))],
last_efree_value = efree[min(which(!is.na(efree)))],
efree_change = last_efree_value - first_efree_value,
efree_change_by_year = efree_change / years_of_efree,
avg_efree = mean(efree, na.rm = TRUE)
)
efree_by_country <- efree_by_country %>% filter(years_of_efree > 1)
efree_by_country %>%
ggplot(aes(x = last_efree_value - first_efree_value)) + geom_histogram()
Most countries remained relatively stable, with some big ups and downs.
Here are the countries that changed the most:
efree_by_country %>%
filter(abs(efree_change) > 15) %>%
arrange(-1 * efree_change) %>%
select(c(country, first_efree_value, last_efree_value, efree_change))
Here’s just another way to plot the same data:
efree_by_country %>% #filter(abs(last_efree_value - first_efree_value) > 10) %>%
ggplot(aes(x = first_efree_value, y = last_efree_value)) +
geom_point() +
geom_text(check_overlap = TRUE, aes(label = country), size = 4) +
labs(title = "Last Ec Freedom Value vs Fist Ec Freedom Value by Country")
Connected Scatterplots
At this point, I knew I wanted to show the connect between these different metrics over time. And I knew I wanted to try something a bit novel in terms of visualizing multiple metrcis together. So I decided to check out what this data looked like using connected scatter plots!
ecfree_hdi_wb_data %>% filter(country %in% c('Brazil', 'China', 'United Kingdom', 'United States')) %>% arrange(country, year) %>%
ggplot(aes( y = hdi, x = efree, colour = country)) +
geom_text(check_overlap = TRUE, aes(label = year)) +
geom_point() +
geom_path() +
labs(title="Connected Scatterplot: HDI vs Economic Freedom")
Pretty nice!
Here is all of the countries together:
ecfree_hdi_wb_data %>% arrange(country, year) %>%
ggplot(aes( y = hdi, x = gdp_per_cap, group = country)) +
geom_text(check_overlap = TRUE, aes(label = year), alpha = 0.5) +
geom_point(alpha = 0.1) +
geom_path(alpha = 0.1) +
labs(title="Connected Scatterplot: All HDI vs GDP")
One other thing I wanted to see was how a country moved through this metric space relative to itself. How is a country performing compared to other years?
That is where normalization / scaling comes in handy!
range01 <- function(x){(x-min(x, na.rm = TRUE))/(max(x, na.rm = TRUE)-min(x, na.rm = TRUE))}
ecfree_hdi_wb_data <- ecfree_hdi_wb_data %>%
group_by(country) %>%
mutate(hdi_01 = range01(hdi), efree_01 = range01(efree), gdp_01 = range01(gdp_per_cap)) %>%
ungroup()
ecfree_hdi_wb_data %>% filter(country %in% c('Brazil', 'China', 'United Kingdom', 'United States')) %>% arrange(country, year) %>%
ggplot(aes( y = hdi_01, x = gdp_01, colour = country)) +
geom_text(check_overlap = TRUE, aes(label = year)) +
geom_point() +
geom_path() +
labs(title="Connected Scatterplot: Relative HDI vs GDP")
Pretty fun to see an individuals arc, as well as a bit of comparison between
Saving to CSV
While this represents only a subset of the data exploration I did to get to the final form, I think it gives a good taste for the basic munging and searching required.
To end, I saved a subset of our combined data to CSV to start digging in more with D3 in the main visualization piece.
gov_data_save <- ecfree_hdi_wb_data %>%
select(country, iso3c, region, `sub-region`, year, population, gni_per_cap, gni_per_cap_percent, gdp_per_cap, efree, hdi, gini)
write_csv(gov_data_save, "output/gov_data_year.csv")
FIN
LS0tCnRpdGxlOiAiV29ybGQgRGF0YSBWaXN1YWxpemF0aW9uIENoYWxsYW5nZSAtIEFuYWx5c2lzIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6IAogICAgdGhlbWU6IHNwYWNlbGFiCi0tLQoKV2VsY29tZSB0byB0aGUgV29ybGQgRGF0YSBWaXN1YWxpemF0aW9uIENoYWxsZW5nZSBFeHBsb3JhdGlvbiBOb3RlYm9vayEgTGV0J3MgZGlnIGludG8gaG93IEkgKFtKaW0gVmFsbGFuZGluZ2hhbV0oaHR0cDovL3ZhbGxhbmRpbmdoYW0ubWUvKSkgc3RhcnRlZCB0aGUgYW5hbHlzaXMgb2YgdGhpcyBkYXRhLCBmb3VuZCBhZGRpdGlvbmFsIHJlbGF0ZWQgaGlzdG9yaWNhbCBkYXRhLCBhbmQgdHJpZWQgdG8gZmluZCBhIHN0b3J5IGluIGl0IGFsbC4KCk15IGhvcGUgaW4gcmVsZWFzaW5nIHRoaXMgcXVpY2sgYW5hbHlzaXMgaXMgdG8gcHJvdmlkZSB0cmFuc3BhcmVuY3kgdG8gdGhlIGZpbmFsIHZpc3VhbGl6YXRpb24sIGFuZCB0byBpbXByb3ZlIG15IGFuYWx5c2lzIHByb2Nlc3MuCgojIyBHb29kIEdvdmVybm1lbnQgRGF0YQoKTGV0J3Mgc3RhcnQgd2l0aCBhIGxvb2sgYXQgdGhlIHByb3ZpZGVkICJ3aGF0IG1ha2VzIGdvb2QgZ292ZXJubWVudCIgZGF0YXNldCwgd2hpY2ggeW91IGNhbiBmaW5kIFtmcm9tIHRoZSBjaGFsbGVuZ2UgaG9tZXBhZ2VdKGh0dHBzOi8vaW5mb3JtYXRpb25pc2JlYXV0aWZ1bC5uZXQvMjAxOC9hbm5vdW5jaW5nLXRoZS13b3JsZC1kYXRhLXZpc3VhbGl6YXRpb24tcHJpemUtYS00MGstZGF0YXZpei1jaGFsbGVuZ2UvKS4KCk15IGFuZ2xlIHdoZW4gbG9va2luZyBhdCB0aGlzIGRhdGEgaXMgc2tld2VkIHRvd2FyZCB0aGUgaWRlYSB0aGF0IGdvb2QgZ292ZXJubWVudCBzaG91bGQgc3VwcG9ydCB0aGUgd2VsbC1iZWluZyBvZiB0aGUgcGVvcGxlIGl0IGdvdmVybnMuIE15IGh5cG90aGVzaXMgaXMgdGhhdCBtb3JlIHRyYWRpdGlvbmFsIG1lYXN1cmVzIG9mIGdvdmVybm1lbnQgcGVyZm9ybWFuY2UgYW5kIHJhbmsgbWlnaHQgYmUgY29ubmVjdGVkIHRvIHRoaXMgcG9wdWxvdXMgd2VsbC1iZWluZy4gTWVhbmluZyB5b3UgZG9uJ3QgaGF2ZSB0byBoYXZlIG9uZSBvciB0aGUgb3RoZXIgLSB5b3UgY2FuIGhhdmUgaGFwcHkgcGVvcGxlIHRoYXQgYXJlIHByb2R1Y3RpdmUgcGVvcGxlLCB3aGljaCBpbiB0dXJuIGhlbHBzIGluY3JlYXNlIHRoZSBwb3dlciBvZiB0aGUgZ292ZXJubWVudC4KCiMjIyBMb2FkaW5nIERhdGEKCkZpcnN0LCB3ZSBuZWVkIHRvIGxvYWQgdGhlIGRhdGEuICBJIGRvd25sb2FkZWQgYSBDU1YgdmVyc2lvbiBvZiB0aGUgR29vZ2xlIERvYyBzaGVldCwgYW5kIGNsZWFuZWQgb3V0IHRoZSBpbmZvcm1hdGlvbiByb3dzLiBJdHMgaW4gdGhlIGBkYXRhYCBkaXJlY3RvcnkuIAoKV2Ugd2lsbCB1c2UgdGhlIHdvbmRlcmZ1bCBbdGlkeXZlcnNlXShodHRwczovL3d3dy50aWR5dmVyc2Uub3JnLykgY29sbGVjdGlvbiBvZiBwYWNrYWdlcyBmb3IgbW9zdCBvZiB0aGlzLCBzbyBsZXQncyBsb2FkIHRoYXQgbm93LgoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKCk5vdyBsb2FkIHRoZSBkYXRhLCBpbmRpY2F0aW5nIHRoZSBgLWAgaXMgdXNlZCBmb3IgbWlzc2luZyB2YWx1ZXMgaW4gdGhlIENTVi4KCmBgYHtyfQpmaWxlbmFtZSA8LSAiZGF0YS9XRFZQX2dvb2RfZ292LmNzdiIKZ292X2RhdGEgPC0gcmVhZF9jc3YoZmlsZW5hbWUsIG5hID0gJy0nKQpgYGAKCgpUaGVyZSBhcmUgc29tZSBzcGFjZXIgY29sdW1ucyBpbiB0aGUgb3JpZ2luYWwgR29vZ2xlIFNoZWV0IC0gc28gd2UgZ2V0IHNvbWUgd2FybmluZ3MuIFRoaXMgaXMgbm90aGluZyB0byB3b3JyeSBhYm91dCB0aG91Z2guIAoKIyMjIE1ldHJpYyBEZXNjcmlwdGlvbnMKCkJlZm9yZSB3ZSBkaXZlIGluLCBpdCBtaWdodCBiZSB3b3J0aHdoaWxlIHRvIHRhbGsgYSBiaXQgYWJvdXQgc29tZSBvZiB0aGUgbWV0cmljcyB0aGlzIGRhdGFzZXQgY29udGFpbnMuIFNvbWUgYXJlIHByZXR0eSBzb3BoaXN0aWNhdGVkIGNvbXBvc2l0ZSB2YWx1ZXMgdGhhdCBJIHdhbnRlZCB0byBsZWFybiBhIGJpdCBtb3JlIGFib3V0IGJlZm9yZSBJIGNoYXJnZWQgYWhlYWQgd2l0aCB0aGUgdmlzdWFsaXphdGlvbiBhbmQgYW5hbHlzaXMuIAoKIyMjIyBHRFAKCkZpcnN0IHRoZSBiYXNpY3M6IEdEUC4gSSBrbm93IGl0cyB1c2VkIGV2ZXJ5d2hlcmUsIGFsbCB0aGUgdGltZSwgYnV0IEkgd2FudGVkIHRvIGdldCBhIHJlZnJlc2hlciBvbiB0aGUgZGV0YWlscy4gCgpXaGlsZSBsb29raW5nIGZvciBwcm9zL2NvbnMgb2YgR0RQIGFzIGEgcGVyZm9ybWFuY2UgbWVhc3VyZSwgSSBmb3VuZCBhbiBhcnRpY2xlIGFib3V0IFt3aHkgdGhlIEdEUCBzdWNrc10oaHR0cHM6Ly9ob3d3ZWdldHRvbmV4dC5jb20vZ2RwLXN1Y2tzLWhlcmUtYXJlLXNvbWUtYmV0dGVyLWFsdGVybmF0aXZlcy04OGNmMmJmZWMwMTcpIHdoaWNoIGxpc3RzIHNvbWUgYWx0ZXJuYXRpdmVzLiBMdWNreSBmb3IgbWUgKHRoYW5rcyB0byB0aGUgZm9yZXNpZ2h0IG9mIHRoZSBJbmZvcm1hdGlvbiBpcyBCZWF1dGlmdWwgZGF0YSBjb2xsZWN0b3JzKSwgbWFueSBvZiB0aGVzZSBhbHRlcm5hdGl2ZXMgYXJlIGluIHRoZSBnb3Zlcm5tZW50IGRhdGFzZXQgd2UgYXJlIGxvb2tpbmcgYXQuIAoKQmVsb3cgYXJlIHNvbWUgbmljZSBxdW90ZXMgZnJvbSB0aGF0IGFydGljbGUsIHN1bW1hcmlzaW5nIGluIHBsYWluLWVuZ2xpc2ggd2hhdCB0aGVzZSBtZXRyaWNzIGFyZSBhYm91dC4KCiMjIyMgSHVtYW4gRGV2ZWxvcG1lbnQgSW5kZXggKEhESSkKCj4gQWxvbmdzaWRlIGZpbmFuY2lhbCBtZWFzdXJlcywgdGhlIEh1bWFuIERldmVsb3BtZW50IEluZGV4IGNvbWJpbmVzIHN0YXRpc3RpY3Mgb24gbGlmZSBleHBlY3RhbmN5LCBlZHVjYXRpb24sIGFuZCBpbmNvbWUgcGVyIGNhcGl0YSB0byByYW5rIGNvdW50cmllcyBpbnRvIHRpZXJzIG9mIGRldmVsb3BtZW50LiBPZnRlbiBmcmFtZWQgaW4gdGVybXMgb2Ygd2hldGhlciBwZW9wbGUgYXJlIGFibGUgdG8g4oCcYmXigJ0gYW5kIOKAnGRv4oCdIGRlc2lyYWJsZSB0aGluZ3MgaW4gbGlmZSwgSERJIHdhcyBkZXZlbG9wZWQgYnkgUGFraXN0YW5pIGVjb25vbWlzdCBNYWhidWIgdWwgSGFxIGFuZCBpcyBiYWNrZWQgYnkgdGhlIFVuaXRlZCBOYXRpb25zLiBUaGUgaGlnaGVyIHRoZSBudW1iZXIsIHRoZSBtb3JlIOKAnGRldmVsb3BlZOKAnSB0aGUgY291bnRyeS4KCkkgbGlrZSB0aGlzIHN1bW1hcnkgb2YgdGhpcyBtZXRyaWMgdHJhY2tpbmcgaWYgcGVvcGxlIGNhbiAiYmUiIGFuZCAiZG8iIHRoZSB0aGluZ3MgdGhleSB3YW50LgoKIyMjIyBIYXBweSBQbGFuZXQgSW5kZXgKCj4gVGhpcyB1c2VzIGdsb2JhbCBkYXRhIG9uIGxpZmUgZXhwZWN0YW5jeSwgZXhwZXJpZW5jZWQgd2VsbC1iZWluZywgYW5kIGVjb2xvZ2ljYWwgZm9vdHByaW50IHRvIGNhbGN1bGF0ZSBhbiBpbmRleCB0aGF0IHJhbmtzIGNvdW50cmllcyBvbiBob3cgbWFueSBsb25nIGFuZCBoYXBweSBsaXZlcyB0aGV5IHByb2R1Y2UgcGVyIHVuaXQgb2YgZW52aXJvbm1lbnRhbCBpbnB1dC4gVGhlIGhpZ2hlciB0aGUgbnVtYmVyLCB0aGUgaGFwcGllciB0aGUgcG9wdWxhdGlvbi4KCiMjIyMgR2luaSBDb2VmZmljaWVudAoKPiBPbmUgb2YgdGhlIGJpZ2dlc3QgaXNzdWVzIHdpdGggR0RQIGlzIHRoYXQgaXQgaWdub3JlcyBpbmVxdWFsaXR5LiBUaGUgR2luaSBjb2VmZmljaWVudCwgaW52ZW50ZWQgaW4gMTkxMiBieSBJdGFsaWFuIHN0YXRpc3RpY2lhbiBDb3JyYWRvIEdpbmksIHJlcHJlc2VudHMgdGhlIGluY29tZSBkaXN0cmlidXRpb24gb2YgYSBuYXRpb27igJlzIHJlc2lkZW50cy4gQSBsb3cgbnVtYmVyIHJlcHJlc2VudHMgbG93IGluZXF1YWxpdHksIHdoaWxlIGEgaGlnaCBvbmUgaW5kaWNhdGVzIGEgbWFqb3IgZ2FwIGJldHdlZW4gdGhlIHJpY2ggYW5kIHBvb3IuCgpBbmQgZnJvbSB0aGUgW0NJQSBGYWN0Ym9va10oaHR0cHM6Ly93d3cuY2lhLmdvdi9saWJyYXJ5L3B1YmxpY2F0aW9ucy90aGUtd29ybGQtZmFjdGJvb2svcmFua29yZGVyLzIxNzJyYW5rLmh0bWwpOiAKCj4gR2luaSBpbmRleCBtZWFzdXJlcyB0aGUgZGVncmVlIG9mIGluZXF1YWxpdHkgaW4gdGhlIGRpc3RyaWJ1dGlvbiBvZiBmYW1pbHkgaW5jb21lIGluIGEgY291bnRyeS4gVGhlIG1vcmUgbmVhcmx5IGVxdWFsIGEgY291bnRyeSdzIGluY29tZSBkaXN0cmlidXRpb24sIHRoZSBsb3dlciBpdHMgR2luaSBpbmRleCwgZS5nLiwgYSBTY2FuZGluYXZpYW4gY291bnRyeSB3aXRoIGFuIGluZGV4IG9mIDI1LiBUaGUgbW9yZSB1bmVxdWFsIGEgY291bnRyeSdzIGluY29tZSBkaXN0cmlidXRpb24sIHRoZSBoaWdoZXIgaXRzIEdpbmkgaW5kZXgsIGUuZy4sIGEgU3ViLVNhaGFyYW4gY291bnRyeSB3aXRoIGFuIGluZGV4IG9mIDUwLiBJZiBpbmNvbWUgd2VyZSBkaXN0cmlidXRlZCB3aXRoIHBlcmZlY3QgZXF1YWxpdHkgdGhlIGluZGV4IHdvdWxkIGJlIHplcm87IGlmIGluY29tZSB3ZXJlIGRpc3RyaWJ1dGVkIHdpdGggcGVyZmVjdCBpbmVxdWFsaXR5LCB0aGUgaW5kZXggd291bGQgYmUgMTAwLgoKIyMjIyBHcm9zcyBOYXRpb25hbCBJbmNvbWUgKEdOSSkKClRoaXMgb25lIGlzICoqbm90KiogaW4gb3VyIGRhdGFzZXQsIGJ1dCBkb2VzIHNvdW5kIGludGVyZXN0aW5nIGZyb20gaXRzIGRlc2NyaXB0aW9uOgoKPiBHTkkgbWVhc3VyZXMgdGhlIGVjb25vbWljIG91dHB1dCBvZiBpdHMgY2l0aXplbnMsIHRha2luZyBpbnRvIGFjY291bnQgdGhlIGdsb2JhbGl6YXRpb24gb2YgbW9kZXJuIGJ1c2luZXNzLiBJdOKAmXMgY2FsY3VsYXRlZCBieSBhZGRpbmcgdXAgYWxsIHRoZSBpbmNvbWUgb2YgdGhlIHJlc2lkZW50cyBvZiBhIGNvdW50cnksIGluY2x1ZGluZyB0aGF0IHJlY2VpdmVkIGZyb20gYWJyb2FkLiBBcyBzdWNoLCBpdCBoZWxwcyBzaG93IHRoZSBlY29ub21pYyBzdHJlbmd0aCBvZiBhIGNvdW50cnnigJlzIHBvcHVsYXRpb24sIHJhdGhlciB0aGFuIHRoZSBjb3VudHJ5IGl0c2VsZi4gCgoKIyMjIyBFY29ub21pYyBGcmVlZG9tCgpUaGlzIG9uZSBpcyBub3QgbGlzdGVkIGluIHRoZSBHRFAgYWx0ZXJuYXRpdmVzIHNpdGUsIGJ1dCBzb3VuZHMgbGlrZSBhIHZlcnkgaW50ZXJlc3RpbmcgbWVhc3VyZW1lbnQgdG8gbG9vayBtb3JlIGNsb3NlbHkgYXQuIAoKRnJvbSB0aGUgW2luZGV4J3Mgc2l0ZV0oaHR0cHM6Ly93d3cuaGVyaXRhZ2Uub3JnL2luZGV4L2Fib3V0KToKCj4gRWNvbm9taWMgZnJlZWRvbSBpcyB0aGUgZnVuZGFtZW50YWwgcmlnaHQgb2YgZXZlcnkgaHVtYW4gdG8gY29udHJvbCBoaXMgb3IgaGVyIG93biBsYWJvciBhbmQgcHJvcGVydHkuIEluIGFuIGVjb25vbWljYWxseSBmcmVlIHNvY2lldHksIGluZGl2aWR1YWxzIGFyZSBmcmVlIHRvIHdvcmssIHByb2R1Y2UsIGNvbnN1bWUsIGFuZCBpbnZlc3QgaW4gYW55IHdheSB0aGV5IHBsZWFzZS4gSW4gZWNvbm9taWNhbGx5IGZyZWUgc29jaWV0aWVzLCBnb3Zlcm5tZW50cyBhbGxvdyBsYWJvciwgY2FwaXRhbCwgYW5kIGdvb2RzIHRvIG1vdmUgZnJlZWx5LCBhbmQgcmVmcmFpbiBmcm9tIGNvZXJjaW9uIG9yIGNvbnN0cmFpbnQgb2YgbGliZXJ0eSBiZXlvbmQgdGhlIGV4dGVudCBuZWNlc3NhcnkgdG8gcHJvdGVjdCBhbmQgbWFpbnRhaW4gbGliZXJ0eSBpdHNlbGYuCgo+IEVjb25vbWljIGZyZWVkb20gYnJpbmdzIGdyZWF0ZXIgcHJvc3Blcml0eS4gVGhlIEluZGV4IG9mIEVjb25vbWljIEZyZWVkb20gZG9jdW1lbnRzIHRoZSBwb3NpdGl2ZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBlY29ub21pYyBmcmVlZG9tIGFuZCBhIHZhcmlldHkgb2YgcG9zaXRpdmUgc29jaWFsIGFuZCBlY29ub21pYyBnb2Fscy4gVGhlIGlkZWFscyBvZiBlY29ub21pYyBmcmVlZG9tIGFyZSBzdHJvbmdseSBhc3NvY2lhdGVkIHdpdGggaGVhbHRoaWVyIHNvY2lldGllcywgY2xlYW5lciBlbnZpcm9ubWVudHMsIGdyZWF0ZXIgcGVyIGNhcGl0YSB3ZWFsdGgsIGh1bWFuIGRldmVsb3BtZW50LCBkZW1vY3JhY3ksIGFuZCBwb3ZlcnR5IGVsaW1pbmF0aW9uLgoKVGhpcyBzZWVtcyBsaWtlIGl0IGZhbGxzIHJpZ2h0IGluIHRoZSB3aGVlbGhvdXNlIG9mIHdoYXQgYSAiZ29vZCIgZ292ZXJubWVudCBjYW4gcHJvdmlkZSEKCiMjIyMgU3VzdGFpbmFibGUgRWNvbm9taWMgRGV2ZWxvcG1lbnQgQXNzZXNzbWVudCAoU0VEQSkKCkFsc28gbm90IGluIHRoZSBHRFAgYWx0ZXJuYXRpdmVzIGxpc3QuIFRoaXMgaXMgYSBuZXcgbWV0cmljIHRvIG1lYXN1cmUgd2VsbC1iZWluZy4gCgo+IFNFREEgaXMgcHJpbWFyaWx5IGFuIG9iamVjdGl2ZSBtZWFzdXJlIChjb21iaW5pbmcgZGF0YSBvbiBvdXRjb21lcywgc3VjaCBhcyBpbiBoZWFsdGggYW5kIGVkdWNhdGlvbiwgd2l0aCBxdWFzaS1vYmplY3RpdmUgZGF0YSwgc3VjaCBhcyBnb3Zlcm5hbmNlIGFzc2Vzc21lbnRzKS4gSXQgaXMgYWxzbyBhIHJlbGF0aXZlIG1lYXN1cmUgdGhhdCBhc3Nlc3NlcyBob3cgYSBjb3VudHJ5IHBlcmZvcm1zIGluIGNvbXBhcmlzb24gdG8gZWl0aGVyIHRoZSBlbnRpcmUgdW5pdmVyc2Ugb2YgY291bnRyaWVzIG9yIHRvIGluZGl2aWR1YWwgcGVlcnMgb3IgZ3JvdXBzLiAKClNFREEgdXNlcyAxMCBkaW1lbnNpb25zLCBpbmNsdWRpbmcgd2VhbHRoLCBxdWFsaXR5IG9mIGVudmlyb25tZW50LCBhbmQgaW5jb21lIGVxdWFsaXR5IHRvIGNhbGN1bGF0ZSBhIGNvdW50cnkncyBzY29yZS4gU291bmRzIGxpa2UgcXVpdGUgYSBjb21wb3NpdGUgbnVtYmVyIQoKIyMjIEV4cGxvcmluZyBEYXRhCgpOb3cgd2UgaGF2ZSBhIGJpdCBvZiBiYWNrc3Rvcnkgb24gdGhlIG1ldHJpY3MsIGxldCdzIGRpZyBtb3JlIGludG8gdGhlIGRhdGEgaXRzZWxmLgoKRmlyc3QsIEknbGwganVzdCByZW5hbWUgc29tZSBvZiB0aGUgY29sdW1ucyBmb3IgZWFzaWVyIGFjY2Vzcy4KCmBgYHtyfQpnb3ZfZGF0YSRnZHBfcGVyX2NhcCA8LSBnb3ZfZGF0YSRgR0RQIHBlciBjYXBpdGEgKFBQUClgCmdvdl9kYXRhJGhkaSA8LSBnb3ZfZGF0YSRgaHVtYW4gZGV2ZWxvcG1lbnQgaW5kZXhgCmdvdl9kYXRhJHNlZGEgPC0gZ292X2RhdGEkYHN1c3RhaW5hYmxlIGVjb25vbWljIGRldmVsb3BtZW50IGFzc2Vzc21lbnQgKFNFREEpYApnb3ZfZGF0YSRnaW5pIDwtIGdvdl9kYXRhJGBHSU5JIGluZGV4YApnb3ZfZGF0YSRlZnJlZSA8LSBnb3ZfZGF0YSRgb3ZlcmFsbCBlY29ub21pYyBmcmVlZG9tIHNjb3JlYCAKYGBgCgpXZSBjYW4gYWxzbyBjYWxjdWxhdGUgYSBmZXcgYWRkaXRpb25hbCBtZXRyaWNzIHVzaW5nIHRoZSBkYXRhIHdlIGhhdmUsIHRoYXQgbWlnaHQgYmUgdXNlZnVsIGZvciBzaG93aW5nIHBhdHRlcm5zLgoKYGBge3J9CiMgcG9wdWxhdGlvbiBkZW5zaXR5Cmdvdl9kYXRhJHBvcF9kZW5zaXR5IDwtIGdvdl9kYXRhJHBvcHVsYXRpb24gLyBnb3ZfZGF0YSRgc3VyZmFjZSBhcmVhIChLbTIpYAoKIyB0aGlzIGlzIGEgc3VnZ2VzdGVkIG1heCBwb3B1bGF0aW9uIGZvciAnc21hbGwnIGNvdW50cmllcwpzbWFsbF9jb3VudHJ5X21heF9wb3AgPSA1MDAwMDAwCgojIHdlIGNhbiB1c2UgdGhpcyB0aHJlc2hvbGQgdG8gY3JlYXRlIGEgbmV3IGNhdGVnb3JpY2FsIGNvbHVtbgpnb3ZfZGF0YSRjb3VudHJ5X3NpemUgPC0gaWZlbHNlKGdvdl9kYXRhJHBvcHVsYXRpb24gPiBzbWFsbF9jb3VudHJ5X21heF9wb3AsICdiaWcnLCAnbGl0dGxlJykKCmdvdl9kYXRhJGxvZ19nZHAgPC0gbG9nKGdvdl9kYXRhJGdkcF9wZXJfY2FwKQpgYGAKCioqSERJKioKCkkgbGlrZSB0byB1c2UgW2hpc3RvZ3JhbXNdKGh0dHA6Ly92YWxsYW5kaW5naGFtLm1lL3F1aWNrZHJhd190YWxrLmh0bWwpIHRvIGdldCBhIHF1aWNrIHNlbnNlIG9mIHdoYXQncyBpbiBhIGRhdGFzZXQsIGFuZCB0byB1bmNvdmVyIGFueSBtaXN0YWtlcyB3aXRoIGltcG9ydGluZyBkYXRhIGludG8gUi4gCgpTbyBsZXQncyB0YWtlIGEgcXVpY2sgbG9vayBhdCB0aGUgSHVtYW4gRGV2ZWxvcG1lbnQgSW5kZXggKEhESSkgcHJvdmlkZWQuIFdlIHdpbGwgdXNlIFtnZ3Bsb3RdKCkgdG8gdmlzdWFsaXplLiAKCmBgYHtyfQpnb3ZfZGF0YSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBoZGkpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAwLjA1KSArCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgSERJIikKYGBgCgpBIGNoYWxsZW5nZSB3aXRoIGhpc3RvZ3JhbXMgaXMgcGlja2luZyBnb29kIGJpbnMuLi4gSSd2ZSB1c2VkIGEgYmlud2lkdGggb2YgYDAuMDVgIGp1c3QgYmVjYXVzZSBJIGtub3cgdGhlIEhESSBzaG91bGQgcmFuZ2UgYmV0d2VlbiAwIGFuZCAxLCBhbmQgSSB3YW50ZWQgdG8gc2VlIGdlbmVyYWxseSB3aGVyZSB0aGVyZSBhcmUgZ2FwcyBhbmQgb3ZlcmxhcHMuIAoKVGhlIHdhcm5pbmcgYWxzbyBpbmRpY2F0ZXMgdGhhdCB0aGVyZSBhcmUgOSBjb3VudHJpZXMgd2l0aCBubyBIREkgZGF0YS4gTm90IHRvbyBtYW55LCBnaXZlbiB0aGUgZGF0YXNldCBjb250YWlucyAxOTUgY291bnRyaWVzLiBTdGlsbCB0aGVzZSBtaWdodCBiZSBnb29kIHRvIGZpbHRlciBvdXQsIGlmIHdlIHB1cnN1ZSBIREkgZnVydGhlci4KCioqR0RQKioKCk5leHQsIGxldCdzIHRha2UgYSBxdWljayBsb29rIGF0IEdEUC4KCmBgYHtyfQpnb3ZfZGF0YSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBnZHBfcGVyX2NhcCkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zPTMwKSArCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgR0RQIikKYGBgCgpBaCwgd2Ugc2VlIGEgbXVjaCBkaWZmZXJlbnQgZGlzdHJpYnV0aW9uIGhlcmUhIFRoaXMgbG9va3MgYSBiaXQgZXhwb25lbnRpYWwsIHdoaWNoIGlzIG5vdCB0b28gc3VycHJpc2luZy4gTGV0J3MgdGFrZSBhIGxvb2sgYXQgdGhlIGNvdW50cmllcyB3aXRoIF9yZWFsbHlfIGJpZyBHRFAgcGVyIGNhcGl0YQoKYGBge3J9Cmdvdl9kYXRhICU+JSAKICBmaWx0ZXIoZ2RwX3Blcl9jYXAgPiA1MDAwMCkgJT4lIAogIGFycmFuZ2UoLWdkcF9wZXJfY2FwKSAlPiUgCiAgc2VsZWN0KGNvdW50cnksIGdkcF9wZXJfY2FwLCBjb3VudHJ5X3NpemUpCmBgYAoKV2UgY2FuIHNlZSB0aGF0IG1vc3Qgb2YgdGhlc2UgYXJlICdsaXR0bGUnIGNvdW50cmllcyAtIHdpdGggc21hbGxlciBwb3B1bGF0aW9ucy4gQXMgbm90ZWQsIHRoZXNlIGNvdW50cmllcyBjYW4gc2tldyByZXN1bHRzIChhbmQgdGhleSBkbyAtIGp1c3QgY2hlY2sgdGhlIGhpc3RvZ3JhbSkuIFRoZXkgYXJlIGNhbmRpZGF0ZXMgdG8gZmlsdGVyIG91dCBpZiB3ZSBhcmUgbW9yZSBjb25jZXJuZWQgd2l0aCB0ZWxsaW5nIGEgJ2JpZyBwaWN0dXJlJyBzdG9yeS4gCgoqKkhESSB2cyBHRFAqKgoKQSBzY2F0dGVycGxvdCBjYW4gc2hvdyBhIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHR3byB2YXJpYWJsZXMuIEhlcmUsIHdlIGNhbiBjaGVjayB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gSERJIGFuZCBHRFAuCgoKYGBge3J9Cmdvdl9kYXRhICU+JQogIGdncGxvdChhZXMoeCA9IGdkcF9wZXJfY2FwLCB5ID0gaGRpLCBjb2xvdXIgPSBjb3VudHJ5X3NpemUpKSArCiAgZ2VvbV9wb2ludChzaXplPTIpICsKICBnZW9tX3RleHQoY2hlY2tfb3ZlcmxhcCA9IFRSVUUsIGFlcyhsYWJlbCA9IGNvdW50cnkpLCBjb2xvdXIgPSAnIzMzMzMzMycsIGFscGhhID0gMC43KSArCiAgbGFicyh0aXRsZSA9ICJIREkgdnMgR0RQIikKYGBgCgpJJ3ZlIGNvbG9yZWQgdGhlIHBvaW50cyBieSBjb3VudHJ5IHNpemUsIHNvIHdlIGNhbiBzZWUgdGhlIGltcGFjdCBvZiB0aGVzZSBsaXR0bGUgY291bnRyaWVzIGFnYWluLiBCdXQgdGhlcmUgaXMgZGVmaW5pdGVseSBhIHJlbGF0aW9uc2hpcCBoZXJlLCBpbmRpY2F0aW5nIHRoYXQgSERJIGltcGFjdHMgR0RQIG9yIHZpY2UgdmVyc2EuIAoKCioqTWV0cmljIENvcnJlbGF0aW9ucyoqCgpXaGF0IG90aGVyIHJlbGF0aW9uc2hpcHMgYXJlIHRoZXJlIGluIHRoaXMgZGF0YXNldD8gCgpMZXQncyBqYW0gYSBidW5jaCB0b2dldGhlciBpbnRvIGEgZmFjZXR0ZWQgc2NhdHRlcnBsb3QhIFRoZSBidWlsdCBpbiBgcGxvdCgpYCBwYWNrYWdlIHdpbGwgZG8gdGhpcyBmb3IgdXMgbmljZWx5LiBCZWxvdywgSSBqdXN0IGZpbHRlciBhIHNtYWxsIHN1YnNldCBvZiB0aGUgZGF0YSBzbyB0aGF0IHRoZSByZWxhdGlvbnNoaXBzIGFyZSBzdGlsbCAoc29tZXdoYXQpIHZpc2FibGUuCgpgYGB7cn0KZ292X2RhdGEgJT4lIAogIHNlbGVjdChnZHBfcGVyX2NhcCwgZ2luaSwgZWZyZWUsIGBoYXBweSBwbGFuZXQgaW5kZXhgLCBoZGksIHNlZGEsIGB1bmVtcGxveW1lbnQgKCUpYCkgJT4lIAogIHBsb3QoKQpgYGAKClNvIHdlIGNhbiBzZWUgc29tZSBjb3JyZWxhdGlvbnMgdmlzdWFsbHkgZnJvbSB0aGVzZSBwbG90cywgbGV0J3MgcXVhbnRpZnkgdGhpcyBhIGJpdCBtb3JlIGJ5IHBsb3R0aW5nIGEgY29ycmVsYXRpb24gbWF0cml4LiBVc2luZyBhIFtuaWNlIHR1dG9yaWFsXShodHRwOi8vd3d3LnN0aGRhLmNvbS9lbmdsaXNoL3dpa2kvY29ycmVsYXRpb24tbWF0cml4LWEtcXVpY2stc3RhcnQtZ3VpZGUtdG8tYW5hbHl6ZS1mb3JtYXQtYW5kLXZpc3VhbGl6ZS1hLWNvcnJlbGF0aW9uLW1hdHJpeC11c2luZy1yLXNvZnR3YXJlKSBhcyBhIGd1aWRlLCBoZXJlIEkgdXNlIHRoZSBgY29yKClgIGZ1bmN0aW9uIHRvIGNhbGN1bGF0ZSB0aGUgY29ycmVsYXRpb24gdmFsdWVzIGJldHdlZW4gdGhlc2UgdmFyaWFibGVzLCB0aGVuIHBsb3QgdXNpbmcgYGNvcnJwbG90YAoKYGBge3J9CiMgSWYgeW91IGRvbid0IGhhdmUgY29ycnBsb3QgaW5zdGFsbCB3aXRoOgojIGluc3RhbGwucGFja2FnZXMoImNvcnJwbG90IikKbGlicmFyeShjb3JycGxvdCkKYGBgCgoKYGBge3J9Cmdvdl9kYXRhICU+JSAKICBzZWxlY3QoZ2RwX3Blcl9jYXAsIGdpbmksIGVmcmVlLCBgaGFwcHkgcGxhbmV0IGluZGV4YCwgaGRpLCBzZWRhLCBgdW5lbXBsb3ltZW50ICglKWApICU+JSAKICBjb3IodXNlID0gImNvbXBsZXRlLm9icyIpICU+JSAKICBjb3JycGxvdCh0eXBlID0gInVwcGVyIiwgb3JkZXIgPSAiaGNsdXN0IiwgdGwuY29sID0gImJsYWNrIiwgdGwuc3J0ID0gNDUpCmBgYAoKSXQgaXMgbm90IHRvbyBzdXJwcmlzaW5nIHRvIHNlZSBoaWdoIGNvcnJlbGF0aW9uIGJldHdlZW4gU0VEQSwgSERJLCBlY29ub21pYyBmcmVlZG9tLCBhbmQgR0RQLiAKCkkgYW0gYSBiaXQgc3VycHJpc2VkIHRoYXQgdGhlIGhhcHB5IHBsYW5ldCBpbmRleCBpcyBub3QgYXMgaGlnaGx5IGNvcnJlbGF0ZWQgd2l0aCB0aGVzZSBtZWFzdXJlcyBhcyB3ZWxsIC0gYnV0IHBlcmhhcHMgdGhhdCBpcyBiZWNhdXNlIG9mIHRoZSBlbnZpcm9ubWVudCBmb2N1cyBvZiB0aGlzIG1ldHJpYy4gVGhlcmUgaXMgbm90IG11Y2ggY29ycmVsYXRpb24gYmV0d2VlbiBIYXBweSBQbGFuZXQgYW5kIHRoZSBHRFAuIFRoaXMgaXMgdW5mb3J0dW5hdGUgLSBhcyB3ZSBjYW4ndCByZWFsbHkgbWFrZSBhbiBhcmd1bWVudCBmb3IgYW4gaW1wcm92ZWQgZW52aXJvbm1lbnRhbCBpbXBhY3QgbWFraW5nIGFuIGltcHJvdmVkIEdEUCAtIGF0IGxlYXN0IG5vdCBhdCB0aGUgdGltZSBiZWluZy4KCkl0IGlzIGFsc28gc3VycHJpc2luZyB0aGF0IHRoZSBHaW5pIGNvZWZmaWNpZW50IGlzIG5vdCBtb3JlIG5lZ2F0aXZlbHkgY29ycmVsYXRlZCB3aXRoIHNvbWUgb2YgdGhlc2Ugb3RoZXIgY29tYm8tbWV0cmljcy4gU0VEQSB0YWtlcyBpbmVxdWFsaXR5IGludG8gYWNjb3VudCBhcyBwYXJ0IG9mIGl0cyBjYWxjdWxhdGlvbiBzbyB0aGF0IGV4cGxhaW5zIHdoeSBpdCBpcyB0aGUgbW9zdCBuZWdhdGl2ZWx5IGNvcnJlbGF0ZWQuIAoKTm90IHNob3duLCBidXQgdGhpbmdzIGRvbid0IGNoYW5nZSB0b28gbXVjaCB3aGVuICdsaXR0bGUnIGNvdW50cmllcyBhcmUgcmVtb3ZlZC4gVHJ5IGl0IG91dCB5b3Vyc2VsZiB3aXRoIGFuIGFkZGl0aW9uYWwgYGZpbHRlcigpYCBpbiB0aGUgY29kZSBhYm92ZS4KCldoaWxlIHRoZXJlIGlzIHNvbWUgbmVnYXRpdmUgY29ycmVsYXRpb24gYmV0d2VlbiBHaW5pIGFuZCB3ZWxsLWJlaW5nIG1ldHJpY3MgbGlrZSBTRURBIGFuZCBIREksIGl0cyBzdGlsbCBwcmV0dHkgbWVzc3kuIAoKSGVyZSBpcyBhIHBsb3Qgc2hvd2luZyBIREkgdnMgR2luaSwgd2l0aCBzaXplcyBvZiBkb3RzIGluZGljYXRpbmcgdGhlIEdEUCAtIGFzIHRoYXQgd2FzIG5lZ2F0aXZlbHkgY29ycmVsYXRlZCBhcyB3ZWxsLiAKCmBgYHtyfQpnb3ZfZGF0YSAlPiUgICNmaWx0ZXIoY291bnRyeV9zaXplID09ICdiaWcnKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gZ2luaSwgeT1oZGksIGNvbG9yID0gY291bnRyeV9zaXplLCBzaXplID0gZ2RwX3Blcl9jYXApKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3RleHQoY2hlY2tfb3ZlcmxhcCA9IFRSVUUsIGFlcyhsYWJlbCA9IGNvdW50cnkpLCBjb2xvciA9ICIjMzMzMzMzIiwgc2l6ZSA9IDMpICsgCiAgbGFicyh0aXRsZSA9ICJIREkgdnMgR0lOSSIpCmBgYAoKV2UgY2FuIHNlZSB0aGF0IHJvdWdobHkgYW4gaW5jcmVhc2UgaW4gdGhlIEdpbmkgY29lZmZpY2llbnQgKG1lYW5pbmcgYW4gaW5jcmVhc2UgaW4gaW5lcXVhbGl0eSkgcmVzdWx0cyBpbiBhIGRlY3JlYXNlIGluIHRoZSBTRURBIG1ldHJpYyBmb3Igd2VsbC1iZWluZy4gVGhpcyBpcyB0cnVlIGZvciBHRFAgcGVyIGNhcGl0YSBhcyB3ZWxsLiBCdXQgdGhlIGNvcnJlbGF0aW9uIGlzIHdlYWsuIAoKQXMgYW4gYXNpZGUsIHdlIGNhbiBzZWUgdGhhdCB3ZSBhcmUgYWxzbyBtaXNzaW5nIGEgbG90IG9mIEdpbmkgc2NvcmVzIGZvciBjb3VudHJpZXMgLSBnaXZlbiB0aGUgd2FybmluZyBtZXNzYWdlcy4KCkNvdWxkIHN0aWxsIGNvbnRyaWJ1dGUgdG8gYW4gaW50ZXJlc3Rpbmcgc3RvcnkhCgoqKkxpbmVhciBSZWdyZXNzaW9uKioKCkFzIGEgcXVpY2sgbG9vayBhdCBob3cgdGhlc2UgdmFyaWFibGVzIHJlbGF0ZSwgbGV0J3MgYnVpbGQgYSBsaW5lYXIgbW9kZWwgdGhhdCB0cmllcyB0byBwcmVkaWN0IEdEUCBwZXIgY2FwaXRhIGZyb20gYSBjb21iaW5hdGlvbiBvZiB0aGUgSHVtYW4gRGV2ZWxvcG1lbnQgSW5kZXgsIHRoZSBHaW5pIGNvZWZmaWNpZW50LCBhbmQgdGhlIEVjb25vbWljIEZyZWVkb20gc2NvcmUuIFdlIHdpbGwgYXZvaWQgU0VEQSBmb3Igbm93LCBhcyBpdCBleHBsaWNpdGx5IHVzZXMgR0RQLWxpa2UgaW5wdXRzIGFzIHBhcnQgb2YgaXRzIGNhbGN1bGF0aW9uLiAKCmBgYHtyfQpsbV9vdXQgPC0gbG0oZm9ybXVsYSA9IGxvZ19nZHAgfiAgaGRpICsgZWZyZWUgKyBnaW5pLCBkYXRhID0gZ292X2RhdGEpCnN1bW1hcnkobG1fb3V0KQpgYGAKClNvLCByb3VnaGx5IHNwZWFraW5nLCBUaGVzZSBpbnB1dHMgY2FwdHVyZSB+ODAlIG9mIHRoZSB2YXJpYWJpbGl0eSBpbiB0aGUgbG9nLXRyYW5zZm9ybWVkIEdEUCAod2UgdXNlIHRoZSBsb2cgb2YgR0RQIHRvIG1ha2UgdGhhdCBleHBvbmVudGlhbCByZWxhdGlvbnNoaXAgd2Ugc2F3IGJlZm9yZSBsaW5lYXIpLgoKQXQgdGhpcyBwb2ludCwgSSBzdGFydGVkIHRoaW5raW5nIGFib3V0IHRoZSBwcm9ncmVzcyBvZiBhbiBpbmRpdmlkdWFsIGNvdW50cnkuIAoKVGhlIGNvbXBhcmlzb25zIHdlIGhhdmUgbG9va2VkIGF0IHNob3cgYSBzbmFwLXNob3Qgb2YgaG93IGNvdW50cmllcyBhcmUgcGVyZm9ybWluZyBub3csIGJ1dCB3aGF0IGFyZSB0aGUgZ2xvYmFsIGFuZCBsb2NhbCB0cmVuZHM/IFdoZXJlIGhhdmUgdGhlc2UgY291bnRyaWVzIF9iZWVuXyB0byByZWFjaCB0aGlzIHNwb3Q/IEFyZSB3ZSBtb3ZpbmcgZm9yd2FyZCB3aXRoIHRoZXNlIG1ldHJpY3Mgb2YgaHVtYW4gcHJvZ3Jlc3MsIG9yIGJhY2t3YXJkcz8gSXMgdGhlcmUgYSBjb25uZWN0aW9uIGJldHdlZW4gdGhlIHJlbGF0aXZlIHBlcmZvcm1hbmNlIG9mIGEgY291bnRyeSBvdmVyIHRpbWUgYW5kIGl0cyBHRFA/IAoKSSB3YW50ZWQgdG8gZmluZCB0aGUgYW5zd2VycyB0byBzb21lIG9mIHRoZXNlIHF1ZXN0aW9ucy4gQW5kIHRvIGRvIHRoYXQsIEkgbmVlZCBoaXN0b3JpY2FsIGRhdGEuIAoKCiMjIEhpc3RvcmljIE1ldHJpYyBEYXRhCgpGb3J0dW5hdGVseSwgdGhlIHN0YXJ0aW5nIGRhdGFzZXQgcHJvdmlkZWQgcmVmZXJlbmNlcyB0byB0aGUgc291cmNlcyBmb3IgYWxsIHRoZSBjb2x1bW5zIG9mIGRhdGEuIAoKQmVjYXVzZSB0aGUgU0VEQSBtZXRyaWMgaXMgc3VjaCBhbiBhbWFsZ2FtYXRpb24gb2Ygb3RoZXIgbWV0cmljcywgYW5kIGJlY2F1c2UgaXQgaXMgaGlnaGx5IGNvcnJlbGF0ZWQgd2l0aCB0aGUgb3RoZXIgbWVhc3VyZW1lbnRzLCBJIGNob3NlIG5vdCB0byBwdXJzdWUgaGlzdG9yaWNhbCBkYXRhIGZvciBpdC4gCgpJbnN0ZWFkLCBJIGZvY3VzZWQgb24gZ2V0dGluZyBoaXN0b3JpY2FsIGRhdGEgZm9yIEhESSwgZWNvbm9taWMgZnJlZWRvbSwgYW5kIEdpbmksIGFsb25nIHdpdGggdGhlIG1vcmUgdHJhZGl0aW9uYWwgR0RQIHZhbHVlLiAKCioqRWNvbm9taWMgRnJlZWRvbSoqCgpUaGUgW0hlcml0YWdlIEZvdW5kYXRpb25dKGh0dHBzOi8vd3d3Lmhlcml0YWdlLm9yZy9pbmRleC9leHBsb3JlP3ZpZXc9YnktcmVnaW9uLWNvdW50cnkteWVhcikgaGFzIGFuIG9wdGlvbiB0byB2aWV3IGFsbCB0aGUgaGlzdG9yaWMgZGF0YS4gVW5mb3J0dW5hdGVseSwgSSBjb3VsZG4ndCBnZXQgdGhlIGRvd25sb2FkIGJ1dHRvbiB0byBkb3dubG9hZCBtb3JlIHRoYW4ganVzdCB0aGUgY3VycmVudCB5ZWFyLiBTbyBpbnN0ZWFkLCBJIGNvcGllZCB0aGUgdGFibGUgYW5kIHBhc3RlZCBpdCBpbnRvIE51bWJlcnMgKHdoaWNoIHdvcmtlZCBidXQgdG9vayBmb3JldmVyKS4gVGhlbiBzYXZlZCBpdCBhcyBhIENTVi4gCgpgYGB7cn0KZmlsZW5hbWUgPC0gImRhdGEvaGVyaXRhZ2VfZWNvbm9taWNfZnJlZWRvbV9zY29yZS5jc3YiCmVjZnJlZV9kYXRhIDwtIHJlYWRfY3N2KGZpbGVuYW1lLCBuYSA9ICJOL0EiKQpgYGAKCioqSHVtYW4gRGV2ZWxvcG1lbnQgSW5kZXggKEhESSkqKgoKVGhlIFtVTiBwcm92aWRlcyBIREldKGh0dHA6Ly9oZHIudW5kcC5vcmcvZW4vaW5kaWNhdG9ycy8xMzc1MDYpIGFzIGEgQ1NWLiBJIGRvd25sb2FkZWQgaXQsIGVuc3VyZWQgdGhlIGVuY29kaW5nIHdhcyBpbiBVVEYtOCwgYW5kIHB1dCBpdCBpbiB0aGUgZGF0YSBkaXJlY3RvcnkuIFdlIGNhbiBsb2FkIGl0IGVhc2lseSwgYW5kIHF1aWNrbHkgcmVtb3ZlIGFsbCB0aGUgc3BhY2VyIGNvbHVtbnMuCgpgYGB7cn0KZmlsZW5hbWUgPC0gImRhdGEvSHVtYW4gRGV2ZWxvcG1lbnQgSW5kZXguY3N2IgpoZGlfZGF0YSA8LSByZWFkX2NzdihmaWxlbmFtZSkKIyBkcm9wIFgjIGNvbHVtbnMuIGRhbmdlcm91cywgYnV0IGVhc3kuIApoZGlfZGF0YSA8LSBoZGlfZGF0YSAlPiUgc2VsZWN0KC1jb250YWlucygnWCcpKQpgYGAKClRoZSBvcmlnaW5hbCB2ZXJzaW9uIGlzIGluIGEgIndpZGUiIGZvcm1hdCwgd2Ugd2FudCBpdCAibG9uZyIgLSBzbyB3ZSBjYW4gZWFzaWx5IGpvaW4gYnkgY291bnRyeSBhbmQgeWVhciB3aXRoIG90aGVyIGRhdGFzZXRzLiBbZ2F0aGVyKCldKGh0dHBzOi8vdGlkeXIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvZ2F0aGVyLmh0bWwpIGRvZXMgdGhpcyBuaWNlbHkgZm9yIHVzLiBOb3RlIHRoZSBjb29sIHVzZSBvZiBhIG5lZ2F0aXZlIGBvbmVfb2YoKWAgdG8gZXhjbHVkZSBhIHNwZWNpZmllZCBzZXQgb2YgY29sdW1ucywgYW5kIHRodXMgaW5jbHVkZSBhbGwgdGhlIG90aGVycy4KCmBgYHtyfQpoZGlfZGF0YV9sb25nIDwtIGhkaV9kYXRhICU+JSBnYXRoZXIoa2V5ID0gInllYXIiLCB2YWx1ZSA9ICJoZGlfdmFsdWUiLCAtb25lX29mKCJDb3VudHJ5IiwgIkhESSBSYW5rICgyMDE3KSIpKQpgYGAKClRoZW4sIG1ha2Ugc29tZSBxdWljayBkZXJpdmVkIGNvbHVtbnMgZm9yIGpvaW5pbmcuIAoKYGBge3J9CmhkaV9kYXRhX2xvbmckY291bnRyeSA8LSBoZGlfZGF0YV9sb25nJENvdW50cnkKaGRpX2RhdGFfbG9uZyR5ZWFyX24gPC0gYXMubnVtZXJpYyhoZGlfZGF0YV9sb25nJHllYXIpCmBgYAoKKipXb3JsZCBCYW5rIERhdGEqKgoKVGhlIHJlc3Qgb2YgdGhlIG1ldHJpY3MgSSBmb3VuZCBJIGNvdWxkIGdldCBmcm9tIHRoZSBbV29ybGQgQmFua10oaHR0cHM6Ly9kYXRhLndvcmxkYmFuay5vcmcvaW5kaWNhdG9yKS4gCgpMdWNreSBmb3IgbWUsIHdpdGggYSBiaXQgb2YgR29vZ2xpbmcsIEkgZm91bmQgdCBzd2VldCBzd2VldCBbd2JzdGF0cyBSIHBhY2thZ2VdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy93YnN0YXRzL3ZpZ25ldHRlcy9Vc2luZ190aGVfd2JzdGF0c19wYWNrYWdlLmh0bWwpIHdoaWNoIGFsbG93cyB5b3UgdG8gcHVsbCBkb3duIG11bHRpcGxlIFdvcmxkQmFuayBtZXRyaWNzIHZpYSBSISBTdXBlciBjb29sLCBhbmQgc3VwZXIgdXNlZnVsLiBUaGlzIHdpbGwgYmUgYSBwYWNrYWdlIHRvIGNoZWNrIG91dCBtb3JlIGZvciBmdXR1cmUgcHJvamVjdHMgYXMgd2VsbC4KCmBgYHtyfQojIGluc3RhbGwgd2l0aDoKIyBpbnN0YWxsLnBhY2thZ2VzKCd3YnN0YXRzJykKbGlicmFyeSh3YnN0YXRzKQpgYGAKClVzaW5nIHRoZSBzZWFyY2ggZmVhdHVyZSBvZiBgd2JzdGF0c2AgYW5kIHRoZSBvbmxpbmUgV29ybGQgQmFuayBpbmRpY2F0b3JzIHBhZ2UsIEkgZm91bmQgdGhlIElEJ3Mgb2YgdGhlIG1ldHJpY3MgSSB3YW50ZWQuIEhlcmUncyBob3cgdG8gcHVsbCBkb3duIHRoZSBkYXRhLCB3aXRoIHNvbWUgbm90ZXM6CgpgYGB7cn0KIyBNZXRyaWMgSURzCiMgTlkuR0RQLlBDQVAuUFAuQ0QgPSBHRFAgcGVyIGNhcGl0YSwgUFBQIChjdXJyZW50IGludGVybmF0aW9uYWwgJCkKIyBOWS5HRFAuTUtUUC5LRC5aRyA9IEdEUCBncm93dGggKGFubnVhbCAlKQojIE5ZLkdEUC5QQ0FQLktELlpHID0gR0RQIHBlciBjYXBpdGEgZ3Jvd3RoIChhbm51YWwgJSkgCiMgTlkuR05QLlBDQVAuUFAuQ0QgPSBHTkkgcGVyIGNhcGl0YSwgUFBQIChjdXJyZW50IGludGVybmF0aW9uYWwgJCkKIyBOWS5HTlAuUENBUC5LRC5aRyA9IEdOSSBwZXIgY2FwaXRhIGdyb3d0aCAoYW5udWFsICUpCgojIFNJLlBPVi5HSU5JID0gR0lOSSBpbmRleCAoV29ybGQgQmFuayBlc3RpbWF0ZSkKIyBTUC5QT1AuVE9UTCA9IHBvcHVsYXRpb24gdG90YWwKCmluZGljYXRvcnMgPC0gYygnTlkuR0RQLlBDQVAuUFAuQ0QnLCAnTlkuR05QLlBDQVAuUFAuQ0QnLCAnTlkuR05QLlBDQVAuS0QuWkcnLCAnU0kuUE9WLkdJTkknLCAnU1AuUE9QLlRPVEwnKQp3Yl9kYXRhIDwtIHdiKGNvdW50cnk9ICJhbGwiLCBpbmRpY2F0b3IgPSBpbmRpY2F0b3JzLCBzdGFydGRhdGUgPSAyMDAwLCBlbmRkYXRlID0gMjAxOCwgcmV0dXJuX3dpZGUgPSBUUlVFKQpgYGAKCllvdSdsbCBub3RlIHRoYXQgaSBsaW1pdGVkIHRoZSB5ZWFyIHJhbmdlIHRvIGJlIGJldHdlZW4gMjAwMCBhbmQgMjAxOC4gVGhpcyBzZWVtZWQgbGlrZSBhIGRlY2VudCBlbm91Z2ggeWVhciBzcGFuIHRvIHNlZSBzb21lIGNoYW5nZXMsIGJ1dCByZWNlbnQgZW5vdWdoIHRvIGJlIG1lYW5pbmdmdWwuIFBlcmhhcHMgSSBzaG91bGQgaGF2ZSBpbnZlc3RpZ2F0ZWQgZ29vZCB5ZWFyIHJhbmdlcyBtb3JlLgoKYGBge3J9CiMgbmVlZCBhIG51bWVyaWMgeWVhciBmb3Igam9pbmluZy4Kd2JfZGF0YSR5ZWFyID0gYXMubnVtZXJpYyh3Yl9kYXRhJGRhdGUpCmBgYAoKVW5mb3J0dW5hdGVseSwgdGhlIGhkaSBhbmQgZWNvbm9taWMgZnJlZWRvbSBoaXN0b3JpY2FsIGRhdGEgb25seSBoYXZlIGNvdW50cnkgbmFtZXMgLSBhbmQgbm90IElTTyBjb2Rlcy4gQSBodWdlIHNob3J0LXNpZ2h0ZWRuZXNzIGlmIHlvdSBhc2sgbWUuIFNvIHdlIGhhdmUgdG8gZG8gc29tZSB0d2Vha2luZyB0byBnZXQgbWF0Y2hlcyBhY3Jvc3MgdGhlc2UgdGhyZWUgZGF0YXNldHMuIEkndmUgdHdlYWtlZCB0aGUgbmFtZXMgaW4gdGhlIHN0YXJpbmcgQ1NWIGZpbGVzIGZvciBzb21lIGNvdW50cmllcywgYW5kIGJlbG93IHdlIGF1Z21lbnQgdGhlIHdvcmxkIGRhdGEgZm9yIHNvbWUgb3RoZXJzLiAKCgpgYGB7cn0Kd2JfZGF0YSRjb3VudHJ5IDwtIHJlY29kZSh3Yl9kYXRhJGNvdW50cnksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiWWVtZW4sIFJlcC4iID0gIlllbWVuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxhbyBQRFIiID0gIkxhb3MiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiS29yZWEsIERlbS4gUGVvcGxl4oCZcyBSZXAuIiA9ICJOb3J0aCBLb3JlYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJLb3JlYSwgUmVwLiIgPSAiU291dGggS29yZWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRWd5cHQsIEFyYWIgUmVwLiIgPSAiRWd5cHQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSXJhbiwgSXNsYW1pYyBSZXAuIiA9ICJJcmFuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNsb3ZhayBSZXB1YmxpYyIgPSAiU2xvdmFraWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVmVuZXp1ZWxhLCBSQiIgPSAiVmVuZXp1ZWxhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkhvbmcgS29uZyBTQVIsIENoaW5hIiA9ICJIb25nIEtvbmciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ29uZ28sIERlbS4gUmVwLiIgPSAiRFIgQ29uZ28iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ29uZ28sIFJlcC4iID0gIlJlcHVibGljIG9mIENvbmdvIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCmBgYAoKCgoqKlJlZ2lvbiBEYXRhKioKCkZpbmFsbHksIEkgd2FudGVkIGEgd2F5IHRvIGdyb3VwIHRoZXNlIGNvdW50cmllcyBpbnRvIGhpZ2hlciB0aGVtZXMuIEkgaGFwcGVuZWQgdXBvbiBbdGhpcyBHaXRodWIgcmVwb10oaHR0cHM6Ly9naXRodWIuY29tL2x1a2VzL0lTTy0zMTY2LUNvdW50cmllcy13aXRoLVJlZ2lvbmFsLUNvZGVzKSB3aGljaCBpbmNsdWRlcyBhIG1hcHBpbmcgZnJvbSBpc28gY29kZSB0byByZWdpb24gbmFtZS4gU2VlbWVkIGxpa2UgYSBnb29kIGFkZGl0aW9uIHRvIG1lIQoKYGBge3J9CmZpbGVuYW1lIDwtICJkYXRhL2NvdW50cnlfcmVnaW9ucy5jc3YiCnJlZ2lvbnNfZGF0YSA8LSByZWFkX2NzdihmaWxlbmFtZSkKYGBgCgojIyMgSm9pbmluZyBEYXRhCgpOb3cgdGhhdCB3ZSBoYXZlIGFsbCB0aGUgaW5ncmVkaWVudHMsIGxldCdzIGpvaW4gdGhlbSBhbGwgdG9nZXRoZXIgaW4gYSBzdXBlciBkYXRhZnJhbWUhCgpUaGVyZSBhcmUgcHJvYmFibHkgYmV0dGVyIHdheXMgdG8gZG8gdGhpcyBpbiBSLCBidXQgSSB3ZW50IHdpdGggcGllY2V3aXNlIGpvaW5pbmcgd2l0aCBgbGVmdF9qb2luKClgLgoKYGBge3J9CmVjZnJlZV9oZGlfZGF0YSA8LSBsZWZ0X2pvaW4oZWNmcmVlX2RhdGEsIGhkaV9kYXRhX2xvbmcsIGJ5ID0gYygibmFtZSIgPSAiY291bnRyeSIsICJpbmRleCB5ZWFyIiA9ICJ5ZWFyX24iKSkKYGBgCgpgYGB7cn0KZWNmcmVlX2hkaV93Yl9kYXRhIDwtIGxlZnRfam9pbihlY2ZyZWVfaGRpX2RhdGEsIHdiX2RhdGEsIGJ5ID0gYygibmFtZSIgPSAiY291bnRyeSIsICJpbmRleCB5ZWFyIiA9ICJ5ZWFyIikpCmBgYAoKYGBge3J9CmVjZnJlZV9oZGlfd2JfZGF0YSA8LSBsZWZ0X2pvaW4oZWNmcmVlX2hkaV93Yl9kYXRhLCByZWdpb25zX2RhdGEsIGJ5ID0gYygiaXNvM2MiID0gImFscGhhLTMiKSkKYGBgCgoKClNvIG5vdyB0aGlzIG9kZGx5IG5hbWVkIGRhdGFmcmFtZSBgZWNmcmVlX2hkaV93Yl9kYXRhYCBpbmNsdWRlcyBjb2x1bW5zIGZyb20gdGhlIGFib3ZlIHNvdXJjZXMuIAoKCgoqKk5vcm1hbGl6YXRpb24qKgoKSGFzdGlseSwgSSBhZGRlZCBldmVuIG1vcmUgY29sdW1ucyB0byB0aGUgZGF0YXNldCBmb3IgZWFzaWVyIGFjY2Vzcy4KCgpgYGB7cn0KIyByZW5hbWVzIHRvIG1ha2UgYWNjZXNzaW5nIGNvbHVtbnMgZWFzaWVyLgojIHNob3VsZCBwcm9iYWJseSByZW5hbWUgY29sdW1uIGRpcmVjdGx5LCBpbnN0ZWFkIG9mIGp1c3QgdGFja2luZyBvbiBtb3JlIGNvbHVtbnMKZWNmcmVlX2hkaV93Yl9kYXRhJGNvdW50cnkgPC0gZWNmcmVlX2hkaV93Yl9kYXRhJG5hbWUueAplY2ZyZWVfaGRpX3diX2RhdGEkeWVhciA8LSBlY2ZyZWVfaGRpX3diX2RhdGEkYGluZGV4IHllYXJgCmVjZnJlZV9oZGlfd2JfZGF0YSRoZGkgPC0gZWNmcmVlX2hkaV93Yl9kYXRhJGhkaV92YWx1ZQplY2ZyZWVfaGRpX3diX2RhdGEkZWZyZWUgPC0gZWNmcmVlX2hkaV93Yl9kYXRhJGBvdmVyYWxsIHNjb3JlYAplY2ZyZWVfaGRpX3diX2RhdGEkZ2luaSA8LSBlY2ZyZWVfaGRpX3diX2RhdGEkU0kuUE9WLkdJTkkKCmVjZnJlZV9oZGlfd2JfZGF0YSRwb3B1bGF0aW9uIDwtIGVjZnJlZV9oZGlfd2JfZGF0YSRTUC5QT1AuVE9UTAplY2ZyZWVfaGRpX3diX2RhdGEkZ25pX3Blcl9jYXAgPC0gZWNmcmVlX2hkaV93Yl9kYXRhJE5ZLkdOUC5QQ0FQLlBQLkNECmVjZnJlZV9oZGlfd2JfZGF0YSRnbmlfcGVyX2NhcF9wZXJjZW50IDwtIGVjZnJlZV9oZGlfd2JfZGF0YSROWS5HTlAuUENBUC5LRC5aRwplY2ZyZWVfaGRpX3diX2RhdGEkZ2RwX3Blcl9jYXAgPC0gZWNmcmVlX2hkaV93Yl9kYXRhJE5ZLkdEUC5QQ0FQLlBQLkNECgplY2ZyZWVfaGRpX3diX2RhdGEkY291bnRyeV9zaXplIDwtIGlmZWxzZShlY2ZyZWVfaGRpX3diX2RhdGEkcG9wdWxhdGlvbiA+IHNtYWxsX2NvdW50cnlfbWF4X3BvcCwgJ2JpZycsICdsaXR0bGUnKQpgYGAKCiMjIyBEYXRhIEV4cGxvcmF0aW9uIAoKTm93IHdlIGNhbiBkbyBzb21lIGV4cGxvcmluZyEKCkZpcnN0LCBsZXQncyBsb29rIGF0IGp1c3QgYSBzaW5nbGUgeWVhciwgYW5kIGNvbXBhcmUgSERJIHRvIEdEUCBsaWtlIHdlIGRpZCBhYm92ZSAtIHRvIGNvbmZpcm0gdGhlIGhpc3RvcmljYWwgZGF0YSBpc24ndCByYWRpY2FsbHkgZGlmZmVyZW50LiAKCmBgYHtyfQplY2ZyZWVfaGRpX3diX2RhdGEgJT4lIGZpbHRlcih5ZWFyID09IDIwMTcpICU+JQogIGdncGxvdChhZXMoeCA9IGdkcF9wZXJfY2FwLCB5ID0gaGRpKSkgKyAKICBsYWJzKHRpdGxlID0gIkdEUCB2cyBIREkiKSArIAogIGdlb21fdGV4dChjaGVja19vdmVybGFwID0gVFJVRSwgYWVzKGxhYmVsID0gY291bnRyeSkpICsgCiAgZ2VvbV9wb2ludCgpCmBgYAoKV2UgY2FuIHVzZSBgZmFjZXRfd3JhcCgpYCB0byBzaG93IHRoZSBzYW1lIGRhdGEgZm9yIGEgc3Vic2V0IG9mIHRoZSB5ZWFycy4gCgpgYGB7cn0KZWNmcmVlX2hkaV93Yl9kYXRhICU+JSBmaWx0ZXIoeWVhciA+IDIwMDYpICU+JQogIGdncGxvdChhZXMoeCA9IGdkcF9wZXJfY2FwLCB5ID0gaGRpKSkgKyAKICBsYWJzKHRpdGxlID0gIkdEUCB2cyBIREkgLSAyMDA3IC0gMjAxNyIpICsgCiAgZ2VvbV9wb2ludChhbHBoYT0wLjIsIHNpemU9MSkgKyAKICBnZW9tX3RleHQoY2hlY2tfb3ZlcmxhcCA9IFRSVUUsIGFlcyhsYWJlbCA9IGNvdW50cnkpLCBzaXplID0gMikgKwogIGZhY2V0X3dyYXAofiB5ZWFyKQpgYGAKClRoaW5ncyBhcmUgbG9va2luZyBwcmV0dHkgZ29vZCwgdGhvdWdoIHdlIG5vdGUgd2UgYXJlIG1pc3NpbmcgMjAxOCBkYXRhLiBUaGlzIGlzIGJlY2F1c2UgV29ybGQgQmFuayBkb2Vzbid0IGhhdmUgdGhpcyBkYXRhIGF2YWlsYWJsZSB5ZXQuIAoKTGV0J3MgbG9vayBhdCB0aGUgY29ycmVsYXRpb25zIGZvciB0aGUgZGlmZmVyZW50IG1ldHJpY3MgbGlrZSB3ZSBkaWQgYmVmb3JlLCBidXQgbm93IHdpdGggYWxsIHRoZXNlIGFkZGl0b25hbCB0aW1lIHBvaW50cywgdG8gZW5zdXJlIHRoZSBjb25uZWN0aW9ucyBob2xkLgoKYGBge3J9CmVjZnJlZV9oZGlfd2JfZGF0YSAlPiUgCiAgc2VsZWN0KGdkcF9wZXJfY2FwLCBnaW5pLCBlZnJlZSwgaGRpKSAlPiUgCiAgY29yKHVzZSA9ICJjb21wbGV0ZS5vYnMiKSAlPiUgCiAgY29ycnBsb3QodHlwZSA9ICJ1cHBlciIsIG9yZGVyID0gImhjbHVzdCIsIHRsLmNvbCA9ICJibGFjayIsIHRsLnNydCA9IDQ1KQpgYGAKCkFwcGVhcnMgdG8gYmUgcHJldHR5IHNpbWlsYXIhCgojIyMgR3JvdXBpbmcgYnkgQ291bnRyeQoKSSB3YW50ZWQgdG8gc2VlIHRyZW5kcyBpbiB0aGVzZSBtZXRyaWNzIG92ZXIgdGltZSBieSBjb3VudHJ5LiAKCkhlcmUgaXMgYSBncm91cGluZyBwcm9jZXNzIHRoYXQgdXNlcyBgZ3JvdXBfYnkoKWAgdG8gc3VtbWFyaXNlIGRhdGEgYnkgbWV0cmljLiBUaGVyZSBpcyBhIGJpdCBvZiB3b3JrIHRvIGRvIGFyb3VuZCBmaW5kaW5nIHRoZSBmaXJzdCBhbmQgbGFzdCB2YWx1ZXMsIGFzIG5vdCBhbGwgeWVhcnMgaGF2ZSBkYXRhIGZvciBhbGwgY291bnRyaWVzLiAKCioqR0RQKioKCmBgYHtyIHdhcm5pbmc9RkFMU0V9CmdkcF9ieV9jb3VudHJ5IDwtIGVjZnJlZV9oZGlfd2JfZGF0YSAlPiUgZ3JvdXBfYnkoY291bnRyeSkgJT4lIHN1bW1hcmlzZSgKICBmaXJzdF9nZHBfeWVhciA9IHllYXJbbWF4KHdoaWNoKCFpcy5uYShnZHBfcGVyX2NhcCkpKV0sIAogIGxhc3RfZ2RwX3llYXIgPSB5ZWFyW21pbih3aGljaCghaXMubmEoZ2RwX3Blcl9jYXApKSldLCAKICB5ZWFyc19vZl9nZHAgPSBsYXN0X2dkcF95ZWFyIC0gZmlyc3RfZ2RwX3llYXIsCiAgZmlyc3RfZ2RwX3ZhbHVlID0gZ2RwX3Blcl9jYXBbbWF4KHdoaWNoKCFpcy5uYShnZHBfcGVyX2NhcCkpKV0sIAogIGxhc3RfZ2RwX3ZhbHVlID0gZ2RwX3Blcl9jYXBbbWluKHdoaWNoKCFpcy5uYShnZHBfcGVyX2NhcCkpKV0sCiAgZ2RwX2NoYW5nZSA9IGxhc3RfZ2RwX3ZhbHVlIC0gZmlyc3RfZ2RwX3ZhbHVlLAogIGdkcF9jaGFuZ2VfYnlfeWVhciA9IGdkcF9jaGFuZ2UgLyB5ZWFyc19vZl9nZHAsCiAgYXZnX2dkcCA9IG1lYW4oZ2RwX3Blcl9jYXAsIG5hLnJtID0gVFJVRSkKICApCmBgYAoKYGBge3J9CmdkcF9ieV9jb3VudHJ5ICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBhdmdfZ2RwKSkgKyBnZW9tX2hpc3RvZ3JhbShiaW5zPTMwKQpgYGAKClNvIGFsbW9zdCBhbGwgY291bnRyaWVzIGluY3JlYXNlZCBpbiBHRFAsIHdoaWNoIG1ha2VzIHNlbnNlLiAKCioqR2luaSoqCgpgYGB7ciB3YXJuaW5nPUZBTFNFfQpnaW5pX2J5X2NvdW50cnkgPC0gZWNmcmVlX2hkaV93Yl9kYXRhICU+JSBncm91cF9ieShjb3VudHJ5KSAlPiUgc3VtbWFyaXNlKAogIGZpcnN0X2dpbmlfeWVhciA9IHllYXJbbWF4KHdoaWNoKCFpcy5uYShnaW5pKSkpXSwgCiAgbGFzdF9naW5pX3llYXIgPSB5ZWFyW21pbih3aGljaCghaXMubmEoZ2luaSkpKV0sIAogIHllYXJzX29mX2dpbmkgPSBsYXN0X2dpbmlfeWVhciAtIGZpcnN0X2dpbmlfeWVhciwKICBmaXJzdF9naW5pX3ZhbHVlID0gZ2luaVttYXgod2hpY2goIWlzLm5hKGdpbmkpKSldLCAKICBsYXN0X2dpbmlfdmFsdWUgPSBnaW5pW21pbih3aGljaCghaXMubmEoZ2luaSkpKV0sCiAgZ2luaV9jaGFuZ2UgPSBsYXN0X2dpbmlfdmFsdWUgLSBmaXJzdF9naW5pX3ZhbHVlLAogIGdpbmlfY2hhbmdlX2J5X3llYXIgPSBnaW5pX2NoYW5nZSAvIHllYXJzX29mX2dpbmksCiAgYXZnX2dpbmkgPSBtZWFuKGdpbmksIG5hLnJtID0gVFJVRSkKICApCgpnaW5pX2J5X2NvdW50cnkgPC0gZ2luaV9ieV9jb3VudHJ5ICU+JSBmaWx0ZXIoeWVhcnNfb2ZfZ2luaSA+IDEpCmdpbmlfYnlfY291bnRyeSRnaW5pX2NhdGVnb3J5ID0gaWZlbHNlKGdpbmlfYnlfY291bnRyeSRnaW5pX2NoYW5nZV9ieV95ZWFyIDwgMCwgIm1vcmUgZXF1YWwiLCAibGVzcyBlcXVhbCIpCmBgYAoKQSBsaXR0bGUgbW9yZSBlZmZvcnQgZ2V0cyBvdXIgZmlyc3QgYW5kIGxhc3QgdmFsdWVzIGluIGxvbmcgZm9ybWF0OgoKYGBge3J9Cmdpbmlfc3RhcnRfZW5kIDwtIGdpbmlfYnlfY291bnRyeSAlPiUgCiAgc2VsZWN0KGMoY291bnRyeSwgZ2luaV9jYXRlZ29yeSwgZmlyc3RfZ2luaV92YWx1ZSwgbGFzdF9naW5pX3ZhbHVlKSkgJT4lIAogIGdhdGhlcihrZXkgPSAibWV0cmljIiwgdmFsdWUgPSAidmFsdWUiLCBmaXJzdF9naW5pX3ZhbHVlLCBsYXN0X2dpbmlfdmFsdWUpCmBgYAoKV2hpY2ggd2UgY2FuIHZpc3VhbGl6ZToKCmBgYHtyfQpnaW5pX3N0YXJ0X2VuZCAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gbWV0cmljLCB5ID0gdmFsdWUsIGdyb3VwID0gY291bnRyeSwgY29sb3VyID0gZ2luaV9jYXRlZ29yeSkpICsKICBnZW9tX2xpbmUoKSArIAogIGdlb21fdGV4dChjaGVja19vdmVybGFwID0gVFJVRSwgYWVzKGxhYmVsID0gY291bnRyeSksIHNpemUgPSA0LCBjb2xvdXIgPSAnYmxhY2snKSArCiAgZmFjZXRfd3JhcCh+IGdpbmlfY2F0ZWdvcnkpCmBgYAoKSGVyZSBJIHdhbnRlZCB0byBzZWUgaWYgdGhlcmUgd2VyZSB0cmVuZHMgaW4gZ2luaSBtb3ZlbWVudCwgc28gSSBtYWRlIGEgcXVpY2sgc2xvcGVjaGFydCBiZXR3ZWVuIHRoZSBjb3VudHJ5J3MgZmlyc3QgYW5kIGxhc3QgR2luaSBpbmRleCB2YWx1ZS4gQ2hhbmdlcyBkb24ndCBzZWVtIHRvIGZvbGxvdyBhbnkgaW1tZWRpYXRlIHBhdHRlcm4uIAoKKipFY29ub21pYyBGcmVlZG9tKioKCmBgYHtyIHdhcm5pbmc9RkFMU0V9CmVmcmVlX2J5X2NvdW50cnkgPC0gZWNmcmVlX2hkaV93Yl9kYXRhICU+JSBncm91cF9ieShjb3VudHJ5KSAlPiUgc3VtbWFyaXNlKAogIGZpcnN0X2VmcmVlX3llYXIgPSB5ZWFyW21heCh3aGljaCghaXMubmEoZWZyZWUpKSldLCAKICBsYXN0X2VmcmVlX3llYXIgPSB5ZWFyW21pbih3aGljaCghaXMubmEoZWZyZWUpKSldLCAKICB5ZWFyc19vZl9lZnJlZSA9IGxhc3RfZWZyZWVfeWVhciAtIGZpcnN0X2VmcmVlX3llYXIsCiAgZmlyc3RfZWZyZWVfdmFsdWUgPSBlZnJlZVttYXgod2hpY2goIWlzLm5hKGVmcmVlKSkpXSwgCiAgbGFzdF9lZnJlZV92YWx1ZSA9IGVmcmVlW21pbih3aGljaCghaXMubmEoZWZyZWUpKSldLAogIGVmcmVlX2NoYW5nZSA9IGxhc3RfZWZyZWVfdmFsdWUgLSBmaXJzdF9lZnJlZV92YWx1ZSwKICBlZnJlZV9jaGFuZ2VfYnlfeWVhciA9IGVmcmVlX2NoYW5nZSAvIHllYXJzX29mX2VmcmVlLAogIGF2Z19lZnJlZSA9IG1lYW4oZWZyZWUsIG5hLnJtID0gVFJVRSkKICApCgplZnJlZV9ieV9jb3VudHJ5IDwtIGVmcmVlX2J5X2NvdW50cnkgJT4lIGZpbHRlcih5ZWFyc19vZl9lZnJlZSA+IDEpCmBgYAoKYGBge3J9CmVmcmVlX2J5X2NvdW50cnkgJT4lIAogIGdncGxvdChhZXMoeCA9IGxhc3RfZWZyZWVfdmFsdWUgLSBmaXJzdF9lZnJlZV92YWx1ZSkpICsgZ2VvbV9oaXN0b2dyYW0oKQpgYGAKCk1vc3QgY291bnRyaWVzIHJlbWFpbmVkIHJlbGF0aXZlbHkgc3RhYmxlLCB3aXRoIHNvbWUgYmlnIHVwcyBhbmQgZG93bnMuCgpIZXJlIGFyZSB0aGUgY291bnRyaWVzIHRoYXQgY2hhbmdlZCB0aGUgbW9zdDoKCmBgYHtyfQplZnJlZV9ieV9jb3VudHJ5ICU+JSAKICBmaWx0ZXIoYWJzKGVmcmVlX2NoYW5nZSkgPiAxNSkgJT4lIAogIGFycmFuZ2UoLTEgKiBlZnJlZV9jaGFuZ2UpICU+JQogIHNlbGVjdChjKGNvdW50cnksIGZpcnN0X2VmcmVlX3ZhbHVlLCBsYXN0X2VmcmVlX3ZhbHVlLCBlZnJlZV9jaGFuZ2UpKQpgYGAKCkhlcmUncyBqdXN0IGFub3RoZXIgd2F5IHRvIHBsb3QgdGhlIHNhbWUgZGF0YToKCmBgYHtyfQplZnJlZV9ieV9jb3VudHJ5ICU+JSAjZmlsdGVyKGFicyhsYXN0X2VmcmVlX3ZhbHVlIC0gZmlyc3RfZWZyZWVfdmFsdWUpID4gMTApICU+JQogIGdncGxvdChhZXMoeCA9IGZpcnN0X2VmcmVlX3ZhbHVlLCB5ID0gbGFzdF9lZnJlZV92YWx1ZSkpICsKICBnZW9tX3BvaW50KCkgKyAKICBnZW9tX3RleHQoY2hlY2tfb3ZlcmxhcCA9IFRSVUUsIGFlcyhsYWJlbCA9IGNvdW50cnkpLCBzaXplID0gNCkgKwogIGxhYnModGl0bGUgPSAiTGFzdCBFYyBGcmVlZG9tIFZhbHVlIHZzIEZpc3QgRWMgRnJlZWRvbSBWYWx1ZSBieSBDb3VudHJ5IikKYGBgCgoKIyMjIENvbm5lY3RlZCBTY2F0dGVycGxvdHMKCkF0IHRoaXMgcG9pbnQsIEkga25ldyBJIHdhbnRlZCB0byBzaG93IHRoZSBjb25uZWN0IGJldHdlZW4gdGhlc2UgZGlmZmVyZW50IG1ldHJpY3Mgb3ZlciB0aW1lLiBBbmQgSSBrbmV3IEkgd2FudGVkIHRvIHRyeSBzb21ldGhpbmcgYSBiaXQgbm92ZWwgaW4gdGVybXMgb2YgdmlzdWFsaXppbmcgbXVsdGlwbGUgbWV0cmNpcyB0b2dldGhlci4gU28gSSBkZWNpZGVkIHRvIGNoZWNrIG91dCB3aGF0IHRoaXMgZGF0YSBsb29rZWQgbGlrZSB1c2luZyBbY29ubmVjdGVkIHNjYXR0ZXIgcGxvdHNdKGh0dHBzOi8vZWFnZXJleWVzLm9yZy9wYXBlcnMvdGhlLWNvbm5lY3RlZC1zY2F0dGVycGxvdC1mb3ItcHJlc2VudGluZy1wYWlyZWQtdGltZS1zZXJpZXMpIQoKYGBge3J9CmVjZnJlZV9oZGlfd2JfZGF0YSAlPiUgZmlsdGVyKGNvdW50cnkgJWluJSBjKCdCcmF6aWwnLCAnQ2hpbmEnLCAnVW5pdGVkIEtpbmdkb20nLCAnVW5pdGVkIFN0YXRlcycpKSAlPiUgYXJyYW5nZShjb3VudHJ5LCB5ZWFyKSAlPiUKICBnZ3Bsb3QoYWVzKCB5ID0gaGRpLCB4ID0gZWZyZWUsIGNvbG91ciA9IGNvdW50cnkpKSArIAogIGdlb21fdGV4dChjaGVja19vdmVybGFwID0gVFJVRSwgYWVzKGxhYmVsID0geWVhcikpICsgCiAgZ2VvbV9wb2ludCgpICsgCiAgZ2VvbV9wYXRoKCkgKyAKICBsYWJzKHRpdGxlPSJDb25uZWN0ZWQgU2NhdHRlcnBsb3Q6IEhESSB2cyBFY29ub21pYyBGcmVlZG9tIikKYGBgCgpQcmV0dHkgbmljZSEgCgpIZXJlIGlzIGFsbCBvZiB0aGUgY291bnRyaWVzIHRvZ2V0aGVyOiAKCmBgYHtyfQplY2ZyZWVfaGRpX3diX2RhdGEgICU+JSBhcnJhbmdlKGNvdW50cnksIHllYXIpICU+JQogIGdncGxvdChhZXMoIHkgPSBoZGksIHggPSBnZHBfcGVyX2NhcCwgZ3JvdXAgPSBjb3VudHJ5KSkgKyAKICBnZW9tX3RleHQoY2hlY2tfb3ZlcmxhcCA9IFRSVUUsIGFlcyhsYWJlbCA9IHllYXIpLCBhbHBoYSA9IDAuNSkgKyAKICBnZW9tX3BvaW50KGFscGhhID0gMC4xKSArIAogIGdlb21fcGF0aChhbHBoYSA9IDAuMSkgKyAKICBsYWJzKHRpdGxlPSJDb25uZWN0ZWQgU2NhdHRlcnBsb3Q6IEFsbCBIREkgdnMgR0RQIikKYGBgCgoKT25lIG90aGVyIHRoaW5nIEkgd2FudGVkIHRvIHNlZSB3YXMgaG93IGEgY291bnRyeSBtb3ZlZCB0aHJvdWdoIHRoaXMgbWV0cmljIHNwYWNlIHJlbGF0aXZlIHRvIGl0c2VsZi4gSG93IGlzIGEgY291bnRyeSBwZXJmb3JtaW5nIGNvbXBhcmVkIHRvIG90aGVyIHllYXJzPwoKVGhhdCBpcyB3aGVyZSAgbm9ybWFsaXphdGlvbiAvIHNjYWxpbmcgY29tZXMgaW4gaGFuZHkhCgpgYGB7cn0KcmFuZ2UwMSA8LSBmdW5jdGlvbih4KXsoeC1taW4oeCwgbmEucm0gPSBUUlVFKSkvKG1heCh4LCBuYS5ybSA9IFRSVUUpLW1pbih4LCBuYS5ybSA9IFRSVUUpKX0KYGBgCgoKYGBge3Igd2FybmluZz1GQUxTRX0KZWNmcmVlX2hkaV93Yl9kYXRhIDwtIGVjZnJlZV9oZGlfd2JfZGF0YSAlPiUgCiAgZ3JvdXBfYnkoY291bnRyeSkgJT4lIAogIG11dGF0ZShoZGlfMDEgPSByYW5nZTAxKGhkaSksIGVmcmVlXzAxID0gcmFuZ2UwMShlZnJlZSksIGdkcF8wMSA9IHJhbmdlMDEoZ2RwX3Blcl9jYXApKSAlPiUgCiAgdW5ncm91cCgpCmBgYAoKCmBgYHtyfQplY2ZyZWVfaGRpX3diX2RhdGEgJT4lIGZpbHRlcihjb3VudHJ5ICVpbiUgYygnQnJhemlsJywgJ0NoaW5hJywgJ1VuaXRlZCBLaW5nZG9tJywgJ1VuaXRlZCBTdGF0ZXMnKSkgJT4lIGFycmFuZ2UoY291bnRyeSwgeWVhcikgJT4lCiAgZ2dwbG90KGFlcyggeSA9IGhkaV8wMSwgeCA9IGdkcF8wMSwgY29sb3VyID0gY291bnRyeSkpICsgCiAgZ2VvbV90ZXh0KGNoZWNrX292ZXJsYXAgPSBUUlVFLCBhZXMobGFiZWwgPSB5ZWFyKSkgKyAKICBnZW9tX3BvaW50KCkgKyAKICBnZW9tX3BhdGgoKSArIAogIGxhYnModGl0bGU9IkNvbm5lY3RlZCBTY2F0dGVycGxvdDogUmVsYXRpdmUgSERJIHZzIEdEUCIpCmBgYAoKUHJldHR5IGZ1biB0byBzZWUgYW4gaW5kaXZpZHVhbHMgYXJjLCBhcyB3ZWxsIGFzIGEgYml0IG9mIGNvbXBhcmlzb24gYmV0d2VlbiAKCiMjIyBTYXZpbmcgdG8gQ1NWCgpXaGlsZSB0aGlzIHJlcHJlc2VudHMgb25seSBhIHN1YnNldCBvZiB0aGUgZGF0YSBleHBsb3JhdGlvbiBJIGRpZCB0byBnZXQgdG8gdGhlIGZpbmFsIGZvcm0sIEkgdGhpbmsgaXQgZ2l2ZXMgYSBnb29kIHRhc3RlIGZvciB0aGUgYmFzaWMgbXVuZ2luZyBhbmQgc2VhcmNoaW5nIHJlcXVpcmVkLiAKClRvIGVuZCwgSSBzYXZlZCBhIHN1YnNldCBvZiBvdXIgY29tYmluZWQgZGF0YSB0byBDU1YgdG8gc3RhcnQgZGlnZ2luZyBpbiBtb3JlIHdpdGggRDMgaW4gdGhlIG1haW4gdmlzdWFsaXphdGlvbiBwaWVjZS4gCgoKYGBge3J9Cmdvdl9kYXRhX3NhdmUgPC0gZWNmcmVlX2hkaV93Yl9kYXRhICU+JSAKICBzZWxlY3QoY291bnRyeSwgaXNvM2MsIHJlZ2lvbiwgYHN1Yi1yZWdpb25gLCB5ZWFyLCBwb3B1bGF0aW9uLCBnbmlfcGVyX2NhcCwgZ25pX3Blcl9jYXBfcGVyY2VudCwgZ2RwX3Blcl9jYXAsIGVmcmVlLCBoZGksIGdpbmkpCndyaXRlX2Nzdihnb3ZfZGF0YV9zYXZlLCAib3V0cHV0L2dvdl9kYXRhX3llYXIuY3N2IikKYGBgCgoKRklOIAo=