Research Question

What countries have the most cases of Covid-19? Which ones have the highest mortality rate from Covid-19? Out of those top countries, what were the cases and mortality rates over each month in 2020 since the pandemic hit?

Importance of this Topic

Covid-19 has affected all of our lives for almost 2 years now. It has had many affect on us personally, the Penn State community, our country, and the whole world. However, we often focus on the direct effects on our lives, like online schooling and missing out on things, and we forget how dangerous this virus has been. So, we wanted to further investigate the effects of Covid-19 across the world. We want to see how deadly this disease really is in the United States and in other countries. We want to find out exactly how many people have had it and have unfortunately died from it. We are also curious about the different months of this ongoing pandemic and when it was the deadliest as well as what it is like now. We chose this topic because it is very relevant to us and we are interested in fully understanding the severity of this global pandemic.

Loading Packages

rm(list = ls())
library(tidyverse)
library(rvest)
library(utils)
library(dplyr)

First Data Source

wikipage <- "https://en.wikipedia.org/wiki/Template:COVID-19_pandemic_data"
tableList <- wikipage %>%
  read_html() %>%
  html_nodes(css = "table") %>%
  html_table(fill = TRUE)

CovidByCountry <-
  tableList[[1]] 

#Selecting only columns 2-4 because the rest are empty
CovidByCountry <-
  CovidByCountry[c(2, 3, 4)] 

#Converting Cases and Deaths to numerical values
CovidByCountry <-  
  CovidByCountry %>%
    mutate(Cases = as.numeric(gsub(",", "", Cases)),
           Deaths = as.numeric(gsub(",", "", Deaths)))
Warning: Problem with `mutate()` column `Cases`.
ℹ `Cases = as.numeric(gsub(",", "", Cases))`.
ℹ NAs introduced by coercion
Warning: Problem with `mutate()` column `Deaths`.
ℹ `Deaths = as.numeric(gsub(",", "", Deaths))`.
ℹ NAs introduced by coercion
head(CovidByCountry)
tail(CovidByCountry)
str(CovidByCountry)
tibble [197 × 3] (S3: tbl_df/tbl/data.frame)
 $ Location: chr [1:197] "World[a]" "European Union[b]" "United States" "India" ...
 $ Cases   : num [1:197] 2.71e+08 5.03e+07 5.02e+07 3.47e+07 2.22e+07 ...
 $ Deaths  : num [1:197] 5320822 873736 800343 476135 616970 ...

This data table shows the total covid cases and deaths for every country. It is a grand total from the start of the pandemic. There are 197 cases included in the data, as we can see from using the str() function.

Second Data Source

EuropaData <- read.csv("https://opendata.ecdc.europa.eu/covid19/casedistribution/csv", na.strings = "", fileEncoding = "UTF-8-BOM")
EuropaData
head(EuropaData)
tail(EuropaData)
str(EuropaData)
'data.frame':   61900 obs. of  12 variables:
 $ dateRep                                                   : chr  "14/12/2020" "13/12/2020" "12/12/2020" "11/12/2020" ...
 $ day                                                       : int  14 13 12 11 10 9 8 7 6 5 ...
 $ month                                                     : int  12 12 12 12 12 12 12 12 12 12 ...
 $ year                                                      : int  2020 2020 2020 2020 2020 2020 2020 2020 2020 2020 ...
 $ cases                                                     : int  746 298 113 63 202 135 200 210 234 235 ...
 $ deaths                                                    : int  6 9 11 10 16 13 6 26 10 18 ...
 $ countriesAndTerritories                                   : chr  "Afghanistan" "Afghanistan" "Afghanistan" "Afghanistan" ...
 $ geoId                                                     : chr  "AF" "AF" "AF" "AF" ...
 $ countryterritoryCode                                      : chr  "AFG" "AFG" "AFG" "AFG" ...
 $ popData2019                                               : int  38041757 38041757 38041757 38041757 38041757 38041757 38041757 38041757 38041757 38041757 ...
 $ continentExp                                              : chr  "Asia" "Asia" "Asia" "Asia" ...
 $ Cumulative_number_for_14_days_of_COVID.19_cases_per_100000: num  9.01 7.05 6.87 7.13 6.97 ...

This data table shows the covid cases and deaths every day in each country. This table includes 61,900 objects with 12 variables. Each case describes a country’s cases and deaths on a given day, so there are multiple rows for a single country.

Total Cases and Deaths by Country

#table displaying the sum of all COVID cases per country
EuropaCases <- 
  EuropaData %>%
  group_by(countriesAndTerritories) %>%
  summarise(totalcases = sum(cases)) %>%
  arrange(desc(totalcases))

#table displaying the sum of all COVID deaths per country
EuropaDeaths <- 
  EuropaData %>%
  group_by(countriesAndTerritories) %>%
  summarise(totaldeaths = sum(deaths)) %>%
  arrange(desc(totaldeaths))

#table combining the total cases and total deaths table, then showing the top 10 countries based on total number of cases
EuropaMerge <-
  merge(x=EuropaCases, y = EuropaDeaths, all=TRUE) %>%
  filter(totalcases > 1400000) %>%
  arrange(desc(totalcases))
EuropaMerge

First, we wanted to combine the total number of cases and deaths by country in order to see which country had the highest total case and death counts. This is a good start to help us answer our research question. We created two tables, one for deaths and the other for cases, with the totals of each and the name of the country. Then, we combined these two tables into one.

Total Cases and Deaths by Continent

#table showing the total number of cases and deaths broken up by Continent j
Continenttotals<-
  EuropaData%>%
  group_by(continentExp) %>%
    summarise(TotalCases = sum(cases, na.rm = TRUE), TotalDeaths = sum(deaths, na.rm = TRUE))
  
Continenttotals
Continenttotals %>%
  ggplot(aes(x = continentExp, y = TotalCases)) +
  geom_col(aes(color = continentExp, fill = continentExp))+
  ggtitle("Covid cases in each Continent")


Continenttotals %>%
  ggplot(aes(x = continentExp, y = TotalDeaths)) +
  geom_col(aes(color = continentExp, fill = continentExp))+
  ggtitle("Covid deaths in each Continent")

Next, we wanted to see the total number of deaths and cases per continent to see the spread of COVID worldwide. We visualized this spread in a bar graph, with each bar representing a continent. Obviously, as Antarctica is barren, it would not make sense to include it in the graph.

Visualization of Cases Worldwide in July

#wrangling data to include only dates in July, preventing for outliers 
EuropaData2 <- 
  EuropaData %>%
  filter(grepl("^07", dateRep,  ignore.case = TRUE)) %>%
  filter(cases < 25000)


EuropaData2 %>%
  ggplot(aes(x = continentExp, fill = continentExp)) + 
  geom_density(alpha = .25) + 
  xlab("Continent")

This graph is an example of the amount of times a country is mentioned as having cases in the month of July. We used an overlaid graph to show this.

Top 5 Countries with Highest Case totals

We wanted to find out which 5 countries had the highest number of cases of Covid-19. We excluded the world and European Union totals because we wanted to focus on individual countries. Using, rank we made a table of these top 5 countries. They include the United States, India, Brazil, United Kingdom, and Russia. The United States had the most with 49,833,439 cases. We represented this data visually as well by making a bar graph with the countries on the x-axis and the Cases on the y-axis. The different colors also represent each country.

Top5Cases <-
  CovidByCountry %>%
    filter(Location != "World[a]") %>%
    filter(Location != "European Union[b]") %>%
    filter( rank(desc(Cases)) <= 5 ) %>%
    select(Location, Cases)

Top5Cases

Top5Cases %>%
    ggplot(aes(x = Location, y = Cases)) +
  geom_col(aes(color = Location, fill = Location)) + 
  ggtitle("Highest Number of Cases in Top 5 Countries")

Similarly, we did the same analysis on the total number of deaths. The top 5 countries here included the United States, India, Brazil, Russia, and Mexico. The only countries that are different between the Top5Cases data and the Top5Deaths data is United Kingdom and Mexico. United Kingdom was 4th for the highest cases and Mexico was 5th for the highest deaths. The other 4 countries were included in both tables. The United States was #1 again here with 796,764 deaths. We also made a bar chart for Top5Deaths that represents these 5 countries.

Top5Deaths <-
  CovidByCountry %>%
    filter(Location != "World[a]") %>%
    filter(Location != "European Union[b]") %>%
    filter( rank(desc(Deaths)) <= 5 ) %>%
    select(Location, Deaths)

Top5Deaths

Top5Deaths %>%
    ggplot(aes(x = Location, y = Deaths)) +
  geom_col(aes(color = Location, fill = Location)) + 
  ggtitle("Highest Number of Deaths in Top 5 Countries")

Mortality Rate

To answer part of our research question, “Which countries have the highest mortality rates of Covid-19?”, we used the first data set to compare the ratio of deaths to cases for each country. We added a variable “ratio” to represent the mortality rate. To calculate this value, we divided the number of deaths by the number of cases for each country. We then ranked the countries based off which ones had the highest mortality rates. We got rid of 2 rows that represented the whole world and the whole European Union since we are only interested in individual countries. Then, we made a scatterplot of each country’s mortality rate to compare them. The x-axis represents the countries and the y-axis represents the mortality rate. We also used the variable Deaths to represent the size of each point. The graph shows us that most mortality rates were below .05, or 5%, with very few countries going above that. The highest mortality rate is about 19%. However, the highest mortality rate is represented by a very small dot, meaning there were very few deaths in that country. This is interesting because this shows that even though this country has the highest mortality rate, it has very few deaths. This is an indicator that this may be an outlier.

MortalityRate <-
  CovidByCountry %>%
    group_by(Location) %>%
    mutate(ratio = Deaths/Cases)

MortalityRate

HighestMortalityRates <-
  MortalityRate %>%
    filter(Location != "World[a]") %>%
    filter(Location != "European Union[b]")

HighestMortalityRates$rank <- rank(HighestMortalityRates$ratio)

HighestMortalityRates <-  
  HighestMortalityRates %>%
    na.omit(ratio) %>%
    arrange(desc(rank)) 

HighestMortalityRates

TotalMortalityRates <-
  HighestMortalityRates %>%
    ggplot(aes(x = Location, y = ratio)) +
    geom_point(aes(size = Deaths)) +
    ggtitle("Mortality Rates of Covid-19") + 
    xlab("Mortality Rate") +
    ylab("Country")
TotalMortalityRates

After looking at the overall mortality rates, we wanted to focus in on the top 5 highest ones. To do this, we filtered out the ones with the highest ratio values and put those into a separate table. Then, we made a bar graph showing these 5 countries and their mortality rates. The top 5 countries included Yemen, Vanuatu, Peru, Mexico, and Sudan. The highest mortality right was .19510740, or about 19.5%, which was in Yemen.

Top5HighestMortalityRates <-
  HighestMortalityRates %>%
    filter(rank >= 185) #Since there are 189 countries with values in 'ratio' we want ones with rank greater than or equal to 185.

Top5HighestMortalityRates

Top5HighestMortalityRates %>%
  ggplot(aes(x = Location, y = ratio)) +
  geom_col(aes(color = Location, fill = Location)) +
  ggtitle("Highest 5 Mortality Rates of Covid-19") +
  xlab("Mortality Rate") +
  ylab("Country")

Calculating Average Mortality Rate

To further our investigation of the mortality rate of Covid-19, we wanted to explore the average mortality rate. To simply find the mean of all the cases, we used the mean() function. The mean of all of the ratio variables is 0.02102764. After examining the scatterplot we created, we wanted to try to get rid of outliers or countries with very few amounts of cases. For example, Yemen had the highest mortality rate but one of the number of deaths. So, we filtered out cases that had less than 100 cases of Covid-19. Then, we used a for loop to go through the countries with more than 100 cases and add the ratio variable to a new variable, “avg”. We also had to keep track of how many countries there were with this condition in a variable “index” in order to be able to calculate the average. After the for loop ran, we simply divided “avg” by “index” to get the average mortality rate for countries with more than 100 cases of Covid-19. The result was 0.02058139, which is lower than the original mean. The change was not as significant as we thought it may be, but there was still about a .05% difference.

#Finding mean mortality rate with all data included
mean(HighestMortalityRates$ratio)
[1] 0.02084382
#Finding mean mortality rate with only countries with more than 100 cases of Covid-19
CasesOver100 <-
  HighestMortalityRates %>%
    filter(Cases > 100)
avg = 0
index = 0
for (i in CasesOver100$ratio) {
    avg <- avg + i
    index <- index + 1
}
avg <- avg/index
avg
[1] 0.0205223

Monthly Cases and Deaths

We decided to analyze the Covid-19 cases and deaths for the year 2020 in the countries with the most amount of cases and deaths. To do this, we first selected the United States, India and Brazil because from our previous findings, they have the most cases. We grouped them by month in order to see the changes. We were able to see the monthly cases and deaths for the three countries.

USAmonthly<-
  EuropaData%>%
    filter(countriesAndTerritories== "United_States_of_America")%>%
  group_by(month) %>%
    summarise(Monthlycases = sum(cases, na.rm = TRUE),  Monthlydeaths = sum(deaths, na.rm = TRUE))%>%
  mutate(Country="USA")

Indiamonthly<-
  EuropaData%>%
    filter(countriesAndTerritories== "India")%>%
  group_by(month) %>%
    summarise(Monthlycases = sum(cases, na.rm = TRUE),  Monthlydeaths = sum(deaths, na.rm = TRUE))%>%
  mutate(Country="India")

Brazilmonthly<-
  EuropaData%>%
    filter(countriesAndTerritories== "Brazil")%>%
  group_by(month) %>%
    summarise(Monthlycases = sum(cases, na.rm = TRUE),  Monthlydeaths = sum(deaths, na.rm = TRUE))%>%
  mutate(Country="Brazil")

Merging tables

We merged the tables for the top 3 countries cases and deaths so we could graph them.

Firstmerge<-
  merge(x=USAmonthly, y=Indiamonthly, all=TRUE)

Top3<-
  merge(x=Firstmerge, y=Brazilmonthly, all=TRUE)

Graphing the top three countries

We graphed the top three countries with Covid cases. USA, Brazil and India are represented by the different lines, respectively. The cases are graphed over time in 2020. United States had a spike in November and India had a spike in September. Overall, the cases have been increasing since the pandemic started and at the end of the year they have slightly gone down as the pandemic has gotten under control.

Top3%>%
  ggplot(aes(x=month, y=Monthlycases)) +
  geom_line(aes(linetype=Country, color=Country))+
  xlab("Month")+
  ylab("Cases")+
  ggtitle("Monthly Covid Cases for the Top Three Countries in 2020")+
  xlim(0,12)

We graphed the top three countries with Covid deaths. USA, Brazil and India are represented by their respective lines here as well. The cases are graphed over time in 2020. There was a spike in USA cases in April as the pandemic was new and unmanageable at the time. The deaths increases for all of the countries in the summer as the pandemic picked up speed. Over the year 2020, the hospitals regained control and the deaths decreased.

Top3%>%
  ggplot(aes(x=month, y=Monthlydeaths)) +
  geom_line(aes(linetype=Country, color=Country))+
  xlab("Month")+
  ylab("Deaths")+
  ggtitle("Monthly Covid Deaths for the Top Three Countries in 2020")+
  xlim(0,12)

Challenges we encountered

One of the main technical challenges we had to overcome was when we were trying to rank the countries from the first data source by their mortality rate. This is in the section entitled “Mortality Rate”. At first, after we used mutate() to add the “ratio” variable we tried to use filter(rank(desc(ratio) >= 5)) on order to get the top 5 highest mortality rates. However, the order of the countries was not resulting in descending ratios. We could not discover the root of this problem even after asking for help. It may have been because the ratios are all decimals, but we are still unsure. To overcome this issue, we had to change how we were going to complete the task of finding which countries had the highest mortality rates. So, instead of using the rank() function, we had to create a new variable in the HighestMortalityRates table called “rank”. The values of this new variable are the rankings of the countries from lowest to highest mortality rates. We did this by doing HighestMortalityRates\(rank <- rank(HighestMortalityRates\)ratio). Once we had this new variable we used the arrange() function to order the country by their rankings. Finally, we were able to find the top 5 by filtering the countries with ranks greater than or equal to 185, since there were a total of 189 countries and the ranking was from lowest to highest mortality rates. Another challenge we had was with our first data source. We were querying with the numbers in this data set and we were not getting the correct results. We then realized that the variables Cases and Deaths were type instead of . To overcome this issue, we used as.numeric() to convert the data from characters to numerical types. The original numbers also contained commas in the character strings, so we had to use the gsub() function, which is a regular expression, to get rid of the commas before converting the data types.

Significant Findings and Conclusion

In analyzing the Covid-19 data sets, we were able to draw conclusions based on our findings. Our first step was finding the countries with the highest Covid-19 cases. These countries, in descending order, were United States, India, Brazil, United Kingdom and Russia. One reason these countries could have the highest amount of cases is their large populations. When looking at the countries with the most deaths, the results were similar. The countries with the top 5 Covid-19 death count are the United States, India, Brazil, Russia and Mexico. The top countries for cases and deaths are very similar with the exception that the United Kingdom replaced Mexico on the top deaths list. To get an accurate depiction of countries who struggle with the pandemic and losing people to Covid-19, we calculated the mortality rates. The countries with the highest mortality rates are Yemen, Vanuatu, Peru, Mexico and Sudan. A reason that these countries have high mortality rates are they don’t have the resources or healthcare system to keep up with the pandemic. Further analysis on the countries healthcare and economic system as well as the standard of living would be needed to understand why those countries have higher mortality rates. We calculated the overall mortality rate of the globe for Covid-19. The result was 2.05%, which is relatively low. With modern medicine, most people survived Covid-19. Additionally, we wanted to graph out the countries with the highest amount of cases and deaths in 2020 to see trends in the pandemic. We choose the top three countries with cases and deaths as they were heavily impacted by the pandemic. For the cases graph, all of the countries were steadily increasing the amount of cases over the summer. The number of Brazil cases began to regain control in August and the India cases started to decline in September. The United States had large spiked in July and November as they struggle to keep the amount of cases under control despite enforcing masking requirements. For the deaths graph, the United States had a gigantic spike in April. This is when the county was on complete lock down because the hospitals were overcrowding and it was difficult to keep the patients alive. The deaths for India and Brazil steadily increased when the pandemic started. Over the summer, the death counts steadied out as the hospitals were able to manage the patients. At the end of the year, death counts declined. The death counts continue to decline since the vaccine was released to the public, saving many from Covid-19.

LS0tCnRpdGxlOiAiRmluYWwgUHJvamVjdCBSZXBvcnQiCmF1dGhvcjogIkFubmEgR2lsbGFyZCwgS2F0aWUgS2VsbHksIEtlbGx5IE1jVmVpZ2giCmRhdGU6ICJEdWU6IERlY2VtYmVyIDE1LCAyMDIxIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgoKIyMjIFJlc2VhcmNoIFF1ZXN0aW9uCgpXaGF0IGNvdW50cmllcyBoYXZlIHRoZSBtb3N0IGNhc2VzIG9mIENvdmlkLTE5PyBXaGljaCBvbmVzIGhhdmUgdGhlIGhpZ2hlc3QgbW9ydGFsaXR5IHJhdGUgZnJvbSBDb3ZpZC0xOT8gT3V0IG9mIHRob3NlIHRvcCBjb3VudHJpZXMsIHdoYXQgd2VyZSB0aGUgY2FzZXMgYW5kIG1vcnRhbGl0eSByYXRlcyBvdmVyIGVhY2ggbW9udGggaW4gMjAyMCBzaW5jZSB0aGUgcGFuZGVtaWMgaGl0PyAKCiMjIyBJbXBvcnRhbmNlIG9mIHRoaXMgVG9waWMKQ292aWQtMTkgaGFzIGFmZmVjdGVkIGFsbCBvZiBvdXIgbGl2ZXMgZm9yIGFsbW9zdCAyIHllYXJzIG5vdy4gSXQgaGFzIGhhZCBtYW55IGFmZmVjdCBvbiB1cyBwZXJzb25hbGx5LCB0aGUgUGVubiBTdGF0ZSBjb21tdW5pdHksIG91ciBjb3VudHJ5LCBhbmQgdGhlIHdob2xlIHdvcmxkLiBIb3dldmVyLCB3ZSBvZnRlbiBmb2N1cyBvbiB0aGUgZGlyZWN0IGVmZmVjdHMgb24gb3VyIGxpdmVzLCBsaWtlIG9ubGluZSBzY2hvb2xpbmcgYW5kIG1pc3Npbmcgb3V0IG9uIHRoaW5ncywgYW5kIHdlIGZvcmdldCBob3cgZGFuZ2Vyb3VzIHRoaXMgdmlydXMgaGFzIGJlZW4uIFNvLCB3ZSB3YW50ZWQgdG8gZnVydGhlciBpbnZlc3RpZ2F0ZSB0aGUgZWZmZWN0cyBvZiBDb3ZpZC0xOSBhY3Jvc3MgdGhlIHdvcmxkLiBXZSB3YW50IHRvIHNlZSBob3cgZGVhZGx5IHRoaXMgZGlzZWFzZSByZWFsbHkgaXMgaW4gdGhlIFVuaXRlZCBTdGF0ZXMgYW5kIGluIG90aGVyIGNvdW50cmllcy4gV2Ugd2FudCB0byBmaW5kIG91dCBleGFjdGx5IGhvdyBtYW55IHBlb3BsZSBoYXZlIGhhZCBpdCBhbmQgaGF2ZSB1bmZvcnR1bmF0ZWx5IGRpZWQgZnJvbSBpdC4gV2UgYXJlIGFsc28gY3VyaW91cyBhYm91dCB0aGUgZGlmZmVyZW50IG1vbnRocyBvZiB0aGlzIG9uZ29pbmcgcGFuZGVtaWMgYW5kIHdoZW4gaXQgd2FzIHRoZSBkZWFkbGllc3QgYXMgd2VsbCBhcyB3aGF0IGl0IGlzIGxpa2Ugbm93LiBXZSBjaG9zZSB0aGlzIHRvcGljIGJlY2F1c2UgaXQgaXMgdmVyeSByZWxldmFudCB0byB1cyBhbmQgd2UgYXJlIGludGVyZXN0ZWQgaW4gZnVsbHkgdW5kZXJzdGFuZGluZyB0aGUgc2V2ZXJpdHkgb2YgdGhpcyBnbG9iYWwgcGFuZGVtaWMuIAoKCiMjIyBMb2FkaW5nIFBhY2thZ2VzCmBgYHtyfQpybShsaXN0ID0gbHMoKSkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkocnZlc3QpCmxpYnJhcnkodXRpbHMpCmxpYnJhcnkoZHBseXIpCmBgYAoKCiMjIyBGaXJzdCBEYXRhIFNvdXJjZQpgYGB7cn0Kd2lraXBhZ2UgPC0gImh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1RlbXBsYXRlOkNPVklELTE5X3BhbmRlbWljX2RhdGEiCnRhYmxlTGlzdCA8LSB3aWtpcGFnZSAlPiUKICByZWFkX2h0bWwoKSAlPiUKICBodG1sX25vZGVzKGNzcyA9ICJ0YWJsZSIpICU+JQogIGh0bWxfdGFibGUoZmlsbCA9IFRSVUUpCgpDb3ZpZEJ5Q291bnRyeSA8LQogIHRhYmxlTGlzdFtbMV1dIAoKI1NlbGVjdGluZyBvbmx5IGNvbHVtbnMgMi00IGJlY2F1c2UgdGhlIHJlc3QgYXJlIGVtcHR5CkNvdmlkQnlDb3VudHJ5IDwtCiAgQ292aWRCeUNvdW50cnlbYygyLCAzLCA0KV0gCgojQ29udmVydGluZyBDYXNlcyBhbmQgRGVhdGhzIHRvIG51bWVyaWNhbCB2YWx1ZXMKQ292aWRCeUNvdW50cnkgPC0gIAogIENvdmlkQnlDb3VudHJ5ICU+JQogICAgbXV0YXRlKENhc2VzID0gYXMubnVtZXJpYyhnc3ViKCIsIiwgIiIsIENhc2VzKSksCiAgICAgICAgICAgRGVhdGhzID0gYXMubnVtZXJpYyhnc3ViKCIsIiwgIiIsIERlYXRocykpKQoKaGVhZChDb3ZpZEJ5Q291bnRyeSkKdGFpbChDb3ZpZEJ5Q291bnRyeSkKc3RyKENvdmlkQnlDb3VudHJ5KQpgYGAKVGhpcyBkYXRhIHRhYmxlIHNob3dzIHRoZSB0b3RhbCBjb3ZpZCBjYXNlcyBhbmQgZGVhdGhzIGZvciBldmVyeSBjb3VudHJ5LiBJdCBpcyBhIGdyYW5kIHRvdGFsIGZyb20gdGhlIHN0YXJ0IG9mIHRoZSBwYW5kZW1pYy4gVGhlcmUgYXJlIDE5NyBjYXNlcyBpbmNsdWRlZCBpbiB0aGUgZGF0YSwgYXMgd2UgY2FuIHNlZSBmcm9tIHVzaW5nIHRoZSBzdHIoKSBmdW5jdGlvbi4gCgoKIyMjIFNlY29uZCBEYXRhIFNvdXJjZSAKYGBge3J9CkV1cm9wYURhdGEgPC0gcmVhZC5jc3YoImh0dHBzOi8vb3BlbmRhdGEuZWNkYy5ldXJvcGEuZXUvY292aWQxOS9jYXNlZGlzdHJpYnV0aW9uL2NzdiIsIG5hLnN0cmluZ3MgPSAiIiwgZmlsZUVuY29kaW5nID0gIlVURi04LUJPTSIpCkV1cm9wYURhdGEKaGVhZChFdXJvcGFEYXRhKQp0YWlsKEV1cm9wYURhdGEpCnN0cihFdXJvcGFEYXRhKQpgYGAKVGhpcyBkYXRhIHRhYmxlIHNob3dzIHRoZSBjb3ZpZCBjYXNlcyBhbmQgZGVhdGhzIGV2ZXJ5IGRheSBpbiBlYWNoIGNvdW50cnkuIFRoaXMgdGFibGUgaW5jbHVkZXMgNjEsOTAwIG9iamVjdHMgd2l0aCAxMiB2YXJpYWJsZXMuIEVhY2ggY2FzZSBkZXNjcmliZXMgYSBjb3VudHJ5J3MgY2FzZXMgYW5kIGRlYXRocyBvbiBhIGdpdmVuIGRheSwgc28gdGhlcmUgYXJlIG11bHRpcGxlIHJvd3MgZm9yIGEgc2luZ2xlIGNvdW50cnkuCgojIyMgVG90YWwgQ2FzZXMgYW5kIERlYXRocyBieSBDb3VudHJ5CmBgYHtyfQojdGFibGUgZGlzcGxheWluZyB0aGUgc3VtIG9mIGFsbCBDT1ZJRCBjYXNlcyBwZXIgY291bnRyeQpFdXJvcGFDYXNlcyA8LSAKICBFdXJvcGFEYXRhICU+JQogIGdyb3VwX2J5KGNvdW50cmllc0FuZFRlcnJpdG9yaWVzKSAlPiUKICBzdW1tYXJpc2UodG90YWxjYXNlcyA9IHN1bShjYXNlcykpICU+JQogIGFycmFuZ2UoZGVzYyh0b3RhbGNhc2VzKSkKCiN0YWJsZSBkaXNwbGF5aW5nIHRoZSBzdW0gb2YgYWxsIENPVklEIGRlYXRocyBwZXIgY291bnRyeQpFdXJvcGFEZWF0aHMgPC0gCiAgRXVyb3BhRGF0YSAlPiUKICBncm91cF9ieShjb3VudHJpZXNBbmRUZXJyaXRvcmllcykgJT4lCiAgc3VtbWFyaXNlKHRvdGFsZGVhdGhzID0gc3VtKGRlYXRocykpICU+JQogIGFycmFuZ2UoZGVzYyh0b3RhbGRlYXRocykpCgojdGFibGUgY29tYmluaW5nIHRoZSB0b3RhbCBjYXNlcyBhbmQgdG90YWwgZGVhdGhzIHRhYmxlLCB0aGVuIHNob3dpbmcgdGhlIHRvcCAxMCBjb3VudHJpZXMgYmFzZWQgb24gdG90YWwgbnVtYmVyIG9mIGNhc2VzCkV1cm9wYU1lcmdlIDwtCiAgbWVyZ2UoeD1FdXJvcGFDYXNlcywgeSA9IEV1cm9wYURlYXRocywgYWxsPVRSVUUpICU+JQogIGZpbHRlcih0b3RhbGNhc2VzID4gMTQwMDAwMCkgJT4lCiAgYXJyYW5nZShkZXNjKHRvdGFsY2FzZXMpKQpFdXJvcGFNZXJnZQpgYGAKRmlyc3QsIHdlIHdhbnRlZCB0byBjb21iaW5lIHRoZSB0b3RhbCBudW1iZXIgb2YgY2FzZXMgYW5kIGRlYXRocyBieSBjb3VudHJ5IGluIG9yZGVyIHRvIHNlZSB3aGljaCBjb3VudHJ5IGhhZCB0aGUgaGlnaGVzdCB0b3RhbCBjYXNlIGFuZCBkZWF0aCBjb3VudHMuIFRoaXMgaXMgYSBnb29kIHN0YXJ0IHRvIGhlbHAgdXMgYW5zd2VyIG91ciByZXNlYXJjaCBxdWVzdGlvbi4gV2UgY3JlYXRlZCB0d28gdGFibGVzLCBvbmUgZm9yIGRlYXRocyBhbmQgdGhlIG90aGVyIGZvciBjYXNlcywgd2l0aCB0aGUgdG90YWxzIG9mIGVhY2ggYW5kIHRoZSBuYW1lIG9mIHRoZSBjb3VudHJ5LiBUaGVuLCB3ZSBjb21iaW5lZCB0aGVzZSB0d28gdGFibGVzIGludG8gb25lLiAKCiMjIyBUb3RhbCBDYXNlcyBhbmQgRGVhdGhzIGJ5IENvbnRpbmVudApgYGB7cn0KI3RhYmxlIHNob3dpbmcgdGhlIHRvdGFsIG51bWJlciBvZiBjYXNlcyBhbmQgZGVhdGhzIGJyb2tlbiB1cCBieSBDb250aW5lbnQgagpDb250aW5lbnR0b3RhbHM8LQogIEV1cm9wYURhdGElPiUKICBncm91cF9ieShjb250aW5lbnRFeHApICU+JQoJc3VtbWFyaXNlKFRvdGFsQ2FzZXMgPSBzdW0oY2FzZXMsIG5hLnJtID0gVFJVRSksIFRvdGFsRGVhdGhzID0gc3VtKGRlYXRocywgbmEucm0gPSBUUlVFKSkKICAKQ29udGluZW50dG90YWxzCmBgYAoKCmBgYHtyfQpDb250aW5lbnR0b3RhbHMgJT4lCiAgZ2dwbG90KGFlcyh4ID0gY29udGluZW50RXhwLCB5ID0gVG90YWxDYXNlcykpICsKICBnZW9tX2NvbChhZXMoY29sb3IgPSBjb250aW5lbnRFeHAsIGZpbGwgPSBjb250aW5lbnRFeHApKSsKICBnZ3RpdGxlKCJDb3ZpZCBjYXNlcyBpbiBlYWNoIENvbnRpbmVudCIpCgpDb250aW5lbnR0b3RhbHMgJT4lCiAgZ2dwbG90KGFlcyh4ID0gY29udGluZW50RXhwLCB5ID0gVG90YWxEZWF0aHMpKSArCiAgZ2VvbV9jb2woYWVzKGNvbG9yID0gY29udGluZW50RXhwLCBmaWxsID0gY29udGluZW50RXhwKSkrCiAgZ2d0aXRsZSgiQ292aWQgZGVhdGhzIGluIGVhY2ggQ29udGluZW50IikKYGBgCk5leHQsIHdlIHdhbnRlZCB0byBzZWUgdGhlIHRvdGFsIG51bWJlciBvZiBkZWF0aHMgYW5kIGNhc2VzIHBlciBjb250aW5lbnQgdG8gc2VlIHRoZSBzcHJlYWQgb2YgQ09WSUQgd29ybGR3aWRlLiBXZSB2aXN1YWxpemVkIHRoaXMgc3ByZWFkIGluIGEgYmFyIGdyYXBoLCB3aXRoIGVhY2ggYmFyIHJlcHJlc2VudGluZyBhIGNvbnRpbmVudC4gT2J2aW91c2x5LCBhcyBBbnRhcmN0aWNhIGlzIGJhcnJlbiwgaXQgd291bGQgbm90IG1ha2Ugc2Vuc2UgdG8gaW5jbHVkZSBpdCBpbiB0aGUgZ3JhcGguIAoKIyMjIFZpc3VhbGl6YXRpb24gb2YgQ2FzZXMgV29ybGR3aWRlIGluIEp1bHkgCmBgYHtyfQojd3JhbmdsaW5nIGRhdGEgdG8gaW5jbHVkZSBvbmx5IGRhdGVzIGluIEp1bHksIHByZXZlbnRpbmcgZm9yIG91dGxpZXJzIApFdXJvcGFEYXRhMiA8LSAKICBFdXJvcGFEYXRhICU+JQogIGZpbHRlcihncmVwbCgiXjA3IiwgZGF0ZVJlcCwgIGlnbm9yZS5jYXNlID0gVFJVRSkpICU+JQogIGZpbHRlcihjYXNlcyA8IDI1MDAwKQoKCkV1cm9wYURhdGEyICU+JQogIGdncGxvdChhZXMoeCA9IGNvbnRpbmVudEV4cCwgZmlsbCA9IGNvbnRpbmVudEV4cCkpICsgCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gLjI1KSArIAogIHhsYWIoIkNvbnRpbmVudCIpCmBgYCAgClRoaXMgZ3JhcGggaXMgYW4gZXhhbXBsZSBvZiB0aGUgYW1vdW50IG9mIHRpbWVzIGEgY291bnRyeSBpcyBtZW50aW9uZWQgYXMgaGF2aW5nIGNhc2VzIGluIHRoZSBtb250aCBvZiBKdWx5LiBXZSB1c2VkIGFuIG92ZXJsYWlkIGdyYXBoIHRvIHNob3cgdGhpcy4gCgojIyMgVG9wIDUgQ291bnRyaWVzIHdpdGggSGlnaGVzdCBDYXNlIHRvdGFscwpXZSB3YW50ZWQgdG8gZmluZCBvdXQgd2hpY2ggNSBjb3VudHJpZXMgaGFkIHRoZSBoaWdoZXN0IG51bWJlciBvZiBjYXNlcyBvZiBDb3ZpZC0xOS4gV2UgZXhjbHVkZWQgdGhlIHdvcmxkIGFuZCBFdXJvcGVhbiBVbmlvbiB0b3RhbHMgYmVjYXVzZSB3ZSB3YW50ZWQgdG8gZm9jdXMgb24gaW5kaXZpZHVhbCBjb3VudHJpZXMuIFVzaW5nLCByYW5rIHdlIG1hZGUgYSB0YWJsZSBvZiB0aGVzZSB0b3AgNSBjb3VudHJpZXMuIFRoZXkgaW5jbHVkZSB0aGUgVW5pdGVkIFN0YXRlcywgSW5kaWEsIEJyYXppbCwgVW5pdGVkIEtpbmdkb20sIGFuZCBSdXNzaWEuIFRoZSBVbml0ZWQgU3RhdGVzIGhhZCB0aGUgbW9zdCB3aXRoIDQ5LDgzMyw0MzkgY2FzZXMuIFdlIHJlcHJlc2VudGVkIHRoaXMgZGF0YSB2aXN1YWxseSBhcyB3ZWxsIGJ5IG1ha2luZyBhIGJhciBncmFwaCB3aXRoIHRoZSBjb3VudHJpZXMgb24gdGhlIHgtYXhpcyBhbmQgdGhlIENhc2VzIG9uIHRoZSB5LWF4aXMuIFRoZSBkaWZmZXJlbnQgY29sb3JzIGFsc28gcmVwcmVzZW50IGVhY2ggY291bnRyeS4gCmBgYHtyfQpUb3A1Q2FzZXMgPC0KICBDb3ZpZEJ5Q291bnRyeSAlPiUKICAgIGZpbHRlcihMb2NhdGlvbiAhPSAiV29ybGRbYV0iKSAlPiUKICAgIGZpbHRlcihMb2NhdGlvbiAhPSAiRXVyb3BlYW4gVW5pb25bYl0iKSAlPiUKICAgIGZpbHRlciggcmFuayhkZXNjKENhc2VzKSkgPD0gNSApICU+JQogICAgc2VsZWN0KExvY2F0aW9uLCBDYXNlcykKClRvcDVDYXNlcwoKVG9wNUNhc2VzICU+JQoJZ2dwbG90KGFlcyh4ID0gTG9jYXRpb24sIHkgPSBDYXNlcykpICsKICBnZW9tX2NvbChhZXMoY29sb3IgPSBMb2NhdGlvbiwgZmlsbCA9IExvY2F0aW9uKSkgKyAKICBnZ3RpdGxlKCJIaWdoZXN0IE51bWJlciBvZiBDYXNlcyBpbiBUb3AgNSBDb3VudHJpZXMiKQpgYGAKClNpbWlsYXJseSwgd2UgZGlkIHRoZSBzYW1lIGFuYWx5c2lzIG9uIHRoZSB0b3RhbCBudW1iZXIgb2YgZGVhdGhzLiBUaGUgdG9wIDUgY291bnRyaWVzIGhlcmUgaW5jbHVkZWQgdGhlIFVuaXRlZCBTdGF0ZXMsIEluZGlhLCBCcmF6aWwsIFJ1c3NpYSwgYW5kIE1leGljby4gVGhlIG9ubHkgY291bnRyaWVzIHRoYXQgYXJlIGRpZmZlcmVudCBiZXR3ZWVuIHRoZSBUb3A1Q2FzZXMgZGF0YSBhbmQgdGhlIFRvcDVEZWF0aHMgZGF0YSBpcyBVbml0ZWQgS2luZ2RvbSBhbmQgTWV4aWNvLiBVbml0ZWQgS2luZ2RvbSB3YXMgNHRoIGZvciB0aGUgaGlnaGVzdCBjYXNlcyBhbmQgTWV4aWNvIHdhcyA1dGggZm9yIHRoZSBoaWdoZXN0IGRlYXRocy4gVGhlIG90aGVyIDQgY291bnRyaWVzIHdlcmUgaW5jbHVkZWQgaW4gYm90aCB0YWJsZXMuIFRoZSBVbml0ZWQgU3RhdGVzIHdhcyAjMSBhZ2FpbiBoZXJlIHdpdGggNzk2LDc2NCBkZWF0aHMuIFdlIGFsc28gbWFkZSBhIGJhciBjaGFydCBmb3IgVG9wNURlYXRocyB0aGF0IHJlcHJlc2VudHMgdGhlc2UgNSBjb3VudHJpZXMuIApgYGB7cn0KVG9wNURlYXRocyA8LQogIENvdmlkQnlDb3VudHJ5ICU+JQogICAgZmlsdGVyKExvY2F0aW9uICE9ICJXb3JsZFthXSIpICU+JQogICAgZmlsdGVyKExvY2F0aW9uICE9ICJFdXJvcGVhbiBVbmlvbltiXSIpICU+JQogICAgZmlsdGVyKCByYW5rKGRlc2MoRGVhdGhzKSkgPD0gNSApICU+JQogICAgc2VsZWN0KExvY2F0aW9uLCBEZWF0aHMpCgpUb3A1RGVhdGhzCgpUb3A1RGVhdGhzICU+JQoJZ2dwbG90KGFlcyh4ID0gTG9jYXRpb24sIHkgPSBEZWF0aHMpKSArCiAgZ2VvbV9jb2woYWVzKGNvbG9yID0gTG9jYXRpb24sIGZpbGwgPSBMb2NhdGlvbikpICsgCiAgZ2d0aXRsZSgiSGlnaGVzdCBOdW1iZXIgb2YgRGVhdGhzIGluIFRvcCA1IENvdW50cmllcyIpCmBgYAoKCiMjIyBNb3J0YWxpdHkgUmF0ZSAKVG8gYW5zd2VyIHBhcnQgb2Ygb3VyIHJlc2VhcmNoIHF1ZXN0aW9uLCAiV2hpY2ggY291bnRyaWVzIGhhdmUgdGhlIGhpZ2hlc3QgbW9ydGFsaXR5IHJhdGVzIG9mIENvdmlkLTE5PyIsIHdlIHVzZWQgdGhlIGZpcnN0IGRhdGEgc2V0IHRvIGNvbXBhcmUgdGhlIHJhdGlvIG9mIGRlYXRocyB0byBjYXNlcyBmb3IgZWFjaCBjb3VudHJ5LiBXZSBhZGRlZCBhIHZhcmlhYmxlICJyYXRpbyIgdG8gcmVwcmVzZW50IHRoZSBtb3J0YWxpdHkgcmF0ZS4gVG8gY2FsY3VsYXRlIHRoaXMgdmFsdWUsIHdlIGRpdmlkZWQgdGhlIG51bWJlciBvZiBkZWF0aHMgYnkgdGhlIG51bWJlciBvZiBjYXNlcyBmb3IgZWFjaCBjb3VudHJ5LiBXZSB0aGVuIHJhbmtlZCB0aGUgY291bnRyaWVzIGJhc2VkIG9mZiB3aGljaCBvbmVzIGhhZCB0aGUgaGlnaGVzdCBtb3J0YWxpdHkgcmF0ZXMuIFdlIGdvdCByaWQgb2YgMiByb3dzIHRoYXQgcmVwcmVzZW50ZWQgdGhlIHdob2xlIHdvcmxkIGFuZCB0aGUgd2hvbGUgRXVyb3BlYW4gVW5pb24gc2luY2Ugd2UgYXJlIG9ubHkgaW50ZXJlc3RlZCBpbiBpbmRpdmlkdWFsIGNvdW50cmllcy4gVGhlbiwgd2UgbWFkZSBhIHNjYXR0ZXJwbG90IG9mIGVhY2ggY291bnRyeSdzIG1vcnRhbGl0eSByYXRlIHRvIGNvbXBhcmUgdGhlbS4gVGhlIHgtYXhpcyByZXByZXNlbnRzIHRoZSBjb3VudHJpZXMgYW5kIHRoZSB5LWF4aXMgcmVwcmVzZW50cyB0aGUgbW9ydGFsaXR5IHJhdGUuIFdlIGFsc28gdXNlZCB0aGUgdmFyaWFibGUgRGVhdGhzIHRvIHJlcHJlc2VudCB0aGUgc2l6ZSBvZiBlYWNoIHBvaW50LiBUaGUgZ3JhcGggc2hvd3MgdXMgdGhhdCBtb3N0IG1vcnRhbGl0eSByYXRlcyB3ZXJlIGJlbG93IC4wNSwgb3IgNSUsIHdpdGggdmVyeSBmZXcgY291bnRyaWVzIGdvaW5nIGFib3ZlIHRoYXQuIFRoZSBoaWdoZXN0IG1vcnRhbGl0eSByYXRlIGlzIGFib3V0IDE5JS4gSG93ZXZlciwgdGhlIGhpZ2hlc3QgbW9ydGFsaXR5IHJhdGUgaXMgcmVwcmVzZW50ZWQgYnkgYSB2ZXJ5IHNtYWxsIGRvdCwgbWVhbmluZyB0aGVyZSB3ZXJlIHZlcnkgZmV3IGRlYXRocyBpbiB0aGF0IGNvdW50cnkuIFRoaXMgaXMgaW50ZXJlc3RpbmcgYmVjYXVzZSB0aGlzIHNob3dzIHRoYXQgZXZlbiB0aG91Z2ggdGhpcyBjb3VudHJ5IGhhcyB0aGUgaGlnaGVzdCBtb3J0YWxpdHkgcmF0ZSwgaXQgaGFzIHZlcnkgZmV3IGRlYXRocy4gVGhpcyBpcyBhbiBpbmRpY2F0b3IgdGhhdCB0aGlzIG1heSBiZSBhbiBvdXRsaWVyLiAgCmBgYHtyfQpNb3J0YWxpdHlSYXRlIDwtCiAgQ292aWRCeUNvdW50cnkgJT4lCiAgCWdyb3VwX2J5KExvY2F0aW9uKSAlPiUKICAgIG11dGF0ZShyYXRpbyA9IERlYXRocy9DYXNlcykKCk1vcnRhbGl0eVJhdGUKCkhpZ2hlc3RNb3J0YWxpdHlSYXRlcyA8LQogIE1vcnRhbGl0eVJhdGUgJT4lCiAgICBmaWx0ZXIoTG9jYXRpb24gIT0gIldvcmxkW2FdIikgJT4lCiAgICBmaWx0ZXIoTG9jYXRpb24gIT0gIkV1cm9wZWFuIFVuaW9uW2JdIikKCkhpZ2hlc3RNb3J0YWxpdHlSYXRlcyRyYW5rIDwtIHJhbmsoSGlnaGVzdE1vcnRhbGl0eVJhdGVzJHJhdGlvKQoKSGlnaGVzdE1vcnRhbGl0eVJhdGVzIDwtICAKICBIaWdoZXN0TW9ydGFsaXR5UmF0ZXMgJT4lCiAgICBuYS5vbWl0KHJhdGlvKSAlPiUKICAgIGFycmFuZ2UoZGVzYyhyYW5rKSkgCgpIaWdoZXN0TW9ydGFsaXR5UmF0ZXMKClRvdGFsTW9ydGFsaXR5UmF0ZXMgPC0KICBIaWdoZXN0TW9ydGFsaXR5UmF0ZXMgJT4lCiAgCWdncGxvdChhZXMoeCA9IExvY2F0aW9uLCB5ID0gcmF0aW8pKSArCiAgICBnZW9tX3BvaW50KGFlcyhzaXplID0gRGVhdGhzKSkgKwogICAgZ2d0aXRsZSgiTW9ydGFsaXR5IFJhdGVzIG9mIENvdmlkLTE5IikgKyAKICAgIHhsYWIoIk1vcnRhbGl0eSBSYXRlIikgKwogICAgeWxhYigiQ291bnRyeSIpClRvdGFsTW9ydGFsaXR5UmF0ZXMKYGBgCgpBZnRlciBsb29raW5nIGF0IHRoZSBvdmVyYWxsIG1vcnRhbGl0eSByYXRlcywgd2Ugd2FudGVkIHRvIGZvY3VzIGluIG9uIHRoZSB0b3AgNSBoaWdoZXN0IG9uZXMuIFRvIGRvIHRoaXMsIHdlIGZpbHRlcmVkIG91dCB0aGUgb25lcyB3aXRoIHRoZSBoaWdoZXN0IHJhdGlvIHZhbHVlcyBhbmQgcHV0IHRob3NlIGludG8gYSBzZXBhcmF0ZSB0YWJsZS4gVGhlbiwgd2UgbWFkZSBhIGJhciBncmFwaCBzaG93aW5nIHRoZXNlIDUgY291bnRyaWVzIGFuZCB0aGVpciBtb3J0YWxpdHkgcmF0ZXMuIFRoZSB0b3AgNSBjb3VudHJpZXMgaW5jbHVkZWQgWWVtZW4sIFZhbnVhdHUsIFBlcnUsIE1leGljbywgYW5kIFN1ZGFuLiBUaGUgaGlnaGVzdCBtb3J0YWxpdHkgcmlnaHQgd2FzIC4xOTUxMDc0MCwgb3IgYWJvdXQgMTkuNSUsIHdoaWNoIHdhcyBpbiBZZW1lbi4gCmBgYHtyfQpUb3A1SGlnaGVzdE1vcnRhbGl0eVJhdGVzIDwtCiAgSGlnaGVzdE1vcnRhbGl0eVJhdGVzICU+JQogICAgZmlsdGVyKHJhbmsgPj0gMTg1KSAjU2luY2UgdGhlcmUgYXJlIDE4OSBjb3VudHJpZXMgd2l0aCB2YWx1ZXMgaW4gJ3JhdGlvJyB3ZSB3YW50IG9uZXMgd2l0aCByYW5rIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAxODUuCgpUb3A1SGlnaGVzdE1vcnRhbGl0eVJhdGVzCgpUb3A1SGlnaGVzdE1vcnRhbGl0eVJhdGVzICU+JQogIGdncGxvdChhZXMoeCA9IExvY2F0aW9uLCB5ID0gcmF0aW8pKSArCiAgZ2VvbV9jb2woYWVzKGNvbG9yID0gTG9jYXRpb24sIGZpbGwgPSBMb2NhdGlvbikpICsKICBnZ3RpdGxlKCJIaWdoZXN0IDUgTW9ydGFsaXR5IFJhdGVzIG9mIENvdmlkLTE5IikgKwogIHhsYWIoIk1vcnRhbGl0eSBSYXRlIikgKwogIHlsYWIoIkNvdW50cnkiKQpgYGAKCiMjIyBDYWxjdWxhdGluZyBBdmVyYWdlIE1vcnRhbGl0eSBSYXRlClRvIGZ1cnRoZXIgb3VyIGludmVzdGlnYXRpb24gb2YgdGhlIG1vcnRhbGl0eSByYXRlIG9mIENvdmlkLTE5LCB3ZSB3YW50ZWQgdG8gZXhwbG9yZSB0aGUgYXZlcmFnZSBtb3J0YWxpdHkgcmF0ZS4gVG8gc2ltcGx5IGZpbmQgdGhlIG1lYW4gb2YgYWxsIHRoZSBjYXNlcywgd2UgdXNlZCB0aGUgbWVhbigpIGZ1bmN0aW9uLiBUaGUgbWVhbiBvZiBhbGwgb2YgdGhlIHJhdGlvIHZhcmlhYmxlcyBpcyAwLjAyMTAyNzY0LiBBZnRlciBleGFtaW5pbmcgdGhlIHNjYXR0ZXJwbG90IHdlIGNyZWF0ZWQsIHdlIHdhbnRlZCB0byB0cnkgdG8gZ2V0IHJpZCBvZiBvdXRsaWVycyBvciBjb3VudHJpZXMgd2l0aCB2ZXJ5IGZldyBhbW91bnRzIG9mIGNhc2VzLiBGb3IgZXhhbXBsZSwgWWVtZW4gaGFkIHRoZSBoaWdoZXN0IG1vcnRhbGl0eSByYXRlIGJ1dCBvbmUgb2YgdGhlIG51bWJlciBvZiBkZWF0aHMuIFNvLCB3ZSBmaWx0ZXJlZCBvdXQgY2FzZXMgdGhhdCBoYWQgbGVzcyB0aGFuIDEwMCBjYXNlcyBvZiBDb3ZpZC0xOS4gVGhlbiwgd2UgdXNlZCBhIGZvciBsb29wIHRvIGdvIHRocm91Z2ggdGhlIGNvdW50cmllcyB3aXRoIG1vcmUgdGhhbiAxMDAgY2FzZXMgYW5kIGFkZCB0aGUgcmF0aW8gdmFyaWFibGUgdG8gYSBuZXcgdmFyaWFibGUsICJhdmciLiBXZSBhbHNvIGhhZCB0byBrZWVwIHRyYWNrIG9mIGhvdyBtYW55IGNvdW50cmllcyB0aGVyZSB3ZXJlIHdpdGggdGhpcyBjb25kaXRpb24gaW4gYSB2YXJpYWJsZSAiaW5kZXgiIGluIG9yZGVyIHRvIGJlIGFibGUgdG8gY2FsY3VsYXRlIHRoZSBhdmVyYWdlLiBBZnRlciB0aGUgZm9yIGxvb3AgcmFuLCB3ZSBzaW1wbHkgZGl2aWRlZCAiYXZnIiBieSAiaW5kZXgiIHRvIGdldCB0aGUgYXZlcmFnZSBtb3J0YWxpdHkgcmF0ZSBmb3IgY291bnRyaWVzIHdpdGggbW9yZSB0aGFuIDEwMCBjYXNlcyBvZiBDb3ZpZC0xOS4gVGhlIHJlc3VsdCB3YXMgMC4wMjA1ODEzOSwgd2hpY2ggaXMgbG93ZXIgdGhhbiB0aGUgb3JpZ2luYWwgbWVhbi4gVGhlIGNoYW5nZSB3YXMgbm90IGFzIHNpZ25pZmljYW50IGFzIHdlIHRob3VnaHQgaXQgbWF5IGJlLCBidXQgdGhlcmUgd2FzIHN0aWxsIGFib3V0IGEgLjA1JSBkaWZmZXJlbmNlLiAKYGBge3J9CiNGaW5kaW5nIG1lYW4gbW9ydGFsaXR5IHJhdGUgd2l0aCBhbGwgZGF0YSBpbmNsdWRlZAptZWFuKEhpZ2hlc3RNb3J0YWxpdHlSYXRlcyRyYXRpbykKCiNGaW5kaW5nIG1lYW4gbW9ydGFsaXR5IHJhdGUgd2l0aCBvbmx5IGNvdW50cmllcyB3aXRoIG1vcmUgdGhhbiAxMDAgY2FzZXMgb2YgQ292aWQtMTkKQ2FzZXNPdmVyMTAwIDwtCiAgSGlnaGVzdE1vcnRhbGl0eVJhdGVzICU+JQogICAgZmlsdGVyKENhc2VzID4gMTAwKQphdmcgPSAwCmluZGV4ID0gMApmb3IgKGkgaW4gQ2FzZXNPdmVyMTAwJHJhdGlvKSB7CiAgICBhdmcgPC0gYXZnICsgaQogICAgaW5kZXggPC0gaW5kZXggKyAxCn0KYXZnIDwtIGF2Zy9pbmRleAphdmcKYGBgCgoKCiMjIyBNb250aGx5IENhc2VzIGFuZCBEZWF0aHMKV2UgZGVjaWRlZCB0byBhbmFseXplIHRoZSBDb3ZpZC0xOSBjYXNlcyBhbmQgZGVhdGhzIGZvciB0aGUgeWVhciAyMDIwIGluIHRoZSBjb3VudHJpZXMgd2l0aCB0aGUgbW9zdCBhbW91bnQgb2YgY2FzZXMgYW5kIGRlYXRocy4gVG8gZG8gdGhpcywgd2UgZmlyc3Qgc2VsZWN0ZWQgdGhlIFVuaXRlZCBTdGF0ZXMsIEluZGlhIGFuZCBCcmF6aWwgYmVjYXVzZSBmcm9tIG91ciBwcmV2aW91cyBmaW5kaW5ncywgdGhleSBoYXZlIHRoZSBtb3N0IGNhc2VzLiBXZSBncm91cGVkIHRoZW0gYnkgbW9udGggaW4gb3JkZXIgdG8gc2VlIHRoZSBjaGFuZ2VzLiBXZSB3ZXJlIGFibGUgdG8gc2VlIHRoZSBtb250aGx5IGNhc2VzIGFuZCBkZWF0aHMgZm9yIHRoZSB0aHJlZSBjb3VudHJpZXMuCgpgYGB7cn0KVVNBbW9udGhseTwtCiAgRXVyb3BhRGF0YSU+JQoJZmlsdGVyKGNvdW50cmllc0FuZFRlcnJpdG9yaWVzPT0gIlVuaXRlZF9TdGF0ZXNfb2ZfQW1lcmljYSIpJT4lCiAgZ3JvdXBfYnkobW9udGgpICU+JQoJc3VtbWFyaXNlKE1vbnRobHljYXNlcyA9IHN1bShjYXNlcywgbmEucm0gPSBUUlVFKSwgIE1vbnRobHlkZWF0aHMgPSBzdW0oZGVhdGhzLCBuYS5ybSA9IFRSVUUpKSU+JQogIG11dGF0ZShDb3VudHJ5PSJVU0EiKQoKSW5kaWFtb250aGx5PC0KICBFdXJvcGFEYXRhJT4lCglmaWx0ZXIoY291bnRyaWVzQW5kVGVycml0b3JpZXM9PSAiSW5kaWEiKSU+JQogIGdyb3VwX2J5KG1vbnRoKSAlPiUKCXN1bW1hcmlzZShNb250aGx5Y2FzZXMgPSBzdW0oY2FzZXMsIG5hLnJtID0gVFJVRSksICBNb250aGx5ZGVhdGhzID0gc3VtKGRlYXRocywgbmEucm0gPSBUUlVFKSklPiUKICBtdXRhdGUoQ291bnRyeT0iSW5kaWEiKQoKQnJhemlsbW9udGhseTwtCiAgRXVyb3BhRGF0YSU+JQoJZmlsdGVyKGNvdW50cmllc0FuZFRlcnJpdG9yaWVzPT0gIkJyYXppbCIpJT4lCiAgZ3JvdXBfYnkobW9udGgpICU+JQoJc3VtbWFyaXNlKE1vbnRobHljYXNlcyA9IHN1bShjYXNlcywgbmEucm0gPSBUUlVFKSwgIE1vbnRobHlkZWF0aHMgPSBzdW0oZGVhdGhzLCBuYS5ybSA9IFRSVUUpKSU+JQogIG11dGF0ZShDb3VudHJ5PSJCcmF6aWwiKQoKYGBgCgojIyMgTWVyZ2luZyB0YWJsZXMKV2UgbWVyZ2VkIHRoZSB0YWJsZXMgZm9yIHRoZSB0b3AgMyBjb3VudHJpZXMgY2FzZXMgYW5kIGRlYXRocyBzbyB3ZSBjb3VsZCBncmFwaCB0aGVtLgoKYGBge3J9CkZpcnN0bWVyZ2U8LQogIG1lcmdlKHg9VVNBbW9udGhseSwgeT1JbmRpYW1vbnRobHksIGFsbD1UUlVFKQoKVG9wMzwtCiAgbWVyZ2UoeD1GaXJzdG1lcmdlLCB5PUJyYXppbG1vbnRobHksIGFsbD1UUlVFKQoKYGBgCgojIyMgR3JhcGhpbmcgdGhlIHRvcCB0aHJlZSBjb3VudHJpZXMKV2UgZ3JhcGhlZCB0aGUgdG9wIHRocmVlIGNvdW50cmllcyB3aXRoIENvdmlkIGNhc2VzLiBVU0EsIEJyYXppbCBhbmQgSW5kaWEgYXJlIHJlcHJlc2VudGVkIGJ5IHRoZSBkaWZmZXJlbnQgbGluZXMsIHJlc3BlY3RpdmVseS4gVGhlIGNhc2VzIGFyZSBncmFwaGVkIG92ZXIgdGltZSBpbiAyMDIwLiBVbml0ZWQgU3RhdGVzIGhhZCBhIHNwaWtlIGluIE5vdmVtYmVyIGFuZCBJbmRpYSBoYWQgYSBzcGlrZSBpbiBTZXB0ZW1iZXIuIE92ZXJhbGwsIHRoZSBjYXNlcyBoYXZlIGJlZW4gaW5jcmVhc2luZyBzaW5jZSB0aGUgcGFuZGVtaWMgc3RhcnRlZCBhbmQgYXQgdGhlIGVuZCBvZiB0aGUgeWVhciB0aGV5IGhhdmUgc2xpZ2h0bHkgZ29uZSBkb3duIGFzIHRoZSBwYW5kZW1pYyBoYXMgZ290dGVuIHVuZGVyIGNvbnRyb2wuCmBgYHtyfQpUb3AzJT4lCiAgZ2dwbG90KGFlcyh4PW1vbnRoLCB5PU1vbnRobHljYXNlcykpICsKICBnZW9tX2xpbmUoYWVzKGxpbmV0eXBlPUNvdW50cnksIGNvbG9yPUNvdW50cnkpKSsKICB4bGFiKCJNb250aCIpKwogIHlsYWIoIkNhc2VzIikrCiAgZ2d0aXRsZSgiTW9udGhseSBDb3ZpZCBDYXNlcyBmb3IgdGhlIFRvcCBUaHJlZSBDb3VudHJpZXMgaW4gMjAyMCIpKwogIHhsaW0oMCwxMikKYGBgCldlIGdyYXBoZWQgdGhlIHRvcCB0aHJlZSBjb3VudHJpZXMgd2l0aCBDb3ZpZCBkZWF0aHMuIFVTQSwgQnJhemlsIGFuZCBJbmRpYSBhcmUgcmVwcmVzZW50ZWQgYnkgdGhlaXIgcmVzcGVjdGl2ZSBsaW5lcyBoZXJlIGFzIHdlbGwuIFRoZSBjYXNlcyBhcmUgZ3JhcGhlZCBvdmVyIHRpbWUgaW4gMjAyMC4gVGhlcmUgd2FzIGEgc3Bpa2UgaW4gVVNBIGNhc2VzIGluIEFwcmlsIGFzIHRoZSBwYW5kZW1pYyB3YXMgbmV3IGFuZCB1bm1hbmFnZWFibGUgYXQgdGhlIHRpbWUuIFRoZSBkZWF0aHMgaW5jcmVhc2VzIGZvciBhbGwgb2YgdGhlIGNvdW50cmllcyBpbiB0aGUgc3VtbWVyIGFzIHRoZSBwYW5kZW1pYyBwaWNrZWQgdXAgc3BlZWQuIE92ZXIgdGhlIHllYXIgMjAyMCwgdGhlIGhvc3BpdGFscyByZWdhaW5lZCBjb250cm9sIGFuZCB0aGUgZGVhdGhzIGRlY3JlYXNlZC4KCmBgYHtyfQpUb3AzJT4lCiAgZ2dwbG90KGFlcyh4PW1vbnRoLCB5PU1vbnRobHlkZWF0aHMpKSArCiAgZ2VvbV9saW5lKGFlcyhsaW5ldHlwZT1Db3VudHJ5LCBjb2xvcj1Db3VudHJ5KSkrCiAgeGxhYigiTW9udGgiKSsKICB5bGFiKCJEZWF0aHMiKSsKICBnZ3RpdGxlKCJNb250aGx5IENvdmlkIERlYXRocyBmb3IgdGhlIFRvcCBUaHJlZSBDb3VudHJpZXMgaW4gMjAyMCIpKwogIHhsaW0oMCwxMikKYGBgCgoKCiMjIyBDaGFsbGVuZ2VzIHdlIGVuY291bnRlcmVkCk9uZSBvZiB0aGUgbWFpbiB0ZWNobmljYWwgY2hhbGxlbmdlcyB3ZSBoYWQgdG8gb3ZlcmNvbWUgd2FzIHdoZW4gd2Ugd2VyZSB0cnlpbmcgdG8gcmFuayB0aGUgY291bnRyaWVzIGZyb20gdGhlIGZpcnN0IGRhdGEgc291cmNlIGJ5IHRoZWlyIG1vcnRhbGl0eSByYXRlLiBUaGlzIGlzIGluIHRoZSBzZWN0aW9uIGVudGl0bGVkICJNb3J0YWxpdHkgUmF0ZSIuIEF0IGZpcnN0LCBhZnRlciB3ZSB1c2VkIG11dGF0ZSgpIHRvIGFkZCB0aGUgInJhdGlvIiB2YXJpYWJsZSB3ZSB0cmllZCB0byB1c2UgZmlsdGVyKHJhbmsoZGVzYyhyYXRpbykgPj0gNSkpIG9uIG9yZGVyIHRvIGdldCB0aGUgdG9wIDUgaGlnaGVzdCBtb3J0YWxpdHkgcmF0ZXMuIEhvd2V2ZXIsIHRoZSBvcmRlciBvZiB0aGUgY291bnRyaWVzIHdhcyBub3QgcmVzdWx0aW5nIGluIGRlc2NlbmRpbmcgcmF0aW9zLiBXZSBjb3VsZCBub3QgZGlzY292ZXIgdGhlIHJvb3Qgb2YgdGhpcyBwcm9ibGVtIGV2ZW4gYWZ0ZXIgYXNraW5nIGZvciBoZWxwLiBJdCBtYXkgaGF2ZSBiZWVuIGJlY2F1c2UgdGhlIHJhdGlvcyBhcmUgYWxsIGRlY2ltYWxzLCBidXQgd2UgYXJlIHN0aWxsIHVuc3VyZS4gVG8gb3ZlcmNvbWUgdGhpcyBpc3N1ZSwgd2UgaGFkIHRvIGNoYW5nZSBob3cgd2Ugd2VyZSBnb2luZyB0byBjb21wbGV0ZSB0aGUgdGFzayBvZiBmaW5kaW5nIHdoaWNoIGNvdW50cmllcyBoYWQgdGhlIGhpZ2hlc3QgbW9ydGFsaXR5IHJhdGVzLiBTbywgaW5zdGVhZCBvZiB1c2luZyB0aGUgcmFuaygpIGZ1bmN0aW9uLCB3ZSBoYWQgdG8gY3JlYXRlIGEgbmV3IHZhcmlhYmxlIGluIHRoZSBIaWdoZXN0TW9ydGFsaXR5UmF0ZXMgdGFibGUgY2FsbGVkICJyYW5rIi4gVGhlIHZhbHVlcyBvZiB0aGlzIG5ldyB2YXJpYWJsZSBhcmUgdGhlIHJhbmtpbmdzIG9mIHRoZSBjb3VudHJpZXMgZnJvbSBsb3dlc3QgdG8gaGlnaGVzdCBtb3J0YWxpdHkgcmF0ZXMuIFdlIGRpZCB0aGlzIGJ5IGRvaW5nIEhpZ2hlc3RNb3J0YWxpdHlSYXRlcyRyYW5rIDwtIHJhbmsoSGlnaGVzdE1vcnRhbGl0eVJhdGVzJHJhdGlvKS4gT25jZSB3ZSBoYWQgdGhpcyBuZXcgdmFyaWFibGUgd2UgdXNlZCB0aGUgYXJyYW5nZSgpIGZ1bmN0aW9uIHRvIG9yZGVyIHRoZSBjb3VudHJ5IGJ5IHRoZWlyIHJhbmtpbmdzLiBGaW5hbGx5LCB3ZSB3ZXJlIGFibGUgdG8gZmluZCB0aGUgdG9wIDUgYnkgZmlsdGVyaW5nIHRoZSBjb3VudHJpZXMgd2l0aCByYW5rcyBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gMTg1LCBzaW5jZSB0aGVyZSB3ZXJlIGEgdG90YWwgb2YgMTg5IGNvdW50cmllcyBhbmQgdGhlIHJhbmtpbmcgd2FzIGZyb20gbG93ZXN0IHRvIGhpZ2hlc3QgbW9ydGFsaXR5IHJhdGVzLgpBbm90aGVyIGNoYWxsZW5nZSB3ZSBoYWQgd2FzIHdpdGggb3VyIGZpcnN0IGRhdGEgc291cmNlLiBXZSB3ZXJlIHF1ZXJ5aW5nIHdpdGggdGhlIG51bWJlcnMgaW4gdGhpcyBkYXRhIHNldCBhbmQgd2Ugd2VyZSBub3QgZ2V0dGluZyB0aGUgY29ycmVjdCByZXN1bHRzLiBXZSB0aGVuIHJlYWxpemVkIHRoYXQgdGhlIHZhcmlhYmxlcyBDYXNlcyBhbmQgRGVhdGhzIHdlcmUgdHlwZSA8Y2hyPiBpbnN0ZWFkIG9mIDxkYmw+LiBUbyBvdmVyY29tZSB0aGlzIGlzc3VlLCB3ZSB1c2VkIGFzLm51bWVyaWMoKSB0byBjb252ZXJ0IHRoZSBkYXRhIGZyb20gY2hhcmFjdGVycyB0byBudW1lcmljYWwgdHlwZXMuIFRoZSBvcmlnaW5hbCBudW1iZXJzIGFsc28gY29udGFpbmVkIGNvbW1hcyBpbiB0aGUgY2hhcmFjdGVyIHN0cmluZ3MsIHNvIHdlIGhhZCB0byB1c2UgdGhlIGdzdWIoKSBmdW5jdGlvbiwgd2hpY2ggaXMgYSByZWd1bGFyIGV4cHJlc3Npb24sIHRvIGdldCByaWQgb2YgdGhlIGNvbW1hcyBiZWZvcmUgY29udmVydGluZyB0aGUgZGF0YSB0eXBlcy4gCgojIyMgU2lnbmlmaWNhbnQgRmluZGluZ3MgYW5kIENvbmNsdXNpb24KSW4gYW5hbHl6aW5nIHRoZSBDb3ZpZC0xOSBkYXRhIHNldHMsIHdlIHdlcmUgYWJsZSB0byBkcmF3IGNvbmNsdXNpb25zIGJhc2VkIG9uIG91ciBmaW5kaW5ncy4gT3VyIGZpcnN0IHN0ZXAgd2FzIGZpbmRpbmcgdGhlIGNvdW50cmllcyB3aXRoIHRoZSBoaWdoZXN0IENvdmlkLTE5IGNhc2VzLiBUaGVzZSBjb3VudHJpZXMsIGluIGRlc2NlbmRpbmcgb3JkZXIsIHdlcmUgVW5pdGVkIFN0YXRlcywgSW5kaWEsIEJyYXppbCwgVW5pdGVkIEtpbmdkb20gYW5kIFJ1c3NpYS4gT25lIHJlYXNvbiB0aGVzZSBjb3VudHJpZXMgY291bGQgaGF2ZSB0aGUgaGlnaGVzdCBhbW91bnQgb2YgY2FzZXMgaXMgdGhlaXIgbGFyZ2UgcG9wdWxhdGlvbnMuIFdoZW4gbG9va2luZyBhdCB0aGUgY291bnRyaWVzIHdpdGggdGhlIG1vc3QgZGVhdGhzLCB0aGUgcmVzdWx0cyB3ZXJlIHNpbWlsYXIuIFRoZSBjb3VudHJpZXMgd2l0aCB0aGUgdG9wIDUgQ292aWQtMTkgZGVhdGggY291bnQgYXJlIHRoZSBVbml0ZWQgU3RhdGVzLCBJbmRpYSwgQnJhemlsLCBSdXNzaWEgYW5kIE1leGljby4gVGhlIHRvcCBjb3VudHJpZXMgZm9yIGNhc2VzIGFuZCBkZWF0aHMgYXJlIHZlcnkgc2ltaWxhciB3aXRoIHRoZSBleGNlcHRpb24gdGhhdCB0aGUgVW5pdGVkIEtpbmdkb20gcmVwbGFjZWQgTWV4aWNvIG9uIHRoZSB0b3AgZGVhdGhzIGxpc3QuIFRvIGdldCBhbiBhY2N1cmF0ZSBkZXBpY3Rpb24gb2YgY291bnRyaWVzIHdobyBzdHJ1Z2dsZSB3aXRoIHRoZSBwYW5kZW1pYyBhbmQgbG9zaW5nIHBlb3BsZSB0byBDb3ZpZC0xOSwgd2UgY2FsY3VsYXRlZCB0aGUgbW9ydGFsaXR5IHJhdGVzLiBUaGUgY291bnRyaWVzIHdpdGggdGhlIGhpZ2hlc3QgbW9ydGFsaXR5IHJhdGVzIGFyZSBZZW1lbiwgVmFudWF0dSwgUGVydSwgTWV4aWNvIGFuZCBTdWRhbi4gQSByZWFzb24gdGhhdCB0aGVzZSBjb3VudHJpZXMgaGF2ZSBoaWdoIG1vcnRhbGl0eSByYXRlcyBhcmUgdGhleSBkb24ndCBoYXZlIHRoZSByZXNvdXJjZXMgb3IgaGVhbHRoY2FyZSBzeXN0ZW0gdG8ga2VlcCB1cCB3aXRoIHRoZSBwYW5kZW1pYy4gRnVydGhlciBhbmFseXNpcyBvbiB0aGUgY291bnRyaWVzIGhlYWx0aGNhcmUgYW5kIGVjb25vbWljIHN5c3RlbSBhcyB3ZWxsIGFzIHRoZSBzdGFuZGFyZCBvZiBsaXZpbmcgd291bGQgYmUgbmVlZGVkIHRvIHVuZGVyc3RhbmQgd2h5IHRob3NlIGNvdW50cmllcyBoYXZlIGhpZ2hlciBtb3J0YWxpdHkgcmF0ZXMuIFdlIGNhbGN1bGF0ZWQgdGhlIG92ZXJhbGwgbW9ydGFsaXR5IHJhdGUgb2YgdGhlIGdsb2JlIGZvciBDb3ZpZC0xOS4gVGhlIHJlc3VsdCB3YXMgMi4wNSUsIHdoaWNoIGlzIHJlbGF0aXZlbHkgbG93LiBXaXRoIG1vZGVybiBtZWRpY2luZSwgbW9zdCBwZW9wbGUgc3Vydml2ZWQgQ292aWQtMTkuIEFkZGl0aW9uYWxseSwgd2Ugd2FudGVkIHRvIGdyYXBoIG91dCB0aGUgY291bnRyaWVzIHdpdGggdGhlIGhpZ2hlc3QgYW1vdW50IG9mIGNhc2VzIGFuZCBkZWF0aHMgaW4gMjAyMCB0byBzZWUgdHJlbmRzIGluIHRoZSBwYW5kZW1pYy4gV2UgY2hvb3NlIHRoZSB0b3AgdGhyZWUgY291bnRyaWVzIHdpdGggY2FzZXMgYW5kIGRlYXRocyBhcyB0aGV5IHdlcmUgaGVhdmlseSBpbXBhY3RlZCBieSB0aGUgcGFuZGVtaWMuIEZvciB0aGUgY2FzZXMgZ3JhcGgsIGFsbCBvZiB0aGUgY291bnRyaWVzIHdlcmUgc3RlYWRpbHkgaW5jcmVhc2luZyB0aGUgYW1vdW50IG9mIGNhc2VzIG92ZXIgdGhlIHN1bW1lci4gVGhlIG51bWJlciBvZiBCcmF6aWwgY2FzZXMgYmVnYW4gdG8gcmVnYWluIGNvbnRyb2wgaW4gQXVndXN0IGFuZCB0aGUgSW5kaWEgY2FzZXMgc3RhcnRlZCB0byBkZWNsaW5lIGluIFNlcHRlbWJlci4gVGhlIFVuaXRlZCBTdGF0ZXMgaGFkIGxhcmdlIHNwaWtlZCBpbiBKdWx5IGFuZCBOb3ZlbWJlciBhcyB0aGV5IHN0cnVnZ2xlIHRvIGtlZXAgdGhlIGFtb3VudCBvZiBjYXNlcyB1bmRlciBjb250cm9sIGRlc3BpdGUgZW5mb3JjaW5nIG1hc2tpbmcgcmVxdWlyZW1lbnRzLiBGb3IgdGhlIGRlYXRocyBncmFwaCwgdGhlIFVuaXRlZCBTdGF0ZXMgaGFkIGEgZ2lnYW50aWMgc3Bpa2UgaW4gQXByaWwuIFRoaXMgaXMgd2hlbiB0aGUgY291bnR5IHdhcyBvbiBjb21wbGV0ZSBsb2NrIGRvd24gYmVjYXVzZSB0aGUgaG9zcGl0YWxzIHdlcmUgb3ZlcmNyb3dkaW5nIGFuZCBpdCB3YXMgZGlmZmljdWx0IHRvIGtlZXAgdGhlIHBhdGllbnRzIGFsaXZlLiBUaGUgZGVhdGhzIGZvciBJbmRpYSBhbmQgQnJhemlsIHN0ZWFkaWx5IGluY3JlYXNlZCB3aGVuIHRoZSBwYW5kZW1pYyBzdGFydGVkLiBPdmVyIHRoZSBzdW1tZXIsIHRoZSBkZWF0aCBjb3VudHMgc3RlYWRpZWQgb3V0IGFzIHRoZSBob3NwaXRhbHMgd2VyZSBhYmxlIHRvIG1hbmFnZSB0aGUgcGF0aWVudHMuIEF0IHRoZSBlbmQgb2YgdGhlIHllYXIsIGRlYXRoIGNvdW50cyBkZWNsaW5lZC4gVGhlIGRlYXRoIGNvdW50cyBjb250aW51ZSB0byBkZWNsaW5lIHNpbmNlIHRoZSB2YWNjaW5lIHdhcyByZWxlYXNlZCB0byB0aGUgcHVibGljLCBzYXZpbmcgbWFueSBmcm9tIENvdmlkLTE5LiAK