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)
serial_number country total_cases total_deaths total_recovered active_cases total_test_taken population
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
    • the country in question
  • 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:

  • Test rate

  • Death rate

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