1 Introduction

This will briefly introduce the steps for taking random samples from a finite population. There are two major types of sampling plans: probabilistic and non-probabilistic sampling plans. The probabilistic sampling plans generate statistically valid data based on which one can perform inferential statistical analysis.

In this project, we consider three probabilistic sampling plans: simple random sampling (SRS), stratified sampling, and systematic sampling. We will use the loan default status as a reference variable to assess the performance of the three sampling plans.

The Bank loan data set will be treated as a finite population. After we load the data to R, we will perform some data manipulation and exploratory data analysis to identify a stratification variable for stratified sampling.

loan01 = read.csv("https://pengdsci.github.io/datasets/SBAloan/w06-SBAnational01.csv", header = TRUE)[, -1]
loan02 = read.csv("https://pengdsci.github.io/datasets/SBAloan/w06-SBAnational02.csv", header = TRUE)[, -1]
loan03 = read.csv("https://pengdsci.github.io/datasets/SBAloan/w06-SBAnational03.csv", header = TRUE)[, -1]
loan04 = read.csv("https://pengdsci.github.io/datasets/SBAloan/w06-SBAnational04.csv", header = TRUE)[, -1]
loan05 = read.csv("https://pengdsci.github.io/datasets/SBAloan/w06-SBAnational05.csv", header = TRUE)[, -1]
loan06 = read.csv("https://pengdsci.github.io/datasets/SBAloan/w06-SBAnational06.csv", header = TRUE)[, -1]
loan07 = read.csv("https://pengdsci.github.io/datasets/SBAloan/w06-SBAnational07.csv", header = TRUE)[, -1]
loan08 = read.csv("https://pengdsci.github.io/datasets/SBAloan/w06-SBAnational08.csv", header = TRUE)[, -1]
loan09 = read.csv("https://pengdsci.github.io/datasets/SBAloan/w06-SBAnational09.csv", header = TRUE)[, -1]
loan = rbind(loan01, loan02, loan03, loan04, loan05, loan06, loan07, loan08, loan09)

2 Identifying A Stratification Variable

We use the 2-digit NAICS code as the stratification variable to define the sub-population.

2.1 2-Digit NAICS Codes

We will still use NAICS to create a categorical variable that is operational in practice. Recall that in the last note, we summarized the distribution of NAICS in the following table.

naics =as.character(loan$NAICS)  # make a character vector
N=length(naics)                  # find the size of the data. 
f.table = -sort(-table(naics))   # sort the vector in descending order
n = length(f.table)              # find the number of distinct industries
n.0 = sum(f.table < 900)         # industry with less than 0.1% of the population size
# A note of length of R variable name: the latest version of R has changed  
# the maximum length of variable names from 256 characters to 10,000 characters. 
# We should try our best to give meaningful names to R variables.
kable(cbind(Population.size = N, Number.of.Industries=n, Sub.Pop.less.1000 = n.0))
Population.size Number.of.Industries Sub.Pop.less.1000
899164 1312 1140

The course web page provides two useful tables. One of the tables https://sta490.s3.amazonaws.com/w03-NAICS-Categories.jpg in the article listed categories based on the first digits of NAICS code. The other related table gives the loan default rate in the corresponding industries https://sta490.s3.amazonaws.com/w03-NAICS-Default-Rates.jpg. You can download these two tables to your local drive and include them in your R Markdown document if you want to practice and reproduce this report.

For the convenience of referring to these tables, I include these two tables in this document.

include_graphics("img/w08-NAICS-Categories.jpg")
List of all industries using the first two digits of the NAICS code

List of all industries using the first two digits of the NAICS code

include_graphics("img/w08-NAICS-Default-Rates.jpg")
List of all industries using the first two digits of the NAICS code and the corresponding loan default rates

List of all industries using the first two digits of the NAICS code and the corresponding loan default rates

Next, we explore the frequency distribution of the 2-digit NAICS codes and decide the potential combinations of categories with a small size.

NAICS.2.digits = substr(loan$NAICS, 1, 2)   # extract the first two digits of the NAICS code
loan$NAICS2Digit = NAICS.2.digits           # add the above two-digit variable the loan data
freq.table = table(NAICS.2.digits)          # create a regular frequency table
kable(freq.table)                           # convert the regular frequency table to kable
NAICS.2.digits Freq
0 201948
11 9005
21 1851
22 663
23 66646
31 11809
32 17936
33 38284
42 48743
44 84737
45 42514
48 20310
49 2221
51 11379
52 9496
53 13632
54 68170
55 257
56 32685
61 6425
62 55366
71 14640
72 67600
81 72618
92 229

Several patterns you observe from the above table:

  • 201948 businesses do not have a NAICS code. Since I will use the 2-digit NAICS code to stratify the population. This variable will be included in the study population that will be defined soon.

  • Several categories (21, 22, 49, 55, 92) have relatively small sizes. Since categories 48 and 49 are both transportation and warehouse industries, we will combine the two as indicated in the above two tables.

  • As we can see from the above two tables, several industries have different codes. We will combine these codes. In other words, we need to modify the 2-digit code to define the final stratification for stratified sampling.

2.2 Combining Categories

We now combine categories suggested in the above NAICS tables in a meaningful way. Before we combine the NAICS codes, we present an example to illustrate how to combine categories using R.

cate.vec0=c(1,4,3,6,7,3,6,5,4,6,4,5,8,9,4,3,4,7,3)  # vector of category labels
cate.vec=c(1,4,3,6,7,3,6,5,4,6,4,5,8,9,4,3,4,7,3)   # a copy of the vector of category labels
labs.2.collapse = c(1,6,7)                          # define a vector to store categories {1,6,7}
logic.vec=cate.vec %in% labs.2.collapse             # TRUE/FALSE ==> match not no-match
cate.vec[logic.vec] = 99                            # if matches (i.e., 1, 5, 7), the value 
                                                    # will be replaced by 99
matx=rbind(cate.vec0=cate.vec0, cate.vec=cate.vec)  # check the results
colnames(matx) = 1:length(cate.vec)                 # next kable() function requires a column names
kable(matx)

We now combine the following sets of 2-digit NAICS codes: (31, 32, 33) will be relabeled as 313, (48, 49) as 489, and (44, 45) as 445. We use strNACIS to denote the resulting stratification variable.

cate.31.33=c("31","32","33")                      # combining categories 31, 32, and 33
cate.48.49 = c("48", "49")
cate.44.45 = c("44", "45")
NAICS2Digit0 = loan$NAICS2Digit                   # extract the 2-digit NAICS
NAICS2Digit =  loan$NAICS2Digit                   # extract the 2-digit NAICS-copy
## combining 31,32, and 33
logic.31.33=NAICS2Digit %in% cate.31.33           # Identify the three categories: 31, 32, 33.
NAICS2Digit[logic.31.33] = 313                      # replace 31, 32, 33 with 313
## combining 44 and 45
logic.44.45=NAICS2Digit %in% cate.44.45           # Identify the three categories: 44 and 45.
NAICS2Digit[logic.44.45] = 445 
## combining 48 and 49
logic.48.49=NAICS2Digit %in% cate.48.49           # Identify the three categories: 48 and 49.
NAICS2Digit[logic.48.49] = 489 
# check the result
# list(tab.naics0=table(NAICS2Digit0),tab.naics=table(NAICS2Digit))   # check the result
### final step
loan$strNAICS = NAICS2Digit
kable(table(loan$strNAICS))
Var1 Freq
0 201948
11 9005
21 1851
22 663
23 66646
313 68029
42 48743
445 127251
489 22531
51 11379
52 9496
53 13632
54 68170
55 257
56 32685
61 6425
62 55366
71 14640
72 67600
81 72618
92 229

2.3 Loan Default Rates by Industry

We now find the loan default rates by industry defined by the stratification variable strNAICS. The loan default status can be defined by the variable MIS_Status. The following table gives the default rates by industry.

x.table = table(loan$strNAICS, loan$MIS_Status)
no.lab = x.table[,1]      # first column consists of unknown default label
default = x.table[,2]
no.default = x.table[,3]
default.rate = round(100*default/(default+no.default),1)
default.status.rate = cbind(no.lab = no.lab, 
                          default = default, 
                          no.default = no.default,
                          default.rate=default.rate)
kable(default.status.rate)
no.lab default no.default default.rate
0 281 16799 184868 8.3
11 10 812 8183 9.0
21 0 157 1694 8.5
22 1 94 568 14.2
23 154 15463 51029 23.3
313 126 10438 57465 15.4
42 70 9480 39193 19.5
445 276 28868 98107 22.7
489 123 5939 16469 26.5
51 17 2821 8541 24.8
52 26 2692 6778 28.4
53 44 3904 9684 28.7
54 248 12957 54965 19.1
55 1 26 230 10.2
56 156 7661 24868 23.6
61 24 1552 4849 24.2
62 102 5736 49528 10.4
71 24 3013 11603 20.6
72 89 14882 52629 22.0
81 223 14229 58166 19.7
92 2 35 192 15.4

2.4 Study Population

Based on the above frequency distribution of the modified 2-digit NAICS codes (the 3-digit codes are combined categories). We use the following inclusion rule to define the study population: excluding small size categories 20, 21, 55, 92, and unclassified businesses with NAICS code 0.

del.categories = c("0", "21", "22", "55", "92")       # categories to be deleted in 
                                                      # the original population
del.obs.status = !(loan$strNAICS %in% del.categories) # deletion status. ! negation operator
study.pop = loan[del.obs.status,]                     # excluding the categories
kable(t(table(study.pop$strNAICS)))                   # Checking correctness operation
11 23 313 42 445 489 51 52 53 54 56 61 62 71 72 81
9005 66646 68029 48743 127251 22531 11379 9496 13632 68170 32685 6425 55366 14640 67600 72618

So we have defined our study population! The new population size is 694216.

3 Sampling Plans

In this section, we are implementing three sampling plans. In each sampling plan, we select 3000 observations in the corresponding samples. The sample size is slightly less than 5% of the study population size. We use without-replacement sampling plans for all three probabilistic sample plans.

3.1 Simple Random Sampling

We define a sampling list and add it to the study population.

study.pop$sampling.frame = 1:length(study.pop$GrAppv)   # sampling list
# names(study.pop)                                      # checking the sampling list variable
sampled.list = sample(1:length(study.pop$GrAppv), 3000) # sampling the list
SRS.sample = study.pop[sampled.list,]                   # extract the sampling units (observations)
## dimension check
dim(SRS.sample )                                        # checking the sample size
[1] 3000   30

3.2 Systematic sampling

We can choose a random integer that is less than the jump size (231 in our case) to guarantee to obtain enough samples.

jump.size = dim(study.pop)[1]%/%3000   # find the jump size in the systematic sampling
# jump.size
rand.starting.pt=sample(1:jump.size,1) # find the random starting value
sampling.id = seq(rand.starting.pt, dim(study.pop)[1], jump.size)  # sampling ID
#length(sampling.id)
sys.sample=study.pop[sampling.id,]    # extract the sampling units of systematic samples
dim(sys.sample)
[1] 3006   30

Because the jump size involves rounding error and the population is large, the actual systematic sample size is slightly different from the target size. In this report, I used the integral part of the actual jump size. The actual systematic sampling size is slightly bigger than the target size. We can take away some records from the systematic sample to make the size to be equal to the target size.

3.3 Stratified Sampling

We take an SRS from each individual stratum. The sample size should be approximately proportional to the size of the corresponding stratum.

First, we calculate the SRS size for each stratum and then take the SRS from the corresponding stratum. The following table shows the sub-sample sizes.

freq.table = table(study.pop$strNAICS)  # frequency table of strNAICS
rel.freq = freq.table/sum(freq.table)   # relative frequency 
strata.size = round(rel.freq*3000)      # strata size allocation
strata.names=names(strata.size)         # extract strNAICS names for accuracy checking
#list(strata.names=names(strata.size), 
     #strata.size = strata.size, 
     #sample.size = sum(strata.size))
kable(t(strata.size))
11 23 313 42 445 489 51 52 53 54 56 61 62 71 72 81
39 288 294 211 550 97 49 41 59 295 141 28 239 63 292 314

When coding, we use a loop to take simple random samples from each stratum and then combine them to get the stratified sample.

strata.sample = study.pop[1,]    # create a reference data frame
strata.sample$add.id = 1         # add a temporary ID to because in the loop
# i =2                           # testing a single iteration
for (i in 1:length(strata.names)){
   ith.strata.names = strata.names[i]   # extract data frame names
   ith.strata.size = strata.size[i]     # allocated stratum size
   # The following code identifies observations to be selected
   ith.sampling.id = which(study.pop$strNAICS==ith.strata.names) 
   ith.strata = study.pop[ith.sampling.id,]  # i-th stratified population
   ith.strata$add.id = 1:dim(ith.strata)[1]  # add sampling list/frame
   # The following code generates a subset of random ID
   ith.sampling.id = sample(1:dim(ith.strata)[1], ith.strata.size) 
   ## Create a selection status -- pay attention to the operator: %in% 
   ith.sample =ith.strata[ith.strata$add.id %in%ith.sampling.id,]
   ## dim(ith.sample)         $ check the sample
   strata.sample = rbind(strata.sample, ith.sample)  # stack all dataframe!
 }
 # dim(strata.sample)
 strat.sample.final = strata.sample[-1,]     # drop the temporary stratum ID
# kable(head(strat.sample.final[1:5,5]))        # accuracy check! only show the first 5 variables

4 Performance Analysis of Random Samples

In this section, we perform a comparative analysis of the three random samples. One metric we can use is the default rate in each industry defined by the first two digits of NAICS classification code. That was also used as the stratification variable in the stratified sampling plan.

4.1 Population-level Default Rates

We have calculated the default rate across the industries in the previous section. That table includes the category with no NAICS classification code. We will use this population-level industry-specific rate as a reference and compare it with the sample-level industry-specific default rates.

x.table = table(loan$strNAICS, loan$MIS_Status)
no.lab = x.table[,1]   # first column consists of unknown default label
default = x.table[,2]
no.default = x.table[,3]
default.rate = round(100*default/(default+no.default),1)
 default.status.rate = cbind(no.lab = no.lab, 
                          default = default, 
                          no.default = no.default,
                          default.rate=default.rate)
kable(default.status.rate, caption = "Population size, default counts, 
                                      and population default rates")
Population size, default counts, and population default rates
no.lab default no.default default.rate
0 281 16799 184868 8.3
11 10 812 8183 9.0
21 0 157 1694 8.5
22 1 94 568 14.2
23 154 15463 51029 23.3
313 126 10438 57465 15.4
42 70 9480 39193 19.5
445 276 28868 98107 22.7
489 123 5939 16469 26.5
51 17 2821 8541 24.8
52 26 2692 6778 28.4
53 44 3904 9684 28.7
54 248 12957 54965 19.1
55 1 26 230 10.2
56 156 7661 24868 23.6
61 24 1552 4849 24.2
62 102 5736 49528 10.4
71 24 3013 11603 20.6
72 89 14882 52629 22.0
81 223 14229 58166 19.7
92 2 35 192 15.4

4.2 Industry-Specific Default Rates based on SRS

For comparison, we construct the following table that includes the industry-specific default rates.

 # names(SRS.sample)
x.table = table(SRS.sample$strNAICS, SRS.sample$MIS_Status)
no.lab.srs = x.table[,1]      # first column consists of unknown default label
default.srs = x.table[,2]
no.default.srs = x.table[,3]
default.rate.srs = round(100*default.srs/(default.srs+no.default.srs),1)
##
industry.code = names(default.rate.srs)    # extract NSICS code
industry.name=c("Agri-forest-fish-hunt","Construction",
                "Manufacturing", "Wholesale-trade", "Retail-trade",
                "Transport-warehousing","Information", "Finance-insurance",
                "Real-estate-rental","Prof-sci-tech-ser",
                "Admin-support-waste-mgnt-remed", "Edu-serv",
                "Healthcare-social-assist","Arts-entertain-rec",
                "Accommodation-food-ser", "Other-ser(no-public-admin)")  # actual industry names!
default.rate.pop = default.rate[industry.code]
# cbind(industry.code,industry.name)
SRS.pop.rates = cbind(default.rate.pop,default.rate.srs)
rownames(SRS.pop.rates) = industry.name
kable(SRS.pop.rates, caption="Comparison of industry-specific default rates 
                               between population and the SRS.")
Comparison of industry-specific default rates between population and the SRS.
default.rate.pop default.rate.srs
Agri-forest-fish-hunt 9.0 4.4
Construction 23.3 27.2
Manufacturing 15.4 16.5
Wholesale-trade 19.5 19.3
Retail-trade 22.7 24.1
Transport-warehousing 26.5 29.7
Information 24.8 12.5
Finance-insurance 28.4 24.4
Real-estate-rental 28.7 28.4
Prof-sci-tech-ser 19.1 19.8
Admin-support-waste-mgnt-remed 23.6 24.4
Edu-serv 24.2 14.3
Healthcare-social-assist 10.4 10.8
Arts-entertain-rec 20.6 22.2
Accommodation-food-ser 22.0 22.1
Other-ser(no-public-admin) 19.7 21.5

Some of the industry-specific default rates seem to be significantly different. More visual comparisons will be given in the next section.

4.3 Industry-specific Rates- Systematics Sample

We will use the sample stratification variable to find the industry-specific rates based on the systematic sample. The following table will include rates of population, SRS, and systematic random samples.

x.table = table(sys.sample$strNAICS, sys.sample$MIS_Status)
no.lab.sys = x.table[,1]      # The first column consists of an unknown default label
default.sys = x.table[,2]
no.default.sys = x.table[,3]
default.rate.sys = round(100*default.sys/(default.sys+no.default.sys),1)
sys.SRS.pop.rates = cbind(default.rate.pop, default.rate.srs, default.rate.sys)
rownames(SRS.pop.rates) = industry.name
kable(sys.SRS.pop.rates, caption="Comparison of industry-specific default rates 
                               between population, SRS, and Systematic Sample.")
Comparison of industry-specific default rates between population, SRS, and Systematic Sample.
default.rate.pop default.rate.srs default.rate.sys
11 9.0 4.4 12.2
23 23.3 27.2 23.7
313 15.4 16.5 15.4
42 19.5 19.3 20.9
445 22.7 24.1 19.9
489 26.5 29.7 20.4
51 24.8 12.5 11.1
52 28.4 24.4 15.2
53 28.7 28.4 24.0
54 19.1 19.8 18.4
56 23.6 24.4 21.7
61 24.2 14.3 42.3
62 10.4 10.8 7.2
71 20.6 22.2 18.5
72 22.0 22.1 22.1
81 19.7 21.5 20.2

It seems that the systematic sample performs better than the SRS sample.

4.4 Industry-specific Default Rates- Stratified Sample

In this section, we put all the information in the following table.

#strat.sample.final
x.table = table(strat.sample.final$strNAICS, strat.sample.final$MIS_Status)
no.lab.str = x.table[,1]      # The first column consists of an unknown default label
default.str = x.table[,2]
no.default.str = x.table[,3]
default.rate.str = round(100*default.str/(default.str+no.default.str),1)
str.SRS.pop.rates = cbind(default.rate.pop, default.rate.srs, default.rate.sys, default.rate.str)
rownames(str.SRS.pop.rates) = industry.name
kable(str.SRS.pop.rates, caption="Comparison of industry-specific default rates 
                               between population, SRS, Systematic Sample, 
                               and Stratified Samples.")
Comparison of industry-specific default rates between population, SRS, Systematic Sample, and Stratified Samples.
default.rate.pop default.rate.srs default.rate.sys default.rate.str
Agri-forest-fish-hunt 9.0 4.4 12.2 12.8
Construction 23.3 27.2 23.7 21.9
Manufacturing 15.4 16.5 15.4 12.7
Wholesale-trade 19.5 19.3 20.9 19.4
Retail-trade 22.7 24.1 19.9 22.0
Transport-warehousing 26.5 29.7 20.4 21.6
Information 24.8 12.5 11.1 18.4
Finance-insurance 28.4 24.4 15.2 22.0
Real-estate-rental 28.7 28.4 24.0 27.1
Prof-sci-tech-ser 19.1 19.8 18.4 20.7
Admin-support-waste-mgnt-remed 23.6 24.4 21.7 22.7
Edu-serv 24.2 14.3 42.3 28.6
Healthcare-social-assist 10.4 10.8 7.2 10.0
Arts-entertain-rec 20.6 22.2 18.5 17.5
Accommodation-food-ser 22.0 22.1 22.1 20.5
Other-ser(no-public-admin) 19.7 21.5 20.2 24.8

5 Visualization - Visual Comparison

In the previous section, we calculated the industry-specific default rates for population, SRS, systematic, and stratified samples. We now create a statistical graphic to compare the default rates among the samples.

n=length(default.rate.pop)
#par(bg = 'gray')
# empty plot
plot(NULL, xlim=c(0,n), ylim=c(0, 50), xlab="", ylab ="", axes=FALSE)
title("Comparison of Industry-specific Default Rates")
points(1:n, as.vector(default.rate.pop), pch=16, col=2, cex = 0.8)
lines(1:n, as.vector(default.rate.pop), lty=1, col=2, cex = 0.8)
#
points(1:n, as.vector(default.rate.srs), pch=17, col=3, cex = 0.8)
lines(1:n, as.vector(default.rate.srs), lty=2, col=3, cex = 0.8)
#
points(1:n, as.vector(default.rate.sys), pch=19, col=4, cex = 0.8)
lines(1:n, as.vector(default.rate.sys), lty=3, col=4, cex = 0.8)
#
points(1:n, as.vector(default.rate.str), pch=20, col=5, cex = 0.8)
lines(1:n, as.vector(default.rate.str), lty=4, col=5, cex = 0.8)
#
axis(1,at=1:n, label=industry.code, las = 2)
axis(2)
#
rowMax=apply(str.SRS.pop.rates, 1, max) # max default rate in each industry
segments(1:n, rep(0,n), 1:n, rowMax, lty=2, col="lightgray", lwd = 0.5)
legend("topright", c("Pop", "SRS", "Sys", "Str"), lty=1:4, col=2:5, pch=c(16,17,19,20), cex=0.6, bty="n")

For ease of interpretation, I make the following table to map the NAICS codes and the corresponding industries.

kable(cbind(industry.name, industry.code), 
      caption="Industry NAICS codes and the corresponding names")
Industry NAICS codes and the corresponding names
industry.name industry.code
Agri-forest-fish-hunt 11
Construction 23
Manufacturing 313
Wholesale-trade 42
Retail-trade 445
Transport-warehousing 489
Information 51
Finance-insurance 52
Real-estate-rental 53
Prof-sci-tech-ser 54
Admin-support-waste-mgnt-remed 56
Edu-serv 61
Healthcare-social-assist 62
Arts-entertain-rec 71
Accommodation-food-ser 72
Other-ser(no-public-admin) 81

Since the above graph is based on one-time samples, the variation is not included. Therefore, we need more information to do a meaningful comparison. For example, we can package the code in this Markdown document and take, say 1000, samples based on each sampling plan. We then can find the mean industry-specific default rates and the corresponding variation.

5.1 Critiques of Visual Representation

Visual representation is a key component in effective storytelling. As an example, we critique the figure of performance comparison of the three sampling plans in the previous section and seek improvements for effective representation.

The following figure is modified based on the comparison line plot given in the previous section.

n=length(default.rate.pop)
#par(bg = 'gray')
# empty plot
plot(NULL, xlim=c(0,n), ylim=c(0, 50), xlab="", ylab ="", axes=FALSE)
# Light gray background
rect(par("usr")[1], par("usr")[3],
     par("usr")[2], par("usr")[4],
     col = "gray")

# Add white grid
grid(nx = NULL, ny = NULL,
     col = "white", lwd = 1)

title("Comparison of Industry-specific Default Rates")
points(1:n, as.vector(default.rate.pop), pch=16, col=2, cex = 0.8)
lines(1:n, as.vector(default.rate.pop), lty=1, col=2, cex = 0.8)
#
points(1:n, as.vector(default.rate.srs), pch=17, col=3, cex = 0.8)
lines(1:n, as.vector(default.rate.srs), lty=2, col=3, cex = 0.8)
#
points(1:n, as.vector(default.rate.sys), pch=19, col=4, cex = 0.8)
lines(1:n, as.vector(default.rate.sys), lty=3, col=4, cex = 0.8)
#
points(1:n, as.vector(default.rate.str), pch=20, col=5, cex = 0.8)
lines(1:n, as.vector(default.rate.str), lty=4, col=5, cex = 0.8)
#
axis(1,at=1:n, label=industry.code, las = 2)
axis(2)
#
rowMax=apply(str.SRS.pop.rates, 1, max) # max default rate in each industry
segments(1:n, rep(0,n), 1:n, rowMax, lty=2, col="lightgray", lwd = 0.5)
legend("topright", c("Pop", "SRS", "Sys", "Str"), lty=1:4, col=2:5, pch=c(16,17,19,20), cex=0.6, bty="n")

There’s a lot of ink here that doesn’t convey information relevant to the main point we’re trying to make.

  • Grey background: not only does it provide absolutely no information. it’s also unsightly. After we remove it, we will likely have to darken some of the lines.

  • Grid lines: it’s very unlikely that our audience cares about the exact values at each data point - it’s the pattern that matters. The grid lines compete with the pattern we’re trying to show.

  • Legend: It takes time to guess the abbreviation. It also confuses readers.

  • Tick marks: Why make the reader tilt his or her head to read?

  • Labels of X- and Y- Axis: labels are missing.

  • Title: The title should be more specific.

  • Line types: Use color and line type to differentiate - this will help people who have a color-impaired vision, and also any grey-scale copies of the poster you make (as for handouts).

  • Color coding: Avoid using use green and red colors in the same graphic to represent different objects. More than 99% of all color-blind people are suffering from a red-green color vision deficiency.

It’s easy to make a graph that looks cleaner and has a higher ratio of information-to-total ink:

n=length(default.rate.pop)
plot(NULL, xlim=c(0,n), ylim=c(0, 50), 
     xlab="Industry Classification Code", 
     ylab ="Default Rates (Percentage)", axes=FALSE) # empty plot
# Light gray background
rect(par("usr")[1], par("usr")[3],
     par("usr")[2], par("usr")[4],
     col = "gray")

# Add white grid
grid(nx = NULL, ny = NULL,
     col = "white", lwd = 1)

title("Comparison of Industry-specific Default Rates Based on Random Samples")
points(1:n, as.vector(default.rate.pop), pch=16, col="darkmagenta", cex = 0.8)
lines(1:n, as.vector(default.rate.pop),  lty=1, col="darkmagenta", cex = 0.8)
#
points(1:n, as.vector(default.rate.srs), pch=17, col="chartreuse4", cex = 0.8)
lines(1:n, as.vector(default.rate.srs), lty=1, col="chartreuse4", cex = 0.8)
#
points(1:n, as.vector(default.rate.sys), pch=19, col="darkblue", cex = 0.8)
lines(1:n, as.vector(default.rate.sys), lty=1, col="darkblue", cex = 0.8)
#
points(1:n, as.vector(default.rate.str), pch=20, col="darkcyan", cex = 0.8)
lines(1:n, as.vector(default.rate.str), lty=1, col="darkcyan", cex = 0.8)
#
axis(1,at=1:n, label=industry.code)
axis(2, las = 2)
#
clr = c("darkmagenta","chartreuse4","darkblue","darkcyan")
rowMax=apply(str.SRS.pop.rates, 1, max) # max default rate in each industry
#segments(1:n, rep(0,n), 1:n, rowMax, lty=2, col="lightgray", lwd = 0.5)
legend(2, 45, c("Population", "Simple Random Sampling", "Systematic Sampling", "Stratified Sampling"), lty=rep(1,4), col=clr, pch=c(16,17,19,20), cex=0.6, bty="n")

Removing the gray background will make the graph cleaner.

n=length(default.rate.pop)
plot(NULL, xlim=c(0,n), ylim=c(0, 50), 
     xlab="Industry Classification Code", 
     ylab ="Default Rates (Percentage)", axes=FALSE) # empty plot

title("Comparison of Industry-specific Default Rates Based on Random Samples")
points(1:n, as.vector(default.rate.pop), pch=16, col="darkmagenta", cex = 0.8)
lines(1:n, as.vector(default.rate.pop),  lty=1, col="darkmagenta", cex = 0.8)
#
points(1:n, as.vector(default.rate.srs), pch=17, col="chartreuse4", cex = 0.8)
lines(1:n, as.vector(default.rate.srs), lty=1, col="chartreuse4", cex = 0.8)
#
points(1:n, as.vector(default.rate.sys), pch=19, col="darkblue", cex = 0.8)
lines(1:n, as.vector(default.rate.sys), lty=1, col="darkblue", cex = 0.8)
#
points(1:n, as.vector(default.rate.str), pch=20, col="darkcyan", cex = 0.8)
lines(1:n, as.vector(default.rate.str), lty=1, col="darkcyan", cex = 0.8)
#
axis(1,at=1:n, label=industry.code)
axis(2, las = 2)
#
clr = c("darkmagenta","chartreuse4","darkblue","darkcyan")
rowMax=apply(str.SRS.pop.rates, 1, max) # max default rate in each industry
#segments(1:n, rep(0,n), 1:n, rowMax, lty=2, col="lightgray", lwd = 0.5)
legend(2, 45, c("Population", "Simple Random Sampling", "Systematic Sampling", "Stratified Sampling"), lty=rep(1,4), col=clr, pch=c(16,17,19,20), cex=0.6, bty="n")

LS0tDQp0aXRsZTogIlJhbmRvbSBTYW1wbGluZyBQbGFucyBhbmQgQ29tcGFyaXNvbnMgIFxuIFtBIEJyaWVmIFJlcG9ydFtdICINCmF1dGhvcjogIkNoZW5nIFBlbmciDQpkYXRlOiAiICINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHNtb290aF9zY3JvbGw6IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdGhlbWU6IHJlYWRhYmxlDQogIHdvcmRfZG9jdW1lbnQ6IA0KICAgIHRvYzogbm8NCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAga2VlcF9tZDogeWVzDQogIHBkZl9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICBmaWdfd2lkdGg6IDUNCiAgICBmaWdfaGVpZ2h0OiA0DQotLS0NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQpoMS50aXRsZSB7DQogIGZvbnQtc2l6ZTogMjRweDsNCiAgY29sb3I6IERhcmtSZWQ7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmg0LmF1dGhvciB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgY29sb3I6IERhcmtSZWQ7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmg0LmRhdGUgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICBmb250LXNpemU6IDE4cHg7DQogIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICBjb2xvcjogRGFya0JsdWU7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmgxIHsgLyogSGVhZGVyIDMgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDIycHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KaDIgeyAvKiBIZWFkZXIgMyAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoMyB7IC8qIEhlYWRlciAzIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxNXB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmg0IHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCjwvc3R5bGU+DQoNCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQoNCmlmICghcmVxdWlyZSgia25pdHIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KICAgbGlicmFyeShrbml0cikNCn0NCg0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5ncyA9IEZBTFNFLCAgIA0KICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBUUlVFLCAgIA0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkEpDQpgYGANCg0KDQoNCiMgSW50cm9kdWN0aW9uDQpUaGlzIHdpbGwgYnJpZWZseSBpbnRyb2R1Y2UgdGhlIHN0ZXBzIGZvciB0YWtpbmcgcmFuZG9tIHNhbXBsZXMgZnJvbSBhIGZpbml0ZSBwb3B1bGF0aW9uLiBUaGVyZSBhcmUgdHdvIG1ham9yIHR5cGVzIG9mIHNhbXBsaW5nIHBsYW5zOiBwcm9iYWJpbGlzdGljIGFuZCBub24tcHJvYmFiaWxpc3RpYyBzYW1wbGluZyBwbGFucy4gVGhlIHByb2JhYmlsaXN0aWMgc2FtcGxpbmcgcGxhbnMgZ2VuZXJhdGUgc3RhdGlzdGljYWxseSB2YWxpZCBkYXRhIGJhc2VkIG9uIHdoaWNoIG9uZSBjYW4gcGVyZm9ybSBpbmZlcmVudGlhbCBzdGF0aXN0aWNhbCBhbmFseXNpcy4gDQoNCkluIHRoaXMgcHJvamVjdCwgd2UgY29uc2lkZXIgdGhyZWUgcHJvYmFiaWxpc3RpYyBzYW1wbGluZyBwbGFuczogc2ltcGxlIHJhbmRvbSBzYW1wbGluZyAoU1JTKSwgc3RyYXRpZmllZCBzYW1wbGluZywgYW5kIHN5c3RlbWF0aWMgc2FtcGxpbmcuIFdlIHdpbGwgdXNlIHRoZSBsb2FuIGRlZmF1bHQgc3RhdHVzIGFzIGEgcmVmZXJlbmNlIHZhcmlhYmxlIHRvIGFzc2VzcyB0aGUgcGVyZm9ybWFuY2Ugb2YgdGhlIHRocmVlIHNhbXBsaW5nIHBsYW5zLg0KDQpUaGUgKipCYW5rIGxvYW4qKiBkYXRhIHNldCB3aWxsIGJlIHRyZWF0ZWQgYXMgYSBmaW5pdGUgcG9wdWxhdGlvbi4gQWZ0ZXIgd2UgbG9hZCB0aGUgZGF0YSB0byBSLCB3ZSB3aWxsIHBlcmZvcm0gc29tZSBkYXRhIG1hbmlwdWxhdGlvbiBhbmQgZXhwbG9yYXRvcnkgZGF0YSBhbmFseXNpcyB0byBpZGVudGlmeSBhIHN0cmF0aWZpY2F0aW9uIHZhcmlhYmxlIGZvciBzdHJhdGlmaWVkIHNhbXBsaW5nLiANCg0KDQpgYGB7cn0NCmxvYW4wMSA9IHJlYWQuY3N2KCJodHRwczovL3Blbmdkc2NpLmdpdGh1Yi5pby9kYXRhc2V0cy9TQkFsb2FuL3cwNi1TQkFuYXRpb25hbDAxLmNzdiIsIGhlYWRlciA9IFRSVUUpWywgLTFdDQpsb2FuMDIgPSByZWFkLmNzdigiaHR0cHM6Ly9wZW5nZHNjaS5naXRodWIuaW8vZGF0YXNldHMvU0JBbG9hbi93MDYtU0JBbmF0aW9uYWwwMi5jc3YiLCBoZWFkZXIgPSBUUlVFKVssIC0xXQ0KbG9hbjAzID0gcmVhZC5jc3YoImh0dHBzOi8vcGVuZ2RzY2kuZ2l0aHViLmlvL2RhdGFzZXRzL1NCQWxvYW4vdzA2LVNCQW5hdGlvbmFsMDMuY3N2IiwgaGVhZGVyID0gVFJVRSlbLCAtMV0NCmxvYW4wNCA9IHJlYWQuY3N2KCJodHRwczovL3Blbmdkc2NpLmdpdGh1Yi5pby9kYXRhc2V0cy9TQkFsb2FuL3cwNi1TQkFuYXRpb25hbDA0LmNzdiIsIGhlYWRlciA9IFRSVUUpWywgLTFdDQpsb2FuMDUgPSByZWFkLmNzdigiaHR0cHM6Ly9wZW5nZHNjaS5naXRodWIuaW8vZGF0YXNldHMvU0JBbG9hbi93MDYtU0JBbmF0aW9uYWwwNS5jc3YiLCBoZWFkZXIgPSBUUlVFKVssIC0xXQ0KbG9hbjA2ID0gcmVhZC5jc3YoImh0dHBzOi8vcGVuZ2RzY2kuZ2l0aHViLmlvL2RhdGFzZXRzL1NCQWxvYW4vdzA2LVNCQW5hdGlvbmFsMDYuY3N2IiwgaGVhZGVyID0gVFJVRSlbLCAtMV0NCmxvYW4wNyA9IHJlYWQuY3N2KCJodHRwczovL3Blbmdkc2NpLmdpdGh1Yi5pby9kYXRhc2V0cy9TQkFsb2FuL3cwNi1TQkFuYXRpb25hbDA3LmNzdiIsIGhlYWRlciA9IFRSVUUpWywgLTFdDQpsb2FuMDggPSByZWFkLmNzdigiaHR0cHM6Ly9wZW5nZHNjaS5naXRodWIuaW8vZGF0YXNldHMvU0JBbG9hbi93MDYtU0JBbmF0aW9uYWwwOC5jc3YiLCBoZWFkZXIgPSBUUlVFKVssIC0xXQ0KbG9hbjA5ID0gcmVhZC5jc3YoImh0dHBzOi8vcGVuZ2RzY2kuZ2l0aHViLmlvL2RhdGFzZXRzL1NCQWxvYW4vdzA2LVNCQW5hdGlvbmFsMDkuY3N2IiwgaGVhZGVyID0gVFJVRSlbLCAtMV0NCmxvYW4gPSByYmluZChsb2FuMDEsIGxvYW4wMiwgbG9hbjAzLCBsb2FuMDQsIGxvYW4wNSwgbG9hbjA2LCBsb2FuMDcsIGxvYW4wOCwgbG9hbjA5KQ0KYGBgDQoNCg0KIyBJZGVudGlmeWluZyBBIFN0cmF0aWZpY2F0aW9uIFZhcmlhYmxlDQoNCldlIHVzZSB0aGUgMi1kaWdpdCBOQUlDUyBjb2RlIGFzIHRoZSBzdHJhdGlmaWNhdGlvbiB2YXJpYWJsZSB0byBkZWZpbmUgdGhlIHN1Yi1wb3B1bGF0aW9uLg0KDQojIyAyLURpZ2l0IE5BSUNTIENvZGVzDQoNCldlIHdpbGwgc3RpbGwgdXNlIE5BSUNTIHRvIGNyZWF0ZSBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlIHRoYXQgaXMgb3BlcmF0aW9uYWwgaW4gcHJhY3RpY2UuIFJlY2FsbCB0aGF0IGluIHRoZSBsYXN0IG5vdGUsIHdlIHN1bW1hcml6ZWQgdGhlIGRpc3RyaWJ1dGlvbiBvZiBOQUlDUyBpbiB0aGUgZm9sbG93aW5nIHRhYmxlLg0KDQpgYGB7ciBkYXRhLXNpemV9DQpuYWljcyA9YXMuY2hhcmFjdGVyKGxvYW4kTkFJQ1MpICAjIG1ha2UgYSBjaGFyYWN0ZXIgdmVjdG9yDQpOPWxlbmd0aChuYWljcykgICAgICAgICAgICAgICAgICAjIGZpbmQgdGhlIHNpemUgb2YgdGhlIGRhdGEuIA0KZi50YWJsZSA9IC1zb3J0KC10YWJsZShuYWljcykpICAgIyBzb3J0IHRoZSB2ZWN0b3IgaW4gZGVzY2VuZGluZyBvcmRlcg0KbiA9IGxlbmd0aChmLnRhYmxlKSAgICAgICAgICAgICAgIyBmaW5kIHRoZSBudW1iZXIgb2YgZGlzdGluY3QgaW5kdXN0cmllcw0Kbi4wID0gc3VtKGYudGFibGUgPCA5MDApICAgICAgICAgIyBpbmR1c3RyeSB3aXRoIGxlc3MgdGhhbiAwLjElIG9mIHRoZSBwb3B1bGF0aW9uIHNpemUNCiMgQSBub3RlIG9mIGxlbmd0aCBvZiBSIHZhcmlhYmxlIG5hbWU6IHRoZSBsYXRlc3QgdmVyc2lvbiBvZiBSIGhhcyBjaGFuZ2VkICANCiMgdGhlIG1heGltdW0gbGVuZ3RoIG9mIHZhcmlhYmxlIG5hbWVzIGZyb20gMjU2IGNoYXJhY3RlcnMgdG8gMTAsMDAwIGNoYXJhY3RlcnMuIA0KIyBXZSBzaG91bGQgdHJ5IG91ciBiZXN0IHRvIGdpdmUgbWVhbmluZ2Z1bCBuYW1lcyB0byBSIHZhcmlhYmxlcy4NCmthYmxlKGNiaW5kKFBvcHVsYXRpb24uc2l6ZSA9IE4sIE51bWJlci5vZi5JbmR1c3RyaWVzPW4sIFN1Yi5Qb3AubGVzcy4xMDAwID0gbi4wKSkNCmBgYA0KDQpUaGUgY291cnNlIHdlYiBwYWdlIHByb3ZpZGVzIHR3byB1c2VmdWwgdGFibGVzLiBPbmUgb2YgdGhlIHRhYmxlcyA8aHR0cHM6Ly9zdGE0OTAuczMuYW1hem9uYXdzLmNvbS93MDMtTkFJQ1MtQ2F0ZWdvcmllcy5qcGc+IGluIHRoZSBhcnRpY2xlIGxpc3RlZCBjYXRlZ29yaWVzIGJhc2VkIG9uIHRoZSBmaXJzdCBkaWdpdHMgb2YgTkFJQ1MgY29kZS4gVGhlIG90aGVyIHJlbGF0ZWQgdGFibGUgZ2l2ZXMgdGhlIGxvYW4gZGVmYXVsdCByYXRlIGluIHRoZSBjb3JyZXNwb25kaW5nIGluZHVzdHJpZXMgPGh0dHBzOi8vc3RhNDkwLnMzLmFtYXpvbmF3cy5jb20vdzAzLU5BSUNTLURlZmF1bHQtUmF0ZXMuanBnPi4gWW91IGNhbiBkb3dubG9hZCB0aGVzZSB0d28gdGFibGVzIHRvIHlvdXIgbG9jYWwgZHJpdmUgYW5kIGluY2x1ZGUgdGhlbSBpbiB5b3VyIFIgTWFya2Rvd24gZG9jdW1lbnQgaWYgeW91IHdhbnQgdG8gcHJhY3RpY2UgYW5kIHJlcHJvZHVjZSB0aGlzIHJlcG9ydC4gIA0KDQpGb3IgdGhlIGNvbnZlbmllbmNlIG9mIHJlZmVycmluZyB0byB0aGVzZSB0YWJsZXMsIEkgaW5jbHVkZSB0aGVzZSB0d28gdGFibGVzIGluIHRoaXMgZG9jdW1lbnQuDQoNCmBgYHtyIGZpZy5jYXA9Ikxpc3Qgb2YgYWxsIGluZHVzdHJpZXMgdXNpbmcgdGhlIGZpcnN0IHR3byBkaWdpdHMgb2YgdGhlIE5BSUNTIGNvZGUiLCBmaWcud2lkdGg9MywgZmlnLmxlbmd0aD01LCAgICAgIGZpZy5hbGlnbiA9ICJjZW50ZXIifQ0KaW5jbHVkZV9ncmFwaGljcygiaW1nL3cwOC1OQUlDUy1DYXRlZ29yaWVzLmpwZyIpDQpgYGANCg0KDQoNCg0KYGBge3IgZmlnLmNhcD0iTGlzdCBvZiBhbGwgaW5kdXN0cmllcyB1c2luZyB0aGUgZmlyc3QgdHdvIGRpZ2l0cyBvZiB0aGUgTkFJQ1MgY29kZSBhbmQgdGhlIGNvcnJlc3BvbmRpbmcgbG9hbiBkZWZhdWx0IHJhdGVzIiwgZmlnLndpZHRoPTMsIGZpZy5sZW5ndGg9NSwgICAgICBmaWcuYWxpZ24gPSAiY2VudGVyIn0NCmluY2x1ZGVfZ3JhcGhpY3MoImltZy93MDgtTkFJQ1MtRGVmYXVsdC1SYXRlcy5qcGciKQ0KYGBgDQpOZXh0LCB3ZSBleHBsb3JlIHRoZSBmcmVxdWVuY3kgZGlzdHJpYnV0aW9uIG9mIHRoZSAyLWRpZ2l0IE5BSUNTIGNvZGVzIGFuZCBkZWNpZGUgdGhlIHBvdGVudGlhbCBjb21iaW5hdGlvbnMgb2YgY2F0ZWdvcmllcyB3aXRoIGEgc21hbGwgc2l6ZS4NCg0KDQpgYGB7cn0NCk5BSUNTLjIuZGlnaXRzID0gc3Vic3RyKGxvYW4kTkFJQ1MsIDEsIDIpICAgIyBleHRyYWN0IHRoZSBmaXJzdCB0d28gZGlnaXRzIG9mIHRoZSBOQUlDUyBjb2RlDQpsb2FuJE5BSUNTMkRpZ2l0ID0gTkFJQ1MuMi5kaWdpdHMgICAgICAgICAgICMgYWRkIHRoZSBhYm92ZSB0d28tZGlnaXQgdmFyaWFibGUgdGhlIGxvYW4gZGF0YQ0KZnJlcS50YWJsZSA9IHRhYmxlKE5BSUNTLjIuZGlnaXRzKSAgICAgICAgICAjIGNyZWF0ZSBhIHJlZ3VsYXIgZnJlcXVlbmN5IHRhYmxlDQprYWJsZShmcmVxLnRhYmxlKSAgICAgICAgICAgICAgICAgICAgICAgICAgICMgY29udmVydCB0aGUgcmVndWxhciBmcmVxdWVuY3kgdGFibGUgdG8ga2FibGUNCmBgYA0KU2V2ZXJhbCBwYXR0ZXJucyB5b3Ugb2JzZXJ2ZSBmcm9tIHRoZSBhYm92ZSB0YWJsZToNCg0KKiAyMDE5NDggYnVzaW5lc3NlcyBkbyBub3QgaGF2ZSBhIE5BSUNTIGNvZGUuIFNpbmNlIEkgd2lsbCB1c2UgdGhlIDItZGlnaXQgTkFJQ1MgY29kZSB0byBzdHJhdGlmeSB0aGUgcG9wdWxhdGlvbi4gVGhpcyB2YXJpYWJsZSB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBzdHVkeSBwb3B1bGF0aW9uIHRoYXQgd2lsbCBiZSBkZWZpbmVkIHNvb24uDQoNCiogU2V2ZXJhbCBjYXRlZ29yaWVzICgyMSwgMjIsIDQ5LCA1NSwgOTIpIGhhdmUgcmVsYXRpdmVseSBzbWFsbCBzaXplcy4gU2luY2UgY2F0ZWdvcmllcyA0OCBhbmQgNDkgYXJlIGJvdGggdHJhbnNwb3J0YXRpb24gYW5kIHdhcmVob3VzZSBpbmR1c3RyaWVzLCB3ZSB3aWxsIGNvbWJpbmUgdGhlIHR3byBhcyBpbmRpY2F0ZWQgaW4gdGhlIGFib3ZlIHR3byB0YWJsZXMuDQoNCiogQXMgd2UgY2FuIHNlZSBmcm9tIHRoZSBhYm92ZSB0d28gdGFibGVzLCBzZXZlcmFsIGluZHVzdHJpZXMgaGF2ZSBkaWZmZXJlbnQgY29kZXMuIFdlIHdpbGwgY29tYmluZSB0aGVzZSBjb2Rlcy4gSW4gb3RoZXIgd29yZHMsIHdlIG5lZWQgdG8gbW9kaWZ5IHRoZSAyLWRpZ2l0IGNvZGUgdG8gZGVmaW5lIHRoZSBmaW5hbCBzdHJhdGlmaWNhdGlvbiBmb3Igc3RyYXRpZmllZCBzYW1wbGluZy4NCg0KIyMgQ29tYmluaW5nIENhdGVnb3JpZXMNCg0KV2Ugbm93IGNvbWJpbmUgY2F0ZWdvcmllcyBzdWdnZXN0ZWQgaW4gdGhlIGFib3ZlIE5BSUNTIHRhYmxlcyBpbiBhIG1lYW5pbmdmdWwgd2F5LiBCZWZvcmUgd2UgY29tYmluZSB0aGUgTkFJQ1MgY29kZXMsIHdlIHByZXNlbnQgYW4gZXhhbXBsZSB0byBpbGx1c3RyYXRlIGhvdyB0byBjb21iaW5lIGNhdGVnb3JpZXMgdXNpbmcgUi4NCg0KYGBge30NCmNhdGUudmVjMD1jKDEsNCwzLDYsNywzLDYsNSw0LDYsNCw1LDgsOSw0LDMsNCw3LDMpICAjIHZlY3RvciBvZiBjYXRlZ29yeSBsYWJlbHMNCmNhdGUudmVjPWMoMSw0LDMsNiw3LDMsNiw1LDQsNiw0LDUsOCw5LDQsMyw0LDcsMykgICAjIGEgY29weSBvZiB0aGUgdmVjdG9yIG9mIGNhdGVnb3J5IGxhYmVscw0KbGFicy4yLmNvbGxhcHNlID0gYygxLDYsNykgICAgICAgICAgICAgICAgICAgICAgICAgICMgZGVmaW5lIGEgdmVjdG9yIHRvIHN0b3JlIGNhdGVnb3JpZXMgezEsNiw3fQ0KbG9naWMudmVjPWNhdGUudmVjICVpbiUgbGFicy4yLmNvbGxhcHNlICAgICAgICAgICAgICMgVFJVRS9GQUxTRSA9PT4gbWF0Y2ggbm90IG5vLW1hdGNoDQpjYXRlLnZlY1tsb2dpYy52ZWNdID0gOTkgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBpZiBtYXRjaGVzIChpLmUuLCAxLCA1LCA3KSwgdGhlIHZhbHVlIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgd2lsbCBiZSByZXBsYWNlZCBieSA5OQ0KbWF0eD1yYmluZChjYXRlLnZlYzA9Y2F0ZS52ZWMwLCBjYXRlLnZlYz1jYXRlLnZlYykgICMgY2hlY2sgdGhlIHJlc3VsdHMNCmNvbG5hbWVzKG1hdHgpID0gMTpsZW5ndGgoY2F0ZS52ZWMpICAgICAgICAgICAgICAgICAjIG5leHQga2FibGUoKSBmdW5jdGlvbiByZXF1aXJlcyBhIGNvbHVtbiBuYW1lcw0Ka2FibGUobWF0eCkNCmBgYA0KDQpXZSBub3cgY29tYmluZSB0aGUgZm9sbG93aW5nIHNldHMgb2YgIDItZGlnaXQgTkFJQ1MgY29kZXM6ICgzMSwgMzIsIDMzKSB3aWxsIGJlIHJlbGFiZWxlZCBhcyAqKjMxMyoqLCAoNDgsIDQ5KSBhcyAqKjQ4OSoqLCBhbmQgKDQ0LCA0NSkgYXMgKio0NDUqKi4gIFdlIHVzZSBzdHJOQUNJUyB0byBkZW5vdGUgdGhlIHJlc3VsdGluZyBzdHJhdGlmaWNhdGlvbiB2YXJpYWJsZS4NCg0KYGBge3J9DQpjYXRlLjMxLjMzPWMoIjMxIiwiMzIiLCIzMyIpICAgICAgICAgICAgICAgICAgICAgICMgY29tYmluaW5nIGNhdGVnb3JpZXMgMzEsIDMyLCBhbmQgMzMNCmNhdGUuNDguNDkgPSBjKCI0OCIsICI0OSIpDQpjYXRlLjQ0LjQ1ID0gYygiNDQiLCAiNDUiKQ0KTkFJQ1MyRGlnaXQwID0gbG9hbiROQUlDUzJEaWdpdCAgICAgICAgICAgICAgICAgICAjIGV4dHJhY3QgdGhlIDItZGlnaXQgTkFJQ1MNCk5BSUNTMkRpZ2l0ID0gIGxvYW4kTkFJQ1MyRGlnaXQgICAgICAgICAgICAgICAgICAgIyBleHRyYWN0IHRoZSAyLWRpZ2l0IE5BSUNTLWNvcHkNCiMjIGNvbWJpbmluZyAzMSwzMiwgYW5kIDMzDQpsb2dpYy4zMS4zMz1OQUlDUzJEaWdpdCAlaW4lIGNhdGUuMzEuMzMgICAgICAgICAgICMgSWRlbnRpZnkgdGhlIHRocmVlIGNhdGVnb3JpZXM6IDMxLCAzMiwgMzMuDQpOQUlDUzJEaWdpdFtsb2dpYy4zMS4zM10gPSAzMTMgICAgICAgICAgICAgICAgICAgICAgIyByZXBsYWNlIDMxLCAzMiwgMzMgd2l0aCAzMTMNCiMjIGNvbWJpbmluZyA0NCBhbmQgNDUNCmxvZ2ljLjQ0LjQ1PU5BSUNTMkRpZ2l0ICVpbiUgY2F0ZS40NC40NSAgICAgICAgICAgIyBJZGVudGlmeSB0aGUgdGhyZWUgY2F0ZWdvcmllczogNDQgYW5kIDQ1Lg0KTkFJQ1MyRGlnaXRbbG9naWMuNDQuNDVdID0gNDQ1IA0KIyMgY29tYmluaW5nIDQ4IGFuZCA0OQ0KbG9naWMuNDguNDk9TkFJQ1MyRGlnaXQgJWluJSBjYXRlLjQ4LjQ5ICAgICAgICAgICAjIElkZW50aWZ5IHRoZSB0aHJlZSBjYXRlZ29yaWVzOiA0OCBhbmQgNDkuDQpOQUlDUzJEaWdpdFtsb2dpYy40OC40OV0gPSA0ODkgDQojIGNoZWNrIHRoZSByZXN1bHQNCiMgbGlzdCh0YWIubmFpY3MwPXRhYmxlKE5BSUNTMkRpZ2l0MCksdGFiLm5haWNzPXRhYmxlKE5BSUNTMkRpZ2l0KSkgICAjIGNoZWNrIHRoZSByZXN1bHQNCiMjIyBmaW5hbCBzdGVwDQpsb2FuJHN0ck5BSUNTID0gTkFJQ1MyRGlnaXQNCmthYmxlKHRhYmxlKGxvYW4kc3RyTkFJQ1MpKQ0KYGBgDQoNCiMjIExvYW4gRGVmYXVsdCBSYXRlcyBieSBJbmR1c3RyeQ0KDQpXZSBub3cgZmluZCB0aGUgbG9hbiBkZWZhdWx0IHJhdGVzIGJ5IGluZHVzdHJ5IGRlZmluZWQgYnkgdGhlIHN0cmF0aWZpY2F0aW9uIHZhcmlhYmxlIHN0ck5BSUNTLiBUaGUgbG9hbiBkZWZhdWx0IHN0YXR1cyBjYW4gYmUgZGVmaW5lZCBieSB0aGUgdmFyaWFibGUgTUlTX1N0YXR1cy4gVGhlIGZvbGxvd2luZyB0YWJsZSBnaXZlcyB0aGUgZGVmYXVsdCByYXRlcyBieSBpbmR1c3RyeS4NCg0KYGBge3J9DQp4LnRhYmxlID0gdGFibGUobG9hbiRzdHJOQUlDUywgbG9hbiRNSVNfU3RhdHVzKQ0Kbm8ubGFiID0geC50YWJsZVssMV0gICAgICAjIGZpcnN0IGNvbHVtbiBjb25zaXN0cyBvZiB1bmtub3duIGRlZmF1bHQgbGFiZWwNCmRlZmF1bHQgPSB4LnRhYmxlWywyXQ0Kbm8uZGVmYXVsdCA9IHgudGFibGVbLDNdDQpkZWZhdWx0LnJhdGUgPSByb3VuZCgxMDAqZGVmYXVsdC8oZGVmYXVsdCtuby5kZWZhdWx0KSwxKQ0KZGVmYXVsdC5zdGF0dXMucmF0ZSA9IGNiaW5kKG5vLmxhYiA9IG5vLmxhYiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGRlZmF1bHQgPSBkZWZhdWx0LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgbm8uZGVmYXVsdCA9IG5vLmRlZmF1bHQsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGRlZmF1bHQucmF0ZT1kZWZhdWx0LnJhdGUpDQprYWJsZShkZWZhdWx0LnN0YXR1cy5yYXRlKQ0KYGBgDQoNCiMjIFN0dWR5IFBvcHVsYXRpb24NCg0KQmFzZWQgb24gdGhlIGFib3ZlIGZyZXF1ZW5jeSBkaXN0cmlidXRpb24gb2YgdGhlIG1vZGlmaWVkIDItZGlnaXQgTkFJQ1MgY29kZXMgKHRoZSAzLWRpZ2l0IGNvZGVzIGFyZSBjb21iaW5lZCBjYXRlZ29yaWVzKS4gV2UgdXNlIHRoZSBmb2xsb3dpbmcgaW5jbHVzaW9uIHJ1bGUgdG8gZGVmaW5lIHRoZSBzdHVkeSBwb3B1bGF0aW9uOiBleGNsdWRpbmcgc21hbGwgc2l6ZSBjYXRlZ29yaWVzIDIwLCAyMSwgNTUsIDkyLCBhbmQgdW5jbGFzc2lmaWVkIGJ1c2luZXNzZXMgd2l0aCBOQUlDUyBjb2RlIDAuDQoNCg0KYGBge3J9DQpkZWwuY2F0ZWdvcmllcyA9IGMoIjAiLCAiMjEiLCAiMjIiLCAiNTUiLCAiOTIiKSAgICAgICAjIGNhdGVnb3JpZXMgdG8gYmUgZGVsZXRlZCBpbiANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhlIG9yaWdpbmFsIHBvcHVsYXRpb24NCmRlbC5vYnMuc3RhdHVzID0gIShsb2FuJHN0ck5BSUNTICVpbiUgZGVsLmNhdGVnb3JpZXMpICMgZGVsZXRpb24gc3RhdHVzLiAhIG5lZ2F0aW9uIG9wZXJhdG9yDQpzdHVkeS5wb3AgPSBsb2FuW2RlbC5vYnMuc3RhdHVzLF0gICAgICAgICAgICAgICAgICAgICAjIGV4Y2x1ZGluZyB0aGUgY2F0ZWdvcmllcw0Ka2FibGUodCh0YWJsZShzdHVkeS5wb3Akc3RyTkFJQ1MpKSkgICAgICAgICAgICAgICAgICAgIyBDaGVja2luZyBjb3JyZWN0bmVzcyBvcGVyYXRpb24NCmBgYA0KDQpTbyB3ZSBoYXZlIGRlZmluZWQgb3VyIHN0dWR5IHBvcHVsYXRpb24hIFRoZSBuZXcgcG9wdWxhdGlvbiBzaXplIGlzIDY5NDIxNi4NCg0KIyBTYW1wbGluZyBQbGFucw0KDQpJbiB0aGlzIHNlY3Rpb24sIHdlIGFyZSBpbXBsZW1lbnRpbmcgdGhyZWUgc2FtcGxpbmcgcGxhbnMuIEluIGVhY2ggc2FtcGxpbmcgcGxhbiwgd2Ugc2VsZWN0IDMwMDAgb2JzZXJ2YXRpb25zIGluIHRoZSBjb3JyZXNwb25kaW5nIHNhbXBsZXMuIFRoZSBzYW1wbGUgc2l6ZSBpcyBzbGlnaHRseSBsZXNzIHRoYW4gNSUgb2YgdGhlIHN0dWR5IHBvcHVsYXRpb24gc2l6ZS4gV2UgdXNlIHdpdGhvdXQtcmVwbGFjZW1lbnQgc2FtcGxpbmcgcGxhbnMgZm9yIGFsbCB0aHJlZSBwcm9iYWJpbGlzdGljIHNhbXBsZSBwbGFucy4NCg0KIyMgU2ltcGxlIFJhbmRvbSBTYW1wbGluZw0KDQpXZSBkZWZpbmUgYSBzYW1wbGluZyBsaXN0IGFuZCBhZGQgaXQgdG8gdGhlIHN0dWR5IHBvcHVsYXRpb24uDQoNCmBgYHtyfQ0Kc3R1ZHkucG9wJHNhbXBsaW5nLmZyYW1lID0gMTpsZW5ndGgoc3R1ZHkucG9wJEdyQXBwdikgICAjIHNhbXBsaW5nIGxpc3QNCiMgbmFtZXMoc3R1ZHkucG9wKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBjaGVja2luZyB0aGUgc2FtcGxpbmcgbGlzdCB2YXJpYWJsZQ0Kc2FtcGxlZC5saXN0ID0gc2FtcGxlKDE6bGVuZ3RoKHN0dWR5LnBvcCRHckFwcHYpLCAzMDAwKSAjIHNhbXBsaW5nIHRoZSBsaXN0DQpTUlMuc2FtcGxlID0gc3R1ZHkucG9wW3NhbXBsZWQubGlzdCxdICAgICAgICAgICAgICAgICAgICMgZXh0cmFjdCB0aGUgc2FtcGxpbmcgdW5pdHMgKG9ic2VydmF0aW9ucykNCiMjIGRpbWVuc2lvbiBjaGVjaw0KZGltKFNSUy5zYW1wbGUgKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGNoZWNraW5nIHRoZSBzYW1wbGUgc2l6ZQ0KYGBgDQojIyBTeXN0ZW1hdGljIHNhbXBsaW5nDQoNCldlIGNhbiBjaG9vc2UgYSByYW5kb20gaW50ZWdlciB0aGF0IGlzIGxlc3MgdGhhbiB0aGUganVtcCBzaXplICgyMzEgaW4gb3VyIGNhc2UpIHRvIGd1YXJhbnRlZSB0byBvYnRhaW4gZW5vdWdoIHNhbXBsZXMuIA0KDQpgYGB7cn0NCmp1bXAuc2l6ZSA9IGRpbShzdHVkeS5wb3ApWzFdJS8lMzAwMCAgICMgZmluZCB0aGUganVtcCBzaXplIGluIHRoZSBzeXN0ZW1hdGljIHNhbXBsaW5nDQojIGp1bXAuc2l6ZQ0KcmFuZC5zdGFydGluZy5wdD1zYW1wbGUoMTpqdW1wLnNpemUsMSkgIyBmaW5kIHRoZSByYW5kb20gc3RhcnRpbmcgdmFsdWUNCnNhbXBsaW5nLmlkID0gc2VxKHJhbmQuc3RhcnRpbmcucHQsIGRpbShzdHVkeS5wb3ApWzFdLCBqdW1wLnNpemUpICAjIHNhbXBsaW5nIElEDQojbGVuZ3RoKHNhbXBsaW5nLmlkKQ0Kc3lzLnNhbXBsZT1zdHVkeS5wb3Bbc2FtcGxpbmcuaWQsXSAgICAjIGV4dHJhY3QgdGhlIHNhbXBsaW5nIHVuaXRzIG9mIHN5c3RlbWF0aWMgc2FtcGxlcw0KZGltKHN5cy5zYW1wbGUpDQpgYGANCkJlY2F1c2UgdGhlIGp1bXAgc2l6ZSBpbnZvbHZlcyByb3VuZGluZyBlcnJvciBhbmQgdGhlIHBvcHVsYXRpb24gaXMgbGFyZ2UsIHRoZSBhY3R1YWwgc3lzdGVtYXRpYyBzYW1wbGUgc2l6ZSBpcyBzbGlnaHRseSBkaWZmZXJlbnQgZnJvbSB0aGUgdGFyZ2V0IHNpemUuIEluIHRoaXMgcmVwb3J0LCBJIHVzZWQgdGhlIGludGVncmFsIHBhcnQgb2YgdGhlIGFjdHVhbCBqdW1wIHNpemUuIFRoZSBhY3R1YWwgc3lzdGVtYXRpYyBzYW1wbGluZyBzaXplIGlzIHNsaWdodGx5IGJpZ2dlciB0aGFuIHRoZSB0YXJnZXQgc2l6ZS4gV2UgY2FuIHRha2UgYXdheSBzb21lIHJlY29yZHMgZnJvbSB0aGUgc3lzdGVtYXRpYyBzYW1wbGUgdG8gbWFrZSB0aGUgc2l6ZSB0byBiZSBlcXVhbCB0byB0aGUgdGFyZ2V0IHNpemUuDQoNCiMjIFN0cmF0aWZpZWQgU2FtcGxpbmcNCg0KV2UgdGFrZSBhbiBTUlMgZnJvbSBlYWNoIGluZGl2aWR1YWwgc3RyYXR1bS4gVGhlIHNhbXBsZSBzaXplIHNob3VsZCBiZSBhcHByb3hpbWF0ZWx5IHByb3BvcnRpb25hbCB0byB0aGUgc2l6ZSBvZiB0aGUgY29ycmVzcG9uZGluZyBzdHJhdHVtLg0KDQpGaXJzdCwgd2UgY2FsY3VsYXRlIHRoZSBTUlMgc2l6ZSBmb3IgZWFjaCBzdHJhdHVtIGFuZCB0aGVuIHRha2UgdGhlIFNSUyBmcm9tIHRoZSBjb3JyZXNwb25kaW5nIHN0cmF0dW0uIFRoZSBmb2xsb3dpbmcgdGFibGUgc2hvd3MgdGhlIHN1Yi1zYW1wbGUgc2l6ZXMuDQoNCmBgYHtyfQ0KZnJlcS50YWJsZSA9IHRhYmxlKHN0dWR5LnBvcCRzdHJOQUlDUykgICMgZnJlcXVlbmN5IHRhYmxlIG9mIHN0ck5BSUNTDQpyZWwuZnJlcSA9IGZyZXEudGFibGUvc3VtKGZyZXEudGFibGUpICAgIyByZWxhdGl2ZSBmcmVxdWVuY3kgDQpzdHJhdGEuc2l6ZSA9IHJvdW5kKHJlbC5mcmVxKjMwMDApICAgICAgIyBzdHJhdGEgc2l6ZSBhbGxvY2F0aW9uDQpzdHJhdGEubmFtZXM9bmFtZXMoc3RyYXRhLnNpemUpICAgICAgICAgIyBleHRyYWN0IHN0ck5BSUNTIG5hbWVzIGZvciBhY2N1cmFjeSBjaGVja2luZw0KI2xpc3Qoc3RyYXRhLm5hbWVzPW5hbWVzKHN0cmF0YS5zaXplKSwgDQogICAgICNzdHJhdGEuc2l6ZSA9IHN0cmF0YS5zaXplLCANCiAgICAgI3NhbXBsZS5zaXplID0gc3VtKHN0cmF0YS5zaXplKSkNCmthYmxlKHQoc3RyYXRhLnNpemUpKQ0KYGBgDQoNCldoZW4gY29kaW5nLCB3ZSB1c2UgYSBsb29wIHRvIHRha2Ugc2ltcGxlIHJhbmRvbSBzYW1wbGVzIGZyb20gZWFjaCBzdHJhdHVtIGFuZCB0aGVuIGNvbWJpbmUgdGhlbSB0byBnZXQgdGhlIHN0cmF0aWZpZWQgc2FtcGxlLg0KDQpgYGB7cn0NCnN0cmF0YS5zYW1wbGUgPSBzdHVkeS5wb3BbMSxdICAgICMgY3JlYXRlIGEgcmVmZXJlbmNlIGRhdGEgZnJhbWUNCnN0cmF0YS5zYW1wbGUkYWRkLmlkID0gMSAgICAgICAgICMgYWRkIGEgdGVtcG9yYXJ5IElEIHRvIGJlY2F1c2UgaW4gdGhlIGxvb3ANCiMgaSA9MiAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGVzdGluZyBhIHNpbmdsZSBpdGVyYXRpb24NCmZvciAoaSBpbiAxOmxlbmd0aChzdHJhdGEubmFtZXMpKXsNCiAgIGl0aC5zdHJhdGEubmFtZXMgPSBzdHJhdGEubmFtZXNbaV0gICAjIGV4dHJhY3QgZGF0YSBmcmFtZSBuYW1lcw0KICAgaXRoLnN0cmF0YS5zaXplID0gc3RyYXRhLnNpemVbaV0gICAgICMgYWxsb2NhdGVkIHN0cmF0dW0gc2l6ZQ0KICAgIyBUaGUgZm9sbG93aW5nIGNvZGUgaWRlbnRpZmllcyBvYnNlcnZhdGlvbnMgdG8gYmUgc2VsZWN0ZWQNCiAgIGl0aC5zYW1wbGluZy5pZCA9IHdoaWNoKHN0dWR5LnBvcCRzdHJOQUlDUz09aXRoLnN0cmF0YS5uYW1lcykgDQogICBpdGguc3RyYXRhID0gc3R1ZHkucG9wW2l0aC5zYW1wbGluZy5pZCxdICAjIGktdGggc3RyYXRpZmllZCBwb3B1bGF0aW9uDQogICBpdGguc3RyYXRhJGFkZC5pZCA9IDE6ZGltKGl0aC5zdHJhdGEpWzFdICAjIGFkZCBzYW1wbGluZyBsaXN0L2ZyYW1lDQogICAjIFRoZSBmb2xsb3dpbmcgY29kZSBnZW5lcmF0ZXMgYSBzdWJzZXQgb2YgcmFuZG9tIElEDQogICBpdGguc2FtcGxpbmcuaWQgPSBzYW1wbGUoMTpkaW0oaXRoLnN0cmF0YSlbMV0sIGl0aC5zdHJhdGEuc2l6ZSkgDQogICAjIyBDcmVhdGUgYSBzZWxlY3Rpb24gc3RhdHVzIC0tIHBheSBhdHRlbnRpb24gdG8gdGhlIG9wZXJhdG9yOiAlaW4lIA0KICAgaXRoLnNhbXBsZSA9aXRoLnN0cmF0YVtpdGguc3RyYXRhJGFkZC5pZCAlaW4laXRoLnNhbXBsaW5nLmlkLF0NCiAgICMjIGRpbShpdGguc2FtcGxlKSAgICAgICAgICQgY2hlY2sgdGhlIHNhbXBsZQ0KICAgc3RyYXRhLnNhbXBsZSA9IHJiaW5kKHN0cmF0YS5zYW1wbGUsIGl0aC5zYW1wbGUpICAjIHN0YWNrIGFsbCBkYXRhZnJhbWUhDQogfQ0KICMgZGltKHN0cmF0YS5zYW1wbGUpDQogc3RyYXQuc2FtcGxlLmZpbmFsID0gc3RyYXRhLnNhbXBsZVstMSxdICAgICAjIGRyb3AgdGhlIHRlbXBvcmFyeSBzdHJhdHVtIElEDQojIGthYmxlKGhlYWQoc3RyYXQuc2FtcGxlLmZpbmFsWzE6NSw1XSkpICAgICAgICAjIGFjY3VyYWN5IGNoZWNrISBvbmx5IHNob3cgdGhlIGZpcnN0IDUgdmFyaWFibGVzDQpgYGANCg0KDQoNCg0KDQojIFBlcmZvcm1hbmNlIEFuYWx5c2lzIG9mIFJhbmRvbSBTYW1wbGVzDQoNCkluIHRoaXMgc2VjdGlvbiwgd2UgcGVyZm9ybSBhIGNvbXBhcmF0aXZlIGFuYWx5c2lzIG9mIHRoZSB0aHJlZSByYW5kb20gc2FtcGxlcy4gT25lIG1ldHJpYyB3ZSBjYW4gdXNlIGlzIHRoZSBkZWZhdWx0IHJhdGUgaW4gZWFjaCBpbmR1c3RyeSBkZWZpbmVkIGJ5IHRoZSBmaXJzdCB0d28gZGlnaXRzIG9mIE5BSUNTIGNsYXNzaWZpY2F0aW9uIGNvZGUuIFRoYXQgd2FzIGFsc28gdXNlZCBhcyB0aGUgc3RyYXRpZmljYXRpb24gdmFyaWFibGUgaW4gdGhlIHN0cmF0aWZpZWQgc2FtcGxpbmcgcGxhbi4gDQoNCiMjIFBvcHVsYXRpb24tbGV2ZWwgRGVmYXVsdCBSYXRlcw0KDQpXZSBoYXZlIGNhbGN1bGF0ZWQgdGhlIGRlZmF1bHQgcmF0ZSBhY3Jvc3MgdGhlIGluZHVzdHJpZXMgaW4gdGhlIHByZXZpb3VzIHNlY3Rpb24uIFRoYXQgdGFibGUgaW5jbHVkZXMgdGhlIGNhdGVnb3J5IHdpdGggbm8gTkFJQ1MgY2xhc3NpZmljYXRpb24gY29kZS4gV2Ugd2lsbCB1c2UgdGhpcyBwb3B1bGF0aW9uLWxldmVsIGluZHVzdHJ5LXNwZWNpZmljIHJhdGUgYXMgYSByZWZlcmVuY2UgYW5kIGNvbXBhcmUgaXQgd2l0aCB0aGUgc2FtcGxlLWxldmVsIGluZHVzdHJ5LXNwZWNpZmljIGRlZmF1bHQgcmF0ZXMuICANCg0KYGBge3IgY2FwdGlvbj0iUG9wdWxhdGlvbi1sZXZlbCBkZWZhdWx0IHJhdGVzIn0NCngudGFibGUgPSB0YWJsZShsb2FuJHN0ck5BSUNTLCBsb2FuJE1JU19TdGF0dXMpDQpuby5sYWIgPSB4LnRhYmxlWywxXSAgICMgZmlyc3QgY29sdW1uIGNvbnNpc3RzIG9mIHVua25vd24gZGVmYXVsdCBsYWJlbA0KZGVmYXVsdCA9IHgudGFibGVbLDJdDQpuby5kZWZhdWx0ID0geC50YWJsZVssM10NCmRlZmF1bHQucmF0ZSA9IHJvdW5kKDEwMCpkZWZhdWx0LyhkZWZhdWx0K25vLmRlZmF1bHQpLDEpDQogZGVmYXVsdC5zdGF0dXMucmF0ZSA9IGNiaW5kKG5vLmxhYiA9IG5vLmxhYiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGRlZmF1bHQgPSBkZWZhdWx0LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgbm8uZGVmYXVsdCA9IG5vLmRlZmF1bHQsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGRlZmF1bHQucmF0ZT1kZWZhdWx0LnJhdGUpDQprYWJsZShkZWZhdWx0LnN0YXR1cy5yYXRlLCBjYXB0aW9uID0gIlBvcHVsYXRpb24gc2l6ZSwgZGVmYXVsdCBjb3VudHMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbmQgcG9wdWxhdGlvbiBkZWZhdWx0IHJhdGVzIikNCmBgYA0KDQojIyBJbmR1c3RyeS1TcGVjaWZpYyBEZWZhdWx0IFJhdGVzIGJhc2VkIG9uIFNSUw0KDQpGb3IgY29tcGFyaXNvbiwgd2UgY29uc3RydWN0IHRoZSBmb2xsb3dpbmcgdGFibGUgdGhhdCBpbmNsdWRlcyB0aGUgaW5kdXN0cnktc3BlY2lmaWMgZGVmYXVsdCByYXRlcy4gDQoNCmBgYHtyfQ0KICMgbmFtZXMoU1JTLnNhbXBsZSkNCngudGFibGUgPSB0YWJsZShTUlMuc2FtcGxlJHN0ck5BSUNTLCBTUlMuc2FtcGxlJE1JU19TdGF0dXMpDQpuby5sYWIuc3JzID0geC50YWJsZVssMV0gICAgICAjIGZpcnN0IGNvbHVtbiBjb25zaXN0cyBvZiB1bmtub3duIGRlZmF1bHQgbGFiZWwNCmRlZmF1bHQuc3JzID0geC50YWJsZVssMl0NCm5vLmRlZmF1bHQuc3JzID0geC50YWJsZVssM10NCmRlZmF1bHQucmF0ZS5zcnMgPSByb3VuZCgxMDAqZGVmYXVsdC5zcnMvKGRlZmF1bHQuc3JzK25vLmRlZmF1bHQuc3JzKSwxKQ0KIyMNCmluZHVzdHJ5LmNvZGUgPSBuYW1lcyhkZWZhdWx0LnJhdGUuc3JzKSAgICAjIGV4dHJhY3QgTlNJQ1MgY29kZQ0KaW5kdXN0cnkubmFtZT1jKCJBZ3JpLWZvcmVzdC1maXNoLWh1bnQiLCJDb25zdHJ1Y3Rpb24iLA0KICAgICAgICAgICAgICAgICJNYW51ZmFjdHVyaW5nIiwgIldob2xlc2FsZS10cmFkZSIsICJSZXRhaWwtdHJhZGUiLA0KICAgICAgICAgICAgICAgICJUcmFuc3BvcnQtd2FyZWhvdXNpbmciLCJJbmZvcm1hdGlvbiIsICJGaW5hbmNlLWluc3VyYW5jZSIsDQogICAgICAgICAgICAgICAgIlJlYWwtZXN0YXRlLXJlbnRhbCIsIlByb2Ytc2NpLXRlY2gtc2VyIiwNCiAgICAgICAgICAgICAgICAiQWRtaW4tc3VwcG9ydC13YXN0ZS1tZ250LXJlbWVkIiwgIkVkdS1zZXJ2IiwNCiAgICAgICAgICAgICAgICAiSGVhbHRoY2FyZS1zb2NpYWwtYXNzaXN0IiwiQXJ0cy1lbnRlcnRhaW4tcmVjIiwNCiAgICAgICAgICAgICAgICAiQWNjb21tb2RhdGlvbi1mb29kLXNlciIsICJPdGhlci1zZXIobm8tcHVibGljLWFkbWluKSIpICAjIGFjdHVhbCBpbmR1c3RyeSBuYW1lcyENCmRlZmF1bHQucmF0ZS5wb3AgPSBkZWZhdWx0LnJhdGVbaW5kdXN0cnkuY29kZV0NCiMgY2JpbmQoaW5kdXN0cnkuY29kZSxpbmR1c3RyeS5uYW1lKQ0KU1JTLnBvcC5yYXRlcyA9IGNiaW5kKGRlZmF1bHQucmF0ZS5wb3AsZGVmYXVsdC5yYXRlLnNycykNCnJvd25hbWVzKFNSUy5wb3AucmF0ZXMpID0gaW5kdXN0cnkubmFtZQ0Ka2FibGUoU1JTLnBvcC5yYXRlcywgY2FwdGlvbj0iQ29tcGFyaXNvbiBvZiBpbmR1c3RyeS1zcGVjaWZpYyBkZWZhdWx0IHJhdGVzIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJldHdlZW4gcG9wdWxhdGlvbiBhbmQgdGhlIFNSUy4iKQ0KYGBgDQoNClNvbWUgb2YgdGhlIGluZHVzdHJ5LXNwZWNpZmljIGRlZmF1bHQgcmF0ZXMgc2VlbSB0byBiZSBzaWduaWZpY2FudGx5IGRpZmZlcmVudC4gTW9yZSB2aXN1YWwgY29tcGFyaXNvbnMgd2lsbCBiZSBnaXZlbiBpbiB0aGUgbmV4dCBzZWN0aW9uLg0KDQoNCiMjIEluZHVzdHJ5LXNwZWNpZmljIFJhdGVzLSBTeXN0ZW1hdGljcyBTYW1wbGUNCg0KV2Ugd2lsbCB1c2UgdGhlIHNhbXBsZSBzdHJhdGlmaWNhdGlvbiB2YXJpYWJsZSB0byBmaW5kIHRoZSBpbmR1c3RyeS1zcGVjaWZpYyByYXRlcyBiYXNlZCBvbiB0aGUgc3lzdGVtYXRpYyBzYW1wbGUuIFRoZSBmb2xsb3dpbmcgdGFibGUgd2lsbCBpbmNsdWRlIHJhdGVzIG9mIHBvcHVsYXRpb24sIFNSUywgYW5kIHN5c3RlbWF0aWMgcmFuZG9tIHNhbXBsZXMuDQoNCmBgYHtyfQ0KeC50YWJsZSA9IHRhYmxlKHN5cy5zYW1wbGUkc3RyTkFJQ1MsIHN5cy5zYW1wbGUkTUlTX1N0YXR1cykNCm5vLmxhYi5zeXMgPSB4LnRhYmxlWywxXSAgICAgICMgVGhlIGZpcnN0IGNvbHVtbiBjb25zaXN0cyBvZiBhbiB1bmtub3duIGRlZmF1bHQgbGFiZWwNCmRlZmF1bHQuc3lzID0geC50YWJsZVssMl0NCm5vLmRlZmF1bHQuc3lzID0geC50YWJsZVssM10NCmRlZmF1bHQucmF0ZS5zeXMgPSByb3VuZCgxMDAqZGVmYXVsdC5zeXMvKGRlZmF1bHQuc3lzK25vLmRlZmF1bHQuc3lzKSwxKQ0Kc3lzLlNSUy5wb3AucmF0ZXMgPSBjYmluZChkZWZhdWx0LnJhdGUucG9wLCBkZWZhdWx0LnJhdGUuc3JzLCBkZWZhdWx0LnJhdGUuc3lzKQ0Kcm93bmFtZXMoU1JTLnBvcC5yYXRlcykgPSBpbmR1c3RyeS5uYW1lDQprYWJsZShzeXMuU1JTLnBvcC5yYXRlcywgY2FwdGlvbj0iQ29tcGFyaXNvbiBvZiBpbmR1c3RyeS1zcGVjaWZpYyBkZWZhdWx0IHJhdGVzIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJldHdlZW4gcG9wdWxhdGlvbiwgU1JTLCBhbmQgU3lzdGVtYXRpYyBTYW1wbGUuIikNCmBgYA0KSXQgc2VlbXMgdGhhdCB0aGUgc3lzdGVtYXRpYyBzYW1wbGUgcGVyZm9ybXMgYmV0dGVyIHRoYW4gdGhlIFNSUyBzYW1wbGUuDQoNCg0KIyMgSW5kdXN0cnktc3BlY2lmaWMgRGVmYXVsdCBSYXRlcy0gU3RyYXRpZmllZCBTYW1wbGUNCg0KSW4gdGhpcyBzZWN0aW9uLCB3ZSBwdXQgYWxsIHRoZSBpbmZvcm1hdGlvbiBpbiB0aGUgZm9sbG93aW5nIHRhYmxlLg0KDQpgYGB7cn0NCiNzdHJhdC5zYW1wbGUuZmluYWwNCngudGFibGUgPSB0YWJsZShzdHJhdC5zYW1wbGUuZmluYWwkc3RyTkFJQ1MsIHN0cmF0LnNhbXBsZS5maW5hbCRNSVNfU3RhdHVzKQ0Kbm8ubGFiLnN0ciA9IHgudGFibGVbLDFdICAgICAgIyBUaGUgZmlyc3QgY29sdW1uIGNvbnNpc3RzIG9mIGFuIHVua25vd24gZGVmYXVsdCBsYWJlbA0KZGVmYXVsdC5zdHIgPSB4LnRhYmxlWywyXQ0Kbm8uZGVmYXVsdC5zdHIgPSB4LnRhYmxlWywzXQ0KZGVmYXVsdC5yYXRlLnN0ciA9IHJvdW5kKDEwMCpkZWZhdWx0LnN0ci8oZGVmYXVsdC5zdHIrbm8uZGVmYXVsdC5zdHIpLDEpDQpzdHIuU1JTLnBvcC5yYXRlcyA9IGNiaW5kKGRlZmF1bHQucmF0ZS5wb3AsIGRlZmF1bHQucmF0ZS5zcnMsIGRlZmF1bHQucmF0ZS5zeXMsIGRlZmF1bHQucmF0ZS5zdHIpDQpyb3duYW1lcyhzdHIuU1JTLnBvcC5yYXRlcykgPSBpbmR1c3RyeS5uYW1lDQprYWJsZShzdHIuU1JTLnBvcC5yYXRlcywgY2FwdGlvbj0iQ29tcGFyaXNvbiBvZiBpbmR1c3RyeS1zcGVjaWZpYyBkZWZhdWx0IHJhdGVzIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJldHdlZW4gcG9wdWxhdGlvbiwgU1JTLCBTeXN0ZW1hdGljIFNhbXBsZSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5kIFN0cmF0aWZpZWQgU2FtcGxlcy4iKQ0KYGBgDQoNCiMgVmlzdWFsaXphdGlvbiAtIFZpc3VhbCBDb21wYXJpc29uDQoNCkluIHRoZSBwcmV2aW91cyBzZWN0aW9uLCB3ZSBjYWxjdWxhdGVkIHRoZSBpbmR1c3RyeS1zcGVjaWZpYyBkZWZhdWx0IHJhdGVzIGZvciBwb3B1bGF0aW9uLCBTUlMsIHN5c3RlbWF0aWMsIGFuZCBzdHJhdGlmaWVkIHNhbXBsZXMuIFdlIG5vdyBjcmVhdGUgYSBzdGF0aXN0aWNhbCBncmFwaGljIHRvIGNvbXBhcmUgdGhlIGRlZmF1bHQgcmF0ZXMgYW1vbmcgdGhlIHNhbXBsZXMuDQoNCg0KYGBge3IgY2FwdGlvbj0iR3JhcGhpY2FsIGNvbXBhcmlzb24gb2YgaW5kdXN0cnktc3BlY2lmaWMgZGVmYXVsdCByYXRlcyBhbW9uZyByYW5kb20gc2FtcGxlcyBhbmQgcG9wdWxhdGlvbi4gQ2F1dGlvbjogVGhpcyBjaGFydCBpcyBiYXNlZCBvbiBvbmUtdGltZSBzYW1wbGVzLiAiLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD00LCB9DQpuPWxlbmd0aChkZWZhdWx0LnJhdGUucG9wKQ0KI3BhcihiZyA9ICdncmF5JykNCiMgZW1wdHkgcGxvdA0KcGxvdChOVUxMLCB4bGltPWMoMCxuKSwgeWxpbT1jKDAsIDUwKSwgeGxhYj0iIiwgeWxhYiA9IiIsIGF4ZXM9RkFMU0UpDQp0aXRsZSgiQ29tcGFyaXNvbiBvZiBJbmR1c3RyeS1zcGVjaWZpYyBEZWZhdWx0IFJhdGVzIikNCnBvaW50cygxOm4sIGFzLnZlY3RvcihkZWZhdWx0LnJhdGUucG9wKSwgcGNoPTE2LCBjb2w9MiwgY2V4ID0gMC44KQ0KbGluZXMoMTpuLCBhcy52ZWN0b3IoZGVmYXVsdC5yYXRlLnBvcCksIGx0eT0xLCBjb2w9MiwgY2V4ID0gMC44KQ0KIw0KcG9pbnRzKDE6biwgYXMudmVjdG9yKGRlZmF1bHQucmF0ZS5zcnMpLCBwY2g9MTcsIGNvbD0zLCBjZXggPSAwLjgpDQpsaW5lcygxOm4sIGFzLnZlY3RvcihkZWZhdWx0LnJhdGUuc3JzKSwgbHR5PTIsIGNvbD0zLCBjZXggPSAwLjgpDQojDQpwb2ludHMoMTpuLCBhcy52ZWN0b3IoZGVmYXVsdC5yYXRlLnN5cyksIHBjaD0xOSwgY29sPTQsIGNleCA9IDAuOCkNCmxpbmVzKDE6biwgYXMudmVjdG9yKGRlZmF1bHQucmF0ZS5zeXMpLCBsdHk9MywgY29sPTQsIGNleCA9IDAuOCkNCiMNCnBvaW50cygxOm4sIGFzLnZlY3RvcihkZWZhdWx0LnJhdGUuc3RyKSwgcGNoPTIwLCBjb2w9NSwgY2V4ID0gMC44KQ0KbGluZXMoMTpuLCBhcy52ZWN0b3IoZGVmYXVsdC5yYXRlLnN0ciksIGx0eT00LCBjb2w9NSwgY2V4ID0gMC44KQ0KIw0KYXhpcygxLGF0PTE6biwgbGFiZWw9aW5kdXN0cnkuY29kZSwgbGFzID0gMikNCmF4aXMoMikNCiMNCnJvd01heD1hcHBseShzdHIuU1JTLnBvcC5yYXRlcywgMSwgbWF4KSAjIG1heCBkZWZhdWx0IHJhdGUgaW4gZWFjaCBpbmR1c3RyeQ0Kc2VnbWVudHMoMTpuLCByZXAoMCxuKSwgMTpuLCByb3dNYXgsIGx0eT0yLCBjb2w9ImxpZ2h0Z3JheSIsIGx3ZCA9IDAuNSkNCmxlZ2VuZCgidG9wcmlnaHQiLCBjKCJQb3AiLCAiU1JTIiwgIlN5cyIsICJTdHIiKSwgbHR5PTE6NCwgY29sPTI6NSwgcGNoPWMoMTYsMTcsMTksMjApLCBjZXg9MC42LCBidHk9Im4iKQ0KDQpgYGANCkZvciBlYXNlIG9mIGludGVycHJldGF0aW9uLCBJIG1ha2UgdGhlIGZvbGxvd2luZyB0YWJsZSB0byBtYXAgdGhlIE5BSUNTIGNvZGVzIGFuZCB0aGUgY29ycmVzcG9uZGluZyBpbmR1c3RyaWVzLg0KDQpgYGB7cn0NCmthYmxlKGNiaW5kKGluZHVzdHJ5Lm5hbWUsIGluZHVzdHJ5LmNvZGUpLCANCiAgICAgIGNhcHRpb249IkluZHVzdHJ5IE5BSUNTIGNvZGVzIGFuZCB0aGUgY29ycmVzcG9uZGluZyBuYW1lcyIpDQpgYGANCg0KU2luY2UgdGhlIGFib3ZlIGdyYXBoIGlzIGJhc2VkIG9uIG9uZS10aW1lIHNhbXBsZXMsIHRoZSB2YXJpYXRpb24gaXMgbm90IGluY2x1ZGVkLiBUaGVyZWZvcmUsIHdlIG5lZWQgbW9yZSBpbmZvcm1hdGlvbiB0byBkbyBhIG1lYW5pbmdmdWwgY29tcGFyaXNvbi4gRm9yIGV4YW1wbGUsIHdlIGNhbiBwYWNrYWdlIHRoZSBjb2RlIGluIHRoaXMgTWFya2Rvd24gZG9jdW1lbnQgYW5kIHRha2UsIHNheSAxMDAwLCBzYW1wbGVzIGJhc2VkIG9uIGVhY2ggc2FtcGxpbmcgcGxhbi4gV2UgdGhlbiBjYW4gZmluZCB0aGUgbWVhbiBpbmR1c3RyeS1zcGVjaWZpYyBkZWZhdWx0IHJhdGVzIGFuZCB0aGUgY29ycmVzcG9uZGluZyB2YXJpYXRpb24uDQoNCg0KIyMgQ3JpdGlxdWVzIG9mIFZpc3VhbCBSZXByZXNlbnRhdGlvbg0KDQpWaXN1YWwgcmVwcmVzZW50YXRpb24gaXMgYSBrZXkgY29tcG9uZW50IGluIGVmZmVjdGl2ZSBzdG9yeXRlbGxpbmcuIEFzIGFuIGV4YW1wbGUsIHdlIGNyaXRpcXVlIHRoZSBmaWd1cmUgb2YgcGVyZm9ybWFuY2UgY29tcGFyaXNvbiBvZiB0aGUgdGhyZWUgc2FtcGxpbmcgcGxhbnMgaW4gdGhlIHByZXZpb3VzIHNlY3Rpb24gYW5kIHNlZWsgaW1wcm92ZW1lbnRzIGZvciBlZmZlY3RpdmUgcmVwcmVzZW50YXRpb24uIA0KDQpUaGUgZm9sbG93aW5nIGZpZ3VyZSBpcyBtb2RpZmllZCBiYXNlZCBvbiB0aGUgY29tcGFyaXNvbiBsaW5lIHBsb3QgZ2l2ZW4gaW4gdGhlIHByZXZpb3VzIHNlY3Rpb24uDQoNCg0KYGBge3IgY2FwdGlvbj0iR3JhcGhpY2FsIGNvbXBhcmlzb24gb2YgaW5kdXN0cnktc3BlY2lmaWMgZGVmYXVsdCByYXRlcyBhbW9uZyByYW5kb20gc2FtcGxlcyBhbmQgcG9wdWxhdGlvbi4gQ2F1dGlvbjogVGhpcyBjaGFydCBpcyBiYXNlZCBvbiBvbmUtdGltZSBzYW1wbGVzLiAifQ0Kbj1sZW5ndGgoZGVmYXVsdC5yYXRlLnBvcCkNCiNwYXIoYmcgPSAnZ3JheScpDQojIGVtcHR5IHBsb3QNCnBsb3QoTlVMTCwgeGxpbT1jKDAsbiksIHlsaW09YygwLCA1MCksIHhsYWI9IiIsIHlsYWIgPSIiLCBheGVzPUZBTFNFKQ0KIyBMaWdodCBncmF5IGJhY2tncm91bmQNCnJlY3QocGFyKCJ1c3IiKVsxXSwgcGFyKCJ1c3IiKVszXSwNCiAgICAgcGFyKCJ1c3IiKVsyXSwgcGFyKCJ1c3IiKVs0XSwNCiAgICAgY29sID0gImdyYXkiKQ0KDQojIEFkZCB3aGl0ZSBncmlkDQpncmlkKG54ID0gTlVMTCwgbnkgPSBOVUxMLA0KICAgICBjb2wgPSAid2hpdGUiLCBsd2QgPSAxKQ0KDQp0aXRsZSgiQ29tcGFyaXNvbiBvZiBJbmR1c3RyeS1zcGVjaWZpYyBEZWZhdWx0IFJhdGVzIikNCnBvaW50cygxOm4sIGFzLnZlY3RvcihkZWZhdWx0LnJhdGUucG9wKSwgcGNoPTE2LCBjb2w9MiwgY2V4ID0gMC44KQ0KbGluZXMoMTpuLCBhcy52ZWN0b3IoZGVmYXVsdC5yYXRlLnBvcCksIGx0eT0xLCBjb2w9MiwgY2V4ID0gMC44KQ0KIw0KcG9pbnRzKDE6biwgYXMudmVjdG9yKGRlZmF1bHQucmF0ZS5zcnMpLCBwY2g9MTcsIGNvbD0zLCBjZXggPSAwLjgpDQpsaW5lcygxOm4sIGFzLnZlY3RvcihkZWZhdWx0LnJhdGUuc3JzKSwgbHR5PTIsIGNvbD0zLCBjZXggPSAwLjgpDQojDQpwb2ludHMoMTpuLCBhcy52ZWN0b3IoZGVmYXVsdC5yYXRlLnN5cyksIHBjaD0xOSwgY29sPTQsIGNleCA9IDAuOCkNCmxpbmVzKDE6biwgYXMudmVjdG9yKGRlZmF1bHQucmF0ZS5zeXMpLCBsdHk9MywgY29sPTQsIGNleCA9IDAuOCkNCiMNCnBvaW50cygxOm4sIGFzLnZlY3RvcihkZWZhdWx0LnJhdGUuc3RyKSwgcGNoPTIwLCBjb2w9NSwgY2V4ID0gMC44KQ0KbGluZXMoMTpuLCBhcy52ZWN0b3IoZGVmYXVsdC5yYXRlLnN0ciksIGx0eT00LCBjb2w9NSwgY2V4ID0gMC44KQ0KIw0KYXhpcygxLGF0PTE6biwgbGFiZWw9aW5kdXN0cnkuY29kZSwgbGFzID0gMikNCmF4aXMoMikNCiMNCnJvd01heD1hcHBseShzdHIuU1JTLnBvcC5yYXRlcywgMSwgbWF4KSAjIG1heCBkZWZhdWx0IHJhdGUgaW4gZWFjaCBpbmR1c3RyeQ0Kc2VnbWVudHMoMTpuLCByZXAoMCxuKSwgMTpuLCByb3dNYXgsIGx0eT0yLCBjb2w9ImxpZ2h0Z3JheSIsIGx3ZCA9IDAuNSkNCmxlZ2VuZCgidG9wcmlnaHQiLCBjKCJQb3AiLCAiU1JTIiwgIlN5cyIsICJTdHIiKSwgbHR5PTE6NCwgY29sPTI6NSwgcGNoPWMoMTYsMTcsMTksMjApLCBjZXg9MC42LCBidHk9Im4iKQ0KDQpgYGANCg0KDQpUaGVyZSdzIGEgbG90IG9mIGluayBoZXJlIHRoYXQgZG9lc24ndCBjb252ZXkgaW5mb3JtYXRpb24gcmVsZXZhbnQgdG8gdGhlIG1haW4gcG9pbnQgd2UncmUgdHJ5aW5nIHRvIG1ha2UuIA0KDQoqICoqR3JleSBiYWNrZ3JvdW5kKio6IG5vdCBvbmx5IGRvZXMgaXQgcHJvdmlkZSBhYnNvbHV0ZWx5IG5vIGluZm9ybWF0aW9uLiBpdCdzIGFsc28gdW5zaWdodGx5LiBBZnRlciB3ZSByZW1vdmUgaXQsIHdlIHdpbGwgbGlrZWx5IGhhdmUgdG8gZGFya2VuIHNvbWUgb2YgdGhlIGxpbmVzLg0KDQoqICoqR3JpZCBsaW5lcyoqOiBpdCdzIHZlcnkgdW5saWtlbHkgdGhhdCBvdXIgYXVkaWVuY2UgY2FyZXMgYWJvdXQgdGhlIGV4YWN0IHZhbHVlcyBhdCBlYWNoIGRhdGEgcG9pbnQgLSBpdCdzIHRoZSBwYXR0ZXJuIHRoYXQgbWF0dGVycy4gVGhlIGdyaWQgbGluZXMgY29tcGV0ZSB3aXRoIHRoZSBwYXR0ZXJuIHdlJ3JlIHRyeWluZyB0byBzaG93Lg0KDQoqICoqTGVnZW5kKio6IEl0IHRha2VzIHRpbWUgdG8gZ3Vlc3MgdGhlIGFiYnJldmlhdGlvbi4gSXQgYWxzbyBjb25mdXNlcyByZWFkZXJzLg0KDQoqICoqVGljayBtYXJrcyoqOiBXaHkgbWFrZSB0aGUgcmVhZGVyIHRpbHQgaGlzIG9yIGhlciBoZWFkIHRvIHJlYWQ/DQoNCiogKipMYWJlbHMgb2YgWC0gYW5kIFktIEF4aXMqKjogbGFiZWxzIGFyZSBtaXNzaW5nLiANCg0KKiAqKlRpdGxlKio6IFRoZSB0aXRsZSBzaG91bGQgYmUgbW9yZSBzcGVjaWZpYy4NCg0KKiAqKkxpbmUgdHlwZXMqKjogVXNlIGNvbG9yIGFuZCBsaW5lIHR5cGUgdG8gZGlmZmVyZW50aWF0ZSAtIHRoaXMgd2lsbCBoZWxwIHBlb3BsZSB3aG8gaGF2ZSBhIGNvbG9yLWltcGFpcmVkIHZpc2lvbiwgYW5kIGFsc28gYW55IGdyZXktc2NhbGUgY29waWVzIG9mIHRoZSBwb3N0ZXIgeW91IG1ha2UgKGFzIGZvciBoYW5kb3V0cykuDQoNCiogKipDb2xvciBjb2RpbmcqKjogIEF2b2lkIHVzaW5nIHVzZSBncmVlbiBhbmQgcmVkIGNvbG9ycyBpbiB0aGUgc2FtZSBncmFwaGljIHRvIHJlcHJlc2VudCBkaWZmZXJlbnQgb2JqZWN0cy4gTW9yZSB0aGFuIDk5JSBvZiBhbGwgY29sb3ItYmxpbmQgcGVvcGxlIGFyZSBzdWZmZXJpbmcgZnJvbSBhIHJlZC1ncmVlbiBjb2xvciB2aXNpb24gZGVmaWNpZW5jeS4NCg0KSXQncyBlYXN5IHRvIG1ha2UgYSBncmFwaCB0aGF0IGxvb2tzIGNsZWFuZXIgYW5kIGhhcyBhIGhpZ2hlciByYXRpbyBvZiBpbmZvcm1hdGlvbi10by10b3RhbCBpbms6DQoNCg0KDQpgYGB7ciBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NCwgIGNhcHRpb249IkltcHJvdmVkIGdyYXBoaWNzIn0NCm49bGVuZ3RoKGRlZmF1bHQucmF0ZS5wb3ApDQpwbG90KE5VTEwsIHhsaW09YygwLG4pLCB5bGltPWMoMCwgNTApLCANCiAgICAgeGxhYj0iSW5kdXN0cnkgQ2xhc3NpZmljYXRpb24gQ29kZSIsIA0KICAgICB5bGFiID0iRGVmYXVsdCBSYXRlcyAoUGVyY2VudGFnZSkiLCBheGVzPUZBTFNFKSAjIGVtcHR5IHBsb3QNCiMgTGlnaHQgZ3JheSBiYWNrZ3JvdW5kDQpyZWN0KHBhcigidXNyIilbMV0sIHBhcigidXNyIilbM10sDQogICAgIHBhcigidXNyIilbMl0sIHBhcigidXNyIilbNF0sDQogICAgIGNvbCA9ICJncmF5IikNCg0KIyBBZGQgd2hpdGUgZ3JpZA0KZ3JpZChueCA9IE5VTEwsIG55ID0gTlVMTCwNCiAgICAgY29sID0gIndoaXRlIiwgbHdkID0gMSkNCg0KdGl0bGUoIkNvbXBhcmlzb24gb2YgSW5kdXN0cnktc3BlY2lmaWMgRGVmYXVsdCBSYXRlcyBCYXNlZCBvbiBSYW5kb20gU2FtcGxlcyIpDQpwb2ludHMoMTpuLCBhcy52ZWN0b3IoZGVmYXVsdC5yYXRlLnBvcCksIHBjaD0xNiwgY29sPSJkYXJrbWFnZW50YSIsIGNleCA9IDAuOCkNCmxpbmVzKDE6biwgYXMudmVjdG9yKGRlZmF1bHQucmF0ZS5wb3ApLCAgbHR5PTEsIGNvbD0iZGFya21hZ2VudGEiLCBjZXggPSAwLjgpDQojDQpwb2ludHMoMTpuLCBhcy52ZWN0b3IoZGVmYXVsdC5yYXRlLnNycyksIHBjaD0xNywgY29sPSJjaGFydHJldXNlNCIsIGNleCA9IDAuOCkNCmxpbmVzKDE6biwgYXMudmVjdG9yKGRlZmF1bHQucmF0ZS5zcnMpLCBsdHk9MSwgY29sPSJjaGFydHJldXNlNCIsIGNleCA9IDAuOCkNCiMNCnBvaW50cygxOm4sIGFzLnZlY3RvcihkZWZhdWx0LnJhdGUuc3lzKSwgcGNoPTE5LCBjb2w9ImRhcmtibHVlIiwgY2V4ID0gMC44KQ0KbGluZXMoMTpuLCBhcy52ZWN0b3IoZGVmYXVsdC5yYXRlLnN5cyksIGx0eT0xLCBjb2w9ImRhcmtibHVlIiwgY2V4ID0gMC44KQ0KIw0KcG9pbnRzKDE6biwgYXMudmVjdG9yKGRlZmF1bHQucmF0ZS5zdHIpLCBwY2g9MjAsIGNvbD0iZGFya2N5YW4iLCBjZXggPSAwLjgpDQpsaW5lcygxOm4sIGFzLnZlY3RvcihkZWZhdWx0LnJhdGUuc3RyKSwgbHR5PTEsIGNvbD0iZGFya2N5YW4iLCBjZXggPSAwLjgpDQojDQpheGlzKDEsYXQ9MTpuLCBsYWJlbD1pbmR1c3RyeS5jb2RlKQ0KYXhpcygyLCBsYXMgPSAyKQ0KIw0KY2xyID0gYygiZGFya21hZ2VudGEiLCJjaGFydHJldXNlNCIsImRhcmtibHVlIiwiZGFya2N5YW4iKQ0Kcm93TWF4PWFwcGx5KHN0ci5TUlMucG9wLnJhdGVzLCAxLCBtYXgpICMgbWF4IGRlZmF1bHQgcmF0ZSBpbiBlYWNoIGluZHVzdHJ5DQojc2VnbWVudHMoMTpuLCByZXAoMCxuKSwgMTpuLCByb3dNYXgsIGx0eT0yLCBjb2w9ImxpZ2h0Z3JheSIsIGx3ZCA9IDAuNSkNCmxlZ2VuZCgyLCA0NSwgYygiUG9wdWxhdGlvbiIsICJTaW1wbGUgUmFuZG9tIFNhbXBsaW5nIiwgIlN5c3RlbWF0aWMgU2FtcGxpbmciLCAiU3RyYXRpZmllZCBTYW1wbGluZyIpLCBsdHk9cmVwKDEsNCksIGNvbD1jbHIsIHBjaD1jKDE2LDE3LDE5LDIwKSwgY2V4PTAuNiwgYnR5PSJuIikNCg0KYGBgDQoNClJlbW92aW5nIHRoZSBncmF5IGJhY2tncm91bmQgd2lsbCBtYWtlIHRoZSBncmFwaCBjbGVhbmVyLiAgDQoNCmBgYHtyIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD00LCAgY2FwdGlvbj0iSW1wcm92ZWQgZ3JhcGhpY3MifQ0Kbj1sZW5ndGgoZGVmYXVsdC5yYXRlLnBvcCkNCnBsb3QoTlVMTCwgeGxpbT1jKDAsbiksIHlsaW09YygwLCA1MCksIA0KICAgICB4bGFiPSJJbmR1c3RyeSBDbGFzc2lmaWNhdGlvbiBDb2RlIiwgDQogICAgIHlsYWIgPSJEZWZhdWx0IFJhdGVzIChQZXJjZW50YWdlKSIsIGF4ZXM9RkFMU0UpICMgZW1wdHkgcGxvdA0KDQp0aXRsZSgiQ29tcGFyaXNvbiBvZiBJbmR1c3RyeS1zcGVjaWZpYyBEZWZhdWx0IFJhdGVzIEJhc2VkIG9uIFJhbmRvbSBTYW1wbGVzIikNCnBvaW50cygxOm4sIGFzLnZlY3RvcihkZWZhdWx0LnJhdGUucG9wKSwgcGNoPTE2LCBjb2w9ImRhcmttYWdlbnRhIiwgY2V4ID0gMC44KQ0KbGluZXMoMTpuLCBhcy52ZWN0b3IoZGVmYXVsdC5yYXRlLnBvcCksICBsdHk9MSwgY29sPSJkYXJrbWFnZW50YSIsIGNleCA9IDAuOCkNCiMNCnBvaW50cygxOm4sIGFzLnZlY3RvcihkZWZhdWx0LnJhdGUuc3JzKSwgcGNoPTE3LCBjb2w9ImNoYXJ0cmV1c2U0IiwgY2V4ID0gMC44KQ0KbGluZXMoMTpuLCBhcy52ZWN0b3IoZGVmYXVsdC5yYXRlLnNycyksIGx0eT0xLCBjb2w9ImNoYXJ0cmV1c2U0IiwgY2V4ID0gMC44KQ0KIw0KcG9pbnRzKDE6biwgYXMudmVjdG9yKGRlZmF1bHQucmF0ZS5zeXMpLCBwY2g9MTksIGNvbD0iZGFya2JsdWUiLCBjZXggPSAwLjgpDQpsaW5lcygxOm4sIGFzLnZlY3RvcihkZWZhdWx0LnJhdGUuc3lzKSwgbHR5PTEsIGNvbD0iZGFya2JsdWUiLCBjZXggPSAwLjgpDQojDQpwb2ludHMoMTpuLCBhcy52ZWN0b3IoZGVmYXVsdC5yYXRlLnN0ciksIHBjaD0yMCwgY29sPSJkYXJrY3lhbiIsIGNleCA9IDAuOCkNCmxpbmVzKDE6biwgYXMudmVjdG9yKGRlZmF1bHQucmF0ZS5zdHIpLCBsdHk9MSwgY29sPSJkYXJrY3lhbiIsIGNleCA9IDAuOCkNCiMNCmF4aXMoMSxhdD0xOm4sIGxhYmVsPWluZHVzdHJ5LmNvZGUpDQpheGlzKDIsIGxhcyA9IDIpDQojDQpjbHIgPSBjKCJkYXJrbWFnZW50YSIsImNoYXJ0cmV1c2U0IiwiZGFya2JsdWUiLCJkYXJrY3lhbiIpDQpyb3dNYXg9YXBwbHkoc3RyLlNSUy5wb3AucmF0ZXMsIDEsIG1heCkgIyBtYXggZGVmYXVsdCByYXRlIGluIGVhY2ggaW5kdXN0cnkNCiNzZWdtZW50cygxOm4sIHJlcCgwLG4pLCAxOm4sIHJvd01heCwgbHR5PTIsIGNvbD0ibGlnaHRncmF5IiwgbHdkID0gMC41KQ0KbGVnZW5kKDIsIDQ1LCBjKCJQb3B1bGF0aW9uIiwgIlNpbXBsZSBSYW5kb20gU2FtcGxpbmciLCAiU3lzdGVtYXRpYyBTYW1wbGluZyIsICJTdHJhdGlmaWVkIFNhbXBsaW5nIiksIGx0eT1yZXAoMSw0KSwgY29sPWNsciwgcGNoPWMoMTYsMTcsMTksMjApLCBjZXg9MC42LCBidHk9Im4iKQ0KDQpgYGANCg0KDQoNCg0KDQoNCg0KDQo=