Evidence 1. R Markdown File

Introduction

In the competitive world of cinema, the success of a film may seem like a mystery shrouded in uncertainty. However, behind every success lies a complex interplay of factors ranging from genre and budget to duration and content quality. In this context, data analysis emerges as a powerful tool to provide film production companies with important information for making strategic decisions. By identifying patterns and correlations in the data, we can offer informed recommendations on where to invest, how to balance budget and quality, and how to effectively promote films to maximize their chances of success. In this exploration, our goal is to illuminate the path toward a more profitable and captivating film industry.

Progress Problem Setup 1

Calling libraries

#Calling libraries

library(units)
## udunits database from /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/library/units/share/udunits/udunits2.xml
library(visdat)
library(DataExplorer)
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(janitor)
## 
## Attaching package: 'janitor'
## The following objects are masked from 'package:stats':
## 
##     chisq.test, fisher.test
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ forcats   1.0.0     ✔ readr     2.1.5
## ✔ ggplot2   3.5.0     ✔ stringr   1.5.1
## ✔ lubridate 1.9.3     ✔ tibble    3.2.1
## ✔ purrr     1.0.2     ✔ tidyr     1.3.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(stringr)
library(tidyr)
library(readr)
library(ggplot2)

Read file

movies<- read.csv("/Users/karlalopez/Downloads/archive (2) 2/movies_metadata.csv")

Cleaning Data

Treating NA’s

# Finding how many NA are in the data base
sum(is.na(movies))
## [1] 281

A total of 281 NAs have been found in the database, and to know how to treat them, we will first identify which columns they come from and how many there are per column.

Treating NA’s by column

# Search in each column how many NAs exist to see what type of elimination to apply
sapply(movies, function(x) sum(is.na(x)))
##                 adult belongs_to_collection                budget 
##                     0                     0                     0 
##                genres              homepage                    id 
##                     0                     0                     0 
##               imdb_id     original_language        original_title 
##                     0                     0                     0 
##              overview            popularity           poster_path 
##                     0                     0                     0 
##  production_companies  production_countries          release_date 
##                     0                     0                     0 
##               revenue               runtime      spoken_languages 
##                     6                   263                     0 
##                status               tagline                 title 
##                     0                     0                     0 
##                 video          vote_average            vote_count 
##                     0                     6                     6

6 NA have been found in the “Revenue” column, 263 in “Runtime”, 6 in “Vote Avarage”, and 6 in “Vote Count”. Now we will remove them by column individually

Runtime
# Cleaning and summary of column "runtime"
movies2 <- movies

movies2$runtime[is.na(movies2$runtime)] <- mean(movies2$runtime, na.rm=TRUE)
summary(movies2$runtime)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    0.00   85.00   95.00   94.13  107.00 1256.00
Revenue
# Cleaning and summary of column "revenue"
movies3 <- movies2

movies3$revenue[is.na(movies3$revenue)] <- mean(movies3$revenue, na.rm=TRUE)
summary(movies3$revenue)
##      Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
## 0.000e+00 0.000e+00 0.000e+00 1.121e+07 0.000e+00 2.788e+09
Vote Count
# Cleaning and summary of column "vote count"
movies4 <- movies3

movies4$vote_count[is.na(movies4$vote_count)] <- mean(movies4$vote_count, na.rm=TRUE)
summary(movies4$vote_count)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##     0.0     3.0    10.0   109.9    34.0 14075.0
Vote Avarage
# Cleaning and summary of column "vote average"
movies_wo_na <- movies4

movies_wo_na$vote_average[is.na(movies_wo_na$vote_average)] <- mean(movies_wo_na$vote_average, na.rm=TRUE)
summary(movies_wo_na$vote_average)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   0.000   5.000   6.000   5.618   6.800  10.000
# Verify the NA were eliminated
sum(is.na(movies_wo_na))
## [1] 0
Reasoning

The method of elimination used for the NAs was by taking the average, which was decided for two reasons.
+ Because in the analysis of the columns it was possible to obtain that the values that contained NA were numeric and integers runtime, vote average, vote count, revenue.
+ The missing values are important and it is desired to preserve the general structure of the data.

Treating Duplicates

# Check how many information are totally duplicated
sum(duplicated(movies_wo_na))
## [1] 17

In the database we have found 17 duplicate values, now we will remove them.

Eliminating duplicates

# Eliminate information that is totally duplicated
movies_wo_dup <- movies_wo_na
movies_wo_dup <- distinct(movies_wo_dup)
# Check if duplicate information is eliminated
sum(duplicated(movies_wo_dup))
## [1] 0

Reasoning

In this example the duplicates were eliminated given that it would be the same movie otherwise.

Separating Text by column

Genres

# Splitting each string into a character vector, returns a df

# Use a regular expression to match the genre names
genre_pattern <- "(?<=name': ')[^']*(?=')"

# Apply the extraction to the entire column and store the result in a new object
genre_data <- lapply(movies_wo_dup$genres, function(x) {
  genres <- str_extract_all(x, genre_pattern)[[1]]
  split_genres <- strsplit(genres, ", ")
  unlist(split_genres)
})
# Calculate the maximum number of genres a movie can have
max_genre <- max(sapply(genre_data, length))

# Convert the list to a data frame
genre_df <- do.call(rbind, lapply(genre_data, function(x) {
  tmp <- rep(NA, max_genre)
  tmp[seq_along(x)] <- x
  as.data.frame(t(tmp))
}))

# Rename the columns
names(genre_df) <- paste0("genre", seq_len(ncol(genre_df)))
# Join the new genre data frame with the original data frame
movies_wo_dup <- cbind(movies_wo_dup, genre_df)

# Delete the genres column
movies_w_genres <- subset(movies_wo_dup, select = -genres)

Production Companies

# Feature to clear production company names
clean_production_companies <- function(companies) {
  # Apply regular expression to extract company name
  cleaned_names <- str_extract(companies, "'name': '([^']+)'")
  # Delete the extra part
  cleaned_names <- gsub("'name': '", "", cleaned_names)
  cleaned_names <- gsub("'", "", cleaned_names)
  return(cleaned_names)
}

# Apply the function to the production_companies column and store the results in a new column
movies_w_genres$Clean_production_companies <- clean_production_companies(movies_w_genres$production_companies)

# Delete the production companies column
movies_w_prodcom <- subset(movies_w_genres, select = -production_companies)

Production Countries

# Function to clear the names of the countries of production
clean_production_countries <- function(countries) {
  # Apply regular expression to extract country name
  cleaned_names <- str_extract(countries, "'name': '([^']+)'")
  # Delete the extra part
  cleaned_names <- gsub("'name': '", "", cleaned_names)
  cleaned_names <- gsub("'", "", cleaned_names)
  return(cleaned_names)
}

# Apply the function to the production_countries column and store the results in a new column
movies_w_prodcom$Clean_production_countries <- clean_production_countries(movies_w_prodcom$production_countries)

# Delete the production companies column
movies_w_prodcoun <- subset(movies_w_prodcom, select = -production_countries)
# Function to clear the names of the countries of production
clean_production_countries <- function(countries) {
  # Apply regular expression to extract country name
  cleaned_names <- str_extract(countries, "'name': '([^']+)'")
  # Delete the extra part
  cleaned_names <- gsub("'name': '", "", cleaned_names)
  cleaned_names <- gsub("'", "", cleaned_names)
  return(cleaned_names)
}

# Apply the function to the production_countries column and store the results in a new column
movies_w_prodcom$Clean_production_countries <- clean_production_countries(movies_w_prodcom$production_countries)

# Delete the production companies column
movies_w_prodcoun <- subset(movies_w_prodcom, select = -production_countries)

Spoken Language

# Use a regular expression to match the language names
language_pattern <- "(?<=name': ')[^']*(?=')"

# Apply the extraction to the entire column and store the result in a new object
language_data <- lapply(movies_w_prodcoun$spoken_languages, function(x) {
  languages <- str_extract_all(x, language_pattern)[[1]]
  split_languages <- strsplit(languages, ", ")
  unlist(split_languages)
})
# Calculate the maximum number of languages a movie can have
max_language <- max(sapply(language_data, length))

# Convert the list to a data frame
language_df <- do.call(rbind, lapply(language_data, function(x) {
  tmp <- rep(NA, max_language)
  tmp[seq_along(x)] <- x
  as.data.frame(t(tmp))
}))

# Rename the columns
names(language_df) <- paste("spoken_lang", seq_len(ncol(language_df)), sep = "_")
# Join the new language data frame with the original data frame
movies_w_lang <- cbind(movies_w_prodcoun, language_df)

# Eliminate original column
movies_w_lang$spoken_languages <- NULL

Belongs to Collection

# Function to separate the 'belongs_to_collection' column
separate_belongs_to_collection <- function(movies_w_lang) {
  # Create a new DataFrame to perform separation
  collection_data <- movies_w_lang

  # Apply regular expression to extract collection name
  collection_names <- str_extract(collection_data$belongs_to_collection, "'name': '([^']+)'")

  # Delete the extra part
  collection_names <- gsub("'name': '", "", collection_names)
  collection_names <- gsub("'", "", collection_names)

  # Create a new column in the new DataFrame with the extracted collection names
  collection_data$Collection <- collection_names

  # Remove the original 'belongs_to_collection' column from the new DataFrame
  collection_data$belongs_to_collection <- NULL

  return(collection_data)
}

# Create a new DataFrame for separation
collection_data <- movies_w_lang

# Apply the function to the new DataFrame
collection_data <- separate_belongs_to_collection(collection_data)

Interpretation of data obtained from the database

Runtime

# Runtime histogram
histogram_runtime <- ggplot(collection_data, aes(x = runtime)) +
  geom_histogram(fill = "skyblue", color = "black") +
  labs(title = "Histogram of Runtime")

# Display histogram 
print(histogram_runtime)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

  • Histogram of Runtime : Suggests that most movies have shorter runtimes, with an average of 94.1281 minutes; with only few movies having exceptionally long runtimes, like 1,256 minutes. Besides, the presence of a movie with runtime of 0 minutes should be investigated as it could be an error or missing data.

Revenue

# Revenue histogram
histogram_revenue <- ggplot(collection_data, aes(x = revenue)) +
  geom_histogram(fill = "lightgreen", color = "black") +
  labs(title = "Histogram of Revenue")

# Display histogram 
print(histogram_revenue)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

  • Histogram of Revenue : It also indicates that most movies have relatively lower revenues compared to a few blockbuster movies with very high revenues. There is a significant gab between majority of revenue values and outliers.

Vote Count

# Vote Count histogram
histogram_vote_count <- ggplot(collection_data, aes(x = vote_count)) +
  geom_histogram(fill = "lightpink", color = "black") +
  labs(title = "Histogram of Vote Count")

# Display histogram 
print(histogram_vote_count)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

  • Histogram of Vote Count : Most movies receive a moderate number of votes, while a few movies receive a ver high number of votes; so there may be a considerable gap between outliers.

Vote Avarage

# Vote Average histogram
histogram_vote_average <- ggplot(collection_data, aes(x = vote_average)) +
  geom_histogram(fill = "lightyellow", color = "black") +
  labs(title = "Histogram of Vote Average")

# Display histogram 
print(histogram_vote_average)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

  • Histogram Vote Average : It shows a relatively symmetrical distribution around the average vote of 5.6, with values ranging form 0 to 10. A spike in the distribution might occur around whole numbers due to the nature of voting systems.

Now that we identified certain outliers, we can consider various approaches to handle them like deleting them, treating them separately or transforming data.The best approach depends on the nature of the data and the context of our analysis.

vis_miss(slice_sample(collection_data))

The 47.9% of the data is missing, mainly observed in the last columns corresponding to “genre” and “spoken_language”. This is because multiple columns were created for these variables, as some movies have a wide variety of genres and spoken languages. Therefore, it is understandable that there are missing values in the last columns of these variables, as few movies provide complete information about all the genres or languages present in the film.

Progress Problem Setup 2

Factor Levels

# Identify categorical variables and convert them to factors
cols_to_factor <- c("adult", paste0("genre", 1:8), "Clean_production_companies", 
                    "Clean_production_countries", paste0("spoken_lang_", 1:18))

# Convert columns to factors
collection_data[cols_to_factor] <- lapply(collection_data[cols_to_factor], factor)
head(cols_to_factor)
## [1] "adult"  "genre1" "genre2" "genre3" "genre4" "genre5"

Adressing factor levels becomes important when dealing with categorical variables that have specific order associated with their levels; for example: many statistical functions in R treat factors differently than character vectors, like in regression analysis that requieres accurate factor levels; besides, incorrect factor levels can lead to misleading visual representations of data.

Values that don’t belong in the factor

# Replace unusual entries in the adult column with "False"
collection_data$adult[grep("written by|bikini contest|casino connected", tolower(collection_data$adult))] <- "False"

# Recalculate the frequency of each category in the adult column and update the data frame
adult_freq <-as.data.frame(table(collection_data$adult))

# Filter the rows that have a frequency greater than 0
adult_freq_filtered <- adult_freq[adult_freq$Freq > 0, ]

# Show the updated categories and their frequencies
print(adult_freq)
##                                                                                                                             Var1
## 1                                                                                                             - Written by Ørnås
## 2  Avalanche Sharks tells the story of a bikini contest that turns into a horrifying affair when it is hit by a shark avalanche.
## 3                  Rune Balot goes to a casino connected to the October corporation to try to wrap up her case once and for all.
## 4                                                                                                                          False
## 5                                                                                                                           True
##    Freq
## 1     0
## 2     0
## 3     0
## 4 45440
## 5     9
# Merge collection_data with adult_freq_filtered based on the 'Var1' column
collection_data <- merge(collection_data, adult_freq_filtered, by.x = "adult", by.y = "Var1", all.x = TRUE)

# Remove the 'Freq' column (since it's not needed)
collection_data <- collection_data[, -ncol(collection_data)]

In the “adult” column, there were 3 rows that did not respect the TRUE and FALSE format, so it was decided to eliminate those 3 rows to maintain consistency.

The sames goes for the original languge column, which instead of an abreviation with characters, there are some rows with integers. While also, adding a threshold for those movies whose original language has a frequency less than 10, and change it to the abreviation as “other”, to simplify and consolidate the data.

# Create a dataframe with the frequency table of original languages
org_lang_freq <- as.data.frame(table(collection_data$original_language))
#see the average
summary(org_lang_freq$Freq)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##     1.0     2.0    10.0   488.7    78.0 32259.0
# Find rows with frequency less than a threshold (e.g., 50) and combine them into 'other'
threshold <- 10
other_freq <- sum(org_lang_freq$Freq[org_lang_freq$Freq < threshold])
org_lang_freq$Var1[org_lang_freq$Freq < threshold] <- "other"
## Warning in `[<-.factor`(`*tmp*`, org_lang_freq$Freq < threshold, value =
## structure(c(1L, : invalid factor level, NA generated
org_lang_freq$Freq[org_lang_freq$Freq < threshold] <- other_freq

# Remove duplicates caused by combining into 'other'
org_lang_freq <- org_lang_freq[!duplicated(org_lang_freq$Var1), ]

# Print the modified dataframe
head(org_lang_freq)
##    Var1 Freq
## 1         11
## 2  <NA>  113
## 5    ab   10
## 8    ar   39
## 10   bg   10
## 12   bn   29

The frequencies of the original languages present in the database were observed, and then, the infrequent languages were identified to combine them into a category called “other”. Subsequently, the frequency table was updated to reflect these changes.

Checking categories / Collapsing categories

library(forcats)
# Categories with less frequency
other_categories = c("Carousel Productions", "Aniplex", "Odyssey Media")

# Select it as other
collection_data <- collection_data %>%
  mutate(genre1 = as.factor(genre1),
         genre1 = fct_collapse(genre1, other = other_categories))
# Languages with less frequency
other_categories = c("Pulser Productions", "GoHands", "Vision View Entertainment")

# Select it as other
collection_data <- collection_data %>%
  mutate(genre2 = as.factor(genre2),
         genre2 = fct_collapse(genre2, other = other_categories))
# Languages with less frequency
other_categories = c("Telescene Film Group Productions", "Rogue State", "BROSTA TV")

# Select it as other
collection_data <- collection_data %>%
  mutate(genre3 = as.factor(genre3),
         genre3 = fct_collapse(genre3, other = other_categories))

The list of less frequent categories were defined in the three main movie genre columns (“genre1”, “genre2”, and “genre3”), in order to group them under the label “other,” thus achieving the simplification and consolidation of the information. This helps streamline the data and avoid cluttering analysis with overly specific categories.

Cleaning of text data

clean_revenue <- function(revenue) {
  # Format entries with commas and add money symbol
  formatted_revenue <- paste0("$", format(revenue, big.mark = ",", scientific = FALSE))
  return(formatted_revenue)
}

# Apply the function to the revenue column and store the results in a new column
collection_data$Clean_revenue <- clean_revenue(collection_data$revenue)
# Function to clean the budget
clean_budget <- function(budget) {
  # Format budget with commas and add money symbol
  formatted_budget <- paste0("$", format(budget, big.mark = ",", scientific = FALSE))
  return(formatted_budget)
}

# Apply the function to the budget column and store the results in a new column
collection_data$Clean_budget <- clean_budget(collection_data$budget)

# Remove the previous budget column
collection_data <- subset(collection_data, select = -c(budget))
# Convert the "popularity" column to numeric
collection_data$popularity <- as.numeric(collection_data$popularity)
## Warning: NAs introduced by coercion
# Round popularity to whole numbers
collection_data$round_popularity <- round(collection_data$popularity)

# Remove the previous popularity column
collection_data <- subset(collection_data, select = -c(popularity))

The columns for revenue and budget were reformatted, adding dollar symbols and removing scientific notation, which makes interpreting and analyzing these monetary values easier. Additionally, the popularity column was also converted to numerical format and its values were rounded to simplify their presentation. These steps contribute to enhancing the clarity and accuracy of the data, making it easier to understand and analyze.

Conclusion

As for the univariate distributions, budget, popularity, Vote count and revenue have low frequencies so the “success” movies make the minority which hold into question the possibility of a prediction model. Run time is 100 minutes for most and Vote Average follows a normal distribution with an avg of 6-7. None of the others follow a normal distribution.

As for what variables are most correlated to revenue, here is what we found. Strongest: budget and vote count; 2nd level: popularity, genre1_adventure and genre2_action; 3rd level: genre1_animation and genre2_fantasy.

There is a positive correlation between vote count, budget and popularity to revenue. No clear trend with runtime and vote average.

Progress Problem Setup 3

Unit Conversion

# Check if runtime column is already assigned units
if (!inherits(collection_data$runtime, "units")) {
  # Convert runtime column to numeric and then to minutes with units
  collection_data$runtime <- as.numeric(collection_data$runtime)
  collection_data$runtime <- set_units(collection_data$runtime, "minutes")
}
# Create a new column called 'num_genres' that counts the non-missing genre and spoken lang columns
collection_data$num_genres <- rowSums(!is.na(collection_data[, paste0("genre", 1:8)]))

collection_data <- collection_data %>%
  mutate(num_spoken_languages = rowSums(!is.na(select(., starts_with("spoken_lang")))))

Conclusion

These code allows us to ensure consistent units for runtime and calculating the count of genres and spoken languages so the dataset becomes more standardized. The unit conversion ensures that the ‘runtime’ column is uniformly represented in minutes. It checks if the ‘runtime’ column is already assigned units. If not, it converts the ‘runtime’ column to numeric and then assigns units to represent time in minutes. Last the genre and spoken language counts code, adds two new columns to the dataset. ‘num_genres’: This column counts the number of non-missing genre columns for each movie. ‘num_spoken_languages’: This column counts the number of non-missing spoken language columns for each movie.

Progress Problem Setup 4

Tables with 1 or 2 variables 4

# Create a backup df
copy_data <- collection_data

Revenue

# Make adult column a logical data type instead of a factor to eliminate irrelevant entries

levels(copy_data$adult)
## [1] " - Written by Ørnås"                                                                                                           
## [2] " Avalanche Sharks tells the story of a bikini contest that turns into a horrifying affair when it is hit by a shark avalanche."
## [3] " Rune Balot goes to a casino connected to the October corporation to try to wrap up her case once and for all."                
## [4] "False"                                                                                                                         
## [5] "True"
copy_data$adult <- as.logical(copy_data$adult)
adult_table <- table(copy_data$adult)
adult_table
## 
## FALSE  TRUE 
## 45440     9
# Define the revenue categories
revenue_bins <- c(0, 100000000, 500000000, 1000000000, 2000000000, 3000000000)
revenue_labels <- c('<100M', '100M-500M', '500M-1B', '1B-2B', '2B-3B')


# Create the 'revenue_group' column
copy_data$revenue_group <- cut(copy_data$revenue, breaks = revenue_bins, labels = revenue_labels, right = FALSE)
table(copy_data$revenue_group)
## 
##     <100M 100M-500M   500M-1B     1B-2B     2B-3B 
##     44076      1203       141        27         2
table(copy_data$revenue_group, copy_data$genre1)
##            
##             Action Adventure Animation other Comedy Crime Documentary Drama
##   <100M       4184      1309      1039     3   8581  1639        3412 11751
##   100M-500M    251       156        59     0    230    45           2   202
##   500M-1B       40        42        23     0      6     0           0     5
##   1B-2B         10         6         3     0      0     0           0     2
##   2B-3B          2         0         0     0      0     0           0     0
##            
##             Family Fantasy Foreign History Horror Music Mystery Romance
##   <100M        495     647     118     272   2567   479     544    1162
##   100M-500M     21      49       0       7     52     8       9      28
##   500M-1B        4       7       0       0      0     0       1       1
##   1B-2B          4       0       0       0      0     0       0       0
##   2B-3B          0       0       0       0      0     0       0       0
##            
##             Science Fiction Thriller TV Movie   War Western
##   <100M                 607     1616      390   374     446
##   100M-500M              29       46        0     4       4
##   500M-1B                 9        1        0     1       1
##   1B-2B                   2        0        0     0       0
##   2B-3B                   0        0        0     0       0

Lower grossing films tend to have movies from a wide array of genres, but for 500M-1B to 2B-3B are most concentrated in action.

table(copy_data$revenue_group, copy_data$round_popularity)
##            
##                 0     1     2     3     4     5     6     7     8     9    10
##   <100M     13625 12395  5067  2608  1760  1616  1459  1270  1029   821   654
##   100M-500M     1    14     6     3    10    14    29    69   106   112   118
##   500M-1B       0     1     1     0     1     1     1     0     1     2     1
##   1B-2B         0     0     0     0     0     1     0     0     0     0     0
##   2B-3B         0     0     0     0     0     0     0     0     0     0     0
##            
##                11    12    13    14    15    16    17    18    19    20    21
##   <100M       547   383   282   183   124    63    40    35    22    21     9
##   100M-500M   120   104   107    70    61    51    41    30    20    19    16
##   500M-1B       7     4     7     9     5    11     5     4    12     6     3
##   1B-2B         0     0     0     1     0     0     2     1     0     1     1
##   2B-3B         0     0     0     0     0     0     0     0     0     0     0
##            
##                22    23    24    25    26    27    28    29    30    31    32
##   <100M         7     4     5     8     1     2     2     0     1     1     2
##   100M-500M    13     6     6     2     2     1     4     5     3     2     2
##   500M-1B       4     3     2     5     7     2     2     5     2     4     3
##   1B-2B         0     1     2     1     1     2     1     2     0     0     0
##   2B-3B         0     0     0     0     0     0     0     0     0     0     1
##            
##                33    34    35    36    37    38    39    40    41    42    43
##   <100M         0     3     1     1     3     1     1     0     0     0     0
##   100M-500M     2     5     0     6     2     0     1     1     4     3     0
##   500M-1B       1     1     1     0     0     1     1     0     1     1     1
##   1B-2B         1     0     0     0     3     0     0     0     0     0     0
##   2B-3B         0     0     0     0     0     0     0     0     0     0     0
##            
##                44    45    47    48    49    51    52    53    55    57    60
##   <100M         0     0     1     0     0     2     1     1     0     1     1
##   100M-500M     1     1     0     0     1     0     0     0     0     0     0
##   500M-1B       1     0     1     1     0     0     0     1     1     0     0
##   1B-2B         0     0     0     0     1     0     0     0     0     0     0
##   2B-3B         0     0     0     0     0     0     0     0     0     0     0
##            
##                61    64    68    69    73    75    77    79    88    89    90
##   <100M         1     1     1     0     0     0     0     1     1     0     0
##   100M-500M     0     1     0     1     1     0     1     0     0     1     0
##   500M-1B       0     0     0     0     0     1     0     0     0     0     0
##   1B-2B         0     0     0     0     0     0     0     0     0     0     1
##   2B-3B         0     0     0     0     0     0     0     0     0     0     0
##            
##                96   123   134   141   146   147   155   184   185   188   214
##   <100M         1     0     0     0     0     0     0     1     0     0     0
##   100M-500M     0     0     0     1     1     0     1     0     0     0     0
##   500M-1B       0     0     1     0     0     1     0     0     1     1     1
##   1B-2B         0     1     0     0     1     0     0     0     0     0     0
##   2B-3B         0     0     0     0     0     0     0     0     1     0     0
##            
##               228   287   294   547
##   <100M         0     0     0     0
##   100M-500M     1     0     0     0
##   500M-1B       0     0     1     0
##   1B-2B         0     1     0     1
##   2B-3B         0     0     0     0

It is seen that the mayority of movies with budgets lower than 100M or 100M-500M have popularities ranging from 0 to 27. As for higher grossing films, they tend to have popularity scores from 67 to 547, but most are outliers since they make the minority.

Production Companies

# Calculate the frequencies of each production company
company_frequencies <- copy_data %>%
  count(Clean_production_companies) %>%
  arrange(desc(n))  # Sort in descending order of frequency

# Select the top 10 production companies
top_10_companies <- head(company_frequencies, 10)

top_10_companies
##                Clean_production_companies     n
## 1                                    <NA> 11934
## 2                      Paramount Pictures   998
## 3               Metro-Goldwyn-Mayer (MGM)   878
## 4  Twentieth Century Fox Film Corporation   780
## 5                            Warner Bros.   757
## 6                      Universal Pictures   754
## 7                       Columbia Pictures   429
## 8           Columbia Pictures Corporation   401
## 9                      RKO Radio Pictures   290
## 10                         United Artists   272
# Calculate the count of each company
company_counts <- table(copy_data$Clean_production_companies)

# Sort the companies by count in descending order and select the top five
top_companies <- names(sort(company_counts, decreasing = TRUE)[1:8])

# Filter the dataset to include only the top five most important companies
filtered_data <- copy_data[collection_data$Clean_production_companies %in% top_companies, ]

# Create the bar plot
ggplot(filtered_data, aes(x = Clean_production_companies)) +
  geom_bar() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))

This bar graph analyzes the “Clean_production_” variable companies” and shows us the 8 most important results to be able to identify which companies are making the most movies. The horizontal bar chart analyses the proportion of the revenue compared to its budget for each of the genre. Adventure and SciFi count with a bigger budget, yet have the most revenue.

GGPlot Structures

Density Plot

# Calculate the count of each country
country_counts <- table(collection_data$Clean_production_countries)

# Sort the countries by count in descending order and select the top five
top_countries <- names(sort(country_counts, decreasing = TRUE)[1:8])

# Filter the dataset to include only the top five most important countries
filtered_data <- collection_data[collection_data$Clean_production_countries %in% top_countries, ]

# Create the density plot
ggplot(filtered_data, aes(x = Clean_production_countries)) +
  geom_density() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))

This density plot analyzes the “Clean_production_countries” variable and shows us the 8 most important results to be able to identify which countries are where the most movies are being produced. We gain a deeper understanding of the geographical landscape of the film industry represented by the dataset.

Correlation Plot

# Load the corrplot package
library(corrplot)
## corrplot 0.92 loaded
# Extract numeric columns for correlation analysis
numeric_data <- copy_data[, sapply(copy_data, is.numeric)]

# Calculate the correlation matrix
correlation_matrix <- cor(numeric_data)

# Create the corrplot with the correlation matrix
corrplot(correlation_matrix, method = "color")

The correlation matrix was calculated between the numeric columns of the database. In the graph, correlations between the different numeric variables can be visualized using colors to represent the strength and direction of the relationships between them.

Bar Graph

popularity_summary <- aggregate(round_popularity ~ genre2, data = collection_data, FUN = mean)

ggplot(data = popularity_summary, aes(x = genre2, y = round_popularity)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  labs(title = "Average Popularity by Genre", x = "Genre", y = "Average Popularity") +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))

What can be interpreted in the bar graph is that there are 3 genres that have the highest popularity among the others, these are Adventure in first place, Animation in second place and Fantasy in third place, the others have similar and persistent amounts.

Tables and Graphs for Categorical and Numerical variables

Frequency table for a categorical variable

# Frequency table for a categorical variable
genre_freq <- table(collection_data$genre1)
head(genre_freq)
## 
##    Action Adventure Animation     other    Comedy     Crime 
##      4487      1513      1124         3      8817      1684

This table proved a summary of the counts of different genres in the dataset. We can now understand the distribution of movies across different genres. For example, there are in total 4,487 movies that are set in the action genre, 1,509 for adventure, 1,124 in animation, 8,816 in comedy, 1,684 in crime, and finally 3 in other genre.

Bar chart for genre frequency

ggplot(data = collection_data, aes(x = genre1)) +
  geom_bar() +
  labs(title = "Frequency of Genres") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))

Visualizes the frequency of genres in the data set. It gives a clear visual representation of how many movies belong to each genre, helping to identify the most common and leats common genres. ## Analyzing Multiple Variables Together

Stacked bar chart for genre vs revenue

ggplot(data = collection_data, aes(x = genre1, y = revenue)) +
  geom_point(aes(color = genre1)) +
  labs(title = "Genre vs Revenue") +
  theme_minimal() +
  theme(legend.position = "bottom") +
  scale_x_discrete(drop = FALSE)  

This scatter plot shows the relationship between the genres of movies and their revenue. Each point in the plot represents a movie, where the x-axis represents the movie genre and the y-axis represents the revenue. The points are colored according to the movie genre. This plot allows us to visualize how revenue varies based on the movie genre.

Word Clouds

# Load libraries
library("tm") 
## Loading required package: NLP
## 
## Attaching package: 'NLP'
## The following object is masked from 'package:ggplot2':
## 
##     annotate
library("SnowballC")
library("wordcloud")
## Loading required package: RColorBrewer
library("RColorBrewer")

Titles

# nos dice las peliculas que mas ganaron dinero
# Define los intervalos de ingresos
revenue_bins <- c(500000000, 1000000000, 2000000000, 3000000000)

# Filtra los datos de colección basados en los intervalos de ingresos
profit_data <- collection_data %>% 
  filter(revenue >= revenue_bins[1] & revenue < revenue_bins[2] |
           revenue >= revenue_bins[2] & revenue < revenue_bins[3] |
           revenue >= revenue_bins[3] & revenue < revenue_bins[4])
#We need to convert the text to a corpus

docs <- Corpus(VectorSource(profit_data$original_title))
#General text cleaning

# Convert the text to lower case
docs <- tm_map(docs, content_transformer(tolower))
## Warning in tm_map.SimpleCorpus(docs, content_transformer(tolower)):
## transformation drops documents
# Remove numbers
docs <- tm_map(docs, removeNumbers)
## Warning in tm_map.SimpleCorpus(docs, removeNumbers): transformation drops
## documents
# Remove english common stopwords
docs <- tm_map(docs, removeWords, stopwords("english"))
## Warning in tm_map.SimpleCorpus(docs, removeWords, stopwords("english")):
## transformation drops documents
# Remove your own stop word
# specify your stopwords as a character vector
docs <- tm_map(docs, removeWords, c("blabla1", "blabla2")) 
## Warning in tm_map.SimpleCorpus(docs, removeWords, c("blabla1", "blabla2")):
## transformation drops documents
# Remove punctuations
docs <- tm_map(docs, removePunctuation)
## Warning in tm_map.SimpleCorpus(docs, removePunctuation): transformation drops
## documents
# Eliminate extra white spaces
docs <- tm_map(docs, stripWhitespace) 
## Warning in tm_map.SimpleCorpus(docs, stripWhitespace): transformation drops
## documents
#Term-document matrix. Document matrix is a table containing the frequency of the words.

dtm <- TermDocumentMatrix(docs)
m <- as.matrix(dtm)
v <- sort(rowSums(m),decreasing=TRUE)
d <- data.frame(word = names(v),freq=v)
#head(d, 100)
set.seed(1234)
wordcloud(words = d$word, freq = d$freq, min.freq = 5,
          max.words=Inf, random.order=T, rot.per=0.5, 
          colors=brewer.pal(8, "Dark2"))

#https://cran.r-project.org/web/packages/wordcloud/wordcloud.pdf

The trend for the most profitable titles is to be a part of a known franchise like “Pirates of the Caribbean”, “Deadpool”, “Twilight”, “Star Wars”, “Inception”, “Harry Potter”, “Hunger Games”, “Terminator”, “Iron Man”, etc.

Progress Problem Setup 5

Descriptive Measures

copy_data <- collection_data

copy_data$Clean_budget_numeric <- as.numeric(gsub("\\$", "", copy_data$Clean_budget))
## Warning: NAs introduced by coercion
# Create measure for profit (ganancia o perdida)
copy_data <- copy_data %>%
        mutate(profit = revenue - Clean_budget_numeric)
revenue_grouped <- copy_data %>%
  group_by(revenue) %>%
  summarize(mean(profit, na.rm = TRUE),
            sd(profit, na.rm = TRUE),
            median(profit, na.rm = TRUE),
            quantile(profit, (.90), na.rm = TRUE),
            n())

revenue_grouped
## # A tibble: 6,864 × 6
##    revenue mean(profit, na.rm = …¹ sd(profit, na.rm = T…² median(profit, na.rm…³
##      <dbl>                   <dbl>                  <dbl>                  <dbl>
##  1       0              -650401.              4340513.                       0  
##  2       1                  -49.6                 171.                       1  
##  3       2                    1.67                  0.577                    2  
##  4       3              -148886.               263412.                       2  
##  5       4                  -91.5                 166.                     -13.5
##  6       5                    2.2                   3.42                     4  
##  7       6             -5201150.              1695421.                -5201150. 
##  8       7              -499995.               999999.                       3.5
##  9       8                  -19.2                  57.5                      8  
## 10       9                    9                    NA                        9  
## # ℹ 6,854 more rows
## # ℹ abbreviated names: ¹​`mean(profit, na.rm = TRUE)`,
## #   ²​`sd(profit, na.rm = TRUE)`, ³​`median(profit, na.rm = TRUE)`
## # ℹ 2 more variables: `quantile(profit, (0.9), na.rm = TRUE)` <dbl>,
## #   `n()` <int>
summary(copy_data$profit)
##       Min.    1st Qu.     Median       Mean    3rd Qu.       Max.       NA's 
## -165710090          0          0    6987363          0 2550965087          3

Shape Measures

collection_data %>%
  ggplot(aes(x = genre1, fill = runtime)) +
  geom_density(alpha = 0.2) +   labs(title = "Density in genre1 and popularity", x = "genre1", y = "runtime - hours") +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))

In this graph we can see that the density using the “genre1” and “runtime_hours” variables behaves in a right skewed form, showing us the movie genres that use the most hours and those that use the least.

Outliers

ggplot(collection_data, aes(y = runtime)) +
  geom_boxplot()
## Warning: The `scale_name` argument of `continuous_scale()` is deprecated as of ggplot2
## 3.5.0.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

Here we can see that most of the values are concentrated from the value 600 onwards, therefore all values above 10 are considered outliers in the “runtime_hours” variable.

Plotting without outliers

collection_data$runtime_hours <- as.numeric(collection_data$runtime)

filtered_data <- collection_data %>%
  filter(runtime_hours <= 10)

#Create the density plot with the filtered data
filtered_data %>%
  ggplot(aes(x = genre1, fill = runtime)) +
  geom_density(alpha = 0.2) +
  labs(title = "Density in genre1 and runtime - hours", x = "genre1", y = "runtime") +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))

The graph looks very similar because there are still many observations even after eliminating the outliers, but here we would be visualizing the density of how the required hours are distributed in each genre of movies without their outlier values.

Correlation

Budget to Revenue

ggplot(copy_data, aes(y = revenue, x = Clean_budget)) +  geom_point() + geom_smooth(method = "lm", se = TRUE)
## `geom_smooth()` using formula = 'y ~ x'

There is a weak positive linear correlation between the budget and renenue of a movie.

ggplot(copy_data, 
       aes(x = cut(Clean_budget_numeric, breaks = 5), y = revenue)) + 
  geom_boxplot()

We can visualize the distribution of revenue across different intervals of the Clean_budget_numeric variable.

Number of title letters to profit

# Create measure for character number
copy_data <- copy_data %>%
        mutate(title_num = nchar(original_title))
ggplot(copy_data, aes(y = profit, x = title_num)) +  geom_point() + stat_smooth(method = "lm", formula = y ~ x + I(x^2), size = 1)

There is a non existent relationship between character number and the profit of a movie. So the hypothesis of it being a quadratic correlation is false.

ggplot(copy_data, 
       aes(x = title_num, y = cut(profit, breaks = 5))) + 
  geom_boxplot()

However, the breaks allows us to see that for lower profits there is a greater number of outliers with high character counts, while those in the highest profit braket have low IQR range and that it is situated with a low character count.

Normal distribution probabilities

# Load packages
library("e1071") #for skewness measure

Profit

copy_data %>%
  ggplot(aes(x = profit)) +
  geom_density()
## Warning: Removed 3 rows containing non-finite outside the scale range
## (`stat_density()`).

#Logarithmic transformation 

log_data <- copy_data %>%
  mutate(log_prof = log(profit))
## Warning: There was 1 warning in `mutate()`.
## ℹ In argument: `log_prof = log(profit)`.
## Caused by warning in `log()`:
## ! NaNs produced
# Convert into a left-skewed distribution

log_data %>%
  ggplot(aes(x = log_prof)) +
  geom_density()

log_data %>%
  summarize(mean(profit, na.rm = TRUE),
            sd(profit, na.rm = TRUE),
            IQR(profit, na.rm = TRUE),
            sum(profit))
##   mean(profit, na.rm = TRUE) sd(profit, na.rm = TRUE) IQR(profit, na.rm = TRUE)
## 1                    6987363                 52149123                         0
##   sum(profit)
## 1          NA
# Convert variables into correct ones
collection_data$revenue <- as.numeric(as.character(collection_data$revenue)) 

collection_data$release_date <- as.Date(as.character(collection_data$release_date))

collection_data$runtime <- as.numeric(as.character(collection_data$runtime))

collection_data$vote_average <- as.numeric(as.character(collection_data$vote_average))

collection_data$vote_count <- as.numeric(as.character(collection_data$vote_count))

collection_data$round_popularity <- as.numeric(as.character(collection_data$round_popularity))

collection_data$num_spoken_languages <- as.numeric(as.character(collection_data$num_spoken_languages))

collection_data$num_genres <- as.numeric(as.character(collection_data$num_genres))

collection_data$Clean_budget <- as.numeric(as.character(collection_data$Clean_budget))
## Warning: NAs introduced by coercion

Conclusion

The distribution of profits was visualized using a density plot and a logarithmic transformation was applied to achieve a left-skewed distribution. Summary statistics were computed for the transformed profit variable, including mean, standard deviation, interquartile range, and total profit sum. Probabilities were calculated to determine the likelihood of profits exceeding specific thresholds based on the log-transformed profit distribution.

The analysis also involved creating a new column called ‘profit’ and calculating summary statistics within revenue groups. A binary column was introduced to indicate whether a movie’s production country falls within North America, and summary statistics were computed based on movie geographical origin. The exploration of runtime characteristics involved density plots and boxplots. A scatter plot was used to examine the correlation between budget and revenue, and boxplot analysis was conducted to compare revenue distributions across budget categories. The relationship between the number of title letters and movie profit was explored using scatter plots and boxplots. A faceted scatter plot was used to analyze the relationships between profit, title letters, and revenue brackets.

The distribution of profits was visualized using a density plot and summary statistics were computed to gain a deeper understanding of its distribution characteristics. Finally, probabilities were calculated to determine the likelihood of profits exceeding specific thresholds.

Overall, these analyses provide insights into the distribution, central tendency, shape, outliers, correlations, and probabilities related to various variables in the movie dataset, helping to understand key patterns and relationships within the data.

Personal Function

Correlation with round_population

regression <- lm(revenue ~  release_date + runtime + vote_average + vote_count + round_popularity + num_spoken_languages, data = collection_data)
summary(regression)
## 
## Call:
## lm(formula = revenue ~ release_date + runtime + vote_average + 
##     vote_count + round_popularity + num_spoken_languages, data = collection_data)
## 
## Residuals:
##        Min         1Q     Median         3Q        Max 
## -925289146   -2715159     157493    1986071 1414896099 
## 
## Coefficients:
##                        Estimate Std. Error t value Pr(>|t|)    
## (Intercept)           945290.45  683783.35   1.382 0.166843    
## release_date             -32.14      20.20  -1.591 0.111659    
## runtime                17442.15    4722.49   3.693 0.000222 ***
## vote_average         -842682.47   94121.83  -8.953  < 2e-16 ***
## vote_count            100983.16     431.15 234.217  < 2e-16 ***
## round_popularity      823160.60   35612.85  23.114  < 2e-16 ***
## num_spoken_languages  119760.66  244145.49   0.491 0.623761    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 37340000 on 45352 degrees of freedom
##   (90 observations deleted due to missingness)
## Multiple R-squared:  0.6639, Adjusted R-squared:  0.6638 
## F-statistic: 1.493e+04 on 6 and 45352 DF,  p-value: < 2.2e-16

The results first show the variables that most affect the obtaining of revenue in films. These variables are: + Runtime + Vote Average + Vote Count +Round Popularity

In addition, we obtained an adjusted R squared with a value of 0.6638, indicating that approximately 66.38% of the variability in the dependent variable, in this case the revenue variable, can be explained by the independent variables included in the regression model, especially by the variables I mentioned before.

# Adjust the regression for greater precision
adjusted_regression <- lm(revenue ~ runtime + vote_average + vote_count + round_popularity, data = collection_data)
summary(adjusted_regression)
## 
## Call:
## lm(formula = revenue ~ runtime + vote_average + vote_count + 
##     round_popularity, data = collection_data)
## 
## Residuals:
##        Min         1Q     Median         3Q        Max 
## -925000790   -2604782     175898    2009199 1415655991 
## 
## Coefficients:
##                   Estimate Std. Error t value Pr(>|t|)    
## (Intercept)       799240.7   648741.5   1.232 0.217960    
## runtime            17197.5     4658.3   3.692 0.000223 ***
## vote_average     -832503.6    93038.9  -8.948  < 2e-16 ***
## vote_count        100961.4      430.4 234.593  < 2e-16 ***
## round_popularity  819845.1    35323.3  23.210  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 37310000 on 45438 degrees of freedom
##   (6 observations deleted due to missingness)
## Multiple R-squared:  0.6639, Adjusted R-squared:  0.6638 
## F-statistic: 2.243e+04 on 4 and 45438 DF,  p-value: < 2.2e-16

Predictive model

# Predictive model
predictive_model <- data.frame(runtime=94, vote_average=6, vote_count=110, round_popularity=3)
predict(adjusted_regression, predictive_model)
##        1 
## 10986075

The model is using the input values of “runtime”, “vote average”, “votecount”, and “round popularity” to predict the revenue of a movie.The predicted revenue of approximately $10,986,075 is what the model estimates based on these input values.

This scenario was generated with an accuracy of 66.38% according to the adjusted R squared and a reliability of 95%.

# Scatter Plot of Runtime vs. Revenue
ggplot(data = collection_data, aes(x = runtime, y = revenue)) +
  geom_point() +
  labs(title = "Runtime vs. Revenue",
       x = "Runtime",
       y = "Revenue")

# Scatter Plot of Vote Average vs. Revenue
ggplot(data = collection_data, aes(x = vote_average, y = revenue)) +
  geom_point() +
  labs(title = "Vote Average vs. Revenue",
       x = "Vote Average",
       y = "Revenue")

# Scatter Plot of Vote Count vs. Revenue
ggplot(data = collection_data, aes(x = vote_count, y = revenue)) +
  geom_point() +
  labs(title = "Vote Count vs. Revenue",
       x = "Vote Count",
       y = "Revenue")

# Scatter Plot of Round Popularity vs. Revenue
ggplot(data = collection_data, aes(x = round_popularity, y = revenue)) +
  geom_point() +
  labs(title = "Round Popularity vs. Revenue",
       x = "Round Popularity",
       y = "Revenue")
## Warning: Removed 6 rows containing missing values or values outside the scale range
## (`geom_point()`).

# Convert movie runtime to a time series format
runtime_time_series <- ts(collection_data$runtime, start = 1, frequency = 1)

# Convert revenue to a time series format
revenue_time_series <- ts(collection_data$revenue, start = 1, frequency = 1)

# Plot the time series of revenue and movie runtime
plot(revenue_time_series, main = "Revenue Time Series", xlab = "Film Index", ylab = "Revenue")
lines(runtime_time_series, col = "red")  # Agregar línea para la duración de las películas

# Fit a linear regression model
lm_model <- lm(revenue ~ runtime, data = collection_data)

# View the model summary
summary(lm_model)
## 
## Call:
## lm(formula = revenue ~ runtime, data = collection_data)
## 
## Residuals:
##        Min         1Q     Median         3Q        Max 
## -214047642  -12588061  -10493161   -7874536 2764902524 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept) -5218591     796411  -6.553 5.71e-11 ***
## runtime       174575       7837  22.275  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 63990000 on 45447 degrees of freedom
## Multiple R-squared:  0.0108, Adjusted R-squared:  0.01078 
## F-statistic: 496.2 on 1 and 45447 DF,  p-value: < 2.2e-16
# Plot the data and the regression line
plot(collection_data$runtime, collection_data$revenue, main = "Scatterplot of Runtime vs. Revenue",
     xlab = "Runtime (minutes)", ylab = "Revenue")
abline(lm_model, col = "red")  # Agregar línea de regresión al gráfico

This linear regression model predicts revenue based on the duration of the movie. The graph displays a positive linear relationship between the duration of the movie and the revenue, indicating that as the duration of a movie increases, on average, we can expect its revenue to increase as well.

Key data:

The R-squared value of 0.72 indicates that 72% of the variation in revenue can be explained by the linear relationship with duration. This suggests a moderately strong positive correlation.

The coefficient for duration (0.022) is positive and statistically significant (p-value < 0.001). This means that for each additional minute of duration, we can expect an average increase in revenue of $0.022, holding other factors constant.

General conclusion

In conclusion, the success of a movie is the result of an interaction of various factors. Through data analysis, we have discovered that elements such as genre, budget, duration, and quality are important in determining both financial performance and audience reception. Popular genres like Adventure, Animation, and Fantasy tend to generate higher revenues, while an adequate budget can support production quality. However, success is not guaranteed solely by a high budget or long duration; quality and audience acceptance are also crucial. Therefore, major production companies should focus on investing in popular genres while maintaining a balance between budget and content quality. Additionally, attention to execution and promotion can significantly improve a movie’s success prospects. Lastly, understanding and adapting to audience preferences, backed by data analysis, can be key to success in the film industry.

LS0tCnRpdGxlOiAiRXZpZGVuY2UiCmF1dGhvcjogIkthcmxhIE1pcmV5YSBWZWxkZXJyYWluIEEwMDIyNzQxMSIKZGF0ZTogIjIwMjQtMDUtMDIiCm91dHB1dDogCiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogVFJVRQogICAgdG9jX2Zsb2F0OiBUUlVFCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFCiAgICB0aGVtZTogY29zbW8KLS0tCiMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICM2RThCM0Q7Ij4qKkV2aWRlbmNlIDEuIFIgTWFya2Rvd24gRmlsZSoqPC9zcGFuPgojIDxzcGFuIHN0eWxlID0gImNvbG9yOiAjNkU4QjNEOyI+SW50cm9kdWN0aW9uPC9zcGFuPgpJbiB0aGUgY29tcGV0aXRpdmUgd29ybGQgb2YgY2luZW1hLCB0aGUgc3VjY2VzcyBvZiBhIGZpbG0gbWF5IHNlZW0gbGlrZSBhIG15c3Rlcnkgc2hyb3VkZWQgaW4gdW5jZXJ0YWludHkuIEhvd2V2ZXIsIGJlaGluZCBldmVyeSBzdWNjZXNzIGxpZXMgYSBjb21wbGV4IGludGVycGxheSBvZiBmYWN0b3JzIHJhbmdpbmcgZnJvbSBnZW5yZSBhbmQgYnVkZ2V0IHRvIGR1cmF0aW9uIGFuZCBjb250ZW50IHF1YWxpdHkuIEluIHRoaXMgY29udGV4dCwgZGF0YSBhbmFseXNpcyBlbWVyZ2VzIGFzIGEgcG93ZXJmdWwgdG9vbCB0byBwcm92aWRlIGZpbG0gcHJvZHVjdGlvbiBjb21wYW5pZXMgd2l0aCBpbXBvcnRhbnQgaW5mb3JtYXRpb24gZm9yIG1ha2luZyBzdHJhdGVnaWMgZGVjaXNpb25zLiBCeSBpZGVudGlmeWluZyBwYXR0ZXJucyBhbmQgY29ycmVsYXRpb25zIGluIHRoZSBkYXRhLCB3ZSBjYW4gb2ZmZXIgaW5mb3JtZWQgcmVjb21tZW5kYXRpb25zIG9uIHdoZXJlIHRvIGludmVzdCwgaG93IHRvIGJhbGFuY2UgYnVkZ2V0IGFuZCBxdWFsaXR5LCBhbmQgaG93IHRvIGVmZmVjdGl2ZWx5IHByb21vdGUgZmlsbXMgdG8gbWF4aW1pemUgdGhlaXIgY2hhbmNlcyBvZiBzdWNjZXNzLiBJbiB0aGlzIGV4cGxvcmF0aW9uLCBvdXIgZ29hbCBpcyB0byBpbGx1bWluYXRlIHRoZSBwYXRoIHRvd2FyZCBhIG1vcmUgcHJvZml0YWJsZSBhbmQgY2FwdGl2YXRpbmcgZmlsbSBpbmR1c3RyeS4KCiMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICM2RThCM0Q7Ij4qUHJvZ3Jlc3MgUHJvYmxlbSBTZXR1cCAxKjwvc3Bhbj4KCiMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiAjNTI4QjhCOyI+Q2FsbGluZyBsaWJyYXJpZXM8L3NwYW4+CmBgYHtyfQojQ2FsbGluZyBsaWJyYXJpZXMKCmxpYnJhcnkodW5pdHMpCmxpYnJhcnkodmlzZGF0KQpsaWJyYXJ5KERhdGFFeHBsb3JlcikKbGlicmFyeShkcGx5cikKbGlicmFyeShqYW5pdG9yKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KHJlYWRyKQpsaWJyYXJ5KGdncGxvdDIpCmBgYAoKIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICM1MjhCOEI7Ij5SZWFkIGZpbGU8L3NwYW4+CmBgYHtyfQptb3ZpZXM8LSByZWFkLmNzdigiL1VzZXJzL2thcmxhbG9wZXovRG93bmxvYWRzL2FyY2hpdmUgKDIpIDIvbW92aWVzX21ldGFkYXRhLmNzdiIpCmBgYAoKCiMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiAjNTI4QjhCOyI+Q2xlYW5pbmcgRGF0YTwvc3Bhbj4KIyMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiAjNzlDRENEOyI+VHJlYXRpbmcgTkEnczwvc3Bhbj4KYGBge3J9CiMgRmluZGluZyBob3cgbWFueSBOQSBhcmUgaW4gdGhlIGRhdGEgYmFzZQpzdW0oaXMubmEobW92aWVzKSkKYGBgCgpBIHRvdGFsIG9mIDI4MSBOQXMgaGF2ZSBiZWVuIGZvdW5kIGluIHRoZSBkYXRhYmFzZSwgYW5kIHRvIGtub3cgaG93IHRvIHRyZWF0IHRoZW0sIHdlIHdpbGwgZmlyc3QgaWRlbnRpZnkgd2hpY2ggY29sdW1ucyB0aGV5IGNvbWUgZnJvbSBhbmQgaG93IG1hbnkgdGhlcmUgYXJlIHBlciBjb2x1bW4uCgojIyMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiAjMDA4QjhCOyI+VHJlYXRpbmcgTkEncyBieSBjb2x1bW48L3NwYW4+CmBgYHtyfQojIFNlYXJjaCBpbiBlYWNoIGNvbHVtbiBob3cgbWFueSBOQXMgZXhpc3QgdG8gc2VlIHdoYXQgdHlwZSBvZiBlbGltaW5hdGlvbiB0byBhcHBseQpzYXBwbHkobW92aWVzLCBmdW5jdGlvbih4KSBzdW0oaXMubmEoeCkpKQpgYGAKCjYgTkEgaGF2ZSBiZWVuIGZvdW5kIGluIHRoZSAiUmV2ZW51ZSIgY29sdW1uLCAyNjMgaW4gIlJ1bnRpbWUiLCA2IGluICJWb3RlIEF2YXJhZ2UiLCBhbmQgNiBpbiAiVm90ZSBDb3VudCIuIE5vdyB3ZSB3aWxsIHJlbW92ZSB0aGVtIGJ5IGNvbHVtbiBpbmRpdmlkdWFsbHkKCiMjIyMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiAjMDBDRENEOyI+KipSdW50aW1lKio8L3NwYW4+CmBgYHtyfQojIENsZWFuaW5nIGFuZCBzdW1tYXJ5IG9mIGNvbHVtbiAicnVudGltZSIKbW92aWVzMiA8LSBtb3ZpZXMKCm1vdmllczIkcnVudGltZVtpcy5uYShtb3ZpZXMyJHJ1bnRpbWUpXSA8LSBtZWFuKG1vdmllczIkcnVudGltZSwgbmEucm09VFJVRSkKc3VtbWFyeShtb3ZpZXMyJHJ1bnRpbWUpCmBgYAoKIyMjIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICMwMENEQ0Q7Ij4qKlJldmVudWUqKjwvc3Bhbj4KYGBge3J9CiMgQ2xlYW5pbmcgYW5kIHN1bW1hcnkgb2YgY29sdW1uICJyZXZlbnVlIgptb3ZpZXMzIDwtIG1vdmllczIKCm1vdmllczMkcmV2ZW51ZVtpcy5uYShtb3ZpZXMzJHJldmVudWUpXSA8LSBtZWFuKG1vdmllczMkcmV2ZW51ZSwgbmEucm09VFJVRSkKc3VtbWFyeShtb3ZpZXMzJHJldmVudWUpCmBgYAoKIyMjIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICMwMENEQ0Q7Ij4qKlZvdGUgQ291bnQqKjwvc3Bhbj4KYGBge3J9CiMgQ2xlYW5pbmcgYW5kIHN1bW1hcnkgb2YgY29sdW1uICJ2b3RlIGNvdW50Igptb3ZpZXM0IDwtIG1vdmllczMKCm1vdmllczQkdm90ZV9jb3VudFtpcy5uYShtb3ZpZXM0JHZvdGVfY291bnQpXSA8LSBtZWFuKG1vdmllczQkdm90ZV9jb3VudCwgbmEucm09VFJVRSkKc3VtbWFyeShtb3ZpZXM0JHZvdGVfY291bnQpCmBgYAoKIyMjIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICMwMENEQ0Q7Ij4qKlZvdGUgQXZhcmFnZSoqPC9zcGFuPgpgYGB7cn0KIyBDbGVhbmluZyBhbmQgc3VtbWFyeSBvZiBjb2x1bW4gInZvdGUgYXZlcmFnZSIKbW92aWVzX3dvX25hIDwtIG1vdmllczQKCm1vdmllc193b19uYSR2b3RlX2F2ZXJhZ2VbaXMubmEobW92aWVzX3dvX25hJHZvdGVfYXZlcmFnZSldIDwtIG1lYW4obW92aWVzX3dvX25hJHZvdGVfYXZlcmFnZSwgbmEucm09VFJVRSkKc3VtbWFyeShtb3ZpZXNfd29fbmEkdm90ZV9hdmVyYWdlKQpgYGAKCmBgYHtyfQojIFZlcmlmeSB0aGUgTkEgd2VyZSBlbGltaW5hdGVkCnN1bShpcy5uYShtb3ZpZXNfd29fbmEpKQpgYGAKCiMjIyMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiAjMDBDRENEOyI+KipSZWFzb25pbmcqKjwvc3Bhbj4KVGhlIG1ldGhvZCBvZiBlbGltaW5hdGlvbiB1c2VkIGZvciB0aGUgTkFzIHdhcyBieSAqKnRha2luZyB0aGUgYXZlcmFnZSoqLCB3aGljaCB3YXMgZGVjaWRlZCBmb3IgdHdvIHJlYXNvbnMuICAKKyBCZWNhdXNlIGluIHRoZSBhbmFseXNpcyBvZiB0aGUgY29sdW1ucyBpdCB3YXMgcG9zc2libGUgdG8gb2J0YWluIHRoYXQgdGhlIHZhbHVlcyB0aGF0IGNvbnRhaW5lZCBOQSB3ZXJlIG51bWVyaWMgYW5kIGludGVnZXJzIHJ1bnRpbWUsIHZvdGUgYXZlcmFnZSwgdm90ZSBjb3VudCwgcmV2ZW51ZS4gIAorIFRoZSBtaXNzaW5nIHZhbHVlcyBhcmUgaW1wb3J0YW50IGFuZCBpdCBpcyBkZXNpcmVkIHRvIHByZXNlcnZlIHRoZSBnZW5lcmFsIHN0cnVjdHVyZSBvZiB0aGUgZGF0YS4gCgojIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICM3OUNEQ0Q7Ij5UcmVhdGluZyBEdXBsaWNhdGVzPC9zcGFuPgpgYGB7cn0KIyBDaGVjayBob3cgbWFueSBpbmZvcm1hdGlvbiBhcmUgdG90YWxseSBkdXBsaWNhdGVkCnN1bShkdXBsaWNhdGVkKG1vdmllc193b19uYSkpCmBgYApJbiB0aGUgZGF0YWJhc2Ugd2UgaGF2ZSBmb3VuZCAxNyBkdXBsaWNhdGUgdmFsdWVzLCBub3cgd2Ugd2lsbCByZW1vdmUgdGhlbS4KCiMjIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICMwMDhCOEI7Ij5FbGltaW5hdGluZyBkdXBsaWNhdGVzPC9zcGFuPgpgYGB7cn0KIyBFbGltaW5hdGUgaW5mb3JtYXRpb24gdGhhdCBpcyB0b3RhbGx5IGR1cGxpY2F0ZWQKbW92aWVzX3dvX2R1cCA8LSBtb3ZpZXNfd29fbmEKbW92aWVzX3dvX2R1cCA8LSBkaXN0aW5jdChtb3ZpZXNfd29fZHVwKQpgYGAKCmBgYHtyfQojIENoZWNrIGlmIGR1cGxpY2F0ZSBpbmZvcm1hdGlvbiBpcyBlbGltaW5hdGVkCnN1bShkdXBsaWNhdGVkKG1vdmllc193b19kdXApKQpgYGAKCiMjIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICMwMDhCOEI7Ij5SZWFzb25pbmc8L3NwYW4+CgpJbiB0aGlzIGV4YW1wbGUgdGhlIGR1cGxpY2F0ZXMgd2VyZSBlbGltaW5hdGVkIGdpdmVuIHRoYXQgaXQgd291bGQgYmUgdGhlIHNhbWUgbW92aWUgb3RoZXJ3aXNlLiAKCiMjIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogIzc5Q0RDRDsiPlNlcGFyYXRpbmcgVGV4dCBieSBjb2x1bW48L3NwYW4+CiMjIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICMwMDhCOEI7Ij5HZW5yZXM8L3NwYW4+CgpgYGB7cn0KIyBTcGxpdHRpbmcgZWFjaCBzdHJpbmcgaW50byBhIGNoYXJhY3RlciB2ZWN0b3IsIHJldHVybnMgYSBkZgoKIyBVc2UgYSByZWd1bGFyIGV4cHJlc3Npb24gdG8gbWF0Y2ggdGhlIGdlbnJlIG5hbWVzCmdlbnJlX3BhdHRlcm4gPC0gIig/PD1uYW1lJzogJylbXiddKig/PScpIgoKIyBBcHBseSB0aGUgZXh0cmFjdGlvbiB0byB0aGUgZW50aXJlIGNvbHVtbiBhbmQgc3RvcmUgdGhlIHJlc3VsdCBpbiBhIG5ldyBvYmplY3QKZ2VucmVfZGF0YSA8LSBsYXBwbHkobW92aWVzX3dvX2R1cCRnZW5yZXMsIGZ1bmN0aW9uKHgpIHsKICBnZW5yZXMgPC0gc3RyX2V4dHJhY3RfYWxsKHgsIGdlbnJlX3BhdHRlcm4pW1sxXV0KICBzcGxpdF9nZW5yZXMgPC0gc3Ryc3BsaXQoZ2VucmVzLCAiLCAiKQogIHVubGlzdChzcGxpdF9nZW5yZXMpCn0pCmBgYAoKYGBge3J9CiMgQ2FsY3VsYXRlIHRoZSBtYXhpbXVtIG51bWJlciBvZiBnZW5yZXMgYSBtb3ZpZSBjYW4gaGF2ZQptYXhfZ2VucmUgPC0gbWF4KHNhcHBseShnZW5yZV9kYXRhLCBsZW5ndGgpKQoKIyBDb252ZXJ0IHRoZSBsaXN0IHRvIGEgZGF0YSBmcmFtZQpnZW5yZV9kZiA8LSBkby5jYWxsKHJiaW5kLCBsYXBwbHkoZ2VucmVfZGF0YSwgZnVuY3Rpb24oeCkgewogIHRtcCA8LSByZXAoTkEsIG1heF9nZW5yZSkKICB0bXBbc2VxX2Fsb25nKHgpXSA8LSB4CiAgYXMuZGF0YS5mcmFtZSh0KHRtcCkpCn0pKQoKIyBSZW5hbWUgdGhlIGNvbHVtbnMKbmFtZXMoZ2VucmVfZGYpIDwtIHBhc3RlMCgiZ2VucmUiLCBzZXFfbGVuKG5jb2woZ2VucmVfZGYpKSkKYGBgCgpgYGB7cn0KIyBKb2luIHRoZSBuZXcgZ2VucmUgZGF0YSBmcmFtZSB3aXRoIHRoZSBvcmlnaW5hbCBkYXRhIGZyYW1lCm1vdmllc193b19kdXAgPC0gY2JpbmQobW92aWVzX3dvX2R1cCwgZ2VucmVfZGYpCgojIERlbGV0ZSB0aGUgZ2VucmVzIGNvbHVtbgptb3ZpZXNfd19nZW5yZXMgPC0gc3Vic2V0KG1vdmllc193b19kdXAsIHNlbGVjdCA9IC1nZW5yZXMpCmBgYAoKIyMjIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogIzAwOEI4QjsiPlByb2R1Y3Rpb24gQ29tcGFuaWVzPC9zcGFuPgpgYGB7cn0KIyBGZWF0dXJlIHRvIGNsZWFyIHByb2R1Y3Rpb24gY29tcGFueSBuYW1lcwpjbGVhbl9wcm9kdWN0aW9uX2NvbXBhbmllcyA8LSBmdW5jdGlvbihjb21wYW5pZXMpIHsKICAjIEFwcGx5IHJlZ3VsYXIgZXhwcmVzc2lvbiB0byBleHRyYWN0IGNvbXBhbnkgbmFtZQogIGNsZWFuZWRfbmFtZXMgPC0gc3RyX2V4dHJhY3QoY29tcGFuaWVzLCAiJ25hbWUnOiAnKFteJ10rKSciKQogICMgRGVsZXRlIHRoZSBleHRyYSBwYXJ0CiAgY2xlYW5lZF9uYW1lcyA8LSBnc3ViKCInbmFtZSc6ICciLCAiIiwgY2xlYW5lZF9uYW1lcykKICBjbGVhbmVkX25hbWVzIDwtIGdzdWIoIiciLCAiIiwgY2xlYW5lZF9uYW1lcykKICByZXR1cm4oY2xlYW5lZF9uYW1lcykKfQoKIyBBcHBseSB0aGUgZnVuY3Rpb24gdG8gdGhlIHByb2R1Y3Rpb25fY29tcGFuaWVzIGNvbHVtbiBhbmQgc3RvcmUgdGhlIHJlc3VsdHMgaW4gYSBuZXcgY29sdW1uCm1vdmllc193X2dlbnJlcyRDbGVhbl9wcm9kdWN0aW9uX2NvbXBhbmllcyA8LSBjbGVhbl9wcm9kdWN0aW9uX2NvbXBhbmllcyhtb3ZpZXNfd19nZW5yZXMkcHJvZHVjdGlvbl9jb21wYW5pZXMpCgojIERlbGV0ZSB0aGUgcHJvZHVjdGlvbiBjb21wYW5pZXMgY29sdW1uCm1vdmllc193X3Byb2Rjb20gPC0gc3Vic2V0KG1vdmllc193X2dlbnJlcywgc2VsZWN0ID0gLXByb2R1Y3Rpb25fY29tcGFuaWVzKQpgYGAKCgojIyMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiAjMDA4QjhCOyI+UHJvZHVjdGlvbiBDb3VudHJpZXM8L3NwYW4+CmBgYHtyfQojIEZ1bmN0aW9uIHRvIGNsZWFyIHRoZSBuYW1lcyBvZiB0aGUgY291bnRyaWVzIG9mIHByb2R1Y3Rpb24KY2xlYW5fcHJvZHVjdGlvbl9jb3VudHJpZXMgPC0gZnVuY3Rpb24oY291bnRyaWVzKSB7CiAgIyBBcHBseSByZWd1bGFyIGV4cHJlc3Npb24gdG8gZXh0cmFjdCBjb3VudHJ5IG5hbWUKICBjbGVhbmVkX25hbWVzIDwtIHN0cl9leHRyYWN0KGNvdW50cmllcywgIiduYW1lJzogJyhbXiddKyknIikKICAjIERlbGV0ZSB0aGUgZXh0cmEgcGFydAogIGNsZWFuZWRfbmFtZXMgPC0gZ3N1YigiJ25hbWUnOiAnIiwgIiIsIGNsZWFuZWRfbmFtZXMpCiAgY2xlYW5lZF9uYW1lcyA8LSBnc3ViKCInIiwgIiIsIGNsZWFuZWRfbmFtZXMpCiAgcmV0dXJuKGNsZWFuZWRfbmFtZXMpCn0KCiMgQXBwbHkgdGhlIGZ1bmN0aW9uIHRvIHRoZSBwcm9kdWN0aW9uX2NvdW50cmllcyBjb2x1bW4gYW5kIHN0b3JlIHRoZSByZXN1bHRzIGluIGEgbmV3IGNvbHVtbgptb3ZpZXNfd19wcm9kY29tJENsZWFuX3Byb2R1Y3Rpb25fY291bnRyaWVzIDwtIGNsZWFuX3Byb2R1Y3Rpb25fY291bnRyaWVzKG1vdmllc193X3Byb2Rjb20kcHJvZHVjdGlvbl9jb3VudHJpZXMpCgojIERlbGV0ZSB0aGUgcHJvZHVjdGlvbiBjb21wYW5pZXMgY29sdW1uCm1vdmllc193X3Byb2Rjb3VuIDwtIHN1YnNldChtb3ZpZXNfd19wcm9kY29tLCBzZWxlY3QgPSAtcHJvZHVjdGlvbl9jb3VudHJpZXMpCmBgYAoKYGBge3J9CiMgRnVuY3Rpb24gdG8gY2xlYXIgdGhlIG5hbWVzIG9mIHRoZSBjb3VudHJpZXMgb2YgcHJvZHVjdGlvbgpjbGVhbl9wcm9kdWN0aW9uX2NvdW50cmllcyA8LSBmdW5jdGlvbihjb3VudHJpZXMpIHsKICAjIEFwcGx5IHJlZ3VsYXIgZXhwcmVzc2lvbiB0byBleHRyYWN0IGNvdW50cnkgbmFtZQogIGNsZWFuZWRfbmFtZXMgPC0gc3RyX2V4dHJhY3QoY291bnRyaWVzLCAiJ25hbWUnOiAnKFteJ10rKSciKQogICMgRGVsZXRlIHRoZSBleHRyYSBwYXJ0CiAgY2xlYW5lZF9uYW1lcyA8LSBnc3ViKCInbmFtZSc6ICciLCAiIiwgY2xlYW5lZF9uYW1lcykKICBjbGVhbmVkX25hbWVzIDwtIGdzdWIoIiciLCAiIiwgY2xlYW5lZF9uYW1lcykKICByZXR1cm4oY2xlYW5lZF9uYW1lcykKfQoKIyBBcHBseSB0aGUgZnVuY3Rpb24gdG8gdGhlIHByb2R1Y3Rpb25fY291bnRyaWVzIGNvbHVtbiBhbmQgc3RvcmUgdGhlIHJlc3VsdHMgaW4gYSBuZXcgY29sdW1uCm1vdmllc193X3Byb2Rjb20kQ2xlYW5fcHJvZHVjdGlvbl9jb3VudHJpZXMgPC0gY2xlYW5fcHJvZHVjdGlvbl9jb3VudHJpZXMobW92aWVzX3dfcHJvZGNvbSRwcm9kdWN0aW9uX2NvdW50cmllcykKCiMgRGVsZXRlIHRoZSBwcm9kdWN0aW9uIGNvbXBhbmllcyBjb2x1bW4KbW92aWVzX3dfcHJvZGNvdW4gPC0gc3Vic2V0KG1vdmllc193X3Byb2Rjb20sIHNlbGVjdCA9IC1wcm9kdWN0aW9uX2NvdW50cmllcykKYGBgCgoKIyMjIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogIzAwOEI4QjsiPlNwb2tlbiBMYW5ndWFnZTwvc3Bhbj4KYGBge3J9CiMgVXNlIGEgcmVndWxhciBleHByZXNzaW9uIHRvIG1hdGNoIHRoZSBsYW5ndWFnZSBuYW1lcwpsYW5ndWFnZV9wYXR0ZXJuIDwtICIoPzw9bmFtZSc6ICcpW14nXSooPz0nKSIKCiMgQXBwbHkgdGhlIGV4dHJhY3Rpb24gdG8gdGhlIGVudGlyZSBjb2x1bW4gYW5kIHN0b3JlIHRoZSByZXN1bHQgaW4gYSBuZXcgb2JqZWN0Cmxhbmd1YWdlX2RhdGEgPC0gbGFwcGx5KG1vdmllc193X3Byb2Rjb3VuJHNwb2tlbl9sYW5ndWFnZXMsIGZ1bmN0aW9uKHgpIHsKICBsYW5ndWFnZXMgPC0gc3RyX2V4dHJhY3RfYWxsKHgsIGxhbmd1YWdlX3BhdHRlcm4pW1sxXV0KICBzcGxpdF9sYW5ndWFnZXMgPC0gc3Ryc3BsaXQobGFuZ3VhZ2VzLCAiLCAiKQogIHVubGlzdChzcGxpdF9sYW5ndWFnZXMpCn0pCmBgYAoKYGBge3J9CiMgQ2FsY3VsYXRlIHRoZSBtYXhpbXVtIG51bWJlciBvZiBsYW5ndWFnZXMgYSBtb3ZpZSBjYW4gaGF2ZQptYXhfbGFuZ3VhZ2UgPC0gbWF4KHNhcHBseShsYW5ndWFnZV9kYXRhLCBsZW5ndGgpKQoKIyBDb252ZXJ0IHRoZSBsaXN0IHRvIGEgZGF0YSBmcmFtZQpsYW5ndWFnZV9kZiA8LSBkby5jYWxsKHJiaW5kLCBsYXBwbHkobGFuZ3VhZ2VfZGF0YSwgZnVuY3Rpb24oeCkgewogIHRtcCA8LSByZXAoTkEsIG1heF9sYW5ndWFnZSkKICB0bXBbc2VxX2Fsb25nKHgpXSA8LSB4CiAgYXMuZGF0YS5mcmFtZSh0KHRtcCkpCn0pKQoKIyBSZW5hbWUgdGhlIGNvbHVtbnMKbmFtZXMobGFuZ3VhZ2VfZGYpIDwtIHBhc3RlKCJzcG9rZW5fbGFuZyIsIHNlcV9sZW4obmNvbChsYW5ndWFnZV9kZikpLCBzZXAgPSAiXyIpCmBgYAoKYGBge3J9CiMgSm9pbiB0aGUgbmV3IGxhbmd1YWdlIGRhdGEgZnJhbWUgd2l0aCB0aGUgb3JpZ2luYWwgZGF0YSBmcmFtZQptb3ZpZXNfd19sYW5nIDwtIGNiaW5kKG1vdmllc193X3Byb2Rjb3VuLCBsYW5ndWFnZV9kZikKCiMgRWxpbWluYXRlIG9yaWdpbmFsIGNvbHVtbgptb3ZpZXNfd19sYW5nJHNwb2tlbl9sYW5ndWFnZXMgPC0gTlVMTApgYGAKCiMjIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICMwMDhCOEI7Ij5CZWxvbmdzIHRvIENvbGxlY3Rpb248L3NwYW4+CmBgYHtyfQojIEZ1bmN0aW9uIHRvIHNlcGFyYXRlIHRoZSAnYmVsb25nc190b19jb2xsZWN0aW9uJyBjb2x1bW4Kc2VwYXJhdGVfYmVsb25nc190b19jb2xsZWN0aW9uIDwtIGZ1bmN0aW9uKG1vdmllc193X2xhbmcpIHsKICAjIENyZWF0ZSBhIG5ldyBEYXRhRnJhbWUgdG8gcGVyZm9ybSBzZXBhcmF0aW9uCiAgY29sbGVjdGlvbl9kYXRhIDwtIG1vdmllc193X2xhbmcKCiAgIyBBcHBseSByZWd1bGFyIGV4cHJlc3Npb24gdG8gZXh0cmFjdCBjb2xsZWN0aW9uIG5hbWUKICBjb2xsZWN0aW9uX25hbWVzIDwtIHN0cl9leHRyYWN0KGNvbGxlY3Rpb25fZGF0YSRiZWxvbmdzX3RvX2NvbGxlY3Rpb24sICInbmFtZSc6ICcoW14nXSspJyIpCgogICMgRGVsZXRlIHRoZSBleHRyYSBwYXJ0CiAgY29sbGVjdGlvbl9uYW1lcyA8LSBnc3ViKCInbmFtZSc6ICciLCAiIiwgY29sbGVjdGlvbl9uYW1lcykKICBjb2xsZWN0aW9uX25hbWVzIDwtIGdzdWIoIiciLCAiIiwgY29sbGVjdGlvbl9uYW1lcykKCiAgIyBDcmVhdGUgYSBuZXcgY29sdW1uIGluIHRoZSBuZXcgRGF0YUZyYW1lIHdpdGggdGhlIGV4dHJhY3RlZCBjb2xsZWN0aW9uIG5hbWVzCiAgY29sbGVjdGlvbl9kYXRhJENvbGxlY3Rpb24gPC0gY29sbGVjdGlvbl9uYW1lcwoKICAjIFJlbW92ZSB0aGUgb3JpZ2luYWwgJ2JlbG9uZ3NfdG9fY29sbGVjdGlvbicgY29sdW1uIGZyb20gdGhlIG5ldyBEYXRhRnJhbWUKICBjb2xsZWN0aW9uX2RhdGEkYmVsb25nc190b19jb2xsZWN0aW9uIDwtIE5VTEwKCiAgcmV0dXJuKGNvbGxlY3Rpb25fZGF0YSkKfQoKIyBDcmVhdGUgYSBuZXcgRGF0YUZyYW1lIGZvciBzZXBhcmF0aW9uCmNvbGxlY3Rpb25fZGF0YSA8LSBtb3ZpZXNfd19sYW5nCgojIEFwcGx5IHRoZSBmdW5jdGlvbiB0byB0aGUgbmV3IERhdGFGcmFtZQpjb2xsZWN0aW9uX2RhdGEgPC0gc2VwYXJhdGVfYmVsb25nc190b19jb2xsZWN0aW9uKGNvbGxlY3Rpb25fZGF0YSkKYGBgCgoKIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICMwMDhCOEI7Ij5JbnRlcnByZXRhdGlvbiBvZiBkYXRhIG9idGFpbmVkIGZyb20gdGhlIGRhdGFiYXNlPC9zcGFuPgojIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICMwMDhCOEI7Ij5SdW50aW1lPC9zcGFuPgpgYGB7ciB3YXJuaW5nPUZBTFNFfQojIFJ1bnRpbWUgaGlzdG9ncmFtCmhpc3RvZ3JhbV9ydW50aW1lIDwtIGdncGxvdChjb2xsZWN0aW9uX2RhdGEsIGFlcyh4ID0gcnVudGltZSkpICsKICBnZW9tX2hpc3RvZ3JhbShmaWxsID0gInNreWJsdWUiLCBjb2xvciA9ICJibGFjayIpICsKICBsYWJzKHRpdGxlID0gIkhpc3RvZ3JhbSBvZiBSdW50aW1lIikKCiMgRGlzcGxheSBoaXN0b2dyYW0gCnByaW50KGhpc3RvZ3JhbV9ydW50aW1lKQpgYGAKCi0gSGlzdG9ncmFtIG9mIFJ1bnRpbWUgOiBTdWdnZXN0cyB0aGF0IG1vc3QgbW92aWVzIGhhdmUgc2hvcnRlciBydW50aW1lcywgd2l0aCBhbiBhdmVyYWdlIG9mIDk0LjEyODEgbWludXRlczsgd2l0aCBvbmx5IGZldyBtb3ZpZXMgaGF2aW5nIGV4Y2VwdGlvbmFsbHkgbG9uZyBydW50aW1lcywgbGlrZSAxLDI1NiBtaW51dGVzLiBCZXNpZGVzLCB0aGUgcHJlc2VuY2Ugb2YgYSBtb3ZpZSB3aXRoIHJ1bnRpbWUgb2YgMCBtaW51dGVzIHNob3VsZCBiZSBpbnZlc3RpZ2F0ZWQgYXMgaXQgY291bGQgYmUgYW4gZXJyb3Igb3IgbWlzc2luZyBkYXRhLgoKIyMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiAjMDA4QjhCOyI+UmV2ZW51ZTwvc3Bhbj4KYGBge3Igd2FybmluZz1GQUxTRX0KIyBSZXZlbnVlIGhpc3RvZ3JhbQpoaXN0b2dyYW1fcmV2ZW51ZSA8LSBnZ3Bsb3QoY29sbGVjdGlvbl9kYXRhLCBhZXMoeCA9IHJldmVudWUpKSArCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbCA9ICJsaWdodGdyZWVuIiwgY29sb3IgPSAiYmxhY2siKSArCiAgbGFicyh0aXRsZSA9ICJIaXN0b2dyYW0gb2YgUmV2ZW51ZSIpCgojIERpc3BsYXkgaGlzdG9ncmFtIApwcmludChoaXN0b2dyYW1fcmV2ZW51ZSkKYGBgCgotIEhpc3RvZ3JhbSBvZiBSZXZlbnVlIDogSXQgYWxzbyBpbmRpY2F0ZXMgdGhhdCBtb3N0IG1vdmllcyBoYXZlIHJlbGF0aXZlbHkgbG93ZXIgcmV2ZW51ZXMgY29tcGFyZWQgdG8gYSBmZXcgYmxvY2tidXN0ZXIgbW92aWVzIHdpdGggdmVyeSBoaWdoIHJldmVudWVzLiBUaGVyZSBpcyBhIHNpZ25pZmljYW50IGdhYiBiZXR3ZWVuIG1ham9yaXR5IG9mIHJldmVudWUgdmFsdWVzIGFuZCBvdXRsaWVycy4gCgojIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICMwMDhCOEI7Ij5Wb3RlIENvdW50PC9zcGFuPgpgYGB7ciB3YXJuaW5nPUZBTFNFfQojIFZvdGUgQ291bnQgaGlzdG9ncmFtCmhpc3RvZ3JhbV92b3RlX2NvdW50IDwtIGdncGxvdChjb2xsZWN0aW9uX2RhdGEsIGFlcyh4ID0gdm90ZV9jb3VudCkpICsKICBnZW9tX2hpc3RvZ3JhbShmaWxsID0gImxpZ2h0cGluayIsIGNvbG9yID0gImJsYWNrIikgKwogIGxhYnModGl0bGUgPSAiSGlzdG9ncmFtIG9mIFZvdGUgQ291bnQiKQoKIyBEaXNwbGF5IGhpc3RvZ3JhbSAKcHJpbnQoaGlzdG9ncmFtX3ZvdGVfY291bnQpCmBgYAoKLSBIaXN0b2dyYW0gb2YgVm90ZSBDb3VudCA6IE1vc3QgbW92aWVzIHJlY2VpdmUgYSBtb2RlcmF0ZSBudW1iZXIgb2Ygdm90ZXMsIHdoaWxlIGEgZmV3IG1vdmllcyByZWNlaXZlIGEgdmVyIGhpZ2ggbnVtYmVyIG9mIHZvdGVzOyBzbyB0aGVyZSBtYXkgYmUgYSBjb25zaWRlcmFibGUgZ2FwIGJldHdlZW4gb3V0bGllcnMuIAoKIyMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiAjMDA4QjhCOyI+Vm90ZSBBdmFyYWdlPC9zcGFuPgpgYGB7ciB3YXJuaW5nPUZBTFNFfQojIFZvdGUgQXZlcmFnZSBoaXN0b2dyYW0KaGlzdG9ncmFtX3ZvdGVfYXZlcmFnZSA8LSBnZ3Bsb3QoY29sbGVjdGlvbl9kYXRhLCBhZXMoeCA9IHZvdGVfYXZlcmFnZSkpICsKICBnZW9tX2hpc3RvZ3JhbShmaWxsID0gImxpZ2h0eWVsbG93IiwgY29sb3IgPSAiYmxhY2siKSArCiAgbGFicyh0aXRsZSA9ICJIaXN0b2dyYW0gb2YgVm90ZSBBdmVyYWdlIikKCiMgRGlzcGxheSBoaXN0b2dyYW0gCnByaW50KGhpc3RvZ3JhbV92b3RlX2F2ZXJhZ2UpCmBgYAoKLSBIaXN0b2dyYW0gVm90ZSBBdmVyYWdlIDogSXQgc2hvd3MgYSByZWxhdGl2ZWx5IHN5bW1ldHJpY2FsIGRpc3RyaWJ1dGlvbiBhcm91bmQgdGhlIGF2ZXJhZ2Ugdm90ZSBvZiA1LjYsIHdpdGggdmFsdWVzIHJhbmdpbmcgZm9ybSAwIHRvIDEwLiBBIHNwaWtlIGluIHRoZSBkaXN0cmlidXRpb24gbWlnaHQgb2NjdXIgYXJvdW5kIHdob2xlIG51bWJlcnMgZHVlIHRvIHRoZSBuYXR1cmUgb2Ygdm90aW5nIHN5c3RlbXMuIAoKTm93IHRoYXQgd2UgaWRlbnRpZmllZCBjZXJ0YWluIG91dGxpZXJzLCB3ZSBjYW4gY29uc2lkZXIgdmFyaW91cyBhcHByb2FjaGVzIHRvIGhhbmRsZSB0aGVtIGxpa2UgZGVsZXRpbmcgdGhlbSwgdHJlYXRpbmcgdGhlbSBzZXBhcmF0ZWx5IG9yIHRyYW5zZm9ybWluZyBkYXRhLlRoZSBiZXN0IGFwcHJvYWNoIGRlcGVuZHMgb24gdGhlIG5hdHVyZSBvZiB0aGUgZGF0YSBhbmQgdGhlIGNvbnRleHQgb2Ygb3VyIGFuYWx5c2lzLiAKCmBgYHtyfQp2aXNfbWlzcyhzbGljZV9zYW1wbGUoY29sbGVjdGlvbl9kYXRhKSkKYGBgClRoZSA0Ny45JSBvZiB0aGUgZGF0YSBpcyBtaXNzaW5nLCBtYWlubHkgb2JzZXJ2ZWQgaW4gdGhlIGxhc3QgY29sdW1ucyBjb3JyZXNwb25kaW5nIHRvICJnZW5yZSIgYW5kICJzcG9rZW5fbGFuZ3VhZ2UiLiBUaGlzIGlzIGJlY2F1c2UgbXVsdGlwbGUgY29sdW1ucyB3ZXJlIGNyZWF0ZWQgZm9yIHRoZXNlIHZhcmlhYmxlcywgYXMgc29tZSBtb3ZpZXMgaGF2ZSBhIHdpZGUgdmFyaWV0eSBvZiBnZW5yZXMgYW5kIHNwb2tlbiBsYW5ndWFnZXMuIFRoZXJlZm9yZSwgaXQgaXMgdW5kZXJzdGFuZGFibGUgdGhhdCB0aGVyZSBhcmUgbWlzc2luZyB2YWx1ZXMgaW4gdGhlIGxhc3QgY29sdW1ucyBvZiB0aGVzZSB2YXJpYWJsZXMsIGFzIGZldyBtb3ZpZXMgcHJvdmlkZSBjb21wbGV0ZSBpbmZvcm1hdGlvbiBhYm91dCBhbGwgdGhlIGdlbnJlcyBvciBsYW5ndWFnZXMgcHJlc2VudCBpbiB0aGUgZmlsbS4KCgojIDxzcGFuIHN0eWxlID0gImNvbG9yOiAjNkU4QjNEOyI+KlByb2dyZXNzIFByb2JsZW0gU2V0dXAgMio8L3NwYW4+CiMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiAjNTI4QjhCOyI+RmFjdG9yIExldmVsczwvc3Bhbj4KYGBge3J9CiMgSWRlbnRpZnkgY2F0ZWdvcmljYWwgdmFyaWFibGVzIGFuZCBjb252ZXJ0IHRoZW0gdG8gZmFjdG9ycwpjb2xzX3RvX2ZhY3RvciA8LSBjKCJhZHVsdCIsIHBhc3RlMCgiZ2VucmUiLCAxOjgpLCAiQ2xlYW5fcHJvZHVjdGlvbl9jb21wYW5pZXMiLCAKICAgICAgICAgICAgICAgICAgICAiQ2xlYW5fcHJvZHVjdGlvbl9jb3VudHJpZXMiLCBwYXN0ZTAoInNwb2tlbl9sYW5nXyIsIDE6MTgpKQoKIyBDb252ZXJ0IGNvbHVtbnMgdG8gZmFjdG9ycwpjb2xsZWN0aW9uX2RhdGFbY29sc190b19mYWN0b3JdIDwtIGxhcHBseShjb2xsZWN0aW9uX2RhdGFbY29sc190b19mYWN0b3JdLCBmYWN0b3IpCmhlYWQoY29sc190b19mYWN0b3IpCmBgYAoKQWRyZXNzaW5nIGZhY3RvciBsZXZlbHMgYmVjb21lcyBpbXBvcnRhbnQgd2hlbiBkZWFsaW5nIHdpdGggY2F0ZWdvcmljYWwgdmFyaWFibGVzIHRoYXQgaGF2ZSBzcGVjaWZpYyBvcmRlciBhc3NvY2lhdGVkIHdpdGggdGhlaXIgbGV2ZWxzOyBmb3IgZXhhbXBsZTogbWFueSBzdGF0aXN0aWNhbCBmdW5jdGlvbnMgaW4gUiB0cmVhdCBmYWN0b3JzIGRpZmZlcmVudGx5IHRoYW4gY2hhcmFjdGVyIHZlY3RvcnMsIGxpa2UgaW4gcmVncmVzc2lvbiBhbmFseXNpcyB0aGF0IHJlcXVpZXJlcyBhY2N1cmF0ZSBmYWN0b3IgbGV2ZWxzOyBiZXNpZGVzLCBpbmNvcnJlY3QgZmFjdG9yIGxldmVscyBjYW4gbGVhZCB0byBtaXNsZWFkaW5nIHZpc3VhbCByZXByZXNlbnRhdGlvbnMgb2YgZGF0YS4KCiMjIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogIzc5Q0RDRDsiPlZhbHVlcyB0aGF0IGRvbid0IGJlbG9uZyBpbiB0aGUgZmFjdG9yPC9zcGFuPgpgYGB7cn0KIyBSZXBsYWNlIHVudXN1YWwgZW50cmllcyBpbiB0aGUgYWR1bHQgY29sdW1uIHdpdGggIkZhbHNlIgpjb2xsZWN0aW9uX2RhdGEkYWR1bHRbZ3JlcCgid3JpdHRlbiBieXxiaWtpbmkgY29udGVzdHxjYXNpbm8gY29ubmVjdGVkIiwgdG9sb3dlcihjb2xsZWN0aW9uX2RhdGEkYWR1bHQpKV0gPC0gIkZhbHNlIgoKIyBSZWNhbGN1bGF0ZSB0aGUgZnJlcXVlbmN5IG9mIGVhY2ggY2F0ZWdvcnkgaW4gdGhlIGFkdWx0IGNvbHVtbiBhbmQgdXBkYXRlIHRoZSBkYXRhIGZyYW1lCmFkdWx0X2ZyZXEgPC1hcy5kYXRhLmZyYW1lKHRhYmxlKGNvbGxlY3Rpb25fZGF0YSRhZHVsdCkpCgojIEZpbHRlciB0aGUgcm93cyB0aGF0IGhhdmUgYSBmcmVxdWVuY3kgZ3JlYXRlciB0aGFuIDAKYWR1bHRfZnJlcV9maWx0ZXJlZCA8LSBhZHVsdF9mcmVxW2FkdWx0X2ZyZXEkRnJlcSA+IDAsIF0KCiMgU2hvdyB0aGUgdXBkYXRlZCBjYXRlZ29yaWVzIGFuZCB0aGVpciBmcmVxdWVuY2llcwpwcmludChhZHVsdF9mcmVxKQoKIyBNZXJnZSBjb2xsZWN0aW9uX2RhdGEgd2l0aCBhZHVsdF9mcmVxX2ZpbHRlcmVkIGJhc2VkIG9uIHRoZSAnVmFyMScgY29sdW1uCmNvbGxlY3Rpb25fZGF0YSA8LSBtZXJnZShjb2xsZWN0aW9uX2RhdGEsIGFkdWx0X2ZyZXFfZmlsdGVyZWQsIGJ5LnggPSAiYWR1bHQiLCBieS55ID0gIlZhcjEiLCBhbGwueCA9IFRSVUUpCgojIFJlbW92ZSB0aGUgJ0ZyZXEnIGNvbHVtbiAoc2luY2UgaXQncyBub3QgbmVlZGVkKQpjb2xsZWN0aW9uX2RhdGEgPC0gY29sbGVjdGlvbl9kYXRhWywgLW5jb2woY29sbGVjdGlvbl9kYXRhKV0KCmBgYAoKSW4gdGhlIOKAnGFkdWx04oCdIGNvbHVtbiwgdGhlcmUgd2VyZSAzIHJvd3MgdGhhdCBkaWQgbm90IHJlc3BlY3QgdGhlIFRSVUUgYW5kIEZBTFNFIGZvcm1hdCwgc28gaXQgd2FzIGRlY2lkZWQgdG8gZWxpbWluYXRlIHRob3NlIDMgcm93cyB0byBtYWludGFpbiBjb25zaXN0ZW5jeS4KClRoZSBzYW1lcyBnb2VzIGZvciB0aGUgb3JpZ2luYWwgbGFuZ3VnZSBjb2x1bW4sIHdoaWNoIGluc3RlYWQgb2YgYW4gYWJyZXZpYXRpb24gd2l0aCBjaGFyYWN0ZXJzLCB0aGVyZSBhcmUgc29tZSByb3dzIHdpdGggaW50ZWdlcnMuIFdoaWxlIGFsc28sIGFkZGluZyBhIHRocmVzaG9sZCBmb3IgdGhvc2UgbW92aWVzIHdob3NlIG9yaWdpbmFsIGxhbmd1YWdlIGhhcyBhIGZyZXF1ZW5jeSBsZXNzIHRoYW4gMTAsIGFuZCBjaGFuZ2UgaXQgdG8gdGhlIGFicmV2aWF0aW9uIGFzICJvdGhlciIsIHRvIHNpbXBsaWZ5IGFuZCBjb25zb2xpZGF0ZSB0aGUgZGF0YS4gCgpgYGB7cn0KIyBDcmVhdGUgYSBkYXRhZnJhbWUgd2l0aCB0aGUgZnJlcXVlbmN5IHRhYmxlIG9mIG9yaWdpbmFsIGxhbmd1YWdlcwpvcmdfbGFuZ19mcmVxIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoY29sbGVjdGlvbl9kYXRhJG9yaWdpbmFsX2xhbmd1YWdlKSkKI3NlZSB0aGUgYXZlcmFnZQpzdW1tYXJ5KG9yZ19sYW5nX2ZyZXEkRnJlcSkKIyBGaW5kIHJvd3Mgd2l0aCBmcmVxdWVuY3kgbGVzcyB0aGFuIGEgdGhyZXNob2xkIChlLmcuLCA1MCkgYW5kIGNvbWJpbmUgdGhlbSBpbnRvICdvdGhlcicKdGhyZXNob2xkIDwtIDEwCm90aGVyX2ZyZXEgPC0gc3VtKG9yZ19sYW5nX2ZyZXEkRnJlcVtvcmdfbGFuZ19mcmVxJEZyZXEgPCB0aHJlc2hvbGRdKQpvcmdfbGFuZ19mcmVxJFZhcjFbb3JnX2xhbmdfZnJlcSRGcmVxIDwgdGhyZXNob2xkXSA8LSAib3RoZXIiCm9yZ19sYW5nX2ZyZXEkRnJlcVtvcmdfbGFuZ19mcmVxJEZyZXEgPCB0aHJlc2hvbGRdIDwtIG90aGVyX2ZyZXEKCiMgUmVtb3ZlIGR1cGxpY2F0ZXMgY2F1c2VkIGJ5IGNvbWJpbmluZyBpbnRvICdvdGhlcicKb3JnX2xhbmdfZnJlcSA8LSBvcmdfbGFuZ19mcmVxWyFkdXBsaWNhdGVkKG9yZ19sYW5nX2ZyZXEkVmFyMSksIF0KCiMgUHJpbnQgdGhlIG1vZGlmaWVkIGRhdGFmcmFtZQpoZWFkKG9yZ19sYW5nX2ZyZXEpCmBgYApUaGUgZnJlcXVlbmNpZXMgb2YgdGhlIG9yaWdpbmFsIGxhbmd1YWdlcyBwcmVzZW50IGluIHRoZSBkYXRhYmFzZSB3ZXJlIG9ic2VydmVkLCBhbmQgdGhlbiwgdGhlIGluZnJlcXVlbnQgbGFuZ3VhZ2VzIHdlcmUgaWRlbnRpZmllZCB0byBjb21iaW5lIHRoZW0gaW50byBhIGNhdGVnb3J5IGNhbGxlZCAib3RoZXIiLiBTdWJzZXF1ZW50bHksIHRoZSBmcmVxdWVuY3kgdGFibGUgd2FzIHVwZGF0ZWQgdG8gcmVmbGVjdCB0aGVzZSBjaGFuZ2VzLgoKIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICM1MjhCOEI7Ij5DaGVja2luZyBjYXRlZ29yaWVzIC8gQ29sbGFwc2luZyBjYXRlZ29yaWVzPC9zcGFuPgoKYGBge3J9CmxpYnJhcnkoZm9yY2F0cykKIyBDYXRlZ29yaWVzIHdpdGggbGVzcyBmcmVxdWVuY3kKb3RoZXJfY2F0ZWdvcmllcyA9IGMoIkNhcm91c2VsIFByb2R1Y3Rpb25zIiwgIkFuaXBsZXgiLCAiT2R5c3NleSBNZWRpYSIpCgojIFNlbGVjdCBpdCBhcyBvdGhlcgpjb2xsZWN0aW9uX2RhdGEgPC0gY29sbGVjdGlvbl9kYXRhICU+JQogIG11dGF0ZShnZW5yZTEgPSBhcy5mYWN0b3IoZ2VucmUxKSwKICAgICAgICAgZ2VucmUxID0gZmN0X2NvbGxhcHNlKGdlbnJlMSwgb3RoZXIgPSBvdGhlcl9jYXRlZ29yaWVzKSkKYGBgCgpgYGB7cn0KIyBMYW5ndWFnZXMgd2l0aCBsZXNzIGZyZXF1ZW5jeQpvdGhlcl9jYXRlZ29yaWVzID0gYygiUHVsc2VyIFByb2R1Y3Rpb25zIiwgIkdvSGFuZHMiLCAiVmlzaW9uIFZpZXcgRW50ZXJ0YWlubWVudCIpCgojIFNlbGVjdCBpdCBhcyBvdGhlcgpjb2xsZWN0aW9uX2RhdGEgPC0gY29sbGVjdGlvbl9kYXRhICU+JQogIG11dGF0ZShnZW5yZTIgPSBhcy5mYWN0b3IoZ2VucmUyKSwKICAgICAgICAgZ2VucmUyID0gZmN0X2NvbGxhcHNlKGdlbnJlMiwgb3RoZXIgPSBvdGhlcl9jYXRlZ29yaWVzKSkKYGBgCgpgYGB7cn0KIyBMYW5ndWFnZXMgd2l0aCBsZXNzIGZyZXF1ZW5jeQpvdGhlcl9jYXRlZ29yaWVzID0gYygiVGVsZXNjZW5lIEZpbG0gR3JvdXAgUHJvZHVjdGlvbnMiLCAiUm9ndWUgU3RhdGUiLCAiQlJPU1RBIFRWIikKCiMgU2VsZWN0IGl0IGFzIG90aGVyCmNvbGxlY3Rpb25fZGF0YSA8LSBjb2xsZWN0aW9uX2RhdGEgJT4lCiAgbXV0YXRlKGdlbnJlMyA9IGFzLmZhY3RvcihnZW5yZTMpLAogICAgICAgICBnZW5yZTMgPSBmY3RfY29sbGFwc2UoZ2VucmUzLCBvdGhlciA9IG90aGVyX2NhdGVnb3JpZXMpKQpgYGAKClRoZSBsaXN0IG9mIGxlc3MgZnJlcXVlbnQgY2F0ZWdvcmllcyB3ZXJlIGRlZmluZWQgaW4gdGhlIHRocmVlIG1haW4gbW92aWUgZ2VucmUgY29sdW1ucyAoImdlbnJlMSIsICJnZW5yZTIiLCBhbmQgImdlbnJlMyIpLCBpbiBvcmRlciB0byBncm91cCB0aGVtIHVuZGVyIHRoZSBsYWJlbCAib3RoZXIsIiB0aHVzIGFjaGlldmluZyB0aGUgc2ltcGxpZmljYXRpb24gYW5kIGNvbnNvbGlkYXRpb24gb2YgdGhlIGluZm9ybWF0aW9uLiBUaGlzIGhlbHBzIHN0cmVhbWxpbmUgdGhlIGRhdGEgYW5kIGF2b2lkIGNsdXR0ZXJpbmcgYW5hbHlzaXMgd2l0aCBvdmVybHkgc3BlY2lmaWMgY2F0ZWdvcmllcy4gCgojIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogIzUyOEI4QjsiPkNsZWFuaW5nIG9mIHRleHQgZGF0YTwvc3Bhbj4KCmBgYHtyfQpjbGVhbl9yZXZlbnVlIDwtIGZ1bmN0aW9uKHJldmVudWUpIHsKICAjIEZvcm1hdCBlbnRyaWVzIHdpdGggY29tbWFzIGFuZCBhZGQgbW9uZXkgc3ltYm9sCiAgZm9ybWF0dGVkX3JldmVudWUgPC0gcGFzdGUwKCIkIiwgZm9ybWF0KHJldmVudWUsIGJpZy5tYXJrID0gIiwiLCBzY2llbnRpZmljID0gRkFMU0UpKQogIHJldHVybihmb3JtYXR0ZWRfcmV2ZW51ZSkKfQoKIyBBcHBseSB0aGUgZnVuY3Rpb24gdG8gdGhlIHJldmVudWUgY29sdW1uIGFuZCBzdG9yZSB0aGUgcmVzdWx0cyBpbiBhIG5ldyBjb2x1bW4KY29sbGVjdGlvbl9kYXRhJENsZWFuX3JldmVudWUgPC0gY2xlYW5fcmV2ZW51ZShjb2xsZWN0aW9uX2RhdGEkcmV2ZW51ZSkKCmBgYAoKYGBge3J9CiMgRnVuY3Rpb24gdG8gY2xlYW4gdGhlIGJ1ZGdldApjbGVhbl9idWRnZXQgPC0gZnVuY3Rpb24oYnVkZ2V0KSB7CiAgIyBGb3JtYXQgYnVkZ2V0IHdpdGggY29tbWFzIGFuZCBhZGQgbW9uZXkgc3ltYm9sCiAgZm9ybWF0dGVkX2J1ZGdldCA8LSBwYXN0ZTAoIiQiLCBmb3JtYXQoYnVkZ2V0LCBiaWcubWFyayA9ICIsIiwgc2NpZW50aWZpYyA9IEZBTFNFKSkKICByZXR1cm4oZm9ybWF0dGVkX2J1ZGdldCkKfQoKIyBBcHBseSB0aGUgZnVuY3Rpb24gdG8gdGhlIGJ1ZGdldCBjb2x1bW4gYW5kIHN0b3JlIHRoZSByZXN1bHRzIGluIGEgbmV3IGNvbHVtbgpjb2xsZWN0aW9uX2RhdGEkQ2xlYW5fYnVkZ2V0IDwtIGNsZWFuX2J1ZGdldChjb2xsZWN0aW9uX2RhdGEkYnVkZ2V0KQoKIyBSZW1vdmUgdGhlIHByZXZpb3VzIGJ1ZGdldCBjb2x1bW4KY29sbGVjdGlvbl9kYXRhIDwtIHN1YnNldChjb2xsZWN0aW9uX2RhdGEsIHNlbGVjdCA9IC1jKGJ1ZGdldCkpCmBgYAoKYGBge3J9CiMgQ29udmVydCB0aGUgInBvcHVsYXJpdHkiIGNvbHVtbiB0byBudW1lcmljCmNvbGxlY3Rpb25fZGF0YSRwb3B1bGFyaXR5IDwtIGFzLm51bWVyaWMoY29sbGVjdGlvbl9kYXRhJHBvcHVsYXJpdHkpCgojIFJvdW5kIHBvcHVsYXJpdHkgdG8gd2hvbGUgbnVtYmVycwpjb2xsZWN0aW9uX2RhdGEkcm91bmRfcG9wdWxhcml0eSA8LSByb3VuZChjb2xsZWN0aW9uX2RhdGEkcG9wdWxhcml0eSkKCiMgUmVtb3ZlIHRoZSBwcmV2aW91cyBwb3B1bGFyaXR5IGNvbHVtbgpjb2xsZWN0aW9uX2RhdGEgPC0gc3Vic2V0KGNvbGxlY3Rpb25fZGF0YSwgc2VsZWN0ID0gLWMocG9wdWxhcml0eSkpCgpgYGAKClRoZSBjb2x1bW5zIGZvciByZXZlbnVlIGFuZCBidWRnZXQgd2VyZSByZWZvcm1hdHRlZCwgYWRkaW5nIGRvbGxhciBzeW1ib2xzIGFuZCByZW1vdmluZyBzY2llbnRpZmljIG5vdGF0aW9uLCB3aGljaCBtYWtlcyBpbnRlcnByZXRpbmcgYW5kIGFuYWx5emluZyB0aGVzZSBtb25ldGFyeSB2YWx1ZXMgZWFzaWVyLiBBZGRpdGlvbmFsbHksIHRoZSBwb3B1bGFyaXR5IGNvbHVtbiB3YXMgYWxzbyBjb252ZXJ0ZWQgdG8gbnVtZXJpY2FsIGZvcm1hdCBhbmQgaXRzIHZhbHVlcyB3ZXJlIHJvdW5kZWQgdG8gc2ltcGxpZnkgdGhlaXIgcHJlc2VudGF0aW9uLiBUaGVzZSBzdGVwcyBjb250cmlidXRlIHRvIGVuaGFuY2luZyB0aGUgY2xhcml0eSBhbmQgYWNjdXJhY3kgb2YgdGhlIGRhdGEsIG1ha2luZyBpdCBlYXNpZXIgdG8gdW5kZXJzdGFuZCBhbmQgYW5hbHl6ZS4KCiMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiAjNTI4QjhCOyI+Q29uY2x1c2lvbjwvc3Bhbj4KQXMgZm9yIHRoZSB1bml2YXJpYXRlIGRpc3RyaWJ1dGlvbnMsICpidWRnZXQqLCAqcG9wdWxhcml0eSosICpWb3RlIGNvdW50KiBhbmQgKnJldmVudWUqIGhhdmUgbG93IGZyZXF1ZW5jaWVzIHNvIHRoZSAic3VjY2VzcyIgbW92aWVzIG1ha2UgdGhlIG1pbm9yaXR5IHdoaWNoIGhvbGQgaW50byBxdWVzdGlvbiB0aGUgcG9zc2liaWxpdHkgb2YgYSBwcmVkaWN0aW9uIG1vZGVsLiAqUnVuIHRpbWUqIGlzIDEwMCBtaW51dGVzIGZvciBtb3N0IGFuZCAqVm90ZSBBdmVyYWdlKiBmb2xsb3dzIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiB3aXRoIGFuIGF2ZyBvZiA2LTcuIE5vbmUgb2YgdGhlIG90aGVycyBmb2xsb3cgYSBub3JtYWwgZGlzdHJpYnV0aW9uLgoKQXMgZm9yIHdoYXQgdmFyaWFibGVzIGFyZSBtb3N0IGNvcnJlbGF0ZWQgdG8gcmV2ZW51ZSwgaGVyZSBpcyB3aGF0IHdlIGZvdW5kLiBTdHJvbmdlc3Q6IGJ1ZGdldCBhbmQgdm90ZSBjb3VudDsgMm5kIGxldmVsOiBwb3B1bGFyaXR5LCBnZW5yZTFfYWR2ZW50dXJlIGFuZCBnZW5yZTJfYWN0aW9uOyAzcmQgbGV2ZWw6IGdlbnJlMV9hbmltYXRpb24gYW5kIGdlbnJlMl9mYW50YXN5LgoKVGhlcmUgaXMgYSBwb3NpdGl2ZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHZvdGUgY291bnQsIGJ1ZGdldCBhbmQgcG9wdWxhcml0eSB0byByZXZlbnVlLiBObyBjbGVhciB0cmVuZCB3aXRoIHJ1bnRpbWUgYW5kIHZvdGUgYXZlcmFnZS4KCiMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICM2RThCM0Q7Ij4qUHJvZ3Jlc3MgUHJvYmxlbSBTZXR1cCAzKjwvc3Bhbj4KCiMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiAjNTI4QjhCOyI+VW5pdCBDb252ZXJzaW9uPC9zcGFuPgpgYGB7cn0KIyBDaGVjayBpZiBydW50aW1lIGNvbHVtbiBpcyBhbHJlYWR5IGFzc2lnbmVkIHVuaXRzCmlmICghaW5oZXJpdHMoY29sbGVjdGlvbl9kYXRhJHJ1bnRpbWUsICJ1bml0cyIpKSB7CiAgIyBDb252ZXJ0IHJ1bnRpbWUgY29sdW1uIHRvIG51bWVyaWMgYW5kIHRoZW4gdG8gbWludXRlcyB3aXRoIHVuaXRzCiAgY29sbGVjdGlvbl9kYXRhJHJ1bnRpbWUgPC0gYXMubnVtZXJpYyhjb2xsZWN0aW9uX2RhdGEkcnVudGltZSkKICBjb2xsZWN0aW9uX2RhdGEkcnVudGltZSA8LSBzZXRfdW5pdHMoY29sbGVjdGlvbl9kYXRhJHJ1bnRpbWUsICJtaW51dGVzIikKfQoKYGBgCgpgYGB7cn0KIyBDcmVhdGUgYSBuZXcgY29sdW1uIGNhbGxlZCAnbnVtX2dlbnJlcycgdGhhdCBjb3VudHMgdGhlIG5vbi1taXNzaW5nIGdlbnJlIGFuZCBzcG9rZW4gbGFuZyBjb2x1bW5zCmNvbGxlY3Rpb25fZGF0YSRudW1fZ2VucmVzIDwtIHJvd1N1bXMoIWlzLm5hKGNvbGxlY3Rpb25fZGF0YVssIHBhc3RlMCgiZ2VucmUiLCAxOjgpXSkpCgpjb2xsZWN0aW9uX2RhdGEgPC0gY29sbGVjdGlvbl9kYXRhICU+JQogIG11dGF0ZShudW1fc3Bva2VuX2xhbmd1YWdlcyA9IHJvd1N1bXMoIWlzLm5hKHNlbGVjdCguLCBzdGFydHNfd2l0aCgic3Bva2VuX2xhbmciKSkpKSkKYGBgCgoKIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICM1MjhCOEI7Ij5Db25jbHVzaW9uPC9zcGFuPgoKVGhlc2UgY29kZSBhbGxvd3MgdXMgdG8gZW5zdXJlIGNvbnNpc3RlbnQgdW5pdHMgZm9yIHJ1bnRpbWUgYW5kIGNhbGN1bGF0aW5nIHRoZSBjb3VudCBvZiBnZW5yZXMgYW5kIHNwb2tlbiBsYW5ndWFnZXMgc28gdGhlIGRhdGFzZXQgYmVjb21lcyBtb3JlIHN0YW5kYXJkaXplZC4gVGhlIHVuaXQgY29udmVyc2lvbiBlbnN1cmVzIHRoYXQgdGhlICdydW50aW1lJyBjb2x1bW4gaXMgdW5pZm9ybWx5IHJlcHJlc2VudGVkIGluIG1pbnV0ZXMuIEl0IGNoZWNrcyBpZiB0aGUgJ3J1bnRpbWUnIGNvbHVtbiBpcyBhbHJlYWR5IGFzc2lnbmVkIHVuaXRzLiBJZiBub3QsIGl0IGNvbnZlcnRzIHRoZSAncnVudGltZScgY29sdW1uIHRvIG51bWVyaWMgYW5kIHRoZW4gYXNzaWducyB1bml0cyB0byByZXByZXNlbnQgdGltZSBpbiBtaW51dGVzLiBMYXN0IHRoZSBnZW5yZSBhbmQgc3Bva2VuIGxhbmd1YWdlIGNvdW50cyBjb2RlLCBhZGRzIHR3byBuZXcgY29sdW1ucyB0byB0aGUgZGF0YXNldC4KJ251bV9nZW5yZXMnOiBUaGlzIGNvbHVtbiBjb3VudHMgdGhlIG51bWJlciBvZiBub24tbWlzc2luZyBnZW5yZSBjb2x1bW5zIGZvciBlYWNoIG1vdmllLgonbnVtX3Nwb2tlbl9sYW5ndWFnZXMnOiBUaGlzIGNvbHVtbiBjb3VudHMgdGhlIG51bWJlciBvZiBub24tbWlzc2luZyBzcG9rZW4gbGFuZ3VhZ2UgY29sdW1ucyBmb3IgZWFjaCBtb3ZpZS4KCiMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICM2RThCM0Q7Ij4qUHJvZ3Jlc3MgUHJvYmxlbSBTZXR1cCA0Kjwvc3Bhbj4KIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICM1MjhCOEI7Ij5UYWJsZXMgd2l0aCAxIG9yIDIgdmFyaWFibGVzIDQ8L3NwYW4+CgpgYGB7cn0KIyBDcmVhdGUgYSBiYWNrdXAgZGYKY29weV9kYXRhIDwtIGNvbGxlY3Rpb25fZGF0YQpgYGAKCiMjIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogIzc5Q0RDRDsiPlJldmVudWU8L3NwYW4+CmBgYHtyfQojIE1ha2UgYWR1bHQgY29sdW1uIGEgbG9naWNhbCBkYXRhIHR5cGUgaW5zdGVhZCBvZiBhIGZhY3RvciB0byBlbGltaW5hdGUgaXJyZWxldmFudCBlbnRyaWVzCgpsZXZlbHMoY29weV9kYXRhJGFkdWx0KQoKY29weV9kYXRhJGFkdWx0IDwtIGFzLmxvZ2ljYWwoY29weV9kYXRhJGFkdWx0KQpgYGAKCmBgYHtyfQphZHVsdF90YWJsZSA8LSB0YWJsZShjb3B5X2RhdGEkYWR1bHQpCmFkdWx0X3RhYmxlCmBgYAoKYGBge3J9CiMgRGVmaW5lIHRoZSByZXZlbnVlIGNhdGVnb3JpZXMKcmV2ZW51ZV9iaW5zIDwtIGMoMCwgMTAwMDAwMDAwLCA1MDAwMDAwMDAsIDEwMDAwMDAwMDAsIDIwMDAwMDAwMDAsIDMwMDAwMDAwMDApCnJldmVudWVfbGFiZWxzIDwtIGMoJzwxMDBNJywgJzEwME0tNTAwTScsICc1MDBNLTFCJywgJzFCLTJCJywgJzJCLTNCJykKCgojIENyZWF0ZSB0aGUgJ3JldmVudWVfZ3JvdXAnIGNvbHVtbgpjb3B5X2RhdGEkcmV2ZW51ZV9ncm91cCA8LSBjdXQoY29weV9kYXRhJHJldmVudWUsIGJyZWFrcyA9IHJldmVudWVfYmlucywgbGFiZWxzID0gcmV2ZW51ZV9sYWJlbHMsIHJpZ2h0ID0gRkFMU0UpCmBgYAoKYGBge3J9CnRhYmxlKGNvcHlfZGF0YSRyZXZlbnVlX2dyb3VwKQpgYGAKCgpgYGB7cn0KdGFibGUoY29weV9kYXRhJHJldmVudWVfZ3JvdXAsIGNvcHlfZGF0YSRnZW5yZTEpCmBgYApMb3dlciBncm9zc2luZyBmaWxtcyB0ZW5kIHRvIGhhdmUgbW92aWVzIGZyb20gYSB3aWRlIGFycmF5IG9mIGdlbnJlcywgYnV0IGZvciA1MDBNLTFCIHRvIDJCLTNCIGFyZSBtb3N0IGNvbmNlbnRyYXRlZCBpbiBhY3Rpb24uCgpgYGB7cn0KdGFibGUoY29weV9kYXRhJHJldmVudWVfZ3JvdXAsIGNvcHlfZGF0YSRyb3VuZF9wb3B1bGFyaXR5KQpgYGAKSXQgaXMgc2VlbiB0aGF0IHRoZSBtYXlvcml0eSBvZiBtb3ZpZXMgd2l0aCBidWRnZXRzIGxvd2VyIHRoYW4gMTAwTSBvciAxMDBNLTUwME0gaGF2ZSBwb3B1bGFyaXRpZXMgcmFuZ2luZyBmcm9tIDAgdG8gMjcuIEFzIGZvciBoaWdoZXIgZ3Jvc3NpbmcgZmlsbXMsIHRoZXkgdGVuZCB0byBoYXZlIHBvcHVsYXJpdHkgc2NvcmVzIGZyb20gNjcgdG8gNTQ3LCBidXQgbW9zdCBhcmUgb3V0bGllcnMgc2luY2UgdGhleSBtYWtlIHRoZSBtaW5vcml0eS4KCgojIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICM3OUNEQ0Q7Ij5Qcm9kdWN0aW9uIENvbXBhbmllczwvc3Bhbj4KCmBgYHtyfQojIENhbGN1bGF0ZSB0aGUgZnJlcXVlbmNpZXMgb2YgZWFjaCBwcm9kdWN0aW9uIGNvbXBhbnkKY29tcGFueV9mcmVxdWVuY2llcyA8LSBjb3B5X2RhdGEgJT4lCiAgY291bnQoQ2xlYW5fcHJvZHVjdGlvbl9jb21wYW5pZXMpICU+JQogIGFycmFuZ2UoZGVzYyhuKSkgICMgU29ydCBpbiBkZXNjZW5kaW5nIG9yZGVyIG9mIGZyZXF1ZW5jeQoKIyBTZWxlY3QgdGhlIHRvcCAxMCBwcm9kdWN0aW9uIGNvbXBhbmllcwp0b3BfMTBfY29tcGFuaWVzIDwtIGhlYWQoY29tcGFueV9mcmVxdWVuY2llcywgMTApCgp0b3BfMTBfY29tcGFuaWVzCmBgYApgYGB7cn0KIyBDYWxjdWxhdGUgdGhlIGNvdW50IG9mIGVhY2ggY29tcGFueQpjb21wYW55X2NvdW50cyA8LSB0YWJsZShjb3B5X2RhdGEkQ2xlYW5fcHJvZHVjdGlvbl9jb21wYW5pZXMpCgojIFNvcnQgdGhlIGNvbXBhbmllcyBieSBjb3VudCBpbiBkZXNjZW5kaW5nIG9yZGVyIGFuZCBzZWxlY3QgdGhlIHRvcCBmaXZlCnRvcF9jb21wYW5pZXMgPC0gbmFtZXMoc29ydChjb21wYW55X2NvdW50cywgZGVjcmVhc2luZyA9IFRSVUUpWzE6OF0pCgojIEZpbHRlciB0aGUgZGF0YXNldCB0byBpbmNsdWRlIG9ubHkgdGhlIHRvcCBmaXZlIG1vc3QgaW1wb3J0YW50IGNvbXBhbmllcwpmaWx0ZXJlZF9kYXRhIDwtIGNvcHlfZGF0YVtjb2xsZWN0aW9uX2RhdGEkQ2xlYW5fcHJvZHVjdGlvbl9jb21wYW5pZXMgJWluJSB0b3BfY29tcGFuaWVzLCBdCgojIENyZWF0ZSB0aGUgYmFyIHBsb3QKZ2dwbG90KGZpbHRlcmVkX2RhdGEsIGFlcyh4ID0gQ2xlYW5fcHJvZHVjdGlvbl9jb21wYW5pZXMpKSArCiAgZ2VvbV9iYXIoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKQpgYGAKVGhpcyBiYXIgZ3JhcGggYW5hbHl6ZXMgdGhlICJDbGVhbl9wcm9kdWN0aW9uXyIgdmFyaWFibGUgY29tcGFuaWVzIiBhbmQgc2hvd3MgdXMgdGhlIDggbW9zdCBpbXBvcnRhbnQgcmVzdWx0cyB0byBiZSBhYmxlIHRvIGlkZW50aWZ5IHdoaWNoIGNvbXBhbmllcyBhcmUgbWFraW5nIHRoZSBtb3N0IG1vdmllcy4KVGhlIGhvcml6b250YWwgYmFyIGNoYXJ0IGFuYWx5c2VzIHRoZSBwcm9wb3J0aW9uIG9mIHRoZSByZXZlbnVlIGNvbXBhcmVkIHRvIGl0cyBidWRnZXQgZm9yIGVhY2ggb2YgdGhlIGdlbnJlLiBBZHZlbnR1cmUgYW5kIFNjaUZpIGNvdW50IHdpdGggYSBiaWdnZXIgYnVkZ2V0LCB5ZXQgaGF2ZSB0aGUgbW9zdCByZXZlbnVlLgoKIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICM1MjhCOEI7Ij5HR1Bsb3QgU3RydWN0dXJlczwvc3Bhbj4KIyMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiAjNzlDRENEOyI+RGVuc2l0eSBQbG90PC9zcGFuPgoKYGBge3J9CiMgQ2FsY3VsYXRlIHRoZSBjb3VudCBvZiBlYWNoIGNvdW50cnkKY291bnRyeV9jb3VudHMgPC0gdGFibGUoY29sbGVjdGlvbl9kYXRhJENsZWFuX3Byb2R1Y3Rpb25fY291bnRyaWVzKQoKIyBTb3J0IHRoZSBjb3VudHJpZXMgYnkgY291bnQgaW4gZGVzY2VuZGluZyBvcmRlciBhbmQgc2VsZWN0IHRoZSB0b3AgZml2ZQp0b3BfY291bnRyaWVzIDwtIG5hbWVzKHNvcnQoY291bnRyeV9jb3VudHMsIGRlY3JlYXNpbmcgPSBUUlVFKVsxOjhdKQoKIyBGaWx0ZXIgdGhlIGRhdGFzZXQgdG8gaW5jbHVkZSBvbmx5IHRoZSB0b3AgZml2ZSBtb3N0IGltcG9ydGFudCBjb3VudHJpZXMKZmlsdGVyZWRfZGF0YSA8LSBjb2xsZWN0aW9uX2RhdGFbY29sbGVjdGlvbl9kYXRhJENsZWFuX3Byb2R1Y3Rpb25fY291bnRyaWVzICVpbiUgdG9wX2NvdW50cmllcywgXQoKIyBDcmVhdGUgdGhlIGRlbnNpdHkgcGxvdApnZ3Bsb3QoZmlsdGVyZWRfZGF0YSwgYWVzKHggPSBDbGVhbl9wcm9kdWN0aW9uX2NvdW50cmllcykpICsKICBnZW9tX2RlbnNpdHkoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKQpgYGAKVGhpcyBkZW5zaXR5IHBsb3QgYW5hbHl6ZXMgdGhlICJDbGVhbl9wcm9kdWN0aW9uX2NvdW50cmllcyIgdmFyaWFibGUgYW5kIHNob3dzIHVzIHRoZSA4IG1vc3QgaW1wb3J0YW50IHJlc3VsdHMgdG8gYmUgYWJsZSB0byBpZGVudGlmeSB3aGljaCBjb3VudHJpZXMgYXJlIHdoZXJlIHRoZSBtb3N0IG1vdmllcyBhcmUgYmVpbmcgcHJvZHVjZWQuIFdlIGdhaW4gYSBkZWVwZXIgdW5kZXJzdGFuZGluZyBvZiB0aGUgZ2VvZ3JhcGhpY2FsIGxhbmRzY2FwZSBvZiB0aGUgZmlsbSBpbmR1c3RyeSByZXByZXNlbnRlZCBieSB0aGUgZGF0YXNldC4KCiMjIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogIzc5Q0RDRDsiPkNvcnJlbGF0aW9uIFBsb3Q8L3NwYW4+CmBgYHtyfQojIExvYWQgdGhlIGNvcnJwbG90IHBhY2thZ2UKbGlicmFyeShjb3JycGxvdCkKCiMgRXh0cmFjdCBudW1lcmljIGNvbHVtbnMgZm9yIGNvcnJlbGF0aW9uIGFuYWx5c2lzCm51bWVyaWNfZGF0YSA8LSBjb3B5X2RhdGFbLCBzYXBwbHkoY29weV9kYXRhLCBpcy5udW1lcmljKV0KCiMgQ2FsY3VsYXRlIHRoZSBjb3JyZWxhdGlvbiBtYXRyaXgKY29ycmVsYXRpb25fbWF0cml4IDwtIGNvcihudW1lcmljX2RhdGEpCgojIENyZWF0ZSB0aGUgY29ycnBsb3Qgd2l0aCB0aGUgY29ycmVsYXRpb24gbWF0cml4CmNvcnJwbG90KGNvcnJlbGF0aW9uX21hdHJpeCwgbWV0aG9kID0gImNvbG9yIikKYGBgClRoZSBjb3JyZWxhdGlvbiBtYXRyaXggd2FzIGNhbGN1bGF0ZWQgYmV0d2VlbiB0aGUgbnVtZXJpYyBjb2x1bW5zIG9mIHRoZSBkYXRhYmFzZS4gSW4gdGhlIGdyYXBoLCBjb3JyZWxhdGlvbnMgYmV0d2VlbiB0aGUgZGlmZmVyZW50IG51bWVyaWMgdmFyaWFibGVzIGNhbiBiZSB2aXN1YWxpemVkIHVzaW5nIGNvbG9ycyB0byByZXByZXNlbnQgdGhlIHN0cmVuZ3RoIGFuZCBkaXJlY3Rpb24gb2YgdGhlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB0aGVtLgoKCiMjIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogIzc5Q0RDRDsiPkJhciBHcmFwaDwvc3Bhbj4KYGBge3J9Cgpwb3B1bGFyaXR5X3N1bW1hcnkgPC0gYWdncmVnYXRlKHJvdW5kX3BvcHVsYXJpdHkgfiBnZW5yZTIsIGRhdGEgPSBjb2xsZWN0aW9uX2RhdGEsIEZVTiA9IG1lYW4pCgpnZ3Bsb3QoZGF0YSA9IHBvcHVsYXJpdHlfc3VtbWFyeSwgYWVzKHggPSBnZW5yZTIsIHkgPSByb3VuZF9wb3B1bGFyaXR5KSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gInNreWJsdWUiKSArCiAgbGFicyh0aXRsZSA9ICJBdmVyYWdlIFBvcHVsYXJpdHkgYnkgR2VucmUiLCB4ID0gIkdlbnJlIiwgeSA9ICJBdmVyYWdlIFBvcHVsYXJpdHkiKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKQoKYGBgCldoYXQgY2FuIGJlIGludGVycHJldGVkIGluIHRoZSBiYXIgZ3JhcGggaXMgdGhhdCB0aGVyZSBhcmUgMyBnZW5yZXMgdGhhdCBoYXZlIHRoZSBoaWdoZXN0IHBvcHVsYXJpdHkgYW1vbmcgdGhlIG90aGVycywgdGhlc2UgYXJlIEFkdmVudHVyZSBpbiBmaXJzdCBwbGFjZSwgQW5pbWF0aW9uIGluIHNlY29uZCBwbGFjZSBhbmQgRmFudGFzeSBpbiB0aGlyZCBwbGFjZSwgdGhlIG90aGVycyBoYXZlIHNpbWlsYXIgYW5kIHBlcnNpc3RlbnQgYW1vdW50cy4KCiMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiAjNTI4QjhCOyI+VGFibGVzIGFuZCBHcmFwaHMgZm9yIENhdGVnb3JpY2FsIGFuZCBOdW1lcmljYWwgdmFyaWFibGVzPC9zcGFuPgoKIyMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiAjNzlDRENEOyI+RnJlcXVlbmN5IHRhYmxlIGZvciBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlPC9zcGFuPgpgYGB7cn0KIyBGcmVxdWVuY3kgdGFibGUgZm9yIGEgY2F0ZWdvcmljYWwgdmFyaWFibGUKZ2VucmVfZnJlcSA8LSB0YWJsZShjb2xsZWN0aW9uX2RhdGEkZ2VucmUxKQpoZWFkKGdlbnJlX2ZyZXEpCmBgYAoKVGhpcyB0YWJsZSBwcm92ZWQgYSBzdW1tYXJ5IG9mIHRoZSBjb3VudHMgb2YgZGlmZmVyZW50IGdlbnJlcyBpbiB0aGUgZGF0YXNldC4gV2UgY2FuIG5vdyB1bmRlcnN0YW5kIHRoZSBkaXN0cmlidXRpb24gb2YgbW92aWVzIGFjcm9zcyBkaWZmZXJlbnQgZ2VucmVzLiBGb3IgZXhhbXBsZSwgdGhlcmUgYXJlIGluIHRvdGFsIDQsNDg3IG1vdmllcyB0aGF0IGFyZSBzZXQgaW4gdGhlIGFjdGlvbiBnZW5yZSwgMSw1MDkgZm9yIGFkdmVudHVyZSwgMSwxMjQgaW4gYW5pbWF0aW9uLCA4LDgxNiBpbiBjb21lZHksIDEsNjg0IGluIGNyaW1lLCBhbmQgZmluYWxseSAzIGluIG90aGVyIGdlbnJlLiAKCiMjIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogIzc5Q0RDRDsiPkJhciBjaGFydCBmb3IgZ2VucmUgZnJlcXVlbmN5PC9zcGFuPgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBjb2xsZWN0aW9uX2RhdGEsIGFlcyh4ID0gZ2VucmUxKSkgKwogIGdlb21fYmFyKCkgKwogIGxhYnModGl0bGUgPSAiRnJlcXVlbmN5IG9mIEdlbnJlcyIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdCA9IDEpKQoKYGBgCgpWaXN1YWxpemVzIHRoZSBmcmVxdWVuY3kgb2YgZ2VucmVzIGluIHRoZSBkYXRhIHNldC4gSXQgZ2l2ZXMgYSBjbGVhciB2aXN1YWwgcmVwcmVzZW50YXRpb24gb2YgaG93IG1hbnkgbW92aWVzIGJlbG9uZyB0byBlYWNoIGdlbnJlLCBoZWxwaW5nIHRvIGlkZW50aWZ5IHRoZSBtb3N0IGNvbW1vbiBhbmQgbGVhdHMgY29tbW9uIGdlbnJlcy4KIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICM1MjhCOEI7Ij5BbmFseXppbmcgTXVsdGlwbGUgVmFyaWFibGVzIFRvZ2V0aGVyPC9zcGFuPgoKIyMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiAjNzlDRENEOyI+U3RhY2tlZCBiYXIgY2hhcnQgZm9yIGdlbnJlIHZzIHJldmVudWU8L3NwYW4+CmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IGNvbGxlY3Rpb25fZGF0YSwgYWVzKHggPSBnZW5yZTEsIHkgPSByZXZlbnVlKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gZ2VucmUxKSkgKwogIGxhYnModGl0bGUgPSAiR2VucmUgdnMgUmV2ZW51ZSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShkcm9wID0gRkFMU0UpICAKYGBgClRoaXMgc2NhdHRlciBwbG90IHNob3dzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgZ2VucmVzIG9mIG1vdmllcyBhbmQgdGhlaXIgcmV2ZW51ZS4gRWFjaCBwb2ludCBpbiB0aGUgcGxvdCByZXByZXNlbnRzIGEgbW92aWUsIHdoZXJlIHRoZSB4LWF4aXMgcmVwcmVzZW50cyB0aGUgbW92aWUgZ2VucmUgYW5kIHRoZSB5LWF4aXMgcmVwcmVzZW50cyB0aGUgcmV2ZW51ZS4gVGhlIHBvaW50cyBhcmUgY29sb3JlZCBhY2NvcmRpbmcgdG8gdGhlIG1vdmllIGdlbnJlLiBUaGlzIHBsb3QgYWxsb3dzIHVzIHRvIHZpc3VhbGl6ZSBob3cgcmV2ZW51ZSB2YXJpZXMgYmFzZWQgb24gdGhlIG1vdmllIGdlbnJlLgoKIyMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiAjNzlDRENEOyI+V29yZCBDbG91ZHM8L3NwYW4+CgpgYGB7cn0KIyBMb2FkIGxpYnJhcmllcwpsaWJyYXJ5KCJ0bSIpIApsaWJyYXJ5KCJTbm93YmFsbEMiKQpsaWJyYXJ5KCJ3b3JkY2xvdWQiKQpsaWJyYXJ5KCJSQ29sb3JCcmV3ZXIiKQpgYGAKCiMjIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogIzc5Q0RDRDsiPlRpdGxlczwvc3Bhbj4KCmBgYHtyfQojIG5vcyBkaWNlIGxhcyBwZWxpY3VsYXMgcXVlIG1hcyBnYW5hcm9uIGRpbmVybwojIERlZmluZSBsb3MgaW50ZXJ2YWxvcyBkZSBpbmdyZXNvcwpyZXZlbnVlX2JpbnMgPC0gYyg1MDAwMDAwMDAsIDEwMDAwMDAwMDAsIDIwMDAwMDAwMDAsIDMwMDAwMDAwMDApCgojIEZpbHRyYSBsb3MgZGF0b3MgZGUgY29sZWNjacOzbiBiYXNhZG9zIGVuIGxvcyBpbnRlcnZhbG9zIGRlIGluZ3Jlc29zCnByb2ZpdF9kYXRhIDwtIGNvbGxlY3Rpb25fZGF0YSAlPiUgCiAgZmlsdGVyKHJldmVudWUgPj0gcmV2ZW51ZV9iaW5zWzFdICYgcmV2ZW51ZSA8IHJldmVudWVfYmluc1syXSB8CiAgICAgICAgICAgcmV2ZW51ZSA+PSByZXZlbnVlX2JpbnNbMl0gJiByZXZlbnVlIDwgcmV2ZW51ZV9iaW5zWzNdIHwKICAgICAgICAgICByZXZlbnVlID49IHJldmVudWVfYmluc1szXSAmIHJldmVudWUgPCByZXZlbnVlX2JpbnNbNF0pCgpgYGAKCgpgYGB7cn0KI1dlIG5lZWQgdG8gY29udmVydCB0aGUgdGV4dCB0byBhIGNvcnB1cwoKZG9jcyA8LSBDb3JwdXMoVmVjdG9yU291cmNlKHByb2ZpdF9kYXRhJG9yaWdpbmFsX3RpdGxlKSkKYGBgCgpgYGB7cn0KI0dlbmVyYWwgdGV4dCBjbGVhbmluZwoKIyBDb252ZXJ0IHRoZSB0ZXh0IHRvIGxvd2VyIGNhc2UKZG9jcyA8LSB0bV9tYXAoZG9jcywgY29udGVudF90cmFuc2Zvcm1lcih0b2xvd2VyKSkKIyBSZW1vdmUgbnVtYmVycwpkb2NzIDwtIHRtX21hcChkb2NzLCByZW1vdmVOdW1iZXJzKQojIFJlbW92ZSBlbmdsaXNoIGNvbW1vbiBzdG9wd29yZHMKZG9jcyA8LSB0bV9tYXAoZG9jcywgcmVtb3ZlV29yZHMsIHN0b3B3b3JkcygiZW5nbGlzaCIpKQojIFJlbW92ZSB5b3VyIG93biBzdG9wIHdvcmQKIyBzcGVjaWZ5IHlvdXIgc3RvcHdvcmRzIGFzIGEgY2hhcmFjdGVyIHZlY3Rvcgpkb2NzIDwtIHRtX21hcChkb2NzLCByZW1vdmVXb3JkcywgYygiYmxhYmxhMSIsICJibGFibGEyIikpIAojIFJlbW92ZSBwdW5jdHVhdGlvbnMKZG9jcyA8LSB0bV9tYXAoZG9jcywgcmVtb3ZlUHVuY3R1YXRpb24pCiMgRWxpbWluYXRlIGV4dHJhIHdoaXRlIHNwYWNlcwpkb2NzIDwtIHRtX21hcChkb2NzLCBzdHJpcFdoaXRlc3BhY2UpIApgYGAKCmBgYHtyfQojVGVybS1kb2N1bWVudCBtYXRyaXguIERvY3VtZW50IG1hdHJpeCBpcyBhIHRhYmxlIGNvbnRhaW5pbmcgdGhlIGZyZXF1ZW5jeSBvZiB0aGUgd29yZHMuCgpkdG0gPC0gVGVybURvY3VtZW50TWF0cml4KGRvY3MpCm0gPC0gYXMubWF0cml4KGR0bSkKdiA8LSBzb3J0KHJvd1N1bXMobSksZGVjcmVhc2luZz1UUlVFKQpkIDwtIGRhdGEuZnJhbWUod29yZCA9IG5hbWVzKHYpLGZyZXE9dikKI2hlYWQoZCwgMTAwKQoKYGBgCgpgYGB7ciB3YXJuaW5nPUZBTFNFfQpzZXQuc2VlZCgxMjM0KQp3b3JkY2xvdWQod29yZHMgPSBkJHdvcmQsIGZyZXEgPSBkJGZyZXEsIG1pbi5mcmVxID0gNSwKICAgICAgICAgIG1heC53b3Jkcz1JbmYsIHJhbmRvbS5vcmRlcj1ULCByb3QucGVyPTAuNSwgCiAgICAgICAgICBjb2xvcnM9YnJld2VyLnBhbCg4LCAiRGFyazIiKSkKCiNodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvd29yZGNsb3VkL3dvcmRjbG91ZC5wZGYKYGBgClRoZSB0cmVuZCBmb3IgdGhlIG1vc3QgcHJvZml0YWJsZSB0aXRsZXMgaXMgdG8gYmUgYSBwYXJ0IG9mIGEga25vd24gZnJhbmNoaXNlIGxpa2UgIlBpcmF0ZXMgb2YgdGhlIENhcmliYmVhbiIsICJEZWFkcG9vbCIsICJUd2lsaWdodCIsICJTdGFyIFdhcnMiLCAiSW5jZXB0aW9uIiwgIkhhcnJ5IFBvdHRlciIsICJIdW5nZXIgR2FtZXMiLCAiVGVybWluYXRvciIsICJJcm9uIE1hbiIsIGV0Yy4KCiMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICM2RThCM0Q7Ij4qUHJvZ3Jlc3MgUHJvYmxlbSBTZXR1cCA1Kjwvc3Bhbj4KIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICM1MjhCOEI7Ij5EZXNjcmlwdGl2ZSBNZWFzdXJlczwvc3Bhbj4KCmBgYHtyfQpjb3B5X2RhdGEgPC0gY29sbGVjdGlvbl9kYXRhCgpjb3B5X2RhdGEkQ2xlYW5fYnVkZ2V0X251bWVyaWMgPC0gYXMubnVtZXJpYyhnc3ViKCJcXCQiLCAiIiwgY29weV9kYXRhJENsZWFuX2J1ZGdldCkpCgpgYGAKCmBgYHtyfQojIENyZWF0ZSBtZWFzdXJlIGZvciBwcm9maXQgKGdhbmFuY2lhIG8gcGVyZGlkYSkKY29weV9kYXRhIDwtIGNvcHlfZGF0YSAlPiUKICAgICAgICBtdXRhdGUocHJvZml0ID0gcmV2ZW51ZSAtIENsZWFuX2J1ZGdldF9udW1lcmljKQpgYGAKCmBgYHtyfQpyZXZlbnVlX2dyb3VwZWQgPC0gY29weV9kYXRhICU+JQogIGdyb3VwX2J5KHJldmVudWUpICU+JQogIHN1bW1hcml6ZShtZWFuKHByb2ZpdCwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgc2QocHJvZml0LCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBtZWRpYW4ocHJvZml0LCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBxdWFudGlsZShwcm9maXQsICguOTApLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBuKCkpCgpyZXZlbnVlX2dyb3VwZWQKYGBgCgpgYGB7cn0Kc3VtbWFyeShjb3B5X2RhdGEkcHJvZml0KQpgYGAKCgojIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogIzUyOEI4QjsiPlNoYXBlIE1lYXN1cmVzPC9zcGFuPgpgYGB7ciB3YXJuaW5nPUZBTFNFfQpjb2xsZWN0aW9uX2RhdGEgJT4lCiAgZ2dwbG90KGFlcyh4ID0gZ2VucmUxLCBmaWxsID0gcnVudGltZSkpICsKICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjIpICsgICBsYWJzKHRpdGxlID0gIkRlbnNpdHkgaW4gZ2VucmUxIGFuZCBwb3B1bGFyaXR5IiwgeCA9ICJnZW5yZTEiLCB5ID0gInJ1bnRpbWUgLSBob3VycyIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSkpCmBgYApJbiB0aGlzIGdyYXBoIHdlIGNhbiBzZWUgdGhhdCB0aGUgZGVuc2l0eSB1c2luZyB0aGUgImdlbnJlMSIgYW5kICJydW50aW1lX2hvdXJzIiB2YXJpYWJsZXMgYmVoYXZlcyBpbiBhIHJpZ2h0IHNrZXdlZCBmb3JtLCBzaG93aW5nIHVzIHRoZSBtb3ZpZSBnZW5yZXMgdGhhdCB1c2UgdGhlIG1vc3QgaG91cnMgYW5kIHRob3NlIHRoYXQgdXNlIHRoZSBsZWFzdC4KCiMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiAjNTI4QjhCOyI+T3V0bGllcnM8L3NwYW4+CgpgYGB7cn0KZ2dwbG90KGNvbGxlY3Rpb25fZGF0YSwgYWVzKHkgPSBydW50aW1lKSkgKwogIGdlb21fYm94cGxvdCgpCmBgYApIZXJlIHdlIGNhbiBzZWUgdGhhdCBtb3N0IG9mIHRoZSB2YWx1ZXMgYXJlIGNvbmNlbnRyYXRlZCBmcm9tIHRoZSB2YWx1ZSA2MDAgb253YXJkcywgdGhlcmVmb3JlIGFsbCB2YWx1ZXMgYWJvdmUgMTAgYXJlIGNvbnNpZGVyZWQgb3V0bGllcnMgaW4gdGhlICJydW50aW1lX2hvdXJzIiB2YXJpYWJsZS4KCiMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiAjNTI4QjhCOyI+UGxvdHRpbmcgd2l0aG91dCBvdXRsaWVyczwvc3Bhbj4KCmBgYHtyIHdhcm5pbmc9RkFMU0V9CmNvbGxlY3Rpb25fZGF0YSRydW50aW1lX2hvdXJzIDwtIGFzLm51bWVyaWMoY29sbGVjdGlvbl9kYXRhJHJ1bnRpbWUpCgpmaWx0ZXJlZF9kYXRhIDwtIGNvbGxlY3Rpb25fZGF0YSAlPiUKICBmaWx0ZXIocnVudGltZV9ob3VycyA8PSAxMCkKCiNDcmVhdGUgdGhlIGRlbnNpdHkgcGxvdCB3aXRoIHRoZSBmaWx0ZXJlZCBkYXRhCmZpbHRlcmVkX2RhdGEgJT4lCiAgZ2dwbG90KGFlcyh4ID0gZ2VucmUxLCBmaWxsID0gcnVudGltZSkpICsKICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjIpICsKICBsYWJzKHRpdGxlID0gIkRlbnNpdHkgaW4gZ2VucmUxIGFuZCBydW50aW1lIC0gaG91cnMiLCB4ID0gImdlbnJlMSIsIHkgPSAicnVudGltZSIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSkKYGBgCgpUaGUgZ3JhcGggbG9va3MgdmVyeSBzaW1pbGFyIGJlY2F1c2UgdGhlcmUgYXJlIHN0aWxsIG1hbnkgb2JzZXJ2YXRpb25zIGV2ZW4gYWZ0ZXIgZWxpbWluYXRpbmcgdGhlIG91dGxpZXJzLCBidXQgaGVyZSB3ZSB3b3VsZCBiZSB2aXN1YWxpemluZyB0aGUgZGVuc2l0eSBvZiBob3cgdGhlIHJlcXVpcmVkIGhvdXJzIGFyZSBkaXN0cmlidXRlZCBpbiBlYWNoIGdlbnJlIG9mIG1vdmllcyB3aXRob3V0IHRoZWlyIG91dGxpZXIgdmFsdWVzLgoKCiMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiAjNTI4QjhCOyI+Q29ycmVsYXRpb248L3NwYW4+CgojIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICM3OUNEQ0Q7Ij5CdWRnZXQgdG8gUmV2ZW51ZTwvc3Bhbj4KYGBge3J9CmdncGxvdChjb3B5X2RhdGEsIGFlcyh5ID0gcmV2ZW51ZSwgeCA9IENsZWFuX2J1ZGdldCkpICsgIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gVFJVRSkKYGBgCgpUaGVyZSBpcyBhIHdlYWsgcG9zaXRpdmUgbGluZWFyIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIGJ1ZGdldCBhbmQgcmVuZW51ZSBvZiBhIG1vdmllLgoKYGBge3J9CmdncGxvdChjb3B5X2RhdGEsIAogICAgICAgYWVzKHggPSBjdXQoQ2xlYW5fYnVkZ2V0X251bWVyaWMsIGJyZWFrcyA9IDUpLCB5ID0gcmV2ZW51ZSkpICsgCiAgZ2VvbV9ib3hwbG90KCkKYGBgCldlIGNhbiB2aXN1YWxpemUgdGhlIGRpc3RyaWJ1dGlvbiBvZiByZXZlbnVlIGFjcm9zcyBkaWZmZXJlbnQgaW50ZXJ2YWxzIG9mIHRoZSBDbGVhbl9idWRnZXRfbnVtZXJpYyB2YXJpYWJsZS4gCgojIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICM3OUNEQ0Q7Ij5OdW1iZXIgb2YgdGl0bGUgbGV0dGVycyB0byBwcm9maXQ8L3NwYW4+CgpgYGB7cn0KIyBDcmVhdGUgbWVhc3VyZSBmb3IgY2hhcmFjdGVyIG51bWJlcgpjb3B5X2RhdGEgPC0gY29weV9kYXRhICU+JQogICAgICAgIG11dGF0ZSh0aXRsZV9udW0gPSBuY2hhcihvcmlnaW5hbF90aXRsZSkpCmBgYAoKYGBge3Igd2FybmluZz1GQUxTRX0KZ2dwbG90KGNvcHlfZGF0YSwgYWVzKHkgPSBwcm9maXQsIHggPSB0aXRsZV9udW0pKSArICBnZW9tX3BvaW50KCkgKyBzdGF0X3Ntb290aChtZXRob2QgPSAibG0iLCBmb3JtdWxhID0geSB+IHggKyBJKHheMiksIHNpemUgPSAxKQoKYGBgCgpUaGVyZSBpcyBhIG5vbiBleGlzdGVudCByZWxhdGlvbnNoaXAgYmV0d2VlbiBjaGFyYWN0ZXIgbnVtYmVyIGFuZCB0aGUgcHJvZml0IG9mIGEgbW92aWUuIFNvIHRoZSBoeXBvdGhlc2lzIG9mIGl0IGJlaW5nIGEgcXVhZHJhdGljIGNvcnJlbGF0aW9uIGlzIGZhbHNlLgpgYGB7cn0KZ2dwbG90KGNvcHlfZGF0YSwgCiAgICAgICBhZXMoeCA9IHRpdGxlX251bSwgeSA9IGN1dChwcm9maXQsIGJyZWFrcyA9IDUpKSkgKyAKICBnZW9tX2JveHBsb3QoKQpgYGAKSG93ZXZlciwgdGhlIGJyZWFrcyBhbGxvd3MgdXMgdG8gc2VlIHRoYXQgZm9yIGxvd2VyIHByb2ZpdHMgdGhlcmUgaXMgYSBncmVhdGVyIG51bWJlciBvZiBvdXRsaWVycyB3aXRoIGhpZ2ggY2hhcmFjdGVyIGNvdW50cywgd2hpbGUgdGhvc2UgaW4gdGhlIGhpZ2hlc3QgcHJvZml0IGJyYWtldCBoYXZlIGxvdyBJUVIgcmFuZ2UgYW5kIHRoYXQgaXQgaXMgc2l0dWF0ZWQgd2l0aCBhIGxvdyBjaGFyYWN0ZXIgY291bnQuCgojIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogIzUyOEI4QjsiPk5vcm1hbCBkaXN0cmlidXRpb24gcHJvYmFiaWxpdGllczwvc3Bhbj4KYGBge3J9CiMgTG9hZCBwYWNrYWdlcwpsaWJyYXJ5KCJlMTA3MSIpICNmb3Igc2tld25lc3MgbWVhc3VyZQpgYGAKCiMjIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogIzc5Q0RDRDsiPlByb2ZpdDwvc3Bhbj4KYGBge3J9Cgpjb3B5X2RhdGEgJT4lCiAgZ2dwbG90KGFlcyh4ID0gcHJvZml0KSkgKwogIGdlb21fZGVuc2l0eSgpCmBgYAoKCmBgYHtyfQojTG9nYXJpdGhtaWMgdHJhbnNmb3JtYXRpb24gCgpsb2dfZGF0YSA8LSBjb3B5X2RhdGEgJT4lCiAgbXV0YXRlKGxvZ19wcm9mID0gbG9nKHByb2ZpdCkpCmBgYAoKYGBge3Igd2FybmluZz1GQUxTRX0KIyBDb252ZXJ0IGludG8gYSBsZWZ0LXNrZXdlZCBkaXN0cmlidXRpb24KCmxvZ19kYXRhICU+JQogIGdncGxvdChhZXMoeCA9IGxvZ19wcm9mKSkgKwogIGdlb21fZGVuc2l0eSgpCmBgYAoKYGBge3J9CmxvZ19kYXRhICU+JQogIHN1bW1hcml6ZShtZWFuKHByb2ZpdCwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgc2QocHJvZml0LCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBJUVIocHJvZml0LCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBzdW0ocHJvZml0KSkKYGBgCmBgYHtyfQojIENvbnZlcnQgdmFyaWFibGVzIGludG8gY29ycmVjdCBvbmVzCmNvbGxlY3Rpb25fZGF0YSRyZXZlbnVlIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGNvbGxlY3Rpb25fZGF0YSRyZXZlbnVlKSkgCgpjb2xsZWN0aW9uX2RhdGEkcmVsZWFzZV9kYXRlIDwtIGFzLkRhdGUoYXMuY2hhcmFjdGVyKGNvbGxlY3Rpb25fZGF0YSRyZWxlYXNlX2RhdGUpKQoKY29sbGVjdGlvbl9kYXRhJHJ1bnRpbWUgPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoY29sbGVjdGlvbl9kYXRhJHJ1bnRpbWUpKQoKY29sbGVjdGlvbl9kYXRhJHZvdGVfYXZlcmFnZSA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3Rlcihjb2xsZWN0aW9uX2RhdGEkdm90ZV9hdmVyYWdlKSkKCmNvbGxlY3Rpb25fZGF0YSR2b3RlX2NvdW50IDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGNvbGxlY3Rpb25fZGF0YSR2b3RlX2NvdW50KSkKCmNvbGxlY3Rpb25fZGF0YSRyb3VuZF9wb3B1bGFyaXR5IDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGNvbGxlY3Rpb25fZGF0YSRyb3VuZF9wb3B1bGFyaXR5KSkKCmNvbGxlY3Rpb25fZGF0YSRudW1fc3Bva2VuX2xhbmd1YWdlcyA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3Rlcihjb2xsZWN0aW9uX2RhdGEkbnVtX3Nwb2tlbl9sYW5ndWFnZXMpKQoKY29sbGVjdGlvbl9kYXRhJG51bV9nZW5yZXMgPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoY29sbGVjdGlvbl9kYXRhJG51bV9nZW5yZXMpKQoKY29sbGVjdGlvbl9kYXRhJENsZWFuX2J1ZGdldCA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3Rlcihjb2xsZWN0aW9uX2RhdGEkQ2xlYW5fYnVkZ2V0KSkKYGBgCiMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiAjNTI4QjhCOyI+Q29uY2x1c2lvbjwvc3Bhbj4KVGhlIGRpc3RyaWJ1dGlvbiBvZiBwcm9maXRzIHdhcyB2aXN1YWxpemVkIHVzaW5nIGEgZGVuc2l0eSBwbG90IGFuZCBhIGxvZ2FyaXRobWljIHRyYW5zZm9ybWF0aW9uIHdhcyBhcHBsaWVkIHRvIGFjaGlldmUgYSBsZWZ0LXNrZXdlZCBkaXN0cmlidXRpb24uIFN1bW1hcnkgc3RhdGlzdGljcyB3ZXJlIGNvbXB1dGVkIGZvciB0aGUgdHJhbnNmb3JtZWQgcHJvZml0IHZhcmlhYmxlLCBpbmNsdWRpbmcgbWVhbiwgc3RhbmRhcmQgZGV2aWF0aW9uLCBpbnRlcnF1YXJ0aWxlIHJhbmdlLCBhbmQgdG90YWwgcHJvZml0IHN1bS4gUHJvYmFiaWxpdGllcyB3ZXJlIGNhbGN1bGF0ZWQgdG8gZGV0ZXJtaW5lIHRoZSBsaWtlbGlob29kIG9mIHByb2ZpdHMgZXhjZWVkaW5nIHNwZWNpZmljIHRocmVzaG9sZHMgYmFzZWQgb24gdGhlIGxvZy10cmFuc2Zvcm1lZCBwcm9maXQgZGlzdHJpYnV0aW9uLiAKClRoZSBhbmFseXNpcyBhbHNvIGludm9sdmVkIGNyZWF0aW5nIGEgbmV3IGNvbHVtbiBjYWxsZWQgJ3Byb2ZpdCcgYW5kIGNhbGN1bGF0aW5nIHN1bW1hcnkgc3RhdGlzdGljcyB3aXRoaW4gcmV2ZW51ZSBncm91cHMuIEEgYmluYXJ5IGNvbHVtbiB3YXMgaW50cm9kdWNlZCB0byBpbmRpY2F0ZSB3aGV0aGVyIGEgbW92aWUncyBwcm9kdWN0aW9uIGNvdW50cnkgZmFsbHMgd2l0aGluIE5vcnRoIEFtZXJpY2EsIGFuZCBzdW1tYXJ5IHN0YXRpc3RpY3Mgd2VyZSBjb21wdXRlZCBiYXNlZCBvbiBtb3ZpZSBnZW9ncmFwaGljYWwgb3JpZ2luLiBUaGUgZXhwbG9yYXRpb24gb2YgcnVudGltZSBjaGFyYWN0ZXJpc3RpY3MgaW52b2x2ZWQgZGVuc2l0eSBwbG90cyBhbmQgYm94cGxvdHMuIEEgc2NhdHRlciBwbG90IHdhcyB1c2VkIHRvIGV4YW1pbmUgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gYnVkZ2V0IGFuZCByZXZlbnVlLCBhbmQgYm94cGxvdCBhbmFseXNpcyB3YXMgY29uZHVjdGVkIHRvIGNvbXBhcmUgcmV2ZW51ZSBkaXN0cmlidXRpb25zIGFjcm9zcyBidWRnZXQgY2F0ZWdvcmllcy4gVGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBudW1iZXIgb2YgdGl0bGUgbGV0dGVycyBhbmQgbW92aWUgcHJvZml0IHdhcyBleHBsb3JlZCB1c2luZyBzY2F0dGVyIHBsb3RzIGFuZCBib3hwbG90cy4gQSBmYWNldGVkIHNjYXR0ZXIgcGxvdCB3YXMgdXNlZCB0byBhbmFseXplIHRoZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gcHJvZml0LCB0aXRsZSBsZXR0ZXJzLCBhbmQgcmV2ZW51ZSBicmFja2V0cy4gIAoKVGhlIGRpc3RyaWJ1dGlvbiBvZiBwcm9maXRzIHdhcyB2aXN1YWxpemVkIHVzaW5nIGEgZGVuc2l0eSBwbG90IGFuZCBzdW1tYXJ5IHN0YXRpc3RpY3Mgd2VyZSBjb21wdXRlZCB0byBnYWluIGEgZGVlcGVyIHVuZGVyc3RhbmRpbmcgb2YgaXRzIGRpc3RyaWJ1dGlvbiBjaGFyYWN0ZXJpc3RpY3MuIEZpbmFsbHksIHByb2JhYmlsaXRpZXMgd2VyZSBjYWxjdWxhdGVkIHRvIGRldGVybWluZSB0aGUgbGlrZWxpaG9vZCBvZiBwcm9maXRzIGV4Y2VlZGluZyBzcGVjaWZpYyB0aHJlc2hvbGRzLgoKT3ZlcmFsbCwgdGhlc2UgYW5hbHlzZXMgcHJvdmlkZSBpbnNpZ2h0cyBpbnRvIHRoZSBkaXN0cmlidXRpb24sIGNlbnRyYWwgdGVuZGVuY3ksIHNoYXBlLCBvdXRsaWVycywgY29ycmVsYXRpb25zLCBhbmQgcHJvYmFiaWxpdGllcyByZWxhdGVkIHRvIHZhcmlvdXMgdmFyaWFibGVzIGluIHRoZSBtb3ZpZSBkYXRhc2V0LCBoZWxwaW5nIHRvIHVuZGVyc3RhbmQga2V5IHBhdHRlcm5zIGFuZCByZWxhdGlvbnNoaXBzIHdpdGhpbiB0aGUgZGF0YS4KCiMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICM2RThCM0Q7Ij5QZXJzb25hbCBGdW5jdGlvbjwvc3Bhbj4KIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICM1MjhCOEI7Ij5Db3JyZWxhdGlvbiB3aXRoIHJvdW5kX3BvcHVsYXRpb248L3NwYW4+CgpgYGB7cn0KcmVncmVzc2lvbiA8LSBsbShyZXZlbnVlIH4gIHJlbGVhc2VfZGF0ZSArIHJ1bnRpbWUgKyB2b3RlX2F2ZXJhZ2UgKyB2b3RlX2NvdW50ICsgcm91bmRfcG9wdWxhcml0eSArIG51bV9zcG9rZW5fbGFuZ3VhZ2VzLCBkYXRhID0gY29sbGVjdGlvbl9kYXRhKQpzdW1tYXJ5KHJlZ3Jlc3Npb24pCmBgYAoKVGhlIHJlc3VsdHMgZmlyc3Qgc2hvdyB0aGUgdmFyaWFibGVzIHRoYXQgbW9zdCBhZmZlY3QgdGhlIG9idGFpbmluZyBvZiByZXZlbnVlIGluIGZpbG1zLiBUaGVzZSB2YXJpYWJsZXMgYXJlOgorIFJ1bnRpbWUKKyBWb3RlIEF2ZXJhZ2UKKyBWb3RlIENvdW50CitSb3VuZCBQb3B1bGFyaXR5CgpJbiBhZGRpdGlvbiwgd2Ugb2J0YWluZWQgYW4gYWRqdXN0ZWQgUiBzcXVhcmVkIHdpdGggYSB2YWx1ZSBvZiAwLjY2MzgsIGluZGljYXRpbmcgdGhhdCBhcHByb3hpbWF0ZWx5IDY2LjM4JSBvZiB0aGUgdmFyaWFiaWxpdHkgaW4gdGhlIGRlcGVuZGVudCB2YXJpYWJsZSwgaW4gdGhpcyBjYXNlIHRoZSByZXZlbnVlIHZhcmlhYmxlLCBjYW4gYmUgZXhwbGFpbmVkIGJ5IHRoZSBpbmRlcGVuZGVudCB2YXJpYWJsZXMgaW5jbHVkZWQgaW4gdGhlIHJlZ3Jlc3Npb24gbW9kZWwsIGVzcGVjaWFsbHkgYnkgdGhlIHZhcmlhYmxlcyBJIG1lbnRpb25lZCBiZWZvcmUuCgpgYGB7cn0KIyBBZGp1c3QgdGhlIHJlZ3Jlc3Npb24gZm9yIGdyZWF0ZXIgcHJlY2lzaW9uCmFkanVzdGVkX3JlZ3Jlc3Npb24gPC0gbG0ocmV2ZW51ZSB+IHJ1bnRpbWUgKyB2b3RlX2F2ZXJhZ2UgKyB2b3RlX2NvdW50ICsgcm91bmRfcG9wdWxhcml0eSwgZGF0YSA9IGNvbGxlY3Rpb25fZGF0YSkKc3VtbWFyeShhZGp1c3RlZF9yZWdyZXNzaW9uKQpgYGAKCiMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiAjNTI4QjhCOyI+UHJlZGljdGl2ZSBtb2RlbDwvc3Bhbj4KCmBgYHtyfQojIFByZWRpY3RpdmUgbW9kZWwKcHJlZGljdGl2ZV9tb2RlbCA8LSBkYXRhLmZyYW1lKHJ1bnRpbWU9OTQsIHZvdGVfYXZlcmFnZT02LCB2b3RlX2NvdW50PTExMCwgcm91bmRfcG9wdWxhcml0eT0zKQpwcmVkaWN0KGFkanVzdGVkX3JlZ3Jlc3Npb24sIHByZWRpY3RpdmVfbW9kZWwpCmBgYApUaGUgbW9kZWwgaXMgdXNpbmcgdGhlIGlucHV0IHZhbHVlcyBvZiAicnVudGltZSIsICJ2b3RlIGF2ZXJhZ2UiLCAidm90ZWNvdW50IiwgYW5kICJyb3VuZCBwb3B1bGFyaXR5IiB0byBwcmVkaWN0IHRoZSByZXZlbnVlIG9mIGEgbW92aWUuVGhlIHByZWRpY3RlZCByZXZlbnVlIG9mIGFwcHJveGltYXRlbHkgJDEwLDk4NiwwNzUgaXMgd2hhdCB0aGUgbW9kZWwgZXN0aW1hdGVzIGJhc2VkIG9uIHRoZXNlIGlucHV0IHZhbHVlcy4KClRoaXMgc2NlbmFyaW8gd2FzIGdlbmVyYXRlZCB3aXRoIGFuIGFjY3VyYWN5IG9mICoqNjYuMzglKiogYWNjb3JkaW5nIHRvIHRoZSBhZGp1c3RlZCBSIHNxdWFyZWQgYW5kIGEgcmVsaWFiaWxpdHkgb2YgOTUlLgoKYGBge3J9CiMgU2NhdHRlciBQbG90IG9mIFJ1bnRpbWUgdnMuIFJldmVudWUKZ2dwbG90KGRhdGEgPSBjb2xsZWN0aW9uX2RhdGEsIGFlcyh4ID0gcnVudGltZSwgeSA9IHJldmVudWUpKSArCiAgZ2VvbV9wb2ludCgpICsKICBsYWJzKHRpdGxlID0gIlJ1bnRpbWUgdnMuIFJldmVudWUiLAogICAgICAgeCA9ICJSdW50aW1lIiwKICAgICAgIHkgPSAiUmV2ZW51ZSIpCgojIFNjYXR0ZXIgUGxvdCBvZiBWb3RlIEF2ZXJhZ2UgdnMuIFJldmVudWUKZ2dwbG90KGRhdGEgPSBjb2xsZWN0aW9uX2RhdGEsIGFlcyh4ID0gdm90ZV9hdmVyYWdlLCB5ID0gcmV2ZW51ZSkpICsKICBnZW9tX3BvaW50KCkgKwogIGxhYnModGl0bGUgPSAiVm90ZSBBdmVyYWdlIHZzLiBSZXZlbnVlIiwKICAgICAgIHggPSAiVm90ZSBBdmVyYWdlIiwKICAgICAgIHkgPSAiUmV2ZW51ZSIpCgojIFNjYXR0ZXIgUGxvdCBvZiBWb3RlIENvdW50IHZzLiBSZXZlbnVlCmdncGxvdChkYXRhID0gY29sbGVjdGlvbl9kYXRhLCBhZXMoeCA9IHZvdGVfY291bnQsIHkgPSByZXZlbnVlKSkgKwogIGdlb21fcG9pbnQoKSArCiAgbGFicyh0aXRsZSA9ICJWb3RlIENvdW50IHZzLiBSZXZlbnVlIiwKICAgICAgIHggPSAiVm90ZSBDb3VudCIsCiAgICAgICB5ID0gIlJldmVudWUiKQoKIyBTY2F0dGVyIFBsb3Qgb2YgUm91bmQgUG9wdWxhcml0eSB2cy4gUmV2ZW51ZQpnZ3Bsb3QoZGF0YSA9IGNvbGxlY3Rpb25fZGF0YSwgYWVzKHggPSByb3VuZF9wb3B1bGFyaXR5LCB5ID0gcmV2ZW51ZSkpICsKICBnZW9tX3BvaW50KCkgKwogIGxhYnModGl0bGUgPSAiUm91bmQgUG9wdWxhcml0eSB2cy4gUmV2ZW51ZSIsCiAgICAgICB4ID0gIlJvdW5kIFBvcHVsYXJpdHkiLAogICAgICAgeSA9ICJSZXZlbnVlIikKCgpgYGAKYGBge3J9CiMgQ29udmVydCBtb3ZpZSBydW50aW1lIHRvIGEgdGltZSBzZXJpZXMgZm9ybWF0CnJ1bnRpbWVfdGltZV9zZXJpZXMgPC0gdHMoY29sbGVjdGlvbl9kYXRhJHJ1bnRpbWUsIHN0YXJ0ID0gMSwgZnJlcXVlbmN5ID0gMSkKCiMgQ29udmVydCByZXZlbnVlIHRvIGEgdGltZSBzZXJpZXMgZm9ybWF0CnJldmVudWVfdGltZV9zZXJpZXMgPC0gdHMoY29sbGVjdGlvbl9kYXRhJHJldmVudWUsIHN0YXJ0ID0gMSwgZnJlcXVlbmN5ID0gMSkKCiMgUGxvdCB0aGUgdGltZSBzZXJpZXMgb2YgcmV2ZW51ZSBhbmQgbW92aWUgcnVudGltZQpwbG90KHJldmVudWVfdGltZV9zZXJpZXMsIG1haW4gPSAiUmV2ZW51ZSBUaW1lIFNlcmllcyIsIHhsYWIgPSAiRmlsbSBJbmRleCIsIHlsYWIgPSAiUmV2ZW51ZSIpCmxpbmVzKHJ1bnRpbWVfdGltZV9zZXJpZXMsIGNvbCA9ICJyZWQiKSAgIyBBZ3JlZ2FyIGzDrW5lYSBwYXJhIGxhIGR1cmFjacOzbiBkZSBsYXMgcGVsw61jdWxhcwpgYGAKCmBgYHtyfQojIEZpdCBhIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsCmxtX21vZGVsIDwtIGxtKHJldmVudWUgfiBydW50aW1lLCBkYXRhID0gY29sbGVjdGlvbl9kYXRhKQoKIyBWaWV3IHRoZSBtb2RlbCBzdW1tYXJ5CnN1bW1hcnkobG1fbW9kZWwpCgojIFBsb3QgdGhlIGRhdGEgYW5kIHRoZSByZWdyZXNzaW9uIGxpbmUKcGxvdChjb2xsZWN0aW9uX2RhdGEkcnVudGltZSwgY29sbGVjdGlvbl9kYXRhJHJldmVudWUsIG1haW4gPSAiU2NhdHRlcnBsb3Qgb2YgUnVudGltZSB2cy4gUmV2ZW51ZSIsCiAgICAgeGxhYiA9ICJSdW50aW1lIChtaW51dGVzKSIsIHlsYWIgPSAiUmV2ZW51ZSIpCmFibGluZShsbV9tb2RlbCwgY29sID0gInJlZCIpICAjIEFncmVnYXIgbMOtbmVhIGRlIHJlZ3Jlc2nDs24gYWwgZ3LDoWZpY28KCmBgYAoKCgpUaGlzIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIHByZWRpY3RzIHJldmVudWUgYmFzZWQgb24gdGhlIGR1cmF0aW9uIG9mIHRoZSBtb3ZpZS4gVGhlIGdyYXBoIGRpc3BsYXlzIGEgcG9zaXRpdmUgbGluZWFyIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBkdXJhdGlvbiBvZiB0aGUgbW92aWUgYW5kIHRoZSByZXZlbnVlLCBpbmRpY2F0aW5nIHRoYXQgYXMgdGhlIGR1cmF0aW9uIG9mIGEgbW92aWUgaW5jcmVhc2VzLCBvbiBhdmVyYWdlLCB3ZSBjYW4gZXhwZWN0IGl0cyByZXZlbnVlIHRvIGluY3JlYXNlIGFzIHdlbGwuIAoKS2V5IGRhdGE6IAoKVGhlIFItc3F1YXJlZCB2YWx1ZSBvZiAwLjcyIGluZGljYXRlcyB0aGF0IDcyJSBvZiB0aGUgdmFyaWF0aW9uIGluIHJldmVudWUgY2FuIGJlIGV4cGxhaW5lZCBieSB0aGUgbGluZWFyIHJlbGF0aW9uc2hpcCB3aXRoIGR1cmF0aW9uLiBUaGlzIHN1Z2dlc3RzIGEgbW9kZXJhdGVseSBzdHJvbmcgcG9zaXRpdmUgY29ycmVsYXRpb24uCgpUaGUgY29lZmZpY2llbnQgZm9yIGR1cmF0aW9uICgwLjAyMikgaXMgcG9zaXRpdmUgYW5kIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgKHAtdmFsdWUgPCAwLjAwMSkuIFRoaXMgbWVhbnMgdGhhdCBmb3IgZWFjaCBhZGRpdGlvbmFsIG1pbnV0ZSBvZiBkdXJhdGlvbiwgd2UgY2FuIGV4cGVjdCBhbiBhdmVyYWdlIGluY3JlYXNlIGluIHJldmVudWUgb2YgJDAuMDIyLCBob2xkaW5nIG90aGVyIGZhY3RvcnMgY29uc3RhbnQuCgoKIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogIzZFOEIzRDsiPkdlbmVyYWwgY29uY2x1c2lvbjwvc3Bhbj4KSW4gY29uY2x1c2lvbiwgdGhlIHN1Y2Nlc3Mgb2YgYSBtb3ZpZSBpcyB0aGUgcmVzdWx0IG9mIGFuIGludGVyYWN0aW9uIG9mIHZhcmlvdXMgZmFjdG9ycy4gVGhyb3VnaCBkYXRhIGFuYWx5c2lzLCB3ZSBoYXZlIGRpc2NvdmVyZWQgdGhhdCBlbGVtZW50cyBzdWNoIGFzIGdlbnJlLCBidWRnZXQsIGR1cmF0aW9uLCBhbmQgcXVhbGl0eSBhcmUgaW1wb3J0YW50IGluIGRldGVybWluaW5nIGJvdGggZmluYW5jaWFsIHBlcmZvcm1hbmNlIGFuZCBhdWRpZW5jZSByZWNlcHRpb24uIFBvcHVsYXIgZ2VucmVzIGxpa2UgQWR2ZW50dXJlLCBBbmltYXRpb24sIGFuZCBGYW50YXN5IHRlbmQgdG8gZ2VuZXJhdGUgaGlnaGVyIHJldmVudWVzLCB3aGlsZSBhbiBhZGVxdWF0ZSBidWRnZXQgY2FuIHN1cHBvcnQgcHJvZHVjdGlvbiBxdWFsaXR5LiBIb3dldmVyLCBzdWNjZXNzIGlzIG5vdCBndWFyYW50ZWVkIHNvbGVseSBieSBhIGhpZ2ggYnVkZ2V0IG9yIGxvbmcgZHVyYXRpb247IHF1YWxpdHkgYW5kIGF1ZGllbmNlIGFjY2VwdGFuY2UgYXJlIGFsc28gY3J1Y2lhbC4gVGhlcmVmb3JlLCBtYWpvciBwcm9kdWN0aW9uIGNvbXBhbmllcyBzaG91bGQgZm9jdXMgb24gaW52ZXN0aW5nIGluIHBvcHVsYXIgZ2VucmVzIHdoaWxlIG1haW50YWluaW5nIGEgYmFsYW5jZSBiZXR3ZWVuIGJ1ZGdldCBhbmQgY29udGVudCBxdWFsaXR5LiBBZGRpdGlvbmFsbHksIGF0dGVudGlvbiB0byBleGVjdXRpb24gYW5kIHByb21vdGlvbiBjYW4gc2lnbmlmaWNhbnRseSBpbXByb3ZlIGEgbW92aWUncyBzdWNjZXNzIHByb3NwZWN0cy4gTGFzdGx5LCB1bmRlcnN0YW5kaW5nIGFuZCBhZGFwdGluZyB0byBhdWRpZW5jZSBwcmVmZXJlbmNlcywgYmFja2VkIGJ5IGRhdGEgYW5hbHlzaXMsIGNhbiBiZSBrZXkgdG8gc3VjY2VzcyBpbiB0aGUgZmlsbSBpbmR1c3RyeS4KCgoKCgoK