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 .
Table 1. Apartments in Wroclaw - prices in PLN by number of rooms.
1 room
2 rooms
3 rooms
4 rooms
Min
359769
590286
632770
736669
Max
657146
888634
965829
1277691
Q1
479684.75
634757.25
769683.75
909371.5
Median
520507
677260
846303.5
964338.5
Q3
555024.75
717728.5
901078.75
1050976.75
Mean
515518.05
683567.7
833706.02
974809.96
Sd
66951.03
65072.66
86943.9
113819.21
IQR
75340
82971.25
131395
141605.25
Sx
37670
41485.62
65697.5
70802.62
Var %
0.13
0.1
0.1
0.12
IQR Var %
0.14
0.12
0.16
0.15
Skewness
-0.2
0.8
-0.42
0.33
Kurtosis
-0.38
0.48
-0.83
0.05
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.
FREQUENCY TABLES
Income in kPLN
x
label
Freq
Percent
Valid Percent
Cumulative Percent
Valid
0-10 kUSD
2
0.2
0.2
0.2
10-20 kUSD
233
17.7
17.7
17.9
20-30 kUSD
498
37.8
37.8
55.7
30-40 kUSD
284
21.6
21.6
77.3
40-50 kUSD
134
10.2
10.2
87.5
50-60 kUSD
71
5.4
5.4
92.9
60-70 kUSD
42
3.2
3.2
96.0
70-80 kUSD
20
1.5
1.5
97.6
80-90 kUSD
10
0.8
0.8
98.3
90-100 kUSD
13
1.0
1.0
99.3
100-110 kUSD
6
0.5
0.5
99.8
110-120 kUSD
1
0.1
0.1
99.8
120-130 kUSD
1
0.1
0.1
99.9
130-140 kUSD
1
0.1
0.1
100.0
Total
1316
100.0
100.0
Missing
<blank>
0
0.0
<NA>
0
0.0
Total
1316
100.0
## # classes Goodness of fit Tabular accuracy
## 14.0000000 0.9740158 0.8105061
Expenditure
x
label
Freq
Percent
Valid Percent
Cumulative Percent
Valid
0-100
337
25.6
34.4
34.4
100-200
261
19.8
26.6
61.0
200-300
126
9.6
12.9
73.9
300-400
97
7.4
9.9
83.8
400-500
70
5.3
7.1
90.9
500-600
32
2.4
3.3
94.2
600-700
25
1.9
2.6
96.7
700-800
11
0.8
1.1
97.9
800-900
16
1.2
1.6
99.5
900-1000
5
0.4
0.5
100.0
Total
980
74.5
100.0
Missing
<blank>
0
0.0
<NA>
336
25.5
Total
1316
100.0
## Warning in classIntervals(CreditCard$expenditure, n = 11, style = "fixed", :
## variable range greater than fixedBreaks
## # classes Goodness of fit Tabular accuracy
## 11.0000000 0.9362416 0.8181726
Age
x
label
Freq
Percent
Valid Percent
Cumulative Percent
Valid
0-10
7
0.5
0.5
0.5
10-20
22
1.7
1.7
2.2
20-30
562
42.7
42.7
44.9
30-40
422
32.1
32.1
77.0
40-50
219
16.6
16.6
93.6
50-60
61
4.6
4.6
98.3
60-70
19
1.4
1.4
99.7
70-80
2
0.2
0.2
99.8
80-90
2
0.2
0.2
100.0
Total
1316
100.0
100.0
Missing
<blank>
0
0.0
<NA>
0
0.0
Total
1316
100.0
## # classes Goodness of fit Tabular accuracy
## 9.0000000 0.9296600 0.7164709
Ratio of monthly expenditure to yearly income
x
label
Freq
Percent
Valid Percent
Cumulative Percent
Valid
0-0.002
929
70.6
92.8
92.8
0.002-0.004
42
3.2
4.2
97.0
0.004-0.006
12
0.9
1.2
98.2
0.006-0.008
6
0.5
0.6
98.8
0.008-0.01
5
0.4
0.5
99.3
0.01-0.012
2
0.2
0.2
99.5
0.012-0.014
2
0.2
0.2
99.7
0.016-0.018
1
0.1
0.1
99.8
0.018-0.02
1
0.1
0.1
99.9
0.024-0.026
1
0.1
0.1
100.0
Total
1001
76.1
100.0
Missing
<blank>
0
0.0
<NA>
315
23.9
Total
1316
100.0
## # classes Goodness of fit Tabular accuracy
## 13.0000000 0.9393423 0.5948975
PLOTS
#income
mean(CreditCard$income)
## [1] 3.363549
median(CreditCard$income)
## [1] 2.9
sd(CreditCard$income) #standard deviation
## [1] 1.692444
var(CreditCard$income) #variance
## [1] 2.864368
coeff_var<-sd(CreditCard$income)/mean(CreditCard$income) #coefficient of variability %
coeff_var
## [1] 0.5031722
IQR(CreditCard$income)# difference between quartiles =Q3-Q1
## 75%
## 1.753125
sx<-IQR(CreditCard$income)/2 #interquartile deviation
coeff_varx<-sx/median(CreditCard$income) #IQR coefficient of variability %
coeff_varx
## 75%
## 0.3022629
min(CreditCard$income)
## [1] 0.21
max(CreditCard$income)
## [1] 13.5
quantile(CreditCard$income,probs=c(0,0.1,0.25,0.5,0.75,0.95,1),na.rm=TRUE)
## 0% 10% 25% 50% 75% 95% 100%
## 0.210000 1.800000 2.246875 2.900000 4.000000 6.891000 13.500000
#expenditure
mean(CreditCard$expenditure)
## [1] 184.9889
median(CreditCard$expenditure)
## [1] 101.3963
sd(CreditCard$expenditure) #standard deviation
## [1] 272.1385
var(CreditCard$expenditure) #variance
## [1] 74059.35
coeff_var<-sd(CreditCard$expenditure)/mean(CreditCard$expenditure) #coefficient of variability %
coeff_var
## [1] 1.471107
IQR(CreditCard$expenditure)# difference between quartiles =Q3-Q1
## 75%
## 243.6843
sx<-IQR(CreditCard$expenditure)/2 #interquartile deviation
coeff_varx<-sx/median(CreditCard$expenditure) #IQR coefficient of variability %
coeff_varx
## 75%
## 1.201644
min(CreditCard$expenditure)
## [1] 0
max(CreditCard$expenditure)
## [1] 3099.505
quantile(CreditCard$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 5.286458 101.396250 248.970800 636.451425
## 100%
## 3099.505000
card
boxplot
histogram
line1
line2
points1
yes
no
card
boxplot
histogram
line1
line2
points1
yes
no
card
boxplot
histogram
line1
line2
points1
yes
no
card
boxplot
histogram
line1
line2
points1
yes
no
Summary Table: Income Summary Statistics by Card
No
Yes
Min
0.49
0.21
Max
11.00
13.50
Q1
2.00
2.35
Median
2.59
3.00
Q3
3.68
4.00
Mean
3.07
3.45
Sd
1.62
1.70
IQR
1.68
1.65
Sx
0.84
0.82
Var_Percent
0.53
0.49
IQR_Var_Percent
0.65
0.55
Skewness
2.04
1.92
Kurtosis
5.20
4.92
Summary Table: Expenditure Summary Statistics By Card
No
Yes
Min
0
0.00
Max
0
3099.50
Q1
0
66.41
Median
0
149.94
Q3
0
313.41
Mean
0
238.20
Sd
0
287.57
IQR
0
247.00
Sx
0
123.50
Var_Percent
NaN
1.21
IQR_Var_Percent
NaN
1.65
Skewness
NaN
3.58
Kurtosis
NaN
20.16
Summary Table: Age Summary Statistics By Card
No
Yes
Min
0.75
0.17
Max
80.17
83.50
Q1
25.60
25.33
Median
32.00
31.12
Q3
38.19
39.73
Mean
33.23
33.22
Sd
9.95
10.21
IQR
12.58
14.40
Sx
6.29
7.20
Var_Percent
0.30
0.31
IQR_Var_Percent
0.39
0.46
Skewness
1.09
0.77
Kurtosis
2.33
1.21
Summary Table: Ratio of expenditure to income Summary Statistics By Card
No
Yes
Min
0
0.00
Max
0
0.03
Q1
0
0.00
Median
0
0.00
Q3
0
0.00
Mean
0
0.00
Sd
0
0.00
IQR
0
0.00
Sx
0
0.00
Var_Percent
NaN
2.69
IQR_Var_Percent
NaN
3.26
Skewness
NaN
7.27
Kurtosis
NaN
73.79
LS0tCnRpdGxlOiAnRGVzY3JpcHRpdmUgU3RhdGlzdGljcycKc3VidGl0bGU6ICdVbml2YXJpYXRlIFN0YXRpc3RpY3MnCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKYXV0aG9yOiAiTWFyaWEgUG9yxJlic2thLCBYaWFveWFuIExpLCBNYWdkYWxlbmEgU2llbGFmZiwgS2FjcGVyIFBpxJl0a2EiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OiAKICAgIHRoZW1lOiBjZXJ1bGVhbgogICAgaGlnaGxpZ2h0OiB0ZXh0bWF0ZQogICAgZm9udHNpemU6IDhwdAogICAgdG9jOiB5ZXMKICAgIGNvZGVfZG93bmxvYWQ6IHllcwogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IG5vCiAgICBkZl9wcmludDogZGVmYXVsdAogICAgdG9jX2RlcHRoOiA1CmVkaXRvcl9vcHRpb25zOiAKICBtYXJrZG93bjogCiAgICB3cmFwOiA3MgotLS0KCmBgYHtyIHNldHVwMSwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpvcHRpb25zKHF3cmFwczJfbWFya3VwID0gIm1hcmtkb3duIikKbGlicmFyeShxd3JhcHMyKQpsaWJyYXJ5KGFyc2VuYWwpCmxpYnJhcnkoZTEwNzEpCmxpYnJhcnkoaGF2ZW4pCmxpYnJhcnkocGFwZVIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGthYmxlRXh0cmEpCmxpYnJhcnkoc3VtbWFyeXRvb2xzKQpsaWJyYXJ5KGNsYXNzSW50KQpsaWJyYXJ5KHBhc3RlY3MpCmxpYnJhcnkocmVwb3J0dG9vbHMpCmxpYnJhcnkoZGVzY3RhYmxlKQpsaWJyYXJ5KHBzeWNoKQpsaWJyYXJ5KGZyZXF1ZW5jeSkKbGlicmFyeShnZ3B1YnIpCmxpYnJhcnkoZ2dmb3JjZSkKbGlicmFyeShnZ2Rpc3QpCmxpYnJhcnkoZ2doYWx2ZXMpCmxpYnJhcnkoZ3RzdW1tYXJ5KQpsaWJyYXJ5KEFFUikKZG93bmxvYWQuZmlsZSgiaHR0cHM6Ly9naXRodWIuY29tL2tmbGlzaWtvd3NraS9kcy9ibG9iL21hc3Rlci9kYXRhX2FwYXJ0bWVudHMuY3N2P3Jhdz10cnVlIiwgZGVzdGZpbGUgPSJtaWVzemthbmlhLmNzdiIsbW9kZT0id2IiKQphcGFydG1lbnRzIDwtIHJlYWQuY3N2KCJtaWVzemthbmlhLmNzdiIsc2VwPSI7IixkZWM9IiwiKQpgYGAKCiMjIERhdGEKCkluIG91ciBleGFtcGxlIHRoaXMgd2Vlaywgd2UgYXJlIGdvaW5nIHRvIHVzZSB0aGUgZmFrZSBkYXRhIC0gYWJvdXQgcmVhbAplc3RhdGVzIGluIFdyb2NsYXcgLSBwcmljZXMgYnkgZGlzdHJpY3RzLCBzaXplIG9mIGFwYXJ0bWVudHMgYW5kIG1hbnkKbW9yZS4KCiMjIyBQcmVwcm9jZXNzaW5nCgpBcyB5b3UgY2FuIHNlZSwgbm90IGFsbCBmb3JtYXRzIG9mIG91ciB2YXJpYWJsZXMgYXJlIGFkYXB0ZWQuIFdlIG5lZWQgdG8KcHJlcGFyZSBhcHByb3ByaWF0ZSBmb3JtYXRzIG9mIG91ciB2YXJpYWJsZXMgYWNjb3JkaW5nIHRvIHRoZWlyCm1lYXN1cmVtZW50IHNjYWxlIGFuZCBmdXR1cmUgYXBwbGljYXRpb24uCgpgYGB7ciB3cmFuZ2xpbmcsIGluY2x1ZGU9VFJVRX0KYXBhcnRtZW50cyRkaXN0cmljdDwtYXMuZmFjdG9yKGFwYXJ0bWVudHMkZGlzdHJpY3QpCmFwYXJ0bWVudHMkYnVpbGRpbmdfdHlwZTwtYXMuZmFjdG9yKGFwYXJ0bWVudHMkYnVpbGRpbmdfdHlwZSkKYXBhcnRtZW50cyRyb29tczwtZmFjdG9yKGFwYXJ0bWVudHMkcm9vbXMsb3JkZXJlZD1UUlVFKQphdHRhY2goYXBhcnRtZW50cykKYXBhcnRtZW50cyRwcmljZV9QTE48LWFzLm51bWVyaWMoYXBhcnRtZW50cyRwcmljZV9QTE4pCmFwYXJ0bWVudHMkcHJpY2VfRVVSPC1hcy5udW1lcmljKGFwYXJ0bWVudHMkcHJpY2VfRVVSKQpgYGAKCiMjIEZyZXF1ZW5jeSBUYWJsZXMKCkluIHRoZSBmaXJzdCBzdGVwIG9mIG91ciBhbmFseXNpcywgd2Ugd2lsbCBncm91cCBvdXIgZGF0YSBpbnRvIGEgc2ltcGxlCmZyZXF1ZW5jeSB0YWJsZS4KCkZpcnN0LCBsZXQncyBsb29rIGF0IHRoZSBkaXN0cmlidXRpb24gb2YgaG91c2luZyBwcmljZXMgaW4gb3VyIHNhbXBsZQphbmQgdmVyaWZ5IHRhYnVsYXIgdmFsaWRpdHkgdXNpbmcgdGhlIFRBSSBtZWFzdXJlOgoKYGBge3IgdGFibGUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0UsIHBhZ2VkLnByaW50PUZBTFNFfQpldHlraWV0eTwtYygiMzUwLTQ1MCBrUExOIiwiNDUwLTU1MCBrUExOIiwiNTUwLTY1MCBrUExOIiwiNjUwLTc1MCBrUExOIiwiNzUwLTg1MCBrUExOIiwiODUwLTk1MCBrUExOIiwiOTUwLTEwNTAga1BMTiIsIjEwNTAtMTE1MCBrUExOIiwiMTE1MC0xMjUwIGtQTE4iLCIxMjUwLTEzNTAga1BMTiIpCmxpbWl0czwtY3V0KGFwYXJ0bWVudHMkcHJpY2VfUExOLHNlcSgzNTAwMDAsMTM1MDAwMCxieT0xMDAwMDApLGxhYmVscz1ldHlraWV0eSkKdGFiZWxhMTwtZnJlcShsaW1pdHMsdHlwZT0iaHRtbCIpCmBgYAoKT2ssIGl0IGxvb2tzIHF1aXRlIHVnbHksIHNvIGxldCdzIHdyYXAgaXQgdXAgdXNpbmcgdGhlICdrYWJsZScgcGFja2FnZToKCmBgYHtyIHRhaSwgZWNobz1GQUxTRX0Ka2JsKHRhYmVsYTEsY2FwdGlvbiA9ICJBcGFydG1lbnRzIGluIFdyb2NsYXcgLSBwcmljZXMgaW4ga1BMTiIpICU+JQogICAga2FibGVfbWF0ZXJpYWwoYygic3RyaXBlZCIsICJob3ZlciIpKQp0YWIxPC1jbGFzc0ludGVydmFscyhhcGFydG1lbnRzJHByaWNlX1BMTixuPTEwLHN0eWxlPSJmaXhlZCIsZml4ZWRCcmVha3M9c2VxKDM1MDAwMCwxMzUwMDAwLGJ5PTEwMDAwMCkpCmplbmtzLnRlc3RzKHRhYjEpCmBgYAoKQXMgd2UgY2FuIHNlZSAtIHRoZSBUQUkgaW5kZXggaXMgcXVpdGUgaGlnaC4gMC44NSBtZWFucyB0aGF0IHdlIGNhbgphY2NlcHQgdGhlIHByb3Bvc2VkIGNvbnN0cnVjdGlvbiBvZiB0aGUgZnJlcXVlbmN5IHRhYmxlLgoKIyMgQmFzaWMgcGxvdHMKCkluIHRoaXMgc2VjdGlvbiwgd2Ugc2hvdWxkIHJlcHJlc2VudCBvdXIgZGF0YSB1c2luZyBiYXNpYyAocHJlLWluc3RhbGxlZAppbiBSKSBncmFwaGljcy4gU2VsZWN0IHRoZSBtb3N0IGFwcHJvcHJpYXRlIGdyYXBocyBkZXBlbmRpbmcgb24gdGhlCnNjYWxlIG9mIHRoZSBzZWxlY3RlZCB2YXJpYWJsZXMuIEV4cGxvcmUgdGhlIGhldGVyb2dlbmVpdHkgb2YgdGhlCmRpc3RyaWJ1dGlvbiBieSBwcmVzZW50aW5nIHRoZSBkYXRhIGJ5IGdyb3VwIChlLmcuLCBieSBuZWlnaGJvcmhvb2QsCmJ1aWxkaW5nIHR5cGUsIGV0Yy4pLiBEb24ndCBmb3JnZXQgYWJvdXQgbWFpbiB0aXRsZXMsIGxhYmVscyBhbmQKbGVnZW5kcy4gUmVhZCBtb3JlIGFib3V0IGdyYXBoaWNhbCBwYXJhbWV0ZXJzCltoZXJlXShodHRwOi8vd3d3LnN0aGRhLmNvbS9lbmdsaXNoL3dpa2kvZ3JhcGhpY2FsLXBhcmFtZXRlcnMpLgoKYGBge3IgaGlzdG9ncmFtLCBlY2hvPUZBTFNFfQpoaXN0KHByaWNlX1BMTiwgYnJlYWtzPSJGRCIsIGNvbD0iZ3JlZW4iLCBwcm9iYWJpbGl0eSA9IFRSVUUsCiAgICAgbWFpbj0iUHJpY2VzIGluIFBMTiAtIFdyb2NsYXcoZGlzdHJpY3RzKSIpCmxpbmVzKGRlbnNpdHkocHJpY2VfUExOW2Rpc3RyaWN0PT0iS3J6eWtpIl0pLGNvbD0yKQpsaW5lcyhkZW5zaXR5KHByaWNlX1BMTltkaXN0cmljdD09IkJpc2t1cGluIl0pLGNvbD0zKQpsaW5lcyhkZW5zaXR5KHByaWNlX1BMTltkaXN0cmljdD09IlNyb2RtaWVzY2llIl0pLGNvbD00KQpsZWdlbmQoInRvcHJpZ2h0IiwgbGVnZW5kPWMoIktyenlraSIsICJCaXNrdXBpbiIsICJTcm9kbWllc2NpZSIpLAogICAgICAgY29sPWMoMiwzLDQpLCBsdHk9MToyLCBob3Jpej1GQUxTRSwgYm94Lmx0eT0wLCBjZXg9MC44KQpoaXN0KHByaWNlX1BMTiwgYnJlYWtzPSJGRCIsIGNvbD0icGluayIsIHByb2JhYmlsaXR5ID0gVFJVRSwKICAgICBtYWluPSJQcmljZXMgaW4gUExOIC0gV3JvY2xhdyhidWlsZGluZyB0eXBlcykiKQpsaW5lcyhkZW5zaXR5KHByaWNlX1BMTltidWlsZGluZ190eXBlPT0ia2FtaWVuaWNhIl0pLGNvbD0yKQpsaW5lcyhkZW5zaXR5KHByaWNlX1BMTltidWlsZGluZ190eXBlPT0ibmlza2kgYmxvayJdKSxjb2w9MykKbGluZXMoZGVuc2l0eShwcmljZV9QTE5bYnVpbGRpbmdfdHlwZT09IndpZXpvd2llYyJdKSxjb2w9NCkKbGVnZW5kKCJ0b3ByaWdodCIsIGxlZ2VuZD1jKCJrYW1pZW5pY2EiLCAibmlza2kgYmxvayIsICJ3aWV6b3dpZWMiKSwgY29sPWMoMiwzLDQpLCBsdHk9MToyLCBob3Jpej1GQUxTRSwgYm94Lmx0eT0wLCBjZXg9MC44KQoKYGBgCgpOb3RlIHRoYXQgdGhlIGBlY2hvID0gRkFMU0VgIHBhcmFtZXRlciBoYXMgYmVlbiBhZGRlZCB0byB0aGUgY29kZQpzbmlwcGV0IHRvIHByZXZlbnQgcHJpbnRpbmcgdGhlIFIgY29kZSB0aGF0IGdlbmVyYXRlZCB0aGUgZ3JhcGguCgpgYGB7ciBib3hwbG90LCBlY2hvPUZBTFNFfQpib3hwbG90KHByaWNlX1BMTn5kaXN0cmljdCkKYm94cGxvdChwcmljZV9QTE5+YnVpbGRpbmdfdHlwZSkKYGBgCgojIyBnZ3Bsb3QyIHBsb3RzCgpOb3csIGxldCdzIHVzZSB0aGUgKioqZ2dwbG90MioqKiBhbmQgKioqZ2dwdWJyKioqIGxpYnJhcmllcyB0byBwbG90LgoKYGBge3IgaGlzdG9ncmFtMiwgZWNobz1GQUxTRX0KIyBEZW5zaXR5IHBsb3Qgb2YgInByaWNlX1BMTiIKIzo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6CmRlbnNpdHkucCA8LSBnZ2RlbnNpdHkoYXBhcnRtZW50cywgeCA9ICJwcmljZV9QTE4iLCAKICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImRpc3RyaWN0IiwgcGFsZXR0ZSA9ICJqY28iKSsKICBzdGF0X292ZXJsYXlfbm9ybWFsX2RlbnNpdHkoY29sb3IgPSAicmVkIiwgbGluZXR5cGUgPSAiZGFzaGVkIikKCiMgRHJhdyB0aGUgc3VtbWFyeSB0YWJsZSBvZiBwcmljZV9QTE4KIzo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6CiMgQ29tcHV0ZSBkZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIGJ5IGdyb3VwcwpzdGFibGUgPC0gZGVzY19zdGF0YnkoYXBhcnRtZW50cywgbWVhc3VyZS52YXIgPSAicHJpY2VfUExOIiwKICAgICAgICAgICAgICAgICAgICAgIGdycHMgPSAiZGlzdHJpY3QiKQpzdGFibGUgPC0gc3RhYmxlWywgYygiZGlzdHJpY3QiLCAibGVuZ3RoIiwgIm1lYW4iLCAic2QiKV0KIyBTdW1tYXJ5IHRhYmxlIHBsb3QsIG1lZGl1bSBvcmFuZ2UgdGhlbWUKc3RhYmxlLnAgPC0gZ2d0ZXh0dGFibGUoc3RhYmxlLCByb3dzID0gTlVMTCwgCiAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lID0gdHRoZW1lKCJtT3JhbmdlIikpCiMgRHJhdyB0ZXh0CiM6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ogp0ZXh0IDwtIHBhc3RlKCJQcmljZSBwZXIgYXBhcnRtZW50IGJ5IDMgZGlzdHJpY3RzIC0gV3JvY2xhdy4iLAogICAgICAgICAgICAgICJSYW5kb20gc2FtcGxlIG9mIDIwMCBhcGFydG1lbnRzLiIsCiAgICAgICAgICAgICAgIHNlcCA9ICIgIikKdGV4dC5wIDwtIGdncGFyYWdyYXBoKHRleHQgPSB0ZXh0LCBmYWNlID0gIml0YWxpYyIsIHNpemUgPSAxMSwgY29sb3IgPSAiYmxhY2siKQojIEFycmFuZ2UgdGhlIHBsb3RzIG9uIHRoZSBzYW1lIHBhZ2UKZ2dhcnJhbmdlKGRlbnNpdHkucCwgc3RhYmxlLnAsIHRleHQucCwgCiAgICAgICAgICBuY29sID0gMSwgbnJvdyA9IDMsCiAgICAgICAgICBoZWlnaHRzID0gYygxLCAwLjUsIDAuMykpCmBgYAoKR2dwbG90MiBhbGxvd3MgeW91IHRvIHNob3cgdGhlIGF2ZXJhZ2UgdmFsdWUgZm9yIGVhY2ggZ3JvdXAgdXNpbmcgdGhlCioqc3RhdF9zdW1tYXJ5KCkqKiBmdW5jdGlvbi4gWW91IG5vIGxvbmdlciBuZWVkIHRvIGNhbGN1bGF0ZSBhdmVyYWdlCnZhbHVlcyBiZWZvcmUgY3JlYXRpbmcgYSBncmFwaCEKCmBgYHtyIGJveHBsb3QyLCBlY2hvPUZBTFNFfQpnZ3Bsb3QoYXBhcnRtZW50cywgYWVzKHg9ZGlzdHJpY3QsIHk9cHJpY2VfUExOKSkgKwogICAgZ2VvbV9ib3hwbG90KGFscGhhPTAuNykgKwogICAgc3RhdF9zdW1tYXJ5KGZ1bj0ibWVhbiIsIGdlb209InBvaW50Iiwgc2hhcGU9MjAsIHNpemU9NSwgY29sb3I9InJlZCIsIGZpbGw9InJlZCIpICsKIGdlb21faml0dGVyKCkgKwogICAgZmFjZXRfZ3JpZCh+YnVpbGRpbmdfdHlwZSkgKwogICAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZT0iU2V0MSIpCgpgYGAKCiMjIyBSYWluQ2xvdWQgUGxvdAoKYGBge3IgcmFpbkNsb3VkLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQphcGFydG1lbnRzICU+JSAKICBmaWx0ZXIocm9vbXMgJWluJSBjKDEsIDIsIDMsIDQpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gZmFjdG9yKHJvb21zKSwgeSA9IHByaWNlX1BMTiwgZmlsbCA9IGZhY3Rvcihyb29tcykpKSArCiAgCiAgIyBhZGQgaGFsZi12aW9saW4gZnJvbSB7Z2dkaXN0fSBwYWNrYWdlCiAgc3RhdF9oYWxmZXllKAogICAgIyBhZGp1c3QgYmFuZHdpZHRoCiAgICBhZGp1c3QgPSAwLjUsCiAgICAjIG1vdmUgdG8gdGhlIHJpZ2h0CiAgICBqdXN0aWZpY2F0aW9uID0gLTAuMiwKICAgICMgcmVtb3ZlIHRoZSBzbHViIGludGVydmFsCiAgICAud2lkdGggPSAwLAogICAgcG9pbnRfY29sb3VyID0gTkEKICApICsKICBnZW9tX2JveHBsb3QoCiAgICB3aWR0aCA9IDAuMTIsCiAgICAjIHJlbW92aW5nIG91dGxpZXJzCiAgICBvdXRsaWVyLmNvbG9yID0gTkEsCiAgICBhbHBoYSA9IDAuNQogICkgKwogIHN0YXRfZG90cygKICAgICMgcGxvdGluZyBvbiBsZWZ0IHNpZGUKICAgIHNpZGUgPSAibGVmdCIsCiAgICAjIGFkanVzdGluZyBwb3NpdGlvbgogICAganVzdGlmaWNhdGlvbiA9IDEuMSwKICAgICMgYWRqdXN0IGdyb3VwaW5nIChiaW5uaW5nKSBvZiBvYnNlcnZhdGlvbnMKICAgIGJpbndpZHRoID0gMC4yNQogICkgKwojIFRoZW1lcyBhbmQgTGFiZWxzCiAgbGFicygKICAgIHRpdGxlID0gIlJhaW5DbG91ZCBQbG90IiwKICAgIHggPSAiTm8uIG9mIHJvb21zIiwKICAgIHkgPSAiUHJpY2VzIGluIFBMTiIsCiAgICBmaWxsID0gInJvb21zIgogICkgKwogIGNvb3JkX2ZsaXAoKQpgYGAKCiMjIyBGYWNldGluZwoKRmFjZXRpbmcgZ2VuZXJhdGVzIHNtYWxsIG11bHRpcGxlcywgZWFjaCBzaG93aW5nIGEgZGlmZmVyZW50IHN1YnNldCBvZgp0aGUgZGF0YS4gVGhleSBhcmUgYSBwb3dlcmZ1bCB0b29sIGZvciBleHBsb3JhdG9yeSBkYXRhIGFuYWx5c2lzOiB5b3UKY2FuIHF1aWNrbHkgY29tcGFyZSBwYXR0ZXJucyBpbiBkaWZmZXJlbnQgcGFydHMgb2YgdGhlIGRhdGEgYW5kIHNlZSBpZgp0aGV5IGFyZSB0aGUgc2FtZSBvciBkaWZmZXJlbnQuIFJlYWQgbW9yZQpbaGVyZV0oaHR0cHM6Ly9nZ3Bsb3QyLWJvb2sub3JnL2ZhY2V0Lmh0bWwpLgoKYGBge3IgZmFjZXQxLCBlY2hvPUZBTFNFfQpwbG90MSA8LSBnZ3Bsb3QoYXBhcnRtZW50cywgYWVzKHByaWNlX1BMTiwgcm9vbXMpKSArIAogIGdlb21fYWJsaW5lKCkgKwogIGdlb21faml0dGVyKHdpZHRoID0gMC4xLCBoZWlnaHQgPSAwLjEpIApwbG90MSArIGZhY2V0X3dyYXAofmRpc3RyaWN0KQpgYGAKCiMjIFVuaXZhcmlhdGUgU3RhdGlzdGljcwoKQmVmb3JlIGF1dG9tYXRpY2FsbHkgcmVwb3J0aW5nIHRoZSBmdWxsIHN1bW1hcnkgdGFibGUgb2YgZGVzY3JpcHRpdmUKc3RhdGlzdGljcywgdGhpcyB0aW1lIHlvdXIgZ29hbCBpcyB0byBtZWFzdXJlIHRoZSBjZW50cmFsIHRlbmRlbmN5IG9mCnRoZSBwcmljZSBkaXN0cmlidXRpb24uIENvbXBhcmUgdGhlIG1lYW4sIG1lZGlhbiwgYW5kIG1vZGUgYWxvbmcgd2l0aApwb3NpdGlvbmFsIG1lYXN1cmVzIC0gcXVhbnRpbGVzIC0gYnkgZGlzdHJpY3QgYW5kIGJ1aWxkaW5nIHR5cGUgb3IKbnVtYmVyIG9mIHJvb21zIGluIHRoZSBhcGFydG1lbnQuCgpgYGB7ciB1bml2YXJpYXRlIHN0YXRpc3RpY3N9CiAgICBtZWFuKHByaWNlX1BMTikKICAgIG1lZGlhbihwcmljZV9QTE4pCiAgICBzZChwcmljZV9QTE4pICNzdGFuZGFyZCBkZXZpYXRpb24KICAgIHZhcihwcmljZV9QTE4pICN2YXJpYW5jZQogICAgY29lZmZfdmFyPC1zZChwcmljZV9QTE4pL21lYW4ocHJpY2VfUExOKSAjY29lZmZpY2llbnQgb2YgdmFyaWFiaWxpdHkgJQogICAgY29lZmZfdmFyCiAgICBJUVIocHJpY2VfUExOKSMgZGlmZmVyZW5jZSBiZXR3ZWVuIHF1YXJ0aWxlcyA9UTMtUTEgCiAgICBzeDwtSVFSKHByaWNlX1BMTikvMiAgI2ludGVycXVhcnRpbGUgZGV2aWF0aW9uCiAgICBjb2VmZl92YXJ4PC1zeC9tZWRpYW4ocHJpY2VfUExOKSAjSVFSIGNvZWZmaWNpZW50IG9mIHZhcmlhYmlsaXR5ICUKICAgIGNvZWZmX3ZhcngKICAgIG1pbihwcmljZV9QTE4pCiAgICBtYXgocHJpY2VfUExOKQogICAgcXVhbnRpbGUocHJpY2VfUExOLHByb2JzPWMoMCwwLjEsMC4yNSwwLjUsMC43NSwwLjk1LDEpLG5hLnJtPVRSVUUpCmBgYAoKT2ssIHdlIGhhdmUgY2FsY3VsYXRlZCBhbGwgb2YgdGhlIGJhc2ljIHN1bW1hcnkgc3RhdGlzdGljcyBhYm92ZS4gTGV0J3MKd3JhcCB0aGVtIHVwIHRvZ2V0aGVyIG5vdy4KCmBgYHtyIGthYmxlX3JlcG9ydCwgZWNobz1GQUxTRX0KYXBhcnRtZW50c19saXN0IDwtIHNwbGl0KGFwYXJ0bWVudHMkcHJpY2VfUExOLCBhcGFydG1lbnRzJHJvb21zKQppbmxpbmVfcGxvdCA8LSBkYXRhLmZyYW1lKHJvb21zID0gYygxLCAyLCAzLCA0KSwgYm94cGxvdCA9ICIiLCBoaXN0b2dyYW0gPSAiIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBsaW5lMSA9ICIiLCBsaW5lMiA9ICIiLCBwb2ludHMxID0gIiIpCmlubGluZV9wbG90ICU+JQogIGtibChib29rdGFicyA9IFRSVUUpICU+JQogIGthYmxlX3BhcGVyKGZ1bGxfd2lkdGggPSBGQUxTRSkgJT4lCiAgY29sdW1uX3NwZWMoMiwgaW1hZ2UgPSBzcGVjX2JveHBsb3QoYXBhcnRtZW50c19saXN0KSkgJT4lCiAgY29sdW1uX3NwZWMoMywgaW1hZ2UgPSBzcGVjX2hpc3QoYXBhcnRtZW50c19saXN0KSkgJT4lCiAgY29sdW1uX3NwZWMoNCwgaW1hZ2UgPSBzcGVjX3Bsb3QoYXBhcnRtZW50c19saXN0LCBzYW1lX2xpbSA9IFRSVUUpKSAlPiUKICBjb2x1bW5fc3BlYyg1LCBpbWFnZSA9IHNwZWNfcGxvdChhcGFydG1lbnRzX2xpc3QsIHNhbWVfbGltID0gRkFMU0UpKSAlPiUKICBjb2x1bW5fc3BlYyg2LCBpbWFnZSA9IHNwZWNfcGxvdChhcGFydG1lbnRzX2xpc3QsIHR5cGUgPSAicCIpKQoKYGBgCgojIyMgU3VtbWFyeSB0YWJsZXMKCk9rLCBub3cgd2Ugd2lsbCBmaW5hbGx5IHN1bW1hcml6ZSB0aGUgYmFzaWMgbWVhc3VyZXMgb2YgY2VudHJhbCB0ZW5kZW5jeQpmb3IgcHJpY2VzIGJ5IGRpc3RyaWN0L2J1aWxkaW5nIHR5cGUgdXNpbmcgdGhlICcqKiprYWJsZSoqKicgcGFja2FnZS4KRmVlbCBmcmVlIHRvIGN1c3RvbWl6ZSB5b3VyIGZpbmFsIHJlcG9ydC4gU2VlIHNvbWUgaGludHMKW2hlcmVdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9xd3JhcHMyL3ZpZ25ldHRlcy9zdW1tYXJ5LXN0YXRpc3RpY3MuaHRtbCkuCgpgYGB7ciBrYWJsZV9yZXBvcnQyLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpyYXBvcnQgPC0KICBsaXN0KCJQcmljZSBpbiBQTE4iID0KICAgICAgIGxpc3QoIk1pbiIgICAgICAgPSB+IG1pbihwcmljZV9QTE4pLAogICAgICAgICAgICAiTWF4IiAgICAgICA9IH4gbWF4KHByaWNlX1BMTiksCiAgICAgICAgICAgICJRMSIgICAgICAgID0gfiBxdWFudGlsZShwcmljZV9QTE4sMC4yNSksCiAgICAgICAgICAgICJNZWRpYW4iID0gfiByb3VuZChtZWRpYW4ocHJpY2VfUExOKSwyKSwKICAgICAgICAgICAgIlEzIiAgICAgICAgPSB+IHF1YW50aWxlKHByaWNlX1BMTiwwLjc1KSwKICAgICAgICAgICAgIk1lYW4iID0gfiByb3VuZChtZWFuKHByaWNlX1BMTiksMiksCiAgICAgICAgICAgICJTZCIgPSB+IHJvdW5kKHNkKHByaWNlX1BMTiksMiksCiAgICAgICAgICAgICAiSVFSIiA9IH4gcm91bmQoaXFyKHByaWNlX1BMTiksMiksCiAgICAgICAgICAgICJTeCIgPSB+IHJvdW5kKGlxcihwcmljZV9QTE4pLzIsMiksCiAgICAgICAgICAgICJWYXIgJSIgPSB+IHJvdW5kKChzZChwcmljZV9QTE4pL21lYW4ocHJpY2VfUExOKSksMiksCiAgICAgICAgICAgICJJUVIgVmFyICUiID0gfiByb3VuZCgoaXFyKHByaWNlX1BMTikvbWVkaWFuKHByaWNlX1BMTikpLDIpLAogICAgICAgICAgICAiU2tld25lc3MiID0gfiAgcm91bmQoc2tldyhwcmljZV9QTE4pLDIpLAogICAgICAgICAgICAgIkt1cnRvc2lzIiA9IH4gIHJvdW5kKGt1cnRvc2kocHJpY2VfUExOKSwyKQogICAgICAgICAgICApKQp0YWJlbGE8LXN1bW1hcnlfdGFibGUoYXBhcnRtZW50cywgc3VtbWFyaWVzID0gcmFwb3J0LCBieSA9IGMoInJvb21zIikpCgp0YWJlbGEgPC0gdGFiZWxhWy0xLCBdICAjIFJlbW92ZSB0aGUgZmlyc3Qgcm93IChQcmljZSBpbiBQTE4pCgprYmwodGFiZWxhLCAgZGlnaXRzID0gMiwKICBjYXB0aW9uPSJUYWJsZSAxLiBBcGFydG1lbnRzIGluIFdyb2NsYXcgLSBwcmljZXMgaW4gUExOIGJ5IG51bWJlciBvZiByb29tcy4iLCAgY29sLm5hbWVzID0gYygiIiwgJzEgcm9vbScsICcyIHJvb21zJywgJzMgcm9vbXMnLCAnNCByb29tcycpLCByb3cubmFtZXMgPSBGQUxTRSwgZXNjYXBlID0gRkFMU0UpICU+JSBrYWJsZV9jbGFzc2ljKGZ1bGxfd2lkdGggPSBGLCBodG1sX2ZvbnQgPSAiQ2FtYnJpYSIpJT4lIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIikpCmBgYAoKIyMjIGd0c3VtbWFyeQoKV2UgY2FuIGNhbGN1bGF0ZSBlYXNpbHkgZGVzY3JpcHRpdmUgc3RhdGlzdGljcyBhbHNvIHVzaW5nIGd0c3VtbWFyeQpwYWNrYWdlOgoKYGBge3IgZ3RzdW1tYXJ5fQphcGFydG1lbnRzICU+JQogIHNlbGVjdChwcmljZV9QTE4scm9vbXMpICU+JQogIHRibF9zdW1tYXJ5KGxhYmVsPSBwcmljZV9QTE4gfiAiUHJpY2UiLGRpZ2l0cz1jKHByaWNlX1BMTil+MixieT1yb29tcyx0eXBlID0gYWxsX2NvbnRpbnVvdXMoKSB+ICJjb250aW51b3VzMiIsIHN0YXRpc3RpYyA9IGFsbF9jb250aW51b3VzKCkgfiBjKCJ7Tl9ub25taXNzfSIsICJ7bWVkaWFufSAoe3AyNX0sIHtwNzV9KSIsICJ7bWlufSwge21heH0iKSxtaXNzaW5nID0gIm5vIikKYGBgCgojIyMgZGZTdW1tYXJ5CgpkZlN1bW1hcnkoKSBjcmVhdGVzIGEgc3VtbWFyeSB0YWJsZSB3aXRoIHN0YXRpc3RpY3MsIGZyZXF1ZW5jaWVzIGFuZApncmFwaHMgZm9yIGFsbCB2YXJpYWJsZXMgaW4gYSBkYXRhIGZyYW1lLiBUaGUgaW5mb3JtYXRpb24gZGlzcGxheWVkIGlzCnR5cGUtc3BlY2lmaWMgKGNoYXJhY3RlciwgZmFjdG9yLCBudW1lcmljLCBkYXRlKSBhbmQgYWxzbyB2YXJpZXMKYWNjb3JkaW5nIHRvIHRoZSBudW1iZXIgb2YgZGlzdGluY3QgdmFsdWVzLgoKV2hlbiB1c2luZyBkZlN1bW1hcnkoKSBpbiBSIE1hcmtkb3duIGRvY3VtZW50cywgaXQgaXMgZ2VuZXJhbGx5IGEgZ29vZAppZGVhIHRvIGV4Y2x1ZGUgYSBjb2x1bW4gb3IgdHdvIHRvIGF2b2lkIG1hcmdpbiBvdmVyZmxvdy4gU2luY2UgdGhlClZhbGlkIGFuZCBNaXNzaW5nIGNvbHVtbnMgYXJlIHJlZHVuZGFudCwgd2UgY2FuIGRyb3AgZWl0aGVyIG9uZSBvZiB0aGVtLgoKYGBge3IgZGZTdW1tYXJ5LCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSJhc2lzIn0KZGZTdW1tYXJ5KGFwYXJ0bWVudHMsCiAgICAgICAgICBwbGFpbi5hc2NpaSAgPSBGQUxTRSwgCiAgICAgICAgICBzdHlsZSAgICAgICAgPSAiZ3JpZCIsIAogICAgICAgICAgZ3JhcGgubWFnbmlmID0gMC43NSwgCiAgICAgICAgICB2YWxpZC5jb2wgICAgPSBGQUxTRSwKICAgICAgICAgIHRtcC5pbWcuZGlyICA9ICIvdG1wIikKYGBgCgpUbyBwcm9kdWNlIG9wdGltYWwgcmVzdWx0cywgc3VtbWFyeXRvb2xzIGhhcyBpdHMgb3duIHZlcnNpb24gb2YgdGhlIGJhc2UKYnkoKSBmdW5jdGlvbi4gSXQncyBjYWxsZWQgc3RieSgpLCBhbmQgd2UgdXNlIGl0IGV4YWN0bHkgYXMgd2Ugd291bGQKYnkoKToKCmBgYHtyIGRmU3VtbWFyeTIsIHJlc3VsdHM9ImFzaXMiLCB3YXJuaW5nPUZBTFNFfQooc3RhdHNfYnlfcm9vbXMgPC0gc3RieShkYXRhICAgICAgPSBhcGFydG1lbnRzLCBJTkRJQ0VTICAgPSBhcGFydG1lbnRzJHJvb21zLCBGVU4gICAgICAgPSBkZXNjciwgc3RhdHMgICAgID0gImNvbW1vbiIsIHRyYW5zcG9zZSA9IFRSVUUpKQpgYGAKCiMjIyBUaWR5IFRhYmxlcwoKV2hlbiBnZW5lcmF0aW5nIGZyZXEoKSBvciBkZXNjcigpIHRhYmxlcywgaXQgaXMgcG9zc2libGUgdG8gdHVybiB0aGUKcmVzdWx0cyBpbnRvICJ0aWR5IiB0YWJsZXMgd2l0aCB0aGUgdXNlIG9mIHRoZSB0YigpIGZ1bmN0aW9uICh0aGluayBvZgp0YiBhcyBhIGRpbWludXRpdmUgZm9yIHRpYmJsZSkuIEZvciBleGFtcGxlOgoKYGBge3IgdGlkeXRhYmxlc30KYXBhcnRtZW50cyAlPiUKICBkZXNjcihzdGF0cyA9ICJjb21tb24iKSAlPiUKICB0YigpCmBgYAoKSGVyZSBhcmUgc29tZSBleGFtcGxlcyBzaG93aW5nIGhvdyBsaXN0cyBjcmVhdGVkIHVzaW5nIHN0YnkoKSBvcgpncm91cF9ieSgpIGNhbiBiZSB0cmFuc2Zvcm1lZCBpbnRvIHRpZHkgdGliYmxlcy4KCmBgYHtyIHRpZHl0YWJsZXMyfQpncm91cGVkX2Rlc2NyIDwtIHN0YnkoZGF0YSAgICA9IGFwYXJ0bWVudHMsSU5ESUNFUyA9IGFwYXJ0bWVudHMkcm9vbXMsIEZVTiAgICAgPSBkZXNjciwgc3RhdHMgICA9ICJjb21tb24iKQoKZ3JvdXBlZF9kZXNjciAlPiUgdGIoKQpgYGAKCiMjIyBBIEJyaWRnZSB0byBPdGhlciBQYWNrYWdlcwoKYGBge3IgYnJpZGdlfQpzdGJ5KGRhdGEgICAgPSBhcGFydG1lbnRzLCAKICAgICBJTkRJQ0VTID0gYXBhcnRtZW50cyRyb29tcywgCiAgICAgRlVOICAgICA9IGRlc2NyLCAKICAgICBzdGF0cyAgID0gImZpdmVudW0iKSAlPiUKICB0YihvcmRlciA9IDMpICU+JQogIGthYmxlKGZvcm1hdCA9ICJodG1sIiwgZGlnaXRzID0gMikgJT4lCiAgY29sbGFwc2Vfcm93cyhjb2x1bW5zID0gMSwgdmFsaWduID0gInRvcCIpCmBgYAoKIyMgWW91ciB0dXJuIQoKWW91ciB0YXNrIHRoaXMgd2VlayBpcyB0bzogcHJlcGFyZSB5b3VyIG93biBkZXNjcmlwdGl2ZSBhbmFseXNpcyBmb3IgdGhlCiJDcmVkaXRDYXJkIiBkYXRhc2V0IChBRVIgcGFja2FnZSkuIEl0IGlzIGEgY3Jvc3Mtc2VjdGlvbmFsIGRhdGFmcmFtZSBvbgp0aGUgY3JlZGl0IGhpc3RvcnkgZm9yIGEgc2FtcGxlIG9mIGFwcGxpY2FudHMgZm9yIGEgdHlwZSBvZiBjcmVkaXQgY2FyZC4KCmBgYHtyIGNyZWRpdGNhcmQsIGluY2x1ZGU9RkFMU0V9CmRhdGEoQ3JlZGl0Q2FyZCkKIz9DcmVkaXRDYXJkICByZWFkIGRlc2NyaXB0aW9uIGZpcnN0CiNmaWx0ZXJpbmcgb3V0IHRoZSBkYXRhIHdpdGggMCBtb250aHMgYW5kIG5vbi16ZXJvIGV4cGVuZGl0dXJlCkNyZWRpdENhcmQgPC0gQ3JlZGl0Q2FyZFtDcmVkaXRDYXJkJG1vbnRocyAhPSAwLCBdCkNyZWRpdENhcmQkcmF0aW9fZXhwZW5kaXR1cmVfaW5jb21lIDwtIChDcmVkaXRDYXJkJGV4cGVuZGl0dXJlIC8gQ3JlZGl0Q2FyZCRtb250aHMpIC8gKENyZWRpdENhcmQkaW5jb21lKjEwMDAwKQoKYGBgCgpBcmUgdGhlIHllYXJseSBpbmNvbWVzIChpbiBVU0QgMTAsMDAwKSwgY3JlZGl0IGNhcmQgZXhwZW5kaXR1cmVzLCBhZ2UsCnJhdGlvIG9mIG1vbnRobHkgY3JlZGl0IGNhcmQgZXhwZW5kaXR1cmUgdG8geWVhcmx5IGluY29tZSAtCnNpZ25pZmljYW50bHkgZGlmZmVyZW50IGZvciBhcHBsaWNhbnRzIGZvciBjdXN0b21lcnMgd2l0aCBkaWZmZXJlbnQKY3JlZGl0IHJpc2sgKCJjYXJkIiB2YXJpYWJsZSAtIGZhY3Rvcik/CgpQcmVwYXJlIGEgcHJvZmVzc2lvbmFsIGRhdGEgdmlzdWFsaXphdGlvbnMsIGRlc2NyaXB0aXZlIHN0YXRpc3RpY3MnCnRhYmxlcyBhbmQgaW50ZXJwcmV0IHRoZW0uCgpGUkVRVUVOQ1kgVEFCTEVTCgpgYGB7ciBmcmVxdWVuY3lfdGFibGVzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRX0KI3llYXJseSBpbmNvbWUKZXR5a2lldHlfaW5jb21lPC1jKCIwLTEwIGtVU0QiLCAiMTAtMjAga1VTRCIgLCIgMjAtMzAga1VTRCIsIjMwLTQwIGtVU0QiLCI0MC01MCBrVVNEIiwiNTAtNjAga1VTRCIsIjYwLTcwIGtVU0QiLCI3MC04MCBrVVNEIiwiODAtOTAga1VTRCIsIjkwLTEwMCBrVVNEIiwiMTAwLTExMCBrVVNEIiwiMTEwLTEyMCBrVVNEIiwgIjEyMC0xMzAga1VTRCIsICIxMzAtMTQwIGtVU0QiKQoKbGltaXRzX2luY29tZTwtY3V0KENyZWRpdENhcmQkaW5jb21lLHNlcSgwLDE0LGJ5PTEpLGxhYmVscz1ldHlraWV0eV9pbmNvbWUpCnRhYmVsYV9pbmNvbWU8LWZyZXEobGltaXRzX2luY29tZSx0eXBlPSJodG1sIikKCiNleHBlbmRpdHVyZQpldHlraWV0eV9leHBlbmRpdHVyZTwtYygiMC0xMDAiLCAiMTAwLTIwMCIsICIyMDAtMzAwIiwgIjMwMC00MDAiLCAiNDAwLTUwMCIsICI1MDAtNjAwIiwiNjAwLTcwMCIsIjcwMC04MDAiLCI4MDAtOTAwIiwiOTAwLTEwMDAiLCIxMDAwLTM1MDAiKQpleHBfYnJlYWtzIDwtIGMoc2VxKDAsIDEwMDAsIGJ5ID0gMTAwKSwgc2VxKDEwMDEsIDM1MDAsIGJ5ID0gMjUwMCkpCmxpbWl0c19leHBlbmRpdHVyZTwtY3V0KENyZWRpdENhcmQkZXhwZW5kaXR1cmUsYnJlYWtzPWV4cF9icmVha3MsbGFiZWxzPWV0eWtpZXR5X2V4cGVuZGl0dXJlKQp0YWJlbGFfZXhwZW5kaXR1cmU8LWZyZXEobGltaXRzX2V4cGVuZGl0dXJlLHR5cGU9Imh0bWwiKQoKI2FnZQpldHlraWV0eV9hZ2U8LWMoIjAtMTAiLCAiMTAtMjAiLCAiMjAtMzAiLCAiMzAtNDAiLCAiNDAtNTAiLCAiNTAtNjAiLCAiNjAtNzAiLCAiNzAtODAiLCAiODAtOTAiKQpsaW1pdHNfYWdlPC1jdXQoQ3JlZGl0Q2FyZCRhZ2UsIHNlcSgwLDkwLGJ5PTEwKSwgbGFiZWxzID0gZXR5a2lldHlfYWdlKQp0YWJlbGFfYWdlPC1mcmVxKGxpbWl0c19hZ2UsdHlwZT0iaHRtbCIpCgojcmF0aW8gZXhwZW5kaXR1cmUvaW5jb21lCmV0eWtpZXR5X3JhdGlvPC1jKCIwLTAuMDAyIiwgIjAuMDAyLTAuMDA0IiwgIjAuMDA0LTAuMDA2IiwgIjAuMDA2LTAuMDA4IiwgIjAuMDA4LTAuMDEiLCAiMC4wMS0wLjAxMiIsICIwLjAxMi0wLjAxNCIsICIwLjAxNC0wLjAxNiIsIjAuMDE2LTAuMDE4IiwgIjAuMDE4LTAuMDIiLCAiMC4wMi0wLjAyMiIsICIwLjAyMi0wLjAyNCIsICIwLjAyNC0wLjAyNiIpCmxpbWl0c19yYXRpbzwtY3V0KENyZWRpdENhcmQkcmF0aW9fZXhwZW5kaXR1cmVfaW5jb21lLCBzZXEoMCwwLjAyNixieT0wLjAwMiksIGxhYmVscyA9IGV0eWtpZXR5X3JhdGlvKQp0YWJlbGFfcmF0aW88LWZyZXEobGltaXRzX3JhdGlvLHR5cGU9Imh0bWwiKQoKYGBgCgpgYGB7ciB0YWkyLCBlY2hvPUZBTFNFfQojaW5jb21lCmtibCh0YWJlbGFfaW5jb21lLGNhcHRpb24gPSAiSW5jb21lIGluIGtQTE4iKSAlPiUKICAgIGthYmxlX21hdGVyaWFsKGMoInN0cmlwZWQiLCAiaG92ZXIiKSkKdGFiX2luY29tZTwtY2xhc3NJbnRlcnZhbHMoQ3JlZGl0Q2FyZCRpbmNvbWUsbj0xNCxzdHlsZT0iZml4ZWQiLGZpeGVkQnJlYWtzPXNlcSgwLDE0LGJ5PTEpKQpqZW5rcy50ZXN0cyh0YWJfaW5jb21lKQojZXhwZW5kaXR1cmUKa2JsKHRhYmVsYV9leHBlbmRpdHVyZSxjYXB0aW9uID0gIkV4cGVuZGl0dXJlIikgJT4lCiAgICBrYWJsZV9tYXRlcmlhbChjKCJzdHJpcGVkIiwgImhvdmVyIikpCnRhYl9leHBlbmRpdHVyZTwtY2xhc3NJbnRlcnZhbHMoQ3JlZGl0Q2FyZCRleHBlbmRpdHVyZSxuPTExLHN0eWxlPSJmaXhlZCIsZml4ZWRCcmVha3M9ZXhwX2JyZWFrcykKamVua3MudGVzdHModGFiX2V4cGVuZGl0dXJlKQojYWdlCmtibCh0YWJlbGFfYWdlLGNhcHRpb24gPSAiQWdlIikgJT4lCiAgICBrYWJsZV9tYXRlcmlhbChjKCJzdHJpcGVkIiwgImhvdmVyIikpCnRhYl9hZ2U8LWNsYXNzSW50ZXJ2YWxzKENyZWRpdENhcmQkYWdlLG49OSxzdHlsZT0iZml4ZWQiLGZpeGVkQnJlYWtzPXNlcSgwLDkwLGJ5PTEwKSkKamVua3MudGVzdHModGFiX2FnZSkKI3JhdGlvIGV4cGVuZGl0dXJlL2luY29tZQprYmwodGFiZWxhX3JhdGlvLGNhcHRpb24gPSAiUmF0aW8gb2YgbW9udGhseSBleHBlbmRpdHVyZSB0byB5ZWFybHkgaW5jb21lIikgJT4lCiAgICBrYWJsZV9tYXRlcmlhbChjKCJzdHJpcGVkIiwgImhvdmVyIikpCnRhYl9yYXRpbzwtY2xhc3NJbnRlcnZhbHMoQ3JlZGl0Q2FyZCRyYXRpb19leHBlbmRpdHVyZV9pbmNvbWUsbj0xMyxzdHlsZT0iZml4ZWQiLGZpeGVkQnJlYWtzPXNlcSgwLDAuMDI2LGJ5PTAuMDAyKSkKamVua3MudGVzdHModGFiX3JhdGlvKQpgYGAKClBMT1RTCgpgYGB7ciBoaXN0b2dyYW1fY3JlZGl0Y2FyZCwgZWNobz1GQUxTRX0KI2luY29tZQpoaXN0KENyZWRpdENhcmQkaW5jb21lLCBicmVha3M9IkZEIiwgY29sPSJsaWdodGJsdWUiLCBwcm9iYWJpbGl0eSA9IFRSVUUsbWFpbj0iWWVhcmx5IGluY29tZSBpbiAxMGtVU0QiLCB4bGFiID0gIlllYXJseSBpbmNvbWUgaW4gMTBrVVNEIiwgeWxhYiA9ICJGcmVxdWVuY3kiKQpsaW5lcyhkZW5zaXR5KENyZWRpdENhcmQkaW5jb21lW0NyZWRpdENhcmQkY2FyZD09InllcyJdKSxjb2w9MikKbGluZXMoZGVuc2l0eShDcmVkaXRDYXJkJGluY29tZVtDcmVkaXRDYXJkJGNhcmQ9PSJubyJdKSxjb2w9MykKbGVnZW5kKCJ0b3ByaWdodCIsIGxlZ2VuZD1jKCJ5ZXMiLCAibm8iKSwKICAgICAgIGNvbD1jKDIsMyksIGx0eT0xOjIsIGhvcml6PUZBTFNFLCBib3gubHR5PTAsIGNleD0wLjgpCiNleHBlbmRpdHVyZQpoaXN0KENyZWRpdENhcmQkZXhwZW5kaXR1cmUsIGJyZWFrcz0iRkQiLCBjb2w9InB1cnBsZSIsIHByb2JhYmlsaXR5ID0gVFJVRSxtYWluPSJFeHBlbmRpdHVyZSBpbiBVU0QiLCB4bGFiID0gIkV4cGVuZGl0dXJlIGluIFVTRCIsIHlsYWIgPSAiRnJlcXVlbmN5IikKbGluZXMoZGVuc2l0eShDcmVkaXRDYXJkJGV4cGVuZGl0dXJlW0NyZWRpdENhcmQkY2FyZD09InllcyJdKSxjb2w9MikKbGluZXMoZGVuc2l0eShDcmVkaXRDYXJkJGV4cGVuZGl0dXJlW0NyZWRpdENhcmQkY2FyZD09Im5vIl0pLGNvbD0zKQpsZWdlbmQoInRvcHJpZ2h0IiwgbGVnZW5kPWMoInllcyIsICJubyIpLAogICAgICAgY29sPWMoMiwzKSwgbHR5PTE6MiwgaG9yaXo9RkFMU0UsIGJveC5sdHk9MCwgY2V4PTAuOCkKI2FnZQpoaXN0KENyZWRpdENhcmQkYWdlLCBicmVha3M9IkZEIiwgY29sPSJwaW5rIiwgcHJvYmFiaWxpdHkgPSBUUlVFLG1haW49IkFnZSIsIHhsYWIgPSAiQWdlIiwgeWxhYiA9ICJGcmVxdWVuY3kiKQpsaW5lcyhkZW5zaXR5KENyZWRpdENhcmQkYWdlW0NyZWRpdENhcmQkY2FyZD09InllcyJdKSxjb2w9MikKbGluZXMoZGVuc2l0eShDcmVkaXRDYXJkJGFnZVtDcmVkaXRDYXJkJGNhcmQ9PSJubyJdKSxjb2w9MykKbGVnZW5kKCJ0b3ByaWdodCIsIGxlZ2VuZD1jKCJ5ZXMiLCAibm8iKSwKICAgICAgIGNvbD1jKDIsMyksIGx0eT0xOjIsIGhvcml6PUZBTFNFLCBib3gubHR5PTAsIGNleD0wLjgpCiNyYXRpbyBleHBlbmRpdHVyZS9pbmNvbWUKaGlzdChDcmVkaXRDYXJkJHJhdGlvX2V4cGVuZGl0dXJlX2luY29tZSwgYnJlYWtzPSJGRCIsIGNvbD0ibGlnaHRncmVlbiIsIHByb2JhYmlsaXR5ID0gVFJVRSxtYWluPSJSYXRpbyBvZiBtb250bHkgZXhwZW5kaXR1cmUgdG8geWVhcmx5IGluY29tZSIsIHhsYWIgPSAiUmF0aW8gb2YgbW9udGhseSBleHBlbmRpdHVyZSB0byB5ZWFybHkgaW5jb21lIiwgeWxhYiA9ICJGcmVxdWVuY3kiKQpsaW5lcyhkZW5zaXR5KENyZWRpdENhcmQkYWdlW0NyZWRpdENhcmQkY2FyZD09InllcyJdKSxjb2w9MikKbGluZXMoZGVuc2l0eShDcmVkaXRDYXJkJGFnZVtDcmVkaXRDYXJkJGNhcmQ9PSJubyJdKSxjb2w9MykKbGVnZW5kKCJ0b3ByaWdodCIsIGxlZ2VuZD1jKCJ5ZXMiLCAibm8iKSwKICAgICAgIGNvbD1jKDIsMyksIGx0eT0xOjIsIGhvcml6PUZBTFNFLCBib3gubHR5PTAsIGNleD0wLjgpCgpib3hwbG90KENyZWRpdENhcmQkaW5jb21lfkNyZWRpdENhcmQkY2FyZCkKYm94cGxvdChDcmVkaXRDYXJkJGV4cGVuZGl0dXJlfkNyZWRpdENhcmQkY2FyZCkKYm94cGxvdChDcmVkaXRDYXJkJGFnZX5DcmVkaXRDYXJkJGNhcmQpCmJveHBsb3QoQ3JlZGl0Q2FyZCRyYXRpb19leHBlbmRpdHVyZV9pbmNvbWV+Q3JlZGl0Q2FyZCRjYXJkKQpgYGAKCmBgYHtyIGhpc3RvZ3JhbTJfY3JlZGl0Y2FyZCwgZWNobz1GQUxTRX0KIyBEZW5zaXR5IHBsb3Qgb2YgImluY29tZSIKIzo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6CmRlbnNpdHkucCA8LSBnZ2RlbnNpdHkoQ3JlZGl0Q2FyZCwgeCA9ICJpbmNvbWUiLCAKICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImNhcmQiLCBwYWxldHRlID0gImpjbyIpKwogIHN0YXRfb3ZlcmxheV9ub3JtYWxfZGVuc2l0eShjb2xvciA9ICJyZWQiLCBsaW5ldHlwZSA9ICJkYXNoZWQiKQoKIyBEcmF3IHRoZSBzdW1tYXJ5IHRhYmxlIG9mIGluY29tZQojOjo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6OjoKIyBDb21wdXRlIGRlc2NyaXB0aXZlIHN0YXRpc3RpY3MgYnkgZ3JvdXBzCnN0YWJsZSA8LSBkZXNjX3N0YXRieShDcmVkaXRDYXJkLCBtZWFzdXJlLnZhciA9ICJpbmNvbWUiLAogICAgICAgICAgICAgICAgICAgICAgZ3JwcyA9ICJjYXJkIikKc3RhYmxlIDwtIHN0YWJsZVssIGMoImNhcmQiLCAibGVuZ3RoIiwgIm1lYW4iLCAic2QiKV0KIyBTdW1tYXJ5IHRhYmxlIHBsb3QsIG1lZGl1bSBvcmFuZ2UgdGhlbWUKc3RhYmxlLnAgPC0gZ2d0ZXh0dGFibGUoc3RhYmxlLCByb3dzID0gTlVMTCwgCiAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lID0gdHRoZW1lKCJtT3JhbmdlIikpCiMgRHJhdyB0ZXh0CiM6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ogp0ZXh0IDwtIHBhc3RlKCJJbmNvbWUgaW4gMTBrVVNEIHBlciBwZXJzb24gZGVwZW5kaW5nIG9uIHRoZSBjYXJkIHZhcmlhYmxlIiwKICAgICAgICAgICAgICAgc2VwID0gIiAiKQp0ZXh0LnAgPC0gZ2dwYXJhZ3JhcGgodGV4dCA9IHRleHQsIGZhY2UgPSAiaXRhbGljIiwgc2l6ZSA9IDExLCBjb2xvciA9ICJibGFjayIpCiMgQXJyYW5nZSB0aGUgcGxvdHMgb24gdGhlIHNhbWUgcGFnZQpnZ2FycmFuZ2UoZGVuc2l0eS5wLCBzdGFibGUucCwgdGV4dC5wLCAKICAgICAgICAgIG5jb2wgPSAxLCBucm93ID0gMywKICAgICAgICAgIGhlaWdodHMgPSBjKDEsIDAuNSwgMC4zKSkKCgojIERlbnNpdHkgcGxvdCBvZiAiZXhwZW5kaXR1cmUiCiM6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6OgpkZW5zaXR5LnAgPC0gZ2dkZW5zaXR5KENyZWRpdENhcmQsIHggPSAiZXhwZW5kaXR1cmUiLCAKICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImNhcmQiLCBwYWxldHRlID0gImpjbyIpKwogIHN0YXRfb3ZlcmxheV9ub3JtYWxfZGVuc2l0eShjb2xvciA9ICJwdXJwbGUiLCBsaW5ldHlwZSA9ICJkYXNoZWQiKQoKIyBEcmF3IHRoZSBzdW1tYXJ5IHRhYmxlIG9mIGV4cGVuZGl0dXJlCiM6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6OgojIENvbXB1dGUgZGVzY3JpcHRpdmUgc3RhdGlzdGljcyBieSBncm91cHMKc3RhYmxlIDwtIGRlc2Nfc3RhdGJ5KENyZWRpdENhcmQsIG1lYXN1cmUudmFyID0gImV4cGVuZGl0dXJlIiwKICAgICAgICAgICAgICAgICAgICAgIGdycHMgPSAiY2FyZCIpCnN0YWJsZSA8LSBzdGFibGVbLCBjKCJjYXJkIiwgImxlbmd0aCIsICJtZWFuIiwgInNkIildCiMgU3VtbWFyeSB0YWJsZSBwbG90LCBtZWRpdW0gb3JhbmdlIHRoZW1lCnN0YWJsZS5wIDwtIGdndGV4dHRhYmxlKHN0YWJsZSwgcm93cyA9IE5VTEwsIAogICAgICAgICAgICAgICAgICAgICAgICB0aGVtZSA9IHR0aGVtZSgibU9yYW5nZSIpKQojIERyYXcgdGV4dAojOjo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6OjoKdGV4dCA8LSBwYXN0ZSgiRXhwZW5kaXR1cmUgcGVyIHBlcnNvbiBkZXBlbmRpbmcgb24gdGhlIGNhcmQgdmFyaWFibGUiLAogICAgICAgICAgICAgICBzZXAgPSAiICIpCnRleHQucCA8LSBnZ3BhcmFncmFwaCh0ZXh0ID0gdGV4dCwgZmFjZSA9ICJpdGFsaWMiLCBzaXplID0gMTEsIGNvbG9yID0gImJsYWNrIikKIyBBcnJhbmdlIHRoZSBwbG90cyBvbiB0aGUgc2FtZSBwYWdlCmdnYXJyYW5nZShkZW5zaXR5LnAsIHN0YWJsZS5wLCB0ZXh0LnAsIAogICAgICAgICAgbmNvbCA9IDEsIG5yb3cgPSAzLAogICAgICAgICAgaGVpZ2h0cyA9IGMoMSwgMC41LCAwLjMpKQoKIyBEZW5zaXR5IHBsb3Qgb2YgImFnZSIKIzo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6CmRlbnNpdHkucCA8LSBnZ2RlbnNpdHkoQ3JlZGl0Q2FyZCwgeCA9ICJhZ2UiLCAKICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImNhcmQiLCBwYWxldHRlID0gImpjbyIpKwogIHN0YXRfb3ZlcmxheV9ub3JtYWxfZGVuc2l0eShjb2xvciA9ICJibHVlIiwgbGluZXR5cGUgPSAiZGFzaGVkIikKCiMgRHJhdyB0aGUgc3VtbWFyeSB0YWJsZSBvZiBhZ2UKIzo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6CiMgQ29tcHV0ZSBkZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIGJ5IGdyb3VwcwpzdGFibGUgPC0gZGVzY19zdGF0YnkoQ3JlZGl0Q2FyZCwgbWVhc3VyZS52YXIgPSAiYWdlIiwKICAgICAgICAgICAgICAgICAgICAgIGdycHMgPSAiY2FyZCIpCnN0YWJsZSA8LSBzdGFibGVbLCBjKCJjYXJkIiwgImxlbmd0aCIsICJtZWFuIiwgInNkIildCiMgU3VtbWFyeSB0YWJsZSBwbG90LCBtZWRpdW0gb3JhbmdlIHRoZW1lCnN0YWJsZS5wIDwtIGdndGV4dHRhYmxlKHN0YWJsZSwgcm93cyA9IE5VTEwsIAogICAgICAgICAgICAgICAgICAgICAgICB0aGVtZSA9IHR0aGVtZSgibU9yYW5nZSIpKQojIERyYXcgdGV4dAojOjo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6OjoKdGV4dCA8LSBwYXN0ZSgiQWdlIG9mIHBlcnNvbiBkZXBlbmRpbmcgb24gdGhlIGNhcmQgdmFyaWFibGUiLAogICAgICAgICAgICAgICBzZXAgPSAiICIpCnRleHQucCA8LSBnZ3BhcmFncmFwaCh0ZXh0ID0gdGV4dCwgZmFjZSA9ICJpdGFsaWMiLCBzaXplID0gMTEsIGNvbG9yID0gImJsYWNrIikKIyBBcnJhbmdlIHRoZSBwbG90cyBvbiB0aGUgc2FtZSBwYWdlCmdnYXJyYW5nZShkZW5zaXR5LnAsIHN0YWJsZS5wLCB0ZXh0LnAsIAogICAgICAgICAgbmNvbCA9IDEsIG5yb3cgPSAzLAogICAgICAgICAgaGVpZ2h0cyA9IGMoMSwgMC41LCAwLjMpKQoKIyBEZW5zaXR5IHBsb3Qgb2YgInJhdGlvIGV4cGVuZGl0dXJlL2luY29tZSIKIzo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6CmRlbnNpdHkucCA8LSBnZ2RlbnNpdHkoQ3JlZGl0Q2FyZCwgeCA9ICJyYXRpb19leHBlbmRpdHVyZV9pbmNvbWUiLCAKICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImNhcmQiLCBwYWxldHRlID0gImpjbyIpKwogIHN0YXRfb3ZlcmxheV9ub3JtYWxfZGVuc2l0eShjb2xvciA9ICJ5ZWxsb3ciLCBsaW5ldHlwZSA9ICJkYXNoZWQiKQoKIyBEcmF3IHRoZSBzdW1tYXJ5IHRhYmxlIG9mIHJhdGlvIGV4cGVuZGl0dXJlIGluY29tZQojOjo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6OjoKIyBDb21wdXRlIGRlc2NyaXB0aXZlIHN0YXRpc3RpY3MgYnkgZ3JvdXBzCnN0YWJsZSA8LSBkZXNjX3N0YXRieShDcmVkaXRDYXJkLCBtZWFzdXJlLnZhciA9ICJyYXRpb19leHBlbmRpdHVyZV9pbmNvbWUiLAogICAgICAgICAgICAgICAgICAgICAgZ3JwcyA9ICJjYXJkIikKc3RhYmxlIDwtIHN0YWJsZVssIGMoImNhcmQiLCAibGVuZ3RoIiwgIm1lYW4iLCAic2QiKV0KIyBTdW1tYXJ5IHRhYmxlIHBsb3QsIG1lZGl1bSBvcmFuZ2UgdGhlbWUKc3RhYmxlLnAgPC0gZ2d0ZXh0dGFibGUoc3RhYmxlLCByb3dzID0gTlVMTCwgCiAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lID0gdHRoZW1lKCJtT3JhbmdlIikpCiMgRHJhdyB0ZXh0CiM6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ogp0ZXh0IDwtIHBhc3RlKCJSYXRpbyBvZiBtb250aGx5IGV4cGVuZGl0dXJlIHRvIHllYXJseSBpbmNvbWUgcGVyIHBlcnNvbiBkZXBlbmRpbmcgb24gdGhlIGNhcmQgdmFyaWFibGUiLAogICAgICAgICAgICAgICBzZXAgPSAiICIpCnRleHQucCA8LSBnZ3BhcmFncmFwaCh0ZXh0ID0gdGV4dCwgZmFjZSA9ICJpdGFsaWMiLCBzaXplID0gMTEsIGNvbG9yID0gImJsYWNrIikKIyBBcnJhbmdlIHRoZSBwbG90cyBvbiB0aGUgc2FtZSBwYWdlCmdnYXJyYW5nZShkZW5zaXR5LnAsIHN0YWJsZS5wLCB0ZXh0LnAsIAogICAgICAgICAgbmNvbCA9IDEsIG5yb3cgPSAzLAogICAgICAgICAgaGVpZ2h0cyA9IGMoMSwgMC41LCAwLjMpKQoKCmBgYAoKYGBge3IgY3JlZGl0Y2FyZCBjYWxjdWxhdGlvbnN9CiNpbmNvbWUKICAgIG1lYW4oQ3JlZGl0Q2FyZCRpbmNvbWUpCiAgICBtZWRpYW4oQ3JlZGl0Q2FyZCRpbmNvbWUpCiAgICBzZChDcmVkaXRDYXJkJGluY29tZSkgI3N0YW5kYXJkIGRldmlhdGlvbgogICAgdmFyKENyZWRpdENhcmQkaW5jb21lKSAjdmFyaWFuY2UKICAgIGNvZWZmX3Zhcjwtc2QoQ3JlZGl0Q2FyZCRpbmNvbWUpL21lYW4oQ3JlZGl0Q2FyZCRpbmNvbWUpICNjb2VmZmljaWVudCBvZiB2YXJpYWJpbGl0eSAlCiAgICBjb2VmZl92YXIKICAgIElRUihDcmVkaXRDYXJkJGluY29tZSkjIGRpZmZlcmVuY2UgYmV0d2VlbiBxdWFydGlsZXMgPVEzLVExIAogICAgc3g8LUlRUihDcmVkaXRDYXJkJGluY29tZSkvMiAgI2ludGVycXVhcnRpbGUgZGV2aWF0aW9uCiAgICBjb2VmZl92YXJ4PC1zeC9tZWRpYW4oQ3JlZGl0Q2FyZCRpbmNvbWUpICNJUVIgY29lZmZpY2llbnQgb2YgdmFyaWFiaWxpdHkgJQogICAgY29lZmZfdmFyeAogICAgbWluKENyZWRpdENhcmQkaW5jb21lKQogICAgbWF4KENyZWRpdENhcmQkaW5jb21lKQogICAgcXVhbnRpbGUoQ3JlZGl0Q2FyZCRpbmNvbWUscHJvYnM9YygwLDAuMSwwLjI1LDAuNSwwLjc1LDAuOTUsMSksbmEucm09VFJVRSkKI2V4cGVuZGl0dXJlCiAgICBtZWFuKENyZWRpdENhcmQkZXhwZW5kaXR1cmUpCiAgICBtZWRpYW4oQ3JlZGl0Q2FyZCRleHBlbmRpdHVyZSkKICAgIHNkKENyZWRpdENhcmQkZXhwZW5kaXR1cmUpICNzdGFuZGFyZCBkZXZpYXRpb24KICAgIHZhcihDcmVkaXRDYXJkJGV4cGVuZGl0dXJlKSAjdmFyaWFuY2UKICAgIGNvZWZmX3Zhcjwtc2QoQ3JlZGl0Q2FyZCRleHBlbmRpdHVyZSkvbWVhbihDcmVkaXRDYXJkJGV4cGVuZGl0dXJlKSAjY29lZmZpY2llbnQgb2YgdmFyaWFiaWxpdHkgJQogICAgY29lZmZfdmFyCiAgICBJUVIoQ3JlZGl0Q2FyZCRleHBlbmRpdHVyZSkjIGRpZmZlcmVuY2UgYmV0d2VlbiBxdWFydGlsZXMgPVEzLVExIAogICAgc3g8LUlRUihDcmVkaXRDYXJkJGV4cGVuZGl0dXJlKS8yICAjaW50ZXJxdWFydGlsZSBkZXZpYXRpb24KICAgIGNvZWZmX3Zhcng8LXN4L21lZGlhbihDcmVkaXRDYXJkJGV4cGVuZGl0dXJlKSAjSVFSIGNvZWZmaWNpZW50IG9mIHZhcmlhYmlsaXR5ICUKICAgIGNvZWZmX3ZhcngKICAgIG1pbihDcmVkaXRDYXJkJGV4cGVuZGl0dXJlKQogICAgbWF4KENyZWRpdENhcmQkZXhwZW5kaXR1cmUpCiAgICBxdWFudGlsZShDcmVkaXRDYXJkJGV4cGVuZGl0dXJlLHByb2JzPWMoMCwwLjEsMC4yNSwwLjUsMC43NSwwLjk1LDEpLG5hLnJtPVRSVUUpCmBgYAoKYGBge3Iga2FibGVfcmVwb3J0X2NyZWRpdGNhcmQsIGVjaG89RkFMU0V9CiNpbmNvbWUKQ3JlZGl0Q2FyZF9pbmNvbWVfbGlzdCA8LSBzcGxpdChDcmVkaXRDYXJkJGluY29tZSwgQ3JlZGl0Q2FyZCRjYXJkKQppbmxpbmVfcGxvdF9pbmNvbWUgPC0gZGF0YS5mcmFtZShjYXJkPWMoInllcyIsICJubyIpLCBib3hwbG90ID0gIiIsIGhpc3RvZ3JhbSA9ICIiLGxpbmUxID0gIiIsIGxpbmUyID0gIiIsIHBvaW50czEgPSAiIikKaW5saW5lX3Bsb3RfaW5jb21lICU+JQogIGtibChib29rdGFicyA9IFRSVUUpICU+JQogIGthYmxlX3BhcGVyKGZ1bGxfd2lkdGggPSBGQUxTRSkgJT4lCiAgY29sdW1uX3NwZWMoMiwgaW1hZ2UgPSBzcGVjX2JveHBsb3QoQ3JlZGl0Q2FyZF9pbmNvbWVfbGlzdCkpICU+JQogIGNvbHVtbl9zcGVjKDMsIGltYWdlID0gc3BlY19oaXN0KENyZWRpdENhcmRfaW5jb21lX2xpc3QpKSAlPiUKICBjb2x1bW5fc3BlYyg0LCBpbWFnZSA9IHNwZWNfcGxvdChDcmVkaXRDYXJkX2luY29tZV9saXN0LCBzYW1lX2xpbSA9IFRSVUUpKSAlPiUKICBjb2x1bW5fc3BlYyg1LCBpbWFnZSA9IHNwZWNfcGxvdChDcmVkaXRDYXJkX2luY29tZV9saXN0LCBzYW1lX2xpbSA9IEZBTFNFKSkgJT4lCiAgY29sdW1uX3NwZWMoNiwgaW1hZ2UgPSBzcGVjX3Bsb3QoQ3JlZGl0Q2FyZF9pbmNvbWVfbGlzdCwgdHlwZSA9ICJwIikpCiNleHBlbmRpdHVyZQpDcmVkaXRDYXJkX2V4cGVuZGl0dXJlX2xpc3QgPC0gc3BsaXQoQ3JlZGl0Q2FyZCRleHBlbmRpdHVyZSwgQ3JlZGl0Q2FyZCRjYXJkKQppbmxpbmVfcGxvdF9leHBlbmRpdHVyZSA8LSBkYXRhLmZyYW1lKGNhcmQ9YygieWVzIiwgIm5vIiksIGJveHBsb3QgPSAiIiwgaGlzdG9ncmFtID0gIiIsbGluZTEgPSAiIiwgbGluZTIgPSAiIiwgcG9pbnRzMSA9ICIiKQppbmxpbmVfcGxvdF9leHBlbmRpdHVyZSAlPiUKICBrYmwoYm9va3RhYnMgPSBUUlVFKSAlPiUKICBrYWJsZV9wYXBlcihmdWxsX3dpZHRoID0gRkFMU0UpICU+JQogIGNvbHVtbl9zcGVjKDIsIGltYWdlID0gc3BlY19ib3hwbG90KENyZWRpdENhcmRfZXhwZW5kaXR1cmVfbGlzdCkpICU+JQogIGNvbHVtbl9zcGVjKDMsIGltYWdlID0gc3BlY19oaXN0KENyZWRpdENhcmRfZXhwZW5kaXR1cmVfbGlzdCkpICU+JQogIGNvbHVtbl9zcGVjKDQsIGltYWdlID0gc3BlY19wbG90KENyZWRpdENhcmRfZXhwZW5kaXR1cmVfbGlzdCwgc2FtZV9saW0gPSBUUlVFKSkgJT4lCiAgY29sdW1uX3NwZWMoNSwgaW1hZ2UgPSBzcGVjX3Bsb3QoQ3JlZGl0Q2FyZF9leHBlbmRpdHVyZV9saXN0LCBzYW1lX2xpbSA9IEZBTFNFKSkgJT4lCiAgY29sdW1uX3NwZWMoNiwgaW1hZ2UgPSBzcGVjX3Bsb3QoQ3JlZGl0Q2FyZF9leHBlbmRpdHVyZV9saXN0LCB0eXBlID0gInAiKSkKI2FnZQpDcmVkaXRDYXJkX2FnZV9saXN0IDwtIHNwbGl0KENyZWRpdENhcmQkYWdlLCBDcmVkaXRDYXJkJGNhcmQpCmlubGluZV9wbG90X2FnZSA8LSBkYXRhLmZyYW1lKGNhcmQ9YygieWVzIiwgIm5vIiksIGJveHBsb3QgPSAiIiwgaGlzdG9ncmFtID0gIiIsbGluZTEgPSAiIiwgbGluZTIgPSAiIiwgcG9pbnRzMSA9ICIiKQppbmxpbmVfcGxvdF9hZ2UgJT4lCiAga2JsKGJvb2t0YWJzID0gVFJVRSkgJT4lCiAga2FibGVfcGFwZXIoZnVsbF93aWR0aCA9IEZBTFNFKSAlPiUKICBjb2x1bW5fc3BlYygyLCBpbWFnZSA9IHNwZWNfYm94cGxvdChDcmVkaXRDYXJkX2FnZV9saXN0KSkgJT4lCiAgY29sdW1uX3NwZWMoMywgaW1hZ2UgPSBzcGVjX2hpc3QoQ3JlZGl0Q2FyZF9hZ2VfbGlzdCkpICU+JQogIGNvbHVtbl9zcGVjKDQsIGltYWdlID0gc3BlY19wbG90KENyZWRpdENhcmRfYWdlX2xpc3QsIHNhbWVfbGltID0gVFJVRSkpICU+JQogIGNvbHVtbl9zcGVjKDUsIGltYWdlID0gc3BlY19wbG90KENyZWRpdENhcmRfYWdlX2xpc3QsIHNhbWVfbGltID0gRkFMU0UpKSAlPiUKICBjb2x1bW5fc3BlYyg2LCBpbWFnZSA9IHNwZWNfcGxvdChDcmVkaXRDYXJkX2FnZV9saXN0LCB0eXBlID0gInAiKSkKI3JhdGlvIGV4cGVuZGl0dXJlIHRvIGluY29tZQpDcmVkaXRDYXJkX3JhdGlvX2xpc3QgPC0gc3BsaXQoQ3JlZGl0Q2FyZCRyYXRpb19leHBlbmRpdHVyZV9pbmNvbWUsIENyZWRpdENhcmQkY2FyZCkKaW5saW5lX3Bsb3RfcmF0aW8gPC0gZGF0YS5mcmFtZShjYXJkPWMoInllcyIsICJubyIpLCBib3hwbG90ID0gIiIsIGhpc3RvZ3JhbSA9ICIiLGxpbmUxID0gIiIsIGxpbmUyID0gIiIsIHBvaW50czEgPSAiIikKaW5saW5lX3Bsb3RfcmF0aW8gJT4lCiAga2JsKGJvb2t0YWJzID0gVFJVRSkgJT4lCiAga2FibGVfcGFwZXIoZnVsbF93aWR0aCA9IEZBTFNFKSAlPiUKICBjb2x1bW5fc3BlYygyLCBpbWFnZSA9IHNwZWNfYm94cGxvdChDcmVkaXRDYXJkX3JhdGlvX2xpc3QpKSAlPiUKICBjb2x1bW5fc3BlYygzLCBpbWFnZSA9IHNwZWNfaGlzdChDcmVkaXRDYXJkX3JhdGlvX2xpc3QpKSAlPiUKICBjb2x1bW5fc3BlYyg0LCBpbWFnZSA9IHNwZWNfcGxvdChDcmVkaXRDYXJkX3JhdGlvX2xpc3QsIHNhbWVfbGltID0gVFJVRSkpICU+JQogIGNvbHVtbl9zcGVjKDUsIGltYWdlID0gc3BlY19wbG90KENyZWRpdENhcmRfcmF0aW9fbGlzdCwgc2FtZV9saW0gPSBGQUxTRSkpICU+JQogIGNvbHVtbl9zcGVjKDYsIGltYWdlID0gc3BlY19wbG90KENyZWRpdENhcmRfcmF0aW9fbGlzdCwgdHlwZSA9ICJwIikpCmBgYAoKYGBge3IgbXlfc3VtbWFyeV90YWJsZSwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyB5b3VyIGNvZGUgaGVyZQojaW5jb21lCnN1bW1hcnlfaW5jb21lIDwtIENyZWRpdENhcmQgJT4lCiAgZ3JvdXBfYnkoY2FyZCkgJT4lCiAgc3VtbWFyaXNlKAogICAgTWluID0gbWluKGluY29tZSksCiAgICBNYXggPSBtYXgoaW5jb21lKSwKICAgIFExID0gcXVhbnRpbGUoaW5jb21lLCAwLjI1KSwKICAgIE1lZGlhbiA9IG1lZGlhbihpbmNvbWUpLAogICAgUTMgPSBxdWFudGlsZShpbmNvbWUsIDAuNzUpLAogICAgTWVhbiA9IG1lYW4oaW5jb21lKSwKICAgIFNkID0gc2QoaW5jb21lKSwKICAgIElRUiA9IElRUihpbmNvbWUpLAogICAgU3ggPSBJUVIoaW5jb21lKSAvIDIsCiAgICBWYXJfUGVyY2VudCA9IHNkKGluY29tZSkgLyBtZWFuKGluY29tZSksCiAgICBJUVJfVmFyX1BlcmNlbnQgPSBJUVIoaW5jb21lKSAvIG1lZGlhbihpbmNvbWUpLAogICAgU2tld25lc3MgPSBza2V3bmVzcyhpbmNvbWUpLAogICAgS3VydG9zaXMgPSBrdXJ0b3NpcyhpbmNvbWUpCiAgKQoKc3VtbWFyeV90YWJsZSA8LSBzdW1tYXJ5X2luY29tZSAlPiUKICBwaXZvdF9sb25nZXIoLWNhcmQpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBjYXJkLCB2YWx1ZXNfZnJvbSA9IHZhbHVlKQoKa2JsKHN1bW1hcnlfdGFibGUsIGRpZ2l0cyA9IDIsCiAgICBjYXB0aW9uID0gIlN1bW1hcnkgVGFibGU6IEluY29tZSBTdW1tYXJ5IFN0YXRpc3RpY3MgYnkgQ2FyZCIsCiAgICBjb2wubmFtZXMgPSBjKCIiLCAiTm8iLCAiWWVzIiksCiAgICByb3cubmFtZXMgPSBGQUxTRSwgZXNjYXBlID0gRkFMU0UpICU+JSBrYWJsZV9jbGFzc2ljKGZ1bGxfd2lkdGggPSBGLCBodG1sX2ZvbnQgPSAiQ2FtYnJpYSIpJT4lIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIikpCgojZXhwZW5kaXR1cmUKc3VtbWFyeV9leHBlbmRpdHVyZSA8LSBDcmVkaXRDYXJkICU+JQogIGdyb3VwX2J5KGNhcmQpICU+JQogIHN1bW1hcmlzZSgKICAgIE1pbiA9IG1pbihleHBlbmRpdHVyZSksCiAgICBNYXggPSBtYXgoZXhwZW5kaXR1cmUpLAogICAgUTEgPSBxdWFudGlsZShleHBlbmRpdHVyZSwgMC4yNSksCiAgICBNZWRpYW4gPSBtZWRpYW4oZXhwZW5kaXR1cmUpLAogICAgUTMgPSBxdWFudGlsZShleHBlbmRpdHVyZSwgMC43NSksCiAgICBNZWFuID0gbWVhbihleHBlbmRpdHVyZSksCiAgICBTZCA9IHNkKGV4cGVuZGl0dXJlKSwKICAgIElRUiA9IElRUihleHBlbmRpdHVyZSksCiAgICBTeCA9IElRUihleHBlbmRpdHVyZSkgLyAyLAogICAgVmFyX1BlcmNlbnQgPSBzZChleHBlbmRpdHVyZSkgLyBtZWFuKGV4cGVuZGl0dXJlKSwKICAgIElRUl9WYXJfUGVyY2VudCA9IElRUihleHBlbmRpdHVyZSkgLyBtZWRpYW4oZXhwZW5kaXR1cmUpLAogICAgU2tld25lc3MgPSBza2V3bmVzcyhleHBlbmRpdHVyZSksCiAgICBLdXJ0b3NpcyA9IGt1cnRvc2lzKGV4cGVuZGl0dXJlKQogICkKCnN1bW1hcnlfdGFibGUgPC0gc3VtbWFyeV9leHBlbmRpdHVyZSAlPiUKICBwaXZvdF9sb25nZXIoLWNhcmQpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBjYXJkLCB2YWx1ZXNfZnJvbSA9IHZhbHVlKQoKa2JsKHN1bW1hcnlfdGFibGUsIGRpZ2l0cyA9IDIsCiAgICBjYXB0aW9uID0gIlN1bW1hcnkgVGFibGU6IEV4cGVuZGl0dXJlIFN1bW1hcnkgU3RhdGlzdGljcyBCeSBDYXJkIiwKICAgIGNvbC5uYW1lcyA9IGMoIiIsICJObyIsICJZZXMiKSwKICAgIHJvdy5uYW1lcyA9IEZBTFNFLCBlc2NhcGUgPSBGQUxTRSkgJT4lIGthYmxlX2NsYXNzaWMoZnVsbF93aWR0aCA9IEYsIGh0bWxfZm9udCA9ICJDYW1icmlhIiklPiUga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiKSkKCiNhZ2UKc3VtbWFyeV9hZ2UgPC0gQ3JlZGl0Q2FyZCAlPiUKICBncm91cF9ieShjYXJkKSAlPiUKICBzdW1tYXJpc2UoCiAgICBNaW4gPSBtaW4oYWdlKSwKICAgIE1heCA9IG1heChhZ2UpLAogICAgUTEgPSBxdWFudGlsZShhZ2UsIDAuMjUpLAogICAgTWVkaWFuID0gbWVkaWFuKGFnZSksCiAgICBRMyA9IHF1YW50aWxlKGFnZSwgMC43NSksCiAgICBNZWFuID0gbWVhbihhZ2UpLAogICAgU2QgPSBzZChhZ2UpLAogICAgSVFSID0gSVFSKGFnZSksCiAgICBTeCA9IElRUihhZ2UpIC8gMiwKICAgIFZhcl9QZXJjZW50ID0gc2QoYWdlKSAvIG1lYW4oYWdlKSwKICAgIElRUl9WYXJfUGVyY2VudCA9IElRUihhZ2UpIC8gbWVkaWFuKGFnZSksCiAgICBTa2V3bmVzcyA9IHNrZXduZXNzKGFnZSksCiAgICBLdXJ0b3NpcyA9IGt1cnRvc2lzKGFnZSkKICApCgpzdW1tYXJ5X3RhYmxlIDwtIHN1bW1hcnlfYWdlICU+JQogIHBpdm90X2xvbmdlcigtY2FyZCkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGNhcmQsIHZhbHVlc19mcm9tID0gdmFsdWUpCgprYmwoc3VtbWFyeV90YWJsZSwgZGlnaXRzID0gMiwKICAgIGNhcHRpb24gPSAiU3VtbWFyeSBUYWJsZTogQWdlIFN1bW1hcnkgU3RhdGlzdGljcyBCeSBDYXJkIiwKICAgIGNvbC5uYW1lcyA9IGMoIiIsICJObyIsICJZZXMiKSwKICAgIHJvdy5uYW1lcyA9IEZBTFNFLCBlc2NhcGUgPSBGQUxTRSkgJT4lIGthYmxlX2NsYXNzaWMoZnVsbF93aWR0aCA9IEYsIGh0bWxfZm9udCA9ICJDYW1icmlhIiklPiUga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiKSkKCiNyYXRpbyBleHBlbmRpdHVyZSB0byBpbmNvbWUKCnN1bW1hcnlfcmF0aW8gPC0gQ3JlZGl0Q2FyZCAlPiUKICBncm91cF9ieShjYXJkKSAlPiUKICBzdW1tYXJpc2UoCiAgICBNaW4gPSBtaW4ocmF0aW9fZXhwZW5kaXR1cmVfaW5jb21lKSwKICAgIE1heCA9IG1heChyYXRpb19leHBlbmRpdHVyZV9pbmNvbWUpLAogICAgUTEgPSBxdWFudGlsZShyYXRpb19leHBlbmRpdHVyZV9pbmNvbWUsIDAuMjUpLAogICAgTWVkaWFuID0gbWVkaWFuKHJhdGlvX2V4cGVuZGl0dXJlX2luY29tZSksCiAgICBRMyA9IHF1YW50aWxlKHJhdGlvX2V4cGVuZGl0dXJlX2luY29tZSwgMC43NSksCiAgICBNZWFuID0gbWVhbihyYXRpb19leHBlbmRpdHVyZV9pbmNvbWUpLAogICAgU2QgPSBzZChyYXRpb19leHBlbmRpdHVyZV9pbmNvbWUpLAogICAgSVFSID0gSVFSKHJhdGlvX2V4cGVuZGl0dXJlX2luY29tZSksCiAgICBTeCA9IElRUihyYXRpb19leHBlbmRpdHVyZV9pbmNvbWUpIC8gMiwKICAgIFZhcl9QZXJjZW50ID0gc2QocmF0aW9fZXhwZW5kaXR1cmVfaW5jb21lKSAvIG1lYW4ocmF0aW9fZXhwZW5kaXR1cmVfaW5jb21lKSwKICAgIElRUl9WYXJfUGVyY2VudCA9IElRUihyYXRpb19leHBlbmRpdHVyZV9pbmNvbWUpIC8gbWVkaWFuKHJhdGlvX2V4cGVuZGl0dXJlX2luY29tZSksCiAgICBTa2V3bmVzcyA9IHNrZXduZXNzKHJhdGlvX2V4cGVuZGl0dXJlX2luY29tZSksCiAgICBLdXJ0b3NpcyA9IGt1cnRvc2lzKHJhdGlvX2V4cGVuZGl0dXJlX2luY29tZSkKICApCgpzdW1tYXJ5X3RhYmxlIDwtIHN1bW1hcnlfcmF0aW8gJT4lCiAgcGl2b3RfbG9uZ2VyKC1jYXJkKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gY2FyZCwgdmFsdWVzX2Zyb20gPSB2YWx1ZSkKCmtibChzdW1tYXJ5X3RhYmxlLCBkaWdpdHMgPSAyLAogICAgY2FwdGlvbiA9ICJTdW1tYXJ5IFRhYmxlOiBSYXRpbyBvZiBleHBlbmRpdHVyZSB0byBpbmNvbWUgU3VtbWFyeSBTdGF0aXN0aWNzIEJ5IENhcmQiLAogICAgY29sLm5hbWVzID0gYygiIiwgIk5vIiwgIlllcyIpLAogICAgcm93Lm5hbWVzID0gRkFMU0UsIGVzY2FwZSA9IEZBTFNFKSAlPiUga2FibGVfY2xhc3NpYyhmdWxsX3dpZHRoID0gRiwgaHRtbF9mb250ID0gIkNhbWJyaWEiKSU+JSBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIpKQoKYGBgCg==