Introduction
This is our first lab when we are considering 2 dimensions and
instead of calculating univariate statistics by groups (or factors) of
other variable - we will measure their common relationships based on
co-variance and correlation coefficients.
*Please be very careful when choosing the measure of correlation! In
case of different measurement scales we have to recode one of the
variables into weaker scale.
It would be nice to add some additional plots in the background. Feel
free to add your own sections and use external packages.
Data
This time we are going to use a typical credit scoring data with
predefined “default” variables and personal demographic and income data.
Please take a look closer at headers and descriptions of each
variable.
Scatterplots
First let’s visualize our quantitative relationships using scatter
plots.

You can also normalize the skewed distribution of incomes using
log:
## Warning: Using size for a discrete variable is not advised.

## [1] 0.4251568
## [1] 0.1577567
## estimate p.value statistic n gp Method
## 1 0.5842774 3.210675e-65 19.0072 700 1 pearson
## estimate p.value statistic n gp Method
## 1 0.3194263 4.805085e-18 8.899323 700 1 pearson
We can add an estimated linear regression line:
## `geom_smooth()` using formula = 'y ~ x'

Scatterplots by groups
We can finally see if there any differences between risk status:
## `geom_smooth()` using formula = 'y ~ x'

We can also see more closely if there any differences between those
two distributions adding their estimated density plots:
## Warning: pakiet 'ggExtra' został zbudowany w wersji R 4.3.3

We can also put those plots together:

Scatterplots with density curves
We can also see more closely if there any differences between those
two distributions adding their estimated density plots:

Correlation coefficients - Pearson’s linear correlation
Ok, let’s move to some calculations. In R, we can use the cor()
function. It takes three arguments and the method: cor(x, y, method) For
2 quantitative data, with all assumptions met, we can calculate simple
Pearson’s coefficient of linear correlation:
## [1] 0.574346
Ok, what about the percentage of the explained variability?
## 32.98734 %
So as we can see almost 32.99% of total log of incomes’ variability
is explained by differences in age. The rest 67% is probably explained
by other factors.
Partial and semipartial correlation
The partial and semi-partial (also known as part) correlations are
used to express the specific portion of variance explained by
eliminating the effect of other variables when assessing the correlation
between two variables.
Partial correlation holds constant one variable when computing the
relations to others. Suppose we want to know the correlation between X
and Y holding Z constant for both X and Y. That would be the partial
correlation between X and Y controlling for Z.
Semipartial correlation holds Z constant for either X or Y, but not
both, so if we wanted to control X for Z, we could compute the
semipartial correlation between X and Y holding Z constant for X.
Suppose we want to know the correlation between the log of income and
age controlling for years of employment. How highly correlated are these
after controlling for tenure?
**There can be more than one control variable.
## Partial Correlation (controlling for years of employment): 0.3194263
## Semipartial Correlation (controlling for years of employment on age): 0.2203711
How can we interpret the obtained partial correlation coefficient?
What is the difference between that one and the semi-partial
coefficient:
The partial correlation between logged income and age, controlling
for years of employment, is 0.3194263 . This value indicates that the
unique relationship between age and logged income, independent of the
years of employment, is positive , suggesting that older individuals
tend to have higher logged incomes, after accounting for their years of
employment.
The semipartial correlation, on the other hand, shows how much of the
variance in logged income can be explained uniquely by age, after
controlling for the effect of years of employment only on the age
variable. The semipartial correlation coefficient is 0.2203711. This
measure highlights the direct influence of age on logged income without
the mixed effects of employment duration on age.
Rank correlation
For 2 different scales - like for example this pair of variables:
income vs. education levels - we cannot use Pearson’s coefficient. The
only possibility is to rank also incomes… and lose some more detailed
information about them.
First, let’s see boxplots of income by education levels.

Now, let’s see Kendal’s coefficient of rank correlation (robust for
ties).
## 0.1577567
Point-biserial correlation
Let’s try to verify if there is a significant relationship between
incomes and risk status. First, let’s take a look at the boxplot:
## Warning: The following aesthetics were dropped during statistical transformation: fill.
## ℹ This can happen when ggplot fails to infer the correct grouping structure in
## the data.
## ℹ Did you forget to specify a `group` aesthetic or to convert a numerical
## variable into a factor?

If you would like to compare 1 quantitative variable (income) and 1
dychotomous variable (default status - binary), then you can use
point-biserial coefficient:
##
## Pearson's product-moment correlation
##
## data: bank$income and as.numeric(bank$default)
## t = -1.8797, df = 698, p-value = 0.06056
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## -0.144313546 0.003149751
## sample estimates:
## cor
## -0.07096966
The point-biserial correlation coefficient is ~ -0.071. It is
negative, so it means that when income increases, likelihood of
defaulting on a loan decreases. It makes sense, because people with
higher incomes are usually less likely to default. But also, p-value can
suggest that this relationship is not so strong as I would thought it
is, because it is above level of 0.05.
Nonlinear correlation - eta coefficient
If you would like to check if there are any nonlinearities between 2
variables, the only possibility (beside transformations and linear
analysis) is to calculate “eta” coefficient and compare it with the
Pearson’s linear coefficient.
## [1] 0.07096966
Eta coefficient is ~ 0.071, so it is the same as previously
calculated point-biserial coefficient. It means the relationship between
our 2 variables is entirely linear.
Correlation matrix
We can also prepare the correlation matrix for all quantitative
variables stored in our data frame.
We can use ggcorr() function:

As you can see - the default correlation matrix is not the best idea
for all measurement scales (including binary variable “default”).
That’s why now we can perform our bivariate analysis with ggpair with
grouping.
Correlation matrix with scatterplots
Here is what we are about to calculate: - The correlation matrix
between age, log_income, employ, address, debtinc, creddebt, and othdebt
variable grouped by whether the person has a default status or not. -
Plot the distribution of each variable by group - Display the scatter
plot with the trend by group
# first correlation matrix still using ggcorr
bank$log_income <- log(bank$income)
data_for_matrix <- c("age", "log_income", "employ", "address", "debtinc", "creddebt", "othdebt")
default_groups <- split(bank, bank$default)
corr_matrix_plots <- lapply(names(default_groups), function(group) {
data_numeric <- default_groups[[group]][, data_for_matrix, drop = FALSE]
data_numeric <- na.omit(data_numeric)
plot <- ggcorr(data_numeric, label = TRUE, hjust = 1) +
ggtitle(paste("Correlation matrix: ", group))
return(plot)
})
# displaying matrices
grid.arrange(grobs = corr_matrix_plots, ncol = 1)

# and now using ggpairs :)
data <- bank[, data_for_matrix]
pairs_plot <- ggpairs(data,
aes(color = as.factor(bank$default), alpha = 0.5),
upper = list(continuous = wrap("cor", size = 4)),
lower = list(continuous = wrap("points", alpha = 0.5)),
diag = list(continuous = wrap("barDiag", fill = "white")))
print(pairs_plot)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
This matrix shows: - scatter plots in the lower triangle - correlation
coefficients in the upper triangle - density plots on the diagonal
Qualitative data
In case of two variables measured on nominal or ordinal&nominal
scale - we are forced to organize so called “contingency” table with
frequencies and calculate some kind of the correlation coefficient based
on them. This is so called “contingency analysis”.
Let’s consider one example based on our data: verify, if there is any
significant correlation between education level and credit risk.
contingency_table <- table(bank$ed, bank$default)
chi_square_result <- chisq.test(contingency_table)
## Warning in chisq.test(contingency_table): Aproksymacja chi-kwadrat może być
## niepoprawna
print(chi_square_result)
##
## Pearson's Chi-squared test
##
## data: contingency_table
## X-squared = 11.492, df = 4, p-value = 0.02155
From the result we can assume that these two variables are not
independent from each other, but probably more tests are needed to tell
exactly how dependent they are.
Exercise 1. Contingency analysis.
Do you believe in the Afterlife? https://nationalpost.com/news/canada/millennials-do-you-believe-in-life-after-life
A survey was conducted and a random sample of 1091 questionnaires is
given in the form of the following contingency table:
## Believe
## Gender Yes No
## Female 435 375
## Male 147 134

Our task is to check if there is a significant relationship between
the belief in the afterlife and gender. We can perform this procedure
with the simple chi-square statistics and chosen qualitative correlation
coefficient (two-way 2x2 table).
##
## Pearson's Chi-squared test with Yates' continuity correction
##
## data: dane
## X-squared = 0.11103, df = 1, p-value = 0.739
## Believe
## Gender Yes No
## Female 0.3987168 0.3437214
## Male 0.1347388 0.1228231
As you can see we can calculate our chi-square statistic really
quickly for two-way tables or larger. Now we can standardize this
contingency measure to see if the relationship is significant.
## [1] 0.01218871


Exercise 2. Contingency analysis for the ‘Titanic’ data.
Let’s consider the titanic dataset which contains a complete list of
passengers and crew members on the RMS Titanic. It includes a variable
indicating whether a person did survive the sinking of the RMS Titanic
on April 15, 1912. A data frame contains 2456 observations on 14
variables.
The website http://www.encyclopedia-titanica.org/ offers detailed
information about passengers and crew members on the RMS Titanic.
According to the website 1317 passengers and 890 crew member were
aboard.
8 musicians and 9 employees of the shipyard company are listed as
passengers, but travelled with a free ticket, which is why they have NA
values in fare. In addition to that, fare is truely missing for a few
regular passengers.
head(titanic)
## Status Disembarked.at Home.Country Age Year.of.Birth
## DE GRASSE, Mr J. Cherbourg NA NA
## EVANS, Miss Cherbourg NA NA
## MULLEN, Cherbourg NA NA
## WOTTON, Mr Henry Swaffin Cherbourg 54 1858
## BRAND, Mr Cherbourg NA NA
## FLETCHER, Miss N. Cherbourg NA NA
## Crew.or.Passenger. Gender Class...Department
## DE GRASSE, Mr J. Passenger Male 2nd Class
## EVANS, Miss Passenger Female 2nd Class
## MULLEN, Passenger Female 2nd Class
## WOTTON, Mr Henry Swaffin Passenger Male 1st Class
## BRAND, Mr Passenger Male 1st Class
## FLETCHER, Miss N. Passenger Female 1st Class
## Embarked Job Job.details
## DE GRASSE, Mr J. Southampton
## EVANS, Miss Southampton
## MULLEN, Southampton
## WOTTON, Mr Henry Swaffin Southampton Butcher Butcher's Shop Proprietor
## BRAND, Mr Southampton
## FLETCHER, Miss N. Southampton
## Ticket.Number Fare.Price Fare_GBP Fare_today
## DE GRASSE, Mr J. 761 P1 1.0 82.110
## EVANS, Miss 88 P1 1.0 82.110
## MULLEN, 404 P1 1.0 82.110
## WOTTON, Mr Henry Swaffin 86 P1 10s 1.5 123.165
## BRAND, Mr 8 P1 10s 1.5 123.165
## FLETCHER, Miss N. 405 P1 10s 1.5 123.165
## Profile.on.Encyclopedia.Titanica
## DE GRASSE, Mr J. http://www.encyclopedia-titanica.org/titanic-biography/j-de-grasse.html
## EVANS, Miss http://www.encyclopedia-titanica.org/titanic-biography/evans.html
## MULLEN, http://www.encyclopedia-titanica.org/titanic-biography/mullen.html
## WOTTON, Mr Henry Swaffin http://www.encyclopedia-titanica.org/titanic-cross-channel-passenger/henry-swaffin-wotton.html
## BRAND, Mr http://www.encyclopedia-titanica.org/titanic-biography/brand.html
## FLETCHER, Miss N. http://www.encyclopedia-titanica.org/titanic-biography/n-fletcher.html
summary(titanic)
## Status Disembarked.at Home.Country Age
## Length:2456 Length:2456 Length:2456 Min. : 0.17
## Class :character Class :character Class :character 1st Qu.:23.00
## Mode :character Mode :character Mode :character Median :29.00
## Mean :30.59
## 3rd Qu.:38.00
## Max. :74.00
## NA's :32
## Year.of.Birth Crew.or.Passenger. Gender Class...Department
## Min. :1837 Length:2456 Length:2456 Length:2456
## 1st Qu.:1874 Class :character Class :character Class :character
## Median :1882 Mode :character Mode :character Mode :character
## Mean :1881
## 3rd Qu.:1889
## Max. :1973
## NA's :32
## Embarked Job Job.details Ticket.Number
## Length:2456 Length:2456 Length:2456 Length:2456
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
##
##
##
##
## Fare.Price Fare_GBP Fare_today
## Length:2456 Min. : 1.00 Min. : 82.11
## Class :character 1st Qu.: 7.90 1st Qu.: 648.33
## Mode :character Median : 14.45 Median : 1186.83
## Mean : 33.16 Mean : 2722.71
## 3rd Qu.: 31.07 3rd Qu.: 2551.06
## Max. :512.33 Max. :42067.35
## NA's :1136 NA's :1136
## Profile.on.Encyclopedia.Titanica
## Length:2456
## Class :character
## Mode :character
##
##
##
##
# Replace NA in fare with the median fare
titanic$Fare[is.na(titanic$Fare)] <- median(titanic$Fare, na.rm = TRUE)
titanic$Age[is.na(titanic$Age)] <- median(titanic$Age, na.rm = TRUE)
ggplot(titanic, aes(x = Age, fill = factor(Status))) +
geom_histogram(binwidth = 5, position = "fill", color = "black") +
labs(y = "Proportion", x = "Age", fill = "Status", title = "Survival by Age") +
theme_minimal()

# contingency table of survival by country
survival_by_country <- table(titanic$Status, titanic$Home.Country)
chisq.test(survival_by_country)
## Warning in chisq.test(survival_by_country): Aproksymacja chi-kwadrat może być
## niepoprawna
##
## Pearson's Chi-squared test
##
## data: survival_by_country
## X-squared = 1696.2, df = 84, p-value < 2.2e-16
# contingency table of survival by gender
survival_by_gender <- table(titanic$Status, titanic$Gender)
chisq.test(survival_by_gender)
##
## Pearson's Chi-squared test
##
## data: survival_by_gender
## X-squared = 552.06, df = 2, p-value < 2.2e-16
# contingency table of survival by age
survival_by_age <- table(titanic$Status, titanic$Age)
chisq.test(survival_by_age)
## Warning in chisq.test(survival_by_age): Aproksymacja chi-kwadrat może być
## niepoprawna
##
## Pearson's Chi-squared test
##
## data: survival_by_age
## X-squared = 308.5, df = 154, p-value = 2.135e-12
From the plot we can see, that there is some small relation between
age and surviving - generally there were more younger than older people
who survived, but also there is some increase when looking at old people
- that were about 60 years old. Looking at chi-squared test results, for
every tested variable p-value is extremely low. It means, that there is
significant dependence between survival status and those variables.
LS0tDQp0aXRsZTogJ0Rlc2NyaXB0aXZlIFN0YXRpc3RpY3MnDQpzdWJ0aXRsZTogJ0JpdmFyaWF0ZSBBbmFseXNpcycNCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCmF1dGhvcjogIkFsZWtzYW5kcmEgVGVtcGxpbiAmIEtzYXdlcnkgUmF1cHVrIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICB0aGVtZTogY2VydWxlYW4NCiAgICBoaWdobGlnaHQ6IHRleHRtYXRlDQogICAgZm9udHNpemU6IDEwcHQNCiAgICB0b2M6IHllcw0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogbm8NCiAgICBkZl9wcmludDogZGVmYXVsdA0KICAgIHRvY19kZXB0aDogNQ0KZWRpdG9yX29wdGlvbnM6IA0KICBtYXJrZG93bjogDQogICAgd3JhcDogNzINCi0tLQ0KDQpgYGB7ciBzZXR1cCwJbWVzc2FnZSA9IEZBTFNFLAl3YXJuaW5nID0gRkFMU0UsCWluY2x1ZGUgPSBGQUxTRX0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoSFNBVVIzKQ0KbGlicmFyeShoYXZlbikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZ3JpZEV4dHJhKQ0KbGlicmFyeShwcGNvcikgIyB0aGlzIHBhY2thZ2UgY29tcHV0ZXMgcGFydGlhbCBhbmQgc2VtaXBhcnRpYWwgY29ycmVsYXRpb25zLg0KbGlicmFyeShsdG0pICMgdGhpcyBwYWNrYWdlIGNvbXB1dGVzIHBvaW50LWJpc2VyaWFsIGNvcnJlbGF0aW9ucy4NCmxpYnJhcnkoZGV2dG9vbHMpIA0KI2luc3RhbGxfZ2l0aHViKCJtYXJraGVja21hbm4vcnlvdXJlYWR5IikgIyBwbGVhc2UgaW5zdGFsbCBwYWNrYWdlICJyeW91cmVhZHkiIGZyb20gZ2l0aHViISAodGhlbiAjIGl0KQ0KbGlicmFyeShyeW91cmVhZHkpICMgdGhpcyBwYWNrYWdlIGNvbXB1dGVzIG5vbmxpbmVhciAiZXRhIiBjb3JyZWxhdGlvbnMuDQpsaWJyYXJ5KEdHYWxseSkgIyB0aGlzIHBhY2thZ2UgY29tcHV0ZXMgY29ycmVsYXRpb24gbWF0cml4Lg0KbGlicmFyeShwc3ljaCkgIyB0aGlzIHBhY2thZ2UgY29tcHV0ZXMgcXVhbGl0YXRpdmUgY29ycmVsYXRpb25zLg0KbGlicmFyeShEZXNjVG9vbHMpICMgdGhpcyBwYWNrYWdlIGNvbXB1dGVzIHF1YWxpdGF0aXZlIGNvcnJlbGF0aW9ucy4NCmBgYA0KDQoNCiMjIEludHJvZHVjdGlvbg0KDQpUaGlzIGlzIG91ciBmaXJzdCBsYWIgd2hlbiB3ZSBhcmUgY29uc2lkZXJpbmcgMiBkaW1lbnNpb25zIGFuZCBpbnN0ZWFkIG9mIGNhbGN1bGF0aW5nIHVuaXZhcmlhdGUgc3RhdGlzdGljcyBieSBncm91cHMgKG9yIGZhY3RvcnMpIG9mIG90aGVyIHZhcmlhYmxlIC0gd2Ugd2lsbCBtZWFzdXJlIHRoZWlyIGNvbW1vbiByZWxhdGlvbnNoaXBzIGJhc2VkIG9uIGNvLXZhcmlhbmNlIGFuZCBjb3JyZWxhdGlvbiBjb2VmZmljaWVudHMuIA0KDQoqUGxlYXNlIGJlIHZlcnkgY2FyZWZ1bCB3aGVuIGNob29zaW5nIHRoZSBtZWFzdXJlIG9mIGNvcnJlbGF0aW9uISBJbiBjYXNlIG9mIGRpZmZlcmVudCBtZWFzdXJlbWVudCBzY2FsZXMgd2UgaGF2ZSB0byByZWNvZGUgb25lIG9mIHRoZSB2YXJpYWJsZXMgaW50byB3ZWFrZXIgc2NhbGUuDQoNCkl0IHdvdWxkIGJlIG5pY2UgdG8gYWRkIHNvbWUgYWRkaXRpb25hbCBwbG90cyBpbiB0aGUgYmFja2dyb3VuZC4gRmVlbCBmcmVlIHRvIGFkZCB5b3VyIG93biBzZWN0aW9ucyBhbmQgdXNlIGV4dGVybmFsIHBhY2thZ2VzLg0KDQojIyBEYXRhDQoNClRoaXMgdGltZSB3ZSBhcmUgZ29pbmcgdG8gdXNlIGEgdHlwaWNhbCBjcmVkaXQgc2NvcmluZyBkYXRhIHdpdGggcHJlZGVmaW5lZCAiZGVmYXVsdCIgdmFyaWFibGVzIGFuZCBwZXJzb25hbCBkZW1vZ3JhcGhpYyBhbmQgaW5jb21lIGRhdGEuIFBsZWFzZSB0YWtlIGEgbG9vayBjbG9zZXIgYXQgaGVhZGVycyBhbmQgZGVzY3JpcHRpb25zIG9mIGVhY2ggdmFyaWFibGUuDQoNCmBgYHtyIGxvYWQtZGF0YSwgd2FybmluZz1UUlVFLCBpbmNsdWRlPUZBTFNFfQ0KZG93bmxvYWQuZmlsZSgiaHR0cHM6Ly9naXRodWIuY29tL2tmbGlzaWtvd3NraS9kcy9ibG9iL21hc3Rlci9iYW5rX2RlZmF1bHRzLnNhdj9yYXc9dHJ1ZSIsIGRlc3RmaWxlID0iYmFua19kZWZhdWx0cy5zYXYiLG1vZGU9IndiIikNCmJhbmtfZGVmYXVsdHMgPC0gcmVhZF9zYXYoImJhbmtfZGVmYXVsdHMuc2F2IikNCmJhbms8LW5hLm9taXQoYmFua19kZWZhdWx0cykNCmJhbmskZGVmPC1hcy5mYWN0b3IoYmFuayRkZWZhdWx0KQ0KYmFuayRlZHVjPC1hcy5mYWN0b3IoYmFuayRlZCkNCmBgYA0KDQojIyBTY2F0dGVycGxvdHMNCg0KRmlyc3QgbGV0J3MgdmlzdWFsaXplIG91ciBxdWFudGl0YXRpdmUgcmVsYXRpb25zaGlwcyB1c2luZyBzY2F0dGVyIHBsb3RzLiANCg0KYGBge3IgZWNobz1GQUxTRSwgd2FybmluZz1UUlVFfQ0KIyBCYXNpYyBzY2F0dGVyIHBsb3QNCmdncGxvdChiYW5rLCBhZXMoeCA9IGFnZSwgeSA9IGluY29tZSkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgbGFicyh4ID0gIkFnZSIsDQogICAgICAgeSA9ICJJbmNvbWUiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCllvdSBjYW4gYWxzbyBub3JtYWxpemUgdGhlIHNrZXdlZCBkaXN0cmlidXRpb24gb2YgaW5jb21lcyB1c2luZyBsb2c6DQoNCmBgYHtyIGVjaG89RkFMU0UsIHdhcm5pbmc9VFJVRX0NCiMgQmFzaWMgc2NhdHRlciBwbG90IHdpdGggdGhlIGxvZyBvZiBpbmNvbWUNCmJhbmskbG9naW5jb21lIDwtIGxvZyhiYW5rJGluY29tZSkNCg0KZ2dwbG90KGJhbmssIGFlcyh4ID0gYWdlLCB5ID0gbG9naW5jb21lLCBjb2xvciA9IGRlZiwgc2l6ZSA9IGVkdWMpKSArDQogIGdlb21fcG9pbnQoKQ0KDQpjb3IoYmFuayRsb2dpbmNvbWUsIGJhbmskYWdlLCBtZXRob2QgPSAia2VuZGFsbCIpDQpjb3IoYmFuayRsb2dpbmNvbWUsIGJhbmskZWQsIG1ldGhvZCA9ICJrZW5kYWxsIikNCnBjb3IudGVzdChiYW5rJGxvZ2luY29tZSwgYmFuayRhZ2UsIGJhbmskZWQpICMgcGFydGlhbCBjb3JyZWxhdGlvbg0KcGNvci50ZXN0KGJhbmskbG9naW5jb21lLCBiYW5rJGFnZSwgYmFuayRlbXBsb3kpDQpgYGANCg0KV2UgY2FuIGFkZCBhbiBlc3RpbWF0ZWQgbGluZWFyIHJlZ3Jlc3Npb24gbGluZToNCg0KYGBge3IgZWNobz1GQUxTRSwgd2FybmluZz1UUlVFfQ0KZ2dwbG90KGJhbmssIGFlcyh4ID0gYWdlLCB5ID0gbG9naW5jb21lKSkgKw0KICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGRlZiksIGFscGhhID0gMC41KSArIA0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IFRSVUUsIGNvbG9yID0gImJsdWUiKSArIA0KICBsYWJzKHggPSAiQWdlIiwgeSA9ICJMb2dnZWQgaW5jb21lIiwgdGl0bGUgPSAiQWdlIHZzIExvZ2dlZCBpbmNvbWUgd2l0aCBsaW5lYXIgdHJlbmQiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCiMjIFNjYXR0ZXJwbG90cyBieSBncm91cHMgDQoNCldlIGNhbiBmaW5hbGx5IHNlZSBpZiB0aGVyZSBhbnkgZGlmZmVyZW5jZXMgYmV0d2VlbiByaXNrIHN0YXR1czoNCg0KYGBge3IgZWNobz1GQUxTRSwgd2FybmluZz1UUlVFfQ0KZ2dwbG90KGJhbmssIGFlcyh4ID0gYWdlLCB5ID0gbG9naW5jb21lKSkgKw0KICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGVkdWMpLCBhbHBoYSA9IDAuNSwgc2l6ZSA9IDMpICsgDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG9yID0gImJsYWNrIikgKyANCiAgZmFjZXRfd3JhcCh+IGRlZiwgc2NhbGVzID0gImZyZWVfeSIpICsgDQogIGxhYnMoeCA9ICJBZ2UiLCB5ID0gIkxvZ2dlZCBJbmNvbWUiLCB0aXRsZSA9ICJBZ2UgdnMgTG9nZ2VkIEluY29tZSBieSBEZWZhdWx0IFN0YXR1cyIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KV2UgY2FuIGFsc28gc2VlIG1vcmUgY2xvc2VseSBpZiB0aGVyZSBhbnkgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aG9zZSB0d28gZGlzdHJpYnV0aW9ucyBhZGRpbmcgdGhlaXIgZXN0aW1hdGVkIGRlbnNpdHkgcGxvdHM6DQoNCmBgYHtyIGVjaG89RkFMU0UsIHdhcm5pbmc9VFJVRX0NCmxpYnJhcnkoZ2dwbG90MikNCg0KcCA8LSBnZ3Bsb3QoYmFuaywgYWVzKHggPSBhZ2UsIHkgPSBsb2dpbmNvbWUsIGNvbG9yID0gZGVmKSkgKw0KICBnZW9tX3BvaW50KGFscGhhID0gMC41KSArICANCiAgbGFicyh4ID0gIkFnZSIsIHkgPSAiTG9nZ2VkIEluY29tZSIsIHRpdGxlID0gIlNjYXR0ZXIgUGxvdCBvZiBBZ2UgdnMgTG9nZ2VkIEluY29tZSIpICsNCiAgdGhlbWVfbWluaW1hbCgpIA0KDQpwcmludChwKSAgDQpsaWJyYXJ5KGdnRXh0cmEpDQoNCmdnRXh0cmE6OmdnTWFyZ2luYWwocCwgdHlwZSA9ICJkZW5zaXR5IiwgZ3JvdXBGaWxsID0gVFJVRSwgc2l6ZSA9IDUpDQoNCmBgYA0KDQpXZSBjYW4gYWxzbyBwdXQgdGhvc2UgcGxvdHMgdG9nZXRoZXI6DQoNCmBgYHtyIGVjaG89RkFMU0UsIHdhcm5pbmc9VFJVRX0NCmxpYnJhcnkoZ2dwbG90MikNCg0KcCA8LSBnZ3Bsb3QoYmFuaywgYWVzKHggPSBhZ2UsIHkgPSBsb2dpbmNvbWUsIGNvbG9yID0gZGVmKSkgKw0KICBnZW9tX3BvaW50KGFscGhhID0gMC41KSArDQogIGxhYnMoeCA9ICJBZ2UiLCB5ID0gIkxvZ2dlZCBJbmNvbWUiLCB0aXRsZSA9ICJTY2F0dGVyIFBsb3Qgd2l0aCBNYXJnaW5hbCBEZW5zaXRpZXMiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpnZ0V4dHJhOjpnZ01hcmdpbmFsKHAsIHR5cGUgPSAiZGVuc2l0eSIsIGdyb3VwRmlsbCA9IFRSVUUsIHNpemUgPSA1KQ0KYGBgDQoNCiMjIFNjYXR0ZXJwbG90cyB3aXRoIGRlbnNpdHkgY3VydmVzIA0KDQpXZSBjYW4gYWxzbyBzZWUgbW9yZSBjbG9zZWx5IGlmIHRoZXJlIGFueSBkaWZmZXJlbmNlcyBiZXR3ZWVuIHRob3NlIHR3byBkaXN0cmlidXRpb25zIGFkZGluZyB0aGVpciBlc3RpbWF0ZWQgZGVuc2l0eSBwbG90czoNCg0KYGBge3IgZWNobz1GQUxTRSwgd2FybmluZz1UUlVFfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShncmlkRXh0cmEpIA0KDQoNCmFnZV9kZW5zaXR5X3Bsb3QgPC0gZ2dwbG90KGJhbmssIGFlcyh4ID0gYWdlLCBmaWxsID0gZGVmKSkgKyANCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC41KSArIA0KICBsYWJzKHRpdGxlID0gIkRlbnNpdHkgUGxvdCBvZiBBZ2UiLCB4ID0gIkFnZSIsIHkgPSAiRGVuc2l0eSIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI0ZGOTk5OSIsICIjOTk5OUZGIikpICANCg0KaW5jb21lX2RlbnNpdHlfcGxvdCA8LSBnZ3Bsb3QoYmFuaywgYWVzKHggPSBsb2dpbmNvbWUsIGZpbGwgPSBkZWYpKSArIA0KICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjUpICsgDQogIGxhYnModGl0bGUgPSAiRGVuc2l0eSBQbG90IG9mIExvZ2dlZCBJbmNvbWUiLCB4ID0gIkxvZ2dlZCBJbmNvbWUiLCB5ID0gIkRlbnNpdHkiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNGRjk5OTkiLCAiIzk5OTlGRiIpKSAgDQoNCmdyaWRFeHRyYTo6Z3JpZC5hcnJhbmdlKGFnZV9kZW5zaXR5X3Bsb3QsIGluY29tZV9kZW5zaXR5X3Bsb3QsIG5yb3cgPSAxKQ0KYGBgDQoNCiMjIENvcnJlbGF0aW9uIGNvZWZmaWNpZW50cyAtIFBlYXJzb24ncyBsaW5lYXIgY29ycmVsYXRpb24NCg0KT2ssIGxldCdzIG1vdmUgdG8gc29tZSBjYWxjdWxhdGlvbnMuDQpJbiBSLCB3ZSBjYW4gdXNlIHRoZSBjb3IoKSBmdW5jdGlvbi4gSXQgdGFrZXMgdGhyZWUgYXJndW1lbnRzIGFuZCB0aGUgbWV0aG9kOiBjb3IoeCwgeSwgbWV0aG9kKQ0KRm9yIDIgcXVhbnRpdGF0aXZlIGRhdGEsIHdpdGggYWxsIGFzc3VtcHRpb25zIG1ldCwgd2UgY2FuIGNhbGN1bGF0ZSBzaW1wbGUgUGVhcnNvbidzIGNvZWZmaWNpZW50IG9mIGxpbmVhciBjb3JyZWxhdGlvbjoNCg0KYGBge3IgZWNobz1GQUxTRSwgd2FybmluZz1UUlVFfQ0KcGVhcnNvbnNfY29ycmVsYXRpb24gPC0gY29yKGJhbmskYWdlLCBiYW5rJGxvZ2luY29tZSwgbWV0aG9kID0gInBlYXJzb24iKQ0KDQpwZWFyc29uc19jb3JyZWxhdGlvbg0KYGBgDQoNCk9rLCB3aGF0IGFib3V0IHRoZSBwZXJjZW50YWdlIG9mIHRoZSBleHBsYWluZWQgdmFyaWFiaWxpdHk/DQoNCmBgYHtyIGVjaG89RkFMU0UsIHdhcm5pbmc9VFJVRX0NCnJfc3F1YXJlZCA8LSBwZWFyc29uc19jb3JyZWxhdGlvbl4yDQoNCnJfc3F1YXJlZF9wZXJjZW50YWdlIDwtIHJfc3F1YXJlZCAqIDEwMCAgDQoNCmNhdChyX3NxdWFyZWRfcGVyY2VudGFnZSwgIiUiKQ0KYGBgDQpTbyBhcyB3ZSBjYW4gc2VlIGFsbW9zdCAzMi45OSUgb2YgdG90YWwgbG9nIG9mIGluY29tZXMnIHZhcmlhYmlsaXR5IGlzIGV4cGxhaW5lZCBieSBkaWZmZXJlbmNlcyBpbiBhZ2UuIFRoZSByZXN0IDY3JSBpcyBwcm9iYWJseSBleHBsYWluZWQgYnkgb3RoZXIgZmFjdG9ycy4NCg0KIyMgUGFydGlhbCBhbmQgc2VtaXBhcnRpYWwgY29ycmVsYXRpb24gDQoNClRoZSBwYXJ0aWFsIGFuZCBzZW1pLXBhcnRpYWwgKGFsc28ga25vd24gYXMgcGFydCkgY29ycmVsYXRpb25zIGFyZSB1c2VkIHRvIGV4cHJlc3MgdGhlIHNwZWNpZmljIHBvcnRpb24gb2YgdmFyaWFuY2UgZXhwbGFpbmVkIGJ5IGVsaW1pbmF0aW5nIHRoZSBlZmZlY3Qgb2Ygb3RoZXIgdmFyaWFibGVzIHdoZW4gYXNzZXNzaW5nIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHR3byB2YXJpYWJsZXMuDQoNClBhcnRpYWwgY29ycmVsYXRpb24gaG9sZHMgY29uc3RhbnQgb25lIHZhcmlhYmxlIHdoZW4gY29tcHV0aW5nIHRoZSByZWxhdGlvbnMgdG8gb3RoZXJzLiBTdXBwb3NlIHdlIHdhbnQgdG8ga25vdyB0aGUgY29ycmVsYXRpb24gYmV0d2VlbiBYIGFuZCBZIGhvbGRpbmcgWiBjb25zdGFudCBmb3IgYm90aCBYIGFuZCBZLiBUaGF0IHdvdWxkIGJlIHRoZSBwYXJ0aWFsIGNvcnJlbGF0aW9uIGJldHdlZW4gWCBhbmQgWSBjb250cm9sbGluZyBmb3IgWi4gDQoNClNlbWlwYXJ0aWFsIGNvcnJlbGF0aW9uIGhvbGRzIFogY29uc3RhbnQgZm9yIGVpdGhlciBYIG9yIFksIGJ1dCBub3QgYm90aCwgc28gaWYgd2Ugd2FudGVkIHRvIGNvbnRyb2wgWCBmb3IgWiwgd2UgY291bGQgY29tcHV0ZSB0aGUgc2VtaXBhcnRpYWwgY29ycmVsYXRpb24gYmV0d2VlbiBYIGFuZCBZIGhvbGRpbmcgWiBjb25zdGFudCBmb3IgWC4NCg0KU3VwcG9zZSB3ZSB3YW50IHRvIGtub3cgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIGxvZyBvZiBpbmNvbWUgYW5kIGFnZSBjb250cm9sbGluZyBmb3IgeWVhcnMgb2YgZW1wbG95bWVudC4gSG93IGhpZ2hseSBjb3JyZWxhdGVkIGFyZSB0aGVzZSBhZnRlciBjb250cm9sbGluZyBmb3IgdGVudXJlPyANCg0KKipUaGVyZSBjYW4gYmUgbW9yZSB0aGFuIG9uZSBjb250cm9sIHZhcmlhYmxlLg0KDQpgYGB7ciBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShwcGNvcikNCg0KbGlicmFyeShwcGNvcikNCg0KcGFydGlhbF9jb3JyIDwtIHBjb3IudGVzdChiYW5rJGxvZ2luY29tZSwgYmFuayRhZ2UsIGJhbmskZW1wbG95LCBtZXRob2QgPSAicGVhcnNvbiIpDQoNCmNhdCgiUGFydGlhbCBDb3JyZWxhdGlvbiAoY29udHJvbGxpbmcgZm9yIHllYXJzIG9mIGVtcGxveW1lbnQpOiIsIHBhcnRpYWxfY29yciRlc3RpbWF0ZSwgIlxuIikNCg0KbW9kZWxfZnVsbCA8LSBsbShsb2dpbmNvbWUgfiBhZ2UgKyBlbXBsb3ksIGRhdGEgPSBiYW5rKQ0KbW9kZWxfY29udHJvbCA8LSBsbShhZ2UgfiBlbXBsb3ksIGRhdGEgPSBiYW5rKQ0KDQpyZXNpZHVhbHNfYWdlIDwtIHJlc2lkdWFscyhtb2RlbF9jb250cm9sKQ0KDQpzZW1pcGFydGlhbF9jb3JyIDwtIGNvcihyZXNpZHVhbHNfYWdlLCBiYW5rJGxvZ2luY29tZSwgbWV0aG9kID0gInBlYXJzb24iKQ0KDQpjYXQoIlNlbWlwYXJ0aWFsIENvcnJlbGF0aW9uIChjb250cm9sbGluZyBmb3IgeWVhcnMgb2YgZW1wbG95bWVudCBvbiBhZ2UpOiIsIHNlbWlwYXJ0aWFsX2NvcnIsICJcbiIpDQpgYGANCg0KSG93IGNhbiB3ZSBpbnRlcnByZXQgdGhlIG9idGFpbmVkIHBhcnRpYWwgY29ycmVsYXRpb24gY29lZmZpY2llbnQ/IFdoYXQgaXMgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGF0IG9uZSBhbmQgdGhlIHNlbWktcGFydGlhbCBjb2VmZmljaWVudDoNCg0KVGhlIHBhcnRpYWwgY29ycmVsYXRpb24gYmV0d2VlbiBsb2dnZWQgaW5jb21lIGFuZCBhZ2UsIGNvbnRyb2xsaW5nIGZvciB5ZWFycyBvZiBlbXBsb3ltZW50LCBpcyAwLjMxOTQyNjMgLg0KVGhpcyB2YWx1ZSBpbmRpY2F0ZXMgdGhhdCB0aGUgdW5pcXVlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGFnZSBhbmQgbG9nZ2VkIGluY29tZSwgaW5kZXBlbmRlbnQgb2YgdGhlIHllYXJzIG9mIGVtcGxveW1lbnQsIGlzIHBvc2l0aXZlICwgc3VnZ2VzdGluZyB0aGF0IG9sZGVyIGluZGl2aWR1YWxzIHRlbmQgdG8gaGF2ZSBoaWdoZXIgbG9nZ2VkIGluY29tZXMsIGFmdGVyIGFjY291bnRpbmcgZm9yIHRoZWlyIHllYXJzIG9mIGVtcGxveW1lbnQuIA0KDQpUaGUgc2VtaXBhcnRpYWwgY29ycmVsYXRpb24sIG9uIHRoZSBvdGhlciBoYW5kLCBzaG93cyBob3cgbXVjaCBvZiB0aGUgdmFyaWFuY2UgaW4gbG9nZ2VkIGluY29tZSBjYW4gYmUgZXhwbGFpbmVkIHVuaXF1ZWx5IGJ5IGFnZSwgYWZ0ZXIgY29udHJvbGxpbmcgZm9yIHRoZSBlZmZlY3Qgb2YgeWVhcnMgb2YgZW1wbG95bWVudCBvbmx5IG9uIHRoZSBhZ2UgdmFyaWFibGUuIFRoZSBzZW1pcGFydGlhbCBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCBpcyAwLjIyMDM3MTEuIFRoaXMgbWVhc3VyZSBoaWdobGlnaHRzIHRoZSBkaXJlY3QgaW5mbHVlbmNlIG9mIGFnZSBvbiBsb2dnZWQgaW5jb21lIHdpdGhvdXQgdGhlIG1peGVkIGVmZmVjdHMgb2YgZW1wbG95bWVudCBkdXJhdGlvbiBvbiBhZ2UuDQoNCiMjIFJhbmsgY29ycmVsYXRpb24gDQoNCkZvciAyIGRpZmZlcmVudCBzY2FsZXMgLSBsaWtlIGZvciBleGFtcGxlIHRoaXMgcGFpciBvZiB2YXJpYWJsZXM6IGluY29tZSB2cy4gZWR1Y2F0aW9uIGxldmVscyAtIHdlIGNhbm5vdCB1c2UgUGVhcnNvbidzIGNvZWZmaWNpZW50LiBUaGUgb25seSBwb3NzaWJpbGl0eSBpcyB0byByYW5rIGFsc28gaW5jb21lcy4uLiBhbmQgbG9zZSBzb21lIG1vcmUgZGV0YWlsZWQgaW5mb3JtYXRpb24gYWJvdXQgdGhlbS4gDQoNCkZpcnN0LCBsZXQncyBzZWUgYm94cGxvdHMgb2YgaW5jb21lIGJ5IGVkdWNhdGlvbiBsZXZlbHMuDQoNCmBgYHtyIGVjaG89RkFMU0UsIHdhcm5pbmc9VFJVRX0NCmdncGxvdChiYW5rLCBhZXMoeCA9IGVkdWMsIHkgPSBpbmNvbWUsIGZpbGwgPSBlZHVjKSkgKyAgDQogIGdlb21fYm94cGxvdChvdXRsaWVyLmNvbG9yID0gInJlZCIsIG91dGxpZXIuc2hhcGUgPSAxKSArICANCiAgbGFicyh0aXRsZSA9ICJCb3hwbG90cyBvZiBJbmNvbWUgYnkgRWR1Y2F0aW9uIExldmVscyIsDQogICAgICAgeCA9ICJFZHVjYXRpb24gTGV2ZWwiLA0KICAgICAgIHkgPSAiSW5jb21lIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKyAgDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiUGFzdGVsMSIpDQpgYGANCg0KTm93LCBsZXQncyBzZWUgS2VuZGFsJ3MgY29lZmZpY2llbnQgb2YgcmFuayBjb3JyZWxhdGlvbiAocm9idXN0IGZvciB0aWVzKS4NCg0KYGBge3IgZWNobz1GQUxTRSwgd2FybmluZz1UUlVFfQ0KYmFuayRlZHVjX251bWVyaWMgPC0gYXMubnVtZXJpYyhhcy5mYWN0b3IoYmFuayRlZHVjKSkNCg0KDQprZW5kYWxsc190YXUgPC0gY29yKGJhbmskaW5jb21lLCBiYW5rJGVkdWNfbnVtZXJpYywgbWV0aG9kID0gImtlbmRhbGwiKQ0KDQpjYXQoa2VuZGFsbHNfdGF1KQ0KYGBgDQoNCg0KIyMgUG9pbnQtYmlzZXJpYWwgY29ycmVsYXRpb24NCg0KTGV0J3MgdHJ5IHRvIHZlcmlmeSBpZiB0aGVyZSBpcyBhIHNpZ25pZmljYW50IHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGluY29tZXMgYW5kIHJpc2sgc3RhdHVzLiBGaXJzdCwgbGV0J3MgdGFrZSBhIGxvb2sgYXQgdGhlIGJveHBsb3Q6DQoNCmBgYHtyIGVjaG89RkFMU0UsIHdhcm5pbmc9VFJVRX0NCmdncGxvdChiYW5rLCBhZXMoeCA9IGVkdWMsIHkgPSBpbmNvbWUsIGZpbGwgPSBkZWZhdWx0KSkgKyAgDQogIGdlb21fYm94cGxvdChvdXRsaWVyLmNvbG9yID0gInJlZCIsIG91dGxpZXIuc2hhcGUgPSAxKSArICANCiAgbGFicyh0aXRsZSA9ICJSZWxhdGlvbnNoaXAgLSBpbmNvbWUgYW5kIHJpc2sgc3RhdHVzIiwNCiAgICAgICB4ID0gIlJpc2sgU3RhdHVzIiwNCiAgICAgICB5ID0gIkluY29tZSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KSWYgeW91IHdvdWxkIGxpa2UgdG8gY29tcGFyZSAxIHF1YW50aXRhdGl2ZSB2YXJpYWJsZSAoaW5jb21lKSBhbmQgMSBkeWNob3RvbW91cyB2YXJpYWJsZSAoZGVmYXVsdCBzdGF0dXMgLSBiaW5hcnkpLCB0aGVuIHlvdSBjYW4gdXNlIHBvaW50LWJpc2VyaWFsIGNvZWZmaWNpZW50Og0KDQpgYGB7ciBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KY29yLnRlc3QoYmFuayRpbmNvbWUsIGFzLm51bWVyaWMoYmFuayRkZWZhdWx0KSwgbWV0aG9kID0gInBlYXJzb24iKQ0KYGBgDQpUaGUgcG9pbnQtYmlzZXJpYWwgY29ycmVsYXRpb24gY29lZmZpY2llbnQgaXMgfiAtMC4wNzEuDQpJdCBpcyBuZWdhdGl2ZSwgc28gaXQgbWVhbnMgdGhhdCB3aGVuIGluY29tZSBpbmNyZWFzZXMsIGxpa2VsaWhvb2Qgb2YgZGVmYXVsdGluZyBvbiBhIGxvYW4gZGVjcmVhc2VzLiBJdCBtYWtlcyBzZW5zZSwgYmVjYXVzZSBwZW9wbGUgd2l0aCBoaWdoZXIgaW5jb21lcyBhcmUgdXN1YWxseSBsZXNzIGxpa2VseSB0byBkZWZhdWx0Lg0KQnV0IGFsc28sIHAtdmFsdWUgY2FuIHN1Z2dlc3QgdGhhdCB0aGlzIHJlbGF0aW9uc2hpcCBpcyBub3Qgc28gc3Ryb25nIGFzIEkgd291bGQgdGhvdWdodCBpdCBpcywgYmVjYXVzZSBpdCBpcyBhYm92ZSBsZXZlbCBvZiAwLjA1Lg0KDQojIyBOb25saW5lYXIgY29ycmVsYXRpb24gLSBldGEgY29lZmZpY2llbnQNCg0KSWYgeW91IHdvdWxkIGxpa2UgdG8gY2hlY2sgaWYgdGhlcmUgYXJlIGFueSBub25saW5lYXJpdGllcyBiZXR3ZWVuIDIgdmFyaWFibGVzLCB0aGUgb25seSBwb3NzaWJpbGl0eSAoYmVzaWRlIHRyYW5zZm9ybWF0aW9ucyBhbmQgbGluZWFyIGFuYWx5c2lzKSBpcyB0byBjYWxjdWxhdGUgImV0YSIgY29lZmZpY2llbnQgYW5kIGNvbXBhcmUgaXQgd2l0aCB0aGUgUGVhcnNvbidzIGxpbmVhciBjb2VmZmljaWVudC4gDQoNCmBgYHtyIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQphb3ZfbW9kZWwgPC0gYW92KGluY29tZSB+IGFzLmZhY3RvcihkZWZhdWx0KSwgZGF0YSA9IGJhbmspDQoNCnN1bV9zcSA8LSBzdW1tYXJ5KGFvdl9tb2RlbClbWzFdXVssICJTdW0gU3EiXQ0KDQpldGFfc3EgPC0gc3VtX3NxWzFdIC8gc3VtKHN1bV9zcSkNCg0KZXRhX2NvZWZmaWNpZW50IDwtIHNxcnQoZXRhX3NxKQ0KDQpldGFfY29lZmZpY2llbnQNCg0KYGBgDQpFdGEgY29lZmZpY2llbnQgaXMgfiAwLjA3MSwgc28gaXQgaXMgdGhlIHNhbWUgYXMgcHJldmlvdXNseSBjYWxjdWxhdGVkIHBvaW50LWJpc2VyaWFsIGNvZWZmaWNpZW50Lg0KSXQgbWVhbnMgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIG91ciAyIHZhcmlhYmxlcyBpcyBlbnRpcmVseSBsaW5lYXIuDQoNCiMjIENvcnJlbGF0aW9uIG1hdHJpeA0KDQpXZSBjYW4gYWxzbyBwcmVwYXJlIHRoZSBjb3JyZWxhdGlvbiBtYXRyaXggZm9yIGFsbCBxdWFudGl0YXRpdmUgdmFyaWFibGVzIHN0b3JlZCBpbiBvdXIgZGF0YSBmcmFtZS4gDQoNCldlIGNhbiB1c2UgZ2djb3JyKCkgZnVuY3Rpb246DQoNCmBgYHtyIGVjaG89RkFMU0UsIHdhcm5pbmc9VFJVRX0NCm51bV92YXIgPC0gYmFua1ssIHNhcHBseShiYW5rLCBpcy5udW1lcmljKV0NCg0KZ2djb3JyKG51bV92YXIsIGxhYmVsID0gVFJVRSwgaGp1c3QgPSAwLjc1LCBjb2xvciA9ICJibHVlIikNCmBgYA0KICANCkFzIHlvdSBjYW4gc2VlIC0gdGhlIGRlZmF1bHQgY29ycmVsYXRpb24gbWF0cml4IGlzIG5vdCB0aGUgYmVzdCBpZGVhIGZvciBhbGwgbWVhc3VyZW1lbnQgc2NhbGVzIChpbmNsdWRpbmcgYmluYXJ5IHZhcmlhYmxlICJkZWZhdWx0IikuIA0KDQpUaGF0J3Mgd2h5IG5vdyB3ZSBjYW4gcGVyZm9ybSBvdXIgYml2YXJpYXRlIGFuYWx5c2lzIHdpdGggZ2dwYWlyIHdpdGggZ3JvdXBpbmcuDQoNCiMjIENvcnJlbGF0aW9uIG1hdHJpeCB3aXRoIHNjYXR0ZXJwbG90cyANCg0KSGVyZSBpcyB3aGF0IHdlIGFyZSBhYm91dCB0byBjYWxjdWxhdGU6DQotIFRoZSBjb3JyZWxhdGlvbiBtYXRyaXggYmV0d2VlbiBhZ2UsIGxvZ19pbmNvbWUsIGVtcGxveSwgYWRkcmVzcywgZGVidGluYywgY3JlZGRlYnQsIGFuZCBvdGhkZWJ0IHZhcmlhYmxlIGdyb3VwZWQgYnkgd2hldGhlciB0aGUgcGVyc29uIGhhcyBhIGRlZmF1bHQgc3RhdHVzIG9yIG5vdC4NCi0gUGxvdCB0aGUgZGlzdHJpYnV0aW9uIG9mIGVhY2ggdmFyaWFibGUgYnkgZ3JvdXANCi0gRGlzcGxheSB0aGUgc2NhdHRlciBwbG90IHdpdGggdGhlIHRyZW5kIGJ5IGdyb3VwDQoNCmBgYHtyfQ0KIyBmaXJzdCBjb3JyZWxhdGlvbiBtYXRyaXggc3RpbGwgdXNpbmcgZ2djb3JyDQoNCmJhbmskbG9nX2luY29tZSA8LSBsb2coYmFuayRpbmNvbWUpDQoNCmRhdGFfZm9yX21hdHJpeCA8LSBjKCJhZ2UiLCAibG9nX2luY29tZSIsICJlbXBsb3kiLCAiYWRkcmVzcyIsICJkZWJ0aW5jIiwgImNyZWRkZWJ0IiwgIm90aGRlYnQiKQ0KDQpkZWZhdWx0X2dyb3VwcyA8LSBzcGxpdChiYW5rLCBiYW5rJGRlZmF1bHQpDQoNCmNvcnJfbWF0cml4X3Bsb3RzIDwtIGxhcHBseShuYW1lcyhkZWZhdWx0X2dyb3VwcyksIGZ1bmN0aW9uKGdyb3VwKSB7DQogIGRhdGFfbnVtZXJpYyA8LSBkZWZhdWx0X2dyb3Vwc1tbZ3JvdXBdXVssIGRhdGFfZm9yX21hdHJpeCwgZHJvcCA9IEZBTFNFXQ0KICBkYXRhX251bWVyaWMgPC0gbmEub21pdChkYXRhX251bWVyaWMpDQogIHBsb3QgPC0gZ2djb3JyKGRhdGFfbnVtZXJpYywgbGFiZWwgPSBUUlVFLCAgaGp1c3QgPSAxKSArDQogICAgZ2d0aXRsZShwYXN0ZSgiQ29ycmVsYXRpb24gbWF0cml4OiAiLCBncm91cCkpDQogIHJldHVybihwbG90KQ0KfSkNCg0KIyBkaXNwbGF5aW5nIG1hdHJpY2VzDQpncmlkLmFycmFuZ2UoZ3JvYnMgPSBjb3JyX21hdHJpeF9wbG90cywgbmNvbCA9IDEpDQpgYGANCmBgYHtyfQ0KIyBhbmQgbm93IHVzaW5nIGdncGFpcnMgOikNCg0KZGF0YSA8LSBiYW5rWywgZGF0YV9mb3JfbWF0cml4XQ0KDQpwYWlyc19wbG90IDwtIGdncGFpcnMoZGF0YSwgDQogICAgICAgICAgICAgICAgICAgICAgYWVzKGNvbG9yID0gYXMuZmFjdG9yKGJhbmskZGVmYXVsdCksIGFscGhhID0gMC41KSwNCiAgICAgICAgICAgICAgICAgICAgICB1cHBlciA9IGxpc3QoY29udGludW91cyA9IHdyYXAoImNvciIsIHNpemUgPSA0KSksDQogICAgICAgICAgICAgICAgICAgICAgbG93ZXIgPSBsaXN0KGNvbnRpbnVvdXMgPSB3cmFwKCJwb2ludHMiLCBhbHBoYSA9IDAuNSkpLA0KICAgICAgICAgICAgICAgICAgICAgIGRpYWcgPSBsaXN0KGNvbnRpbnVvdXMgPSB3cmFwKCJiYXJEaWFnIiwgZmlsbCA9ICJ3aGl0ZSIpKSkNCg0KcHJpbnQocGFpcnNfcGxvdCkNCmBgYA0KVGhpcyBtYXRyaXggc2hvd3M6DQotIHNjYXR0ZXIgcGxvdHMgaW4gdGhlIGxvd2VyIHRyaWFuZ2xlDQotIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50cyBpbiB0aGUgdXBwZXIgdHJpYW5nbGUNCi0gZGVuc2l0eSBwbG90cyBvbiB0aGUgZGlhZ29uYWwNCg0KIyMgUXVhbGl0YXRpdmUgZGF0YQ0KDQpJbiBjYXNlIG9mIHR3byB2YXJpYWJsZXMgbWVhc3VyZWQgb24gbm9taW5hbCBvciBvcmRpbmFsJm5vbWluYWwgc2NhbGUgLSB3ZSBhcmUgZm9yY2VkIHRvIG9yZ2FuaXplIHNvIGNhbGxlZCAiY29udGluZ2VuY3kiIHRhYmxlIHdpdGggZnJlcXVlbmNpZXMgYW5kIGNhbGN1bGF0ZSBzb21lIGtpbmQgb2YgdGhlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50IGJhc2VkIG9uIHRoZW0uIFRoaXMgaXMgc28gY2FsbGVkICJjb250aW5nZW5jeSBhbmFseXNpcyIuIA0KDQpMZXQncyBjb25zaWRlciBvbmUgZXhhbXBsZSBiYXNlZCBvbiBvdXIgZGF0YTogdmVyaWZ5LCBpZiB0aGVyZSBpcyBhbnkgc2lnbmlmaWNhbnQgY29ycmVsYXRpb24gYmV0d2VlbiBlZHVjYXRpb24gbGV2ZWwgYW5kIGNyZWRpdCByaXNrLg0KDQpgYGB7cn0NCmNvbnRpbmdlbmN5X3RhYmxlIDwtIHRhYmxlKGJhbmskZWQsIGJhbmskZGVmYXVsdCkNCg0KY2hpX3NxdWFyZV9yZXN1bHQgPC0gY2hpc3EudGVzdChjb250aW5nZW5jeV90YWJsZSkNCg0KcHJpbnQoY2hpX3NxdWFyZV9yZXN1bHQpDQpgYGANCkZyb20gdGhlIHJlc3VsdCB3ZSBjYW4gYXNzdW1lIHRoYXQgdGhlc2UgdHdvIHZhcmlhYmxlcyBhcmUgbm90IGluZGVwZW5kZW50IGZyb20gZWFjaCBvdGhlciwgYnV0IHByb2JhYmx5IG1vcmUgdGVzdHMgYXJlIG5lZWRlZCB0byB0ZWxsIGV4YWN0bHkgaG93IGRlcGVuZGVudCB0aGV5IGFyZS4NCg0KIyMgRXhlcmNpc2UgMS4gQ29udGluZ2VuY3kgYW5hbHlzaXMuDQoNCkRvIHlvdSBiZWxpZXZlIGluIHRoZSBBZnRlcmxpZmU/DQpodHRwczovL25hdGlvbmFscG9zdC5jb20vbmV3cy9jYW5hZGEvbWlsbGVubmlhbHMtZG8teW91LWJlbGlldmUtaW4tbGlmZS1hZnRlci1saWZlDQpBIHN1cnZleSB3YXMgY29uZHVjdGVkIGFuZCBhIHJhbmRvbSBzYW1wbGUgb2YgMTA5MSBxdWVzdGlvbm5haXJlcyBpcyBnaXZlbiBpbiB0aGUgZm9ybSBvZiB0aGUgZm9sbG93aW5nIGNvbnRpbmdlbmN5IHRhYmxlOg0KDQpgYGB7ciBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KeD1jKDQzNSwxNDcsMzc1LDEzNCkNCmRpbSh4KT1jKDIsMikNCmRhbmU8LWFzLnRhYmxlKHgpDQpkaW1uYW1lcyhkYW5lKT1saXN0KEdlbmRlcj1jKCdGZW1hbGUnLCdNYWxlJyksQmVsaWV2ZT1jKCdZZXMnLCdObycpKQ0KZGFuZQ0KZm91cmZvbGRwbG90KGRhbmUpDQpgYGANCg0KT3VyIHRhc2sgaXMgdG8gY2hlY2sgaWYgdGhlcmUgaXMgYSBzaWduaWZpY2FudCByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgYmVsaWVmIGluIHRoZSBhZnRlcmxpZmUgYW5kIGdlbmRlci4gV2UgY2FuIHBlcmZvcm0gdGhpcyBwcm9jZWR1cmUgd2l0aCB0aGUgc2ltcGxlIGNoaS1zcXVhcmUgc3RhdGlzdGljcyBhbmQgY2hvc2VuIHF1YWxpdGF0aXZlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50ICh0d28td2F5IDJ4MiB0YWJsZSkuDQoNCmBgYHtyIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQp5ZXM8LWMoNDM1LDE0NykNCm5vPC1jKDM3NSwxMzQpDQojY29oZW4ua2FwcGEoY2JpbmQoeWVzLG5vKSkNCmNoaXNxLnRlc3QoZGFuZSkNCnByb3AudGFibGUoZGFuZSkNCmBgYA0KDQpBcyB5b3UgY2FuIHNlZSB3ZSBjYW4gY2FsY3VsYXRlIG91ciBjaGktc3F1YXJlIHN0YXRpc3RpYyByZWFsbHkgcXVpY2tseSBmb3IgdHdvLXdheSB0YWJsZXMgb3IgbGFyZ2VyLiANCk5vdyB3ZSBjYW4gc3RhbmRhcmRpemUgdGhpcyBjb250aW5nZW5jeSBtZWFzdXJlIHRvIHNlZSBpZiB0aGUgcmVsYXRpb25zaGlwIGlzIHNpZ25pZmljYW50Lg0KDQpgYGB7ciBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KUGhpKGRhbmUpDQojP0NvbnRDb2VmDQojQ29udENvZWYoZGFuZSkNCiNDcmFtZXJWKGRhbmUpDQojVHNjaHVwcm93VChkYW5lKQ0KbW9zYWljcGxvdChkYW5lKQ0KYmFycGxvdChkYW5lKQ0KYGBgDQoNCg0KIyMgRXhlcmNpc2UgMi4gQ29udGluZ2VuY3kgYW5hbHlzaXMgZm9yIHRoZSAnVGl0YW5pYycgZGF0YS4NCg0KTGV0J3MgY29uc2lkZXIgdGhlIHRpdGFuaWMgZGF0YXNldCB3aGljaCBjb250YWlucyBhIGNvbXBsZXRlIGxpc3Qgb2YgcGFzc2VuZ2VycyBhbmQgY3JldyBtZW1iZXJzIG9uIHRoZSBSTVMgVGl0YW5pYy4gSXQgaW5jbHVkZXMgYSB2YXJpYWJsZSBpbmRpY2F0aW5nIHdoZXRoZXIgYSBwZXJzb24gZGlkIHN1cnZpdmUgdGhlIHNpbmtpbmcgb2YgdGhlIFJNUyBUaXRhbmljIG9uIEFwcmlsIDE1LCAxOTEyLg0KQSBkYXRhIGZyYW1lIGNvbnRhaW5zIDI0NTYgb2JzZXJ2YXRpb25zIG9uIDE0IHZhcmlhYmxlcy4NCg0KYGBge3IgbG9hZC1kYXRhMiwgd2FybmluZz1UUlVFLCBpbmNsdWRlPUZBTFNFfQ0KZG93bmxvYWQuZmlsZSgiaHR0cHM6Ly9naXRodWIuY29tL2tmbGlzaWtvd3NraS9kcy9ibG9iL21hc3Rlci90aXRhbmljLmNzdj9yYXc9dHJ1ZSIsIGRlc3RmaWxlID0idGl0YW5pYy5jc3YiLG1vZGU9IndiIikNCnRpdGFuaWMgPC0gcmVhZC5jc3YoInRpdGFuaWMuY3N2Iixyb3cubmFtZXM9MSxzZXA9IjsiKQ0KYGBgDQoNClRoZSB3ZWJzaXRlIGh0dHA6Ly93d3cuZW5jeWNsb3BlZGlhLXRpdGFuaWNhLm9yZy8gb2ZmZXJzIGRldGFpbGVkIGluZm9ybWF0aW9uIGFib3V0IHBhc3NlbmdlcnMgYW5kIGNyZXcgbWVtYmVycyBvbiB0aGUgUk1TIFRpdGFuaWMuIEFjY29yZGluZyB0byB0aGUgd2Vic2l0ZSAxMzE3IHBhc3NlbmdlcnMgYW5kIDg5MCBjcmV3IG1lbWJlciB3ZXJlIGFib2FyZC4NCg0KOCBtdXNpY2lhbnMgYW5kIDkgZW1wbG95ZWVzIG9mIHRoZSBzaGlweWFyZCBjb21wYW55IGFyZSBsaXN0ZWQgYXMgcGFzc2VuZ2VycywgYnV0IHRyYXZlbGxlZCB3aXRoIGEgZnJlZSB0aWNrZXQsIHdoaWNoIGlzIHdoeSB0aGV5IGhhdmUgTkEgdmFsdWVzIGluIGZhcmUuIEluIGFkZGl0aW9uIHRvIHRoYXQsIGZhcmUgaXMgdHJ1ZWx5IG1pc3NpbmcgZm9yIGEgZmV3IHJlZ3VsYXIgcGFzc2VuZ2Vycy4gDQoNCmBgYHtyfQ0KaGVhZCh0aXRhbmljKQ0Kc3VtbWFyeSh0aXRhbmljKQ0KDQojIFJlcGxhY2UgTkEgaW4gZmFyZSB3aXRoIHRoZSBtZWRpYW4gZmFyZQ0KdGl0YW5pYyRGYXJlW2lzLm5hKHRpdGFuaWMkRmFyZSldIDwtIG1lZGlhbih0aXRhbmljJEZhcmUsIG5hLnJtID0gVFJVRSkNCnRpdGFuaWMkQWdlW2lzLm5hKHRpdGFuaWMkQWdlKV0gPC0gbWVkaWFuKHRpdGFuaWMkQWdlLCBuYS5ybSA9IFRSVUUpDQoNCmdncGxvdCh0aXRhbmljLCBhZXMoeCA9IEFnZSwgZmlsbCA9IGZhY3RvcihTdGF0dXMpKSkgKyANCiAgICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDUsIHBvc2l0aW9uID0gImZpbGwiLCBjb2xvciA9ICJibGFjayIpICsgDQogICAgbGFicyh5ID0gIlByb3BvcnRpb24iLCB4ID0gIkFnZSIsIGZpbGwgPSAiU3RhdHVzIiwgdGl0bGUgPSAiU3Vydml2YWwgYnkgQWdlIikgKw0KICAgIHRoZW1lX21pbmltYWwoKQ0KDQojIGNvbnRpbmdlbmN5IHRhYmxlIG9mIHN1cnZpdmFsIGJ5IGNvdW50cnkNCnN1cnZpdmFsX2J5X2NvdW50cnkgPC0gdGFibGUodGl0YW5pYyRTdGF0dXMsIHRpdGFuaWMkSG9tZS5Db3VudHJ5KQ0KY2hpc3EudGVzdChzdXJ2aXZhbF9ieV9jb3VudHJ5KQ0KDQojIGNvbnRpbmdlbmN5IHRhYmxlIG9mIHN1cnZpdmFsIGJ5IGdlbmRlcg0Kc3Vydml2YWxfYnlfZ2VuZGVyIDwtIHRhYmxlKHRpdGFuaWMkU3RhdHVzLCB0aXRhbmljJEdlbmRlcikNCmNoaXNxLnRlc3Qoc3Vydml2YWxfYnlfZ2VuZGVyKQ0KDQojIGNvbnRpbmdlbmN5IHRhYmxlIG9mIHN1cnZpdmFsIGJ5IGFnZQ0Kc3Vydml2YWxfYnlfYWdlIDwtIHRhYmxlKHRpdGFuaWMkU3RhdHVzLCB0aXRhbmljJEFnZSkNCmNoaXNxLnRlc3Qoc3Vydml2YWxfYnlfYWdlKQ0KYGBgDQpGcm9tIHRoZSBwbG90IHdlIGNhbiBzZWUsIHRoYXQgdGhlcmUgaXMgc29tZSBzbWFsbCByZWxhdGlvbiBiZXR3ZWVuIGFnZSBhbmQgc3Vydml2aW5nIC0gZ2VuZXJhbGx5IHRoZXJlIHdlcmUgbW9yZSB5b3VuZ2VyIHRoYW4gb2xkZXIgcGVvcGxlIHdobyBzdXJ2aXZlZCwgYnV0IGFsc28gdGhlcmUgaXMgc29tZSBpbmNyZWFzZSB3aGVuIGxvb2tpbmcgYXQgb2xkIHBlb3BsZSAtIHRoYXQgd2VyZSBhYm91dCA2MCB5ZWFycyBvbGQuDQpMb29raW5nIGF0IGNoaS1zcXVhcmVkIHRlc3QgcmVzdWx0cywgZm9yIGV2ZXJ5IHRlc3RlZCB2YXJpYWJsZSBwLXZhbHVlIGlzIGV4dHJlbWVseSBsb3cuIEl0IG1lYW5zLCB0aGF0IHRoZXJlIGlzIHNpZ25pZmljYW50IGRlcGVuZGVuY2UgYmV0d2VlbiBzdXJ2aXZhbCBzdGF0dXMgYW5kIHRob3NlIHZhcmlhYmxlcy4NCg0K