Data cleaning and summarizing with dplyr

We’ll learn how to clean and filter the United Nations voting dataset using the dplyr package, and how to summarize it into smaller, interpretable units.

votes <- readRDS("votes.rds")

The United Nations Voting Dataset

Filtering rows

The vote column in the dataset has a number that represents that country’s vote:

  • 1 = Yes
  • 2 = Abstain
  • 3 = No
  • 8 = Not present
  • 9 = Not a member

One step of data cleaning is removing observations (rows) that you’re not interested in. In this case, you want to remove “Not present” and “Not a member”.

# Load the dplyr package
library(dplyr)

# Print the votes dataset
head(votes)

# Filter for votes that are "yes", "abstain", or "no"
votes_filtered <- votes %>% 
  filter(vote <= 3)
head(votes_filtered)

Adding a year column

The next step of data cleaning is manipulating your variables (columns) to make them more informative.

In this case, you have a session column that is hard to interpret intuitively. But since the UN started voting in 1946, and holds one session per year, you can get the year of a UN resolution by adding 1945 to the session number.

# Add another %>% step to add a year column
votes_filtered <- votes %>%
  filter(vote <= 3) %>% 
  mutate(year = session + 1945)
head(votes_filtered)

Adding a country column

The country codes in the ccode column are what’s called Correlates of War codes. This isn’t ideal for an analysis, since you’d like to work with recognizable country names.

You can use the countrycode package to translate. For example:

library(countrycode)

# Translate the country code 2
countrycode(2, "cown", "country.name")
[1] "United States"
# Translate multiple country codes
countrycode(c(2, 20, 40), "cown", "country.name")
[1] "United States" "Canada"        "Cuba"         
# Convert country code 100
countrycode(100, "cown", "country.name")
[1] "Colombia"
# Add a country column within the mutate: votes_processed
votes_processed <- votes %>%
  filter(vote <= 3) %>%
  mutate(year = session + 1945,
  country = countrycode(ccode, "cown", "country.name")) 
Some values were not matched unambiguously: 260

Grouping and summarizing

Summarizing the full dataset

In this analysis, we’re going to focus on “% of votes that are yes” as a metric for the “agreeableness” of countries.

We’ll start by finding this summary for the entire dataset: the fraction of all votes in their history that were “yes”. Note that within our call to summarize(), we can use n() to find the total number of votes and mean(vote == 1) to find the fraction of “yes” votes.

# Print votes_processed
head(votes_processed)

# Find total and fraction of "yes" votes
votes_processed %>%
  summarize(total = n(),
  percent_yes = mean(vote == 1))

Summarizing by year

The summarize() function is especially useful because it can be used within groups.

For example, we might like to know how much the average “agreeableness” of countries changed from year to year. To examine this, you can use group_by() to perform your summary not for the entire dataset, but within each year.

# Change this code to summarize by year
votes_processed %>%
  group_by(year) %>%
  summarize(total = n(),
            percent_yes = mean(vote == 1))

The group_by() function must go before your call to summarize() when you’re trying to perform your summary within groups.

Summarizing by country

We could instead summarize() within each country, which would let you compare voting patterns between countries.

# Summarize by country: by_country
by_country = votes_processed %>%
  group_by(country) %>%
  summarize(total = n(),
            percent_yes = mean(vote == 1))
head(by_country)

Sorting and filtering summarized data

Sorting by percentage of “yes” votes

Now that we ’ve summarized the dataset by country, we can start examining it and answering interesting questions.

For example, we might be especially interested in the countries that voted “yes” least often, or the ones that voted “yes” most often.

# You have the votes summarized by country
by_country <- votes_processed %>%
  group_by(country) %>%
  summarize(total = n(),
            percent_yes = mean(vote == 1))

# Print the by_country dataset
head(by_country)

# Sort in ascending order of percent_yes
head(by_country %>%
  arrange(percent_yes))

# Now sort in descending order
head(by_country %>%
  arrange(desc(percent_yes)))

Filtering summarized output

In the last exercise, we may have noticed that the country that voted least frequently, Zanzibar, had only 2 votes in the entire dataset. We certainly can’t make any substantial conclusions based on that data!

Typically in a progressive analysis, when we find that a few of your observations have very little data while others have plenty, you set some threshold to filter them out.

# Filter out countries with fewer than 100 votes
head(by_country %>%
  arrange(percent_yes) %>%
  filter(total >= 100))

Data visualization with ggplot2

Plotting a data over time

Line plotter

We’ll now use the ggplot2 package to turn our results into a visualization of the percentage of “yes” votes over time.

# Define by_year
by_year <- votes_processed %>%
  group_by(year) %>%
  summarize(total = n(),
            percent_yes = mean(vote == 1))

# Load the ggplot2 package
library(ggplot2)

# Create line plot
ggplot(by_year, aes(x = year, y = percent_yes)) +
  geom_line()

Scatter plotter

A line plot is one way to display this data. Weu could also choose to display it as a scatter plot, with each year represented as a single point. This requires changing the layer (i.e. geom_line() to geom_point()).

We can also add additional layers to your graph, such as a smoothing curve with geom_smooth().

# Change to scatter plot and add smoothing curve
ggplot(by_year, aes(year, percent_yes)) +
  geom_point() +
  geom_smooth()

Visualizing by country

Summarizing by year and country

We’re more interested in trends of voting within specific countries than we are in the overall trend. So instead of summarizing just by year, summarize by both year and country, constructing a dataset that shows what fraction of the time each country votes “yes” in each year.

# Group by year and country: by_year_country
by_year_country <- votes_processed %>%
  group_by(year, country) %>%
  summarize(total = n(),
            percent_yes = mean(vote == 1))

Plotting just the UK over time

Now that we have the percentage of time that each country voted “yes” within each year, you can plot the trend for a particular country. In this case, you’ll look at the trend for just the United Kingdom.

This will involve using filter() on your data before giving it to ggplot2.

# Start with by_year_country dataset
by_year_country <- votes_processed %>%
  group_by(year, country) %>%
  summarize(total = n(),
            percent_yes = mean(vote == 1))

# Print by_year_country
head(by_year_country)

# Create a filtered version: UK_by_year
UK_by_year <- by_year_country %>%
  filter(country == "United Kingdom")

# Line plot of percent_yes over time for UK only
ggplot(UK_by_year, aes(x = year, y = percent_yes)) +
  geom_line()

Plotting multiple countries

Plotting just one country at a time is interesting, but you really want to compare trends between countries. For example, suppose you want to compare voting trends for the United States, the UK, France, and India.

We’ll have to filter to include all four of these countries and use another aesthetic (not just x- and y-axes) to distinguish the countries on the resulting visualization. Instead, we’ll use the color aesthetic to represent different countries.

# Vector of four countries to examine
countries <- c("United States", "United Kingdom",
               "France", "India")

# Filter by_year_country: filtered_4_countries
filtered_4_countries <- by_year_country %>%
  filter(country %in% countries)

# Line plot of % yes in four countries
ggplot(filtered_4_countries, aes(x = year, y = percent_yes, color = country)) +
  geom_line()

Faceting by country

Faceting the time series

Now we’ll take a look at six countries. While in the previous exercise you used color to represent distinct countries, this gets a little too crowded with six.

Instead, we will facet, giving each country its own sub-plot. To do so, you add a facet_wrap() step after all of your layers.

# Vector of six countries to examine
countries <- c("United States", "United Kingdom",
               "France", "Japan", "Brazil", "India")

# Filtered by_year_country: filtered_6_countries
filtered_6_countries <- by_year_country %>%
  filter(country %in% countries)

# Line plot of % yes over time faceted by country
ggplot(filtered_6_countries, aes(x = year, y = percent_yes)) +
  geom_line() +
  facet_wrap(~country)

Faceting with free y-axis

All six graphs had the same axis limits. This made the changes over time hard to examine for plots with relatively little change.

Instead, we may want to let the plot choose a different y-axis for each facet.

# Vector of six countries to examine
countries <- c("United States", "United Kingdom",
               "France", "Japan", "Brazil", "India")

# Filtered by_year_country: filtered_6_countries
filtered_6_countries <- by_year_country %>%
  filter(country %in% countries)

# Line plot of % yes over time faceted by country
ggplot(filtered_6_countries, aes(year, percent_yes)) +
  geom_line() +
  facet_wrap(~ country, scales = "free_y")

More countries

# Add three more countries to this list
countries <- c("United States", "United Kingdom",
               "France", "Japan", "Germany", "Spain", "Ireland", "Russia", "China")

# Filtered by_year_country: filtered_countries
filtered_countries <- by_year_country %>%
  filter(country %in% countries)

# Line plot of % yes over time faceted by country
ggplot(filtered_countries, aes(year, percent_yes)) +
  geom_line() +
  facet_wrap(~ country, scales = "free_y")

Tidy modeling with broom

Linear regression

Linear regression on the United States

A linear regression is a model that lets us examine how one variable changes with respect to another by fitting a best fit line. It is done with the lm() function in R.

Here, we’ll fit a linear regression to just the percentage of “yes” votes from the United States.

# Percentage of yes votes from the US by year: US_by_year
US_by_year <- by_year_country %>%
  filter(country == "United States")

# Print the US_by_year data
head(US_by_year)

# Perform a linear regression of percent_yes by year: US_fit
US_fit <- lm(percent_yes~year, data = US_by_year)

# Perform summary() on the US_fit object
summary(US_fit)

Call:
lm(formula = percent_yes ~ year, data = US_by_year)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.222491 -0.080635 -0.008661  0.081948  0.194307 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept) 12.6641455  1.8379743   6.890 8.48e-08 ***
year        -0.0062393  0.0009282  -6.722 1.37e-07 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.1062 on 32 degrees of freedom
Multiple R-squared:  0.5854,    Adjusted R-squared:  0.5724 
F-statistic: 45.18 on 1 and 32 DF,  p-value: 1.367e-07

What is the estimated slope of this relationship? -0.006

Finding the p-value of a linear regression

Not all positive or negative slopes are necessarily real. A p-value is a way of assessing whether a trend could be due to chance. Generally, data scientists set a threshold by declaring that, for example, p-values below .05 are significant.

What is the p-value of the relationship between year and percent_yes? 1.37e-07 It seems year is very significant when modeling percent_yes.

Tidy models with broom

Tidying a linear regression model

We’ll use the tidy() function in the broom package to turn that model into a tidy data frame.

# Load the broom package
library(broom)

# Call the tidy() function on the US_fit object
tidy(US_fit)

Combining models for multiple countries

One important advantage of changing models to tidied data frames is that they can be combined.

Earlier, we fit a linear model to the percentage of “yes” votes for each year in the United States. Now we’ll fit the same model for the United Kingdom and combine the results from both countries.

# Linear regression of percent_yes by year for US
US_by_year <- by_year_country %>%
  filter(country == "United States")
US_fit <- lm(percent_yes ~ year, US_by_year)

# Fit model for the United Kingdom
UK_by_year <- by_year_country %>%
  filter(country == "United Kingdom")
UK_fit <- lm(percent_yes ~ year, UK_by_year)

# Create US_tidied and UK_tidied
US_tidied <- tidy(US_fit)
UK_tidied <- tidy(UK_fit)

# Combine the two tidied models
bind_rows(US_tidied, UK_tidied)

Nesting for multiple models

Nesting a data frame

Right now, the by_year_country data frame has one row per country-vote pair. So that you can model each country individually, we’re going to “nest” all columns besides country, which will result in a data frame with one row per country. The data for each individual country will then be stored in a list column called data.

# Load the tidyr package
library(tidyr)
# Nest all columns besides country
head(by_year_country %>%
  nest(-country))
All elements of `...` must be named.
Did you want `data = c(year, total, percent_yes)`?

List columns

This “nested” data has an interesting structure. The second column, data, is a list, a type of R object that allows complicated objects to be stored within each row. This is because each item of the data column is itself a data frame. We can use nested$data to access this list column and double brackets to access a particular element. For example, nested$data[[1]] would give we the data frame with Afghanistan’s voting history (the percent_yes per year), since Afghanistan is the first row of the table.

# All countries are nested besides country
nested <- by_year_country %>%
  nest(-country)
All elements of `...` must be named.
Did you want `data = c(year, total, percent_yes)`?
# Print the nested data for Brazil
nested$data[[7]]

Unnesting

The opposite of the nest() operation is the unnest() operation. This takes each of the data frames in the list column and brings those rows back to the main data frame.

We’ll learn how to fit a model in between these nesting and unnesting steps that makes this process useful.

# All countries are nested besides country
nested <- by_year_country %>%
  nest(-country)
All elements of `...` must be named.
Did you want `data = c(year, total, percent_yes)`?
# Unnest the data column to return it to its original form
head(nested %>%
  unnest(data))

Fitting multiple models

Performing linear regression on each nested dataset

Now that we’ve divided the data for each country into a separate dataset in the data column, we need to fit a linear model to each of these datasets.

The map() function from purrr works by applying a formula to each item in a list, where . represents the individual item. For example, you could add one to each of a list of numbers:

map(numbers, ~ 1 + .)

This means that to fit a model to each dataset, we can do:

map(data, ~ lm(percent_yes ~ year, data = .))

where . represents each individual item from the data column in by_year_country. Recall that each item in the data column is a dataset that pertains to a specific country.

# Load tidyr and purrr
library(tidyr)
library(purrr)

# Perform a linear regression on each item in the data column
head(by_year_country %>%
  nest(-country) %>%
  mutate(model = map(data, ~ lm(percent_yes~year, data = .))))
All elements of `...` must be named.
Did you want `data = c(year, total, percent_yes)`?

Tidy each linear regression model

We’ve now performed a linear regression on each nested dataset and have a linear model stored in the list column model. But we can’t recombine the models until we’ve tidied each into a table of coefficients. To do that, we’ll need to use map() one more time and the tidy() function from the broom package.

Recall that we can simply give a function to map() (e.g. map(models, tidy)) in order to apply that function to each item of a list.

# Add another mutate that applies tidy() to each model
head(by_year_country %>%
  nest(-country) %>%
  mutate(model = map(data, ~ lm(percent_yes ~ year, data = .))) %>%
  mutate(tidied = map(model, tidy)))
All elements of `...` must be named.
Did you want `data = c(year, total, percent_yes)`?

Unnesting a data frame

We now have a tidied version of each model stored in the tidied column. We want to combine all of those into a large data frame, similar to how you combined the US and UK tidied models earlier. Recall that the unnest() function from tidyr achieves this.

# Add one more step that unnests the tidied column
country_coefficients <- by_year_country %>%
  nest(-country) %>%
  mutate(model = map(data, ~ lm(percent_yes ~ year, data = .)),
         tidied = map(model, tidy)) %>%
         unnest(tidied)
All elements of `...` must be named.
Did you want `data = c(year, total, percent_yes)`?
# Print the resulting country_coefficients variable
head(country_coefficients)

Working with many tidy models

Filtering model terms

We currently have both the intercept and slope terms for each by-country model. We’re probably more interested in how each is changing over time, so we want to focus on the slope terms.

# Print the country_coefficients dataset
head(country_coefficients)

# Filter for only the slope terms
head(country_coefficients %>%
  filter(term == "year"))

Filtering for significant countries

Not all slopes are significant, and we can use the p-value to guess which are and which are not.

However, when we have lots of p-values, like one for each country, we run into the problem of multiple hypothesis testing, where we have to set a stricter threshold. The p.adjust() function is a simple way to correct for this, where p.adjust(p.value) on a vector of p-values returns a set that we can trust.

Here we’ll add two steps to process the slope_terms dataset: use a mutate to create the new, adjusted p-value column, and filter to filter for those below a .05 threshold.

# Filter for only the slope terms
slope_terms <- country_coefficients %>%
  filter(term == "year")

# Add p.adjusted column, then filter
head(slope_terms %>%
  mutate(p.adjusted = p.adjust(p.value)) %>%
  filter(p.adjusted < 0.05))

Notice that there are now only 61 countries with significant trends.

Sorting by slope

Now that we’ve filtered for countries where the trend is probably not due to chance, we may be interested in countries whose percentage of “yes” votes is changing most quickly over time. Thus, we want to find the countries with the highest and lowest slopes; that is, the estimate column.

# Filter by adjusted p-values
filtered_countries <- country_coefficients %>%
  filter(term == "year") %>%
  mutate(p.adjusted = p.adjust(p.value)) %>%
  filter(p.adjusted < .05)

# Sort for the countries increasing most quickly
head(filtered_countries %>%
  arrange(estimate))


# Sort for the countries decreasing most quickly
head(filtered_countries %>%
  arrange(desc(estimate)))

Joining and tidying

##Joining datasets

We’ll now combine votes_processed dataset with the new descriptions dataset, which includes topic information about each country, so that we can analyze votes within particular topics.

To do this, we’ll make use of the inner_join() function from dplyr.

# Load dplyr package
library(dplyr)

# Print the votes_processed dataset
head(votes_processed)

# Print the descriptions dataset
descriptions <- readRDS("descriptions.rds")
head(descriptions)

# Join them together based on the "rcid" and "session" columns
votes_joined <- votes_processed %>%
  inner_join(descriptions, by= c("rcid" , "session"))
Column `rcid` has different attributes on LHS and RHS of joinColumn `session` has different attributes on LHS and RHS of join

Filtering the joined dataset

There are six columns in the descriptions dataset (and therefore in the new joined dataset) that describe the topic of a resolution:

  1. me: Palestinian conflict

  2. nu: Nuclear weapons and nuclear material

  3. di: Arms control and disarmament

  4. hr: Human rights

  5. co: Colonialism

  6. ec: Economic development

Each contains a 1 if the resolution is related to this topic and a 0 otherwise

# Filter for votes related to colonialism
votes_col <- votes_joined %>%
  filter(co == 1)
head(votes_col)

Visualizing colonialism votes

Earlier exercise, we graphed the percentage of votes each year where the US voted “yes”. Now we’ll create that same graph, but only for votes related to colonialism.

# Load the ggplot2 package
library(ggplot2)

# Filter, then summarize by year: US_co_by_year
US_co_by_year <- votes_joined %>%
  filter(country == "United States", co == 1) %>%
  group_by(year) %>%
  summarize(percent_yes = mean(vote==1))

# Graph the % of "yes" votes over time
ggplot(US_co_by_year, aes(x = year, y = percent_yes)) +
  geom_line()

Tidy data

Using gather to tidy a dataset

In order to represent the joined vote-topic data in a tidy form so we can analyze and graph by topic, we need to transform the data so that each row has one combination of country-vote-topic. This will change the data from having six columns (me, nu, di, hr, co, ec) to having two columns (topic and has_topic).

# Load the tidyr package
library(tidyr)

# Gather the six me/nu/di/hr/co/ec columns
votes_gathered <- votes_joined %>%
  gather(topic, has_topic, me:ec)
head(votes_gathered)

# Perform gather again, then filter
votes_gathered <- votes_joined %>%
  gather(topic, has_topic, me:ec) %>%
  filter(has_topic == 1)

Recoding the topics

There’s one more step of data cleaning to make this more interpretable. Right now, topics are represented by two-letter codes

So that we can interpret the data more easily, recode the data to replace these codes with their full name. We can do that with dplyr’s recode() function, which replaces values with ones you specify:

 example <- c("apple", "banana", "apple", "orange")
 recode(example,
        apple = "plum",
        banana = "grape")
# Replace the two-letter codes in topic: votes_tidied
votes_tidied <- votes_gathered %>%
  mutate(topic = recode(topic,
                        "me" = "Palestinian conflict",
                        "nu" = "Nuclear weapons and nuclear material",
                        "di" = "Arms control and disarmament",
                        "hr" = "Human rights",
                        "co" = "Colonialism",
                        "ec" = "Economic development"))

Summarize by country, year, and topic

Now that we have topic as an additional variable, you can summarize the votes for each combination of country, year, and topic (e.g. for the United States in 2013 on the topic of nuclear weapons.)

# Print votes_tidied
head(votes_tidied)

# Summarize the percentage "yes" per country-year-topic
by_country_year_topic <- votes_tidied %>%
  group_by(country, year, topic) %>%
  summarize(total = n(),
  percent_yes = mean(vote == 1)) %>%
  ungroup()

# Print by_country_year_topic
head(by_country_year_topic)

Tidy modeling by topic and country

Nesting by topic and country

We constructed a linear model for each country by nesting the data in each country, fitting a model to each dataset, then tidying each model with broom and unnesting the coefficients. The code looked something like this:

country_coefficients <- by_year_country %>%
  nest(-country) %>%
  mutate(model = map(data, ~ lm(percent_yes ~ year, data = .)),
         tidied = map(model, tidy)) %>%
  unnest(tidied)

Now, we’ll again be modeling change in “percentage” yes over time, but instead of fitting one model for each country, we’ll fit one for each combination of country and topic.

# Print by_country_year_topic
head(by_country_year_topic)

# Fit model on the by_country_year_topic dataset
country_topic_coefficients <- by_country_year_topic %>%
  nest(-country, -topic) %>%
  mutate(model = map(data, ~ lm(percent_yes ~ year, data = .)),
         tidied = map(model, tidy)) %>%
  unnest(tidied)
All elements of `...` must be named.
Did you want `data = c(year, total, percent_yes)`?essentially perfect fit: summary may be unreliableessentially perfect fit: summary may be unreliableessentially perfect fit: summary may be unreliableessentially perfect fit: summary may be unreliableessentially perfect fit: summary may be unreliableessentially perfect fit: summary may be unreliableessentially perfect fit: summary may be unreliableessentially perfect fit: summary may be unreliableessentially perfect fit: summary may be unreliableessentially perfect fit: summary may be unreliableessentially perfect fit: summary may be unreliableessentially perfect fit: summary may be unreliableessentially perfect fit: summary may be unreliableessentially perfect fit: summary may be unreliable
# Print country_topic_coefficients
head(country_topic_coefficients)

We can ignore the warning messages in the console for now.

Interpreting tidy models

Now we have both the slope and intercept terms for each model. Just as you did in the last chapter with the tidied coefficients, we’ll need to filter for only the slope terms.

We’ll also have to extract only cases that are statistically significant, which means adjusting the p-value for the number of models, and then filtering to include only significant changes.

# Create country_topic_filtered
country_topic_filtered <- country_topic_coefficients %>%
  filter(term == "year") %>%
  mutate(p.adjusted = p.adjust(p.value)) %>%
  filter(p.adjusted < .05)

Checking models visually

Let’s examine this country’s voting patterns more closely. Recall that the by_country_year_topic dataset contained one row for each combination of country, year, and topic. You can use that to create a plot of Vanuatu’s voting, faceted by topic.

# Create vanuatu_by_country_year_topic
vanuatu_by_country_year_topic <- by_country_year_topic %>%
  filter(country == "Vanuatu")

# Plot of percentage "yes" over time, faceted by topic
ggplot(vanuatu_by_country_year_topic, aes(x = year, y = percent_yes)) +
  geom_line() +
  facet_wrap(~topic)

LS0tDQp0aXRsZTogIkNhc2UgU3R1ZHk6IEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMgaW4gUiAtIFVuaXRlZCBOYXRpb25zIHZvdGluZyBkYXRhc2V0Ig0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOg0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgIHRvY19jb2xsYXBzZWQ6IGZhbHNlDQogICAgDQp0b2NfZGVwdGg6IDMNCi0tLQ0KIyBEYXRhIGNsZWFuaW5nIGFuZCBzdW1tYXJpemluZyB3aXRoIGRwbHlyDQoNCldlJ2xsIGxlYXJuIGhvdyB0byBjbGVhbiBhbmQgZmlsdGVyIHRoZSBVbml0ZWQgTmF0aW9ucyB2b3RpbmcgZGF0YXNldCB1c2luZyB0aGUgZHBseXIgcGFja2FnZSwgYW5kIGhvdyB0byBzdW1tYXJpemUgaXQgaW50byBzbWFsbGVyLCBpbnRlcnByZXRhYmxlIHVuaXRzLg0KYGBge3J9DQp2b3RlcyA8LSByZWFkUkRTKCJ2b3Rlcy5yZHMiKQ0KYGBgDQojIyBUaGUgVW5pdGVkIE5hdGlvbnMgVm90aW5nIERhdGFzZXQNCg0KIyMjIEZpbHRlcmluZyByb3dzDQoNClRoZSB2b3RlIGNvbHVtbiBpbiB0aGUgZGF0YXNldCBoYXMgYSBudW1iZXIgdGhhdCByZXByZXNlbnRzIHRoYXQgY291bnRyeSdzIHZvdGU6DQoNCiogMSA9IFllcw0KKiAyID0gQWJzdGFpbg0KKiAzID0gTm8NCiogOCA9IE5vdCBwcmVzZW50DQoqIDkgPSBOb3QgYSBtZW1iZXINCg0KT25lIHN0ZXAgb2YgZGF0YSBjbGVhbmluZyBpcyByZW1vdmluZyBvYnNlcnZhdGlvbnMgKHJvd3MpIHRoYXQgeW91J3JlIG5vdCBpbnRlcmVzdGVkIGluLiBJbiB0aGlzIGNhc2UsIHlvdSB3YW50IHRvIHJlbW92ZSAiTm90IHByZXNlbnQiIGFuZCAiTm90IGEgbWVtYmVyIi4NCmBgYHtyfQ0KIyBMb2FkIHRoZSBkcGx5ciBwYWNrYWdlDQpsaWJyYXJ5KGRwbHlyKQ0KDQojIFByaW50IHRoZSB2b3RlcyBkYXRhc2V0DQpoZWFkKHZvdGVzKQ0KDQojIEZpbHRlciBmb3Igdm90ZXMgdGhhdCBhcmUgInllcyIsICJhYnN0YWluIiwgb3IgIm5vIg0Kdm90ZXNfZmlsdGVyZWQgPC0gdm90ZXMgJT4lIA0KICBmaWx0ZXIodm90ZSA8PSAzKQ0KaGVhZCh2b3Rlc19maWx0ZXJlZCkNCmBgYA0KIyMjIEFkZGluZyBhIHllYXIgY29sdW1uDQoNClRoZSBuZXh0IHN0ZXAgb2YgZGF0YSBjbGVhbmluZyBpcyBtYW5pcHVsYXRpbmcgeW91ciB2YXJpYWJsZXMgKGNvbHVtbnMpIHRvIG1ha2UgdGhlbSBtb3JlIGluZm9ybWF0aXZlLg0KDQpJbiB0aGlzIGNhc2UsIHlvdSBoYXZlIGEgc2Vzc2lvbiBjb2x1bW4gdGhhdCBpcyBoYXJkIHRvIGludGVycHJldCBpbnR1aXRpdmVseS4gQnV0IHNpbmNlIHRoZSBVTiBzdGFydGVkIHZvdGluZyBpbiAxOTQ2LCBhbmQgaG9sZHMgb25lIHNlc3Npb24gcGVyIHllYXIsIHlvdSBjYW4gZ2V0IHRoZSB5ZWFyIG9mIGEgVU4gcmVzb2x1dGlvbiBieSBhZGRpbmcgMTk0NSB0byB0aGUgc2Vzc2lvbiBudW1iZXIuDQpgYGB7cn0NCiMgQWRkIGFub3RoZXIgJT4lIHN0ZXAgdG8gYWRkIGEgeWVhciBjb2x1bW4NCnZvdGVzX2ZpbHRlcmVkIDwtIHZvdGVzICU+JQ0KICBmaWx0ZXIodm90ZSA8PSAzKSAlPiUgDQogIG11dGF0ZSh5ZWFyID0gc2Vzc2lvbiArIDE5NDUpDQpoZWFkKHZvdGVzX2ZpbHRlcmVkKQ0KYGBgDQojIyMgQWRkaW5nIGEgY291bnRyeSBjb2x1bW4NCg0KVGhlIGNvdW50cnkgY29kZXMgaW4gdGhlIGNjb2RlIGNvbHVtbiBhcmUgd2hhdCdzIGNhbGxlZCBDb3JyZWxhdGVzIG9mIFdhciBjb2Rlcy4gVGhpcyBpc24ndCBpZGVhbCBmb3IgYW4gYW5hbHlzaXMsIHNpbmNlIHlvdSdkIGxpa2UgdG8gd29yayB3aXRoIHJlY29nbml6YWJsZSBjb3VudHJ5IG5hbWVzLg0KDQpZb3UgY2FuIHVzZSB0aGUgY291bnRyeWNvZGUgcGFja2FnZSB0byB0cmFuc2xhdGUuIEZvciBleGFtcGxlOg0KYGBge3J9DQpsaWJyYXJ5KGNvdW50cnljb2RlKQ0KDQojIFRyYW5zbGF0ZSB0aGUgY291bnRyeSBjb2RlIDINCmNvdW50cnljb2RlKDIsICJjb3duIiwgImNvdW50cnkubmFtZSIpDQojIFRyYW5zbGF0ZSBtdWx0aXBsZSBjb3VudHJ5IGNvZGVzDQpjb3VudHJ5Y29kZShjKDIsIDIwLCA0MCksICJjb3duIiwgImNvdW50cnkubmFtZSIpDQpgYGANCmBgYHtyfQ0KIyBDb252ZXJ0IGNvdW50cnkgY29kZSAxMDANCmNvdW50cnljb2RlKDEwMCwgImNvd24iLCAiY291bnRyeS5uYW1lIikNCg0KIyBBZGQgYSBjb3VudHJ5IGNvbHVtbiB3aXRoaW4gdGhlIG11dGF0ZTogdm90ZXNfcHJvY2Vzc2VkDQp2b3Rlc19wcm9jZXNzZWQgPC0gdm90ZXMgJT4lDQogIGZpbHRlcih2b3RlIDw9IDMpICU+JQ0KICBtdXRhdGUoeWVhciA9IHNlc3Npb24gKyAxOTQ1LA0KICBjb3VudHJ5ID0gY291bnRyeWNvZGUoY2NvZGUsICJjb3duIiwgImNvdW50cnkubmFtZSIpKSANCmBgYA0KIyMgR3JvdXBpbmcgYW5kIHN1bW1hcml6aW5nDQoNCiMjIyBTdW1tYXJpemluZyB0aGUgZnVsbCBkYXRhc2V0DQoNCkluIHRoaXMgYW5hbHlzaXMsIHdlJ3JlIGdvaW5nIHRvIGZvY3VzIG9uICIlIG9mIHZvdGVzIHRoYXQgYXJlIHllcyIgYXMgYSBtZXRyaWMgZm9yIHRoZSAiYWdyZWVhYmxlbmVzcyIgb2YgY291bnRyaWVzLg0KDQpXZSdsbCBzdGFydCBieSBmaW5kaW5nIHRoaXMgc3VtbWFyeSBmb3IgdGhlIGVudGlyZSBkYXRhc2V0OiB0aGUgZnJhY3Rpb24gb2YgYWxsIHZvdGVzIGluIHRoZWlyIGhpc3RvcnkgdGhhdCB3ZXJlICJ5ZXMiLiBOb3RlIHRoYXQgd2l0aGluIG91ciBjYWxsIHRvIHN1bW1hcml6ZSgpLCB3ZSBjYW4gdXNlIG4oKSB0byBmaW5kIHRoZSB0b3RhbCBudW1iZXIgb2Ygdm90ZXMgYW5kIG1lYW4odm90ZSA9PSAxKSB0byBmaW5kIHRoZSBmcmFjdGlvbiBvZiAieWVzIiB2b3Rlcy4NCmBgYHtyfQ0KIyBQcmludCB2b3Rlc19wcm9jZXNzZWQNCmhlYWQodm90ZXNfcHJvY2Vzc2VkKQ0KDQojIEZpbmQgdG90YWwgYW5kIGZyYWN0aW9uIG9mICJ5ZXMiIHZvdGVzDQp2b3Rlc19wcm9jZXNzZWQgJT4lDQogIHN1bW1hcml6ZSh0b3RhbCA9IG4oKSwNCiAgcGVyY2VudF95ZXMgPSBtZWFuKHZvdGUgPT0gMSkpDQpgYGANCiMjIyBTdW1tYXJpemluZyBieSB5ZWFyDQoNClRoZSBzdW1tYXJpemUoKSBmdW5jdGlvbiBpcyBlc3BlY2lhbGx5IHVzZWZ1bCBiZWNhdXNlIGl0IGNhbiBiZSB1c2VkIHdpdGhpbiBncm91cHMuDQoNCkZvciBleGFtcGxlLCB3ZSBtaWdodCBsaWtlIHRvIGtub3cgaG93IG11Y2ggdGhlIGF2ZXJhZ2UgImFncmVlYWJsZW5lc3MiIG9mIGNvdW50cmllcyBjaGFuZ2VkIGZyb20geWVhciB0byB5ZWFyLiBUbyBleGFtaW5lIHRoaXMsIHlvdSBjYW4gdXNlIGdyb3VwX2J5KCkgdG8gcGVyZm9ybSB5b3VyIHN1bW1hcnkgbm90IGZvciB0aGUgZW50aXJlIGRhdGFzZXQsIGJ1dCB3aXRoaW4gZWFjaCB5ZWFyLg0KYGBge3J9DQojIENoYW5nZSB0aGlzIGNvZGUgdG8gc3VtbWFyaXplIGJ5IHllYXINCnZvdGVzX3Byb2Nlc3NlZCAlPiUNCiAgZ3JvdXBfYnkoeWVhcikgJT4lDQogIHN1bW1hcml6ZSh0b3RhbCA9IG4oKSwNCiAgICAgICAgICAgIHBlcmNlbnRfeWVzID0gbWVhbih2b3RlID09IDEpKQ0KYGBgDQpUaGUgZ3JvdXBfYnkoKSBmdW5jdGlvbiBtdXN0IGdvIGJlZm9yZSB5b3VyIGNhbGwgdG8gc3VtbWFyaXplKCkgd2hlbiB5b3UncmUgdHJ5aW5nIHRvIHBlcmZvcm0geW91ciBzdW1tYXJ5IHdpdGhpbiBncm91cHMuDQoNCiMjIyBTdW1tYXJpemluZyBieSBjb3VudHJ5DQoNCldlIGNvdWxkIGluc3RlYWQgc3VtbWFyaXplKCkgd2l0aGluIGVhY2ggY291bnRyeSwgd2hpY2ggd291bGQgbGV0IHlvdSBjb21wYXJlIHZvdGluZyBwYXR0ZXJucyBiZXR3ZWVuIGNvdW50cmllcy4NCmBgYHtyfQ0KIyBTdW1tYXJpemUgYnkgY291bnRyeTogYnlfY291bnRyeQ0KYnlfY291bnRyeSA9IHZvdGVzX3Byb2Nlc3NlZCAlPiUNCiAgZ3JvdXBfYnkoY291bnRyeSkgJT4lDQogIHN1bW1hcml6ZSh0b3RhbCA9IG4oKSwNCiAgICAgICAgICAgIHBlcmNlbnRfeWVzID0gbWVhbih2b3RlID09IDEpKQ0KaGVhZChieV9jb3VudHJ5KQ0KYGBgDQojIyBTb3J0aW5nIGFuZCBmaWx0ZXJpbmcgc3VtbWFyaXplZCBkYXRhDQoNCiMjIyBTb3J0aW5nIGJ5IHBlcmNlbnRhZ2Ugb2YgInllcyIgdm90ZXMNCg0KTm93IHRoYXQgd2UgJ3ZlIHN1bW1hcml6ZWQgdGhlIGRhdGFzZXQgYnkgY291bnRyeSwgd2UgY2FuIHN0YXJ0IGV4YW1pbmluZyBpdCBhbmQgYW5zd2VyaW5nIGludGVyZXN0aW5nIHF1ZXN0aW9ucy4NCg0KRm9yIGV4YW1wbGUsIHdlIG1pZ2h0IGJlIGVzcGVjaWFsbHkgaW50ZXJlc3RlZCBpbiB0aGUgY291bnRyaWVzIHRoYXQgdm90ZWQgInllcyIgbGVhc3Qgb2Z0ZW4sIG9yIHRoZSBvbmVzIHRoYXQgdm90ZWQgInllcyIgbW9zdCBvZnRlbi4NCmBgYHtyfQ0KIyBZb3UgaGF2ZSB0aGUgdm90ZXMgc3VtbWFyaXplZCBieSBjb3VudHJ5DQpieV9jb3VudHJ5IDwtIHZvdGVzX3Byb2Nlc3NlZCAlPiUNCiAgZ3JvdXBfYnkoY291bnRyeSkgJT4lDQogIHN1bW1hcml6ZSh0b3RhbCA9IG4oKSwNCiAgICAgICAgICAgIHBlcmNlbnRfeWVzID0gbWVhbih2b3RlID09IDEpKQ0KDQojIFByaW50IHRoZSBieV9jb3VudHJ5IGRhdGFzZXQNCmhlYWQoYnlfY291bnRyeSkNCg0KIyBTb3J0IGluIGFzY2VuZGluZyBvcmRlciBvZiBwZXJjZW50X3llcw0KaGVhZChieV9jb3VudHJ5ICU+JQ0KICBhcnJhbmdlKHBlcmNlbnRfeWVzKSkNCg0KIyBOb3cgc29ydCBpbiBkZXNjZW5kaW5nIG9yZGVyDQpoZWFkKGJ5X2NvdW50cnkgJT4lDQogIGFycmFuZ2UoZGVzYyhwZXJjZW50X3llcykpKQ0KYGBgDQojIyMgRmlsdGVyaW5nIHN1bW1hcml6ZWQgb3V0cHV0DQpJbiB0aGUgbGFzdCBleGVyY2lzZSwgd2UgbWF5IGhhdmUgbm90aWNlZCB0aGF0IHRoZSBjb3VudHJ5IHRoYXQgdm90ZWQgbGVhc3QgZnJlcXVlbnRseSwgWmFuemliYXIsIGhhZCBvbmx5IDIgdm90ZXMgaW4gdGhlIGVudGlyZSBkYXRhc2V0LiBXZSBjZXJ0YWlubHkgY2FuJ3QgbWFrZSBhbnkgc3Vic3RhbnRpYWwgY29uY2x1c2lvbnMgYmFzZWQgb24gdGhhdCBkYXRhIQ0KDQpUeXBpY2FsbHkgaW4gYSBwcm9ncmVzc2l2ZSBhbmFseXNpcywgd2hlbiB3ZSBmaW5kIHRoYXQgYSBmZXcgb2YgeW91ciBvYnNlcnZhdGlvbnMgaGF2ZSB2ZXJ5IGxpdHRsZSBkYXRhIHdoaWxlIG90aGVycyBoYXZlIHBsZW50eSwgeW91IHNldCBzb21lIHRocmVzaG9sZCB0byBmaWx0ZXIgdGhlbSBvdXQuDQpgYGB7cn0NCiMgRmlsdGVyIG91dCBjb3VudHJpZXMgd2l0aCBmZXdlciB0aGFuIDEwMCB2b3Rlcw0KaGVhZChieV9jb3VudHJ5ICU+JQ0KICBhcnJhbmdlKHBlcmNlbnRfeWVzKSAlPiUNCiAgZmlsdGVyKHRvdGFsID49IDEwMCkpDQpgYGANCiMgRGF0YSB2aXN1YWxpemF0aW9uIHdpdGggZ2dwbG90Mg0KDQojIyBQbG90dGluZyBhIGRhdGEgb3ZlciB0aW1lDQoNCiMjIyBMaW5lIHBsb3R0ZXINCg0KV2UnbGwgbm93IHVzZSB0aGUgZ2dwbG90MiBwYWNrYWdlIHRvIHR1cm4gb3VyIHJlc3VsdHMgaW50byBhIHZpc3VhbGl6YXRpb24gb2YgdGhlIHBlcmNlbnRhZ2Ugb2YgInllcyIgdm90ZXMgb3ZlciB0aW1lLg0KYGBge3J9DQojIERlZmluZSBieV95ZWFyDQpieV95ZWFyIDwtIHZvdGVzX3Byb2Nlc3NlZCAlPiUNCiAgZ3JvdXBfYnkoeWVhcikgJT4lDQogIHN1bW1hcml6ZSh0b3RhbCA9IG4oKSwNCiAgICAgICAgICAgIHBlcmNlbnRfeWVzID0gbWVhbih2b3RlID09IDEpKQ0KDQojIExvYWQgdGhlIGdncGxvdDIgcGFja2FnZQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQojIENyZWF0ZSBsaW5lIHBsb3QNCmdncGxvdChieV95ZWFyLCBhZXMoeCA9IHllYXIsIHkgPSBwZXJjZW50X3llcykpICsNCiAgZ2VvbV9saW5lKCkNCmBgYA0KIyMjIFNjYXR0ZXIgcGxvdHRlcg0KDQpBIGxpbmUgcGxvdCBpcyBvbmUgd2F5IHRvIGRpc3BsYXkgdGhpcyBkYXRhLiBXZXUgY291bGQgYWxzbyBjaG9vc2UgdG8gZGlzcGxheSBpdCBhcyBhIHNjYXR0ZXIgcGxvdCwgd2l0aCBlYWNoIHllYXIgcmVwcmVzZW50ZWQgYXMgYSBzaW5nbGUgcG9pbnQuIFRoaXMgcmVxdWlyZXMgY2hhbmdpbmcgdGhlIGxheWVyIChpLmUuIGdlb21fbGluZSgpIHRvIGdlb21fcG9pbnQoKSkuDQoNCldlIGNhbiBhbHNvIGFkZCBhZGRpdGlvbmFsIGxheWVycyB0byB5b3VyIGdyYXBoLCBzdWNoIGFzIGEgc21vb3RoaW5nIGN1cnZlIHdpdGggZ2VvbV9zbW9vdGgoKS4NCmBgYHtyfQ0KIyBDaGFuZ2UgdG8gc2NhdHRlciBwbG90IGFuZCBhZGQgc21vb3RoaW5nIGN1cnZlDQpnZ3Bsb3QoYnlfeWVhciwgYWVzKHllYXIsIHBlcmNlbnRfeWVzKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX3Ntb290aCgpDQpgYGANCiMjIFZpc3VhbGl6aW5nIGJ5IGNvdW50cnkNCg0KIyMjIFN1bW1hcml6aW5nIGJ5IHllYXIgYW5kIGNvdW50cnkNCg0KV2UncmUgbW9yZSBpbnRlcmVzdGVkIGluIHRyZW5kcyBvZiB2b3Rpbmcgd2l0aGluIHNwZWNpZmljIGNvdW50cmllcyB0aGFuIHdlIGFyZSBpbiB0aGUgb3ZlcmFsbCB0cmVuZC4gU28gaW5zdGVhZCBvZiBzdW1tYXJpemluZyBqdXN0IGJ5IHllYXIsIHN1bW1hcml6ZSBieSBib3RoIHllYXIgYW5kIGNvdW50cnksIGNvbnN0cnVjdGluZyBhIGRhdGFzZXQgdGhhdCBzaG93cyB3aGF0IGZyYWN0aW9uIG9mIHRoZSB0aW1lIGVhY2ggY291bnRyeSB2b3RlcyAieWVzIiBpbiBlYWNoIHllYXIuDQpgYGB7cn0NCiMgR3JvdXAgYnkgeWVhciBhbmQgY291bnRyeTogYnlfeWVhcl9jb3VudHJ5DQpieV95ZWFyX2NvdW50cnkgPC0gdm90ZXNfcHJvY2Vzc2VkICU+JQ0KICBncm91cF9ieSh5ZWFyLCBjb3VudHJ5KSAlPiUNCiAgc3VtbWFyaXplKHRvdGFsID0gbigpLA0KICAgICAgICAgICAgcGVyY2VudF95ZXMgPSBtZWFuKHZvdGUgPT0gMSkpDQpgYGANCiMjIyBQbG90dGluZyBqdXN0IHRoZSBVSyBvdmVyIHRpbWUNCg0KTm93IHRoYXQgd2UgaGF2ZSB0aGUgcGVyY2VudGFnZSBvZiB0aW1lIHRoYXQgZWFjaCBjb3VudHJ5IHZvdGVkICJ5ZXMiIHdpdGhpbiBlYWNoIHllYXIsIHlvdSBjYW4gcGxvdCB0aGUgdHJlbmQgZm9yIGEgcGFydGljdWxhciBjb3VudHJ5LiBJbiB0aGlzIGNhc2UsIHlvdSdsbCBsb29rIGF0IHRoZSB0cmVuZCBmb3IganVzdCB0aGUgVW5pdGVkIEtpbmdkb20uDQoNClRoaXMgd2lsbCBpbnZvbHZlIHVzaW5nIGZpbHRlcigpIG9uIHlvdXIgZGF0YSBiZWZvcmUgZ2l2aW5nIGl0IHRvIGdncGxvdDIuDQpgYGB7cn0NCiMgU3RhcnQgd2l0aCBieV95ZWFyX2NvdW50cnkgZGF0YXNldA0KYnlfeWVhcl9jb3VudHJ5IDwtIHZvdGVzX3Byb2Nlc3NlZCAlPiUNCiAgZ3JvdXBfYnkoeWVhciwgY291bnRyeSkgJT4lDQogIHN1bW1hcml6ZSh0b3RhbCA9IG4oKSwNCiAgICAgICAgICAgIHBlcmNlbnRfeWVzID0gbWVhbih2b3RlID09IDEpKQ0KDQojIFByaW50IGJ5X3llYXJfY291bnRyeQ0KaGVhZChieV95ZWFyX2NvdW50cnkpDQoNCiMgQ3JlYXRlIGEgZmlsdGVyZWQgdmVyc2lvbjogVUtfYnlfeWVhcg0KVUtfYnlfeWVhciA8LSBieV95ZWFyX2NvdW50cnkgJT4lDQogIGZpbHRlcihjb3VudHJ5ID09ICJVbml0ZWQgS2luZ2RvbSIpDQoNCiMgTGluZSBwbG90IG9mIHBlcmNlbnRfeWVzIG92ZXIgdGltZSBmb3IgVUsgb25seQ0KZ2dwbG90KFVLX2J5X3llYXIsIGFlcyh4ID0geWVhciwgeSA9IHBlcmNlbnRfeWVzKSkgKw0KICBnZW9tX2xpbmUoKQ0KYGBgDQojIyMgUGxvdHRpbmcgbXVsdGlwbGUgY291bnRyaWVzDQoNClBsb3R0aW5nIGp1c3Qgb25lIGNvdW50cnkgYXQgYSB0aW1lIGlzIGludGVyZXN0aW5nLCBidXQgeW91IHJlYWxseSB3YW50IHRvIGNvbXBhcmUgdHJlbmRzIGJldHdlZW4gY291bnRyaWVzLiBGb3IgZXhhbXBsZSwgc3VwcG9zZSB5b3Ugd2FudCB0byBjb21wYXJlIHZvdGluZyB0cmVuZHMgZm9yIHRoZSBVbml0ZWQgU3RhdGVzLCB0aGUgVUssIEZyYW5jZSwgYW5kIEluZGlhLg0KDQpXZSdsbCBoYXZlIHRvIGZpbHRlciB0byBpbmNsdWRlIGFsbCBmb3VyIG9mIHRoZXNlIGNvdW50cmllcyBhbmQgdXNlIGFub3RoZXIgYWVzdGhldGljIChub3QganVzdCB4LSBhbmQgeS1heGVzKSB0byBkaXN0aW5ndWlzaCB0aGUgY291bnRyaWVzIG9uIHRoZSByZXN1bHRpbmcgdmlzdWFsaXphdGlvbi4gSW5zdGVhZCwgd2UnbGwgdXNlIHRoZSBjb2xvciBhZXN0aGV0aWMgdG8gcmVwcmVzZW50IGRpZmZlcmVudCBjb3VudHJpZXMuDQpgYGB7cn0NCiMgVmVjdG9yIG9mIGZvdXIgY291bnRyaWVzIHRvIGV4YW1pbmUNCmNvdW50cmllcyA8LSBjKCJVbml0ZWQgU3RhdGVzIiwgIlVuaXRlZCBLaW5nZG9tIiwNCiAgICAgICAgICAgICAgICJGcmFuY2UiLCAiSW5kaWEiKQ0KDQojIEZpbHRlciBieV95ZWFyX2NvdW50cnk6IGZpbHRlcmVkXzRfY291bnRyaWVzDQpmaWx0ZXJlZF80X2NvdW50cmllcyA8LSBieV95ZWFyX2NvdW50cnkgJT4lDQogIGZpbHRlcihjb3VudHJ5ICVpbiUgY291bnRyaWVzKQ0KDQojIExpbmUgcGxvdCBvZiAlIHllcyBpbiBmb3VyIGNvdW50cmllcw0KZ2dwbG90KGZpbHRlcmVkXzRfY291bnRyaWVzLCBhZXMoeCA9IHllYXIsIHkgPSBwZXJjZW50X3llcywgY29sb3IgPSBjb3VudHJ5KSkgKw0KICBnZW9tX2xpbmUoKQ0KYGBgDQojIyBGYWNldGluZyBieSBjb3VudHJ5DQoNCiMjIyBGYWNldGluZyB0aGUgdGltZSBzZXJpZXMNCg0KTm93IHdlJ2xsIHRha2UgYSBsb29rIGF0IHNpeCBjb3VudHJpZXMuIFdoaWxlIGluIHRoZSBwcmV2aW91cyBleGVyY2lzZSB5b3UgdXNlZCBjb2xvciB0byByZXByZXNlbnQgZGlzdGluY3QgY291bnRyaWVzLCB0aGlzIGdldHMgYSBsaXR0bGUgdG9vIGNyb3dkZWQgd2l0aCBzaXguDQoNCkluc3RlYWQsIHdlIHdpbGwgZmFjZXQsIGdpdmluZyBlYWNoIGNvdW50cnkgaXRzIG93biBzdWItcGxvdC4gVG8gZG8gc28sIHlvdSBhZGQgYSBmYWNldF93cmFwKCkgc3RlcCBhZnRlciBhbGwgb2YgeW91ciBsYXllcnMuDQpgYGB7cn0NCiMgVmVjdG9yIG9mIHNpeCBjb3VudHJpZXMgdG8gZXhhbWluZQ0KY291bnRyaWVzIDwtIGMoIlVuaXRlZCBTdGF0ZXMiLCAiVW5pdGVkIEtpbmdkb20iLA0KICAgICAgICAgICAgICAgIkZyYW5jZSIsICJKYXBhbiIsICJCcmF6aWwiLCAiSW5kaWEiKQ0KDQojIEZpbHRlcmVkIGJ5X3llYXJfY291bnRyeTogZmlsdGVyZWRfNl9jb3VudHJpZXMNCmZpbHRlcmVkXzZfY291bnRyaWVzIDwtIGJ5X3llYXJfY291bnRyeSAlPiUNCiAgZmlsdGVyKGNvdW50cnkgJWluJSBjb3VudHJpZXMpDQoNCiMgTGluZSBwbG90IG9mICUgeWVzIG92ZXIgdGltZSBmYWNldGVkIGJ5IGNvdW50cnkNCmdncGxvdChmaWx0ZXJlZF82X2NvdW50cmllcywgYWVzKHggPSB5ZWFyLCB5ID0gcGVyY2VudF95ZXMpKSArDQogIGdlb21fbGluZSgpICsNCiAgZmFjZXRfd3JhcCh+Y291bnRyeSkNCmBgYA0KIyMjIEZhY2V0aW5nIHdpdGggZnJlZSB5LWF4aXMNCg0KQWxsIHNpeCBncmFwaHMgaGFkIHRoZSBzYW1lIGF4aXMgbGltaXRzLiBUaGlzIG1hZGUgdGhlIGNoYW5nZXMgb3ZlciB0aW1lIGhhcmQgdG8gZXhhbWluZSBmb3IgcGxvdHMgd2l0aCByZWxhdGl2ZWx5IGxpdHRsZSBjaGFuZ2UuDQoNCkluc3RlYWQsIHdlIG1heSB3YW50IHRvIGxldCB0aGUgcGxvdCBjaG9vc2UgYSBkaWZmZXJlbnQgeS1heGlzIGZvciBlYWNoIGZhY2V0Lg0KYGBge3J9DQojIFZlY3RvciBvZiBzaXggY291bnRyaWVzIHRvIGV4YW1pbmUNCmNvdW50cmllcyA8LSBjKCJVbml0ZWQgU3RhdGVzIiwgIlVuaXRlZCBLaW5nZG9tIiwNCiAgICAgICAgICAgICAgICJGcmFuY2UiLCAiSmFwYW4iLCAiQnJhemlsIiwgIkluZGlhIikNCg0KIyBGaWx0ZXJlZCBieV95ZWFyX2NvdW50cnk6IGZpbHRlcmVkXzZfY291bnRyaWVzDQpmaWx0ZXJlZF82X2NvdW50cmllcyA8LSBieV95ZWFyX2NvdW50cnkgJT4lDQogIGZpbHRlcihjb3VudHJ5ICVpbiUgY291bnRyaWVzKQ0KDQojIExpbmUgcGxvdCBvZiAlIHllcyBvdmVyIHRpbWUgZmFjZXRlZCBieSBjb3VudHJ5DQpnZ3Bsb3QoZmlsdGVyZWRfNl9jb3VudHJpZXMsIGFlcyh5ZWFyLCBwZXJjZW50X3llcykpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBmYWNldF93cmFwKH4gY291bnRyeSwgc2NhbGVzID0gImZyZWVfeSIpDQpgYGANCiMjIyBNb3JlIGNvdW50cmllcw0KDQpgYGB7cn0NCiMgQWRkIHRocmVlIG1vcmUgY291bnRyaWVzIHRvIHRoaXMgbGlzdA0KY291bnRyaWVzIDwtIGMoIlVuaXRlZCBTdGF0ZXMiLCAiVW5pdGVkIEtpbmdkb20iLA0KICAgICAgICAgICAgICAgIkZyYW5jZSIsICJKYXBhbiIsICJHZXJtYW55IiwgIlNwYWluIiwgIklyZWxhbmQiLCAiUnVzc2lhIiwgIkNoaW5hIikNCg0KIyBGaWx0ZXJlZCBieV95ZWFyX2NvdW50cnk6IGZpbHRlcmVkX2NvdW50cmllcw0KZmlsdGVyZWRfY291bnRyaWVzIDwtIGJ5X3llYXJfY291bnRyeSAlPiUNCiAgZmlsdGVyKGNvdW50cnkgJWluJSBjb3VudHJpZXMpDQoNCiMgTGluZSBwbG90IG9mICUgeWVzIG92ZXIgdGltZSBmYWNldGVkIGJ5IGNvdW50cnkNCmdncGxvdChmaWx0ZXJlZF9jb3VudHJpZXMsIGFlcyh5ZWFyLCBwZXJjZW50X3llcykpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBmYWNldF93cmFwKH4gY291bnRyeSwgc2NhbGVzID0gImZyZWVfeSIpDQpgYGANCiMgVGlkeSBtb2RlbGluZyB3aXRoIGJyb29tDQoNCiMjIExpbmVhciByZWdyZXNzaW9uDQoNCiMjIyBMaW5lYXIgcmVncmVzc2lvbiBvbiB0aGUgVW5pdGVkIFN0YXRlcw0KDQpBIGxpbmVhciByZWdyZXNzaW9uIGlzIGEgbW9kZWwgdGhhdCBsZXRzIHVzIGV4YW1pbmUgaG93IG9uZSB2YXJpYWJsZSBjaGFuZ2VzIHdpdGggcmVzcGVjdCB0byBhbm90aGVyIGJ5IGZpdHRpbmcgYSBiZXN0IGZpdCBsaW5lLiBJdCBpcyBkb25lIHdpdGggdGhlIGxtKCkgZnVuY3Rpb24gaW4gUi4NCg0KSGVyZSwgd2UnbGwgZml0IGEgbGluZWFyIHJlZ3Jlc3Npb24gdG8ganVzdCB0aGUgcGVyY2VudGFnZSBvZiAieWVzIiB2b3RlcyBmcm9tIHRoZSBVbml0ZWQgU3RhdGVzLg0KYGBge3J9DQojIFBlcmNlbnRhZ2Ugb2YgeWVzIHZvdGVzIGZyb20gdGhlIFVTIGJ5IHllYXI6IFVTX2J5X3llYXINClVTX2J5X3llYXIgPC0gYnlfeWVhcl9jb3VudHJ5ICU+JQ0KICBmaWx0ZXIoY291bnRyeSA9PSAiVW5pdGVkIFN0YXRlcyIpDQoNCiMgUHJpbnQgdGhlIFVTX2J5X3llYXIgZGF0YQ0KaGVhZChVU19ieV95ZWFyKQ0KDQojIFBlcmZvcm0gYSBsaW5lYXIgcmVncmVzc2lvbiBvZiBwZXJjZW50X3llcyBieSB5ZWFyOiBVU19maXQNClVTX2ZpdCA8LSBsbShwZXJjZW50X3llc355ZWFyLCBkYXRhID0gVVNfYnlfeWVhcikNCg0KIyBQZXJmb3JtIHN1bW1hcnkoKSBvbiB0aGUgVVNfZml0IG9iamVjdA0Kc3VtbWFyeShVU19maXQpDQpgYGANCldoYXQgaXMgdGhlIGVzdGltYXRlZCBzbG9wZSBvZiB0aGlzIHJlbGF0aW9uc2hpcD8NCi0wLjAwNg0KDQojIyMgRmluZGluZyB0aGUgcC12YWx1ZSBvZiBhIGxpbmVhciByZWdyZXNzaW9uDQoNCk5vdCBhbGwgcG9zaXRpdmUgb3IgbmVnYXRpdmUgc2xvcGVzIGFyZSBuZWNlc3NhcmlseSByZWFsLiBBIHAtdmFsdWUgaXMgYSB3YXkgb2YgYXNzZXNzaW5nIHdoZXRoZXIgYSB0cmVuZCBjb3VsZCBiZSBkdWUgdG8gY2hhbmNlLiBHZW5lcmFsbHksIGRhdGEgc2NpZW50aXN0cyBzZXQgYSB0aHJlc2hvbGQgYnkgZGVjbGFyaW5nIHRoYXQsIGZvciBleGFtcGxlLCBwLXZhbHVlcyBiZWxvdyAuMDUgYXJlIHNpZ25pZmljYW50Lg0KDQpXaGF0IGlzIHRoZSBwLXZhbHVlIG9mIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB5ZWFyIGFuZCBwZXJjZW50X3llcz8NCjEuMzdlLTA3DQpJdCBzZWVtcyB5ZWFyIGlzIHZlcnkgc2lnbmlmaWNhbnQgd2hlbiBtb2RlbGluZyBwZXJjZW50X3llcy4NCg0KIyMgVGlkeSBtb2RlbHMgd2l0aCBicm9vbQ0KDQojIyMgVGlkeWluZyBhIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsDQoNCldlJ2xsIHVzZSB0aGUgdGlkeSgpIGZ1bmN0aW9uIGluIHRoZSBicm9vbSBwYWNrYWdlIHRvIHR1cm4gdGhhdCBtb2RlbCBpbnRvIGEgdGlkeSBkYXRhIGZyYW1lLg0KYGBge3J9DQojIExvYWQgdGhlIGJyb29tIHBhY2thZ2UNCmxpYnJhcnkoYnJvb20pDQoNCiMgQ2FsbCB0aGUgdGlkeSgpIGZ1bmN0aW9uIG9uIHRoZSBVU19maXQgb2JqZWN0DQp0aWR5KFVTX2ZpdCkNCmBgYA0KIyMjIENvbWJpbmluZyBtb2RlbHMgZm9yIG11bHRpcGxlIGNvdW50cmllcw0KDQpPbmUgaW1wb3J0YW50IGFkdmFudGFnZSBvZiBjaGFuZ2luZyBtb2RlbHMgdG8gdGlkaWVkIGRhdGEgZnJhbWVzIGlzIHRoYXQgdGhleSBjYW4gYmUgY29tYmluZWQuDQoNCkVhcmxpZXIsIHdlIGZpdCBhIGxpbmVhciBtb2RlbCB0byB0aGUgcGVyY2VudGFnZSBvZiAieWVzIiB2b3RlcyBmb3IgZWFjaCB5ZWFyIGluIHRoZSBVbml0ZWQgU3RhdGVzLiBOb3cgd2UnbGwgZml0IHRoZSBzYW1lIG1vZGVsIGZvciB0aGUgVW5pdGVkIEtpbmdkb20gYW5kIGNvbWJpbmUgdGhlIHJlc3VsdHMgZnJvbSBib3RoIGNvdW50cmllcy4NCmBgYHtyfQ0KIyBMaW5lYXIgcmVncmVzc2lvbiBvZiBwZXJjZW50X3llcyBieSB5ZWFyIGZvciBVUw0KVVNfYnlfeWVhciA8LSBieV95ZWFyX2NvdW50cnkgJT4lDQogIGZpbHRlcihjb3VudHJ5ID09ICJVbml0ZWQgU3RhdGVzIikNClVTX2ZpdCA8LSBsbShwZXJjZW50X3llcyB+IHllYXIsIFVTX2J5X3llYXIpDQoNCiMgRml0IG1vZGVsIGZvciB0aGUgVW5pdGVkIEtpbmdkb20NClVLX2J5X3llYXIgPC0gYnlfeWVhcl9jb3VudHJ5ICU+JQ0KICBmaWx0ZXIoY291bnRyeSA9PSAiVW5pdGVkIEtpbmdkb20iKQ0KVUtfZml0IDwtIGxtKHBlcmNlbnRfeWVzIH4geWVhciwgVUtfYnlfeWVhcikNCg0KIyBDcmVhdGUgVVNfdGlkaWVkIGFuZCBVS190aWRpZWQNClVTX3RpZGllZCA8LSB0aWR5KFVTX2ZpdCkNClVLX3RpZGllZCA8LSB0aWR5KFVLX2ZpdCkNCg0KIyBDb21iaW5lIHRoZSB0d28gdGlkaWVkIG1vZGVscw0KYmluZF9yb3dzKFVTX3RpZGllZCwgVUtfdGlkaWVkKQ0KYGBgDQojIyBOZXN0aW5nIGZvciBtdWx0aXBsZSBtb2RlbHMNCg0KIyMjIE5lc3RpbmcgYSBkYXRhIGZyYW1lDQoNClJpZ2h0IG5vdywgdGhlIGJ5X3llYXJfY291bnRyeSBkYXRhIGZyYW1lIGhhcyBvbmUgcm93IHBlciBjb3VudHJ5LXZvdGUgcGFpci4gU28gdGhhdCB5b3UgY2FuIG1vZGVsIGVhY2ggY291bnRyeSBpbmRpdmlkdWFsbHksIHdlJ3JlIGdvaW5nIHRvICJuZXN0IiBhbGwgY29sdW1ucyBiZXNpZGVzIGNvdW50cnksIHdoaWNoIHdpbGwgcmVzdWx0IGluIGEgZGF0YSBmcmFtZSB3aXRoIG9uZSByb3cgcGVyIGNvdW50cnkuIFRoZSBkYXRhIGZvciBlYWNoIGluZGl2aWR1YWwgY291bnRyeSB3aWxsIHRoZW4gYmUgc3RvcmVkIGluIGEgbGlzdCBjb2x1bW4gY2FsbGVkIGRhdGEuDQpgYGB7cn0NCiMgTG9hZCB0aGUgdGlkeXIgcGFja2FnZQ0KbGlicmFyeSh0aWR5cikNCiMgTmVzdCBhbGwgY29sdW1ucyBiZXNpZGVzIGNvdW50cnkNCmhlYWQoYnlfeWVhcl9jb3VudHJ5ICU+JQ0KICBuZXN0KC1jb3VudHJ5KSkNCmBgYA0KIyMjIExpc3QgY29sdW1ucw0KDQpUaGlzICJuZXN0ZWQiIGRhdGEgaGFzIGFuIGludGVyZXN0aW5nIHN0cnVjdHVyZS4gVGhlIHNlY29uZCBjb2x1bW4sIGRhdGEsIGlzIGEgbGlzdCwgYSB0eXBlIG9mIFIgb2JqZWN0IHRoYXQgYWxsb3dzIGNvbXBsaWNhdGVkIG9iamVjdHMgdG8gYmUgc3RvcmVkIHdpdGhpbiBlYWNoIHJvdy4gVGhpcyBpcyBiZWNhdXNlIGVhY2ggaXRlbSBvZiB0aGUgZGF0YSBjb2x1bW4gaXMgaXRzZWxmIGEgZGF0YSBmcmFtZS4NCldlIGNhbiB1c2UgbmVzdGVkXCRkYXRhIHRvIGFjY2VzcyB0aGlzIGxpc3QgY29sdW1uIGFuZCBkb3VibGUgYnJhY2tldHMgdG8gYWNjZXNzIGEgcGFydGljdWxhciBlbGVtZW50LiBGb3IgZXhhbXBsZSwgbmVzdGVkXCRkYXRhW1sxXV0gd291bGQgZ2l2ZSB3ZSB0aGUgZGF0YSBmcmFtZSB3aXRoIEFmZ2hhbmlzdGFuJ3Mgdm90aW5nIGhpc3RvcnkgKHRoZSBwZXJjZW50X3llcyBwZXIgeWVhciksIHNpbmNlIEFmZ2hhbmlzdGFuIGlzIHRoZSBmaXJzdCByb3cgb2YgdGhlIHRhYmxlLg0KYGBge3J9DQojIEFsbCBjb3VudHJpZXMgYXJlIG5lc3RlZCBiZXNpZGVzIGNvdW50cnkNCm5lc3RlZCA8LSBieV95ZWFyX2NvdW50cnkgJT4lDQogIG5lc3QoLWNvdW50cnkpDQoNCiMgUHJpbnQgdGhlIG5lc3RlZCBkYXRhIGZvciBCcmF6aWwNCm5lc3RlZCRkYXRhW1s3XV0NCmBgYA0KIyMjIFVubmVzdGluZw0KDQpUaGUgb3Bwb3NpdGUgb2YgdGhlIG5lc3QoKSBvcGVyYXRpb24gaXMgdGhlIHVubmVzdCgpIG9wZXJhdGlvbi4gVGhpcyB0YWtlcyBlYWNoIG9mIHRoZSBkYXRhIGZyYW1lcyBpbiB0aGUgbGlzdCBjb2x1bW4gYW5kIGJyaW5ncyB0aG9zZSByb3dzIGJhY2sgdG8gdGhlIG1haW4gZGF0YSBmcmFtZS4NCg0KV2UnbGwgbGVhcm4gaG93IHRvIGZpdCBhIG1vZGVsIGluIGJldHdlZW4gdGhlc2UgbmVzdGluZyBhbmQgdW5uZXN0aW5nIHN0ZXBzIHRoYXQgbWFrZXMgdGhpcyBwcm9jZXNzIHVzZWZ1bC4NCmBgYHtyfQ0KIyBBbGwgY291bnRyaWVzIGFyZSBuZXN0ZWQgYmVzaWRlcyBjb3VudHJ5DQpuZXN0ZWQgPC0gYnlfeWVhcl9jb3VudHJ5ICU+JQ0KICBuZXN0KC1jb3VudHJ5KQ0KDQojIFVubmVzdCB0aGUgZGF0YSBjb2x1bW4gdG8gcmV0dXJuIGl0IHRvIGl0cyBvcmlnaW5hbCBmb3JtDQpoZWFkKG5lc3RlZCAlPiUNCiAgdW5uZXN0KGRhdGEpKQ0KYGBgDQojIyBGaXR0aW5nIG11bHRpcGxlIG1vZGVscw0KDQojIyMgUGVyZm9ybWluZyBsaW5lYXIgcmVncmVzc2lvbiBvbiBlYWNoIG5lc3RlZCBkYXRhc2V0DQoNCk5vdyB0aGF0IHdlJ3ZlIGRpdmlkZWQgdGhlIGRhdGEgZm9yIGVhY2ggY291bnRyeSBpbnRvIGEgc2VwYXJhdGUgZGF0YXNldCBpbiB0aGUgZGF0YSBjb2x1bW4sIHdlIG5lZWQgdG8gZml0IGEgbGluZWFyIG1vZGVsIHRvIGVhY2ggb2YgdGhlc2UgZGF0YXNldHMuDQoNClRoZSBtYXAoKSBmdW5jdGlvbiBmcm9tIHB1cnJyIHdvcmtzIGJ5IGFwcGx5aW5nIGEgZm9ybXVsYSB0byBlYWNoIGl0ZW0gaW4gYSBsaXN0LCB3aGVyZSAuIHJlcHJlc2VudHMgdGhlIGluZGl2aWR1YWwgaXRlbS4gRm9yIGV4YW1wbGUsIHlvdSBjb3VsZCBhZGQgb25lIHRvIGVhY2ggb2YgYSBsaXN0IG9mIG51bWJlcnM6DQogICAgDQogICAgbWFwKG51bWJlcnMsIH4gMSArIC4pDQoNClRoaXMgbWVhbnMgdGhhdCB0byBmaXQgYSBtb2RlbCB0byBlYWNoIGRhdGFzZXQsIHdlIGNhbiBkbzoNCg0KICAgIG1hcChkYXRhLCB+IGxtKHBlcmNlbnRfeWVzIH4geWVhciwgZGF0YSA9IC4pKQ0KDQp3aGVyZSAuIHJlcHJlc2VudHMgZWFjaCBpbmRpdmlkdWFsIGl0ZW0gZnJvbSB0aGUgZGF0YSBjb2x1bW4gaW4gYnlfeWVhcl9jb3VudHJ5LiBSZWNhbGwgdGhhdCBlYWNoIGl0ZW0gaW4gdGhlIGRhdGEgY29sdW1uIGlzIGEgZGF0YXNldCB0aGF0IHBlcnRhaW5zIHRvIGEgc3BlY2lmaWMgY291bnRyeS4NCmBgYHtyfQ0KIyBMb2FkIHRpZHlyIGFuZCBwdXJycg0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkocHVycnIpDQoNCiMgUGVyZm9ybSBhIGxpbmVhciByZWdyZXNzaW9uIG9uIGVhY2ggaXRlbSBpbiB0aGUgZGF0YSBjb2x1bW4NCmhlYWQoYnlfeWVhcl9jb3VudHJ5ICU+JQ0KICBuZXN0KC1jb3VudHJ5KSAlPiUNCiAgbXV0YXRlKG1vZGVsID0gbWFwKGRhdGEsIH4gbG0ocGVyY2VudF95ZXN+eWVhciwgZGF0YSA9IC4pKSkpDQpgYGANCiMjIyBUaWR5IGVhY2ggbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwNCg0KV2UndmUgbm93IHBlcmZvcm1lZCBhIGxpbmVhciByZWdyZXNzaW9uIG9uIGVhY2ggbmVzdGVkIGRhdGFzZXQgYW5kIGhhdmUgYSBsaW5lYXIgbW9kZWwgc3RvcmVkIGluIHRoZSBsaXN0IGNvbHVtbiBtb2RlbC4gQnV0IHdlIGNhbid0IHJlY29tYmluZSB0aGUgbW9kZWxzIHVudGlsIHdlJ3ZlIHRpZGllZCBlYWNoIGludG8gYSB0YWJsZSBvZiBjb2VmZmljaWVudHMuIFRvIGRvIHRoYXQsIHdlJ2xsIG5lZWQgdG8gdXNlIG1hcCgpIG9uZSBtb3JlIHRpbWUgYW5kIHRoZSB0aWR5KCkgZnVuY3Rpb24gZnJvbSB0aGUgYnJvb20gcGFja2FnZS4NCg0KUmVjYWxsIHRoYXQgd2UgY2FuIHNpbXBseSBnaXZlIGEgZnVuY3Rpb24gdG8gbWFwKCkgKGUuZy4gbWFwKG1vZGVscywgdGlkeSkpIGluIG9yZGVyIHRvIGFwcGx5IHRoYXQgZnVuY3Rpb24gdG8gZWFjaCBpdGVtIG9mIGEgbGlzdC4NCmBgYHtyfQ0KIyBBZGQgYW5vdGhlciBtdXRhdGUgdGhhdCBhcHBsaWVzIHRpZHkoKSB0byBlYWNoIG1vZGVsDQpoZWFkKGJ5X3llYXJfY291bnRyeSAlPiUNCiAgbmVzdCgtY291bnRyeSkgJT4lDQogIG11dGF0ZShtb2RlbCA9IG1hcChkYXRhLCB+IGxtKHBlcmNlbnRfeWVzIH4geWVhciwgZGF0YSA9IC4pKSkgJT4lDQogIG11dGF0ZSh0aWRpZWQgPSBtYXAobW9kZWwsIHRpZHkpKSkNCmBgYA0KIyMjIFVubmVzdGluZyBhIGRhdGEgZnJhbWUNCg0KV2Ugbm93IGhhdmUgYSB0aWRpZWQgdmVyc2lvbiBvZiBlYWNoIG1vZGVsIHN0b3JlZCBpbiB0aGUgdGlkaWVkIGNvbHVtbi4gV2Ugd2FudCB0byBjb21iaW5lIGFsbCBvZiB0aG9zZSBpbnRvIGEgbGFyZ2UgZGF0YSBmcmFtZSwgc2ltaWxhciB0byBob3cgeW91IGNvbWJpbmVkIHRoZSBVUyBhbmQgVUsgdGlkaWVkIG1vZGVscyBlYXJsaWVyLiBSZWNhbGwgdGhhdCB0aGUgdW5uZXN0KCkgZnVuY3Rpb24gZnJvbSB0aWR5ciBhY2hpZXZlcyB0aGlzLg0KDQpgYGB7cn0NCiMgQWRkIG9uZSBtb3JlIHN0ZXAgdGhhdCB1bm5lc3RzIHRoZSB0aWRpZWQgY29sdW1uDQpjb3VudHJ5X2NvZWZmaWNpZW50cyA8LSBieV95ZWFyX2NvdW50cnkgJT4lDQogIG5lc3QoLWNvdW50cnkpICU+JQ0KICBtdXRhdGUobW9kZWwgPSBtYXAoZGF0YSwgfiBsbShwZXJjZW50X3llcyB+IHllYXIsIGRhdGEgPSAuKSksDQogICAgICAgICB0aWRpZWQgPSBtYXAobW9kZWwsIHRpZHkpKSAlPiUNCiAgICAgICAgIHVubmVzdCh0aWRpZWQpDQoNCg0KIyBQcmludCB0aGUgcmVzdWx0aW5nIGNvdW50cnlfY29lZmZpY2llbnRzIHZhcmlhYmxlDQpoZWFkKGNvdW50cnlfY29lZmZpY2llbnRzKQ0KYGBgDQojIyAgV29ya2luZyB3aXRoIG1hbnkgdGlkeSBtb2RlbHMNCg0KIyMjIEZpbHRlcmluZyBtb2RlbCB0ZXJtcw0KDQpXZSBjdXJyZW50bHkgaGF2ZSBib3RoIHRoZSBpbnRlcmNlcHQgYW5kIHNsb3BlIHRlcm1zIGZvciBlYWNoIGJ5LWNvdW50cnkgbW9kZWwuIFdlJ3JlIHByb2JhYmx5IG1vcmUgaW50ZXJlc3RlZCBpbiBob3cgZWFjaCBpcyBjaGFuZ2luZyBvdmVyIHRpbWUsIHNvIHdlIHdhbnQgdG8gZm9jdXMgb24gdGhlIHNsb3BlIHRlcm1zLg0KYGBge3J9DQojIFByaW50IHRoZSBjb3VudHJ5X2NvZWZmaWNpZW50cyBkYXRhc2V0DQpoZWFkKGNvdW50cnlfY29lZmZpY2llbnRzKQ0KDQojIEZpbHRlciBmb3Igb25seSB0aGUgc2xvcGUgdGVybXMNCmhlYWQoY291bnRyeV9jb2VmZmljaWVudHMgJT4lDQogIGZpbHRlcih0ZXJtID09ICJ5ZWFyIikpDQpgYGANCiMjIyBGaWx0ZXJpbmcgZm9yIHNpZ25pZmljYW50IGNvdW50cmllcw0KDQpOb3QgYWxsIHNsb3BlcyBhcmUgc2lnbmlmaWNhbnQsIGFuZCB3ZSBjYW4gdXNlIHRoZSBwLXZhbHVlIHRvIGd1ZXNzIHdoaWNoIGFyZSBhbmQgd2hpY2ggYXJlIG5vdC4NCg0KSG93ZXZlciwgd2hlbiB3ZSBoYXZlIGxvdHMgb2YgcC12YWx1ZXMsIGxpa2Ugb25lIGZvciBlYWNoIGNvdW50cnksIHdlIHJ1biBpbnRvIHRoZSBwcm9ibGVtIG9mIG11bHRpcGxlIGh5cG90aGVzaXMgdGVzdGluZywgd2hlcmUgd2UgaGF2ZSB0byBzZXQgYSBzdHJpY3RlciB0aHJlc2hvbGQuIFRoZSBwLmFkanVzdCgpIGZ1bmN0aW9uIGlzIGEgc2ltcGxlIHdheSB0byBjb3JyZWN0IGZvciB0aGlzLCB3aGVyZSBwLmFkanVzdChwLnZhbHVlKSBvbiBhIHZlY3RvciBvZiBwLXZhbHVlcyByZXR1cm5zIGEgc2V0IHRoYXQgd2UgY2FuIHRydXN0Lg0KDQpIZXJlIHdlJ2xsIGFkZCB0d28gc3RlcHMgdG8gcHJvY2VzcyB0aGUgc2xvcGVfdGVybXMgZGF0YXNldDogdXNlIGEgbXV0YXRlIHRvIGNyZWF0ZSB0aGUgbmV3LCBhZGp1c3RlZCBwLXZhbHVlIGNvbHVtbiwgYW5kIGZpbHRlciB0byBmaWx0ZXIgZm9yIHRob3NlIGJlbG93IGEgLjA1IHRocmVzaG9sZC4NCmBgYHtyfQ0KIyBGaWx0ZXIgZm9yIG9ubHkgdGhlIHNsb3BlIHRlcm1zDQpzbG9wZV90ZXJtcyA8LSBjb3VudHJ5X2NvZWZmaWNpZW50cyAlPiUNCiAgZmlsdGVyKHRlcm0gPT0gInllYXIiKQ0KDQojIEFkZCBwLmFkanVzdGVkIGNvbHVtbiwgdGhlbiBmaWx0ZXINCmhlYWQoc2xvcGVfdGVybXMgJT4lDQogIG11dGF0ZShwLmFkanVzdGVkID0gcC5hZGp1c3QocC52YWx1ZSkpICU+JQ0KICBmaWx0ZXIocC5hZGp1c3RlZCA8IDAuMDUpKQ0KYGBgDQpOb3RpY2UgdGhhdCB0aGVyZSBhcmUgbm93IG9ubHkgNjEgY291bnRyaWVzIHdpdGggc2lnbmlmaWNhbnQgdHJlbmRzLg0KDQojIyMgU29ydGluZyBieSBzbG9wZQ0KDQpOb3cgdGhhdCB3ZSd2ZSBmaWx0ZXJlZCBmb3IgY291bnRyaWVzIHdoZXJlIHRoZSB0cmVuZCBpcyBwcm9iYWJseSBub3QgZHVlIHRvIGNoYW5jZSwgd2UgbWF5IGJlIGludGVyZXN0ZWQgaW4gY291bnRyaWVzIHdob3NlIHBlcmNlbnRhZ2Ugb2YgInllcyIgdm90ZXMgaXMgY2hhbmdpbmcgbW9zdCBxdWlja2x5IG92ZXIgdGltZS4gVGh1cywgd2Ugd2FudCB0byBmaW5kIHRoZSBjb3VudHJpZXMgd2l0aCB0aGUgaGlnaGVzdCBhbmQgbG93ZXN0IHNsb3BlczsgdGhhdCBpcywgdGhlIGVzdGltYXRlIGNvbHVtbi4NCmBgYHtyfQ0KIyBGaWx0ZXIgYnkgYWRqdXN0ZWQgcC12YWx1ZXMNCmZpbHRlcmVkX2NvdW50cmllcyA8LSBjb3VudHJ5X2NvZWZmaWNpZW50cyAlPiUNCiAgZmlsdGVyKHRlcm0gPT0gInllYXIiKSAlPiUNCiAgbXV0YXRlKHAuYWRqdXN0ZWQgPSBwLmFkanVzdChwLnZhbHVlKSkgJT4lDQogIGZpbHRlcihwLmFkanVzdGVkIDwgLjA1KQ0KDQojIFNvcnQgZm9yIHRoZSBjb3VudHJpZXMgaW5jcmVhc2luZyBtb3N0IHF1aWNrbHkNCmhlYWQoZmlsdGVyZWRfY291bnRyaWVzICU+JQ0KICBhcnJhbmdlKGVzdGltYXRlKSkNCg0KDQojIFNvcnQgZm9yIHRoZSBjb3VudHJpZXMgZGVjcmVhc2luZyBtb3N0IHF1aWNrbHkNCmhlYWQoZmlsdGVyZWRfY291bnRyaWVzICU+JQ0KICBhcnJhbmdlKGRlc2MoZXN0aW1hdGUpKSkNCmBgYA0KIyBKb2luaW5nIGFuZCB0aWR5aW5nDQoNCiMjSm9pbmluZyBkYXRhc2V0cw0KDQpXZSdsbCBub3cgY29tYmluZSB2b3Rlc19wcm9jZXNzZWQgZGF0YXNldCB3aXRoIHRoZSBuZXcgZGVzY3JpcHRpb25zIGRhdGFzZXQsIHdoaWNoIGluY2x1ZGVzIHRvcGljIGluZm9ybWF0aW9uIGFib3V0IGVhY2ggY291bnRyeSwgc28gdGhhdCB3ZSBjYW4gYW5hbHl6ZSB2b3RlcyB3aXRoaW4gcGFydGljdWxhciB0b3BpY3MuDQoNClRvIGRvIHRoaXMsIHdlJ2xsIG1ha2UgdXNlIG9mIHRoZSBpbm5lcl9qb2luKCkgZnVuY3Rpb24gZnJvbSBkcGx5ci4NCmBgYHtyfQ0KIyBMb2FkIGRwbHlyIHBhY2thZ2UNCmxpYnJhcnkoZHBseXIpDQoNCiMgUHJpbnQgdGhlIHZvdGVzX3Byb2Nlc3NlZCBkYXRhc2V0DQpoZWFkKHZvdGVzX3Byb2Nlc3NlZCkNCg0KIyBQcmludCB0aGUgZGVzY3JpcHRpb25zIGRhdGFzZXQNCmRlc2NyaXB0aW9ucyA8LSByZWFkUkRTKCJkZXNjcmlwdGlvbnMucmRzIikNCmhlYWQoZGVzY3JpcHRpb25zKQ0KDQojIEpvaW4gdGhlbSB0b2dldGhlciBiYXNlZCBvbiB0aGUgInJjaWQiIGFuZCAic2Vzc2lvbiIgY29sdW1ucw0Kdm90ZXNfam9pbmVkIDwtIHZvdGVzX3Byb2Nlc3NlZCAlPiUNCiAgaW5uZXJfam9pbihkZXNjcmlwdGlvbnMsIGJ5PSBjKCJyY2lkIiAsICJzZXNzaW9uIikpDQpgYGANCiMjIyBGaWx0ZXJpbmcgdGhlIGpvaW5lZCBkYXRhc2V0DQoNClRoZXJlIGFyZSBzaXggY29sdW1ucyBpbiB0aGUgZGVzY3JpcHRpb25zIGRhdGFzZXQgKGFuZCB0aGVyZWZvcmUgaW4gdGhlIG5ldyBqb2luZWQgZGF0YXNldCkgdGhhdCBkZXNjcmliZSB0aGUgdG9waWMgb2YgYSByZXNvbHV0aW9uOg0KDQoxLiBtZTogUGFsZXN0aW5pYW4gY29uZmxpY3QNCg0KMi4gbnU6IE51Y2xlYXIgd2VhcG9ucyBhbmQgbnVjbGVhciBtYXRlcmlhbA0KDQozLiBkaTogQXJtcyBjb250cm9sIGFuZCBkaXNhcm1hbWVudA0KDQo0LiBocjogSHVtYW4gcmlnaHRzDQoNCjUuIGNvOiBDb2xvbmlhbGlzbQ0KDQo2LiBlYzogRWNvbm9taWMgZGV2ZWxvcG1lbnQNCg0KRWFjaCBjb250YWlucyBhIDEgaWYgdGhlIHJlc29sdXRpb24gaXMgcmVsYXRlZCB0byB0aGlzIHRvcGljIGFuZCBhIDAgb3RoZXJ3aXNlDQpgYGB7cn0NCiMgRmlsdGVyIGZvciB2b3RlcyByZWxhdGVkIHRvIGNvbG9uaWFsaXNtDQp2b3Rlc19jb2wgPC0gdm90ZXNfam9pbmVkICU+JQ0KICBmaWx0ZXIoY28gPT0gMSkNCmhlYWQodm90ZXNfY29sKQ0KYGBgDQojIyMgVmlzdWFsaXppbmcgY29sb25pYWxpc20gdm90ZXMNCg0KRWFybGllciBleGVyY2lzZSwgd2UgZ3JhcGhlZCB0aGUgcGVyY2VudGFnZSBvZiB2b3RlcyBlYWNoIHllYXIgd2hlcmUgdGhlIFVTIHZvdGVkICJ5ZXMiLiBOb3cgd2UnbGwgY3JlYXRlIHRoYXQgc2FtZSBncmFwaCwgYnV0IG9ubHkgZm9yIHZvdGVzIHJlbGF0ZWQgdG8gY29sb25pYWxpc20uDQpgYGB7cn0NCiMgTG9hZCB0aGUgZ2dwbG90MiBwYWNrYWdlDQpsaWJyYXJ5KGdncGxvdDIpDQoNCiMgRmlsdGVyLCB0aGVuIHN1bW1hcml6ZSBieSB5ZWFyOiBVU19jb19ieV95ZWFyDQpVU19jb19ieV95ZWFyIDwtIHZvdGVzX2pvaW5lZCAlPiUNCiAgZmlsdGVyKGNvdW50cnkgPT0gIlVuaXRlZCBTdGF0ZXMiLCBjbyA9PSAxKSAlPiUNCiAgZ3JvdXBfYnkoeWVhcikgJT4lDQogIHN1bW1hcml6ZShwZXJjZW50X3llcyA9IG1lYW4odm90ZT09MSkpDQoNCiMgR3JhcGggdGhlICUgb2YgInllcyIgdm90ZXMgb3ZlciB0aW1lDQpnZ3Bsb3QoVVNfY29fYnlfeWVhciwgYWVzKHggPSB5ZWFyLCB5ID0gcGVyY2VudF95ZXMpKSArDQogIGdlb21fbGluZSgpDQpgYGANCiMjIFRpZHkgZGF0YQ0KDQojIyMgVXNpbmcgZ2F0aGVyIHRvIHRpZHkgYSBkYXRhc2V0DQoNCkluIG9yZGVyIHRvIHJlcHJlc2VudCB0aGUgam9pbmVkIHZvdGUtdG9waWMgZGF0YSBpbiBhIHRpZHkgZm9ybSBzbyB3ZSBjYW4gYW5hbHl6ZSBhbmQgZ3JhcGggYnkgdG9waWMsIHdlIG5lZWQgdG8gdHJhbnNmb3JtIHRoZSBkYXRhIHNvIHRoYXQgZWFjaCByb3cgaGFzIG9uZSBjb21iaW5hdGlvbiBvZiBjb3VudHJ5LXZvdGUtdG9waWMuIFRoaXMgd2lsbCBjaGFuZ2UgdGhlIGRhdGEgZnJvbSBoYXZpbmcgc2l4IGNvbHVtbnMgKG1lLCBudSwgZGksIGhyLCBjbywgZWMpIHRvIGhhdmluZyB0d28gY29sdW1ucyAodG9waWMgYW5kIGhhc190b3BpYykuDQpgYGB7cn0NCiMgTG9hZCB0aGUgdGlkeXIgcGFja2FnZQ0KbGlicmFyeSh0aWR5cikNCg0KIyBHYXRoZXIgdGhlIHNpeCBtZS9udS9kaS9oci9jby9lYyBjb2x1bW5zDQp2b3Rlc19nYXRoZXJlZCA8LSB2b3Rlc19qb2luZWQgJT4lDQogIGdhdGhlcih0b3BpYywgaGFzX3RvcGljLCBtZTplYykNCmhlYWQodm90ZXNfZ2F0aGVyZWQpDQoNCiMgUGVyZm9ybSBnYXRoZXIgYWdhaW4sIHRoZW4gZmlsdGVyDQp2b3Rlc19nYXRoZXJlZCA8LSB2b3Rlc19qb2luZWQgJT4lDQogIGdhdGhlcih0b3BpYywgaGFzX3RvcGljLCBtZTplYykgJT4lDQogIGZpbHRlcihoYXNfdG9waWMgPT0gMSkNCmBgYA0KIyMjIFJlY29kaW5nIHRoZSB0b3BpY3MNCg0KVGhlcmUncyBvbmUgbW9yZSBzdGVwIG9mIGRhdGEgY2xlYW5pbmcgdG8gbWFrZSB0aGlzIG1vcmUgaW50ZXJwcmV0YWJsZS4gUmlnaHQgbm93LCB0b3BpY3MgYXJlIHJlcHJlc2VudGVkIGJ5IHR3by1sZXR0ZXIgY29kZXMNCg0KU28gdGhhdCB3ZSBjYW4gaW50ZXJwcmV0IHRoZSBkYXRhIG1vcmUgZWFzaWx5LCByZWNvZGUgdGhlIGRhdGEgdG8gcmVwbGFjZSB0aGVzZSBjb2RlcyB3aXRoIHRoZWlyIGZ1bGwgbmFtZS4gV2UgY2FuIGRvIHRoYXQgd2l0aCBkcGx5cidzIHJlY29kZSgpIGZ1bmN0aW9uLCB3aGljaCByZXBsYWNlcyB2YWx1ZXMgd2l0aCBvbmVzIHlvdSBzcGVjaWZ5Og0KDQogICAgIGV4YW1wbGUgPC0gYygiYXBwbGUiLCAiYmFuYW5hIiwgImFwcGxlIiwgIm9yYW5nZSIpDQogICAgIHJlY29kZShleGFtcGxlLA0KICAgICAgICAgICAgYXBwbGUgPSAicGx1bSIsDQogICAgICAgICAgICBiYW5hbmEgPSAiZ3JhcGUiKQ0KDQoNCmBgYHtyfQ0KIyBSZXBsYWNlIHRoZSB0d28tbGV0dGVyIGNvZGVzIGluIHRvcGljOiB2b3Rlc190aWRpZWQNCnZvdGVzX3RpZGllZCA8LSB2b3Rlc19nYXRoZXJlZCAlPiUNCiAgbXV0YXRlKHRvcGljID0gcmVjb2RlKHRvcGljLA0KICAgICAgICAgICAgICAgICAgICAgICAgIm1lIiA9ICJQYWxlc3RpbmlhbiBjb25mbGljdCIsDQogICAgICAgICAgICAgICAgICAgICAgICAibnUiID0gIk51Y2xlYXIgd2VhcG9ucyBhbmQgbnVjbGVhciBtYXRlcmlhbCIsDQogICAgICAgICAgICAgICAgICAgICAgICAiZGkiID0gIkFybXMgY29udHJvbCBhbmQgZGlzYXJtYW1lbnQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgImhyIiA9ICJIdW1hbiByaWdodHMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgImNvIiA9ICJDb2xvbmlhbGlzbSIsDQogICAgICAgICAgICAgICAgICAgICAgICAiZWMiID0gIkVjb25vbWljIGRldmVsb3BtZW50IikpDQpgYGANCiMjIyBTdW1tYXJpemUgYnkgY291bnRyeSwgeWVhciwgYW5kIHRvcGljDQoNCk5vdyB0aGF0IHdlIGhhdmUgdG9waWMgYXMgYW4gYWRkaXRpb25hbCB2YXJpYWJsZSwgeW91IGNhbiBzdW1tYXJpemUgdGhlIHZvdGVzIGZvciBlYWNoIGNvbWJpbmF0aW9uIG9mIGNvdW50cnksIHllYXIsIGFuZCB0b3BpYyAoZS5nLiBmb3IgdGhlIFVuaXRlZCBTdGF0ZXMgaW4gMjAxMyBvbiB0aGUgdG9waWMgb2YgbnVjbGVhciB3ZWFwb25zLikNCmBgYHtyfQ0KIyBQcmludCB2b3Rlc190aWRpZWQNCmhlYWQodm90ZXNfdGlkaWVkKQ0KDQojIFN1bW1hcml6ZSB0aGUgcGVyY2VudGFnZSAieWVzIiBwZXIgY291bnRyeS15ZWFyLXRvcGljDQpieV9jb3VudHJ5X3llYXJfdG9waWMgPC0gdm90ZXNfdGlkaWVkICU+JQ0KICBncm91cF9ieShjb3VudHJ5LCB5ZWFyLCB0b3BpYykgJT4lDQogIHN1bW1hcml6ZSh0b3RhbCA9IG4oKSwNCiAgcGVyY2VudF95ZXMgPSBtZWFuKHZvdGUgPT0gMSkpICU+JQ0KICB1bmdyb3VwKCkNCg0KIyBQcmludCBieV9jb3VudHJ5X3llYXJfdG9waWMNCmhlYWQoYnlfY291bnRyeV95ZWFyX3RvcGljKQ0KYGBgDQojIyMgVmlzdWFsaXppbmcgdHJlbmRzIGluIHRvcGljcyBmb3Igb25lIGNvdW50cnkNCg0KV2UgY2FuIG5vdyB2aXN1YWxpemUgdGhlIHRyZW5kcyBpbiBwZXJjZW50YWdlICJ5ZXMiIG92ZXIgdGltZSBmb3IgYWxsIHNpeCB0b3BpY3Mgc2lkZS1ieS1zaWRlLiBIZXJlLCB3ZSdsbCB2aXN1YWxpemUgdGhlbSBqdXN0IGZvciB0aGUgVW5pdGVkIFN0YXRlcy4NCmBgYHtyfQ0KIyBMb2FkIHRoZSBnZ3Bsb3QyIHBhY2thZ2UNCmxpYnJhcnkoZ2dwbG90MikNCg0KIyBGaWx0ZXIgYnlfY291bnRyeV95ZWFyX3RvcGljIGZvciBqdXN0IHRoZSBVUw0KVVNfYnlfY291bnRyeV95ZWFyX3RvcGljIDwtIGJ5X2NvdW50cnlfeWVhcl90b3BpYyAlPiUNCiBmaWx0ZXIoY291bnRyeSA9PSAiVW5pdGVkIFN0YXRlcyIpDQoNCiMgUGxvdCAlIHllcyBvdmVyIHRpbWUgZm9yIHRoZSBVUywgZmFjZXRpbmcgYnkgdG9waWMNCmdncGxvdChVU19ieV9jb3VudHJ5X3llYXJfdG9waWMsIGFlcyh4ID0geWVhciwgeSA9IHBlcmNlbnRfeWVzKSkgKw0KICBnZW9tX2xpbmUoKSArDQogIGZhY2V0X3dyYXAofnRvcGljKQ0KYGBgDQojIyBUaWR5IG1vZGVsaW5nIGJ5IHRvcGljIGFuZCBjb3VudHJ5DQoNCiMjIyBOZXN0aW5nIGJ5IHRvcGljIGFuZCBjb3VudHJ5DQoNCldlIGNvbnN0cnVjdGVkIGEgbGluZWFyIG1vZGVsIGZvciBlYWNoIGNvdW50cnkgYnkgbmVzdGluZyB0aGUgZGF0YSBpbiBlYWNoIGNvdW50cnksIGZpdHRpbmcgYSBtb2RlbCB0byBlYWNoIGRhdGFzZXQsIHRoZW4gdGlkeWluZyBlYWNoIG1vZGVsIHdpdGggYnJvb20gYW5kIHVubmVzdGluZyB0aGUgY29lZmZpY2llbnRzLiBUaGUgY29kZSBsb29rZWQgc29tZXRoaW5nIGxpa2UgdGhpczoNCg0KICAgIGNvdW50cnlfY29lZmZpY2llbnRzIDwtIGJ5X3llYXJfY291bnRyeSAlPiUNCiAgICAgIG5lc3QoLWNvdW50cnkpICU+JQ0KICAgICAgbXV0YXRlKG1vZGVsID0gbWFwKGRhdGEsIH4gbG0ocGVyY2VudF95ZXMgfiB5ZWFyLCBkYXRhID0gLikpLA0KICAgICAgICAgICAgIHRpZGllZCA9IG1hcChtb2RlbCwgdGlkeSkpICU+JQ0KICAgICAgdW5uZXN0KHRpZGllZCkNCg0KTm93LCB3ZSdsbCBhZ2FpbiBiZSBtb2RlbGluZyBjaGFuZ2UgaW4gInBlcmNlbnRhZ2UiIHllcyBvdmVyIHRpbWUsIGJ1dCBpbnN0ZWFkIG9mIGZpdHRpbmcgb25lIG1vZGVsIGZvciBlYWNoIGNvdW50cnksIHdlJ2xsIGZpdCBvbmUgZm9yIGVhY2ggY29tYmluYXRpb24gb2YgY291bnRyeSBhbmQgdG9waWMuDQpgYGB7cn0NCiMgUHJpbnQgYnlfY291bnRyeV95ZWFyX3RvcGljDQpoZWFkKGJ5X2NvdW50cnlfeWVhcl90b3BpYykNCg0KIyBGaXQgbW9kZWwgb24gdGhlIGJ5X2NvdW50cnlfeWVhcl90b3BpYyBkYXRhc2V0DQpjb3VudHJ5X3RvcGljX2NvZWZmaWNpZW50cyA8LSBieV9jb3VudHJ5X3llYXJfdG9waWMgJT4lDQogIG5lc3QoLWNvdW50cnksIC10b3BpYykgJT4lDQogIG11dGF0ZShtb2RlbCA9IG1hcChkYXRhLCB+IGxtKHBlcmNlbnRfeWVzIH4geWVhciwgZGF0YSA9IC4pKSwNCiAgICAgICAgIHRpZGllZCA9IG1hcChtb2RlbCwgdGlkeSkpICU+JQ0KICB1bm5lc3QodGlkaWVkKQ0KDQojIFByaW50IGNvdW50cnlfdG9waWNfY29lZmZpY2llbnRzDQpoZWFkKGNvdW50cnlfdG9waWNfY29lZmZpY2llbnRzKQ0KYGBgDQpXZSBjYW4gaWdub3JlIHRoZSB3YXJuaW5nIG1lc3NhZ2VzIGluIHRoZSBjb25zb2xlIGZvciBub3cuDQoNCiMjIyBJbnRlcnByZXRpbmcgdGlkeSBtb2RlbHMNCg0KTm93IHdlIGhhdmUgYm90aCB0aGUgc2xvcGUgYW5kIGludGVyY2VwdCB0ZXJtcyBmb3IgZWFjaCBtb2RlbC4gSnVzdCBhcyB5b3UgZGlkIGluIHRoZSBsYXN0IGNoYXB0ZXIgd2l0aCB0aGUgdGlkaWVkIGNvZWZmaWNpZW50cywgd2UnbGwgbmVlZCB0byBmaWx0ZXIgZm9yIG9ubHkgdGhlIHNsb3BlIHRlcm1zLg0KDQpXZSdsbCBhbHNvIGhhdmUgdG8gZXh0cmFjdCBvbmx5IGNhc2VzIHRoYXQgYXJlIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQsIHdoaWNoIG1lYW5zIGFkanVzdGluZyB0aGUgcC12YWx1ZSBmb3IgdGhlIG51bWJlciBvZiBtb2RlbHMsIGFuZCB0aGVuIGZpbHRlcmluZyB0byBpbmNsdWRlIG9ubHkgc2lnbmlmaWNhbnQgY2hhbmdlcy4NCmBgYHtyfQ0KIyBDcmVhdGUgY291bnRyeV90b3BpY19maWx0ZXJlZA0KY291bnRyeV90b3BpY19maWx0ZXJlZCA8LSBjb3VudHJ5X3RvcGljX2NvZWZmaWNpZW50cyAlPiUNCiAgZmlsdGVyKHRlcm0gPT0gInllYXIiKSAlPiUNCiAgbXV0YXRlKHAuYWRqdXN0ZWQgPSBwLmFkanVzdChwLnZhbHVlKSkgJT4lDQogIGZpbHRlcihwLmFkanVzdGVkIDwgLjA1KQ0KYGBgDQojIyMgU3RlZXBlc3QgdHJlbmRzIGJ5IHRvcGljDQoNCldoaWNoIGNvbWJpbmF0aW9uIG9mIGNvdW50cnkgYW5kIHRvcGljIGhhcyB0aGUgc3RlZXBlc3QgZG93bndhcmQgdHJlbmQ/DQpgYGB7cn0NCmhlYWQoY291bnRyeV90b3BpY19maWx0ZXJlZCAlPiUgDQogIGFycmFuZ2UoZXN0aW1hdGUpKQ0KYGBgDQpWYW51YXR1IChhbiBpc2xhbmQgbmF0aW9uIGluIHRoZSBQYWNpZmljIE9jZWFuKSBzaGFycGx5IGNoYW5nZWQgaXRzIHBhdHRlcm4gb2Ygdm90aW5nIG9uIHRoZSB0b3BpYyBvZiBQYWxlc3RpbmlhbiBjb25mbGljdC4NCg0KIyMjIENoZWNraW5nIG1vZGVscyB2aXN1YWxseQ0KDQpMZXQncyBleGFtaW5lIHRoaXMgY291bnRyeSdzIHZvdGluZyBwYXR0ZXJucyBtb3JlIGNsb3NlbHkuIFJlY2FsbCB0aGF0IHRoZSBieV9jb3VudHJ5X3llYXJfdG9waWMgZGF0YXNldCBjb250YWluZWQgb25lIHJvdyBmb3IgZWFjaCBjb21iaW5hdGlvbiBvZiBjb3VudHJ5LCB5ZWFyLCBhbmQgdG9waWMuIFlvdSBjYW4gdXNlIHRoYXQgdG8gY3JlYXRlIGEgcGxvdCBvZiBWYW51YXR1J3Mgdm90aW5nLCBmYWNldGVkIGJ5IHRvcGljLg0KYGBge3J9DQojIENyZWF0ZSB2YW51YXR1X2J5X2NvdW50cnlfeWVhcl90b3BpYw0KdmFudWF0dV9ieV9jb3VudHJ5X3llYXJfdG9waWMgPC0gYnlfY291bnRyeV95ZWFyX3RvcGljICU+JQ0KICBmaWx0ZXIoY291bnRyeSA9PSAiVmFudWF0dSIpDQoNCiMgUGxvdCBvZiBwZXJjZW50YWdlICJ5ZXMiIG92ZXIgdGltZSwgZmFjZXRlZCBieSB0b3BpYw0KZ2dwbG90KHZhbnVhdHVfYnlfY291bnRyeV95ZWFyX3RvcGljLCBhZXMoeCA9IHllYXIsIHkgPSBwZXJjZW50X3llcykpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBmYWNldF93cmFwKH50b3BpYykNCmBgYA0KDQoNCg==