Return to Homepage
Introduction
In the following report, I will be investigating and examining the
untold story behind seemingly transparent records pertaining to
worldwide COVID cases and death tolls. While the data has already been
cleaned and contains fairly simple information, this project aims to
investigate the disparities between countries, their COVID death tolls,
COVID recovery rates, and the correlation between those statistics and
their financial standing and population size. In simpler terms, does a
country having a high death toll inherently imply that they handled the
outbreak worse than another? What does the total number of cases in
relation to the number of recovered patients and deaths tell us about
that nation’s pandemic response? Did active participants in COVID tests
actually have any noticable affect on total number of cases and in turn,
deaths? These are just some of the questions I hope to explore in this
writing.
Background
This project was inspired in part by my previous research on
non-substance use disorder treatment services offered in Baltimore, MD,
which primarily consisted of COVID-related services. It was also
inspired by general happen stance: I found a very nice data set on
Kaggle and felt it could be an interesting take on a seemingly dull data
set. As mentioned, this data set was found here,
as updated 2 years ago (2022) by Mrityunjay Pathak.
The data set consists of various reported statistics regarding
Coronavirus (COVID-19), an infectious disease caused by the SARS-CoV-2
virus. Most of those infected by the virus will experience some mild to
moderate respitory symptoms and recover with requiring any particular
medical treatment, albeit taking a bit longer than most other diseases.
However, some individuals may become seriously ill and require medical
attention and even hospitalization. The elderly and those with existing
medical conditions such as cardiovascular disease, chronic respiratory
illness, cancer, and other such conditions are more likely to develop
serious symptoms. That being said, anyone, regardless
of age or medical history, could grow seriously ill and die as a result
of COVID-19 infection.
Prevention is the primary defense for the spread of the disease.
Understanding how the virus spreads is important as protecting oneself
from the illness is the best way to protect others as well. At the peak
of the pandemic, it was advised that individuals stay at leaast 1 meter
apart from each, wear properly fitted medical-grade masks, and wash
hands or use hand sanitizer frequently. Once the vaccines were released,
it was also advised by the CDC to get vaccinated to statt building up
herd immunity.
The virus can spread through liquid particles associated with
coughing, sneezing, speaking, singing, or breathing. The obvious avenue
for this is through the mouth or nose of the sick individual. This can
be spread through larger droplets to smaller aerosols. Individuals are
encouraged to practice proper respiratory etiquette, stay home when
sick, and to self-isolate at least 1 week after sympotmns have
ceased.
This data has been compiled through reports from the onset of the
pandemic (2020) up until its last update in 2022. The data does not
distinguish between variants of the virus, however, it does imply that
it accounts for the original variant, Delta, Omicron and its subvariants
of BA.4 and BA.5.
Data
As already described, this data set was retrieved from Kaggle and had
already been mostly cleaned for analysis. However,
there are some changes I wanted to make to the data structure, missing
values/empty spaces, and superfluous characters found throughout the
data set. The following code and outputs demonstrate the changes I’ve
made to allow for smoother data analysis:
# shows the original data structure
str(og_covid_world_dat)
## 'data.frame': 231 obs. of 8 variables:
## $ Serial.Number : int 1 2 3 4 5 6 7 8 9 10 ...
## $ Country : chr "USA" "India" "France" "Germany" ...
## $ Total.Cases : chr "104,196,861" "44,682,784" "39,524,311" "37,779,833" ...
## $ Total.Deaths : chr "1,132,935" "530,740" "164,233" "165,711" ...
## $ Total.Recovered: chr "101,322,779" "44,150,289" "39,264,546" "37,398,100" ...
## $ Active.Cases : chr "1,741,147" "1,755" "95,532" "216,022" ...
## $ Total.Test : chr "1,159,832,679" "915,265,788" "271,490,188" "122,332,384" ...
## $ Population : chr "334,805,269" "1,406,631,776" "65,584,518" "83,883,596" ...
# converts all N/A chr values to actual missing values and fills in empty spaces with missing values
covid_world_dat <- og_covid_world_dat |>
mutate(across(where(is.character), ~ na_if(., "N/A") |> na_if("")))
# convert column titles to snake_case
covid_world_dat <- clean_names(covid_world_dat)
# replace commas in all chr columns to avoid issue with conversion to num data type
covid_world_dat <- covid_world_dat |>
mutate(across(where(is.character), ~ str_replace_all(., ",", "")))
# converts data structure to more appropriate data types
covid_world_dat <- covid_world_dat |>
mutate(country = as.factor(country),
across(-c(country, serial_number), as.numeric), # converts to num (not int) to account for math that results in decimals
total_test_taken = total_test) |> # makes a column name clearer to understand
relocate(total_test_taken, .before = population) |>
select(-total_test) # removes that original column
# shows the updated data structure
str(covid_world_dat)
## 'data.frame': 231 obs. of 8 variables:
## $ serial_number : int 1 2 3 4 5 6 7 8 9 10 ...
## $ country : Factor w/ 231 levels "Afghanistan",..: 221 95 73 79 27 105 172 102 218 170 ...
## $ total_cases : num 104196861 44682784 39524311 37779833 36824580 ...
## $ total_deaths : num 1132935 530740 164233 165711 697074 ...
## $ total_recovered : num 101322779 44150289 39264546 37398100 35919372 ...
## $ active_cases : num 1741147 1755 95532 216022 208134 ...
## $ total_test_taken: num 1159832679 915265788 271490188 122332384 63776166 ...
## $ population : num 334805269 1406631776 65584518 83883596 215353593 ...
# demonstrates a portion of our updated data set
head(covid_world_dat)
| 1 |
USA |
104196861 |
1132935 |
101322779 |
1741147 |
1159832679 |
334805269 |
| 2 |
India |
44682784 |
530740 |
44150289 |
1755 |
915265788 |
1406631776 |
| 3 |
France |
39524311 |
164233 |
39264546 |
95532 |
271490188 |
65584518 |
| 4 |
Germany |
37779833 |
165711 |
37398100 |
216022 |
122332384 |
83883596 |
| 5 |
Brazil |
36824580 |
697074 |
35919372 |
208134 |
63776166 |
215353593 |
| 6 |
Japan |
32588442 |
68399 |
21567425 |
10952618 |
92144639 |
125584838 |
As noted before, the data was collected accross 231 countries (231
rows) along with 6 particular statistics associated with each country.
The columns are described as follows:
- serial_number
- a unique but arbitrary ID given to each row of data to serve as a
key column
- country
- total_cases
- total number of cases of COVID-19 reported at that point in the
country
- total_deaths
- total number of deaths from COVID-19 reported at that point in the
country
- total_recovered
- total number of partients who recovered from COVID-19 at that point
in the country
- active_cases
- currently on-going cases reported at the moment the survey was
conducted
- total_test_taken
- total number of COVID-19 tests administered and reported at that
point in the country
- population
- total number of people living in the country at that point of the
survey
Exploratory Analysis
Death Rate vs. Testing Rate
First, we will be investigating two metrics that aren’t given to us
in the actual data set:
The test rate refers to how extensively a country
has tested its population for COVID-19. A higher rate would suggest that
a country is conducting more tests relative to its population size,
which also implies more thorough effort in identifying and tackling
cases. Conversely, a lower test rate suggests the opposite: less of the
population is tested thus resulting in more overlooked cases.
- Formula: test_rate = total_test_taken /
population
The death rate represents the fatality rate of
COVID-19 in a country in relation to total cases. As this simply
implies, it offers an indication of of how deadly the disease is in the
population that is contracting it. A higher death rate suggests a larger
proportion of individuals are dying in the population; a lower rate
suggests the opposite. The death rate can be influenced by variety of
factors including healthcare quality, the age distribution of the
population, presence of underlying health conditions, and effectiveness
in medical intervention. Higher death rates don’t always mean that the
virus is more deadly; it can also be a sign of insufficient healthcare,
testing, or reporting.
- Formula: death_rate = total_deaths /
total_cases
As we can see this correlation plotted below. Each dot represents a
country. However, the first graph is one based on the standard numerical
values given in the data set. This results in a poor graph as the points
are too close to each other to make any meaningful conclusions.

The following graph is a more effective version that is fit to log
scale to separate the points out and allow us to visualize the data more
clearly:
# scatter plot showing the correlation between a population's death rate and testing rate per population fit by log scale
covid_world_dat |>
mutate(death_rate = total_deaths / total_cases,
test_rate = total_test_taken / population) |>
ggplot(aes(x = test_rate, y = death_rate)) +
geom_point(aes(color = country), size = 3, alpha = 0.7) +
scale_x_log10() + scale_y_log10() + # added log scale to more effective visualization
geom_smooth(method = "lm", se = FALSE, color = "black") + # line of best fit (linear model)
labs(title = "Death Rate vs. Testing Rate (Log Scale)",
x = "Tests per Population",
y = "Death Rate") +
theme_minimal() +
theme(legend.position = "none")

As we can obviously see, the more testing a country has
administered to its citizens, the lower the death rate.
- Higher testing = lower death rate
- Lower testing = higher death rate
Highest and Lowest death-to-test Ratio
In conjunction to the previous analysis, I calculated which countries
have the highest death-to-test ratio (the points that
are furthest to the left and up on the graph). This represents the how
many deaths occur relative to the number of tests conducted in each
country.
# calculation of the countries with the highest death-to-test ratio
high_death_to_test_ratio <- covid_world_dat |>
mutate(death_rate = total_deaths / total_cases,
test_rate = total_test_taken / population,
death_to_test_ratio = death_rate / test_rate) |>
arrange(desc(death_to_test_ratio)) |>
select(country, death_rate, test_rate, death_to_test_ratio) |>
head(10) # shows the top 10 countries
On the other hand, the countries with the lowest
death-to-test ratio are listed below. Simiarly, this denotes
which points were the furthest to the right and down on the graph.
# calculation of the countries with the lowest death-to-test ratio
low_death_to_test_ratio <- covid_world_dat |>
mutate(death_rate = total_deaths / total_cases,
test_rate = total_test_taken / population,
death_to_test_ratio = death_rate / test_rate) |>
arrange(death_to_test_ratio) |>
select(country, death_rate, test_rate, death_to_test_ratio) |>
head(10) # shows the top 10 countries
Top 10 Countries by Total Cases, Deaths, and Recoveries
The following graphs visualize the 10 countries with the
highest total of cases, deaths, and recoveries.
I separated the stacked bar plots because the actual disparity
between the total number of deaths and deaths is so high that you can
hardly see it. When we include the recoveries, you cannot even see the
death count for countries as large as the USA. This offers us a relative
comparison that is easy to compare. Now this isn’t meant to discredit
the heavy toll COVID had on the first-world; a million people still
died. However, it must be understood that 1,000,000 is only 1% of the
~100,000,000 recoveries made in the US alone (a population of over
300,000,000). With that consideration, we can come to appreciate the
excellent response that the USA and similar countries had under the
pressure of overfilled hospitals and understaffed medical personnel.
This is especially noticable by simply looking at the height of the bar
plots which simplies a heavy burden set onto the country due to
COVID-19. The correlation between recovery and death ratio can indicate
how well a country was able to respond to the cases appearing within
their borders.
- Due to the size of the count, R forces the count to be in scientific
notation. Keep in mind that the largest count to the right end of the
X-axis amounts to larger than 100,000,000 people.
# stacked bar plot of both the total cases and deaths for the countries with the most COVID-19 cases and deaths
covid_world_dat |>
arrange(desc(total_cases)) |>
head(10) |>
ggplot(aes(x = reorder(country, total_cases))) +
geom_bar(aes(y = total_cases, fill = "Cases"), stat = "identity", position = "dodge") +
geom_bar(aes(y = total_deaths, fill = "Deaths"), stat = "identity", position = "dodge") +
coord_flip() +
labs(title = "Top 10 Countries with the Most COVID-19 Cases and Deaths",
x = "Country",
y = "Count",
fill = "Category") +
theme_minimal()

# stacked bar plot of total cases, deaths, and recovered patients for the countries with the most COVID-19 cases and deaths
covid_world_dat |>
arrange(desc(total_cases)) |>
head(10) |>
ggplot(aes(x = reorder(country, total_cases))) +
geom_bar(aes(y = total_cases, fill = "Cases"), stat = "identity") +
geom_bar(aes(y = total_deaths, fill = "Deaths"), stat = "identity") +
geom_bar(aes(y = total_recovered, fill = "Recovered"), stat = "identity") +
coord_flip() +
labs(title = "Top 10 Countries with the Most COVID-19 Cases, Deaths, and Recovery",
x = "Country",
y = "Count",
fill = "Category") +
theme_minimal()

The following graphs visualize the 10 countries with the
lowest total of cases, deaths, and recoveries.
Once again, I also separated the plots to allow for easier
visualization. However, as you may have noticed, the countries with the
lowest number of cases also happen to have next to no reported deaths as
a result. We are talking about countries such as Tuvalu with a
population of 12,000. Though a large proportion of their population was
affected by the virus, there were no reported deaths. With that said, we
see that the top two countries also had next to no reported recoveries
(Saint Helena had 2).
What does this tell us about those two countries?
- Though they may not have done an excellent job at isolation, those
who got sick 1) received great treatment, or 2) had very few at-risk and
elderly individuals sick.
We see these values simply decrease with the population itself.
Tokelau has a population of a tiny 1,378 and a total of 5 reported cases
(of which were active at the time this survey was recorded). However, it
is difficult to quantify results so small seeing as these countries may
struggle to simply report an accurate count of all these instances. Who
knows, maybe we should go pay a visit to the Vatican!
# stacked bar plot of both the total cases and deaths for the countries with the least COVID-19 cases and deaths
covid_world_dat |>
arrange(total_cases) |>
head(10) |>
ggplot(aes(x = reorder(country, total_cases))) +
geom_bar(aes(y = total_cases, fill = "Cases"), stat = "identity", position = "dodge") +
geom_bar(aes(y = total_deaths, fill = "Deaths"), stat = "identity", position = "dodge") +
coord_flip() +
labs(title = "Top 10 Countries with the Least COVID-19 Cases and Deaths",
x = "Country",
y = "Count",
fill = "Category") +
theme_minimal()

# stacked bar plot of total cases, deaths, and recovered patients for the countries with the least COVID-19 cases and deaths
covid_world_dat |>
arrange(total_cases) |>
head(10) |>
ggplot(aes(x = reorder(country, total_cases))) +
geom_bar(aes(y = total_cases, fill = "Cases"), stat = "identity") +
geom_bar(aes(y = total_deaths, fill = "Deaths"), stat = "identity") +
geom_bar(aes(y = total_recovered, fill = "Recovered"), stat = "identity") +
coord_flip() +
labs(title = "Top 10 Countries with the Least COVID-19 Cases, Deaths, and Recovery",
x = "Country",
y = "Count",
fill = "Category") +
theme_minimal()

Visualizing Correlations between Key Metrics
The following analysis is a bit different than what I’m used to and I
do think it has the potential of being a bit inaccurate, or more like
deceiving. A correlation matrix is a table that shows the correlation
coefficients between many variables. Each cell within the table displays
the correlation between 2 variables, ranging from -1 to 1. These
coefficients indicate the strength and direction of a linear relation
between two variables.
How do we read the matrix?
- +1: Perfect positive correlation (both variables move in the same
direction)
- As one variable increase, the other increases
- -1: Perfect negative correlation (variables move in opposite
directions)
- As one variable decreases, the other decreases
- 0: No linear correlation (no relationship between the variables)
- No predictable linear relationship between the variables
With that in mind, I see no reason to really explain the correlations
in words when the matrix does a better job at doing so.
# calculate the correlation matrix
corr_matrix <- covid_world_dat |>
select(total_cases, total_deaths, total_recovered, active_cases, total_test_taken, population) |>
na.omit() |> # remove NAs to avoid conflict
cor()
# create the correlation plot with improved labels
corr_matrix |>
corrplot(method = "circle",
type = "upper",
tl.col = "black",
tl.srt = 45,
tl.cex = 0.8,
mar = c(0,0,1,0),
addCoef.col = "black",
number.cex = 0.7,
diag = FALSE)

Predictive Modeling
After having viewed and interpreted different statistical measures of
the COVID data, I feel it would be best served if we attempt to use what
we learned from the correlations between variables to try to predict the
most important metric in these surveys: total
deaths.
The following consists of the painstaking steps to produce a linear
regression model and make predictions on the total number of deaths
found in this data set.
1) Preprocessing the Data
Before building a model, it is best to preprocess the data in order
to clear out any missing values and creating any relevant features we
may need to allow for more specific modeling. In this case:
- deaths_per_million
- tells us how many deaths per million people in a country
- recovery_rate
- proportion of recovered cases compared to total cases which may
indicate healthcare effectiveness
- active_cases_ratio
- proportion of active cases to total cases; a higher number could
mean a more serious situation
# preparing the data
model_covid_world_dat <- covid_world_dat |>
mutate(
deaths_per_million = total_deaths / (population / 1e6), # deaths per million
recovery_rate = total_recovered / total_cases, # recovery rate
active_cases_ratio = active_cases / total_cases # active cases ratio
) |>
na.omit() # remove rows with NA values to avoid conflicts
To avoid redundancy and clutter, I will not be including any output,
just the code above.
2) Training the Linear Regression Model
We will now build a linear regression model to predict total_deaths
based on the above features. This linear regression should help us
understand the relation between the response (total_deaths) and
predictor values (everything else we made).
# train a linear regression model to predict total deaths
model <- lm(total_deaths ~ total_cases + total_recovered + active_cases + population, data = model_covid_world_dat)
# view model summary
summary(model)
##
## Call:
## lm(formula = total_deaths ~ total_cases + total_recovered + active_cases +
## population, data = model_covid_world_dat)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.000000032779 -0.000000000524 0.000000000359 0.000000001223 0.000000048890
##
## Coefficients:
## Estimate Std. Error
## (Intercept) 0.000000010184390607263 0.000000000456701745159
## total_cases 1.000000000000053512750 0.000000000000008702001
## total_recovered -1.000000000000053734794 0.000000000000008785060
## active_cases -1.000000000000053068661 0.000000000000008615763
## population -0.000000000000000077293 0.000000000000000004788
## t value Pr(>|t|)
## (Intercept) 22.30 <0.0000000000000002 ***
## total_cases 114916092899285.61 <0.0000000000000002 ***
## total_recovered -113829621331453.84 <0.0000000000000002 ***
## active_cases -116066326687905.08 <0.0000000000000002 ***
## population -16.14 <0.0000000000000002 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.000000006005 on 190 degrees of freedom
## Multiple R-squared: 1, Adjusted R-squared: 1
## F-statistic: 1.703e+28 on 4 and 190 DF, p-value: < 0.00000000000000022
The output summary of the model tells us:
- Coefficients
- Tell us how much each variable effects the response variable
(total_deaths)
- Example: if total_cases has a coefficient of 0.05, it means for
every 1 increase in total_cases, total_deaths will increase by 0.05
- P-value
- Tells us if the relationship between a predictor and a target is
statistically significant
- Values lower than 0.05 typically mean the predictor is
significant
- R-squared
- Measures how well the model fits the data
- An R-squared value closer to 1 means the model explains most of the
variability in total_deaths
3) Model Evaluation
We will now proceed to evaluate the model according to Root Mean
Squared Error (RMSE). This tells us, on average, how far off our
predictions are.
# predict total_deaths using the trained model
predictions <- predict(model, newdata = model_covid_world_dat)
# calculate RMSE (Root Mean Squared Error)
rmse <- sqrt(mean((predictions - model_covid_world_dat$total_deaths)^2))
print(paste("RMSE:", round(rmse, 2)))
## [1] "RMSE: 0"
A lower RMSE indicates better model performance. For example, an RMSE
of 500 means that, on average, the model’s predictions are off by 500
deaths.
4) Model Interpreation
The coefficients will us how strongly each predictor variable affects
total_deaths.
# view the coefficients
coef(model)
## (Intercept) total_cases
## 0.00000001018439060726309 1.00000000000005351274979
## total_recovered active_cases
## -1.00000000000005373479439 -1.00000000000005306866058
## population
## -0.00000000000000007729323
For example, if total_cases has a large positive coefficient, this
means that as the number of cases increases, so does the number of
deaths. If population has a negative coefficient, this could suggest
that countries with larger populations have relatively fewer deaths
compared to smaller countries, depending on other factors.
5) Model Tuning
Something many people, including myself, don’t do is cross-validation
to tune our model and avoid overfitting.
We can also use cross-validation to tune the model and avoid
overfitting (performs well on the training data but not very well on
unseen data). This is done by dividing the data into training sets to
check if the model generalizes well to other data.
# create a train/test split
set.seed(123) # random number generator
train_index <- createDataPartition(model_covid_world_dat$total_deaths, p = 0.8, list = FALSE)
train_data <- model_covid_world_dat[train_index, ] # used to train the model
test_data <- model_covid_world_dat[-train_index, ] # used to test the model after it has been trained
# train the model on the training set
model_cv <- lm(total_deaths ~ total_cases + total_recovered + active_cases + population, data = train_data)
# predict on the test set
test_predictions <- predict(model_cv, newdata = test_data)
# calculate RMSE on the test set
rmse_cv <- sqrt(mean((test_predictions - test_data$total_deaths)^2))
print(paste("Test RMSE:", round(rmse_cv, 2)))
## [1] "Test RMSE: 0"
Fantastic! The RMSE for these training tests came out the same as the
previous one.
6) Visualization of Predictions vs. Actuals
Finally, let’s visualize how well our model’s predictions match the
actual total_deaths
# create a data frame with the actual and predicted values
comparison <- data.frame(
Actual = model_covid_world_dat$total_deaths,
Predicted = predictions
)
# plot the actual vs. predicted deaths
comparison |>
ggplot(aes(x = Actual, y = Predicted)) +
geom_point(color = "red") +
geom_abline(slope = 1, intercept = 0, linetype = "dashed") +
labs(title = "Actual vs. Predicted Total COVID-19 Deaths", x = "Actual Deaths", y = "Predicted Deaths") +
theme_minimal()

The above scatter plot demonstrates the model’s performance in its
prediction.
- Points represent the model’s predictions
- Dashed line represents the actual values (i.e. perfect
predictions)
The closer the points are to the dashed line, the better the model’s
performance. If the points are spread too far, the model may need
improvement.
It’s actually insane how perfect this model turned out. This also
took me quite a few hours to get down with the help of Stack Overflow
and ChatGPT so shout out to them.
Conclusion
All my thoughts and interpretations have been strewn across this
entire document so there isn’t much for me to share here other than the
point that there is much to be learned from what might seem like even
the dullest of data. Data does not need to be super complex for it to be
analyzed. Creative thought process of how to look at the data and what
types of predictions you might be able to make with said data is just as
important to. COVID-19 offers great insight into how the world can
handle large medical crisis and if they did handle it well. That can be
said for many other forms of data so be on the look out and think
creatively! You’ll never know what you may find. I also didn’t sleep all
night in the process of writing this entire script so I’m calling it
good now, thank you for reading!
Return to Homepage
LS0tCnRpdGxlOiAiQW4gRXhwbG9yYXRvcnkgQW5hbHlzaXMgb2YgV29ybGR3aWRlIENPVklELTE5IENhc2VzIGFuZCBEZWF0aHMiCmRhdGU6ICJEZWNlbWJlciA1LCAyMDI0IgpvdXRwdXQ6IAogICAgaHRtbF9kb2N1bWVudDoKICAgICAgICB0aGVtZTogcGFwZXIKICAgICAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICAgICAgdG9jOiB0cnVlCiAgICAgICAgdG9jX2Zsb2F0OgogICAgICAgICAgICBjb2xsYXBzZWQ6IHRydWUKICAgICAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlCiAgICAgICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgICAgIGRmX3ByaW50OiBrYWJsZQogICAgICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgICAgIG1vZGU6IHNlbGZjb250YWluZWQKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZSA9IEZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIGNhY2hlID0gVFJVRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UpCmBgYAoKW1JldHVybiB0byBIb21lcGFnZV0oLi4vaW5kZXguaHRtbCkKCiMgKipJbnRyb2R1Y3Rpb24qKgpJbiB0aGUgZm9sbG93aW5nIHJlcG9ydCwgSSB3aWxsIGJlIGludmVzdGlnYXRpbmcgYW5kIGV4YW1pbmluZyB0aGUgdW50b2xkIHN0b3J5IGJlaGluZCBzZWVtaW5nbHkgdHJhbnNwYXJlbnQgcmVjb3JkcyBwZXJ0YWluaW5nIHRvIHdvcmxkd2lkZSBDT1ZJRCBjYXNlcyBhbmQgZGVhdGggdG9sbHMuIFdoaWxlIHRoZSBkYXRhIGhhcyBhbHJlYWR5IGJlZW4gY2xlYW5lZCBhbmQgY29udGFpbnMgZmFpcmx5IHNpbXBsZSBpbmZvcm1hdGlvbiwgdGhpcyBwcm9qZWN0IGFpbXMgdG8gaW52ZXN0aWdhdGUgdGhlIGRpc3Bhcml0aWVzIGJldHdlZW4gY291bnRyaWVzLCB0aGVpciBDT1ZJRCBkZWF0aCB0b2xscywgQ09WSUQgcmVjb3ZlcnkgcmF0ZXMsIGFuZCB0aGUgY29ycmVsYXRpb24gYmV0d2VlbiB0aG9zZSBzdGF0aXN0aWNzIGFuZCB0aGVpciBmaW5hbmNpYWwgc3RhbmRpbmcgYW5kIHBvcHVsYXRpb24gc2l6ZS4gSW4gc2ltcGxlciB0ZXJtcywgZG9lcyBhIGNvdW50cnkgaGF2aW5nIGEgaGlnaCBkZWF0aCB0b2xsIGluaGVyZW50bHkgaW1wbHkgdGhhdCB0aGV5IGhhbmRsZWQgdGhlIG91dGJyZWFrIHdvcnNlIHRoYW4gYW5vdGhlcj8gV2hhdCBkb2VzIHRoZSB0b3RhbCBudW1iZXIgb2YgY2FzZXMgaW4gcmVsYXRpb24gdG8gdGhlIG51bWJlciBvZiByZWNvdmVyZWQgcGF0aWVudHMgYW5kIGRlYXRocyB0ZWxsIHVzIGFib3V0IHRoYXQgbmF0aW9uJ3MgcGFuZGVtaWMgcmVzcG9uc2U/IERpZCBhY3RpdmUgcGFydGljaXBhbnRzIGluIENPVklEIHRlc3RzIGFjdHVhbGx5IGhhdmUgYW55IG5vdGljYWJsZSBhZmZlY3Qgb24gdG90YWwgbnVtYmVyIG9mIGNhc2VzIGFuZCBpbiB0dXJuLCBkZWF0aHM/IFRoZXNlIGFyZSBqdXN0IHNvbWUgb2YgdGhlIHF1ZXN0aW9ucyBJIGhvcGUgdG8gZXhwbG9yZSBpbiB0aGlzIHdyaXRpbmcuIAoKIyAqKkJhY2tncm91bmQqKgpUaGlzIHByb2plY3Qgd2FzIGluc3BpcmVkIGluIHBhcnQgYnkgbXkgcHJldmlvdXMgcmVzZWFyY2ggb24gbm9uLXN1YnN0YW5jZSB1c2UgZGlzb3JkZXIgdHJlYXRtZW50IHNlcnZpY2VzIG9mZmVyZWQgaW4gQmFsdGltb3JlLCBNRCwgd2hpY2ggcHJpbWFyaWx5IGNvbnNpc3RlZCBvZiBDT1ZJRC1yZWxhdGVkIHNlcnZpY2VzLiBJdCB3YXMgYWxzbyBpbnNwaXJlZCBieSBnZW5lcmFsIGhhcHBlbiBzdGFuY2U6IEkgZm91bmQgYSB2ZXJ5IG5pY2UgZGF0YSBzZXQgb24gS2FnZ2xlIGFuZCBmZWx0IGl0IGNvdWxkIGJlIGFuIGludGVyZXN0aW5nIHRha2Ugb24gYSBzZWVtaW5nbHkgZHVsbCBkYXRhIHNldC4gQXMgbWVudGlvbmVkLCB0aGlzIGRhdGEgc2V0IHdhcyBmb3VuZCBbaGVyZV0oaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9kYXRhc2V0cy90aGVtcml0eXVuamF5cGF0aGFrL2NvdmlkLWNhc2VzLWFuZC1kZWF0aHMtd29ybGR3aWRlL2RhdGEpLCBhcyB1cGRhdGVkIDIgeWVhcnMgYWdvICgyMDIyKSBieSBNcml0eXVuamF5IFBhdGhhay4KClRoZSBkYXRhIHNldCBjb25zaXN0cyBvZiB2YXJpb3VzIHJlcG9ydGVkIHN0YXRpc3RpY3MgcmVnYXJkaW5nIENvcm9uYXZpcnVzIChDT1ZJRC0xOSksIGFuIGluZmVjdGlvdXMgZGlzZWFzZSBjYXVzZWQgYnkgdGhlIFNBUlMtQ29WLTIgdmlydXMuIE1vc3Qgb2YgdGhvc2UgaW5mZWN0ZWQgYnkgdGhlIHZpcnVzIHdpbGwgZXhwZXJpZW5jZSBzb21lIG1pbGQgdG8gbW9kZXJhdGUgcmVzcGl0b3J5IHN5bXB0b21zIGFuZCByZWNvdmVyIHdpdGggcmVxdWlyaW5nIGFueSBwYXJ0aWN1bGFyIG1lZGljYWwgdHJlYXRtZW50LCBhbGJlaXQgdGFraW5nIGEgYml0IGxvbmdlciB0aGFuIG1vc3Qgb3RoZXIgZGlzZWFzZXMuIEhvd2V2ZXIsIHNvbWUgaW5kaXZpZHVhbHMgbWF5IGJlY29tZSBzZXJpb3VzbHkgaWxsIGFuZCByZXF1aXJlIG1lZGljYWwgYXR0ZW50aW9uIGFuZCBldmVuIGhvc3BpdGFsaXphdGlvbi4gVGhlIGVsZGVybHkgYW5kIHRob3NlIHdpdGggZXhpc3RpbmcgbWVkaWNhbCBjb25kaXRpb25zIHN1Y2ggYXMgY2FyZGlvdmFzY3VsYXIgZGlzZWFzZSwgY2hyb25pYyByZXNwaXJhdG9yeSBpbGxuZXNzLCBjYW5jZXIsIGFuZCBvdGhlciBzdWNoIGNvbmRpdGlvbnMgYXJlIG1vcmUgbGlrZWx5IHRvIGRldmVsb3Agc2VyaW91cyBzeW1wdG9tcy4gVGhhdCBiZWluZyBzYWlkLCAqKmFueW9uZSoqLCByZWdhcmRsZXNzIG9mIGFnZSBvciBtZWRpY2FsIGhpc3RvcnksIGNvdWxkIGdyb3cgc2VyaW91c2x5IGlsbCBhbmQgZGllIGFzIGEgcmVzdWx0IG9mIENPVklELTE5IGluZmVjdGlvbi4gCgpQcmV2ZW50aW9uIGlzIHRoZSBwcmltYXJ5IGRlZmVuc2UgZm9yIHRoZSBzcHJlYWQgb2YgdGhlIGRpc2Vhc2UuIFVuZGVyc3RhbmRpbmcgaG93IHRoZSB2aXJ1cyBzcHJlYWRzIGlzIGltcG9ydGFudCBhcyBwcm90ZWN0aW5nIG9uZXNlbGYgZnJvbSB0aGUgaWxsbmVzcyBpcyB0aGUgYmVzdCB3YXkgdG8gcHJvdGVjdCBvdGhlcnMgYXMgd2VsbC4gQXQgdGhlIHBlYWsgb2YgdGhlIHBhbmRlbWljLCBpdCB3YXMgYWR2aXNlZCB0aGF0IGluZGl2aWR1YWxzIHN0YXkgYXQgbGVhYXN0IDEgbWV0ZXIgYXBhcnQgZnJvbSBlYWNoLCB3ZWFyIHByb3Blcmx5IGZpdHRlZCBtZWRpY2FsLWdyYWRlIG1hc2tzLCBhbmQgd2FzaCBoYW5kcyBvciB1c2UgaGFuZCBzYW5pdGl6ZXIgZnJlcXVlbnRseS4gT25jZSB0aGUgdmFjY2luZXMgd2VyZSByZWxlYXNlZCwgaXQgd2FzIGFsc28gYWR2aXNlZCBieSB0aGUgQ0RDIHRvIGdldCB2YWNjaW5hdGVkIHRvIHN0YXR0IGJ1aWxkaW5nIHVwIGhlcmQgaW1tdW5pdHkuIAoKVGhlIHZpcnVzIGNhbiBzcHJlYWQgdGhyb3VnaCBsaXF1aWQgcGFydGljbGVzIGFzc29jaWF0ZWQgd2l0aCBjb3VnaGluZywgc25lZXppbmcsIHNwZWFraW5nLCBzaW5naW5nLCBvciBicmVhdGhpbmcuIFRoZSBvYnZpb3VzIGF2ZW51ZSBmb3IgdGhpcyBpcyB0aHJvdWdoIHRoZSBtb3V0aCBvciBub3NlIG9mIHRoZSBzaWNrIGluZGl2aWR1YWwuIFRoaXMgY2FuIGJlIHNwcmVhZCB0aHJvdWdoIGxhcmdlciBkcm9wbGV0cyB0byBzbWFsbGVyIGFlcm9zb2xzLiBJbmRpdmlkdWFscyBhcmUgZW5jb3VyYWdlZCB0byBwcmFjdGljZSBwcm9wZXIgcmVzcGlyYXRvcnkgZXRpcXVldHRlLCBzdGF5IGhvbWUgd2hlbiBzaWNrLCBhbmQgdG8gc2VsZi1pc29sYXRlIGF0IGxlYXN0IDEgd2VlayBhZnRlciBzeW1wb3RtbnMgaGF2ZSBjZWFzZWQuIAoKVGhpcyBkYXRhIGhhcyBiZWVuIGNvbXBpbGVkIHRocm91Z2ggcmVwb3J0cyBmcm9tIHRoZSBvbnNldCBvZiB0aGUgcGFuZGVtaWMgKDIwMjApIHVwIHVudGlsIGl0cyBsYXN0IHVwZGF0ZSBpbiAyMDIyLiBUaGUgZGF0YSBkb2VzIG5vdCBkaXN0aW5ndWlzaCBiZXR3ZWVuIHZhcmlhbnRzIG9mIHRoZSB2aXJ1cywgaG93ZXZlciwgaXQgZG9lcyBpbXBseSB0aGF0IGl0IGFjY291bnRzIGZvciB0aGUgb3JpZ2luYWwgdmFyaWFudCwgRGVsdGEsIE9taWNyb24gYW5kIGl0cyBzdWJ2YXJpYW50cyBvZiBCQS40IGFuZCBCQS41LiAKCiMgKipEYXRhKioKYGBge3IsIGVjaG8gPSBGQUxTRSwgcmVzdWx0cyA9ICdoaWRlJ30KIyBsb2FkIGFsbCBuZWNlc3NhcnkgbGlicmFyaWVzIApsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShicm9vbSkKbGlicmFyeShqYW5pdG9yKQpsaWJyYXJ5KHJlYWN0YWJsZSkKbGlicmFyeShjb3JycGxvdCkKbGlicmFyeShjYXJldCkKCiMgY29udmVydHMgYWxsIG51bWJlcnMgdG8gc3RhbmRhcmQgbm90YXRpb24gCm9wdGlvbnMoc2NpcGVuID0gOTk5KQoKIyByZWFkaW5nIGluIGthZ2dsZSBkYXRhIHNldCAKb2dfY292aWRfd29ybGRfZGF0IDwtIHJlYWQuY3N2KCJjb3ZpZF93b3JsZHdpZGUuY3N2IikKCmBgYApBcyBhbHJlYWR5IGRlc2NyaWJlZCwgdGhpcyBkYXRhIHNldCB3YXMgcmV0cmlldmVkIGZyb20gS2FnZ2xlIGFuZCBoYWQgYWxyZWFkeSBiZWVuICoqbW9zdGx5KiogY2xlYW5lZCBmb3IgYW5hbHlzaXMuIEhvd2V2ZXIsIHRoZXJlIGFyZSBzb21lIGNoYW5nZXMgSSB3YW50ZWQgdG8gbWFrZSB0byB0aGUgZGF0YSBzdHJ1Y3R1cmUsIG1pc3NpbmcgdmFsdWVzL2VtcHR5IHNwYWNlcywgYW5kIHN1cGVyZmx1b3VzIGNoYXJhY3RlcnMgZm91bmQgdGhyb3VnaG91dCB0aGUgZGF0YSBzZXQuIFRoZSBmb2xsb3dpbmcgY29kZSBhbmQgb3V0cHV0cyBkZW1vbnN0cmF0ZSB0aGUgY2hhbmdlcyBJJ3ZlIG1hZGUgdG8gYWxsb3cgZm9yIHNtb290aGVyIGRhdGEgYW5hbHlzaXM6IAoKYGBge3J9CiMgc2hvd3MgdGhlIG9yaWdpbmFsIGRhdGEgc3RydWN0dXJlIApzdHIob2dfY292aWRfd29ybGRfZGF0KQoKIyBjb252ZXJ0cyBhbGwgTi9BIGNociB2YWx1ZXMgdG8gYWN0dWFsIG1pc3NpbmcgdmFsdWVzIGFuZCBmaWxscyBpbiBlbXB0eSBzcGFjZXMgd2l0aCBtaXNzaW5nIHZhbHVlcyAKY292aWRfd29ybGRfZGF0IDwtIG9nX2NvdmlkX3dvcmxkX2RhdCB8PgogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMuY2hhcmFjdGVyKSwgfiBuYV9pZiguLCAiTi9BIikgfD4gbmFfaWYoIiIpKSkKCiMgY29udmVydCBjb2x1bW4gdGl0bGVzIHRvIHNuYWtlX2Nhc2UgCmNvdmlkX3dvcmxkX2RhdCA8LSBjbGVhbl9uYW1lcyhjb3ZpZF93b3JsZF9kYXQpCgojIHJlcGxhY2UgY29tbWFzIGluIGFsbCBjaHIgY29sdW1ucyB0byBhdm9pZCBpc3N1ZSB3aXRoIGNvbnZlcnNpb24gdG8gbnVtIGRhdGEgdHlwZSAKY292aWRfd29ybGRfZGF0IDwtIGNvdmlkX3dvcmxkX2RhdCB8PgogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMuY2hhcmFjdGVyKSwgfiBzdHJfcmVwbGFjZV9hbGwoLiwgIiwiLCAiIikpKQoKIyBjb252ZXJ0cyBkYXRhIHN0cnVjdHVyZSB0byBtb3JlIGFwcHJvcHJpYXRlIGRhdGEgdHlwZXMgCmNvdmlkX3dvcmxkX2RhdCA8LSBjb3ZpZF93b3JsZF9kYXQgfD4KICBtdXRhdGUoY291bnRyeSA9IGFzLmZhY3Rvcihjb3VudHJ5KSwKICAgICAgICAgYWNyb3NzKC1jKGNvdW50cnksIHNlcmlhbF9udW1iZXIpLCBhcy5udW1lcmljKSwgIyBjb252ZXJ0cyB0byBudW0gKG5vdCBpbnQpIHRvIGFjY291bnQgZm9yIG1hdGggdGhhdCByZXN1bHRzIGluIGRlY2ltYWxzIAogICAgICAgICB0b3RhbF90ZXN0X3Rha2VuID0gdG90YWxfdGVzdCkgfD4gIyBtYWtlcyBhIGNvbHVtbiBuYW1lIGNsZWFyZXIgdG8gdW5kZXJzdGFuZCAKICByZWxvY2F0ZSh0b3RhbF90ZXN0X3Rha2VuLCAuYmVmb3JlID0gcG9wdWxhdGlvbikgfD4KICBzZWxlY3QoLXRvdGFsX3Rlc3QpICMgcmVtb3ZlcyB0aGF0IG9yaWdpbmFsIGNvbHVtbiAKCiMgc2hvd3MgdGhlIHVwZGF0ZWQgZGF0YSBzdHJ1Y3R1cmUKc3RyKGNvdmlkX3dvcmxkX2RhdCkKCiMgZGVtb25zdHJhdGVzIGEgcG9ydGlvbiBvZiBvdXIgdXBkYXRlZCBkYXRhIHNldCAKaGVhZChjb3ZpZF93b3JsZF9kYXQpCgpgYGAKCkFzIG5vdGVkIGJlZm9yZSwgdGhlIGRhdGEgd2FzIGNvbGxlY3RlZCBhY2Nyb3NzIDIzMSBjb3VudHJpZXMgKDIzMSByb3dzKSBhbG9uZyB3aXRoIDYgcGFydGljdWxhciBzdGF0aXN0aWNzIGFzc29jaWF0ZWQgd2l0aCBlYWNoIGNvdW50cnkuIFRoZSBjb2x1bW5zIGFyZSBkZXNjcmliZWQgYXMgZm9sbG93czogCgotICoqc2VyaWFsX251bWJlcioqCiAgLSBhIHVuaXF1ZSBidXQgYXJiaXRyYXJ5IElEIGdpdmVuIHRvIGVhY2ggcm93IG9mIGRhdGEgdG8gc2VydmUgYXMgYSBrZXkgY29sdW1uIAogIAotICoqY291bnRyeSoqIAogIC0gdGhlIGNvdW50cnkgaW4gcXVlc3Rpb24gCiAgCi0gKip0b3RhbF9jYXNlcyoqCiAgLSB0b3RhbCBudW1iZXIgb2YgY2FzZXMgb2YgQ09WSUQtMTkgcmVwb3J0ZWQgYXQgdGhhdCBwb2ludCBpbiB0aGUgY291bnRyeSAKICAKLSAqKnRvdGFsX2RlYXRocyoqCiAgLSB0b3RhbCBudW1iZXIgb2YgZGVhdGhzIGZyb20gQ09WSUQtMTkgcmVwb3J0ZWQgYXQgdGhhdCBwb2ludCBpbiB0aGUgY291bnRyeSAKICAKLSAqKnRvdGFsX3JlY292ZXJlZCoqIAogIC0gdG90YWwgbnVtYmVyIG9mIHBhcnRpZW50cyB3aG8gcmVjb3ZlcmVkIGZyb20gQ09WSUQtMTkgYXQgdGhhdCBwb2ludCBpbiB0aGUgY291bnRyeSAKICAKLSAqKmFjdGl2ZV9jYXNlcyoqCiAgLSBjdXJyZW50bHkgb24tZ29pbmcgY2FzZXMgcmVwb3J0ZWQgYXQgdGhlIG1vbWVudCB0aGUgc3VydmV5IHdhcyBjb25kdWN0ZWQgCiAgCi0gKip0b3RhbF90ZXN0X3Rha2VuKioKICAtIHRvdGFsIG51bWJlciBvZiBDT1ZJRC0xOSB0ZXN0cyBhZG1pbmlzdGVyZWQgYW5kIHJlcG9ydGVkIGF0IHRoYXQgcG9pbnQgaW4gdGhlIGNvdW50cnkgCiAgCi0gKipwb3B1bGF0aW9uKioKICAtIHRvdGFsIG51bWJlciBvZiBwZW9wbGUgbGl2aW5nIGluIHRoZSBjb3VudHJ5IGF0IHRoYXQgcG9pbnQgb2YgdGhlIHN1cnZleQogIAojICoqRXhwbG9yYXRvcnkgQW5hbHlzaXMqKgojIyBEZWF0aCBSYXRlIHZzLiBUZXN0aW5nIFJhdGUgCkZpcnN0LCB3ZSB3aWxsIGJlIGludmVzdGlnYXRpbmcgdHdvIG1ldHJpY3MgdGhhdCBhcmVuJ3QgZ2l2ZW4gdG8gdXMgaW4gdGhlIGFjdHVhbCBkYXRhIHNldDogCgotIFRlc3QgcmF0ZSAKCi0gRGVhdGggcmF0ZSAKClRoZSAqKnRlc3QgcmF0ZSoqIHJlZmVycyB0byBob3cgZXh0ZW5zaXZlbHkgYSBjb3VudHJ5IGhhcyB0ZXN0ZWQgaXRzIHBvcHVsYXRpb24gZm9yIENPVklELTE5LiBBIGhpZ2hlciByYXRlIHdvdWxkIHN1Z2dlc3QgdGhhdCBhIGNvdW50cnkgaXMgY29uZHVjdGluZyBtb3JlIHRlc3RzIHJlbGF0aXZlIHRvIGl0cyBwb3B1bGF0aW9uIHNpemUsIHdoaWNoIGFsc28gaW1wbGllcyBtb3JlIHRob3JvdWdoIGVmZm9ydCBpbiBpZGVudGlmeWluZyBhbmQgdGFja2xpbmcgY2FzZXMuIENvbnZlcnNlbHksIGEgbG93ZXIgdGVzdCByYXRlIHN1Z2dlc3RzIHRoZSBvcHBvc2l0ZTogbGVzcyBvZiB0aGUgcG9wdWxhdGlvbiBpcyB0ZXN0ZWQgdGh1cyByZXN1bHRpbmcgaW4gbW9yZSBvdmVybG9va2VkIGNhc2VzLiAKCi0gKipGb3JtdWxhOioqIHRlc3RfcmF0ZSA9IHRvdGFsX3Rlc3RfdGFrZW4gLyBwb3B1bGF0aW9uCgpUaGUgKipkZWF0aCByYXRlKiogcmVwcmVzZW50cyB0aGUgZmF0YWxpdHkgcmF0ZSBvZiBDT1ZJRC0xOSBpbiBhIGNvdW50cnkgaW4gcmVsYXRpb24gdG8gdG90YWwgY2FzZXMuIEFzIHRoaXMgc2ltcGx5IGltcGxpZXMsIGl0IG9mZmVycyBhbiBpbmRpY2F0aW9uIG9mIG9mIGhvdyBkZWFkbHkgdGhlIGRpc2Vhc2UgaXMgaW4gdGhlIHBvcHVsYXRpb24gdGhhdCBpcyBjb250cmFjdGluZyBpdC4gQSBoaWdoZXIgZGVhdGggcmF0ZSBzdWdnZXN0cyBhIGxhcmdlciBwcm9wb3J0aW9uIG9mIGluZGl2aWR1YWxzIGFyZSBkeWluZyBpbiB0aGUgcG9wdWxhdGlvbjsgYSBsb3dlciByYXRlIHN1Z2dlc3RzIHRoZSBvcHBvc2l0ZS4gVGhlIGRlYXRoIHJhdGUgY2FuIGJlIGluZmx1ZW5jZWQgYnkgdmFyaWV0eSBvZiBmYWN0b3JzIGluY2x1ZGluZyBoZWFsdGhjYXJlIHF1YWxpdHksIHRoZSBhZ2UgZGlzdHJpYnV0aW9uIG9mIHRoZSBwb3B1bGF0aW9uLCBwcmVzZW5jZSBvZiB1bmRlcmx5aW5nIGhlYWx0aCBjb25kaXRpb25zLCBhbmQgZWZmZWN0aXZlbmVzcyBpbiBtZWRpY2FsIGludGVydmVudGlvbi4gSGlnaGVyIGRlYXRoIHJhdGVzIGRvbid0IGFsd2F5cyBtZWFuIHRoYXQgdGhlIHZpcnVzIGlzIG1vcmUgZGVhZGx5OyBpdCBjYW4gYWxzbyBiZSBhIHNpZ24gb2YgaW5zdWZmaWNpZW50IGhlYWx0aGNhcmUsIHRlc3RpbmcsIG9yIHJlcG9ydGluZy4gCgotICoqRm9ybXVsYToqKiBkZWF0aF9yYXRlID0gdG90YWxfZGVhdGhzIC8gdG90YWxfY2FzZXMKCkFzIHdlIGNhbiBzZWUgdGhpcyBjb3JyZWxhdGlvbiBwbG90dGVkIGJlbG93LiBFYWNoIGRvdCByZXByZXNlbnRzIGEgY291bnRyeS4gSG93ZXZlciwgdGhlIGZpcnN0IGdyYXBoIGlzIG9uZSBiYXNlZCBvbiB0aGUgc3RhbmRhcmQgbnVtZXJpY2FsIHZhbHVlcyBnaXZlbiBpbiB0aGUgZGF0YSBzZXQuIFRoaXMgcmVzdWx0cyBpbiBhIHBvb3IgZ3JhcGggYXMgdGhlIHBvaW50cyBhcmUgdG9vIGNsb3NlIHRvIGVhY2ggb3RoZXIgdG8gbWFrZSBhbnkgbWVhbmluZ2Z1bCBjb25jbHVzaW9ucy4gCgpgYGB7ciwgZWNobyA9IEZBTFNFfQojIHBvb3JseSByZXByZXNlbnRlZCBzY2F0dGVyIHBsb3Qgb2YgdGhlIGRlYXRoIHJhdGUgY29ycmVsYXRlZCB0byB0aGUgdGVzdCByYXRlIGJ5IHBvcHVsYXRpb24gKG5vIGxvZyBzY2FsZSkKY292aWRfd29ybGRfZGF0IHw+CiAgbXV0YXRlKGRlYXRoX3JhdGUgPSB0b3RhbF9kZWF0aHMgLyB0b3RhbF9jYXNlcywgCiAgICAgICAgIHRlc3RfcmF0ZSA9IHRvdGFsX3Rlc3RfdGFrZW4gLyBwb3B1bGF0aW9uKSB8PgogIGdncGxvdChhZXMoeCA9IHRlc3RfcmF0ZSwgeSA9IGRlYXRoX3JhdGUpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBjb3VudHJ5KSwgc2l6ZSA9IDMsIGFscGhhID0gMC42KSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAiYmxhY2siKSArCiAgbGFicyh0aXRsZSA9ICJEZWF0aCBSYXRlIHZzLiBUZXN0aW5nIFJhdGUiLAogICAgICAgeCA9ICJUZXN0cyBwZXIgUG9wdWxhdGlvbiIsIAogICAgICAgeSA9ICJEZWF0aCBSYXRlIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKYGBgCgpUaGUgZm9sbG93aW5nIGdyYXBoIGlzIGEgbW9yZSBlZmZlY3RpdmUgdmVyc2lvbiB0aGF0IGlzIGZpdCB0byBsb2cgc2NhbGUgdG8gc2VwYXJhdGUgdGhlIHBvaW50cyBvdXQgYW5kIGFsbG93IHVzIHRvIHZpc3VhbGl6ZSB0aGUgZGF0YSBtb3JlIGNsZWFybHk6IAoKYGBge3J9CiMgc2NhdHRlciBwbG90IHNob3dpbmcgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gYSBwb3B1bGF0aW9uJ3MgZGVhdGggcmF0ZSBhbmQgdGVzdGluZyByYXRlIHBlciBwb3B1bGF0aW9uIGZpdCBieSBsb2cgc2NhbGUgCmNvdmlkX3dvcmxkX2RhdCB8PgogIG11dGF0ZShkZWF0aF9yYXRlID0gdG90YWxfZGVhdGhzIC8gdG90YWxfY2FzZXMsIAogICAgICAgICB0ZXN0X3JhdGUgPSB0b3RhbF90ZXN0X3Rha2VuIC8gcG9wdWxhdGlvbikgfD4KICBnZ3Bsb3QoYWVzKHggPSB0ZXN0X3JhdGUsIHkgPSBkZWF0aF9yYXRlKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gY291bnRyeSksIHNpemUgPSAzLCBhbHBoYSA9IDAuNykgKwogIHNjYWxlX3hfbG9nMTAoKSArIHNjYWxlX3lfbG9nMTAoKSArICAjIGFkZGVkIGxvZyBzY2FsZSB0byBtb3JlIGVmZmVjdGl2ZSB2aXN1YWxpemF0aW9uIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG9yID0gImJsYWNrIikgKyAgIyBsaW5lIG9mIGJlc3QgZml0IChsaW5lYXIgbW9kZWwpCiAgbGFicyh0aXRsZSA9ICJEZWF0aCBSYXRlIHZzLiBUZXN0aW5nIFJhdGUgKExvZyBTY2FsZSkiLAogICAgICAgeCA9ICJUZXN0cyBwZXIgUG9wdWxhdGlvbiIsIAogICAgICAgeSA9ICJEZWF0aCBSYXRlIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKCmBgYAoKQXMgd2UgY2FuIG9idmlvdXNseSBzZWUsICoqdGhlIG1vcmUgdGVzdGluZyBhIGNvdW50cnkgaGFzIGFkbWluaXN0ZXJlZCB0byBpdHMgY2l0aXplbnMsIHRoZSBsb3dlciB0aGUgZGVhdGggcmF0ZS4qKgoKLSBIaWdoZXIgdGVzdGluZyA9IGxvd2VyIGRlYXRoIHJhdGUgCi0gTG93ZXIgdGVzdGluZyA9IGhpZ2hlciBkZWF0aCByYXRlIAoKIyMgSGlnaGVzdCBhbmQgTG93ZXN0IGRlYXRoLXRvLXRlc3QgUmF0aW8KSW4gY29uanVuY3Rpb24gdG8gdGhlIHByZXZpb3VzIGFuYWx5c2lzLCBJIGNhbGN1bGF0ZWQgd2hpY2ggY291bnRyaWVzIGhhdmUgdGhlICoqaGlnaGVzdCBkZWF0aC10by10ZXN0IHJhdGlvKiogKHRoZSBwb2ludHMgdGhhdCBhcmUgZnVydGhlc3QgdG8gdGhlIGxlZnQgYW5kIHVwIG9uIHRoZSBncmFwaCkuIFRoaXMgcmVwcmVzZW50cyB0aGUgaG93IG1hbnkgZGVhdGhzIG9jY3VyIHJlbGF0aXZlIHRvIHRoZSBudW1iZXIgb2YgdGVzdHMgY29uZHVjdGVkIGluIGVhY2ggY291bnRyeS4gCgpgYGB7cn0KIyBjYWxjdWxhdGlvbiBvZiB0aGUgY291bnRyaWVzIHdpdGggdGhlIGhpZ2hlc3QgZGVhdGgtdG8tdGVzdCByYXRpbyAKaGlnaF9kZWF0aF90b190ZXN0X3JhdGlvIDwtIGNvdmlkX3dvcmxkX2RhdCB8PgogIG11dGF0ZShkZWF0aF9yYXRlID0gdG90YWxfZGVhdGhzIC8gdG90YWxfY2FzZXMsIAogICAgICAgICB0ZXN0X3JhdGUgPSB0b3RhbF90ZXN0X3Rha2VuIC8gcG9wdWxhdGlvbiwKICAgICAgICAgZGVhdGhfdG9fdGVzdF9yYXRpbyA9IGRlYXRoX3JhdGUgLyB0ZXN0X3JhdGUpIHw+CiAgYXJyYW5nZShkZXNjKGRlYXRoX3RvX3Rlc3RfcmF0aW8pKSB8PgogIHNlbGVjdChjb3VudHJ5LCBkZWF0aF9yYXRlLCB0ZXN0X3JhdGUsIGRlYXRoX3RvX3Rlc3RfcmF0aW8pIHw+CiAgaGVhZCgxMCkgICMgc2hvd3MgdGhlIHRvcCAxMCBjb3VudHJpZXMKCmBgYAoKYGBge3IsIGVjaG8gPSBGQUxTRX0KIyB1c2luZyByZWFjdGFibGUgdG8gbWFrZSB0aGUgZGF0YSBwcmV0dGllcgpoaWdoX2RlYXRoX3RvX3Rlc3RfcmF0aW8gfD4KICByZWFjdGFibGUoY29sdW1ucyA9IGxpc3QoCiAgICBjb3VudHJ5ID0gY29sRGVmKG5hbWUgPSAiQ291bnRyeSIpLAogICAgZGVhdGhfcmF0ZSA9IGNvbERlZihuYW1lID0gIkRlYXRoIFJhdGUiLCBmb3JtYXQgPSBjb2xGb3JtYXQoZGlnaXRzID0gMikpLAogICAgdGVzdF9yYXRlID0gY29sRGVmKG5hbWUgPSAiVGVzdCBSYXRlIiwgZm9ybWF0ID0gY29sRm9ybWF0KGRpZ2l0cyA9IDIpKSwKICAgIGRlYXRoX3RvX3Rlc3RfcmF0aW8gPSBjb2xEZWYobmFtZSA9ICJEZWF0aC10by1UZXN0IFJhdGlvIiwgZm9ybWF0ID0gY29sRm9ybWF0KGRpZ2l0cyA9IDIpKQogICAgKSwKICAgIGRlZmF1bHRQYWdlU2l6ZSA9IDEwLAogICAgaGlnaGxpZ2h0ID0gVFJVRSwgCiAgICBzdHJpcGVkID0gVFJVRSwKICAgIGJvcmRlcmVkID0gVFJVRSwKICAgIHNob3dQYWdlU2l6ZU9wdGlvbnMgPSBUUlVFLAogICAgcGFnaW5hdGlvbiA9IFRSVUUpCgpgYGAKCk9uIHRoZSBvdGhlciBoYW5kLCB0aGUgY291bnRyaWVzIHdpdGggdGhlICoqbG93ZXN0IGRlYXRoLXRvLXRlc3QgcmF0aW8qKiBhcmUgbGlzdGVkIGJlbG93LiBTaW1pYXJseSwgdGhpcyBkZW5vdGVzIHdoaWNoIHBvaW50cyB3ZXJlIHRoZSBmdXJ0aGVzdCB0byB0aGUgcmlnaHQgYW5kIGRvd24gb24gdGhlIGdyYXBoLiAKCmBgYHtyfQojIGNhbGN1bGF0aW9uIG9mIHRoZSBjb3VudHJpZXMgd2l0aCB0aGUgbG93ZXN0IGRlYXRoLXRvLXRlc3QgcmF0aW8gCmxvd19kZWF0aF90b190ZXN0X3JhdGlvIDwtIGNvdmlkX3dvcmxkX2RhdCB8PgogIG11dGF0ZShkZWF0aF9yYXRlID0gdG90YWxfZGVhdGhzIC8gdG90YWxfY2FzZXMsIAogICAgICAgICB0ZXN0X3JhdGUgPSB0b3RhbF90ZXN0X3Rha2VuIC8gcG9wdWxhdGlvbiwKICAgICAgICAgZGVhdGhfdG9fdGVzdF9yYXRpbyA9IGRlYXRoX3JhdGUgLyB0ZXN0X3JhdGUpIHw+CiAgYXJyYW5nZShkZWF0aF90b190ZXN0X3JhdGlvKSB8PgogIHNlbGVjdChjb3VudHJ5LCBkZWF0aF9yYXRlLCB0ZXN0X3JhdGUsIGRlYXRoX3RvX3Rlc3RfcmF0aW8pIHw+CiAgaGVhZCgxMCkgICMgc2hvd3MgdGhlIHRvcCAxMCBjb3VudHJpZXMgCgpgYGAKCmBgYHtyLCBlY2hvID0gRkFMU0V9CiMgdXNpbmcgcmVhY3RhYmxlIHRvIG1ha2UgdGhlIGRhdGEgcHJldHRpZXIKbG93X2RlYXRoX3RvX3Rlc3RfcmF0aW8gfD4KICByZWFjdGFibGUoY29sdW1ucyA9IGxpc3QoCiAgICBjb3VudHJ5ID0gY29sRGVmKG5hbWUgPSAiQ291bnRyeSIpLAogICAgZGVhdGhfcmF0ZSA9IGNvbERlZihuYW1lID0gIkRlYXRoIFJhdGUiLCBmb3JtYXQgPSBjb2xGb3JtYXQoZGlnaXRzID0gMikpLAogICAgdGVzdF9yYXRlID0gY29sRGVmKG5hbWUgPSAiVGVzdCBSYXRlIiwgZm9ybWF0ID0gY29sRm9ybWF0KGRpZ2l0cyA9IDIpKSwKICAgIGRlYXRoX3RvX3Rlc3RfcmF0aW8gPSBjb2xEZWYobmFtZSA9ICJEZWF0aC10by1UZXN0IFJhdGlvIiwgZm9ybWF0ID0gY29sRm9ybWF0KGRpZ2l0cyA9IDIpKQogICAgKSwKICAgIGRlZmF1bHRQYWdlU2l6ZSA9IDEwLAogICAgaGlnaGxpZ2h0ID0gVFJVRSwKICAgIHN0cmlwZWQgPSBUUlVFLAogICAgYm9yZGVyZWQgPSBUUlVFLAogICAgc2hvd1BhZ2VTaXplT3B0aW9ucyA9IFRSVUUsCiAgICBwYWdpbmF0aW9uID0gVFJVRSkKCmBgYAoKIyMgVG9wIDEwIENvdW50cmllcyBieSBUb3RhbCBDYXNlcywgRGVhdGhzLCBhbmQgUmVjb3ZlcmllcwpUaGUgZm9sbG93aW5nIGdyYXBocyB2aXN1YWxpemUgdGhlIDEwIGNvdW50cmllcyB3aXRoIHRoZSAqKmhpZ2hlc3QgdG90YWwgb2YgY2FzZXMsIGRlYXRocywgYW5kIHJlY292ZXJpZXMqKi4gCgpJIHNlcGFyYXRlZCB0aGUgc3RhY2tlZCBiYXIgcGxvdHMgYmVjYXVzZSB0aGUgYWN0dWFsIGRpc3Bhcml0eSBiZXR3ZWVuIHRoZSB0b3RhbCBudW1iZXIgb2YgZGVhdGhzIGFuZCBkZWF0aHMgaXMgc28gaGlnaCB0aGF0IHlvdSBjYW4gaGFyZGx5IHNlZSBpdC4gV2hlbiB3ZSBpbmNsdWRlIHRoZSByZWNvdmVyaWVzLCB5b3UgY2Fubm90IGV2ZW4gc2VlIHRoZSBkZWF0aCBjb3VudCBmb3IgY291bnRyaWVzIGFzIGxhcmdlIGFzIHRoZSBVU0EuIFRoaXMgb2ZmZXJzIHVzIGEgcmVsYXRpdmUgY29tcGFyaXNvbiB0aGF0IGlzIGVhc3kgdG8gY29tcGFyZS4gTm93IHRoaXMgaXNuJ3QgbWVhbnQgdG8gZGlzY3JlZGl0IHRoZSBoZWF2eSB0b2xsIENPVklEIGhhZCBvbiB0aGUgZmlyc3Qtd29ybGQ7IGEgbWlsbGlvbiBwZW9wbGUgc3RpbGwgZGllZC4gSG93ZXZlciwgaXQgbXVzdCBiZSB1bmRlcnN0b29kIHRoYXQgMSwwMDAsMDAwIGlzIG9ubHkgMSUgb2YgdGhlIH4xMDAsMDAwLDAwMCByZWNvdmVyaWVzIG1hZGUgaW4gdGhlIFVTIGFsb25lIChhIHBvcHVsYXRpb24gb2Ygb3ZlciAzMDAsMDAwLDAwMCkuIFdpdGggdGhhdCBjb25zaWRlcmF0aW9uLCB3ZSBjYW4gY29tZSB0byBhcHByZWNpYXRlIHRoZSBleGNlbGxlbnQgcmVzcG9uc2UgdGhhdCB0aGUgVVNBIGFuZCBzaW1pbGFyIGNvdW50cmllcyBoYWQgdW5kZXIgdGhlIHByZXNzdXJlIG9mIG92ZXJmaWxsZWQgaG9zcGl0YWxzIGFuZCB1bmRlcnN0YWZmZWQgbWVkaWNhbCBwZXJzb25uZWwuIFRoaXMgaXMgZXNwZWNpYWxseSBub3RpY2FibGUgYnkgc2ltcGx5IGxvb2tpbmcgYXQgdGhlIGhlaWdodCBvZiB0aGUgYmFyIHBsb3RzIHdoaWNoIHNpbXBsaWVzIGEgaGVhdnkgYnVyZGVuIHNldCBvbnRvIHRoZSBjb3VudHJ5IGR1ZSB0byBDT1ZJRC0xOS4gVGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gcmVjb3ZlcnkgYW5kIGRlYXRoIHJhdGlvIGNhbiBpbmRpY2F0ZSBob3cgd2VsbCBhIGNvdW50cnkgd2FzIGFibGUgdG8gcmVzcG9uZCB0byB0aGUgY2FzZXMgYXBwZWFyaW5nIHdpdGhpbiB0aGVpciBib3JkZXJzLiAKCiAgLSBEdWUgdG8gdGhlIHNpemUgb2YgdGhlIGNvdW50LCBSIGZvcmNlcyB0aGUgY291bnQgdG8gYmUgaW4gc2NpZW50aWZpYyBub3RhdGlvbi4gS2VlcCBpbiBtaW5kIHRoYXQgdGhlIGxhcmdlc3QgY291bnQgdG8gdGhlIHJpZ2h0IGVuZCBvZiB0aGUgWC1heGlzIGFtb3VudHMgdG8gbGFyZ2VyIHRoYW4gMTAwLDAwMCwwMDAgcGVvcGxlLiAKCmBgYHtyfQojIHN0YWNrZWQgYmFyIHBsb3Qgb2YgYm90aCB0aGUgdG90YWwgY2FzZXMgYW5kIGRlYXRocyBmb3IgdGhlIGNvdW50cmllcyB3aXRoIHRoZSBtb3N0IENPVklELTE5IGNhc2VzIGFuZCBkZWF0aHMKY292aWRfd29ybGRfZGF0IHw+CiAgYXJyYW5nZShkZXNjKHRvdGFsX2Nhc2VzKSkgfD4KICBoZWFkKDEwKSB8PgogIGdncGxvdChhZXMoeCA9IHJlb3JkZXIoY291bnRyeSwgdG90YWxfY2FzZXMpKSkgKwogIGdlb21fYmFyKGFlcyh5ID0gdG90YWxfY2FzZXMsIGZpbGwgPSAiQ2FzZXMiKSwgc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKwogIGdlb21fYmFyKGFlcyh5ID0gdG90YWxfZGVhdGhzLCBmaWxsID0gIkRlYXRocyIpLCBzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgY29vcmRfZmxpcCgpICsKICBsYWJzKHRpdGxlID0gIlRvcCAxMCBDb3VudHJpZXMgd2l0aCB0aGUgTW9zdCBDT1ZJRC0xOSBDYXNlcyBhbmQgRGVhdGhzIiwgCiAgICAgICB4ID0gIkNvdW50cnkiLCAKICAgICAgIHkgPSAiQ291bnQiLCAKICAgICAgIGZpbGwgPSAiQ2F0ZWdvcnkiKSArCiAgdGhlbWVfbWluaW1hbCgpCgpgYGAKCmBgYHtyfQojIHN0YWNrZWQgYmFyIHBsb3Qgb2YgdG90YWwgY2FzZXMsIGRlYXRocywgYW5kIHJlY292ZXJlZCBwYXRpZW50cyBmb3IgdGhlIGNvdW50cmllcyB3aXRoIHRoZSBtb3N0IENPVklELTE5IGNhc2VzIGFuZCBkZWF0aHMKY292aWRfd29ybGRfZGF0IHw+CiAgYXJyYW5nZShkZXNjKHRvdGFsX2Nhc2VzKSkgfD4KICBoZWFkKDEwKSB8PgogIGdncGxvdChhZXMoeCA9IHJlb3JkZXIoY291bnRyeSwgdG90YWxfY2FzZXMpKSkgKyAKICBnZW9tX2JhcihhZXMoeSA9IHRvdGFsX2Nhc2VzLCBmaWxsID0gIkNhc2VzIiksIHN0YXQgPSAiaWRlbnRpdHkiKSArIAogIGdlb21fYmFyKGFlcyh5ID0gdG90YWxfZGVhdGhzLCBmaWxsID0gIkRlYXRocyIpLCBzdGF0ID0gImlkZW50aXR5IikgKyAKICBnZW9tX2JhcihhZXMoeSA9IHRvdGFsX3JlY292ZXJlZCwgZmlsbCA9ICJSZWNvdmVyZWQiKSwgc3RhdCA9ICJpZGVudGl0eSIpICsgCiAgY29vcmRfZmxpcCgpICsgCiAgbGFicyh0aXRsZSA9ICJUb3AgMTAgQ291bnRyaWVzIHdpdGggdGhlIE1vc3QgQ09WSUQtMTkgQ2FzZXMsIERlYXRocywgYW5kIFJlY292ZXJ5IiwgCiAgICAgICB4ID0gIkNvdW50cnkiLCAKICAgICAgIHkgPSAiQ291bnQiLCAKICAgICAgIGZpbGwgPSAiQ2F0ZWdvcnkiKSArIAogIHRoZW1lX21pbmltYWwoKQoKYGBgCgpUaGUgZm9sbG93aW5nIGdyYXBocyB2aXN1YWxpemUgdGhlIDEwIGNvdW50cmllcyB3aXRoIHRoZSAqKmxvd2VzdCB0b3RhbCBvZiBjYXNlcywgZGVhdGhzLCBhbmQgcmVjb3ZlcmllcyoqLiAKCk9uY2UgYWdhaW4sIEkgYWxzbyBzZXBhcmF0ZWQgdGhlIHBsb3RzIHRvIGFsbG93IGZvciBlYXNpZXIgdmlzdWFsaXphdGlvbi4gSG93ZXZlciwgYXMgeW91IG1heSBoYXZlIG5vdGljZWQsIHRoZSBjb3VudHJpZXMgd2l0aCB0aGUgbG93ZXN0IG51bWJlciBvZiBjYXNlcyBhbHNvIGhhcHBlbiB0byBoYXZlIG5leHQgdG8gbm8gcmVwb3J0ZWQgZGVhdGhzIGFzIGEgcmVzdWx0LiBXZSBhcmUgdGFsa2luZyBhYm91dCBjb3VudHJpZXMgc3VjaCBhcyBUdXZhbHUgd2l0aCBhIHBvcHVsYXRpb24gb2YgMTIsMDAwLiBUaG91Z2ggYSBsYXJnZSBwcm9wb3J0aW9uIG9mIHRoZWlyIHBvcHVsYXRpb24gd2FzIGFmZmVjdGVkIGJ5IHRoZSB2aXJ1cywgdGhlcmUgd2VyZSBubyByZXBvcnRlZCBkZWF0aHMuIFdpdGggdGhhdCBzYWlkLCB3ZSBzZWUgdGhhdCB0aGUgdG9wIHR3byBjb3VudHJpZXMgYWxzbyBoYWQgbmV4dCB0byBubyByZXBvcnRlZCByZWNvdmVyaWVzIChTYWludCBIZWxlbmEgaGFkIDIpLiAKCldoYXQgZG9lcyB0aGlzIHRlbGwgdXMgYWJvdXQgdGhvc2UgdHdvIGNvdW50cmllcz8gCgotIFRob3VnaCB0aGV5IG1heSBub3QgaGF2ZSBkb25lIGFuIGV4Y2VsbGVudCBqb2IgYXQgaXNvbGF0aW9uLCB0aG9zZSB3aG8gZ290IHNpY2sgMSkgcmVjZWl2ZWQgZ3JlYXQgdHJlYXRtZW50LCBvciAyKSBoYWQgdmVyeSBmZXcgYXQtcmlzayBhbmQgZWxkZXJseSBpbmRpdmlkdWFscyBzaWNrLgoKV2Ugc2VlIHRoZXNlIHZhbHVlcyBzaW1wbHkgZGVjcmVhc2Ugd2l0aCB0aGUgcG9wdWxhdGlvbiBpdHNlbGYuIFRva2VsYXUgaGFzIGEgcG9wdWxhdGlvbiBvZiBhIHRpbnkgMSwzNzggYW5kIGEgdG90YWwgb2YgNSByZXBvcnRlZCBjYXNlcyAob2Ygd2hpY2ggd2VyZSBhY3RpdmUgYXQgdGhlIHRpbWUgdGhpcyBzdXJ2ZXkgd2FzIHJlY29yZGVkKS4gSG93ZXZlciwgaXQgaXMgZGlmZmljdWx0IHRvIHF1YW50aWZ5IHJlc3VsdHMgc28gc21hbGwgc2VlaW5nIGFzIHRoZXNlIGNvdW50cmllcyBtYXkgc3RydWdnbGUgdG8gc2ltcGx5IHJlcG9ydCBhbiBhY2N1cmF0ZSBjb3VudCBvZiBhbGwgdGhlc2UgaW5zdGFuY2VzLiBXaG8ga25vd3MsIG1heWJlIHdlIHNob3VsZCBnbyBwYXkgYSB2aXNpdCB0byB0aGUgVmF0aWNhbiEKCmBgYHtyfQojIHN0YWNrZWQgYmFyIHBsb3Qgb2YgYm90aCB0aGUgdG90YWwgY2FzZXMgYW5kIGRlYXRocyBmb3IgdGhlIGNvdW50cmllcyB3aXRoIHRoZSBsZWFzdCBDT1ZJRC0xOSBjYXNlcyBhbmQgZGVhdGhzCmNvdmlkX3dvcmxkX2RhdCB8PgogIGFycmFuZ2UodG90YWxfY2FzZXMpIHw+CiAgaGVhZCgxMCkgfD4KICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKGNvdW50cnksIHRvdGFsX2Nhc2VzKSkpICsKICBnZW9tX2JhcihhZXMoeSA9IHRvdGFsX2Nhc2VzLCBmaWxsID0gIkNhc2VzIiksIHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsKICBnZW9tX2JhcihhZXMoeSA9IHRvdGFsX2RlYXRocywgZmlsbCA9ICJEZWF0aHMiKSwgc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKwogIGNvb3JkX2ZsaXAoKSArCiAgbGFicyh0aXRsZSA9ICJUb3AgMTAgQ291bnRyaWVzIHdpdGggdGhlIExlYXN0IENPVklELTE5IENhc2VzIGFuZCBEZWF0aHMiLCAKICAgICAgIHggPSAiQ291bnRyeSIsIAogICAgICAgeSA9ICJDb3VudCIsIAogICAgICAgZmlsbCA9ICJDYXRlZ29yeSIpICsKICB0aGVtZV9taW5pbWFsKCkKCmBgYApgYGB7cn0KIyBzdGFja2VkIGJhciBwbG90IG9mIHRvdGFsIGNhc2VzLCBkZWF0aHMsIGFuZCByZWNvdmVyZWQgcGF0aWVudHMgZm9yIHRoZSBjb3VudHJpZXMgd2l0aCB0aGUgbGVhc3QgQ09WSUQtMTkgY2FzZXMgYW5kIGRlYXRocwpjb3ZpZF93b3JsZF9kYXQgfD4KICBhcnJhbmdlKHRvdGFsX2Nhc2VzKSB8PgogIGhlYWQoMTApIHw+CiAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihjb3VudHJ5LCB0b3RhbF9jYXNlcykpKSArIAogIGdlb21fYmFyKGFlcyh5ID0gdG90YWxfY2FzZXMsIGZpbGwgPSAiQ2FzZXMiKSwgc3RhdCA9ICJpZGVudGl0eSIpICsgCiAgZ2VvbV9iYXIoYWVzKHkgPSB0b3RhbF9kZWF0aHMsIGZpbGwgPSAiRGVhdGhzIiksIHN0YXQgPSAiaWRlbnRpdHkiKSArIAogIGdlb21fYmFyKGFlcyh5ID0gdG90YWxfcmVjb3ZlcmVkLCBmaWxsID0gIlJlY292ZXJlZCIpLCBzdGF0ID0gImlkZW50aXR5IikgKyAKICBjb29yZF9mbGlwKCkgKyAKICBsYWJzKHRpdGxlID0gIlRvcCAxMCBDb3VudHJpZXMgd2l0aCB0aGUgTGVhc3QgQ09WSUQtMTkgQ2FzZXMsIERlYXRocywgYW5kIFJlY292ZXJ5IiwgCiAgICAgICB4ID0gIkNvdW50cnkiLCAKICAgICAgIHkgPSAiQ291bnQiLCAKICAgICAgIGZpbGwgPSAiQ2F0ZWdvcnkiKSArIAogIHRoZW1lX21pbmltYWwoKQoKYGBgCgojIyBWaXN1YWxpemluZyBDb3JyZWxhdGlvbnMgYmV0d2VlbiBLZXkgTWV0cmljcyAKVGhlIGZvbGxvd2luZyBhbmFseXNpcyBpcyBhIGJpdCBkaWZmZXJlbnQgdGhhbiB3aGF0IEknbSB1c2VkIHRvIGFuZCBJIGRvIHRoaW5rIGl0IGhhcyB0aGUgcG90ZW50aWFsIG9mIGJlaW5nIGEgYml0IGluYWNjdXJhdGUsIG9yIG1vcmUgbGlrZSBkZWNlaXZpbmcuIEEgY29ycmVsYXRpb24gbWF0cml4IGlzIGEgdGFibGUgdGhhdCBzaG93cyB0aGUgY29ycmVsYXRpb24gY29lZmZpY2llbnRzIGJldHdlZW4gbWFueSB2YXJpYWJsZXMuIEVhY2ggY2VsbCB3aXRoaW4gdGhlIHRhYmxlIGRpc3BsYXlzIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIDIgdmFyaWFibGVzLCByYW5naW5nIGZyb20gLTEgdG8gMS4gVGhlc2UgY29lZmZpY2llbnRzIGluZGljYXRlIHRoZSBzdHJlbmd0aCBhbmQgZGlyZWN0aW9uIG9mIGEgbGluZWFyIHJlbGF0aW9uIGJldHdlZW4gdHdvIHZhcmlhYmxlcy4gCgpIb3cgZG8gd2UgcmVhZCB0aGUgbWF0cml4PyAKCi0gKzE6IFBlcmZlY3QgcG9zaXRpdmUgY29ycmVsYXRpb24gKGJvdGggdmFyaWFibGVzIG1vdmUgaW4gdGhlIHNhbWUgZGlyZWN0aW9uKQogIC0gQXMgb25lIHZhcmlhYmxlIGluY3JlYXNlLCB0aGUgb3RoZXIgaW5jcmVhc2VzIAotIC0xOiBQZXJmZWN0IG5lZ2F0aXZlIGNvcnJlbGF0aW9uICh2YXJpYWJsZXMgbW92ZSBpbiBvcHBvc2l0ZSBkaXJlY3Rpb25zKQogIC0gQXMgb25lIHZhcmlhYmxlIGRlY3JlYXNlcywgdGhlIG90aGVyIGRlY3JlYXNlcyAKLSAwOiBObyBsaW5lYXIgY29ycmVsYXRpb24gKG5vIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSB2YXJpYWJsZXMpCiAgLSBObyBwcmVkaWN0YWJsZSBsaW5lYXIgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHZhcmlhYmxlcyAKCldpdGggdGhhdCBpbiBtaW5kLCBJIHNlZSBubyByZWFzb24gdG8gcmVhbGx5IGV4cGxhaW4gdGhlIGNvcnJlbGF0aW9ucyBpbiB3b3JkcyB3aGVuIHRoZSBtYXRyaXggZG9lcyBhIGJldHRlciBqb2IgYXQgZG9pbmcgc28uIAoKYGBge3J9CiMgY2FsY3VsYXRlIHRoZSBjb3JyZWxhdGlvbiBtYXRyaXgKY29ycl9tYXRyaXggPC0gY292aWRfd29ybGRfZGF0IHw+CiAgc2VsZWN0KHRvdGFsX2Nhc2VzLCB0b3RhbF9kZWF0aHMsIHRvdGFsX3JlY292ZXJlZCwgYWN0aXZlX2Nhc2VzLCB0b3RhbF90ZXN0X3Rha2VuLCBwb3B1bGF0aW9uKSB8PgogIG5hLm9taXQoKSB8PiAjIHJlbW92ZSBOQXMgdG8gYXZvaWQgY29uZmxpY3QgCiAgY29yKCkKCiMgY3JlYXRlIHRoZSBjb3JyZWxhdGlvbiBwbG90IHdpdGggaW1wcm92ZWQgbGFiZWxzCmNvcnJfbWF0cml4IHw+CiAgY29ycnBsb3QobWV0aG9kID0gImNpcmNsZSIsIAogICAgICAgICAgIHR5cGUgPSAidXBwZXIiLCAKICAgICAgICAgICB0bC5jb2wgPSAiYmxhY2siLAogICAgICAgICAgIHRsLnNydCA9IDQ1LCAgICAgICAgICAgICAgICAKICAgICAgICAgICB0bC5jZXggPSAwLjgsICAgICAgICAgICAgICAgCiAgICAgICAgICAgbWFyID0gYygwLDAsMSwwKSwgICAgICAgICAgIAogICAgICAgICAgIGFkZENvZWYuY29sID0gImJsYWNrIiwgICAgICAKICAgICAgICAgICBudW1iZXIuY2V4ID0gMC43LCAgICAgICAgICAgCiAgICAgICAgICAgZGlhZyA9IEZBTFNFKQoKYGBgCgojICoqUHJlZGljdGl2ZSBNb2RlbGluZyoqCkFmdGVyIGhhdmluZyB2aWV3ZWQgYW5kIGludGVycHJldGVkIGRpZmZlcmVudCBzdGF0aXN0aWNhbCBtZWFzdXJlcyBvZiB0aGUgQ09WSUQgZGF0YSwgSSBmZWVsIGl0IHdvdWxkIGJlIGJlc3Qgc2VydmVkIGlmIHdlIGF0dGVtcHQgdG8gdXNlIHdoYXQgd2UgbGVhcm5lZCBmcm9tIHRoZSBjb3JyZWxhdGlvbnMgYmV0d2VlbiB2YXJpYWJsZXMgdG8gdHJ5IHRvIHByZWRpY3QgdGhlIG1vc3QgaW1wb3J0YW50IG1ldHJpYyBpbiB0aGVzZSBzdXJ2ZXlzOiAqKnRvdGFsIGRlYXRocyoqLgoKVGhlIGZvbGxvd2luZyBjb25zaXN0cyBvZiB0aGUgcGFpbnN0YWtpbmcgc3RlcHMgdG8gcHJvZHVjZSBhIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIGFuZCBtYWtlIHByZWRpY3Rpb25zIG9uIHRoZSB0b3RhbCBudW1iZXIgb2YgZGVhdGhzIGZvdW5kIGluIHRoaXMgZGF0YSBzZXQuIAoKIyMgMSkgUHJlcHJvY2Vzc2luZyB0aGUgRGF0YSAKQmVmb3JlIGJ1aWxkaW5nIGEgbW9kZWwsIGl0IGlzIGJlc3QgdG8gcHJlcHJvY2VzcyB0aGUgZGF0YSBpbiBvcmRlciB0byBjbGVhciBvdXQgYW55IG1pc3NpbmcgdmFsdWVzIGFuZCBjcmVhdGluZyBhbnkgcmVsZXZhbnQgZmVhdHVyZXMgd2UgbWF5IG5lZWQgdG8gYWxsb3cgZm9yIG1vcmUgc3BlY2lmaWMgbW9kZWxpbmcuIEluIHRoaXMgY2FzZTogCgotIGRlYXRoc19wZXJfbWlsbGlvbgogIC0gdGVsbHMgdXMgaG93IG1hbnkgZGVhdGhzIHBlciBtaWxsaW9uIHBlb3BsZSBpbiBhIGNvdW50cnkgCi0gcmVjb3ZlcnlfcmF0ZSAKICAtIHByb3BvcnRpb24gb2YgcmVjb3ZlcmVkIGNhc2VzIGNvbXBhcmVkIHRvIHRvdGFsIGNhc2VzIHdoaWNoIG1heSBpbmRpY2F0ZSBoZWFsdGhjYXJlIGVmZmVjdGl2ZW5lc3MgCi0gYWN0aXZlX2Nhc2VzX3JhdGlvIAogIC0gcHJvcG9ydGlvbiBvZiBhY3RpdmUgY2FzZXMgdG8gdG90YWwgY2FzZXM7IGEgaGlnaGVyIG51bWJlciBjb3VsZCBtZWFuIGEgbW9yZSBzZXJpb3VzIHNpdHVhdGlvbiAKCmBgYHtyLCByZXN1bHRzID0gJ2hpZGUnfQojIHByZXBhcmluZyB0aGUgZGF0YSAKbW9kZWxfY292aWRfd29ybGRfZGF0IDwtIGNvdmlkX3dvcmxkX2RhdCB8PgogIG11dGF0ZSgKICAgIGRlYXRoc19wZXJfbWlsbGlvbiA9IHRvdGFsX2RlYXRocyAvIChwb3B1bGF0aW9uIC8gMWU2KSwgIyBkZWF0aHMgcGVyIG1pbGxpb24KICAgIHJlY292ZXJ5X3JhdGUgPSB0b3RhbF9yZWNvdmVyZWQgLyB0b3RhbF9jYXNlcywgIyByZWNvdmVyeSByYXRlCiAgICBhY3RpdmVfY2FzZXNfcmF0aW8gPSBhY3RpdmVfY2FzZXMgLyB0b3RhbF9jYXNlcyAjIGFjdGl2ZSBjYXNlcyByYXRpbwogICkgfD4KICBuYS5vbWl0KCkgIyByZW1vdmUgcm93cyB3aXRoIE5BIHZhbHVlcyB0byBhdm9pZCBjb25mbGljdHMgCgpgYGAKClRvIGF2b2lkIHJlZHVuZGFuY3kgYW5kIGNsdXR0ZXIsIEkgd2lsbCBub3QgYmUgaW5jbHVkaW5nIGFueSBvdXRwdXQsIGp1c3QgdGhlIGNvZGUgYWJvdmUuIAoKIyMgMikgVHJhaW5pbmcgdGhlIExpbmVhciBSZWdyZXNzaW9uIE1vZGVsIApXZSB3aWxsIG5vdyBidWlsZCBhIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIHRvIHByZWRpY3QgdG90YWxfZGVhdGhzIGJhc2VkIG9uIHRoZSBhYm92ZSBmZWF0dXJlcy4gVGhpcyBsaW5lYXIgcmVncmVzc2lvbiBzaG91bGQgaGVscCB1cyB1bmRlcnN0YW5kIHRoZSByZWxhdGlvbiBiZXR3ZWVuIHRoZSByZXNwb25zZSAodG90YWxfZGVhdGhzKSBhbmQgcHJlZGljdG9yIHZhbHVlcyAoZXZlcnl0aGluZyBlbHNlIHdlIG1hZGUpLiAKCmBgYHtyfQojIHRyYWluIGEgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgdG8gcHJlZGljdCB0b3RhbCBkZWF0aHMKbW9kZWwgPC0gbG0odG90YWxfZGVhdGhzIH4gdG90YWxfY2FzZXMgKyB0b3RhbF9yZWNvdmVyZWQgKyBhY3RpdmVfY2FzZXMgKyBwb3B1bGF0aW9uLCBkYXRhID0gbW9kZWxfY292aWRfd29ybGRfZGF0KQoKIyB2aWV3IG1vZGVsIHN1bW1hcnkKc3VtbWFyeShtb2RlbCkKCmBgYAoKVGhlIG91dHB1dCBzdW1tYXJ5IG9mIHRoZSBtb2RlbCB0ZWxscyB1czogCgotIENvZWZmaWNpZW50cyAKICAtIFRlbGwgdXMgaG93IG11Y2ggZWFjaCB2YXJpYWJsZSBlZmZlY3RzIHRoZSByZXNwb25zZSB2YXJpYWJsZSAodG90YWxfZGVhdGhzKQogICAgLSBFeGFtcGxlOiBpZiB0b3RhbF9jYXNlcyBoYXMgYSBjb2VmZmljaWVudCBvZiAwLjA1LCBpdCBtZWFucyBmb3IgZXZlcnkgMSBpbmNyZWFzZSBpbiB0b3RhbF9jYXNlcywgdG90YWxfZGVhdGhzIHdpbGwgaW5jcmVhc2UgYnkgMC4wNQoKLSBQLXZhbHVlIAogIC0gVGVsbHMgdXMgaWYgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGEgcHJlZGljdG9yIGFuZCBhIHRhcmdldCBpcyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50CiAgICAtIFZhbHVlcyBsb3dlciB0aGFuIDAuMDUgdHlwaWNhbGx5IG1lYW4gdGhlIHByZWRpY3RvciBpcyBzaWduaWZpY2FudCAKICAgIAotIFItc3F1YXJlZAogIC0gTWVhc3VyZXMgaG93IHdlbGwgdGhlIG1vZGVsIGZpdHMgdGhlIGRhdGEKICAgIC0gQW4gUi1zcXVhcmVkIHZhbHVlIGNsb3NlciB0byAxIG1lYW5zIHRoZSBtb2RlbCBleHBsYWlucyBtb3N0IG9mIHRoZSB2YXJpYWJpbGl0eSBpbiB0b3RhbF9kZWF0aHMgCgojIyAzKSBNb2RlbCBFdmFsdWF0aW9uIApXZSB3aWxsIG5vdyBwcm9jZWVkIHRvIGV2YWx1YXRlIHRoZSBtb2RlbCBhY2NvcmRpbmcgdG8gUm9vdCBNZWFuIFNxdWFyZWQgRXJyb3IgKFJNU0UpLiBUaGlzIHRlbGxzIHVzLCBvbiBhdmVyYWdlLCBob3cgZmFyIG9mZiBvdXIgcHJlZGljdGlvbnMgYXJlLiAKCmBgYHtyfQojIHByZWRpY3QgdG90YWxfZGVhdGhzIHVzaW5nIHRoZSB0cmFpbmVkIG1vZGVsCnByZWRpY3Rpb25zIDwtIHByZWRpY3QobW9kZWwsIG5ld2RhdGEgPSBtb2RlbF9jb3ZpZF93b3JsZF9kYXQpCgojIGNhbGN1bGF0ZSBSTVNFIChSb290IE1lYW4gU3F1YXJlZCBFcnJvcikKcm1zZSA8LSBzcXJ0KG1lYW4oKHByZWRpY3Rpb25zIC0gbW9kZWxfY292aWRfd29ybGRfZGF0JHRvdGFsX2RlYXRocyleMikpCnByaW50KHBhc3RlKCJSTVNFOiIsIHJvdW5kKHJtc2UsIDIpKSkKCmBgYAoKQSBsb3dlciBSTVNFIGluZGljYXRlcyBiZXR0ZXIgbW9kZWwgcGVyZm9ybWFuY2UuIEZvciBleGFtcGxlLCBhbiBSTVNFIG9mIDUwMCBtZWFucyB0aGF0LCBvbiBhdmVyYWdlLCB0aGUgbW9kZWwncyBwcmVkaWN0aW9ucyBhcmUgb2ZmIGJ5IDUwMCBkZWF0aHMuIAoKIyMgNCkgTW9kZWwgSW50ZXJwcmVhdGlvbiAKVGhlIGNvZWZmaWNpZW50cyB3aWxsIHVzIGhvdyBzdHJvbmdseSBlYWNoIHByZWRpY3RvciB2YXJpYWJsZSBhZmZlY3RzIHRvdGFsX2RlYXRocy4KCmBgYHtyfQojIHZpZXcgdGhlIGNvZWZmaWNpZW50cwpjb2VmKG1vZGVsKQoKYGBgCgpGb3IgZXhhbXBsZSwgaWYgdG90YWxfY2FzZXMgaGFzIGEgbGFyZ2UgcG9zaXRpdmUgY29lZmZpY2llbnQsIHRoaXMgbWVhbnMgdGhhdCBhcyB0aGUgbnVtYmVyIG9mIGNhc2VzIGluY3JlYXNlcywgc28gZG9lcyB0aGUgbnVtYmVyIG9mIGRlYXRocy4gSWYgcG9wdWxhdGlvbiBoYXMgYSBuZWdhdGl2ZSBjb2VmZmljaWVudCwgdGhpcyBjb3VsZCBzdWdnZXN0IHRoYXQgY291bnRyaWVzIHdpdGggbGFyZ2VyIHBvcHVsYXRpb25zIGhhdmUgcmVsYXRpdmVseSBmZXdlciBkZWF0aHMgY29tcGFyZWQgdG8gc21hbGxlciBjb3VudHJpZXMsIGRlcGVuZGluZyBvbiBvdGhlciBmYWN0b3JzLgoKIyMgNSkgTW9kZWwgVHVuaW5nIApTb21ldGhpbmcgbWFueSBwZW9wbGUsIGluY2x1ZGluZyBteXNlbGYsIGRvbid0IGRvIGlzIGNyb3NzLXZhbGlkYXRpb24gdG8gdHVuZSBvdXIgbW9kZWwgYW5kIGF2b2lkIG92ZXJmaXR0aW5nLiAKCldlIGNhbiBhbHNvIHVzZSBjcm9zcy12YWxpZGF0aW9uIHRvIHR1bmUgdGhlIG1vZGVsIGFuZCBhdm9pZCBvdmVyZml0dGluZyAocGVyZm9ybXMgd2VsbCBvbiB0aGUgdHJhaW5pbmcgZGF0YSBidXQgbm90IHZlcnkgd2VsbCBvbiB1bnNlZW4gZGF0YSkuIFRoaXMgaXMgZG9uZSBieSBkaXZpZGluZyB0aGUgZGF0YSBpbnRvIHRyYWluaW5nIHNldHMgdG8gY2hlY2sgaWYgdGhlIG1vZGVsIGdlbmVyYWxpemVzIHdlbGwgdG8gb3RoZXIgZGF0YS4KCmBgYHtyfQojIGNyZWF0ZSBhIHRyYWluL3Rlc3Qgc3BsaXQKc2V0LnNlZWQoMTIzKSAjIHJhbmRvbSBudW1iZXIgZ2VuZXJhdG9yIAp0cmFpbl9pbmRleCA8LSBjcmVhdGVEYXRhUGFydGl0aW9uKG1vZGVsX2NvdmlkX3dvcmxkX2RhdCR0b3RhbF9kZWF0aHMsIHAgPSAwLjgsIGxpc3QgPSBGQUxTRSkKdHJhaW5fZGF0YSA8LSBtb2RlbF9jb3ZpZF93b3JsZF9kYXRbdHJhaW5faW5kZXgsIF0gIyB1c2VkIHRvIHRyYWluIHRoZSBtb2RlbCAKdGVzdF9kYXRhIDwtIG1vZGVsX2NvdmlkX3dvcmxkX2RhdFstdHJhaW5faW5kZXgsIF0gIyB1c2VkIHRvIHRlc3QgdGhlIG1vZGVsIGFmdGVyIGl0IGhhcyBiZWVuIHRyYWluZWQgCgojIHRyYWluIHRoZSBtb2RlbCBvbiB0aGUgdHJhaW5pbmcgc2V0Cm1vZGVsX2N2IDwtIGxtKHRvdGFsX2RlYXRocyB+IHRvdGFsX2Nhc2VzICsgdG90YWxfcmVjb3ZlcmVkICsgYWN0aXZlX2Nhc2VzICsgcG9wdWxhdGlvbiwgZGF0YSA9IHRyYWluX2RhdGEpCgojIHByZWRpY3Qgb24gdGhlIHRlc3Qgc2V0CnRlc3RfcHJlZGljdGlvbnMgPC0gcHJlZGljdChtb2RlbF9jdiwgbmV3ZGF0YSA9IHRlc3RfZGF0YSkKCiMgY2FsY3VsYXRlIFJNU0Ugb24gdGhlIHRlc3Qgc2V0CnJtc2VfY3YgPC0gc3FydChtZWFuKCh0ZXN0X3ByZWRpY3Rpb25zIC0gdGVzdF9kYXRhJHRvdGFsX2RlYXRocyleMikpCnByaW50KHBhc3RlKCJUZXN0IFJNU0U6Iiwgcm91bmQocm1zZV9jdiwgMikpKQoKYGBgCgpGYW50YXN0aWMhIFRoZSBSTVNFIGZvciB0aGVzZSB0cmFpbmluZyB0ZXN0cyBjYW1lIG91dCB0aGUgc2FtZSBhcyB0aGUgcHJldmlvdXMgb25lLiAKCiMjIDYpIFZpc3VhbGl6YXRpb24gb2YgUHJlZGljdGlvbnMgdnMuIEFjdHVhbHMKRmluYWxseSwgbGV0J3MgdmlzdWFsaXplIGhvdyB3ZWxsIG91ciBtb2RlbCdzIHByZWRpY3Rpb25zIG1hdGNoIHRoZSBhY3R1YWwgdG90YWxfZGVhdGhzCgpgYGB7cn0KIyBjcmVhdGUgYSBkYXRhIGZyYW1lIHdpdGggdGhlIGFjdHVhbCBhbmQgcHJlZGljdGVkIHZhbHVlcwpjb21wYXJpc29uIDwtIGRhdGEuZnJhbWUoCiAgQWN0dWFsID0gbW9kZWxfY292aWRfd29ybGRfZGF0JHRvdGFsX2RlYXRocywKICBQcmVkaWN0ZWQgPSBwcmVkaWN0aW9ucwopCgojIHBsb3QgdGhlIGFjdHVhbCB2cy4gcHJlZGljdGVkIGRlYXRocwpjb21wYXJpc29uIHw+CiAgZ2dwbG90KGFlcyh4ID0gQWN0dWFsLCB5ID0gUHJlZGljdGVkKSkgKwogIGdlb21fcG9pbnQoY29sb3IgPSAicmVkIikgKwogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGxhYnModGl0bGUgPSAiQWN0dWFsIHZzLiBQcmVkaWN0ZWQgVG90YWwgQ09WSUQtMTkgRGVhdGhzIiwgeCA9ICJBY3R1YWwgRGVhdGhzIiwgeSA9ICJQcmVkaWN0ZWQgRGVhdGhzIikgKwogIHRoZW1lX21pbmltYWwoKQoKYGBgCgpUaGUgYWJvdmUgc2NhdHRlciBwbG90IGRlbW9uc3RyYXRlcyB0aGUgbW9kZWwncyBwZXJmb3JtYW5jZSBpbiBpdHMgcHJlZGljdGlvbi4gCgotIFBvaW50cyByZXByZXNlbnQgdGhlIG1vZGVsJ3MgcHJlZGljdGlvbnMgCi0gRGFzaGVkIGxpbmUgcmVwcmVzZW50cyB0aGUgYWN0dWFsIHZhbHVlcyAoaS5lLiBwZXJmZWN0IHByZWRpY3Rpb25zKQoKVGhlIGNsb3NlciB0aGUgcG9pbnRzIGFyZSB0byB0aGUgZGFzaGVkIGxpbmUsIHRoZSBiZXR0ZXIgdGhlIG1vZGVsJ3MgcGVyZm9ybWFuY2UuIElmIHRoZSBwb2ludHMgYXJlIHNwcmVhZCB0b28gZmFyLCB0aGUgbW9kZWwgbWF5IG5lZWQgaW1wcm92ZW1lbnQuIAoKSXQncyBhY3R1YWxseSBpbnNhbmUgaG93IHBlcmZlY3QgdGhpcyBtb2RlbCB0dXJuZWQgb3V0LiBUaGlzIGFsc28gdG9vayBtZSBxdWl0ZSBhIGZldyBob3VycyB0byBnZXQgZG93biB3aXRoIHRoZSBoZWxwIG9mIFN0YWNrIE92ZXJmbG93IGFuZCBDaGF0R1BUIHNvIHNob3V0IG91dCB0byB0aGVtLiAKCiMgKipDb25jbHVzaW9uKiogCkFsbCBteSB0aG91Z2h0cyBhbmQgaW50ZXJwcmV0YXRpb25zIGhhdmUgYmVlbiBzdHJld24gYWNyb3NzIHRoaXMgZW50aXJlIGRvY3VtZW50IHNvIHRoZXJlIGlzbid0IG11Y2ggZm9yIG1lIHRvIHNoYXJlIGhlcmUgb3RoZXIgdGhhbiB0aGUgcG9pbnQgdGhhdCB0aGVyZSBpcyBtdWNoIHRvIGJlIGxlYXJuZWQgZnJvbSB3aGF0IG1pZ2h0IHNlZW0gbGlrZSBldmVuIHRoZSBkdWxsZXN0IG9mIGRhdGEuIERhdGEgZG9lcyBub3QgbmVlZCB0byBiZSBzdXBlciBjb21wbGV4IGZvciBpdCB0byBiZSBhbmFseXplZC4gQ3JlYXRpdmUgdGhvdWdodCBwcm9jZXNzIG9mIGhvdyB0byBsb29rIGF0IHRoZSBkYXRhIGFuZCB3aGF0IHR5cGVzIG9mIHByZWRpY3Rpb25zIHlvdSBtaWdodCBiZSBhYmxlIHRvIG1ha2Ugd2l0aCBzYWlkIGRhdGEgaXMganVzdCBhcyBpbXBvcnRhbnQgdG8uIENPVklELTE5IG9mZmVycyBncmVhdCBpbnNpZ2h0IGludG8gaG93IHRoZSB3b3JsZCBjYW4gaGFuZGxlIGxhcmdlIG1lZGljYWwgY3Jpc2lzIGFuZCBpZiB0aGV5IGRpZCBoYW5kbGUgaXQgd2VsbC4gVGhhdCBjYW4gYmUgc2FpZCBmb3IgbWFueSBvdGhlciBmb3JtcyBvZiBkYXRhIHNvIGJlIG9uIHRoZSBsb29rIG91dCBhbmQgdGhpbmsgY3JlYXRpdmVseSEgWW91J2xsIG5ldmVyIGtub3cgd2hhdCB5b3UgbWF5IGZpbmQuIEkgYWxzbyBkaWRuJ3Qgc2xlZXAgYWxsIG5pZ2h0IGluIHRoZSBwcm9jZXNzIG9mIHdyaXRpbmcgdGhpcyBlbnRpcmUgc2NyaXB0IHNvIEknbSBjYWxsaW5nIGl0IGdvb2Qgbm93LCB0aGFuayB5b3UgZm9yIHJlYWRpbmchIAoKW1JldHVybiB0byBIb21lcGFnZV0oLi4vaW5kZXguaHRtbCkK