0.0.1 First things first.

Install and load all required packages.

#nstall.packages("devtools")
#nstall.packages("tidyverse")
#nstall.packages("kableExtra")
#nstall.packages("visreg")
#nstall.packages("stargazer")
#nstall.packages("ggrepel")
#nstall.packages("gridExtra")
#nstall.packages("fBasics")
#nstall.packages("DescTools")
#nstall.packages("ggmosaic")
install.packages(descr)
Error in install.packages : object 'descr' not found
#install.packages("devtools")
#install.packages("tidyverse")
#ibrary(tidyverse)
#ibrary(kableExtra)
#ibrary(visreg)
#ibrary(stargazer)
#ibrary(ggrepel)
#ibrary(gridExtra)
#ibrary(fBasics)
#lbrary(DescTools)
#ibrary(ggmosaic)
library(descr)

0.0.2 Exploring the data

Descriptive, summary statistics helps us generate useful descriptions of our dataset, identify data anomalies and help us frame our questions and hypothesis. The aim of this tutorial/quiz is to help you become familiar with useful R functions and packages for descriptive analysis.

Let’s create a subset of the state data. The variable state is the state’s name, region indicates the region, trumpwin records whether Donald Trump won the state’s electoral college in the 2016 race, percwom is the average woman’s salary relative to men, and inc records per capita income. Note: remember to install and load your packages.

states<-read_csv(file.choose())
New names:Rows: 50 Columns: 45── Column specification ─────────────────────────
Delimiter: ","
chr  (3): state, st, region
dbl (42): ...1, raperate, murderrate, abort, ...
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
stdat <- head(dplyr::select(states, state, region, trumpwin, percwom, inc))
head(stdat)

And a subset of the world data:

world<-read_csv(file.choose())
New names:Rows: 182 Columns: 45── Column specification ─────────────────────────
Delimiter: ","
chr  (8): iso3c, region, country, dpicode, ac...
dbl (36): ...1, fdi, nourish, aid, oil, homic...
lgl  (1): lifeexp
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
wdat <- world %>% select(country, regime,aclpregion, fdi, fhliberties, inf,nourish, health, gdppc, turnout, womyear)
head(wdat)

####Tables

We are going to use the kable() function to create good-looking tables. Take a moment to explore the package documentation using RStudio help: type: ?kableExtra or use the link: https://haozhu233.github.io/kableExtra/awesome_table_in_html.html

?kableExtra

Let’s use it here to create a formatted table of the dataframe “wdat” we just created with a subset of the world data. The package includes six ready-to-use themes. Let’s try the kable_minimal(), and add it with a pipe operator like in this example. Since we are not using any summary stats in our table, we can use the head() function to just print the first rows of our wdat


head(wdat) %>% kbl()%>% 
  kable_minimal()
country regime aclpregion fdi fhliberties inf nourish health gdppc turnout womyear
Afghanistan Civilian Dictatorship Eastern Europe/Soviet Union 0.3400968 6 75.1 24.7 9.197723 1629.167 45.83 NA
Angola Civilian Dictatorship Sub-Saharan Africa -3.9131508 5 109.6 20.7 3.391146 6360.849 62.77 1975
Albania Parliamentary Democracy Eastern Europe/Soviet Union 9.1340709 3 14.8 NA 5.335035 9646.582 53.31 1920
United Arab Emirates Royal Dictatorship Oil States 3.0752631 5 7.3 5.0 3.929452 56245.478 NA NA
Argentina Presidential Democracy Latin America 2.6751617 2 13.0 5.0 6.550156 18333.995 81.07 1947
Armenia Mixed Democracy Eastern Europe/Soviet Union 5.7160378 4 16.1 6.5 4.562263 6376.268 62.87 1921

now let’s add a caption to our table.

#now let's add a caption to our table
head(wdat) %>%   kbl(caption = "Table a: World Data")%>% 
        kable_minimal()
Table a: World Data
country regime aclpregion fdi fhliberties inf nourish health gdppc turnout womyear
Afghanistan Civilian Dictatorship Eastern Europe/Soviet Union 0.3400968 6 75.1 24.7 9.197723 1629.167 45.83 NA
Angola Civilian Dictatorship Sub-Saharan Africa -3.9131508 5 109.6 20.7 3.391146 6360.849 62.77 1975
Albania Parliamentary Democracy Eastern Europe/Soviet Union 9.1340709 3 14.8 NA 5.335035 9646.582 53.31 1920
United Arab Emirates Royal Dictatorship Oil States 3.0752631 5 7.3 5.0 3.929452 56245.478 NA NA
Argentina Presidential Democracy Latin America 2.6751617 2 13.0 5.0 6.550156 18333.995 81.07 1947
Armenia Mixed Democracy Eastern Europe/Soviet Union 5.7160378 4 16.1 6.5 4.562263 6376.268 62.87 1921

now let’s try another theme, this time the kable_classic [note: Other themes to consides: kable_classic(), kable_paper(), kable_classic_2(),kable_minimal(), kable_material()]

#now let's try another 
head(wdat) %>%   kbl(caption = "Table a: World Data")%>% 
        kable_classic()
Table a: World Data
country regime aclpregion fdi fhliberties inf nourish health gdppc turnout womyear
Afghanistan Civilian Dictatorship Eastern Europe/Soviet Union 0.3400968 6 75.1 24.7 9.197723 1629.167 45.83 NA
Angola Civilian Dictatorship Sub-Saharan Africa -3.9131508 5 109.6 20.7 3.391146 6360.849 62.77 1975
Albania Parliamentary Democracy Eastern Europe/Soviet Union 9.1340709 3 14.8 NA 5.335035 9646.582 53.31 1920
United Arab Emirates Royal Dictatorship Oil States 3.0752631 5 7.3 5.0 3.929452 56245.478 NA NA
Argentina Presidential Democracy Latin America 2.6751617 2 13.0 5.0 6.550156 18333.995 81.07 1947
Armenia Mixed Democracy Eastern Europe/Soviet Union 5.7160378 4 16.1 6.5 4.562263 6376.268 62.87 1921

and if we specify full_width false (=F), notice the change

#now let's try another 
head(wdat) %>%   kbl(caption = "Table a: World Data")%>% 
        kable_classic( full_width = F)
Table a: World Data
country regime aclpregion fdi fhliberties inf nourish health gdppc turnout womyear
Afghanistan Civilian Dictatorship Eastern Europe/Soviet Union 0.3400968 6 75.1 24.7 9.197723 1629.167 45.83 NA
Angola Civilian Dictatorship Sub-Saharan Africa -3.9131508 5 109.6 20.7 3.391146 6360.849 62.77 1975
Albania Parliamentary Democracy Eastern Europe/Soviet Union 9.1340709 3 14.8 NA 5.335035 9646.582 53.31 1920
United Arab Emirates Royal Dictatorship Oil States 3.0752631 5 7.3 5.0 3.929452 56245.478 NA NA
Argentina Presidential Democracy Latin America 2.6751617 2 13.0 5.0 6.550156 18333.995 81.07 1947
Armenia Mixed Democracy Eastern Europe/Soviet Union 5.7160378 4 16.1 6.5 4.562263 6376.268 62.87 1921

Now let’s specify “hover” and after running the chunk hover your mouse over the table.

#now let's try another 
head(wdat) %>%   kbl(caption = "Table a: World Data")%>% 
        kable_classic("hover", full_width = F) 
Table a: World Data
country regime aclpregion fdi fhliberties inf nourish health gdppc turnout womyear
Afghanistan Civilian Dictatorship Eastern Europe/Soviet Union 0.3400968 6 75.1 24.7 9.197723 1629.167 45.83 NA
Angola Civilian Dictatorship Sub-Saharan Africa -3.9131508 5 109.6 20.7 3.391146 6360.849 62.77 1975
Albania Parliamentary Democracy Eastern Europe/Soviet Union 9.1340709 3 14.8 NA 5.335035 9646.582 53.31 1920
United Arab Emirates Royal Dictatorship Oil States 3.0752631 5 7.3 5.0 3.929452 56245.478 NA NA
Argentina Presidential Democracy Latin America 2.6751617 2 13.0 5.0 6.550156 18333.995 81.07 1947
Armenia Mixed Democracy Eastern Europe/Soviet Union 5.7160378 4 16.1 6.5 4.562263 6376.268 62.87 1921

We can also specify a more informative name for our columns. Let’s try changing the labels using col.names:

#now let's try another 

stdat %>%   kbl(caption = "Table a: States Data",
                  col.names = c("Country", "Regime", "Trump Won", "Percent Women", "Income"))%>% 
        kable_classic("hover", full_width = F)
Table a: States Data
Country Regime Trump Won Percent Women Income
Alabama South 1 75.49 34650
Alaska West 1 79.02 45529
Arizona West 1 84.00 35875
Arkansas South 1 88.52 34014
California West 0 89.94 44481
Colorado West 0 79.57 44088

####graphs

let’s create a simple ggplot graph looking at the variable regime. A bar plot will show the frequency for the variable, that is the y axis will show the count of observations in our dataset for each category of regime.

 world %>% ggplot( aes(regime))+
geom_bar()

We can assign the graph to an object, let’s call it wplot1. And remember we need to add the object in the chunk if we want R to “print” it to our screen. And as a bonus, we can use the option fill to color our bars.

wplot1<-  world %>% ggplot( aes(regime) )+
geom_bar(fill="lightblue")

wplot1

Now let’s add a bar plot of foreign direct investment[fdi] which is the net foreign investment inflows as a percentage of GDP) against regime type. We will first group the data by the variable regime, then create a new variable m that computes the mean of fdi for each regime, then we can ungroup the data again and produce our graph of mean fdi by regime. And remember that each of these steps can be string together in the tidyverse with our pipe operator [%>%].


wdat %>% 
  filter(!is.na(fdi)) %>% # name of the dataset
  group_by(regime) %>%                    # grouping the data by type of regime
  summarize(m = mean(fdi)) %>%            # calculating the mean of fdi
  ungroup() %>%                           # ungroup the data again
  ggplot( aes(x=regime, y=m))+            # set up the graph
geom_col()                                # set geometry of the graph

Now, let’s use the option fill to the aesthetics of our plot to color our plot with each category of regime


wdat %>% 
  filter(!is.na(fdi)) %>% # name of the dataset
  group_by(regime) %>%                    # grouping the data by type of regime
  summarize(m = mean(fdi)) %>%            # calculating the mean of fdi
  ungroup() %>%                           # ungroup the data again
  ggplot( aes(x=regime, y=m, fill=regime))+            # set up the graph
geom_col()                                # set geometry of the graph

Let’s see if our plot is more readable when we rotate our plot, changing the orientation of the bars with the coord_flip function.

wdat %>% 
  filter(!is.na(fdi)) %>% # name of the dataset
  group_by(regime) %>%                    # grouping the data by type of regime
  summarize(m = mean(fdi)) %>%            # calculating the mean of fdi
  ungroup() %>%                           # ungroup the data again
  ggplot( aes(x=regime, y=m,fill=regime)) +   # set up the graph
geom_col() +                              # set geometry of the graph
coord_flip()                               #flip the orientation of the bar 

Lastly, our categories can be reordered so Royal dictatorship is not right next to presidential democracy. We first need to define a new variable reg2 that reorders the levels (categories) of the regime variable.


wdat <- wdat %>% mutate(reg2 = factor(regime,
                  levels = c("Royal Dictatorship",
                              "Military Dictatorship",
                              "Civilian Dictatorship",
                              "Mixed Democracy",
                              "Parliamentary Democracy",
                              "Presidential Democracy")))
wdat %>% 
  filter(!is.na(fdi)) %>% # name of the dataset
  group_by(reg2) %>%                    # grouping the data by type of regime
  summarize(m = mean(fdi)) %>%            # calculating the mean of fdi
  ungroup() %>%                           # ungroup the data again
  ggplot( aes(x=reg2, y=m,fill=reg2)) +   # set up the graph
geom_col() +                              # set geometry of the graph
coord_flip()                               #flip the orientation of the bar 

Now let’s add a ready-to-use theme: theme_minimal(). We also specify the axis from 0 to 10 to fit better the bars, and of course, we should also add more informative labels for our variables


wdat <- wdat %>% mutate(reg2 = factor(regime,
                  levels = c("Royal Dictatorship",
                              "Military Dictatorship",
                              "Civilian Dictatorship",
                              "Mixed Democracy",
                              "Parliamentary Democracy",
                              "Presidential Democracy")))
wdat %>% 
  filter(!is.na(fdi)) %>% # name of the dataset
  group_by(reg2) %>%                    # grouping the data by type of regime
  summarize(m = mean(fdi)) %>%            # calculating the mean of fdi
  ungroup() %>%                           # ungroup the data again
  ggplot( aes(x=reg2, y=m,fill=reg2)) +   # set up the graph
geom_col() +                              # set geometry of the graph
coord_flip(ylim=c(0,10)) +  
  theme_minimal()+
  ylab("Foreign direct investment") +
  xlab("Regime") 

. We need to know the shape of the data first to determine what summaries and models to use. When we look at the distribution of our variables we can learn whether all cases are evenly distributed or whether values cluster closer to the minimum, median, or maximum.

Let’s use two examples of our world dataset. First we will explore the histogram of the variable turnout. And let’s add another layer with a density plot to see the smooth density line. For a great explanation of kernel density I recommend this link: https://mathisonian.github.io/kde/


world %>% ggplot(aes(x = turnout)) + 
  geom_histogram(aes(y = ..density..),
                 colour = 1, fill = "white") +
  geom_density() + 
xlab("Voter Turnout") +
ggtitle("Voter Turnout Is Normally Distributed") 

We can see that the distribution of voting turnout seems normally distributed. Let’s look at the shape of the infant mortality in the world (the number of deaths in each country per 1,000 live births), using the variable inf.


world %>% ggplot(aes(x = inf)) + 
  geom_histogram(aes(y = ..density..),
                 colour = 1, fill = "white") +
  geom_density() + 
xlab("Infant Mortality Rate") +
ggtitle(" Infant Mortality Is Not Normally Distributed") 

We can see from the histogram that many countries have low infant mortality, and, unfortunately,some countries have 30, 60, and even 90 deaths per 1,000 live births.

0.0.2.1 Five view of Univariate data

0.0.2.1.1 Frequency Table

Use a frequency table when the variable is categorical. The frequency table indicates how many cases reside in each category, giving the category’s relative size. Let’s use the freq() command to get a frequency table of the National Election Studies (nes) dataset, and see how many Democrats, Republicans, and Independents are included. First let’s set the describe plot option as False (descr.plot).

nes<-read_csv(file.choose())
New names:Rows: 1178 Columns: 52── Column specification ─────────────────────────
Delimiter: ","
chr (35): follow, turnout12, vote12, meet, ma...
dbl (17): ...1, birthyr, ftobama, ftblack, ft...
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Freq(nes$pid3, plot = options(descr.plot = FALSE))
head(nes)

Now, if we set the descr.plot = TRUE, we will get tha frequency table and a histogram.

Freq(nes$pid3, plot = options(descr.plot = TRUE))

Frequency tables help us get a good sense about the categories in a variable to decide if we need to combine or exclude some categories. For instance, if we look at a frequency table of the variable employ from the NES data set, we can see that there are nine categories, or that “temporarily laid off” only has four respondents, so we might want to consider combining it with the “other” category

Freq(nes$employ, plot = options(descr.plot = FALSE))
0.0.2.1.2 Bar Plot

Bar plots are useful to identify categories with the highest frequency and are an easy way to make comparisons across categories. Let’s try creating a bar plot of our employment variables.

ggplot(nes, aes(employ)) +
  geom_bar() 

Now, let’s use additional options to make our plot better, we will add a theme, add a title for our plot [ggtitle], add a title for our y label and remove our title for our x-axis by setting it to ““. We will also use the [coord_flip] to change the orientation of our plot. And we will change the color with the fill option, here we are using”ligthblue”, but feel free to play with other colors [https://r-graph-gallery.com/ggplot2-color.html].

ggplot(nes, aes(employ)) +
  geom_bar(fill = "lightblue") +
  theme_minimal() +
  ggtitle("Barplot of Employment Variable") +
  xlab("") +
  ylab("Number of Respondents") +
  coord_flip()

We can see that a large share of the population is employed full-time.

0.0.2.1.3 Boxplot (or Box-and-Whisker Plot)

Boxplots are useful to plot the distribution of a continuous variable. Let’s use a boxplot to look at the percentage of the voting age population that voted in each country’s last national election. Since we only want to plot one variable, we need specify that x=“ ”. The y variable will be our “turnout” variable from the world dataset.

ggplot(world, aes(x="", turnout)) +
  geom_boxplot() 

We can see the median (the thick line in the middle of the box) is a bit above 60% and the interquartile range (the box) is between 55% and 80%. Now, let’s format the plot a bit more.

ggplot(world, aes(x="", turnout)) +
  geom_boxplot(col="dark green") +
  theme_minimal() +
  ggtitle("Boxplot of Turnout") +
  ylab("Percent Voting in Last Election") +
  xlab("") +
  theme_minimal()

And remember boxplots don’t typically show individual observations, so we will “jitter” the points so that they don’t lie directly on top of each other. We control the size of the points with the [size] option, the fill color with the [fill] option and the outline color with the [colour] option.


ggplot(world, aes(x="", turnout)) +
  geom_boxplot(col="darkgreen") +
  theme_minimal() +
  ggtitle("Boxplot of Turnout") +
  ylab("Percent Voting in Last Election") +
  xlab("") +
  theme_minimal() +
    geom_point(fill = "grey", size=1,
             shape=21, colour="grey",
             position=position_jitter(seed = 1))

And if we want to learn a bonus trick, we can add a geom_text_repel layer where we use the ifelse conditional to only show the label only for Canada or the US. We use the ifelse() function to say that if the label is equal to Canada (CAN) or the US (USA), then label them with the dpicode variable; otherwise leave it blank. We specify “blank” with the two single quotations with nothing in between (‘ ’).


ggplot(world, aes(x="", turnout)) +
  geom_boxplot(col="darkgreen") +
  theme_minimal() +
  ggtitle("Boxplot of Turnout") +
  ylab("Percent Voting in Last Election") +
  xlab("") +
  theme_minimal() +
    geom_point(fill = "grey", size=1,
             shape=21, colour="grey",
             position=position_jitter(seed = 1)) +
     geom_text_repel(aes(label=ifelse(dpicode=="CAN" | dpicode=="USA", as.character(dpicode),'')), col ="grey",
                  position = position_jitter(seed = 1),
                  hjust=1, vjust=2)      

NA
NA

aes(label=ifelse(st==“HI” | st==“MA”, as.character(st),’’), hjust = 0, vjust=-1), show.legend=FALSE)

0.0.2.1.4 Histogram

We use histograms to visualize the frequency distribution of continuous variables. They show the shape of the variable’s distribution, and how disperse the values of the variable are. Each bar represents a range of values ( a bin) and we can define the number of bins that makes better sense for our data. Let’s create a histogram of the years since last regime change for all countries in the World dataset using the variable [durable].

ggplot(world, aes(durable)) +
  geom_histogram() 

Now let’s change the number ofbins to10 with the option [bin], and format the histogram by setting the color, the theme and labelin the variable and the plot.

ggplot(world, aes(durable)) +
  geom_histogram(bins=10, fill = "lightblue") +
  ggtitle("Histogram of the durable Variable") +
  xlab("Years Since Last Significant Regime Change") +
  theme_minimal() 

this is a much more informative histogram, so it’s important to think about the choices of bins. for instance, if we were to only use three bins, the resulting histogram will not be as useful:

ggplot(world, aes(durable)) +
  geom_histogram(bins=3, fill = "lightblue") +
  labs(title = paste("Not Enough Bins")) +
  xlab("Years Since Last Significant Regime Change") +
  ylab("Count")+
  theme_minimal() 

0.0.2.1.5 Stem-and-Leaf Plot

One additional descriptive plot that we have not discussed in class is the stem-and-leaf plot, which also help us see a variable’s distribution when the number of observations is somewhat small.The number in the leaf represents the first decimal.Let’s try a plot of household income for the 50 states, using the variable [inc].

stem(states$inc, scale=1)

  The decimal point is 3 digit(s) to the right of the |

  32 | 235778
  34 | 06769
  36 | 12556389
  38 | 022666
  40 | 1556668
  42 | 51
  44 | 0113575789
  46 | 3
  48 | 
  50 | 50
  52 | 26
  54 | 
  56 | 9

The stem is ordered by 2,000. Each step represents $2,000. In the first row, we see six numbers (six leaves), meaning there are six cases between 32,000 and 34,000. In this case, we don’t know exactly what the numbers are; we just know they’re between 32,000 and 34,000.

0.0.2.2 Bivariate descriptives

Bivariate descriptions illustrate the relationship between two variables, whether they are continuous or categorical. Bivariate plots helps us understand the relationship between the variables and identify potential data errors.

0.0.2.2.1 Scatter Plot

Scatter plots are two dimensional, showing the relationship between two continuous variables. And we can use the color or shape of the point to add a third variable. Let’s create a scatter plot of voting turnout and political knowledge ( percent of the population that recognizes the name of the governor for any given state)

ggplot(states, aes(knowgov, turnout, label = st)) +
  geom_point()

Again, let’s format our scatterplot.

ggplot(states, aes(knowgov, turnout, label = st)) +
  geom_point(col="orange") +
  ggtitle("Turnout Not Related to Political Knowledge") +
  ylab("Voting Turnout") +
  xlab("Political Knowledge") +
  theme_minimal() 

We can quickly tell there is not much of a relationship between political knowledge and voting turnout, as turnout does not systematically increase or decrease with increases in political turnout.

Let’s use infant mortality and the percentage of a state’s population that has a high school degree in our States dataset as an example of a scatterplot showing a fairly strong relationship:

ggplot(states, aes(hsdiploma, infant)) +
  geom_point() 

Now let’s format our plot.

ggplot(states, aes(hsdiploma, infant)) +
  geom_point(col="red") +
  ggtitle("Education Reduces Infant Mortality") +
  ylab("Infant Mortality") +
  xlab("High School Diploma") +
  theme_minimal() 

And to take it up a level, let’s draw a line fit to the plot with the geom_smooth layer and a method = “lm” (for linear fit).

ggplot(states, aes(hsdiploma, infant)) +
  geom_point(col="red") +
  geom_smooth(method = "lm", se = FALSE, col="grey") +
  ggtitle("Same Education, Different Outcome") +
  ylab("Infant Mortality") +
  xlab("High School Diploma") +
  theme_minimal()

After adding this fitted line, we see that there is a negative association between education and infant mortality: as one variable increases (education), the other decreases (infant mortality). It is also a fairly linear relationship. The decline in infant mortality is constant over the range of education.

0.0.2.2.2 Boxplot (Bivariate)

Boxplots can also be useful when looking at the relationship between continuous and categorical variables, if there are not too many categories (between 5 and 10). Let’s look at a boxplot of the feeling thermometer towards science (a variable ranging from 0 to 100 that indicate how survey respondents feel about a particular kind of person or policy).

ggplot(nes, aes(pid7, ftsci)) +
  geom_boxplot(col="cadetblue") +
  theme_minimal() +
  theme(axis.text.x = element_text(size=8, angle=0, vjust=.7)) +
  ggtitle("Partisanship Shapes Attitudes") +
  ylab("Science Thermometer") +
  xlab("Party Identification") +
  coord_flip()

Let’s use the subset() function in our first ggplot() line to filter out the categories “NA” and “Not Sure” from the party identification variable.

ggplot(subset(nes, pid7!="NA" & pid7!="Not sure"), aes(pid7, ftsci)) +
  geom_boxplot(col="cadetblue") +
  theme_minimal() +
  theme(axis.text.x = element_text(size=8, angle=0, vjust=.7)) +
  ggtitle("Partisanship Shapes Attitudes") +
  ylab("Science Thermometer") +
  xlab("Party Identification") +
  coord_flip()

0.0.2.2.3 Mosaic Plot

Mosaic Plot is an intuitive visual representation of cross-tabs (tables that display the association between two categorical variables). Mosaic plots show the breakdown between the categories fo the two variables, but also uses the width of the bars to represent the number of observations in each category of the x axis.

ggplot(nes)+
  geom_mosaic(aes(x = product(gender, pid3),
  fill=gender,na.rm=TRUE))

Let’s try to filtered observations with values “Not sure”, “Other” in a new varialbe pid3_new. and also missing values (using “NA”)



ggplot(subset(nes, pid3 %in% c("Democrat","Republican","Indepent"),  pid3!="NA"), aes(x = gender, y= pid3)) +
geom_mosaic(aes(x = product(gender, pid3),
  fill=gender,na.rm=TRUE)) +
  xlab("") +
  ylab("") +
  ggtitle("Gender by Party Identification") +
  theme_minimal() +
  scale_fill_brewer(palette="Blues") +
  theme(legend.position = "none")

NA
NA
NA

The mosaic plot indicates males make up a slightly larger percentage of Independents than either Republicans or Democrats. We can observe that women are not systematically more conservative than men. And we can look at the width of the columns to observe that a larger percentage of the population identifies with the Democratic party, then Independents, followed by Republicans.

now, let’s create a mosaic plot using variables party identification and whether the respondent worries about terrorism from the NES data.We are first going to create a new variable var2, that excludes observations with values equal “Not asked”.

nes$var2 <- gsub("Not asked", "", as.character(nes$terror_worry))

ggplot(data = subset(nes, pid3!="NA" & var2 !="NA")) +
  geom_mosaic(aes(x = product(var2, pid3), fill=var2, na.rm=TRUE)) +
  xlab("") +
  ylab("") +
  ggtitle("Democrats Are Less Worried About Terrorism") +
  theme_minimal() +
  scale_fill_brewer(palette="Blues") +
  theme(legend.position = "none") 

We can quickly see that Democrats are the least worried about a terrorist attack.

0.0.2.2.4 Cross-Tab

Cross-tab are a commonly used summary of categorical variables. We are going to use it to look at the breakdown of categories using variables party identification and Gender from the NES data.

The cross-tab includes both the count (frequency) and the column percentage. For example, looking at the Total column, we can see there are 577 females in the sample and that they represents 52.5% o of the sample (.525) -add the percents going down the column, they should add up to 100%-.

CrossTable(nes$gender, nes$pid3,
           main="Cross-Tabulation of Gender and Party ID",
           prop.chisq=FALSE)
   Cell Contents 
|-------------------------|
|                       N | 
|           N / Row Total | 
|           N / Col Total | 
|         N / Table Total | 
|-------------------------|

======================================================
         nes$pid3
ns$gn    Dmcrt   Indpn   Nt sr   Other   Rpblc   Total
------------------------------------------------------
Femal      262     167       4      30     148     611
         0.429   0.273   0.007   0.049   0.242   0.519
         0.584   0.445   1.000   0.405   0.536        
         0.222   0.142   0.003   0.025   0.126        
------------------------------------------------------
Male       187     208       0      44     128     567
         0.330   0.367   0.000   0.078   0.226   0.481
         0.416   0.555   0.000   0.595   0.464        
         0.159   0.177   0.000   0.037   0.109        
------------------------------------------------------
Total      449     375       4      74     276    1178
         0.381   0.318   0.003   0.063   0.234        
======================================================

0.0.3 quizz time

0.0.3.1 Let’s create more tables.

Let’s use again kable here to create a table of the dataframe “stdat” we just created with a subset of the states data. The package includes six ready-to-use themes. Let’s try the kable_minimal(), and add it with a pipe operator like in this example: Note: this will follow the same code including in the “Tables” part of this tutorial, so you just need to apply it to the stdat dataset.

# Table using
stdat %>% kbl()%>% 
  kable_minimal()
state region trumpwin percwom inc
Alabama South 1 75.49 34650
Alaska West 1 79.02 45529
Arizona West 1 84.00 35875
Arkansas South 1 88.52 34014
California West 0 89.94 44481
Colorado West 0 79.57 44088

now let’s add a caption to our table: “Table a: States Data”

#now let's add a caption to our table
head(stdat) %>%   kbl(caption = "Table a: States Data")%>% 
        kable_minimal()
Table a: States Data
state region trumpwin percwom inc
Alabama South 1 75.49 34650
Alaska West 1 79.02 45529
Arizona West 1 84.00 35875
Arkansas South 1 88.52 34014
California West 0 89.94 44481
Colorado West 0 79.57 44088
NA
NA

now let’s try another theme, this time the kable_classic [note: Other themes to consides: kable_classic(), kable_paper(), kable_classic_2(),kable_minimal(), kable_material()]

#now let's try another theme
head(stdat) %>%   kbl(caption = "Table a: States Data")%>% 
        kable_minimal()
Table a: States Data
state region trumpwin percwom inc
Alabama South 1 75.49 34650
Alaska West 1 79.02 45529
Arizona West 1 84.00 35875
Arkansas South 1 88.52 34014
California West 0 89.94 44481
Colorado West 0 79.57 44088
NA
NA

and if we specify full_width false (=F), notice the change

head(stdat) %>%   kbl(caption = "Table a: States Data")%>% 
        kable_classic( full_width = F)
Table a: States Data
state region trumpwin percwom inc
Alabama South 1 75.49 34650
Alaska West 1 79.02 45529
Arizona West 1 84.00 35875
Arkansas South 1 88.52 34014
California West 0 89.94 44481
Colorado West 0 79.57 44088
NA
NA

Now let’s specify (“hover”, full_width = F) and after running the chunk hover your mouse over the table.

#let's specify hover
head(stdat) %>%   kbl(caption = "Table a: States Data")%>% 
        kable_classic("hover", full_width = F) 
Table a: States Data
state region trumpwin percwom inc
Alabama South 1 75.49 34650
Alaska West 1 79.02 45529
Arizona West 1 84.00 35875
Arkansas South 1 88.52 34014
California West 0 89.94 44481
Colorado West 0 79.57 44088

We can also specify a more informative name for our columns. Let’s try changing the labels using col.names: col.names = c(“State”, “Region”, “Trump Won”, “Percent Women”, “Income”))

#let's change the labels for our columns
stdat %>%   kbl(caption = "Table a: States Data",
                  col.names = c("State", "Region", "Trump Won", "Percent Women", "Income"))%>% 
        kable_classic("hover", full_width = F)
Table a: States Data
State Region Trump Won Percent Women Income
Alabama South 1 75.49 34650
Alaska West 1 79.02 45529
Arizona West 1 84.00 35875
Arkansas South 1 88.52 34014
California West 0 89.94 44481
Colorado West 0 79.57 44088

0.0.3.2 Time to plot

Using the states dataset, produce four different plots (two univariate -single variable- and two bivariate -two variables-) following the examples in the tutorial.

#your code for plot 1 here
ggplot(states, aes(x="", democrat)) +
  geom_boxplot() 

#your code for plot 2 here
ggplot(states, aes(region)) +
  geom_bar() 

#your code for plot 3 here
ggplot(states)+
  geom_mosaic(aes(x = product(region, weed),
  fill=region,na.rm=TRUE))

#your code for plot 4 here
CrossTable(states$region, states$weed,
           main="Cross-Tabulation of Region and Weed Usage",
           prop.chisq=FALSE)
   Cell Contents 
|-------------------------|
|                       N | 
|           N / Row Total | 
|           N / Col Total | 
|         N / Table Total | 
|-------------------------|

======================================
                 states$weed
states$region        0       1   Total
--------------------------------------
Midwest              7       5      12
                 0.583   0.417   0.240
                 0.333   0.172        
                  0.14    0.10        
--------------------------------------
Northeast            0       9       9
                 0.000   1.000   0.180
                 0.000   0.310        
                  0.00    0.18        
--------------------------------------
South               11       5      16
                 0.688   0.312   0.320
                 0.524   0.172        
                  0.22    0.10        
--------------------------------------
West                 3      10      13
                 0.231   0.769   0.260
                 0.143   0.345        
                  0.06    0.20        
--------------------------------------
Total               21      29      50
                  0.42    0.58        
======================================

0.0.4 Additional notes

Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Cmd+Option+I.

When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Cmd+Shift+K to preview the HTML file).

The preview shows you a rendered HTML copy of the contents of the editor. Consequently, unlike Knit, Preview does not run any R code chunks. Instead, the output of the chunk when it was last run in the editor is displayed.

LS0tCnRpdGxlOiAiUFVBRCA1MTQwIgpzdWJ0aXRsZTogIkRlc2NyaWJpbmcgRGF0YSIKYXV0aG9yOiAiSmVzc2UgTGV3aXMiCmRhdGU6ICJOb3ZlbWJlciAyMiwgMjAyMiIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICBoaWdobGlnaHQ6IGhhZGRvY2sKICAgIHRvY19kZXB0aDogNQogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogICAgdGhlbWU6IGNlcnVsZWFuCiAgICBoaWdobGlnaHQ6IGhhZGRvY2sKICAgIHRvY19kZXB0aDogNQotLS0KCiMjIyBGaXJzdCB0aGluZ3MgZmlyc3QuIAoKSW5zdGFsbCBhbmQgbG9hZCBhbGwgcmVxdWlyZWQgcGFja2FnZXMuIApgYGB7cn0KI25zdGFsbC5wYWNrYWdlcygiZGV2dG9vbHMiKQojbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQojbnN0YWxsLnBhY2thZ2VzKCJrYWJsZUV4dHJhIikKI25zdGFsbC5wYWNrYWdlcygidmlzcmVnIikKI25zdGFsbC5wYWNrYWdlcygic3RhcmdhemVyIikKI25zdGFsbC5wYWNrYWdlcygiZ2dyZXBlbCIpCiNuc3RhbGwucGFja2FnZXMoImdyaWRFeHRyYSIpCiNuc3RhbGwucGFja2FnZXMoImZCYXNpY3MiKQojbnN0YWxsLnBhY2thZ2VzKCJEZXNjVG9vbHMiKQojbnN0YWxsLnBhY2thZ2VzKCJnZ21vc2FpYyIpCmluc3RhbGwucGFja2FnZXMoZGVzY3IpCgoKYGBgCgoKYGBge3J9CiNpbnN0YWxsLnBhY2thZ2VzKCJkZXZ0b29scyIpCiNpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQojaWJyYXJ5KHRpZHl2ZXJzZSkKI2licmFyeShrYWJsZUV4dHJhKQojaWJyYXJ5KHZpc3JlZykKI2licmFyeShzdGFyZ2F6ZXIpCiNpYnJhcnkoZ2dyZXBlbCkKI2licmFyeShncmlkRXh0cmEpCiNpYnJhcnkoZkJhc2ljcykKI2xicmFyeShEZXNjVG9vbHMpCiNpYnJhcnkoZ2dtb3NhaWMpCmxpYnJhcnkoZGVzY3IpCgpgYGAKCiMjIyBFeHBsb3JpbmcgdGhlIGRhdGEgCgoKRGVzY3JpcHRpdmUsIHN1bW1hcnkgc3RhdGlzdGljcyBoZWxwcyB1cyBnZW5lcmF0ZSB1c2VmdWwgZGVzY3JpcHRpb25zIG9mIG91ciBkYXRhc2V0LCBpZGVudGlmeSBkYXRhIGFub21hbGllcyBhbmQgaGVscCB1cyBmcmFtZSBvdXIgcXVlc3Rpb25zIGFuZCBoeXBvdGhlc2lzLiBUaGUgYWltIG9mIHRoaXMgdHV0b3JpYWwvcXVpeiBpcyB0byBoZWxwIHlvdSBiZWNvbWUgZmFtaWxpYXIgd2l0aCB1c2VmdWwgUiBmdW5jdGlvbnMgYW5kIHBhY2thZ2VzIGZvciBkZXNjcmlwdGl2ZSBhbmFseXNpcy4gCgpMZXQncyBjcmVhdGUgYSBzdWJzZXQgb2YgdGhlIHN0YXRlIGRhdGEuIFRoZSB2YXJpYWJsZSBzdGF0ZSBpcyB0aGUgc3RhdGXigJlzIG5hbWUsIHJlZ2lvbiBpbmRpY2F0ZXMgdGhlIHJlZ2lvbiwgIHRydW1wd2luIHJlY29yZHMgd2hldGhlciBEb25hbGQgVHJ1bXAgd29uIHRoZSBzdGF0ZeKAmXMgZWxlY3RvcmFsIGNvbGxlZ2UgaW4gdGhlIDIwMTYgcmFjZSwgcGVyY3dvbSBpcyB0aGUgYXZlcmFnZSB3b21hbuKAmXMgc2FsYXJ5IHJlbGF0aXZlIHRvIG1lbiwgYW5kICoqKmluYyoqKiByZWNvcmRzIHBlciBjYXBpdGEgaW5jb21lLiBOb3RlOiByZW1lbWJlciB0byBpbnN0YWxsIGFuZCBsb2FkIHlvdXIgcGFja2FnZXMuIAoKYGBge3J9CnN0YXRlczwtcmVhZF9jc3YoZmlsZS5jaG9vc2UoKSkKc3RkYXQgPC0gaGVhZChkcGx5cjo6c2VsZWN0KHN0YXRlcywgc3RhdGUsIHJlZ2lvbiwgdHJ1bXB3aW4sIHBlcmN3b20sIGluYykpCmhlYWQoc3RkYXQpCmBgYAoKQW5kIGEgc3Vic2V0IG9mIHRoZSB3b3JsZCBkYXRhOgoKYGBge3J9CndvcmxkPC1yZWFkX2NzdihmaWxlLmNob29zZSgpKQp3ZGF0IDwtIHdvcmxkICU+JSBzZWxlY3QoY291bnRyeSwgcmVnaW1lLGFjbHByZWdpb24sIGZkaSwgZmhsaWJlcnRpZXMsIGluZixub3VyaXNoLCBoZWFsdGgsIGdkcHBjLCB0dXJub3V0LCB3b215ZWFyKQpoZWFkKHdkYXQpCmBgYAoKCgoKIyMjI1RhYmxlcwoKCldlIGFyZSBnb2luZyB0byB1c2UgdGhlIGthYmxlKCkgZnVuY3Rpb24gdG8gY3JlYXRlIGdvb2QtbG9va2luZyB0YWJsZXMuIFRha2UgYSBtb21lbnQgdG8gZXhwbG9yZSB0aGUgcGFja2FnZSBkb2N1bWVudGF0aW9uIHVzaW5nIFJTdHVkaW8gaGVscDogdHlwZTogP2thYmxlRXh0cmEgb3IgdXNlIHRoZSBsaW5rOiBodHRwczovL2hhb3podTIzMy5naXRodWIuaW8va2FibGVFeHRyYS9hd2Vzb21lX3RhYmxlX2luX2h0bWwuaHRtbCAKCmBgYHtyfQo/a2FibGVFeHRyYQpgYGAKCkxldCdzIHVzZSBpdCBoZXJlIHRvIGNyZWF0ZSBhIGZvcm1hdHRlZCB0YWJsZSBvZiB0aGUgZGF0YWZyYW1lICJ3ZGF0IiB3ZSBqdXN0IGNyZWF0ZWQgd2l0aCBhIHN1YnNldCBvZiB0aGUgd29ybGQgZGF0YS4gVGhlIHBhY2thZ2UgaW5jbHVkZXMgc2l4IHJlYWR5LXRvLXVzZSB0aGVtZXMuIExldCdzIHRyeSB0aGUga2FibGVfbWluaW1hbCgpLCBhbmQgYWRkIGl0IHdpdGggYSBwaXBlIG9wZXJhdG9yIGxpa2UgaW4gdGhpcyBleGFtcGxlLiBTaW5jZSB3ZSBhcmUgbm90IHVzaW5nIGFueSBzdW1tYXJ5IHN0YXRzIGluIG91ciB0YWJsZSwgd2UgY2FuIHVzZSB0aGUgaGVhZCgpIGZ1bmN0aW9uIHRvIGp1c3QgcHJpbnQgdGhlIGZpcnN0IHJvd3Mgb2Ygb3VyIHdkYXQKYGBge3J9CgpoZWFkKHdkYXQpICU+JSBrYmwoKSU+JSAKICBrYWJsZV9taW5pbWFsKCkKYGBgCgoKbm93IGxldCdzIGFkZCBhIGNhcHRpb24gdG8gb3VyIHRhYmxlLiAKCmBgYHtyfQojbm93IGxldCdzIGFkZCBhIGNhcHRpb24gdG8gb3VyIHRhYmxlCmhlYWQod2RhdCkgJT4lICAga2JsKGNhcHRpb24gPSAiVGFibGUgYTogV29ybGQgRGF0YSIpJT4lIAogICAgICAgIGthYmxlX21pbmltYWwoKQpgYGAKCm5vdyBsZXQncyB0cnkgYW5vdGhlciB0aGVtZSwgdGhpcyB0aW1lIHRoZSBrYWJsZV9jbGFzc2ljIFtub3RlOiBPdGhlciB0aGVtZXMgdG8gY29uc2lkZXM6IGthYmxlX2NsYXNzaWMoKSwga2FibGVfcGFwZXIoKSwga2FibGVfY2xhc3NpY18yKCksa2FibGVfbWluaW1hbCgpLCBrYWJsZV9tYXRlcmlhbCgpXQpgYGB7cn0KI25vdyBsZXQncyB0cnkgYW5vdGhlciAKaGVhZCh3ZGF0KSAlPiUgICBrYmwoY2FwdGlvbiA9ICJUYWJsZSBhOiBXb3JsZCBEYXRhIiklPiUgCiAgICAgICAga2FibGVfY2xhc3NpYygpCmBgYAoKYW5kIGlmIHdlIHNwZWNpZnkgZnVsbF93aWR0aCBmYWxzZSAoPUYpLCBub3RpY2UgdGhlIGNoYW5nZQoKYGBge3J9CiNub3cgbGV0J3MgdHJ5IGFub3RoZXIgCmhlYWQod2RhdCkgJT4lICAga2JsKGNhcHRpb24gPSAiVGFibGUgYTogV29ybGQgRGF0YSIpJT4lIAogICAgICAgIGthYmxlX2NsYXNzaWMoIGZ1bGxfd2lkdGggPSBGKQpgYGAKCk5vdyBsZXQncyBzcGVjaWZ5ICJob3ZlciIgYW5kIGFmdGVyIHJ1bm5pbmcgdGhlIGNodW5rIGhvdmVyIHlvdXIgbW91c2Ugb3ZlciB0aGUgdGFibGUuCmBgYHtyfQojbm93IGxldCdzIHRyeSBhbm90aGVyIApoZWFkKHdkYXQpICU+JSAgIGtibChjYXB0aW9uID0gIlRhYmxlIGE6IFdvcmxkIERhdGEiKSU+JSAKICAgICAgICBrYWJsZV9jbGFzc2ljKCJob3ZlciIsIGZ1bGxfd2lkdGggPSBGKSAKYGBgCgpXZSBjYW4gYWxzbyBzcGVjaWZ5IGEgbW9yZSBpbmZvcm1hdGl2ZSBuYW1lIGZvciBvdXIgY29sdW1ucy4gTGV0J3MgdHJ5IGNoYW5naW5nIHRoZSBsYWJlbHMgdXNpbmcgY29sLm5hbWVzOgoKYGBge3J9CiNub3cgbGV0J3MgdHJ5IGFub3RoZXIgCgpzdGRhdCAlPiUgICBrYmwoY2FwdGlvbiA9ICJUYWJsZSBhOiBTdGF0ZXMgRGF0YSIsCiAgICAgICAgICAgICAgICAgIGNvbC5uYW1lcyA9IGMoIkNvdW50cnkiLCAiUmVnaW1lIiwgIlRydW1wIFdvbiIsICJQZXJjZW50IFdvbWVuIiwgIkluY29tZSIpKSU+JSAKICAgICAgICBrYWJsZV9jbGFzc2ljKCJob3ZlciIsIGZ1bGxfd2lkdGggPSBGKQpgYGAKCgojIyMjZ3JhcGhzCgpsZXQncyBjcmVhdGUgYSBzaW1wbGUgZ2dwbG90IGdyYXBoIGxvb2tpbmcgYXQgdGhlIHZhcmlhYmxlIHJlZ2ltZS4gQSBiYXIgcGxvdCB3aWxsIHNob3cgdGhlIGZyZXF1ZW5jeSBmb3IgdGhlIHZhcmlhYmxlLCB0aGF0IGlzIHRoZSB5IGF4aXMgd2lsbCBzaG93IHRoZSBjb3VudCBvZiBvYnNlcnZhdGlvbnMgaW4gb3VyIGRhdGFzZXQgZm9yIGVhY2ggY2F0ZWdvcnkgb2YgcmVnaW1lLiAKCmBgYHtyfQogd29ybGQgJT4lIGdncGxvdCggYWVzKHJlZ2ltZSkpKwpnZW9tX2JhcigpCgpgYGAKCldlIGNhbiBhc3NpZ24gdGhlIGdyYXBoIHRvIGFuIG9iamVjdCwgbGV0J3MgY2FsbCBpdCB3cGxvdDEuIEFuZCByZW1lbWJlciB3ZSBuZWVkIHRvIGFkZCB0aGUgb2JqZWN0IGluIHRoZSBjaHVuayBpZiB3ZSB3YW50IFIgdG8gInByaW50IiBpdCB0byBvdXIgc2NyZWVuLiBBbmQgYXMgYSBib251cywgd2UgY2FuIHVzZSB0aGUgb3B0aW9uIGZpbGwgdG8gY29sb3Igb3VyIGJhcnMuCmBgYHtyfQp3cGxvdDE8LSAgd29ybGQgJT4lIGdncGxvdCggYWVzKHJlZ2ltZSkgKSsKZ2VvbV9iYXIoZmlsbD0ibGlnaHRibHVlIikKCndwbG90MQpgYGAKCk5vdyBsZXQncyBhZGQgYSBiYXIgcGxvdCBvZiBmb3JlaWduIGRpcmVjdCBpbnZlc3RtZW50W2ZkaV0gd2hpY2ggaXMgdGhlIG5ldCBmb3JlaWduIGludmVzdG1lbnQgaW5mbG93cyBhcyBhIHBlcmNlbnRhZ2Ugb2YgR0RQKSBhZ2FpbnN0IHJlZ2ltZSB0eXBlLiBXZSB3aWxsIGZpcnN0IGdyb3VwIHRoZSBkYXRhIGJ5IHRoZSB2YXJpYWJsZSByZWdpbWUsIHRoZW4gY3JlYXRlIGEgbmV3IHZhcmlhYmxlICoqKm0qKiogdGhhdCBjb21wdXRlcyB0aGUgbWVhbiBvZiBmZGkgZm9yIGVhY2ggcmVnaW1lLCB0aGVuIHdlIGNhbiB1bmdyb3VwIHRoZSBkYXRhIGFnYWluIGFuZCBwcm9kdWNlIG91ciBncmFwaCBvZiBtZWFuIGZkaSBieSByZWdpbWUuIEFuZCByZW1lbWJlciB0aGF0IGVhY2ggb2YgdGhlc2Ugc3RlcHMgY2FuIGJlIHN0cmluZyB0b2dldGhlciBpbiB0aGUgdGlkeXZlcnNlIHdpdGggb3VyIHBpcGUgb3BlcmF0b3IgWyU+JV0uCgpgYGB7cn0KCndkYXQgJT4lIAogIGZpbHRlcighaXMubmEoZmRpKSkgJT4lICMgbmFtZSBvZiB0aGUgZGF0YXNldAogIGdyb3VwX2J5KHJlZ2ltZSkgJT4lICAgICAgICAgICAgICAgICAgICAjIGdyb3VwaW5nIHRoZSBkYXRhIGJ5IHR5cGUgb2YgcmVnaW1lCiAgc3VtbWFyaXplKG0gPSBtZWFuKGZkaSkpICU+JSAgICAgICAgICAgICMgY2FsY3VsYXRpbmcgdGhlIG1lYW4gb2YgZmRpCiAgdW5ncm91cCgpICU+JSAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdW5ncm91cCB0aGUgZGF0YSBhZ2FpbgogIGdncGxvdCggYWVzKHg9cmVnaW1lLCB5PW0pKSsgICAgICAgICAgICAjIHNldCB1cCB0aGUgZ3JhcGgKZ2VvbV9jb2woKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBzZXQgZ2VvbWV0cnkgb2YgdGhlIGdyYXBoCmBgYApOb3csIGxldCdzIHVzZSB0aGUgb3B0aW9uIGZpbGwgdG8gdGhlIGFlc3RoZXRpY3Mgb2Ygb3VyIHBsb3QgdG8gY29sb3Igb3VyIHBsb3Qgd2l0aCBlYWNoIGNhdGVnb3J5IG9mIHJlZ2ltZQoKYGBge3J9Cgp3ZGF0ICU+JSAKICBmaWx0ZXIoIWlzLm5hKGZkaSkpICU+JSAjIG5hbWUgb2YgdGhlIGRhdGFzZXQKICBncm91cF9ieShyZWdpbWUpICU+JSAgICAgICAgICAgICAgICAgICAgIyBncm91cGluZyB0aGUgZGF0YSBieSB0eXBlIG9mIHJlZ2ltZQogIHN1bW1hcml6ZShtID0gbWVhbihmZGkpKSAlPiUgICAgICAgICAgICAjIGNhbGN1bGF0aW5nIHRoZSBtZWFuIG9mIGZkaQogIHVuZ3JvdXAoKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHVuZ3JvdXAgdGhlIGRhdGEgYWdhaW4KICBnZ3Bsb3QoIGFlcyh4PXJlZ2ltZSwgeT1tLCBmaWxsPXJlZ2ltZSkpKyAgICAgICAgICAgICMgc2V0IHVwIHRoZSBncmFwaApnZW9tX2NvbCgpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHNldCBnZW9tZXRyeSBvZiB0aGUgZ3JhcGgKYGBgCgpMZXQncyBzZWUgaWYgb3VyIHBsb3QgaXMgbW9yZSByZWFkYWJsZSB3aGVuIHdlIHJvdGF0ZSBvdXIgcGxvdCwgY2hhbmdpbmcgdGhlIG9yaWVudGF0aW9uIG9mIHRoZSBiYXJzIHdpdGggdGhlIGNvb3JkX2ZsaXAgZnVuY3Rpb24uCmBgYHtyfQp3ZGF0ICU+JSAKICBmaWx0ZXIoIWlzLm5hKGZkaSkpICU+JSAjIG5hbWUgb2YgdGhlIGRhdGFzZXQKICBncm91cF9ieShyZWdpbWUpICU+JSAgICAgICAgICAgICAgICAgICAgIyBncm91cGluZyB0aGUgZGF0YSBieSB0eXBlIG9mIHJlZ2ltZQogIHN1bW1hcml6ZShtID0gbWVhbihmZGkpKSAlPiUgICAgICAgICAgICAjIGNhbGN1bGF0aW5nIHRoZSBtZWFuIG9mIGZkaQogIHVuZ3JvdXAoKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHVuZ3JvdXAgdGhlIGRhdGEgYWdhaW4KICBnZ3Bsb3QoIGFlcyh4PXJlZ2ltZSwgeT1tLGZpbGw9cmVnaW1lKSkgKyAgICMgc2V0IHVwIHRoZSBncmFwaApnZW9tX2NvbCgpICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHNldCBnZW9tZXRyeSBvZiB0aGUgZ3JhcGgKY29vcmRfZmxpcCgpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNmbGlwIHRoZSBvcmllbnRhdGlvbiBvZiB0aGUgYmFyIApgYGAKCkxhc3RseSwgb3VyIGNhdGVnb3JpZXMgY2FuIGJlIHJlb3JkZXJlZCBzbyBSb3lhbCBkaWN0YXRvcnNoaXAgaXMgbm90IHJpZ2h0IG5leHQgdG8gcHJlc2lkZW50aWFsIGRlbW9jcmFjeS4gCldlIGZpcnN0IG5lZWQgdG8gZGVmaW5lIGEgbmV3IHZhcmlhYmxlIHJlZzIgdGhhdCByZW9yZGVycyB0aGUgbGV2ZWxzIChjYXRlZ29yaWVzKSBvZiB0aGUgcmVnaW1lIHZhcmlhYmxlLgoKYGBge3J9Cgp3ZGF0IDwtIHdkYXQgJT4lIG11dGF0ZShyZWcyID0gZmFjdG9yKHJlZ2ltZSwKICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiUm95YWwgRGljdGF0b3JzaGlwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1pbGl0YXJ5IERpY3RhdG9yc2hpcCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDaXZpbGlhbiBEaWN0YXRvcnNoaXAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTWl4ZWQgRGVtb2NyYWN5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBhcmxpYW1lbnRhcnkgRGVtb2NyYWN5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlByZXNpZGVudGlhbCBEZW1vY3JhY3kiKSkpCndkYXQgJT4lIAogIGZpbHRlcighaXMubmEoZmRpKSkgJT4lICMgbmFtZSBvZiB0aGUgZGF0YXNldAogIGdyb3VwX2J5KHJlZzIpICU+JSAgICAgICAgICAgICAgICAgICAgIyBncm91cGluZyB0aGUgZGF0YSBieSB0eXBlIG9mIHJlZ2ltZQogIHN1bW1hcml6ZShtID0gbWVhbihmZGkpKSAlPiUgICAgICAgICAgICAjIGNhbGN1bGF0aW5nIHRoZSBtZWFuIG9mIGZkaQogIHVuZ3JvdXAoKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHVuZ3JvdXAgdGhlIGRhdGEgYWdhaW4KICBnZ3Bsb3QoIGFlcyh4PXJlZzIsIHk9bSxmaWxsPXJlZzIpKSArICAgIyBzZXQgdXAgdGhlIGdyYXBoCmdlb21fY29sKCkgKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgc2V0IGdlb21ldHJ5IG9mIHRoZSBncmFwaApjb29yZF9mbGlwKCkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI2ZsaXAgdGhlIG9yaWVudGF0aW9uIG9mIHRoZSBiYXIgCgpgYGAKCgpOb3cgbGV0J3MgYWRkIGEgcmVhZHktdG8tdXNlIHRoZW1lOiB0aGVtZV9taW5pbWFsKCkuIFdlIGFsc28gc3BlY2lmeSB0aGUgYXhpcyBmcm9tIDAgdG8gMTAgdG8gZml0IGJldHRlciB0aGUgYmFycywgYW5kIG9mIGNvdXJzZSwgd2Ugc2hvdWxkIGFsc28gYWRkIG1vcmUgaW5mb3JtYXRpdmUgbGFiZWxzIGZvciBvdXIgdmFyaWFibGVzCgpgYGB7cn0KCndkYXQgPC0gd2RhdCAlPiUgbXV0YXRlKHJlZzIgPSBmYWN0b3IocmVnaW1lLAogICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJSb3lhbCBEaWN0YXRvcnNoaXAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTWlsaXRhcnkgRGljdGF0b3JzaGlwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNpdmlsaWFuIERpY3RhdG9yc2hpcCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNaXhlZCBEZW1vY3JhY3kiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUGFybGlhbWVudGFyeSBEZW1vY3JhY3kiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUHJlc2lkZW50aWFsIERlbW9jcmFjeSIpKSkKd2RhdCAlPiUgCiAgZmlsdGVyKCFpcy5uYShmZGkpKSAlPiUgIyBuYW1lIG9mIHRoZSBkYXRhc2V0CiAgZ3JvdXBfYnkocmVnMikgJT4lICAgICAgICAgICAgICAgICAgICAjIGdyb3VwaW5nIHRoZSBkYXRhIGJ5IHR5cGUgb2YgcmVnaW1lCiAgc3VtbWFyaXplKG0gPSBtZWFuKGZkaSkpICU+JSAgICAgICAgICAgICMgY2FsY3VsYXRpbmcgdGhlIG1lYW4gb2YgZmRpCiAgdW5ncm91cCgpICU+JSAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdW5ncm91cCB0aGUgZGF0YSBhZ2FpbgogIGdncGxvdCggYWVzKHg9cmVnMiwgeT1tLGZpbGw9cmVnMikpICsgICAjIHNldCB1cCB0aGUgZ3JhcGgKZ2VvbV9jb2woKSArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBzZXQgZ2VvbWV0cnkgb2YgdGhlIGdyYXBoCmNvb3JkX2ZsaXAoeWxpbT1jKDAsMTApKSArICAKICB0aGVtZV9taW5pbWFsKCkrCiAgeWxhYigiRm9yZWlnbiBkaXJlY3QgaW52ZXN0bWVudCIpICsKICB4bGFiKCJSZWdpbWUiKSAKYGBgCgouIFdlIG5lZWQgdG8ga25vdyB0aGUgc2hhcGUgb2YgdGhlIGRhdGEgZmlyc3QgdG8gZGV0ZXJtaW5lIHdoYXQgc3VtbWFyaWVzIGFuZCBtb2RlbHMgdG8gdXNlLiBXaGVuIHdlIGxvb2sgYXQgdGhlIGRpc3RyaWJ1dGlvbiBvZiBvdXIgdmFyaWFibGVzIHdlIGNhbiBsZWFybiB3aGV0aGVyIGFsbCBjYXNlcyBhcmUgZXZlbmx5IGRpc3RyaWJ1dGVkIG9yIHdoZXRoZXIgdmFsdWVzIGNsdXN0ZXIgY2xvc2VyIHRvIHRoZSBtaW5pbXVtLCBtZWRpYW4sIG9yIG1heGltdW0uIAoKTGV0J3MgdXNlIHR3byBleGFtcGxlcyBvZiBvdXIgd29ybGQgZGF0YXNldC4gRmlyc3Qgd2Ugd2lsbCBleHBsb3JlIHRoZSBoaXN0b2dyYW0gb2YgdGhlIHZhcmlhYmxlIHR1cm5vdXQuIEFuZCBsZXQncyBhZGQgYW5vdGhlciBsYXllciB3aXRoIGEgZGVuc2l0eSBwbG90IHRvIHNlZSB0aGUgc21vb3RoIGRlbnNpdHkgbGluZS4gRm9yIGEgZ3JlYXQgZXhwbGFuYXRpb24gb2Yga2VybmVsIGRlbnNpdHkgSSByZWNvbW1lbmQgdGhpcyBsaW5rOiBodHRwczovL21hdGhpc29uaWFuLmdpdGh1Yi5pby9rZGUvCgpgYGB7cn0KCndvcmxkICU+JSBnZ3Bsb3QoYWVzKHggPSB0dXJub3V0KSkgKyAKICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IC4uZGVuc2l0eS4uKSwKICAgICAgICAgICAgICAgICBjb2xvdXIgPSAxLCBmaWxsID0gIndoaXRlIikgKwogIGdlb21fZGVuc2l0eSgpICsgCnhsYWIoIlZvdGVyIFR1cm5vdXQiKSArCmdndGl0bGUoIlZvdGVyIFR1cm5vdXQgSXMgTm9ybWFsbHkgRGlzdHJpYnV0ZWQiKSAKCmBgYAoKV2UgY2FuIHNlZSB0aGF0IHRoZSBkaXN0cmlidXRpb24gb2Ygdm90aW5nIHR1cm5vdXQgc2VlbXMgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuIExldCdzIGxvb2sgYXQgdGhlIHNoYXBlIG9mIHRoZSBpbmZhbnQgbW9ydGFsaXR5IGluIHRoZSB3b3JsZCAodGhlIG51bWJlciBvZiBkZWF0aHMgaW4gZWFjaCBjb3VudHJ5IHBlciAxLDAwMCBsaXZlIGJpcnRocyksIHVzaW5nIHRoZSB2YXJpYWJsZSBpbmYuCgpgYGB7cn0KCndvcmxkICU+JSBnZ3Bsb3QoYWVzKHggPSBpbmYpKSArIAogIGdlb21faGlzdG9ncmFtKGFlcyh5ID0gLi5kZW5zaXR5Li4pLAogICAgICAgICAgICAgICAgIGNvbG91ciA9IDEsIGZpbGwgPSAid2hpdGUiKSArCiAgZ2VvbV9kZW5zaXR5KCkgKyAKeGxhYigiSW5mYW50IE1vcnRhbGl0eSBSYXRlIikgKwpnZ3RpdGxlKCIgSW5mYW50IE1vcnRhbGl0eSBJcyBOb3QgTm9ybWFsbHkgRGlzdHJpYnV0ZWQiKSAKCmBgYApXZSBjYW4gc2VlIGZyb20gdGhlIGhpc3RvZ3JhbSB0aGF0IG1hbnkgY291bnRyaWVzIGhhdmUgbG93IGluZmFudCBtb3J0YWxpdHksIGFuZCwgdW5mb3J0dW5hdGVseSxzb21lIGNvdW50cmllcyBoYXZlIDMwLCA2MCwgYW5kIGV2ZW4gOTAgZGVhdGhzIHBlciAxLDAwMCBsaXZlIGJpcnRocy4KCgogICAgCiMjIyMgRml2ZSB2aWV3IG9mIFVuaXZhcmlhdGUgZGF0YQoKIyMjIyMgRnJlcXVlbmN5IFRhYmxlCgpVc2UgYSBmcmVxdWVuY3kgdGFibGUgd2hlbiB0aGUgdmFyaWFibGUgaXMgY2F0ZWdvcmljYWwuIFRoZSBmcmVxdWVuY3kgdGFibGUgaW5kaWNhdGVzIGhvdyBtYW55IGNhc2VzIHJlc2lkZSBpbiBlYWNoIGNhdGVnb3J5LCBnaXZpbmcgdGhlIGNhdGVnb3J54oCZcyByZWxhdGl2ZSBzaXplLiBMZXQncyB1c2UgdGhlIGZyZXEoKSAgY29tbWFuZCB0byBnZXQgYSBmcmVxdWVuY3kgdGFibGUgb2YgdGhlICBOYXRpb25hbCBFbGVjdGlvbiBTdHVkaWVzIChuZXMpIGRhdGFzZXQsIGFuZCBzZWUgaG93IG1hbnkgRGVtb2NyYXRzLCBSZXB1YmxpY2FucywgYW5kIEluZGVwZW5kZW50cyBhcmUgaW5jbHVkZWQuIApGaXJzdCBsZXQncyBzZXQgdGhlIGRlc2NyaWJlIHBsb3Qgb3B0aW9uIGFzIEZhbHNlIChkZXNjci5wbG90KS4KYGBge3J9Cm5lczwtcmVhZF9jc3YoZmlsZS5jaG9vc2UoKSkKRnJlcShuZXMkcGlkMywgcGxvdCA9IG9wdGlvbnMoZGVzY3IucGxvdCA9IEZBTFNFKSkKaGVhZChuZXMpCmBgYAoKTm93LCBpZiB3ZSBzZXQgdGhlIGRlc2NyLnBsb3QgPSBUUlVFLCB3ZSB3aWxsIGdldCB0aGEgZnJlcXVlbmN5IHRhYmxlIGFuZCBhIGhpc3RvZ3JhbS4gCmBgYHtyfQpGcmVxKG5lcyRwaWQzLCBwbG90ID0gb3B0aW9ucyhkZXNjci5wbG90ID0gVFJVRSkpCmBgYAoKRnJlcXVlbmN5IHRhYmxlcyBoZWxwIHVzIGdldCBhIGdvb2Qgc2Vuc2UgYWJvdXQgdGhlIGNhdGVnb3JpZXMgaW4gYSB2YXJpYWJsZSB0byBkZWNpZGUgaWYgd2UgbmVlZCB0byBjb21iaW5lIG9yIGV4Y2x1ZGUgc29tZSBjYXRlZ29yaWVzLiBGb3IgaW5zdGFuY2UsIGlmIHdlIGxvb2sgYXQgYSBmcmVxdWVuY3kgdGFibGUgb2YgdGhlIHZhcmlhYmxlIGVtcGxveSBmcm9tIHRoZSBORVMgZGF0YSBzZXQsIHdlIGNhbiBzZWUgdGhhdCB0aGVyZSBhcmUgbmluZSBjYXRlZ29yaWVzLCBvciB0aGF0ICDigJx0ZW1wb3JhcmlseSBsYWlkIG9mZuKAnSBvbmx5IGhhcyBmb3VyIHJlc3BvbmRlbnRzLCBzbyB3ZSBtaWdodCB3YW50IHRvIGNvbnNpZGVyIGNvbWJpbmluZyBpdCB3aXRoIHRoZSAib3RoZXIiIGNhdGVnb3J5CgpgYGB7cn0KRnJlcShuZXMkZW1wbG95LCBwbG90ID0gb3B0aW9ucyhkZXNjci5wbG90ID0gRkFMU0UpKQpgYGAKCiMjIyMjIEJhciBQbG90CgpCYXIgcGxvdHMgYXJlIHVzZWZ1bCB0byBpZGVudGlmeSBjYXRlZ29yaWVzIHdpdGggdGhlIGhpZ2hlc3QgZnJlcXVlbmN5IGFuZCBhcmUgYW4gZWFzeSB3YXkgdG8gbWFrZSBjb21wYXJpc29ucyBhY3Jvc3MgY2F0ZWdvcmllcy4gTGV0J3MgdHJ5IGNyZWF0aW5nIGEgYmFyIHBsb3Qgb2Ygb3VyIGVtcGxveW1lbnQgdmFyaWFibGVzLgoKYGBge3J9CmdncGxvdChuZXMsIGFlcyhlbXBsb3kpKSArCiAgZ2VvbV9iYXIoKSAKYGBgCk5vdywgbGV0J3MgdXNlIGFkZGl0aW9uYWwgb3B0aW9ucyB0byBtYWtlIG91ciBwbG90IGJldHRlciwgd2Ugd2lsbCBhZGQgYSB0aGVtZSwgYWRkIGEgdGl0bGUgZm9yIG91ciBwbG90IFtnZ3RpdGxlXSwgYWRkIGEgdGl0bGUgZm9yIG91ciB5IGxhYmVsIGFuZCByZW1vdmUgb3VyIHRpdGxlIGZvciBvdXIgeC1heGlzIGJ5IHNldHRpbmcgaXQgdG8gIiIuIFdlIHdpbGwgYWxzbyB1c2UgdGhlIFtjb29yZF9mbGlwXSB0byBjaGFuZ2UgdGhlIG9yaWVudGF0aW9uIG9mIG91ciBwbG90LiBBbmQgd2Ugd2lsbCBjaGFuZ2UgdGhlIGNvbG9yIHdpdGggdGhlIGZpbGwgb3B0aW9uLCBoZXJlIHdlIGFyZSB1c2luZyAibGlndGhibHVlIiwgYnV0IGZlZWwgZnJlZSB0byBwbGF5IHdpdGggb3RoZXIgY29sb3JzIFtodHRwczovL3ItZ3JhcGgtZ2FsbGVyeS5jb20vZ2dwbG90Mi1jb2xvci5odG1sXS4KCmBgYHtyfQpnZ3Bsb3QobmVzLCBhZXMoZW1wbG95KSkgKwogIGdlb21fYmFyKGZpbGwgPSAibGlnaHRibHVlIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgZ2d0aXRsZSgiQmFycGxvdCBvZiBFbXBsb3ltZW50IFZhcmlhYmxlIikgKwogIHhsYWIoIiIpICsKICB5bGFiKCJOdW1iZXIgb2YgUmVzcG9uZGVudHMiKSArCiAgY29vcmRfZmxpcCgpCgpgYGAKV2UgY2FuIHNlZSB0aGF0IGEgbGFyZ2Ugc2hhcmUgb2YgdGhlIHBvcHVsYXRpb24gaXMgZW1wbG95ZWQgZnVsbC10aW1lLiAKCgojIyMjIyBCb3hwbG90IChvciBCb3gtYW5kLVdoaXNrZXIgUGxvdCkKCkJveHBsb3RzIGFyZSB1c2VmdWwgdG8gcGxvdCB0aGUgZGlzdHJpYnV0aW9uIG9mIGEgY29udGludW91cyB2YXJpYWJsZS4gTGV0J3MgdXNlIGEgYm94cGxvdCB0byBsb29rIGF0IHRoZSBwZXJjZW50YWdlIG9mIHRoZSB2b3RpbmcgYWdlIHBvcHVsYXRpb24gdGhhdCB2b3RlZCBpbiBlYWNoIGNvdW50cnnigJlzIGxhc3QgbmF0aW9uYWwgZWxlY3Rpb24uIFNpbmNlIHdlIG9ubHkgd2FudCB0byBwbG90IG9uZSB2YXJpYWJsZSwgd2UgbmVlZCBzcGVjaWZ5IHRoYXQgeD3igJwg4oCdLiBUaGUgeSB2YXJpYWJsZSB3aWxsIGJlIG91ciAidHVybm91dCIgdmFyaWFibGUgZnJvbSB0aGUgd29ybGQgZGF0YXNldC4gCgpgYGB7cn0KZ2dwbG90KHdvcmxkLCBhZXMoeD0iIiwgdHVybm91dCkpICsKICBnZW9tX2JveHBsb3QoKSAKCmBgYAoKV2UgY2FuIHNlZSB0aGUgbWVkaWFuICh0aGUgdGhpY2sgbGluZSBpbiB0aGUgbWlkZGxlIG9mIHRoZSBib3gpIGlzIGEgYml0IGFib3ZlIDYwJSBhbmQgdGhlIGludGVycXVhcnRpbGUgcmFuZ2UgKHRoZSBib3gpIGlzIGJldHdlZW4gNTUlIGFuZCA4MCUuIE5vdywgbGV0J3MgZm9ybWF0IHRoZSBwbG90IGEgYml0IG1vcmUuIAoKCmBgYHtyfQpnZ3Bsb3Qod29ybGQsIGFlcyh4PSIiLCB0dXJub3V0KSkgKwogIGdlb21fYm94cGxvdChjb2w9ImRhcmsgZ3JlZW4iKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBnZ3RpdGxlKCJCb3hwbG90IG9mIFR1cm5vdXQiKSArCiAgeWxhYigiUGVyY2VudCBWb3RpbmcgaW4gTGFzdCBFbGVjdGlvbiIpICsKICB4bGFiKCIiKSArCiAgdGhlbWVfbWluaW1hbCgpCgpgYGAKCkFuZCByZW1lbWJlciBib3hwbG90cyBkb27igJl0IHR5cGljYWxseSBzaG93IGluZGl2aWR1YWwgb2JzZXJ2YXRpb25zLCBzbyB3ZSB3aWxsICDigJxqaXR0ZXLigJ0gdGhlIHBvaW50cyBzbyB0aGF0IHRoZXkgZG9u4oCZdCBsaWUgZGlyZWN0bHkgb24gdG9wIG9mIGVhY2ggb3RoZXIuIFdlIGNvbnRyb2wgdGhlIHNpemUgb2YgdGhlIHBvaW50cyB3aXRoIHRoZSBbc2l6ZV0gb3B0aW9uLCB0aGUgZmlsbCBjb2xvciB3aXRoIHRoZSBbZmlsbF0gb3B0aW9uIGFuZCB0aGUgb3V0bGluZSBjb2xvciB3aXRoIHRoZSBbY29sb3VyXSBvcHRpb24uCgpgYGB7cn0KCmdncGxvdCh3b3JsZCwgYWVzKHg9IiIsIHR1cm5vdXQpKSArCiAgZ2VvbV9ib3hwbG90KGNvbD0iZGFya2dyZWVuIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgZ2d0aXRsZSgiQm94cGxvdCBvZiBUdXJub3V0IikgKwogIHlsYWIoIlBlcmNlbnQgVm90aW5nIGluIExhc3QgRWxlY3Rpb24iKSArCiAgeGxhYigiIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgICBnZW9tX3BvaW50KGZpbGwgPSAiZ3JleSIsIHNpemU9MSwKICAgICAgICAgICAgIHNoYXBlPTIxLCBjb2xvdXI9ImdyZXkiLAogICAgICAgICAgICAgcG9zaXRpb249cG9zaXRpb25faml0dGVyKHNlZWQgPSAxKSkKCmBgYAoKQW5kIGlmIHdlIHdhbnQgdG8gbGVhcm4gYSBib251cyB0cmljaywgd2UgY2FuIGFkZCBhICBnZW9tX3RleHRfcmVwZWwgbGF5ZXIgd2hlcmUgd2UgdXNlIHRoZSBpZmVsc2UgY29uZGl0aW9uYWwgdG8gb25seSBzaG93IHRoZSBsYWJlbCBvbmx5IGZvciBDYW5hZGEgb3IgdGhlIFVTLiBXZSB1c2UgdGhlIGlmZWxzZSgpIGZ1bmN0aW9uIHRvIHNheSB0aGF0IGlmIHRoZSBsYWJlbCBpcyBlcXVhbCB0byBDYW5hZGEgKENBTikgb3IgdGhlIFVTIChVU0EpLCB0aGVuIGxhYmVsIHRoZW0gd2l0aCB0aGUgZHBpY29kZSB2YXJpYWJsZTsgb3RoZXJ3aXNlIGxlYXZlIGl0IGJsYW5rLiBXZSBzcGVjaWZ5IOKAnGJsYW5r4oCdIHdpdGggdGhlIHR3byBzaW5nbGUgcXVvdGF0aW9ucyB3aXRoIG5vdGhpbmcgaW4gYmV0d2VlbiAo4oCYIOKAmSkuCgoKYGBge3J9CgpnZ3Bsb3Qod29ybGQsIGFlcyh4PSIiLCB0dXJub3V0KSkgKwogIGdlb21fYm94cGxvdChjb2w9ImRhcmtncmVlbiIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGdndGl0bGUoIkJveHBsb3Qgb2YgVHVybm91dCIpICsKICB5bGFiKCJQZXJjZW50IFZvdGluZyBpbiBMYXN0IEVsZWN0aW9uIikgKwogIHhsYWIoIiIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogICAgZ2VvbV9wb2ludChmaWxsID0gImdyZXkiLCBzaXplPTEsCiAgICAgICAgICAgICBzaGFwZT0yMSwgY29sb3VyPSJncmV5IiwKICAgICAgICAgICAgIHBvc2l0aW9uPXBvc2l0aW9uX2ppdHRlcihzZWVkID0gMSkpICsKICAgICBnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsPWlmZWxzZShkcGljb2RlPT0iQ0FOIiB8IGRwaWNvZGU9PSJVU0EiLCBhcy5jaGFyYWN0ZXIoZHBpY29kZSksJycpKSwgY29sID0iZ3JleSIsCiAgICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyKHNlZWQgPSAxKSwKICAgICAgICAgICAgICAgICAgaGp1c3Q9MSwgdmp1c3Q9MikgICAgICAKCgpgYGAKCiAgYWVzKGxhYmVsPWlmZWxzZShzdD09IkhJIiB8IHN0PT0iTUEiLCBhcy5jaGFyYWN0ZXIoc3QpLCcnKSwKICAgIGhqdXN0ID0gMCwgdmp1c3Q9LTEpLCBzaG93LmxlZ2VuZD1GQUxTRSkKICAgIAojIyMjIyBIaXN0b2dyYW0KCldlIHVzZSBoaXN0b2dyYW1zIHRvIHZpc3VhbGl6ZSB0aGUgZnJlcXVlbmN5IGRpc3RyaWJ1dGlvbiBvZiBjb250aW51b3VzIHZhcmlhYmxlcy4gVGhleSBzaG93IHRoZSBzaGFwZSBvZiB0aGUgdmFyaWFibGXigJlzIGRpc3RyaWJ1dGlvbiwgYW5kIGhvdyBkaXNwZXJzZSB0aGUgdmFsdWVzIG9mIHRoZSB2YXJpYWJsZSBhcmUuIEVhY2ggYmFyIHJlcHJlc2VudHMgYSByYW5nZSBvZiB2YWx1ZXMgKCBhIGJpbikgYW5kIHdlIGNhbiBkZWZpbmUgdGhlIG51bWJlciBvZiBiaW5zIHRoYXQgbWFrZXMgYmV0dGVyIHNlbnNlIGZvciBvdXIgZGF0YS4gTGV0J3MgY3JlYXRlIGEgaGlzdG9ncmFtIG9mIHRoZSB5ZWFycyBzaW5jZSBsYXN0IHJlZ2ltZSBjaGFuZ2UgZm9yIGFsbCBjb3VudHJpZXMgaW4gdGhlIFdvcmxkIGRhdGFzZXQgdXNpbmcgdGhlIHZhcmlhYmxlIFtkdXJhYmxlXS4KCmBgYHtyfQpnZ3Bsb3Qod29ybGQsIGFlcyhkdXJhYmxlKSkgKwogIGdlb21faGlzdG9ncmFtKCkgCmBgYApOb3cgbGV0J3MgIGNoYW5nZSB0aGUgbnVtYmVyIG9mYmlucyB0bzEwIHdpdGggdGhlIG9wdGlvbiBbYmluXSwgYW5kIGZvcm1hdCB0aGUgaGlzdG9ncmFtIGJ5IHNldHRpbmcgdGhlIGNvbG9yLCB0aGUgdGhlbWUgYW5kIGxhYmVsaW4gdGhlIHZhcmlhYmxlIGFuZCB0aGUgcGxvdC4KYGBge3J9CmdncGxvdCh3b3JsZCwgYWVzKGR1cmFibGUpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucz0xMCwgZmlsbCA9ICJsaWdodGJsdWUiKSArCiAgZ2d0aXRsZSgiSGlzdG9ncmFtIG9mIHRoZSBkdXJhYmxlIFZhcmlhYmxlIikgKwogIHhsYWIoIlllYXJzIFNpbmNlIExhc3QgU2lnbmlmaWNhbnQgUmVnaW1lIENoYW5nZSIpICsKICB0aGVtZV9taW5pbWFsKCkgCgpgYGAKdGhpcyBpcyBhIG11Y2ggbW9yZSBpbmZvcm1hdGl2ZSBoaXN0b2dyYW0sIHNvIGl0J3MgaW1wb3J0YW50IHRvIHRoaW5rIGFib3V0IHRoZSBjaG9pY2VzIG9mIGJpbnMuIGZvciBpbnN0YW5jZSwgaWYgd2Ugd2VyZSB0byBvbmx5IHVzZSB0aHJlZSBiaW5zLCB0aGUgcmVzdWx0aW5nIGhpc3RvZ3JhbSB3aWxsIG5vdCBiZSBhcyB1c2VmdWw6CgpgYGB7cn0KZ2dwbG90KHdvcmxkLCBhZXMoZHVyYWJsZSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zPTMsIGZpbGwgPSAibGlnaHRibHVlIikgKwogIGxhYnModGl0bGUgPSBwYXN0ZSgiTm90IEVub3VnaCBCaW5zIikpICsKICB4bGFiKCJZZWFycyBTaW5jZSBMYXN0IFNpZ25pZmljYW50IFJlZ2ltZSBDaGFuZ2UiKSArCiAgeWxhYigiQ291bnQiKSsKICB0aGVtZV9taW5pbWFsKCkgCgpgYGAKCgojIyMjIyBTdGVtLWFuZC1MZWFmIFBsb3QKCk9uZSBhZGRpdGlvbmFsIGRlc2NyaXB0aXZlIHBsb3QgdGhhdCB3ZSBoYXZlIG5vdCBkaXNjdXNzZWQgaW4gY2xhc3MgaXMgdGhlIHN0ZW0tYW5kLWxlYWYgcGxvdCwgd2hpY2ggYWxzbyBoZWxwIHVzIHNlZSBhIHZhcmlhYmxl4oCZcyBkaXN0cmlidXRpb24gd2hlbiB0aGUgIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgaXMgc29tZXdoYXQgc21hbGwuVGhlIG51bWJlciBpbiB0aGUgbGVhZiByZXByZXNlbnRzIHRoZSBmaXJzdCBkZWNpbWFsLkxldCdzIHRyeSBhIHBsb3Qgb2YgaG91c2Vob2xkIGluY29tZSBmb3IgdGhlIDUwIHN0YXRlcywgdXNpbmcgdGhlIHZhcmlhYmxlIFtpbmNdLgoKCmBgYHtyfQpzdGVtKHN0YXRlcyRpbmMsIHNjYWxlPTEpCgpgYGAKCgpUaGUgc3RlbSBpcyBvcmRlcmVkIGJ5IDIsMDAwLiBFYWNoIHN0ZXAgcmVwcmVzZW50cyAkMiwwMDAuIEluIHRoZSBmaXJzdCByb3csIHdlIHNlZSBzaXggbnVtYmVycyAoc2l4IGxlYXZlcyksIG1lYW5pbmcgdGhlcmUgYXJlIHNpeCBjYXNlcyBiZXR3ZWVuIDMyLDAwMCBhbmQgMzQsMDAwLiBJbiB0aGlzIGNhc2UsIHdlIGRvbuKAmXQga25vdyBleGFjdGx5IHdoYXQgdGhlIG51bWJlcnMgYXJlOyB3ZSBqdXN0IGtub3cgdGhleeKAmXJlIGJldHdlZW4gMzIsMDAwIGFuZCAzNCwwMDAuIAoKCgojIyMjIEJpdmFyaWF0ZSBkZXNjcmlwdGl2ZXMKCkJpdmFyaWF0ZSBkZXNjcmlwdGlvbnMgaWxsdXN0cmF0ZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdHdvIHZhcmlhYmxlcywgd2hldGhlciB0aGV5IGFyZSBjb250aW51b3VzIG9yIGNhdGVnb3JpY2FsLiBCaXZhcmlhdGUgcGxvdHMgaGVscHMgdXMgdW5kZXJzdGFuZCB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHZhcmlhYmxlcyBhbmQgaWRlbnRpZnkgcG90ZW50aWFsIGRhdGEgZXJyb3JzLiAKCiMjIyMjIFNjYXR0ZXIgUGxvdAoKU2NhdHRlciBwbG90cyBhcmUgdHdvIGRpbWVuc2lvbmFsLCBzaG93aW5nIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0d28gY29udGludW91cyB2YXJpYWJsZXMuIEFuZCB3ZSBjYW4gdXNlIHRoZSBjb2xvciBvciBzaGFwZSBvZiB0aGUgcG9pbnQgdG8gYWRkIGEgdGhpcmQgdmFyaWFibGUuIExldCdzIGNyZWF0ZSBhIHNjYXR0ZXIgcGxvdCBvZiB2b3RpbmcgdHVybm91dCBhbmQgcG9saXRpY2FsIGtub3dsZWRnZSAoIHBlcmNlbnQgb2YgdGhlIHBvcHVsYXRpb24gdGhhdCByZWNvZ25pemVzIHRoZSBuYW1lIG9mIHRoZSBnb3Zlcm5vciBmb3IgYW55IGdpdmVuIHN0YXRlKSAKCgoKYGBge3J9CmdncGxvdChzdGF0ZXMsIGFlcyhrbm93Z292LCB0dXJub3V0LCBsYWJlbCA9IHN0KSkgKwogIGdlb21fcG9pbnQoKQpgYGAKCkFnYWluLCBsZXQncyBmb3JtYXQgb3VyIHNjYXR0ZXJwbG90LiAKYGBge3J9CmdncGxvdChzdGF0ZXMsIGFlcyhrbm93Z292LCB0dXJub3V0LCBsYWJlbCA9IHN0KSkgKwogIGdlb21fcG9pbnQoY29sPSJvcmFuZ2UiKSArCiAgZ2d0aXRsZSgiVHVybm91dCBOb3QgUmVsYXRlZCB0byBQb2xpdGljYWwgS25vd2xlZGdlIikgKwogIHlsYWIoIlZvdGluZyBUdXJub3V0IikgKwogIHhsYWIoIlBvbGl0aWNhbCBLbm93bGVkZ2UiKSArCiAgdGhlbWVfbWluaW1hbCgpIAoKYGBgCldlIGNhbiBxdWlja2x5IHRlbGwgdGhlcmUgaXMgbm90IG11Y2ggb2YgYSByZWxhdGlvbnNoaXAgYmV0d2VlbiBwb2xpdGljYWwga25vd2xlZGdlIGFuZCB2b3RpbmcgdHVybm91dCwgYXMgdHVybm91dCBkb2VzIG5vdCBzeXN0ZW1hdGljYWxseSBpbmNyZWFzZSBvciBkZWNyZWFzZSB3aXRoIGluY3JlYXNlcyBpbiBwb2xpdGljYWwgdHVybm91dC4gCgoKTGV0J3MgdXNlIGluZmFudCBtb3J0YWxpdHkgYW5kIHRoZSBwZXJjZW50YWdlIG9mIGEgc3RhdGXigJlzIHBvcHVsYXRpb24gdGhhdCBoYXMgYSBoaWdoIHNjaG9vbCBkZWdyZWUgaW4gb3VyIFN0YXRlcyBkYXRhc2V0IGFzIGFuIGV4YW1wbGUgb2YgYSBzY2F0dGVycGxvdCBzaG93aW5nIGEgZmFpcmx5IHN0cm9uZyByZWxhdGlvbnNoaXA6CgpgYGB7cn0KZ2dwbG90KHN0YXRlcywgYWVzKGhzZGlwbG9tYSwgaW5mYW50KSkgKwogIGdlb21fcG9pbnQoKSAKYGBgCk5vdyBsZXQncyBmb3JtYXQgb3VyIHBsb3QuIApgYGB7cn0KZ2dwbG90KHN0YXRlcywgYWVzKGhzZGlwbG9tYSwgaW5mYW50KSkgKwogIGdlb21fcG9pbnQoY29sPSJyZWQiKSArCiAgZ2d0aXRsZSgiRWR1Y2F0aW9uIFJlZHVjZXMgSW5mYW50IE1vcnRhbGl0eSIpICsKICB5bGFiKCJJbmZhbnQgTW9ydGFsaXR5IikgKwogIHhsYWIoIkhpZ2ggU2Nob29sIERpcGxvbWEiKSArCiAgdGhlbWVfbWluaW1hbCgpIAoKYGBgCgpBbmQgdG8gdGFrZSBpdCB1cCBhIGxldmVsLCBsZXQncyBkcmF3IGEgbGluZSBmaXQgdG8gdGhlIHBsb3Qgd2l0aCB0aGUgZ2VvbV9zbW9vdGggbGF5ZXIgYW5kIGEgbWV0aG9kID0gImxtIiAoZm9yIGxpbmVhciBmaXQpLgoKYGBge3J9CmdncGxvdChzdGF0ZXMsIGFlcyhoc2RpcGxvbWEsIGluZmFudCkpICsKICBnZW9tX3BvaW50KGNvbD0icmVkIikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbD0iZ3JleSIpICsKICBnZ3RpdGxlKCJTYW1lIEVkdWNhdGlvbiwgRGlmZmVyZW50IE91dGNvbWUiKSArCiAgeWxhYigiSW5mYW50IE1vcnRhbGl0eSIpICsKICB4bGFiKCJIaWdoIFNjaG9vbCBEaXBsb21hIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKIEFmdGVyIGFkZGluZyB0aGlzIGZpdHRlZCBsaW5lLCB3ZSBzZWUgdGhhdCB0aGVyZSBpcyBhIG5lZ2F0aXZlIGFzc29jaWF0aW9uIGJldHdlZW4gZWR1Y2F0aW9uIGFuZCBpbmZhbnQgbW9ydGFsaXR5OiBhcyBvbmUgdmFyaWFibGUgaW5jcmVhc2VzIChlZHVjYXRpb24pLCB0aGUgb3RoZXIgZGVjcmVhc2VzIChpbmZhbnQgbW9ydGFsaXR5KS4gSXQgaXMgYWxzbyBhIGZhaXJseSBsaW5lYXIgcmVsYXRpb25zaGlwLiBUaGUgZGVjbGluZSBpbiBpbmZhbnQgbW9ydGFsaXR5IGlzIGNvbnN0YW50IG92ZXIgdGhlIHJhbmdlIG9mIGVkdWNhdGlvbi4KCgojIyMjIyBCb3hwbG90IChCaXZhcmlhdGUpCgpCb3hwbG90cyBjYW4gYWxzbyBiZSB1c2VmdWwgd2hlbiBsb29raW5nIGF0IHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBjb250aW51b3VzIGFuZCBjYXRlZ29yaWNhbCB2YXJpYWJsZXMsIGlmIHRoZXJlIGFyZSBub3QgdG9vIG1hbnkgY2F0ZWdvcmllcyAoYmV0d2VlbiA1IGFuZCAxMCkuIExldCdzIGxvb2sgYXQgYSBib3hwbG90IG9mIHRoZSBmZWVsaW5nIHRoZXJtb21ldGVyIHRvd2FyZHMgc2NpZW5jZSAoYSB2YXJpYWJsZSByYW5naW5nIGZyb20gMCB0byAxMDAgdGhhdCBpbmRpY2F0ZSBob3cgc3VydmV5IHJlc3BvbmRlbnRzIGZlZWwgYWJvdXQgYSBwYXJ0aWN1bGFyIGtpbmQgb2YgcGVyc29uIG9yIHBvbGljeSkuICAKCgpgYGB7cn0KZ2dwbG90KG5lcywgYWVzKHBpZDcsIGZ0c2NpKSkgKwogIGdlb21fYm94cGxvdChjb2w9ImNhZGV0Ymx1ZSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9OCwgYW5nbGU9MCwgdmp1c3Q9LjcpKSArCiAgZ2d0aXRsZSgiUGFydGlzYW5zaGlwIFNoYXBlcyBBdHRpdHVkZXMiKSArCiAgeWxhYigiU2NpZW5jZSBUaGVybW9tZXRlciIpICsKICB4bGFiKCJQYXJ0eSBJZGVudGlmaWNhdGlvbiIpICsKICBjb29yZF9mbGlwKCkKCmBgYAoKTGV0J3MgdXNlIHRoZSBzdWJzZXQoKSBmdW5jdGlvbiBpbiBvdXIgZmlyc3QgZ2dwbG90KCkgbGluZSB0byBmaWx0ZXIgb3V0IHRoZSBjYXRlZ29yaWVzICJOQSIgYW5kICJOb3QgU3VyZSIgZnJvbSB0aGUgcGFydHkgaWRlbnRpZmljYXRpb24gdmFyaWFibGUuIApgYGB7cn0KZ2dwbG90KHN1YnNldChuZXMsIHBpZDchPSJOQSIgJiBwaWQ3IT0iTm90IHN1cmUiKSwgYWVzKHBpZDcsIGZ0c2NpKSkgKwogIGdlb21fYm94cGxvdChjb2w9ImNhZGV0Ymx1ZSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9OCwgYW5nbGU9MCwgdmp1c3Q9LjcpKSArCiAgZ2d0aXRsZSgiUGFydGlzYW5zaGlwIFNoYXBlcyBBdHRpdHVkZXMiKSArCiAgeWxhYigiU2NpZW5jZSBUaGVybW9tZXRlciIpICsKICB4bGFiKCJQYXJ0eSBJZGVudGlmaWNhdGlvbiIpICsKICBjb29yZF9mbGlwKCkKCmBgYAojIyMjIyBNb3NhaWMgUGxvdAoKTW9zYWljIFBsb3QgaXMgYW4gaW50dWl0aXZlIHZpc3VhbCByZXByZXNlbnRhdGlvbiBvZiBjcm9zcy10YWJzICh0YWJsZXMgdGhhdCBkaXNwbGF5IHRoZSBhc3NvY2lhdGlvbiBiZXR3ZWVuIHR3byBjYXRlZ29yaWNhbCB2YXJpYWJsZXMpLiAgTW9zYWljIHBsb3RzIHNob3cgdGhlIGJyZWFrZG93biBiZXR3ZWVuIHRoZSBjYXRlZ29yaWVzIGZvIHRoZSB0d28gdmFyaWFibGVzLCBidXQgYWxzbyB1c2VzIHRoZSB3aWR0aCBvZiB0aGUgYmFycyB0byByZXByZXNlbnQgdGhlIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgaW4gZWFjaCBjYXRlZ29yeSBvZiB0aGUgIHggYXhpcy4KCmBgYHtyfQpnZ3Bsb3QobmVzKSsKICBnZW9tX21vc2FpYyhhZXMoeCA9IHByb2R1Y3QoZ2VuZGVyLCBwaWQzKSwKICBmaWxsPWdlbmRlcixuYS5ybT1UUlVFKSkKYGBgCkxldCdzIHRyeSB0byBmaWx0ZXJlZCBvYnNlcnZhdGlvbnMgd2l0aCB2YWx1ZXMgIk5vdCBzdXJlIiwgIk90aGVyIiBpbiBhIG5ldyB2YXJpYWxiZSBwaWQzX25ldy4gYW5kIGFsc28gbWlzc2luZyB2YWx1ZXMgKHVzaW5nICAiTkEiKQpgYGB7cn0KCgpnZ3Bsb3Qoc3Vic2V0KG5lcywgcGlkMyAlaW4lIGMoIkRlbW9jcmF0IiwiUmVwdWJsaWNhbiIsIkluZGVwZW50IiksICBwaWQzIT0iTkEiKSwgYWVzKHggPSBnZW5kZXIsIHk9IHBpZDMpKSArCmdlb21fbW9zYWljKGFlcyh4ID0gcHJvZHVjdChnZW5kZXIsIHBpZDMpLAogIGZpbGw9Z2VuZGVyLG5hLnJtPVRSVUUpKSArCiAgeGxhYigiIikgKwogIHlsYWIoIiIpICsKICBnZ3RpdGxlKCJHZW5kZXIgYnkgUGFydHkgSWRlbnRpZmljYXRpb24iKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlPSJCbHVlcyIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgoKICAKYGBgCgpUaGUgbW9zYWljIHBsb3QgaW5kaWNhdGVzIG1hbGVzIG1ha2UgdXAgYSBzbGlnaHRseSBsYXJnZXIgcGVyY2VudGFnZSBvZiBJbmRlcGVuZGVudHMgdGhhbiBlaXRoZXIgUmVwdWJsaWNhbnMgb3IgRGVtb2NyYXRzLiAgV2UgY2FuIG9ic2VydmUgIHRoYXQgd29tZW4gYXJlIG5vdCBzeXN0ZW1hdGljYWxseSBtb3JlIGNvbnNlcnZhdGl2ZSB0aGFuIG1lbi4gQW5kIHdlIGNhbiBsb29rIGF0IHRoZSB3aWR0aCBvZiB0aGUgY29sdW1ucyB0byBvYnNlcnZlIHRoYXQgYSBsYXJnZXIgcGVyY2VudGFnZSBvZiB0aGUgcG9wdWxhdGlvbiBpZGVudGlmaWVzIHdpdGggdGhlIERlbW9jcmF0aWMgcGFydHksIHRoZW4gSW5kZXBlbmRlbnRzLCBmb2xsb3dlZCBieSBSZXB1YmxpY2Fucy4KCiBub3csIGxldCdzIGNyZWF0ZSBhIG1vc2FpYyBwbG90IHVzaW5nIHZhcmlhYmxlcyAgcGFydHkgaWRlbnRpZmljYXRpb24gYW5kIHdoZXRoZXIgdGhlIHJlc3BvbmRlbnQgd29ycmllcyBhYm91dCB0ZXJyb3Jpc20gZnJvbSB0aGUgTkVTIGRhdGEuV2UgYXJlIGZpcnN0IGdvaW5nIHRvIGNyZWF0ZSBhIG5ldyB2YXJpYWJsZSB2YXIyLCB0aGF0IGV4Y2x1ZGVzIG9ic2VydmF0aW9ucyB3aXRoIHZhbHVlcyBlcXVhbCAiTm90IGFza2VkIi4KCmBgYHtyfQpuZXMkdmFyMiA8LSBnc3ViKCJOb3QgYXNrZWQiLCAiIiwgYXMuY2hhcmFjdGVyKG5lcyR0ZXJyb3Jfd29ycnkpKQoKZ2dwbG90KGRhdGEgPSBzdWJzZXQobmVzLCBwaWQzIT0iTkEiICYgdmFyMiAhPSJOQSIpKSArCiAgZ2VvbV9tb3NhaWMoYWVzKHggPSBwcm9kdWN0KHZhcjIsIHBpZDMpLCBmaWxsPXZhcjIsIG5hLnJtPVRSVUUpKSArCiAgeGxhYigiIikgKwogIHlsYWIoIiIpICsKICBnZ3RpdGxlKCJEZW1vY3JhdHMgQXJlIExlc3MgV29ycmllZCBBYm91dCBUZXJyb3Jpc20iKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlPSJCbHVlcyIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpIAoKYGBgCgpXZSBjYW4gcXVpY2tseSBzZWUgdGhhdCBEZW1vY3JhdHMgYXJlIHRoZSBsZWFzdCB3b3JyaWVkIGFib3V0IGEgdGVycm9yaXN0IGF0dGFjay4KCgojIyMjIyBDcm9zcy1UYWIKCkNyb3NzLXRhYiBhcmUgYSBjb21tb25seSB1c2VkIHN1bW1hcnkgb2YgY2F0ZWdvcmljYWwgdmFyaWFibGVzLiBXZSBhcmUgZ29pbmcgdG8gdXNlIGl0IHRvIGxvb2sgYXQgdGhlIGJyZWFrZG93biBvZiBjYXRlZ29yaWVzIHVzaW5nIHZhcmlhYmxlcyAgcGFydHkgaWRlbnRpZmljYXRpb24gYW5kIEdlbmRlciBmcm9tIHRoZSBORVMgZGF0YS4KCgpUaGUgY3Jvc3MtdGFiIGluY2x1ZGVzIGJvdGggdGhlIGNvdW50IChmcmVxdWVuY3kpIGFuZCB0aGUgY29sdW1uIHBlcmNlbnRhZ2UuIEZvciBleGFtcGxlLCBsb29raW5nIGF0IHRoZSBUb3RhbCBjb2x1bW4sIHdlIGNhbiBzZWUgdGhlcmUgYXJlIDU3NyBmZW1hbGVzIGluIHRoZSBzYW1wbGUgYW5kIHRoYXQgdGhleSByZXByZXNlbnRzIDUyLjUlIG8gb2YgdGhlIHNhbXBsZSAoLjUyNSkgLWFkZCB0aGUgcGVyY2VudHMgZ29pbmcgZG93biB0aGUgY29sdW1uLCB0aGV5IHNob3VsZCBhZGQgdXAgdG8gMTAwJS0uCgoKYGBge3J9CkNyb3NzVGFibGUobmVzJGdlbmRlciwgbmVzJHBpZDMsCiAgICAgICAgICAgbWFpbj0iQ3Jvc3MtVGFidWxhdGlvbiBvZiBHZW5kZXIgYW5kIFBhcnR5IElEIiwKICAgICAgICAgICBwcm9wLmNoaXNxPUZBTFNFKQpgYGAKCiMjIyBxdWl6eiB0aW1lIAoKIyMjIyBMZXQncyBjcmVhdGUgbW9yZSB0YWJsZXMuIAoKCgpMZXQncyB1c2UgYWdhaW4ga2FibGUgaGVyZSB0byBjcmVhdGUgYSB0YWJsZSBvZiB0aGUgZGF0YWZyYW1lICJzdGRhdCIgd2UganVzdCBjcmVhdGVkIHdpdGggYSBzdWJzZXQgb2YgdGhlIHN0YXRlcyBkYXRhLiBUaGUgcGFja2FnZSBpbmNsdWRlcyBzaXggcmVhZHktdG8tdXNlIHRoZW1lcy4gTGV0J3MgdHJ5IHRoZSBrYWJsZV9taW5pbWFsKCksIGFuZCBhZGQgaXQgd2l0aCBhIHBpcGUgb3BlcmF0b3IgbGlrZSBpbiB0aGlzIGV4YW1wbGU6IE5vdGU6IHRoaXMgd2lsbCBmb2xsb3cgdGhlIHNhbWUgY29kZSBpbmNsdWRpbmcgaW4gdGhlICJUYWJsZXMiIHBhcnQgb2YgdGhpcyB0dXRvcmlhbCwgc28geW91IGp1c3QgbmVlZCB0byBhcHBseSBpdCB0byB0aGUgc3RkYXQgZGF0YXNldC4gCgpgYGB7cn0KIyBUYWJsZSB1c2luZwpzdGRhdCAlPiUga2JsKCklPiUgCiAga2FibGVfbWluaW1hbCgpCmBgYApub3cgbGV0J3MgYWRkIGEgY2FwdGlvbiB0byBvdXIgdGFibGU6ICJUYWJsZSBhOiBTdGF0ZXMgRGF0YSIKCmBgYHtyfQojbm93IGxldCdzIGFkZCBhIGNhcHRpb24gdG8gb3VyIHRhYmxlCmhlYWQoc3RkYXQpICU+JSAgIGtibChjYXB0aW9uID0gIlRhYmxlIGE6IFN0YXRlcyBEYXRhIiklPiUgCiAgICAgICAga2FibGVfbWluaW1hbCgpCgoKYGBgCgpub3cgbGV0J3MgdHJ5IGFub3RoZXIgdGhlbWUsIHRoaXMgdGltZSB0aGUga2FibGVfY2xhc3NpYyBbbm90ZTogT3RoZXIgdGhlbWVzIHRvIGNvbnNpZGVzOiBrYWJsZV9jbGFzc2ljKCksIGthYmxlX3BhcGVyKCksIGthYmxlX2NsYXNzaWNfMigpLGthYmxlX21pbmltYWwoKSwga2FibGVfbWF0ZXJpYWwoKV0KYGBge3J9CiNub3cgbGV0J3MgdHJ5IGFub3RoZXIgdGhlbWUKaGVhZChzdGRhdCkgJT4lICAga2JsKGNhcHRpb24gPSAiVGFibGUgYTogU3RhdGVzIERhdGEiKSU+JSAKICAgICAgICBrYWJsZV9taW5pbWFsKCkKCgpgYGAKCmFuZCBpZiB3ZSBzcGVjaWZ5IGZ1bGxfd2lkdGggZmFsc2UgKD1GKSwgbm90aWNlIHRoZSBjaGFuZ2UKCmBgYHtyfQpoZWFkKHN0ZGF0KSAlPiUgICBrYmwoY2FwdGlvbiA9ICJUYWJsZSBhOiBTdGF0ZXMgRGF0YSIpJT4lIAogICAgICAgIGthYmxlX2NsYXNzaWMoIGZ1bGxfd2lkdGggPSBGKQoKCmBgYAoKTm93IGxldCdzIHNwZWNpZnkgKCJob3ZlciIsIGZ1bGxfd2lkdGggPSBGKSBhbmQgYWZ0ZXIgcnVubmluZyB0aGUgY2h1bmsgaG92ZXIgeW91ciBtb3VzZSBvdmVyIHRoZSB0YWJsZS4KYGBge3J9CiNsZXQncyBzcGVjaWZ5IGhvdmVyCmhlYWQoc3RkYXQpICU+JSAgIGtibChjYXB0aW9uID0gIlRhYmxlIGE6IFN0YXRlcyBEYXRhIiklPiUgCiAgICAgICAga2FibGVfY2xhc3NpYygiaG92ZXIiLCBmdWxsX3dpZHRoID0gRikgCmBgYAoKV2UgY2FuIGFsc28gc3BlY2lmeSBhIG1vcmUgaW5mb3JtYXRpdmUgbmFtZSBmb3Igb3VyIGNvbHVtbnMuIExldCdzIHRyeSBjaGFuZ2luZyB0aGUgbGFiZWxzIHVzaW5nIGNvbC5uYW1lczogIGNvbC5uYW1lcyA9IGMoIlN0YXRlIiwgIlJlZ2lvbiIsICJUcnVtcCBXb24iLCAiUGVyY2VudCBXb21lbiIsICJJbmNvbWUiKSkKCmBgYHtyfQojbGV0J3MgY2hhbmdlIHRoZSBsYWJlbHMgZm9yIG91ciBjb2x1bW5zCnN0ZGF0ICU+JSAgIGtibChjYXB0aW9uID0gIlRhYmxlIGE6IFN0YXRlcyBEYXRhIiwKICAgICAgICAgICAgICAgICAgY29sLm5hbWVzID0gYygiU3RhdGUiLCAiUmVnaW9uIiwgIlRydW1wIFdvbiIsICJQZXJjZW50IFdvbWVuIiwgIkluY29tZSIpKSU+JSAKICAgICAgICBrYWJsZV9jbGFzc2ljKCJob3ZlciIsIGZ1bGxfd2lkdGggPSBGKQpgYGAKCgoKIyMjIyBUaW1lIHRvIHBsb3QgCgpVc2luZyB0aGUgc3RhdGVzIGRhdGFzZXQsIHByb2R1Y2UgZm91ciBkaWZmZXJlbnQgcGxvdHMgKHR3byB1bml2YXJpYXRlIC1zaW5nbGUgdmFyaWFibGUtIGFuZCB0d28gYml2YXJpYXRlIC10d28gdmFyaWFibGVzLSkgZm9sbG93aW5nIHRoZSBleGFtcGxlcyBpbiB0aGUgdHV0b3JpYWwuIAoKYGBge3J9CiN5b3VyIGNvZGUgZm9yIHBsb3QgMSBoZXJlCmdncGxvdChzdGF0ZXMsIGFlcyh4PSIiLCBkZW1vY3JhdCkpICsKICBnZW9tX2JveHBsb3QoKSAKCmBgYAoKCgpgYGB7cn0KI3lvdXIgY29kZSBmb3IgcGxvdCAyIGhlcmUKZ2dwbG90KHN0YXRlcywgYWVzKHJlZ2lvbikpICsKICBnZW9tX2JhcigpIAoKYGBgCgpgYGB7cn0KI3lvdXIgY29kZSBmb3IgcGxvdCAzIGhlcmUKZ2dwbG90KHN0YXRlcykrCiAgZ2VvbV9tb3NhaWMoYWVzKHggPSBwcm9kdWN0KHJlZ2lvbiwgd2VlZCksCiAgZmlsbD1yZWdpb24sbmEucm09VFJVRSkpCgpgYGAKCgpgYGB7cn0KI3lvdXIgY29kZSBmb3IgcGxvdCA0IGhlcmUKQ3Jvc3NUYWJsZShzdGF0ZXMkcmVnaW9uLCBzdGF0ZXMkd2VlZCwKICAgICAgICAgICBtYWluPSJDcm9zcy1UYWJ1bGF0aW9uIG9mIFJlZ2lvbiBhbmQgV2VlZCBVc2FnZSIsCiAgICAgICAgICAgcHJvcC5jaGlzcT1GQUxTRSkKYGBgCgoKCgojIyMgQWRkaXRpb25hbCBub3RlcwoKCkFkZCBhIG5ldyBjaHVuayBieSBjbGlja2luZyB0aGUgKkluc2VydCBDaHVuayogYnV0dG9uIG9uIHRoZSB0b29sYmFyIG9yIGJ5IHByZXNzaW5nICpDbWQrT3B0aW9uK0kqLgoKV2hlbiB5b3Ugc2F2ZSB0aGUgbm90ZWJvb2ssIGFuIEhUTUwgZmlsZSBjb250YWluaW5nIHRoZSBjb2RlIGFuZCBvdXRwdXQgd2lsbCBiZSBzYXZlZCBhbG9uZ3NpZGUgaXQgKGNsaWNrIHRoZSAqUHJldmlldyogYnV0dG9uIG9yIHByZXNzICpDbWQrU2hpZnQrSyogdG8gcHJldmlldyB0aGUgSFRNTCBmaWxlKS4gCgpUaGUgcHJldmlldyBzaG93cyB5b3UgYSByZW5kZXJlZCBIVE1MIGNvcHkgb2YgdGhlIGNvbnRlbnRzIG9mIHRoZSBlZGl0b3IuIENvbnNlcXVlbnRseSwgdW5saWtlICpLbml0KiwgKlByZXZpZXcqIGRvZXMgbm90IHJ1biBhbnkgUiBjb2RlIGNodW5rcy4gSW5zdGVhZCwgdGhlIG91dHB1dCBvZiB0aGUgY2h1bmsgd2hlbiBpdCB3YXMgbGFzdCBydW4gaW4gdGhlIGVkaXRvciBpcyBkaXNwbGF5ZWQuCgo=