Group Members

  • Randy Koliha

  • Isaiah Sarria

  • Owen Telis

  • John Levitt

Introduction

Steam is a popular, online video game distributor with many other complementing features. Steam hosts community discussion threads, access to download community-made modifications to games sold on the platform, social media-like user profiles and friends lists that displays the users overall or recent video game activity, and sales events which are based on holidays or unique themes.

We want to analyze a dataset regarding Steam games to dive deep into the behavior of gamers on the platform.

Packages

Loading any needed packages.

library(tidyverse)
library(scales)
library(directlabels)

The Dataset

The games.csv dataset has data collected for games on the popular game license selling platform, Steam, over the months from the years July 2012- Febuary 2021. The data set has records of 1258 games (also includes other miscellaneous pieces of software), and includes their titles, monthly player peaks, monthly average players at the same time, monthly gains/losses of players compared to the previous month, and the percentage of how closely the average players approach the peak. It should also be noted that the data set was scrapped data from Steam by Steam Charts, and only tracks relevant games on Steam.

Running the data & cleaning up

# Storing dataset in `games`
games <- read.csv("games.csv")

#cleaning it up

games <- games %>% 
  mutate( number_of_month = match(games[1:83631,3], month.name) ) %>% 
  select(gamename,year,number_of_month,everything()) %>% 
  arrange(desc(year), number_of_month)
  games

Data Exploration

summary(games)
   gamename              year      number_of_month     month                avg                 gain                peak         avg_peak_perc     
 Length:83631       Min.   :2012   Min.   : 1.000   Length:83631       Min.   :      0.0   Min.   :-250249.0   Min.   :      0   Length:83631      
 Class :character   1st Qu.:2016   1st Qu.: 3.000   Class :character   1st Qu.:     53.1   1st Qu.:    -38.2   1st Qu.:    137   Class :character  
 Mode  :character   Median :2018   Median : 7.000   Mode  :character   Median :    203.1   Median :     -1.6   Median :    500   Mode  :character  
                    Mean   :2017   Mean   : 6.546                      Mean   :   2765.7   Mean   :    -10.3   Mean   :   5470                     
                    3rd Qu.:2019   3rd Qu.:10.000                      3rd Qu.:    764.0   3rd Qu.:     22.2   3rd Qu.:   1727                     
                    Max.   :2021   Max.   :12.000                      Max.   :1584886.8   Max.   : 426446.1   Max.   :3236027                     
                                                                                           NA's   :1258                                            

How many games are in the data set?

# Finding the distinct number of `gamenames`
dist_g <- games %>% 
  distinct(gamename) 

dist_g

# in alpha order

 dist_g_alpha <- games %>% 
  distinct(gamename) %>% 
  arrange(gamename)

dist_g_alpha

There is 1258 games on steam.

Question 1: Do all games lose popularity overtime? How do multiplayer and single player titles differ?

Case 1: What if the game is given out for free after its been for sale?

g_payday <- games %>% 
  filter(gamename == "PAYDAY 2") %>% 
  filter(year %in% c(2012:2021)) %>% 
  mutate(label = if_else(number_of_month == max(number_of_month), as.character(year), NA_character_))
g_payday

#makes the PAYDAY 2 dataframe 

Years_Payday2 <- as.factor(g_payday$year)
ggplot(g_payday,aes(x = number_of_month,y = avg, group = year, color = Years_Payday2)) +
geom_line(size = 1) +
geom_point()+ 
scale_x_continuous(breaks = seq(1, 12, by = 1),expand=c(0, 1))+ 
geom_dl(aes(label = year), method = list(dl.trans(x = x + 0.1), "last.points", cex = 1)) +
scale_colour_manual(values=c("#964B00","#f58231","#030000", "#00FBFE", "#3cb44b", "#FF0004", "#4363d8", "#911eb4", "#f032e6", "#a9a9a9" )) +
  xlab("Months")+
  ylab("Average Players") +
  labs(title = "Payday 2: Average Players by Year")


#auto color pallet if + scale manual is removed
Why Payday 2 Spiked In 2017
Why Payday 2 Spiked In 2017

Case 2: Multiplayer/Esports Titles

g_pubg <- games %>% 
  filter(gamename == "PLAYERUNKNOWN'S BATTLEGROUNDS") %>% 
  filter(year %in% c(2017:2021)) %>% 
  mutate(label = if_else(number_of_month == max(number_of_month), as.character(year), NA_character_))
g_pubg

Years_PUBG <- as.factor(g_pubg$year)
ggplot(g_pubg,aes(x = number_of_month,y = avg, group = year, color = Years_PUBG)) +
geom_line(size = 1) +
geom_point()+ 
scale_x_continuous(breaks = seq(1, 12, by = 1),expand=c(0, 1))+ 
geom_dl(aes(label = year), method = list(dl.trans(x = x + 0.1), "last.points", cex = 1)) +
scale_colour_manual(values=c("#964B00","#f58231","#030000", "#00FBFE", "#3cb44b",  "#a9a9a9" )) +
  xlab("Months")+
  ylab("Average Players") +
  labs(title = "PLAYERUNKNOWN'S BATTLEGROUNDS: Average Players by Year")


g_csgo <- games %>% 
  filter(gamename == "Counter-Strike: Global Offensive") %>% 
  filter(year %in% c(2012:2021)) %>% 
  mutate(label = if_else(number_of_month == max(number_of_month), as.character(year), NA_character_))
g_csgo

Years_csgo <- as.factor(g_csgo$year)
ggplot(g_csgo,aes(x = number_of_month,y = avg, group = year, color = Years_csgo)) +
geom_line(size = 1) +
geom_point()+ 
scale_x_continuous(breaks = seq(1, 12, by = 1),expand=c(0, 1))+ 
geom_dl(aes(label = year), method = list(dl.trans(x = x + 0.1), "last.points", cex = 1)) +
scale_colour_manual(values=c("#964B00","#f58231","#030000", "#00FBFE", "#3cb44b", "#FF0004", "#4363d8", "#911eb4", "#f032e6", "#a9a9a9" )) +
  xlab("Months")+
  ylab("Average Players") +
  labs(title = "Counter Strike: Global Offensive: Average Players by Year")


g_gtav <- games %>% 
  filter(gamename == "Grand Theft Auto V") %>% 
  filter(year %in% c(2012:2021)) %>% 
  mutate(label = if_else(number_of_month == max(number_of_month), as.character(year), NA_character_))
g_gtav

Years_gtav <- as.factor(g_gtav$year)
ggplot(g_gtav,aes(x = number_of_month,y = avg, group = year, color = Years_gtav)) +
geom_line(size = 1) +
geom_point()+ 
scale_x_continuous(breaks = seq(1, 12, by = 1),expand=c(0, 1))+ 
geom_dl(aes(label = year), method = list(dl.trans(x = x + 0.1), "last.points", cex = 1)) +
scale_colour_manual(values=c("#964B00","#f58231","#030000", "#00FBFE", "#3cb44b", "#FF0004", "#4363d8", "#911eb4", "#f032e6", "#a9a9a9" )) +
  xlab("Months")+
  ylab("Average Players") +
  labs(title = "Grand Theft Auto V: Average Players by Year")


g_dota2 <- games %>% 
  filter(gamename == "Dota 2") %>% 
  filter(year %in% c(2012:2021)) %>% 
  mutate(label = if_else(number_of_month == max(number_of_month), as.character(year), NA_character_))
g_dota2

Years_dota2 <- as.factor(g_dota2$year)
ggplot(g_dota2,aes(x = number_of_month,y = avg, group = year, color = Years_dota2)) +
geom_line(size = 1) +
geom_point()+ 
scale_x_continuous(breaks = seq(1, 12, by = 1),expand=c(0, 1))+ 
geom_dl(aes(label = year), method = list(dl.trans(x = x + 0.1), "last.points", cex = 1)) +
scale_colour_manual(values=c("#964B00","#f58231","#030000", "#00FBFE", "#3cb44b", "#FF0004", "#4363d8", "#911eb4", "#f032e6", "#a9a9a9" )) +
  xlab("Months")+
  ylab("Average Players") +
  scale_y_continuous(labels = comma) +
  labs(title = "DOTA 2: Average Players by Year")

CSGO also was given out for free in 2020 so that shows similarities with the games given out for free over time.

This data shows that many multiplayer games seem to gain players over time and often have their peak average players occur in a period signficantly after the launch of the game. While GTA 5 decreases unlike the multiplayer games in the first year, a varible that has to be factored in is that GTA 5 is a single and mutiplayer game. So, we see a sudden drop on release but increasing players over time.

Case 3: Single Player Titles

g_fallout4 <- games %>% 
  filter(gamename == "Fallout 4") %>% 
  filter(year %in% c(2012:2021)) %>% 
  mutate(label = if_else(number_of_month == max(number_of_month), as.character(year), NA_character_))
g_fallout4

Years_fallout4 <- as.factor(g_fallout4$year)
ggplot(g_fallout4,aes(x = number_of_month,y = avg, group = year, color = Years_fallout4)) +
geom_line(size = 1) +
geom_point()+ 
scale_x_continuous(breaks = seq(1, 12, by = 1),expand=c(0, 1))+ 
geom_dl(aes(label = year), method = list(dl.trans(x = x + 0.1), "last.points", cex = 1)) +
scale_colour_manual(values=c("#964B00","#f58231","#030000", "#00FBFE", "#3cb44b", "#FF0004", "#4363d8", "#911eb4", "#f032e6", "#a9a9a9" )) +
  xlab("Months")+
  ylab("Average Players") +
  labs(title = "Fallout 4: Average Players by Year")


g_farcry5 <- games %>% 
  filter(gamename == "Far Cry 5") %>% 
  filter(year %in% c(2012:2021)) %>% 
  mutate(label = if_else(number_of_month == max(number_of_month), as.character(year), NA_character_))
g_farcry5

Years_farcry5 <- as.factor(g_farcry5$year)
ggplot(g_farcry5,aes(x = number_of_month,y = avg, group = year, color = Years_farcry5)) +
geom_line(size = 1) +
geom_point()+ 
scale_x_continuous(breaks = seq(1, 12, by = 1),expand=c(0, 1))+ 
geom_dl(aes(label = year), method = list(dl.trans(x = x + 0.1), "last.points", cex = 1)) +
scale_colour_manual(values=c("#964B00","#f58231","#030000", "#00FBFE", "#3cb44b", "#FF0004", "#4363d8", "#911eb4", "#f032e6", "#a9a9a9" )) +
  xlab("Months")+
  ylab("Average Players") +
  labs(title = "Farcry 5: Average Players by Year")


g_cyberpunk <- games %>% 
  filter(gamename == "Cyberpunk 2077") %>% 
  filter(year %in% c(2012:2021)) %>% 
  mutate(label = if_else(number_of_month == max(number_of_month), as.character(year), NA_character_))
g_cyberpunk

Years_cyberpunk <- as.factor(g_cyberpunk$year)
ggplot(g_cyberpunk,aes(x = number_of_month,y = avg, group = year, color = Years_cyberpunk)) +
geom_line(size = 1) +
geom_point()+ 
scale_x_continuous(breaks = seq(1, 12, by = 1),expand=c(0, 1))+ 
geom_dl(aes(label = year), method = list(dl.trans(x = x + 0.1), "last.points", cex = 1)) +
scale_colour_manual(values=c("#964B00","#f58231","#030000", "#00FBFE", "#3cb44b", "#FF0004", "#4363d8", "#911eb4", "#f032e6", "#a9a9a9" )) +
  xlab("Months")+
  ylab("Average Players") +
  labs(title = "Cyberpunk 2077: Average Players by Year")


g_girl <- games %>% 
  filter(gamename == "Hentai Girl") %>% 
  filter(year %in% c(2012:2021)) %>% 
  mutate(label = if_else(number_of_month == max(number_of_month), as.character(year), NA_character_))
g_girl

Years_girl <- as.factor(g_girl$year)
ggplot(g_girl,aes(x = number_of_month,y = avg, group = year, color = Years_girl)) +
geom_line(size = 1) +
geom_point()+ 
scale_x_continuous(breaks = seq(1, 12, by = 1),expand=c(0, 1))+ 
geom_dl(aes(label = year), method = list(dl.trans(x = x + 0.1), "last.points", cex = 1)) +
scale_colour_manual(values=c("#964B00","#f58231","#030000", "#00FBFE", "#3cb44b", "#FF0004", "#4363d8", "#911eb4", "#f032e6", "#a9a9a9" )) +
  xlab("Months")+
  ylab("Average Players") +
  labs(title = "Hentai Girl: Average Players by Year")

This data shows that singleplayer titles seem to have a drastic fall off in their player base following the launch of the game. This most likely occurs because once someone beats a single player game they are less likely to return to it. This can also be attributed to the fact that multiplayer/esports games are usually continually updated with new content, where as single player game typically are less likely to receive these updates consistently.

Question 2: Is the Steam platform affected by seasonality?

games_seasons <- games %>% 
  filter(year %in% c(2012:2021)) %>% 
  group_by(number_of_month) %>% 
  summarise(avg_month_sum = sum(avg)) 
ggplot(data = games_seasons) +
  geom_line(aes(x = number_of_month, y = avg_month_sum),color = "blue", size = 1) +
  geom_point(aes(x = number_of_month, y = avg_month_sum),color = "red", size = 3)+
  scale_x_continuous(breaks = seq(1, 12, by = 1),expand=c(0, 1)) +
  scale_y_continuous(labels = comma) +
  xlab("Months")+
  ylab("Average Number of Players") +
  labs(title = "Steam Seasonality using Avg. Players")

games_seasons

games_seasons_pk <- games %>% 
  filter(year %in% c(2012:2021)) %>% 
  group_by(number_of_month) %>% 
  summarise(peak_month_sum = sum(peak)) 
ggplot(data = games_seasons_pk) +
  geom_line(aes(x = number_of_month, y = peak_month_sum),color = "blue", size = 1) +
  geom_point(aes(x = number_of_month, y = peak_month_sum),color = "red", size = 3)+
  scale_x_continuous(breaks = seq(1, 12, by = 1),expand=c(0, 1)) +
  scale_y_continuous(labels = comma) +
  xlab("Months")+
  ylab("Peak Number of Players") +
  labs(title = "Steam Seasonality using Peak Players")

games_seasons_pk

The data suggests that there is a seasonality to Steam’s player data. This shows that Steam has the most players around December, Janurary, and Feburary. We suspect that this occurs because of the Christmas season and people recieving money and games as gifts. The steep fall off we see in Feburary may occur because individuals have completed the games they received during the holiday season. We also see an increase in players during the summer months. We suspect that this occurs because individuals are out of school for their summer break, giving them more time to play video games on Steam.

Question 3: What does the growth of Steam players look like from 2012 - 2021?

games_user_growth <- games %>% 
  filter(year %in% c(2012:2020)) %>% 
  group_by(year) %>% 
  summarise(avg_month_all_years = sum(avg))
ggplot(data = games_user_growth) +
  geom_line(aes(x = year, y = avg_month_all_years),color = "blue", size = 1) +
  geom_point(aes(x = year, y = avg_month_all_years),color = "red", size = 3) +
  scale_x_continuous(breaks = seq(2012, 2020, by = 1)) +
  scale_y_continuous(labels = comma) +
  xlab("Years")+
  ylab("Average Number of Players") +
  labs(title = "Steam Platform Growth using Avg. Players")

games_user_growth

games_user_growth_pk <- games %>% 
  filter(year %in% c(2012:2020)) %>% 
  group_by(year) %>% 
  summarise(peak_month_all_years = sum(peak)) 
ggplot(data = games_user_growth_pk) +
  geom_line(aes(x = year, y = peak_month_all_years),color = "blue", size = 1) +
  geom_point(aes(x = year, y = peak_month_all_years),color = "red", size = 3) +
  scale_x_continuous(breaks = seq(2012, 2020, by = 1)) +
  scale_y_continuous(labels = comma) +
  xlab("Years")+
  ylab("Peak Number of Players") +
  labs(title = "Steam Platform Growth using Peak Players")

games_user_growth_pk
NA
NA

The graph shows that the Steam platform has had relatively consistent growth from 2012 to 2020. However, we can see the only time Steam has a drop in users was from 2018 to 2019. We suspect this to be related to the rise of other online games market places such as the EPIC Games store and the popularity of Fortnite at the time. In November of 2018, Fortnite hit a 8.3 million concurrent players. We suspect that the popularity of Fortnite combined with the fact it was not on Steam is ultimately what caused the dip in players from 2018-2019.

Question 4: What is the total number of relevant titles on the Steam platform from 2012 - 2021?

g_without_2021 <- games %>% 
  filter(number_of_month == 12, year %in% 2012:2020)

g_added <- g_without_2021 %>% 
ggplot()+
  geom_bar(aes(x = year))+
  scale_x_continuous(breaks = seq(2012, 2020, by = 1)) +
  xlab("Years")+
  ylab("Number of Games") +
  labs(title = "Total Number of Relevent Games on Steam")

g_added

Question 5: Whats the change in new relevant titles being published to Steam from 2012 - 2021?

g_added_count <- g_without_2021 %>% 
  count(year)

grow_diff_titles <- c(268,268,393,549,720,911,1034,1101,1165)

g_added_count$differ <- grow_diff_titles

g_added_count <- g_added_count %>% 
  mutate(subtracted = n - differ) 
  
g_added_count %>%
  ggplot() +
  geom_line(aes(x = year, y = subtracted, group = 1), size = 1, color = "red")+
  geom_point(aes(x = year, y = subtracted, group = 1), size = 3, color = "red")+
  scale_x_continuous(breaks = seq(2012, 2020, by = 1)) +
  xlab("Years")+
  ylab("Numbers of Games") +
  labs(title = "New Relevant Games Published to Steam by Year")


g_added_count
NA

When analyzing this data we are looking at what we consider to be relevant titles published on the Steam platform. Anyone can publish their game on Steam and as of 2020 their were nearly 50,000 titles published on the platform. The data utilized in the data set is pulled from a data set that focuses on games that are actually played. When looking at the graphs we can see that the total games on the library have increasing over the years. However, we can also see in the line graph that there has been less games being published to Steam since 2016.

Data Analysis

Question 1: What game had the best avg players performance on Steam?

games %>% 
  filter(avg == max(avg))

PLAYERUNKNOWN’S BATTLEGROUNDS is the game with the best avg player performance.

Question 2: What game had the most peak players in Steam history?

games %>% 
  filter(peak == max(peak))

The game with the highest peak players in Steam history is PLAYERUNKNOWN’S BATTLEGROUNDS with 3,236,027 players.

Question 3: Which game had the highest gain in players from the previous month?

games %>% 
  drop_na(gain) %>% 
  filter(gain == max(gain))
NA

PLAYERUNKNOWN’S BATTLEGROUNDS has had the greatest gain from the prior month in all of steam history.

Question 4: Which game has had the biggest loss of players from one month to the next in Steam history?

games %>% 
  drop_na(gain) %>%
  filter(gain == min(gain))

It makes sense that Cyberpunk 2077 had the biggest loss of players from one month to the next because the game was filled with bugs that made the game had to enjoy so many poeple returned the game.

Conclusion

With all the exploratory data analysis complete, lets run down what we have learned. We found that single player games differ when it comes to average players over years when compared to multiplayer games. Multiplayer games tend to have an increase from launch and either stay consistent in rising for each year or decreasing (EX. Dota 2 & Playerunknowns Battlegrounds respectively). While single player games have a all time high avg players on launch and then drops down and stays consistent. This makes a lot of sense when looking at GTA 5 because the game is a mix of single and multiplayer, so it declines on the first year but once people finished the single player the multiplayer version of the game follows the trend of other purely multiplayer titles. We also learned that large spikes in avg players of a game that are not gradual means that there was most likely a game give away at some point. An example of this is Payday 2 and CSGO where they just jump from one month to the next. When aggregating all games on Steam we learned that there is a seasonal trend when it comes to peak and avg players. We found that gamers tend to play more when there is holidays, or summer break. When looking at total number of players in each year based on peak and average players we see a linear increase in players over the years. This means that Steam is growing its customer base over time, although there was a slight decrease in 2019 when popular title Fortnite was being played on another platform EPIC Games. So, we believe that Fortnite to be the ultimate cause, however after Fortnite lost traction Steam’s overall players increased passed 2018. We also found that the relevant total number of games released on steam has increased over time. However, the amount of relevant games published from 2016-present has been lower than other years. Finally, we found the best game on Steam which was Playerunknowns Battlegrounds with the best avg, peak, and gain in all of Steam history. We found the worst game in terms of players lost with the lowest gain in Steam history which was Cyberpunk 2077 which lost 250249 players from one month to the next.

Future works

There is still a lot to be found and explored with this dataset. For one the data that we did analyze for single player and multiplayer games was just a handful of games, so we would run more analysis for those types. Another thing that would improve the analysis of this data set would be to mutate a column that specifies what type of game that it is whether it be multiplayer, single player, or both. Another good mutate would be what genre the game is in, and price of the game. These mutates would enable us to make sense of how gamers behave when there is a certain price for certain titles. We do know that when games are suddenly given out for free avg players increase, but at the moment we cant compare two shooter multiplayer games at different prices without doing research. It would also be useful for the future to determine how Steam Charts decides which games are relevant enough to record. When looking at the actual Steam platform there is more than 1200 games. Currently, we are just assuming that these titles have enough players to be considered worth while keeping track of.

LS0tDQp0aXRsZTogJ0ZpbmFsIFJlcG9ydCBmb3IgSW50cm8gdG8gRGF0YSBTY2llbmNlOiBTdGVhbSBHYW1lcycNCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICB0aGVtZTogZGFya2x5DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB0cnVlDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQotLS0NCg0KIyMgR3JvdXAgTWVtYmVycw0KDQotIFJhbmR5IEtvbGloYQ0KDQotIElzYWlhaCBTYXJyaWENCg0KLSBPd2VuIFRlbGlzDQoNCi0gSm9obiBMZXZpdHQNCg0KDQoNCiMgSW50cm9kdWN0aW9uDQoNClN0ZWFtIGlzIGEgcG9wdWxhciwgb25saW5lIHZpZGVvIGdhbWUgZGlzdHJpYnV0b3Igd2l0aCBtYW55IG90aGVyIGNvbXBsZW1lbnRpbmcgZmVhdHVyZXMuIFN0ZWFtIGhvc3RzIGNvbW11bml0eSBkaXNjdXNzaW9uIHRocmVhZHMsIGFjY2VzcyB0byBkb3dubG9hZCBjb21tdW5pdHktbWFkZSBtb2RpZmljYXRpb25zIHRvIGdhbWVzIHNvbGQgb24gdGhlIHBsYXRmb3JtLCBzb2NpYWwgbWVkaWEtbGlrZSB1c2VyIHByb2ZpbGVzIGFuZCBmcmllbmRzIGxpc3RzIHRoYXQgZGlzcGxheXMgdGhlIHVzZXJzIG92ZXJhbGwgb3IgcmVjZW50IHZpZGVvIGdhbWUgYWN0aXZpdHksIGFuZCBzYWxlcyBldmVudHMgd2hpY2ggYXJlIGJhc2VkIG9uIGhvbGlkYXlzIG9yIHVuaXF1ZSB0aGVtZXMuDQoNCldlIHdhbnQgdG8gYW5hbHl6ZSBhIGRhdGFzZXQgcmVnYXJkaW5nIFN0ZWFtIGdhbWVzIHRvIGRpdmUgZGVlcCBpbnRvIHRoZSBiZWhhdmlvciBvZiBnYW1lcnMgb24gdGhlIHBsYXRmb3JtLg0KDQoNCg0KDQojIFBhY2thZ2VzDQoNCg0KTG9hZGluZyBhbnkgbmVlZGVkIHBhY2thZ2VzLg0KDQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShzY2FsZXMpDQpsaWJyYXJ5KGRpcmVjdGxhYmVscykNCmBgYA0KDQojIFRoZSBEYXRhc2V0DQoNClRoZSBnYW1lcy5jc3YgZGF0YXNldCBoYXMgZGF0YSBjb2xsZWN0ZWQgZm9yIGdhbWVzIG9uIHRoZSBwb3B1bGFyIGdhbWUgbGljZW5zZSBzZWxsaW5nIHBsYXRmb3JtLCBTdGVhbSwgb3ZlciB0aGUgbW9udGhzIGZyb20gdGhlIHllYXJzIEp1bHkgMjAxMi0gRmVidWFyeSAyMDIxLiBUaGUgZGF0YSBzZXQgaGFzIHJlY29yZHMgb2YgMTI1OCBnYW1lcyAoYWxzbyBpbmNsdWRlcyBvdGhlciBtaXNjZWxsYW5lb3VzIHBpZWNlcyBvZiBzb2Z0d2FyZSksIGFuZCBpbmNsdWRlcyB0aGVpciB0aXRsZXMsIG1vbnRobHkgcGxheWVyIHBlYWtzLCBtb250aGx5IGF2ZXJhZ2UgcGxheWVycyBhdCB0aGUgc2FtZSB0aW1lLCBtb250aGx5IGdhaW5zL2xvc3NlcyBvZiBwbGF5ZXJzIGNvbXBhcmVkIHRvIHRoZSBwcmV2aW91cyBtb250aCwgYW5kIHRoZSBwZXJjZW50YWdlIG9mIGhvdyBjbG9zZWx5IHRoZSBhdmVyYWdlIHBsYXllcnMgYXBwcm9hY2ggdGhlIHBlYWsuIEl0IHNob3VsZCBhbHNvIGJlIG5vdGVkIHRoYXQgdGhlIGRhdGEgc2V0IHdhcyBzY3JhcHBlZCBkYXRhIGZyb20gU3RlYW0gYnkgU3RlYW0gQ2hhcnRzLCBhbmQgb25seSB0cmFja3MgcmVsZXZhbnQgZ2FtZXMgb24gU3RlYW0uDQoNCiMjIFJ1bm5pbmcgdGhlIGRhdGEgJiBjbGVhbmluZyB1cA0KDQpgYGB7cn0NCiMgU3RvcmluZyBkYXRhc2V0IGluIGBnYW1lc2ANCmdhbWVzIDwtIHJlYWQuY3N2KCJnYW1lcy5jc3YiKQ0KDQojY2xlYW5pbmcgaXQgdXANCg0KZ2FtZXMgPC0gZ2FtZXMgJT4lIA0KICBtdXRhdGUoIG51bWJlcl9vZl9tb250aCA9IG1hdGNoKGdhbWVzWzE6ODM2MzEsM10sIG1vbnRoLm5hbWUpICkgJT4lIA0KICBzZWxlY3QoZ2FtZW5hbWUseWVhcixudW1iZXJfb2ZfbW9udGgsZXZlcnl0aGluZygpKSAlPiUgDQogIGFycmFuZ2UoZGVzYyh5ZWFyKSwgbnVtYmVyX29mX21vbnRoKQ0KICBnYW1lcw0KYGBgDQoNCiMgRGF0YSBFeHBsb3JhdGlvbg0KDQpgYGB7cn0NCnN1bW1hcnkoZ2FtZXMpDQpgYGANCg0KDQojIyBIb3cgbWFueSBnYW1lcyBhcmUgaW4gdGhlIGRhdGEgc2V0Pw0KDQpgYGB7cn0NCiMgRmluZGluZyB0aGUgZGlzdGluY3QgbnVtYmVyIG9mIGBnYW1lbmFtZXNgDQpkaXN0X2cgPC0gZ2FtZXMgJT4lIA0KICBkaXN0aW5jdChnYW1lbmFtZSkgDQoNCmRpc3RfZw0KDQojIGluIGFscGhhIG9yZGVyDQoNCiBkaXN0X2dfYWxwaGEgPC0gZ2FtZXMgJT4lIA0KICBkaXN0aW5jdChnYW1lbmFtZSkgJT4lIA0KICBhcnJhbmdlKGdhbWVuYW1lKQ0KDQpkaXN0X2dfYWxwaGENCmBgYA0KDQo+IFRoZXJlIGlzIDEyNTggZ2FtZXMgb24gc3RlYW0uDQoNCg0KIyMgKipRdWVzdGlvbiAxOiBEbyBhbGwgZ2FtZXMgbG9zZSBwb3B1bGFyaXR5IG92ZXJ0aW1lPyBIb3cgZG8gbXVsdGlwbGF5ZXIgYW5kIHNpbmdsZSBwbGF5ZXIgdGl0bGVzIGRpZmZlcj8qKg0KDQojIyMgQ2FzZSAxOiBXaGF0IGlmIHRoZSBnYW1lIGlzIGdpdmVuIG91dCBmb3IgZnJlZSBhZnRlciBpdHMgYmVlbiBmb3Igc2FsZT8NCg0KYGBge3J9DQpnX3BheWRheSA8LSBnYW1lcyAlPiUgDQogIGZpbHRlcihnYW1lbmFtZSA9PSAiUEFZREFZIDIiKSAlPiUgDQogIGZpbHRlcih5ZWFyICVpbiUgYygyMDEyOjIwMjEpKSAlPiUgDQogIG11dGF0ZShsYWJlbCA9IGlmX2Vsc2UobnVtYmVyX29mX21vbnRoID09IG1heChudW1iZXJfb2ZfbW9udGgpLCBhcy5jaGFyYWN0ZXIoeWVhciksIE5BX2NoYXJhY3Rlcl8pKQ0KZ19wYXlkYXkNCg0KI21ha2VzIHRoZSBQQVlEQVkgMiBkYXRhZnJhbWUgDQoNClllYXJzX1BheWRheTIgPC0gYXMuZmFjdG9yKGdfcGF5ZGF5JHllYXIpDQpnZ3Bsb3QoZ19wYXlkYXksYWVzKHggPSBudW1iZXJfb2ZfbW9udGgseSA9IGF2ZywgZ3JvdXAgPSB5ZWFyLCBjb2xvciA9IFllYXJzX1BheWRheTIpKSArDQpnZW9tX2xpbmUoc2l6ZSA9IDEpICsNCmdlb21fcG9pbnQoKSsgDQpzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDEsIDEyLCBieSA9IDEpLGV4cGFuZD1jKDAsIDEpKSsgDQpnZW9tX2RsKGFlcyhsYWJlbCA9IHllYXIpLCBtZXRob2QgPSBsaXN0KGRsLnRyYW5zKHggPSB4ICsgMC4xKSwgImxhc3QucG9pbnRzIiwgY2V4ID0gMSkpICsNCnNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzPWMoIiM5NjRCMDAiLCIjZjU4MjMxIiwiIzAzMDAwMCIsICIjMDBGQkZFIiwgIiMzY2I0NGIiLCAiI0ZGMDAwNCIsICIjNDM2M2Q4IiwgIiM5MTFlYjQiLCAiI2YwMzJlNiIsICIjYTlhOWE5IiApKSArDQogIHhsYWIoIk1vbnRocyIpKw0KICB5bGFiKCJBdmVyYWdlIFBsYXllcnMiKSArDQogIGxhYnModGl0bGUgPSAiUGF5ZGF5IDI6IEF2ZXJhZ2UgUGxheWVycyBieSBZZWFyIikNCg0KI2F1dG8gY29sb3IgcGFsbGV0IGlmICsgc2NhbGUgbWFudWFsIGlzIHJlbW92ZWQNCmBgYA0KDQo+ICFbKipXaHkgUGF5ZGF5IDIgU3Bpa2VkIEluIDIwMTcqKl0oaHR0cHM6Ly9pLmliYi5jby9qZndtV2p5L3BheWRheTJwaWMuanBnKQ0KDQojIyMgQ2FzZSAyOiBNdWx0aXBsYXllci9Fc3BvcnRzIFRpdGxlcw0KDQpgYGB7cn0NCmdfcHViZyA8LSBnYW1lcyAlPiUgDQogIGZpbHRlcihnYW1lbmFtZSA9PSAiUExBWUVSVU5LTk9XTidTIEJBVFRMRUdST1VORFMiKSAlPiUgDQogIGZpbHRlcih5ZWFyICVpbiUgYygyMDE3OjIwMjEpKSAlPiUgDQogIG11dGF0ZShsYWJlbCA9IGlmX2Vsc2UobnVtYmVyX29mX21vbnRoID09IG1heChudW1iZXJfb2ZfbW9udGgpLCBhcy5jaGFyYWN0ZXIoeWVhciksIE5BX2NoYXJhY3Rlcl8pKQ0KZ19wdWJnDQoNClllYXJzX1BVQkcgPC0gYXMuZmFjdG9yKGdfcHViZyR5ZWFyKQ0KZ2dwbG90KGdfcHViZyxhZXMoeCA9IG51bWJlcl9vZl9tb250aCx5ID0gYXZnLCBncm91cCA9IHllYXIsIGNvbG9yID0gWWVhcnNfUFVCRykpICsNCmdlb21fbGluZShzaXplID0gMSkgKw0KZ2VvbV9wb2ludCgpKyANCnNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMSwgMTIsIGJ5ID0gMSksZXhwYW5kPWMoMCwgMSkpKyANCmdlb21fZGwoYWVzKGxhYmVsID0geWVhciksIG1ldGhvZCA9IGxpc3QoZGwudHJhbnMoeCA9IHggKyAwLjEpLCAibGFzdC5wb2ludHMiLCBjZXggPSAxKSkgKw0Kc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXM9YygiIzk2NEIwMCIsIiNmNTgyMzEiLCIjMDMwMDAwIiwgIiMwMEZCRkUiLCAiIzNjYjQ0YiIsICAiI2E5YTlhOSIgKSkgKw0KICB4bGFiKCJNb250aHMiKSsNCiAgeWxhYigiQXZlcmFnZSBQbGF5ZXJzIikgKw0KICBsYWJzKHRpdGxlID0gIlBMQVlFUlVOS05PV04nUyBCQVRUTEVHUk9VTkRTOiBBdmVyYWdlIFBsYXllcnMgYnkgWWVhciIpDQoNCmdfY3NnbyA8LSBnYW1lcyAlPiUgDQogIGZpbHRlcihnYW1lbmFtZSA9PSAiQ291bnRlci1TdHJpa2U6IEdsb2JhbCBPZmZlbnNpdmUiKSAlPiUgDQogIGZpbHRlcih5ZWFyICVpbiUgYygyMDEyOjIwMjEpKSAlPiUgDQogIG11dGF0ZShsYWJlbCA9IGlmX2Vsc2UobnVtYmVyX29mX21vbnRoID09IG1heChudW1iZXJfb2ZfbW9udGgpLCBhcy5jaGFyYWN0ZXIoeWVhciksIE5BX2NoYXJhY3Rlcl8pKQ0KZ19jc2dvDQoNClllYXJzX2NzZ28gPC0gYXMuZmFjdG9yKGdfY3NnbyR5ZWFyKQ0KZ2dwbG90KGdfY3NnbyxhZXMoeCA9IG51bWJlcl9vZl9tb250aCx5ID0gYXZnLCBncm91cCA9IHllYXIsIGNvbG9yID0gWWVhcnNfY3NnbykpICsNCmdlb21fbGluZShzaXplID0gMSkgKw0KZ2VvbV9wb2ludCgpKyANCnNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMSwgMTIsIGJ5ID0gMSksZXhwYW5kPWMoMCwgMSkpKyANCmdlb21fZGwoYWVzKGxhYmVsID0geWVhciksIG1ldGhvZCA9IGxpc3QoZGwudHJhbnMoeCA9IHggKyAwLjEpLCAibGFzdC5wb2ludHMiLCBjZXggPSAxKSkgKw0Kc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXM9YygiIzk2NEIwMCIsIiNmNTgyMzEiLCIjMDMwMDAwIiwgIiMwMEZCRkUiLCAiIzNjYjQ0YiIsICIjRkYwMDA0IiwgIiM0MzYzZDgiLCAiIzkxMWViNCIsICIjZjAzMmU2IiwgIiNhOWE5YTkiICkpICsNCiAgeGxhYigiTW9udGhzIikrDQogIHlsYWIoIkF2ZXJhZ2UgUGxheWVycyIpICsNCiAgbGFicyh0aXRsZSA9ICJDb3VudGVyIFN0cmlrZTogR2xvYmFsIE9mZmVuc2l2ZTogQXZlcmFnZSBQbGF5ZXJzIGJ5IFllYXIiKQ0KDQpnX2d0YXYgPC0gZ2FtZXMgJT4lIA0KICBmaWx0ZXIoZ2FtZW5hbWUgPT0gIkdyYW5kIFRoZWZ0IEF1dG8gViIpICU+JSANCiAgZmlsdGVyKHllYXIgJWluJSBjKDIwMTI6MjAyMSkpICU+JSANCiAgbXV0YXRlKGxhYmVsID0gaWZfZWxzZShudW1iZXJfb2ZfbW9udGggPT0gbWF4KG51bWJlcl9vZl9tb250aCksIGFzLmNoYXJhY3Rlcih5ZWFyKSwgTkFfY2hhcmFjdGVyXykpDQpnX2d0YXYNCg0KWWVhcnNfZ3RhdiA8LSBhcy5mYWN0b3IoZ19ndGF2JHllYXIpDQpnZ3Bsb3QoZ19ndGF2LGFlcyh4ID0gbnVtYmVyX29mX21vbnRoLHkgPSBhdmcsIGdyb3VwID0geWVhciwgY29sb3IgPSBZZWFyc19ndGF2KSkgKw0KZ2VvbV9saW5lKHNpemUgPSAxKSArDQpnZW9tX3BvaW50KCkrIA0Kc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgxLCAxMiwgYnkgPSAxKSxleHBhbmQ9YygwLCAxKSkrIA0KZ2VvbV9kbChhZXMobGFiZWwgPSB5ZWFyKSwgbWV0aG9kID0gbGlzdChkbC50cmFucyh4ID0geCArIDAuMSksICJsYXN0LnBvaW50cyIsIGNleCA9IDEpKSArDQpzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcz1jKCIjOTY0QjAwIiwiI2Y1ODIzMSIsIiMwMzAwMDAiLCAiIzAwRkJGRSIsICIjM2NiNDRiIiwgIiNGRjAwMDQiLCAiIzQzNjNkOCIsICIjOTExZWI0IiwgIiNmMDMyZTYiLCAiI2E5YTlhOSIgKSkgKw0KICB4bGFiKCJNb250aHMiKSsNCiAgeWxhYigiQXZlcmFnZSBQbGF5ZXJzIikgKw0KICBsYWJzKHRpdGxlID0gIkdyYW5kIFRoZWZ0IEF1dG8gVjogQXZlcmFnZSBQbGF5ZXJzIGJ5IFllYXIiKQ0KDQpnX2RvdGEyIDwtIGdhbWVzICU+JSANCiAgZmlsdGVyKGdhbWVuYW1lID09ICJEb3RhIDIiKSAlPiUgDQogIGZpbHRlcih5ZWFyICVpbiUgYygyMDEyOjIwMjEpKSAlPiUgDQogIG11dGF0ZShsYWJlbCA9IGlmX2Vsc2UobnVtYmVyX29mX21vbnRoID09IG1heChudW1iZXJfb2ZfbW9udGgpLCBhcy5jaGFyYWN0ZXIoeWVhciksIE5BX2NoYXJhY3Rlcl8pKQ0KZ19kb3RhMg0KDQpZZWFyc19kb3RhMiA8LSBhcy5mYWN0b3IoZ19kb3RhMiR5ZWFyKQ0KZ2dwbG90KGdfZG90YTIsYWVzKHggPSBudW1iZXJfb2ZfbW9udGgseSA9IGF2ZywgZ3JvdXAgPSB5ZWFyLCBjb2xvciA9IFllYXJzX2RvdGEyKSkgKw0KZ2VvbV9saW5lKHNpemUgPSAxKSArDQpnZW9tX3BvaW50KCkrIA0Kc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgxLCAxMiwgYnkgPSAxKSxleHBhbmQ9YygwLCAxKSkrIA0KZ2VvbV9kbChhZXMobGFiZWwgPSB5ZWFyKSwgbWV0aG9kID0gbGlzdChkbC50cmFucyh4ID0geCArIDAuMSksICJsYXN0LnBvaW50cyIsIGNleCA9IDEpKSArDQpzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcz1jKCIjOTY0QjAwIiwiI2Y1ODIzMSIsIiMwMzAwMDAiLCAiIzAwRkJGRSIsICIjM2NiNDRiIiwgIiNGRjAwMDQiLCAiIzQzNjNkOCIsICIjOTExZWI0IiwgIiNmMDMyZTYiLCAiI2E5YTlhOSIgKSkgKw0KICB4bGFiKCJNb250aHMiKSsNCiAgeWxhYigiQXZlcmFnZSBQbGF5ZXJzIikgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsNCiAgbGFicyh0aXRsZSA9ICJET1RBIDI6IEF2ZXJhZ2UgUGxheWVycyBieSBZZWFyIikNCmBgYA0KDQo+IENTR08gYWxzbyB3YXMgZ2l2ZW4gb3V0IGZvciBmcmVlIGluIDIwMjAgc28gdGhhdCBzaG93cyBzaW1pbGFyaXRpZXMgd2l0aCB0aGUgZ2FtZXMgZ2l2ZW4gb3V0IGZvciBmcmVlIG92ZXIgdGltZS4NCg0KPiBUaGlzIGRhdGEgc2hvd3MgdGhhdCBtYW55IG11bHRpcGxheWVyIGdhbWVzIHNlZW0gdG8gZ2FpbiBwbGF5ZXJzIG92ZXIgdGltZSBhbmQgb2Z0ZW4gaGF2ZSB0aGVpciBwZWFrIGF2ZXJhZ2UgcGxheWVycyBvY2N1ciBpbiBhIHBlcmlvZCBzaWduZmljYW50bHkgYWZ0ZXIgdGhlIGxhdW5jaCBvZiB0aGUgZ2FtZS4gV2hpbGUgR1RBIDUgZGVjcmVhc2VzIHVubGlrZSB0aGUgbXVsdGlwbGF5ZXIgZ2FtZXMgaW4gdGhlIGZpcnN0IHllYXIsIGEgdmFyaWJsZSB0aGF0IGhhcyB0byBiZSBmYWN0b3JlZCBpbiBpcyB0aGF0IEdUQSA1IGlzIGEgc2luZ2xlIGFuZCBtdXRpcGxheWVyIGdhbWUuIFNvLCB3ZSBzZWUgYSBzdWRkZW4gZHJvcCBvbiByZWxlYXNlIGJ1dCBpbmNyZWFzaW5nIHBsYXllcnMgb3ZlciB0aW1lLg0KDQojIyMgQ2FzZSAzOiBTaW5nbGUgUGxheWVyIFRpdGxlcw0KYGBge3J9DQpnX2ZhbGxvdXQ0IDwtIGdhbWVzICU+JSANCiAgZmlsdGVyKGdhbWVuYW1lID09ICJGYWxsb3V0IDQiKSAlPiUgDQogIGZpbHRlcih5ZWFyICVpbiUgYygyMDEyOjIwMjEpKSAlPiUgDQogIG11dGF0ZShsYWJlbCA9IGlmX2Vsc2UobnVtYmVyX29mX21vbnRoID09IG1heChudW1iZXJfb2ZfbW9udGgpLCBhcy5jaGFyYWN0ZXIoeWVhciksIE5BX2NoYXJhY3Rlcl8pKQ0KZ19mYWxsb3V0NA0KDQpZZWFyc19mYWxsb3V0NCA8LSBhcy5mYWN0b3IoZ19mYWxsb3V0NCR5ZWFyKQ0KZ2dwbG90KGdfZmFsbG91dDQsYWVzKHggPSBudW1iZXJfb2ZfbW9udGgseSA9IGF2ZywgZ3JvdXAgPSB5ZWFyLCBjb2xvciA9IFllYXJzX2ZhbGxvdXQ0KSkgKw0KZ2VvbV9saW5lKHNpemUgPSAxKSArDQpnZW9tX3BvaW50KCkrIA0Kc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgxLCAxMiwgYnkgPSAxKSxleHBhbmQ9YygwLCAxKSkrIA0KZ2VvbV9kbChhZXMobGFiZWwgPSB5ZWFyKSwgbWV0aG9kID0gbGlzdChkbC50cmFucyh4ID0geCArIDAuMSksICJsYXN0LnBvaW50cyIsIGNleCA9IDEpKSArDQpzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcz1jKCIjOTY0QjAwIiwiI2Y1ODIzMSIsIiMwMzAwMDAiLCAiIzAwRkJGRSIsICIjM2NiNDRiIiwgIiNGRjAwMDQiLCAiIzQzNjNkOCIsICIjOTExZWI0IiwgIiNmMDMyZTYiLCAiI2E5YTlhOSIgKSkgKw0KICB4bGFiKCJNb250aHMiKSsNCiAgeWxhYigiQXZlcmFnZSBQbGF5ZXJzIikgKw0KICBsYWJzKHRpdGxlID0gIkZhbGxvdXQgNDogQXZlcmFnZSBQbGF5ZXJzIGJ5IFllYXIiKQ0KDQpnX2ZhcmNyeTUgPC0gZ2FtZXMgJT4lIA0KICBmaWx0ZXIoZ2FtZW5hbWUgPT0gIkZhciBDcnkgNSIpICU+JSANCiAgZmlsdGVyKHllYXIgJWluJSBjKDIwMTI6MjAyMSkpICU+JSANCiAgbXV0YXRlKGxhYmVsID0gaWZfZWxzZShudW1iZXJfb2ZfbW9udGggPT0gbWF4KG51bWJlcl9vZl9tb250aCksIGFzLmNoYXJhY3Rlcih5ZWFyKSwgTkFfY2hhcmFjdGVyXykpDQpnX2ZhcmNyeTUNCg0KWWVhcnNfZmFyY3J5NSA8LSBhcy5mYWN0b3IoZ19mYXJjcnk1JHllYXIpDQpnZ3Bsb3QoZ19mYXJjcnk1LGFlcyh4ID0gbnVtYmVyX29mX21vbnRoLHkgPSBhdmcsIGdyb3VwID0geWVhciwgY29sb3IgPSBZZWFyc19mYXJjcnk1KSkgKw0KZ2VvbV9saW5lKHNpemUgPSAxKSArDQpnZW9tX3BvaW50KCkrIA0Kc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgxLCAxMiwgYnkgPSAxKSxleHBhbmQ9YygwLCAxKSkrIA0KZ2VvbV9kbChhZXMobGFiZWwgPSB5ZWFyKSwgbWV0aG9kID0gbGlzdChkbC50cmFucyh4ID0geCArIDAuMSksICJsYXN0LnBvaW50cyIsIGNleCA9IDEpKSArDQpzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcz1jKCIjOTY0QjAwIiwiI2Y1ODIzMSIsIiMwMzAwMDAiLCAiIzAwRkJGRSIsICIjM2NiNDRiIiwgIiNGRjAwMDQiLCAiIzQzNjNkOCIsICIjOTExZWI0IiwgIiNmMDMyZTYiLCAiI2E5YTlhOSIgKSkgKw0KICB4bGFiKCJNb250aHMiKSsNCiAgeWxhYigiQXZlcmFnZSBQbGF5ZXJzIikgKw0KICBsYWJzKHRpdGxlID0gIkZhcmNyeSA1OiBBdmVyYWdlIFBsYXllcnMgYnkgWWVhciIpDQoNCmdfY3liZXJwdW5rIDwtIGdhbWVzICU+JSANCiAgZmlsdGVyKGdhbWVuYW1lID09ICJDeWJlcnB1bmsgMjA3NyIpICU+JSANCiAgZmlsdGVyKHllYXIgJWluJSBjKDIwMTI6MjAyMSkpICU+JSANCiAgbXV0YXRlKGxhYmVsID0gaWZfZWxzZShudW1iZXJfb2ZfbW9udGggPT0gbWF4KG51bWJlcl9vZl9tb250aCksIGFzLmNoYXJhY3Rlcih5ZWFyKSwgTkFfY2hhcmFjdGVyXykpDQpnX2N5YmVycHVuaw0KDQpZZWFyc19jeWJlcnB1bmsgPC0gYXMuZmFjdG9yKGdfY3liZXJwdW5rJHllYXIpDQpnZ3Bsb3QoZ19jeWJlcnB1bmssYWVzKHggPSBudW1iZXJfb2ZfbW9udGgseSA9IGF2ZywgZ3JvdXAgPSB5ZWFyLCBjb2xvciA9IFllYXJzX2N5YmVycHVuaykpICsNCmdlb21fbGluZShzaXplID0gMSkgKw0KZ2VvbV9wb2ludCgpKyANCnNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMSwgMTIsIGJ5ID0gMSksZXhwYW5kPWMoMCwgMSkpKyANCmdlb21fZGwoYWVzKGxhYmVsID0geWVhciksIG1ldGhvZCA9IGxpc3QoZGwudHJhbnMoeCA9IHggKyAwLjEpLCAibGFzdC5wb2ludHMiLCBjZXggPSAxKSkgKw0Kc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXM9YygiIzk2NEIwMCIsIiNmNTgyMzEiLCIjMDMwMDAwIiwgIiMwMEZCRkUiLCAiIzNjYjQ0YiIsICIjRkYwMDA0IiwgIiM0MzYzZDgiLCAiIzkxMWViNCIsICIjZjAzMmU2IiwgIiNhOWE5YTkiICkpICsNCiAgeGxhYigiTW9udGhzIikrDQogIHlsYWIoIkF2ZXJhZ2UgUGxheWVycyIpICsNCiAgbGFicyh0aXRsZSA9ICJDeWJlcnB1bmsgMjA3NzogQXZlcmFnZSBQbGF5ZXJzIGJ5IFllYXIiKQ0KDQpnX2dpcmwgPC0gZ2FtZXMgJT4lIA0KICBmaWx0ZXIoZ2FtZW5hbWUgPT0gIkhlbnRhaSBHaXJsIikgJT4lIA0KICBmaWx0ZXIoeWVhciAlaW4lIGMoMjAxMjoyMDIxKSkgJT4lIA0KICBtdXRhdGUobGFiZWwgPSBpZl9lbHNlKG51bWJlcl9vZl9tb250aCA9PSBtYXgobnVtYmVyX29mX21vbnRoKSwgYXMuY2hhcmFjdGVyKHllYXIpLCBOQV9jaGFyYWN0ZXJfKSkNCmdfZ2lybA0KDQpZZWFyc19naXJsIDwtIGFzLmZhY3RvcihnX2dpcmwkeWVhcikNCmdncGxvdChnX2dpcmwsYWVzKHggPSBudW1iZXJfb2ZfbW9udGgseSA9IGF2ZywgZ3JvdXAgPSB5ZWFyLCBjb2xvciA9IFllYXJzX2dpcmwpKSArDQpnZW9tX2xpbmUoc2l6ZSA9IDEpICsNCmdlb21fcG9pbnQoKSsgDQpzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDEsIDEyLCBieSA9IDEpLGV4cGFuZD1jKDAsIDEpKSsgDQpnZW9tX2RsKGFlcyhsYWJlbCA9IHllYXIpLCBtZXRob2QgPSBsaXN0KGRsLnRyYW5zKHggPSB4ICsgMC4xKSwgImxhc3QucG9pbnRzIiwgY2V4ID0gMSkpICsNCnNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzPWMoIiM5NjRCMDAiLCIjZjU4MjMxIiwiIzAzMDAwMCIsICIjMDBGQkZFIiwgIiMzY2I0NGIiLCAiI0ZGMDAwNCIsICIjNDM2M2Q4IiwgIiM5MTFlYjQiLCAiI2YwMzJlNiIsICIjYTlhOWE5IiApKSArDQogIHhsYWIoIk1vbnRocyIpKw0KICB5bGFiKCJBdmVyYWdlIFBsYXllcnMiKSArDQogIGxhYnModGl0bGUgPSAiSGVudGFpIEdpcmw6IEF2ZXJhZ2UgUGxheWVycyBieSBZZWFyIikNCmBgYA0KDQo+IFRoaXMgZGF0YSBzaG93cyB0aGF0IHNpbmdsZXBsYXllciB0aXRsZXMgc2VlbSB0byBoYXZlIGEgZHJhc3RpYyBmYWxsIG9mZiBpbiB0aGVpciBwbGF5ZXIgYmFzZSBmb2xsb3dpbmcgdGhlIGxhdW5jaCBvZiB0aGUgZ2FtZS4gVGhpcyBtb3N0IGxpa2VseSBvY2N1cnMgYmVjYXVzZSBvbmNlIHNvbWVvbmUgYmVhdHMgYSBzaW5nbGUgcGxheWVyIGdhbWUgdGhleSBhcmUgbGVzcyBsaWtlbHkgdG8gcmV0dXJuIHRvIGl0LiBUaGlzIGNhbiBhbHNvIGJlIGF0dHJpYnV0ZWQgdG8gdGhlIGZhY3QgdGhhdCBtdWx0aXBsYXllci9lc3BvcnRzIGdhbWVzIGFyZSB1c3VhbGx5IGNvbnRpbnVhbGx5IHVwZGF0ZWQgd2l0aCBuZXcgY29udGVudCwgd2hlcmUgYXMgc2luZ2xlIHBsYXllciBnYW1lIHR5cGljYWxseSBhcmUgbGVzcyBsaWtlbHkgdG8gcmVjZWl2ZSB0aGVzZSB1cGRhdGVzIGNvbnNpc3RlbnRseS4NCg0KIyMgKipRdWVzdGlvbiAyOiBJcyB0aGUgU3RlYW0gcGxhdGZvcm0gYWZmZWN0ZWQgYnkgc2Vhc29uYWxpdHk/KioNCg0KYGBge3J9DQpnYW1lc19zZWFzb25zIDwtIGdhbWVzICU+JSANCiAgZmlsdGVyKHllYXIgJWluJSBjKDIwMTI6MjAyMSkpICU+JSANCiAgZ3JvdXBfYnkobnVtYmVyX29mX21vbnRoKSAlPiUgDQogIHN1bW1hcmlzZShhdmdfbW9udGhfc3VtID0gc3VtKGF2ZykpIA0KZ2dwbG90KGRhdGEgPSBnYW1lc19zZWFzb25zKSArDQogIGdlb21fbGluZShhZXMoeCA9IG51bWJlcl9vZl9tb250aCwgeSA9IGF2Z19tb250aF9zdW0pLGNvbG9yID0gImJsdWUiLCBzaXplID0gMSkgKw0KICBnZW9tX3BvaW50KGFlcyh4ID0gbnVtYmVyX29mX21vbnRoLCB5ID0gYXZnX21vbnRoX3N1bSksY29sb3IgPSAicmVkIiwgc2l6ZSA9IDMpKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDEsIDEyLCBieSA9IDEpLGV4cGFuZD1jKDAsIDEpKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkgKw0KICB4bGFiKCJNb250aHMiKSsNCiAgeWxhYigiQXZlcmFnZSBOdW1iZXIgb2YgUGxheWVycyIpICsNCiAgbGFicyh0aXRsZSA9ICJTdGVhbSBTZWFzb25hbGl0eSB1c2luZyBBdmcuIFBsYXllcnMiKQ0KZ2FtZXNfc2Vhc29ucw0KDQpnYW1lc19zZWFzb25zX3BrIDwtIGdhbWVzICU+JSANCiAgZmlsdGVyKHllYXIgJWluJSBjKDIwMTI6MjAyMSkpICU+JSANCiAgZ3JvdXBfYnkobnVtYmVyX29mX21vbnRoKSAlPiUgDQogIHN1bW1hcmlzZShwZWFrX21vbnRoX3N1bSA9IHN1bShwZWFrKSkgDQpnZ3Bsb3QoZGF0YSA9IGdhbWVzX3NlYXNvbnNfcGspICsNCiAgZ2VvbV9saW5lKGFlcyh4ID0gbnVtYmVyX29mX21vbnRoLCB5ID0gcGVha19tb250aF9zdW0pLGNvbG9yID0gImJsdWUiLCBzaXplID0gMSkgKw0KICBnZW9tX3BvaW50KGFlcyh4ID0gbnVtYmVyX29mX21vbnRoLCB5ID0gcGVha19tb250aF9zdW0pLGNvbG9yID0gInJlZCIsIHNpemUgPSAzKSsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgxLCAxMiwgYnkgPSAxKSxleHBhbmQ9YygwLCAxKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsNCiAgeGxhYigiTW9udGhzIikrDQogIHlsYWIoIlBlYWsgTnVtYmVyIG9mIFBsYXllcnMiKSArDQogIGxhYnModGl0bGUgPSAiU3RlYW0gU2Vhc29uYWxpdHkgdXNpbmcgUGVhayBQbGF5ZXJzIikNCmdhbWVzX3NlYXNvbnNfcGsNCmBgYA0KDQo+IFRoZSBkYXRhIHN1Z2dlc3RzIHRoYXQgdGhlcmUgaXMgYSBzZWFzb25hbGl0eSB0byBTdGVhbSdzIHBsYXllciBkYXRhLiBUaGlzIHNob3dzIHRoYXQgU3RlYW0gaGFzIHRoZSBtb3N0IHBsYXllcnMgYXJvdW5kIERlY2VtYmVyLCBKYW51cmFyeSwgYW5kIEZlYnVyYXJ5LiBXZSBzdXNwZWN0IHRoYXQgdGhpcyBvY2N1cnMgYmVjYXVzZSBvZiB0aGUgQ2hyaXN0bWFzIHNlYXNvbiBhbmQgcGVvcGxlIHJlY2lldmluZyBtb25leSBhbmQgZ2FtZXMgYXMgZ2lmdHMuIFRoZSBzdGVlcCBmYWxsIG9mZiB3ZSBzZWUgaW4gRmVidXJhcnkgbWF5IG9jY3VyIGJlY2F1c2UgaW5kaXZpZHVhbHMgaGF2ZSBjb21wbGV0ZWQgdGhlIGdhbWVzIHRoZXkgcmVjZWl2ZWQgZHVyaW5nIHRoZSBob2xpZGF5IHNlYXNvbi4gV2UgYWxzbyBzZWUgYW4gaW5jcmVhc2UgaW4gcGxheWVycyBkdXJpbmcgdGhlIHN1bW1lciBtb250aHMuIFdlIHN1c3BlY3QgdGhhdCB0aGlzIG9jY3VycyBiZWNhdXNlIGluZGl2aWR1YWxzIGFyZSBvdXQgb2Ygc2Nob29sIGZvciB0aGVpciBzdW1tZXIgYnJlYWssIGdpdmluZyB0aGVtIG1vcmUgdGltZSB0byBwbGF5IHZpZGVvIGdhbWVzIG9uIFN0ZWFtLg0KDQojIyAqKlF1ZXN0aW9uIDM6IFdoYXQgZG9lcyB0aGUgZ3Jvd3RoIG9mIFN0ZWFtIHBsYXllcnMgbG9vayBsaWtlIGZyb20gMjAxMiAtIDIwMjE/KioNCg0KYGBge3J9DQpnYW1lc191c2VyX2dyb3d0aCA8LSBnYW1lcyAlPiUgDQogIGZpbHRlcih5ZWFyICVpbiUgYygyMDEyOjIwMjApKSAlPiUgDQogIGdyb3VwX2J5KHllYXIpICU+JSANCiAgc3VtbWFyaXNlKGF2Z19tb250aF9hbGxfeWVhcnMgPSBzdW0oYXZnKSkNCmdncGxvdChkYXRhID0gZ2FtZXNfdXNlcl9ncm93dGgpICsNCiAgZ2VvbV9saW5lKGFlcyh4ID0geWVhciwgeSA9IGF2Z19tb250aF9hbGxfeWVhcnMpLGNvbG9yID0gImJsdWUiLCBzaXplID0gMSkgKw0KICBnZW9tX3BvaW50KGFlcyh4ID0geWVhciwgeSA9IGF2Z19tb250aF9hbGxfeWVhcnMpLGNvbG9yID0gInJlZCIsIHNpemUgPSAzKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMjAxMiwgMjAyMCwgYnkgPSAxKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsNCiAgeGxhYigiWWVhcnMiKSsNCiAgeWxhYigiQXZlcmFnZSBOdW1iZXIgb2YgUGxheWVycyIpICsNCiAgbGFicyh0aXRsZSA9ICJTdGVhbSBQbGF0Zm9ybSBHcm93dGggdXNpbmcgQXZnLiBQbGF5ZXJzIikNCmdhbWVzX3VzZXJfZ3Jvd3RoDQoNCmdhbWVzX3VzZXJfZ3Jvd3RoX3BrIDwtIGdhbWVzICU+JSANCiAgZmlsdGVyKHllYXIgJWluJSBjKDIwMTI6MjAyMCkpICU+JSANCiAgZ3JvdXBfYnkoeWVhcikgJT4lIA0KICBzdW1tYXJpc2UocGVha19tb250aF9hbGxfeWVhcnMgPSBzdW0ocGVhaykpIA0KZ2dwbG90KGRhdGEgPSBnYW1lc191c2VyX2dyb3d0aF9waykgKw0KICBnZW9tX2xpbmUoYWVzKHggPSB5ZWFyLCB5ID0gcGVha19tb250aF9hbGxfeWVhcnMpLGNvbG9yID0gImJsdWUiLCBzaXplID0gMSkgKw0KICBnZW9tX3BvaW50KGFlcyh4ID0geWVhciwgeSA9IHBlYWtfbW9udGhfYWxsX3llYXJzKSxjb2xvciA9ICJyZWQiLCBzaXplID0gMykgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDIwMTIsIDIwMjAsIGJ5ID0gMSkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSArDQogIHhsYWIoIlllYXJzIikrDQogIHlsYWIoIlBlYWsgTnVtYmVyIG9mIFBsYXllcnMiKSArDQogIGxhYnModGl0bGUgPSAiU3RlYW0gUGxhdGZvcm0gR3Jvd3RoIHVzaW5nIFBlYWsgUGxheWVycyIpDQpnYW1lc191c2VyX2dyb3d0aF9waw0KDQoNCmBgYA0KDQo+IFRoZSBncmFwaCBzaG93cyB0aGF0IHRoZSBTdGVhbSBwbGF0Zm9ybSBoYXMgaGFkIHJlbGF0aXZlbHkgY29uc2lzdGVudCBncm93dGggZnJvbSAyMDEyIHRvIDIwMjAuIEhvd2V2ZXIsIHdlIGNhbiBzZWUgdGhlIG9ubHkgdGltZSBTdGVhbSBoYXMgYSBkcm9wIGluIHVzZXJzIHdhcyBmcm9tIDIwMTggdG8gMjAxOS4gV2Ugc3VzcGVjdCB0aGlzIHRvIGJlIHJlbGF0ZWQgdG8gdGhlIHJpc2Ugb2Ygb3RoZXIgb25saW5lIGdhbWVzIG1hcmtldCBwbGFjZXMgc3VjaCBhcyB0aGUgRVBJQyBHYW1lcyBzdG9yZSBhbmQgdGhlIHBvcHVsYXJpdHkgb2YgRm9ydG5pdGUgYXQgdGhlIHRpbWUuIEluIE5vdmVtYmVyIG9mIDIwMTgsIEZvcnRuaXRlIGhpdCBhIDguMyBtaWxsaW9uIGNvbmN1cnJlbnQgcGxheWVycy4gV2Ugc3VzcGVjdCB0aGF0IHRoZSBwb3B1bGFyaXR5IG9mIEZvcnRuaXRlIGNvbWJpbmVkIHdpdGggdGhlIGZhY3QgaXQgd2FzIG5vdCBvbiBTdGVhbSBpcyB1bHRpbWF0ZWx5IHdoYXQgY2F1c2VkIHRoZSBkaXAgaW4gcGxheWVycyBmcm9tIDIwMTgtMjAxOS4NCg0KIyMgKipRdWVzdGlvbiA0OiBXaGF0IGlzIHRoZSB0b3RhbCBudW1iZXIgb2YgcmVsZXZhbnQgdGl0bGVzIG9uIHRoZSBTdGVhbSBwbGF0Zm9ybSBmcm9tIDIwMTIgLSAyMDIxPyoqDQoNCg0KYGBge3J9DQpnX3dpdGhvdXRfMjAyMSA8LSBnYW1lcyAlPiUgDQogIGZpbHRlcihudW1iZXJfb2ZfbW9udGggPT0gMTIsIHllYXIgJWluJSAyMDEyOjIwMjApDQoNCmdfYWRkZWQgPC0gZ193aXRob3V0XzIwMjEgJT4lIA0KZ2dwbG90KCkrDQogIGdlb21fYmFyKGFlcyh4ID0geWVhcikpKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDIwMTIsIDIwMjAsIGJ5ID0gMSkpICsNCiAgeGxhYigiWWVhcnMiKSsNCiAgeWxhYigiTnVtYmVyIG9mIEdhbWVzIikgKw0KICBsYWJzKHRpdGxlID0gIlRvdGFsIE51bWJlciBvZiBSZWxldmVudCBHYW1lcyBvbiBTdGVhbSIpDQoNCmdfYWRkZWQNCmBgYA0KDQoNCiMjICoqUXVlc3Rpb24gNTogV2hhdHMgdGhlIGNoYW5nZSBpbiBuZXcgcmVsZXZhbnQgdGl0bGVzIGJlaW5nIHB1Ymxpc2hlZCB0byBTdGVhbSBmcm9tIDIwMTIgLSAyMDIxPyoqDQoNCmBgYHtyfQ0KZ19hZGRlZF9jb3VudCA8LSBnX3dpdGhvdXRfMjAyMSAlPiUgDQogIGNvdW50KHllYXIpDQoNCmdyb3dfZGlmZl90aXRsZXMgPC0gYygyNjgsMjY4LDM5Myw1NDksNzIwLDkxMSwxMDM0LDExMDEsMTE2NSkNCg0KZ19hZGRlZF9jb3VudCRkaWZmZXIgPC0gZ3Jvd19kaWZmX3RpdGxlcw0KDQpnX2FkZGVkX2NvdW50IDwtIGdfYWRkZWRfY291bnQgJT4lIA0KICBtdXRhdGUoc3VidHJhY3RlZCA9IG4gLSBkaWZmZXIpIA0KICANCmdfYWRkZWRfY291bnQgJT4lDQogIGdncGxvdCgpICsNCiAgZ2VvbV9saW5lKGFlcyh4ID0geWVhciwgeSA9IHN1YnRyYWN0ZWQsIGdyb3VwID0gMSksIHNpemUgPSAxLCBjb2xvciA9ICJyZWQiKSsNCiAgZ2VvbV9wb2ludChhZXMoeCA9IHllYXIsIHkgPSBzdWJ0cmFjdGVkLCBncm91cCA9IDEpLCBzaXplID0gMywgY29sb3IgPSAicmVkIikrDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMjAxMiwgMjAyMCwgYnkgPSAxKSkgKw0KICB4bGFiKCJZZWFycyIpKw0KICB5bGFiKCJOdW1iZXJzIG9mIEdhbWVzIikgKw0KICBsYWJzKHRpdGxlID0gIk5ldyBSZWxldmFudCBHYW1lcyBQdWJsaXNoZWQgdG8gU3RlYW0gYnkgWWVhciIpDQoNCmdfYWRkZWRfY291bnQNCg0KYGBgDQoNCj4gV2hlbiBhbmFseXppbmcgdGhpcyBkYXRhIHdlIGFyZSBsb29raW5nIGF0IHdoYXQgd2UgY29uc2lkZXIgdG8gYmUgcmVsZXZhbnQgdGl0bGVzIHB1Ymxpc2hlZCBvbiB0aGUgU3RlYW0gcGxhdGZvcm0uIEFueW9uZSBjYW4gcHVibGlzaCB0aGVpciBnYW1lIG9uIFN0ZWFtIGFuZCBhcyBvZiAyMDIwIHRoZWlyIHdlcmUgbmVhcmx5IDUwLDAwMCB0aXRsZXMgcHVibGlzaGVkIG9uIHRoZSBwbGF0Zm9ybS4gVGhlIGRhdGEgdXRpbGl6ZWQgaW4gdGhlIGRhdGEgc2V0IGlzIHB1bGxlZCBmcm9tIGEgZGF0YSBzZXQgdGhhdCBmb2N1c2VzIG9uIGdhbWVzIHRoYXQgYXJlIGFjdHVhbGx5IHBsYXllZC4gV2hlbiBsb29raW5nIGF0IHRoZSBncmFwaHMgd2UgY2FuIHNlZSB0aGF0IHRoZSB0b3RhbCBnYW1lcyBvbiB0aGUgbGlicmFyeSBoYXZlIGluY3JlYXNpbmcgb3ZlciB0aGUgeWVhcnMuIEhvd2V2ZXIsIHdlIGNhbiBhbHNvIHNlZSBpbiB0aGUgbGluZSBncmFwaCB0aGF0IHRoZXJlIGhhcyBiZWVuIGxlc3MgZ2FtZXMgYmVpbmcgcHVibGlzaGVkIHRvIFN0ZWFtIHNpbmNlIDIwMTYuDQoNCiMgRGF0YSBBbmFseXNpcyANCg0KIyMgKipRdWVzdGlvbiAxOiBXaGF0IGdhbWUgaGFkIHRoZSBiZXN0IGF2ZyBwbGF5ZXJzIHBlcmZvcm1hbmNlIG9uIFN0ZWFtPyoqDQoNCmBgYHtyfQ0KZ2FtZXMgJT4lIA0KICBmaWx0ZXIoYXZnID09IG1heChhdmcpKQ0KYGBgDQo+IFBMQVlFUlVOS05PV04nUyBCQVRUTEVHUk9VTkRTIGlzIHRoZSBnYW1lIHdpdGggdGhlIGJlc3QgYXZnIHBsYXllciBwZXJmb3JtYW5jZS4NCg0KIyMgKipRdWVzdGlvbiAyOiBXaGF0IGdhbWUgaGFkIHRoZSBtb3N0IHBlYWsgcGxheWVycyBpbiBTdGVhbSBoaXN0b3J5PyoqDQoNCmBgYHtyfQ0KZ2FtZXMgJT4lIA0KICBmaWx0ZXIocGVhayA9PSBtYXgocGVhaykpDQpgYGANCj4gVGhlIGdhbWUgd2l0aCB0aGUgaGlnaGVzdCBwZWFrIHBsYXllcnMgaW4gU3RlYW0gaGlzdG9yeSBpcyBQTEFZRVJVTktOT1dOJ1MgQkFUVExFR1JPVU5EUyB3aXRoIDMsMjM2LDAyNyBwbGF5ZXJzLg0KDQojIyAqKlF1ZXN0aW9uIDM6IFdoaWNoIGdhbWUgaGFkIHRoZSBoaWdoZXN0IGdhaW4gaW4gcGxheWVycyBmcm9tIHRoZSBwcmV2aW91cyBtb250aD8qKg0KDQpgYGB7cn0NCmdhbWVzICU+JSANCiAgZHJvcF9uYShnYWluKSAlPiUgDQogIGZpbHRlcihnYWluID09IG1heChnYWluKSkNCiAgDQpgYGANCj4gUExBWUVSVU5LTk9XTidTIEJBVFRMRUdST1VORFMgaGFzIGhhZCB0aGUgZ3JlYXRlc3QgZ2FpbiBmcm9tIHRoZSBwcmlvciBtb250aCBpbiBhbGwgb2Ygc3RlYW0gaGlzdG9yeS4NCg0KIyMgKipRdWVzdGlvbiA0OiBXaGljaCBnYW1lIGhhcyBoYWQgdGhlIGJpZ2dlc3QgbG9zcyBvZiBwbGF5ZXJzIGZyb20gb25lIG1vbnRoIHRvIHRoZSBuZXh0IGluIFN0ZWFtIGhpc3Rvcnk/KioNCg0KYGBge3J9DQpnYW1lcyAlPiUgDQogIGRyb3BfbmEoZ2FpbikgJT4lDQogIGZpbHRlcihnYWluID09IG1pbihnYWluKSkNCmBgYA0KPiBJdCBtYWtlcyBzZW5zZSB0aGF0IEN5YmVycHVuayAyMDc3IGhhZCB0aGUgYmlnZ2VzdCBsb3NzIG9mIHBsYXllcnMgZnJvbSBvbmUgbW9udGggdG8gdGhlIG5leHQgYmVjYXVzZSB0aGUgZ2FtZSB3YXMgZmlsbGVkIHdpdGggYnVncyB0aGF0IG1hZGUgdGhlIGdhbWUgaGFkIHRvIGVuam95IHNvIG1hbnkgcG9lcGxlIHJldHVybmVkIHRoZSBnYW1lLg0KDQojICoqQ29uY2x1c2lvbioqDQoNCldpdGggYWxsIHRoZSBleHBsb3JhdG9yeSBkYXRhIGFuYWx5c2lzIGNvbXBsZXRlLCBsZXRzIHJ1biBkb3duIHdoYXQgd2UgaGF2ZSBsZWFybmVkLiBXZSBmb3VuZCB0aGF0IHNpbmdsZSBwbGF5ZXIgZ2FtZXMgZGlmZmVyIHdoZW4gaXQgY29tZXMgdG8gYXZlcmFnZSBwbGF5ZXJzIG92ZXIgeWVhcnMgd2hlbiBjb21wYXJlZCB0byBtdWx0aXBsYXllciBnYW1lcy4gTXVsdGlwbGF5ZXIgZ2FtZXMgdGVuZCB0byBoYXZlIGFuIGluY3JlYXNlIGZyb20gbGF1bmNoIGFuZCBlaXRoZXIgc3RheSBjb25zaXN0ZW50IGluIHJpc2luZyBmb3IgZWFjaCB5ZWFyIG9yIGRlY3JlYXNpbmcgKEVYLiBEb3RhIDIgJiBQbGF5ZXJ1bmtub3ducyBCYXR0bGVncm91bmRzIHJlc3BlY3RpdmVseSkuIFdoaWxlIHNpbmdsZSBwbGF5ZXIgZ2FtZXMgaGF2ZSBhIGFsbCB0aW1lIGhpZ2ggYXZnIHBsYXllcnMgb24gbGF1bmNoIGFuZCB0aGVuIGRyb3BzIGRvd24gYW5kIHN0YXlzIGNvbnNpc3RlbnQuIFRoaXMgbWFrZXMgYSBsb3Qgb2Ygc2Vuc2Ugd2hlbiBsb29raW5nIGF0IEdUQSA1IGJlY2F1c2UgdGhlIGdhbWUgaXMgYSBtaXggb2Ygc2luZ2xlIGFuZCBtdWx0aXBsYXllciwgc28gaXQgZGVjbGluZXMgb24gdGhlIGZpcnN0IHllYXIgYnV0IG9uY2UgcGVvcGxlIGZpbmlzaGVkIHRoZSBzaW5nbGUgcGxheWVyIHRoZSBtdWx0aXBsYXllciB2ZXJzaW9uIG9mIHRoZSBnYW1lIGZvbGxvd3MgdGhlIHRyZW5kIG9mIG90aGVyIHB1cmVseSBtdWx0aXBsYXllciB0aXRsZXMuIFdlIGFsc28gbGVhcm5lZCB0aGF0IGxhcmdlIHNwaWtlcyBpbiBhdmcgcGxheWVycyBvZiBhIGdhbWUgdGhhdCBhcmUgbm90IGdyYWR1YWwgbWVhbnMgdGhhdCB0aGVyZSB3YXMgbW9zdCBsaWtlbHkgYSBnYW1lIGdpdmUgYXdheSBhdCBzb21lIHBvaW50LiBBbiBleGFtcGxlIG9mIHRoaXMgaXMgUGF5ZGF5IDIgYW5kIENTR08gd2hlcmUgdGhleSBqdXN0IGp1bXAgZnJvbSBvbmUgbW9udGggdG8gdGhlIG5leHQuIFdoZW4gYWdncmVnYXRpbmcgYWxsIGdhbWVzIG9uIFN0ZWFtIHdlIGxlYXJuZWQgdGhhdCB0aGVyZSBpcyBhIHNlYXNvbmFsIHRyZW5kIHdoZW4gaXQgY29tZXMgdG8gcGVhayBhbmQgYXZnIHBsYXllcnMuIFdlIGZvdW5kIHRoYXQgZ2FtZXJzIHRlbmQgdG8gcGxheSBtb3JlIHdoZW4gdGhlcmUgaXMgaG9saWRheXMsIG9yIHN1bW1lciBicmVhay4gV2hlbiBsb29raW5nIGF0IHRvdGFsIG51bWJlciBvZiBwbGF5ZXJzIGluIGVhY2ggeWVhciBiYXNlZCBvbiBwZWFrIGFuZCBhdmVyYWdlIHBsYXllcnMgd2Ugc2VlIGEgbGluZWFyIGluY3JlYXNlIGluIHBsYXllcnMgb3ZlciB0aGUgeWVhcnMuIFRoaXMgbWVhbnMgdGhhdCBTdGVhbSBpcyBncm93aW5nIGl0cyBjdXN0b21lciBiYXNlIG92ZXIgdGltZSwgYWx0aG91Z2ggdGhlcmUgd2FzIGEgc2xpZ2h0IGRlY3JlYXNlIGluIDIwMTkgd2hlbiBwb3B1bGFyIHRpdGxlIEZvcnRuaXRlIHdhcyBiZWluZyBwbGF5ZWQgb24gYW5vdGhlciBwbGF0Zm9ybSBFUElDIEdhbWVzLiBTbywgd2UgYmVsaWV2ZSB0aGF0IEZvcnRuaXRlIHRvIGJlIHRoZSB1bHRpbWF0ZSBjYXVzZSwgaG93ZXZlciBhZnRlciBGb3J0bml0ZSBsb3N0IHRyYWN0aW9uIFN0ZWFtJ3Mgb3ZlcmFsbCBwbGF5ZXJzIGluY3JlYXNlZCBwYXNzZWQgMjAxOC4gV2UgYWxzbyBmb3VuZCB0aGF0IHRoZSByZWxldmFudCB0b3RhbCBudW1iZXIgb2YgZ2FtZXMgcmVsZWFzZWQgb24gc3RlYW0gaGFzIGluY3JlYXNlZCBvdmVyIHRpbWUuIEhvd2V2ZXIsIHRoZSBhbW91bnQgb2YgcmVsZXZhbnQgZ2FtZXMgcHVibGlzaGVkIGZyb20gMjAxNi1wcmVzZW50IGhhcyBiZWVuIGxvd2VyIHRoYW4gb3RoZXIgeWVhcnMuIEZpbmFsbHksIHdlIGZvdW5kIHRoZSBiZXN0IGdhbWUgb24gU3RlYW0gd2hpY2ggd2FzIFBsYXllcnVua25vd25zIEJhdHRsZWdyb3VuZHMgd2l0aCB0aGUgYmVzdCBhdmcsIHBlYWssIGFuZCBnYWluIGluIGFsbCBvZiBTdGVhbSBoaXN0b3J5LiBXZSBmb3VuZCB0aGUgd29yc3QgZ2FtZSBpbiB0ZXJtcyBvZiBwbGF5ZXJzIGxvc3Qgd2l0aCB0aGUgbG93ZXN0IGdhaW4gaW4gU3RlYW0gaGlzdG9yeSB3aGljaCB3YXMgQ3liZXJwdW5rIDIwNzcgd2hpY2ggbG9zdCAyNTAyNDkgcGxheWVycyBmcm9tIG9uZSBtb250aCB0byB0aGUgbmV4dC4NCg0KDQojICoqRnV0dXJlIHdvcmtzKioNCg0KVGhlcmUgaXMgc3RpbGwgYSBsb3QgdG8gYmUgZm91bmQgYW5kIGV4cGxvcmVkIHdpdGggdGhpcyBkYXRhc2V0LiBGb3Igb25lIHRoZSBkYXRhIHRoYXQgd2UgZGlkIGFuYWx5emUgZm9yIHNpbmdsZSBwbGF5ZXIgYW5kIG11bHRpcGxheWVyIGdhbWVzIHdhcyBqdXN0IGEgaGFuZGZ1bCBvZiBnYW1lcywgc28gd2Ugd291bGQgcnVuIG1vcmUgYW5hbHlzaXMgZm9yIHRob3NlIHR5cGVzLiBBbm90aGVyIHRoaW5nIHRoYXQgd291bGQgaW1wcm92ZSB0aGUgYW5hbHlzaXMgb2YgdGhpcyBkYXRhIHNldCB3b3VsZCBiZSB0byBtdXRhdGUgYSBjb2x1bW4gdGhhdCBzcGVjaWZpZXMgd2hhdCB0eXBlIG9mIGdhbWUgdGhhdCBpdCBpcyB3aGV0aGVyIGl0IGJlIG11bHRpcGxheWVyLCBzaW5nbGUgcGxheWVyLCBvciBib3RoLiBBbm90aGVyIGdvb2QgbXV0YXRlIHdvdWxkIGJlIHdoYXQgZ2VucmUgdGhlIGdhbWUgaXMgaW4sIGFuZCBwcmljZSBvZiB0aGUgZ2FtZS4gVGhlc2UgbXV0YXRlcyB3b3VsZCBlbmFibGUgdXMgdG8gbWFrZSBzZW5zZSBvZiBob3cgZ2FtZXJzIGJlaGF2ZSB3aGVuIHRoZXJlIGlzIGEgY2VydGFpbiBwcmljZSBmb3IgY2VydGFpbiB0aXRsZXMuIFdlIGRvIGtub3cgdGhhdCB3aGVuIGdhbWVzIGFyZSBzdWRkZW5seSBnaXZlbiBvdXQgZm9yIGZyZWUgYXZnIHBsYXllcnMgaW5jcmVhc2UsIGJ1dCBhdCB0aGUgbW9tZW50IHdlIGNhbnQgY29tcGFyZSB0d28gc2hvb3RlciBtdWx0aXBsYXllciBnYW1lcyBhdCBkaWZmZXJlbnQgcHJpY2VzIHdpdGhvdXQgZG9pbmcgcmVzZWFyY2guIEl0IHdvdWxkIGFsc28gYmUgdXNlZnVsIGZvciB0aGUgZnV0dXJlIHRvIGRldGVybWluZSBob3cgU3RlYW0gQ2hhcnRzIGRlY2lkZXMgd2hpY2ggZ2FtZXMgYXJlIHJlbGV2YW50IGVub3VnaCB0byByZWNvcmQuIFdoZW4gbG9va2luZyBhdCB0aGUgYWN0dWFsIFN0ZWFtIHBsYXRmb3JtIHRoZXJlIGlzIG1vcmUgdGhhbiAxMjAwIGdhbWVzLiBDdXJyZW50bHksIHdlIGFyZSBqdXN0IGFzc3VtaW5nIHRoYXQgdGhlc2UgdGl0bGVzIGhhdmUgZW5vdWdoIHBsYXllcnMgdG8gYmUgY29uc2lkZXJlZCB3b3J0aCB3aGlsZSBrZWVwaW5nIHRyYWNrIG9mLg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQo=