Introduction
In this section we will continue to use the regional report “The
Pulse of Democracy”, available here,
where the main findings of the 2018/19 round of the AmericasBarometer
are presented. One of the sections of this report reports data on social
networks and political attitudes. This section presents data on the use
of the Internet and the use of social networks, in general and by
country. In this case we are going to work with the frequency of use of
social networks. In this section we are going to descriptively analyze
these variables on the frequency of use of social networks, ordinal
variables (or factor variables, in the language of R).
About the dataset
The data we are going to use should be cited as follows: Source:
AmericasBarometer by the Latin American Public Opinion Project (LAPOP),
wwww.LapopSurveys.org. This document reloads a trimmed database. To
reproduce the results shown in this section, you must clean the
Environment.
This database is hosted in the “materials_edu” repository of the
LAPOP account on GitHub. Using the rio
library and the
import
command, we can import this database from this
repository. In addition, the data from countries with codes less than or
equal to 35 are selected, that is, the observations of the United States
and Canada are eliminated.
library(rio)
lapop18 = import("https://raw.github.com/lapop-central/materials_edu/main/LAPOP_AB_Merge_2018_v1.0.sav")
lapop18 = subset(lapop18, pais<=35)
We also load data from the 2021 round.
lapop21 = import("https://raw.github.com/lapop-central/materials_edu/main/lapop21.RData")
lapop21 = subset(lapop21, pais<=35)
Describing and plotting variables
In the section on descriptive statistics, which can be seen here,
we worked with nominal variables, with dichotomous response options
(Yes/No). In this document we will work with politomic ordinal
variables.
Votes are correctly counted
In this section, we use the variable COUNTFAIR1. Votes are counted
correctly and fairly. Would you say it happens always, sometimes or
never? Figure 2.5 of the report The Pulse of Democracy, available here,
shows results of this variable by country.
In the same way as with nominal variables, these ordinal variables
have to be declared as “factor” in new variables.
library(haven)
lapop21$countfair1r = as.factor(lapop21$countfair1)
Then, these variables have to be labelled. We can create a basic
descriptive table with the command table
.
levels(lapop21$countfair1r) = c("Always", "Sometimes", "Never")
table(lapop21$countfair1r)
##
## Always Sometimes Never
## 3477 5235 1698
To calculate tables with percentages, rounded to one decimal place,
we use prop.table
and round
. Again, these
percentages are not the same as those presented in the report because
these calculations do not include factor weights.
round(prop.table(table(lapop21$countfair1r)), 3)*100
##
## Always Sometimes Never
## 33.4 50.3 16.3
As we mention in the previous section, we can plot this variable
using the command barplot
.
barplot(prop.table(table(lapop21$countfair1r))*100)
Other option is create this plot using the library
ggplot
. One option is working with the dataset from
scratch. The following code, however, shows a big bar with the
percentage of missing values. This is because this question was applied
to a split sample. The dataset records NA to the other half of those who
do not answer this question.
library(ggplot2)
ggplot(data=lapop21, aes(x=countfair1r))+
geom_bar(aes(y=..prop..*100, group=1), width=0.5)+
labs(x="Votes are counted correctly", y="Percentage",
caption="AmericasBarometer by LAPOP, 2021")+
coord_cartesian(ylim=c(0, 100))
To prevent that the figure shows a bar for NAs, these observations
should be filtered before producing the graph. In the same manner as the
previous section, we can filter the NAs for the variable “countfair1”
with the command subset
and the specification
!is.na
.
ggplot(data=subset(lapop21, !is.na(countfair1r)), aes(x=countfair1r))+
geom_bar(aes(y=..prop..*100, group=1), width=0.5)+
labs(x="Votes are counted correctly", y="Percentage",
caption="AmericasBarometer by LAPOP, 2021")+
coord_cartesian(ylim=c(0, 60))
Other option, that simplify the code, is to create a frequency table
of this variable with the command table
and
prop.table
. This table is rounded to one decimal place with
the command round
and is saved as a dataframe with the
command as.data.frame
in an object “count”. This table
records two columns, the first is called “Var1” with the labels of the
variables and the second is called “Freq” and stores the
percentages.
count = as.data.frame(round(prop.table(table(lapop21$countfair1r)), 3)*100)
count
We can use this table “count” to produce a bar plot with the command
ggplot
. The specification aes
defines that the
values of the column “Var1” are presented in the X axis and the values
of the column “Freq” are shown in the Y axis. We define a simple bar
plot, using the command geom_bar( )
, where internally we
define the width of bars. We define labels of axis and the “caption”
with the specification labs
.
ggplot(data=count, aes(x=Var1, y=Freq))+
geom_bar(stat="identity", width=0.5)+
geom_text(aes(label=paste(Freq, "%", sep="")), color="white",
position=position_stack(vjust=0.5), size=3)+
labs(x="Votes are counted correctly", y="Percentage",
caption="AmericasBarometer by LAPOP, 2021")
Figure 2.5 shows a stacked bar with information for each country.
First, we present a stacked bar plot using all observation of the 2021
round of the AmericasBarometer, that is including all countries. To
produce a stacked horizontal bar, we use the variable “Freq”, now in the
X axis. We use the option fill
to divive this bar by values
of the variable “Var1”. Because Y axis does not show a variable, we
define as " "
. In the same way as we change the variables
in the axis, we can also change the labels in labs
. In this
specification we change the label of the legend with
fill
.
ggplot(data=count, aes(x=Freq, y="", fill=Var1))+
geom_bar(stat="identity", width=0.3)+
geom_text(aes(label=paste(Freq, "%", sep="")), color="white",
position=position_stack(vjust=0.5), size=3)+
labs(x="Percentage", y="", fill="Votes are counted correctly",
caption="AmericasBarometer by LAPOP, 2021")
To replicate the comparative graph by country, we have to create a
contingency table between variable “countfair1” and “pais”. This
crosstable is saved in an object “count_country”. We should note that
the dataframe creates a row for each value of “countfair” in each
country. In this way, we have 3 option x 20 countries = 60 rows.
count_country = as.data.frame(round(prop.table(table(lapop21$pais, lapop21$countfair1r), 1), 3)*100)
count_country
We calculate data for each value of the variable “pais” in this
table, even when there is no data in the variable “countfair” because
this question was not fielded in a country. For this reason, we have to
drop rows of countries where we could not record information. We can do
this with the specification [-c(rows), ]
. After that, we
can create a vector with the names of countries. This list of countries
is repeated three times (15 remaining countries x 3 options). This
vector is added to the dataframe in a column “country”.
count_country = count_country[-c(1:4,18,21:24,38,41:44,58),]
country = c("Nicaragua", "Costa Rica", "Panama", "Colombia", "Ecuador", "Bolivia", "Peru",
"Paraguay", "Chile", "Uruguay", "Brazil", "Argentina", "Dom. Rep.", "Jamaica", "Guyana",
"Nicaragua", "Costa Rica", "Panama", "Colombia", "Ecuador", "Bolivia", "Peru",
"Paraguay", "Chile", "Uruguay", "Brazil", "Argentina", "Dom. Rep.", "Jamaica", "Guyana",
"Nicaragua", "Costa Rica", "Panama", "Colombia", "Ecuador", "Bolivia", "Peru",
"Paraguay", "Chile", "Uruguay", "Brazil", "Argentina", "Dom. Rep.","Jamaica", "Guyana")
count_country$country = country
count_country
With this dataframe “count_country”, we have the elements to
replicate the figure with stacked bars by country. In the specification
aes
, we define that percentages are in X axis, countries in
Y axis and that each bar is divided by column “Var2”.
ggplot(data=count_country, aes(x=Freq, y=country, fill=Var2))+
geom_bar(stat="identity", width=0.3)+
geom_text(aes(label=paste(Freq, "%", sep="")), color="white",
position=position_stack(vjust=0.5), size=2)+
labs(x="Percentage", y="Country", fill="Votes are counted correctly",
caption="AmericasBarometer by LAPOP, 2021")
Frequency of use of social networks
The 2018/19 round evaluates the use of social networks and includes
variables to measure the use of Facebook, Twitter and Whatsapp: SMEDIA2
measures the use of Facebook. How often do you view content on Facebook?
SMEDIA5.How often do you see content on Twitter? and SMEDIA8. How often
do you use Whatsapp? These variables have as response options:
- Daily
- A few times a week
- A few times a month
- A few times a year
- Never
In the same way as with nominal variables, these variables have to be
declared as “factor” in new variables.
lapop18$smedia2r = as.factor(lapop18$smedia2)
lapop18$smedia5r = as.factor(lapop18$smedia5)
lapop18$smedia8r = as.factor(lapop18$smedia8)
Footnote 15 of the report indicates that “interviewees who report
never seeing content on Facebook and Twitter, and who indicate that they
never use Whatsapp, are considered non-users of these social networks”
(p. 64). For this reason, Figure 3.3 of frequency of use of social
networks (page 57) only includes the categories “Daily”, “Some times a
week”, “Some times a month” and “Some times a year”. The category
“Never” is excluded.
In the new variables we are going to declare the value 5,
corresponding to “never”, as “NA”, that is, as a missing value in R.
library(car)
lapop18$smedia2r = car::recode(lapop18$smedia2r, "5=NA")
lapop18$smedia5r = car::recode(lapop18$smedia5r, "5=NA")
lapop18$smedia8r = car::recode(lapop18$smedia8r, "5=NA")
Then, these variables have to be labeled and the basic descriptive
tables generated, with the command table
.
levels(lapop18$smedia2r) <- c("Daily", "A few times a week",
"A few times a month", "A few times a year")
levels(lapop18$smedia5r) <- c("Daily", "A few times a week",
"A few times a month", "A few times a year")
levels(lapop18$smedia8r) <- c("Daily", "A few times a week",
"A few times a month", "A few times a year")
table(lapop18$smedia2r)
##
## Daily A few times a week A few times a month A few times a year
## 8633 4927 1286 282
table(lapop18$smedia5r)
##
## Daily A few times a week A few times a month A few times a year
## 795 728 422 193
table(lapop18$smedia8r)
##
## Daily A few times a week A few times a month A few times a year
## 14151 2646 495 50
To calculate tables with percentages, rounded to a decimal place, we
use prop.table
and round
. Again, these
percentages are not exactly the same as those presented in the report
because these calculations do not include survey weights.
round(prop.table(table(lapop18$smedia2r)), 3)*100
##
## Daily A few times a week A few times a month A few times a year
## 57.1 32.6 8.5 1.9
round(prop.table(table(lapop18$smedia5r)), 3)*100
##
## Daily A few times a week A few times a month A few times a year
## 37.2 34.1 19.7 9.0
round(prop.table(table(lapop18$smedia8r)), 3)*100
##
## Daily A few times a week A few times a month A few times a year
## 81.6 15.3 2.9 0.3
To present all the data in a joint table, the table of each social
network is saved in a new R object (named after each social network).
Then all of these partial tables, containing the same answer choices,
are joined as rows with the rbind
command. This new joint
table is saved as a new dataframe “table”.
Facebook = round(prop.table(table(lapop18$smedia2r)), 3)*100
Twitter = round(prop.table(table(lapop18$smedia5r)), 3)*100
Whatsapp = round(prop.table(table(lapop18$smedia8r)), 3)*100
table = as.data.frame(rbind(Facebook, Twitter, Whatsapp))
table
To get a better presentation of the table, you can use the
kable
command from the knitr
package or the
formattable
command from the knitr
package.
library(knitr)
kable(head(table), format="markdown", digits=1)
Facebook |
57.1 |
32.6 |
8.5 |
1.9 |
Twitter |
37.2 |
34.1 |
19.7 |
9.0 |
Whatsapp |
81.6 |
15.3 |
2.9 |
0.3 |
library(formattable)
formattable(table)
|
Daily
|
A few times a week
|
A few times a month
|
A few times a year
|
Facebook
|
57.1
|
32.6
|
8.5
|
1.9
|
Twitter
|
37.2
|
34.1
|
19.7
|
9.0
|
Whatsapp
|
81.6
|
15.3
|
2.9
|
0.3
|
To graph this variable we are not going to follow the same procedure
as in the previous section. In this section we are going to work
directly from the table created with the percentages of the three social
networks. This table has each social network in the rows and the answer
options in the columns. In order to graph this data, it is required that
the social networks are in the columns and the answer options in the
rows, so first we are going to transpose this table. We do this
procedure using the data.table
library and the
transpose
command. We save these transposed data in a new
table “table_tr”.
This command transposes the data, but leaves the rows and columns
unnamed. Columns are first named with the command colnames
using the row names of “table”. The rows are then named with the command
rownames
using the column names of “table”.
Finally, we require a column inside “table_tr” that contains the
response labels of the smedia questions. These labels are like row
names. To include them as one more variable, add a variable
“tabla_tr$lab” to which the names of the rows are assigned with
row.names
.
library(data.table)
table_tr = transpose(table)
colnames(table_tr) = rownames(table)
rownames(table_tr) = colnames(table)
table_tr$lab <- rownames(table_tr)
table_tr
Second, the ggplot2
library is activated to plot the
data stored in “table_tr” with the command ggplot
. Within
this command it is specified that this command is going to work with the
dataframe “table_tr” (and not with lapop18), data=table_tr
.
The “aesthetic” is specified: the X axis will not include a variable,
the Y axis will show the “Facebook” information from the dataframe
“table_tr”, and fill=lab
indicates that data will be
divided by categories of the variable stored in “lab”.
Then the geom_bar
layer is added to indicate that it
will be graphed in bars of width (width = 1
) and that the
bar will replicate what is specified in the aesthetic
(stat="identity"
). With geom_text
you add the
labels of the data, with the percentage symbol, and you specify the
position of the text with position=position_stack(…)
and
the size with size=3
. With coord_polar
you
transform the bars into a pie chart. Finally, the “theme” is defined
with theme_void
indicating a white background and the
legend tag is modified with scale_fill_discrete
.
library(ggplot2)
ggplot(data=table_tr, aes(x="", y=Facebook, fill=lab))+
geom_bar(width=1, stat="identity")+
geom_text(aes(label=paste(Facebook, "%", sep="")), color="white",
position=position_stack(vjust=0.5), size=3)+
coord_polar("y", start=0)+
theme_void()+
scale_fill_discrete(name="Frequency of use of Facebook")
In figure 3.3 of the report “The Pulse of Democracy” a circular
“donna” type graph is presented. To exactly reproduce this type of
graph, a few details of the above syntax have to be accommodated. We set
“x=2” in the “aesthetics” and set limits on the X axis, between 0.5 and
2.5, so that when the axis is rotated, the “hole” inside the circle is
created.
ggplot(data=table_tr, aes(x=2, y=Facebook, fill=lab))+
geom_bar(stat="identity")+
geom_text(aes(label=paste(Facebook, "%", sep="")), color="white",
position=position_stack(vjust=0.5), size=3)+
coord_polar("y")+
theme_void()+
scale_fill_discrete(name="Frequency of use of Facebook")+
labs(title="How often do you view content on Facebook?",
caption="AmericasBarometer by LAPOP, 2018/19")+
xlim(0.5, 2.5)
To replicate the bar chart, some modifications are made to the code
above. For example, in “aesthetics”, it is now indicated that the
variable “smedia2r” goes on the X axis and the percentage “per” goes on
the Y axis. In addition, the specification of polar coordinates is
eliminated. We can add a title to the chart, axis labels, and a caption
with the specification labs
. Finally, the Y axis is defined
between 0 and 60 with the coord_cartesian
specification. An
important point is that this graph can also be saved in an object in R,
which we will call “plot1”
plot1 <- ggplot(table_tr, aes(x=lab, y=Facebook))+
geom_bar(stat="identity", width=0.5)+
geom_text(aes(label=paste(Facebook, "%", sep="")), color="black", vjust=-0.5)+
labs(title="Frequency of use of social networks", x="Frequency of use of Facebook",
y="Percentage", caption="AmericaBarometer by LAPOP, 2018/19")+
coord_cartesian(ylim=c(0, 60))
plot1
Saving a chart to an object allows us to later add more layers or
enhancements to the chart. The plot above, for example, has the
“Frequency of use” labels on a single line, so they could overlap.
To improve this visualization, these labels can be tilted, but if you
want to maintain the horizontality to facilitate reading, what you can
do is separate the long labels into two or more lines. This can be done,
for example, by creating a vector with the new labels. Long tags can be
broken into lines by including \n
between the texts you
want to break. Then a new layer can be added to the object “plot1” to
replace the labels with the new ones divided into lines. This is done
with the specification scale_x_discrete
where we define to
use the labels in the new vector.
etiq <- c("Daily", "A few times\n a week", "A few times\n a month",
"A few times\n a year")
plot1 + scale_x_discrete(labels=etiq)
This makes the graph more readable. So far, we have replicated the
tables and graphs that were used with the nominal variables, now using
ordinal variables. If you want to replicate the pie chart of the other
social networks, you can run the same code, but change the social
network column. For Twitter, for example, you would have.
plot2 <- ggplot(data=table_tr, aes(x=2, y=Twitter, fill=lab))+
geom_bar(stat="identity")+
geom_text(aes(label=paste(Twitter, "%", sep="")), color="white",
position=position_stack(vjust=0.5), size=3)+
coord_polar("y")+
theme_void()+
scale_fill_discrete(name="Frequency of Twitter use")+
labs(title="How often you view content on Twitter", caption="Americas Barometer by LAPOP, 2018/19")+
xlim(0.5, 2.5)
plot2
Cross tables
Table 3.1 (page 55) of the report “The Pulse of Democracy” shows the
percentages of use of social networks by country. Then, on page 56,
there is a table with the percentage of social network users by
sociodemographic characteristics, for example, urban/rural, male,
average age, average wealth, and years of study.
We will start by replicating the general data on the use of social
networks that is reported in Table 3.1. To replicate this table, you
must first define the variable “country” and the variables for the use
of social networks (smedia1, smedia4 and smedia7).
lapop18$smedia1r = as.factor(lapop18$smedia1)
lapop18$smedia4r = as.factor(lapop18$smedia4)
lapop18$smedia7r = as.factor(lapop18$smedia7)
levels(lapop18$smedia1r) = c("Yes", "No")
levels(lapop18$smedia4r) = c("Yes", "No")
levels(lapop18$smedia7r) = c("Yes", "No")
lapop18$pais = as.factor(lapop18$pais)
levels(lapop18$pais) = c("México", "Guatemala", "El Salvador", "Honduras",
"Nicaragua","Costa Rica", "Panamá", "Colombia",
"Ecuador", "Bolivia", "Perú", "Paraguay",
"Chile", "Uruguay", "Brasil", "Argentina",
"Rep. Dom.", "Jamaica")
table(lapop18$pais) #Country
##
## México Guatemala El Salvador Honduras Nicaragua Costa Rica
## 1580 1596 1511 1560 1547 1501
## Panamá Colombia Ecuador Bolivia Perú Paraguay
## 1559 1663 1533 1682 1521 1515
## Chile Uruguay Brasil Argentina Rep. Dom. Jamaica
## 1638 1581 1498 1528 1516 1513
table(lapop18$smedia1r) #Facebook
##
## Yes No
## 15389 11573
However, the variable “user” of each social network is calculated as
a condition of two variables, as seen in the document on data
manipulation, with the following code.
lapop18$fb_user = ifelse(lapop18$smedia1==1 & lapop18$smedia2<=4, 1, 0)
lapop18$tw_user = ifelse(lapop18$smedia4==1 & lapop18$smedia5<=4, 1, 0)
lapop18$wa_user = ifelse(lapop18$smedia7==1 & lapop18$smedia8<=4, 1, 0)
These variables are plotted in the report in Figure 3.1. To reproduce
this data, you can describe these variables.
prop.table(table(lapop18$fb_user))*100
##
## 0 1
## 43.8289 56.1711
prop.table(table(lapop18$tw_user))*100
##
## 0 1
## 92.056769 7.943231
prop.table(table(lapop18$wa_user))*100
##
## 0 1
## 35.76561 64.23439
As in previous graphs, with this data a dataframe can be created that
would be used to make the circular graphs shown in the report.
To replicate the table of use of social networks by country, first,
bivariate tables are created with the percentage of those who use and
the percentage of those who do not use each social network in each
country. These tables are stored in R objects. These objects are then
merged using the commands cbind
to bind the columns and
as.data.frame
to bind the tables as a dataframe. This table
also presents the percentages of those who do not use these social
networks. To present a table that includes only those who do use social
networks, columns are eliminated, using the specification
[, c(-1,-3,-5)]
, which indicates that we want to eliminate
columns 1 , 3 and 5. Finally, the dataframe columns are renamed.
fbcountry = round(prop.table(table(lapop18$pais, lapop18$fb_user), 1), 3)*100
twcountry = round(prop.table(table(lapop18$pais, lapop18$tw_user), 1), 3)*100
whcountry = round(prop.table(table(lapop18$pais, lapop18$wa_user), 1), 3)*100
tablecountry = as.data.frame(cbind(fbcountry, twcountry, whcountry))
tablecountry = tablecountry[, c(-1,-3,-5)]
varnames = c("Use facebook", "Use Twitter", "Use Whatsapp")
colnames(tablecountry) = varnames
tablecountry
To have a better presentation of the table, there are two
alternatives: the first with the knitr
library and the
other with the formattable
library.
library(knitr)
kable(head(tablecountry), format="markdown", digits=1)
México |
47.9 |
7.6 |
55.1 |
Guatemala |
43.2 |
6.5 |
47.6 |
El Salvador |
56.2 |
6.7 |
56.0 |
Honduras |
44.6 |
4.8 |
46.9 |
Nicaragua |
48.1 |
5.8 |
47.7 |
Costa Rica |
66.6 |
8.0 |
81.6 |
library(formattable)
formattable(tablecountry)
|
Use facebook
|
Use Twitter
|
Use Whatsapp
|
México
|
47.9
|
7.6
|
55.1
|
Guatemala
|
43.2
|
6.5
|
47.6
|
El Salvador
|
56.2
|
6.7
|
56.0
|
Honduras
|
44.6
|
4.8
|
46.9
|
Nicaragua
|
48.1
|
5.8
|
47.7
|
Costa Rica
|
66.6
|
8.0
|
81.6
|
Panamá
|
34.6
|
5.8
|
56.7
|
Colombia
|
60.0
|
10.7
|
63.5
|
Ecuador
|
66.9
|
11.2
|
60.2
|
Bolivia
|
57.9
|
5.6
|
63.5
|
Perú
|
61.4
|
7.6
|
58.6
|
Paraguay
|
60.5
|
8.0
|
69.2
|
Chile
|
62.9
|
9.2
|
75.5
|
Uruguay
|
66.5
|
9.8
|
80.0
|
Brasil
|
59.2
|
7.9
|
74.9
|
Argentina
|
67.3
|
12.9
|
78.9
|
Rep. Dom.
|
61.9
|
9.5
|
68.2
|
Jamaica
|
45.9
|
4.5
|
68.1
|
Crosstables with sociodemographic variables
On page 56 of the report “The pulse of democracy” the results of the
crosstable between the variables use of social networks and
sociodemographic variables such as urban/rural, gender, age, wealth and
years of education are presented.
The variable “q1” records the gender of the interviewee. This
variable is encoded as follows:
- Man
- Woman
To calculate a “dummy” variable called “man”, such that male is 1 and
female is 0, one way to do it is algebraically (2-variable q1). In this
way, now the men maintain the value 1 (2-1) and the women become 0
(2-2). In this case, the new variable “man” is created as a numeric
variable. We are going to keep the variable as “num” so that, further
down, we can calculate the mean of this variable (something that cannot
be done with a variable declared as a factor).
lapop18$men <- 2-lapop18$q1
table(lapop18$men)
##
## 0 1
## 14084 13943
The urban/rural variable is named “ur” in the database and is encoded
as follows:
- Urban
- Rural
In the same way as with gender, the formula 2- variable ur is used,
but this variable is converted into a factor and is labeled.
lapop18$urban <- 2-lapop18$ur
lapop18$urban = as.factor(lapop18$urban)
levels(lapop18$urban) <- c("Rural", "Urban")
table(lapop18$urban)
##
## Rural Urban
## 8089 19953
The crosstables of the use of social networks by some of the
sociodemographic variables will be presented, to better understand how
the general table is constructed. For example, the report shows in Table
3.2, after the general population column, the columns for WhatsApp users
and non-users (variable “wa_user”) and in the rows, the first
corresponds to urban (variable “urban”, where 0 is rural and 1 urban).
It is presented that among WhatsApp users, 76.7% are urban and among
non-users, 62% are urban. These data are generated with the
table
command that allows you to make a contingency table
of 2 variables. In this case it should be noted that each variable has a
title. So the command is
table(title1 = var1, title2 = var2)
. Then, the
prop.table
command is used so that the observations are not
displayed, but the percentages. This command allows you to calculate the
percentages of the total (the default option), of the rows and of the
columns. To calculate on columns you must specify
prop.table(table(...), 2)
. If you wanted the percentage
over the rows, the code would be prop.table(table(...), 1)
.
This table can be saved as a dataframe with the
as.data.frame
command in a new object “t1”.
t1 = as.data.frame(round(prop.table(table(Urban = lapop18$urban, User = lapop18$wa_user), 2)*100, 1))
t1
The rows corresponding to “Urban” in this table reproduce the data in
Table 3.2: 62.1% are urban among non-Whatsapp users and 76.7% are urban
among users.
Now the table will be presented between Facebook users (variable
“fb_user”) and men (variable “men”), but presenting only the percentages
used in the table and now using the code style of the Tidyverse, using
the “pipe” operator. The first thing is to define the variable “fb_user”
as a factor and label it. Then, the subset
command is used
to filter the missing cases on the “fb_user” variable. Then the results
are requested to be grouped by categories of the variable “fb_user”.
With the summarise
command, the average of the “man”
variable is saved in the “man” column, with the mean
command that includes the specification na.rm=T
so as not
to include missing values in the calculation. In this case, it takes
advantage of the fact that the variable “men” is a dummy variable, in
such a way that the average corresponds to the proportion of men.
lapop18$fb_user = as.factor(lapop18$fb_user)
levels(lapop18$fb_user) = c("No user", "User")
library(tidyverse)
table1 = subset(lapop18, !is.na(fb_user)) %>% #To not include the NA group of Facebook users
group_by(fb_user) %>%
dplyr::summarise(Men=mean(men, na.rm=T)*100) #na.rm=T is included because man has NAs
table1
These are the percentages for Facebook users, in the row of the Male
variable in Table 3.2. That is, among non-users, 49.9% are men and among
users this percentage is 49.7%. So far we have replicated some results
from Table 3.2. The other data can continue to be reconstructed through
combinations of the social network user variables and the
sociodemographic variables.
Two-Variable Bar Chart
The cross between WhatsApp users and the urban variable can also be
seen in a grouped bar graph. The first thing we will do is define the
variable “wa_user” as a factor and label it. Then, it is required to
create a table with the grouped data. The “t1” dataframe created earlier
can be used, but here we will again use the “pipe” operator to recreate
the data.
For this, it is grouped both by use of WhatsApp and by urban/rural,
that is, in four combinations. In each subgroup the n is calculated.
Since the % have to be calculated for each group of “wa_user”, it is
grouped again and the % of each subgroup is calculated, in such a way
that the percentages add up to 100% in each subgroup of “wa_user”.
lapop18$wa_user = as.factor(lapop18$wa_user)
levels(lapop18$wa_user) = c("No user", "User")
face <- subset(lapop18, !is.na(wa_user)) %>% #!is.na is used so that NAs are not reported in the table
group_by(wa_user, urban) %>% #groups are configured
dplyr::count() %>% #n is calculated
group_by(wa_user) %>% #It is grouped by WhatsApp user
dplyr::mutate(percentage = round(n/sum(n), 3)*100) #The percentage is calculated in each WhatsApp group
face
The data in this new table is exactly the same as in “t1”. With the
table ready, use the ggplot
command, defining “wa_user” to
be the variable on the X axis, the Y axis to be the percentage, and the
subgroups to be formed by the variable “urban” with the
fill
specification. . The dodge
specification
is used in geom_bar
to have the bars separated by each
group.
ggplot(data=face, aes(x=wa_user, y=percentage, fill=urban, ymax=100))+
geom_bar(position="dodge", stat="identity")+
geom_text(aes(label=paste(percentage, "%", sep="")),
position=position_dodge(width=0.9), vjust=-0.25)+
ylab("Percentage")+
xlab("Whatsapp user")
If we wanted to make the graph with stacked bars, we would have to
change the position="stack"
specification in
geom_bar
and the position=position_stack()
specification in geom_text
.
ggplot(data=face, aes(x=wa_user, y=percentage, fill=urban, ymax=100))+
geom_bar(position="stack", stat="identity")+
geom_text(aes(label=paste(percentage, "%", sep="")),
position=position_stack(), vjust=2.5)+
ylab("Percentage")+
xlab("Whatsapp user")
In both cases, the light blue bars indicate the percentages reported
in table 3.2 of the report and correspond to the proportion of people
living in urban areas between users and non-users.
Summary
In this document we have worked with ordinal categorical variables,
such as the frequency of use of social networks. The use of contingency
tables of two categorical variables and the creation of grouped bar
graphs for 2 variables have also been introduced.
Calculations including survey weights
Example using the 2021 dataset
With the data of the 2021 wave of the AmericasBarometer, we have
calculated the percentages of the variable that gauges whether the votes
are counted correctly. The figure we have produced is for the total
sample; it means, for all the countries. The Figure 2.5 of the report
The Pulse of Democracy presents results for each country.
If we calculate percentages with the commands table
and
prop.table
, we would get different results from those show
in the Figure. For example, Nicaragua, country 5, display that 26% of
citizens in this country indicate that votes are always counted
correctly, 49% indicate that votes are sometimes counted correctly, and
24.4% that voter are never counted correctly. However, the figure shows
that 29% indicate that votes are never counted correctly in Nicaragua,
45% that sometimes, and 25% that always. These percentages do not match
those produced with these commands.
round(prop.table(table(lapop21$pais, lapop21$countfair1r), 1), 3)*100
##
## Always Sometimes Never
## 1
## 2
## 3
## 4
## 5 26.2 49.4 24.4
## 6 52.3 40.2 7.5
## 7 27.6 57.1 15.4
## 8 18.1 50.4 31.5
## 9 21.5 59.1 19.4
## 10 24.5 59.2 16.3
## 11 25.1 61.1 13.8
## 12 25.9 48.3 25.8
## 13 64.1 30.1 5.8
## 14 80.0 16.9 3.0
## 15 48.1 35.7 16.1
## 17 31.5 51.0 17.5
## 21 25.2 60.1 14.7
## 22
## 23 17.9 67.9 14.2
## 24 17.0 65.1 17.8
This difference is due to the fact that commands table
and prop.table
do not include survey weights in
calculations. More information about these differences are found here.
To replicate the results of Figure 2.5, there are some options. The
first option is using an specialized librery called
survey
.
To be allowed to use this library, we should first prepare the
dataset, dropping missing values of variables that define the survey
design. An additional step is transforming the variables in the
dataframe. When we import the dataset, the system reads these variables
as “haven_labelled” type, that is, they ma.intain labels of variables,
with which we may produce a codebook. This may be useful in other
ocassions, but it generates problems with the library
survey
. For this, we transform the variables to other type
with the command sapply
.
Once prepared the dataset, we activate the library and declare the
survey design. In the last section, we also use this library to
calculate the results with the survey weights in the round 2018.
Contrary to this code, the 2021 round of the AmericasBarometer uses
phone interviews, and not face to face. For this reason, the primary
unit of sampling is the individual, and so it is defined in the variable
“upm”. The variable that defines strata is “strata” (and not
“estratopri”, as in the 2018 round). The weighting variable is still
“weight1500”.
With this information, we save the design in an object
“design21”.
library(survey)
design21 = svydesign(ids = ~upm, strata = ~strata, weights = ~weight1500, nest=TRUE, data=lapop21)
The library survey
includes native commands to perform
multiple operations including survey weights. One is this commands is
svytable
that allows to make a crosstable between the
variable “countfair1” and “pais”, specifying the design. This command
returns the weighting absolute frequencies. For this reason, we have to
nest this code in the command prop.table
to calculate the
percentages from weighting absolute frequencies. We also use the
commands round
to round percentage, and the command
as.data.table
to save this table in an object
“votexcountry” as a dataframe that allows to use this data with
ggplot
.
votexcountry = as.data.frame(round(prop.table(svytable(~pais+countfair1r, design=design21), 1)*100, 0))
votexcountry$country = country
votexcountry
ggplot(data=votexcountry, aes(fill=countfair1r, x=Freq, y=country))+
geom_bar(stat="identity", width=0.3)+
geom_text(aes(label=paste(Freq, "%", sep="")), color="white",
position=position_stack(vjust=0.5), size=3)+
labs(x="Percentage", y="Country", fill="Votes are counted correctly",
caption="AmericasBarometer by LAPOP, 2021")
This figure reproduces exactly the results shown in the Figure 2.5 of
the report, even in a different order.
Example using the 2018/19 dataset
The small difference between the percentages shown in Figure 3.3 and
those shown in the “Describing and plotting variables” section may be
due to the fact that the survey weight is not included in all the
previous tables and graphs. If included, using the variable
“weight1500”, the percentages shown in the report would be replicated.
For example, to use WhatsApp, you can use the command freq
from the library descr
, which allows you to include a
weighting variable.
This table can be saved to a dataframe, from which the rows and
columns that are not required can be removed, and the remaining columns
can be renamed.
table2 = as.data.frame(descr::freq(lapop18$smedia8r, lapop18$weight1500, plot=F))
table2 = table2[-c(5,6), -2]
colnames(table2) <- c("frec", "per")
table2$lab <- rownames(table2)
table2
With this new dataframe, we can replicate the figure for Whatsapp ,
with the data weighted, using the ggplot
code.
ggplot(data=table2, aes(x=2, y=per, fill=lab))+
geom_bar(stat="identity")+
geom_text(aes(label=paste(round(per, 1), "%", sep="")), color="white",
position=position_stack(vjust=0.5), size=3)+
coord_polar("y")+
theme_void()+
scale_fill_discrete(name="Frequency of use of Facebook")+
labs(title="Frequency with which you view content on Facebook",
caption="AmericasBarometer by LAPOP, 2018/19")+
xlim(0.5, 2.5)
In addition to the freq
command, you can also use the
library survey
and the native command
svytable
.
library(survey)
design18 = svydesign(ids = ~upm, strata = ~estratopri, weights = ~weight1500, nest=TRUE, data=lapop18)
The results obtained are the same as with the previous method and
those presented in the report. These results can also be saved in a
“dataframe” to make the graph.
prop.table(svytable(~smedia8r, design=design18))*100
## smedia8r
## Daily A few times a week A few times a month A few times a year
## 81.6626475 15.2056787 2.8473540 0.2843197
The section “Cross with variables” presents the data of users of
social networks by country. To build the table considering the design
effect, you can also use the native svytable
command that
allows you to compute a bivariate table. In the same way as in the
unweighted case, the partial tables of each social network are stored in
list-type objects, which are put together as a “dataframe” and edited to
present only the data of the users of each social network. for
country.
fbpais_2 = round(prop.table(svytable(~pais+fb_user, design=design18), 1), 3)*100
twpais_2 = round(prop.table(svytable(~pais+tw_user, design=design18), 1), 3)*100
wapais_2 = round(prop.table(svytable(~pais+wa_user, design=design18), 1), 3)*100
tablecountry_2 = as.data.frame(cbind(fbpais_2, twpais_2, wapais_2))
tablecountry_2 = tablecountry_2[, c(-1,-3,-5)]
varnames = c("Use Facebook", "Use Twitter", "Use Whatsapp")
colnames(tablecountry_2) = varnames
tablecountry_2
Finally, the section “Crosstables with sociodemographic variables”
reproduces the results of Table 3.2 of the report. In the same way as in
the previous case, the native command svytable
can be used
to perform the cross between the social network usage variables and the
urban variable. The results of the Urban row in each social network
would correspond to the first row of results in Table 3.2.
round(prop.table(svytable(~urban+wa_user, design=design18), 2), 3)*100
## wa_user
## urban No user User
## Rural 38.0 23.3
## Urban 62.0 76.7
round(prop.table(svytable(~urban+fb_user, design=design18), 2), 3)*100
## fb_user
## urban No user User
## Rural 35.6 23.0
## Urban 64.4 77.0
round(prop.table(svytable(~urban+tw_user, design=design18), 2), 3)*100
## tw_user
## urban 0 1
## Rural 29.7 15.3
## Urban 70.3 84.7
In this way, frequency distribution tables and bivariate (or
contingency) tables can be calculated including the design effect or the
expansion factor.
LS0tCnRpdGxlOiAiRGVzY3JpcHRpdmUgc3RhdGlzdGljcyB1c2luZyB0aGUgQW1lcmljYXNCYXJvbWV0ZXIgKDIpIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlCiAgICB0b2NfZGVwdGg6IDEKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIHRoZW1lOiBmbGF0bHkKICAgIGRmX3ByaW50OiBwYWdlZAogICAgc2VsZl9jb250YWluZWQ6IG5vCiAgICBrZWVwX21kOiB5ZXMKICAgICNjb2RlX2ZvbGRpbmc6IGhpZGUKZWRpdG9yX29wdGlvbnM6IAogIG1hcmtkb3duOiAKICAgIHdyYXA6IHNlbnRlbmNlCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0UsIGNhY2hlPVRSVUUpCmBgYAoKYGBge2NzcyBjb2xvciwgZWNobz1GQUxTRX0KLmNvbHVtbnMge2Rpc3BsYXk6IGZsZXg7fQpoMSB7Y29sb3I6ICMzMzY2Q0M7fQpgYGAKCiMgSW50cm9kdWN0aW9uCgpJbiB0aGlzIHNlY3Rpb24gd2Ugd2lsbCBjb250aW51ZSB0byB1c2UgdGhlIHJlZ2lvbmFsIHJlcG9ydCAiVGhlIFB1bHNlIG9mIERlbW9jcmFjeSIsIGF2YWlsYWJsZSBbaGVyZV0oaHR0cHM6Ly93d3cudmFuZGVyYmlsdC5lZHUvbGFwb3AvYWIyMDE4LzIwMTgtMTlfQW1lcmljYXNCYXJvbWV0ZXJfUmVnaW9uYWxfUmVwb3J0X1NwYW5pc2hfV18wMy4yNy4yMC5wZGYpLCB3aGVyZSB0aGUgbWFpbiBmaW5kaW5ncyBvZiB0aGUgMjAxOC8xOSByb3VuZCBvZiB0aGUgQW1lcmljYXNCYXJvbWV0ZXIgYXJlIHByZXNlbnRlZC4KT25lIG9mIHRoZSBzZWN0aW9ucyBvZiB0aGlzIHJlcG9ydCByZXBvcnRzIGRhdGEgb24gc29jaWFsIG5ldHdvcmtzIGFuZCBwb2xpdGljYWwgYXR0aXR1ZGVzLgpUaGlzIHNlY3Rpb24gcHJlc2VudHMgZGF0YSBvbiB0aGUgdXNlIG9mIHRoZSBJbnRlcm5ldCBhbmQgdGhlIHVzZSBvZiBzb2NpYWwgbmV0d29ya3MsIGluIGdlbmVyYWwgYW5kIGJ5IGNvdW50cnkuCkluIHRoaXMgY2FzZSB3ZSBhcmUgZ29pbmcgdG8gd29yayB3aXRoIHRoZSBmcmVxdWVuY3kgb2YgdXNlIG9mIHNvY2lhbCBuZXR3b3Jrcy4KSW4gdGhpcyBzZWN0aW9uIHdlIGFyZSBnb2luZyB0byBkZXNjcmlwdGl2ZWx5IGFuYWx5emUgdGhlc2UgdmFyaWFibGVzIG9uIHRoZSBmcmVxdWVuY3kgb2YgdXNlIG9mIHNvY2lhbCBuZXR3b3Jrcywgb3JkaW5hbCB2YXJpYWJsZXMgKG9yIGZhY3RvciB2YXJpYWJsZXMsIGluIHRoZSBsYW5ndWFnZSBvZiBSKS4KCiMgQWJvdXQgdGhlIGRhdGFzZXQKClRoZSBkYXRhIHdlIGFyZSBnb2luZyB0byB1c2Ugc2hvdWxkIGJlIGNpdGVkIGFzIGZvbGxvd3M6IFNvdXJjZTogQW1lcmljYXNCYXJvbWV0ZXIgYnkgdGhlIExhdGluIEFtZXJpY2FuIFB1YmxpYyBPcGluaW9uIFByb2plY3QgKExBUE9QKSwgd3d3dy5MYXBvcFN1cnZleXMub3JnLgpUaGlzIGRvY3VtZW50IHJlbG9hZHMgYSB0cmltbWVkIGRhdGFiYXNlLgpUbyByZXByb2R1Y2UgdGhlIHJlc3VsdHMgc2hvd24gaW4gdGhpcyBzZWN0aW9uLCB5b3UgbXVzdCBjbGVhbiB0aGUgRW52aXJvbm1lbnQuCgpUaGlzIGRhdGFiYXNlIGlzIGhvc3RlZCBpbiB0aGUgIm1hdGVyaWFsc19lZHUiIHJlcG9zaXRvcnkgb2YgdGhlIExBUE9QIGFjY291bnQgb24gR2l0SHViLgpVc2luZyB0aGUgYHJpb2AgbGlicmFyeSBhbmQgdGhlIGBpbXBvcnRgIGNvbW1hbmQsIHdlIGNhbiBpbXBvcnQgdGhpcyBkYXRhYmFzZSBmcm9tIHRoaXMgcmVwb3NpdG9yeS4KSW4gYWRkaXRpb24sIHRoZSBkYXRhIGZyb20gY291bnRyaWVzIHdpdGggY29kZXMgbGVzcyB0aGFuIG9yIGVxdWFsIHRvIDM1IGFyZSBzZWxlY3RlZCwgdGhhdCBpcywgdGhlIG9ic2VydmF0aW9ucyBvZiB0aGUgVW5pdGVkIFN0YXRlcyBhbmQgQ2FuYWRhIGFyZSBlbGltaW5hdGVkLgoKYGBge3IgYmFzZTE4fQpsaWJyYXJ5KHJpbykKbGFwb3AxOCA9IGltcG9ydCgiaHR0cHM6Ly9yYXcuZ2l0aHViLmNvbS9sYXBvcC1jZW50cmFsL21hdGVyaWFsc19lZHUvbWFpbi9MQVBPUF9BQl9NZXJnZV8yMDE4X3YxLjAuc2F2IikKbGFwb3AxOCA9IHN1YnNldChsYXBvcDE4LCBwYWlzPD0zNSkKYGBgCgpXZSBhbHNvIGxvYWQgZGF0YSBmcm9tIHRoZSAyMDIxIHJvdW5kLgoKYGBge3IgYmFzZTIxfQpsYXBvcDIxID0gaW1wb3J0KCJodHRwczovL3Jhdy5naXRodWIuY29tL2xhcG9wLWNlbnRyYWwvbWF0ZXJpYWxzX2VkdS9tYWluL2xhcG9wMjEuUkRhdGEiKQpsYXBvcDIxID0gc3Vic2V0KGxhcG9wMjEsIHBhaXM8PTM1KQpgYGAKCiMgRGVzY3JpYmluZyBhbmQgcGxvdHRpbmcgdmFyaWFibGVzCgpJbiB0aGUgc2VjdGlvbiBvbiBkZXNjcmlwdGl2ZSBzdGF0aXN0aWNzLCB3aGljaCBjYW4gYmUgc2VlbiBbaGVyZV0oaHR0cHM6Ly9hcnR1cm9tYWxkb25hZG8uZ2l0aHViLmlvL0Jhcm9tZXRyb0VkdV9XZWJfRW5nL0Rlc2NyaXB0aXZlcy5odG1sKSwgd2Ugd29ya2VkIHdpdGggbm9taW5hbCB2YXJpYWJsZXMsIHdpdGggZGljaG90b21vdXMgcmVzcG9uc2Ugb3B0aW9ucyAoWWVzL05vKS4KSW4gdGhpcyBkb2N1bWVudCB3ZSB3aWxsIHdvcmsgd2l0aCBwb2xpdG9taWMgb3JkaW5hbCB2YXJpYWJsZXMuCgojIFZvdGVzIGFyZSBjb3JyZWN0bHkgY291bnRlZAoKSW4gdGhpcyBzZWN0aW9uLCB3ZSB1c2UgdGhlIHZhcmlhYmxlIENPVU5URkFJUjEuClZvdGVzIGFyZSBjb3VudGVkIGNvcnJlY3RseSBhbmQgZmFpcmx5LgpXb3VsZCB5b3Ugc2F5IGl0IGhhcHBlbnMgYWx3YXlzLCBzb21ldGltZXMgb3IgbmV2ZXI/CkZpZ3VyZSAyLjUgb2YgdGhlIHJlcG9ydCBUaGUgUHVsc2Ugb2YgRGVtb2NyYWN5LCBhdmFpbGFibGUgW2hlcmVdKGh0dHBzOi8vd3d3LnZhbmRlcmJpbHQuZWR1L2xhcG9wL2FiMjAyMS8yMDIxX0xBUE9QX0FtZXJpY2FzQmFyb21ldGVyXzIwMjFfUHVsc2Vfb2ZfRGVtb2NyYWN5X1NQQS5wZGYpLCBzaG93cyByZXN1bHRzIG9mIHRoaXMgdmFyaWFibGUgYnkgY291bnRyeS4KCiFbXShGaWd1cmUyLjUucG5nKXt3aWR0aD0iNTQ0In0KCkluIHRoZSBzYW1lIHdheSBhcyB3aXRoIG5vbWluYWwgdmFyaWFibGVzLCB0aGVzZSBvcmRpbmFsIHZhcmlhYmxlcyBoYXZlIHRvIGJlIGRlY2xhcmVkIGFzICJmYWN0b3IiIGluIG5ldyB2YXJpYWJsZXMuCgpgYGB7cn0KbGlicmFyeShoYXZlbikKbGFwb3AyMSRjb3VudGZhaXIxciA9IGFzLmZhY3RvcihsYXBvcDIxJGNvdW50ZmFpcjEpCmBgYAoKVGhlbiwgdGhlc2UgdmFyaWFibGVzIGhhdmUgdG8gYmUgbGFiZWxsZWQuCldlIGNhbiBjcmVhdGUgYSBiYXNpYyBkZXNjcmlwdGl2ZSB0YWJsZSB3aXRoIHRoZSBjb21tYW5kIGB0YWJsZWAuCgpgYGB7cn0KbGV2ZWxzKGxhcG9wMjEkY291bnRmYWlyMXIpID0gYygiQWx3YXlzIiwgIlNvbWV0aW1lcyIsICJOZXZlciIpCnRhYmxlKGxhcG9wMjEkY291bnRmYWlyMXIpCmBgYAoKVG8gY2FsY3VsYXRlIHRhYmxlcyB3aXRoIHBlcmNlbnRhZ2VzLCByb3VuZGVkIHRvIG9uZSBkZWNpbWFsIHBsYWNlLCB3ZSB1c2UgYHByb3AudGFibGVgIGFuZCBgcm91bmRgLgpBZ2FpbiwgdGhlc2UgcGVyY2VudGFnZXMgYXJlIG5vdCB0aGUgc2FtZSBhcyB0aG9zZSBwcmVzZW50ZWQgaW4gdGhlIHJlcG9ydCBiZWNhdXNlIHRoZXNlIGNhbGN1bGF0aW9ucyBkbyBub3QgaW5jbHVkZSBmYWN0b3Igd2VpZ2h0cy4KCmBgYHtyfQpyb3VuZChwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMjEkY291bnRmYWlyMXIpKSwgMykqMTAwCmBgYAoKQXMgd2UgbWVudGlvbiBpbiB0aGUgcHJldmlvdXMgc2VjdGlvbiwgd2UgY2FuIHBsb3QgdGhpcyB2YXJpYWJsZSB1c2luZyB0aGUgY29tbWFuZCBgYmFycGxvdGAuCgpgYGB7cn0KYmFycGxvdChwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMjEkY291bnRmYWlyMXIpKSoxMDApCmBgYAoKT3RoZXIgb3B0aW9uIGlzIGNyZWF0ZSB0aGlzIHBsb3QgdXNpbmcgdGhlIGxpYnJhcnkgYGdncGxvdGAuCk9uZSBvcHRpb24gaXMgd29ya2luZyB3aXRoIHRoZSBkYXRhc2V0IGZyb20gc2NyYXRjaC4KVGhlIGZvbGxvd2luZyBjb2RlLCBob3dldmVyLCBzaG93cyBhIGJpZyBiYXIgd2l0aCB0aGUgcGVyY2VudGFnZSBvZiBtaXNzaW5nIHZhbHVlcy4KVGhpcyBpcyBiZWNhdXNlIHRoaXMgcXVlc3Rpb24gd2FzIGFwcGxpZWQgdG8gYSBzcGxpdCBzYW1wbGUuClRoZSBkYXRhc2V0IHJlY29yZHMgTkEgdG8gdGhlIG90aGVyIGhhbGYgb2YgdGhvc2Ugd2hvIGRvIG5vdCBhbnN3ZXIgdGhpcyBxdWVzdGlvbi4KCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCmdncGxvdChkYXRhPWxhcG9wMjEsIGFlcyh4PWNvdW50ZmFpcjFyKSkrCiAgZ2VvbV9iYXIoYWVzKHk9Li5wcm9wLi4qMTAwLCBncm91cD0xKSwgd2lkdGg9MC41KSsKICBsYWJzKHg9IlZvdGVzIGFyZSBjb3VudGVkIGNvcnJlY3RseSIsIHk9IlBlcmNlbnRhZ2UiLCAKICAgICAgIGNhcHRpb249IkFtZXJpY2FzQmFyb21ldGVyIGJ5IExBUE9QLCAyMDIxIikrCiAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLCAxMDApKQpgYGAKClRvIHByZXZlbnQgdGhhdCB0aGUgZmlndXJlIHNob3dzIGEgYmFyIGZvciBOQXMsIHRoZXNlIG9ic2VydmF0aW9ucyBzaG91bGQgYmUgZmlsdGVyZWQgYmVmb3JlIHByb2R1Y2luZyB0aGUgZ3JhcGguCkluIHRoZSBzYW1lIG1hbm5lciBhcyB0aGUgcHJldmlvdXMgc2VjdGlvbiwgd2UgY2FuIGZpbHRlciB0aGUgTkFzIGZvciB0aGUgdmFyaWFibGUgImNvdW50ZmFpcjEiIHdpdGggdGhlIGNvbW1hbmQgYHN1YnNldGAgYW5kIHRoZSBzcGVjaWZpY2F0aW9uIGAhaXMubmFgLgoKYGBge3J9CmdncGxvdChkYXRhPXN1YnNldChsYXBvcDIxLCAhaXMubmEoY291bnRmYWlyMXIpKSwgYWVzKHg9Y291bnRmYWlyMXIpKSsKICBnZW9tX2JhcihhZXMoeT0uLnByb3AuLioxMDAsIGdyb3VwPTEpLCB3aWR0aD0wLjUpKwogIGxhYnMoeD0iVm90ZXMgYXJlIGNvdW50ZWQgY29ycmVjdGx5IiwgeT0iUGVyY2VudGFnZSIsIAogICAgICAgY2FwdGlvbj0iQW1lcmljYXNCYXJvbWV0ZXIgYnkgTEFQT1AsIDIwMjEiKSsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsIDYwKSkKYGBgCgpPdGhlciBvcHRpb24sIHRoYXQgc2ltcGxpZnkgdGhlIGNvZGUsIGlzIHRvIGNyZWF0ZSBhIGZyZXF1ZW5jeSB0YWJsZSBvZiB0aGlzIHZhcmlhYmxlIHdpdGggdGhlIGNvbW1hbmQgYHRhYmxlYCBhbmQgYHByb3AudGFibGVgLgpUaGlzIHRhYmxlIGlzIHJvdW5kZWQgdG8gb25lIGRlY2ltYWwgcGxhY2Ugd2l0aCB0aGUgY29tbWFuZCBgcm91bmRgIGFuZCBpcyBzYXZlZCBhcyBhIGRhdGFmcmFtZSB3aXRoIHRoZSBjb21tYW5kIGBhcy5kYXRhLmZyYW1lYCBpbiBhbiBvYmplY3QgImNvdW50Ii4KVGhpcyB0YWJsZSByZWNvcmRzIHR3byBjb2x1bW5zLCB0aGUgZmlyc3QgaXMgY2FsbGVkICJWYXIxIiB3aXRoIHRoZSBsYWJlbHMgb2YgdGhlIHZhcmlhYmxlcyBhbmQgdGhlIHNlY29uZCBpcyBjYWxsZWQgIkZyZXEiIGFuZCBzdG9yZXMgdGhlIHBlcmNlbnRhZ2VzLgoKYGBge3J9CmNvdW50ID0gYXMuZGF0YS5mcmFtZShyb3VuZChwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMjEkY291bnRmYWlyMXIpKSwgMykqMTAwKQpjb3VudApgYGAKCldlIGNhbiB1c2UgdGhpcyB0YWJsZSAiY291bnQiIHRvIHByb2R1Y2UgYSBiYXIgcGxvdCB3aXRoIHRoZSBjb21tYW5kIGBnZ3Bsb3RgLgpUaGUgc3BlY2lmaWNhdGlvbiBgYWVzYCBkZWZpbmVzIHRoYXQgdGhlIHZhbHVlcyBvZiB0aGUgY29sdW1uICJWYXIxIiBhcmUgcHJlc2VudGVkIGluIHRoZSBYIGF4aXMgYW5kIHRoZSB2YWx1ZXMgb2YgdGhlIGNvbHVtbiAiRnJlcSIgYXJlIHNob3duIGluIHRoZSBZIGF4aXMuCldlIGRlZmluZSBhIHNpbXBsZSBiYXIgcGxvdCwgdXNpbmcgdGhlIGNvbW1hbmQgYGdlb21fYmFyKCApYCwgd2hlcmUgaW50ZXJuYWxseSB3ZSBkZWZpbmUgdGhlIHdpZHRoIG9mIGJhcnMuCldlIGRlZmluZSBsYWJlbHMgb2YgYXhpcyBhbmQgdGhlICJjYXB0aW9uIiB3aXRoIHRoZSBzcGVjaWZpY2F0aW9uIGBsYWJzYC4KCmBgYHtyfQpnZ3Bsb3QoZGF0YT1jb3VudCwgYWVzKHg9VmFyMSwgeT1GcmVxKSkrCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCB3aWR0aD0wLjUpKwogIGdlb21fdGV4dChhZXMobGFiZWw9cGFzdGUoRnJlcSwgIiUiLCBzZXA9IiIpKSwgY29sb3I9IndoaXRlIiwgCiAgICAgICAgICAgIHBvc2l0aW9uPXBvc2l0aW9uX3N0YWNrKHZqdXN0PTAuNSksIHNpemU9MykrCiAgbGFicyh4PSJWb3RlcyBhcmUgY291bnRlZCBjb3JyZWN0bHkiLCB5PSJQZXJjZW50YWdlIiwgCiAgICAgICBjYXB0aW9uPSJBbWVyaWNhc0Jhcm9tZXRlciBieSBMQVBPUCwgMjAyMSIpCmBgYAoKRmlndXJlIDIuNSBzaG93cyBhIHN0YWNrZWQgYmFyIHdpdGggaW5mb3JtYXRpb24gZm9yIGVhY2ggY291bnRyeS4KRmlyc3QsIHdlIHByZXNlbnQgYSBzdGFja2VkIGJhciBwbG90IHVzaW5nIGFsbCBvYnNlcnZhdGlvbiBvZiB0aGUgMjAyMSByb3VuZCBvZiB0aGUgQW1lcmljYXNCYXJvbWV0ZXIsIHRoYXQgaXMgaW5jbHVkaW5nIGFsbCBjb3VudHJpZXMuClRvIHByb2R1Y2UgYSBzdGFja2VkIGhvcml6b250YWwgYmFyLCB3ZSB1c2UgdGhlIHZhcmlhYmxlICJGcmVxIiwgbm93IGluIHRoZSBYIGF4aXMuCldlIHVzZSB0aGUgb3B0aW9uIGBmaWxsYCB0byBkaXZpdmUgdGhpcyBiYXIgYnkgdmFsdWVzIG9mIHRoZSB2YXJpYWJsZSAiVmFyMSIuCkJlY2F1c2UgWSBheGlzIGRvZXMgbm90IHNob3cgYSB2YXJpYWJsZSwgd2UgZGVmaW5lIGFzIGAiICJgLgpJbiB0aGUgc2FtZSB3YXkgYXMgd2UgY2hhbmdlIHRoZSB2YXJpYWJsZXMgaW4gdGhlIGF4aXMsIHdlIGNhbiBhbHNvIGNoYW5nZSB0aGUgbGFiZWxzIGluIGBsYWJzYC4KSW4gdGhpcyBzcGVjaWZpY2F0aW9uIHdlIGNoYW5nZSB0aGUgbGFiZWwgb2YgdGhlIGxlZ2VuZCB3aXRoIGBmaWxsYC4KCmBgYHtyfQpnZ3Bsb3QoZGF0YT1jb3VudCwgYWVzKHg9RnJlcSwgeT0iIiwgZmlsbD1WYXIxKSkrCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCB3aWR0aD0wLjMpKwogIGdlb21fdGV4dChhZXMobGFiZWw9cGFzdGUoRnJlcSwgIiUiLCBzZXA9IiIpKSwgY29sb3I9IndoaXRlIiwgCiAgICAgICAgICAgIHBvc2l0aW9uPXBvc2l0aW9uX3N0YWNrKHZqdXN0PTAuNSksIHNpemU9MykrCiAgbGFicyh4PSJQZXJjZW50YWdlIiwgeT0iIiwgZmlsbD0iVm90ZXMgYXJlIGNvdW50ZWQgY29ycmVjdGx5IiwgIAogICAgICAgY2FwdGlvbj0iQW1lcmljYXNCYXJvbWV0ZXIgYnkgTEFQT1AsIDIwMjEiKQpgYGAKClRvIHJlcGxpY2F0ZSB0aGUgY29tcGFyYXRpdmUgZ3JhcGggYnkgY291bnRyeSwgd2UgaGF2ZSB0byBjcmVhdGUgYSBjb250aW5nZW5jeSB0YWJsZSBiZXR3ZWVuIHZhcmlhYmxlICJjb3VudGZhaXIxIiBhbmQgInBhaXMiLgpUaGlzIGNyb3NzdGFibGUgaXMgc2F2ZWQgaW4gYW4gb2JqZWN0ICJjb3VudF9jb3VudHJ5Ii4KV2Ugc2hvdWxkIG5vdGUgdGhhdCB0aGUgZGF0YWZyYW1lIGNyZWF0ZXMgYSByb3cgZm9yIGVhY2ggdmFsdWUgb2YgImNvdW50ZmFpciIgaW4gZWFjaCBjb3VudHJ5LgpJbiB0aGlzIHdheSwgd2UgaGF2ZSAzIG9wdGlvbiB4IDIwIGNvdW50cmllcyA9IDYwIHJvd3MuCgpgYGB7cn0KY291bnRfY291bnRyeSA9IGFzLmRhdGEuZnJhbWUocm91bmQocHJvcC50YWJsZSh0YWJsZShsYXBvcDIxJHBhaXMsIGxhcG9wMjEkY291bnRmYWlyMXIpLCAxKSwgMykqMTAwKQpjb3VudF9jb3VudHJ5CmBgYAoKV2UgY2FsY3VsYXRlIGRhdGEgZm9yIGVhY2ggdmFsdWUgb2YgdGhlIHZhcmlhYmxlICJwYWlzIiBpbiB0aGlzIHRhYmxlLCBldmVuIHdoZW4gdGhlcmUgaXMgbm8gZGF0YSBpbiB0aGUgdmFyaWFibGUgImNvdW50ZmFpciIgYmVjYXVzZSB0aGlzIHF1ZXN0aW9uIHdhcyBub3QgZmllbGRlZCBpbiBhIGNvdW50cnkuCkZvciB0aGlzIHJlYXNvbiwgd2UgaGF2ZSB0byBkcm9wIHJvd3Mgb2YgY291bnRyaWVzIHdoZXJlIHdlIGNvdWxkIG5vdCByZWNvcmQgaW5mb3JtYXRpb24uCldlIGNhbiBkbyB0aGlzIHdpdGggdGhlIHNwZWNpZmljYXRpb24gYFstYyhyb3dzKSwgXWAuCkFmdGVyIHRoYXQsIHdlIGNhbiBjcmVhdGUgYSB2ZWN0b3Igd2l0aCB0aGUgbmFtZXMgb2YgY291bnRyaWVzLgpUaGlzIGxpc3Qgb2YgY291bnRyaWVzIGlzIHJlcGVhdGVkIHRocmVlIHRpbWVzICgxNSByZW1haW5pbmcgY291bnRyaWVzIHggMyBvcHRpb25zKS4KVGhpcyB2ZWN0b3IgaXMgYWRkZWQgdG8gdGhlIGRhdGFmcmFtZSBpbiBhIGNvbHVtbiAiY291bnRyeSIuCgpgYGB7cn0KY291bnRfY291bnRyeSA9IGNvdW50X2NvdW50cnlbLWMoMTo0LDE4LDIxOjI0LDM4LDQxOjQ0LDU4KSxdCmNvdW50cnkgPSBjKCJOaWNhcmFndWEiLCAiQ29zdGEgUmljYSIsICJQYW5hbWEiLCAiQ29sb21iaWEiLCAiRWN1YWRvciIsICJCb2xpdmlhIiwgIlBlcnUiLAogICAgICAgICJQYXJhZ3VheSIsICJDaGlsZSIsICJVcnVndWF5IiwgIkJyYXppbCIsICJBcmdlbnRpbmEiLCAiRG9tLiBSZXAuIiwgIkphbWFpY2EiLCAiR3V5YW5hIiwKICAgICAgICAiTmljYXJhZ3VhIiwgIkNvc3RhIFJpY2EiLCAiUGFuYW1hIiwgIkNvbG9tYmlhIiwgIkVjdWFkb3IiLCAiQm9saXZpYSIsICJQZXJ1IiwKICAgICAgICAiUGFyYWd1YXkiLCAiQ2hpbGUiLCAiVXJ1Z3VheSIsICJCcmF6aWwiLCAiQXJnZW50aW5hIiwgIkRvbS4gUmVwLiIsICJKYW1haWNhIiwgIkd1eWFuYSIsCiAgICAgICAgIk5pY2FyYWd1YSIsICJDb3N0YSBSaWNhIiwgIlBhbmFtYSIsICJDb2xvbWJpYSIsICJFY3VhZG9yIiwgIkJvbGl2aWEiLCAiUGVydSIsCiAgICAgICAgIlBhcmFndWF5IiwgIkNoaWxlIiwgIlVydWd1YXkiLCAiQnJhemlsIiwgIkFyZ2VudGluYSIsICJEb20uIFJlcC4iLCJKYW1haWNhIiwgIkd1eWFuYSIpCmNvdW50X2NvdW50cnkkY291bnRyeSA9IGNvdW50cnkKY291bnRfY291bnRyeQpgYGAKCldpdGggdGhpcyBkYXRhZnJhbWUgImNvdW50X2NvdW50cnkiLCB3ZSBoYXZlIHRoZSBlbGVtZW50cyB0byByZXBsaWNhdGUgdGhlIGZpZ3VyZSB3aXRoIHN0YWNrZWQgYmFycyBieSBjb3VudHJ5LgpJbiB0aGUgc3BlY2lmaWNhdGlvbiBgYWVzYCwgd2UgZGVmaW5lIHRoYXQgcGVyY2VudGFnZXMgYXJlIGluIFggYXhpcywgY291bnRyaWVzIGluIFkgYXhpcyBhbmQgdGhhdCBlYWNoIGJhciBpcyBkaXZpZGVkIGJ5IGNvbHVtbiAiVmFyMiIuCgpgYGB7cn0KZ2dwbG90KGRhdGE9Y291bnRfY291bnRyeSwgYWVzKHg9RnJlcSwgeT1jb3VudHJ5LCBmaWxsPVZhcjIpKSsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHdpZHRoPTAuMykrCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1wYXN0ZShGcmVxLCAiJSIsIHNlcD0iIikpLCBjb2xvcj0id2hpdGUiLCAKICAgICAgICAgICAgcG9zaXRpb249cG9zaXRpb25fc3RhY2sodmp1c3Q9MC41KSwgc2l6ZT0yKSsKICBsYWJzKHg9IlBlcmNlbnRhZ2UiLCB5PSJDb3VudHJ5IiwgZmlsbD0iVm90ZXMgYXJlIGNvdW50ZWQgY29ycmVjdGx5IiwgIAogICAgICAgY2FwdGlvbj0iQW1lcmljYXNCYXJvbWV0ZXIgYnkgTEFQT1AsIDIwMjEiKQpgYGAKCiMgRnJlcXVlbmN5IG9mIHVzZSBvZiBzb2NpYWwgbmV0d29ya3MKClRoZSAyMDE4LzE5IHJvdW5kIGV2YWx1YXRlcyB0aGUgdXNlIG9mIHNvY2lhbCBuZXR3b3JrcyBhbmQgaW5jbHVkZXMgdmFyaWFibGVzIHRvIG1lYXN1cmUgdGhlIHVzZSBvZiBGYWNlYm9vaywgVHdpdHRlciBhbmQgV2hhdHNhcHA6IFNNRURJQTIgbWVhc3VyZXMgdGhlIHVzZSBvZiBGYWNlYm9vay4KSG93IG9mdGVuIGRvIHlvdSB2aWV3IGNvbnRlbnQgb24gRmFjZWJvb2s/ClNNRURJQTUuSG93IG9mdGVuIGRvIHlvdSBzZWUgY29udGVudCBvbiBUd2l0dGVyPwphbmQgU01FRElBOC4KSG93IG9mdGVuIGRvIHlvdSB1c2UgV2hhdHNhcHA/ClRoZXNlIHZhcmlhYmxlcyBoYXZlIGFzIHJlc3BvbnNlIG9wdGlvbnM6CgoxLiAgRGFpbHkKMi4gIEEgZmV3IHRpbWVzIGEgd2VlawozLiAgQSBmZXcgdGltZXMgYSBtb250aAo0LiAgQSBmZXcgdGltZXMgYSB5ZWFyCjUuICBOZXZlcgoKSW4gdGhlIHNhbWUgd2F5IGFzIHdpdGggbm9taW5hbCB2YXJpYWJsZXMsIHRoZXNlIHZhcmlhYmxlcyBoYXZlIHRvIGJlIGRlY2xhcmVkIGFzICJmYWN0b3IiIGluIG5ldyB2YXJpYWJsZXMuCgpgYGB7ciBmYWN0b3J9CmxhcG9wMTgkc21lZGlhMnIgPSBhcy5mYWN0b3IobGFwb3AxOCRzbWVkaWEyKQpsYXBvcDE4JHNtZWRpYTVyID0gYXMuZmFjdG9yKGxhcG9wMTgkc21lZGlhNSkKbGFwb3AxOCRzbWVkaWE4ciA9IGFzLmZhY3RvcihsYXBvcDE4JHNtZWRpYTgpCmBgYAoKRm9vdG5vdGUgMTUgb2YgdGhlIHJlcG9ydCBpbmRpY2F0ZXMgdGhhdCAiaW50ZXJ2aWV3ZWVzIHdobyByZXBvcnQgbmV2ZXIgc2VlaW5nIGNvbnRlbnQgb24gRmFjZWJvb2sgYW5kIFR3aXR0ZXIsIGFuZCB3aG8gaW5kaWNhdGUgdGhhdCB0aGV5IG5ldmVyIHVzZSBXaGF0c2FwcCwgYXJlIGNvbnNpZGVyZWQgbm9uLXVzZXJzIG9mIHRoZXNlIHNvY2lhbCBuZXR3b3JrcyIgKHAuIDY0KS4KRm9yIHRoaXMgcmVhc29uLCBGaWd1cmUgMy4zIG9mIGZyZXF1ZW5jeSBvZiB1c2Ugb2Ygc29jaWFsIG5ldHdvcmtzIChwYWdlIDU3KSBvbmx5IGluY2x1ZGVzIHRoZSBjYXRlZ29yaWVzICJEYWlseSIsICJTb21lIHRpbWVzIGEgd2VlayIsICJTb21lIHRpbWVzIGEgbW9udGgiIGFuZCAiU29tZSB0aW1lcyBhIHllYXIiLgpUaGUgY2F0ZWdvcnkgIk5ldmVyIiBpcyBleGNsdWRlZC4KCiFbXShGaWd1cmUzLjMuSlBHKXt3aWR0aD0iNDYzIn0KCkluIHRoZSBuZXcgdmFyaWFibGVzIHdlIGFyZSBnb2luZyB0byBkZWNsYXJlIHRoZSB2YWx1ZSA1LCBjb3JyZXNwb25kaW5nIHRvICJuZXZlciIsIGFzICJOQSIsIHRoYXQgaXMsIGFzIGEgbWlzc2luZyB2YWx1ZSBpbiBSLgoKYGBge3IgZWxpbWluYXIgbnVuY2F9CmxpYnJhcnkoY2FyKQpsYXBvcDE4JHNtZWRpYTJyID0gY2FyOjpyZWNvZGUobGFwb3AxOCRzbWVkaWEyciwgIjU9TkEiKQpsYXBvcDE4JHNtZWRpYTVyID0gY2FyOjpyZWNvZGUobGFwb3AxOCRzbWVkaWE1ciwgIjU9TkEiKQpsYXBvcDE4JHNtZWRpYThyID0gY2FyOjpyZWNvZGUobGFwb3AxOCRzbWVkaWE4ciwgIjU9TkEiKQpgYGAKClRoZW4sIHRoZXNlIHZhcmlhYmxlcyBoYXZlIHRvIGJlIGxhYmVsZWQgYW5kIHRoZSBiYXNpYyBkZXNjcmlwdGl2ZSB0YWJsZXMgZ2VuZXJhdGVkLCB3aXRoIHRoZSBjb21tYW5kIGB0YWJsZWAuCgpgYGB7ciBsYWJlbH0KbGV2ZWxzKGxhcG9wMTgkc21lZGlhMnIpIDwtIGMoIkRhaWx5IiwgIkEgZmV3IHRpbWVzIGEgd2VlayIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIkEgZmV3IHRpbWVzIGEgbW9udGgiLCAiQSBmZXcgdGltZXMgYSB5ZWFyIikKbGV2ZWxzKGxhcG9wMTgkc21lZGlhNXIpIDwtIGMoIkRhaWx5IiwgIkEgZmV3IHRpbWVzIGEgd2VlayIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIkEgZmV3IHRpbWVzIGEgbW9udGgiLCAiQSBmZXcgdGltZXMgYSB5ZWFyIikKbGV2ZWxzKGxhcG9wMTgkc21lZGlhOHIpIDwtIGMoIkRhaWx5IiwgIkEgZmV3IHRpbWVzIGEgd2VlayIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIkEgZmV3IHRpbWVzIGEgbW9udGgiLCAiQSBmZXcgdGltZXMgYSB5ZWFyIikKdGFibGUobGFwb3AxOCRzbWVkaWEycikKdGFibGUobGFwb3AxOCRzbWVkaWE1cikKdGFibGUobGFwb3AxOCRzbWVkaWE4cikKYGBgCgpUbyBjYWxjdWxhdGUgdGFibGVzIHdpdGggcGVyY2VudGFnZXMsIHJvdW5kZWQgdG8gYSBkZWNpbWFsIHBsYWNlLCB3ZSB1c2UgYHByb3AudGFibGVgIGFuZCBgcm91bmRgLgpBZ2FpbiwgdGhlc2UgcGVyY2VudGFnZXMgYXJlIG5vdCBleGFjdGx5IHRoZSBzYW1lIGFzIHRob3NlIHByZXNlbnRlZCBpbiB0aGUgcmVwb3J0IGJlY2F1c2UgdGhlc2UgY2FsY3VsYXRpb25zIGRvIG5vdCBpbmNsdWRlIHN1cnZleSB3ZWlnaHRzLgoKYGBge3IgcGVyY2VudGFnZXN9CnJvdW5kKHByb3AudGFibGUodGFibGUobGFwb3AxOCRzbWVkaWEycikpLCAzKSoxMDAKcm91bmQocHJvcC50YWJsZSh0YWJsZShsYXBvcDE4JHNtZWRpYTVyKSksIDMpKjEwMApyb3VuZChwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMTgkc21lZGlhOHIpKSwgMykqMTAwCmBgYAoKVG8gcHJlc2VudCBhbGwgdGhlIGRhdGEgaW4gYSBqb2ludCB0YWJsZSwgdGhlIHRhYmxlIG9mIGVhY2ggc29jaWFsIG5ldHdvcmsgaXMgc2F2ZWQgaW4gYSBuZXcgUiBvYmplY3QgKG5hbWVkIGFmdGVyIGVhY2ggc29jaWFsIG5ldHdvcmspLgpUaGVuIGFsbCBvZiB0aGVzZSBwYXJ0aWFsIHRhYmxlcywgY29udGFpbmluZyB0aGUgc2FtZSBhbnN3ZXIgY2hvaWNlcywgYXJlIGpvaW5lZCBhcyByb3dzIHdpdGggdGhlIGByYmluZGAgY29tbWFuZC4KVGhpcyBuZXcgam9pbnQgdGFibGUgaXMgc2F2ZWQgYXMgYSBuZXcgZGF0YWZyYW1lICJ0YWJsZSIuCgpgYGB7ciBiYXNpYyB0YWJsZX0KRmFjZWJvb2sgPSByb3VuZChwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMTgkc21lZGlhMnIpKSwgMykqMTAwClR3aXR0ZXIgPSByb3VuZChwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMTgkc21lZGlhNXIpKSwgMykqMTAwCldoYXRzYXBwID0gcm91bmQocHJvcC50YWJsZSh0YWJsZShsYXBvcDE4JHNtZWRpYThyKSksIDMpKjEwMAp0YWJsZSA9IGFzLmRhdGEuZnJhbWUocmJpbmQoRmFjZWJvb2ssIFR3aXR0ZXIsIFdoYXRzYXBwKSkKdGFibGUKYGBgCgpUbyBnZXQgYSBiZXR0ZXIgcHJlc2VudGF0aW9uIG9mIHRoZSB0YWJsZSwgeW91IGNhbiB1c2UgdGhlIGBrYWJsZWAgY29tbWFuZCBmcm9tIHRoZSBga25pdHJgIHBhY2thZ2Ugb3IgdGhlIGBmb3JtYXR0YWJsZWAgY29tbWFuZCBmcm9tIHRoZSBga25pdHJgIHBhY2thZ2UuCgpgYGB7ciBpbXByb3ZlZCB0YWJsZX0KbGlicmFyeShrbml0cikKa2FibGUoaGVhZCh0YWJsZSksIGZvcm1hdD0ibWFya2Rvd24iLCBkaWdpdHM9MSkKbGlicmFyeShmb3JtYXR0YWJsZSkKZm9ybWF0dGFibGUodGFibGUpCmBgYAoKVG8gZ3JhcGggdGhpcyB2YXJpYWJsZSB3ZSBhcmUgbm90IGdvaW5nIHRvIGZvbGxvdyB0aGUgc2FtZSBwcm9jZWR1cmUgYXMgaW4gdGhlIHByZXZpb3VzIHNlY3Rpb24uCkluIHRoaXMgc2VjdGlvbiB3ZSBhcmUgZ29pbmcgdG8gd29yayBkaXJlY3RseSBmcm9tIHRoZSB0YWJsZSBjcmVhdGVkIHdpdGggdGhlIHBlcmNlbnRhZ2VzIG9mIHRoZSB0aHJlZSBzb2NpYWwgbmV0d29ya3MuClRoaXMgdGFibGUgaGFzIGVhY2ggc29jaWFsIG5ldHdvcmsgaW4gdGhlIHJvd3MgYW5kIHRoZSBhbnN3ZXIgb3B0aW9ucyBpbiB0aGUgY29sdW1ucy4KSW4gb3JkZXIgdG8gZ3JhcGggdGhpcyBkYXRhLCBpdCBpcyByZXF1aXJlZCB0aGF0IHRoZSBzb2NpYWwgbmV0d29ya3MgYXJlIGluIHRoZSBjb2x1bW5zIGFuZCB0aGUgYW5zd2VyIG9wdGlvbnMgaW4gdGhlIHJvd3MsIHNvIGZpcnN0IHdlIGFyZSBnb2luZyB0byB0cmFuc3Bvc2UgdGhpcyB0YWJsZS4KV2UgZG8gdGhpcyBwcm9jZWR1cmUgdXNpbmcgdGhlIGBkYXRhLnRhYmxlYCBsaWJyYXJ5IGFuZCB0aGUgYHRyYW5zcG9zZWAgY29tbWFuZC4KV2Ugc2F2ZSB0aGVzZSB0cmFuc3Bvc2VkIGRhdGEgaW4gYSBuZXcgdGFibGUgInRhYmxlX3RyIi4KClRoaXMgY29tbWFuZCB0cmFuc3Bvc2VzIHRoZSBkYXRhLCBidXQgbGVhdmVzIHRoZSByb3dzIGFuZCBjb2x1bW5zIHVubmFtZWQuCkNvbHVtbnMgYXJlIGZpcnN0IG5hbWVkIHdpdGggdGhlIGNvbW1hbmQgYGNvbG5hbWVzYCB1c2luZyB0aGUgcm93IG5hbWVzIG9mICJ0YWJsZSIuClRoZSByb3dzIGFyZSB0aGVuIG5hbWVkIHdpdGggdGhlIGNvbW1hbmQgYHJvd25hbWVzYCB1c2luZyB0aGUgY29sdW1uIG5hbWVzIG9mICJ0YWJsZSIuCgpGaW5hbGx5LCB3ZSByZXF1aXJlIGEgY29sdW1uIGluc2lkZSAidGFibGVfdHIiIHRoYXQgY29udGFpbnMgdGhlIHJlc3BvbnNlIGxhYmVscyBvZiB0aGUgc21lZGlhIHF1ZXN0aW9ucy4KVGhlc2UgbGFiZWxzIGFyZSBsaWtlIHJvdyBuYW1lcy4KVG8gaW5jbHVkZSB0aGVtIGFzIG9uZSBtb3JlIHZhcmlhYmxlLCBhZGQgYSB2YXJpYWJsZSAidGFibGFfdHJcJGxhYiIgdG8gd2hpY2ggdGhlIG5hbWVzIG9mIHRoZSByb3dzIGFyZSBhc3NpZ25lZCB3aXRoIGByb3cubmFtZXNgLgoKYGBge3IgdHJhbnNwb3NlZCB0YWJsZSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShkYXRhLnRhYmxlKQp0YWJsZV90ciA9IHRyYW5zcG9zZSh0YWJsZSkKY29sbmFtZXModGFibGVfdHIpID0gcm93bmFtZXModGFibGUpCnJvd25hbWVzKHRhYmxlX3RyKSA9IGNvbG5hbWVzKHRhYmxlKQp0YWJsZV90ciRsYWIgPC0gcm93bmFtZXModGFibGVfdHIpCnRhYmxlX3RyCmBgYAoKU2Vjb25kLCB0aGUgYGdncGxvdDJgIGxpYnJhcnkgaXMgYWN0aXZhdGVkIHRvIHBsb3QgdGhlIGRhdGEgc3RvcmVkIGluICJ0YWJsZV90ciIgd2l0aCB0aGUgY29tbWFuZCBgZ2dwbG90YC4KV2l0aGluIHRoaXMgY29tbWFuZCBpdCBpcyBzcGVjaWZpZWQgdGhhdCB0aGlzIGNvbW1hbmQgaXMgZ29pbmcgdG8gd29yayB3aXRoIHRoZSBkYXRhZnJhbWUgInRhYmxlX3RyIiAoYW5kIG5vdCB3aXRoIGxhcG9wMTgpLCBgZGF0YT10YWJsZV90cmAuClRoZSAiYWVzdGhldGljIiBpcyBzcGVjaWZpZWQ6IHRoZSBYIGF4aXMgd2lsbCBub3QgaW5jbHVkZSBhIHZhcmlhYmxlLCB0aGUgWSBheGlzIHdpbGwgc2hvdyB0aGUgIkZhY2Vib29rIiBpbmZvcm1hdGlvbiBmcm9tIHRoZSBkYXRhZnJhbWUgInRhYmxlX3RyIiwgYW5kIGBmaWxsPWxhYmAgaW5kaWNhdGVzIHRoYXQgZGF0YSB3aWxsIGJlIGRpdmlkZWQgYnkgY2F0ZWdvcmllcyBvZiB0aGUgdmFyaWFibGUgc3RvcmVkIGluICJsYWIiLgoKVGhlbiB0aGUgYGdlb21fYmFyYCBsYXllciBpcyBhZGRlZCB0byBpbmRpY2F0ZSB0aGF0IGl0IHdpbGwgYmUgZ3JhcGhlZCBpbiBiYXJzIG9mIHdpZHRoIChgd2lkdGggPSAxYCkgYW5kIHRoYXQgdGhlIGJhciB3aWxsIHJlcGxpY2F0ZSB3aGF0IGlzIHNwZWNpZmllZCBpbiB0aGUgYWVzdGhldGljIChgc3RhdD0iaWRlbnRpdHkiYCkuCldpdGggYGdlb21fdGV4dGAgeW91IGFkZCB0aGUgbGFiZWxzIG9mIHRoZSBkYXRhLCB3aXRoIHRoZSBwZXJjZW50YWdlIHN5bWJvbCwgYW5kIHlvdSBzcGVjaWZ5IHRoZSBwb3NpdGlvbiBvZiB0aGUgdGV4dCB3aXRoIGBwb3NpdGlvbj1wb3NpdGlvbl9zdGFjayjigKYpYCBhbmQgdGhlIHNpemUgd2l0aCBgc2l6ZT0zYC4KV2l0aCBgY29vcmRfcG9sYXJgIHlvdSB0cmFuc2Zvcm0gdGhlIGJhcnMgaW50byBhIHBpZSBjaGFydC4KRmluYWxseSwgdGhlICJ0aGVtZSIgaXMgZGVmaW5lZCB3aXRoIGB0aGVtZV92b2lkYCBpbmRpY2F0aW5nIGEgd2hpdGUgYmFja2dyb3VuZCBhbmQgdGhlIGxlZ2VuZCB0YWcgaXMgbW9kaWZpZWQgd2l0aCBgc2NhbGVfZmlsbF9kaXNjcmV0ZWAuCgpgYGB7ciBwaWUgY2hhcnR9CmxpYnJhcnkoZ2dwbG90MikKZ2dwbG90KGRhdGE9dGFibGVfdHIsIGFlcyh4PSIiLCB5PUZhY2Vib29rLCBmaWxsPWxhYikpKwogIGdlb21fYmFyKHdpZHRoPTEsIHN0YXQ9ImlkZW50aXR5IikrCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1wYXN0ZShGYWNlYm9vaywgIiUiLCBzZXA9IiIpKSwgY29sb3I9IndoaXRlIiwgCiAgICAgICAgICAgIHBvc2l0aW9uPXBvc2l0aW9uX3N0YWNrKHZqdXN0PTAuNSksIHNpemU9MykrCiAgY29vcmRfcG9sYXIoInkiLCBzdGFydD0wKSsKICB0aGVtZV92b2lkKCkrCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZShuYW1lPSJGcmVxdWVuY3kgb2YgdXNlIG9mIEZhY2Vib29rIikKYGBgCgpJbiBmaWd1cmUgMy4zIG9mIHRoZSByZXBvcnQgIlRoZSBQdWxzZSBvZiBEZW1vY3JhY3kiIGEgY2lyY3VsYXIgImRvbm5hIiB0eXBlIGdyYXBoIGlzIHByZXNlbnRlZC4KVG8gZXhhY3RseSByZXByb2R1Y2UgdGhpcyB0eXBlIG9mIGdyYXBoLCBhIGZldyBkZXRhaWxzIG9mIHRoZSBhYm92ZSBzeW50YXggaGF2ZSB0byBiZSBhY2NvbW1vZGF0ZWQuCldlIHNldCAieD0yIiBpbiB0aGUgImFlc3RoZXRpY3MiIGFuZCBzZXQgbGltaXRzIG9uIHRoZSBYIGF4aXMsIGJldHdlZW4gMC41IGFuZCAyLjUsIHNvIHRoYXQgd2hlbiB0aGUgYXhpcyBpcyByb3RhdGVkLCB0aGUgImhvbGUiIGluc2lkZSB0aGUgY2lyY2xlIGlzIGNyZWF0ZWQuCgpgYGB7ciBkb25hfQpnZ3Bsb3QoZGF0YT10YWJsZV90ciwgYWVzKHg9MiwgeT1GYWNlYm9vaywgZmlsbD1sYWIpKSsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpKwogIGdlb21fdGV4dChhZXMobGFiZWw9cGFzdGUoRmFjZWJvb2ssICIlIiwgc2VwPSIiKSksIGNvbG9yPSJ3aGl0ZSIsIAogICAgICAgICAgICBwb3NpdGlvbj1wb3NpdGlvbl9zdGFjayh2anVzdD0wLjUpLCBzaXplPTMpKwogIGNvb3JkX3BvbGFyKCJ5IikrCiAgdGhlbWVfdm9pZCgpKwogIHNjYWxlX2ZpbGxfZGlzY3JldGUobmFtZT0iRnJlcXVlbmN5IG9mIHVzZSBvZiBGYWNlYm9vayIpKwogICBsYWJzKHRpdGxlPSJIb3cgb2Z0ZW4gZG8geW91IHZpZXcgY29udGVudCBvbiBGYWNlYm9vaz8iLCAKICAgICAgICBjYXB0aW9uPSJBbWVyaWNhc0Jhcm9tZXRlciBieSBMQVBPUCwgMjAxOC8xOSIpKwogIHhsaW0oMC41LCAyLjUpCmBgYAoKVG8gcmVwbGljYXRlIHRoZSBiYXIgY2hhcnQsIHNvbWUgbW9kaWZpY2F0aW9ucyBhcmUgbWFkZSB0byB0aGUgY29kZSBhYm92ZS4KRm9yIGV4YW1wbGUsIGluICJhZXN0aGV0aWNzIiwgaXQgaXMgbm93IGluZGljYXRlZCB0aGF0IHRoZSB2YXJpYWJsZSAic21lZGlhMnIiIGdvZXMgb24gdGhlIFggYXhpcyBhbmQgdGhlIHBlcmNlbnRhZ2UgInBlciIgZ29lcyBvbiB0aGUgWSBheGlzLgpJbiBhZGRpdGlvbiwgdGhlIHNwZWNpZmljYXRpb24gb2YgcG9sYXIgY29vcmRpbmF0ZXMgaXMgZWxpbWluYXRlZC4KV2UgY2FuIGFkZCBhIHRpdGxlIHRvIHRoZSBjaGFydCwgYXhpcyBsYWJlbHMsIGFuZCBhIGNhcHRpb24gd2l0aCB0aGUgc3BlY2lmaWNhdGlvbiBgbGFic2AuCkZpbmFsbHksIHRoZSBZIGF4aXMgaXMgZGVmaW5lZCBiZXR3ZWVuIDAgYW5kIDYwIHdpdGggdGhlIGBjb29yZF9jYXJ0ZXNpYW5gIHNwZWNpZmljYXRpb24uCkFuIGltcG9ydGFudCBwb2ludCBpcyB0aGF0IHRoaXMgZ3JhcGggY2FuIGFsc28gYmUgc2F2ZWQgaW4gYW4gb2JqZWN0IGluIFIsIHdoaWNoIHdlIHdpbGwgY2FsbCAicGxvdDEiCgpgYGB7ciBiYXIgZ3JhcGhpY30KcGxvdDEgPC0gZ2dwbG90KHRhYmxlX3RyLCBhZXMoeD1sYWIsIHk9RmFjZWJvb2spKSsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsICB3aWR0aD0wLjUpKwogIGdlb21fdGV4dChhZXMobGFiZWw9cGFzdGUoRmFjZWJvb2ssICIlIiwgc2VwPSIiKSksIGNvbG9yPSJibGFjayIsIHZqdXN0PS0wLjUpKwogIGxhYnModGl0bGU9IkZyZXF1ZW5jeSBvZiB1c2Ugb2Ygc29jaWFsIG5ldHdvcmtzIiwgeD0iRnJlcXVlbmN5IG9mIHVzZSBvZiBGYWNlYm9vayIsIAogICAgICAgeT0iUGVyY2VudGFnZSIsIGNhcHRpb249IkFtZXJpY2FCYXJvbWV0ZXIgYnkgTEFQT1AsIDIwMTgvMTkiKSsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsIDYwKSkKcGxvdDEKYGBgCgpTYXZpbmcgYSBjaGFydCB0byBhbiBvYmplY3QgYWxsb3dzIHVzIHRvIGxhdGVyIGFkZCBtb3JlIGxheWVycyBvciBlbmhhbmNlbWVudHMgdG8gdGhlIGNoYXJ0LgpUaGUgcGxvdCBhYm92ZSwgZm9yIGV4YW1wbGUsIGhhcyB0aGUgIkZyZXF1ZW5jeSBvZiB1c2UiIGxhYmVscyBvbiBhIHNpbmdsZSBsaW5lLCBzbyB0aGV5IGNvdWxkIG92ZXJsYXAuCgpUbyBpbXByb3ZlIHRoaXMgdmlzdWFsaXphdGlvbiwgdGhlc2UgbGFiZWxzIGNhbiBiZSB0aWx0ZWQsIGJ1dCBpZiB5b3Ugd2FudCB0byBtYWludGFpbiB0aGUgaG9yaXpvbnRhbGl0eSB0byBmYWNpbGl0YXRlIHJlYWRpbmcsIHdoYXQgeW91IGNhbiBkbyBpcyBzZXBhcmF0ZSB0aGUgbG9uZyBsYWJlbHMgaW50byB0d28gb3IgbW9yZSBsaW5lcy4KVGhpcyBjYW4gYmUgZG9uZSwgZm9yIGV4YW1wbGUsIGJ5IGNyZWF0aW5nIGEgdmVjdG9yIHdpdGggdGhlIG5ldyBsYWJlbHMuCkxvbmcgdGFncyBjYW4gYmUgYnJva2VuIGludG8gbGluZXMgYnkgaW5jbHVkaW5nIGBcbmAgYmV0d2VlbiB0aGUgdGV4dHMgeW91IHdhbnQgdG8gYnJlYWsuClRoZW4gYSBuZXcgbGF5ZXIgY2FuIGJlIGFkZGVkIHRvIHRoZSBvYmplY3QgInBsb3QxIiB0byByZXBsYWNlIHRoZSBsYWJlbHMgd2l0aCB0aGUgbmV3IG9uZXMgZGl2aWRlZCBpbnRvIGxpbmVzLgpUaGlzIGlzIGRvbmUgd2l0aCB0aGUgc3BlY2lmaWNhdGlvbiBgc2NhbGVfeF9kaXNjcmV0ZWAgd2hlcmUgd2UgZGVmaW5lIHRvIHVzZSB0aGUgbGFiZWxzIGluIHRoZSBuZXcgdmVjdG9yLgoKYGBge3Igb3ZlcmxhcHBpbmcgbGFiZWxzfQpldGlxIDwtIGMoIkRhaWx5IiwgIkEgZmV3IHRpbWVzXG4gYSB3ZWVrIiwgIkEgZmV3IHRpbWVzXG4gYSBtb250aCIsIAogICAgICAgICAgIkEgZmV3IHRpbWVzXG4gYSB5ZWFyIikKcGxvdDEgKyAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHM9ZXRpcSkKYGBgCgpUaGlzIG1ha2VzIHRoZSBncmFwaCBtb3JlIHJlYWRhYmxlLgpTbyBmYXIsIHdlIGhhdmUgcmVwbGljYXRlZCB0aGUgdGFibGVzIGFuZCBncmFwaHMgdGhhdCB3ZXJlIHVzZWQgd2l0aCB0aGUgbm9taW5hbCB2YXJpYWJsZXMsIG5vdyB1c2luZyBvcmRpbmFsIHZhcmlhYmxlcy4KSWYgeW91IHdhbnQgdG8gcmVwbGljYXRlIHRoZSBwaWUgY2hhcnQgb2YgdGhlIG90aGVyIHNvY2lhbCBuZXR3b3JrcywgeW91IGNhbiBydW4gdGhlIHNhbWUgY29kZSwgYnV0IGNoYW5nZSB0aGUgc29jaWFsIG5ldHdvcmsgY29sdW1uLgpGb3IgVHdpdHRlciwgZm9yIGV4YW1wbGUsIHlvdSB3b3VsZCBoYXZlLgoKYGBge3IgVHdpdHRlciBncmFwaH0KcGxvdDIgPC0gZ2dwbG90KGRhdGE9dGFibGVfdHIsIGFlcyh4PTIsIHk9VHdpdHRlciwgZmlsbD1sYWIpKSsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpKwogIGdlb21fdGV4dChhZXMobGFiZWw9cGFzdGUoVHdpdHRlciwgIiUiLCBzZXA9IiIpKSwgY29sb3I9IndoaXRlIiwgCiAgICAgICAgICAgIHBvc2l0aW9uPXBvc2l0aW9uX3N0YWNrKHZqdXN0PTAuNSksIHNpemU9MykrCiAgY29vcmRfcG9sYXIoInkiKSsKICB0aGVtZV92b2lkKCkrCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZShuYW1lPSJGcmVxdWVuY3kgb2YgVHdpdHRlciB1c2UiKSsKICBsYWJzKHRpdGxlPSJIb3cgb2Z0ZW4geW91IHZpZXcgY29udGVudCBvbiBUd2l0dGVyIiwgY2FwdGlvbj0iQW1lcmljYXMgQmFyb21ldGVyIGJ5IExBUE9QLCAyMDE4LzE5IikrCiAgeGxpbSgwLjUsIDIuNSkKcGxvdDIKYGBgCgojIENyb3NzIHRhYmxlcwoKVGFibGUgMy4xIChwYWdlIDU1KSBvZiB0aGUgcmVwb3J0ICJUaGUgUHVsc2Ugb2YgRGVtb2NyYWN5IiBzaG93cyB0aGUgcGVyY2VudGFnZXMgb2YgdXNlIG9mIHNvY2lhbCBuZXR3b3JrcyBieSBjb3VudHJ5LgpUaGVuLCBvbiBwYWdlIDU2LCB0aGVyZSBpcyBhIHRhYmxlIHdpdGggdGhlIHBlcmNlbnRhZ2Ugb2Ygc29jaWFsIG5ldHdvcmsgdXNlcnMgYnkgc29jaW9kZW1vZ3JhcGhpYyBjaGFyYWN0ZXJpc3RpY3MsIGZvciBleGFtcGxlLCB1cmJhbi9ydXJhbCwgbWFsZSwgYXZlcmFnZSBhZ2UsIGF2ZXJhZ2Ugd2VhbHRoLCBhbmQgeWVhcnMgb2Ygc3R1ZHkuCgohW10oVGFibGUlMjAzLjEuSlBHKXt3aWR0aD0iMzk3In0KCldlIHdpbGwgc3RhcnQgYnkgcmVwbGljYXRpbmcgdGhlIGdlbmVyYWwgZGF0YSBvbiB0aGUgdXNlIG9mIHNvY2lhbCBuZXR3b3JrcyB0aGF0IGlzIHJlcG9ydGVkIGluIFRhYmxlIDMuMS4KVG8gcmVwbGljYXRlIHRoaXMgdGFibGUsIHlvdSBtdXN0IGZpcnN0IGRlZmluZSB0aGUgdmFyaWFibGUgImNvdW50cnkiIGFuZCB0aGUgdmFyaWFibGVzIGZvciB0aGUgdXNlIG9mIHNvY2lhbCBuZXR3b3JrcyAoc21lZGlhMSwgc21lZGlhNCBhbmQgc21lZGlhNykuCgpgYGB7ciBwYcOtc30KbGFwb3AxOCRzbWVkaWExciA9IGFzLmZhY3RvcihsYXBvcDE4JHNtZWRpYTEpCmxhcG9wMTgkc21lZGlhNHIgPSBhcy5mYWN0b3IobGFwb3AxOCRzbWVkaWE0KQpsYXBvcDE4JHNtZWRpYTdyID0gYXMuZmFjdG9yKGxhcG9wMTgkc21lZGlhNykKbGV2ZWxzKGxhcG9wMTgkc21lZGlhMXIpID0gYygiWWVzIiwgIk5vIikKbGV2ZWxzKGxhcG9wMTgkc21lZGlhNHIpID0gYygiWWVzIiwgIk5vIikKbGV2ZWxzKGxhcG9wMTgkc21lZGlhN3IpID0gYygiWWVzIiwgIk5vIikKbGFwb3AxOCRwYWlzID0gYXMuZmFjdG9yKGxhcG9wMTgkcGFpcykKbGV2ZWxzKGxhcG9wMTgkcGFpcykgPSBjKCJNw6l4aWNvIiwgIkd1YXRlbWFsYSIsICJFbCBTYWx2YWRvciIsICJIb25kdXJhcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICJOaWNhcmFndWEiLCJDb3N0YSBSaWNhIiwgIlBhbmFtw6EiLCAiQ29sb21iaWEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIkVjdWFkb3IiLCAiQm9saXZpYSIsICJQZXLDuiIsICJQYXJhZ3VheSIsIAogICAgICAgICAgICAgICAgICAgICAgICAiQ2hpbGUiLCAiVXJ1Z3VheSIsICJCcmFzaWwiLCAiQXJnZW50aW5hIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICJSZXAuIERvbS4iLCAiSmFtYWljYSIpCnRhYmxlKGxhcG9wMTgkcGFpcykgI0NvdW50cnkKdGFibGUobGFwb3AxOCRzbWVkaWExcikgI0ZhY2Vib29rCmBgYAoKSG93ZXZlciwgdGhlIHZhcmlhYmxlICJ1c2VyIiBvZiBlYWNoIHNvY2lhbCBuZXR3b3JrIGlzIGNhbGN1bGF0ZWQgYXMgYSBjb25kaXRpb24gb2YgdHdvIHZhcmlhYmxlcywgYXMgc2VlbiBpbiB0aGUgZG9jdW1lbnQgb24gZGF0YSBtYW5pcHVsYXRpb24sIHdpdGggdGhlIGZvbGxvd2luZyBjb2RlLgoKYGBge3IgdXN1YXJpb3N9CmxhcG9wMTgkZmJfdXNlciA9IGlmZWxzZShsYXBvcDE4JHNtZWRpYTE9PTEgJiBsYXBvcDE4JHNtZWRpYTI8PTQsIDEsIDApCmxhcG9wMTgkdHdfdXNlciA9IGlmZWxzZShsYXBvcDE4JHNtZWRpYTQ9PTEgJiBsYXBvcDE4JHNtZWRpYTU8PTQsIDEsIDApCmxhcG9wMTgkd2FfdXNlciA9IGlmZWxzZShsYXBvcDE4JHNtZWRpYTc9PTEgJiBsYXBvcDE4JHNtZWRpYTg8PTQsIDEsIDApCmBgYAoKVGhlc2UgdmFyaWFibGVzIGFyZSBwbG90dGVkIGluIHRoZSByZXBvcnQgaW4gRmlndXJlIDMuMS4KVG8gcmVwcm9kdWNlIHRoaXMgZGF0YSwgeW91IGNhbiBkZXNjcmliZSB0aGVzZSB2YXJpYWJsZXMuCgpgYGB7ciB1c2VyfQpwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMTgkZmJfdXNlcikpKjEwMApwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMTgkdHdfdXNlcikpKjEwMApwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMTgkd2FfdXNlcikpKjEwMApgYGAKCkFzIGluIHByZXZpb3VzIGdyYXBocywgd2l0aCB0aGlzIGRhdGEgYSBkYXRhZnJhbWUgY2FuIGJlIGNyZWF0ZWQgdGhhdCB3b3VsZCBiZSB1c2VkIHRvIG1ha2UgdGhlIGNpcmN1bGFyIGdyYXBocyBzaG93biBpbiB0aGUgcmVwb3J0LgoKVG8gcmVwbGljYXRlIHRoZSB0YWJsZSBvZiB1c2Ugb2Ygc29jaWFsIG5ldHdvcmtzIGJ5IGNvdW50cnksIGZpcnN0LCBiaXZhcmlhdGUgdGFibGVzIGFyZSBjcmVhdGVkIHdpdGggdGhlIHBlcmNlbnRhZ2Ugb2YgdGhvc2Ugd2hvIHVzZSBhbmQgdGhlIHBlcmNlbnRhZ2Ugb2YgdGhvc2Ugd2hvIGRvIG5vdCB1c2UgZWFjaCBzb2NpYWwgbmV0d29yayBpbiBlYWNoIGNvdW50cnkuClRoZXNlIHRhYmxlcyBhcmUgc3RvcmVkIGluIFIgb2JqZWN0cy4KVGhlc2Ugb2JqZWN0cyBhcmUgdGhlbiBtZXJnZWQgdXNpbmcgdGhlIGNvbW1hbmRzIGBjYmluZGAgdG8gYmluZCB0aGUgY29sdW1ucyBhbmQgYGFzLmRhdGEuZnJhbWVgIHRvIGJpbmQgdGhlIHRhYmxlcyBhcyBhIGRhdGFmcmFtZS4KVGhpcyB0YWJsZSBhbHNvIHByZXNlbnRzIHRoZSBwZXJjZW50YWdlcyBvZiB0aG9zZSB3aG8gZG8gbm90IHVzZSB0aGVzZSBzb2NpYWwgbmV0d29ya3MuClRvIHByZXNlbnQgYSB0YWJsZSB0aGF0IGluY2x1ZGVzIG9ubHkgdGhvc2Ugd2hvIGRvIHVzZSBzb2NpYWwgbmV0d29ya3MsIGNvbHVtbnMgYXJlIGVsaW1pbmF0ZWQsIHVzaW5nIHRoZSBzcGVjaWZpY2F0aW9uIGBbLCBjKC0xLC0zLC01KV1gLCB3aGljaCBpbmRpY2F0ZXMgdGhhdCB3ZSB3YW50IHRvIGVsaW1pbmF0ZSBjb2x1bW5zIDEgLCAzIGFuZCA1LgpGaW5hbGx5LCB0aGUgZGF0YWZyYW1lIGNvbHVtbnMgYXJlIHJlbmFtZWQuCgpgYGB7ciB0YWJsZSBieSBjb3VudHJ5fQpmYmNvdW50cnkgPSByb3VuZChwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMTgkcGFpcywgbGFwb3AxOCRmYl91c2VyKSwgMSksIDMpKjEwMAp0d2NvdW50cnkgPSByb3VuZChwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMTgkcGFpcywgbGFwb3AxOCR0d191c2VyKSwgMSksIDMpKjEwMAp3aGNvdW50cnkgPSByb3VuZChwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMTgkcGFpcywgbGFwb3AxOCR3YV91c2VyKSwgMSksIDMpKjEwMAp0YWJsZWNvdW50cnkgPSBhcy5kYXRhLmZyYW1lKGNiaW5kKGZiY291bnRyeSwgdHdjb3VudHJ5LCB3aGNvdW50cnkpKQp0YWJsZWNvdW50cnkgPSB0YWJsZWNvdW50cnlbLCBjKC0xLC0zLC01KV0KdmFybmFtZXMgPSBjKCJVc2UgZmFjZWJvb2siLCAiVXNlIFR3aXR0ZXIiLCAiVXNlIFdoYXRzYXBwIikKY29sbmFtZXModGFibGVjb3VudHJ5KSA9IHZhcm5hbWVzCnRhYmxlY291bnRyeQpgYGAKClRvIGhhdmUgYSBiZXR0ZXIgcHJlc2VudGF0aW9uIG9mIHRoZSB0YWJsZSwgdGhlcmUgYXJlIHR3byBhbHRlcm5hdGl2ZXM6IHRoZSBmaXJzdCB3aXRoIHRoZSBga25pdHJgIGxpYnJhcnkgYW5kIHRoZSBvdGhlciB3aXRoIHRoZSBgZm9ybWF0dGFibGVgIGxpYnJhcnkuCgpgYGB7ciBpbXByb3ZlZCB0YWJsZSBieSBjb3VudHJ5fQpsaWJyYXJ5KGtuaXRyKQprYWJsZShoZWFkKHRhYmxlY291bnRyeSksIGZvcm1hdD0ibWFya2Rvd24iLCBkaWdpdHM9MSkKbGlicmFyeShmb3JtYXR0YWJsZSkKZm9ybWF0dGFibGUodGFibGVjb3VudHJ5KQpgYGAKCiMgQ3Jvc3N0YWJsZXMgd2l0aCBzb2Npb2RlbW9ncmFwaGljIHZhcmlhYmxlcwoKT24gcGFnZSA1NiBvZiB0aGUgcmVwb3J0ICJUaGUgcHVsc2Ugb2YgZGVtb2NyYWN5IiB0aGUgcmVzdWx0cyBvZiB0aGUgY3Jvc3N0YWJsZSBiZXR3ZWVuIHRoZSB2YXJpYWJsZXMgdXNlIG9mIHNvY2lhbCBuZXR3b3JrcyBhbmQgc29jaW9kZW1vZ3JhcGhpYyB2YXJpYWJsZXMgc3VjaCBhcyB1cmJhbi9ydXJhbCwgZ2VuZGVyLCBhZ2UsIHdlYWx0aCBhbmQgeWVhcnMgb2YgZWR1Y2F0aW9uIGFyZSBwcmVzZW50ZWQuCgohW10oVGFibGUlMjAzLjIuSlBHKXt3aWR0aD0iNjcyIn0KClRoZSB2YXJpYWJsZSAicTEiIHJlY29yZHMgdGhlIGdlbmRlciBvZiB0aGUgaW50ZXJ2aWV3ZWUuClRoaXMgdmFyaWFibGUgaXMgZW5jb2RlZCBhcyBmb2xsb3dzOgoKMS4gIE1hbgoyLiAgV29tYW4KClRvIGNhbGN1bGF0ZSBhICJkdW1teSIgdmFyaWFibGUgY2FsbGVkICJtYW4iLCBzdWNoIHRoYXQgbWFsZSBpcyAxIGFuZCBmZW1hbGUgaXMgMCwgb25lIHdheSB0byBkbyBpdCBpcyBhbGdlYnJhaWNhbGx5ICgyLXZhcmlhYmxlIHExKS4KSW4gdGhpcyB3YXksIG5vdyB0aGUgbWVuIG1haW50YWluIHRoZSB2YWx1ZSAxICgyLTEpIGFuZCB0aGUgd29tZW4gYmVjb21lIDAgKDItMikuCkluIHRoaXMgY2FzZSwgdGhlIG5ldyB2YXJpYWJsZSAibWFuIiBpcyBjcmVhdGVkIGFzIGEgbnVtZXJpYyB2YXJpYWJsZS4KV2UgYXJlIGdvaW5nIHRvIGtlZXAgdGhlIHZhcmlhYmxlIGFzICJudW0iIHNvIHRoYXQsIGZ1cnRoZXIgZG93biwgd2UgY2FuIGNhbGN1bGF0ZSB0aGUgbWVhbiBvZiB0aGlzIHZhcmlhYmxlIChzb21ldGhpbmcgdGhhdCBjYW5ub3QgYmUgZG9uZSB3aXRoIGEgdmFyaWFibGUgZGVjbGFyZWQgYXMgYSBmYWN0b3IpLgoKYGBge3IgbWFufQpsYXBvcDE4JG1lbiA8LSAyLWxhcG9wMTgkcTEKdGFibGUobGFwb3AxOCRtZW4pCmBgYAoKVGhlIHVyYmFuL3J1cmFsIHZhcmlhYmxlIGlzIG5hbWVkICJ1ciIgaW4gdGhlIGRhdGFiYXNlIGFuZCBpcyBlbmNvZGVkIGFzIGZvbGxvd3M6CgoxLiAgVXJiYW4KMi4gIFJ1cmFsCgpJbiB0aGUgc2FtZSB3YXkgYXMgd2l0aCBnZW5kZXIsIHRoZSBmb3JtdWxhIDItIHZhcmlhYmxlIHVyIGlzIHVzZWQsIGJ1dCB0aGlzIHZhcmlhYmxlIGlzIGNvbnZlcnRlZCBpbnRvIGEgZmFjdG9yIGFuZCBpcyBsYWJlbGVkLgoKYGBge3IgdXJiYW59CmxhcG9wMTgkdXJiYW4gPC0gMi1sYXBvcDE4JHVyCmxhcG9wMTgkdXJiYW4gPSBhcy5mYWN0b3IobGFwb3AxOCR1cmJhbikKbGV2ZWxzKGxhcG9wMTgkdXJiYW4pIDwtIGMoIlJ1cmFsIiwgIlVyYmFuIikKdGFibGUobGFwb3AxOCR1cmJhbikKYGBgCgpUaGUgY3Jvc3N0YWJsZXMgb2YgdGhlIHVzZSBvZiBzb2NpYWwgbmV0d29ya3MgYnkgc29tZSBvZiB0aGUgc29jaW9kZW1vZ3JhcGhpYyB2YXJpYWJsZXMgd2lsbCBiZSBwcmVzZW50ZWQsIHRvIGJldHRlciB1bmRlcnN0YW5kIGhvdyB0aGUgZ2VuZXJhbCB0YWJsZSBpcyBjb25zdHJ1Y3RlZC4KRm9yIGV4YW1wbGUsIHRoZSByZXBvcnQgc2hvd3MgaW4gVGFibGUgMy4yLCBhZnRlciB0aGUgZ2VuZXJhbCBwb3B1bGF0aW9uIGNvbHVtbiwgdGhlIGNvbHVtbnMgZm9yIFdoYXRzQXBwIHVzZXJzIGFuZCBub24tdXNlcnMgKHZhcmlhYmxlICJ3YV91c2VyIikgYW5kIGluIHRoZSByb3dzLCB0aGUgZmlyc3QgY29ycmVzcG9uZHMgdG8gdXJiYW4gKHZhcmlhYmxlICJ1cmJhbiIsIHdoZXJlIDAgaXMgcnVyYWwgYW5kIDEgdXJiYW4pLgpJdCBpcyBwcmVzZW50ZWQgdGhhdCBhbW9uZyBXaGF0c0FwcCB1c2VycywgNzYuNyUgYXJlIHVyYmFuIGFuZCBhbW9uZyBub24tdXNlcnMsIDYyJSBhcmUgdXJiYW4uClRoZXNlIGRhdGEgYXJlIGdlbmVyYXRlZCB3aXRoIHRoZSBgdGFibGVgIGNvbW1hbmQgdGhhdCBhbGxvd3MgeW91IHRvIG1ha2UgYSBjb250aW5nZW5jeSB0YWJsZSBvZiAyIHZhcmlhYmxlcy4KSW4gdGhpcyBjYXNlIGl0IHNob3VsZCBiZSBub3RlZCB0aGF0IGVhY2ggdmFyaWFibGUgaGFzIGEgdGl0bGUuClNvIHRoZSBjb21tYW5kIGlzIGB0YWJsZSh0aXRsZTEgPSB2YXIxLCB0aXRsZTIgPSB2YXIyKWAuClRoZW4sIHRoZSBgcHJvcC50YWJsZWAgY29tbWFuZCBpcyB1c2VkIHNvIHRoYXQgdGhlIG9ic2VydmF0aW9ucyBhcmUgbm90IGRpc3BsYXllZCwgYnV0IHRoZSBwZXJjZW50YWdlcy4KVGhpcyBjb21tYW5kIGFsbG93cyB5b3UgdG8gY2FsY3VsYXRlIHRoZSBwZXJjZW50YWdlcyBvZiB0aGUgdG90YWwgKHRoZSBkZWZhdWx0IG9wdGlvbiksIG9mIHRoZSByb3dzIGFuZCBvZiB0aGUgY29sdW1ucy4KVG8gY2FsY3VsYXRlIG9uIGNvbHVtbnMgeW91IG11c3Qgc3BlY2lmeSBgcHJvcC50YWJsZSh0YWJsZSguLi4pLCAyKWAuCklmIHlvdSB3YW50ZWQgdGhlIHBlcmNlbnRhZ2Ugb3ZlciB0aGUgcm93cywgdGhlIGNvZGUgd291bGQgYmUgYHByb3AudGFibGUodGFibGUoLi4uKSwgMSlgLgpUaGlzIHRhYmxlIGNhbiBiZSBzYXZlZCBhcyBhIGRhdGFmcmFtZSB3aXRoIHRoZSBgYXMuZGF0YS5mcmFtZWAgY29tbWFuZCBpbiBhIG5ldyBvYmplY3QgInQxIi4KCmBgYHtyIHRhYmxlIFdoeFVyfQp0MSA9IGFzLmRhdGEuZnJhbWUocm91bmQocHJvcC50YWJsZSh0YWJsZShVcmJhbiA9IGxhcG9wMTgkdXJiYW4sIFVzZXIgPSBsYXBvcDE4JHdhX3VzZXIpLCAyKSoxMDAsIDEpKQp0MQpgYGAKClRoZSByb3dzIGNvcnJlc3BvbmRpbmcgdG8gIlVyYmFuIiBpbiB0aGlzIHRhYmxlIHJlcHJvZHVjZSB0aGUgZGF0YSBpbiBUYWJsZSAzLjI6IDYyLjElIGFyZSB1cmJhbiBhbW9uZyBub24tV2hhdHNhcHAgdXNlcnMgYW5kIDc2LjclIGFyZSB1cmJhbiBhbW9uZyB1c2Vycy4KCk5vdyB0aGUgdGFibGUgd2lsbCBiZSBwcmVzZW50ZWQgYmV0d2VlbiBGYWNlYm9vayB1c2VycyAodmFyaWFibGUgImZiX3VzZXIiKSBhbmQgbWVuICh2YXJpYWJsZSAibWVuIiksIGJ1dCBwcmVzZW50aW5nIG9ubHkgdGhlIHBlcmNlbnRhZ2VzIHVzZWQgaW4gdGhlIHRhYmxlIGFuZCBub3cgdXNpbmcgdGhlIGNvZGUgc3R5bGUgb2YgdGhlIFRpZHl2ZXJzZSwgdXNpbmcgdGhlICJwaXBlIiBvcGVyYXRvci4KVGhlIGZpcnN0IHRoaW5nIGlzIHRvIGRlZmluZSB0aGUgdmFyaWFibGUgImZiX3VzZXIiIGFzIGEgZmFjdG9yIGFuZCBsYWJlbCBpdC4KVGhlbiwgdGhlIGBzdWJzZXRgIGNvbW1hbmQgaXMgdXNlZCB0byBmaWx0ZXIgdGhlIG1pc3NpbmcgY2FzZXMgb24gdGhlICJmYl91c2VyIiB2YXJpYWJsZS4KVGhlbiB0aGUgcmVzdWx0cyBhcmUgcmVxdWVzdGVkIHRvIGJlIGdyb3VwZWQgYnkgY2F0ZWdvcmllcyBvZiB0aGUgdmFyaWFibGUgImZiX3VzZXIiLgpXaXRoIHRoZSBgc3VtbWFyaXNlYCBjb21tYW5kLCB0aGUgYXZlcmFnZSBvZiB0aGUgIm1hbiIgdmFyaWFibGUgaXMgc2F2ZWQgaW4gdGhlICJtYW4iIGNvbHVtbiwgd2l0aCB0aGUgYG1lYW5gIGNvbW1hbmQgdGhhdCBpbmNsdWRlcyB0aGUgc3BlY2lmaWNhdGlvbiBgbmEucm09VGAgc28gYXMgbm90IHRvIGluY2x1ZGUgbWlzc2luZyB2YWx1ZXMgaW4gdGhlIGNhbGN1bGF0aW9uLgpJbiB0aGlzIGNhc2UsIGl0IHRha2VzIGFkdmFudGFnZSBvZiB0aGUgZmFjdCB0aGF0IHRoZSB2YXJpYWJsZSAibWVuIiBpcyBhIGR1bW15IHZhcmlhYmxlLCBpbiBzdWNoIGEgd2F5IHRoYXQgdGhlIGF2ZXJhZ2UgY29ycmVzcG9uZHMgdG8gdGhlIHByb3BvcnRpb24gb2YgbWVuLgoKYGBge3IgdGFibCBGYnhtYW4sIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxhcG9wMTgkZmJfdXNlciA9IGFzLmZhY3RvcihsYXBvcDE4JGZiX3VzZXIpCmxldmVscyhsYXBvcDE4JGZiX3VzZXIpID0gYygiTm8gdXNlciIsICJVc2VyIikKbGlicmFyeSh0aWR5dmVyc2UpCnRhYmxlMSA9IHN1YnNldChsYXBvcDE4LCAhaXMubmEoZmJfdXNlcikpICU+JSAjVG8gbm90IGluY2x1ZGUgdGhlIE5BIGdyb3VwIG9mIEZhY2Vib29rIHVzZXJzCiAgZ3JvdXBfYnkoZmJfdXNlcikgJT4lCiAgZHBseXI6OnN1bW1hcmlzZShNZW49bWVhbihtZW4sIG5hLnJtPVQpKjEwMCkgI25hLnJtPVQgaXMgaW5jbHVkZWQgYmVjYXVzZSBtYW4gaGFzIE5Bcwp0YWJsZTEKYGBgCgpUaGVzZSBhcmUgdGhlIHBlcmNlbnRhZ2VzIGZvciBGYWNlYm9vayB1c2VycywgaW4gdGhlIHJvdyBvZiB0aGUgTWFsZSB2YXJpYWJsZSBpbiBUYWJsZSAzLjIuClRoYXQgaXMsIGFtb25nIG5vbi11c2VycywgNDkuOSUgYXJlIG1lbiBhbmQgYW1vbmcgdXNlcnMgdGhpcyBwZXJjZW50YWdlIGlzIDQ5LjclLgpTbyBmYXIgd2UgaGF2ZSByZXBsaWNhdGVkIHNvbWUgcmVzdWx0cyBmcm9tIFRhYmxlIDMuMi4KVGhlIG90aGVyIGRhdGEgY2FuIGNvbnRpbnVlIHRvIGJlIHJlY29uc3RydWN0ZWQgdGhyb3VnaCBjb21iaW5hdGlvbnMgb2YgdGhlIHNvY2lhbCBuZXR3b3JrIHVzZXIgdmFyaWFibGVzIGFuZCB0aGUgc29jaW9kZW1vZ3JhcGhpYyB2YXJpYWJsZXMuCgojIFR3by1WYXJpYWJsZSBCYXIgQ2hhcnQKClRoZSBjcm9zcyBiZXR3ZWVuIFdoYXRzQXBwIHVzZXJzIGFuZCB0aGUgdXJiYW4gdmFyaWFibGUgY2FuIGFsc28gYmUgc2VlbiBpbiBhIGdyb3VwZWQgYmFyIGdyYXBoLgpUaGUgZmlyc3QgdGhpbmcgd2Ugd2lsbCBkbyBpcyBkZWZpbmUgdGhlIHZhcmlhYmxlICJ3YV91c2VyIiBhcyBhIGZhY3RvciBhbmQgbGFiZWwgaXQuClRoZW4sIGl0IGlzIHJlcXVpcmVkIHRvIGNyZWF0ZSBhIHRhYmxlIHdpdGggdGhlIGdyb3VwZWQgZGF0YS4KVGhlICJ0MSIgZGF0YWZyYW1lIGNyZWF0ZWQgZWFybGllciBjYW4gYmUgdXNlZCwgYnV0IGhlcmUgd2Ugd2lsbCBhZ2FpbiB1c2UgdGhlICJwaXBlIiBvcGVyYXRvciB0byByZWNyZWF0ZSB0aGUgZGF0YS4KCkZvciB0aGlzLCBpdCBpcyBncm91cGVkIGJvdGggYnkgdXNlIG9mIFdoYXRzQXBwIGFuZCBieSB1cmJhbi9ydXJhbCwgdGhhdCBpcywgaW4gZm91ciBjb21iaW5hdGlvbnMuCkluIGVhY2ggc3ViZ3JvdXAgdGhlIG4gaXMgY2FsY3VsYXRlZC4KU2luY2UgdGhlICUgaGF2ZSB0byBiZSBjYWxjdWxhdGVkIGZvciBlYWNoIGdyb3VwIG9mICJ3YV91c2VyIiwgaXQgaXMgZ3JvdXBlZCBhZ2FpbiBhbmQgdGhlICUgb2YgZWFjaCBzdWJncm91cCBpcyBjYWxjdWxhdGVkLCBpbiBzdWNoIGEgd2F5IHRoYXQgdGhlIHBlcmNlbnRhZ2VzIGFkZCB1cCB0byAxMDAlIGluIGVhY2ggc3ViZ3JvdXAgb2YgIndhX3VzZXIiLgoKYGBge3IgdGFibGUgd2F9CmxhcG9wMTgkd2FfdXNlciA9IGFzLmZhY3RvcihsYXBvcDE4JHdhX3VzZXIpCmxldmVscyhsYXBvcDE4JHdhX3VzZXIpID0gYygiTm8gdXNlciIsICJVc2VyIikKZmFjZSA8LSBzdWJzZXQobGFwb3AxOCwgIWlzLm5hKHdhX3VzZXIpKSAlPiUgIyFpcy5uYSBpcyB1c2VkIHNvIHRoYXQgTkFzIGFyZSBub3QgcmVwb3J0ZWQgaW4gdGhlIHRhYmxlCiAgZ3JvdXBfYnkod2FfdXNlciwgdXJiYW4pICU+JSAjZ3JvdXBzIGFyZSBjb25maWd1cmVkCiAgZHBseXI6OmNvdW50KCkgJT4lICNuIGlzIGNhbGN1bGF0ZWQKICBncm91cF9ieSh3YV91c2VyKSAlPiUgI0l0IGlzIGdyb3VwZWQgYnkgV2hhdHNBcHAgdXNlcgogIGRwbHlyOjptdXRhdGUocGVyY2VudGFnZSA9IHJvdW5kKG4vc3VtKG4pLCAzKSoxMDApICNUaGUgcGVyY2VudGFnZSBpcyBjYWxjdWxhdGVkIGluIGVhY2ggV2hhdHNBcHAgZ3JvdXAKZmFjZQpgYGAKClRoZSBkYXRhIGluIHRoaXMgbmV3IHRhYmxlIGlzIGV4YWN0bHkgdGhlIHNhbWUgYXMgaW4gInQxIi4KV2l0aCB0aGUgdGFibGUgcmVhZHksIHVzZSB0aGUgYGdncGxvdGAgY29tbWFuZCwgZGVmaW5pbmcgIndhX3VzZXIiIHRvIGJlIHRoZSB2YXJpYWJsZSBvbiB0aGUgWCBheGlzLCB0aGUgWSBheGlzIHRvIGJlIHRoZSBwZXJjZW50YWdlLCBhbmQgdGhlIHN1Ymdyb3VwcyB0byBiZSBmb3JtZWQgYnkgdGhlIHZhcmlhYmxlICJ1cmJhbiIgd2l0aCB0aGUgYGZpbGxgIHNwZWNpZmljYXRpb24uCi4gVGhlIGBkb2RnZWAgc3BlY2lmaWNhdGlvbiBpcyB1c2VkIGluIGBnZW9tX2JhcmAgdG8gaGF2ZSB0aGUgYmFycyBzZXBhcmF0ZWQgYnkgZWFjaCBncm91cC4KCmBgYHtyIGdyb3VwZWQgZ3JhcGhpY3N9CmdncGxvdChkYXRhPWZhY2UsIGFlcyh4PXdhX3VzZXIsIHk9cGVyY2VudGFnZSwgZmlsbD11cmJhbiwgeW1heD0xMDApKSsKICBnZW9tX2Jhcihwb3NpdGlvbj0iZG9kZ2UiLCBzdGF0PSJpZGVudGl0eSIpKwogIGdlb21fdGV4dChhZXMobGFiZWw9cGFzdGUocGVyY2VudGFnZSwgIiUiLCBzZXA9IiIpKSwgCiAgICAgICAgICAgIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoPTAuOSksIHZqdXN0PS0wLjI1KSsKICB5bGFiKCJQZXJjZW50YWdlIikrCiAgeGxhYigiV2hhdHNhcHAgdXNlciIpCmBgYAoKSWYgd2Ugd2FudGVkIHRvIG1ha2UgdGhlIGdyYXBoIHdpdGggc3RhY2tlZCBiYXJzLCB3ZSB3b3VsZCBoYXZlIHRvIGNoYW5nZSB0aGUgYHBvc2l0aW9uPSJzdGFjayJgIHNwZWNpZmljYXRpb24gaW4gYGdlb21fYmFyYCBhbmQgdGhlIGBwb3NpdGlvbj1wb3NpdGlvbl9zdGFjaygpYCBzcGVjaWZpY2F0aW9uIGluIGBnZW9tX3RleHRgLgoKYGBge3Igc3RhY2tlZCBiYXJzfQpnZ3Bsb3QoZGF0YT1mYWNlLCBhZXMoeD13YV91c2VyLCB5PXBlcmNlbnRhZ2UsIGZpbGw9dXJiYW4sIHltYXg9MTAwKSkrCiAgZ2VvbV9iYXIocG9zaXRpb249InN0YWNrIiwgc3RhdD0iaWRlbnRpdHkiKSsKICBnZW9tX3RleHQoYWVzKGxhYmVsPXBhc3RlKHBlcmNlbnRhZ2UsICIlIiwgc2VwPSIiKSksIAogICAgICAgICAgICBwb3NpdGlvbj1wb3NpdGlvbl9zdGFjaygpLCB2anVzdD0yLjUpKwogIHlsYWIoIlBlcmNlbnRhZ2UiKSsKICB4bGFiKCJXaGF0c2FwcCB1c2VyIikKYGBgCgpJbiBib3RoIGNhc2VzLCB0aGUgbGlnaHQgYmx1ZSBiYXJzIGluZGljYXRlIHRoZSBwZXJjZW50YWdlcyByZXBvcnRlZCBpbiB0YWJsZSAzLjIgb2YgdGhlIHJlcG9ydCBhbmQgY29ycmVzcG9uZCB0byB0aGUgcHJvcG9ydGlvbiBvZiBwZW9wbGUgbGl2aW5nIGluIHVyYmFuIGFyZWFzIGJldHdlZW4gdXNlcnMgYW5kIG5vbi11c2Vycy4KCiMgU3VtbWFyeQoKSW4gdGhpcyBkb2N1bWVudCB3ZSBoYXZlIHdvcmtlZCB3aXRoIG9yZGluYWwgY2F0ZWdvcmljYWwgdmFyaWFibGVzLCBzdWNoIGFzIHRoZSBmcmVxdWVuY3kgb2YgdXNlIG9mIHNvY2lhbCBuZXR3b3Jrcy4KVGhlIHVzZSBvZiBjb250aW5nZW5jeSB0YWJsZXMgb2YgdHdvIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyBhbmQgdGhlIGNyZWF0aW9uIG9mIGdyb3VwZWQgYmFyIGdyYXBocyBmb3IgMiB2YXJpYWJsZXMgaGF2ZSBhbHNvIGJlZW4gaW50cm9kdWNlZC4KCiMgQ2FsY3VsYXRpb25zIGluY2x1ZGluZyBzdXJ2ZXkgd2VpZ2h0cwoKIyMgRXhhbXBsZSB1c2luZyB0aGUgMjAyMSBkYXRhc2V0CgpXaXRoIHRoZSBkYXRhIG9mIHRoZSAyMDIxIHdhdmUgb2YgdGhlIEFtZXJpY2FzQmFyb21ldGVyLCB3ZSBoYXZlIGNhbGN1bGF0ZWQgdGhlIHBlcmNlbnRhZ2VzIG9mIHRoZSB2YXJpYWJsZSB0aGF0IGdhdWdlcyB3aGV0aGVyIHRoZSB2b3RlcyBhcmUgY291bnRlZCBjb3JyZWN0bHkuClRoZSBmaWd1cmUgd2UgaGF2ZSBwcm9kdWNlZCBpcyBmb3IgdGhlIHRvdGFsIHNhbXBsZTsgaXQgbWVhbnMsIGZvciBhbGwgdGhlIGNvdW50cmllcy4KVGhlIEZpZ3VyZSAyLjUgb2YgdGhlIHJlcG9ydCBUaGUgUHVsc2Ugb2YgRGVtb2NyYWN5IHByZXNlbnRzIHJlc3VsdHMgZm9yIGVhY2ggY291bnRyeS4KCklmIHdlIGNhbGN1bGF0ZSBwZXJjZW50YWdlcyB3aXRoIHRoZSBjb21tYW5kcyBgdGFibGVgIGFuZCBgcHJvcC50YWJsZWAsIHdlIHdvdWxkIGdldCBkaWZmZXJlbnQgcmVzdWx0cyBmcm9tIHRob3NlIHNob3cgaW4gdGhlIEZpZ3VyZS4KRm9yIGV4YW1wbGUsIE5pY2FyYWd1YSwgY291bnRyeSA1LCBkaXNwbGF5IHRoYXQgMjYlIG9mIGNpdGl6ZW5zIGluIHRoaXMgY291bnRyeSBpbmRpY2F0ZSB0aGF0IHZvdGVzIGFyZSBhbHdheXMgY291bnRlZCBjb3JyZWN0bHksIDQ5JSBpbmRpY2F0ZSB0aGF0IHZvdGVzIGFyZSBzb21ldGltZXMgY291bnRlZCBjb3JyZWN0bHksIGFuZCAyNC40JSB0aGF0IHZvdGVyIGFyZSBuZXZlciBjb3VudGVkIGNvcnJlY3RseS4KSG93ZXZlciwgdGhlIGZpZ3VyZSBzaG93cyB0aGF0IDI5JSBpbmRpY2F0ZSB0aGF0IHZvdGVzIGFyZSBuZXZlciBjb3VudGVkIGNvcnJlY3RseSBpbiBOaWNhcmFndWEsIDQ1JSB0aGF0IHNvbWV0aW1lcywgYW5kIDI1JSB0aGF0IGFsd2F5cy4KVGhlc2UgcGVyY2VudGFnZXMgZG8gbm90IG1hdGNoIHRob3NlIHByb2R1Y2VkIHdpdGggdGhlc2UgY29tbWFuZHMuCgpgYGB7cn0Kcm91bmQocHJvcC50YWJsZSh0YWJsZShsYXBvcDIxJHBhaXMsIGxhcG9wMjEkY291bnRmYWlyMXIpLCAxKSwgMykqMTAwCmBgYAoKVGhpcyBkaWZmZXJlbmNlIGlzIGR1ZSB0byB0aGUgZmFjdCB0aGF0IGNvbW1hbmRzIGB0YWJsZWAgYW5kIGBwcm9wLnRhYmxlYCBkbyBub3QgaW5jbHVkZSBzdXJ2ZXkgd2VpZ2h0cyBpbiBjYWxjdWxhdGlvbnMuCk1vcmUgaW5mb3JtYXRpb24gYWJvdXQgdGhlc2UgZGlmZmVyZW5jZXMgYXJlIGZvdW5kIFtoZXJlXShodHRwczovL2FydHVyb21hbGRvbmFkby5naXRodWIuaW8vQmFyb21ldHJvRWR1X1dlYl9FbmcvRXhwYW5zaW9uLmh0bWwpLgoKVG8gcmVwbGljYXRlIHRoZSByZXN1bHRzIG9mIEZpZ3VyZSAyLjUsIHRoZXJlIGFyZSBzb21lIG9wdGlvbnMuClRoZSBmaXJzdCBvcHRpb24gaXMgdXNpbmcgYW4gc3BlY2lhbGl6ZWQgbGlicmVyeSBjYWxsZWQgYHN1cnZleWAuCgpUbyBiZSBhbGxvd2VkIHRvIHVzZSB0aGlzIGxpYnJhcnksIHdlIHNob3VsZCBmaXJzdCBwcmVwYXJlIHRoZSBkYXRhc2V0LCBkcm9wcGluZyBtaXNzaW5nIHZhbHVlcyBvZiB2YXJpYWJsZXMgdGhhdCBkZWZpbmUgdGhlIHN1cnZleSBkZXNpZ24uCkFuIGFkZGl0aW9uYWwgc3RlcCBpcyB0cmFuc2Zvcm1pbmcgdGhlIHZhcmlhYmxlcyBpbiB0aGUgZGF0YWZyYW1lLgpXaGVuIHdlIGltcG9ydCB0aGUgZGF0YXNldCwgdGhlIHN5c3RlbSByZWFkcyB0aGVzZSB2YXJpYWJsZXMgYXMgImhhdmVuX2xhYmVsbGVkIiB0eXBlLCB0aGF0IGlzLCB0aGV5IG1hLmludGFpbiBsYWJlbHMgb2YgdmFyaWFibGVzLCB3aXRoIHdoaWNoIHdlIG1heSBwcm9kdWNlIGEgY29kZWJvb2suClRoaXMgbWF5IGJlIHVzZWZ1bCBpbiBvdGhlciBvY2Fzc2lvbnMsIGJ1dCBpdCBnZW5lcmF0ZXMgcHJvYmxlbXMgd2l0aCB0aGUgbGlicmFyeSBgc3VydmV5YC4KRm9yIHRoaXMsIHdlIHRyYW5zZm9ybSB0aGUgdmFyaWFibGVzIHRvIG90aGVyIHR5cGUgd2l0aCB0aGUgY29tbWFuZCBgc2FwcGx5YC4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmxhcG9wMjEgPSBzdWJzZXQobGFwb3AyMSwgIWlzLm5hKHdlaWdodDE1MDApKQpzYXBwbHkobGFwb3AyMSwgaGF2ZW46OnphcF9sYWJlbHMpCmBgYAoKT25jZSBwcmVwYXJlZCB0aGUgZGF0YXNldCwgd2UgYWN0aXZhdGUgdGhlIGxpYnJhcnkgYW5kIGRlY2xhcmUgdGhlIHN1cnZleSBkZXNpZ24uCkluIHRoZSBsYXN0IHNlY3Rpb24sIHdlIGFsc28gdXNlIHRoaXMgbGlicmFyeSB0byBjYWxjdWxhdGUgdGhlIHJlc3VsdHMgd2l0aCB0aGUgc3VydmV5IHdlaWdodHMgaW4gdGhlIHJvdW5kIDIwMTguCkNvbnRyYXJ5IHRvIHRoaXMgY29kZSwgdGhlIDIwMjEgcm91bmQgb2YgdGhlIEFtZXJpY2FzQmFyb21ldGVyIHVzZXMgcGhvbmUgaW50ZXJ2aWV3cywgYW5kIG5vdCBmYWNlIHRvIGZhY2UuCkZvciB0aGlzIHJlYXNvbiwgdGhlIHByaW1hcnkgdW5pdCBvZiBzYW1wbGluZyBpcyB0aGUgaW5kaXZpZHVhbCwgYW5kIHNvIGl0IGlzIGRlZmluZWQgaW4gdGhlIHZhcmlhYmxlICJ1cG0iLgpUaGUgdmFyaWFibGUgdGhhdCBkZWZpbmVzIHN0cmF0YSBpcyAic3RyYXRhIiAoYW5kIG5vdCAiZXN0cmF0b3ByaSIsIGFzIGluIHRoZSAyMDE4IHJvdW5kKS4KVGhlIHdlaWdodGluZyB2YXJpYWJsZSBpcyBzdGlsbCAid2VpZ2h0MTUwMCIuCgpXaXRoIHRoaXMgaW5mb3JtYXRpb24sIHdlIHNhdmUgdGhlIGRlc2lnbiBpbiBhbiBvYmplY3QgImRlc2lnbjIxIi4KCmBgYHtyfQpsaWJyYXJ5KHN1cnZleSkKZGVzaWduMjEgPSBzdnlkZXNpZ24oaWRzID0gfnVwbSwgc3RyYXRhID0gfnN0cmF0YSwgd2VpZ2h0cyA9IH53ZWlnaHQxNTAwLCBuZXN0PVRSVUUsIGRhdGE9bGFwb3AyMSkKYGBgCgpUaGUgbGlicmFyeSBgc3VydmV5YCBpbmNsdWRlcyBuYXRpdmUgY29tbWFuZHMgdG8gcGVyZm9ybSBtdWx0aXBsZSBvcGVyYXRpb25zIGluY2x1ZGluZyBzdXJ2ZXkgd2VpZ2h0cy4KT25lIGlzIHRoaXMgY29tbWFuZHMgaXMgYHN2eXRhYmxlYCB0aGF0IGFsbG93cyB0byBtYWtlIGEgY3Jvc3N0YWJsZSBiZXR3ZWVuIHRoZSB2YXJpYWJsZSAiY291bnRmYWlyMSIgYW5kICJwYWlzIiwgc3BlY2lmeWluZyB0aGUgZGVzaWduLgpUaGlzIGNvbW1hbmQgcmV0dXJucyB0aGUgd2VpZ2h0aW5nIGFic29sdXRlIGZyZXF1ZW5jaWVzLgpGb3IgdGhpcyByZWFzb24sIHdlIGhhdmUgdG8gbmVzdCB0aGlzIGNvZGUgaW4gdGhlIGNvbW1hbmQgYHByb3AudGFibGVgIHRvIGNhbGN1bGF0ZSB0aGUgcGVyY2VudGFnZXMgZnJvbSB3ZWlnaHRpbmcgYWJzb2x1dGUgZnJlcXVlbmNpZXMuCldlIGFsc28gdXNlIHRoZSBjb21tYW5kcyBgcm91bmRgIHRvIHJvdW5kIHBlcmNlbnRhZ2UsIGFuZCB0aGUgY29tbWFuZCBgYXMuZGF0YS50YWJsZWAgdG8gc2F2ZSB0aGlzIHRhYmxlIGluIGFuIG9iamVjdCAidm90ZXhjb3VudHJ5IiBhcyBhIGRhdGFmcmFtZSB0aGF0IGFsbG93cyB0byB1c2UgdGhpcyBkYXRhIHdpdGggYGdncGxvdGAuCgpgYGB7cn0Kdm90ZXhjb3VudHJ5ID0gYXMuZGF0YS5mcmFtZShyb3VuZChwcm9wLnRhYmxlKHN2eXRhYmxlKH5wYWlzK2NvdW50ZmFpcjFyLCBkZXNpZ249ZGVzaWduMjEpLCAxKSoxMDAsIDApKQp2b3RleGNvdW50cnkkY291bnRyeSA9IGNvdW50cnkKdm90ZXhjb3VudHJ5CmBgYAoKYGBge3J9CmdncGxvdChkYXRhPXZvdGV4Y291bnRyeSwgYWVzKGZpbGw9Y291bnRmYWlyMXIsIHg9RnJlcSwgeT1jb3VudHJ5KSkrCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCB3aWR0aD0wLjMpKwogIGdlb21fdGV4dChhZXMobGFiZWw9cGFzdGUoRnJlcSwgIiUiLCBzZXA9IiIpKSwgY29sb3I9IndoaXRlIiwgCiAgICAgICAgICAgIHBvc2l0aW9uPXBvc2l0aW9uX3N0YWNrKHZqdXN0PTAuNSksIHNpemU9MykrCiAgbGFicyh4PSJQZXJjZW50YWdlIiwgeT0iQ291bnRyeSIsIGZpbGw9IlZvdGVzIGFyZSBjb3VudGVkIGNvcnJlY3RseSIsCiAgICAgICBjYXB0aW9uPSJBbWVyaWNhc0Jhcm9tZXRlciBieSBMQVBPUCwgMjAyMSIpCmBgYAoKVGhpcyBmaWd1cmUgcmVwcm9kdWNlcyBleGFjdGx5IHRoZSByZXN1bHRzIHNob3duIGluIHRoZSBGaWd1cmUgMi41IG9mIHRoZSByZXBvcnQsIGV2ZW4gaW4gYSBkaWZmZXJlbnQgb3JkZXIuCgojIyBFeGFtcGxlIHVzaW5nIHRoZSAyMDE4LzE5IGRhdGFzZXQKClRoZSBzbWFsbCBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHBlcmNlbnRhZ2VzIHNob3duIGluIEZpZ3VyZSAzLjMgYW5kIHRob3NlIHNob3duIGluIHRoZSAiRGVzY3JpYmluZyBhbmQgcGxvdHRpbmcgdmFyaWFibGVzIiBzZWN0aW9uIG1heSBiZSBkdWUgdG8gdGhlIGZhY3QgdGhhdCB0aGUgc3VydmV5IHdlaWdodCBpcyBub3QgaW5jbHVkZWQgaW4gYWxsIHRoZSBwcmV2aW91cyB0YWJsZXMgYW5kIGdyYXBocy4KSWYgaW5jbHVkZWQsIHVzaW5nIHRoZSB2YXJpYWJsZSAid2VpZ2h0MTUwMCIsIHRoZSBwZXJjZW50YWdlcyBzaG93biBpbiB0aGUgcmVwb3J0IHdvdWxkIGJlIHJlcGxpY2F0ZWQuCkZvciBleGFtcGxlLCB0byB1c2UgV2hhdHNBcHAsIHlvdSBjYW4gdXNlIHRoZSBjb21tYW5kIGBmcmVxYCBmcm9tIHRoZSBsaWJyYXJ5IGBkZXNjcmAsIHdoaWNoIGFsbG93cyB5b3UgdG8gaW5jbHVkZSBhIHdlaWdodGluZyB2YXJpYWJsZS4KClRoaXMgdGFibGUgY2FuIGJlIHNhdmVkIHRvIGEgZGF0YWZyYW1lLCBmcm9tIHdoaWNoIHRoZSByb3dzIGFuZCBjb2x1bW5zIHRoYXQgYXJlIG5vdCByZXF1aXJlZCBjYW4gYmUgcmVtb3ZlZCwgYW5kIHRoZSByZW1haW5pbmcgY29sdW1ucyBjYW4gYmUgcmVuYW1lZC4KCmBgYHtyIHdhIHdlaWdodGVkfQp0YWJsZTIgPSBhcy5kYXRhLmZyYW1lKGRlc2NyOjpmcmVxKGxhcG9wMTgkc21lZGlhOHIsIGxhcG9wMTgkd2VpZ2h0MTUwMCwgcGxvdD1GKSkKdGFibGUyID0gdGFibGUyWy1jKDUsNiksIC0yXQpjb2xuYW1lcyh0YWJsZTIpIDwtIGMoImZyZWMiLCAicGVyIikKdGFibGUyJGxhYiA8LSByb3duYW1lcyh0YWJsZTIpCnRhYmxlMgpgYGAKCldpdGggdGhpcyBuZXcgZGF0YWZyYW1lLCB3ZSBjYW4gcmVwbGljYXRlIHRoZSBmaWd1cmUgZm9yIFdoYXRzYXBwICwgd2l0aCB0aGUgZGF0YSB3ZWlnaHRlZCwgdXNpbmcgdGhlIGBnZ3Bsb3RgIGNvZGUuCgpgYGB7ciB3YSBncmFmIHBvbmR9CmdncGxvdChkYXRhPXRhYmxlMiwgYWVzKHg9MiwgeT1wZXIsIGZpbGw9bGFiKSkrCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSsKICBnZW9tX3RleHQoYWVzKGxhYmVsPXBhc3RlKHJvdW5kKHBlciwgMSksICIlIiwgc2VwPSIiKSksIGNvbG9yPSJ3aGl0ZSIsIAogICAgICAgICAgICBwb3NpdGlvbj1wb3NpdGlvbl9zdGFjayh2anVzdD0wLjUpLCBzaXplPTMpKwogIGNvb3JkX3BvbGFyKCJ5IikrCiAgdGhlbWVfdm9pZCgpKwogIHNjYWxlX2ZpbGxfZGlzY3JldGUobmFtZT0iRnJlcXVlbmN5IG9mIHVzZSBvZiBGYWNlYm9vayIpKwogICBsYWJzKHRpdGxlPSJGcmVxdWVuY3kgd2l0aCB3aGljaCB5b3UgdmlldyBjb250ZW50IG9uIEZhY2Vib29rIiwgCiAgICAgICAgY2FwdGlvbj0iQW1lcmljYXNCYXJvbWV0ZXIgYnkgTEFQT1AsIDIwMTgvMTkiKSsKICB4bGltKDAuNSwgMi41KQpgYGAKCkluIGFkZGl0aW9uIHRvIHRoZSBgZnJlcWAgY29tbWFuZCwgeW91IGNhbiBhbHNvIHVzZSB0aGUgbGlicmFyeSBgc3VydmV5YCBhbmQgdGhlIG5hdGl2ZSBjb21tYW5kIGBzdnl0YWJsZWAuCgpgYGB7ciBzdXJ2ZXl9CmxpYnJhcnkoc3VydmV5KQpkZXNpZ24xOCA9IHN2eWRlc2lnbihpZHMgPSB+dXBtLCBzdHJhdGEgPSB+ZXN0cmF0b3ByaSwgd2VpZ2h0cyA9IH53ZWlnaHQxNTAwLCBuZXN0PVRSVUUsIGRhdGE9bGFwb3AxOCkKYGBgCgpUaGUgcmVzdWx0cyBvYnRhaW5lZCBhcmUgdGhlIHNhbWUgYXMgd2l0aCB0aGUgcHJldmlvdXMgbWV0aG9kIGFuZCB0aG9zZSBwcmVzZW50ZWQgaW4gdGhlIHJlcG9ydC4KVGhlc2UgcmVzdWx0cyBjYW4gYWxzbyBiZSBzYXZlZCBpbiBhICJkYXRhZnJhbWUiIHRvIG1ha2UgdGhlIGdyYXBoLgoKYGBge3Igc3Z5dGFibGV9CnByb3AudGFibGUoc3Z5dGFibGUofnNtZWRpYThyLCBkZXNpZ249ZGVzaWduMTgpKSoxMDAKYGBgCgpUaGUgc2VjdGlvbiAiQ3Jvc3Mgd2l0aCB2YXJpYWJsZXMiIHByZXNlbnRzIHRoZSBkYXRhIG9mIHVzZXJzIG9mIHNvY2lhbCBuZXR3b3JrcyBieSBjb3VudHJ5LgpUbyBidWlsZCB0aGUgdGFibGUgY29uc2lkZXJpbmcgdGhlIGRlc2lnbiBlZmZlY3QsIHlvdSBjYW4gYWxzbyB1c2UgdGhlIG5hdGl2ZSBgc3Z5dGFibGVgIGNvbW1hbmQgdGhhdCBhbGxvd3MgeW91IHRvIGNvbXB1dGUgYSBiaXZhcmlhdGUgdGFibGUuCkluIHRoZSBzYW1lIHdheSBhcyBpbiB0aGUgdW53ZWlnaHRlZCBjYXNlLCB0aGUgcGFydGlhbCB0YWJsZXMgb2YgZWFjaCBzb2NpYWwgbmV0d29yayBhcmUgc3RvcmVkIGluIGxpc3QtdHlwZSBvYmplY3RzLCB3aGljaCBhcmUgcHV0IHRvZ2V0aGVyIGFzIGEgImRhdGFmcmFtZSIgYW5kIGVkaXRlZCB0byBwcmVzZW50IG9ubHkgdGhlIGRhdGEgb2YgdGhlIHVzZXJzIG9mIGVhY2ggc29jaWFsIG5ldHdvcmsuCmZvciBjb3VudHJ5LgoKYGBge3IgYml2YXJpYXRlIHN2eXRhYmxlfQpmYnBhaXNfMiA9IHJvdW5kKHByb3AudGFibGUoc3Z5dGFibGUofnBhaXMrZmJfdXNlciwgZGVzaWduPWRlc2lnbjE4KSwgMSksIDMpKjEwMAp0d3BhaXNfMiA9IHJvdW5kKHByb3AudGFibGUoc3Z5dGFibGUofnBhaXMrdHdfdXNlciwgZGVzaWduPWRlc2lnbjE4KSwgMSksIDMpKjEwMAp3YXBhaXNfMiA9IHJvdW5kKHByb3AudGFibGUoc3Z5dGFibGUofnBhaXMrd2FfdXNlciwgZGVzaWduPWRlc2lnbjE4KSwgMSksIDMpKjEwMAp0YWJsZWNvdW50cnlfMiA9IGFzLmRhdGEuZnJhbWUoY2JpbmQoZmJwYWlzXzIsIHR3cGFpc18yLCB3YXBhaXNfMikpCnRhYmxlY291bnRyeV8yID0gdGFibGVjb3VudHJ5XzJbLCBjKC0xLC0zLC01KV0KdmFybmFtZXMgPSBjKCJVc2UgRmFjZWJvb2siLCAiVXNlIFR3aXR0ZXIiLCAiVXNlIFdoYXRzYXBwIikKY29sbmFtZXModGFibGVjb3VudHJ5XzIpID0gdmFybmFtZXMKdGFibGVjb3VudHJ5XzIKYGBgCgpGaW5hbGx5LCB0aGUgc2VjdGlvbiAiQ3Jvc3N0YWJsZXMgd2l0aCBzb2Npb2RlbW9ncmFwaGljIHZhcmlhYmxlcyIgcmVwcm9kdWNlcyB0aGUgcmVzdWx0cyBvZiBUYWJsZSAzLjIgb2YgdGhlIHJlcG9ydC4KSW4gdGhlIHNhbWUgd2F5IGFzIGluIHRoZSBwcmV2aW91cyBjYXNlLCB0aGUgbmF0aXZlIGNvbW1hbmQgYHN2eXRhYmxlYCBjYW4gYmUgdXNlZCB0byBwZXJmb3JtIHRoZSBjcm9zcyBiZXR3ZWVuIHRoZSBzb2NpYWwgbmV0d29yayB1c2FnZSB2YXJpYWJsZXMgYW5kIHRoZSB1cmJhbiB2YXJpYWJsZS4KVGhlIHJlc3VsdHMgb2YgdGhlIFVyYmFuIHJvdyBpbiBlYWNoIHNvY2lhbCBuZXR3b3JrIHdvdWxkIGNvcnJlc3BvbmQgdG8gdGhlIGZpcnN0IHJvdyBvZiByZXN1bHRzIGluIFRhYmxlIDMuMi4KCmBgYHtyfQpyb3VuZChwcm9wLnRhYmxlKHN2eXRhYmxlKH51cmJhbit3YV91c2VyLCBkZXNpZ249ZGVzaWduMTgpLCAyKSwgMykqMTAwCnJvdW5kKHByb3AudGFibGUoc3Z5dGFibGUofnVyYmFuK2ZiX3VzZXIsIGRlc2lnbj1kZXNpZ24xOCksIDIpLCAzKSoxMDAKcm91bmQocHJvcC50YWJsZShzdnl0YWJsZSh+dXJiYW4rdHdfdXNlciwgZGVzaWduPWRlc2lnbjE4KSwgMiksIDMpKjEwMApgYGAKCkluIHRoaXMgd2F5LCBmcmVxdWVuY3kgZGlzdHJpYnV0aW9uIHRhYmxlcyBhbmQgYml2YXJpYXRlIChvciBjb250aW5nZW5jeSkgdGFibGVzIGNhbiBiZSBjYWxjdWxhdGVkIGluY2x1ZGluZyB0aGUgZGVzaWduIGVmZmVjdCBvciB0aGUgZXhwYW5zaW9uIGZhY3Rvci4K