Introduction

In this lab we will be replicating a classical analysis originally done by Berkeley’s own Prof. David Card on the effects of immigrants on labor markets. If we want to discover the causal effect of adding immigrants, then it’s not enough to look at whether places with more immigrants have different rates of unemployment or wages. This is because immigrants choose their destination – and with all other things equal pick areas with strong labor markets. So, typically we will be unable to distinguish the causal effect of immigrants on labor markets from the reverse effect of labor markets on choice of place to immigrate to. Prof. Card’s insight was that there are certain circumstances in which a wave of immigrants arrives in a way that has little or nothing to do with labor market conditions in the destination. The “Mariel boatlift” was such an event. Here is his description

The experiences of the Miami labor market in the aftermath of the Mariel Boatlift form one such [“natural”] experiment. From May to September 1980, some 125,000 Cuban immigrants arrived in Miami on a flotilla of privately chartered boats. Their arrival was the consequence of an unlikely sequence of events culminating in Castro’s declaration on April 20, 1980, that Cubans wishing to emigrate to the United States were free to leave from the port of Mariel. Fifty percent of the Mariel immigrants settled permanently in Miami. The result was a 7% increase in the labor force of Miami and a 20% increase in the number of Cuban workers in Miami. (Card, 1990:245-6)

You should download a copy of the original paper and read at least pages 245-251 and pages 255-257. It is available at (davidcard.berkeley.edu/papers/mariel-impact.pdf)

Our goals in this lab are

  1. To see if we can replicate Prof. Card’s findings on the effects of this sudden influx of immigrants on the unemployment and wage rates of natives of different racial and ethnic groups. Even if we are not able to replicate the exact numbers of the original study, we can see if we can replicate the essential findings.

  2. To see how a “control” group is useful even for natural experiments

  3. To do a new analysis of the effects broken down by education.

The Current Population Survey “outgoing rotation groups” that we are using for the analysis is the largest sample available for this time period. Still, once we limit ourselves to Miami and the comparison cities, the sample sizes are still small.

Note: some of the “hints” in the auto-correct functions suggest running some additional R-code. You can do this by pasting the hint into the bottom of the last chunk of code and rerunning the chunk.

# Do not edit this chunk, but *do* press the green button to the answer key for the quiz info (the unreadable string below)
tot = 0
answer.key = "eJytlk1v2zgQhu/9FYNgAdmAo03s+GML7CEJFuge0kNboOiRosYS1xSp8MOK/31nKNmtqu7NF8OkxOG8z7xDKn81sSnQ3ef38DfQ77tcWudQhlwY350f3DzfvMtrZcIwzIIoNM4w1E5InGf0VBkfXJRBWeOHtz5hq+kxhBrh4yN0KtRwstFBHxpmmFf5ArLHDJSB12gD+jmFwjdaZwSHGiJ9oQjWqUoZocFHd8QTCH/AEkRhYwDOgqKW8EH5Vhglh7fBYyucCKhP76HD7IggbVMoQyspK0+5WSh40njlA5rQZ8kZSy28V3slUyIQPa0pTvAsXJlTkhdwywRuOQW3HINLww/09z1kNYpyhsKZ2uEC7u/u5hm8KKOa2EAnKmQe93/t7mjgB4l/rEgg1IQvn9BeXo12ivQN/WLAI9qW0jxTIj4eWoqV0kgoQJT/RU/Te+so7l73tGiHWnlINvE5fEXKR1PpgpKHH4iNbVJFWbIHuL1NUbxqWq2kCqcR51XivJpyXo05r37i3NvUN55MYA6/8enqauRWvU9JNOumSKpEAXYPgt0VnNVQORvbBXS1kjWUar9H58EafeKwvOQonOKMeRkJQIc+jBg8JAYPUwb84ObpwiANCXqp2OeKd4E2utZ6zOHfwCkaGyi1hlwvDji11MPVwDycG1gUHo3EnslzLIRJholvnE5XiwANpeK5Q6lplaecyQSKZgR33z7qMckRmXUis56SWY/JpOE/R2TgNlY1sJw+CO3jKEsoVBiqQ35PjZAeSE30AE1aRQ3hY9taF1IXZLy2ig0fIIyaW3i5vptiXV8Na4r0qP9HBVcX34QMZC7exosGeymBVJUc90WJRp2d0FnHh2GdatIff79WYYR7k3Bvprg342ZMw8/0zmlB+wBPTphsrsZkc+lBaaMu+cwqrSHhfKwQDjpXaECHuICAsjbqNZJQoXV/HUBWWBsoNdFmI7XbpHY7Vbsdq03DF+sGkrT11AHbq6ndnhtLGelQUP1Y5hMFPqRDqFBVhe5SahJO1wjvWKFBR8fuYIXeAUd0px+2H8nfJfm7qfxd8uBFfhpqW80e53AL9AdmT/N+Os3++TRfgLeg9oP5+nO/464pbWfAIV8fx3Qrc6KWftxgPzo36RJJZSUKlEV645ywHG5yci1CwxUwWKVY0wrsrlaB3eW2ZLRdclsW6KODP0aIJvZ16UWH4TL1F9mUZTSCBMiA9E3xHQO0H6g="
library(quizify)
source.coded.txt(answer.key)

The data

We have combined the CPS files from 1979 to 1985 and put the relevant variables into a clean version of the file, which you can read-in below.

df <- read.csv("/data175/mariel_clean.csv")
esr <- df$esr # employment status
ftpt79 <- df$ftpt79 # full-time / part-time
ethrace <- df$ethrace ## combination of race and ethnicity
educ <- df$educ
year <- df$.id+1978 # years 1979, 1980, ..., 1985 for each record
weight <- df$weight # we are going to not use the weights (for simplicity)
earnwt <- df$earnwt # this is the weight one would use if you were using weights (we're not)
earnhr <- df$earnhr  
earnhre<-df$earnhre # this is the wage variable we use
age <- df$age
smsarank <- df$smsarank # names of "standard metropolitan statistical areas" (e.g. Miami)
## some vectors for the categories we're interested in 
ethrace.vec <- c("whites","blacks","cubans","hispanics") # good for ordering output
year.vec <- 1979:1985 # good for plotting

Q1.1 What categories are there in the “ethrace” variable?

A. White and Black B. White and Black and Cuban C. White, Black, Cuban, Hispanic, and Other D. Cuban, Hispanic, non-Hispanic?

##  "Replace the NA with your answer (e.g., 'A' in quotes)"
answer1.1 = 'C'
quiz.check(answer1.1)
Your  answer1.1 : C
Correct.
Explanation:  The original survey asked about race and Hispanic origin separately: we've combined these to be consistent with the classification used by Card.

Q1.2 What are the units of the earnhre variable?

A. 1980 dollars per hour B. 1980 cents per hour C. Nominal cents per hour (not adjusting for inflation) D. Nominal dollars per hour (not adjusting for inflation)

##  "Replace the NA with your answer (e.g., 'A' in quotes)"
answer1.2 = 'C'
quiz.check(answer1.2)
Your  answer1.2 : C
Correct.
Explanation:  Yes, these appear to be cents per hour. Card adjusts for inflation in his tables. We will stick with the nominal wages  -- for simplicity.

Q1.3 What cities make up the comparison group?

A. All U.S. cities except Miami B. All Florida cities except Miami C. Cities around the country that Card thought would be subject to the same macro-economic influences as Miami but that didn’t receive many Cuban immigrants. D. Cities that also received a lot of Cuban immigrants.

head(smsarank)
[1] Los Angeles Los Angeles Los Angeles
[4] Los Angeles Los Angeles Los Angeles
5 Levels: Atlanta Houston ... Tampa-St. Petersburg
##  "Replace the NA with your answer (e.g., 'A' in quotes)"
answer1.3 = 'C'
quiz.check(answer1.3)
Your  answer1.3 : C
Correct.
Explanation:  This is the idea of a control group, which differs only in the variable of interest.

Attempt to replicate results for unemployment

We’re going to begin by trying to replicate Card’s results for unemployment in his Table 4. (We’ll do wages in Table 3 later).

The goal here is 3-fold.

  1. To compare over time to see if we can detect a change following the influx of Cuban migrants.

  2. To compare across racial and ethnic groups to see if groups that we might assume are more likely to be in portions of the labor market influenced by the Cubans are influenced more by the influx of Cuban migrants.

  3. To compare the changes in Miami with the comparison cities to try to isolate the effect of the migrant influx per se, separating it from the nationwide changes in the economy. (A large recession began in 1981, as a result of intentional monetary contraction, trying to slow inflation. See https://en.wikipedia.org/wiki/Early_1980s_recession#United_States)

Note: our replication will be slightly different than Card’s original analysis for several reasons. First, we will not use the sampling weights. (We experimented with these but it did not make the replication much closer and so we set them aside for simpler programming – not recommended for research, but ok here for our educational purposes). Second, the selection of cases may not be the same. He removed some of the misreported wage data, but we don’t. Third, while Card worked with CPI deflators, for simplicity we’re going to use nominal wages (divided by 100) rather than deflated wages. (This should be ok, since we will be comparing Miami to the comparison cities, year by year.)

Programming background

We’re going to use the R-function tapply(), which is similar to “pivot tables” in Excel. It will calculate values for each specific combinations of indices (e.g., whites in 1981) and return a table of the values for all combinations.

Here’s an example of the logic, taking the mean of x by sex

x <- 1:4
sex = c("m", "m", "f","f")
height = c("short", "tall", "short", "tall")
print(x)
[1] 1 2 3 4
print(sex)
[1] "m" "m" "f" "f"
print(height)
[1] "short" "tall"  "short" "tall" 
average.by.sex.table <- tapply(X = x,
       INDEX = list(sex),
       FUN = mean)
print(average.by.sex.table)
  f   m 
3.5 1.5 

Try to create the “average.by.height” using tapply(). You should get

short tall 2 3

average.by.height <- tapply( X = x,
                             INDEX = list(height),
                             FUN = mean)
print(average.by.height)
short  tall 
    2     3 

(You can also check this by hand.)

In our case, we’re going to tabulate by year and ethrace, so we’ll “list” two elements when we specify the INDEX. In addition, we’re going to use the custom function get.ue() instead of mean(). The final difference is that we’re going to specify a specific subset of the data, ages 16-61 and Miami/not-Miami. For this we’ll use the TRUE/FALSE index “s”, and we’ll index our arguments using “[s]”. Note, we’ll reuse the same letter “s” for different subsets. So rerun each chunk in its entirety instead of line by line, so that you can be sure that the value R is using for “s” is correct.

get.ue <- function(esr)
{
    ## our function for calculating unemployment rate
    ## from esr variable
    sum(esr == "Unemployed-Looking") /
        sum(esr %in% c("Unemployed-Looking",
                       "Employed-At Work",
                       "Employed-Absent"))
}
# The unemployment rate for Miami
s <- smsarank == "Miami" & age %in% 16:61 #as the true/false index
ue.table.miami <- tapply(X = esr[s],
                         FUN = get.ue,
                         INDEX = list(ethrace[s], year[s]))
## express in percent and round to 1 digit
ue.table.miami.pretty <- round(100*ue.table.miami[ethrace.vec,], 1)
print("Unemployment Rates, as in Card's Table 4")
[1] "Unemployment Rates, as in Card's Table 4"
print("Miami")
[1] "Miami"
(ue.table.miami.pretty) # new trick: outer parentheses will print contents
          1979 1980 1981 1982 1983 1984 1985
whites     5.0  2.8  4.1  5.3  7.1  3.6  5.0
blacks     8.7  5.1  9.3 16.3 19.2 14.5  7.5
cubans     5.3  7.2 10.3 11.2 13.2  7.5  5.6
hispanics  5.6  8.0  9.7  8.8  7.7 12.4  4.4
# The unemployment rate for comparison cities (not Miami)
s <- smsarank != "Miami" & age %in% 16:61
ue.table.notmiami <- tapply(X = esr[s],
                         FUN = get.ue,
                         INDEX = list(ethrace[s], year[s]))
## remove cubans in nonmiami because there are so few we don't want to be misled
ue.table.notmiami["cubans",] <- NA
print("Comparison Cities: Not Miami")
[1] "Comparison Cities: Not Miami"
(ue.table.notmiami.pretty <- round(100*ue.table.notmiami[ethrace.vec,], 1))
          1979 1980 1981 1982 1983 1984 1985
whites     4.5  4.5  4.3  6.9  7.1  5.6  5.2
blacks    10.8 13.5 12.6 12.6 18.2 12.4 12.9
cubans      NA   NA   NA   NA   NA   NA   NA
hispanics  6.6  9.1  8.8 12.0 12.8 10.5 10.0

Now plot results

The following code makes a function that takes in the subgroup we want to make a plot for as an input and output the plot.

ue.plot.fun <- function(my.ethrace)
{
    ## based on:
    ##    plot(year.vec, ue.table.miami["whites",], type = "l",
    ##     ylim = my.ylim)
    ## lines(year.vec, ue.table.notmiami["whites",], lty = 2)
    my.ylim = c(0.01, .2)
    plot(year.vec, ue.table.miami[my.ethrace,], type = "l",
         ylim = my.ylim,
         ylab = "Unemployment",
         xlab = "year")
    lines(year.vec, ue.table.notmiami[my.ethrace,], lty = 2)
    title(my.ethrace)
    abline(v = 1980, col = "grey")
    legend("topright",
           lty = c(1,2),
           legend = c("Miami", "Comparison"),
           bty = "n")
}

Don’t forget to keep the quotation marks for inputs.

par(mfrow = c(2,2))
ue.plot.fun("whites")
ue.plot.fun("blacks")
ue.plot.fun("hispanics")
ue.plot.fun("cubans")

Question 1.4 Why do the “Cubans” have no comparison group?

A. Because there’s a mistake in the code B. Because there are not many Cubans in the comparison cities C. Because there are many Cubans in the comparison cities and it would be confusing to include them.

##  "Replace the NA with your answer (e.g., 'A' in quotes)"
answer1.4 = 'B'
quiz.check(answer1.4)
Your  answer1.4 : B
Correct.
Explanation:  The absence of a Cuban influx is what makes comparison cities a useful control group.

Question 1.5 Unemployment after the Mariel boatlift goes up for all groups. Why does Card argue that there is “There is no evidence that the Mariel influx adversely affected the unemployment rate of either whites or blacks.” (p. 250)

A. Because our replication gives different numbers that Card’s original analysis

B. Because the increases in unemployment were also seen in cities that didn’t have the sudden Cuban migration.

##  "Replace the NA with your answer (e.g., 'A' in quotes)"
answer1.5 = 'B'
quiz.check(answer1.5)
Your  answer1.5 : B
Correct.
Explanation:  Although our numbers are not exactly the same, the trend in Miami is not worse than in the comparison cities.

Question 1.6 How much attention should we pay to the ups and downs in these graphs? Are these chance fluctuations from the sample survey (“noise”), or are they important information that we should pay attention to (“signal”)?

A. They are signal B. They are noise C. We can’t tell just by looking, but one could in theory (and with the help of a statistics course) quantify the magnitude of fluctuations that we would expect from random sampling.

##  "Replace the NA with your answer (e.g., 'A' in quotes)"
answer1.6 = 'C'
quiz.check(answer1.6)
Your  answer1.6 : C
Correct.
Explanation:  This could be done, for example, by a technique called the 'bootstrap'.

Question 1.7 Is there any evidence that unemployment rates for Blacks rose because of the migrant influx?

A. Maybe, since there is such a large spike. B. Maybe, but since we would expect Hispanics to be closer substitutes, the fact that we don’t see the rise for Hispanics should make us skeptical. C. Not much because sample sizes are small. D. All of the above.

##  "Replace the NA with your answer (e.g., 'A' in quotes)"
answer1.7 = 'C'
quiz.check(answer1.7)
Your  answer1.7 : C
Correct.
Explanation:  The increase for Blacks is bigger in Miami, but the general trend is not very different.

Wages

Now we will try to replicate Card’s findings that the Mariel boatlift also had little or no effect on wages of natives.

For simplicity we will not deflate the wages but instead consider the nominal wages. (Note: we’re also doing this because even with the published deflators, we were unable to very closely replicate Card’s Table 3.)

log.w <- log(earnhre/100) # we divide by 100 to get roughly the same units as Card's deflated log wages.
## Miami
s <- age %in% 16:61 & smsarank == "Miami" & !is.na(earnhre) & 
     ftpt79 %in% c("Employed full-time") 
wage.table.miami <- tapply(X = log.w [s],
                          INDEX = list(ethrace[s], year[s]),
                          FUN = mean)
(round(wage.table.miami[ethrace.vec,], 2))
          1979 1980 1981 1982 1983 1984 1985
whites    1.66 1.74 1.82 1.88 1.91 1.92 1.87
blacks    1.43 1.56 1.72 1.67 1.68 1.78 1.86
cubans    1.44 1.46 1.58 1.61 1.62 1.69 1.61
hispanics 1.34 1.42 1.55 1.68 1.64 1.75 1.81
## Not Miami
s <- age %in% 16:61 & smsarank != "Miami" & !is.na(earnhre) &
    ftpt79 %in% c("Employed full-time") 
wage.table.notmiami <- tapply(X = log.w [s],
                          INDEX = list(ethrace[s], year[s]),
                          FUN = mean)
wage.table.notmiami["cubans",] <- NA
(round(wage.table.notmiami[ethrace.vec,], 2))
          1979 1980 1981 1982 1983 1984 1985
whites    1.72 1.82 1.89 1.97 1.98 2.01 2.06
blacks    1.59 1.70 1.76 1.86 1.89 1.88 1.89
cubans      NA   NA   NA   NA   NA   NA   NA
hispanics 1.53 1.61 1.71 1.74 1.77 1.83 1.83

Plot results

wage.plot.fun <- function(my.ethrace)
{
    my.ylim = c(1.3, 2.2)
    plot(year.vec, wage.table.miami[my.ethrace,], type = "l",
         ylim = my.ylim,
         ylab = "Log hourly wages",
         xlab = "year")
    lines(year.vec, wage.table.notmiami[my.ethrace,], lty = 2)
    title(my.ethrace)
    abline(v = 1980, col = "grey")
    legend("topright",
           lty = c(1,2),
           legend = c("Miami", "Comparison"),
           bty = "n")
}
par(mfrow = c(2,2))
wage.plot.fun("whites")
wage.plot.fun("blacks")
wage.plot.fun("hispanics")
wage.plot.fun("cubans")

Our numbers differ from Card’s Table 4 because we are not accounting for inflation. In order to make inferences about the effect of the boatlift on wages easier, let’s plot the differences between Miami and the Comparison Cities.

diff.wage.plot.fun <- function(my.ethrace)
{
    my.ylim = c(-.3, .3)
    plot(year.vec,
    (wage.table.miami[my.ethrace,] - wage.table.notmiami[my.ethrace,]),
    type = "l",
    ylim = my.ylim,
    ylab = "Difference in log wages",
    xlab = "year")
    title(paste("log(Miami wage)- log(Comparison wage) of", my.ethrace),
                cex.main = .5)
    abline(v = 1980, col = "grey")
    abline(h = 0, col = "grey")
}
par(mfrow = c(2,2))
diff.wage.plot.fun("whites")
diff.wage.plot.fun("blacks")
diff.wage.plot.fun("hispanics")
diff.wage.plot.fun("cubans")

Question 1.8 If wages were hurt by the influx of migrants, we would expect this graph to show

A. A decrease after 1980, as Miami wages went down relative to other cities

B. Values below 0 for all periods, because Miami would always have lower wages

C. An uptick after 1980 because we are working with logarithms.

##  "Replace the NA with your answer (e.g., 'A' in quotes)"
answer1.8 = 'A'
quiz.check(answer1.8)
Your  answer1.8 : A
Correct.
Explanation:  Yes, but we don't see any decrease, so it appears wages were unaffected.

So it seems that indeed our analysis is consistent with Card’s conclusion that “the Mariel immigration had virtually no effect on wages or unemployment outcomes of non-Cuban workers in the Miami labor market” (p. 255).

Education

We would expect any negative effect of the influx of immigrants to be strongest on the group that they most resemble. Because most of the Cuban immigrants in the boatlift were unskilled, we would expect the strongest effect on natives with the least education, with perhaps the clearest comparison group being Hispanics with the least education.

Card used a different approach, looking at the effects for low-skilled workers by predicting wages based on education and years of experience. Here we do something a bit simpler, using education only. This portion will provide the material you need to answer the next graded questions.

Programming background (continued)

We can use the above approach with tapply(), adding an additional index, “educ”. The result will then be an array of 3 tables, one for each level of education. To index the array, we need to specify 3 dimensions A[i,j,k].

Unemployment by year and education for Miami

s <- age %in% 16:61 & smsarank == "Miami"
ue.educ.table.miami <- tapply(X = esr[s],
                         FUN = get.ue,
                         INDEX = list(educ[s], year[s]))
print("Unemployment in Miami")
[1] "Unemployment in Miami"
(ue.educ.table.miami.pretty <- round(100*ue.educ.table.miami,1))
       1979 1980 1981 1982 1983 1984 1985
BA      3.6  3.8  3.2  3.1  2.6  2.4  2.0
HS      5.0  3.8  6.9  8.4 10.8  8.0  6.2
lessHS  9.5  8.5 13.0 16.4 17.9 12.5  7.8

Graded Question 1. What happens to the unemployment rates of those with a college education (BA) between 1980 and 1982, when the effects of the Mariel boatlift should have been felt? What happens to those with the least education? (“lessHS”). Is this consistent with a large effect of immigration on the least educated? (Three sentences are fine here).

Graded Question 2. Modify the following chunk of code and calculate the same table for the comparison cities. Does this change your answer about the effect of the boatlift? (< 50 words).

## not miami 
## Hint: you need to change the code defining "s" below so that it specifies the comparison cities. Examples of how to do this are found in our earlier analysis.
s <- age %in% 16:61 & smsarank != "Miami"
ue.educ.table.notmiami <- tapply(X = esr[s],
                         FUN = get.ue,
                         INDEX = list(educ[s], year[s]))
print("Unemployment in Comparison Cities, not Miami")
[1] "Unemployment in Comparison Cities, not Miami"
(ue.educ.table.notmiami.pretty <- round(100*ue.educ.table.notmiami,1))
       1979 1980 1981 1982 1983 1984 1985
BA      3.6  3.1  2.7  4.4  4.2  4.2  3.5
HS      5.0  5.9  5.5  8.0  8.7  7.0  6.6
lessHS  9.2 11.4 11.5 15.2 17.9 13.1 13.3

Graded Question 3. Plot the results of your educational comparison. Copy your image as the answer.

(No additional coding is required. But if you want you can add your name using the text() function like we did in previous labs.)

Here is code that should do this for you, as long as you have created ue.educ.table.miami and ue.educ.table.notmiami above:

ue.plot.fun <- function(my.index, miami.table, notmiami.table)
{
    ## based on:
    ##    plot(year.vec, ue.table.miami["whites",], type = "l",
    ##     ylim = my.ylim)
    ## lines(year.vec, ue.table.notmiami["whites",], lty = 2)
    my.ylim = c(0.01, .2)
    plot(year.vec, miami.table[my.index,], type = "l",
         ylim = my.ylim,
         ylab = "Unemployment",
         xlab = "year")
    lines(year.vec, notmiami.table[my.index,], lty = 2)
    title(my.index)
    abline(v = 1980, col = "grey")
    legend("topright",
           lty = c(1,2),
           legend = c("Miami", "Comparison"),
           bty = "n")
}
par(mfrow = c(2,2))
ue.plot.fun(my.index = "BA", miami.table = ue.educ.table.miami,
            notmiami.table = ue.educ.table.notmiami)
ue.plot.fun(my.index = "HS", miami.table = ue.educ.table.miami,
notmiami.table = ue.educ.table.notmiami)
ue.plot.fun(my.index = "lessHS", miami.table = ue.educ.table.miami,
            notmiami.table = ue.educ.table.notmiami)

Graded question 4. Like Card’s study, many empirical works find very small or no impact of immigration on local workers’ wages and employment. Several studies even found positive impact of skilled immigration on wages and employment. What are 2 possible reasons that having immigrants would benefit the native-born workers? (< 50 words)

Graded question 5. According to the guest lecture, in what way would immigration create negative fiscal effects on the state-level (< 50 words)? In what way would immigration create positive fiscal effect on the federal level (< 50 words)?

Congratulations: You have finished lab 11!

LS0tCnRpdGxlOiAiTGFiXzExX01hcmllbDogTGFib3IgTWFya2V0IEVmZmVjdHMgb2YgdGhlIE1hcmllbCBCb2F0bGlmdCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMgSW50cm9kdWN0aW9uCgpJbiB0aGlzIGxhYiB3ZSB3aWxsIGJlIHJlcGxpY2F0aW5nIGEgY2xhc3NpY2FsIGFuYWx5c2lzIG9yaWdpbmFsbHkKZG9uZSBieSBCZXJrZWxleSdzIG93biBQcm9mLiBEYXZpZCBDYXJkIG9uIHRoZSBlZmZlY3RzIG9mIGltbWlncmFudHMKb24gbGFib3IgbWFya2V0cy4gSWYgd2Ugd2FudCB0byBkaXNjb3ZlciB0aGUgY2F1c2FsIGVmZmVjdCBvZiBhZGRpbmcKaW1taWdyYW50cywgdGhlbiBpdCdzIG5vdCBlbm91Z2ggdG8gbG9vayBhdCB3aGV0aGVyIHBsYWNlcyB3aXRoIG1vcmUKaW1taWdyYW50cyBoYXZlIGRpZmZlcmVudCByYXRlcyBvZiB1bmVtcGxveW1lbnQgb3Igd2FnZXMuIFRoaXMgaXMKYmVjYXVzZSBpbW1pZ3JhbnRzIGNob29zZSB0aGVpciBkZXN0aW5hdGlvbiAtLSBhbmQgd2l0aCBhbGwgb3RoZXIKdGhpbmdzIGVxdWFsIHBpY2sgYXJlYXMgd2l0aCBzdHJvbmcgbGFib3IgbWFya2V0cy4gU28sIHR5cGljYWxseSB3ZQp3aWxsIGJlIHVuYWJsZSB0byBkaXN0aW5ndWlzaCB0aGUgY2F1c2FsIGVmZmVjdCBvZiBpbW1pZ3JhbnRzIG9uIGxhYm9yCm1hcmtldHMgZnJvbSB0aGUgcmV2ZXJzZSBlZmZlY3Qgb2YgbGFib3IgbWFya2V0cyBvbiBjaG9pY2Ugb2YgcGxhY2UgdG8KaW1taWdyYXRlIHRvLiAgUHJvZi4gQ2FyZCdzIGluc2lnaHQgd2FzIHRoYXQgdGhlcmUgYXJlIGNlcnRhaW4KY2lyY3Vtc3RhbmNlcyBpbiB3aGljaCBhIHdhdmUgb2YgaW1taWdyYW50cyBhcnJpdmVzIGluIGEgd2F5IHRoYXQgaGFzCmxpdHRsZSBvciBub3RoaW5nIHRvIGRvIHdpdGggbGFib3IgbWFya2V0IGNvbmRpdGlvbnMgaW4gdGhlCmRlc3RpbmF0aW9uLiBUaGUgIk1hcmllbCBib2F0bGlmdCIgd2FzIHN1Y2ggYW4gZXZlbnQuIEhlcmUgaXMgaGlzCmRlc2NyaXB0aW9uCgoKPiBUaGUgZXhwZXJpZW5jZXMgb2YgdGhlIE1pYW1pIGxhYm9yIG1hcmtldCBpbiB0aGUgYWZ0ZXJtYXRoIG9mIHRoZQo+IE1hcmllbCBCb2F0bGlmdCBmb3JtIG9uZSBzdWNoIFsibmF0dXJhbCJdIGV4cGVyaW1lbnQuIEZyb20gTWF5IHRvCj4gU2VwdGVtYmVyIDE5ODAsIHNvbWUgMTI1LDAwMCBDdWJhbiBpbW1pZ3JhbnRzIGFycml2ZWQgaW4gTWlhbWkgb24gYQo+IGZsb3RpbGxhIG9mIHByaXZhdGVseSBjaGFydGVyZWQgYm9hdHMuIFRoZWlyIGFycml2YWwgd2FzIHRoZQo+IGNvbnNlcXVlbmNlIG9mIGFuIHVubGlrZWx5IHNlcXVlbmNlIG9mIGV2ZW50cyBjdWxtaW5hdGluZyBpbgo+IENhc3RybydzIGRlY2xhcmF0aW9uIG9uIEFwcmlsIDIwLCAxOTgwLCB0aGF0IEN1YmFucyB3aXNoaW5nIHRvCj4gZW1pZ3JhdGUgdG8gdGhlIFVuaXRlZCBTdGF0ZXMgd2VyZSBmcmVlIHRvIGxlYXZlIGZyb20gdGhlIHBvcnQgb2YKPiBNYXJpZWwuIEZpZnR5IHBlcmNlbnQgb2YgdGhlIE1hcmllbCBpbW1pZ3JhbnRzIHNldHRsZWQgcGVybWFuZW50bHkKPiBpbiBNaWFtaS4gVGhlIHJlc3VsdCB3YXMgYSA3JSBpbmNyZWFzZSBpbiB0aGUgbGFib3IgZm9yY2Ugb2YgTWlhbWkKPiBhbmQgYSAyMCUgaW5jcmVhc2UgaW4gdGhlIG51bWJlciBvZiBDdWJhbiB3b3JrZXJzIGluIE1pYW1pLiAoQ2FyZCwKPiAxOTkwOjI0NS02KQoKWW91IHNob3VsZCBkb3dubG9hZCBhIGNvcHkgb2YgdGhlIG9yaWdpbmFsIHBhcGVyIGFuZCByZWFkIGF0IGxlYXN0CnBhZ2VzIDI0NS0yNTEgYW5kIHBhZ2VzIDI1NS0yNTcuIEl0IGlzIGF2YWlsYWJsZSBhdAooZGF2aWRjYXJkLmJlcmtlbGV5LmVkdS9wYXBlcnMvbWFyaWVsLWltcGFjdC5wZGYpCgoKT3VyIGdvYWxzIGluIHRoaXMgbGFiIGFyZQoKMS4gVG8gc2VlIGlmIHdlIGNhbiByZXBsaWNhdGUgUHJvZi4gQ2FyZCdzIGZpbmRpbmdzIG9uIHRoZSBlZmZlY3RzIG9mCiAgIHRoaXMgc3VkZGVuIGluZmx1eCBvZiBpbW1pZ3JhbnRzIG9uIHRoZSB1bmVtcGxveW1lbnQgYW5kIHdhZ2UgcmF0ZXMKICAgb2YgbmF0aXZlcyBvZiBkaWZmZXJlbnQgcmFjaWFsIGFuZCBldGhuaWMgZ3JvdXBzLiBFdmVuIGlmIHdlIGFyZQogICBub3QgYWJsZSB0byByZXBsaWNhdGUgdGhlIGV4YWN0IG51bWJlcnMgb2YgdGhlIG9yaWdpbmFsIHN0dWR5LCB3ZQogICBjYW4gc2VlIGlmIHdlIGNhbiByZXBsaWNhdGUgdGhlIGVzc2VudGlhbCBmaW5kaW5ncy4KCjIuIFRvIHNlZSBob3cgYSAiY29udHJvbCIgZ3JvdXAgaXMgdXNlZnVsIGV2ZW4gZm9yIG5hdHVyYWwgZXhwZXJpbWVudHMKCjMuIFRvIGRvIGEgbmV3IGFuYWx5c2lzIG9mIHRoZSBlZmZlY3RzIGJyb2tlbiBkb3duIGJ5IGVkdWNhdGlvbi4KClRoZSBDdXJyZW50IFBvcHVsYXRpb24gU3VydmV5ICJvdXRnb2luZyByb3RhdGlvbiBncm91cHMiIHRoYXQgd2UgYXJlCnVzaW5nIGZvciB0aGUgYW5hbHlzaXMgaXMgdGhlIGxhcmdlc3Qgc2FtcGxlIGF2YWlsYWJsZSBmb3IgdGhpcyB0aW1lCnBlcmlvZC4gU3RpbGwsIG9uY2Ugd2UgbGltaXQgb3Vyc2VsdmVzIHRvIE1pYW1pIGFuZCB0aGUgY29tcGFyaXNvbgpjaXRpZXMsIHRoZSBzYW1wbGUgc2l6ZXMgYXJlIHN0aWxsIHNtYWxsLgoKTm90ZTogc29tZSBvZiB0aGUgImhpbnRzIiBpbiB0aGUgYXV0by1jb3JyZWN0IGZ1bmN0aW9ucyBzdWdnZXN0CnJ1bm5pbmcgc29tZSBhZGRpdGlvbmFsIFItY29kZS4gWW91IGNhbiBkbyB0aGlzIGJ5IHBhc3RpbmcgdGhlIGhpbnQKaW50byB0aGUgYm90dG9tIG9mIHRoZSBsYXN0IGNodW5rIG9mIGNvZGUgYW5kIHJlcnVubmluZyB0aGUgY2h1bmsuCgpgYGB7cn0KIyBEbyBub3QgZWRpdCB0aGlzIGNodW5rLCBidXQgKmRvKiBwcmVzcyB0aGUgZ3JlZW4gYnV0dG9uIHRvIHRoZSBhbnN3ZXIga2V5IGZvciB0aGUgcXVpeiBpbmZvICh0aGUgdW5yZWFkYWJsZSBzdHJpbmcgYmVsb3cpCnRvdCA9IDAKYW5zd2VyLmtleSA9ICJlSnl0bGsxdjJ6Z1FodS85RllOZ0FkbUFvMDNzK0dNTDdDRUpGdWdlMGtOYm9PaVJvc1lTMXhTcDhNT0svMzFuS05tdHF1N05GOE9reE9HOHo3eERLbjgxc1NuUTNlZjM4RGZRNzd0Y1d1ZFFobHdZMzUwZjNEemZ2TXRyWmNJd3pJSW9OTTR3MUU1SW5HZjBWQmtmWEpSQldlT0h0ejVocStreGhCcmg0eU4wS3RSd3N0RkJIeHBtbUZmNUFyTEhESlNCMTJnRCtqbUZ3amRhWndTSEdpSjlvUWpXcVVvWm9jRkhkOFFUQ0gvQUVrUmhZd0RPZ3FLVzhFSDVWaGdsaDdmQll5dWNDS2hQNzZIRDdJZ2diVk1vUXlzcEswKzVXU2g0MG5qbEE1clFaOGtaU3kyOFYzc2xVeUlRUGEwcFR2QXNYSmxUa2hkd3l3UnVPUVczSElOTHd3LzA5ejFrTllweWhzS1oydUVDN3UvdTVobThLS09hMkVBbkttUWU5My90N21qZ0I0bC9yRWdnMUlRdm45QmVYbzEyaXZRTi9XTEFJOXFXMGp4VElqNGVXb3FWMGtnb1FKVC9SVS9UZStzbzdsNzN0R2lIV25sSU52RTVmRVhLUjFQcGdwS0hINGlOYlZKRldiSUh1TDFOVWJ4cVdxMmtDcWNSNTFYaXZKcHlYbzA1cjM3aTNOdlVONTVNWUE2LzhlbnFhdVJXdlU5Sk5PdW1TS3BFQVhZUGd0MFZuTlZRT1J2YkJYUzFraldVYXI5SDU4RWFmZUt3dk9Rb25PS01lUmtKUUljK2pCZzhKQVlQVXdiODRPYnB3aUFOQ1hxcDJPZUtkNEUydXRaNnpPSGZ3Q2thR3lpMWhsd3ZEamkxMU1QVndEeWNHMWdVSG8zRW5zbHpMSVJKaG9sdm5FNVhpd0FOcGVLNVE2bHBsYWVjeVFTS1pnUjMzejdxTWNrUm1YVWlzNTZTV1kvSnBPRS9SMlRnTmxZMXNKdytDTzNqS0Vzb1ZCaXFRMzVQalpBZVNFMzBBRTFhUlEzaFk5dGFGMUlYWkx5MmlnMGZJSXlhVzNpNXZwdGlYVjhOYTRyMHFQOUhCVmNYMzRRTVpDN2V4b3NHZXltQlZKVWM5MFdKUnAyZDBGbkhoMkdkYXRJZmY3OVdZWVI3azNCdnByZzM0MlpNdzgvMHptbEIrd0JQVHBoc3JzWmtjK2xCYWFNdStjd3FyU0hoZkt3UURqcFhhRUNIdUlDQXNqYnFOWkpRb1hWL0hVQldXQnNvTmRGbUk3WGJwSFk3VmJzZHEwM0RGK3NHa3JUMTFBSGJxNm5kbmh0TEdlbFFVUDFZNWhNRlBxUkRxRkJWaGU1U2FoSk8xd2p2V0tGQlI4ZnVZSVhlQVVkMHB4KzJIOG5mSmZtN3FmeGQ4dUJGZmhwcVc4MGU1M0FMOUFkbVQvTitPczMrK1RSZmdMZWc5b1A1K25PLzQ2NHBiV2ZBSVY4ZngzUXJjNktXZnR4Z1B6bzM2UkpKWlNVS2xFVjY0NXl3SEc1eWNpMUN3eFV3V0tWWTB3cnNybGFCM2VXMlpMUmRjbHNXNktPRFAwYUlKdloxNlVXSDRUTDFGOW1VWlRTQ0JNaUE5RTN4SFFPMEg2Zz0iCmxpYnJhcnkocXVpemlmeSkKc291cmNlLmNvZGVkLnR4dChhbnN3ZXIua2V5KQpgYGAKCiMgVGhlIGRhdGEKCldlIGhhdmUgY29tYmluZWQgdGhlIENQUyBmaWxlcyBmcm9tIDE5NzkgdG8gMTk4NSBhbmQgcHV0IHRoZSByZWxldmFudAp2YXJpYWJsZXMgaW50byBhIGNsZWFuIHZlcnNpb24gb2YgdGhlIGZpbGUsIHdoaWNoIHlvdSBjYW4gcmVhZC1pbgpiZWxvdy4KCmBgYHtyfQoKZGYgPC0gcmVhZC5jc3YoIi9kYXRhMTc1L21hcmllbF9jbGVhbi5jc3YiKQplc3IgPC0gZGYkZXNyICMgZW1wbG95bWVudCBzdGF0dXMKZnRwdDc5IDwtIGRmJGZ0cHQ3OSAjIGZ1bGwtdGltZSAvIHBhcnQtdGltZQpldGhyYWNlIDwtIGRmJGV0aHJhY2UgIyMgY29tYmluYXRpb24gb2YgcmFjZSBhbmQgZXRobmljaXR5CmVkdWMgPC0gZGYkZWR1Ywp5ZWFyIDwtIGRmJC5pZCsxOTc4ICMgeWVhcnMgMTk3OSwgMTk4MCwgLi4uLCAxOTg1IGZvciBlYWNoIHJlY29yZAp3ZWlnaHQgPC0gZGYkd2VpZ2h0ICMgd2UgYXJlIGdvaW5nIHRvIG5vdCB1c2UgdGhlIHdlaWdodHMgKGZvciBzaW1wbGljaXR5KQplYXJud3QgPC0gZGYkZWFybnd0ICMgdGhpcyBpcyB0aGUgd2VpZ2h0IG9uZSB3b3VsZCB1c2UgaWYgeW91IHdlcmUgdXNpbmcgd2VpZ2h0cyAod2UncmUgbm90KQplYXJuaHIgPC0gZGYkZWFybmhyICAKZWFybmhyZTwtZGYkZWFybmhyZSAjIHRoaXMgaXMgdGhlIHdhZ2UgdmFyaWFibGUgd2UgdXNlCmFnZSA8LSBkZiRhZ2UKc21zYXJhbmsgPC0gZGYkc21zYXJhbmsgIyBuYW1lcyBvZiAic3RhbmRhcmQgbWV0cm9wb2xpdGFuIHN0YXRpc3RpY2FsIGFyZWFzIiAoZS5nLiBNaWFtaSkKIyMgc29tZSB2ZWN0b3JzIGZvciB0aGUgY2F0ZWdvcmllcyB3ZSdyZSBpbnRlcmVzdGVkIGluIApldGhyYWNlLnZlYyA8LSBjKCJ3aGl0ZXMiLCJibGFja3MiLCJjdWJhbnMiLCJoaXNwYW5pY3MiKSAjIGdvb2QgZm9yIG9yZGVyaW5nIG91dHB1dAp5ZWFyLnZlYyA8LSAxOTc5OjE5ODUgIyBnb29kIGZvciBwbG90dGluZwoKYGBgCgoKUTEuMSBXaGF0IGNhdGVnb3JpZXMgYXJlIHRoZXJlIGluIHRoZSAiZXRocmFjZSIgdmFyaWFibGU/CgpBLiBXaGl0ZSBhbmQgQmxhY2sKQi4gV2hpdGUgYW5kIEJsYWNrIGFuZCBDdWJhbgpDLiBXaGl0ZSwgQmxhY2ssIEN1YmFuLCBIaXNwYW5pYywgYW5kIE90aGVyCkQuIEN1YmFuLCBIaXNwYW5pYywgbm9uLUhpc3BhbmljPwoKYGBge3J9CiMjICAiUmVwbGFjZSB0aGUgTkEgd2l0aCB5b3VyIGFuc3dlciAoZS5nLiwgJ0EnIGluIHF1b3RlcykiCmFuc3dlcjEuMSA9ICdDJwpxdWl6LmNoZWNrKGFuc3dlcjEuMSkKYGBgCgpRMS4yIFdoYXQgYXJlIHRoZSB1bml0cyBvZiB0aGUgZWFybmhyZSB2YXJpYWJsZT8KCkEuIDE5ODAgZG9sbGFycyBwZXIgaG91cgpCLiAxOTgwIGNlbnRzIHBlciBob3VyCkMuIE5vbWluYWwgY2VudHMgcGVyIGhvdXIgKG5vdCBhZGp1c3RpbmcgZm9yIGluZmxhdGlvbikKRC4gTm9taW5hbCBkb2xsYXJzIHBlciBob3VyIChub3QgYWRqdXN0aW5nIGZvciBpbmZsYXRpb24pCgpgYGB7cn0KIyMgICJSZXBsYWNlIHRoZSBOQSB3aXRoIHlvdXIgYW5zd2VyIChlLmcuLCAnQScgaW4gcXVvdGVzKSIKYW5zd2VyMS4yID0gJ0MnCnF1aXouY2hlY2soYW5zd2VyMS4yKQpgYGAKClExLjMgV2hhdCBjaXRpZXMgbWFrZSB1cCB0aGUgY29tcGFyaXNvbiBncm91cD8KCkEuIEFsbCBVLlMuIGNpdGllcyBleGNlcHQgTWlhbWkKQi4gQWxsIEZsb3JpZGEgY2l0aWVzIGV4Y2VwdCBNaWFtaQpDLiBDaXRpZXMgYXJvdW5kIHRoZSBjb3VudHJ5IHRoYXQgQ2FyZCB0aG91Z2h0IHdvdWxkIGJlIHN1YmplY3QgdG8gdGhlIHNhbWUgbWFjcm8tZWNvbm9taWMgaW5mbHVlbmNlcyBhcyBNaWFtaSBidXQgdGhhdCBkaWRuJ3QgcmVjZWl2ZSBtYW55IEN1YmFuIGltbWlncmFudHMuCkQuIENpdGllcyB0aGF0IGFsc28gcmVjZWl2ZWQgYSBsb3Qgb2YgQ3ViYW4gaW1taWdyYW50cy4KCmBgYHtyfQpoZWFkKHNtc2FyYW5rKQpgYGAKCmBgYHtyfQojIyAgIlJlcGxhY2UgdGhlIE5BIHdpdGggeW91ciBhbnN3ZXIgKGUuZy4sICdBJyBpbiBxdW90ZXMpIgphbnN3ZXIxLjMgPSAnQycKcXVpei5jaGVjayhhbnN3ZXIxLjMpCmBgYAoKCgojIyBBdHRlbXB0IHRvIHJlcGxpY2F0ZSByZXN1bHRzIGZvciB1bmVtcGxveW1lbnQgCgpXZSdyZSBnb2luZyB0byBiZWdpbiBieSB0cnlpbmcgdG8gcmVwbGljYXRlIENhcmQncyByZXN1bHRzIGZvcgp1bmVtcGxveW1lbnQgaW4gaGlzIFRhYmxlIDQuIChXZSdsbCBkbyB3YWdlcyBpbiBUYWJsZSAzIGxhdGVyKS4KClRoZSBnb2FsIGhlcmUgaXMgMy1mb2xkLiAKCjEuIFRvIGNvbXBhcmUgb3ZlciB0aW1lIHRvIHNlZSBpZiB3ZSBjYW4gZGV0ZWN0IGEgY2hhbmdlIGZvbGxvd2luZyB0aGUKICAgaW5mbHV4IG9mIEN1YmFuIG1pZ3JhbnRzLgoKMi4gVG8gY29tcGFyZSBhY3Jvc3MgcmFjaWFsIGFuZCBldGhuaWMgZ3JvdXBzIHRvIHNlZSBpZiBncm91cHMgdGhhdCB3ZQogICBtaWdodCBhc3N1bWUgYXJlIG1vcmUgbGlrZWx5IHRvIGJlIGluIHBvcnRpb25zIG9mIHRoZSBsYWJvciBtYXJrZXQKICAgaW5mbHVlbmNlZCBieSB0aGUgQ3ViYW5zIGFyZSBpbmZsdWVuY2VkIG1vcmUgYnkgdGhlIGluZmx1eCBvZiBDdWJhbgogICBtaWdyYW50cy4KCjMuIFRvIGNvbXBhcmUgdGhlIGNoYW5nZXMgaW4gTWlhbWkgd2l0aCB0aGUgY29tcGFyaXNvbiBjaXRpZXMgdG8gdHJ5CiAgIHRvIGlzb2xhdGUgdGhlIGVmZmVjdCBvZiB0aGUgbWlncmFudCBpbmZsdXggcGVyIHNlLCBzZXBhcmF0aW5nIGl0CiAgIGZyb20gdGhlIG5hdGlvbndpZGUgY2hhbmdlcyBpbiB0aGUgZWNvbm9teS4gKEEgbGFyZ2UgcmVjZXNzaW9uCiAgIGJlZ2FuIGluIDE5ODEsIGFzIGEgcmVzdWx0IG9mIGludGVudGlvbmFsIG1vbmV0YXJ5IGNvbnRyYWN0aW9uLAogICB0cnlpbmcgdG8gc2xvdyBpbmZsYXRpb24uIFNlZQogICBodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9FYXJseV8xOTgwc19yZWNlc3Npb24jVW5pdGVkX1N0YXRlcykKCk5vdGU6IG91ciByZXBsaWNhdGlvbiB3aWxsIGJlIHNsaWdodGx5IGRpZmZlcmVudCB0aGFuIENhcmQncyBvcmlnaW5hbAphbmFseXNpcyBmb3Igc2V2ZXJhbCByZWFzb25zLiBGaXJzdCwgd2Ugd2lsbCBub3QgdXNlIHRoZSBzYW1wbGluZwp3ZWlnaHRzLiAoV2UgZXhwZXJpbWVudGVkIHdpdGggdGhlc2UgYnV0IGl0IGRpZCBub3QgbWFrZSB0aGUKcmVwbGljYXRpb24gbXVjaCBjbG9zZXIgYW5kIHNvIHdlIHNldCB0aGVtIGFzaWRlIGZvciBzaW1wbGVyCnByb2dyYW1taW5nIC0tIG5vdCByZWNvbW1lbmRlZCBmb3IgcmVzZWFyY2gsIGJ1dCBvayBoZXJlIGZvciBvdXIKZWR1Y2F0aW9uYWwgcHVycG9zZXMpLiBTZWNvbmQsIHRoZSBzZWxlY3Rpb24gb2YgY2FzZXMgbWF5IG5vdCBiZSB0aGUKc2FtZS4gSGUgcmVtb3ZlZCBzb21lIG9mIHRoZSBtaXNyZXBvcnRlZCB3YWdlIGRhdGEsIGJ1dCB3ZQpkb24ndC4gVGhpcmQsIHdoaWxlIENhcmQgd29ya2VkIHdpdGggQ1BJIGRlZmxhdG9ycywgZm9yIHNpbXBsaWNpdHkKd2UncmUgZ29pbmcgdG8gdXNlIG5vbWluYWwgd2FnZXMgKGRpdmlkZWQgYnkgMTAwKSByYXRoZXIgdGhhbiBkZWZsYXRlZAp3YWdlcy4gKFRoaXMgc2hvdWxkIGJlIG9rLCBzaW5jZSB3ZSB3aWxsIGJlIGNvbXBhcmluZyBNaWFtaSB0byB0aGUKY29tcGFyaXNvbiBjaXRpZXMsIHllYXIgYnkgeWVhci4pCgoKIyMjIFByb2dyYW1taW5nIGJhY2tncm91bmQKCldlJ3JlIGdvaW5nIHRvIHVzZSB0aGUgUi1mdW5jdGlvbiB0YXBwbHkoKSwgd2hpY2ggaXMgc2ltaWxhciB0byAicGl2b3QKdGFibGVzIiBpbiBFeGNlbC4gSXQgd2lsbCBjYWxjdWxhdGUgdmFsdWVzIGZvciBlYWNoIHNwZWNpZmljCmNvbWJpbmF0aW9ucyBvZiBpbmRpY2VzIChlLmcuLCB3aGl0ZXMgaW4gMTk4MSkgYW5kIHJldHVybiBhIHRhYmxlIG9mCnRoZSB2YWx1ZXMgZm9yIGFsbCBjb21iaW5hdGlvbnMuCgpIZXJlJ3MgYW4gZXhhbXBsZSBvZiB0aGUgbG9naWMsIHRha2luZyB0aGUgbWVhbiBvZiB4IGJ5IHNleApgYGB7cn0KeCA8LSAxOjQKc2V4ID0gYygibSIsICJtIiwgImYiLCJmIikKaGVpZ2h0ID0gYygic2hvcnQiLCAidGFsbCIsICJzaG9ydCIsICJ0YWxsIikKcHJpbnQoeCkKcHJpbnQoc2V4KQpwcmludChoZWlnaHQpCmF2ZXJhZ2UuYnkuc2V4LnRhYmxlIDwtIHRhcHBseShYID0geCwKICAgICAgIElOREVYID0gbGlzdChzZXgpLAogICAgICAgRlVOID0gbWVhbikKcHJpbnQoYXZlcmFnZS5ieS5zZXgudGFibGUpCmBgYAoKVHJ5IHRvIGNyZWF0ZSB0aGUgImF2ZXJhZ2UuYnkuaGVpZ2h0IiB1c2luZyB0YXBwbHkoKS4gWW91IHNob3VsZCBnZXQKCj4gc2hvcnQgIHRhbGwgCj4gICAgMiAgICAgMyAKCmBgYHtyfQphdmVyYWdlLmJ5LmhlaWdodCA8LSB0YXBwbHkoIFggPSB4LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIElOREVYID0gbGlzdChoZWlnaHQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZVTiA9IG1lYW4pCnByaW50KGF2ZXJhZ2UuYnkuaGVpZ2h0KQoKYGBgCgooWW91IGNhbiBhbHNvIGNoZWNrIHRoaXMgYnkgaGFuZC4pCgpJbiBvdXIgY2FzZSwgd2UncmUgZ29pbmcgdG8gdGFidWxhdGUgYnkgeWVhciBhbmQgZXRocmFjZSwgc28gd2UnbGwKImxpc3QiIHR3byBlbGVtZW50cyB3aGVuIHdlIHNwZWNpZnkgdGhlIElOREVYLiBJbiBhZGRpdGlvbiwgd2UncmUKZ29pbmcgdG8gdXNlIHRoZSBjdXN0b20gZnVuY3Rpb24gZ2V0LnVlKCkgaW5zdGVhZCBvZiBtZWFuKCkuIFRoZSBmaW5hbApkaWZmZXJlbmNlIGlzIHRoYXQgd2UncmUgZ29pbmcgdG8gc3BlY2lmeSBhIHNwZWNpZmljIHN1YnNldCBvZiB0aGUKZGF0YSwgYWdlcyAxNi02MSBhbmQgTWlhbWkvbm90LU1pYW1pLiBGb3IgdGhpcyB3ZSdsbCB1c2UgdGhlClRSVUUvRkFMU0UgaW5kZXggInMiLCBhbmQgd2UnbGwgaW5kZXggb3VyIGFyZ3VtZW50cyB1c2luZyAiW3NdIi4gTm90ZSwKd2UnbGwgcmV1c2UgdGhlIHNhbWUgbGV0dGVyICJzIiBmb3IgZGlmZmVyZW50IHN1YnNldHMuIFNvIHJlcnVuIGVhY2gKY2h1bmsgaW4gaXRzIGVudGlyZXR5IGluc3RlYWQgb2YgbGluZSBieSBsaW5lLCBzbyB0aGF0IHlvdSBjYW4gYmUgc3VyZQp0aGF0IHRoZSB2YWx1ZSBSIGlzIHVzaW5nIGZvciAicyIgaXMgY29ycmVjdC4KCgpgYGB7cn0KZ2V0LnVlIDwtIGZ1bmN0aW9uKGVzcikKewogICAgIyMgb3VyIGZ1bmN0aW9uIGZvciBjYWxjdWxhdGluZyB1bmVtcGxveW1lbnQgcmF0ZQogICAgIyMgZnJvbSBlc3IgdmFyaWFibGUKICAgIHN1bShlc3IgPT0gIlVuZW1wbG95ZWQtTG9va2luZyIpIC8KICAgICAgICBzdW0oZXNyICVpbiUgYygiVW5lbXBsb3llZC1Mb29raW5nIiwKICAgICAgICAgICAgICAgICAgICAgICAiRW1wbG95ZWQtQXQgV29yayIsCiAgICAgICAgICAgICAgICAgICAgICAgIkVtcGxveWVkLUFic2VudCIpKQp9CgojIFRoZSB1bmVtcGxveW1lbnQgcmF0ZSBmb3IgTWlhbWkKcyA8LSBzbXNhcmFuayA9PSAiTWlhbWkiICYgYWdlICVpbiUgMTY6NjEgI2FzIHRoZSB0cnVlL2ZhbHNlIGluZGV4CnVlLnRhYmxlLm1pYW1pIDwtIHRhcHBseShYID0gZXNyW3NdLAogICAgICAgICAgICAgICAgICAgICAgICAgRlVOID0gZ2V0LnVlLAogICAgICAgICAgICAgICAgICAgICAgICAgSU5ERVggPSBsaXN0KGV0aHJhY2Vbc10sIHllYXJbc10pKQojIyBleHByZXNzIGluIHBlcmNlbnQgYW5kIHJvdW5kIHRvIDEgZGlnaXQKdWUudGFibGUubWlhbWkucHJldHR5IDwtIHJvdW5kKDEwMCp1ZS50YWJsZS5taWFtaVtldGhyYWNlLnZlYyxdLCAxKQpwcmludCgiVW5lbXBsb3ltZW50IFJhdGVzLCBhcyBpbiBDYXJkJ3MgVGFibGUgNCIpCnByaW50KCJNaWFtaSIpCih1ZS50YWJsZS5taWFtaS5wcmV0dHkpICMgbmV3IHRyaWNrOiBvdXRlciBwYXJlbnRoZXNlcyB3aWxsIHByaW50IGNvbnRlbnRzCgojIFRoZSB1bmVtcGxveW1lbnQgcmF0ZSBmb3IgY29tcGFyaXNvbiBjaXRpZXMgKG5vdCBNaWFtaSkKcyA8LSBzbXNhcmFuayAhPSAiTWlhbWkiICYgYWdlICVpbiUgMTY6NjEKdWUudGFibGUubm90bWlhbWkgPC0gdGFwcGx5KFggPSBlc3Jbc10sCiAgICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSBnZXQudWUsCiAgICAgICAgICAgICAgICAgICAgICAgICBJTkRFWCA9IGxpc3QoZXRocmFjZVtzXSwgeWVhcltzXSkpCiMjIHJlbW92ZSBjdWJhbnMgaW4gbm9ubWlhbWkgYmVjYXVzZSB0aGVyZSBhcmUgc28gZmV3IHdlIGRvbid0IHdhbnQgdG8gYmUgbWlzbGVkCnVlLnRhYmxlLm5vdG1pYW1pWyJjdWJhbnMiLF0gPC0gTkEKcHJpbnQoIkNvbXBhcmlzb24gQ2l0aWVzOiBOb3QgTWlhbWkiKQoodWUudGFibGUubm90bWlhbWkucHJldHR5IDwtIHJvdW5kKDEwMCp1ZS50YWJsZS5ub3RtaWFtaVtldGhyYWNlLnZlYyxdLCAxKSkKCgoKYGBgCgpOb3cgcGxvdCByZXN1bHRzCgpUaGUgZm9sbG93aW5nIGNvZGUgbWFrZXMgYSBmdW5jdGlvbiB0aGF0IHRha2VzIGluIHRoZSBzdWJncm91cCB3ZSB3YW50IHRvIG1ha2UgYSBwbG90IGZvciBhcyBhbiBpbnB1dCBhbmQgb3V0cHV0IHRoZSBwbG90LgpgYGB7cn0KdWUucGxvdC5mdW4gPC0gZnVuY3Rpb24obXkuZXRocmFjZSkKewoKICAgICMjIGJhc2VkIG9uOgogICAgIyMgICAgcGxvdCh5ZWFyLnZlYywgdWUudGFibGUubWlhbWlbIndoaXRlcyIsXSwgdHlwZSA9ICJsIiwKICAgICMjICAgICB5bGltID0gbXkueWxpbSkKICAgICMjIGxpbmVzKHllYXIudmVjLCB1ZS50YWJsZS5ub3RtaWFtaVsid2hpdGVzIixdLCBsdHkgPSAyKQogICAgbXkueWxpbSA9IGMoMC4wMSwgLjIpCiAgICBwbG90KHllYXIudmVjLCB1ZS50YWJsZS5taWFtaVtteS5ldGhyYWNlLF0sIHR5cGUgPSAibCIsCiAgICAgICAgIHlsaW0gPSBteS55bGltLAogICAgICAgICB5bGFiID0gIlVuZW1wbG95bWVudCIsCiAgICAgICAgIHhsYWIgPSAieWVhciIpCiAgICBsaW5lcyh5ZWFyLnZlYywgdWUudGFibGUubm90bWlhbWlbbXkuZXRocmFjZSxdLCBsdHkgPSAyKQogICAgdGl0bGUobXkuZXRocmFjZSkKICAgIGFibGluZSh2ID0gMTk4MCwgY29sID0gImdyZXkiKQogICAgbGVnZW5kKCJ0b3ByaWdodCIsCiAgICAgICAgICAgbHR5ID0gYygxLDIpLAogICAgICAgICAgIGxlZ2VuZCA9IGMoIk1pYW1pIiwgIkNvbXBhcmlzb24iKSwKICAgICAgICAgICBidHkgPSAibiIpCn0KYGBgCgpEb24ndCBmb3JnZXQgdG8ga2VlcCB0aGUgcXVvdGF0aW9uIG1hcmtzIGZvciBpbnB1dHMuCmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMH0KcGFyKG1mcm93ID0gYygyLDIpKQp1ZS5wbG90LmZ1bigid2hpdGVzIikKdWUucGxvdC5mdW4oImJsYWNrcyIpCnVlLnBsb3QuZnVuKCJoaXNwYW5pY3MiKQp1ZS5wbG90LmZ1bigiY3ViYW5zIikKYGBgClF1ZXN0aW9uIDEuNCBXaHkgZG8gdGhlICJDdWJhbnMiIGhhdmUgbm8gY29tcGFyaXNvbiBncm91cD8KCkEuIEJlY2F1c2UgdGhlcmUncyBhIG1pc3Rha2UgaW4gdGhlIGNvZGUKQi4gQmVjYXVzZSB0aGVyZSBhcmUgbm90IG1hbnkgQ3ViYW5zIGluIHRoZSBjb21wYXJpc29uIGNpdGllcyAKQy4gQmVjYXVzZSB0aGVyZSBhcmUgbWFueSBDdWJhbnMgaW4gdGhlIGNvbXBhcmlzb24gY2l0aWVzIGFuZCBpdCB3b3VsZCBiZSBjb25mdXNpbmcgdG8gaW5jbHVkZSB0aGVtLgoKYGBge3J9CiMjICAiUmVwbGFjZSB0aGUgTkEgd2l0aCB5b3VyIGFuc3dlciAoZS5nLiwgJ0EnIGluIHF1b3RlcykiCmFuc3dlcjEuNCA9ICdCJwpxdWl6LmNoZWNrKGFuc3dlcjEuNCkKYGBgCgpRdWVzdGlvbiAxLjUgVW5lbXBsb3ltZW50IGFmdGVyIHRoZSBNYXJpZWwgYm9hdGxpZnQgZ29lcyB1cCBmb3IgYWxsCmdyb3Vwcy4gV2h5IGRvZXMgQ2FyZCBhcmd1ZSB0aGF0IHRoZXJlIGlzICJUaGVyZSBpcyBubyBldmlkZW5jZSB0aGF0CnRoZSBNYXJpZWwgaW5mbHV4IGFkdmVyc2VseSBhZmZlY3RlZCB0aGUgdW5lbXBsb3ltZW50IHJhdGUgb2YgZWl0aGVyCndoaXRlcyBvciBibGFja3MuIiAocC4gMjUwKQoKQS4gQmVjYXVzZSBvdXIgcmVwbGljYXRpb24gZ2l2ZXMgZGlmZmVyZW50IG51bWJlcnMgdGhhdCBDYXJkJ3MKb3JpZ2luYWwgYW5hbHlzaXMKCkIuIEJlY2F1c2UgdGhlIGluY3JlYXNlcyBpbiB1bmVtcGxveW1lbnQgd2VyZSBhbHNvIHNlZW4gaW4gY2l0aWVzIHRoYXQKZGlkbid0IGhhdmUgdGhlIHN1ZGRlbiBDdWJhbiBtaWdyYXRpb24uIAoKCmBgYHtyfQojIyAgIlJlcGxhY2UgdGhlIE5BIHdpdGggeW91ciBhbnN3ZXIgKGUuZy4sICdBJyBpbiBxdW90ZXMpIgphbnN3ZXIxLjUgPSAnQicKcXVpei5jaGVjayhhbnN3ZXIxLjUpCmBgYAoKClF1ZXN0aW9uIDEuNiBIb3cgbXVjaCBhdHRlbnRpb24gc2hvdWxkIHdlIHBheSB0byB0aGUgdXBzIGFuZCBkb3ducyBpbgp0aGVzZSBncmFwaHM/IEFyZSB0aGVzZSBjaGFuY2UgZmx1Y3R1YXRpb25zIGZyb20gdGhlIHNhbXBsZSBzdXJ2ZXkKKCJub2lzZSIpLCBvciBhcmUgdGhleSBpbXBvcnRhbnQgaW5mb3JtYXRpb24gdGhhdCB3ZSBzaG91bGQgcGF5CmF0dGVudGlvbiB0byAoInNpZ25hbCIpPwoKQS4gVGhleSBhcmUgc2lnbmFsCkIuIFRoZXkgYXJlIG5vaXNlCkMuIFdlIGNhbuKAmXQgdGVsbCBqdXN0IGJ5IGxvb2tpbmcsIGJ1dCBvbmUgY291bGQgaW4gdGhlb3J5IChhbmQgd2l0aAogICB0aGUgaGVscCBvZiBhIHN0YXRpc3RpY3MgY291cnNlKSBxdWFudGlmeSB0aGUgbWFnbml0dWRlIG9mCiAgIGZsdWN0dWF0aW9ucyB0aGF0IHdlIHdvdWxkIGV4cGVjdCBmcm9tIHJhbmRvbSBzYW1wbGluZy4KCmBgYHtyfQojIyAgIlJlcGxhY2UgdGhlIE5BIHdpdGggeW91ciBhbnN3ZXIgKGUuZy4sICdBJyBpbiBxdW90ZXMpIgphbnN3ZXIxLjYgPSAnQycKcXVpei5jaGVjayhhbnN3ZXIxLjYpCmBgYAoKClF1ZXN0aW9uIDEuNyBJcyB0aGVyZSBhbnkgZXZpZGVuY2UgdGhhdCB1bmVtcGxveW1lbnQgcmF0ZXMgZm9yIEJsYWNrcwpyb3NlIGJlY2F1c2Ugb2YgdGhlIG1pZ3JhbnQgaW5mbHV4PwoKQS4gTWF5YmUsIHNpbmNlIHRoZXJlIGlzIHN1Y2ggYSBsYXJnZSBzcGlrZS4KQi4gTWF5YmUsIGJ1dCBzaW5jZSB3ZSB3b3VsZCBleHBlY3QgSGlzcGFuaWNzIHRvIGJlIGNsb3NlcgogICBzdWJzdGl0dXRlcywgdGhlIGZhY3QgdGhhdCB3ZSBkb24ndCBzZWUgdGhlIHJpc2UgZm9yIEhpc3BhbmljcwogICBzaG91bGQgbWFrZSB1cyBza2VwdGljYWwuCkMuIE5vdCBtdWNoIGJlY2F1c2Ugc2FtcGxlIHNpemVzIGFyZSBzbWFsbC4KRC4gQWxsIG9mIHRoZSBhYm92ZS4KCmBgYHtyfQojIyAgIlJlcGxhY2UgdGhlIE5BIHdpdGggeW91ciBhbnN3ZXIgKGUuZy4sICdBJyBpbiBxdW90ZXMpIgphbnN3ZXIxLjcgPSAnQycKcXVpei5jaGVjayhhbnN3ZXIxLjcpCmBgYAoKIyMgV2FnZXMKCk5vdyB3ZSB3aWxsIHRyeSB0byByZXBsaWNhdGUgQ2FyZCdzIGZpbmRpbmdzIHRoYXQgdGhlIE1hcmllbCBib2F0bGlmdAphbHNvIGhhZCBsaXR0bGUgb3Igbm8gZWZmZWN0IG9uIHdhZ2VzIG9mIG5hdGl2ZXMuCgpGb3Igc2ltcGxpY2l0eSB3ZSB3aWxsIG5vdCBkZWZsYXRlIHRoZSB3YWdlcyBidXQgaW5zdGVhZCBjb25zaWRlciB0aGUKbm9taW5hbCB3YWdlcy4gKE5vdGU6IHdlJ3JlIGFsc28gZG9pbmcgdGhpcyBiZWNhdXNlIGV2ZW4gd2l0aCB0aGUKcHVibGlzaGVkIGRlZmxhdG9ycywgd2Ugd2VyZSB1bmFibGUgdG8gdmVyeSBjbG9zZWx5IHJlcGxpY2F0ZSBDYXJkJ3MKVGFibGUgMy4pCgoKCmBgYHtyfQoKbG9nLncgPC0gbG9nKGVhcm5ocmUvMTAwKSAjIHdlIGRpdmlkZSBieSAxMDAgdG8gZ2V0IHJvdWdobHkgdGhlIHNhbWUgdW5pdHMgYXMgQ2FyZCdzIGRlZmxhdGVkIGxvZyB3YWdlcy4KCgojIyBNaWFtaQpzIDwtIGFnZSAlaW4lIDE2OjYxICYgc21zYXJhbmsgPT0gIk1pYW1pIiAmICFpcy5uYShlYXJuaHJlKSAmIAogICAgIGZ0cHQ3OSAlaW4lIGMoIkVtcGxveWVkIGZ1bGwtdGltZSIpIAp3YWdlLnRhYmxlLm1pYW1pIDwtIHRhcHBseShYID0gbG9nLncgW3NdLAogICAgICAgICAgICAgICAgICAgICAgICAgIElOREVYID0gbGlzdChldGhyYWNlW3NdLCB5ZWFyW3NdKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSBtZWFuKQoocm91bmQod2FnZS50YWJsZS5taWFtaVtldGhyYWNlLnZlYyxdLCAyKSkKCiMjIE5vdCBNaWFtaQpzIDwtIGFnZSAlaW4lIDE2OjYxICYgc21zYXJhbmsgIT0gIk1pYW1pIiAmICFpcy5uYShlYXJuaHJlKSAmCiAgICBmdHB0NzkgJWluJSBjKCJFbXBsb3llZCBmdWxsLXRpbWUiKSAKd2FnZS50YWJsZS5ub3RtaWFtaSA8LSB0YXBwbHkoWCA9IGxvZy53IFtzXSwKICAgICAgICAgICAgICAgICAgICAgICAgICBJTkRFWCA9IGxpc3QoZXRocmFjZVtzXSwgeWVhcltzXSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgRlVOID0gbWVhbikKd2FnZS50YWJsZS5ub3RtaWFtaVsiY3ViYW5zIixdIDwtIE5BCihyb3VuZCh3YWdlLnRhYmxlLm5vdG1pYW1pW2V0aHJhY2UudmVjLF0sIDIpKQpgYGAKClBsb3QgcmVzdWx0cwpgYGB7ciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTB9Cgp3YWdlLnBsb3QuZnVuIDwtIGZ1bmN0aW9uKG15LmV0aHJhY2UpCnsKICAgIG15LnlsaW0gPSBjKDEuMywgMi4yKQogICAgcGxvdCh5ZWFyLnZlYywgd2FnZS50YWJsZS5taWFtaVtteS5ldGhyYWNlLF0sIHR5cGUgPSAibCIsCiAgICAgICAgIHlsaW0gPSBteS55bGltLAogICAgICAgICB5bGFiID0gIkxvZyBob3VybHkgd2FnZXMiLAogICAgICAgICB4bGFiID0gInllYXIiKQogICAgbGluZXMoeWVhci52ZWMsIHdhZ2UudGFibGUubm90bWlhbWlbbXkuZXRocmFjZSxdLCBsdHkgPSAyKQogICAgdGl0bGUobXkuZXRocmFjZSkKICAgIGFibGluZSh2ID0gMTk4MCwgY29sID0gImdyZXkiKQogICAgbGVnZW5kKCJ0b3ByaWdodCIsCiAgICAgICAgICAgbHR5ID0gYygxLDIpLAogICAgICAgICAgIGxlZ2VuZCA9IGMoIk1pYW1pIiwgIkNvbXBhcmlzb24iKSwKICAgICAgICAgICBidHkgPSAibiIpCn0KcGFyKG1mcm93ID0gYygyLDIpKQp3YWdlLnBsb3QuZnVuKCJ3aGl0ZXMiKQp3YWdlLnBsb3QuZnVuKCJibGFja3MiKQp3YWdlLnBsb3QuZnVuKCJoaXNwYW5pY3MiKQp3YWdlLnBsb3QuZnVuKCJjdWJhbnMiKQpgYGAKCk91ciBudW1iZXJzIGRpZmZlciBmcm9tIENhcmQncyBUYWJsZSA0IGJlY2F1c2Ugd2UgYXJlIG5vdCBhY2NvdW50aW5nCmZvciBpbmZsYXRpb24uIEluIG9yZGVyIHRvIG1ha2UgaW5mZXJlbmNlcyBhYm91dCB0aGUgZWZmZWN0IG9mIHRoZQpib2F0bGlmdCBvbiB3YWdlcyBlYXNpZXIsIGxldCdzIHBsb3QgdGhlIGRpZmZlcmVuY2VzIGJldHdlZW4gTWlhbWkgYW5kCnRoZSBDb21wYXJpc29uIENpdGllcy4KCmBgYHtyfQpkaWZmLndhZ2UucGxvdC5mdW4gPC0gZnVuY3Rpb24obXkuZXRocmFjZSkKewogICAgbXkueWxpbSA9IGMoLS4zLCAuMykKICAgIHBsb3QoeWVhci52ZWMsCiAgICAod2FnZS50YWJsZS5taWFtaVtteS5ldGhyYWNlLF0gLSB3YWdlLnRhYmxlLm5vdG1pYW1pW215LmV0aHJhY2UsXSksCiAgICB0eXBlID0gImwiLAogICAgeWxpbSA9IG15LnlsaW0sCiAgICB5bGFiID0gIkRpZmZlcmVuY2UgaW4gbG9nIHdhZ2VzIiwKICAgIHhsYWIgPSAieWVhciIpCiAgICB0aXRsZShwYXN0ZSgibG9nKE1pYW1pIHdhZ2UpLSBsb2coQ29tcGFyaXNvbiB3YWdlKSBvZiIsIG15LmV0aHJhY2UpLAogICAgICAgICAgICAgICAgY2V4Lm1haW4gPSAuNSkKICAgIGFibGluZSh2ID0gMTk4MCwgY29sID0gImdyZXkiKQogICAgYWJsaW5lKGggPSAwLCBjb2wgPSAiZ3JleSIpCn0KCnBhcihtZnJvdyA9IGMoMiwyKSkKZGlmZi53YWdlLnBsb3QuZnVuKCJ3aGl0ZXMiKQpkaWZmLndhZ2UucGxvdC5mdW4oImJsYWNrcyIpCmRpZmYud2FnZS5wbG90LmZ1bigiaGlzcGFuaWNzIikKZGlmZi53YWdlLnBsb3QuZnVuKCJjdWJhbnMiKQpgYGAKClF1ZXN0aW9uIDEuOCBJZiB3YWdlcyB3ZXJlIGh1cnQgYnkgdGhlIGluZmx1eCBvZiBtaWdyYW50cywgd2Ugd291bGQKZXhwZWN0IHRoaXMgZ3JhcGggdG8gc2hvdwoKQS4gQSBkZWNyZWFzZSBhZnRlciAxOTgwLCBhcyBNaWFtaSB3YWdlcyB3ZW50IGRvd24gcmVsYXRpdmUgdG8gb3RoZXIgY2l0aWVzCgpCLiBWYWx1ZXMgYmVsb3cgMCBmb3IgYWxsIHBlcmlvZHMsIGJlY2F1c2UgTWlhbWkgd291bGQgYWx3YXlzIGhhdmUKbG93ZXIgd2FnZXMKCkMuIEFuIHVwdGljayBhZnRlciAxOTgwIGJlY2F1c2Ugd2UgYXJlIHdvcmtpbmcgd2l0aCBsb2dhcml0aG1zLgoKYGBge3J9CiMjICAiUmVwbGFjZSB0aGUgTkEgd2l0aCB5b3VyIGFuc3dlciAoZS5nLiwgJ0EnIGluIHF1b3RlcykiCmFuc3dlcjEuOCA9ICdBJwpxdWl6LmNoZWNrKGFuc3dlcjEuOCkKYGBgCgpTbyBpdCBzZWVtcyB0aGF0IGluZGVlZCBvdXIgYW5hbHlzaXMgaXMgY29uc2lzdGVudCB3aXRoIENhcmQncwpjb25jbHVzaW9uIHRoYXQgInRoZSBNYXJpZWwgaW1taWdyYXRpb24gaGFkIHZpcnR1YWxseSBubyBlZmZlY3Qgb24Kd2FnZXMgb3IgdW5lbXBsb3ltZW50IG91dGNvbWVzIG9mIG5vbi1DdWJhbiB3b3JrZXJzIGluIHRoZSBNaWFtaSBsYWJvcgptYXJrZXQiIChwLiAyNTUpLgoKIyMgRWR1Y2F0aW9uCgpXZSB3b3VsZCBleHBlY3QgYW55IG5lZ2F0aXZlIGVmZmVjdCBvZiB0aGUgaW5mbHV4IG9mIGltbWlncmFudHMgdG8gYmUKc3Ryb25nZXN0IG9uIHRoZSBncm91cCB0aGF0IHRoZXkgbW9zdCByZXNlbWJsZS4gQmVjYXVzZSBtb3N0IG9mIHRoZQpDdWJhbiBpbW1pZ3JhbnRzIGluIHRoZSBib2F0bGlmdCB3ZXJlIHVuc2tpbGxlZCwgd2Ugd291bGQgZXhwZWN0IHRoZQpzdHJvbmdlc3QgZWZmZWN0IG9uIG5hdGl2ZXMgd2l0aCB0aGUgbGVhc3QgZWR1Y2F0aW9uLCB3aXRoIHBlcmhhcHMgdGhlCmNsZWFyZXN0IGNvbXBhcmlzb24gZ3JvdXAgYmVpbmcgSGlzcGFuaWNzIHdpdGggdGhlIGxlYXN0IGVkdWNhdGlvbi4KCkNhcmQgdXNlZCBhIGRpZmZlcmVudCBhcHByb2FjaCwgbG9va2luZyBhdCB0aGUgZWZmZWN0cyBmb3IgbG93LXNraWxsZWQKd29ya2VycyBieSBwcmVkaWN0aW5nIHdhZ2VzIGJhc2VkIG9uIGVkdWNhdGlvbiBhbmQgeWVhcnMgb2YKZXhwZXJpZW5jZS4gSGVyZSB3ZSBkbyBzb21ldGhpbmcgYSBiaXQgc2ltcGxlciwgdXNpbmcgZWR1Y2F0aW9uCm9ubHkuIFRoaXMgcG9ydGlvbiB3aWxsIHByb3ZpZGUgdGhlIG1hdGVyaWFsIHlvdSBuZWVkIHRvIGFuc3dlciB0aGUKbmV4dCBncmFkZWQgcXVlc3Rpb25zLgoKIyMjIFByb2dyYW1taW5nIGJhY2tncm91bmQgKGNvbnRpbnVlZCkKCldlIGNhbiB1c2UgdGhlIGFib3ZlIGFwcHJvYWNoIHdpdGggdGFwcGx5KCksIGFkZGluZyBhbiBhZGRpdGlvbmFsCmluZGV4LCAiZWR1YyIuIFRoZSByZXN1bHQgd2lsbCB0aGVuIGJlIGFuIGFycmF5IG9mIDMgdGFibGVzLCBvbmUgZm9yCmVhY2ggbGV2ZWwgb2YgZWR1Y2F0aW9uLiBUbyBpbmRleCB0aGUgYXJyYXksIHdlIG5lZWQgdG8gc3BlY2lmeSAzCmRpbWVuc2lvbnMgQVtpLGosa10uCgpVbmVtcGxveW1lbnQgYnkgeWVhciBhbmQgZWR1Y2F0aW9uIGZvciBNaWFtaQpgYGB7cn0KcyA8LSBhZ2UgJWluJSAxNjo2MSAmIHNtc2FyYW5rID09ICJNaWFtaSIKdWUuZWR1Yy50YWJsZS5taWFtaSA8LSB0YXBwbHkoWCA9IGVzcltzXSwKICAgICAgICAgICAgICAgICAgICAgICAgIEZVTiA9IGdldC51ZSwKICAgICAgICAgICAgICAgICAgICAgICAgIElOREVYID0gbGlzdChlZHVjW3NdLCB5ZWFyW3NdKSkKcHJpbnQoIlVuZW1wbG95bWVudCBpbiBNaWFtaSIpCih1ZS5lZHVjLnRhYmxlLm1pYW1pLnByZXR0eSA8LSByb3VuZCgxMDAqdWUuZWR1Yy50YWJsZS5taWFtaSwxKSkKYGBgCgo+IEdyYWRlZCBRdWVzdGlvbiAxLiBXaGF0IGhhcHBlbnMgdG8gdGhlIHVuZW1wbG95bWVudCByYXRlcyBvZiB0aG9zZQo+IHdpdGggYSBjb2xsZWdlIGVkdWNhdGlvbiAoQkEpIGJldHdlZW4gMTk4MCBhbmQgMTk4Miwgd2hlbiB0aGUKPiBlZmZlY3RzIG9mIHRoZSBNYXJpZWwgYm9hdGxpZnQgc2hvdWxkIGhhdmUgYmVlbiBmZWx0PyBXaGF0IGhhcHBlbnMKPiB0byB0aG9zZSB3aXRoIHRoZSBsZWFzdCBlZHVjYXRpb24/ICgibGVzc0hTIikuIElzIHRoaXMgY29uc2lzdGVudAo+IHdpdGggYSBsYXJnZSBlZmZlY3Qgb2YgaW1taWdyYXRpb24gb24gdGhlIGxlYXN0IGVkdWNhdGVkPyAoVGhyZWUKPiBzZW50ZW5jZXMgYXJlIGZpbmUgaGVyZSkuCgo+IEdyYWRlZCBRdWVzdGlvbiAyLiBNb2RpZnkgdGhlIGZvbGxvd2luZyBjaHVuayBvZiBjb2RlIGFuZCBjYWxjdWxhdGUKPiB0aGUgc2FtZSB0YWJsZSBmb3IgdGhlIGNvbXBhcmlzb24gY2l0aWVzLiBEb2VzIHRoaXMgY2hhbmdlIHlvdXIKPiBhbnN3ZXIgYWJvdXQgdGhlIGVmZmVjdCBvZiB0aGUgYm9hdGxpZnQ/ICg8IDUwIHdvcmRzKS4KCmBgYHtyfQojIyBub3QgbWlhbWkgCiMjIEhpbnQ6IHlvdSBuZWVkIHRvIGNoYW5nZSB0aGUgY29kZSBkZWZpbmluZyAicyIgYmVsb3cgc28gdGhhdCBpdCBzcGVjaWZpZXMgdGhlIGNvbXBhcmlzb24gY2l0aWVzLiBFeGFtcGxlcyBvZiBob3cgdG8gZG8gdGhpcyBhcmUgZm91bmQgaW4gb3VyIGVhcmxpZXIgYW5hbHlzaXMuCnMgPC0gYWdlICVpbiUgMTY6NjEgJiBzbXNhcmFuayAhPSAiTWlhbWkiCnVlLmVkdWMudGFibGUubm90bWlhbWkgPC0gdGFwcGx5KFggPSBlc3Jbc10sCiAgICAgICAgICAgICAgICAgICAgICAgICBGVU4gPSBnZXQudWUsCiAgICAgICAgICAgICAgICAgICAgICAgICBJTkRFWCA9IGxpc3QoZWR1Y1tzXSwgeWVhcltzXSkpCnByaW50KCJVbmVtcGxveW1lbnQgaW4gQ29tcGFyaXNvbiBDaXRpZXMsIG5vdCBNaWFtaSIpCih1ZS5lZHVjLnRhYmxlLm5vdG1pYW1pLnByZXR0eSA8LSByb3VuZCgxMDAqdWUuZWR1Yy50YWJsZS5ub3RtaWFtaSwxKSkKCmBgYAoKCgo+IEdyYWRlZCBRdWVzdGlvbiAzLiBQbG90IHRoZSByZXN1bHRzIG9mIHlvdXIgZWR1Y2F0aW9uYWwKPiBjb21wYXJpc29uLiBDb3B5IHlvdXIgaW1hZ2UgYXMgdGhlIGFuc3dlci4KCihObyBhZGRpdGlvbmFsIGNvZGluZyBpcyByZXF1aXJlZC4gQnV0IGlmIHlvdSB3YW50IHlvdSBjYW4gYWRkIHlvdXIKbmFtZSB1c2luZyB0aGUgdGV4dCgpIGZ1bmN0aW9uIGxpa2Ugd2UgZGlkIGluIHByZXZpb3VzIGxhYnMuKQoKSGVyZSBpcyBjb2RlIHRoYXQgc2hvdWxkIGRvIHRoaXMgZm9yIHlvdSwgYXMgbG9uZyBhcyB5b3UgaGF2ZSBjcmVhdGVkIHVlLmVkdWMudGFibGUubWlhbWkgYW5kIHVlLmVkdWMudGFibGUubm90bWlhbWkgYWJvdmU6CgpgYGB7cn0KdWUucGxvdC5mdW4gPC0gZnVuY3Rpb24obXkuaW5kZXgsIG1pYW1pLnRhYmxlLCBub3RtaWFtaS50YWJsZSkKewoKICAgICMjIGJhc2VkIG9uOgogICAgIyMgICAgcGxvdCh5ZWFyLnZlYywgdWUudGFibGUubWlhbWlbIndoaXRlcyIsXSwgdHlwZSA9ICJsIiwKICAgICMjICAgICB5bGltID0gbXkueWxpbSkKICAgICMjIGxpbmVzKHllYXIudmVjLCB1ZS50YWJsZS5ub3RtaWFtaVsid2hpdGVzIixdLCBsdHkgPSAyKQogICAgbXkueWxpbSA9IGMoMC4wMSwgLjIpCiAgICBwbG90KHllYXIudmVjLCBtaWFtaS50YWJsZVtteS5pbmRleCxdLCB0eXBlID0gImwiLAogICAgICAgICB5bGltID0gbXkueWxpbSwKICAgICAgICAgeWxhYiA9ICJVbmVtcGxveW1lbnQiLAogICAgICAgICB4bGFiID0gInllYXIiKQogICAgbGluZXMoeWVhci52ZWMsIG5vdG1pYW1pLnRhYmxlW215LmluZGV4LF0sIGx0eSA9IDIpCiAgICB0aXRsZShteS5pbmRleCkKICAgIGFibGluZSh2ID0gMTk4MCwgY29sID0gImdyZXkiKQogICAgbGVnZW5kKCJ0b3ByaWdodCIsCiAgICAgICAgICAgbHR5ID0gYygxLDIpLAogICAgICAgICAgIGxlZ2VuZCA9IGMoIk1pYW1pIiwgIkNvbXBhcmlzb24iKSwKICAgICAgICAgICBidHkgPSAibiIpCn0KYGBgCgpgYGB7ciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTB9CnBhcihtZnJvdyA9IGMoMiwyKSkKdWUucGxvdC5mdW4obXkuaW5kZXggPSAiQkEiLCBtaWFtaS50YWJsZSA9IHVlLmVkdWMudGFibGUubWlhbWksCiAgICAgICAgICAgIG5vdG1pYW1pLnRhYmxlID0gdWUuZWR1Yy50YWJsZS5ub3RtaWFtaSkKdWUucGxvdC5mdW4obXkuaW5kZXggPSAiSFMiLCBtaWFtaS50YWJsZSA9IHVlLmVkdWMudGFibGUubWlhbWksCm5vdG1pYW1pLnRhYmxlID0gdWUuZWR1Yy50YWJsZS5ub3RtaWFtaSkKdWUucGxvdC5mdW4obXkuaW5kZXggPSAibGVzc0hTIiwgbWlhbWkudGFibGUgPSB1ZS5lZHVjLnRhYmxlLm1pYW1pLAogICAgICAgICAgICBub3RtaWFtaS50YWJsZSA9IHVlLmVkdWMudGFibGUubm90bWlhbWkpCmBgYAoKCj4gR3JhZGVkIHF1ZXN0aW9uIDQuIExpa2UgQ2FyZCdzIHN0dWR5LCBtYW55IGVtcGlyaWNhbCB3b3JrcyBmaW5kIHZlcnkKPiBzbWFsbCBvciBubyBpbXBhY3Qgb2YgaW1taWdyYXRpb24gb24gbG9jYWwgd29ya2Vycycgd2FnZXMgYW5kCj4gZW1wbG95bWVudC4gU2V2ZXJhbCBzdHVkaWVzIGV2ZW4gZm91bmQgcG9zaXRpdmUgaW1wYWN0IG9mIHNraWxsZWQKPiBpbW1pZ3JhdGlvbiBvbiB3YWdlcyBhbmQgZW1wbG95bWVudC4gV2hhdCBhcmUgMiBwb3NzaWJsZSByZWFzb25zCj4gdGhhdCBoYXZpbmcgaW1taWdyYW50cyB3b3VsZCBiZW5lZml0IHRoZSBuYXRpdmUtYm9ybiB3b3JrZXJzPyAoPCA1MAo+IHdvcmRzKQoKPiBHcmFkZWQgcXVlc3Rpb24gNS4gQWNjb3JkaW5nIHRvIHRoZSBndWVzdCBsZWN0dXJlLCBpbiB3aGF0IHdheSB3b3VsZAo+IGltbWlncmF0aW9uIGNyZWF0ZSBuZWdhdGl2ZSBmaXNjYWwgZWZmZWN0cyBvbiB0aGUgc3RhdGUtbGV2ZWwgKDwgNTAKPiB3b3Jkcyk/IEluIHdoYXQgd2F5IHdvdWxkIGltbWlncmF0aW9uIGNyZWF0ZSBwb3NpdGl2ZSBmaXNjYWwgZWZmZWN0Cj4gb24gdGhlIGZlZGVyYWwgbGV2ZWwgKDwgNTAgd29yZHMpPwoKQ29uZ3JhdHVsYXRpb25zOiBZb3UgaGF2ZSBmaW5pc2hlZCBsYWIgMTEhCg==