Project 1: Explore and Prepare Data (2023)

Note: This project involves getting data ready for analysis and doing some preliminary investigations. Project 2 will involve modeling and predictions, and will be released at a later date. Both projects will have equal weightage towards your grade.

In this project, you will explore a dataset that contains information about movies, including ratings, budget, gross revenue and other attributes. It was prepared by Dr.Guy Lebanon, and here is his description of the dataset:

The file movies_merged contains a dataframe with the same name that has 40K rows and 39 columns. Each row represents a movie title and each column represents a descriptor such as Title, Actors, and Budget. I collected the data by querying IMDb’s API (see www.omdbapi.com) and joining it with a separate dataset of movie budgets and gross earnings (unknown to you). The join key was the movie title. This data is available for personal use, but IMDb’s terms of service do not allow it to be used for commercial purposes or for creating a competing repository.

Your goal is to investigate the relationship between the movie descriptors and the box office success of movies, as represented by the variable Gross. This task is extremely important as it can help a studio decide which titles to fund for production, how much to bid on produced movies, when to release a title, how much to invest in marketing and PR, etc. This information is most useful before a title is released, but it is still very valuable after the movie is already released to the public (for example it can affect additional marketing spend or how much a studio should negotiate with on-demand streaming companies for a second window streaming rights).

This is an R Markdown Notebook. Open this file in RStudio to get started.

When you execute code within the notebook, the results appear beneath the code. Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Cmd+Shift+Enter.

x = 1:10print(x^2)
 [1] 1 4 9 16 25 36 49 64 81 100

Plots appear inline too:

plot(x, x^2, 'o')

Project 1: Explore and Prepare Data (1)

Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Cmd+Option+I.

When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Cmd+Shift+K to preview the HTML file).

Please complete the tasks below and submit this R Markdown file (as pr1.Rmd) as well as a PDF export of it (as pr1.pdf). Both should contain all the code, output, plots and written responses for each task.

Load data

Make sure you’ve downloaded the movies_merged file and it is in the current working directory. Now load it into memory:

load('movies_merged')

This creates an object of the same name (movies_merged). For convenience, you can copy it to df and start using it:

df = movies_mergedcat("Dataset has", dim(df)[1], "rows and", dim(df)[2], "columns", end="\n", file="")
Dataset has 40789 rows and 39 columns 
colnames(df)
 [1] "Title" "Year" "Rated" "Released" "Runtime" "Genre" "Director" "Writer" [9] "Actors" "Plot" "Language" "Country" "Awards" "Poster" "Metascore" "imdbRating" [17] "imdbVotes" "imdbID" "Type" "tomatoMeter" "tomatoImage" "tomatoRating" "tomatoReviews" "tomatoFresh" [25] "tomatoRotten" "tomatoConsensus" "tomatoUserMeter" "tomatoUserRating" "tomatoUserReviews" "tomatoURL" "DVD" "BoxOffice" [33] "Production" "Website" "Response" "Budget" "Domestic_Gross" "Gross" "Date" 

Load R packages

Load any R packages that you will need to use. You can come back to this chunk, edit it and re-run to load any additional packages later.

library(ggplot2)library(GGally)library(tm)library(SnowballC)
package <U+393C><U+3E31>SnowballC<U+393C><U+3E32> was built under R version 3.3.2
library(stringi)library("tm")library(stringr)library(reshape2)library(GGally)

If you are loading any non-standard packages (ones that have not been discussed in class or explicitly allowed for this project), please mention them below. Include any special instructions if they cannot be installed using the regular install.packages('<pkg name>') command.

Non-standard packages used: None

Each task below is worth 10 points, and is meant to be performed sequentially, i.e.do step 2 after you have processed the data as described in step 1. Total points: 100

Complete each task by implementing code chunks as described by TODO comments, and by responding to questions (“Q:”) with written answers (“A:”). If you are unable to find a meaningful or strong relationship in any of the cases when requested, explain why not by referring to appropriate plots/statistics.

It is OK to handle missing values below by omission, but please omit as little as possible. It is worthwhile to invest in reusable and clear code as you may need to use it or modify it in project 2.

1. Remove non-movie rows

The variable Type captures whether the row is a movie, a TV series, or a game. Remove all rows from df that do not correspond to movies.

# TODO: Remove all rows from df that do not correspond to moviesdf = df[df$Type=="movie",]nrow(df)
[1] 40000

Q: How many rows are left after removal? Enter your response below.

A: 4000

2. Process Runtime column

The variable Runtime represents the length of the title as a string. Write R code to convert it to a numeric value (in minutes) and replace df$Runtime with the new numeric column.

# TODO: Replace df$Runtime with a numeric column containing the runtime in minutesRuntimeToMinutes = function(str){ v = strsplit(str, " ")[[1]] res = 0 if(length(v) < 2){ print(v) return(0) } for (i in seq(2, length(v)+1, 2)) { if (v[[i]] == "min") res = res + as.integer(v[i-1]) if (v[[i]] == "h") res = res + as.integer(v[i-1]) * 60 } return(res)}# Let's remove NAsdf = df[df$Runtime != "N/A" & !is.na(df$Runtime),]# Convert Runtime variable to numericdf$Runtime = sapply(df$Runtime, RuntimeToMinutes)

Now investigate the distribution of Runtime values and how it changes over years (variable Year, which you can bucket into decades) and in relation to the budget (variable Budget). Include any plots that illustrate.

Answer Part 1 - Runtime distribution

# TODO: Investigate the distribution of Runtime values and how it varies by Year and Budgetsummary(df$Runtime)
 Min. 1st Qu. Median Mean 3rd Qu. Max. 1.00 72.00 90.00 81.79 101.00 873.00 
sd(df$Runtime)
[1] 38.29093

Let’s see the movies Runtime distribution

chart <- ggplot(df) + geom_density(aes(x=Runtime), fill='yellow') + xlab("Runtime in minutes") + ylab("Density") + ggtitle("Figure 1 - Distribution of Movies Runtime")print(chart)

Project 1: Explore and Prepare Data (2)

Answer Part 2 - Relationship between Runtime and Year

Let’s first bucket movies into decades.

YearToDecade = function(year){ if(year >= 1880 && year < 1890) return("1880s") if(year >= 1890 && year < 1900) return("1890s") if(year >= 1900 && year < 1910) return("1900s") if(year >= 1910 && year < 1920) return("1910s") if(year >= 1920 && year < 1930) return("1920s") if(year >= 1930 && year < 1940) return("1930s") if(year >= 1940 && year < 1950) return("1940s") if(year >= 1950 && year < 1960) return("1950s") if(year >= 1960 && year < 1970) return("1960s") if(year >= 1970 && year < 1980) return("1970s") if(year >= 1980 && year < 1990) return("1980s") if(year >= 1990 && year < 2000) return("1990s") if(year >= 2000 && year < 2010) return("2000s") if(year >= 2010) return("2010s") return("Other")}df$Decade = factor(sapply(df$Year, YearToDecade), levels=c("1880s","1890s","1900s","1910s","1920s","1930s","1940s","1950s","1960s","1970s","1980s","1990s","2000s","2010s"))

Now let’s see how Runtime density look like over the decades.

chart <- ggplot(df) + geom_density(aes(x=Runtime), fill='yellow') + facet_wrap(~Decade,scales = "free") + ggtitle("Figure 2 - Movies Runtime density vs Decade")print(chart)

Project 1: Explore and Prepare Data (3)

Now let’s see how Runtime distribution look like over the decades.

chart <- ggplot(df, aes(Decade,Runtime )) + geom_boxplot() + coord_flip() + scale_y_continuous(breaks = round(seq(min(0), max(df$Runtime), by = 20),1)) + ggtitle("Figure 3 - Movies Runtime distribution vs Decade") + theme(axis.text.x=element_text(angle=90,hjust=1,vjust=0.5))print(chart)

Project 1: Explore and Prepare Data (4)

Answer Part 3 - Relationship between Runtime and Budget

Let’s fisrt bucket Budget into buckets.

df = df[!is.na(df$Budget),]ratios = quantile(df$Budget, c(.20, .40, .60, .80))BudgetToType = function(budget){ if(budget<ratios[[1]]) return("Very Low") if(budget<ratios[[2]]) return("Low") if(budget<ratios[[3]]) return("Medium") if(budget<ratios[[4]]) return("High") return("Very High")}df$BudgetType = factor(sapply(as.numeric(df$Budget), BudgetToType), levels = c("Very Low", "Low", "Medium","High","Very High"))

Now let’s see how Runtime density look like over the Budget types.

chart <- ggplot(df) + geom_density(aes(x=Runtime), fill='yellow') + facet_wrap(~BudgetType,scales = "free") + ggtitle("Figure 4 - Movies Runtime density vs Budget types")print(chart)

Project 1: Explore and Prepare Data (5)

Now let’s see how Runtime distribution look like over the Budget types

chart <- ggplot(df, aes(BudgetType,Runtime )) + geom_boxplot() + coord_flip() + scale_y_continuous(breaks = round(seq(min(0), max(df$Runtime), by = 20),1)) + theme(axis.text.x=element_text(angle=90,hjust=1,vjust=0.5)) + ggtitle("Figure 5 - Movies Runtime distribution vs Budget types")print(chart)

Project 1: Explore and Prepare Data (6)

Q: Comment on the distribution as well as relationships. Are there any patterns or trends that you can observe?

A: We can see that the mean Runtime is 81.44 minutes with a standard deviation of 38.29 minutes. The median is 90 minutes, the minimum is 1 minute, and the maximum is 873 minutes. There are two main peaks in movies Runtime distribution: 15 minutes and 90 minutes, please refer to Figure 1 - Distribution of Movies Runtime. Most probably these peaks, 15 and 90 minutes , represent the most common length for short films and feature films respectively.

Regarding relationship between Runtime and Year: we grouped the movies into Decade buckets and then plotted movies Runtime density, Figure 2 - Movies Runtime density vs Decade, and distribution, Figure 3 - Movies Runtime distribution vs Decade, in each decade. Figures show that the median movie Runtime is increase over time with the biggest increase in the 1920s. It shows also that the short-feature films trend started in the 1920s. Since its start, the short-feature film trend lasted till 1950s in a more balanced shape. Since 1960s number of feature films started to increase significantly relative to number of short films. This increase in feature films continues till today (Maybe becuase feature films are more profitable).

From Figure 4 - Movies Runtime density vs Budget types : it seems to be the movies Runtime have a normal distribution with median that increases as the Budget increases. It make sense because the bigger budget you have, the longer movie you can produce. Although some movies have very high or very low budgets, the median Runtime generally falls between 90 and 120 minutes (Maybe because the movie Runtime is not the only factor that consumes the budget).

3. Encode Genre column

The column Genre represents a list of genres associated with the movie in a string format. Write code to parse each text string into a binary vector with 1s representing the presence of a genre and 0s the absence, and add it to the dataframe as additional columns. Then remove the original Genre column.

For example, if there are a total of 3 genres: Drama, Comedy, and Action, a movie that is both Action and Comedy should be represented by a binary vector <0, 1, 1>. Note that you need to first compile a dictionary of all possible genres and then figure out which movie has which genres (you can use the R tm package to create the dictionary).

# TODO: Replace Genre with a collection of binary columnsgenreCorpus = VCorpus(VectorSource(df$Genre))genreCorpus = tm_map(genreCorpus, content_transformer(tolower))genreCorpus = tm_map(genreCorpus, removeWords, c("N/A"))genreCorpus = tm_map(genreCorpus, removePunctuation)genreDocumentTermMatrix = DocumentTermMatrix(genreCorpus)genreMatrix = as.data.frame(as.matrix(genreDocumentTermMatrix))df = merge(genreMatrix, df, by=0, all=TRUE)

Plot the relative proportions of movies having the top 10 most common genres.

# TODO: Select movies from top 10 most common genres and plot their relative proportionsgenreFrequencies = colSums(as.matrix(genreDocumentTermMatrix))genreFrequenciesOrdered = genreFrequencies[order(genreFrequencies,decreasing = TRUE)]topGenres = genreFrequenciesOrdered[1:10]topGenresName = names(topGenres)genresDataFrame = data.frame(names(genreFrequenciesOrdered), genreFrequenciesOrdered/sum(genreFrequencies))names(genresDataFrame) = c("Genre","Frequency")chart <- ggplot(genresDataFrame) + geom_bar(aes(x = Genre, y = Frequency), stat = "identity") + theme(axis.text.x=element_text(angle=90,hjust=1,vjust=0.5)) + ggtitle("Figure 6 - Movies Genre frequency")print(chart)

Project 1: Explore and Prepare Data (7)

Examine how the distribution of Runtime changes across genres for the top 10 most common genres.

# TODO: Plot Runtime distribution for top 10 most common genres# Let's prepare our datameltedTopGenresRuntime = melt(df, id.vars = c("Title","Runtime"), measure.vars = c(topGenresName))meltedTopGenresRuntime = meltedTopGenresRuntime[meltedTopGenresRuntime$value!=0,]meltedTopGenresRuntime = meltedTopGenresRuntime[!is.na(meltedTopGenresRuntime$Runtime),]

Now we can examine the Runtime distribution for top 10 most common Genres

chart <- ggplot(meltedTopGenresRuntime, aes(reorder(variable, Runtime, median), Runtime)) + geom_boxplot() + coord_flip() + scale_y_continuous(labels = scales::comma) + xlab("Genre") + ggtitle("Figure 7 - Movies Runtime distribution for top 10 most common Genres") print(chart)

Project 1: Explore and Prepare Data (8)

And also the Runtime density

chart <- ggplot(meltedTopGenresRuntime) + geom_density(aes(x=Runtime), fill='yellow') + facet_wrap(~variable, scales = "free") + ggtitle("Figure 8 - Movies Runtime density for top 10 most common Genres")print(chart)

Project 1: Explore and Prepare Data (9)

Q: Describe the interesting relationship(s) you observe. Are there any expected or unexpected trends that are evident?

A: We can notice from Figure 7 - Movies Runtime distribution for top 10 most common Genres that top 10 most common movie genres have a median close to 100 minutes, with comedy have the lowest median and sci-fi have the highest median. We can also notice from Figure 8 - Movies Runtime density for top 10 most common Genres that all top 10 most common genres have one clear peak which could be helpful if predictions need to be make in the future.

4. Eliminate mismatched rows

The dataframe was put together by merging two different sources of data and it is possible that the merging process was inaccurate in some cases (the merge was done based on movie title, but there are cases of different movies with the same title). The first source is release time was represented by the column Year (numeric representation of the year) and the second by the column Released (string representation of release date).

Find and remove all rows where you suspect a merge error occurred based on a mismatch between these two variables. To make sure subsequent analysis and modeling work well, avoid removing more than 10% of the rows that have a Gross value present.

# TODO: Remove rows with Released-Year mismatchdf$YearReleased <- as.numeric(format(as.Date(df$Released, format = "%Y-%m-%d"), "%Y"))temp <- dfdf <- df[ (df$Year != df$YearReleased) | (is.na(df$YearReleased) & !is.na(df$Year)) | (!is.na(df$YearReleased) & is.na(df$Year)),]

The number of removed rows is

print(nrow(temp)-nrow(df))
[1] 3718

Q: What is your precise removal logic and how many rows did you end up removing?

A: In order to find Released-Year mismatch, we need to parse Released column and extract the year part of it and assign it to a new column YearReleased. Then we remove the rows that YearReleased don’t equal Year OR one and only one of the two columns (Year, YearReleased) is NA. We removed 3718 rows

5. Explore Gross revenue

For the commercial success of a movie, production houses want to maximize Gross revenue. Investigate if Gross revenue is related to Budget, Runtime or Genre in any way.

Note: To get a meaningful relationship, you may have to partition the movies into subsets such as short vs.long duration, or by genre, etc.

# TODO: Investigate if Gross Revenue is related to Budget, Runtime or Genreoptions(scipen=999)

Answer Part 1 - Gross Revenue vs Budget

chart <- ggplot(df, aes(Budget, Gross)) + geom_point() + ggtitle("Figure 9 - Movies Budget vs. Gross")print(chart)

Project 1: Explore and Prepare Data (10)

Answer Part 2 - Gross Revenue vs Runtime

chart <- ggplot(df, aes(Runtime, Gross)) + geom_point() + ggtitle("Figure 10 - Movies Runtime vs. Gross")print(chart)

Project 1: Explore and Prepare Data (11)

Answer Part 3 - Gross Revenue vs Genre

# Let's do so preparations firstmeltedTopGenresGross = melt(df, id.vars = c("Title","Gross"), measure.vars = c(names(genreFrequencies)))meltedTopGenresGross = meltedTopGenresGross[meltedTopGenresGross$value!=0,]meltedTopGenresGross = meltedTopGenresGross[!is.na(meltedTopGenresGross$Gross),]# let's use this gross distribution to do a visual zoom on our blot to focus on non-outlierszeroToFifthQ = boxplot.stats(meltedTopGenresGross$Gross)$stats[c(1, 5)]chart <- ggplot(meltedTopGenresGross, aes(reorder(variable, -Gross,median), Gross)) + geom_boxplot() + theme(axis.text.x=element_text(angle=90,hjust=1,vjust=0.5)) + xlab("Genre") + coord_flip() + coord_cartesian(ylim = zeroToFifthQ*2) + scale_y_continuous(labels = scales::comma) + ggtitle("Figure 11 - Movies Genre vs. Gross")print(chart)

Project 1: Explore and Prepare Data (12)

Q: Did you find any observable relationships or combinations of Budget/Runtime/Genre that result in high Gross revenue? If you divided the movies into different subsets, you may get different answers for them - point out interesting ones.

A: It seems from Figure 9 - Movies Budget vs.Gross and Figure 10 - Movies Runtime vs.Gross that there is no direct clear relationship between Budget and Gross nor Runtim and Gross. Most movies’ budget falls below 50000000 and Gross below 200000000. Most movies’ runtime falls between 75 and 150 minutes. Within this budget range and runtime range, there is no clear correlation between Budget and Gross nor Runtim and Gross. It seems from Figure 11 - Movies Genre vs.Gross that (musical, western, sport) genres have the highest median gross; on the other hand (documentry, mystery, history) have the lowest gross

# TODO: Investigate if Gross Revenue is related to Release Monthdf$Month = as.numeric(format(as.Date(df$Released, format = "%Y-%m-%d"), "%m"))GetMonthName = function(num){ switch(as.numeric(num),"Jan","Feb","Mar","Apr","May","Jun", "Jul","Aug","Sep","Oct","Nov","Dec")}df$Month = factor( lapply(as.numeric(df$Month, units="months"), GetMonthName), levels=c("Jan","Feb","Mar","Apr","May","Jun", "Jul","Aug","Sep","Oct","Nov","Dec"))cleanDF = df[!is.na(df$Month),]chart <- ggplot(cleanDF, aes(reorder(Month, Gross, median), Gross)) + geom_boxplot() + coord_flip() + scale_y_continuous(labels = scales::comma) + xlab("Month") + ggtitle("Figure 10 - Movies Gross distribution vs. release Month")print(chart)

Project 1: Explore and Prepare Data (13)

We see from Figure 10 - Movies Gross distribution vs.release Month that movies Gross is related to release Month with (Jan, Feb, Dec) represent the top months in median Gross and (Aug, Nov, Sep) are the lowest in median Gross.

6. Process Awards column

The variable Awards describes nominations and awards in text format. Convert it to 2 numeric columns, the first capturing the number of wins, and the second capturing nominations. Replace the Awards column with these new columns, and then study the relationship of Gross revenue with respect to them.

Note that the format of the Awards column is not standard; you may have to use regular expressions to find the relevant values. Try your best to process them, and you may leave the ones that don’t have enough information as NAs or set them to 0s.

# TODO: Convert Awards to 2 numeric columns: wins and nominations# Let's process Awards columndf$AwardsNum <- sapply(df$Awards, function(awards) as.numeric( unlist( regmatches(awards, gregexpr("+[0-9]+", awards))[[1]] ) ) )df$Wins = 0df$Nominations = 0rowsWithInvalidAwards <- 0for(i in 1:nrow(df)){ #print(paste(i, df[i,]$Awards, sep = " == > ")) # 1 number found : find out if it is win or nomination if( (length(df[i,]$AwardsNum[[1]])!=3) & (length(df[i,]$AwardsNum[[1]])!=2) & (length(df[i,]$AwardsNum[[1]])!=0)){ if(length(grep("win",df[i,]$Awards))>0){ #print(paste(as.character(df[i,]$AwardsNum[[1]][1]) , "Win", sep=" ")) df[i,]$Wins = as.numeric(df[i,]$AwardsNum[[1]][1]) } if(length(grep("nomination",df[i,]$Awards))>0){ #print(paste(as.character(df[i,]$AwardsNum[[1]][1]) , "nomination", sep=" ")) df[i,]$Nominations = as.numeric(df[i,]$AwardsNum[[1]][1]) } } # 2 numbers found : most probably the first is win and the second is nomination if(length(df[i,]$AwardsNum[[1]])==2){ if((length(grep("win",df[i,]$Awards))>0) || (length(grep("won",df[i,]$Awards))>0)|| (length(grep("Won",df[i,]$Awards))>0)){ #print(paste(as.character(df[i,]$AwardsNum[[1]][1]) , "Win", sep=" ")) df[i,]$Wins = as.numeric(df[i,]$AwardsNum[[1]][1]) } if(length(grep("nomination",df[i,]$Awards))>0){ #print(paste(as.character(df[i,]$AwardsNum[[1]][2]) , "nomination", sep=" ")) df[i,]$Nominations = as.numeric(df[i,]$AwardsNum[[1]][2]) } } # 3 numbers found : most probably the first is total or another award, the second is win, and the third is nomination if(length(df[i,]$AwardsNum[[1]])==3){ if((length(grep("win",df[i,]$Awards))>0) || (length(grep("won",df[i,]$Awards))>0)|| (length(grep("Won",df[i,]$Awards))>0)){ #print(paste(as.character(df[i,]$AwardsNum[[1]][2]) , "Win", sep=" ")) df[i,]$Wins = as.numeric(df[i,]$AwardsNum[[1]][2]) } if(length(grep("nomination",df[i,]$Awards))>0){ #print(paste(as.character(df[i,]$AwardsNum[[1]][3]) , "nomination", sep=" ")) df[i,]$Nominations = as.numeric(df[i,]$AwardsNum[[1]][3]) } } # no numbers found : set both win and nomination to 0, increment the rowsWithInvalidAwards counter if(length(df[i,]$AwardsNum[[1]])==0){ df[i,]$Wins = 0 df[i,]$Nominations = 0 rowsWithInvalidAwards = rowsWithInvalidAwards + 1 } if(length(unlist(df[i,]$Wins))==1) df[i,]$Wins = as.numeric(unlist(df[i,]$Wins)) else print(paste(df[i,]$Awards, df[i,]$Wins, sep = " ==> " )) if(length(unlist(df[i,]$Nominations))==1) df[i,]$Nominations = as.numeric(unlist(df[i,]$Nominations)[[1]]) else print(paste(df[i,]$Nominations, df[i,]$Nominations, sep = " ==> " ))}

Number of rows that have non-zero wins nominations is 675

print(nrow(df) - rowsWithInvalidAwards)
[1] 675

Q: How did you construct your conversion mechanism? How many rows had valid/non-zero wins or nominations?

A: First I counted how many numbers exist in the Awards column using regular expressions. Based on number of regular expression matches (each match represent one number within the Awards column) we decide the value for Wins and Nominations column. If there is one number: use regular expression to decide if this number is for Wins or Nominations. If there are two numbers: use regular expressions to make sure the first one goes to Wins if any of the following exist(“Win”, “win”, “won”), use regular expression to make sure the second one goes to Nominations if (“nomination”) exists. If there are three numbers: use regular expressions to make sure the second one goes to Wins if any of the following exist(“Win”, “win”, “won”), use regular expression to make sure the third one goes to Nominations if (“nomination”) exists. If there are no numbers: count this row as Invalid row. This counter will be used to answer the second part of this question. I found 674 rows with valid non-zero wins or nominations.

# TODO: Plot Gross revenue against wins and nominationsggplot(df, aes(Gross)) + geom_point(data=df, aes(y=Wins, color="Wins")) + geom_point(data=df, aes(y=Nominations, color="Nominations")) + labs(title="Figure 11 - Nominations/Wins vs. Gross", x="Gross", y="Nominations / Wins")

Project 1: Explore and Prepare Data (14)

Let’s see Wins alone against Gross

ggplot(df) + geom_point(data=df, aes(x=Wins, y=Gross)) + labs(title="Figure 12 - Wins vs. Gross", x="Wins", y="Gross")

Project 1: Explore and Prepare Data (15)

Let’s see Nominations alone against Gross

ggplot(df) + geom_point(data=df, aes(x=Nominations, y=Gross)) + labs(title="Figure 13 - Nominations vs. Gross", x="Nominations", y="Gross")

Project 1: Explore and Prepare Data (16)

Q: How does the gross revenue vary by number of awards won and nominations received?

A: We can notice from Figures 11, Figure 12, and Figure 13 that neither wins nor nominations correlate with Gross. Both wins and nominations fall below 50 regardless to Gross.

7. Movie ratings from IMDb and Rotten Tomatoes

There are several variables that describe ratings, including IMDb ratings (imdbRating represents average user ratings and imdbVotes represents the number of user ratings), and multiple Rotten Tomatoes ratings (represented by several variables pre-fixed by tomato). Read up on such ratings on the web (for example rottentomatoes.com/about and www.imdb.com/help/show_leaf?votestopfaq).

Investigate the pairwise relationships between these different descriptors using graphs.

# TODO: Illustrate how ratings from IMDb and Rotten Tomatoes are relatedchart <- ggpairs(df[, c("imdbVotes","imdbRating","tomatoMeter","tomatoRating", "tomatoUserRating")], title = "Figure 14 - Pairwise relationships between IMDB and tomato ratings.")print(chart)
 plot: [1,1] [=====------------------------------------------------------------------------------------------------------------------------------------] 4% est: 0s plot: [1,2] [===========------------------------------------------------------------------------------------------------------------------------------] 8% est: 2s plot: [1,3] [================-------------------------------------------------------------------------------------------------------------------------] 12% est: 2s plot: [1,4] [======================-------------------------------------------------------------------------------------------------------------------] 16% est: 2s plot: [1,5] [===========================--------------------------------------------------------------------------------------------------------------] 20% est: 2s plot: [2,1] [=================================--------------------------------------------------------------------------------------------------------] 24% est: 2s plot: [2,2] [======================================---------------------------------------------------------------------------------------------------] 28% est: 2s plot: [2,3] [============================================---------------------------------------------------------------------------------------------] 32% est: 2s plot: [2,4] [=================================================----------------------------------------------------------------------------------------] 36% est: 2s plot: [2,5] [=======================================================----------------------------------------------------------------------------------] 40% est: 2s plot: [3,1] [============================================================-----------------------------------------------------------------------------] 44% est: 2s plot: [3,2] [==================================================================-----------------------------------------------------------------------] 48% est: 2s plot: [3,3] [=======================================================================------------------------------------------------------------------] 52% est: 1s plot: [3,4] [=============================================================================------------------------------------------------------------] 56% est: 1s plot: [3,5] [==================================================================================-------------------------------------------------------] 60% est: 1s plot: [4,1] [========================================================================================-------------------------------------------------] 64% est: 1s plot: [4,2] [=============================================================================================--------------------------------------------] 68% est: 1s plot: [4,3] [===================================================================================================--------------------------------------] 72% est: 1s plot: [4,4] [========================================================================================================---------------------------------] 76% est: 1s plot: [4,5] [==============================================================================================================---------------------------] 80% est: 1s plot: [5,1] [===================================================================================================================----------------------] 84% est: 0s plot: [5,2] [=========================================================================================================================----------------] 88% est: 0s plot: [5,3] [==============================================================================================================================-----------] 92% est: 0s plot: [5,4] [====================================================================================================================================-----] 96% est: 0s plot: [5,5] [=========================================================================================================================================]100% est: 0s 

Project 1: Explore and Prepare Data (17)

We can notice from Figure 14 - Pairwise relationships between IMDB and tomato ratings. that most rating columns have a bell shaped distribution with some sort skewness except imdbVotes. We can also notice that tomatoRating and tomatoMeter have high correlation 95 which make sense given that tomatoMeter is the percentage of critics giving positive review and tomatoRating is overall critics average. tomatoUserRating and imdbRating follows that with 86.1 correlation which make sense since both provided by users. tomatoRating and imdbRating follows that with 73.5 correlation. Lowest correlation happend to be between tomatoMeter and imdbVotes.

Q: Comment on the similarities and differences between the user ratings of IMDb and the critics ratings of Rotten Tomatoes.

A: We can notice from Figure 14 - Pairwise relationships between IMDB and tomato ratings. that tomatoRating and imdbRating have 73.5 correlation, both have similar bell shapped distributions, both have peaks close to 7. Although there is high correlation, but it is not as high as the 86.1 correlation between tomatoUserRating and imdbRating.

8. Ratings and awards

These ratings typically reflect the general appeal of the movie to the public or gather opinions from a larger body of critics. Whereas awards are given by professional societies that may evaluate a movie on specific attributes, such as artistic performance, screenplay, sound design, etc.

Study the relationship between ratings and awards using graphs (awards here refers to wins and/or nominations).

# TODO: Show how ratings and awards are related#Will study Win + Nominations against ("imdbVotes","imdbRating","tomatoMeter","tomatoRating", "tomatoUserRating")

Win + Nominations vs.imdbVotes

chart <- ggplot(df) + geom_point(aes(x=imdbVotes,Wins+Nominations)) + geom_smooth(aes(x=imdbVotes, Wins+Nominations), method="lm") + labs(title="Figure 15 - Wins + Nominations vs. IMDB Votes", x="IMDB Votes", y="Wins + Nominations")print(chart)

Project 1: Explore and Prepare Data (18)

Win + Nominations vs.imdbRating

chart <- ggplot(df) + geom_point(aes(x=imdbRating,Wins+Nominations)) + geom_smooth(aes(x=imdbRating, Wins+Nominations), method="lm") + labs(title="Figure 16 - Wins + Nominations vs. IMDB Rating", x="IMDB Rating", y="Wins + Nominations")print(chart)

Project 1: Explore and Prepare Data (19)

Win + Nominations vs.tomatoMeter

chart <- ggplot(df) + geom_point(aes(x=tomatoMeter,Wins+Nominations)) + geom_smooth(aes(x=tomatoMeter, Wins+Nominations), method="lm") + labs(title="Figure 17 - Wins + Nominations vs. tomato Meter", x="tomato Meter", y="Wins + Nominations")print(chart)

Project 1: Explore and Prepare Data (20)

Win + Nominations vs.tomato Rating

chart <- ggplot(df) + geom_point(aes(x=tomatoRating,Wins+Nominations)) + geom_smooth(aes(x=tomatoRating, Wins+Nominations), method="lm") + labs(title="Figure 18 - Wins + Nominations vs. tomato Rating", x="tomato Rating", y="Wins + Nominations")print(chart)

Project 1: Explore and Prepare Data (21)

Win + Nominations vs.tomato User Rating

chart <- ggplot(df) + geom_point(aes(x=tomatoUserRating,Wins+Nominations)) + geom_smooth(aes(x=tomatoUserRating, Wins+Nominations), method="lm") + labs(title="Figure 19 - Wins + Nominations vs. tomato User Rating", x="tomato Rating", y="Wins + Nominations")print(chart)

Project 1: Explore and Prepare Data (22)

Q: How good are these ratings in terms of predicting the success of a movie in winning awards or nominations? Is there a high correlation between two variables?

A: All ratings have clear linear correlation with movies’ Wins + Nominations; so they can be good predictors for movie award model. The highest correlation is between IMDB votes and total award wins/nomination.

9. Expected insights

Come up with two new insights (backed up by data and graphs) that is expected. Here a new means insights that are not an immediate consequence of one of the above tasks. You may use any of the columns already explored above or a different one in the dataset, such as Title, Actors, etc.

# TODO: Find and illustrate two expected insights

Expected insight #1 - Domestic Gross vs Gross

chart <- ggplot(df) + geom_point(aes(x=Domestic_Gross,Gross)) + geom_smooth(aes(x=Domestic_Gross,Gross), method="lm") + scale_x_continuous(labels = scales::comma) + scale_y_continuous(labels = scales::comma) + labs(title="Figure 20 - Domestic Gross vs. Gross", x="Domestic Gross", y="Gross")print(chart)

Project 1: Explore and Prepare Data (23)

Q: Expected insight #1.

A: As it is clear from Figure 13 - Domestic Gross vs.Gross that is a linear relationship between Domestic Gross and Gross.

Expected insight #2 - Observations regarding how much the dataset is focused on USA English movies

print(paste("%", (( nrow(df[(df$Language == "English"),]) / nrow(df) ) * 100), "of movies are only in English.", sep = " "))
[1] "% 94.2016980741354 of movies are only in English."
print(paste("%", (( nrow(df[(df$Country == "USA"),]) / nrow(df) ) * 100), "of movies are made in USA.", sep = " "))
[1] "% 91.4889211016774 of movies are made in USA."
print(paste("%", (( nrow(df[((df$Gross + df$Domestic_Gross - df$Budget) < 0),])/nrow(df) ) * 100), "of movies are losing money.", sep = " "))
[1] "% 90.9919237937461 of movies are losing money."

Q: Expected insight #2.

A: The following statistics show how much the data set is focused on movies produced in USA in English: % 94.2 of movies are only in English. % 91.5 of movies are made in USA. % 90.9 of movies are losing money.

10. Unexpected insight

Come up with one new insight (backed up by data and graphs) that is unexpected at first glance and do your best to motivate it. Same instructions apply as the previous task.

# TODO: Find and illustrate one unexpected insight

Investigating Budget vs.Total Gross

chart <- ggplot(df) + geom_point(aes(x=Budget,Gross + Domestic_Gross)) + geom_smooth(aes(x=Budget, Gross + Domestic_Gross),method="lm") + labs(title="Figure 21 - Budget vs. Total Gross", x="Budget", y="Total Gross")print(chart)

Project 1: Explore and Prepare Data (24)

Investigating Budget vs.Total Award wins and nominations

chart <- ggplot(df) + geom_point(aes(x=Budget, Wins+Nominations)) + geom_smooth(aes(x=Budget, Wins+Nominations),method="lm") + labs(title="Figure 22 - Budget vs. Wins + Nominations", x="Budget", y="Wins + Nominations")print(chart)

Project 1: Explore and Prepare Data (25)

Investigating Budget vs.tomatoRating (Critic reviews)

chart <- ggplot(df) + geom_point(aes(x=Budget, tomatoRating )) + geom_smooth(aes(x=Budget, tomatoRating),method="lm") + labs(title="Figure 23 - Budget vs. tomato Rating", x="Budget", y="tomatoRating")print(chart)

Project 1: Explore and Prepare Data (26)

Q: Unexpected insight.

A: As we notice from Figures 20, 21, 22: Budget is highly correlated with total gross and award winning and nominations but not with average critics ratings. This means that increasing the movie budget will increase its gross and also its awards’ chances, but it is irrelavant to critics reviews of the movie. I was expecting the awards’ wins/nominations to correlate with tomatoRating, but it doesn’t.

LS0tDQp0aXRsZTogJ1Byb2plY3QgMTogRXhwbG9yZSBhbmQgUHJlcGFyZSBEYXRhJw0Kc3VidGl0bGU6ICJDU0U2MjQyIC0gRGF0YSBhbmQgVmlzdWFsIEFuYWx5dGljcyAtIFNwcmluZyAyMDE3IC1cbkViZWlkIEVsU2F5ZWQgLSBFYmVpZEBnYXRlY2guZWR1ICINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdA0KICBodG1sX2RvY3VtZW50OiBkZWZhdWx0DQogIHBkZl9kb2N1bWVudDogZGVmYXVsdA0KLS0tDQoNCl9Ob3RlOiBUaGlzIHByb2plY3QgaW52b2x2ZXMgZ2V0dGluZyBkYXRhIHJlYWR5IGZvciBhbmFseXNpcyBhbmQgZG9pbmcgc29tZSBwcmVsaW1pbmFyeSBpbnZlc3RpZ2F0aW9ucy4gUHJvamVjdCAyIHdpbGwgaW52b2x2ZSBtb2RlbGluZyBhbmQgcHJlZGljdGlvbnMsIGFuZCB3aWxsIGJlIHJlbGVhc2VkIGF0IGEgbGF0ZXIgZGF0ZS4gQm90aCBwcm9qZWN0cyB3aWxsIGhhdmUgZXF1YWwgd2VpZ2h0YWdlIHRvd2FyZHMgeW91ciBncmFkZS5fDQoNCiMgRGF0YQ0KDQpJbiB0aGlzIHByb2plY3QsIHlvdSB3aWxsIGV4cGxvcmUgYSBkYXRhc2V0IHRoYXQgY29udGFpbnMgaW5mb3JtYXRpb24gYWJvdXQgbW92aWVzLCBpbmNsdWRpbmcgcmF0aW5ncywgYnVkZ2V0LCBncm9zcyByZXZlbnVlIGFuZCBvdGhlciBhdHRyaWJ1dGVzLiBJdCB3YXMgcHJlcGFyZWQgYnkgRHIuIEd1eSBMZWJhbm9uLCBhbmQgaGVyZSBpcyBoaXMgZGVzY3JpcHRpb24gb2YgdGhlIGRhdGFzZXQ6DQoNCj4gVGhlIGZpbGUgW2Btb3ZpZXNfbWVyZ2VkYF0oaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL2NvbnRlbnQudWRhY2l0eS1kYXRhLmNvbS9jb3Vyc2VzL2d0LWNzNjI0Mi9wcm9qZWN0L21vdmllc19tZXJnZWQpIGNvbnRhaW5zIGEgZGF0YWZyYW1lIHdpdGggdGhlIHNhbWUgbmFtZSB0aGF0IGhhcyA0MEsgcm93cyBhbmQgMzkgY29sdW1ucy4gRWFjaCByb3cgcmVwcmVzZW50cyBhIG1vdmllIHRpdGxlIGFuZCBlYWNoIGNvbHVtbiByZXByZXNlbnRzIGEgZGVzY3JpcHRvciBzdWNoIGFzIGBUaXRsZWAsIGBBY3RvcnNgLCBhbmQgYEJ1ZGdldGAuIEkgY29sbGVjdGVkIHRoZSBkYXRhIGJ5IHF1ZXJ5aW5nIElNRGIncyBBUEkgKHNlZSBbd3d3Lm9tZGJhcGkuY29tXShodHRwOi8vd3d3Lm9tZGJhcGkuY29tLykpIGFuZCBqb2luaW5nIGl0IHdpdGggYSBzZXBhcmF0ZSBkYXRhc2V0IG9mIG1vdmllIGJ1ZGdldHMgYW5kIGdyb3NzIGVhcm5pbmdzICh1bmtub3duIHRvIHlvdSkuIFRoZSBqb2luIGtleSB3YXMgdGhlIG1vdmllIHRpdGxlLiBUaGlzIGRhdGEgaXMgYXZhaWxhYmxlIGZvciBwZXJzb25hbCB1c2UsIGJ1dCBJTURiJ3MgdGVybXMgb2Ygc2VydmljZSBkbyBub3QgYWxsb3cgaXQgdG8gYmUgdXNlZCBmb3IgY29tbWVyY2lhbCBwdXJwb3NlcyBvciBmb3IgY3JlYXRpbmcgYSBjb21wZXRpbmcgcmVwb3NpdG9yeS4NCg0KIyBPYmplY3RpdmUNCg0KWW91ciBnb2FsIGlzIHRvIGludmVzdGlnYXRlIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgbW92aWUgZGVzY3JpcHRvcnMgYW5kIHRoZSBib3ggb2ZmaWNlIHN1Y2Nlc3Mgb2YgbW92aWVzLCBhcyByZXByZXNlbnRlZCBieSB0aGUgdmFyaWFibGUgYEdyb3NzYC4gVGhpcyB0YXNrIGlzIGV4dHJlbWVseSBpbXBvcnRhbnQgYXMgaXQgY2FuIGhlbHAgYSBzdHVkaW8gZGVjaWRlIHdoaWNoIHRpdGxlcyB0byBmdW5kIGZvciBwcm9kdWN0aW9uLCBob3cgbXVjaCB0byBiaWQgb24gcHJvZHVjZWQgbW92aWVzLCB3aGVuIHRvIHJlbGVhc2UgYSB0aXRsZSwgaG93IG11Y2ggdG8gaW52ZXN0IGluIG1hcmtldGluZyBhbmQgUFIsIGV0Yy4gVGhpcyBpbmZvcm1hdGlvbiBpcyBtb3N0IHVzZWZ1bCBiZWZvcmUgYSB0aXRsZSBpcyByZWxlYXNlZCwgYnV0IGl0IGlzIHN0aWxsIHZlcnkgdmFsdWFibGUgYWZ0ZXIgdGhlIG1vdmllIGlzIGFscmVhZHkgcmVsZWFzZWQgdG8gdGhlIHB1YmxpYyAoZm9yIGV4YW1wbGUgaXQgY2FuIGFmZmVjdCBhZGRpdGlvbmFsIG1hcmtldGluZyBzcGVuZCBvciBob3cgbXVjaCBhIHN0dWRpbyBzaG91bGQgbmVnb3RpYXRlIHdpdGggb24tZGVtYW5kIHN0cmVhbWluZyBjb21wYW5pZXMgZm9yIGEgc2Vjb25kIHdpbmRvdyBzdHJlYW1pbmcgcmlnaHRzKS4NCg0KIyBJbnN0cnVjdGlvbnMNClRoaXMgaXMgYW4gW1IgTWFya2Rvd25dKGh0dHA6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20pIE5vdGVib29rLiBPcGVuIHRoaXMgZmlsZSBpbiBSU3R1ZGlvIHRvIGdldCBzdGFydGVkLg0KDQpXaGVuIHlvdSBleGVjdXRlIGNvZGUgd2l0aGluIHRoZSBub3RlYm9vaywgdGhlIHJlc3VsdHMgYXBwZWFyIGJlbmVhdGggdGhlIGNvZGUuIFRyeSBleGVjdXRpbmcgdGhpcyBjaHVuayBieSBjbGlja2luZyB0aGUgKlJ1biogYnV0dG9uIHdpdGhpbiB0aGUgY2h1bmsgb3IgYnkgcGxhY2luZyB5b3VyIGN1cnNvciBpbnNpZGUgaXQgYW5kIHByZXNzaW5nICpDbWQrU2hpZnQrRW50ZXIqLiANCg0KYGBge3J9DQp4ID0gMToxMA0KcHJpbnQoeF4yKQ0KYGBgDQoNClBsb3RzIGFwcGVhciBpbmxpbmUgdG9vOg0KYGBge3J9DQpwbG90KHgsIHheMiwgJ28nKQ0KYGBgDQoNCkFkZCBhIG5ldyBjaHVuayBieSBjbGlja2luZyB0aGUgKkluc2VydCBDaHVuayogYnV0dG9uIG9uIHRoZSB0b29sYmFyIG9yIGJ5IHByZXNzaW5nICpDbWQrT3B0aW9uK0kqLg0KDQpXaGVuIHlvdSBzYXZlIHRoZSBub3RlYm9vaywgYW4gSFRNTCBmaWxlIGNvbnRhaW5pbmcgdGhlIGNvZGUgYW5kIG91dHB1dCB3aWxsIGJlIHNhdmVkIGFsb25nc2lkZSBpdCAoY2xpY2sgdGhlICpQcmV2aWV3KiBidXR0b24gb3IgcHJlc3MgKkNtZCtTaGlmdCtLKiB0byBwcmV2aWV3IHRoZSBIVE1MIGZpbGUpLg0KDQpQbGVhc2UgY29tcGxldGUgdGhlIHRhc2tzIGJlbG93IGFuZCBzdWJtaXQgdGhpcyBSIE1hcmtkb3duIGZpbGUgKGFzICoqcHIxLlJtZCoqKSBhcyB3ZWxsIGFzIGEgUERGIGV4cG9ydCBvZiBpdCAoYXMgKipwcjEucGRmKiopLiBCb3RoIHNob3VsZCBjb250YWluIGFsbCB0aGUgY29kZSwgb3V0cHV0LCBwbG90cyBhbmQgd3JpdHRlbiByZXNwb25zZXMgZm9yIGVhY2ggdGFzay4NCg0KIyBTZXR1cA0KDQojIyBMb2FkIGRhdGENCg0KTWFrZSBzdXJlIHlvdSd2ZSBkb3dubG9hZGVkIHRoZSBbYG1vdmllc19tZXJnZWRgXShodHRwczovL3MzLmFtYXpvbmF3cy5jb20vY29udGVudC51ZGFjaXR5LWRhdGEuY29tL2NvdXJzZXMvZ3QtY3M2MjQyL3Byb2plY3QvbW92aWVzX21lcmdlZCkgZmlsZSBhbmQgaXQgaXMgaW4gdGhlIGN1cnJlbnQgd29ya2luZyBkaXJlY3RvcnkuIE5vdyBsb2FkIGl0IGludG8gbWVtb3J5Og0KDQpgYGB7cn0NCmxvYWQoJ21vdmllc19tZXJnZWQnKQ0KYGBgDQoNClRoaXMgY3JlYXRlcyBhbiBvYmplY3Qgb2YgdGhlIHNhbWUgbmFtZSAoYG1vdmllc19tZXJnZWRgKS4gRm9yIGNvbnZlbmllbmNlLCB5b3UgY2FuIGNvcHkgaXQgdG8gYGRmYCBhbmQgc3RhcnQgdXNpbmcgaXQ6DQoNCmBgYHtyfQ0KZGYgPSBtb3ZpZXNfbWVyZ2VkDQpjYXQoIkRhdGFzZXQgaGFzIiwgZGltKGRmKVsxXSwgInJvd3MgYW5kIiwgZGltKGRmKVsyXSwgImNvbHVtbnMiLCBlbmQ9IlxuIiwgZmlsZT0iIikNCmNvbG5hbWVzKGRmKQ0KYGBgDQoNCiMjIExvYWQgUiBwYWNrYWdlcw0KDQpMb2FkIGFueSBSIHBhY2thZ2VzIHRoYXQgeW91IHdpbGwgbmVlZCB0byB1c2UuIFlvdSBjYW4gY29tZSBiYWNrIHRvIHRoaXMgY2h1bmssIGVkaXQgaXQgYW5kIHJlLXJ1biB0byBsb2FkIGFueSBhZGRpdGlvbmFsIHBhY2thZ2VzIGxhdGVyLg0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoR0dhbGx5KQ0KbGlicmFyeSh0bSkNCmxpYnJhcnkoU25vd2JhbGxDKQ0KbGlicmFyeShzdHJpbmdpKQ0KbGlicmFyeSgidG0iKQ0KbGlicmFyeShzdHJpbmdyKQ0KbGlicmFyeShyZXNoYXBlMikNCmxpYnJhcnkoR0dhbGx5KQ0KYGBgDQoNCklmIHlvdSBhcmUgbG9hZGluZyBhbnkgbm9uLXN0YW5kYXJkIHBhY2thZ2VzIChvbmVzIHRoYXQgaGF2ZSBub3QgYmVlbiBkaXNjdXNzZWQgaW4gY2xhc3Mgb3IgZXhwbGljaXRseSBhbGxvd2VkIGZvciB0aGlzIHByb2plY3QpLCBwbGVhc2UgbWVudGlvbiB0aGVtIGJlbG93LiBJbmNsdWRlIGFueSBzcGVjaWFsIGluc3RydWN0aW9ucyBpZiB0aGV5IGNhbm5vdCBiZSBpbnN0YWxsZWQgdXNpbmcgdGhlIHJlZ3VsYXIgYGluc3RhbGwucGFja2FnZXMoJzxwa2cgbmFtZT4nKWAgY29tbWFuZC4NCg0KKipOb24tc3RhbmRhcmQgcGFja2FnZXMgdXNlZCoqOiBOb25lDQoNCiMgVGFza3MNCg0KRWFjaCB0YXNrIGJlbG93IGlzIHdvcnRoICoqMTAqKiBwb2ludHMsIGFuZCBpcyBtZWFudCB0byBiZSBwZXJmb3JtZWQgc2VxdWVudGlhbGx5LCBpLmUuIGRvIHN0ZXAgMiBhZnRlciB5b3UgaGF2ZSBwcm9jZXNzZWQgdGhlIGRhdGEgYXMgZGVzY3JpYmVkIGluIHN0ZXAgMS4gVG90YWwgcG9pbnRzOiAqKjEwMCoqDQoNCkNvbXBsZXRlIGVhY2ggdGFzayBieSBpbXBsZW1lbnRpbmcgY29kZSBjaHVua3MgYXMgZGVzY3JpYmVkIGJ5IGBUT0RPYCBjb21tZW50cywgYW5kIGJ5IHJlc3BvbmRpbmcgdG8gcXVlc3Rpb25zICgiKipRKio6Iikgd2l0aCB3cml0dGVuIGFuc3dlcnMgKCIqKkEqKjoiKS4gSWYgeW91IGFyZSB1bmFibGUgdG8gZmluZCBhIG1lYW5pbmdmdWwgb3Igc3Ryb25nIHJlbGF0aW9uc2hpcCBpbiBhbnkgb2YgdGhlIGNhc2VzIHdoZW4gcmVxdWVzdGVkLCBleHBsYWluIHdoeSBub3QgYnkgcmVmZXJyaW5nIHRvIGFwcHJvcHJpYXRlIHBsb3RzL3N0YXRpc3RpY3MuDQoNCkl0IGlzIE9LIHRvIGhhbmRsZSBtaXNzaW5nIHZhbHVlcyBiZWxvdyBieSBvbWlzc2lvbiwgYnV0IHBsZWFzZSBvbWl0IGFzIGxpdHRsZSBhcyBwb3NzaWJsZS4gSXQgaXMgd29ydGh3aGlsZSB0byBpbnZlc3QgaW4gcmV1c2FibGUgYW5kIGNsZWFyIGNvZGUgYXMgeW91IG1heSBuZWVkIHRvIHVzZSBpdCBvciBtb2RpZnkgaXQgaW4gcHJvamVjdCAyLg0KDQojIyAxLiBSZW1vdmUgbm9uLW1vdmllIHJvd3MNCg0KVGhlIHZhcmlhYmxlIGBUeXBlYCBjYXB0dXJlcyB3aGV0aGVyIHRoZSByb3cgaXMgYSBtb3ZpZSwgYSBUViBzZXJpZXMsIG9yIGEgZ2FtZS4gUmVtb3ZlIGFsbCByb3dzIGZyb20gYGRmYCB0aGF0IGRvIG5vdCBjb3JyZXNwb25kIHRvIG1vdmllcy4NCg0KYGBge3J9DQojIFRPRE86IFJlbW92ZSBhbGwgcm93cyBmcm9tIGRmIHRoYXQgZG8gbm90IGNvcnJlc3BvbmQgdG8gbW92aWVzDQpkZiA9IGRmW2RmJFR5cGU9PSJtb3ZpZSIsXQ0KbnJvdyhkZikNCmBgYA0KDQoqKlEqKjogSG93IG1hbnkgcm93cyBhcmUgbGVmdCBhZnRlciByZW1vdmFsPyBfRW50ZXIgeW91ciByZXNwb25zZSBiZWxvdy5fDQoNCioqQSoqOiA0MDAwDQoNCiMjIDIuIFByb2Nlc3MgYFJ1bnRpbWVgIGNvbHVtbg0KDQpUaGUgdmFyaWFibGUgYFJ1bnRpbWVgIHJlcHJlc2VudHMgdGhlIGxlbmd0aCBvZiB0aGUgdGl0bGUgYXMgYSBzdHJpbmcuIFdyaXRlIFIgY29kZSB0byBjb252ZXJ0IGl0IHRvIGEgbnVtZXJpYyB2YWx1ZSAoaW4gbWludXRlcykgYW5kIHJlcGxhY2UgYGRmJFJ1bnRpbWVgIHdpdGggdGhlIG5ldyBudW1lcmljIGNvbHVtbi4NCg0KYGBge3J9DQojIFRPRE86IFJlcGxhY2UgZGYkUnVudGltZSB3aXRoIGEgbnVtZXJpYyBjb2x1bW4gY29udGFpbmluZyB0aGUgcnVudGltZSBpbiBtaW51dGVzDQpSdW50aW1lVG9NaW51dGVzID0gZnVuY3Rpb24oc3RyKXsNCiAgdiA9IHN0cnNwbGl0KHN0ciwgIiAiKVtbMV1dDQogIHJlcyA9IDANCiAgaWYobGVuZ3RoKHYpIDwgMil7DQogICAgcHJpbnQodikNCiAgICByZXR1cm4oMCkNCiAgfQ0KICBmb3IgKGkgaW4gc2VxKDIsIGxlbmd0aCh2KSsxLCAyKSkgew0KICAgIGlmICh2W1tpXV0gPT0gIm1pbiIpIHJlcyA9IHJlcyArIGFzLmludGVnZXIodltpLTFdKQ0KICAgIGlmICh2W1tpXV0gPT0gImgiKSAgIHJlcyA9IHJlcyArIGFzLmludGVnZXIodltpLTFdKSAqIDYwDQogIH0NCiAgcmV0dXJuKHJlcykNCn0NCiMgTGV0J3MgcmVtb3ZlIE5Bcw0KZGYgPSBkZltkZiRSdW50aW1lICE9ICJOL0EiICYgIWlzLm5hKGRmJFJ1bnRpbWUpLF0NCiMgQ29udmVydCBSdW50aW1lIHZhcmlhYmxlIHRvIG51bWVyaWMNCmRmJFJ1bnRpbWUgPSBzYXBwbHkoZGYkUnVudGltZSwgUnVudGltZVRvTWludXRlcykNCmBgYA0KDQpOb3cgaW52ZXN0aWdhdGUgdGhlIGRpc3RyaWJ1dGlvbiBvZiBgUnVudGltZWAgdmFsdWVzIGFuZCBob3cgaXQgY2hhbmdlcyBvdmVyIHllYXJzICh2YXJpYWJsZSBgWWVhcmAsIHdoaWNoIHlvdSBjYW4gYnVja2V0IGludG8gZGVjYWRlcykgYW5kIGluIHJlbGF0aW9uIHRvIHRoZSBidWRnZXQgKHZhcmlhYmxlIGBCdWRnZXRgKS4gSW5jbHVkZSBhbnkgcGxvdHMgdGhhdCBpbGx1c3RyYXRlLg0KDQojIyMgQW5zd2VyIFBhcnQgMSAtIFJ1bnRpbWUgZGlzdHJpYnV0aW9uDQpgYGB7cn0NCiMgVE9ETzogSW52ZXN0aWdhdGUgdGhlIGRpc3RyaWJ1dGlvbiBvZiBSdW50aW1lIHZhbHVlcyBhbmQgaG93IGl0IHZhcmllcyBieSBZZWFyIGFuZCBCdWRnZXQNCnN1bW1hcnkoZGYkUnVudGltZSkNCnNkKGRmJFJ1bnRpbWUpDQpgYGANCkxldCdzIHNlZSB0aGUgbW92aWVzIFJ1bnRpbWUgZGlzdHJpYnV0aW9uDQpgYGB7cn0NCmNoYXJ0IDwtIGdncGxvdChkZikgKyBnZW9tX2RlbnNpdHkoYWVzKHg9UnVudGltZSksIGZpbGw9J3llbGxvdycpICsgeGxhYigiUnVudGltZSBpbiBtaW51dGVzIikgKyB5bGFiKCJEZW5zaXR5IikgKyANCiAgZ2d0aXRsZSgiRmlndXJlIDEgLSBEaXN0cmlidXRpb24gb2YgTW92aWVzIFJ1bnRpbWUiKQ0KcHJpbnQoY2hhcnQpDQpgYGANCg0KIyMjIEFuc3dlciBQYXJ0IDIgLSBSZWxhdGlvbnNoaXAgYmV0d2VlbiBSdW50aW1lIGFuZCBZZWFyDQpMZXQncyBmaXJzdCBidWNrZXQgbW92aWVzIGludG8gZGVjYWRlcy4NCmBgYHtyfQ0KWWVhclRvRGVjYWRlID0gZnVuY3Rpb24oeWVhcil7DQogIGlmKHllYXIgPj0gMTg4MCAmJiB5ZWFyIDwgMTg5MCkgcmV0dXJuKCIxODgwcyIpDQogIGlmKHllYXIgPj0gMTg5MCAmJiB5ZWFyIDwgMTkwMCkgcmV0dXJuKCIxODkwcyIpDQogIGlmKHllYXIgPj0gMTkwMCAmJiB5ZWFyIDwgMTkxMCkgcmV0dXJuKCIxOTAwcyIpDQogIGlmKHllYXIgPj0gMTkxMCAmJiB5ZWFyIDwgMTkyMCkgcmV0dXJuKCIxOTEwcyIpDQogIGlmKHllYXIgPj0gMTkyMCAmJiB5ZWFyIDwgMTkzMCkgcmV0dXJuKCIxOTIwcyIpDQogIGlmKHllYXIgPj0gMTkzMCAmJiB5ZWFyIDwgMTk0MCkgcmV0dXJuKCIxOTMwcyIpDQogIGlmKHllYXIgPj0gMTk0MCAmJiB5ZWFyIDwgMTk1MCkgcmV0dXJuKCIxOTQwcyIpDQogIGlmKHllYXIgPj0gMTk1MCAmJiB5ZWFyIDwgMTk2MCkgcmV0dXJuKCIxOTUwcyIpDQogIGlmKHllYXIgPj0gMTk2MCAmJiB5ZWFyIDwgMTk3MCkgcmV0dXJuKCIxOTYwcyIpDQogIGlmKHllYXIgPj0gMTk3MCAmJiB5ZWFyIDwgMTk4MCkgcmV0dXJuKCIxOTcwcyIpDQogIGlmKHllYXIgPj0gMTk4MCAmJiB5ZWFyIDwgMTk5MCkgcmV0dXJuKCIxOTgwcyIpDQogIGlmKHllYXIgPj0gMTk5MCAmJiB5ZWFyIDwgMjAwMCkgcmV0dXJuKCIxOTkwcyIpDQogIGlmKHllYXIgPj0gMjAwMCAmJiB5ZWFyIDwgMjAxMCkgcmV0dXJuKCIyMDAwcyIpDQogIGlmKHllYXIgPj0gMjAxMCkgcmV0dXJuKCIyMDEwcyIpDQogIHJldHVybigiT3RoZXIiKQ0KfQ0KDQpkZiREZWNhZGUgPSBmYWN0b3Ioc2FwcGx5KGRmJFllYXIsIFllYXJUb0RlY2FkZSksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzPWMoIjE4ODBzIiwiMTg5MHMiLCIxOTAwcyIsIjE5MTBzIiwiMTkyMHMiLCIxOTMwcyIsIjE5NDBzIiwiMTk1MHMiLCIxOTYwcyIsIjE5NzBzIiwiMTk4MHMiLCIxOTkwcyIsIjIwMDBzIiwiMjAxMHMiKSkNCmBgYA0KTm93IGxldCdzIHNlZSBob3cgUnVudGltZSBkZW5zaXR5IGxvb2sgbGlrZSBvdmVyIHRoZSBkZWNhZGVzLg0KYGBge3J9DQpjaGFydCA8LSBnZ3Bsb3QoZGYpICsgZ2VvbV9kZW5zaXR5KGFlcyh4PVJ1bnRpbWUpLCBmaWxsPSd5ZWxsb3cnKSArIGZhY2V0X3dyYXAofkRlY2FkZSxzY2FsZXMgPSAiZnJlZSIpICsgZ2d0aXRsZSgiRmlndXJlIDIgLSBNb3ZpZXMgUnVudGltZSBkZW5zaXR5IHZzIERlY2FkZSIpDQpwcmludChjaGFydCkNCmBgYA0KTm93IGxldCdzIHNlZSBob3cgUnVudGltZSBkaXN0cmlidXRpb24gbG9vayBsaWtlIG92ZXIgdGhlIGRlY2FkZXMuDQpgYGB7cn0NCmNoYXJ0IDwtIGdncGxvdChkZiwgYWVzKERlY2FkZSxSdW50aW1lICkpICsgZ2VvbV9ib3hwbG90KCkgKyBjb29yZF9mbGlwKCkgKyBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gcm91bmQoc2VxKG1pbigwKSwgbWF4KGRmJFJ1bnRpbWUpLCBieSA9IDIwKSwxKSkgKyAgZ2d0aXRsZSgiRmlndXJlIDMgLSBNb3ZpZXMgUnVudGltZSBkaXN0cmlidXRpb24gdnMgRGVjYWRlIikgKyB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9OTAsaGp1c3Q9MSx2anVzdD0wLjUpKQ0KcHJpbnQoY2hhcnQpDQpgYGANCiMjIyBBbnN3ZXIgUGFydCAzIC0gUmVsYXRpb25zaGlwIGJldHdlZW4gUnVudGltZSBhbmQgQnVkZ2V0DQpMZXQncyBmaXNydCBidWNrZXQgQnVkZ2V0IGludG8gYnVja2V0cy4NCmBgYHtyfQ0KZGYgPSBkZlshaXMubmEoZGYkQnVkZ2V0KSxdDQpyYXRpb3MgPSBxdWFudGlsZShkZiRCdWRnZXQsIGMoLjIwLCAuNDAsIC42MCwgLjgwKSkNCkJ1ZGdldFRvVHlwZSA9IGZ1bmN0aW9uKGJ1ZGdldCl7DQogIGlmKGJ1ZGdldDxyYXRpb3NbWzFdXSkgcmV0dXJuKCJWZXJ5IExvdyIpDQogIGlmKGJ1ZGdldDxyYXRpb3NbWzJdXSkgcmV0dXJuKCJMb3ciKQ0KICBpZihidWRnZXQ8cmF0aW9zW1szXV0pIHJldHVybigiTWVkaXVtIikNCiAgaWYoYnVkZ2V0PHJhdGlvc1tbNF1dKSByZXR1cm4oIkhpZ2giKQ0KICByZXR1cm4oIlZlcnkgSGlnaCIpDQp9DQoNCmRmJEJ1ZGdldFR5cGUgPSBmYWN0b3Ioc2FwcGx5KGFzLm51bWVyaWMoZGYkQnVkZ2V0KSwgQnVkZ2V0VG9UeXBlKSwgbGV2ZWxzID0gYygiVmVyeSBMb3ciLCAiTG93IiwgIk1lZGl1bSIsIkhpZ2giLCJWZXJ5IEhpZ2giKSkNCmBgYA0KTm93IGxldCdzIHNlZSBob3cgUnVudGltZSBkZW5zaXR5IGxvb2sgbGlrZSBvdmVyIHRoZSBCdWRnZXQgdHlwZXMuDQpgYGB7cn0NCmNoYXJ0IDwtIGdncGxvdChkZikgKyBnZW9tX2RlbnNpdHkoYWVzKHg9UnVudGltZSksIGZpbGw9J3llbGxvdycpICsgZmFjZXRfd3JhcCh+QnVkZ2V0VHlwZSxzY2FsZXMgPSAiZnJlZSIpICsgDQogIGdndGl0bGUoIkZpZ3VyZSA0IC0gTW92aWVzIFJ1bnRpbWUgZGVuc2l0eSB2cyBCdWRnZXQgdHlwZXMiKQ0KcHJpbnQoY2hhcnQpDQpgYGANCk5vdyBsZXQncyBzZWUgaG93IFJ1bnRpbWUgZGlzdHJpYnV0aW9uIGxvb2sgbGlrZSBvdmVyIHRoZSBCdWRnZXQgdHlwZXMNCmBgYHtyfQ0KY2hhcnQgPC0gZ2dwbG90KGRmLCBhZXMoQnVkZ2V0VHlwZSxSdW50aW1lICkpICsgZ2VvbV9ib3hwbG90KCkgKyBjb29yZF9mbGlwKCkgKyBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gcm91bmQoc2VxKG1pbigwKSwgbWF4KGRmJFJ1bnRpbWUpLCBieSA9IDIwKSwxKSkgKw0KICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9OTAsaGp1c3Q9MSx2anVzdD0wLjUpKSArIGdndGl0bGUoIkZpZ3VyZSA1IC0gTW92aWVzIFJ1bnRpbWUgZGlzdHJpYnV0aW9uIHZzIEJ1ZGdldCB0eXBlcyIpDQpwcmludChjaGFydCkNCmBgYA0KDQoqKlEqKjogQ29tbWVudCBvbiB0aGUgZGlzdHJpYnV0aW9uIGFzIHdlbGwgYXMgcmVsYXRpb25zaGlwcy4gQXJlIHRoZXJlIGFueSBwYXR0ZXJucyBvciB0cmVuZHMgdGhhdCB5b3UgY2FuIG9ic2VydmU/DQoNCioqQSoqOiBXZSBjYW4gc2VlIHRoYXQgdGhlIG1lYW4gUnVudGltZSBpcyA4MS40NCBtaW51dGVzIHdpdGggYSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgMzguMjkgbWludXRlcy4gVGhlIG1lZGlhbiBpcyA5MCBtaW51dGVzLCB0aGUgbWluaW11bSBpcyAxIG1pbnV0ZSwgYW5kIHRoZSBtYXhpbXVtIGlzIDg3MyBtaW51dGVzLiBUaGVyZSBhcmUgdHdvIG1haW4gcGVha3MgaW4gbW92aWVzIFJ1bnRpbWUgZGlzdHJpYnV0aW9uOiAxNSBtaW51dGVzIGFuZCA5MCBtaW51dGVzLCBwbGVhc2UgcmVmZXIgdG8gKkZpZ3VyZSAxIC0gRGlzdHJpYnV0aW9uIG9mIE1vdmllcyBSdW50aW1lKi4gTW9zdCBwcm9iYWJseSB0aGVzZSBwZWFrcywgMTUgYW5kIDkwIG1pbnV0ZXMgLCByZXByZXNlbnQgdGhlIG1vc3QgY29tbW9uIGxlbmd0aCBmb3IgW3Nob3J0IGZpbG1zXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9TaG9ydF9maWxtKSBhbmQgW2ZlYXR1cmUgZmlsbXNdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0ZlYXR1cmVfZmlsbSkgcmVzcGVjdGl2ZWx5Lg0KDQpSZWdhcmRpbmcgcmVsYXRpb25zaGlwIGJldHdlZW4gUnVudGltZSBhbmQgWWVhcjogd2UgZ3JvdXBlZCB0aGUgbW92aWVzIGludG8gRGVjYWRlIGJ1Y2tldHMgYW5kIHRoZW4gcGxvdHRlZCBtb3ZpZXMgUnVudGltZSBkZW5zaXR5LCAqRmlndXJlIDIgLSBNb3ZpZXMgUnVudGltZSBkZW5zaXR5IHZzIERlY2FkZSosIGFuZCBkaXN0cmlidXRpb24sICpGaWd1cmUgMyAtIE1vdmllcyBSdW50aW1lIGRpc3RyaWJ1dGlvbiB2cyBEZWNhZGUqLCBpbiBlYWNoIGRlY2FkZS4gRmlndXJlcyBzaG93IHRoYXQgdGhlIG1lZGlhbiBtb3ZpZSBSdW50aW1lIGlzIGluY3JlYXNlIG92ZXIgdGltZSB3aXRoIHRoZSBiaWdnZXN0IGluY3JlYXNlIGluIHRoZSAxOTIwcy4gSXQgc2hvd3MgYWxzbyB0aGF0IHRoZSBzaG9ydC1mZWF0dXJlIGZpbG1zIHRyZW5kIHN0YXJ0ZWQgaW4gdGhlIDE5MjBzLiBTaW5jZSBpdHMgc3RhcnQsIHRoZSBzaG9ydC1mZWF0dXJlIGZpbG0gdHJlbmQgbGFzdGVkIHRpbGwgMTk1MHMgaW4gYSBtb3JlIGJhbGFuY2VkIHNoYXBlLiBTaW5jZSAxOTYwcyBudW1iZXIgb2YgZmVhdHVyZSBmaWxtcyBzdGFydGVkIHRvIGluY3JlYXNlIHNpZ25pZmljYW50bHkgcmVsYXRpdmUgdG8gbnVtYmVyIG9mIHNob3J0IGZpbG1zLiBUaGlzIGluY3JlYXNlIGluIGZlYXR1cmUgZmlsbXMgY29udGludWVzIHRpbGwgdG9kYXkgKE1heWJlIGJlY3Vhc2UgZmVhdHVyZSBmaWxtcyBhcmUgbW9yZSBwcm9maXRhYmxlKS4NCg0KRnJvbSAqRmlndXJlIDQgLSBNb3ZpZXMgUnVudGltZSBkZW5zaXR5IHZzIEJ1ZGdldCB0eXBlcyogOiBpdCBzZWVtcyB0byBiZSB0aGUgbW92aWVzIFJ1bnRpbWUgaGF2ZSBhIG5vcm1hbCBkaXN0cmlidXRpb24gd2l0aCBtZWRpYW4gdGhhdCBpbmNyZWFzZXMgYXMgdGhlIEJ1ZGdldCBpbmNyZWFzZXMuIEl0IG1ha2Ugc2Vuc2UgYmVjYXVzZSB0aGUgYmlnZ2VyIGJ1ZGdldCB5b3UgaGF2ZSwgdGhlIGxvbmdlciBtb3ZpZSB5b3UgY2FuIHByb2R1Y2UuIEFsdGhvdWdoIHNvbWUgbW92aWVzIGhhdmUgdmVyeSBoaWdoIG9yIHZlcnkgbG93IGJ1ZGdldHMsIHRoZSBtZWRpYW4gUnVudGltZSBnZW5lcmFsbHkgZmFsbHMgYmV0d2VlbiA5MCBhbmQgMTIwIG1pbnV0ZXMgKE1heWJlIGJlY2F1c2UgdGhlIG1vdmllIFJ1bnRpbWUgaXMgbm90IHRoZSBvbmx5IGZhY3RvciB0aGF0IGNvbnN1bWVzIHRoZSBidWRnZXQpLiANCg0KIyMgMy4gRW5jb2RlIGBHZW5yZWAgY29sdW1uDQoNClRoZSBjb2x1bW4gYEdlbnJlYCByZXByZXNlbnRzIGEgbGlzdCBvZiBnZW5yZXMgYXNzb2NpYXRlZCB3aXRoIHRoZSBtb3ZpZSBpbiBhIHN0cmluZyBmb3JtYXQuIFdyaXRlIGNvZGUgdG8gcGFyc2UgZWFjaCB0ZXh0IHN0cmluZyBpbnRvIGEgYmluYXJ5IHZlY3RvciB3aXRoIDFzIHJlcHJlc2VudGluZyB0aGUgcHJlc2VuY2Ugb2YgYSBnZW5yZSBhbmQgMHMgdGhlIGFic2VuY2UsIGFuZCBhZGQgaXQgdG8gdGhlIGRhdGFmcmFtZSBhcyBhZGRpdGlvbmFsIGNvbHVtbnMuIFRoZW4gcmVtb3ZlIHRoZSBvcmlnaW5hbCBgR2VucmVgIGNvbHVtbi4NCg0KRm9yIGV4YW1wbGUsIGlmIHRoZXJlIGFyZSBhIHRvdGFsIG9mIDMgZ2VucmVzOiBEcmFtYSwgQ29tZWR5LCBhbmQgQWN0aW9uLCBhIG1vdmllIHRoYXQgaXMgYm90aCBBY3Rpb24gYW5kIENvbWVkeSBzaG91bGQgYmUgcmVwcmVzZW50ZWQgYnkgYSBiaW5hcnkgdmVjdG9yIDwwLCAxLCAxPi4gTm90ZSB0aGF0IHlvdSBuZWVkIHRvIGZpcnN0IGNvbXBpbGUgYSBkaWN0aW9uYXJ5IG9mIGFsbCBwb3NzaWJsZSBnZW5yZXMgYW5kIHRoZW4gZmlndXJlIG91dCB3aGljaCBtb3ZpZSBoYXMgd2hpY2ggZ2VucmVzICh5b3UgY2FuIHVzZSB0aGUgUiBgdG1gIHBhY2thZ2UgdG8gY3JlYXRlIHRoZSBkaWN0aW9uYXJ5KS4NCg0KYGBge3J9DQojIFRPRE86IFJlcGxhY2UgR2VucmUgd2l0aCBhIGNvbGxlY3Rpb24gb2YgYmluYXJ5IGNvbHVtbnMNCmdlbnJlQ29ycHVzID0gVkNvcnB1cyhWZWN0b3JTb3VyY2UoZGYkR2VucmUpKQ0KZ2VucmVDb3JwdXMgPSB0bV9tYXAoZ2VucmVDb3JwdXMsIGNvbnRlbnRfdHJhbnNmb3JtZXIodG9sb3dlcikpDQpnZW5yZUNvcnB1cyA9IHRtX21hcChnZW5yZUNvcnB1cywgcmVtb3ZlV29yZHMsIGMoIk4vQSIpKQ0KZ2VucmVDb3JwdXMgPSB0bV9tYXAoZ2VucmVDb3JwdXMsIHJlbW92ZVB1bmN0dWF0aW9uKQ0KDQpnZW5yZURvY3VtZW50VGVybU1hdHJpeCA9IERvY3VtZW50VGVybU1hdHJpeChnZW5yZUNvcnB1cykNCmdlbnJlTWF0cml4ID0gYXMuZGF0YS5mcmFtZShhcy5tYXRyaXgoZ2VucmVEb2N1bWVudFRlcm1NYXRyaXgpKQ0KZGYgPSBtZXJnZShnZW5yZU1hdHJpeCwgZGYsIGJ5PTAsIGFsbD1UUlVFKQ0KYGBgDQoNClBsb3QgdGhlIHJlbGF0aXZlIHByb3BvcnRpb25zIG9mIG1vdmllcyBoYXZpbmcgdGhlIHRvcCAxMCBtb3N0IGNvbW1vbiBnZW5yZXMuDQoNCmBgYHtyfQ0KIyBUT0RPOiBTZWxlY3QgbW92aWVzIGZyb20gdG9wIDEwIG1vc3QgY29tbW9uIGdlbnJlcyBhbmQgcGxvdCB0aGVpciByZWxhdGl2ZSBwcm9wb3J0aW9ucw0KZ2VucmVGcmVxdWVuY2llcyA9IGNvbFN1bXMoYXMubWF0cml4KGdlbnJlRG9jdW1lbnRUZXJtTWF0cml4KSkNCmdlbnJlRnJlcXVlbmNpZXNPcmRlcmVkID0gZ2VucmVGcmVxdWVuY2llc1tvcmRlcihnZW5yZUZyZXF1ZW5jaWVzLGRlY3JlYXNpbmcgPSBUUlVFKV0NCg0KdG9wR2VucmVzID0gZ2VucmVGcmVxdWVuY2llc09yZGVyZWRbMToxMF0NCnRvcEdlbnJlc05hbWUgPSBuYW1lcyh0b3BHZW5yZXMpDQoNCmdlbnJlc0RhdGFGcmFtZSA9IGRhdGEuZnJhbWUobmFtZXMoZ2VucmVGcmVxdWVuY2llc09yZGVyZWQpLCBnZW5yZUZyZXF1ZW5jaWVzT3JkZXJlZC9zdW0oZ2VucmVGcmVxdWVuY2llcykpDQpuYW1lcyhnZW5yZXNEYXRhRnJhbWUpID0gYygiR2VucmUiLCJGcmVxdWVuY3kiKQ0KDQpjaGFydCA8LSBnZ3Bsb3QoZ2VucmVzRGF0YUZyYW1lKSArIGdlb21fYmFyKGFlcyh4ID0gR2VucmUsIHkgPSBGcmVxdWVuY3kpLCBzdGF0ID0gImlkZW50aXR5IikgKyB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9OTAsaGp1c3Q9MSx2anVzdD0wLjUpKSArIGdndGl0bGUoIkZpZ3VyZSA2IC0gTW92aWVzIEdlbnJlIGZyZXF1ZW5jeSIpDQpwcmludChjaGFydCkNCmBgYA0KDQpFeGFtaW5lIGhvdyB0aGUgZGlzdHJpYnV0aW9uIG9mIGBSdW50aW1lYCBjaGFuZ2VzIGFjcm9zcyBnZW5yZXMgZm9yIHRoZSB0b3AgMTAgbW9zdCBjb21tb24gZ2VucmVzLg0KDQpgYGB7cn0NCiMgVE9ETzogUGxvdCBSdW50aW1lIGRpc3RyaWJ1dGlvbiBmb3IgdG9wIDEwIG1vc3QgY29tbW9uIGdlbnJlcw0KDQojIExldCdzIHByZXBhcmUgb3VyIGRhdGENCm1lbHRlZFRvcEdlbnJlc1J1bnRpbWUgPSBtZWx0KGRmLCBpZC52YXJzID0gYygiVGl0bGUiLCJSdW50aW1lIiksIG1lYXN1cmUudmFycyA9IGModG9wR2VucmVzTmFtZSkpDQptZWx0ZWRUb3BHZW5yZXNSdW50aW1lID0gbWVsdGVkVG9wR2VucmVzUnVudGltZVttZWx0ZWRUb3BHZW5yZXNSdW50aW1lJHZhbHVlIT0wLF0NCm1lbHRlZFRvcEdlbnJlc1J1bnRpbWUgPSBtZWx0ZWRUb3BHZW5yZXNSdW50aW1lWyFpcy5uYShtZWx0ZWRUb3BHZW5yZXNSdW50aW1lJFJ1bnRpbWUpLF0NCmBgYA0KTm93IHdlIGNhbiBleGFtaW5lIHRoZSBSdW50aW1lIGRpc3RyaWJ1dGlvbiBmb3IgdG9wIDEwIG1vc3QgY29tbW9uIEdlbnJlcw0KYGBge3J9DQpjaGFydCA8LSBnZ3Bsb3QobWVsdGVkVG9wR2VucmVzUnVudGltZSwgYWVzKHJlb3JkZXIodmFyaWFibGUsIFJ1bnRpbWUsIG1lZGlhbiksIFJ1bnRpbWUpKSArIGdlb21fYm94cGxvdCgpICsgY29vcmRfZmxpcCgpICsgDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmNvbW1hKSArIHhsYWIoIkdlbnJlIikgKyBnZ3RpdGxlKCJGaWd1cmUgNyAtIE1vdmllcyBSdW50aW1lIGRpc3RyaWJ1dGlvbiBmb3IgdG9wIDEwIG1vc3QgY29tbW9uIEdlbnJlcyIpIA0KcHJpbnQoY2hhcnQpDQpgYGANCkFuZCBhbHNvIHRoZSBSdW50aW1lIGRlbnNpdHkNCmBgYHtyfQ0KY2hhcnQgPC0gZ2dwbG90KG1lbHRlZFRvcEdlbnJlc1J1bnRpbWUpICsgZ2VvbV9kZW5zaXR5KGFlcyh4PVJ1bnRpbWUpLCBmaWxsPSd5ZWxsb3cnKSArIGZhY2V0X3dyYXAofnZhcmlhYmxlLCBzY2FsZXMgPSAiZnJlZSIpICsgDQogIGdndGl0bGUoIkZpZ3VyZSA4IC0gTW92aWVzIFJ1bnRpbWUgZGVuc2l0eSBmb3IgdG9wIDEwIG1vc3QgY29tbW9uIEdlbnJlcyIpDQpwcmludChjaGFydCkNCmBgYA0KDQoqKlEqKjogRGVzY3JpYmUgdGhlIGludGVyZXN0aW5nIHJlbGF0aW9uc2hpcChzKSB5b3Ugb2JzZXJ2ZS4gQXJlIHRoZXJlIGFueSBleHBlY3RlZCBvciB1bmV4cGVjdGVkIHRyZW5kcyB0aGF0IGFyZSBldmlkZW50Pw0KDQoqKkEqKjogV2UgY2FuIG5vdGljZSBmcm9tICpGaWd1cmUgNyAtIE1vdmllcyBSdW50aW1lIGRpc3RyaWJ1dGlvbiBmb3IgdG9wIDEwIG1vc3QgY29tbW9uIEdlbnJlcyogdGhhdCB0b3AgMTAgbW9zdCBjb21tb24gbW92aWUgZ2VucmVzIGhhdmUgYSBtZWRpYW4gY2xvc2UgdG8gMTAwIG1pbnV0ZXMsIHdpdGggY29tZWR5IGhhdmUgdGhlIGxvd2VzdCBtZWRpYW4gYW5kIHNjaS1maSBoYXZlIHRoZSBoaWdoZXN0IG1lZGlhbi4gV2UgY2FuIGFsc28gbm90aWNlIGZyb20gKkZpZ3VyZSA4IC0gTW92aWVzIFJ1bnRpbWUgZGVuc2l0eSBmb3IgdG9wIDEwIG1vc3QgY29tbW9uIEdlbnJlcyogdGhhdCBhbGwgdG9wIDEwIG1vc3QgY29tbW9uIGdlbnJlcyBoYXZlIG9uZSBjbGVhciBwZWFrIHdoaWNoIGNvdWxkIGJlIGhlbHBmdWwgaWYgcHJlZGljdGlvbnMgbmVlZCB0byBiZSBtYWtlIGluIHRoZSBmdXR1cmUuDQoNCiMjIDQuIEVsaW1pbmF0ZSBtaXNtYXRjaGVkIHJvd3MNCg0KVGhlIGRhdGFmcmFtZSB3YXMgcHV0IHRvZ2V0aGVyIGJ5IG1lcmdpbmcgdHdvIGRpZmZlcmVudCBzb3VyY2VzIG9mIGRhdGEgYW5kIGl0IGlzIHBvc3NpYmxlIHRoYXQgdGhlIG1lcmdpbmcgcHJvY2VzcyB3YXMgaW5hY2N1cmF0ZSBpbiBzb21lIGNhc2VzICh0aGUgbWVyZ2Ugd2FzIGRvbmUgYmFzZWQgb24gbW92aWUgdGl0bGUsIGJ1dCB0aGVyZSBhcmUgY2FzZXMgb2YgZGlmZmVyZW50IG1vdmllcyB3aXRoIHRoZSBzYW1lIHRpdGxlKS4gVGhlIGZpcnN0IHNvdXJjZSBpcyByZWxlYXNlIHRpbWUgd2FzIHJlcHJlc2VudGVkIGJ5IHRoZSBjb2x1bW4gYFllYXJgIChudW1lcmljIHJlcHJlc2VudGF0aW9uIG9mIHRoZSB5ZWFyKSBhbmQgdGhlIHNlY29uZCBieSB0aGUgY29sdW1uIGBSZWxlYXNlZGAgKHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiByZWxlYXNlIGRhdGUpLg0KDQpGaW5kIGFuZCByZW1vdmUgYWxsIHJvd3Mgd2hlcmUgeW91IHN1c3BlY3QgYSBtZXJnZSBlcnJvciBvY2N1cnJlZCBiYXNlZCBvbiBhIG1pc21hdGNoIGJldHdlZW4gdGhlc2UgdHdvIHZhcmlhYmxlcy4gVG8gbWFrZSBzdXJlIHN1YnNlcXVlbnQgYW5hbHlzaXMgYW5kIG1vZGVsaW5nIHdvcmsgd2VsbCwgYXZvaWQgcmVtb3ZpbmcgbW9yZSB0aGFuIDEwJSBvZiB0aGUgcm93cyB0aGF0IGhhdmUgYSBgR3Jvc3NgIHZhbHVlIHByZXNlbnQuDQoNCmBgYHtyfQ0KIyBUT0RPOiBSZW1vdmUgcm93cyB3aXRoIFJlbGVhc2VkLVllYXIgbWlzbWF0Y2gNCmRmJFllYXJSZWxlYXNlZCA8LSBhcy5udW1lcmljKGZvcm1hdChhcy5EYXRlKGRmJFJlbGVhc2VkLCBmb3JtYXQgPSAiJVktJW0tJWQiKSwgIiVZIikpDQp0ZW1wIDwtIGRmDQpkZiA8LSBkZlsNCiAgKGRmJFllYXIgIT0gZGYkWWVhclJlbGVhc2VkKSB8IA0KICAgIChpcy5uYShkZiRZZWFyUmVsZWFzZWQpICYgIWlzLm5hKGRmJFllYXIpKSB8DQogICAgKCFpcy5uYShkZiRZZWFyUmVsZWFzZWQpICYgaXMubmEoZGYkWWVhcikpLF0NCmBgYA0KVGhlIG51bWJlciBvZiByZW1vdmVkIHJvd3MgaXMNCmBgYHtyfQ0KcHJpbnQobnJvdyh0ZW1wKS1ucm93KGRmKSkNCmBgYA0KKipRKio6IFdoYXQgaXMgeW91ciBwcmVjaXNlIHJlbW92YWwgbG9naWMgYW5kIGhvdyBtYW55IHJvd3MgZGlkIHlvdSBlbmQgdXAgcmVtb3Zpbmc/DQoNCioqQSoqOiBJbiBvcmRlciB0byBmaW5kIFJlbGVhc2VkLVllYXIgbWlzbWF0Y2gsIHdlIG5lZWQgdG8gcGFyc2UgUmVsZWFzZWQgY29sdW1uIGFuZCBleHRyYWN0IHRoZSB5ZWFyIHBhcnQgb2YgaXQgYW5kIGFzc2lnbiBpdCB0byBhIG5ldyBjb2x1bW4gWWVhclJlbGVhc2VkLiBUaGVuIHdlIHJlbW92ZSB0aGUgcm93cyB0aGF0IFllYXJSZWxlYXNlZCBkb24ndCBlcXVhbCBZZWFyIE9SIG9uZSBhbmQgb25seSBvbmUgb2YgdGhlIHR3byBjb2x1bW5zIChZZWFyLCBZZWFyUmVsZWFzZWQpIGlzIE5BLg0KV2UgcmVtb3ZlZCAzNzE4IHJvd3MNCg0KIyMgNS4gRXhwbG9yZSBgR3Jvc3NgIHJldmVudWUNCg0KRm9yIHRoZSBjb21tZXJjaWFsIHN1Y2Nlc3Mgb2YgYSBtb3ZpZSwgcHJvZHVjdGlvbiBob3VzZXMgd2FudCB0byBtYXhpbWl6ZSBHcm9zcyByZXZlbnVlLiBJbnZlc3RpZ2F0ZSBpZiBHcm9zcyByZXZlbnVlIGlzIHJlbGF0ZWQgdG8gQnVkZ2V0LCBSdW50aW1lIG9yIEdlbnJlIGluIGFueSB3YXkuDQoNCk5vdGU6IFRvIGdldCBhIG1lYW5pbmdmdWwgcmVsYXRpb25zaGlwLCB5b3UgbWF5IGhhdmUgdG8gcGFydGl0aW9uIHRoZSBtb3ZpZXMgaW50byBzdWJzZXRzIHN1Y2ggYXMgc2hvcnQgdnMuIGxvbmcgZHVyYXRpb24sIG9yIGJ5IGdlbnJlLCBldGMuDQoNCmBgYHtyfQ0KIyBUT0RPOiBJbnZlc3RpZ2F0ZSBpZiBHcm9zcyBSZXZlbnVlIGlzIHJlbGF0ZWQgdG8gQnVkZ2V0LCBSdW50aW1lIG9yIEdlbnJlDQpvcHRpb25zKHNjaXBlbj05OTkpDQpgYGANCiMjIyBBbnN3ZXIgUGFydCAxIC0gR3Jvc3MgUmV2ZW51ZSB2cyBCdWRnZXQNCmBgYHtyfQ0KY2hhcnQgPC0gZ2dwbG90KGRmLCBhZXMoQnVkZ2V0LCBHcm9zcykpICsgZ2VvbV9wb2ludCgpICsgZ2d0aXRsZSgiRmlndXJlIDkgLSBNb3ZpZXMgQnVkZ2V0IHZzLiBHcm9zcyIpDQpwcmludChjaGFydCkNCmBgYA0KIyMjIEFuc3dlciBQYXJ0IDIgLSBHcm9zcyBSZXZlbnVlIHZzIFJ1bnRpbWUNCmBgYHtyfQ0KY2hhcnQgPC0gZ2dwbG90KGRmLCBhZXMoUnVudGltZSwgR3Jvc3MpKSArIGdlb21fcG9pbnQoKSArIGdndGl0bGUoIkZpZ3VyZSAxMCAtIE1vdmllcyBSdW50aW1lIHZzLiBHcm9zcyIpDQpwcmludChjaGFydCkNCmBgYA0KIyMjIEFuc3dlciBQYXJ0IDMgLSBHcm9zcyBSZXZlbnVlIHZzIEdlbnJlDQpgYGB7cn0NCiMgTGV0J3MgZG8gc28gcHJlcGFyYXRpb25zIGZpcnN0DQptZWx0ZWRUb3BHZW5yZXNHcm9zcyA9IG1lbHQoZGYsIGlkLnZhcnMgPSBjKCJUaXRsZSIsIkdyb3NzIiksIG1lYXN1cmUudmFycyA9IGMobmFtZXMoZ2VucmVGcmVxdWVuY2llcykpKQ0KbWVsdGVkVG9wR2VucmVzR3Jvc3MgPSBtZWx0ZWRUb3BHZW5yZXNHcm9zc1ttZWx0ZWRUb3BHZW5yZXNHcm9zcyR2YWx1ZSE9MCxdDQptZWx0ZWRUb3BHZW5yZXNHcm9zcyA9IG1lbHRlZFRvcEdlbnJlc0dyb3NzWyFpcy5uYShtZWx0ZWRUb3BHZW5yZXNHcm9zcyRHcm9zcyksXQ0KDQojIGxldCdzIHVzZSB0aGlzIGdyb3NzIGRpc3RyaWJ1dGlvbiB0byBkbyBhIHZpc3VhbCB6b29tIG9uIG91ciBibG90IHRvIGZvY3VzIG9uIG5vbi1vdXRsaWVycw0KemVyb1RvRmlmdGhRID0gYm94cGxvdC5zdGF0cyhtZWx0ZWRUb3BHZW5yZXNHcm9zcyRHcm9zcykkc3RhdHNbYygxLCA1KV0NCmNoYXJ0IDwtIGdncGxvdChtZWx0ZWRUb3BHZW5yZXNHcm9zcywgYWVzKHJlb3JkZXIodmFyaWFibGUsIC1Hcm9zcyxtZWRpYW4pLCBHcm9zcykpICsgDQogIGdlb21fYm94cGxvdCgpICsgDQogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT05MCxoanVzdD0xLHZqdXN0PTAuNSkpICsNCiAgeGxhYigiR2VucmUiKSArDQogIGNvb3JkX2ZsaXAoKSArIA0KICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IHplcm9Ub0ZpZnRoUSoyKSArIA0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpjb21tYSkgKyANCiAgZ2d0aXRsZSgiRmlndXJlIDExIC0gTW92aWVzIEdlbnJlIHZzLiBHcm9zcyIpDQpwcmludChjaGFydCkNCmBgYA0KDQoqKlEqKjogRGlkIHlvdSBmaW5kIGFueSBvYnNlcnZhYmxlIHJlbGF0aW9uc2hpcHMgb3IgY29tYmluYXRpb25zIG9mIEJ1ZGdldC9SdW50aW1lL0dlbnJlIHRoYXQgcmVzdWx0IGluIGhpZ2ggR3Jvc3MgcmV2ZW51ZT8gSWYgeW91IGRpdmlkZWQgdGhlIG1vdmllcyBpbnRvIGRpZmZlcmVudCBzdWJzZXRzLCB5b3UgbWF5IGdldCBkaWZmZXJlbnQgYW5zd2VycyBmb3IgdGhlbSAtIHBvaW50IG91dCBpbnRlcmVzdGluZyBvbmVzLg0KDQoqKkEqKjogSXQgc2VlbXMgZnJvbSAqRmlndXJlIDkgLSBNb3ZpZXMgQnVkZ2V0IHZzLiBHcm9zcyogYW5kICpGaWd1cmUgMTAgLSBNb3ZpZXMgUnVudGltZSB2cy4gR3Jvc3MqIHRoYXQgdGhlcmUgaXMgbm8gZGlyZWN0IGNsZWFyIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIEJ1ZGdldCBhbmQgR3Jvc3Mgbm9yIFJ1bnRpbSBhbmQgR3Jvc3MuIE1vc3QgbW92aWVzJyBidWRnZXQgZmFsbHMgYmVsb3cgNTAwMDAwMDAgYW5kIEdyb3NzIGJlbG93IDIwMDAwMDAwMC4gTW9zdCBtb3ZpZXMnIHJ1bnRpbWUgZmFsbHMgYmV0d2VlbiA3NSBhbmQgMTUwIG1pbnV0ZXMuIFdpdGhpbiB0aGlzIGJ1ZGdldCByYW5nZSBhbmQgcnVudGltZSByYW5nZSwgdGhlcmUgaXMgbm8gY2xlYXIgY29ycmVsYXRpb24gYmV0d2VlbiBCdWRnZXQgYW5kIEdyb3NzIG5vciBSdW50aW0gYW5kIEdyb3NzLiBJdCBzZWVtcyBmcm9tICpGaWd1cmUgMTEgLSBNb3ZpZXMgR2VucmUgdnMuIEdyb3NzKiB0aGF0IChtdXNpY2FsLCB3ZXN0ZXJuLCBzcG9ydCkgZ2VucmVzIGhhdmUgdGhlIGhpZ2hlc3QgbWVkaWFuIGdyb3NzOyBvbiB0aGUgb3RoZXIgaGFuZCAoZG9jdW1lbnRyeSwgbXlzdGVyeSwgaGlzdG9yeSkgaGF2ZSB0aGUgbG93ZXN0IGdyb3NzDQoNCmBgYHtyfQ0KIyBUT0RPOiBJbnZlc3RpZ2F0ZSBpZiBHcm9zcyBSZXZlbnVlIGlzIHJlbGF0ZWQgdG8gUmVsZWFzZSBNb250aA0KZGYkTW9udGggPSBhcy5udW1lcmljKGZvcm1hdChhcy5EYXRlKGRmJFJlbGVhc2VkLCBmb3JtYXQgPSAiJVktJW0tJWQiKSwgIiVtIikpDQoNCkdldE1vbnRoTmFtZSA9IGZ1bmN0aW9uKG51bSl7DQogIHN3aXRjaChhcy5udW1lcmljKG51bSksIkphbiIsIkZlYiIsIk1hciIsIkFwciIsIk1heSIsIkp1biIsICJKdWwiLCJBdWciLCJTZXAiLCJPY3QiLCJOb3YiLCJEZWMiKQ0KfQ0KDQpkZiRNb250aCA9IGZhY3RvcigNCiAgbGFwcGx5KGFzLm51bWVyaWMoZGYkTW9udGgsIHVuaXRzPSJtb250aHMiKSwgR2V0TW9udGhOYW1lKSwNCiAgbGV2ZWxzPWMoIkphbiIsIkZlYiIsIk1hciIsIkFwciIsIk1heSIsIkp1biIsICJKdWwiLCJBdWciLCJTZXAiLCJPY3QiLCJOb3YiLCJEZWMiKSkNCg0KY2xlYW5ERiA9IGRmWyFpcy5uYShkZiRNb250aCksXQ0KY2hhcnQgPC0gZ2dwbG90KGNsZWFuREYsIGFlcyhyZW9yZGVyKE1vbnRoLCBHcm9zcywgbWVkaWFuKSwgR3Jvc3MpKSArIGdlb21fYm94cGxvdCgpICsgY29vcmRfZmxpcCgpICsgDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmNvbW1hKSArIHhsYWIoIk1vbnRoIikgKyBnZ3RpdGxlKCJGaWd1cmUgMTAgLSBNb3ZpZXMgR3Jvc3MgZGlzdHJpYnV0aW9uIHZzLiByZWxlYXNlIE1vbnRoIikNCnByaW50KGNoYXJ0KQ0KYGBgDQpXZSBzZWUgZnJvbSAqRmlndXJlIDEwIC0gTW92aWVzIEdyb3NzIGRpc3RyaWJ1dGlvbiB2cy4gcmVsZWFzZSBNb250aCogdGhhdCBtb3ZpZXMgR3Jvc3MgaXMgcmVsYXRlZCB0byByZWxlYXNlIE1vbnRoIHdpdGggKEphbiwgRmViLCBEZWMpIHJlcHJlc2VudCB0aGUgdG9wIG1vbnRocyBpbiBtZWRpYW4gR3Jvc3MgYW5kIChBdWcsIE5vdiwgU2VwKSBhcmUgdGhlIGxvd2VzdCBpbiBtZWRpYW4gR3Jvc3MuDQoNCiMjIDYuIFByb2Nlc3MgYEF3YXJkc2AgY29sdW1uDQoNClRoZSB2YXJpYWJsZSBgQXdhcmRzYCBkZXNjcmliZXMgbm9taW5hdGlvbnMgYW5kIGF3YXJkcyBpbiB0ZXh0IGZvcm1hdC4gQ29udmVydCBpdCB0byAyIG51bWVyaWMgY29sdW1ucywgdGhlIGZpcnN0IGNhcHR1cmluZyB0aGUgbnVtYmVyIG9mIHdpbnMsIGFuZCB0aGUgc2Vjb25kIGNhcHR1cmluZyBub21pbmF0aW9ucy4gUmVwbGFjZSB0aGUgYEF3YXJkc2AgY29sdW1uIHdpdGggdGhlc2UgbmV3IGNvbHVtbnMsIGFuZCB0aGVuIHN0dWR5IHRoZSByZWxhdGlvbnNoaXAgb2YgYEdyb3NzYCByZXZlbnVlIHdpdGggcmVzcGVjdCB0byB0aGVtLg0KDQpOb3RlIHRoYXQgdGhlIGZvcm1hdCBvZiB0aGUgYEF3YXJkc2AgY29sdW1uIGlzIG5vdCBzdGFuZGFyZDsgeW91IG1heSBoYXZlIHRvIHVzZSByZWd1bGFyIGV4cHJlc3Npb25zIHRvIGZpbmQgdGhlIHJlbGV2YW50IHZhbHVlcy4gVHJ5IHlvdXIgYmVzdCB0byBwcm9jZXNzIHRoZW0sIGFuZCB5b3UgbWF5IGxlYXZlIHRoZSBvbmVzIHRoYXQgZG9uJ3QgaGF2ZSBlbm91Z2ggaW5mb3JtYXRpb24gYXMgTkFzIG9yIHNldCB0aGVtIHRvIDBzLg0KDQpgYGB7cn0NCiMgVE9ETzogQ29udmVydCBBd2FyZHMgdG8gMiBudW1lcmljIGNvbHVtbnM6IHdpbnMgYW5kIG5vbWluYXRpb25zDQojIExldCdzIHByb2Nlc3MgQXdhcmRzIGNvbHVtbg0KZGYkQXdhcmRzTnVtIDwtIHNhcHBseShkZiRBd2FyZHMsIA0KICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbihhd2FyZHMpIGFzLm51bWVyaWMoIHVubGlzdCgNCiAgICAgICAgICAgICAgICAgICAgICAgICByZWdtYXRjaGVzKGF3YXJkcywgZ3JlZ2V4cHIoIitbMC05XSsiLCBhd2FyZHMpKVtbMV1dDQogICAgICAgICAgICAgICAgICAgICAgICAgKSApICkNCmRmJFdpbnMgPSAwDQpkZiROb21pbmF0aW9ucyA9IDANCnJvd3NXaXRoSW52YWxpZEF3YXJkcyA8LSAwDQpmb3IoaSBpbiAxOm5yb3coZGYpKXsNCiAgI3ByaW50KHBhc3RlKGksIGRmW2ksXSRBd2FyZHMsIHNlcCA9ICIgPT0gPiAiKSkNCiAgIyAxIG51bWJlciBmb3VuZCA6IGZpbmQgb3V0IGlmIGl0IGlzIHdpbiBvciBub21pbmF0aW9uDQogIGlmKCAobGVuZ3RoKGRmW2ksXSRBd2FyZHNOdW1bWzFdXSkhPTMpICYgKGxlbmd0aChkZltpLF0kQXdhcmRzTnVtW1sxXV0pIT0yKSAmIChsZW5ndGgoZGZbaSxdJEF3YXJkc051bVtbMV1dKSE9MCkpew0KICAgIGlmKGxlbmd0aChncmVwKCJ3aW4iLGRmW2ksXSRBd2FyZHMpKT4wKXsNCiAgICAgICNwcmludChwYXN0ZShhcy5jaGFyYWN0ZXIoZGZbaSxdJEF3YXJkc051bVtbMV1dWzFdKSAsICJXaW4iLCBzZXA9IiAiKSkNCiAgICAgIGRmW2ksXSRXaW5zID0gYXMubnVtZXJpYyhkZltpLF0kQXdhcmRzTnVtW1sxXV1bMV0pICAgICAgICAgIA0KICAgICAgfQ0KICAgIGlmKGxlbmd0aChncmVwKCJub21pbmF0aW9uIixkZltpLF0kQXdhcmRzKSk+MCl7DQogICAgICAjcHJpbnQocGFzdGUoYXMuY2hhcmFjdGVyKGRmW2ksXSRBd2FyZHNOdW1bWzFdXVsxXSkgLCAibm9taW5hdGlvbiIsIHNlcD0iICIpKQ0KICAgICAgZGZbaSxdJE5vbWluYXRpb25zID0gYXMubnVtZXJpYyhkZltpLF0kQXdhcmRzTnVtW1sxXV1bMV0pICAgDQogICAgICB9DQogIH0NCiAgIyAyIG51bWJlcnMgZm91bmQgOiBtb3N0IHByb2JhYmx5IHRoZSBmaXJzdCBpcyB3aW4gYW5kIHRoZSBzZWNvbmQgaXMgbm9taW5hdGlvbg0KICBpZihsZW5ndGgoZGZbaSxdJEF3YXJkc051bVtbMV1dKT09Mil7DQogICAgaWYoKGxlbmd0aChncmVwKCJ3aW4iLGRmW2ksXSRBd2FyZHMpKT4wKSB8fCAobGVuZ3RoKGdyZXAoIndvbiIsZGZbaSxdJEF3YXJkcykpPjApfHwgKGxlbmd0aChncmVwKCJXb24iLGRmW2ksXSRBd2FyZHMpKT4wKSl7DQogICAgICAjcHJpbnQocGFzdGUoYXMuY2hhcmFjdGVyKGRmW2ksXSRBd2FyZHNOdW1bWzFdXVsxXSkgLCAiV2luIiwgc2VwPSIgIikpDQogICAgICBkZltpLF0kV2lucyA9IGFzLm51bWVyaWMoZGZbaSxdJEF3YXJkc051bVtbMV1dWzFdKSAgICAgICAgICANCiAgICB9DQogICAgaWYobGVuZ3RoKGdyZXAoIm5vbWluYXRpb24iLGRmW2ksXSRBd2FyZHMpKT4wKXsNCiAgICAgICNwcmludChwYXN0ZShhcy5jaGFyYWN0ZXIoZGZbaSxdJEF3YXJkc051bVtbMV1dWzJdKSAsICJub21pbmF0aW9uIiwgc2VwPSIgIikpDQogICAgICBkZltpLF0kTm9taW5hdGlvbnMgPSBhcy5udW1lcmljKGRmW2ksXSRBd2FyZHNOdW1bWzFdXVsyXSkgICANCiAgICB9DQogIH0NCiAgIyAzIG51bWJlcnMgZm91bmQgOiBtb3N0IHByb2JhYmx5IHRoZSBmaXJzdCBpcyB0b3RhbCBvciBhbm90aGVyIGF3YXJkLCB0aGUgc2Vjb25kIGlzIHdpbiwgYW5kIHRoZSB0aGlyZCBpcyBub21pbmF0aW9uDQogIGlmKGxlbmd0aChkZltpLF0kQXdhcmRzTnVtW1sxXV0pPT0zKXsNCiAgICBpZigobGVuZ3RoKGdyZXAoIndpbiIsZGZbaSxdJEF3YXJkcykpPjApIHx8IChsZW5ndGgoZ3JlcCgid29uIixkZltpLF0kQXdhcmRzKSk+MCl8fCAobGVuZ3RoKGdyZXAoIldvbiIsZGZbaSxdJEF3YXJkcykpPjApKXsNCiAgICAgICNwcmludChwYXN0ZShhcy5jaGFyYWN0ZXIoZGZbaSxdJEF3YXJkc051bVtbMV1dWzJdKSAsICJXaW4iLCBzZXA9IiAiKSkNCiAgICAgIGRmW2ksXSRXaW5zID0gYXMubnVtZXJpYyhkZltpLF0kQXdhcmRzTnVtW1sxXV1bMl0pICAgICAgICAgIA0KICAgIH0NCiAgICBpZihsZW5ndGgoZ3JlcCgibm9taW5hdGlvbiIsZGZbaSxdJEF3YXJkcykpPjApew0KICAgICAgI3ByaW50KHBhc3RlKGFzLmNoYXJhY3RlcihkZltpLF0kQXdhcmRzTnVtW1sxXV1bM10pICwgIm5vbWluYXRpb24iLCBzZXA9IiAiKSkNCiAgICAgIGRmW2ksXSROb21pbmF0aW9ucyA9IGFzLm51bWVyaWMoZGZbaSxdJEF3YXJkc051bVtbMV1dWzNdKSAgIA0KICAgIH0NCiAgfQ0KICAjIG5vIG51bWJlcnMgZm91bmQgOiBzZXQgYm90aCB3aW4gYW5kIG5vbWluYXRpb24gdG8gMCwgaW5jcmVtZW50IHRoZSByb3dzV2l0aEludmFsaWRBd2FyZHMgY291bnRlcg0KICBpZihsZW5ndGgoZGZbaSxdJEF3YXJkc051bVtbMV1dKT09MCl7DQogICAgZGZbaSxdJFdpbnMgPSAwDQogICAgZGZbaSxdJE5vbWluYXRpb25zID0gMA0KICAgIHJvd3NXaXRoSW52YWxpZEF3YXJkcyA9IHJvd3NXaXRoSW52YWxpZEF3YXJkcyArIDENCiAgfQ0KICANCiAgaWYobGVuZ3RoKHVubGlzdChkZltpLF0kV2lucykpPT0xKQ0KICAgIGRmW2ksXSRXaW5zID0gYXMubnVtZXJpYyh1bmxpc3QoZGZbaSxdJFdpbnMpKQ0KICBlbHNlDQogICAgcHJpbnQocGFzdGUoZGZbaSxdJEF3YXJkcywgZGZbaSxdJFdpbnMsIHNlcCA9ICIgPT0+ICIgKSkNCiAgaWYobGVuZ3RoKHVubGlzdChkZltpLF0kTm9taW5hdGlvbnMpKT09MSkNCiAgICBkZltpLF0kTm9taW5hdGlvbnMgPSBhcy5udW1lcmljKHVubGlzdChkZltpLF0kTm9taW5hdGlvbnMpW1sxXV0pDQogIGVsc2UNCiAgICBwcmludChwYXN0ZShkZltpLF0kTm9taW5hdGlvbnMsIGRmW2ksXSROb21pbmF0aW9ucywgc2VwID0gIiA9PT4gIiApKQ0KfQ0KYGBgDQpOdW1iZXIgb2Ygcm93cyB0aGF0IGhhdmUgbm9uLXplcm8gd2lucyBub21pbmF0aW9ucyBpcyA2NzUNCmBgYHtyfQ0KcHJpbnQobnJvdyhkZikgLSByb3dzV2l0aEludmFsaWRBd2FyZHMpDQpgYGANCg0KKipRKio6IEhvdyBkaWQgeW91IGNvbnN0cnVjdCB5b3VyIGNvbnZlcnNpb24gbWVjaGFuaXNtPyBIb3cgbWFueSByb3dzIGhhZCB2YWxpZC9ub24temVybyB3aW5zIG9yIG5vbWluYXRpb25zPw0KDQoqKkEqKjogRmlyc3QgSSBjb3VudGVkIGhvdyBtYW55IG51bWJlcnMgZXhpc3QgaW4gdGhlIEF3YXJkcyBjb2x1bW4gdXNpbmcgcmVndWxhciBleHByZXNzaW9ucy4gQmFzZWQgb24gbnVtYmVyIG9mIHJlZ3VsYXIgZXhwcmVzc2lvbiBtYXRjaGVzIChlYWNoIG1hdGNoIHJlcHJlc2VudCBvbmUgbnVtYmVyIHdpdGhpbiB0aGUgQXdhcmRzIGNvbHVtbikgd2UgZGVjaWRlIHRoZSB2YWx1ZSBmb3IgV2lucyBhbmQgTm9taW5hdGlvbnMgY29sdW1uLiANCklmIHRoZXJlIGlzIG9uZSBudW1iZXI6IHVzZSByZWd1bGFyIGV4cHJlc3Npb24gdG8gZGVjaWRlIGlmIHRoaXMgbnVtYmVyIGlzIGZvciBXaW5zIG9yIE5vbWluYXRpb25zLg0KSWYgdGhlcmUgYXJlIHR3byBudW1iZXJzOiB1c2UgcmVndWxhciBleHByZXNzaW9ucyB0byBtYWtlIHN1cmUgdGhlIGZpcnN0IG9uZSBnb2VzIHRvIFdpbnMgaWYgYW55IG9mIHRoZSBmb2xsb3dpbmcgZXhpc3QoIldpbiIsICJ3aW4iLCAid29uIiksIHVzZSByZWd1bGFyIGV4cHJlc3Npb24gdG8gbWFrZSBzdXJlIHRoZSBzZWNvbmQgb25lIGdvZXMgdG8gTm9taW5hdGlvbnMgaWYgKCJub21pbmF0aW9uIikgZXhpc3RzLg0KSWYgdGhlcmUgYXJlIHRocmVlIG51bWJlcnM6IHVzZSByZWd1bGFyIGV4cHJlc3Npb25zIHRvIG1ha2Ugc3VyZSB0aGUgc2Vjb25kIG9uZSBnb2VzIHRvIFdpbnMgaWYgYW55IG9mIHRoZSBmb2xsb3dpbmcgZXhpc3QoIldpbiIsICJ3aW4iLCAid29uIiksIHVzZSByZWd1bGFyIGV4cHJlc3Npb24gdG8gbWFrZSBzdXJlIHRoZSB0aGlyZCBvbmUgZ29lcyB0byBOb21pbmF0aW9ucyBpZiAoIm5vbWluYXRpb24iKSBleGlzdHMuDQpJZiB0aGVyZSBhcmUgbm8gbnVtYmVyczogY291bnQgdGhpcyByb3cgYXMgSW52YWxpZCByb3cuIFRoaXMgY291bnRlciB3aWxsIGJlIHVzZWQgdG8gYW5zd2VyIHRoZSBzZWNvbmQgcGFydCBvZiB0aGlzIHF1ZXN0aW9uLg0KSSBmb3VuZCA2NzQgcm93cyB3aXRoIHZhbGlkIG5vbi16ZXJvIHdpbnMgb3Igbm9taW5hdGlvbnMuICANCg0KYGBge3J9DQojIFRPRE86IFBsb3QgR3Jvc3MgcmV2ZW51ZSBhZ2FpbnN0IHdpbnMgYW5kIG5vbWluYXRpb25zDQpnZ3Bsb3QoZGYsIGFlcyhHcm9zcykpICsNCiAgZ2VvbV9wb2ludChkYXRhPWRmLCBhZXMoeT1XaW5zLCBjb2xvcj0iV2lucyIpKSArDQogIGdlb21fcG9pbnQoZGF0YT1kZiwgYWVzKHk9Tm9taW5hdGlvbnMsIGNvbG9yPSJOb21pbmF0aW9ucyIpKSArDQogIGxhYnModGl0bGU9IkZpZ3VyZSAxMSAtIE5vbWluYXRpb25zL1dpbnMgdnMuIEdyb3NzIiwNCiAgICAgICB4PSJHcm9zcyIsDQogICAgICAgeT0iTm9taW5hdGlvbnMgLyBXaW5zIikNCmBgYA0KTGV0J3Mgc2VlIFdpbnMgYWxvbmUgYWdhaW5zdCBHcm9zcyANCmBgYHtyfQ0KZ2dwbG90KGRmKSArDQogIGdlb21fcG9pbnQoZGF0YT1kZiwgYWVzKHg9V2lucywgeT1Hcm9zcykpICsNCiAgbGFicyh0aXRsZT0iRmlndXJlIDEyIC0gV2lucyB2cy4gR3Jvc3MiLA0KICAgICAgIHg9IldpbnMiLA0KICAgICAgIHk9Ikdyb3NzIikNCmBgYA0KTGV0J3Mgc2VlIE5vbWluYXRpb25zIGFsb25lIGFnYWluc3QgR3Jvc3MNCmBgYHtyfQ0KZ2dwbG90KGRmKSArDQogIGdlb21fcG9pbnQoZGF0YT1kZiwgYWVzKHg9Tm9taW5hdGlvbnMsIHk9R3Jvc3MpKSArDQogIGxhYnModGl0bGU9IkZpZ3VyZSAxMyAtIE5vbWluYXRpb25zIHZzLiBHcm9zcyIsDQogICAgICAgeD0iTm9taW5hdGlvbnMiLA0KICAgICAgIHk9Ikdyb3NzIikNCmBgYA0KDQoqKlEqKjogSG93IGRvZXMgdGhlIGdyb3NzIHJldmVudWUgdmFyeSBieSBudW1iZXIgb2YgYXdhcmRzIHdvbiBhbmQgbm9taW5hdGlvbnMgcmVjZWl2ZWQ/DQoNCioqQSoqOiBXZSBjYW4gbm90aWNlIGZyb20gRmlndXJlcyAxMSwgRmlndXJlIDEyLCBhbmQgRmlndXJlIDEzIHRoYXQgbmVpdGhlciB3aW5zIG5vciBub21pbmF0aW9ucyBjb3JyZWxhdGUgd2l0aCBHcm9zcy4gQm90aCB3aW5zIGFuZCBub21pbmF0aW9ucyBmYWxsIGJlbG93IDUwIHJlZ2FyZGxlc3MgdG8gR3Jvc3MuDQoNCiMjIDcuIE1vdmllIHJhdGluZ3MgZnJvbSBJTURiIGFuZCBSb3R0ZW4gVG9tYXRvZXMNCg0KVGhlcmUgYXJlIHNldmVyYWwgdmFyaWFibGVzIHRoYXQgZGVzY3JpYmUgcmF0aW5ncywgaW5jbHVkaW5nIElNRGIgcmF0aW5ncyAoYGltZGJSYXRpbmdgIHJlcHJlc2VudHMgYXZlcmFnZSB1c2VyIHJhdGluZ3MgYW5kIGBpbWRiVm90ZXNgIHJlcHJlc2VudHMgdGhlIG51bWJlciBvZiB1c2VyIHJhdGluZ3MpLCBhbmQgbXVsdGlwbGUgUm90dGVuIFRvbWF0b2VzIHJhdGluZ3MgKHJlcHJlc2VudGVkIGJ5IHNldmVyYWwgdmFyaWFibGVzIHByZS1maXhlZCBieSBgdG9tYXRvYCkuIFJlYWQgdXAgb24gc3VjaCByYXRpbmdzIG9uIHRoZSB3ZWIgKGZvciBleGFtcGxlIFtyb3R0ZW50b21hdG9lcy5jb20vYWJvdXRdKGh0dHBzOi8vd3d3LnJvdHRlbnRvbWF0b2VzLmNvbS9hYm91dCkgYW5kIFsgd3d3LmltZGIuY29tL2hlbHAvc2hvd19sZWFmP3ZvdGVzdG9wZmFxXShodHRwOi8vIHd3dy5pbWRiLmNvbS9oZWxwL3Nob3dfbGVhZj92b3Rlc3RvcGZhcSkpLg0KDQpJbnZlc3RpZ2F0ZSB0aGUgcGFpcndpc2UgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIHRoZXNlIGRpZmZlcmVudCBkZXNjcmlwdG9ycyB1c2luZyBncmFwaHMuDQoNCmBgYHtyfQ0KIyBUT0RPOiBJbGx1c3RyYXRlIGhvdyByYXRpbmdzIGZyb20gSU1EYiBhbmQgUm90dGVuIFRvbWF0b2VzIGFyZSByZWxhdGVkDQpjaGFydCA8LSBnZ3BhaXJzKGRmWywgYygiaW1kYlZvdGVzIiwiaW1kYlJhdGluZyIsInRvbWF0b01ldGVyIiwidG9tYXRvUmF0aW5nIiwgInRvbWF0b1VzZXJSYXRpbmciKV0sIA0KICAgICAgICAgICAgICAgICB0aXRsZSA9ICJGaWd1cmUgMTQgLSBQYWlyd2lzZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gSU1EQiBhbmQgdG9tYXRvIHJhdGluZ3MuIikNCnByaW50KGNoYXJ0KQ0KYGBgDQpXZSBjYW4gbm90aWNlIGZyb20gKkZpZ3VyZSAxNCAtIFBhaXJ3aXNlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiBJTURCIGFuZCB0b21hdG8gcmF0aW5ncy4qIHRoYXQgbW9zdCByYXRpbmcgY29sdW1ucyBoYXZlIGEgYmVsbCBzaGFwZWQgZGlzdHJpYnV0aW9uIHdpdGggc29tZSBzb3J0IHNrZXduZXNzIGV4Y2VwdCBpbWRiVm90ZXMuIFdlIGNhbiBhbHNvIG5vdGljZSB0aGF0IHRvbWF0b1JhdGluZyBhbmQgdG9tYXRvTWV0ZXIgaGF2ZSBoaWdoIGNvcnJlbGF0aW9uIDk1IHdoaWNoIG1ha2Ugc2Vuc2UgZ2l2ZW4gdGhhdCB0b21hdG9NZXRlciBpcyB0aGUgcGVyY2VudGFnZSBvZiBjcml0aWNzIGdpdmluZyBwb3NpdGl2ZSByZXZpZXcgYW5kIHRvbWF0b1JhdGluZyBpcyBvdmVyYWxsIGNyaXRpY3MgYXZlcmFnZS4gdG9tYXRvVXNlclJhdGluZyBhbmQgaW1kYlJhdGluZyBmb2xsb3dzIHRoYXQgd2l0aCA4Ni4xIGNvcnJlbGF0aW9uIHdoaWNoIG1ha2Ugc2Vuc2Ugc2luY2UgYm90aCBwcm92aWRlZCBieSB1c2Vycy4gdG9tYXRvUmF0aW5nIGFuZCBpbWRiUmF0aW5nIGZvbGxvd3MgdGhhdCB3aXRoIDczLjUgY29ycmVsYXRpb24uIExvd2VzdCBjb3JyZWxhdGlvbiBoYXBwZW5kIHRvIGJlIGJldHdlZW4gdG9tYXRvTWV0ZXIgYW5kIGltZGJWb3Rlcy4NCg0KDQoqKlEqKjogQ29tbWVudCBvbiB0aGUgc2ltaWxhcml0aWVzIGFuZCBkaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZSB1c2VyIHJhdGluZ3Mgb2YgSU1EYiBhbmQgdGhlIGNyaXRpY3MgcmF0aW5ncyBvZiBSb3R0ZW4gVG9tYXRvZXMuDQoNCioqQSoqOiBXZSBjYW4gbm90aWNlIGZyb20gKkZpZ3VyZSAxNCAtIFBhaXJ3aXNlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiBJTURCIGFuZCB0b21hdG8gcmF0aW5ncy4qIHRoYXQgdG9tYXRvUmF0aW5nIGFuZCBpbWRiUmF0aW5nIGhhdmUgNzMuNSBjb3JyZWxhdGlvbiwgYm90aCBoYXZlIHNpbWlsYXIgYmVsbCBzaGFwcGVkIGRpc3RyaWJ1dGlvbnMsIGJvdGggaGF2ZSBwZWFrcyBjbG9zZSB0byA3Lg0KQWx0aG91Z2ggdGhlcmUgaXMgaGlnaCBjb3JyZWxhdGlvbiwgYnV0IGl0IGlzIG5vdCBhcyBoaWdoIGFzIHRoZSA4Ni4xIGNvcnJlbGF0aW9uIGJldHdlZW4gdG9tYXRvVXNlclJhdGluZyBhbmQgaW1kYlJhdGluZy4NCg0KIyMgOC4gUmF0aW5ncyBhbmQgYXdhcmRzDQoNClRoZXNlIHJhdGluZ3MgdHlwaWNhbGx5IHJlZmxlY3QgdGhlIGdlbmVyYWwgYXBwZWFsIG9mIHRoZSBtb3ZpZSB0byB0aGUgcHVibGljIG9yIGdhdGhlciBvcGluaW9ucyBmcm9tIGEgbGFyZ2VyIGJvZHkgb2YgY3JpdGljcy4gV2hlcmVhcyBhd2FyZHMgYXJlIGdpdmVuIGJ5IHByb2Zlc3Npb25hbCBzb2NpZXRpZXMgdGhhdCBtYXkgZXZhbHVhdGUgYSBtb3ZpZSBvbiBzcGVjaWZpYyBhdHRyaWJ1dGVzLCBzdWNoIGFzIGFydGlzdGljIHBlcmZvcm1hbmNlLCBzY3JlZW5wbGF5LCBzb3VuZCBkZXNpZ24sIGV0Yy4NCg0KU3R1ZHkgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHJhdGluZ3MgYW5kIGF3YXJkcyB1c2luZyBncmFwaHMgKGF3YXJkcyBoZXJlIHJlZmVycyB0byB3aW5zIGFuZC9vciBub21pbmF0aW9ucykuIA0KDQpgYGB7cn0NCiMgVE9ETzogU2hvdyBob3cgcmF0aW5ncyBhbmQgYXdhcmRzIGFyZSByZWxhdGVkDQojV2lsbCBzdHVkeSBXaW4gKyBOb21pbmF0aW9ucyBhZ2FpbnN0ICgiaW1kYlZvdGVzIiwiaW1kYlJhdGluZyIsInRvbWF0b01ldGVyIiwidG9tYXRvUmF0aW5nIiwgInRvbWF0b1VzZXJSYXRpbmciKQ0KYGBgDQojIyMgV2luICsgTm9taW5hdGlvbnMgdnMuIGltZGJWb3Rlcw0KYGBge3J9DQpjaGFydCA8LSBnZ3Bsb3QoZGYpICsgDQogIGdlb21fcG9pbnQoYWVzKHg9aW1kYlZvdGVzLFdpbnMrTm9taW5hdGlvbnMpKSArIA0KICBnZW9tX3Ntb290aChhZXMoeD1pbWRiVm90ZXMsIFdpbnMrTm9taW5hdGlvbnMpLCBtZXRob2Q9ImxtIikgKw0KICBsYWJzKHRpdGxlPSJGaWd1cmUgMTUgLSBXaW5zICsgTm9taW5hdGlvbnMgdnMuIElNREIgVm90ZXMiLA0KICAgICAgIHg9IklNREIgVm90ZXMiLA0KICAgICAgIHk9IldpbnMgKyBOb21pbmF0aW9ucyIpDQpwcmludChjaGFydCkNCmBgYA0KIyMjIFdpbiArIE5vbWluYXRpb25zIHZzLiBpbWRiUmF0aW5nDQpgYGB7cn0NCmNoYXJ0IDwtIGdncGxvdChkZikgKyANCiAgZ2VvbV9wb2ludChhZXMoeD1pbWRiUmF0aW5nLFdpbnMrTm9taW5hdGlvbnMpKSArIA0KICBnZW9tX3Ntb290aChhZXMoeD1pbWRiUmF0aW5nLCBXaW5zK05vbWluYXRpb25zKSwgbWV0aG9kPSJsbSIpICsNCiAgbGFicyh0aXRsZT0iRmlndXJlIDE2IC0gV2lucyArIE5vbWluYXRpb25zIHZzLiBJTURCIFJhdGluZyIsDQogICAgICAgeD0iSU1EQiBSYXRpbmciLA0KICAgICAgIHk9IldpbnMgKyBOb21pbmF0aW9ucyIpDQpwcmludChjaGFydCkNCmBgYA0KIyMjIFdpbiArIE5vbWluYXRpb25zIHZzLiB0b21hdG9NZXRlcg0KYGBge3J9DQpjaGFydCA8LSBnZ3Bsb3QoZGYpICsgDQogIGdlb21fcG9pbnQoYWVzKHg9dG9tYXRvTWV0ZXIsV2lucytOb21pbmF0aW9ucykpICsgDQogIGdlb21fc21vb3RoKGFlcyh4PXRvbWF0b01ldGVyLCBXaW5zK05vbWluYXRpb25zKSwgbWV0aG9kPSJsbSIpICsNCiAgbGFicyh0aXRsZT0iRmlndXJlIDE3IC0gV2lucyArIE5vbWluYXRpb25zIHZzLiB0b21hdG8gTWV0ZXIiLA0KICAgICAgIHg9InRvbWF0byBNZXRlciIsDQogICAgICAgeT0iV2lucyArIE5vbWluYXRpb25zIikNCnByaW50KGNoYXJ0KQ0KYGBgDQojIyMgV2luICsgTm9taW5hdGlvbnMgdnMuIHRvbWF0byBSYXRpbmcNCmBgYHtyfQ0KY2hhcnQgPC0gZ2dwbG90KGRmKSArIA0KICBnZW9tX3BvaW50KGFlcyh4PXRvbWF0b1JhdGluZyxXaW5zK05vbWluYXRpb25zKSkgKyANCiAgZ2VvbV9zbW9vdGgoYWVzKHg9dG9tYXRvUmF0aW5nLCBXaW5zK05vbWluYXRpb25zKSwgbWV0aG9kPSJsbSIpICsNCiAgbGFicyh0aXRsZT0iRmlndXJlIDE4IC0gV2lucyArIE5vbWluYXRpb25zIHZzLiB0b21hdG8gUmF0aW5nIiwNCiAgICAgICB4PSJ0b21hdG8gUmF0aW5nIiwNCiAgICAgICB5PSJXaW5zICsgTm9taW5hdGlvbnMiKQ0KcHJpbnQoY2hhcnQpDQpgYGANCiMjIyBXaW4gKyBOb21pbmF0aW9ucyB2cy4gdG9tYXRvIFVzZXIgUmF0aW5nDQpgYGB7cn0NCmNoYXJ0IDwtIGdncGxvdChkZikgKyANCiAgZ2VvbV9wb2ludChhZXMoeD10b21hdG9Vc2VyUmF0aW5nLFdpbnMrTm9taW5hdGlvbnMpKSArIA0KICBnZW9tX3Ntb290aChhZXMoeD10b21hdG9Vc2VyUmF0aW5nLCBXaW5zK05vbWluYXRpb25zKSwgbWV0aG9kPSJsbSIpICsNCiAgbGFicyh0aXRsZT0iRmlndXJlIDE5IC0gV2lucyArIE5vbWluYXRpb25zIHZzLiB0b21hdG8gVXNlciBSYXRpbmciLA0KICAgICAgIHg9InRvbWF0byBSYXRpbmciLA0KICAgICAgIHk9IldpbnMgKyBOb21pbmF0aW9ucyIpDQpwcmludChjaGFydCkNCmBgYA0KKipRKio6IEhvdyBnb29kIGFyZSB0aGVzZSByYXRpbmdzIGluIHRlcm1zIG9mIHByZWRpY3RpbmcgdGhlIHN1Y2Nlc3Mgb2YgYSBtb3ZpZSBpbiB3aW5uaW5nIGF3YXJkcyBvciBub21pbmF0aW9ucz8gSXMgdGhlcmUgYSBoaWdoIGNvcnJlbGF0aW9uIGJldHdlZW4gdHdvIHZhcmlhYmxlcz8NCg0KKipBKio6IEFsbCByYXRpbmdzIGhhdmUgY2xlYXIgbGluZWFyIGNvcnJlbGF0aW9uIHdpdGggbW92aWVzJyBXaW5zICsgTm9taW5hdGlvbnM7IHNvIHRoZXkgY2FuIGJlIGdvb2QgcHJlZGljdG9ycyBmb3IgbW92aWUgYXdhcmQgbW9kZWwuIFRoZSBoaWdoZXN0IGNvcnJlbGF0aW9uIGlzIGJldHdlZW4gSU1EQiB2b3RlcyBhbmQgdG90YWwgYXdhcmQgd2lucy9ub21pbmF0aW9uLg0KDQojIyA5LiBFeHBlY3RlZCBpbnNpZ2h0cw0KDQpDb21lIHVwIHdpdGggdHdvIG5ldyBpbnNpZ2h0cyAoYmFja2VkIHVwIGJ5IGRhdGEgYW5kIGdyYXBocykgdGhhdCBpcyBleHBlY3RlZC4gSGVyZSBhIG5ldyBtZWFucyBpbnNpZ2h0cyB0aGF0IGFyZSBub3QgYW4gaW1tZWRpYXRlIGNvbnNlcXVlbmNlIG9mIG9uZSBvZiB0aGUgYWJvdmUgdGFza3MuIFlvdSBtYXkgdXNlIGFueSBvZiB0aGUgY29sdW1ucyBhbHJlYWR5IGV4cGxvcmVkIGFib3ZlIG9yIGEgZGlmZmVyZW50IG9uZSBpbiB0aGUgZGF0YXNldCwgc3VjaCBhcyBgVGl0bGVgLCBgQWN0b3JzYCwgZXRjLg0KDQpgYGB7cn0NCiMgVE9ETzogRmluZCBhbmQgaWxsdXN0cmF0ZSB0d28gZXhwZWN0ZWQgaW5zaWdodHMNCmBgYA0KDQojIyMgRXhwZWN0ZWQgaW5zaWdodCAjMSAtIERvbWVzdGljIEdyb3NzIHZzIEdyb3NzDQpgYGB7cn0NCmNoYXJ0IDwtIGdncGxvdChkZikgKyANCiAgZ2VvbV9wb2ludChhZXMoeD1Eb21lc3RpY19Hcm9zcyxHcm9zcykpICsNCiAgZ2VvbV9zbW9vdGgoYWVzKHg9RG9tZXN0aWNfR3Jvc3MsR3Jvc3MpLCBtZXRob2Q9ImxtIikgKyANCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6Y29tbWEpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6Y29tbWEpICsgDQogIGxhYnModGl0bGU9IkZpZ3VyZSAyMCAtIERvbWVzdGljIEdyb3NzIHZzLiBHcm9zcyIsDQogICAgIHg9IkRvbWVzdGljIEdyb3NzIiwNCiAgICAgeT0iR3Jvc3MiKQ0KcHJpbnQoY2hhcnQpDQpgYGANCioqUSoqOiBFeHBlY3RlZCBpbnNpZ2h0ICMxLg0KDQoqKkEqKjogQXMgaXQgaXMgY2xlYXIgZnJvbSAqRmlndXJlIDEzIC0gRG9tZXN0aWMgR3Jvc3MgdnMuIEdyb3NzKiB0aGF0IGlzIGEgbGluZWFyIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIERvbWVzdGljIEdyb3NzIGFuZCBHcm9zcy4NCg0KIyMjIEV4cGVjdGVkIGluc2lnaHQgIzIgLSBPYnNlcnZhdGlvbnMgcmVnYXJkaW5nIGhvdyBtdWNoIHRoZSBkYXRhc2V0IGlzIGZvY3VzZWQgb24gVVNBIEVuZ2xpc2ggbW92aWVzDQpgYGB7cn0NCnByaW50KHBhc3RlKCIlIiwgKCggbnJvdyhkZlsoZGYkTGFuZ3VhZ2UgPT0gIkVuZ2xpc2giKSxdKSAvIG5yb3coZGYpICkgKiAxMDApLCAib2YgbW92aWVzIGFyZSBvbmx5IGluIEVuZ2xpc2guIiwgc2VwID0gIiAiKSkNCnByaW50KHBhc3RlKCIlIiwgKCggbnJvdyhkZlsoZGYkQ291bnRyeSA9PSAiVVNBIiksXSkgLyBucm93KGRmKSApICogMTAwKSwgIm9mIG1vdmllcyBhcmUgbWFkZSBpbiBVU0EuIiwgc2VwID0gIiAiKSkNCnByaW50KHBhc3RlKCIlIiwgKCggbnJvdyhkZlsoKGRmJEdyb3NzICsgZGYkRG9tZXN0aWNfR3Jvc3MgLSBkZiRCdWRnZXQpIDwgMCksXSkvbnJvdyhkZikgKSAqIDEwMCksICJvZiBtb3ZpZXMgYXJlIGxvc2luZyBtb25leS4iLCBzZXAgPSAiICIpKQ0KYGBgDQoqKlEqKjogRXhwZWN0ZWQgaW5zaWdodCAjMi4NCg0KKipBKio6IFRoZSBmb2xsb3dpbmcgc3RhdGlzdGljcyBzaG93IGhvdyBtdWNoIHRoZSBkYXRhIHNldCBpcyBmb2N1c2VkIG9uIG1vdmllcyBwcm9kdWNlZCBpbiBVU0EgaW4gRW5nbGlzaDogJSA5NC4yIG9mIG1vdmllcyBhcmUgb25seSBpbiBFbmdsaXNoLiAlIDkxLjUgb2YgbW92aWVzIGFyZSBtYWRlIGluIFVTQS4gJSA5MC45IG9mIG1vdmllcyBhcmUgbG9zaW5nIG1vbmV5Lg0KDQoNCiMjIDEwLiBVbmV4cGVjdGVkIGluc2lnaHQNCg0KQ29tZSB1cCB3aXRoIG9uZSBuZXcgaW5zaWdodCAoYmFja2VkIHVwIGJ5IGRhdGEgYW5kIGdyYXBocykgdGhhdCBpcyB1bmV4cGVjdGVkIGF0IGZpcnN0IGdsYW5jZSBhbmQgZG8geW91ciBiZXN0IHRvIG1vdGl2YXRlIGl0LiBTYW1lIGluc3RydWN0aW9ucyBhcHBseSBhcyB0aGUgcHJldmlvdXMgdGFzay4NCg0KYGBge3J9DQojIFRPRE86IEZpbmQgYW5kIGlsbHVzdHJhdGUgb25lIHVuZXhwZWN0ZWQgaW5zaWdodA0KYGBgDQojIyMgSW52ZXN0aWdhdGluZyBCdWRnZXQgdnMuIFRvdGFsIEdyb3NzDQpgYGB7cn0NCmNoYXJ0IDwtIGdncGxvdChkZikgKyANCiAgZ2VvbV9wb2ludChhZXMoeD1CdWRnZXQsR3Jvc3MgKyBEb21lc3RpY19Hcm9zcykpICsgDQogIGdlb21fc21vb3RoKGFlcyh4PUJ1ZGdldCwgR3Jvc3MgKyBEb21lc3RpY19Hcm9zcyksbWV0aG9kPSJsbSIpICsNCiAgbGFicyh0aXRsZT0iRmlndXJlIDIxIC0gQnVkZ2V0IHZzLiBUb3RhbCBHcm9zcyIsDQogICAgICAgeD0iQnVkZ2V0IiwNCiAgICAgICB5PSJUb3RhbCBHcm9zcyIpDQpwcmludChjaGFydCkNCmBgYA0KIyMjIEludmVzdGlnYXRpbmcgQnVkZ2V0IHZzLiBUb3RhbCBBd2FyZCB3aW5zIGFuZCBub21pbmF0aW9ucw0KYGBge3J9DQpjaGFydCA8LSBnZ3Bsb3QoZGYpICsgDQogIGdlb21fcG9pbnQoYWVzKHg9QnVkZ2V0LCBXaW5zK05vbWluYXRpb25zKSkgKyANCiAgZ2VvbV9zbW9vdGgoYWVzKHg9QnVkZ2V0LCBXaW5zK05vbWluYXRpb25zKSxtZXRob2Q9ImxtIikgKw0KICBsYWJzKHRpdGxlPSJGaWd1cmUgMjIgLSBCdWRnZXQgdnMuIFdpbnMgKyBOb21pbmF0aW9ucyIsDQogICAgICAgeD0iQnVkZ2V0IiwNCiAgICAgICB5PSJXaW5zICsgTm9taW5hdGlvbnMiKQ0KcHJpbnQoY2hhcnQpDQpgYGANCiMjIyBJbnZlc3RpZ2F0aW5nIEJ1ZGdldCB2cy4gdG9tYXRvUmF0aW5nIChDcml0aWMgcmV2aWV3cykNCmBgYHtyfQ0KY2hhcnQgPC0gZ2dwbG90KGRmKSArIA0KICBnZW9tX3BvaW50KGFlcyh4PUJ1ZGdldCwgdG9tYXRvUmF0aW5nICkpICsgDQogIGdlb21fc21vb3RoKGFlcyh4PUJ1ZGdldCwgdG9tYXRvUmF0aW5nKSxtZXRob2Q9ImxtIikgKw0KICBsYWJzKHRpdGxlPSJGaWd1cmUgMjMgLSBCdWRnZXQgdnMuIHRvbWF0byBSYXRpbmciLA0KICAgICAgIHg9IkJ1ZGdldCIsDQogICAgICAgeT0idG9tYXRvUmF0aW5nIikNCnByaW50KGNoYXJ0KQ0KYGBgDQoqKlEqKjogVW5leHBlY3RlZCBpbnNpZ2h0Lg0KDQoqKkEqKjogQXMgd2Ugbm90aWNlIGZyb20gRmlndXJlcyAyMCwgMjEsIDIyOiBCdWRnZXQgaXMgaGlnaGx5IGNvcnJlbGF0ZWQgd2l0aCB0b3RhbCBncm9zcyBhbmQgYXdhcmQgd2lubmluZyBhbmQgbm9taW5hdGlvbnMgYnV0IG5vdCB3aXRoIGF2ZXJhZ2UgY3JpdGljcyByYXRpbmdzLiBUaGlzIG1lYW5zIHRoYXQgaW5jcmVhc2luZyB0aGUgbW92aWUgYnVkZ2V0IHdpbGwgaW5jcmVhc2UgaXRzIGdyb3NzIGFuZCBhbHNvIGl0cyBhd2FyZHMnIGNoYW5jZXMsIGJ1dCBpdCBpcyBpcnJlbGF2YW50IHRvIGNyaXRpY3MgcmV2aWV3cyBvZiB0aGUgbW92aWUuIEkgd2FzIGV4cGVjdGluZyB0aGUgYXdhcmRzJyB3aW5zL25vbWluYXRpb25zIHRvIGNvcnJlbGF0ZSB3aXRoIHRvbWF0b1JhdGluZywgYnV0IGl0IGRvZXNuJ3QuDQoNCg==

Top Articles
Latest Posts
Article information

Author: Amb. Frankie Simonis

Last Updated: 01/16/2023

Views: 6509

Rating: 4.6 / 5 (76 voted)

Reviews: 91% of readers found this page helpful

Author information

Name: Amb. Frankie Simonis

Birthday: 1998-02-19

Address: 64841 Delmar Isle, North Wiley, OR 74073

Phone: +17844167847676

Job: Forward IT Agent

Hobby: LARPing, Kitesurfing, Sewing, Digital arts, Sand art, Gardening, Dance

Introduction: My name is Amb. Frankie Simonis, I am a hilarious, enchanting, energetic, cooperative, innocent, cute, joyous person who loves writing and wants to share my knowledge and understanding with you.