1 Introduction

For starters, this report was made using the coding language known as R, with the objective of finding out which variables determine the success of a movie. To seek to find this answers, we used the csv file known as movies_metadata.csv. This csv file was obtained from Kaggle (https://www.kaggle.com/datasets/rounakbanik/the-movies-dataset/data), and it contains a registry of over 45,000 movies, 270,000 users and over 26 million ratings. This is important, since we are looking to find concrete answers to our question, and so using a big amount of data will make our results more accurate.

2 Objectives and Variables

As previously mentioned, the main objective is to determine what makes (or doesn’t make) a movie successful. To do this, we looked at the variables within this dataset. These variables are the following: adult, belongs_to_collection, budget, genres homepage, id, imdb_id, original_language, original_title, overview, popularity, poster_path, production_companies, production_countries, release_date, revenue, runtime, spoken_languages, status, tagline, title video, vote_average and vote_count. These variables range from descriptions to numerical values, so we had to assign them a different value and judge them differently from each other. Obviously, to determine the success of a movie, we did not necessarily need to utilize all of these variables, and so to do this, a cleaning process had to be made.

3 Cleaning Process

For this cleaning process, we had to elaborate codes with the objective of filtering out data that is either incorrect, invalid or simply unnecessary for our analysis. To ensure that our data is as well-arranged as possible, I began by ordering the columns by importance, in the manner that I thought would be easiest to understand for the reader. Because of this, the first 2 columns are the name of the movie, and the identification number. After this, I continued by checking for NA values. This refers to values that weren’t recorded properly, and so they make the analysis extremely complicated. Because of this, I deleted these values. Next, I checked for duplicate rows, and logically deleted the copies, to make sure that there is only one row for each movie. Then I continued by cleaning the columns individually: Adult: All values were assigned to either True or False. Runtime: Deleted rows that had impossible runtimes. (Ex. 0 or 1984920 minutes.) Vote_Average: Gave the average rating to rows with a value of 0. Collection: Deleted the parts of the column that I deemed unnecessary (Ex. Parentheses and Collection IDs) Genres, Companies, Countries, Languages: I separated the different values assigned to the movie into different columns, as well as graphed the top 20 of each category. Poster_Path, Tagline, Video: I deleted these columns since I deemed them unnecessary. The remaining columns were left untouched, since I considered that they were both clean, and relevant to the analysis I was trying to do.

//////////

# Checking for NAs
columns_to_check <- c("budget", "genres", "homepage", "id", "imdb_id", "original_language", 
                      "original_title", "overview", "popularity", "poster_path", 
                      "production_companies", "production_countries", "release_date", 
                      "revenue", "runtime", "spoken_languages", "status",
                      "title", "video", "vote_average", "vote_count", "adult")

missing_rows <- which(!complete.cases(movies[, columns_to_check]))

num_missing_rows <- length(missing_rows)

print(paste("Number of missing rows:", num_missing_rows))
## [1] "Number of missing rows: 263"
print("Indices of missing rows:")
## [1] "Indices of missing rows:"
print(missing_rows)
##   [1]   635   636   645   803   864  2141 13563 13577 13661 13758 14770 14891
##  [13] 15246 15385 15734 16902 17318 17491 17952 18039 18573 18673 18917 18969
##  [25] 19316 19372 19730 19731 19875 20167 20380 20643 20712 20827 21103 21251
##  [37] 21985 22314 22347 22425 22664 22819 23039 23227 23419 23421 23830 24231
##  [49] 25204 25505 25508 25512 25515 25562 25631 25678 25912 25938 26075 27881
##  [61] 27968 28133 28246 28274 28277 28416 28658 28801 28952 28965 29228 29265
##  [73] 29301 29308 29309 29310 29312 29449 29451 29503 29504 30357 30380 30386
##  [85] 30783 30790 30828 30945 31011 31057 31230 31359 31416 31533 31544 31545
##  [97] 31557 31581 31588 31589 32004 32065 32156 32177 32424 32498 32499 32509
## [109] 32637 33004 33529 33532 34398 34447 34527 34558 34606 34672 34703 34860
## [121] 35036 35164 35217 35314 35492 35518 35587 35588 35653 35661 35691 35982
## [133] 36218 36348 36352 36403 36422 36461 36592 36858 36864 36900 37077 37085
## [145] 37151 37157 37186 37210 37215 37242 37275 37405 37451 37472 37488 37491
## [157] 37641 37642 37754 37755 37814 38101 38182 38360 38402 38415 39144 39271
## [169] 39302 39365 39367 39497 39568 39678 39721 39723 39852 39971 39972 40152
## [181] 40204 40207 40379 40577 40726 40776 40887 41046 41068 41069 41079 41368
## [193] 41369 41371 41373 41377 41379 41400 41659 41696 41699 41719 41833 41888
## [205] 41922 41923 42069 42150 42151 42198 42199 42258 42290 42298 42321 42345
## [217] 42574 42776 42848 43107 43111 43129 43203 43393 43470 43471 43477 43481
## [229] 43487 43488 43533 43597 43674 43682 43942 43950 43964 43986 44017 44066
## [241] 44121 44152 44383 44395 44424 44560 44568 44574 44593 44784 44878 44912
## [253] 44960 44989 45016 45055 45063 45232 45247 45311 45314 45378 45411
# Cleaning NAs
movies_clean <- movies[complete.cases(movies[, columns_to_check]), ]

print("Dimensions of cleaned dataframe:")
## [1] "Dimensions of cleaned dataframe:"
print(dim(movies_clean))
## [1] 45203    24

//////////

/////////

movies_clean$adult <- ifelse(movies_clean$adult != "True" & movies_clean$adult != "False", "False", movies_clean$adult)

//////////

//////////

//////////

//////////

4 Statistical and Analytical Techniques

After concluding the cleaning process, I began to graph the data into charts and plots. The first 4 graphs I made were the ones I mentioned previously. They contain the 20 most common Genres, Companies, Countries and Languages. These graphs are extremely simple, but I considered them to be essential to the analysis, since they represent the majority of the population. Values that are smaller tend to be much less significant, and so the most popular values in these columns are of the utmost importance. These are the graphs I obtained:

barplot(top_20_studios, main = "Top 20 Most Common Studios", xlab = "Studios", ylab = "Count", las = 2, col = "forestgreen")

# New countries (Top 20 countries graph)
country_counts <- table(movies_clean$production_countries)


new_countries <- str_split_fixed(movies_clean$production_countries, "\\},", n = Inf)


new_countries <- new_countries[, 1:7]


new_countries <- as.data.frame(new_countries)
new_countries <- new_countries %>% 
  mutate(country1 = str_extract(V1, "'name':\\s+'([[:alnum:]\\s]+)'"),
         country2 = str_extract(V2, "'name':\\s+'([[:alnum:]\\s]+)'"),
         country3 = str_extract(V3, "'name':\\s+'([[:alnum:]\\s]+)'"),
         country4 = str_extract(V4, "'name':\\s+'([[:alnum:]\\s]+)'"),
         country5 = str_extract(V5, "'name':\\s+'([[:alnum:]\\s]+)'"),
         country6 = str_extract(V6, "'name':\\s+'([[:alnum:]\\s]+)'"),
         country7 = str_extract(V7, "'name':\\s+'([[:alnum:]\\s]+)'"))


new_countries$country1 <- str_remove(new_countries$country1, "'name':\\s+")
new_countries$country2 <- str_remove(new_countries$country2, "'name':\\s+")
new_countries$country3 <- str_remove(new_countries$country3, "'name':\\s+")
new_countries$country4 <- str_remove(new_countries$country4, "'name':\\s+")
new_countries$country5 <- str_remove(new_countries$country5, "'name':\\s+")
new_countries$country6 <- str_remove(new_countries$country6, "'name':\\s+")
new_countries$country7 <- str_remove(new_countries$country7, "'name':\\s+")

all_countries <- c(new_countries$country1, new_countries$country2, new_countries$country3,
                   new_countries$country4, new_countries$country5, new_countries$country6,
                   new_countries$country7)


country_counts <- table(all_countries)


country_counts <- sort(country_counts, decreasing = TRUE)


top_20_countries <- head(country_counts, 20)

print("Counts of Each Country:")
## [1] "Counts of Each Country:"
print(top_20_countries)
## all_countries
## 'United States of America'           'United Kingdom' 
##                      21128                       4084 
##                   'France'                  'Germany' 
##                       3915                       2211 
##                    'Italy'                   'Canada' 
##                       2132                       1762 
##                    'Japan'                    'Spain' 
##                       1642                        944 
##                   'Russia'                    'India' 
##                        907                        826 
##                'Hong Kong'                   'Sweden' 
##                        595                        579 
##                'Australia'              'South Korea' 
##                        570                        493 
##                  'Belgium'                  'Denmark' 
##                        443                        384 
##                    'China'              'Netherlands' 
##                        372                        372 
##                  'Finland'                   'Mexico' 
##                        371                        325
barplot(top_20_countries, main = "Top 20 Most Common Countries", xlab = "Countries", ylab = "Count", las = 2, col = "red")

# New languages (Top 20 languages graph)
new_languages <- str_split_fixed(movies_clean$spoken_languages, "\\},", n = Inf)

new_languages <- new_languages[, 1:7]

new_languages <- as.data.frame(new_languages)
new_languages <- new_languages %>% 
  mutate(language1 = str_extract(V1, "'name':\\s+'([[:alnum:]\\s]+)'"),
         language2 = str_extract(V2, "'name':\\s+'([[:alnum:]\\s]+)'"),
         language3 = str_extract(V3, "'name':\\s+'([[:alnum:]\\s]+)'"),
         language4 = str_extract(V4, "'name':\\s+'([[:alnum:]\\s]+)'"),
         language5 = str_extract(V5, "'name':\\s+'([[:alnum:]\\s]+)'"),
         language6 = str_extract(V6, "'name':\\s+'([[:alnum:]\\s]+)'"),
         language7 = str_extract(V7, "'name':\\s+'([[:alnum:]\\s]+)'"))

new_languages$language1 <- str_remove(new_languages$language1, "'name':\\s+")
new_languages$language2 <- str_remove(new_languages$language2, "'name':\\s+")
new_languages$language3 <- str_remove(new_languages$language3, "'name':\\s+")
new_languages$language4 <- str_remove(new_languages$language4, "'name':\\s+")
new_languages$language5 <- str_remove(new_languages$language5, "'name':\\s+")
new_languages$language6 <- str_remove(new_languages$language6, "'name':\\s+")
new_languages$language7 <- str_remove(new_languages$language7, "'name':\\s+")

all_languages <- c(new_languages$language1, new_languages$language2, new_languages$language3,
                   new_languages$language4, new_languages$language5, new_languages$language6,
                   new_languages$language7)

language_counts <- table(all_languages)


language_counts <- sort(language_counts, decreasing = TRUE)


top_20_languages <- head(language_counts, 20)

print("Counts of Each Language:")
## [1] "Counts of Each Language:"
print(top_20_languages)
## all_languages
##     'English'    'Français'     'Deutsch'     'Español'    'Italiano' 
##         28716          4173          2590          2387          2338 
##      '日本語'     'Pусский'      '普通话'   'Português'     'svenska' 
##          1755          1547           788           584           553 
##      'Polski'       'suomi'      'Magyar'     'العربية'  'Nederlands' 
##           520           360           359           340           333 
## 'No Language'       'Dansk'       'Český'      'Türkçe'       'עִבְרִית' 
##           319           301           283           238           214
barplot(top_20_languages, main = "Top 20 Most Common Spoken Languages", xlab = "Languages", ylab = "Count", las = 2, col = "skyblue")

Next, I made a table that gives you the name of the different countries and obtains both the average revenue and runtime for each. I considered that these values are also important, since different countries tend to have different preferences when it comes to the duration of films, and well as the fact that they have different amounts of resources, which tends to have an impact on how much a movie earns in sales. This is how this table looks like:

# Runtime and revenue data
all_countries <- c(new_countries$country1, new_countries$country2, new_countries$country3,
                   new_countries$country4, new_countries$country5, new_countries$country6,
                   new_countries$country7)


movie_country <- data.frame(movie_id = rep(movies_clean$id, each = 7), country = all_countries)


movie_country_revenue_runtime <- left_join(movie_country, movies_clean, by = c("movie_id" = "id"))


country_stats <- movie_country_revenue_runtime %>%
  group_by(country) %>%
  summarize(average_revenue = mean(revenue, na.rm = TRUE),
            average_runtime = mean(runtime, na.rm = TRUE),
            average_budget = mean(budget, na.rm = TRUE))
## Warning: There were 159 warnings in `summarize()`.
## The first warning was:
## ℹ In argument: `average_budget = mean(budget, na.rm = TRUE)`.
## ℹ In group 1: `country = "'Afghanistan'"`.
## Caused by warning in `mean.default()`:
## ! argument is not numeric or logical: returning NA
## ℹ Run `dplyr::last_dplyr_warnings()` to see the 158 remaining warnings.
print(country_stats)
## # A tibble: 159 × 4
##    country       average_revenue average_runtime average_budget
##    <chr>                   <dbl>           <dbl>          <dbl>
##  1 'Afghanistan'       18780959.           113.              NA
##  2 'Albania'                  0             95.3             NA
##  3 'Algeria'           65245073.            91.5             NA
##  4 'Angola'            41241269             90.3             NA
##  5 'Antarctica'               0             95               NA
##  6 'Argentina'         20087200.           104.              NA
##  7 'Armenia'           37011790.           107.              NA
##  8 'Aruba'               483333.           103.              NA
##  9 'Australia'         30705248.           106.              NA
## 10 'Austria'           17337497.           104.              NA
## # ℹ 149 more rows

After obtaining this table, I graphed it in a scatter plot, where we can see the top 20 countries by both revenue and runtime, as well as the bottom 20 countries. These are the graphs:

# Highest runtime and revenues scatterplots
top_20_countries <- head(country_stats[order(country_stats$average_revenue, decreasing = TRUE),], 20)


ggplot(top_20_countries, aes(x = country, y = average_revenue)) +
  geom_point() +
  labs(title = "Top 20 Countries: Average Revenue",
       x = "Country", y = "Average Revenue") +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))

top_20_countries <- head(country_stats[order(country_stats$average_runtime, decreasing = TRUE),], 20)


ggplot(top_20_countries, aes(x = country, y = average_runtime)) +
  geom_point() +
  labs(title = "Top 20 Countries: Average Runtime",
       x = "Country", y = "Average Runtime") +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))

Finally, I obtained the average rating by the different studios, by combining all of the results obtained from the different movies. To do this, I made a filter to only include studios with at least 10 movies. This helps us only look at important studios, since some studios might only have 1 or 2 movies, which would increase the range of error in the analysis. After obtaining this average, I graphed the top 20 highest and lowest studios. This is how the graphs look like:

# Top 20 best and worst rated studios (at least 10 movies)
studio_ratings_filtered <- studio_ratings_filtered %>%
  filter(!is.na(average_vote_average))

top_studios <- head(studio_ratings_filtered, 20)
bottom_studios <- tail(studio_ratings_filtered, 20)

ggplot(top_studios, aes(x = average_vote_average, y = reorder(studio, average_vote_average))) +
  geom_bar(stat = "identity", fill = "darkblue") +
  labs(title = "Top 20 Studios by Average Ratings (with at least 10 movies)",
       x = "Average Vote Average", y = "Studio") +
  theme(axis.text.y = element_text(angle = 0, hjust = 1))

ggplot(bottom_studios, aes(x = average_vote_average, y = reorder(studio, average_vote_average))) +
  geom_bar(stat = "identity", fill = "orange") +
  labs(title = "Bottom 20 Studios by Average Ratings (with at least 10 movies)",
       x = "Average Vote Average", y = "Studio") +
  theme(axis.text.y = element_text(angle = 0, hjust = 1))

5 Findings and Results

After these graphs and charts, we can finally view our findings. The first finding we can see, is that the genre with the most movies is Drama. Based on this, we can assume 2 things. First, that studios keep making Drama-oriented movies because there is demand for this genre. Based on this, we can assume that Drama is the most successful genre, considering that there are over 18 thousand movies that have this genre as one of their main identifiers.

For our next finding, we can see which studios are the most successful. The top 3 studios in terms of movies made are Paramount, Fox and Universal, which are extremely well known at a global level. The interesting detail is that these 3 studios are all from the United States, and not only that. Out of the top 10 studios with the most movies made, 9 are from the US. This leads to the conclusion that movies made in this country tend to have higher success rates than others. We can see this graphically, since in the “Most Common Countries” graph, the United States has over 10 times as many movies as the second place (United Kingdom).

This same argument goes on towards the next graph. We can see that the English language is the most popular by an incredibly wide margin. This is not only due to the fact that the USA is the country with the most movies made, but also that English tends to be considered the “World’s Language”, and so people from all over the world seem to be attracted towards movies that have English as one of their options.

The final observation that can be made is related to the last graphs. Most of the lower ranked studios are either not proper studios, or based in countries that have a smaller amount of resources to make their movies. On the other hand, most of the studios with the highest average scores hail from the United States of America.

6 Conclusions and Recommendations

After this thorough analysis, I have arrived at the conclusion that the most important factor in a movies success is it’s country of production. Of course, this is mainly oriented towards the United States, which can be explained by the fact that they have the highest amount of studios out of any country by far. Another factor that can be attributed to this is that American studios tend to have a higher amount of popularity. Take Universal Studios for example. This studio is so popular, that it has pretty much transcended movie-making, to the point that it even has a theme park based around it.

The other conclusion that i’ve reached is that for a movie to be successful, it has to at least have a translation to the English language. As we can clearly see, over 85% of movies have the option to be watched in English. To me, this is a key factor. This is due to the fact that it is the most popular language in the world, and so adapting a movie to this language could very well take a movie from being a local hit, to a worldwide phenomenom.

LS0tCnRpdGxlOiAiPHNwYW4gc3R5bGU9J2NvbG9yOiBicm93bjsnPkV2aWRlbmNpYSAyPC9zcGFuPiIKYXV0aG9yOiAiUGFibG8gU2FuY2hvIC0gQTAxNzIyMjM2IgpkYXRlOiAiMjAyNC0wNS0wMyIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUgCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIHRoZW1lOiBkYXJrCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKZWRpdG9yX3M6IAogIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogY29uc29sZQotLS0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChldmFsID0gVFJVRSkKYGBgCgojIDxzcGFuIHN0eWxlPSJjb2xvcjogZ3JlZW47Ij5JbnRyb2R1Y3Rpb248L3NwYW4+ICAKCkZvciBzdGFydGVycywgdGhpcyByZXBvcnQgd2FzIG1hZGUgdXNpbmcgdGhlIGNvZGluZyBsYW5ndWFnZSBrbm93biBhcyAqUiosIHdpdGggdGhlIG9iamVjdGl2ZSBvZiBmaW5kaW5nIG91dCB3aGljaCB2YXJpYWJsZXMgZGV0ZXJtaW5lIHRoZSBzdWNjZXNzIG9mIGEgbW92aWUuIFRvIHNlZWsgdG8gZmluZCB0aGlzIGFuc3dlcnMsIHdlIHVzZWQgdGhlIGNzdiBmaWxlIGtub3duIGFzICoqbW92aWVzX21ldGFkYXRhLmNzdioqLiBUaGlzIGNzdiBmaWxlIHdhcyBvYnRhaW5lZCBmcm9tIEthZ2dsZSAoaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9kYXRhc2V0cy9yb3VuYWtiYW5pay90aGUtbW92aWVzLWRhdGFzZXQvZGF0YSksIGFuZCBpdCBjb250YWlucyBhIHJlZ2lzdHJ5IG9mIG92ZXIgNDUsMDAwIG1vdmllcywgMjcwLDAwMCB1c2VycyBhbmQgb3ZlciAyNiBtaWxsaW9uIHJhdGluZ3MuIFRoaXMgaXMgaW1wb3J0YW50LCBzaW5jZSB3ZSBhcmUgbG9va2luZyB0byBmaW5kIGNvbmNyZXRlIGFuc3dlcnMgdG8gb3VyIHF1ZXN0aW9uLCBhbmQgc28gdXNpbmcgYSBiaWcgYW1vdW50IG9mIGRhdGEgd2lsbCBtYWtlIG91ciByZXN1bHRzIG1vcmUgYWNjdXJhdGUuIAoKIyA8c3BhbiBzdHlsZT0iY29sb3I6IGdyZWVuOyI+T2JqZWN0aXZlcyBhbmQgVmFyaWFibGVzPC9zcGFuPiAKCkFzIHByZXZpb3VzbHkgbWVudGlvbmVkLCB0aGUgbWFpbiBvYmplY3RpdmUgaXMgdG8gZGV0ZXJtaW5lIHdoYXQgbWFrZXMgKG9yIGRvZXNu4oCZdCBtYWtlKSBhIG1vdmllIHN1Y2Nlc3NmdWwuIFRvIGRvIHRoaXMsIHdlIGxvb2tlZCBhdCB0aGUgdmFyaWFibGVzIHdpdGhpbiB0aGlzIGRhdGFzZXQuIFRoZXNlIHZhcmlhYmxlcyBhcmUgdGhlIGZvbGxvd2luZzogYWR1bHQsIGJlbG9uZ3NfdG9fY29sbGVjdGlvbiwgYnVkZ2V0LCBnZW5yZXMJaG9tZXBhZ2UsIGlkLCBpbWRiX2lkLCBvcmlnaW5hbF9sYW5ndWFnZSwgb3JpZ2luYWxfdGl0bGUsIG92ZXJ2aWV3LCBwb3B1bGFyaXR5LCBwb3N0ZXJfcGF0aCwgcHJvZHVjdGlvbl9jb21wYW5pZXMsIHByb2R1Y3Rpb25fY291bnRyaWVzLCByZWxlYXNlX2RhdGUsIHJldmVudWUsIHJ1bnRpbWUsIHNwb2tlbl9sYW5ndWFnZXMsIHN0YXR1cywgdGFnbGluZSwgdGl0bGUJdmlkZW8sIHZvdGVfYXZlcmFnZSBhbmQgdm90ZV9jb3VudC4gVGhlc2UgdmFyaWFibGVzIHJhbmdlIGZyb20gZGVzY3JpcHRpb25zIHRvIG51bWVyaWNhbCB2YWx1ZXMsIHNvIHdlIGhhZCB0byBhc3NpZ24gdGhlbSBhIGRpZmZlcmVudCB2YWx1ZSBhbmQganVkZ2UgdGhlbSBkaWZmZXJlbnRseSBmcm9tIGVhY2ggb3RoZXIuIE9idmlvdXNseSwgdG8gZGV0ZXJtaW5lIHRoZSBzdWNjZXNzIG9mIGEgbW92aWUsIHdlIGRpZCBub3QgbmVjZXNzYXJpbHkgbmVlZCB0byB1dGlsaXplIGFsbCBvZiB0aGVzZSB2YXJpYWJsZXMsIGFuZCBzbyB0byBkbyB0aGlzLCBhIGNsZWFuaW5nIHByb2Nlc3MgaGFkIHRvIGJlIG1hZGUuCgojIDxzcGFuIHN0eWxlPSJjb2xvcjogZ3JlZW47Ij5DbGVhbmluZyBQcm9jZXNzPC9zcGFuPiAKCkZvciB0aGlzIGNsZWFuaW5nIHByb2Nlc3MsIHdlIGhhZCB0byBlbGFib3JhdGUgY29kZXMgd2l0aCB0aGUgb2JqZWN0aXZlIG9mIGZpbHRlcmluZyBvdXQgZGF0YSB0aGF0IGlzIGVpdGhlciBpbmNvcnJlY3QsIGludmFsaWQgb3Igc2ltcGx5IHVubmVjZXNzYXJ5IGZvciBvdXIgYW5hbHlzaXMuIFRvIGVuc3VyZSB0aGF0IG91ciBkYXRhIGlzIGFzIHdlbGwtYXJyYW5nZWQgYXMgcG9zc2libGUsIEkgYmVnYW4gYnkgb3JkZXJpbmcgdGhlIGNvbHVtbnMgYnkgaW1wb3J0YW5jZSwgaW4gdGhlIG1hbm5lciB0aGF0IEkgdGhvdWdodCB3b3VsZCBiZSBlYXNpZXN0IHRvIHVuZGVyc3RhbmQgZm9yIHRoZSByZWFkZXIuIEJlY2F1c2Ugb2YgdGhpcywgdGhlIGZpcnN0IDIgY29sdW1ucyBhcmUgdGhlIG5hbWUgb2YgdGhlIG1vdmllLCBhbmQgdGhlIGlkZW50aWZpY2F0aW9uIG51bWJlci4gQWZ0ZXIgdGhpcywgSSBjb250aW51ZWQgYnkgY2hlY2tpbmcgZm9yIE5BIHZhbHVlcy4gVGhpcyByZWZlcnMgdG8gdmFsdWVzIHRoYXQgd2VyZW7igJl0IHJlY29yZGVkIHByb3Blcmx5LCBhbmQgc28gdGhleSBtYWtlIHRoZSBhbmFseXNpcyBleHRyZW1lbHkgY29tcGxpY2F0ZWQuIEJlY2F1c2Ugb2YgdGhpcywgSSBkZWxldGVkIHRoZXNlIHZhbHVlcy4gTmV4dCwgSSBjaGVja2VkIGZvciBkdXBsaWNhdGUgcm93cywgYW5kIGxvZ2ljYWxseSBkZWxldGVkIHRoZSBjb3BpZXMsIHRvIG1ha2Ugc3VyZSB0aGF0IHRoZXJlIGlzIG9ubHkgb25lIHJvdyBmb3IgZWFjaCBtb3ZpZS4KVGhlbiBJIGNvbnRpbnVlZCBieSBjbGVhbmluZyB0aGUgY29sdW1ucyBpbmRpdmlkdWFsbHk6CkFkdWx0OiBBbGwgdmFsdWVzIHdlcmUgYXNzaWduZWQgdG8gZWl0aGVyIFRydWUgb3IgRmFsc2UuClJ1bnRpbWU6IERlbGV0ZWQgcm93cyB0aGF0IGhhZCBpbXBvc3NpYmxlIHJ1bnRpbWVzLiAoRXguIDAgb3IgMTk4NDkyMCBtaW51dGVzLikKVm90ZV9BdmVyYWdlOiBHYXZlIHRoZSBhdmVyYWdlIHJhdGluZyB0byByb3dzIHdpdGggYSB2YWx1ZSBvZiAwLgpDb2xsZWN0aW9uOiBEZWxldGVkIHRoZSBwYXJ0cyBvZiB0aGUgY29sdW1uIHRoYXQgSSBkZWVtZWQgdW5uZWNlc3NhcnkgKEV4LiBQYXJlbnRoZXNlcyBhbmQgQ29sbGVjdGlvbiBJRHMpCkdlbnJlcywgQ29tcGFuaWVzLCBDb3VudHJpZXMsIExhbmd1YWdlczogSSBzZXBhcmF0ZWQgdGhlIGRpZmZlcmVudCB2YWx1ZXMgYXNzaWduZWQgdG8gdGhlIG1vdmllIGludG8gZGlmZmVyZW50IGNvbHVtbnMsIGFzIHdlbGwgYXMgZ3JhcGhlZCB0aGUgdG9wIDIwIG9mIGVhY2ggY2F0ZWdvcnkuClBvc3Rlcl9QYXRoLCBUYWdsaW5lLCBWaWRlbzogSSBkZWxldGVkIHRoZXNlIGNvbHVtbnMgc2luY2UgSSBkZWVtZWQgdGhlbSB1bm5lY2Vzc2FyeS4KVGhlIHJlbWFpbmluZyBjb2x1bW5zIHdlcmUgbGVmdCB1bnRvdWNoZWQsIHNpbmNlIEkgY29uc2lkZXJlZCB0aGF0IHRoZXkgd2VyZSBib3RoIGNsZWFuLCBhbmQgcmVsZXZhbnQgdG8gdGhlIGFuYWx5c2lzIEkgd2FzIHRyeWluZyB0byBkby4KCmBgYHtyIGluY2x1ZGUgPSBGQUxTRX0KbW92aWVzIDwtIHJlYWQuY3N2KCIvVXNlcnMvcGFibG9zYW5jaG8vRGVza3RvcC9tb3ZpZXNfbWV0YWRhdGEuY3N2IikKYGBgCgpgYGB7ciBpbmNsdWRlID0gRkFMU0V9CmxpYnJhcnkoImRwbHlyIikKbGlicmFyeSh2aXNkYXQpCmxpYnJhcnkoZHBseXIpIApsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShkcGx5cikKbGlicmFyeShmdXp6eWpvaW4pCmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKCmBgYHtyIGluY2x1ZGUgPSBGQUxTRX0KIyBSZWFycmFuZ2UgY29sdW1ucyB0byBtYWtlIHRoZSBmaXJzdCAzIHRoZSBvbmVzIG5lZWRlZCB0byBpZGVudGlmeSB0aGUgbW92aWUKbW92aWVzIDwtIG1vdmllcyAlPiUKICBzZWxlY3QodGl0bGUsIGlkLCBpbWRiX2lkLCBldmVyeXRoaW5nKCkpCiAgCmhlYWQobW92aWVzKQpgYGAKCi8vLy8vLy8vLy8KYGBge3J9CiMgQ2hlY2tpbmcgZm9yIE5Bcwpjb2x1bW5zX3RvX2NoZWNrIDwtIGMoImJ1ZGdldCIsICJnZW5yZXMiLCAiaG9tZXBhZ2UiLCAiaWQiLCAiaW1kYl9pZCIsICJvcmlnaW5hbF9sYW5ndWFnZSIsIAogICAgICAgICAgICAgICAgICAgICAgIm9yaWdpbmFsX3RpdGxlIiwgIm92ZXJ2aWV3IiwgInBvcHVsYXJpdHkiLCAicG9zdGVyX3BhdGgiLCAKICAgICAgICAgICAgICAgICAgICAgICJwcm9kdWN0aW9uX2NvbXBhbmllcyIsICJwcm9kdWN0aW9uX2NvdW50cmllcyIsICJyZWxlYXNlX2RhdGUiLCAKICAgICAgICAgICAgICAgICAgICAgICJyZXZlbnVlIiwgInJ1bnRpbWUiLCAic3Bva2VuX2xhbmd1YWdlcyIsICJzdGF0dXMiLAogICAgICAgICAgICAgICAgICAgICAgInRpdGxlIiwgInZpZGVvIiwgInZvdGVfYXZlcmFnZSIsICJ2b3RlX2NvdW50IiwgImFkdWx0IikKCm1pc3Npbmdfcm93cyA8LSB3aGljaCghY29tcGxldGUuY2FzZXMobW92aWVzWywgY29sdW1uc190b19jaGVja10pKQoKbnVtX21pc3Npbmdfcm93cyA8LSBsZW5ndGgobWlzc2luZ19yb3dzKQoKcHJpbnQocGFzdGUoIk51bWJlciBvZiBtaXNzaW5nIHJvd3M6IiwgbnVtX21pc3Npbmdfcm93cykpCnByaW50KCJJbmRpY2VzIG9mIG1pc3Npbmcgcm93czoiKQpwcmludChtaXNzaW5nX3Jvd3MpCmBgYAoKYGBge3J9CiMgQ2xlYW5pbmcgTkFzCm1vdmllc19jbGVhbiA8LSBtb3ZpZXNbY29tcGxldGUuY2FzZXMobW92aWVzWywgY29sdW1uc190b19jaGVja10pLCBdCgpwcmludCgiRGltZW5zaW9ucyBvZiBjbGVhbmVkIGRhdGFmcmFtZToiKQpwcmludChkaW0obW92aWVzX2NsZWFuKSkKYGBgCgovLy8vLy8vLy8vCmBgYHtyIGluY2x1ZGUgPSBGQUxTRX0KCm1vdmllc19jbGVhbl91bmlxdWUgPC0gZGlzdGluY3QobW92aWVzX2NsZWFuLCBpZCwgLmtlZXBfYWxsID0gVFJVRSkKCnByaW50KHBhc3RlKCJOdW1iZXIgb2Ygcm93cyBiZWZvcmUgcmVtb3ZpbmcgZHVwbGljYXRlczoiLCBucm93KG1vdmllc19jbGVhbikpKQpwcmludChwYXN0ZSgiTnVtYmVyIG9mIHJvd3MgYWZ0ZXIgcmVtb3ZpbmcgZHVwbGljYXRlczoiLCBucm93KG1vdmllc19jbGVhbl91bmlxdWUpKSkKCm1vdmllc19jbGVhbiA8LSBtb3ZpZXNfY2xlYW5fdW5pcXVlCgpgYGAKCgovLy8vLy8vLy8KYGBge3IgaW5jbHVkZSA9IEZBTFNFfQojIENsZWFuaW5nIGFkdWx0IGNvbHVtbgp1bmlxdWVfYWR1bHQgPC0gdGFibGUobW92aWVzX2NsZWFuJGFkdWx0KQp1bmlxdWVfYWR1bHQKYGBgCgpgYGB7cn0KbW92aWVzX2NsZWFuJGFkdWx0IDwtIGlmZWxzZShtb3ZpZXNfY2xlYW4kYWR1bHQgIT0gIlRydWUiICYgbW92aWVzX2NsZWFuJGFkdWx0ICE9ICJGYWxzZSIsICJGYWxzZSIsIG1vdmllc19jbGVhbiRhZHVsdCkKYGBgCgovLy8vLy8vLy8vCmBgYHtyIGluY2x1ZGUgPSBGQUxTRX0KdG9wXzEwX3J1bnRpbWUgPC0gaGVhZChtb3ZpZXNfY2xlYW5bb3JkZXIobW92aWVzX2NsZWFuJHJ1bnRpbWUsIGRlY3JlYXNpbmcgPSBUUlVFKSwgXSwgMTApCgoKYm90dG9tXzEwX3J1bnRpbWUgPC0gaGVhZChtb3ZpZXNfY2xlYW5bb3JkZXIobW92aWVzX2NsZWFuJHJ1bnRpbWUpLCBdLCAxMCkKCnByaW50KCJIaWdoZXN0IFJ1bnRpbWVzOiIpCnByaW50KHRvcF8xMF9ydW50aW1lKQoKcHJpbnQoIkxvd2VzdCBSdW50aW1lczoiKQpwcmludChib3R0b21fMTBfcnVudGltZSkKYGBgCmBgYHtyIGluY2x1ZGUgPSBGQUxTRX0KI0NsZWFuaW5nIHJ1bnRpbWUgY29sdW1uCmF2ZXJhZ2VfcnVudGltZSA8LSBtZWFuKG1vdmllc19jbGVhbiRydW50aW1lW21vdmllc19jbGVhbiRydW50aW1lICE9IDAgJiAhaXMubmEobW92aWVzX2NsZWFuJHJ1bnRpbWUpXSwgbmEucm0gPSBUUlVFKQoKbW92aWVzX2NsZWFuJHJ1bnRpbWUgPC0gaWZlbHNlKG1vdmllc19jbGVhbiRydW50aW1lID09IDAgfCBpcy5uYShtb3ZpZXNfY2xlYW4kcnVudGltZSksIGF2ZXJhZ2VfcnVudGltZSwgbW92aWVzX2NsZWFuJHJ1bnRpbWUpCgpwcmludChwYXN0ZSgiVmFsdWVzIEJlZm9yZToiLCBhdmVyYWdlX3J1bnRpbWUpKQoKCnJlcGxhY2VkX2NvdW50IDwtIHN1bShtb3ZpZXNfY2xlYW4kcnVudGltZSA9PSBhdmVyYWdlX3J1bnRpbWUpCnByaW50KHBhc3RlKCJWYWx1ZXMgUmVwbGFjZWQ6IiwgcmVwbGFjZWRfY291bnQpKQpgYGAKLy8vLy8vLy8vLwpgYGB7ciBpbmNsdWRlID0gRkFMU0V9CiMgQ2xlYW5pbmcgdm90ZSBhdmVyYWdlIGNvbHVtbgphdmVyYWdlX3ZvdGVfYXZlcmFnZSA8LSBtZWFuKG1vdmllc19jbGVhbiR2b3RlX2F2ZXJhZ2VbbW92aWVzX2NsZWFuJHZvdGVfYXZlcmFnZSAhPSAwICYgIWlzLm5hKG1vdmllc19jbGVhbiR2b3RlX2F2ZXJhZ2UpXSwgbmEucm0gPSBUUlVFKQoKCm1vdmllc19jbGVhbiR2b3RlX2F2ZXJhZ2UgPC0gaWZlbHNlKG1vdmllc19jbGVhbiR2b3RlX2F2ZXJhZ2UgPT0gMCB8IGlzLm5hKG1vdmllc19jbGVhbiR2b3RlX2F2ZXJhZ2UpLCBhdmVyYWdlX3ZvdGVfYXZlcmFnZSwgbW92aWVzX2NsZWFuJHZvdGVfYXZlcmFnZSkKCgpwcmludChwYXN0ZSgiVmFsdWVzIEJlZm9yZToiLCBhdmVyYWdlX3ZvdGVfYXZlcmFnZSkpCgoKcmVwbGFjZWRfY291bnQgPC0gc3VtKG1vdmllc19jbGVhbiR2b3RlX2F2ZXJhZ2UgPT0gYXZlcmFnZV92b3RlX2F2ZXJhZ2UpCnByaW50KHBhc3RlKCJWYWx1ZXMgUmVwbGFjZWQ6IiwgcmVwbGFjZWRfY291bnQpKQpgYGAKCgovLy8vLy8vLy8vCmBgYHtyIGluY2x1ZGUgPSBGQUxTRX0KIyBDbGVhbmluZyBjb2xsZWN0aW9uIGNvbHVtbgpjb2xsZWN0aW9uX25hbWVzIDwtIHN0cl9leHRyYWN0KG1vdmllc19jbGVhbiRiZWxvbmdzX3RvX2NvbGxlY3Rpb24sICInbmFtZSc6XFxzKycoW1s6YWxudW06XVxcc10rKSciKQoKY29sbGVjdGlvbl9uYW1lcyA8LSBjb2xsZWN0aW9uX25hbWVzWyFpcy5uYShjb2xsZWN0aW9uX25hbWVzKV0KCmNvbGxlY3Rpb25fY291bnRzIDwtIHRhYmxlKGNvbGxlY3Rpb25fbmFtZXMpCgpjb2xsZWN0aW9uX2NvdW50cyA8LSBzb3J0KGNvbGxlY3Rpb25fY291bnRzLCBkZWNyZWFzaW5nID0gVFJVRSkKCnRvcF8xMF9jb2xsZWN0aW9ucyA8LSBoZWFkKGNvbGxlY3Rpb25fY291bnRzLCAxMCkKcHJpbnQodG9wXzEwX2NvbGxlY3Rpb25zKQpgYGAKCi8vLy8vLy8vLy8KCmBgYHtyIGluY2x1ZGUgPSBGQUxTRX0KIyBOZXcgR2VucmVzCm1vdmllc19jbGVhbiRnZW5yZXNfc3RyaW5nIDwtIGFzLmNoYXJhY3Rlcihtb3ZpZXNfY2xlYW4kZ2VucmVzKQoKbGlicmFyeSgic3RyaW5nciIpCm5ld19nZW5yZXMgPC0gc3RyX3NwbGl0X2ZpeGVkKG1vdmllc19jbGVhbiRnZW5yZXNfc3RyaW5nLCAiOiIsIG4gPSBJbmYpCgpuZXdfZ2VucmVzIDwtIG5ld19nZW5yZXNbLDE6N10KCm5ld19nZW5yZXMgPC0gbmV3X2dlbnJlc1ssIGMoMyw1LDcpXQoKc3VtbWFyeShuZXdfZ2VucmVzKQoKbmV3X2dlbnJlcyA8LSBhcy5kYXRhLmZyYW1lKG5ld19nZW5yZXMpCgojaHR0cHM6Ly9zdGF0LmV0aHouY2gvUi1tYW51YWwvUi1kZXZlbC9saWJyYXJ5L2Jhc2UvaHRtbC9yZWdleC5odG1sCgpuZXdfZ2VucmVzIDwtIG5ld19nZW5yZXMgJT4lIAogIG11dGF0ZShnZW5yZTEgPSBzdHJfcmVwbGFjZV9hbGwobmV3X2dlbnJlcyRWMSwgIltbOnB1bmN0Ol1dIiwgIiAiKSkKCm5ld19nZW5yZXMgPC0gbmV3X2dlbnJlcyAlPiUgCiAgbXV0YXRlKGdlbnJlMiA9IHN0cl9yZXBsYWNlX2FsbChuZXdfZ2VucmVzJFYyLCAiW1s6cHVuY3Q6XV0iLCAiICIpKQoKbmV3X2dlbnJlcyA8LSBuZXdfZ2VucmVzICU+JSAKICBtdXRhdGUoZ2VucmUzID0gc3RyX3JlcGxhY2VfYWxsKG5ld19nZW5yZXMkVjMsICJbWzpwdW5jdDpdXSIsICIgIikpCgoKbmV3X2dlbnJlcyRnZW5yZTEgPC0gc3RyX3JlbW92ZShuZXdfZ2VucmVzJGdlbnJlMSwiaWQiKQpuZXdfZ2VucmVzJGdlbnJlMiA8LSBzdHJfcmVtb3ZlKG5ld19nZW5yZXMkZ2VucmUyLCJpZCIpCm5ld19nZW5yZXMkZ2VucmUzIDwtIHN0cl9yZW1vdmUobmV3X2dlbnJlcyRnZW5yZTMsImlkIikKCmdlbnJlc19jbGVhbiA8LSBuZXdfZ2VucmVzWyw0OjZdCgpzdW1tYXJ5KGdlbnJlc19jbGVhbikKYGBgCgoKYGBge3IgaW5jbHVkZSA9IEZBTFNFfQpnZW5yZXNfY2xlYW4kZ2VucmUxIDwtIHN0cl90cmltKGdlbnJlc19jbGVhbiRnZW5yZTEsICJib3RoIikKZ2VucmVzX2NsZWFuJGdlbnJlMiA8LSBzdHJfdHJpbShnZW5yZXNfY2xlYW4kZ2VucmUyLCAiYm90aCIpCmdlbnJlc19jbGVhbiRnZW5yZTMgPC0gc3RyX3RyaW0oZ2VucmVzX2NsZWFuJGdlbnJlMywgImJvdGgiKQoKZ2VucmVzX2NsZWFuJGdlbnJlMSA8LSBhcy5mYWN0b3IoZ2VucmVzX2NsZWFuJGdlbnJlMSkKZ2VucmVzX2NsZWFuJGdlbnJlMiA8LSBhcy5mYWN0b3IoZ2VucmVzX2NsZWFuJGdlbnJlMikKZ2VucmVzX2NsZWFuJGdlbnJlMyA8LSBhcy5mYWN0b3IoZ2VucmVzX2NsZWFuJGdlbnJlMykKYGBgCgojIDxzcGFuIHN0eWxlPSJjb2xvcjogZ3JlZW47Ij5TdGF0aXN0aWNhbCBhbmQgQW5hbHl0aWNhbCBUZWNobmlxdWVzPC9zcGFuPiAKCkFmdGVyIGNvbmNsdWRpbmcgdGhlIGNsZWFuaW5nIHByb2Nlc3MsIEkgYmVnYW4gdG8gZ3JhcGggdGhlIGRhdGEgaW50byBjaGFydHMgYW5kIHBsb3RzLiBUaGUgZmlyc3QgNCBncmFwaHMgSSBtYWRlIHdlcmUgdGhlIG9uZXMgSSBtZW50aW9uZWQgcHJldmlvdXNseS4gVGhleSBjb250YWluIHRoZSAyMCBtb3N0IGNvbW1vbiBHZW5yZXMsIENvbXBhbmllcywgQ291bnRyaWVzIGFuZCBMYW5ndWFnZXMuIFRoZXNlIGdyYXBocyBhcmUgZXh0cmVtZWx5IHNpbXBsZSwgYnV0IEkgY29uc2lkZXJlZCB0aGVtIHRvIGJlIGVzc2VudGlhbCB0byB0aGUgYW5hbHlzaXMsIHNpbmNlIHRoZXkgcmVwcmVzZW50IHRoZSBtYWpvcml0eSBvZiB0aGUgcG9wdWxhdGlvbi4gVmFsdWVzIHRoYXQgYXJlIHNtYWxsZXIgdGVuZCB0byBiZSBtdWNoIGxlc3Mgc2lnbmlmaWNhbnQsIGFuZCBzbyB0aGUgbW9zdCBwb3B1bGFyIHZhbHVlcyBpbiB0aGVzZSBjb2x1bW5zIGFyZSBvZiB0aGUgdXRtb3N0IGltcG9ydGFuY2UuIFRoZXNlIGFyZSB0aGUgZ3JhcGhzIEkgb2J0YWluZWQ6CgpgYGB7ciBpbmNsdWRlID0gRkFMU0V9CiMgTmV3IGNvbXBhbmllcyAoMjAgbW9zdCBwb3B1bGFyIGNvbXBhbmllcyBncmFwaCkKbmV3X2NvbXBhbmllcyA8LSBzdHJfc3BsaXRfZml4ZWQobW92aWVzX2NsZWFuJHByb2R1Y3Rpb25fY29tcGFuaWVzLCAiXFx9LCIsIG4gPSBJbmYpCgoKbmV3X2NvbXBhbmllcyA8LSBuZXdfY29tcGFuaWVzWywgMToyMV0KCm5ld19jb21wYW5pZXMgPC0gYXMuZGF0YS5mcmFtZShuZXdfY29tcGFuaWVzKQpuZXdfY29tcGFuaWVzIDwtIG5ld19jb21wYW5pZXMgJT4lIAogIG11dGF0ZShjb21wYW55MSA9IHN0cl9leHRyYWN0KFYxLCAiJ25hbWUnOlxccysnKFtbOmFsbnVtOl1cXHNdKyknIiksCiAgICAgICAgIGNvbXBhbnkyID0gc3RyX2V4dHJhY3QoVjIsICInbmFtZSc6XFxzKycoW1s6YWxudW06XVxcc10rKSciKSwKICAgICAgICAgY29tcGFueTMgPSBzdHJfZXh0cmFjdChWMywgIiduYW1lJzpcXHMrJyhbWzphbG51bTpdXFxzXSspJyIpLAogICAgICAgICBjb21wYW55NCA9IHN0cl9leHRyYWN0KFY0LCAiJ25hbWUnOlxccysnKFtbOmFsbnVtOl1cXHNdKyknIiksCiAgICAgICAgIGNvbXBhbnk1ID0gc3RyX2V4dHJhY3QoVjUsICInbmFtZSc6XFxzKycoW1s6YWxudW06XVxcc10rKSciKSwKICAgICAgICAgY29tcGFueTYgPSBzdHJfZXh0cmFjdChWNiwgIiduYW1lJzpcXHMrJyhbWzphbG51bTpdXFxzXSspJyIpLAogICAgICAgICBjb21wYW55NyA9IHN0cl9leHRyYWN0KFY3LCAiJ25hbWUnOlxccysnKFtbOmFsbnVtOl1cXHNdKyknIiksCiAgICAgICAgIGNvbXBhbnk4ID0gc3RyX2V4dHJhY3QoVjgsICInbmFtZSc6XFxzKycoW1s6YWxudW06XVxcc10rKSciKSwKICAgICAgICAgY29tcGFueTkgPSBzdHJfZXh0cmFjdChWOSwgIiduYW1lJzpcXHMrJyhbWzphbG51bTpdXFxzXSspJyIpLAogICAgICAgICBjb21wYW55MTAgPSBzdHJfZXh0cmFjdChWMTAsICInbmFtZSc6XFxzKycoW1s6YWxudW06XVxcc10rKSciKSwKICAgICAgICAgY29tcGFueTExID0gc3RyX2V4dHJhY3QoVjExLCAiJ25hbWUnOlxccysnKFtbOmFsbnVtOl1cXHNdKyknIiksCiAgICAgICAgIGNvbXBhbnkxMiA9IHN0cl9leHRyYWN0KFYxMiwgIiduYW1lJzpcXHMrJyhbWzphbG51bTpdXFxzXSspJyIpLAogICAgICAgICBjb21wYW55MTMgPSBzdHJfZXh0cmFjdChWMTMsICInbmFtZSc6XFxzKycoW1s6YWxudW06XVxcc10rKSciKSwKICAgICAgICAgY29tcGFueTE0ID0gc3RyX2V4dHJhY3QoVjE0LCAiJ25hbWUnOlxccysnKFtbOmFsbnVtOl1cXHNdKyknIiksCiAgICAgICAgIGNvbXBhbnkxNSA9IHN0cl9leHRyYWN0KFYxNSwgIiduYW1lJzpcXHMrJyhbWzphbG51bTpdXFxzXSspJyIpLAogICAgICAgICBjb21wYW55MTYgPSBzdHJfZXh0cmFjdChWMTYsICInbmFtZSc6XFxzKycoW1s6YWxudW06XVxcc10rKSciKSwKICAgICAgICAgY29tcGFueTE3ID0gc3RyX2V4dHJhY3QoVjE3LCAiJ25hbWUnOlxccysnKFtbOmFsbnVtOl1cXHNdKyknIiksCiAgICAgICAgIGNvbXBhbnkxOCA9IHN0cl9leHRyYWN0KFYxOCwgIiduYW1lJzpcXHMrJyhbWzphbG51bTpdXFxzXSspJyIpLAogICAgICAgICBjb21wYW55MTkgPSBzdHJfZXh0cmFjdChWMTksICInbmFtZSc6XFxzKycoW1s6YWxudW06XVxcc10rKSciKSwKICAgICAgICAgY29tcGFueTIwID0gc3RyX2V4dHJhY3QoVjIwLCAiJ25hbWUnOlxccysnKFtbOmFsbnVtOl1cXHNdKyknIiksCiAgICAgICAgIGNvbXBhbnkyMSA9IHN0cl9leHRyYWN0KFYyMSwgIiduYW1lJzpcXHMrJyhbWzphbG51bTpdXFxzXSspJyIpKQoKCm5ld19jb21wYW5pZXMkY29tcGFueTEgPC0gc3RyX3JlbW92ZShuZXdfY29tcGFuaWVzJGNvbXBhbnkxLCAiJ25hbWUnOlxccysiKQpuZXdfY29tcGFuaWVzJGNvbXBhbnkyIDwtIHN0cl9yZW1vdmUobmV3X2NvbXBhbmllcyRjb21wYW55MiwgIiduYW1lJzpcXHMrIikKbmV3X2NvbXBhbmllcyRjb21wYW55MyA8LSBzdHJfcmVtb3ZlKG5ld19jb21wYW5pZXMkY29tcGFueTMsICInbmFtZSc6XFxzKyIpCm5ld19jb21wYW5pZXMkY29tcGFueTQgPC0gc3RyX3JlbW92ZShuZXdfY29tcGFuaWVzJGNvbXBhbnk0LCAiJ25hbWUnOlxccysiKQpuZXdfY29tcGFuaWVzJGNvbXBhbnk1IDwtIHN0cl9yZW1vdmUobmV3X2NvbXBhbmllcyRjb21wYW55NSwgIiduYW1lJzpcXHMrIikKbmV3X2NvbXBhbmllcyRjb21wYW55NiA8LSBzdHJfcmVtb3ZlKG5ld19jb21wYW5pZXMkY29tcGFueTYsICInbmFtZSc6XFxzKyIpCm5ld19jb21wYW5pZXMkY29tcGFueTcgPC0gc3RyX3JlbW92ZShuZXdfY29tcGFuaWVzJGNvbXBhbnk3LCAiJ25hbWUnOlxccysiKQpuZXdfY29tcGFuaWVzJGNvbXBhbnk4IDwtIHN0cl9yZW1vdmUobmV3X2NvbXBhbmllcyRjb21wYW55OCwgIiduYW1lJzpcXHMrIikKbmV3X2NvbXBhbmllcyRjb21wYW55OSA8LSBzdHJfcmVtb3ZlKG5ld19jb21wYW5pZXMkY29tcGFueTksICInbmFtZSc6XFxzKyIpCm5ld19jb21wYW5pZXMkY29tcGFueTEwIDwtIHN0cl9yZW1vdmUobmV3X2NvbXBhbmllcyRjb21wYW55MTAsICInbmFtZSc6XFxzKyIpCm5ld19jb21wYW5pZXMkY29tcGFueTExIDwtIHN0cl9yZW1vdmUobmV3X2NvbXBhbmllcyRjb21wYW55MTEsICInbmFtZSc6XFxzKyIpCm5ld19jb21wYW5pZXMkY29tcGFueTEyIDwtIHN0cl9yZW1vdmUobmV3X2NvbXBhbmllcyRjb21wYW55MTIsICInbmFtZSc6XFxzKyIpCm5ld19jb21wYW5pZXMkY29tcGFueTEzIDwtIHN0cl9yZW1vdmUobmV3X2NvbXBhbmllcyRjb21wYW55MTMsICInbmFtZSc6XFxzKyIpCm5ld19jb21wYW5pZXMkY29tcGFueTE0IDwtIHN0cl9yZW1vdmUobmV3X2NvbXBhbmllcyRjb21wYW55MTQsICInbmFtZSc6XFxzKyIpCm5ld19jb21wYW5pZXMkY29tcGFueTE1IDwtIHN0cl9yZW1vdmUobmV3X2NvbXBhbmllcyRjb21wYW55MTUsICInbmFtZSc6XFxzKyIpCm5ld19jb21wYW5pZXMkY29tcGFueTE2IDwtIHN0cl9yZW1vdmUobmV3X2NvbXBhbmllcyRjb21wYW55MTYsICInbmFtZSc6XFxzKyIpCm5ld19jb21wYW5pZXMkY29tcGFueTE3IDwtIHN0cl9yZW1vdmUobmV3X2NvbXBhbmllcyRjb21wYW55MTcsICInbmFtZSc6XFxzKyIpCm5ld19jb21wYW5pZXMkY29tcGFueTE4IDwtIHN0cl9yZW1vdmUobmV3X2NvbXBhbmllcyRjb21wYW55MTgsICInbmFtZSc6XFxzKyIpCm5ld19jb21wYW5pZXMkY29tcGFueTE5IDwtIHN0cl9yZW1vdmUobmV3X2NvbXBhbmllcyRjb21wYW55MTksICInbmFtZSc6XFxzKyIpCm5ld19jb21wYW5pZXMkY29tcGFueTIwIDwtIHN0cl9yZW1vdmUobmV3X2NvbXBhbmllcyRjb21wYW55MjAsICInbmFtZSc6XFxzKyIpCm5ld19jb21wYW5pZXMkY29tcGFueTIxIDwtIHN0cl9yZW1vdmUobmV3X2NvbXBhbmllcyRjb21wYW55MjEsICInbmFtZSc6XFxzKyIpCgoKYWxsX2NvbXBhbmllcyA8LSBjKG5ld19jb21wYW5pZXMkY29tcGFueTEsIG5ld19jb21wYW5pZXMkY29tcGFueTIsIG5ld19jb21wYW5pZXMkY29tcGFueTMsIG5ld19jb21wYW5pZXMkY29tcGFueTQsIG5ld19jb21wYW5pZXMkY29tcGFueTUsIG5ld19jb21wYW5pZXMkY29tcGFueTYsIG5ld19jb21wYW5pZXMkY29tcGFueTcsIG5ld19jb21wYW5pZXMkY29tcGFueTgsIG5ld19jb21wYW5pZXMkY29tcGFueTksIG5ld19jb21wYW5pZXMkY29tcGFueTEwLCBuZXdfY29tcGFuaWVzJGNvbXBhbnkxMSwgbmV3X2NvbXBhbmllcyRjb21wYW55MTIsIG5ld19jb21wYW5pZXMkY29tcGFueTEzLCBuZXdfY29tcGFuaWVzJGNvbXBhbnkxNCwgbmV3X2NvbXBhbmllcyRjb21wYW55MTUsIG5ld19jb21wYW5pZXMkY29tcGFueTE2LCBuZXdfY29tcGFuaWVzJGNvbXBhbnkxNywgbmV3X2NvbXBhbmllcyRjb21wYW55MTgsIG5ld19jb21wYW5pZXMkY29tcGFueTE5LCBuZXdfY29tcGFuaWVzJGNvbXBhbnkyMCwgbmV3X2NvbXBhbmllcyRjb21wYW55MjEpCgoKY29tcGFueV9jb3VudHMgPC0gdGFibGUoYWxsX2NvbXBhbmllcykKCgpjb21wYW55X2NvdW50cyA8LSBzb3J0KGNvbXBhbnlfY291bnRzLCBkZWNyZWFzaW5nID0gVFJVRSkKCgp0b3BfMjBfc3R1ZGlvcyA8LSBoZWFkKGNvbXBhbnlfY291bnRzLCAyMCkKCnByaW50KCJDb3VudHMgb2YgRWFjaCBTdHVkaW86IikKcHJpbnQodG9wXzIwX3N0dWRpb3MpCmBgYAoKYGBge3J9CmJhcnBsb3QodG9wXzIwX3N0dWRpb3MsIG1haW4gPSAiVG9wIDIwIE1vc3QgQ29tbW9uIFN0dWRpb3MiLCB4bGFiID0gIlN0dWRpb3MiLCB5bGFiID0gIkNvdW50IiwgbGFzID0gMiwgY29sID0gImZvcmVzdGdyZWVuIikKYGBgCmBgYHtyfQojIE5ldyBjb3VudHJpZXMgKFRvcCAyMCBjb3VudHJpZXMgZ3JhcGgpCmNvdW50cnlfY291bnRzIDwtIHRhYmxlKG1vdmllc19jbGVhbiRwcm9kdWN0aW9uX2NvdW50cmllcykKCgpuZXdfY291bnRyaWVzIDwtIHN0cl9zcGxpdF9maXhlZChtb3ZpZXNfY2xlYW4kcHJvZHVjdGlvbl9jb3VudHJpZXMsICJcXH0sIiwgbiA9IEluZikKCgpuZXdfY291bnRyaWVzIDwtIG5ld19jb3VudHJpZXNbLCAxOjddCgoKbmV3X2NvdW50cmllcyA8LSBhcy5kYXRhLmZyYW1lKG5ld19jb3VudHJpZXMpCm5ld19jb3VudHJpZXMgPC0gbmV3X2NvdW50cmllcyAlPiUgCiAgbXV0YXRlKGNvdW50cnkxID0gc3RyX2V4dHJhY3QoVjEsICInbmFtZSc6XFxzKycoW1s6YWxudW06XVxcc10rKSciKSwKICAgICAgICAgY291bnRyeTIgPSBzdHJfZXh0cmFjdChWMiwgIiduYW1lJzpcXHMrJyhbWzphbG51bTpdXFxzXSspJyIpLAogICAgICAgICBjb3VudHJ5MyA9IHN0cl9leHRyYWN0KFYzLCAiJ25hbWUnOlxccysnKFtbOmFsbnVtOl1cXHNdKyknIiksCiAgICAgICAgIGNvdW50cnk0ID0gc3RyX2V4dHJhY3QoVjQsICInbmFtZSc6XFxzKycoW1s6YWxudW06XVxcc10rKSciKSwKICAgICAgICAgY291bnRyeTUgPSBzdHJfZXh0cmFjdChWNSwgIiduYW1lJzpcXHMrJyhbWzphbG51bTpdXFxzXSspJyIpLAogICAgICAgICBjb3VudHJ5NiA9IHN0cl9leHRyYWN0KFY2LCAiJ25hbWUnOlxccysnKFtbOmFsbnVtOl1cXHNdKyknIiksCiAgICAgICAgIGNvdW50cnk3ID0gc3RyX2V4dHJhY3QoVjcsICInbmFtZSc6XFxzKycoW1s6YWxudW06XVxcc10rKSciKSkKCgpuZXdfY291bnRyaWVzJGNvdW50cnkxIDwtIHN0cl9yZW1vdmUobmV3X2NvdW50cmllcyRjb3VudHJ5MSwgIiduYW1lJzpcXHMrIikKbmV3X2NvdW50cmllcyRjb3VudHJ5MiA8LSBzdHJfcmVtb3ZlKG5ld19jb3VudHJpZXMkY291bnRyeTIsICInbmFtZSc6XFxzKyIpCm5ld19jb3VudHJpZXMkY291bnRyeTMgPC0gc3RyX3JlbW92ZShuZXdfY291bnRyaWVzJGNvdW50cnkzLCAiJ25hbWUnOlxccysiKQpuZXdfY291bnRyaWVzJGNvdW50cnk0IDwtIHN0cl9yZW1vdmUobmV3X2NvdW50cmllcyRjb3VudHJ5NCwgIiduYW1lJzpcXHMrIikKbmV3X2NvdW50cmllcyRjb3VudHJ5NSA8LSBzdHJfcmVtb3ZlKG5ld19jb3VudHJpZXMkY291bnRyeTUsICInbmFtZSc6XFxzKyIpCm5ld19jb3VudHJpZXMkY291bnRyeTYgPC0gc3RyX3JlbW92ZShuZXdfY291bnRyaWVzJGNvdW50cnk2LCAiJ25hbWUnOlxccysiKQpuZXdfY291bnRyaWVzJGNvdW50cnk3IDwtIHN0cl9yZW1vdmUobmV3X2NvdW50cmllcyRjb3VudHJ5NywgIiduYW1lJzpcXHMrIikKCmFsbF9jb3VudHJpZXMgPC0gYyhuZXdfY291bnRyaWVzJGNvdW50cnkxLCBuZXdfY291bnRyaWVzJGNvdW50cnkyLCBuZXdfY291bnRyaWVzJGNvdW50cnkzLAogICAgICAgICAgICAgICAgICAgbmV3X2NvdW50cmllcyRjb3VudHJ5NCwgbmV3X2NvdW50cmllcyRjb3VudHJ5NSwgbmV3X2NvdW50cmllcyRjb3VudHJ5NiwKICAgICAgICAgICAgICAgICAgIG5ld19jb3VudHJpZXMkY291bnRyeTcpCgoKY291bnRyeV9jb3VudHMgPC0gdGFibGUoYWxsX2NvdW50cmllcykKCgpjb3VudHJ5X2NvdW50cyA8LSBzb3J0KGNvdW50cnlfY291bnRzLCBkZWNyZWFzaW5nID0gVFJVRSkKCgp0b3BfMjBfY291bnRyaWVzIDwtIGhlYWQoY291bnRyeV9jb3VudHMsIDIwKQoKcHJpbnQoIkNvdW50cyBvZiBFYWNoIENvdW50cnk6IikKcHJpbnQodG9wXzIwX2NvdW50cmllcykKCgpiYXJwbG90KHRvcF8yMF9jb3VudHJpZXMsIG1haW4gPSAiVG9wIDIwIE1vc3QgQ29tbW9uIENvdW50cmllcyIsIHhsYWIgPSAiQ291bnRyaWVzIiwgeWxhYiA9ICJDb3VudCIsIGxhcyA9IDIsIGNvbCA9ICJyZWQiKQpgYGAKYGBge3J9CiMgTmV3IGxhbmd1YWdlcyAoVG9wIDIwIGxhbmd1YWdlcyBncmFwaCkKbmV3X2xhbmd1YWdlcyA8LSBzdHJfc3BsaXRfZml4ZWQobW92aWVzX2NsZWFuJHNwb2tlbl9sYW5ndWFnZXMsICJcXH0sIiwgbiA9IEluZikKCm5ld19sYW5ndWFnZXMgPC0gbmV3X2xhbmd1YWdlc1ssIDE6N10KCm5ld19sYW5ndWFnZXMgPC0gYXMuZGF0YS5mcmFtZShuZXdfbGFuZ3VhZ2VzKQpuZXdfbGFuZ3VhZ2VzIDwtIG5ld19sYW5ndWFnZXMgJT4lIAogIG11dGF0ZShsYW5ndWFnZTEgPSBzdHJfZXh0cmFjdChWMSwgIiduYW1lJzpcXHMrJyhbWzphbG51bTpdXFxzXSspJyIpLAogICAgICAgICBsYW5ndWFnZTIgPSBzdHJfZXh0cmFjdChWMiwgIiduYW1lJzpcXHMrJyhbWzphbG51bTpdXFxzXSspJyIpLAogICAgICAgICBsYW5ndWFnZTMgPSBzdHJfZXh0cmFjdChWMywgIiduYW1lJzpcXHMrJyhbWzphbG51bTpdXFxzXSspJyIpLAogICAgICAgICBsYW5ndWFnZTQgPSBzdHJfZXh0cmFjdChWNCwgIiduYW1lJzpcXHMrJyhbWzphbG51bTpdXFxzXSspJyIpLAogICAgICAgICBsYW5ndWFnZTUgPSBzdHJfZXh0cmFjdChWNSwgIiduYW1lJzpcXHMrJyhbWzphbG51bTpdXFxzXSspJyIpLAogICAgICAgICBsYW5ndWFnZTYgPSBzdHJfZXh0cmFjdChWNiwgIiduYW1lJzpcXHMrJyhbWzphbG51bTpdXFxzXSspJyIpLAogICAgICAgICBsYW5ndWFnZTcgPSBzdHJfZXh0cmFjdChWNywgIiduYW1lJzpcXHMrJyhbWzphbG51bTpdXFxzXSspJyIpKQoKbmV3X2xhbmd1YWdlcyRsYW5ndWFnZTEgPC0gc3RyX3JlbW92ZShuZXdfbGFuZ3VhZ2VzJGxhbmd1YWdlMSwgIiduYW1lJzpcXHMrIikKbmV3X2xhbmd1YWdlcyRsYW5ndWFnZTIgPC0gc3RyX3JlbW92ZShuZXdfbGFuZ3VhZ2VzJGxhbmd1YWdlMiwgIiduYW1lJzpcXHMrIikKbmV3X2xhbmd1YWdlcyRsYW5ndWFnZTMgPC0gc3RyX3JlbW92ZShuZXdfbGFuZ3VhZ2VzJGxhbmd1YWdlMywgIiduYW1lJzpcXHMrIikKbmV3X2xhbmd1YWdlcyRsYW5ndWFnZTQgPC0gc3RyX3JlbW92ZShuZXdfbGFuZ3VhZ2VzJGxhbmd1YWdlNCwgIiduYW1lJzpcXHMrIikKbmV3X2xhbmd1YWdlcyRsYW5ndWFnZTUgPC0gc3RyX3JlbW92ZShuZXdfbGFuZ3VhZ2VzJGxhbmd1YWdlNSwgIiduYW1lJzpcXHMrIikKbmV3X2xhbmd1YWdlcyRsYW5ndWFnZTYgPC0gc3RyX3JlbW92ZShuZXdfbGFuZ3VhZ2VzJGxhbmd1YWdlNiwgIiduYW1lJzpcXHMrIikKbmV3X2xhbmd1YWdlcyRsYW5ndWFnZTcgPC0gc3RyX3JlbW92ZShuZXdfbGFuZ3VhZ2VzJGxhbmd1YWdlNywgIiduYW1lJzpcXHMrIikKCmFsbF9sYW5ndWFnZXMgPC0gYyhuZXdfbGFuZ3VhZ2VzJGxhbmd1YWdlMSwgbmV3X2xhbmd1YWdlcyRsYW5ndWFnZTIsIG5ld19sYW5ndWFnZXMkbGFuZ3VhZ2UzLAogICAgICAgICAgICAgICAgICAgbmV3X2xhbmd1YWdlcyRsYW5ndWFnZTQsIG5ld19sYW5ndWFnZXMkbGFuZ3VhZ2U1LCBuZXdfbGFuZ3VhZ2VzJGxhbmd1YWdlNiwKICAgICAgICAgICAgICAgICAgIG5ld19sYW5ndWFnZXMkbGFuZ3VhZ2U3KQoKbGFuZ3VhZ2VfY291bnRzIDwtIHRhYmxlKGFsbF9sYW5ndWFnZXMpCgoKbGFuZ3VhZ2VfY291bnRzIDwtIHNvcnQobGFuZ3VhZ2VfY291bnRzLCBkZWNyZWFzaW5nID0gVFJVRSkKCgp0b3BfMjBfbGFuZ3VhZ2VzIDwtIGhlYWQobGFuZ3VhZ2VfY291bnRzLCAyMCkKCnByaW50KCJDb3VudHMgb2YgRWFjaCBMYW5ndWFnZToiKQpwcmludCh0b3BfMjBfbGFuZ3VhZ2VzKQoKCmJhcnBsb3QodG9wXzIwX2xhbmd1YWdlcywgbWFpbiA9ICJUb3AgMjAgTW9zdCBDb21tb24gU3Bva2VuIExhbmd1YWdlcyIsIHhsYWIgPSAiTGFuZ3VhZ2VzIiwgeWxhYiA9ICJDb3VudCIsIGxhcyA9IDIsIGNvbCA9ICJza3libHVlIikKYGBgCgpOZXh0LCBJIG1hZGUgYSB0YWJsZSB0aGF0IGdpdmVzIHlvdSB0aGUgbmFtZSBvZiB0aGUgZGlmZmVyZW50IGNvdW50cmllcyBhbmQgb2J0YWlucyBib3RoIHRoZSBhdmVyYWdlIHJldmVudWUgYW5kIHJ1bnRpbWUgZm9yIGVhY2guIEkgY29uc2lkZXJlZCB0aGF0IHRoZXNlIHZhbHVlcyBhcmUgYWxzbyBpbXBvcnRhbnQsIHNpbmNlIGRpZmZlcmVudCBjb3VudHJpZXMgdGVuZCB0byBoYXZlIGRpZmZlcmVudCBwcmVmZXJlbmNlcyB3aGVuIGl0IGNvbWVzIHRvIHRoZSBkdXJhdGlvbiBvZiBmaWxtcywgYW5kIHdlbGwgYXMgdGhlIGZhY3QgdGhhdCB0aGV5IGhhdmUgZGlmZmVyZW50IGFtb3VudHMgb2YgcmVzb3VyY2VzLCB3aGljaCB0ZW5kcyB0byBoYXZlIGFuIGltcGFjdCBvbiBob3cgbXVjaCBhIG1vdmllIGVhcm5zIGluIHNhbGVzLiBUaGlzIGlzIGhvdyB0aGlzIHRhYmxlIGxvb2tzIGxpa2U6CgpgYGB7cn0KIyBSdW50aW1lIGFuZCByZXZlbnVlIGRhdGEKYWxsX2NvdW50cmllcyA8LSBjKG5ld19jb3VudHJpZXMkY291bnRyeTEsIG5ld19jb3VudHJpZXMkY291bnRyeTIsIG5ld19jb3VudHJpZXMkY291bnRyeTMsCiAgICAgICAgICAgICAgICAgICBuZXdfY291bnRyaWVzJGNvdW50cnk0LCBuZXdfY291bnRyaWVzJGNvdW50cnk1LCBuZXdfY291bnRyaWVzJGNvdW50cnk2LAogICAgICAgICAgICAgICAgICAgbmV3X2NvdW50cmllcyRjb3VudHJ5NykKCgptb3ZpZV9jb3VudHJ5IDwtIGRhdGEuZnJhbWUobW92aWVfaWQgPSByZXAobW92aWVzX2NsZWFuJGlkLCBlYWNoID0gNyksIGNvdW50cnkgPSBhbGxfY291bnRyaWVzKQoKCm1vdmllX2NvdW50cnlfcmV2ZW51ZV9ydW50aW1lIDwtIGxlZnRfam9pbihtb3ZpZV9jb3VudHJ5LCBtb3ZpZXNfY2xlYW4sIGJ5ID0gYygibW92aWVfaWQiID0gImlkIikpCgoKY291bnRyeV9zdGF0cyA8LSBtb3ZpZV9jb3VudHJ5X3JldmVudWVfcnVudGltZSAlPiUKICBncm91cF9ieShjb3VudHJ5KSAlPiUKICBzdW1tYXJpemUoYXZlcmFnZV9yZXZlbnVlID0gbWVhbihyZXZlbnVlLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBhdmVyYWdlX3J1bnRpbWUgPSBtZWFuKHJ1bnRpbWUsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIGF2ZXJhZ2VfYnVkZ2V0ID0gbWVhbihidWRnZXQsIG5hLnJtID0gVFJVRSkpCgoKcHJpbnQoY291bnRyeV9zdGF0cykKYGBgCgpBZnRlciBvYnRhaW5pbmcgdGhpcyB0YWJsZSwgSSBncmFwaGVkIGl0IGluIGEgc2NhdHRlciBwbG90LCB3aGVyZSB3ZSBjYW4gc2VlIHRoZSB0b3AgMjAgY291bnRyaWVzIGJ5IGJvdGggcmV2ZW51ZSBhbmQgcnVudGltZSwgYXMgd2VsbCBhcyB0aGUgYm90dG9tIDIwIGNvdW50cmllcy4gVGhlc2UgYXJlIHRoZSBncmFwaHM6CgpgYGB7cn0KIyBIaWdoZXN0IHJ1bnRpbWUgYW5kIHJldmVudWVzIHNjYXR0ZXJwbG90cwp0b3BfMjBfY291bnRyaWVzIDwtIGhlYWQoY291bnRyeV9zdGF0c1tvcmRlcihjb3VudHJ5X3N0YXRzJGF2ZXJhZ2VfcmV2ZW51ZSwgZGVjcmVhc2luZyA9IFRSVUUpLF0sIDIwKQoKCmdncGxvdCh0b3BfMjBfY291bnRyaWVzLCBhZXMoeCA9IGNvdW50cnksIHkgPSBhdmVyYWdlX3JldmVudWUpKSArCiAgZ2VvbV9wb2ludCgpICsKICBsYWJzKHRpdGxlID0gIlRvcCAyMCBDb3VudHJpZXM6IEF2ZXJhZ2UgUmV2ZW51ZSIsCiAgICAgICB4ID0gIkNvdW50cnkiLCB5ID0gIkF2ZXJhZ2UgUmV2ZW51ZSIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSkpCgoKdG9wXzIwX2NvdW50cmllcyA8LSBoZWFkKGNvdW50cnlfc3RhdHNbb3JkZXIoY291bnRyeV9zdGF0cyRhdmVyYWdlX3J1bnRpbWUsIGRlY3JlYXNpbmcgPSBUUlVFKSxdLCAyMCkKCgpnZ3Bsb3QodG9wXzIwX2NvdW50cmllcywgYWVzKHggPSBjb3VudHJ5LCB5ID0gYXZlcmFnZV9ydW50aW1lKSkgKwogIGdlb21fcG9pbnQoKSArCiAgbGFicyh0aXRsZSA9ICJUb3AgMjAgQ291bnRyaWVzOiBBdmVyYWdlIFJ1bnRpbWUiLAogICAgICAgeCA9ICJDb3VudHJ5IiwgeSA9ICJBdmVyYWdlIFJ1bnRpbWUiKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKQoKCmBgYAoKRmluYWxseSwgSSBvYnRhaW5lZCB0aGUgYXZlcmFnZSByYXRpbmcgYnkgdGhlIGRpZmZlcmVudCBzdHVkaW9zLCBieSBjb21iaW5pbmcgYWxsIG9mIHRoZSByZXN1bHRzIG9idGFpbmVkIGZyb20gdGhlIGRpZmZlcmVudCBtb3ZpZXMuIFRvIGRvIHRoaXMsIEkgbWFkZSBhIGZpbHRlciB0byBvbmx5IGluY2x1ZGUgc3R1ZGlvcyB3aXRoIGF0IGxlYXN0IDEwIG1vdmllcy4gVGhpcyBoZWxwcyB1cyBvbmx5IGxvb2sgYXQgaW1wb3J0YW50IHN0dWRpb3MsIHNpbmNlIHNvbWUgc3R1ZGlvcyBtaWdodCBvbmx5IGhhdmUgMSBvciAyIG1vdmllcywgd2hpY2ggd291bGQgaW5jcmVhc2UgdGhlIHJhbmdlIG9mIGVycm9yIGluIHRoZSBhbmFseXNpcy4gQWZ0ZXIgb2J0YWluaW5nIHRoaXMgYXZlcmFnZSwgSSBncmFwaGVkIHRoZSB0b3AgMjAgaGlnaGVzdCBhbmQgbG93ZXN0IHN0dWRpb3MuIFRoaXMgaXMgaG93IHRoZSBncmFwaHMgbG9vayBsaWtlOiAKYGBge3IgaW5jbHVkZSA9IEZBTFNFfQptb3ZpZV9zdHVkaW8gPC0gZGF0YS5mcmFtZShtb3ZpZV9pZCA9IHJlcChtb3ZpZXNfY2xlYW4kaWQsIGVhY2ggPSAzKSwgc3R1ZGlvID0gYWxsX2NvbXBhbmllcykKCgptb3ZpZV9zdHVkaW9fcmF0aW5ncyA8LSBsZWZ0X2pvaW4obW92aWVfc3R1ZGlvLCBtb3ZpZXNfY2xlYW4sIGJ5ID0gYygibW92aWVfaWQiID0gImlkIikpCgoKc3R1ZGlvX3JhdGluZ3MgPC0gbW92aWVfc3R1ZGlvX3JhdGluZ3MgJT4lCiAgZ3JvdXBfYnkoc3R1ZGlvKSAlPiUKICBzdW1tYXJpemUoYXZlcmFnZV92b3RlX2F2ZXJhZ2UgPSBtZWFuKHZvdGVfYXZlcmFnZSwgbmEucm0gPSBUUlVFKSkKCgpzdHVkaW9fcmF0aW5ncyA8LSBzdHVkaW9fcmF0aW5nc1tvcmRlcihzdHVkaW9fcmF0aW5ncyRhdmVyYWdlX3ZvdGVfYXZlcmFnZSwgZGVjcmVhc2luZyA9IFRSVUUpLCBdCgoKcHJpbnQoIkF2ZXJhZ2UgUmF0aW5ncyBieSBTdHVkaW86IikKcHJpbnQoc3R1ZGlvX3JhdGluZ3MpCgpzdHVkaW9fbW92aWVfY291bnRzIDwtIG1vdmllX3N0dWRpb19yYXRpbmdzICU+JQogIGdyb3VwX2J5KHN0dWRpbykgJT4lCiAgc3VtbWFyaXplKG51bV9tb3ZpZXMgPSBuX2Rpc3RpbmN0KG1vdmllX2lkKSkKCgpzdHVkaW9fbW92aWVfY291bnRzIDwtIHN0dWRpb19tb3ZpZV9jb3VudHMgJT4lCiAgZmlsdGVyKG51bV9tb3ZpZXMgPj0gMTApCgoKc3R1ZGlvX3JhdGluZ3NfZmlsdGVyZWQgPC0gbGVmdF9qb2luKHN0dWRpb19tb3ZpZV9jb3VudHMsIHN0dWRpb19yYXRpbmdzLCBieSA9ICJzdHVkaW8iKQoKCnN0dWRpb19yYXRpbmdzX2ZpbHRlcmVkIDwtIHN0dWRpb19yYXRpbmdzX2ZpbHRlcmVkW29yZGVyKHN0dWRpb19yYXRpbmdzX2ZpbHRlcmVkJGF2ZXJhZ2Vfdm90ZV9hdmVyYWdlLCBkZWNyZWFzaW5nID0gVFJVRSksIF0KCgpwcmludCgiQXZlcmFnZSBSYXRpbmdzIGJ5IFN0dWRpbyAod2l0aCBhdCBsZWFzdCAxMCBtb3ZpZXMgbWFkZSk6IikKcHJpbnQoc3R1ZGlvX3JhdGluZ3NfZmlsdGVyZWQpCgpgYGAKYGBge3J9CiMgVG9wIDIwIGJlc3QgYW5kIHdvcnN0IHJhdGVkIHN0dWRpb3MgKGF0IGxlYXN0IDEwIG1vdmllcykKc3R1ZGlvX3JhdGluZ3NfZmlsdGVyZWQgPC0gc3R1ZGlvX3JhdGluZ3NfZmlsdGVyZWQgJT4lCiAgZmlsdGVyKCFpcy5uYShhdmVyYWdlX3ZvdGVfYXZlcmFnZSkpCgp0b3Bfc3R1ZGlvcyA8LSBoZWFkKHN0dWRpb19yYXRpbmdzX2ZpbHRlcmVkLCAyMCkKYm90dG9tX3N0dWRpb3MgPC0gdGFpbChzdHVkaW9fcmF0aW5nc19maWx0ZXJlZCwgMjApCgpnZ3Bsb3QodG9wX3N0dWRpb3MsIGFlcyh4ID0gYXZlcmFnZV92b3RlX2F2ZXJhZ2UsIHkgPSByZW9yZGVyKHN0dWRpbywgYXZlcmFnZV92b3RlX2F2ZXJhZ2UpKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gImRhcmtibHVlIikgKwogIGxhYnModGl0bGUgPSAiVG9wIDIwIFN0dWRpb3MgYnkgQXZlcmFnZSBSYXRpbmdzICh3aXRoIGF0IGxlYXN0IDEwIG1vdmllcykiLAogICAgICAgeCA9ICJBdmVyYWdlIFZvdGUgQXZlcmFnZSIsIHkgPSAiU3R1ZGlvIikgKwogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgaGp1c3QgPSAxKSkKCgpnZ3Bsb3QoYm90dG9tX3N0dWRpb3MsIGFlcyh4ID0gYXZlcmFnZV92b3RlX2F2ZXJhZ2UsIHkgPSByZW9yZGVyKHN0dWRpbywgYXZlcmFnZV92b3RlX2F2ZXJhZ2UpKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gIm9yYW5nZSIpICsKICBsYWJzKHRpdGxlID0gIkJvdHRvbSAyMCBTdHVkaW9zIGJ5IEF2ZXJhZ2UgUmF0aW5ncyAod2l0aCBhdCBsZWFzdCAxMCBtb3ZpZXMpIiwKICAgICAgIHggPSAiQXZlcmFnZSBWb3RlIEF2ZXJhZ2UiLCB5ID0gIlN0dWRpbyIpICsKICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIGhqdXN0ID0gMSkpCmBgYAoKIyA8c3BhbiBzdHlsZT0iY29sb3I6IGdyZWVuOyI+RmluZGluZ3MgYW5kIFJlc3VsdHM8L3NwYW4+IAoKQWZ0ZXIgdGhlc2UgZ3JhcGhzIGFuZCBjaGFydHMsIHdlIGNhbiBmaW5hbGx5IHZpZXcgb3VyIGZpbmRpbmdzLiBUaGUgZmlyc3QgZmluZGluZyB3ZSBjYW4gc2VlLCBpcyB0aGF0IHRoZSBnZW5yZSB3aXRoIHRoZSBtb3N0IG1vdmllcyBpcyBEcmFtYS4gQmFzZWQgb24gdGhpcywgd2UgY2FuIGFzc3VtZSAyIHRoaW5ncy4gRmlyc3QsIHRoYXQgc3R1ZGlvcyBrZWVwIG1ha2luZyBEcmFtYS1vcmllbnRlZCBtb3ZpZXMgYmVjYXVzZSB0aGVyZSBpcyBkZW1hbmQgZm9yIHRoaXMgZ2VucmUuIEJhc2VkIG9uIHRoaXMsIHdlIGNhbiBhc3N1bWUgdGhhdCBEcmFtYSBpcyB0aGUgbW9zdCBzdWNjZXNzZnVsIGdlbnJlLCBjb25zaWRlcmluZyB0aGF0IHRoZXJlIGFyZSBvdmVyIDE4IHRob3VzYW5kIG1vdmllcyB0aGF0IGhhdmUgdGhpcyBnZW5yZSBhcyBvbmUgb2YgdGhlaXIgbWFpbiBpZGVudGlmaWVycy4KCkZvciBvdXIgbmV4dCBmaW5kaW5nLCB3ZSBjYW4gc2VlIHdoaWNoIHN0dWRpb3MgYXJlIHRoZSBtb3N0IHN1Y2Nlc3NmdWwuIFRoZSB0b3AgMyBzdHVkaW9zIGluIHRlcm1zIG9mIG1vdmllcyBtYWRlIGFyZSBQYXJhbW91bnQsIEZveCBhbmQgVW5pdmVyc2FsLCB3aGljaCBhcmUgZXh0cmVtZWx5IHdlbGwga25vd24gYXQgYSBnbG9iYWwgbGV2ZWwuIFRoZSBpbnRlcmVzdGluZyBkZXRhaWwgaXMgdGhhdCB0aGVzZSAzIHN0dWRpb3MgYXJlIGFsbCBmcm9tIHRoZSBVbml0ZWQgU3RhdGVzLCBhbmQgbm90IG9ubHkgdGhhdC4gT3V0IG9mIHRoZSB0b3AgMTAgc3R1ZGlvcyB3aXRoIHRoZSBtb3N0IG1vdmllcyBtYWRlLCA5IGFyZSBmcm9tIHRoZSBVUy4gVGhpcyBsZWFkcyB0byB0aGUgY29uY2x1c2lvbiB0aGF0IG1vdmllcyBtYWRlIGluIHRoaXMgY291bnRyeSB0ZW5kIHRvIGhhdmUgaGlnaGVyIHN1Y2Nlc3MgcmF0ZXMgdGhhbiBvdGhlcnMuIFdlIGNhbiBzZWUgdGhpcyBncmFwaGljYWxseSwgc2luY2UgaW4gdGhlIOKAnE1vc3QgQ29tbW9uIENvdW50cmllc+KAnSBncmFwaCwgdGhlIFVuaXRlZCBTdGF0ZXMgaGFzIG92ZXIgMTAgdGltZXMgYXMgbWFueSBtb3ZpZXMgYXMgdGhlIHNlY29uZCBwbGFjZSAoVW5pdGVkIEtpbmdkb20pLgoKVGhpcyBzYW1lIGFyZ3VtZW50IGdvZXMgb24gdG93YXJkcyB0aGUgbmV4dCBncmFwaC4gV2UgY2FuIHNlZSB0aGF0IHRoZSBFbmdsaXNoIGxhbmd1YWdlIGlzIHRoZSBtb3N0IHBvcHVsYXIgYnkgYW4gaW5jcmVkaWJseSB3aWRlIG1hcmdpbi4gVGhpcyBpcyBub3Qgb25seSBkdWUgdG8gdGhlIGZhY3QgdGhhdCB0aGUgVVNBIGlzIHRoZSBjb3VudHJ5IHdpdGggdGhlIG1vc3QgbW92aWVzIG1hZGUsIGJ1dCBhbHNvIHRoYXQgRW5nbGlzaCB0ZW5kcyB0byBiZSBjb25zaWRlcmVkIHRoZSDigJxXb3JsZOKAmXMgTGFuZ3VhZ2XigJ0sIGFuZCBzbyBwZW9wbGUgZnJvbSBhbGwgb3ZlciB0aGUgd29ybGQgc2VlbSB0byBiZSBhdHRyYWN0ZWQgdG93YXJkcyBtb3ZpZXMgdGhhdCBoYXZlIEVuZ2xpc2ggYXMgb25lIG9mIHRoZWlyIG9wdGlvbnMuCgpUaGUgZmluYWwgb2JzZXJ2YXRpb24gdGhhdCBjYW4gYmUgbWFkZSBpcyByZWxhdGVkIHRvIHRoZSBsYXN0IGdyYXBocy4gTW9zdCBvZiB0aGUgbG93ZXIgcmFua2VkIHN0dWRpb3MgYXJlIGVpdGhlciBub3QgcHJvcGVyIHN0dWRpb3MsIG9yIGJhc2VkIGluIGNvdW50cmllcyB0aGF0IGhhdmUgYSBzbWFsbGVyIGFtb3VudCBvZiByZXNvdXJjZXMgdG8gbWFrZSB0aGVpciBtb3ZpZXMuIE9uIHRoZSBvdGhlciBoYW5kLCBtb3N0IG9mIHRoZSBzdHVkaW9zIHdpdGggdGhlIGhpZ2hlc3QgYXZlcmFnZSBzY29yZXMgaGFpbCBmcm9tIHRoZSBVbml0ZWQgU3RhdGVzIG9mIEFtZXJpY2EuCgojIDxzcGFuIHN0eWxlPSJjb2xvcjogZ3JlZW47Ij5Db25jbHVzaW9ucyBhbmQgUmVjb21tZW5kYXRpb25zPC9zcGFuPiAKCkFmdGVyIHRoaXMgdGhvcm91Z2ggYW5hbHlzaXMsIEkgaGF2ZSBhcnJpdmVkIGF0IHRoZSBjb25jbHVzaW9uIHRoYXQgdGhlIG1vc3QgaW1wb3J0YW50IGZhY3RvciBpbiBhIG1vdmllcyBzdWNjZXNzIGlzIGl0J3MgY291bnRyeSBvZiBwcm9kdWN0aW9uLiBPZiBjb3Vyc2UsIHRoaXMgaXMgbWFpbmx5IG9yaWVudGVkIHRvd2FyZHMgdGhlIFVuaXRlZCBTdGF0ZXMsIHdoaWNoIGNhbiBiZSBleHBsYWluZWQgYnkgdGhlIGZhY3QgdGhhdCB0aGV5IGhhdmUgdGhlIGhpZ2hlc3QgYW1vdW50IG9mIHN0dWRpb3Mgb3V0IG9mIGFueSBjb3VudHJ5IGJ5IGZhci4gQW5vdGhlciBmYWN0b3IgdGhhdCBjYW4gYmUgYXR0cmlidXRlZCB0byB0aGlzIGlzIHRoYXQgQW1lcmljYW4gc3R1ZGlvcyB0ZW5kIHRvIGhhdmUgYSBoaWdoZXIgYW1vdW50IG9mIHBvcHVsYXJpdHkuIFRha2UgVW5pdmVyc2FsIFN0dWRpb3MgZm9yIGV4YW1wbGUuIFRoaXMgc3R1ZGlvIGlzIHNvIHBvcHVsYXIsIHRoYXQgaXQgaGFzIHByZXR0eSBtdWNoIHRyYW5zY2VuZGVkIG1vdmllLW1ha2luZywgdG8gdGhlIHBvaW50IHRoYXQgaXQgZXZlbiBoYXMgYSB0aGVtZSBwYXJrIGJhc2VkIGFyb3VuZCBpdC4KClRoZSBvdGhlciBjb25jbHVzaW9uIHRoYXQgaSd2ZSByZWFjaGVkIGlzIHRoYXQgZm9yIGEgbW92aWUgdG8gYmUgc3VjY2Vzc2Z1bCwgaXQgaGFzIHRvIGF0IGxlYXN0IGhhdmUgYSB0cmFuc2xhdGlvbiB0byB0aGUgRW5nbGlzaCBsYW5ndWFnZS4gQXMgd2UgY2FuIGNsZWFybHkgc2VlLCBvdmVyIDg1JSBvZiBtb3ZpZXMgaGF2ZSB0aGUgb3B0aW9uIHRvIGJlIHdhdGNoZWQgaW4gRW5nbGlzaC4gVG8gbWUsIHRoaXMgaXMgYSBrZXkgZmFjdG9yLiBUaGlzIGlzIGR1ZSB0byB0aGUgZmFjdCB0aGF0IGl0IGlzIHRoZSBtb3N0IHBvcHVsYXIgbGFuZ3VhZ2UgaW4gdGhlIHdvcmxkLCBhbmQgc28gYWRhcHRpbmcgYSBtb3ZpZSB0byB0aGlzIGxhbmd1YWdlIGNvdWxkIHZlcnkgd2VsbCB0YWtlIGEgbW92aWUgZnJvbSBiZWluZyBhIGxvY2FsIGhpdCwgdG8gYSB3b3JsZHdpZGUgcGhlbm9tZW5vbS4KCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiBncmVlbjsiPlJlZmVyZW5jZTwvc3Bhbj4gCgpNb3ZpZXMgTWV0YWRhdGEgRGF0YXNldDogaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9kYXRhc2V0cy9yb3VuYWtiYW5pay90aGUtbW92aWVzLWRhdGFzZXQvZGF0YQ==