Exploratory Data Analysis
Dependencies
To complete our Data Analysis we’ll be using the tidyverse library. To visualize our data we will be using ggplot2, dplyr, maps and viridis. To get the weather based on latitude and longitude, we will be making an api call using weatherr. To get country based data such as population density, country code etc… we will be using WDI which is the World Development Indicators DataBank and the countrycode Library.
# Tidyverse
library(tidyverse)
# Graphing Library
library(ggplot2)
library(dplyr)
library(maps)
library(viridis)
#------------------
library(dygraphs)
library(xts)
library(tidyverse)
library(lubridate)
# Weather and Country Data
library(weatherr)
library(WDI)
library(countrycode)
Reading The Data
Let’s first go ahead and see what our data looks like by printing out first few rows
# Reading
covid_19 <- read_csv("03-17-2020.csv")
Parsed with column specification:
cols(
`Province/State` = col_character(),
`Country/Region` = col_character(),
`Last Update` = col_datetime(format = ""),
Confirmed = col_double(),
Deaths = col_double(),
Recovered = col_double(),
Latitude = col_double(),
Longitude = col_double()
)
names(covid_19)[1] <- "Province"
names(covid_19)[2] <- "Country"
head(covid_19)
By the looks of the data we have the following fields:
1. Province : Region in the country where the virus was reported
2. Country : Country where it was reported
3. Last Update : The time when the total count was reviewed onto the datatset
4. Confirmed: Total number of people affected by the virus
5. Deaths : Total number of deaths from the virus
6. Recovered : Total number of people that recovered after they have been affected
7. Latitute : Geo-logical location of the reported incident
8. Longtitude : Geo-logical location of the reported incident
Graphing
Now let’s try to visualize our data to get a broader view of the problem at hand. Firstly we’ll take a look at the total number of confirmed cases.
world <- map_data("world")
ggplot() +
geom_polygon(data = world, aes(x=long, y = lat, group = group), fill="grey", alpha=0.3) +
geom_point( data=covid_19, aes(x=covid_19$Longitude, y=covid_19$Latitude, size=covid_19$Confirmed, color=covid_19$Confirmed)) +
scale_color_viridis(trans="log") +
theme_void()+ coord_map()

By looking at the graph we can that the most number of cases reported to-date happen to be in China. We also see some cases being reported at sea, these are most probably ships which were traveling at the time.
world <- map_data("world")
ggplot() +
geom_polygon(data = world, aes(x=long, y = lat, group = group), fill="grey", alpha=0.3) +
geom_point( data=covid_19, aes(x=covid_19$Longitude, y=covid_19$Latitude, size=covid_19$Deaths, color=covid_19$Deaths)) +
scale_color_viridis(trans="log") +
theme_void()+ coord_map()

From the graph we can see that the most number of deaths happened in China and Italy. As compared to the number of confirmed cases this graph seems to be less dense which is a good sign.
world <- map_data("world")
ggplot() +
geom_polygon(data = world, aes(x=long, y = lat, group = group), fill="grey", alpha=0.3) +
geom_point( data=covid_19, aes(x=covid_19$Longitude, y=covid_19$Latitude, size=covid_19$Recovered, color=covid_19$Recovered)) +
scale_color_viridis(trans="log") +
theme_void()+ coord_map()

From this graph we see that most of the recovered cases happened again in China and Italy. With a number of recovered cases growing in North America.
Data Cleaning
Before we can begin to understand the data and effectively use it to do our analysis, we first need to do some data cleaning. We should group by country and we should get the weather for all of them. Population size will also be an important factor in our study, so well will also factor that in. We will not clean our data accordingly.
# Made a new data frame with a columns called temperature,then using the latitude and longitude got there respective weather by doing an api call to the weather station
data.frame(covid_19) -> country_data
country_data$Province = NULL
country_data$Temperature = c(0)
n = nrow(country_data)
for (i in 1:n){
weather = suppressWarnings( locationforecast(lat=country_data$Latitude[i], lon=country_data$Longitude[i]) )
temp = suppressWarnings(mean(weather$temperature))
country_data$Temperature[i] = temp
}
# Get the weather data
Weather_data = country_data
Weather_data$Latitude = NULL
Weather_data$Longitude = NULL
Weather_data %>%
group_by(Country) %>%
summarise(Confirmed_Cases = sum(Confirmed)) -> con
Weather_data %>%
group_by(Country) %>%
summarise(Death_Cases = sum(Deaths)) -> dea
Weather_data %>%
group_by(Country) %>%
summarise(Recovered_Cases = sum(Recovered)) -> rec
Weather_data %>%
group_by(Country) %>%
summarise(Mean_Temprature = mean(Temperature)) -> tem
Weather_data_country = data.frame(con$Country, con$Confirmed_Cases, dea$Death_Cases, rec$Recovered_Cases, tem$Mean_Temprature)
colnames(Weather_data_country) <- c("Country", "Confirmed Cases", "Death Cases", "Recovered Cases", "Average Temprature")
country = Weather_data_country$Country
countrycode(country, origin = 'country.name', destination = 'iso2c') -> Country_code
cbind(Country_code ,Weather_data_country) -> Weather_data_country
WDI(country = Weather_data_country$Country_code, indicator="SP.POP.TOTL",start=2018, end=2018) -> population
#
head(Weather_data_country)
merge(Weather_data_country, population, by.x = "Country_code", by.y = "iso2c") -> df
df$country = NULL
df$year = NULL
colnames(df)[7] = "Total Population"
head(df)
c_url = "https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_19-covid-Confirmed.csv"
d_url = "https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_19-covid-Deaths.csv"
r_url = "https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_19-covid-Recovered.csv"
# Reading in the Time Data-Set
confirmed_ts = read_delim(c_url, ",")
death_ts = read_delim(d_url, ",")
recover_ts = read_delim(r_url, ",")
# Confirmed Cases for dates
confirmed_ts %>%
pivot_longer("1/22/20":"3/21/20", names_to = "Dates", values_to = "Confirmed_Cases") -> confirmed_ts
# Death Cases for dates
death_ts %>%
pivot_longer("1/22/20":"3/21/20", names_to = "Dates", values_to = "Death_Cases") -> death_ts
# Recovered Cases for dates
recover_ts %>%
pivot_longer("1/22/20":"3/21/20", names_to = "Dates", values_to = "Recover_Cases") -> recover_ts
confirmed_ts %>%
group_by(Dates) %>%
summarise(Confirmed_Cases = sum(`Confirmed_Cases`))->cs
recover_ts %>%
group_by(Dates) %>%
summarise(Recover_Cases = sum(`Recover_Cases`)) -> rs
death_ts %>%
group_by(Dates) %>%
summarise(Death_Cases = sum(`Death_Cases`)) -> ds
merge(cs, rs, by.x = "Dates", by.y = "Dates") -> dfr
merge(dfr, ds, by.x = "Dates", by.y = "Dates" ) -> TotalCount_ByDate
Now that we have cleaned our data lets answer some questions.
Analysis
a. Which country has the most number of casualties ?
df %>%
group_by(Country) %>%
arrange(desc(`Confirmed Cases`, `Death Cases`, `Recovered Cases`)) -> conf_df
head(conf_df,4) -> dfmax
dfmax
As we can see China ranks the most amongs all of them, followed by Italy, Iran and Spain
b. Which country has the least number of casualties ?
df %>%
group_by(Country) %>%
arrange(`Confirmed Cases`, `Death Cases`, `Recovered Cases`) -> conf_df
head(conf_df,4) -> conf_df
conf_df
As we can see Republic of the Congo ranks the most among all of them, followed by Puerto Rico, Palestinian territory and Antigua and Barbuda
c. What is the general trend of the COVID-19 virus as the day’s progress?
Let us call the data we cleaned up above and show some of the rows
head(TotalCount_ByDate)
We see one categorical data called Dates and three Quantitative Data called Confirmed Cases, Recover Cases and Death Cases . However since we have a time series data, we thought it would be interesting to try using the xts library.
as.Date(TotalCount_ByDate$Dates,format="%m/%d/%y") -> o
data.frame(o, TotalCount_ByDate$Confirmed_Cases, TotalCount_ByDate$Death_Cases, TotalCount_ByDate$Recover_Cases) -> data
don <- xts(x = data, order.by = data$o)
names(don)[2] = "Confirmed Cases"
names(don)[3] = "Death Cases"
names(don)[4] = "Recovered Cases"
# Finally the plot
p <- dygraph(don) %>%
dyOptions(labelsUTC = TRUE, fillGraph=TRUE, fillAlpha=0.1, drawGrid = FALSE, colors = RColorBrewer::brewer.pal(3, "Set1")) %>%
dyRangeSelector() %>%
dyCrosshair(direction = "vertical") %>%
dyHighlight(highlightCircleSize = 5, highlightSeriesBackgroundAlpha = 0.2, hideOnMouseOut = FALSE) %>%
dyRoller(rollPeriod = 1)
p
From the graph we can see that there’s been a global sharp increase in the number of cases after March 12. The graph might possibly be following an exponential curve, but have yet to hit the surge. We also see that the number of confirmed cases are growing at a faster rate than Recovered and Death Cases.
d. Does Climate have an effect on the COVID-19 virus?
For the purpose of the analysis we want to see if the temperature has any affect on the COVID-19 virus. From question (a) we found out that the countries with the most number of confirmed cases is China and Italy. We start by taking the mean of the two temperatures as a bench mark.
bench_temp = c(dfmax$`Average Temprature`[1],dfmax$`Average Temprature`[2])
mu = mean(bench_temp)
mu
[1] 11.62157
Our mu here is 11.6 which signifies that this temperature is ideal for the virus to sustain.
Now lets split our dataset into 3 categories by their number of confirmed cases. Which are as follows: 1. Small: Confirmed cases between 0 and 200 2. Medium: Confirmed cases between 200 and 20000 3. Large: Confirmed cases are larger than 20000
df %>%
filter(df$`Confirmed Cases` < 200) -> small
head(small)
df %>%
filter(df$`Confirmed Cases` <5000 ,df$`Confirmed Cases` >200 ) -> medium
head(medium)
df %>%
filter(df$`Confirmed Cases` >= 5000) -> large
head(large)
This is a scatter plot of all of our separated data sets
ggplot(small, aes(y = `Confirmed Cases`, x = `Average Temprature`)) + geom_point()

Small Graph: We can see that the number of confirmed cases has a high density when the temperature is above 10 degrees celsius. So we can speculate that the temperature might play an important role when the number of confirmed cases is between 0 and 200.
ggplot(medium, aes(y = `Confirmed Cases`, x = `Average Temprature`)) + geom_point()

Medium Graph: We can see that the number of confirmed cases are mostly in between 500 and 750. We also see that for those cases, the temperature is evenly spread out meaning that once there is a certain threshold of people who have been affected, the temperature may no longer play an effective part in shortening the virus lifespan enough to make a difference. We can see that for the number of cases between 750 and 5000 have a lower average temperature, about 15 degrees celsius and below.
ggplot(large, aes(y = `Confirmed Cases`, x = `Average Temprature`)) +geom_point()

Large Graph: We can see that almost all of our data points lie below 15 degrees celsius. Also there is only one data point which is above 40000 confirmed cases. (This is China from our previous EDA).
Lets start by checking if there is any correlation between our variable
cor.test(small$`Average Temprature`, small$`Confirmed Cases`)
Pearson's product-moment correlation
data: small$`Average Temprature` and small$`Confirmed Cases`
t = -0.96404, df = 110, p-value = 0.3371
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
-0.27246040 0.09564811
sample estimates:
cor
-0.09153218
small.1 <- lm(small$`Average Temprature` ~ small$`Confirmed Cases`, data = small)
summary(small.1)
Call:
lm(formula = small$`Average Temprature` ~ small$`Confirmed Cases`,
data = small)
Residuals:
Min 1Q Median 3Q Max
-37.042 -7.943 3.804 7.070 14.597
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 19.76523 1.17111 16.877 <2e-16 ***
small$`Confirmed Cases` -0.01802 0.01869 -0.964 0.337
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 9.776 on 110 degrees of freedom
Multiple R-squared: 0.008378, Adjusted R-squared: -0.0006366
F-statistic: 0.9294 on 1 and 110 DF, p-value: 0.3371
medium.1 <- lm(medium$`Average Temprature` ~ medium$`Confirmed Cases`, data = medium)
summary(medium.1)
Call:
lm(formula = medium$`Average Temprature` ~ medium$`Confirmed Cases`,
data = medium)
Residuals:
Min 1Q Median 3Q Max
-21.451 -5.933 -2.701 6.218 16.041
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 12.975510 2.853452 4.547 0.000111 ***
medium$`Confirmed Cases` -0.002692 0.003011 -0.894 0.379490
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 10.01 on 26 degrees of freedom
Multiple R-squared: 0.02983, Adjusted R-squared: -0.007487
F-statistic: 0.7994 on 1 and 26 DF, p-value: 0.3795
large.1 <- lm(large$`Average Temprature` ~ large$`Confirmed Cases`, data = large)
summary(large.1)
Call:
lm(formula = large$`Average Temprature` ~ large$`Confirmed Cases`,
data = large)
Residuals:
Min 1Q Median 3Q Max
-8.5335 -3.2256 -0.7415 1.5434 11.0840
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.250e+01 3.210e+00 3.896 0.00802 **
large$`Confirmed Cases` -9.623e-06 1.001e-04 -0.096 0.92658
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 6.728 on 6 degrees of freedom
Multiple R-squared: 0.001536, Adjusted R-squared: -0.1649
F-statistic: 0.009233 on 1 and 6 DF, p-value: 0.9266
After running a linear regression on all 3 datasets, we can see that the p-value in all 3 sets are all above 0.05. This means that Confirmed Cases for all 3 sets is not significant. We also have an r-squared values which are very low, meaning that temperature does not tell us much about its correlation with confirmed cases across all 3 datasets.
After looking at our datasets, our graphs and running linear regressions on our sets, we cannot confidently say that there is a correlation between temperature and the amount of confirmed cases. From the small dataset, it initially may have seemed that there is a relation between higher temperatures and confirmed cases but as we went to the medium and large datasets, we were unable to continue on with the assumption. This makes sense, as our small data sets have a smaller numbers of confirmed cases so we may not have enough evidence in this set in order to make proper assumptions. Overall, based on our evidence and findings, we cannot say with confidence that there is a relationship between temperature and the spread of the virus. Of course something to note is that this virus began to spread during the cooler months of the most effected countries, so it hard to also tell if our conclusions could have been different if this were happening at a different time line.
e. Does Population have an effect on COVID-19 virus ?
Since our dataset has multiple fields and for the purpose of this questuon we will only be concerned with confirmed casea and total population and drop everything else.
df %>% select(Country,`Confirmed Cases`, `Total Population`) %>%
arrange(desc(`Total Population`)) -> dfpop
head(dfpop)
ggplot(dfpop, aes(x = `Total Population`, y = `Confirmed Cases`)) +geom_point()

dfpop %>%
filter(dfpop$`Total Population` < 1000000) -> smallpop
head(smallpop)
dfpop %>%
filter(dfpop$`Total Population` > 1000000, dfpop$`Total Population` < 50000000 ) -> mediumpop
head(mediumpop)
dfpop %>%
filter(dfpop$`Total Population` > 50000000 ) -> largepop
head(largepop)
ggplot(smallpop, aes(x = `Total Population`, y = `Confirmed Cases`)) +geom_point()

ggplot(mediumpop, aes(x = `Total Population`, y = `Confirmed Cases`)) +geom_point()

ggplot(largepop, aes(x = `Total Population`, y = `Confirmed Cases`)) +geom_point()

From all three groups, we can see that the majority of confirmed cases are relatively low with respect to the countries total population. There are a couple outliers in each dataset but this can be expected. There is no trend to show that a higher population equates to more confirmed cases. We can run a linear regression once again to see if there is a trend that we cannot determine from our graphs.
smallpop.1 <- lm(smallpop$`Confirmed Cases` ~ smallpop$`Total Population`, data = smallpop)
summary(smallpop.1)
Call:
lm(formula = smallpop$`Confirmed Cases` ~ smallpop$`Total Population`,
data = smallpop)
Residuals:
Min 1Q Median 3Q Max
-37.948 -26.928 -23.287 -0.944 189.183
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 2.364e+01 1.972e+01 1.199 0.244
smallpop$`Total Population` 2.029e-05 5.001e-05 0.406 0.689
Residual standard error: 57.5 on 20 degrees of freedom
Multiple R-squared: 0.008158, Adjusted R-squared: -0.04143
F-statistic: 0.1645 on 1 and 20 DF, p-value: 0.6893
mediumpop.1 <- lm(mediumpop$`Confirmed Cases` ~ mediumpop$`Total Population`, data = mediumpop)
summary(mediumpop.1)
Call:
lm(formula = mediumpop$`Confirmed Cases` ~ mediumpop$`Total Population`,
data = mediumpop)
Residuals:
Min 1Q Median 3Q Max
-1062.8 -332.8 -100.0 -24.1 10686.6
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.053e+00 1.765e+02 0.006 0.9953
mediumpop$`Total Population` 2.269e-05 9.458e-06 2.400 0.0183 *
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 1205 on 97 degrees of freedom
Multiple R-squared: 0.05603, Adjusted R-squared: 0.0463
F-statistic: 5.758 on 1 and 97 DF, p-value: 0.01833
largepop.1 <- lm(largepop$`Confirmed Cases` ~ largepop$`Total Population`, data = largepop)
summary(largepop.1)
Call:
lm(formula = largepop$`Confirmed Cases` ~ largepop$`Total Population`,
data = largepop)
Residuals:
Min 1Q Median 3Q Max
-38122 -3840 -2701 -802 41662
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.215e+02 3.112e+03 0.039 0.96918
largepop$`Total Population` 2.820e-05 7.841e-06 3.596 0.00139 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 13660 on 25 degrees of freedom
Multiple R-squared: 0.3409, Adjusted R-squared: 0.3146
F-statistic: 12.93 on 1 and 25 DF, p-value: 0.001386
Based on our data above, we can conclude that a higher population does not necessarily mean more confirmed cases. This can be clearly shown by looking at our dfpop dataframe. We can see that India has a total of 142 confirmed cases with a total population of 1352617328, where as Italy has a total of 31506 confirmed cases with a total population of 60431283.
Despite being half the population of India, there is tens of thousands of more confirmed cases. There are a number of factors which significantly contribute the amount of confirmed cases, however having more people in a country does not always mean more people have the virus. There is a an increased likelihood of the virus spreading faster, if precautions are not taken by the government and people, such is the case in Italy. However, there are many actions individuals can take in order to stop the spread of the virus so quickly, such as social distancing, self quarantining and practicing good hygiene and cleanliness. A high population doesn’t always mean a high number of confirmed cases, but more of a risk of more individuals to catch the virus.
Conclusion
It seems that the global fear of COVID-19 and it’s rapid increase is due to the same problem we drew from doing this project; it is difficult to contain an unknown disease from spreading when we cannot predict how well it thrives in its environment. Our analysis could not help us conclude if temperature played an effective role in controlling the growth of the virus, with the most number of cases being in China and the least number of cases being in Republic of Congo. Although there seemed to be signs of the virus being less effective in hotter climates when looking at the countries with the least number of casualties, as the number of victims grew exponentially, temperature’s effect on the lifespan of the virus became possibly insignificant. And since this growth happened during the colder months of the most effected countries, it is even more difficult to draw any strong conclusions. It is possible that on a different timeline, the scenario could have been completely different, and it may be still too early to draw an opinion. As we’ve seen from our first graph, we have yet to reach worldwide peak. Similarly, we could not conclude that the population size of a country had a play in its spread. There may be other factors that come into play, such as a country’s age distribution, travel restrictions etc., that could explain its current state. From recent events we do know that in general the more people that are traveling, the more the virus is able to spread by contact, with it being somewhat of a domino effect. So our solution has been to go into quarantine despite whatever level of cases in the area. Hopefully we can soon expect to gather enough data to successfully know how to reduce casualties arising from COVID-19.
LS0tCnRpdGxlOiAnRGF0YSBBbmFseXNpczogQ09WSUQtMTkgVmlydXMnCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAotLS0KIyBBdXRob3JzCkFiaGludiBDaGF1ZGhhcnkgOiAxMDAyNzA3NzMzCgpBZGhhbSBGYXJhZyA6IDEwMDM3ODgxOTAKCkV0aGFuIEFuYWRhIDogMTAwMzE3MTkwNwoKSGFtaXNoIFJhaml2IDoKCkx5bGEgVGFtaW0gOiAxMDAzNDU5NDY1CgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKYGBgCgojIFByZWZhY2UKCgoqKk9uIDMxIERlY2VtYmVyIDIwMTkqKiwgV0hPIHdhcyBhbGVydGVkIHRvIHNldmVyYWwgY2FzZXMgb2YgcG5ldW1vbmlhIGluIFd1aGFuIENpdHksIEh1YmVpIFByb3ZpbmNlIG9mIENoaW5hLiBUaGUgdmlydXMgcmVzcG9uc2libGUgd2FzIG5vdCBhIGtub3duIG9uZSBhbmQgdGhpcyByYWlzZWQgaW1tZWRpYXRlIGNvbmNlcm4gcmVnYXJkaW5nIHBlb3BsZSdzIHNhZmV0eSwgZXNwZWNpYWxseSBnaXZlbiB0aGUgcmF0ZSBpdCB3YXMgc3ByZWFkaW5nIHRocm91Z2hvdXQgdGhlIGdsb2JhbCBtYXAuIFdpdGggaXQncyBwcm9wZXIgc3ltcHRvbXMgYW5kIHRyZWF0bWVudHMgc3RpbGwgdW5rbm93biwgZGFpbHkgbGV2ZWwgaW5mb3JtYXRpb24gb24gdGhlIGFmZmVjdGVkIHBlb3BsZSBjYW4gZ2l2ZSBzb21lIGludGVyZXN0aW5nIGluc2lnaHRzLiBXZSB3b3VsZCBsaWtlIHRvIHRoYW5rIEpvaG5zIEhvcGtpbnMgVW5pdmVyc2l0eSBmb3IgbWFraW5nIHRoZSBkYXRhIGF2YWlsYWJsZSBmb3IgZWR1Y2F0aW9uYWwgYW5kIGFjYWRlbWljIHJlc2VhcmNoIHB1cnBvc2VzLgoKCiMgSW50cm9kdWN0aW9uCioqVGhlIDIwMTkgTm92ZWwgQ29yb25hdmlydXMqKiBpcyBhIHZpcnVzIGlkZW50aWZpZWQgYXMgdGhlIGNhdXNlIG9mIGFuIG91dGJyZWFrIG9mIHJlc3BpcmF0b3J5IGlsbG5lc3MgZmlyc3QgZGV0ZWN0ZWQgaW4gV3VoYW4sIENoaW5hLiBBdCB0aGlzIHRpbWUsIGl0IGlzIHVuY2xlYXIgaG93IGVhc2lseSBvciBzdXN0YWluYWJsZSB0aGlzIHZpcnVzIGlzIHNwcmVhZGluZyBiZXR3ZWVuIHBlb3BsZS4gVGhpcyBkYXRhc2V0IGhhcyBkYWlseSBsZXZlbCBpbmZvcm1hdGlvbiBvbiB0aGUgbnVtYmVyIG9mIGFmZmVjdGVkIGNhc2VzLCBkZWF0aHMgYW5kIHJlY292ZXJ5IGZyb20gKioyMDE5IG5vdmVsIGNvcm9uYXZpcnVzKiosIHRoZSBuYW1lIG5vdyBzaG9ydGVuZWQgdG8gQ09WSUQtMTkuIEZvciB0aGUgcHVycG9zZXMgb2YgdGhpcyBwcm9qZWN0LCB3ZSB3aWxsIG9ubHkgYmUgY29sbGVjdGluZyBkYXRhIHRpbGwgKioxN3RoIE1hcmNoIDIwMjAuKiogCgpPdXIgdGFyZ2V0IGZvciB0aGlzIHByb2plY3Qgd2lsbCBiZSB0byBzdHVkeSB0aGUgZWZmZWN0cyBvZiBnZW9ncmFwaHkgYW5kIHBvcHVsYXRpb24gb24gdGhlIHJhdGUgYXQgd2hpY2ggdGhlIHZpcnVzIGlzIGFibGUgdG8gc3ByZWFkLiBTdHVkeWluZyB0aGUgZ2VvZ3JhcGh5IG9mIGVhY2ggY2FzZSB3aWxsIGhlbHAgdXMgYW5hbHl6aW5nIGlmIHRlbXBlcmF0dXJlIHBsYXlzIGEgcGFydCBpbiBob3cgd2VsbCB0aGUgdmlydXMgaXMgYWJsZSB0byBleGlzdCwgYW5kIHNvIGhvdyBmYXN0IGl0IGlzIGFibGUgdG8gbXVsdGlwbHkuIFdlIHdpbGwgYWxzbyBsb29rIGF0IHRoZSBwb3B1bGF0aW9uIGRlbnNpdHkgb2YgdGhlIGVmZmVjdGVkIGNvdW50cmllcyBhbmQgc2VlIGlmIHRoZSBudW1iZXIgb2YgY2FzZXMgaGF2ZSBhIGxpbmVhciByZWxhdGlvbnNoaXAgd2l0aCB0aGUgcG9wdWxhdGlvbiBzaXplIGl0c2VsZi5Nb3N0IGltcG9ydGFudGx5LCB0aGlzIHByb2plY3Qgd2lsbCBoZWxwIHVzIGJldHRlciB1bmRlcnN0YW5kIGFuZCBwcmVwYXJlIGZvciB0aGUgcGFuZGVtaWMgYW5kIHBvc3NpYmx5IGhlbHAgcmVhY3QgYWNjb3JkaW5nbHkgdG8gZXZlcnkgcmFuZ2Ugb2Ygc2V2ZXJpdHksIGllLiB3aGF0IHRoZSBhcHByb3ByaWF0ZSBzYWZldHkgbWVhc3VyZXMgYXJlLiAKCgojIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMKCgojIyMgRGVwZW5kZW5jaWVzCgpUbyBjb21wbGV0ZSBvdXIgRGF0YSBBbmFseXNpcyB3ZSdsbCBiZSB1c2luZyB0aGUgKip0aWR5dmVyc2UqKiBsaWJyYXJ5LiBUbyB2aXN1YWxpemUgb3VyIGRhdGEgd2Ugd2lsbCBiZSB1c2luZyAqKmdncGxvdDIsIGRwbHlyLCBtYXBzIGFuZCB2aXJpZGlzKiouIFRvIGdldCB0aGUgd2VhdGhlciBiYXNlZCBvbiBsYXRpdHVkZSBhbmQgbG9uZ2l0dWRlLCB3ZSB3aWxsIGJlIG1ha2luZyBhbiBhcGkgY2FsbCB1c2luZyAqKndlYXRoZXJyKiouIFRvIGdldCBjb3VudHJ5IGJhc2VkIGRhdGEgc3VjaCBhcyBwb3B1bGF0aW9uIGRlbnNpdHksIGNvdW50cnkgY29kZSBldGMuLi4gd2Ugd2lsbCBiZSB1c2luZyAqKldESSoqIHdoaWNoIGlzIHRoZSAqV29ybGQgRGV2ZWxvcG1lbnQgSW5kaWNhdG9ycyogRGF0YUJhbmsgYW5kIHRoZSAqKmNvdW50cnljb2RlKiogIExpYnJhcnkuCmBgYHtyfQojIFRpZHl2ZXJzZQpsaWJyYXJ5KHRpZHl2ZXJzZSkKIyBHcmFwaGluZyBMaWJyYXJ5CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShkcGx5cikKbGlicmFyeShtYXBzKQpsaWJyYXJ5KHZpcmlkaXMpCiMtLS0tLS0tLS0tLS0tLS0tLS0KbGlicmFyeShkeWdyYXBocykKbGlicmFyeSh4dHMpICAgICAgICAgCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKIyBXZWF0aGVyIGFuZCBDb3VudHJ5IERhdGEKbGlicmFyeSh3ZWF0aGVycikKbGlicmFyeShXREkpCmxpYnJhcnkoY291bnRyeWNvZGUpCgpgYGAKCiMjIyBSZWFkaW5nIFRoZSBEYXRhIApMZXQncyBmaXJzdCBnbyBhaGVhZCBhbmQgc2VlIHdoYXQgb3VyIGRhdGEgbG9va3MgbGlrZSBieSBwcmludGluZyBvdXQgZmlyc3QgZmV3IHJvd3MKCmBgYHtyfQojIFJlYWRpbmcKY292aWRfMTkgPC0gcmVhZF9jc3YoIjAzLTE3LTIwMjAuY3N2IikKCmBgYAoKYGBge3J9Cm5hbWVzKGNvdmlkXzE5KVsxXSA8LSAiUHJvdmluY2UiCm5hbWVzKGNvdmlkXzE5KVsyXSA8LSAiQ291bnRyeSIKaGVhZChjb3ZpZF8xOSkKYGBgCgpCeSB0aGUgbG9va3Mgb2YgdGhlIGRhdGEgd2UgaGF2ZSB0aGUgZm9sbG93aW5nIGZpZWxkczoKCgoqKjEuIFByb3ZpbmNlIDoqKiBSZWdpb24gaW4gdGhlIGNvdW50cnkgd2hlcmUgdGhlIHZpcnVzIHdhcyByZXBvcnRlZAoKCioqMi4gQ291bnRyeSA6KiogQ291bnRyeSB3aGVyZSBpdCB3YXMgcmVwb3J0ZWQKCgoqKjMuIExhc3QgVXBkYXRlIDoqKiBUaGUgdGltZSB3aGVuIHRoZSB0b3RhbCBjb3VudCB3YXMgcmV2aWV3ZWQgb250byB0aGUgZGF0YXRzZXQKCgoqKjQuIENvbmZpcm1lZDoqKiBUb3RhbCBudW1iZXIgb2YgcGVvcGxlIGFmZmVjdGVkIGJ5IHRoZSB2aXJ1cyAKCgoqKjUuIERlYXRocyA6KiogVG90YWwgbnVtYmVyIG9mIGRlYXRocyBmcm9tIHRoZSB2aXJ1cyAKCgoqKjYuIFJlY292ZXJlZCA6KiogVG90YWwgbnVtYmVyIG9mIHBlb3BsZSB0aGF0IHJlY292ZXJlZCBhZnRlciB0aGV5IGhhdmUgYmVlbiBhZmZlY3RlZCAKCgoqKjcuIExhdGl0dXRlIDoqKiBHZW8tbG9naWNhbCBsb2NhdGlvbiBvZiB0aGUgcmVwb3J0ZWQgaW5jaWRlbnQgCgoKKio4LiBMb25ndGl0dWRlIDoqKiBHZW8tbG9naWNhbCBsb2NhdGlvbiBvZiB0aGUgcmVwb3J0ZWQgaW5jaWRlbnQKCiMjIyBHcmFwaGluZyAKTm93IGxldCdzIHRyeSB0byB2aXN1YWxpemUgb3VyIGRhdGEgdG8gZ2V0IGEgYnJvYWRlciB2aWV3IG9mIHRoZSBwcm9ibGVtIGF0IGhhbmQuIEZpcnN0bHkgd2UnbGwgdGFrZSBhIGxvb2sgYXQgdGhlIHRvdGFsIG51bWJlciBvZiAqKmNvbmZpcm1lZCBjYXNlcyoqLgoKYGBge3J9CndvcmxkIDwtIG1hcF9kYXRhKCJ3b3JsZCIpCmdncGxvdCgpICsKICBnZW9tX3BvbHlnb24oZGF0YSA9IHdvcmxkLCBhZXMoeD1sb25nLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwKSwgZmlsbD0iZ3JleSIsIGFscGhhPTAuMykgKwogIGdlb21fcG9pbnQoIGRhdGE9Y292aWRfMTksIGFlcyh4PWNvdmlkXzE5JExvbmdpdHVkZSwgeT1jb3ZpZF8xOSRMYXRpdHVkZSwgc2l6ZT1jb3ZpZF8xOSRDb25maXJtZWQsIGNvbG9yPWNvdmlkXzE5JENvbmZpcm1lZCkpICsKICAgIHNjYWxlX2NvbG9yX3ZpcmlkaXModHJhbnM9ImxvZyIpICsKCiAgdGhlbWVfdm9pZCgpKyBjb29yZF9tYXAoKSAKYGBgCkJ5IGxvb2tpbmcgYXQgdGhlIGdyYXBoIHdlIGNhbiB0aGF0IHRoZSBtb3N0IG51bWJlciBvZiBjYXNlcyByZXBvcnRlZCB0by1kYXRlIGhhcHBlbiB0byBiZSBpbiBDaGluYS4gV2UgYWxzbyBzZWUgc29tZSBjYXNlcyBiZWluZyByZXBvcnRlZCBhdCBzZWEsIHRoZXNlIGFyZSBtb3N0IHByb2JhYmx5IHNoaXBzIHdoaWNoIHdlcmUgdHJhdmVsaW5nIGF0IHRoZSB0aW1lLgoKCgoKYGBge3J9CndvcmxkIDwtIG1hcF9kYXRhKCJ3b3JsZCIpCmdncGxvdCgpICsKICBnZW9tX3BvbHlnb24oZGF0YSA9IHdvcmxkLCBhZXMoeD1sb25nLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwKSwgZmlsbD0iZ3JleSIsIGFscGhhPTAuMykgKwogIGdlb21fcG9pbnQoIGRhdGE9Y292aWRfMTksIGFlcyh4PWNvdmlkXzE5JExvbmdpdHVkZSwgeT1jb3ZpZF8xOSRMYXRpdHVkZSwgc2l6ZT1jb3ZpZF8xOSREZWF0aHMsIGNvbG9yPWNvdmlkXzE5JERlYXRocykpICsKICBzY2FsZV9jb2xvcl92aXJpZGlzKHRyYW5zPSJsb2ciKSArCiAgdGhlbWVfdm9pZCgpKyBjb29yZF9tYXAoKSAKYGBgCkZyb20gdGhlIGdyYXBoIHdlIGNhbiBzZWUgdGhhdCB0aGUgbW9zdCBudW1iZXIgb2YgZGVhdGhzIGhhcHBlbmVkIGluIENoaW5hIGFuZCBJdGFseS4gQXMgY29tcGFyZWQgdG8gdGhlIG51bWJlciBvZiBjb25maXJtZWQgY2FzZXMgdGhpcyBncmFwaCBzZWVtcyB0byBiZSBsZXNzIGRlbnNlIHdoaWNoIGlzIGEgZ29vZCBzaWduLiAKCgoKYGBge3J9CndvcmxkIDwtIG1hcF9kYXRhKCJ3b3JsZCIpCmdncGxvdCgpICsKICBnZW9tX3BvbHlnb24oZGF0YSA9IHdvcmxkLCBhZXMoeD1sb25nLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwKSwgZmlsbD0iZ3JleSIsIGFscGhhPTAuMykgKwogIGdlb21fcG9pbnQoIGRhdGE9Y292aWRfMTksIGFlcyh4PWNvdmlkXzE5JExvbmdpdHVkZSwgeT1jb3ZpZF8xOSRMYXRpdHVkZSwgc2l6ZT1jb3ZpZF8xOSRSZWNvdmVyZWQsIGNvbG9yPWNvdmlkXzE5JFJlY292ZXJlZCkpICsKICBzY2FsZV9jb2xvcl92aXJpZGlzKHRyYW5zPSJsb2ciKSArCiAgdGhlbWVfdm9pZCgpKyBjb29yZF9tYXAoKSAKYGBgCkZyb20gdGhpcyBncmFwaCB3ZSBzZWUgdGhhdCBtb3N0IG9mIHRoZSByZWNvdmVyZWQgY2FzZXMgaGFwcGVuZWQgYWdhaW4gaW4gQ2hpbmEgYW5kIEl0YWx5LiBXaXRoIGEgbnVtYmVyIG9mIHJlY292ZXJlZCBjYXNlcyBncm93aW5nIGluIE5vcnRoIEFtZXJpY2EuIAoKCiMjIERhdGEgQ2xlYW5pbmcgCkJlZm9yZSB3ZSBjYW4gYmVnaW4gdG8gdW5kZXJzdGFuZCB0aGUgZGF0YSBhbmQgZWZmZWN0aXZlbHkgdXNlIGl0IHRvIGRvIG91ciBhbmFseXNpcywgd2UgZmlyc3QgbmVlZCB0byBkbyBzb21lIGRhdGEgY2xlYW5pbmcuIFdlIHNob3VsZCBncm91cCBieSBjb3VudHJ5IGFuZCB3ZSBzaG91bGQgZ2V0IHRoZSB3ZWF0aGVyIGZvciBhbGwgb2YgdGhlbS4gUG9wdWxhdGlvbiBzaXplIHdpbGwgYWxzbyBiZSBhbiBpbXBvcnRhbnQgZmFjdG9yIGluIG91ciBzdHVkeSwgc28gd2VsbCB3aWxsIGFsc28gZmFjdG9yIHRoYXQgaW4uIFdlIHdpbGwgbm90IGNsZWFuIG91ciBkYXRhIGFjY29yZGluZ2x5LgoKYGBge3J9CgojIE1hZGUgYSBuZXcgZGF0YSBmcmFtZSB3aXRoIGEgY29sdW1ucyBjYWxsZWQgdGVtcGVyYXR1cmUsdGhlbiB1c2luZyB0aGUgbGF0aXR1ZGUgYW5kIGxvbmdpdHVkZSBnb3QgdGhlcmUgcmVzcGVjdGl2ZSB3ZWF0aGVyIGJ5IGRvaW5nIGFuIGFwaSBjYWxsIHRvIHRoZSB3ZWF0aGVyIHN0YXRpb24gCmRhdGEuZnJhbWUoY292aWRfMTkpIC0+IGNvdW50cnlfZGF0YQpjb3VudHJ5X2RhdGEkUHJvdmluY2UgPSBOVUxMCmNvdW50cnlfZGF0YSRUZW1wZXJhdHVyZSA9IGMoMCkKCm4gPSBucm93KGNvdW50cnlfZGF0YSkKZm9yIChpIGluIDE6bil7CiAgd2VhdGhlciA9IHN1cHByZXNzV2FybmluZ3MoIGxvY2F0aW9uZm9yZWNhc3QobGF0PWNvdW50cnlfZGF0YSRMYXRpdHVkZVtpXSwgbG9uPWNvdW50cnlfZGF0YSRMb25naXR1ZGVbaV0pICkKICB0ZW1wID0gc3VwcHJlc3NXYXJuaW5ncyhtZWFuKHdlYXRoZXIkdGVtcGVyYXR1cmUpKQogIGNvdW50cnlfZGF0YSRUZW1wZXJhdHVyZVtpXSA9IHRlbXAKfQoKYGBgCmBgYHtyfQoKIyBHZXQgdGhlIHdlYXRoZXIgZGF0YSAKV2VhdGhlcl9kYXRhICA9IGNvdW50cnlfZGF0YQpXZWF0aGVyX2RhdGEkTGF0aXR1ZGUgPSBOVUxMCldlYXRoZXJfZGF0YSRMb25naXR1ZGUgPSBOVUxMCldlYXRoZXJfZGF0YSAlPiUgCiAgZ3JvdXBfYnkoQ291bnRyeSkgJT4lIAogIHN1bW1hcmlzZShDb25maXJtZWRfQ2FzZXMgPSBzdW0oQ29uZmlybWVkKSkgLT4gY29uCldlYXRoZXJfZGF0YSAlPiUgCiAgZ3JvdXBfYnkoQ291bnRyeSkgJT4lIAogIHN1bW1hcmlzZShEZWF0aF9DYXNlcyA9IHN1bShEZWF0aHMpKSAtPiBkZWEKV2VhdGhlcl9kYXRhICU+JSAKICBncm91cF9ieShDb3VudHJ5KSAlPiUgCiAgc3VtbWFyaXNlKFJlY292ZXJlZF9DYXNlcyA9IHN1bShSZWNvdmVyZWQpKSAtPiByZWMKV2VhdGhlcl9kYXRhICU+JSAKICBncm91cF9ieShDb3VudHJ5KSAlPiUgCiAgc3VtbWFyaXNlKE1lYW5fVGVtcHJhdHVyZSA9IG1lYW4oVGVtcGVyYXR1cmUpKSAtPiB0ZW0KCldlYXRoZXJfZGF0YV9jb3VudHJ5ID0gZGF0YS5mcmFtZShjb24kQ291bnRyeSwgY29uJENvbmZpcm1lZF9DYXNlcywgZGVhJERlYXRoX0Nhc2VzLCByZWMkUmVjb3ZlcmVkX0Nhc2VzLCB0ZW0kTWVhbl9UZW1wcmF0dXJlKQpjb2xuYW1lcyhXZWF0aGVyX2RhdGFfY291bnRyeSkgPC0gYygiQ291bnRyeSIsICJDb25maXJtZWQgQ2FzZXMiLCAiRGVhdGggQ2FzZXMiLCAiUmVjb3ZlcmVkIENhc2VzIiwgIkF2ZXJhZ2UgVGVtcHJhdHVyZSIpCgpgYGAKYGBge3J9CmNvdW50cnkgPSBXZWF0aGVyX2RhdGFfY291bnRyeSRDb3VudHJ5CmNvdW50cnljb2RlKGNvdW50cnksIG9yaWdpbiA9ICdjb3VudHJ5Lm5hbWUnLCBkZXN0aW5hdGlvbiA9ICdpc28yYycpIC0+IENvdW50cnlfY29kZQpjYmluZChDb3VudHJ5X2NvZGUgLFdlYXRoZXJfZGF0YV9jb3VudHJ5KSAtPiBXZWF0aGVyX2RhdGFfY291bnRyeQpXREkoY291bnRyeSA9IFdlYXRoZXJfZGF0YV9jb3VudHJ5JENvdW50cnlfY29kZSwgaW5kaWNhdG9yPSJTUC5QT1AuVE9UTCIsc3RhcnQ9MjAxOCwgZW5kPTIwMTgpIC0+IHBvcHVsYXRpb24KIyAKaGVhZChXZWF0aGVyX2RhdGFfY291bnRyeSkKYGBgCmBgYHtyfQptZXJnZShXZWF0aGVyX2RhdGFfY291bnRyeSwgcG9wdWxhdGlvbiwgYnkueCA9ICJDb3VudHJ5X2NvZGUiLCBieS55ID0gImlzbzJjIikgLT4gZGYKZGYkY291bnRyeSA9IE5VTEwKZGYkeWVhciA9IE5VTEwKY29sbmFtZXMoZGYpWzddID0gIlRvdGFsIFBvcHVsYXRpb24iCmhlYWQoZGYpCgpgYGAKCgoKYGBge3J9CmNfdXJsID0gImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9DU1NFR0lTYW5kRGF0YS9DT1ZJRC0xOS9tYXN0ZXIvY3NzZV9jb3ZpZF8xOV9kYXRhL2Nzc2VfY292aWRfMTlfdGltZV9zZXJpZXMvdGltZV9zZXJpZXNfMTktY292aWQtQ29uZmlybWVkLmNzdiIKZF91cmwgPSAiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0NTU0VHSVNhbmREYXRhL0NPVklELTE5L21hc3Rlci9jc3NlX2NvdmlkXzE5X2RhdGEvY3NzZV9jb3ZpZF8xOV90aW1lX3Nlcmllcy90aW1lX3Nlcmllc18xOS1jb3ZpZC1EZWF0aHMuY3N2IgpyX3VybCA9ICJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vQ1NTRUdJU2FuZERhdGEvQ09WSUQtMTkvbWFzdGVyL2Nzc2VfY292aWRfMTlfZGF0YS9jc3NlX2NvdmlkXzE5X3RpbWVfc2VyaWVzL3RpbWVfc2VyaWVzXzE5LWNvdmlkLVJlY292ZXJlZC5jc3YiCgojIFJlYWRpbmcgaW4gdGhlIFRpbWUgRGF0YS1TZXQgIApjb25maXJtZWRfdHMgPSByZWFkX2RlbGltKGNfdXJsLCAiLCIpCmRlYXRoX3RzID0gcmVhZF9kZWxpbShkX3VybCwgIiwiKQpyZWNvdmVyX3RzID0gcmVhZF9kZWxpbShyX3VybCwgIiwiKQpgYGAKYGBge3J9CiMgQ29uZmlybWVkIENhc2VzIGZvciBkYXRlcwpjb25maXJtZWRfdHMgJT4lIAogIHBpdm90X2xvbmdlcigiMS8yMi8yMCI6IjMvMjEvMjAiLCBuYW1lc190byA9ICJEYXRlcyIsIHZhbHVlc190byA9ICJDb25maXJtZWRfQ2FzZXMiKSAtPiBjb25maXJtZWRfdHMKCiMgRGVhdGggQ2FzZXMgZm9yIGRhdGVzCmRlYXRoX3RzICU+JSAKICBwaXZvdF9sb25nZXIoIjEvMjIvMjAiOiIzLzIxLzIwIiwgbmFtZXNfdG8gPSAiRGF0ZXMiLCB2YWx1ZXNfdG8gPSAiRGVhdGhfQ2FzZXMiKSAtPiBkZWF0aF90cwoKIyBSZWNvdmVyZWQgQ2FzZXMgZm9yIGRhdGVzCnJlY292ZXJfdHMgJT4lIAogIHBpdm90X2xvbmdlcigiMS8yMi8yMCI6IjMvMjEvMjAiLCBuYW1lc190byA9ICJEYXRlcyIsIHZhbHVlc190byA9ICJSZWNvdmVyX0Nhc2VzIikgLT4gcmVjb3Zlcl90cwpgYGAKYGBge3J9CmNvbmZpcm1lZF90cyAlPiUgCiAgZ3JvdXBfYnkoRGF0ZXMpICU+JQogIHN1bW1hcmlzZShDb25maXJtZWRfQ2FzZXMgPSBzdW0oYENvbmZpcm1lZF9DYXNlc2ApKS0+Y3MKCnJlY292ZXJfdHMgJT4lCiAgZ3JvdXBfYnkoRGF0ZXMpICU+JSAKICBzdW1tYXJpc2UoUmVjb3Zlcl9DYXNlcyA9IHN1bShgUmVjb3Zlcl9DYXNlc2ApKSAtPiBycwoKZGVhdGhfdHMgJT4lCiAgZ3JvdXBfYnkoRGF0ZXMpICU+JSAKICBzdW1tYXJpc2UoRGVhdGhfQ2FzZXMgPSBzdW0oYERlYXRoX0Nhc2VzYCkpIC0+IGRzCmBgYApgYGB7cn0KbWVyZ2UoY3MsIHJzLCBieS54ID0gIkRhdGVzIiwgYnkueSA9ICJEYXRlcyIpIC0+IGRmciAgIAptZXJnZShkZnIsIGRzLCBieS54ID0gIkRhdGVzIiwgYnkueSA9ICJEYXRlcyIgKSAtPiBUb3RhbENvdW50X0J5RGF0ZQpgYGAKCgpOb3cgdGhhdCB3ZSBoYXZlIGNsZWFuZWQgb3VyIGRhdGEgbGV0cyBhbnN3ZXIgc29tZSBxdWVzdGlvbnMuCgojIEFuYWx5c2lzCgojIyMgYS4gV2hpY2ggY291bnRyeSBoYXMgdGhlIG1vc3QgbnVtYmVyIG9mIGNhc3VhbHRpZXMgPyAKYGBge3J9CmRmICU+JSAKICBncm91cF9ieShDb3VudHJ5KSAlPiUgCiAgYXJyYW5nZShkZXNjKGBDb25maXJtZWQgQ2FzZXNgLCBgRGVhdGggQ2FzZXNgLCBgUmVjb3ZlcmVkIENhc2VzYCkpIC0+IGNvbmZfZGYKaGVhZChjb25mX2RmLDQpIC0+IGRmbWF4CmRmbWF4CmBgYAogQXMgd2UgY2FuIHNlZSAqKkNoaW5hKiogcmFua3MgdGhlIG1vc3QgYW1vbmdzIGFsbCBvZiB0aGVtLCBmb2xsb3dlZCBieSAqKkl0YWx5KiosICoqSXJhbioqIGFuZCAqKlNwYWluKioKIAogCiMjIyBiLiBXaGljaCBjb3VudHJ5IGhhcyB0aGUgbGVhc3QgbnVtYmVyIG9mIGNhc3VhbHRpZXMgPwpgYGB7cn0KZGYgJT4lIAogIGdyb3VwX2J5KENvdW50cnkpICU+JSAKICBhcnJhbmdlKGBDb25maXJtZWQgQ2FzZXNgLCBgRGVhdGggQ2FzZXNgLCBgUmVjb3ZlcmVkIENhc2VzYCkgLT4gY29uZl9kZgpoZWFkKGNvbmZfZGYsNCkgLT4gY29uZl9kZgpjb25mX2RmCmBgYAogQXMgd2UgY2FuIHNlZSAqKlJlcHVibGljIG9mIHRoZSBDb25nbyoqIHJhbmtzIHRoZSBtb3N0IGFtb25nIGFsbCBvZiB0aGVtLCBmb2xsb3dlZCBieSAqKlB1ZXJ0byBSaWNvKiosICoqUGFsZXN0aW5pYW4gdGVycml0b3J5KiogYW5kICoqQW50aWd1YSBhbmQgQmFyYnVkYSoqCiAKIAojIyMgYy4gV2hhdCBpcyB0aGUgZ2VuZXJhbCB0cmVuZCBvZiB0aGUgQ09WSUQtMTkgdmlydXMgYXMgdGhlIGRheSdzIHByb2dyZXNzPwoKTGV0IHVzIGNhbGwgdGhlIGRhdGEgd2UgY2xlYW5lZCB1cCBhYm92ZSBhbmQgc2hvdyBzb21lIG9mIHRoZSByb3dzCmBgYHtyfQpoZWFkKFRvdGFsQ291bnRfQnlEYXRlKQpgYGAKV2Ugc2VlIG9uZSBjYXRlZ29yaWNhbCBkYXRhIGNhbGxlZCAqKkRhdGVzKiogYW5kIHRocmVlIFF1YW50aXRhdGl2ZSBEYXRhIGNhbGxlZCAqKkNvbmZpcm1lZCBDYXNlcywgUmVjb3ZlciBDYXNlcyBhbmQgRGVhdGggQ2FzZXMgKiouIEhvd2V2ZXIgc2luY2Ugd2UgaGF2ZSBhIHRpbWUgc2VyaWVzIGRhdGEsIHdlIHRob3VnaHQgaXQgd291bGQgYmUgaW50ZXJlc3RpbmcgdG8gdHJ5IHVzaW5nICB0aGUgKip4dHMqKiBsaWJyYXJ5LgoKYGBge3J9CmFzLkRhdGUoVG90YWxDb3VudF9CeURhdGUkRGF0ZXMsZm9ybWF0PSIlbS8lZC8leSIpIC0+IG8KCmRhdGEuZnJhbWUobywgVG90YWxDb3VudF9CeURhdGUkQ29uZmlybWVkX0Nhc2VzLCBUb3RhbENvdW50X0J5RGF0ZSREZWF0aF9DYXNlcywgVG90YWxDb3VudF9CeURhdGUkUmVjb3Zlcl9DYXNlcykgLT4gZGF0YQpkb24gPC0geHRzKHggPSBkYXRhLCBvcmRlci5ieSA9IGRhdGEkbykKbmFtZXMoZG9uKVsyXSA9ICJDb25maXJtZWQgQ2FzZXMiCm5hbWVzKGRvbilbM10gPSAiRGVhdGggQ2FzZXMiCm5hbWVzKGRvbilbNF0gPSAiUmVjb3ZlcmVkIENhc2VzIgpgYGAKCmBgYHtyfQojIEZpbmFsbHkgdGhlIHBsb3QKcCA8LSBkeWdyYXBoKGRvbikgJT4lCiAgZHlPcHRpb25zKGxhYmVsc1VUQyA9IFRSVUUsIGZpbGxHcmFwaD1UUlVFLCBmaWxsQWxwaGE9MC4xLCBkcmF3R3JpZCA9IEZBTFNFLCBjb2xvcnMgPSBSQ29sb3JCcmV3ZXI6OmJyZXdlci5wYWwoMywgIlNldDEiKSkgJT4lCiAgZHlSYW5nZVNlbGVjdG9yKCkgJT4lCiAgZHlDcm9zc2hhaXIoZGlyZWN0aW9uID0gInZlcnRpY2FsIikgJT4lCiAgZHlIaWdobGlnaHQoaGlnaGxpZ2h0Q2lyY2xlU2l6ZSA9IDUsIGhpZ2hsaWdodFNlcmllc0JhY2tncm91bmRBbHBoYSA9IDAuMiwgaGlkZU9uTW91c2VPdXQgPSBGQUxTRSkgICU+JQogIGR5Um9sbGVyKHJvbGxQZXJpb2QgPSAxKQpwCmBgYApGcm9tIHRoZSBncmFwaCB3ZSBjYW4gc2VlIHRoYXQgdGhlcmUncyBiZWVuIGEgZ2xvYmFsIHNoYXJwIGluY3JlYXNlIGluIHRoZSBudW1iZXIgb2YgY2FzZXMgYWZ0ZXIgTWFyY2ggMTIuIFRoZSBncmFwaCBtaWdodCBwb3NzaWJseSBiZSBmb2xsb3dpbmcgYW4gZXhwb25lbnRpYWwgY3VydmUsIGJ1dCBoYXZlIHlldCB0byBoaXQgdGhlIHN1cmdlLiBXZSBhbHNvIHNlZSB0aGF0IHRoZSBudW1iZXIgb2YgY29uZmlybWVkIGNhc2VzIGFyZSBncm93aW5nIGF0IGEgZmFzdGVyIHJhdGUgdGhhbiBSZWNvdmVyZWQgYW5kIERlYXRoIENhc2VzLgoKCiMjIyBkLiBEb2VzIENsaW1hdGUgaGF2ZSBhbiBlZmZlY3Qgb24gdGhlIENPVklELTE5IHZpcnVzPwogIEZvciB0aGUgcHVycG9zZSBvZiB0aGUgYW5hbHlzaXMgd2Ugd2FudCB0byBzZWUgaWYgdGhlIHRlbXBlcmF0dXJlIGhhcyBhbnkgYWZmZWN0IG9uIHRoZSBDT1ZJRC0xOSB2aXJ1cy4gRnJvbSBxdWVzdGlvbiAoYSkgd2UgZm91bmQgb3V0IHRoYXQgdGhlIGNvdW50cmllcyB3aXRoIHRoZSBtb3N0IG51bWJlciBvZiBjb25maXJtZWQgY2FzZXMgaXMgQ2hpbmEgYW5kIEl0YWx5LiBXZSBzdGFydCBieSB0YWtpbmcgdGhlIG1lYW4gb2YgdGhlIHR3byB0ZW1wZXJhdHVyZXMgYXMgYSBiZW5jaCBtYXJrLiAKYGBge3J9CmJlbmNoX3RlbXAgPSBjKGRmbWF4JGBBdmVyYWdlIFRlbXByYXR1cmVgWzFdLGRmbWF4JGBBdmVyYWdlIFRlbXByYXR1cmVgWzJdKQptdSA9IG1lYW4oYmVuY2hfdGVtcCkKbXUKYGBgCk91ciBtdSBoZXJlIGlzIDExLjYgd2hpY2ggc2lnbmlmaWVzIHRoYXQgdGhpcyB0ZW1wZXJhdHVyZSBpcyBpZGVhbCBmb3IgdGhlIHZpcnVzIHRvIHN1c3RhaW4uIAoKTm93IGxldHMgc3BsaXQgb3VyIGRhdGFzZXQgaW50byAzIGNhdGVnb3JpZXMgYnkgdGhlaXIgbnVtYmVyIG9mIGNvbmZpcm1lZCBjYXNlcy4gV2hpY2ggYXJlIGFzIGZvbGxvd3M6CjEuIFNtYWxsOiBDb25maXJtZWQgY2FzZXMgYmV0d2VlbiAwIGFuZCAyMDAKMi4gTWVkaXVtOiBDb25maXJtZWQgY2FzZXMgYmV0d2VlbiAyMDAgYW5kIDIwMDAwCjMuIExhcmdlOiBDb25maXJtZWQgY2FzZXMgYXJlIGxhcmdlciB0aGFuIDIwMDAwCgoKYGBge3J9CmRmICU+JSAKICBmaWx0ZXIoZGYkYENvbmZpcm1lZCBDYXNlc2AgIDwgMjAwKSAtPiBzbWFsbAoKaGVhZChzbWFsbCkKYGBgCgpgYGB7cn0KZGYgJT4lIAogIGZpbHRlcihkZiRgQ29uZmlybWVkIENhc2VzYCAgPDUwMDAgLGRmJGBDb25maXJtZWQgQ2FzZXNgICA+MjAwICkgLT4gbWVkaXVtCgpoZWFkKG1lZGl1bSkKYGBgCgoKYGBge3J9CmRmICU+JSAKICBmaWx0ZXIoZGYkYENvbmZpcm1lZCBDYXNlc2AgID49IDUwMDApIC0+IGxhcmdlCgpoZWFkKGxhcmdlKQpgYGAKCgoKClRoaXMgaXMgYSBzY2F0dGVyIHBsb3Qgb2YgYWxsIG9mIG91ciBzZXBhcmF0ZWQgZGF0YSBzZXRzIApgYGB7cn0KZ2dwbG90KHNtYWxsLCBhZXMoeSA9IGBDb25maXJtZWQgQ2FzZXNgLCB4ID0gYEF2ZXJhZ2UgVGVtcHJhdHVyZWApKSArIGdlb21fcG9pbnQoKQpgYGAKCioqU21hbGwgR3JhcGg6KiogV2UgY2FuIHNlZSB0aGF0IHRoZSBudW1iZXIgb2YgY29uZmlybWVkIGNhc2VzIGhhcyBhIGhpZ2ggZGVuc2l0eSB3aGVuIHRoZSB0ZW1wZXJhdHVyZSBpcyBhYm92ZSAxMCBkZWdyZWVzIGNlbHNpdXMuIFNvIHdlIGNhbiBzcGVjdWxhdGUgdGhhdCB0aGUgdGVtcGVyYXR1cmUgbWlnaHQgcGxheSBhbiBpbXBvcnRhbnQgcm9sZSB3aGVuIHRoZSBudW1iZXIgb2YgY29uZmlybWVkIGNhc2VzIGlzIGJldHdlZW4gMCBhbmQgMjAwLgoKCgpgYGB7cn0KZ2dwbG90KG1lZGl1bSwgYWVzKHkgPSBgQ29uZmlybWVkIENhc2VzYCwgeCA9IGBBdmVyYWdlIFRlbXByYXR1cmVgKSkgKyBnZW9tX3BvaW50KCkKYGBgCgoqKk1lZGl1bSBHcmFwaDoqKiBXZSBjYW4gc2VlIHRoYXQgdGhlIG51bWJlciBvZiBjb25maXJtZWQgY2FzZXMgYXJlIG1vc3RseSBpbiBiZXR3ZWVuIDUwMCBhbmQgNzUwLiBXZSBhbHNvIHNlZSB0aGF0IGZvciB0aG9zZSBjYXNlcywgdGhlIHRlbXBlcmF0dXJlIGlzIGV2ZW5seSBzcHJlYWQgb3V0IG1lYW5pbmcgdGhhdCBvbmNlIHRoZXJlIGlzIGEgY2VydGFpbiB0aHJlc2hvbGQgb2YgcGVvcGxlIHdobyBoYXZlIGJlZW4gYWZmZWN0ZWQsIHRoZSB0ZW1wZXJhdHVyZSBtYXkgbm8gbG9uZ2VyIHBsYXkgYW4gZWZmZWN0aXZlIHBhcnQgaW4gc2hvcnRlbmluZyB0aGUgdmlydXMgbGlmZXNwYW4gZW5vdWdoIHRvIG1ha2UgYSBkaWZmZXJlbmNlLiBXZSBjYW4gc2VlIHRoYXQgZm9yIHRoZSBudW1iZXIgb2YgY2FzZXMgYmV0d2VlbiA3NTAgYW5kIDUwMDAgaGF2ZSBhIGxvd2VyIGF2ZXJhZ2UgdGVtcGVyYXR1cmUsIGFib3V0IDE1IGRlZ3JlZXMgY2Vsc2l1cyBhbmQgYmVsb3cuCgoKCmBgYHtyfQpnZ3Bsb3QobGFyZ2UsIGFlcyh5ID0gYENvbmZpcm1lZCBDYXNlc2AsIHggPSBgQXZlcmFnZSBUZW1wcmF0dXJlYCkpICtnZW9tX3BvaW50KCkKYGBgCgoqKkxhcmdlIEdyYXBoOioqIFdlIGNhbiBzZWUgdGhhdCBhbG1vc3QgYWxsIG9mIG91ciBkYXRhIHBvaW50cyBsaWUgYmVsb3cgMTUgZGVncmVlcyBjZWxzaXVzLiBBbHNvIHRoZXJlIGlzIG9ubHkgb25lIGRhdGEgcG9pbnQgd2hpY2ggaXMgYWJvdmUgNDAwMDAgY29uZmlybWVkIGNhc2VzLiAoVGhpcyBpcyBDaGluYSBmcm9tIG91ciBwcmV2aW91cyBFREEpLiAKCkxldHMgc3RhcnQgYnkgY2hlY2tpbmcgaWYgdGhlcmUgaXMgYW55IGNvcnJlbGF0aW9uIGJldHdlZW4gb3VyIHZhcmlhYmxlIAoKYGBge3J9CmNvci50ZXN0KHNtYWxsJGBBdmVyYWdlIFRlbXByYXR1cmVgLCBzbWFsbCRgQ29uZmlybWVkIENhc2VzYCkKYGBgCgoKCgpgYGB7cn0Kc21hbGwuMSA8LSBsbShzbWFsbCRgQXZlcmFnZSBUZW1wcmF0dXJlYCB+IHNtYWxsJGBDb25maXJtZWQgQ2FzZXNgLCBkYXRhID0gc21hbGwpCnN1bW1hcnkoc21hbGwuMSkKYGBgCmBgYHtyfQptZWRpdW0uMSA8LSBsbShtZWRpdW0kYEF2ZXJhZ2UgVGVtcHJhdHVyZWAgfiBtZWRpdW0kYENvbmZpcm1lZCBDYXNlc2AsIGRhdGEgPSBtZWRpdW0pCnN1bW1hcnkobWVkaXVtLjEpCmBgYAoKYGBge3J9CmxhcmdlLjEgPC0gbG0obGFyZ2UkYEF2ZXJhZ2UgVGVtcHJhdHVyZWAgfiBsYXJnZSRgQ29uZmlybWVkIENhc2VzYCwgZGF0YSA9IGxhcmdlKQpzdW1tYXJ5KGxhcmdlLjEpCmBgYApBZnRlciBydW5uaW5nIGEgbGluZWFyIHJlZ3Jlc3Npb24gb24gYWxsIDMgZGF0YXNldHMsIHdlIGNhbiBzZWUgdGhhdCB0aGUgcC12YWx1ZSBpbiBhbGwgMyBzZXRzIGFyZSBhbGwgYWJvdmUgMC4wNS4gVGhpcyBtZWFucyB0aGF0IENvbmZpcm1lZCBDYXNlcyBmb3IgYWxsIDMgc2V0cyBpcyBub3Qgc2lnbmlmaWNhbnQuIFdlIGFsc28gaGF2ZSBhbiByLXNxdWFyZWQgdmFsdWVzIHdoaWNoIGFyZSB2ZXJ5IGxvdywgbWVhbmluZyB0aGF0IHRlbXBlcmF0dXJlIGRvZXMgbm90IHRlbGwgdXMgbXVjaCBhYm91dCBpdHMgY29ycmVsYXRpb24gd2l0aCBjb25maXJtZWQgY2FzZXMgYWNyb3NzIGFsbCAzIGRhdGFzZXRzLgoKQWZ0ZXIgbG9va2luZyBhdCBvdXIgZGF0YXNldHMsIG91ciBncmFwaHMgYW5kIHJ1bm5pbmcgbGluZWFyIHJlZ3Jlc3Npb25zIG9uIG91ciBzZXRzLCB3ZSBjYW5ub3QgY29uZmlkZW50bHkgc2F5IHRoYXQgdGhlcmUgaXMgYSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRlbXBlcmF0dXJlIGFuZCB0aGUgYW1vdW50IG9mIGNvbmZpcm1lZCBjYXNlcy4gRnJvbSB0aGUgc21hbGwgZGF0YXNldCwgaXQgaW5pdGlhbGx5IG1heSBoYXZlIHNlZW1lZCB0aGF0IHRoZXJlIGlzIGEgcmVsYXRpb24gYmV0d2VlbiBoaWdoZXIgdGVtcGVyYXR1cmVzIGFuZCBjb25maXJtZWQgY2FzZXMgYnV0IGFzIHdlIHdlbnQgdG8gdGhlIG1lZGl1bSBhbmQgbGFyZ2UgZGF0YXNldHMsIHdlIHdlcmUgdW5hYmxlIHRvIGNvbnRpbnVlIG9uIHdpdGggdGhlIGFzc3VtcHRpb24uIFRoaXMgbWFrZXMgc2Vuc2UsIGFzIG91ciBzbWFsbCBkYXRhIHNldHMgaGF2ZSBhIHNtYWxsZXIgbnVtYmVycyBvZiBjb25maXJtZWQgY2FzZXMgc28gd2UgbWF5IG5vdCBoYXZlIGVub3VnaCBldmlkZW5jZSBpbiB0aGlzIHNldCBpbiBvcmRlciB0byBtYWtlIHByb3BlciBhc3N1bXB0aW9ucy4gT3ZlcmFsbCwgYmFzZWQgb24gb3VyIGV2aWRlbmNlIGFuZCBmaW5kaW5ncywgd2UgY2Fubm90IHNheSB3aXRoIGNvbmZpZGVuY2UgdGhhdCB0aGVyZSBpcyBhIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRlbXBlcmF0dXJlIGFuZCB0aGUgc3ByZWFkIG9mIHRoZSB2aXJ1cy4gT2YgY291cnNlIHNvbWV0aGluZyB0byBub3RlIGlzIHRoYXQgdGhpcyB2aXJ1cyBiZWdhbiB0byBzcHJlYWQgZHVyaW5nIHRoZSBjb29sZXIgbW9udGhzIG9mIHRoZSBtb3N0IGVmZmVjdGVkIGNvdW50cmllcywgc28gaXQgaGFyZCB0byBhbHNvIHRlbGwgaWYgb3VyIGNvbmNsdXNpb25zIGNvdWxkIGhhdmUgYmVlbiBkaWZmZXJlbnQgaWYgdGhpcyB3ZXJlIGhhcHBlbmluZyBhdCBhIGRpZmZlcmVudCB0aW1lIGxpbmUuIAoKCgojIyMgZS4gRG9lcyBQb3B1bGF0aW9uIGhhdmUgYW4gZWZmZWN0IG9uIENPVklELTE5IHZpcnVzID8KClNpbmNlIG91ciBkYXRhc2V0IGhhcyBtdWx0aXBsZSBmaWVsZHMgYW5kIGZvciB0aGUgcHVycG9zZSBvZiB0aGlzIHF1ZXN0dW9uIHdlIHdpbGwgb25seSBiZSBjb25jZXJuZWQgd2l0aCBjb25maXJtZWQgY2FzZWEgYW5kIHRvdGFsIHBvcHVsYXRpb24gYW5kIGRyb3AgZXZlcnl0aGluZyBlbHNlLgoKCmBgYHtyfQpkZiAlPiUgc2VsZWN0KENvdW50cnksYENvbmZpcm1lZCBDYXNlc2AsIGBUb3RhbCBQb3B1bGF0aW9uYCkgJT4lIAogIGFycmFuZ2UoZGVzYyhgVG90YWwgUG9wdWxhdGlvbmApKSAtPiBkZnBvcApoZWFkKGRmcG9wKQpgYGAKCmBgYHtyfQpnZ3Bsb3QoZGZwb3AsIGFlcyh4ID0gYFRvdGFsIFBvcHVsYXRpb25gLCB5ID0gYENvbmZpcm1lZCBDYXNlc2ApKSArZ2VvbV9wb2ludCgpCmBgYAoKCmBgYHtyfQpkZnBvcCAlPiUgCiAgZmlsdGVyKGRmcG9wJGBUb3RhbCBQb3B1bGF0aW9uYCAgPCAxMDAwMDAwKSAtPiBzbWFsbHBvcApoZWFkKHNtYWxscG9wKQpgYGAKCmBgYHtyfQpkZnBvcCAlPiUgCiAgZmlsdGVyKGRmcG9wJGBUb3RhbCBQb3B1bGF0aW9uYCAgPiAxMDAwMDAwLCBkZnBvcCRgVG90YWwgUG9wdWxhdGlvbmAgPCA1MDAwMDAwMCApIC0+IG1lZGl1bXBvcAoKaGVhZChtZWRpdW1wb3ApCmBgYAoKCmBgYHtyfQpkZnBvcCAlPiUgCiAgZmlsdGVyKGRmcG9wJGBUb3RhbCBQb3B1bGF0aW9uYCAgPiA1MDAwMDAwMCApIC0+IGxhcmdlcG9wCmhlYWQobGFyZ2Vwb3ApCmBgYAoKCmBgYHtyfQpnZ3Bsb3Qoc21hbGxwb3AsIGFlcyh4ID0gYFRvdGFsIFBvcHVsYXRpb25gLCB5ID0gYENvbmZpcm1lZCBDYXNlc2ApKSArZ2VvbV9wb2ludCgpCmBgYAoKYGBge3J9CmdncGxvdChtZWRpdW1wb3AsIGFlcyh4ID0gYFRvdGFsIFBvcHVsYXRpb25gLCB5ID0gYENvbmZpcm1lZCBDYXNlc2ApKSArZ2VvbV9wb2ludCgpCmBgYAoKYGBge3J9CmdncGxvdChsYXJnZXBvcCwgYWVzKHggPSBgVG90YWwgUG9wdWxhdGlvbmAsIHkgPSBgQ29uZmlybWVkIENhc2VzYCkpICtnZW9tX3BvaW50KCkKYGBgCgoKRnJvbSBhbGwgdGhyZWUgZ3JvdXBzLCB3ZSBjYW4gc2VlIHRoYXQgdGhlIG1ham9yaXR5IG9mIGNvbmZpcm1lZCBjYXNlcyBhcmUgcmVsYXRpdmVseSBsb3cgd2l0aCByZXNwZWN0IHRvIHRoZSBjb3VudHJpZXMgdG90YWwgcG9wdWxhdGlvbi4gVGhlcmUgYXJlIGEgY291cGxlIG91dGxpZXJzIGluIGVhY2ggZGF0YXNldCBidXQgdGhpcyBjYW4gYmUgZXhwZWN0ZWQuIFRoZXJlIGlzIG5vIHRyZW5kIHRvIHNob3cgdGhhdCBhIGhpZ2hlciBwb3B1bGF0aW9uIGVxdWF0ZXMgdG8gbW9yZSBjb25maXJtZWQgY2FzZXMuCldlIGNhbiBydW4gYSBsaW5lYXIgcmVncmVzc2lvbiBvbmNlIGFnYWluIHRvIHNlZSBpZiB0aGVyZSBpcyBhIHRyZW5kIHRoYXQgd2UgY2Fubm90IGRldGVybWluZSBmcm9tIG91ciBncmFwaHMuCgpgYGB7cn0Kc21hbGxwb3AuMSA8LSBsbShzbWFsbHBvcCRgQ29uZmlybWVkIENhc2VzYCB+IHNtYWxscG9wJGBUb3RhbCBQb3B1bGF0aW9uYCwgZGF0YSA9IHNtYWxscG9wKQpzdW1tYXJ5KHNtYWxscG9wLjEpCmBgYApgYGB7cn0KbWVkaXVtcG9wLjEgPC0gbG0obWVkaXVtcG9wJGBDb25maXJtZWQgQ2FzZXNgIH4gbWVkaXVtcG9wJGBUb3RhbCBQb3B1bGF0aW9uYCwgZGF0YSA9IG1lZGl1bXBvcCkKc3VtbWFyeShtZWRpdW1wb3AuMSkKYGBgCmBgYHtyfQpsYXJnZXBvcC4xIDwtIGxtKGxhcmdlcG9wJGBDb25maXJtZWQgQ2FzZXNgIH4gbGFyZ2Vwb3AkYFRvdGFsIFBvcHVsYXRpb25gLCBkYXRhID0gbGFyZ2Vwb3ApCnN1bW1hcnkobGFyZ2Vwb3AuMSkKYGBgCkJhc2VkIG9uIG91ciBkYXRhIGFib3ZlLCB3ZSBjYW4gY29uY2x1ZGUgdGhhdCBhIGhpZ2hlciBwb3B1bGF0aW9uIGRvZXMgbm90IG5lY2Vzc2FyaWx5IG1lYW4gbW9yZSBjb25maXJtZWQgY2FzZXMuIFRoaXMgY2FuIGJlIGNsZWFybHkgc2hvd24gYnkgbG9va2luZyBhdCBvdXIgZGZwb3AgZGF0YWZyYW1lLiBXZSBjYW4gc2VlIHRoYXQgSW5kaWEJaGFzIGEgdG90YWwgb2YgMTQyIGNvbmZpcm1lZCBjYXNlcyB3aXRoIGEgdG90YWwgcG9wdWxhdGlvbiBvZiAxMzUyNjE3MzI4LCB3aGVyZSBhcyBJdGFseSBoYXMgYSB0b3RhbCBvZiAzMTUwNiBjb25maXJtZWQgY2FzZXMgd2l0aCBhIHRvdGFsIHBvcHVsYXRpb24gb2YgNjA0MzEyODMuIAoKRGVzcGl0ZSBiZWluZyBoYWxmIHRoZSBwb3B1bGF0aW9uIG9mIEluZGlhLCB0aGVyZSBpcyB0ZW5zIG9mIHRob3VzYW5kcyBvZiBtb3JlIGNvbmZpcm1lZCBjYXNlcy4gVGhlcmUgYXJlIGEgbnVtYmVyIG9mIGZhY3RvcnMgd2hpY2ggc2lnbmlmaWNhbnRseSBjb250cmlidXRlIHRoZSBhbW91bnQgb2YgY29uZmlybWVkIGNhc2VzLCBob3dldmVyIGhhdmluZyBtb3JlIHBlb3BsZSBpbiBhIGNvdW50cnkgZG9lcyBub3QgYWx3YXlzIG1lYW4gbW9yZSBwZW9wbGUgaGF2ZSB0aGUgdmlydXMuIFRoZXJlIGlzIGEgYW4gaW5jcmVhc2VkIGxpa2VsaWhvb2Qgb2YgdGhlIHZpcnVzIHNwcmVhZGluZyBmYXN0ZXIsIGlmIHByZWNhdXRpb25zIGFyZSBub3QgdGFrZW4gYnkgdGhlIGdvdmVybm1lbnQgYW5kIHBlb3BsZSwgc3VjaCBpcyB0aGUgY2FzZSBpbiBJdGFseS4gSG93ZXZlciwgdGhlcmUgYXJlIG1hbnkgYWN0aW9ucyBpbmRpdmlkdWFscyBjYW4gdGFrZSBpbiBvcmRlciB0byBzdG9wIHRoZSBzcHJlYWQgb2YgdGhlIHZpcnVzIHNvIHF1aWNrbHksIHN1Y2ggYXMgc29jaWFsIGRpc3RhbmNpbmcsIHNlbGYgcXVhcmFudGluaW5nIGFuZCBwcmFjdGljaW5nIGdvb2QgaHlnaWVuZSBhbmQgY2xlYW5saW5lc3MuIEEgaGlnaCBwb3B1bGF0aW9uIGRvZXNuJ3QgYWx3YXlzIG1lYW4gYSBoaWdoIG51bWJlciBvZiBjb25maXJtZWQgY2FzZXMsIGJ1dCBtb3JlIG9mIGEgcmlzayBvZiBtb3JlIGluZGl2aWR1YWxzIHRvIGNhdGNoIHRoZSB2aXJ1cy4gCgojIyMgQ29uY2x1c2lvbgoKSXQgc2VlbXMgdGhhdCB0aGUgZ2xvYmFsIGZlYXIgb2YgQ09WSUQtMTkgYW5kIGl0J3MgcmFwaWQgaW5jcmVhc2UgaXMgZHVlIHRvIHRoZSBzYW1lIHByb2JsZW0gd2UgZHJldyBmcm9tIGRvaW5nIHRoaXMgcHJvamVjdDsgaXQgaXMgZGlmZmljdWx0IHRvIGNvbnRhaW4gYW4gdW5rbm93biBkaXNlYXNlIGZyb20gc3ByZWFkaW5nIHdoZW4gd2UgY2Fubm90IHByZWRpY3QgaG93IHdlbGwgaXQgdGhyaXZlcyBpbiBpdHMgZW52aXJvbm1lbnQuIE91ciBhbmFseXNpcyBjb3VsZCBub3QgaGVscCB1cyBjb25jbHVkZSBpZiB0ZW1wZXJhdHVyZSBwbGF5ZWQgYW4gZWZmZWN0aXZlIHJvbGUgaW4gY29udHJvbGxpbmcgdGhlIGdyb3d0aCBvZiB0aGUgdmlydXMsIHdpdGggdGhlIG1vc3QgbnVtYmVyIG9mIGNhc2VzIGJlaW5nIGluIENoaW5hIGFuZCB0aGUgbGVhc3QgbnVtYmVyIG9mIGNhc2VzIGJlaW5nIGluIFJlcHVibGljIG9mIENvbmdvLiBBbHRob3VnaCB0aGVyZSBzZWVtZWQgdG8gYmUgc2lnbnMgb2YgdGhlIHZpcnVzIGJlaW5nIGxlc3MgZWZmZWN0aXZlIGluIGhvdHRlciBjbGltYXRlcyB3aGVuIGxvb2tpbmcgYXQgdGhlIGNvdW50cmllcyB3aXRoIHRoZSBsZWFzdCBudW1iZXIgb2YgY2FzdWFsdGllcywgYXMgdGhlIG51bWJlciBvZiB2aWN0aW1zIGdyZXcgZXhwb25lbnRpYWxseSwgdGVtcGVyYXR1cmUncyBlZmZlY3Qgb24gdGhlIGxpZmVzcGFuIG9mIHRoZSB2aXJ1cyBiZWNhbWUgcG9zc2libHkgaW5zaWduaWZpY2FudC4gQW5kIHNpbmNlIHRoaXMgZ3Jvd3RoIGhhcHBlbmVkIGR1cmluZyB0aGUgY29sZGVyIG1vbnRocyBvZiB0aGUgbW9zdCBlZmZlY3RlZCBjb3VudHJpZXMsIGl0IGlzIGV2ZW4gbW9yZSBkaWZmaWN1bHQgdG8gZHJhdyBhbnkgc3Ryb25nIGNvbmNsdXNpb25zLiBJdCBpcyBwb3NzaWJsZSB0aGF0IG9uIGEgZGlmZmVyZW50IHRpbWVsaW5lLCB0aGUgc2NlbmFyaW8gY291bGQgaGF2ZSBiZWVuIGNvbXBsZXRlbHkgZGlmZmVyZW50LCBhbmQgaXQgbWF5IGJlIHN0aWxsIHRvbyBlYXJseSB0byBkcmF3IGFuIG9waW5pb24uIEFzIHdlJ3ZlIHNlZW4gZnJvbSBvdXIgZmlyc3QgZ3JhcGgsIHdlIGhhdmUgeWV0IHRvIHJlYWNoIHdvcmxkd2lkZSBwZWFrLiBTaW1pbGFybHksIHdlIGNvdWxkIG5vdCBjb25jbHVkZSB0aGF0IHRoZSBwb3B1bGF0aW9uIHNpemUgb2YgYSBjb3VudHJ5IGhhZCBhIHBsYXkgaW4gaXRzIHNwcmVhZC4gVGhlcmUgbWF5IGJlIG90aGVyIGZhY3RvcnMgdGhhdCBjb21lIGludG8gcGxheSwgc3VjaCBhcyBhIGNvdW50cnkncyBhZ2UgZGlzdHJpYnV0aW9uLCB0cmF2ZWwgcmVzdHJpY3Rpb25zIGV0Yy4sIHRoYXQgY291bGQgZXhwbGFpbiBpdHMgY3VycmVudCBzdGF0ZS4gRnJvbSByZWNlbnQgZXZlbnRzIHdlIGRvIGtub3cgdGhhdCBpbiBnZW5lcmFsIHRoZSBtb3JlIHBlb3BsZSB0aGF0IGFyZSB0cmF2ZWxpbmcsIHRoZSBtb3JlIHRoZSB2aXJ1cyBpcyBhYmxlIHRvIHNwcmVhZCBieSBjb250YWN0LCB3aXRoIGl0IGJlaW5nIHNvbWV3aGF0IG9mIGEgZG9taW5vIGVmZmVjdC4gU28gb3VyIHNvbHV0aW9uIGhhcyBiZWVuIHRvIGdvIGludG8gcXVhcmFudGluZSBkZXNwaXRlIHdoYXRldmVyIGxldmVsIG9mIGNhc2VzIGluIHRoZSBhcmVhLiBIb3BlZnVsbHkgd2UgY2FuIHNvb24gZXhwZWN0IHRvIGdhdGhlciBlbm91Z2ggZGF0YSB0byBzdWNjZXNzZnVsbHkga25vdyBob3cgdG8gcmVkdWNlIGNhc3VhbHRpZXMgYXJpc2luZyBmcm9tIENPVklELTE5LiAKCgoKCgo=