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

No Variable Stats / Values Freqs (% of Valid) Graph Missing
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

Mean Std.Dev Min Median Max N.Valid Pct.Valid
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

Mean Std.Dev Min Median Max N.Valid Pct.Valid
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

Mean Std.Dev Min Median Max N.Valid Pct.Valid
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

Mean Std.Dev Min Median Max N.Valid Pct.Valid
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