Midterm
Define Your Research Question (10 points)
Define your research question below. What about the data interests you? What is a specific question you want to find out about the data?
I found this BoardGames dataset on the TidyTuesday github page, and I thought it looked really interesting because I love playing board games but I had no idea there were so many of them! I was interested to learn more about what made a board game popular, when there were so many that I had never heard of. Therefore, I came up with the following research question: How does minimum length of play affect average rating of board game on Board Game Geek? How does this change if you stratify by minimum age of player? I was interested in whether people prefer longer or shorter games, and if this changes based on the age group that is the target audience of the game.
Given your question, what is your expectation about the data?
I would expect that overall, longer minimum playtime would lead to lower ratings because aside from committed board game enthusiasts, the casual player might either not want to try the game, or might get bored of it before they can learn to enjoy it. I would think that this effect might be more pronounced among games with a lower minimum player age, due to the typically lower attention span of children and tweens. Games aimed at an older teenage or adult audience might see less of an effect of minimum playtime on rating since those players might be more willing to devote longer to the process, and also may be more likely to already be enthusiastic board-game fans and therefore more used to playing for longer periods or in a social setting.
Loading the Data (10 points)
Load the data below and use dplyr::glimpse()
or skimr::skim()
on the data. You should upload the data file into the data
directory.
I got this data from the TidyTuesday github page, and the folder containing the data can be accessed using the following link: https://github.com/rfordatascience/tidytuesday/tree/master/data/2019/2019-03-12
First I will load the BoardGames dataset:
BoardGames <- read.csv("board_games.csv")
head(BoardGames)
Then I will check to make sure that the average_rating, min_playtime, and min_age columns are all encoded as numbers and not characters, so that I can do my analysis properly.
glimpse(BoardGames)
## Rows: 10,532
## Columns: 22
## $ game_id <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,…
## $ description <chr> "Die Macher is a game about seven sequential political…
## $ image <chr> "//cf.geekdo-images.com/images/pic159509.jpg", "//cf.g…
## $ max_players <int> 5, 4, 4, 4, 6, 6, 2, 5, 4, 6, 7, 5, 4, 4, 6, 4, 2, 8, …
## $ max_playtime <int> 240, 30, 60, 60, 90, 240, 20, 120, 90, 60, 45, 60, 120…
## $ min_age <int> 14, 12, 10, 12, 12, 12, 8, 12, 13, 10, 13, 12, 10, 10,…
## $ min_players <int> 3, 3, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 3, 2, 2, …
## $ min_playtime <int> 240, 30, 30, 60, 90, 240, 20, 120, 90, 60, 45, 45, 60,…
## $ name <chr> "Die Macher", "Dragonmaster", "Samurai", "Tal der Köni…
## $ playing_time <int> 240, 30, 60, 60, 90, 240, 20, 120, 90, 60, 45, 60, 120…
## $ thumbnail <chr> "//cf.geekdo-images.com/images/pic159509_t.jpg", "//cf…
## $ year_published <int> 1986, 1981, 1998, 1992, 1964, 1989, 1978, 1993, 1998, …
## $ artist <chr> "Marcus Gschwendtner", "Bob Pepper", "Franz Vohwinkel"…
## $ category <chr> "Economic,Negotiation,Political", "Card Game,Fantasy",…
## $ compilation <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, "CATAN…
## $ designer <chr> "Karl-Heinz Schmiel", "G. W. \"Jerry\" D'Arcey", "Rein…
## $ expansion <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, "Elfengold,Elfenla…
## $ family <chr> "Country: Germany,Valley Games Classic Line", "Animals…
## $ mechanic <chr> "Area Control / Area Influence,Auction/Bidding,Dice Ro…
## $ publisher <chr> "Hans im Glück Verlags-GmbH,Moskito Spiele,Valley Game…
## $ average_rating <dbl> 7.66508, 6.60815, 7.44119, 6.60675, 7.35830, 6.52534, …
## $ users_rated <int> 4498, 478, 12019, 314, 15195, 73, 2751, 186, 1263, 672…
Lastly, I’ll check for NA values in my columns of interest (again, average_rating, min_playtime, and min_age):
#I just found this code/refreshed my memory using the help function in RStudio
anyNA(BoardGames$min_age)
## [1] FALSE
anyNA(BoardGames$min_playtime)
## [1] FALSE
anyNA(BoardGames$average_rating)
## [1] FALSE
There are no missing values encoded as NA for my three columns of interest.
If there are any quirks that you have to deal with NA
coded as something else, or it is multiple tables, please make some notes here about what you need to do before you start transforming the data in the next section.
Note: I thought I did not have NA values, but once I started exploring the data further, it turned out that there was minimum age data encoded as zero, and minimum playtime data encoded as zero. It was unsure if this meant that there really was no minimum age/playtime or just that the data was missing. I chose to create a separate category for these values when I categorized both of those variables. I looked at them briefly in my tables, and excluded them from my graphs, using the category I had created.
Make sure your data types are correct!
Done! See above.
Transforming the data (15 points)
If the data needs to be transformed in any way (values recoded, pivoted, etc), do it here. Examples include transforming a continuous variable into a categorical using case_when()
, etc.
The three main things I’d like to do to my dataframe to make it more useful for this project are:
Move the columns I will be using the the beginning of the table, because the 2nd column containing the description of the board-game is very long and makes the table unwieldy to look at quickly using functions like head, and doesn’t show up well in the final html file.
Divide minimum playtime into groups, to ease analysis; this will involve making a new categorical variable for minimum playtime.
Divide minimum age into categories for my analysis; I’ll need to look at the range and distribution of ages first, and then choose appropriate category breaks and add a new column with the re-coded categorical variable. This will allow me to subset for the next question.
Subset of the data and think of a question to answer the subset
I will be sub-setting the data into age groups in order to look not only the correlation between minimum playtime and average rating overall, but also in each of the separate age groups.
Bonus points (5 points) for datasets that require merging of tables, but only if you reason through whether you should use left_join
, inner_join
, or right_join
on these tables. No credit will be provided if you don’t.
I don’t anticipate needing to merge tables for this project, as the BoardGames dataset came in a complete form.
#First, I am rearranging the columns in the table. This code came from Dr. Minnier and Dr. Niederhausen's "An Introduction to R and RStudio for Exploratory Data Analysis" Part 2 slides. https://jminnier-berd-r-courses.netlify.app/01-intro-r-eda/01_intro_r_eda_part2#1
BoardGames_V1 <- BoardGames %>%
relocate(min_age)
BoardGames_V1 <- BoardGames_V1 %>%
relocate(min_playtime, .before = game_id)
BoardGames_V1 <- BoardGames_V1 %>%
relocate(average_rating, .before = game_id)
head(BoardGames_V1)
#Now that my columns are in a good order, I want to look at my minimum playtime data, and see what the distribution is so that I can find good cut points for my categorization. First I used the count function to see the distribution of observations for each playtime.
BoardGames_V1 %>%
count(min_playtime)
#Then I made a boxplot of the minimum play times to visualize the distribution
boxplot(BoardGames_V1$min_playtime, horizontal = T, xlab = "Minimum Playtime (Min)", main = "Boxplot of Min Playtime Distribution")
As we can see, there are a few extreme outliers; which is making it hard to visualize the data; I’m going to remove those points temporarily.
# I'm filtering out the highest 3 observations which were much higher than any of the other min play-times
BoardGames_V1.1 <- BoardGames_V1 %>%
filter(min_playtime <= 6000)
boxplot(BoardGames_V1.1$min_playtime, horizontal = T, xlab = "Minimum Playtime (Min)", main = "Boxplot of Min Playtime Distribution w/ Out Most Extreme Outliers")
As we can see, this graph still isn’t great, with most of the data cramped at the low end and a few high values, however, at this point I’m still going to try to divide up the data into categories:
# Here I am using case_when to create categories for the minimum playtime for each game, with +10-30 meaning more than 10, up to 30 minutes, etc.
BoardGames_V2 <- BoardGames_V1 %>%
mutate(min_play_categories = case_when(
min_playtime == 0 ~ "0:No Min Playtime",
min_playtime > 0 & min_playtime <= 10 ~ "1:10 min or less",
min_playtime > 10 & min_playtime <= 30 ~ "2:+10-30 min",
min_playtime > 30 & min_playtime <= 60 ~ "3:+30-60 min",
min_playtime > 60 & min_playtime <= 180 ~ "4:+1-3 hrs",
min_playtime > 180 & min_playtime <= 720 ~ "5:+3-12 hrs",
min_playtime > 720 ~ "6:More than 12 hrs"
)
)
BoardGames_V2 <- BoardGames_V2 %>%
relocate(min_play_categories, .after = min_playtime)
head(BoardGames_V2)
#Similar to above, I want to look at my age data, and see what the distribution is so that I can find good cut points for my categorization. First I used the count function to see the distribution of observations for each age.
BoardGames_V2 %>%
count(min_age)
#Then I made a rough histogram to visualize the distribution
hist(BoardGames_V2$min_age, xlab = "Minimum Age (yrs)", ylab = "Frequency", main = "Histogram of Min Age Distribution")
Based on the information from my exploratory analysis of the minimum age distribution, and my own knowledge of children, I have chosen to cut the age distribution into the following categories: No Min Age, Young Child (1-6 yrs), Older Child (7-12 yrs), Teen (13-17 yrs), and Adult (18+ yrs)
# Here I am using case_when to create categories for the minimum age of player for each game
BoardGames_V3 <- BoardGames_V2 %>%
mutate(min_age_categories = case_when(
min_age == 0 ~ "0:No Min Age",
min_age > 0 & min_age <= 6 ~ "1:Young Child (0-6 yrs)",
min_age > 6 & min_age <= 12 ~ "2:Older Child (7-12 yrs)",
min_age > 12 & min_age <= 17 ~ "3:Teen (13-17 yrs)",
min_age > 17 ~ "4:Adult (18+ yrs)"
)
)
BoardGames_V3 <- BoardGames_V3 %>%
relocate(min_age_categories, .after = min_age)
Show your transformed table here. Use tools such as glimpse()
, skim()
or head()
to illustrate your point.
Now, we can see that our rearrangement and re-categorization worked:
head(BoardGames_V3)
I can also make separate tables for each of the different age groups, if needed for subsetting analysis later:
#Again, this code came from Dr. Minnier and Dr. Niederhausen's "An Introduction to R and RStudio for Exploratory Data Analysis" Part 2 slides. https://jminnier-berd-r-courses.netlify.app/01-intro-r-eda/01_intro_r_eda_part2#1, as mentioned above for the relocation data
NoMinAge_Games <- BoardGames_V3 %>%
filter(min_age_categories == "0:No Min Age")
head(NoMinAge_Games)
YoungChild_BoardGames <- BoardGames_V3 %>%
filter(min_age_categories == "1:Young Child (0-6 yrs)")
head(YoungChild_BoardGames)
OlderChild_BoardGames <- BoardGames_V3 %>%
filter(min_age_categories == "2:Older Child (7-12 yrs)")
head(OlderChild_BoardGames)
Teen_BoardGames <- BoardGames_V3 %>%
filter(min_age_categories == "3:Teen (13-17 yrs)")
head(Teen_BoardGames)
Adult_BoardGames <- BoardGames_V3 %>%
filter(min_age_categories == "4:Adult (18+ yrs)")
head(Adult_BoardGames)
Are the values what you expected for the variables? Why or Why not?
I was surprised that there were so many minimum playtime and minimum age values of zero; I honestly wasn’t sure if this was the equivalent of a “NA,” or if it was the game-designer’s indication that there was not a minimum playtime or not a minimum age limit. It order to account for this, I made a separate category for these games, so that I could choose whether or not to use them in my final analysis. Otherwise, I was not terribly surprised by anything so far.
Visualizing and Summarizing the Data (15 points)
Use group_by()/summarize()
to make a summary of the data here. The summary should be relevant to your research question
First I will be addressing my primary research question, which was: how does the minimum playtime affect the average rating in the overall dataset?
Main Question
#This summary is the average rating, grouped by minimum playtime
BoardGames_V3 %>%
group_by(min_play_categories) %>%
summarise(Number_Games = n(), Mean_Rating = mean(average_rating), Median_Rating = median(average_rating), Min_Rating = min(average_rating), Max_Rating = max(average_rating))
## `summarise()` ungrouping output (override with `.groups` argument)
Next I’ll look into my secondary question, which is: how does the min playtime affect mean rating when we stratify by age group?
No Min Age
#No Min Age (possibly just NA category)
NoMinAge_Games %>%
group_by(min_play_categories) %>%
summarise(Number_Games = n(), Mean_Rating = mean(average_rating), Median_Rating = median(average_rating), Min_Rating = min(average_rating), Max_Rating = max(average_rating))
## `summarise()` ungrouping output (override with `.groups` argument)
Young Children
#Young Children
YoungChild_BoardGames %>%
group_by(min_play_categories) %>%
summarise(Number_Games = n(), Mean_Rating = mean(average_rating), Median_Rating = median(average_rating), Min_Rating = min(average_rating), Max_Rating = max(average_rating))
## `summarise()` ungrouping output (override with `.groups` argument)
Older Children
#Older Children
OlderChild_BoardGames %>%
group_by(min_play_categories) %>%
summarise(Number_Games = n(), Mean_Rating = mean(average_rating), Median_Rating = median(average_rating), Min_Rating = min(average_rating), Max_Rating = max(average_rating))
## `summarise()` ungrouping output (override with `.groups` argument)
Teens
#Teens
Teen_BoardGames %>%
group_by(min_play_categories) %>%
summarise(Number_Games = n(), Mean_Rating = mean(average_rating), Median_Rating = median(average_rating), Min_Rating = min(average_rating), Max_Rating = max(average_rating))
## `summarise()` ungrouping output (override with `.groups` argument)
Adults
#Adults
Adult_BoardGames %>%
group_by(min_play_categories) %>%
summarise(Number_Games = n(), Mean_Rating = mean(average_rating), Median_Rating = median(average_rating), Min_Rating = min(average_rating), Max_Rating = max(average_rating))
## `summarise()` ungrouping output (override with `.groups` argument)
What are your findings about the summary? Are they what you expected?
Initially looking at the data, I was surprised, because (especially if we ignore the No Min Playtime category, which I think is reasonable since we are not sure if that is really just the NA category or not), we can see that mean rating and median rating both go up with each Minimum Playtime category; it seems from this summary data that the players actually prefer longer playtime!
But what about if we subset by age group?
The pattern is less consistent when we break the data down into age groups. No Min Age this group is of unknown usefulness, since we don’t know if it is just a stand-in for NA. In this table, we see that the longer games are highest rated, but there is not a consistent pattern with the ratings. Young Children seem to enjoy +10-30 min games the most, but ratings were fairly consistent across playtime categories. There were no games for young children with playtimes longer than 3 hours. Older Children and Teens both seemed to follow the overall pattern of preferring longer games, with mean(average_rating) rising steadily as playtimes rose. Adults seem from the data to enjoy +1-3 hr games the most, but there were much fewer games aimed for a minimum age of Adults 18+, an only one adult game longer than 3 hours, so it is harder to trust the pattern in this data as much as for some of the other groups.
Make at least two plots that help you answer your question on the transformed or summarized data.
Plot of Minimum Playtime vs Average Game Rating
# First I created a new dataframe with all the No Min Age and No Min Playtime, since we aren't sure if those are useful or just differently coded NA values.
BoardGames_V4 <- BoardGames_V3 %>%
filter(min_play_categories != "0:No Min Playtime")
BoardGames_V4 <- BoardGames_V4 %>%
filter(min_age_categories != "0:No Min Age")
#First I want to make a plot addressing the main research question, the relationship between minimum playtime and average rating. Again, I made use of Dr. Minnier and Dr. Niederhausen's slides from their "An Introduction to R and RStudio for Exploratory Data Analysis" pt 2 presentation, and also the "Data Visualization with ggplot2 : : CHEAT SHEET" available through the help function in RStudio. I also used the Part 4 lecture from this course to help with my code.
ggplot(data = BoardGames_V4,
aes(x = min_playtime, y = average_rating, color = average_rating)) +
geom_point() +
geom_smooth(method = lm) +
scale_x_log10() +
labs(title = "Minimum Playtime vs Average Game Rating", x = "Log(10) of Minimum Playtime", y = "Average Rating")
## `geom_smooth()` using formula 'y ~ x'
I used a log scale for the x-axis to fit all the data in without having to remove outliers, and graphically added a linear model to visualize the data trend.
Boxplots of Minimum Playtime vs Average Game Rating by Age Group Next, I wanted to look at my age-category subsets:
# For this boxplot, I used the Part 3 lecture and Part 3 assignment for assistance with the code, as well as the "Data Visualization with ggplot2 : : CHEAT SHEET" available through the help function in RStudio
ggplot(BoardGames_V4) +
aes(x = min_play_categories,
y = average_rating,
fill = min_play_categories) +
geom_boxplot() +
facet_grid(rows = vars(min_age_categories)) +
labs(title ="Boxplot of Min Playtime and Avg Rating by Age Group", x = "Min Playtime", y = "Avg Rating") +
scale_fill_discrete(name = "Min Playtime")
Final Summary (10 points)
Summarize your research question and findings below.
My original questions were how does minimum length of play affect average rating of board game on Board Game Geek? How does this change if you stratify by minimum age of player? What I found was that overall, the longer the minimum length of play, the higher the mean of the average rating on Board Game Geek (when excluding the games with no listed minimum playtime due to not knowing if those were the equivilent of NA values). However, when I broke the data down by age group, I found that while this trend held true for Older Children and Teens, it did not as much for Young Children and Adults. For adults the preferred length of gameplay was more than 1 and up to 3 hours, and for young children the preferred length of gameplay was more than 10 and up to 30 minutes. However, it is important to mention that there were very few observations in the adult group, and by far the most observations in the older child and teen groups, so that could certainly be part of the reason why the overall trend followed the pattern of those two groups.
Are your findings what you expected? Why or Why not?
My findings for the overall data were not what I expected; I had expected people to prefer shorter games but the overall trend showed the opposite, the longer the game, the higher the average rating. However, I had also hypothesized that young children’s shorter attention spans would cause them to prefer shorter games, and this did hold pretty true; the games that were less than 10 minutes, or 10-30 minutes both had higher ratings than longer games in the Young Child category. I had hypothesized that attention span would keep going up as players got older, and generally for the older children and teens, longer games were preferred. There was little data for the adult minimum age group, and since there was only one game longer than +1-3 hrs, it is hard to conclude whether adults dislike very long games; for adults the preferred game length was +1-3 hrs.
LS0tCnRpdGxlOiAiTWlkdGVybSBQcm9qZWN0IgphdXRob3I6ICJOYXRoYWxpZSBHYXJpbWVsbGEiCmRhdGU6ICIyLzEwLzIwMjEiCm91dHB1dDogCiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdGhlbWU6IGNlcnVsZWFuCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoamFuaXRvcikKbGlicmFyeShza2ltcikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGJyb29tKQpsaWJyYXJ5KGdndGhlbWVzKQpsaWJyYXJ5KHdlc2FuZGVyc29uKQpgYGAKCgojIE1pZHRlcm0gCgojIyBEZWZpbmUgWW91ciBSZXNlYXJjaCBRdWVzdGlvbiAoMTAgcG9pbnRzKQoKPiAqRGVmaW5lIHlvdXIgcmVzZWFyY2ggcXVlc3Rpb24gYmVsb3cuIFdoYXQgYWJvdXQgdGhlIGRhdGEgaW50ZXJlc3RzIHlvdT8gV2hhdCBpcyBhIHNwZWNpZmljIHF1ZXN0aW9uIHlvdSB3YW50IHRvIGZpbmQgb3V0IGFib3V0IHRoZSBkYXRhPyoKCkkgZm91bmQgdGhpcyBCb2FyZEdhbWVzIGRhdGFzZXQgb24gdGhlIFRpZHlUdWVzZGF5IGdpdGh1YiBwYWdlLCBhbmQgSSB0aG91Z2h0IGl0IGxvb2tlZCByZWFsbHkgaW50ZXJlc3RpbmcgYmVjYXVzZSBJIGxvdmUgcGxheWluZyBib2FyZCBnYW1lcyBidXQgSSBoYWQgbm8gaWRlYSB0aGVyZSB3ZXJlIHNvIG1hbnkgb2YgdGhlbSEgSSB3YXMgaW50ZXJlc3RlZCB0byBsZWFybiBtb3JlIGFib3V0IHdoYXQgbWFkZSBhIGJvYXJkIGdhbWUgcG9wdWxhciwgd2hlbiB0aGVyZSB3ZXJlIHNvIG1hbnkgdGhhdCBJIGhhZCBuZXZlciBoZWFyZCBvZi4gVGhlcmVmb3JlLCBJIGNhbWUgdXAgd2l0aCB0aGUgZm9sbG93aW5nIHJlc2VhcmNoIHF1ZXN0aW9uOgpIb3cgZG9lcyBtaW5pbXVtIGxlbmd0aCBvZiBwbGF5IGFmZmVjdCBhdmVyYWdlIHJhdGluZyBvZiBib2FyZCBnYW1lIG9uIEJvYXJkIEdhbWUgR2Vlaz8gSG93IGRvZXMgdGhpcyBjaGFuZ2UgaWYgeW91IHN0cmF0aWZ5IGJ5IG1pbmltdW0gYWdlIG9mIHBsYXllcj8KSSB3YXMgaW50ZXJlc3RlZCBpbiB3aGV0aGVyIHBlb3BsZSBwcmVmZXIgbG9uZ2VyIG9yIHNob3J0ZXIgZ2FtZXMsIGFuZCBpZiB0aGlzIGNoYW5nZXMgYmFzZWQgb24gdGhlIGFnZSBncm91cCB0aGF0IGlzIHRoZSB0YXJnZXQgYXVkaWVuY2Ugb2YgdGhlIGdhbWUuIAoKPiAqR2l2ZW4geW91ciBxdWVzdGlvbiwgd2hhdCBpcyB5b3VyIGV4cGVjdGF0aW9uIGFib3V0IHRoZSBkYXRhPyoKCkkgd291bGQgZXhwZWN0IHRoYXQgb3ZlcmFsbCwgbG9uZ2VyIG1pbmltdW0gcGxheXRpbWUgd291bGQgbGVhZCB0byBsb3dlciByYXRpbmdzIGJlY2F1c2UgYXNpZGUgZnJvbSBjb21taXR0ZWQgYm9hcmQgZ2FtZSBlbnRodXNpYXN0cywgdGhlIGNhc3VhbCBwbGF5ZXIgbWlnaHQgZWl0aGVyIG5vdCB3YW50IHRvIHRyeSB0aGUgZ2FtZSwgb3IgbWlnaHQgZ2V0IGJvcmVkIG9mIGl0IGJlZm9yZSB0aGV5IGNhbiBsZWFybiB0byBlbmpveSBpdC4gSSB3b3VsZCB0aGluayB0aGF0IHRoaXMgZWZmZWN0IG1pZ2h0IGJlIG1vcmUgcHJvbm91bmNlZCBhbW9uZyBnYW1lcyB3aXRoIGEgbG93ZXIgbWluaW11bSBwbGF5ZXIgYWdlLCBkdWUgdG8gdGhlIHR5cGljYWxseSBsb3dlciBhdHRlbnRpb24gc3BhbiBvZiBjaGlsZHJlbiBhbmQgdHdlZW5zLiBHYW1lcyBhaW1lZCBhdCBhbiBvbGRlciB0ZWVuYWdlIG9yIGFkdWx0IGF1ZGllbmNlIG1pZ2h0IHNlZSBsZXNzIG9mIGFuIGVmZmVjdCBvZiBtaW5pbXVtIHBsYXl0aW1lIG9uIHJhdGluZyBzaW5jZSB0aG9zZSBwbGF5ZXJzIG1pZ2h0IGJlIG1vcmUgd2lsbGluZyB0byBkZXZvdGUgbG9uZ2VyIHRvIHRoZSBwcm9jZXNzLCBhbmQgYWxzbyBtYXkgYmUgbW9yZSBsaWtlbHkgdG8gYWxyZWFkeSBiZSBlbnRodXNpYXN0aWMgYm9hcmQtZ2FtZSBmYW5zIGFuZCB0aGVyZWZvcmUgbW9yZSB1c2VkIHRvIHBsYXlpbmcgZm9yIGxvbmdlciBwZXJpb2RzIG9yIGluIGEgc29jaWFsIHNldHRpbmcuCgoKCiMjIExvYWRpbmcgdGhlIERhdGEgKDEwIHBvaW50cykKCj4gKkxvYWQgdGhlIGRhdGEgYmVsb3cgYW5kIHVzZSBgZHBseXI6OmdsaW1wc2UoKWAgb3IgYHNraW1yOjpza2ltKClgIG9uIHRoZSBkYXRhLiBZb3Ugc2hvdWxkIHVwbG9hZCB0aGUgZGF0YSBmaWxlIGludG8gdGhlIGBkYXRhYCBkaXJlY3RvcnkuKiAKCkkgZ290IHRoaXMgZGF0YSBmcm9tIHRoZSBUaWR5VHVlc2RheSBnaXRodWIgcGFnZSwgYW5kIHRoZSBmb2xkZXIgY29udGFpbmluZyB0aGUgZGF0YSBjYW4gYmUgYWNjZXNzZWQgdXNpbmcgdGhlIGZvbGxvd2luZyBsaW5rOgpodHRwczovL2dpdGh1Yi5jb20vcmZvcmRhdGFzY2llbmNlL3RpZHl0dWVzZGF5L3RyZWUvbWFzdGVyL2RhdGEvMjAxOS8yMDE5LTAzLTEyCgpGaXJzdCBJIHdpbGwgbG9hZCB0aGUgQm9hcmRHYW1lcyBkYXRhc2V0OgpgYGB7ciBsb2FkIGRhdGEsIGluY2x1ZGU9VFJVRX0KQm9hcmRHYW1lcyA8LSByZWFkLmNzdigiYm9hcmRfZ2FtZXMuY3N2IikKaGVhZChCb2FyZEdhbWVzKQpgYGAKVGhlbiBJIHdpbGwgY2hlY2sgdG8gbWFrZSBzdXJlIHRoYXQgdGhlIGF2ZXJhZ2VfcmF0aW5nLCBtaW5fcGxheXRpbWUsIGFuZCBtaW5fYWdlIGNvbHVtbnMgYXJlIGFsbCBlbmNvZGVkIGFzIG51bWJlcnMgYW5kIG5vdCBjaGFyYWN0ZXJzLCBzbyB0aGF0IEkgY2FuIGRvIG15IGFuYWx5c2lzIHByb3Blcmx5LiAgCmBgYHtyfQpnbGltcHNlKEJvYXJkR2FtZXMpCmBgYAoKTGFzdGx5LCBJJ2xsIGNoZWNrIGZvciBOQSB2YWx1ZXMgaW4gbXkgY29sdW1ucyBvZiBpbnRlcmVzdCAoYWdhaW4sIGF2ZXJhZ2VfcmF0aW5nLCBtaW5fcGxheXRpbWUsIGFuZCBtaW5fYWdlKToKYGBge3J9CiNJIGp1c3QgZm91bmQgdGhpcyBjb2RlL3JlZnJlc2hlZCBteSBtZW1vcnkgdXNpbmcgdGhlIGhlbHAgZnVuY3Rpb24gaW4gUlN0dWRpbwphbnlOQShCb2FyZEdhbWVzJG1pbl9hZ2UpCmFueU5BKEJvYXJkR2FtZXMkbWluX3BsYXl0aW1lKQphbnlOQShCb2FyZEdhbWVzJGF2ZXJhZ2VfcmF0aW5nKQpgYGAKClRoZXJlIGFyZSBubyBtaXNzaW5nIHZhbHVlcyBlbmNvZGVkIGFzIE5BIGZvciBteSB0aHJlZSBjb2x1bW5zIG9mIGludGVyZXN0LgoKPiAqSWYgdGhlcmUgYXJlIGFueSBxdWlya3MgdGhhdCB5b3UgaGF2ZSB0byBkZWFsIHdpdGggYE5BYCBjb2RlZCBhcyBzb21ldGhpbmcgZWxzZSwgb3IgaXQgaXMgbXVsdGlwbGUgdGFibGVzLCBwbGVhc2UgbWFrZSBzb21lIG5vdGVzIGhlcmUgYWJvdXQgd2hhdCB5b3UgbmVlZCB0byBkbyBiZWZvcmUgeW91IHN0YXJ0IHRyYW5zZm9ybWluZyB0aGUgZGF0YSBpbiB0aGUgbmV4dCBzZWN0aW9uLiogCgpOb3RlOiBJIHRob3VnaHQgSSBkaWQgbm90IGhhdmUgTkEgdmFsdWVzLCBidXQgb25jZSBJIHN0YXJ0ZWQgZXhwbG9yaW5nIHRoZSBkYXRhIGZ1cnRoZXIsIGl0IHR1cm5lZCBvdXQgdGhhdCB0aGVyZSB3YXMgbWluaW11bSBhZ2UgZGF0YSBlbmNvZGVkIGFzIHplcm8sIGFuZCBtaW5pbXVtIHBsYXl0aW1lIGRhdGEgZW5jb2RlZCBhcyB6ZXJvLiBJdCB3YXMgdW5zdXJlIGlmIHRoaXMgbWVhbnQgdGhhdCB0aGVyZSByZWFsbHkgd2FzIG5vIG1pbmltdW0gYWdlL3BsYXl0aW1lIG9yIGp1c3QgdGhhdCB0aGUgZGF0YSB3YXMgbWlzc2luZy4gSSBjaG9zZSB0byBjcmVhdGUgYSBzZXBhcmF0ZSBjYXRlZ29yeSBmb3IgdGhlc2UgdmFsdWVzIHdoZW4gSSBjYXRlZ29yaXplZCBib3RoIG9mIHRob3NlIHZhcmlhYmxlcy4gSSBsb29rZWQgYXQgdGhlbSBicmllZmx5IGluIG15IHRhYmxlcywgYW5kIGV4Y2x1ZGVkIHRoZW0gZnJvbSBteSBncmFwaHMsIHVzaW5nIHRoZSBjYXRlZ29yeSBJIGhhZCBjcmVhdGVkLiAKCgo+ICoqTWFrZSBzdXJlIHlvdXIgZGF0YSB0eXBlcyBhcmUgY29ycmVjdCEqKgoKRG9uZSEgU2VlIGFib3ZlLiAKCiMjIFRyYW5zZm9ybWluZyB0aGUgZGF0YSAoMTUgcG9pbnRzKQoKPiAqSWYgdGhlIGRhdGEgbmVlZHMgdG8gYmUgdHJhbnNmb3JtZWQgaW4gYW55IHdheSAodmFsdWVzIHJlY29kZWQsIHBpdm90ZWQsIGV0YyksIGRvIGl0IGhlcmUuIEV4YW1wbGVzIGluY2x1ZGUgdHJhbnNmb3JtaW5nIGEgY29udGludW91cyB2YXJpYWJsZSBpbnRvIGEgY2F0ZWdvcmljYWwgdXNpbmcgYGNhc2Vfd2hlbigpYCwgZXRjLioKCipUaGUgdGhyZWUgbWFpbiB0aGluZ3MgSSdkIGxpa2UgdG8gZG8gdG8gbXkgZGF0YWZyYW1lIHRvIG1ha2UgaXQgbW9yZSB1c2VmdWwgZm9yIHRoaXMgcHJvamVjdCBhcmU6KgoKMSkgTW92ZSB0aGUgY29sdW1ucyBJIHdpbGwgYmUgdXNpbmcgdGhlIHRoZSBiZWdpbm5pbmcgb2YgdGhlIHRhYmxlLCBiZWNhdXNlIHRoZSAybmQgY29sdW1uIGNvbnRhaW5pbmcgdGhlIGRlc2NyaXB0aW9uIG9mIHRoZSBib2FyZC1nYW1lIGlzIHZlcnkgbG9uZyBhbmQgbWFrZXMgdGhlIHRhYmxlIHVud2llbGR5IHRvIGxvb2sgYXQgcXVpY2tseSB1c2luZyBmdW5jdGlvbnMgbGlrZSBoZWFkLCBhbmQgZG9lc24ndCBzaG93IHVwIHdlbGwgaW4gdGhlIGZpbmFsIGh0bWwgZmlsZS4KCjIpIERpdmlkZSBtaW5pbXVtIHBsYXl0aW1lIGludG8gZ3JvdXBzLCB0byBlYXNlIGFuYWx5c2lzOyB0aGlzIHdpbGwgaW52b2x2ZSBtYWtpbmcgYSBuZXcgY2F0ZWdvcmljYWwgdmFyaWFibGUgZm9yIG1pbmltdW0gcGxheXRpbWUuIAoKMykgRGl2aWRlIG1pbmltdW0gYWdlIGludG8gY2F0ZWdvcmllcyBmb3IgbXkgYW5hbHlzaXM7IEknbGwgbmVlZCB0byBsb29rIGF0IHRoZSByYW5nZSBhbmQgZGlzdHJpYnV0aW9uIG9mIGFnZXMgZmlyc3QsIGFuZCB0aGVuIGNob29zZSBhcHByb3ByaWF0ZSBjYXRlZ29yeSBicmVha3MgYW5kIGFkZCBhIG5ldyBjb2x1bW4gd2l0aCB0aGUgcmUtY29kZWQgY2F0ZWdvcmljYWwgdmFyaWFibGUuIFRoaXMgd2lsbCBhbGxvdyBtZSB0byBzdWJzZXQgZm9yIHRoZSBuZXh0IHF1ZXN0aW9uLgoKPiAqU3Vic2V0IG9mIHRoZSBkYXRhIGFuZCB0aGluayBvZiBhIHF1ZXN0aW9uIHRvIGFuc3dlciB0aGUgc3Vic2V0KgoKSSB3aWxsIGJlIHN1Yi1zZXR0aW5nIHRoZSBkYXRhIGludG8gYWdlIGdyb3VwcyBpbiBvcmRlciB0byBsb29rIG5vdCBvbmx5IHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIG1pbmltdW0gcGxheXRpbWUgYW5kIGF2ZXJhZ2UgcmF0aW5nIG92ZXJhbGwsIGJ1dCBhbHNvIGluIGVhY2ggb2YgdGhlIHNlcGFyYXRlIGFnZSBncm91cHMuIAoKPiAqQm9udXMgcG9pbnRzICg1IHBvaW50cykgZm9yIGRhdGFzZXRzIHRoYXQgcmVxdWlyZSBtZXJnaW5nIG9mIHRhYmxlcywgYnV0IG9ubHkgaWYgeW91IHJlYXNvbiB0aHJvdWdoIHdoZXRoZXIgeW91IHNob3VsZCB1c2UgYGxlZnRfam9pbmAsIGBpbm5lcl9qb2luYCwgb3IgYHJpZ2h0X2pvaW5gIG9uIHRoZXNlIHRhYmxlcy4gTm8gY3JlZGl0IHdpbGwgYmUgcHJvdmlkZWQgaWYgeW91IGRvbid0LioKCkkgZG9uJ3QgYW50aWNpcGF0ZSBuZWVkaW5nIHRvIG1lcmdlIHRhYmxlcyBmb3IgdGhpcyBwcm9qZWN0LCBhcyB0aGUgQm9hcmRHYW1lcyBkYXRhc2V0IGNhbWUgaW4gYSBjb21wbGV0ZSBmb3JtLiAKCgpgYGB7cn0KI0ZpcnN0LCBJIGFtIHJlYXJyYW5naW5nIHRoZSBjb2x1bW5zIGluIHRoZSB0YWJsZS4gVGhpcyBjb2RlIGNhbWUgZnJvbSBEci4gTWlubmllciBhbmQgRHIuIE5pZWRlcmhhdXNlbidzICJBbiBJbnRyb2R1Y3Rpb24gdG8gUiBhbmQgUlN0dWRpbyBmb3IgRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcyIgUGFydCAyIHNsaWRlcy4gaHR0cHM6Ly9qbWlubmllci1iZXJkLXItY291cnNlcy5uZXRsaWZ5LmFwcC8wMS1pbnRyby1yLWVkYS8wMV9pbnRyb19yX2VkYV9wYXJ0MiMxCgpCb2FyZEdhbWVzX1YxIDwtIEJvYXJkR2FtZXMgJT4lCiAgcmVsb2NhdGUobWluX2FnZSkgCkJvYXJkR2FtZXNfVjEgPC0gQm9hcmRHYW1lc19WMSAlPiUKICByZWxvY2F0ZShtaW5fcGxheXRpbWUsIC5iZWZvcmUgPSBnYW1lX2lkKQpCb2FyZEdhbWVzX1YxIDwtIEJvYXJkR2FtZXNfVjEgJT4lCiAgcmVsb2NhdGUoYXZlcmFnZV9yYXRpbmcsIC5iZWZvcmUgPSBnYW1lX2lkKQpoZWFkKEJvYXJkR2FtZXNfVjEpCmBgYAoKYGBge3J9CiNOb3cgdGhhdCBteSBjb2x1bW5zIGFyZSBpbiBhIGdvb2Qgb3JkZXIsIEkgd2FudCB0byBsb29rIGF0IG15IG1pbmltdW0gcGxheXRpbWUgZGF0YSwgYW5kIHNlZSB3aGF0IHRoZSBkaXN0cmlidXRpb24gaXMgc28gdGhhdCBJIGNhbiBmaW5kIGdvb2QgY3V0IHBvaW50cyBmb3IgbXkgY2F0ZWdvcml6YXRpb24uIEZpcnN0IEkgdXNlZCB0aGUgY291bnQgZnVuY3Rpb24gdG8gc2VlIHRoZSBkaXN0cmlidXRpb24gb2Ygb2JzZXJ2YXRpb25zIGZvciBlYWNoIHBsYXl0aW1lLiAKQm9hcmRHYW1lc19WMSAlPiUKICBjb3VudChtaW5fcGxheXRpbWUpCmBgYAoKYGBge3J9CiNUaGVuIEkgbWFkZSBhIGJveHBsb3Qgb2YgdGhlIG1pbmltdW0gcGxheSB0aW1lcyB0byB2aXN1YWxpemUgdGhlIGRpc3RyaWJ1dGlvbgpib3hwbG90KEJvYXJkR2FtZXNfVjEkbWluX3BsYXl0aW1lLCBob3Jpem9udGFsID0gVCwgeGxhYiA9ICJNaW5pbXVtIFBsYXl0aW1lIChNaW4pIiwgbWFpbiA9ICJCb3hwbG90IG9mIE1pbiBQbGF5dGltZSBEaXN0cmlidXRpb24iKQpgYGAKCkFzIHdlIGNhbiBzZWUsIHRoZXJlIGFyZSBhIGZldyBleHRyZW1lIG91dGxpZXJzOyB3aGljaCBpcyBtYWtpbmcgaXQgaGFyZCB0byB2aXN1YWxpemUgdGhlIGRhdGE7IEknbSBnb2luZyB0byByZW1vdmUgdGhvc2UgcG9pbnRzIHRlbXBvcmFyaWx5LgpgYGB7cn0KIyBJJ20gZmlsdGVyaW5nIG91dCB0aGUgaGlnaGVzdCAzIG9ic2VydmF0aW9ucyB3aGljaCB3ZXJlIG11Y2ggaGlnaGVyIHRoYW4gYW55IG9mIHRoZSBvdGhlciBtaW4gcGxheS10aW1lcwpCb2FyZEdhbWVzX1YxLjEgPC0gQm9hcmRHYW1lc19WMSAlPiUKICBmaWx0ZXIobWluX3BsYXl0aW1lIDw9IDYwMDApCmJveHBsb3QoQm9hcmRHYW1lc19WMS4xJG1pbl9wbGF5dGltZSwgaG9yaXpvbnRhbCA9IFQsIHhsYWIgPSAiTWluaW11bSBQbGF5dGltZSAoTWluKSIsIG1haW4gPSAiQm94cGxvdCBvZiBNaW4gUGxheXRpbWUgRGlzdHJpYnV0aW9uIHcvIE91dCBNb3N0IEV4dHJlbWUgT3V0bGllcnMiKQpgYGAKCkFzIHdlIGNhbiBzZWUsIHRoaXMgZ3JhcGggc3RpbGwgaXNuJ3QgZ3JlYXQsIHdpdGggbW9zdCBvZiB0aGUgZGF0YSBjcmFtcGVkIGF0IHRoZSBsb3cgZW5kIGFuZCBhIGZldyBoaWdoIHZhbHVlcywgaG93ZXZlciwgYXQgdGhpcyBwb2ludCBJJ20gc3RpbGwgZ29pbmcgdG8gdHJ5IHRvIGRpdmlkZSB1cCB0aGUgZGF0YSBpbnRvIGNhdGVnb3JpZXM6CgpgYGB7cn0KIyBIZXJlIEkgYW0gdXNpbmcgY2FzZV93aGVuIHRvIGNyZWF0ZSBjYXRlZ29yaWVzIGZvciB0aGUgbWluaW11bSBwbGF5dGltZSBmb3IgZWFjaCBnYW1lLCB3aXRoICsxMC0zMCBtZWFuaW5nIG1vcmUgdGhhbiAxMCwgdXAgdG8gMzAgbWludXRlcywgZXRjLgpCb2FyZEdhbWVzX1YyIDwtIEJvYXJkR2FtZXNfVjEgJT4lCiAgbXV0YXRlKG1pbl9wbGF5X2NhdGVnb3JpZXMgPSBjYXNlX3doZW4oCiAgICBtaW5fcGxheXRpbWUgPT0gMCB+ICIwOk5vIE1pbiBQbGF5dGltZSIsCiAgICBtaW5fcGxheXRpbWUgPiAwICYgbWluX3BsYXl0aW1lIDw9IDEwIH4gIjE6MTAgbWluIG9yIGxlc3MiLAogICAgbWluX3BsYXl0aW1lID4gMTAgJiBtaW5fcGxheXRpbWUgPD0gMzAgfiAiMjorMTAtMzAgbWluIiwKICAgIG1pbl9wbGF5dGltZSA+IDMwICYgbWluX3BsYXl0aW1lIDw9IDYwIH4gIjM6KzMwLTYwIG1pbiIsCiAgICBtaW5fcGxheXRpbWUgPiA2MCAmIG1pbl9wbGF5dGltZSA8PSAxODAgfiAiNDorMS0zIGhycyIsCiAgICBtaW5fcGxheXRpbWUgPiAxODAgJiBtaW5fcGxheXRpbWUgPD0gNzIwIH4gIjU6KzMtMTIgaHJzIiwKICAgIG1pbl9wbGF5dGltZSA+IDcyMCB+ICI2Ok1vcmUgdGhhbiAxMiBocnMiCiAgKQopCkJvYXJkR2FtZXNfVjIgPC0gQm9hcmRHYW1lc19WMiAlPiUKICByZWxvY2F0ZShtaW5fcGxheV9jYXRlZ29yaWVzLCAuYWZ0ZXIgPSBtaW5fcGxheXRpbWUpCmhlYWQoQm9hcmRHYW1lc19WMikKYGBgCgoKYGBge3J9CiNTaW1pbGFyIHRvIGFib3ZlLCBJIHdhbnQgdG8gbG9vayBhdCBteSBhZ2UgZGF0YSwgYW5kIHNlZSB3aGF0IHRoZSBkaXN0cmlidXRpb24gaXMgc28gdGhhdCBJIGNhbiBmaW5kIGdvb2QgY3V0IHBvaW50cyBmb3IgbXkgY2F0ZWdvcml6YXRpb24uIEZpcnN0IEkgdXNlZCB0aGUgY291bnQgZnVuY3Rpb24gdG8gc2VlIHRoZSBkaXN0cmlidXRpb24gb2Ygb2JzZXJ2YXRpb25zIGZvciBlYWNoIGFnZS4KQm9hcmRHYW1lc19WMiAlPiUKICBjb3VudChtaW5fYWdlKQpgYGAKYGBge3J9CiNUaGVuIEkgbWFkZSBhIHJvdWdoIGhpc3RvZ3JhbSB0byB2aXN1YWxpemUgdGhlIGRpc3RyaWJ1dGlvbgpoaXN0KEJvYXJkR2FtZXNfVjIkbWluX2FnZSwgeGxhYiA9ICJNaW5pbXVtIEFnZSAoeXJzKSIsIHlsYWIgPSAiRnJlcXVlbmN5IiwgbWFpbiA9ICJIaXN0b2dyYW0gb2YgTWluIEFnZSBEaXN0cmlidXRpb24iKQpgYGAKCkJhc2VkIG9uIHRoZSBpbmZvcm1hdGlvbiBmcm9tIG15IGV4cGxvcmF0b3J5IGFuYWx5c2lzIG9mIHRoZSBtaW5pbXVtIGFnZSBkaXN0cmlidXRpb24sIGFuZCBteSBvd24ga25vd2xlZGdlIG9mIGNoaWxkcmVuLCBJIGhhdmUgY2hvc2VuIHRvIGN1dCB0aGUgYWdlIGRpc3RyaWJ1dGlvbiBpbnRvIHRoZSBmb2xsb3dpbmcgY2F0ZWdvcmllczogTm8gTWluIEFnZSwgWW91bmcgQ2hpbGQgKDEtNiB5cnMpLCBPbGRlciBDaGlsZCAoNy0xMiB5cnMpLCBUZWVuICgxMy0xNyB5cnMpLCBhbmQgQWR1bHQgKDE4KyB5cnMpCmBgYHtyfQojIEhlcmUgSSBhbSB1c2luZyBjYXNlX3doZW4gdG8gY3JlYXRlIGNhdGVnb3JpZXMgZm9yIHRoZSBtaW5pbXVtIGFnZSBvZiBwbGF5ZXIgZm9yIGVhY2ggZ2FtZQpCb2FyZEdhbWVzX1YzIDwtIEJvYXJkR2FtZXNfVjIgJT4lCiAgbXV0YXRlKG1pbl9hZ2VfY2F0ZWdvcmllcyA9IGNhc2Vfd2hlbigKICAgIG1pbl9hZ2UgPT0gMCB+ICIwOk5vIE1pbiBBZ2UiLAogICAgbWluX2FnZSA+IDAgJiBtaW5fYWdlIDw9IDYgfiAiMTpZb3VuZyBDaGlsZCAoMC02IHlycykiLAogICAgbWluX2FnZSA+IDYgJiBtaW5fYWdlIDw9IDEyIH4gIjI6T2xkZXIgQ2hpbGQgKDctMTIgeXJzKSIsCiAgICBtaW5fYWdlID4gMTIgJiBtaW5fYWdlIDw9IDE3IH4gIjM6VGVlbiAoMTMtMTcgeXJzKSIsCiAgICBtaW5fYWdlID4gMTcgfiAiNDpBZHVsdCAoMTgrIHlycykiCiAgKQopCkJvYXJkR2FtZXNfVjMgPC0gQm9hcmRHYW1lc19WMyAlPiUKICByZWxvY2F0ZShtaW5fYWdlX2NhdGVnb3JpZXMsIC5hZnRlciA9IG1pbl9hZ2UpCmBgYAoKPiAqU2hvdyB5b3VyIHRyYW5zZm9ybWVkIHRhYmxlIGhlcmUuKiBVc2UgdG9vbHMgc3VjaCBhcyBgZ2xpbXBzZSgpYCwgYHNraW0oKWAgb3IgYGhlYWQoKWAgdG8gaWxsdXN0cmF0ZSB5b3VyIHBvaW50LiAKCk5vdywgd2UgY2FuIHNlZSB0aGF0IG91ciByZWFycmFuZ2VtZW50IGFuZCByZS1jYXRlZ29yaXphdGlvbiB3b3JrZWQ6CmBgYHtyfQpoZWFkKEJvYXJkR2FtZXNfVjMpCmBgYAoKSSBjYW4gYWxzbyBtYWtlIHNlcGFyYXRlIHRhYmxlcyBmb3IgZWFjaCBvZiB0aGUgZGlmZmVyZW50IGFnZSBncm91cHMsIGlmIG5lZWRlZCBmb3Igc3Vic2V0dGluZyBhbmFseXNpcyBsYXRlcjoKYGBge3J9CiNBZ2FpbiwgdGhpcyBjb2RlIGNhbWUgZnJvbSBEci4gTWlubmllciBhbmQgRHIuIE5pZWRlcmhhdXNlbidzICJBbiBJbnRyb2R1Y3Rpb24gdG8gUiBhbmQgUlN0dWRpbyBmb3IgRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcyIgUGFydCAyIHNsaWRlcy4gaHR0cHM6Ly9qbWlubmllci1iZXJkLXItY291cnNlcy5uZXRsaWZ5LmFwcC8wMS1pbnRyby1yLWVkYS8wMV9pbnRyb19yX2VkYV9wYXJ0MiMxLCBhcyBtZW50aW9uZWQgYWJvdmUgZm9yIHRoZSByZWxvY2F0aW9uIGRhdGEKCk5vTWluQWdlX0dhbWVzIDwtIEJvYXJkR2FtZXNfVjMgJT4lCiAgZmlsdGVyKG1pbl9hZ2VfY2F0ZWdvcmllcyA9PSAiMDpObyBNaW4gQWdlIikKaGVhZChOb01pbkFnZV9HYW1lcykKWW91bmdDaGlsZF9Cb2FyZEdhbWVzIDwtIEJvYXJkR2FtZXNfVjMgJT4lCiAgZmlsdGVyKG1pbl9hZ2VfY2F0ZWdvcmllcyA9PSAiMTpZb3VuZyBDaGlsZCAoMC02IHlycykiKQpoZWFkKFlvdW5nQ2hpbGRfQm9hcmRHYW1lcykKT2xkZXJDaGlsZF9Cb2FyZEdhbWVzIDwtIEJvYXJkR2FtZXNfVjMgJT4lCiAgZmlsdGVyKG1pbl9hZ2VfY2F0ZWdvcmllcyA9PSAiMjpPbGRlciBDaGlsZCAoNy0xMiB5cnMpIikKaGVhZChPbGRlckNoaWxkX0JvYXJkR2FtZXMpClRlZW5fQm9hcmRHYW1lcyA8LSBCb2FyZEdhbWVzX1YzICU+JQogIGZpbHRlcihtaW5fYWdlX2NhdGVnb3JpZXMgPT0gIjM6VGVlbiAoMTMtMTcgeXJzKSIpCmhlYWQoVGVlbl9Cb2FyZEdhbWVzKQpBZHVsdF9Cb2FyZEdhbWVzIDwtIEJvYXJkR2FtZXNfVjMgJT4lCiAgZmlsdGVyKG1pbl9hZ2VfY2F0ZWdvcmllcyA9PSAiNDpBZHVsdCAoMTgrIHlycykiKQpoZWFkKEFkdWx0X0JvYXJkR2FtZXMpCmBgYAoKCj4gKkFyZSB0aGUgdmFsdWVzIHdoYXQgeW91IGV4cGVjdGVkIGZvciB0aGUgdmFyaWFibGVzPyBXaHkgb3IgV2h5IG5vdD8qCgpJIHdhcyBzdXJwcmlzZWQgdGhhdCB0aGVyZSB3ZXJlIHNvIG1hbnkgbWluaW11bSBwbGF5dGltZSBhbmQgbWluaW11bSBhZ2UgdmFsdWVzIG9mIHplcm87IEkgaG9uZXN0bHkgd2Fzbid0IHN1cmUgaWYgdGhpcyB3YXMgdGhlIGVxdWl2YWxlbnQgb2YgYSAiTkEsIiBvciBpZiBpdCB3YXMgdGhlIGdhbWUtZGVzaWduZXIncyBpbmRpY2F0aW9uIHRoYXQgdGhlcmUgd2FzIG5vdCBhIG1pbmltdW0gcGxheXRpbWUgb3Igbm90IGEgbWluaW11bSBhZ2UgbGltaXQuIEl0IG9yZGVyIHRvIGFjY291bnQgZm9yIHRoaXMsIEkgbWFkZSBhIHNlcGFyYXRlIGNhdGVnb3J5IGZvciB0aGVzZSBnYW1lcywgc28gdGhhdCBJIGNvdWxkIGNob29zZSB3aGV0aGVyIG9yIG5vdCB0byB1c2UgdGhlbSBpbiBteSBmaW5hbCBhbmFseXNpcy4gT3RoZXJ3aXNlLCBJIHdhcyBub3QgdGVycmlibHkgc3VycHJpc2VkIGJ5IGFueXRoaW5nIHNvIGZhci4gCgoKIyMgVmlzdWFsaXppbmcgYW5kIFN1bW1hcml6aW5nIHRoZSBEYXRhICgxNSBwb2ludHMpCgo+ICpVc2UgYGdyb3VwX2J5KCkvc3VtbWFyaXplKClgIHRvIG1ha2UgYSBzdW1tYXJ5IG9mIHRoZSBkYXRhIGhlcmUuIFRoZSBzdW1tYXJ5IHNob3VsZCBiZSByZWxldmFudCB0byB5b3VyIHJlc2VhcmNoIHF1ZXN0aW9uKiAKCkZpcnN0IEkgd2lsbCBiZSBhZGRyZXNzaW5nIG15IHByaW1hcnkgcmVzZWFyY2ggcXVlc3Rpb24sIHdoaWNoIHdhczogaG93IGRvZXMgdGhlIG1pbmltdW0gcGxheXRpbWUgYWZmZWN0IHRoZSBhdmVyYWdlIHJhdGluZyBpbiB0aGUgb3ZlcmFsbCBkYXRhc2V0PwoKKipNYWluIFF1ZXN0aW9uKioKYGBge3J9CiNUaGlzIHN1bW1hcnkgaXMgdGhlIGF2ZXJhZ2UgcmF0aW5nLCBncm91cGVkIGJ5IG1pbmltdW0gcGxheXRpbWUKQm9hcmRHYW1lc19WMyAlPiUKICBncm91cF9ieShtaW5fcGxheV9jYXRlZ29yaWVzKSAlPiUKICBzdW1tYXJpc2UoTnVtYmVyX0dhbWVzID0gbigpLCBNZWFuX1JhdGluZyA9IG1lYW4oYXZlcmFnZV9yYXRpbmcpLCBNZWRpYW5fUmF0aW5nID0gbWVkaWFuKGF2ZXJhZ2VfcmF0aW5nKSwgTWluX1JhdGluZyA9IG1pbihhdmVyYWdlX3JhdGluZyksIE1heF9SYXRpbmcgPSBtYXgoYXZlcmFnZV9yYXRpbmcpKQpgYGAKCk5leHQgSSdsbCBsb29rIGludG8gbXkgc2Vjb25kYXJ5IHF1ZXN0aW9uLCB3aGljaCBpczogaG93IGRvZXMgdGhlIG1pbiBwbGF5dGltZSBhZmZlY3QgbWVhbiByYXRpbmcgd2hlbiB3ZSBzdHJhdGlmeSBieSBhZ2UgZ3JvdXA/CgoqKk5vIE1pbiBBZ2UqKgpgYGB7cn0KI05vIE1pbiBBZ2UgKHBvc3NpYmx5IGp1c3QgTkEgY2F0ZWdvcnkpCk5vTWluQWdlX0dhbWVzICU+JQogIGdyb3VwX2J5KG1pbl9wbGF5X2NhdGVnb3JpZXMpICU+JQogIHN1bW1hcmlzZShOdW1iZXJfR2FtZXMgPSBuKCksIE1lYW5fUmF0aW5nID0gbWVhbihhdmVyYWdlX3JhdGluZyksIE1lZGlhbl9SYXRpbmcgPSBtZWRpYW4oYXZlcmFnZV9yYXRpbmcpLCBNaW5fUmF0aW5nID0gbWluKGF2ZXJhZ2VfcmF0aW5nKSwgTWF4X1JhdGluZyA9IG1heChhdmVyYWdlX3JhdGluZykpCmBgYAoKKipZb3VuZyBDaGlsZHJlbioqCmBgYHtyfQojWW91bmcgQ2hpbGRyZW4KWW91bmdDaGlsZF9Cb2FyZEdhbWVzICU+JQogIGdyb3VwX2J5KG1pbl9wbGF5X2NhdGVnb3JpZXMpICU+JQogIHN1bW1hcmlzZShOdW1iZXJfR2FtZXMgPSBuKCksIE1lYW5fUmF0aW5nID0gbWVhbihhdmVyYWdlX3JhdGluZyksIE1lZGlhbl9SYXRpbmcgPSBtZWRpYW4oYXZlcmFnZV9yYXRpbmcpLCBNaW5fUmF0aW5nID0gbWluKGF2ZXJhZ2VfcmF0aW5nKSwgTWF4X1JhdGluZyA9IG1heChhdmVyYWdlX3JhdGluZykpCmBgYAoKKipPbGRlciBDaGlsZHJlbioqCmBgYHtyfQojT2xkZXIgQ2hpbGRyZW4KT2xkZXJDaGlsZF9Cb2FyZEdhbWVzICU+JQogIGdyb3VwX2J5KG1pbl9wbGF5X2NhdGVnb3JpZXMpICU+JQogIHN1bW1hcmlzZShOdW1iZXJfR2FtZXMgPSBuKCksIE1lYW5fUmF0aW5nID0gbWVhbihhdmVyYWdlX3JhdGluZyksIE1lZGlhbl9SYXRpbmcgPSBtZWRpYW4oYXZlcmFnZV9yYXRpbmcpLCBNaW5fUmF0aW5nID0gbWluKGF2ZXJhZ2VfcmF0aW5nKSwgTWF4X1JhdGluZyA9IG1heChhdmVyYWdlX3JhdGluZykpCmBgYAoKKipUZWVucyoqCmBgYHtyfQojVGVlbnMKVGVlbl9Cb2FyZEdhbWVzICU+JQogIGdyb3VwX2J5KG1pbl9wbGF5X2NhdGVnb3JpZXMpICU+JQogIHN1bW1hcmlzZShOdW1iZXJfR2FtZXMgPSBuKCksIE1lYW5fUmF0aW5nID0gbWVhbihhdmVyYWdlX3JhdGluZyksIE1lZGlhbl9SYXRpbmcgPSBtZWRpYW4oYXZlcmFnZV9yYXRpbmcpLCBNaW5fUmF0aW5nID0gbWluKGF2ZXJhZ2VfcmF0aW5nKSwgTWF4X1JhdGluZyA9IG1heChhdmVyYWdlX3JhdGluZykpCmBgYAoKKipBZHVsdHMqKgpgYGB7cn0KI0FkdWx0cwpBZHVsdF9Cb2FyZEdhbWVzICU+JQogIGdyb3VwX2J5KG1pbl9wbGF5X2NhdGVnb3JpZXMpICU+JQogIHN1bW1hcmlzZShOdW1iZXJfR2FtZXMgPSBuKCksIE1lYW5fUmF0aW5nID0gbWVhbihhdmVyYWdlX3JhdGluZyksIE1lZGlhbl9SYXRpbmcgPSBtZWRpYW4oYXZlcmFnZV9yYXRpbmcpLCBNaW5fUmF0aW5nID0gbWluKGF2ZXJhZ2VfcmF0aW5nKSwgTWF4X1JhdGluZyA9IG1heChhdmVyYWdlX3JhdGluZykpCmBgYAoKCj4gKldoYXQgYXJlIHlvdXIgZmluZGluZ3MgYWJvdXQgdGhlIHN1bW1hcnk/IEFyZSB0aGV5IHdoYXQgeW91IGV4cGVjdGVkPyoKCkluaXRpYWxseSBsb29raW5nIGF0IHRoZSBkYXRhLCBJIHdhcyBzdXJwcmlzZWQsIGJlY2F1c2UgKGVzcGVjaWFsbHkgaWYgd2UgaWdub3JlIHRoZSBObyBNaW4gUGxheXRpbWUgY2F0ZWdvcnksIHdoaWNoIEkgdGhpbmsgaXMgcmVhc29uYWJsZSBzaW5jZSB3ZSBhcmUgbm90IHN1cmUgaWYgdGhhdCBpcyByZWFsbHkganVzdCB0aGUgTkEgY2F0ZWdvcnkgb3Igbm90KSwgd2UgY2FuIHNlZSB0aGF0IG1lYW4gcmF0aW5nIGFuZCBtZWRpYW4gcmF0aW5nIGJvdGggZ28gdXAgd2l0aCBlYWNoIE1pbmltdW0gUGxheXRpbWUgY2F0ZWdvcnk7IGl0IHNlZW1zIGZyb20gdGhpcyBzdW1tYXJ5IGRhdGEgdGhhdCB0aGUgcGxheWVycyBhY3R1YWxseSBwcmVmZXIgbG9uZ2VyIHBsYXl0aW1lIQoKQnV0IHdoYXQgYWJvdXQgaWYgd2Ugc3Vic2V0IGJ5IGFnZSBncm91cD8gCgpUaGUgcGF0dGVybiBpcyBsZXNzIGNvbnNpc3RlbnQgd2hlbiB3ZSBicmVhayB0aGUgZGF0YSBkb3duIGludG8gYWdlIGdyb3Vwcy4gCipObyBNaW4gQWdlKiB0aGlzIGdyb3VwIGlzIG9mIHVua25vd24gdXNlZnVsbmVzcywgc2luY2Ugd2UgZG9uJ3Qga25vdyBpZiBpdCBpcyBqdXN0IGEgc3RhbmQtaW4gZm9yIE5BLiBJbiB0aGlzIHRhYmxlLCB3ZSBzZWUgdGhhdCB0aGUgbG9uZ2VyIGdhbWVzIGFyZSBoaWdoZXN0IHJhdGVkLCBidXQgdGhlcmUgaXMgbm90IGEgY29uc2lzdGVudCBwYXR0ZXJuIHdpdGggdGhlIHJhdGluZ3MuIAoqWW91bmcgQ2hpbGRyZW4qIHNlZW0gdG8gZW5qb3kgKzEwLTMwIG1pbiBnYW1lcyB0aGUgbW9zdCwgYnV0IHJhdGluZ3Mgd2VyZSBmYWlybHkgY29uc2lzdGVudCBhY3Jvc3MgcGxheXRpbWUgY2F0ZWdvcmllcy4gVGhlcmUgd2VyZSBubyBnYW1lcyBmb3IgeW91bmcgY2hpbGRyZW4gd2l0aCBwbGF5dGltZXMgbG9uZ2VyIHRoYW4gMyBob3Vycy4KKk9sZGVyIENoaWxkcmVuKiBhbmQgKlRlZW5zKiBib3RoIHNlZW1lZCB0byBmb2xsb3cgdGhlIG92ZXJhbGwgcGF0dGVybiBvZiBwcmVmZXJyaW5nIGxvbmdlciBnYW1lcywgd2l0aCBtZWFuKGF2ZXJhZ2VfcmF0aW5nKSByaXNpbmcgc3RlYWRpbHkgYXMgcGxheXRpbWVzIHJvc2UuIAoqQWR1bHRzKiBzZWVtIGZyb20gdGhlIGRhdGEgdG8gZW5qb3kgKzEtMyBociBnYW1lcyB0aGUgbW9zdCwgYnV0IHRoZXJlIHdlcmUgbXVjaCBmZXdlciBnYW1lcyBhaW1lZCBmb3IgYSBtaW5pbXVtIGFnZSBvZiBBZHVsdHMgMTgrLCBhbiBvbmx5IG9uZSBhZHVsdCBnYW1lIGxvbmdlciB0aGFuIDMgaG91cnMsIHNvIGl0IGlzIGhhcmRlciB0byB0cnVzdCB0aGUgcGF0dGVybiBpbiB0aGlzIGRhdGEgYXMgbXVjaCBhcyBmb3Igc29tZSBvZiB0aGUgb3RoZXIgZ3JvdXBzLiAKCgo+ICpNYWtlIGF0IGxlYXN0IHR3byBwbG90cyB0aGF0IGhlbHAgeW91IGFuc3dlciB5b3VyIHF1ZXN0aW9uIG9uIHRoZSB0cmFuc2Zvcm1lZCBvciBzdW1tYXJpemVkIGRhdGEuKgoKKipQbG90IG9mIE1pbmltdW0gUGxheXRpbWUgdnMgQXZlcmFnZSBHYW1lIFJhdGluZyoqCgoKYGBge3J9CiMgRmlyc3QgSSBjcmVhdGVkIGEgbmV3IGRhdGFmcmFtZSB3aXRoIGFsbCB0aGUgTm8gTWluIEFnZSBhbmQgTm8gTWluIFBsYXl0aW1lLCBzaW5jZSB3ZSBhcmVuJ3Qgc3VyZSBpZiB0aG9zZSBhcmUgdXNlZnVsIG9yIGp1c3QgZGlmZmVyZW50bHkgY29kZWQgTkEgdmFsdWVzLgpCb2FyZEdhbWVzX1Y0IDwtIEJvYXJkR2FtZXNfVjMgJT4lCiAgZmlsdGVyKG1pbl9wbGF5X2NhdGVnb3JpZXMgIT0gIjA6Tm8gTWluIFBsYXl0aW1lIikKQm9hcmRHYW1lc19WNCA8LSBCb2FyZEdhbWVzX1Y0ICU+JQogIGZpbHRlcihtaW5fYWdlX2NhdGVnb3JpZXMgIT0gIjA6Tm8gTWluIEFnZSIpCmBgYAoKYGBge3J9CiNGaXJzdCBJIHdhbnQgdG8gbWFrZSBhIHBsb3QgYWRkcmVzc2luZyB0aGUgbWFpbiByZXNlYXJjaCBxdWVzdGlvbiwgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIG1pbmltdW0gcGxheXRpbWUgYW5kIGF2ZXJhZ2UgcmF0aW5nLiBBZ2FpbiwgSSBtYWRlIHVzZSBvZiBEci4gTWlubmllciBhbmQgRHIuIE5pZWRlcmhhdXNlbidzIHNsaWRlcyBmcm9tIHRoZWlyICJBbiBJbnRyb2R1Y3Rpb24gdG8gUiBhbmQgUlN0dWRpbyBmb3IgRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcyIgcHQgMiBwcmVzZW50YXRpb24sIGFuZCBhbHNvIHRoZSAiRGF0YSBWaXN1YWxpemF0aW9uIHdpdGggZ2dwbG90MiA6IDogQ0hFQVQgU0hFRVQiIGF2YWlsYWJsZSB0aHJvdWdoIHRoZSBoZWxwIGZ1bmN0aW9uIGluIFJTdHVkaW8uIEkgYWxzbyB1c2VkIHRoZSBQYXJ0IDQgbGVjdHVyZSBmcm9tIHRoaXMgY291cnNlIHRvIGhlbHAgd2l0aCBteSBjb2RlLiAKZ2dwbG90KGRhdGEgPSBCb2FyZEdhbWVzX1Y0LAogICAgICAgYWVzKHggPSBtaW5fcGxheXRpbWUsIHkgPSBhdmVyYWdlX3JhdGluZywgY29sb3IgPSBhdmVyYWdlX3JhdGluZykpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9IGxtKSArCiAgc2NhbGVfeF9sb2cxMCgpICsKICBsYWJzKHRpdGxlID0gIk1pbmltdW0gUGxheXRpbWUgdnMgQXZlcmFnZSBHYW1lIFJhdGluZyIsIHggPSAiTG9nKDEwKSBvZiBNaW5pbXVtIFBsYXl0aW1lIiwgeSA9ICJBdmVyYWdlIFJhdGluZyIpIApgYGAKCkkgdXNlZCBhIGxvZyBzY2FsZSBmb3IgdGhlIHgtYXhpcyB0byBmaXQgYWxsIHRoZSBkYXRhIGluIHdpdGhvdXQgaGF2aW5nIHRvIHJlbW92ZSBvdXRsaWVycywgYW5kIGdyYXBoaWNhbGx5IGFkZGVkIGEgbGluZWFyIG1vZGVsIHRvIHZpc3VhbGl6ZSB0aGUgZGF0YSB0cmVuZC4KCioqQm94cGxvdHMgb2YgTWluaW11bSBQbGF5dGltZSB2cyBBdmVyYWdlIEdhbWUgUmF0aW5nIGJ5IEFnZSBHcm91cCoqCk5leHQsIEkgd2FudGVkIHRvIGxvb2sgYXQgbXkgYWdlLWNhdGVnb3J5IHN1YnNldHM6CmBgYHtyfQojIEZvciB0aGlzIGJveHBsb3QsIEkgdXNlZCB0aGUgUGFydCAzIGxlY3R1cmUgYW5kIFBhcnQgMyBhc3NpZ25tZW50IGZvciBhc3Npc3RhbmNlIHdpdGggdGhlIGNvZGUsIGFzIHdlbGwgYXMgdGhlICJEYXRhIFZpc3VhbGl6YXRpb24gd2l0aCBnZ3Bsb3QyIDogOiBDSEVBVCBTSEVFVCIgYXZhaWxhYmxlIHRocm91Z2ggdGhlIGhlbHAgZnVuY3Rpb24gaW4gUlN0dWRpbwpnZ3Bsb3QoQm9hcmRHYW1lc19WNCkgKwogIAogIGFlcyh4ID0gbWluX3BsYXlfY2F0ZWdvcmllcywgCiAgICAgIHkgPSBhdmVyYWdlX3JhdGluZywgCiAgICAgIGZpbGwgPSBtaW5fcGxheV9jYXRlZ29yaWVzKSArCiAgCiAgZ2VvbV9ib3hwbG90KCkgKwogIAogIGZhY2V0X2dyaWQocm93cyA9IHZhcnMobWluX2FnZV9jYXRlZ29yaWVzKSkgKwogIAogIGxhYnModGl0bGUgPSJCb3hwbG90IG9mIE1pbiBQbGF5dGltZSBhbmQgQXZnIFJhdGluZyBieSBBZ2UgR3JvdXAiLCB4ID0gIk1pbiBQbGF5dGltZSIsIHkgPSAiQXZnIFJhdGluZyIpICsKICAKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiTWluIFBsYXl0aW1lIikKYGBgCgoKCgojIyBGaW5hbCBTdW1tYXJ5ICgxMCBwb2ludHMpCgo+ICpTdW1tYXJpemUgeW91ciByZXNlYXJjaCBxdWVzdGlvbiBhbmQgZmluZGluZ3MgYmVsb3cuKiAKCk15IG9yaWdpbmFsIHF1ZXN0aW9ucyB3ZXJlIGhvdyBkb2VzIG1pbmltdW0gbGVuZ3RoIG9mIHBsYXkgYWZmZWN0IGF2ZXJhZ2UgcmF0aW5nIG9mIGJvYXJkIGdhbWUgb24gQm9hcmQgR2FtZSBHZWVrPyBIb3cgZG9lcyB0aGlzIGNoYW5nZSBpZiB5b3Ugc3RyYXRpZnkgYnkgbWluaW11bSBhZ2Ugb2YgcGxheWVyPyBXaGF0IEkgZm91bmQgd2FzIHRoYXQgb3ZlcmFsbCwgdGhlIGxvbmdlciB0aGUgbWluaW11bSBsZW5ndGggb2YgcGxheSwgdGhlIGhpZ2hlciB0aGUgbWVhbiBvZiB0aGUgYXZlcmFnZSByYXRpbmcgb24gQm9hcmQgR2FtZSBHZWVrICh3aGVuIGV4Y2x1ZGluZyB0aGUgZ2FtZXMgd2l0aCBubyBsaXN0ZWQgbWluaW11bSBwbGF5dGltZSBkdWUgdG8gbm90IGtub3dpbmcgaWYgdGhvc2Ugd2VyZSB0aGUgZXF1aXZpbGVudCBvZiBOQSB2YWx1ZXMpLiAKSG93ZXZlciwgd2hlbiBJIGJyb2tlIHRoZSBkYXRhIGRvd24gYnkgYWdlIGdyb3VwLCBJIGZvdW5kIHRoYXQgd2hpbGUgdGhpcyB0cmVuZCBoZWxkIHRydWUgZm9yIE9sZGVyIENoaWxkcmVuIGFuZCBUZWVucywgaXQgZGlkIG5vdCBhcyBtdWNoIGZvciBZb3VuZyBDaGlsZHJlbiBhbmQgQWR1bHRzLiBGb3IgYWR1bHRzIHRoZSBwcmVmZXJyZWQgbGVuZ3RoIG9mIGdhbWVwbGF5IHdhcyBtb3JlIHRoYW4gMSBhbmQgdXAgdG8gMyBob3VycywgYW5kIGZvciB5b3VuZyBjaGlsZHJlbiB0aGUgcHJlZmVycmVkIGxlbmd0aCBvZiBnYW1lcGxheSB3YXMgbW9yZSB0aGFuIDEwIGFuZCB1cCB0byAzMCBtaW51dGVzLiBIb3dldmVyLCBpdCBpcyBpbXBvcnRhbnQgdG8gbWVudGlvbiB0aGF0IHRoZXJlIHdlcmUgdmVyeSBmZXcgb2JzZXJ2YXRpb25zIGluIHRoZSBhZHVsdCBncm91cCwgYW5kIGJ5IGZhciB0aGUgbW9zdCBvYnNlcnZhdGlvbnMgaW4gdGhlIG9sZGVyIGNoaWxkIGFuZCB0ZWVuIGdyb3Vwcywgc28gdGhhdCBjb3VsZCBjZXJ0YWlubHkgYmUgcGFydCBvZiB0aGUgcmVhc29uIHdoeSB0aGUgb3ZlcmFsbCB0cmVuZCBmb2xsb3dlZCB0aGUgcGF0dGVybiBvZiB0aG9zZSB0d28gZ3JvdXBzLiAKCgo+ICpBcmUgeW91ciBmaW5kaW5ncyB3aGF0IHlvdSBleHBlY3RlZD8gV2h5IG9yIFdoeSBub3Q/KgoKTXkgZmluZGluZ3MgZm9yIHRoZSBvdmVyYWxsIGRhdGEgd2VyZSBub3Qgd2hhdCBJIGV4cGVjdGVkOyBJIGhhZCBleHBlY3RlZCBwZW9wbGUgdG8gcHJlZmVyIHNob3J0ZXIgZ2FtZXMgYnV0IHRoZSBvdmVyYWxsIHRyZW5kIHNob3dlZCB0aGUgb3Bwb3NpdGUsIHRoZSBsb25nZXIgdGhlIGdhbWUsIHRoZSBoaWdoZXIgdGhlIGF2ZXJhZ2UgcmF0aW5nLiBIb3dldmVyLCBJIGhhZCBhbHNvIGh5cG90aGVzaXplZCB0aGF0IHlvdW5nIGNoaWxkcmVuJ3Mgc2hvcnRlciBhdHRlbnRpb24gc3BhbnMgd291bGQgY2F1c2UgdGhlbSB0byBwcmVmZXIgc2hvcnRlciBnYW1lcywgYW5kIHRoaXMgZGlkIGhvbGQgcHJldHR5IHRydWU7IHRoZSBnYW1lcyB0aGF0IHdlcmUgbGVzcyB0aGFuIDEwIG1pbnV0ZXMsIG9yIDEwLTMwIG1pbnV0ZXMgYm90aCBoYWQgaGlnaGVyIHJhdGluZ3MgdGhhbiBsb25nZXIgZ2FtZXMgaW4gdGhlIFlvdW5nIENoaWxkIGNhdGVnb3J5LiBJIGhhZCBoeXBvdGhlc2l6ZWQgdGhhdCBhdHRlbnRpb24gc3BhbiB3b3VsZCBrZWVwIGdvaW5nIHVwIGFzIHBsYXllcnMgZ290IG9sZGVyLCBhbmQgZ2VuZXJhbGx5IGZvciB0aGUgb2xkZXIgY2hpbGRyZW4gYW5kIHRlZW5zLCBsb25nZXIgZ2FtZXMgd2VyZSBwcmVmZXJyZWQuIFRoZXJlIHdhcyBsaXR0bGUgZGF0YSBmb3IgdGhlIGFkdWx0IG1pbmltdW0gYWdlIGdyb3VwLCBhbmQgc2luY2UgdGhlcmUgd2FzIG9ubHkgb25lIGdhbWUgbG9uZ2VyIHRoYW4gKzEtMyBocnMsIGl0IGlzIGhhcmQgdG8gY29uY2x1ZGUgd2hldGhlciBhZHVsdHMgZGlzbGlrZSB2ZXJ5IGxvbmcgZ2FtZXM7IGZvciBhZHVsdHMgdGhlIHByZWZlcnJlZCBnYW1lIGxlbmd0aCB3YXMgKzEtMyBocnMuIAoK