This visualization nerd-sniped me today two weeks ago (see original Reddit thread). It is based on the Special Eurobarometer 2015 (EBM) and it suggests all kinds of horribleness about my home country:

(Heatmap of Europe, colored by responses to the Special Eurobarometer 2015 question Would you feel comfortable if one of your children was in a relationship with an X person?) For my non-European friends, my home country is the red one in the center-left.

(Heatmap of Europe, colored by responses to the Special Eurobarometer 2015 question “Would you feel comfortable if one of your children was in a relationship with an X person?”) For my non-European friends, my home country is the red one in the center-left.

This looks all sorts of unpleasant. More to the point, it looks wrong. Czechs think of themselves as the cool stoner uncle of the region, secular and colorblind and live-and-let-live. Could we really be this bad? More importantly - sure, we’ve had some issues recently, but how could Czechland become more xenophobic than Poland? (Humorous tongue-in-cheek nationalist chauvinism is to Europe as baseball is to the US. You can see how this could lead to problems.)

So, is it a survey artifact or is it real? Can we perhaps dismiss it as noise driven by a mistranslation? In terms of mechanism, can the dataset suggest any? Could this, for instance, be driven by the urban-rural gap?

Luckily, this was data from the Special Eurobarometer 2015, so it’s publicly accessible along with complete documentation. That means we can poke it. I kept this RMarkdown notebook to retrace my steps, so that you can poke it too. (You can download it from the top-right button.) Note that I usually haven’t gone back to re-visualize early graphs on the basis of later explorations.

This is equal parts a dataset exploration and data-tidying exercise so if you’re here to talk about why all of this is bullcrap, feel free to skip the parts with R code and go straight to the discussion of validity.

1 Getting the data

Eurobarometer releases its full dataset, which is also indexed by social-science aggregators like ICPSR and GESIS. Using the gesis package, extracting the desired Eurobarometer data is easy. (The only difficult part was determining which Eurobarometer to download because GESIS follows the original EBM numbering convention of (survey round #).(wave #), whereas the EBM reports usually go by a single-integer ID. Here, we knew what year we wanted, so finding the GESIS equivalent was a matter of one Google search.)

You will have to register for free and use those credentials to download the dataset.

setwd("~/Coding/ebm2015/")
library(gesis)
library(tidyverse)
library(haven)
library(ggplot2)
library(scales)
library(ggalt)
library(countrycode)
library(sjmisc)
library(cowplot)
library(printr)
library(stringr)
library(forcats)
library(RColorBrewer)
library(countrycode)
theme_set(theme_bw())
# Look at availability
study_types <- gesis::get_study_groups()
datasets <-    gesis::get_datasets("0008") # EB - Standard and Special Eurobarometer
gesis_login <- gesis::login(username = "simon.podhajsky@gmail.com",
                            password = Sys.getenv('GESIS_PWD')) # Saved in .Renviron
# If you're not planning to share your code, you could type in your password
# above, but you should really get used to storing your secrets elsewhere.

gesis::download_dataset(s = gesis_login, doi = 6595) # Eurobarometer 83.4 (2015)
# past:
# - 2012: 77.4 (DOI 5613)
# - 2009: 71.2 (DOI 4972)
# - 2008: 69.1 (DOI 4743)
# - 2007: 65.4 (DOI 4508)
# - 2002: 57.0 (DOI 3638)
# gesis::download_codebook(doi = 6595) # errors out, for some reason

Downloading the codebook from the GESIS API hasn’t worked for me, so you can get it from ICPSR instead.

# There's no control over the naming of the saved file, so you'll have
# to take a look to make sure you're loading the right one - but GESIS
# will save each survey under a consistent filename, so at least you've
# got that
eb15 <- read_dta("ZA6595_v2-0-0.dta")
dim(eb15)
[1] 27718   512

That’s a lot of Eurobarometer data! But even without downloading the codebook, the structure is well-documented in the data frame attributes. This means that we can take a look-see.

# A lot of well-documented variables -- so many that it overwhelms R console,
# so we'll save the output into a file and look it over in a text editor or
# work it with grep
sink("labels.txt")
(eb15_labels <- sapply(names(eb15), function(x) attributes(eb15[[x]])))
sink()

1.1 Basic properties

Each row is a record of one interview. Grouping by country reveals that each has a sample of about a thousand, except for Montenegro, Northern Ireland, Luxembourg, and former East Germany:

# Look over sample size per country
eb15 %>% group_by(isocntry) %>% summarize(n())

Other identifying info I care about is a listed nationality (which is not the same as country of interview - Czechs can be interviewed abroad, dual citizenship is a thing, …), size of community the respondent lives in (stored separately for each country in p6* columns, but same for the V4 countries), and region of origin at NUTS-2 level. (Each region in each country is sampled roughly equally. I don’t know exactly how the authors of the survey do their stratified sampling, so it’s possible that I’m missing some re-weighting.)

The measures I care about the most were “comfort with X coworker” and “comfort with X child-in-law”. For each value of X, these are stored in columns qc13_* and qc14_*, respectively. There’s a lot of other interesting goodies, but these will do for now.

2 A first look: responses versus community size

To make our analysis easier, we extract columns of interest and then convert the attitude questions from wide to long. We’ll also label some of the values to make visualization easier.

# See raw Rmd original or the codebook for description of question codes
# select countries of the V4 + relevant cols
eb15_v4 <- eb15 %>% 
  select(isocntry, q1_17, q1_19, q1_23, q1_24, uniqid, # country + citizenship
         starts_with("qc13"), starts_with("qc14"), 
         starts_with("p6"), starts_with("p7"),
         ends_with("cz"), ends_with("sk"), 
         ends_with("pl"), ends_with("hu")) %>%
  filter(isocntry %in% c("CZ", "SK", "PL", "HU"))
# Data reshaping:
# - merge "size of community" for CZ, SK and PL
# - make long all presently loaded survey questions (qc*)
eb15_v4_long <- eb15_v4 %>% 
  mutate(community_size = coalesce(p6pl, p6cz, p6sk, p6hu)) %>% 
  select(-starts_with("p6")) %>%
  gather(question, response, starts_with("qc13"), starts_with("qc14")) %>%
  mutate(response = factor(response, levels = 1:13, 
                           labels = c("Not at all comfortable", 2:9, 
                                      "Totally comfortable", 
                                      "Indifferent", "It depends", "Don't know")),
         community_size = factor(community_size, 
                                 labels = c("1" = "Rural area",
                                            "2" = "Towns and suburbs",
                                            "3" = "Cities")))

(Sidenote: here, I convert data into factors manually. This is because when I did this two weeks ago, I did not think to dig through sjmisc, a package that is excellent about digging out and applying the metadata from .dta files. I do use it later.)

Remember the metadata we stored separately? We can create a lookup table for facet_wrap in ggplot2 in order to make our labels more informative.

# Clean up the question codes
question_names <- sapply(eb15_labels, function(x) x$label)
question_names <- gsub("COLLEAGUES AT WORK: ", "", question_names)
question_names["qc13_11"] <- "Trans* person" # Too long for facet labels
question_names <- gsub("LOVE RELATIONSSHIP OF CHILD: ", "", question_names)
question_names["qc14_11"] <- "Trans* person"
question_names <- sapply(question_names, 
                         function(x) R.utils::capitalize(stringr::str_to_lower(x)))
# We'll also create a named vector of country codes for later use as a lookup 
# table
ebs_countries <- unique(eb15$isocntry)
# setNames is a way to get names for an unnamed vector
ebs_country_dict <- setNames(
  countrycode(ebs_countries, 
              "iso2c", "country.name", 
              custom_match = c("GB-NIR" = "GB (Northern Ireland)",
                               "GB-GBN" = "Great Britain",
                               "DE-E" = "Germany (East)",
                               "DE-W" = "Germany (West)")),
  ebs_countries)
# Some of the `isocntry` labels are not actually in the ISO standard, but we
# still want to label them, so we provide a custom_match dictionary

Initially, I visualized all categories of interest in the same graph, but that turned out to be a little overwhelming. I split the attitudes into three categories and ordered them so that the most “popular” subgroup is at the top. (If you’re dealing with a lot of factors, forcats has methods to do this automatically.)

# Reorder the facets
ethnicities = paste0("qc14_", c(4, 3:1))
religions = paste0("qc14_", c(8:9, 5, 7, 6))
sexdisability = paste0("qc14_", 10:12)
ordered_questions = question_names[c(ethnicities, religions, sexdisability)]
# Other than reordering the factors, this also gives them the names from
# the codebook
eb15_v4_long <- eb15_v4_long  %>%
  mutate(question = fct_relevel(as.factor(question),
                                names(ordered_questions)))

We’ll make three graphs that we’ll then combine with the cowplot package, which means that we’ll be reusing a lot of ggplot2 layers. Luckily, we can prepare those ahead of time in a list. (The following assumes ggplot2 knowledge; the short summary is that it implements a “grammar of graphics”, which lets you assign variables to different graphical representations and handles the imperative work that used to take up the most time. Harvard Data Science Services has a good intro.)

## Prepare layers for reuse - we'll be graphing a lot of bar charts! (How can we
# use variables in here before they're ever defined? It is the magic of
# non-standard evaluation! You'll want to read Advanced R by Hadley Wickham, but
# for now, just settle for the explanationof "arguments in ggplot2 are only
# evaluated when it's time to draw the graphs.")
layers <- list(
  # separate graph for each country and each attitude
  facet_grid(question ~ isocntry,
             labeller = labeller(question = as_labeller(question_names),
                                 isocntry = ebs_country_dict)),
  # separate the 1-10 comfort rating from indifference/IDK
  geom_vline(xintercept = 10.5), 
  theme(legend.position = "top", strip.text = element_text(size = 11),
        axis.text.x = element_text(angle = 60, hjust = 1, size = 11)),
  xlab(""), 
  ylab("Response count"),
  ylim(0, 800)
  # highlight community size of respondents to shine some initial light on
  # the urban-rural question
)
makeMainTitle <- function(subset_description = "all", countries = "CZ, HU, PL & SK") {
  ggtitle(paste0("How comfortable would you feel if one of your children was in ",
                 "a love relationship with ___?"),
          subtitle = paste0("Eurobarometer 83.4 (2015) via GESIS, ", 
                            subset_description, " questions, ", countries, 
                            " answers"))
}

Now, we prepare the graphs and put them together with cowplot::plot_grid.

v4_love_ethnicities <- eb15_v4_long %>%
  filter(question %in% ethnicities) %>%
  ggplot() + makeMainTitle("ethnicity") +
  geom_bar(aes(x = response, fill = community_size), width = 0.8) +
  layers
  
v4_love_religions <- eb15_v4_long %>%
  filter(question %in% religions) %>%
  ggplot() + makeMainTitle("religious-affiliation") +
  geom_bar(aes(x = response, fill = community_size), width = 0.8) +
  layers
v4_love_sexdisability <- eb15_v4_long %>%
  filter(question %in% sexdisability) %>%
  ggplot() + makeMainTitle("LGBTQ/disability") +
  geom_bar(aes(x = response, fill = community_size), width = 0.8) +
  layers
v4_love_all <- cowplot::plot_grid(v4_love_ethnicities + makeMainTitle(), 
          v4_love_religions + ggtitle("Subsection: Religions") + 
            theme(legend.position = "none"),
          v4_love_sexdisability + ggtitle("Subsection: LGBTQ and disability") +
            theme(legend.position = "bottom"), 
          ncol = 1, rel_heights = c(4.5, 5, 4))
v4_love_all

This isn’t bad as a first pass. Here’s a couple of things of note:

  1. Different community sizes weren’t sampled evenly, so there’s fewer rural respondents – and they aren’t all conservative. They don’t drive the trends. (A mosaic plot could tell us more about the within-rural split, but doing it with categorical variables would require an edge version of ggmosaic and ggplot2, which has been breaking things for me.)
  2. Holy shit we all suck, but Poland and Hungary have a bimodal distribution of discomfort (a solid second-place finish for “Totally comfortable”), whereas Czech and Slovak respondents differ mostly on the degree of discomfort. This is odd.
  3. Most Czech and Slovak response distributions look oddly similar.

We’ll get to the weirdness in a bit.

2.1 Collapsing the scales

Visual comparisons with a 10-point Likert scale are difficult, so let’s collapse it. This frees up space to print percentages on top. We’ll do the collapsing with forcats::fct_collapse; for now, we’ll stick with my initial choice of grouping the top four response levels, the bottom four, and everything in between. (This is not a neutral choice, of course - more about this in the next section. Do note that in the original EBM report, “Indifferent” was grouped with the most positive responses.)

data_collapsed <- eb15_v4_long %>%
  filter(question %in% c(ethnicities, religions, sexdisability)) %>%
  mutate(response_detailed = fct_relevel(response, # to prettify the legend order
                                         "Don't know", "Indifferent", 
                                         "It depends", after = 5),
         response = 
           fct_collapse(response,
                        "Uncomfortable" = c("Not at all comfortable", 2:3),
                        "Meh" = c(4:6, "Indifferent", 
                                  "It depends", "Don't know"),
                        "Comfortable" = c(7:9, "Totally comfortable")) %>%
           fct_drop())
# precalculated percentages!
# Doing this dance to get the total number of respondents that's different 
# for every country (and possibly every question, though hopefully that does
# not change)
# 
# Note: if not filtered before use, the inclusion of this in a ggplot2 layer 
#   will create additional facets.
data_collapsed_percentages_temp <- data_collapsed %>%
  group_by(isocntry, question, response) %>%
  summarize(count = n())
data_collapsed_percentages <- data_collapsed_percentages_temp %>%
  summarize(total_count = sum(count)) %>%
  merge(data_collapsed_percentages_temp) %>%
  mutate(perc = round(100*count/total_count, 1))
# replace the settings that wouldn't work here
layers_collapsed <- layers
layers_collapsed[[2]] <- scale_fill_manual(
  values = colorRampPalette(brewer.pal(11, "RdYlGn"))(13),
  guide = guide_legend(nrow = 1, label.position = "bottom", title = NULL))
layers_collapsed[[3]] <- theme(panel.grid = element_blank(), 
                               axis.text.x = element_text(hjust = 1, angle = 25),
                               legend.position = "top", strip.text = element_text(size = 11))
layers_collapsed[[6]] <- ylim(0, 1000)
layers_collapsed[[7]] <- geom_bar(aes(x = response, fill = response_detailed), width = 0.8)
collapsed_ethnicities <- ggplot(data_collapsed %>% filter(question %in% ethnicities)) + 
  makeMainTitle("ethnicities") +
  geom_text(data = data_collapsed_percentages %>% filter(question %in% ethnicities), 
            size = 3.5,
            aes(x = response, y = count + 65, label = paste0(perc, "%"))) +
  layers_collapsed
collapsed_religions <- ggplot(data_collapsed %>% filter(question %in% religions)) + 
  makeMainTitle("religious-affiliation") +
  geom_text(data = data_collapsed_percentages %>% filter(question %in% religions), 
            size = 3.5,
            aes(x = response, y = count + 65, label = paste0(perc, "%"))) +
  layers_collapsed
collapsed_sexdisability <- ggplot(data_collapsed %>% filter(question %in% sexdisability)) + 
  makeMainTitle("LGBTQ/disability") +
  geom_text(data = data_collapsed_percentages %>% filter(question %in% sexdisability), 
            size = 3.5,
            aes(x = response, y = count + 65, label = paste0(perc, "%"))) +
  layers_collapsed
collapsed_all <- plot_grid(collapsed_ethnicities + makeMainTitle(), 
          collapsed_religions + ggtitle("Subsection: Religions") + 
            theme(legend.position = "none"),
          collapsed_sexdisability + ggtitle("Subsection: LGBTQ and disability") +
            theme(legend.position = "none"), 
          ncol = 1, rel_heights = c(4.5, 5, 4))
collapsed_all

So that looks pretty bad. Can we blame this on methodology?

3 Methodological criticisms

3.1 The issue of mistranslation

The most common criticism is that the Slovak and Czech surveys have been translated sloppily, which made the data ineligible for cross-border comparisons or, for people who like to make quick conclusions, disqualified this survey in particular and Eurobarometer in general. For the most part, I think that this line of inquiry overreaches.

(You can download each translation from GESIS. The Czech one is here.)

3.1.1 What’s “comfortable”?

Jan Kulveit argues that EBM shat the bed on translating “comfortable” to Czech and Slovak. If you speak Czech, go read it. Here are the four main arguments (some of which appear in the comments):

  1. “Comfortable,” the operative response keyword, is not translated into Czech and Slovak in a way that guarantees one-to-one equivalence of connotations.
  2. The Czech translation of the question is at odds with its colloquial usage, which primes respondents negatively. “How comfortable would you feel if X” is usually used with toddlers who are still working on their theory of mind; “X” is usually “that other kid took your toys away.”
  3. The Czech and Slovak translation of the top response option is awkward. The Czech question asks (approximately) “how great would you feel,” and the most-positive label, “totally great,” is a very peculiar translation of “totally comfortable.” Some argue that it comes off as “extremely overjoyed,” since a common colloquial usage is understating your chagrin by saying that you’re “not extremely overjoyed”.
  4. Although the isn’t a flaw shared by all translations, the translations differ among each other - the top-most response ranges from “wouldn’t mind at all” (Polish) to “would be totally cool with it” (Hungarian & most everything else). Some make positive responses more natural than others. Consequently, cross-national comparisons are right out.

The author then goes on to (accurately) rip the media misrepresentation of the survey and concludes by dismissing the survey as a whole (which is a step too far).

I’m grateful that Jan looked into the nitty-gritty of survey wording. Jan’s hypothesis also explains some of the weirdness I’ve noted - the uncanny Czech/Slovak similarity could be due to the shared mistranslation, and the comparative lack of positive-response spike makes plausible the unpalatability of the positive-most response.

So why shouldn’t we bin the study?

  1. The translation is close enough; one-to-one connotational equivalence is an unreasonably high standard. It’s great if it can happen! It should happen whenever it can! But a lot of our vocabulary, especially the vocabulary that describes culturally shaped subjective experience, some disparity will necessarily exist. It’s the price we pay for comparative research. We should absolutely keep track of differences and should call bullshit when the disparity grows too large.

But in this case, I don’t think the translations are so different as to measure a different construct. “Zcela příjemné” is awkward but not insanely off. Given EBM’s wealth of questions, we can actually check that empirically:

  1. The translation hasn’t precluded Czechs and Slovaks from using the full scale almost as often as other nations when it came to attitudes to a potential white inlaw. Look at the graph from earlier and focus on the “white people” plots in the top row:
v4_love_ethnicities

Jan presents this as conclusive evidence of negative skew / overly positive translation - in the lily-white Czechland and Slovakia, surely you’d expect more than ~70% of people to be “totally comfortable” with a white inlaw, right? I concur that positive responses are probably bleeding into the “indifferent” column - which, for the record, the original EBM report counted among “comfortable” responses. But the fact that the majority of people did use the “totally comfortable” response for a white inlaw also means that the top-most response isn’t off the menu by virtue of catastrophic mistranslation. You can’t shrug off the non-selection of this option for any other demographic subgroup by appealing to mild semantic differences.

The mid-scale bump provides an upper bound on the suggested error. Mostly, it’s pretty tiny. All V4 countries have it to some extent, as does Britain, Germany, and many others. All of this suggests that positive attitudes aren’t getting drastically underreported there. (Both German samples have a higher rate of “Indifferent” responses, though, which is consistent with translation variation redirecting responses there - but again, since “Indifferent” was interpreted as a positive response, this wouldn’t matter for the original EBM report.)

# All countries' attitudes to potential white inlaw
eb15_graph_white <- eb15 %>% select(isocntry, qc14_4) %>% 
  mutate(qc14_4 = to_label(qc14_4)) %>%
  ggplot(aes(x = qc14_4)) + 
  facet_wrap(~ isocntry, ncol = 5, labeller = labeller(isocntry = ebs_country_dict)) + 
  stat_count(mapping = aes(y = ..prop.., group = 1), width = 0.7) +
  geom_rect(data = data.frame(isocntry = c("CZ", "HU", "PL", "SK")), inherit.aes = FALSE, 
            fill = "blue", alpha = 0.1, xmin = -Inf, ymin = -Inf, xmax = Inf, ymax = Inf) +
  scale_y_continuous(labels = percent, sec.axis = dup_axis()) +
  ggtitle(paste0("How comfortable would you feel if one of your children was in \n",
                 "a love relationship with a white person?")) + labs(x = "", y = "") +
  geom_vline(xintercept = 10.5) +
  theme(axis.text.x = element_text(angle = 60, hjust = 1))
eb15_graph_white

  1. Even if the most positive label was problematic, the most negative level is not. “I wouldn’t feel great at all [about having X as an inlaw]” is roughly equivalent to “I wouldn’t feel at all comfortable”. Both express the kind of fear and apprehension that the study is after. At worst, the peculiar translation of the positive label introduces some noise into the top of the scale for Czech and Slovak respondents; it doesn’t invalidate it altogether, and it doesn’t invalidate the negative responses at all.

In summary, the critique properly cautions about transnational response-level percentage comparisons, especially at the positive end of the scale, and about the possible disparate floor/ceiling levels between languages. But it overplays its hand.

(For further empirical testing, see the section below that compares the Eurobarometer results with those from the European Social Survey.)

3.2 Social desirability bias and actual discrimination

Three other criticism I’ve seen floating around:

  • Czechs’ and Slovaks’ answers are not as positive as other nations’ because we’re honest. We’re not as subject to social desirability bias as other countries. If Czechs and Slovaks don’t feel a particular taboo as strongly as other Europeans, isn’t that an interesting finding in its own right? Not to mention that what people feel comfortable saying is an important element of your everyday experience in a society.
  • Due to social desirability bias, positive answers in other countries don’t necessarily translate into tolerant behavior. True. Do note, however, that the converse does not apply: since there’s no social force forcing the negative responses, there’s no reason to think that negative responses don’t predict intolerance (or that the negative respondents are secretly super-tolerant). If people say they’re uncomfortable about minorities, we should probably believe them.
  • The survey cannot sniff out hidden discriminatory behavior. Absolutely. Unlike other measures, it isn’t designed to do that. This doesn’t mean it’s worthless.

To be clear, there’s no way to determine the amount of social desirability bias in each country. You can claim that the differences between countries estimate the difference in social desirability bias rather than the difference in level of (dis)comfort with different people. That’s fine. But let’s not criticize a puzzle piece for failing to contain the whole picture.

So Eurobarometer is not the end-all and be-all of surveys, but its data retain meaning. What better approaches can we take to reporting and visualizing it?

4 Alternative 1: Make conservative estimates of self-reported intolerance

Let’s assume that Jan is correct that many a 5 response in Czech and Slovak is the nonchalant colorblind tolerance that respondents in other languages would put down as 10. If we move response levels 3 and 4 from “Uncomfortable” into “Meh”, we’ll get an adequate count of otherness-based discomfort for Czechs and Slovaks.

Of course, if Jan is right, then the “Meh” and “Comfortable” responses aren’t meaningful. Let’s remove them from the visualization in the best Tuftean tradition. (Which makes it a glorified table, but tables are great. Fancy geometries are for suckers.)

(Under these assumptions, we’re undercounting bigoted Poles and Hungarians, but not by a lot – the distributions cluster around the extremes and not that many people were picking 3 and 4 on the scale anyway.)

It turns out that things don’t get much better.

# We can take the previous data and reshape it
data_collapsed_12 <- data_collapsed %>%
  mutate(response = 
           fct_collapse(response_detailed,
                        "Uncomfortable" = c("Not at all comfortable", 2),
                        "Meh" = c(3:6, "Indifferent", 
                                  "It depends", "Don't know"),
                        "Comfortable" = c(7:9, "Totally comfortable")) %>%
           fct_drop())
data_collapsed_percentages_temp <- data_collapsed_12 %>%
  group_by(isocntry, question, response) %>%
  summarize(count = n())
data_collapsed_12_percentages <- data_collapsed_percentages_temp %>%
  summarize(total_count = sum(count)) %>%
  merge(data_collapsed_percentages_temp) %>%
  mutate(perc = round(100*count/total_count, 1))
# ...but now, we'll remove everything but the "Uncomfortable" factor
data_collapsed_12 <- filter(data_collapsed_12, response == "Uncomfortable")
data_collapsed_12_percentages <- filter(data_collapsed_12_percentages, 
                                        response == "Uncomfortable")
ggplot(data_collapsed_12_percentages, aes(x = isocntry, y = fct_rev(question), fill = perc)) +
  geom_tile() + geom_label(aes(label = paste0(perc, "%")), color = "black") +
  scale_fill_distiller(limits = c(0, 100), palette = "Reds", direction = 1) +
  scale_x_discrete(position = "top", labels = ebs_country_dict) +
  scale_y_discrete(labels = question_names) + ylab("") + xlab("") +
  ggtitle(paste0("How comfortable would you feel if one of your children was in \n",
                 "a love relationship with ___?"),
          subtitle = "Percentage of respondents who rated their comfort below 2 out of 10\n(inclusive), where 1 is 'not at all comfortable'") +
  theme_minimal() +
  theme(legend.position = "none", axis.ticks.x = element_blank(), 
        axis.text = element_text(size = 11))

5 Alternative 2: Measure relative discomfort

The other way to avoid the semantics debate: we can look at respondents’ comfort relative to the comfort with the dominant majority group in the country. (For V4, that’s pretty clearly white people.). This seems like a better measure in a number of ways: for one, it works even if response item 10 in Polish doesn’t translate to response item 10 in Czech. For another, the majority-minority differential is arguably what we mean when we talk about discrimination.

(Alternatively, we could norm relative to the respondent’s own most favored group. I don’t have a clear idea of what we’d be gaining/missing out on.)

Of course, there’s a reason why the EBM people aren’t doing this. The most important that I can think of is that the non-responses – “Don’t know”, “Indifferent”, and “It depends” – don’t fall neatly in the response scale, but excluding them misses out on real information. (We’d miss out on the entire response set of respondents who selected one of these responses for their reference attitude.) Placing them on the scale, however, gives them meaning they might not have. (The decision to place them in the “Meh” category above was only okay because I had no plans to make any inferences about “Meh”.)

This seems like a fun visualization to think about; I hope to get to it later.

6 Alternative 3: Abandon cross-country comparisons

It’s really tempting to compare my tribe to yours. (Admittedly, this is how I fell into this rabbit hole.) But there’s plenty to be gleaned from within-country comparisons, too! So far, the visualizations I’ve been using have invited cross-country comparison - but I don’t actually need to see Poland’s share of uncomfortable attitudes toward the Romani to say that the Czech ones are horribly high.

As a bonus, this also allows for a display of multiple positions that the respondents were asked about the comfort for.

# Let's start again and shape the data better
binary_measures <- vars(starts_with("qc2"), -qc2t, starts_with("qc3"))
comfort_measures <- vars(starts_with("qc4"),
                         starts_with("qc13"), starts_with("qc14"), starts_with("qc18"))
eb15_all <-  select(eb15, isocntry, uniqid,
                    starts_with("qc"), starts_with("sd"), starts_with("d")) %>%
  mutate_all(to_label) %>%
  mutate_at(binary_measures, function(x) x != "Not mentioned") %>% # Binary measures
  mutate_at(comfort_measures, function(x) {
    fct_recode(x, 
               "Not at all comfortable" = "1 Not at all comfortable",
               "Totally comfortable" = "10 Totally comfortable",
               "Indifferent" = "Indifferent (SPONTANEOUS)",
               "Don't know" = "DK")
  })
# question_names_valid <- setNames(names(question_names), make.names(question_names))
# question_names_valid <- question_names_valid[question_names_valid %in% names(eb15_comfort)]
question_names_original <- sapply(eb15_labels, function(x) x$label)
eb15_comfort_wide <- select(eb15_all, isocntry, uniqid, !!! comfort_measures) %>%
  gather(question, response, !!! comfort_measures, -isocntry, -uniqid)
attributes are not identical across measure variables; they will be dropped
eb15_comfort_wide$question <- question_names_original[eb15_comfort_wide$question]
eb15_comfort_wide <- separate(eb15_comfort_wide, question, 
                              into = c("question_kind", "target"), sep = ": ") %>%
  mutate_at(vars(question_kind, target), funs(str_to_lower))
country_counts <- eb15 %>% group_by(isocntry) %>% summarize(total = n())
replication_base <- eb15_comfort_wide %>%
  mutate(target = fct_relevel(target, "different ethnic origin", "white person", "asian person", "black person", "roma person", "different religion", "christian person", "atheist person", "jewish person", "buddhist person", "muslim person", "person under 25 years", "aged under 30", "person over 60 years", "aged over 75")) %>% 
  group_by(isocntry, question_kind, target, response)
# creating a map with measures we're more certain about
uncomfortable_map <- replication_base %>%
  summarize(count = n()) %>% filter(response %in% c("Not at all comfortable", "2")) %>%
  summarize(selected_count = sum(count)) %>%
  merge(country_counts) %>%
  mutate(negative2 = round(100 * selected_count / total, 2))
question_kind_dict = c("colleagues at work" = "How comfortable would you feel if one of your colleagues at work was a  ___?",
                       "love relationsship of child" = "How comfortable would you feel if one of your children was in a love relationship with ___?",
                       "elected politician" = "How comfortable would you feel if the politician in the highest elected office was a ___?")
uncomfortable_map %>% filter(isocntry %in% c("CZ"), question_kind != "showing affection in public") %>%
  ggplot(aes(y = question_kind, x = target, fill = negative2)) +
  facet_wrap(~ question_kind, ncol = 1, scales = "free", 
             labeller = labeller(question_kind = question_kind_dict)) + 
  geom_tile() +
  theme_minimal(base_size = 15) +
  theme(axis.text.y = element_blank(),
        axis.text.x = element_text(angle = 15, hjust = 1, size = 14),
        legend.position = "none",
        plot.margin = unit(c(1, 1, 1, 3), "cm")) +
  scale_fill_distiller(limits = c(0, 100), palette = "Reds", direction = 1) +
  geom_label(aes(label = paste0(negative2, "%")), color = "black") +
  ggtitle("Czech discomfort",
          subtitle = "Percentage of respondents who rated their comfort below 2 out of 10 (inclusive)") +
  labs(x = "", y = "")

I don’t like this visualization - there’s almost certainly a better way to go about doing this. It does get the point across, though: whatever their standing relative to the rest of Europe, there certainly are groups of people that Czechs openly admit being much less comfortable about than others.

7 Alternative 4: Use a better survey

“The European Social Survey measures the same thing better, so why do people keep using the Eurobarometer?” Indeed it does! Sort of. It asks the question in terms of “minding,” which some claim makes the Eurobarometer results different, and it only asks about immigrants of a different race or ethnicity. Here’s an overview for all surveyed countries.

# integrated data file for ESS 2014 - we're looking for "imdetmr"
ess14 <- read_dta("ESS7e02_1.stata/ESS7e02_1.dta")
ess14 %>% group_by(cntry) %>% summarize(n())
library(ggalt)
library(countrycode)
library(sjmisc)
ess14_sub <- ess14 %>% select(cntry, imdetbs, imdetmr, 
                              dweight, pweight, pspwght) %>% # weighting variables
  mutate_at(vars(imdetbs, imdetmr), 
            sjmisc::to_label) %>% 
  filter(cntry != "AT") # apparently, the question was improperly administered in Austria
ess14_overview <- ggplot(ess14_sub, aes(x = imdetmr)) +
  stat_count(mapping = aes(x = imdetmr, y = ..prop.., group = 1), width = 0.7) +
  scale_y_continuous(labels = percent) +
  facet_wrap(~ cntry, ncol = 4, 
             labeller = labeller(cntry = function(x) countrycode(x, "iso2c", "country.name", 
                                                                 custom_match = c("GB" = "Great Britain")))) +
  theme(axis.text.x = element_text(angle = 60, hjust = 1)) +
  geom_vline(xintercept = 11.5) +
  labs(title = paste0("How much you would mind or not mind if an immigrant of ",
                      "a different race \nor ethnic group married a close relative of yours?"),
       subtitle = "European Social Survey 2014, without weighting",
       x = "", y = "") +
  geom_rect(data = data.frame(cntry = c("CZ", "HU", "PL")), inherit.aes = FALSE, 
            fill = "blue", alpha = 0.1, xmin = -Inf, ymin = -Inf, 
            xmax = Inf, ymax = Inf)
ess14_overview

There’s a bunch of properties that make ESS a clumsy comparison. For one, it’s just not as detailed as Eurobarometer: it asks two questions about discomfort/minding and both are coached in general terms (“immigrant of a different race or ethnic group”), so we can neither do the “comfort with white person” sanity check nor can we match the question directly to any one EBM item. ESS also hasn’t included Slovakia, the one other country we know to show a similar pattern potentially related to mistranslation, so we can’t diagnose that either. Finally, ESS has 11 response-scale points contra EBM’s 10 + the “Indifferent option”.

Plus, y’know, different survey taken at a different time with a different methodology asking a different question.

But this entire exercise is about making do with what we have, so let’s compare with the closest EBM equivalent: attitudes towards potential black and Asian inlaws for the subset of countries that were surveyed in both.

(Note that the positive-to-negative direction is reversed in ESS – I didn’t want to mess with reverse scoring. I also drew the intersecting set of ESS/EBM countries manually, so I might have missed some.)

eb15_black_asian <- eb15 %>% select(isocntry, qc14_2, qc14_3) %>% 
  mutate_at(vars(qc14_2, qc14_3), to_label) %>%
  rename(black = qc14_2, asian = qc14_3) %>%
  gather(inlaw, response, black, asian) %>%
  mutate(response = fct_relevel(factor(response), "10 Totally comfortable", after = 9))
ebs_ess_countries <- c("CZ", "HU", "PL", "NL", "BE", "FR", "DK")
ebs_comparison <- eb15_black_asian %>% filter(isocntry %in% ebs_ess_countries)
ess_comparison <- ess14_sub %>% filter(cntry %in% ebs_ess_countries)
ebs_graph <- ggplot(ebs_comparison, aes(x = response)) + 
  facet_wrap(~ isocntry, ncol = 1, labeller = labeller(isocntry = ebs_country_dict)) + 
  stat_count(mapping = aes(y = ..prop.., fill = inlaw, group = inlaw), 
             position = position_dodge(), width = 0.7) +
  labs(x = "", y = "") +
  geom_vline(xintercept = 10.5) +
  theme(axis.text.x = element_text(angle = 60, hjust = 1), legend.position = "bottom") +
  scale_y_continuous(labels = percent, limits = c(0, .75)) +
  ggtitle("Eurobarometer 2015", 
          subtitle = paste0("How comfortable you would feel if one of your children was in \n",
                 "a love relationship with a black or an Asian person?")) 
ess_graph <- ggplot(ess_comparison, aes(x = imdetmr)) +
  stat_count(mapping = aes(x = imdetmr, y = ..prop.., group = 1), width = 0.7) +
  scale_y_continuous(labels = percent, limits = c(0, .75)) +
  facet_wrap(~ cntry, ncol = 1, 
             labeller = labeller(cntry = function(x) countrycode(x, "iso2c", "country.name"))) +
  theme(axis.text.x = element_text(angle = 60, hjust = 1)) +
  geom_vline(xintercept = 11.5) +
  xlab("") + ylab("") +
  ggtitle("European Social Survey 2014", 
          subtitle = paste0("How much you would mind or not mind if an immigrant of ",
                 "a different race \nor ethnic group married a close relative of yours?"))
combined_ebs_ess <- cowplot::plot_grid(ess_graph, ebs_graph, axis = "tblr", align = "h")
combined_ebs_ess

Most countries have a similar response distribution for both surveys, but the Czech one in ESS is noticeably flatter. Let’s look at the extreme ends of each survey’s scale to see how much the two surveys differed:

# Difference: compute percentages, rename levels ("most negative", "most positive"), merge, and make a lollipop chart of differences
ebm_minmax <- ebs_comparison %>% filter(inlaw == "black") %>% 
  group_by(isocntry, response) %>%
  summarize(response_count = n()) %>% 
  mutate(response_perc = response_count / sum(response_count)) %>%
  filter(response %in% c("1 Not at all comfortable", "10 Totally comfortable")) %>%
  ungroup() %>%
  transmute(cntry = isocntry, response_perc,
            response_kind = 
              fct_recode(response,
                         "Negative" = "1 Not at all comfortable",
                         "Positive" = "10 Totally comfortable") %>%
              as.character())
ess_minmax <- ess_comparison %>%  group_by(cntry, imdetmr) %>%
  summarize(response_count = n()) %>% 
  mutate(response_perc = response_count / sum(response_count)) %>%
  filter(imdetmr %in% c("Not mind at all", "Mind a lot")) %>%
  ungroup() %>%
  transmute(cntry, response_perc,
            response_kind = 
              fct_recode(imdetmr,
                         "Negative" = "Mind a lot",
                         "Positive" = "Not mind at all") %>%
              as.character())
ess_ebm_minmax_difference <- inner_join(ebm_minmax, ess_minmax, 
                                        by = c("cntry", "response_kind"), 
                                        suffix = c(".ebm", ".ess")) %>%
  mutate(ess_ebm_delta = response_perc.ess - response_perc.ebm)
Column `cntry` has different attributes on LHS and RHS of join
library(ggalt)
ggplot(data = ess_ebm_minmax_difference, aes(x = 100 * response_perc.ebm, 
                                             xend = 100 * response_perc.ess,
                                             y = cntry)) +
  geom_dumbbell(size_x = 1.8, size_xend = 2, 
                colour_x = "grey12", colour_xend = "dodgerblue2") + 
  facet_grid(. ~ response_kind, 
             labeller = labeller(response_kind = 
                                   c("Negative" = "Mind a lot (ESS) / Not comfortable at all (EBM)",
                                     "Positive" = "Don't mind at all (ESS) / Totally comfortable (EBM)"))) +
  # Unfortunately, since geom_dumbbell cannot create labels for us, we need to
  # draw them manually
  geom_text(data_frame(response_kind = c("Negative", "Negative", 
                                         "Positive", "Positive"), # for faceting
                       x_position = c(2.1, 19.3, 28.5, 38.2),
                       survey_name = c("ESS", "EBM", "ESS", "EBM")),
            inherit.aes = FALSE,
            mapping = aes(y = "PL", x = x_position, 
                          label = survey_name, color = survey_name),
            size = 2.5, fontface = "bold", nudge_y = 0.02) + 
  scale_color_manual(values = c("grey12", "dodgerblue2"), guide = "none") +
  scale_x_continuous(limits = c(0, 60), breaks = c(0, 15, 30, 45, 60)) +
  labs(x = "Percentage points", y = "",
       title = "Fight! European Social Survey 2014 vs. Eurobarometer 2015",
       subtitle = "(using question about potential black inlaws as proxy for the more general question in ESS)",
       caption = "Positive scores include the 4 most positive responses; in EBM, it also includes the 'Indifferent' answer.") +
  theme(plot.caption = element_text(color = "grey40", size = 8))

Bearing in mind the limitations of this comparison (different year, sample, and question mean that we cannot determine how much of the difference is due to measurement error and how much due to genuine attitude difference), allow me to draw your attention to a couple of things:

  • The Czech measure that jumped a lot is not the potentially mistranslated positive one; it’s the negative one. In other words, if the original map was based on ESS, it would look very similar.
  • It’s worth noting, though, that the Czech sample is the only one in which the positive rating decreased from ESS to EBM. (Well, technically, the Belgian sample saw a decrease as well, but one that was well within the margin of error.) This is weak evidence in support of the mistranslation hypothesis - arguendo, the mistranslation didn’t make a difference when it should have, thus exaggerating the true cross-country differences.
    • French was one of the original languages of the Eurobarometer survey, so - by definition - it could not have been mistranslated. Nonetheless, the 22-point rise in positive ratings from ESS to EBM is the largest of any changes - is it because that’s the “natural” result of the reframing? Or perhaps because there’s a larger difference in perception between “immigrant” and “black person” due to the number of French citizens from the overseas territories, so the compared question is not really the same? (Again, I find myself wishing that ESS asked the same questions as EBM.)
  • But there are a lot of country samples that were invariant to the different question and the different response scale, lending support to the idea that the measured construct - explicit admission of discomfort - is robust to different question phrasings in many European countries.

Again, due to the difference between the two surveys, we have to take the differences with a grain of salt. I really wish ESS did ask the same question.

7.1 Are there other ways to (in)validate the EBM results?

My cousin Jan suggested the racial-differences Implicit Association Test, which has some unfortunate issues. Perhaps someone has done the resume methodology? I will be grateful for suggestions – like I said, this is neither my circus nor my monkeys.

8 Making new maps

My original goal was to remake and play around with the little map. This took me the longest and I went through a bunch of attempts, which will in time get their own article.

## Setup
library(tmap)
library(tmaptools)
data(Europe)
convertEBMCountryCodes <- function(isocntry_column) {
  countrycode::countrycode(isocntry_column, "iso2c", "iso3c", 
                           custom_match = c("GB-NIR" = "GBR",
                                            "GB-GBN" = "GBR",
                                            "DE-E" = "DEU",
                                            "DE-W" = "DEU"))
}
# This is a different reshaping of the data
mappable_ebm <- eb15_comfort_wide %>%
  mutate(iso_a3 = convertEBMCountryCodes(isocntry))
ebm_country_counts <- eb15 %>% 
  mutate(iso_a3 = convertEBMCountryCodes(isocntry)) %>%
  group_by(iso_a3) %>%
  summarize(total_respondents = n())
mappable_prepped <- mappable_ebm %>% 
  mutate(response = fct_collapse(as.factor(response), 
                                 "Uncomfortable" = c("Not at all comfortable",
                                                     "2"),
                                 "Comfortable" = c("7", "8", "9", "Totally comfortable", "Indifferent"))) %>%
  mutate_at(vars(iso_a3, question_kind, target), as.factor) %>%
  group_by(iso_a3, question_kind, target, response) %>%
  summarize(response_count = n())
mappable_uncomfortable <- mappable_prepped %>%
  filter(response == "Uncomfortable") %>%
  merge(ebm_country_counts) %>%
  mutate(uncomfortable_percent = 100 * response_count / total_respondents) %>%
  select(iso_a3, question_kind, target, uncomfortable_percent)
mappable_comfortable <- mappable_prepped %>%
  filter(response == "Comfortable") %>%
  merge(ebm_country_counts) %>%
  mutate(comfortable_percent = 100 * response_count / total_respondents) %>%
  select(iso_a3, question_kind, target, comfortable_percent)
mappable_both <- full_join(mappable_comfortable, mappable_uncomfortable,
                           by = c("iso_a3", "question_kind", "target"))
# and reshape the data from ESS to be plottable alongside
mappable_ess <- ess14_sub %>%
  mutate(iso_a3 = countrycode::countrycode(cntry, "iso2c", "iso3c")) %>%
  mutate(imdetmr = fct_collapse(imdetmr, 
                                "Comfortable" = c("Not mind at all", "1", "2", "3"),
                                "Uncomfortable" = c("9", "Mind a lot"))) %>%
  group_by(iso_a3, imdetmr) %>% summarize(response_count = n()) %>%
  mutate(response_percentage = 100 * (response_count / sum(response_count))) %>%
  select(-response_count) %>%
  filter(imdetmr %in% c("Comfortable", "Uncomfortable")) %>%
  spread(imdetmr, response_percentage) %>% ungroup()
## Workhorse function for map display
# expects a long dataset that is ready for a merge by `iso_a3` column
mapLoveComfort <- function(dataset, target_name, column_of_interest = "comfortable_percent",
                           column_title = "% totally comfortable\n(7-10 on scale or answered 'Indifferent')", 
                           palette = "RdYlGn") {
  append_data(Europe, dataset %>%
                filter(question_kind == "love relationsship of child",
                       target == target_name),
              "iso_a3", "iso_a3", ignore.na = TRUE, 
              ignore.duplicates = TRUE) %>%
    tm_shape() +
    tm_polygons(column_of_interest,
                title = column_title,
                palette = palette,
                auto.palette.mapping = FALSE,
                breaks = seq.int(0, 100, 10), 
                legend.format = function(x) paste0(x, "%")) +
    tm_layout(legend.outside = F, legend.position = c("RIGHT", "TOP"),
              legend.frame = T, 
              main.title = paste0("How comfortable would you feel if your child\nwas in ",
                                  "a love relationship with a ", R.utils::capitalize(target_name), "?"),
              main.title.size = 1)
}
targets <- paste0(c("black", "asian", "muslim", "jewish"), " person")

8.1 Replicating the original map

This is, sort of, the original map. The main difference is that it uses yellow midpoints for the transition between red and green.

original_comfort_maps <- sapply(targets, function(x) mapLoveComfort(mappable_both, x, column_of_interest = "comfortable_percent"), simplify = FALSE)
do.call(tmap_arrange, original_comfort_maps)

This is an improvement on the original map’s colorscheme, I think. There’s still an implication that the green areas are “correct”, though, which misleadingly suggests a normative criterion at >50% “comfortable” population, so…

8.1.1 The original map with a better color scale

…we can make a single-color map, which also has the benefit of not being an asshole to people with red-green colorblindness.

original_comfort_maps <- sapply(targets, function(x) mapLoveComfort(mappable_both, x, column_of_interest = "comfortable_percent", palette = "-Reds"), simplify = FALSE)
do.call(tmap_arrange, original_comfort_maps)

8.2 The European Social Survey “comfort” map

As a relevant comparison, we can, of course, take a look at the European Social Survey’s most positive responses. For clarity’s sake, I show them using both palettes.

ess_common_map <- append_data(Europe, mappable_ess,
                              "iso_a3", "iso_a3", ignore.na = TRUE, 
                              ignore.duplicates = TRUE) %>%
  tm_shape() +
  tm_layout(legend.outside = F, legend.position = c("RIGHT", "TOP"),
            legend.frame = T, 
            main.title = paste0("How comfortable would you feel if your child\nwas in ",
                                "a love relationship with an immigrant?"),
            main.title.size = 1)
ess_single_palette_map <- ess_common_map + tm_polygons("Comfortable",
              title = "% comfortable (7 to 'Not mind at all')",
              palette = "-Reds",
              auto.palette.mapping = FALSE,
              breaks = seq.int(0, 100, 10), 
              legend.format = function(x) paste0(x, "%"))
ess_original_palette_map <- ess_common_map + tm_polygons("Comfortable",
              title = "% comfortable (7 to 'Not mind at all')",
              palette = "RdYlGn",
              auto.palette.mapping = FALSE,
              breaks = seq.int(0, 100, 10), 
              legend.format = function(x) paste0(x, "%"))
tmap_arrange(ess_single_palette_map, ess_original_palette_map)

8.3 The conservative “discomfort” map

As noted in the Methodological criticisms section, we have a bunch of reasons to think that the extreme negative end of the scale might be more informative than the positive end.

In this case, we’ve applied stricter inclusion criteria – we only take the lowest two points rather than the lowest four.

original_discomfort_maps <- sapply(targets, function(x) mapLoveComfort(mappable_both, x, column_of_interest = "uncomfortable_percent", column_title = "% not at all comfortable\n(1 or 2 on scale)",  palette = "Reds"), simplify = FALSE)
do.call(tmap_arrange, original_discomfort_maps)

This makes my homeland look much less anti-Semitic, so hurray!

8.3.1 Conservative “discomfort” measure with the original palette

Finally, just because we can, here’s the same map with the original colors.

ebm_discomfort <- sapply(targets, function(x) mapLoveComfort(mappable_both, x, column_of_interest = "uncomfortable_percent", column_title = "% not at all comfortable\n(1 or 2 on scale)",  palette = "-RdYlGn"), simplify = FALSE)
do.call(tmap_arrange, ebm_discomfort)

9 Motivations and limitations

Since my motivations for writing this are going to come up, I thought I’d supply a couple of answers. (This is, of course, to divert the pure of heart away from the (((TrUtH))). You caught me.)

9.1 Who’s paying you?

Not George Soros, although back in ninth grade, I really wanted him to. Over the years, I’m afraid I actually spent much more time on Charles Koch’s dime. I was a Bakala Scholar, which would ~exPlain tHings~, but also a Kellner Family Scholar, which… wouldn’t. Hilariously enough, to the best of my knowledge, I have never received an EU grant.

Right now, the only institution that’s paying me is Yale, but not for this.

If you’re seeking to impute impure incentives to me, my list of past funding sources might prove confusing. It might almost be simpler to imagine that some people might hold beliefs that are independent of their funding.

To suggest an alternative to the monetary motive, I’d like to share three things about myself:

  1. I like detailed open data and the level of Eurobarometer’s coverage was delightful. Dismissing it out of hand seems wasteful.
  2. I like butting into arguments that allow for empirical counter-claims.
  3. I get stuck on interesting problems, especially when people are eager to argue about them.

9.2 You’re just protecting a study that confirms your beliefs!

You’re just dismissing a study that questions your beliefs! See how this is not a useful criticism? Nobody is free of cognitive biases.

But we can take a look at the data, make our best arguments, and see if others can tear them down in a way that makes us discard them. I might not change your mind and you might not change mine (though I’ll try!), but we don’t just do it for ourselves; we do it so that the people who aren’t as invested in the question can make a better decision. My epistemology needs not be flawless to benefit the community epistemics.

Honestly, what animates me the most in writing this post is the blithe dismissal of a survey that is carefully documented, its raw data publicly available, and its scope narrow enough that it can ask questions at a very granular level. It collected a large sample using in-person interviews, taking care to obtain geographical variability within each country. It actually did try to guard against mistranslation by implementing a back-translation step. In short, the people begind Eurobarometer did a lot of things right.

Some have called #OpenScience mere methodological terrorism. As that line of argument goes, we’re just mean bullies seeking to find a couple of flaws in order to discredit a whole research program. If we’ve become large, the critique goes, it is because we’re standing on the corpses of well-meaning colleagues. My preferred response to that criticism is giving credit where it’s due.

I care about the quality of science. I care about the quality of science a lot. In the past couple of years, this has often meant cutting away sloppy and/or underpowered research in order to reduce false positives. But it’s important to remember that we’re trying to reach a balance between Type I and Type II errors here, though: there’s an amount of error that’s sufficient to dismiss a dataset, but it’s not any amount.

(In other words, it’s that sweet, sweet Arnold Foundation cash I’m after.)

Which doesn’t actually mean that I’m letting Eurobarometer of the hook.

9.3 There are not the limitations you are looking for

In a real sense, much of the criticism misses the forest for the trees. It’s nitpicking, whether or not the nits are there, because nit-sized problems we can deal with.

Does any of the critiques I addressed matter? Even if the survey translation achieved perfect fidelity across languages and the original questions were phrased so that they avoided biasing the respondents, it would still be a social-science instrument which, along with everything, is fucked.

In one sense, this survey is fine. It attempted to observe an accurate estimate of the response distribution, sampling the population evenly; within its constraints, it succeeded. Interpretations and inferences are our problem, as is overcoming the inevitable conceptual challenges on the way. You wouldn’t blame the Apollo Command Module for its inability to land on the Moon. It isn’t a problem that we need the wider tapestry of research findings to embed this one in a context.

It’s important to note that the survey doesn’t go for any underlying constructs. Nobody claims that the questions predict particular behaviors. We do with this survey what we do with most surveys: describe it thoroughly, then wave it suggestively.

But then there’s a list of potential methodological issues that is longer than my arm. The thing with that list is that you can’t win. Doing in-person interviews? Some people will give answers to please the recruiter, not accurate self-report. Sending out an internet survey? You probably don’t have a representative sample. If your question doesn’t bias the respondent negatively, it’s probably just because it’s biasing them in the opposite direction. Should you count the 11% of people reporting the belief that the country is or might be run by lizardmen? Include them and your aggregate will get a lot of noise; omit them and you’re undersampling the conspiracy theorists.

(If you want to read a thorough takedown of “asking people things is useful,” Bertrand and Mullainathan (2001) provide a particularly vicious lashing, which nonetheless includes a measurement error perspective. Most of their examples and logic come from Plous (1993).)

Each decision in designing a study has to find the lesser evils. I can’t think of a design that is beyond reproach. Everywhere you look, you have to deal with imperfection.

This is what makes social science hard.

9.4 Quantifying the error

The original Eurobarometer Report’s Technical Appendix provides a table that gives the percentage-point margin of error. I assume that this margin accounts for sampling error. With the data and the criticisms we have, we can enlarge the margin by each of the following:

  • semantic shifts between translations (5-10 percentage points, based on the analysis above)
  • respondent error (3-5 percentage points, based on the analysis above)
  • people trolling (3-5 percentage points)

(I’m not including the social desirability bias because I think that’s a part of the construct under measurement. If you wish to use this study to estimate possible racist behavior, feel free to tack on that error, too.)

Am I pulling these out of my butt? You bet, but I think these are pretty pessimistic numbers, and it’s not like you don’t have them. For example, if you’re dismissing the study outright, then the error bars you assign must be unable to distinguish between 0% and 100% response. Since surveys will always contain errors, I’d say this framework is more useful than a blanket rejection – or a blanket acceptance – of a survey. For one, the framework also forces you to be explicit about the things that you consider well done.

Let’s assume the worst-case scenario: each of the errors is independent of others and all are on the higher end of the range. If we sum them up, we end up with a margin of error of twenty-something percentage points. With these error bars, the cross-country comparison is much rougher – but we can still say with some confidence that former Czechoslovakia has a larger explicit anti-Roma attitude problem than most of Europe.

9.5 …so what you’re saying is that social science is useless?

I prefer the term differently useful. No. I’m saying that if you’re going to dismiss a social-science result, you should do that on the basis of problems it actually has, and only to the extent that those problems warrant. The measurement crisis is upon us; let’s cut through the bullshit and talk about the problems that actually matter.

If that makes you not at all comfortable, good; me too.

10 References

Bertrand, Marianne, and Sendhil Mullainathan. 2001. “Do People Mean What They Say? Implications for Subjective Survey Data.” papers.ssrn.com. doi:10.2139/ssrn.260131.

Plous, Scott. 1993. “The Effects of Question Wording and Framing.” In The Psychology of Judgment and Decision Making, 65–76. McGraw-Hill Book Company. http://psycnet.apa.org/psycinfo/1993-97429-000.

LS0tCnRpdGxlOiAiSG93IHByZWp1ZGljZWQgYXJlIHdlIHJlYWxseT8gT25lIG1vcmUgbG9vayBhdCB0aGF0IDIwMTUgRXVyb2Jhcm9tZXRlciIKYXV0aG9yOiAiU2ltb24gUG9kaGFqc2t5IgpkYXRlOiAiMjcgQXVndXN0IDIwMTciCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICBmaWdfaGVpZ2h0OiA2CiAgICBmaWdfd2lkdGg6IDgKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICB0aGVtZTogY29zbW8KICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGZpZ19oZWlnaHQ6IDYKICAgIGZpZ193aWR0aDogOAogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRoZW1lOiBjb3NtbwogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCmJpYmxpb2dyYXBoeTogc3VydmV5X2xpbWl0YXRpb25zLmJpYgotLS0KClRoaXMgdmlzdWFsaXphdGlvbiBuZXJkLXNuaXBlZCBtZSB+fnRvZGF5fn4gdHdvIHdlZWtzIGFnbyAoW3NlZSBvcmlnaW5hbCBSZWRkaXQgdGhyZWFkXShodHRwczovL3d3dy5yZWRkaXQuY29tL3IvTWFwUG9ybi9jb21tZW50cy82dDQxdm0vZXVfd291bGRfeW91X2ZlZWxfY29tZm9ydGFibGVfaWZfeW91cl9jaGlsZF93YXMvKSkuIEl0IGlzIGJhc2VkIG9uIHRoZSBTcGVjaWFsIEV1cm9iYXJvbWV0ZXIgMjAxNSAoRUJNKSBhbmQgaXQgc3VnZ2VzdHMgYWxsIGtpbmRzIG9mIGhvcnJpYmxlbmVzcyBhYm91dCBteSBob21lIGNvdW50cnk6CgohW18oSGVhdG1hcCBvZiBFdXJvcGUsIGNvbG9yZWQgYnkgcmVzcG9uc2VzIHRvIHRoZSBTcGVjaWFsIEV1cm9iYXJvbWV0ZXIgMjAxNSBxdWVzdGlvbiAiV291bGQgeW91IGZlZWwgY29tZm9ydGFibGUgaWYgb25lIG9mIHlvdXIgY2hpbGRyZW4gd2FzIGluIGEgcmVsYXRpb25zaGlwIHdpdGggYW4gWCBwZXJzb24/IikgRm9yIG15IG5vbi1FdXJvcGVhbiBmcmllbmRzLCBteSBob21lIGNvdW50cnkgaXMgdGhlIHJlZCBvbmUgaW4gdGhlIGNlbnRlci1sZWZ0Ll9dKGh0dHBzOi8vaS5yZWRkLml0L2JmZzJuZGg3ODZmei5wbmcpCgpUaGlzIGxvb2tzIGFsbCBzb3J0cyBvZiB1bnBsZWFzYW50LiBNb3JlIHRvIHRoZSBwb2ludCwgaXQgbG9va3MgX3dyb25nXy4gQ3plY2hzIHRoaW5rIG9mIHRoZW1zZWx2ZXMgYXMgdGhlIGNvb2wgc3RvbmVyIHVuY2xlIG9mIHRoZSByZWdpb24sIHNlY3VsYXIgYW5kIGNvbG9yYmxpbmQgYW5kIGxpdmUtYW5kLWxldC1saXZlLiBDb3VsZCB3ZSByZWFsbHkgYmUgdGhpcyBiYWQ/IE1vcmUgaW1wb3J0YW50bHkgLSBzdXJlLCB3ZSd2ZSBoYWQgc29tZSBpc3N1ZXMgcmVjZW50bHksIGJ1dCBob3cgY291bGQgQ3plY2hsYW5kIGJlY29tZSBtb3JlIHhlbm9waG9iaWMgdGhhbiBfUG9sYW5kXz8gKEh1bW9yb3VzIHRvbmd1ZS1pbi1jaGVlayBuYXRpb25hbGlzdCBjaGF1dmluaXNtIGlzIHRvIEV1cm9wZSBhcyBiYXNlYmFsbCBpcyB0byB0aGUgVVMuIFlvdSBjYW4gc2VlIGhvdyB0aGlzIGNvdWxkIGxlYWQgdG8gcHJvYmxlbXMuKQoKU28sIGlzIGl0IGEgc3VydmV5IGFydGlmYWN0IG9yIGlzIGl0IHJlYWw/IENhbiB3ZSBwZXJoYXBzIGRpc21pc3MgaXQgYXMgbm9pc2UgZHJpdmVuIGJ5IGEgbWlzdHJhbnNsYXRpb24/IEluIHRlcm1zIG9mIG1lY2hhbmlzbSwgY2FuIHRoZSBkYXRhc2V0IHN1Z2dlc3QgYW55PyBDb3VsZCB0aGlzLCBmb3IgaW5zdGFuY2UsIGJlIGRyaXZlbiBieSB0aGUgdXJiYW4tcnVyYWwgZ2FwPyAKCkx1Y2tpbHksIHRoaXMgd2FzIGRhdGEgZnJvbSB0aGUgU3BlY2lhbCBFdXJvYmFyb21ldGVyIDIwMTUsIHNvIGl0J3MgcHVibGljbHkgYWNjZXNzaWJsZSBhbG9uZyB3aXRoIGNvbXBsZXRlIGRvY3VtZW50YXRpb24uIFRoYXQgbWVhbnMgd2UgY2FuIHBva2UgaXQuIEkga2VwdCB0aGlzIFJNYXJrZG93biBub3RlYm9vayB0byByZXRyYWNlIG15IHN0ZXBzLCBzbyB0aGF0IHlvdSBjYW4gcG9rZSBpdCB0b28uIChZb3UgY2FuIGRvd25sb2FkIGl0IGZyb20gdGhlIHRvcC1yaWdodCBidXR0b24uKSBOb3RlIHRoYXQgSSB1c3VhbGx5IGhhdmVuJ3QgZ29uZSBiYWNrIHRvIHJlLXZpc3VhbGl6ZSBlYXJseSBncmFwaHMgb24gdGhlIGJhc2lzIG9mIGxhdGVyIGV4cGxvcmF0aW9ucy4KClRoaXMgaXMgZXF1YWwgcGFydHMgYSBkYXRhc2V0IGV4cGxvcmF0aW9uIGFuZCBkYXRhLXRpZHlpbmcgZXhlcmNpc2Ugc28gaWYgeW91J3JlIGhlcmUgdG8gdGFsayBhYm91dCB3aHkgYWxsIG9mIHRoaXMgaXMgYnVsbGNyYXAsIGZlZWwgZnJlZSB0byBza2lwIHRoZSBwYXJ0cyB3aXRoIFIgY29kZSBhbmQgZ28gc3RyYWlnaHQgdG8gW3RoZSBkaXNjdXNzaW9uIG9mIHZhbGlkaXR5XSgjbWV0aG9kb2xvZ2ljYWwtY3JpdGljaXNtcykuCgojIEdldHRpbmcgdGhlIGRhdGEKCkV1cm9iYXJvbWV0ZXIgcmVsZWFzZXMgaXRzIGZ1bGwgZGF0YXNldCwgd2hpY2ggaXMgYWxzbyBpbmRleGVkIGJ5IHNvY2lhbC1zY2llbmNlIGFnZ3JlZ2F0b3JzIGxpa2UgW0lDUFNSXShodHRwczovL3d3dy5pY3Bzci51bWljaC5lZHUvaWNwc3J3ZWIvKSBhbmQgW0dFU0lTLl0oaHR0cHM6Ly93d3cuZ2VzaXMub3JnL2hvbWUvKSBVc2luZyB0aGUgYGdlc2lzYCBwYWNrYWdlLCBleHRyYWN0aW5nIHRoZSBkZXNpcmVkIEV1cm9iYXJvbWV0ZXIgZGF0YSBpcyBlYXN5LiAoVGhlIG9ubHkgZGlmZmljdWx0IHBhcnQgd2FzIGRldGVybWluaW5nIHdoaWNoIEV1cm9iYXJvbWV0ZXIgdG8gZG93bmxvYWQgYmVjYXVzZSBHRVNJUyBmb2xsb3dzIHRoZSBvcmlnaW5hbCBFQk0gbnVtYmVyaW5nIGNvbnZlbnRpb24gb2YgYChzdXJ2ZXkgcm91bmQgIykuKHdhdmUgIylgLCB3aGVyZWFzIHRoZSBFQk0gcmVwb3J0cyB1c3VhbGx5IGdvIGJ5IGEgc2luZ2xlLWludGVnZXIgSUQuIEhlcmUsIHdlIGtuZXcgd2hhdCB5ZWFyIHdlIHdhbnRlZCwgc28gZmluZGluZyB0aGUgR0VTSVMgZXF1aXZhbGVudCB3YXMgYSBtYXR0ZXIgb2Ygb25lIEdvb2dsZSBzZWFyY2guKQoKWW91IHdpbGwgaGF2ZSB0byByZWdpc3RlciBmb3IgZnJlZSBhbmQgdXNlIHRob3NlIGNyZWRlbnRpYWxzIHRvIGRvd25sb2FkIHRoZSBkYXRhc2V0LgoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnNldHdkKCJ+L0NvZGluZy9lYm0yMDE1LyIpCmxpYnJhcnkoZ2VzaXMpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGhhdmVuKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoc2NhbGVzKQpsaWJyYXJ5KGdnYWx0KQpsaWJyYXJ5KGNvdW50cnljb2RlKQpsaWJyYXJ5KHNqbWlzYykKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KHByaW50cikKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KGZvcmNhdHMpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KGNvdW50cnljb2RlKQp0aGVtZV9zZXQodGhlbWVfYncoKSkKYGBgCmBgYHtyLCBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBjYWNoZT1UUlVFfQojIExvb2sgYXQgYXZhaWxhYmlsaXR5CnN0dWR5X3R5cGVzIDwtIGdlc2lzOjpnZXRfc3R1ZHlfZ3JvdXBzKCkKZGF0YXNldHMgPC0gICAgZ2VzaXM6OmdldF9kYXRhc2V0cygiMDAwOCIpICMgRUIgLSBTdGFuZGFyZCBhbmQgU3BlY2lhbCBFdXJvYmFyb21ldGVyCmdlc2lzX2xvZ2luIDwtIGdlc2lzOjpsb2dpbih1c2VybmFtZSA9ICJzaW1vbi5wb2RoYWpza3lAZ21haWwuY29tIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3N3b3JkID0gU3lzLmdldGVudignR0VTSVNfUFdEJykpICMgU2F2ZWQgaW4gLlJlbnZpcm9uCiMgSWYgeW91J3JlIG5vdCBwbGFubmluZyB0byBzaGFyZSB5b3VyIGNvZGUsIHlvdSBjb3VsZCB0eXBlIGluIHlvdXIgcGFzc3dvcmQKIyBhYm92ZSwgYnV0IHlvdSBzaG91bGQgcmVhbGx5IGdldCB1c2VkIHRvIHN0b3JpbmcgeW91ciBzZWNyZXRzIGVsc2V3aGVyZS4KCmdlc2lzOjpkb3dubG9hZF9kYXRhc2V0KHMgPSBnZXNpc19sb2dpbiwgZG9pID0gNjU5NSkgIyBFdXJvYmFyb21ldGVyIDgzLjQgKDIwMTUpCiMgcGFzdDoKIyAtIDIwMTI6IDc3LjQgKERPSSA1NjEzKQojIC0gMjAwOTogNzEuMiAoRE9JIDQ5NzIpCiMgLSAyMDA4OiA2OS4xIChET0kgNDc0MykKIyAtIDIwMDc6IDY1LjQgKERPSSA0NTA4KQojIC0gMjAwMjogNTcuMCAoRE9JIDM2MzgpCiMgZ2VzaXM6OmRvd25sb2FkX2NvZGVib29rKGRvaSA9IDY1OTUpICMgZXJyb3JzIG91dCwgZm9yIHNvbWUgcmVhc29uCmBgYAoKRG93bmxvYWRpbmcgdGhlIGNvZGVib29rIGZyb20gdGhlIEdFU0lTIEFQSSBoYXNuJ3Qgd29ya2VkIGZvciBtZSwgc28geW91IGNhbiBbZ2V0IGl0IGZyb20gSUNQU1IgaW5zdGVhZF0oaHR0cDovL3d3dy5pY3Bzci51bWljaC5lZHUvY2dpLWJpbi9maWxlP2NvbXA9bm9uZSZzdHVkeT0zNjQwMyZkcz0xJmZpbGVfaWQ9MTIxNzY3MyZwYXRoPUlDUFNSKS4KCmBgYHtyfQojIFRoZXJlJ3Mgbm8gY29udHJvbCBvdmVyIHRoZSBuYW1pbmcgb2YgdGhlIHNhdmVkIGZpbGUsIHNvIHlvdSdsbCBoYXZlCiMgdG8gdGFrZSBhIGxvb2sgdG8gbWFrZSBzdXJlIHlvdSdyZSBsb2FkaW5nIHRoZSByaWdodCBvbmUgLSBidXQgR0VTSVMKIyB3aWxsIHNhdmUgZWFjaCBzdXJ2ZXkgdW5kZXIgYSBjb25zaXN0ZW50IGZpbGVuYW1lLCBzbyBhdCBsZWFzdCB5b3UndmUKIyBnb3QgdGhhdAplYjE1IDwtIHJlYWRfZHRhKCJaQTY1OTVfdjItMC0wLmR0YSIpCmRpbShlYjE1KQpgYGAKClRoYXQncyBhIGxvdCBvZiBFdXJvYmFyb21ldGVyIGRhdGEhIEJ1dCBldmVuIHdpdGhvdXQgW2Rvd25sb2FkaW5nIHRoZSBjb2RlYm9va10oaHR0cDovL3d3dy5pY3Bzci51bWljaC5lZHUvY2dpLWJpbi9maWxlP2NvbXA9bm9uZSZzdHVkeT0zNjQwMyZkcz0xJmZpbGVfaWQ9MTIxNzY3MyZwYXRoPUlDUFNSKSwgdGhlIHN0cnVjdHVyZSBpcyB3ZWxsLWRvY3VtZW50ZWQgaW4gdGhlIGRhdGEgZnJhbWUgYXR0cmlidXRlcy4gVGhpcyBtZWFucyB0aGF0IHdlIGNhbiB0YWtlIGEgbG9vay1zZWUuCgpgYGB7ciwgcmVzdWx0cz0iaGlkZSJ9CiMgQSBsb3Qgb2Ygd2VsbC1kb2N1bWVudGVkIHZhcmlhYmxlcyAtLSBzbyBtYW55IHRoYXQgaXQgb3ZlcndoZWxtcyBSIGNvbnNvbGUsCiMgc28gd2UnbGwgc2F2ZSB0aGUgb3V0cHV0IGludG8gYSBmaWxlIGFuZCBsb29rIGl0IG92ZXIgaW4gYSB0ZXh0IGVkaXRvciBvcgojIHdvcmsgaXQgd2l0aCBncmVwCnNpbmsoImxhYmVscy50eHQiKQooZWIxNV9sYWJlbHMgPC0gc2FwcGx5KG5hbWVzKGViMTUpLCBmdW5jdGlvbih4KSBhdHRyaWJ1dGVzKGViMTVbW3hdXSkpKQpzaW5rKCkKYGBgCgojIyBCYXNpYyBwcm9wZXJ0aWVzCgpFYWNoIHJvdyBpcyBhIHJlY29yZCBvZiBvbmUgaW50ZXJ2aWV3LiBHcm91cGluZyBieSBjb3VudHJ5IHJldmVhbHMgdGhhdCBlYWNoIGhhcyBhIHNhbXBsZSBvZiBhYm91dCBhIHRob3VzYW5kLCBleGNlcHQgZm9yIE1vbnRlbmVncm8sIE5vcnRoZXJuIElyZWxhbmQsIEx1eGVtYm91cmcsIGFuZCBmb3JtZXIgRWFzdCBHZXJtYW55OgoKYGBge3J9CiMgTG9vayBvdmVyIHNhbXBsZSBzaXplIHBlciBjb3VudHJ5CmViMTUgJT4lIGdyb3VwX2J5KGlzb2NudHJ5KSAlPiUgc3VtbWFyaXplKG4oKSkKYGBgCgpPdGhlciBpZGVudGlmeWluZyBpbmZvIEkgY2FyZSBhYm91dCBpcyBhIGxpc3RlZCBuYXRpb25hbGl0eSAod2hpY2ggaXMgbm90IHRoZSBzYW1lIGFzIGNvdW50cnkgb2YgaW50ZXJ2aWV3IC0gQ3plY2hzIGNhbiBiZSBpbnRlcnZpZXdlZCBhYnJvYWQsIGR1YWwgY2l0aXplbnNoaXAgaXMgYSB0aGluZywgLi4uKSwgc2l6ZSBvZiBjb21tdW5pdHkgdGhlIHJlc3BvbmRlbnQgbGl2ZXMgaW4gKHN0b3JlZCBzZXBhcmF0ZWx5IGZvciBlYWNoIGNvdW50cnkgaW4gYHA2KmAgY29sdW1ucywgYnV0IHNhbWUgZm9yIHRoZSBWNCBjb3VudHJpZXMpLCBhbmQgcmVnaW9uIG9mIG9yaWdpbiBhdCBOVVRTLTIgbGV2ZWwuIChFYWNoIHJlZ2lvbiBpbiBlYWNoIGNvdW50cnkgaXMgc2FtcGxlZCByb3VnaGx5IGVxdWFsbHkuIEkgZG9uJ3Qga25vdyBleGFjdGx5IGhvdyB0aGUgYXV0aG9ycyBvZiB0aGUgc3VydmV5IGRvIHRoZWlyIHN0cmF0aWZpZWQgc2FtcGxpbmcsIHNvIGl0J3MgcG9zc2libGUgdGhhdCBJJ20gbWlzc2luZyBzb21lIHJlLXdlaWdodGluZy4pCgpUaGUgbWVhc3VyZXMgSSBjYXJlIGFib3V0IHRoZSBtb3N0IHdlcmUgImNvbWZvcnQgd2l0aCBYIGNvd29ya2VyIiBhbmQgImNvbWZvcnQgd2l0aCBYIGNoaWxkLWluLWxhdyIuIEZvciBlYWNoIHZhbHVlIG9mIFgsIHRoZXNlIGFyZSBzdG9yZWQgaW4gY29sdW1ucyBgcWMxM18qYCBhbmQgYHFjMTRfKmAsIHJlc3BlY3RpdmVseS4gVGhlcmUncyBhIGxvdCBvZiBvdGhlciBpbnRlcmVzdGluZyBnb29kaWVzLCBidXQgdGhlc2Ugd2lsbCBkbyBmb3Igbm93LiAKCiMgQSBmaXJzdCBsb29rOiByZXNwb25zZXMgdmVyc3VzIGNvbW11bml0eSBzaXplCgpUbyBtYWtlIG91ciBhbmFseXNpcyBlYXNpZXIsIHdlIGV4dHJhY3QgY29sdW1ucyBvZiBpbnRlcmVzdCBhbmQgdGhlbiBjb252ZXJ0IHRoZSBhdHRpdHVkZSBxdWVzdGlvbnMgZnJvbSB3aWRlIHRvIGxvbmcuIFdlJ2xsIGFsc28gbGFiZWwgc29tZSBvZiB0aGUgdmFsdWVzIHRvIG1ha2UgdmlzdWFsaXphdGlvbiBlYXNpZXIuCgpgYGB7ciwgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KIyBJZGVudGlmaWVyczogaXNvY250cnksIHExXzE3ID0gQ3plY2ggbmF0aW9uYWxpdHksIHExXzI0ID0gU2xvdmFrIG5hdGlvbmFsaXR5CiMgT3RoZXI6IHA2Y3ogKHNpemUgb2YgY29tbXVuaXR5IGluIENaKSwgcDdjeiAoTlVUUyAyIHJlZ2lvbmFsIGNvZGUpCiMgcWMxXyo6IHBlcmNlcHRpb24gb2YgZGlzY3JpbWluYXRpb24gb24gdGhlIGJhc2lzIG9mIFggaW4gY291bnRyeQojIHFjMl8qOiBleHBlcmllbmNlZCBkaXNjcmltaW5hdGlvbiBvbiB0aGUgYmFzaXMgb2YgWAojIHFjM18qOiBqb2IgY2FuZGlkYXRlIGlzIGF0IGEgZGlzYWR2YW50YWdlIGJlY2F1c2Ugb2YgWAojIHFjNF8qOiBjb21mb3J0YWJsZSB3aXRoIGhpZ2hlc3QgZWxlY3RlZCBwb2xpdGljaWFuIHdobyBpcyBYCiMgcWM1Xyo6IHN1cHBvcnQgdnMuIG9wcG9zZSBkaXZlcnNpdHkgbWVhc3VyZXMgYXQgd29yawojIHFjNjogcmF0aW5nIG9mIGVmZmVjdGl2ZW5lc3Mgb2YgZWZmb3J0cyB0byBmaWdodCBkaXNjcmltaW5hdGlvbgojIHFjN18qOiBlbm91Z2ggYmVpbmcgZG9uZSB0byBwcm9tb3RlIGRpdmVyc2l0eQojIHFjMTJfKjogZGl2ZXJzaXR5IHN1ZmZpY2llbnRseSByZWZsZWN0ZWQgaW4gdGhlIG1lZGlhCiMgcWMxM18qOiBjb21mb3J0IHdpdGggY29sbGVhZ3VlIGF0IHdvcmsgd2hvIGlzIFgKIyBxYzE2Xyo6IGVxdWFsLXJpZ2h0cyBzdGF0ZW1lbnRzIGZvciBnYXkvdHJhbnMgcHBsCiMgcWMxOF8qOiBjb21mb3J0IHdpdGggWCBwZW9wbGUgc2hvd2luZyBhZmZlY3Rpb24gaW4gcHVibGljCiMgc2QxXyo6IGhhZCBjb250YWN0IHdpdGggbWlub3JpdHkgWAojIHNkMl8qOiBjb25zaWRlciB5b3Vyc2VsZiBhIG1pbm9yaXR5IFgKIyBzZDM6IHlvdXIgcmVsaWdpb24KIyBkMTogbGVmdC1yaWdodCBwb2xpdGljYWwgcGxhY2VtZW50CiMgZDEwOiBnZW5kZXIKIyBkMTE6IGFnZQojIGQ4OiBzdG9wcGVkIHN0dWR5aW5nIGF0IGFnZQojIGQyNTogY29tbXVuaXR5IGtpbmQvc2l6ZQojIGQ2MDogZWNvbm9taWMgZGlmZmljdWx0eSAocGF5aW5nIHRoZSBiaWxscykKIyBkNjM6IFNFUyBzZWxmLXBsYWNlbWVudAojIGQ3MDogc2F0aXNmaWVkIHdpdGggbGlmZSB5b3UgbGVhZAojIGQ3NzogdHJ5aW5nIHRvIHBlcnN1YWRlIGZyaWVuZHMKIyBkNzJfKiBteSB2b2ljZSBjb3VudHMgaW4gKDEpIEVVICgyKSBteSBjb3VudHJ5CiMgZDc4OiBFVSBhdHRpdHVkZQojIGQ3M18qOiBFVS9teSBjb3VudHJ5IGluIHJpZ2h0L3dyb25nIGRpcmVjdGlvbgojCiMgbWFyZ2luIG9mIGVycm9yIGJldHdlZW4gMS41IGFuZCAzIHBlcmNlbnRhZ2UgcG9pbnRzIGZvciB0aGlzIHNhbXBsZSBzaXplCmBgYApgYGB7cn0KIyBTZWUgcmF3IFJtZCBvcmlnaW5hbCBvciB0aGUgY29kZWJvb2sgZm9yIGRlc2NyaXB0aW9uIG9mIHF1ZXN0aW9uIGNvZGVzCiMgc2VsZWN0IGNvdW50cmllcyBvZiB0aGUgVjQgKyByZWxldmFudCBjb2xzCmViMTVfdjQgPC0gZWIxNSAlPiUgCiAgc2VsZWN0KGlzb2NudHJ5LCBxMV8xNywgcTFfMTksIHExXzIzLCBxMV8yNCwgdW5pcWlkLCAjIGNvdW50cnkgKyBjaXRpemVuc2hpcAogICAgICAgICBzdGFydHNfd2l0aCgicWMxMyIpLCBzdGFydHNfd2l0aCgicWMxNCIpLCAKICAgICAgICAgc3RhcnRzX3dpdGgoInA2IiksIHN0YXJ0c193aXRoKCJwNyIpLAogICAgICAgICBlbmRzX3dpdGgoImN6IiksIGVuZHNfd2l0aCgic2siKSwgCiAgICAgICAgIGVuZHNfd2l0aCgicGwiKSwgZW5kc193aXRoKCJodSIpKSAlPiUKICBmaWx0ZXIoaXNvY250cnkgJWluJSBjKCJDWiIsICJTSyIsICJQTCIsICJIVSIpKQpgYGAKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgRGF0YSByZXNoYXBpbmc6CiMgLSBtZXJnZSAic2l6ZSBvZiBjb21tdW5pdHkiIGZvciBDWiwgU0sgYW5kIFBMCiMgLSBtYWtlIGxvbmcgYWxsIHByZXNlbnRseSBsb2FkZWQgc3VydmV5IHF1ZXN0aW9ucyAocWMqKQplYjE1X3Y0X2xvbmcgPC0gZWIxNV92NCAlPiUgCiAgbXV0YXRlKGNvbW11bml0eV9zaXplID0gY29hbGVzY2UocDZwbCwgcDZjeiwgcDZzaywgcDZodSkpICU+JSAKICBzZWxlY3QoLXN0YXJ0c193aXRoKCJwNiIpKSAlPiUKICBnYXRoZXIocXVlc3Rpb24sIHJlc3BvbnNlLCBzdGFydHNfd2l0aCgicWMxMyIpLCBzdGFydHNfd2l0aCgicWMxNCIpKSAlPiUKICBtdXRhdGUocmVzcG9uc2UgPSBmYWN0b3IocmVzcG9uc2UsIGxldmVscyA9IDE6MTMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJOb3QgYXQgYWxsIGNvbWZvcnRhYmxlIiwgMjo5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVG90YWxseSBjb21mb3J0YWJsZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJJbmRpZmZlcmVudCIsICJJdCBkZXBlbmRzIiwgIkRvbid0IGtub3ciKSksCiAgICAgICAgIGNvbW11bml0eV9zaXplID0gZmFjdG9yKGNvbW11bml0eV9zaXplLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiMSIgPSAiUnVyYWwgYXJlYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIiID0gIlRvd25zIGFuZCBzdWJ1cmJzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMyIgPSAiQ2l0aWVzIikpKQoKYGBgCgooU2lkZW5vdGU6IGhlcmUsIEkgY29udmVydCBkYXRhIGludG8gZmFjdG9ycyBtYW51YWxseS4gVGhpcyBpcyBiZWNhdXNlIHdoZW4gSSBkaWQgdGhpcyB0d28gd2Vla3MgYWdvLCBJIGRpZCBub3QgdGhpbmsgdG8gZGlnIHRocm91Z2ggYHNqbWlzY2AsIGEgcGFja2FnZSB0aGF0IGlzIGV4Y2VsbGVudCBhYm91dCBkaWdnaW5nIG91dCBhbmQgYXBwbHlpbmcgdGhlIG1ldGFkYXRhIGZyb20gYC5kdGFgIGZpbGVzLiBJIGRvIHVzZSBpdCBsYXRlci4pCgpSZW1lbWJlciB0aGUgbWV0YWRhdGEgd2Ugc3RvcmVkIHNlcGFyYXRlbHk/IFdlIGNhbiBjcmVhdGUgYSBsb29rdXAgdGFibGUgZm9yIGBmYWNldF93cmFwYCBpbiBnZ3Bsb3QyIGluIG9yZGVyIHRvIG1ha2Ugb3VyIGxhYmVscyBtb3JlIGluZm9ybWF0aXZlLgoKYGBge3J9CiMgQ2xlYW4gdXAgdGhlIHF1ZXN0aW9uIGNvZGVzCnF1ZXN0aW9uX25hbWVzIDwtIHNhcHBseShlYjE1X2xhYmVscywgZnVuY3Rpb24oeCkgeCRsYWJlbCkKcXVlc3Rpb25fbmFtZXMgPC0gZ3N1YigiQ09MTEVBR1VFUyBBVCBXT1JLOiAiLCAiIiwgcXVlc3Rpb25fbmFtZXMpCnF1ZXN0aW9uX25hbWVzWyJxYzEzXzExIl0gPC0gIlRyYW5zKiBwZXJzb24iICMgVG9vIGxvbmcgZm9yIGZhY2V0IGxhYmVscwpxdWVzdGlvbl9uYW1lcyA8LSBnc3ViKCJMT1ZFIFJFTEFUSU9OU1NISVAgT0YgQ0hJTEQ6ICIsICIiLCBxdWVzdGlvbl9uYW1lcykKcXVlc3Rpb25fbmFtZXNbInFjMTRfMTEiXSA8LSAiVHJhbnMqIHBlcnNvbiIKcXVlc3Rpb25fbmFtZXMgPC0gc2FwcGx5KHF1ZXN0aW9uX25hbWVzLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIFIudXRpbHM6OmNhcGl0YWxpemUoc3RyaW5ncjo6c3RyX3RvX2xvd2VyKHgpKSkKYGBgCmBgYHtyfQojIFdlJ2xsIGFsc28gY3JlYXRlIGEgbmFtZWQgdmVjdG9yIG9mIGNvdW50cnkgY29kZXMgZm9yIGxhdGVyIHVzZSBhcyBhIGxvb2t1cCAKIyB0YWJsZQplYnNfY291bnRyaWVzIDwtIHVuaXF1ZShlYjE1JGlzb2NudHJ5KQojIHNldE5hbWVzIGlzIGEgd2F5IHRvIGdldCBuYW1lcyBmb3IgYW4gdW5uYW1lZCB2ZWN0b3IKZWJzX2NvdW50cnlfZGljdCA8LSBzZXROYW1lcygKICBjb3VudHJ5Y29kZShlYnNfY291bnRyaWVzLCAKICAgICAgICAgICAgICAiaXNvMmMiLCAiY291bnRyeS5uYW1lIiwgCiAgICAgICAgICAgICAgY3VzdG9tX21hdGNoID0gYygiR0ItTklSIiA9ICJHQiAoTm9ydGhlcm4gSXJlbGFuZCkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdCLUdCTiIgPSAiR3JlYXQgQnJpdGFpbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiREUtRSIgPSAiR2VybWFueSAoRWFzdCkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkRFLVciID0gIkdlcm1hbnkgKFdlc3QpIikpLAogIGVic19jb3VudHJpZXMpCiMgU29tZSBvZiB0aGUgYGlzb2NudHJ5YCBsYWJlbHMgYXJlIG5vdCBhY3R1YWxseSBpbiB0aGUgSVNPIHN0YW5kYXJkLCBidXQgd2UKIyBzdGlsbCB3YW50IHRvIGxhYmVsIHRoZW0sIHNvIHdlIHByb3ZpZGUgYSBjdXN0b21fbWF0Y2ggZGljdGlvbmFyeQoKYGBgCgpJbml0aWFsbHksIEkgdmlzdWFsaXplZCBhbGwgY2F0ZWdvcmllcyBvZiBpbnRlcmVzdCBpbiB0aGUgc2FtZSBncmFwaCwgYnV0IHRoYXQgdHVybmVkIG91dCB0byBiZSBhIGxpdHRsZSBvdmVyd2hlbG1pbmcuIEkgc3BsaXQgdGhlIGF0dGl0dWRlcyBpbnRvIHRocmVlIGNhdGVnb3JpZXMgYW5kIG9yZGVyZWQgdGhlbSBzbyB0aGF0IHRoZSBtb3N0ICJwb3B1bGFyIiBzdWJncm91cCBpcyBhdCB0aGUgdG9wLiAoSWYgeW91J3JlIGRlYWxpbmcgd2l0aCBhIGxvdCBvZiBmYWN0b3JzLCBgZm9yY2F0c2AgaGFzIG1ldGhvZHMgdG8gZG8gdGhpcyBhdXRvbWF0aWNhbGx5LikKCmBgYHtyfQojIFJlb3JkZXIgdGhlIGZhY2V0cwpldGhuaWNpdGllcyA9IHBhc3RlMCgicWMxNF8iLCBjKDQsIDM6MSkpCnJlbGlnaW9ucyA9IHBhc3RlMCgicWMxNF8iLCBjKDg6OSwgNSwgNywgNikpCnNleGRpc2FiaWxpdHkgPSBwYXN0ZTAoInFjMTRfIiwgMTA6MTIpCm9yZGVyZWRfcXVlc3Rpb25zID0gcXVlc3Rpb25fbmFtZXNbYyhldGhuaWNpdGllcywgcmVsaWdpb25zLCBzZXhkaXNhYmlsaXR5KV0KIyBPdGhlciB0aGFuIHJlb3JkZXJpbmcgdGhlIGZhY3RvcnMsIHRoaXMgYWxzbyBnaXZlcyB0aGVtIHRoZSBuYW1lcyBmcm9tCiMgdGhlIGNvZGVib29rCmViMTVfdjRfbG9uZyA8LSBlYjE1X3Y0X2xvbmcgICU+JQogIG11dGF0ZShxdWVzdGlvbiA9IGZjdF9yZWxldmVsKGFzLmZhY3RvcihxdWVzdGlvbiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZXMob3JkZXJlZF9xdWVzdGlvbnMpKSkKYGBgCgpXZSdsbCBtYWtlIHRocmVlIGdyYXBocyB0aGF0IHdlJ2xsIHRoZW4gY29tYmluZSB3aXRoIHRoZSBgY293cGxvdGAgcGFja2FnZSwgd2hpY2ggbWVhbnMgdGhhdCB3ZSdsbCBiZSByZXVzaW5nIGEgbG90IG9mIGdncGxvdDIgbGF5ZXJzLiBMdWNraWx5LCB3ZSBjYW4gcHJlcGFyZSB0aG9zZSBhaGVhZCBvZiB0aW1lIGluIGEgbGlzdC4gKFRoZSBmb2xsb3dpbmcgYXNzdW1lcyBgZ2dwbG90MmAga25vd2xlZGdlOyB0aGUgc2hvcnQgc3VtbWFyeSBpcyB0aGF0IGl0IGltcGxlbWVudHMgYSAiZ3JhbW1hciBvZiBncmFwaGljcyIsIHdoaWNoIGxldHMgeW91IGFzc2lnbiB2YXJpYWJsZXMgdG8gZGlmZmVyZW50IGdyYXBoaWNhbCByZXByZXNlbnRhdGlvbnMgYW5kIGhhbmRsZXMgdGhlIGltcGVyYXRpdmUgd29yayB0aGF0IHVzZWQgdG8gdGFrZSB1cCB0aGUgbW9zdCB0aW1lLiBbSGFydmFyZCBEYXRhIFNjaWVuY2UgU2VydmljZXNdKGh0dHA6Ly90dXRvcmlhbHMuaXEuaGFydmFyZC5lZHUvUi9SZ3JhcGhpY3MvUmdyYXBoaWNzLmh0bWwpIGhhcyBhIGdvb2QgaW50cm8uKQoKYGBge3J9CiMjIFByZXBhcmUgbGF5ZXJzIGZvciByZXVzZSAtIHdlJ2xsIGJlIGdyYXBoaW5nIGEgbG90IG9mIGJhciBjaGFydHMhIChIb3cgY2FuIHdlCiMgdXNlIHZhcmlhYmxlcyBpbiBoZXJlIGJlZm9yZSB0aGV5J3JlIGV2ZXIgZGVmaW5lZD8gSXQgaXMgdGhlIG1hZ2ljIG9mCiMgbm9uLXN0YW5kYXJkIGV2YWx1YXRpb24hIFlvdSdsbCB3YW50IHRvIHJlYWQgQWR2YW5jZWQgUiBieSBIYWRsZXkgV2lja2hhbSwgYnV0CiMgZm9yIG5vdywganVzdCBzZXR0bGUgZm9yIHRoZSBleHBsYW5hdGlvbm9mICJhcmd1bWVudHMgaW4gZ2dwbG90MiBhcmUgb25seQojIGV2YWx1YXRlZCB3aGVuIGl0J3MgdGltZSB0byBkcmF3IHRoZSBncmFwaHMuIikKbGF5ZXJzIDwtIGxpc3QoCiAgIyBzZXBhcmF0ZSBncmFwaCBmb3IgZWFjaCBjb3VudHJ5IGFuZCBlYWNoIGF0dGl0dWRlCiAgZmFjZXRfZ3JpZChxdWVzdGlvbiB+IGlzb2NudHJ5LAogICAgICAgICAgICAgbGFiZWxsZXIgPSBsYWJlbGxlcihxdWVzdGlvbiA9IGFzX2xhYmVsbGVyKHF1ZXN0aW9uX25hbWVzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXNvY250cnkgPSBlYnNfY291bnRyeV9kaWN0KSksCiAgIyBzZXBhcmF0ZSB0aGUgMS0xMCBjb21mb3J0IHJhdGluZyBmcm9tIGluZGlmZmVyZW5jZS9JREsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAxMC41KSwgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDYwLCBoanVzdCA9IDEsIHNpemUgPSAxMSkpLAogIHhsYWIoIiIpLCAKICB5bGFiKCJSZXNwb25zZSBjb3VudCIpLAogIHlsaW0oMCwgODAwKQogICMgaGlnaGxpZ2h0IGNvbW11bml0eSBzaXplIG9mIHJlc3BvbmRlbnRzIHRvIHNoaW5lIHNvbWUgaW5pdGlhbCBsaWdodCBvbgogICMgdGhlIHVyYmFuLXJ1cmFsIHF1ZXN0aW9uCikKbWFrZU1haW5UaXRsZSA8LSBmdW5jdGlvbihzdWJzZXRfZGVzY3JpcHRpb24gPSAiYWxsIiwgY291bnRyaWVzID0gIkNaLCBIVSwgUEwgJiBTSyIpIHsKICBnZ3RpdGxlKHBhc3RlMCgiSG93IGNvbWZvcnRhYmxlIHdvdWxkIHlvdSBmZWVsIGlmIG9uZSBvZiB5b3VyIGNoaWxkcmVuIHdhcyBpbiAiLAogICAgICAgICAgICAgICAgICJhIGxvdmUgcmVsYXRpb25zaGlwIHdpdGggX19fPyIpLAogICAgICAgICAgc3VidGl0bGUgPSBwYXN0ZTAoIkV1cm9iYXJvbWV0ZXIgODMuNCAoMjAxNSkgdmlhIEdFU0lTLCAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YnNldF9kZXNjcmlwdGlvbiwgIiBxdWVzdGlvbnMsICIsIGNvdW50cmllcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiIGFuc3dlcnMiKSkKfQpgYGAKCk5vdywgd2UgcHJlcGFyZSB0aGUgZ3JhcGhzIGFuZCBwdXQgdGhlbSB0b2dldGhlciB3aXRoIGBjb3dwbG90OjpwbG90X2dyaWRgLgoKYGBge3J9CnY0X2xvdmVfZXRobmljaXRpZXMgPC0gZWIxNV92NF9sb25nICU+JQogIGZpbHRlcihxdWVzdGlvbiAlaW4lIGV0aG5pY2l0aWVzKSAlPiUKICBnZ3Bsb3QoKSArIG1ha2VNYWluVGl0bGUoImV0aG5pY2l0eSIpICsKICBnZW9tX2JhcihhZXMoeCA9IHJlc3BvbnNlLCBmaWxsID0gY29tbXVuaXR5X3NpemUpLCB3aWR0aCA9IDAuOCkgKwogIGxheWVycwogIAp2NF9sb3ZlX3JlbGlnaW9ucyA8LSBlYjE1X3Y0X2xvbmcgJT4lCiAgZmlsdGVyKHF1ZXN0aW9uICVpbiUgcmVsaWdpb25zKSAlPiUKICBnZ3Bsb3QoKSArIG1ha2VNYWluVGl0bGUoInJlbGlnaW91cy1hZmZpbGlhdGlvbiIpICsKICBnZW9tX2JhcihhZXMoeCA9IHJlc3BvbnNlLCBmaWxsID0gY29tbXVuaXR5X3NpemUpLCB3aWR0aCA9IDAuOCkgKwogIGxheWVycwp2NF9sb3ZlX3NleGRpc2FiaWxpdHkgPC0gZWIxNV92NF9sb25nICU+JQogIGZpbHRlcihxdWVzdGlvbiAlaW4lIHNleGRpc2FiaWxpdHkpICU+JQogIGdncGxvdCgpICsgbWFrZU1haW5UaXRsZSgiTEdCVFEvZGlzYWJpbGl0eSIpICsKICBnZW9tX2JhcihhZXMoeCA9IHJlc3BvbnNlLCBmaWxsID0gY29tbXVuaXR5X3NpemUpLCB3aWR0aCA9IDAuOCkgKwogIGxheWVycwoKYGBgCmBgYHtyLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDI0LCBtZXNzYWdlcyA9IEZBTFNFfQp2NF9sb3ZlX2FsbCA8LSBjb3dwbG90OjpwbG90X2dyaWQodjRfbG92ZV9ldGhuaWNpdGllcyArIG1ha2VNYWluVGl0bGUoKSwgCiAgICAgICAgICB2NF9sb3ZlX3JlbGlnaW9ucyArIGdndGl0bGUoIlN1YnNlY3Rpb246IFJlbGlnaW9ucyIpICsgCiAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiksCiAgICAgICAgICB2NF9sb3ZlX3NleGRpc2FiaWxpdHkgKyBnZ3RpdGxlKCJTdWJzZWN0aW9uOiBMR0JUUSBhbmQgZGlzYWJpbGl0eSIpICsKICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpLCAKICAgICAgICAgIG5jb2wgPSAxLCByZWxfaGVpZ2h0cyA9IGMoNC41LCA1LCA0KSkKdjRfbG92ZV9hbGwKYGBgCgoKYGBge3IsIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0UsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSAxMH0KZ2dzYXZlKCJsb3ZlX2V0aG5pY2l0aWVzLnBuZyIsIAogICAgICAgdjRfbG92ZV9ldGhuaWNpdGllcywgCiAgICAgICB3aWR0aCA9IDEwLCBoZWlnaHQgPSA5KQpnZ3NhdmUoImxvdmVfcmVsaWdpb25zLnBuZyIsIAogICAgICAgdjRfbG92ZV9yZWxpZ2lvbnMsIAogICAgICAgd2lkdGggPSAxMCwgaGVpZ2h0ID0gMTApCmdnc2F2ZSgibG92ZV9zZXhkaXNhYmlsaXR5LnBuZyIsIAogICAgICAgdjRfbG92ZV9zZXhkaXNhYmlsaXR5LCAKICAgICAgIHdpZHRoID0gMTAsIGhlaWdodCA9IDgpCmBgYApgYGB7ciwgZXZhbD1GQUxTRSwgZmlnLmhlaWdodD0yNCwgZmlnLndpZHRoPTEwLCBpbmNsdWRlPUZBTFNFfQpnZ3NhdmUoInY0X2xvdmVfYWxsLnBuZyIsIHY0X2xvdmVfYWxsLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSAyNCkKYGBgCgpUaGlzIGlzbid0IGJhZCBhcyBhIGZpcnN0IHBhc3MuIEhlcmUncyBhIGNvdXBsZSBvZiB0aGluZ3Mgb2Ygbm90ZToKCjEuIERpZmZlcmVudCBjb21tdW5pdHkgc2l6ZXMgd2VyZW4ndCBzYW1wbGVkIGV2ZW5seSwgc28gdGhlcmUncyBmZXdlciBydXJhbCByZXNwb25kZW50cyAtLSBhbmQgdGhleSBhcmVuJ3QgYWxsIGNvbnNlcnZhdGl2ZS4gVGhleSBkb24ndCBkcml2ZSB0aGUgdHJlbmRzLiAoQSBtb3NhaWMgcGxvdCBjb3VsZCB0ZWxsIHVzIG1vcmUgYWJvdXQgdGhlIHdpdGhpbi1ydXJhbCBzcGxpdCwgYnV0IGRvaW5nIGl0IHdpdGggY2F0ZWdvcmljYWwgdmFyaWFibGVzIHdvdWxkIHJlcXVpcmUgYW4gZWRnZSB2ZXJzaW9uIG9mIGBnZ21vc2FpY2AgYW5kIGBnZ3Bsb3QyYCwgd2hpY2ggaGFzIGJlZW4gW2JyZWFraW5nIHRoaW5ncyBmb3IgbWUuXShodHRwczovL2dpdGh1Yi5jb20vaGFsZXlqZXBwc29uL2dnbW9zYWljL2lzc3Vlcy8xMSkpCjIuIEhvbHkgc2hpdCB3ZSBhbGwgc3VjaywgYnV0IFBvbGFuZCBhbmQgSHVuZ2FyeSBoYXZlIGEgYmltb2RhbCBkaXN0cmlidXRpb24gb2YgZGlzY29tZm9ydCAoYSBzb2xpZCBzZWNvbmQtcGxhY2UgZmluaXNoIGZvciAiVG90YWxseSBjb21mb3J0YWJsZSIpLCB3aGVyZWFzIEN6ZWNoIGFuZCBTbG92YWsgcmVzcG9uZGVudHMgZGlmZmVyIG1vc3RseSBvbiB0aGUgZGVncmVlIG9mIGRpc2NvbWZvcnQuIFRoaXMgaXMgb2RkLgozLiBNb3N0IEN6ZWNoIGFuZCBTbG92YWsgcmVzcG9uc2UgZGlzdHJpYnV0aW9ucyBsb29rIG9kZGx5IHNpbWlsYXIuCgpXZSdsbCBnZXQgdG8gdGhlIHdlaXJkbmVzcyBpbiBhIGJpdC4KCiMjIENvbGxhcHNpbmcgdGhlIHNjYWxlcwoKVmlzdWFsIGNvbXBhcmlzb25zIHdpdGggYSAxMC1wb2ludCBMaWtlcnQgc2NhbGUgYXJlIGRpZmZpY3VsdCwgc28gbGV0J3MgY29sbGFwc2UgaXQuIFRoaXMgZnJlZXMgdXAgc3BhY2UgdG8gcHJpbnQgcGVyY2VudGFnZXMgb24gdG9wLiBXZSdsbCBkbyB0aGUgY29sbGFwc2luZyB3aXRoIGBmb3JjYXRzOjpmY3RfY29sbGFwc2VgOyBmb3Igbm93LCB3ZSdsbCBzdGljayB3aXRoIG15IGluaXRpYWwgY2hvaWNlIG9mIGdyb3VwaW5nIHRoZSB0b3AgZm91ciByZXNwb25zZSBsZXZlbHMsIHRoZSBib3R0b20gZm91ciwgYW5kIGV2ZXJ5dGhpbmcgaW4gYmV0d2Vlbi4gKFRoaXMgaXMgbm90IGEgbmV1dHJhbCBjaG9pY2UsIG9mIGNvdXJzZSAtIG1vcmUgYWJvdXQgdGhpcyBpbiB0aGUgbmV4dCBzZWN0aW9uLiBEbyBub3RlIHRoYXQgaW4gdGhlIG9yaWdpbmFsIEVCTSByZXBvcnQsICJJbmRpZmZlcmVudCIgd2FzIGdyb3VwZWQgd2l0aCB0aGUgbW9zdCBwb3NpdGl2ZSByZXNwb25zZXMuKQoKYGBge3IsIGZpZy5oZWlnaHQ9MjQsIGZpZy53aWR0aD04LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpkYXRhX2NvbGxhcHNlZCA8LSBlYjE1X3Y0X2xvbmcgJT4lCiAgZmlsdGVyKHF1ZXN0aW9uICVpbiUgYyhldGhuaWNpdGllcywgcmVsaWdpb25zLCBzZXhkaXNhYmlsaXR5KSkgJT4lCiAgbXV0YXRlKHJlc3BvbnNlX2RldGFpbGVkID0gZmN0X3JlbGV2ZWwocmVzcG9uc2UsICMgdG8gcHJldHRpZnkgdGhlIGxlZ2VuZCBvcmRlcgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJEb24ndCBrbm93IiwgIkluZGlmZmVyZW50IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkl0IGRlcGVuZHMiLCBhZnRlciA9IDUpLAogICAgICAgICByZXNwb25zZSA9IAogICAgICAgICAgIGZjdF9jb2xsYXBzZShyZXNwb25zZSwKICAgICAgICAgICAgICAgICAgICAgICAgIlVuY29tZm9ydGFibGUiID0gYygiTm90IGF0IGFsbCBjb21mb3J0YWJsZSIsIDI6MyksCiAgICAgICAgICAgICAgICAgICAgICAgICJNZWgiID0gYyg0OjYsICJJbmRpZmZlcmVudCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkl0IGRlcGVuZHMiLCAiRG9uJ3Qga25vdyIpLAogICAgICAgICAgICAgICAgICAgICAgICAiQ29tZm9ydGFibGUiID0gYyg3OjksICJUb3RhbGx5IGNvbWZvcnRhYmxlIikpICU+JQogICAgICAgICAgIGZjdF9kcm9wKCkpCgojIHByZWNhbGN1bGF0ZWQgcGVyY2VudGFnZXMhCiMgRG9pbmcgdGhpcyBkYW5jZSB0byBnZXQgdGhlIHRvdGFsIG51bWJlciBvZiByZXNwb25kZW50cyB0aGF0J3MgZGlmZmVyZW50IAojIGZvciBldmVyeSBjb3VudHJ5IChhbmQgcG9zc2libHkgZXZlcnkgcXVlc3Rpb24sIHRob3VnaCBob3BlZnVsbHkgdGhhdCBkb2VzCiMgbm90IGNoYW5nZSkKIyAKIyBOb3RlOiBpZiBub3QgZmlsdGVyZWQgYmVmb3JlIHVzZSwgdGhlIGluY2x1c2lvbiBvZiB0aGlzIGluIGEgZ2dwbG90MiBsYXllciAKIyAgIHdpbGwgY3JlYXRlIGFkZGl0aW9uYWwgZmFjZXRzLgpkYXRhX2NvbGxhcHNlZF9wZXJjZW50YWdlc190ZW1wIDwtIGRhdGFfY29sbGFwc2VkICU+JQogIGdyb3VwX2J5KGlzb2NudHJ5LCBxdWVzdGlvbiwgcmVzcG9uc2UpICU+JQogIHN1bW1hcml6ZShjb3VudCA9IG4oKSkKZGF0YV9jb2xsYXBzZWRfcGVyY2VudGFnZXMgPC0gZGF0YV9jb2xsYXBzZWRfcGVyY2VudGFnZXNfdGVtcCAlPiUKICBzdW1tYXJpemUodG90YWxfY291bnQgPSBzdW0oY291bnQpKSAlPiUKICBtZXJnZShkYXRhX2NvbGxhcHNlZF9wZXJjZW50YWdlc190ZW1wKSAlPiUKICBtdXRhdGUocGVyYyA9IHJvdW5kKDEwMCpjb3VudC90b3RhbF9jb3VudCwgMSkpCgojIHJlcGxhY2UgdGhlIHNldHRpbmdzIHRoYXQgd291bGRuJ3Qgd29yayBoZXJlCmxheWVyc19jb2xsYXBzZWQgPC0gbGF5ZXJzCmxheWVyc19jb2xsYXBzZWRbWzJdXSA8LSBzY2FsZV9maWxsX21hbnVhbCgKICB2YWx1ZXMgPSBjb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwoMTEsICJSZFlsR24iKSkoMTMpLAogIGd1aWRlID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxLCBsYWJlbC5wb3NpdGlvbiA9ICJib3R0b20iLCB0aXRsZSA9IE5VTEwpKQpsYXllcnNfY29sbGFwc2VkW1szXV0gPC0gdGhlbWUocGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDEsIGFuZ2xlID0gMjUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExKSkKbGF5ZXJzX2NvbGxhcHNlZFtbNl1dIDwtIHlsaW0oMCwgMTAwMCkKbGF5ZXJzX2NvbGxhcHNlZFtbN11dIDwtIGdlb21fYmFyKGFlcyh4ID0gcmVzcG9uc2UsIGZpbGwgPSByZXNwb25zZV9kZXRhaWxlZCksIHdpZHRoID0gMC44KQpgYGAKCmBgYHtyLCBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gOH0KY29sbGFwc2VkX2V0aG5pY2l0aWVzIDwtIGdncGxvdChkYXRhX2NvbGxhcHNlZCAlPiUgZmlsdGVyKHF1ZXN0aW9uICVpbiUgZXRobmljaXRpZXMpKSArIAogIG1ha2VNYWluVGl0bGUoImV0aG5pY2l0aWVzIikgKwogIGdlb21fdGV4dChkYXRhID0gZGF0YV9jb2xsYXBzZWRfcGVyY2VudGFnZXMgJT4lIGZpbHRlcihxdWVzdGlvbiAlaW4lIGV0aG5pY2l0aWVzKSwgCiAgICAgICAgICAgIHNpemUgPSAzLjUsCiAgICAgICAgICAgIGFlcyh4ID0gcmVzcG9uc2UsIHkgPSBjb3VudCArIDY1LCBsYWJlbCA9IHBhc3RlMChwZXJjLCAiJSIpKSkgKwogIGxheWVyc19jb2xsYXBzZWQKYGBgCmBgYHtyLCBmaWcuaGVpZ2h0PTksIGZpZy53aWR0aD04fQpjb2xsYXBzZWRfcmVsaWdpb25zIDwtIGdncGxvdChkYXRhX2NvbGxhcHNlZCAlPiUgZmlsdGVyKHF1ZXN0aW9uICVpbiUgcmVsaWdpb25zKSkgKyAKICBtYWtlTWFpblRpdGxlKCJyZWxpZ2lvdXMtYWZmaWxpYXRpb24iKSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBkYXRhX2NvbGxhcHNlZF9wZXJjZW50YWdlcyAlPiUgZmlsdGVyKHF1ZXN0aW9uICVpbiUgcmVsaWdpb25zKSwgCiAgICAgICAgICAgIHNpemUgPSAzLjUsCiAgICAgICAgICAgIGFlcyh4ID0gcmVzcG9uc2UsIHkgPSBjb3VudCArIDY1LCBsYWJlbCA9IHBhc3RlMChwZXJjLCAiJSIpKSkgKwogIGxheWVyc19jb2xsYXBzZWQKYGBgCgpgYGB7ciwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDd9CmNvbGxhcHNlZF9zZXhkaXNhYmlsaXR5IDwtIGdncGxvdChkYXRhX2NvbGxhcHNlZCAlPiUgZmlsdGVyKHF1ZXN0aW9uICVpbiUgc2V4ZGlzYWJpbGl0eSkpICsgCiAgbWFrZU1haW5UaXRsZSgiTEdCVFEvZGlzYWJpbGl0eSIpICsKICBnZW9tX3RleHQoZGF0YSA9IGRhdGFfY29sbGFwc2VkX3BlcmNlbnRhZ2VzICU+JSBmaWx0ZXIocXVlc3Rpb24gJWluJSBzZXhkaXNhYmlsaXR5KSwgCiAgICAgICAgICAgIHNpemUgPSAzLjUsCiAgICAgICAgICAgIGFlcyh4ID0gcmVzcG9uc2UsIHkgPSBjb3VudCArIDY1LCBsYWJlbCA9IHBhc3RlMChwZXJjLCAiJSIpKSkgKwogIGxheWVyc19jb2xsYXBzZWQKYGBgCgpgYGB7ciwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDI0fQpjb2xsYXBzZWRfYWxsIDwtIHBsb3RfZ3JpZChjb2xsYXBzZWRfZXRobmljaXRpZXMgKyBtYWtlTWFpblRpdGxlKCksIAogICAgICAgICAgY29sbGFwc2VkX3JlbGlnaW9ucyArIGdndGl0bGUoIlN1YnNlY3Rpb246IFJlbGlnaW9ucyIpICsgCiAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiksCiAgICAgICAgICBjb2xsYXBzZWRfc2V4ZGlzYWJpbGl0eSArIGdndGl0bGUoIlN1YnNlY3Rpb246IExHQlRRIGFuZCBkaXNhYmlsaXR5IikgKwogICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpLCAKICAgICAgICAgIG5jb2wgPSAxLCByZWxfaGVpZ2h0cyA9IGMoNC41LCA1LCA0KSkKY29sbGFwc2VkX2FsbApgYGAKYGBge3IsIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9Cmdnc2F2ZSgibG92ZV9ldGhuaWNpdGllc19wZXJjLnBuZyIsIAogICAgICAgY29sbGFwc2VkX2V0aG5pY2l0aWVzLCAKICAgICAgIHdpZHRoID0gOCwgaGVpZ2h0ID0gOCkKZ2dzYXZlKCJsb3ZlX3JlbGlnaW9uc19wZXJjLnBuZyIsIAogICAgICAgY29sbGFwc2VkX3JlbGlnaW9ucywgCiAgICAgICB3aWR0aCA9IDgsIGhlaWdodCA9IDkpCmdnc2F2ZSgibG92ZV9zZXhkaXNhYmlsaXR5X3BlcmMucG5nIiwgCiAgICAgICBjb2xsYXBzZWRfc2V4ZGlzYWJpbGl0eSwgCiAgICAgICB3aWR0aCA9IDgsIGhlaWdodCA9IDcpCmdnc2F2ZSgidjRfbG92ZV9hbGxfcGVyYy5wbmciLCBjb2xsYXBzZWRfYWxsLCB3aWR0aCA9IDgsIGhlaWdodCA9IDI0KQpgYGAKClNvIHRoYXQgbG9va3MgcHJldHR5IGJhZC4gQ2FuIHdlIGJsYW1lIHRoaXMgb24gbWV0aG9kb2xvZ3k/CgojIE1ldGhvZG9sb2dpY2FsIGNyaXRpY2lzbXMKCiMjIFRoZSBpc3N1ZSBvZiBtaXN0cmFuc2xhdGlvbgoKVGhlIG1vc3QgY29tbW9uIGNyaXRpY2lzbSBpcyB0aGF0IHRoZSBTbG92YWsgYW5kIEN6ZWNoIHN1cnZleXMgaGF2ZSBiZWVuIHRyYW5zbGF0ZWQgc2xvcHBpbHksIHdoaWNoIG1hZGUgdGhlIGRhdGEgaW5lbGlnaWJsZSBmb3IgY3Jvc3MtYm9yZGVyIGNvbXBhcmlzb25zIG9yLCBmb3IgcGVvcGxlIHdobyBsaWtlIHRvIG1ha2UgcXVpY2sgY29uY2x1c2lvbnMsIGRpc3F1YWxpZmllZCB0aGlzIHN1cnZleSBpbiBwYXJ0aWN1bGFyIGFuZCBFdXJvYmFyb21ldGVyIGluIGdlbmVyYWwuIEZvciB0aGUgbW9zdCBwYXJ0LCBJIHRoaW5rIHRoYXQgdGhpcyBsaW5lIG9mIGlucXVpcnkgb3ZlcnJlYWNoZXMuCgooW1lvdSBjYW4gZG93bmxvYWQgZWFjaCB0cmFuc2xhdGlvbiBmcm9tIEdFU0lTLl0oaHR0cHM6Ly9kYmsuZ2VzaXMub3JnL2Ria3NlYXJjaC9TRGVzYzIuYXNwP25vPTY1OTUmbGw9MTAmYWY9Jm5mPTEmZGI9ZSZzZWFyY2g9JnNlYXJjaDI9Jm5vdGFicz0xJmw9cCZwPTEpIFtUaGUgQ3plY2ggb25lIGlzIGhlcmUuXShodHRwczovL2Riay5nZXNpcy5vcmcvZGJrc2VhcmNoL2Rvd25sb2FkLmFzcD9kYj1FJmlkPTU4MzQ4KSkKCiMjIyBXaGF0J3MgImNvbWZvcnRhYmxlIj8KCltKYW4gS3VsdmVpdCBhcmd1ZXMgdGhhdCBFQk0gc2hhdCB0aGUgYmVkIG9uIHRyYW5zbGF0aW5nICJjb21mb3J0YWJsZSIgdG8gQ3plY2ggYW5kIFNsb3Zhay5dKGh0dHBzOi8vd3d3LmZhY2Vib29rLmNvbS9ub3Rlcy9qYW4ta3VsdmVpdC9uZXRvbGVyYW50biVDMyVBRC0lQzQlOERlJUM1JUExaS1hLXNsb3YlQzMlQTFjaS1hbmViLWphay1wcm9ibCVDMyVBOW0temF0ZW1uaXQtc3RhdGlzdGlrb3UvMTAxNTMyMDA5MTE2NjAxMDgvKSBJZiB5b3Ugc3BlYWsgQ3plY2gsIGdvIHJlYWQgaXQuIEhlcmUgYXJlIHRoZSBmb3VyIG1haW4gYXJndW1lbnRzIChzb21lIG9mIHdoaWNoIGFwcGVhciBpbiB0aGUgY29tbWVudHMpOiAKCjEuICJDb21mb3J0YWJsZSwiIHRoZSBvcGVyYXRpdmUgcmVzcG9uc2Uga2V5d29yZCwgaXMgbm90IHRyYW5zbGF0ZWQgaW50byBDemVjaCBhbmQgU2xvdmFrIGluIGEgd2F5IHRoYXQgZ3VhcmFudGVlcyBvbmUtdG8tb25lIGVxdWl2YWxlbmNlIG9mIGNvbm5vdGF0aW9ucy4KMi4gVGhlIEN6ZWNoIHRyYW5zbGF0aW9uIG9mIHRoZSBxdWVzdGlvbiBpcyBhdCBvZGRzIHdpdGggaXRzIGNvbGxvcXVpYWwgdXNhZ2UsIHdoaWNoIHByaW1lcyByZXNwb25kZW50cyBuZWdhdGl2ZWx5LiAiSG93IGNvbWZvcnRhYmxlIHdvdWxkIHlvdSBmZWVsIGlmIFgiIGlzIHVzdWFsbHkgdXNlZCB3aXRoIHRvZGRsZXJzIHdobyBhcmUgc3RpbGwgd29ya2luZyBvbiB0aGVpciB0aGVvcnkgb2YgbWluZDsgIlgiIGlzIHVzdWFsbHkgInRoYXQgb3RoZXIga2lkIHRvb2sgX3lvdXJfIHRveXMgYXdheS4iCjMuIFRoZSBDemVjaCBhbmQgU2xvdmFrIHRyYW5zbGF0aW9uIG9mIHRoZSB0b3AgcmVzcG9uc2Ugb3B0aW9uIGlzIGF3a3dhcmQuIFRoZSBDemVjaCBxdWVzdGlvbiBhc2tzIChhcHByb3hpbWF0ZWx5KSAiaG93IGdyZWF0IHdvdWxkIHlvdSBmZWVsLCIgYW5kIHRoZSBtb3N0LXBvc2l0aXZlIGxhYmVsLCAidG90YWxseSBncmVhdCwiIGlzIGEgdmVyeSBwZWN1bGlhciB0cmFuc2xhdGlvbiBvZiAidG90YWxseSBjb21mb3J0YWJsZS4iIFNvbWUgYXJndWUgdGhhdCBpdCBjb21lcyBvZmYgYXMgImV4dHJlbWVseSBvdmVyam95ZWQsIiBzaW5jZSBhIGNvbW1vbiBjb2xsb3F1aWFsIHVzYWdlIGlzIHVuZGVyc3RhdGluZyB5b3VyIGNoYWdyaW4gYnkgc2F5aW5nIHRoYXQgeW91J3JlICJub3QgZXh0cmVtZWx5IG92ZXJqb3llZCIuIAo0LiBBbHRob3VnaCB0aGUgaXNuJ3QgYSBmbGF3IHNoYXJlZCBieSBhbGwgdHJhbnNsYXRpb25zLCB0aGUgdHJhbnNsYXRpb25zIGRpZmZlciBhbW9uZyBlYWNoIG90aGVyIC0gdGhlIHRvcC1tb3N0IHJlc3BvbnNlIHJhbmdlcyBmcm9tICJ3b3VsZG4ndCBtaW5kIGF0IGFsbCIgKFBvbGlzaCkgdG8gIndvdWxkIGJlIHRvdGFsbHkgY29vbCB3aXRoIGl0IiAoSHVuZ2FyaWFuICYgbW9zdCBldmVyeXRoaW5nIGVsc2UpLiBTb21lIG1ha2UgcG9zaXRpdmUgcmVzcG9uc2VzIG1vcmUgbmF0dXJhbCB0aGFuIG90aGVycy4gQ29uc2VxdWVudGx5LCBjcm9zcy1uYXRpb25hbCBjb21wYXJpc29ucyBhcmUgcmlnaHQgb3V0LgoKVGhlIGF1dGhvciB0aGVuIGdvZXMgb24gdG8gKGFjY3VyYXRlbHkpIHJpcCB0aGUgbWVkaWEgbWlzcmVwcmVzZW50YXRpb24gb2YgdGhlIHN1cnZleSBhbmQgY29uY2x1ZGVzIGJ5IGRpc21pc3NpbmcgdGhlIHN1cnZleSBhcyBhIHdob2xlICh3aGljaCBpcyBhIHN0ZXAgdG9vIGZhcikuCgpJJ20gZ3JhdGVmdWwgdGhhdCBKYW4gbG9va2VkIGludG8gdGhlIG5pdHR5LWdyaXR0eSBvZiBzdXJ2ZXkgd29yZGluZy4gSmFuJ3MgaHlwb3RoZXNpcyBhbHNvIGV4cGxhaW5zIHNvbWUgb2YgdGhlIHdlaXJkbmVzcyBJJ3ZlIG5vdGVkIC0gdGhlIHVuY2FubnkgQ3plY2gvU2xvdmFrIHNpbWlsYXJpdHkgY291bGQgYmUgZHVlIHRvIHRoZSBzaGFyZWQgbWlzdHJhbnNsYXRpb24sIGFuZCB0aGUgY29tcGFyYXRpdmUgbGFjayBvZiBwb3NpdGl2ZS1yZXNwb25zZSBzcGlrZSBtYWtlcyBwbGF1c2libGUgdGhlIHVucGFsYXRhYmlsaXR5IG9mIHRoZSBwb3NpdGl2ZS1tb3N0IHJlc3BvbnNlLgoKU28gd2h5IHNob3VsZG4ndCB3ZSBiaW4gdGhlIHN0dWR5PwoKMS4gKipUaGUgdHJhbnNsYXRpb24gaXMgY2xvc2UgZW5vdWdoOyBvbmUtdG8tb25lIGNvbm5vdGF0aW9uYWwgZXF1aXZhbGVuY2UgaXMgYW4gdW5yZWFzb25hYmx5IGhpZ2ggc3RhbmRhcmQuKiogSXQncyBncmVhdCBpZiBpdCBjYW4gaGFwcGVuISBJdCBzaG91bGQgaGFwcGVuIHdoZW5ldmVyIGl0IGNhbiEgQnV0IGEgbG90IG9mIG91ciB2b2NhYnVsYXJ5LCBlc3BlY2lhbGx5IHRoZSB2b2NhYnVsYXJ5IHRoYXQgZGVzY3JpYmVzIGN1bHR1cmFsbHkgc2hhcGVkIHN1YmplY3RpdmUgZXhwZXJpZW5jZSwgc29tZSBkaXNwYXJpdHkgd2lsbCBuZWNlc3NhcmlseSBleGlzdC4gSXQncyB0aGUgcHJpY2Ugd2UgcGF5IGZvciBjb21wYXJhdGl2ZSByZXNlYXJjaC4gV2Ugc2hvdWxkIGFic29sdXRlbHkga2VlcCB0cmFjayBvZiBkaWZmZXJlbmNlcyBhbmQgc2hvdWxkIGNhbGwgYnVsbHNoaXQgd2hlbiB0aGUgZGlzcGFyaXR5IGdyb3dzIHRvbyBsYXJnZS4gCgpCdXQgaW4gdGhpcyBjYXNlLCBJIGRvbid0IHRoaW5rIHRoZSB0cmFuc2xhdGlvbnMgYXJlIHNvIGRpZmZlcmVudCBhcyB0byBtZWFzdXJlIGEgZGlmZmVyZW50IGNvbnN0cnVjdC4gIlpjZWxhIHDFmcOtamVtbsOpIiBpcyBhd2t3YXJkIGJ1dCBub3QgaW5zYW5lbHkgb2ZmLiBHaXZlbiBFQk0ncyB3ZWFsdGggb2YgcXVlc3Rpb25zLCB3ZSBjYW4gYWN0dWFsbHkgY2hlY2sgdGhhdCBlbXBpcmljYWxseToKCjIuICoqVGhlIHRyYW5zbGF0aW9uIGhhc24ndCBwcmVjbHVkZWQgQ3plY2hzIGFuZCBTbG92YWtzIGZyb20gdXNpbmcgdGhlIGZ1bGwgc2NhbGUgYWxtb3N0IGFzIG9mdGVuIGFzIG90aGVyIG5hdGlvbnMgd2hlbiBpdCBjYW1lIHRvIGF0dGl0dWRlcyB0byBhIHBvdGVudGlhbCB3aGl0ZSBpbmxhdyoqLiBMb29rIGF0IHRoZSBncmFwaCBmcm9tIGVhcmxpZXIgYW5kIGZvY3VzIG9uIHRoZSAid2hpdGUgcGVvcGxlIiBwbG90cyBpbiB0aGUgdG9wIHJvdzoKCmBgYHtyLCBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gOH0KdjRfbG92ZV9ldGhuaWNpdGllcwpgYGAKCkphbiBwcmVzZW50cyB0aGlzIGFzIGNvbmNsdXNpdmUgZXZpZGVuY2Ugb2YgbmVnYXRpdmUgc2tldyAvIG92ZXJseSBwb3NpdGl2ZSB0cmFuc2xhdGlvbiAtIGluIHRoZSBsaWx5LXdoaXRlIEN6ZWNobGFuZCBhbmQgU2xvdmFraWEsIHN1cmVseSB5b3UnZCBleHBlY3QgbW9yZSB0aGFuIH43MCUgb2YgcGVvcGxlIHRvIGJlICJ0b3RhbGx5IGNvbWZvcnRhYmxlIiB3aXRoIGEgd2hpdGUgaW5sYXcsIHJpZ2h0PyBJIGNvbmN1ciB0aGF0IHBvc2l0aXZlIHJlc3BvbnNlcyBhcmUgcHJvYmFibHkgYmxlZWRpbmcgaW50byB0aGUgImluZGlmZmVyZW50IiBjb2x1bW4gLSB3aGljaCwgZm9yIHRoZSByZWNvcmQsIFt0aGUgb3JpZ2luYWwgRUJNIHJlcG9ydF0oaHR0cDovL2VjLmV1cm9wYS5ldS9jb21tZnJvbnRvZmZpY2UvcHVibGljb3Bpbmlvbi9pbmRleC5jZm0vUmVzdWx0RG9jL2Rvd25sb2FkL0RvY3VtZW50S3kvNjgwMDQpIGNvdW50ZWQgYW1vbmcgImNvbWZvcnRhYmxlIiByZXNwb25zZXMuIEJ1dCB0aGUgZmFjdCB0aGF0IHRoZSBtYWpvcml0eSBvZiBwZW9wbGUgX2RpZF8gdXNlIHRoZSAidG90YWxseSBjb21mb3J0YWJsZSIgcmVzcG9uc2UgZm9yIGEgd2hpdGUgaW5sYXcgYWxzbyBtZWFucyB0aGF0IHRoZSB0b3AtbW9zdCByZXNwb25zZSBpc24ndCBvZmYgdGhlIG1lbnUgYnkgdmlydHVlIG9mIGNhdGFzdHJvcGhpYyBtaXN0cmFuc2xhdGlvbi4gKipZb3UgY2FuJ3Qgc2hydWcgb2ZmIHRoZSBub24tc2VsZWN0aW9uIG9mIHRoaXMgb3B0aW9uIGZvciBhbnkgb3RoZXIgZGVtb2dyYXBoaWMgc3ViZ3JvdXAgYnkgYXBwZWFsaW5nIHRvIG1pbGQgc2VtYW50aWMgZGlmZmVyZW5jZXMqKi4KClRoZSBtaWQtc2NhbGUgYnVtcCBwcm92aWRlcyBhbiB1cHBlciBib3VuZCBvbiB0aGUgc3VnZ2VzdGVkIGVycm9yLiBNb3N0bHksIGl0J3MgcHJldHR5IHRpbnkuIEFsbCBWNCBjb3VudHJpZXMgaGF2ZSBpdCB0byBzb21lIGV4dGVudCwgYXMgZG9lcyBCcml0YWluLCBHZXJtYW55LCBhbmQgbWFueSBvdGhlcnMuIEFsbCBvZiB0aGlzIHN1Z2dlc3RzIHRoYXQgcG9zaXRpdmUgYXR0aXR1ZGVzIGFyZW4ndCBnZXR0aW5nIGRyYXN0aWNhbGx5IHVuZGVycmVwb3J0ZWQgdGhlcmUuIChCb3RoIEdlcm1hbiBzYW1wbGVzIGhhdmUgYSBoaWdoZXIgcmF0ZSBvZiAiSW5kaWZmZXJlbnQiIHJlc3BvbnNlcywgdGhvdWdoLCB3aGljaCBpcyBjb25zaXN0ZW50IHdpdGggdHJhbnNsYXRpb24gdmFyaWF0aW9uIHJlZGlyZWN0aW5nIHJlc3BvbnNlcyB0aGVyZSAtIGJ1dCBhZ2Fpbiwgc2luY2UgIkluZGlmZmVyZW50IiB3YXMgaW50ZXJwcmV0ZWQgYXMgYSBwb3NpdGl2ZSByZXNwb25zZSwgdGhpcyB3b3VsZG4ndCBtYXR0ZXIgZm9yIHRoZSBvcmlnaW5hbCBFQk0gcmVwb3J0LikKCmBgYHtyLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDEwfQojIEFsbCBjb3VudHJpZXMnIGF0dGl0dWRlcyB0byBwb3RlbnRpYWwgd2hpdGUgaW5sYXcKZWIxNV9ncmFwaF93aGl0ZSA8LSBlYjE1ICU+JSBzZWxlY3QoaXNvY250cnksIHFjMTRfNCkgJT4lIAogIG11dGF0ZShxYzE0XzQgPSB0b19sYWJlbChxYzE0XzQpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBxYzE0XzQpKSArIAogIGZhY2V0X3dyYXAofiBpc29jbnRyeSwgbmNvbCA9IDUsIGxhYmVsbGVyID0gbGFiZWxsZXIoaXNvY250cnkgPSBlYnNfY291bnRyeV9kaWN0KSkgKyAKICBzdGF0X2NvdW50KG1hcHBpbmcgPSBhZXMoeSA9IC4ucHJvcC4uLCBncm91cCA9IDEpLCB3aWR0aCA9IDAuNykgKwogIGdlb21fcmVjdChkYXRhID0gZGF0YS5mcmFtZShpc29jbnRyeSA9IGMoIkNaIiwgIkhVIiwgIlBMIiwgIlNLIikpLCBpbmhlcml0LmFlcyA9IEZBTFNFLCAKICAgICAgICAgICAgZmlsbCA9ICJibHVlIiwgYWxwaGEgPSAwLjEsIHhtaW4gPSAtSW5mLCB5bWluID0gLUluZiwgeG1heCA9IEluZiwgeW1heCA9IEluZikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50LCBzZWMuYXhpcyA9IGR1cF9heGlzKCkpICsKICBnZ3RpdGxlKHBhc3RlMCgiSG93IGNvbWZvcnRhYmxlIHdvdWxkIHlvdSBmZWVsIGlmIG9uZSBvZiB5b3VyIGNoaWxkcmVuIHdhcyBpbiBcbiIsCiAgICAgICAgICAgICAgICAgImEgbG92ZSByZWxhdGlvbnNoaXAgd2l0aCBhIHdoaXRlIHBlcnNvbj8iKSkgKyBsYWJzKHggPSAiIiwgeSA9ICIiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMTAuNSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNjAsIGhqdXN0ID0gMSkpCmViMTVfZ3JhcGhfd2hpdGUKYGBgCgpgYGB7ciwgZXZhbCA9IEZBTFNFLCBpbmNsdWRlID0gRkFMU0V9Cmdnc2F2ZSgiZWIxNV9ncmFwaF93aGl0ZS5wbmciLCBlYjE1X2dyYXBoX3doaXRlLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSAxMCkKYGBgCgozLiAqKkV2ZW4gaWYgdGhlIG1vc3QgcG9zaXRpdmUgbGFiZWwgd2FzIHByb2JsZW1hdGljLCB0aGUgbW9zdCBuZWdhdGl2ZSBsZXZlbCBpcyBub3QuKiogIkkgd291bGRuJ3QgZmVlbCBncmVhdCBhdCBhbGwgW2Fib3V0IGhhdmluZyBYIGFzIGFuIGlubGF3XSIgKippcyoqIHJvdWdobHkgZXF1aXZhbGVudCB0byAiSSB3b3VsZG4ndCBmZWVsIGF0IGFsbCBjb21mb3J0YWJsZSIuIEJvdGggZXhwcmVzcyB0aGUga2luZCBvZiBmZWFyIGFuZCBhcHByZWhlbnNpb24gdGhhdCB0aGUgc3R1ZHkgaXMgYWZ0ZXIuIEF0IHdvcnN0LCB0aGUgcGVjdWxpYXIgdHJhbnNsYXRpb24gb2YgdGhlIHBvc2l0aXZlIGxhYmVsIGludHJvZHVjZXMgc29tZSBub2lzZSBpbnRvIHRoZSB0b3Agb2YgdGhlIHNjYWxlIGZvciBDemVjaCBhbmQgU2xvdmFrIHJlc3BvbmRlbnRzOyBpdCBkb2Vzbid0IGludmFsaWRhdGUgaXQgYWx0b2dldGhlciwgYW5kIGl0IGRvZXNuJ3QgaW52YWxpZGF0ZSB0aGUgbmVnYXRpdmUgcmVzcG9uc2VzIGF0IGFsbC4KCkluIHN1bW1hcnksIHRoZSBjcml0aXF1ZSBwcm9wZXJseSBjYXV0aW9ucyBhYm91dCB0cmFuc25hdGlvbmFsIHJlc3BvbnNlLWxldmVsIHBlcmNlbnRhZ2UgY29tcGFyaXNvbnMsIGVzcGVjaWFsbHkgYXQgdGhlIHBvc2l0aXZlIGVuZCBvZiB0aGUgc2NhbGUsIGFuZCBhYm91dCB0aGUgcG9zc2libGUgZGlzcGFyYXRlIGZsb29yL2NlaWxpbmcgbGV2ZWxzIGJldHdlZW4gbGFuZ3VhZ2VzLiBCdXQgaXQgb3ZlcnBsYXlzIGl0cyBoYW5kLgoKWyhGb3IgZnVydGhlciBlbXBpcmljYWwgdGVzdGluZywgc2VlIHRoZSBzZWN0aW9uIGJlbG93IHRoYXQgY29tcGFyZXMgdGhlIEV1cm9iYXJvbWV0ZXIgcmVzdWx0cyB3aXRoIHRob3NlIGZyb20gdGhlIEV1cm9wZWFuIFNvY2lhbCBTdXJ2ZXkuKV0oI3NvbHV0aW9uLTQtdXNlLWEtYmV0dGVyLXN1cnZleSkKCiMjIFNvY2lhbCBkZXNpcmFiaWxpdHkgYmlhcyBhbmQgX2FjdHVhbF8gZGlzY3JpbWluYXRpb24KClRocmVlIG90aGVyIGNyaXRpY2lzbSBJJ3ZlIHNlZW4gZmxvYXRpbmcgYXJvdW5kOgoKLSAqKkN6ZWNocycgYW5kIFNsb3Zha3MnIGFuc3dlcnMgYXJlIG5vdCBhcyBwb3NpdGl2ZSBhcyBvdGhlciBuYXRpb25zJyBiZWNhdXNlIHdlJ3JlIGhvbmVzdC4gV2UncmUgbm90IGFzIHN1YmplY3QgdG8gW3NvY2lhbCBkZXNpcmFiaWxpdHkgYmlhc10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvU29jaWFsX2Rlc2lyYWJpbGl0eV9iaWFzKSBhcyBvdGhlciBjb3VudHJpZXMuKiogSWYgQ3plY2hzIGFuZCBTbG92YWtzIGRvbid0IGZlZWwgYSBwYXJ0aWN1bGFyIHRhYm9vIGFzIHN0cm9uZ2x5IGFzIG90aGVyIEV1cm9wZWFucywgaXNuJ3QgdGhhdCBhbiBpbnRlcmVzdGluZyBmaW5kaW5nIGluIGl0cyBvd24gcmlnaHQ/IE5vdCB0byBtZW50aW9uIHRoYXQgd2hhdCBwZW9wbGUgZmVlbCBjb21mb3J0YWJsZSBzYXlpbmcgaXMgYW4gaW1wb3J0YW50IGVsZW1lbnQgb2YgeW91ciBldmVyeWRheSBleHBlcmllbmNlIGluIGEgc29jaWV0eS4KLSAqKkR1ZSB0byBzb2NpYWwgZGVzaXJhYmlsaXR5IGJpYXMsIHBvc2l0aXZlIGFuc3dlcnMgaW4gb3RoZXIgY291bnRyaWVzIGRvbid0IG5lY2Vzc2FyaWx5IHRyYW5zbGF0ZSBpbnRvIHRvbGVyYW50IGJlaGF2aW9yLioqIFRydWUuIERvIG5vdGUsIGhvd2V2ZXIsIHRoYXQgdGhlIGNvbnZlcnNlIGRvZXMgbm90IGFwcGx5OiBzaW5jZSB0aGVyZSdzIG5vIHNvY2lhbCBmb3JjZSBmb3JjaW5nIHRoZSBuZWdhdGl2ZSByZXNwb25zZXMsIHRoZXJlJ3Mgbm8gcmVhc29uIHRvIHRoaW5rIHRoYXQgbmVnYXRpdmUgcmVzcG9uc2VzIGRvbid0IHByZWRpY3QgaW50b2xlcmFuY2UgKG9yIHRoYXQgdGhlIG5lZ2F0aXZlIHJlc3BvbmRlbnRzIGFyZSBzZWNyZXRseSBzdXBlci10b2xlcmFudCkuICoqSWYgcGVvcGxlIHNheSB0aGV5J3JlIHVuY29tZm9ydGFibGUgYWJvdXQgbWlub3JpdGllcywgd2Ugc2hvdWxkIHByb2JhYmx5IGJlbGlldmUgdGhlbS4qKgotICoqVGhlIHN1cnZleSBjYW5ub3Qgc25pZmYgb3V0IGhpZGRlbiBkaXNjcmltaW5hdG9yeSBiZWhhdmlvci4qKiBBYnNvbHV0ZWx5LiBVbmxpa2Ugb3RoZXIgbWVhc3VyZXMsIGl0IGlzbid0IGRlc2lnbmVkIHRvIGRvIHRoYXQuIFRoaXMgZG9lc24ndCBtZWFuIGl0J3Mgd29ydGhsZXNzLgoKVG8gYmUgY2xlYXIsIHRoZXJlJ3Mgbm8gd2F5IHRvIGRldGVybWluZSB0aGUgYW1vdW50IG9mIHNvY2lhbCBkZXNpcmFiaWxpdHkgYmlhcyBpbiBlYWNoIGNvdW50cnkuIFlvdSBjYW4gY2xhaW0gdGhhdCB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBjb3VudHJpZXMgZXN0aW1hdGUgdGhlIGRpZmZlcmVuY2UgaW4gc29jaWFsIGRlc2lyYWJpbGl0eSBiaWFzIHJhdGhlciB0aGFuIHRoZSBkaWZmZXJlbmNlIGluIGxldmVsIG9mIChkaXMpY29tZm9ydCB3aXRoIGRpZmZlcmVudCBwZW9wbGUuIFRoYXQncyBmaW5lLiBCdXQgbGV0J3Mgbm90IGNyaXRpY2l6ZSBhIHB1enpsZSBwaWVjZSBmb3IgZmFpbGluZyB0byBjb250YWluIHRoZSB3aG9sZSBwaWN0dXJlLgoKU28gRXVyb2Jhcm9tZXRlciBpcyBub3QgdGhlIGVuZC1hbGwgYW5kIGJlLWFsbCBvZiBzdXJ2ZXlzLCBidXQgaXRzIGRhdGEgcmV0YWluIG1lYW5pbmcuIFdoYXQgYmV0dGVyIGFwcHJvYWNoZXMgY2FuIHdlIHRha2UgdG8gcmVwb3J0aW5nIGFuZCB2aXN1YWxpemluZyBpdD8KCiMgQWx0ZXJuYXRpdmUgMTogTWFrZSBjb25zZXJ2YXRpdmUgZXN0aW1hdGVzIG9mIHNlbGYtcmVwb3J0ZWQgaW50b2xlcmFuY2UKCkxldCdzIGFzc3VtZSB0aGF0IEphbiBpcyBjb3JyZWN0IHRoYXQgbWFueSBhIDUgcmVzcG9uc2UgaW4gQ3plY2ggYW5kIFNsb3ZhayBpcyB0aGUgbm9uY2hhbGFudCBjb2xvcmJsaW5kIHRvbGVyYW5jZSB0aGF0IHJlc3BvbmRlbnRzIGluIG90aGVyIGxhbmd1YWdlcyB3b3VsZCBwdXQgZG93biBhcyAxMC4gSWYgd2UgbW92ZSByZXNwb25zZSBsZXZlbHMgMyBhbmQgNCBmcm9tICJVbmNvbWZvcnRhYmxlIiBpbnRvICJNZWgiLCB3ZSdsbCBnZXQgYW4gYWRlcXVhdGUgY291bnQgb2Ygb3RoZXJuZXNzLWJhc2VkIGRpc2NvbWZvcnQgZm9yIEN6ZWNocyBhbmQgU2xvdmFrcy4gCgpPZiBjb3Vyc2UsIGlmIEphbiBpcyByaWdodCwgdGhlbiB0aGUgIk1laCIgYW5kICJDb21mb3J0YWJsZSIgcmVzcG9uc2VzIGFyZW4ndCBtZWFuaW5nZnVsLiBMZXQncyByZW1vdmUgdGhlbSBmcm9tIHRoZSB2aXN1YWxpemF0aW9uIGluIHRoZSBiZXN0IFR1ZnRlYW4gdHJhZGl0aW9uLiAoV2hpY2ggbWFrZXMgaXQgYSBnbG9yaWZpZWQgdGFibGUsIGJ1dCB0YWJsZXMgYXJlIGdyZWF0LiBGYW5jeSBnZW9tZXRyaWVzIGFyZSBmb3Igc3Vja2Vycy4pCgooVW5kZXIgdGhlc2UgYXNzdW1wdGlvbnMsIHdlJ3JlIHVuZGVyY291bnRpbmcgYmlnb3RlZCBQb2xlcyBhbmQgSHVuZ2FyaWFucywgYnV0IG5vdCBieSBhIGxvdCAtLSB0aGUgZGlzdHJpYnV0aW9ucyBjbHVzdGVyIGFyb3VuZCB0aGUgZXh0cmVtZXMgYW5kIG5vdCB0aGF0IG1hbnkgcGVvcGxlIHdlcmUgcGlja2luZyAzIGFuZCA0IG9uIHRoZSBzY2FsZSBhbnl3YXkuKQoKSXQgdHVybnMgb3V0IHRoYXQgdGhpbmdzIGRvbid0IGdldCBtdWNoIGJldHRlci4KCmBgYHtyLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDV9CiMgV2UgY2FuIHRha2UgdGhlIHByZXZpb3VzIGRhdGEgYW5kIHJlc2hhcGUgaXQKZGF0YV9jb2xsYXBzZWRfMTIgPC0gZGF0YV9jb2xsYXBzZWQgJT4lCiAgbXV0YXRlKHJlc3BvbnNlID0gCiAgICAgICAgICAgZmN0X2NvbGxhcHNlKHJlc3BvbnNlX2RldGFpbGVkLAogICAgICAgICAgICAgICAgICAgICAgICAiVW5jb21mb3J0YWJsZSIgPSBjKCJOb3QgYXQgYWxsIGNvbWZvcnRhYmxlIiwgMiksCiAgICAgICAgICAgICAgICAgICAgICAgICJNZWgiID0gYygzOjYsICJJbmRpZmZlcmVudCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkl0IGRlcGVuZHMiLCAiRG9uJ3Qga25vdyIpLAogICAgICAgICAgICAgICAgICAgICAgICAiQ29tZm9ydGFibGUiID0gYyg3OjksICJUb3RhbGx5IGNvbWZvcnRhYmxlIikpICU+JQogICAgICAgICAgIGZjdF9kcm9wKCkpCgpkYXRhX2NvbGxhcHNlZF9wZXJjZW50YWdlc190ZW1wIDwtIGRhdGFfY29sbGFwc2VkXzEyICU+JQogIGdyb3VwX2J5KGlzb2NudHJ5LCBxdWVzdGlvbiwgcmVzcG9uc2UpICU+JQogIHN1bW1hcml6ZShjb3VudCA9IG4oKSkKZGF0YV9jb2xsYXBzZWRfMTJfcGVyY2VudGFnZXMgPC0gZGF0YV9jb2xsYXBzZWRfcGVyY2VudGFnZXNfdGVtcCAlPiUKICBzdW1tYXJpemUodG90YWxfY291bnQgPSBzdW0oY291bnQpKSAlPiUKICBtZXJnZShkYXRhX2NvbGxhcHNlZF9wZXJjZW50YWdlc190ZW1wKSAlPiUKICBtdXRhdGUocGVyYyA9IHJvdW5kKDEwMCpjb3VudC90b3RhbF9jb3VudCwgMSkpCgojIC4uLmJ1dCBub3csIHdlJ2xsIHJlbW92ZSBldmVyeXRoaW5nIGJ1dCB0aGUgIlVuY29tZm9ydGFibGUiIGZhY3RvcgpkYXRhX2NvbGxhcHNlZF8xMiA8LSBmaWx0ZXIoZGF0YV9jb2xsYXBzZWRfMTIsIHJlc3BvbnNlID09ICJVbmNvbWZvcnRhYmxlIikKZGF0YV9jb2xsYXBzZWRfMTJfcGVyY2VudGFnZXMgPC0gZmlsdGVyKGRhdGFfY29sbGFwc2VkXzEyX3BlcmNlbnRhZ2VzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3BvbnNlID09ICJVbmNvbWZvcnRhYmxlIikKCmdncGxvdChkYXRhX2NvbGxhcHNlZF8xMl9wZXJjZW50YWdlcywgYWVzKHggPSBpc29jbnRyeSwgeSA9IGZjdF9yZXYocXVlc3Rpb24pLCBmaWxsID0gcGVyYykpICsKICBnZW9tX3RpbGUoKSArIGdlb21fbGFiZWwoYWVzKGxhYmVsID0gcGFzdGUwKHBlcmMsICIlIikpLCBjb2xvciA9ICJibGFjayIpICsKICBzY2FsZV9maWxsX2Rpc3RpbGxlcihsaW1pdHMgPSBjKDAsIDEwMCksIHBhbGV0dGUgPSAiUmVkcyIsIGRpcmVjdGlvbiA9IDEpICsKICBzY2FsZV94X2Rpc2NyZXRlKHBvc2l0aW9uID0gInRvcCIsIGxhYmVscyA9IGVic19jb3VudHJ5X2RpY3QpICsKICBzY2FsZV95X2Rpc2NyZXRlKGxhYmVscyA9IHF1ZXN0aW9uX25hbWVzKSArIHlsYWIoIiIpICsgeGxhYigiIikgKwogIGdndGl0bGUocGFzdGUwKCJIb3cgY29tZm9ydGFibGUgd291bGQgeW91IGZlZWwgaWYgb25lIG9mIHlvdXIgY2hpbGRyZW4gd2FzIGluIFxuIiwKICAgICAgICAgICAgICAgICAiYSBsb3ZlIHJlbGF0aW9uc2hpcCB3aXRoIF9fXz8iKSwKICAgICAgICAgIHN1YnRpdGxlID0gIlBlcmNlbnRhZ2Ugb2YgcmVzcG9uZGVudHMgd2hvIHJhdGVkIHRoZWlyIGNvbWZvcnQgYmVsb3cgMiBvdXQgb2YgMTBcbihpbmNsdXNpdmUpLCB3aGVyZSAxIGlzICdub3QgYXQgYWxsIGNvbWZvcnRhYmxlJyIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExKSkKYGBgCgoKIyBBbHRlcm5hdGl2ZSAyOiBNZWFzdXJlIHJlbGF0aXZlIGRpc2NvbWZvcnQKClRoZSBvdGhlciB3YXkgdG8gYXZvaWQgdGhlIHNlbWFudGljcyBkZWJhdGU6IHdlIGNhbiBsb29rIGF0IHJlc3BvbmRlbnRzJyBjb21mb3J0IF9yZWxhdGl2ZSB0byB0aGUgY29tZm9ydCB3aXRoIHRoZSBkb21pbmFudCBtYWpvcml0eSBncm91cCBpbiB0aGUgY291bnRyeV8uIChGb3IgVjQsIHRoYXQncyBwcmV0dHkgY2xlYXJseSB3aGl0ZSBwZW9wbGUuKS4gVGhpcyBzZWVtcyBsaWtlIGEgYmV0dGVyIG1lYXN1cmUgaW4gYSBudW1iZXIgb2Ygd2F5czogZm9yIG9uZSwgaXQgd29ya3MgZXZlbiBpZiByZXNwb25zZSBpdGVtIDEwIGluIFBvbGlzaCBkb2Vzbid0IHRyYW5zbGF0ZSB0byByZXNwb25zZSBpdGVtIDEwIGluIEN6ZWNoLiBGb3IgYW5vdGhlciwgdGhlIG1ham9yaXR5LW1pbm9yaXR5IGRpZmZlcmVudGlhbCBpcyBhcmd1YWJseSB3aGF0IHdlIG1lYW4gd2hlbiB3ZSB0YWxrIGFib3V0IGRpc2NyaW1pbmF0aW9uLgoKKEFsdGVybmF0aXZlbHksIHdlIGNvdWxkIG5vcm0gX3JlbGF0aXZlIHRvIHRoZSByZXNwb25kZW50J3Mgb3duIG1vc3QgZmF2b3JlZCBncm91cF8uIEkgZG9uJ3QgaGF2ZSBhIGNsZWFyIGlkZWEgb2Ygd2hhdCB3ZSdkIGJlIGdhaW5pbmcvbWlzc2luZyBvdXQgb24uKQoKT2YgY291cnNlLCB0aGVyZSdzIGEgcmVhc29uIHdoeSB0aGUgRUJNIHBlb3BsZSBhcmVuJ3QgZG9pbmcgdGhpcy4gVGhlIG1vc3QgaW1wb3J0YW50IHRoYXQgSSBjYW4gdGhpbmsgb2YgaXMgdGhhdCB0aGUgbm9uLXJlc3BvbnNlcyAtLSAiRG9uJ3Qga25vdyIsICJJbmRpZmZlcmVudCIsIGFuZCAiSXQgZGVwZW5kcyIgLS0gZG9uJ3QgZmFsbCBuZWF0bHkgaW4gdGhlIHJlc3BvbnNlIHNjYWxlLCBidXQgZXhjbHVkaW5nIHRoZW0gbWlzc2VzIG91dCBvbiByZWFsIGluZm9ybWF0aW9uLiAoV2UnZCBtaXNzIG91dCBvbiB0aGUgZW50aXJlIHJlc3BvbnNlIHNldCBvZiByZXNwb25kZW50cyB3aG8gc2VsZWN0ZWQgb25lIG9mIHRoZXNlIHJlc3BvbnNlcyBmb3IgdGhlaXIgcmVmZXJlbmNlIGF0dGl0dWRlLikgUGxhY2luZyB0aGVtIG9uIHRoZSBzY2FsZSwgaG93ZXZlciwgZ2l2ZXMgdGhlbSBtZWFuaW5nIHRoZXkgbWlnaHQgbm90IGhhdmUuIChUaGUgZGVjaXNpb24gdG8gcGxhY2UgdGhlbSBpbiB0aGUgIk1laCIgY2F0ZWdvcnkgYWJvdmUgd2FzIG9ubHkgb2theSBiZWNhdXNlIEkgaGFkIG5vIHBsYW5zIHRvIG1ha2UgYW55IGluZmVyZW5jZXMgYWJvdXQgIk1laCIuKQoKVGhpcyBzZWVtcyBsaWtlIGEgZnVuIHZpc3VhbGl6YXRpb24gdG8gdGhpbmsgYWJvdXQ7IEkgaG9wZSB0byBnZXQgdG8gaXQgbGF0ZXIuCgojIEFsdGVybmF0aXZlIDM6IEFiYW5kb24gY3Jvc3MtY291bnRyeSBjb21wYXJpc29ucwoKSXQncyByZWFsbHkgdGVtcHRpbmcgdG8gY29tcGFyZSBteSB0cmliZSB0byB5b3Vycy4gKEFkbWl0dGVkbHksIHRoaXMgaXMgaG93IEkgZmVsbCBpbnRvIHRoaXMgcmFiYml0IGhvbGUuKSBCdXQgdGhlcmUncyBwbGVudHkgdG8gYmUgZ2xlYW5lZCBmcm9tIHdpdGhpbi1jb3VudHJ5IGNvbXBhcmlzb25zLCB0b28hIFNvIGZhciwgdGhlIHZpc3VhbGl6YXRpb25zIEkndmUgYmVlbiB1c2luZyBoYXZlIGludml0ZWQgY3Jvc3MtY291bnRyeSBjb21wYXJpc29uIC0gYnV0IEkgZG9uJ3QgYWN0dWFsbHkgbmVlZCB0byBzZWUgUG9sYW5kJ3Mgc2hhcmUgb2YgdW5jb21mb3J0YWJsZSBhdHRpdHVkZXMgdG93YXJkIHRoZSBSb21hbmkgdG8gc2F5IHRoYXQgdGhlIEN6ZWNoIG9uZXMgYXJlIGhvcnJpYmx5IGhpZ2guCgpBcyBhIGJvbnVzLCB0aGlzIGFsc28gYWxsb3dzIGZvciBhIGRpc3BsYXkgb2YgbXVsdGlwbGUgcG9zaXRpb25zIHRoYXQgdGhlIHJlc3BvbmRlbnRzIHdlcmUgYXNrZWQgYWJvdXQgdGhlIGNvbWZvcnQgZm9yLgoKYGBge3J9CiMgTGV0J3Mgc3RhcnQgYWdhaW4gYW5kIHNoYXBlIHRoZSBkYXRhIGJldHRlcgpiaW5hcnlfbWVhc3VyZXMgPC0gdmFycyhzdGFydHNfd2l0aCgicWMyIiksIC1xYzJ0LCBzdGFydHNfd2l0aCgicWMzIikpCmNvbWZvcnRfbWVhc3VyZXMgPC0gdmFycyhzdGFydHNfd2l0aCgicWM0IiksCiAgICAgICAgICAgICAgICAgICAgICAgICBzdGFydHNfd2l0aCgicWMxMyIpLCBzdGFydHNfd2l0aCgicWMxNCIpLCBzdGFydHNfd2l0aCgicWMxOCIpKQplYjE1X2FsbCA8LSAgc2VsZWN0KGViMTUsIGlzb2NudHJ5LCB1bmlxaWQsCiAgICAgICAgICAgICAgICAgICAgc3RhcnRzX3dpdGgoInFjIiksIHN0YXJ0c193aXRoKCJzZCIpLCBzdGFydHNfd2l0aCgiZCIpKSAlPiUKICBtdXRhdGVfYWxsKHRvX2xhYmVsKSAlPiUKICBtdXRhdGVfYXQoYmluYXJ5X21lYXN1cmVzLCBmdW5jdGlvbih4KSB4ICE9ICJOb3QgbWVudGlvbmVkIikgJT4lICMgQmluYXJ5IG1lYXN1cmVzCiAgbXV0YXRlX2F0KGNvbWZvcnRfbWVhc3VyZXMsIGZ1bmN0aW9uKHgpIHsKICAgIGZjdF9yZWNvZGUoeCwgCiAgICAgICAgICAgICAgICJOb3QgYXQgYWxsIGNvbWZvcnRhYmxlIiA9ICIxIE5vdCBhdCBhbGwgY29tZm9ydGFibGUiLAogICAgICAgICAgICAgICAiVG90YWxseSBjb21mb3J0YWJsZSIgPSAiMTAgVG90YWxseSBjb21mb3J0YWJsZSIsCiAgICAgICAgICAgICAgICJJbmRpZmZlcmVudCIgPSAiSW5kaWZmZXJlbnQgKFNQT05UQU5FT1VTKSIsCiAgICAgICAgICAgICAgICJEb24ndCBrbm93IiA9ICJESyIpCiAgfSkKIyBxdWVzdGlvbl9uYW1lc192YWxpZCA8LSBzZXROYW1lcyhuYW1lcyhxdWVzdGlvbl9uYW1lcyksIG1ha2UubmFtZXMocXVlc3Rpb25fbmFtZXMpKQojIHF1ZXN0aW9uX25hbWVzX3ZhbGlkIDwtIHF1ZXN0aW9uX25hbWVzX3ZhbGlkW3F1ZXN0aW9uX25hbWVzX3ZhbGlkICVpbiUgbmFtZXMoZWIxNV9jb21mb3J0KV0KcXVlc3Rpb25fbmFtZXNfb3JpZ2luYWwgPC0gc2FwcGx5KGViMTVfbGFiZWxzLCBmdW5jdGlvbih4KSB4JGxhYmVsKQplYjE1X2NvbWZvcnRfd2lkZSA8LSBzZWxlY3QoZWIxNV9hbGwsIGlzb2NudHJ5LCB1bmlxaWQsICEhISBjb21mb3J0X21lYXN1cmVzKSAlPiUKICBnYXRoZXIocXVlc3Rpb24sIHJlc3BvbnNlLCAhISEgY29tZm9ydF9tZWFzdXJlcywgLWlzb2NudHJ5LCAtdW5pcWlkKQplYjE1X2NvbWZvcnRfd2lkZSRxdWVzdGlvbiA8LSBxdWVzdGlvbl9uYW1lc19vcmlnaW5hbFtlYjE1X2NvbWZvcnRfd2lkZSRxdWVzdGlvbl0KZWIxNV9jb21mb3J0X3dpZGUgPC0gc2VwYXJhdGUoZWIxNV9jb21mb3J0X3dpZGUsIHF1ZXN0aW9uLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW50byA9IGMoInF1ZXN0aW9uX2tpbmQiLCAidGFyZ2V0IiksIHNlcCA9ICI6ICIpICU+JQogIG11dGF0ZV9hdCh2YXJzKHF1ZXN0aW9uX2tpbmQsIHRhcmdldCksIGZ1bnMoc3RyX3RvX2xvd2VyKSkKYGBgCmBgYHtyLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDZ9CmNvdW50cnlfY291bnRzIDwtIGViMTUgJT4lIGdyb3VwX2J5KGlzb2NudHJ5KSAlPiUgc3VtbWFyaXplKHRvdGFsID0gbigpKQpyZXBsaWNhdGlvbl9iYXNlIDwtIGViMTVfY29tZm9ydF93aWRlICU+JQogIG11dGF0ZSh0YXJnZXQgPSBmY3RfcmVsZXZlbCh0YXJnZXQsICJkaWZmZXJlbnQgZXRobmljIG9yaWdpbiIsICJ3aGl0ZSBwZXJzb24iLCAiYXNpYW4gcGVyc29uIiwgImJsYWNrIHBlcnNvbiIsICJyb21hIHBlcnNvbiIsICJkaWZmZXJlbnQgcmVsaWdpb24iLCAiY2hyaXN0aWFuIHBlcnNvbiIsICJhdGhlaXN0IHBlcnNvbiIsICJqZXdpc2ggcGVyc29uIiwgImJ1ZGRoaXN0IHBlcnNvbiIsICJtdXNsaW0gcGVyc29uIiwgInBlcnNvbiB1bmRlciAyNSB5ZWFycyIsICJhZ2VkIHVuZGVyIDMwIiwgInBlcnNvbiBvdmVyIDYwIHllYXJzIiwgImFnZWQgb3ZlciA3NSIpKSAlPiUgCiAgZ3JvdXBfYnkoaXNvY250cnksIHF1ZXN0aW9uX2tpbmQsIHRhcmdldCwgcmVzcG9uc2UpCiMgY3JlYXRpbmcgYSBtYXAgd2l0aCBtZWFzdXJlcyB3ZSdyZSBtb3JlIGNlcnRhaW4gYWJvdXQKdW5jb21mb3J0YWJsZV9tYXAgPC0gcmVwbGljYXRpb25fYmFzZSAlPiUKICBzdW1tYXJpemUoY291bnQgPSBuKCkpICU+JSBmaWx0ZXIocmVzcG9uc2UgJWluJSBjKCJOb3QgYXQgYWxsIGNvbWZvcnRhYmxlIiwgIjIiKSkgJT4lCiAgc3VtbWFyaXplKHNlbGVjdGVkX2NvdW50ID0gc3VtKGNvdW50KSkgJT4lCiAgbWVyZ2UoY291bnRyeV9jb3VudHMpICU+JQogIG11dGF0ZShuZWdhdGl2ZTIgPSByb3VuZCgxMDAgKiBzZWxlY3RlZF9jb3VudCAvIHRvdGFsLCAyKSkKcXVlc3Rpb25fa2luZF9kaWN0ID0gYygiY29sbGVhZ3VlcyBhdCB3b3JrIiA9ICJIb3cgY29tZm9ydGFibGUgd291bGQgeW91IGZlZWwgaWYgb25lIG9mIHlvdXIgY29sbGVhZ3VlcyBhdCB3b3JrIHdhcyBhICBfX18/IiwKICAgICAgICAgICAgICAgICAgICAgICAibG92ZSByZWxhdGlvbnNzaGlwIG9mIGNoaWxkIiA9ICJIb3cgY29tZm9ydGFibGUgd291bGQgeW91IGZlZWwgaWYgb25lIG9mIHlvdXIgY2hpbGRyZW4gd2FzIGluIGEgbG92ZSByZWxhdGlvbnNoaXAgd2l0aCBfX18/IiwKICAgICAgICAgICAgICAgICAgICAgICAiZWxlY3RlZCBwb2xpdGljaWFuIiA9ICJIb3cgY29tZm9ydGFibGUgd291bGQgeW91IGZlZWwgaWYgdGhlIHBvbGl0aWNpYW4gaW4gdGhlIGhpZ2hlc3QgZWxlY3RlZCBvZmZpY2Ugd2FzIGEgX19fPyIpCnVuY29tZm9ydGFibGVfbWFwICU+JSBmaWx0ZXIoaXNvY250cnkgJWluJSBjKCJDWiIpLCBxdWVzdGlvbl9raW5kICE9ICJzaG93aW5nIGFmZmVjdGlvbiBpbiBwdWJsaWMiKSAlPiUKICBnZ3Bsb3QoYWVzKHkgPSBxdWVzdGlvbl9raW5kLCB4ID0gdGFyZ2V0LCBmaWxsID0gbmVnYXRpdmUyKSkgKwogIGZhY2V0X3dyYXAofiBxdWVzdGlvbl9raW5kLCBuY29sID0gMSwgc2NhbGVzID0gImZyZWUiLCAKICAgICAgICAgICAgIGxhYmVsbGVyID0gbGFiZWxsZXIocXVlc3Rpb25fa2luZCA9IHF1ZXN0aW9uX2tpbmRfZGljdCkpICsgCiAgZ2VvbV90aWxlKCkgKwogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTUpICsKICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDE1LCBoanVzdCA9IDEsIHNpemUgPSAxNCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBsb3QubWFyZ2luID0gdW5pdChjKDEsIDEsIDEsIDMpLCAiY20iKSkgKwogIHNjYWxlX2ZpbGxfZGlzdGlsbGVyKGxpbWl0cyA9IGMoMCwgMTAwKSwgcGFsZXR0ZSA9ICJSZWRzIiwgZGlyZWN0aW9uID0gMSkgKwogIGdlb21fbGFiZWwoYWVzKGxhYmVsID0gcGFzdGUwKG5lZ2F0aXZlMiwgIiUiKSksIGNvbG9yID0gImJsYWNrIikgKwogIGdndGl0bGUoIkN6ZWNoIGRpc2NvbWZvcnQiLAogICAgICAgICAgc3VidGl0bGUgPSAiUGVyY2VudGFnZSBvZiByZXNwb25kZW50cyB3aG8gcmF0ZWQgdGhlaXIgY29tZm9ydCBiZWxvdyAyIG91dCBvZiAxMCAoaW5jbHVzaXZlKSIpICsKICBsYWJzKHggPSAiIiwgeSA9ICIiKQpgYGAKCkkgZG9uJ3QgbGlrZSB0aGlzIHZpc3VhbGl6YXRpb24gLSB0aGVyZSdzIGFsbW9zdCBjZXJ0YWlubHkgYSBiZXR0ZXIgd2F5IHRvIGdvIGFib3V0IGRvaW5nIHRoaXMuIEl0IGRvZXMgZ2V0IHRoZSBwb2ludCBhY3Jvc3MsIHRob3VnaDogd2hhdGV2ZXIgdGhlaXIgc3RhbmRpbmcgcmVsYXRpdmUgdG8gdGhlIHJlc3Qgb2YgRXVyb3BlLCB0aGVyZSBjZXJ0YWlubHkgYXJlIGdyb3VwcyBvZiBwZW9wbGUgdGhhdCBDemVjaHMgb3Blbmx5IGFkbWl0IGJlaW5nIG11Y2ggbGVzcyBjb21mb3J0YWJsZSBhYm91dCB0aGFuIG90aGVycy4KCiMgQWx0ZXJuYXRpdmUgNDogVXNlIGEgYmV0dGVyIHN1cnZleQoKIlRoZSBFdXJvcGVhbiBTb2NpYWwgU3VydmV5IG1lYXN1cmVzIHRoZSBzYW1lIHRoaW5nIGJldHRlciwgc28gd2h5IGRvIHBlb3BsZSBrZWVwIHVzaW5nIHRoZSBFdXJvYmFyb21ldGVyPyIgW0luZGVlZCBpdCBkb2VzIV0oaHR0cDovL25lc3N0YXIuZXNzLm5zZC51aWIubm8vd2Vidmlldy9pbmRleC5qc3A/dj0yJnN1Ym1vZGU9dmFyaWFibGUmc3R1ZHk9aHR0cCUzQSUyRiUyRjEyOS4xNzcuOTAuODMlM0EtMSUyRm9iaiUyRmZTdHVkeSUyRkVTUzdlMDIuMSZncz11bmRlZmluZWQmdmFyaWFibGU9aHR0cCUzQSUyRiUyRjEyOS4xNzcuOTAuODMlM0E4MCUyRm9iaiUyRmZWYXJpYWJsZSUyRkVTUzdlMDIuMV9WMTgxJm1vZGU9ZG9jdW1lbnRhdGlvbiZ0b3A9eWVzKSBTb3J0IG9mLiBJdCBhc2tzIHRoZSBxdWVzdGlvbiBpbiB0ZXJtcyBvZiAibWluZGluZywiIHdoaWNoIHNvbWUgY2xhaW0gbWFrZXMgdGhlIEV1cm9iYXJvbWV0ZXIgcmVzdWx0cyBkaWZmZXJlbnQsIGFuZCBpdCBvbmx5IGFza3MgYWJvdXQgaW1taWdyYW50cyBvZiBhIGRpZmZlcmVudCByYWNlIG9yIGV0aG5pY2l0eS4gSGVyZSdzIGFuIG92ZXJ2aWV3IGZvciBhbGwgc3VydmV5ZWQgY291bnRyaWVzLgoKYGBge3J9CiMgaW50ZWdyYXRlZCBkYXRhIGZpbGUgZm9yIEVTUyAyMDE0IC0gd2UncmUgbG9va2luZyBmb3IgImltZGV0bXIiCmVzczE0IDwtIHJlYWRfZHRhKCJFU1M3ZTAyXzEuc3RhdGEvRVNTN2UwMl8xLmR0YSIpCmBgYApgYGB7cn0KZXNzMTQgJT4lIGdyb3VwX2J5KGNudHJ5KSAlPiUgc3VtbWFyaXplKG4oKSkKYGBgCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD04fQpsaWJyYXJ5KGdnYWx0KQpsaWJyYXJ5KGNvdW50cnljb2RlKQpsaWJyYXJ5KHNqbWlzYykKZXNzMTRfc3ViIDwtIGVzczE0ICU+JSBzZWxlY3QoY250cnksIGltZGV0YnMsIGltZGV0bXIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkd2VpZ2h0LCBwd2VpZ2h0LCBwc3B3Z2h0KSAlPiUgIyB3ZWlnaHRpbmcgdmFyaWFibGVzCiAgbXV0YXRlX2F0KHZhcnMoaW1kZXRicywgaW1kZXRtciksIAogICAgICAgICAgICBzam1pc2M6OnRvX2xhYmVsKSAlPiUgCiAgZmlsdGVyKGNudHJ5ICE9ICJBVCIpICMgYXBwYXJlbnRseSwgdGhlIHF1ZXN0aW9uIHdhcyBpbXByb3Blcmx5IGFkbWluaXN0ZXJlZCBpbiBBdXN0cmlhCgplc3MxNF9vdmVydmlldyA8LSBnZ3Bsb3QoZXNzMTRfc3ViLCBhZXMoeCA9IGltZGV0bXIpKSArCiAgc3RhdF9jb3VudChtYXBwaW5nID0gYWVzKHggPSBpbWRldG1yLCB5ID0gLi5wcm9wLi4sIGdyb3VwID0gMSksIHdpZHRoID0gMC43KSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnQpICsKICBmYWNldF93cmFwKH4gY250cnksIG5jb2wgPSA0LCAKICAgICAgICAgICAgIGxhYmVsbGVyID0gbGFiZWxsZXIoY250cnkgPSBmdW5jdGlvbih4KSBjb3VudHJ5Y29kZSh4LCAiaXNvMmMiLCAiY291bnRyeS5uYW1lIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VzdG9tX21hdGNoID0gYygiR0IiID0gIkdyZWF0IEJyaXRhaW4iKSkpKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA2MCwgaGp1c3QgPSAxKSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDExLjUpICsKICBsYWJzKHRpdGxlID0gcGFzdGUwKCJIb3cgbXVjaCB5b3Ugd291bGQgbWluZCBvciBub3QgbWluZCBpZiBhbiBpbW1pZ3JhbnQgb2YgIiwKICAgICAgICAgICAgICAgICAgICAgICJhIGRpZmZlcmVudCByYWNlIFxub3IgZXRobmljIGdyb3VwIG1hcnJpZWQgYSBjbG9zZSByZWxhdGl2ZSBvZiB5b3Vycz8iKSwKICAgICAgIHN1YnRpdGxlID0gIkV1cm9wZWFuIFNvY2lhbCBTdXJ2ZXkgMjAxNCwgd2l0aG91dCB3ZWlnaHRpbmciLAogICAgICAgeCA9ICIiLCB5ID0gIiIpICsKICBnZW9tX3JlY3QoZGF0YSA9IGRhdGEuZnJhbWUoY250cnkgPSBjKCJDWiIsICJIVSIsICJQTCIpKSwgaW5oZXJpdC5hZXMgPSBGQUxTRSwgCiAgICAgICAgICAgIGZpbGwgPSAiYmx1ZSIsIGFscGhhID0gMC4xLCB4bWluID0gLUluZiwgeW1pbiA9IC1JbmYsIAogICAgICAgICAgICB4bWF4ID0gSW5mLCB5bWF4ID0gSW5mKQplc3MxNF9vdmVydmlldwpgYGAKClRoZXJlJ3MgYSBidW5jaCBvZiBwcm9wZXJ0aWVzIHRoYXQgbWFrZSBFU1MgYSBjbHVtc3kgY29tcGFyaXNvbi4gRm9yIG9uZSwgaXQncyBqdXN0IG5vdCBhcyBkZXRhaWxlZCBhcyBFdXJvYmFyb21ldGVyOiBpdCBhc2tzIHR3byBxdWVzdGlvbnMgYWJvdXQgZGlzY29tZm9ydC9taW5kaW5nIGFuZCBib3RoIGFyZSBjb2FjaGVkIGluIGdlbmVyYWwgdGVybXMgKCJpbW1pZ3JhbnQgb2YgYSBkaWZmZXJlbnQgcmFjZSBvciBldGhuaWMgZ3JvdXAiKSwgc28gd2UgY2FuIG5laXRoZXIgZG8gdGhlICJjb21mb3J0IHdpdGggd2hpdGUgcGVyc29uIiBzYW5pdHkgY2hlY2sgbm9yIGNhbiB3ZSBtYXRjaCB0aGUgcXVlc3Rpb24gZGlyZWN0bHkgdG8gYW55IG9uZSBFQk0gaXRlbS4gRVNTIGFsc28gaGFzbid0IGluY2x1ZGVkIFNsb3Zha2lhLCB0aGUgb25lIG90aGVyIGNvdW50cnkgd2Uga25vdyB0byBzaG93IGEgc2ltaWxhciBwYXR0ZXJuIHBvdGVudGlhbGx5IHJlbGF0ZWQgdG8gbWlzdHJhbnNsYXRpb24sIHNvIHdlIGNhbid0IGRpYWdub3NlIHRoYXQgZWl0aGVyLiBGaW5hbGx5LCBFU1MgaGFzIDExIHJlc3BvbnNlLXNjYWxlIHBvaW50cyBjb250cmEgRUJNJ3MgMTAgKyB0aGUgIkluZGlmZmVyZW50IG9wdGlvbiIuCgpQbHVzLCB5J2tub3csIGRpZmZlcmVudCBzdXJ2ZXkgdGFrZW4gYXQgYSBkaWZmZXJlbnQgdGltZSB3aXRoIGEgZGlmZmVyZW50IG1ldGhvZG9sb2d5IGFza2luZyBhIGRpZmZlcmVudCBxdWVzdGlvbi4KCkJ1dCB0aGlzIGVudGlyZSBleGVyY2lzZSBpcyBhYm91dCBtYWtpbmcgZG8gd2l0aCB3aGF0IHdlIGhhdmUsIHNvIGxldCdzIGNvbXBhcmUgd2l0aCB0aGUgY2xvc2VzdCBFQk0gZXF1aXZhbGVudDogYXR0aXR1ZGVzIHRvd2FyZHMgcG90ZW50aWFsIGJsYWNrIGFuZCBBc2lhbiBpbmxhd3MgZm9yIHRoZSBzdWJzZXQgb2YgY291bnRyaWVzIHRoYXQgd2VyZSBzdXJ2ZXllZCBpbiBib3RoLgoKKE5vdGUgdGhhdCB0aGUgcG9zaXRpdmUtdG8tbmVnYXRpdmUgZGlyZWN0aW9uIGlzIHJldmVyc2VkIGluIEVTUyAtLSBJIGRpZG4ndCB3YW50IHRvIG1lc3Mgd2l0aCByZXZlcnNlIHNjb3JpbmcuIEkgYWxzbyBkcmV3IHRoZSBpbnRlcnNlY3Rpbmcgc2V0IG9mIEVTUy9FQk0gY291bnRyaWVzIG1hbnVhbGx5LCBzbyBJIG1pZ2h0IGhhdmUgbWlzc2VkIHNvbWUuKQoKYGBge3IsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD04LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQplYjE1X2JsYWNrX2FzaWFuIDwtIGViMTUgJT4lIHNlbGVjdChpc29jbnRyeSwgcWMxNF8yLCBxYzE0XzMpICU+JSAKICBtdXRhdGVfYXQodmFycyhxYzE0XzIsIHFjMTRfMyksIHRvX2xhYmVsKSAlPiUKICByZW5hbWUoYmxhY2sgPSBxYzE0XzIsIGFzaWFuID0gcWMxNF8zKSAlPiUKICBnYXRoZXIoaW5sYXcsIHJlc3BvbnNlLCBibGFjaywgYXNpYW4pICU+JQogIG11dGF0ZShyZXNwb25zZSA9IGZjdF9yZWxldmVsKGZhY3RvcihyZXNwb25zZSksICIxMCBUb3RhbGx5IGNvbWZvcnRhYmxlIiwgYWZ0ZXIgPSA5KSkKZWJzX2Vzc19jb3VudHJpZXMgPC0gYygiQ1oiLCAiSFUiLCAiUEwiLCAiTkwiLCAiQkUiLCAiRlIiLCAiREsiKQplYnNfY29tcGFyaXNvbiA8LSBlYjE1X2JsYWNrX2FzaWFuICU+JSBmaWx0ZXIoaXNvY250cnkgJWluJSBlYnNfZXNzX2NvdW50cmllcykKZXNzX2NvbXBhcmlzb24gPC0gZXNzMTRfc3ViICU+JSBmaWx0ZXIoY250cnkgJWluJSBlYnNfZXNzX2NvdW50cmllcykKZWJzX2dyYXBoIDwtIGdncGxvdChlYnNfY29tcGFyaXNvbiwgYWVzKHggPSByZXNwb25zZSkpICsgCiAgZmFjZXRfd3JhcCh+IGlzb2NudHJ5LCBuY29sID0gMSwgbGFiZWxsZXIgPSBsYWJlbGxlcihpc29jbnRyeSA9IGVic19jb3VudHJ5X2RpY3QpKSArIAogIHN0YXRfY291bnQobWFwcGluZyA9IGFlcyh5ID0gLi5wcm9wLi4sIGZpbGwgPSBpbmxhdywgZ3JvdXAgPSBpbmxhdyksIAogICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgpLCB3aWR0aCA9IDAuNykgKwogIGxhYnMoeCA9ICIiLCB5ID0gIiIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAxMC41KSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA2MCwgaGp1c3QgPSAxKSwgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudCwgbGltaXRzID0gYygwLCAuNzUpKSArCiAgZ2d0aXRsZSgiRXVyb2Jhcm9tZXRlciAyMDE1IiwgCiAgICAgICAgICBzdWJ0aXRsZSA9IHBhc3RlMCgiSG93IGNvbWZvcnRhYmxlIHlvdSB3b3VsZCBmZWVsIGlmIG9uZSBvZiB5b3VyIGNoaWxkcmVuIHdhcyBpbiBcbiIsCiAgICAgICAgICAgICAgICAgImEgbG92ZSByZWxhdGlvbnNoaXAgd2l0aCBhIGJsYWNrIG9yIGFuIEFzaWFuIHBlcnNvbj8iKSkgCgplc3NfZ3JhcGggPC0gZ2dwbG90KGVzc19jb21wYXJpc29uLCBhZXMoeCA9IGltZGV0bXIpKSArCiAgc3RhdF9jb3VudChtYXBwaW5nID0gYWVzKHggPSBpbWRldG1yLCB5ID0gLi5wcm9wLi4sIGdyb3VwID0gMSksIHdpZHRoID0gMC43KSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnQsIGxpbWl0cyA9IGMoMCwgLjc1KSkgKwogIGZhY2V0X3dyYXAofiBjbnRyeSwgbmNvbCA9IDEsIAogICAgICAgICAgICAgbGFiZWxsZXIgPSBsYWJlbGxlcihjbnRyeSA9IGZ1bmN0aW9uKHgpIGNvdW50cnljb2RlKHgsICJpc28yYyIsICJjb3VudHJ5Lm5hbWUiKSkpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDYwLCBoanVzdCA9IDEpKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMTEuNSkgKwogIHhsYWIoIiIpICsgeWxhYigiIikgKwogIGdndGl0bGUoIkV1cm9wZWFuIFNvY2lhbCBTdXJ2ZXkgMjAxNCIsIAogICAgICAgICAgc3VidGl0bGUgPSBwYXN0ZTAoIkhvdyBtdWNoIHlvdSB3b3VsZCBtaW5kIG9yIG5vdCBtaW5kIGlmIGFuIGltbWlncmFudCBvZiAiLAogICAgICAgICAgICAgICAgICJhIGRpZmZlcmVudCByYWNlIFxub3IgZXRobmljIGdyb3VwIG1hcnJpZWQgYSBjbG9zZSByZWxhdGl2ZSBvZiB5b3Vycz8iKSkKY29tYmluZWRfZWJzX2VzcyA8LSBjb3dwbG90OjpwbG90X2dyaWQoZXNzX2dyYXBoLCBlYnNfZ3JhcGgsIGF4aXMgPSAidGJsciIsIGFsaWduID0gImgiKQpjb21iaW5lZF9lYnNfZXNzCmBgYApgYGB7ciwgZXZhbCA9IEZBTFNFLCBpbmNsdWRlID0gRkFMU0V9Cmdnc2F2ZSgiY29tYmluZWRfZWJzX2Vzcy5wbmciLCBjb21iaW5lZF9lYnNfZXNzLCB3aWR0aCA9IDgsIGhlaWdodCA9IDEwKQpgYGAKCk1vc3QgY291bnRyaWVzIGhhdmUgYSBzaW1pbGFyIHJlc3BvbnNlIGRpc3RyaWJ1dGlvbiBmb3IgYm90aCBzdXJ2ZXlzLCBidXQgdGhlIEN6ZWNoIG9uZSBpbiBFU1MgaXMgbm90aWNlYWJseSBmbGF0dGVyLiBMZXQncyBsb29rIGF0IHRoZSBleHRyZW1lIGVuZHMgb2YgZWFjaCBzdXJ2ZXkncyBzY2FsZSB0byBzZWUgaG93IG11Y2ggdGhlIHR3byBzdXJ2ZXlzIGRpZmZlcmVkOgoKYGBge3J9CiMgRGlmZmVyZW5jZTogY29tcHV0ZSBwZXJjZW50YWdlcywgcmVuYW1lIGxldmVscyAoIm1vc3QgbmVnYXRpdmUiLCAibW9zdCBwb3NpdGl2ZSIpLCBtZXJnZSwgYW5kIG1ha2UgYSBsb2xsaXBvcCBjaGFydCBvZiBkaWZmZXJlbmNlcwplYm1fbWlubWF4IDwtIGVic19jb21wYXJpc29uICU+JSBmaWx0ZXIoaW5sYXcgPT0gImJsYWNrIikgJT4lIAogIGdyb3VwX2J5KGlzb2NudHJ5LCByZXNwb25zZSkgJT4lCiAgc3VtbWFyaXplKHJlc3BvbnNlX2NvdW50ID0gbigpKSAlPiUgCiAgbXV0YXRlKHJlc3BvbnNlX3BlcmMgPSByZXNwb25zZV9jb3VudCAvIHN1bShyZXNwb25zZV9jb3VudCkpICU+JQogIGZpbHRlcihyZXNwb25zZSAlaW4lIGMoIjEgTm90IGF0IGFsbCBjb21mb3J0YWJsZSIsICIxMCBUb3RhbGx5IGNvbWZvcnRhYmxlIikpICU+JQogIHVuZ3JvdXAoKSAlPiUKICB0cmFuc211dGUoY250cnkgPSBpc29jbnRyeSwgcmVzcG9uc2VfcGVyYywKICAgICAgICAgICAgcmVzcG9uc2Vfa2luZCA9IAogICAgICAgICAgICAgIGZjdF9yZWNvZGUocmVzcG9uc2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAiTmVnYXRpdmUiID0gIjEgTm90IGF0IGFsbCBjb21mb3J0YWJsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAiUG9zaXRpdmUiID0gIjEwIFRvdGFsbHkgY29tZm9ydGFibGUiKSAlPiUKICAgICAgICAgICAgICBhcy5jaGFyYWN0ZXIoKSkKZXNzX21pbm1heCA8LSBlc3NfY29tcGFyaXNvbiAlPiUgIGdyb3VwX2J5KGNudHJ5LCBpbWRldG1yKSAlPiUKICBzdW1tYXJpemUocmVzcG9uc2VfY291bnQgPSBuKCkpICU+JSAKICBtdXRhdGUocmVzcG9uc2VfcGVyYyA9IHJlc3BvbnNlX2NvdW50IC8gc3VtKHJlc3BvbnNlX2NvdW50KSkgJT4lCiAgZmlsdGVyKGltZGV0bXIgJWluJSBjKCJOb3QgbWluZCBhdCBhbGwiLCAiTWluZCBhIGxvdCIpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgdHJhbnNtdXRlKGNudHJ5LCByZXNwb25zZV9wZXJjLAogICAgICAgICAgICByZXNwb25zZV9raW5kID0gCiAgICAgICAgICAgICAgZmN0X3JlY29kZShpbWRldG1yLAogICAgICAgICAgICAgICAgICAgICAgICAgIk5lZ2F0aXZlIiA9ICJNaW5kIGEgbG90IiwKICAgICAgICAgICAgICAgICAgICAgICAgICJQb3NpdGl2ZSIgPSAiTm90IG1pbmQgYXQgYWxsIikgJT4lCiAgICAgICAgICAgICAgYXMuY2hhcmFjdGVyKCkpCmVzc19lYm1fbWlubWF4X2RpZmZlcmVuY2UgPC0gaW5uZXJfam9pbihlYm1fbWlubWF4LCBlc3NfbWlubWF4LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gYygiY250cnkiLCAicmVzcG9uc2Vfa2luZCIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1ZmZpeCA9IGMoIi5lYm0iLCAiLmVzcyIpKSAlPiUKICBtdXRhdGUoZXNzX2VibV9kZWx0YSA9IHJlc3BvbnNlX3BlcmMuZXNzIC0gcmVzcG9uc2VfcGVyYy5lYm0pCmBgYApgYGB7ciwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSA0fQpsaWJyYXJ5KGdnYWx0KQpnZ3Bsb3QoZGF0YSA9IGVzc19lYm1fbWlubWF4X2RpZmZlcmVuY2UsIGFlcyh4ID0gMTAwICogcmVzcG9uc2VfcGVyYy5lYm0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ZW5kID0gMTAwICogcmVzcG9uc2VfcGVyYy5lc3MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBjbnRyeSkpICsKICBnZW9tX2R1bWJiZWxsKHNpemVfeCA9IDEuOCwgc2l6ZV94ZW5kID0gMiwgCiAgICAgICAgICAgICAgICBjb2xvdXJfeCA9ICJncmV5MTIiLCBjb2xvdXJfeGVuZCA9ICJkb2RnZXJibHVlMiIpICsgCiAgZmFjZXRfZ3JpZCguIH4gcmVzcG9uc2Vfa2luZCwgCiAgICAgICAgICAgICBsYWJlbGxlciA9IGxhYmVsbGVyKHJlc3BvbnNlX2tpbmQgPSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKCJOZWdhdGl2ZSIgPSAiTWluZCBhIGxvdCAoRVNTKSAvIE5vdCBjb21mb3J0YWJsZSBhdCBhbGwgKEVCTSkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBvc2l0aXZlIiA9ICJEb24ndCBtaW5kIGF0IGFsbCAoRVNTKSAvIFRvdGFsbHkgY29tZm9ydGFibGUgKEVCTSkiKSkpICsKICAjIFVuZm9ydHVuYXRlbHksIHNpbmNlIGdlb21fZHVtYmJlbGwgY2Fubm90IGNyZWF0ZSBsYWJlbHMgZm9yIHVzLCB3ZSBuZWVkIHRvCiAgIyBkcmF3IHRoZW0gbWFudWFsbHkKICBnZW9tX3RleHQoZGF0YV9mcmFtZShyZXNwb25zZV9raW5kID0gYygiTmVnYXRpdmUiLCAiTmVnYXRpdmUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUG9zaXRpdmUiLCAiUG9zaXRpdmUiKSwgIyBmb3IgZmFjZXRpbmcKICAgICAgICAgICAgICAgICAgICAgICB4X3Bvc2l0aW9uID0gYygyLjEsIDE5LjMsIDI4LjUsIDM4LjIpLAogICAgICAgICAgICAgICAgICAgICAgIHN1cnZleV9uYW1lID0gYygiRVNTIiwgIkVCTSIsICJFU1MiLCAiRUJNIikpLAogICAgICAgICAgICBpbmhlcml0LmFlcyA9IEZBTFNFLAogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHkgPSAiUEwiLCB4ID0geF9wb3NpdGlvbiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBzdXJ2ZXlfbmFtZSwgY29sb3IgPSBzdXJ2ZXlfbmFtZSksCiAgICAgICAgICAgIHNpemUgPSAyLjUsIGZvbnRmYWNlID0gImJvbGQiLCBudWRnZV95ID0gMC4wMikgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiZ3JleTEyIiwgImRvZGdlcmJsdWUyIiksIGd1aWRlID0gIm5vbmUiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgNjApLCBicmVha3MgPSBjKDAsIDE1LCAzMCwgNDUsIDYwKSkgKwogIGxhYnMoeCA9ICJQZXJjZW50YWdlIHBvaW50cyIsIHkgPSAiIiwKICAgICAgIHRpdGxlID0gIkZpZ2h0ISBFdXJvcGVhbiBTb2NpYWwgU3VydmV5IDIwMTQgdnMuIEV1cm9iYXJvbWV0ZXIgMjAxNSIsCiAgICAgICBzdWJ0aXRsZSA9ICIodXNpbmcgcXVlc3Rpb24gYWJvdXQgcG90ZW50aWFsIGJsYWNrIGlubGF3cyBhcyBwcm94eSBmb3IgdGhlIG1vcmUgZ2VuZXJhbCBxdWVzdGlvbiBpbiBFU1MpIiwKICAgICAgIGNhcHRpb24gPSAiUG9zaXRpdmUgc2NvcmVzIGluY2x1ZGUgdGhlIDQgbW9zdCBwb3NpdGl2ZSByZXNwb25zZXM7IGluIEVCTSwgaXQgYWxzbyBpbmNsdWRlcyB0aGUgJ0luZGlmZmVyZW50JyBhbnN3ZXIuIikgKwogIHRoZW1lKHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJncmV5NDAiLCBzaXplID0gOCkpCmBgYAoKQmVhcmluZyBpbiBtaW5kIHRoZSBsaW1pdGF0aW9ucyBvZiB0aGlzIGNvbXBhcmlzb24gKGRpZmZlcmVudCB5ZWFyLCBzYW1wbGUsIGFuZCBxdWVzdGlvbiBtZWFuIHRoYXQgd2UgY2Fubm90IGRldGVybWluZSBob3cgbXVjaCBvZiB0aGUgZGlmZmVyZW5jZSBpcyBkdWUgdG8gbWVhc3VyZW1lbnQgZXJyb3IgYW5kIGhvdyBtdWNoIGR1ZSB0byBnZW51aW5lIGF0dGl0dWRlIGRpZmZlcmVuY2UpLCBhbGxvdyBtZSB0byBkcmF3IHlvdXIgYXR0ZW50aW9uIHRvIGEgY291cGxlIG9mIHRoaW5nczoKCiogVGhlIEN6ZWNoIG1lYXN1cmUgdGhhdCBqdW1wZWQgX2EgbG90XyBpcyBub3QgdGhlIHBvdGVudGlhbGx5IG1pc3RyYW5zbGF0ZWQgcG9zaXRpdmUgb25lOyBpdCdzIHRoZSBuZWdhdGl2ZSBvbmUuIEluIG90aGVyIHdvcmRzLCAqKmlmIHRoZSBvcmlnaW5hbCBtYXAgd2FzIGJhc2VkIG9uIEVTUywgaXQgd291bGQgbG9vayB2ZXJ5IHNpbWlsYXIuKioKKiBJdCdzIHdvcnRoIG5vdGluZywgdGhvdWdoLCB0aGF0IHRoZSBDemVjaCBzYW1wbGUgaXMgdGhlIG9ubHkgb25lIGluIHdoaWNoIHRoZSBwb3NpdGl2ZSByYXRpbmcgX2RlY3JlYXNlZF8gZnJvbSBFU1MgdG8gRUJNLiAoV2VsbCwgdGVjaG5pY2FsbHksIHRoZSBCZWxnaWFuIHNhbXBsZSBzYXcgYSBkZWNyZWFzZSBhcyB3ZWxsLCBidXQgb25lIHRoYXQgd2FzIHdlbGwgd2l0aGluIHRoZSBtYXJnaW4gb2YgZXJyb3IuKSBUaGlzIGlzIHdlYWsgZXZpZGVuY2UgaW4gc3VwcG9ydCBvZiB0aGUgbWlzdHJhbnNsYXRpb24gaHlwb3RoZXNpcyAtIF9hcmd1ZW5kb18sIHRoZSBtaXN0cmFuc2xhdGlvbiBkaWRuJ3QgbWFrZSBhIGRpZmZlcmVuY2Ugd2hlbiBpdCBzaG91bGQgaGF2ZSwgdGh1cyBleGFnZ2VyYXRpbmcgdGhlIHRydWUgY3Jvc3MtY291bnRyeSBkaWZmZXJlbmNlcy4KICAgICogRnJlbmNoIHdhcyBvbmUgb2YgdGhlIG9yaWdpbmFsIGxhbmd1YWdlcyBvZiB0aGUgRXVyb2Jhcm9tZXRlciBzdXJ2ZXksIHNvICAtIGJ5IGRlZmluaXRpb24gLSBpdCBjb3VsZCBub3QgaGF2ZSBiZWVuIG1pc3RyYW5zbGF0ZWQuIE5vbmV0aGVsZXNzLCB0aGUgMjItcG9pbnQgcmlzZSBpbiBwb3NpdGl2ZSByYXRpbmdzIGZyb20gRVNTIHRvIEVCTSBpcyB0aGUgbGFyZ2VzdCBvZiBhbnkgY2hhbmdlcyAtIGlzIGl0IGJlY2F1c2UgdGhhdCdzIHRoZSAibmF0dXJhbCIgcmVzdWx0IG9mIHRoZSByZWZyYW1pbmc/IE9yIHBlcmhhcHMgYmVjYXVzZSB0aGVyZSdzIGEgbGFyZ2VyIGRpZmZlcmVuY2UgaW4gcGVyY2VwdGlvbiBiZXR3ZWVuICJpbW1pZ3JhbnQiIGFuZCAiYmxhY2sgcGVyc29uIiBkdWUgdG8gdGhlIG51bWJlciBvZiBGcmVuY2ggY2l0aXplbnMgZnJvbSB0aGUgb3ZlcnNlYXMgdGVycml0b3JpZXMsIHNvIHRoZSBjb21wYXJlZCBxdWVzdGlvbiBpcyBub3QgcmVhbGx5IHRoZSBzYW1lPyAoQWdhaW4sIEkgZmluZCBteXNlbGYgd2lzaGluZyB0aGF0IEVTUyBhc2tlZCB0aGUgc2FtZSBxdWVzdGlvbnMgYXMgRUJNLikKKiBCdXQgdGhlcmUgYXJlIGEgbG90IG9mIGNvdW50cnkgc2FtcGxlcyB0aGF0IHdlcmUgaW52YXJpYW50IHRvIHRoZSBkaWZmZXJlbnQgcXVlc3Rpb24gYW5kIHRoZSBkaWZmZXJlbnQgcmVzcG9uc2Ugc2NhbGUsIGxlbmRpbmcgc3VwcG9ydCB0byB0aGUgaWRlYSB0aGF0ICoqdGhlIG1lYXN1cmVkIGNvbnN0cnVjdCAtIGV4cGxpY2l0IGFkbWlzc2lvbiBvZiBkaXNjb21mb3J0IC0gaXMgcm9idXN0IHRvIGRpZmZlcmVudCBxdWVzdGlvbiBwaHJhc2luZ3MgaW4gbWFueSBFdXJvcGVhbiBjb3VudHJpZXMuKioKCkFnYWluLCBkdWUgdG8gdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgdHdvIHN1cnZleXMsIHdlIGhhdmUgdG8gdGFrZSB0aGUgZGlmZmVyZW5jZXMgd2l0aCBhIGdyYWluIG9mIHNhbHQuIEkgcmVhbGx5IHdpc2ggRVNTIGRpZCBhc2sgdGhlIF9zYW1lXyBxdWVzdGlvbi4KCiMjIEFyZSB0aGVyZSBvdGhlciB3YXlzIHRvIChpbil2YWxpZGF0ZSB0aGUgRUJNIHJlc3VsdHM/CgpNeSBjb3VzaW4gSmFuIHN1Z2dlc3RlZCB0aGUgcmFjaWFsLWRpZmZlcmVuY2VzIEltcGxpY2l0IEFzc29jaWF0aW9uIFRlc3QsIFt3aGljaCBoYXMgc29tZSB1bmZvcnR1bmF0ZSBpc3N1ZXMuXShodHRwOi8vbnltYWcuY29tL3NjaWVuY2VvZnVzLzIwMTcvMDEvcHN5Y2hvbG9neXMtcmFjaXNtLW1lYXN1cmluZy10b29sLWlzbnQtdXAtdG8tdGhlLWpvYi5odG1sKSBQZXJoYXBzIHNvbWVvbmUgaGFzIGRvbmUgdGhlIHJlc3VtZSBtZXRob2RvbG9neT8gSSB3aWxsIGJlIGdyYXRlZnVsIGZvciBzdWdnZXN0aW9ucyAtLSBsaWtlIEkgc2FpZCwgdGhpcyBpcyBuZWl0aGVyIG15IGNpcmN1cyBub3IgbXkgbW9ua2V5cy4KCiMgTWFraW5nIG5ldyBtYXBzCgpNeSBvcmlnaW5hbCBnb2FsIHdhcyB0byByZW1ha2UgYW5kIHBsYXkgYXJvdW5kIHdpdGggdGhlIGxpdHRsZSBtYXAuIFRoaXMgdG9vayBtZSB0aGUgbG9uZ2VzdCBhbmQgSSB3ZW50IHRocm91Z2ggYSBidW5jaCBvZiBhdHRlbXB0cywgd2hpY2ggd2lsbCBpbiB0aW1lIGdldCB0aGVpciBvd24gYXJ0aWNsZS4KCmBgYHtyfQojIyBTZXR1cApsaWJyYXJ5KHRtYXApCmxpYnJhcnkodG1hcHRvb2xzKQoKZGF0YShFdXJvcGUpCmNvbnZlcnRFQk1Db3VudHJ5Q29kZXMgPC0gZnVuY3Rpb24oaXNvY250cnlfY29sdW1uKSB7CiAgY291bnRyeWNvZGU6OmNvdW50cnljb2RlKGlzb2NudHJ5X2NvbHVtbiwgImlzbzJjIiwgImlzbzNjIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1c3RvbV9tYXRjaCA9IGMoIkdCLU5JUiIgPSAiR0JSIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR0ItR0JOIiA9ICJHQlIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJERS1FIiA9ICJERVUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJERS1XIiA9ICJERVUiKSkKfQoKIyBUaGlzIGlzIGEgZGlmZmVyZW50IHJlc2hhcGluZyBvZiB0aGUgZGF0YQptYXBwYWJsZV9lYm0gPC0gZWIxNV9jb21mb3J0X3dpZGUgJT4lCiAgbXV0YXRlKGlzb19hMyA9IGNvbnZlcnRFQk1Db3VudHJ5Q29kZXMoaXNvY250cnkpKQplYm1fY291bnRyeV9jb3VudHMgPC0gZWIxNSAlPiUgCiAgbXV0YXRlKGlzb19hMyA9IGNvbnZlcnRFQk1Db3VudHJ5Q29kZXMoaXNvY250cnkpKSAlPiUKICBncm91cF9ieShpc29fYTMpICU+JQogIHN1bW1hcml6ZSh0b3RhbF9yZXNwb25kZW50cyA9IG4oKSkKbWFwcGFibGVfcHJlcHBlZCA8LSBtYXBwYWJsZV9lYm0gJT4lIAogIG11dGF0ZShyZXNwb25zZSA9IGZjdF9jb2xsYXBzZShhcy5mYWN0b3IocmVzcG9uc2UpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlVuY29tZm9ydGFibGUiID0gYygiTm90IGF0IGFsbCBjb21mb3J0YWJsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNvbWZvcnRhYmxlIiA9IGMoIjciLCAiOCIsICI5IiwgIlRvdGFsbHkgY29tZm9ydGFibGUiLCAiSW5kaWZmZXJlbnQiKSkpICU+JQogIG11dGF0ZV9hdCh2YXJzKGlzb19hMywgcXVlc3Rpb25fa2luZCwgdGFyZ2V0KSwgYXMuZmFjdG9yKSAlPiUKICBncm91cF9ieShpc29fYTMsIHF1ZXN0aW9uX2tpbmQsIHRhcmdldCwgcmVzcG9uc2UpICU+JQogIHN1bW1hcml6ZShyZXNwb25zZV9jb3VudCA9IG4oKSkKbWFwcGFibGVfdW5jb21mb3J0YWJsZSA8LSBtYXBwYWJsZV9wcmVwcGVkICU+JQogIGZpbHRlcihyZXNwb25zZSA9PSAiVW5jb21mb3J0YWJsZSIpICU+JQogIG1lcmdlKGVibV9jb3VudHJ5X2NvdW50cykgJT4lCiAgbXV0YXRlKHVuY29tZm9ydGFibGVfcGVyY2VudCA9IDEwMCAqIHJlc3BvbnNlX2NvdW50IC8gdG90YWxfcmVzcG9uZGVudHMpICU+JQogIHNlbGVjdChpc29fYTMsIHF1ZXN0aW9uX2tpbmQsIHRhcmdldCwgdW5jb21mb3J0YWJsZV9wZXJjZW50KQptYXBwYWJsZV9jb21mb3J0YWJsZSA8LSBtYXBwYWJsZV9wcmVwcGVkICU+JQogIGZpbHRlcihyZXNwb25zZSA9PSAiQ29tZm9ydGFibGUiKSAlPiUKICBtZXJnZShlYm1fY291bnRyeV9jb3VudHMpICU+JQogIG11dGF0ZShjb21mb3J0YWJsZV9wZXJjZW50ID0gMTAwICogcmVzcG9uc2VfY291bnQgLyB0b3RhbF9yZXNwb25kZW50cykgJT4lCiAgc2VsZWN0KGlzb19hMywgcXVlc3Rpb25fa2luZCwgdGFyZ2V0LCBjb21mb3J0YWJsZV9wZXJjZW50KQptYXBwYWJsZV9ib3RoIDwtIGZ1bGxfam9pbihtYXBwYWJsZV9jb21mb3J0YWJsZSwgbWFwcGFibGVfdW5jb21mb3J0YWJsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSBjKCJpc29fYTMiLCAicXVlc3Rpb25fa2luZCIsICJ0YXJnZXQiKSkKCiMgYW5kIHJlc2hhcGUgdGhlIGRhdGEgZnJvbSBFU1MgdG8gYmUgcGxvdHRhYmxlIGFsb25nc2lkZQptYXBwYWJsZV9lc3MgPC0gZXNzMTRfc3ViICU+JQogIG11dGF0ZShpc29fYTMgPSBjb3VudHJ5Y29kZTo6Y291bnRyeWNvZGUoY250cnksICJpc28yYyIsICJpc28zYyIpKSAlPiUKICBtdXRhdGUoaW1kZXRtciA9IGZjdF9jb2xsYXBzZShpbWRldG1yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ29tZm9ydGFibGUiID0gYygiTm90IG1pbmQgYXQgYWxsIiwgIjEiLCAiMiIsICIzIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlVuY29tZm9ydGFibGUiID0gYygiOSIsICJNaW5kIGEgbG90IikpKSAlPiUKICBncm91cF9ieShpc29fYTMsIGltZGV0bXIpICU+JSBzdW1tYXJpemUocmVzcG9uc2VfY291bnQgPSBuKCkpICU+JQogIG11dGF0ZShyZXNwb25zZV9wZXJjZW50YWdlID0gMTAwICogKHJlc3BvbnNlX2NvdW50IC8gc3VtKHJlc3BvbnNlX2NvdW50KSkpICU+JQogIHNlbGVjdCgtcmVzcG9uc2VfY291bnQpICU+JQogIGZpbHRlcihpbWRldG1yICVpbiUgYygiQ29tZm9ydGFibGUiLCAiVW5jb21mb3J0YWJsZSIpKSAlPiUKICBzcHJlYWQoaW1kZXRtciwgcmVzcG9uc2VfcGVyY2VudGFnZSkgJT4lIHVuZ3JvdXAoKQpgYGAKYGBge3J9CiMjIFdvcmtob3JzZSBmdW5jdGlvbiBmb3IgbWFwIGRpc3BsYXkKIyBleHBlY3RzIGEgbG9uZyBkYXRhc2V0IHRoYXQgaXMgcmVhZHkgZm9yIGEgbWVyZ2UgYnkgYGlzb19hM2AgY29sdW1uCm1hcExvdmVDb21mb3J0IDwtIGZ1bmN0aW9uKGRhdGFzZXQsIHRhcmdldF9uYW1lLCBjb2x1bW5fb2ZfaW50ZXJlc3QgPSAiY29tZm9ydGFibGVfcGVyY2VudCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbl90aXRsZSA9ICIlIHRvdGFsbHkgY29tZm9ydGFibGVcbig3LTEwIG9uIHNjYWxlIG9yIGFuc3dlcmVkICdJbmRpZmZlcmVudCcpIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhbGV0dGUgPSAiUmRZbEduIikgewogIGFwcGVuZF9kYXRhKEV1cm9wZSwgZGF0YXNldCAlPiUKICAgICAgICAgICAgICAgIGZpbHRlcihxdWVzdGlvbl9raW5kID09ICJsb3ZlIHJlbGF0aW9uc3NoaXAgb2YgY2hpbGQiLAogICAgICAgICAgICAgICAgICAgICAgIHRhcmdldCA9PSB0YXJnZXRfbmFtZSksCiAgICAgICAgICAgICAgImlzb19hMyIsICJpc29fYTMiLCBpZ25vcmUubmEgPSBUUlVFLCAKICAgICAgICAgICAgICBpZ25vcmUuZHVwbGljYXRlcyA9IFRSVUUpICU+JQogICAgdG1fc2hhcGUoKSArCiAgICB0bV9wb2x5Z29ucyhjb2x1bW5fb2ZfaW50ZXJlc3QsCiAgICAgICAgICAgICAgICB0aXRsZSA9IGNvbHVtbl90aXRsZSwKICAgICAgICAgICAgICAgIHBhbGV0dGUgPSBwYWxldHRlLAogICAgICAgICAgICAgICAgYXV0by5wYWxldHRlLm1hcHBpbmcgPSBGQUxTRSwKICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcS5pbnQoMCwgMTAwLCAxMCksIAogICAgICAgICAgICAgICAgbGVnZW5kLmZvcm1hdCA9IGZ1bmN0aW9uKHgpIHBhc3RlMCh4LCAiJSIpKSArCiAgICB0bV9sYXlvdXQobGVnZW5kLm91dHNpZGUgPSBGLCBsZWdlbmQucG9zaXRpb24gPSBjKCJSSUdIVCIsICJUT1AiKSwKICAgICAgICAgICAgICBsZWdlbmQuZnJhbWUgPSBULCAKICAgICAgICAgICAgICBtYWluLnRpdGxlID0gcGFzdGUwKCJIb3cgY29tZm9ydGFibGUgd291bGQgeW91IGZlZWwgaWYgeW91ciBjaGlsZFxud2FzIGluICIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYSBsb3ZlIHJlbGF0aW9uc2hpcCB3aXRoIGEgIiwgUi51dGlsczo6Y2FwaXRhbGl6ZSh0YXJnZXRfbmFtZSksICI/IiksCiAgICAgICAgICAgICAgbWFpbi50aXRsZS5zaXplID0gMSkKfQoKdGFyZ2V0cyA8LSBwYXN0ZTAoYygiYmxhY2siLCAiYXNpYW4iLCAibXVzbGltIiwgImpld2lzaCIpLCAiIHBlcnNvbiIpCmBgYAoKIyMgUmVwbGljYXRpbmcgdGhlIG9yaWdpbmFsIG1hcAoKVGhpcyBpcywgc29ydCBvZiwgdGhlIG9yaWdpbmFsIG1hcC4gVGhlIG1haW4gZGlmZmVyZW5jZSBpcyB0aGF0IGl0IHVzZXMgeWVsbG93IG1pZHBvaW50cyBmb3IgdGhlIHRyYW5zaXRpb24gYmV0d2VlbiByZWQgYW5kIGdyZWVuLgoKYGBge3IsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0Kb3JpZ2luYWxfY29tZm9ydF9tYXBzIDwtIHNhcHBseSh0YXJnZXRzLCBmdW5jdGlvbih4KSBtYXBMb3ZlQ29tZm9ydChtYXBwYWJsZV9ib3RoLCB4LCBjb2x1bW5fb2ZfaW50ZXJlc3QgPSAiY29tZm9ydGFibGVfcGVyY2VudCIpLCBzaW1wbGlmeSA9IEZBTFNFKQpkby5jYWxsKHRtYXBfYXJyYW5nZSwgb3JpZ2luYWxfY29tZm9ydF9tYXBzKQpgYGAKClRoaXMgaXMgYW4gaW1wcm92ZW1lbnQgb24gdGhlIG9yaWdpbmFsIG1hcCdzIGNvbG9yc2NoZW1lLCBJIHRoaW5rLiBUaGVyZSdzIHN0aWxsIGFuIGltcGxpY2F0aW9uIHRoYXQgdGhlIGdyZWVuIGFyZWFzIGFyZSAiY29ycmVjdCIsIHRob3VnaCwgd2hpY2ggbWlzbGVhZGluZ2x5IHN1Z2dlc3RzIGEgbm9ybWF0aXZlIGNyaXRlcmlvbiBhdCA+NTAlICJjb21mb3J0YWJsZSIgcG9wdWxhdGlvbiwgc28uLi4KCiMjIyBUaGUgb3JpZ2luYWwgbWFwIHdpdGggYSBiZXR0ZXIgY29sb3Igc2NhbGUKCi4uLndlIGNhbiBtYWtlIGEgc2luZ2xlLWNvbG9yIG1hcCwgd2hpY2ggYWxzbyBoYXMgdGhlIGJlbmVmaXQgb2Ygbm90IGJlaW5nIGFuIGFzc2hvbGUgdG8gcGVvcGxlIHdpdGggcmVkLWdyZWVuIGNvbG9yYmxpbmRuZXNzLgoKYGBge3IsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9Cm9yaWdpbmFsX2NvbWZvcnRfbWFwcyA8LSBzYXBwbHkodGFyZ2V0cywgZnVuY3Rpb24oeCkgbWFwTG92ZUNvbWZvcnQobWFwcGFibGVfYm90aCwgeCwgY29sdW1uX29mX2ludGVyZXN0ID0gImNvbWZvcnRhYmxlX3BlcmNlbnQiLCBwYWxldHRlID0gIi1SZWRzIiksIHNpbXBsaWZ5ID0gRkFMU0UpCmRvLmNhbGwodG1hcF9hcnJhbmdlLCBvcmlnaW5hbF9jb21mb3J0X21hcHMpCmBgYAoKIyMgVGhlIEV1cm9wZWFuIFNvY2lhbCBTdXJ2ZXkgImNvbWZvcnQiIG1hcAoKQXMgYSByZWxldmFudCBjb21wYXJpc29uLCB3ZSBjYW4sIG9mIGNvdXJzZSwgdGFrZSBhIGxvb2sgYXQgdGhlIEV1cm9wZWFuIFNvY2lhbCBTdXJ2ZXkncyBtb3N0IHBvc2l0aXZlIHJlc3BvbnNlcy4gRm9yIGNsYXJpdHkncyBzYWtlLCBJIHNob3cgdGhlbSB1c2luZyBib3RoIHBhbGV0dGVzLgoKYGBge3IsIGZpZy5oZWlnaHQgPSA2LCBmaWcud2lkdGggPSAxMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZXNzX2NvbW1vbl9tYXAgPC0gYXBwZW5kX2RhdGEoRXVyb3BlLCBtYXBwYWJsZV9lc3MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJpc29fYTMiLCAiaXNvX2EzIiwgaWdub3JlLm5hID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlnbm9yZS5kdXBsaWNhdGVzID0gVFJVRSkgJT4lCiAgdG1fc2hhcGUoKSArCiAgdG1fbGF5b3V0KGxlZ2VuZC5vdXRzaWRlID0gRiwgbGVnZW5kLnBvc2l0aW9uID0gYygiUklHSFQiLCAiVE9QIiksCiAgICAgICAgICAgIGxlZ2VuZC5mcmFtZSA9IFQsIAogICAgICAgICAgICBtYWluLnRpdGxlID0gcGFzdGUwKCJIb3cgY29tZm9ydGFibGUgd291bGQgeW91IGZlZWwgaWYgeW91ciBjaGlsZFxud2FzIGluICIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImEgbG92ZSByZWxhdGlvbnNoaXAgd2l0aCBhbiBpbW1pZ3JhbnQ/IiksCiAgICAgICAgICAgIG1haW4udGl0bGUuc2l6ZSA9IDEpCgplc3Nfc2luZ2xlX3BhbGV0dGVfbWFwIDwtIGVzc19jb21tb25fbWFwICsgdG1fcG9seWdvbnMoIkNvbWZvcnRhYmxlIiwKICAgICAgICAgICAgICB0aXRsZSA9ICIlIGNvbWZvcnRhYmxlICg3IHRvICdOb3QgbWluZCBhdCBhbGwnKSIsCiAgICAgICAgICAgICAgcGFsZXR0ZSA9ICItUmVkcyIsCiAgICAgICAgICAgICAgYXV0by5wYWxldHRlLm1hcHBpbmcgPSBGQUxTRSwKICAgICAgICAgICAgICBicmVha3MgPSBzZXEuaW50KDAsIDEwMCwgMTApLCAKICAgICAgICAgICAgICBsZWdlbmQuZm9ybWF0ID0gZnVuY3Rpb24oeCkgcGFzdGUwKHgsICIlIikpCmVzc19vcmlnaW5hbF9wYWxldHRlX21hcCA8LSBlc3NfY29tbW9uX21hcCArIHRtX3BvbHlnb25zKCJDb21mb3J0YWJsZSIsCiAgICAgICAgICAgICAgdGl0bGUgPSAiJSBjb21mb3J0YWJsZSAoNyB0byAnTm90IG1pbmQgYXQgYWxsJykiLAogICAgICAgICAgICAgIHBhbGV0dGUgPSAiUmRZbEduIiwKICAgICAgICAgICAgICBhdXRvLnBhbGV0dGUubWFwcGluZyA9IEZBTFNFLAogICAgICAgICAgICAgIGJyZWFrcyA9IHNlcS5pbnQoMCwgMTAwLCAxMCksIAogICAgICAgICAgICAgIGxlZ2VuZC5mb3JtYXQgPSBmdW5jdGlvbih4KSBwYXN0ZTAoeCwgIiUiKSkKdG1hcF9hcnJhbmdlKGVzc19zaW5nbGVfcGFsZXR0ZV9tYXAsIGVzc19vcmlnaW5hbF9wYWxldHRlX21hcCkKYGBgCgojIyBUaGUgY29uc2VydmF0aXZlICJkaXNjb21mb3J0IiBtYXAKCkFzIG5vdGVkIGluIHRoZSBNZXRob2RvbG9naWNhbCBjcml0aWNpc21zIHNlY3Rpb24sIHdlIGhhdmUgYSBidW5jaCBvZiByZWFzb25zIHRvIHRoaW5rIHRoYXQgdGhlIGV4dHJlbWUgbmVnYXRpdmUgZW5kIG9mIHRoZSBzY2FsZSBtaWdodCBiZSBtb3JlIGluZm9ybWF0aXZlIHRoYW4gdGhlIHBvc2l0aXZlIGVuZC4KCkluIHRoaXMgY2FzZSwgd2UndmUgYXBwbGllZCBzdHJpY3RlciBpbmNsdXNpb24gY3JpdGVyaWEgLS0gd2Ugb25seSB0YWtlIHRoZSBsb3dlc3QgdHdvIHBvaW50cyByYXRoZXIgdGhhbiB0aGUgbG93ZXN0IGZvdXIuCgpgYGB7ciwgZmlnLmhlaWdodCA9IDEwLCBmaWcud2lkdGggPSAxMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0Kb3JpZ2luYWxfZGlzY29tZm9ydF9tYXBzIDwtIHNhcHBseSh0YXJnZXRzLCBmdW5jdGlvbih4KSBtYXBMb3ZlQ29tZm9ydChtYXBwYWJsZV9ib3RoLCB4LCBjb2x1bW5fb2ZfaW50ZXJlc3QgPSAidW5jb21mb3J0YWJsZV9wZXJjZW50IiwgY29sdW1uX3RpdGxlID0gIiUgbm90IGF0IGFsbCBjb21mb3J0YWJsZVxuKDEgb3IgMiBvbiBzY2FsZSkiLCAgcGFsZXR0ZSA9ICJSZWRzIiksIHNpbXBsaWZ5ID0gRkFMU0UpCmRvLmNhbGwodG1hcF9hcnJhbmdlLCBvcmlnaW5hbF9kaXNjb21mb3J0X21hcHMpCmBgYAoKVGhpcyBtYWtlcyBteSBob21lbGFuZCBsb29rIG11Y2ggbGVzcyBhbnRpLVNlbWl0aWMsIHNvIGh1cnJheSEKCiMjIyBDb25zZXJ2YXRpdmUgImRpc2NvbWZvcnQiIG1lYXN1cmUgd2l0aCB0aGUgb3JpZ2luYWwgcGFsZXR0ZQoKRmluYWxseSwganVzdCBiZWNhdXNlIHdlIGNhbiwgaGVyZSdzIHRoZSBzYW1lIG1hcCB3aXRoIHRoZSBvcmlnaW5hbCBjb2xvcnMuCgpgYGB7ciwgZmlnLmhlaWdodCA9IDEwLCBmaWcud2lkdGggPSAxMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZWJtX2Rpc2NvbWZvcnQgPC0gc2FwcGx5KHRhcmdldHMsIGZ1bmN0aW9uKHgpIG1hcExvdmVDb21mb3J0KG1hcHBhYmxlX2JvdGgsIHgsIGNvbHVtbl9vZl9pbnRlcmVzdCA9ICJ1bmNvbWZvcnRhYmxlX3BlcmNlbnQiLCBjb2x1bW5fdGl0bGUgPSAiJSBub3QgYXQgYWxsIGNvbWZvcnRhYmxlXG4oMSBvciAyIG9uIHNjYWxlKSIsICBwYWxldHRlID0gIi1SZFlsR24iKSwgc2ltcGxpZnkgPSBGQUxTRSkKZG8uY2FsbCh0bWFwX2FycmFuZ2UsIGVibV9kaXNjb21mb3J0KQpgYGAKCiMgTW90aXZhdGlvbnMgYW5kIGxpbWl0YXRpb25zCgpTaW5jZSBteSBtb3RpdmF0aW9ucyBmb3Igd3JpdGluZyB0aGlzIGFyZSBnb2luZyB0byBjb21lIHVwLCBJIHRob3VnaHQgSSdkIHN1cHBseSBhIGNvdXBsZSBvZiBhbnN3ZXJzLiAoVGhpcyBpcywgb2YgY291cnNlLCB0byBkaXZlcnQgdGhlIHB1cmUgb2YgaGVhcnQgYXdheSBmcm9tIHRoZSBgKCgoVHJVdEgpKSlgLiBZb3UgY2F1Z2h0IG1lLikKCiMjIFdobydzIHBheWluZyB5b3U/CgpOb3QgR2VvcmdlIFNvcm9zLCBhbHRob3VnaCBiYWNrIGluIG5pbnRoIGdyYWRlLCBbSSByZWFsbHkgd2FudGVkIGhpbSB0b10oaHR0cDovL29zZi5jei9jcy9qYWstcG9tYWhhbWUvc3RpcGVuZGlhL3N0cmVkb3Nrb2xza2EvKS4gT3ZlciB0aGUgeWVhcnMsIEknbSBhZnJhaWQgSSBhY3R1YWxseSBzcGVudCBtdWNoIG1vcmUgdGltZSBvbiBbQ2hhcmxlcyBLb2NoJ3MgZGltZV0oaHR0cHM6Ly90aGVpaHMub3JnLykuIEkgd2FzIGEgQmFrYWxhIFNjaG9sYXIsIHdoaWNoIHdvdWxkIGB+ZXhQbGFpbiB0SGluZ3N+YCwgYnV0IGFsc28gYSBLZWxsbmVyIEZhbWlseSBTY2hvbGFyLCB3aGljaC4uLiB3b3VsZG4ndC4gSGlsYXJpb3VzbHkgZW5vdWdoLCB0byB0aGUgYmVzdCBvZiBteSBrbm93bGVkZ2UsIEkgaGF2ZSBuZXZlciByZWNlaXZlZCBhbiBFVSBncmFudC4KClJpZ2h0IG5vdywgdGhlIG9ubHkgaW5zdGl0dXRpb24gdGhhdCdzIHBheWluZyBtZSBpcyBZYWxlLCBidXQgbm90IGZvciB0aGlzLgoKSWYgeW91J3JlIHNlZWtpbmcgdG8gaW1wdXRlIGltcHVyZSBpbmNlbnRpdmVzIHRvIG1lLCBteSBsaXN0IG9mIHBhc3QgZnVuZGluZyBzb3VyY2VzIG1pZ2h0IHByb3ZlIGNvbmZ1c2luZy4gSXQgbWlnaHQgYWxtb3N0IGJlIHNpbXBsZXIgdG8gaW1hZ2luZSB0aGF0IHNvbWUgcGVvcGxlIG1pZ2h0IGhvbGQgYmVsaWVmcyB0aGF0IGFyZSBpbmRlcGVuZGVudCBvZiB0aGVpciBmdW5kaW5nLgoKVG8gc3VnZ2VzdCBhbiBhbHRlcm5hdGl2ZSB0byB0aGUgbW9uZXRhcnkgbW90aXZlLCBJJ2QgbGlrZSB0byBzaGFyZSB0aHJlZSB0aGluZ3MgYWJvdXQgbXlzZWxmOgoKMS4gSSBsaWtlIGRldGFpbGVkIG9wZW4gZGF0YSBhbmQgdGhlIGxldmVsIG9mIEV1cm9iYXJvbWV0ZXIncyBjb3ZlcmFnZSB3YXMgZGVsaWdodGZ1bC4gRGlzbWlzc2luZyBpdCBvdXQgb2YgaGFuZCBzZWVtcyB3YXN0ZWZ1bC4KMi4gSSBsaWtlIGJ1dHRpbmcgaW50byBhcmd1bWVudHMgdGhhdCBhbGxvdyBmb3IgZW1waXJpY2FsIGNvdW50ZXItY2xhaW1zLgozLiBJIGdldCBzdHVjayBvbiBpbnRlcmVzdGluZyBwcm9ibGVtcywgZXNwZWNpYWxseSB3aGVuIHBlb3BsZSBhcmUgZWFnZXIgdG8gYXJndWUgYWJvdXQgdGhlbS4KCiMjIFlvdSdyZSBqdXN0IHByb3RlY3RpbmcgYSBzdHVkeSB0aGF0IGNvbmZpcm1zIHlvdXIgYmVsaWVmcyEKCllvdSdyZSBqdXN0IGRpc21pc3NpbmcgYSBzdHVkeSB0aGF0IHF1ZXN0aW9ucyB5b3VyIGJlbGllZnMhIFNlZSBob3cgdGhpcyBpcyBub3QgYSB1c2VmdWwgY3JpdGljaXNtPyBOb2JvZHkgaXMgZnJlZSBvZiBjb2duaXRpdmUgYmlhc2VzLgoKQnV0IHdlIGNhbiB0YWtlIGEgbG9vayBhdCB0aGUgZGF0YSwgbWFrZSBvdXIgYmVzdCBhcmd1bWVudHMsIGFuZCBzZWUgaWYgb3RoZXJzIGNhbiB0ZWFyIHRoZW0gZG93biBpbiBhIHdheSB0aGF0IG1ha2VzIHVzIGRpc2NhcmQgdGhlbS4gSSBtaWdodCBub3QgY2hhbmdlIHlvdXIgbWluZCBhbmQgeW91IG1pZ2h0IG5vdCBjaGFuZ2UgbWluZSAodGhvdWdoIEknbGwgdHJ5ISksIGJ1dCB3ZSBkb24ndCBqdXN0IGRvIGl0IGZvciBvdXJzZWx2ZXM7IHdlIGRvIGl0IHNvIHRoYXQgdGhlIHBlb3BsZSB3aG8gYXJlbid0IGFzIGludmVzdGVkIGluIHRoZSBxdWVzdGlvbiBjYW4gbWFrZSBhIGJldHRlciBkZWNpc2lvbi4gTXkgZXBpc3RlbW9sb2d5IG5lZWRzIG5vdCBiZSBmbGF3bGVzcyB0byBiZW5lZml0IHRoZSBjb21tdW5pdHkgZXBpc3RlbWljcy4KCkhvbmVzdGx5LCB3aGF0IGFuaW1hdGVzIG1lIHRoZSBtb3N0IGluIHdyaXRpbmcgdGhpcyBwb3N0IGlzIHRoZSBibGl0aGUgZGlzbWlzc2FsIG9mIGEgc3VydmV5IHRoYXQgaXMgY2FyZWZ1bGx5IGRvY3VtZW50ZWQsIGl0cyByYXcgZGF0YSBwdWJsaWNseSBhdmFpbGFibGUsIGFuZCBpdHMgc2NvcGUgbmFycm93IGVub3VnaCB0aGF0IGl0IGNhbiBhc2sgcXVlc3Rpb25zIGF0IGEgdmVyeSBncmFudWxhciBsZXZlbC4gSXQgY29sbGVjdGVkIGEgbGFyZ2Ugc2FtcGxlIHVzaW5nIGluLXBlcnNvbiBpbnRlcnZpZXdzLCB0YWtpbmcgY2FyZSB0byBvYnRhaW4gZ2VvZ3JhcGhpY2FsIHZhcmlhYmlsaXR5IHdpdGhpbiBlYWNoIGNvdW50cnkuIEl0IGFjdHVhbGx5IF9kaWRfIHRyeSB0byBndWFyZCBhZ2FpbnN0IG1pc3RyYW5zbGF0aW9uIGJ5IGltcGxlbWVudGluZyBhIGJhY2stdHJhbnNsYXRpb24gc3RlcC4gSW4gc2hvcnQsIHRoZSBwZW9wbGUgYmVnaW5kIEV1cm9iYXJvbWV0ZXIgZGlkIGEgbG90IG9mIHRoaW5ncyByaWdodC4KClNvbWUgaGF2ZSBjYWxsZWQgI09wZW5TY2llbmNlIG1lcmUgbWV0aG9kb2xvZ2ljYWwgdGVycm9yaXNtLiBBcyB0aGF0IGxpbmUgb2YgYXJndW1lbnQgZ29lcywgd2UncmUganVzdCBtZWFuIGJ1bGxpZXMgc2Vla2luZyB0byBmaW5kIGEgY291cGxlIG9mIGZsYXdzIGluIG9yZGVyIHRvIGRpc2NyZWRpdCBhIHdob2xlIHJlc2VhcmNoIHByb2dyYW0uIElmIHdlJ3ZlIGJlY29tZSBsYXJnZSwgdGhlIGNyaXRpcXVlIGdvZXMsIGl0IGlzIGJlY2F1c2Ugd2UncmUgc3RhbmRpbmcgb24gdGhlIGNvcnBzZXMgb2Ygd2VsbC1tZWFuaW5nIGNvbGxlYWd1ZXMuIE15IHByZWZlcnJlZCByZXNwb25zZSB0byB0aGF0IGNyaXRpY2lzbSBpcyBnaXZpbmcgY3JlZGl0IHdoZXJlIGl0J3MgZHVlLgoKSSBjYXJlIGFib3V0IHRoZSBxdWFsaXR5IG9mIHNjaWVuY2UuIEkgY2FyZSBhYm91dCB0aGUgcXVhbGl0eSBvZiBzY2llbmNlIF9hIGxvdF8uIEluIHRoZSBwYXN0IGNvdXBsZSBvZiB5ZWFycywgdGhpcyBoYXMgb2Z0ZW4gbWVhbnQgY3V0dGluZyBhd2F5IHNsb3BweSBhbmQvb3IgdW5kZXJwb3dlcmVkIHJlc2VhcmNoIGluIG9yZGVyIHRvIHJlZHVjZSBmYWxzZSBwb3NpdGl2ZXMuIEJ1dCBpdCdzIGltcG9ydGFudCB0byByZW1lbWJlciB0aGF0IHdlJ3JlIHRyeWluZyB0byByZWFjaCBhIGJhbGFuY2UgYmV0d2VlbiBUeXBlIEkgYW5kIFR5cGUgSUkgZXJyb3JzIGhlcmUsIHRob3VnaDogdGhlcmUncyBfYW5fIGFtb3VudCBvZiBlcnJvciB0aGF0J3Mgc3VmZmljaWVudCB0byBkaXNtaXNzIGEgZGF0YXNldCwgYnV0IGl0J3Mgbm90IF9hbnlfIGFtb3VudC4KCihJbiBvdGhlciB3b3JkcywgaXQncyB0aGF0IHN3ZWV0LCBzd2VldCBbQXJub2xkIEZvdW5kYXRpb25dKGh0dHBzOi8vd3d3LndpcmVkLmNvbS8yMDE3LzAxL2pvaG4tYXJub2xkLXdhZ2luZy13YXItb24tYmFkLXNjaWVuY2UvKSBjYXNoIEknbSBhZnRlci4pCgpXaGljaCBkb2Vzbid0IGFjdHVhbGx5IG1lYW4gdGhhdCBJJ20gbGV0dGluZyBFdXJvYmFyb21ldGVyIG9mIHRoZSBob29rLgoKIyMgVGhlcmUgYXJlIG5vdCB0aGUgbGltaXRhdGlvbnMgeW91IGFyZSBsb29raW5nIGZvcgoKSW4gYSByZWFsIHNlbnNlLCBtdWNoIG9mIHRoZSBjcml0aWNpc20gbWlzc2VzIHRoZSBmb3Jlc3QgZm9yIHRoZSB0cmVlcy4gSXTigJlzIG5pdHBpY2tpbmcsIHdoZXRoZXIgb3Igbm90IHRoZSBuaXRzIGFyZSB0aGVyZSwgYmVjYXVzZSBuaXQtc2l6ZWQgcHJvYmxlbXMgd2UgY2FuIGRlYWwgd2l0aC4KCkRvZXMgYW55IG9mIHRoZSBjcml0aXF1ZXMgSSBhZGRyZXNzZWQgbWF0dGVyPyBFdmVuIGlmIHRoZSBzdXJ2ZXkgdHJhbnNsYXRpb24gYWNoaWV2ZWQgcGVyZmVjdCBmaWRlbGl0eSBhY3Jvc3MgbGFuZ3VhZ2VzIGFuZCB0aGUgb3JpZ2luYWwgcXVlc3Rpb25zIHdlcmUgcGhyYXNlZCBzbyB0aGF0IHRoZXkgYXZvaWRlZCBiaWFzaW5nIHRoZSByZXNwb25kZW50cywgaXQgd291bGQgc3RpbGwgYmUgYSBzb2NpYWwtc2NpZW5jZSBpbnN0cnVtZW50IFt3aGljaCwgYWxvbmcgd2l0aCBldmVyeXRoaW5nLCBpcyBmdWNrZWQuXShodHRwczovL2hhcmRzY2kud29yZHByZXNzLmNvbS8yMDE2LzA4LzExL2V2ZXJ5dGhpbmctaXMtZnVja2VkLXRoZS1zeWxsYWJ1cy8pIAoKSW4gb25lIHNlbnNlLCB0aGlzIHN1cnZleSBpcyBmaW5lLiBJdCBhdHRlbXB0ZWQgdG8gb2JzZXJ2ZSBhbiBhY2N1cmF0ZSBlc3RpbWF0ZSBvZiB0aGUgcmVzcG9uc2UgZGlzdHJpYnV0aW9uLCBzYW1wbGluZyB0aGUgcG9wdWxhdGlvbiBldmVubHk7IHdpdGhpbiBpdHMgY29uc3RyYWludHMsIGl0IHN1Y2NlZWRlZC4gSW50ZXJwcmV0YXRpb25zIGFuZCBpbmZlcmVuY2VzIGFyZSBvdXIgcHJvYmxlbSwgYXMgaXMgb3ZlcmNvbWluZyB0aGUgaW5ldml0YWJsZSBjb25jZXB0dWFsIGNoYWxsZW5nZXMgb24gdGhlIHdheS4gWW91IHdvdWxkbuKAmXQgYmxhbWUgdGhlIEFwb2xsbyBDb21tYW5kIE1vZHVsZSBmb3IgaXRzIGluYWJpbGl0eSB0byBsYW5kIG9uIHRoZSBNb29uLiBJdCBpc27igJl0IGEgcHJvYmxlbSB0aGF0IHdlIG5lZWQgdGhlIHdpZGVyIHRhcGVzdHJ5IG9mIHJlc2VhcmNoIGZpbmRpbmdzIHRvIGVtYmVkIHRoaXMgb25lIGluIGEgY29udGV4dC4KCkl0J3MgaW1wb3J0YW50IHRvIG5vdGUgdGhhdCB0aGUgc3VydmV5IGRvZXNuJ3QgZ28gZm9yIGFueSB1bmRlcmx5aW5nIGNvbnN0cnVjdHMuIE5vYm9keSBjbGFpbXMgdGhhdCB0aGUgcXVlc3Rpb25zIHByZWRpY3QgcGFydGljdWxhciBiZWhhdmlvcnMuIFdlIGRvIHdpdGggdGhpcyBzdXJ2ZXkgd2hhdCB3ZSBkbyB3aXRoIG1vc3Qgc3VydmV5czogZGVzY3JpYmUgaXQgdGhvcm91Z2hseSwgdGhlbiB3YXZlIGl0IHN1Z2dlc3RpdmVseS4KCkJ1dCB0aGVuIHRoZXJl4oCZcyBhIGxpc3Qgb2YgcG90ZW50aWFsIG1ldGhvZG9sb2dpY2FsIGlzc3VlcyB0aGF0IGlzIGxvbmdlciB0aGFuIG15IGFybS4gVGhlIHRoaW5nIHdpdGggdGhhdCBsaXN0IGlzIHRoYXQgeW91IGNhbuKAmXQgd2luLiBEb2luZyBpbi1wZXJzb24gaW50ZXJ2aWV3cz8gU29tZSBwZW9wbGUgd2lsbCBnaXZlIGFuc3dlcnMgdG8gcGxlYXNlIHRoZSByZWNydWl0ZXIsIG5vdCBhY2N1cmF0ZSBzZWxmLXJlcG9ydC4gU2VuZGluZyBvdXQgYW4gaW50ZXJuZXQgc3VydmV5PyBZb3UgcHJvYmFibHkgZG9u4oCZdCBoYXZlIGEgcmVwcmVzZW50YXRpdmUgc2FtcGxlLiBJZiB5b3VyIHF1ZXN0aW9uIGRvZXNu4oCZdCBiaWFzIHRoZSByZXNwb25kZW50IG5lZ2F0aXZlbHksIGl04oCZcyBwcm9iYWJseSBqdXN0IGJlY2F1c2UgaXTigJlzIGJpYXNpbmcgdGhlbSBpbiB0aGUgb3Bwb3NpdGUgZGlyZWN0aW9uLiBTaG91bGQgeW91IGNvdW50IFt0aGUgMTElIG9mIHBlb3BsZSByZXBvcnRpbmcgdGhlIGJlbGllZiB0aGF0IHRoZSBjb3VudHJ5IGlzIG9yIG1pZ2h0IGJlIHJ1biBieSBsaXphcmRtZW5dKGh0dHA6Ly9zbGF0ZXN0YXJjb2RleC5jb20vMjAxMy8wNC8xMi9ub2lzeS1wb2xsLXJlc3VsdHMtYW5kLXJlcHRpbGlhbi1tdXNsaW0tY2xpbWF0b2xvZ2lzdHMtZnJvbS1tYXJzLyk/IEluY2x1ZGUgdGhlbSBhbmQgeW91ciBhZ2dyZWdhdGUgd2lsbCBnZXQgYSBsb3Qgb2Ygbm9pc2U7IG9taXQgdGhlbSBhbmQgeW914oCZcmUgdW5kZXJzYW1wbGluZyB0aGUgY29uc3BpcmFjeSB0aGVvcmlzdHMuCgooSWYgeW91IHdhbnQgdG8gcmVhZCBhIHRob3JvdWdoIHRha2Vkb3duIG9mICJhc2tpbmcgcGVvcGxlIHRoaW5ncyBpcyB1c2VmdWwsIiBAQmVydHJhbmQyMDAxLXRrIHByb3ZpZGUgYSBwYXJ0aWN1bGFybHkgdmljaW91cyBsYXNoaW5nLCB3aGljaCBub25ldGhlbGVzcyBpbmNsdWRlcyBhIG1lYXN1cmVtZW50IGVycm9yIHBlcnNwZWN0aXZlLiBNb3N0IG9mIHRoZWlyIGV4YW1wbGVzIGFuZCBsb2dpYyBjb21lIGZyb20gQFBsb3VzMTk5My1scy4pCgpFYWNoIGRlY2lzaW9uIGluIGRlc2lnbmluZyBhIHN0dWR5IGhhcyB0byBmaW5kIHRoZSBsZXNzZXIgZXZpbHMuIEkgY2Fu4oCZdCB0aGluayBvZiBhIGRlc2lnbiB0aGF0IGlzIGJleW9uZCByZXByb2FjaC4gRXZlcnl3aGVyZSB5b3UgbG9vaywgeW91IGhhdmUgdG8gZGVhbCB3aXRoIGltcGVyZmVjdGlvbi4KClRoaXMgaXMgd2hhdCBtYWtlcyBzb2NpYWwgc2NpZW5jZSBoYXJkLgoKIyMgUXVhbnRpZnlpbmcgdGhlIGVycm9yCgpUaGUgb3JpZ2luYWwgRXVyb2Jhcm9tZXRlciBSZXBvcnQncyBUZWNobmljYWwgQXBwZW5kaXggcHJvdmlkZXMgYSB0YWJsZSB0aGF0IGdpdmVzIHRoZSBwZXJjZW50YWdlLXBvaW50IG1hcmdpbiBvZiBlcnJvci4gSSBhc3N1bWUgdGhhdCB0aGlzIG1hcmdpbiBhY2NvdW50cyBmb3Igc2FtcGxpbmcgZXJyb3IuIFdpdGggdGhlIGRhdGEgYW5kIHRoZSBjcml0aWNpc21zIHdlIGhhdmUsIHdlIGNhbiBlbmxhcmdlIHRoZSBtYXJnaW4gYnkgZWFjaCBvZiB0aGUgZm9sbG93aW5nOgoKKglzZW1hbnRpYyBzaGlmdHMgYmV0d2VlbiB0cmFuc2xhdGlvbnMgKDUtMTAgcGVyY2VudGFnZSBwb2ludHMsIGJhc2VkIG9uIHRoZSBhbmFseXNpcyBhYm92ZSkgCioJcmVzcG9uZGVudCBlcnJvciAoMy01IHBlcmNlbnRhZ2UgcG9pbnRzLCBiYXNlZCBvbiB0aGUgYW5hbHlzaXMgYWJvdmUpCioJcGVvcGxlIHRyb2xsaW5nICgzLTUgcGVyY2VudGFnZSBwb2ludHMpCgooSeKAmW0gbm90IGluY2x1ZGluZyB0aGUgc29jaWFsIGRlc2lyYWJpbGl0eSBiaWFzIGJlY2F1c2UgSSB0aGluayB0aGF04oCZcyBhIHBhcnQgb2YgdGhlIGNvbnN0cnVjdCB1bmRlciBtZWFzdXJlbWVudC4gSWYgeW91IHdpc2ggdG8gdXNlIHRoaXMgc3R1ZHkgdG8gZXN0aW1hdGUgcG9zc2libGUgcmFjaXN0IGJlaGF2aW9yLCBmZWVsIGZyZWUgdG8gdGFjayBvbiB0aGF0IGVycm9yLCB0b28uKQoKQW0gSSBwdWxsaW5nIHRoZXNlIG91dCBvZiBteSBidXR0PyBZb3UgYmV0LCBidXQgSSB0aGluayB0aGVzZSBhcmUgcHJldHR5IHBlc3NpbWlzdGljIG51bWJlcnMsIGFuZCBpdOKAmXMgbm90IGxpa2UgeW91IGRvbuKAmXQgaGF2ZSB0aGVtLiBGb3IgZXhhbXBsZSwgaWYgeW914oCZcmUgZGlzbWlzc2luZyB0aGUgc3R1ZHkgb3V0cmlnaHQsIHRoZW4gdGhlIGVycm9yIGJhcnMgeW91IGFzc2lnbiBtdXN0IGJlIHVuYWJsZSB0byBkaXN0aW5ndWlzaCBiZXR3ZWVuIDAlIGFuZCAxMDAlIHJlc3BvbnNlLiBTaW5jZSBzdXJ2ZXlzIHdpbGwgYWx3YXlzIGNvbnRhaW4gZXJyb3JzLCBJ4oCZZCBzYXkgdGhpcyBmcmFtZXdvcmsgaXMgbW9yZSB1c2VmdWwgdGhhbiBhIGJsYW5rZXQgcmVqZWN0aW9uIOKAkyBvciBhIGJsYW5rZXQgYWNjZXB0YW5jZSDigJMgb2YgYSBzdXJ2ZXkuICBGb3Igb25lLCB0aGUgZnJhbWV3b3JrIGFsc28gZm9yY2VzIHlvdSB0byBiZSBleHBsaWNpdCBhYm91dCB0aGUgdGhpbmdzIHRoYXQgeW91IGNvbnNpZGVyIHdlbGwgZG9uZS4KCkxldOKAmXMgYXNzdW1lIHRoZSB3b3JzdC1jYXNlIHNjZW5hcmlvOiBlYWNoIG9mIHRoZSBlcnJvcnMgaXMgaW5kZXBlbmRlbnQgb2Ygb3RoZXJzIGFuZCBhbGwgYXJlIG9uIHRoZSBoaWdoZXIgZW5kIG9mIHRoZSByYW5nZS4gSWYgd2Ugc3VtIHRoZW0gdXAsIHdlIGVuZCB1cCB3aXRoIGEgbWFyZ2luIG9mIGVycm9yIG9mIHR3ZW50eS1zb21ldGhpbmcgcGVyY2VudGFnZSBwb2ludHMuIFdpdGggdGhlc2UgZXJyb3IgYmFycywgdGhlIGNyb3NzLWNvdW50cnkgY29tcGFyaXNvbiBpcyBtdWNoIHJvdWdoZXIgLS0gYnV0IHdlIGNhbiAqKnN0aWxsKiogc2F5IHdpdGggc29tZSBjb25maWRlbmNlIHRoYXQgZm9ybWVyIEN6ZWNob3Nsb3Zha2lhIGhhcyBhIGxhcmdlciBleHBsaWNpdCBhbnRpLVJvbWEgYXR0aXR1ZGUgcHJvYmxlbSB0aGFuIG1vc3Qgb2YgRXVyb3BlLgoKIyMgLi4uc28gd2hhdCB5b3UncmUgc2F5aW5nIGlzIHRoYXQgc29jaWFsIHNjaWVuY2UgaXMgdXNlbGVzcz8KCn5+SSBwcmVmZXIgdGhlIHRlcm0gX2RpZmZlcmVudGx5IHVzZWZ1bF8ufn4gTm8uIEknbSBzYXlpbmcgdGhhdCBpZiB5b3UncmUgZ29pbmcgdG8gZGlzbWlzcyBhIHNvY2lhbC1zY2llbmNlIHJlc3VsdCwgeW91IHNob3VsZCBkbyB0aGF0IG9uIHRoZSBiYXNpcyBvZiBwcm9ibGVtcyBpdCBhY3R1YWxseSBoYXMsIGFuZCBvbmx5IHRvIHRoZSBleHRlbnQgdGhhdCB0aG9zZSBwcm9ibGVtcyB3YXJyYW50LiBbVGhlIG1lYXN1cmVtZW50IGNyaXNpcyBpcyB1cG9uIHVzO10oaHR0cHM6Ly90d2l0dGVyLmNvbS9Ka2F5Rmxha2Uvc3RhdHVzLzg5MjI2NjUxMDI3MzY5OTg0MCkgbGV0J3MgY3V0IHRocm91Z2ggdGhlIGJ1bGxzaGl0IGFuZCB0YWxrIGFib3V0IHRoZSBwcm9ibGVtcyB0aGF0IGFjdHVhbGx5IG1hdHRlci4KCklmIHRoYXQgbWFrZXMgeW91IF9ub3QgYXQgYWxsIGNvbWZvcnRhYmxlXywgZ29vZDsgbWUgdG9vLgoKIyBSZWZlcmVuY2Vz