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.
Preprocessing
income<-as.numeric(CreditCard$income)
expenditure<-as.numeric(CreditCard$expenditure)
age<-as.integer(CreditCard$age)
card<-as.factor(CreditCard$card)
Frequency Tables
In the first step of our analysis, we will group our data into a
simple frequency table.
First, let’s look at the distribution of income in our sample and
verify tabular validity using the TAI measure:
Ok, it looks quite ugly, so let’s wrap it up using the ‘kable’
package:
Incomes in kPLN
x
label
Freq
Percent
Valid Percent
Cumulative Percent
Valid
0-2 kPLN
236
17.9
17.9
17.9
2-4 kPLN
783
59.4
59.4
77.3
4-6 kPLN
205
15.5
15.5
92.8
6-8 kPLN
63
4.8
4.8
97.6
8-10 kPLN
23
1.7
1.7
99.3
10-12 kPLN
7
0.5
0.5
99.8
12-14 kPLN
2
0.2
0.2
100.0
Total
1319
100.0
100.0
Missing
<blank>
0
0.0
<NA>
0
0.0
Total
1319
100.0
## # classes Goodness of fit Tabular accuracy
## 7.0000000 0.9085328 0.6568085
As we can see - the TAI index is quite high. 0.65 means that we can
accept the proposed construction of the frequency table.
Expenditure
How about the relation between expenditure and card factor?
By this single plot we can observe that expenditure is highly dependent
from card factor. As shown above, expenditure of card non-holders in all
cases is close if not equal to zero, whereas for the other group this
variable is in range from 0 to so much as 3000.
mean(expenditure)
## [1] 185.0571
median(expenditure)
## [1] 101.2983
sd(expenditure) #standard deviation
## [1] 272.2189
var(expenditure) #variance
## [1] 74103.14
coeff_var<-sd(expenditure)/mean(expenditure) #coefficient of variability %
coeff_var
## [1] 1.471
IQR(expenditure)# difference between quartiles =Q3-Q1
## 75%
## 244.4525
sx<-IQR(expenditure)/2 #interquartile deviation
coeff_varx<-sx/median(expenditure) #IQR coefficient of variability %
coeff_varx
## 75%
## 1.206597
min(expenditure)
## [1] 0
max(expenditure)
## [1] 3099.505
quantile(expenditure,probs=c(0,0.1,0.25,0.5,0.75,0.95,1),na.rm=TRUE)
## 0% 10% 25% 50% 75% 95%
## 0.000000 0.000000 4.583333 101.298300 249.035800 640.730130
## 100%
## 3099.505000
Ok, we have calculated all of the basic summary statistics above.
Let’s wrap them up together now.
card
boxplot
histogram
line1
line2
points1
no
yes
##Age
ggplot(CreditCard, aes(x=card, y=age)) +
geom_boxplot() +
labs(title="Age distribution box plot", x="Credit card holdings", y="Age")
With age the correlation is similar to income. The mean and average is
similar for both groups, but more extreme values are present in card
holders group. Only this time mean seems to be higher for non-holders
than for holders.
Ratio of monthly expenditure to income
## [1] 0.51205875 0.11976382 0.05747126 2.17116850 0.87252231 0.68145681
Since expenditure corelation with card factor is very high, ratio
corelation will also be high.
## Warning: Removed 2 rows containing missing values or values outside the scale range
## (`geom_point()`).
Here the corelation can be clearly seen.
Summary tables
grouped_stats <- CreditCard %>%
dplyr::group_by(card) %>%
dplyr::summarise(
Mean_Income = mean(income, na.rm = TRUE),
SD_Income = sd(income, na.rm = TRUE),
Median_Income = median(income, na.rm = TRUE),
Mean_Expenditure = mean(expenditure, na.rm = TRUE),
SD_Expenditure = sd(expenditure, na.rm = TRUE),
Median_Expenditure = median(expenditure, na.rm = TRUE),
Median_Age = median(age, na.rm = TRUE),
Mean_Age = mean(age, na.rm = TRUE),
SD_Age = sd(age, na.rm = TRUE),
)
print(grouped_stats)
## # A tibble: 2 × 10
## card Mean_Income SD_Income Median_Income Mean_Expenditure SD_Expenditure
## <fct> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 no 3.07 1.62 2.59 0 0
## 2 yes 3.45 1.71 3 239. 288.
## # ℹ 4 more variables: Median_Expenditure <dbl>, Median_Age <dbl>,
## # Mean_Age <dbl>, SD_Age <dbl>
gtsummary
We can calculate easily descriptive statistics also using gtsummary
package:
gt_summary_table <- CreditCard %>%
select(income, expenditure, age, card) %>%
tbl_summary(
by = card,
statistic = list(all_continuous() ~ "{mean} ({sd})")
)
gt_summary_table
Characteristic
no , N = 296
yes , N = 1,023
income
3.07 (1.62)
3.45 (1.71)
expenditure
0 (0)
239 (288)
age
33 (10)
33 (10)
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.
CreditCard<- CreditCard %>%
select(income, expenditure, age, card)
dfSummary(
CreditCard,
plain.ascii = FALSE,
style = "grid",
graph.magnif = 0.75,
valid.col = FALSE,
tmp.img.dir = "/tmp"
)
## temporary images written to 'C:\tmp'
LS0tDQp0aXRsZTogJ0Rlc2NyaXB0aXZlIFN0YXRpc3RpY3MnDQpzdWJ0aXRsZTogJ1VuaXZhcmlhdGUgU3RhdGlzdGljcycNCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCmF1dGhvcjogIk5hdGFsaWEgU2FyYmlld3NrYSwgTWFyY2luIFN1Y2h0bywgWmhhbmcgSGFva2FuZywgTWFjaWVqIEthcndpayINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogDQogICAgdGhlbWU6IGNlcnVsZWFuDQogICAgaGlnaGxpZ2h0OiB0ZXh0bWF0ZQ0KICAgIGZvbnRzaXplOiA4cHQNCiAgICB0b2M6IHllcw0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogbm8NCiAgICBkZl9wcmludDogZGVmYXVsdA0KICAgIHRvY19kZXB0aDogNQ0KZWRpdG9yX29wdGlvbnM6IA0KICBtYXJrZG93bjogDQogICAgd3JhcDogNzINCi0tLQ0KDQpgYGB7ciBzZXR1cDEsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpvcHRpb25zKHF3cmFwczJfbWFya3VwID0gIm1hcmtkb3duIikNCmxpYnJhcnkocXdyYXBzMikNCmxpYnJhcnkoYXJzZW5hbCkNCmxpYnJhcnkoZTEwNzEpDQpsaWJyYXJ5KGhhdmVuKQ0KbGlicmFyeShwYXBlUikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoa2FibGVFeHRyYSkNCmxpYnJhcnkoc3VtbWFyeXRvb2xzKQ0KbGlicmFyeShjbGFzc0ludCkNCmxpYnJhcnkocGFzdGVjcykNCmxpYnJhcnkocmVwb3J0dG9vbHMpDQpsaWJyYXJ5KGRlc2N0YWJsZSkNCmxpYnJhcnkocHN5Y2gpDQpsaWJyYXJ5KGZyZXF1ZW5jeSkNCmxpYnJhcnkoZ2dwdWJyKQ0KbGlicmFyeShnZ2ZvcmNlKQ0KbGlicmFyeShnZ2Rpc3QpDQpsaWJyYXJ5KGdnaGFsdmVzKQ0KbGlicmFyeShndHN1bW1hcnkpDQpsaWJyYXJ5KEFFUikNCg0KYGBgDQojIyBZb3VyIHR1cm4hDQoNCllvdXIgdGFzayB0aGlzIHdlZWsgaXMgdG86IHByZXBhcmUgeW91ciBvd24gZGVzY3JpcHRpdmUgYW5hbHlzaXMgZm9yIHRoZQ0KIkNyZWRpdENhcmQiIGRhdGFzZXQgKEFFUiBwYWNrYWdlKS4gSXQgaXMgYSBjcm9zcy1zZWN0aW9uYWwgZGF0YWZyYW1lIG9uDQp0aGUgY3JlZGl0IGhpc3RvcnkgZm9yIGEgc2FtcGxlIG9mIGFwcGxpY2FudHMgZm9yIGEgdHlwZSBvZiBjcmVkaXQgY2FyZC4NCg0KYGBge3IgaW5jbHVkZT1GQUxTRX0NCmRhdGEoQ3JlZGl0Q2FyZCkNCg0Kc3RyKENyZWRpdENhcmQpDQpzdW1tYXJ5KENyZWRpdENhcmQpDQpgYGANCg0KQXJlIHRoZSB5ZWFybHkgaW5jb21lcyAoaW4gVVNEIDEwLDAwMCksIGNyZWRpdCBjYXJkIGV4cGVuZGl0dXJlcywgYWdlLA0KcmF0aW8gb2YgbW9udGhseSBjcmVkaXQgY2FyZCBleHBlbmRpdHVyZSB0byB5ZWFybHkgaW5jb21lIC0NCnNpZ25pZmljYW50bHkgZGlmZmVyZW50IGZvciBhcHBsaWNhbnRzIGZvciBjdXN0b21lcnMgd2l0aCBkaWZmZXJlbnQNCmNyZWRpdCByaXNrICgiY2FyZCIgdmFyaWFibGUgLSBmYWN0b3IpPw0KDQpQcmVwYXJlIGEgcHJvZmVzc2lvbmFsIGRhdGEgdmlzdWFsaXphdGlvbnMsIGRlc2NyaXB0aXZlIHN0YXRpc3RpY3MnDQp0YWJsZXMgYW5kIGludGVycHJldCB0aGVtLg0KDQojIyBQcmVwcm9jZXNzaW5nDQpgYGB7ciB3cmFuZ2xpbmd9DQppbmNvbWU8LWFzLm51bWVyaWMoQ3JlZGl0Q2FyZCRpbmNvbWUpDQpleHBlbmRpdHVyZTwtYXMubnVtZXJpYyhDcmVkaXRDYXJkJGV4cGVuZGl0dXJlKQ0KYWdlPC1hcy5pbnRlZ2VyKENyZWRpdENhcmQkYWdlKQ0KY2FyZDwtYXMuZmFjdG9yKENyZWRpdENhcmQkY2FyZCkNCg0KYGBgDQojIyBGcmVxdWVuY3kgVGFibGVzDQoNCkluIHRoZSBmaXJzdCBzdGVwIG9mIG91ciBhbmFseXNpcywgd2Ugd2lsbCBncm91cCBvdXIgZGF0YSBpbnRvIGEgc2ltcGxlDQpmcmVxdWVuY3kgdGFibGUuDQoNCkZpcnN0LCBsZXQncyBsb29rIGF0IHRoZSBkaXN0cmlidXRpb24gb2YgaW5jb21lIGluIG91ciBzYW1wbGUNCmFuZCB2ZXJpZnkgdGFidWxhciB2YWxpZGl0eSB1c2luZyB0aGUgVEFJIG1lYXN1cmU6DQoNCmBgYHtyIHRhYmxlLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRX0NCmxhYjwtYygiMC0yIGtQTE4iLCIyLTQga1BMTiIsIjQtNiBrUExOIiwiNi04IGtQTE4iLCI4LTEwIGtQTE4iLCIxMC0xMiBrUExOIiwiMTItMTQga1BMTiIpDQpsaW08LWN1dChDcmVkaXRDYXJkJGluY29tZSxzZXEoIDAsIDE0ICxieT0yKSxsYWJlbHM9bGFiKQ0KdGFiPC1mcmVxKGxpbSwgdHlwZT0iaHRtbCIpDQpgYGANCg0KT2ssIGl0IGxvb2tzIHF1aXRlIHVnbHksIHNvIGxldCdzIHdyYXAgaXQgdXAgdXNpbmcgdGhlICdrYWJsZScgcGFja2FnZToNCg0KYGBge3IgdGFpLCBlY2hvPUZBTFNFfQ0Ka2JsKHRhYixjYXB0aW9uID0gIkluY29tZXMgaW4ga1BMTiIpICU+JQ0KICAgIGthYmxlX21hdGVyaWFsKGMoInN0cmlwZWQiLCAiaG92ZXIiKSkNCnRhYjwtY2xhc3NJbnRlcnZhbHMoQ3JlZGl0Q2FyZCRpbmNvbWUsbj0xMCxzdHlsZT0iZml4ZWQiLGZpeGVkQnJlYWtzPXNlcSgwLCAxNCAsYnk9MikpDQpqZW5rcy50ZXN0cyh0YWIpDQpgYGANCkFzIHdlIGNhbiBzZWUgLSB0aGUgVEFJIGluZGV4IGlzIHF1aXRlIGhpZ2guIDAuNjUgbWVhbnMgdGhhdCB3ZSBjYW4NCmFjY2VwdCB0aGUgcHJvcG9zZWQgY29uc3RydWN0aW9uIG9mIHRoZSBmcmVxdWVuY3kgdGFibGUuDQoNCiMjIEluY29tZQ0KYGBge3IgaGlzdG9ncmFtLCBlY2hvPUZBTFNFfQ0KI0ZpcnN0IGEgaGlzdG9ncmFtDQogIGhpc3QoaW5jb21lLCBicmVha3M9IkZEIiwgY29sPSJwaW5rIiwgcHJvYmFiaWxpdHkgPSBUUlVFLA0KICAgICAgbWFpbj0iSW5jb21lIGluIDEwayBvZiBQTE4iKQ0KICBsaW5lcyhkZW5zaXR5KGluY29tZVtjYXJkPT0ibm8iXSksY29sPTQpDQogIGxpbmVzKGRlbnNpdHkoaW5jb21lW2NhcmQ9PSJ5ZXMiXSksY29sPSJwdXJwbGUiKQ0KICBsZWdlbmQoInRvcHJpZ2h0IiwgbGVnZW5kPWMoIm5vIiwgInllcyIpLA0KICAgICAgICBjb2w9Yyg0LCJwdXJwbGUiKSwgbHR5PTE6MiwgaG9yaXo9RkFMU0UsIGJveC5sdHk9MCwgY2V4PTAuOCkNCg0KZGVuc2l0eS5wIDwtIGdnZGVuc2l0eShDcmVkaXRDYXJkLCB4ID0gImluY29tZSIsIA0KICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImNhcmQiLCBwYWxldHRlID0gImpjbyIpKw0KICBzdGF0X292ZXJsYXlfbm9ybWFsX2RlbnNpdHkoY29sb3IgPSAicmVkIiwgbGluZXR5cGUgPSAiZGFzaGVkIikNCg0KDQojIENvbXB1dGUgZGVzY3JpcHRpdmUgc3RhdGlzdGljcyBieSBncm91cHMNCnN0YWJsZSA8LSBkZXNjX3N0YXRieShDcmVkaXRDYXJkLCBtZWFzdXJlLnZhciA9ICJpbmNvbWUiLA0KICAgICAgICAgICAgICAgICAgICAgIGdycHMgPSAiY2FyZCIpDQpzdGFibGUgPC0gc3RhYmxlWywgYygiY2FyZCIsICJsZW5ndGgiLCAibWVhbiIsICJzZCIpXQ0KIyBTdW1tYXJ5IHRhYmxlIHBsb3QsIG1lZGl1bSBvcmFuZ2UgdGhlbWUNCnN0YWJsZS5wIDwtIGdndGV4dHRhYmxlKHN0YWJsZSwgcm93cyA9IE5VTEwsIA0KICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUgPSB0dGhlbWUoIm1PcmFuZ2UiKSkNCiMgRHJhdyB0ZXh0DQojOjo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6OjoNCnRleHQgPC0gcGFzdGUoIlllYXJseSBpbmNvbWVzIGluIDEwayBVU0QgaW4gcmVsYXRpb24gdG8gY2FyZCBmYWN0b3IiLA0KICAgICAgICAgICAgICAgc2VwID0gIiAiKQ0KdGV4dC5wIDwtIGdncGFyYWdyYXBoKHRleHQgPSB0ZXh0LCBmYWNlID0gIml0YWxpYyIsIHNpemUgPSAxMSwgY29sb3IgPSAiYmxhY2siKQ0KIyBBcnJhbmdlIHRoZSBwbG90cyBvbiB0aGUgc2FtZSBwYWdlDQpnZ2FycmFuZ2UoZGVuc2l0eS5wLCBzdGFibGUucCwgdGV4dC5wLCANCiAgICAgICAgICBuY29sID0gMSwgbnJvdyA9IDMsDQogICAgICAgICAgaGVpZ2h0cyA9IGMoMSwgMC41LCAwLjMpKQ0KDQojR2dwbG90ICANCmdncGxvdChDcmVkaXRDYXJkLCBhZXMoeD1jYXJkLCB5PWluY29tZSwgZmlsbD1jYXJkKSkgKyANCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbj0iZG9kZ2UiKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJibHVlIiwgInJlZCIpKSArICAjIOaMh+WumuminOiJsg0KICBsYWJzKHRpdGxlPSJBbm51YWwgaW5jb21lIGRpc3RyaWJ1dGlvbiBvZiBjcmVkaXQgY2FyZCBob2xkZXJzIGFuZCBub24taG9sZGVycyIsIA0KICAgICAgIHg9IkNyZWRpdCBjYXJkIGhvbGRpbmdzIiwgDQogICAgICAgeT0iQW5udWFsIGluY29tZSAoVW5pdDogVVNEIDEwLDAwMCkiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpnZ3Bsb3QoQ3JlZGl0Q2FyZCwgYWVzKHg9Y2FyZCwgeT1pbmNvbWUpKSArIA0KICBnZW9tX2JveHBsb3QoKSArDQogIGxhYnModGl0bGU9IkFubnVhbCBpbmNvbWUgZGlzdHJpYnV0aW9uIGJveCBwbG90IiwgeD0iQ3JlZGl0IGNhcmQgaG9sZGluZ3MiLCB5PSJBbm51YWwgaW5jb21lIChVbml0OiBVU0QgMTAsMDAwKSIpDQpgYGANCkJhc2VkIG9uIHRoZXNlIGdyYXBocyB3ZSBjYW4gb2JzZXJ2ZSBhIGZldyB0aGluZ3MuIEZpcnN0IG9mIGFsbCwgaW4gdGhlIGZpcnN0IHR3byBncmFwaHMgd2UgY2FuIHNlZSB0aGF0IHRoZSBpbmNvbWUgbGluZSBvZiB0aG9zZSB3aG8gZG8gbm90IGhhdmUgY2FyZHMgaXMgc2xpZ2h0bHkgc2hpZnRlZCB0byB0aGUgbGVmdCwgd2hpY2ggbWVhbnMgdGhhdCB0aGVpciBpbmNvbWUgaXMgc21hbGxlciBjb21wYXJlZCB0byB0aG9zZSB3aXRoIGNhcmRzLiBXZSBjb25maXJtZWQgdGhpcyBvYnNlcnZhdGlvbiBieSBnZW5lcmF0aW5nIHRoZSBtZWFuIG9mIGluY29tZSBmb3IgdGhvc2UgdHdvIGdyb3VwcyBvZiBwZW9wbGUsIHdoZXJlIHdlIGNhbiBjbGVhcmx5IHNlZSB0aGUgZGlmZmVyZW5jZS4gTW9yZW92ZXIsIHRoZSBib3hwbG90IGdyYXBocyBzaG93IHRoYXQgdGhlIG1vcmUgZXh0cmVtZSBpbmNvbWUgdmFsdWVzIChhYm92ZSAxMCkgb2NjdXIgbW9zdGx5IGluIHRoZSBjYXJkLWhvbGRlcnMgZ3JvdXAgd2l0aCBxdWl0ZSBhbiBhZHZhbnRhZ2UuIEJhc2VkIG9uIGFsbCB0aGF0IGluZm9ybWF0aW9uIHRoZXJlIHNlZW1zIHRvIGJlIGxpdHRsZSBjb3JlbGF0aW9uIGJldHdlZW4gaW5jb21lIGFuZCBjYXJkIGZhY3RvciwgaG93ZXZlciB0aGUgZGlmZmVyZW5jZSBpcyBtb3JlIHNpZ25pZmljYW50IHdoZW4gaXQgY29tZXMgdG8gdGhlIHJhbmdlIG9mIGluY29tZSB0aGFuIGl0cyBhdmVyYWdlIA0KDQojIyBFeHBlbmRpdHVyZQ0KSG93IGFib3V0IHRoZSByZWxhdGlvbiBiZXR3ZWVuIGV4cGVuZGl0dXJlIGFuZCBjYXJkIGZhY3Rvcj8NCg0KYGBge3IgYm94cGxvdDIsIGVjaG89RkFMU0V9DQpnZ3Bsb3QoQ3JlZGl0Q2FyZCwgYWVzKHg9Y2FyZCwgeT1leHBlbmRpdHVyZSkpICsNCiAgICBnZW9tX2JveHBsb3QoYWxwaGE9MC43KSArDQogICAgc3RhdF9zdW1tYXJ5KGZ1bj0ibWVhbiIsIGdlb209InBvaW50Iiwgc2hhcGU9MjAsIHNpemU9NSwgY29sb3I9InJlZCIsIGZpbGw9InJlZCIpICsNCiBnZW9tX2ppdHRlcigpICsNCiAgICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlPSJTZXQxIikNCg0KYGBgDQpCeSB0aGlzIHNpbmdsZSBwbG90IHdlIGNhbiBvYnNlcnZlIHRoYXQgZXhwZW5kaXR1cmUgaXMgaGlnaGx5IGRlcGVuZGVudCBmcm9tIGNhcmQgZmFjdG9yLiBBcyBzaG93biBhYm92ZSwgZXhwZW5kaXR1cmUgb2YgY2FyZCBub24taG9sZGVycyBpbiBhbGwgY2FzZXMgaXMgY2xvc2UgaWYgbm90IGVxdWFsIHRvIHplcm8sIHdoZXJlYXMgZm9yIHRoZSBvdGhlciBncm91cCB0aGlzIHZhcmlhYmxlIGlzIGluIHJhbmdlIGZyb20gMCB0byBzbyBtdWNoIGFzIDMwMDAuDQpgYGB7cn0NCiAgICANCiAgICBtZWFuKGV4cGVuZGl0dXJlKQ0KICAgIG1lZGlhbihleHBlbmRpdHVyZSkNCiAgICBzZChleHBlbmRpdHVyZSkgI3N0YW5kYXJkIGRldmlhdGlvbg0KICAgIHZhcihleHBlbmRpdHVyZSkgI3ZhcmlhbmNlDQogICAgY29lZmZfdmFyPC1zZChleHBlbmRpdHVyZSkvbWVhbihleHBlbmRpdHVyZSkgI2NvZWZmaWNpZW50IG9mIHZhcmlhYmlsaXR5ICUNCiAgICBjb2VmZl92YXINCiAgICBJUVIoZXhwZW5kaXR1cmUpIyBkaWZmZXJlbmNlIGJldHdlZW4gcXVhcnRpbGVzID1RMy1RMSANCiAgICBzeDwtSVFSKGV4cGVuZGl0dXJlKS8yICAjaW50ZXJxdWFydGlsZSBkZXZpYXRpb24NCiAgICBjb2VmZl92YXJ4PC1zeC9tZWRpYW4oZXhwZW5kaXR1cmUpICNJUVIgY29lZmZpY2llbnQgb2YgdmFyaWFiaWxpdHkgJQ0KICAgIGNvZWZmX3ZhcngNCiAgICBtaW4oZXhwZW5kaXR1cmUpDQogICAgbWF4KGV4cGVuZGl0dXJlKQ0KICAgIHF1YW50aWxlKGV4cGVuZGl0dXJlLHByb2JzPWMoMCwwLjEsMC4yNSwwLjUsMC43NSwwLjk1LDEpLG5hLnJtPVRSVUUpDQogICAgDQpgYGANCg0KT2ssIHdlIGhhdmUgY2FsY3VsYXRlZCBhbGwgb2YgdGhlIGJhc2ljIHN1bW1hcnkgc3RhdGlzdGljcyBhYm92ZS4gTGV0J3MNCndyYXAgdGhlbSB1cCB0b2dldGhlciBub3cuDQoNCmBgYHtyIGthYmxlX3JlcG9ydCwgZWNobz1GQUxTRX0NCmxpYnJhcnkoa2FibGVFeHRyYSkNCmNhcmRfbGlzdCA8LSBzcGxpdChDcmVkaXRDYXJkJGV4cGVuZGl0dXJlLCBDcmVkaXRDYXJkJGNhcmQpDQppbmxpbmVfcGxvdCA8LSBkYXRhLmZyYW1lKGNhcmQgPSBjKCdubycsICd5ZXMnKSwgYm94cGxvdCA9ICIiLCBoaXN0b2dyYW0gPSAiIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbGluZTEgPSAiIiwgbGluZTIgPSAiIiwgcG9pbnRzMSA9ICIiKQ0KaW5saW5lX3Bsb3QgJT4lDQogIGtibChib29rdGFicyA9IFRSVUUpICU+JQ0KICBrYWJsZV9wYXBlcihmdWxsX3dpZHRoID0gRkFMU0UpICU+JQ0KICBjb2x1bW5fc3BlYygyLCBpbWFnZSA9IHNwZWNfYm94cGxvdChjYXJkX2xpc3QpKSAlPiUNCiAgY29sdW1uX3NwZWMoMywgaW1hZ2UgPSBzcGVjX2hpc3QoY2FyZF9saXN0KSkgJT4lDQogIGNvbHVtbl9zcGVjKDQsIGltYWdlID0gc3BlY19wbG90KGNhcmRfbGlzdCwgc2FtZV9saW0gPSBUUlVFKSkgJT4lDQogIGNvbHVtbl9zcGVjKDUsIGltYWdlID0gc3BlY19wbG90KGNhcmRfbGlzdCwgc2FtZV9saW0gPSBGQUxTRSkpICU+JQ0KICBjb2x1bW5fc3BlYyg2LCBpbWFnZSA9IHNwZWNfcGxvdChjYXJkX2xpc3QsIHR5cGUgPSAicCIpKQ0KDQpgYGANCg0KIyNBZ2UNCmBgYHtyIH0NCg0KZ2dwbG90KENyZWRpdENhcmQsIGFlcyh4PWNhcmQsIHk9YWdlKSkgKyANCiAgZ2VvbV9ib3hwbG90KCkgKw0KICBsYWJzKHRpdGxlPSJBZ2UgZGlzdHJpYnV0aW9uIGJveCBwbG90IiwgeD0iQ3JlZGl0IGNhcmQgaG9sZGluZ3MiLCB5PSJBZ2UiKQ0KDQpgYGANCldpdGggYWdlIHRoZSBjb3JyZWxhdGlvbiBpcyBzaW1pbGFyIHRvIGluY29tZS4gVGhlIG1lYW4gYW5kIGF2ZXJhZ2UgaXMgc2ltaWxhciBmb3IgYm90aCBncm91cHMsIGJ1dCBtb3JlIGV4dHJlbWUgdmFsdWVzIGFyZSBwcmVzZW50IGluIGNhcmQgaG9sZGVycyBncm91cC4gT25seSB0aGlzIHRpbWUgbWVhbiBzZWVtcyB0byBiZSBoaWdoZXIgZm9yIG5vbi1ob2xkZXJzIHRoYW4gZm9yIGhvbGRlcnMuDQoNCiMjIFJhdGlvIG9mIG1vbnRobHkgZXhwZW5kaXR1cmUgdG8gaW5jb21lDQoNCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQoNCkNyZWRpdENhcmQgPC0gdHJhbnNmb3JtKENyZWRpdENhcmQsIHJhdGlvID0gaWZlbHNlKGluY29tZSAhPSAwLCBleHBlbmRpdHVyZSAvIChpbmNvbWUgKiBtb250aHMpLCBOQSkpDQpoZWFkKENyZWRpdENhcmQkcmF0aW8pDQpDcmVkaXRDYXJkICU+JSANCiAgZmlsdGVyKGNhcmQgJWluJSBjKCJubyIsICJ5ZXMiKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBmYWN0b3IoY2FyZCksIHkgPSByYXRpbywgZmlsbCA9IGZhY3RvcihjYXJkKSkpICsNCiAgDQogIHN0YXRfaGFsZmV5ZSgNCiAgICBhZGp1c3QgPSAwLjUsDQogICAganVzdGlmaWNhdGlvbiA9IC0wLjIsDQogICAgLndpZHRoID0gMCwNCiAgICBwb2ludF9jb2xvdXIgPSBOQQ0KICApICsNCiAgZ2VvbV9ib3hwbG90KA0KICAgIHdpZHRoID0gMC4xMiwNCiAgICBvdXRsaWVyLmNvbG9yID0gTkEsDQogICAgYWxwaGEgPSAwLjUNCiAgKSAgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlJhaW5DbG91ZCBQbG90IiwNCiAgICB4ID0gIkNhcmQiLA0KICAgIHkgPSAiUmF0aW8gb2YgZXhwZW5kaXR1cmUgdG8gaW5jb21lIg0KICApICsNCiAgY29vcmRfZmxpcCgpKw0KICB5bGltKGMoMCwgNCkpDQpgYGANClNpbmNlIGV4cGVuZGl0dXJlIGNvcmVsYXRpb24gd2l0aCBjYXJkIGZhY3RvciBpcyB2ZXJ5IGhpZ2gsIHJhdGlvIGNvcmVsYXRpb24gd2lsbCBhbHNvIGJlIGhpZ2guIA0KDQpgYGB7ciBmYWNldDEsIGVjaG89RkFMU0V9DQpwbG90MSA8LSBnZ3Bsb3QoQ3JlZGl0Q2FyZCwgYWVzKGluY29tZSwgcmF0aW8pKSArIA0KICBnZW9tX2ppdHRlcih3aWR0aCA9IDAuMSwgaGVpZ2h0ID0gMC4xKSANCnBsb3QxICsgZmFjZXRfd3JhcCh+Y2FyZCkNCmBgYA0KSGVyZSB0aGUgY29yZWxhdGlvbiBjYW4gYmUgY2xlYXJseSBzZWVuLg0KDQojIyBTdW1tYXJ5IHRhYmxlcw0KDQpgYGB7cn0NCmdyb3VwZWRfc3RhdHMgPC0gQ3JlZGl0Q2FyZCAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KGNhcmQpICU+JQ0KICBkcGx5cjo6c3VtbWFyaXNlKA0KICAgIE1lYW5fSW5jb21lID0gbWVhbihpbmNvbWUsIG5hLnJtID0gVFJVRSksDQogICAgU0RfSW5jb21lID0gc2QoaW5jb21lLCBuYS5ybSA9IFRSVUUpLA0KICAgIE1lZGlhbl9JbmNvbWUgPSBtZWRpYW4oaW5jb21lLCBuYS5ybSA9IFRSVUUpLA0KICAgIE1lYW5fRXhwZW5kaXR1cmUgPSBtZWFuKGV4cGVuZGl0dXJlLCBuYS5ybSA9IFRSVUUpLA0KICAgIFNEX0V4cGVuZGl0dXJlID0gc2QoZXhwZW5kaXR1cmUsIG5hLnJtID0gVFJVRSksDQogICAgTWVkaWFuX0V4cGVuZGl0dXJlID0gbWVkaWFuKGV4cGVuZGl0dXJlLCBuYS5ybSA9IFRSVUUpLA0KICAgIE1lZGlhbl9BZ2UgPSBtZWRpYW4oYWdlLCBuYS5ybSA9IFRSVUUpLA0KICAgIE1lYW5fQWdlID0gbWVhbihhZ2UsIG5hLnJtID0gVFJVRSksDQogICAgU0RfQWdlID0gc2QoYWdlLCBuYS5ybSA9IFRSVUUpLA0KICAgDQogICkNCg0KIHByaW50KGdyb3VwZWRfc3RhdHMpDQoNCmBgYA0KDQoNCiMjIyBndHN1bW1hcnkNCg0KV2UgY2FuIGNhbGN1bGF0ZSBlYXNpbHkgZGVzY3JpcHRpdmUgc3RhdGlzdGljcyBhbHNvIHVzaW5nIGd0c3VtbWFyeQ0KcGFja2FnZToNCg0KYGBge3J9DQoNCg0KZ3Rfc3VtbWFyeV90YWJsZSA8LSBDcmVkaXRDYXJkICU+JQ0KICBzZWxlY3QoaW5jb21lLCBleHBlbmRpdHVyZSwgYWdlLCBjYXJkKSAlPiUNCiAgdGJsX3N1bW1hcnkoDQogICAgYnkgPSBjYXJkLA0KICAgIHN0YXRpc3RpYyA9IGxpc3QoYWxsX2NvbnRpbnVvdXMoKSB+ICJ7bWVhbn0gKHtzZH0pIikNCg0KICApDQoNCmd0X3N1bW1hcnlfdGFibGUNCg0KYGBgDQoNCiMjIyBkZlN1bW1hcnkNCg0KZGZTdW1tYXJ5KCkgY3JlYXRlcyBhIHN1bW1hcnkgdGFibGUgd2l0aCBzdGF0aXN0aWNzLCBmcmVxdWVuY2llcyBhbmQNCmdyYXBocyBmb3IgYWxsIHZhcmlhYmxlcyBpbiBhIGRhdGEgZnJhbWUuIFRoZSBpbmZvcm1hdGlvbiBkaXNwbGF5ZWQgaXMNCnR5cGUtc3BlY2lmaWMgKGNoYXJhY3RlciwgZmFjdG9yLCBudW1lcmljLCBkYXRlKSBhbmQgYWxzbyB2YXJpZXMNCmFjY29yZGluZyB0byB0aGUgbnVtYmVyIG9mIGRpc3RpbmN0IHZhbHVlcy4NCg0KV2hlbiB1c2luZyBkZlN1bW1hcnkoKSBpbiBSIE1hcmtkb3duIGRvY3VtZW50cywgaXQgaXMgZ2VuZXJhbGx5IGEgZ29vZA0KaWRlYSB0byBleGNsdWRlIGEgY29sdW1uIG9yIHR3byB0byBhdm9pZCBtYXJnaW4gb3ZlcmZsb3cuIFNpbmNlIHRoZQ0KVmFsaWQgYW5kIE1pc3NpbmcgY29sdW1ucyBhcmUgcmVkdW5kYW50LCB3ZSBjYW4gZHJvcCBlaXRoZXIgb25lIG9mIHRoZW0uDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9ImFzaXMifQ0KIENyZWRpdENhcmQ8LSBDcmVkaXRDYXJkICU+JQ0KICBzZWxlY3QoaW5jb21lLCBleHBlbmRpdHVyZSwgYWdlLCBjYXJkKQ0KZGZTdW1tYXJ5KA0KICBDcmVkaXRDYXJkLA0KICBwbGFpbi5hc2NpaSA9IEZBTFNFLA0KICBzdHlsZSA9ICJncmlkIiwNCiAgZ3JhcGgubWFnbmlmID0gMC43NSwNCiAgdmFsaWQuY29sID0gRkFMU0UsDQogIHRtcC5pbWcuZGlyID0gIi90bXAiDQopDQoNCmBgYA0KDQpUbyBwcm9kdWNlIG9wdGltYWwgcmVzdWx0cywgc3VtbWFyeXRvb2xzIGhhcyBpdHMgb3duIHZlcnNpb24gb2YgdGhlIGJhc2UNCmJ5KCkgZnVuY3Rpb24uIEl0J3MgY2FsbGVkIHN0YnkoKSwgYW5kIHdlIHVzZSBpdCBleGFjdGx5IGFzIHdlIHdvdWxkDQpieSgpOg0KDQoNCmBgYHtyIGVjaG89RkFMU0V9DQogQ3JlZGl0Q2FyZDwtIENyZWRpdENhcmQgJT4lDQogIHNlbGVjdChpbmNvbWUsIGV4cGVuZGl0dXJlLCBhZ2UsIGNhcmQpDQpDcmVkaXRDYXJkICU+JQ0KICBkZXNjcihzdGF0cyA9ICJjb21tb24iKSAlPiUNCiAgdGIoKQ0KDQpncm91cGVkX2Rlc2NyIDwtIHN0YnkoZGF0YSA9IENyZWRpdENhcmQsIElORElDRVMgPSBDcmVkaXRDYXJkJGNhcmQsIEZVTiA9IGRlc2NyLCBzdGF0cyA9ICJjb21tb24iKQ0KDQpncm91cGVkX2Rlc2NyICU+JSB0YigpDQpgYGANCg0KYGBge3IgZWNobz1GQUxTRX0NCiBDcmVkaXRDYXJkPC0gQ3JlZGl0Q2FyZCAlPiUNCiAgc2VsZWN0KGluY29tZSwgZXhwZW5kaXR1cmUsIGFnZSwgY2FyZCkNCnN0YnkoZGF0YSAgICA9IENyZWRpdENhcmQsIA0KICAgICBJTkRJQ0VTID0gQ3JlZGl0Q2FyZCRjYXJkLCANCiAgICAgRlVOICAgICA9IGRlc2NyLCANCiAgICAgc3RhdHMgICA9ICJmaXZlbnVtIikgJT4lDQogIHRiKG9yZGVyID0gMykgJT4lDQogIGthYmxlKGZvcm1hdCA9ICJodG1sIiwgZGlnaXRzID0gMikNCmBgYA0KDQo=