Introduction

The previous sections corresponding to the t-test and the ANOVA test are about the relationship of a numerical variable with a categorical variable, in such a way that the goal is to compare and extrapolate the means of a numerical variable by groups of a categorical variable.

In this section we will look at bivariate relationships between two categorical (or factor in R terminology) variables. This evaluation is done using cross-tables (or contingency tables) and is evaluated using the chi-square test.

About the dataset

The data we are going to use should be cited as follows: Source: AmericasBarometer by the Latin American Public Opinion Project (LAPOP), wwww.LapopSurveys.org. We can download the data freely here.

This section loads a trimmed database, originally in SPSS (.sav) format. It is recommended to clean the Environment before starting this section.

This dataset is hosted in the “materials_edu” repository of the LAPOP account on GitHub. Using the library rio and the command import, we can import this database from this repository. In addition, the data from countries with codes less than or equal to 35 are selected, that is, the observations of the United States and Canada are eliminated.

library(rio) 
lapop18 = import("https://raw.github.com/lapop-central/materials_edu/main/LAPOP_AB_Merge_2018_v1.0.sav")
lapop18 = subset(lapop18, pais<=35)

We also load the dataset for the 2021 round.

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

Votes are counted fairly

The report The Pulse of Democracy for the 2021 round of the AmericasBarometer reports the results of variable COUNTFAIR1. Votes are counted correctly and fairly. Would you say it happens always, sometimes or never? Percentages are presented by countries.

This figure is reporting the cross of a categorical variable (or factor in R language), called “countfair1” that has three categories (never, sometimes and always), with other categorical variables called “pais” that has 15 categories (each country presented).

This variable is imported in R as numeric. For be able to work with this variable, we have to declare it as a factor variable, using the command as.factor. We then label this variable with the command levels.

library(haven)
lapop21$countfair1r = as.factor(lapop21$countfair1)
levels(lapop21$countfair1r) = c("Always", "Sometimes", "Never")
table(lapop21$countfair1r)
## 
##    Always Sometimes     Never 
##      3477      5235      1698

Cross-table of votes are counted fairly by country

Before replicating this figure, it is useful to see results in a cross-table. We can create this table with the command table. However, this table presents absolute frequencies. Also, this table shows that this question was not fielded in some countries.

table(lapop21$pais, lapop21$countfair1r)
##     
##      Always Sometimes Never
##   1       0         0     0
##   2       0         0     0
##   3       0         0     0
##   4       0         0     0
##   5     186       351   173
##   6     354       272    51
##   7     215       445   120
##   8     130       362   226
##   9     158       435   143
##   10    169       408   112
##   11    177       430    97
##   12    169       315   168
##   13    428       201    39
##   14    525       111    20
##   15    346       257   116
##   17    216       350   120
##   21    170       406    99
##   22      0         0     0
##   23    122       464    97
##   24    112       428   117

To reproduce the relative frequencies, we have to use the command prop.table. This command returns the percentages for the total by defect. We want to calculate percentages by rows (that is, by country) in this case.

prop.table(table(lapop21$pais, lapop21$countfair1r))
##     
##           Always   Sometimes       Never
##   1  0.000000000 0.000000000 0.000000000
##   2  0.000000000 0.000000000 0.000000000
##   3  0.000000000 0.000000000 0.000000000
##   4  0.000000000 0.000000000 0.000000000
##   5  0.017867435 0.033717579 0.016618636
##   6  0.034005764 0.026128722 0.004899135
##   7  0.020653218 0.042747358 0.011527378
##   8  0.012487992 0.034774256 0.021709894
##   9  0.015177714 0.041786744 0.013736792
##   10 0.016234390 0.039193084 0.010758886
##   11 0.017002882 0.041306436 0.009317963
##   12 0.016234390 0.030259366 0.016138329
##   13 0.041114313 0.019308357 0.003746398
##   14 0.050432277 0.010662824 0.001921230
##   15 0.033237272 0.024687800 0.011143132
##   17 0.020749280 0.033621518 0.011527378
##   21 0.016330451 0.039000961 0.009510086
##   22 0.000000000 0.000000000 0.000000000
##   23 0.011719500 0.044572526 0.009317963
##   24 0.010758886 0.041114313 0.011239193

To calculate the percentages by rows, we have to add the specification , 1 in prop.table. We can also nest this code in the command addmargins to calculate the sum of horizontal percentages. These are the same percentages that are presented in a bar plot below. These percentages are not equal to those presented in Figure 2.5 because this calculation does not include survey weights.

addmargins(prop.table(table(lapop21$pais, lapop21$countfair1r), 1)*100, 2)
##     
##          Always  Sometimes      Never        Sum
##   1                                             
##   2                                             
##   3                                             
##   4                                             
##   5   26.197183  49.436620  24.366197 100.000000
##   6   52.289513  40.177253   7.533235 100.000000
##   7   27.564103  57.051282  15.384615 100.000000
##   8   18.105850  50.417827  31.476323 100.000000
##   9   21.467391  59.103261  19.429348 100.000000
##   10  24.528302  59.216255  16.255443 100.000000
##   11  25.142045  61.079545  13.778409 100.000000
##   12  25.920245  48.312883  25.766871 100.000000
##   13  64.071856  30.089820   5.838323 100.000000
##   14  80.030488  16.920732   3.048780 100.000000
##   15  48.122392  35.744089  16.133519 100.000000
##   17  31.486880  51.020408  17.492711 100.000000
##   21  25.185185  60.148148  14.666667 100.000000
##   22                                            
##   23  17.862372  67.935578  14.202050 100.000000
##   24  17.047184  65.144597  17.808219 100.000000

Bar graph of votes are counted fairly by country

In the same way as we did in the section about ordinal variables, available here, we can replicate the comparative graph by country we have to create a contingency table between variables “countfair1” and “pais”. This cross-table is saved in an abject “count_pais”. We should note that the dataframe include a row for each value of “countfair1” in each country. In this way, we have 3 options x 20 countries = 60 rows.

count_pais = as.data.frame(round(prop.table(table(lapop21$pais, lapop21$countfair1r), 1), 3)*100)
count_pais

This table presents NAs for countries where the question “countfair1” was not asked. For this reason, we have to drop rows where there is no data. We can do this with the specification [-c(rows)]. After that we create a vector with the names of countries. We repeat names three times (15 countries x 3 options). We dd this vector to the dataframe in column “country”.

count_pais = count_pais[-c(1:4,18,21:24,38,41:44,58),]
country = c("Nicaragua","Costa Rica", "Panama", "Colombia", "Ecuador", "Bolivia", "Peru",
        "Paraguay", "Chile", "Uruguay", "Brazil", "Argentina", "Dom. Rep.","Jamaica", "Guyana", "Nicaragua","Costa Rica", "Panama", "Colombia", "Ecuador", "Bolivia", "Peru",
        "Paraguay", "Chile", "Uruguay", "Brazil", "Argentina", "Dom. Rep.","Jamaica", "Guyana","Nicaragua","Costa Rica", "Panama", "Colombia", "Ecuador", "Bolivia", "Peru",
        "Paraguay", "Chile", "Uruguay", "Brazil", "Argentina", "Dom. Rep.","Jamaica", "Guyana")
count_pais$country = country
count_pais

We have the elements in this dataframe “count_pais” to replicate the stacked bar plot. We specify in aes that percentages are in X axis, countries in Y axis and each bar is divided by column Var2.

library(ggplot2)
ggplot(data=count_pais, aes(x=Freq, y=country, fill=Var2))+
  geom_bar(stat="identity", width=0.3)+
  geom_text(aes(label=paste(Freq, "%", sep="")), color="white", 
            position=position_stack(vjust=0.5), size=2)+
  labs(x="Percentage", y="Country", fill="Votes are counted fairly",
       caption="AmericasBarometer by LAPOP, 2021")

Evaluating Democracy in Practice

From page 20, the report The Pulse of Democracy evaluates democracy in practice. In particular, this section of the report uses the variable “pn4”. This variable is worded as follows: “In general, would you say that you are very satisfied, satisfied, dissatisfied, or very dissatisfied with the way democracy works in (country)?”

The report indicates that this variable is recoded as a dichotomous variable to be able to work with percentages. In this section we are going to work with the original variable, which is an ordinal categorical variable (or factor).

Figure 1.14 of the report presents an evaluation of satisfaction with democracy by demographic and socioeconomic variables, such as educational level, quintiles of wealth, place of residence, gender or age groups. That is, satisfaction with democracy is used as the dependent variable and each demographic or socioeconomic variable as the independent variable.

For example, the report indicates that among men, 42.3% are satisfied with democracy (using the variable recoded as a dummy), while among women, this percentage drops to 36.9%. Here we are going to analyze these same variables, but using the variable “pn4” in its original form (as an ordinal categorical). Before proceeding, we need to recode the variables as factor and label them.

lapop18$gender = as.factor(lapop18$q1)
levels(lapop18$gender) = c("Male", "Female")
table(lapop18$gender)
## 
##   Male Female 
##  13943  14084

The same is done for the variable “pn4” which becomes a new variable “satis”.

lapop18$satis = as.factor(lapop18$pn4)
levels(lapop18$satis) = c("Very satisfied", "Satisfied", "Dissatisfied", "Very dissatisfied")
table(lapop18$satis)
## 
##    Very satisfied         Satisfied      Dissatisfied Very dissatisfied 
##              1727              8916             12455              3855

Cross-table of satisfaction with democracy by gender

With the new factor variables, we first calculate a cross-table or contingency table. The command table is used to present the frequencies of one or two variables. By convention, the dependent variable “satisfaction with democracy” is placed in the rows and the independent variable “gender” in the columns.

table(lapop18$satis, lapop18$gender)
##                    
##                     Male Female
##   Very satisfied     919    803
##   Satisfied         4821   4091
##   Dissatisfied      5994   6457
##   Very dissatisfied 1874   1979

To calculate the relative frequencies, you have to nest the command table inside the command prop.table. If nested only, this command calculates the proportions over the total observations.

prop.table(table(lapop18$satis, lapop18$gender))
##                    
##                           Male     Female
##   Very satisfied    0.03411538 0.02980919
##   Satisfied         0.17896652 0.15186725
##   Dissatisfied      0.22251095 0.23969857
##   Very dissatisfied 0.06956715 0.07346499

These proportions are not very useful for the comparison we want to make. What we require are the conditional distributions of “satisfaction with democracy” for each gender group. That is, calculate the percentages for each column. In order for prop.table to calculate these percentages, we have to add the specification (…, 2). Multiply by 100 to go from ratios to percentages. You can also nest all code inside the command addmargins to check the sum of percentages over the columns, with the specification (..., 1).

addmargins(prop.table(table(lapop18$satis, lapop18$gender), 2)*100, 1)
##                    
##                           Male     Female
##   Very satisfied      6.753380   6.024006
##   Satisfied          35.427690  30.690173
##   Dissatisfied       44.047619  48.439610
##   Very dissatisfied  13.771311  14.846212
##   Sum               100.000000 100.000000

The table shows that 6.8% of men are very satisfied with democracy, a percentage very similar to that of women. 44% of men are dissatisfied with democracy. In this category, women have a higher percentage (48.4%).

In this way, it is possible to compare the percentages of the dependent variable “satisfaction with democracy” for each category of the independent variable “gender”.

Graphs of satisfaction with democracy by gender

In the section about descriptives of ordinal variables, we presented a preview of what we are seeing in this section. Here we will revisit those themes, using the tidyverse.

To make the graph, we first create a new dataframe with the data from the cross-table. The command as.data.frame is used to transform the bivariate table into a new dataframe called “table”. Using this command, the results are sorted by new columns (Var1, Var2 and Freq) so that they can be used to create a graph.

table = as.data.frame(prop.table(table(lapop18$satis, lapop18$gender), 2)*100)
table

We will use the library ggplot2 and the command ggplot to create a bar chart, using the dataframe “table” containing the percentages of satisfaction with democracy for men and women. This command requires an aesthetic where it is specified that “Var1” will be included on the X axis, which corresponds to the categories of satisfaction with democracy. The “Freq” is included on the Y axis, which corresponds to percentages. Also included is the specification fill to indicate that it will be split into Male/Female groups for each category of “Var1” and ymax to specify the upper limit of the Y axis.

After defining the variables in the axes, it is indicated that a bar graph is wanted with the command geom_bar and with the specification position="dodge" it is indicated that a graph with bars separated by each combination of categories is wanted. The specification stat="identity" is added to indicate that the command works with the data in the table.

The command geom_text includes the percentages of each bar, which is found in the “Freq” column. These percentages are rounded with round to 1 decimal place and the “%” symbol is added with paste. Also included is the specification position=position_dodge(...) which places these percentages at the top of each column. The default option within this specification is width=NULL, but this way the percentages would be misplaced, so width=0.9 is defined to center the percentages.

By default, the legend includes the name of the column with the gender data, which is “Var2”. To change this name, use the command labs(fill="Gender") to properly name the legend. Finally, the Y and X axis are labeled with ylab and xlab.

library(ggplot2)
ggplot(data=table, aes(x=Var1, y=Freq, fill=Var2, ymax=60))+
  geom_bar(position="dodge", stat="identity")+
  geom_text(aes(label=paste(round(Freq, 1), "%", sep="")),
            position=position_dodge(width=0.9), vjust=-0.25)+
  labs(fill="Gender")+
  ylab("Percentage")+
  xlab("Satisfaction with democracy")

Other way to display this data is through stacked bars. That is, for each gender category, the distribution of satisfaction with democracy is shown. For this, we use the same command ggplot but now the order of the variables in the aesthetic is changed. Now the variable “Var2” (with the gender categories) is located on the X axis and each bar is divided according to the values of Var1.

The bar type changes in the command geom_bar to position="stack". In the same way, the data labels have to consider the position of each slice, with position=position_stack().

ggplot(data=table, aes(x=Var2, y=Freq, fill=Var1, ymax=100))+
  geom_bar(position="stack", stat="identity")+
  geom_text(aes(label=paste(round(Freq, 1), "%", sep="")),
            position=position_stack(), vjust=2)+
  labs(fill="Satisfaction with democracy")+
  ylab("Percentage")+
  xlab("Gender")

Cross-table of satisfaction with democracy by educational level

Figure 1.14 of the report shows the results on satisfaction with democracy (according to the recoded dummy variable) by educational level. As a second example, here we are going to replicate that relationship using the original variable of type factor.

We first recode the education variable. The original variable “ed” is a numerical variable (years of study). This variable has values ranging from 0 to 18. It is recoded in such a way that those with zero years of education are assigned a value of 0 “None”, those between 1 and 6 years of education are assigned a value of 1 “Primary”, those between 7 and 11 years of education are assigns them the value of 2 “Secondary” and between 12 and 18 years of education the value of 3 “Post-secondary”.

library(car)
lapop18$educ <- car::recode(lapop18$ed, "0=0; 1:6=1; 7:11=2; 12:18=3")
lapop18$educ <- as.factor(lapop18$educ)
levels(lapop18$educ) <- c("None", "Primary", "Secondary", "Post-secondary")
table(lapop18$educ)
## 
##           None        Primary      Secondary Post-secondary 
##            643           6156          10176          10595

With the recoded variable it is possible to calculate the cross-table of satisfaction with democracy by educational levels.

addmargins(prop.table(table(lapop18$satis, lapop18$educ), 2)*100, 1)
##                    
##                           None    Primary  Secondary Post-secondary
##   Very satisfied     13.818182   9.874826   6.002645       4.324428
##   Satisfied          38.363636  34.961752  33.045071      31.760523
##   Dissatisfied       34.363636  42.576495  46.596805      48.596963
##   Very dissatisfied  13.454545  12.586926  14.355479      15.318086
##   Sum               100.000000 100.000000 100.000000     100.000000

To create the graph, we have to save the table as a dataframe. The command as.data.frame is used to save the percentages so that they can be used with the command ggplot.

table2 <- as.data.frame(prop.table(table(lapop18$satis, lapop18$educ), 2)*100)
table2

In this case, since we have 4 categories for satisfaction with democracy and another 4 categories for educational levels, a bar graph would create 16 bars, which would complicate the comparison. So, in this case, the stacked bar type is preferred.

library(ggplot2)
ggplot(data=table2, aes(x=Var2, y=Freq, fill=Var1, ymax=100))+
  geom_bar(position="stack", stat="identity")+
  geom_text(aes(label=paste(round(Freq, 1), "%", sep="")),
            position=position_stack(), vjust=2)+
  labs(fill="Satisfaction with democracy")+
  ylab("Percentage")+
  xlab("Education level")

Figure 1.14 shows that there is a higher percentage of satisfaction with democracy among the least educated. This relationship can also be seen in this graph. The sectors “very satisfied” (in pink) and “satisfied” (in green) decrease as we go from none to primary, secondary and higher.

In all examples, we can observe percent differences in a variable by categories of other variable. These percentages can be compared directly in the graph, but we should run a significance test to evaluate if there is a statistically significant relationship.

Chi-square test of independence

Two categorical variables are said to be statistically independent if the conditional (population) distributions are identical for each category of the independent variable. In the above bivariate relationship, this means that being male or female does not change opinions regarding satisfaction with democracy. As these conditional distributions differ more from each other, both variables are said to be more related or more dependent.

This evaluation is done using the chi-square or \(\chi^2\) test of independence. This test is based on the comparison of the observed frequencies (the observations collected in the field) versus the expected frequencies (the observations that should be in each cell if the variables were independent). The test statistic summarizes how close the expected frequencies are to the observed frequencies.

\[ \chi^2 = \sum\frac{(f_o-f_e)^2}{f_e} \]

The smaller the distance in each cell, the less likely it is to reject the null hypothesis. The larger the distance in each cell, the more likely it is to reject the null hypothesis.

\[ H0: f_o = f_e \]

With the value of \(\chi^2\) and with the degrees of freedom (rows-1*columns-1), a p-value is calculated on the chi-square distribution. If this p-value is less than 0.05, H0 is rejected. This test requires that there be at least 5 observations in each cell.

Test of votes are counted fairly by country

In R, the command chisq.test is used to calculate the statistic and the associated p-value. The results of this test can be saved to a new object “chitest1”.

chitest1 <- chisq.test(lapop21$countfair1r, lapop21$pais)
chitest1
## 
##  Pearson's Chi-squared test
## 
## data:  lapop21$countfair1r and lapop21$pais
## X-squared = 1691.6, df = 28, p-value < 2.2e-16

The p-value obtained is less than 0.05, so the H0 is rejected, so we say that the observed frequencies seem to be different from the expected frequencies that would exist in each cell if there were no relationship, so we say that there is a relationship between the variables or that there is a dependency between the two.

It is important to note that “chitest1” is an object of type list. This type of object can store other information of a different type. For example, “chitest1” saves the tables of observed frequencies (same result as with the command table) and the table of expected frequencies. In this object the value of the residuals, the standardized residuals and the value of the p-value are also saved.

chitest1$observed
##                    lapop21$pais
## lapop21$countfair1r   5   6   7   8   9  10  11  12  13  14  15  17  21  23  24
##           Always    186 354 215 130 158 169 177 169 428 525 346 216 170 122 112
##           Sometimes 351 272 445 362 435 408 430 315 201 111 257 350 406 464 428
##           Never     173  51 120 226 143 112  97 168  39  20 116 120  99  97 117
chitest1$expected
##                    lapop21$pais
## lapop21$countfair1r        5        6        7        8        9       10
##           Always    237.1441 226.1219 260.5245 239.8161 245.8282 230.1300
##           Sometimes 357.0461 340.4510 392.2478 361.0692 370.1210 346.4856
##           Never     115.8098 110.4271 127.2277 117.1147 120.0507 112.3844
##                    lapop21$pais
## lapop21$countfair1r       11       12       13       14       15       17
##           Always    235.1401 217.7718 223.1159 219.1078 240.1501 229.1280
##           Sometimes 354.0288 327.8790 335.9251 329.8905 361.5720 344.9769
##           Never     114.8311 106.3493 108.9591 107.0017 117.2778 111.8951
##                    lapop21$pais
## lapop21$countfair1r       21       23       24
##           Always    225.4539 228.1259 219.4418
##           Sometimes 339.4452 343.4683 330.3934
##           Never     110.1009 111.4058 107.1648

To evaluate the strength of the relationship, we use the librery vcd that has the command assocstats that offers a series of measures of association for a cross-table between an ordinal variable, as “countfair1”, and a nominal variable, as “pais”.

The command assocstats cannot calculate measures of associations if cells of a cross-table have null values. Because we have some countries where question “countfair1” was not asked, we have to indicate that this command does not take into account these countries. For deal with this, we create a new “country2” variable, where observations of these countries are set as NAs.

lapop21$country_r = lapop21$pais
lapop21$country_r[lapop21$pais==1] = NA
lapop21$country_r[lapop21$pais==2] = NA
lapop21$country_r[lapop21$pais==3] = NA
lapop21$country_r[lapop21$pais==4] = NA
lapop21$country_r[lapop21$pais==22] = NA

With this new variable, we can create a cross-table between “countfair1” and “country_r” and calculate measures of association.

library(vcd)
table2 <- table(lapop21$countfair1r, lapop21$country_r)
assocstats(table2)
##                     X^2 df P(> X^2)
## Likelihood Ratio 1639.2 28        0
## Pearson          1691.6 28        0
## 
## Phi-Coefficient   : NA 
## Contingency Coeff.: 0.374 
## Cramer's V        : 0.285

The command assocstats returns the contingency coefficient and Cramer´s V as measures. These measures vary between 0 and 1. While closer to zero, the relationship is weaker. On the contrary, while closer to 1, the relationship is stronger.

By convention, we can assume that weak relationships are between 0 and 0.3, moderate relationships betwen 0.3 and 0.6 and strong relationships are higher than 0.6. In this case, we can indicate that the relationship between votes are counted fairly and country is weak.

Test of satisfaction with democracy by educational level

To evaluate the relationship between satisfaction with democracy and gender, we can also use the test of independence of \(\chi^2\). The results of this test are saved in an object “chitest2”.

chitest2 <- chisq.test(lapop18$satis, lapop18$educ)
chitest2
## 
##  Pearson's Chi-squared test
## 
## data:  lapop18$satis and lapop18$educ
## X-squared = 312.2, df = 9, p-value < 2.2e-16

Again, we obtain a p-value of less than 0.05, with which the null hypothesis is rejected and it is affirmed that the observed frequencies are different from those expected, with which we conclude that there would be a dependency relationship between the variables.

To evaluate the strength of the relationship, we use the library oii and the command association.measures, that return a series of association measures that fit this types of variables, that in this case are both ordinal

library(oii)
association.measures(lapop18$satis, lapop18$educ)
## Chi-square-based measures of association:
##    Phi:                      0.108 
##    Contingency coefficient:  0.108 
##    Cramer's V:               0.063 
## 
## Ordinal measures of association:
##    Total number of pairs:   352092916 
##    Concordant pairs:        84356625   ( 23.96 %)
##    Discordant pairs:        68163337   ( 19.36 %)
##    Tied on first variable:  80445182   ( 22.85 %)
##    Tied on second variable: 77098765   ( 21.9 %)
##    Tied on both variables:  42029007   ( 11.94 %)
## 
##    Goodman-Kruskal Gamma: 0.106 
##    Somers' d (col dep.):  0.071 
##    Kendall's tau-b:       0.070 
##    Stuart's tau-c:        0.061

In this case, we observe the measures of association for ordinal variables. This command reports 4 of these measurements, all of them vary between -1 to +1. In our example, they all have a positive sign, which indicates a direct relationship between both variables. This would seem to go against what is reported in Figure 1.14 of the report where it is clearly observed that satisfaction with democracy decreases at higher educational levels, which would be expressed in a negative sign.

This apparent contradiction is due on how satisfaction with democracy (“satis” variable that is created from “pn4”) has been coded. The original variable has values between 1 and 4, where 1 means “very satisfied” and 4 means “very dissatisfied”. That is, high values indicate “less”in the variable. It is for this reason that the association test results with a positive sign, which in this case would indicate that a higher value of the education variable means “more” of the satisfaction with democracy variable (which is actually less).

To avoid this confusion, the monotony of the satisfaction with democracy variable should have been changed so that higher values indicate greater satisfaction and, with this, a negative sign is obtained in the association measures. This has been done in this section to draw attention to the fact that coding has consequences for the results and can lead to confusion if care is not taken.

Finally, the value of the association measures are less than 0.3, indicating that the relationship between the variables is weak.

Summary

In this section we have worked with bivariate relationships between categorical variables. Cross-tables and bar graphs have been calculated to show the descriptive results. Then, the chi-square test of independence has been used to infer whether there is a dependency relationship between the variables in the population and finally the strength of the association between the variables is evaluated, differentiating when it comes to nominal or ordinal variables.

Calculations including survey weights

We calculate the percentage of votes are counted fairly by country including survey weights in the section about descriptives of ordinal variables. With this data, we replicate Figure 2.5.

To calculate a chi-square test including survey weights, we can use the library survey and the command svychisq.

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

We calculate the contingency table with the command svytable. In this case we cross satisfaction with democracy by gender. This command is nested inside prop.table to display the relative frequencies and not the absolute ones. In turn, all of this is nested inside the command addmargins to present the relative frequencies as percentages. In the same way as above, we can save this table in an object for graphing these results.

addmargins(prop.table(svytable(~satis+gender, design=design18),2)*100,1)
##                    gender
## satis                     Male     Female
##   Very satisfied      6.777875   6.025175
##   Satisfied          35.341585  30.695022
##   Dissatisfied       44.119892  48.450745
##   Very dissatisfied  13.760648  14.829058
##   Sum               100.000000 100.000000

The Chi-square test of independence incorporating survey weights is computed using the command svychisq. The dependent variable, the independent variable and the object are included with the sample design.

chitest3 =svychisq(~satis+gender,design18)
chitest3
## 
##  Pearson's X^2: Rao & Scott adjustment
## 
## data:  svychisq(~satis + gender, design18)
## F = 28.172, ndf = 2.9969, ddf = 3985.8861, p-value < 2.2e-16

The results show a p-value less than 0.05, so the H0 of equal expected and observed frequencies can be rejected, so we conclude that there is a relationship of statistical dependence between both variables.

Observed and expected values can be calculated. As can be seen, the expected values differ from the results without survey weights.

chitest3$observed
##                    gender
## satis                    Male    Female
##   Very satisfied     960.0493  836.1461
##   Satisfied         5005.9443 4259.7143
##   Dissatisfied      6249.3440 6723.7720
##   Very dissatisfied 1949.1214 2057.9086
chitest3$expected
##                    gender
## satis                    Male    Female
##   Very satisfied     907.2868  888.9086
##   Satisfied         4680.2311 4585.4274
##   Dissatisfied      6552.9267 6420.1893
##   Very dissatisfied 2024.0144 1983.0156

In this case, there is no command to calculate the association measures incorporating the design effect. Unweighted association measures can be taken as reference values.

LS0tCnRpdGxlOiAiQ3Jvc3MtdGFibGVzIHdpdGggdGhlIEFtZXJpY2FzQmFyb21ldGVyIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlCiAgICB0b2NfZGVwdGg6IDEKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIHRoZW1lOiBmbGF0bHkKICAgIGRmX3ByaW50OiBwYWdlZAogICAgc2VsZl9jb250YWluZWQ6IG5vCiAgICBrZWVwX21kOiB5ZXMKZWRpdG9yX29wdGlvbnM6IAogIG1hcmtkb3duOiAKICAgIHdyYXA6IHNlbnRlbmNlCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0UsIGNhY2hlPVRSVUUpCmBgYAoKYGBge2NzcyBjb2xvciwgZWNobz1GQUxTRX0KLmNvbHVtbnMge2Rpc3BsYXk6IGZsZXg7fQpoMSB7Y29sb3I6ICMzMzY2Q0M7fQpgYGAKCiMgSW50cm9kdWN0aW9uCgpUaGUgcHJldmlvdXMgc2VjdGlvbnMgY29ycmVzcG9uZGluZyB0byB0aGUgW3QtdGVzdF0oaHR0cHM6Ly9hcnR1cm9tYWxkb25hZG8uZ2l0aHViLmlvL0Jhcm9tZXRyb0VkdV9XZWJfRW5nL3R0ZXN0Lmh0bWwpIGFuZCB0aGUgW0FOT1ZBIHRlc3RdKGh0dHBzOi8vYXJ0dXJvbWFsZG9uYWRvLmdpdGh1Yi5pby9CYXJvbWV0cm9FZHVfV2ViX0VuZy9hbm92YS5odG1sKSBhcmUgYWJvdXQgdGhlIHJlbGF0aW9uc2hpcCBvZiBhIG51bWVyaWNhbCB2YXJpYWJsZSB3aXRoIGEgY2F0ZWdvcmljYWwgdmFyaWFibGUsIGluIHN1Y2ggYSB3YXkgdGhhdCB0aGUgZ29hbCBpcyB0byBjb21wYXJlIGFuZCBleHRyYXBvbGF0ZSB0aGUgbWVhbnMgb2YgYSBudW1lcmljYWwgdmFyaWFibGUgYnkgZ3JvdXBzIG9mIGEgY2F0ZWdvcmljYWwgdmFyaWFibGUuCgpJbiB0aGlzIHNlY3Rpb24gd2Ugd2lsbCBsb29rIGF0IGJpdmFyaWF0ZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gdHdvIGNhdGVnb3JpY2FsIChvciBmYWN0b3IgaW4gUiB0ZXJtaW5vbG9neSkgdmFyaWFibGVzLgpUaGlzIGV2YWx1YXRpb24gaXMgZG9uZSB1c2luZyBjcm9zcy10YWJsZXMgKG9yIGNvbnRpbmdlbmN5IHRhYmxlcykgYW5kIGlzIGV2YWx1YXRlZCB1c2luZyB0aGUgY2hpLXNxdWFyZSB0ZXN0LgoKIyBBYm91dCB0aGUgZGF0YXNldAoKVGhlIGRhdGEgd2UgYXJlIGdvaW5nIHRvIHVzZSBzaG91bGQgYmUgY2l0ZWQgYXMgZm9sbG93czogU291cmNlOiBBbWVyaWNhc0Jhcm9tZXRlciBieSB0aGUgTGF0aW4gQW1lcmljYW4gUHVibGljIE9waW5pb24gUHJvamVjdCAoTEFQT1ApLCB3d3d3LkxhcG9wU3VydmV5cy5vcmcuCldlIGNhbiBkb3dubG9hZCB0aGUgZGF0YSBmcmVlbHkgW2hlcmVdKGh0dHA6Ly9kYXRhc2V0cy5hbWVyaWNhc2Jhcm9tZXRlci5vcmcvZGF0YWJhc2UvbG9naW4ucGhwKS4KClRoaXMgc2VjdGlvbiBsb2FkcyBhIHRyaW1tZWQgZGF0YWJhc2UsIG9yaWdpbmFsbHkgaW4gU1BTUyAoLnNhdikgZm9ybWF0LgpJdCBpcyByZWNvbW1lbmRlZCB0byBjbGVhbiB0aGUgRW52aXJvbm1lbnQgYmVmb3JlIHN0YXJ0aW5nIHRoaXMgc2VjdGlvbi4KClRoaXMgZGF0YXNldCBpcyBob3N0ZWQgaW4gdGhlICJtYXRlcmlhbHNfZWR1IiByZXBvc2l0b3J5IG9mIHRoZSBMQVBPUCBhY2NvdW50IG9uIEdpdEh1Yi4KVXNpbmcgdGhlIGxpYnJhcnkgYHJpb2AgYW5kIHRoZSBjb21tYW5kIGBpbXBvcnRgLCB3ZSBjYW4gaW1wb3J0IHRoaXMgZGF0YWJhc2UgZnJvbSB0aGlzIHJlcG9zaXRvcnkuCkluIGFkZGl0aW9uLCB0aGUgZGF0YSBmcm9tIGNvdW50cmllcyB3aXRoIGNvZGVzIGxlc3MgdGhhbiBvciBlcXVhbCB0byAzNSBhcmUgc2VsZWN0ZWQsIHRoYXQgaXMsIHRoZSBvYnNlcnZhdGlvbnMgb2YgdGhlIFVuaXRlZCBTdGF0ZXMgYW5kIENhbmFkYSBhcmUgZWxpbWluYXRlZC4KCmBgYHtyIGJhc2V9CmxpYnJhcnkocmlvKSAKbGFwb3AxOCA9IGltcG9ydCgiaHR0cHM6Ly9yYXcuZ2l0aHViLmNvbS9sYXBvcC1jZW50cmFsL21hdGVyaWFsc19lZHUvbWFpbi9MQVBPUF9BQl9NZXJnZV8yMDE4X3YxLjAuc2F2IikKbGFwb3AxOCA9IHN1YnNldChsYXBvcDE4LCBwYWlzPD0zNSkKYGBgCgpXZSBhbHNvIGxvYWQgdGhlIGRhdGFzZXQgZm9yIHRoZSAyMDIxIHJvdW5kLgoKYGBge3J9CmxhcG9wMjEgPSBpbXBvcnQoImh0dHBzOi8vcmF3LmdpdGh1Yi5jb20vbGFwb3AtY2VudHJhbC9tYXRlcmlhbHNfZWR1L21haW4vbGFwb3AyMS5SRGF0YSIpCmxhcG9wMjEgPSBzdWJzZXQobGFwb3AyMSwgcGFpczw9MzUpCmBgYAoKIyBWb3RlcyBhcmUgY291bnRlZCBmYWlybHkKClRoZSByZXBvcnQgVGhlIFB1bHNlIG9mIERlbW9jcmFjeSBmb3IgdGhlIDIwMjEgcm91bmQgb2YgdGhlIEFtZXJpY2FzQmFyb21ldGVyIHJlcG9ydHMgdGhlIHJlc3VsdHMgb2YgdmFyaWFibGUgKipDT1VOVEZBSVIxLioqIFZvdGVzIGFyZSBjb3VudGVkIGNvcnJlY3RseSBhbmQgZmFpcmx5LgpXb3VsZCB5b3Ugc2F5IGl0IGhhcHBlbnMgYWx3YXlzLCBzb21ldGltZXMgb3IgbmV2ZXI/ClBlcmNlbnRhZ2VzIGFyZSBwcmVzZW50ZWQgYnkgY291bnRyaWVzLgoKVGhpcyBmaWd1cmUgaXMgcmVwb3J0aW5nIHRoZSBjcm9zcyBvZiBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlIChvciBmYWN0b3IgaW4gUiBsYW5ndWFnZSksIGNhbGxlZCAiY291bnRmYWlyMSIgdGhhdCBoYXMgdGhyZWUgY2F0ZWdvcmllcyAobmV2ZXIsIHNvbWV0aW1lcyBhbmQgYWx3YXlzKSwgd2l0aCBvdGhlciBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgY2FsbGVkICJwYWlzIiB0aGF0IGhhcyAxNSBjYXRlZ29yaWVzIChlYWNoIGNvdW50cnkgcHJlc2VudGVkKS4KCiFbXShGaWd1cmUyLjUucG5nKXt3aWR0aD0iNTk2In0KClRoaXMgdmFyaWFibGUgaXMgaW1wb3J0ZWQgaW4gUiBhcyBudW1lcmljLgpGb3IgYmUgYWJsZSB0byB3b3JrIHdpdGggdGhpcyB2YXJpYWJsZSwgd2UgaGF2ZSB0byBkZWNsYXJlIGl0IGFzIGEgZmFjdG9yIHZhcmlhYmxlLCB1c2luZyB0aGUgY29tbWFuZCBgYXMuZmFjdG9yYC4KV2UgdGhlbiBsYWJlbCB0aGlzIHZhcmlhYmxlIHdpdGggdGhlIGNvbW1hbmQgYGxldmVsc2AuCgpgYGB7cn0KbGlicmFyeShoYXZlbikKbGFwb3AyMSRjb3VudGZhaXIxciA9IGFzLmZhY3RvcihsYXBvcDIxJGNvdW50ZmFpcjEpCmxldmVscyhsYXBvcDIxJGNvdW50ZmFpcjFyKSA9IGMoIkFsd2F5cyIsICJTb21ldGltZXMiLCAiTmV2ZXIiKQp0YWJsZShsYXBvcDIxJGNvdW50ZmFpcjFyKQpgYGAKCiMgQ3Jvc3MtdGFibGUgb2Ygdm90ZXMgYXJlIGNvdW50ZWQgZmFpcmx5IGJ5IGNvdW50cnkKCkJlZm9yZSByZXBsaWNhdGluZyB0aGlzIGZpZ3VyZSwgaXQgaXMgdXNlZnVsIHRvIHNlZSByZXN1bHRzIGluIGEgY3Jvc3MtdGFibGUuCldlIGNhbiBjcmVhdGUgdGhpcyB0YWJsZSB3aXRoIHRoZSBjb21tYW5kIGB0YWJsZWAuCkhvd2V2ZXIsIHRoaXMgdGFibGUgcHJlc2VudHMgYWJzb2x1dGUgZnJlcXVlbmNpZXMuCkFsc28sIHRoaXMgdGFibGUgc2hvd3MgdGhhdCB0aGlzIHF1ZXN0aW9uIHdhcyBub3QgZmllbGRlZCBpbiBzb21lIGNvdW50cmllcy4KCmBgYHtyfQp0YWJsZShsYXBvcDIxJHBhaXMsIGxhcG9wMjEkY291bnRmYWlyMXIpCmBgYAoKVG8gcmVwcm9kdWNlIHRoZSByZWxhdGl2ZSBmcmVxdWVuY2llcywgd2UgaGF2ZSB0byB1c2UgdGhlIGNvbW1hbmQgYHByb3AudGFibGVgLgpUaGlzIGNvbW1hbmQgcmV0dXJucyB0aGUgcGVyY2VudGFnZXMgZm9yIHRoZSB0b3RhbCBieSBkZWZlY3QuCldlIHdhbnQgdG8gY2FsY3VsYXRlIHBlcmNlbnRhZ2VzIGJ5IHJvd3MgKHRoYXQgaXMsIGJ5IGNvdW50cnkpIGluIHRoaXMgY2FzZS4KCmBgYHtyfQpwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMjEkcGFpcywgbGFwb3AyMSRjb3VudGZhaXIxcikpCmBgYAoKVG8gY2FsY3VsYXRlIHRoZSBwZXJjZW50YWdlcyBieSByb3dzLCB3ZSBoYXZlIHRvIGFkZCB0aGUgc3BlY2lmaWNhdGlvbiBgLCAxYCBpbiBgcHJvcC50YWJsZWAuCldlIGNhbiBhbHNvIG5lc3QgdGhpcyBjb2RlIGluIHRoZSBjb21tYW5kIGBhZGRtYXJnaW5zYCB0byBjYWxjdWxhdGUgdGhlIHN1bSBvZiBob3Jpem9udGFsIHBlcmNlbnRhZ2VzLgpUaGVzZSBhcmUgdGhlIHNhbWUgcGVyY2VudGFnZXMgdGhhdCBhcmUgcHJlc2VudGVkIGluIGEgYmFyIHBsb3QgYmVsb3cuClRoZXNlIHBlcmNlbnRhZ2VzIGFyZSBub3QgZXF1YWwgdG8gdGhvc2UgcHJlc2VudGVkIGluIEZpZ3VyZSAyLjUgYmVjYXVzZSB0aGlzIGNhbGN1bGF0aW9uIGRvZXMgbm90IGluY2x1ZGUgc3VydmV5IHdlaWdodHMuCgpgYGB7cn0KYWRkbWFyZ2lucyhwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMjEkcGFpcywgbGFwb3AyMSRjb3VudGZhaXIxciksIDEpKjEwMCwgMikKYGBgCgojIEJhciBncmFwaCBvZiB2b3RlcyBhcmUgY291bnRlZCBmYWlybHkgYnkgY291bnRyeQoKSW4gdGhlIHNhbWUgd2F5IGFzIHdlIGRpZCBpbiB0aGUgc2VjdGlvbiBhYm91dCBvcmRpbmFsIHZhcmlhYmxlcywgYXZhaWxhYmxlIFtoZXJlXShodHRwczovL2FydHVyb21hbGRvbmFkby5naXRodWIuaW8vQmFyb21ldHJvRWR1X1dlYl9FbmcvRGVzY3JpcHRpdmVzMi5odG1sKSwgd2UgY2FuIHJlcGxpY2F0ZSB0aGUgY29tcGFyYXRpdmUgZ3JhcGggYnkgY291bnRyeSB3ZSBoYXZlIHRvIGNyZWF0ZSBhIGNvbnRpbmdlbmN5IHRhYmxlIGJldHdlZW4gdmFyaWFibGVzICJjb3VudGZhaXIxIiBhbmQgInBhaXMiLgpUaGlzIGNyb3NzLXRhYmxlIGlzIHNhdmVkIGluIGFuIGFiamVjdCAiY291bnRfcGFpcyIuCldlIHNob3VsZCBub3RlIHRoYXQgdGhlIGRhdGFmcmFtZSBpbmNsdWRlIGEgcm93IGZvciBlYWNoIHZhbHVlIG9mICJjb3VudGZhaXIxIiBpbiBlYWNoIGNvdW50cnkuCkluIHRoaXMgd2F5LCB3ZSBoYXZlIDMgb3B0aW9ucyB4IDIwIGNvdW50cmllcyA9IDYwIHJvd3MuCgpgYGB7cn0KY291bnRfcGFpcyA9IGFzLmRhdGEuZnJhbWUocm91bmQocHJvcC50YWJsZSh0YWJsZShsYXBvcDIxJHBhaXMsIGxhcG9wMjEkY291bnRmYWlyMXIpLCAxKSwgMykqMTAwKQpjb3VudF9wYWlzCmBgYAoKVGhpcyB0YWJsZSBwcmVzZW50cyBOQXMgZm9yIGNvdW50cmllcyB3aGVyZSB0aGUgcXVlc3Rpb24gImNvdW50ZmFpcjEiIHdhcyBub3QgYXNrZWQuCkZvciB0aGlzIHJlYXNvbiwgd2UgaGF2ZSB0byBkcm9wIHJvd3Mgd2hlcmUgdGhlcmUgaXMgbm8gZGF0YS4KV2UgY2FuIGRvIHRoaXMgd2l0aCB0aGUgc3BlY2lmaWNhdGlvbiBgWy1jKHJvd3MpXWAuCkFmdGVyIHRoYXQgd2UgY3JlYXRlIGEgdmVjdG9yIHdpdGggdGhlIG5hbWVzIG9mIGNvdW50cmllcy4KV2UgcmVwZWF0IG5hbWVzIHRocmVlIHRpbWVzICgxNSBjb3VudHJpZXMgeCAzIG9wdGlvbnMpLgpXZSBkZCB0aGlzIHZlY3RvciB0byB0aGUgZGF0YWZyYW1lIGluIGNvbHVtbiAiY291bnRyeSIuCgpgYGB7cn0KY291bnRfcGFpcyA9IGNvdW50X3BhaXNbLWMoMTo0LDE4LDIxOjI0LDM4LDQxOjQ0LDU4KSxdCmNvdW50cnkgPSBjKCJOaWNhcmFndWEiLCJDb3N0YSBSaWNhIiwgIlBhbmFtYSIsICJDb2xvbWJpYSIsICJFY3VhZG9yIiwgIkJvbGl2aWEiLCAiUGVydSIsCiAgICAgICAgIlBhcmFndWF5IiwgIkNoaWxlIiwgIlVydWd1YXkiLCAiQnJhemlsIiwgIkFyZ2VudGluYSIsICJEb20uIFJlcC4iLCJKYW1haWNhIiwgIkd1eWFuYSIsICJOaWNhcmFndWEiLCJDb3N0YSBSaWNhIiwgIlBhbmFtYSIsICJDb2xvbWJpYSIsICJFY3VhZG9yIiwgIkJvbGl2aWEiLCAiUGVydSIsCiAgICAgICAgIlBhcmFndWF5IiwgIkNoaWxlIiwgIlVydWd1YXkiLCAiQnJhemlsIiwgIkFyZ2VudGluYSIsICJEb20uIFJlcC4iLCJKYW1haWNhIiwgIkd1eWFuYSIsIk5pY2FyYWd1YSIsIkNvc3RhIFJpY2EiLCAiUGFuYW1hIiwgIkNvbG9tYmlhIiwgIkVjdWFkb3IiLCAiQm9saXZpYSIsICJQZXJ1IiwKICAgICAgICAiUGFyYWd1YXkiLCAiQ2hpbGUiLCAiVXJ1Z3VheSIsICJCcmF6aWwiLCAiQXJnZW50aW5hIiwgIkRvbS4gUmVwLiIsIkphbWFpY2EiLCAiR3V5YW5hIikKY291bnRfcGFpcyRjb3VudHJ5ID0gY291bnRyeQpjb3VudF9wYWlzCmBgYAoKV2UgaGF2ZSB0aGUgZWxlbWVudHMgaW4gdGhpcyBkYXRhZnJhbWUgImNvdW50X3BhaXMiIHRvIHJlcGxpY2F0ZSB0aGUgc3RhY2tlZCBiYXIgcGxvdC4KV2Ugc3BlY2lmeSBpbiBgYWVzYCB0aGF0IHBlcmNlbnRhZ2VzIGFyZSBpbiBYIGF4aXMsIGNvdW50cmllcyBpbiBZIGF4aXMgYW5kIGVhY2ggYmFyIGlzIGRpdmlkZWQgYnkgY29sdW1uIFZhcjIuCgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQpnZ3Bsb3QoZGF0YT1jb3VudF9wYWlzLCBhZXMoeD1GcmVxLCB5PWNvdW50cnksIGZpbGw9VmFyMikpKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5Iiwgd2lkdGg9MC4zKSsKICBnZW9tX3RleHQoYWVzKGxhYmVsPXBhc3RlKEZyZXEsICIlIiwgc2VwPSIiKSksIGNvbG9yPSJ3aGl0ZSIsIAogICAgICAgICAgICBwb3NpdGlvbj1wb3NpdGlvbl9zdGFjayh2anVzdD0wLjUpLCBzaXplPTIpKwogIGxhYnMoeD0iUGVyY2VudGFnZSIsIHk9IkNvdW50cnkiLCBmaWxsPSJWb3RlcyBhcmUgY291bnRlZCBmYWlybHkiLAogICAgICAgY2FwdGlvbj0iQW1lcmljYXNCYXJvbWV0ZXIgYnkgTEFQT1AsIDIwMjEiKQpgYGAKCiMgRXZhbHVhdGluZyBEZW1vY3JhY3kgaW4gUHJhY3RpY2UKCkZyb20gcGFnZSAyMCwgdGhlIHJlcG9ydCAqVGhlIFB1bHNlIG9mIERlbW9jcmFjeSogZXZhbHVhdGVzIGRlbW9jcmFjeSBpbiBwcmFjdGljZS4KSW4gcGFydGljdWxhciwgdGhpcyBzZWN0aW9uIG9mIHRoZSByZXBvcnQgdXNlcyB0aGUgdmFyaWFibGUgInBuNCIuClRoaXMgdmFyaWFibGUgaXMgd29yZGVkIGFzIGZvbGxvd3M6ICJJbiBnZW5lcmFsLCB3b3VsZCB5b3Ugc2F5IHRoYXQgeW91IGFyZSB2ZXJ5IHNhdGlzZmllZCwgc2F0aXNmaWVkLCBkaXNzYXRpc2ZpZWQsIG9yIHZlcnkgZGlzc2F0aXNmaWVkIHdpdGggdGhlIHdheSBkZW1vY3JhY3kgd29ya3MgaW4gKGNvdW50cnkpPyIKClRoZSByZXBvcnQgaW5kaWNhdGVzIHRoYXQgdGhpcyB2YXJpYWJsZSBpcyByZWNvZGVkIGFzIGEgZGljaG90b21vdXMgdmFyaWFibGUgdG8gYmUgYWJsZSB0byB3b3JrIHdpdGggcGVyY2VudGFnZXMuCkluIHRoaXMgc2VjdGlvbiB3ZSBhcmUgZ29pbmcgdG8gd29yayB3aXRoIHRoZSBvcmlnaW5hbCB2YXJpYWJsZSwgd2hpY2ggaXMgYW4gb3JkaW5hbCBjYXRlZ29yaWNhbCB2YXJpYWJsZSAob3IgZmFjdG9yKS4KCkZpZ3VyZSAxLjE0IG9mIHRoZSByZXBvcnQgcHJlc2VudHMgYW4gZXZhbHVhdGlvbiBvZiBzYXRpc2ZhY3Rpb24gd2l0aCBkZW1vY3JhY3kgYnkgZGVtb2dyYXBoaWMgYW5kIHNvY2lvZWNvbm9taWMgdmFyaWFibGVzLCBzdWNoIGFzIGVkdWNhdGlvbmFsIGxldmVsLCBxdWludGlsZXMgb2Ygd2VhbHRoLCBwbGFjZSBvZiByZXNpZGVuY2UsIGdlbmRlciBvciBhZ2UgZ3JvdXBzLgpUaGF0IGlzLCBzYXRpc2ZhY3Rpb24gd2l0aCBkZW1vY3JhY3kgaXMgdXNlZCBhcyB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIGFuZCBlYWNoIGRlbW9ncmFwaGljIG9yIHNvY2lvZWNvbm9taWMgdmFyaWFibGUgYXMgdGhlIGluZGVwZW5kZW50IHZhcmlhYmxlLgoKIVtdKEZpZ3VyZTEuMTQuSlBHKXt3aWR0aD0iNDE5In0KCkZvciBleGFtcGxlLCB0aGUgcmVwb3J0IGluZGljYXRlcyB0aGF0IGFtb25nIG1lbiwgNDIuMyUgYXJlIHNhdGlzZmllZCB3aXRoIGRlbW9jcmFjeSAodXNpbmcgdGhlIHZhcmlhYmxlIHJlY29kZWQgYXMgYSBkdW1teSksIHdoaWxlIGFtb25nIHdvbWVuLCB0aGlzIHBlcmNlbnRhZ2UgZHJvcHMgdG8gMzYuOSUuCkhlcmUgd2UgYXJlIGdvaW5nIHRvIGFuYWx5emUgdGhlc2Ugc2FtZSB2YXJpYWJsZXMsIGJ1dCB1c2luZyB0aGUgdmFyaWFibGUgInBuNCIgaW4gaXRzIG9yaWdpbmFsIGZvcm0gKGFzIGFuIG9yZGluYWwgY2F0ZWdvcmljYWwpLgpCZWZvcmUgcHJvY2VlZGluZywgd2UgbmVlZCB0byByZWNvZGUgdGhlIHZhcmlhYmxlcyBhcyBmYWN0b3IgYW5kIGxhYmVsIHRoZW0uCgpgYGB7ciBnZW5kZXJ9CmxhcG9wMTgkZ2VuZGVyID0gYXMuZmFjdG9yKGxhcG9wMTgkcTEpCmxldmVscyhsYXBvcDE4JGdlbmRlcikgPSBjKCJNYWxlIiwgIkZlbWFsZSIpCnRhYmxlKGxhcG9wMTgkZ2VuZGVyKQpgYGAKClRoZSBzYW1lIGlzIGRvbmUgZm9yIHRoZSB2YXJpYWJsZSAicG40IiB3aGljaCBiZWNvbWVzIGEgbmV3IHZhcmlhYmxlICJzYXRpcyIuCgpgYGB7ciBzYXRpc30KbGFwb3AxOCRzYXRpcyA9IGFzLmZhY3RvcihsYXBvcDE4JHBuNCkKbGV2ZWxzKGxhcG9wMTgkc2F0aXMpID0gYygiVmVyeSBzYXRpc2ZpZWQiLCAiU2F0aXNmaWVkIiwgIkRpc3NhdGlzZmllZCIsICJWZXJ5IGRpc3NhdGlzZmllZCIpCnRhYmxlKGxhcG9wMTgkc2F0aXMpCmBgYAoKIyBDcm9zcy10YWJsZSBvZiBzYXRpc2ZhY3Rpb24gd2l0aCBkZW1vY3JhY3kgYnkgZ2VuZGVyCgpXaXRoIHRoZSBuZXcgZmFjdG9yIHZhcmlhYmxlcywgd2UgZmlyc3QgY2FsY3VsYXRlIGEgY3Jvc3MtdGFibGUgb3IgY29udGluZ2VuY3kgdGFibGUuClRoZSBjb21tYW5kIGB0YWJsZWAgaXMgdXNlZCB0byBwcmVzZW50IHRoZSBmcmVxdWVuY2llcyBvZiBvbmUgb3IgdHdvIHZhcmlhYmxlcy4KQnkgY29udmVudGlvbiwgdGhlIGRlcGVuZGVudCB2YXJpYWJsZSAic2F0aXNmYWN0aW9uIHdpdGggZGVtb2NyYWN5IiBpcyBwbGFjZWQgaW4gdGhlIHJvd3MgYW5kIHRoZSBpbmRlcGVuZGVudCB2YXJpYWJsZSAiZ2VuZGVyIiBpbiB0aGUgY29sdW1ucy4KCmBgYHtyIHRhYmxlfQp0YWJsZShsYXBvcDE4JHNhdGlzLCBsYXBvcDE4JGdlbmRlcikKYGBgCgpUbyBjYWxjdWxhdGUgdGhlIHJlbGF0aXZlIGZyZXF1ZW5jaWVzLCB5b3UgaGF2ZSB0byBuZXN0IHRoZSBjb21tYW5kIGB0YWJsZWAgaW5zaWRlIHRoZSBjb21tYW5kIGBwcm9wLnRhYmxlYC4KSWYgbmVzdGVkIG9ubHksIHRoaXMgY29tbWFuZCBjYWxjdWxhdGVzIHRoZSBwcm9wb3J0aW9ucyBvdmVyIHRoZSB0b3RhbCBvYnNlcnZhdGlvbnMuCgpgYGB7ciB0YWJsZTJ9CnByb3AudGFibGUodGFibGUobGFwb3AxOCRzYXRpcywgbGFwb3AxOCRnZW5kZXIpKQpgYGAKClRoZXNlIHByb3BvcnRpb25zIGFyZSBub3QgdmVyeSB1c2VmdWwgZm9yIHRoZSBjb21wYXJpc29uIHdlIHdhbnQgdG8gbWFrZS4KV2hhdCB3ZSByZXF1aXJlIGFyZSB0aGUgY29uZGl0aW9uYWwgZGlzdHJpYnV0aW9ucyBvZiAic2F0aXNmYWN0aW9uIHdpdGggZGVtb2NyYWN5IiBmb3IgZWFjaCBnZW5kZXIgZ3JvdXAuClRoYXQgaXMsIGNhbGN1bGF0ZSB0aGUgcGVyY2VudGFnZXMgZm9yIGVhY2ggY29sdW1uLgpJbiBvcmRlciBmb3IgYHByb3AudGFibGVgIHRvIGNhbGN1bGF0ZSB0aGVzZSBwZXJjZW50YWdlcywgd2UgaGF2ZSB0byBhZGQgdGhlIHNwZWNpZmljYXRpb24gYCjigKYsIDIpYC4KTXVsdGlwbHkgYnkgMTAwIHRvIGdvIGZyb20gcmF0aW9zIHRvIHBlcmNlbnRhZ2VzLgpZb3UgY2FuIGFsc28gbmVzdCBhbGwgY29kZSBpbnNpZGUgdGhlIGNvbW1hbmQgYGFkZG1hcmdpbnNgIHRvIGNoZWNrIHRoZSBzdW0gb2YgcGVyY2VudGFnZXMgb3ZlciB0aGUgY29sdW1ucywgd2l0aCB0aGUgc3BlY2lmaWNhdGlvbiBgKC4uLiwgMSlgLgoKYGBge3IgdGFibGVzM30KYWRkbWFyZ2lucyhwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMTgkc2F0aXMsIGxhcG9wMTgkZ2VuZGVyKSwgMikqMTAwLCAxKQpgYGAKClRoZSB0YWJsZSBzaG93cyB0aGF0IDYuOCUgb2YgbWVuIGFyZSB2ZXJ5IHNhdGlzZmllZCB3aXRoIGRlbW9jcmFjeSwgYSBwZXJjZW50YWdlIHZlcnkgc2ltaWxhciB0byB0aGF0IG9mIHdvbWVuLgo0NCUgb2YgbWVuIGFyZSBkaXNzYXRpc2ZpZWQgd2l0aCBkZW1vY3JhY3kuCkluIHRoaXMgY2F0ZWdvcnksIHdvbWVuIGhhdmUgYSBoaWdoZXIgcGVyY2VudGFnZSAoNDguNCUpLgoKSW4gdGhpcyB3YXksIGl0IGlzIHBvc3NpYmxlIHRvIGNvbXBhcmUgdGhlIHBlcmNlbnRhZ2VzIG9mIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgInNhdGlzZmFjdGlvbiB3aXRoIGRlbW9jcmFjeSIgZm9yIGVhY2ggY2F0ZWdvcnkgb2YgdGhlIGluZGVwZW5kZW50IHZhcmlhYmxlICJnZW5kZXIiLgoKIyBHcmFwaHMgb2Ygc2F0aXNmYWN0aW9uIHdpdGggZGVtb2NyYWN5IGJ5IGdlbmRlcgoKSW4gdGhlIHNlY3Rpb24gYWJvdXQgW2Rlc2NyaXB0aXZlcyBvZiBvcmRpbmFsIHZhcmlhYmxlc10oaHR0cHM6Ly9hcnR1cm9tYWxkb25hZG8uZ2l0aHViLmlvL0Jhcm9tZXRyb0VkdV9XZWJfRW5nL0Rlc2NyaXB0aXZlczIuaHRtbCksIHdlIHByZXNlbnRlZCBhIHByZXZpZXcgb2Ygd2hhdCB3ZSBhcmUgc2VlaW5nIGluIHRoaXMgc2VjdGlvbi4KSGVyZSB3ZSB3aWxsIHJldmlzaXQgdGhvc2UgdGhlbWVzLCB1c2luZyB0aGUgdGlkeXZlcnNlLgoKVG8gbWFrZSB0aGUgZ3JhcGgsIHdlIGZpcnN0IGNyZWF0ZSBhIG5ldyBkYXRhZnJhbWUgd2l0aCB0aGUgZGF0YSBmcm9tIHRoZSBjcm9zcy10YWJsZS4KVGhlIGNvbW1hbmQgYGFzLmRhdGEuZnJhbWVgIGlzIHVzZWQgdG8gdHJhbnNmb3JtIHRoZSBiaXZhcmlhdGUgdGFibGUgaW50byBhIG5ldyBkYXRhZnJhbWUgY2FsbGVkICJ0YWJsZSIuClVzaW5nIHRoaXMgY29tbWFuZCwgdGhlIHJlc3VsdHMgYXJlIHNvcnRlZCBieSBuZXcgY29sdW1ucyAoVmFyMSwgVmFyMiBhbmQgRnJlcSkgc28gdGhhdCB0aGV5IGNhbiBiZSB1c2VkIHRvIGNyZWF0ZSBhIGdyYXBoLgoKYGBge3IgdGFibGU0fQp0YWJsZSA9IGFzLmRhdGEuZnJhbWUocHJvcC50YWJsZSh0YWJsZShsYXBvcDE4JHNhdGlzLCBsYXBvcDE4JGdlbmRlciksIDIpKjEwMCkKdGFibGUKYGBgCgpXZSB3aWxsIHVzZSB0aGUgbGlicmFyeSBgZ2dwbG90MmAgYW5kIHRoZSBjb21tYW5kIGBnZ3Bsb3RgIHRvIGNyZWF0ZSBhIGJhciBjaGFydCwgdXNpbmcgdGhlIGRhdGFmcmFtZSAidGFibGUiIGNvbnRhaW5pbmcgdGhlIHBlcmNlbnRhZ2VzIG9mIHNhdGlzZmFjdGlvbiB3aXRoIGRlbW9jcmFjeSBmb3IgbWVuIGFuZCB3b21lbi4KVGhpcyBjb21tYW5kIHJlcXVpcmVzIGFuIGFlc3RoZXRpYyB3aGVyZSBpdCBpcyBzcGVjaWZpZWQgdGhhdCAiVmFyMSIgd2lsbCBiZSBpbmNsdWRlZCBvbiB0aGUgWCBheGlzLCB3aGljaCBjb3JyZXNwb25kcyB0byB0aGUgY2F0ZWdvcmllcyBvZiBzYXRpc2ZhY3Rpb24gd2l0aCBkZW1vY3JhY3kuClRoZSAiRnJlcSIgaXMgaW5jbHVkZWQgb24gdGhlIFkgYXhpcywgd2hpY2ggY29ycmVzcG9uZHMgdG8gcGVyY2VudGFnZXMuCkFsc28gaW5jbHVkZWQgaXMgdGhlIHNwZWNpZmljYXRpb24gYGZpbGxgIHRvIGluZGljYXRlIHRoYXQgaXQgd2lsbCBiZSBzcGxpdCBpbnRvIE1hbGUvRmVtYWxlIGdyb3VwcyBmb3IgZWFjaCBjYXRlZ29yeSBvZiAiVmFyMSIgYW5kIGB5bWF4YCB0byBzcGVjaWZ5IHRoZSB1cHBlciBsaW1pdCBvZiB0aGUgWSBheGlzLgoKQWZ0ZXIgZGVmaW5pbmcgdGhlIHZhcmlhYmxlcyBpbiB0aGUgYXhlcywgaXQgaXMgaW5kaWNhdGVkIHRoYXQgYSBiYXIgZ3JhcGggaXMgd2FudGVkIHdpdGggdGhlIGNvbW1hbmQgYGdlb21fYmFyYCBhbmQgd2l0aCB0aGUgc3BlY2lmaWNhdGlvbiBgcG9zaXRpb249ImRvZGdlImAgaXQgaXMgaW5kaWNhdGVkIHRoYXQgYSBncmFwaCB3aXRoIGJhcnMgc2VwYXJhdGVkIGJ5IGVhY2ggY29tYmluYXRpb24gb2YgY2F0ZWdvcmllcyBpcyB3YW50ZWQuClRoZSBzcGVjaWZpY2F0aW9uIGBzdGF0PSJpZGVudGl0eSJgIGlzIGFkZGVkIHRvIGluZGljYXRlIHRoYXQgdGhlIGNvbW1hbmQgd29ya3Mgd2l0aCB0aGUgZGF0YSBpbiB0aGUgdGFibGUuCgpUaGUgY29tbWFuZCBgZ2VvbV90ZXh0YCBpbmNsdWRlcyB0aGUgcGVyY2VudGFnZXMgb2YgZWFjaCBiYXIsIHdoaWNoIGlzIGZvdW5kIGluIHRoZSAiRnJlcSIgY29sdW1uLgpUaGVzZSBwZXJjZW50YWdlcyBhcmUgcm91bmRlZCB3aXRoIGByb3VuZGAgdG8gMSBkZWNpbWFsIHBsYWNlIGFuZCB0aGUgIiUiIHN5bWJvbCBpcyBhZGRlZCB3aXRoIGBwYXN0ZWAuCkFsc28gaW5jbHVkZWQgaXMgdGhlIHNwZWNpZmljYXRpb24gYHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKC4uLilgIHdoaWNoIHBsYWNlcyB0aGVzZSBwZXJjZW50YWdlcyBhdCB0aGUgdG9wIG9mIGVhY2ggY29sdW1uLgpUaGUgZGVmYXVsdCBvcHRpb24gd2l0aGluIHRoaXMgc3BlY2lmaWNhdGlvbiBpcyBgd2lkdGg9TlVMTGAsIGJ1dCB0aGlzIHdheSB0aGUgcGVyY2VudGFnZXMgd291bGQgYmUgbWlzcGxhY2VkLCBzbyBgd2lkdGg9MC45YCBpcyBkZWZpbmVkIHRvIGNlbnRlciB0aGUgcGVyY2VudGFnZXMuCgpCeSBkZWZhdWx0LCB0aGUgbGVnZW5kIGluY2x1ZGVzIHRoZSBuYW1lIG9mIHRoZSBjb2x1bW4gd2l0aCB0aGUgZ2VuZGVyIGRhdGEsIHdoaWNoIGlzICJWYXIyIi4KVG8gY2hhbmdlIHRoaXMgbmFtZSwgdXNlIHRoZSBjb21tYW5kIGBsYWJzKGZpbGw9IkdlbmRlciIpYCB0byBwcm9wZXJseSBuYW1lIHRoZSBsZWdlbmQuCkZpbmFsbHksIHRoZSBZIGFuZCBYIGF4aXMgYXJlIGxhYmVsZWQgd2l0aCBgeWxhYmAgYW5kIGB4bGFiLmAKCmBgYHtyIGdyYWZiYXJ9CmxpYnJhcnkoZ2dwbG90MikKZ2dwbG90KGRhdGE9dGFibGUsIGFlcyh4PVZhcjEsIHk9RnJlcSwgZmlsbD1WYXIyLCB5bWF4PTYwKSkrCiAgZ2VvbV9iYXIocG9zaXRpb249ImRvZGdlIiwgc3RhdD0iaWRlbnRpdHkiKSsKICBnZW9tX3RleHQoYWVzKGxhYmVsPXBhc3RlKHJvdW5kKEZyZXEsIDEpLCAiJSIsIHNlcD0iIikpLAogICAgICAgICAgICBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjkpLCB2anVzdD0tMC4yNSkrCiAgbGFicyhmaWxsPSJHZW5kZXIiKSsKICB5bGFiKCJQZXJjZW50YWdlIikrCiAgeGxhYigiU2F0aXNmYWN0aW9uIHdpdGggZGVtb2NyYWN5IikKYGBgCgpPdGhlciB3YXkgdG8gZGlzcGxheSB0aGlzIGRhdGEgaXMgdGhyb3VnaCBzdGFja2VkIGJhcnMuClRoYXQgaXMsIGZvciBlYWNoIGdlbmRlciBjYXRlZ29yeSwgdGhlIGRpc3RyaWJ1dGlvbiBvZiBzYXRpc2ZhY3Rpb24gd2l0aCBkZW1vY3JhY3kgaXMgc2hvd24uCkZvciB0aGlzLCB3ZSB1c2UgdGhlIHNhbWUgY29tbWFuZCBgZ2dwbG90YCBidXQgbm93IHRoZSBvcmRlciBvZiB0aGUgdmFyaWFibGVzIGluIHRoZSBhZXN0aGV0aWMgaXMgY2hhbmdlZC4KTm93IHRoZSB2YXJpYWJsZSAiVmFyMiIgKHdpdGggdGhlIGdlbmRlciBjYXRlZ29yaWVzKSBpcyBsb2NhdGVkIG9uIHRoZSBYIGF4aXMgYW5kIGVhY2ggYmFyIGlzIGRpdmlkZWQgYWNjb3JkaW5nIHRvIHRoZSB2YWx1ZXMgb2YgVmFyMS4KClRoZSBiYXIgdHlwZSBjaGFuZ2VzIGluIHRoZSBjb21tYW5kIGBnZW9tX2JhcmAgdG8gYHBvc2l0aW9uPSJzdGFjayJgLgpJbiB0aGUgc2FtZSB3YXksIHRoZSBkYXRhIGxhYmVscyBoYXZlIHRvIGNvbnNpZGVyIHRoZSBwb3NpdGlvbiBvZiBlYWNoIHNsaWNlLCB3aXRoIGBwb3NpdGlvbj1wb3NpdGlvbl9zdGFjaygpYC4KCmBgYHtyIGdyYWZiYXJhcGlsYX0KZ2dwbG90KGRhdGE9dGFibGUsIGFlcyh4PVZhcjIsIHk9RnJlcSwgZmlsbD1WYXIxLCB5bWF4PTEwMCkpKwogIGdlb21fYmFyKHBvc2l0aW9uPSJzdGFjayIsIHN0YXQ9ImlkZW50aXR5IikrCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1wYXN0ZShyb3VuZChGcmVxLCAxKSwgIiUiLCBzZXA9IiIpKSwKICAgICAgICAgICAgcG9zaXRpb249cG9zaXRpb25fc3RhY2soKSwgdmp1c3Q9MikrCiAgbGFicyhmaWxsPSJTYXRpc2ZhY3Rpb24gd2l0aCBkZW1vY3JhY3kiKSsKICB5bGFiKCJQZXJjZW50YWdlIikrCiAgeGxhYigiR2VuZGVyIikKYGBgCgojIENyb3NzLXRhYmxlIG9mIHNhdGlzZmFjdGlvbiB3aXRoIGRlbW9jcmFjeSBieSBlZHVjYXRpb25hbCBsZXZlbAoKRmlndXJlIDEuMTQgb2YgdGhlIHJlcG9ydCBzaG93cyB0aGUgcmVzdWx0cyBvbiBzYXRpc2ZhY3Rpb24gd2l0aCBkZW1vY3JhY3kgKGFjY29yZGluZyB0byB0aGUgcmVjb2RlZCBkdW1teSB2YXJpYWJsZSkgYnkgZWR1Y2F0aW9uYWwgbGV2ZWwuCkFzIGEgc2Vjb25kIGV4YW1wbGUsIGhlcmUgd2UgYXJlIGdvaW5nIHRvIHJlcGxpY2F0ZSB0aGF0IHJlbGF0aW9uc2hpcCB1c2luZyB0aGUgb3JpZ2luYWwgdmFyaWFibGUgb2YgdHlwZSBmYWN0b3IuCgpXZSBmaXJzdCByZWNvZGUgdGhlIGVkdWNhdGlvbiB2YXJpYWJsZS4KVGhlIG9yaWdpbmFsIHZhcmlhYmxlICJlZCIgaXMgYSBudW1lcmljYWwgdmFyaWFibGUgKHllYXJzIG9mIHN0dWR5KS4KVGhpcyB2YXJpYWJsZSBoYXMgdmFsdWVzIHJhbmdpbmcgZnJvbSAwIHRvIDE4LgpJdCBpcyByZWNvZGVkIGluIHN1Y2ggYSB3YXkgdGhhdCB0aG9zZSB3aXRoIHplcm8geWVhcnMgb2YgZWR1Y2F0aW9uIGFyZSBhc3NpZ25lZCBhIHZhbHVlIG9mIDAgIk5vbmUiLCB0aG9zZSBiZXR3ZWVuIDEgYW5kIDYgeWVhcnMgb2YgZWR1Y2F0aW9uIGFyZSBhc3NpZ25lZCBhIHZhbHVlIG9mIDEgIlByaW1hcnkiLCB0aG9zZSBiZXR3ZWVuIDcgYW5kIDExIHllYXJzIG9mIGVkdWNhdGlvbiBhcmUgYXNzaWducyB0aGVtIHRoZSB2YWx1ZSBvZiAyICJTZWNvbmRhcnkiIGFuZCBiZXR3ZWVuIDEyIGFuZCAxOCB5ZWFycyBvZiBlZHVjYXRpb24gdGhlIHZhbHVlIG9mIDMgIlBvc3Qtc2Vjb25kYXJ5Ii4KCmBgYHtyIHJlY29lZH0KbGlicmFyeShjYXIpCmxhcG9wMTgkZWR1YyA8LSBjYXI6OnJlY29kZShsYXBvcDE4JGVkLCAiMD0wOyAxOjY9MTsgNzoxMT0yOyAxMjoxOD0zIikKbGFwb3AxOCRlZHVjIDwtIGFzLmZhY3RvcihsYXBvcDE4JGVkdWMpCmxldmVscyhsYXBvcDE4JGVkdWMpIDwtIGMoIk5vbmUiLCAiUHJpbWFyeSIsICJTZWNvbmRhcnkiLCAiUG9zdC1zZWNvbmRhcnkiKQp0YWJsZShsYXBvcDE4JGVkdWMpCmBgYAoKV2l0aCB0aGUgcmVjb2RlZCB2YXJpYWJsZSBpdCBpcyBwb3NzaWJsZSB0byBjYWxjdWxhdGUgdGhlIGNyb3NzLXRhYmxlIG9mIHNhdGlzZmFjdGlvbiB3aXRoIGRlbW9jcmFjeSBieSBlZHVjYXRpb25hbCBsZXZlbHMuCgpgYGB7ciB0YWJsZWVkfQphZGRtYXJnaW5zKHByb3AudGFibGUodGFibGUobGFwb3AxOCRzYXRpcywgbGFwb3AxOCRlZHVjKSwgMikqMTAwLCAxKQpgYGAKClRvIGNyZWF0ZSB0aGUgZ3JhcGgsIHdlIGhhdmUgdG8gc2F2ZSB0aGUgdGFibGUgYXMgYSBkYXRhZnJhbWUuClRoZSBjb21tYW5kIGBhcy5kYXRhLmZyYW1lYCBpcyB1c2VkIHRvIHNhdmUgdGhlIHBlcmNlbnRhZ2VzIHNvIHRoYXQgdGhleSBjYW4gYmUgdXNlZCB3aXRoIHRoZSBjb21tYW5kIGBnZ3Bsb3RgLgoKYGBge3IgdGFibGU1fQp0YWJsZTIgPC0gYXMuZGF0YS5mcmFtZShwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMTgkc2F0aXMsIGxhcG9wMTgkZWR1YyksIDIpKjEwMCkKdGFibGUyCmBgYAoKSW4gdGhpcyBjYXNlLCBzaW5jZSB3ZSBoYXZlIDQgY2F0ZWdvcmllcyBmb3Igc2F0aXNmYWN0aW9uIHdpdGggZGVtb2NyYWN5IGFuZCBhbm90aGVyIDQgY2F0ZWdvcmllcyBmb3IgZWR1Y2F0aW9uYWwgbGV2ZWxzLCBhIGJhciBncmFwaCB3b3VsZCBjcmVhdGUgMTYgYmFycywgd2hpY2ggd291bGQgY29tcGxpY2F0ZSB0aGUgY29tcGFyaXNvbi4KU28sIGluIHRoaXMgY2FzZSwgdGhlIHN0YWNrZWQgYmFyIHR5cGUgaXMgcHJlZmVycmVkLgoKYGBge3IgYmFycmFwaWxhZGFzZWR9CmxpYnJhcnkoZ2dwbG90MikKZ2dwbG90KGRhdGE9dGFibGUyLCBhZXMoeD1WYXIyLCB5PUZyZXEsIGZpbGw9VmFyMSwgeW1heD0xMDApKSsKICBnZW9tX2Jhcihwb3NpdGlvbj0ic3RhY2siLCBzdGF0PSJpZGVudGl0eSIpKwogIGdlb21fdGV4dChhZXMobGFiZWw9cGFzdGUocm91bmQoRnJlcSwgMSksICIlIiwgc2VwPSIiKSksCiAgICAgICAgICAgIHBvc2l0aW9uPXBvc2l0aW9uX3N0YWNrKCksIHZqdXN0PTIpKwogIGxhYnMoZmlsbD0iU2F0aXNmYWN0aW9uIHdpdGggZGVtb2NyYWN5IikrCiAgeWxhYigiUGVyY2VudGFnZSIpKwogIHhsYWIoIkVkdWNhdGlvbiBsZXZlbCIpCmBgYAoKRmlndXJlIDEuMTQgc2hvd3MgdGhhdCB0aGVyZSBpcyBhIGhpZ2hlciBwZXJjZW50YWdlIG9mIHNhdGlzZmFjdGlvbiB3aXRoIGRlbW9jcmFjeSBhbW9uZyB0aGUgbGVhc3QgZWR1Y2F0ZWQuClRoaXMgcmVsYXRpb25zaGlwIGNhbiBhbHNvIGJlIHNlZW4gaW4gdGhpcyBncmFwaC4KVGhlIHNlY3RvcnMgInZlcnkgc2F0aXNmaWVkIiAoaW4gcGluaykgYW5kICJzYXRpc2ZpZWQiIChpbiBncmVlbikgZGVjcmVhc2UgYXMgd2UgZ28gZnJvbSBub25lIHRvIHByaW1hcnksIHNlY29uZGFyeSBhbmQgaGlnaGVyLgoKSW4gYWxsIGV4YW1wbGVzLCB3ZSBjYW4gb2JzZXJ2ZSBwZXJjZW50IGRpZmZlcmVuY2VzIGluIGEgdmFyaWFibGUgYnkgY2F0ZWdvcmllcyBvZiBvdGhlciB2YXJpYWJsZS4KVGhlc2UgcGVyY2VudGFnZXMgY2FuIGJlIGNvbXBhcmVkIGRpcmVjdGx5IGluIHRoZSBncmFwaCwgYnV0IHdlIHNob3VsZCBydW4gYSBzaWduaWZpY2FuY2UgdGVzdCB0byBldmFsdWF0ZSBpZiB0aGVyZSBpcyBhIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgcmVsYXRpb25zaGlwLgoKIyBDaGktc3F1YXJlIHRlc3Qgb2YgaW5kZXBlbmRlbmNlCgpUd28gY2F0ZWdvcmljYWwgdmFyaWFibGVzIGFyZSBzYWlkIHRvIGJlIHN0YXRpc3RpY2FsbHkgaW5kZXBlbmRlbnQgaWYgdGhlIGNvbmRpdGlvbmFsIChwb3B1bGF0aW9uKSBkaXN0cmlidXRpb25zIGFyZSBpZGVudGljYWwgZm9yIGVhY2ggY2F0ZWdvcnkgb2YgdGhlIGluZGVwZW5kZW50IHZhcmlhYmxlLgpJbiB0aGUgYWJvdmUgYml2YXJpYXRlIHJlbGF0aW9uc2hpcCwgdGhpcyBtZWFucyB0aGF0IGJlaW5nIG1hbGUgb3IgZmVtYWxlIGRvZXMgbm90IGNoYW5nZSBvcGluaW9ucyByZWdhcmRpbmcgc2F0aXNmYWN0aW9uIHdpdGggZGVtb2NyYWN5LgpBcyB0aGVzZSBjb25kaXRpb25hbCBkaXN0cmlidXRpb25zIGRpZmZlciBtb3JlIGZyb20gZWFjaCBvdGhlciwgYm90aCB2YXJpYWJsZXMgYXJlIHNhaWQgdG8gYmUgbW9yZSByZWxhdGVkIG9yIG1vcmUgZGVwZW5kZW50LgoKVGhpcyBldmFsdWF0aW9uIGlzIGRvbmUgdXNpbmcgdGhlIGNoaS1zcXVhcmUgb3IgJFxjaGleMiQgdGVzdCBvZiBpbmRlcGVuZGVuY2UuClRoaXMgdGVzdCBpcyBiYXNlZCBvbiB0aGUgY29tcGFyaXNvbiBvZiB0aGUgb2JzZXJ2ZWQgZnJlcXVlbmNpZXMgKHRoZSBvYnNlcnZhdGlvbnMgY29sbGVjdGVkIGluIHRoZSBmaWVsZCkgdmVyc3VzIHRoZSBleHBlY3RlZCBmcmVxdWVuY2llcyAodGhlIG9ic2VydmF0aW9ucyB0aGF0IHNob3VsZCBiZSBpbiBlYWNoIGNlbGwgaWYgdGhlIHZhcmlhYmxlcyB3ZXJlIGluZGVwZW5kZW50KS4KVGhlIHRlc3Qgc3RhdGlzdGljIHN1bW1hcml6ZXMgaG93IGNsb3NlIHRoZSBleHBlY3RlZCBmcmVxdWVuY2llcyBhcmUgdG8gdGhlIG9ic2VydmVkIGZyZXF1ZW5jaWVzLgoKJCQKXGNoaV4yID0gXHN1bVxmcmFjeyhmX28tZl9lKV4yfXtmX2V9CiQkCgpUaGUgc21hbGxlciB0aGUgZGlzdGFuY2UgaW4gZWFjaCBjZWxsLCB0aGUgbGVzcyBsaWtlbHkgaXQgaXMgdG8gcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMuClRoZSBsYXJnZXIgdGhlIGRpc3RhbmNlIGluIGVhY2ggY2VsbCwgdGhlIG1vcmUgbGlrZWx5IGl0IGlzIHRvIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzLgoKJCQKSDA6IGZfbyA9IGZfZQokJAoKV2l0aCB0aGUgdmFsdWUgb2YgJFxjaGleMiQgYW5kIHdpdGggdGhlIGRlZ3JlZXMgb2YgZnJlZWRvbSAocm93cy0xXCpjb2x1bW5zLTEpLCBhIHAtdmFsdWUgaXMgY2FsY3VsYXRlZCBvbiB0aGUgY2hpLXNxdWFyZSBkaXN0cmlidXRpb24uCklmIHRoaXMgcC12YWx1ZSBpcyBsZXNzIHRoYW4gMC4wNSwgSDAgaXMgcmVqZWN0ZWQuClRoaXMgdGVzdCByZXF1aXJlcyB0aGF0IHRoZXJlIGJlIGF0IGxlYXN0IDUgb2JzZXJ2YXRpb25zIGluIGVhY2ggY2VsbC4KCiMgVGVzdCBvZiB2b3RlcyBhcmUgY291bnRlZCBmYWlybHkgYnkgY291bnRyeQoKSW4gUiwgdGhlIGNvbW1hbmQgYGNoaXNxLnRlc3RgIGlzIHVzZWQgdG8gY2FsY3VsYXRlIHRoZSBzdGF0aXN0aWMgYW5kIHRoZSBhc3NvY2lhdGVkIHAtdmFsdWUuClRoZSByZXN1bHRzIG9mIHRoaXMgdGVzdCBjYW4gYmUgc2F2ZWQgdG8gYSBuZXcgb2JqZWN0ICJjaGl0ZXN0MSIuCgpgYGB7cn0KY2hpdGVzdDEgPC0gY2hpc3EudGVzdChsYXBvcDIxJGNvdW50ZmFpcjFyLCBsYXBvcDIxJHBhaXMpCmNoaXRlc3QxCmBgYAoKVGhlIHAtdmFsdWUgb2J0YWluZWQgaXMgbGVzcyB0aGFuIDAuMDUsIHNvIHRoZSBIMCBpcyByZWplY3RlZCwgc28gd2Ugc2F5IHRoYXQgdGhlIG9ic2VydmVkIGZyZXF1ZW5jaWVzIHNlZW0gdG8gYmUgZGlmZmVyZW50IGZyb20gdGhlIGV4cGVjdGVkIGZyZXF1ZW5jaWVzIHRoYXQgd291bGQgZXhpc3QgaW4gZWFjaCBjZWxsIGlmIHRoZXJlIHdlcmUgbm8gcmVsYXRpb25zaGlwLCBzbyB3ZSBzYXkgdGhhdCB0aGVyZSBpcyBhIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSB2YXJpYWJsZXMgb3IgdGhhdCB0aGVyZSBpcyBhIGRlcGVuZGVuY3kgYmV0d2VlbiB0aGUgdHdvLgoKSXQgaXMgaW1wb3J0YW50IHRvIG5vdGUgdGhhdCAiY2hpdGVzdDEiIGlzIGFuIG9iamVjdCBvZiB0eXBlICpsaXN0Ki4KVGhpcyB0eXBlIG9mIG9iamVjdCBjYW4gc3RvcmUgb3RoZXIgaW5mb3JtYXRpb24gb2YgYSBkaWZmZXJlbnQgdHlwZS4KRm9yIGV4YW1wbGUsICJjaGl0ZXN0MSIgc2F2ZXMgdGhlIHRhYmxlcyBvZiBvYnNlcnZlZCBmcmVxdWVuY2llcyAoc2FtZSByZXN1bHQgYXMgd2l0aCB0aGUgY29tbWFuZCBgdGFibGVgKSBhbmQgdGhlIHRhYmxlIG9mIGV4cGVjdGVkIGZyZXF1ZW5jaWVzLgpJbiB0aGlzIG9iamVjdCB0aGUgdmFsdWUgb2YgdGhlIHJlc2lkdWFscywgdGhlIHN0YW5kYXJkaXplZCByZXNpZHVhbHMgYW5kIHRoZSB2YWx1ZSBvZiB0aGUgcC12YWx1ZSBhcmUgYWxzbyBzYXZlZC4KCmBgYHtyfQpjaGl0ZXN0MSRvYnNlcnZlZApjaGl0ZXN0MSRleHBlY3RlZApgYGAKClRvIGV2YWx1YXRlIHRoZSBzdHJlbmd0aCBvZiB0aGUgcmVsYXRpb25zaGlwLCB3ZSB1c2UgdGhlIGxpYnJlcnkgYHZjZGAgdGhhdCBoYXMgdGhlIGNvbW1hbmQgYGFzc29jc3RhdHNgIHRoYXQgb2ZmZXJzIGEgc2VyaWVzIG9mIG1lYXN1cmVzIG9mIGFzc29jaWF0aW9uIGZvciBhIGNyb3NzLXRhYmxlIGJldHdlZW4gYW4gb3JkaW5hbCB2YXJpYWJsZSwgYXMgImNvdW50ZmFpcjEiLCBhbmQgYSBub21pbmFsIHZhcmlhYmxlLCBhcyAicGFpcyIuCgpUaGUgY29tbWFuZCBgYXNzb2NzdGF0c2AgY2Fubm90IGNhbGN1bGF0ZSBtZWFzdXJlcyBvZiBhc3NvY2lhdGlvbnMgaWYgY2VsbHMgb2YgYSBjcm9zcy10YWJsZSBoYXZlIG51bGwgdmFsdWVzLgpCZWNhdXNlIHdlIGhhdmUgc29tZSBjb3VudHJpZXMgd2hlcmUgcXVlc3Rpb24gImNvdW50ZmFpcjEiIHdhcyBub3QgYXNrZWQsIHdlIGhhdmUgdG8gaW5kaWNhdGUgdGhhdCB0aGlzIGNvbW1hbmQgZG9lcyBub3QgdGFrZSBpbnRvIGFjY291bnQgdGhlc2UgY291bnRyaWVzLgpGb3IgZGVhbCB3aXRoIHRoaXMsIHdlIGNyZWF0ZSBhIG5ldyAiY291bnRyeTIiIHZhcmlhYmxlLCB3aGVyZSBvYnNlcnZhdGlvbnMgb2YgdGhlc2UgY291bnRyaWVzIGFyZSBzZXQgYXMgTkFzLgoKYGBge3J9CmxhcG9wMjEkY291bnRyeV9yID0gbGFwb3AyMSRwYWlzCmxhcG9wMjEkY291bnRyeV9yW2xhcG9wMjEkcGFpcz09MV0gPSBOQQpsYXBvcDIxJGNvdW50cnlfcltsYXBvcDIxJHBhaXM9PTJdID0gTkEKbGFwb3AyMSRjb3VudHJ5X3JbbGFwb3AyMSRwYWlzPT0zXSA9IE5BCmxhcG9wMjEkY291bnRyeV9yW2xhcG9wMjEkcGFpcz09NF0gPSBOQQpsYXBvcDIxJGNvdW50cnlfcltsYXBvcDIxJHBhaXM9PTIyXSA9IE5BCmBgYAoKV2l0aCB0aGlzIG5ldyB2YXJpYWJsZSwgd2UgY2FuIGNyZWF0ZSBhIGNyb3NzLXRhYmxlIGJldHdlZW4gImNvdW50ZmFpcjEiIGFuZCAiY291bnRyeV9yIiBhbmQgY2FsY3VsYXRlIG1lYXN1cmVzIG9mIGFzc29jaWF0aW9uLgoKYGBge3J9CmxpYnJhcnkodmNkKQp0YWJsZTIgPC0gdGFibGUobGFwb3AyMSRjb3VudGZhaXIxciwgbGFwb3AyMSRjb3VudHJ5X3IpCmFzc29jc3RhdHModGFibGUyKQpgYGAKClRoZSBjb21tYW5kIGBhc3NvY3N0YXRzYCByZXR1cm5zIHRoZSBjb250aW5nZW5jeSBjb2VmZmljaWVudCBhbmQgQ3JhbWVywrRzIFYgYXMgbWVhc3VyZXMuClRoZXNlIG1lYXN1cmVzIHZhcnkgYmV0d2VlbiAwIGFuZCAxLgpXaGlsZSBjbG9zZXIgdG8gemVybywgdGhlIHJlbGF0aW9uc2hpcCBpcyB3ZWFrZXIuCk9uIHRoZSBjb250cmFyeSwgd2hpbGUgY2xvc2VyIHRvIDEsIHRoZSByZWxhdGlvbnNoaXAgaXMgc3Ryb25nZXIuCgpCeSBjb252ZW50aW9uLCB3ZSBjYW4gYXNzdW1lIHRoYXQgd2VhayByZWxhdGlvbnNoaXBzIGFyZSBiZXR3ZWVuIDAgYW5kIDAuMywgbW9kZXJhdGUgcmVsYXRpb25zaGlwcyBiZXR3ZW4gMC4zIGFuZCAwLjYgYW5kIHN0cm9uZyByZWxhdGlvbnNoaXBzIGFyZSBoaWdoZXIgdGhhbiAwLjYuCkluIHRoaXMgY2FzZSwgd2UgY2FuIGluZGljYXRlIHRoYXQgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHZvdGVzIGFyZSBjb3VudGVkIGZhaXJseSBhbmQgY291bnRyeSBpcyB3ZWFrLgoKIyBUZXN0IG9mIHNhdGlzZmFjdGlvbiB3aXRoIGRlbW9jcmFjeSBieSBlZHVjYXRpb25hbCBsZXZlbAoKVG8gZXZhbHVhdGUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHNhdGlzZmFjdGlvbiB3aXRoIGRlbW9jcmFjeSBhbmQgZ2VuZGVyLCB3ZSBjYW4gYWxzbyB1c2UgdGhlIHRlc3Qgb2YgaW5kZXBlbmRlbmNlIG9mICRcY2hpXjIkLgpUaGUgcmVzdWx0cyBvZiB0aGlzIHRlc3QgYXJlIHNhdmVkIGluIGFuIG9iamVjdCAiY2hpdGVzdDIiLgoKYGBge3J9CmNoaXRlc3QyIDwtIGNoaXNxLnRlc3QobGFwb3AxOCRzYXRpcywgbGFwb3AxOCRlZHVjKQpjaGl0ZXN0MgpgYGAKCkFnYWluLCB3ZSBvYnRhaW4gYSBwLXZhbHVlIG9mIGxlc3MgdGhhbiAwLjA1LCB3aXRoIHdoaWNoIHRoZSBudWxsIGh5cG90aGVzaXMgaXMgcmVqZWN0ZWQgYW5kIGl0IGlzIGFmZmlybWVkIHRoYXQgdGhlIG9ic2VydmVkIGZyZXF1ZW5jaWVzIGFyZSBkaWZmZXJlbnQgZnJvbSB0aG9zZSBleHBlY3RlZCwgd2l0aCB3aGljaCB3ZSBjb25jbHVkZSB0aGF0IHRoZXJlIHdvdWxkIGJlIGEgZGVwZW5kZW5jeSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgdmFyaWFibGVzLgoKVG8gZXZhbHVhdGUgdGhlIHN0cmVuZ3RoIG9mIHRoZSByZWxhdGlvbnNoaXAsIHdlIHVzZSB0aGUgbGlicmFyeSBgb2lpYCBhbmQgdGhlIGNvbW1hbmQgYGFzc29jaWF0aW9uLm1lYXN1cmVzYCwgdGhhdCByZXR1cm4gYSBzZXJpZXMgb2YgYXNzb2NpYXRpb24gbWVhc3VyZXMgdGhhdCBmaXQgdGhpcyB0eXBlcyBvZiB2YXJpYWJsZXMsIHRoYXQgaW4gdGhpcyBjYXNlIGFyZSBib3RoIG9yZGluYWwKCmBgYHtyIG9yZGluYWx9CmxpYnJhcnkob2lpKQphc3NvY2lhdGlvbi5tZWFzdXJlcyhsYXBvcDE4JHNhdGlzLCBsYXBvcDE4JGVkdWMpCmBgYAoKSW4gdGhpcyBjYXNlLCB3ZSBvYnNlcnZlIHRoZSBtZWFzdXJlcyBvZiBhc3NvY2lhdGlvbiBmb3Igb3JkaW5hbCB2YXJpYWJsZXMuClRoaXMgY29tbWFuZCByZXBvcnRzIDQgb2YgdGhlc2UgbWVhc3VyZW1lbnRzLCBhbGwgb2YgdGhlbSB2YXJ5IGJldHdlZW4gLTEgdG8gKzEuCkluIG91ciBleGFtcGxlLCB0aGV5IGFsbCBoYXZlIGEgcG9zaXRpdmUgc2lnbiwgd2hpY2ggaW5kaWNhdGVzIGEgZGlyZWN0IHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGJvdGggdmFyaWFibGVzLgpUaGlzIHdvdWxkIHNlZW0gdG8gZ28gYWdhaW5zdCB3aGF0IGlzIHJlcG9ydGVkIGluIEZpZ3VyZSAxLjE0IG9mIHRoZSByZXBvcnQgd2hlcmUgaXQgaXMgY2xlYXJseSBvYnNlcnZlZCB0aGF0IHNhdGlzZmFjdGlvbiB3aXRoIGRlbW9jcmFjeSBkZWNyZWFzZXMgYXQgaGlnaGVyIGVkdWNhdGlvbmFsIGxldmVscywgd2hpY2ggd291bGQgYmUgZXhwcmVzc2VkIGluIGEgbmVnYXRpdmUgc2lnbi4KClRoaXMgYXBwYXJlbnQgY29udHJhZGljdGlvbiBpcyBkdWUgb24gaG93IHNhdGlzZmFjdGlvbiB3aXRoIGRlbW9jcmFjeSAoInNhdGlzIiB2YXJpYWJsZSB0aGF0IGlzIGNyZWF0ZWQgZnJvbSAicG40IikgaGFzIGJlZW4gY29kZWQuClRoZSBvcmlnaW5hbCB2YXJpYWJsZSBoYXMgdmFsdWVzIGJldHdlZW4gMSBhbmQgNCwgd2hlcmUgMSBtZWFucyAidmVyeSBzYXRpc2ZpZWQiIGFuZCA0IG1lYW5zICJ2ZXJ5IGRpc3NhdGlzZmllZCIuClRoYXQgaXMsIGhpZ2ggdmFsdWVzIGluZGljYXRlICJsZXNzImluIHRoZSB2YXJpYWJsZS4KSXQgaXMgZm9yIHRoaXMgcmVhc29uIHRoYXQgdGhlIGFzc29jaWF0aW9uIHRlc3QgcmVzdWx0cyB3aXRoIGEgcG9zaXRpdmUgc2lnbiwgd2hpY2ggaW4gdGhpcyBjYXNlIHdvdWxkIGluZGljYXRlIHRoYXQgYSBoaWdoZXIgdmFsdWUgb2YgdGhlIGVkdWNhdGlvbiB2YXJpYWJsZSBtZWFucyAibW9yZSIgb2YgdGhlIHNhdGlzZmFjdGlvbiB3aXRoIGRlbW9jcmFjeSB2YXJpYWJsZSAod2hpY2ggaXMgYWN0dWFsbHkgbGVzcykuCgpUbyBhdm9pZCB0aGlzIGNvbmZ1c2lvbiwgdGhlIG1vbm90b255IG9mIHRoZSBzYXRpc2ZhY3Rpb24gd2l0aCBkZW1vY3JhY3kgdmFyaWFibGUgc2hvdWxkIGhhdmUgYmVlbiBjaGFuZ2VkIHNvIHRoYXQgaGlnaGVyIHZhbHVlcyBpbmRpY2F0ZSBncmVhdGVyIHNhdGlzZmFjdGlvbiBhbmQsIHdpdGggdGhpcywgYSBuZWdhdGl2ZSBzaWduIGlzIG9idGFpbmVkIGluIHRoZSBhc3NvY2lhdGlvbiBtZWFzdXJlcy4KVGhpcyBoYXMgYmVlbiBkb25lIGluIHRoaXMgc2VjdGlvbiB0byBkcmF3IGF0dGVudGlvbiB0byB0aGUgZmFjdCB0aGF0IGNvZGluZyBoYXMgY29uc2VxdWVuY2VzIGZvciB0aGUgcmVzdWx0cyBhbmQgY2FuIGxlYWQgdG8gY29uZnVzaW9uIGlmIGNhcmUgaXMgbm90IHRha2VuLgoKRmluYWxseSwgdGhlIHZhbHVlIG9mIHRoZSBhc3NvY2lhdGlvbiBtZWFzdXJlcyBhcmUgbGVzcyB0aGFuIDAuMywgaW5kaWNhdGluZyB0aGF0IHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgdmFyaWFibGVzIGlzIHdlYWsuCgojIFN1bW1hcnkKCkluIHRoaXMgc2VjdGlvbiB3ZSBoYXZlIHdvcmtlZCB3aXRoIGJpdmFyaWF0ZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gY2F0ZWdvcmljYWwgdmFyaWFibGVzLgpDcm9zcy10YWJsZXMgYW5kIGJhciBncmFwaHMgaGF2ZSBiZWVuIGNhbGN1bGF0ZWQgdG8gc2hvdyB0aGUgZGVzY3JpcHRpdmUgcmVzdWx0cy4KVGhlbiwgdGhlIGNoaS1zcXVhcmUgdGVzdCBvZiBpbmRlcGVuZGVuY2UgaGFzIGJlZW4gdXNlZCB0byBpbmZlciB3aGV0aGVyIHRoZXJlIGlzIGEgZGVwZW5kZW5jeSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgdmFyaWFibGVzIGluIHRoZSBwb3B1bGF0aW9uIGFuZCBmaW5hbGx5IHRoZSBzdHJlbmd0aCBvZiB0aGUgYXNzb2NpYXRpb24gYmV0d2VlbiB0aGUgdmFyaWFibGVzIGlzIGV2YWx1YXRlZCwgZGlmZmVyZW50aWF0aW5nIHdoZW4gaXQgY29tZXMgdG8gbm9taW5hbCBvciBvcmRpbmFsIHZhcmlhYmxlcy4KCiMgQ2FsY3VsYXRpb25zIGluY2x1ZGluZyBzdXJ2ZXkgd2VpZ2h0cwoKV2UgY2FsY3VsYXRlIHRoZSBwZXJjZW50YWdlIG9mIHZvdGVzIGFyZSBjb3VudGVkIGZhaXJseSBieSBjb3VudHJ5IGluY2x1ZGluZyBzdXJ2ZXkgd2VpZ2h0cyBpbiB0aGUgc2VjdGlvbiBhYm91dCBbZGVzY3JpcHRpdmVzIG9mIG9yZGluYWwgdmFyaWFibGVzXShodHRwczovL2FydHVyb21hbGRvbmFkby5naXRodWIuaW8vQmFyb21ldHJvRWR1X1dlYl9FbmcvRGVzY3JpcHRpdmVzMi5odG1sKS4KV2l0aCB0aGlzIGRhdGEsIHdlIHJlcGxpY2F0ZSBGaWd1cmUgMi41LgoKVG8gY2FsY3VsYXRlIGEgY2hpLXNxdWFyZSB0ZXN0IGluY2x1ZGluZyBzdXJ2ZXkgd2VpZ2h0cywgd2UgY2FuIHVzZSB0aGUgbGlicmFyeSBgc3VydmV5YCBhbmQgdGhlIGNvbW1hbmQgYHN2eWNoaXNxYC4KCmBgYHtyIGRlc2lnbn0KbGlicmFyeShzdXJ2ZXkpCmRlc2lnbjE4ID0gc3Z5ZGVzaWduKGlkcyA9IH51cG0sIHN0cmF0YSA9IH5lc3RyYXRvcHJpLCB3ZWlnaHRzID0gfndlaWdodDE1MDAsIG5lc3Q9VFJVRSwgZGF0YT1sYXBvcDE4KQpgYGAKCldlIGNhbGN1bGF0ZSB0aGUgY29udGluZ2VuY3kgdGFibGUgd2l0aCB0aGUgY29tbWFuZCBgc3Z5dGFibGVgLgpJbiB0aGlzIGNhc2Ugd2UgY3Jvc3Mgc2F0aXNmYWN0aW9uIHdpdGggZGVtb2NyYWN5IGJ5IGdlbmRlci4KVGhpcyBjb21tYW5kIGlzIG5lc3RlZCBpbnNpZGUgYHByb3AudGFibGVgIHRvIGRpc3BsYXkgdGhlIHJlbGF0aXZlIGZyZXF1ZW5jaWVzIGFuZCBub3QgdGhlIGFic29sdXRlIG9uZXMuCkluIHR1cm4sIGFsbCBvZiB0aGlzIGlzIG5lc3RlZCBpbnNpZGUgdGhlIGNvbW1hbmQgYGFkZG1hcmdpbnNgIHRvIHByZXNlbnQgdGhlIHJlbGF0aXZlIGZyZXF1ZW5jaWVzIGFzIHBlcmNlbnRhZ2VzLgpJbiB0aGUgc2FtZSB3YXkgYXMgYWJvdmUsIHdlIGNhbiBzYXZlIHRoaXMgdGFibGUgaW4gYW4gb2JqZWN0IGZvciBncmFwaGluZyB0aGVzZSByZXN1bHRzLgoKYGBge3IgdGFibGV3fQphZGRtYXJnaW5zKHByb3AudGFibGUoc3Z5dGFibGUofnNhdGlzK2dlbmRlciwgZGVzaWduPWRlc2lnbjE4KSwyKSoxMDAsMSkKYGBgCgpUaGUgQ2hpLXNxdWFyZSB0ZXN0IG9mIGluZGVwZW5kZW5jZSBpbmNvcnBvcmF0aW5nIHN1cnZleSB3ZWlnaHRzIGlzIGNvbXB1dGVkIHVzaW5nIHRoZSBjb21tYW5kIGBzdnljaGlzcWAuClRoZSBkZXBlbmRlbnQgdmFyaWFibGUsIHRoZSBpbmRlcGVuZGVudCB2YXJpYWJsZSBhbmQgdGhlIG9iamVjdCBhcmUgaW5jbHVkZWQgd2l0aCB0aGUgc2FtcGxlIGRlc2lnbi4KCmBgYHtyIGNoaXd9CmNoaXRlc3QzID1zdnljaGlzcSh+c2F0aXMrZ2VuZGVyLGRlc2lnbjE4KQpjaGl0ZXN0MwpgYGAKClRoZSByZXN1bHRzIHNob3cgYSBwLXZhbHVlIGxlc3MgdGhhbiAwLjA1LCBzbyB0aGUgSDAgb2YgZXF1YWwgZXhwZWN0ZWQgYW5kIG9ic2VydmVkIGZyZXF1ZW5jaWVzIGNhbiBiZSByZWplY3RlZCwgc28gd2UgY29uY2x1ZGUgdGhhdCB0aGVyZSBpcyBhIHJlbGF0aW9uc2hpcCBvZiBzdGF0aXN0aWNhbCBkZXBlbmRlbmNlIGJldHdlZW4gYm90aCB2YXJpYWJsZXMuCgpPYnNlcnZlZCBhbmQgZXhwZWN0ZWQgdmFsdWVzIGNhbiBiZSBjYWxjdWxhdGVkLgpBcyBjYW4gYmUgc2VlbiwgdGhlIGV4cGVjdGVkIHZhbHVlcyBkaWZmZXIgZnJvbSB0aGUgcmVzdWx0cyB3aXRob3V0IHN1cnZleSB3ZWlnaHRzLgoKYGBge3Igb2JzdnJleHB3fQpjaGl0ZXN0MyRvYnNlcnZlZApjaGl0ZXN0MyRleHBlY3RlZApgYGAKCkluIHRoaXMgY2FzZSwgdGhlcmUgaXMgbm8gY29tbWFuZCB0byBjYWxjdWxhdGUgdGhlIGFzc29jaWF0aW9uIG1lYXN1cmVzIGluY29ycG9yYXRpbmcgdGhlIGRlc2lnbiBlZmZlY3QuClVud2VpZ2h0ZWQgYXNzb2NpYXRpb24gbWVhc3VyZXMgY2FuIGJlIHRha2VuIGFzIHJlZmVyZW5jZSB2YWx1ZXMuCg==