Introduction and
Background
Here we have a dataset originally composed of over 5,000 songs that
were available on the music-streaming service Spotify over the course of
2024. These tracks stem from a wide array of vastly different genres and
styles of creation. The dataset is publicly available on the platform
Kaggle and is provided in the References section below. Although the
data originally contained 29 variables, only 11 play a particularly
relevant role in the analysis I wish to do here. A breakdown of those
variables, their meanings and data types is below:
|
Name
|
Meaning
|
Data_Type
|
|
track_popularity
|
song’s rating on the 0 - 100 metric
|
double
|
|
popular
|
how popular the track is (more on that later)
|
character
|
|
track_name
|
name of the song
|
character
|
|
track_artist
|
artist’s stage name
|
character
|
|
playlist_genre
|
genre that Spotify classifies the song in
|
character
|
|
playlist_subgenre
|
subgenre that Spotify classifies the song in
|
character
|
|
tempo
|
the speed of a track, measured in beats per minute (BPM)
|
double
|
|
danceability
|
A score describing how suitable a track is for dancing based on tempo,
rhythm stability, beat strength and overall regularity (0 to 1 scale)
|
double
|
|
speechiness
|
the presence of audible words (0 to 1 scale)
|
double
|
|
instrumentalness
|
likelihood that the track contains instrumentals (0 to 1 scale)
|
double
|
|
duration_mins
|
length of track in minutes
|
double
|
Many of the other variables in the dataset I chose to disregard as
they either pertained to unnecessary technical information (such as the
algorithmic identifier for the particular song or its album), or
extremely niche musical topics that the average listener or introductory
critic would most likely not pick up on (such as mode and key).
Objective for my
Analysis
Using this dataset, I wish to quantifiably examine what musical
qualities and characteristics lead to a song (or “track”) becoming
extremely successful (hence popular) via Spotify. As of October of 2025,
Spotify has a market cap of over 139 billion dollars and close to 700
million users. This means that for any aspiring musician, “making it
big” on Spotify would serve as a monumental and life-altering
milestone.
Spotify has a metric known as the popularity index which serves to
numerically represent the popularity of tracks on its platform. While
the exact formula behind the score is kept confidential, critics in the
music industry and those with strong technical backgrounds have
theorized that the primary factors which influence a track’s score are
the following; its total number of streams, its recent number of
streams, its number of downloads and saves, and its month-to-month
growth in all three of said metrics.
This popularity index operates on a scale ranging from 0 to 100, with
only the most well-established stars reaching the 90th percentile and
higher. That being said, any track with a rating of 75 or higher is
largely considered a “top track” by industry experts, so that is the
interpretation I will apply with my analysis. I created a categorical
binary variable “popular”, which is valued as “yes” for tracks with a
popularity index rating of 75 or higher, and “no” for tracks with a
lower rating. I will perform associative logistic regression to assess
which, if any, of the factors mentioned in my variable breakdown above
contribute to a track being deemed popular or not.
Finally, after performing simple and multiple linear regression
processes to analyze the association between a track’s popularity and
its status of the variables I have laid out, I will then use predictive
modeling techniques in the effort to create a model which can accurately
predict a particular track’s likelihood of being popular on Spotify.
Simple Logistic
Regression Model
Checking for Pairwise
Relationships
Before jumping into model creation, I created a correlation matrix
for the quantitative predictor variables I am going to use in my
analysis. This is because variables with very high correlations (r >=
0.8) often can function as almost multiples of one another, leading to
inaccurate conclusions, especially when performing multiple
regression.
cor_matrix = cor(Quantitative_Variables)
# No high correlations between the variables
kable(cor_matrix, caption = "Correlation Matrix")
Correlation Matrix
| tempo |
1.0000000 |
0.0338179 |
0.0576956 |
-0.1518469 |
0.0397516 |
| danceability |
0.0338179 |
1.0000000 |
0.2840300 |
-0.3205070 |
-0.1374377 |
| speechiness |
0.0576956 |
0.2840300 |
1.0000000 |
-0.1903130 |
-0.1050720 |
| instrumentalness |
-0.1518469 |
-0.3205070 |
-0.1903130 |
1.0000000 |
-0.2218689 |
| duration_mins |
0.0397516 |
-0.1374377 |
-0.1050720 |
-0.2218689 |
1.0000000 |
After creating a correlation matrix, we can see that none of the
quantitative predictor variables that we are examining have a high
correlation with one another. Practically speaking, this is not very
surprising as even “similar” songs by the same artist or within the same
genre can have wildly different characteristics when it comes to tempo
or anything else we are looking at.
Picking Variable for
Simple Model
Below I created histograms to represent the distributions of all five
quantitative variables I am going to use in this analysis. The purpose
for doing such is to determine if any sort of variable manipulation is
necessary before using the variable in our logistic model.
par(mfrow = c(2, 3), mar = c(4, 4, 2, 1)) # mar controls margins
ylimit = max(density(Work_Data$tempo)$y)
hist(Work_Data$tempo, probability = TRUE, main = "Tempo Distribution", xlab="Tempo",
col = "azure1", border="lightseagreen")
lines(density(Work_Data$tempo, adjust=2), col="blue")
ylimit = max(density(Work_Data$danceability)$y)
hist(Work_Data$danceability, probability = TRUE, main = "Danceability Distribution", xlab="Danceability",
col = "azure1", border="lightseagreen")
lines(density(Work_Data$danceability, adjust=2), col="blue")
ylimit = max(density(Work_Data$speechiness)$y)
hist(Work_Data$speechiness, probability = TRUE, main = "Speechiness Distribution", xlab="Speechiness",
col = "azure1", border="lightseagreen")
lines(density(Work_Data$speechiness, adjust=2), col="blue")
ylimit = max(density(Work_Data$instrumentalness)$y)
hist(Work_Data$instrumentalness, probability = TRUE, main = "Instrumentalness Distribution", xlab="Instrumentalness",
col = "azure1", border="lightseagreen")
lines(density(Work_Data$instrumentalness, adjust=2), col="blue")
ylimit = max(density(Work_Data$duration_mins)$y)
hist(Work_Data$duration_mins, probability = TRUE, main = "Length (mins) Distribution", xlab="Length (mins)",
col = "azure1", border="lightseagreen")
lines(density(Work_Data$duration_mins, adjust=2), col="blue")

We can see from the histograms that there is an extreme skew in
speechiness, instrumentalness and length. While there are slight skews
in tempo and danceability, they are far more moderate. Since
tempo appears to be the least skewed of the variables, and it’s
calculation is the most straightforward (a simple measure of beats per
minute), I will use tempo to perform my simple logistic regression.
Creating the Simple
Model
Using built-in R functions, I created a simple binary logistic
regression model, in which the tempo of a song is meant to predict
whether or not that track is popular or not (popularity score of 75 or
not). In the calculations, the base level, or 0, was stored for
instances of a track’s popularity being marked as “no”. While the
instance level, or 1, was stored for instances of a track’s popularity
being marked as “yes”.
Simple_Log_Model = glm(formula = popular ~ tempo, family = binomial(link = "logit"),
data = Work_Data)
invisible(summary(Simple_Log_Model))
Simple_Log_Model_Coef_Summary = summary(Simple_Log_Model)$coef # output stats of coefficients
Simple_Confidence_Interval = confint(Simple_Log_Model) # confidence intervals of betas
Simple_Summary_Stats = cbind(Simple_Log_Model_Coef_Summary, Simple_Confidence_Interval.95=Simple_Confidence_Interval) # rounding off decimals
kable(Simple_Summary_Stats,caption = "Simple Logistic Regression Model Summary")
Simple Logistic Regression Model Summary
| (Intercept) |
-2.2643674 |
0.2126810 |
-10.646777 |
0.000000 |
-2.6844577 |
-1.8504312 |
| tempo |
0.0060146 |
0.0017127 |
3.511866 |
0.000445 |
0.0026561 |
0.0093727 |
The summary of our model above leads us to believe that a track’s
tempo does have a positive association with the likelihood that a track
is popular on Spotify, however that association is very small in
practical effect. Despite a statistically significant p value, \(\beta\)1 has an estimated
association with the probability of a track being deemed popular of
.006, and a 95% confidence interval deeming the association to fall
between the interval [.003, .009].
Odds Ratio
Summary
While the direct interpretation of a logistic regression model’s
summary statistics can be helpful, it is sometimes more practical to
examine our model’s odds ratio. An odds ratio represents the likelihood
of success divided by the likelihood of failure. For example, an odds
ratio of 2 would mean that whatever instance we are considering a
“success” occurs twice the number of times than it fails to occur.
# Odds ratio
Simple_Log_Model_Coef_Summary = summary(Simple_Log_Model)$coef
Odds_Ratio = exp(coef(Simple_Log_Model))
out.stats = cbind(Simple_Log_Model_Coef_Summary, odds.ratio = Odds_Ratio)
kable(out.stats,caption = "Simple Regression Model Coefficients W/ Odds Ratios")
Simple Regression Model Coefficients W/ Odds Ratios
| (Intercept) |
-2.2643674 |
0.2126810 |
-10.646777 |
0.000000 |
0.1038957 |
| tempo |
0.0060146 |
0.0017127 |
3.511866 |
0.000445 |
1.0060327 |
The odds ratio between a track’s tempo and it’s popularity status is
~ 1.006. Since tempo is measured in beats per minute (BPM), this means
that for every additional beat per minute that a song is recorded in,
it’s probability of having a popularity score above 75 increases by
about 0.6%.
Goodness-of-fit
measures
Below I calculated the goodness-of-fit (GOF) measures for the
logistic regression model. Generally speaking, it is beneficial to find
a model’s GOF features as they serve as relative comparisons of model
efficiency when comparing multiple models. In this instance, we only
created one model so far, so the measures are not of practical use at
the moment.
Residual_Deviance = Simple_Log_Model$deviance
Null_Residual_Deviance = Simple_Log_Model$null.deviance
aic = Simple_Log_Model$aic
Goodness_Of_Fit = cbind(Deviance.residual = Residual_Deviance, Null.Deviance.Residual = Null_Residual_Deviance,
AIC = aic)
pander(Goodness_Of_Fit)
Success Probability
Curve
Below I created a visual of the the model’s S curve (also called
success probability curve or logistic curve). The S curve helps us see
the change in probability of an event happening (a track being popular
or not on Spotify), in relation to a change in the value of a predictor
variable (tempo in BPM in this instance).
###
tempo_range = range(Work_Data$tempo)
x = seq(tempo_range[1], tempo_range[2], length = 200)
beta.x = coef(Simple_Log_Model)[1] + coef(Simple_Log_Model)[2]*x
success.prob = exp(beta.x)/(1+exp(beta.x))
failure.prob = 1/(1+exp(beta.x))
ylimit = max(success.prob, failure.prob)
##
beta1 = coef(Simple_Log_Model)[2]
success.prob.rate = beta1*exp(beta.x)/(1+exp(beta.x))^2
##
##
par(mfrow = c(1,1))
plot(x, success.prob, type = "l", lwd = 2, col = "black",
main = "The Probability of a Track Being \n Considered Popular on Spotify",
ylim=c(0, 1.1*ylimit),
xlab = "Tempo (BPM)",
ylab = "probability",
axes = FALSE,
col.main = "black",
cex.main = 1.1)
# lines(x, failure.prob,lwd = 2, col = "darkred")
axis(1, pos = 0)
axis(2)

##
y.rate = max(success.prob.rate)
plot(x, success.prob.rate, type = "l", lwd = 2, col = "black",
main = "The Rate of Change in Probability of a Track Being \n Considered Popular on Spotify",
xlab = "Tempo (BPM)",
ylab = "Rate of Change",
ylim=c(0,1.1*y.rate),
axes = FALSE,
col.main = "black",
cex.main = 1.1
)
axis(1, pos = 0)
axis(2)

The S Curve provides visual confirmation of the conclusions we were
able to draw from analyzing our coefficient summary, confidence
intervals and odds ratio. That is, that there is a positive association
between a track’s tempo and it’s likelihood of being a popular track on
Spotify, but that association is very minimal in
practical effect.
We can see from our second plot, that looked at the relationship
between the rate of change in said probability and a track’s tempo, that
from 50 to 200 beats per minute, the probability of a track being
popular’s positive rate of change only increases from 0.0006 to
0.0012.
Takeaways from Simple
Logistic Regression Model
To conclude, we can say that although there is a statistically
significant and positive relationship between a track’s tempo and the
probability that it is popular on Spotify, that association is of such a
small magnitude that it is relatively a non-factor in practical sense.
Therefore, it would be overly simplistic and hyperbolic for music labels
or agents to aggressively push their artists towards a more up-tempo
production, as the return on such a decision would likely not be worth
the cost of souring the relationship with the artist at hand.
Multiple Logistic
Regression Model
As we saw earlier when creating our simple regression model, there is
no significant risk of multicollinearity with the data we are working
with. However, we also saw there is an extreme rightward skew in the
distribution of speechiness, instrumentalness and length. Below I take a
closer look at the distributions of those three variables.
## Remember in the HW instructions, include not just the numerical variables but two categorical ones too (let's use playlist_genre and playlist_subgenre)
par(mfrow=c(1,2))
hist(speechiness, xlab="Speechiness", main = "")
hist(instrumentalness, xlab = "Instrumentalness", main = "")

hist(duration_mins, xlab = "Length (Mins)", main = "")

To combat the skew of all three variables, I will perform
discretization on each of them. The coding for such can be seen
below.
# Speechiness = "presence of audible words on 0 to 1 scale"
grp.speechiness = speechiness
grp.speechiness[speechiness < 0.5] = ": s under 0.5"
grp.speechiness[speechiness > 0.5] = ": s over 0.5"
# sum(speechiness > 0.5) = 14
# sum(speechiness < 0.5) = 2641
# Instrumentalness = "likelihood that the track contains instrumentals (0 to 1 scale)"
grp.instrumentalness = instrumentalness
grp.instrumentalness[instrumentalness < 0.1] = ": s under 0.1"
grp.instrumentalness[instrumentalness > 0.1 & instrumentalness <= 0.7] = ": s from 0.1 to 0.7"
grp.instrumentalness[instrumentalness > 0.7] = ": s over 0.7"
# sum(instrumentalness < 0.1) = 1802
# sum(instrumentalness > 0.1 & instrumentalness < 0.7) = 193
# sum(instrumentalness > 0.7) = 659
# duration_mins below
grp.duration_mins = duration_mins
grp.duration_mins[duration_mins < 5] = ": Under 5 mins"
grp.duration_mins[duration_mins >= 5 & duration_mins <= 10] = ": Between 5 and 10 mins"
grp.duration_mins[duration_mins > 10] = ": Over 10 mins"
# sum(duration_mins < 5) = 2424
# sum(duration_mins >= 5 & duration_mins <= 10) = 211
# sum(duration_mins > 10) = 20
Work_Data$grp.speechiness = grp.speechiness
Work_Data$grp.instrumentalness = grp.instrumentalness
Work_Data$grp.duration_mins = grp.duration_mins
Building Full
Multiple Logistic Model
For the full multiple logistic model, I will initially include the
continuous numerical variables tempo and danceability in their original
form, as well as the discretized transformations of instrumentalness,
length in minutes and speechiness. After coding this model in, I will
examine its summary statistics.
Multiple_Full_Log_Model = glm(formula = popular ~ tempo + danceability + grp.speechiness + grp.instrumentalness + grp.duration_mins, family = binomial(link = "logit"),
data = Work_Data)
invisible(summary(Multiple_Full_Log_Model))
Multiple_Full_Log_Model_Coef_Summary = summary(Multiple_Full_Log_Model)$coef
Multiple_Full_Confidence_Interval = confint(Multiple_Full_Log_Model)
Multiple_Full_Summary_Stats = cbind(Multiple_Full_Log_Model_Coef_Summary, Multiple_Full_Confidence_Interval.95=Multiple_Full_Confidence_Interval) # rounding off decimals
kable(Multiple_Full_Summary_Stats,caption = "Full Multiple Logistic Regression Model Summary")
Full Multiple Logistic Regression Model Summary
| (Intercept) |
-17.3380444 |
375.7154226 |
-0.0461467 |
0.9631933 |
NA |
7.5447416 |
| tempo |
0.0038700 |
0.0018965 |
2.0405532 |
0.0412953 |
0.0001487 |
0.0075874 |
| danceability |
0.3230690 |
0.3274150 |
0.9867263 |
0.3237768 |
-0.3156955 |
0.9684832 |
| grp.speechiness: s under 0.5 |
14.2760281 |
375.7151570 |
0.0379969 |
0.9696901 |
-10.9252242 |
NA |
| grp.instrumentalness: s over 0.7 |
-2.1650529 |
0.3613366 |
-5.9917905 |
0.0000000 |
-2.9070614 |
-1.4777880 |
| grp.instrumentalness: s under 0.1 |
0.6024645 |
0.2205999 |
2.7310277 |
0.0063137 |
0.1872867 |
1.0554459 |
| grp.duration_mins: Over 10 mins |
-13.2932711 |
310.2840235 |
-0.0428423 |
0.9658273 |
NA |
4.4755962 |
| grp.duration_mins: Under 5 mins |
0.6782754 |
0.2321971 |
2.9211189 |
0.0034878 |
0.2431306 |
1.1574116 |
invisible(table(Work_Data$popular, Work_Data$grp.speechiness))
invisible(table(Work_Data$popular, Work_Data$grp.instrumentalness))
invisible(table(Work_Data$popular, Work_Data$grp.duration_mins))
#NA's in kable function display are due to "perfect" results between certain levels of our discretized variables and the response variable of popular or not. If all observations in a certain level result in one of the two options for the response variable, then that coefficient will trend towards negative or positive infinity per R's calculations.
We can see the following from our model summary. First, just like the
results from our simple regression model, there is once again a
statistically significant association between a track’s tempo and its
likelihood of being popular on Spotify (p ~ 0.0413). However that
association is so small that it is of little practical
importance. Additionally, it appears that a track’s instrumentalness and
length absolutely play a part in its probability of being popular on
Spotify.
If we look at the discretized breakdown of instrumentalness, we see
that there is an significant difference in tracks whose instrumentalness
rating is of 0.7 and higher, or less than 0.1, when compared to tracks
whose rating is somewhere in the middle. For track length, there also
appears to be significant evidence that tracks less than 5 minutes long
have a greater probability of achieving popularity on Spotify than those
of any other lengths in our dataset.
On the other hand, there is not evidence to suggest that a track’s
danceability or speechiness have such an association with its
popularity.
After examining the model summary, I also chose to run VIF on this
full model, which can be seen below. Given that all GVIF are below 1.1,
we can safely say that multicollinearity is not pertinent to this
dataset. This finding is in line with the takeaway from our pairwise
scatterplot earlier on.
vif(Multiple_Full_Log_Model)
GVIF Df GVIF^(1/(2*Df))
tempo 1.018314 1 1.009116
danceability 1.048916 1 1.024166
grp.speechiness 1.000000 1 1.000000
grp.instrumentalness 1.035527 2 1.008766
grp.duration_mins 1.012616 2 1.003139
Manually Reduced
Multiple Logistic Model
Since parsimony (having as least amount of variables as possible
without losing significant accuracy in association examination or
prediction accuracy) is an important aspect of statistical modeling, I
also then chose to create a reduced version of my multiple logistic
model above. In this model, I did not include predictors whose impact
was very clearly insignificant as per the original full model’s summary
(danceability and speechiness). The summary for this new reduced model
is below.
Multiple_Reduced_Log_Model = glm(formula = popular ~ tempo + grp.instrumentalness + grp.duration_mins, family = binomial(link = "logit"),
data = Work_Data)
invisible(summary(Multiple_Reduced_Log_Model))
Multiple_Reduced_Log_Model_Coef_Summary = summary(Multiple_Reduced_Log_Model)$coef
Multiple_Reduced_Log_Model_Confidence_Interval = confint(Multiple_Reduced_Log_Model)
Multiple_Reduced_Summary_Stats = cbind(Multiple_Reduced_Log_Model_Coef_Summary, Multiple_Reduced_Confidence_Interval.95=Multiple_Reduced_Log_Model_Confidence_Interval) # rounding off decimals
kable(Multiple_Reduced_Summary_Stats,caption = "Reduced Multiple Logistic Regression Model Summary")
Reduced Multiple Logistic Regression Model Summary
| (Intercept) |
-2.8580203 |
0.3686009 |
-7.7536985 |
0.0000000 |
-3.5991921 |
-2.1520692 |
| tempo |
0.0035527 |
0.0018681 |
1.9017792 |
0.0572000 |
-0.0001176 |
0.0072091 |
| grp.instrumentalness: s over 0.7 |
-2.1920495 |
0.3605499 |
-6.0797397 |
0.0000000 |
-2.9326652 |
-1.5064166 |
| grp.instrumentalness: s under 0.1 |
0.6152133 |
0.2195892 |
2.8016558 |
0.0050841 |
0.2022035 |
1.0664024 |
| grp.duration_mins: Over 10 mins |
-13.3332333 |
310.6582027 |
-0.0429193 |
0.9657659 |
NA |
4.4642172 |
| grp.duration_mins: Under 5 mins |
0.6999423 |
0.2308747 |
3.0316973 |
0.0024318 |
0.2676486 |
1.1767544 |
The results from this new reduced model largely align with the
findings from the original multiple model. However, just as overfitting
a model with needless information is a poor practice, so is underfitting
a model by not including everything that is truly important. To ensure
validity of this reduced model’s structure, below I ran automatic
stepwwise selection via R’s AIC function. The model’s summary statistics
have been printed.
Algorithmically
Reduced Multiple Logistic Model
library(MASS)
AIC_Model = stepAIC(Multiple_Reduced_Log_Model,
scope = list(lower=formula(Multiple_Reduced_Log_Model),upper=formula(Multiple_Full_Log_Model)),
direction = "forward", # forward selection
trace = 0 # do not show the details
)
kable(Multiple_Reduced_Summary_Stats,caption ="AIC-Created Multiple Logistic Regression Model Summary")
AIC-Created Multiple Logistic Regression Model
Summary
| (Intercept) |
-2.8580203 |
0.3686009 |
-7.7536985 |
0.0000000 |
-3.5991921 |
-2.1520692 |
| tempo |
0.0035527 |
0.0018681 |
1.9017792 |
0.0572000 |
-0.0001176 |
0.0072091 |
| grp.instrumentalness: s over 0.7 |
-2.1920495 |
0.3605499 |
-6.0797397 |
0.0000000 |
-2.9326652 |
-1.5064166 |
| grp.instrumentalness: s under 0.1 |
0.6152133 |
0.2195892 |
2.8016558 |
0.0050841 |
0.2022035 |
1.0664024 |
| grp.duration_mins: Over 10 mins |
-13.3332333 |
310.6582027 |
-0.0429193 |
0.9657659 |
NA |
4.4642172 |
| grp.duration_mins: Under 5 mins |
0.6999423 |
0.2308747 |
3.0316973 |
0.0024318 |
0.2676486 |
1.1767544 |
We can see from our model summary that the AIC-created model and the
reduced model I coded in via manual variable selection are identical.
This is not surprising due to how clearly significant or insignificant
the predictors were in the original full model. Below I will perform
global GOF measures on the model to have record of a formal comparison
of each one’s accuracy.
Model Comparison and
Selection
# GOF Full Multiple Model
Mult_Full_Residual_Deviance = Multiple_Full_Log_Model$deviance
Mult_Full_Null_Residual_Deviance = Multiple_Full_Log_Model$null.deviance
Mult_Full_aic = Multiple_Full_Log_Model$aic
Mult_Full_Goodness_Of_Fit = cbind(Mult_Full_Residual_Deviance,
Mult_Full_Null_Residual_Deviance, Mult_Full_aic)
# GOF Manually Reduced Multiple Model
Mult_Reduced_Residual_Deviance = Multiple_Reduced_Log_Model$deviance
Mult_Reduced_Null_Residual_Deviance = Multiple_Reduced_Log_Model$null.deviance
Mult_Reduced_aic = Multiple_Reduced_Log_Model$aic
Mult_Reduced_Goodness_Of_Fit = cbind(Mult_Reduced_Residual_Deviance,
Mult_Reduced_Null_Residual_Deviance, Mult_Reduced_aic)
# GOF AIC Reduced Model
Mult_AIC_Residual_Deviance = AIC_Model$deviance
Mult_AIC_Null_Residual_Deviance = AIC_Model$null.deviance
Mult_AIC_aic = AIC_Model$aic
Mult_AIC_Goodness_Of_Fit = cbind(Mult_AIC_Residual_Deviance,
Mult_AIC_Null_Residual_Deviance, Mult_AIC_aic)
Model_GOFs = rbind(Mult_Full_Goodness_Of_Fit, Mult_Reduced_Goodness_Of_Fit,
Mult_AIC_Goodness_Of_Fit)
rownames(Model_GOFs) = c("Full Model", "Manually Reduced Model", "AIC Reduced Model")
colnames(Model_GOFs) = c("Residual Deviance", "Null Deviance", "AIC")
kable(Model_GOFs, caption ="GOF Summary of Each Model")
GOF Summary of Each Model
| Full Model |
2216.519 |
2463.55 |
2232.519 |
| Manually Reduced Model |
2224.352 |
2463.55 |
2236.352 |
| AIC Reduced Model |
2217.497 |
2463.55 |
2231.497 |
As we can see from the table above, all three models perform
extremely similar. Since our AIC-created model has the lowest AIC, and
its residual deviance is only a fraction greater than that of our full
model, we will accept the AIC-created model as our final choice to use
for interpetation of this dataset.
Takeaways from
Multiple Logistic Regression Modeling Process
After the simple logistic regression modeling process earlier, we
came away with the conclusion that a track’s tempo was ‘technically’
significant in it’s likelihood of being popular on Spotify, but the
practical magnitude of its impact was so small that it was not a factor
that deserves a great deal of emphasis in the real world. Our
AIC-created model for the most part confirms this finding, (p ~
.0572).
The most important findings from our multiple logistic regression
process come from what was discovered by our discretized variables.
Tracks with very high instrumentalness (over 0.7 on this dataset’s
scale) have a lesser likelihood of being popular on Spotify than those
that fall in between 0.1 and 0.7 on said scale. Additionally, tracks
under 0.1 on the scale actually have a slighly higher chance of being
popular.
Regarding a track’s length, tracks being under 5 minutes does have a
significant association with increased likelihood of popularity when
compared to tracks ranging from 5 to 10 minutes and tracks beyond 10
minutes. However, there is not sufficient evidence that tracks going
above 10 minutes significantly reduces their chance of being popular
when compared to those in the 5 to 10 minute category.
Below is a visual displaying the odds ratios for relevant variables
from my AIC-created model, they will be referenced in my final
conclusion. The extreme estimate, standard error and odds ratio for
speechiness can be disregarded and attributed largely to the vast
majority of observations falling below 0.5 on the speechiness scale.
That along with the variable’s extremely high p value, and standard
error being practically identical to the standard error of the model’s
null intercept lead us to believe that the summary statistics for
speechiness can be chalked up to random chance, not true logistic
association.
AIC_Model_Coef_Summary = summary(AIC_Model)$coef
AIC_Odds_Ratio = exp(coef(AIC_Model))
AIC_out.stats = cbind(AIC_Model_Coef_Summary, odds.ratio = AIC_Odds_Ratio)
kable(AIC_out.stats,caption = "AIC-Created Multiple Regression Model Coefficients W/ Odds Ratios")
AIC-Created Multiple Regression Model Coefficients W/ Odds
Ratios
| (Intercept) |
-17.1140371 |
375.3481554 |
-0.0455951 |
0.9636330 |
0.0000000 |
| tempo |
0.0036649 |
0.0018745 |
1.9551582 |
0.0505644 |
1.0036716 |
| grp.instrumentalness: s over 0.7 |
-2.1888224 |
0.3605641 |
-6.0705491 |
0.0000000 |
0.1120486 |
| grp.instrumentalness: s under 0.1 |
0.6234236 |
0.2196071 |
2.8388131 |
0.0045282 |
1.8653032 |
| grp.duration_mins: Over 10 mins |
-13.3387936 |
310.5685700 |
-0.0429496 |
0.9657417 |
0.0000016 |
| grp.duration_mins: Under 5 mins |
0.7018358 |
0.2310153 |
3.0380492 |
0.0023812 |
2.0174530 |
| grp.speechiness: s under 0.5 |
14.2414898 |
375.3479579 |
0.0379421 |
0.9697338 |
1531088.9917716 |
Final Association
Modeling Conclusion
To conclude, in the most practical sense there are two factors that
seem to have the greatest association on a track’s chance of being
popular on Spotify. Those being its instrumentalness and length. Tracks
that are under 5 minutes long have about twice the
likelihood of being popular than not, while tracks that are longer than
10 minutes do not have nearly as great a chance. Tracks that are not
very instrumental (s under 0.1) also have close to twice as great a
chance of being popular than not. Much better odds than their very
instrumental (s over 0.7) and mildly instrumental (0.1 < s < 0.7)
counterparts.
Predictive Binary
Logistic Model
Now that we have deeply studied the association of a track’s
likelihood of popularity with some of the track’s characteristics, I am
going to take our analysis one step further, away from the realm of
strict observation and into the realm of educated and predictive
speculation. For this process, I will utilize the models constructed in
sections 3.1 through 3.3 above, as well as standard predictive modeling
techniques like data splitting and ROC visualization.
Data Splitting
Below I split the data we have been analyzing into two subsets, one
for training purposes and one for assessment purposes, at a rate of 70%
to 30% respectively. This procedure is done to counteract the risk of
overfitting a model and to ensure that the true rate of inaccurate
prediction (both false positives and false negatives) is known.
n = nrow(Work_Data) # Sample size of data we are working with
Training_n =round(0.7*n) # Sample size of training data
Training_ID = sample(1:n, Training_n, replace = FALSE)
# The number of rows to choose from is 1:n, the number that will be selected is Training_n, replacement is set to FALSE since we are taking a subset of the data, so do not want to take the same observation(s) more than once.
Training_Data = Work_Data[Training_ID, ]
# Creates a subset of Work_Data, assigning only the observations from the dataset that were marked with Training_ID to be in the Training_Data subset
Testing_Data = Work_Data[-Training_ID, ]
# Creates an alternate subset of Work_Data, assigning only the observations from the dataset that were NOT marked with Training_ID to be in the Testing_Data subset
Cross Validation (CV)
Process and Model Selection
Now I will use the aforementioned models, created in my multiple
regression association analysis, in the CV process. I will create 3
folds (distinct groups) and set the cut-off probability (what
constitutes “yes” or “no” as the value of our binary response variable)
to the standard 0.5. The results and interpretation can be seen
below.
# Multiple_Full_Log_Model = First multiple log model
# Multiple_Reduced_Log_Model = Manually reduced one
# AIC_Model = The final Algorithmically Reduced one we used
# 3 fold cross-validation
k = 3
fold_size = floor(dim(Training_Data)[1]/k)
## PE vectors for candidate models
PE1 = rep(0,5)
PE2 = rep(0,5)
PE3 = rep(0,5)
for(i in 1:k){ # Start of big FOR loop
## Training and testing folds
valid.id = (fold_size*(i-1)+1):(fold_size*i)
valid = Training_Data[valid.id, ]
train.dat = Training_Data[-valid.id,]
# Full Log Model
CVModel1 = glm(formula = popular ~ tempo + danceability + grp.speechiness + grp.instrumentalness + grp.duration_mins, family = binomial(link = "logit"),
data = train.dat)
table(Training_Data$popular)
# Manually Reduced Log Model
CVModel2 = glm(formula = popular ~ tempo + grp.instrumentalness + grp.duration_mins, family = binomial(link = "logit"),
data = train.dat)
# AIC Reduced (Final) Log Model
CVModel3 = stepAIC(CVModel1,
scope = list(lower=formula(CVModel2),upper=formula(CVModel1)),
direction = "forward", # forward selection
trace = 0 )
## predicted probabilities of each candidate model
pred01 = predict(CVModel1, newdata = valid, type="response")
pred02 = predict(CVModel2, newdata = valid, type="response")
pred03 = predict(CVModel3, newdata = valid, type="response")
pre.outcome01 = ifelse(as.vector(pred01) > 0.5, "yes", "no")
pre.outcome02 = ifelse(as.vector(pred02) > 0.5, "yes", "no")
pre.outcome03 = ifelse(as.vector(pred03) > 0.5, "yes", "no")
# Have our cut-off probability set to 0.5
# HAVE to set responses as "yes" and "no", earlier had them set as "pos" and "neg" to mimic the case study code, which is why outcome was illogical
PE1[i] = 1-sum(pre.outcome01 == valid$popular )/length(pred01)
PE2[i] = 1-sum(pre.outcome02 == valid$popular )/length(pred02)
PE3[i] = 1-sum(pre.outcome02 == valid$popular)/length(pred03)
# valid$popular = “From the validation subset valid, take the column named popular.”
} # End of big FOR loop
# Display the output of the loop
Avg.Prediction_Error = cbind(PE1 = mean(PE1), PE2 = mean(PE2), PE3 = mean(PE3))
kable(Avg.Prediction_Error, digits = 4, caption = "Average Prediction Errors of the CV Models")
Average Prediction Errors of the CV Models
| 0.104 |
0.104 |
0.104 |
pred02 = predict(CVModel2, newdata = Testing_Data, type="response")
pred02.outcome = ifelse(as.vector(pred02)>0.5, "yes", "no")
accuracy = sum(pred02.outcome == Testing_Data$popular)/length(pred02)
kable(accuracy, caption="The actual accuracy of the final model")
The actual accuracy of the final model
| 0.8205772 |
We can see from above that, at a cut-off probability of 0.5, all
three of our models used for associative analysis function with an
average prediction error of ~ 0.1057 (this number can vary by about .01
either way depending on which run of the simulation we are on). This is
not too surprising given the shared associative findings of each model
(check Multiple Regression section). Given that I previously determined
the AIC-produced model was the most ideal, that is the one I
will consider as the ultimate or “final” predictive model. This
model’s rate of accuracy, which was found through applying it’s
structure to the testing dataset that we subsetted earlier, is about
82.67% (like prediction error, can have slight variation).
ROC
Visualization
To assist with understanding, I also constructed a ROC (Receiver
Operating Characteristics) curve. This image allows us to interpret the
relationship between our different models’ specificity (rate of
producing false positives) on the x axis VS sensitivity (rate of
producing true positives) on the y axis.
We can see from the curve below that all three models are extremely
similar in their ratio of sensitivity to specificity, and hence have
almost identical AUC values. As mentioned above, we will utilize the
AIC-reduced model given that it was deemed the most accurate for our
previous association analysis.
######### Using a function to extract false positive and false negative values
TPR.FPR=function(pred){
prob.seq = seq(0,1, length=50) # 50 equally spaced cut-off probabilities
pn=length(prob.seq)
true.lab=as.vector(Training_Data$popular)
TPR = NULL
FPR = NULL
##
for (i in 1:pn){
pred.lab = as.vector(ifelse(pred >prob.seq[i],"yes", "no"))
TPR[i] = length(which(true.lab=="yes" & pred.lab=="yes"))/length(which(true.lab=="yes"))
FPR[i] = length(which(true.lab=="no" & pred.lab=="yes"))/length(which(true.lab=="no"))
}
cbind(FPR = FPR, TPR = TPR)
}
######### Calculating the AUC
if (!require("pROC")) {
install.packages("pROC")
library(pROC)
}
### Candidate Models
# Full Log Model
CVModel1 = glm(formula = popular ~ tempo + danceability + grp.speechiness + grp.instrumentalness + grp.duration_mins, family = binomial(link = "logit"),
data = train.dat)
# Manually Reduced Log Model
CVModel2 = glm(formula = popular ~ tempo + grp.instrumentalness + grp.duration_mins, family = binomial(link = "logit"),
data = train.dat)
# AIC Reduced (Final) Log Model
CVModel3 = stepAIC(CVModel1,
scope = list(lower=formula(CVModel2),upper=formula(CVModel1)),
direction = "forward", # forward selection
trace = 0 )
## predicted probabilities
pred01 = predict.glm(CVModel1, newdata = Training_Data, type="response")
pred02 = predict.glm(CVModel2, newdata = Training_Data, type="response")
pred03 = predict.glm(CVModel3, newdata = Training_Data, type="response")
####
## ROC curve
plot(TPR.FPR(pred01)[,1], TPR.FPR(pred01)[,2],
type="l", col="red", lty=1, lwd = 2, xlim=c(0,1), ylim=c(0,1),
xlab = "False Positive Rate (FPR)",
ylab ="True Positive Rate (TPR)",
main = "ROC curves of the three candidate models",
cex.main = 1.1,
col.main = "black")
lines(TPR.FPR(pred02)[,1], TPR.FPR(pred02)[,2], col="darkblue", lty=2, lwd = 2)
lines(TPR.FPR(pred03)[,1], TPR.FPR(pred03)[,2], col="black", lty=3, lwd = 2)
##
category = Training_Data$popular == "yes"
ROCobj01 <- roc(category, as.vector(pred01))
ROCobj02 <- roc(category, as.vector(pred02))
ROCobj03 <- roc(category, as.vector(pred03))
AUC01 = round(auc(ROCobj01),4)
AUC02 = round(auc(ROCobj02),4)
AUC03 = round(auc(ROCobj03),4)
##
legend("bottomright", c(paste("Full Log Model AUC = ",AUC01),
paste("Man Reduced Log Model AUC = ",AUC02),
paste("AIC Reduced Log Model AUC = ", AUC03)),
col=c("red","darkblue", "black"), lty=1:3, cex = 0.85, bty="n")

Predictive Modeling
Takeaways
To conclude, if someone had interest in predicting a song’s chance of
being popular given its length, instrumentalness and (to a minor extent)
tempo, they should utilize the AIC-reduced model that was formed in
section 3.3 above. I could see those most interested in this predictive
model being agents, record label executives and aspiring artists, all
attempting to “fix” their music to fit the mold of what tends to
commercially succeed on the world’s largest streaming platform.
LS0tCnRpdGxlOiAiQmluYXJ5IExvZ2lzdGljIFByZWRpY3RpdmUgTW9kZWxpbmcgb2YgYSBUcmFjaydzIExpa2VsaWhvb2QgdG8gYmUgUG9wdWxhciBvbiBTcG90aWZ5IgphdXRob3I6ICJDaHJpcyBCYWhtIgpkYXRlOiAiMjAyNS0xMC0yMyIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiB0cnVlCiAgICAgIHNtb290aF9zY3JvbGw6IHRydWUKICAgIHRvY19kZXB0aDogNAogICAgZmlnX3dpZHRoOiA2CiAgICBmaWdfaGVpZ2h0OiA0CiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIHRoZW1lOiBsdW1lbgogICAgaGlnaGxpZ2h0OiB0YW5nbwogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiA0CiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgd29yZF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiA0Ci0tLQoKYGBge2NzcywgZWNobyA9IEZBTFNFfQpkaXYjVE9DIGxpIHsgICAgIC8qIHRhYmxlIG9mIGNvbnRlbnQgICovCiAgICBsaXN0LXN0eWxlOnVwcGVyLXJvbWFuOwogICAgYmFja2dyb3VuZC1pbWFnZTpub25lOwogICAgYmFja2dyb3VuZC1yZXBlYXQ6bm9uZTsKICAgIGJhY2tncm91bmQtcG9zaXRpb246MDsKfQoKaDEudGl0bGUgeyAgICAvKiBsZXZlbCAxIGhlYWRlciBvZiB0aXRsZSAgKi8KICBmb250LXNpemU6IDI0cHg7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgY29sb3I6IERhcmtSZWQ7CiAgdGV4dC1hbGlnbjogY2VudGVyOwp9CgpoNC5hdXRob3IgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogIGZvbnQtc2l6ZTogMThweDsKICBmb250LXdlaWdodDogYm9sZDsKICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICBjb2xvcjogRGFya1JlZDsKICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KCmg0LmRhdGUgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogIGZvbnQtc2l6ZTogMThweDsKICBmb250LXdlaWdodDogYm9sZDsKICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICBjb2xvcjogRGFya0JsdWU7CiAgdGV4dC1hbGlnbjogY2VudGVyOwp9CgpoMSB7IC8qIEhlYWRlciAxIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgICBmb250LXNpemU6IDIwcHg7CiAgICBmb250LXdlaWdodDogYm9sZDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IGRhcmtyZWQ7CiAgICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KCmgyIHsgLyogSGVhZGVyIDIgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICAgIGZvbnQtc2l6ZTogMThweDsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogbmF2eTsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KCmgzIHsgLyogSGVhZGVyIDMgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICAgIGZvbnQtc2l6ZTogMTZweDsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogbmF2eTsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KCmg0IHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICAgIGZvbnQtc2l6ZTogMTRweDsKICBmb250LXdlaWdodDogYm9sZDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IGRhcmtyZWQ7CiAgICB0ZXh0LWFsaWduOiBsZWZ0Owp9CgovKiBBZGQgZG90cyBhZnRlciBudW1iZXJlZCBoZWFkZXJzICovCi5oZWFkZXItc2VjdGlvbi1udW1iZXI6OmFmdGVyIHsKICBjb250ZW50OiAiLiI7Cn0KYGBgCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KIyBjb2RlIGNodW5rIHNwZWNpZmllcyB3aGV0aGVyIHRoZSBSIGNvZGUsIHdhcm5pbmdzLCBhbmQgb3V0cHV0IAojIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIG91dHB1dCBmaWxlcy4KCmlmICghcmVxdWlyZSgia25pdHIiKSkgeyAgICAgICAgICAgICAgICAgICAgICAjIHVzZSBjb25kaXRpb25hbCBzdGF0ZW1lbnQgdG8gZGV0ZWN0CiAgIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikgICAgICAgICAgICAgICAgICAjIHdoZXRoZXIgYSBwYWNrYWdlIHdhcyBpbnN0YWxsZWQgaW4KICAgbGlicmFyeShrbml0cikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgeW91ciBtYWNoaW5lLiBJZiBub3QsIGluc3RhbGwgaXQgYW5kCn0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGxvYWQgaXQgdG8gdGhlIHdvcmtpbmcgZGlyZWN0b3J5LgoKaWYgKCFyZXF1aXJlKHRpZHl2ZXJzZSkpIHtsaWJyYXJ5KHRpZHl2c2Vyc2UpfSAKCmlmICghcmVxdWlyZShHR2FsbHkpKSB7bGlicmFyeShHR2FsbHkpfSAKCmlmICghcmVxdWlyZShrYWJsZUV4dHJhKSkge2xpYnJhcnkoa2FibGVFeHRyYSl9IAoKaWYgKCFyZXF1aXJlKGdncGxvdDIpKSB7bGlicmFyeShnZ3Bsb3QyKX0gCgppZiAoIXJlcXVpcmUoY2FyKSkge2xpYnJhcnkoY2FyKX0gCgppZiAoIXJlcXVpcmUoZHBseXIpKSB7bGlicmFyeShkcGx5cil9IAoKaWYgKCFyZXF1aXJlKHBhbmRlcikpIHtsaWJyYXJ5KHBhbmRlcil9IAoKaWYgKCFyZXF1aXJlKGNhcikpIHtsaWJyYXJ5KGNhcil9IAoKaWYgKCFyZXF1aXJlKCJzY2FsZXMiKSkgewppbnN0YWxsLnBhY2thZ2VzKCJzY2FsZXMiKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKbGlicmFyeSgic2NhbGVzIikgCn0KCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKCWVjaG8gPSBUUlVFLAoJbWVzc2FnZSA9IEZBTFNFLAoJd2FybmluZyA9IEZBTFNFLAoJY29tbWVudCA9IE5BLAoJcmVzdWx0cyA9IFRSVUUKKQogICAKYGBgCgojIEludHJvZHVjdGlvbiBhbmQgQmFja2dyb3VuZAoKSGVyZSB3ZSBoYXZlIGEgZGF0YXNldCBvcmlnaW5hbGx5IGNvbXBvc2VkIG9mIG92ZXIgNSwwMDAgc29uZ3MgdGhhdCB3ZXJlIGF2YWlsYWJsZSBvbiB0aGUgbXVzaWMtc3RyZWFtaW5nIHNlcnZpY2UgU3BvdGlmeSBvdmVyIHRoZSBjb3Vyc2Ugb2YgMjAyNC4gVGhlc2UgdHJhY2tzIHN0ZW0gZnJvbSBhIHdpZGUgYXJyYXkgb2YgdmFzdGx5IGRpZmZlcmVudCBnZW5yZXMgYW5kIHN0eWxlcyBvZiBjcmVhdGlvbi4gVGhlIGRhdGFzZXQgaXMgcHVibGljbHkgYXZhaWxhYmxlIG9uIHRoZSBwbGF0Zm9ybSBLYWdnbGUgYW5kIGlzIHByb3ZpZGVkIGluIHRoZSBSZWZlcmVuY2VzIHNlY3Rpb24gYmVsb3cuIEFsdGhvdWdoIHRoZSBkYXRhIG9yaWdpbmFsbHkgY29udGFpbmVkIDI5IHZhcmlhYmxlcywgb25seSAxMSBwbGF5IGEgcGFydGljdWxhcmx5IHJlbGV2YW50IHJvbGUgaW4gdGhlIGFuYWx5c2lzIEkgd2lzaCB0byBkbyBoZXJlLiBBIGJyZWFrZG93biBvZiB0aG9zZSB2YXJpYWJsZXMsIHRoZWlyIG1lYW5pbmdzIGFuZCBkYXRhIHR5cGVzIGlzIGJlbG93OgoKYGBge3IgVmFyaWFibGUgVGFibGUsIGVjaG89RkFMU0V9CmxpYnJhcnkoa25pdHIpCgpWYXJfVGFibGUgPSBkYXRhLmZyYW1lKAogIE5hbWUgPSBjKCJ0cmFja19wb3B1bGFyaXR5IiwgInBvcHVsYXIiLCAidHJhY2tfbmFtZSIsICJ0cmFja19hcnRpc3QiLCAicGxheWxpc3RfZ2VucmUiLCAicGxheWxpc3Rfc3ViZ2VucmUiLCAidGVtcG8iLCAiZGFuY2VhYmlsaXR5Iiwic3BlZWNoaW5lc3MiLCAiaW5zdHJ1bWVudGFsbmVzcyIsICJkdXJhdGlvbl9taW5zIiksCiAgCiAgTWVhbmluZyA9IGMoInNvbmcncyByYXRpbmcgb24gdGhlIDAgLSAxMDAgbWV0cmljIiwgImhvdyBwb3B1bGFyIHRoZSB0cmFjayBpcyAobW9yZSBvbiB0aGF0IGxhdGVyKSIsCiAgICAgICAgICAgICAgIm5hbWUgb2YgdGhlIHNvbmciLAogICAgICAgICAgICAgICJhcnRpc3QncyBzdGFnZSBuYW1lIiwgCiAgICAgICAgICAgICAgImdlbnJlIHRoYXQgU3BvdGlmeSBjbGFzc2lmaWVzIHRoZSBzb25nIGluIiwgCiAgICAgICAgICAgICAgInN1YmdlbnJlIHRoYXQgU3BvdGlmeSBjbGFzc2lmaWVzIHRoZSBzb25nIGluIiwgIAogICAgICAgICAgICAgICJ0aGUgc3BlZWQgb2YgYSB0cmFjaywgbWVhc3VyZWQgaW4gYmVhdHMgcGVyIG1pbnV0ZSAoQlBNKSIsIAogICAgICAgICAgICAgICJBIHNjb3JlIGRlc2NyaWJpbmcgaG93IHN1aXRhYmxlIGEgdHJhY2sgaXMgZm9yIGRhbmNpbmcgYmFzZWQgb24gdGVtcG8sIHJoeXRobSBzdGFiaWxpdHksIGJlYXQgc3RyZW5ndGggYW5kIG92ZXJhbGwgcmVndWxhcml0eSAoMCB0byAxIHNjYWxlKSIsIAogICAgICAgICAgICAgICJ0aGUgcHJlc2VuY2Ugb2YgYXVkaWJsZSB3b3JkcyAoMCB0byAxIHNjYWxlKSIsIAogICAgICAgICAgICAgICJsaWtlbGlob29kIHRoYXQgdGhlIHRyYWNrIGNvbnRhaW5zIGluc3RydW1lbnRhbHMgKDAgdG8gMSBzY2FsZSkgIiwgCiAgICAgICAgICAgICAgImxlbmd0aCBvZiB0cmFjayBpbiBtaW51dGVzIiksCiAgCiAgRGF0YV9UeXBlID0gYygiZG91YmxlIiwgImNoYXJhY3RlciIsICJjaGFyYWN0ZXIiLCAiY2hhcmFjdGVyIiwgImNoYXJhY3RlciIsICJjaGFyYWN0ZXIiLCAiZG91YmxlIiwgImRvdWJsZSIsICJkb3VibGUiLCAiZG91YmxlIiwgImRvdWJsZSIpCikKCmthYmxlKFZhcl9UYWJsZSkgJT4lCiAga2FibGVfc3R5bGluZygKICAgIGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJib3JkZXJlZCIpLAogICAgZnVsbF93aWR0aCA9IEZBTFNFLAogICAgcG9zaXRpb24gPSAiY2VudGVyIikKYGBgCgpNYW55IG9mIHRoZSBvdGhlciB2YXJpYWJsZXMgaW4gdGhlIGRhdGFzZXQgSSBjaG9zZSB0byBkaXNyZWdhcmQgYXMgdGhleSBlaXRoZXIgcGVydGFpbmVkIHRvIHVubmVjZXNzYXJ5IHRlY2huaWNhbCBpbmZvcm1hdGlvbiAoc3VjaCBhcyB0aGUgYWxnb3JpdGhtaWMgaWRlbnRpZmllciBmb3IgdGhlIHBhcnRpY3VsYXIgc29uZyBvciBpdHMgYWxidW0pLCBvciBleHRyZW1lbHkgbmljaGUgbXVzaWNhbCB0b3BpY3MgdGhhdCB0aGUgYXZlcmFnZSBsaXN0ZW5lciBvciBpbnRyb2R1Y3RvcnkgY3JpdGljIHdvdWxkIG1vc3QgbGlrZWx5IG5vdCBwaWNrIHVwIG9uIChzdWNoIGFzIG1vZGUgYW5kIGtleSkuCgojIyBPYmplY3RpdmUgZm9yIG15IEFuYWx5c2lzClVzaW5nIHRoaXMgZGF0YXNldCwgSSB3aXNoIHRvIHF1YW50aWZpYWJseSBleGFtaW5lIHdoYXQgbXVzaWNhbCBxdWFsaXRpZXMgYW5kIGNoYXJhY3RlcmlzdGljcyBsZWFkIHRvIGEgc29uZyAob3IgInRyYWNrIikgYmVjb21pbmcgZXh0cmVtZWx5IHN1Y2Nlc3NmdWwgKGhlbmNlIHBvcHVsYXIpIHZpYSBTcG90aWZ5LiBBcyBvZiBPY3RvYmVyIG9mIDIwMjUsIFNwb3RpZnkgaGFzIGEgbWFya2V0IGNhcCBvZiBvdmVyIDEzOSBiaWxsaW9uIGRvbGxhcnMgYW5kIGNsb3NlIHRvIDcwMCBtaWxsaW9uIHVzZXJzLiBUaGlzIG1lYW5zIHRoYXQgZm9yIGFueSBhc3BpcmluZyBtdXNpY2lhbiwgIm1ha2luZyBpdCBiaWciIG9uIFNwb3RpZnkgd291bGQgc2VydmUgYXMgYSBtb251bWVudGFsIGFuZCBsaWZlLWFsdGVyaW5nIG1pbGVzdG9uZS4gCgpTcG90aWZ5IGhhcyBhIG1ldHJpYyBrbm93biBhcyB0aGUgcG9wdWxhcml0eSBpbmRleCB3aGljaCBzZXJ2ZXMgdG8gbnVtZXJpY2FsbHkgcmVwcmVzZW50IHRoZSBwb3B1bGFyaXR5IG9mIHRyYWNrcyBvbiBpdHMgcGxhdGZvcm0uIFdoaWxlIHRoZSBleGFjdCBmb3JtdWxhIGJlaGluZCB0aGUgc2NvcmUgaXMga2VwdCBjb25maWRlbnRpYWwsIGNyaXRpY3MgaW4gdGhlIG11c2ljIGluZHVzdHJ5IGFuZCB0aG9zZSB3aXRoIHN0cm9uZyB0ZWNobmljYWwgYmFja2dyb3VuZHMgaGF2ZSB0aGVvcml6ZWQgdGhhdCB0aGUgcHJpbWFyeSBmYWN0b3JzIHdoaWNoIGluZmx1ZW5jZSBhIHRyYWNrJ3Mgc2NvcmUgYXJlIHRoZSBmb2xsb3dpbmc7IGl0cyB0b3RhbCBudW1iZXIgb2Ygc3RyZWFtcywgaXRzIHJlY2VudCBudW1iZXIgb2Ygc3RyZWFtcywgaXRzIG51bWJlciBvZiBkb3dubG9hZHMgYW5kIHNhdmVzLCBhbmQgaXRzIG1vbnRoLXRvLW1vbnRoIGdyb3d0aCBpbiBhbGwgdGhyZWUgb2Ygc2FpZCBtZXRyaWNzLgoKVGhpcyBwb3B1bGFyaXR5IGluZGV4IG9wZXJhdGVzIG9uIGEgc2NhbGUgcmFuZ2luZyBmcm9tIDAgdG8gMTAwLCB3aXRoIG9ubHkgdGhlIG1vc3Qgd2VsbC1lc3RhYmxpc2hlZCBzdGFycyByZWFjaGluZyB0aGUgOTB0aCBwZXJjZW50aWxlIGFuZCBoaWdoZXIuIFRoYXQgYmVpbmcgc2FpZCwgYW55IHRyYWNrIHdpdGggYSByYXRpbmcgb2YgNzUgb3IgaGlnaGVyIGlzIGxhcmdlbHkgY29uc2lkZXJlZCBhICJ0b3AgdHJhY2siIGJ5IGluZHVzdHJ5IGV4cGVydHMsIHNvIHRoYXQgaXMgdGhlIGludGVycHJldGF0aW9uIEkgd2lsbCBhcHBseSB3aXRoIG15IGFuYWx5c2lzLiBJIGNyZWF0ZWQgYSBjYXRlZ29yaWNhbCBiaW5hcnkgdmFyaWFibGUgInBvcHVsYXIiLCB3aGljaCBpcyB2YWx1ZWQgYXMgInllcyIgZm9yIHRyYWNrcyB3aXRoIGEgcG9wdWxhcml0eSBpbmRleCByYXRpbmcgb2YgNzUgb3IgaGlnaGVyLCBhbmQgIm5vIiBmb3IgdHJhY2tzIHdpdGggYSBsb3dlciByYXRpbmcuIEkgd2lsbCBwZXJmb3JtIGFzc29jaWF0aXZlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gdG8gYXNzZXNzIHdoaWNoLCBpZiBhbnksIG9mIHRoZSBmYWN0b3JzIG1lbnRpb25lZCBpbiBteSB2YXJpYWJsZSBicmVha2Rvd24gYWJvdmUgY29udHJpYnV0ZSB0byBhIHRyYWNrIGJlaW5nIGRlZW1lZCBwb3B1bGFyIG9yIG5vdC4gCgpGaW5hbGx5LCBhZnRlciBwZXJmb3JtaW5nIHNpbXBsZSBhbmQgbXVsdGlwbGUgbGluZWFyIHJlZ3Jlc3Npb24gcHJvY2Vzc2VzIHRvIGFuYWx5emUgdGhlIGFzc29jaWF0aW9uIGJldHdlZW4gYSB0cmFjaydzIHBvcHVsYXJpdHkgYW5kIGl0cyBzdGF0dXMgb2YgdGhlIHZhcmlhYmxlcyBJIGhhdmUgbGFpZCBvdXQsIEkgd2lsbCB0aGVuIHVzZSBwcmVkaWN0aXZlIG1vZGVsaW5nIHRlY2huaXF1ZXMgaW4gdGhlIGVmZm9ydCB0byBjcmVhdGUgYSBtb2RlbCB3aGljaCBjYW4gYWNjdXJhdGVseSBwcmVkaWN0IGEgcGFydGljdWxhciB0cmFjaydzIGxpa2VsaWhvb2Qgb2YgYmVpbmcgcG9wdWxhciBvbiBTcG90aWZ5LgoKYGBge3IgRGF0YSBSZWFkIGluIGFuZCBDbGVhbmluZywgaW5jbHVkZT1GQUxTRX0Kb3B0aW9ucyhzY2lwZW4gPSA5OTkpICMgT3V0IG9mIHNjaWVudGlmaWMgbm90YXRpb24sIHBlcnNvbmFsIHByZWZlcmVuY2UKCkRhdGFfVXJsX0EgPSAiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0NocmlzQjIzMjMvU1RBMzIxL3JlZnMvaGVhZHMvbWFpbi9oaWdoX3BvcHVsYXJpdHlfc3BvdGlmeV9kYXRhLmNzdiIKQWJvdmVfNjggPSByZWFkX2RlbGltKERhdGFfVXJsX0EsIGRlbGltID0gIiwiLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKQoKRGF0YV9VcmxfQiA9ICJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vQ2hyaXNCMjMyMy9TVEEzMjEvcmVmcy9oZWFkcy9tYWluL2xvd19wb3B1bGFyaXR5X3Nwb3RpZnlfZGF0YS5jc3YiCkJlbG93XzY4ID0gcmVhZF9kZWxpbShEYXRhX1VybF9CLCBkZWxpbSA9ICIsIiwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkKCgojIyMgTGluZSBiZWxvdyB3YXMgdXNlZCBmb3IgaW5pdGlhbCB2aXN1YWwgcHVycG9zZXMgCiNBYm92ZV82OCA9IEFib3ZlXzY4WywgYygidHJhY2tfbmFtZSIsICJ0cmFja19hbGJ1bV9uYW1lIiwgInRyYWNrX2FydGlzdCIsICJwbGF5bGlzdF9uYW1lIiwgInBsYXlsaXN0X2dlbnJlIiwgInBsYXlsaXN0X3N1YmdlbnJlIiwgInRyYWNrX3BvcHVsYXJpdHkiLCAiZW5lcmd5IiwgInRlbXBvIiwgImRhbmNlYWJpbGl0eSIsICJsb3VkbmVzcyIsICJsaXZlbmVzcyIsICJ2YWxlbmNlIiwgInNwZWVjaGluZXNzIiwgImluc3RydW1lbnRhbG5lc3MiLCAia2V5IiwgImR1cmF0aW9uX21zIiwgInRpbWVfc2lnbmF0dXJlIiwgInRyYWNrX2hyZWYiLCAibW9kZSIsICJ1cmkiLCAidHlwZSIsICJ0cmFja19hbGJ1bV9yZWxlYXNlX2RhdGUiLCAiYW5hbHlzaXNfdXJsIiwgImlkIiwgInRyYWNrX2FsYnVtX2lkIiwgInBsYXlsaXN0X2lkIiwgInRyYWNrX2lkIiwgImFjb3VzdGljbmVzcyIpXQoKCkRhdGEgPSByYmluZChBYm92ZV82OCwgQmVsb3dfNjgpCiAgRGF0YSRkdXJhdGlvbl9taW5zID0gRGF0YSRkdXJhdGlvbl9tcy82MDAwMApEYXRhJHBvcHVsYXIgPSBpZmVsc2UoRGF0YSR0cmFja19wb3B1bGFyaXR5ID4gNzUsICJ5ZXMiLCAibm8iKQoKRGF0YSA9IGRwbHlyOjpzZWxlY3QoRGF0YSwgdHJhY2tfcG9wdWxhcml0eSwgcG9wdWxhciwgdHJhY2tfbmFtZSwgdHJhY2tfYWxidW1fbmFtZSwgdHJhY2tfYXJ0aXN0LCBwbGF5bGlzdF9uYW1lLCBwbGF5bGlzdF9nZW5yZSwgcGxheWxpc3Rfc3ViZ2VucmUsIGVuZXJneSwgdGVtcG8sIGRhbmNlYWJpbGl0eSwgbG91ZG5lc3MsIGxpdmVuZXNzLCB2YWxlbmNlLCBzcGVlY2hpbmVzcywgaW5zdHJ1bWVudGFsbmVzcywga2V5LCBkdXJhdGlvbl9taW5zKQoKdW5pcXVlKERhdGEkcGxheWxpc3RfZ2VucmUpCgojIEJyZWFrZG93biBvZiBWYXJpYWJsZXMgS2VwdAogICAjIElkZW50aWZ5aW5nIFZhcmlhYmxlczoKICAgICAgICMgdHJhY2tfbmFtZQogICAgICAgIyB0cmFja19hbGJ1bV9uYW1lCiAgICAgICAjIHRyYWNrX2FydGlzdAogICAjIENhdGVnb3JpY2FsIEluZm86CiAgICAgICAjIHBsYXlsaXN0X25hbWUKICAgICAgICMgcGxheWxpc3RfZ2VucmUKICAgICAgICMgcGxheWxpc3Rfc3ViZ2VucmUKICAgICAgICMgKioqKiBwb3B1bGFyICoqKiogYmluYXJ5IHJlc3BvbnNlIHZhcmlhYmxlIHNlbGYtY3JlYXRlZAogICAjIFF1YW50aXRhdGl2ZSBJbmZvOgogICAgICAgIyB0cmFja19wb3B1bGFyaXR5CiAgICAgICAjIGVuZXJneQogICAgICAgIyB0ZW1wbwogICAgICAgIyBkYW5jZWFiaWxpdHkKICAgICAgICMgbG91ZG5lc3MKICAgICAgICMgbGl2ZW5lc3MKICAgICAgICMgdmFsZW5jZQogICAgICAgIyBzcGVlY2hpbmVzcwogICAgICAgIyBpbnN0cnVtZW50YWxuZXNzCiAgICAgICAjIGtleQogICAgICAgIyBkdXJhdGlvbl9tcwogICAKICAgICMgMTcgc2VsZWN0ZWQgYWJvdmUgZnJvbSBvcmlnaW5hbCBkYXRhIHNldCwgcGx1cyBwb3B1bGFyCiAgIAogICMgVmFyaWFibGVzIHdlIGFyZSBub3QgaW5jbHVkaW5nIGluIHJlZHVjZWQgZGF0YSBzZXQgYXJlIGxhcmdlbHkgdGVjaG5pY2FsIHRyYWNraW5nIHZhcmlhYmxlcyBzdWNoIGFzIGlkIGFuZCBhbmFseXNpc191cmwsIG9yIHZlcnkgbmljaGUgbXVzaWNhbCBtZXRyaWNzIHRoYXQgdGhlIGF2ZXJhZ2UgbGlzdGVuZXIgd291bGQgYmUgdW5hd2FyZSBvZiBzdWNoIGFzIG1vZGUuCgoKIyMjIyBDaGVja2luZyBmb3IgRHVwbGljYXRlczoKCkR1cGxpY2F0ZV9Tb25ncyA9IERhdGFbZHVwbGljYXRlZChEYXRhJHRyYWNrX25hbWUpIHwgZHVwbGljYXRlZChEYXRhJHRyYWNrX25hbWUsIGZyb21MYXN0ID0gVFJVRSksIF0KRHVwbGljYXRlX1NvbmdzX1JlZHVjZWQgPSBkcGx5cjo6c2VsZWN0KER1cGxpY2F0ZV9Tb25ncywgdHJhY2tfbmFtZSwgdHJhY2tfYXJ0aXN0LCBwbGF5bGlzdF9uYW1lLCBwbGF5bGlzdF9nZW5yZSwgcGxheWxpc3Rfc3ViZ2VucmUpCgpEdXBsaWNhdGVfU29uZ19Db3VudHMgPSBhcy5kYXRhLmZyYW1lKHRhYmxlKER1cGxpY2F0ZV9Tb25ncyR0cmFja19uYW1lKSkgICAKICAjIDgzNyBpbnN0YW5jZXMgb2YgdGhlIHNhbWUgc29uZyBiZWluZyBsaXN0ZWQgbW9yZSB0aGFuIG9uY2UKCm5hbWVzKER1cGxpY2F0ZV9Tb25nX0NvdW50cykgPSBjKCJ0cmFja19uYW1lIiwgImNvdW50IikKICAjIDM3OCBzb25ncyBsaXN0ZWQgbW9yZSB0aGFuIG9uY2UKCnN1bShEdXBsaWNhdGVfU29uZ19Db3VudHMkY291bnQpICAgIyBTdW0gZnVuY3Rpb24gY29uZmlybXMgdGhlcmUgYXJlIDgzNyB0b3RhbCByZXBlYXRzCgogIAojIEdvaW5nIHRvIHJlZHVjZSBtYWluIGRhdGFzZXQgdG8gb25seSBvbmUgb2JzZXJ2YXRpb24gcGVyIHNvbmcsIHVzZWQgYmFzZSBSIGZ1bmN0aW9uIHRvIGtlZXAgZmlyc3Qgb2NjdXJlbmNlIG9mIGVhY2ggc29uZwoKIyMjIyBOZXdfRGF0YSA9IG5vIGR1cGxpY2F0ZXMKTmV3X0RhdGEgPSBEYXRhWyFkdXBsaWNhdGVkKERhdGEkdHJhY2tfbmFtZSksIF0KCiMgR29pbmcgdG8gZWxpbWluYXRlIGdlbnJlcyB0aGF0IGFyZSBub3QgcHJldmFsZW50IGluIE5vcnRoIEFtZXJpY2EgYW5kIEV1cm9wZSwgYXMgbXkgYW5hbHlzaXMgd2lsbCBhcHBseSBsYXJnZWx5IHRvIGF1ZGllbmNlIGluIFdlc3Rlcm4gd29ybGQKCnVuaXF1ZShOZXdfRGF0YSRwbGF5bGlzdF9nZW5yZSkKCk5ld19EYXRhJFdlc3QgPSBpZmVsc2UoCiAgTmV3X0RhdGEkcGxheWxpc3RfZ2VucmUgJWluJSBjKCJicmF6aWxpYW4iLCAiYXJhYmljIiwgImluZGlhbiIsICJtYW5kb3BvcCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjYW50b3BvcCIsICJrLXBvcCIsICJ0dXJraXNoIiwgImtvcmVhbiIsICJqLXBvcCIsICJ3b3JsZCIsICJsYXRpbiIsICJlbGVjdHJvbmljIiksCiAgIm5vIiwKICAieWVzIgopCgp0YWJsZShOZXdfRGF0YSRXZXN0KQoKIyMjIyBOZXdfRGF0YTIgPSBDb25maW5lZCB0byBXZXN0ZXJuIG11c2ljIGdlbnJlcwpOZXdfRGF0YTIgPSBOZXdfRGF0YVtOZXdfRGF0YSRXZXN0IT0gIm5vIiwgXQpjb2xuYW1lcyhOZXdfRGF0YTIpCgojIyMjIFdvcmtfRGF0YSA9IFJlZHVjZWQgbnVtYmVyIG9mIHZhcmlhYmxlcyB0byBwZXJmb3JtIGFuYWx5c2lzIG9uLCBtaXNzaW5nIHZhbHVlIGNoZWNrcyBwZXJmb3JtZWQKV29ya19EYXRhID0gZHBseXI6OnNlbGVjdChOZXdfRGF0YTIsIHRyYWNrX3BvcHVsYXJpdHksIHBvcHVsYXIsIHRyYWNrX25hbWUsIHRyYWNrX2FydGlzdCwgcGxheWxpc3RfZ2VucmUsIHBsYXlsaXN0X3N1YmdlbnJlLCB0ZW1wbywgZGFuY2VhYmlsaXR5LCBzcGVlY2hpbmVzcywgaW5zdHJ1bWVudGFsbmVzcywgZHVyYXRpb25fbWlucykKCldvcmtfRGF0YSA9IHNvcnRfYnkoV29ya19EYXRhLCBXb3JrX0RhdGEkdHJhY2tfcG9wdWxhcml0eSwgZGVjcmVhc2luZz1UUlVFKQoKc3VtKGlzLm5hKFdvcmtfRGF0YSkpICMgNSBtaXNzaW5nIHZhbHVlcyBpbiBkYXRhc2V0CgpNaXNzaW5nX1Jvd3MgPSBXb3JrX0RhdGFbIWNvbXBsZXRlLmNhc2VzKFdvcmtfRGF0YSksIF0KICMgQWxsIDUgbWlzc2luZyB2YWx1ZXMgY29tZSBmcm9tIG9uZSBvYnNlcnZhdGlvbiwgdGhlIHNvbmcgaXMgIk1ha2UgSXQiIGJ5IEJlcmhhbmlvLiBJIHdpbGwganVzdCByZW1vdmUgdGhpcyBzb25nIGZyb20gdGhlIGRhdGFzZXQgdXNpbmcgZmlsdGVyIGZ1bmN0aW9uIGJlbG93LgoKV29ya19EYXRhID0gZmlsdGVyKFdvcmtfRGF0YSwgdHJhY2tfbmFtZSAhPSAiTWFrZSBJdCIgKQoKICB0cmFja19wb3B1bGFyaXR5ID0gV29ya19EYXRhJHRyYWNrX3BvcHVsYXJpdHkgCiAgcG9wdWxhciA9IFdvcmtfRGF0YSRwb3B1bGFyCiAgdHJhY2tfbmFtZSA9IFdvcmtfRGF0YSR0cmFja19uYW1lCiAgdHJhY2tfYXJ0aXN0ID0gV29ya19EYXRhJHRyYWNrX2FydGlzdAogIHBsYXlsaXN0X2dlbnJlID0gV29ya19EYXRhJHBsYXlsaXN0X2dlbnJlCiAgcGxheWxpc3Rfc3ViZ2VucmUgPSBXb3JrX0RhdGEkcGxheWxpc3Rfc3ViZ2VucmUKICB0ZW1wbyA9IFdvcmtfRGF0YSR0ZW1wbwogIGRhbmNlYWJpbGl0eSA9IFdvcmtfRGF0YSRkYW5jZWFiaWxpdHkKICBzcGVlY2hpbmVzcyA9IFdvcmtfRGF0YSRzcGVlY2hpbmVzcwogIGluc3RydW1lbnRhbG5lc3MgPSBXb3JrX0RhdGEkaW5zdHJ1bWVudGFsbmVzcwogIGR1cmF0aW9uX21pbnMgPSBXb3JrX0RhdGEkZHVyYXRpb25fbWlucwogIApRdWFudGl0YXRpdmVfVmFyaWFibGVzID0gY2JpbmQodGVtcG8sIGRhbmNlYWJpbGl0eSwgc3BlZWNoaW5lc3MsIGluc3RydW1lbnRhbG5lc3MsIGR1cmF0aW9uX21pbnMpCgpDYXRlZ29yaWNhbF9WYXJpYWJsZXMgPSBjYmluZChwbGF5bGlzdF9nZW5yZSwgcGxheWxpc3Rfc3ViZ2VucmUpCiAKYGBgCgojIFNpbXBsZSBMb2dpc3RpYyBSZWdyZXNzaW9uIE1vZGVsCgojIyBDaGVja2luZyBmb3IgUGFpcndpc2UgUmVsYXRpb25zaGlwcwpCZWZvcmUganVtcGluZyBpbnRvIG1vZGVsIGNyZWF0aW9uLCBJIGNyZWF0ZWQgYSBjb3JyZWxhdGlvbiBtYXRyaXggZm9yIHRoZSBxdWFudGl0YXRpdmUgcHJlZGljdG9yIHZhcmlhYmxlcyBJIGFtIGdvaW5nIHRvIHVzZSBpbiBteSBhbmFseXNpcy4gVGhpcyBpcyBiZWNhdXNlIHZhcmlhYmxlcyB3aXRoIHZlcnkgaGlnaCBjb3JyZWxhdGlvbnMgKHIgPj0gMC44KSBvZnRlbiBjYW4gZnVuY3Rpb24gYXMgYWxtb3N0IG11bHRpcGxlcyBvZiBvbmUgYW5vdGhlciwgbGVhZGluZyB0byBpbmFjY3VyYXRlIGNvbmNsdXNpb25zLCBlc3BlY2lhbGx5IHdoZW4gcGVyZm9ybWluZyBtdWx0aXBsZSByZWdyZXNzaW9uLgpgYGB7cn0KY29yX21hdHJpeCA9IGNvcihRdWFudGl0YXRpdmVfVmFyaWFibGVzKQogICMgTm8gaGlnaCBjb3JyZWxhdGlvbnMgYmV0d2VlbiB0aGUgdmFyaWFibGVzCgprYWJsZShjb3JfbWF0cml4LCBjYXB0aW9uID0gIkNvcnJlbGF0aW9uIE1hdHJpeCIpCmBgYAoKQWZ0ZXIgY3JlYXRpbmcgYSBjb3JyZWxhdGlvbiBtYXRyaXgsIHdlIGNhbiBzZWUgdGhhdCBub25lIG9mIHRoZSBxdWFudGl0YXRpdmUgcHJlZGljdG9yIHZhcmlhYmxlcyB0aGF0IHdlIGFyZSBleGFtaW5pbmcgaGF2ZSBhIGhpZ2ggY29ycmVsYXRpb24gd2l0aCBvbmUgYW5vdGhlci4gUHJhY3RpY2FsbHkgc3BlYWtpbmcsIHRoaXMgaXMgbm90IHZlcnkgc3VycHJpc2luZyBhcyBldmVuICJzaW1pbGFyIiBzb25ncyBieSB0aGUgc2FtZSBhcnRpc3Qgb3Igd2l0aGluIHRoZSBzYW1lIGdlbnJlIGNhbiBoYXZlIHdpbGRseSBkaWZmZXJlbnQgY2hhcmFjdGVyaXN0aWNzIHdoZW4gaXQgY29tZXMgdG8gdGVtcG8gb3IgYW55dGhpbmcgZWxzZSB3ZSBhcmUgbG9va2luZyBhdC4KCgojIyBQaWNraW5nIFZhcmlhYmxlIGZvciBTaW1wbGUgTW9kZWwKQmVsb3cgSSBjcmVhdGVkIGhpc3RvZ3JhbXMgdG8gcmVwcmVzZW50IHRoZSBkaXN0cmlidXRpb25zIG9mIGFsbCBmaXZlIHF1YW50aXRhdGl2ZSB2YXJpYWJsZXMgSSBhbSBnb2luZyB0byB1c2UgaW4gdGhpcyBhbmFseXNpcy4gVGhlIHB1cnBvc2UgZm9yIGRvaW5nIHN1Y2ggaXMgdG8gZGV0ZXJtaW5lIGlmIGFueSBzb3J0IG9mIHZhcmlhYmxlIG1hbmlwdWxhdGlvbiBpcyBuZWNlc3NhcnkgYmVmb3JlIHVzaW5nIHRoZSB2YXJpYWJsZSBpbiBvdXIgbG9naXN0aWMgbW9kZWwuCmBgYHtyfQpwYXIobWZyb3cgPSBjKDIsIDMpLCBtYXIgPSBjKDQsIDQsIDIsIDEpKSAgIyBtYXIgY29udHJvbHMgbWFyZ2lucyAKICAKICAKeWxpbWl0ID0gbWF4KGRlbnNpdHkoV29ya19EYXRhJHRlbXBvKSR5KQpoaXN0KFdvcmtfRGF0YSR0ZW1wbywgcHJvYmFiaWxpdHkgPSBUUlVFLCBtYWluID0gIlRlbXBvIERpc3RyaWJ1dGlvbiIsIHhsYWI9IlRlbXBvIiwgCiAgICAgICBjb2wgPSAiYXp1cmUxIiwgYm9yZGVyPSJsaWdodHNlYWdyZWVuIikKICBsaW5lcyhkZW5zaXR5KFdvcmtfRGF0YSR0ZW1wbywgYWRqdXN0PTIpLCBjb2w9ImJsdWUiKSAKCnlsaW1pdCA9IG1heChkZW5zaXR5KFdvcmtfRGF0YSRkYW5jZWFiaWxpdHkpJHkpCmhpc3QoV29ya19EYXRhJGRhbmNlYWJpbGl0eSwgcHJvYmFiaWxpdHkgPSBUUlVFLCBtYWluID0gIkRhbmNlYWJpbGl0eSBEaXN0cmlidXRpb24iLCB4bGFiPSJEYW5jZWFiaWxpdHkiLCAKICAgICAgIGNvbCA9ICJhenVyZTEiLCBib3JkZXI9ImxpZ2h0c2VhZ3JlZW4iKQogIGxpbmVzKGRlbnNpdHkoV29ya19EYXRhJGRhbmNlYWJpbGl0eSwgYWRqdXN0PTIpLCBjb2w9ImJsdWUiKSAKICAKeWxpbWl0ID0gbWF4KGRlbnNpdHkoV29ya19EYXRhJHNwZWVjaGluZXNzKSR5KQpoaXN0KFdvcmtfRGF0YSRzcGVlY2hpbmVzcywgcHJvYmFiaWxpdHkgPSBUUlVFLCBtYWluID0gIlNwZWVjaGluZXNzIERpc3RyaWJ1dGlvbiIsIHhsYWI9IlNwZWVjaGluZXNzIiwgCiAgICAgICBjb2wgPSAiYXp1cmUxIiwgYm9yZGVyPSJsaWdodHNlYWdyZWVuIikKICBsaW5lcyhkZW5zaXR5KFdvcmtfRGF0YSRzcGVlY2hpbmVzcywgYWRqdXN0PTIpLCBjb2w9ImJsdWUiKSAKICAKICAKeWxpbWl0ID0gbWF4KGRlbnNpdHkoV29ya19EYXRhJGluc3RydW1lbnRhbG5lc3MpJHkpCmhpc3QoV29ya19EYXRhJGluc3RydW1lbnRhbG5lc3MsIHByb2JhYmlsaXR5ID0gVFJVRSwgbWFpbiA9ICJJbnN0cnVtZW50YWxuZXNzIERpc3RyaWJ1dGlvbiIsIHhsYWI9Ikluc3RydW1lbnRhbG5lc3MiLCAKICAgICAgIGNvbCA9ICJhenVyZTEiLCBib3JkZXI9ImxpZ2h0c2VhZ3JlZW4iKQogIGxpbmVzKGRlbnNpdHkoV29ya19EYXRhJGluc3RydW1lbnRhbG5lc3MsIGFkanVzdD0yKSwgY29sPSJibHVlIikgCiAgCiAgCnlsaW1pdCA9IG1heChkZW5zaXR5KFdvcmtfRGF0YSRkdXJhdGlvbl9taW5zKSR5KQpoaXN0KFdvcmtfRGF0YSRkdXJhdGlvbl9taW5zLCBwcm9iYWJpbGl0eSA9IFRSVUUsIG1haW4gPSAiTGVuZ3RoIChtaW5zKSBEaXN0cmlidXRpb24iLCB4bGFiPSJMZW5ndGggKG1pbnMpIiwgCiAgICAgICBjb2wgPSAiYXp1cmUxIiwgYm9yZGVyPSJsaWdodHNlYWdyZWVuIikKICBsaW5lcyhkZW5zaXR5KFdvcmtfRGF0YSRkdXJhdGlvbl9taW5zLCBhZGp1c3Q9MiksIGNvbD0iYmx1ZSIpIAoKCmBgYAoKV2UgY2FuIHNlZSBmcm9tIHRoZSBoaXN0b2dyYW1zIHRoYXQgdGhlcmUgaXMgYW4gZXh0cmVtZSBza2V3IGluIHNwZWVjaGluZXNzLCBpbnN0cnVtZW50YWxuZXNzIGFuZCBsZW5ndGguIFdoaWxlIHRoZXJlIGFyZSBzbGlnaHQgc2tld3MgaW4gdGVtcG8gYW5kIGRhbmNlYWJpbGl0eSwgdGhleSBhcmUgKmZhciogbW9yZSBtb2RlcmF0ZS4gU2luY2UgdGVtcG8gYXBwZWFycyB0byBiZSB0aGUgbGVhc3Qgc2tld2VkIG9mIHRoZSB2YXJpYWJsZXMsIGFuZCBpdCdzIGNhbGN1bGF0aW9uIGlzIHRoZSBtb3N0IHN0cmFpZ2h0Zm9yd2FyZCAoYSBzaW1wbGUgbWVhc3VyZSBvZiBiZWF0cyBwZXIgbWludXRlKSwgSSB3aWxsIHVzZSB0ZW1wbyB0byBwZXJmb3JtIG15IHNpbXBsZSBsb2dpc3RpYyByZWdyZXNzaW9uLgoKCiMjIENyZWF0aW5nIHRoZSBTaW1wbGUgTW9kZWwKVXNpbmcgYnVpbHQtaW4gUiBmdW5jdGlvbnMsIEkgY3JlYXRlZCBhIHNpbXBsZSBiaW5hcnkgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbCwgaW4gd2hpY2ggdGhlIHRlbXBvIG9mIGEgc29uZyBpcyBtZWFudCB0byBwcmVkaWN0IHdoZXRoZXIgb3Igbm90IHRoYXQgdHJhY2sgaXMgcG9wdWxhciBvciBub3QgKHBvcHVsYXJpdHkgc2NvcmUgb2YgNzUgb3Igbm90KS4gSW4gdGhlIGNhbGN1bGF0aW9ucywgdGhlIGJhc2UgbGV2ZWwsIG9yIDAsIHdhcyBzdG9yZWQgZm9yIGluc3RhbmNlcyBvZiBhIHRyYWNrJ3MgcG9wdWxhcml0eSBiZWluZyBtYXJrZWQgYXMgIm5vIi4gV2hpbGUgdGhlIGluc3RhbmNlIGxldmVsLCBvciAxLCB3YXMgc3RvcmVkIGZvciBpbnN0YW5jZXMgb2YgYSB0cmFjaydzIHBvcHVsYXJpdHkgYmVpbmcgbWFya2VkIGFzICJ5ZXMiLgpgYGB7ciwgaW5jbHVkZT1GQUxTRX0KIyBDb252ZXJ0IHRoZSBjaGFyYWN0ZXIgdmFsdWVzIHRvIGZhY3RvcnMsIG5lY2Vzc2FyeSBmb3IgZ2xtIGZ1bmN0aW9uIHRvIHdvcmsKV29ya19EYXRhJHBvcHVsYXIgPSBmYWN0b3IoV29ya19EYXRhJHBvcHVsYXIsIGxldmVscyA9IGMoIm5vIiwgInllcyIpKQogIGludmlzaWJsZShzdHIoV29ya19EYXRhJHBvcHVsYXIpKQogIGludmlzaWJsZSh1bmlxdWUoV29ya19EYXRhJHBvcHVsYXIpKQpgYGAKYGBge3J9ClNpbXBsZV9Mb2dfTW9kZWwgPSBnbG0oZm9ybXVsYSA9IHBvcHVsYXIgfiB0ZW1wbywgZmFtaWx5ID0gYmlub21pYWwobGluayA9ICJsb2dpdCIpLCAKICAgIGRhdGEgPSBXb3JrX0RhdGEpCgppbnZpc2libGUoc3VtbWFyeShTaW1wbGVfTG9nX01vZGVsKSkKClNpbXBsZV9Mb2dfTW9kZWxfQ29lZl9TdW1tYXJ5ID0gc3VtbWFyeShTaW1wbGVfTG9nX01vZGVsKSRjb2VmICAgICAgICMgb3V0cHV0IHN0YXRzIG9mIGNvZWZmaWNpZW50cwpTaW1wbGVfQ29uZmlkZW5jZV9JbnRlcnZhbCA9IGNvbmZpbnQoU2ltcGxlX0xvZ19Nb2RlbCkgICAgICAgICAgICAgICAgICAgICAjIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIG9mIGJldGFzClNpbXBsZV9TdW1tYXJ5X1N0YXRzID0gY2JpbmQoU2ltcGxlX0xvZ19Nb2RlbF9Db2VmX1N1bW1hcnksIFNpbXBsZV9Db25maWRlbmNlX0ludGVydmFsLjk1PVNpbXBsZV9Db25maWRlbmNlX0ludGVydmFsKSAgICMgcm91bmRpbmcgb2ZmIGRlY2ltYWxzCmthYmxlKFNpbXBsZV9TdW1tYXJ5X1N0YXRzLGNhcHRpb24gPSAiU2ltcGxlIExvZ2lzdGljIFJlZ3Jlc3Npb24gTW9kZWwgU3VtbWFyeSIpICAKYGBgClRoZSBzdW1tYXJ5IG9mIG91ciBtb2RlbCBhYm92ZSBsZWFkcyB1cyB0byBiZWxpZXZlIHRoYXQgYSB0cmFjaydzIHRlbXBvIGRvZXMgaGF2ZSBhIHBvc2l0aXZlIGFzc29jaWF0aW9uIHdpdGggdGhlIGxpa2VsaWhvb2QgdGhhdCBhIHRyYWNrIGlzIHBvcHVsYXIgb24gU3BvdGlmeSwgaG93ZXZlciB0aGF0IGFzc29jaWF0aW9uIGlzIHZlcnkgc21hbGwgaW4gcHJhY3RpY2FsIGVmZmVjdC4gRGVzcGl0ZSBhIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgcCB2YWx1ZSwgJFxiZXRhJH4xfiBoYXMgYW4gZXN0aW1hdGVkIGFzc29jaWF0aW9uIHdpdGggdGhlIHByb2JhYmlsaXR5IG9mIGEgdHJhY2sgYmVpbmcgZGVlbWVkIHBvcHVsYXIgb2YgLjAwNiwgYW5kIGEgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgZGVlbWluZyB0aGUgYXNzb2NpYXRpb24gdG8gZmFsbCBiZXR3ZWVuIHRoZSBpbnRlcnZhbCBbLjAwMywgLjAwOV0uCgoKIyMgT2RkcyBSYXRpbyBTdW1tYXJ5CldoaWxlIHRoZSBkaXJlY3QgaW50ZXJwcmV0YXRpb24gb2YgYSBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsJ3Mgc3VtbWFyeSBzdGF0aXN0aWNzIGNhbiBiZSBoZWxwZnVsLCBpdCBpcyBzb21ldGltZXMgbW9yZSBwcmFjdGljYWwgdG8gZXhhbWluZSBvdXIgbW9kZWwncyBvZGRzIHJhdGlvLiBBbiBvZGRzIHJhdGlvIHJlcHJlc2VudHMgdGhlIGxpa2VsaWhvb2Qgb2Ygc3VjY2VzcyBkaXZpZGVkIGJ5IHRoZSBsaWtlbGlob29kIG9mIGZhaWx1cmUuIEZvciBleGFtcGxlLCBhbiBvZGRzIHJhdGlvIG9mIDIgd291bGQgbWVhbiB0aGF0IHdoYXRldmVyIGluc3RhbmNlIHdlIGFyZSBjb25zaWRlcmluZyBhICJzdWNjZXNzIiBvY2N1cnMgdHdpY2UgdGhlIG51bWJlciBvZiB0aW1lcyB0aGFuIGl0IGZhaWxzIHRvIG9jY3VyLgpgYGB7cn0KIyBPZGRzIHJhdGlvClNpbXBsZV9Mb2dfTW9kZWxfQ29lZl9TdW1tYXJ5ID0gc3VtbWFyeShTaW1wbGVfTG9nX01vZGVsKSRjb2VmCk9kZHNfUmF0aW8gPSBleHAoY29lZihTaW1wbGVfTG9nX01vZGVsKSkKb3V0LnN0YXRzID0gY2JpbmQoU2ltcGxlX0xvZ19Nb2RlbF9Db2VmX1N1bW1hcnksIG9kZHMucmF0aW8gPSBPZGRzX1JhdGlvKSAgICAgICAgICAgICAgICAgCmthYmxlKG91dC5zdGF0cyxjYXB0aW9uID0gIlNpbXBsZSBSZWdyZXNzaW9uIE1vZGVsIENvZWZmaWNpZW50cyBXLyBPZGRzIFJhdGlvcyIpCmBgYApUaGUgb2RkcyByYXRpbyBiZXR3ZWVuIGEgdHJhY2sncyB0ZW1wbyBhbmQgaXQncyBwb3B1bGFyaXR5IHN0YXR1cyBpcyB+IDEuMDA2LiBTaW5jZSB0ZW1wbyBpcyBtZWFzdXJlZCBpbiBiZWF0cyBwZXIgbWludXRlIChCUE0pLCB0aGlzIG1lYW5zIHRoYXQgZm9yIGV2ZXJ5IGFkZGl0aW9uYWwgYmVhdCBwZXIgbWludXRlIHRoYXQgYSBzb25nIGlzIHJlY29yZGVkIGluLCBpdCdzIHByb2JhYmlsaXR5IG9mIGhhdmluZyBhIHBvcHVsYXJpdHkgc2NvcmUgYWJvdmUgNzUgaW5jcmVhc2VzIGJ5IGFib3V0IDAuNiUuCgojIyBHb29kbmVzcy1vZi1maXQgbWVhc3VyZXMKQmVsb3cgSSBjYWxjdWxhdGVkIHRoZSBnb29kbmVzcy1vZi1maXQgKEdPRikgbWVhc3VyZXMgZm9yIHRoZSBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsLiBHZW5lcmFsbHkgc3BlYWtpbmcsIGl0IGlzIGJlbmVmaWNpYWwgdG8gZmluZCBhIG1vZGVsJ3MgR09GIGZlYXR1cmVzIGFzIHRoZXkgc2VydmUgYXMgcmVsYXRpdmUgY29tcGFyaXNvbnMgb2YgbW9kZWwgZWZmaWNpZW5jeSB3aGVuIGNvbXBhcmluZyBtdWx0aXBsZSBtb2RlbHMuIEluIHRoaXMgaW5zdGFuY2UsIHdlIG9ubHkgY3JlYXRlZCBvbmUgbW9kZWwgc28gZmFyLCBzbyB0aGUgbWVhc3VyZXMgYXJlIG5vdCBvZiBwcmFjdGljYWwgdXNlIGF0IHRoZSBtb21lbnQuCmBgYHtyfQpSZXNpZHVhbF9EZXZpYW5jZSA9IFNpbXBsZV9Mb2dfTW9kZWwkZGV2aWFuY2UKTnVsbF9SZXNpZHVhbF9EZXZpYW5jZSA9IFNpbXBsZV9Mb2dfTW9kZWwkbnVsbC5kZXZpYW5jZQphaWMgPSBTaW1wbGVfTG9nX01vZGVsJGFpYwpHb29kbmVzc19PZl9GaXQgPSBjYmluZChEZXZpYW5jZS5yZXNpZHVhbCA9IFJlc2lkdWFsX0RldmlhbmNlLCBOdWxsLkRldmlhbmNlLlJlc2lkdWFsID0gTnVsbF9SZXNpZHVhbF9EZXZpYW5jZSwKICAgICAgQUlDID0gYWljKQpwYW5kZXIoR29vZG5lc3NfT2ZfRml0KQoKYGBgCgojIyBTdWNjZXNzIFByb2JhYmlsaXR5IEN1cnZlCkJlbG93IEkgY3JlYXRlZCBhIHZpc3VhbCBvZiB0aGUgdGhlIG1vZGVsJ3MgUyBjdXJ2ZSAoYWxzbyBjYWxsZWQgc3VjY2VzcyBwcm9iYWJpbGl0eSBjdXJ2ZSBvciBsb2dpc3RpYyBjdXJ2ZSkuIFRoZSBTIGN1cnZlIGhlbHBzIHVzIHNlZSB0aGUgY2hhbmdlIGluIHByb2JhYmlsaXR5IG9mIGFuIGV2ZW50IGhhcHBlbmluZyAoYSB0cmFjayBiZWluZyBwb3B1bGFyIG9yIG5vdCBvbiBTcG90aWZ5KSwgaW4gcmVsYXRpb24gdG8gYSBjaGFuZ2UgaW4gdGhlIHZhbHVlIG9mIGEgcHJlZGljdG9yIHZhcmlhYmxlICh0ZW1wbyBpbiBCUE0gaW4gdGhpcyBpbnN0YW5jZSkuCmBgYHtyfQojIyMKCnRlbXBvX3JhbmdlID0gcmFuZ2UoV29ya19EYXRhJHRlbXBvKQp4ID0gc2VxKHRlbXBvX3JhbmdlWzFdLCB0ZW1wb19yYW5nZVsyXSwgbGVuZ3RoID0gMjAwKQpiZXRhLnggPSBjb2VmKFNpbXBsZV9Mb2dfTW9kZWwpWzFdICsgY29lZihTaW1wbGVfTG9nX01vZGVsKVsyXSp4CnN1Y2Nlc3MucHJvYiA9IGV4cChiZXRhLngpLygxK2V4cChiZXRhLngpKQpmYWlsdXJlLnByb2IgPSAxLygxK2V4cChiZXRhLngpKQp5bGltaXQgPSBtYXgoc3VjY2Vzcy5wcm9iLCBmYWlsdXJlLnByb2IpCiMjCmJldGExID0gY29lZihTaW1wbGVfTG9nX01vZGVsKVsyXQpzdWNjZXNzLnByb2IucmF0ZSA9IGJldGExKmV4cChiZXRhLngpLygxK2V4cChiZXRhLngpKV4yCiMjCiMjCnBhcihtZnJvdyA9IGMoMSwxKSkKcGxvdCh4LCBzdWNjZXNzLnByb2IsIHR5cGUgPSAibCIsIGx3ZCA9IDIsIGNvbCA9ICJibGFjayIsCiAgICAgbWFpbiA9ICJUaGUgUHJvYmFiaWxpdHkgb2YgYSBUcmFjayBCZWluZyBcbiBDb25zaWRlcmVkIFBvcHVsYXIgb24gU3BvdGlmeSIsIAogICAgIHlsaW09YygwLCAxLjEqeWxpbWl0KSwKICAgICB4bGFiID0gIlRlbXBvIChCUE0pIiwKICAgICB5bGFiID0gInByb2JhYmlsaXR5IiwKICAgICBheGVzID0gRkFMU0UsCiAgICAgY29sLm1haW4gPSAiYmxhY2siLAogICAgIGNleC5tYWluID0gMS4xKQojIGxpbmVzKHgsIGZhaWx1cmUucHJvYixsd2QgPSAyLCBjb2wgPSAiZGFya3JlZCIpCmF4aXMoMSwgcG9zID0gMCkKYXhpcygyKQoKIyMKeS5yYXRlID0gbWF4KHN1Y2Nlc3MucHJvYi5yYXRlKQpwbG90KHgsIHN1Y2Nlc3MucHJvYi5yYXRlLCB0eXBlID0gImwiLCBsd2QgPSAyLCBjb2wgPSAiYmxhY2siLAogICAgIG1haW4gPSAiVGhlIFJhdGUgb2YgQ2hhbmdlIGluIFByb2JhYmlsaXR5IG9mIGEgVHJhY2sgQmVpbmcgXG4gQ29uc2lkZXJlZCBQb3B1bGFyIG9uIFNwb3RpZnkiLCAKICAgICB4bGFiID0gIlRlbXBvIChCUE0pIiwKICAgICB5bGFiID0gIlJhdGUgb2YgQ2hhbmdlIiwKICAgICB5bGltPWMoMCwxLjEqeS5yYXRlKSwKICAgICBheGVzID0gRkFMU0UsCiAgICAgY29sLm1haW4gPSAiYmxhY2siLAogICAgIGNleC5tYWluID0gMS4xCiAgICAgKQpheGlzKDEsIHBvcyA9IDApCmF4aXMoMikKYGBgCgpUaGUgUyBDdXJ2ZSBwcm92aWRlcyB2aXN1YWwgY29uZmlybWF0aW9uIG9mIHRoZSBjb25jbHVzaW9ucyB3ZSB3ZXJlIGFibGUgdG8gZHJhdyBmcm9tIGFuYWx5emluZyBvdXIgY29lZmZpY2llbnQgc3VtbWFyeSwgY29uZmlkZW5jZSBpbnRlcnZhbHMgYW5kIG9kZHMgcmF0aW8uIFRoYXQgaXMsIHRoYXQgdGhlcmUgaXMgYSBwb3NpdGl2ZSBhc3NvY2lhdGlvbiBiZXR3ZWVuIGEgdHJhY2sncyB0ZW1wbyBhbmQgaXQncyBsaWtlbGlob29kIG9mIGJlaW5nIGEgcG9wdWxhciB0cmFjayBvbiBTcG90aWZ5LCAqKmJ1dCoqIHRoYXQgYXNzb2NpYXRpb24gaXMgdmVyeSBtaW5pbWFsIGluIHByYWN0aWNhbCBlZmZlY3QuCgpXZSBjYW4gc2VlIGZyb20gb3VyIHNlY29uZCBwbG90LCB0aGF0IGxvb2tlZCBhdCB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHJhdGUgb2YgY2hhbmdlIGluIHNhaWQgcHJvYmFiaWxpdHkgYW5kIGEgdHJhY2sncyB0ZW1wbywgdGhhdCBmcm9tIDUwIHRvIDIwMCBiZWF0cyBwZXIgbWludXRlLCB0aGUgcHJvYmFiaWxpdHkgb2YgYSB0cmFjayBiZWluZyBwb3B1bGFyJ3MgcG9zaXRpdmUgcmF0ZSBvZiBjaGFuZ2Ugb25seSBpbmNyZWFzZXMgZnJvbSAwLjAwMDYgdG8gMC4wMDEyLgoKIyMgVGFrZWF3YXlzIGZyb20gU2ltcGxlIExvZ2lzdGljIFJlZ3Jlc3Npb24gTW9kZWwKVG8gY29uY2x1ZGUsIHdlIGNhbiBzYXkgdGhhdCBhbHRob3VnaCB0aGVyZSBpcyBhIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgYW5kIHBvc2l0aXZlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGEgdHJhY2sncyB0ZW1wbyBhbmQgdGhlIHByb2JhYmlsaXR5IHRoYXQgaXQgaXMgcG9wdWxhciBvbiBTcG90aWZ5LCB0aGF0IGFzc29jaWF0aW9uIGlzIG9mIHN1Y2ggYSBzbWFsbCBtYWduaXR1ZGUgdGhhdCBpdCBpcyByZWxhdGl2ZWx5IGEgbm9uLWZhY3RvciBpbiBwcmFjdGljYWwgc2Vuc2UuIFRoZXJlZm9yZSwgaXQgd291bGQgYmUgb3Zlcmx5IHNpbXBsaXN0aWMgYW5kIGh5cGVyYm9saWMgZm9yIG11c2ljIGxhYmVscyBvciBhZ2VudHMgdG8gYWdncmVzc2l2ZWx5IHB1c2ggdGhlaXIgYXJ0aXN0cyB0b3dhcmRzIGEgbW9yZSB1cC10ZW1wbyBwcm9kdWN0aW9uLCBhcyB0aGUgcmV0dXJuIG9uIHN1Y2ggYSBkZWNpc2lvbiB3b3VsZCBsaWtlbHkgbm90IGJlIHdvcnRoIHRoZSBjb3N0IG9mIHNvdXJpbmcgdGhlIHJlbGF0aW9uc2hpcCB3aXRoIHRoZSBhcnRpc3QgYXQgaGFuZC4gCgojIE11bHRpcGxlIExvZ2lzdGljIFJlZ3Jlc3Npb24gTW9kZWwKQXMgd2Ugc2F3IGVhcmxpZXIgd2hlbiBjcmVhdGluZyBvdXIgc2ltcGxlIHJlZ3Jlc3Npb24gbW9kZWwsIHRoZXJlIGlzIG5vIHNpZ25pZmljYW50IHJpc2sgb2YgbXVsdGljb2xsaW5lYXJpdHkgd2l0aCB0aGUgZGF0YSB3ZSBhcmUgd29ya2luZyB3aXRoLiBIb3dldmVyLCB3ZSBhbHNvIHNhdyB0aGVyZSBpcyBhbiBleHRyZW1lIHJpZ2h0d2FyZCBza2V3IGluIHRoZSBkaXN0cmlidXRpb24gb2Ygc3BlZWNoaW5lc3MsIGluc3RydW1lbnRhbG5lc3MgYW5kIGxlbmd0aC4gQmVsb3cgSSB0YWtlIGEgY2xvc2VyIGxvb2sgYXQgdGhlIGRpc3RyaWJ1dGlvbnMgb2YgdGhvc2UgdGhyZWUgdmFyaWFibGVzLgpgYGB7cn0KIyMgUmVtZW1iZXIgaW4gdGhlIEhXIGluc3RydWN0aW9ucywgaW5jbHVkZSBub3QganVzdCB0aGUgbnVtZXJpY2FsIHZhcmlhYmxlcyBidXQgdHdvIGNhdGVnb3JpY2FsIG9uZXMgdG9vIChsZXQncyB1c2UgcGxheWxpc3RfZ2VucmUgYW5kIHBsYXlsaXN0X3N1YmdlbnJlKQoKcGFyKG1mcm93PWMoMSwyKSkKaGlzdChzcGVlY2hpbmVzcywgeGxhYj0iU3BlZWNoaW5lc3MiLCBtYWluID0gIiIpCmhpc3QoaW5zdHJ1bWVudGFsbmVzcywgeGxhYiA9ICJJbnN0cnVtZW50YWxuZXNzIiwgbWFpbiA9ICIiKQpoaXN0KGR1cmF0aW9uX21pbnMsIHhsYWIgPSAiTGVuZ3RoIChNaW5zKSIsIG1haW4gPSAiIikKYGBgCgpUbyBjb21iYXQgdGhlIHNrZXcgb2YgYWxsIHRocmVlIHZhcmlhYmxlcywgSSB3aWxsIHBlcmZvcm0gZGlzY3JldGl6YXRpb24gb24gZWFjaCBvZiB0aGVtLiBUaGUgY29kaW5nIGZvciBzdWNoIGNhbiBiZSBzZWVuIGJlbG93LgpgYGB7cn0KICAjIFNwZWVjaGluZXNzID0gInByZXNlbmNlIG9mIGF1ZGlibGUgd29yZHMgb24gMCB0byAxIHNjYWxlIgpncnAuc3BlZWNoaW5lc3MgPSBzcGVlY2hpbmVzcwpncnAuc3BlZWNoaW5lc3Nbc3BlZWNoaW5lc3MgPCAwLjVdID0gIjogcyB1bmRlciAwLjUiCmdycC5zcGVlY2hpbmVzc1tzcGVlY2hpbmVzcyA+IDAuNV0gPSAiOiBzIG92ZXIgMC41IgoKICAjIHN1bShzcGVlY2hpbmVzcyA+IDAuNSkgPSAxNAogICMgc3VtKHNwZWVjaGluZXNzIDwgMC41KSA9IDI2NDEKCgogICMgSW5zdHJ1bWVudGFsbmVzcyA9ICJsaWtlbGlob29kIHRoYXQgdGhlIHRyYWNrIGNvbnRhaW5zIGluc3RydW1lbnRhbHMgKDAgdG8gMSBzY2FsZSkiCmdycC5pbnN0cnVtZW50YWxuZXNzID0gaW5zdHJ1bWVudGFsbmVzcwpncnAuaW5zdHJ1bWVudGFsbmVzc1tpbnN0cnVtZW50YWxuZXNzIDwgMC4xXSA9ICI6IHMgdW5kZXIgMC4xIgpncnAuaW5zdHJ1bWVudGFsbmVzc1tpbnN0cnVtZW50YWxuZXNzID4gMC4xICYgaW5zdHJ1bWVudGFsbmVzcyA8PSAwLjddID0gIjogcyBmcm9tIDAuMSB0byAwLjciCmdycC5pbnN0cnVtZW50YWxuZXNzW2luc3RydW1lbnRhbG5lc3MgPiAwLjddID0gIjogcyBvdmVyIDAuNyIKIAogIyAgc3VtKGluc3RydW1lbnRhbG5lc3MgPCAwLjEpID0gMTgwMgogIyAgc3VtKGluc3RydW1lbnRhbG5lc3MgPiAwLjEgJiBpbnN0cnVtZW50YWxuZXNzIDwgMC43KSA9IDE5MwogIyAgc3VtKGluc3RydW1lbnRhbG5lc3MgPiAwLjcpID0gNjU5CiAgCgogICMgZHVyYXRpb25fbWlucyBiZWxvdwpncnAuZHVyYXRpb25fbWlucyA9IGR1cmF0aW9uX21pbnMKZ3JwLmR1cmF0aW9uX21pbnNbZHVyYXRpb25fbWlucyA8IDVdID0gIjogVW5kZXIgNSBtaW5zIgpncnAuZHVyYXRpb25fbWluc1tkdXJhdGlvbl9taW5zID49IDUgJiBkdXJhdGlvbl9taW5zIDw9IDEwXSA9ICI6IEJldHdlZW4gNSBhbmQgMTAgbWlucyIKZ3JwLmR1cmF0aW9uX21pbnNbZHVyYXRpb25fbWlucyA+IDEwXSA9ICI6IE92ZXIgMTAgbWlucyIKICAKIyBzdW0oZHVyYXRpb25fbWlucyA8IDUpID0gMjQyNAojIHN1bShkdXJhdGlvbl9taW5zID49IDUgJiBkdXJhdGlvbl9taW5zIDw9IDEwKSA9IDIxMQojIHN1bShkdXJhdGlvbl9taW5zID4gMTApID0gMjAKCgpXb3JrX0RhdGEkZ3JwLnNwZWVjaGluZXNzID0gZ3JwLnNwZWVjaGluZXNzCldvcmtfRGF0YSRncnAuaW5zdHJ1bWVudGFsbmVzcyA9IGdycC5pbnN0cnVtZW50YWxuZXNzCldvcmtfRGF0YSRncnAuZHVyYXRpb25fbWlucyA9IGdycC5kdXJhdGlvbl9taW5zCmBgYAoKCiMjIEJ1aWxkaW5nIEZ1bGwgTXVsdGlwbGUgTG9naXN0aWMgTW9kZWwKRm9yIHRoZSBmdWxsIG11bHRpcGxlIGxvZ2lzdGljIG1vZGVsLCBJIHdpbGwgaW5pdGlhbGx5IGluY2x1ZGUgdGhlIGNvbnRpbnVvdXMgbnVtZXJpY2FsIHZhcmlhYmxlcyB0ZW1wbyBhbmQgZGFuY2VhYmlsaXR5IGluIHRoZWlyIG9yaWdpbmFsIGZvcm0sIGFzIHdlbGwgYXMgdGhlIGRpc2NyZXRpemVkIHRyYW5zZm9ybWF0aW9ucyBvZiBpbnN0cnVtZW50YWxuZXNzLCBsZW5ndGggaW4gbWludXRlcyBhbmQgc3BlZWNoaW5lc3MuIEFmdGVyIGNvZGluZyB0aGlzIG1vZGVsIGluLCBJIHdpbGwgZXhhbWluZSBpdHMgc3VtbWFyeSBzdGF0aXN0aWNzLgoKYGBge3J9Ck11bHRpcGxlX0Z1bGxfTG9nX01vZGVsID0gZ2xtKGZvcm11bGEgPSBwb3B1bGFyIH4gdGVtcG8gKyBkYW5jZWFiaWxpdHkgKyBncnAuc3BlZWNoaW5lc3MgKyBncnAuaW5zdHJ1bWVudGFsbmVzcyArIGdycC5kdXJhdGlvbl9taW5zLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IiksIAogICAgZGF0YSA9IFdvcmtfRGF0YSkKCmludmlzaWJsZShzdW1tYXJ5KE11bHRpcGxlX0Z1bGxfTG9nX01vZGVsKSkKCk11bHRpcGxlX0Z1bGxfTG9nX01vZGVsX0NvZWZfU3VtbWFyeSA9IHN1bW1hcnkoTXVsdGlwbGVfRnVsbF9Mb2dfTW9kZWwpJGNvZWYKTXVsdGlwbGVfRnVsbF9Db25maWRlbmNlX0ludGVydmFsID0gY29uZmludChNdWx0aXBsZV9GdWxsX0xvZ19Nb2RlbCkgIAoKTXVsdGlwbGVfRnVsbF9TdW1tYXJ5X1N0YXRzID0gY2JpbmQoTXVsdGlwbGVfRnVsbF9Mb2dfTW9kZWxfQ29lZl9TdW1tYXJ5LCBNdWx0aXBsZV9GdWxsX0NvbmZpZGVuY2VfSW50ZXJ2YWwuOTU9TXVsdGlwbGVfRnVsbF9Db25maWRlbmNlX0ludGVydmFsKSAgICMgcm91bmRpbmcgb2ZmIGRlY2ltYWxzCgprYWJsZShNdWx0aXBsZV9GdWxsX1N1bW1hcnlfU3RhdHMsY2FwdGlvbiA9ICJGdWxsIE11bHRpcGxlIExvZ2lzdGljIFJlZ3Jlc3Npb24gTW9kZWwgU3VtbWFyeSIpIAoKaW52aXNpYmxlKHRhYmxlKFdvcmtfRGF0YSRwb3B1bGFyLCBXb3JrX0RhdGEkZ3JwLnNwZWVjaGluZXNzKSkKaW52aXNpYmxlKHRhYmxlKFdvcmtfRGF0YSRwb3B1bGFyLCBXb3JrX0RhdGEkZ3JwLmluc3RydW1lbnRhbG5lc3MpKQppbnZpc2libGUodGFibGUoV29ya19EYXRhJHBvcHVsYXIsIFdvcmtfRGF0YSRncnAuZHVyYXRpb25fbWlucykpCiAgI05BJ3MgaW4ga2FibGUgZnVuY3Rpb24gZGlzcGxheSBhcmUgZHVlIHRvICJwZXJmZWN0IiByZXN1bHRzIGJldHdlZW4gY2VydGFpbiBsZXZlbHMgb2Ygb3VyIGRpc2NyZXRpemVkIHZhcmlhYmxlcyBhbmQgdGhlIHJlc3BvbnNlIHZhcmlhYmxlIG9mIHBvcHVsYXIgb3Igbm90LiBJZiBhbGwgb2JzZXJ2YXRpb25zIGluIGEgY2VydGFpbiBsZXZlbCByZXN1bHQgaW4gb25lIG9mIHRoZSB0d28gb3B0aW9ucyBmb3IgdGhlIHJlc3BvbnNlIHZhcmlhYmxlLCB0aGVuIHRoYXQgY29lZmZpY2llbnQgd2lsbCB0cmVuZCB0b3dhcmRzIG5lZ2F0aXZlIG9yIHBvc2l0aXZlIGluZmluaXR5IHBlciBSJ3MgY2FsY3VsYXRpb25zLgpgYGAKCldlIGNhbiBzZWUgdGhlIGZvbGxvd2luZyBmcm9tIG91ciBtb2RlbCBzdW1tYXJ5LiBGaXJzdCwganVzdCBsaWtlIHRoZSByZXN1bHRzIGZyb20gb3VyIHNpbXBsZSByZWdyZXNzaW9uIG1vZGVsLCB0aGVyZSBpcyBvbmNlIGFnYWluIGEgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBhc3NvY2lhdGlvbiBiZXR3ZWVuIGEgdHJhY2sncyB0ZW1wbyBhbmQgaXRzIGxpa2VsaWhvb2Qgb2YgYmVpbmcgcG9wdWxhciBvbiBTcG90aWZ5IChwIH4gMC4wNDEzKS4gSG93ZXZlciB0aGF0IGFzc29jaWF0aW9uIGlzIHNvIHNtYWxsIHRoYXQgaXQgaXMgb2YgbGl0dGxlICpwcmFjdGljYWwqIGltcG9ydGFuY2UuIEFkZGl0aW9uYWxseSwgaXQgYXBwZWFycyB0aGF0IGEgdHJhY2sncyBpbnN0cnVtZW50YWxuZXNzIGFuZCBsZW5ndGggYWJzb2x1dGVseSBwbGF5IGEgcGFydCBpbiBpdHMgcHJvYmFiaWxpdHkgb2YgYmVpbmcgcG9wdWxhciBvbiBTcG90aWZ5LiAKCklmIHdlIGxvb2sgYXQgdGhlIGRpc2NyZXRpemVkIGJyZWFrZG93biBvZiBpbnN0cnVtZW50YWxuZXNzLCB3ZSBzZWUgdGhhdCB0aGVyZSBpcyBhbiBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGluIHRyYWNrcyB3aG9zZSBpbnN0cnVtZW50YWxuZXNzIHJhdGluZyBpcyBvZiAwLjcgYW5kIGhpZ2hlciwgb3IgbGVzcyB0aGFuIDAuMSwgd2hlbiBjb21wYXJlZCB0byB0cmFja3Mgd2hvc2UgcmF0aW5nIGlzIHNvbWV3aGVyZSBpbiB0aGUgbWlkZGxlLiBGb3IgdHJhY2sgbGVuZ3RoLCB0aGVyZSBhbHNvIGFwcGVhcnMgdG8gYmUgc2lnbmlmaWNhbnQgZXZpZGVuY2UgdGhhdCB0cmFja3MgbGVzcyB0aGFuIDUgbWludXRlcyBsb25nIGhhdmUgYSBncmVhdGVyIHByb2JhYmlsaXR5IG9mIGFjaGlldmluZyBwb3B1bGFyaXR5IG9uIFNwb3RpZnkgdGhhbiB0aG9zZSBvZiBhbnkgb3RoZXIgbGVuZ3RocyBpbiBvdXIgZGF0YXNldC4KCk9uIHRoZSBvdGhlciBoYW5kLCB0aGVyZSBpcyBub3QgZXZpZGVuY2UgdG8gc3VnZ2VzdCB0aGF0IGEgdHJhY2sncyBkYW5jZWFiaWxpdHkgb3Igc3BlZWNoaW5lc3MgaGF2ZSBzdWNoIGFuIGFzc29jaWF0aW9uIHdpdGggaXRzIHBvcHVsYXJpdHkuCgpBZnRlciBleGFtaW5pbmcgdGhlIG1vZGVsIHN1bW1hcnksIEkgYWxzbyBjaG9zZSB0byBydW4gVklGIG9uIHRoaXMgZnVsbCBtb2RlbCwgd2hpY2ggY2FuIGJlIHNlZW4gYmVsb3cuIEdpdmVuIHRoYXQgYWxsIEdWSUYgYXJlIGJlbG93IDEuMSwgd2UgY2FuIHNhZmVseSBzYXkgdGhhdCBtdWx0aWNvbGxpbmVhcml0eSBpcyBub3QgcGVydGluZW50IHRvIHRoaXMgZGF0YXNldC4gVGhpcyBmaW5kaW5nIGlzIGluIGxpbmUgd2l0aCB0aGUgdGFrZWF3YXkgZnJvbSBvdXIgcGFpcndpc2Ugc2NhdHRlcnBsb3QgZWFybGllciBvbi4KYGBge3J9CnZpZihNdWx0aXBsZV9GdWxsX0xvZ19Nb2RlbCkKYGBgCgojIyBNYW51YWxseSBSZWR1Y2VkIE11bHRpcGxlIExvZ2lzdGljIE1vZGVsClNpbmNlIHBhcnNpbW9ueSAoaGF2aW5nIGFzIGxlYXN0IGFtb3VudCBvZiB2YXJpYWJsZXMgYXMgcG9zc2libGUgd2l0aG91dCBsb3Npbmcgc2lnbmlmaWNhbnQgYWNjdXJhY3kgaW4gYXNzb2NpYXRpb24gZXhhbWluYXRpb24gb3IgcHJlZGljdGlvbiBhY2N1cmFjeSkgaXMgYW4gaW1wb3J0YW50IGFzcGVjdCBvZiBzdGF0aXN0aWNhbCBtb2RlbGluZywgSSBhbHNvIHRoZW4gY2hvc2UgdG8gY3JlYXRlIGEgcmVkdWNlZCB2ZXJzaW9uIG9mIG15IG11bHRpcGxlIGxvZ2lzdGljIG1vZGVsIGFib3ZlLiBJbiB0aGlzIG1vZGVsLCBJIGRpZCBub3QgaW5jbHVkZSBwcmVkaWN0b3JzIHdob3NlIGltcGFjdCB3YXMgdmVyeSBjbGVhcmx5IGluc2lnbmlmaWNhbnQgYXMgcGVyIHRoZSBvcmlnaW5hbCBmdWxsIG1vZGVsJ3Mgc3VtbWFyeSAoZGFuY2VhYmlsaXR5IGFuZCBzcGVlY2hpbmVzcykuIFRoZSBzdW1tYXJ5IGZvciB0aGlzIG5ldyByZWR1Y2VkIG1vZGVsIGlzIGJlbG93LgoKYGBge3J9Ck11bHRpcGxlX1JlZHVjZWRfTG9nX01vZGVsID0gZ2xtKGZvcm11bGEgPSBwb3B1bGFyIH4gdGVtcG8gKyBncnAuaW5zdHJ1bWVudGFsbmVzcyArIGdycC5kdXJhdGlvbl9taW5zLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IiksIAogICAgZGF0YSA9IFdvcmtfRGF0YSkKCmludmlzaWJsZShzdW1tYXJ5KE11bHRpcGxlX1JlZHVjZWRfTG9nX01vZGVsKSkKCk11bHRpcGxlX1JlZHVjZWRfTG9nX01vZGVsX0NvZWZfU3VtbWFyeSA9IHN1bW1hcnkoTXVsdGlwbGVfUmVkdWNlZF9Mb2dfTW9kZWwpJGNvZWYKTXVsdGlwbGVfUmVkdWNlZF9Mb2dfTW9kZWxfQ29uZmlkZW5jZV9JbnRlcnZhbCA9IGNvbmZpbnQoTXVsdGlwbGVfUmVkdWNlZF9Mb2dfTW9kZWwpICAKCk11bHRpcGxlX1JlZHVjZWRfU3VtbWFyeV9TdGF0cyA9IGNiaW5kKE11bHRpcGxlX1JlZHVjZWRfTG9nX01vZGVsX0NvZWZfU3VtbWFyeSwgTXVsdGlwbGVfUmVkdWNlZF9Db25maWRlbmNlX0ludGVydmFsLjk1PU11bHRpcGxlX1JlZHVjZWRfTG9nX01vZGVsX0NvbmZpZGVuY2VfSW50ZXJ2YWwpICAgIyByb3VuZGluZyBvZmYgZGVjaW1hbHMKCmthYmxlKE11bHRpcGxlX1JlZHVjZWRfU3VtbWFyeV9TdGF0cyxjYXB0aW9uID0gIlJlZHVjZWQgTXVsdGlwbGUgTG9naXN0aWMgUmVncmVzc2lvbiBNb2RlbCBTdW1tYXJ5IikgCmBgYAoKVGhlIHJlc3VsdHMgZnJvbSB0aGlzIG5ldyByZWR1Y2VkIG1vZGVsIGxhcmdlbHkgYWxpZ24gd2l0aCB0aGUgZmluZGluZ3MgZnJvbSB0aGUgb3JpZ2luYWwgbXVsdGlwbGUgbW9kZWwuIEhvd2V2ZXIsIGp1c3QgYXMgb3ZlcmZpdHRpbmcgYSBtb2RlbCB3aXRoIG5lZWRsZXNzIGluZm9ybWF0aW9uIGlzIGEgcG9vciBwcmFjdGljZSwgc28gaXMgdW5kZXJmaXR0aW5nIGEgbW9kZWwgYnkgbm90IGluY2x1ZGluZyBldmVyeXRoaW5nIHRoYXQgaXMgdHJ1bHkgaW1wb3J0YW50LiBUbyBlbnN1cmUgdmFsaWRpdHkgb2YgdGhpcyByZWR1Y2VkIG1vZGVsJ3Mgc3RydWN0dXJlLCBiZWxvdyBJIHJhbiBhdXRvbWF0aWMgc3RlcHd3aXNlIHNlbGVjdGlvbiB2aWEgUidzIEFJQyBmdW5jdGlvbi4gVGhlIG1vZGVsJ3Mgc3VtbWFyeSBzdGF0aXN0aWNzIGhhdmUgYmVlbiBwcmludGVkLgoKIyMgQWxnb3JpdGhtaWNhbGx5IFJlZHVjZWQgTXVsdGlwbGUgTG9naXN0aWMgTW9kZWwKYGBge3J9CmxpYnJhcnkoTUFTUykKQUlDX01vZGVsID0gc3RlcEFJQyhNdWx0aXBsZV9SZWR1Y2VkX0xvZ19Nb2RlbCwgCiAgICAgICAgICAgICAgICAgICAgICBzY29wZSA9IGxpc3QobG93ZXI9Zm9ybXVsYShNdWx0aXBsZV9SZWR1Y2VkX0xvZ19Nb2RlbCksdXBwZXI9Zm9ybXVsYShNdWx0aXBsZV9GdWxsX0xvZ19Nb2RlbCkpLAogICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImZvcndhcmQiLCAgICMgZm9yd2FyZCBzZWxlY3Rpb24KICAgICAgICAgICAgICAgICAgICAgIHRyYWNlID0gMCAgICMgZG8gbm90IHNob3cgdGhlIGRldGFpbHMKICAgICAgICAgICAgICAgICAgICAgICkKCmthYmxlKE11bHRpcGxlX1JlZHVjZWRfU3VtbWFyeV9TdGF0cyxjYXB0aW9uID0iQUlDLUNyZWF0ZWQgTXVsdGlwbGUgTG9naXN0aWMgUmVncmVzc2lvbiBNb2RlbCBTdW1tYXJ5IikKYGBgCgpXZSBjYW4gc2VlIGZyb20gb3VyIG1vZGVsIHN1bW1hcnkgdGhhdCB0aGUgQUlDLWNyZWF0ZWQgbW9kZWwgYW5kIHRoZSByZWR1Y2VkIG1vZGVsIEkgY29kZWQgaW4gdmlhIG1hbnVhbCB2YXJpYWJsZSBzZWxlY3Rpb24gYXJlIGlkZW50aWNhbC4gVGhpcyBpcyBub3Qgc3VycHJpc2luZyBkdWUgdG8gaG93IGNsZWFybHkgc2lnbmlmaWNhbnQgb3IgaW5zaWduaWZpY2FudCB0aGUgcHJlZGljdG9ycyB3ZXJlIGluIHRoZSBvcmlnaW5hbCBmdWxsIG1vZGVsLiBCZWxvdyBJIHdpbGwgcGVyZm9ybSBnbG9iYWwgR09GIG1lYXN1cmVzIG9uIHRoZSBtb2RlbCB0byBoYXZlIHJlY29yZCBvZiBhIGZvcm1hbCBjb21wYXJpc29uIG9mIGVhY2ggb25lJ3MgYWNjdXJhY3kuCgojIyBNb2RlbCBDb21wYXJpc29uIGFuZCBTZWxlY3Rpb24KYGBge3J9CiAjIEdPRiBGdWxsIE11bHRpcGxlIE1vZGVsCk11bHRfRnVsbF9SZXNpZHVhbF9EZXZpYW5jZSA9IE11bHRpcGxlX0Z1bGxfTG9nX01vZGVsJGRldmlhbmNlCk11bHRfRnVsbF9OdWxsX1Jlc2lkdWFsX0RldmlhbmNlID0gTXVsdGlwbGVfRnVsbF9Mb2dfTW9kZWwkbnVsbC5kZXZpYW5jZQpNdWx0X0Z1bGxfYWljID0gTXVsdGlwbGVfRnVsbF9Mb2dfTW9kZWwkYWljCk11bHRfRnVsbF9Hb29kbmVzc19PZl9GaXQgPSBjYmluZChNdWx0X0Z1bGxfUmVzaWR1YWxfRGV2aWFuY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBNdWx0X0Z1bGxfTnVsbF9SZXNpZHVhbF9EZXZpYW5jZSwgTXVsdF9GdWxsX2FpYykKCiAjIEdPRiBNYW51YWxseSBSZWR1Y2VkIE11bHRpcGxlIE1vZGVsCk11bHRfUmVkdWNlZF9SZXNpZHVhbF9EZXZpYW5jZSA9IE11bHRpcGxlX1JlZHVjZWRfTG9nX01vZGVsJGRldmlhbmNlCk11bHRfUmVkdWNlZF9OdWxsX1Jlc2lkdWFsX0RldmlhbmNlID0gTXVsdGlwbGVfUmVkdWNlZF9Mb2dfTW9kZWwkbnVsbC5kZXZpYW5jZQpNdWx0X1JlZHVjZWRfYWljID0gTXVsdGlwbGVfUmVkdWNlZF9Mb2dfTW9kZWwkYWljCk11bHRfUmVkdWNlZF9Hb29kbmVzc19PZl9GaXQgPSBjYmluZChNdWx0X1JlZHVjZWRfUmVzaWR1YWxfRGV2aWFuY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBNdWx0X1JlZHVjZWRfTnVsbF9SZXNpZHVhbF9EZXZpYW5jZSwgTXVsdF9SZWR1Y2VkX2FpYykKCiAjIEdPRiBBSUMgUmVkdWNlZCBNb2RlbApNdWx0X0FJQ19SZXNpZHVhbF9EZXZpYW5jZSA9IEFJQ19Nb2RlbCRkZXZpYW5jZQpNdWx0X0FJQ19OdWxsX1Jlc2lkdWFsX0RldmlhbmNlID0gQUlDX01vZGVsJG51bGwuZGV2aWFuY2UKTXVsdF9BSUNfYWljID0gQUlDX01vZGVsJGFpYwpNdWx0X0FJQ19Hb29kbmVzc19PZl9GaXQgPSBjYmluZChNdWx0X0FJQ19SZXNpZHVhbF9EZXZpYW5jZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE11bHRfQUlDX051bGxfUmVzaWR1YWxfRGV2aWFuY2UsIE11bHRfQUlDX2FpYykKCk1vZGVsX0dPRnMgPSByYmluZChNdWx0X0Z1bGxfR29vZG5lc3NfT2ZfRml0LCBNdWx0X1JlZHVjZWRfR29vZG5lc3NfT2ZfRml0LAogICAgICAgICAgICAgICAgICAgTXVsdF9BSUNfR29vZG5lc3NfT2ZfRml0KQpyb3duYW1lcyhNb2RlbF9HT0ZzKSA9IGMoIkZ1bGwgTW9kZWwiLCAiTWFudWFsbHkgUmVkdWNlZCBNb2RlbCIsICJBSUMgUmVkdWNlZCBNb2RlbCIpCmNvbG5hbWVzKE1vZGVsX0dPRnMpID0gYygiUmVzaWR1YWwgRGV2aWFuY2UiLCAiTnVsbCBEZXZpYW5jZSIsICJBSUMiKQoKa2FibGUoTW9kZWxfR09GcywgY2FwdGlvbiA9IkdPRiBTdW1tYXJ5IG9mIEVhY2ggTW9kZWwiKQpgYGAKCkFzIHdlIGNhbiBzZWUgZnJvbSB0aGUgdGFibGUgYWJvdmUsIGFsbCB0aHJlZSBtb2RlbHMgcGVyZm9ybSBleHRyZW1lbHkgc2ltaWxhci4gU2luY2Ugb3VyIEFJQy1jcmVhdGVkIG1vZGVsIGhhcyB0aGUgbG93ZXN0IEFJQywgYW5kIGl0cyByZXNpZHVhbCBkZXZpYW5jZSBpcyBvbmx5IGEgZnJhY3Rpb24gZ3JlYXRlciB0aGFuIHRoYXQgb2Ygb3VyIGZ1bGwgbW9kZWwsIHdlIHdpbGwgYWNjZXB0IHRoZSBBSUMtY3JlYXRlZCBtb2RlbCBhcyBvdXIgZmluYWwgY2hvaWNlIHRvIHVzZSBmb3IgaW50ZXJwZXRhdGlvbiBvZiB0aGlzIGRhdGFzZXQuCgojIyBUYWtlYXdheXMgZnJvbSBNdWx0aXBsZSBMb2dpc3RpYyBSZWdyZXNzaW9uIE1vZGVsaW5nIFByb2Nlc3MKQWZ0ZXIgdGhlIHNpbXBsZSBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsaW5nIHByb2Nlc3MgZWFybGllciwgd2UgY2FtZSBhd2F5IHdpdGggdGhlIGNvbmNsdXNpb24gdGhhdCBhIHRyYWNrJ3MgdGVtcG8gd2FzICd0ZWNobmljYWxseScgc2lnbmlmaWNhbnQgaW4gaXQncyBsaWtlbGlob29kIG9mIGJlaW5nIHBvcHVsYXIgb24gU3BvdGlmeSwgYnV0IHRoZSBwcmFjdGljYWwgbWFnbml0dWRlIG9mIGl0cyBpbXBhY3Qgd2FzIHNvIHNtYWxsIHRoYXQgaXQgd2FzIG5vdCBhIGZhY3RvciB0aGF0IGRlc2VydmVzIGEgZ3JlYXQgZGVhbCBvZiBlbXBoYXNpcyBpbiB0aGUgcmVhbCB3b3JsZC4gT3VyIEFJQy1jcmVhdGVkIG1vZGVsIGZvciB0aGUgbW9zdCBwYXJ0IGNvbmZpcm1zIHRoaXMgZmluZGluZywgKHAgfiAuMDU3MikuIAoKVGhlIG1vc3QgaW1wb3J0YW50IGZpbmRpbmdzIGZyb20gb3VyIG11bHRpcGxlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gcHJvY2VzcyBjb21lIGZyb20gd2hhdCB3YXMgZGlzY292ZXJlZCBieSBvdXIgZGlzY3JldGl6ZWQgdmFyaWFibGVzLiBUcmFja3Mgd2l0aCB2ZXJ5IGhpZ2ggaW5zdHJ1bWVudGFsbmVzcyAob3ZlciAwLjcgb24gdGhpcyBkYXRhc2V0J3Mgc2NhbGUpIGhhdmUgYSBsZXNzZXIgbGlrZWxpaG9vZCBvZiBiZWluZyBwb3B1bGFyIG9uIFNwb3RpZnkgdGhhbiB0aG9zZSB0aGF0IGZhbGwgaW4gYmV0d2VlbiAwLjEgYW5kIDAuNyBvbiBzYWlkIHNjYWxlLiBBZGRpdGlvbmFsbHksIHRyYWNrcyB1bmRlciAwLjEgb24gdGhlIHNjYWxlIGFjdHVhbGx5IGhhdmUgYSBzbGlnaGx5IGhpZ2hlciBjaGFuY2Ugb2YgYmVpbmcgcG9wdWxhci4KClJlZ2FyZGluZyBhIHRyYWNrJ3MgbGVuZ3RoLCB0cmFja3MgYmVpbmcgdW5kZXIgNSBtaW51dGVzIGRvZXMgaGF2ZSBhIHNpZ25pZmljYW50IGFzc29jaWF0aW9uIHdpdGggaW5jcmVhc2VkIGxpa2VsaWhvb2Qgb2YgcG9wdWxhcml0eSB3aGVuIGNvbXBhcmVkIHRvIHRyYWNrcyByYW5naW5nIGZyb20gNSB0byAxMCBtaW51dGVzIGFuZCB0cmFja3MgYmV5b25kIDEwIG1pbnV0ZXMuIEhvd2V2ZXIsIHRoZXJlIGlzIG5vdCBzdWZmaWNpZW50IGV2aWRlbmNlIHRoYXQgdHJhY2tzIGdvaW5nIGFib3ZlIDEwIG1pbnV0ZXMgc2lnbmlmaWNhbnRseSByZWR1Y2VzIHRoZWlyIGNoYW5jZSBvZiBiZWluZyBwb3B1bGFyIHdoZW4gY29tcGFyZWQgdG8gdGhvc2UgaW4gdGhlIDUgdG8gMTAgbWludXRlIGNhdGVnb3J5LgoKQmVsb3cgaXMgYSB2aXN1YWwgZGlzcGxheWluZyB0aGUgb2RkcyByYXRpb3MgZm9yIHJlbGV2YW50IHZhcmlhYmxlcyBmcm9tIG15IEFJQy1jcmVhdGVkIG1vZGVsLCB0aGV5IHdpbGwgYmUgcmVmZXJlbmNlZCBpbiBteSBmaW5hbCBjb25jbHVzaW9uLiBUaGUgZXh0cmVtZSBlc3RpbWF0ZSwgc3RhbmRhcmQgZXJyb3IgYW5kIG9kZHMgcmF0aW8gZm9yIHNwZWVjaGluZXNzIGNhbiBiZSBkaXNyZWdhcmRlZCBhbmQgYXR0cmlidXRlZCBsYXJnZWx5IHRvIHRoZSB2YXN0IG1ham9yaXR5IG9mIG9ic2VydmF0aW9ucyBmYWxsaW5nIGJlbG93IDAuNSBvbiB0aGUgc3BlZWNoaW5lc3Mgc2NhbGUuIFRoYXQgYWxvbmcgd2l0aCB0aGUgdmFyaWFibGUncyBleHRyZW1lbHkgaGlnaCBwIHZhbHVlLCBhbmQgc3RhbmRhcmQgZXJyb3IgYmVpbmcgcHJhY3RpY2FsbHkgaWRlbnRpY2FsIHRvIHRoZSBzdGFuZGFyZCBlcnJvciBvZiB0aGUgbW9kZWwncyBudWxsIGludGVyY2VwdCBsZWFkIHVzIHRvIGJlbGlldmUgdGhhdCB0aGUgc3VtbWFyeSBzdGF0aXN0aWNzIGZvciBzcGVlY2hpbmVzcyBjYW4gYmUgY2hhbGtlZCB1cCB0byByYW5kb20gY2hhbmNlLCBub3QgdHJ1ZSBsb2dpc3RpYyBhc3NvY2lhdGlvbi4KYGBge3J9CkFJQ19Nb2RlbF9Db2VmX1N1bW1hcnkgPSBzdW1tYXJ5KEFJQ19Nb2RlbCkkY29lZgpBSUNfT2Rkc19SYXRpbyA9IGV4cChjb2VmKEFJQ19Nb2RlbCkpCkFJQ19vdXQuc3RhdHMgPSBjYmluZChBSUNfTW9kZWxfQ29lZl9TdW1tYXJ5LCBvZGRzLnJhdGlvID0gQUlDX09kZHNfUmF0aW8pICAgICAgICAgICAgICAgICAKa2FibGUoQUlDX291dC5zdGF0cyxjYXB0aW9uID0gIkFJQy1DcmVhdGVkIE11bHRpcGxlIFJlZ3Jlc3Npb24gTW9kZWwgQ29lZmZpY2llbnRzIFcvIE9kZHMgUmF0aW9zIikKYGBgCgojIyBGaW5hbCBBc3NvY2lhdGlvbiBNb2RlbGluZyBDb25jbHVzaW9uClRvIGNvbmNsdWRlLCBpbiB0aGUgbW9zdCBwcmFjdGljYWwgc2Vuc2UgdGhlcmUgYXJlIHR3byBmYWN0b3JzIHRoYXQgc2VlbSB0byBoYXZlIHRoZSBncmVhdGVzdCBhc3NvY2lhdGlvbiBvbiBhIHRyYWNrJ3MgY2hhbmNlIG9mIGJlaW5nIHBvcHVsYXIgb24gU3BvdGlmeS4gVGhvc2UgYmVpbmcgaXRzIGluc3RydW1lbnRhbG5lc3MgYW5kIGxlbmd0aC4gVHJhY2tzIHRoYXQgYXJlIHVuZGVyIDUgbWludXRlcyBsb25nIGhhdmUgYWJvdXQgKip0d2ljZSoqIHRoZSBsaWtlbGlob29kIG9mIGJlaW5nIHBvcHVsYXIgdGhhbiBub3QsIHdoaWxlIHRyYWNrcyB0aGF0IGFyZSBsb25nZXIgdGhhbiAxMCBtaW51dGVzIGRvIG5vdCBoYXZlIG5lYXJseSBhcyBncmVhdCBhIGNoYW5jZS4gVHJhY2tzIHRoYXQgYXJlIG5vdCB2ZXJ5IGluc3RydW1lbnRhbCAocyB1bmRlciAwLjEpIGFsc28gaGF2ZSBjbG9zZSB0byB0d2ljZSBhcyBncmVhdCBhIGNoYW5jZSBvZiBiZWluZyBwb3B1bGFyIHRoYW4gbm90LiBNdWNoIGJldHRlciBvZGRzIHRoYW4gdGhlaXIgdmVyeSBpbnN0cnVtZW50YWwgKHMgb3ZlciAwLjcpIGFuZCBtaWxkbHkgaW5zdHJ1bWVudGFsICgwLjEgPCBzIDwgMC43KSBjb3VudGVycGFydHMuCgojIFByZWRpY3RpdmUgQmluYXJ5IExvZ2lzdGljIE1vZGVsCk5vdyB0aGF0IHdlIGhhdmUgZGVlcGx5IHN0dWRpZWQgdGhlIGFzc29jaWF0aW9uIG9mIGEgdHJhY2sncyBsaWtlbGlob29kIG9mIHBvcHVsYXJpdHkgd2l0aCBzb21lIG9mIHRoZSB0cmFjaydzIGNoYXJhY3RlcmlzdGljcywgSSBhbSBnb2luZyB0byB0YWtlIG91ciBhbmFseXNpcyBvbmUgc3RlcCBmdXJ0aGVyLCBhd2F5IGZyb20gdGhlIHJlYWxtIG9mIHN0cmljdCBvYnNlcnZhdGlvbiBhbmQgaW50byB0aGUgcmVhbG0gb2YgZWR1Y2F0ZWQgYW5kIHByZWRpY3RpdmUgc3BlY3VsYXRpb24uIEZvciB0aGlzIHByb2Nlc3MsIEkgd2lsbCB1dGlsaXplIHRoZSBtb2RlbHMgY29uc3RydWN0ZWQgaW4gc2VjdGlvbnMgMy4xIHRocm91Z2ggMy4zIGFib3ZlLCBhcyB3ZWxsIGFzIHN0YW5kYXJkIHByZWRpY3RpdmUgbW9kZWxpbmcgdGVjaG5pcXVlcyBsaWtlIGRhdGEgc3BsaXR0aW5nIGFuZCBST0MgdmlzdWFsaXphdGlvbi4KCiMjIERhdGEgU3BsaXR0aW5nCkJlbG93IEkgc3BsaXQgdGhlIGRhdGEgd2UgaGF2ZSBiZWVuIGFuYWx5emluZyBpbnRvIHR3byBzdWJzZXRzLCBvbmUgZm9yIHRyYWluaW5nIHB1cnBvc2VzIGFuZCBvbmUgZm9yIGFzc2Vzc21lbnQgcHVycG9zZXMsIGF0IGEgcmF0ZSBvZiA3MCUgdG8gMzAlIHJlc3BlY3RpdmVseS4gVGhpcyBwcm9jZWR1cmUgaXMgZG9uZSB0byBjb3VudGVyYWN0IHRoZSByaXNrIG9mIG92ZXJmaXR0aW5nIGEgbW9kZWwgYW5kIHRvIGVuc3VyZSB0aGF0IHRoZSB0cnVlIHJhdGUgb2YgaW5hY2N1cmF0ZSBwcmVkaWN0aW9uIChib3RoIGZhbHNlIHBvc2l0aXZlcyBhbmQgZmFsc2UgbmVnYXRpdmVzKSBpcyBrbm93bi4KCmBgYHtyIFN1YnNldHRpbmcgRGF0YSBmb3IgVGVzdGluZyBhbmQgVHJhaW5pbmd9Cm4gPSBucm93KFdvcmtfRGF0YSkgIyBTYW1wbGUgc2l6ZSBvZiBkYXRhIHdlIGFyZSB3b3JraW5nIHdpdGgKVHJhaW5pbmdfbiA9cm91bmQoMC43Km4pICMgU2FtcGxlIHNpemUgb2YgdHJhaW5pbmcgZGF0YQpUcmFpbmluZ19JRCA9IHNhbXBsZSgxOm4sIFRyYWluaW5nX24sIHJlcGxhY2UgPSBGQUxTRSkgCiAgIyBUaGUgbnVtYmVyIG9mIHJvd3MgdG8gY2hvb3NlIGZyb20gaXMgMTpuLCB0aGUgbnVtYmVyIHRoYXQgd2lsbCBiZSBzZWxlY3RlZCBpcyBUcmFpbmluZ19uLCByZXBsYWNlbWVudCBpcyBzZXQgdG8gRkFMU0Ugc2luY2Ugd2UgYXJlIHRha2luZyBhIHN1YnNldCBvZiB0aGUgZGF0YSwgc28gZG8gbm90IHdhbnQgdG8gdGFrZSB0aGUgc2FtZSBvYnNlcnZhdGlvbihzKSBtb3JlIHRoYW4gb25jZS4KClRyYWluaW5nX0RhdGEgPSBXb3JrX0RhdGFbVHJhaW5pbmdfSUQsIF0KICAjIENyZWF0ZXMgYSBzdWJzZXQgb2YgV29ya19EYXRhLCBhc3NpZ25pbmcgb25seSB0aGUgb2JzZXJ2YXRpb25zIGZyb20gdGhlIGRhdGFzZXQgdGhhdCB3ZXJlIG1hcmtlZCB3aXRoIFRyYWluaW5nX0lEIHRvIGJlIGluIHRoZSBUcmFpbmluZ19EYXRhIHN1YnNldAoKVGVzdGluZ19EYXRhID0gV29ya19EYXRhWy1UcmFpbmluZ19JRCwgXQogICMgQ3JlYXRlcyBhbiBhbHRlcm5hdGUgc3Vic2V0IG9mIFdvcmtfRGF0YSwgYXNzaWduaW5nIG9ubHkgdGhlIG9ic2VydmF0aW9ucyBmcm9tIHRoZSBkYXRhc2V0IHRoYXQgd2VyZSBOT1QgbWFya2VkIHdpdGggVHJhaW5pbmdfSUQgdG8gYmUgaW4gdGhlIFRlc3RpbmdfRGF0YSBzdWJzZXQKYGBgCgojIyBDcm9zcyBWYWxpZGF0aW9uIChDVikgUHJvY2VzcyBhbmQgTW9kZWwgU2VsZWN0aW9uCk5vdyBJIHdpbGwgdXNlIHRoZSBhZm9yZW1lbnRpb25lZCBtb2RlbHMsIGNyZWF0ZWQgaW4gbXkgbXVsdGlwbGUgcmVncmVzc2lvbiBhc3NvY2lhdGlvbiBhbmFseXNpcywgaW4gdGhlIENWIHByb2Nlc3MuIEkgd2lsbCBjcmVhdGUgMyBmb2xkcyAoZGlzdGluY3QgZ3JvdXBzKSBhbmQgc2V0IHRoZSBjdXQtb2ZmIHByb2JhYmlsaXR5ICh3aGF0IGNvbnN0aXR1dGVzIOKAnHllc+KAnSBvciDigJxub+KAnSBhcyB0aGUgdmFsdWUgb2Ygb3VyIGJpbmFyeSByZXNwb25zZSB2YXJpYWJsZSkgdG8gdGhlIHN0YW5kYXJkIDAuNS4gVGhlIHJlc3VsdHMgYW5kIGludGVycHJldGF0aW9uIGNhbiBiZSBzZWVuIGJlbG93LgoKYGBge3J9CiMgTXVsdGlwbGVfRnVsbF9Mb2dfTW9kZWwgPSBGaXJzdCBtdWx0aXBsZSBsb2cgbW9kZWwKIyBNdWx0aXBsZV9SZWR1Y2VkX0xvZ19Nb2RlbCA9IE1hbnVhbGx5IHJlZHVjZWQgb25lCiMgQUlDX01vZGVsID0gVGhlIGZpbmFsIEFsZ29yaXRobWljYWxseSBSZWR1Y2VkIG9uZSB3ZSB1c2VkCgojIDMgZm9sZCBjcm9zcy12YWxpZGF0aW9uCmsgPSAzCgpmb2xkX3NpemUgPSBmbG9vcihkaW0oVHJhaW5pbmdfRGF0YSlbMV0vaykKCiMjIFBFIHZlY3RvcnMgZm9yIGNhbmRpZGF0ZSBtb2RlbHMKUEUxID0gcmVwKDAsNSkKUEUyID0gcmVwKDAsNSkKUEUzID0gcmVwKDAsNSkKZm9yKGkgaW4gMTprKXsgICMgU3RhcnQgb2YgYmlnIEZPUiBsb29wCiAgIyMgVHJhaW5pbmcgYW5kIHRlc3RpbmcgZm9sZHMKICB2YWxpZC5pZCA9IChmb2xkX3NpemUqKGktMSkrMSk6KGZvbGRfc2l6ZSppKQogIHZhbGlkID0gVHJhaW5pbmdfRGF0YVt2YWxpZC5pZCwgXQogIHRyYWluLmRhdCA9IFRyYWluaW5nX0RhdGFbLXZhbGlkLmlkLF0KCiAgIyBGdWxsIExvZyBNb2RlbApDVk1vZGVsMSA9IGdsbShmb3JtdWxhID0gcG9wdWxhciB+IHRlbXBvICsgZGFuY2VhYmlsaXR5ICsgZ3JwLnNwZWVjaGluZXNzICsgZ3JwLmluc3RydW1lbnRhbG5lc3MgKyBncnAuZHVyYXRpb25fbWlucywgZmFtaWx5ID0gYmlub21pYWwobGluayA9ICJsb2dpdCIpLCAKICAgIGRhdGEgPSB0cmFpbi5kYXQpCnRhYmxlKFRyYWluaW5nX0RhdGEkcG9wdWxhcikKCgogICMgTWFudWFsbHkgUmVkdWNlZCBMb2cgTW9kZWwKQ1ZNb2RlbDIgPSBnbG0oZm9ybXVsYSA9IHBvcHVsYXIgfiB0ZW1wbyArIGdycC5pbnN0cnVtZW50YWxuZXNzICsgZ3JwLmR1cmF0aW9uX21pbnMsIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKSwgCiAgICBkYXRhID0gdHJhaW4uZGF0KQoKICAKICAjIEFJQyBSZWR1Y2VkIChGaW5hbCkgTG9nIE1vZGVsCiAgQ1ZNb2RlbDMgPSBzdGVwQUlDKENWTW9kZWwxLCAKICAgICAgICAgIHNjb3BlID0gbGlzdChsb3dlcj1mb3JtdWxhKENWTW9kZWwyKSx1cHBlcj1mb3JtdWxhKENWTW9kZWwxKSksCiAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiZm9yd2FyZCIsICAgIyBmb3J3YXJkIHNlbGVjdGlvbgogICAgICAgICAgICAgICAgICAgICAgdHJhY2UgPSAwICkKCiAgICMjICBwcmVkaWN0ZWQgcHJvYmFiaWxpdGllcyBvZiBlYWNoIGNhbmRpZGF0ZSBtb2RlbAogICBwcmVkMDEgPSBwcmVkaWN0KENWTW9kZWwxLCBuZXdkYXRhID0gdmFsaWQsIHR5cGU9InJlc3BvbnNlIikKICAgcHJlZDAyID0gcHJlZGljdChDVk1vZGVsMiwgbmV3ZGF0YSA9IHZhbGlkLCB0eXBlPSJyZXNwb25zZSIpCiAgIHByZWQwMyA9IHByZWRpY3QoQ1ZNb2RlbDMsIG5ld2RhdGEgPSB2YWxpZCwgdHlwZT0icmVzcG9uc2UiKQogICAKICAgcHJlLm91dGNvbWUwMSA9IGlmZWxzZShhcy52ZWN0b3IocHJlZDAxKSA+IDAuNSwgInllcyIsICJubyIpCiAgIHByZS5vdXRjb21lMDIgPSBpZmVsc2UoYXMudmVjdG9yKHByZWQwMikgPiAwLjUsICJ5ZXMiLCAibm8iKQogICBwcmUub3V0Y29tZTAzID0gaWZlbHNlKGFzLnZlY3RvcihwcmVkMDMpID4gMC41LCAieWVzIiwgIm5vIikKICAgICAgIyBIYXZlIG91ciBjdXQtb2ZmIHByb2JhYmlsaXR5IHNldCB0byAwLjUKICAgICAgICAjIEhBVkUgdG8gc2V0IHJlc3BvbnNlcyBhcyAieWVzIiBhbmQgIm5vIiwgZWFybGllciBoYWQgdGhlbSBzZXQgYXMgInBvcyIgYW5kICJuZWciIHRvIG1pbWljIHRoZSBjYXNlIHN0dWR5IGNvZGUsIHdoaWNoIGlzIHdoeSBvdXRjb21lIHdhcyBpbGxvZ2ljYWwKICAgCiAgIFBFMVtpXSA9IDEtc3VtKHByZS5vdXRjb21lMDEgPT0gdmFsaWQkcG9wdWxhciApL2xlbmd0aChwcmVkMDEpCiAgIFBFMltpXSA9IDEtc3VtKHByZS5vdXRjb21lMDIgPT0gdmFsaWQkcG9wdWxhciApL2xlbmd0aChwcmVkMDIpCiAgIFBFM1tpXSA9IDEtc3VtKHByZS5vdXRjb21lMDIgPT0gdmFsaWQkcG9wdWxhcikvbGVuZ3RoKHByZWQwMykKICAgIyB2YWxpZCRwb3B1bGFyID0g4oCcRnJvbSB0aGUgdmFsaWRhdGlvbiBzdWJzZXQgdmFsaWQsIHRha2UgdGhlIGNvbHVtbiBuYW1lZCBwb3B1bGFyLuKAnQogICAKICB9ICMgRW5kIG9mIGJpZyBGT1IgbG9vcAogCiAjIERpc3BsYXkgdGhlIG91dHB1dCBvZiB0aGUgbG9vcApBdmcuUHJlZGljdGlvbl9FcnJvciA9IGNiaW5kKFBFMSA9IG1lYW4oUEUxKSwgUEUyID0gbWVhbihQRTIpLCBQRTMgPSBtZWFuKFBFMykpCmthYmxlKEF2Zy5QcmVkaWN0aW9uX0Vycm9yLCBkaWdpdHMgPSA0LCBjYXB0aW9uID0gIkF2ZXJhZ2UgUHJlZGljdGlvbiBFcnJvcnMgb2YgdGhlIENWIE1vZGVscyIpCgpwcmVkMDIgPSBwcmVkaWN0KENWTW9kZWwyLCBuZXdkYXRhID0gVGVzdGluZ19EYXRhLCB0eXBlPSJyZXNwb25zZSIpCnByZWQwMi5vdXRjb21lID0gaWZlbHNlKGFzLnZlY3RvcihwcmVkMDIpPjAuNSwgInllcyIsICJubyIpCgphY2N1cmFjeSA9IHN1bShwcmVkMDIub3V0Y29tZSA9PSBUZXN0aW5nX0RhdGEkcG9wdWxhcikvbGVuZ3RoKHByZWQwMikKa2FibGUoYWNjdXJhY3ksIGNhcHRpb249IlRoZSBhY3R1YWwgYWNjdXJhY3kgb2YgdGhlIGZpbmFsIG1vZGVsIikKYGBgCgpXZSBjYW4gc2VlIGZyb20gYWJvdmUgdGhhdCwgYXQgYSBjdXQtb2ZmIHByb2JhYmlsaXR5IG9mIDAuNSwgYWxsIHRocmVlIG9mIG91ciBtb2RlbHMgdXNlZCBmb3IgYXNzb2NpYXRpdmUgYW5hbHlzaXMgZnVuY3Rpb24gd2l0aCBhbiBhdmVyYWdlIHByZWRpY3Rpb24gZXJyb3Igb2YgfiAwLjEwNTcgKHRoaXMgbnVtYmVyIGNhbiB2YXJ5IGJ5IGFib3V0IC4wMSBlaXRoZXIgd2F5IGRlcGVuZGluZyBvbiB3aGljaCBydW4gb2YgdGhlIHNpbXVsYXRpb24gd2UgYXJlIG9uKS4gVGhpcyBpcyBub3QgdG9vIHN1cnByaXNpbmcgZ2l2ZW4gdGhlIHNoYXJlZCBhc3NvY2lhdGl2ZSBmaW5kaW5ncyBvZiBlYWNoIG1vZGVsIChjaGVjayBNdWx0aXBsZSBSZWdyZXNzaW9uIHNlY3Rpb24pLiBHaXZlbiB0aGF0IEkgcHJldmlvdXNseSBkZXRlcm1pbmVkIHRoZSAqQUlDLXByb2R1Y2VkIG1vZGVsKiB3YXMgdGhlIG1vc3QgaWRlYWwsIHRoYXQgaXMgdGhlIG9uZSBJIHdpbGwgY29uc2lkZXIgYXMgdGhlIHVsdGltYXRlIG9yICJmaW5hbCIgcHJlZGljdGl2ZSBtb2RlbC4gKlRoaXMqIG1vZGVsJ3MgcmF0ZSBvZiBhY2N1cmFjeSwgd2hpY2ggd2FzIGZvdW5kIHRocm91Z2ggYXBwbHlpbmcgaXQncyBzdHJ1Y3R1cmUgdG8gdGhlIHRlc3RpbmcgZGF0YXNldCB0aGF0IHdlIHN1YnNldHRlZCBlYXJsaWVyLCBpcyBhYm91dCA4Mi42NyUgKGxpa2UgcHJlZGljdGlvbiBlcnJvciwgY2FuIGhhdmUgc2xpZ2h0IHZhcmlhdGlvbikuCgojIyBST0MgVmlzdWFsaXphdGlvbgpUbyBhc3Npc3Qgd2l0aCB1bmRlcnN0YW5kaW5nLCBJIGFsc28gY29uc3RydWN0ZWQgYSBST0MgKFJlY2VpdmVyIE9wZXJhdGluZyBDaGFyYWN0ZXJpc3RpY3MpIGN1cnZlLiBUaGlzIGltYWdlIGFsbG93cyB1cyB0byBpbnRlcnByZXQgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIG91ciBkaWZmZXJlbnQgbW9kZWxzJyBzcGVjaWZpY2l0eSAocmF0ZSBvZiBwcm9kdWNpbmcgZmFsc2UgcG9zaXRpdmVzKSBvbiB0aGUgeCBheGlzIFZTIHNlbnNpdGl2aXR5IChyYXRlIG9mIHByb2R1Y2luZyB0cnVlIHBvc2l0aXZlcykgb24gdGhlIHkgYXhpcy4gCgpXZSBjYW4gc2VlIGZyb20gdGhlIGN1cnZlIGJlbG93IHRoYXQgYWxsIHRocmVlIG1vZGVscyBhcmUgZXh0cmVtZWx5IHNpbWlsYXIgaW4gdGhlaXIgcmF0aW8gb2Ygc2Vuc2l0aXZpdHkgdG8gc3BlY2lmaWNpdHksIGFuZCBoZW5jZSBoYXZlIGFsbW9zdCBpZGVudGljYWwgQVVDIHZhbHVlcy4gQXMgbWVudGlvbmVkIGFib3ZlLCB3ZSB3aWxsIHV0aWxpemUgdGhlIEFJQy1yZWR1Y2VkIG1vZGVsIGdpdmVuIHRoYXQgaXQgd2FzIGRlZW1lZCB0aGUgbW9zdCBhY2N1cmF0ZSBmb3Igb3VyIHByZXZpb3VzIGFzc29jaWF0aW9uIGFuYWx5c2lzLgpgYGB7cn0KIyMjIyMjIyMjIFVzaW5nIGEgZnVuY3Rpb24gdG8gZXh0cmFjdCBmYWxzZSBwb3NpdGl2ZSBhbmQgZmFsc2UgbmVnYXRpdmUgdmFsdWVzClRQUi5GUFI9ZnVuY3Rpb24ocHJlZCl7CiAgcHJvYi5zZXEgPSBzZXEoMCwxLCBsZW5ndGg9NTApICAjIDUwIGVxdWFsbHkgc3BhY2VkIGN1dC1vZmYgcHJvYmFiaWxpdGllcwogIHBuPWxlbmd0aChwcm9iLnNlcSkKICB0cnVlLmxhYj1hcy52ZWN0b3IoVHJhaW5pbmdfRGF0YSRwb3B1bGFyKQogIFRQUiA9IE5VTEwKICBGUFIgPSBOVUxMCiAgIyMKICBmb3IgKGkgaW4gMTpwbil7CiAgIHByZWQubGFiID0gYXMudmVjdG9yKGlmZWxzZShwcmVkID5wcm9iLnNlcVtpXSwieWVzIiwgIm5vIikpCiAgIFRQUltpXSA9IGxlbmd0aCh3aGljaCh0cnVlLmxhYj09InllcyIgJiBwcmVkLmxhYj09InllcyIpKS9sZW5ndGgod2hpY2godHJ1ZS5sYWI9PSJ5ZXMiKSkKICAgRlBSW2ldID0gbGVuZ3RoKHdoaWNoKHRydWUubGFiPT0ibm8iICYgcHJlZC5sYWI9PSJ5ZXMiKSkvbGVuZ3RoKHdoaWNoKHRydWUubGFiPT0ibm8iKSkKICB9CiBjYmluZChGUFIgPSBGUFIsIFRQUiA9IFRQUikKfQoKIyMjIyMjIyMjIENhbGN1bGF0aW5nIHRoZSBBVUMKaWYgKCFyZXF1aXJlKCJwUk9DIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygicFJPQyIpCiAgIGxpYnJhcnkocFJPQykKfQojIyMgIENhbmRpZGF0ZSBNb2RlbHMKICMgRnVsbCBMb2cgTW9kZWwKQ1ZNb2RlbDEgPSBnbG0oZm9ybXVsYSA9IHBvcHVsYXIgfiB0ZW1wbyArIGRhbmNlYWJpbGl0eSArIGdycC5zcGVlY2hpbmVzcyArIGdycC5pbnN0cnVtZW50YWxuZXNzICsgZ3JwLmR1cmF0aW9uX21pbnMsIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKSwgCiAgICBkYXRhID0gdHJhaW4uZGF0KQoKICAjIE1hbnVhbGx5IFJlZHVjZWQgTG9nIE1vZGVsCkNWTW9kZWwyID0gZ2xtKGZvcm11bGEgPSBwb3B1bGFyIH4gdGVtcG8gKyBncnAuaW5zdHJ1bWVudGFsbmVzcyArIGdycC5kdXJhdGlvbl9taW5zLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IiksIAogICAgZGF0YSA9IHRyYWluLmRhdCkKCiAgIyBBSUMgUmVkdWNlZCAoRmluYWwpIExvZyBNb2RlbAogIENWTW9kZWwzID0gc3RlcEFJQyhDVk1vZGVsMSwgCiAgICAgICAgICBzY29wZSA9IGxpc3QobG93ZXI9Zm9ybXVsYShDVk1vZGVsMiksdXBwZXI9Zm9ybXVsYShDVk1vZGVsMSkpLAogICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImZvcndhcmQiLCAgICMgZm9yd2FyZCBzZWxlY3Rpb24KICAgICAgICAgICAgICAgICAgICAgIHRyYWNlID0gMCApCiMjICBwcmVkaWN0ZWQgcHJvYmFiaWxpdGllcwpwcmVkMDEgPSBwcmVkaWN0LmdsbShDVk1vZGVsMSwgbmV3ZGF0YSA9IFRyYWluaW5nX0RhdGEsIHR5cGU9InJlc3BvbnNlIikgCnByZWQwMiA9IHByZWRpY3QuZ2xtKENWTW9kZWwyLCBuZXdkYXRhID0gVHJhaW5pbmdfRGF0YSwgdHlwZT0icmVzcG9uc2UiKQpwcmVkMDMgPSBwcmVkaWN0LmdsbShDVk1vZGVsMywgbmV3ZGF0YSA9IFRyYWluaW5nX0RhdGEsIHR5cGU9InJlc3BvbnNlIikKIyMjIwojIyBST0MgY3VydmUKIHBsb3QoVFBSLkZQUihwcmVkMDEpWywxXSwgVFBSLkZQUihwcmVkMDEpWywyXSwgCiAgICAgIHR5cGU9ImwiLCBjb2w9InJlZCIsIGx0eT0xLCBsd2QgPSAyLCB4bGltPWMoMCwxKSwgeWxpbT1jKDAsMSksCiAgICAgIHhsYWIgPSAiRmFsc2UgUG9zaXRpdmUgUmF0ZSAoRlBSKSIsCiAgICAgIHlsYWIgPSJUcnVlIFBvc2l0aXZlIFJhdGUgKFRQUikiLAogICAgICBtYWluID0gIlJPQyBjdXJ2ZXMgb2YgdGhlIHRocmVlIGNhbmRpZGF0ZSBtb2RlbHMiLAogICAgICBjZXgubWFpbiA9IDEuMSwKICAgICAgY29sLm1haW4gPSAiYmxhY2siKQogbGluZXMoVFBSLkZQUihwcmVkMDIpWywxXSwgVFBSLkZQUihwcmVkMDIpWywyXSwgIGNvbD0iZGFya2JsdWUiLCBsdHk9MiwgbHdkID0gMikKIGxpbmVzKFRQUi5GUFIocHJlZDAzKVssMV0sIFRQUi5GUFIocHJlZDAzKVssMl0sICBjb2w9ImJsYWNrIiwgbHR5PTMsIGx3ZCA9IDIpICAgIAoKICAjIwogIGNhdGVnb3J5ID0gVHJhaW5pbmdfRGF0YSRwb3B1bGFyID09ICJ5ZXMiCiAgUk9Db2JqMDEgPC0gcm9jKGNhdGVnb3J5LCBhcy52ZWN0b3IocHJlZDAxKSkKICBST0NvYmowMiA8LSByb2MoY2F0ZWdvcnksIGFzLnZlY3RvcihwcmVkMDIpKQogIFJPQ29iajAzIDwtIHJvYyhjYXRlZ29yeSwgYXMudmVjdG9yKHByZWQwMykpCiAgQVVDMDEgPSByb3VuZChhdWMoUk9Db2JqMDEpLDQpCiAgQVVDMDIgPSByb3VuZChhdWMoUk9Db2JqMDIpLDQpCiAgQVVDMDMgPSByb3VuZChhdWMoUk9Db2JqMDMpLDQpCiAgIyMKICBsZWdlbmQoImJvdHRvbXJpZ2h0IiwgYyhwYXN0ZSgiRnVsbCBMb2cgTW9kZWwgQVVDID0gIixBVUMwMSksIAogICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoIk1hbiBSZWR1Y2VkIExvZyBNb2RlbCBBVUMgPSAiLEFVQzAyKSwKICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKCJBSUMgUmVkdWNlZCBMb2cgTW9kZWwgQVVDID0gIiwgQVVDMDMpKSwKICAgICAgICBjb2w9YygicmVkIiwiZGFya2JsdWUiLCAiYmxhY2siKSwgbHR5PTE6MywgY2V4ID0gMC44NSwgYnR5PSJuIikKYGBgCgojIyBQcmVkaWN0aXZlIE1vZGVsaW5nIFRha2Vhd2F5cyAKVG8gY29uY2x1ZGUsIGlmIHNvbWVvbmUgaGFkIGludGVyZXN0IGluIHByZWRpY3RpbmcgYSBzb25nJ3MgY2hhbmNlIG9mIGJlaW5nIHBvcHVsYXIgZ2l2ZW4gaXRzIGxlbmd0aCwgaW5zdHJ1bWVudGFsbmVzcyBhbmQgKHRvIGEgbWlub3IgZXh0ZW50KSB0ZW1wbywgdGhleSBzaG91bGQgdXRpbGl6ZSB0aGUgQUlDLXJlZHVjZWQgbW9kZWwgdGhhdCB3YXMgZm9ybWVkIGluIHNlY3Rpb24gMy4zIGFib3ZlLiBJIGNvdWxkIHNlZSB0aG9zZSBtb3N0IGludGVyZXN0ZWQgaW4gdGhpcyBwcmVkaWN0aXZlIG1vZGVsIGJlaW5nIGFnZW50cywgcmVjb3JkIGxhYmVsIGV4ZWN1dGl2ZXMgYW5kIGFzcGlyaW5nIGFydGlzdHMsIGFsbCBhdHRlbXB0aW5nIHRvICJmaXgiIHRoZWlyIG11c2ljIHRvIGZpdCB0aGUgbW9sZCBvZiB3aGF0IHRlbmRzIHRvIGNvbW1lcmNpYWxseSBzdWNjZWVkIG9uIHRoZSB3b3JsZCdzIGxhcmdlc3Qgc3RyZWFtaW5nIHBsYXRmb3JtLiAKCiMgUmVmZXJlbmNlczoKCk9yaWdpbmFsIERhdGFzZXQgU291cmNlOgoKLSBodHRwczovL3d3dy5rYWdnbGUuY29tL2RhdGFzZXRzL3NvbG9tb25hbWVoL3Nwb3RpZnktbXVzaWMtZGF0YXNldD9zZWxlY3Q9aGlnaF9wb3B1bGFyaXR5X3Nwb3RpZnlfZGF0YS5jc3YKCkRhdGFzZXQgRG93bmxvYWQgTGlua3MgdmlhIEdpdGh1YjoKCi0gaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0NocmlzQjIzMjMvU1RBMzIxL3JlZnMvaGVhZHMvbWFpbi9oaWdoX3BvcHVsYXJpdHlfc3BvdGlmeV9kYXRhLmNzdgoKLSBodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vQ2hyaXNCMjMyMy9TVEEzMjEvcmVmcy9oZWFkcy9tYWluL2xvd19wb3B1bGFyaXR5X3Nwb3RpZnlfZGF0YS5jc3YK