This is a RMarkdown version of the tutorial “Performing fuzzy- and crisp set QCA with R A user-oriented beginner’s guide” version 07.03.2018 Authors: Dr. Eva Thomann Ioana-Elena Oana Stefan Wittwer Bamberg, March 18

I use most of the examples and the text from this source, often verbatim. Different from the tutorial, I use real data so as to have computable examples.

Data

We use the data set from the QCA package, also often used by Ragin and others.

data(LR)
data(LC)
data (LM)
data(LF)

LR are the raw data, LC is a crisp set, LM is a multi-value fuzzy set, and LF a fuzzy set version of LR.

A data frame containing 18 rows and the following 6 columns:

Switching to the naming style in the tutorial:

mydata <- LR

Chapter 4 Calibration and operation with sets

(Note. Chapters 1-3 are mainly on generic R and are skipped here.)

4.1 Calibration

4.1.1 Fuzzy sets

Direct method of calibration

We want to practice calibration on the DEV variable. Firs we copy this over into the name used in the tutorial, rawvar:

(To remove DEV we could domydata$DEV <- NULL but let’s not.)

The values in this variable are:

 [1]  720 1098  586  468  590  983  795  390  424  662  517 1008  350  320  331  367  897 1038

To calibrate DEV, we in principle should use theory. Here, we use what looks like reasonable values from the 18 values:

  • e - threshold for nonmembership: 300
  • c - crossover point: 600
  • i - full membership: 800
mydata$MYFUZZYSET <- round(calibrate(mydata$rawvar, type = "fuzzy", thresholds = "e=300, c=600, i=800", logistic=TRUE), digits=2)
mydata$MYFUZZYSET
 [1] 0.85 1.00 0.47 0.21 0.48 1.00 0.95 0.11 0.15 0.71 0.31 1.00 0.08 0.06 0.07 0.09 0.99 1.00

(NOTE. The naming convention is to use capital var names for sets, and small letters for negated sets, see below.)

The data in the fuzzy set vary between zero and one. logistic = TRUE is the default; to use a linear method, specify logistic = FALSE.

Insert here what the meaning and difference between the two is.

Values can be overwritten by hand, if needed, like so:

mydata$MYFUZZYSET[mydata$rawvar == 3] <- 0.05

doing so requires a good reason, of course, and it reduces reproducability.

Multi-value fuzzy sets

This is a ‘manual’ method, essentially a recoding of a variable. For instance:

mydata$MYFUZZYSET <- NA
mydata$MYFUZZYSET[(mydata$rawvar >= 1)&(mydata$rawvar <= 400)] <- 0
mydata$MYFUZZYSET[(mydata$rawvar >= 401)&(mydata$rawvar <= 800)] <- 0.3
mydata$MYFUZZYSET[(mydata$rawvar >= 801)] <- 1
mydata$MYFUZZYSET
 [1] 0.3 1.0 0.3 0.3 0.3 1.0 0.3 0.0 0.3 0.3 0.3 1.0 0.0 0.0 0.0 0.0 1.0 1.0

Avoid 0.5 as value!

Crisp sets

For calibratig a crisp set we need only to specify the crossover point, e.g. 600. Of course, this can also be done directly on the data by recoding.

mydata$CRISPSET <- calibrate(mydata$rawvar, type = "crisp", thresholds = 600, include = TRUE)
mydata$CRISPSET
 [1] 1 1 0 0 0 1 1 0 0 1 0 1 0 0 0 0 1 1

If you set include = TRUE, values of 50 will be calibrated as set membership 1. If it is set to FALSE, values of 50 will be counted as set membership 0.

Avoid 0.5 as value!

Tips for calibration

Labelling sets

Future versions of QCA will have a lot of commands that allow you to negate sets using lowercase notation. In this scenario, whether you use upper- or lowercase letters is really decisive. To avoid problems and confusion, always use uppercase letters for labelling your sets, and lowercase letters for their negation.

Keep labels for sets short.

Finding calibration thresholds

The QCA package does offer data-driven ways to find calibration thresholds. They are not included in this manual because the resulting sets are very hard to interpret. The most important analytic choice is that of the threshold that establishes the difference in kind. Whenever possible, use conceptual and theoretical criteria for the crossover point and avoid using purely empirical criteria such as descriptive statistics. Avoid using the median as crossover point: it can usually not be interpreted other than the set of “cases with values equal as or higher than 50% of the other cases”. Similarly, if you use the sample mean (e.g., for unemployment) as crossover point, the conceptual meaning of the set is “unemployment above average in the cases observed”. All this does not mean that empirical criteria are not important for determining calibration thresholds. In particular, you should avoid overly skewed sets (4.2.2 and 8.1) and empirical cases on the crossover point (4.2.3).

Technically, it is easy to calibrate sets. However, calibration is essentially a process of concept formation and definition that interacts decisively with your theory, research design and results. Therefore, calibration is one of the most demanding analytic phases of a QCA analysis. Take a lot of time for calibration, and try out different options. If you find that several different crossover points are equally plausible, try them all and see how that affects the analysis. This is called a robustness test and a very good thing to do (see also Maggetti and Levi-Faur 2013). See 4.2.1 and the online appendix of Hinterleitner, Sager and Thomann (2016) for an illustration.

After calibrating your raw data, save the calibrated sets in a new dataset. Some commands do not work if the dataset does not contain only variables that range from 0-1.

myfuzzydata <- subset(mydata, select = c("mydata$MYFUZZYSET", "mydata$CRISPSET")) write.csv2(myfuzzydata, "myfuzzydata.csv")

4.2 Calibration diagnostics

You can visualize the calibration with an XY plot, which will equally show you not only if there are cases on the 0.5 threshold, but also how the cases distribute in the set (see also section 5 on graphs).

A basic way of doing this can be to plot a set against its raw scores and set a horizontal line at the crossover point, as well as a vertical line at the raw value that indicates the crossover point (here: 600).

mydata$MYFUZZYSET <- round(calibrate(mydata$rawvar, type = "fuzzy", thresholds = "e=300, c=600, i=800", logistic=TRUE), digits=2)
plot(mydata$rawvar, mydata$MYFUZZY, pch=18, col="black", main='MYFUZZYSET',
xlab=' Raw score ',
ylab=' Fuzzy score ')
abline(h=0.5, col="black") 
abline(v= 600, col="black")

In the example below, we plot the calibration of “MYFUZZYSET”. The crossover point is set at 600, and indicated by a vertical black line (v= 60); we have also added a horizontal black line at set membership 0.5 (h=0.5 – optional). In addition, the last two command lines (optional) add two dotted vertical lines to the graph to indicate two alternative plausible crossover points (500 and 700) that we decided could be tested for robustness. The plot shows us whether, for example, changing the crossover point from 500 to 700 would change the qualitative set membership of an empirical case (indicated by a dot in-between the black and the left-hand side dotted line).

plot(mydata$rawvar, mydata$MYFUZZYSET, pch=18, col="black", main='MYFUZZYSET',
   xlab=' Raw score ',
   ylab=' Fuzzy score ')
abline(h=0.5, col="black")
abline(v= 600, col="black")
abline(v= 500, col="black", lty="dotted") 
abline(v= 700, col="black", lty="dotted")

In the following plot, we only test for one possible alternative crossover point (25 = regular crossover point, 500 = alternative crossover point). The line for the alternative crossover point is shaded grey, and we also add the data curve for the alternative calibration using the points option – again, shaded blue. The alternative is computed using the linear calibration option.

mydata$MYALTERNATIVESET <- round(calibrate(mydata$rawvar, type = "fuzzy", thresholds = "e=300, c=600, i=800", logistic=FALSE), digits=2)
plot(mydata$rawvar, mydata$MYFUZZYSET, pch=18, col="black", main=' MYFUZZYSET ',
xlab=' Raw score ',
ylab=' Fuzzy score ')
points(mydata$rawvar, mydata$MYALTERNATIVESET, pch=18, col="blue", lty="dotted")
abline(h=0.5, col="black")
abline(v= 600, col="black")
abline(v= 500, col="black", lty="dotted")

4.2.2. Skewness

To check the skewness of your set, you can identify the number of cases that have set membership above 0.5 and check whether there is a disproportionate amount of them in your data.

skewMYSET <- as.numeric(mydata$MYFUZZYSET > 0.5) 
skewMYSET
 [1] 1 1 0 0 0 1 1 0 0 1 0 1 0 0 0 0 1 1
sum(skewMYSET)
[1] 8

as.numeric turns the logical test result into zeros and 1s, and the sum over that is the number of cases GT 0.5. 8 cases out of 18 does not seem too imbalanced.

Obtain the percentage of cases with set membership above 0.5 (right-hand side value):

prop.table(table(skewMYSET))
skewMYSET
        0         1 
0.5555556 0.4444444 

Identify the names of the cases with set membership above 0.5:

rownames(subset(mydata, MYFUZZYSET > 0.5))
[1] "AU" "BE" "FR" "DE" "IE" "NL" "SE" "UK"

4.2.3 Cases on crossover point

You can check the number of cases that have membership of 0.5 in a set:

checkMYSET <- as.numeric(mydata$MYFUZZYSET == 0.5) 
sum(checkMYSET)
[1] 0

It should be zero.

If the value is not zero for a set, you can identify which cases are offending. Here’s a way of doing this for multiple sets with one command:

rownames(subset(mydata, checkMYSET1==1 | checkMYSET2==1 | checkMYSET3==1))

To exclude these cases, run something like this (note that the trailing comma is needed):

mydata = mydata[mydata$MYFUZZYSET != 0.5,]

In summary, here’s a template code for what you could use as a standard procedure when calibrating a fuzzy set using the direct calibration method:

# descriptive statistics
describe(mydata$var)

# check for missings (% of cases with missings) 
varmiss <- as.numeric(is.na(mydata$var)) prop.table(table(varmiss))

# calibration (fuzzy set, direct calibration method, rounded to 2 digits) 
mydata$MYFUZZYSET <- round(calibrate(mydata$var, type = "fuzzy", thresholds = "e=1, c=2.5, i=4", logistic = TRUE), digits=2)

# Number of cases on the crossover point 
checkMYSET <- as.numeric(mydata$MYSET == 0.5) 
sum(checkMYSET)

# check for skewness (% of cases with membership > 0.5) 
skewMYSET <- as.numeric(mydata$MYSET > 0.5)
prop.table(table(skewMYSET))

# visualize calibration
plot(mydata$var, mydata$MYSET, pch=18, col="black",
  main='MYSET', 
  xlab=' Raw score ',
  ylab=' Fuzzy score ')
abline(h=0.5, col="black") 
abline(v= 25, col="black")

4.3 Calculating membership in operations on sets

If you create a new set (a negated set, a disjunction or a conjunction, or a combination of these), you may want to store it as an object (NEWSET <- operation), so that you can use it for further analysis. You can also (but don’t have to) tie it to the dataset by using the dollar sign (mydata$NEWSET <- operation), so that it appears as a new variable in the dataset. You have several options to calculate the cases’ membership in combined sets.

A. Automatically, using compute()

The compute() command allows you to directly calculate the membership in any expression you wish to indicate, e.g. in truth table rows or the solution term. You can use either the tilde ~ sign or lowercase notation to negate sets, but be consistent. You can also skip the ’*’ sign if you prefer. Below we calculate the cases’ membership in the set set1*SET2 + set3*SET4*set5 + SET6 and store the values as an object “sol” for further use.

# use the crisp set for these operations
mydata <- LF

This is directly from the help text:

compute("DEV*ind + URB*STB", data = LF)
 [1] 0.27 0.89 0.91 0.16 0.58 0.19 0.31 0.09 0.13 0.72 0.34 0.99 0.02 0.01 0.03 0.20 0.33 0.98
sol <- compute("myset1*MYSET2 + myset3*MYSET4*myset5 + MYSET6", data=mydata)

B. Via logical operators

To calculate the cases’ membership in a negated set, you can simply subtract the set from 1:

mydata$dev <- 1-mydata$DEV
mydata$DEV
 [1] 0.81 0.99 0.58 0.16 0.58 0.98 0.89 0.04 0.07 0.72 0.34 0.98 0.02 0.01 0.01 0.03 0.95 0.98
mydata$dev
 [1] 0.19 0.01 0.42 0.84 0.42 0.02 0.11 0.96 0.93 0.28 0.66 0.02 0.98 0.99 0.99 0.97 0.05 0.02

Note the use of capitals and small letters. This way, you can also directly negate the set within a different command, without previously creating the negated set as a separate object. We do this here:

path1 <- fuzzyand(mydata$DEV, mydata$URB, 1-mydata$LIT)
path1
 [1] 0.01 0.02 0.02 0.02 0.01 0.01 0.01 0.04 0.07 0.02 0.10 0.01 0.02 0.01 0.01 0.03 0.01 0.01

In the tutorial, we seem to miss computation of path2, but the logical union can also be shown with other sets:

myunion <- fuzzyor(mydata$DEV, mydata$URB)
myunion
 [1] 0.81 0.99 0.98 0.16 0.58 0.98 0.89 0.09 0.16 0.72 0.34 1.00 0.17 0.02 0.03 0.30 0.95 0.99

This also works on crisp sets, which should be easier to follow:

# use the crisp set for these operations
mydata <- LC
# calculate negated set
mydata$dev <- 1-mydata$DEV
mydata$DEV
 [1] 1 1 1 0 1 1 1 0 0 1 0 1 0 0 0 0 1 1
mydata$dev
 [1] 0 0 0 1 0 0 0 1 1 0 1 0 1 1 1 1 0 0

Fuzzy AND:

mydata$DEV
 [1] 1 1 1 0 1 1 1 0 0 1 0 1 0 0 0 0 1 1
mydata$URB
 [1] 0 1 1 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1
fuzzyand(mydata$DEV, mydata$URB)
 [1] 0 1 1 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1

A more complex AND, including a negated set on the fly:

path1 <- fuzzyand(mydata$DEV, mydata$URB, 1-mydata$STB)
path1
 [1] 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0

Logical OR:

myunion <- fuzzyor(mydata$DEV, mydata$URB)
mydata$DEV
 [1] 1 1 1 0 1 1 1 0 0 1 0 1 0 0 0 0 1 1
mydata$URB
 [1] 0 1 1 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1
myunion
 [1] 1 1 1 0 1 1 1 0 0 1 0 1 0 0 0 0 1 1

(some content skipped which requires more understanding of method)

Chapter 5. XY-Plots

These are plots of a condition against the outcome. You have four commands at disposal to produce xy-plots with R. For QCA, we will usually work with either xy.plot() (for plotting single conditions or customized predefined sets; XYplot() from the QCA package equally works) or pimplot() (for plotting the solution term).

1. xy.plot (package SetMethods)

 mydata <- LF

First plot:

xy.plot("DEV", "SURV", data = mydata, labs = rownames(mydata), necessity=TRUE, 
        jitter = TRUE, main = "DEV as necessary for SURV", xlab = "DEV", ylab = "SURV")

It also automatically integrates lines for the quadrants, and a black diagonal; and it indicates the parameters of fit (consistency, coverage, PRI or RoN), which can be set to necessity (necessity=TRUE) or sufficiency (skip the necessity option or set necessity=FALSE). Use “1- “for negating sets, for example 1-mydata$myy. This plot also indicates you Haesebrouck’s consistency value, in addition to the other parameters of fit (see Haesebrouck 2015). What these values mean will be explained in Chp. 6.

The relation above is not of a kind that suggests an influence of DEV on SUIRV. Let’s try another relation:

xy.plot("LIT", "SURV", data = mydata, labs = rownames(mydata), necessity=TRUE, 
        jitter = TRUE, main = "LIT as necessary for SURV", xlab = "LIT", ylab = "SURV")

Here we see a much more > More graphic functions after we covered sufficiency and necessity.

Chapter 6. Analysis of necessity

See file Dusa2019-chp5-necessity.Rmd for more conceptual explanations.

If you want to “deductively” test the necessity for single necessary conditions or theoretically defined disjunctions representing higher-order constructs, the pof command (package: QCA) can be used if the option relation = “nec” is set (if it is set to “suf”, then the command tests for the sufficiency of the listed conditions). If you want to test for several conditions, create the list the conditions for which you want to test first. For negating conditions or the outcome, use either a tilde or 1-. This command gives you the consistency, coverage and relevance (RoN) of necessity for each listed condition. 8 In the example below, we test the necessity of conditions 1, 2, and 3 for the negated outcome.

mydata <- LF

Subsetting on three conditions:

conds <- subset(mydata, select = c("DEV", "URB", "LIT"))

Testing necessity for outcome ~SURV (which, remember, is not symmetrical to the outcome SURV):

pof(conds, '~SURV', mydata, relation = "nec")

        inclN   RoN   covN  
--------------------------- 
1  DEV  0.322  0.593  0.334 
2  URB  0.239  0.766  0.382 
3  LIT  0.573  0.387  0.414 
--------------------------- 

For some reason this function returns the data first, which is annoying. It can be changed by using $ notation to get data frames for the conds, see next example. I think that the example above is not fully correct for the current implementation of pof().

Add an interpretation of what this means.

You can also use this command for testing the necessity of only one condition (in position one, DEV). (Note that the expression as indicated on p.37, which only would suggest to put DEV in position 1 does throw an error.)

pof(mydata$DEV, '~SURV', mydata, relation = "nec")

        inclN   RoN   covN  
--------------------------- 
1  DEV  0.322  0.593  0.334 
--------------------------- 

You can also use pof() for complex condition sets. You can use either lowercase notation or tildes to negate conditions. For example, we want to know whether the condition “COND1 + cond2*COND3” is necessary (<=) for the outcome:

pof("DEV + lit*IND <= SURV", data = mydata)

               inclN   RoN   covN  
---------------------------------- 
1  DEV         0.831  0.811  0.775 
2  lit*IND     0.049  0.947  0.311 
3  expression  0.842  0.751  0.726 
---------------------------------- 

By using =>, you can test the same for sufficiency.

You can also make an XY plot that integrates the parameters of fit. This can be done for necessity (necessity=TRUE), but also for sufficiency (necessity=FALSE). This has the advantage that you can make a visual diagnostic of contradictory cases (in the upper left quadrant) and trivialness. We have done this before, but here again for ease of reference:

xy.plot("DEV", "SURV", data = mydata, necessity=TRUE)

6.2 SuperSubset procedure

The superSubset() command (package: QCA) “inductively” identifies all supersets of the outcome, both single conditions, conjunctions and disjunctions (unions) of sets. So using this command, you can basically skip the steps described in 6.1. The option incl.cut serves to specify a minimal consistency threshold that the conditions need to pass (for fuzzy sets, usually 0.9; typically 1.0 for crisp sets). Using cov.cut, you can also specify a coverage cutoff (here: 0.6), below which the necessary conditions and are deemed trivial and will not appear in the list. Use a tilde ~ to negate the outcome, e.g. outcome = “~OUTCOME”.

superSubset(mydata, outcome = "SURV",
  conditions = "DEV, URB, LIT, IND, STB",
  incl.cut = 0.9, cov.cut = 0.6)

                inclN   RoN   covN  
----------------------------------- 
1  LIT          0.991  0.509  0.643 
2  STB          0.920  0.680  0.707 
3  LIT*STB      0.915  0.800  0.793 
4  DEV+URB+IND  0.903  0.704  0.716 
----------------------------------- 

This command will give you a lot of supersets, but to decide whether they can be deemed necessary, you will still have to 1) check for deviant cases consistency in kind (plot the result), 2) check for empirical relevance / trivialness (Goertz 2006), and 3) identify whether the superset makes theoretical sense as a necessary condition, that is, whether the sets combined with the logical OR represent some higher-order concept (see Schneider and Wagemann 2012). Note also that the different supersets produced by this command are alternatives to each other: for example, if A*B is necessary, in the output you will find A*B, but also A, and also B. In summary, this command is useful because it gives you all potential necessary conditions in one go; but do not use it for mindless data-mining.

If you store the results of superSubset() as an object (here: nec), you can plot all compound necessary conditions by using pimplot():

nec <- superSubset(mydata, outcome = "SURV",
  conditions = "DEV, URB, LIT, IND, STB",
  incl.cut = 0.9, cov.cut = 0.6)

pimplot(data=mydata, results=nec, outcome="SURV", necessity=TRUE, 
        all_labels=TRUE, jitter=TRUE)

Use the backward arrow above the plot window to view all plots. The latter also indicate all parameters of fit (including RoN) and the cases with membership > 0.5 in the outcome are labelled.

Chapter 7 Analysis of sufficiency

Testing for single sufficient conditions

While the QCA technique always uses the truth table procedure for the analysis of sufficiency, in principle the sufficiency (consistency, coverage and PRI) of single conditions can also be (“deductively”) tested using the pof() command of the QCA package (just specify relation = “suf”), and visualized using, for instance, the xy.plot() command (again, specify necessity=FALSE) (see section 6.1). Alternatively, you can use QCAfit() of the SetMethods package (which additionally gives you the Haesebrouck consistency and also works for necessity, specify necessity=TRUE). You can negate the outcome by specifying neg.out=TRUE. If you don’t want to label your condition, skip cond.lab= “COND”.

QCAfit(LF$STB, LF$SURV, cond.lab= "STB", necessity=FALSE, neg.out=FALSE)
    Cons.Suf Cov.Suf   PRI Cons.Suf(H)
STB    0.707    0.92 0.664        0.65

You can also do this for several conditions at once. Just build an object (here: conds) first that contains your conditions.

conds <- subset(LF, select = c("DEV", "URB", "LIT"))
QCAfit(conds, LF$SURV, cond.lab= c("DEV", "URB", "LIT"), necessity=FALSE, neg.out=FALSE)
     Cons.Suf Cov.Suf    PRI Cons.Suf(H)
DEV    0.7746  0.8310 0.7431      0.7198
URB    0.7714  0.5387 0.7202      0.6903
LIT    0.6428  0.9906 0.5868      0.5643
~DEV   0.2743  0.2852 0.0982      0.2584
~URB   0.4017  0.5681 0.3047      0.3697
~LIT   0.1684  0.0962 0.0000      0.1598

For combinations of conditions, we need truth tables

7.2 Building the truth table and logical minimazation

Very important: the zeros and ones in TTs are not to be confused with crisp set values! The zeros and ones refer to logical conditions, not set membership.

First you want to figure out where to set the raw consistency threshold. For this you can produce a basic truth table, with raw consistencies (sorted by descending) and indicating individual cases (package: QCA).

ttSURV <- truthTable(data=LF, outcome = "SURV", conditions = "DEV, URB, LIT, IND, STB",
              incl.cut=1.00, sort.by="incl, n", complete=FALSE, show.cases=TRUE) 
ttSURV 

  OUT: output value
    n: number of cases in configuration
 incl: sufficiency inclusion score
  PRI: proportional reduction in inconsistency

     DEV URB LIT IND STB   OUT    n  incl  PRI   cases      
32    1   1   1   1   1     0     4  0.904 0.886 BE,CZ,NL,UK
22    1   0   1   0   1     0     2  0.804 0.719 FI,IE      
24    1   0   1   1   1     0     2  0.709 0.634 FR,SE      
 6    0   0   1   0   1     0     1  0.529 0.228 EE         
 5    0   0   1   0   0     0     2  0.521 0.113 HU,PL      
31    1   1   1   1   0     0     1  0.445 0.050 DE         
23    1   0   1   1   0     0     1  0.378 0.040 AU         
 2    0   0   0   0   1     0     2  0.278 0.000 IT,RO      
 1    0   0   0   0   0     0     3  0.216 0.000 GR,PT,ES   

It seems that all outcome values have been coded to zero.
Suggestion: lower the inclusion score for the presence of the outcome,
the relevant argument is "incl.cut" which now has a value of 1.

Follong this advise to the generally recommended minimal inclusion score (.8), we get:

ttSURV <- truthTable(data=LF, outcome = "SURV", conditions = "DEV, URB, LIT, IND, STB",
              incl.cut=.80, sort.by="incl, n", complete=FALSE, show.cases=TRUE) 
ttSURV

  OUT: output value
    n: number of cases in configuration
 incl: sufficiency inclusion score
  PRI: proportional reduction in inconsistency

     DEV URB LIT IND STB   OUT    n  incl  PRI   cases      
32    1   1   1   1   1     1     4  0.904 0.886 BE,CZ,NL,UK
22    1   0   1   0   1     1     2  0.804 0.719 FI,IE      
24    1   0   1   1   1     0     2  0.709 0.634 FR,SE      
 6    0   0   1   0   1     0     1  0.529 0.228 EE         
 5    0   0   1   0   0     0     2  0.521 0.113 HU,PL      
31    1   1   1   1   0     0     1  0.445 0.050 DE         
23    1   0   1   1   0     0     1  0.378 0.040 AU         
 2    0   0   0   0   1     0     2  0.278 0.000 IT,RO      
 1    0   0   0   0   0     0     3  0.216 0.000 GR,PT,ES   

The truth table command provides several options: * We set the raw consistency threshold using incl.cut. If you skip this option, then all outcomes are coded 0 except for rows with consistency 1. * n.cut is used to specify a frequency threshold (by default: 1). * The sort.by option can be set such that the rows are ordered by raw consistency (“incl”), or by the N (“n”), or by both (as done here). With decreasing = FALSE, the truth table rows would be ordered in ascending (instead of descending) order, e.g., by ascending raw consistencies. * With the show.cases option, we can choose whether we want to indicate the single cases contained in a truth table row (TRUE) or not (FALSE). * If the complete option is set to TRUE, then all logical remainders are also displayed; if FALSE, then only empirically observed truth table rows are displayed.

The next command produces the truth table from c145a in the ‘standard’ form, with all 32 possible combination of the conditions:

ttSURV <- truthTable(data=LF, outcome = "SURV", conditions = "DEV, URB, LIT, IND, STB",
              incl.cut=.80, complete=TRUE, show.cases=TRUE) 
ttSURV

  OUT: output value
    n: number of cases in configuration
 incl: sufficiency inclusion score
  PRI: proportional reduction in inconsistency

     DEV URB LIT IND STB   OUT    n  incl  PRI   cases      
 1    0   0   0   0   0     0     3  0.216 0.000 GR,PT,ES   
 2    0   0   0   0   1     0     2  0.278 0.000 IT,RO      
 3    0   0   0   1   0     ?     0    -     -              
 4    0   0   0   1   1     ?     0    -     -              
 5    0   0   1   0   0     0     2  0.521 0.113 HU,PL      
 6    0   0   1   0   1     0     1  0.529 0.228 EE         
 7    0   0   1   1   0     ?     0    -     -              
 8    0   0   1   1   1     ?     0    -     -              
 9    0   1   0   0   0     ?     0    -     -              
10    0   1   0   0   1     ?     0    -     -              
11    0   1   0   1   0     ?     0    -     -              
12    0   1   0   1   1     ?     0    -     -              
13    0   1   1   0   0     ?     0    -     -              
14    0   1   1   0   1     ?     0    -     -              
15    0   1   1   1   0     ?     0    -     -              
16    0   1   1   1   1     ?     0    -     -              
17    1   0   0   0   0     ?     0    -     -              
18    1   0   0   0   1     ?     0    -     -              
19    1   0   0   1   0     ?     0    -     -              
20    1   0   0   1   1     ?     0    -     -              
21    1   0   1   0   0     ?     0    -     -              
22    1   0   1   0   1     1     2  0.804 0.719 FI,IE      
23    1   0   1   1   0     0     1  0.378 0.040 AU         
24    1   0   1   1   1     0     2  0.709 0.634 FR,SE      
25    1   1   0   0   0     ?     0    -     -              
26    1   1   0   0   1     ?     0    -     -              
27    1   1   0   1   0     ?     0    -     -              
28    1   1   0   1   1     ?     0    -     -              
29    1   1   1   0   0     ?     0    -     -              
30    1   1   1   0   1     ?     0    -     -              
31    1   1   1   1   0     0     1  0.445 0.050 DE         
32    1   1   1   1   1     1     4  0.904 0.886 BE,CZ,NL,UK

The command below produces a truth table for the negated outcome, with raw consistency threshold 0.828, frequency threshold 1, sorted by descending raw consistency (and, raw consistency being equal, by N), showing only empirically observed rows, and showing individual cases. Note that we used lowercase letters here for labelling the truth table object because it analyzes the negated outcome. You will know that ttOUTCOME is the truth table for the positive outcome, and ttoutcome, for the negated outcome.

ttsurv <- truthTable(LF, outcome="~SURV", conditions = "DEV, URB, LIT, IND, STB",
            incl.cut=0.828, n.cut=1, sort.by="incl, n", decreasing=TRUE, complete=FALSE, show.cases=TRUE)
ttsurv

  OUT: output value
    n: number of cases in configuration
 incl: sufficiency inclusion score
  PRI: proportional reduction in inconsistency

     DEV URB LIT IND STB   OUT    n  incl  PRI   cases      
 1    0   0   0   0   0     1     3  1.000 1.000 GR,PT,ES   
 2    0   0   0   0   1     1     2  0.982 0.975 IT,RO      
23    1   0   1   1   0     1     1  0.974 0.960 AU         
31    1   1   1   1   0     1     1  0.971 0.950 DE         
 6    0   0   1   0   1     1     1  0.861 0.772 EE         
 5    0   0   1   0   0     1     2  0.855 0.732 HU,PL      
22    1   0   1   0   1     0     2  0.498 0.281 FI,IE      
24    1   0   1   1   1     0     2  0.495 0.366 FR,SE      
32    1   1   1   1   1     0     4  0.250 0.106 BE,CZ,NL,UK

The minimize() command (package: QCA) performs logical minimization of the truth table (i.e., the object we created with the truth table command, below: ttOUTCOME). First we calculate the conservative solution and obtain all details (consistency, raw and unique coverage). We also want to display the cases (show.cases) contained in the prime implicants (optional). The use.tilde option can be set to FALSE if you prefer using uppercase and lowercase notation for sets and their negation; and to TRUE if your prefer to denote negated sets with a tilde. It can be skipped and then upper-/lowercase notation is used.

csSURV <- minimize(ttSURV, details=TRUE, show.cases=TRUE, row.dom=TRUE, all.sol=FALSE, use.tilde=FALSE)
csSURV

n OUT = 1/0/C: 6/12/0 
  Total      : 18 

Number of multiple-covered cases: 0 

M1: DEV*URB*LIT*IND*STB + DEV*urb*LIT*ind*STB => SURV

                        inclS   PRI   covS   covU   cases 
--------------------------------------------------------------- 
1  DEV*URB*LIT*IND*STB  0.904  0.886  0.454  0.393  BE,CZ,NL,UK 
2  DEV*urb*LIT*ind*STB  0.804  0.719  0.265  0.204  FI,IE 
--------------------------------------------------------------- 
   M1                   0.870  0.843  0.658 

To calculate the parsimonious solution, we tell the software to include logical remainders (those with outcome “?”) representing simplifying assumptions.

psSURV <- minimize(ttSURV, include="?", details=TRUE, show.cases=TRUE, row.dom=TRUE, all.sol=FALSE)
psSURV

n OUT = 1/0/C: 6/12/0 
  Total      : 18 

Number of multiple-covered cases: 0 

M1: DEV*ind + URB*STB => SURV

            inclS   PRI   covS   covU   cases 
--------------------------------------------------- 
1  DEV*ind  0.815  0.721  0.284  0.194  FI,IE 
2  URB*STB  0.874  0.845  0.520  0.430  BE,CZ,NL,UK 
--------------------------------------------------- 
   M1       0.850  0.819  0.714 

Box 7: Useful tools for truth table analysis

psOUTCOME <- psSURV
mydata <- LF

Once you see the truth table, in order to find the appropriate raw consistency threshold, you may want to plot different truth table rows. You can plot truth table rows easily using pimplot(), including the names of cases with membership > 0.5 in the row and all parameters of fit (consistency, coverage, PRI, Haesebrouck’s consistency). However, note that this requires you to already have calculated a solution which you stored as an object (here: psOUTCOME; you could use any raw consistency to begin with, just to get such a provisional solution object to work with). Here we plot the truth table rows number 1 and 26. Use the backward arrow above the plot window in order to get inspect all the different plots:

pimplot(data=mydata, results=psOUTCOME, ttrows=c("1", "5", "32"), outcome= "SURV")

Note that the rows must have at least one case to get plotted.

You can also simply plot all truth table rows above a certain raw consistency level (here: 0.8) at once. The resulting plots have the row number as label of the X axis:

pimplot(data=mydata, results=psOUTCOME, incl.tt=0.8, outcome= "SURV")

Assessing the consequences of setting a frequency threshold:

If you set a frequency threshold of more than 1 and you want to see which rows are now treated as logical remainders by imposing such a threshold, type

ttoutcome$excluded

Exporting the truth table

You can save the truth table as a csv file. This will make it very easy to then copy-paste the table into your word file (e.g. the online appendix).

write.csv(ttOUTCOME$tt, "mytt.csv")

Box 8: Default settings for logical minimization

The row.dom option for logical minimization, if set to TRUE, is used to further eliminate redundant prime implicants when solving the PI chart, applying the principle of row dominance: if a prime implicant X covers the same configurations as another prime implicant Y and in the same time covers other configurations which Y does not cover, then Y is redundant and eliminated. By setting all.sol=TRUE, you can derive all possible solutions, irrespective of the number of prime implicants.

To obtain a subset of the solution space, set row.dom=TRUE and all.sol=FALSE. This is the default setting that the QCA package implements if you do not specify these two options (as done here in this manual). Conversely, for revealing the full extent of model ambiguity, set row.dom=FALSE and all.sol=TRUE (see Baumgartner 2015 and Baumgartner and Thiem 2015). The usage of all.sol = TRUE does not represent the opinion of the QCA package author, where the default option is FALSE.

By presenting the templates using the default options, we do not intend to make a recommendation. It is good to be aware of the fact that there are often many possible solutions, and that you have several possibilities how to deal with this.

7.3 Standard Analysis: Specifying directional expectations

Note. This section needs explanations. What does “standard analaysis” mean? What are directional expectations?

To derive an intermediate solution using Standard Analysis (Ragin 2008), we may want to specify directional expectations. Just like with the parsimonious solution, we tell the software to include simplifying assumptions; but then we specify the directional expectations (dir.exp) for each condition in the same order as the conditions were listed when creating the truth table (see section 7.2). In the example, we assume that condition 1 contributes to the outcome when present (1); condition 2 contributes to the outcome when absent (0); and we have no directional expectation (“-“) for condition 3.

7.4 Enhanced Standard Analysis: Excluding truth table rows

When deriving an intermediate solution and performing an Enhanced Standard Analysis, we may or may not specify directional expectations; but in addition, we exclude those truth table rows from the analysis of sufficiency that a) display a negated necessary condition for the same outcome, b) display a sufficient condition for the negated outcome, or c) are logically implausible (the “pregnant man”). You have several possibilities to do this. In the running text, we discuss two of them; see Box 10 for more options.

7.4.1 Excluding truth table rows before logical minimization

We can build a new truth table where we simply tell the software to code those rows with outcome 0 that display a certain configuration of conditions – we can do this only for logical remainders, or for all truth table rows, whether they are empirically observed or logical remainders. This possibility is an easy and transparent way if you think that neither your observations nor your simplifying assumptions should contradict prior findings and / or logic, and you want to see what you did to the truth table before turning to logical minimization.

In a first step, we build the truth table (here: for the negated outcome and for 5 conditions) that also displays the logical remainders (complete=TRUE):

As we have seen above (see c147), there are two sufficient conditions for the outcome SURV: M1: DEV*URB*LIT*IND*STB + DEV*urb*LIT*ind*STB => SURV. They are hence not tenable for the negated outcome, surv. Let’s find the rows with these two patterns:

I cannot use either of M1’s conditions: Whenever I add the last condition element, I get an error, even though there are matching rows in the TT.

Having found rows, we can recode these to OUT=0 in the TT:

it is worth unpackiung this command as it makes compact use of the object

With the recoded TT, one can then calculated enhanced solutions, such as the enhanced parsimonous solution:

LS0tCnRpdGxlOiAiUUNBIFR1dG9yaWFsIFRob21hbm4gZXQgYWwiCmF1dGhvcjogIlBldGVyIFJlaW1hbm4iCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0Ci0tLQoKVGhpcyBpcyBhIFJNYXJrZG93biB2ZXJzaW9uIG9mIHRoZSB0dXRvcmlhbCAiUGVyZm9ybWluZyBmdXp6eS0gYW5kIGNyaXNwIHNldCBRQ0Egd2l0aCBSCkEgdXNlci1vcmllbnRlZCBiZWdpbm5lcuKAmXMgZ3VpZGUiCnZlcnNpb24gMDcuMDMuMjAxOApBdXRob3JzOgpEci4gRXZhIFRob21hbm4gSW9hbmEtRWxlbmEgT2FuYSBTdGVmYW4gV2l0dHdlcgpCYW1iZXJnLCBNYXJjaCAxOAoKSSB1c2UgbW9zdCBvZiB0aGUgZXhhbXBsZXMgYW5kIHRoZSB0ZXh0IGZyb20gdGhpcyBzb3VyY2UsIG9mdGVuIHZlcmJhdGltLiBEaWZmZXJlbnQgZnJvbSB0aGUgdHV0b3JpYWwsIEkgdXNlIHJlYWwgZGF0YSBzbyBhcyB0byBoYXZlIGNvbXB1dGFibGUgZXhhbXBsZXMuIAoKYGBge3IgbWVzc2FnZT1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoUUNBKQpsaWJyYXJ5KFNldE1ldGhvZHMpCmxpYnJhcnkoVmVubkRpYWdyYW0pCmBgYAoKIyMjIERhdGEKCldlIHVzZSB0aGUgZGF0YSBzZXQgZnJvbSB0aGUgUUNBIHBhY2thZ2UsIGFsc28gb2Z0ZW4gdXNlZCBieSBSYWdpbiBhbmQgb3RoZXJzLgoKYGBge3J9CmRhdGEoTFIpCmRhdGEoTEMpCmRhdGEgKExNKQpkYXRhKExGKQpgYGAKCkxSIGFyZSB0aGUgcmF3IGRhdGEsIExDIGlzIGEgY3Jpc3Agc2V0LCBMTSBpcyBhIG11bHRpLXZhbHVlIGZ1enp5IHNldCwgYW5kIExGIGEgZnV6enkgc2V0IHZlcnNpb24gb2YgTFIuCgpBIGRhdGEgZnJhbWUgY29udGFpbmluZyAxOCByb3dzIGFuZCB0aGUgZm9sbG93aW5nIDYgY29sdW1uczoKCiogREVWCQogICAgKyBMZXZlbCBvZiBkZXZlbG9wbWVudDogaXQgaXMgdGhlIEdEUCBwZXIgY2FwaXRhIChVU0QpIGluIHRoZSByYXcgZGF0YSwgY2FsaWJyYXRlZCBpbiB0aGUKYmluYXJ5IGNyaXNwIHZlcnNpb24gdG8gMCBpZiBiZWxvdyA1NTAgVVNEIGFuZCAxIG90aGVyd2lzZS4gRm9yIHRoZSBtdWx0aS12YWx1ZSBjcmlzcAp2ZXJzaW9uLCB0d28gdGhyZXNob2xkcyB3ZXJlIHVzZWQ6IDU1MCBhbmQgODUwIFVTRC4KKiBVUkIJCiAgICArIExldmVsIG9mIHVyYmFuaXphdGlvbjogcGVyY2VudCBvZiB0aGUgcG9wdWxhdGlvbiBpbiB0b3ducyB3aXRoIDIwMDAwIG9yIG1vcmUKaW5oYWJpdGFudHMsIGNhbGlicmF0ZWQgaW4gdGhlIGNyaXNwIHZlcnNpb25zIHRvIDAgaWYgYmVsb3cgNTAlIGFuZCAxIGlmIGFib3ZlLgoqIExJVAkKICAgICArIExldmVsIG9mIGxpdGVyYWN5OiBwZXJjZW50IG9mIHRoZSBsaXRlcmF0ZSBwb3B1bGF0aW9uLCBjYWxpYnJhdGVkIGluIHRoZSBjcmlzcCB2ZXJzaW9ucwp0byAwIGlmIGJlbG93IDc1JSBhbmQgMSBpZiBhYm92ZS4KKiBJTkQJCiAgICAgKyBMZXZlbCBvZiBpbmR1c3RyaWFsaXphdGlvbjogcGVyY2VudCBvZiB0aGUgaW5kdXN0cmlhbCBsYWJvciBmb3JjZSwgY2FsaWJyYXRlZCBpbiB0aGUKY3Jpc3AgdmVyc2lvbnMgdG8gMCBpZiBiZWxvdyAzMCUgYW5kIDEgaWYgYWJvdmUuCiogU1RCCQogICAgICArIEdvdmVybm1lbnQgc3RhYmlsaXR5OiBhIOKAnHBvbGl0aWNhbC1pbnN0aXR1dGlvbmFs4oCdIGNvbmRpdGlvbiBhZGRlZCB0byB0aGUgcHJldmlvdXMKZm91ciDigJxzb2Npb2Vjb25vbWlj4oCdIG9uZXMuIFRoZSByYXcgZGF0YSBoYXMgdGhlIG51bWJlciBvZiBjYWJpbmV0cyB3aGljaCBnb3Zlcm5lZAppbiB0aGUgcGVyaW9kIHVuZGVyIHN0dWR5LCBjYWxpYnJhdGVkIGluIHRoZSBjcmlzcCB2ZXJzaW9ucyB0byAwIGlmIDEwIG9yIGFib3ZlIGFuZCB0byAxCmlmIGJlbG93IDEwLgoqIFNVUlYJCiAgICAgICsgT3V0Y29tZTogc3Vydml2YWwgb2YgZGVtb2NyYWN5IGR1cmluZyB0aGUgaW50ZXItd2FyIHBlcmlvZDogY2FsaWJyYXRlZCB0byAwIGlmIG5lZ2F0aXZlLAphbmQgMSBpZiBwb3NpdGl2ZSByYXcgZGF0YS4KClN3aXRjaGluZyB0byB0aGUgbmFtaW5nIHN0eWxlIGluIHRoZSB0dXRvcmlhbDoKCmBgYHtyfQpteWRhdGEgPC0gTFIKYGBgCgojIENoYXB0ZXIgNCBDYWxpYnJhdGlvbiBhbmQgb3BlcmF0aW9uIHdpdGggc2V0cwoKKCpOb3RlLiBDaGFwdGVycyAxLTMgYXJlIG1haW5seSBvbiBnZW5lcmljIFIgYW5kIGFyZSBza2lwcGVkIGhlcmUuKikKCiMjIDQuMSBDYWxpYnJhdGlvbgoKIyMjIDQuMS4xIEZ1enp5IHNldHMKCiMjIyMgRGlyZWN0IG1ldGhvZCBvZiBjYWxpYnJhdGlvbgoKV2Ugd2FudCB0byBwcmFjdGljZSBjYWxpYnJhdGlvbiBvbiB0aGUgREVWIHZhcmlhYmxlLiBGaXJzIHdlIGNvcHkgdGhpcyBvdmVyIGludG8gdGhlIG5hbWUgdXNlZCBpbiB0aGUgdHV0b3JpYWwsIGByYXd2YXJgOgoKYGBge3IgZWNobz1GQUxTRX0KbXlkYXRhJHJhd3ZhciA8LSBteWRhdGEkREVWCmBgYAooVG8gcmVtb3ZlIERFViB3ZSBjb3VsZCBkb2BteWRhdGEkREVWIDwtIE5VTExgIGJ1dCBsZXQncyBub3QuKQoKVGhlIHZhbHVlcyBpbiB0aGlzIHZhcmlhYmxlIGFyZToKYGBge3IgZWNobz1GQUxTRX0gCm15ZGF0YSRyYXd2YXIKYGBgCgpUbyBjYWxpYnJhdGUgREVWLCB3ZSBpbiBwcmluY2lwbGUgc2hvdWxkIHVzZSB0aGVvcnkuIEhlcmUsIHdlIHVzZSB3aGF0IGxvb2tzIGxpa2UgcmVhc29uYWJsZSB2YWx1ZXMgZnJvbSB0aGUgMTggdmFsdWVzOiAKCiogZSAtIHRocmVzaG9sZCBmb3Igbm9ubWVtYmVyc2hpcDogMzAwCiogYyAtIGNyb3Nzb3ZlciBwb2ludDogIDYwMAoqIGkgLSBmdWxsIG1lbWJlcnNoaXA6IDgwMAoKYGBge3J9Cm15ZGF0YSRNWUZVWlpZU0VUIDwtIHJvdW5kKGNhbGlicmF0ZShteWRhdGEkcmF3dmFyLCB0eXBlID0gImZ1enp5IiwgdGhyZXNob2xkcyA9ICJlPTMwMCwgYz02MDAsIGk9ODAwIiwgbG9naXN0aWM9VFJVRSksIGRpZ2l0cz0yKQpteWRhdGEkTVlGVVpaWVNFVApgYGAKKE5PVEUuIFRoZSBuYW1pbmcgY29udmVudGlvbiBpcyB0byB1c2UgY2FwaXRhbCB2YXIgbmFtZXMgZm9yIHNldHMsIGFuZCBzbWFsbCBsZXR0ZXJzIGZvciBuZWdhdGVkIHNldHMsIHNlZSBiZWxvdy4pCgpUaGUgZGF0YSBpbiB0aGUgZnV6enkgc2V0IHZhcnkgYmV0d2VlbiB6ZXJvIGFuZCBvbmUuIGBsb2dpc3RpYyA9IFRSVUVgIGlzIHRoZSBkZWZhdWx0OyB0byB1c2UgYSBsaW5lYXIgbWV0aG9kLCBzcGVjaWZ5IGBsb2dpc3RpYyA9IEZBTFNFYC4gCgo+IEluc2VydCBoZXJlIHdoYXQgdGhlIG1lYW5pbmcgYW5kIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgdHdvIGlzLiAKClZhbHVlcyBjYW4gYmUgb3ZlcndyaXR0ZW4gYnkgaGFuZCwgaWYgbmVlZGVkLCBsaWtlIHNvOgpgYGAKbXlkYXRhJE1ZRlVaWllTRVRbbXlkYXRhJHJhd3ZhciA9PSAzXSA8LSAwLjA1CmBgYApkb2luZyBzbyByZXF1aXJlcyBhIGdvb2QgcmVhc29uLCBvZiBjb3Vyc2UsIGFuZCBpdCByZWR1Y2VzIHJlcHJvZHVjYWJpbGl0eS4gCgojIyMjIE11bHRpLXZhbHVlIGZ1enp5IHNldHMKClRoaXMgaXMgYSAnbWFudWFsJyBtZXRob2QsIGVzc2VudGlhbGx5IGEgcmVjb2Rpbmcgb2YgYSB2YXJpYWJsZS4gRm9yIGluc3RhbmNlOgoKYGBge3J9Cm15ZGF0YSRNWUZVWlpZU0VUIDwtIE5BCm15ZGF0YSRNWUZVWlpZU0VUWyhteWRhdGEkcmF3dmFyID49IDEpJihteWRhdGEkcmF3dmFyIDw9IDQwMCldIDwtIDAKbXlkYXRhJE1ZRlVaWllTRVRbKG15ZGF0YSRyYXd2YXIgPj0gNDAxKSYobXlkYXRhJHJhd3ZhciA8PSA4MDApXSA8LSAwLjMKbXlkYXRhJE1ZRlVaWllTRVRbKG15ZGF0YSRyYXd2YXIgPj0gODAxKV0gPC0gMQpteWRhdGEkTVlGVVpaWVNFVApgYGAKQXZvaWQgMC41IGFzIHZhbHVlISAKCiMjIyMgQ3Jpc3Agc2V0cwoKRm9yIGNhbGlicmF0aWcgYSBjcmlzcCBzZXQgd2UgbmVlZCBvbmx5IHRvIHNwZWNpZnkgdGhlIGNyb3Nzb3ZlciBwb2ludCwgZS5nLiA2MDAuIE9mIGNvdXJzZSwgdGhpcyBjYW4gYWxzbyBiZSBkb25lIGRpcmVjdGx5IG9uIHRoZSBkYXRhIGJ5IHJlY29kaW5nLiAKCmBgYHtyfQpteWRhdGEkQ1JJU1BTRVQgPC0gY2FsaWJyYXRlKG15ZGF0YSRyYXd2YXIsIHR5cGUgPSAiY3Jpc3AiLCB0aHJlc2hvbGRzID0gNjAwLCBpbmNsdWRlID0gVFJVRSkKbXlkYXRhJENSSVNQU0VUCmBgYApJZiB5b3Ugc2V0IGluY2x1ZGUgPSBUUlVFLCB2YWx1ZXMgb2YgNTAgd2lsbCBiZSBjYWxpYnJhdGVkIGFzIHNldCBtZW1iZXJzaGlwIDEuIElmIGl0IGlzIHNldCB0byBGQUxTRSwgdmFsdWVzIG9mIDUwIHdpbGwgYmUgY291bnRlZCBhcyBzZXQgbWVtYmVyc2hpcCAwLgoKQXZvaWQgMC41IGFzIHZhbHVlISAKCiMjIyBUaXBzIGZvciBjYWxpYnJhdGlvbgoKIyMjIyBMYWJlbGxpbmcgc2V0cwoKRnV0dXJlIHZlcnNpb25zIG9mIFFDQSB3aWxsIGhhdmUgYSBsb3Qgb2YgY29tbWFuZHMgdGhhdCBhbGxvdyB5b3UgdG8gbmVnYXRlIHNldHMgdXNpbmcgbG93ZXJjYXNlIG5vdGF0aW9uLiBJbiB0aGlzIHNjZW5hcmlvLCB3aGV0aGVyIHlvdSB1c2UgdXBwZXItIG9yIGxvd2VyY2FzZSBsZXR0ZXJzIGlzIHJlYWxseSBkZWNpc2l2ZS4gVG8gYXZvaWQgcHJvYmxlbXMgYW5kIGNvbmZ1c2lvbiwgYWx3YXlzIHVzZSB1cHBlcmNhc2UgbGV0dGVycyBmb3IgbGFiZWxsaW5nIHlvdXIgc2V0cywgYW5kIGxvd2VyY2FzZSBsZXR0ZXJzIGZvciB0aGVpciBuZWdhdGlvbi4KCktlZXAgbGFiZWxzIGZvciBzZXRzIHNob3J0LiAKCiMjIyMgRmluZGluZyBjYWxpYnJhdGlvbiB0aHJlc2hvbGRzCgpUaGUgUUNBIHBhY2thZ2UgZG9lcyBvZmZlciBkYXRhLWRyaXZlbiB3YXlzIHRvIGZpbmQgY2FsaWJyYXRpb24gdGhyZXNob2xkcy4gVGhleSBhcmUgbm90IGluY2x1ZGVkIGluIHRoaXMgbWFudWFsIGJlY2F1c2UgdGhlIHJlc3VsdGluZyBzZXRzIGFyZSB2ZXJ5IGhhcmQgdG8gaW50ZXJwcmV0LiBUaGUgbW9zdCBpbXBvcnRhbnQgYW5hbHl0aWMgY2hvaWNlIGlzIHRoYXQgb2YgdGhlIHRocmVzaG9sZCB0aGF0IGVzdGFibGlzaGVzIHRoZSBkaWZmZXJlbmNlIGluIGtpbmQuIFdoZW5ldmVyIHBvc3NpYmxlLCB1c2UgY29uY2VwdHVhbCBhbmQgdGhlb3JldGljYWwgY3JpdGVyaWEgZm9yIHRoZSBjcm9zc292ZXIgcG9pbnQgYW5kIGF2b2lkIHVzaW5nIHB1cmVseSBlbXBpcmljYWwgY3JpdGVyaWEgc3VjaCBhcyBkZXNjcmlwdGl2ZSBzdGF0aXN0aWNzLiBBdm9pZCB1c2luZyB0aGUgbWVkaWFuIGFzIGNyb3Nzb3ZlciBwb2ludDogaXQgY2FuIHVzdWFsbHkgbm90IGJlIGludGVycHJldGVkIG90aGVyIHRoYW4gdGhlIHNldCBvZiDigJxjYXNlcyB3aXRoIHZhbHVlcyBlcXVhbCBhcyBvciBoaWdoZXIgdGhhbiA1MCUgb2YgdGhlIG90aGVyIGNhc2Vz4oCdLiBTaW1pbGFybHksIGlmIHlvdSB1c2UgdGhlIHNhbXBsZSBtZWFuIChlLmcuLCBmb3IgdW5lbXBsb3ltZW50KSBhcyBjcm9zc292ZXIgcG9pbnQsIHRoZSBjb25jZXB0dWFsIG1lYW5pbmcgb2YgdGhlIHNldCBpcyDigJx1bmVtcGxveW1lbnQgYWJvdmUgYXZlcmFnZSBpbiB0aGUgY2FzZXMgb2JzZXJ2ZWTigJ0uIEFsbCB0aGlzIGRvZXMgbm90IG1lYW4gdGhhdCBlbXBpcmljYWwgY3JpdGVyaWEgYXJlIG5vdCBpbXBvcnRhbnQgZm9yIGRldGVybWluaW5nIGNhbGlicmF0aW9uIHRocmVzaG9sZHMuIEluIHBhcnRpY3VsYXIsIHlvdSBzaG91bGQgYXZvaWQgb3Zlcmx5IHNrZXdlZCBzZXRzICg0LjIuMiBhbmQgOC4xKSBhbmQgZW1waXJpY2FsIGNhc2VzIG9uIHRoZSBjcm9zc292ZXIgcG9pbnQgKDQuMi4zKS4KClRlY2huaWNhbGx5LCBpdCBpcyBlYXN5IHRvIGNhbGlicmF0ZSBzZXRzLiBIb3dldmVyLCBjYWxpYnJhdGlvbiBpcyBlc3NlbnRpYWxseSBhIHByb2Nlc3Mgb2YgY29uY2VwdCBmb3JtYXRpb24gYW5kIGRlZmluaXRpb24gdGhhdCBpbnRlcmFjdHMgZGVjaXNpdmVseSB3aXRoIHlvdXIgdGhlb3J5LCByZXNlYXJjaCBkZXNpZ24gYW5kIHJlc3VsdHMuIFRoZXJlZm9yZSwgY2FsaWJyYXRpb24gaXMgb25lIG9mIHRoZSBtb3N0IGRlbWFuZGluZyBhbmFseXRpYyBwaGFzZXMgb2YgYSBRQ0EgYW5hbHlzaXMuIFRha2UgYSBsb3Qgb2YgdGltZSBmb3IgY2FsaWJyYXRpb24sIGFuZCB0cnkgb3V0IGRpZmZlcmVudCBvcHRpb25zLiBJZiB5b3UgZmluZCB0aGF0IHNldmVyYWwgZGlmZmVyZW50IGNyb3Nzb3ZlciBwb2ludHMgYXJlIGVxdWFsbHkgcGxhdXNpYmxlLCB0cnkgdGhlbSBhbGwgYW5kIHNlZSBob3cgdGhhdCBhZmZlY3RzIHRoZSBhbmFseXNpcy4gVGhpcyBpcyBjYWxsZWQgYSByb2J1c3RuZXNzIHRlc3QgYW5kIGEgdmVyeSBnb29kIHRoaW5nIHRvIGRvIChzZWUgYWxzbyBNYWdnZXR0aSBhbmQgTGV2aS1GYXVyIDIwMTMpLiBTZWUgNC4yLjEgYW5kIHRoZSBvbmxpbmUgYXBwZW5kaXggb2YgSGludGVybGVpdG5lciwgU2FnZXIgYW5kIFRob21hbm4gKDIwMTYpIGZvciBhbiBpbGx1c3RyYXRpb24uCgpBZnRlciBjYWxpYnJhdGluZyB5b3VyIHJhdyBkYXRhLCBzYXZlIHRoZSBjYWxpYnJhdGVkIHNldHMgaW4gYSBuZXcgZGF0YXNldC4gU29tZSBjb21tYW5kcyBkbyBub3Qgd29yayBpZiB0aGUgZGF0YXNldCBkb2VzIG5vdCBjb250YWluIG9ubHkgdmFyaWFibGVzIHRoYXQgcmFuZ2UgZnJvbSAwLTEuIAoKYGBgCm15ZnV6enlkYXRhIDwtIHN1YnNldChteWRhdGEsIHNlbGVjdCA9IGMoIm15ZGF0YSRNWUZVWlpZU0VUIiwgIm15ZGF0YSRDUklTUFNFVCIpKSB3cml0ZS5jc3YyKG15ZnV6enlkYXRhLCAibXlmdXp6eWRhdGEuY3N2IikKYGBgCgojIyA0LjIgQ2FsaWJyYXRpb24gZGlhZ25vc3RpY3MKCllvdSBjYW4gdmlzdWFsaXplIHRoZSBjYWxpYnJhdGlvbiB3aXRoIGFuIFhZIHBsb3QsIHdoaWNoIHdpbGwgZXF1YWxseSBzaG93IHlvdSBub3Qgb25seSBpZiB0aGVyZSBhcmUgY2FzZXMgb24gdGhlIDAuNSB0aHJlc2hvbGQsIGJ1dCBhbHNvIGhvdyB0aGUgY2FzZXMgZGlzdHJpYnV0ZSBpbiB0aGUgc2V0IChzZWUgYWxzbyBzZWN0aW9uIDUgb24gZ3JhcGhzKS4KCkEgYmFzaWMgd2F5IG9mIGRvaW5nIHRoaXMgY2FuIGJlIHRvIHBsb3QgYSBzZXQgYWdhaW5zdCBpdHMgcmF3IHNjb3JlcyBhbmQgc2V0IGEgaG9yaXpvbnRhbCBsaW5lIGF0IHRoZSBjcm9zc292ZXIgcG9pbnQsIGFzIHdlbGwgYXMgYSB2ZXJ0aWNhbCBsaW5lIGF0IHRoZSByYXcgdmFsdWUgdGhhdCBpbmRpY2F0ZXMgdGhlIGNyb3Nzb3ZlciBwb2ludCAoaGVyZTogNjAwKS4gCgpgYGB7cn0KbXlkYXRhJE1ZRlVaWllTRVQgPC0gcm91bmQoY2FsaWJyYXRlKG15ZGF0YSRyYXd2YXIsIHR5cGUgPSAiZnV6enkiLCB0aHJlc2hvbGRzID0gImU9MzAwLCBjPTYwMCwgaT04MDAiLCBsb2dpc3RpYz1UUlVFKSwgZGlnaXRzPTIpCnBsb3QobXlkYXRhJHJhd3ZhciwgbXlkYXRhJE1ZRlVaWlksIHBjaD0xOCwgY29sPSJibGFjayIsIG1haW49J01ZRlVaWllTRVQnLAp4bGFiPScgUmF3IHNjb3JlICcsCnlsYWI9JyBGdXp6eSBzY29yZSAnKQphYmxpbmUoaD0wLjUsIGNvbD0iYmxhY2siKSAKYWJsaW5lKHY9IDYwMCwgY29sPSJibGFjayIpCmBgYAoKSW4gdGhlIGV4YW1wbGUgYmVsb3csIHdlIHBsb3QgdGhlIGNhbGlicmF0aW9uIG9mIOKAnE1ZRlVaWllTRVTigJ0uIFRoZSBjcm9zc292ZXIgcG9pbnQgaXMgc2V0IGF0IDYwMCwgYW5kIGluZGljYXRlZCBieSBhIHZlcnRpY2FsIGJsYWNrIGxpbmUgKHY9IDYwKTsgd2UgaGF2ZSBhbHNvIGFkZGVkIGEgaG9yaXpvbnRhbCBibGFjayBsaW5lIGF0IHNldCBtZW1iZXJzaGlwIDAuNSAoaD0wLjUg4oCTIG9wdGlvbmFsKS4gSW4gYWRkaXRpb24sIHRoZSBsYXN0IHR3byBjb21tYW5kIGxpbmVzIChvcHRpb25hbCkgYWRkIHR3byBkb3R0ZWQgdmVydGljYWwgbGluZXMgdG8gdGhlIGdyYXBoIHRvIGluZGljYXRlIHR3byBhbHRlcm5hdGl2ZSBwbGF1c2libGUgY3Jvc3NvdmVyIHBvaW50cyAoNTAwIGFuZCA3MDApIHRoYXQgd2UgZGVjaWRlZCBjb3VsZCBiZSB0ZXN0ZWQgZm9yIHJvYnVzdG5lc3MuIFRoZSBwbG90IHNob3dzIHVzIHdoZXRoZXIsIGZvciBleGFtcGxlLCBjaGFuZ2luZyB0aGUgY3Jvc3NvdmVyIHBvaW50IGZyb20gNTAwIHRvIDcwMCB3b3VsZCBjaGFuZ2UgdGhlIHF1YWxpdGF0aXZlIHNldCBtZW1iZXJzaGlwIG9mIGFuIGVtcGlyaWNhbCBjYXNlIChpbmRpY2F0ZWQgYnkgYSBkb3QgaW4tYmV0d2VlbiB0aGUgYmxhY2sgYW5kIHRoZSBsZWZ0LWhhbmQgc2lkZSBkb3R0ZWQgbGluZSkuCgpgYGB7cn0KcGxvdChteWRhdGEkcmF3dmFyLCBteWRhdGEkTVlGVVpaWVNFVCwgcGNoPTE4LCBjb2w9ImJsYWNrIiwgbWFpbj0nTVlGVVpaWVNFVCcsCiAgIHhsYWI9JyBSYXcgc2NvcmUgJywKICAgeWxhYj0nIEZ1enp5IHNjb3JlICcpCmFibGluZShoPTAuNSwgY29sPSJibGFjayIpCmFibGluZSh2PSA2MDAsIGNvbD0iYmxhY2siKQphYmxpbmUodj0gNTAwLCBjb2w9ImJsYWNrIiwgbHR5PSJkb3R0ZWQiKSAKYWJsaW5lKHY9IDcwMCwgY29sPSJibGFjayIsIGx0eT0iZG90dGVkIikKYGBgCgpJbiB0aGUgZm9sbG93aW5nIHBsb3QsIHdlIG9ubHkgdGVzdCBmb3Igb25lIHBvc3NpYmxlIGFsdGVybmF0aXZlIGNyb3Nzb3ZlciBwb2ludCAoMjUgPSByZWd1bGFyIGNyb3Nzb3ZlciBwb2ludCwgNTAwID0gYWx0ZXJuYXRpdmUgY3Jvc3NvdmVyIHBvaW50KS4gVGhlIGxpbmUgZm9yIHRoZSBhbHRlcm5hdGl2ZSBjcm9zc292ZXIgcG9pbnQgaXMgc2hhZGVkIGdyZXksIGFuZCB3ZSBhbHNvIGFkZCB0aGUgZGF0YSBjdXJ2ZSBmb3IgdGhlIGFsdGVybmF0aXZlIGNhbGlicmF0aW9uIHVzaW5nIHRoZSBwb2ludHMgb3B0aW9uIOKAkyBhZ2Fpbiwgc2hhZGVkIGJsdWUuIFRoZSBhbHRlcm5hdGl2ZSBpcyBjb21wdXRlZCB1c2luZyB0aGUgbGluZWFyIGNhbGlicmF0aW9uIG9wdGlvbi4gCgpgYGB7cn0KbXlkYXRhJE1ZQUxURVJOQVRJVkVTRVQgPC0gcm91bmQoY2FsaWJyYXRlKG15ZGF0YSRyYXd2YXIsIHR5cGUgPSAiZnV6enkiLCB0aHJlc2hvbGRzID0gImU9MzAwLCBjPTYwMCwgaT04MDAiLCBsb2dpc3RpYz1GQUxTRSksIGRpZ2l0cz0yKQpwbG90KG15ZGF0YSRyYXd2YXIsIG15ZGF0YSRNWUZVWlpZU0VULCBwY2g9MTgsIGNvbD0iYmxhY2siLCBtYWluPScgTVlGVVpaWVNFVCAnLAp4bGFiPScgUmF3IHNjb3JlICcsCnlsYWI9JyBGdXp6eSBzY29yZSAnKQpwb2ludHMobXlkYXRhJHJhd3ZhciwgbXlkYXRhJE1ZQUxURVJOQVRJVkVTRVQsIHBjaD0xOCwgY29sPSJibHVlIiwgbHR5PSJkb3R0ZWQiKQphYmxpbmUoaD0wLjUsIGNvbD0iYmxhY2siKQphYmxpbmUodj0gNjAwLCBjb2w9ImJsYWNrIikKYWJsaW5lKHY9IDUwMCwgY29sPSJibGFjayIsIGx0eT0iZG90dGVkIikKYGBgCgojIyMgNC4yLjIuIFNrZXduZXNzClRvIGNoZWNrIHRoZSBza2V3bmVzcyBvZiB5b3VyIHNldCwgeW91IGNhbiBpZGVudGlmeSB0aGUgbnVtYmVyIG9mIGNhc2VzIHRoYXQgaGF2ZSBzZXQgbWVtYmVyc2hpcCBhYm92ZSAwLjUgYW5kIGNoZWNrIHdoZXRoZXIgdGhlcmUgaXMgYSBkaXNwcm9wb3J0aW9uYXRlIGFtb3VudCBvZiB0aGVtIGluIHlvdXIgZGF0YS4KCmBgYHtyfQpza2V3TVlTRVQgPC0gYXMubnVtZXJpYyhteWRhdGEkTVlGVVpaWVNFVCA+IDAuNSkgCnNrZXdNWVNFVApzdW0oc2tld01ZU0VUKQpgYGAKYGFzLm51bWVyaWNgIHR1cm5zIHRoZSBsb2dpY2FsIHRlc3QgcmVzdWx0IGludG8gemVyb3MgYW5kIDFzLCBhbmQgdGhlIHN1bSBvdmVyIHRoYXQgaXMgdGhlIG51bWJlciBvZiBjYXNlcyBHVCAwLjUuIGByIHN1bShza2V3TVlTRVQpYCBjYXNlcyBvdXQgb2YgMTggIGRvZXMgbm90IHNlZW0gdG9vIGltYmFsYW5jZWQuIAoKT2J0YWluIHRoZSBwZXJjZW50YWdlIG9mIGNhc2VzIHdpdGggc2V0IG1lbWJlcnNoaXAgYWJvdmUgMC41IChyaWdodC1oYW5kIHNpZGUgdmFsdWUpOgoKYGBge3J9CnByb3AudGFibGUodGFibGUoc2tld01ZU0VUKSkKYGBgCgpJZGVudGlmeSB0aGUgbmFtZXMgb2YgdGhlIGNhc2VzIHdpdGggc2V0IG1lbWJlcnNoaXAgYWJvdmUgMC41OgoKYGBge3J9CnJvd25hbWVzKHN1YnNldChteWRhdGEsIE1ZRlVaWllTRVQgPiAwLjUpKQpgYGAKCiMjIyA0LjIuMyBDYXNlcyBvbiBjcm9zc292ZXIgcG9pbnQKCllvdSBjYW4gY2hlY2sgdGhlIG51bWJlciBvZiBjYXNlcyB0aGF0IGhhdmUgbWVtYmVyc2hpcCBvZiAwLjUgaW4gYSBzZXQ6CgpgYGB7cn0KY2hlY2tNWVNFVCA8LSBhcy5udW1lcmljKG15ZGF0YSRNWUZVWlpZU0VUID09IDAuNSkgCnN1bShjaGVja01ZU0VUKQpgYGAKSXQgc2hvdWxkIGJlIHplcm8uIAoKSWYgdGhlIHZhbHVlIGlzIG5vdCB6ZXJvIGZvciBhIHNldCwgeW91IGNhbiBpZGVudGlmeSB3aGljaCBjYXNlcyBhcmUgb2ZmZW5kaW5nLiBIZXJlJ3MgYSB3YXkgb2YgZG9pbmcgdGhpcyBmb3IgbXVsdGlwbGUgc2V0cyB3aXRoIG9uZSBjb21tYW5kOgoKYGBgCnJvd25hbWVzKHN1YnNldChteWRhdGEsIGNoZWNrTVlTRVQxPT0xIHwgY2hlY2tNWVNFVDI9PTEgfCBjaGVja01ZU0VUMz09MSkpCmBgYAoKVG8gZXhjbHVkZSB0aGVzZSBjYXNlcywgcnVuIHNvbWV0aGluZyBsaWtlIHRoaXMgKG5vdGUgdGhhdCB0aGUgdHJhaWxpbmcgY29tbWEgaXMgbmVlZGVkKTogCgpgYGB7cn0KbXlkYXRhID0gbXlkYXRhW215ZGF0YSRNWUZVWlpZU0VUICE9IDAuNSxdCmBgYAoKSW4gc3VtbWFyeSwgaGVyZSdzIGEgdGVtcGxhdGUgY29kZSBmb3Igd2hhdCB5b3UgY291bGQgdXNlIGFzIGEgc3RhbmRhcmQgcHJvY2VkdXJlIHdoZW4gY2FsaWJyYXRpbmcgYSBmdXp6eSBzZXQgdXNpbmcgdGhlIGRpcmVjdCBjYWxpYnJhdGlvbiBtZXRob2Q6CgpgYGAKIyBkZXNjcmlwdGl2ZSBzdGF0aXN0aWNzCmRlc2NyaWJlKG15ZGF0YSR2YXIpCgojIGNoZWNrIGZvciBtaXNzaW5ncyAoJSBvZiBjYXNlcyB3aXRoIG1pc3NpbmdzKSAKdmFybWlzcyA8LSBhcy5udW1lcmljKGlzLm5hKG15ZGF0YSR2YXIpKSBwcm9wLnRhYmxlKHRhYmxlKHZhcm1pc3MpKQoKIyBjYWxpYnJhdGlvbiAoZnV6enkgc2V0LCBkaXJlY3QgY2FsaWJyYXRpb24gbWV0aG9kLCByb3VuZGVkIHRvIDIgZGlnaXRzKSAKbXlkYXRhJE1ZRlVaWllTRVQgPC0gcm91bmQoY2FsaWJyYXRlKG15ZGF0YSR2YXIsIHR5cGUgPSAiZnV6enkiLCB0aHJlc2hvbGRzID0gImU9MSwgYz0yLjUsIGk9NCIsIGxvZ2lzdGljID0gVFJVRSksIGRpZ2l0cz0yKQoKIyBOdW1iZXIgb2YgY2FzZXMgb24gdGhlIGNyb3Nzb3ZlciBwb2ludCAKY2hlY2tNWVNFVCA8LSBhcy5udW1lcmljKG15ZGF0YSRNWVNFVCA9PSAwLjUpIApzdW0oY2hlY2tNWVNFVCkKCiMgY2hlY2sgZm9yIHNrZXduZXNzICglIG9mIGNhc2VzIHdpdGggbWVtYmVyc2hpcCA+IDAuNSkgCnNrZXdNWVNFVCA8LSBhcy5udW1lcmljKG15ZGF0YSRNWVNFVCA+IDAuNSkKcHJvcC50YWJsZSh0YWJsZShza2V3TVlTRVQpKQoKIyB2aXN1YWxpemUgY2FsaWJyYXRpb24KcGxvdChteWRhdGEkdmFyLCBteWRhdGEkTVlTRVQsIHBjaD0xOCwgY29sPSJibGFjayIsCiAgbWFpbj0nTVlTRVQnLCAKICB4bGFiPScgUmF3IHNjb3JlICcsCiAgeWxhYj0nIEZ1enp5IHNjb3JlICcpCmFibGluZShoPTAuNSwgY29sPSJibGFjayIpIAphYmxpbmUodj0gMjUsIGNvbD0iYmxhY2siKQpgYGAKCiMjIDQuMyBDYWxjdWxhdGluZyBtZW1iZXJzaGlwIGluIG9wZXJhdGlvbnMgb24gc2V0cwoKSWYgeW91IGNyZWF0ZSBhIG5ldyBzZXQgKGEgbmVnYXRlZCBzZXQsIGEgZGlzanVuY3Rpb24gb3IgYSBjb25qdW5jdGlvbiwgb3IgYSBjb21iaW5hdGlvbiBvZiB0aGVzZSksIHlvdSBtYXkgd2FudCB0byBzdG9yZSBpdCBhcyBhbiBvYmplY3QgKE5FV1NFVCA8LSBvcGVyYXRpb24pLCBzbyB0aGF0IHlvdSBjYW4gdXNlIGl0IGZvciBmdXJ0aGVyIGFuYWx5c2lzLiBZb3UgY2FuIGFsc28gKGJ1dCBkb27igJl0IGhhdmUgdG8pIHRpZSBpdCB0byB0aGUgZGF0YXNldCBieSB1c2luZyB0aGUgZG9sbGFyIHNpZ24gKG15ZGF0YSRORVdTRVQgPC0gb3BlcmF0aW9uKSwgc28gdGhhdCBpdCBhcHBlYXJzIGFzIGEgbmV3IHZhcmlhYmxlIGluIHRoZSBkYXRhc2V0LgpZb3UgaGF2ZSBzZXZlcmFsIG9wdGlvbnMgdG8gY2FsY3VsYXRlIHRoZSBjYXNlc+KAmSBtZW1iZXJzaGlwIGluIGNvbWJpbmVkIHNldHMuCgojIyMjIEEuIEF1dG9tYXRpY2FsbHksIHVzaW5nIGNvbXB1dGUoKQoKVGhlIGNvbXB1dGUoKSBjb21tYW5kIGFsbG93cyB5b3UgdG8gZGlyZWN0bHkgY2FsY3VsYXRlIHRoZSBtZW1iZXJzaGlwIGluIGFueSBleHByZXNzaW9uIHlvdSB3aXNoIHRvIGluZGljYXRlLCBlLmcuIGluIHRydXRoIHRhYmxlIHJvd3Mgb3IgdGhlIHNvbHV0aW9uIHRlcm0uIFlvdSBjYW4gdXNlIGVpdGhlciB0aGUgdGlsZGUgfiBzaWduIG9yIGxvd2VyY2FzZSBub3RhdGlvbiB0byBuZWdhdGUgc2V0cywgYnV0IGJlIGNvbnNpc3RlbnQuIFlvdSBjYW4gYWxzbyBza2lwIHRoZSAnKicgc2lnbiBpZiB5b3UgcHJlZmVyLiBCZWxvdyB3ZSBjYWxjdWxhdGUgdGhlIGNhc2Vz4oCZIG1lbWJlcnNoaXAgaW4gdGhlIHNldCBgc2V0MSpTRVQyICsgc2V0MypTRVQ0KnNldDUgKyBTRVQ2YCBhbmQgc3RvcmUgdGhlIHZhbHVlcyBhcyBhbiBvYmplY3Qg4oCcc29s4oCdIGZvciBmdXJ0aGVyIHVzZS4gCgpgYGB7cn0KIyB1c2UgdGhlIGNyaXNwIHNldCBmb3IgdGhlc2Ugb3BlcmF0aW9ucwpteWRhdGEgPC0gTEYKYGBgCgpUaGlzIGlzIGRpcmVjdGx5IGZyb20gdGhlIGhlbHAgdGV4dDoKCmBgYHtyfQpjb21wdXRlKCJERVYqaW5kICsgVVJCKlNUQiIsIGRhdGEgPSBMRikKYGBgCgpgYGAKc29sIDwtIGNvbXB1dGUoIm15c2V0MSpNWVNFVDIgKyBteXNldDMqTVlTRVQ0Km15c2V0NSArIE1ZU0VUNiIsIGRhdGE9bXlkYXRhKQpgYGAKCiMjIyMgQi4gVmlhIGxvZ2ljYWwgb3BlcmF0b3JzCgpUbyBjYWxjdWxhdGUgdGhlIGNhc2Vz4oCZIG1lbWJlcnNoaXAgaW4gYSBuZWdhdGVkIHNldCwgeW91IGNhbiBzaW1wbHkgc3VidHJhY3QgdGhlIHNldCBmcm9tIDE6CgpgYGB7cn0KbXlkYXRhJGRldiA8LSAxLW15ZGF0YSRERVYKbXlkYXRhJERFVgpteWRhdGEkZGV2CmBgYApOb3RlIHRoZSB1c2Ugb2YgY2FwaXRhbHMgYW5kIHNtYWxsIGxldHRlcnMuIFRoaXMgd2F5LCB5b3UgY2FuIGFsc28gZGlyZWN0bHkgbmVnYXRlIHRoZSBzZXQgd2l0aGluIGEgZGlmZmVyZW50IGNvbW1hbmQsIHdpdGhvdXQgcHJldmlvdXNseSBjcmVhdGluZyB0aGUgbmVnYXRlZCBzZXQgYXMgYSBzZXBhcmF0ZSBvYmplY3QuIFdlIGRvIHRoaXMgaGVyZToKCmBgYHtyfQpwYXRoMSA8LSBmdXp6eWFuZChteWRhdGEkREVWLCBteWRhdGEkVVJCLCAxLW15ZGF0YSRMSVQpCnBhdGgxCmBgYAoKSW4gdGhlIHR1dG9yaWFsLCB3ZSBzZWVtIHRvIG1pc3MgY29tcHV0YXRpb24gb2YgcGF0aDIsIGJ1dCB0aGUgbG9naWNhbCB1bmlvbiBjYW4gYWxzbyBiZSBzaG93biB3aXRoIG90aGVyIHNldHM6CgpgYGB7cn0KbXl1bmlvbiA8LSBmdXp6eW9yKG15ZGF0YSRERVYsIG15ZGF0YSRVUkIpCm15dW5pb24KYGBgCgpUaGlzIGFsc28gd29ya3Mgb24gY3Jpc3Agc2V0cywgd2hpY2ggc2hvdWxkIGJlIGVhc2llciB0byBmb2xsb3c6CgpgYGB7cn0KIyB1c2UgdGhlIGNyaXNwIHNldCBmb3IgdGhlc2Ugb3BlcmF0aW9ucwpteWRhdGEgPC0gTEMKIyBjYWxjdWxhdGUgbmVnYXRlZCBzZXQKbXlkYXRhJGRldiA8LSAxLW15ZGF0YSRERVYKbXlkYXRhJERFVgpteWRhdGEkZGV2CmBgYAoKRnV6enkgQU5EOgpgYGB7cn0KbXlkYXRhJERFVgpteWRhdGEkVVJCCmZ1enp5YW5kKG15ZGF0YSRERVYsIG15ZGF0YSRVUkIpCmBgYAoKQSBtb3JlIGNvbXBsZXggQU5ELCBpbmNsdWRpbmcgYSBuZWdhdGVkIHNldCBvbiB0aGUgZmx5OgoKYGBge3J9CnBhdGgxIDwtIGZ1enp5YW5kKG15ZGF0YSRERVYsIG15ZGF0YSRVUkIsIDEtbXlkYXRhJFNUQikKcGF0aDEKYGBgCgpMb2dpY2FsIE9SOiAKYGBge3J9Cm15dW5pb24gPC0gZnV6enlvcihteWRhdGEkREVWLCBteWRhdGEkVVJCKQpteWRhdGEkREVWCm15ZGF0YSRVUkIKbXl1bmlvbgpgYGAKCihzb21lIGNvbnRlbnQgc2tpcHBlZCB3aGljaCByZXF1aXJlcyBtb3JlIHVuZGVyc3RhbmRpbmcgb2YgbWV0aG9kKQoKIyBDaGFwdGVyIDUuIFhZLVBsb3RzCgpUaGVzZSBhcmUgcGxvdHMgb2YgYSBjb25kaXRpb24gYWdhaW5zdCB0aGUgb3V0Y29tZS4gWW91IGhhdmUgZm91ciBjb21tYW5kcyBhdCBkaXNwb3NhbCB0byBwcm9kdWNlIHh5LXBsb3RzIHdpdGggUi4gRm9yIFFDQSwgd2Ugd2lsbCB1c3VhbGx5IHdvcmsgd2l0aCBlaXRoZXIgeHkucGxvdCgpIChmb3IgcGxvdHRpbmcgc2luZ2xlIGNvbmRpdGlvbnMgb3IgY3VzdG9taXplZCBwcmVkZWZpbmVkIHNldHM7IFhZcGxvdCgpIGZyb20gdGhlIFFDQSBwYWNrYWdlIGVxdWFsbHkgd29ya3MpIG9yIHBpbXBsb3QoKSAoZm9yIHBsb3R0aW5nIHRoZSBzb2x1dGlvbiB0ZXJtKS4KCiMjIyMgMS4geHkucGxvdCAocGFja2FnZSBTZXRNZXRob2RzKQoKYGBge3J9CiBteWRhdGEgPC0gTEYKYGBgCkZpcnN0IHBsb3Q6CgpgYGB7cn0KeHkucGxvdCgiREVWIiwgIlNVUlYiLCBkYXRhID0gbXlkYXRhLCBsYWJzID0gcm93bmFtZXMobXlkYXRhKSwgbmVjZXNzaXR5PVRSVUUsIAogICAgICAgIGppdHRlciA9IFRSVUUsIG1haW4gPSAiREVWIGFzIG5lY2Vzc2FyeSBmb3IgU1VSViIsIHhsYWIgPSAiREVWIiwgeWxhYiA9ICJTVVJWIikKYGBgCgpJdCBhbHNvIGF1dG9tYXRpY2FsbHkgaW50ZWdyYXRlcyAgbGluZXMgZm9yIHRoZSBxdWFkcmFudHMsIGFuZCBhIGJsYWNrIGRpYWdvbmFsOyBhbmQgaXQgaW5kaWNhdGVzIHRoZSBwYXJhbWV0ZXJzIG9mIGZpdCAoY29uc2lzdGVuY3ksIGNvdmVyYWdlLCBQUkkgb3IgUm9OKSwgd2hpY2ggY2FuIGJlIHNldCB0byBuZWNlc3NpdHkgKG5lY2Vzc2l0eT1UUlVFKSBvciBzdWZmaWNpZW5jeSAoc2tpcCB0aGUgbmVjZXNzaXR5IG9wdGlvbiBvciBzZXQgbmVjZXNzaXR5PUZBTFNFKS4gVXNlIOKAnDEtIOKAnGZvciBuZWdhdGluZyBzZXRzLCBmb3IgZXhhbXBsZSAxLW15ZGF0YSRteXkuIFRoaXMgcGxvdCBhbHNvIGluZGljYXRlcyB5b3UgSGFlc2Vicm91Y2vigJlzIGNvbnNpc3RlbmN5IHZhbHVlLCBpbiBhZGRpdGlvbiB0byB0aGUgb3RoZXIgcGFyYW1ldGVycyBvZiBmaXQgKHNlZSBIYWVzZWJyb3VjayAyMDE1KS4gV2hhdCB0aGVzZSB2YWx1ZXMgbWVhbiB3aWxsIGJlIGV4cGxhaW5lZCBpbiAgQ2hwLiA2LiAKClRoZSByZWxhdGlvbiBhYm92ZSBpcyBub3Qgb2YgYSBraW5kIHRoYXQgIHN1Z2dlc3RzIGFuIGluZmx1ZW5jZSBvZiBERVYgIG9uIFNVSVJWLiBMZXQncyB0cnkgYW5vdGhlciAgcmVsYXRpb246CgpgYGB7cn0KeHkucGxvdCgiTElUIiwgIlNVUlYiLCBkYXRhID0gbXlkYXRhLCBsYWJzID0gcm93bmFtZXMobXlkYXRhKSwgbmVjZXNzaXR5PVRSVUUsIAogICAgICAgIGppdHRlciA9IFRSVUUsIG1haW4gPSAiTElUIGFzIG5lY2Vzc2FyeSBmb3IgU1VSViIsIHhsYWIgPSAiTElUIiwgeWxhYiA9ICJTVVJWIikKYGBgCkhlcmUgd2Ugc2VlIGEgbXVjaCBtb3JlIAo+IE1vcmUgZ3JhcGhpYyBmdW5jdGlvbnMgYWZ0ZXIgd2UgY292ZXJlZCBzdWZmaWNpZW5jeSBhbmQgbmVjZXNzaXR5LgoKIyBDaGFwdGVyIDYuIEFuYWx5c2lzIG9mIG5lY2Vzc2l0eQoKClNlZSBmaWxlIER1c2EyMDE5LWNocDUtbmVjZXNzaXR5LlJtZCBmb3IgbW9yZSBjb25jZXB0dWFsIGV4cGxhbmF0aW9ucy4gCgoKSWYgeW91IHdhbnQgdG8g4oCcZGVkdWN0aXZlbHnigJ0gdGVzdCB0aGUgbmVjZXNzaXR5IGZvciBzaW5nbGUgbmVjZXNzYXJ5IGNvbmRpdGlvbnMgb3IgdGhlb3JldGljYWxseSBkZWZpbmVkIGRpc2p1bmN0aW9ucyByZXByZXNlbnRpbmcgaGlnaGVyLW9yZGVyIGNvbnN0cnVjdHMsIHRoZSBwb2YgY29tbWFuZCAocGFja2FnZTogUUNBKSBjYW4gYmUgdXNlZCBpZiB0aGUgb3B0aW9uIHJlbGF0aW9uID0gIm5lYyIgaXMgc2V0IChpZiBpdCBpcyBzZXQgdG8gInN1ZiIsIHRoZW4gdGhlIGNvbW1hbmQgdGVzdHMgZm9yIHRoZSBzdWZmaWNpZW5jeSBvZiB0aGUgbGlzdGVkIGNvbmRpdGlvbnMpLiBJZiB5b3Ugd2FudCB0byB0ZXN0IGZvciBzZXZlcmFsIGNvbmRpdGlvbnMsIGNyZWF0ZSB0aGUgbGlzdCB0aGUgY29uZGl0aW9ucyBmb3Igd2hpY2ggeW91IHdhbnQgdG8gdGVzdCBmaXJzdC4gRm9yIG5lZ2F0aW5nIGNvbmRpdGlvbnMgb3IgdGhlIG91dGNvbWUsIHVzZSBlaXRoZXIgYSB0aWxkZSBvciAxLS4gVGhpcyBjb21tYW5kIGdpdmVzIHlvdSB0aGUgY29uc2lzdGVuY3ksIGNvdmVyYWdlIGFuZCByZWxldmFuY2UgKFJvTikgb2YgbmVjZXNzaXR5IGZvciBlYWNoIGxpc3RlZCBjb25kaXRpb24uIDggSW4gdGhlIGV4YW1wbGUgYmVsb3csIHdlIHRlc3QgdGhlIG5lY2Vzc2l0eSBvZiBjb25kaXRpb25zIDEsIDIsIGFuZCAzIGZvciB0aGUgbmVnYXRlZCBvdXRjb21lLgoKYGBge3J9Cm15ZGF0YSA8LSBMRgpgYGAKClN1YnNldHRpbmcgb24gdGhyZWUgY29uZGl0aW9uczoKCmBgYHtyIGVjaG89VFJVRX0KY29uZHMgPC0gc3Vic2V0KG15ZGF0YSwgc2VsZWN0ID0gYygiREVWIiwgIlVSQiIsICJMSVQiKSkKYGBgCgpUZXN0aW5nIG5lY2Vzc2l0eSBmb3Igb3V0Y29tZSB+U1VSViAod2hpY2gsIHJlbWVtYmVyLCBpcyBub3Qgc3ltbWV0cmljYWwgdG8gdGhlIG91dGNvbWUgU1VSVik6CmBgYHtyfQpwb2YoY29uZHMsICd+U1VSVicsIG15ZGF0YSwgcmVsYXRpb24gPSAibmVjIikKYGBgCkZvciBzb21lIHJlYXNvbiB0aGlzIGZ1bmN0aW9uIHJldHVybnMgdGhlIGRhdGEgZmlyc3QsIHdoaWNoIGlzIGFubm95aW5nLiBJdCBjYW4gYmUgY2hhbmdlZCBieSB1c2luZyAkIG5vdGF0aW9uIHRvIGdldCBkYXRhIGZyYW1lcyBmb3IgdGhlIGNvbmRzLCBzZWUgbmV4dCBleGFtcGxlLiBJIHRoaW5rIHRoYXQgdGhlIGV4YW1wbGUgYWJvdmUgaXMgbm90IGZ1bGx5IGNvcnJlY3QgZm9yIHRoZSBjdXJyZW50IGltcGxlbWVudGF0aW9uIG9mIHBvZigpLiAKCj4gQWRkIGFuIGludGVycHJldGF0aW9uIG9mIHdoYXQgdGhpcyBtZWFucy4gIAoKWW91IGNhbiBhbHNvIHVzZSB0aGlzIGNvbW1hbmQgZm9yIHRlc3RpbmcgdGhlIG5lY2Vzc2l0eSBvZiBvbmx5IG9uZSBjb25kaXRpb24gKGluIHBvc2l0aW9uIG9uZSwgREVWKS4gKE5vdGUgdGhhdCB0aGUgZXhwcmVzc2lvbiBhcyBpbmRpY2F0ZWQgb24gcC4zNywgd2hpY2ggb25seSB3b3VsZCBzdWdnZXN0IHRvIHB1dCBERVYgaW4gcG9zaXRpb24gMSBkb2VzIHRocm93IGFuIGVycm9yLikgCgpgYGB7cn0KcG9mKG15ZGF0YSRERVYsICd+U1VSVicsIG15ZGF0YSwgcmVsYXRpb24gPSAibmVjIikKYGBgCllvdSBjYW4gYWxzbyB1c2UgcG9mKCkgZm9yIGNvbXBsZXggY29uZGl0aW9uIHNldHMuIFlvdSBjYW4gdXNlIGVpdGhlciBsb3dlcmNhc2Ugbm90YXRpb24gb3IgdGlsZGVzIHRvIG5lZ2F0ZSBjb25kaXRpb25zLiBGb3IgZXhhbXBsZSwgd2Ugd2FudCB0byBrbm93IHdoZXRoZXIgdGhlIGNvbmRpdGlvbiDigJxDT05EMSArIGNvbmQyKkNPTkQz4oCdIGlzIG5lY2Vzc2FyeSAoPD0pIGZvciB0aGUgb3V0Y29tZToKCmBgYHtyfQpwb2YoIkRFViArIGxpdCpJTkQgPD0gU1VSViIsIGRhdGEgPSBteWRhdGEpCmBgYAoKQnkgdXNpbmcgPT4sIHlvdSBjYW4gdGVzdCB0aGUgc2FtZSBmb3Igc3VmZmljaWVuY3kuCgpZb3UgY2FuIGFsc28gbWFrZSBhbiBYWSBwbG90IHRoYXQgaW50ZWdyYXRlcyB0aGUgcGFyYW1ldGVycyBvZiBmaXQuIFRoaXMgY2FuIGJlIGRvbmUgZm9yIG5lY2Vzc2l0eSAobmVjZXNzaXR5PVRSVUUpLCBidXQgYWxzbyBmb3Igc3VmZmljaWVuY3kgKG5lY2Vzc2l0eT1GQUxTRSkuIFRoaXMgaGFzIHRoZSBhZHZhbnRhZ2UgdGhhdCB5b3UgY2FuIG1ha2UgYSB2aXN1YWwgZGlhZ25vc3RpYyBvZiBjb250cmFkaWN0b3J5IGNhc2VzIChpbiB0aGUgdXBwZXIgbGVmdCBxdWFkcmFudCkgYW5kIHRyaXZpYWxuZXNzLiBXZSBoYXZlIGRvbmUgdGhpcyBiZWZvcmUsIGJ1dCBoZXJlIGFnYWluIGZvciBlYXNlIG9mIHJlZmVyZW5jZToKCmBgYHtyfQp4eS5wbG90KCJERVYiLCAiU1VSViIsIGRhdGEgPSBteWRhdGEsIG5lY2Vzc2l0eT1UUlVFKQpgYGAKCiMjIDYuMiBTdXBlclN1YnNldCBwcm9jZWR1cmUKClRoZSBgc3VwZXJTdWJzZXQoKWAgY29tbWFuZCAocGFja2FnZTogUUNBKSDigJxpbmR1Y3RpdmVseeKAnSBpZGVudGlmaWVzIGFsbCBzdXBlcnNldHMgb2YgdGhlIG91dGNvbWUsIGJvdGggc2luZ2xlIGNvbmRpdGlvbnMsIGNvbmp1bmN0aW9ucyBhbmQgZGlzanVuY3Rpb25zICh1bmlvbnMpIG9mIHNldHMuIFNvIHVzaW5nIHRoaXMgY29tbWFuZCwgeW91IGNhbiBiYXNpY2FsbHkgc2tpcCB0aGUgc3RlcHMgZGVzY3JpYmVkIGluIDYuMS4gVGhlIG9wdGlvbiBgaW5jbC5jdXRgIHNlcnZlcyB0byBzcGVjaWZ5IGEgbWluaW1hbCBjb25zaXN0ZW5jeSB0aHJlc2hvbGQgdGhhdCB0aGUgY29uZGl0aW9ucyBuZWVkIHRvIHBhc3MgKGZvciBmdXp6eSBzZXRzLCB1c3VhbGx5IDAuOTsgdHlwaWNhbGx5IDEuMCBmb3IgY3Jpc3Agc2V0cykuIFVzaW5nIGBjb3YuY3V0YCwgeW91IGNhbiBhbHNvIHNwZWNpZnkgYSBjb3ZlcmFnZSBjdXRvZmYgKGhlcmU6IDAuNiksIGJlbG93IHdoaWNoIHRoZSBuZWNlc3NhcnkgY29uZGl0aW9ucyBhbmQgYXJlIGRlZW1lZCB0cml2aWFsIGFuZCB3aWxsIG5vdCBhcHBlYXIgaW4gdGhlIGxpc3QuIFVzZSBhIHRpbGRlIH4gdG8gbmVnYXRlIHRoZSBvdXRjb21lLCBlLmcuIG91dGNvbWUgPSAifk9VVENPTUUiLgoKYGBge3J9CnN1cGVyU3Vic2V0KG15ZGF0YSwgb3V0Y29tZSA9ICJTVVJWIiwKICBjb25kaXRpb25zID0gIkRFViwgVVJCLCBMSVQsIElORCwgU1RCIiwKICBpbmNsLmN1dCA9IDAuOSwgY292LmN1dCA9IDAuNikKYGBgClRoaXMgY29tbWFuZCB3aWxsIGdpdmUgeW91IGEgbG90IG9mIHN1cGVyc2V0cywgYnV0IHRvIGRlY2lkZSB3aGV0aGVyIHRoZXkgY2FuIGJlIGRlZW1lZCBuZWNlc3NhcnksIHlvdSB3aWxsIHN0aWxsIGhhdmUgdG8gMSkgY2hlY2sgZm9yIGRldmlhbnQgY2FzZXMgY29uc2lzdGVuY3kgaW4ga2luZCAocGxvdCB0aGUgcmVzdWx0KSwgMikgY2hlY2sgZm9yIGVtcGlyaWNhbCByZWxldmFuY2UgLyB0cml2aWFsbmVzcyAoR29lcnR6IDIwMDYpLCBhbmQgMykgaWRlbnRpZnkgd2hldGhlciB0aGUgc3VwZXJzZXQgbWFrZXMgdGhlb3JldGljYWwgc2Vuc2UgYXMgYSBuZWNlc3NhcnkgY29uZGl0aW9uLCB0aGF0IGlzLCB3aGV0aGVyIHRoZSBzZXRzIGNvbWJpbmVkIHdpdGggdGhlIGxvZ2ljYWwgT1IgcmVwcmVzZW50IHNvbWUgaGlnaGVyLW9yZGVyIGNvbmNlcHQgKHNlZSBTY2huZWlkZXIgYW5kIFdhZ2VtYW5uIDIwMTIpLiBOb3RlIGFsc28gdGhhdCB0aGUgZGlmZmVyZW50IHN1cGVyc2V0cyBwcm9kdWNlZCBieSB0aGlzIGNvbW1hbmQgYXJlIGFsdGVybmF0aXZlcyB0byBlYWNoIG90aGVyOiBmb3IgZXhhbXBsZSwgaWYgYEEqQmAgaXMgbmVjZXNzYXJ5LCBpbiB0aGUgb3V0cHV0IHlvdSB3aWxsIGZpbmQgYEEqQmAsIGJ1dCBhbHNvIEEsIGFuZCBhbHNvIEIuIEluIHN1bW1hcnksIHRoaXMgY29tbWFuZCBpcyB1c2VmdWwgYmVjYXVzZSBpdCBnaXZlcyB5b3UgYWxsIHBvdGVudGlhbCBuZWNlc3NhcnkgY29uZGl0aW9ucyBpbiBvbmUgZ287IGJ1dCBkbyBub3QgdXNlIGl0IGZvciBtaW5kbGVzcyBkYXRhLW1pbmluZy4KCklmIHlvdSBzdG9yZSB0aGUgcmVzdWx0cyBvZiBzdXBlclN1YnNldCgpIGFzIGFuIG9iamVjdCAoaGVyZTogbmVjKSwgeW91IGNhbiBwbG90IGFsbCBjb21wb3VuZCBuZWNlc3NhcnkgY29uZGl0aW9ucyBieSB1c2luZyBwaW1wbG90KCk6CgpgYGB7ciBjMTQxfQpuZWMgPC0gc3VwZXJTdWJzZXQobXlkYXRhLCBvdXRjb21lID0gIlNVUlYiLAogIGNvbmRpdGlvbnMgPSAiREVWLCBVUkIsIExJVCwgSU5ELCBTVEIiLAogIGluY2wuY3V0ID0gMC45LCBjb3YuY3V0ID0gMC42KQoKcGltcGxvdChkYXRhPW15ZGF0YSwgcmVzdWx0cz1uZWMsIG91dGNvbWU9IlNVUlYiLCBuZWNlc3NpdHk9VFJVRSwgCiAgICAgICAgYWxsX2xhYmVscz1UUlVFLCBqaXR0ZXI9VFJVRSkKYGBgCgpVc2UgdGhlIGJhY2t3YXJkIGFycm93IGFib3ZlIHRoZSBwbG90IHdpbmRvdyB0byB2aWV3IGFsbCBwbG90cy4gVGhlIGxhdHRlciBhbHNvIGluZGljYXRlIGFsbCBwYXJhbWV0ZXJzIG9mIGZpdCAoaW5jbHVkaW5nIFJvTikgYW5kIHRoZSBjYXNlcyB3aXRoIG1lbWJlcnNoaXAgPiAwLjUgaW4gdGhlIG91dGNvbWUgYXJlIGxhYmVsbGVkLiAKCiMgQ2hhcHRlciA3IEFuYWx5c2lzIG9mIHN1ZmZpY2llbmN5CgojIyBUZXN0aW5nIGZvciBzaW5nbGUgc3VmZmljaWVudCBjb25kaXRpb25zCgpXaGlsZSB0aGUgUUNBIHRlY2huaXF1ZSBhbHdheXMgdXNlcyB0aGUgdHJ1dGggdGFibGUgcHJvY2VkdXJlIGZvciB0aGUgYW5hbHlzaXMgb2Ygc3VmZmljaWVuY3ksIGluIHByaW5jaXBsZSB0aGUgc3VmZmljaWVuY3kgKGNvbnNpc3RlbmN5LCBjb3ZlcmFnZSBhbmQgUFJJKSBvZiBzaW5nbGUgY29uZGl0aW9ucyBjYW4gYWxzbyBiZSAo4oCcZGVkdWN0aXZlbHnigJ0pIHRlc3RlZCB1c2luZyB0aGUgcG9mKCkgY29tbWFuZCBvZiB0aGUgUUNBIHBhY2thZ2UgKGp1c3Qgc3BlY2lmeSByZWxhdGlvbiA9ICJzdWYiKSwgYW5kIHZpc3VhbGl6ZWQgdXNpbmcsIGZvciBpbnN0YW5jZSwgdGhlIHh5LnBsb3QoKSBjb21tYW5kIChhZ2Fpbiwgc3BlY2lmeSBuZWNlc3NpdHk9RkFMU0UpIChzZWUgc2VjdGlvbiA2LjEpLiBBbHRlcm5hdGl2ZWx5LCB5b3UgY2FuIHVzZSBRQ0FmaXQoKSBvZiB0aGUgU2V0TWV0aG9kcyBwYWNrYWdlICh3aGljaCBhZGRpdGlvbmFsbHkgZ2l2ZXMgeW91IHRoZSBIYWVzZWJyb3VjayBjb25zaXN0ZW5jeSBhbmQgYWxzbyB3b3JrcyBmb3IgbmVjZXNzaXR5LCBzcGVjaWZ5IG5lY2Vzc2l0eT1UUlVFKS4gWW91IGNhbiBuZWdhdGUgdGhlIG91dGNvbWUgYnkgc3BlY2lmeWluZyBuZWcub3V0PVRSVUUuIElmIHlvdSBkb27igJl0IHdhbnQgdG8gbGFiZWwgeW91ciBjb25kaXRpb24sIHNraXAgY29uZC5sYWI9ICJDT05EIi4KCmBgYHtyIGMxNDJ9ClFDQWZpdChMRiRTVEIsIExGJFNVUlYsIGNvbmQubGFiPSAiU1RCIiwgbmVjZXNzaXR5PUZBTFNFLCBuZWcub3V0PUZBTFNFKQpgYGAKWW91IGNhbiBhbHNvIGRvIHRoaXMgZm9yIHNldmVyYWwgY29uZGl0aW9ucyBhdCBvbmNlLiBKdXN0IGJ1aWxkIGFuIG9iamVjdCAoaGVyZTogY29uZHMpIGZpcnN0IHRoYXQgY29udGFpbnMgeW91ciBjb25kaXRpb25zLgoKYGBge3IgYzE0M30KY29uZHMgPC0gc3Vic2V0KExGLCBzZWxlY3QgPSBjKCJERVYiLCAiVVJCIiwgIkxJVCIpKQpRQ0FmaXQoY29uZHMsIExGJFNVUlYsIGNvbmQubGFiPSBjKCJERVYiLCAiVVJCIiwgIkxJVCIpLCBuZWNlc3NpdHk9RkFMU0UsIG5lZy5vdXQ9RkFMU0UpCmBgYAoKRm9yIGNvbWJpbmF0aW9ucyBvZiBjb25kaXRpb25zLCB3ZSBuZWVkIHRydXRoIHRhYmxlcwoKIyMgNy4yIEJ1aWxkaW5nIHRoZSB0cnV0aCB0YWJsZSBhbmQgbG9naWNhbCBtaW5pbWF6YXRpb24KClZlcnkgaW1wb3J0YW50OiB0aGUgemVyb3MgYW5kIG9uZXMgaW4gVFRzIGFyZSBub3QgdG8gYmUgY29uZnVzZWQgd2l0aCBjcmlzcCBzZXQgdmFsdWVzISBUaGUgemVyb3MgYW5kIG9uZXMgcmVmZXIgdG8gbG9naWNhbCBjb25kaXRpb25zLCBub3Qgc2V0IG1lbWJlcnNoaXAuIAoKRmlyc3QgeW91IHdhbnQgdG8gZmlndXJlIG91dCB3aGVyZSB0byBzZXQgdGhlIHJhdyBjb25zaXN0ZW5jeSB0aHJlc2hvbGQuIEZvciB0aGlzIHlvdSBjYW4gcHJvZHVjZSBhIGJhc2ljIHRydXRoIHRhYmxlLCB3aXRoIHJhdyBjb25zaXN0ZW5jaWVzIChzb3J0ZWQgYnkgZGVzY2VuZGluZykgYW5kIGluZGljYXRpbmcgaW5kaXZpZHVhbCBjYXNlcyAocGFja2FnZTogUUNBKS4KCmBgYHtyIGMxNDV9CnR0U1VSViA8LSB0cnV0aFRhYmxlKGRhdGE9TEYsIG91dGNvbWUgPSAiU1VSViIsIGNvbmRpdGlvbnMgPSAiREVWLCBVUkIsIExJVCwgSU5ELCBTVEIiLAogICAgICAgICAgICAgIGluY2wuY3V0PTEuMDAsIHNvcnQuYnk9ImluY2wsIG4iLCBjb21wbGV0ZT1GQUxTRSwgc2hvdy5jYXNlcz1UUlVFKSAKdHRTVVJWIApgYGAKRm9sbG9uZyB0aGlzIGFkdmlzZSB0byB0aGUgZ2VuZXJhbGx5IHJlY29tbWVuZGVkIG1pbmltYWwgaW5jbHVzaW9uIHNjb3JlICguOCksIHdlIGdldDogCgpgYGB7ciBjMTQ1YX0KdHRTVVJWIDwtIHRydXRoVGFibGUoZGF0YT1MRiwgb3V0Y29tZSA9ICJTVVJWIiwgY29uZGl0aW9ucyA9ICJERVYsIFVSQiwgTElULCBJTkQsIFNUQiIsCiAgICAgICAgICAgICAgaW5jbC5jdXQ9LjgwLCBzb3J0LmJ5PSJpbmNsLCBuIiwgY29tcGxldGU9RkFMU0UsIHNob3cuY2FzZXM9VFJVRSkgCnR0U1VSVgpgYGAKClRoZSB0cnV0aCB0YWJsZSBjb21tYW5kIHByb3ZpZGVzIHNldmVyYWwgb3B0aW9uczogCiogV2Ugc2V0IHRoZSByYXcgY29uc2lzdGVuY3kgdGhyZXNob2xkIHVzaW5nIGluY2wuY3V0LiBJZiB5b3Ugc2tpcCB0aGlzIG9wdGlvbiwgdGhlbiBhbGwgb3V0Y29tZXMgYXJlIGNvZGVkIDAgZXhjZXB0IGZvciByb3dzIHdpdGggY29uc2lzdGVuY3kgMS4gCiogbi5jdXQgaXMgdXNlZCB0byBzcGVjaWZ5IGEgZnJlcXVlbmN5IHRocmVzaG9sZCAoYnkgZGVmYXVsdDogMSkuIAoqIFRoZSBzb3J0LmJ5IG9wdGlvbiBjYW4gYmUgc2V0IHN1Y2ggdGhhdCB0aGUgcm93cyBhcmUgb3JkZXJlZCBieSByYXcgY29uc2lzdGVuY3kgKCJpbmNsIiksIG9yIGJ5IHRoZSBOICgibiIpLCBvciBieSBib3RoIChhcyBkb25lIGhlcmUpLiBXaXRoIGRlY3JlYXNpbmcgPSBGQUxTRSwgdGhlIHRydXRoIHRhYmxlIHJvd3Mgd291bGQgYmUgb3JkZXJlZCBpbiBhc2NlbmRpbmcgCihpbnN0ZWFkIG9mIGRlc2NlbmRpbmcpIG9yZGVyLCBlLmcuLCBieSBhc2NlbmRpbmcgcmF3IGNvbnNpc3RlbmNpZXMuCiogV2l0aCB0aGUgc2hvdy5jYXNlcyBvcHRpb24sIHdlIGNhbiBjaG9vc2Ugd2hldGhlciB3ZSB3YW50IHRvIGluZGljYXRlIHRoZSBzaW5nbGUgY2FzZXMgY29udGFpbmVkIGluIGEgdHJ1dGggdGFibGUgcm93IChUUlVFKSBvciBub3QgKEZBTFNFKS4gCiogSWYgdGhlIGNvbXBsZXRlIG9wdGlvbiBpcyBzZXQgdG8gVFJVRSwgdGhlbiBhbGwgbG9naWNhbCByZW1haW5kZXJzIGFyZSBhbHNvIGRpc3BsYXllZDsgaWYgRkFMU0UsIHRoZW4gb25seSBlbXBpcmljYWxseSBvYnNlcnZlZCB0cnV0aCB0YWJsZSByb3dzIGFyZSBkaXNwbGF5ZWQuIAoKVGhlIG5leHQgY29tbWFuZCBwcm9kdWNlcyB0aGUgdHJ1dGggdGFibGUgZnJvbSBjMTQ1YSBpbiB0aGUgJ3N0YW5kYXJkJyBmb3JtLCB3aXRoIGFsbCAzMiBwb3NzaWJsZSBjb21iaW5hdGlvbiBvZiB0aGUgY29uZGl0aW9uczogCgpgYGB7ciBjMTQ1Yn0KdHRTVVJWIDwtIHRydXRoVGFibGUoZGF0YT1MRiwgb3V0Y29tZSA9ICJTVVJWIiwgY29uZGl0aW9ucyA9ICJERVYsIFVSQiwgTElULCBJTkQsIFNUQiIsCiAgICAgICAgICAgICAgaW5jbC5jdXQ9LjgwLCBjb21wbGV0ZT1UUlVFLCBzaG93LmNhc2VzPVRSVUUpIAp0dFNVUlYKYGBgCgoKVGhlIGNvbW1hbmQgYmVsb3cgcHJvZHVjZXMgYSB0cnV0aCB0YWJsZSBmb3IgdGhlIG5lZ2F0ZWQgb3V0Y29tZSwgd2l0aCByYXcgY29uc2lzdGVuY3kgdGhyZXNob2xkIDAuODI4LCBmcmVxdWVuY3kgdGhyZXNob2xkIDEsIHNvcnRlZCBieSBkZXNjZW5kaW5nIHJhdyBjb25zaXN0ZW5jeSAoYW5kLCByYXcgY29uc2lzdGVuY3kgYmVpbmcgZXF1YWwsIGJ5IE4pLCBzaG93aW5nIG9ubHkgZW1waXJpY2FsbHkgb2JzZXJ2ZWQgcm93cywgYW5kIHNob3dpbmcgaW5kaXZpZHVhbCBjYXNlcy4gTm90ZSB0aGF0IHdlIHVzZWQgbG93ZXJjYXNlIGxldHRlcnMgaGVyZSBmb3IgbGFiZWxsaW5nIHRoZSB0cnV0aCB0YWJsZSBvYmplY3QgYmVjYXVzZSBpdCBhbmFseXplcyB0aGUgbmVnYXRlZCBvdXRjb21lLiBZb3Ugd2lsbCBrbm93IHRoYXQgdHRPVVRDT01FIGlzIHRoZSB0cnV0aCB0YWJsZSBmb3IgdGhlIHBvc2l0aXZlIG91dGNvbWUsIGFuZCB0dG91dGNvbWUsIGZvciB0aGUgbmVnYXRlZCBvdXRjb21lLgoKYGBge3IgYzE0Nn0KdHRzdXJ2IDwtIHRydXRoVGFibGUoTEYsIG91dGNvbWU9In5TVVJWIiwgY29uZGl0aW9ucyA9ICJERVYsIFVSQiwgTElULCBJTkQsIFNUQiIsCiAgICAgICAgICAgIGluY2wuY3V0PTAuODI4LCBuLmN1dD0xLCBzb3J0LmJ5PSJpbmNsLCBuIiwgZGVjcmVhc2luZz1UUlVFLCBjb21wbGV0ZT1GQUxTRSwgc2hvdy5jYXNlcz1UUlVFKQp0dHN1cnYKYGBgCgpUaGUgbWluaW1pemUoKSBjb21tYW5kIChwYWNrYWdlOiBRQ0EpIHBlcmZvcm1zIGxvZ2ljYWwgbWluaW1pemF0aW9uIG9mIHRoZSB0cnV0aCB0YWJsZSAoaS5lLiwgdGhlIG9iamVjdCB3ZSBjcmVhdGVkIHdpdGggdGhlIHRydXRoIHRhYmxlIGNvbW1hbmQsIGJlbG93OiB0dE9VVENPTUUpLiBGaXJzdCB3ZSBjYWxjdWxhdGUgdGhlICoqY29uc2VydmF0aXZlKiogc29sdXRpb24gYW5kIG9idGFpbiBhbGwgZGV0YWlscyAoY29uc2lzdGVuY3ksIHJhdyBhbmQgdW5pcXVlIGNvdmVyYWdlKS4gV2UgYWxzbyB3YW50IHRvIGRpc3BsYXkgdGhlIGNhc2VzIChzaG93LmNhc2VzKSBjb250YWluZWQgaW4gdGhlIHByaW1lIGltcGxpY2FudHMgKG9wdGlvbmFsKS4gVGhlIHVzZS50aWxkZSBvcHRpb24gY2FuIGJlIHNldCB0byBGQUxTRSBpZiB5b3UgcHJlZmVyIHVzaW5nIHVwcGVyY2FzZSBhbmQgbG93ZXJjYXNlIG5vdGF0aW9uIGZvciBzZXRzIGFuZCB0aGVpciBuZWdhdGlvbjsgYW5kIHRvIFRSVUUgaWYgeW91ciBwcmVmZXIgdG8gZGVub3RlIG5lZ2F0ZWQgc2V0cyB3aXRoIGEgdGlsZGUuIEl0IGNhbiBiZSBza2lwcGVkIGFuZCB0aGVuIHVwcGVyLS9sb3dlcmNhc2Ugbm90YXRpb24gaXMgdXNlZC4KCmBgYHtyIEMxNDd9CmNzU1VSViA8LSBtaW5pbWl6ZSh0dFNVUlYsIGRldGFpbHM9VFJVRSwgc2hvdy5jYXNlcz1UUlVFLCByb3cuZG9tPVRSVUUsIGFsbC5zb2w9RkFMU0UsIHVzZS50aWxkZT1GQUxTRSkKY3NTVVJWCmBgYApUbyBjYWxjdWxhdGUgdGhlICoqcGFyc2ltb25pb3VzKiogc29sdXRpb24sIHdlIHRlbGwgdGhlIHNvZnR3YXJlIHRvIGluY2x1ZGUgbG9naWNhbCByZW1haW5kZXJzICh0aG9zZSB3aXRoIG91dGNvbWUg4oCcP+KAnSkgcmVwcmVzZW50aW5nIHNpbXBsaWZ5aW5nIGFzc3VtcHRpb25zLgoKYGBge3J9CnBzU1VSViA8LSBtaW5pbWl6ZSh0dFNVUlYsIGluY2x1ZGU9Ij8iLCBkZXRhaWxzPVRSVUUsIHNob3cuY2FzZXM9VFJVRSwgcm93LmRvbT1UUlVFLCBhbGwuc29sPUZBTFNFKQpwc1NVUlYKYGBgCgojIyMgQm94IDc6IFVzZWZ1bCB0b29scyBmb3IgdHJ1dGggdGFibGUgYW5hbHlzaXMKCmBgYHtyfQpwc09VVENPTUUgPC0gcHNTVVJWCm15ZGF0YSA8LSBMRgpgYGAKCgpPbmNlIHlvdSBzZWUgdGhlIHRydXRoIHRhYmxlLCBpbiBvcmRlciB0byBmaW5kIHRoZSBhcHByb3ByaWF0ZSByYXcgY29uc2lzdGVuY3kgdGhyZXNob2xkLCB5b3UgbWF5IHdhbnQgdG8gcGxvdCBkaWZmZXJlbnQgdHJ1dGggdGFibGUgcm93cy4gWW91IGNhbiBwbG90IHRydXRoIHRhYmxlIHJvd3MgZWFzaWx5IHVzaW5nIHBpbXBsb3QoKSwgaW5jbHVkaW5nIHRoZSBuYW1lcyBvZiBjYXNlcyB3aXRoIG1lbWJlcnNoaXAgPiAwLjUgaW4gdGhlIHJvdyBhbmQgYWxsIHBhcmFtZXRlcnMgb2YgZml0IChjb25zaXN0ZW5jeSwgY292ZXJhZ2UsIFBSSSwgSGFlc2Vicm91Y2vigJlzIGNvbnNpc3RlbmN5KS4gSG93ZXZlciwgbm90ZSB0aGF0IHRoaXMgcmVxdWlyZXMgeW91IHRvIGFscmVhZHkgaGF2ZSBjYWxjdWxhdGVkIGEgc29sdXRpb24gd2hpY2ggeW91IHN0b3JlZCBhcyBhbiBvYmplY3QgKGhlcmU6IHBzT1VUQ09NRTsgeW91IGNvdWxkIHVzZSBhbnkgcmF3IGNvbnNpc3RlbmN5IHRvIGJlZ2luIHdpdGgsIGp1c3QgdG8gZ2V0IHN1Y2ggYSBwcm92aXNpb25hbCBzb2x1dGlvbiBvYmplY3QgdG8gd29yayB3aXRoKS4gSGVyZSB3ZSBwbG90IHRoZSB0cnV0aCB0YWJsZSByb3dzIG51bWJlciAxIGFuZCAyNi4gVXNlIHRoZSBiYWNrd2FyZCBhcnJvdyBhYm92ZSB0aGUgcGxvdCB3aW5kb3cgaW4gb3JkZXIgdG8gZ2V0IGluc3BlY3QgYWxsIHRoZSBkaWZmZXJlbnQgcGxvdHM6CgpgYGB7ciBjMTQ5fQpwaW1wbG90KGRhdGE9bXlkYXRhLCByZXN1bHRzPXBzT1VUQ09NRSwgdHRyb3dzPWMoIjEiLCAiNSIsICIzMiIpLCBvdXRjb21lPSAiU1VSViIpCmBgYApOb3RlIHRoYXQgdGhlIHJvd3MgbXVzdCBoYXZlIGF0IGxlYXN0IG9uZSBjYXNlIHRvIGdldCAgcGxvdHRlZC4gCgpZb3UgY2FuIGFsc28gc2ltcGx5IHBsb3QgYWxsIHRydXRoIHRhYmxlIHJvd3MgYWJvdmUgYSBjZXJ0YWluIHJhdyBjb25zaXN0ZW5jeSBsZXZlbCAoaGVyZTogMC44KSBhdCBvbmNlLiBUaGUgcmVzdWx0aW5nIHBsb3RzIGhhdmUgdGhlIHJvdyBudW1iZXIgYXMgbGFiZWwgb2YgdGhlIFggYXhpczoKCmBgYHtyIGMxNTB9CnBpbXBsb3QoZGF0YT1teWRhdGEsIHJlc3VsdHM9cHNPVVRDT01FLCBpbmNsLnR0PTAuOCwgb3V0Y29tZT0gIlNVUlYiKQpgYGAKCkFzc2Vzc2luZyB0aGUgY29uc2VxdWVuY2VzIG9mIHNldHRpbmcgYSBmcmVxdWVuY3kgdGhyZXNob2xkOiAKCklmIHlvdSBzZXQgYSBmcmVxdWVuY3kgdGhyZXNob2xkIG9mIG1vcmUgdGhhbiAxIGFuZCB5b3Ugd2FudCB0byBzZWUgd2hpY2ggcm93cyBhcmUgbm93IHRyZWF0ZWQgYXMgbG9naWNhbCByZW1haW5kZXJzIGJ5IGltcG9zaW5nIHN1Y2ggYSB0aHJlc2hvbGQsIHR5cGUKCmBgYAp0dG91dGNvbWUkZXhjbHVkZWQKYGBgCkV4cG9ydGluZyB0aGUgdHJ1dGggdGFibGUKCllvdSBjYW4gc2F2ZSB0aGUgdHJ1dGggdGFibGUgYXMgYSBjc3YgZmlsZS4gVGhpcyB3aWxsIG1ha2UgaXQgdmVyeSBlYXN5IHRvIHRoZW4gY29weS1wYXN0ZSB0aGUgdGFibGUgaW50byB5b3VyIHdvcmQgZmlsZSAoZS5nLiB0aGUgb25saW5lIGFwcGVuZGl4KS4KYGBgCndyaXRlLmNzdih0dE9VVENPTUUkdHQsICJteXR0LmNzdiIpCmBgYAoKIyMjIEJveCA4OiBEZWZhdWx0IHNldHRpbmdzIGZvciBsb2dpY2FsIG1pbmltaXphdGlvbgoKVGhlIGByb3cuZG9tYCBvcHRpb24gZm9yIGxvZ2ljYWwgbWluaW1pemF0aW9uLCBpZiBzZXQgdG8gVFJVRSwgaXMgdXNlZCB0byBmdXJ0aGVyIGVsaW1pbmF0ZSByZWR1bmRhbnQgcHJpbWUgaW1wbGljYW50cyB3aGVuIHNvbHZpbmcgdGhlIFBJIGNoYXJ0LCBhcHBseWluZyB0aGUgcHJpbmNpcGxlIG9mIHJvdyBkb21pbmFuY2U6IGlmIGEgcHJpbWUgaW1wbGljYW50IFggY292ZXJzIHRoZSBzYW1lIGNvbmZpZ3VyYXRpb25zIGFzIGFub3RoZXIgcHJpbWUgaW1wbGljYW50IFkgYW5kIGluIHRoZSBzYW1lIHRpbWUgY292ZXJzIG90aGVyIGNvbmZpZ3VyYXRpb25zIHdoaWNoIFkgZG9lcyBub3QgY292ZXIsIHRoZW4gWSBpcyByZWR1bmRhbnQgYW5kIGVsaW1pbmF0ZWQuIEJ5IHNldHRpbmcgYGFsbC5zb2w9VFJVRWAsIHlvdSBjYW4gZGVyaXZlIGFsbCBwb3NzaWJsZSBzb2x1dGlvbnMsIGlycmVzcGVjdGl2ZSBvZiB0aGUgbnVtYmVyIG9mIHByaW1lIGltcGxpY2FudHMuCgpUbyBvYnRhaW4gYSBzdWJzZXQgb2YgdGhlIHNvbHV0aW9uIHNwYWNlLCBzZXQgYHJvdy5kb209VFJVRWAgYW5kIGBhbGwuc29sPUZBTFNFYC4gVGhpcyBpcyB0aGUgZGVmYXVsdCBzZXR0aW5nIHRoYXQgdGhlIFFDQSBwYWNrYWdlIGltcGxlbWVudHMgaWYgeW91IGRvIG5vdCBzcGVjaWZ5IHRoZXNlIHR3byBvcHRpb25zIChhcyBkb25lIGhlcmUgaW4gdGhpcyBtYW51YWwpLiBDb252ZXJzZWx5LCBmb3IgcmV2ZWFsaW5nIHRoZSBmdWxsIGV4dGVudCBvZiBtb2RlbCBhbWJpZ3VpdHksIHNldCBgcm93LmRvbT1GQUxTRWAgYW5kIGBhbGwuc29sPVRSVUVgIChzZWUgQmF1bWdhcnRuZXIgMjAxNSBhbmQgQmF1bWdhcnRuZXIgYW5kIFRoaWVtIDIwMTUpLiBUaGUgdXNhZ2Ugb2YgYGFsbC5zb2wgPSBUUlVFYCBkb2VzIG5vdCByZXByZXNlbnQgdGhlIG9waW5pb24gb2YgdGhlIFFDQSBwYWNrYWdlIGF1dGhvciwgd2hlcmUgdGhlIGRlZmF1bHQgb3B0aW9uIGlzIEZBTFNFLgoKQnkgcHJlc2VudGluZyB0aGUgdGVtcGxhdGVzIHVzaW5nIHRoZSBkZWZhdWx0IG9wdGlvbnMsIHdlIGRvIG5vdCBpbnRlbmQgdG8gbWFrZSBhIHJlY29tbWVuZGF0aW9uLiBJdCBpcyBnb29kIHRvIGJlIGF3YXJlIG9mIHRoZSBmYWN0IHRoYXQgdGhlcmUgYXJlIG9mdGVuIG1hbnkgcG9zc2libGUgc29sdXRpb25zLCBhbmQgdGhhdCB5b3UgaGF2ZSBzZXZlcmFsIHBvc3NpYmlsaXRpZXMgaG93IHRvIGRlYWwgd2l0aCB0aGlzLgoKIyMgNy4zIFN0YW5kYXJkIEFuYWx5c2lzOiBTcGVjaWZ5aW5nIGRpcmVjdGlvbmFsIGV4cGVjdGF0aW9ucwoKPiBOb3RlLiBUaGlzIHNlY3Rpb24gbmVlZHMgZXhwbGFuYXRpb25zLiBXaGF0IGRvZXMgInN0YW5kYXJkIGFuYWxheXNpcyIgbWVhbj8gV2hhdCBhcmUgZGlyZWN0aW9uYWwgZXhwZWN0YXRpb25zPyAKClRvIGRlcml2ZSBhbiBpbnRlcm1lZGlhdGUgc29sdXRpb24gdXNpbmcgU3RhbmRhcmQgQW5hbHlzaXMgKFJhZ2luIDIwMDgpLCB3ZSBtYXkgd2FudCB0byBzcGVjaWZ5IGRpcmVjdGlvbmFsIGV4cGVjdGF0aW9ucy4gSnVzdCBsaWtlIHdpdGggdGhlIHBhcnNpbW9uaW91cyBzb2x1dGlvbiwgd2UgdGVsbCB0aGUgc29mdHdhcmUgdG8gaW5jbHVkZSBzaW1wbGlmeWluZyBhc3N1bXB0aW9uczsgYnV0IHRoZW4gd2Ugc3BlY2lmeSB0aGUgZGlyZWN0aW9uYWwgZXhwZWN0YXRpb25zIChkaXIuZXhwKSBmb3IgZWFjaCBjb25kaXRpb24gaW4gdGhlIHNhbWUgb3JkZXIgYXMgdGhlIGNvbmRpdGlvbnMgd2VyZSBsaXN0ZWQgd2hlbiBjcmVhdGluZyB0aGUgdHJ1dGggdGFibGUgKHNlZSBzZWN0aW9uIDcuMikuIEluIHRoZSBleGFtcGxlLCB3ZSBhc3N1bWUgdGhhdCBjb25kaXRpb24gMSBjb250cmlidXRlcyB0byB0aGUgb3V0Y29tZSB3aGVuIHByZXNlbnQgKDEpOyBjb25kaXRpb24gMiBjb250cmlidXRlcyB0byB0aGUgb3V0Y29tZSB3aGVuIGFic2VudCAoMCk7IGFuZCB3ZSBoYXZlIG5vIGRpcmVjdGlvbmFsIGV4cGVjdGF0aW9uICjigJwt4oCcKSBmb3IgY29uZGl0aW9uIDMuCgpgYGB7cn0KaXNTVVJWICA8LSBtaW5pbWl6ZSh0dFNVUlYsIGluY2x1ZGUgPSAiPyIsIGRldGFpbHM9VFJVRSwgc2hvdy5jYXNlcz1UUlVFLCByb3cuZG9tPVRSVUUsIAogICAgICAgICAgYWxsLnNvbD1GQUxTRSwgZGlyLmV4cCA9ICIxLCAwLCAtLCAwLCAxIikgCiMgTm90ZSB0aGF0IHlvdSBuZWVkIGFzIG1hbnkgZXhwZWN0YXRpb25zIGFzIHRoZXJlIGFyZSBjb25kaXRpb25zCmlzU1VSVgpgYGAKCiMjIDcuNCBFbmhhbmNlZCBTdGFuZGFyZCBBbmFseXNpczogRXhjbHVkaW5nIHRydXRoIHRhYmxlIHJvd3MKCldoZW4gZGVyaXZpbmcgYW4gaW50ZXJtZWRpYXRlIHNvbHV0aW9uIGFuZCBwZXJmb3JtaW5nIGFuIEVuaGFuY2VkIFN0YW5kYXJkIEFuYWx5c2lzLCB3ZSBtYXkgb3IgbWF5IG5vdCBzcGVjaWZ5IGRpcmVjdGlvbmFsIGV4cGVjdGF0aW9uczsgYnV0IGluIGFkZGl0aW9uLCB3ZSBleGNsdWRlIHRob3NlIHRydXRoIHRhYmxlIApyb3dzIGZyb20gdGhlIGFuYWx5c2lzIG9mIHN1ZmZpY2llbmN5IHRoYXQgYSkgZGlzcGxheSBhIG5lZ2F0ZWQgbmVjZXNzYXJ5IGNvbmRpdGlvbiBmb3IgdGhlIHNhbWUgb3V0Y29tZSwgYikgZGlzcGxheSBhIHN1ZmZpY2llbnQgY29uZGl0aW9uIGZvciB0aGUgbmVnYXRlZCBvdXRjb21lLCBvciBjKSBhcmUgbG9naWNhbGx5IGltcGxhdXNpYmxlICh0aGUg4oCccHJlZ25hbnQgbWFu4oCdKS4gWW91IGhhdmUgc2V2ZXJhbCBwb3NzaWJpbGl0aWVzIHRvIGRvIHRoaXMuIEluIHRoZSBydW5uaW5nIHRleHQsIHdlIGRpc2N1c3MgdHdvIG9mIHRoZW07IHNlZSBCb3ggMTAgZm9yIG1vcmUgb3B0aW9ucy4KCiMjIyA3LjQuMSBFeGNsdWRpbmcgdHJ1dGggdGFibGUgcm93cyBiZWZvcmUgbG9naWNhbCBtaW5pbWl6YXRpb24KCldlIGNhbiBidWlsZCBhIG5ldyB0cnV0aCB0YWJsZSB3aGVyZSB3ZSBzaW1wbHkgdGVsbCB0aGUgc29mdHdhcmUgdG8gY29kZSB0aG9zZSByb3dzIHdpdGggb3V0Y29tZSAwIHRoYXQgZGlzcGxheSBhIGNlcnRhaW4gY29uZmlndXJhdGlvbiBvZiBjb25kaXRpb25zIOKAkyB3ZSBjYW4gZG8gdGhpcyBvbmx5IGZvciBsb2dpY2FsIHJlbWFpbmRlcnMsIG9yIGZvciBhbGwgdHJ1dGggdGFibGUgcm93cywgd2hldGhlciB0aGV5IGFyZSBlbXBpcmljYWxseSBvYnNlcnZlZCBvciBsb2dpY2FsIHJlbWFpbmRlcnMuIFRoaXMgcG9zc2liaWxpdHkgaXMgYW4gZWFzeSBhbmQgdHJhbnNwYXJlbnQgd2F5IGlmIHlvdSB0aGluayB0aGF0IG5laXRoZXIgeW91ciBvYnNlcnZhdGlvbnMgbm9yIHlvdXIgc2ltcGxpZnlpbmcgYXNzdW1wdGlvbnMgc2hvdWxkIGNvbnRyYWRpY3QgcHJpb3IgZmluZGluZ3MgYW5kIC8gb3IgbG9naWMsIGFuZCB5b3Ugd2FudCB0byBzZWUgd2hhdCB5b3UgZGlkIHRvIHRoZSB0cnV0aCB0YWJsZSBiZWZvcmUgdHVybmluZyB0byBsb2dpY2FsIG1pbmltaXphdGlvbi4KCkluIGEgZmlyc3Qgc3RlcCwgd2UgYnVpbGQgdGhlIHRydXRoIHRhYmxlIChoZXJlOiBmb3IgdGhlIG5lZ2F0ZWQgb3V0Y29tZSBhbmQgZm9yIDUgY29uZGl0aW9ucykgdGhhdCBhbHNvIGRpc3BsYXlzIHRoZSBsb2dpY2FsIHJlbWFpbmRlcnMgKGNvbXBsZXRlPVRSVUUpOgoKYGBge3IgYzE1NX0KZXR0b3V0Y29tZSA8LSB0cnV0aFRhYmxlKExGLCBvdXRjb21lPSJ+U1VSViIsIGNvbmRpdGlvbnMgPSAiREVWLCBVUkIsIExJVCwgSU5ELCBTVEIiLAogICAgICAgICAgICAgIGluY2wuY3V0PTAuOCwgbi5jdXQ9MSwgc29ydC5ieT0iaW5jbCwgbiIsIGRlY3JlYXNpbmc9VFJVRSwgY29tcGxldGU9VFJVRSwgc2hvdy5jYXNlcz1UUlVFKQpldHRvdXRjb21lCmBgYAoKQXMgd2UgaGF2ZSBzZWVuIGFib3ZlIChzZWUgYzE0NyksIHRoZXJlIGFyZSB0d28gc3VmZmljaWVudCBjb25kaXRpb25zIGZvciB0aGUgb3V0Y29tZSBTVVJWOgpgTTE6IERFVipVUkIqTElUKklORCpTVEIgKyBERVYqdXJiKkxJVCppbmQqU1RCID0+IFNVUlZgLiAKVGhleSBhcmUgaGVuY2Ugbm90IHRlbmFibGUgZm9yIHRoZSBuZWdhdGVkIG91dGNvbWUsIGBzdXJ2YC4gTGV0J3MgZmluZCB0aGUgcm93cyB3aXRoIHRoZXNlIHR3byBwYXR0ZXJuczogCgpgYGB7ciBjMTU2fQpyb3dzIDwtIGZpbmRSb3dzKCJERVYqdXJiKkxJVCppbmQiLCBldHRvdXRjb21lLCByZW1haW5kZXJzID0gRkFMU0UpCnJvd3MKYGBgCkkgY2Fubm90IHVzZSBlaXRoZXIgb2YgTTEncyBjb25kaXRpb25zOiBXaGVuZXZlciBJIGFkZCB0aGUgbGFzdCBjb25kaXRpb24gZWxlbWVudCwgSSBnZXQgYW4gZXJyb3IsIGV2ZW4gdGhvdWdoIHRoZXJlIGFyZSBtYXRjaGluZyByb3dzIGluIHRoZSBUVC4gCgoKYGBge3J9CnJvd3MgPC0gZmluZFJvd3Mob2JqID0gZXR0b3V0Y29tZSwgdHlwZSA9IDIpICMgY29udHJhZGljdG9yeSBzaW1wbGlmeWluZyBhc3N1bXB0aW9ucwpyb3dzCmBgYApIYXZpbmcgZm91bmQgcm93cywgd2UgY2FuIHJlY29kZSB0aGVzZSB0byBPVVQ9MCBpbiB0aGUgVFQ6IAoKYGBge3IgYzE1OX0KZXR0b3V0Y29tZSR0dFthcy5jaGFyYWN0ZXIocm93cyksICJPVVQiXSA8LSAwIApldHRvdXRjb21lCmBgYAo+IGl0IGlzIHdvcnRoIHVucGFja2l1bmcgdGhpcyBjb21tYW5kIGFzIGl0IG1ha2VzIGNvbXBhY3QgdXNlIG9mIHRoZSBvYmplY3QgCgpXaXRoIHRoZSByZWNvZGVkIFRULCBvbmUgY2FuIHRoZW4gY2FsY3VsYXRlZCBlbmhhbmNlZCBzb2x1dGlvbnMsIHN1Y2ggYXMgdGhlIGVuaGFuY2VkIHBhcnNpbW9ub3VzIHNvbHV0aW9uOgoKYGBge3IgYzE2MX0KZXBzb3V0Y29tZSA8LSBtaW5pbWl6ZShldHRvdXRjb21lLCBpbmNsdWRlPSI/IiwgZGV0YWlscz1UUlVFLCBzaG93LmNhc2VzPVRSVUUsIAogICAgICAgICAgICAgIHJvdy5kb209VFJVRSwgYWxsLnNvbD1GQUxTRSkKZXBzb3V0Y29tZQpgYGAKCg==