Background
What are the most important factors in determining the IMDB rating of a movie and can we use a multiple linear regression model to predict this rating?
This project is based on a fictitious scenario where I’ve been hired as a data scientist at Paramount Pictures. The data presents numerous variables on movies such as audience/critic ratings, number of votes, runtime, genre, etc. Paramount Pictures is looking to gather insights into determining the acclaim of a film and other novel patterns or ideas. The data set is comprised of 651 randomly sampled movies produced and released before 2016.
Part 1: Data
generabizability
The dataset is comprised of 651 randomly sampled movies produced and released before 2016. Therefore,due to the random sampling, it can be assumed that the data is representative of all movies produced.
However, as seen below, the earliest date included is 1970 and some years do not have a significant amount of data. Thus, the data is not representative of each year within our sample and this should be considered when interpreting the results. We should also ensure to not extrapolate outside of this year range when calculating predictions.
movies%>%
group_by(thtr_rel_year)%>%
summarise(count = n())%>%
ggplot(aes(thtr_rel_year, count))+
geom_col(col="black", fill = "dark red", width = 1)+
geom_text(aes(label = count), nudge_y = 3, size = 3)+
theme_few()+
theme(axis.text.y = element_blank(),
axis.ticks.y = element_blank())+
labs(x = NULL,
y = NULL,
title = "Number of movies included within each year")

causality
Due to the observational nature of the study, no random assignment was used (test/control group), and hence causality cannot be inferred.
Part 2: Research question
What are the most important factors in determining the IMDB rating of a movie and can we use a multiple linear regression model to predict this rating?
The ability to predict ratings based on film metrics could help:
- understand the popularity of a movie before the full ratings are generated
- inform us if a movie is performing better or worse than expected
- provide insight into which areas to focus for the most desirable outcome
Part 3: Exploratory data analysis (EDA)
Collinearity and Parsimony
We can observe high correlations between our various ratings (IMDB rating, audience score and critics score). We should consider only keeping one of our variables for our final model, but we will explore all of them throughout our EDA.
There’s also a high correlation between theatre release year and DVD release year so we should only choose to include one. With the current trend of online streaming (ie. Netflix, Hulu, Amazon), physical DVDs are not as relevant and we can choose to exclude the DVD variables in favour of the theatre ones.
#select all to start
raw_data_corr <- select_if(movies, is.numeric)
# Compute a correlation matrix
corr <- round(cor(raw_data_corr, use="complete.obs"),2)
# Compute a matrix of correlation p-values
p.mat <- cor_pmat(raw_data_corr)
# Visualize the correlation matrix
ggcorrplot(corr, method = "square",
ggtheme = ggthemes::theme_few,
#title = "We can observe some clear patterns",
outline.col = "black",
colors = c("blue","white", "red"),
lab = TRUE,
lab_size = 2.5,
digits = 2,
type = "lower",
legend = "",
tl.cex = 8,
#show insignificant ones as blank
p.mat = p.mat,
hc.order = TRUE,
insig = "blank")

movies <- movies%>%
select(-dvd_rel_year, -dvd_rel_month, -dvd_rel_day)
Which types of film are included in our analysis?
We can see that the majority of the movies were within the Feature Film category. Given that Paramount operates in this area (rather than documentaries or TV shows), we will also focus our analysis/model on this category.
movies%>%
group_by(title_type)%>%
summarise(count = n())%>%
mutate(prop = round(count/sum(count)*100,0))%>%
ggplot(aes(title_type, prop))+
geom_col(col="black", fill = "dark red")+
geom_text(aes(label = paste(count, " - (", prop, "%)", sep = "")), nudge_y = 5, size = 5)+
theme_few()+
theme(axis.text.y = element_blank(),
axis.ticks.y = element_blank())+
labs(x = NULL,
y = NULL)

movies <- movies%>%
filter(title_type == "Feature Film")%>%
select(-title_type)
Which genres are included in our analysis?
The majority of our data contains Drama movies(51%), followed by Comedy(14%) and Action and Adventure(11%). We can see that we still have a few documentaries left, even though we removed them based on type. We will also remove this subset for the same reason as before.
movie_genre <- movies%>%
group_by(genre)%>%
summarise(count = n())%>%
mutate(proportion = round(count/sum(count)*100,1))%>%
arrange(desc(count))
movie_genre%>%
kbl(caption = "Summary of movie genres")%>%
kable_paper("hover", full_width = F)
Summary of movie genres
|
genre
|
count
|
proportion
|
|
Drama
|
301
|
50.9
|
|
Comedy
|
85
|
14.4
|
|
Action & Adventure
|
65
|
11.0
|
|
Mystery & Suspense
|
59
|
10.0
|
|
Horror
|
23
|
3.9
|
|
Other
|
15
|
2.5
|
|
Art House & International
|
14
|
2.4
|
|
Animation
|
9
|
1.5
|
|
Science Fiction & Fantasy
|
9
|
1.5
|
|
Musical & Performing Arts
|
8
|
1.4
|
|
Documentary
|
3
|
0.5
|
movies <- movies%>%
filter(genre != "Documentary")
Are the IMDB ratings impacted by the genre?
We can observe significant differences between the various genres and metrics such as variance, medians, range and outliers.
ggplot(movies, aes(genre, imdb_rating, col = genre))+
geom_boxplot(show.legend = FALSE)+
geom_jitter(alpha = 0.1, show.legend = FALSE)+
coord_flip()+
labs(y = "IMDB rating")+
theme_few()+
labs(x=NULL)

Is there an association between the IMDB rating and the total amount of IMDB votes?
The high-performing movies (as measured by IMDB rating) also have a higher number of votes. This trend seems exponential towards the higher IMDB ratings/votes, where the increase in total number of votes is much higher than in the low/medium ranges.
movies%>%
ggplot(aes(imdb_rating, imdb_num_votes))+
geom_jitter(width=0.1, height = 0.1, alpha = 0.5)+
geom_smooth(se = FALSE)+
theme_few()+
labs(x = "IMDB rating",
y = "Total IMDB votes")+
theme(legend.position = "none")

Do movie critics and audiences share the same taste in movies?
Judging by the variances in our scatter plots, we can observe fairly large discrepancies between how audiences and critics perceive movies. This is even more apparent in genres such as Action & Adventure and Comedy, where audiences tend to give much higher ratings than the critics.
movies%>%
ggplot(aes(audience_score, critics_score, col = genre))+
geom_jitter(width=0.1, height = 0.1, show.legend = FALSE)+
facet_wrap(.~genre)+
theme_few()+
annotate("segment", x=-Inf, xend=Inf, y=-Inf, yend=Inf, alpha = 0.5, lty = 2)+
theme(legend.position = "none")+
labs(x = "Audience score",
y = "Critics score")

We can focus more on these differences by looking in average scores for each genre. Below, we can observe very large differences between the various genres.
movies %>%
select(genre, audience_score, critics_score)%>%
group_by(genre)%>%
summarise(audience_score = mean(audience_score),
critics_score = mean(critics_score))%>%
mutate(difference_score = round((audience_score - critics_score), 1),
status = ifelse(abs(difference_score) <=3, "good (lower than 3)",
ifelse(abs(difference_score) <=5, "ok (between 3 and 5)", "bad (higher than 5)")))%>%
#create plot
ggplot(aes(reorder(genre, difference_score), difference_score, fill = status))+
geom_col(col = "black")+
scale_fill_manual(values = c("dark red", "#009E73", "gold3"))+
scale_colour_manual(values = c("dark red", "#009E73", "gold3"))+
geom_label(aes(genre, difference_score + ifelse(difference_score >= 0, +0.2, -0.2), label = difference_score), show.legend = FALSE, size = 3, fill = "white")+
labs(x=NULL,
y="Points disagreement",
title = "Rating disagreement between critics and audiences",
subtitle = "A positive score means the audience rated higher than critics",
fill = "Status")+
theme(legend.position = "top",
axis.ticks.x = element_blank(),
axis.text.x = element_blank())+
coord_flip()+
theme_few()

Is there an association between the year a movie was released in and the IMDB rating?
Given that we have the number of votes for each IMDB rating, we will use a weighted mean for this comparison.
While the total number of votes increased, as shown by the size of the points, we can see that the overall rating was fairly consistent. Again, to note the relatively low sample size of movies released before ~1990.
movies%>%
group_by(thtr_rel_year)%>%
summarise(imdb_wmean = weighted.mean(imdb_rating, imdb_num_votes),
count = n(),
votes = sum(imdb_num_votes))%>%
ggplot(aes(thtr_rel_year, imdb_wmean))+
geom_point(aes(size = votes), show.legend = FALSE)+
geom_line()+
coord_cartesian(ylim = c(0,10))+
labs(x = NULL,
y = "IMDB rating",
subtitle = "Size of point shows the relative sample of number of votes within each year")+
theme_few()

Are there any associations between the IMDB rating and the month of release?
It seems that the release dates are fairly equal distributed across the year (width of the bar) as well as equal in variance. Thus, we can say that it looks like these factors are independent of each other.
movies%>%
mutate(thtr_rel_month = as.factor(thtr_rel_month))%>%
ggplot(aes(thtr_rel_month, imdb_rating, col = thtr_rel_month))+
geom_boxplot(aes(group = thtr_rel_month), varwidth = TRUE, show.legend = FALSE)+
geom_jitter(alpha = 0.1, show.legend = FALSE)+
labs(x = "Month",
y = "IMDB rating")+
theme_few()

Is there an association between the day of the week a movie was released and the IMDB rating?
Both the boxplot and table below show that almost 75% of movie releases happen on a Friday and 11% on a Wednesday. An squal split of around 2-3% each happen on the other days. While the sample sizes are different across the various weekdays, there doesn’t seem to be a clear trend regarding the IMDB rating. Both audiences and critics tend to agree that movies released on Monday, Tuesday and Friday perform worse than the rest.
day_of_week <- movies%>%
mutate(date = make_date(thtr_rel_year, thtr_rel_month, thtr_rel_day),
wday = weekdays.Date(date),
wday_num = wday(date, week_start = 1))%>%
group_by(wday, wday_num)%>%
summarise(count = n(),
votes = round(mean(imdb_num_votes)),
imdb_wmean = weighted.mean(imdb_rating, imdb_num_votes),
audience_score = round(mean(audience_score),1),
critics_score = round(mean(critics_score),1),
imdb_wmean = round(imdb_wmean, 1))%>%
ungroup()%>%
mutate(prop = round(count/sum(count)*100,1))%>%
arrange(wday_num)
#add the weekday column to our model
movies <- movies%>%
mutate(date = make_date(thtr_rel_year, thtr_rel_month, thtr_rel_day),
wday = as.factor(weekdays.Date(date)),
wday_num = wday(date, week_start = 1))%>%
select(-date)
ggplot(movies, aes(reorder(wday,wday_num), imdb_rating, col = wday))+
geom_boxplot(show.legend = FALSE, varwidth = TRUE)+
geom_jitter(alpha = 0.1, show.legend = FALSE)+
labs(x = NULL,
y = "IMDB rating")+
theme_few()

day_of_week%>%
kbl(caption = "Proportion of releases by day of week")%>%
kable_paper("hover", full_width = F)
Proportion of releases by day of week
|
wday
|
wday_num
|
count
|
votes
|
imdb_wmean
|
audience_score
|
critics_score
|
prop
|
|
Monday
|
1
|
12
|
35906
|
7.0
|
57.8
|
52.1
|
2.0
|
|
Tuesday
|
2
|
20
|
104076
|
8.1
|
58.1
|
57.3
|
3.4
|
|
Wednesday
|
3
|
65
|
62649
|
7.3
|
67.4
|
65.7
|
11.1
|
|
Thursday
|
4
|
23
|
54167
|
6.9
|
66.2
|
65.4
|
3.9
|
|
Friday
|
5
|
430
|
65142
|
7.1
|
58.8
|
51.2
|
73.1
|
|
Saturday
|
6
|
20
|
43208
|
7.3
|
67.1
|
71.9
|
3.4
|
|
Sunday
|
7
|
18
|
22631
|
7.1
|
62.4
|
68.6
|
3.1
|
Does the runtime of the movie affect the IMDB rating?
We can see a slight trend where movies of a longer length correlate with a higher IMDB rating. However, this is not causal and it could be that this is an indirect effect of the genre of the movie (and thus, longer movies are of a favourable genre).
ggplot(movies, aes(runtime, imdb_rating))+
geom_jitter(width = 0.1, height = 0.1, alpha = 0.75)+
geom_smooth(se=FALSE)+
theme_few()+
labs(x = "Runtime (min)",
y = "IMDB rating")

Where does Paramount Pictures rank amogst the various other studios?
Based on movie averages, Paramount Pictures is ranked somewhere at the top, based on the IMDB rating/number of total votes and just above average regarding audience ratings.
studios <- movies%>%
group_by(studio)%>%
summarise(imdb_wmean = weighted.mean(imdb_rating, imdb_num_votes),
audience_score = mean(audience_score, na.rm = TRUE),
count = n(),
avg_votes = sum(imdb_num_votes)/count)
paramount_studio <- studios%>%
filter(studio == "Paramount Pictures")
ggplot()+
geom_point(data = studios, aes(audience_score, imdb_wmean, size = avg_votes), show.legend = FALSE, alpha = 0.6)+
geom_text(data = paramount_studio, aes(audience_score, imdb_wmean, label = "Paramount"), col = "red", size = 5, nudge_y = 0.3)+
geom_point(data = paramount_studio, aes(audience_score, imdb_wmean), col = "red", size = 3.7)+
labs(x = "Audience score",
y = "IMDB rating",
subtitle = "Size of point shows the relative sample of number of votes within each year (average per studio)")+
theme_few()

Is there an association between the type of an award a movie receives and the rating?
We can notice significant differences for the bottom three awards, but not nothing significant between those that received the top 3 awards in the below boxplot.
awards <- movies%>%
select(audience_score, critics_score, imdb_rating, imdb_num_votes, best_pic_nom:top200_box)%>%
gather(Award, Status, -audience_score, -critics_score, -imdb_rating, -imdb_num_votes)
ggplot(awards, aes(Status, imdb_rating, col = Status))+
geom_boxplot()+
theme_few()+
labs(col = "Award received",
x = NULL,
y = "IMDB rating")+
facet_wrap(.~Award)+
theme(legend.position = "top")

The same trend can be seen below where movies that have received the bottom 3 awards tend to perform better than those who have not on either movie rating score.
award_yes <- awards%>%
filter(Status == "yes")
ggplot(awards, aes(critics_score, imdb_rating, col = Status))+
geom_point(alpha = 0.50)+
geom_point(data = award_yes, aes(critics_score, imdb_rating), col = "dark red")+
theme_few()+
scale_colour_manual(values = c("gold3", "dark red"))+
labs(col = "Award received",
x = "Critics score",
y = "IMDB rating")+
facet_wrap(.~Award)+
theme(legend.position = "top")

We can also spot a trend where, generally speaking, the rarer the award, the higher the chance it would impact any of the ratings in a favourable way.
awards_table <- awards%>%
group_by(Award, Status)%>%
summarise(count = n(),
audience_score = round(mean(audience_score),1),
critics_score = round(mean(critics_score),1),
imdb_rating = round(weighted.mean(imdb_rating, imdb_num_votes),1),
imdb_num_votes = round(mean(imdb_num_votes),0))%>%
mutate(proportion = round(count/sum(count)*100,1))%>%
arrange(proportion)
awards_table%>%
kbl(caption = "Summary of awards and movie ratings")%>%
kable_paper("hover", full_width = F)
Summary of awards and movie ratings
|
Award
|
Status
|
count
|
audience_score
|
critics_score
|
imdb_rating
|
imdb_num_votes
|
proportion
|
|
best_pic_win
|
yes
|
7
|
84.7
|
91.3
|
8.1
|
399420
|
1.2
|
|
top200_box
|
yes
|
15
|
74.5
|
75.5
|
7.4
|
269876
|
2.6
|
|
best_pic_nom
|
yes
|
22
|
85.3
|
87.5
|
8.1
|
253804
|
3.7
|
|
best_dir_win
|
yes
|
43
|
69.5
|
72.1
|
7.7
|
137816
|
7.3
|
|
best_actress_win
|
yes
|
70
|
63.6
|
61.7
|
7.5
|
98932
|
11.9
|
|
best_actor_win
|
yes
|
91
|
62.7
|
60.2
|
7.4
|
82086
|
15.5
|
|
best_actor_win
|
no
|
497
|
60.0
|
53.9
|
7.1
|
59644
|
84.5
|
|
best_actress_win
|
no
|
518
|
60.0
|
53.9
|
7.1
|
58278
|
88.1
|
|
best_dir_win
|
no
|
545
|
59.7
|
53.5
|
7.1
|
57224
|
92.7
|
|
best_pic_nom
|
no
|
566
|
59.4
|
53.6
|
7.0
|
55705
|
96.3
|
|
top200_box
|
no
|
573
|
60.0
|
54.3
|
7.2
|
57705
|
97.4
|
|
best_pic_win
|
no
|
581
|
60.1
|
54.4
|
7.1
|
59066
|
98.8
|
Part 4: Modeling
Feature selection
We will be excluding the following variables from our full model:
- title, studio as they might cause our model to overfit
- critics/audience ratings and scores as they are highly correlated with our predicted variables (IMDB rating)
- number of IMDB ratings as it would act as a proxy for the IMDB rating (they’re also correlated)
- DVD release year, month and day for reasons mention before (high correlation with theatre release dates and lack of importance given current streaming trends)
Feature engineering: we also added day of the week to see if there are any trends
Selection method
We chose a backward p value adjustment to our model, given the context of the study where we could not use an automated way to reduce variables. An R adjustment would be incredibly time-consuming given the manual methodology and prone to human error. Furthermore, a p value adjustment would ensure that the factors included are significant (which is not necessarily true in an R adjustment).
model_initial <- lm(imdb_rating ~ genre + runtime + mpaa_rating + thtr_rel_year + thtr_rel_month + thtr_rel_day + best_pic_nom + best_pic_win + best_actor_win + best_actress_win + best_dir_win + top200_box + wday, data=movies)
tidy(model_initial)%>%
arrange(term, p.value)%>%
kbl(caption = "Initial model - summary")%>%
kable_paper("hover", full_width = F)
Initial model - summary
|
term
|
estimate
|
std.error
|
statistic
|
p.value
|
|
(Intercept)
|
8.1742438
|
7.9644193
|
1.0263452
|
0.3051744
|
|
best_actor_winyes
|
-0.0711392
|
0.1125253
|
-0.6322066
|
0.5275113
|
|
best_actress_winyes
|
0.0044981
|
0.1237113
|
0.0363600
|
0.9710083
|
|
best_dir_winyes
|
0.3188387
|
0.1590998
|
2.0040174
|
0.0455519
|
|
best_pic_nomyes
|
0.8816059
|
0.2389923
|
3.6888459
|
0.0002474
|
|
best_pic_winyes
|
-0.1331604
|
0.4210997
|
-0.3162206
|
0.7519535
|
|
genreAnimation
|
-0.1133041
|
0.3741316
|
-0.3028455
|
0.7621207
|
|
genreArt House & International
|
0.5010347
|
0.2879901
|
1.7397636
|
0.0824529
|
|
genreComedy
|
-0.0658930
|
0.1555755
|
-0.4235434
|
0.6720624
|
|
genreDrama
|
0.5711587
|
0.1325883
|
4.3077606
|
0.0000195
|
|
genreHorror
|
-0.1636790
|
0.2321635
|
-0.7050161
|
0.4810949
|
|
genreMusical & Performing Arts
|
0.9702023
|
0.3466066
|
2.7991452
|
0.0053014
|
|
genreMystery & Suspense
|
0.4188761
|
0.1730444
|
2.4206272
|
0.0158125
|
|
genreOther
|
0.5762551
|
0.2713937
|
2.1233178
|
0.0341675
|
|
genreScience Fiction & Fantasy
|
-0.2579984
|
0.3285955
|
-0.7851551
|
0.4326965
|
|
mpaa_ratingNC-17
|
-0.3952647
|
0.7098442
|
-0.5568330
|
0.5778652
|
|
mpaa_ratingPG
|
-0.5859253
|
0.2845822
|
-2.0588966
|
0.0399685
|
|
mpaa_ratingPG-13
|
-0.7732551
|
0.2979153
|
-2.5955536
|
0.0096929
|
|
mpaa_ratingR
|
-0.4397807
|
0.2897715
|
-1.5176811
|
0.1296621
|
|
mpaa_ratingUnrated
|
0.0134913
|
0.3910641
|
0.0344990
|
0.9724916
|
|
runtime
|
0.0124955
|
0.0027001
|
4.6277832
|
0.0000046
|
|
thtr_rel_day
|
0.0005832
|
0.0044814
|
0.1301413
|
0.8965016
|
|
thtr_rel_month
|
0.0042229
|
0.0113959
|
0.3705581
|
0.7111076
|
|
thtr_rel_year
|
-0.0015561
|
0.0039896
|
-0.3900363
|
0.6966588
|
|
top200_boxyes
|
0.5304606
|
0.2501291
|
2.1207471
|
0.0343843
|
|
wdayMonday
|
-0.1617262
|
0.2759457
|
-0.5860798
|
0.5580593
|
|
wdaySaturday
|
0.4156167
|
0.2156469
|
1.9273016
|
0.0544503
|
|
wdaySunday
|
0.2682264
|
0.2287683
|
1.1724810
|
0.2415052
|
|
wdayThursday
|
0.3603500
|
0.2023244
|
1.7810508
|
0.0754490
|
|
wdayTuesday
|
0.0488718
|
0.2158849
|
0.2263792
|
0.8209896
|
|
wdayWednesday
|
0.1893176
|
0.1287452
|
1.4704825
|
0.1419958
|
# removed best_actor_win
model_final <- lm(imdb_rating ~ genre + runtime + mpaa_rating + thtr_rel_year + thtr_rel_month + thtr_rel_day + best_pic_nom + best_pic_win + best_actress_win + best_dir_win + top200_box + wday, data=movies)
# removed best_actress_win
model_final <- lm(imdb_rating ~ genre + runtime + mpaa_rating + thtr_rel_year + thtr_rel_month + thtr_rel_day + best_pic_nom + best_pic_win + best_dir_win + top200_box + wday, data=movies)
# removed thtr_rel_day
model_final <- lm(imdb_rating ~ genre + runtime + mpaa_rating + thtr_rel_year + thtr_rel_month + best_pic_nom + best_pic_win + best_dir_win + top200_box + wday, data=movies)
# removed thtr_rel_month
model_final <- lm(imdb_rating ~ genre + runtime + mpaa_rating + thtr_rel_year + best_pic_nom + best_pic_win + best_dir_win + top200_box + wday, data=movies)
# removed thtr_rel_year
model_final <- lm(imdb_rating ~ genre + runtime + mpaa_rating + best_pic_nom + best_pic_win + best_dir_win + top200_box + wday, data=movies)
# removed best_pic_win
model_final <- lm(imdb_rating ~ genre + runtime + mpaa_rating + best_pic_nom + best_dir_win + top200_box + wday, data=movies)
Final model
Reason for excluding certain variables: following a backward model adjustment, the following variables were not proven to be significant and were excluded from the final model (in order of exclusion):
- best_actor_win
- best_actress_win
- thtr_rel_day
- thtr_rel_month
- thtr_rel_year
- best_pic_win
That leaves us with the following variables included in our final model:
- genre
- runtime
- mpaa_rating
- best_pic_nom
- best_dir_win
- top200_box
- weekday
Interpretation of our prediction model
Overall, we can see that the model was able to capture 26% of the variability in our data.
glance(model_final)%>%
kbl(caption = "Final model - overall summary")%>%
kable_paper("hover", full_width = F)
Final model - overall summary
|
r.squared
|
adj.r.squared
|
sigma
|
statistic
|
p.value
|
df
|
logLik
|
AIC
|
BIC
|
deviance
|
df.residual
|
nobs
|
|
0.2890144
|
0.2587059
|
0.9103221
|
9.535769
|
0
|
24
|
-766.3157
|
1584.631
|
1698.426
|
466.5504
|
563
|
588
|
At the coefficient level, we can see that all our included predictors were significant. The most significant predictor was runtime. This was followed by whether a movie was nominated for Best Picture as well as whether it belonged to the “Drama” genre.
We can conclude that with everything else held constant:
- for each minute of additional runtime, it is expected that the IMDB rating increases by 0.012 points
- a movie nominated for the Best Picture award is estimated to have a higher rating, on average, by 0.84 points
- a movie that won the Best Director award is predicted to have a higher rating, on average, by 0.30 points
- movies included in the top 200 box are estimated to be rated higher by 0.53 points
- a movie within the Drama genre is expected to score 0.57 points higher than an Action and Adventure movie (the intercept). Three other genres can also be estimated to have a significantly higher rating than the intercept, based on their coefficient and p-value:
- Musical & Performing Arts
- Mystery & Suspsense
- Other
- movies with an mpaa rating of PG and PG-13 are estimated to score lower than G rated movies by 0.59 and 0.80, respectively
- day of week was also significant. A movie released on a Saturday was predicted to score higher than the intercept (Friday) by 0.42 points
tidy(model_final)%>%
arrange(term, p.value)%>%
kbl(caption = "Final model - summary")%>%
kable_paper("hover", full_width = F)
Final model - summary
|
term
|
estimate
|
std.error
|
statistic
|
p.value
|
|
(Intercept)
|
5.1202358
|
0.3674164
|
13.9357829
|
0.0000000
|
|
best_dir_winyes
|
0.3074598
|
0.1516608
|
2.0272859
|
0.0431038
|
|
best_pic_nomyes
|
0.8476648
|
0.2101322
|
4.0339600
|
0.0000624
|
|
genreAnimation
|
-0.1310169
|
0.3679277
|
-0.3560942
|
0.7219034
|
|
genreArt House & International
|
0.5161796
|
0.2839500
|
1.8178537
|
0.0696178
|
|
genreComedy
|
-0.0659667
|
0.1536537
|
-0.4293205
|
0.6678543
|
|
genreDrama
|
0.5713490
|
0.1306699
|
4.3724595
|
0.0000146
|
|
genreHorror
|
-0.1514570
|
0.2296387
|
-0.6595445
|
0.5098159
|
|
genreMusical & Performing Arts
|
0.9816999
|
0.3446402
|
2.8484779
|
0.0045535
|
|
genreMystery & Suspense
|
0.4064704
|
0.1702345
|
2.3877091
|
0.0172826
|
|
genreOther
|
0.5816296
|
0.2678480
|
2.1714917
|
0.0303109
|
|
genreScience Fiction & Fantasy
|
-0.2464390
|
0.3258388
|
-0.7563218
|
0.4497726
|
|
mpaa_ratingNC-17
|
-0.4266973
|
0.7044137
|
-0.6057482
|
0.5449261
|
|
mpaa_ratingPG
|
-0.5940688
|
0.2825116
|
-2.1028121
|
0.0359255
|
|
mpaa_ratingPG-13
|
-0.7953364
|
0.2902341
|
-2.7403270
|
0.0063326
|
|
mpaa_ratingR
|
-0.4562930
|
0.2840804
|
-1.6062106
|
0.1087883
|
|
mpaa_ratingUnrated
|
-0.0221070
|
0.3768923
|
-0.0586561
|
0.9532468
|
|
runtime
|
0.0123815
|
0.0025315
|
4.8909967
|
0.0000013
|
|
top200_boxyes
|
0.5299325
|
0.2479966
|
2.1368538
|
0.0330402
|
|
wdayMonday
|
-0.1414877
|
0.2696405
|
-0.5247271
|
0.5999794
|
|
wdaySaturday
|
0.4245825
|
0.2098264
|
2.0234936
|
0.0434942
|
|
wdaySunday
|
0.2597699
|
0.2249641
|
1.1547171
|
0.2486962
|
|
wdayThursday
|
0.3673926
|
0.1997341
|
1.8394085
|
0.0663815
|
|
wdayTuesday
|
0.0494167
|
0.2117060
|
0.2334211
|
0.8155193
|
|
wdayWednesday
|
0.1969639
|
0.1272882
|
1.5473853
|
0.1223323
|
To note, however, that while our model performs well in the middle regions, it significantly over-predicts for low IMDB ratings and under-predicts for high IMDB ratings.
ggplot(model_final, aes(imdb_rating, .resid))+
geom_hline(yintercept = 0, alpha = 0.5, size = 3, color = "grey52")+
geom_jitter(alpha = 0.5, color = "blue", height = 0.1, width = 0.1)+
geom_smooth(method = "lm", lwd = 0.5, col = "red", se = FALSE)+
theme_few()+
labs(x = "IMDB rating",
y="Residuals")

Model diagnostics
1. linear relationship between each (numerical) explanatory variable and response
We only have one numerical variable (runtime) which is shown to have a linear relationship with our predictor variable (IMDB rating) by the random scatter in the below residual plot. However, to note that there weren’t many movies with a runtime of over 150 minutes.
ggplot(model_final, aes(runtime, .resid))+
geom_hline(yintercept = 0, alpha = 0.5, size = 3, color = "grey52")+
geom_point(alpha = 0.5, color = "blue")+
geom_smooth(method = "lm", lwd = 0.5, col = "red", se = FALSE)+
theme_few()+
labs(x = "Runtime",
y="Residuals")

2. nearly normal residuals with mean 0
Despite a slight skew to the left, the majority of our residuals within the below residual histogram are centered around the mean 0.
ggplot(model_final, aes(.resid))+
#geom_histogram(binwidth = 0.1, col = "black", fill = "blue")+
geom_histogram(aes(y=..density..), color="black", fill="white", lwd = 0.75) +
geom_density(alpha=0.2, fill="#FF6666") +
geom_vline(aes(xintercept=mean(.resid)), col = 'red', lwd = 1, lty = 2) +
labs(x="Residuals",
y= "Density")+
theme_few()

Similarly, the Normal probability plot of residuals (QQ plot) below shows a similar trend. Outside of the tail areas, we do not see any significant deviations from the mean.
ggplot(model_final, aes(sample=.resid))+
stat_qq()+
stat_qq_line()+
theme_few()+
theme(legend.position = "none")

3. constant variability of residuals
We can see that our residuals are equally variable for low and high values of the predicted response variable (IMDB rating).
ggplot(model_final, aes(.fitted, .resid))+
geom_hline(yintercept = 0, alpha = 0.5, size = 3, color = "grey52")+
geom_point(alpha = 0.5, color = "blue")+
geom_smooth(method = "lm", lwd = 0.5, col = "red", se = FALSE)+
theme_few()+
labs(x = "IMDB rating prediction",
y="Residuals")

We can also plot the absolute values of the residuals as seen below. This can be thought of the above plot folded in half. Thus, a fan shape in the above plot would look as a triangle in the below plot. This is not the case here, and thus, this condition is also met.
ggplot(model_final, aes(.fitted, abs(.resid)))+
geom_hline(yintercept = 0, alpha = 0.5, size = 3, color = "grey52")+
geom_point(alpha = 0.5, color = "blue")+
#geom_smooth(method = "lm", lwd = 0.5, col = "red", se = FALSE)+
theme_few()+
labs(x = "IMDB rating prediction",
y="Residuals")

4. independence of residuals (and hence observations)
No apparent trend which suggests independence from the order of data collection.
df <- augment(model_final)
ggplot(data=df, aes(x = 1:nrow(df), y = .resid)) +
labs(x = "Index",
y = "Residuals")+
geom_hline(yintercept = 0, alpha = 0.5, size = 3, color = "grey52", lty = 2)+
geom_hline(yintercept=0, col="red", linetype="dashed")+
geom_point(alpha = 0.5, color = "blue")+
geom_smooth(method = "lm", lwd = 0.5, col = "red", se = FALSE)+
theme_few()

Part 5: Prediction
Prediction and interpretation
Here are the details of the La La Land movie, a movie released in 2016.
Reference - IMDB, Oscars and Box Office Mojo official websites.
movie_lalaland <- data.frame("genre" = c("Musical & Performing Arts"),
"runtime" = c(128),
"best_dir_win" = "yes",
"best_pic_nom" = "yes",
"mpaa_rating" = "PG-13",
"wday" = "Friday",
"top200_box" = "yes")
movie_lalaland%>%
kbl(caption = "Movie data")%>%
kable_paper("hover", full_width = F)
Movie data
|
genre
|
runtime
|
best_dir_win
|
best_pic_nom
|
mpaa_rating
|
wday
|
top200_box
|
|
Musical & Performing Arts
|
128
|
yes
|
yes
|
PG-13
|
Friday
|
yes
|
Given this data, the model predicted an IMDB rating of 8.58. The lower and upper interval values tell us that the IMDB rating for La La Land is in the interval (7.65 and 9.50) with 95% probability.
pred_lalaland <- predict(model_final, newdata = movie_lalaland, interval = "confidence")
pred_lalaland%>%
kbl(caption = "Predictions")%>%
kable_paper("hover", full_width = F)
Predictions
|
fit
|
lwr
|
upr
|
|
8.576486
|
7.650619
|
9.502354
|
Lastly, we can plot this data to be able to visually interpret it. We can see that it was relatively close to the prediction and within the predicted interval.
ggplot(movies, aes(imdb_rating, imdb_num_votes))+
geom_jitter(alpha = 0.5, size = 0.75, width = 0.1, height = 0.1)+
geom_smooth(se=FALSE)+
#plot prediction
geom_point(aes(x=8.576486 , y = 513225), size = 5, col = "blue")+
geom_text(aes(x=8.576486 , y = 513225), label = "Prediction", nudge_x = 0.25, nudge_y = -75000)+
#correct value
geom_point(aes(x=8.0, y = 513225), size = 5, col = "red")+
geom_text(aes(x=8.0, y = 513225), label = "Actual", nudge_y = -55000)+
#confidence interval
geom_errorbar(aes(xmax = 9.502354, xmin = 7.650619, x =8.576486, y=513225), width = 0.5)+
geom_text(aes(x=9.2, y = 513225), label = "(CI)", col = "black", nudge_y = 48000)+
theme_few()+
labs(x = "IMDB rating",
y = "IMDB number of votes")

LS0tDQogIG91dHB1dDoNCiAgICBodG1sX2RvY3VtZW50Og0KICAgICAgICB0b2M6IHRydWUNCiAgICAgICAgdG9jX2Zsb2F0OiBmYWxzZQ0KICAgICAgICB0b2NfZGVwdGg6IDQNCiAgICAgICAgbnVtYmVyX3NlY3Rpb25zOiBmYWxzZQ0KICANCiAgICAgICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgDQogICAgICAgIGZpZ193aWR0aDogOQ0KICAgICAgICBmaWdfaGVpZ2h0OiA0DQogICAgICAgIGZpZ19hbGlnbjogImNlbnRlciINCiAgICAgICAgDQogICAgICAgIGhpZ2hsaWdodDogcHlnbWVudHMNCiAgICAgICAgdGhlbWU6IGNlcnVsZWFuDQogICAgICAgIA0KICAgICAgICBrZWVwX21kOiB0cnVlDQogICAgICAgIA0KICAgIHRpdGxlOiAiSU1EQiByYXRpbmcgcHJlZGljdGlvbiINCiAgICBzdWJ0aXRsZTogIlZhcmlhYmxlIGltcG9ydGFuY2UgYW5kIHByZWRpY3Rpb24iDQogICAgYXV0aG9yOiAiYnkgUGV0ZXIgSG9udGFydSINCi0tLQ0KIA0KIyMgQmFja2dyb3VuZA0KDQoqKldoYXQgYXJlIHRoZSBtb3N0IGltcG9ydGFudCBmYWN0b3JzIGluIGRldGVybWluaW5nIHRoZSBJTURCIHJhdGluZyBvZiBhIG1vdmllIGFuZCBjYW4gd2UgdXNlIGEgbXVsdGlwbGUgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgdG8gcHJlZGljdCB0aGlzIHJhdGluZz8qKg0KDQpUaGlzIHByb2plY3QgaXMgYmFzZWQgb24gYSBmaWN0aXRpb3VzIHNjZW5hcmlvIHdoZXJlIEnigJl2ZSBiZWVuIGhpcmVkIGFzIGEgZGF0YSBzY2llbnRpc3QgYXQgUGFyYW1vdW50ICBQaWN0dXJlcy4gVGhlIGRhdGEgcHJlc2VudHMgbnVtZXJvdXMgdmFyaWFibGVzIG9uIG1vdmllcyBzdWNoIGFzIGF1ZGllbmNlL2NyaXRpYyByYXRpbmdzLCBudW1iZXIgb2Ygdm90ZXMsIHJ1bnRpbWUsIGdlbnJlLCBldGMuIFBhcmFtb3VudCBQaWN0dXJlcyBpcyBsb29raW5nIHRvIGdhdGhlciBpbnNpZ2h0cyBpbnRvIGRldGVybWluaW5nIHRoZSBhY2NsYWltIG9mIGEgZmlsbSBhbmQgb3RoZXIgbm92ZWwgcGF0dGVybnMgb3IgaWRlYXMuIFRoZSBkYXRhIHNldCBpcyBjb21wcmlzZWQgb2YgNjUxIHJhbmRvbWx5IHNhbXBsZWQgbW92aWVzIHByb2R1Y2VkIGFuZCByZWxlYXNlZCBiZWZvcmUgMjAxNi4NCg0KYGBge3IgbG9hZC1wYWNrYWdlcywgbWVzc2FnZT1GQUxTRSwgaW5jbHVkZT1GQUxTRX0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdnbW9zYWljKQ0KbGlicmFyeShnZ2NvcnJwbG90KQ0KbGlicmFyeShnZ3RoZW1lcykNCmxpYnJhcnkoYnJvb20pDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkoc3RhdHNyKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGthYmxlRXh0cmEpDQpsaWJyYXJ5KGdncHVicikNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShjYXIpDQpsaWJyYXJ5KGJyb29tKQ0KbGlicmFyeShxdWFudHJlZykNCg0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICAgIGVjaG8gPSBUUlVFLCAjIHNob3cgYWxsIGNvZGUNCiAgICB0aWR5ID0gRkFMU0UsICMgY2xlYW5lciBjb2RlIHByaW50aW5nDQogICAgc2l6ZSA9ICJzbWFsbCIsICMgc21hbGxlciBjb2RlDQogICAgDQogICAgZmlnLnBhdGggPSAiZmlndXJlcy8iLCAjZ3JhcGhpY3MgbG9jYXRpb24NCiAgICBvdXQud2lkdGggPSAiMTAwJSIsDQoNCiAgICBtZXNzYWdlID0gRkFMU0UsDQogICAgd2FybmluZyA9IEZBTFNFDQogICAgKQ0KDQpsb2FkKCJtb3ZpZXMuUmRhdGEiKQ0KDQojcmVtb3ZlIHNvbWUgY29sdW1ucyB0aGF0IGFyZSBub3QgbmVlZGVkIA0KbW92aWVzIDwtIG1vdmllcyU+JQ0KICBzZWxlY3QoLWltZGJfdXJsLCAtcnRfdXJsLCAtZGlyZWN0b3I6LWFjdG9yNSkNCmBgYA0KDQoqICogKg0KDQojIyBQYXJ0IDE6IERhdGENCg0KIyMjIGdlbmVyYWJpemFiaWxpdHkNCg0KVGhlIGRhdGFzZXQgaXMgY29tcHJpc2VkIG9mIDY1MSByYW5kb21seSBzYW1wbGVkIG1vdmllcyBwcm9kdWNlZCBhbmQgcmVsZWFzZWQgYmVmb3JlIDIwMTYuIFRoZXJlZm9yZSxkdWUgdG8gdGhlIHJhbmRvbSBzYW1wbGluZywgaXQgY2FuIGJlIGFzc3VtZWQgdGhhdCB0aGUgZGF0YSBpcyByZXByZXNlbnRhdGl2ZSBvZiBhbGwgbW92aWVzIHByb2R1Y2VkLiANCg0KSG93ZXZlciwgYXMgc2VlbiBiZWxvdywgdGhlIGVhcmxpZXN0IGRhdGUgaW5jbHVkZWQgaXMgMTk3MCBhbmQgc29tZSB5ZWFycyBkbyBub3QgaGF2ZSBhIHNpZ25pZmljYW50IGFtb3VudCBvZiBkYXRhLiBUaHVzLCB0aGUgZGF0YSBpcyBub3QgcmVwcmVzZW50YXRpdmUgb2YgZWFjaCB5ZWFyIHdpdGhpbiBvdXIgc2FtcGxlIGFuZCB0aGlzIHNob3VsZCBiZSBjb25zaWRlcmVkIHdoZW4gaW50ZXJwcmV0aW5nIHRoZSByZXN1bHRzLiBXZSBzaG91bGQgYWxzbyBlbnN1cmUgdG8gbm90IGV4dHJhcG9sYXRlIG91dHNpZGUgb2YgdGhpcyB5ZWFyIHJhbmdlIHdoZW4gY2FsY3VsYXRpbmcgcHJlZGljdGlvbnMuDQoNCmBgYHtyfQ0KbW92aWVzJT4lDQogIGdyb3VwX2J5KHRodHJfcmVsX3llYXIpJT4lDQogIHN1bW1hcmlzZShjb3VudCA9IG4oKSklPiUNCiAgDQogIGdncGxvdChhZXModGh0cl9yZWxfeWVhciwgY291bnQpKSsNCiAgZ2VvbV9jb2woY29sPSJibGFjayIsIGZpbGwgPSAiZGFyayByZWQiLCB3aWR0aCA9IDEpKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gY291bnQpLCBudWRnZV95ID0gMywgc2l6ZSA9IDMpKw0KICB0aGVtZV9mZXcoKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSkrDQogIGxhYnMoeCA9IE5VTEwsDQogICAgICAgeSA9IE5VTEwsDQogICAgICAgdGl0bGUgPSAiTnVtYmVyIG9mIG1vdmllcyBpbmNsdWRlZCB3aXRoaW4gZWFjaCB5ZWFyIikNCmBgYA0KDQojIyMgY2F1c2FsaXR5IA0KDQpEdWUgdG8gdGhlIG9ic2VydmF0aW9uYWwgbmF0dXJlIG9mIHRoZSBzdHVkeSwgbm8gcmFuZG9tIGFzc2lnbm1lbnQgd2FzIHVzZWQgKHRlc3QvY29udHJvbCBncm91cCksIGFuZCBoZW5jZSBjYXVzYWxpdHkgY2Fubm90IGJlIGluZmVycmVkLg0KDQoqICogKg0KDQojIyBQYXJ0IDI6IFJlc2VhcmNoIHF1ZXN0aW9uDQoNCioqV2hhdCBhcmUgdGhlIG1vc3QgaW1wb3J0YW50IGZhY3RvcnMgaW4gZGV0ZXJtaW5pbmcgdGhlIElNREIgcmF0aW5nIG9mIGEgbW92aWUgYW5kIGNhbiB3ZSB1c2UgYSBtdWx0aXBsZSBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCB0byBwcmVkaWN0IHRoaXMgcmF0aW5nPyoqDQoNClRoZSBhYmlsaXR5IHRvIHByZWRpY3QgcmF0aW5ncyBiYXNlZCBvbiBmaWxtIG1ldHJpY3MgY291bGQgaGVscDoNCg0KLSB1bmRlcnN0YW5kIHRoZSBwb3B1bGFyaXR5IG9mIGEgbW92aWUgYmVmb3JlIHRoZSBmdWxsIHJhdGluZ3MgYXJlIGdlbmVyYXRlZA0KLSBpbmZvcm0gdXMgaWYgYSBtb3ZpZSBpcyBwZXJmb3JtaW5nIGJldHRlciBvciB3b3JzZSB0aGFuIGV4cGVjdGVkDQotIHByb3ZpZGUgaW5zaWdodCBpbnRvIHdoaWNoIGFyZWFzIHRvIGZvY3VzIGZvciB0aGUgbW9zdCBkZXNpcmFibGUgb3V0Y29tZQ0KDQoqICogKg0KDQojIyBQYXJ0IDM6IEV4cGxvcmF0b3J5IGRhdGEgYW5hbHlzaXMgKEVEQSkNCg0KIyMjIENvbGxpbmVhcml0eSBhbmQgUGFyc2ltb255DQoNCldlIGNhbiBvYnNlcnZlIGhpZ2ggY29ycmVsYXRpb25zIGJldHdlZW4gb3VyIHZhcmlvdXMgcmF0aW5ncyAoSU1EQiByYXRpbmcsIGF1ZGllbmNlIHNjb3JlIGFuZCBjcml0aWNzIHNjb3JlKS4gV2Ugc2hvdWxkIGNvbnNpZGVyIG9ubHkga2VlcGluZyBvbmUgb2Ygb3VyIHZhcmlhYmxlcyBmb3Igb3VyIGZpbmFsIG1vZGVsLCBidXQgd2Ugd2lsbCBleHBsb3JlIGFsbCBvZiB0aGVtIHRocm91Z2hvdXQgb3VyIEVEQS4NCg0KVGhlcmUncyBhbHNvIGEgaGlnaCBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZWF0cmUgcmVsZWFzZSB5ZWFyIGFuZCBEVkQgcmVsZWFzZSB5ZWFyIHNvIHdlIHNob3VsZCBvbmx5IGNob29zZSB0byBpbmNsdWRlIG9uZS4gV2l0aCB0aGUgY3VycmVudCB0cmVuZCBvZiBvbmxpbmUgc3RyZWFtaW5nIChpZS4gTmV0ZmxpeCwgSHVsdSwgQW1hem9uKSwgcGh5c2ljYWwgRFZEcyBhcmUgbm90IGFzIHJlbGV2YW50IGFuZCB3ZSBjYW4gY2hvb3NlIHRvIGV4Y2x1ZGUgdGhlIERWRCB2YXJpYWJsZXMgaW4gZmF2b3VyIG9mIHRoZSB0aGVhdHJlIG9uZXMuDQoNCmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTEwfQ0KI3NlbGVjdCBhbGwgdG8gc3RhcnQNCnJhd19kYXRhX2NvcnIgPC0gc2VsZWN0X2lmKG1vdmllcywgaXMubnVtZXJpYykgIA0KDQojIENvbXB1dGUgYSBjb3JyZWxhdGlvbiBtYXRyaXgNCmNvcnIgPC0gcm91bmQoY29yKHJhd19kYXRhX2NvcnIsIHVzZT0iY29tcGxldGUub2JzIiksMikNCg0KIyBDb21wdXRlIGEgbWF0cml4IG9mIGNvcnJlbGF0aW9uIHAtdmFsdWVzDQpwLm1hdCA8LSBjb3JfcG1hdChyYXdfZGF0YV9jb3JyKQ0KDQojIFZpc3VhbGl6ZSB0aGUgY29ycmVsYXRpb24gbWF0cml4DQpnZ2NvcnJwbG90KGNvcnIsIG1ldGhvZCA9ICJzcXVhcmUiLCANCiAgICAgICAgICAgZ2d0aGVtZSA9IGdndGhlbWVzOjp0aGVtZV9mZXcsIA0KICAgICAgICAgICAjdGl0bGUgPSAiV2UgY2FuIG9ic2VydmUgc29tZSBjbGVhciBwYXR0ZXJucyIsDQogICAgICAgICAgIA0KICAgICAgICAgICBvdXRsaW5lLmNvbCA9ICJibGFjayIsDQogICAgICAgICAgIGNvbG9ycyA9IGMoImJsdWUiLCJ3aGl0ZSIsICJyZWQiKSwNCiAgICAgICAgICAgDQogICAgICAgICAgIGxhYiA9IFRSVUUsDQogICAgICAgICAgIGxhYl9zaXplID0gMi41LA0KICAgICAgICAgICBkaWdpdHMgPSAyLA0KICAgICAgICAgICANCiAgICAgICAgICAgdHlwZSA9ICJsb3dlciIsDQogICAgICAgICAgIGxlZ2VuZCA9ICIiLA0KICAgICAgICAgICB0bC5jZXggPSA4LA0KICAgICAgICAgICAjc2hvdyBpbnNpZ25pZmljYW50IG9uZXMgYXMgYmxhbmsNCiAgICAgICAgICAgcC5tYXQgPSBwLm1hdCwNCiAgICAgICAgICAgaGMub3JkZXIgPSBUUlVFLA0KICAgICAgICAgICBpbnNpZyA9ICJibGFuayIpDQoNCm1vdmllcyA8LSBtb3ZpZXMlPiUNCiAgc2VsZWN0KC1kdmRfcmVsX3llYXIsIC1kdmRfcmVsX21vbnRoLCAtZHZkX3JlbF9kYXkpDQpgYGANCg0KIyMjIFdoaWNoIHR5cGVzIG9mIGZpbG0gYXJlIGluY2x1ZGVkIGluIG91ciBhbmFseXNpcz8NCg0KV2UgY2FuIHNlZSB0aGF0IHRoZSBtYWpvcml0eSBvZiB0aGUgbW92aWVzIHdlcmUgd2l0aGluIHRoZSBGZWF0dXJlIEZpbG0gY2F0ZWdvcnkuIEdpdmVuIHRoYXQgUGFyYW1vdW50IG9wZXJhdGVzIGluIHRoaXMgYXJlYSAocmF0aGVyIHRoYW4gZG9jdW1lbnRhcmllcyBvciBUViBzaG93cyksIHdlIHdpbGwgYWxzbyBmb2N1cyBvdXIgYW5hbHlzaXMvbW9kZWwgb24gdGhpcyBjYXRlZ29yeS4NCg0KYGBge3J9DQptb3ZpZXMlPiUNCiAgZ3JvdXBfYnkodGl0bGVfdHlwZSklPiUNCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSU+JQ0KICBtdXRhdGUocHJvcCA9IHJvdW5kKGNvdW50L3N1bShjb3VudCkqMTAwLDApKSU+JQ0KICANCiAgZ2dwbG90KGFlcyh0aXRsZV90eXBlLCBwcm9wKSkrDQogIGdlb21fY29sKGNvbD0iYmxhY2siLCBmaWxsID0gImRhcmsgcmVkIikrDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZShjb3VudCwgIiAtICgiLCBwcm9wLCAiJSkiLCBzZXAgPSAiIikpLCBudWRnZV95ID0gNSwgc2l6ZSA9IDUpKw0KICB0aGVtZV9mZXcoKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSkrDQogIGxhYnMoeCA9IE5VTEwsDQogICAgICAgeSA9IE5VTEwpDQoNCm1vdmllcyA8LSBtb3ZpZXMlPiUNCiAgZmlsdGVyKHRpdGxlX3R5cGUgPT0gIkZlYXR1cmUgRmlsbSIpJT4lDQogIHNlbGVjdCgtdGl0bGVfdHlwZSkNCmBgYA0KDQojIyMgV2hpY2ggZ2VucmVzIGFyZSBpbmNsdWRlZCBpbiBvdXIgYW5hbHlzaXM/DQoNClRoZSBtYWpvcml0eSBvZiBvdXIgZGF0YSBjb250YWlucyBEcmFtYSBtb3ZpZXMoNTElKSwgZm9sbG93ZWQgYnkgQ29tZWR5KDE0JSkgYW5kIEFjdGlvbiBhbmQgQWR2ZW50dXJlKDExJSkuIFdlIGNhbiBzZWUgdGhhdCB3ZSBzdGlsbCBoYXZlIGEgZmV3IGRvY3VtZW50YXJpZXMgbGVmdCwgZXZlbiB0aG91Z2ggd2UgcmVtb3ZlZCB0aGVtIGJhc2VkIG9uIHR5cGUuIFdlIHdpbGwgYWxzbyByZW1vdmUgdGhpcyBzdWJzZXQgZm9yIHRoZSBzYW1lIHJlYXNvbiBhcyBiZWZvcmUuDQoNCmBgYHtyfQ0KbW92aWVfZ2VucmUgPC0gbW92aWVzJT4lDQogIGdyb3VwX2J5KGdlbnJlKSU+JQ0KICBzdW1tYXJpc2UoY291bnQgPSBuKCkpJT4lDQogIG11dGF0ZShwcm9wb3J0aW9uID0gcm91bmQoY291bnQvc3VtKGNvdW50KSoxMDAsMSkpJT4lDQogIGFycmFuZ2UoZGVzYyhjb3VudCkpDQogIA0KICBtb3ZpZV9nZW5yZSU+JQ0KICBrYmwoY2FwdGlvbiA9ICJTdW1tYXJ5IG9mIG1vdmllIGdlbnJlcyIpJT4lDQogIGthYmxlX3BhcGVyKCJob3ZlciIsIGZ1bGxfd2lkdGggPSBGKQ0KICANCiAgbW92aWVzIDwtIG1vdmllcyU+JQ0KICAgIGZpbHRlcihnZW5yZSAhPSAiRG9jdW1lbnRhcnkiKQ0KYGBgDQoNCiMjIyBBcmUgdGhlIElNREIgcmF0aW5ncyBpbXBhY3RlZCBieSB0aGUgZ2VucmU/DQoNCldlIGNhbiBvYnNlcnZlIHNpZ25pZmljYW50IGRpZmZlcmVuY2VzIGJldHdlZW4gdGhlIHZhcmlvdXMgZ2VucmVzIGFuZCBtZXRyaWNzIHN1Y2ggYXMgdmFyaWFuY2UsIG1lZGlhbnMsIHJhbmdlIGFuZCBvdXRsaWVycy4NCg0KYGBge3J9DQogIGdncGxvdChtb3ZpZXMsIGFlcyhnZW5yZSwgaW1kYl9yYXRpbmcsIGNvbCA9IGdlbnJlKSkrDQogIGdlb21fYm94cGxvdChzaG93LmxlZ2VuZCA9IEZBTFNFKSsNCiAgZ2VvbV9qaXR0ZXIoYWxwaGEgPSAwLjEsIHNob3cubGVnZW5kID0gRkFMU0UpKw0KICBjb29yZF9mbGlwKCkrDQogIGxhYnMoeSA9ICJJTURCIHJhdGluZyIpKw0KICB0aGVtZV9mZXcoKSsNCiAgbGFicyh4PU5VTEwpDQpgYGANCg0KIyMjIElzIHRoZXJlIGFuIGFzc29jaWF0aW9uIGJldHdlZW4gdGhlIElNREIgcmF0aW5nIGFuZCB0aGUgdG90YWwgYW1vdW50IG9mIElNREIgdm90ZXM/DQoNClRoZSBoaWdoLXBlcmZvcm1pbmcgbW92aWVzIChhcyBtZWFzdXJlZCBieSBJTURCIHJhdGluZykgYWxzbyBoYXZlIGEgaGlnaGVyIG51bWJlciBvZiB2b3Rlcy4gVGhpcyB0cmVuZCBzZWVtcyBleHBvbmVudGlhbCB0b3dhcmRzIHRoZSBoaWdoZXIgSU1EQiByYXRpbmdzL3ZvdGVzLCB3aGVyZSB0aGUgaW5jcmVhc2UgaW4gdG90YWwgbnVtYmVyIG9mIHZvdGVzIGlzIG11Y2ggaGlnaGVyIHRoYW4gaW4gdGhlIGxvdy9tZWRpdW0gcmFuZ2VzLg0KDQpgYGB7cn0NCm1vdmllcyU+JQ0KICBnZ3Bsb3QoYWVzKGltZGJfcmF0aW5nLCBpbWRiX251bV92b3RlcykpKw0KICBnZW9tX2ppdHRlcih3aWR0aD0wLjEsIGhlaWdodCA9IDAuMSwgYWxwaGEgPSAwLjUpKw0KICBnZW9tX3Ntb290aChzZSA9IEZBTFNFKSsNCiAgdGhlbWVfZmV3KCkrDQogIGxhYnMoeCA9ICJJTURCIHJhdGluZyIsDQogICAgICAgeSA9ICJUb3RhbCBJTURCIHZvdGVzIikrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCmBgYA0KDQojIyMgRG8gbW92aWUgY3JpdGljcyBhbmQgYXVkaWVuY2VzIHNoYXJlIHRoZSBzYW1lIHRhc3RlIGluIG1vdmllcz8NCg0KSnVkZ2luZyBieSB0aGUgdmFyaWFuY2VzIGluIG91ciBzY2F0dGVyIHBsb3RzLCB3ZSBjYW4gb2JzZXJ2ZSBmYWlybHkgbGFyZ2UgZGlzY3JlcGFuY2llcyBiZXR3ZWVuIGhvdyBhdWRpZW5jZXMgYW5kIGNyaXRpY3MgcGVyY2VpdmUgbW92aWVzLiBUaGlzIGlzIGV2ZW4gbW9yZSBhcHBhcmVudCBpbiBnZW5yZXMgc3VjaCBhcyBBY3Rpb24gJiBBZHZlbnR1cmUgYW5kIENvbWVkeSwgd2hlcmUgYXVkaWVuY2VzIHRlbmQgdG8gZ2l2ZSBtdWNoIGhpZ2hlciByYXRpbmdzIHRoYW4gdGhlIGNyaXRpY3MuDQoNCmBgYHtyfQ0KbW92aWVzJT4lDQogIGdncGxvdChhZXMoYXVkaWVuY2Vfc2NvcmUsIGNyaXRpY3Nfc2NvcmUsIGNvbCA9IGdlbnJlKSkrDQogIGdlb21faml0dGVyKHdpZHRoPTAuMSwgaGVpZ2h0ID0gMC4xLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSsNCiAgZmFjZXRfd3JhcCgufmdlbnJlKSsNCiAgdGhlbWVfZmV3KCkrDQogIGFubm90YXRlKCJzZWdtZW50IiwgeD0tSW5mLCB4ZW5kPUluZiwgeT0tSW5mLCB5ZW5kPUluZiwgYWxwaGEgPSAwLjUsIGx0eSA9IDIpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpKw0KICBsYWJzKHggPSAiQXVkaWVuY2Ugc2NvcmUiLA0KICAgICAgIHkgPSAiQ3JpdGljcyBzY29yZSIpDQpgYGANCg0KV2UgY2FuIGZvY3VzIG1vcmUgb24gdGhlc2UgZGlmZmVyZW5jZXMgYnkgbG9va2luZyBpbiBhdmVyYWdlIHNjb3JlcyBmb3IgZWFjaCBnZW5yZS4gQmVsb3csIHdlIGNhbiBvYnNlcnZlIHZlcnkgbGFyZ2UgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgdmFyaW91cyBnZW5yZXMuDQoNCmBgYHtyfQ0KbW92aWVzICU+JQ0KICBzZWxlY3QoZ2VucmUsIGF1ZGllbmNlX3Njb3JlLCBjcml0aWNzX3Njb3JlKSU+JQ0KICBncm91cF9ieShnZW5yZSklPiUNCiAgc3VtbWFyaXNlKGF1ZGllbmNlX3Njb3JlID0gbWVhbihhdWRpZW5jZV9zY29yZSksDQogICAgICAgICAgICBjcml0aWNzX3Njb3JlID0gbWVhbihjcml0aWNzX3Njb3JlKSklPiUNCiAgbXV0YXRlKGRpZmZlcmVuY2Vfc2NvcmUgPSByb3VuZCgoYXVkaWVuY2Vfc2NvcmUgLSBjcml0aWNzX3Njb3JlKSwgMSksDQogICAgICAgICBzdGF0dXMgPSBpZmVsc2UoYWJzKGRpZmZlcmVuY2Vfc2NvcmUpIDw9MywgImdvb2QgKGxvd2VyIHRoYW4gMykiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoYWJzKGRpZmZlcmVuY2Vfc2NvcmUpIDw9NSwgIm9rIChiZXR3ZWVuIDMgYW5kIDUpIiwgImJhZCAoaGlnaGVyIHRoYW4gNSkiKSkpJT4lDQojY3JlYXRlIHBsb3QgICAgICAgIA0KICBnZ3Bsb3QoYWVzKHJlb3JkZXIoZ2VucmUsIGRpZmZlcmVuY2Vfc2NvcmUpLCBkaWZmZXJlbmNlX3Njb3JlLCBmaWxsID0gc3RhdHVzKSkrDQogIGdlb21fY29sKGNvbCA9ICJibGFjayIpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJkYXJrIHJlZCIsICIjMDA5RTczIiwgImdvbGQzIikpKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImRhcmsgcmVkIiwgIiMwMDlFNzMiLCAiZ29sZDMiKSkrDQogIGdlb21fbGFiZWwoYWVzKGdlbnJlLCBkaWZmZXJlbmNlX3Njb3JlICsgaWZlbHNlKGRpZmZlcmVuY2Vfc2NvcmUgPj0gMCwgKzAuMiwgLTAuMiksIGxhYmVsID0gZGlmZmVyZW5jZV9zY29yZSksIHNob3cubGVnZW5kID0gRkFMU0UsIHNpemUgPSAzLCBmaWxsID0gIndoaXRlIikrDQogIGxhYnMoeD1OVUxMLA0KICAgICAgIHk9IlBvaW50cyBkaXNhZ3JlZW1lbnQiLA0KICAgICAgIHRpdGxlID0gIlJhdGluZyBkaXNhZ3JlZW1lbnQgYmV0d2VlbiBjcml0aWNzIGFuZCBhdWRpZW5jZXMiLA0KICAgICAgIHN1YnRpdGxlID0gIkEgcG9zaXRpdmUgc2NvcmUgbWVhbnMgdGhlIGF1ZGllbmNlIHJhdGVkIGhpZ2hlciB0aGFuIGNyaXRpY3MiLA0KICAgICAgIGZpbGwgPSAiU3RhdHVzIikrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLA0KICAgICAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKSsNCiAgY29vcmRfZmxpcCgpKw0KICB0aGVtZV9mZXcoKQ0KYGBgDQoNCiMjIyBJcyB0aGVyZSBhbiBhc3NvY2lhdGlvbiBiZXR3ZWVuIHRoZSB5ZWFyIGEgbW92aWUgd2FzIHJlbGVhc2VkIGluIGFuZCB0aGUgSU1EQiByYXRpbmc/DQoNCkdpdmVuIHRoYXQgd2UgaGF2ZSB0aGUgbnVtYmVyIG9mIHZvdGVzIGZvciBlYWNoIElNREIgcmF0aW5nLCB3ZSB3aWxsIHVzZSBhIHdlaWdodGVkIG1lYW4gZm9yIHRoaXMgY29tcGFyaXNvbi4NCg0KV2hpbGUgdGhlIHRvdGFsIG51bWJlciBvZiB2b3RlcyBpbmNyZWFzZWQsIGFzIHNob3duIGJ5IHRoZSBzaXplIG9mIHRoZSBwb2ludHMsIHdlIGNhbiBzZWUgdGhhdCB0aGUgb3ZlcmFsbCByYXRpbmcgd2FzIGZhaXJseSBjb25zaXN0ZW50LiBBZ2FpbiwgdG8gbm90ZSB0aGUgcmVsYXRpdmVseSBsb3cgc2FtcGxlIHNpemUgb2YgbW92aWVzIHJlbGVhc2VkIGJlZm9yZSB+MTk5MC4NCg0KYGBge3J9DQptb3ZpZXMlPiUNCiAgZ3JvdXBfYnkodGh0cl9yZWxfeWVhciklPiUNCiAgc3VtbWFyaXNlKGltZGJfd21lYW4gPSB3ZWlnaHRlZC5tZWFuKGltZGJfcmF0aW5nLCBpbWRiX251bV92b3RlcyksDQogICAgICAgICAgICBjb3VudCA9IG4oKSwNCiAgICAgICAgICAgIHZvdGVzID0gc3VtKGltZGJfbnVtX3ZvdGVzKSklPiUNCg0KZ2dwbG90KGFlcyh0aHRyX3JlbF95ZWFyLCBpbWRiX3dtZWFuKSkrDQogIGdlb21fcG9pbnQoYWVzKHNpemUgPSB2b3RlcyksIHNob3cubGVnZW5kID0gRkFMU0UpKw0KICBnZW9tX2xpbmUoKSsNCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAsMTApKSsNCiAgbGFicyh4ID0gTlVMTCwNCiAgICAgICB5ID0gIklNREIgcmF0aW5nIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJTaXplIG9mIHBvaW50IHNob3dzIHRoZSByZWxhdGl2ZSBzYW1wbGUgb2YgbnVtYmVyIG9mIHZvdGVzIHdpdGhpbiBlYWNoIHllYXIiKSsNCiAgdGhlbWVfZmV3KCkNCmBgYA0KDQojIyMgQXJlIHRoZXJlIGFueSBhc3NvY2lhdGlvbnMgYmV0d2VlbiB0aGUgSU1EQiByYXRpbmcgYW5kIHRoZSBtb250aCBvZiByZWxlYXNlPw0KDQpJdCBzZWVtcyB0aGF0IHRoZSByZWxlYXNlIGRhdGVzIGFyZSBmYWlybHkgZXF1YWwgZGlzdHJpYnV0ZWQgYWNyb3NzIHRoZSB5ZWFyICh3aWR0aCBvZiB0aGUgYmFyKSBhcyB3ZWxsIGFzIGVxdWFsIGluIHZhcmlhbmNlLiBUaHVzLCB3ZSBjYW4gc2F5IHRoYXQgaXQgbG9va3MgbGlrZSB0aGVzZSBmYWN0b3JzIGFyZSBpbmRlcGVuZGVudCBvZiBlYWNoIG90aGVyLg0KDQpgYGB7cn0NCm1vdmllcyU+JQ0KICBtdXRhdGUodGh0cl9yZWxfbW9udGggPSBhcy5mYWN0b3IodGh0cl9yZWxfbW9udGgpKSU+JQ0KICANCmdncGxvdChhZXModGh0cl9yZWxfbW9udGgsIGltZGJfcmF0aW5nLCBjb2wgPSB0aHRyX3JlbF9tb250aCkpKw0KICBnZW9tX2JveHBsb3QoYWVzKGdyb3VwID0gdGh0cl9yZWxfbW9udGgpLCB2YXJ3aWR0aCA9IFRSVUUsIHNob3cubGVnZW5kID0gRkFMU0UpKw0KICBnZW9tX2ppdHRlcihhbHBoYSA9IDAuMSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkrDQogIGxhYnMoeCA9ICJNb250aCIsDQogICAgICAgeSA9ICJJTURCIHJhdGluZyIpKw0KICB0aGVtZV9mZXcoKQ0KYGBgDQoNCiMjIyBJcyB0aGVyZSBhbiBhc3NvY2lhdGlvbiBiZXR3ZWVuIHRoZSBkYXkgb2YgdGhlIHdlZWsgYSBtb3ZpZSB3YXMgcmVsZWFzZWQgYW5kIHRoZSBJTURCIHJhdGluZz8NCg0KQm90aCB0aGUgYm94cGxvdCBhbmQgdGFibGUgYmVsb3cgc2hvdyB0aGF0IGFsbW9zdCA3NSUgb2YgbW92aWUgcmVsZWFzZXMgaGFwcGVuIG9uIGEgRnJpZGF5IGFuZCAxMSUgb24gYSBXZWRuZXNkYXkuIEFuIHNxdWFsIHNwbGl0IG9mIGFyb3VuZCAyLTMlIGVhY2ggaGFwcGVuIG9uIHRoZSBvdGhlciBkYXlzLiBXaGlsZSB0aGUgc2FtcGxlIHNpemVzIGFyZSBkaWZmZXJlbnQgYWNyb3NzIHRoZSB2YXJpb3VzIHdlZWtkYXlzLCB0aGVyZSBkb2Vzbid0IHNlZW0gdG8gYmUgYSBjbGVhciB0cmVuZCByZWdhcmRpbmcgdGhlIElNREIgcmF0aW5nLiBCb3RoIGF1ZGllbmNlcyBhbmQgY3JpdGljcyB0ZW5kIHRvIGFncmVlIHRoYXQgbW92aWVzIHJlbGVhc2VkIG9uIE1vbmRheSwgVHVlc2RheSBhbmQgRnJpZGF5IHBlcmZvcm0gd29yc2UgdGhhbiB0aGUgcmVzdC4NCg0KYGBge3J9DQpkYXlfb2Zfd2VlayA8LSBtb3ZpZXMlPiUNCiAgbXV0YXRlKGRhdGUgPSBtYWtlX2RhdGUodGh0cl9yZWxfeWVhciwgdGh0cl9yZWxfbW9udGgsIHRodHJfcmVsX2RheSksDQogICAgICAgICB3ZGF5ID0gd2Vla2RheXMuRGF0ZShkYXRlKSwNCiAgICAgICAgIHdkYXlfbnVtID0gd2RheShkYXRlLCB3ZWVrX3N0YXJ0ID0gMSkpJT4lDQogIGdyb3VwX2J5KHdkYXksIHdkYXlfbnVtKSU+JQ0KICBzdW1tYXJpc2UoY291bnQgPSBuKCksDQogICAgICAgICAgICB2b3RlcyA9IHJvdW5kKG1lYW4oaW1kYl9udW1fdm90ZXMpKSwNCiAgICAgICAgICAgIGltZGJfd21lYW4gPSB3ZWlnaHRlZC5tZWFuKGltZGJfcmF0aW5nLCBpbWRiX251bV92b3RlcyksDQogICAgICAgICAgICBhdWRpZW5jZV9zY29yZSA9IHJvdW5kKG1lYW4oYXVkaWVuY2Vfc2NvcmUpLDEpLA0KICAgICAgICAgICAgY3JpdGljc19zY29yZSA9IHJvdW5kKG1lYW4oY3JpdGljc19zY29yZSksMSksDQogICAgICAgICAgICBpbWRiX3dtZWFuID0gcm91bmQoaW1kYl93bWVhbiwgMSkpJT4lDQogIHVuZ3JvdXAoKSU+JQ0KICBtdXRhdGUocHJvcCA9IHJvdW5kKGNvdW50L3N1bShjb3VudCkqMTAwLDEpKSU+JQ0KICBhcnJhbmdlKHdkYXlfbnVtKQ0KDQojYWRkIHRoZSB3ZWVrZGF5IGNvbHVtbiB0byBvdXIgbW9kZWwNCm1vdmllcyA8LSBtb3ZpZXMlPiUNCiAgbXV0YXRlKGRhdGUgPSBtYWtlX2RhdGUodGh0cl9yZWxfeWVhciwgdGh0cl9yZWxfbW9udGgsIHRodHJfcmVsX2RheSksDQogICAgICAgICB3ZGF5ID0gYXMuZmFjdG9yKHdlZWtkYXlzLkRhdGUoZGF0ZSkpLA0KICAgICAgICAgd2RheV9udW0gPSB3ZGF5KGRhdGUsIHdlZWtfc3RhcnQgPSAxKSklPiUNCiAgc2VsZWN0KC1kYXRlKQ0KDQpnZ3Bsb3QobW92aWVzLCBhZXMocmVvcmRlcih3ZGF5LHdkYXlfbnVtKSwgaW1kYl9yYXRpbmcsIGNvbCA9IHdkYXkpKSsNCiAgZ2VvbV9ib3hwbG90KHNob3cubGVnZW5kID0gRkFMU0UsIHZhcndpZHRoID0gVFJVRSkrDQogIGdlb21faml0dGVyKGFscGhhID0gMC4xLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSsNCiAgbGFicyh4ID0gTlVMTCwNCiAgICAgICB5ID0gIklNREIgcmF0aW5nIikrDQogIHRoZW1lX2ZldygpDQogIA0KICBkYXlfb2Zfd2VlayU+JQ0KICBrYmwoY2FwdGlvbiA9ICJQcm9wb3J0aW9uIG9mIHJlbGVhc2VzIGJ5IGRheSBvZiB3ZWVrIiklPiUNCiAga2FibGVfcGFwZXIoImhvdmVyIiwgZnVsbF93aWR0aCA9IEYpDQpgYGANCg0KIyMjIERvZXMgdGhlIHJ1bnRpbWUgb2YgdGhlIG1vdmllIGFmZmVjdCB0aGUgSU1EQiByYXRpbmc/DQoNCldlIGNhbiBzZWUgYSBzbGlnaHQgdHJlbmQgd2hlcmUgbW92aWVzIG9mIGEgbG9uZ2VyIGxlbmd0aCBjb3JyZWxhdGUgd2l0aCBhIGhpZ2hlciBJTURCIHJhdGluZy4gSG93ZXZlciwgdGhpcyBpcyBub3QgY2F1c2FsIGFuZCBpdCBjb3VsZCBiZSB0aGF0IHRoaXMgaXMgYW4gaW5kaXJlY3QgZWZmZWN0IG9mIHRoZSBnZW5yZSBvZiB0aGUgbW92aWUgKGFuZCB0aHVzLCBsb25nZXIgbW92aWVzIGFyZSBvZiBhIGZhdm91cmFibGUgZ2VucmUpLg0KDQpgYGB7cn0NCmdncGxvdChtb3ZpZXMsIGFlcyhydW50aW1lLCBpbWRiX3JhdGluZykpKw0KICBnZW9tX2ppdHRlcih3aWR0aCA9IDAuMSwgaGVpZ2h0ID0gMC4xLCBhbHBoYSA9IDAuNzUpKw0KICBnZW9tX3Ntb290aChzZT1GQUxTRSkrDQogIHRoZW1lX2ZldygpKw0KICBsYWJzKHggPSAiUnVudGltZSAobWluKSIsDQogICAgICAgeSA9ICJJTURCIHJhdGluZyIpDQpgYGANCg0KIyMjIFdoZXJlIGRvZXMgUGFyYW1vdW50IFBpY3R1cmVzIHJhbmsgYW1vZ3N0IHRoZSB2YXJpb3VzIG90aGVyIHN0dWRpb3M/DQoNCkJhc2VkIG9uIG1vdmllIGF2ZXJhZ2VzLCBQYXJhbW91bnQgUGljdHVyZXMgaXMgcmFua2VkIHNvbWV3aGVyZSBhdCB0aGUgdG9wLCBiYXNlZCBvbiB0aGUgSU1EQiByYXRpbmcvbnVtYmVyIG9mIHRvdGFsIHZvdGVzIGFuZCBqdXN0IGFib3ZlIGF2ZXJhZ2UgcmVnYXJkaW5nIGF1ZGllbmNlIHJhdGluZ3MuDQoNCmBgYHtyfQ0Kc3R1ZGlvcyA8LSBtb3ZpZXMlPiUNCiAgZ3JvdXBfYnkoc3R1ZGlvKSU+JQ0KICBzdW1tYXJpc2UoaW1kYl93bWVhbiA9IHdlaWdodGVkLm1lYW4oaW1kYl9yYXRpbmcsIGltZGJfbnVtX3ZvdGVzKSwNCiAgICAgICAgICAgIGF1ZGllbmNlX3Njb3JlID0gbWVhbihhdWRpZW5jZV9zY29yZSwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgIGNvdW50ID0gbigpLA0KICAgICAgICAgICAgYXZnX3ZvdGVzID0gc3VtKGltZGJfbnVtX3ZvdGVzKS9jb3VudCkNCg0KcGFyYW1vdW50X3N0dWRpbyA8LSBzdHVkaW9zJT4lDQogIGZpbHRlcihzdHVkaW8gPT0gIlBhcmFtb3VudCBQaWN0dXJlcyIpDQoNCmdncGxvdCgpKw0KICBnZW9tX3BvaW50KGRhdGEgPSBzdHVkaW9zLCBhZXMoYXVkaWVuY2Vfc2NvcmUsIGltZGJfd21lYW4sIHNpemUgPSBhdmdfdm90ZXMpLCBzaG93LmxlZ2VuZCA9IEZBTFNFLCBhbHBoYSA9IDAuNikrDQogIGdlb21fdGV4dChkYXRhID0gcGFyYW1vdW50X3N0dWRpbywgYWVzKGF1ZGllbmNlX3Njb3JlLCBpbWRiX3dtZWFuLCBsYWJlbCA9ICJQYXJhbW91bnQiKSwgY29sID0gInJlZCIsIHNpemUgPSA1LCBudWRnZV95ID0gMC4zKSsNCiAgZ2VvbV9wb2ludChkYXRhID0gcGFyYW1vdW50X3N0dWRpbywgYWVzKGF1ZGllbmNlX3Njb3JlLCBpbWRiX3dtZWFuKSwgY29sID0gInJlZCIsIHNpemUgPSAzLjcpKw0KICBsYWJzKHggPSAiQXVkaWVuY2Ugc2NvcmUiLA0KICAgICAgIHkgPSAiSU1EQiByYXRpbmciLA0KICAgICAgIHN1YnRpdGxlID0gIlNpemUgb2YgcG9pbnQgc2hvd3MgdGhlIHJlbGF0aXZlIHNhbXBsZSBvZiBudW1iZXIgb2Ygdm90ZXMgd2l0aGluIGVhY2ggeWVhciAoYXZlcmFnZSBwZXIgc3R1ZGlvKSIpKw0KICB0aGVtZV9mZXcoKQ0KYGBgDQoNCiMjIyBJcyB0aGVyZSBhbiBhc3NvY2lhdGlvbiBiZXR3ZWVuIHRoZSB0eXBlIG9mIGFuIGF3YXJkIGEgbW92aWUgcmVjZWl2ZXMgYW5kIHRoZSByYXRpbmc/DQoNCldlIGNhbiBub3RpY2Ugc2lnbmlmaWNhbnQgZGlmZmVyZW5jZXMgZm9yIHRoZSBib3R0b20gdGhyZWUgYXdhcmRzLCBidXQgbm90IG5vdGhpbmcgc2lnbmlmaWNhbnQgYmV0d2VlbiB0aG9zZSB0aGF0IHJlY2VpdmVkIHRoZSB0b3AgMyBhd2FyZHMgaW4gdGhlIGJlbG93IGJveHBsb3QuDQoNCmBgYHtyfQ0KYXdhcmRzIDwtIG1vdmllcyU+JQ0KICBzZWxlY3QoYXVkaWVuY2Vfc2NvcmUsIGNyaXRpY3Nfc2NvcmUsIGltZGJfcmF0aW5nLCBpbWRiX251bV92b3RlcywgYmVzdF9waWNfbm9tOnRvcDIwMF9ib3gpJT4lDQogIGdhdGhlcihBd2FyZCwgU3RhdHVzLCAtYXVkaWVuY2Vfc2NvcmUsIC1jcml0aWNzX3Njb3JlLCAtaW1kYl9yYXRpbmcsIC1pbWRiX251bV92b3RlcykNCg0KZ2dwbG90KGF3YXJkcywgYWVzKFN0YXR1cywgaW1kYl9yYXRpbmcsIGNvbCA9IFN0YXR1cykpKw0KICBnZW9tX2JveHBsb3QoKSsNCiAgdGhlbWVfZmV3KCkrDQogIGxhYnMoY29sID0gIkF3YXJkIHJlY2VpdmVkIiwNCiAgICAgICB4ID0gTlVMTCwNCiAgICAgICB5ID0gIklNREIgcmF0aW5nIikrDQogIGZhY2V0X3dyYXAoLn5Bd2FyZCkrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQ0KYGBgDQoNClRoZSBzYW1lIHRyZW5kIGNhbiBiZSBzZWVuIGJlbG93IHdoZXJlIG1vdmllcyB0aGF0IGhhdmUgcmVjZWl2ZWQgdGhlIGJvdHRvbSAzIGF3YXJkcyB0ZW5kIHRvIHBlcmZvcm0gYmV0dGVyIHRoYW4gdGhvc2Ugd2hvIGhhdmUgbm90IG9uIGVpdGhlciBtb3ZpZSByYXRpbmcgc2NvcmUuDQoNCmBgYHtyfQ0KICBhd2FyZF95ZXMgPC0gYXdhcmRzJT4lDQogIGZpbHRlcihTdGF0dXMgPT0gInllcyIpDQoNCiAgZ2dwbG90KGF3YXJkcywgYWVzKGNyaXRpY3Nfc2NvcmUsIGltZGJfcmF0aW5nLCBjb2wgPSBTdGF0dXMpKSsNCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNTApKw0KICBnZW9tX3BvaW50KGRhdGEgPSBhd2FyZF95ZXMsIGFlcyhjcml0aWNzX3Njb3JlLCBpbWRiX3JhdGluZyksIGNvbCA9ICJkYXJrIHJlZCIpKw0KICB0aGVtZV9mZXcoKSsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJnb2xkMyIsICJkYXJrIHJlZCIpKSsNCiAgbGFicyhjb2wgPSAiQXdhcmQgcmVjZWl2ZWQiLA0KICAgICAgIHggPSAiQ3JpdGljcyBzY29yZSIsDQogICAgICAgeSA9ICJJTURCIHJhdGluZyIpKw0KICBmYWNldF93cmFwKC5+QXdhcmQpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikNCmBgYA0KDQpXZSBjYW4gYWxzbyBzcG90IGEgdHJlbmQgd2hlcmUsIGdlbmVyYWxseSBzcGVha2luZywgdGhlIHJhcmVyIHRoZSBhd2FyZCwgdGhlIGhpZ2hlciB0aGUgY2hhbmNlIGl0IHdvdWxkIGltcGFjdCBhbnkgb2YgdGhlIHJhdGluZ3MgaW4gYSBmYXZvdXJhYmxlIHdheS4NCg0KYGBge3J9DQphd2FyZHNfdGFibGUgPC0gYXdhcmRzJT4lDQogICAgZ3JvdXBfYnkoQXdhcmQsIFN0YXR1cyklPiUNCiAgICBzdW1tYXJpc2UoY291bnQgPSBuKCksDQogICAgICAgICAgICAgIGF1ZGllbmNlX3Njb3JlID0gcm91bmQobWVhbihhdWRpZW5jZV9zY29yZSksMSksDQogICAgICAgICAgICAgIGNyaXRpY3Nfc2NvcmUgPSByb3VuZChtZWFuKGNyaXRpY3Nfc2NvcmUpLDEpLA0KICAgICAgICAgICAgICBpbWRiX3JhdGluZyA9IHJvdW5kKHdlaWdodGVkLm1lYW4oaW1kYl9yYXRpbmcsIGltZGJfbnVtX3ZvdGVzKSwxKSwNCiAgICAgICAgICAgICAgaW1kYl9udW1fdm90ZXMgPSByb3VuZChtZWFuKGltZGJfbnVtX3ZvdGVzKSwwKSklPiUNCiAgbXV0YXRlKHByb3BvcnRpb24gPSByb3VuZChjb3VudC9zdW0oY291bnQpKjEwMCwxKSklPiUNCiAgYXJyYW5nZShwcm9wb3J0aW9uKQ0KDQphd2FyZHNfdGFibGUlPiUNCiAga2JsKGNhcHRpb24gPSAiU3VtbWFyeSBvZiBhd2FyZHMgYW5kIG1vdmllIHJhdGluZ3MiKSU+JQ0KICBrYWJsZV9wYXBlcigiaG92ZXIiLCBmdWxsX3dpZHRoID0gRikNCmBgYA0KDQoqICogKg0KDQojIyBQYXJ0IDQ6IE1vZGVsaW5nDQoNCiMjIyBGZWF0dXJlIHNlbGVjdGlvbg0KDQpXZSB3aWxsIGJlIGV4Y2x1ZGluZyB0aGUgZm9sbG93aW5nIHZhcmlhYmxlcyBmcm9tIG91ciAqKmZ1bGwgbW9kZWwqKjoNCg0KLSB0aXRsZSwgc3R1ZGlvIGFzIHRoZXkgbWlnaHQgY2F1c2Ugb3VyIG1vZGVsIHRvIG92ZXJmaXQNCi0gY3JpdGljcy9hdWRpZW5jZSByYXRpbmdzIGFuZCBzY29yZXMgYXMgdGhleSBhcmUgaGlnaGx5IGNvcnJlbGF0ZWQgd2l0aCBvdXIgcHJlZGljdGVkIHZhcmlhYmxlcyAoSU1EQiByYXRpbmcpDQotIG51bWJlciBvZiBJTURCIHJhdGluZ3MgYXMgaXQgd291bGQgYWN0IGFzIGEgcHJveHkgZm9yIHRoZSBJTURCIHJhdGluZyAodGhleSdyZSBhbHNvIGNvcnJlbGF0ZWQpDQotIERWRCByZWxlYXNlIHllYXIsIG1vbnRoIGFuZCBkYXkgZm9yIHJlYXNvbnMgbWVudGlvbiBiZWZvcmUgKGhpZ2ggY29ycmVsYXRpb24gd2l0aCB0aGVhdHJlIHJlbGVhc2UgZGF0ZXMgYW5kIGxhY2sgb2YgaW1wb3J0YW5jZSBnaXZlbiBjdXJyZW50IHN0cmVhbWluZyB0cmVuZHMpDQoNCioqRmVhdHVyZSBlbmdpbmVlcmluZyoqOiB3ZSBhbHNvIGFkZGVkIGRheSBvZiB0aGUgd2VlayB0byBzZWUgaWYgdGhlcmUgYXJlIGFueSB0cmVuZHMNCg0KIyMjIFNlbGVjdGlvbiBtZXRob2QNCg0KV2UgY2hvc2UgYSBiYWNrd2FyZCBwIHZhbHVlIGFkanVzdG1lbnQgdG8gb3VyIG1vZGVsLCBnaXZlbiB0aGUgY29udGV4dCBvZiB0aGUgc3R1ZHkgd2hlcmUgd2UgY291bGQgbm90IHVzZSBhbiBhdXRvbWF0ZWQgd2F5IHRvIHJlZHVjZSB2YXJpYWJsZXMuIEFuIFIgYWRqdXN0bWVudCB3b3VsZCBiZSBpbmNyZWRpYmx5IHRpbWUtY29uc3VtaW5nIGdpdmVuIHRoZSBtYW51YWwgbWV0aG9kb2xvZ3kgYW5kIHByb25lIHRvIGh1bWFuIGVycm9yLiBGdXJ0aGVybW9yZSwgYSBwIHZhbHVlIGFkanVzdG1lbnQgd291bGQgZW5zdXJlIHRoYXQgdGhlIGZhY3RvcnMgaW5jbHVkZWQgYXJlIHNpZ25pZmljYW50ICh3aGljaCBpcyBub3QgbmVjZXNzYXJpbHkgdHJ1ZSBpbiBhbiBSIGFkanVzdG1lbnQpLg0KDQpgYGB7cn0NCm1vZGVsX2luaXRpYWwgPC0gbG0oaW1kYl9yYXRpbmcgfiBnZW5yZSArIHJ1bnRpbWUgKyBtcGFhX3JhdGluZyArIHRodHJfcmVsX3llYXIgKyB0aHRyX3JlbF9tb250aCArIHRodHJfcmVsX2RheSArIGJlc3RfcGljX25vbSArIGJlc3RfcGljX3dpbiArIGJlc3RfYWN0b3Jfd2luICsgYmVzdF9hY3RyZXNzX3dpbiArIGJlc3RfZGlyX3dpbiArIHRvcDIwMF9ib3ggKyB3ZGF5LCBkYXRhPW1vdmllcykNCg0KdGlkeShtb2RlbF9pbml0aWFsKSU+JQ0KICBhcnJhbmdlKHRlcm0sIHAudmFsdWUpJT4lDQogIGtibChjYXB0aW9uID0gIkluaXRpYWwgbW9kZWwgLSBzdW1tYXJ5IiklPiUNCiAga2FibGVfcGFwZXIoImhvdmVyIiwgZnVsbF93aWR0aCA9IEYpDQoNCiMgcmVtb3ZlZCBiZXN0X2FjdG9yX3dpbg0KbW9kZWxfZmluYWwgPC0gbG0oaW1kYl9yYXRpbmcgfiBnZW5yZSArIHJ1bnRpbWUgKyBtcGFhX3JhdGluZyArIHRodHJfcmVsX3llYXIgKyB0aHRyX3JlbF9tb250aCArIHRodHJfcmVsX2RheSArIGJlc3RfcGljX25vbSArIGJlc3RfcGljX3dpbiArIGJlc3RfYWN0cmVzc193aW4gKyBiZXN0X2Rpcl93aW4gKyB0b3AyMDBfYm94ICsgd2RheSwgZGF0YT1tb3ZpZXMpDQoNCiMgcmVtb3ZlZCBiZXN0X2FjdHJlc3Nfd2luDQptb2RlbF9maW5hbCA8LSBsbShpbWRiX3JhdGluZyB+IGdlbnJlICsgcnVudGltZSArIG1wYWFfcmF0aW5nICsgdGh0cl9yZWxfeWVhciArIHRodHJfcmVsX21vbnRoICsgdGh0cl9yZWxfZGF5ICsgYmVzdF9waWNfbm9tICsgYmVzdF9waWNfd2luICsgYmVzdF9kaXJfd2luICsgdG9wMjAwX2JveCArIHdkYXksIGRhdGE9bW92aWVzKQ0KDQojIHJlbW92ZWQgdGh0cl9yZWxfZGF5DQptb2RlbF9maW5hbCA8LSBsbShpbWRiX3JhdGluZyB+IGdlbnJlICsgcnVudGltZSArIG1wYWFfcmF0aW5nICsgdGh0cl9yZWxfeWVhciArIHRodHJfcmVsX21vbnRoICsgYmVzdF9waWNfbm9tICsgYmVzdF9waWNfd2luICsgYmVzdF9kaXJfd2luICsgdG9wMjAwX2JveCArIHdkYXksIGRhdGE9bW92aWVzKQ0KDQojIHJlbW92ZWQgdGh0cl9yZWxfbW9udGgNCm1vZGVsX2ZpbmFsIDwtIGxtKGltZGJfcmF0aW5nIH4gZ2VucmUgKyBydW50aW1lICsgbXBhYV9yYXRpbmcgKyB0aHRyX3JlbF95ZWFyICsgYmVzdF9waWNfbm9tICsgYmVzdF9waWNfd2luICsgYmVzdF9kaXJfd2luICsgdG9wMjAwX2JveCArIHdkYXksIGRhdGE9bW92aWVzKQ0KDQojIHJlbW92ZWQgdGh0cl9yZWxfeWVhcg0KbW9kZWxfZmluYWwgPC0gbG0oaW1kYl9yYXRpbmcgfiBnZW5yZSArIHJ1bnRpbWUgKyBtcGFhX3JhdGluZyArIGJlc3RfcGljX25vbSArIGJlc3RfcGljX3dpbiArIGJlc3RfZGlyX3dpbiArIHRvcDIwMF9ib3ggKyB3ZGF5LCBkYXRhPW1vdmllcykNCg0KIyByZW1vdmVkIGJlc3RfcGljX3dpbg0KbW9kZWxfZmluYWwgPC0gbG0oaW1kYl9yYXRpbmcgfiBnZW5yZSArIHJ1bnRpbWUgKyBtcGFhX3JhdGluZyArIGJlc3RfcGljX25vbSArIGJlc3RfZGlyX3dpbiArIHRvcDIwMF9ib3ggKyB3ZGF5LCBkYXRhPW1vdmllcykNCmBgYA0KDQojIyMgRmluYWwgbW9kZWwNCg0KKipSZWFzb24gZm9yIGV4Y2x1ZGluZyBjZXJ0YWluIHZhcmlhYmxlcyoqOiBmb2xsb3dpbmcgYSBiYWNrd2FyZCBtb2RlbCBhZGp1c3RtZW50LCB0aGUgZm9sbG93aW5nIHZhcmlhYmxlcyB3ZXJlIG5vdCBwcm92ZW4gdG8gYmUgc2lnbmlmaWNhbnQgYW5kIHdlcmUgZXhjbHVkZWQgZnJvbSB0aGUgZmluYWwgbW9kZWwgKGluIG9yZGVyIG9mIGV4Y2x1c2lvbik6DQoNCi0gYmVzdF9hY3Rvcl93aW4NCi0gYmVzdF9hY3RyZXNzX3dpbg0KLSB0aHRyX3JlbF9kYXkNCi0gdGh0cl9yZWxfbW9udGgNCi0gdGh0cl9yZWxfeWVhcg0KLSBiZXN0X3BpY193aW4NCg0KVGhhdCBsZWF2ZXMgdXMgd2l0aCB0aGUgZm9sbG93aW5nIHZhcmlhYmxlcyBpbmNsdWRlZCBpbiBvdXIgKipmaW5hbCBtb2RlbCoqOg0KDQotIGdlbnJlDQotIHJ1bnRpbWUNCi0gbXBhYV9yYXRpbmcgDQotIGJlc3RfcGljX25vbSANCi0gYmVzdF9kaXJfd2luIA0KLSB0b3AyMDBfYm94DQotIHdlZWtkYXkNCg0KIyMjIEludGVycHJldGF0aW9uIG9mIG91ciBwcmVkaWN0aW9uIG1vZGVsDQoNCk92ZXJhbGwsIHdlIGNhbiBzZWUgdGhhdCB0aGUgbW9kZWwgd2FzIGFibGUgdG8gY2FwdHVyZSAyNiUgb2YgdGhlIHZhcmlhYmlsaXR5IGluIG91ciBkYXRhLg0KDQpgYGB7cn0NCmdsYW5jZShtb2RlbF9maW5hbCklPiUNCiAga2JsKGNhcHRpb24gPSAiRmluYWwgbW9kZWwgLSBvdmVyYWxsIHN1bW1hcnkiKSU+JQ0KICBrYWJsZV9wYXBlcigiaG92ZXIiLCBmdWxsX3dpZHRoID0gRikNCmBgYA0KDQpBdCB0aGUgY29lZmZpY2llbnQgbGV2ZWwsIHdlIGNhbiBzZWUgdGhhdCBhbGwgb3VyIGluY2x1ZGVkIHByZWRpY3RvcnMgd2VyZSBzaWduaWZpY2FudC4gVGhlIG1vc3Qgc2lnbmlmaWNhbnQgcHJlZGljdG9yIHdhcyBydW50aW1lLiBUaGlzIHdhcyBmb2xsb3dlZCBieSB3aGV0aGVyIGEgbW92aWUgd2FzIG5vbWluYXRlZCBmb3IgQmVzdCBQaWN0dXJlIGFzIHdlbGwgYXMgd2hldGhlciBpdCBiZWxvbmdlZCB0byB0aGUgIkRyYW1hIiBnZW5yZS4NCg0KV2UgY2FuIGNvbmNsdWRlIHRoYXQgd2l0aCBldmVyeXRoaW5nIGVsc2UgaGVsZCBjb25zdGFudDogDQoNCiogZm9yIGVhY2ggbWludXRlIG9mIGFkZGl0aW9uYWwgKipydW50aW1lKiosIGl0IGlzIGV4cGVjdGVkIHRoYXQgdGhlIElNREIgcmF0aW5nIGluY3JlYXNlcyBieSAwLjAxMiBwb2ludHMNCiogYSBtb3ZpZSBub21pbmF0ZWQgZm9yIHRoZSAqKkJlc3QgUGljdHVyZSoqIGF3YXJkIGlzIGVzdGltYXRlZCB0byBoYXZlIGEgaGlnaGVyIHJhdGluZywgb24gYXZlcmFnZSwgYnkgMC44NCBwb2ludHMNCiogYSBtb3ZpZSB0aGF0IHdvbiB0aGUgKipCZXN0IERpcmVjdG9yKiogYXdhcmQgaXMgcHJlZGljdGVkIHRvIGhhdmUgYSBoaWdoZXIgcmF0aW5nLCBvbiBhdmVyYWdlLCBieSAwLjMwIHBvaW50cw0KKiBtb3ZpZXMgaW5jbHVkZWQgaW4gdGhlICoqdG9wIDIwMCBib3gqKiBhcmUgZXN0aW1hdGVkIHRvIGJlIHJhdGVkIGhpZ2hlciBieSAwLjUzIHBvaW50cw0KKiBhIG1vdmllIHdpdGhpbiB0aGUgRHJhbWEgKipnZW5yZSoqIGlzIGV4cGVjdGVkIHRvIHNjb3JlIDAuNTcgcG9pbnRzIGhpZ2hlciB0aGFuIGFuIEFjdGlvbiBhbmQgQWR2ZW50dXJlIG1vdmllICh0aGUgaW50ZXJjZXB0KS4gVGhyZWUgb3RoZXIgZ2VucmVzIGNhbiBhbHNvIGJlIGVzdGltYXRlZCB0byBoYXZlIGEgc2lnbmlmaWNhbnRseSBoaWdoZXIgcmF0aW5nIHRoYW4gdGhlIGludGVyY2VwdCwgYmFzZWQgb24gdGhlaXIgY29lZmZpY2llbnQgYW5kIHAtdmFsdWU6DQogICogTXVzaWNhbCAmIFBlcmZvcm1pbmcgQXJ0cw0KICAqIE15c3RlcnkgJiBTdXNwc2Vuc2UNCiAgKiBPdGhlcg0KKiBtb3ZpZXMgd2l0aCBhbiAqKm1wYWEgcmF0aW5nKiogb2YgUEcgYW5kIFBHLTEzIGFyZSBlc3RpbWF0ZWQgdG8gc2NvcmUgbG93ZXIgdGhhbiBHIHJhdGVkIG1vdmllcyBieSAwLjU5IGFuZCAwLjgwLCByZXNwZWN0aXZlbHkNCiogKipkYXkgb2Ygd2VlayoqIHdhcyBhbHNvIHNpZ25pZmljYW50LiBBIG1vdmllIHJlbGVhc2VkIG9uIGEgU2F0dXJkYXkgd2FzIHByZWRpY3RlZCB0byBzY29yZSBoaWdoZXIgdGhhbiB0aGUgaW50ZXJjZXB0IChGcmlkYXkpIGJ5IDAuNDIgcG9pbnRzDQoNCmBgYHtyfQ0KdGlkeShtb2RlbF9maW5hbCklPiUNCiAgYXJyYW5nZSh0ZXJtLCBwLnZhbHVlKSU+JQ0KICBrYmwoY2FwdGlvbiA9ICJGaW5hbCBtb2RlbCAtIHN1bW1hcnkiKSU+JQ0KICBrYWJsZV9wYXBlcigiaG92ZXIiLCBmdWxsX3dpZHRoID0gRikNCmBgYA0KDQpUbyBub3RlLCBob3dldmVyLCB0aGF0IHdoaWxlIG91ciBtb2RlbCBwZXJmb3JtcyB3ZWxsIGluIHRoZSBtaWRkbGUgcmVnaW9ucywgaXQgc2lnbmlmaWNhbnRseSBvdmVyLXByZWRpY3RzIGZvciBsb3cgSU1EQiByYXRpbmdzIGFuZCB1bmRlci1wcmVkaWN0cyBmb3IgaGlnaCBJTURCIHJhdGluZ3MuDQoNCmBgYHtyfQ0KZ2dwbG90KG1vZGVsX2ZpbmFsLCBhZXMoaW1kYl9yYXRpbmcsIC5yZXNpZCkpKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBhbHBoYSA9IDAuNSwgc2l6ZSA9IDMsIGNvbG9yID0gImdyZXk1MiIpKw0KICBnZW9tX2ppdHRlcihhbHBoYSA9IDAuNSwgY29sb3IgPSAiYmx1ZSIsIGhlaWdodCA9IDAuMSwgd2lkdGggPSAwLjEpKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBsd2QgPSAwLjUsIGNvbCA9ICJyZWQiLCBzZSA9IEZBTFNFKSsNCiAgdGhlbWVfZmV3KCkrDQogIGxhYnMoeCA9ICJJTURCIHJhdGluZyIsDQogICAgICAgeT0iUmVzaWR1YWxzIikNCmBgYA0KDQojIyMgTW9kZWwgZGlhZ25vc3RpY3MNCg0KIyMjIyAxLiBsaW5lYXIgcmVsYXRpb25zaGlwIGJldHdlZW4gZWFjaCAobnVtZXJpY2FsKSBleHBsYW5hdG9yeSB2YXJpYWJsZSBhbmQgcmVzcG9uc2UNCg0KV2Ugb25seSBoYXZlIG9uZSBudW1lcmljYWwgdmFyaWFibGUgKHJ1bnRpbWUpIHdoaWNoIGlzIHNob3duIHRvIGhhdmUgYSBsaW5lYXIgcmVsYXRpb25zaGlwIHdpdGggb3VyIHByZWRpY3RvciB2YXJpYWJsZSAoSU1EQiByYXRpbmcpIGJ5IHRoZSByYW5kb20gc2NhdHRlciBpbiB0aGUgYmVsb3cgKipyZXNpZHVhbCBwbG90KiouIEhvd2V2ZXIsIHRvIG5vdGUgdGhhdCB0aGVyZSB3ZXJlbid0IG1hbnkgbW92aWVzIHdpdGggYSBydW50aW1lIG9mIG92ZXIgMTUwIG1pbnV0ZXMuDQoNCmBgYHtyfQ0KZ2dwbG90KG1vZGVsX2ZpbmFsLCBhZXMocnVudGltZSwgLnJlc2lkKSkrDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGFscGhhID0gMC41LCBzaXplID0gMywgY29sb3IgPSAiZ3JleTUyIikrDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUsIGNvbG9yID0gImJsdWUiKSsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgbHdkID0gMC41LCBjb2wgPSAicmVkIiwgc2UgPSBGQUxTRSkrDQogIHRoZW1lX2ZldygpKw0KICBsYWJzKHggPSAiUnVudGltZSIsDQogICAgICAgeT0iUmVzaWR1YWxzIikNCmBgYA0KDQojIyMjIDIuIG5lYXJseSBub3JtYWwgcmVzaWR1YWxzIHdpdGggbWVhbiAwDQoNCkRlc3BpdGUgYSBzbGlnaHQgc2tldyB0byB0aGUgbGVmdCwgdGhlIG1ham9yaXR5IG9mIG91ciByZXNpZHVhbHMgd2l0aGluIHRoZSBiZWxvdyAqKnJlc2lkdWFsIGhpc3RvZ3JhbSoqIGFyZSBjZW50ZXJlZCBhcm91bmQgdGhlIG1lYW4gMC4NCg0KYGBge3J9DQpnZ3Bsb3QobW9kZWxfZmluYWwsIGFlcygucmVzaWQpKSsNCiAgI2dlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMC4xLCBjb2wgPSAiYmxhY2siLCBmaWxsID0gImJsdWUiKSsNCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHk9Li5kZW5zaXR5Li4pLCBjb2xvcj0iYmxhY2siLCBmaWxsPSJ3aGl0ZSIsIGx3ZCA9IDAuNzUpICsNCiAgZ2VvbV9kZW5zaXR5KGFscGhhPTAuMiwgZmlsbD0iI0ZGNjY2NiIpICsNCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1tZWFuKC5yZXNpZCkpLCBjb2wgPSAncmVkJywgbHdkID0gMSwgbHR5ID0gMikgKw0KICBsYWJzKHg9IlJlc2lkdWFscyIsDQogICAgICAgeT0gIkRlbnNpdHkiKSsNCiAgdGhlbWVfZmV3KCkNCmBgYA0KDQpTaW1pbGFybHksIHRoZSAqKk5vcm1hbCBwcm9iYWJpbGl0eSBwbG90IG9mIHJlc2lkdWFscyAoUVEgcGxvdCkqKiBiZWxvdyBzaG93cyBhIHNpbWlsYXIgdHJlbmQuIE91dHNpZGUgb2YgdGhlIHRhaWwgYXJlYXMsIHdlIGRvIG5vdCBzZWUgYW55IHNpZ25pZmljYW50IGRldmlhdGlvbnMgZnJvbSB0aGUgbWVhbi4NCg0KYGBge3J9DQoNCmdncGxvdChtb2RlbF9maW5hbCwgYWVzKHNhbXBsZT0ucmVzaWQpKSsNCiAgc3RhdF9xcSgpKw0KICBzdGF0X3FxX2xpbmUoKSsNCiAgdGhlbWVfZmV3KCkrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCmBgYA0KDQojIyMjIDMuIGNvbnN0YW50IHZhcmlhYmlsaXR5IG9mIHJlc2lkdWFscw0KDQpXZSBjYW4gc2VlIHRoYXQgb3VyIHJlc2lkdWFscyBhcmUgZXF1YWxseSB2YXJpYWJsZSBmb3IgbG93IGFuZCBoaWdoIHZhbHVlcyBvZiB0aGUgcHJlZGljdGVkIHJlc3BvbnNlIHZhcmlhYmxlIChJTURCIHJhdGluZykuDQoNCmBgYHtyfQ0KZ2dwbG90KG1vZGVsX2ZpbmFsLCBhZXMoLmZpdHRlZCwgLnJlc2lkKSkrDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGFscGhhID0gMC41LCBzaXplID0gMywgY29sb3IgPSAiZ3JleTUyIikrDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUsIGNvbG9yID0gImJsdWUiKSsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgbHdkID0gMC41LCBjb2wgPSAicmVkIiwgc2UgPSBGQUxTRSkrDQogIHRoZW1lX2ZldygpKw0KICBsYWJzKHggPSAiSU1EQiByYXRpbmcgcHJlZGljdGlvbiIsDQogICAgICAgeT0iUmVzaWR1YWxzIikNCmBgYA0KDQpXZSBjYW4gYWxzbyBwbG90IHRoZSBhYnNvbHV0ZSB2YWx1ZXMgb2YgdGhlIHJlc2lkdWFscyBhcyBzZWVuIGJlbG93LiBUaGlzIGNhbiBiZSB0aG91Z2h0IG9mIHRoZSBhYm92ZSBwbG90IGZvbGRlZCBpbiBoYWxmLiBUaHVzLCBhIGZhbiBzaGFwZSBpbiB0aGUgYWJvdmUgcGxvdCB3b3VsZCBsb29rIGFzIGEgdHJpYW5nbGUgaW4gdGhlIGJlbG93IHBsb3QuIFRoaXMgaXMgbm90IHRoZSBjYXNlIGhlcmUsIGFuZCB0aHVzLCB0aGlzIGNvbmRpdGlvbiBpcyBhbHNvIG1ldC4NCg0KYGBge3J9DQpnZ3Bsb3QobW9kZWxfZmluYWwsIGFlcyguZml0dGVkLCBhYnMoLnJlc2lkKSkpKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBhbHBoYSA9IDAuNSwgc2l6ZSA9IDMsIGNvbG9yID0gImdyZXk1MiIpKw0KICBnZW9tX3BvaW50KGFscGhhID0gMC41LCBjb2xvciA9ICJibHVlIikrDQogICNnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBsd2QgPSAwLjUsIGNvbCA9ICJyZWQiLCBzZSA9IEZBTFNFKSsNCiAgdGhlbWVfZmV3KCkrDQogIGxhYnMoeCA9ICJJTURCIHJhdGluZyBwcmVkaWN0aW9uIiwNCiAgICAgICB5PSJSZXNpZHVhbHMiKQ0KYGBgDQoNCiMjIyMgNC4gaW5kZXBlbmRlbmNlIG9mIHJlc2lkdWFscyAoYW5kIGhlbmNlIG9ic2VydmF0aW9ucykNCg0KTm8gYXBwYXJlbnQgdHJlbmQgd2hpY2ggc3VnZ2VzdHMgaW5kZXBlbmRlbmNlIGZyb20gdGhlIG9yZGVyIG9mIGRhdGEgY29sbGVjdGlvbi4NCg0KYGBge3J9DQpkZiA8LSBhdWdtZW50KG1vZGVsX2ZpbmFsKQ0KDQogIGdncGxvdChkYXRhPWRmLCBhZXMoeCA9IDE6bnJvdyhkZiksIHkgPSAucmVzaWQpKSArIA0KICBsYWJzKHggPSAiSW5kZXgiLCANCiAgICAgICB5ID0gIlJlc2lkdWFscyIpKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBhbHBoYSA9IDAuNSwgc2l6ZSA9IDMsIGNvbG9yID0gImdyZXk1MiIsIGx0eSA9IDIpKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MCwgY29sPSJyZWQiLCBsaW5ldHlwZT0iZGFzaGVkIikrDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUsIGNvbG9yID0gImJsdWUiKSsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgbHdkID0gMC41LCBjb2wgPSAicmVkIiwgc2UgPSBGQUxTRSkrDQogIHRoZW1lX2ZldygpDQpgYGANCg0KKiAqICoNCg0KIyMgUGFydCA1OiBQcmVkaWN0aW9uDQoNCiMjIyBQcmVkaWN0aW9uIGFuZCBpbnRlcnByZXRhdGlvbg0KDQpIZXJlIGFyZSB0aGUgZGV0YWlscyBvZiB0aGUgKipMYSBMYSBMYW5kKiogbW92aWUsIGEgbW92aWUgcmVsZWFzZWQgaW4gMjAxNi4NCg0KKlJlZmVyZW5jZSAtIElNREIsIE9zY2FycyBhbmQgQm94IE9mZmljZSBNb2pvIG9mZmljaWFsIHdlYnNpdGVzKi4NCg0KYGBge3J9DQptb3ZpZV9sYWxhbGFuZCA8LSBkYXRhLmZyYW1lKCJnZW5yZSIgPSBjKCJNdXNpY2FsICYgUGVyZm9ybWluZyBBcnRzIiksIA0KICAgICAgICAgICAgICAgICAgICAgICAicnVudGltZSIgPSBjKDEyOCksIA0KICAgICAgICAgICAgICAgICAgICAgICAiYmVzdF9kaXJfd2luIiA9ICJ5ZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAiYmVzdF9waWNfbm9tIiA9ICJ5ZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAibXBhYV9yYXRpbmciID0gIlBHLTEzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgIndkYXkiID0gIkZyaWRheSIsDQogICAgICAgICAgICAgICAgICAgICAgICJ0b3AyMDBfYm94IiA9ICJ5ZXMiKQ0KDQptb3ZpZV9sYWxhbGFuZCU+JQ0KICBrYmwoY2FwdGlvbiA9ICJNb3ZpZSBkYXRhIiklPiUNCiAga2FibGVfcGFwZXIoImhvdmVyIiwgZnVsbF93aWR0aCA9IEYpDQpgYGANCg0KR2l2ZW4gdGhpcyBkYXRhLCB0aGUgbW9kZWwgcHJlZGljdGVkIGFuIElNREIgcmF0aW5nIG9mICoqOC41OCoqLiBUaGUgbG93ZXIgYW5kIHVwcGVyIGludGVydmFsIHZhbHVlcyB0ZWxsIHVzIHRoYXQgdGhlIElNREIgcmF0aW5nIGZvciBMYSBMYSBMYW5kIGlzIGluIHRoZSBpbnRlcnZhbCAoNy42NSBhbmQgOS41MCkgd2l0aCA5NSUgcHJvYmFiaWxpdHkuDQoNCmBgYHtyfQ0KcHJlZF9sYWxhbGFuZCA8LSBwcmVkaWN0KG1vZGVsX2ZpbmFsLCBuZXdkYXRhID0gbW92aWVfbGFsYWxhbmQsIGludGVydmFsID0gImNvbmZpZGVuY2UiKQ0KDQpwcmVkX2xhbGFsYW5kJT4lDQogIGtibChjYXB0aW9uID0gIlByZWRpY3Rpb25zIiklPiUNCiAga2FibGVfcGFwZXIoImhvdmVyIiwgZnVsbF93aWR0aCA9IEYpDQpgYGANCg0KTGFzdGx5LCB3ZSBjYW4gcGxvdCB0aGlzIGRhdGEgdG8gYmUgYWJsZSB0byB2aXN1YWxseSBpbnRlcnByZXQgaXQuIFdlIGNhbiBzZWUgdGhhdCBpdCB3YXMgcmVsYXRpdmVseSBjbG9zZSB0byB0aGUgcHJlZGljdGlvbiBhbmQgd2l0aGluIHRoZSBwcmVkaWN0ZWQgaW50ZXJ2YWwuDQoNCmBgYHtyfQ0KZ2dwbG90KG1vdmllcywgYWVzKGltZGJfcmF0aW5nLCBpbWRiX251bV92b3RlcykpKw0KICBnZW9tX2ppdHRlcihhbHBoYSA9IDAuNSwgc2l6ZSA9IDAuNzUsIHdpZHRoID0gMC4xLCBoZWlnaHQgPSAwLjEpKw0KICBnZW9tX3Ntb290aChzZT1GQUxTRSkrDQogICNwbG90IHByZWRpY3Rpb24NCiAgZ2VvbV9wb2ludChhZXMoeD04LjU3NjQ4NiAsIHkgPSA1MTMyMjUpLCBzaXplID0gNSwgY29sID0gImJsdWUiKSsNCiAgZ2VvbV90ZXh0KGFlcyh4PTguNTc2NDg2ICwgeSA9IDUxMzIyNSksIGxhYmVsID0gIlByZWRpY3Rpb24iLCBudWRnZV94ID0gMC4yNSwgbnVkZ2VfeSA9IC03NTAwMCkrDQogICNjb3JyZWN0IHZhbHVlDQogIGdlb21fcG9pbnQoYWVzKHg9OC4wLCB5ID0gNTEzMjI1KSwgc2l6ZSA9IDUsIGNvbCA9ICJyZWQiKSsNCiAgZ2VvbV90ZXh0KGFlcyh4PTguMCwgeSA9IDUxMzIyNSksIGxhYmVsID0gIkFjdHVhbCIsIG51ZGdlX3kgPSAtNTUwMDApKw0KICAjY29uZmlkZW5jZSBpbnRlcnZhbA0KICBnZW9tX2Vycm9yYmFyKGFlcyh4bWF4ID0gOS41MDIzNTQsIHhtaW4gPSA3LjY1MDYxOSwgeCA9OC41NzY0ODYsIHk9NTEzMjI1KSwgd2lkdGggPSAwLjUpKw0KICBnZW9tX3RleHQoYWVzKHg9OS4yLCB5ID0gNTEzMjI1KSwgbGFiZWwgPSAiKENJKSIsIGNvbCA9ICJibGFjayIsIG51ZGdlX3kgPSA0ODAwMCkrDQogIHRoZW1lX2ZldygpKw0KICBsYWJzKHggPSAiSU1EQiByYXRpbmciLA0KICAgICAgIHkgPSAiSU1EQiBudW1iZXIgb2Ygdm90ZXMiKQ0KYGBgDQoNCiogKiAqDQoNCiMjIFBhcnQgNjogQ29uY2x1c2lvbg0KDQojIyMgU3VtbWFyeQ0KDQotIG91ciBsaW5lYXIgbW9kZWwgd2FzIG9ubHkgYWJsZSB0byBjYXB0dXJlIDI5JSBvZiB0aGUgdmFyaWFiaWxpdHkgaW4gb3VyIGRhdGENCi0gdGhlIG1vZGVsIHNpZ25pZmljYW50bHkgb3Zlci1wcmVkaWN0cyBmb3IgbG93IElNREIgcmF0aW5ncyBhbmQgb3Zlci1wcmVkaWN0cyBmb3IgaGlnaCBJTURCIHJhdGluZ3MNCi0gd2hpbGUgd2Ugd2VyZSBhYmxlIHRvIGlkZW50aWZ5IHNpZ25pZmljYW50IHByZWRpY3RvcnMsIHRoZSBkZXNpZ24gb2YgdGhlIHN0dWR5IGRvZXMgbm90IGFsbG93IGZvciBjYXVzYXRpb24NCi0gY3JpdGljcyBhbmQgYXVkaWVuY2VzIHRlbmQgdG8gZGlmZmVyIGluIHRoZWlyIG1vdmllIHRhc3RlLCBwYXJ0aWN1bGFybHkgaW4gY2F0ZWdvcmllcyBzdWNoIGFzIENvbWVkeSBhbmQgQWN0aW9uICYgQWR2ZW50dXJlDQotIHNvbWUgYWNjb2xhZGVzIGFyZSBiZXR0ZXIgcHJlZGljdG9ycyBvZiBJTURCIHJhdGluZ3MgdGhhbiBvdGhlcnMNCi0gRnJpZGF5IG1pZ2h0IGJlIHRoZSBiZXN0IGRheSB0byByZWxlYXNlIGEgbW92aWUgaW4gdGVybXMgb2YgYXVkaWVuY2UgYWNjZXNzLCBidXQgdGhlIG1vdmllcyBhcmUgbm90IHRoZSBtb3N0IHBvcHVsYXIgKGFzIGp1ZGdlZCBieSB0b3RhbCBJTURCIHZvdGVzIG9yIElNREIgcmF0aW5nKQ0KLSB0aGVyZSBpcyBhbiBleHBvbmVudGlhbCByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgbnVtYmVyIG9mIHZvdGVzIGEgbW92aWUgcmVjZWl2ZXMgYW5kIHRoZSBJTURCIHJhdGluZywgd2hlcmUgaGlnaGx5IHJhdGVkIG1vdmllcyBhcmUgbXVjaCBtb3JlIHBvcHVsYXIgdGhhbiBub3JtYWxseSBleHBlY3RlZA0KLSBmdXJ0aGVyIG9wdGltaXNhdGlvbiBjYW4gYmUgbWFkZSBpZiB3ZSBoYXZlIGEgc3BlY2lmaWMgZ29hbCB0byBtYWtlIGEgbW92aWUgZm9yIGVpdGhlciBjcml0aWNzIG9yIGF1ZGllbmNlDQogIC0gc2ltaWxhcmx5LCBwb3B1bGFyaXR5IGNvdWxkIGFsc28gYmUgZGV0ZXJtaW5lZCBieSB0b3RhbCBudW1iZXIgb2Ygdm90ZXMgKHF1YW50aXR5KSByYXRoZXIgdGhhbiByYXRpbmcgKHF1YWxpdHkpDQoNCiMjIyBTaG9ydGNvbWluZ3MvY2hhbGxlbmdlcw0KDQotIHJlbGF0aXZlbHkgbG93IHNhbXBsZSBzaXplcyBiZWZvcmUgMTk5MDsgb3VyIGRhdGEgaXMgbm90IHJlcHJlc2VudGF0aXZlIG9mIGVhY2ggeWVhciBpbmNsdWRlZCBpbiB0aGUgZGF0YXNldChidXQgaXQgaXMgcmVwcmVzZW50YXRpdmUgb3ZlcmFsbCkNCi0gd2UgY291bGQgdXNlIG1vcmUgZGF0YSBvbiBmYWN0b3JzIHdlIHdvdWxkIG5vcm1hbGx5IGhhdmUgYWNjZXNzIGJlZm9yZSB0aGUgcmVsZWFzZSBvZiB0aGUgZmlsbTogYnVkZ2V0LCBhY3Rvci9kaXJlY3RvciBzb2NpYWwgbWVkaWEgaW5mbHVlbmNlICh3aGljaCBtaWdodCBhZmZlY3QgcmF0aW5ncyBvciBwb3B1bGFyaXR5KSwgZXRjDQotIG90aGVyIHR5cGVzIG9mIG1vZGVscyBjb3VsZCBiZSBleHBsb3JlZCwgcGFydGljdWxhcmx5IGV4cG9uZW50aWFsIG9uZXMNCi0gc29tZSB0ZWNobmlxdWVzIHdlcmUgc3BlY2lmaWNhbGx5IHVzZWQgaW4gdGhlIGNvbnRleHQgb2YgdGhlIGNvdXJzZSAtIG1vcmUgcm9idXN0IG1ldGhvZHMgYXJlIGF2YWlsYWJsZSBzdWNoIGFzOg0KICAtIFIgYWRqdXN0bWVudCwgYXMgaXQgaXMga25vd24gdG8gYmUgbW9yZSByZWxpYWJsZSB0aGFuIGFuIGFyYml0cmFyeSBwIHZhbHVlIHNlbGVjdGlvbg0KICAtIHRyYWluL3Rlc3Qgc3BsaXQgb2Ygb3VyIGRhdGFzZXQNCiAgLSBhdXRvbWF0ZWQgYmFja3dhcmQvZm9yd2FyZCBtb2RlbCBzZWxlY3Rpb24gKGllLiB0aHJvdWdoIENhcmV0KSwgc2luY2UgYSBtYW51YWwgYXBwcm9hY2ggaXMgc3VzY2VwdGlibGUgdG8gaHVtYW4gZXJyb3INCiAgLSBubyBkYXRhIHByZS1wcm9jZXNzaW5n