Univariate Statistics
Before automatically reporting the full summary table of descriptive
statistics, this time your goal is to measure the central tendency of
the price distribution. Compare the mean, median, and mode along with
positional measures - quantiles - by district and building type or
number of rooms in the apartment.
mean(price_PLN)
## [1] 760035
median(price_PLN)
## [1] 755719.5
sd(price_PLN) #standard deviation
## [1] 186099.8
var(price_PLN) #variance
## [1] 34633125960
coeff_var<-sd(price_PLN)/mean(price_PLN) #coefficient of variability %
coeff_var
## [1] 0.2448568
IQR(price_PLN)# difference between quartiles =Q3-Q1
## 75%
## 282686.5
sx<-IQR(price_PLN)/2 #interquartile deviation
coeff_varx<-sx/median(price_PLN) #IQR coefficient of variability %
coeff_varx
## 75%
## 0.1870314
min(price_PLN)
## [1] 359769
max(price_PLN)
## [1] 1277691
quantile(price_PLN,probs=c(0,0.1,0.25,0.5,0.75,0.95,1),na.rm=TRUE)
## 0% 10% 25% 50% 75% 95% 100%
## 359769.0 518806.8 619073.8 755719.5 901760.2 1054250.8 1277691.0
Ok, we have calculated all of the basic summary statistics above.
Let’s wrap them up together now.
rooms
boxplot
histogram
line1
line2
points1
1
2
3
4
Summary tables
Ok, now we will finally summarize the basic measures of central
tendency for prices by district/building type using the
‘kable ’ package. Feel free to customize your
final report. See some hints here .
## 'qwraps2_summary_table' chr [1:14, 1:5] "\\bf{Price in PLN}" "~~ Min" ...
## - attr(*, "dimnames")=List of 2
## ..$ : NULL
## ..$ : chr [1:5] "" "1 (N = 44)" "2 (N = 50)" "3 (N = 58)" ...
## - attr(*, "qable_args")=List of 6
## ..$ rtitle : chr ""
## ..$ rgroup : Named int 13
## .. ..- attr(*, "names")= chr "Price in PLN"
## ..$ rnames : chr [1:13] "Min" "Max" "Q1" "Median" ...
## ..$ cnames : chr [1:5] "" "1 (N = 44)" "2 (N = 50)" "3 (N = 58)" ...
## ..$ markup : chr "latex"
## ..$ kable_args: list()
gtsummary
We can calculate easily descriptive statistics also using gtsummary
package:
apartments %>%
select(price_PLN,rooms) %>%
tbl_summary(label= price_PLN ~ "Price",digits=c(price_PLN)~2,by=rooms,type = all_continuous() ~ "continuous2", statistic = all_continuous() ~ c("{N_nonmiss}", "{median} ({p25}, {p75})", "{min}, {max}"),missing = "no")
Characteristic
1 , N = 44
2 , N = 50
3 , N = 58
4 , N = 48
Price
N
44.00
50.00
58.00
48.00
Median (IQR)
520,507.00 (479,684.75, 555,024.75)
677,260.00 (634,757.25, 717,728.50)
846,303.50 (769,683.75, 901,078.75)
964,338.50 (909,371.50, 1,050,976.75)
Range
359,769.00, 657,146.00
590,286.00, 888,634.00
632,770.00, 965,829.00
736,669.00, 1,277,691.00
dfSummary
dfSummary() creates a summary table with statistics, frequencies and
graphs for all variables in a data frame. The information displayed is
type-specific (character, factor, numeric, date) and also varies
according to the number of distinct values.
When using dfSummary() in R Markdown documents, it is generally a
good idea to exclude a column or two to avoid margin overflow. Since the
Valid and Missing columns are redundant, we can drop either one of
them.
dfSummary(apartments,
plain.ascii = FALSE,
style = "grid",
graph.magnif = 0.75,
valid.col = FALSE,
tmp.img.dir = "/tmp")
## temporary images written to 'C:\tmp'
Data Frame Summary
apartments
Dimensions: 200 x 6
Duplicates: 0
1
price_PLN
[numeric]
Mean (sd) : 760035 (186099.8)
min < med < max:
359769 < 755719.5 < 1277691
IQR (CV) : 282686.5 (0.2)
200 distinct values
0
(0.0%)
2
price_EUR
[numeric]
Mean (sd) : 175934 (43078.6)
min < med < max:
83280 < 174935 < 295762
IQR (CV) : 65436.2 (0.2)
200 distinct values
0
(0.0%)
3
rooms
[ordered, factor]
1. 1
2. 2
3. 3
4. 4
44 (22.0%)
50 (25.0%)
58 (29.0%)
48 (24.0%)
0
(0.0%)
4
size
[numeric]
Mean (sd) : 46.2 (20.1)
min < med < max:
17 < 43.7 < 87.7
IQR (CV) : 30.2 (0.4)
162 distinct values
0
(0.0%)
5
district
[factor]
1. Biskupin
2. Krzyki
3. Srodmiescie
65 (32.5%)
79 (39.5%)
56 (28.0%)
0
(0.0%)
6
building_type
[factor]
1. kamienica
2. niski blok
3. wiezowiec
61 (30.5%)
63 (31.5%)
76 (38.0%)
0
(0.0%)
To produce optimal results, summarytools has its own version of the
base by() function. It’s called stby(), and we use it exactly as we
would by():
(stats_by_rooms <- stby(data = apartments, INDICES = apartments$rooms, FUN = descr, stats = "common", transpose = TRUE))
## Non-numerical variable(s) ignored: rooms, district, building_type
Descriptive Statistics
apartments
Group: rooms = 1
N: 44
price_EUR
119332.95
15497.90
83280.00
120488.00
152117.00
44.00
100.00
price_PLN
515518.05
66951.03
359769.00
520507.00
657146.00
44.00
100.00
size
19.28
1.46
17.00
19.10
21.90
44.00
100.00
Group: rooms = 2
N: 50
price_EUR
158233.22
15063.13
136640.00
156773.00
205702.00
50.00
100.00
price_PLN
683567.70
65072.66
590286.00
677260.00
888634.00
50.00
100.00
size
36.80
4.46
29.60
35.95
43.70
50.00
100.00
Group: rooms = 3
N: 58
price_EUR
192987.55
20125.88
146475.00
195904.00
223572.00
58.00
100.00
price_PLN
833706.02
86943.90
632770.00
846303.50
965829.00
58.00
100.00
size
53.33
7.21
41.20
53.45
65.20
58.00
100.00
Group: rooms = 4
N: 48
price_EUR
225650.42
26347.03
170525.00
223226.50
295762.00
48.00
100.00
price_PLN
974809.96
113819.21
736669.00
964338.50
1277691.00
48.00
100.00
size
72.05
10.18
53.30
70.85
87.70
48.00
100.00
Tidy Tables
When generating freq() or descr() tables, it is possible to turn the
results into “tidy” tables with the use of the tb() function (think of
tb as a diminutive for tibble). For example:
apartments %>%
descr(stats = "common") %>%
tb()
## # A tibble: 3 × 8
## variable mean sd min med max n.valid pct.valid
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 price_EUR 175934. 43079. 83280 174935 295762 200 100
## 2 price_PLN 760035. 186100. 359769 755720. 1277691 200 100
## 3 size 46.2 20.1 17 43.7 87.7 200 100
Here are some examples showing how lists created using stby() or
group_by() can be transformed into tidy tibbles.
grouped_descr <- stby(data = apartments,INDICES = apartments$rooms, FUN = descr, stats = "common")
grouped_descr %>% tb()
## # A tibble: 12 × 9
## rooms variable mean sd min med max n.valid pct.valid
## <fct> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1 price_EUR 119333. 15498. 83280 120488 1.52e5 44 100
## 2 1 price_PLN 515518. 66951. 359769 520507 6.57e5 44 100
## 3 1 size 19.3 1.46 17 19.1 2.19e1 44 100
## 4 2 price_EUR 158233. 15063. 136640 156773 2.06e5 50 100
## 5 2 price_PLN 683568. 65073. 590286 677260 8.89e5 50 100
## 6 2 size 36.8 4.46 29.6 36.0 4.37e1 50 100
## 7 3 price_EUR 192988. 20126. 146475 195904 2.24e5 58 100
## 8 3 price_PLN 833706. 86944. 632770 846304. 9.66e5 58 100
## 9 3 size 53.3 7.21 41.2 53.4 6.52e1 58 100
## 10 4 price_EUR 225650. 26347. 170525 223226. 2.96e5 48 100
## 11 4 price_PLN 974810. 113819. 736669 964338. 1.28e6 48 100
## 12 4 size 72.0 10.2 53.3 70.8 8.77e1 48 100
A Bridge to Other Packages
stby(data = apartments,
INDICES = apartments$rooms,
FUN = descr,
stats = "fivenum") %>%
tb(order = 3) %>%
kable(format = "html", digits = 2) %>%
collapse_rows(columns = 1, valign = "top")
variable
rooms
min
q1
med
q3
max
price_EUR
1
83280.0
110881.0
120488.00
128568.00
152117.0
2
136640.0
146754.0
156773.00
166259.00
205702.0
3
146475.0
177478.0
195904.00
208599.00
223572.0
4
170525.0
209827.5
223226.50
243300.00
295762.0
price_PLN
1
359769.0
479005.5
520507.00
555411.50
657146.0
2
590286.0
633978.0
677260.00
718237.00
888634.0
3
632770.0
766707.0
846303.50
901149.00
965829.0
4
736669.0
906455.0
964338.50
1051055.50
1277691.0
size
1
17.0
18.1
19.10
20.60
21.9
2
29.6
32.9
35.95
40.50
43.7
3
41.2
47.9
53.45
59.70
65.2
4
53.3
64.2
70.85
82.15
87.7
Your turn!
Your task this week is to: prepare your own descriptive analysis for
the “CreditCard” dataset (AER package). It is a cross-sectional
dataframe on the credit history for a sample of applicants for a type of
credit card.
Are the yearly incomes (in USD 10,000), credit card expenditures,
age, ratio of monthly credit card expenditure to yearly income -
significantly different for applicants for customers with different
credit risk (“card” variable - factor)?
Prepare a professional data visualizations, descriptive statistics’
tables and interpret them.
# your code here
CreditCard$age<-as.numeric(CreditCard$age)
CreditCard$reports<-as.numeric(CreditCard$reports)
CreditCard$income<-as.numeric(CreditCard$income)
CreditCard$share<-as.numeric(CreditCard$share)
CreditCard$expenditure<-as.numeric(CreditCard$expenditure)
CreditCard$card<-as.factor(CreditCard$card)
credit_card_yes <- subset(CreditCard, card == 'yes')
credit_card_no <- subset(CreditCard, card == 'no')
credit_card_yes <- subset(CreditCard, card == 'yes')
credit_card_no <- subset(CreditCard, card == 'no')
age_yes <- credit_card_yes$age
age_no <- credit_card_no$age
summary(age_yes)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.1667 25.3333 31.0833 33.2160 39.7083 83.5000
summary(age_no)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.75 25.65 31.83 33.20 38.06 80.17
ggplot() +
geom_density(data = credit_card_yes, aes(x = age, fill = "Card Owner"), color = "coral4", alpha = 0.7) +
geom_density(data = credit_card_no, aes(x = age, fill = "Non-Owner"), color = "pink", alpha = 0.7) +
labs(x = "Age", y = "Density", title = "Density Plot of Age by Card Ownership") +
scale_fill_manual(values = c("Card Owner" = "coral4", "Non-Owner" = "pink"),
name = "Card Ownership",
labels = c("Owner", "Non-Owner")) +
theme_minimal()
ggplot() +
geom_boxplot(data = credit_card_yes, aes(x = "Card Owner", y = age, fill = "Card Owner"), color = "coral4", alpha = 0.7) +
geom_boxplot(data = credit_card_no, aes(x = "Non-Owner", y = age, fill = "Non-Owner"), color = "pink", alpha = 0.7) +
labs(x = "Card Ownership", y = "Age", title = "Boxplot of Age by Card Ownership") +
scale_fill_manual(values = c("Card Owner" = "coral4", "Non-Owner" = "pink"),
name = "Card Ownership",
labels = c("Owner", "Non-Owner")) +
theme_minimal()
summary_df_yes <- data.frame(
Statistic = c("Mean", "Median", "Standard Deviation", "Variance", "Coefficient of Variability (%)",
"Interquartile Range (IQR)", "Interquartile Deviation", "IQR Coefficient of Variability (%)",
"Minimum", "Maximum"),
Card_Owners = c(
mean(age_yes), median(age_yes), sd(age_yes), var(age_yes),
sd(age_yes) / mean(age_yes) * 100, IQR(age_yes), IQR(age_yes) / 2,
(IQR(age_yes) / 2) / median(age_yes) * 100, min(age_yes), max(age_yes)
)
)
summary_df_no <- data.frame(
Statistic = c("Mean", "Median", "Standard Deviation", "Variance", "Coefficient of Variability (%)",
"Interquartile Range (IQR)", "Interquartile Deviation", "IQR Coefficient of Variability (%)",
"Minimum", "Maximum"),
Non_Card_Owners = c(
mean(age_no), median(age_no), sd(age_no), var(age_no),
sd(age_no) / mean(age_no) * 100, IQR(age_no), IQR(age_no) / 2,
(IQR(age_no) / 2) / median(age_no) * 100, min(age_no), max(age_no)
)
)
summary_combined <- merge(summary_df_yes, summary_df_no, by = "Statistic", all = TRUE)
knitr::kable(summary_combined, format = "markdown", caption = "Summary Statistics for Age by Card Ownership") %>%
kable_styling(full_width = FALSE, bootstrap_options = "striped", position = "center")
Summary Statistics for Age by Card Ownership
Statistic
Card_Owners
Non_Card_Owners
Coefficient of Variability (%)
30.7404349
29.880709
Interquartile Deviation
7.1875025
6.208333
Interquartile Range (IQR)
14.3750050
12.416665
IQR Coefficient of Variability (%)
23.1233349
19.502614
Maximum
83.5000000
80.166660
Mean
33.2160312
33.202984
Median
31.0833300
31.833335
Minimum
0.1666667
0.750000
Standard Deviation
10.2107524
9.921287
Variance
104.2594649
98.431938
Summing up the data showing from the table and two plots of age of
people using credit cards and age of people who don’t we can present
some interesting information:
maximum age is bigger in the group using credit cards, which most
people would think is oppositely,
there is more people around age 25 who are owners of credit card
then people around same age not owing credit cards,
people owining cedit cards are mostly young people, we can see
big decline around age 27 to 35,
in the group owning credit card age is more diverse,
in both groups we have some data errors because we can see some
outliner around 0, which is impossible in real life,
income_yes <- credit_card_yes$income
income_no <- credit_card_no$income
summary(income_yes)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.210 2.350 3.000 3.451 4.000 13.500
summary(income_no)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.490 2.000 2.590 3.069 3.625 11.000
ggplot() +
geom_density(data = credit_card_yes, aes(x = income, fill = "Card Owner"), color = "violetred2", alpha = 0.7) +
geom_density(data = credit_card_no, aes(x = income, fill = "Non-Owner"), color = "violet", alpha = 0.7) +
labs(x = "Income", y = "Density", title = "Density Plot of Income (in USD 10,000) by Card Owners") +
scale_fill_manual(values = c("Card Owner" = "violetred2", "Non-Owner" = "violet"),
name = "Card Ownership",
labels = c("Owner", "Non-owner")) +
theme_minimal()
ggplot() +
geom_boxplot(data = credit_card_yes, aes(x = "Card Owner", y = income, fill = "Card Owner"), color = "violetred2", alpha = 0.7) +
geom_boxplot(data = credit_card_no, aes(x = "Non-Owner", y = income, fill = "Non-Owner"), color = "violet", alpha = 0.7) +
labs(x = "Card Ownership", y = "Income (in USD 10,000)", title = "Boxplot of Income (in USD 10,000) by Card Ownership") +
scale_fill_manual(values = c("Card Owner" = "violetred2", "Non-Owner" = "violet"),
name = "Card Ownership",
labels = c("Owner", "Non-Owner")) +
theme_minimal()
summary_df_yes <- data.frame(
Statistic = c("Mean", "Median", "Standard Deviation", "Variance", "Coefficient of Variability (%)",
"Interquartile Range (IQR)", "Interquartile Deviation", "IQR Coefficient of Variability (%)",
"Minimum", "Maximum"),
Card_Owners = c(
mean(income_yes), median(income_yes), sd(income_yes), var(income_yes),
sd(income_yes) / mean(income_yes) * 100, IQR(income_yes), IQR(income_yes) / 2,
(IQR(income_yes) / 2) / median(income_yes) * 100, min(income_yes), max(income_yes)
)
)
summary_df_no <- data.frame(
Statistic = c("Mean", "Median", "Standard Deviation", "Variance", "Coefficient of Variability (%)",
"Interquartile Range (IQR)", "Interquartile Deviation", "IQR Coefficient of Variability (%)",
"Minimum", "Maximum"),
Non_Card_Owners = c(
mean(income_no), median(income_no), sd(income_no), var(income_no),
sd(income_no) / mean(income_no) * 100, IQR(income_no), IQR(income_no) / 2,
(IQR(income_no) / 2) / median(income_no) * 100, min(income_no), max(income_no)
)
)
summary_combined <- merge(summary_df_yes, summary_df_no, by = "Statistic", all = TRUE)
knitr::kable(summary_combined, format = "markdown", caption = "Summary Statistics for Income by Card Ownership") %>%
kable_styling(full_width = FALSE, bootstrap_options = "striped", position = "center")
Summary Statistics for Income by Card Ownership
Statistic
Card_Owners
Non_Card_Owners
Coefficient of Variability (%)
49.463385
52.642387
Interquartile Deviation
0.825000
0.812500
Interquartile Range (IQR)
1.650000
1.625000
IQR Coefficient of Variability (%)
27.500000
31.370656
Maximum
13.500000
11.000000
Mean
3.451273
3.068509
Median
3.000000
2.590000
Minimum
0.210000
0.490000
Standard Deviation
1.707116
1.615336
Variance
2.914247
2.609312
Analizing data from the plots and table we can conclude:
there is bigger diversity in the income of card owners,
if we group card owners by hey income we can tell that the most
numerous group is the one of income 25000 USD,
if we do the same with non card owners then the biggest group is
the one of income around 20000 USD,
people with credit cards have bigger average income then people
without them,
maximum income of credit card owners is bigger then in non
owners.
income_age_yes <- credit_card_yes[, c("income", "age")]
summary(income_age_yes)
## income age
## Min. : 0.210 Min. : 0.1667
## 1st Qu.: 2.350 1st Qu.:25.3333
## Median : 3.000 Median :31.0833
## Mean : 3.451 Mean :33.2160
## 3rd Qu.: 4.000 3rd Qu.:39.7083
## Max. :13.500 Max. :83.5000
income_age_no <- credit_card_no[, c("income", "age")]
summary(income_age_no)
## income age
## Min. : 0.490 Min. : 0.75
## 1st Qu.: 2.000 1st Qu.:25.65
## Median : 2.590 Median :31.83
## Mean : 3.069 Mean :33.20
## 3rd Qu.: 3.625 3rd Qu.:38.06
## Max. :11.000 Max. :80.17
ggplot(income_age_yes, aes(x = age, y = income)) +
geom_bar(stat = "identity", fill = "skyblue", color = "skyblue") +
labs(x = "Age", y = "Income (in USD 10,000)", title = "Income by Age (For People with Cards)") +
theme_grey()
ggplot(income_age_no, aes(x = age, y = income)) +
geom_bar(stat = "identity", fill = "pink", color = "pink") +
labs(x = "Age", y = "Income (in USD 10,000)", title = "Income by Age (For People Without Cards)") +
theme_grey()
Now lets compare income by age in both of he groups: - with credit cards
biggest income have people around age of 42, while for non - owners this
age is a little bit smaller, because it’s around 35.
we can see bigger differences in income of different age groups
for card owners comparing to non-owners,
there is more age groups lacking in the non-owners, which is only
assuring us that there is bigger age diversity in the card owners
group,
again we can see some errors in data set, because here is group
of people around age 0 which has some income and it’s rather impossible
in real life, so based on this we can assume that those are
errors.
ggplot() +
geom_boxplot(data = credit_card_yes, aes(x = "Card Owner", y = share, fill = "Card Owner"), color = "turquoise2", alpha = 0.7) +
geom_boxplot(data = credit_card_no, aes(x = "Non-Owner", y = share, fill = "Non-Owner"), color = "purple", alpha = 0.7) +
labs(x = "Card Ownership", y = "Share", title = "Boxplot of Share by Card Ownership") +
scale_fill_manual(values = c("Card Owner" = "turquoise2", "Non-Owner" = "purple"),
name = "Card Ownership",
labels = c("Owner", "Non-Owner")) +
theme_minimal()
ggplot() +
geom_density(data = credit_card_yes, aes(x = share, fill = "Card Owner"), color = "turquoise2", alpha = 0.7) +
labs(x = "Share", y = "Density", title = "Density Plot of Share by Card Owners") +
scale_fill_manual(values = c("Card Owner" = "turquoise2"),
name = "Card Ownership",
labels = c("Owner")) +
theme_minimal()
share_yes <- credit_card_yes$share
share_no <- credit_card_no$share
summary_df_yes <- data.frame(
Statistic = c("Mean", "Median", "Standard Deviation", "Variance", "Coefficient of Variability (%)",
"Interquartile Range (IQR)", "Interquartile Deviation", "IQR Coefficient of Variability (%)",
"Minimum", "Maximum"),
Card_Owners = c(
mean(share_yes), median(share_yes), sd(share_yes), var(share_yes),
sd(share_yes) / mean(share_yes) * 100, IQR(share_yes), IQR(share_yes) / 2,
(IQR(share_yes) / 2) / median(share_yes) * 100, min(share_yes), max(share_yes)
)
)
summary_df_no <- data.frame(
Statistic = c("Mean", "Median", "Standard Deviation", "Variance", "Coefficient of Variability (%)",
"Interquartile Range (IQR)", "Interquartile Deviation", "IQR Coefficient of Variability (%)",
"Minimum", "Maximum"),
Non_Card_Owners = c(
mean(share_no), median(share_no), sd(share_no), var(share_no),
sd(share_no) / mean(share_no) * 100, IQR(share_no), IQR(share_no) / 2,
(IQR(share_no) / 2) / median(share_no) * 100, min(share_no), max(share_no)
)
)
summary_combined <- merge(summary_df_yes, summary_df_no, by = "Statistic", all = TRUE)
knitr::kable(summary_combined, format = "markdown", caption = "Summary Statistics for Age by Card Ownership") %>%
kable_styling(full_width = FALSE, bootstrap_options = "striped", position = "center")
Summary Statistics for Age by Card Ownership
Statistic
Card_Owners
Non_Card_Owners
Coefficient of Variability (%)
111.9670714
44.6937484
Interquartile Deviation
0.0436119
0.0001345
Interquartile Range (IQR)
0.0872238
0.0002689
IQR Coefficient of Variability (%)
72.4336454
29.0204022
Maximum
0.9063205
0.0024490
Mean
0.0884815
0.0004768
Median
0.0602094
0.0004633
Minimum
0.0001860
0.0001091
Standard Deviation
0.0990702
0.0002131
Variance
0.0098149
0.0000000
Those plots and table shows us share (Ratio of monthly credit card
expenditure to yearly income) of card owners and non-owners, and it
shows us something very interesting. We could assume that share for
non-owners should be 0, because how someone without credit card can have
a ratio of monthly credit card expenditure to yearly income, but from
the table it’s says that those are extremely small numbers, which we can
assume are just incorrect values.
So we will be only focusing on the group of card owners while
analising the data.
diversit of the share is quite big,
when we gropu people by their share we can say, that most
numerous gruop is of people having share around 0.12,
maximum share is 0.9 which is almost 1 so it would mean that
thoes people spend all their salary by credit card,
expenditures_age<-credit_card_yes[, c("expenditure", "age")]
summary(expenditures_age)
## expenditure age
## Min. : 0.00 Min. : 0.1667
## 1st Qu.: 66.52 1st Qu.:25.3333
## Median : 150.18 Median :31.0833
## Mean : 238.60 Mean :33.2160
## 3rd Qu.: 313.96 3rd Qu.:39.7083
## Max. :3099.51 Max. :83.5000
ggplot(expenditures_age, aes(x = age, y = expenditure)) +
geom_bar(stat = "identity", fill = "maroon", color = "maroon") +
labs(x = "Age", y = "Expenditure", title = "Expenditure by Age") +
theme_minimal()
Now just quick conclusion from this bar plot:
mostly young people are paying with credit card,
biggest expenditure have people around 35,
expedtiture of people after 50 is decreasing,
again we see incorrect data around age 0.
share_age<-credit_card_yes[, c("share", "age")]
summary(share_age)
## share age
## Min. :0.000186 Min. : 0.1667
## 1st Qu.:0.026635 1st Qu.:25.3333
## Median :0.060209 Median :31.0833
## Mean :0.088482 Mean :33.2160
## 3rd Qu.:0.113858 3rd Qu.:39.7083
## Max. :0.906320 Max. :83.5000
ggplot(share_age, aes(x = age, y = share)) +
geom_bar(stat = "identity", fill = "slateblue2" ,color = "slateblue2") +
labs(x = "Age", y = "Share", title = "Ratio of monthly credit card expenditure to yearly income by Age") +
theme_minimal()
And quick assumptions from this one:
biggest share have people around age of 25,
we can see that after age of 40 the share is way smaller
compering to younger people,
again we see some incorrect data values around age 0.
Summing up all the data analysis we have few most important
conclusions:
more people use credit card then not,
biggest group age of credit card users are young people, around
age 20-30,
people who have bigger income they tend to have credit
cards,
young people use credit card more frequently then people after
40s.
LS0tDQp0aXRsZTogJ0Rlc2NyaXB0aXZlIFN0YXRpc3RpY3MnDQpzdWJ0aXRsZTogJ1VuaXZhcmlhdGUgU3RhdGlzdGljcycNCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCmF1dGhvcjogIkp1bGlhIEtvemEsIFRvbWFzeiBCxYJhc3pjemFrLCBNaWNoYcWCIE1hbGlub3dza2kiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIHRoZW1lOiBjZXJ1bGVhbg0KICAgIGhpZ2hsaWdodDogdGV4dG1hdGUNCiAgICBmb250c2l6ZTogOHB0DQogICAgdG9jOiB5ZXMNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IG5vDQogICAgZGZfcHJpbnQ6IGRlZmF1bHQNCiAgICB0b2NfZGVwdGg6IDUNCmVkaXRvcl9vcHRpb25zOiANCiAgbWFya2Rvd246IA0KICAgIHdyYXA6IDcyDQotLS0NCg0KYGBge3Igc2V0dXAxLCBpbmNsdWRlPUZBTFNFfQ0KcmVxdWlyZWRfcGFja2FnZXMgPC0gYygicXdyYXBzMiIsICJhcnNlbmFsIiwgImUxMDcxIiwgImhhdmVuIiwgInBhcGVSIiwgDQogICAgICAgICAgICAgICAgICAgICAgICJkcGx5ciIsICJ0aWR5dmVyc2UiLCAia2FibGVFeHRyYSIsICJzdW1tYXJ5dG9vbHMiLCANCiAgICAgICAgICAgICAgICAgICAgICAgImNsYXNzSW50IiwgInBhc3RlY3MiLCAicmVwb3J0dG9vbHMiLCAiZGVzY3RhYmxlIiwgDQogICAgICAgICAgICAgICAgICAgICAgICJwc3ljaCIsICJmcmVxdWVuY3kiLCAiZ2dwdWJyIiwgImdnZm9yY2UiLCAiZ2dkaXN0IiwgDQogICAgICAgICAgICAgICAgICAgICAgICJnZ2hhbHZlcyIsICJndHN1bW1hcnkiLCAiQUVSIikNCmZvciAocGFja2FnZSBpbiByZXF1aXJlZF9wYWNrYWdlcykgew0KICBpZiAoIShwYWNrYWdlICVpbiUgaW5zdGFsbGVkLnBhY2thZ2VzKCkpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcyhwYWNrYWdlKQ0KICB9DQp9DQoNCiMgTG9hZCByZXF1aXJlZCBwYWNrYWdlcw0KbGlicmFyeShxd3JhcHMyKQ0KbGlicmFyeShhcnNlbmFsKQ0KbGlicmFyeShlMTA3MSkNCmxpYnJhcnkoaGF2ZW4pDQpsaWJyYXJ5KHBhcGVSKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShrYWJsZUV4dHJhKQ0KbGlicmFyeShzdW1tYXJ5dG9vbHMpDQpsaWJyYXJ5KGNsYXNzSW50KQ0KbGlicmFyeShwYXN0ZWNzKQ0KbGlicmFyeShyZXBvcnR0b29scykNCmxpYnJhcnkoZGVzY3RhYmxlKQ0KbGlicmFyeShwc3ljaCkNCmxpYnJhcnkoZnJlcXVlbmN5KQ0KbGlicmFyeShnZ3B1YnIpDQpsaWJyYXJ5KGdnZm9yY2UpDQpsaWJyYXJ5KGdnZGlzdCkNCmxpYnJhcnkoZ2doYWx2ZXMpDQpsaWJyYXJ5KGd0c3VtbWFyeSkNCmxpYnJhcnkoQUVSKQ0KZG93bmxvYWQuZmlsZSgiaHR0cHM6Ly9naXRodWIuY29tL2tmbGlzaWtvd3NraS9kcy9ibG9iL21hc3Rlci9kYXRhX2FwYXJ0bWVudHMuY3N2P3Jhdz10cnVlIiwgDQogICAgICAgICAgICAgIGRlc3RmaWxlID0ibWllc3prYW5pYS5jc3YiLG1vZGU9IndiIikNCmFwYXJ0bWVudHMgPC0gcmVhZC5jc3YoIm1pZXN6a2FuaWEuY3N2Iiwgc2VwPSI7IiwgZGVjPSIsIikNCmBgYA0KDQojIyBEYXRhDQoNCkluIG91ciBleGFtcGxlIHRoaXMgd2Vlaywgd2UgYXJlIGdvaW5nIHRvIHVzZSB0aGUgZmFrZSBkYXRhIC0gYWJvdXQgcmVhbA0KZXN0YXRlcyBpbiBXcm9jbGF3IC0gcHJpY2VzIGJ5IGRpc3RyaWN0cywgc2l6ZSBvZiBhcGFydG1lbnRzIGFuZCBtYW55DQptb3JlLg0KDQojIyMgUHJlcHJvY2Vzc2luZw0KDQpBcyB5b3UgY2FuIHNlZSwgbm90IGFsbCBmb3JtYXRzIG9mIG91ciB2YXJpYWJsZXMgYXJlIGFkYXB0ZWQuIFdlIG5lZWQgdG8NCnByZXBhcmUgYXBwcm9wcmlhdGUgZm9ybWF0cyBvZiBvdXIgdmFyaWFibGVzIGFjY29yZGluZyB0byB0aGVpcg0KbWVhc3VyZW1lbnQgc2NhbGUgYW5kIGZ1dHVyZSBhcHBsaWNhdGlvbi4NCg0KYGBge3Igd3JhbmdsaW5nLCBpbmNsdWRlPVRSVUV9DQphcGFydG1lbnRzJGRpc3RyaWN0PC1hcy5mYWN0b3IoYXBhcnRtZW50cyRkaXN0cmljdCkNCmFwYXJ0bWVudHMkYnVpbGRpbmdfdHlwZTwtYXMuZmFjdG9yKGFwYXJ0bWVudHMkYnVpbGRpbmdfdHlwZSkNCmFwYXJ0bWVudHMkcm9vbXM8LWZhY3RvcihhcGFydG1lbnRzJHJvb21zLG9yZGVyZWQ9VFJVRSkNCmF0dGFjaChhcGFydG1lbnRzKQ0KYXBhcnRtZW50cyRwcmljZV9QTE48LWFzLm51bWVyaWMoYXBhcnRtZW50cyRwcmljZV9QTE4pDQphcGFydG1lbnRzJHByaWNlX0VVUjwtYXMubnVtZXJpYyhhcGFydG1lbnRzJHByaWNlX0VVUikNCmBgYA0KDQojIyBGcmVxdWVuY3kgVGFibGVzDQoNCkluIHRoZSBmaXJzdCBzdGVwIG9mIG91ciBhbmFseXNpcywgd2Ugd2lsbCBncm91cCBvdXIgZGF0YSBpbnRvIGEgc2ltcGxlDQpmcmVxdWVuY3kgdGFibGUuDQoNCkZpcnN0LCBsZXQncyBsb29rIGF0IHRoZSBkaXN0cmlidXRpb24gb2YgaG91c2luZyBwcmljZXMgaW4gb3VyIHNhbXBsZQ0KYW5kIHZlcmlmeSB0YWJ1bGFyIHZhbGlkaXR5IHVzaW5nIHRoZSBUQUkgbWVhc3VyZToNCg0KYGBge3IgdGFibGUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0UsIHBhZ2VkLnByaW50PUZBTFNFfQ0KZXR5a2lldHk8LWMoIjM1MC00NTAga1BMTiIsIjQ1MC01NTAga1BMTiIsIjU1MC02NTAga1BMTiIsIjY1MC03NTAga1BMTiIsIjc1MC04NTAga1BMTiIsIjg1MC05NTAga1BMTiIsIjk1MC0xMDUwIGtQTE4iLCIxMDUwLTExNTAga1BMTiIsIjExNTAtMTI1MCBrUExOIiwiMTI1MC0xMzUwIGtQTE4iKQ0KbGltaXRzPC1jdXQoYXBhcnRtZW50cyRwcmljZV9QTE4sc2VxKDM1MDAwMCwxMzUwMDAwLGJ5PTEwMDAwMCksbGFiZWxzPWV0eWtpZXR5KQ0KdGFiZWxhMTwtZnJlcShsaW1pdHMsdHlwZT0iaHRtbCIpDQpgYGANCg0KT2ssIGl0IGxvb2tzIHF1aXRlIHVnbHksIHNvIGxldCdzIHdyYXAgaXQgdXAgdXNpbmcgdGhlICdrYWJsZScgcGFja2FnZToNCg0KYGBge3IgdGFpLCBlY2hvPUZBTFNFfQ0Ka2JsKHRhYmVsYTEsY2FwdGlvbiA9ICJBcGFydG1lbnRzIGluIFdyb2NsYXcgLSBwcmljZXMgaW4ga1BMTiIpICU+JQ0KICAgIGthYmxlX21hdGVyaWFsKGMoInN0cmlwZWQiLCAiaG92ZXIiKSkNCnRhYjE8LWNsYXNzSW50ZXJ2YWxzKGFwYXJ0bWVudHMkcHJpY2VfUExOLG49MTAsc3R5bGU9ImZpeGVkIixmaXhlZEJyZWFrcz1zZXEoMzUwMDAwLDEzNTAwMDAsYnk9MTAwMDAwKSkNCmplbmtzLnRlc3RzKHRhYjEpDQpgYGANCg0KQXMgd2UgY2FuIHNlZSAtIHRoZSBUQUkgaW5kZXggaXMgcXVpdGUgaGlnaC4gMC44NSBtZWFucyB0aGF0IHdlIGNhbg0KYWNjZXB0IHRoZSBwcm9wb3NlZCBjb25zdHJ1Y3Rpb24gb2YgdGhlIGZyZXF1ZW5jeSB0YWJsZS4NCg0KIyMgQmFzaWMgcGxvdHMNCg0KSW4gdGhpcyBzZWN0aW9uLCB3ZSBzaG91bGQgcmVwcmVzZW50IG91ciBkYXRhIHVzaW5nIGJhc2ljIChwcmUtaW5zdGFsbGVkDQppbiBSKSBncmFwaGljcy4gU2VsZWN0IHRoZSBtb3N0IGFwcHJvcHJpYXRlIGdyYXBocyBkZXBlbmRpbmcgb24gdGhlDQpzY2FsZSBvZiB0aGUgc2VsZWN0ZWQgdmFyaWFibGVzLiBFeHBsb3JlIHRoZSBoZXRlcm9nZW5laXR5IG9mIHRoZQ0KZGlzdHJpYnV0aW9uIGJ5IHByZXNlbnRpbmcgdGhlIGRhdGEgYnkgZ3JvdXAgKGUuZy4sIGJ5IG5laWdoYm9yaG9vZCwNCmJ1aWxkaW5nIHR5cGUsIGV0Yy4pLiBEb24ndCBmb3JnZXQgYWJvdXQgbWFpbiB0aXRsZXMsIGxhYmVscyBhbmQNCmxlZ2VuZHMuIFJlYWQgbW9yZSBhYm91dCBncmFwaGljYWwgcGFyYW1ldGVycw0KW2hlcmVdKGh0dHA6Ly93d3cuc3RoZGEuY29tL2VuZ2xpc2gvd2lraS9ncmFwaGljYWwtcGFyYW1ldGVycykuDQoNCmBgYHtyIGhpc3RvZ3JhbSwgZWNobz1GQUxTRX0NCmhpc3QocHJpY2VfUExOLCBicmVha3M9IkZEIiwgY29sPSJncmVlbiIsIHByb2JhYmlsaXR5ID0gVFJVRSwNCiAgICAgbWFpbj0iUHJpY2VzIGluIFBMTiAtIFdyb2NsYXciKQ0KbGluZXMoZGVuc2l0eShwcmljZV9QTE5bZGlzdHJpY3Q9PSJLcnp5a2kiXSksY29sPTIpDQpsaW5lcyhkZW5zaXR5KHByaWNlX1BMTltkaXN0cmljdD09IkJpc2t1cGluIl0pLGNvbD0zKQ0KbGluZXMoZGVuc2l0eShwcmljZV9QTE5bZGlzdHJpY3Q9PSJTcm9kbWllc2NpZSJdKSxjb2w9NCkNCmxlZ2VuZCgidG9wcmlnaHQiLCBsZWdlbmQ9YygiS3J6eWtpIiwgIkJpc2t1cGluIiwgIlNyb2RtaWVzY2llIiksDQogICAgICAgY29sPWMoMiwzLDQpLCBsdHk9MToyLCBob3Jpej1GQUxTRSwgYm94Lmx0eT0wLCBjZXg9MC44KQ0KDQpgYGANCg0KTm90ZSB0aGF0IHRoZSBgZWNobyA9IEZBTFNFYCBwYXJhbWV0ZXIgaGFzIGJlZW4gYWRkZWQgdG8gdGhlIGNvZGUNCnNuaXBwZXQgdG8gcHJldmVudCBwcmludGluZyB0aGUgUiBjb2RlIHRoYXQgZ2VuZXJhdGVkIHRoZSBncmFwaC4NCg0KYGBge3IgYm94cGxvdCwgZWNobz1GQUxTRX0NCmJveHBsb3QocHJpY2VfUExOfmRpc3RyaWN0KQ0KYGBgDQoNCiMjIGdncGxvdDIgcGxvdHMNCg0KTm93LCBsZXQncyB1c2UgdGhlICoqKmdncGxvdDIqKiogYW5kICoqKmdncHVicioqKiBsaWJyYXJpZXMgdG8gcGxvdC4NCg0KYGBge3IgaGlzdG9ncmFtMiwgZWNobz1GQUxTRX0NCiMgRGVuc2l0eSBwbG90IG9mICJwcmljZV9QTE4iDQojOjo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6OjoNCmRlbnNpdHkucCA8LSBnZ2RlbnNpdHkoYXBhcnRtZW50cywgeCA9ICJwcmljZV9QTE4iLCANCiAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJkaXN0cmljdCIsIHBhbGV0dGUgPSAiamNvIikrDQogIHN0YXRfb3ZlcmxheV9ub3JtYWxfZGVuc2l0eShjb2xvciA9ICJyZWQiLCBsaW5ldHlwZSA9ICJkYXNoZWQiKQ0KDQojIERyYXcgdGhlIHN1bW1hcnkgdGFibGUgb2YgcHJpY2VfUExODQojOjo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6OjoNCiMgQ29tcHV0ZSBkZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIGJ5IGdyb3Vwcw0Kc3RhYmxlIDwtIGRlc2Nfc3RhdGJ5KGFwYXJ0bWVudHMsIG1lYXN1cmUudmFyID0gInByaWNlX1BMTiIsDQogICAgICAgICAgICAgICAgICAgICAgZ3JwcyA9ICJkaXN0cmljdCIpDQpzdGFibGUgPC0gc3RhYmxlWywgYygiZGlzdHJpY3QiLCAibGVuZ3RoIiwgIm1lYW4iLCAic2QiKV0NCiMgU3VtbWFyeSB0YWJsZSBwbG90LCBtZWRpdW0gb3JhbmdlIHRoZW1lDQpzdGFibGUucCA8LSBnZ3RleHR0YWJsZShzdGFibGUsIHJvd3MgPSBOVUxMLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lID0gdHRoZW1lKCJtT3JhbmdlIikpDQojIERyYXcgdGV4dA0KIzo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6DQp0ZXh0IDwtIHBhc3RlKCJQcmljZSBwZXIgYXBhcnRtZW50IGJ5IDMgZGlzdHJpY3RzIC0gV3JvY2xhdy4iLA0KICAgICAgICAgICAgICAiUmFuZG9tIHNhbXBsZSBvZiAyMDAgYXBhcnRtZW50cy4iLA0KICAgICAgICAgICAgICAgc2VwID0gIiAiKQ0KdGV4dC5wIDwtIGdncGFyYWdyYXBoKHRleHQgPSB0ZXh0LCBmYWNlID0gIml0YWxpYyIsIHNpemUgPSAxMSwgY29sb3IgPSAiYmxhY2siKQ0KIyBBcnJhbmdlIHRoZSBwbG90cyBvbiB0aGUgc2FtZSBwYWdlDQpnZ2FycmFuZ2UoZGVuc2l0eS5wLCBzdGFibGUucCwgdGV4dC5wLCANCiAgICAgICAgICBuY29sID0gMSwgbnJvdyA9IDMsDQogICAgICAgICAgaGVpZ2h0cyA9IGMoMSwgMC41LCAwLjMpKQ0KYGBgDQoNCkdncGxvdDIgYWxsb3dzIHlvdSB0byBzaG93IHRoZSBhdmVyYWdlIHZhbHVlIGZvciBlYWNoIGdyb3VwIHVzaW5nIHRoZQ0KKipzdGF0X3N1bW1hcnkoKSoqIGZ1bmN0aW9uLiBZb3Ugbm8gbG9uZ2VyIG5lZWQgdG8gY2FsY3VsYXRlIGF2ZXJhZ2UNCnZhbHVlcyBiZWZvcmUgY3JlYXRpbmcgYSBncmFwaCENCg0KYGBge3IgYm94cGxvdDIsIGVjaG89RkFMU0V9DQpnZ3Bsb3QoYXBhcnRtZW50cywgYWVzKHg9ZGlzdHJpY3QsIHk9cHJpY2VfUExOKSkgKw0KICAgIGdlb21fYm94cGxvdChhbHBoYT0wLjcpICsNCiAgICBzdGF0X3N1bW1hcnkoZnVuPSJtZWFuIiwgZ2VvbT0icG9pbnQiLCBzaGFwZT0yMCwgc2l6ZT01LCBjb2xvcj0icmVkIiwgZmlsbD0icmVkIikgKw0KIGdlb21faml0dGVyKCkgKw0KICAgIGZhY2V0X2dyaWQofmJ1aWxkaW5nX3R5cGUpICsNCiAgICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlPSJTZXQxIikNCg0KYGBgDQoNCiMjIyBSYWluQ2xvdWQgUGxvdA0KDQpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KYXBhcnRtZW50cyAlPiUgDQogIGZpbHRlcihyb29tcyAlaW4lIGMoMSwgMiwgMywgNCkpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gZmFjdG9yKHJvb21zKSwgeSA9IHByaWNlX1BMTiwgZmlsbCA9IGZhY3Rvcihyb29tcykpKSArDQogIA0KICAjIGFkZCBoYWxmLXZpb2xpbiBmcm9tIHtnZ2Rpc3R9IHBhY2thZ2UNCiAgc3RhdF9oYWxmZXllKA0KICAgICMgYWRqdXN0IGJhbmR3aWR0aA0KICAgIGFkanVzdCA9IDAuNSwNCiAgICAjIG1vdmUgdG8gdGhlIHJpZ2h0DQogICAganVzdGlmaWNhdGlvbiA9IC0wLjIsDQogICAgIyByZW1vdmUgdGhlIHNsdWIgaW50ZXJ2YWwNCiAgICAud2lkdGggPSAwLA0KICAgIHBvaW50X2NvbG91ciA9IE5BDQogICkgKw0KICBnZW9tX2JveHBsb3QoDQogICAgd2lkdGggPSAwLjEyLA0KICAgICMgcmVtb3Zpbmcgb3V0bGllcnMNCiAgICBvdXRsaWVyLmNvbG9yID0gTkEsDQogICAgYWxwaGEgPSAwLjUNCiAgKSArDQogIHN0YXRfZG90cygNCiAgICAjIHBsb3Rpbmcgb24gbGVmdCBzaWRlDQogICAgc2lkZSA9ICJsZWZ0IiwNCiAgICAjIGFkanVzdGluZyBwb3NpdGlvbg0KICAgIGp1c3RpZmljYXRpb24gPSAxLjEsDQogICAgIyBhZGp1c3QgZ3JvdXBpbmcgKGJpbm5pbmcpIG9mIG9ic2VydmF0aW9ucw0KICAgIGJpbndpZHRoID0gMC4yNQ0KICApICsNCiMgVGhlbWVzIGFuZCBMYWJlbHMNCiAgbGFicygNCiAgICB0aXRsZSA9ICJSYWluQ2xvdWQgUGxvdCIsDQogICAgeCA9ICJOby4gb2Ygcm9vbXMiLA0KICAgIHkgPSAiUHJpY2VzIGluIFBMTiIsDQogICAgZmlsbCA9ICJyb29tcyINCiAgKSArDQogIGNvb3JkX2ZsaXAoKQ0KYGBgDQoNCiMjIyBGYWNldGluZw0KDQpGYWNldGluZyBnZW5lcmF0ZXMgc21hbGwgbXVsdGlwbGVzLCBlYWNoIHNob3dpbmcgYSBkaWZmZXJlbnQgc3Vic2V0IG9mDQp0aGUgZGF0YS4gVGhleSBhcmUgYSBwb3dlcmZ1bCB0b29sIGZvciBleHBsb3JhdG9yeSBkYXRhIGFuYWx5c2lzOiB5b3UNCmNhbiBxdWlja2x5IGNvbXBhcmUgcGF0dGVybnMgaW4gZGlmZmVyZW50IHBhcnRzIG9mIHRoZSBkYXRhIGFuZCBzZWUgaWYNCnRoZXkgYXJlIHRoZSBzYW1lIG9yIGRpZmZlcmVudC4gUmVhZCBtb3JlDQpbaGVyZV0oaHR0cHM6Ly9nZ3Bsb3QyLWJvb2sub3JnL2ZhY2V0Lmh0bWwpLg0KDQpgYGB7ciBmYWNldDEsIGVjaG89RkFMU0V9DQpwbG90MSA8LSBnZ3Bsb3QoYXBhcnRtZW50cywgYWVzKHByaWNlX1BMTiwgcm9vbXMpKSArIA0KICBnZW9tX2FibGluZSgpICsNCiAgZ2VvbV9qaXR0ZXIod2lkdGggPSAwLjEsIGhlaWdodCA9IDAuMSkgDQpwbG90MSArIGZhY2V0X3dyYXAofmRpc3RyaWN0KQ0KYGBgDQoNCiMjIFVuaXZhcmlhdGUgU3RhdGlzdGljcw0KDQpCZWZvcmUgYXV0b21hdGljYWxseSByZXBvcnRpbmcgdGhlIGZ1bGwgc3VtbWFyeSB0YWJsZSBvZiBkZXNjcmlwdGl2ZQ0Kc3RhdGlzdGljcywgdGhpcyB0aW1lIHlvdXIgZ29hbCBpcyB0byBtZWFzdXJlIHRoZSBjZW50cmFsIHRlbmRlbmN5IG9mDQp0aGUgcHJpY2UgZGlzdHJpYnV0aW9uLiBDb21wYXJlIHRoZSBtZWFuLCBtZWRpYW4sIGFuZCBtb2RlIGFsb25nIHdpdGgNCnBvc2l0aW9uYWwgbWVhc3VyZXMgLSBxdWFudGlsZXMgLSBieSBkaXN0cmljdCBhbmQgYnVpbGRpbmcgdHlwZSBvcg0KbnVtYmVyIG9mIHJvb21zIGluIHRoZSBhcGFydG1lbnQuDQoNCmBgYHtyfQ0KICAgIG1lYW4ocHJpY2VfUExOKQ0KICAgIG1lZGlhbihwcmljZV9QTE4pDQogICAgc2QocHJpY2VfUExOKSAjc3RhbmRhcmQgZGV2aWF0aW9uDQogICAgdmFyKHByaWNlX1BMTikgI3ZhcmlhbmNlDQogICAgY29lZmZfdmFyPC1zZChwcmljZV9QTE4pL21lYW4ocHJpY2VfUExOKSAjY29lZmZpY2llbnQgb2YgdmFyaWFiaWxpdHkgJQ0KICAgIGNvZWZmX3Zhcg0KICAgIElRUihwcmljZV9QTE4pIyBkaWZmZXJlbmNlIGJldHdlZW4gcXVhcnRpbGVzID1RMy1RMSANCiAgICBzeDwtSVFSKHByaWNlX1BMTikvMiAgI2ludGVycXVhcnRpbGUgZGV2aWF0aW9uDQogICAgY29lZmZfdmFyeDwtc3gvbWVkaWFuKHByaWNlX1BMTikgI0lRUiBjb2VmZmljaWVudCBvZiB2YXJpYWJpbGl0eSAlDQogICAgY29lZmZfdmFyeA0KICAgIG1pbihwcmljZV9QTE4pDQogICAgbWF4KHByaWNlX1BMTikNCiAgICBxdWFudGlsZShwcmljZV9QTE4scHJvYnM9YygwLDAuMSwwLjI1LDAuNSwwLjc1LDAuOTUsMSksbmEucm09VFJVRSkNCmBgYA0KDQpPaywgd2UgaGF2ZSBjYWxjdWxhdGVkIGFsbCBvZiB0aGUgYmFzaWMgc3VtbWFyeSBzdGF0aXN0aWNzIGFib3ZlLiBMZXQncw0Kd3JhcCB0aGVtIHVwIHRvZ2V0aGVyIG5vdy4NCg0KYGBge3Iga2FibGVfcmVwb3J0LCBlY2hvPUZBTFNFfQ0KYXBhcnRtZW50c19saXN0IDwtIHNwbGl0KGFwYXJ0bWVudHMkcHJpY2VfUExOLCBhcGFydG1lbnRzJHJvb21zKQ0KaW5saW5lX3Bsb3QgPC0gZGF0YS5mcmFtZShyb29tcyA9IGMoMSwgMiwgMywgNCksIGJveHBsb3QgPSAiIiwgaGlzdG9ncmFtID0gIiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmUxID0gIiIsIGxpbmUyID0gIiIsIHBvaW50czEgPSAiIikNCmlubGluZV9wbG90ICU+JQ0KICBrYmwoYm9va3RhYnMgPSBUUlVFKSAlPiUNCiAga2FibGVfcGFwZXIoZnVsbF93aWR0aCA9IEZBTFNFKSAlPiUNCiAgY29sdW1uX3NwZWMoMiwgaW1hZ2UgPSBzcGVjX2JveHBsb3QoYXBhcnRtZW50c19saXN0KSkgJT4lDQogIGNvbHVtbl9zcGVjKDMsIGltYWdlID0gc3BlY19oaXN0KGFwYXJ0bWVudHNfbGlzdCkpICU+JQ0KICBjb2x1bW5fc3BlYyg0LCBpbWFnZSA9IHNwZWNfcGxvdChhcGFydG1lbnRzX2xpc3QsIHNhbWVfbGltID0gVFJVRSkpICU+JQ0KICBjb2x1bW5fc3BlYyg1LCBpbWFnZSA9IHNwZWNfcGxvdChhcGFydG1lbnRzX2xpc3QsIHNhbWVfbGltID0gRkFMU0UpKSAlPiUNCiAgY29sdW1uX3NwZWMoNiwgaW1hZ2UgPSBzcGVjX3Bsb3QoYXBhcnRtZW50c19saXN0LCB0eXBlID0gInAiKSkNCg0KYGBgDQoNCiMjIyBTdW1tYXJ5IHRhYmxlcw0KDQpPaywgbm93IHdlIHdpbGwgZmluYWxseSBzdW1tYXJpemUgdGhlIGJhc2ljIG1lYXN1cmVzIG9mIGNlbnRyYWwgdGVuZGVuY3kNCmZvciBwcmljZXMgYnkgZGlzdHJpY3QvYnVpbGRpbmcgdHlwZSB1c2luZyB0aGUgJyoqKmthYmxlKioqJyBwYWNrYWdlLg0KRmVlbCBmcmVlIHRvIGN1c3RvbWl6ZSB5b3VyIGZpbmFsIHJlcG9ydC4gU2VlIHNvbWUgaGludHMNCltoZXJlXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvcXdyYXBzMi92aWduZXR0ZXMvc3VtbWFyeS1zdGF0aXN0aWNzLmh0bWwpLg0KDQpgYGB7ciBrYWJsZV9yZXBvcnQyLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KcmFwb3J0IDwtIGxpc3QoIlByaWNlIGluIFBMTiIgPQ0KICAgICAgICAgICAgICAgIGxpc3QoIk1pbiIgPSB+IG1pbihwcmljZV9QTE4pLA0KICAgICAgICAgICAgICAgICAgICAgIk1heCIgPSB+IG1heChwcmljZV9QTE4pLA0KICAgICAgICAgICAgICAgICAgICAgIlExIiA9IH4gcXVhbnRpbGUocHJpY2VfUExOLCAwLjI1KSwNCiAgICAgICAgICAgICAgICAgICAgICJNZWRpYW4iID0gfiByb3VuZChtZWRpYW4ocHJpY2VfUExOKSwgMiksDQogICAgICAgICAgICAgICAgICAgICAiUTMiID0gfiBxdWFudGlsZShwcmljZV9QTE4sIDAuNzUpLA0KICAgICAgICAgICAgICAgICAgICAgIk1lYW4iID0gfiByb3VuZChtZWFuKHByaWNlX1BMTiksIDIpLA0KICAgICAgICAgICAgICAgICAgICAgIlNkIiA9IH4gcm91bmQoc2QocHJpY2VfUExOKSwgMiksDQogICAgICAgICAgICAgICAgICAgICAiSVFSIiA9IH4gcm91bmQoSVFSKHByaWNlX1BMTiksIDIpLA0KICAgICAgICAgICAgICAgICAgICAgIlN4IiA9IH4gcm91bmQoSVFSKHByaWNlX1BMTikgLyAyLCAyKSwNCiAgICAgICAgICAgICAgICAgICAgICJWYXIgJSIgPSB+IHJvdW5kKChzZChwcmljZV9QTE4pIC8gbWVhbihwcmljZV9QTE4pKSwgMiksDQogICAgICAgICAgICAgICAgICAgICAiSVFSIFZhciAlIiA9IH4gcm91bmQoKElRUihwcmljZV9QTE4pIC8gbWVkaWFuKHByaWNlX1BMTikpLCAyKSwNCiAgICAgICAgICAgICAgICAgICAgICJTa2V3bmVzcyIgPSB+IHJvdW5kKHNrZXduZXNzKHByaWNlX1BMTiksIDIpLA0KICAgICAgICAgICAgICAgICAgICAgIkt1cnRvc2lzIiA9IH4gcm91bmQoa3VydG9zaXMocHJpY2VfUExOKSwgMikNCiAgICAgICAgICAgICAgICApKQ0KDQojIEdlbmVyYXRlIHRoZSBzdW1tYXJ5IHRhYmxlDQp0YWJlbGEgPC0gc3VtbWFyeV90YWJsZShhcGFydG1lbnRzLCBzdW1tYXJpZXMgPSByYXBvcnQsIGJ5ID0gYygicm9vbXMiKSkNCg0KIyBJbnNwZWN0IHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIHRhYmVsYSBvYmplY3QNCnN0cih0YWJlbGEpDQoNCiMgRGVmaW5lIGNvbHVtbiBuYW1lcyBiYXNlZCBvbiB0aGUgbnVtYmVyIG9mIHJvb21zDQpjb2xfbmFtZXMgPC0gcGFzdGUodW5pcXVlKGFwYXJ0bWVudHMkcm9vbXMpLCAicm9vbXMiKQ0KDQojIFJlbmRlciB0aGUgdGFibGUgdXNpbmcga2JsDQoja2JsKHRhYmVsYSwgY2FwdGlvbiA9ICJUYWJsZSAxLiBBcGFydG1lbnRzIGluIFdyb2NsYXcgLSBwcmljZXMgaW4gUExOIGJ5IG51bWJlciBvZiByb29tcy4iLA0KICMgICBjb2wubmFtZXMgPSBjb2xfbmFtZXMpICU+JQ0KICAja2FibGVfY2xhc3NpYyhmdWxsX3dpZHRoID0gRkFMU0UsIGh0bWxfZm9udCA9ICJDYW1icmlhIikgJT4lDQogICNrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIpKQ0KYGBgDQoNCiMjIyBndHN1bW1hcnkNCg0KV2UgY2FuIGNhbGN1bGF0ZSBlYXNpbHkgZGVzY3JpcHRpdmUgc3RhdGlzdGljcyBhbHNvIHVzaW5nIGd0c3VtbWFyeQ0KcGFja2FnZToNCg0KYGBge3J9DQphcGFydG1lbnRzICU+JQ0KICBzZWxlY3QocHJpY2VfUExOLHJvb21zKSAlPiUNCiAgdGJsX3N1bW1hcnkobGFiZWw9IHByaWNlX1BMTiB+ICJQcmljZSIsZGlnaXRzPWMocHJpY2VfUExOKX4yLGJ5PXJvb21zLHR5cGUgPSBhbGxfY29udGludW91cygpIH4gImNvbnRpbnVvdXMyIiwgc3RhdGlzdGljID0gYWxsX2NvbnRpbnVvdXMoKSB+IGMoIntOX25vbm1pc3N9IiwgInttZWRpYW59ICh7cDI1fSwge3A3NX0pIiwgInttaW59LCB7bWF4fSIpLG1pc3NpbmcgPSAibm8iKQ0KYGBgDQoNCiMjIyBkZlN1bW1hcnkNCg0KZGZTdW1tYXJ5KCkgY3JlYXRlcyBhIHN1bW1hcnkgdGFibGUgd2l0aCBzdGF0aXN0aWNzLCBmcmVxdWVuY2llcyBhbmQNCmdyYXBocyBmb3IgYWxsIHZhcmlhYmxlcyBpbiBhIGRhdGEgZnJhbWUuIFRoZSBpbmZvcm1hdGlvbiBkaXNwbGF5ZWQgaXMNCnR5cGUtc3BlY2lmaWMgKGNoYXJhY3RlciwgZmFjdG9yLCBudW1lcmljLCBkYXRlKSBhbmQgYWxzbyB2YXJpZXMNCmFjY29yZGluZyB0byB0aGUgbnVtYmVyIG9mIGRpc3RpbmN0IHZhbHVlcy4NCg0KV2hlbiB1c2luZyBkZlN1bW1hcnkoKSBpbiBSIE1hcmtkb3duIGRvY3VtZW50cywgaXQgaXMgZ2VuZXJhbGx5IGEgZ29vZA0KaWRlYSB0byBleGNsdWRlIGEgY29sdW1uIG9yIHR3byB0byBhdm9pZCBtYXJnaW4gb3ZlcmZsb3cuIFNpbmNlIHRoZQ0KVmFsaWQgYW5kIE1pc3NpbmcgY29sdW1ucyBhcmUgcmVkdW5kYW50LCB3ZSBjYW4gZHJvcCBlaXRoZXIgb25lIG9mIHRoZW0uDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9ImFzaXMifQ0KZGZTdW1tYXJ5KGFwYXJ0bWVudHMsDQogICAgICAgICAgcGxhaW4uYXNjaWkgID0gRkFMU0UsIA0KICAgICAgICAgIHN0eWxlICAgICAgICA9ICJncmlkIiwgDQogICAgICAgICAgZ3JhcGgubWFnbmlmID0gMC43NSwgDQogICAgICAgICAgdmFsaWQuY29sICAgID0gRkFMU0UsDQogICAgICAgICAgdG1wLmltZy5kaXIgID0gIi90bXAiKQ0KYGBgDQoNClRvIHByb2R1Y2Ugb3B0aW1hbCByZXN1bHRzLCBzdW1tYXJ5dG9vbHMgaGFzIGl0cyBvd24gdmVyc2lvbiBvZiB0aGUgYmFzZQ0KYnkoKSBmdW5jdGlvbi4gSXQncyBjYWxsZWQgc3RieSgpLCBhbmQgd2UgdXNlIGl0IGV4YWN0bHkgYXMgd2Ugd291bGQNCmJ5KCk6DQoNCmBgYHtyIHJlc3VsdHM9ImFzaXMiLCB3YXJuaW5nPUZBTFNFfQ0KKHN0YXRzX2J5X3Jvb21zIDwtIHN0YnkoZGF0YSAgICAgID0gYXBhcnRtZW50cywgSU5ESUNFUyAgID0gYXBhcnRtZW50cyRyb29tcywgRlVOICAgICAgID0gZGVzY3IsIHN0YXRzICAgICA9ICJjb21tb24iLCB0cmFuc3Bvc2UgPSBUUlVFKSkNCmBgYA0KDQojIyMgVGlkeSBUYWJsZXMNCg0KV2hlbiBnZW5lcmF0aW5nIGZyZXEoKSBvciBkZXNjcigpIHRhYmxlcywgaXQgaXMgcG9zc2libGUgdG8gdHVybiB0aGUNCnJlc3VsdHMgaW50byAidGlkeSIgdGFibGVzIHdpdGggdGhlIHVzZSBvZiB0aGUgdGIoKSBmdW5jdGlvbiAodGhpbmsgb2YNCnRiIGFzIGEgZGltaW51dGl2ZSBmb3IgdGliYmxlKS4gRm9yIGV4YW1wbGU6DQoNCmBgYHtyfQ0KYXBhcnRtZW50cyAlPiUNCiAgZGVzY3Ioc3RhdHMgPSAiY29tbW9uIikgJT4lDQogIHRiKCkNCmBgYA0KDQpIZXJlIGFyZSBzb21lIGV4YW1wbGVzIHNob3dpbmcgaG93IGxpc3RzIGNyZWF0ZWQgdXNpbmcgc3RieSgpIG9yDQpncm91cF9ieSgpIGNhbiBiZSB0cmFuc2Zvcm1lZCBpbnRvIHRpZHkgdGliYmxlcy4NCg0KYGBge3J9DQpncm91cGVkX2Rlc2NyIDwtIHN0YnkoZGF0YSAgICA9IGFwYXJ0bWVudHMsSU5ESUNFUyA9IGFwYXJ0bWVudHMkcm9vbXMsIEZVTiAgICAgPSBkZXNjciwgc3RhdHMgICA9ICJjb21tb24iKQ0KDQpncm91cGVkX2Rlc2NyICU+JSB0YigpDQpgYGANCg0KIyMjIEEgQnJpZGdlIHRvIE90aGVyIFBhY2thZ2VzDQoNCmBgYHtyfQ0Kc3RieShkYXRhICAgID0gYXBhcnRtZW50cywgDQogICAgIElORElDRVMgPSBhcGFydG1lbnRzJHJvb21zLCANCiAgICAgRlVOICAgICA9IGRlc2NyLCANCiAgICAgc3RhdHMgICA9ICJmaXZlbnVtIikgJT4lDQogIHRiKG9yZGVyID0gMykgJT4lDQogIGthYmxlKGZvcm1hdCA9ICJodG1sIiwgZGlnaXRzID0gMikgJT4lDQogIGNvbGxhcHNlX3Jvd3MoY29sdW1ucyA9IDEsIHZhbGlnbiA9ICJ0b3AiKQ0KYGBgDQoNCiMjIFlvdXIgdHVybiENCg0KWW91ciB0YXNrIHRoaXMgd2VlayBpcyB0bzogcHJlcGFyZSB5b3VyIG93biBkZXNjcmlwdGl2ZSBhbmFseXNpcyBmb3IgdGhlDQoiQ3JlZGl0Q2FyZCIgZGF0YXNldCAoQUVSIHBhY2thZ2UpLiBJdCBpcyBhIGNyb3NzLXNlY3Rpb25hbCBkYXRhZnJhbWUgb24NCnRoZSBjcmVkaXQgaGlzdG9yeSBmb3IgYSBzYW1wbGUgb2YgYXBwbGljYW50cyBmb3IgYSB0eXBlIG9mIGNyZWRpdCBjYXJkLg0KDQpgYGB7ciBpbmNsdWRlPUZBTFNFfQ0KZGF0YShDcmVkaXRDYXJkKQ0KIz9DcmVkaXRDYXJkICByZWFkIGRlc2NyaXB0aW9uIGZpcnN0DQpgYGANCg0KQXJlIHRoZSB5ZWFybHkgaW5jb21lcyAoaW4gVVNEIDEwLDAwMCksIGNyZWRpdCBjYXJkIGV4cGVuZGl0dXJlcywgYWdlLA0KcmF0aW8gb2YgbW9udGhseSBjcmVkaXQgY2FyZCBleHBlbmRpdHVyZSB0byB5ZWFybHkgaW5jb21lIC0NCnNpZ25pZmljYW50bHkgZGlmZmVyZW50IGZvciBhcHBsaWNhbnRzIGZvciBjdXN0b21lcnMgd2l0aCBkaWZmZXJlbnQNCmNyZWRpdCByaXNrICgiY2FyZCIgdmFyaWFibGUgLSBmYWN0b3IpPw0KDQpQcmVwYXJlIGEgcHJvZmVzc2lvbmFsIGRhdGEgdmlzdWFsaXphdGlvbnMsIGRlc2NyaXB0aXZlIHN0YXRpc3RpY3MnDQp0YWJsZXMgYW5kIGludGVycHJldCB0aGVtLg0KDQpgYGB7ciBteV9zdW1tYXJ5X3RhYmxlfQ0KIyB5b3VyIGNvZGUgaGVyZQ0KQ3JlZGl0Q2FyZCRhZ2U8LWFzLm51bWVyaWMoQ3JlZGl0Q2FyZCRhZ2UpDQpDcmVkaXRDYXJkJHJlcG9ydHM8LWFzLm51bWVyaWMoQ3JlZGl0Q2FyZCRyZXBvcnRzKQ0KQ3JlZGl0Q2FyZCRpbmNvbWU8LWFzLm51bWVyaWMoQ3JlZGl0Q2FyZCRpbmNvbWUpDQpDcmVkaXRDYXJkJHNoYXJlPC1hcy5udW1lcmljKENyZWRpdENhcmQkc2hhcmUpDQpDcmVkaXRDYXJkJGV4cGVuZGl0dXJlPC1hcy5udW1lcmljKENyZWRpdENhcmQkZXhwZW5kaXR1cmUpDQpDcmVkaXRDYXJkJGNhcmQ8LWFzLmZhY3RvcihDcmVkaXRDYXJkJGNhcmQpDQpgYGANCg0KYGBge3J9DQpjcmVkaXRfY2FyZF95ZXMgPC0gc3Vic2V0KENyZWRpdENhcmQsIGNhcmQgPT0gJ3llcycpDQpjcmVkaXRfY2FyZF9ubyA8LSBzdWJzZXQoQ3JlZGl0Q2FyZCwgY2FyZCA9PSAnbm8nKQ0KYGBgDQoNCmBgYHtyfQ0KY3JlZGl0X2NhcmRfeWVzIDwtIHN1YnNldChDcmVkaXRDYXJkLCBjYXJkID09ICd5ZXMnKQ0KY3JlZGl0X2NhcmRfbm8gPC0gc3Vic2V0KENyZWRpdENhcmQsIGNhcmQgPT0gJ25vJykNCg0KYWdlX3llcyA8LSBjcmVkaXRfY2FyZF95ZXMkYWdlDQphZ2Vfbm8gPC0gY3JlZGl0X2NhcmRfbm8kYWdlDQoNCnN1bW1hcnkoYWdlX3llcykNCnN1bW1hcnkoYWdlX25vKQ0KDQpnZ3Bsb3QoKSArDQogIGdlb21fZGVuc2l0eShkYXRhID0gY3JlZGl0X2NhcmRfeWVzLCBhZXMoeCA9IGFnZSwgZmlsbCA9ICJDYXJkIE93bmVyIiksIGNvbG9yID0gImNvcmFsNCIsIGFscGhhID0gMC43KSArDQogIGdlb21fZGVuc2l0eShkYXRhID0gY3JlZGl0X2NhcmRfbm8sIGFlcyh4ID0gYWdlLCBmaWxsID0gIk5vbi1Pd25lciIpLCBjb2xvciA9ICJwaW5rIiwgYWxwaGEgPSAwLjcpICsNCiAgbGFicyh4ID0gIkFnZSIsIHkgPSAiRGVuc2l0eSIsIHRpdGxlID0gIkRlbnNpdHkgUGxvdCBvZiBBZ2UgYnkgQ2FyZCBPd25lcnNoaXAiKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIkNhcmQgT3duZXIiID0gImNvcmFsNCIsICJOb24tT3duZXIiID0gInBpbmsiKSwNCiAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJDYXJkIE93bmVyc2hpcCIsDQogICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIk93bmVyIiwgIk5vbi1Pd25lciIpKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KCkgKw0KICBnZW9tX2JveHBsb3QoZGF0YSA9IGNyZWRpdF9jYXJkX3llcywgYWVzKHggPSAiQ2FyZCBPd25lciIsIHkgPSBhZ2UsIGZpbGwgPSAiQ2FyZCBPd25lciIpLCBjb2xvciA9ICJjb3JhbDQiLCBhbHBoYSA9IDAuNykgKw0KICBnZW9tX2JveHBsb3QoZGF0YSA9IGNyZWRpdF9jYXJkX25vLCBhZXMoeCA9ICJOb24tT3duZXIiLCB5ID0gYWdlLCBmaWxsID0gIk5vbi1Pd25lciIpLCBjb2xvciA9ICJwaW5rIiwgYWxwaGEgPSAwLjcpICsNCiAgbGFicyh4ID0gIkNhcmQgT3duZXJzaGlwIiwgeSA9ICJBZ2UiLCB0aXRsZSA9ICJCb3hwbG90IG9mIEFnZSBieSBDYXJkIE93bmVyc2hpcCIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiQ2FyZCBPd25lciIgPSAiY29yYWw0IiwgIk5vbi1Pd25lciIgPSAicGluayIpLA0KICAgICAgICAgICAgICAgICAgICBuYW1lID0gIkNhcmQgT3duZXJzaGlwIiwNCiAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiT3duZXIiLCAiTm9uLU93bmVyIikpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KDQpgYGB7cn0NCnN1bW1hcnlfZGZfeWVzIDwtIGRhdGEuZnJhbWUoDQogIFN0YXRpc3RpYyA9IGMoIk1lYW4iLCAiTWVkaWFuIiwgIlN0YW5kYXJkIERldmlhdGlvbiIsICJWYXJpYW5jZSIsICJDb2VmZmljaWVudCBvZiBWYXJpYWJpbGl0eSAoJSkiLCANCiAgICAgICAgICAgICAgICAiSW50ZXJxdWFydGlsZSBSYW5nZSAoSVFSKSIsICJJbnRlcnF1YXJ0aWxlIERldmlhdGlvbiIsICJJUVIgQ29lZmZpY2llbnQgb2YgVmFyaWFiaWxpdHkgKCUpIiwNCiAgICAgICAgICAgICAgICAiTWluaW11bSIsICJNYXhpbXVtIiksDQogIENhcmRfT3duZXJzID0gYygNCiAgICBtZWFuKGFnZV95ZXMpLCBtZWRpYW4oYWdlX3llcyksIHNkKGFnZV95ZXMpLCB2YXIoYWdlX3llcyksDQogICAgc2QoYWdlX3llcykgLyBtZWFuKGFnZV95ZXMpICogMTAwLCBJUVIoYWdlX3llcyksIElRUihhZ2VfeWVzKSAvIDIsDQogICAgKElRUihhZ2VfeWVzKSAvIDIpIC8gbWVkaWFuKGFnZV95ZXMpICogMTAwLCBtaW4oYWdlX3llcyksIG1heChhZ2VfeWVzKQ0KICApDQopDQoNCnN1bW1hcnlfZGZfbm8gPC0gZGF0YS5mcmFtZSgNCiAgU3RhdGlzdGljID0gYygiTWVhbiIsICJNZWRpYW4iLCAiU3RhbmRhcmQgRGV2aWF0aW9uIiwgIlZhcmlhbmNlIiwgIkNvZWZmaWNpZW50IG9mIFZhcmlhYmlsaXR5ICglKSIsIA0KICAgICAgICAgICAgICAgICJJbnRlcnF1YXJ0aWxlIFJhbmdlIChJUVIpIiwgIkludGVycXVhcnRpbGUgRGV2aWF0aW9uIiwgIklRUiBDb2VmZmljaWVudCBvZiBWYXJpYWJpbGl0eSAoJSkiLA0KICAgICAgICAgICAgICAgICJNaW5pbXVtIiwgIk1heGltdW0iKSwNCiAgTm9uX0NhcmRfT3duZXJzID0gYygNCiAgICBtZWFuKGFnZV9ubyksIG1lZGlhbihhZ2Vfbm8pLCBzZChhZ2Vfbm8pLCB2YXIoYWdlX25vKSwNCiAgICBzZChhZ2Vfbm8pIC8gbWVhbihhZ2Vfbm8pICogMTAwLCBJUVIoYWdlX25vKSwgSVFSKGFnZV9ubykgLyAyLA0KICAgIChJUVIoYWdlX25vKSAvIDIpIC8gbWVkaWFuKGFnZV9ubykgKiAxMDAsIG1pbihhZ2Vfbm8pLCBtYXgoYWdlX25vKQ0KICApDQopDQoNCnN1bW1hcnlfY29tYmluZWQgPC0gbWVyZ2Uoc3VtbWFyeV9kZl95ZXMsIHN1bW1hcnlfZGZfbm8sIGJ5ID0gIlN0YXRpc3RpYyIsIGFsbCA9IFRSVUUpDQoNCmtuaXRyOjprYWJsZShzdW1tYXJ5X2NvbWJpbmVkLCBmb3JtYXQgPSAibWFya2Rvd24iLCBjYXB0aW9uID0gIlN1bW1hcnkgU3RhdGlzdGljcyBmb3IgQWdlIGJ5IENhcmQgT3duZXJzaGlwIikgJT4lDQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFLCBib290c3RyYXBfb3B0aW9ucyA9ICJzdHJpcGVkIiwgcG9zaXRpb24gPSAiY2VudGVyIikNCmBgYA0KDQoNClN1bW1pbmcgdXAgdGhlIGRhdGEgc2hvd2luZyBmcm9tIHRoZSB0YWJsZSBhbmQgdHdvIHBsb3RzIG9mIGFnZSBvZiBwZW9wbGUgdXNpbmcgY3JlZGl0IGNhcmRzIGFuZCBhZ2Ugb2YgcGVvcGxlIHdobyBkb24ndCB3ZSBjYW4gcHJlc2VudCBzb21lIGludGVyZXN0aW5nIGluZm9ybWF0aW9uOg0KDQotIG1heGltdW0gYWdlIGlzIGJpZ2dlciBpbiB0aGUgZ3JvdXAgdXNpbmcgY3JlZGl0IGNhcmRzLCB3aGljaCBtb3N0IHBlb3BsZSB3b3VsZCB0aGluayBpcyBvcHBvc2l0ZWx5LA0KDQotIHRoZXJlIGlzIG1vcmUgcGVvcGxlIGFyb3VuZCBhZ2UgMjUgd2hvIGFyZSBvd25lcnMgb2YgY3JlZGl0IGNhcmQgdGhlbiBwZW9wbGUgYXJvdW5kIHNhbWUgYWdlIG5vdCBvd2luZyBjcmVkaXQgY2FyZHMsDQoNCi0gcGVvcGxlIG93aW5pbmcgY2VkaXQgY2FyZHMgYXJlIG1vc3RseSB5b3VuZyBwZW9wbGUsIHdlIGNhbiBzZWUgYmlnIGRlY2xpbmUgYXJvdW5kIGFnZSAyNyB0byAzNSwNCg0KLSBpbiB0aGUgZ3JvdXAgb3duaW5nIGNyZWRpdCBjYXJkIGFnZSBpcyBtb3JlIGRpdmVyc2UsDQoNCi0gaW4gYm90aCBncm91cHMgd2UgaGF2ZSBzb21lIGRhdGEgZXJyb3JzIGJlY2F1c2Ugd2UgY2FuIHNlZSBzb21lIG91dGxpbmVyIGFyb3VuZCAwLCB3aGljaCBpcyBpbXBvc3NpYmxlIGluIHJlYWwgbGlmZSwNCg0KDQpgYGB7cn0NCmluY29tZV95ZXMgPC0gY3JlZGl0X2NhcmRfeWVzJGluY29tZQ0KaW5jb21lX25vIDwtIGNyZWRpdF9jYXJkX25vJGluY29tZQ0KDQpzdW1tYXJ5KGluY29tZV95ZXMpDQpzdW1tYXJ5KGluY29tZV9ubykNCg0KZ2dwbG90KCkgKw0KICBnZW9tX2RlbnNpdHkoZGF0YSA9IGNyZWRpdF9jYXJkX3llcywgYWVzKHggPSBpbmNvbWUsIGZpbGwgPSAiQ2FyZCBPd25lciIpLCBjb2xvciA9ICJ2aW9sZXRyZWQyIiwgYWxwaGEgPSAwLjcpICsNCiAgZ2VvbV9kZW5zaXR5KGRhdGEgPSBjcmVkaXRfY2FyZF9ubywgYWVzKHggPSBpbmNvbWUsIGZpbGwgPSAiTm9uLU93bmVyIiksIGNvbG9yID0gInZpb2xldCIsIGFscGhhID0gMC43KSArDQogIGxhYnMoeCA9ICJJbmNvbWUiLCB5ID0gIkRlbnNpdHkiLCB0aXRsZSA9ICJEZW5zaXR5IFBsb3Qgb2YgSW5jb21lIChpbiBVU0QgMTAsMDAwKSBieSBDYXJkIE93bmVycyIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiQ2FyZCBPd25lciIgPSAidmlvbGV0cmVkMiIsICJOb24tT3duZXIiID0gInZpb2xldCIpLA0KICAgICAgICAgICAgICAgICAgICBuYW1lID0gIkNhcmQgT3duZXJzaGlwIiwNCiAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiT3duZXIiLCAiTm9uLW93bmVyIikpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoKSArDQogIGdlb21fYm94cGxvdChkYXRhID0gY3JlZGl0X2NhcmRfeWVzLCBhZXMoeCA9ICJDYXJkIE93bmVyIiwgeSA9IGluY29tZSwgZmlsbCA9ICJDYXJkIE93bmVyIiksIGNvbG9yID0gInZpb2xldHJlZDIiLCBhbHBoYSA9IDAuNykgKw0KICBnZW9tX2JveHBsb3QoZGF0YSA9IGNyZWRpdF9jYXJkX25vLCBhZXMoeCA9ICJOb24tT3duZXIiLCB5ID0gaW5jb21lLCBmaWxsID0gIk5vbi1Pd25lciIpLCBjb2xvciA9ICJ2aW9sZXQiLCBhbHBoYSA9IDAuNykgKw0KICBsYWJzKHggPSAiQ2FyZCBPd25lcnNoaXAiLCB5ID0gIkluY29tZSAoaW4gVVNEIDEwLDAwMCkiLCB0aXRsZSA9ICJCb3hwbG90IG9mIEluY29tZSAoaW4gVVNEIDEwLDAwMCkgYnkgQ2FyZCBPd25lcnNoaXAiKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIkNhcmQgT3duZXIiID0gInZpb2xldHJlZDIiLCAiTm9uLU93bmVyIiA9ICJ2aW9sZXQiKSwNCiAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJDYXJkIE93bmVyc2hpcCIsDQogICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIk93bmVyIiwgIk5vbi1Pd25lciIpKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCg0KYGBge3J9DQpzdW1tYXJ5X2RmX3llcyA8LSBkYXRhLmZyYW1lKA0KICBTdGF0aXN0aWMgPSBjKCJNZWFuIiwgIk1lZGlhbiIsICJTdGFuZGFyZCBEZXZpYXRpb24iLCAiVmFyaWFuY2UiLCAiQ29lZmZpY2llbnQgb2YgVmFyaWFiaWxpdHkgKCUpIiwgDQogICAgICAgICAgICAgICAgIkludGVycXVhcnRpbGUgUmFuZ2UgKElRUikiLCAiSW50ZXJxdWFydGlsZSBEZXZpYXRpb24iLCAiSVFSIENvZWZmaWNpZW50IG9mIFZhcmlhYmlsaXR5ICglKSIsDQogICAgICAgICAgICAgICAgIk1pbmltdW0iLCAiTWF4aW11bSIpLA0KICBDYXJkX093bmVycyA9IGMoDQogICAgbWVhbihpbmNvbWVfeWVzKSwgbWVkaWFuKGluY29tZV95ZXMpLCBzZChpbmNvbWVfeWVzKSwgdmFyKGluY29tZV95ZXMpLA0KICAgIHNkKGluY29tZV95ZXMpIC8gbWVhbihpbmNvbWVfeWVzKSAqIDEwMCwgSVFSKGluY29tZV95ZXMpLCBJUVIoaW5jb21lX3llcykgLyAyLA0KICAgIChJUVIoaW5jb21lX3llcykgLyAyKSAvIG1lZGlhbihpbmNvbWVfeWVzKSAqIDEwMCwgbWluKGluY29tZV95ZXMpLCBtYXgoaW5jb21lX3llcykNCiAgKQ0KKQ0KDQpzdW1tYXJ5X2RmX25vIDwtIGRhdGEuZnJhbWUoDQogIFN0YXRpc3RpYyA9IGMoIk1lYW4iLCAiTWVkaWFuIiwgIlN0YW5kYXJkIERldmlhdGlvbiIsICJWYXJpYW5jZSIsICJDb2VmZmljaWVudCBvZiBWYXJpYWJpbGl0eSAoJSkiLCANCiAgICAgICAgICAgICAgICAiSW50ZXJxdWFydGlsZSBSYW5nZSAoSVFSKSIsICJJbnRlcnF1YXJ0aWxlIERldmlhdGlvbiIsICJJUVIgQ29lZmZpY2llbnQgb2YgVmFyaWFiaWxpdHkgKCUpIiwNCiAgICAgICAgICAgICAgICAiTWluaW11bSIsICJNYXhpbXVtIiksDQogIE5vbl9DYXJkX093bmVycyA9IGMoDQogICAgbWVhbihpbmNvbWVfbm8pLCBtZWRpYW4oaW5jb21lX25vKSwgc2QoaW5jb21lX25vKSwgdmFyKGluY29tZV9ubyksDQogICAgc2QoaW5jb21lX25vKSAvIG1lYW4oaW5jb21lX25vKSAqIDEwMCwgSVFSKGluY29tZV9ubyksIElRUihpbmNvbWVfbm8pIC8gMiwNCiAgICAoSVFSKGluY29tZV9ubykgLyAyKSAvIG1lZGlhbihpbmNvbWVfbm8pICogMTAwLCBtaW4oaW5jb21lX25vKSwgbWF4KGluY29tZV9ubykNCiAgKQ0KKQ0KDQpzdW1tYXJ5X2NvbWJpbmVkIDwtIG1lcmdlKHN1bW1hcnlfZGZfeWVzLCBzdW1tYXJ5X2RmX25vLCBieSA9ICJTdGF0aXN0aWMiLCBhbGwgPSBUUlVFKQ0KDQprbml0cjo6a2FibGUoc3VtbWFyeV9jb21iaW5lZCwgZm9ybWF0ID0gIm1hcmtkb3duIiwgY2FwdGlvbiA9ICJTdW1tYXJ5IFN0YXRpc3RpY3MgZm9yIEluY29tZSBieSBDYXJkIE93bmVyc2hpcCIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGQUxTRSwgYm9vdHN0cmFwX29wdGlvbnMgPSAic3RyaXBlZCIsIHBvc2l0aW9uID0gImNlbnRlciIpDQoNCmBgYA0KQW5hbGl6aW5nIGRhdGEgZnJvbSB0aGUgcGxvdHMgYW5kIHRhYmxlIHdlIGNhbiBjb25jbHVkZToNCg0KLSB0aGVyZSBpcyBiaWdnZXIgZGl2ZXJzaXR5IGluIHRoZSBpbmNvbWUgb2YgY2FyZCBvd25lcnMsIA0KDQotIGlmIHdlIGdyb3VwIGNhcmQgb3duZXJzIGJ5IGhleSBpbmNvbWUgd2UgY2FuIHRlbGwgdGhhdCB0aGUgbW9zdCBudW1lcm91cyBncm91cCBpcyB0aGUgb25lIG9mIGluY29tZSAyNTAwMCBVU0QsDQoNCi0gaWYgd2UgZG8gdGhlIHNhbWUgd2l0aCBub24gY2FyZCBvd25lcnMgdGhlbiB0aGUgYmlnZ2VzdCBncm91cCBpcyB0aGUgb25lIG9mIGluY29tZSBhcm91bmQgMjAwMDAgVVNELA0KDQotIHBlb3BsZSB3aXRoIGNyZWRpdCBjYXJkcyBoYXZlIGJpZ2dlciBhdmVyYWdlIGluY29tZSB0aGVuIHBlb3BsZSB3aXRob3V0IHRoZW0sDQoNCi0gbWF4aW11bSBpbmNvbWUgb2YgY3JlZGl0IGNhcmQgb3duZXJzIGlzIGJpZ2dlciB0aGVuIGluIG5vbiBvd25lcnMuDQoNCg0KYGBge3J9DQppbmNvbWVfYWdlX3llcyA8LSBjcmVkaXRfY2FyZF95ZXNbLCBjKCJpbmNvbWUiLCAiYWdlIildDQpzdW1tYXJ5KGluY29tZV9hZ2VfeWVzKQ0KaW5jb21lX2FnZV9ubyA8LSBjcmVkaXRfY2FyZF9ub1ssIGMoImluY29tZSIsICJhZ2UiKV0NCnN1bW1hcnkoaW5jb21lX2FnZV9ubykNCg0KZ2dwbG90KGluY29tZV9hZ2VfeWVzLCBhZXMoeCA9IGFnZSwgeSA9IGluY29tZSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAic2t5Ymx1ZSIsIGNvbG9yID0gInNreWJsdWUiKSArDQogIGxhYnMoeCA9ICJBZ2UiLCB5ID0gIkluY29tZSAoaW4gVVNEIDEwLDAwMCkiLCB0aXRsZSA9ICJJbmNvbWUgYnkgQWdlIChGb3IgUGVvcGxlIHdpdGggQ2FyZHMpIikgKw0KICB0aGVtZV9ncmV5KCkNCg0KZ2dwbG90KGluY29tZV9hZ2Vfbm8sIGFlcyh4ID0gYWdlLCB5ID0gaW5jb21lKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJwaW5rIiwgY29sb3IgPSAicGluayIpICsNCiAgbGFicyh4ID0gIkFnZSIsIHkgPSAiSW5jb21lIChpbiBVU0QgMTAsMDAwKSIsIHRpdGxlID0gIkluY29tZSBieSBBZ2UgKEZvciBQZW9wbGUgV2l0aG91dCBDYXJkcykiKSArDQogIHRoZW1lX2dyZXkoKQ0KYGBgDQpOb3cgbGV0cyBjb21wYXJlIGluY29tZSBieSBhZ2UgaW4gYm90aCBvZiBoZSBncm91cHM6DQotIHdpdGggY3JlZGl0IGNhcmRzIGJpZ2dlc3QgaW5jb21lIGhhdmUgcGVvcGxlIGFyb3VuZCBhZ2Ugb2YgNDIsIHdoaWxlIGZvciBub24gLSBvd25lcnMgdGhpcyBhZ2UgaXMgYSBsaXR0bGUgYml0IHNtYWxsZXIsIGJlY2F1c2UgaXQncyBhcm91bmQgMzUuDQoNCi0gd2UgY2FuIHNlZSBiaWdnZXIgZGlmZmVyZW5jZXMgaW4gaW5jb21lIG9mIGRpZmZlcmVudCBhZ2UgZ3JvdXBzIGZvciBjYXJkIG93bmVycyBjb21wYXJpbmcgdG8gbm9uLW93bmVycywgDQoNCi0gdGhlcmUgaXMgbW9yZSBhZ2UgZ3JvdXBzIGxhY2tpbmcgaW4gdGhlIG5vbi1vd25lcnMsIHdoaWNoIGlzIG9ubHkgYXNzdXJpbmcgdXMgdGhhdCB0aGVyZSBpcyBiaWdnZXIgYWdlIGRpdmVyc2l0eSBpbiB0aGUgY2FyZCBvd25lcnMgZ3JvdXAsDQoNCi0gYWdhaW4gd2UgY2FuIHNlZSBzb21lIGVycm9ycyBpbiBkYXRhIHNldCwgYmVjYXVzZSBoZXJlIGlzIGdyb3VwIG9mIHBlb3BsZSBhcm91bmQgYWdlIDAgd2hpY2ggaGFzIHNvbWUgaW5jb21lIGFuZCBpdCdzIHJhdGhlciBpbXBvc3NpYmxlIGluIHJlYWwgbGlmZSwgc28gYmFzZWQgb24gdGhpcyB3ZSBjYW4gYXNzdW1lIHRoYXQgdGhvc2UgYXJlIGVycm9ycy4NCg0KDQpgYGB7cn0NCmdncGxvdCgpICsNCiAgZ2VvbV9ib3hwbG90KGRhdGEgPSBjcmVkaXRfY2FyZF95ZXMsIGFlcyh4ID0gIkNhcmQgT3duZXIiLCB5ID0gc2hhcmUsIGZpbGwgPSAiQ2FyZCBPd25lciIpLCBjb2xvciA9ICJ0dXJxdW9pc2UyIiwgYWxwaGEgPSAwLjcpICsNCiAgZ2VvbV9ib3hwbG90KGRhdGEgPSBjcmVkaXRfY2FyZF9ubywgYWVzKHggPSAiTm9uLU93bmVyIiwgeSA9IHNoYXJlLCBmaWxsID0gIk5vbi1Pd25lciIpLCBjb2xvciA9ICJwdXJwbGUiLCBhbHBoYSA9IDAuNykgKw0KICBsYWJzKHggPSAiQ2FyZCBPd25lcnNoaXAiLCB5ID0gIlNoYXJlIiwgdGl0bGUgPSAiQm94cGxvdCBvZiBTaGFyZSBieSBDYXJkIE93bmVyc2hpcCIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiQ2FyZCBPd25lciIgPSAidHVycXVvaXNlMiIsICJOb24tT3duZXIiID0gInB1cnBsZSIpLA0KICAgICAgICAgICAgICAgICAgICBuYW1lID0gIkNhcmQgT3duZXJzaGlwIiwNCiAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiT3duZXIiLCAiTm9uLU93bmVyIikpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCmBgYA0KDQpgYGB7cn0NCmdncGxvdCgpICsNCiAgZ2VvbV9kZW5zaXR5KGRhdGEgPSBjcmVkaXRfY2FyZF95ZXMsIGFlcyh4ID0gc2hhcmUsIGZpbGwgPSAiQ2FyZCBPd25lciIpLCBjb2xvciA9ICJ0dXJxdW9pc2UyIiwgYWxwaGEgPSAwLjcpICsNCiAgbGFicyh4ID0gIlNoYXJlIiwgeSA9ICJEZW5zaXR5IiwgdGl0bGUgPSAiRGVuc2l0eSBQbG90IG9mIFNoYXJlIGJ5IENhcmQgT3duZXJzIikgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJDYXJkIE93bmVyIiA9ICJ0dXJxdW9pc2UyIiksDQogICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiQ2FyZCBPd25lcnNoaXAiLA0KICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJPd25lciIpKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpgYGANCg0KYGBge3J9DQpzaGFyZV95ZXMgPC0gY3JlZGl0X2NhcmRfeWVzJHNoYXJlDQpzaGFyZV9ubyA8LSBjcmVkaXRfY2FyZF9ubyRzaGFyZQ0KDQpzdW1tYXJ5X2RmX3llcyA8LSBkYXRhLmZyYW1lKA0KICBTdGF0aXN0aWMgPSBjKCJNZWFuIiwgIk1lZGlhbiIsICJTdGFuZGFyZCBEZXZpYXRpb24iLCAiVmFyaWFuY2UiLCAiQ29lZmZpY2llbnQgb2YgVmFyaWFiaWxpdHkgKCUpIiwgDQogICAgICAgICAgICAgICAgIkludGVycXVhcnRpbGUgUmFuZ2UgKElRUikiLCAiSW50ZXJxdWFydGlsZSBEZXZpYXRpb24iLCAiSVFSIENvZWZmaWNpZW50IG9mIFZhcmlhYmlsaXR5ICglKSIsDQogICAgICAgICAgICAgICAgIk1pbmltdW0iLCAiTWF4aW11bSIpLA0KICBDYXJkX093bmVycyA9IGMoDQogICAgbWVhbihzaGFyZV95ZXMpLCBtZWRpYW4oc2hhcmVfeWVzKSwgc2Qoc2hhcmVfeWVzKSwgdmFyKHNoYXJlX3llcyksDQogICAgc2Qoc2hhcmVfeWVzKSAvIG1lYW4oc2hhcmVfeWVzKSAqIDEwMCwgSVFSKHNoYXJlX3llcyksIElRUihzaGFyZV95ZXMpIC8gMiwNCiAgICAoSVFSKHNoYXJlX3llcykgLyAyKSAvIG1lZGlhbihzaGFyZV95ZXMpICogMTAwLCBtaW4oc2hhcmVfeWVzKSwgbWF4KHNoYXJlX3llcykNCiAgKQ0KKQ0KDQpzdW1tYXJ5X2RmX25vIDwtIGRhdGEuZnJhbWUoDQogIFN0YXRpc3RpYyA9IGMoIk1lYW4iLCAiTWVkaWFuIiwgIlN0YW5kYXJkIERldmlhdGlvbiIsICJWYXJpYW5jZSIsICJDb2VmZmljaWVudCBvZiBWYXJpYWJpbGl0eSAoJSkiLCANCiAgICAgICAgICAgICAgICAiSW50ZXJxdWFydGlsZSBSYW5nZSAoSVFSKSIsICJJbnRlcnF1YXJ0aWxlIERldmlhdGlvbiIsICJJUVIgQ29lZmZpY2llbnQgb2YgVmFyaWFiaWxpdHkgKCUpIiwNCiAgICAgICAgICAgICAgICAiTWluaW11bSIsICJNYXhpbXVtIiksDQogIE5vbl9DYXJkX093bmVycyA9IGMoDQogICAgbWVhbihzaGFyZV9ubyksIG1lZGlhbihzaGFyZV9ubyksIHNkKHNoYXJlX25vKSwgdmFyKHNoYXJlX25vKSwNCiAgICBzZChzaGFyZV9ubykgLyBtZWFuKHNoYXJlX25vKSAqIDEwMCwgSVFSKHNoYXJlX25vKSwgSVFSKHNoYXJlX25vKSAvIDIsDQogICAgKElRUihzaGFyZV9ubykgLyAyKSAvIG1lZGlhbihzaGFyZV9ubykgKiAxMDAsIG1pbihzaGFyZV9ubyksIG1heChzaGFyZV9ubykNCiAgKQ0KKQ0KDQpzdW1tYXJ5X2NvbWJpbmVkIDwtIG1lcmdlKHN1bW1hcnlfZGZfeWVzLCBzdW1tYXJ5X2RmX25vLCBieSA9ICJTdGF0aXN0aWMiLCBhbGwgPSBUUlVFKQ0KDQprbml0cjo6a2FibGUoc3VtbWFyeV9jb21iaW5lZCwgZm9ybWF0ID0gIm1hcmtkb3duIiwgY2FwdGlvbiA9ICJTdW1tYXJ5IFN0YXRpc3RpY3MgZm9yIEFnZSBieSBDYXJkIE93bmVyc2hpcCIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGQUxTRSwgYm9vdHN0cmFwX29wdGlvbnMgPSAic3RyaXBlZCIsIHBvc2l0aW9uID0gImNlbnRlciIpDQoNCmBgYA0KVGhvc2UgcGxvdHMgYW5kIHRhYmxlIHNob3dzIHVzIHNoYXJlIChSYXRpbyBvZiBtb250aGx5IGNyZWRpdCBjYXJkIGV4cGVuZGl0dXJlIHRvIHllYXJseSBpbmNvbWUpIG9mIGNhcmQgb3duZXJzIGFuZCBub24tb3duZXJzLCBhbmQgaXQgc2hvd3MgdXMgc29tZXRoaW5nIHZlcnkgaW50ZXJlc3RpbmcuIFdlIGNvdWxkIGFzc3VtZSB0aGF0IHNoYXJlIGZvciBub24tb3duZXJzIHNob3VsZCBiZSAwLCBiZWNhdXNlIGhvdyBzb21lb25lIHdpdGhvdXQgY3JlZGl0IGNhcmQgY2FuIGhhdmUgYSByYXRpbyBvZiBtb250aGx5IGNyZWRpdCBjYXJkIGV4cGVuZGl0dXJlIHRvIHllYXJseSBpbmNvbWUsIGJ1dCBmcm9tIHRoZSB0YWJsZSBpdCdzIHNheXMgdGhhdCB0aG9zZSBhcmUgZXh0cmVtZWx5IHNtYWxsIG51bWJlcnMsIHdoaWNoIHdlIGNhbiBhc3N1bWUgYXJlIGp1c3QgaW5jb3JyZWN0IHZhbHVlcy4gDQoNClNvIHdlIHdpbGwgYmUgb25seSBmb2N1c2luZyBvbiB0aGUgZ3JvdXAgb2YgY2FyZCBvd25lcnMgd2hpbGUgYW5hbGlzaW5nIHRoZSBkYXRhLg0KDQotIGRpdmVyc2l0IG9mIHRoZSBzaGFyZSBpcyBxdWl0ZSBiaWcsDQoNCi0gd2hlbiB3ZSBncm9wdSBwZW9wbGUgYnkgdGhlaXIgc2hhcmUgd2UgY2FuIHNheSwgdGhhdCBtb3N0IG51bWVyb3VzIGdydW9wIGlzIG9mIHBlb3BsZSBoYXZpbmcgc2hhcmUgYXJvdW5kIDAuMTIsDQoNCi0gbWF4aW11bSBzaGFyZSBpcyAwLjkgd2hpY2ggaXMgYWxtb3N0IDEgc28gaXQgd291bGQgbWVhbiB0aGF0IHRob2VzIHBlb3BsZSBzcGVuZCBhbGwgdGhlaXIgc2FsYXJ5IGJ5IGNyZWRpdCBjYXJkLA0KDQpgYGB7cn0NCmV4cGVuZGl0dXJlc19hZ2U8LWNyZWRpdF9jYXJkX3llc1ssIGMoImV4cGVuZGl0dXJlIiwgImFnZSIpXQ0KDQpzdW1tYXJ5KGV4cGVuZGl0dXJlc19hZ2UpDQoNCmdncGxvdChleHBlbmRpdHVyZXNfYWdlLCBhZXMoeCA9IGFnZSwgeSA9IGV4cGVuZGl0dXJlKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJtYXJvb24iLCBjb2xvciA9ICJtYXJvb24iKSArDQogIGxhYnMoeCA9ICJBZ2UiLCB5ID0gIkV4cGVuZGl0dXJlIiwgdGl0bGUgPSAiRXhwZW5kaXR1cmUgYnkgQWdlIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KTm93IGp1c3QgcXVpY2sgY29uY2x1c2lvbiBmcm9tIHRoaXMgYmFyIHBsb3Q6DQoNCi0gbW9zdGx5IHlvdW5nIHBlb3BsZSBhcmUgcGF5aW5nIHdpdGggY3JlZGl0IGNhcmQsDQoNCi0gYmlnZ2VzdCBleHBlbmRpdHVyZSBoYXZlIHBlb3BsZSBhcm91bmQgMzUsDQoNCi0gZXhwZWR0aXR1cmUgb2YgcGVvcGxlIGFmdGVyIDUwIGlzIGRlY3JlYXNpbmcsDQoNCi0gYWdhaW4gd2Ugc2VlIGluY29ycmVjdCBkYXRhIGFyb3VuZCBhZ2UgMC4NCg0KYGBge3J9DQpzaGFyZV9hZ2U8LWNyZWRpdF9jYXJkX3llc1ssIGMoInNoYXJlIiwgImFnZSIpXQ0KDQpzdW1tYXJ5KHNoYXJlX2FnZSkNCg0KZ2dwbG90KHNoYXJlX2FnZSwgYWVzKHggPSBhZ2UsIHkgPSBzaGFyZSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAic2xhdGVibHVlMiIgLGNvbG9yID0gInNsYXRlYmx1ZTIiKSArDQogIGxhYnMoeCA9ICJBZ2UiLCB5ID0gIlNoYXJlIiwgdGl0bGUgPSAiUmF0aW8gb2YgbW9udGhseSBjcmVkaXQgY2FyZCBleHBlbmRpdHVyZSB0byB5ZWFybHkgaW5jb21lIGJ5IEFnZSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCkFuZCBxdWljayBhc3N1bXB0aW9ucyBmcm9tIHRoaXMgb25lOg0KDQotIGJpZ2dlc3Qgc2hhcmUgaGF2ZSBwZW9wbGUgYXJvdW5kIGFnZSBvZiAyNSwgDQoNCi0gd2UgY2FuIHNlZSB0aGF0IGFmdGVyIGFnZSBvZiA0MCB0aGUgc2hhcmUgaXMgd2F5IHNtYWxsZXIgY29tcGVyaW5nIHRvIHlvdW5nZXIgcGVvcGxlLA0KDQotIGFnYWluIHdlIHNlZSBzb21lIGluY29ycmVjdCBkYXRhIHZhbHVlcyBhcm91bmQgYWdlIDAuDQoNCg0KDQoNCg0KDQpTdW1taW5nIHVwIGFsbCB0aGUgZGF0YSBhbmFseXNpcyB3ZSBoYXZlIGZldyBtb3N0IGltcG9ydGFudCBjb25jbHVzaW9uczoNCg0KLSBtb3JlIHBlb3BsZSB1c2UgY3JlZGl0IGNhcmQgdGhlbiBub3QsIA0KDQotIGJpZ2dlc3QgZ3JvdXAgYWdlIG9mIGNyZWRpdCBjYXJkIHVzZXJzIGFyZSB5b3VuZyBwZW9wbGUsIGFyb3VuZCBhZ2UgMjAtMzAsDQoNCi0gcGVvcGxlIHdobyBoYXZlIGJpZ2dlciBpbmNvbWUgdGhleSB0ZW5kIHRvIGhhdmUgY3JlZGl0IGNhcmRzLA0KDQotIHlvdW5nIHBlb3BsZSB1c2UgY3JlZGl0IGNhcmQgbW9yZSBmcmVxdWVudGx5IHRoZW4gcGVvcGxlIGFmdGVyIDQwcy4NCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQo=