Assignment Four: The Week Five Assignment

tidyr and WIR2022

  • Create an R Notebook of a Data Analysis containing the following and submit the rendered HTML file (e.g., a3_123456.nb.html by replacing 123456 with your ID)
    1. create an R Notebook using the R Notebook Template in Moodle, save it as a3_123456.Rmd,
    2. write your name and ID and the contents,
    3. run each code block,
    4. preview to create a3_123456.nb.html,
    5. submit a3_123456.nb.html to Moodle.
  1. Choose data with at least two categorical variables and at least two numerical variables.

    • Information of the data: Name, Indicator, Description, Source, etc.
    • Explain why you chose the indicator
    • List questions you want to study
  2. Explore the data using visualization using ggplot2.

    • Create various charts
    • Create at least one chart with at least two categorical variables and one numerical variable.
    • Create at least one chart with at least two numerical and one categorical variable.
  3. Observations based on your data visualization and difficulties and questions encountered, if any.

Due: 2023-01-23 23:59:00. Submit your R Notebook file in Moodle (The Fourth Assignment). Due on Monday!

1 Set up

library(tidyverse)
library(readxl) # for excel files
library(WDI)

1.1 World Development Indicator - WDI

The following is useful when you use WDI.

wdi_cache <- WDIcache()

Or, write the cache and read it from your computer. Since wdi_cache is a list of two data frames, we cannot use write_csv(); instead, we use write_rds.

write_rds(wdi_cache, "./data/wdi_cache")
wdi_cache <- read_rds("./data/wdi_cache")

WDIcache() produces a list containing two data frames: wdi_cache$series and wdi_cache$country.

glimpse(wdi_cache)
List of 2
 $ series :'data.frame':    21034 obs. of  5 variables:
  ..$ indicator         : chr [1:21034] "1.0.HCount.1.90usd" "1.0.HCount.2.5usd" "1.0.HCount.Mid10to50" "1.0.HCount.Ofcl" ...
  ..$ name              : chr [1:21034] "Poverty Headcount ($1.90 a day)" "Poverty Headcount ($2.50 a day)" "Middle Class ($10-50 a day) Headcount" "Official Moderate Poverty Rate-National" ...
  ..$ description       : chr [1:21034] "The poverty headcount index measures the proportion of the population with daily per capita income (in 2011 PPP"| __truncated__ "The poverty headcount index measures the proportion of the population with daily per capita income (in 2005 PPP"| __truncated__ "The poverty headcount index measures the proportion of the population with daily per capita income (in 2005 PPP"| __truncated__ "The poverty headcount index measures the proportion of the population with daily per capita income below the of"| __truncated__ ...
  ..$ sourceDatabase    : chr [1:21034] "LAC Equity Lab" "LAC Equity Lab" "LAC Equity Lab" "LAC Equity Lab" ...
  ..$ sourceOrganization: chr [1:21034] "LAC Equity Lab tabulations of SEDLAC (CEDLAS and the World Bank)." "LAC Equity Lab tabulations of SEDLAC (CEDLAS and the World Bank)." "LAC Equity Lab tabulations of SEDLAC (CEDLAS and the World Bank)." "LAC Equity Lab tabulations of data from National Statistical Offices." ...
 $ country:'data.frame':    299 obs. of  9 variables:
  ..$ iso3c    : chr [1:299] "ABW" "AFE" "AFG" "AFR" ...
  ..$ iso2c    : chr [1:299] "AW" "ZH" "AF" "A9" ...
  ..$ country  : chr [1:299] "Aruba" "Africa Eastern and Southern" "Afghanistan" "Africa" ...
  ..$ region   : chr [1:299] "Latin America & Caribbean" "Aggregates" "South Asia" "Aggregates" ...
  ..$ capital  : chr [1:299] "Oranjestad" "" "Kabul" "" ...
  ..$ longitude: chr [1:299] "-70.0167" "" "69.1761" "" ...
  ..$ latitude : chr [1:299] "12.5167" "" "34.5228" "" ...
  ..$ income   : chr [1:299] "High income" "Aggregates" "Low income" "Aggregates" ...
  ..$ lending  : chr [1:299] "Not classified" "Aggregates" "IDA" "Aggregates" ...

1.2 World Inequility Report - WIR2022

Please add mode="wb" (web binary). This should work better.

url_summary <- "https://wir2022.wid.world/www-site/uploads/2022/03/WIR2022TablesFigures-Summary.xlsx"
download.file(url = url_summary, 
              destfile = "./data/WIR2022s.xlsx", 
              mode = "wb") 

If you get an error, download the file directory from the methodology site into your computer, then open it with Excel and save it in the data folder of your R Studio project. Then R studio can recognize it easily as an Excel data.

Generally, a text file such as a CSV file is easy to import, but a binary file is difficult to handle. It is because unless R can recognize its file type, for example, Excel or so, R cannot import the data.

excel_sheets("./data/WIR2022s.xlsx")
 [1] "Index"     "F1"        "F2"        "F3"        "F4"        "F5."      
 [7] "F6"        "F7"        "F8"        "F9"        "F10"       "F11"      
[13] "F12"       "F13"       "F14"       "F15"       "T1"        "data-F1"  
[19] "data-F2"   "data-F3"   "data-F4"   "data-F5"   "data-F6"   "data-F7"  
[25] "data-F8"   "data-F9"   "data-F10"  "data-F11"  "data-F12"  "data-F13."
[31] "data-F14." "data-F15" 

2 General Comments

2.1 Reproducibility and Literate Programming

Reproducibility and Literate Programming are critical to exploratory data analysis (EDA). These are for communication; communication with readers of the paper, graders of the assignments, and communication with yourself, as we always forget. Please think about the reader of the article, and record the procedure and output so that reader can easily understand what you have done.

The data source is critical. Unless the reader obtains the same data quickly, the communication on EDA does not start. If the data is not downloaded automatically through the code chunk, you should explain how to obtain the data and the part of the data you applied. It is crucial when you use copying and paste using read_delim(clipboard()). Please describe the way for the reader to retrieve the same data easily. It is best to read your paper; in some cases, it can be a hard copy from the beginning to check whether the reader can reproduce what you have done in the article.

2.2 Varibles

In this Assignment Four, we required the following:

  • Create at least one chart with at least two categorical variables and one numerical variable.
  • Create at least one chart with at least two numerical and one categorical variable.

You can create a simple chart, such as a histogram or a box plot with only one variable. If you have two variables, you can create a scatter plot. But with ggplot2, you can create various charts with rich information using more than two variables. For example, the year can be used for both numerical and categorical variables using factor(year) or recognized as a character vector by as.character(year). So the distinction between categorical variables and numerical variables is flexible. The purpose of this assignment is to experience creating a chart with rich information using more than two variables.

However, I needed to clarify the variables’ requirements for some of you. So I sent out an extra message from Announcement that you do not need to take it so strictly.

If you use WDI, the following may be examples:

  • two categorical and one numerical: a. country, region, and indicator; b. country, income, and indicator; c. after selecting a couple of years and using factor(year), country, indicator, d. create a table using group_by and summarize this type, etc.
  • two numerical and one categorical: a. year, indicator, and country; b. two indicators and region, etc.

If you use WIR, the following may be examples you saw in the executive summary:

  • two categorical and one numerical: F1, F2, F4, F13 (year in this case is categorical), F15

  • two numerical and one categorical: F6, F7, F10

  • Three categorical: F3

  • Two categorical and two numerical: F8, F11

2.3 Visualization

Data visualization is a key to EDA. Create various charts and write your observations you can or cannot obtain from the chart.

The following are the first two fundamental questions you keep in mind.

  • What type of variation occurs within my variables?
  • What type of covariation occurs between my variables?

3 Your Work

Here is a list of data your classmates used for Assignment Four.

3.1 World Inequality Report 2022 - WIR

  • WIR2022TablesFigures-Summary.xlsx: Data of Exective Summary
  • WIR2022TablesFigures-Chapter6.xlsx: Historical and current emissions, Income and Population by world region

3.2 World Development Indicators - WDI

  • SP.DYN.TFRT.IN: Fertility rate, total (births per woman)
  • SP.POP.GROW: Population growth (annual %)
  • NY.GDP.MKTP.CD: GDP (current US$)
  • NY.GDP.MKTP.KD.ZG: GDP growth (annual %)
  • BX.KLT.DINV.CD.WD: Foreign Direct Investment (FDI) inflows
  • BX.KLT.DINV.CD.WD: Foreign direct investment, net inflows (BoP, current US$)
  • BN.CAB.XOKA.CD: Current account balance (BoP, current US$)
  • NE.EXP.GNFS.KD: Exports of goods and services (constant 2015 US$)
  • NE.IMP.GNFS.KD: Imports of goods and services (constant 2015 US$)
  • BX.TRF.PWKR.CD.DT: Personal remittances, received (current US$)
  • NY.GNS.ICTR.ZS: Gross savings (% of GDP)
  • EN.ATM.CO2E.KT: CO2 emissions (kt)
  • SE.XPD.TOTL.GB.ZS: Government expenditure on education, total (% of government expenditure)
  • SE.ENR.PRSC.FM.ZS: School enrollment, primary and secondary (gross), gender parity index (GPI)
  • SE.PRM.UNER.FE: Children out of school, primary, female
  • SE.PRM.UNER.MA: Children out of school, primary, male

4 Responses to Questions

4.1 Q. WIR2022, F8 with a fixed year, say 2020 describing the difference of goevernment and private income.

As for WIR2022, please refer to: https://ds-sl.github.io/data-analysis/wir2022.nb.html

I added explanations to each chart.

  • Step 1. Import the data

There is a step-by-step explanation of how to recreate a chart.

df_f8 <- read_excel("./data/WIR2022s.xlsx", sheet = "data-F8")
df_f8
  • Step 2. Tidy up the data by pivot_longer.
df_f8_rev <- df_f8 %>% filter(year == "2020") %>%
  select(year, Germany_public = Germany, Germany_private = 'Germany (private)', 
         Spain_public = Spain, Spain_private = 'Spain (private)', 
         France_public = France, France_private = 'France (private)', 
         UK_public  = UK, UK_private = 'UK (private)', 
         Japan_public = Japan, Japan_private = 'Japan (private)', 
         Norway_public = Norway, Norway_private = 'Norway (private)',
         USA_public = USA, USA_private = 'USA (private)') %>%
  pivot_longer(!year, names_to = c("country",".value"), names_sep = "_") %>%
  pivot_longer(3:4, names_to = "type", values_to = "value")
df_f8_rev
  • Step 3. Visualize using ggplot2.

Then, in this case, geom_col seems to fit.

df_f8_rev %>%
  ggplot() +
  geom_col(aes(x = country, y = value, fill = type), position = "dodge") +
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  labs(title = "Private versus public wealth in rich countries in 2020", 
       x = "", y = "wealth as % of national income", color = "", type = "")

Can you find a similar data of other countries of this type?

It is in Chapter 3 of the report:

https://wir2022.wid.world/chapter-3/

From methodology, I explained on January 25, you can download the data for chapter three: WIR2022TablesFigures-Chapter3.xlsx

4.2 Q. The line graph looked strange at first and I couldn’t really see the results clearly. However, I could solve that problem by using “smoothstat” and then the results looked way better and I was able to interpret them easily.

The strange looking line graph is called a sawtooth shape, and happens very often. So let me explain it

  • WDI indicator: BX.KLT.DINV.CD.WD: Foreign Direct Investment (FDI) inflows

  • Step 1. Import the data.

df_fdi <- WDI(country = "all", indicator = c(fdi = "BX.KLT.DINV.CD.WD"), start =1970 , extra = TRUE, cache = NULL)
df_fdi
  • Step 2. Check the list of income names.

The following code in Base R does the same as the following using tidyverse: df_fdi %>% distinct(income) %>% pull(). If the list is long, it may be better to check using tibble by `df_fdi %>% distinct(income). You can also use DT::datatable(df_fdi) and search items of interest, though it takes up a lot of memory.

unique(df_fdi$income)
[1] "Low income"          "Aggregates"          "Upper middle income"
[4] "Lower middle income" "High income"         NA                   
[7] "Not classified"     
  • Step 3. Try a line graph.
df_dfi %>% ggplot(aes(x=year, y=fdi, color=income)) + geom_line()

We observe several problems. But the most significant issue is it looks like a sawtooth. It is because there are so many y values at the same x value. When you draw a line graph, you need to choose only several countries or use group_by and summarize and use summarized data. However, there is an option; we can use a model to summarize the data of each group using geom_smooth(). Since you do not want a line but a curve, we use “loess” with span, we used to draw some of WIR2022 charts.

  • Step 4. Let us try group_by and summarize.
df_fdi %>% drop_na(fdi) %>% drop_na(income) %>% 
  filter(!income %in% c("Aggregates","Not classified")) %>%
  group_by(income, year) %>% summarize(fdi_mean = mean(fdi)) %>% 
  ggplot(aes(x=year,y=fdi_mean,color=income)) + 
  geom_line()
`summarise()` has grouped output by 'income'. You can override using the `.groups` argument.

If you do not want the message ‘summarise() has grouped output by ’income’. You can override using the .groups argument.’ try the following by adding .group = drop.

df_fdi %>% drop_na(fdi) %>% drop_na(income) %>% 
  filter(!income %in% c("Aggregates","Not classified")) %>%
  group_by(income, year) %>% summarize(fdi_mean = mean(fdi), .groups = "drop") %>% 
  ggplot(aes(x=year,y=fdi_mean,color=income)) + 
  geom_line()

  • Step 5. Let us try geom_smooth with loess and span.

Do you see similarities and differences? We need to choose the one from the other by our objective, and explain

df_fdi  %>% drop_na(fdi) %>% drop_na(income) %>% 
  filter(!income %in% c("Aggregates","Not classified")) %>%
  ggplot(aes(x=year,y=fdi,color=income)) + 
  geom_smooth(formula = y~x, method = "loess", span = 0.25, se = FALSE)

  • Step 6. Change of the scale.

It may be a good choice to use scale_y_log10(). However, since log10 is not finite if the value is not positive, you need to choose those with the indicator positive. Let us see how many zero values are in each income level.

df_fdi %>% filter(!income %in% c(NA, "Aggregates")) %>% filter(fdi <= 0) %>%
  ggplot(aes(x = income, fill = income)) + geom_bar() + 
  labs(title = "Number of countries with FDI is not positive") +
  theme(legend.position = "none")

df_fdi %>% drop_na(income) %>% filter(fdi > 0) %>%
  filter(!income %in% c("Aggregates","Not classified")) %>%
  ggplot(aes(x=year,y=fdi,color=income)) + 
  geom_smooth(formula = y~x, method = "loess", span = 0.25, se = FALSE) +
  scale_y_log10() + labs(title="The Value FID < 0 or Zero Excluded")

Note. If this is the target chart, it may be better to check the number of NA values, 0 values, negative values, and nonzero values in each income group. I add mutate(value = factor(value, levels = c("Positive", "Zero", "Negative", "NA"), labels = c("Positive", "Zero", "Negative", "NA"))) in order to set the order of the labels. Please try the same without the line.

df_fdi %>% select(country, year, fdi, income) %>%
  filter(!income %in% c("Aggregates", NA)) %>% 
  mutate(value = case_when(
    fdi == NA ~ "NA",
    fdi == 0  ~ "Zero",
    fdi < 0  ~ "Negative",
    fdi > 0 ~ "Positive")) %>%
  mutate(value = factor(value, levels = c("Positive", "Zero", "Negative", "NA"), labels = c("Positive", "Zero", "Negative", "NA"))) %>%
  group_by(income, value) %>% summarize(n = n(), .groups = "drop") %>% 
  ggplot(aes(income, n, fill = value)) + geom_col(position="dodge") + 
  labs(x = "")

4.3 Q. How is it possible to organize better the name of the value in the x axis so that they are better readable?

  • In the example above, the labels are overlapping. One way is to give an angle to the text with vjust and hjust values to place the labels in appropriate places: theme(axis.text.x = element_text(angle = 30, vjust = 1, hjust=1))
df_fdi %>% select(country, year, fdi, income) %>%
  filter(!income %in% c("Aggregates", NA)) %>% 
  mutate(value = case_when(
    fdi == NA ~ "NA",
    fdi == 0  ~ "Zero",
    fdi < 0  ~ "Negative",
    fdi > 0 ~ "Positive")) %>%
  mutate(value = factor(value, levels = c("Positive", "Zero", "Negative", "NA"), labels = c("Positive", "Zero", "Negative", "NA"))) %>%
  group_by(income, value) %>% summarize(n = n(), .groups = "drop") %>% 
  ggplot(aes(income, n, fill = value)) + geom_col(position="dodge") + 
  theme(axis.text.x = element_text(angle = 30, vjust = 1, hjust=1)) + 
  labs(x = "")

  • You can use another package stringr included in tidyverse but not loaded. scale_x_discrete(labels = function(x) stringr::str_wrap(x, width = 15)) Change the width value to fit to your chart. If you add library(stringr), then scale_x_discrete(labels = function(x) str_wrap(x, width = 15)) is enough.
df_fdi %>% select(country, year, fdi, income) %>%
  filter(!income %in% c("Aggregates", NA)) %>% 
  mutate(value = case_when(
    fdi == NA ~ "NA",
    fdi == 0  ~ "Zero",
    fdi < 0  ~ "Negative",
    fdi > 0 ~ "Positive")) %>%
  mutate(value = factor(value, levels = c("Positive", "Zero", "Negative", "NA"), labels = c("Positive", "Zero", "Negative", "NA"))) %>%
  group_by(income, value) %>% summarize(n = n(), .groups = "drop") %>% 
  ggplot(aes(income, n, fill = value)) + geom_col(position="dodge") + 
  scale_x_discrete(labels = function(x) stringr::str_wrap(x, width = 15)) + 
  labs(x = "")

  • If you have a long name for the title, use \n for the line feed.
df_fdi %>% select(country, year, fdi, income) %>%
  filter(!income %in% c("Aggregates", NA)) %>% 
  mutate(value = case_when(
    fdi == NA ~ "NA",
    fdi == 0  ~ "Zero",
    fdi < 0  ~ "Negative",
    fdi > 0 ~ "Positive")) %>%
  mutate(value = factor(value, levels = c("Positive", "Zero", "Negative", "NA"), labels = c("Positive", "Zero", "Negative", "NA"))) %>%
  group_by(income, value) %>% summarize(n = n(), .groups = "drop") %>% 
  ggplot(aes(income, n, fill = value)) + geom_col(position="dodge") + 
  scale_x_discrete(labels = function(x) stringr::str_wrap(x, width = 15)) + 
  labs(title = "long long long long long long long \nlong long long title", x = "")

4.4 Q. Position of the labels

color_list <- c("#00AE9D","#F58220","#6C676E")
  • Import the data and tidy up
df_f1 <- read_excel("./data/WIR2022s.xlsx", sheet = "data-F1")
New names:
df_f1_rev <- pivot_longer(df_f1, -1, names_to = "group", values_to = "value")
df_f1_rev
  • Step 3. Visualize the data using geom_col(), change the default fill color using the list of the color in Step 1, and change the scale of the y axis into percents.
df_f1_rev[df_f1_rev$group != "Top 1%",] %>%
  ggplot(aes(x = ...1, y = value, fill = group)) + 
  geom_col(position = "dodge", width = 0.8) + 
  scale_fill_manual(values = color_list) + 
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  labs(x = "")

  • Step 4. Add the values in the text. Do not forget that the values should be in percentages.
df_f1_rev[df_f1_rev$group != "Top 1%",] %>%
  ggplot(aes(x = ...1, y = value, fill = group)) + 
  geom_col(position = "dodge", width = 0.8) + 
  scale_fill_manual(values = color_list) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  labs(x="") +
  geom_text(aes(x = ...1, y = value, group = group, 
            label = scales::label_percent(accuracy=1)(value)), 
            position = position_dodge(0.8))  

  • Step 5. If you want to change the locations of texts use vjust = -0.2.
df_f1_rev[df_f1_rev$group != "Top 1%",] %>%
  ggplot(aes(x = ...1, y = value, fill = group)) + 
  geom_col(position = "dodge", width = 0.8) + 
  scale_fill_manual(values = color_list) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  labs(x="") +
  geom_text(aes(x = ...1, y = value, group = group, 
            label = scales::label_percent(accuracy=1)(value)), vjust = -0.2,
            position = position_dodge(0.8))  

  • One student used another method to add 0.03 to the value of y by y = value+0.03. Great!
df_f1_rev[df_f1_rev$group != "Top 1%",] %>%
  ggplot(aes(x = ...1, y = value, fill = group)) + 
  geom_col(position = "dodge", width = 0.8) + 
  scale_fill_manual(values = color_list) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  labs(x="") +
  geom_text(aes(x = ...1, y = value+0.03, group = group, 
            label = scales::label_percent(accuracy=1)(value)), 
            position = position_dodge(0.8))  

5 My Comments after Review

5.1 Visualization by Charts

Please try as various charts as possible. You can learn only by experience or from others.

5.1.1 Treat year as a group?

df_wdi <- WDI(
  country = "all", 
  indicator = c(lifeExp = "SP.DYN.LE00.IN"), start = 1990, extra = TRUE, cache =  wdi_cache)
df_wdi
  • Something is wrong in the next chart. Can you tell what the problem is?
df_wdi %>%
  filter(year %in% c("1988", "1998", "2008", "2018")) %>%
  filter(country %in% c("Afghanistan", "Israel", "Azerbaijan", "Austria", "Australia")) %>%
  ggplot(aes(x=year)) +
  geom_boxplot(aes(y=lifeExp, fill=country))

I erased the second line: filter(year %in% c("1988", "1998", "2008", "2018")) but the result is very similar.

df_wdi %>%
  filter(country %in% c("Afghanistan", "Israel", "Azerbaijan", "Austria", "Australia")) %>%
  ggplot(aes(x=year)) +
  geom_boxplot(aes(y=lifeExp, fill=country))

If you look at the table, you can see that year is a integer vector, not a character vector. Then what happens if we remove quotation marks. The next chart is not a box plot anymore. It is because, for each year there is only one value for each country.

df_wdi %>%
  filter(year %in% c(1988, 1998, 2008, 2018)) %>%
  filter(country %in% c("Afghanistan", "Israel", "Azerbaijan", "Austria", "Australia")) %>%
  ggplot(aes(x=factor(year))) +
  geom_boxplot(aes(y=lifeExp, fill=country))

If we want to take year as a group after selecting some years, then we should try the next using factor(year). You can change the label of x axis by labs(x = "year") easily. We should also notice that there are no values for 1988. We should check basic information as such first.

df_wdi %>%
  filter(year %in% c(1988, 1998, 2008, 2018)) %>%
  filter(country %in% c("Afghanistan", "Israel", "Azerbaijan", "Austria", "Australia")) %>%
  ggplot(aes(x=factor(year), y=lifeExp, fill=country)) +
  geom_col(position = "dodge", col = "black")

It is possible if you change year to a character vector by mutate(year = as.character(year)).

df_wdi %>% mutate(year = as.character(year)) %>% 
  filter(year %in% c("1998", "2008", "2018")) %>%
  filter(country %in% c("Afghanistan", "Israel", "Azerbaijan", "Austria", "Australia")) %>%
  ggplot(aes(x=year, y=lifeExp, fill=country)) +
  geom_col(position = "dodge", col = "black") +
  labs(x = "year")

5.2 UN Data

Data of World Development Indicators are in a uniform format and downloadable using an R package WDI. So it is easy to handle. However, other data require data transformation to make it tidy. We give a couple of examples. Most of the UN data, they are in CSV, and you can get a link quickly, or download it by clicking. Though the data structure is not uniform, it is relatively easy to handle.

5.2.1 Education

By the following, you can see that the first row is not the column name. R gives column names such as …1, …2, etc., when the column name is void.

You can copy the link (url) by right click or ctrl+click.

url_un_edu <- "https://data.un.org/_Docs/SYB/CSV/SYB65_309_202209_Education.csv"
un_edu <- read_csv(url_un_edu)
New names:Rows: 7283 Columns: 7── Column specification ─────────────────────────────────────────────────────
Delimiter: ","
chr (7): T08, Enrolment in primary, secondary and tertiary education leve...
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
un_edu

Let is skip the first row by adding 1skip = 11.

un_edu <- read_csv(url_un_edu, skip = 1)
New names:Rows: 7282 Columns: 7── Column specification ─────────────────────────────────────────────────────
Delimiter: ","
chr (4): ...2, Series, Footnotes, Source
dbl (2): Region/Country/Area, Year
num (1): Value
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
un_edu

It is a very large data, and we need to check the values.

summary(un_edu)
 Region/Country/Area     ...2                Year         Series         
 Min.   :  1.0       Length:7282        Min.   :2000   Length:7282       
 1st Qu.:178.0       Class :character   1st Qu.:2005   Class :character  
 Median :417.0       Mode  :character   Median :2010   Mode  :character  
 Mean   :408.8                          Mean   :2012                     
 3rd Qu.:626.0                          3rd Qu.:2015                     
 Max.   :894.0                          Max.   :2021                     
     Value           Footnotes            Source         
 Min.   :     0.0   Length:7282        Length:7282       
 1st Qu.:    71.6   Class :character   Class :character  
 Median :   100.2   Mode  :character   Mode  :character  
 Mean   :  2534.7                                        
 3rd Qu.:   133.6                                        
 Max.   :750125.0                                        

We can see that the Year is from 2000 to 2021. The first variable, Region/Country/Area and the fifth variable, Value are dbl, i.e., double; hence, these are numerical variables, and you can see them from the summary as well. But it is not easy to see other variables. Let us try them one by one.

un_edu %>% distinct(...2)
un_edu %>% distinct(Series)
un_edu %>% distinct(Footnotes)
un_edu %>% distinct(Source)
  • We may need to handle Footnotes carefully later, but for the first exploration, we need, …2 for Region, Year, Series, Values.
df_un_edu <- un_edu %>%
  select(Region = ...2, Year, Series, Value)
df_un_edu

Is there a way to separate regions from countries?

df_un_edu %>% left_join(wdi_cache$country, by = c("Region"="country")) %>%
  filter(!is.na(iso2c)) %>% distinct(Region)
df_un_edu %>% left_join(wdi_cache$country, by = c("Region"="country")) %>%
  filter(is.na(iso2c)) %>% distinct(Region)
df_un_edu %>% left_join(wdi_cache$country, by = c("Region"="country")) %>%
  filter(is.na(iso2c)) %>% distinct(Region) %>% pull()
 [1] "Total, all countries or areas" "Northern Africa"              
 [3] "Sub-Saharan Africa"            "Northern America"             
 [5] "Latin America & the Caribbean" "Central Asia"                 
 [7] "Eastern Asia"                  "South-eastern Asia"           
 [9] "Southern Asia"                 "Western Asia"                 
[11] "Europe"                        "Oceania"                      
[13] "Anguilla"                      "Bahamas"                      
[15] "Bolivia (Plurin. State of)"    "China, Hong Kong SAR"         
[17] "China, Macao SAR"              "Congo"                        
[19] "Cook Islands"                  "Côte d’Ivoire"                
[21] "Curaçao"                       "Dem. People's Rep. Korea"     
[23] "Dem. Rep. of the Congo"        "Egypt"                        
[25] "Gambia"                        "Holy See"                     
[27] "Iran (Islamic Republic of)"    "Kyrgyzstan"                   
[29] "Lao People's Dem. Rep."        "Micronesia (Fed. States of)"  
[31] "Montserrat"                    "Netherlands Antilles [former]"
[33] "Niue"                          "Republic of Korea"            
[35] "Republic of Moldova"           "Saint Kitts and Nevis"        
[37] "Saint Lucia"                   "Saint Vincent & Grenadines"   
[39] "Slovakia"                      "State of Palestine"           
[41] "Sudan [former]"                "Tokelau"                      
[43] "Türkiye"                       "United Rep. of Tanzania"      
[45] "United States of America"      "Venezuela (Boliv. Rep. of)"   
[47] "Viet Nam"                      "Yemen"                        

There are some countries iso2c is not properly assigned. From the list above, Probably, the first 12 are areas and the value contains the aggregated value.

area <- df_un_edu %>% distinct(Region) %>% slice(1:12) %>% pull()
area
 [1] "Total, all countries or areas" "Northern Africa"              
 [3] "Sub-Saharan Africa"            "Northern America"             
 [5] "Latin America & the Caribbean" "Central Asia"                 
 [7] "Eastern Asia"                  "South-eastern Asia"           
 [9] "Southern Asia"                 "Western Asia"                 
[11] "Europe"                        "Oceania"                      
un_edu_area <- df_un_edu %>% filter(Region %in% area)
un_edu_region <- df_un_edu %>% filter(!Region %in% area)

Now we can start studying the data.

un_edu_area %>% 
  filter(Series %in% c("Gross enrollment ratio - Upper secondary level (male)", "Gross enrollment ratio - Upper secondary level (female)")) %>%
  ggplot(aes(Year, Value, color = Region, linetype = Series)) + geom_line()

un_edu_area %>% 
  filter(Series %in% c("Gross enrollment ratio - Upper secondary level (male)", "Gross enrollment ratio - Upper secondary level (female)")) %>% 
  pivot_wider(names_from = Series, values_from = Value) %>%
  mutate (Ratio = `Gross enrollment ratio - Upper secondary level (female)`/`Gross enrollment ratio - Upper secondary level (male)`) %>%
  ggplot(aes(Year, Ratio, color = Region, linetype = Region)) + geom_line() +
  labs(title = "Upper Secondary Level Education", subtitle = "Ratio = female/male")

5.2.2 Population

Data structure is similar to the previous one. So use skip=1, and check the variable s briefly.

url_un_pop = "https://data.un.org/_Docs/SYB/CSV/SYB65_246_202209_Population%20Growth,%20Fertility%20and%20Mortality%20Indicators.csv"
df_un_pop <- read.csv(url_un_pop, skip = 1)
df_un_pop
df_un_pop %>% distinct(Source)
df_un_pop %>% distinct(Footnotes)
df_un_pop %>% distinct(X)
df_un_pop %>% distinct(Series)
  1. Footnotes need to be studied.
  2. There are four different sources.
  3. X is for the region, the first 30 are areas, and the rest are countries or regions.
  4. There are seven series. It may be easier if we assign shorter names for each value.
pop_area <- df_un_pop %>% distinct(X) %>% slice(1:30) %>% pull()
pop_area
 [1] "Total, all countries or areas" "Africa"                       
 [3] "Northern Africa"               "Sub-Saharan Africa"           
 [5] "Eastern Africa"                "Middle Africa"                
 [7] "Southern Africa"               "Western Africa"               
 [9] "Northern America"              "Latin America & the Caribbean"
[11] "Caribbean"                     "Central America"              
[13] "South America"                 "Asia"                         
[15] "Central Asia"                  "Eastern Asia"                 
[17] "South-central Asia"            "South-eastern Asia"           
[19] "Southern Asia"                 "Western Asia"                 
[21] "Europe"                        "Eastern Europe"               
[23] "Northern Europe"               "Southern Europe"              
[25] "Western Europe"                "Oceania"                      
[27] "Australia and New Zealand"     "Melanesia"                    
[29] "Micronesia"                    "Polynesia"                    
un_pop <- df_un_pop %>% select(Region = X, Year, Series, Value)
un_pop

Let us change the names of series.

un_pop_wide <- un_pop %>% pivot_wider(names_from = Series, values_from = Value)
colnames(un_pop_wide) <- c("Region", "Year", "IncRate", "Fert", "InfDeath", "MatDeath", "LifeExp", "LifeExpM", "LifeExpF")
un_pop_wide
un_pop_long <- un_pop_wide %>% pivot_longer(cols = -c(1,2), names_to = "Series", values_to = "Value")
un_pop_long                                           
un_pop_long_area <- un_pop_long %>% filter(Region %in% pop_area)
un_pop_long_region <- un_pop_long %>% filter(!Region %in% pop_area)
un_pop_wide_area <- un_pop_wide %>% filter(Region %in% pop_area)
un_pop_wide_region <- un_pop_wide %>% filter(!Region %in% pop_area)

Now we can visualize data.

5.3 WIR

In the following, we explain how to download data by an R package wir. First, you need to install the package. However, it is not an official R package yet; you need to use the package devtools to install it.

install.packages("devtools")
devtools::install_github("WIDworld/wid-r-tool")

I have not studied fully, but you can download the data by a package called wir. See here. After installing the package, check the codebook of the indicators. The following is not the ratio given in F8, but an example.

  • w wealth-to-income ratio or labor/capital share fraction of national income
  • wealg: net public wealth to net national income ratio
  • wealp: net private wealth to net national income ratio
library(wid)
wwealg <- download_wid(indicators = "wwealg", areas = "all", years = "all")
wwealp <- download_wid(indicators = "wwealp", areas = "all", years = "all")
public <- wwealg %>% select(country, year, public = value)
public
private <- wwealp %>% select(country, year, private = value)
private
public_vs_private <- public %>% left_join(private)
Joining, by = c("country", "year")
public_vs_private
df_pub_priv <- public_vs_private %>% pivot_longer(cols = c(3,4), names_to = "category", values_to = "value") %>% left_join(wdi_cache$country, by = c("country"="iso2c")) %>%
  select(country = country.y, iso2c = country, year, category, value, region, income, lending)
df_pub_priv
unique(df_pub_priv$country)
  [1] "Andorra"                                     
  [2] "United Arab Emirates"                        
  [3] "Afghanistan"                                 
  [4] "Antigua and Barbuda"                         
  [5] NA                                            
  [6] "Albania"                                     
  [7] "Armenia"                                     
  [8] "Angola"                                      
  [9] "Argentina"                                   
 [10] "American Samoa"                              
 [11] "Austria"                                     
 [12] "Australia"                                   
 [13] "Aruba"                                       
 [14] "Azerbaijan"                                  
 [15] "Bosnia and Herzegovina"                      
 [16] "Barbados"                                    
 [17] "Bangladesh"                                  
 [18] "Belgium"                                     
 [19] "Burkina Faso"                                
 [20] "Bulgaria"                                    
 [21] "Bahrain"                                     
 [22] "Burundi"                                     
 [23] "Benin"                                       
 [24] "Bermuda"                                     
 [25] "Brunei Darussalam"                           
 [26] "Bolivia"                                     
 [27] "Brazil"                                      
 [28] "Bahamas, The"                                
 [29] "Bhutan"                                      
 [30] "Botswana"                                    
 [31] "Belize"                                      
 [32] "Canada"                                      
 [33] "Congo, Dem. Rep."                            
 [34] "Central African Republic"                    
 [35] "Congo, Rep."                                 
 [36] "Switzerland"                                 
 [37] "Cote d'Ivoire"                               
 [38] "Chile"                                       
 [39] "Cameroon"                                    
 [40] "China"                                       
 [41] "Colombia"                                    
 [42] "Costa Rica"                                  
 [43] "Cuba"                                        
 [44] "Cabo Verde"                                  
 [45] "Curacao"                                     
 [46] "Cyprus"                                      
 [47] "Czechia"                                     
 [48] "Germany"                                     
 [49] "Djibouti"                                    
 [50] "Denmark"                                     
 [51] "Dominica"                                    
 [52] "Dominican Republic"                          
 [53] "Algeria"                                     
 [54] "Ecuador"                                     
 [55] "Estonia"                                     
 [56] "Egypt, Arab Rep."                            
 [57] "Eritrea"                                     
 [58] "Spain"                                       
 [59] "Ethiopia"                                    
 [60] "Finland"                                     
 [61] "Fiji"                                        
 [62] "Micronesia, Fed. Sts."                       
 [63] "France"                                      
 [64] "Gabon"                                       
 [65] "United Kingdom"                              
 [66] "Grenada"                                     
 [67] "Georgia"                                     
 [68] "Ghana"                                       
 [69] "Greenland"                                   
 [70] "Gambia, The"                                 
 [71] "Guinea"                                      
 [72] "Equatorial Guinea"                           
 [73] "Greece"                                      
 [74] "Guatemala"                                   
 [75] "Guam"                                        
 [76] "Guinea-Bissau"                               
 [77] "Guyana"                                      
 [78] "Hong Kong SAR, China"                        
 [79] "Honduras"                                    
 [80] "Croatia"                                     
 [81] "Haiti"                                       
 [82] "Hungary"                                     
 [83] "Indonesia"                                   
 [84] "Ireland"                                     
 [85] "Israel"                                      
 [86] "Isle of Man"                                 
 [87] "India"                                       
 [88] "Iraq"                                        
 [89] "Iran, Islamic Rep."                          
 [90] "Iceland"                                     
 [91] "Italy"                                       
 [92] "Jamaica"                                     
 [93] "Jordan"                                      
 [94] "Japan"                                       
 [95] "Kenya"                                       
 [96] "Kyrgyz Republic"                             
 [97] "Cambodia"                                    
 [98] "Kiribati"                                    
 [99] "Comoros"                                     
[100] "St. Kitts and Nevis"                         
[101] "Korea, Dem. People's Rep."                   
[102] "Korea, Rep."                                 
[103] "Kuwait"                                      
[104] "Cayman Islands"                              
[105] "Kazakhstan"                                  
[106] "Lao PDR"                                     
[107] "Lebanon"                                     
[108] "St. Lucia"                                   
[109] "Liechtenstein"                               
[110] "Sri Lanka"                                   
[111] "Liberia"                                     
[112] "Lesotho"                                     
[113] "Lithuania"                                   
[114] "Luxembourg"                                  
[115] "Latvia"                                      
[116] "Libya"                                       
[117] "Morocco"                                     
[118] "Monaco"                                      
[119] "Moldova"                                     
[120] "Montenegro"                                  
[121] "Madagascar"                                  
[122] "Marshall Islands"                            
[123] "North Macedonia"                             
[124] "Mali"                                        
[125] "Myanmar"                                     
[126] "Mongolia"                                    
[127] "Macao SAR, China"                            
[128] "Northern Mariana Islands"                    
[129] "Mauritania"                                  
[130] "Malta"                                       
[131] "Mauritius"                                   
[132] "Maldives"                                    
[133] "Malawi"                                      
[134] "Mexico"                                      
[135] "Malaysia"                                    
[136] "Mozambique"                                  
[137] "Namibia"                                     
[138] "New Caledonia"                               
[139] "Niger"                                       
[140] "Nigeria"                                     
[141] "Nicaragua"                                   
[142] "Netherlands"                                 
[143] "Norway"                                      
[144] "Nepal"                                       
[145] "Nauru"                                       
[146] "New Zealand"                                 
[147] "OECD members"                                
[148] "Oman"                                        
[149] "Panama"                                      
[150] "Peru"                                        
[151] "French Polynesia"                            
[152] "Papua New Guinea"                            
[153] "Philippines"                                 
[154] "Pakistan"                                    
[155] "Poland"                                      
[156] "Puerto Rico"                                 
[157] "West Bank and Gaza"                          
[158] "Portugal"                                    
[159] "Palau"                                       
[160] "Paraguay"                                    
[161] "Qatar"                                       
[162] "Romania"                                     
[163] "Serbia"                                      
[164] "Russian Federation"                          
[165] "Rwanda"                                      
[166] "Saudi Arabia"                                
[167] "Solomon Islands"                             
[168] "Seychelles"                                  
[169] "Sudan"                                       
[170] "Sweden"                                      
[171] "Singapore"                                   
[172] "Slovenia"                                    
[173] "Slovak Republic"                             
[174] "Sierra Leone"                                
[175] "San Marino"                                  
[176] "Senegal"                                     
[177] "Somalia"                                     
[178] "Suriname"                                    
[179] "South Sudan"                                 
[180] "Sao Tome and Principe"                       
[181] "El Salvador"                                 
[182] "Sint Maarten (Dutch part)"                   
[183] "Syrian Arab Republic"                        
[184] "Eswatini"                                    
[185] "Turks and Caicos Islands"                    
[186] "Chad"                                        
[187] "Togo"                                        
[188] "Thailand"                                    
[189] "Tajikistan"                                  
[190] "Timor-Leste"                                 
[191] "Turkmenistan"                                
[192] "Tunisia"                                     
[193] "Tonga"                                       
[194] "Turkiye"                                     
[195] "Trinidad and Tobago"                         
[196] "Tuvalu"                                      
[197] "Taiwan, China"                               
[198] "Tanzania"                                    
[199] "Ukraine"                                     
[200] "Uganda"                                      
[201] "United States"                               
[202] "Uruguay"                                     
[203] "Uzbekistan"                                  
[204] "St. Vincent and the Grenadines"              
[205] "Venezuela, RB"                               
[206] "British Virgin Islands"                      
[207] "Virgin Islands (U.S.)"                       
[208] "Vietnam"                                     
[209] "Vanuatu"                                     
[210] "Samoa"                                       
[211] "IBRD only"                                   
[212] "IDA only"                                    
[213] "Least developed countries: UN classification"
[214] "Low income"                                  
[215] "Lower middle income"                         
[216] "Yemen, Rep."                                 
[217] "South Africa"                                
[218] "Zambia"                                      
[219] "Zimbabwe"                                    
df_pub_priv %>% 
  filter(country %in% c("Japan", "Norway", "Sweden", "Denmark", "Finland"), year %in% 1970:2020) %>%
  ggplot(aes(year, value, color = country, linetype = category)) + geom_line()

We choose two indicators: ‘wealg’ and ‘wealp’. WIR2022 indicators consists of 6 characters; 1 letter code plus 5 letter code. You can find the list in the codebook.

If you want to study WIR2022, please study the report, the codebook, and wir vignette together with the R Notebook.

As I mentioned earlier, the data tables used in the report are available from the following page.

LS0tCnRpdGxlOiAiUmVzcG9uc2VzIHRvIEFzc2lnbm1lbnQgNCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIGhpZ2hsaWdodDogaGFkZG9jawogICAgdGhlbWU6IGNvc21vCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogeWVzCi0tLQoKIyMgQXNzaWdubWVudCBGb3VyOiBUaGUgV2VlayBGaXZlIEFzc2lnbm1lbnQgey51bm51bWJlcmVkfQoKKipgdGlkeXJgIGFuZCBXSVIyMDIyKioKCi0gICBDcmVhdGUgYW4gUiBOb3RlYm9vayBvZiBhIERhdGEgQW5hbHlzaXMgY29udGFpbmluZyB0aGUgZm9sbG93aW5nIGFuZCBzdWJtaXQgdGhlIHJlbmRlcmVkIEhUTUwgZmlsZSAoZS5nLiwgYGEzXzEyMzQ1Ni5uYi5odG1sYCBieSByZXBsYWNpbmcgMTIzNDU2IHdpdGggeW91ciBJRCkKICAgIDEuICBjcmVhdGUgYW4gUiBOb3RlYm9vayB1c2luZyB0aGUgUiBOb3RlYm9vayBUZW1wbGF0ZSBpbiBNb29kbGUsIHNhdmUgaXQgYXMgYGEzXzEyMzQ1Ni5SbWRgLAogICAgMi4gIHdyaXRlIHlvdXIgbmFtZSBhbmQgSUQgYW5kIHRoZSBjb250ZW50cywKICAgIDMuICBydW4gZWFjaCBjb2RlIGJsb2NrLAogICAgNC4gIHByZXZpZXcgdG8gY3JlYXRlIGBhM18xMjM0NTYubmIuaHRtbGAsCiAgICA1LiAgc3VibWl0IGBhM18xMjM0NTYubmIuaHRtbGAgdG8gTW9vZGxlLgoKMS4gIENob29zZSBkYXRhIHdpdGggYXQgbGVhc3QgdHdvIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyBhbmQgYXQgbGVhc3QgdHdvIG51bWVyaWNhbCB2YXJpYWJsZXMuCgogICAgLSAgIEluZm9ybWF0aW9uIG9mIHRoZSBkYXRhOiBOYW1lLCBJbmRpY2F0b3IsIERlc2NyaXB0aW9uLCBTb3VyY2UsIGV0Yy4KICAgIC0gICBFeHBsYWluIHdoeSB5b3UgY2hvc2UgdGhlIGluZGljYXRvcgogICAgLSAgIExpc3QgcXVlc3Rpb25zIHlvdSB3YW50IHRvIHN0dWR5CgoyLiAgRXhwbG9yZSB0aGUgZGF0YSB1c2luZyB2aXN1YWxpemF0aW9uIHVzaW5nIGBnZ3Bsb3QyYC4KCiAgICAtICAgQ3JlYXRlIHZhcmlvdXMgY2hhcnRzCiAgICAtICAgQ3JlYXRlIGF0IGxlYXN0IG9uZSBjaGFydCB3aXRoIGF0IGxlYXN0IHR3byBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgYW5kIG9uZSBudW1lcmljYWwgdmFyaWFibGUuCiAgICAtICAgQ3JlYXRlIGF0IGxlYXN0IG9uZSBjaGFydCB3aXRoIGF0IGxlYXN0IHR3byBudW1lcmljYWwgYW5kIG9uZSBjYXRlZ29yaWNhbCB2YXJpYWJsZS4KCjMuICBPYnNlcnZhdGlvbnMgYmFzZWQgb24geW91ciBkYXRhIHZpc3VhbGl6YXRpb24gYW5kIGRpZmZpY3VsdGllcyBhbmQgcXVlc3Rpb25zIGVuY291bnRlcmVkLCBpZiBhbnkuCgoqKkR1ZToqKiAyMDIzLTAxLTIzIDIzOjU5OjAwLiBTdWJtaXQgeW91ciBSIE5vdGVib29rIGZpbGUgaW4gTW9vZGxlIChUaGUgRm91cnRoIEFzc2lnbm1lbnQpLiBEdWUgb24gTW9uZGF5IQoKIyBTZXQgdXAKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShyZWFkeGwpICMgZm9yIGV4Y2VsIGZpbGVzCmxpYnJhcnkoV0RJKQpgYGAKCiMjIFdvcmxkIERldmVsb3BtZW50IEluZGljYXRvciAtIFdESQoKVGhlIGZvbGxvd2luZyBpcyB1c2VmdWwgd2hlbiB5b3UgdXNlIFdESS4KCmBgYHtyIGNhY2hlID0gVFJVRSwgZXZhbCA9IEZBTFNFfQp3ZGlfY2FjaGUgPC0gV0RJY2FjaGUoKQpgYGAKCk9yLCB3cml0ZSB0aGUgY2FjaGUgYW5kIHJlYWQgaXQgZnJvbSB5b3VyIGNvbXB1dGVyLiBTaW5jZSBgd2RpX2NhY2hlYCBpcyBhIGxpc3Qgb2YgdHdvIGRhdGEgZnJhbWVzLCB3ZSBjYW5ub3QgdXNlIGB3cml0ZV9jc3YoKWA7IGluc3RlYWQsIHdlIHVzZSBgd3JpdGVfcmRzYC4KCmBgYHtyIGNhY2hlID0gVFJVRSwgZXZhbCA9IEZBTFNFfQp3cml0ZV9yZHMod2RpX2NhY2hlLCAiLi9kYXRhL3dkaV9jYWNoZSIpCmBgYAoKYGBge3IgY2FjaGUgPSBUUlVFfQp3ZGlfY2FjaGUgPC0gcmVhZF9yZHMoIi4vZGF0YS93ZGlfY2FjaGUiKQpgYGAKCmBXREljYWNoZSgpYCBwcm9kdWNlcyBhIGxpc3QgY29udGFpbmluZyB0d28gZGF0YSBmcmFtZXM6IGB3ZGlfY2FjaGUkc2VyaWVzYCBhbmQgYHdkaV9jYWNoZSRjb3VudHJ5YC4KCmBgYHtyfQpnbGltcHNlKHdkaV9jYWNoZSkKYGBgCgojIyBXb3JsZCBJbmVxdWlsaXR5IFJlcG9ydCAtIFdJUjIwMjIKCiogV29ybGQgSW5lcXVhbGl0eSBSZXBvcnQ6IGh0dHBzOi8vd2lyMjAyMi53aWQud29ybGQvCiogRXhlY3V0aXZlIFN1bW1hcnk6IGh0dHBzOi8vd2lyMjAyMi53aWQud29ybGQvZXhlY3V0aXZlLXN1bW1hcnkvCiogTWV0aG9kb2xvZ3k6IGh0dHBzOi8vd2lyMjAyMi53aWQud29ybGQvbWV0aG9kb2xvZ3kvCiogVVJMIG9mIEV4ZWN1dGl2ZSBTdW1tYXJ5IERhdGE6IGh0dHBzOi8vd2lyMjAyMi53aWQud29ybGQvd3d3LXNpdGUvdXBsb2Fkcy8yMDIyLzAzL1dJUjIwMjJUYWJsZXNGaWd1cmVzLVN1bW1hcnkueGxzeAoKUGxlYXNlIGFkZCBgbW9kZT0id2IiYCAod2ViIGJpbmFyeSkuIFRoaXMgc2hvdWxkIHdvcmsgYmV0dGVyLiAKCmBgYHtyIHN1bW1hcnktZGF0YSwgY2FzaCA9IFRSVUUsIGV2YWwgPSBGQUxTRX0KdXJsX3N1bW1hcnkgPC0gImh0dHBzOi8vd2lyMjAyMi53aWQud29ybGQvd3d3LXNpdGUvdXBsb2Fkcy8yMDIyLzAzL1dJUjIwMjJUYWJsZXNGaWd1cmVzLVN1bW1hcnkueGxzeCIKZG93bmxvYWQuZmlsZSh1cmwgPSB1cmxfc3VtbWFyeSwgCiAgICAgICAgICAgICAgZGVzdGZpbGUgPSAiLi9kYXRhL1dJUjIwMjJzLnhsc3giLCAKICAgICAgICAgICAgICBtb2RlID0gIndiIikgCmBgYAoKSWYgeW91IGdldCBhbiBlcnJvciwgZG93bmxvYWQgdGhlIGZpbGUgZGlyZWN0b3J5IGZyb20gdGhlIG1ldGhvZG9sb2d5IHNpdGUgaW50byB5b3VyIGNvbXB1dGVyLCB0aGVuIG9wZW4gaXQgd2l0aCBFeGNlbCBhbmQgc2F2ZSBpdCBpbiB0aGUgZGF0YSBmb2xkZXIgb2YgeW91ciBSIFN0dWRpbyBwcm9qZWN0LiBUaGVuIFIgc3R1ZGlvIGNhbiByZWNvZ25pemUgaXQgZWFzaWx5IGFzIGFuIEV4Y2VsIGRhdGEuCgpHZW5lcmFsbHksIGEgdGV4dCBmaWxlIHN1Y2ggYXMgYSBDU1YgZmlsZSBpcyBlYXN5IHRvIGltcG9ydCwgYnV0IGEgYmluYXJ5IGZpbGUgaXMgZGlmZmljdWx0IHRvIGhhbmRsZS4gSXQgaXMgYmVjYXVzZSB1bmxlc3MgUiBjYW4gcmVjb2duaXplIGl0cyBmaWxlIHR5cGUsIGZvciBleGFtcGxlLCBFeGNlbCBvciBzbywgUiBjYW5ub3QgaW1wb3J0IHRoZSBkYXRhLgoKYGBge3J9CmV4Y2VsX3NoZWV0cygiLi9kYXRhL1dJUjIwMjJzLnhsc3giKQpgYGAKCgojIEdlbmVyYWwgQ29tbWVudHMKCiMjIFJlcHJvZHVjaWJpbGl0eSBhbmQgTGl0ZXJhdGUgUHJvZ3JhbW1pbmcKClJlcHJvZHVjaWJpbGl0eSBhbmQgTGl0ZXJhdGUgUHJvZ3JhbW1pbmcgYXJlIGNyaXRpY2FsIHRvIGV4cGxvcmF0b3J5IGRhdGEgYW5hbHlzaXMgKEVEQSkuIFRoZXNlIGFyZSBmb3IgY29tbXVuaWNhdGlvbjsgY29tbXVuaWNhdGlvbiB3aXRoIHJlYWRlcnMgb2YgdGhlIHBhcGVyLCBncmFkZXJzIG9mIHRoZSBhc3NpZ25tZW50cywgYW5kIGNvbW11bmljYXRpb24gd2l0aCB5b3Vyc2VsZiwgYXMgd2UgYWx3YXlzIGZvcmdldC4gUGxlYXNlIHRoaW5rIGFib3V0IHRoZSByZWFkZXIgb2YgdGhlIGFydGljbGUsIGFuZCByZWNvcmQgdGhlIHByb2NlZHVyZSBhbmQgb3V0cHV0IHNvIHRoYXQgcmVhZGVyIGNhbiBlYXNpbHkgdW5kZXJzdGFuZCB3aGF0IHlvdSBoYXZlIGRvbmUuCgpUaGUgZGF0YSBzb3VyY2UgaXMgY3JpdGljYWwuIFVubGVzcyB0aGUgcmVhZGVyIG9idGFpbnMgdGhlIHNhbWUgZGF0YSBxdWlja2x5LCB0aGUgY29tbXVuaWNhdGlvbiBvbiBFREEgZG9lcyBub3Qgc3RhcnQuIElmIHRoZSBkYXRhIGlzIG5vdCBkb3dubG9hZGVkIGF1dG9tYXRpY2FsbHkgdGhyb3VnaCB0aGUgY29kZSBjaHVuaywgeW91IHNob3VsZCBleHBsYWluIGhvdyB0byBvYnRhaW4gdGhlIGRhdGEgYW5kIHRoZSBwYXJ0IG9mIHRoZSBkYXRhIHlvdSBhcHBsaWVkLiBJdCBpcyBjcnVjaWFsIHdoZW4geW91IHVzZSBjb3B5aW5nIGFuZCBwYXN0ZSB1c2luZyBgcmVhZF9kZWxpbShjbGlwYm9hcmQoKSlgLiBQbGVhc2UgZGVzY3JpYmUgdGhlIHdheSBmb3IgdGhlIHJlYWRlciB0byByZXRyaWV2ZSB0aGUgc2FtZSBkYXRhIGVhc2lseS4gSXQgaXMgYmVzdCB0byByZWFkIHlvdXIgcGFwZXI7IGluIHNvbWUgY2FzZXMsIGl0IGNhbiBiZSBhIGhhcmQgY29weSBmcm9tIHRoZSBiZWdpbm5pbmcgdG8gY2hlY2sgd2hldGhlciB0aGUgcmVhZGVyIGNhbiByZXByb2R1Y2Ugd2hhdCB5b3UgaGF2ZSBkb25lIGluIHRoZSBhcnRpY2xlLgoKIyMgVmFyaWJsZXMKCkluIHRoaXMgQXNzaWdubWVudCBGb3VyLCB3ZSByZXF1aXJlZCB0aGUgZm9sbG93aW5nOgoKLSAgIENyZWF0ZSBhdCBsZWFzdCBvbmUgY2hhcnQgd2l0aCBhdCBsZWFzdCB0d28gY2F0ZWdvcmljYWwgdmFyaWFibGVzIGFuZCBvbmUgbnVtZXJpY2FsIHZhcmlhYmxlLgotICAgQ3JlYXRlIGF0IGxlYXN0IG9uZSBjaGFydCB3aXRoIGF0IGxlYXN0IHR3byBudW1lcmljYWwgYW5kIG9uZSBjYXRlZ29yaWNhbCB2YXJpYWJsZS4KCllvdSBjYW4gY3JlYXRlIGEgc2ltcGxlIGNoYXJ0LCBzdWNoIGFzIGEgaGlzdG9ncmFtIG9yIGEgYm94IHBsb3Qgd2l0aCBvbmx5IG9uZSB2YXJpYWJsZS4gSWYgeW91IGhhdmUgdHdvIHZhcmlhYmxlcywgeW91IGNhbiBjcmVhdGUgYSBzY2F0dGVyIHBsb3QuIEJ1dCB3aXRoIGBnZ3Bsb3QyYCwgeW91IGNhbiBjcmVhdGUgdmFyaW91cyBjaGFydHMgd2l0aCByaWNoIGluZm9ybWF0aW9uIHVzaW5nIG1vcmUgdGhhbiB0d28gdmFyaWFibGVzLiBGb3IgZXhhbXBsZSwgdGhlIHllYXIgY2FuIGJlIHVzZWQgZm9yIGJvdGggbnVtZXJpY2FsIGFuZCBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgdXNpbmcgYGZhY3Rvcih5ZWFyKWAgb3IgcmVjb2duaXplZCBhcyBhIGNoYXJhY3RlciB2ZWN0b3IgYnkgYGFzLmNoYXJhY3Rlcih5ZWFyKWAuIFNvIHRoZSBkaXN0aW5jdGlvbiBiZXR3ZWVuIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyBhbmQgbnVtZXJpY2FsIHZhcmlhYmxlcyBpcyBmbGV4aWJsZS4gVGhlIHB1cnBvc2Ugb2YgdGhpcyBhc3NpZ25tZW50IGlzIHRvIGV4cGVyaWVuY2UgY3JlYXRpbmcgYSBjaGFydCB3aXRoIHJpY2ggaW5mb3JtYXRpb24gdXNpbmcgbW9yZSB0aGFuIHR3byB2YXJpYWJsZXMuCgpIb3dldmVyLCBJIG5lZWRlZCB0byBjbGFyaWZ5IHRoZSB2YXJpYWJsZXMnIHJlcXVpcmVtZW50cyBmb3Igc29tZSBvZiB5b3UuIFNvIEkgc2VudCBvdXQgYW4gZXh0cmEgbWVzc2FnZSBmcm9tIEFubm91bmNlbWVudCB0aGF0IHlvdSBkbyBub3QgbmVlZCB0byB0YWtlIGl0IHNvIHN0cmljdGx5LgoKSWYgeW91IHVzZSBXREksIHRoZSBmb2xsb3dpbmcgbWF5IGJlIGV4YW1wbGVzOgoKLSAgIHR3byBjYXRlZ29yaWNhbCBhbmQgb25lIG51bWVyaWNhbDogYS4gY291bnRyeSwgcmVnaW9uLCBhbmQgaW5kaWNhdG9yOyBiLiBjb3VudHJ5LCBpbmNvbWUsIGFuZCBpbmRpY2F0b3I7IGMuIGFmdGVyIHNlbGVjdGluZyBhIGNvdXBsZSBvZiB5ZWFycyBhbmQgdXNpbmcgZmFjdG9yKHllYXIpLCBjb3VudHJ5LCBpbmRpY2F0b3IsIGQuIGNyZWF0ZSBhIHRhYmxlIHVzaW5nIGdyb3VwX2J5IGFuZCBzdW1tYXJpemUgdGhpcyB0eXBlLCBldGMuCi0gICB0d28gbnVtZXJpY2FsIGFuZCBvbmUgY2F0ZWdvcmljYWw6IGEuIHllYXIsIGluZGljYXRvciwgYW5kIGNvdW50cnk7IGIuIHR3byBpbmRpY2F0b3JzIGFuZCByZWdpb24sIGV0Yy4KCklmIHlvdSB1c2UgV0lSLCB0aGUgZm9sbG93aW5nIG1heSBiZSBleGFtcGxlcyB5b3Ugc2F3IGluIHRoZSBleGVjdXRpdmUgc3VtbWFyeToKCi0gICB0d28gY2F0ZWdvcmljYWwgYW5kIG9uZSBudW1lcmljYWw6IEYxLCBGMiwgRjQsIEYxMyAoeWVhciBpbiB0aGlzIGNhc2UgaXMgY2F0ZWdvcmljYWwpLCBGMTUKCi0gICB0d28gbnVtZXJpY2FsIGFuZCBvbmUgY2F0ZWdvcmljYWw6IEY2LCBGNywgRjEwCgotICAgVGhyZWUgY2F0ZWdvcmljYWw6IEYzCgotICAgVHdvIGNhdGVnb3JpY2FsIGFuZCB0d28gbnVtZXJpY2FsOiBGOCwgRjExCgojIyBWaXN1YWxpemF0aW9uCgpEYXRhIHZpc3VhbGl6YXRpb24gaXMgYSBrZXkgdG8gRURBLiBDcmVhdGUgdmFyaW91cyBjaGFydHMgYW5kIHdyaXRlIHlvdXIgb2JzZXJ2YXRpb25zIHlvdSBjYW4gb3IgY2Fubm90IG9idGFpbiBmcm9tIHRoZSBjaGFydC4KClRoZSBmb2xsb3dpbmcgYXJlIHRoZSBmaXJzdCB0d28gZnVuZGFtZW50YWwgcXVlc3Rpb25zIHlvdSBrZWVwIGluIG1pbmQuCgotICAgV2hhdCB0eXBlIG9mIHZhcmlhdGlvbiBvY2N1cnMgd2l0aGluIG15IHZhcmlhYmxlcz8KLSAgIFdoYXQgdHlwZSBvZiBjb3ZhcmlhdGlvbiBvY2N1cnMgYmV0d2VlbiBteSB2YXJpYWJsZXM/CgojIFlvdXIgV29yawoKSGVyZSBpcyBhIGxpc3Qgb2YgZGF0YSB5b3VyIGNsYXNzbWF0ZXMgdXNlZCBmb3IgQXNzaWdubWVudCBGb3VyLgoKIyMgV29ybGQgSW5lcXVhbGl0eSBSZXBvcnQgMjAyMiAtIFdJUgoKLSBXSVIyMDIyVGFibGVzRmlndXJlcy1TdW1tYXJ5Lnhsc3g6IERhdGEgb2YgRXhlY3RpdmUgU3VtbWFyeQotIFdJUjIwMjJUYWJsZXNGaWd1cmVzLUNoYXB0ZXI2Lnhsc3g6IApIaXN0b3JpY2FsIGFuZCBjdXJyZW50IGVtaXNzaW9ucywgSW5jb21lIGFuZCBQb3B1bGF0aW9uIGJ5IHdvcmxkIHJlZ2lvbgoKIyMgV29ybGQgRGV2ZWxvcG1lbnQgSW5kaWNhdG9ycyAtIFdESQoKLSBTUC5EWU4uVEZSVC5JTjoJRmVydGlsaXR5IHJhdGUsIHRvdGFsIChiaXJ0aHMgcGVyIHdvbWFuKQotIFNQLlBPUC5HUk9XOiBQb3B1bGF0aW9uIGdyb3d0aCAoYW5udWFsICUpCi0gTlkuR0RQLk1LVFAuQ0Q6IEdEUCAoY3VycmVudCBVUyQpCi0gTlkuR0RQLk1LVFAuS0QuWkc6IEdEUCBncm93dGggKGFubnVhbCAlKQotIEJYLktMVC5ESU5WLkNELldEOiBGb3JlaWduIERpcmVjdCBJbnZlc3RtZW50IChGREkpIGluZmxvd3MKLSBCWC5LTFQuRElOVi5DRC5XRDogRm9yZWlnbiBkaXJlY3QgaW52ZXN0bWVudCwgbmV0IGluZmxvd3MgKEJvUCwgY3VycmVudCBVUyQpCi0gQk4uQ0FCLlhPS0EuQ0Q6IEN1cnJlbnQgYWNjb3VudCBiYWxhbmNlIChCb1AsIGN1cnJlbnQgVVMkKQotIE5FLkVYUC5HTkZTLktEOiBFeHBvcnRzIG9mIGdvb2RzIGFuZCBzZXJ2aWNlcyAoY29uc3RhbnQgMjAxNSBVUyQpCi0gTkUuSU1QLkdORlMuS0Q6IEltcG9ydHMgb2YgZ29vZHMgYW5kIHNlcnZpY2VzIChjb25zdGFudCAyMDE1IFVTJCkKLSBCWC5UUkYuUFdLUi5DRC5EVDogUGVyc29uYWwgcmVtaXR0YW5jZXMsIHJlY2VpdmVkIChjdXJyZW50IFVTJCkKLSBOWS5HTlMuSUNUUi5aUzogR3Jvc3Mgc2F2aW5ncyAoJSBvZiBHRFApCi0gRU4uQVRNLkNPMkUuS1Q6IENPMiBlbWlzc2lvbnMgKGt0KQotIFNFLlhQRC5UT1RMLkdCLlpTOiBHb3Zlcm5tZW50IGV4cGVuZGl0dXJlIG9uIGVkdWNhdGlvbiwgdG90YWwgKCUgb2YgZ292ZXJubWVudCBleHBlbmRpdHVyZSkKLSBTRS5FTlIuUFJTQy5GTS5aUzogU2Nob29sIGVucm9sbG1lbnQsIHByaW1hcnkgYW5kIHNlY29uZGFyeSAoZ3Jvc3MpLCBnZW5kZXIgcGFyaXR5IGluZGV4IChHUEkpCi0gU0UuUFJNLlVORVIuRkU6IENoaWxkcmVuIG91dCBvZiBzY2hvb2wsIHByaW1hcnksIGZlbWFsZQotIFNFLlBSTS5VTkVSLk1BOiBDaGlsZHJlbiBvdXQgb2Ygc2Nob29sLCBwcmltYXJ5LCBtYWxlCgoKIyMgVW5pdGVkIE5hdGlvbnMgLSBVTmRhdGEKCi0gRWR1Y2F0aW9uOiAiaHR0cHM6Ly9kYXRhLnVuLm9yZy9fRG9jcy9TWUIvQ1NWL1NZQjY1XzMwOV8yMDIyMDlfRWR1Y2F0aW9uLmNzdiIKLSBQb3B1bGF0aW9uOiAiaHR0cHM6Ly9kYXRhLnVuLm9yZy9fRG9jcy9TWUIvQ1NWL1NZQjY1XzI0Nl8yMDIyMDlfUG9wdWxhdGlvbiUyMEdyb3d0aCwlMjBGZXJ0aWxpdHklMjBhbmQlMjBNb3J0YWxpdHklMjBJbmRpY2F0b3JzLmNzdiIKCgojIFJlc3BvbnNlcyB0byBRdWVzdGlvbnMKCiMjIFEuIFdJUjIwMjIsIEY4IHdpdGggYSBmaXhlZCB5ZWFyLCBzYXkgMjAyMCBkZXNjcmliaW5nIHRoZSBkaWZmZXJlbmNlIG9mIGdvZXZlcm5tZW50IGFuZCBwcml2YXRlIGluY29tZS4KCkFzIGZvciBXSVIyMDIyLCBwbGVhc2UgcmVmZXIgdG86IGh0dHBzOi8vZHMtc2wuZ2l0aHViLmlvL2RhdGEtYW5hbHlzaXMvd2lyMjAyMi5uYi5odG1sCgpJIGFkZGVkIGV4cGxhbmF0aW9ucyB0byBlYWNoIGNoYXJ0LgoKKiBTdGVwIDEuIEltcG9ydCB0aGUgZGF0YQoKVGhlcmUgaXMgYSBzdGVwLWJ5LXN0ZXAgZXhwbGFuYXRpb24gb2YgaG93IHRvIHJlY3JlYXRlIGEgY2hhcnQuCgpgYGB7ciBkYXRhLWYxLCBjYXNoID0gVFJVRSwgbWVzc2FnZSA9IEZBTFNFfQpkZl9mOCA8LSByZWFkX2V4Y2VsKCIuL2RhdGEvV0lSMjAyMnMueGxzeCIsIHNoZWV0ID0gImRhdGEtRjgiKQpkZl9mOApgYGAKCiogU3RlcCAyLiBUaWR5IHVwIHRoZSBkYXRhIGJ5IGBwaXZvdF9sb25nZXJgLgoKYGBge3J9CmRmX2Y4X3JldiA8LSBkZl9mOCAlPiUgZmlsdGVyKHllYXIgPT0gIjIwMjAiKSAlPiUKICBzZWxlY3QoeWVhciwgR2VybWFueV9wdWJsaWMgPSBHZXJtYW55LCBHZXJtYW55X3ByaXZhdGUgPSAnR2VybWFueSAocHJpdmF0ZSknLCAKICAgICAgICAgU3BhaW5fcHVibGljID0gU3BhaW4sIFNwYWluX3ByaXZhdGUgPSAnU3BhaW4gKHByaXZhdGUpJywgCiAgICAgICAgIEZyYW5jZV9wdWJsaWMgPSBGcmFuY2UsIEZyYW5jZV9wcml2YXRlID0gJ0ZyYW5jZSAocHJpdmF0ZSknLCAKICAgICAgICAgVUtfcHVibGljICA9IFVLLCBVS19wcml2YXRlID0gJ1VLIChwcml2YXRlKScsIAogICAgICAgICBKYXBhbl9wdWJsaWMgPSBKYXBhbiwgSmFwYW5fcHJpdmF0ZSA9ICdKYXBhbiAocHJpdmF0ZSknLCAKICAgICAgICAgTm9yd2F5X3B1YmxpYyA9IE5vcndheSwgTm9yd2F5X3ByaXZhdGUgPSAnTm9yd2F5IChwcml2YXRlKScsCiAgICAgICAgIFVTQV9wdWJsaWMgPSBVU0EsIFVTQV9wcml2YXRlID0gJ1VTQSAocHJpdmF0ZSknKSAlPiUKICBwaXZvdF9sb25nZXIoIXllYXIsIG5hbWVzX3RvID0gYygiY291bnRyeSIsIi52YWx1ZSIpLCBuYW1lc19zZXAgPSAiXyIpICU+JQogIHBpdm90X2xvbmdlcigzOjQsIG5hbWVzX3RvID0gInR5cGUiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKQpkZl9mOF9yZXYKYGBgCgoqIFN0ZXAgMy4gVmlzdWFsaXplIHVzaW5nIGBnZ3Bsb3QyYC4KClRoZW4sIGluIHRoaXMgY2FzZSwgYGdlb21fY29sYCBzZWVtcyB0byBmaXQuCgpgYGB7cn0KZGZfZjhfcmV2ICU+JQogIGdncGxvdCgpICsKICBnZW9tX2NvbChhZXMoeCA9IGNvdW50cnksIHkgPSB2YWx1ZSwgZmlsbCA9IHR5cGUpLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDEpKSArCiAgbGFicyh0aXRsZSA9ICJQcml2YXRlIHZlcnN1cyBwdWJsaWMgd2VhbHRoIGluIHJpY2ggY291bnRyaWVzIGluIDIwMjAiLCAKICAgICAgIHggPSAiIiwgeSA9ICJ3ZWFsdGggYXMgJSBvZiBuYXRpb25hbCBpbmNvbWUiLCBjb2xvciA9ICIiLCB0eXBlID0gIiIpCmBgYAoKCkNhbiB5b3UgZmluZCBhIHNpbWlsYXIgZGF0YSBvZiBvdGhlciBjb3VudHJpZXMgb2YgdGhpcyB0eXBlPwoKSXQgaXMgaW4gQ2hhcHRlciAzIG9mIHRoZSByZXBvcnQ6CgpodHRwczovL3dpcjIwMjIud2lkLndvcmxkL2NoYXB0ZXItMy8KCkZyb20gbWV0aG9kb2xvZ3ksIEkgZXhwbGFpbmVkIG9uIEphbnVhcnkgMjUsIHlvdSBjYW4gZG93bmxvYWQgdGhlIGRhdGEgZm9yIGNoYXB0ZXIgdGhyZWU6IFdJUjIwMjJUYWJsZXNGaWd1cmVzLUNoYXB0ZXIzLnhsc3gKCgojIyBRLiBUaGUgbGluZSBncmFwaCBsb29rZWQgc3RyYW5nZSBhdCBmaXJzdCBhbmQgSSBjb3VsZG7igJl0IHJlYWxseSBzZWUgdGhlIHJlc3VsdHMgY2xlYXJseS4gSG93ZXZlciwgSSBjb3VsZCBzb2x2ZSB0aGF0IHByb2JsZW0gYnkgdXNpbmcg4oCcc21vb3Roc3RhdOKAnSBhbmQgdGhlbiB0aGUgcmVzdWx0cyBsb29rZWQgd2F5IGJldHRlciBhbmQgSSB3YXMgYWJsZSB0byBpbnRlcnByZXQgdGhlbSBlYXNpbHkuCgpUaGUgc3RyYW5nZSBsb29raW5nIGxpbmUgZ3JhcGggaXMgY2FsbGVkIGEgc2F3dG9vdGggc2hhcGUsIGFuZCBoYXBwZW5zIHZlcnkgb2Z0ZW4uIFNvIGxldCBtZSBleHBsYWluIGl0CgoqIFdESSBpbmRpY2F0b3I6IEJYLktMVC5ESU5WLkNELldEOiBGb3JlaWduIERpcmVjdCBJbnZlc3RtZW50IChGREkpIGluZmxvd3MKCiogU3RlcCAxLiBJbXBvcnQgdGhlIGRhdGEuCgpgYGB7cn0KZGZfZmRpIDwtIFdESShjb3VudHJ5ID0gImFsbCIsIGluZGljYXRvciA9IGMoZmRpID0gIkJYLktMVC5ESU5WLkNELldEIiksIHN0YXJ0ID0xOTcwICwgZXh0cmEgPSBUUlVFLCBjYWNoZSA9IE5VTEwpCmRmX2ZkaQpgYGAKCiogU3RlcCAyLiBDaGVjayB0aGUgbGlzdCBvZiBgaW5jb21lYCBuYW1lcy4KClRoZSBmb2xsb3dpbmcgY29kZSBpbiBgQmFzZSBSYCBkb2VzIHRoZSBzYW1lIGFzIHRoZSBmb2xsb3dpbmcgdXNpbmcgYHRpZHl2ZXJzZWA6IApgZGZfZmRpICU+JSBkaXN0aW5jdChpbmNvbWUpICU+JSBwdWxsKClgLiAKSWYgdGhlIGxpc3QgaXMgbG9uZywgaXQgbWF5IGJlIGJldHRlciB0byBjaGVjayB1c2luZyBgdGliYmxlYCBieSBgYGRmX2ZkaSAlPiUgZGlzdGluY3QoaW5jb21lKWAuIFlvdSBjYW4gYWxzbyB1c2UgYERUOjpkYXRhdGFibGUoZGZfZmRpKWAgYW5kIHNlYXJjaCBpdGVtcyBvZiBpbnRlcmVzdCwgdGhvdWdoIGl0IHRha2VzIHVwIGEgbG90IG9mIG1lbW9yeS4KCgpgYGB7cn0KdW5pcXVlKGRmX2ZkaSRpbmNvbWUpCmBgYAoKKiBTdGVwIDMuIFRyeSBhIGxpbmUgZ3JhcGguCgpgYGB7cn0KZGZfZGZpICU+JSBnZ3Bsb3QoYWVzKHg9eWVhciwgeT1mZGksIGNvbG9yPWluY29tZSkpICsgZ2VvbV9saW5lKCkKYGBgCgpXZSBvYnNlcnZlIHNldmVyYWwgcHJvYmxlbXMuIEJ1dCB0aGUgbW9zdCBzaWduaWZpY2FudCBpc3N1ZSBpcyBpdCBsb29rcyBsaWtlIGEgc2F3dG9vdGguIEl0IGlzIGJlY2F1c2UgdGhlcmUgYXJlIHNvIG1hbnkgYHlgIHZhbHVlcyBhdCB0aGUgc2FtZSBgeGAgdmFsdWUuIFdoZW4geW91IGRyYXcgYSBsaW5lIGdyYXBoLCB5b3UgbmVlZCB0byBjaG9vc2Ugb25seSBzZXZlcmFsIGNvdW50cmllcyBvciB1c2UgZ3JvdXBfYnkgYW5kIHN1bW1hcml6ZSBhbmQgdXNlIHN1bW1hcml6ZWQgZGF0YS4gSG93ZXZlciwgdGhlcmUgaXMgYW4gb3B0aW9uOyB3ZSBjYW4gdXNlIGEgbW9kZWwgdG8gc3VtbWFyaXplIHRoZSBkYXRhIG9mIGVhY2ggZ3JvdXAgdXNpbmcgYGdlb21fc21vb3RoKClgLiBTaW5jZSB5b3UgZG8gbm90IHdhbnQgYSBsaW5lIGJ1dCBhIGN1cnZlLCB3ZSB1c2UgImxvZXNzIiB3aXRoIGBzcGFuYCwgd2UgdXNlZCB0byBkcmF3IHNvbWUgb2YgV0lSMjAyMiBjaGFydHMuCgoqIFN0ZXAgNC4gTGV0IHVzIHRyeSBgZ3JvdXBfYnlgIGFuZCBgc3VtbWFyaXplYC4KCmBgYHtyfQpkZl9mZGkgJT4lIGRyb3BfbmEoZmRpKSAlPiUgZHJvcF9uYShpbmNvbWUpICU+JSAKICBmaWx0ZXIoIWluY29tZSAlaW4lIGMoIkFnZ3JlZ2F0ZXMiLCJOb3QgY2xhc3NpZmllZCIpKSAlPiUKICBncm91cF9ieShpbmNvbWUsIHllYXIpICU+JSBzdW1tYXJpemUoZmRpX21lYW4gPSBtZWFuKGZkaSkpICU+JSAKICBnZ3Bsb3QoYWVzKHg9eWVhcix5PWZkaV9tZWFuLGNvbG9yPWluY29tZSkpICsgCiAgZ2VvbV9saW5lKCkKYGBgCgpJZiB5b3UgZG8gbm90IHdhbnQgdGhlIG1lc3NhZ2UgJ2BzdW1tYXJpc2UoKWAgaGFzIGdyb3VwZWQgb3V0cHV0IGJ5ICdpbmNvbWUnLiBZb3UgY2FuIG92ZXJyaWRlIHVzaW5nIHRoZSBgLmdyb3Vwc2AgYXJndW1lbnQuJyB0cnkgdGhlIGZvbGxvd2luZyBieSBhZGRpbmcgYC5ncm91cCA9IGRyb3BgLgoKYGBge3J9CmRmX2ZkaSAlPiUgZHJvcF9uYShmZGkpICU+JSBkcm9wX25hKGluY29tZSkgJT4lIAogIGZpbHRlcighaW5jb21lICVpbiUgYygiQWdncmVnYXRlcyIsIk5vdCBjbGFzc2lmaWVkIikpICU+JQogIGdyb3VwX2J5KGluY29tZSwgeWVhcikgJT4lIHN1bW1hcml6ZShmZGlfbWVhbiA9IG1lYW4oZmRpKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lIAogIGdncGxvdChhZXMoeD15ZWFyLHk9ZmRpX21lYW4sY29sb3I9aW5jb21lKSkgKyAKICBnZW9tX2xpbmUoKQpgYGAKCgoqIFN0ZXAgNS4gTGV0IHVzIHRyeSBgZ2VvbV9zbW9vdGhgIHdpdGggYGxvZXNzYCBhbmQgYHNwYW5gLgoKRG8geW91IHNlZSBzaW1pbGFyaXRpZXMgYW5kIGRpZmZlcmVuY2VzPyBXZSBuZWVkIHRvIGNob29zZSB0aGUgb25lIGZyb20gdGhlIG90aGVyIGJ5IG91ciBvYmplY3RpdmUsIGFuZCBleHBsYWluCgpgYGB7cn0KZGZfZmRpICAlPiUgZHJvcF9uYShmZGkpICU+JSBkcm9wX25hKGluY29tZSkgJT4lIAogIGZpbHRlcighaW5jb21lICVpbiUgYygiQWdncmVnYXRlcyIsIk5vdCBjbGFzc2lmaWVkIikpICU+JQogIGdncGxvdChhZXMoeD15ZWFyLHk9ZmRpLGNvbG9yPWluY29tZSkpICsgCiAgZ2VvbV9zbW9vdGgoZm9ybXVsYSA9IHl+eCwgbWV0aG9kID0gImxvZXNzIiwgc3BhbiA9IDAuMjUsIHNlID0gRkFMU0UpCmBgYAoKKiBTdGVwIDYuIENoYW5nZSBvZiB0aGUgc2NhbGUuCgpJdCBtYXkgYmUgYSBnb29kIGNob2ljZSB0byB1c2UgYHNjYWxlX3lfbG9nMTAoKWAuIEhvd2V2ZXIsIHNpbmNlIGxvZzEwIGlzIG5vdCBmaW5pdGUgaWYgdGhlIHZhbHVlIGlzIG5vdCBwb3NpdGl2ZSwgeW91IG5lZWQgdG8gY2hvb3NlIHRob3NlIHdpdGggdGhlIGluZGljYXRvciBwb3NpdGl2ZS4gTGV0IHVzIHNlZSBob3cgbWFueSB6ZXJvIHZhbHVlcyBhcmUgaW4gZWFjaCBpbmNvbWUgbGV2ZWwuCgpgYGB7cn0KZGZfZmRpICU+JSBmaWx0ZXIoIWluY29tZSAlaW4lIGMoTkEsICJBZ2dyZWdhdGVzIikpICU+JSBmaWx0ZXIoZmRpIDw9IDApICU+JQogIGdncGxvdChhZXMoeCA9IGluY29tZSwgZmlsbCA9IGluY29tZSkpICsgZ2VvbV9iYXIoKSArIAogIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIGNvdW50cmllcyB3aXRoIEZESSBpcyBub3QgcG9zaXRpdmUiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCgpgYGB7cn0KZGZfZmRpICU+JSBkcm9wX25hKGluY29tZSkgJT4lIGZpbHRlcihmZGkgPiAwKSAlPiUKICBmaWx0ZXIoIWluY29tZSAlaW4lIGMoIkFnZ3JlZ2F0ZXMiLCJOb3QgY2xhc3NpZmllZCIpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9eWVhcix5PWZkaSxjb2xvcj1pbmNvbWUpKSArIAogIGdlb21fc21vb3RoKGZvcm11bGEgPSB5fngsIG1ldGhvZCA9ICJsb2VzcyIsIHNwYW4gPSAwLjI1LCBzZSA9IEZBTFNFKSArCiAgc2NhbGVfeV9sb2cxMCgpICsgbGFicyh0aXRsZT0iVGhlIFZhbHVlIEZJRCA8IDAgb3IgWmVybyBFeGNsdWRlZCIpCmBgYAoKKipOb3RlLioqIElmIHRoaXMgaXMgdGhlIHRhcmdldCBjaGFydCwgaXQgbWF5IGJlIGJldHRlciB0byBjaGVjayB0aGUgbnVtYmVyIG9mIE5BIHZhbHVlcywgMCB2YWx1ZXMsIG5lZ2F0aXZlIHZhbHVlcywgYW5kIG5vbnplcm8gdmFsdWVzIGluIGVhY2ggaW5jb21lIGdyb3VwLiBJIGFkZCBgICBtdXRhdGUodmFsdWUgPSBmYWN0b3IodmFsdWUsIGxldmVscyA9IGMoIlBvc2l0aXZlIiwgIlplcm8iLCAiTmVnYXRpdmUiLCAiTkEiKSwgbGFiZWxzID0gYygiUG9zaXRpdmUiLCAiWmVybyIsICJOZWdhdGl2ZSIsICJOQSIpKSlgIGluIG9yZGVyIHRvIHNldCB0aGUgb3JkZXIgb2YgdGhlIGxhYmVscy4gUGxlYXNlIHRyeSB0aGUgc2FtZSB3aXRob3V0IHRoZSBsaW5lLgoKYGBge3J9CmRmX2ZkaSAlPiUgc2VsZWN0KGNvdW50cnksIHllYXIsIGZkaSwgaW5jb21lKSAlPiUKICBmaWx0ZXIoIWluY29tZSAlaW4lIGMoIkFnZ3JlZ2F0ZXMiLCBOQSkpICU+JSAKICBtdXRhdGUodmFsdWUgPSBjYXNlX3doZW4oCiAgICBmZGkgPT0gTkEgfiAiTkEiLAogICAgZmRpID09IDAgIH4gIlplcm8iLAogICAgZmRpIDwgMCAgfiAiTmVnYXRpdmUiLAogICAgZmRpID4gMCB+ICJQb3NpdGl2ZSIpKSAlPiUKICBtdXRhdGUodmFsdWUgPSBmYWN0b3IodmFsdWUsIGxldmVscyA9IGMoIlBvc2l0aXZlIiwgIlplcm8iLCAiTmVnYXRpdmUiLCAiTkEiKSwgbGFiZWxzID0gYygiUG9zaXRpdmUiLCAiWmVybyIsICJOZWdhdGl2ZSIsICJOQSIpKSkgJT4lCiAgZ3JvdXBfYnkoaW5jb21lLCB2YWx1ZSkgJT4lIHN1bW1hcml6ZShuID0gbigpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgCiAgZ2dwbG90KGFlcyhpbmNvbWUsIG4sIGZpbGwgPSB2YWx1ZSkpICsgZ2VvbV9jb2wocG9zaXRpb249ImRvZGdlIikgKyAKICBsYWJzKHggPSAiIikKYGBgCgojIyBRLiBIb3cgaXMgaXQgcG9zc2libGUgdG8gb3JnYW5pemUgYmV0dGVyIHRoZSBuYW1lIG9mIHRoZSB2YWx1ZSBpbiB0aGUgeCBheGlzIHNvIHRoYXQgdGhleSBhcmUgYmV0dGVyIHJlYWRhYmxlPwoKKiBJbiB0aGUgZXhhbXBsZSBhYm92ZSwgdGhlIGxhYmVscyBhcmUgb3ZlcmxhcHBpbmcuIE9uZSB3YXkgaXMgdG8gZ2l2ZSBhbiBhbmdsZSB0byB0aGUgdGV4dCB3aXRoIGB2anVzdGAgYW5kIGBoanVzdGAgdmFsdWVzIHRvIHBsYWNlIHRoZSBsYWJlbHMgaW4gYXBwcm9wcmlhdGUgcGxhY2VzOiBgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAzMCwgdmp1c3QgPSAxLCBoanVzdD0xKSlgCgpgYGB7cn0KZGZfZmRpICU+JSBzZWxlY3QoY291bnRyeSwgeWVhciwgZmRpLCBpbmNvbWUpICU+JQogIGZpbHRlcighaW5jb21lICVpbiUgYygiQWdncmVnYXRlcyIsIE5BKSkgJT4lIAogIG11dGF0ZSh2YWx1ZSA9IGNhc2Vfd2hlbigKICAgIGZkaSA9PSBOQSB+ICJOQSIsCiAgICBmZGkgPT0gMCAgfiAiWmVybyIsCiAgICBmZGkgPCAwICB+ICJOZWdhdGl2ZSIsCiAgICBmZGkgPiAwIH4gIlBvc2l0aXZlIikpICU+JQogIG11dGF0ZSh2YWx1ZSA9IGZhY3Rvcih2YWx1ZSwgbGV2ZWxzID0gYygiUG9zaXRpdmUiLCAiWmVybyIsICJOZWdhdGl2ZSIsICJOQSIpLCBsYWJlbHMgPSBjKCJQb3NpdGl2ZSIsICJaZXJvIiwgIk5lZ2F0aXZlIiwgIk5BIikpKSAlPiUKICBncm91cF9ieShpbmNvbWUsIHZhbHVlKSAlPiUgc3VtbWFyaXplKG4gPSBuKCksIC5ncm91cHMgPSAiZHJvcCIpICU+JSAKICBnZ3Bsb3QoYWVzKGluY29tZSwgbiwgZmlsbCA9IHZhbHVlKSkgKyBnZW9tX2NvbChwb3NpdGlvbj0iZG9kZ2UiKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzAsIHZqdXN0ID0gMSwgaGp1c3Q9MSkpICsgCiAgbGFicyh4ID0gIiIpCmBgYAoKKiBZb3UgY2FuIHVzZSBhbm90aGVyIHBhY2thZ2UgYHN0cmluZ3JgIGluY2x1ZGVkIGluIGB0aWR5dmVyc2VgIGJ1dCBub3QgbG9hZGVkLiBgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSBmdW5jdGlvbih4KSBzdHJpbmdyOjpzdHJfd3JhcCh4LCB3aWR0aCA9IDE1KSlgCkNoYW5nZSB0aGUgd2lkdGggdmFsdWUgdG8gZml0IHRvIHlvdXIgY2hhcnQuIElmIHlvdSBhZGQgbGlicmFyeShzdHJpbmdyKSwgdGhlbiBgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSBmdW5jdGlvbih4KSBzdHJfd3JhcCh4LCB3aWR0aCA9IDE1KSlgIGlzIGVub3VnaC4KCmBgYHtyfQpkZl9mZGkgJT4lIHNlbGVjdChjb3VudHJ5LCB5ZWFyLCBmZGksIGluY29tZSkgJT4lCiAgZmlsdGVyKCFpbmNvbWUgJWluJSBjKCJBZ2dyZWdhdGVzIiwgTkEpKSAlPiUgCiAgbXV0YXRlKHZhbHVlID0gY2FzZV93aGVuKAogICAgZmRpID09IE5BIH4gIk5BIiwKICAgIGZkaSA9PSAwICB+ICJaZXJvIiwKICAgIGZkaSA8IDAgIH4gIk5lZ2F0aXZlIiwKICAgIGZkaSA+IDAgfiAiUG9zaXRpdmUiKSkgJT4lCiAgbXV0YXRlKHZhbHVlID0gZmFjdG9yKHZhbHVlLCBsZXZlbHMgPSBjKCJQb3NpdGl2ZSIsICJaZXJvIiwgIk5lZ2F0aXZlIiwgIk5BIiksIGxhYmVscyA9IGMoIlBvc2l0aXZlIiwgIlplcm8iLCAiTmVnYXRpdmUiLCAiTkEiKSkpICU+JQogIGdyb3VwX2J5KGluY29tZSwgdmFsdWUpICU+JSBzdW1tYXJpemUobiA9IG4oKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lIAogIGdncGxvdChhZXMoaW5jb21lLCBuLCBmaWxsID0gdmFsdWUpKSArIGdlb21fY29sKHBvc2l0aW9uPSJkb2RnZSIpICsgCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSBmdW5jdGlvbih4KSBzdHJpbmdyOjpzdHJfd3JhcCh4LCB3aWR0aCA9IDE1KSkgKyAKICBsYWJzKHggPSAiIikKYGBgCgoqIElmIHlvdSBoYXZlIGEgbG9uZyBuYW1lIGZvciB0aGUgdGl0bGUsIHVzZSBgXG5gIGZvciB0aGUgbGluZSBmZWVkLgoKYGBge3J9CmRmX2ZkaSAlPiUgc2VsZWN0KGNvdW50cnksIHllYXIsIGZkaSwgaW5jb21lKSAlPiUKICBmaWx0ZXIoIWluY29tZSAlaW4lIGMoIkFnZ3JlZ2F0ZXMiLCBOQSkpICU+JSAKICBtdXRhdGUodmFsdWUgPSBjYXNlX3doZW4oCiAgICBmZGkgPT0gTkEgfiAiTkEiLAogICAgZmRpID09IDAgIH4gIlplcm8iLAogICAgZmRpIDwgMCAgfiAiTmVnYXRpdmUiLAogICAgZmRpID4gMCB+ICJQb3NpdGl2ZSIpKSAlPiUKICBtdXRhdGUodmFsdWUgPSBmYWN0b3IodmFsdWUsIGxldmVscyA9IGMoIlBvc2l0aXZlIiwgIlplcm8iLCAiTmVnYXRpdmUiLCAiTkEiKSwgbGFiZWxzID0gYygiUG9zaXRpdmUiLCAiWmVybyIsICJOZWdhdGl2ZSIsICJOQSIpKSkgJT4lCiAgZ3JvdXBfYnkoaW5jb21lLCB2YWx1ZSkgJT4lIHN1bW1hcml6ZShuID0gbigpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgCiAgZ2dwbG90KGFlcyhpbmNvbWUsIG4sIGZpbGwgPSB2YWx1ZSkpICsgZ2VvbV9jb2wocG9zaXRpb249ImRvZGdlIikgKyAKICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGZ1bmN0aW9uKHgpIHN0cmluZ3I6OnN0cl93cmFwKHgsIHdpZHRoID0gMTUpKSArIAogIGxhYnModGl0bGUgPSAibG9uZyBsb25nIGxvbmcgbG9uZyBsb25nIGxvbmcgbG9uZyBcbmxvbmcgbG9uZyBsb25nIHRpdGxlIiwgeCA9ICIiKQpgYGAKCiMjIFEuIFBvc2l0aW9uIG9mIHRoZSBsYWJlbHMKCiogU3RlcCAxLiBJZiB5b3Ugd2FudCB0byB1c2UgeW91IG93biBjb2xvciBwYWxldHRlLCBjaG9vc2UgdGhlIGNvZGVzIG9yIHRoZSBjb2xvciBuYW1lcyBmcm9tIHRoZSBmb2xsb3dpbmcgc2l0ZXMuCgogIC0gQ29sb3IgTmFtZXM6IGh0dHA6Ly93d3cuY29va2Jvb2stci5jb20vR3JhcGhzL0NvbG9yc18oZ2dwbG90MikvCiAgLSBSR0IgY29kZXM6IGh0dHBzOi8vd3d3LnJhcGlkdGFibGVzLmNvbS93ZWIvY29sb3IvUkdCX0NvbG9yLmh0bWwKCmBgYHtyfQpjb2xvcl9saXN0IDwtIGMoIiMwMEFFOUQiLCIjRjU4MjIwIiwiIzZDNjc2RSIpCmBgYAoKKiBJbXBvcnQgdGhlIGRhdGEgYW5kIHRpZHkgdXAKCmBgYHtyfQpkZl9mMSA8LSByZWFkX2V4Y2VsKCIuL2RhdGEvV0lSMjAyMnMueGxzeCIsIHNoZWV0ID0gImRhdGEtRjEiKQpkZl9mMV9yZXYgPC0gcGl2b3RfbG9uZ2VyKGRmX2YxLCAtMSwgbmFtZXNfdG8gPSAiZ3JvdXAiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKQpkZl9mMV9yZXYKYGBgCgoqIFN0ZXAgMy4gVmlzdWFsaXplIHRoZSBkYXRhIHVzaW5nIGBnZW9tX2NvbCgpYCwgY2hhbmdlIHRoZSBkZWZhdWx0IGZpbGwgY29sb3IgdXNpbmcgdGhlIGxpc3Qgb2YgdGhlIGNvbG9yIGluIFN0ZXAgMSwgYW5kIGNoYW5nZSB0aGUgc2NhbGUgb2YgdGhlIHkgYXhpcyBpbnRvIHBlcmNlbnRzLiAKCmBgYHtyfQpkZl9mMV9yZXZbZGZfZjFfcmV2JGdyb3VwICE9ICJUb3AgMSUiLF0gJT4lCiAgZ2dwbG90KGFlcyh4ID0gLi4uMSwgeSA9IHZhbHVlLCBmaWxsID0gZ3JvdXApKSArIAogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIiwgd2lkdGggPSAwLjgpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sb3JfbGlzdCkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDEpKSArCiAgbGFicyh4ID0gIiIpCmBgYAoKKiBTdGVwIDQuIEFkZCB0aGUgdmFsdWVzIGluIHRoZSB0ZXh0LiBEbyBub3QgZm9yZ2V0IHRoYXQgdGhlIHZhbHVlcyBzaG91bGQgYmUgaW4gcGVyY2VudGFnZXMuCgpgYGB7cn0KZGZfZjFfcmV2W2RmX2YxX3JldiRncm91cCAhPSAiVG9wIDElIixdICU+JQogIGdncGxvdChhZXMoeCA9IC4uLjEsIHkgPSB2YWx1ZSwgZmlsbCA9IGdyb3VwKSkgKyAKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIsIHdpZHRoID0gMC44KSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbG9yX2xpc3QpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDEpKSArCiAgbGFicyh4PSIiKSArCiAgZ2VvbV90ZXh0KGFlcyh4ID0gLi4uMSwgeSA9IHZhbHVlLCBncm91cCA9IGdyb3VwLCAKICAgICAgICAgICAgbGFiZWwgPSBzY2FsZXM6OmxhYmVsX3BlcmNlbnQoYWNjdXJhY3k9MSkodmFsdWUpKSwgCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC44KSkgIApgYGAKKiBTdGVwIDUuIElmIHlvdSB3YW50IHRvIGNoYW5nZSB0aGUgbG9jYXRpb25zIG9mIHRleHRzIHVzZSBgdmp1c3QgPSAtMC4yYC4gCgpgYGB7cn0KZGZfZjFfcmV2W2RmX2YxX3JldiRncm91cCAhPSAiVG9wIDElIixdICU+JQogIGdncGxvdChhZXMoeCA9IC4uLjEsIHkgPSB2YWx1ZSwgZmlsbCA9IGdyb3VwKSkgKyAKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIsIHdpZHRoID0gMC44KSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbG9yX2xpc3QpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDEpKSArCiAgbGFicyh4PSIiKSArCiAgZ2VvbV90ZXh0KGFlcyh4ID0gLi4uMSwgeSA9IHZhbHVlLCBncm91cCA9IGdyb3VwLCAKICAgICAgICAgICAgbGFiZWwgPSBzY2FsZXM6OmxhYmVsX3BlcmNlbnQoYWNjdXJhY3k9MSkodmFsdWUpKSwgdmp1c3QgPSAtMC4yLAogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuOCkpICAKYGBgCgoqIE9uZSBzdHVkZW50IHVzZWQgYW5vdGhlciBtZXRob2QgdG8gYWRkIGAwLjAzYCB0byB0aGUgdmFsdWUgb2YgYHlgIGJ5IGB5ID0gdmFsdWUrMC4wM2AuIEdyZWF0IQoKYGBge3J9CmRmX2YxX3JldltkZl9mMV9yZXYkZ3JvdXAgIT0gIlRvcCAxJSIsXSAlPiUKICBnZ3Bsb3QoYWVzKHggPSAuLi4xLCB5ID0gdmFsdWUsIGZpbGwgPSBncm91cCkpICsgCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiLCB3aWR0aCA9IDAuOCkgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xvcl9saXN0KSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAxKSkgKwogIGxhYnMoeD0iIikgKwogIGdlb21fdGV4dChhZXMoeCA9IC4uLjEsIHkgPSB2YWx1ZSswLjAzLCBncm91cCA9IGdyb3VwLCAKICAgICAgICAgICAgbGFiZWwgPSBzY2FsZXM6OmxhYmVsX3BlcmNlbnQoYWNjdXJhY3k9MSkodmFsdWUpKSwgCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC44KSkgIApgYGAKIyBNeSBDb21tZW50cyBhZnRlciBSZXZpZXcKCiMjIFZpc3VhbGl6YXRpb24gYnkgQ2hhcnRzCgpQbGVhc2UgdHJ5IGFzIHZhcmlvdXMgY2hhcnRzIGFzIHBvc3NpYmxlLiBZb3UgY2FuIGxlYXJuIG9ubHkgYnkgZXhwZXJpZW5jZSBvciBmcm9tIG90aGVycy4KCiMjIyBUcmVhdCBgeWVhcmAgYXMgYSBncm91cD8KCmBgYHtyfQpkZl93ZGkgPC0gV0RJKAogIGNvdW50cnkgPSAiYWxsIiwgCiAgaW5kaWNhdG9yID0gYyhsaWZlRXhwID0gIlNQLkRZTi5MRTAwLklOIiksIHN0YXJ0ID0gMTk5MCwgZXh0cmEgPSBUUlVFLCBjYWNoZSA9ICB3ZGlfY2FjaGUpCmRmX3dkaQpgYGAKCiogU29tZXRoaW5nIGlzIHdyb25nIGluIHRoZSBuZXh0IGNoYXJ0LiBDYW4geW91IHRlbGwgd2hhdCB0aGUgcHJvYmxlbSBpcz8KCmBgYHtyfQpkZl93ZGkgJT4lCiAgZmlsdGVyKHllYXIgJWluJSBjKCIxOTg4IiwgIjE5OTgiLCAiMjAwOCIsICIyMDE4IikpICU+JQogIGZpbHRlcihjb3VudHJ5ICVpbiUgYygiQWZnaGFuaXN0YW4iLCAiSXNyYWVsIiwgIkF6ZXJiYWlqYW4iLCAiQXVzdHJpYSIsICJBdXN0cmFsaWEiKSkgJT4lCiAgZ2dwbG90KGFlcyh4PXllYXIpKSArCiAgZ2VvbV9ib3hwbG90KGFlcyh5PWxpZmVFeHAsIGZpbGw9Y291bnRyeSkpCmBgYApJIGVyYXNlZCB0aGUgc2Vjb25kIGxpbmU6IGBmaWx0ZXIoeWVhciAlaW4lIGMoIjE5ODgiLCAiMTk5OCIsICIyMDA4IiwgIjIwMTgiKSlgIGJ1dCB0aGUgcmVzdWx0IGlzIHZlcnkgc2ltaWxhci4gCgoKYGBge3J9CmRmX3dkaSAlPiUKICBmaWx0ZXIoY291bnRyeSAlaW4lIGMoIkFmZ2hhbmlzdGFuIiwgIklzcmFlbCIsICJBemVyYmFpamFuIiwgIkF1c3RyaWEiLCAiQXVzdHJhbGlhIikpICU+JQogIGdncGxvdChhZXMoeD15ZWFyKSkgKwogIGdlb21fYm94cGxvdChhZXMoeT1saWZlRXhwLCBmaWxsPWNvdW50cnkpKQpgYGAKCklmIHlvdSBsb29rIGF0IHRoZSB0YWJsZSwgeW91IGNhbiBzZWUgdGhhdCB5ZWFyIGlzIGEgaW50ZWdlciB2ZWN0b3IsIG5vdCBhIGNoYXJhY3RlciB2ZWN0b3IuIFRoZW4gd2hhdCBoYXBwZW5zIGlmIHdlIHJlbW92ZSBxdW90YXRpb24gbWFya3MuIFRoZSBuZXh0IGNoYXJ0IGlzIG5vdCBhIGJveCBwbG90IGFueW1vcmUuIEl0IGlzIGJlY2F1c2UsIGZvciBlYWNoIHllYXIgdGhlcmUgaXMgb25seSBvbmUgdmFsdWUgZm9yIGVhY2ggY291bnRyeS4KCmBgYHtyfQpkZl93ZGkgJT4lCiAgZmlsdGVyKHllYXIgJWluJSBjKDE5ODgsIDE5OTgsIDIwMDgsIDIwMTgpKSAlPiUKICBmaWx0ZXIoY291bnRyeSAlaW4lIGMoIkFmZ2hhbmlzdGFuIiwgIklzcmFlbCIsICJBemVyYmFpamFuIiwgIkF1c3RyaWEiLCAiQXVzdHJhbGlhIikpICU+JQogIGdncGxvdChhZXMoeD1mYWN0b3IoeWVhcikpKSArCiAgZ2VvbV9ib3hwbG90KGFlcyh5PWxpZmVFeHAsIGZpbGw9Y291bnRyeSkpCmBgYAoKSWYgd2Ugd2FudCB0byB0YWtlIGB5ZWFyYCBhcyBhIGdyb3VwIGFmdGVyIHNlbGVjdGluZyBzb21lIHllYXJzLCB0aGVuIHdlIHNob3VsZCB0cnkgdGhlIG5leHQgdXNpbmcgYGZhY3Rvcih5ZWFyKWAuIFlvdSBjYW4gY2hhbmdlIHRoZSBsYWJlbCBvZiB4IGF4aXMgYnkKICBgbGFicyh4ID0gInllYXIiKWAgZWFzaWx5LiBXZSBzaG91bGQgYWxzbyBub3RpY2UgdGhhdCB0aGVyZSBhcmUgbm8gdmFsdWVzIGZvciAxOTg4LiBXZSBzaG91bGQgY2hlY2sgYmFzaWMgaW5mb3JtYXRpb24gYXMgc3VjaCBmaXJzdC4KCgpgYGB7cn0KZGZfd2RpICU+JQogIGZpbHRlcih5ZWFyICVpbiUgYygxOTg4LCAxOTk4LCAyMDA4LCAyMDE4KSkgJT4lCiAgZmlsdGVyKGNvdW50cnkgJWluJSBjKCJBZmdoYW5pc3RhbiIsICJJc3JhZWwiLCAiQXplcmJhaWphbiIsICJBdXN0cmlhIiwgIkF1c3RyYWxpYSIpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9ZmFjdG9yKHllYXIpLCB5PWxpZmVFeHAsIGZpbGw9Y291bnRyeSkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIsIGNvbCA9ICJibGFjayIpCmBgYApJdCBpcyBwb3NzaWJsZSBpZiB5b3UgY2hhbmdlIHllYXIgdG8gYSBjaGFyYWN0ZXIgdmVjdG9yIGJ5IGBtdXRhdGUoeWVhciA9IGFzLmNoYXJhY3Rlcih5ZWFyKSlgLgoKYGBge3J9CmRmX3dkaSAlPiUgbXV0YXRlKHllYXIgPSBhcy5jaGFyYWN0ZXIoeWVhcikpICU+JSAKICBmaWx0ZXIoeWVhciAlaW4lIGMoIjE5OTgiLCAiMjAwOCIsICIyMDE4IikpICU+JQogIGZpbHRlcihjb3VudHJ5ICVpbiUgYygiQWZnaGFuaXN0YW4iLCAiSXNyYWVsIiwgIkF6ZXJiYWlqYW4iLCAiQXVzdHJpYSIsICJBdXN0cmFsaWEiKSkgJT4lCiAgZ2dwbG90KGFlcyh4PXllYXIsIHk9bGlmZUV4cCwgZmlsbD1jb3VudHJ5KSkgKwogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIiwgY29sID0gImJsYWNrIikgKwogIGxhYnMoeCA9ICJ5ZWFyIikKYGBgCgoKIyMgVU4gRGF0YQoKKiBVTmRhdGE6IGh0dHBzOi8vZGF0YS51bi5vcmcKCkRhdGEgb2YgV29ybGQgRGV2ZWxvcG1lbnQgSW5kaWNhdG9ycyBhcmUgaW4gYSB1bmlmb3JtIGZvcm1hdCBhbmQgZG93bmxvYWRhYmxlIHVzaW5nIGFuIFIgcGFja2FnZSBXREkuIFNvIGl0IGlzIGVhc3kgdG8gaGFuZGxlLiBIb3dldmVyLCBvdGhlciBkYXRhIHJlcXVpcmUgZGF0YSB0cmFuc2Zvcm1hdGlvbiB0byBtYWtlIGl0IHRpZHkuIFdlIGdpdmUgYSBjb3VwbGUgb2YgZXhhbXBsZXMuIE1vc3Qgb2YgdGhlIFVOIGRhdGEsIHRoZXkgYXJlIGluIENTViwgYW5kIHlvdSBjYW4gZ2V0IGEgbGluayBxdWlja2x5LCBvciBkb3dubG9hZCBpdCBieSBjbGlja2luZy4gVGhvdWdoIHRoZSBkYXRhIHN0cnVjdHVyZSBpcyBub3QgdW5pZm9ybSwgaXQgaXMgcmVsYXRpdmVseSBlYXN5IHRvIGhhbmRsZS4KCiMjIyBFZHVjYXRpb24KCkJ5IHRoZSBmb2xsb3dpbmcsIHlvdSBjYW4gc2VlIHRoYXQgdGhlIGZpcnN0IHJvdyBpcyBub3QgdGhlIGNvbHVtbiBuYW1lLiBSIGdpdmVzIGNvbHVtbiBuYW1lcyBzdWNoIGFzIC4uLjEsIC4uLjIsIGV0Yy4sIHdoZW4gdGhlIGNvbHVtbiBuYW1lIGlzIHZvaWQuCgpZb3UgY2FuIGNvcHkgdGhlIGxpbmsgKHVybCkgYnkgcmlnaHQgY2xpY2sgb3IgY3RybCtjbGljay4KCmBgYHtyfQp1cmxfdW5fZWR1IDwtICJodHRwczovL2RhdGEudW4ub3JnL19Eb2NzL1NZQi9DU1YvU1lCNjVfMzA5XzIwMjIwOV9FZHVjYXRpb24uY3N2IgpgYGAKCmBgYHtyfQp1bl9lZHUgPC0gcmVhZF9jc3YodXJsX3VuX2VkdSkKdW5fZWR1CmBgYAoKTGV0IGlzIHNraXAgdGhlIGZpcnN0IHJvdyBieSBhZGRpbmcgMXNraXAgPSAxMS4KCmBgYHtyfQp1bl9lZHUgPC0gcmVhZF9jc3YodXJsX3VuX2VkdSwgc2tpcCA9IDEpCnVuX2VkdQpgYGAKCkl0IGlzIGEgdmVyeSBsYXJnZSBkYXRhLCBhbmQgd2UgbmVlZCB0byBjaGVjayB0aGUgdmFsdWVzLgoKYGBge3J9CnN1bW1hcnkodW5fZWR1KQpgYGAKV2UgY2FuIHNlZSB0aGF0IHRoZSBZZWFyIGlzIGZyb20gMjAwMCB0byAyMDIxLiBUaGUgZmlyc3QgdmFyaWFibGUsIFJlZ2lvbi9Db3VudHJ5L0FyZWEgYW5kIHRoZSBmaWZ0aCB2YXJpYWJsZSwgVmFsdWUgYXJlIGBkYmxgLCBpLmUuLCBkb3VibGU7IGhlbmNlLCB0aGVzZSBhcmUgbnVtZXJpY2FsIHZhcmlhYmxlcywgYW5kIHlvdSBjYW4gc2VlIHRoZW0gZnJvbSB0aGUgc3VtbWFyeSBhcyB3ZWxsLiBCdXQgaXQgaXMgbm90IGVhc3kgdG8gc2VlIG90aGVyIHZhcmlhYmxlcy4gTGV0IHVzIHRyeSB0aGVtIG9uZSBieSBvbmUuCgpgYGB7cn0KdW5fZWR1ICU+JSBkaXN0aW5jdCguLi4yKQpgYGAKCmBgYHtyfQp1bl9lZHUgJT4lIGRpc3RpbmN0KFNlcmllcykKYGBgCmBgYHtyfQp1bl9lZHUgJT4lIGRpc3RpbmN0KEZvb3Rub3RlcykKYGBgCgpgYGB7cn0KdW5fZWR1ICU+JSBkaXN0aW5jdChTb3VyY2UpCmBgYAoKKiBXZSBtYXkgbmVlZCB0byBoYW5kbGUgRm9vdG5vdGVzIGNhcmVmdWxseSBsYXRlciwgYnV0IGZvciB0aGUgZmlyc3QgZXhwbG9yYXRpb24sIHdlIG5lZWQsIC4uLjIgZm9yIFJlZ2lvbiwgWWVhciwgU2VyaWVzLCBWYWx1ZXMuCgpgYGB7cn0KZGZfdW5fZWR1IDwtIHVuX2VkdSAlPiUKICBzZWxlY3QoUmVnaW9uID0gLi4uMiwgWWVhciwgU2VyaWVzLCBWYWx1ZSkKZGZfdW5fZWR1CmBgYAoKSXMgdGhlcmUgYSB3YXkgdG8gc2VwYXJhdGUgcmVnaW9ucyBmcm9tIGNvdW50cmllcz8KCmBgYHtyfQpkZl91bl9lZHUgJT4lIGxlZnRfam9pbih3ZGlfY2FjaGUkY291bnRyeSwgYnkgPSBjKCJSZWdpb24iPSJjb3VudHJ5IikpICU+JQogIGZpbHRlcighaXMubmEoaXNvMmMpKSAlPiUgZGlzdGluY3QoUmVnaW9uKQpgYGAKCmBgYHtyfQpkZl91bl9lZHUgJT4lIGxlZnRfam9pbih3ZGlfY2FjaGUkY291bnRyeSwgYnkgPSBjKCJSZWdpb24iPSJjb3VudHJ5IikpICU+JQogIGZpbHRlcihpcy5uYShpc28yYykpICU+JSBkaXN0aW5jdChSZWdpb24pCmBgYAoKYGBge3J9CmRmX3VuX2VkdSAlPiUgbGVmdF9qb2luKHdkaV9jYWNoZSRjb3VudHJ5LCBieSA9IGMoIlJlZ2lvbiI9ImNvdW50cnkiKSkgJT4lCiAgZmlsdGVyKGlzLm5hKGlzbzJjKSkgJT4lIGRpc3RpbmN0KFJlZ2lvbikgJT4lIHB1bGwoKQpgYGAKClRoZXJlIGFyZSBzb21lIGNvdW50cmllcyBpc28yYyBpcyBub3QgcHJvcGVybHkgYXNzaWduZWQuIEZyb20gdGhlIGxpc3QgYWJvdmUsIFByb2JhYmx5LCB0aGUgZmlyc3QgMTIgYXJlIGFyZWFzIGFuZCB0aGUgdmFsdWUgY29udGFpbnMgdGhlIGFnZ3JlZ2F0ZWQgdmFsdWUuIAoKYGBge3J9CmFyZWEgPC0gZGZfdW5fZWR1ICU+JSBkaXN0aW5jdChSZWdpb24pICU+JSBzbGljZSgxOjEyKSAlPiUgcHVsbCgpCmFyZWEKYGBgCmBgYHtyfQp1bl9lZHVfYXJlYSA8LSBkZl91bl9lZHUgJT4lIGZpbHRlcihSZWdpb24gJWluJSBhcmVhKQp1bl9lZHVfcmVnaW9uIDwtIGRmX3VuX2VkdSAlPiUgZmlsdGVyKCFSZWdpb24gJWluJSBhcmVhKQpgYGAKCk5vdyB3ZSBjYW4gc3RhcnQgc3R1ZHlpbmcgdGhlIGRhdGEuCgpgYGB7cn0KdW5fZWR1X2FyZWEgJT4lIAogIGZpbHRlcihTZXJpZXMgJWluJSBjKCJHcm9zcyBlbnJvbGxtZW50IHJhdGlvIC0gVXBwZXIgc2Vjb25kYXJ5IGxldmVsIChtYWxlKSIsICJHcm9zcyBlbnJvbGxtZW50IHJhdGlvIC0gVXBwZXIgc2Vjb25kYXJ5IGxldmVsIChmZW1hbGUpIikpICU+JQogIGdncGxvdChhZXMoWWVhciwgVmFsdWUsIGNvbG9yID0gUmVnaW9uLCBsaW5ldHlwZSA9IFNlcmllcykpICsgZ2VvbV9saW5lKCkKYGBgCgpgYGB7cn0KdW5fZWR1X2FyZWEgJT4lIAogIGZpbHRlcihTZXJpZXMgJWluJSBjKCJHcm9zcyBlbnJvbGxtZW50IHJhdGlvIC0gVXBwZXIgc2Vjb25kYXJ5IGxldmVsIChtYWxlKSIsICJHcm9zcyBlbnJvbGxtZW50IHJhdGlvIC0gVXBwZXIgc2Vjb25kYXJ5IGxldmVsIChmZW1hbGUpIikpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gU2VyaWVzLCB2YWx1ZXNfZnJvbSA9IFZhbHVlKSAlPiUKICBtdXRhdGUgKFJhdGlvID0gYEdyb3NzIGVucm9sbG1lbnQgcmF0aW8gLSBVcHBlciBzZWNvbmRhcnkgbGV2ZWwgKGZlbWFsZSlgL2BHcm9zcyBlbnJvbGxtZW50IHJhdGlvIC0gVXBwZXIgc2Vjb25kYXJ5IGxldmVsIChtYWxlKWApICU+JQogIGdncGxvdChhZXMoWWVhciwgUmF0aW8sIGNvbG9yID0gUmVnaW9uLCBsaW5ldHlwZSA9IFJlZ2lvbikpICsgZ2VvbV9saW5lKCkgKwogIGxhYnModGl0bGUgPSAiVXBwZXIgU2Vjb25kYXJ5IExldmVsIEVkdWNhdGlvbiIsIHN1YnRpdGxlID0gIlJhdGlvID0gZmVtYWxlL21hbGUiKQpgYGAKCiMjIyBQb3B1bGF0aW9uCgpEYXRhIHN0cnVjdHVyZSBpcyBzaW1pbGFyIHRvIHRoZSBwcmV2aW91cyBvbmUuIFNvIHVzZSBgc2tpcD0xYCwgYW5kIGNoZWNrIHRoZSB2YXJpYWJsZSBzIGJyaWVmbHkuCgoKYGBge3J9CnVybF91bl9wb3AgPSAiaHR0cHM6Ly9kYXRhLnVuLm9yZy9fRG9jcy9TWUIvQ1NWL1NZQjY1XzI0Nl8yMDIyMDlfUG9wdWxhdGlvbiUyMEdyb3d0aCwlMjBGZXJ0aWxpdHklMjBhbmQlMjBNb3J0YWxpdHklMjBJbmRpY2F0b3JzLmNzdiIKZGZfdW5fcG9wIDwtIHJlYWQuY3N2KHVybF91bl9wb3AsIHNraXAgPSAxKQpkZl91bl9wb3AKYGBgCgpgYGB7cn0KZGZfdW5fcG9wICU+JSBkaXN0aW5jdChTb3VyY2UpCmBgYAoKYGBge3J9CmRmX3VuX3BvcCAlPiUgZGlzdGluY3QoRm9vdG5vdGVzKQpgYGAKCmBgYHtyfQpkZl91bl9wb3AgJT4lIGRpc3RpbmN0KFgpCmBgYAoKYGBge3J9CmRmX3VuX3BvcCAlPiUgZGlzdGluY3QoU2VyaWVzKQpgYGAKCjEuIEZvb3Rub3RlcyBuZWVkIHRvIGJlIHN0dWRpZWQuCjIuIFRoZXJlIGFyZSBmb3VyIGRpZmZlcmVudCBzb3VyY2VzLgozLiBYIGlzIGZvciB0aGUgcmVnaW9uLCB0aGUgZmlyc3QgMzAgYXJlIGFyZWFzLCBhbmQgdGhlIHJlc3QgYXJlIGNvdW50cmllcyBvciByZWdpb25zLgo0LiBUaGVyZSBhcmUgc2V2ZW4gc2VyaWVzLiBJdCBtYXkgYmUgZWFzaWVyIGlmIHdlIGFzc2lnbiBzaG9ydGVyIG5hbWVzIGZvciBlYWNoIHZhbHVlLgoKYGBge3J9CnBvcF9hcmVhIDwtIGRmX3VuX3BvcCAlPiUgZGlzdGluY3QoWCkgJT4lIHNsaWNlKDE6MzApICU+JSBwdWxsKCkKcG9wX2FyZWEKYGBgCgpgYGB7cn0KdW5fcG9wIDwtIGRmX3VuX3BvcCAlPiUgc2VsZWN0KFJlZ2lvbiA9IFgsIFllYXIsIFNlcmllcywgVmFsdWUpCnVuX3BvcApgYGAKCkxldCB1cyBjaGFuZ2UgdGhlIG5hbWVzIG9mIHNlcmllcy4KCmBgYHtyfQp1bl9wb3Bfd2lkZSA8LSB1bl9wb3AgJT4lIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBTZXJpZXMsIHZhbHVlc19mcm9tID0gVmFsdWUpCmNvbG5hbWVzKHVuX3BvcF93aWRlKSA8LSBjKCJSZWdpb24iLCAiWWVhciIsICJJbmNSYXRlIiwgIkZlcnQiLCAiSW5mRGVhdGgiLCAiTWF0RGVhdGgiLCAiTGlmZUV4cCIsICJMaWZlRXhwTSIsICJMaWZlRXhwRiIpCnVuX3BvcF93aWRlCmBgYAoKYGBge3J9CnVuX3BvcF9sb25nIDwtIHVuX3BvcF93aWRlICU+JSBwaXZvdF9sb25nZXIoY29scyA9IC1jKDEsMiksIG5hbWVzX3RvID0gIlNlcmllcyIsIHZhbHVlc190byA9ICJWYWx1ZSIpCnVuX3BvcF9sb25nICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIApgYGAKCgpgYGB7cn0KdW5fcG9wX2xvbmdfYXJlYSA8LSB1bl9wb3BfbG9uZyAlPiUgZmlsdGVyKFJlZ2lvbiAlaW4lIHBvcF9hcmVhKQp1bl9wb3BfbG9uZ19yZWdpb24gPC0gdW5fcG9wX2xvbmcgJT4lIGZpbHRlcighUmVnaW9uICVpbiUgcG9wX2FyZWEpCnVuX3BvcF93aWRlX2FyZWEgPC0gdW5fcG9wX3dpZGUgJT4lIGZpbHRlcihSZWdpb24gJWluJSBwb3BfYXJlYSkKdW5fcG9wX3dpZGVfcmVnaW9uIDwtIHVuX3BvcF93aWRlICU+JSBmaWx0ZXIoIVJlZ2lvbiAlaW4lIHBvcF9hcmVhKQpgYGAKCgpOb3cgd2UgY2FuIHZpc3VhbGl6ZSBkYXRhLgoKCiMjIFdJUgoKSW4gdGhlIGZvbGxvd2luZywgd2UgZXhwbGFpbiBob3cgdG8gZG93bmxvYWQgZGF0YSBieSBhbiBSIHBhY2thZ2UgYHdpcmAuIEZpcnN0LCB5b3UgbmVlZCB0byBpbnN0YWxsIHRoZSBwYWNrYWdlLiBIb3dldmVyLCBpdCBpcyBub3QgYW4gb2ZmaWNpYWwgUiBwYWNrYWdlIHlldDsgeW91IG5lZWQgdG8gdXNlIHRoZSBwYWNrYWdlIGBkZXZ0b29sc2AgdG8gaW5zdGFsbCBpdC4KCmBgYHtyIGV2YWw9RkFMU0V9Cmluc3RhbGwucGFja2FnZXMoImRldnRvb2xzIikKZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJXSUR3b3JsZC93aWQtci10b29sIikKYGBgCgoKSSBoYXZlIG5vdCBzdHVkaWVkIGZ1bGx5LCBidXQgeW91IGNhbiBkb3dubG9hZCB0aGUgZGF0YSBieSBhIHBhY2thZ2UgY2FsbGVkIGB3aXJgLiBTZWUgW2hlcmVdKGh0dHBzOi8vZHMtc2wuZ2l0aHViLmlvL2RhdGEtYW5hbHlzaXMvd2lyMjAyMi5uYi5odG1sKS4gQWZ0ZXIgaW5zdGFsbGluZyB0aGUgcGFja2FnZSwgY2hlY2sgdGhlIFtjb2RlYm9va10oaHR0cHM6Ly93aWQud29ybGQvY29kZXMtZGljdGlvbmFyeSkgb2YgdGhlIGluZGljYXRvcnMuIFRoZSBmb2xsb3dpbmcgaXMgbm90IHRoZSByYXRpbyBnaXZlbiBpbiBGOCwgYnV0IGFuIGV4YW1wbGUuIAoKKiB3CXdlYWx0aC10by1pbmNvbWUgcmF0aW8gb3IgbGFib3IvY2FwaXRhbCBzaGFyZQlmcmFjdGlvbiBvZiBuYXRpb25hbCBpbmNvbWUKKiB3ZWFsZzogbmV0IHB1YmxpYyB3ZWFsdGggdG8gbmV0IG5hdGlvbmFsIGluY29tZSByYXRpbwoqIHdlYWxwOiBuZXQgcHJpdmF0ZSB3ZWFsdGggdG8gbmV0IG5hdGlvbmFsIGluY29tZSByYXRpbwoKYGBge3J9CmxpYnJhcnkod2lkKQp3d2VhbGcgPC0gZG93bmxvYWRfd2lkKGluZGljYXRvcnMgPSAid3dlYWxnIiwgYXJlYXMgPSAiYWxsIiwgeWVhcnMgPSAiYWxsIikKd3dlYWxwIDwtIGRvd25sb2FkX3dpZChpbmRpY2F0b3JzID0gInd3ZWFscCIsIGFyZWFzID0gImFsbCIsIHllYXJzID0gImFsbCIpCmBgYAoKYGBge3J9CnB1YmxpYyA8LSB3d2VhbGcgJT4lIHNlbGVjdChjb3VudHJ5LCB5ZWFyLCBwdWJsaWMgPSB2YWx1ZSkKcHVibGljCmBgYAoKYGBge3J9CnByaXZhdGUgPC0gd3dlYWxwICU+JSBzZWxlY3QoY291bnRyeSwgeWVhciwgcHJpdmF0ZSA9IHZhbHVlKQpwcml2YXRlCmBgYAoKYGBge3J9CnB1YmxpY192c19wcml2YXRlIDwtIHB1YmxpYyAlPiUgbGVmdF9qb2luKHByaXZhdGUpCnB1YmxpY192c19wcml2YXRlCmBgYAoKYGBge3J9CmRmX3B1Yl9wcml2IDwtIHB1YmxpY192c19wcml2YXRlICU+JSBwaXZvdF9sb25nZXIoY29scyA9IGMoMyw0KSwgbmFtZXNfdG8gPSAiY2F0ZWdvcnkiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUgbGVmdF9qb2luKHdkaV9jYWNoZSRjb3VudHJ5LCBieSA9IGMoImNvdW50cnkiPSJpc28yYyIpKSAlPiUKICBzZWxlY3QoY291bnRyeSA9IGNvdW50cnkueSwgaXNvMmMgPSBjb3VudHJ5LCB5ZWFyLCBjYXRlZ29yeSwgdmFsdWUsIHJlZ2lvbiwgaW5jb21lLCBsZW5kaW5nKQpkZl9wdWJfcHJpdgpgYGAKCmBgYHtyfQp1bmlxdWUoZGZfcHViX3ByaXYkY291bnRyeSkKYGBgCgoKYGBge3J9CmRmX3B1Yl9wcml2ICU+JSAKICBmaWx0ZXIoY291bnRyeSAlaW4lIGMoIkphcGFuIiwgIk5vcndheSIsICJTd2VkZW4iLCAiRGVubWFyayIsICJGaW5sYW5kIiksIHllYXIgJWluJSAxOTcwOjIwMjApICU+JQogIGdncGxvdChhZXMoeWVhciwgdmFsdWUsIGNvbG9yID0gY291bnRyeSwgbGluZXR5cGUgPSBjYXRlZ29yeSkpICsgZ2VvbV9saW5lKCkKYGBgCgpXZSBjaG9vc2UgdHdvIGluZGljYXRvcnM6ICd3ZWFsZycgYW5kICd3ZWFscCcuIFdJUjIwMjIgaW5kaWNhdG9ycyBjb25zaXN0cyBvZiA2IGNoYXJhY3RlcnM7IDEgbGV0dGVyIGNvZGUgcGx1cyA1IGxldHRlciBjb2RlLiBZb3UgY2FuIGZpbmQgdGhlIGxpc3QgaW4gdGhlIGNvZGVib29rLgoKSWYgeW91IHdhbnQgdG8gc3R1ZHkgV0lSMjAyMiwgcGxlYXNlIHN0dWR5IHRoZSBbcmVwb3J0XShodHRwczovL3dpcjIwMjIud2lkLndvcmxkLyksIHRoZSBbY29kZWJvb2tdKGh0dHBzOi8vd2lkLndvcmxkL2NvZGVzLWRpY3Rpb25hcnkpLCBhbmQgd2lyIFt2aWduZXR0ZV0oaHR0cHM6Ly9kcy1zbC5naXRodWIuaW8vZGF0YS1hbmFseXNpcy93aXJfZG93bmxvYWQucGRmKSB0b2dldGhlciB3aXRoIHRoZSBbUiBOb3RlYm9va10oaHR0cHM6Ly9kcy1zbC5naXRodWIuaW8vZGF0YS1hbmFseXNpcy93aXIyMDIyLm5iLmh0bWwpLiAKCkFzIEkgbWVudGlvbmVkIGVhcmxpZXIsIHRoZSBkYXRhIHRhYmxlcyB1c2VkIGluIHRoZSByZXBvcnQgYXJlIGF2YWlsYWJsZSBmcm9tIHRoZSBmb2xsb3dpbmcgcGFnZS4gCgoqIE1ldGhvZG9sb2d5OiBodHRwczovL3dpcjIwMjIud2lkLndvcmxkL21ldGhvZG9sb2d5LwoK