Data
In our example this week, we are going to use the fake data - about
real estates in Wroclaw - prices by districts, size of apartments and
many more.
Preprocessing
As you can see, not all formats of our variables are adapted. We need
to prepare appropriate formats of our variables according to their
measurement scale and future application.
apartments$district<-as.factor(apartments$district)
apartments$building_type<-as.factor(apartments$building_type)
apartments$rooms<-factor(apartments$rooms,ordered=TRUE)
attach(apartments)
apartments$price_PLN<-as.numeric(apartments$price_PLN)
apartments$price_EUR<-as.numeric(apartments$price_EUR)
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 housing prices 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:
Apartments in Wroclaw - prices in kPLN
x
label
Freq
Percent
Valid Percent
Cumulative Percent
Valid
350-450 kPLN
9
4.5
4.5
4.5
450-550 kPLN
21
10.5
10.5
15.0
550-650 kPLN
33
16.5
16.5
31.5
650-750 kPLN
36
18.0
18.0
49.5
750-850 kPLN
31
15.5
15.5
65.0
850-950 kPLN
36
18.0
18.0
83.0
950-1050 kPLN
21
10.5
10.5
93.5
1050-1150 kPLN
10
5.0
5.0
98.5
1150-1250 kPLN
2
1.0
1.0
99.5
1250-1350 kPLN
1
0.5
0.5
100.0
Total
200
100.0
100.0
Missing
<blank>
0
0.0
<NA>
0
0.0
Total
200
100.0
## # classes Goodness of fit Tabular accuracy
## 10.0000000 0.9780872 0.8508467
As we can see - the TAI index is quite high. 0.85 means that we can
accept the proposed construction of the frequency table.
Basic plots
In this section, we should represent our data using basic
(pre-installed in R) graphics. Select the most appropriate graphs
depending on the scale of the selected variables. Explore the
heterogeneity of the distribution by presenting the data by group (e.g.,
by neighborhood, building type, etc.). Don’t forget about main titles,
labels and legends. Read more about graphical parameters here .
Note that the echo = FALSE parameter has been added to
the code snippet to prevent printing the R code that generated the
graph.
ggplot2 plots
Now, let’s use the ggplot2 and
ggpubr libraries to plot.
Ggplot2 allows you to show the average value for each group using the
stat_summary() function. You no longer need to
calculate average values before creating a graph!
RainCloud Plot
Faceting
Faceting generates small multiples, each showing a different subset
of the data. They are a powerful tool for exploratory data analysis: you
can quickly compare patterns in different parts of the data and see if
they are the same or different. Read more here .
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 .
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")
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.
Preprocessing
attach(CreditCard)
CreditCard$expenditure<-as.numeric(CreditCard$expenditure)
Frequency Table
table<-c("0-300 PLN", "300-600 PLN","600-900 PLN","900-1200 PLN","1200-1500 PLN","1500-1800 PLN","1800-2100 PLN","2100-2400 PLN","2400-2700 PLN","2700-3000 PLN", "3000-3300 PLN")
limits<-cut(CreditCard$expenditure,seq(0,3300,by=300),labels=table)
table1<-freq(limits, type="html")
## Building tables
##
|
| | 0%
|
|======================================================================| 100%
## Temporary file saved to: /var/folders/99/w3lm9dwd2q929kjsdm9dyy7c0000gn/T//RtmpRE1oEA/file1083daf9cfd7.html
## To open by default use: options(frequency_open_output = TRUE)
kbl(table1,caption = "Expenditures") %>%
kable_material(c("striped", "hover"))
Expenditures
x
label
Freq
Percent
Valid Percent
Cumulative Percent
Valid
0-300 PLN
724
54.9
72.3
72.3
300-600 PLN
199
15.1
19.9
92.1
600-900 PLN
53
4.0
5.3
97.4
900-1200 PLN
10
0.8
1.0
98.4
1200-1500 PLN
3
0.2
0.3
98.7
1500-1800 PLN
6
0.5
0.6
99.3
1800-2100 PLN
5
0.4
0.5
99.8
2100-2400 PLN
1
0.1
0.1
99.9
3000-3300 PLN
1
0.1
0.1
100.0
Total
1002
76.0
100.0
Missing
<blank>
0
0.0
<NA>
317
24.0
Total
1319
100.0
tab1<-classIntervals(CreditCard$expenditure,n=11,style="fixed",fixedBreaks=seq(0,3300,by=300))
jenks.tests(tab1)
## # classes Goodness of fit Tabular accuracy
## 11.0000000 0.9037459 0.5889084
Plot
# Define the age groups
age_groups <- c("0 - 10", "10 - 20", "20 - 30", "30 - 40", "40 - 50", "50 - 60", "60 - 70", "70 - 80", "80 - 90")
# Create a new column 'age_group' based on the specified ranges
CreditCard$age_group <- cut(CreditCard$age, breaks = c(0, 10, 20, 30, 40, 50, 60, 70, 80, 90), labels = age_groups, include.lowest = TRUE)
# Calculate average expenditures for each age group
avg_expenditures <- aggregate(expenditure ~ age_group, data = CreditCard, FUN = mean)
# Bar plot of average expenditures by age group
ggplot(avg_expenditures, aes(x = age_group, y = expenditure)) +
geom_bar(stat = "identity", fill = "skyblue", color = "black") +
labs(title = "Average Expenditures by Age Group", x = "Age Group", y = "Average Expenditures") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
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
expenditure_list <- split(CreditCard$expenditure, CreditCard$age_group)
inline_plot <- data.frame(age_groups = c("0 - 10", "10 - 20", "20 - 30", "30 - 40", "40 - 50", "50 - 60", "60 - 70", "70 - 80", "80 - 90"), boxplot = "", histogram = "", line1 = "", line2 = "", points1 = "")
inline_plot %>%
kbl(booktabs = TRUE) %>%
kable_paper(full_width = FALSE) %>%
column_spec(2, image = spec_boxplot(expenditure_list)) %>%
column_spec(3, image = spec_hist(expenditure_list)) %>%
column_spec(4, image = spec_plot(expenditure_list, same_lim = TRUE)) %>%
column_spec(5, image = spec_plot(expenditure_list, same_lim = FALSE)) %>%
column_spec(6, image = spec_plot(expenditure_list, type = "p"))
age_groups
boxplot
histogram
line1
line2
points1
0 - 10
10 - 20
20 - 30
30 - 40
40 - 50
50 - 60
60 - 70
70 - 80
80 - 90
# Calculate total yearly credit card expenditure
CreditCard$total_expenditure <- CreditCard$expenditure * 12
# Calculate ratio of total yearly credit card expenditure to yearly income
CreditCard$ratio <- CreditCard$total_expenditure / CreditCard$income
# Group by credit risk (card) and calculate mean ratio
ratio_by_card <- CreditCard %>%
group_by(card) %>%
summarise(mean_ratio = mean(ratio))
# Print the result
print(ratio_by_card)
## # A tibble: 2 × 2
## card mean_ratio
## <fct> <dbl>
## 1 no 0
## 2 yes 884.
From the boxplots, we observe that there are variations in yearly
incomes, credit card expenditures, age, and the ratio of monthly credit
card expenditure to yearly income across different credit risk
categories.
# Descriptive analysis and visualization
# Boxplot for yearly incomes by credit risk
ggplot(CreditCard, aes(x = card, y = income)) +
geom_boxplot(fill = "skyblue", color = "blue") +
labs(x = "Credit Risk", y = "Yearly Income (in USD 10,000)", title = "Yearly Incomes by Credit Risk")
# Boxplot for credit card expenditures by credit risk
ggplot(CreditCard, aes(x = card, y = expenditure)) +
geom_boxplot(fill = "lightgreen", color = "darkgreen") +
labs(x = "Credit Risk", y = "Credit Card Expenditure", title = "Credit Card Expenditures by Credit Risk")
# Boxplot for age by credit risk
ggplot(CreditCard, aes(x = card, y = age)) +
geom_boxplot(fill = "lightcoral", color = "darkred") +
labs(x = "Credit Risk", y = "Age", title = "Age by Credit Risk")
# Boxplot for ratio of monthly credit card expenditure to yearly income by credit risk
ggplot(CreditCard, aes(x = card, y = ratio)) +
geom_boxplot(fill = "lightyellow", color = "darkorange") +
labs(x = "Credit Risk", y = "Ratio of Monthly Expenditure to Yearly Income", title = "Ratio by Credit Risk")
# Descriptive statistics table for yearly incomes by credit risk
yearly_income_summary <- CreditCard %>%
group_by(card) %>%
summarise(mean_income = mean(income),
median_income = median(income),
sd_income = sd(income),
min_income = min(income),
max_income = max(income))
# Descriptive statistics table for credit card expenditures by credit risk
expenditure_summary <- CreditCard %>%
group_by(card) %>%
summarise(mean_expenditure = mean(expenditure),
median_expenditure = median(expenditure),
sd_expenditure = sd(expenditure),
min_expenditure = min(expenditure),
max_expenditure = max(expenditure))
# Descriptive statistics table for age by credit risk
age_summary <- CreditCard %>%
group_by(card) %>%
summarise(mean_age = mean(age),
median_age = median(age),
sd_age = sd(age),
min_age = min(age),
max_age = max(age))
# Descriptive statistics table for ratio of monthly credit card expenditure to yearly income by credit risk
ratio_summary <- CreditCard %>%
group_by(card) %>%
summarise(mean_ratio = mean(ratio),
median_ratio = median(ratio),
sd_ratio = sd(ratio),
min_ratio = min(ratio),
max_ratio = max(ratio))
# Print descriptive statistics tables
print("Descriptive Statistics for Yearly Incomes by Credit Risk:")
## [1] "Descriptive Statistics for Yearly Incomes by Credit Risk:"
print(yearly_income_summary)
## # A tibble: 2 × 6
## card mean_income median_income sd_income min_income max_income
## <fct> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 no 3.07 2.59 1.62 0.49 11
## 2 yes 3.45 3 1.71 0.21 13.5
print("Descriptive Statistics for Credit Card Expenditures by Credit Risk:")
## [1] "Descriptive Statistics for Credit Card Expenditures by Credit Risk:"
print(expenditure_summary)
## # A tibble: 2 × 6
## card mean_expenditure median_expenditure sd_expenditure min_expenditure
## <fct> <dbl> <dbl> <dbl> <dbl>
## 1 no 0 0 0 0
## 2 yes 239. 150. 288. 0
## # ℹ 1 more variable: max_expenditure <dbl>
print("Descriptive Statistics for Age by Credit Risk:")
## [1] "Descriptive Statistics for Age by Credit Risk:"
print(age_summary)
## # A tibble: 2 × 6
## card mean_age median_age sd_age min_age max_age
## <fct> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 no 33.2 31.8 9.92 0.75 80.2
## 2 yes 33.2 31.1 10.2 0.167 83.5
print("Descriptive Statistics for Ratio of Monthly Expenditure to Yearly Income by Credit Risk:")
## [1] "Descriptive Statistics for Ratio of Monthly Expenditure to Yearly Income by Credit Risk:"
print(ratio_summary)
## # A tibble: 2 × 6
## card mean_ratio median_ratio sd_ratio min_ratio max_ratio
## <fct> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 no 0 0 0 0 0
## 2 yes 884. 602. 991. 0 9063.
LS0tCnRpdGxlOiAnRGVzY3JpcHRpdmUgU3RhdGlzdGljcycKc3VidGl0bGU6ICdVbml2YXJpYXRlIFN0YXRpc3RpY3MnCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKYXV0aG9yOiAiWW91ciBOYW1lIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDogCiAgICB0aGVtZTogY2VydWxlYW4KICAgIGhpZ2hsaWdodDogdGV4dG1hdGUKICAgIGZvbnRzaXplOiA4cHQKICAgIHRvYzogeWVzCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiBubwogICAgZGZfcHJpbnQ6IGRlZmF1bHQKICAgIHRvY19kZXB0aDogNQplZGl0b3Jfb3B0aW9uczogCiAgbWFya2Rvd246IAogICAgd3JhcDogNzIKLS0tCgpgYGB7ciBzZXR1cDEsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKb3B0aW9ucyhxd3JhcHMyX21hcmt1cCA9ICJtYXJrZG93biIpCmxpYnJhcnkocXdyYXBzMikKbGlicmFyeShhcnNlbmFsKQpsaWJyYXJ5KGUxMDcxKQpsaWJyYXJ5KGhhdmVuKQpsaWJyYXJ5KHBhcGVSKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShrYWJsZUV4dHJhKQpsaWJyYXJ5KHN1bW1hcnl0b29scykKbGlicmFyeShjbGFzc0ludCkKbGlicmFyeShwYXN0ZWNzKQpsaWJyYXJ5KHJlcG9ydHRvb2xzKQpsaWJyYXJ5KGRlc2N0YWJsZSkKbGlicmFyeShwc3ljaCkKbGlicmFyeShmcmVxdWVuY3kpCmxpYnJhcnkoZ2dwdWJyKQpsaWJyYXJ5KGdnZm9yY2UpCmxpYnJhcnkoZ2dkaXN0KQpsaWJyYXJ5KGdnaGFsdmVzKQpsaWJyYXJ5KGd0c3VtbWFyeSkKbGlicmFyeShBRVIpCmRvd25sb2FkLmZpbGUoImh0dHBzOi8vZ2l0aHViLmNvbS9rZmxpc2lrb3dza2kvZHMvYmxvYi9tYXN0ZXIvZGF0YV9hcGFydG1lbnRzLmNzdj9yYXc9dHJ1ZSIsIGRlc3RmaWxlID0ibWllc3prYW5pYS5jc3YiLG1vZGU9IndiIikKYXBhcnRtZW50cyA8LSByZWFkLmNzdigibWllc3prYW5pYS5jc3YiLHNlcD0iOyIsZGVjPSIsIikKYGBgCgojIyBEYXRhCgpJbiBvdXIgZXhhbXBsZSB0aGlzIHdlZWssIHdlIGFyZSBnb2luZyB0byB1c2UgdGhlIGZha2UgZGF0YSAtIGFib3V0IHJlYWwKZXN0YXRlcyBpbiBXcm9jbGF3IC0gcHJpY2VzIGJ5IGRpc3RyaWN0cywgc2l6ZSBvZiBhcGFydG1lbnRzIGFuZCBtYW55Cm1vcmUuCgojIyMgUHJlcHJvY2Vzc2luZwoKQXMgeW91IGNhbiBzZWUsIG5vdCBhbGwgZm9ybWF0cyBvZiBvdXIgdmFyaWFibGVzIGFyZSBhZGFwdGVkLiBXZSBuZWVkIHRvCnByZXBhcmUgYXBwcm9wcmlhdGUgZm9ybWF0cyBvZiBvdXIgdmFyaWFibGVzIGFjY29yZGluZyB0byB0aGVpcgptZWFzdXJlbWVudCBzY2FsZSBhbmQgZnV0dXJlIGFwcGxpY2F0aW9uLgoKYGBge3Igd3JhbmdsaW5nLCBpbmNsdWRlPVRSVUV9CmFwYXJ0bWVudHMkZGlzdHJpY3Q8LWFzLmZhY3RvcihhcGFydG1lbnRzJGRpc3RyaWN0KQphcGFydG1lbnRzJGJ1aWxkaW5nX3R5cGU8LWFzLmZhY3RvcihhcGFydG1lbnRzJGJ1aWxkaW5nX3R5cGUpCmFwYXJ0bWVudHMkcm9vbXM8LWZhY3RvcihhcGFydG1lbnRzJHJvb21zLG9yZGVyZWQ9VFJVRSkKYXR0YWNoKGFwYXJ0bWVudHMpCmFwYXJ0bWVudHMkcHJpY2VfUExOPC1hcy5udW1lcmljKGFwYXJ0bWVudHMkcHJpY2VfUExOKQphcGFydG1lbnRzJHByaWNlX0VVUjwtYXMubnVtZXJpYyhhcGFydG1lbnRzJHByaWNlX0VVUikKYGBgCgojIyBGcmVxdWVuY3kgVGFibGVzCgpJbiB0aGUgZmlyc3Qgc3RlcCBvZiBvdXIgYW5hbHlzaXMsIHdlIHdpbGwgZ3JvdXAgb3VyIGRhdGEgaW50byBhIHNpbXBsZQpmcmVxdWVuY3kgdGFibGUuCgpGaXJzdCwgbGV0J3MgbG9vayBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIGhvdXNpbmcgcHJpY2VzIGluIG91ciBzYW1wbGUKYW5kIHZlcmlmeSB0YWJ1bGFyIHZhbGlkaXR5IHVzaW5nIHRoZSBUQUkgbWVhc3VyZToKCmBgYHtyIHRhYmxlLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRX0KZXR5a2lldHk8LWMoIjM1MC00NTAga1BMTiIsIjQ1MC01NTAga1BMTiIsIjU1MC02NTAga1BMTiIsIjY1MC03NTAga1BMTiIsIjc1MC04NTAga1BMTiIsIjg1MC05NTAga1BMTiIsIjk1MC0xMDUwIGtQTE4iLCIxMDUwLTExNTAga1BMTiIsIjExNTAtMTI1MCBrUExOIiwiMTI1MC0xMzUwIGtQTE4iKQpsaW1pdHM8LWN1dChhcGFydG1lbnRzJHByaWNlX1BMTixzZXEoMzUwMDAwLDEzNTAwMDAsYnk9MTAwMDAwKSxsYWJlbHM9ZXR5a2lldHkpCnRhYmVsYTE8LWZyZXEobGltaXRzLHR5cGU9Imh0bWwiKQpgYGAKCk9rLCBpdCBsb29rcyBxdWl0ZSB1Z2x5LCBzbyBsZXQncyB3cmFwIGl0IHVwIHVzaW5nIHRoZSAna2FibGUnIHBhY2thZ2U6CgpgYGB7ciB0YWksIGVjaG89RkFMU0V9CmtibCh0YWJlbGExLGNhcHRpb24gPSAiQXBhcnRtZW50cyBpbiBXcm9jbGF3IC0gcHJpY2VzIGluIGtQTE4iKSAlPiUKICAgIGthYmxlX21hdGVyaWFsKGMoInN0cmlwZWQiLCAiaG92ZXIiKSkKdGFiMTwtY2xhc3NJbnRlcnZhbHMoYXBhcnRtZW50cyRwcmljZV9QTE4sbj0xMCxzdHlsZT0iZml4ZWQiLGZpeGVkQnJlYWtzPXNlcSgzNTAwMDAsMTM1MDAwMCxieT0xMDAwMDApKQpqZW5rcy50ZXN0cyh0YWIxKQpgYGAKCkFzIHdlIGNhbiBzZWUgLSB0aGUgVEFJIGluZGV4IGlzIHF1aXRlIGhpZ2guIDAuODUgbWVhbnMgdGhhdCB3ZSBjYW4KYWNjZXB0IHRoZSBwcm9wb3NlZCBjb25zdHJ1Y3Rpb24gb2YgdGhlIGZyZXF1ZW5jeSB0YWJsZS4KCiMjIEJhc2ljIHBsb3RzCgpJbiB0aGlzIHNlY3Rpb24sIHdlIHNob3VsZCByZXByZXNlbnQgb3VyIGRhdGEgdXNpbmcgYmFzaWMgKHByZS1pbnN0YWxsZWQKaW4gUikgZ3JhcGhpY3MuIFNlbGVjdCB0aGUgbW9zdCBhcHByb3ByaWF0ZSBncmFwaHMgZGVwZW5kaW5nIG9uIHRoZQpzY2FsZSBvZiB0aGUgc2VsZWN0ZWQgdmFyaWFibGVzLiBFeHBsb3JlIHRoZSBoZXRlcm9nZW5laXR5IG9mIHRoZQpkaXN0cmlidXRpb24gYnkgcHJlc2VudGluZyB0aGUgZGF0YSBieSBncm91cCAoZS5nLiwgYnkgbmVpZ2hib3Job29kLApidWlsZGluZyB0eXBlLCBldGMuKS4gRG9uJ3QgZm9yZ2V0IGFib3V0IG1haW4gdGl0bGVzLCBsYWJlbHMgYW5kCmxlZ2VuZHMuIFJlYWQgbW9yZSBhYm91dCBncmFwaGljYWwgcGFyYW1ldGVycwpbaGVyZV0oaHR0cDovL3d3dy5zdGhkYS5jb20vZW5nbGlzaC93aWtpL2dyYXBoaWNhbC1wYXJhbWV0ZXJzKS4KCmBgYHtyIGhpc3RvZ3JhbSwgZWNobz1GQUxTRX0KaGlzdChwcmljZV9QTE4sIGJyZWFrcz0iRkQiLCBjb2w9ImdyZWVuIiwgcHJvYmFiaWxpdHkgPSBUUlVFLAogICAgIG1haW49IlByaWNlcyBpbiBQTE4gLSBXcm9jbGF3IikKbGluZXMoZGVuc2l0eShwcmljZV9QTE5bZGlzdHJpY3Q9PSJLcnp5a2kiXSksY29sPTIpCmxpbmVzKGRlbnNpdHkocHJpY2VfUExOW2Rpc3RyaWN0PT0iQmlza3VwaW4iXSksY29sPTMpCmxpbmVzKGRlbnNpdHkocHJpY2VfUExOW2Rpc3RyaWN0PT0iU3JvZG1pZXNjaWUiXSksY29sPTQpCmxlZ2VuZCgidG9wcmlnaHQiLCBsZWdlbmQ9YygiS3J6eWtpIiwgIkJpc2t1cGluIiwgIlNyb2RtaWVzY2llIiksCiAgICAgICBjb2w9YygyLDMsNCksIGx0eT0xOjIsIGhvcml6PUZBTFNFLCBib3gubHR5PTAsIGNleD0wLjgpCgpgYGAKCk5vdGUgdGhhdCB0aGUgYGVjaG8gPSBGQUxTRWAgcGFyYW1ldGVyIGhhcyBiZWVuIGFkZGVkIHRvIHRoZSBjb2RlCnNuaXBwZXQgdG8gcHJldmVudCBwcmludGluZyB0aGUgUiBjb2RlIHRoYXQgZ2VuZXJhdGVkIHRoZSBncmFwaC4KCmBgYHtyIGJveHBsb3QsIGVjaG89RkFMU0V9CmJveHBsb3QocHJpY2VfUExOfmRpc3RyaWN0KQpgYGAKCiMjIGdncGxvdDIgcGxvdHMKCk5vdywgbGV0J3MgdXNlIHRoZSAqKipnZ3Bsb3QyKioqIGFuZCAqKipnZ3B1YnIqKiogbGlicmFyaWVzIHRvIHBsb3QuCgpgYGB7ciBoaXN0b2dyYW0yLCBlY2hvPUZBTFNFfQojIERlbnNpdHkgcGxvdCBvZiAicHJpY2VfUExOIgojOjo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6OjoKZGVuc2l0eS5wIDwtIGdnZGVuc2l0eShhcGFydG1lbnRzLCB4ID0gInByaWNlX1BMTiIsIAogICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiZGlzdHJpY3QiLCBwYWxldHRlID0gImpjbyIpKwogIHN0YXRfb3ZlcmxheV9ub3JtYWxfZGVuc2l0eShjb2xvciA9ICJyZWQiLCBsaW5ldHlwZSA9ICJkYXNoZWQiKQoKIyBEcmF3IHRoZSBzdW1tYXJ5IHRhYmxlIG9mIHByaWNlX1BMTgojOjo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6OjoKIyBDb21wdXRlIGRlc2NyaXB0aXZlIHN0YXRpc3RpY3MgYnkgZ3JvdXBzCnN0YWJsZSA8LSBkZXNjX3N0YXRieShhcGFydG1lbnRzLCBtZWFzdXJlLnZhciA9ICJwcmljZV9QTE4iLAogICAgICAgICAgICAgICAgICAgICAgZ3JwcyA9ICJkaXN0cmljdCIpCnN0YWJsZSA8LSBzdGFibGVbLCBjKCJkaXN0cmljdCIsICJsZW5ndGgiLCAibWVhbiIsICJzZCIpXQojIFN1bW1hcnkgdGFibGUgcGxvdCwgbWVkaXVtIG9yYW5nZSB0aGVtZQpzdGFibGUucCA8LSBnZ3RleHR0YWJsZShzdGFibGUsIHJvd3MgPSBOVUxMLCAKICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUgPSB0dGhlbWUoIm1PcmFuZ2UiKSkKIyBEcmF3IHRleHQKIzo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6CnRleHQgPC0gcGFzdGUoIlByaWNlIHBlciBhcGFydG1lbnQgYnkgMyBkaXN0cmljdHMgLSBXcm9jbGF3LiIsCiAgICAgICAgICAgICAgIlJhbmRvbSBzYW1wbGUgb2YgMjAwIGFwYXJ0bWVudHMuIiwKICAgICAgICAgICAgICAgc2VwID0gIiAiKQp0ZXh0LnAgPC0gZ2dwYXJhZ3JhcGgodGV4dCA9IHRleHQsIGZhY2UgPSAiaXRhbGljIiwgc2l6ZSA9IDExLCBjb2xvciA9ICJibGFjayIpCiMgQXJyYW5nZSB0aGUgcGxvdHMgb24gdGhlIHNhbWUgcGFnZQpnZ2FycmFuZ2UoZGVuc2l0eS5wLCBzdGFibGUucCwgdGV4dC5wLCAKICAgICAgICAgIG5jb2wgPSAxLCBucm93ID0gMywKICAgICAgICAgIGhlaWdodHMgPSBjKDEsIDAuNSwgMC4zKSkKYGBgCgpHZ3Bsb3QyIGFsbG93cyB5b3UgdG8gc2hvdyB0aGUgYXZlcmFnZSB2YWx1ZSBmb3IgZWFjaCBncm91cCB1c2luZyB0aGUKKipzdGF0X3N1bW1hcnkoKSoqIGZ1bmN0aW9uLiBZb3Ugbm8gbG9uZ2VyIG5lZWQgdG8gY2FsY3VsYXRlIGF2ZXJhZ2UKdmFsdWVzIGJlZm9yZSBjcmVhdGluZyBhIGdyYXBoIQoKYGBge3IgYm94cGxvdDIsIGVjaG89RkFMU0V9CmdncGxvdChhcGFydG1lbnRzLCBhZXMoeD1kaXN0cmljdCwgeT1wcmljZV9QTE4pKSArCiAgICBnZW9tX2JveHBsb3QoYWxwaGE9MC43KSArCiAgICBzdGF0X3N1bW1hcnkoZnVuPSJtZWFuIiwgZ2VvbT0icG9pbnQiLCBzaGFwZT0yMCwgc2l6ZT01LCBjb2xvcj0icmVkIiwgZmlsbD0icmVkIikgKwogZ2VvbV9qaXR0ZXIoKSArCiAgICBmYWNldF9ncmlkKH5idWlsZGluZ190eXBlKSArCiAgICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlPSJTZXQxIikKCmBgYAoKIyMjIFJhaW5DbG91ZCBQbG90CgpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQphcGFydG1lbnRzICU+JSAKICBmaWx0ZXIocm9vbXMgJWluJSBjKDEsIDIsIDMsIDQpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gZmFjdG9yKHJvb21zKSwgeSA9IHByaWNlX1BMTiwgZmlsbCA9IGZhY3Rvcihyb29tcykpKSArCiAgCiAgIyBhZGQgaGFsZi12aW9saW4gZnJvbSB7Z2dkaXN0fSBwYWNrYWdlCiAgc3RhdF9oYWxmZXllKAogICAgIyBhZGp1c3QgYmFuZHdpZHRoCiAgICBhZGp1c3QgPSAwLjUsCiAgICAjIG1vdmUgdG8gdGhlIHJpZ2h0CiAgICBqdXN0aWZpY2F0aW9uID0gLTAuMiwKICAgICMgcmVtb3ZlIHRoZSBzbHViIGludGVydmFsCiAgICAud2lkdGggPSAwLAogICAgcG9pbnRfY29sb3VyID0gTkEKICApICsKICBnZW9tX2JveHBsb3QoCiAgICB3aWR0aCA9IDAuMTIsCiAgICAjIHJlbW92aW5nIG91dGxpZXJzCiAgICBvdXRsaWVyLmNvbG9yID0gTkEsCiAgICBhbHBoYSA9IDAuNQogICkgKwogIHN0YXRfZG90cygKICAgICMgcGxvdGluZyBvbiBsZWZ0IHNpZGUKICAgIHNpZGUgPSAibGVmdCIsCiAgICAjIGFkanVzdGluZyBwb3NpdGlvbgogICAganVzdGlmaWNhdGlvbiA9IDEuMSwKICAgICMgYWRqdXN0IGdyb3VwaW5nIChiaW5uaW5nKSBvZiBvYnNlcnZhdGlvbnMKICAgIGJpbndpZHRoID0gMC4yNQogICkgKwojIFRoZW1lcyBhbmQgTGFiZWxzCiAgbGFicygKICAgIHRpdGxlID0gIlJhaW5DbG91ZCBQbG90IiwKICAgIHggPSAiTm8uIG9mIHJvb21zIiwKICAgIHkgPSAiUHJpY2VzIGluIFBMTiIsCiAgICBmaWxsID0gInJvb21zIgogICkgKwogIGNvb3JkX2ZsaXAoKQpgYGAKCiMjIyBGYWNldGluZwoKRmFjZXRpbmcgZ2VuZXJhdGVzIHNtYWxsIG11bHRpcGxlcywgZWFjaCBzaG93aW5nIGEgZGlmZmVyZW50IHN1YnNldCBvZgp0aGUgZGF0YS4gVGhleSBhcmUgYSBwb3dlcmZ1bCB0b29sIGZvciBleHBsb3JhdG9yeSBkYXRhIGFuYWx5c2lzOiB5b3UKY2FuIHF1aWNrbHkgY29tcGFyZSBwYXR0ZXJucyBpbiBkaWZmZXJlbnQgcGFydHMgb2YgdGhlIGRhdGEgYW5kIHNlZSBpZgp0aGV5IGFyZSB0aGUgc2FtZSBvciBkaWZmZXJlbnQuIFJlYWQgbW9yZQpbaGVyZV0oaHR0cHM6Ly9nZ3Bsb3QyLWJvb2sub3JnL2ZhY2V0Lmh0bWwpLgoKYGBge3IgZmFjZXQxLCBlY2hvPUZBTFNFfQpwbG90MSA8LSBnZ3Bsb3QoYXBhcnRtZW50cywgYWVzKHByaWNlX1BMTiwgcm9vbXMpKSArIAogIGdlb21fYWJsaW5lKCkgKwogIGdlb21faml0dGVyKHdpZHRoID0gMC4xLCBoZWlnaHQgPSAwLjEpIApwbG90MSArIGZhY2V0X3dyYXAofmRpc3RyaWN0KQpgYGAKCiMjIFVuaXZhcmlhdGUgU3RhdGlzdGljcwoKQmVmb3JlIGF1dG9tYXRpY2FsbHkgcmVwb3J0aW5nIHRoZSBmdWxsIHN1bW1hcnkgdGFibGUgb2YgZGVzY3JpcHRpdmUKc3RhdGlzdGljcywgdGhpcyB0aW1lIHlvdXIgZ29hbCBpcyB0byBtZWFzdXJlIHRoZSBjZW50cmFsIHRlbmRlbmN5IG9mCnRoZSBwcmljZSBkaXN0cmlidXRpb24uIENvbXBhcmUgdGhlIG1lYW4sIG1lZGlhbiwgYW5kIG1vZGUgYWxvbmcgd2l0aApwb3NpdGlvbmFsIG1lYXN1cmVzIC0gcXVhbnRpbGVzIC0gYnkgZGlzdHJpY3QgYW5kIGJ1aWxkaW5nIHR5cGUgb3IKbnVtYmVyIG9mIHJvb21zIGluIHRoZSBhcGFydG1lbnQuCgpgYGB7cn0KICAgIG1lYW4ocHJpY2VfUExOKQogICAgbWVkaWFuKHByaWNlX1BMTikKICAgIHNkKHByaWNlX1BMTikgI3N0YW5kYXJkIGRldmlhdGlvbgogICAgdmFyKHByaWNlX1BMTikgI3ZhcmlhbmNlCiAgICBjb2VmZl92YXI8LXNkKHByaWNlX1BMTikvbWVhbihwcmljZV9QTE4pICNjb2VmZmljaWVudCBvZiB2YXJpYWJpbGl0eSAlCiAgICBjb2VmZl92YXIKICAgIElRUihwcmljZV9QTE4pIyBkaWZmZXJlbmNlIGJldHdlZW4gcXVhcnRpbGVzID1RMy1RMSAKICAgIHN4PC1JUVIocHJpY2VfUExOKS8yICAjaW50ZXJxdWFydGlsZSBkZXZpYXRpb24KICAgIGNvZWZmX3Zhcng8LXN4L21lZGlhbihwcmljZV9QTE4pICNJUVIgY29lZmZpY2llbnQgb2YgdmFyaWFiaWxpdHkgJQogICAgY29lZmZfdmFyeAogICAgbWluKHByaWNlX1BMTikKICAgIG1heChwcmljZV9QTE4pCiAgICBxdWFudGlsZShwcmljZV9QTE4scHJvYnM9YygwLDAuMSwwLjI1LDAuNSwwLjc1LDAuOTUsMSksbmEucm09VFJVRSkKYGBgCgpPaywgd2UgaGF2ZSBjYWxjdWxhdGVkIGFsbCBvZiB0aGUgYmFzaWMgc3VtbWFyeSBzdGF0aXN0aWNzIGFib3ZlLiBMZXQncwp3cmFwIHRoZW0gdXAgdG9nZXRoZXIgbm93LgoKYGBge3Iga2FibGVfcmVwb3J0LCBlY2hvPUZBTFNFfQphcGFydG1lbnRzX2xpc3QgPC0gc3BsaXQoYXBhcnRtZW50cyRwcmljZV9QTE4sIGFwYXJ0bWVudHMkcm9vbXMpCmlubGluZV9wbG90IDwtIGRhdGEuZnJhbWUocm9vbXMgPSBjKDEsIDIsIDMsIDQpLCBib3hwbG90ID0gIiIsIGhpc3RvZ3JhbSA9ICIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmUxID0gIiIsIGxpbmUyID0gIiIsIHBvaW50czEgPSAiIikKaW5saW5lX3Bsb3QgJT4lCiAga2JsKGJvb2t0YWJzID0gVFJVRSkgJT4lCiAga2FibGVfcGFwZXIoZnVsbF93aWR0aCA9IEZBTFNFKSAlPiUKICBjb2x1bW5fc3BlYygyLCBpbWFnZSA9IHNwZWNfYm94cGxvdChhcGFydG1lbnRzX2xpc3QpKSAlPiUKICBjb2x1bW5fc3BlYygzLCBpbWFnZSA9IHNwZWNfaGlzdChhcGFydG1lbnRzX2xpc3QpKSAlPiUKICBjb2x1bW5fc3BlYyg0LCBpbWFnZSA9IHNwZWNfcGxvdChhcGFydG1lbnRzX2xpc3QsIHNhbWVfbGltID0gVFJVRSkpICU+JQogIGNvbHVtbl9zcGVjKDUsIGltYWdlID0gc3BlY19wbG90KGFwYXJ0bWVudHNfbGlzdCwgc2FtZV9saW0gPSBGQUxTRSkpICU+JQogIGNvbHVtbl9zcGVjKDYsIGltYWdlID0gc3BlY19wbG90KGFwYXJ0bWVudHNfbGlzdCwgdHlwZSA9ICJwIikpCgpgYGAKCiMjIyBTdW1tYXJ5IHRhYmxlcwoKT2ssIG5vdyB3ZSB3aWxsIGZpbmFsbHkgc3VtbWFyaXplIHRoZSBiYXNpYyBtZWFzdXJlcyBvZiBjZW50cmFsIHRlbmRlbmN5CmZvciBwcmljZXMgYnkgZGlzdHJpY3QvYnVpbGRpbmcgdHlwZSB1c2luZyB0aGUgJyoqKmthYmxlKioqJyBwYWNrYWdlLgpGZWVsIGZyZWUgdG8gY3VzdG9taXplIHlvdXIgZmluYWwgcmVwb3J0LiBTZWUgc29tZSBoaW50cwpbaGVyZV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3F3cmFwczIvdmlnbmV0dGVzL3N1bW1hcnktc3RhdGlzdGljcy5odG1sKS4KCmBgYHtyIGthYmxlX3JlcG9ydDIsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnJhcG9ydCA8LQogIGxpc3QoIlByaWNlIGluIFBMTiIgPQogICAgICAgbGlzdCgiTWluIiAgICAgICA9IH4gbWluKHByaWNlX1BMTiksCiAgICAgICAgICAgICJNYXgiICAgICAgID0gfiBtYXgocHJpY2VfUExOKSwKICAgICAgICAgICAgIlExIiAgICAgICAgPSB+IHF1YW50aWxlKHByaWNlX1BMTiwwLjI1KSwKICAgICAgICAgICAgIk1lZGlhbiIgPSB+IHJvdW5kKG1lZGlhbihwcmljZV9QTE4pLDIpLAogICAgICAgICAgICAiUTMiICAgICAgICA9IH4gcXVhbnRpbGUocHJpY2VfUExOLDAuNzUpLAogICAgICAgICAgICAiTWVhbiIgPSB+IHJvdW5kKG1lYW4ocHJpY2VfUExOKSwyKSwKICAgICAgICAgICAgIlNkIiA9IH4gcm91bmQoc2QocHJpY2VfUExOKSwyKSwKICAgICAgICAgICAgICJJUVIiID0gfiByb3VuZChpcXIocHJpY2VfUExOKSwyKSwKICAgICAgICAgICAgIlN4IiA9IH4gcm91bmQoaXFyKHByaWNlX1BMTikvMiwyKSwKICAgICAgICAgICAgIlZhciAlIiA9IH4gcm91bmQoKHNkKHByaWNlX1BMTikvbWVhbihwcmljZV9QTE4pKSwyKSwKICAgICAgICAgICAgIklRUiBWYXIgJSIgPSB+IHJvdW5kKChpcXIocHJpY2VfUExOKS9tZWRpYW4ocHJpY2VfUExOKSksMiksCiAgICAgICAgICAgICJTa2V3bmVzcyIgPSB+ICByb3VuZChza2V3KHByaWNlX1BMTiksMiksCiAgICAgICAgICAgICAiS3VydG9zaXMiID0gfiAgcm91bmQoa3VydG9zaShwcmljZV9QTE4pLDIpCiAgICAgICAgICAgICkpCnRhYmVsYTwtc3VtbWFyeV90YWJsZShhcGFydG1lbnRzLCBzdW1tYXJpZXMgPSByYXBvcnQsIGJ5ID0gYygicm9vbXMiKSkKCiNrYmwodGFiZWxhLCAgZGlnaXRzID0gMiwKIyAgY2FwdGlvbj0iVGFibGUgMS4gQXBhcnRtZW50cyBpbiBXcm9jbGF3IC0gcHJpY2VzIGluIFBMTiBieSBudW1iZXIgb2Ygcm9vbXMuIiwgIGNvbC5uYW1lcyA9IGMoJzEgcm9vbScsICcyIHJvb21zJywgJzMgcm9vbXMnLCAnNCByb29tcycpKSAlPiUga2FibGVfY2xhc3NpYyhmdWxsX3dpZHRoID0gRiwgaHRtbF9mb250ID0gIkNhbWJyaWEiKSU+JSBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIpKQpgYGAKCiMjIyBndHN1bW1hcnkKCldlIGNhbiBjYWxjdWxhdGUgZWFzaWx5IGRlc2NyaXB0aXZlIHN0YXRpc3RpY3MgYWxzbyB1c2luZyBndHN1bW1hcnkKcGFja2FnZToKCmBgYHtyfQphcGFydG1lbnRzICU+JQogIHNlbGVjdChwcmljZV9QTE4scm9vbXMpICU+JQogIHRibF9zdW1tYXJ5KGxhYmVsPSBwcmljZV9QTE4gfiAiUHJpY2UiLGRpZ2l0cz1jKHByaWNlX1BMTil+MixieT1yb29tcyx0eXBlID0gYWxsX2NvbnRpbnVvdXMoKSB+ICJjb250aW51b3VzMiIsIHN0YXRpc3RpYyA9IGFsbF9jb250aW51b3VzKCkgfiBjKCJ7Tl9ub25taXNzfSIsICJ7bWVkaWFufSAoe3AyNX0sIHtwNzV9KSIsICJ7bWlufSwge21heH0iKSxtaXNzaW5nID0gIm5vIikKYGBgCgojIyMgZGZTdW1tYXJ5CgpkZlN1bW1hcnkoKSBjcmVhdGVzIGEgc3VtbWFyeSB0YWJsZSB3aXRoIHN0YXRpc3RpY3MsIGZyZXF1ZW5jaWVzIGFuZApncmFwaHMgZm9yIGFsbCB2YXJpYWJsZXMgaW4gYSBkYXRhIGZyYW1lLiBUaGUgaW5mb3JtYXRpb24gZGlzcGxheWVkIGlzCnR5cGUtc3BlY2lmaWMgKGNoYXJhY3RlciwgZmFjdG9yLCBudW1lcmljLCBkYXRlKSBhbmQgYWxzbyB2YXJpZXMKYWNjb3JkaW5nIHRvIHRoZSBudW1iZXIgb2YgZGlzdGluY3QgdmFsdWVzLgoKV2hlbiB1c2luZyBkZlN1bW1hcnkoKSBpbiBSIE1hcmtkb3duIGRvY3VtZW50cywgaXQgaXMgZ2VuZXJhbGx5IGEgZ29vZAppZGVhIHRvIGV4Y2x1ZGUgYSBjb2x1bW4gb3IgdHdvIHRvIGF2b2lkIG1hcmdpbiBvdmVyZmxvdy4gU2luY2UgdGhlClZhbGlkIGFuZCBNaXNzaW5nIGNvbHVtbnMgYXJlIHJlZHVuZGFudCwgd2UgY2FuIGRyb3AgZWl0aGVyIG9uZSBvZiB0aGVtLgoKYGBge3Igd2FybmluZz1GQUxTRSwgcmVzdWx0cz0iYXNpcyJ9CmRmU3VtbWFyeShhcGFydG1lbnRzLAogICAgICAgICAgcGxhaW4uYXNjaWkgID0gRkFMU0UsIAogICAgICAgICAgc3R5bGUgICAgICAgID0gImdyaWQiLCAKICAgICAgICAgIGdyYXBoLm1hZ25pZiA9IDAuNzUsIAogICAgICAgICAgdmFsaWQuY29sICAgID0gRkFMU0UsCiAgICAgICAgICB0bXAuaW1nLmRpciAgPSAiL3RtcCIpCmBgYAoKVG8gcHJvZHVjZSBvcHRpbWFsIHJlc3VsdHMsIHN1bW1hcnl0b29scyBoYXMgaXRzIG93biB2ZXJzaW9uIG9mIHRoZSBiYXNlCmJ5KCkgZnVuY3Rpb24uIEl0J3MgY2FsbGVkIHN0YnkoKSwgYW5kIHdlIHVzZSBpdCBleGFjdGx5IGFzIHdlIHdvdWxkCmJ5KCk6CgpgYGB7ciByZXN1bHRzPSJhc2lzIiwgd2FybmluZz1GQUxTRX0KKHN0YXRzX2J5X3Jvb21zIDwtIHN0YnkoZGF0YSAgICAgID0gYXBhcnRtZW50cywgSU5ESUNFUyAgID0gYXBhcnRtZW50cyRyb29tcywgRlVOICAgICAgID0gZGVzY3IsIHN0YXRzICAgICA9ICJjb21tb24iLCB0cmFuc3Bvc2UgPSBUUlVFKSkKYGBgCgojIyMgVGlkeSBUYWJsZXMKCldoZW4gZ2VuZXJhdGluZyBmcmVxKCkgb3IgZGVzY3IoKSB0YWJsZXMsIGl0IGlzIHBvc3NpYmxlIHRvIHR1cm4gdGhlCnJlc3VsdHMgaW50byAidGlkeSIgdGFibGVzIHdpdGggdGhlIHVzZSBvZiB0aGUgdGIoKSBmdW5jdGlvbiAodGhpbmsgb2YKdGIgYXMgYSBkaW1pbnV0aXZlIGZvciB0aWJibGUpLiBGb3IgZXhhbXBsZToKCmBgYHtyfQphcGFydG1lbnRzICU+JQogIGRlc2NyKHN0YXRzID0gImNvbW1vbiIpICU+JQogIHRiKCkKYGBgCgpIZXJlIGFyZSBzb21lIGV4YW1wbGVzIHNob3dpbmcgaG93IGxpc3RzIGNyZWF0ZWQgdXNpbmcgc3RieSgpIG9yCmdyb3VwX2J5KCkgY2FuIGJlIHRyYW5zZm9ybWVkIGludG8gdGlkeSB0aWJibGVzLgoKYGBge3J9Cmdyb3VwZWRfZGVzY3IgPC0gc3RieShkYXRhICAgID0gYXBhcnRtZW50cyxJTkRJQ0VTID0gYXBhcnRtZW50cyRyb29tcywgRlVOICAgICA9IGRlc2NyLCBzdGF0cyAgID0gImNvbW1vbiIpCgpncm91cGVkX2Rlc2NyICU+JSB0YigpCmBgYAoKIyMjIEEgQnJpZGdlIHRvIE90aGVyIFBhY2thZ2VzCgpgYGB7cn0Kc3RieShkYXRhICAgID0gYXBhcnRtZW50cywgCiAgICAgSU5ESUNFUyA9IGFwYXJ0bWVudHMkcm9vbXMsIAogICAgIEZVTiAgICAgPSBkZXNjciwgCiAgICAgc3RhdHMgICA9ICJmaXZlbnVtIikgJT4lCiAgdGIob3JkZXIgPSAzKSAlPiUKICBrYWJsZShmb3JtYXQgPSAiaHRtbCIsIGRpZ2l0cyA9IDIpICU+JQogIGNvbGxhcHNlX3Jvd3MoY29sdW1ucyA9IDEsIHZhbGlnbiA9ICJ0b3AiKQpgYGAKCiMjIFlvdXIgdHVybiEKCllvdXIgdGFzayB0aGlzIHdlZWsgaXMgdG86IHByZXBhcmUgeW91ciBvd24gZGVzY3JpcHRpdmUgYW5hbHlzaXMgZm9yIHRoZQoiQ3JlZGl0Q2FyZCIgZGF0YXNldCAoQUVSIHBhY2thZ2UpLiBJdCBpcyBhIGNyb3NzLXNlY3Rpb25hbCBkYXRhZnJhbWUgb24KdGhlIGNyZWRpdCBoaXN0b3J5IGZvciBhIHNhbXBsZSBvZiBhcHBsaWNhbnRzIGZvciBhIHR5cGUgb2YgY3JlZGl0IGNhcmQuCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQpkYXRhKENyZWRpdENhcmQpCiM/Q3JlZGl0Q2FyZCAgcmVhZCBkZXNjcmlwdGlvbiBmaXJzdApgYGAKCkFyZSB0aGUgeWVhcmx5IGluY29tZXMgKGluIFVTRCAxMCwwMDApLCBjcmVkaXQgY2FyZCBleHBlbmRpdHVyZXMsIGFnZSwKcmF0aW8gb2YgbW9udGhseSBjcmVkaXQgY2FyZCBleHBlbmRpdHVyZSB0byB5ZWFybHkgaW5jb21lIC0Kc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgZm9yIGFwcGxpY2FudHMgZm9yIGN1c3RvbWVycyB3aXRoIGRpZmZlcmVudApjcmVkaXQgcmlzayAoImNhcmQiIHZhcmlhYmxlIC0gZmFjdG9yKT8KClByZXBhcmUgYSBwcm9mZXNzaW9uYWwgZGF0YSB2aXN1YWxpemF0aW9ucywgZGVzY3JpcHRpdmUgc3RhdGlzdGljcycKdGFibGVzIGFuZCBpbnRlcnByZXQgdGhlbS4KCiMjIFByZXByb2Nlc3NpbmcKCmBgYHtyfQphdHRhY2goQ3JlZGl0Q2FyZCkKQ3JlZGl0Q2FyZCRleHBlbmRpdHVyZTwtYXMubnVtZXJpYyhDcmVkaXRDYXJkJGV4cGVuZGl0dXJlKQpgYGAKCiMjIEZyZXF1ZW5jeSBUYWJsZQoKYGBge3IgbXlfc3VtbWFyeV90YWJsZX0KCnRhYmxlPC1jKCIwLTMwMCBQTE4iLCAiMzAwLTYwMCBQTE4iLCI2MDAtOTAwIFBMTiIsIjkwMC0xMjAwIFBMTiIsIjEyMDAtMTUwMCBQTE4iLCIxNTAwLTE4MDAgUExOIiwiMTgwMC0yMTAwIFBMTiIsIjIxMDAtMjQwMCBQTE4iLCIyNDAwLTI3MDAgUExOIiwiMjcwMC0zMDAwIFBMTiIsICIzMDAwLTMzMDAgUExOIikKbGltaXRzPC1jdXQoQ3JlZGl0Q2FyZCRleHBlbmRpdHVyZSxzZXEoMCwzMzAwLGJ5PTMwMCksbGFiZWxzPXRhYmxlKQp0YWJsZTE8LWZyZXEobGltaXRzLCB0eXBlPSJodG1sIikKCmtibCh0YWJsZTEsY2FwdGlvbiA9ICJFeHBlbmRpdHVyZXMiKSAlPiUKICAgIGthYmxlX21hdGVyaWFsKGMoInN0cmlwZWQiLCAiaG92ZXIiKSkKdGFiMTwtY2xhc3NJbnRlcnZhbHMoQ3JlZGl0Q2FyZCRleHBlbmRpdHVyZSxuPTExLHN0eWxlPSJmaXhlZCIsZml4ZWRCcmVha3M9c2VxKDAsMzMwMCxieT0zMDApKQpqZW5rcy50ZXN0cyh0YWIxKQoKYGBgCiMjIFBsb3QKCmBgYHtyfQoKIyBEZWZpbmUgdGhlIGFnZSBncm91cHMKYWdlX2dyb3VwcyA8LSBjKCIwIC0gMTAiLCAiMTAgLSAyMCIsICIyMCAtIDMwIiwgIjMwIC0gNDAiLCAiNDAgLSA1MCIsICI1MCAtIDYwIiwgIjYwIC0gNzAiLCAiNzAgLSA4MCIsICI4MCAtIDkwIikKCiMgQ3JlYXRlIGEgbmV3IGNvbHVtbiAnYWdlX2dyb3VwJyBiYXNlZCBvbiB0aGUgc3BlY2lmaWVkIHJhbmdlcwpDcmVkaXRDYXJkJGFnZV9ncm91cCA8LSBjdXQoQ3JlZGl0Q2FyZCRhZ2UsIGJyZWFrcyA9IGMoMCwgMTAsIDIwLCAzMCwgNDAsIDUwLCA2MCwgNzAsIDgwLCA5MCksIGxhYmVscyA9IGFnZV9ncm91cHMsIGluY2x1ZGUubG93ZXN0ID0gVFJVRSkKCiMgQ2FsY3VsYXRlIGF2ZXJhZ2UgZXhwZW5kaXR1cmVzIGZvciBlYWNoIGFnZSBncm91cAphdmdfZXhwZW5kaXR1cmVzIDwtIGFnZ3JlZ2F0ZShleHBlbmRpdHVyZSB+IGFnZV9ncm91cCwgZGF0YSA9IENyZWRpdENhcmQsIEZVTiA9IG1lYW4pCgojIEJhciBwbG90IG9mIGF2ZXJhZ2UgZXhwZW5kaXR1cmVzIGJ5IGFnZSBncm91cApnZ3Bsb3QoYXZnX2V4cGVuZGl0dXJlcywgYWVzKHggPSBhZ2VfZ3JvdXAsIHkgPSBleHBlbmRpdHVyZSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJza3libHVlIiwgY29sb3IgPSAiYmxhY2siKSArCiAgbGFicyh0aXRsZSA9ICJBdmVyYWdlIEV4cGVuZGl0dXJlcyBieSBBZ2UgR3JvdXAiLCB4ID0gIkFnZSBHcm91cCIsIHkgPSAiQXZlcmFnZSBFeHBlbmRpdHVyZXMiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQoKYGBgCmBgYHtyfQogICAgbWVhbihleHBlbmRpdHVyZSkKICAgIG1lZGlhbihleHBlbmRpdHVyZSkKICAgIHNkKGV4cGVuZGl0dXJlKSAjc3RhbmRhcmQgZGV2aWF0aW9uCiAgICB2YXIoZXhwZW5kaXR1cmUpICN2YXJpYW5jZQogICAgY29lZmZfdmFyPC1zZChleHBlbmRpdHVyZSkvbWVhbihleHBlbmRpdHVyZSkgI2NvZWZmaWNpZW50IG9mIHZhcmlhYmlsaXR5ICUKICAgIGNvZWZmX3ZhcgogICAgSVFSKGV4cGVuZGl0dXJlKSMgZGlmZmVyZW5jZSBiZXR3ZWVuIHF1YXJ0aWxlcyA9UTMtUTEgCiAgICBzeDwtSVFSKGV4cGVuZGl0dXJlKS8yICAjaW50ZXJxdWFydGlsZSBkZXZpYXRpb24KICAgIGNvZWZmX3Zhcng8LXN4L21lZGlhbihleHBlbmRpdHVyZSkgI0lRUiBjb2VmZmljaWVudCBvZiB2YXJpYWJpbGl0eSAlCiAgICBjb2VmZl92YXJ4CiAgICBtaW4oZXhwZW5kaXR1cmUpCiAgICBtYXgoZXhwZW5kaXR1cmUpCiAgICBxdWFudGlsZShleHBlbmRpdHVyZSxwcm9icz1jKDAsMC4xLDAuMjUsMC41LDAuNzUsMC45NSwxKSxuYS5ybT1UUlVFKQogICAgCiAgICAKICAgIGV4cGVuZGl0dXJlX2xpc3QgPC0gc3BsaXQoQ3JlZGl0Q2FyZCRleHBlbmRpdHVyZSwgQ3JlZGl0Q2FyZCRhZ2VfZ3JvdXApCmlubGluZV9wbG90IDwtIGRhdGEuZnJhbWUoYWdlX2dyb3VwcyA9IGMoIjAgLSAxMCIsICIxMCAtIDIwIiwgIjIwIC0gMzAiLCAiMzAgLSA0MCIsICI0MCAtIDUwIiwgIjUwIC0gNjAiLCAiNjAgLSA3MCIsICI3MCAtIDgwIiwgIjgwIC0gOTAiKSwgYm94cGxvdCA9ICIiLCBoaXN0b2dyYW0gPSAiIiwgbGluZTEgPSAiIiwgbGluZTIgPSAiIiwgcG9pbnRzMSA9ICIiKQppbmxpbmVfcGxvdCAlPiUKICAKICBrYmwoYm9va3RhYnMgPSBUUlVFKSAlPiUKICBrYWJsZV9wYXBlcihmdWxsX3dpZHRoID0gRkFMU0UpICU+JQogIGNvbHVtbl9zcGVjKDIsIGltYWdlID0gc3BlY19ib3hwbG90KGV4cGVuZGl0dXJlX2xpc3QpKSAlPiUKICBjb2x1bW5fc3BlYygzLCBpbWFnZSA9IHNwZWNfaGlzdChleHBlbmRpdHVyZV9saXN0KSkgJT4lCiAgY29sdW1uX3NwZWMoNCwgaW1hZ2UgPSBzcGVjX3Bsb3QoZXhwZW5kaXR1cmVfbGlzdCwgc2FtZV9saW0gPSBUUlVFKSkgJT4lCiAgY29sdW1uX3NwZWMoNSwgaW1hZ2UgPSBzcGVjX3Bsb3QoZXhwZW5kaXR1cmVfbGlzdCwgc2FtZV9saW0gPSBGQUxTRSkpICU+JQogIGNvbHVtbl9zcGVjKDYsIGltYWdlID0gc3BlY19wbG90KGV4cGVuZGl0dXJlX2xpc3QsIHR5cGUgPSAicCIpKQoKYGBgCgoKYGBge3J9CiMgQ2FsY3VsYXRlIHRvdGFsIHllYXJseSBjcmVkaXQgY2FyZCBleHBlbmRpdHVyZQpDcmVkaXRDYXJkJHRvdGFsX2V4cGVuZGl0dXJlIDwtIENyZWRpdENhcmQkZXhwZW5kaXR1cmUgKiAxMgoKIyBDYWxjdWxhdGUgcmF0aW8gb2YgdG90YWwgeWVhcmx5IGNyZWRpdCBjYXJkIGV4cGVuZGl0dXJlIHRvIHllYXJseSBpbmNvbWUKQ3JlZGl0Q2FyZCRyYXRpbyA8LSBDcmVkaXRDYXJkJHRvdGFsX2V4cGVuZGl0dXJlIC8gQ3JlZGl0Q2FyZCRpbmNvbWUKCiMgR3JvdXAgYnkgY3JlZGl0IHJpc2sgKGNhcmQpIGFuZCBjYWxjdWxhdGUgbWVhbiByYXRpbwpyYXRpb19ieV9jYXJkIDwtIENyZWRpdENhcmQgJT4lCiAgZ3JvdXBfYnkoY2FyZCkgJT4lCiAgc3VtbWFyaXNlKG1lYW5fcmF0aW8gPSBtZWFuKHJhdGlvKSkKCiMgUHJpbnQgdGhlIHJlc3VsdApwcmludChyYXRpb19ieV9jYXJkKQpgYGAKCgpGcm9tIHRoZSBib3hwbG90cywgd2Ugb2JzZXJ2ZSB0aGF0IHRoZXJlIGFyZSB2YXJpYXRpb25zIGluIHllYXJseSBpbmNvbWVzLCBjcmVkaXQgY2FyZCBleHBlbmRpdHVyZXMsIGFnZSwgYW5kIHRoZSByYXRpbyBvZiBtb250aGx5IGNyZWRpdCBjYXJkIGV4cGVuZGl0dXJlIHRvIHllYXJseSBpbmNvbWUgYWNyb3NzIGRpZmZlcmVudCBjcmVkaXQgcmlzayBjYXRlZ29yaWVzLgoKYGBge3J9CiMgRGVzY3JpcHRpdmUgYW5hbHlzaXMgYW5kIHZpc3VhbGl6YXRpb24KIyBCb3hwbG90IGZvciB5ZWFybHkgaW5jb21lcyBieSBjcmVkaXQgcmlzawpnZ3Bsb3QoQ3JlZGl0Q2FyZCwgYWVzKHggPSBjYXJkLCB5ID0gaW5jb21lKSkgKwogIGdlb21fYm94cGxvdChmaWxsID0gInNreWJsdWUiLCBjb2xvciA9ICJibHVlIikgKwogIGxhYnMoeCA9ICJDcmVkaXQgUmlzayIsIHkgPSAiWWVhcmx5IEluY29tZSAoaW4gVVNEIDEwLDAwMCkiLCB0aXRsZSA9ICJZZWFybHkgSW5jb21lcyBieSBDcmVkaXQgUmlzayIpCgojIEJveHBsb3QgZm9yIGNyZWRpdCBjYXJkIGV4cGVuZGl0dXJlcyBieSBjcmVkaXQgcmlzawpnZ3Bsb3QoQ3JlZGl0Q2FyZCwgYWVzKHggPSBjYXJkLCB5ID0gZXhwZW5kaXR1cmUpKSArCiAgZ2VvbV9ib3hwbG90KGZpbGwgPSAibGlnaHRncmVlbiIsIGNvbG9yID0gImRhcmtncmVlbiIpICsKICBsYWJzKHggPSAiQ3JlZGl0IFJpc2siLCB5ID0gIkNyZWRpdCBDYXJkIEV4cGVuZGl0dXJlIiwgdGl0bGUgPSAiQ3JlZGl0IENhcmQgRXhwZW5kaXR1cmVzIGJ5IENyZWRpdCBSaXNrIikKCiMgQm94cGxvdCBmb3IgYWdlIGJ5IGNyZWRpdCByaXNrCmdncGxvdChDcmVkaXRDYXJkLCBhZXMoeCA9IGNhcmQsIHkgPSBhZ2UpKSArCiAgZ2VvbV9ib3hwbG90KGZpbGwgPSAibGlnaHRjb3JhbCIsIGNvbG9yID0gImRhcmtyZWQiKSArCiAgbGFicyh4ID0gIkNyZWRpdCBSaXNrIiwgeSA9ICJBZ2UiLCB0aXRsZSA9ICJBZ2UgYnkgQ3JlZGl0IFJpc2siKQoKIyBCb3hwbG90IGZvciByYXRpbyBvZiBtb250aGx5IGNyZWRpdCBjYXJkIGV4cGVuZGl0dXJlIHRvIHllYXJseSBpbmNvbWUgYnkgY3JlZGl0IHJpc2sKZ2dwbG90KENyZWRpdENhcmQsIGFlcyh4ID0gY2FyZCwgeSA9IHJhdGlvKSkgKwogIGdlb21fYm94cGxvdChmaWxsID0gImxpZ2h0eWVsbG93IiwgY29sb3IgPSAiZGFya29yYW5nZSIpICsKICBsYWJzKHggPSAiQ3JlZGl0IFJpc2siLCB5ID0gIlJhdGlvIG9mIE1vbnRobHkgRXhwZW5kaXR1cmUgdG8gWWVhcmx5IEluY29tZSIsIHRpdGxlID0gIlJhdGlvIGJ5IENyZWRpdCBSaXNrIikKCmBgYAoKCmBgYHtyfQojIERlc2NyaXB0aXZlIHN0YXRpc3RpY3MgdGFibGUgZm9yIHllYXJseSBpbmNvbWVzIGJ5IGNyZWRpdCByaXNrCnllYXJseV9pbmNvbWVfc3VtbWFyeSA8LSBDcmVkaXRDYXJkICU+JQogIGdyb3VwX2J5KGNhcmQpICU+JQogIHN1bW1hcmlzZShtZWFuX2luY29tZSA9IG1lYW4oaW5jb21lKSwKICAgICAgICAgICAgbWVkaWFuX2luY29tZSA9IG1lZGlhbihpbmNvbWUpLAogICAgICAgICAgICBzZF9pbmNvbWUgPSBzZChpbmNvbWUpLAogICAgICAgICAgICBtaW5faW5jb21lID0gbWluKGluY29tZSksCiAgICAgICAgICAgIG1heF9pbmNvbWUgPSBtYXgoaW5jb21lKSkKCiMgRGVzY3JpcHRpdmUgc3RhdGlzdGljcyB0YWJsZSBmb3IgY3JlZGl0IGNhcmQgZXhwZW5kaXR1cmVzIGJ5IGNyZWRpdCByaXNrCmV4cGVuZGl0dXJlX3N1bW1hcnkgPC0gQ3JlZGl0Q2FyZCAlPiUKICBncm91cF9ieShjYXJkKSAlPiUKICBzdW1tYXJpc2UobWVhbl9leHBlbmRpdHVyZSA9IG1lYW4oZXhwZW5kaXR1cmUpLAogICAgICAgICAgICBtZWRpYW5fZXhwZW5kaXR1cmUgPSBtZWRpYW4oZXhwZW5kaXR1cmUpLAogICAgICAgICAgICBzZF9leHBlbmRpdHVyZSA9IHNkKGV4cGVuZGl0dXJlKSwKICAgICAgICAgICAgbWluX2V4cGVuZGl0dXJlID0gbWluKGV4cGVuZGl0dXJlKSwKICAgICAgICAgICAgbWF4X2V4cGVuZGl0dXJlID0gbWF4KGV4cGVuZGl0dXJlKSkKCiMgRGVzY3JpcHRpdmUgc3RhdGlzdGljcyB0YWJsZSBmb3IgYWdlIGJ5IGNyZWRpdCByaXNrCmFnZV9zdW1tYXJ5IDwtIENyZWRpdENhcmQgJT4lCiAgZ3JvdXBfYnkoY2FyZCkgJT4lCiAgc3VtbWFyaXNlKG1lYW5fYWdlID0gbWVhbihhZ2UpLAogICAgICAgICAgICBtZWRpYW5fYWdlID0gbWVkaWFuKGFnZSksCiAgICAgICAgICAgIHNkX2FnZSA9IHNkKGFnZSksCiAgICAgICAgICAgIG1pbl9hZ2UgPSBtaW4oYWdlKSwKICAgICAgICAgICAgbWF4X2FnZSA9IG1heChhZ2UpKQoKIyBEZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIHRhYmxlIGZvciByYXRpbyBvZiBtb250aGx5IGNyZWRpdCBjYXJkIGV4cGVuZGl0dXJlIHRvIHllYXJseSBpbmNvbWUgYnkgY3JlZGl0IHJpc2sKcmF0aW9fc3VtbWFyeSA8LSBDcmVkaXRDYXJkICU+JQogIGdyb3VwX2J5KGNhcmQpICU+JQogIHN1bW1hcmlzZShtZWFuX3JhdGlvID0gbWVhbihyYXRpbyksCiAgICAgICAgICAgIG1lZGlhbl9yYXRpbyA9IG1lZGlhbihyYXRpbyksCiAgICAgICAgICAgIHNkX3JhdGlvID0gc2QocmF0aW8pLAogICAgICAgICAgICBtaW5fcmF0aW8gPSBtaW4ocmF0aW8pLAogICAgICAgICAgICBtYXhfcmF0aW8gPSBtYXgocmF0aW8pKQoKIyBQcmludCBkZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIHRhYmxlcwpwcmludCgiRGVzY3JpcHRpdmUgU3RhdGlzdGljcyBmb3IgWWVhcmx5IEluY29tZXMgYnkgQ3JlZGl0IFJpc2s6IikKcHJpbnQoeWVhcmx5X2luY29tZV9zdW1tYXJ5KQoKcHJpbnQoIkRlc2NyaXB0aXZlIFN0YXRpc3RpY3MgZm9yIENyZWRpdCBDYXJkIEV4cGVuZGl0dXJlcyBieSBDcmVkaXQgUmlzazoiKQpwcmludChleHBlbmRpdHVyZV9zdW1tYXJ5KQoKcHJpbnQoIkRlc2NyaXB0aXZlIFN0YXRpc3RpY3MgZm9yIEFnZSBieSBDcmVkaXQgUmlzazoiKQpwcmludChhZ2Vfc3VtbWFyeSkKCnByaW50KCJEZXNjcmlwdGl2ZSBTdGF0aXN0aWNzIGZvciBSYXRpbyBvZiBNb250aGx5IEV4cGVuZGl0dXJlIHRvIFllYXJseSBJbmNvbWUgYnkgQ3JlZGl0IFJpc2s6IikKcHJpbnQocmF0aW9fc3VtbWFyeSkKYGBg