Introduction

In this section we will start with the basics of how to use the LAPOP AmericasBarometer dataset for statistical purposes. First, we will look at the basics of how to describe a variable using a frequency distribution table and how to graph that variable using pie or bar charts. For that, we are going to use the latest 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 document, reports data on social networks and political attitudes. In this section, data on the use of the internet and the use of social networks are presented, in general and by country. With the data from the AmericasBarometer, it is possible to know the percentage of households with cell phone access, with internet access, as well as the percentage of people who use WhatsApp, Facebook or Twitter. In this document we are going to reproduce these results.

About the dataset

The data that we are going to use should be cited as follows: Source: AmericasBarometer by the Latin American Public Opinion Project (LAPOP), wwww.LapopSurveys.org. In this document a trimmed dataset is reloaded from scratch. It is recommended again to clean the Environment of the objects used in previous modules.

This dataset is hosted in the “materials_edu” repository of LAPOP’s GitHub account. Using the library rio and the commandimport, this dataset can be imported from this repository. In addition, the data for countries with codes less than or equal to 35 are selected, it means that observations for 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 the 2021 round dataset.

lapop21 = import("https://raw.github.com/lapop-central/materials_edu/main/lapop21.RData")
lapop21 = subset(lapop21, pais<=35)

Support for democracy

The report The Pulse of Democracy 2021 shows the results for support for democracy by country. Figure 1.1 shows the percentage of people who support democracy in abstract in each country.

In a previous section, we explain how to recode variable ING4, originally measured in a 1-7 scale, where 1 means “Strongly diesagree” and 7 means “Strongly agree”. Values between 5 and 7 are recoded as “1” and this value identifies those who support democracy. The rest are recoded as “0”, those who do not support democracy. The new recoded variable are saved in a new variable “ing4rec”.

library(car)
lapop21$ing4rec = car::recode(lapop21$ing4, "1:4=0; 5:7=1")

In strict sense, this variable is not numeric even though it is defined as “dbl” in the dataset, which is a type of numeric variable. This variable is qualitative, nominal, that is defined as factor in R. For correctly defined and labelled, we have to transform this variable. First, we have to define as factor with the command as.factor.

lapop21$ing4rec = as.factor(lapop21$ing4rec)

A factor variable can have levels for each numeric value. The definition of levels has the goal that tables of figures do not show numeric codes, but the corresponding label. We can do this using the command levels. Then, we can describe this variable with the command table that gives absolute frequencies for each category of this variable.

levels(lapop21$ing4rec) = c("No", "Yes")
table(lapop21$ing4rec)
## 
##    No   Yes 
## 20523 36240

Describe variables

As we see in the section Manipulation, we can use the command prop.table to obtain relative frequencies and the command round to show just one decimal.

round(prop.table(table(lapop21$ing4rec))*100, 1)
## 
##   No  Yes 
## 36.2 63.8

Results show two categories in the variable “support for democracy”. However, this variable has missing values. For getting a table showing missing values, we can use the command table with the specification useNA = "always".

round(prop.table(table(lapop21$ing4rec, useNA = "always"))*100, 1)
## 
##   No  Yes <NA> 
## 33.8 59.7  6.4

This table shows that we have 6.4% of missing cases of the total observations. The presentation of missing values in tables or figures depends of the researcher.

Plot a variable

We can plot a variable of type “factor” in multiple ways. A possibility is by a circular graph. We can use the command pie, which is part of the basic syntax of R. Within this command, we can nest the command table to plot values of a contingency table.

pie(table(lapop21$ing4rec))

This figure has some option to customization. For example, the specification labels = … serves to include the number of observation in each sector, and the specification col =… works to define colors of sectors.

pie(table(lapop21$ing4rec), labels=table(lapop21$ing4rec), col=1:2)

Other option is using a bar plot. Using the basic command of R, we can use barplot. We nest the commands table and prop.table within barplot.

barplot(prop.table(table(lapop21$ing4rec))*100, col=1:2)

The base commands in R have a level of customization, but we have a specialized library to produce a graph with more customization options called ggplot. For example, to reproduce a bar plot of the variable support for democracy, we call the library ggplot2.

In this example, we have to define the basic specification within the command ggplot. This command works by layers. First, we specify the data to be used with data=lapop. Then, the specification aes defines the aesthetic of the plot. Generally, it is used to indicate what variables are plotted in what axis (x or y). In this case, we are working with the data from scratch, from the original dataset “lapop21”. This option obliges to “calculate” the percentages within the specification aes with y =..prop..*100. Also, we should use the specification fill = to define that bars should present a percentage.

Other easier option is to create before a table from the original data that captures percentages and to use this table in the specification aes. Below, we present examples using this option.

After the specification of data and axis, we have to define the type of plot we want to use. We do this with geometries (“geom”). We define a basic bar plot using the command geom_bar( ), where we define internally the width of bars. With the specification labs we define the labels of axis and the “caption”. Finally, with the specification coord_cartesian we define limits for x axis from 0 to 80.

library(ggplot2)
ggplot(data=lapop21, aes(x=ing4rec))+
  geom_bar(aes(y=..prop..*100, group=1), width=0.5)+
  labs(x="Support for democracy", y="Percentage", 
       caption="AmericasBarometer by LAPOP, 2021")+
  coord_cartesian(ylim=c(0, 80))

As we say, this plot presents a bar for the percentage of missing values. If a researcher would like to present a plot with percentages of valid cases, missing values should be dropped. We can use the command subset again, but within ggplot for the command (internally) works with the variable no considering the missing values. The syntax !is.na( ) makes the command to not include missing values of a variable in calculations. If we would have used !is.na( ) out of ggplot, we would have dropped all observations with missing values in the dataset, decreasing the N and affecting next calculations.

ggplot(data=subset(lapop21, !is.na(ing4rec)), aes(x=ing4rec))+
  geom_bar(aes(y=..prop..*100, group=1), width=0.5)+
  labs(x="Support for democracy", y="Percentage", 
       caption="AmericasBarometer by LAPOP, 2021")+
  coord_cartesian(ylim=c(0, 80))

Up to this point, we have presented a bar plot of a single variable, support for democracy, for the whole sample, that includes all countries. Figure 1.1 shows the percentage of support for democracy by country. We will see this type of plot in a following section.

Social media users

Now, we are presenting an example of the report The Pulse of Democracy for the 2018/19 round. We follow similar procedures as the section above and we will replicate some figures of the report for the 2018/19 round. We are going to work with these variables: SMEDIA1. Do you have a Facebook account?; SMEDIA4. Do you have a Twitter account?; SMEDIA7. Do you have a WhatsApp account?. These questions have as answer options:

  1. Yes

  2. No

When reading the database in R, this program imports the variables as “num”, which most functions in R treat as numeric. These variables have to be converted to variables of type “factor” with the command as.factor, since they are categorical variables. We save these new variables in the dataframe. Here we have used the = operator which is similar to the <- operator that assigns a procedure to a new object of an R dataframe.

lapop18$smedia1r = as.factor(lapop18$smedia1)
lapop18$smedia4r = as.factor(lapop18$smedia4)
lapop18$smedia7r = as.factor(lapop18$smedia7)

These new variables of type factor have to be labeled with the command levels. A vector with concatenated labels is used, using the command c( ).

levels(lapop18$smedia1r) <- c("Yes", "No")
levels(lapop18$smedia4r) <- c("Yes", "No")
levels(lapop18$smedia7r) <- c("Yes", "No")

Calculating the variables of social network users

As we saw in a previous module, you can calculate new variables with conditional values of other variables using the ifelse command. In this way, we calculate the variables of social network users.

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)

Describing the variables

With the variables ready, we now proceed to make the general tables with the table command. Note the use of # as a way of making annotations, which are not R code.

table(lapop18$smedia1r) #Facebook
## 
##   Yes    No 
## 15389 11573
table(lapop18$smedia4r) #Twitter
## 
##   Yes    No 
##  2363 24558
table(lapop18$smedia7r) #Whatsapp
## 
##   Yes    No 
## 17446  9569

This table command gives us the absolute frequencies (number of observations) for each category of variables (in this case Yes and No). To get the relative frequencies, we will use the command prop.table, where the previous command table is nested.

prop.table(table(lapop18$smedia1r))
## 
##       Yes        No 
## 0.5707663 0.4292337
prop.table(table(lapop18$smedia4r))
## 
##        Yes         No 
## 0.08777534 0.91222466
prop.table(table(lapop18$smedia7r))
## 
##       Yes        No 
## 0.6457894 0.3542106

However, the command prop.table returns us too many decimal places and the relative frequencies on a scale of 0 to 1. To round this figure we use the round command, which allows us to specify the number of decimal places to be displayed. Both the table command and the prop.table are nested within this new command. In this case, we use 3 decimals, so when it is multiplied by 100, it remains in the form of a percentage with 1 decimal place.

round(prop.table(table(lapop18$smedia1r)), 3)*100
## 
##  Yes   No 
## 57.1 42.9
round(prop.table(table(lapop18$smedia4r)), 3)*100
## 
##  Yes   No 
##  8.8 91.2
round(prop.table(table(lapop18$smedia7r)), 3)*100
## 
##  Yes   No 
## 64.6 35.4

It is not practical to present 3 tables when the variables have the same response categories. For presentation purposes it might be better to build a single table. You can save the partial tables in new objects with the operator = and then join them as rows with the command rbind in a new dataframe “table” with the command as.data.frame, in such a way that the responses to each social network appear in rows.

Facebook = round(prop.table(table(lapop18$smedia1r)), 3)*100
Twitter = round(prop.table(table(lapop18$smedia4r)), 3)*100
Whatsapp = round(prop.table(table(lapop18$smedia7r)), 3)*100
tabla = as.data.frame(rbind(Facebook, Twitter, Whatsapp))
tabla
##           Yes   No
## Facebook 57.1 42.9
## Twitter   8.8 91.2
## Whatsapp 64.6 35.4

To have a better presentation of the table, you can use the kable command from the knitr package, using the table built above.

library(knitr)
knitr::kable(tabla, format="markdown")
Yes No
Facebook 57.1 42.9
Twitter 8.8 91.2
Whatsapp 64.6 35.4

Plotting the variables

In Graph 3.1 of the report it is observed that these data are reported through a pie chart.

We can reproduce that graph using the pie command which is part of the basic R syntax. Within this command you can nest the table command to graph these values.

pie(table(lapop18$smedia1r))

You could also think of a bar chart. Using the basic R commands, you can use the barplot command.

barplot(prop.table(table(lapop18$smedia1r)))

These graphical commands have options to adjust the graph, for example to include percentages and adjust scales. But, to have more graphical options, we can use the ggplot package to reproduce the pie chart.

In this example, we have to define first the data to be used. The subset command has been used again, but inside ggplot so that the command (internally) works with the variable but without the missing values. The !is.na () syntax prevents the command from including missing values of a variable in calculations. If data = lapop had been used the graph would have included a large sector corresponding to the proportion of NA. If !is.na () had been used outside of ggplot creating a new variable, all observations with missing values would have been removed, which would decrease the N, affecting future calculations.

The ggplot command works by adding layers. The aes specification is used to define the “aesthetics” of the graph. It is generally used to indicate which variable is going to be graphed on which axis (x or y). You can also use the fill = specification to define the groups to be generated.

After specifying the data and the axes, you have to specify the type of graph you want to make. This is done with geometries (“geom”). There is no direct geometry to make a pie chart, so you have to initially use a simple bar chart, using the command geom_bar (), where the width of the bar is defined internally. If we left the syntax at this point, a bar would be generated that would be divided by the values of the variable “smedia1r”. To generate the pie chart, you have to add another command coord_polar, which transforms the bar to polar coordinates, creating a pie chart.

library(ggplot2) #librería especializada en gráficos
ggplot(data=subset(lapop18, !is.na(smedia1r)), aes(x="", fill=smedia1r))+
  geom_bar(width=1) +
  coord_polar("y", start=0)

The above graph has started from the same dataframe “lapop18”, using the data from “smedia1r”. However, to better manipulate the graph it is easier to create a new dataframe with the aggregated data (frequencies and %). In other words, save the results data from the “smedia1r” table in a new dataframe. Then that new dataframe is used to make the pie graph with ggplot.

One aspect to note is that in this case the tidyverse is being used, which includes the pipe %>% command from the dplyr library, which is a (slightly) different way of writing code in R, in a concatenated way, step by step. A simple explanation of how the pipe is used can be found here.

The first thing to notice is that a new object called “df” is going to be created. Information coming from the dataframe “lapop18” will be stored in this object. The subset command is used to remove the missing values of “smedia1r” from the calculation of the percentages. Then (%>%), this data will be grouped by categories of the variable “smedia1r”. Next (%>%), in each group the total number of observations is calculated with the command summarise(n = n()). Finally (last step with %>%), with this total by groups the percentages are calculated and these percentages are saved in a new column “per”.

library(dplyr)
df = subset(lapop18, !is.na(smedia1r)) %>%
      group_by(smedia1r) %>% 
      dplyr::summarise(n = n()) %>%
      mutate(per=round(n/sum(n), 3)*100)
df
## # A tibble: 2 × 3
##   smedia1r     n   per
##   <fct>    <int> <dbl>
## 1 Yes      15389  57.1
## 2 No       11573  42.9

With this syntax, a table is created containing the total number of observations and the percentage for each category of the variable “smedia1r”. A more direct way to create the same data is to use the janitor library and the tabyl command. In R there are multiple ways to get to the same results.

library(janitor)
subset(lapop18, !is.na(smedia1r)) %>%
  tabyl(smedia1r)
##  smedia1r     n   percent
##       Yes 15389 0.5707663
##        No 11573 0.4292337

Once we have the table, we can use it to produce the pie chart with ggplot. Note that in this case the data used comes from the dataframe df (not from lapop18). This dataframe has a column called “per” with the respective percentages, which should be plotted on the Y-axis. As in the previous case, to make the pie chart, we start from the bar chart (hence geom_bar), which is then passed to polar coordinates (hence coord_polar).

A text layer is added, with the specification geom_text. Within this specification, an “aesthetic” is determined with the data label aes(label=...), where the percentage data “per” and the symbol “%” are joined with the paste command, with a space (sep=...) between them. Set the font color with color="...", sets to white to contrast with the colors of the pie chart. With the command hjust=... the horizontal position of this text is adjusted. The ggplot command can include various “themes” for the plot. In this case, theme_void() has been used, which indicates an empty background. Finally, with the specification scale_fill_discrete(name=...) you can change the title of the legend so that it does not show the name of the variable, but a more suitable label.

ggplot(data=df, aes(x="", y=per, fill=smedia1r))+
  geom_bar(width=1, stat="identity")+
  geom_text(aes(label=paste(per, "%", sep="")), color="white",
            position=position_stack(vjust=0.5), size=3)+
  coord_polar("y")+
  theme_void()+
  scale_fill_discrete(name="Do you have a Facebook account?")

If instead of a pie chart you want to display a bar chart, with the data from the “lapop18” dataframe you can use the following code. Unlike the first pie chart, the aes(..) specification now includes the variable “smedia1r” as the variable to be plotted on the X-axis. Inside the geometric object geom_bar() it is indicated that the bar must represent the proportions in percentages aes(y=..prop..*100, group=1). In this example, a general label for the graph and for the axes has been included with the labs(...) command. In this command you can also add a “caption” to indicate the source of the data. Finally, the specification coord_cartesian(ylim=c(0,60)) limits the Y axis to values between 0 and 60.

ggplot(data=subset(lapop18, !is.na(smedia1r)), aes(x=smedia1r))+
  geom_bar(aes(y=..prop..*100, group=1), width=0.5)+
  labs(title="Do you have a Facebook account?", x="Facebook user", y="Percentage", caption="AmericasBarometer by LAPOP, 2018/19")+
  coord_cartesian(ylim=c(0, 60))

In this case you can also use the grouped data of the “df” dataframe. Unlike the previous option, in “df” there is the percentage data, so it should not be calculated in the code, so in the aesthetics specification it indicates that the alternatives should be shown on the X axis of the variable “smedia1r” and on the Y axis the percentage, in this way aes(x=media1r, y=per). For this reason also in the geom_bar specification, now instead of requiring the calculation of the percentage, it is only indicated to replicate the data (with stat="identity") from aes. Finally, in this case we add the text layer to include the percentages in each column, with the geom_text specification.

ggplot(df, aes(x=smedia1r, y=per))+
  geom_bar(stat="identity",  width=0.5)+
  geom_text(aes(label=paste(per, "%", sep="")), color="black", vjust=-0.5)+
  labs(title="Do you have a Facebook account?", x="Facebook user", y="Percentage", caption="AmericasBarometer by LAPOP, 2018/19")+
  coord_cartesian(ylim=c(0, 60))

We consider this option a easier way to work with this data. First, we have to create a dataframe with the percentages and the labels. Then, we have to use this dataframe in ggplot. In the following sections, we will use this way.

Summary

In this document we have worked with nominal categorical variables, such as whether or not you suppport democracy or whether or not you use social networks. We present several ways to describe these variables in frequency tables and to plot these variables, using circular or bar graphs.

Calculations including design effect

The results for the 2018/19 wave are not exactly the same as those in the report, since LAPOP includes the effect of the sample design in its calculations. According to this syntax, it is found that 57.1% of interviewees report being a Facebook user, when 56.2% appear in the report. The same with Twitter, which here is calculated at 8.8% and in the report 7.9%; and with WhatsApp that appears here with 64.6% and in the report with 64.4%. As indicated in the section on the use of survey weights using data from the AmericasBarometer (available here), there are several ways to reproduce the results by incorporating the survey weights. A first option is to use the command freq, which allows the inclusion of a weighting variable, such as “weight1500”. The plot=F specification is included to not produce the bar graphs.

library(descr)
descr::freq(lapop18$fb_user, lapop18$weight1500, plot = F)
## lapop18$fb_user 
##       Frequency Percent Valid Percent
## 0         11337  41.988         43.77
## 1         14564  53.939         56.23
## NA's       1100   4.073              
## Total     27000 100.000        100.00
descr::freq(lapop18$tw_user, lapop18$weight1500, plot = F)
## lapop18$tw_user 
##       Frequency Percent Valid Percent
## 0         23819  88.220        92.023
## 1          2065   7.647         7.977
## NA's       1116   4.133              
## Total     27000 100.000       100.000
descr::freq(lapop18$wa_user, lapop18$weight1500, plot = F)
## lapop18$wa_user 
##       Frequency Percent Valid Percent
## 0          9252  34.266         35.63
## 1         16714  61.903         64.37
## NA's       1035   3.832              
## Total     27000 100.000        100.00

Without considering the survey weights, 57.1% of the interviewees have a Facebook account. This percentage varies to 55.2% if the expansion variable is included, which is the value shown in the report. These weighted results can also be saved to objects and then graphed in the same way as the unweighted results.

In the case of Facebook, the table can be saved as a dataframe, using the command as.data.frame. This table includes data that we do not require, such as the NA’s and Total row and the Percent column. These rows and this column are deleted using the specification [-c(3,4), -2].

The columns are then renamed to avoid the “Valid Percent” name. They are simply named “freq” and “per”. This column “per” is the one that has the data that we will graph. Finally, a “lab” column is added with the labels of each row of results.

fb <- as.data.frame(descr::freq(lapop18$fb_user, lapop18$weight1500, plot = F))
fb = fb[-c(3,4), -2]
colnames(fb) = c("freq", "per")
fb$lab = c("No", "Yes")
fb
##       freq      per lab
## 0 11336.69 43.77052  No
## 1 14563.60 56.22948 Yes

With this new dataframe we can replicate the same codes used above to make a bar chart or a pie chart. The following code displays the bar chart. Note that now the “fb” dataframe is used and that in aes it is specified that the data from the “lab” column must be on the X axis and the data from the “per” column must be on the Y axis.

ggplot(data=fb, aes(x=lab, y=per))+
  geom_bar(stat="identity",  width=0.5)+
  geom_text(aes(label=paste(round(per, 1), "%", sep="")), color="black", vjust=-0.5)+
  labs(title="Do you have a Facebook account?", x="Facebook user", 
       y="Percentage", caption="AmericasBarometer by LAPOP, 2018/19")+
  coord_cartesian(ylim=c(0, 60))

The same can be done to create a pie chart. This graph reproduces the results found in Graph 3.1 of the report.

ggplot(data=fb, 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()+
  labs(caption="AméricasBarometer by LAPOP, 2018/19")+
  scale_fill_discrete(name="Do you have a Facebook account?")+
  xlim(0.5, 2.5)

The second option to reproduce the results in the report is using the package survey. As we indicate in this section, we have to define first the sample design with the command svydesign.

library(survey)
lapop.design = svydesign(ids = ~upm, strata = ~estratopri, weights = ~weight1500, nest=TRUE, data=lapop18)

Once you have created the data with the expansion factor in the “lapop.design” object, you can use the native commands of the package survey to perform calculations. For example, to calculate the frequency distribution table you can use the svytable command.

svytable(~fb_user, design=lapop.design)
## fb_user
##        0        1 
## 11336.69 14563.60

These frequencies can be nested in the prop.table command to calculate the percentages of social network users. These results are the same as those shown in the previous graphs and those that appear in the report.

These data can also be saved in a dataframe that is adapted for graphing, following the same procedure as in the previous graphs.

prop.table(svytable(~fb_user, design=lapop.design))
## fb_user
##         0         1 
## 0.4377052 0.5622948
prop.table(svytable(~tw_user, design=lapop.design))
## tw_user
##          0          1 
## 0.92023002 0.07976998
prop.table(svytable(~wa_user, design=lapop.design))
## wa_user
##         0         1 
## 0.3563091 0.6436909
LS0tCnRpdGxlOiAiRGVzY3JpcHRpdmUgc3RhdGlzdGljcyB1c2luZyB0aGUgQW1lcmljYXNCYXJvbWV0ZXIgKDEpIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlCiAgICB0b2NfZGVwdGg6IDEKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIHRoZW1lOiBmbGF0bHkKICAgICNjb2RlX2ZvbGRpbmc6IGhpZGUKZWRpdG9yX29wdGlvbnM6IAogIG1hcmtkb3duOiAKICAgIHdyYXA6IHNlbnRlbmNlCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0UsIGNhY2hlPVRSVUUpCmBgYAoKYGBge2NzcyBjb2xvciwgZWNobz1GQUxTRX0KLmNvbHVtbnMge2Rpc3BsYXk6IGZsZXg7fQpoMSB7Y29sb3I6ICMzMzY2Q0M7fQpgYGAKCiMgSW50cm9kdWN0aW9uCgpJbiB0aGlzIHNlY3Rpb24gd2Ugd2lsbCBzdGFydCB3aXRoIHRoZSBiYXNpY3Mgb2YgaG93IHRvIHVzZSB0aGUgTEFQT1AgQW1lcmljYXNCYXJvbWV0ZXIgZGF0YXNldCBmb3Igc3RhdGlzdGljYWwgcHVycG9zZXMuCkZpcnN0LCB3ZSB3aWxsIGxvb2sgYXQgdGhlIGJhc2ljcyBvZiBob3cgdG8gZGVzY3JpYmUgYSB2YXJpYWJsZSB1c2luZyBhIGZyZXF1ZW5jeSBkaXN0cmlidXRpb24gdGFibGUgYW5kIGhvdyB0byBncmFwaCB0aGF0IHZhcmlhYmxlIHVzaW5nIHBpZSBvciBiYXIgY2hhcnRzLgpGb3IgdGhhdCwgd2UgYXJlIGdvaW5nIHRvIHVzZSB0aGUgbGF0ZXN0IHJlZ2lvbmFsIHJlcG9ydCAiVGhlIHB1bHNlIG9mIGRlbW9jcmFjeSIsIGF2YWlsYWJsZSBbaGVyZV0oaHR0cHM6Ly93d3cudmFuZGVyYmlsdC5lZHUvbGFwb3AvYWIyMDIxLzIwMjFfTEFQT1BfQW1lcmljYXNCYXJvbWV0ZXJfMjAyMV9QdWxzZV9vZl9EZW1vY3JhY3kucGRmKSwgd2hlcmUgdGhlIG1haW4gZmluZGluZ3Mgb2YgdGhlIDIwMTgvMTkgcm91bmQgb2YgdGhlIEFtZXJpY2FzQmFyb21ldGVyIGFyZSBwcmVzZW50ZWQuCk9uZSBvZiB0aGUgc2VjdGlvbnMgb2YgdGhpcyBkb2N1bWVudCwgcmVwb3J0cyBkYXRhIG9uIHNvY2lhbCBuZXR3b3JrcyBhbmQgcG9saXRpY2FsIGF0dGl0dWRlcy4KSW4gdGhpcyBzZWN0aW9uLCBkYXRhIG9uIHRoZSB1c2Ugb2YgdGhlIGludGVybmV0IGFuZCB0aGUgdXNlIG9mIHNvY2lhbCBuZXR3b3JrcyBhcmUgcHJlc2VudGVkLCBpbiBnZW5lcmFsIGFuZCBieSBjb3VudHJ5LgpXaXRoIHRoZSBkYXRhIGZyb20gdGhlIEFtZXJpY2FzQmFyb21ldGVyLCBpdCBpcyBwb3NzaWJsZSB0byBrbm93IHRoZSBwZXJjZW50YWdlIG9mIGhvdXNlaG9sZHMgd2l0aCBjZWxsIHBob25lIGFjY2Vzcywgd2l0aCBpbnRlcm5ldCBhY2Nlc3MsIGFzIHdlbGwgYXMgdGhlIHBlcmNlbnRhZ2Ugb2YgcGVvcGxlIHdobyB1c2UgV2hhdHNBcHAsIEZhY2Vib29rIG9yIFR3aXR0ZXIuCkluIHRoaXMgZG9jdW1lbnQgd2UgYXJlIGdvaW5nIHRvIHJlcHJvZHVjZSB0aGVzZSByZXN1bHRzLgoKIyBBYm91dCB0aGUgZGF0YXNldAoKVGhlIGRhdGEgdGhhdCB3ZSBhcmUgZ29pbmcgdG8gdXNlIHNob3VsZCBiZSBjaXRlZCBhcyBmb2xsb3dzOiBTb3VyY2U6IEFtZXJpY2FzQmFyb21ldGVyIGJ5IHRoZSBMYXRpbiBBbWVyaWNhbiBQdWJsaWMgT3BpbmlvbiBQcm9qZWN0IChMQVBPUCksIHd3d3cuTGFwb3BTdXJ2ZXlzLm9yZy4KSW4gdGhpcyBkb2N1bWVudCBhIHRyaW1tZWQgZGF0YXNldCBpcyByZWxvYWRlZCBmcm9tIHNjcmF0Y2guCkl0IGlzIHJlY29tbWVuZGVkIGFnYWluIHRvIGNsZWFuIHRoZSBFbnZpcm9ubWVudCBvZiB0aGUgb2JqZWN0cyB1c2VkIGluIHByZXZpb3VzIG1vZHVsZXMuCgpUaGlzIGRhdGFzZXQgaXMgaG9zdGVkIGluIHRoZSAibWF0ZXJpYWxzX2VkdSIgcmVwb3NpdG9yeSBvZiBMQVBPUCdzIEdpdEh1YiBhY2NvdW50LgpVc2luZyB0aGUgbGlicmFyeSBgcmlvYCBhbmQgdGhlIGNvbW1hbmRgaW1wb3J0YCwgdGhpcyBkYXRhc2V0IGNhbiBiZSBpbXBvcnRlZCBmcm9tIHRoaXMgcmVwb3NpdG9yeS4KSW4gYWRkaXRpb24sIHRoZSBkYXRhIGZvciBjb3VudHJpZXMgd2l0aCBjb2RlcyBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gMzUgYXJlIHNlbGVjdGVkLCBpdCBtZWFucyB0aGF0IG9ic2VydmF0aW9ucyBmb3IgdGhlIFVuaXRlZCBTdGF0ZXMgYW5kIENhbmFkYSBhcmUgZWxpbWluYXRlZC4KCmBgYHtyIGJhc2UxOCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShyaW8pCmxhcG9wMTggPSBpbXBvcnQoImh0dHBzOi8vcmF3LmdpdGh1Yi5jb20vbGFwb3AtY2VudHJhbC9tYXRlcmlhbHNfZWR1L21haW4vTEFQT1BfQUJfTWVyZ2VfMjAxOF92MS4wLnNhdiIpCmxhcG9wMTggPSBzdWJzZXQobGFwb3AxOCwgcGFpczw9MzUpCmBgYAoKV2UgYWxzbyBsb2FkIHRoZSAyMDIxIHJvdW5kIGRhdGFzZXQuCgpgYGB7ciBiYXNlMjF9CmxhcG9wMjEgPSBpbXBvcnQoImh0dHBzOi8vcmF3LmdpdGh1Yi5jb20vbGFwb3AtY2VudHJhbC9tYXRlcmlhbHNfZWR1L21haW4vbGFwb3AyMS5SRGF0YSIpCmxhcG9wMjEgPSBzdWJzZXQobGFwb3AyMSwgcGFpczw9MzUpCmBgYAoKIyBTdXBwb3J0IGZvciBkZW1vY3JhY3kKClRoZSByZXBvcnQgVGhlIFB1bHNlIG9mIERlbW9jcmFjeSAyMDIxIHNob3dzIHRoZSByZXN1bHRzIGZvciBzdXBwb3J0IGZvciBkZW1vY3JhY3kgYnkgY291bnRyeS4KRmlndXJlIDEuMSBzaG93cyB0aGUgcGVyY2VudGFnZSBvZiBwZW9wbGUgd2hvIHN1cHBvcnQgZGVtb2NyYWN5IGluIGFic3RyYWN0IGluIGVhY2ggY291bnRyeS4KCiFbXShGaWd1cmUxLjEucG5nKXt3aWR0aD0iNTA4In0KCkluIGEgcHJldmlvdXMgc2VjdGlvbiwgd2UgZXhwbGFpbiBob3cgdG8gcmVjb2RlIHZhcmlhYmxlIElORzQsIG9yaWdpbmFsbHkgbWVhc3VyZWQgaW4gYSAxLTcgc2NhbGUsIHdoZXJlIDEgbWVhbnMgIlN0cm9uZ2x5IGRpZXNhZ3JlZSIgYW5kIDcgbWVhbnMgIlN0cm9uZ2x5IGFncmVlIi4KVmFsdWVzIGJldHdlZW4gNSBhbmQgNyBhcmUgcmVjb2RlZCBhcyAiMSIgYW5kIHRoaXMgdmFsdWUgaWRlbnRpZmllcyB0aG9zZSB3aG8gc3VwcG9ydCBkZW1vY3JhY3kuClRoZSByZXN0IGFyZSByZWNvZGVkIGFzICIwIiwgdGhvc2Ugd2hvIGRvIG5vdCBzdXBwb3J0IGRlbW9jcmFjeS4KVGhlIG5ldyByZWNvZGVkIHZhcmlhYmxlIGFyZSBzYXZlZCBpbiBhIG5ldyB2YXJpYWJsZSAiaW5nNHJlYyIuCgpgYGB7ciByZWNvZGV9CmxpYnJhcnkoY2FyKQpsYXBvcDIxJGluZzRyZWMgPSBjYXI6OnJlY29kZShsYXBvcDIxJGluZzQsICIxOjQ9MDsgNTo3PTEiKQpgYGAKCkluIHN0cmljdCBzZW5zZSwgdGhpcyB2YXJpYWJsZSBpcyBub3QgbnVtZXJpYyBldmVuIHRob3VnaCBpdCBpcyBkZWZpbmVkIGFzICJkYmwiIGluIHRoZSBkYXRhc2V0LCB3aGljaCBpcyBhIHR5cGUgb2YgbnVtZXJpYyB2YXJpYWJsZS4KVGhpcyB2YXJpYWJsZSBpcyBxdWFsaXRhdGl2ZSwgbm9taW5hbCwgdGhhdCBpcyBkZWZpbmVkIGFzIGZhY3RvciBpbiBSLgpGb3IgY29ycmVjdGx5IGRlZmluZWQgYW5kIGxhYmVsbGVkLCB3ZSBoYXZlIHRvIHRyYW5zZm9ybSB0aGlzIHZhcmlhYmxlLgpGaXJzdCwgd2UgaGF2ZSB0byBkZWZpbmUgYXMgZmFjdG9yIHdpdGggdGhlIGNvbW1hbmQgYGFzLmZhY3RvcmAuCgpgYGB7ciBmYWN0b3J9CmxhcG9wMjEkaW5nNHJlYyA9IGFzLmZhY3RvcihsYXBvcDIxJGluZzRyZWMpCmBgYAoKQSBmYWN0b3IgdmFyaWFibGUgY2FuIGhhdmUgbGV2ZWxzIGZvciBlYWNoIG51bWVyaWMgdmFsdWUuClRoZSBkZWZpbml0aW9uIG9mIGxldmVscyBoYXMgdGhlIGdvYWwgdGhhdCB0YWJsZXMgb2YgZmlndXJlcyBkbyBub3Qgc2hvdyBudW1lcmljIGNvZGVzLCBidXQgdGhlIGNvcnJlc3BvbmRpbmcgbGFiZWwuCldlIGNhbiBkbyB0aGlzIHVzaW5nIHRoZSBjb21tYW5kIGBsZXZlbHNgLgpUaGVuLCB3ZSBjYW4gZGVzY3JpYmUgdGhpcyB2YXJpYWJsZSB3aXRoIHRoZSBjb21tYW5kIGB0YWJsZWAgdGhhdCBnaXZlcyBhYnNvbHV0ZSBmcmVxdWVuY2llcyBmb3IgZWFjaCBjYXRlZ29yeSBvZiB0aGlzIHZhcmlhYmxlLgoKYGBge3IgbGV2ZWxzfQpsZXZlbHMobGFwb3AyMSRpbmc0cmVjKSA9IGMoIk5vIiwgIlllcyIpCnRhYmxlKGxhcG9wMjEkaW5nNHJlYykKYGBgCgojIERlc2NyaWJlIHZhcmlhYmxlcwoKQXMgd2Ugc2VlIGluIHRoZSBzZWN0aW9uIE1hbmlwdWxhdGlvbiwgd2UgY2FuIHVzZSB0aGUgY29tbWFuZCBgcHJvcC50YWJsZWAgdG8gb2J0YWluIHJlbGF0aXZlIGZyZXF1ZW5jaWVzIGFuZCB0aGUgY29tbWFuZCBgcm91bmRgIHRvIHNob3cganVzdCBvbmUgZGVjaW1hbC4KCmBgYHtyIHJvdW5kfQpyb3VuZChwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMjEkaW5nNHJlYykpKjEwMCwgMSkKYGBgCgpSZXN1bHRzIHNob3cgdHdvIGNhdGVnb3JpZXMgaW4gdGhlIHZhcmlhYmxlICJzdXBwb3J0IGZvciBkZW1vY3JhY3kiLgpIb3dldmVyLCB0aGlzIHZhcmlhYmxlIGhhcyBtaXNzaW5nIHZhbHVlcy4KRm9yIGdldHRpbmcgYSB0YWJsZSBzaG93aW5nIG1pc3NpbmcgdmFsdWVzLCB3ZSBjYW4gdXNlIHRoZSBjb21tYW5kIGB0YWJsZWAgd2l0aCB0aGUgc3BlY2lmaWNhdGlvbiBgdXNlTkEgPSAiYWx3YXlzImAuCgpgYGB7ciBOQXN9CnJvdW5kKHByb3AudGFibGUodGFibGUobGFwb3AyMSRpbmc0cmVjLCB1c2VOQSA9ICJhbHdheXMiKSkqMTAwLCAxKQpgYGAKClRoaXMgdGFibGUgc2hvd3MgdGhhdCB3ZSBoYXZlIDYuNCUgb2YgbWlzc2luZyBjYXNlcyBvZiB0aGUgdG90YWwgb2JzZXJ2YXRpb25zLgpUaGUgcHJlc2VudGF0aW9uIG9mIG1pc3NpbmcgdmFsdWVzIGluIHRhYmxlcyBvciBmaWd1cmVzIGRlcGVuZHMgb2YgdGhlIHJlc2VhcmNoZXIuCgojIFBsb3QgYSB2YXJpYWJsZQoKV2UgY2FuIHBsb3QgYSB2YXJpYWJsZSBvZiB0eXBlICJmYWN0b3IiIGluIG11bHRpcGxlIHdheXMuCkEgcG9zc2liaWxpdHkgaXMgYnkgYSBjaXJjdWxhciBncmFwaC4KV2UgY2FuIHVzZSB0aGUgY29tbWFuZCBgcGllYCwgd2hpY2ggaXMgcGFydCBvZiB0aGUgYmFzaWMgc3ludGF4IG9mIFIuCldpdGhpbiB0aGlzIGNvbW1hbmQsIHdlIGNhbiBuZXN0IHRoZSBjb21tYW5kIGB0YWJsZWAgdG8gcGxvdCB2YWx1ZXMgb2YgYSBjb250aW5nZW5jeSB0YWJsZS4KCmBgYHtyIHBpZTF9CnBpZSh0YWJsZShsYXBvcDIxJGluZzRyZWMpKQpgYGAKClRoaXMgZmlndXJlIGhhcyBzb21lIG9wdGlvbiB0byBjdXN0b21pemF0aW9uLgpGb3IgZXhhbXBsZSwgdGhlIHNwZWNpZmljYXRpb24gYGxhYmVscyA9IOKApmAgc2VydmVzIHRvIGluY2x1ZGUgdGhlIG51bWJlciBvZiBvYnNlcnZhdGlvbiBpbiBlYWNoIHNlY3RvciwgYW5kIHRoZSBzcGVjaWZpY2F0aW9uIGBjb2wgPeKApmAgd29ya3MgdG8gZGVmaW5lIGNvbG9ycyBvZiBzZWN0b3JzLgoKYGBge3IgcGllMn0KcGllKHRhYmxlKGxhcG9wMjEkaW5nNHJlYyksIGxhYmVscz10YWJsZShsYXBvcDIxJGluZzRyZWMpLCBjb2w9MToyKQpgYGAKCk90aGVyIG9wdGlvbiBpcyB1c2luZyBhIGJhciBwbG90LgpVc2luZyB0aGUgYmFzaWMgY29tbWFuZCBvZiBSLCB3ZSBjYW4gdXNlIGBiYXJwbG90YC4KV2UgbmVzdCB0aGUgY29tbWFuZHMgYHRhYmxlYCBhbmQgYHByb3AudGFibGVgIHdpdGhpbiBgYmFycGxvdGAuCgpgYGB7ciBiYXIxfQpiYXJwbG90KHByb3AudGFibGUodGFibGUobGFwb3AyMSRpbmc0cmVjKSkqMTAwLCBjb2w9MToyKQpgYGAKClRoZSBiYXNlIGNvbW1hbmRzIGluIFIgaGF2ZSBhIGxldmVsIG9mIGN1c3RvbWl6YXRpb24sIGJ1dCB3ZSBoYXZlIGEgc3BlY2lhbGl6ZWQgbGlicmFyeSB0byBwcm9kdWNlIGEgZ3JhcGggd2l0aCBtb3JlIGN1c3RvbWl6YXRpb24gb3B0aW9ucyBjYWxsZWQgYGdncGxvdGAuCkZvciBleGFtcGxlLCB0byByZXByb2R1Y2UgYSBiYXIgcGxvdCBvZiB0aGUgdmFyaWFibGUgc3VwcG9ydCBmb3IgZGVtb2NyYWN5LCB3ZSBjYWxsIHRoZSBsaWJyYXJ5IGBnZ3Bsb3QyYC4KCkluIHRoaXMgZXhhbXBsZSwgd2UgaGF2ZSB0byBkZWZpbmUgdGhlIGJhc2ljIHNwZWNpZmljYXRpb24gd2l0aGluIHRoZSBjb21tYW5kIGBnZ3Bsb3RgLgpUaGlzIGNvbW1hbmQgd29ya3MgYnkgbGF5ZXJzLgpGaXJzdCwgd2Ugc3BlY2lmeSB0aGUgZGF0YSB0byBiZSB1c2VkIHdpdGggYGRhdGE9bGFwb3BgLgpUaGVuLCB0aGUgc3BlY2lmaWNhdGlvbiBgYWVzYCBkZWZpbmVzIHRoZSBhZXN0aGV0aWMgb2YgdGhlIHBsb3QuCkdlbmVyYWxseSwgaXQgaXMgdXNlZCB0byBpbmRpY2F0ZSB3aGF0IHZhcmlhYmxlcyBhcmUgcGxvdHRlZCBpbiB3aGF0IGF4aXMgKHggb3IgeSkuCkluIHRoaXMgY2FzZSwgd2UgYXJlIHdvcmtpbmcgd2l0aCB0aGUgZGF0YSBmcm9tIHNjcmF0Y2gsIGZyb20gdGhlIG9yaWdpbmFsIGRhdGFzZXQgImxhcG9wMjEiLgpUaGlzIG9wdGlvbiBvYmxpZ2VzIHRvICJjYWxjdWxhdGUiIHRoZSBwZXJjZW50YWdlcyB3aXRoaW4gdGhlIHNwZWNpZmljYXRpb24gYGFlc2Agd2l0aCBgeSA9Li5wcm9wLi4qMTAwYC4KQWxzbywgd2Ugc2hvdWxkIHVzZSB0aGUgc3BlY2lmaWNhdGlvbiBgZmlsbCA9YCB0byBkZWZpbmUgdGhhdCBiYXJzIHNob3VsZCBwcmVzZW50IGEgcGVyY2VudGFnZS4KCk90aGVyIGVhc2llciBvcHRpb24gaXMgdG8gY3JlYXRlIGJlZm9yZSBhIHRhYmxlIGZyb20gdGhlIG9yaWdpbmFsIGRhdGEgdGhhdCBjYXB0dXJlcyBwZXJjZW50YWdlcyBhbmQgdG8gdXNlIHRoaXMgdGFibGUgaW4gdGhlIHNwZWNpZmljYXRpb24gYGFlc2AuCkJlbG93LCB3ZSBwcmVzZW50IGV4YW1wbGVzIHVzaW5nIHRoaXMgb3B0aW9uLgoKQWZ0ZXIgdGhlIHNwZWNpZmljYXRpb24gb2YgZGF0YSBhbmQgYXhpcywgd2UgaGF2ZSB0byBkZWZpbmUgdGhlIHR5cGUgb2YgcGxvdCB3ZSB3YW50IHRvIHVzZS4KV2UgZG8gdGhpcyB3aXRoIGdlb21ldHJpZXMgKCJnZW9tIikuCldlIGRlZmluZSBhIGJhc2ljIGJhciBwbG90IHVzaW5nIHRoZSBjb21tYW5kIGBnZW9tX2JhciggKWAsIHdoZXJlIHdlIGRlZmluZSBpbnRlcm5hbGx5IHRoZSB3aWR0aCBvZiBiYXJzLgpXaXRoIHRoZSBzcGVjaWZpY2F0aW9uIGBsYWJzYCB3ZSBkZWZpbmUgdGhlIGxhYmVscyBvZiBheGlzIGFuZCB0aGUgImNhcHRpb24iLgpGaW5hbGx5LCB3aXRoIHRoZSBzcGVjaWZpY2F0aW9uIGBjb29yZF9jYXJ0ZXNpYW5gIHdlIGRlZmluZSBsaW1pdHMgZm9yIHggYXhpcyBmcm9tIDAgdG8gODAuCgpgYGB7ciBnZ2JhcjF9CmxpYnJhcnkoZ2dwbG90MikKZ2dwbG90KGRhdGE9bGFwb3AyMSwgYWVzKHg9aW5nNHJlYykpKwogIGdlb21fYmFyKGFlcyh5PS4ucHJvcC4uKjEwMCwgZ3JvdXA9MSksIHdpZHRoPTAuNSkrCiAgbGFicyh4PSJTdXBwb3J0IGZvciBkZW1vY3JhY3kiLCB5PSJQZXJjZW50YWdlIiwgCiAgICAgICBjYXB0aW9uPSJBbWVyaWNhc0Jhcm9tZXRlciBieSBMQVBPUCwgMjAyMSIpKwogIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCwgODApKQpgYGAKCkFzIHdlIHNheSwgdGhpcyBwbG90IHByZXNlbnRzIGEgYmFyIGZvciB0aGUgcGVyY2VudGFnZSBvZiBtaXNzaW5nIHZhbHVlcy4KSWYgYSByZXNlYXJjaGVyIHdvdWxkIGxpa2UgdG8gcHJlc2VudCBhIHBsb3Qgd2l0aCBwZXJjZW50YWdlcyBvZiB2YWxpZCBjYXNlcywgbWlzc2luZyB2YWx1ZXMgc2hvdWxkIGJlIGRyb3BwZWQuCldlIGNhbiB1c2UgdGhlIGNvbW1hbmQgYHN1YnNldGAgYWdhaW4sIGJ1dCB3aXRoaW4gYGdncGxvdGAgZm9yIHRoZSBjb21tYW5kIChpbnRlcm5hbGx5KSB3b3JrcyB3aXRoIHRoZSB2YXJpYWJsZSBubyBjb25zaWRlcmluZyB0aGUgbWlzc2luZyB2YWx1ZXMuClRoZSBzeW50YXggYCFpcy5uYSggKWAgbWFrZXMgdGhlIGNvbW1hbmQgdG8gbm90IGluY2x1ZGUgbWlzc2luZyB2YWx1ZXMgb2YgYSB2YXJpYWJsZSBpbiBjYWxjdWxhdGlvbnMuCklmIHdlIHdvdWxkIGhhdmUgdXNlZCBgIWlzLm5hKCApYCBvdXQgb2YgYGdncGxvdGAsIHdlIHdvdWxkIGhhdmUgZHJvcHBlZCBhbGwgb2JzZXJ2YXRpb25zIHdpdGggbWlzc2luZyB2YWx1ZXMgaW4gdGhlIGRhdGFzZXQsIGRlY3JlYXNpbmcgdGhlIE4gYW5kIGFmZmVjdGluZyBuZXh0IGNhbGN1bGF0aW9ucy4KCmBgYHtyIGdnYmFyMn0KZ2dwbG90KGRhdGE9c3Vic2V0KGxhcG9wMjEsICFpcy5uYShpbmc0cmVjKSksIGFlcyh4PWluZzRyZWMpKSsKICBnZW9tX2JhcihhZXMoeT0uLnByb3AuLioxMDAsIGdyb3VwPTEpLCB3aWR0aD0wLjUpKwogIGxhYnMoeD0iU3VwcG9ydCBmb3IgZGVtb2NyYWN5IiwgeT0iUGVyY2VudGFnZSIsIAogICAgICAgY2FwdGlvbj0iQW1lcmljYXNCYXJvbWV0ZXIgYnkgTEFQT1AsIDIwMjEiKSsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsIDgwKSkKYGBgCgpVcCB0byB0aGlzIHBvaW50LCB3ZSBoYXZlIHByZXNlbnRlZCBhIGJhciBwbG90IG9mIGEgc2luZ2xlIHZhcmlhYmxlLCBzdXBwb3J0IGZvciBkZW1vY3JhY3ksIGZvciB0aGUgd2hvbGUgc2FtcGxlLCB0aGF0IGluY2x1ZGVzIGFsbCBjb3VudHJpZXMuCkZpZ3VyZSAxLjEgc2hvd3MgdGhlIHBlcmNlbnRhZ2Ugb2Ygc3VwcG9ydCBmb3IgZGVtb2NyYWN5IGJ5IGNvdW50cnkuCldlIHdpbGwgc2VlIHRoaXMgdHlwZSBvZiBwbG90IGluIGEgZm9sbG93aW5nIHNlY3Rpb24uCgojIFNvY2lhbCBtZWRpYSB1c2VycwoKTm93LCB3ZSBhcmUgcHJlc2VudGluZyBhbiBleGFtcGxlIG9mIHRoZSByZXBvcnQgVGhlIFB1bHNlIG9mIERlbW9jcmFjeSBmb3IgdGhlIDIwMTgvMTkgcm91bmQuCldlIGZvbGxvdyBzaW1pbGFyIHByb2NlZHVyZXMgYXMgdGhlIHNlY3Rpb24gYWJvdmUgYW5kIHdlIHdpbGwgcmVwbGljYXRlIHNvbWUgZmlndXJlcyBvZiB0aGUgcmVwb3J0IGZvciB0aGUgMjAxOC8xOSByb3VuZC4KV2UgYXJlIGdvaW5nIHRvIHdvcmsgd2l0aCB0aGVzZSB2YXJpYWJsZXM6IFNNRURJQTEuCkRvIHlvdSBoYXZlIGEgRmFjZWJvb2sgYWNjb3VudD87ClNNRURJQTQuCkRvIHlvdSBoYXZlIGEgVHdpdHRlciBhY2NvdW50PzsKU01FRElBNy4KRG8geW91IGhhdmUgYSBXaGF0c0FwcCBhY2NvdW50Py4KVGhlc2UgcXVlc3Rpb25zIGhhdmUgYXMgYW5zd2VyIG9wdGlvbnM6CgoxLiAgWWVzCgoyLiAgTm8KCldoZW4gcmVhZGluZyB0aGUgZGF0YWJhc2UgaW4gUiwgdGhpcyBwcm9ncmFtIGltcG9ydHMgdGhlIHZhcmlhYmxlcyBhcyAibnVtIiwgd2hpY2ggbW9zdCBmdW5jdGlvbnMgaW4gUiB0cmVhdCBhcyBudW1lcmljLgpUaGVzZSB2YXJpYWJsZXMgaGF2ZSB0byBiZSBjb252ZXJ0ZWQgdG8gdmFyaWFibGVzIG9mIHR5cGUgImZhY3RvciIgd2l0aCB0aGUgY29tbWFuZCBgYXMuZmFjdG9yYCwgc2luY2UgdGhleSBhcmUgY2F0ZWdvcmljYWwgdmFyaWFibGVzLgpXZSBzYXZlIHRoZXNlIG5ldyB2YXJpYWJsZXMgaW4gdGhlIGRhdGFmcmFtZS4KSGVyZSB3ZSBoYXZlIHVzZWQgdGhlIGA9YCBvcGVyYXRvciB3aGljaCBpcyBzaW1pbGFyIHRvIHRoZSBgPC1gIG9wZXJhdG9yIHRoYXQgYXNzaWducyBhIHByb2NlZHVyZSB0byBhIG5ldyBvYmplY3Qgb2YgYW4gUiBkYXRhZnJhbWUuCgpgYGB7ciBmYWN0b3IyfQpsYXBvcDE4JHNtZWRpYTFyID0gYXMuZmFjdG9yKGxhcG9wMTgkc21lZGlhMSkKbGFwb3AxOCRzbWVkaWE0ciA9IGFzLmZhY3RvcihsYXBvcDE4JHNtZWRpYTQpCmxhcG9wMTgkc21lZGlhN3IgPSBhcy5mYWN0b3IobGFwb3AxOCRzbWVkaWE3KQpgYGAKClRoZXNlIG5ldyB2YXJpYWJsZXMgb2YgdHlwZSBmYWN0b3IgaGF2ZSB0byBiZSBsYWJlbGVkIHdpdGggdGhlIGNvbW1hbmQgYGxldmVsc2AuCkEgdmVjdG9yIHdpdGggY29uY2F0ZW5hdGVkIGxhYmVscyBpcyB1c2VkLCB1c2luZyB0aGUgY29tbWFuZCBgYyggKWAuCgpgYGB7ciBsZXZlbDJ9CmxldmVscyhsYXBvcDE4JHNtZWRpYTFyKSA8LSBjKCJZZXMiLCAiTm8iKQpsZXZlbHMobGFwb3AxOCRzbWVkaWE0cikgPC0gYygiWWVzIiwgIk5vIikKbGV2ZWxzKGxhcG9wMTgkc21lZGlhN3IpIDwtIGMoIlllcyIsICJObyIpCmBgYAoKIyBDYWxjdWxhdGluZyB0aGUgdmFyaWFibGVzIG9mIHNvY2lhbCBuZXR3b3JrIHVzZXJzCgpBcyB3ZSBzYXcgaW4gYSBwcmV2aW91cyBtb2R1bGUsIHlvdSBjYW4gY2FsY3VsYXRlIG5ldyB2YXJpYWJsZXMgd2l0aCBjb25kaXRpb25hbCB2YWx1ZXMgb2Ygb3RoZXIgdmFyaWFibGVzIHVzaW5nIHRoZSBgaWZlbHNlYCBjb21tYW5kLgpJbiB0aGlzIHdheSwgd2UgY2FsY3VsYXRlIHRoZSB2YXJpYWJsZXMgb2Ygc29jaWFsIG5ldHdvcmsgdXNlcnMuCgpgYGB7ciB1c2VyfQpsYXBvcDE4JGZiX3VzZXIgPC0gaWZlbHNlKGxhcG9wMTgkc21lZGlhMT09MSAmIGxhcG9wMTgkc21lZGlhMjw9NCwgMSwgMCkKbGFwb3AxOCR0d191c2VyIDwtIGlmZWxzZShsYXBvcDE4JHNtZWRpYTQ9PTEgJiBsYXBvcDE4JHNtZWRpYTU8PTQsIDEsIDApCmxhcG9wMTgkd2FfdXNlciA8LSBpZmVsc2UobGFwb3AxOCRzbWVkaWE3PT0xICYgbGFwb3AxOCRzbWVkaWE4PD00LCAxLCAwKQpgYGAKCiMgRGVzY3JpYmluZyB0aGUgdmFyaWFibGVzCgpXaXRoIHRoZSB2YXJpYWJsZXMgcmVhZHksIHdlIG5vdyBwcm9jZWVkIHRvIG1ha2UgdGhlIGdlbmVyYWwgdGFibGVzIHdpdGggdGhlIGB0YWJsZWAgY29tbWFuZC4KTm90ZSB0aGUgdXNlIG9mIGAjYCBhcyBhIHdheSBvZiBtYWtpbmcgYW5ub3RhdGlvbnMsIHdoaWNoIGFyZSBub3QgUiBjb2RlLgoKYGBge3IgdGFibGVzfQp0YWJsZShsYXBvcDE4JHNtZWRpYTFyKSAjRmFjZWJvb2sKdGFibGUobGFwb3AxOCRzbWVkaWE0cikgI1R3aXR0ZXIKdGFibGUobGFwb3AxOCRzbWVkaWE3cikgI1doYXRzYXBwCmBgYAoKVGhpcyBgdGFibGVgIGNvbW1hbmQgZ2l2ZXMgdXMgdGhlIGFic29sdXRlIGZyZXF1ZW5jaWVzIChudW1iZXIgb2Ygb2JzZXJ2YXRpb25zKSBmb3IgZWFjaCBjYXRlZ29yeSBvZiB2YXJpYWJsZXMgKGluIHRoaXMgY2FzZSBZZXMgYW5kIE5vKS4KVG8gZ2V0IHRoZSByZWxhdGl2ZSBmcmVxdWVuY2llcywgd2Ugd2lsbCB1c2UgdGhlIGNvbW1hbmQgYHByb3AudGFibGVgLCB3aGVyZSB0aGUgcHJldmlvdXMgY29tbWFuZCBgdGFibGVgIGlzIG5lc3RlZC4KCmBgYHtyIHByb3BvcnRpb25zfQpwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMTgkc21lZGlhMXIpKQpwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMTgkc21lZGlhNHIpKQpwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMTgkc21lZGlhN3IpKQpgYGAKCkhvd2V2ZXIsIHRoZSBjb21tYW5kIGBwcm9wLnRhYmxlYCByZXR1cm5zIHVzIHRvbyBtYW55IGRlY2ltYWwgcGxhY2VzIGFuZCB0aGUgcmVsYXRpdmUgZnJlcXVlbmNpZXMgb24gYSBzY2FsZSBvZiAwIHRvIDEuClRvIHJvdW5kIHRoaXMgZmlndXJlIHdlIHVzZSB0aGUgYHJvdW5kYCBjb21tYW5kLCB3aGljaCBhbGxvd3MgdXMgdG8gc3BlY2lmeSB0aGUgbnVtYmVyIG9mIGRlY2ltYWwgcGxhY2VzIHRvIGJlIGRpc3BsYXllZC4KQm90aCB0aGUgYHRhYmxlYCBjb21tYW5kIGFuZCB0aGUgYHByb3AudGFibGVgIGFyZSBuZXN0ZWQgd2l0aGluIHRoaXMgbmV3IGNvbW1hbmQuCkluIHRoaXMgY2FzZSwgd2UgdXNlIDMgZGVjaW1hbHMsIHNvIHdoZW4gaXQgaXMgbXVsdGlwbGllZCBieSAxMDAsIGl0IHJlbWFpbnMgaW4gdGhlIGZvcm0gb2YgYSBwZXJjZW50YWdlIHdpdGggMSBkZWNpbWFsIHBsYWNlLgoKYGBge3IgdGFibGV9CnJvdW5kKHByb3AudGFibGUodGFibGUobGFwb3AxOCRzbWVkaWExcikpLCAzKSoxMDAKcm91bmQocHJvcC50YWJsZSh0YWJsZShsYXBvcDE4JHNtZWRpYTRyKSksIDMpKjEwMApyb3VuZChwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMTgkc21lZGlhN3IpKSwgMykqMTAwCmBgYAoKSXQgaXMgbm90IHByYWN0aWNhbCB0byBwcmVzZW50IDMgdGFibGVzIHdoZW4gdGhlIHZhcmlhYmxlcyBoYXZlIHRoZSBzYW1lIHJlc3BvbnNlIGNhdGVnb3JpZXMuCkZvciBwcmVzZW50YXRpb24gcHVycG9zZXMgaXQgbWlnaHQgYmUgYmV0dGVyIHRvIGJ1aWxkIGEgc2luZ2xlIHRhYmxlLgpZb3UgY2FuIHNhdmUgdGhlIHBhcnRpYWwgdGFibGVzIGluIG5ldyBvYmplY3RzIHdpdGggdGhlIG9wZXJhdG9yIGA9YCBhbmQgdGhlbiBqb2luIHRoZW0gYXMgcm93cyB3aXRoIHRoZSBjb21tYW5kIGByYmluZGAgaW4gYSBuZXcgZGF0YWZyYW1lICJ0YWJsZSIgd2l0aCB0aGUgY29tbWFuZCBgYXMuZGF0YS5mcmFtZWAsIGluIHN1Y2ggYSB3YXkgdGhhdCB0aGUgcmVzcG9uc2VzIHRvIGVhY2ggc29jaWFsIG5ldHdvcmsgYXBwZWFyIGluIHJvd3MuCgpgYGB7ciBmdWxsIHRhYmxlfQpGYWNlYm9vayA9IHJvdW5kKHByb3AudGFibGUodGFibGUobGFwb3AxOCRzbWVkaWExcikpLCAzKSoxMDAKVHdpdHRlciA9IHJvdW5kKHByb3AudGFibGUodGFibGUobGFwb3AxOCRzbWVkaWE0cikpLCAzKSoxMDAKV2hhdHNhcHAgPSByb3VuZChwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMTgkc21lZGlhN3IpKSwgMykqMTAwCnRhYmxhID0gYXMuZGF0YS5mcmFtZShyYmluZChGYWNlYm9vaywgVHdpdHRlciwgV2hhdHNhcHApKQp0YWJsYQpgYGAKClRvIGhhdmUgYSBiZXR0ZXIgcHJlc2VudGF0aW9uIG9mIHRoZSB0YWJsZSwgeW91IGNhbiB1c2UgdGhlIGBrYWJsZWAgY29tbWFuZCBmcm9tIHRoZSBga25pdHJgIHBhY2thZ2UsIHVzaW5nIHRoZSB0YWJsZSBidWlsdCBhYm92ZS4KCmBgYHtyIHRhYmxhbWVqb3JhZGEsIHJlc3VsdHM9J2FzaXMnfQpsaWJyYXJ5KGtuaXRyKQprbml0cjo6a2FibGUodGFibGEsIGZvcm1hdD0ibWFya2Rvd24iKQpgYGAKCiMgUGxvdHRpbmcgdGhlIHZhcmlhYmxlcwoKSW4gR3JhcGggMy4xIG9mIHRoZSByZXBvcnQgaXQgaXMgb2JzZXJ2ZWQgdGhhdCB0aGVzZSBkYXRhIGFyZSByZXBvcnRlZCB0aHJvdWdoIGEgcGllIGNoYXJ0LgoKIVtdKEZpZ3VyZTMuMS5wbmcpe3dpZHRoPSI0NTEifQoKV2UgY2FuIHJlcHJvZHVjZSB0aGF0IGdyYXBoIHVzaW5nIHRoZSBgcGllYCBjb21tYW5kIHdoaWNoIGlzIHBhcnQgb2YgdGhlIGJhc2ljIFIgc3ludGF4LgpXaXRoaW4gdGhpcyBjb21tYW5kIHlvdSBjYW4gbmVzdCB0aGUgYHRhYmxlYCBjb21tYW5kIHRvIGdyYXBoIHRoZXNlIHZhbHVlcy4KCmBgYHtyIHBpZTN9CnBpZSh0YWJsZShsYXBvcDE4JHNtZWRpYTFyKSkKYGBgCgpZb3UgY291bGQgYWxzbyB0aGluayBvZiBhIGJhciBjaGFydC4KVXNpbmcgdGhlIGJhc2ljIFIgY29tbWFuZHMsIHlvdSBjYW4gdXNlIHRoZSBgYmFycGxvdGAgY29tbWFuZC4KCmBgYHtyIGJhcjJ9CmJhcnBsb3QocHJvcC50YWJsZSh0YWJsZShsYXBvcDE4JHNtZWRpYTFyKSkpCmBgYAoKVGhlc2UgZ3JhcGhpY2FsIGNvbW1hbmRzIGhhdmUgb3B0aW9ucyB0byBhZGp1c3QgdGhlIGdyYXBoLCBmb3IgZXhhbXBsZSB0byBpbmNsdWRlIHBlcmNlbnRhZ2VzIGFuZCBhZGp1c3Qgc2NhbGVzLgpCdXQsIHRvIGhhdmUgbW9yZSBncmFwaGljYWwgb3B0aW9ucywgd2UgY2FuIHVzZSB0aGUgYGdncGxvdGAgcGFja2FnZSB0byByZXByb2R1Y2UgdGhlIHBpZSBjaGFydC4KCkluIHRoaXMgZXhhbXBsZSwgd2UgaGF2ZSB0byBkZWZpbmUgZmlyc3QgdGhlIGRhdGEgdG8gYmUgdXNlZC4KVGhlIGBzdWJzZXRgIGNvbW1hbmQgaGFzIGJlZW4gdXNlZCBhZ2FpbiwgYnV0IGluc2lkZSBgZ2dwbG90YCBzbyB0aGF0IHRoZSBjb21tYW5kIChpbnRlcm5hbGx5KSB3b3JrcyB3aXRoIHRoZSB2YXJpYWJsZSBidXQgd2l0aG91dCB0aGUgbWlzc2luZyB2YWx1ZXMuClRoZSBgIWlzLm5hICgpYCBzeW50YXggcHJldmVudHMgdGhlIGNvbW1hbmQgZnJvbSBpbmNsdWRpbmcgbWlzc2luZyB2YWx1ZXMgb2YgYSB2YXJpYWJsZSBpbiBjYWxjdWxhdGlvbnMuCklmIGBkYXRhID0gbGFwb3BgIGhhZCBiZWVuIHVzZWQgdGhlIGdyYXBoIHdvdWxkIGhhdmUgaW5jbHVkZWQgYSBsYXJnZSBzZWN0b3IgY29ycmVzcG9uZGluZyB0byB0aGUgcHJvcG9ydGlvbiBvZiBOQS4KSWYgYCFpcy5uYSAoKWAgaGFkIGJlZW4gdXNlZCBvdXRzaWRlIG9mIGBnZ3Bsb3RgIGNyZWF0aW5nIGEgbmV3IHZhcmlhYmxlLCBhbGwgb2JzZXJ2YXRpb25zIHdpdGggbWlzc2luZyB2YWx1ZXMgd291bGQgaGF2ZSBiZWVuIHJlbW92ZWQsIHdoaWNoIHdvdWxkIGRlY3JlYXNlIHRoZSBOLCBhZmZlY3RpbmcgZnV0dXJlIGNhbGN1bGF0aW9ucy4KClRoZSBgZ2dwbG90YCBjb21tYW5kIHdvcmtzIGJ5IGFkZGluZyBsYXllcnMuClRoZSBgYWVzYCBzcGVjaWZpY2F0aW9uIGlzIHVzZWQgdG8gZGVmaW5lIHRoZSAiYWVzdGhldGljcyIgb2YgdGhlIGdyYXBoLgpJdCBpcyBnZW5lcmFsbHkgdXNlZCB0byBpbmRpY2F0ZSB3aGljaCB2YXJpYWJsZSBpcyBnb2luZyB0byBiZSBncmFwaGVkIG9uIHdoaWNoIGF4aXMgKHggb3IgeSkuCllvdSBjYW4gYWxzbyB1c2UgdGhlIGBmaWxsID1gIHNwZWNpZmljYXRpb24gdG8gZGVmaW5lIHRoZSBncm91cHMgdG8gYmUgZ2VuZXJhdGVkLgoKQWZ0ZXIgc3BlY2lmeWluZyB0aGUgZGF0YSBhbmQgdGhlIGF4ZXMsIHlvdSBoYXZlIHRvIHNwZWNpZnkgdGhlIHR5cGUgb2YgZ3JhcGggeW91IHdhbnQgdG8gbWFrZS4KVGhpcyBpcyBkb25lIHdpdGggZ2VvbWV0cmllcyAoImdlb20iKS4KVGhlcmUgaXMgbm8gZGlyZWN0IGdlb21ldHJ5IHRvIG1ha2UgYSBwaWUgY2hhcnQsIHNvIHlvdSBoYXZlIHRvIGluaXRpYWxseSB1c2UgYSBzaW1wbGUgYmFyIGNoYXJ0LCB1c2luZyB0aGUgY29tbWFuZCBgZ2VvbV9iYXIgKClgLCB3aGVyZSB0aGUgd2lkdGggb2YgdGhlIGJhciBpcyBkZWZpbmVkIGludGVybmFsbHkuCklmIHdlIGxlZnQgdGhlIHN5bnRheCBhdCB0aGlzIHBvaW50LCBhIGJhciB3b3VsZCBiZSBnZW5lcmF0ZWQgdGhhdCB3b3VsZCBiZSBkaXZpZGVkIGJ5IHRoZSB2YWx1ZXMgb2YgdGhlIHZhcmlhYmxlICJzbWVkaWExciIuClRvIGdlbmVyYXRlIHRoZSBwaWUgY2hhcnQsIHlvdSBoYXZlIHRvIGFkZCBhbm90aGVyIGNvbW1hbmQgYGNvb3JkX3BvbGFyYCwgd2hpY2ggdHJhbnNmb3JtcyB0aGUgYmFyIHRvIHBvbGFyIGNvb3JkaW5hdGVzLCBjcmVhdGluZyBhIHBpZSBjaGFydC4KCmBgYHtyIGdncGllLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KGdncGxvdDIpICNsaWJyZXLDrWEgZXNwZWNpYWxpemFkYSBlbiBncsOhZmljb3MKZ2dwbG90KGRhdGE9c3Vic2V0KGxhcG9wMTgsICFpcy5uYShzbWVkaWExcikpLCBhZXMoeD0iIiwgZmlsbD1zbWVkaWExcikpKwogIGdlb21fYmFyKHdpZHRoPTEpICsKICBjb29yZF9wb2xhcigieSIsIHN0YXJ0PTApCmBgYAoKVGhlIGFib3ZlIGdyYXBoIGhhcyBzdGFydGVkIGZyb20gdGhlIHNhbWUgZGF0YWZyYW1lICJsYXBvcDE4IiwgdXNpbmcgdGhlIGRhdGEgZnJvbSAic21lZGlhMXIiLgpIb3dldmVyLCB0byBiZXR0ZXIgbWFuaXB1bGF0ZSB0aGUgZ3JhcGggaXQgaXMgZWFzaWVyIHRvIGNyZWF0ZSBhIG5ldyBkYXRhZnJhbWUgd2l0aCB0aGUgYWdncmVnYXRlZCBkYXRhIChmcmVxdWVuY2llcyBhbmQgJSkuCkluIG90aGVyIHdvcmRzLCBzYXZlIHRoZSByZXN1bHRzIGRhdGEgZnJvbSB0aGUgInNtZWRpYTFyIiB0YWJsZSBpbiBhIG5ldyBkYXRhZnJhbWUuClRoZW4gdGhhdCBuZXcgZGF0YWZyYW1lIGlzIHVzZWQgdG8gbWFrZSB0aGUgcGllIGdyYXBoIHdpdGggYGdncGxvdGAuCgpPbmUgYXNwZWN0IHRvIG5vdGUgaXMgdGhhdCBpbiB0aGlzIGNhc2UgdGhlIHRpZHl2ZXJzZSBpcyBiZWluZyB1c2VkLCB3aGljaCBpbmNsdWRlcyB0aGUgcGlwZSBgJT4lYCBjb21tYW5kIGZyb20gdGhlIGBkcGx5cmAgbGlicmFyeSwgd2hpY2ggaXMgYSAoc2xpZ2h0bHkpIGRpZmZlcmVudCB3YXkgb2Ygd3JpdGluZyBjb2RlIGluIFIsIGluIGEgY29uY2F0ZW5hdGVkIHdheSwgc3RlcCBieSBzdGVwLgpBIHNpbXBsZSBleHBsYW5hdGlvbiBvZiBob3cgdGhlIHBpcGUgaXMgdXNlZCBjYW4gYmUgZm91bmQgW2hlcmVdKGh0dHBzOi8vcHN5ci5kam5hdmFycm8ubmV0L3ByZWx1ZGUtdG8tZGF0YS5odG1sIzEyNF90aGVfcGlwZSxfJSUpLgoKVGhlIGZpcnN0IHRoaW5nIHRvIG5vdGljZSBpcyB0aGF0IGEgbmV3IG9iamVjdCBjYWxsZWQgImRmIiBpcyBnb2luZyB0byBiZSBjcmVhdGVkLgpJbmZvcm1hdGlvbiBjb21pbmcgZnJvbSB0aGUgZGF0YWZyYW1lICJsYXBvcDE4IiB3aWxsIGJlIHN0b3JlZCBpbiB0aGlzIG9iamVjdC4KVGhlIGBzdWJzZXRgIGNvbW1hbmQgaXMgdXNlZCB0byByZW1vdmUgdGhlIG1pc3NpbmcgdmFsdWVzIG9mICJzbWVkaWExciIgZnJvbSB0aGUgY2FsY3VsYXRpb24gb2YgdGhlIHBlcmNlbnRhZ2VzLgpUaGVuIChgJT4lYCksIHRoaXMgZGF0YSB3aWxsIGJlIGdyb3VwZWQgYnkgY2F0ZWdvcmllcyBvZiB0aGUgdmFyaWFibGUgInNtZWRpYTFyIi4KTmV4dCAoYCU+JWApLCBpbiBlYWNoIGdyb3VwIHRoZSB0b3RhbCBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zIGlzIGNhbGN1bGF0ZWQgd2l0aCB0aGUgY29tbWFuZCBgc3VtbWFyaXNlKG4gPSBuKCkpYC4KRmluYWxseSAobGFzdCBzdGVwIHdpdGggYCU+JWApLCB3aXRoIHRoaXMgdG90YWwgYnkgZ3JvdXBzIHRoZSBwZXJjZW50YWdlcyBhcmUgY2FsY3VsYXRlZCBhbmQgdGhlc2UgcGVyY2VudGFnZXMgYXJlIHNhdmVkIGluIGEgbmV3IGNvbHVtbiAicGVyIi4KCmBgYHtyIHN1bW1hcnl0YWJsZSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShkcGx5cikKZGYgPSBzdWJzZXQobGFwb3AxOCwgIWlzLm5hKHNtZWRpYTFyKSkgJT4lCiAgICAgIGdyb3VwX2J5KHNtZWRpYTFyKSAlPiUgCiAgICAgIGRwbHlyOjpzdW1tYXJpc2UobiA9IG4oKSkgJT4lCiAgICAgIG11dGF0ZShwZXI9cm91bmQobi9zdW0obiksIDMpKjEwMCkKZGYKYGBgCgpXaXRoIHRoaXMgc3ludGF4LCBhIHRhYmxlIGlzIGNyZWF0ZWQgY29udGFpbmluZyB0aGUgdG90YWwgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBhbmQgdGhlIHBlcmNlbnRhZ2UgZm9yIGVhY2ggY2F0ZWdvcnkgb2YgdGhlIHZhcmlhYmxlICJzbWVkaWExciIuCkEgbW9yZSBkaXJlY3Qgd2F5IHRvIGNyZWF0ZSB0aGUgc2FtZSBkYXRhIGlzIHRvIHVzZSB0aGUgYGphbml0b3JgIGxpYnJhcnkgYW5kIHRoZSBgdGFieWxgIGNvbW1hbmQuCkluIFIgdGhlcmUgYXJlIG11bHRpcGxlIHdheXMgdG8gZ2V0IHRvIHRoZSBzYW1lIHJlc3VsdHMuCgpgYGB7ciBzdW1tYXJ5dGFibGUyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KGphbml0b3IpCnN1YnNldChsYXBvcDE4LCAhaXMubmEoc21lZGlhMXIpKSAlPiUKICB0YWJ5bChzbWVkaWExcikKYGBgCgpPbmNlIHdlIGhhdmUgdGhlIHRhYmxlLCB3ZSBjYW4gdXNlIGl0IHRvIHByb2R1Y2UgdGhlIHBpZSBjaGFydCB3aXRoIGBnZ3Bsb3RgLgpOb3RlIHRoYXQgaW4gdGhpcyBjYXNlIHRoZSBkYXRhIHVzZWQgY29tZXMgZnJvbSB0aGUgZGF0YWZyYW1lIGRmIChub3QgZnJvbSBsYXBvcDE4KS4KVGhpcyBkYXRhZnJhbWUgaGFzIGEgY29sdW1uIGNhbGxlZCAicGVyIiB3aXRoIHRoZSByZXNwZWN0aXZlIHBlcmNlbnRhZ2VzLCB3aGljaCBzaG91bGQgYmUgcGxvdHRlZCBvbiB0aGUgWS1heGlzLgpBcyBpbiB0aGUgcHJldmlvdXMgY2FzZSwgdG8gbWFrZSB0aGUgcGllIGNoYXJ0LCB3ZSBzdGFydCBmcm9tIHRoZSBiYXIgY2hhcnQgKGhlbmNlIGBnZW9tX2JhcmApLCB3aGljaCBpcyB0aGVuIHBhc3NlZCB0byBwb2xhciBjb29yZGluYXRlcyAoaGVuY2UgYGNvb3JkX3BvbGFyYCkuCgpBIHRleHQgbGF5ZXIgaXMgYWRkZWQsIHdpdGggdGhlIHNwZWNpZmljYXRpb24gYGdlb21fdGV4dGAuCldpdGhpbiB0aGlzIHNwZWNpZmljYXRpb24sIGFuICJhZXN0aGV0aWMiIGlzIGRldGVybWluZWQgd2l0aCB0aGUgZGF0YSBsYWJlbCBgYWVzKGxhYmVsPS4uLilgLCB3aGVyZSB0aGUgcGVyY2VudGFnZSBkYXRhICJwZXIiIGFuZCB0aGUgc3ltYm9sICIlIiBhcmUgam9pbmVkIHdpdGggdGhlIGBwYXN0ZWAgY29tbWFuZCwgd2l0aCBhIHNwYWNlIChgc2VwPS4uLmApIGJldHdlZW4gdGhlbS4KU2V0IHRoZSBmb250IGNvbG9yIHdpdGggYGNvbG9yPSIuLi4iYCwgc2V0cyB0byB3aGl0ZSB0byBjb250cmFzdCB3aXRoIHRoZSBjb2xvcnMgb2YgdGhlIHBpZSBjaGFydC4KV2l0aCB0aGUgY29tbWFuZCBgaGp1c3Q9Li4uYCB0aGUgaG9yaXpvbnRhbCBwb3NpdGlvbiBvZiB0aGlzIHRleHQgaXMgYWRqdXN0ZWQuClRoZSBgZ2dwbG90YCBjb21tYW5kIGNhbiBpbmNsdWRlIHZhcmlvdXMgInRoZW1lcyIgZm9yIHRoZSBwbG90LgpJbiB0aGlzIGNhc2UsIGB0aGVtZV92b2lkKClgIGhhcyBiZWVuIHVzZWQsIHdoaWNoIGluZGljYXRlcyBhbiBlbXB0eSBiYWNrZ3JvdW5kLgpGaW5hbGx5LCB3aXRoIHRoZSBzcGVjaWZpY2F0aW9uIGBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWU9Li4uKWAgeW91IGNhbiBjaGFuZ2UgdGhlIHRpdGxlIG9mIHRoZSBsZWdlbmQgc28gdGhhdCBpdCBkb2VzIG5vdCBzaG93IHRoZSBuYW1lIG9mIHRoZSB2YXJpYWJsZSwgYnV0IGEgbW9yZSBzdWl0YWJsZSBsYWJlbC4KCmBgYHtyIGdncGllMn0KZ2dwbG90KGRhdGE9ZGYsIGFlcyh4PSIiLCB5PXBlciwgZmlsbD1zbWVkaWExcikpKwogIGdlb21fYmFyKHdpZHRoPTEsIHN0YXQ9ImlkZW50aXR5IikrCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1wYXN0ZShwZXIsICIlIiwgc2VwPSIiKSksIGNvbG9yPSJ3aGl0ZSIsCiAgICAgICAgICAgIHBvc2l0aW9uPXBvc2l0aW9uX3N0YWNrKHZqdXN0PTAuNSksIHNpemU9MykrCiAgY29vcmRfcG9sYXIoInkiKSsKICB0aGVtZV92b2lkKCkrCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZShuYW1lPSJEbyB5b3UgaGF2ZSBhIEZhY2Vib29rIGFjY291bnQ/IikKYGBgCgpJZiBpbnN0ZWFkIG9mIGEgcGllIGNoYXJ0IHlvdSB3YW50IHRvIGRpc3BsYXkgYSBiYXIgY2hhcnQsIHdpdGggdGhlIGRhdGEgZnJvbSB0aGUgImxhcG9wMTgiIGRhdGFmcmFtZSB5b3UgY2FuIHVzZSB0aGUgZm9sbG93aW5nIGNvZGUuClVubGlrZSB0aGUgZmlyc3QgcGllIGNoYXJ0LCB0aGUgYGFlcyguLilgIHNwZWNpZmljYXRpb24gbm93IGluY2x1ZGVzIHRoZSB2YXJpYWJsZSAic21lZGlhMXIiIGFzIHRoZSB2YXJpYWJsZSB0byBiZSBwbG90dGVkIG9uIHRoZSBYLWF4aXMuCkluc2lkZSB0aGUgZ2VvbWV0cmljIG9iamVjdCBgZ2VvbV9iYXIoKWAgaXQgaXMgaW5kaWNhdGVkIHRoYXQgdGhlIGJhciBtdXN0IHJlcHJlc2VudCB0aGUgcHJvcG9ydGlvbnMgaW4gcGVyY2VudGFnZXMgYGFlcyh5PS4ucHJvcC4uKjEwMCwgZ3JvdXA9MSlgLgpJbiB0aGlzIGV4YW1wbGUsIGEgZ2VuZXJhbCBsYWJlbCBmb3IgdGhlIGdyYXBoIGFuZCBmb3IgdGhlIGF4ZXMgaGFzIGJlZW4gaW5jbHVkZWQgd2l0aCB0aGUgYGxhYnMoLi4uKWAgY29tbWFuZC4KSW4gdGhpcyBjb21tYW5kIHlvdSBjYW4gYWxzbyBhZGQgYSAiY2FwdGlvbiIgdG8gaW5kaWNhdGUgdGhlIHNvdXJjZSBvZiB0aGUgZGF0YS4KRmluYWxseSwgdGhlIHNwZWNpZmljYXRpb24gYGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCw2MCkpYCBsaW1pdHMgdGhlIFkgYXhpcyB0byB2YWx1ZXMgYmV0d2VlbiAwIGFuZCA2MC4KCmBgYHtyIGdnYmFyM30KZ2dwbG90KGRhdGE9c3Vic2V0KGxhcG9wMTgsICFpcy5uYShzbWVkaWExcikpLCBhZXMoeD1zbWVkaWExcikpKwogIGdlb21fYmFyKGFlcyh5PS4ucHJvcC4uKjEwMCwgZ3JvdXA9MSksIHdpZHRoPTAuNSkrCiAgbGFicyh0aXRsZT0iRG8geW91IGhhdmUgYSBGYWNlYm9vayBhY2NvdW50PyIsIHg9IkZhY2Vib29rIHVzZXIiLCB5PSJQZXJjZW50YWdlIiwgY2FwdGlvbj0iQW1lcmljYXNCYXJvbWV0ZXIgYnkgTEFQT1AsIDIwMTgvMTkiKSsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsIDYwKSkKYGBgCgpJbiB0aGlzIGNhc2UgeW91IGNhbiBhbHNvIHVzZSB0aGUgZ3JvdXBlZCBkYXRhIG9mIHRoZSAiZGYiIGRhdGFmcmFtZS4KVW5saWtlIHRoZSBwcmV2aW91cyBvcHRpb24sIGluICJkZiIgdGhlcmUgaXMgdGhlIHBlcmNlbnRhZ2UgZGF0YSwgc28gaXQgc2hvdWxkIG5vdCBiZSBjYWxjdWxhdGVkIGluIHRoZSBjb2RlLCBzbyBpbiB0aGUgYWVzdGhldGljcyBzcGVjaWZpY2F0aW9uIGl0IGluZGljYXRlcyB0aGF0IHRoZSBhbHRlcm5hdGl2ZXMgc2hvdWxkIGJlIHNob3duIG9uIHRoZSBYIGF4aXMgb2YgdGhlIHZhcmlhYmxlICJzbWVkaWExciIgYW5kIG9uIHRoZSBZIGF4aXMgdGhlIHBlcmNlbnRhZ2UsIGluIHRoaXMgd2F5IGBhZXMoeD1tZWRpYTFyLCB5PXBlcilgLgpGb3IgdGhpcyByZWFzb24gYWxzbyBpbiB0aGUgYGdlb21fYmFyYCBzcGVjaWZpY2F0aW9uLCBub3cgaW5zdGVhZCBvZiByZXF1aXJpbmcgdGhlIGNhbGN1bGF0aW9uIG9mIHRoZSBwZXJjZW50YWdlLCBpdCBpcyBvbmx5IGluZGljYXRlZCB0byByZXBsaWNhdGUgdGhlIGRhdGEgKHdpdGggYHN0YXQ9ImlkZW50aXR5ImApIGZyb20gYGFlc2AuCkZpbmFsbHksIGluIHRoaXMgY2FzZSB3ZSBhZGQgdGhlIHRleHQgbGF5ZXIgdG8gaW5jbHVkZSB0aGUgcGVyY2VudGFnZXMgaW4gZWFjaCBjb2x1bW4sIHdpdGggdGhlIGBnZW9tX3RleHRgIHNwZWNpZmljYXRpb24uCgpgYGB7ciB9CmdncGxvdChkZiwgYWVzKHg9c21lZGlhMXIsIHk9cGVyKSkrCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCAgd2lkdGg9MC41KSsKICBnZW9tX3RleHQoYWVzKGxhYmVsPXBhc3RlKHBlciwgIiUiLCBzZXA9IiIpKSwgY29sb3I9ImJsYWNrIiwgdmp1c3Q9LTAuNSkrCiAgbGFicyh0aXRsZT0iRG8geW91IGhhdmUgYSBGYWNlYm9vayBhY2NvdW50PyIsIHg9IkZhY2Vib29rIHVzZXIiLCB5PSJQZXJjZW50YWdlIiwgY2FwdGlvbj0iQW1lcmljYXNCYXJvbWV0ZXIgYnkgTEFQT1AsIDIwMTgvMTkiKSsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsIDYwKSkKYGBgCgpXZSBjb25zaWRlciB0aGlzIG9wdGlvbiBhIGVhc2llciB3YXkgdG8gd29yayB3aXRoIHRoaXMgZGF0YS4KRmlyc3QsIHdlIGhhdmUgdG8gY3JlYXRlIGEgZGF0YWZyYW1lIHdpdGggdGhlIHBlcmNlbnRhZ2VzIGFuZCB0aGUgbGFiZWxzLgpUaGVuLCB3ZSBoYXZlIHRvIHVzZSB0aGlzIGRhdGFmcmFtZSBpbiBgZ2dwbG90YC4KSW4gdGhlIGZvbGxvd2luZyBzZWN0aW9ucywgd2Ugd2lsbCB1c2UgdGhpcyB3YXkuCgojIFN1bW1hcnkKCkluIHRoaXMgZG9jdW1lbnQgd2UgaGF2ZSB3b3JrZWQgd2l0aCBub21pbmFsIGNhdGVnb3JpY2FsIHZhcmlhYmxlcywgc3VjaCBhcyB3aGV0aGVyIG9yIG5vdCB5b3Ugc3VwcHBvcnQgZGVtb2NyYWN5IG9yIHdoZXRoZXIgb3Igbm90IHlvdSB1c2Ugc29jaWFsIG5ldHdvcmtzLgpXZSBwcmVzZW50IHNldmVyYWwgd2F5cyB0byBkZXNjcmliZSB0aGVzZSB2YXJpYWJsZXMgaW4gZnJlcXVlbmN5IHRhYmxlcyBhbmQgdG8gcGxvdCB0aGVzZSB2YXJpYWJsZXMsIHVzaW5nIGNpcmN1bGFyIG9yIGJhciBncmFwaHMuCgojIENhbGN1bGF0aW9ucyBpbmNsdWRpbmcgZGVzaWduIGVmZmVjdAoKVGhlIHJlc3VsdHMgZm9yIHRoZSAyMDE4LzE5IHdhdmUgYXJlIG5vdCBleGFjdGx5IHRoZSBzYW1lIGFzIHRob3NlIGluIHRoZSByZXBvcnQsIHNpbmNlIExBUE9QIGluY2x1ZGVzIHRoZSBlZmZlY3Qgb2YgdGhlIHNhbXBsZSBkZXNpZ24gaW4gaXRzIGNhbGN1bGF0aW9ucy4KQWNjb3JkaW5nIHRvIHRoaXMgc3ludGF4LCBpdCBpcyBmb3VuZCB0aGF0IDU3LjElIG9mIGludGVydmlld2VlcyByZXBvcnQgYmVpbmcgYSBGYWNlYm9vayB1c2VyLCB3aGVuIDU2LjIlIGFwcGVhciBpbiB0aGUgcmVwb3J0LgpUaGUgc2FtZSB3aXRoIFR3aXR0ZXIsIHdoaWNoIGhlcmUgaXMgY2FsY3VsYXRlZCBhdCA4LjglIGFuZCBpbiB0aGUgcmVwb3J0IDcuOSU7IGFuZCB3aXRoIFdoYXRzQXBwIHRoYXQgYXBwZWFycyBoZXJlIHdpdGggNjQuNiUgYW5kIGluIHRoZSByZXBvcnQgd2l0aCA2NC40JS4KQXMgaW5kaWNhdGVkIGluIHRoZSBzZWN0aW9uIG9uIHRoZSB1c2Ugb2Ygc3VydmV5IHdlaWdodHMgdXNpbmcgZGF0YSBmcm9tIHRoZSBBbWVyaWNhc0Jhcm9tZXRlciAoYXZhaWxhYmxlIFtoZXJlXShodHRwczovL2FydHVyb21hbGRvbmFkby5naXRodWIuaW8vQmFyb21ldHJvRWR1X1dlYl9FbmcvRXhwYW5zaW9uLmh0bWwpKSwgdGhlcmUgYXJlIHNldmVyYWwgd2F5cyB0byByZXByb2R1Y2UgdGhlIHJlc3VsdHMgYnkgaW5jb3Jwb3JhdGluZyB0aGUgc3VydmV5IHdlaWdodHMuCkEgZmlyc3Qgb3B0aW9uIGlzIHRvIHVzZSB0aGUgY29tbWFuZCBgZnJlcWAsIHdoaWNoIGFsbG93cyB0aGUgaW5jbHVzaW9uIG9mIGEgd2VpZ2h0aW5nIHZhcmlhYmxlLCBzdWNoIGFzICJ3ZWlnaHQxNTAwIi4KVGhlIGBwbG90PUZgIHNwZWNpZmljYXRpb24gaXMgaW5jbHVkZWQgdG8gbm90IHByb2R1Y2UgdGhlIGJhciBncmFwaHMuCgpgYGB7ciB3ZWlnaHRlZCBkZXNjcmlwdGl2ZX0KbGlicmFyeShkZXNjcikKZGVzY3I6OmZyZXEobGFwb3AxOCRmYl91c2VyLCBsYXBvcDE4JHdlaWdodDE1MDAsIHBsb3QgPSBGKQpkZXNjcjo6ZnJlcShsYXBvcDE4JHR3X3VzZXIsIGxhcG9wMTgkd2VpZ2h0MTUwMCwgcGxvdCA9IEYpCmRlc2NyOjpmcmVxKGxhcG9wMTgkd2FfdXNlciwgbGFwb3AxOCR3ZWlnaHQxNTAwLCBwbG90ID0gRikKYGBgCgpXaXRob3V0IGNvbnNpZGVyaW5nIHRoZSBzdXJ2ZXkgd2VpZ2h0cywgNTcuMSUgb2YgdGhlIGludGVydmlld2VlcyBoYXZlIGEgRmFjZWJvb2sgYWNjb3VudC4KVGhpcyBwZXJjZW50YWdlIHZhcmllcyB0byA1NS4yJSBpZiB0aGUgZXhwYW5zaW9uIHZhcmlhYmxlIGlzIGluY2x1ZGVkLCB3aGljaCBpcyB0aGUgdmFsdWUgc2hvd24gaW4gdGhlIHJlcG9ydC4KVGhlc2Ugd2VpZ2h0ZWQgcmVzdWx0cyBjYW4gYWxzbyBiZSBzYXZlZCB0byBvYmplY3RzIGFuZCB0aGVuIGdyYXBoZWQgaW4gdGhlIHNhbWUgd2F5IGFzIHRoZSB1bndlaWdodGVkIHJlc3VsdHMuCgpJbiB0aGUgY2FzZSBvZiBGYWNlYm9vaywgdGhlIHRhYmxlIGNhbiBiZSBzYXZlZCBhcyBhIGRhdGFmcmFtZSwgdXNpbmcgdGhlIGNvbW1hbmQgYGFzLmRhdGEuZnJhbWVgLgpUaGlzIHRhYmxlIGluY2x1ZGVzIGRhdGEgdGhhdCB3ZSBkbyBub3QgcmVxdWlyZSwgc3VjaCBhcyB0aGUgTkEncyBhbmQgVG90YWwgcm93IGFuZCB0aGUgUGVyY2VudCBjb2x1bW4uClRoZXNlIHJvd3MgYW5kIHRoaXMgY29sdW1uIGFyZSBkZWxldGVkIHVzaW5nIHRoZSBzcGVjaWZpY2F0aW9uIGBbLWMoMyw0KSwgLTJdYC4KClRoZSBjb2x1bW5zIGFyZSB0aGVuIHJlbmFtZWQgdG8gYXZvaWQgdGhlICJWYWxpZCBQZXJjZW50IiBuYW1lLgpUaGV5IGFyZSBzaW1wbHkgbmFtZWQgImZyZXEiIGFuZCAicGVyIi4KVGhpcyBjb2x1bW4gInBlciIgaXMgdGhlIG9uZSB0aGF0IGhhcyB0aGUgZGF0YSB0aGF0IHdlIHdpbGwgZ3JhcGguCkZpbmFsbHksIGEgImxhYiIgY29sdW1uIGlzIGFkZGVkIHdpdGggdGhlIGxhYmVscyBvZiBlYWNoIHJvdyBvZiByZXN1bHRzLgoKYGBge3IgdGFibGUgZmJ9CmZiIDwtIGFzLmRhdGEuZnJhbWUoZGVzY3I6OmZyZXEobGFwb3AxOCRmYl91c2VyLCBsYXBvcDE4JHdlaWdodDE1MDAsIHBsb3QgPSBGKSkKZmIgPSBmYlstYygzLDQpLCAtMl0KY29sbmFtZXMoZmIpID0gYygiZnJlcSIsICJwZXIiKQpmYiRsYWIgPSBjKCJObyIsICJZZXMiKQpmYgpgYGAKCldpdGggdGhpcyBuZXcgZGF0YWZyYW1lIHdlIGNhbiByZXBsaWNhdGUgdGhlIHNhbWUgY29kZXMgdXNlZCBhYm92ZSB0byBtYWtlIGEgYmFyIGNoYXJ0IG9yIGEgcGllIGNoYXJ0LgpUaGUgZm9sbG93aW5nIGNvZGUgZGlzcGxheXMgdGhlIGJhciBjaGFydC4KTm90ZSB0aGF0IG5vdyB0aGUgImZiIiBkYXRhZnJhbWUgaXMgdXNlZCBhbmQgdGhhdCBpbiBhZXMgaXQgaXMgc3BlY2lmaWVkIHRoYXQgdGhlIGRhdGEgZnJvbSB0aGUgImxhYiIgY29sdW1uIG11c3QgYmUgb24gdGhlIFggYXhpcyBhbmQgdGhlIGRhdGEgZnJvbSB0aGUgInBlciIgY29sdW1uIG11c3QgYmUgb24gdGhlIFkgYXhpcy4KCmBgYHtyIHdlaWdodGVkIGJhcnN9CmdncGxvdChkYXRhPWZiLCBhZXMoeD1sYWIsIHk9cGVyKSkrCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCAgd2lkdGg9MC41KSsKICBnZW9tX3RleHQoYWVzKGxhYmVsPXBhc3RlKHJvdW5kKHBlciwgMSksICIlIiwgc2VwPSIiKSksIGNvbG9yPSJibGFjayIsIHZqdXN0PS0wLjUpKwogIGxhYnModGl0bGU9IkRvIHlvdSBoYXZlIGEgRmFjZWJvb2sgYWNjb3VudD8iLCB4PSJGYWNlYm9vayB1c2VyIiwgCiAgICAgICB5PSJQZXJjZW50YWdlIiwgY2FwdGlvbj0iQW1lcmljYXNCYXJvbWV0ZXIgYnkgTEFQT1AsIDIwMTgvMTkiKSsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsIDYwKSkKYGBgCgpUaGUgc2FtZSBjYW4gYmUgZG9uZSB0byBjcmVhdGUgYSBwaWUgY2hhcnQuClRoaXMgZ3JhcGggcmVwcm9kdWNlcyB0aGUgcmVzdWx0cyBmb3VuZCBpbiBHcmFwaCAzLjEgb2YgdGhlIHJlcG9ydC4KCmBgYHtyIHdlaWdodGVkIHBpZX0KZ2dwbG90KGRhdGE9ZmIsIGFlcyh4PTIsIHk9cGVyLCBmaWxsPWxhYikpKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikrCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1wYXN0ZShyb3VuZChwZXIsIDEpLCAiJSIsIHNlcD0iIikpLCBjb2xvcj0id2hpdGUiLCAKICAgICAgICAgICAgcG9zaXRpb249cG9zaXRpb25fc3RhY2sodmp1c3Q9MC41KSwgc2l6ZT0zKSsKICBjb29yZF9wb2xhcigieSIpKwogIHRoZW1lX3ZvaWQoKSsKICBsYWJzKGNhcHRpb249IkFtw6lyaWNhc0Jhcm9tZXRlciBieSBMQVBPUCwgMjAxOC8xOSIpKwogIHNjYWxlX2ZpbGxfZGlzY3JldGUobmFtZT0iRG8geW91IGhhdmUgYSBGYWNlYm9vayBhY2NvdW50PyIpKwogIHhsaW0oMC41LCAyLjUpCmBgYAoKVGhlIHNlY29uZCBvcHRpb24gdG8gcmVwcm9kdWNlIHRoZSByZXN1bHRzIGluIHRoZSByZXBvcnQgaXMgdXNpbmcgdGhlIHBhY2thZ2UgYHN1cnZleWAuCkFzIHdlIGluZGljYXRlIGluIHRoaXMgW3NlY3Rpb25dKGh0dHBzOi8vYXJ0dXJvbWFsZG9uYWRvLmdpdGh1Yi5pby9CYXJvbWV0cm9FZHVfV2ViX0VuZy9FeHBhbnNpb24uaHRtbCksIHdlIGhhdmUgdG8gZGVmaW5lIGZpcnN0IHRoZSBzYW1wbGUgZGVzaWduIHdpdGggdGhlIGNvbW1hbmQgYHN2eWRlc2lnbmAuCgpgYGB7ciBzdXJ2ZXl9CmxpYnJhcnkoc3VydmV5KQpsYXBvcC5kZXNpZ24gPSBzdnlkZXNpZ24oaWRzID0gfnVwbSwgc3RyYXRhID0gfmVzdHJhdG9wcmksIHdlaWdodHMgPSB+d2VpZ2h0MTUwMCwgbmVzdD1UUlVFLCBkYXRhPWxhcG9wMTgpCmBgYAoKT25jZSB5b3UgaGF2ZSBjcmVhdGVkIHRoZSBkYXRhIHdpdGggdGhlIGV4cGFuc2lvbiBmYWN0b3IgaW4gdGhlICJsYXBvcC5kZXNpZ24iIG9iamVjdCwgeW91IGNhbiB1c2UgdGhlIG5hdGl2ZSBjb21tYW5kcyBvZiB0aGUgcGFja2FnZSBgc3VydmV5YCB0byBwZXJmb3JtIGNhbGN1bGF0aW9ucy4KRm9yIGV4YW1wbGUsIHRvIGNhbGN1bGF0ZSB0aGUgZnJlcXVlbmN5IGRpc3RyaWJ1dGlvbiB0YWJsZSB5b3UgY2FuIHVzZSB0aGUgYHN2eXRhYmxlYCBjb21tYW5kLgoKYGBge3Igc3Z5dGFibGV9CnN2eXRhYmxlKH5mYl91c2VyLCBkZXNpZ249bGFwb3AuZGVzaWduKQpgYGAKClRoZXNlIGZyZXF1ZW5jaWVzIGNhbiBiZSBuZXN0ZWQgaW4gdGhlIGBwcm9wLnRhYmxlYCBjb21tYW5kIHRvIGNhbGN1bGF0ZSB0aGUgcGVyY2VudGFnZXMgb2Ygc29jaWFsIG5ldHdvcmsgdXNlcnMuClRoZXNlIHJlc3VsdHMgYXJlIHRoZSBzYW1lIGFzIHRob3NlIHNob3duIGluIHRoZSBwcmV2aW91cyBncmFwaHMgYW5kIHRob3NlIHRoYXQgYXBwZWFyIGluIHRoZSByZXBvcnQuCgpUaGVzZSBkYXRhIGNhbiBhbHNvIGJlIHNhdmVkIGluIGEgZGF0YWZyYW1lIHRoYXQgaXMgYWRhcHRlZCBmb3IgZ3JhcGhpbmcsIGZvbGxvd2luZyB0aGUgc2FtZSBwcm9jZWR1cmUgYXMgaW4gdGhlIHByZXZpb3VzIGdyYXBocy4KCmBgYHtyIHN2eXRhYmxlIHByb3B9CnByb3AudGFibGUoc3Z5dGFibGUofmZiX3VzZXIsIGRlc2lnbj1sYXBvcC5kZXNpZ24pKQpwcm9wLnRhYmxlKHN2eXRhYmxlKH50d191c2VyLCBkZXNpZ249bGFwb3AuZGVzaWduKSkKcHJvcC50YWJsZShzdnl0YWJsZSh+d2FfdXNlciwgZGVzaWduPWxhcG9wLmRlc2lnbikpCmBgYAo=