Let’s install all required packages

install.packages("readr")
install.packages("dplyr")
install.packages("ggplot2")
install.packages("purrr")
install.packages("magrittr")
install.packages("stringr")
print('All packages installed')

Let’s now import our packages

library(dplyr)
library(readr)
library(ggplot2)
library(magrittr)
library(stringr)
print("Imported!")

Fandango has been suspected of releasing inflated ratings to increase ticket sales. After they found that some films that garnered poor ratings elsewhere were rated highly on Fandango, analysts from FiveThirtyEight investigated and published an article about bias in movie ratings.

To conduct the investigation, the team compiled data for 147 films from 2015 with reviews from movie critics and consumers.

In this mission, you’ll use this data and ggplot2 to visualize reviews from Metacritic, Fandango, Rotten Tomatoes, and IMDB to get a sense for differences in the way the four sites compute movie ratings.

We have made a subset of the data available for you to work with in this mission in a file named “movie_reviews.csv”. The file contains three columns:

# See the movie review link below just incase reading diectly from Github
reviews_link <- "https://raw.githubusercontent.com/fivethirtyeight/data/master/fandango/fandango_scrape.csv"  

reviews <- read_csv("movie_reviews.csv")
Parsed with column specification:
cols(
  FILM = col_character(),
  Rating_Site = col_character(),
  Rating = col_double()
)
#View(reviews)
head(reviews)

Let’s start by getting a sense for how reviews reported by the four sites compare.

You can approach this problem by calculating the average ratings for each rating site. To do this, you could group the reviews data frame into one group for each value of Rating_Site and calculate the average of Rating for each group.

Recall from the R Intermediate course that such problems, where you perform summary calculations on grouped data, are known as “split-apply-combine”(SAC) problems.

Once you’ve calculated average ratings for each site, we’ll introduce you to a new type of graph for visualizing comparisons among groups, or categories, of data.

Let’s calculate average ratings for each movie rating site.

# Instructions
# Use group_by() to group the reviews data frame by Rating_Site.
# Use summarize() to calculate the average Rating for each Rating_Site. Save the summary data frame as review_avgs.
review_avgs <- reviews %>% group_by(Rating_Site) %>% summarise(avg = mean(Rating))
review_avgs

Like line graphs, bar charts depict the relationship between two variables. To create a bar chart to visualize the average ratings for each movie rating site, you would use the review_avgs data frame. The syntax for the data and aesthetics layers you’ll specify when creating a bar chart with ggplot2 is the same as the syntax you learned when creating line graphs. The layer that distinguishes a bar chart from a line graph is the layer in which you’ll specify the geometric shape used to display the data. While before you used geom_line(), now you’ll use geom_bar():

ggplot(data = review_avgs) +
  aes(x = rating_site, y = avg) + 
  geom_bar(stat = 'identity)

In the code above, we specify stat = “identity” within the geom_bar() layer. This is because, by default, using geom_bar() creates a bar graph where the height of the bars corresponds to the number of values in the specified y-variable. Using stat = “identity” overrides the default behavior and creates bars equal to the value of the y-variable, the average.

# Instructions -->
# 
# Use ggplot2 to create a bar chart depicting the average movie ratings for Rotten Tomatoes, IMDB, Metacritic, and Fandango. We have loaded the ggplot2 package for you. -->
# Use the review_avgs data frame that contains your calculated average ratings for each site. -->

ggplot(data = review_avgs) + 
  aes(x = Rating_Site, y = avg, color=Rating_Site) +
  geom_bar(stat = 'identity')

As you look at the chart, you can clearly see that Fandango has a higher average movie rating than the other three sites. Does this mean Fandango tends to give higher ratings?

As you consider that question, let’s think about what the bar chart does not show us. It makes sense to wonder if Fandango’s average movie rating is higher than those of the other sites because it tends to give all movies good ratings, or because it gave some movies average ratings and a small number of movies excellent ratings.

However, the bar graph does not provide this information.

The average of a set of numbers does not tell us anyting about the spread of the numbers that were used to calculate the average. For example, the values of these two variables both have an average of 5:

Variable 1: 5 5 5 5 5 4 5 5 6 5
Variable 2: 20 9 1 2 8 4 9 5 7

However, while values of Variable 1 are distributed between 4 and 6, values of Variable 2 are distributed between 1 and 20. The values of Variable 2 are much more spread out than those of Variable 1.

This leads us to the next chart, which is called a Histogram. A Histogram will show us the count or frequency of values in each rating scale.

To visualize data using a histogram, the syntax for the data and aesthetics layers are similar to what you have used to generate line graphs and bar charts:

ggplot(data = reviews) + 
  aes(x = Rating) +
  geom_histogram(binwidth = 1)

Within the aes() layer, you only need to specify the independent variable. Remember when you create a histogram, the dependent variable count is calculated for you.

The geom_histogram() layer specifies creation of a histogram to represent the independent variable. The argument binwidth = 1 specifies the size of the categories used to bin the values of the independent variable.

Within the geom_histogram() layer, you can use two different arguments to specify the number of categories for binning the independent variable.

binwidth = allows you to specify the size of the bins, and is useful for instances, such as this example, where you want categories to span specific intervals. bins = allows you to specify the number of bins, which can be useful to experiment with when deciding how much detail you want to use to display your data. If you don’t use any arguments within the geom_histogram() layer, ggplot2 will use a default number of bins.

# Instructions
# 
# Create a histogram to show the distribution of all values of the Rating variable in the reviews data frame.
# Specify 30 bins to categorize values of the independent variable.

ggplot(data = reviews) + 
  aes(x = Rating) + 
  geom_histogram(bins = 30)

Histograms allow you to visualize the shape of a distribution — where values of the data are clustered. Most values of Rating are clustered between 3.5 and 4.5.

This histogram tells us about the distribution of all values of the Rating variable, but what we really want to investigate is how ratings for different rating sites differ.

One way to compare Rating distributions for the four sites is to create a faceted plot, as you learned to do for line graphs.

Recall that to create a faceted plot for categories of a variable, you can add a layer to your graph using facet_wrap():

# Instructions
# 
# Add a layer to the histogram you created on the last screen to create a faceted graph containing four histograms of the distribution of Rating for each site:
# Rotten Tomatoes
# IMDB
# Metacritic
# Fandango
# Use nrow = 2 within the facet_wrap() layer to specify a two-by-two arrangement of the histograms.

ggplot(data = reviews) +
  aes(x = Rating) + 
  geom_histogram(bins = 30) +
  facet_wrap(~Rating_Site, nrow = 2)

The distributions of Rating for Rotten Tomatoes and Metacritic indicate that those two sites are more likely to give movies poor ratings than Fandango or IMDB, which have most values of Rating clustered over 3.

Comparing these distributions suggests some sites give poor ratings more often than others. For example, the difference between the distributions of Ratings for Fandango and Rotten Tomatoes is very clear. However, Fandango and IMDB have distributions that look similar. Is there a better way to visualize differences between them?

Remember that when you created line charts, plotting multiple variables on the same set of axes was useful for creating a more nuanced comparison. Similarly, we can plot histograms for the four rating sites on the same set of axes.

As you did for line graphs, you can distinguish values associated with different variables by mapping them to different colors within the aes() layer:

ggplot(data = reviews) + 
  aes(x = Rating, color = Rating_Site) +
  geom_histogram(bins = 30)

When creating histograms (or bar charts), using the argument color = within aes() maps your specified variable to bar outlines of different colors:

Another option for using aesthetics to map values of Rating to different values of Rating_Site is to use the argument fill = instead of color =. Instead of outlines, fill = depicts bars filled in with different colors. Let’s use both option to visualize differences in Rating distributions of the four sites.

# Instructions
# Create a histogram depicting the distribution of Ratings for each site using bars with different color lines.

ggplot(data = reviews) + 
  aes(x = Rating, color = Rating_Site) + 
  geom_histogram(bins = 30) + 
  facet_wrap(~Rating_Site, nrow = 2)

# Instructions
# Create a histogram depicting the distribution of Ratings for each site using bars filled with different colors.

ggplot(data = reviews) + 
  aes(x = Rating, fill = Rating_Site) + 
  geom_histogram(bins = 30) + 
  facet_wrap(~Rating_Site, nrow = 2)

# Plotting all four histograms on one canvas with different filled colors
ggplot(data = reviews) + 
  aes(x = Rating, fill = Rating_Site) + 
  geom_histogram(bins = 30)

# Plotting all four histograms on one canvas with different edge colors colors
ggplot(data = reviews) + 
  aes(x = Rating, color = Rating_Site) + 
  geom_histogram(bins = 30)

Visualizing the distributions of Rankings for each rating site makes it clear that Fandango is more likely to rate movies highly than the other sites are, which supports the argument that it is biased toward assigning higher ratings.

You’ll often use histograms in your data science career for initial explorations of your data. Knowing how to visualize and interpret distributions will become increasingly important later on when you learn about statistics and modeling.

Now that you’re able to make bar charts to visualize data summaries and histograms to visualize data distributions, we’ll introduce you to a type of plot for visualizing both the center of and the variation in your data.

Like Bar charts, Box plots provide a summary of data by group. Like histograms, they provide information about how data are spread.

To create a box plot using ggplot2, the syntax for creating the data layer and mapping data to x and y variables is familiar.

ggplot(data = reviews) + 
  aes(x = Rating, color = Rating_Site) +
  geom_histogram(bins = 30)
ggplot(data = reviews) +
  aes(x = Rating_Site, y = Rating)

You’ll add a geom_boxplot() layer to specify creation of a box plot.

Let’s create a box plot of ratings for each site in the reviews data frame.

# Instructions
# 
# Create a box plot to visualize summaries of values of the Rating variable for each value of Rating_Site.
# Add a geom_boxplot() layer to specify creation of a box pot.

ggplot(data = reviews) + 
  aes(x = Rating_Site, y = Rating, fill = Rating_Site) + 
  geom_boxplot()

In general, you can see that the box representing Fandango ratings is higher up on the y-axis than those for the other sites. You can also see the Rotten Tomatoes ratings appear to be more spread out, which is consistent with what you saw when we plotted the data using histograms.

While you’ve been able to glean some information from this box plot, let’s dig deeper into the individual components to fully understand all they can tell us about data.

Box plots present what is known to statisticians as a five-number summary. The five numbers refer to percentiles of the data you’re working with:

The five percentiles summarized by a box plot are:

The largest value: Represented by the top of the black line extending from the top of the box. These lines are also known as “whiskers”. The third quartile (Q3): Represented by the top of the box. Seventy-five percent of the values are smaller than the third quartile. The median: Represented by the thick black line. The median is the value that falls in the middle of the data. The first quartile (Q1): Represented by the bottom of the box. Twenty-five percent of the values are smaller than the first quartile. The smallest value: Represented by the bottom of the black line extending from the bottom of the box. The white box, bounded by Q3 and Q1, is referred to as the Interquartile Range or IQR. The IQR encompasses 50 percent of the data, and is calculated by subtracting Q1 from Q3.

In the box plot you created, notice there are some points that fall below the bottom of the black lines that represent the smallest values. These points are referred to as outliers because they are outside the range of what would be expected based on the rest of the data.

When you make a box plot using ggplot2, data points that fall below Q1 − 1.5 IQR or above Q3 + 1.5 IQR are defined as outliers.

Now that you’ve delved into the meaning of the components of a box plot, what can you learn about the movie rating data? Here are some observations:

Values of Rating for Rotten Tomatoes are spread out, indicating they regularly give movies ratings that range from poor to excellent.

The range of values of Rating for Fandango and IMDB are both quite narrow. Fandango’s lowest reviews are around 2.5, whle outliers indicate that IMDB has some reviews that are between 2 and 2.4.

Fandango’s median for values of Rating is higher than the median of the other sites, indicating Fandango tends to give higher ratings.

Does the box plot you made support the idea that Fandango’s reviews are biased? Which site do you think would provide the most unbiased reviews?

From this exercise, My personal opinion is that Rotten-Tomatoes give the most unbiased reviews.

# Instructions
# 
# In the previous exercise, you created a box plot to visualize summaries of ratings for Fandango, IMDB, Metacritic, and Rotten Tomatoes.
# 
# Add layers to your plot so it fits the following specifications:
# 
# White panel background
# The plot title: "Comparison of Movie Ratings"
ggplot(data = reviews) + 
  aes(x = Rating_Site, y = Rating, fill = Rating_Site) + 
  geom_boxplot() + 
  labs(title = "Comparison of Movie Ratings") +
  theme(panel.background = element_rect(fill = 'white'))

As we discussed earlier in this course, building intuition around when to use different types of visualizations to understand your data is an important skill you will develop.

When should you use the three types of plots you learned about in this mission? You will probably explore different options for visualizing each new data set, and doing so is a good idea. However, here are some general guidelines:

Bar charts may be used for showing a quick summary of your data, such as averages or counts of the number of instances of a value that occur for a given variable.

Histograms are useful for visualizing distributions of data when you want to know the shape of a distribution (in other words, where most values are clustered).

Box plots provide an informative summary of the shape, spread, and center of your data.

LS0tDQp0aXRsZTogIkJhciBDaGFydHMsIEJveC1QbG90cyBhbmQgSGlzdG9ncmFtcyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KYXV0aG9yOiAiTGF3cmVuY2UgS3J1a3J1Ym8iDQotLS0NCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KDQpMZXQncyBpbnN0YWxsIGFsbCByZXF1aXJlZCBwYWNrYWdlcw0KDQpgYGB7cn0NCmluc3RhbGwucGFja2FnZXMoInJlYWRyIikNCmluc3RhbGwucGFja2FnZXMoImRwbHlyIikNCmluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQ0KaW5zdGFsbC5wYWNrYWdlcygicHVycnIiKQ0KaW5zdGFsbC5wYWNrYWdlcygibWFncml0dHIiKQ0KaW5zdGFsbC5wYWNrYWdlcygic3RyaW5nciIpDQpwcmludCgnQWxsIHBhY2thZ2VzIGluc3RhbGxlZCcpDQpgYGANCg0KTGV0J3Mgbm93IGltcG9ydCBvdXIgcGFja2FnZXMNCg0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkobWFncml0dHIpDQpsaWJyYXJ5KHN0cmluZ3IpDQpwcmludCgiSW1wb3J0ZWQhIikNCmBgYA0KDQpGYW5kYW5nbyBoYXMgYmVlbiBzdXNwZWN0ZWQgb2YgcmVsZWFzaW5nIGluZmxhdGVkIHJhdGluZ3MgdG8gaW5jcmVhc2UgdGlja2V0IHNhbGVzLiBBZnRlciB0aGV5IGZvdW5kIHRoYXQgc29tZSBmaWxtcyB0aGF0IGdhcm5lcmVkIHBvb3IgcmF0aW5ncyBlbHNld2hlcmUgd2VyZSByYXRlZCBoaWdobHkgb24gRmFuZGFuZ28sIGFuYWx5c3RzIGZyb20gRml2ZVRoaXJ0eUVpZ2h0IGludmVzdGlnYXRlZCBhbmQgcHVibGlzaGVkIGFuIGFydGljbGUgYWJvdXQgYmlhcyBpbiBtb3ZpZSByYXRpbmdzLg0KDQpUbyBjb25kdWN0IHRoZSBpbnZlc3RpZ2F0aW9uLCB0aGUgdGVhbSBjb21waWxlZCBkYXRhIGZvciAxNDcgZmlsbXMgZnJvbSAyMDE1IHdpdGggcmV2aWV3cyBmcm9tIG1vdmllIGNyaXRpY3MgYW5kIGNvbnN1bWVycy4NCg0KSW4gdGhpcyBtaXNzaW9uLCB5b3UnbGwgdXNlIHRoaXMgZGF0YSBhbmQgZ2dwbG90MiB0byB2aXN1YWxpemUgcmV2aWV3cyBmcm9tIE1ldGFjcml0aWMsIEZhbmRhbmdvLCBSb3R0ZW4gVG9tYXRvZXMsIGFuZCBJTURCIHRvIGdldCBhIHNlbnNlIGZvciBkaWZmZXJlbmNlcyBpbiB0aGUgd2F5IHRoZSBmb3VyIHNpdGVzIGNvbXB1dGUgbW92aWUgcmF0aW5ncy4NCg0KV2UgaGF2ZSBtYWRlIGEgc3Vic2V0IG9mIHRoZSBkYXRhIGF2YWlsYWJsZSBmb3IgeW91IHRvIHdvcmsgd2l0aCBpbiB0aGlzIG1pc3Npb24gaW4gYSBmaWxlIG5hbWVkICJtb3ZpZV9yZXZpZXdzLmNzdiIuIFRoZSBmaWxlIGNvbnRhaW5zIHRocmVlIGNvbHVtbnM6DQoNCmBgYHtyfQ0KIyBTZWUgdGhlIG1vdmllIHJldmlldyBsaW5rIGJlbG93IGp1c3QgaW5jYXNlIHJlYWRpbmcgZGllY3RseSBmcm9tIEdpdGh1Yg0KcmV2aWV3c19saW5rIDwtICJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vZml2ZXRoaXJ0eWVpZ2h0L2RhdGEvbWFzdGVyL2ZhbmRhbmdvL2ZhbmRhbmdvX3NjcmFwZS5jc3YiICANCg0KcmV2aWV3cyA8LSByZWFkX2NzdigibW92aWVfcmV2aWV3cy5jc3YiKQ0KI1ZpZXcocmV2aWV3cykNCmhlYWQocmV2aWV3cykNCmBgYA0KDQoNCkxldCdzIHN0YXJ0IGJ5IGdldHRpbmcgYSBzZW5zZSBmb3IgaG93IHJldmlld3MgcmVwb3J0ZWQgYnkgdGhlIGZvdXIgc2l0ZXMgY29tcGFyZS4NCg0KWW91IGNhbiBhcHByb2FjaCB0aGlzIHByb2JsZW0gYnkgY2FsY3VsYXRpbmcgdGhlIGF2ZXJhZ2UgcmF0aW5ncyBmb3IgZWFjaCByYXRpbmcgc2l0ZS4gVG8gZG8gdGhpcywgeW91IGNvdWxkIGdyb3VwIHRoZSByZXZpZXdzIGRhdGEgZnJhbWUgaW50byBvbmUgZ3JvdXAgZm9yIGVhY2ggdmFsdWUgb2YgUmF0aW5nX1NpdGUgYW5kIGNhbGN1bGF0ZSB0aGUgYXZlcmFnZSBvZiBSYXRpbmcgZm9yIGVhY2ggZ3JvdXAuDQoNClJlY2FsbCBmcm9tIHRoZSBSIEludGVybWVkaWF0ZSBjb3Vyc2UgdGhhdCBzdWNoIHByb2JsZW1zLCB3aGVyZSB5b3UgcGVyZm9ybSBzdW1tYXJ5IGNhbGN1bGF0aW9ucyBvbiBncm91cGVkIGRhdGEsIGFyZSBrbm93biBhcyAic3BsaXQtYXBwbHktY29tYmluZSIoU0FDKSBwcm9ibGVtcy4NCg0KT25jZSB5b3UndmUgY2FsY3VsYXRlZCBhdmVyYWdlIHJhdGluZ3MgZm9yIGVhY2ggc2l0ZSwgd2UnbGwgaW50cm9kdWNlIHlvdSB0byBhIG5ldyB0eXBlIG9mIGdyYXBoIGZvciB2aXN1YWxpemluZyBjb21wYXJpc29ucyBhbW9uZyBncm91cHMsIG9yIGNhdGVnb3JpZXMsIG9mIGRhdGEuDQoNCkxldCdzIGNhbGN1bGF0ZSBhdmVyYWdlIHJhdGluZ3MgZm9yIGVhY2ggbW92aWUgcmF0aW5nIHNpdGUuDQoNCmBgYHtyfQ0KIyBJbnN0cnVjdGlvbnMNCiMgVXNlIGdyb3VwX2J5KCkgdG8gZ3JvdXAgdGhlIHJldmlld3MgZGF0YSBmcmFtZSBieSBSYXRpbmdfU2l0ZS4NCiMgVXNlIHN1bW1hcml6ZSgpIHRvIGNhbGN1bGF0ZSB0aGUgYXZlcmFnZSBSYXRpbmcgZm9yIGVhY2ggUmF0aW5nX1NpdGUuIFNhdmUgdGhlIHN1bW1hcnkgZGF0YSBmcmFtZSBhcyByZXZpZXdfYXZncy4NCnJldmlld19hdmdzIDwtIHJldmlld3MgJT4lIGdyb3VwX2J5KFJhdGluZ19TaXRlKSAlPiUgc3VtbWFyaXNlKGF2ZyA9IG1lYW4oUmF0aW5nKSkNCnJldmlld19hdmdzDQpgYGANCg0KTGlrZSBsaW5lIGdyYXBocywgYmFyIGNoYXJ0cyBkZXBpY3QgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHR3byB2YXJpYWJsZXMuIFRvIGNyZWF0ZSBhIGJhciBjaGFydCB0byB2aXN1YWxpemUgdGhlIGF2ZXJhZ2UgcmF0aW5ncyBmb3IgZWFjaCBtb3ZpZSByYXRpbmcgc2l0ZSwgeW91IHdvdWxkIHVzZSB0aGUgcmV2aWV3X2F2Z3MgZGF0YSBmcmFtZS4gVGhlIHN5bnRheCBmb3IgdGhlIGRhdGEgYW5kIGFlc3RoZXRpY3MgbGF5ZXJzIHlvdSdsbCBzcGVjaWZ5IHdoZW4gY3JlYXRpbmcgYSBiYXIgY2hhcnQgd2l0aCBnZ3Bsb3QyIGlzIHRoZSBzYW1lIGFzIHRoZSBzeW50YXggeW91IGxlYXJuZWQgd2hlbiBjcmVhdGluZyBsaW5lIGdyYXBocy4gDQpUaGUgbGF5ZXIgdGhhdCBkaXN0aW5ndWlzaGVzIGEgYmFyIGNoYXJ0IGZyb20gYSBsaW5lIGdyYXBoIGlzIHRoZSBsYXllciBpbiB3aGljaCB5b3UnbGwgc3BlY2lmeSB0aGUgZ2VvbWV0cmljIHNoYXBlIHVzZWQgdG8gZGlzcGxheSB0aGUgZGF0YS4gV2hpbGUgYmVmb3JlIHlvdSB1c2VkIGdlb21fbGluZSgpLCBub3cgeW91J2xsIHVzZSBnZW9tX2JhcigpOg0KDQpgYGANCmdncGxvdChkYXRhID0gcmV2aWV3X2F2Z3MpICsNCiAgYWVzKHggPSByYXRpbmdfc2l0ZSwgeSA9IGF2ZykgKyANCiAgZ2VvbV9iYXIoc3RhdCA9ICdpZGVudGl0eSkNCmBgYA0KSW4gdGhlIGNvZGUgYWJvdmUsIHdlIHNwZWNpZnkgc3RhdCA9ICJpZGVudGl0eSIgd2l0aGluIHRoZSBnZW9tX2JhcigpIGxheWVyLiBUaGlzIGlzIGJlY2F1c2UsIGJ5IGRlZmF1bHQsIHVzaW5nIGdlb21fYmFyKCkgY3JlYXRlcyBhIGJhciBncmFwaCB3aGVyZSB0aGUgaGVpZ2h0IG9mIHRoZSBiYXJzIGNvcnJlc3BvbmRzIHRvIHRoZSBudW1iZXIgb2YgdmFsdWVzIGluIHRoZSBzcGVjaWZpZWQgeS12YXJpYWJsZS4gVXNpbmcgc3RhdCA9ICJpZGVudGl0eSIgb3ZlcnJpZGVzIHRoZSBkZWZhdWx0IGJlaGF2aW9yIGFuZCBjcmVhdGVzIGJhcnMgZXF1YWwgdG8gdGhlIHZhbHVlIG9mIHRoZSB5LXZhcmlhYmxlLCB0aGUgYXZlcmFnZS4NCg0KYGBge3J9DQojIEluc3RydWN0aW9ucyAtLT4NCiMgDQojIFVzZSBnZ3Bsb3QyIHRvIGNyZWF0ZSBhIGJhciBjaGFydCBkZXBpY3RpbmcgdGhlIGF2ZXJhZ2UgbW92aWUgcmF0aW5ncyBmb3IgUm90dGVuIFRvbWF0b2VzLCBJTURCLCBNZXRhY3JpdGljLCBhbmQgRmFuZGFuZ28uIFdlIGhhdmUgbG9hZGVkIHRoZSBnZ3Bsb3QyIHBhY2thZ2UgZm9yIHlvdS4gLS0+DQojIFVzZSB0aGUgcmV2aWV3X2F2Z3MgZGF0YSBmcmFtZSB0aGF0IGNvbnRhaW5zIHlvdXIgY2FsY3VsYXRlZCBhdmVyYWdlIHJhdGluZ3MgZm9yIGVhY2ggc2l0ZS4gLS0+DQoNCmdncGxvdChkYXRhID0gcmV2aWV3X2F2Z3MpICsgDQogIGFlcyh4ID0gUmF0aW5nX1NpdGUsIHkgPSBhdmcsIGNvbG9yPVJhdGluZ19TaXRlKSArDQogIGdlb21fYmFyKHN0YXQgPSAnaWRlbnRpdHknKQ0KYGBgDQoNCkFzIHlvdSBsb29rIGF0IHRoZSBjaGFydCwgeW91IGNhbiBjbGVhcmx5IHNlZSB0aGF0IEZhbmRhbmdvIGhhcyBhIGhpZ2hlciBhdmVyYWdlIG1vdmllIHJhdGluZyB0aGFuIHRoZSBvdGhlciB0aHJlZSBzaXRlcy4gRG9lcyB0aGlzIG1lYW4gRmFuZGFuZ28gdGVuZHMgdG8gZ2l2ZSBoaWdoZXIgcmF0aW5ncz8NCg0KQXMgeW91IGNvbnNpZGVyIHRoYXQgcXVlc3Rpb24sIGxldCdzIHRoaW5rIGFib3V0IHdoYXQgdGhlIGJhciBjaGFydCBkb2VzIG5vdCBzaG93IHVzLiBJdCBtYWtlcyBzZW5zZSB0byB3b25kZXIgaWYgRmFuZGFuZ28ncyBhdmVyYWdlIG1vdmllIHJhdGluZyBpcyBoaWdoZXIgdGhhbiB0aG9zZSBvZiB0aGUgb3RoZXIgc2l0ZXMgYmVjYXVzZSBpdCB0ZW5kcyB0byBnaXZlIGFsbCBtb3ZpZXMgZ29vZCByYXRpbmdzLCBvciBiZWNhdXNlIGl0IGdhdmUgc29tZSBtb3ZpZXMgYXZlcmFnZSByYXRpbmdzIGFuZCBhIHNtYWxsIG51bWJlciBvZiBtb3ZpZXMgZXhjZWxsZW50IHJhdGluZ3MuDQoNCkhvd2V2ZXIsIHRoZSBiYXIgZ3JhcGggZG9lcyBub3QgcHJvdmlkZSB0aGlzIGluZm9ybWF0aW9uLg0KDQpUaGUgYXZlcmFnZSBvZiBhIHNldCBvZiBudW1iZXJzIGRvZXMgbm90IHRlbGwgdXMgYW55dGluZyBhYm91dCB0aGUgc3ByZWFkIG9mIHRoZSBudW1iZXJzIHRoYXQgd2VyZSB1c2VkIHRvIGNhbGN1bGF0ZSB0aGUgYXZlcmFnZS4gRm9yIGV4YW1wbGUsIHRoZSB2YWx1ZXMgb2YgdGhlc2UgdHdvIHZhcmlhYmxlcyBib3RoIGhhdmUgYW4gYXZlcmFnZSBvZiA1Og0KDQpgYGANClZhcmlhYmxlIDE6IDUgNSA1IDUgNSA0IDUgNSA2IDUNClZhcmlhYmxlIDI6IDIwIDkgMSAyIDggNCA5IDUgNw0KYGBgDQpIb3dldmVyLCB3aGlsZSB2YWx1ZXMgb2YgVmFyaWFibGUgMSBhcmUgZGlzdHJpYnV0ZWQgYmV0d2VlbiA0IGFuZCA2LCB2YWx1ZXMgb2YgVmFyaWFibGUgMiBhcmUgZGlzdHJpYnV0ZWQgYmV0d2VlbiAxIGFuZCAyMC4gVGhlIHZhbHVlcyBvZiBWYXJpYWJsZSAyIGFyZSBtdWNoIG1vcmUgc3ByZWFkIG91dCB0aGFuIHRob3NlIG9mIFZhcmlhYmxlIDEuDQoNClRoaXMgbGVhZHMgdXMgdG8gdGhlIG5leHQgY2hhcnQsIHdoaWNoIGlzIGNhbGxlZCBhIEhpc3RvZ3JhbS4gQSBIaXN0b2dyYW0gd2lsbCBzaG93IHVzIHRoZSBjb3VudCBvciBmcmVxdWVuY3kgb2YgdmFsdWVzIGluIGVhY2ggcmF0aW5nIHNjYWxlLg0KDQpUbyB2aXN1YWxpemUgZGF0YSB1c2luZyBhIGhpc3RvZ3JhbSwgdGhlIHN5bnRheCBmb3IgdGhlIGRhdGEgYW5kIGFlc3RoZXRpY3MgbGF5ZXJzIGFyZSBzaW1pbGFyIHRvIHdoYXQgeW91IGhhdmUgdXNlZCB0byBnZW5lcmF0ZSBsaW5lIGdyYXBocyBhbmQgYmFyIGNoYXJ0czoNCmBgYA0KZ2dwbG90KGRhdGEgPSByZXZpZXdzKSArIA0KICBhZXMoeCA9IFJhdGluZykgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEpDQpgYGANCg0KV2l0aGluIHRoZSBhZXMoKSBsYXllciwgeW91IG9ubHkgbmVlZCB0byBzcGVjaWZ5IHRoZSBpbmRlcGVuZGVudCB2YXJpYWJsZS4gUmVtZW1iZXIgd2hlbiB5b3UgY3JlYXRlIGEgaGlzdG9ncmFtLCB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIGNvdW50IGlzIGNhbGN1bGF0ZWQgZm9yIHlvdS4NCg0KVGhlIGdlb21faGlzdG9ncmFtKCkgbGF5ZXIgc3BlY2lmaWVzIGNyZWF0aW9uIG9mIGEgaGlzdG9ncmFtIHRvIHJlcHJlc2VudCB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGUuIFRoZSBhcmd1bWVudCBiaW53aWR0aCA9IDEgc3BlY2lmaWVzIHRoZSBzaXplIG9mIHRoZSBjYXRlZ29yaWVzIHVzZWQgdG8gYmluIHRoZSB2YWx1ZXMgb2YgdGhlIGluZGVwZW5kZW50IHZhcmlhYmxlLg0KDQpXaXRoaW4gdGhlIGdlb21faGlzdG9ncmFtKCkgbGF5ZXIsIHlvdSBjYW4gdXNlIHR3byBkaWZmZXJlbnQgYXJndW1lbnRzIHRvIHNwZWNpZnkgdGhlIG51bWJlciBvZiBjYXRlZ29yaWVzIGZvciBiaW5uaW5nIHRoZSBpbmRlcGVuZGVudCB2YXJpYWJsZS4NCg0KYmlud2lkdGggPSBhbGxvd3MgeW91IHRvIHNwZWNpZnkgdGhlIHNpemUgb2YgdGhlIGJpbnMsIGFuZCBpcyB1c2VmdWwgZm9yIGluc3RhbmNlcywgc3VjaCBhcyB0aGlzIGV4YW1wbGUsIHdoZXJlIHlvdSB3YW50IGNhdGVnb3JpZXMgdG8gc3BhbiBzcGVjaWZpYyBpbnRlcnZhbHMuDQpiaW5zID0gYWxsb3dzIHlvdSB0byBzcGVjaWZ5IHRoZSBudW1iZXIgb2YgYmlucywgd2hpY2ggY2FuIGJlIHVzZWZ1bCB0byBleHBlcmltZW50IHdpdGggd2hlbiBkZWNpZGluZyBob3cgbXVjaCBkZXRhaWwgeW91IHdhbnQgdG8gdXNlIHRvIGRpc3BsYXkgeW91ciBkYXRhLg0KSWYgeW91IGRvbid0IHVzZSBhbnkgYXJndW1lbnRzIHdpdGhpbiB0aGUgZ2VvbV9oaXN0b2dyYW0oKSBsYXllciwgZ2dwbG90MiB3aWxsIHVzZSBhIGRlZmF1bHQgbnVtYmVyIG9mIGJpbnMuDQoNCmBgYHtyfQ0KIyBJbnN0cnVjdGlvbnMNCiMgDQojIENyZWF0ZSBhIGhpc3RvZ3JhbSB0byBzaG93IHRoZSBkaXN0cmlidXRpb24gb2YgYWxsIHZhbHVlcyBvZiB0aGUgUmF0aW5nIHZhcmlhYmxlIGluIHRoZSByZXZpZXdzIGRhdGEgZnJhbWUuDQojIFNwZWNpZnkgMzAgYmlucyB0byBjYXRlZ29yaXplIHZhbHVlcyBvZiB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGUuDQoNCmdncGxvdChkYXRhID0gcmV2aWV3cykgKyANCiAgYWVzKHggPSBSYXRpbmcpICsgDQogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAzMCkNCmBgYA0KDQpIaXN0b2dyYW1zIGFsbG93IHlvdSB0byB2aXN1YWxpemUgdGhlIHNoYXBlIG9mIGEgZGlzdHJpYnV0aW9uIOKAlCB3aGVyZSB2YWx1ZXMgb2YgdGhlIGRhdGEgYXJlIGNsdXN0ZXJlZC4gTW9zdCB2YWx1ZXMgb2YgUmF0aW5nIGFyZSBjbHVzdGVyZWQgYmV0d2VlbiAzLjUgYW5kIDQuNS4NCg0KVGhpcyBoaXN0b2dyYW0gdGVsbHMgdXMgYWJvdXQgdGhlIGRpc3RyaWJ1dGlvbiBvZiBhbGwgdmFsdWVzIG9mIHRoZSBSYXRpbmcgdmFyaWFibGUsIGJ1dCB3aGF0IHdlIHJlYWxseSB3YW50IHRvIGludmVzdGlnYXRlIGlzIGhvdyByYXRpbmdzIGZvciBkaWZmZXJlbnQgcmF0aW5nIHNpdGVzIGRpZmZlci4NCg0KT25lIHdheSB0byBjb21wYXJlIFJhdGluZyBkaXN0cmlidXRpb25zIGZvciB0aGUgZm91ciBzaXRlcyBpcyB0byBjcmVhdGUgYSBmYWNldGVkIHBsb3QsIGFzIHlvdSBsZWFybmVkIHRvIGRvIGZvciBsaW5lIGdyYXBocy4NCg0KUmVjYWxsIHRoYXQgdG8gY3JlYXRlIGEgZmFjZXRlZCBwbG90IGZvciBjYXRlZ29yaWVzIG9mIGEgdmFyaWFibGUsIHlvdSBjYW4gYWRkIGEgbGF5ZXIgdG8geW91ciBncmFwaCB1c2luZyBmYWNldF93cmFwKCk6DQoNCmBgYHtyfQ0KIyBJbnN0cnVjdGlvbnMNCiMgDQojIEFkZCBhIGxheWVyIHRvIHRoZSBoaXN0b2dyYW0geW91IGNyZWF0ZWQgb24gdGhlIGxhc3Qgc2NyZWVuIHRvIGNyZWF0ZSBhIGZhY2V0ZWQgZ3JhcGggY29udGFpbmluZyBmb3VyIGhpc3RvZ3JhbXMgb2YgdGhlIGRpc3RyaWJ1dGlvbiBvZiBSYXRpbmcgZm9yIGVhY2ggc2l0ZToNCiMgUm90dGVuIFRvbWF0b2VzDQojIElNREINCiMgTWV0YWNyaXRpYw0KIyBGYW5kYW5nbw0KIyBVc2UgbnJvdyA9IDIgd2l0aGluIHRoZSBmYWNldF93cmFwKCkgbGF5ZXIgdG8gc3BlY2lmeSBhIHR3by1ieS10d28gYXJyYW5nZW1lbnQgb2YgdGhlIGhpc3RvZ3JhbXMuDQoNCmdncGxvdChkYXRhID0gcmV2aWV3cykgKw0KICBhZXMoeCA9IFJhdGluZykgKyANCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDMwKSArDQogIGZhY2V0X3dyYXAoflJhdGluZ19TaXRlLCBucm93ID0gMikNCmBgYA0KDQpUaGUgZGlzdHJpYnV0aW9ucyBvZiBSYXRpbmcgZm9yIFJvdHRlbiBUb21hdG9lcyBhbmQgTWV0YWNyaXRpYyBpbmRpY2F0ZSB0aGF0IHRob3NlIHR3byBzaXRlcyBhcmUgbW9yZSBsaWtlbHkgdG8gZ2l2ZSBtb3ZpZXMgcG9vciByYXRpbmdzIHRoYW4gRmFuZGFuZ28gb3IgSU1EQiwgd2hpY2ggaGF2ZSBtb3N0IHZhbHVlcyBvZiBSYXRpbmcgY2x1c3RlcmVkIG92ZXIgMy4NCg0KQ29tcGFyaW5nIHRoZXNlIGRpc3RyaWJ1dGlvbnMgc3VnZ2VzdHMgc29tZSBzaXRlcyBnaXZlIHBvb3IgcmF0aW5ncyBtb3JlIG9mdGVuIHRoYW4gb3RoZXJzLiBGb3IgZXhhbXBsZSwgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgZGlzdHJpYnV0aW9ucyBvZiBSYXRpbmdzIGZvciBGYW5kYW5nbyBhbmQgUm90dGVuIFRvbWF0b2VzIGlzIHZlcnkgY2xlYXIuIEhvd2V2ZXIsIEZhbmRhbmdvIGFuZCBJTURCIGhhdmUgZGlzdHJpYnV0aW9ucyB0aGF0IGxvb2sgc2ltaWxhci4gSXMgdGhlcmUgYSBiZXR0ZXIgd2F5IHRvIHZpc3VhbGl6ZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZW0/DQoNClJlbWVtYmVyIHRoYXQgd2hlbiB5b3UgY3JlYXRlZCBsaW5lIGNoYXJ0cywgcGxvdHRpbmcgbXVsdGlwbGUgdmFyaWFibGVzIG9uIHRoZSBzYW1lIHNldCBvZiBheGVzIHdhcyB1c2VmdWwgZm9yIGNyZWF0aW5nIGEgbW9yZSBudWFuY2VkIGNvbXBhcmlzb24uIFNpbWlsYXJseSwgd2UgY2FuIHBsb3QgaGlzdG9ncmFtcyBmb3IgdGhlIGZvdXIgcmF0aW5nIHNpdGVzIG9uIHRoZSBzYW1lIHNldCBvZiBheGVzLg0KDQpBcyB5b3UgZGlkIGZvciBsaW5lIGdyYXBocywgeW91IGNhbiBkaXN0aW5ndWlzaCB2YWx1ZXMgYXNzb2NpYXRlZCB3aXRoIGRpZmZlcmVudCB2YXJpYWJsZXMgYnkgbWFwcGluZyB0aGVtIHRvIGRpZmZlcmVudCBjb2xvcnMgd2l0aGluIHRoZSBhZXMoKSBsYXllcjoNCmBgYA0KZ2dwbG90KGRhdGEgPSByZXZpZXdzKSArIA0KICBhZXMoeCA9IFJhdGluZywgY29sb3IgPSBSYXRpbmdfU2l0ZSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMzApDQpgYGANCldoZW4gY3JlYXRpbmcgaGlzdG9ncmFtcyAob3IgYmFyIGNoYXJ0cyksIHVzaW5nIHRoZSBhcmd1bWVudCBjb2xvciA9IHdpdGhpbiBhZXMoKSBtYXBzIHlvdXIgc3BlY2lmaWVkIHZhcmlhYmxlIHRvIGJhciBvdXRsaW5lcyBvZiBkaWZmZXJlbnQgY29sb3JzOg0KDQpBbm90aGVyIG9wdGlvbiBmb3IgdXNpbmcgYWVzdGhldGljcyB0byBtYXAgdmFsdWVzIG9mIFJhdGluZyB0byBkaWZmZXJlbnQgdmFsdWVzIG9mIFJhdGluZ19TaXRlIGlzIHRvIHVzZSB0aGUgYXJndW1lbnQgZmlsbCA9IGluc3RlYWQgb2YgY29sb3IgPS4gSW5zdGVhZCBvZiBvdXRsaW5lcywgZmlsbCA9IGRlcGljdHMgYmFycyBmaWxsZWQgaW4gd2l0aCBkaWZmZXJlbnQgY29sb3JzLiBMZXQncyB1c2UgYm90aCBvcHRpb24gdG8gdmlzdWFsaXplIGRpZmZlcmVuY2VzIGluIFJhdGluZyBkaXN0cmlidXRpb25zIG9mIHRoZSBmb3VyIHNpdGVzLg0KDQpgYGB7cn0NCiMgSW5zdHJ1Y3Rpb25zDQojIENyZWF0ZSBhIGhpc3RvZ3JhbSBkZXBpY3RpbmcgdGhlIGRpc3RyaWJ1dGlvbiBvZiBSYXRpbmdzIGZvciBlYWNoIHNpdGUgdXNpbmcgYmFycyB3aXRoIGRpZmZlcmVudCBjb2xvciBsaW5lcy4NCg0KZ2dwbG90KGRhdGEgPSByZXZpZXdzKSArIA0KICBhZXMoeCA9IFJhdGluZywgY29sb3IgPSBSYXRpbmdfU2l0ZSkgKyANCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDMwKSArIA0KICBmYWNldF93cmFwKH5SYXRpbmdfU2l0ZSwgbnJvdyA9IDIpDQpgYGANCg0KYGBge3J9DQojIEluc3RydWN0aW9ucw0KIyBDcmVhdGUgYSBoaXN0b2dyYW0gZGVwaWN0aW5nIHRoZSBkaXN0cmlidXRpb24gb2YgUmF0aW5ncyBmb3IgZWFjaCBzaXRlIHVzaW5nIGJhcnMgZmlsbGVkIHdpdGggZGlmZmVyZW50IGNvbG9ycy4NCg0KZ2dwbG90KGRhdGEgPSByZXZpZXdzKSArIA0KICBhZXMoeCA9IFJhdGluZywgZmlsbCA9IFJhdGluZ19TaXRlKSArIA0KICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMzApICsgDQogIGZhY2V0X3dyYXAoflJhdGluZ19TaXRlLCBucm93ID0gMikNCmBgYA0KDQpgYGB7cn0NCiMgUGxvdHRpbmcgYWxsIGZvdXIgaGlzdG9ncmFtcyBvbiBvbmUgY2FudmFzIHdpdGggZGlmZmVyZW50IGZpbGxlZCBjb2xvcnMNCmdncGxvdChkYXRhID0gcmV2aWV3cykgKyANCiAgYWVzKHggPSBSYXRpbmcsIGZpbGwgPSBSYXRpbmdfU2l0ZSkgKyANCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDMwKQ0KYGBgDQoNCmBgYHtyfQ0KIyBQbG90dGluZyBhbGwgZm91ciBoaXN0b2dyYW1zIG9uIG9uZSBjYW52YXMgd2l0aCBkaWZmZXJlbnQgZWRnZSBjb2xvcnMgY29sb3JzDQpnZ3Bsb3QoZGF0YSA9IHJldmlld3MpICsgDQogIGFlcyh4ID0gUmF0aW5nLCBjb2xvciA9IFJhdGluZ19TaXRlKSArIA0KICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMzApDQpgYGANCg0KVmlzdWFsaXppbmcgdGhlIGRpc3RyaWJ1dGlvbnMgb2YgUmFua2luZ3MgZm9yIGVhY2ggcmF0aW5nIHNpdGUgbWFrZXMgaXQgY2xlYXIgdGhhdCBGYW5kYW5nbyBpcyBtb3JlIGxpa2VseSB0byByYXRlIG1vdmllcyBoaWdobHkgdGhhbiB0aGUgb3RoZXIgc2l0ZXMgYXJlLCB3aGljaCBzdXBwb3J0cyB0aGUgYXJndW1lbnQgdGhhdCBpdCBpcyBiaWFzZWQgdG93YXJkIGFzc2lnbmluZyBoaWdoZXIgcmF0aW5ncy4NCg0KWW91J2xsIG9mdGVuIHVzZSBoaXN0b2dyYW1zIGluIHlvdXIgZGF0YSBzY2llbmNlIGNhcmVlciBmb3IgaW5pdGlhbCBleHBsb3JhdGlvbnMgb2YgeW91ciBkYXRhLiBLbm93aW5nIGhvdyB0byB2aXN1YWxpemUgYW5kIGludGVycHJldCBkaXN0cmlidXRpb25zIHdpbGwgYmVjb21lIGluY3JlYXNpbmdseSBpbXBvcnRhbnQgbGF0ZXIgb24gd2hlbiB5b3UgbGVhcm4gYWJvdXQgc3RhdGlzdGljcyBhbmQgbW9kZWxpbmcuDQoNCk5vdyB0aGF0IHlvdSdyZSBhYmxlIHRvIG1ha2UgYmFyIGNoYXJ0cyB0byB2aXN1YWxpemUgZGF0YSBzdW1tYXJpZXMgYW5kIGhpc3RvZ3JhbXMgdG8gdmlzdWFsaXplIGRhdGEgZGlzdHJpYnV0aW9ucywgd2UnbGwgaW50cm9kdWNlIHlvdSB0byBhIHR5cGUgb2YgcGxvdCBmb3IgdmlzdWFsaXppbmcgYm90aCB0aGUgY2VudGVyIG9mIGFuZCB0aGUgdmFyaWF0aW9uIGluIHlvdXIgZGF0YS4NCg0KDQpMaWtlIEJhciBjaGFydHMsIEJveCBwbG90cyBwcm92aWRlIGEgc3VtbWFyeSBvZiBkYXRhIGJ5IGdyb3VwLiBMaWtlIGhpc3RvZ3JhbXMsIHRoZXkgcHJvdmlkZSBpbmZvcm1hdGlvbiBhYm91dCBob3cgZGF0YSBhcmUgc3ByZWFkLg0KDQpUbyBjcmVhdGUgYSBib3ggcGxvdCB1c2luZyBnZ3Bsb3QyLCB0aGUgc3ludGF4IGZvciBjcmVhdGluZyB0aGUgZGF0YSBsYXllciBhbmQgbWFwcGluZyBkYXRhIHRvIHggYW5kIHkgdmFyaWFibGVzIGlzIGZhbWlsaWFyLg0KYGBgDQpnZ3Bsb3QoZGF0YSA9IHJldmlld3MpICsgDQogIGFlcyh4ID0gUmF0aW5nLCBjb2xvciA9IFJhdGluZ19TaXRlKSArDQogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAzMCkNCmdncGxvdChkYXRhID0gcmV2aWV3cykgKw0KICBhZXMoeCA9IFJhdGluZ19TaXRlLCB5ID0gUmF0aW5nKQ0KYGBgDQpZb3UnbGwgYWRkIGEgZ2VvbV9ib3hwbG90KCkgbGF5ZXIgdG8gc3BlY2lmeSBjcmVhdGlvbiBvZiBhIGJveCBwbG90Lg0KDQpMZXQncyBjcmVhdGUgYSBib3ggcGxvdCBvZiByYXRpbmdzIGZvciBlYWNoIHNpdGUgaW4gdGhlIHJldmlld3MgZGF0YSBmcmFtZS4NCg0KYGBge3J9DQojIEluc3RydWN0aW9ucw0KIyANCiMgQ3JlYXRlIGEgYm94IHBsb3QgdG8gdmlzdWFsaXplIHN1bW1hcmllcyBvZiB2YWx1ZXMgb2YgdGhlIFJhdGluZyB2YXJpYWJsZSBmb3IgZWFjaCB2YWx1ZSBvZiBSYXRpbmdfU2l0ZS4NCiMgQWRkIGEgZ2VvbV9ib3hwbG90KCkgbGF5ZXIgdG8gc3BlY2lmeSBjcmVhdGlvbiBvZiBhIGJveCBwb3QuDQoNCmdncGxvdChkYXRhID0gcmV2aWV3cykgKyANCiAgYWVzKHggPSBSYXRpbmdfU2l0ZSwgeSA9IFJhdGluZywgZmlsbCA9IFJhdGluZ19TaXRlKSArIA0KICBnZW9tX2JveHBsb3QoKQ0KYGBgDQoNCkluIGdlbmVyYWwsIHlvdSBjYW4gc2VlIHRoYXQgdGhlIGJveCByZXByZXNlbnRpbmcgRmFuZGFuZ28gcmF0aW5ncyBpcyBoaWdoZXIgdXAgb24gdGhlIHktYXhpcyB0aGFuIHRob3NlIGZvciB0aGUgb3RoZXIgc2l0ZXMuIFlvdSBjYW4gYWxzbyBzZWUgdGhlIFJvdHRlbiBUb21hdG9lcyByYXRpbmdzIGFwcGVhciB0byBiZSBtb3JlIHNwcmVhZCBvdXQsIHdoaWNoIGlzIGNvbnNpc3RlbnQgd2l0aCB3aGF0IHlvdSBzYXcgd2hlbiB3ZSBwbG90dGVkIHRoZSBkYXRhIHVzaW5nIGhpc3RvZ3JhbXMuDQoNCldoaWxlIHlvdSd2ZSBiZWVuIGFibGUgdG8gZ2xlYW4gc29tZSBpbmZvcm1hdGlvbiBmcm9tIHRoaXMgYm94IHBsb3QsIGxldCdzIGRpZyBkZWVwZXIgaW50byB0aGUgaW5kaXZpZHVhbCBjb21wb25lbnRzIHRvIGZ1bGx5IHVuZGVyc3RhbmQgYWxsIHRoZXkgY2FuIHRlbGwgdXMgYWJvdXQgZGF0YS4NCg0KQm94IHBsb3RzIHByZXNlbnQgd2hhdCBpcyBrbm93biB0byBzdGF0aXN0aWNpYW5zIGFzIGEgZml2ZS1udW1iZXIgc3VtbWFyeS4gVGhlIGZpdmUgbnVtYmVycyByZWZlciB0byBwZXJjZW50aWxlcyBvZiB0aGUgZGF0YSB5b3UncmUgd29ya2luZyB3aXRoOg0KDQpUaGUgZml2ZSBwZXJjZW50aWxlcyBzdW1tYXJpemVkIGJ5IGEgYm94IHBsb3QgYXJlOg0KDQpUaGUgbGFyZ2VzdCB2YWx1ZTogUmVwcmVzZW50ZWQgYnkgdGhlIHRvcCBvZiB0aGUgYmxhY2sgbGluZSBleHRlbmRpbmcgZnJvbSB0aGUgdG9wIG9mIHRoZSBib3guIFRoZXNlIGxpbmVzIGFyZSBhbHNvIGtub3duIGFzICJ3aGlza2VycyIuDQpUaGUgdGhpcmQgcXVhcnRpbGUgKFEzKTogUmVwcmVzZW50ZWQgYnkgdGhlIHRvcCBvZiB0aGUgYm94LiBTZXZlbnR5LWZpdmUgcGVyY2VudCBvZiB0aGUgdmFsdWVzIGFyZSBzbWFsbGVyIHRoYW4gdGhlIHRoaXJkIHF1YXJ0aWxlLg0KVGhlIG1lZGlhbjogUmVwcmVzZW50ZWQgYnkgdGhlIHRoaWNrIGJsYWNrIGxpbmUuIFRoZSBtZWRpYW4gaXMgdGhlIHZhbHVlIHRoYXQgZmFsbHMgaW4gdGhlIG1pZGRsZSBvZiB0aGUgZGF0YS4NClRoZSBmaXJzdCBxdWFydGlsZSAoUTEpOiBSZXByZXNlbnRlZCBieSB0aGUgYm90dG9tIG9mIHRoZSBib3guIFR3ZW50eS1maXZlIHBlcmNlbnQgb2YgdGhlIHZhbHVlcyBhcmUgc21hbGxlciB0aGFuIHRoZSBmaXJzdCBxdWFydGlsZS4NClRoZSBzbWFsbGVzdCB2YWx1ZTogUmVwcmVzZW50ZWQgYnkgdGhlIGJvdHRvbSBvZiB0aGUgYmxhY2sgbGluZSBleHRlbmRpbmcgZnJvbSB0aGUgYm90dG9tIG9mIHRoZSBib3guDQpUaGUgd2hpdGUgYm94LCBib3VuZGVkIGJ5IFEzIGFuZCBRMSwgaXMgcmVmZXJyZWQgdG8gYXMgdGhlIEludGVycXVhcnRpbGUgUmFuZ2Ugb3IgSVFSLiBUaGUgSVFSIGVuY29tcGFzc2VzIDUwIHBlcmNlbnQgb2YgdGhlIGRhdGEsIGFuZCBpcyBjYWxjdWxhdGVkIGJ5IHN1YnRyYWN0aW5nIFExIGZyb20gUTMuDQoNCkluIHRoZSBib3ggcGxvdCB5b3UgY3JlYXRlZCwgbm90aWNlIHRoZXJlIGFyZSBzb21lIHBvaW50cyB0aGF0IGZhbGwgYmVsb3cgdGhlIGJvdHRvbSBvZiB0aGUgYmxhY2sgbGluZXMgdGhhdCByZXByZXNlbnQgdGhlIHNtYWxsZXN0IHZhbHVlcy4gVGhlc2UgcG9pbnRzIGFyZSByZWZlcnJlZCB0byBhcyBvdXRsaWVycyBiZWNhdXNlIHRoZXkgYXJlIG91dHNpZGUgdGhlIHJhbmdlIG9mIHdoYXQgd291bGQgYmUgZXhwZWN0ZWQgYmFzZWQgb24gdGhlIHJlc3Qgb2YgdGhlIGRhdGEuDQoNCldoZW4geW91IG1ha2UgYSBib3ggcGxvdCB1c2luZyBnZ3Bsb3QyLCBkYXRhIHBvaW50cyB0aGF0IGZhbGwgYmVsb3cgUTEg4oiSIDEuNSBJUVIgb3IgYWJvdmUgUTMgKyAxLjUgSVFSIGFyZSBkZWZpbmVkIGFzIG91dGxpZXJzLg0KDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KDQpOb3cgdGhhdCB5b3UndmUgZGVsdmVkIGludG8gdGhlIG1lYW5pbmcgb2YgdGhlIGNvbXBvbmVudHMgb2YgYSBib3ggcGxvdCwgd2hhdCBjYW4geW91IGxlYXJuIGFib3V0IHRoZSBtb3ZpZSByYXRpbmcgZGF0YT8gSGVyZSBhcmUgc29tZSBvYnNlcnZhdGlvbnM6DQoNClZhbHVlcyBvZiBSYXRpbmcgZm9yIFJvdHRlbiBUb21hdG9lcyBhcmUgc3ByZWFkIG91dCwgaW5kaWNhdGluZyB0aGV5IHJlZ3VsYXJseSBnaXZlIG1vdmllcyByYXRpbmdzIHRoYXQgcmFuZ2UgZnJvbSBwb29yIHRvIGV4Y2VsbGVudC4NCg0KVGhlIHJhbmdlIG9mIHZhbHVlcyBvZiBSYXRpbmcgZm9yIEZhbmRhbmdvIGFuZCBJTURCIGFyZSBib3RoIHF1aXRlIG5hcnJvdy4gRmFuZGFuZ28ncyBsb3dlc3QgcmV2aWV3cyBhcmUgYXJvdW5kIDIuNSwgd2hsZSBvdXRsaWVycyBpbmRpY2F0ZSB0aGF0IElNREIgaGFzIHNvbWUgcmV2aWV3cyB0aGF0IGFyZSBiZXR3ZWVuIDIgYW5kIDIuNC4NCg0KRmFuZGFuZ28ncyBtZWRpYW4gZm9yIHZhbHVlcyBvZiBSYXRpbmcgaXMgaGlnaGVyIHRoYW4gdGhlIG1lZGlhbiBvZiB0aGUgb3RoZXIgc2l0ZXMsIGluZGljYXRpbmcgRmFuZGFuZ28gdGVuZHMgdG8gZ2l2ZSBoaWdoZXIgcmF0aW5ncy4NCg0KRG9lcyB0aGUgYm94IHBsb3QgeW91IG1hZGUgc3VwcG9ydCB0aGUgaWRlYSB0aGF0IEZhbmRhbmdvJ3MgcmV2aWV3cyBhcmUgYmlhc2VkPyBXaGljaCBzaXRlIGRvIHlvdSB0aGluayB3b3VsZCBwcm92aWRlIHRoZSBtb3N0IHVuYmlhc2VkIHJldmlld3M/DQoNCkZyb20gdGhpcyBleGVyY2lzZSwgTXkgcGVyc29uYWwgb3BpbmlvbiBpcyB0aGF0IFJvdHRlbi1Ub21hdG9lcyBnaXZlIHRoZSBtb3N0IHVuYmlhc2VkIHJldmlld3MuDQoNCmBgYHtyfQ0KIyBJbnN0cnVjdGlvbnMNCiMgDQojIEluIHRoZSBwcmV2aW91cyBleGVyY2lzZSwgeW91IGNyZWF0ZWQgYSBib3ggcGxvdCB0byB2aXN1YWxpemUgc3VtbWFyaWVzIG9mIHJhdGluZ3MgZm9yIEZhbmRhbmdvLCBJTURCLCBNZXRhY3JpdGljLCBhbmQgUm90dGVuIFRvbWF0b2VzLg0KIyANCiMgQWRkIGxheWVycyB0byB5b3VyIHBsb3Qgc28gaXQgZml0cyB0aGUgZm9sbG93aW5nIHNwZWNpZmljYXRpb25zOg0KIyANCiMgV2hpdGUgcGFuZWwgYmFja2dyb3VuZA0KIyBUaGUgcGxvdCB0aXRsZTogIkNvbXBhcmlzb24gb2YgTW92aWUgUmF0aW5ncyINCmdncGxvdChkYXRhID0gcmV2aWV3cykgKyANCiAgYWVzKHggPSBSYXRpbmdfU2l0ZSwgeSA9IFJhdGluZywgZmlsbCA9IFJhdGluZ19TaXRlKSArIA0KICBnZW9tX2JveHBsb3QoKSArIA0KICBsYWJzKHRpdGxlID0gIkNvbXBhcmlzb24gb2YgTW92aWUgUmF0aW5ncyIpICsNCiAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gJ3doaXRlJykpDQpgYGANCg0KQXMgd2UgZGlzY3Vzc2VkIGVhcmxpZXIgaW4gdGhpcyBjb3Vyc2UsIGJ1aWxkaW5nIGludHVpdGlvbiBhcm91bmQgd2hlbiB0byB1c2UgZGlmZmVyZW50IHR5cGVzIG9mIHZpc3VhbGl6YXRpb25zIHRvIHVuZGVyc3RhbmQgeW91ciBkYXRhIGlzIGFuIGltcG9ydGFudCBza2lsbCB5b3Ugd2lsbCBkZXZlbG9wLg0KDQpXaGVuIHNob3VsZCB5b3UgdXNlIHRoZSB0aHJlZSB0eXBlcyBvZiBwbG90cyB5b3UgbGVhcm5lZCBhYm91dCBpbiB0aGlzIG1pc3Npb24/IFlvdSB3aWxsIHByb2JhYmx5IGV4cGxvcmUgZGlmZmVyZW50IG9wdGlvbnMgZm9yIHZpc3VhbGl6aW5nIGVhY2ggbmV3IGRhdGEgc2V0LCBhbmQgZG9pbmcgc28gaXMgYSBnb29kIGlkZWEuIEhvd2V2ZXIsIGhlcmUgYXJlIHNvbWUgZ2VuZXJhbCBndWlkZWxpbmVzOg0KDQpCYXIgY2hhcnRzIG1heSBiZSB1c2VkIGZvciBzaG93aW5nIGEgcXVpY2sgc3VtbWFyeSBvZiB5b3VyIGRhdGEsIHN1Y2ggYXMgYXZlcmFnZXMgb3IgY291bnRzIG9mIHRoZSBudW1iZXIgb2YgaW5zdGFuY2VzIG9mIGEgdmFsdWUgdGhhdCBvY2N1ciBmb3IgYSBnaXZlbiB2YXJpYWJsZS4NCg0KSGlzdG9ncmFtcyBhcmUgdXNlZnVsIGZvciB2aXN1YWxpemluZyBkaXN0cmlidXRpb25zIG9mIGRhdGEgd2hlbiB5b3Ugd2FudCB0byBrbm93IHRoZSBzaGFwZSBvZiBhIGRpc3RyaWJ1dGlvbiAoaW4gb3RoZXIgd29yZHMsIHdoZXJlIG1vc3QgdmFsdWVzIGFyZSBjbHVzdGVyZWQpLg0KDQpCb3ggcGxvdHMgcHJvdmlkZSBhbiBpbmZvcm1hdGl2ZSBzdW1tYXJ5IG9mIHRoZSBzaGFwZSwgc3ByZWFkLCBhbmQgY2VudGVyIG9mIHlvdXIgZGF0YS4NCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0K