1 Introduction

In this note, I will introduce the steps for taking random samples from the study population. The Bank load data set is treated as a population. We will use this data set as a population to implement various sampling plans.

The original data set was split into 9 subsets that are stored on GitHub. We first load these data sets to R and then combine them as a single data set.

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]
bankLoan = rbind(loan01, loan02, loan03, loan04, loan05, loan06, loan07, loan08, loan09)

2 Creating a meaningful and operational stratification variable

A stratification variable is a categorical variable that can be used to stratify the population based on its values. Each value (or category) defines a subpopulation. When sampling the population, we can take one random sub-sample from each sub-population and then combine these sub-samples to define a random sample of the population.

There are different ways of defining a stratification variable. For example, we can discretize a numerical variable, use an existing categorical variable, or modify an existing categorical variable by combining some of the categories in a meaningful way, etc. In this note, I use the North American Industry Classification System (NAICS) as an example to show you how to modify an existing categorical variable to define a stratification variable for sampling purposes.

2.1 Description of Existing 2-Digit NAICS Codes

We first summarized the distribution of the existing NAICS in the following table.

naics =as.character(bankLoan$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: the latest version of R has upper bound 
# the maximum length of variable names from 256 characters to a whopping 10,000. 
# We should try our best to give meaningful names to R variables.
kable(cbind(Population.size = N, Number.of.Industries=n, Sub.Pop.less.900 = n.0))
Population.size Number.of.Industries Sub.Pop.less.900
899164 1312 1140

I posted an article that used this data for the case study. One of the tables https://github.com/pengdsci/STA490/blob/main/w06/w06-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://github.com/pengdsci/STA490/blob/main/w06/w06-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.

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

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(bankLoan$NAICS, 1, 2)   # extract the first two digits of the NAICS code
bankLoan$NAICS2Digit = NAICS.2.digits           # add the above two-digit variable the loan data
ftable = table(bankLoan$NAICS2Digit)
kable(t(ftable))
0 11 21 22 23 31 32 33 42 44 45 48 49 51 52 53 54 55 56 61 62 71 72 81 92
201948 9005 1851 663 66646 11809 17936 38284 48743 84737 42514 20310 2221 11379 9496 13632 68170 257 32685 6425 55366 14640 67600 72618 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. 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)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
cate.vec0 1 4 3 6 7 3 6 5 4 6 4 5 8 9 4 3 4 7 3
cate.vec 99 4 3 99 99 3 99 5 4 99 4 5 8 9 4 3 4 99 3

We now combine the actual 2-digit NAICS codes

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 = bankLoan$NAICS2Digit  # extract the 2-digit NAICS
NAICS2Digit =  bankLoan$NAICS2Digit  # extract the 2-digit NAICS-copy
## combining 31,32,and 33
logic.31.33=NAICS2Digit %in% cate.31.33 # identify the three categories.
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.
NAICS2Digit[logic.44.45] = 445 
## combining 48 and 49
logic.48.49=NAICS2Digit %in% cate.48.49  # identify the three categories.
NAICS2Digit[logic.48.49] = 489 
bankLoan$strNAICS = NAICS2Digit

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.

x.table = table(bankLoan$strNAICS, bankLoan$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 business with NAICS code 0.

del.categories = c("0", "21", "22", "55", "92") 
# categories to be deleted in 
# the original population
del.obs.status = !(bankLoan$strNAICS %in% del.categories) 
# deletion status. ! negation operator
study.pop = bankLoan[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!

3 Sampling Plans

In this section, we are implementing three sampling plans. In each sampling plan, we select 4000 observations in the corresponding samples.

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), 4000) 
# sampling the list
SRS.sample = study.pop[sampled.list,]                  
# extract the sampling units (observations)
## dimension check
dimension.SRS = dim(SRS.sample)
names(dimension.SRS) = c("Size", "Var.count")
kable(t(dimension.SRS))   # checking the sample size
Size Var.count
4000 30

3.2 Systematic sampling

jump.size = dim(study.pop)[1]%/%4000  
# 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 IDs
#length(sampling.id)
sys.sample=study.pop[sampling.id,]    
# extract the sampling units of systematic samples
sys.Sample.dim = dim(sys.sample)
names(sys.Sample.dim) = c("Size", "Var.count")
kable(t(sys.Sample.dim))
Size Var.count
4013 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 integer part of the actual jump size. The actual systematic sampling size is slightly bigger than the target size. We can take away some records random 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 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.

freq.table = table(study.pop$strNAICS)  # frequency table of strNAICS
rel.freq = freq.table/sum(freq.table)   # relative frequency 
strata.size = round(rel.freq*4000)      # strata size allocation
strata.names=names(strata.size)         # extract strNAICS names for accuracy checking
kable(t(strata.size))  # make a nice-looking table using kable().
11 23 313 42 445 489 51 52 53 54 56 61 62 71 72 81
52 384 392 281 733 130 66 55 79 393 188 37 319 84 390 418

In the following code chunk, we take stratified samples.

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 data frame!
 }
 # dim(strata.sample)
 strat.sample.final = strata.sample[-1,]  # drop the temporary stratum ID
 #kable(head(strat.sample.final))         # accuracy check!

4 Performance Analysis of Random Samples

Next week, we perform a comparative analysis of the three random samples using the baseline default rates.

5 Assignment

In this assignment, You need to take three random samples as I did in this note:

  1. Simple random sample (SRS).

  2. Systematic random sample: you need to choose a random starting number.

  3. Stratified sample: you need a stratification variable to split the population.

  4. Cluster sampling: you need to (a) define a new vector with unique zip codes, (b)take a random sample of zip codes, (c) include all loans in the randomly selected zip codes to get the cluster sample.

LS0tDQp0aXRsZTogIkltcGxlbWVudGluZyBSYW1kb20gU2FtcGxpbmcgUGxhbnMgIg0KYXV0aG9yOiAiQ2hlbmcgUGVuZyINCmRhdGU6ICIgICINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIGZpZ193aWR0aDogNg0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdG9jX2NvbGxhcHNlZDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgc21vb3RoX3Njcm9sbDogdHJ1ZQ0KICAgIHRoZW1lOiByZWFkYWJsZQ0KICAgIGZpZ19oZWlnaHQ6IDQNCiAgd29yZF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAga2VlcF9tZDogeWVzDQogIHBkZl9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIGZpZ193aWR0aDogNQ0KICAgIGZpZ19oZWlnaHQ6IDQNCi0tLQ0KDQpgYGB7PWh0bWx9DQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KaDEudGl0bGUgew0KICBmb250LXNpemU6IDIwcHg7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmg0LmF1dGhvciB7IA0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQpoNC5kYXRlIHsgDQogIGZvbnQtc2l6ZTogMThweDsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KaDEgew0KICAgIGZvbnQtc2l6ZTogMjJweDsNCiAgICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQpoMiB7DQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmRpdiNUT0MgbGkgew0KICAgIGxpc3Qtc3R5bGU6bm9uZTsNCn0NCjwvc3R5bGU+DQpgYGANCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KIyBjb2RlIGNodW5rIHNwZWNpZmllcyB3aGV0aGVyIHRoZSBSIGNvZGUsIHdhcm5pbmdzLCBhbmQgb3V0cHV0IA0KIyB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBvdXRwdXQgZmlsZXMuDQppZiAoIXJlcXVpcmUoImtuaXRyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikNCiAgIGxpYnJhcnkoa25pdHIpDQp9DQoNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZ3MgPSBGQUxTRSwgICANCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHRzID0gVFJVRSwgICANCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgZmlnLmFsaWduPSdjZW50ZXInLCANCiAgICAgICAgICAgICAgICAgICAgICBmaWcucG9zID0gJ2h0JykNCiNrbml0cjo6b3B0c19rbml0JHNldChyb290LmRpciA9ICdDOlxcU1RBNTUxXFx3a2RpcjAnKQ0KYGBgDQoNCg0KIyBJbnRyb2R1Y3Rpb24NCg0KDQpJbiB0aGlzIG5vdGUsIEkgd2lsbCBpbnRyb2R1Y2UgdGhlIHN0ZXBzIGZvciB0YWtpbmcgcmFuZG9tIHNhbXBsZXMgZnJvbSB0aGUgc3R1ZHkgcG9wdWxhdGlvbi4gVGhlIEJhbmsgbG9hZCBkYXRhIHNldCBpcyB0cmVhdGVkIGFzIGEgcG9wdWxhdGlvbi4gV2Ugd2lsbCB1c2UgdGhpcyBkYXRhIHNldCBhcyBhIHBvcHVsYXRpb24gdG8gaW1wbGVtZW50IHZhcmlvdXMgc2FtcGxpbmcgcGxhbnMuDQoNClRoZSBvcmlnaW5hbCBkYXRhIHNldCB3YXMgc3BsaXQgaW50byA5IHN1YnNldHMgdGhhdCBhcmUgc3RvcmVkIG9uIEdpdEh1Yi4gV2UgZmlyc3QgbG9hZCB0aGVzZSBkYXRhIHNldHMgdG8gUiBhbmQgdGhlbiBjb21iaW5lIHRoZW0gYXMgYSBzaW5nbGUgZGF0YSBzZXQuDQoNCmBgYHtyfQ0KbG9hbjAxID0gcmVhZC5jc3YoImh0dHBzOi8vcGVuZ2RzY2kuZ2l0aHViLmlvL2RhdGFzZXRzL1NCQWxvYW4vdzA2LVNCQW5hdGlvbmFsMDEuY3N2IiwgaGVhZGVyID0gVFJVRSlbLCAtMV0NCmxvYW4wMiA9IHJlYWQuY3N2KCJodHRwczovL3Blbmdkc2NpLmdpdGh1Yi5pby9kYXRhc2V0cy9TQkFsb2FuL3cwNi1TQkFuYXRpb25hbDAyLmNzdiIsIGhlYWRlciA9IFRSVUUpWywgLTFdDQpsb2FuMDMgPSByZWFkLmNzdigiaHR0cHM6Ly9wZW5nZHNjaS5naXRodWIuaW8vZGF0YXNldHMvU0JBbG9hbi93MDYtU0JBbmF0aW9uYWwwMy5jc3YiLCBoZWFkZXIgPSBUUlVFKVssIC0xXQ0KbG9hbjA0ID0gcmVhZC5jc3YoImh0dHBzOi8vcGVuZ2RzY2kuZ2l0aHViLmlvL2RhdGFzZXRzL1NCQWxvYW4vdzA2LVNCQW5hdGlvbmFsMDQuY3N2IiwgaGVhZGVyID0gVFJVRSlbLCAtMV0NCmxvYW4wNSA9IHJlYWQuY3N2KCJodHRwczovL3Blbmdkc2NpLmdpdGh1Yi5pby9kYXRhc2V0cy9TQkFsb2FuL3cwNi1TQkFuYXRpb25hbDA1LmNzdiIsIGhlYWRlciA9IFRSVUUpWywgLTFdDQpsb2FuMDYgPSByZWFkLmNzdigiaHR0cHM6Ly9wZW5nZHNjaS5naXRodWIuaW8vZGF0YXNldHMvU0JBbG9hbi93MDYtU0JBbmF0aW9uYWwwNi5jc3YiLCBoZWFkZXIgPSBUUlVFKVssIC0xXQ0KbG9hbjA3ID0gcmVhZC5jc3YoImh0dHBzOi8vcGVuZ2RzY2kuZ2l0aHViLmlvL2RhdGFzZXRzL1NCQWxvYW4vdzA2LVNCQW5hdGlvbmFsMDcuY3N2IiwgaGVhZGVyID0gVFJVRSlbLCAtMV0NCmxvYW4wOCA9IHJlYWQuY3N2KCJodHRwczovL3Blbmdkc2NpLmdpdGh1Yi5pby9kYXRhc2V0cy9TQkFsb2FuL3cwNi1TQkFuYXRpb25hbDA4LmNzdiIsIGhlYWRlciA9IFRSVUUpWywgLTFdDQpsb2FuMDkgPSByZWFkLmNzdigiaHR0cHM6Ly9wZW5nZHNjaS5naXRodWIuaW8vZGF0YXNldHMvU0JBbG9hbi93MDYtU0JBbmF0aW9uYWwwOS5jc3YiLCBoZWFkZXIgPSBUUlVFKVssIC0xXQ0KYmFua0xvYW4gPSByYmluZChsb2FuMDEsIGxvYW4wMiwgbG9hbjAzLCBsb2FuMDQsIGxvYW4wNSwgbG9hbjA2LCBsb2FuMDcsIGxvYW4wOCwgbG9hbjA5KQ0KYGBgDQoNCg0KIyBDcmVhdGluZyBhIG1lYW5pbmdmdWwgYW5kIG9wZXJhdGlvbmFsIHN0cmF0aWZpY2F0aW9uIHZhcmlhYmxlDQoNCg0KQSBzdHJhdGlmaWNhdGlvbiB2YXJpYWJsZSBpcyBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlIHRoYXQgY2FuIGJlIHVzZWQgdG8gc3RyYXRpZnkgdGhlIHBvcHVsYXRpb24gYmFzZWQgb24gaXRzIHZhbHVlcy4gRWFjaCB2YWx1ZSAob3IgY2F0ZWdvcnkpIGRlZmluZXMgYSBzdWJwb3B1bGF0aW9uLiBXaGVuIHNhbXBsaW5nIHRoZSBwb3B1bGF0aW9uLCB3ZSBjYW4gdGFrZSBvbmUgcmFuZG9tIHN1Yi1zYW1wbGUgZnJvbSBlYWNoIHN1Yi1wb3B1bGF0aW9uIGFuZCB0aGVuIGNvbWJpbmUgdGhlc2Ugc3ViLXNhbXBsZXMgdG8gZGVmaW5lIGEgcmFuZG9tIHNhbXBsZSBvZiB0aGUgcG9wdWxhdGlvbi4NCg0KVGhlcmUgYXJlIGRpZmZlcmVudCB3YXlzIG9mIGRlZmluaW5nIGEgc3RyYXRpZmljYXRpb24gdmFyaWFibGUuIEZvciBleGFtcGxlLCB3ZSBjYW4gZGlzY3JldGl6ZSBhIG51bWVyaWNhbCB2YXJpYWJsZSwgdXNlIGFuIGV4aXN0aW5nIGNhdGVnb3JpY2FsIHZhcmlhYmxlLCBvciBtb2RpZnkgYW4gZXhpc3RpbmcgY2F0ZWdvcmljYWwgdmFyaWFibGUgYnkgY29tYmluaW5nIHNvbWUgb2YgdGhlIGNhdGVnb3JpZXMgaW4gYSBtZWFuaW5nZnVsIHdheSwgZXRjLiBJbiB0aGlzIG5vdGUsIEkgdXNlIHRoZSBOb3J0aCBBbWVyaWNhbiBJbmR1c3RyeSBDbGFzc2lmaWNhdGlvbiBTeXN0ZW0gKE5BSUNTKSBhcyBhbiBleGFtcGxlIHRvIHNob3cgeW91IGhvdyB0byBtb2RpZnkgYW4gZXhpc3RpbmcgY2F0ZWdvcmljYWwgdmFyaWFibGUgdG8gZGVmaW5lIGEgc3RyYXRpZmljYXRpb24gdmFyaWFibGUgZm9yIHNhbXBsaW5nIHB1cnBvc2VzLg0KDQoNCiMjIERlc2NyaXB0aW9uIG9mIEV4aXN0aW5nIDItRGlnaXQgTkFJQ1MgQ29kZXMNCg0KDQpXZSBmaXJzdCBzdW1tYXJpemVkIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIGV4aXN0aW5nIE5BSUNTIGluIHRoZSBmb2xsb3dpbmcgdGFibGUuDQoNCmBgYHtyIGRhdGEtc2l6ZX0NCm5haWNzID1hcy5jaGFyYWN0ZXIoYmFua0xvYW4kTkFJQ1MpICAjIG1ha2UgYSBjaGFyYWN0ZXIgdmVjdG9yDQpOPWxlbmd0aChuYWljcykgICAgICAgICAgICAgICAgICAgICAgIyBmaW5kIHRoZSBzaXplIG9mIHRoZSBkYXRhLiANCmYudGFibGUgPSAtc29ydCgtdGFibGUobmFpY3MpKSAgICAgICAjIHNvcnQgdGhlIHZlY3RvciBpbiBkZXNjZW5kaW5nIG9yZGVyDQpuID0gbGVuZ3RoKGYudGFibGUpICAgICAgICAgICAgICAgICAgIyBmaW5kIHRoZSBudW1iZXIgb2YgZGlzdGluY3QgaW5kdXN0cmllcw0Kbi4wID0gc3VtKGYudGFibGUgPCA5MDApICAgICAgICAgICAgICMgaW5kdXN0cnkgd2l0aCBsZXNzIHRoYW4gMC4xJSBvZiB0aGUgcG9wdWxhdGlvbiBzaXplDQojIEEgbm90ZSBvZiBsZW5ndGggb2YgUiB2YXJpYWJsZTogdGhlIGxhdGVzdCB2ZXJzaW9uIG9mIFIgaGFzIHVwcGVyIGJvdW5kIA0KIyB0aGUgbWF4aW11bSBsZW5ndGggb2YgdmFyaWFibGUgbmFtZXMgZnJvbSAyNTYgY2hhcmFjdGVycyB0byBhIHdob3BwaW5nIDEwLDAwMC4gDQojIFdlIHNob3VsZCB0cnkgb3VyIGJlc3QgdG8gZ2l2ZSBtZWFuaW5nZnVsIG5hbWVzIHRvIFIgdmFyaWFibGVzLg0Ka2FibGUoY2JpbmQoUG9wdWxhdGlvbi5zaXplID0gTiwgTnVtYmVyLm9mLkluZHVzdHJpZXM9biwgU3ViLlBvcC5sZXNzLjkwMCA9IG4uMCkpDQpgYGANCg0KSSBwb3N0ZWQgYW4gYXJ0aWNsZSB0aGF0IHVzZWQgdGhpcyBkYXRhIGZvciB0aGUgY2FzZSBzdHVkeS4gT25lIG9mIHRoZSB0YWJsZXMgPGh0dHBzOi8vZ2l0aHViLmNvbS9wZW5nZHNjaS9TVEE0OTAvYmxvYi9tYWluL3cwNi93MDYtTkFJQ1MtQ2F0ZWdvcmllcy5qcGc+IGluIHRoZSBhcnRpY2xlIGxpc3RlZCBjYXRlZ29yaWVzIGJhc2VkIG9uIHRoZSBmaXJzdCBkaWdpdHMgb2YgTkFJQ1MgY29kZS4gVGhlIG90aGVyIHJlbGF0ZWQgdGFibGUgZ2l2ZXMgdGhlIGxvYW4gZGVmYXVsdCByYXRlIGluIHRoZSBjb3JyZXNwb25kaW5nIGluZHVzdHJpZXMgPGh0dHBzOi8vZ2l0aHViLmNvbS9wZW5nZHNjaS9TVEE0OTAvYmxvYi9tYWluL3cwNi93MDYtTkFJQ1MtRGVmYXVsdC1SYXRlcy5qcGc+LiBZb3UgY2FuIGRvd25sb2FkIHRoZXNlIHR3byB0YWJsZXMgdG8geW91ciBsb2NhbCBkcml2ZSBhbmQgaW5jbHVkZSB0aGVtIGluIHlvdXIgUiBNYXJrZG93biBkb2N1bWVudCBpZiB5b3Ugd2FudCB0byBwcmFjdGljZSBhbmQgcmVwcm9kdWNlIHRoaXMgcmVwb3J0Lg0KDQpGb3IgdGhlIGNvbnZlbmllbmNlIG9mIHJlZmVycmluZyB0byB0aGVzZSB0YWJsZXMsIEkgaW5jbHVkZSB0aGVzZSB0d28gdGFibGVzIGluIHRoaXMgZG9jdW1lbnQuDQoNCmBgYHtyIGVjaG89RkFMU0UsIGZpZy5jYXA9Ikxpc3Qgb2YgYWxsIGluZHVzdHJpZXMgdXNpbmcgdGhlIGZpcnN0IHR3byBkaWdpdHMgb2YgdGhlIE5BSUNTIGNvZGUiLCBmaWcuYWxpZ249J2NlbnRlcicsIG91dC53aWR0aCA9ICc3MCUnfQ0KaW5jbHVkZV9ncmFwaGljcygiaW1nL3cwNi1OQUlDUy1DYXRlZ29yaWVzLmpwZyIpDQpgYGANCg0KYGBge3IgZWNobz1GQUxTRSwgZmlnLmNhcD0iTGlzdCBvZiBhbGwgaW5kdXN0cmllcyB1c2luZyB0aGUgZmlyc3QgdHdvIGRpZ2l0cyBvZiB0aGUgTkFJQ1MgY29kZSBhbmQgdGhlIGNvcnJlc3BvbmRpbmcgbG9hbiBkZWZhdWx0IHJhdGVzIiwgZmlnLmFsaWduPSdjZW50ZXInLG91dC53aWR0aCA9ICc3MCUnfQ0KaW5jbHVkZV9ncmFwaGljcygiaW1nL3cwNi1OQUlDUy1EZWZhdWx0LVJhdGVzLmpwZyIpDQpgYGANCg0KTmV4dCwgd2UgZXhwbG9yZSB0aGUgZnJlcXVlbmN5IGRpc3RyaWJ1dGlvbiBvZiB0aGUgMi1kaWdpdCBOQUlDUyBjb2RlcyBhbmQgZGVjaWRlIHRoZSBwb3RlbnRpYWwgY29tYmluYXRpb25zIG9mIGNhdGVnb3JpZXMgd2l0aCBhIHNtYWxsIHNpemUuDQoNCg0KYGBge3J9DQpOQUlDUy4yLmRpZ2l0cyA9IHN1YnN0cihiYW5rTG9hbiROQUlDUywgMSwgMikgICAjIGV4dHJhY3QgdGhlIGZpcnN0IHR3byBkaWdpdHMgb2YgdGhlIE5BSUNTIGNvZGUNCmJhbmtMb2FuJE5BSUNTMkRpZ2l0ID0gTkFJQ1MuMi5kaWdpdHMgICAgICAgICAgICMgYWRkIHRoZSBhYm92ZSB0d28tZGlnaXQgdmFyaWFibGUgdGhlIGxvYW4gZGF0YQ0KZnRhYmxlID0gdGFibGUoYmFua0xvYW4kTkFJQ1MyRGlnaXQpDQprYWJsZSh0KGZ0YWJsZSkpDQpgYGANCg0KU2V2ZXJhbCBwYXR0ZXJucyB5b3Ugb2JzZXJ2ZSBmcm9tIHRoZSBhYm92ZSB0YWJsZToNCg0KLSAgIDIwMTk0OCBidXNpbmVzc2VzIGRvIG5vdCBoYXZlIGEgTkFJQ1MgY29kZS4gU2luY2UgSSB3aWxsIHVzZSB0aGUgMi1kaWdpdCBOQUlDUyBjb2RlIHRvIHN0cmF0aWZ5IHRoZSBwb3B1bGF0aW9uLiBUaGlzIHZhcmlhYmxlIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIHN0dWR5IHBvcHVsYXRpb24gdGhhdCB3aWxsIGJlIGRlZmluZWQgc29vbi4NCg0KLSAgIFNldmVyYWwgY2F0ZWdvcmllcyAoMjEsIDIyLCA0OSwgNTUsIDkyKSBoYXZlIHJlbGF0aXZlbHkgc21hbGwgc2l6ZXMuIFNpbmNlIGNhdGVnb3JpZXMgNDggYW5kIDQ5IGFyZSBib3RoIHRyYW5zcG9ydGF0aW9uIGFuZCB3YXJlaG91c2UgaW5kdXN0cmllcywgd2Ugd2lsbCBjb21iaW5lIHRoZSB0d28gYXMgaW5kaWNhdGVkIGluIHRoZSBhYm92ZSB0d28gdGFibGVzLg0KDQotICAgQXMgd2UgY2FuIHNlZSBmcm9tIHRoZSBhYm92ZSB0d28gdGFibGVzLCBzZXZlcmFsIGluZHVzdHJpZXMgaGF2ZSBkaWZmZXJlbnQgY29kZXMuIFdlIHdpbGwgY29tYmluZSB0aGVzZSBjb2Rlcy4gSW4gb3RoZXIgd29yZHMsIHdlIG5lZWQgdG8gbW9kaWZ5IHRoZSAyLWRpZ2l0IGNvZGUgdG8gZGVmaW5lIHRoZSBmaW5hbCBzdHJhdGlmaWNhdGlvbiBmb3Igc3RyYXRpZmllZCBzYW1wbGluZy4NCg0KIyMgQ29tYmluaW5nIENhdGVnb3JpZXMNCg0KV2Ugbm93IGNvbWJpbmUgY2F0ZWdvcmllcyBzdWdnZXN0ZWQgaW4gdGhlIGFib3ZlIE5BSUNTIHRhYmxlcy4gQmVmb3JlIHdlIGNvbWJpbmUgdGhlIE5BSUNTIGNvZGVzLCB3ZSBwcmVzZW50IGFuIGV4YW1wbGUgdG8gaWxsdXN0cmF0ZSBob3cgdG8gY29tYmluZSBjYXRlZ29yaWVzIHVzaW5nIFIuDQoNCg0KYGBge3J9DQpjYXRlLnZlYzA9YygxLDQsMyw2LDcsMyw2LDUsNCw2LDQsNSw4LDksNCwzLDQsNywzKSAgDQojIHZlY3RvciBvZiBjYXRlZ29yeSBsYWJlbHMNCmNhdGUudmVjPWMoMSw0LDMsNiw3LDMsNiw1LDQsNiw0LDUsOCw5LDQsMyw0LDcsMykgICANCiMgYSBjb3B5IG9mIHRoZSB2ZWN0b3Igb2YgY2F0ZWdvcnkgbGFiZWxzDQpsYWJzLjIuY29sbGFwc2UgPSBjKDEsNiw3KSAgIyBkZWZpbmUgYSB2ZWN0b3IgdG8gc3RvcmUgY2F0ZWdvcmllcyB7MSw2LDd9DQpsb2dpYy52ZWM9Y2F0ZS52ZWMgJWluJSBsYWJzLjIuY29sbGFwc2UgICAgICAgICAgICAgDQojIFRSVUUvRkFMU0UgPT0+IG1hdGNoIG5vdCBuby1tYXRjaA0KY2F0ZS52ZWNbbG9naWMudmVjXSA9IDk5ICAjIGlmIG1hdGNoZXMgKGkuZS4sIDEsIDUsIDcpLCB0aGUgdmFsdWUgDQogICAgICAgICAgICAgICAgICAgICAgICAgICMgd2lsbCBiZSByZXBsYWNlZCBieSA5OQ0KbWF0eD1yYmluZChjYXRlLnZlYzA9Y2F0ZS52ZWMwLCBjYXRlLnZlYz1jYXRlLnZlYykgICMgY2hlY2sgdGhlIHJlc3VsdHMNCmNvbG5hbWVzKG1hdHgpID0gMTpsZW5ndGgoY2F0ZS52ZWMpICAgICAgICAgICAgICAgICANCiMgbmV4dCBrYWJsZSgpIGZ1bmN0aW9uIHJlcXVpcmVzIGEgY29sdW1uIG5hbWVzDQprYWJsZShtYXR4KQ0KYGBgDQoNCg0KV2Ugbm93IGNvbWJpbmUgdGhlIGFjdHVhbCAyLWRpZ2l0IE5BSUNTIGNvZGVzDQoNCg0KYGBge3J9DQpjYXRlLjMxLjMzPWMoIjMxIiwiMzIiLCIzMyIpICMgY29tYmluaW5nIGNhdGVnb3JpZXMgMzEsIDMyLCBhbmQgMzMNCmNhdGUuNDguNDkgPSBjKCI0OCIsICI0OSIpDQpjYXRlLjQ0LjQ1ID0gYygiNDQiLCAiNDUiKQ0KTkFJQ1MyRGlnaXQwID0gYmFua0xvYW4kTkFJQ1MyRGlnaXQgICMgZXh0cmFjdCB0aGUgMi1kaWdpdCBOQUlDUw0KTkFJQ1MyRGlnaXQgPSAgYmFua0xvYW4kTkFJQ1MyRGlnaXQgICMgZXh0cmFjdCB0aGUgMi1kaWdpdCBOQUlDUy1jb3B5DQojIyBjb21iaW5pbmcgMzEsMzIsYW5kIDMzDQpsb2dpYy4zMS4zMz1OQUlDUzJEaWdpdCAlaW4lIGNhdGUuMzEuMzMgIyBpZGVudGlmeSB0aGUgdGhyZWUgY2F0ZWdvcmllcy4NCk5BSUNTMkRpZ2l0W2xvZ2ljLjMxLjMzXSA9IDMxMyAgICMgcmVwbGFjZSAzMSwgMzIsIDMzIHdpdGggMzEzDQojIyBjb21iaW5pbmcgNDQgYW5kIDQ1DQpsb2dpYy40NC40NT1OQUlDUzJEaWdpdCAlaW4lIGNhdGUuNDQuNDUgIyBpZGVudGlmeSB0aGUgdGhyZWUgY2F0ZWdvcmllcy4NCk5BSUNTMkRpZ2l0W2xvZ2ljLjQ0LjQ1XSA9IDQ0NSANCiMjIGNvbWJpbmluZyA0OCBhbmQgNDkNCmxvZ2ljLjQ4LjQ5PU5BSUNTMkRpZ2l0ICVpbiUgY2F0ZS40OC40OSAgIyBpZGVudGlmeSB0aGUgdGhyZWUgY2F0ZWdvcmllcy4NCk5BSUNTMkRpZ2l0W2xvZ2ljLjQ4LjQ5XSA9IDQ4OSANCmJhbmtMb2FuJHN0ck5BSUNTID0gTkFJQ1MyRGlnaXQNCmBgYA0KDQojIyBMb2FuIERlZmF1bHQgUmF0ZXMgQnkgSW5kdXN0cnkNCg0KV2Ugbm93IGZpbmQgdGhlIGxvYW4gZGVmYXVsdCByYXRlcyBieSBpbmR1c3RyeSBkZWZpbmVkIGJ5IHRoZSBzdHJhdGlmaWNhdGlvbiB2YXJpYWJsZSBzdHJOQUlDUy4gVGhlIGxvYW4gZGVmYXVsdCBzdGF0dXMgY2FuIGJlIGRlZmluZWQgYnkgdGhlIHZhcmlhYmxlIE1JU19TdGF0dXMuDQoNCmBgYHtyfQ0KeC50YWJsZSA9IHRhYmxlKGJhbmtMb2FuJHN0ck5BSUNTLCBiYW5rTG9hbiRNSVNfU3RhdHVzKQ0Kbm8ubGFiID0geC50YWJsZVssMV0gICMgZmlyc3QgY29sdW1uIGNvbnNpc3RzIG9mIHVua25vd24gZGVmYXVsdCBsYWJlbA0KZGVmYXVsdCA9IHgudGFibGVbLDJdDQpuby5kZWZhdWx0ID0geC50YWJsZVssM10NCmRlZmF1bHQucmF0ZSA9IHJvdW5kKDEwMCpkZWZhdWx0LyhkZWZhdWx0K25vLmRlZmF1bHQpLDEpDQpkZWZhdWx0LnN0YXR1cy5yYXRlID0gY2JpbmQobm8ubGFiID0gbm8ubGFiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgZGVmYXVsdCA9IGRlZmF1bHQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBuby5kZWZhdWx0ID0gbm8uZGVmYXVsdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZGVmYXVsdC5yYXRlPWRlZmF1bHQucmF0ZSkNCmthYmxlKGRlZmF1bHQuc3RhdHVzLnJhdGUpDQpgYGANCg0KIyMgU3R1ZHkgUG9wdWxhdGlvbg0KDQpCYXNlZCBvbiB0aGUgYWJvdmUgZnJlcXVlbmN5IGRpc3RyaWJ1dGlvbiBvZiB0aGUgbW9kaWZpZWQgMi1kaWdpdCBOQUlDUyBjb2RlcyAodGhlIDMtZGlnaXQgY29kZXMgYXJlIGNvbWJpbmVkIGNhdGVnb3JpZXMpLiBXZSB1c2UgdGhlIGZvbGxvd2luZyBpbmNsdXNpb24gcnVsZSB0byBkZWZpbmUgdGhlIHN0dWR5IHBvcHVsYXRpb246IGV4Y2x1ZGluZyBzbWFsbC1zaXplIGNhdGVnb3JpZXMgMjAsIDIxLCA1NSwgOTIsIGFuZCB1bmNsYXNzaWZpZWQgYnVzaW5lc3Mgd2l0aCBOQUlDUyBjb2RlIDAuDQoNCmBgYHtyfQ0KZGVsLmNhdGVnb3JpZXMgPSBjKCIwIiwgIjIxIiwgIjIyIiwgIjU1IiwgIjkyIikgDQojIGNhdGVnb3JpZXMgdG8gYmUgZGVsZXRlZCBpbiANCiMgdGhlIG9yaWdpbmFsIHBvcHVsYXRpb24NCmRlbC5vYnMuc3RhdHVzID0gIShiYW5rTG9hbiRzdHJOQUlDUyAlaW4lIGRlbC5jYXRlZ29yaWVzKSANCiMgZGVsZXRpb24gc3RhdHVzLiAhIG5lZ2F0aW9uIG9wZXJhdG9yDQpzdHVkeS5wb3AgPSBiYW5rTG9hbltkZWwub2JzLnN0YXR1cyxdICAjIGV4Y2x1ZGluZyB0aGUgY2F0ZWdvcmllcw0Ka2FibGUodCh0YWJsZShzdHVkeS5wb3Akc3RyTkFJQ1MpKSkgIyBDaGVja2luZyBjb3JyZWN0bmVzcyBvcGVyYXRpb24NCmBgYA0KDQpTbyB3ZSBoYXZlIGRlZmluZWQgb3VyIHN0dWR5IHBvcHVsYXRpb24hDQoNCiMgU2FtcGxpbmcgUGxhbnMNCg0KSW4gdGhpcyBzZWN0aW9uLCB3ZSBhcmUgaW1wbGVtZW50aW5nIHRocmVlIHNhbXBsaW5nIHBsYW5zLiBJbiBlYWNoIHNhbXBsaW5nIHBsYW4sIHdlIHNlbGVjdCA0MDAwIG9ic2VydmF0aW9ucyBpbiB0aGUgY29ycmVzcG9uZGluZyBzYW1wbGVzLg0KDQojIyBTaW1wbGUgUmFuZG9tIFNhbXBsaW5nDQoNCldlIGRlZmluZSBhIHNhbXBsaW5nIGxpc3QgYW5kIGFkZCBpdCB0byB0aGUgc3R1ZHkgcG9wdWxhdGlvbi4NCg0KYGBge3J9DQpzdHVkeS5wb3Akc2FtcGxpbmcuZnJhbWUgPSAxOmxlbmd0aChzdHVkeS5wb3AkR3JBcHB2KSAgIA0KIyBzYW1wbGluZyBsaXN0DQojIG5hbWVzKHN0dWR5LnBvcCkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQojIGNoZWNraW5nIHRoZSBzYW1wbGluZyBsaXN0IHZhcmlhYmxlDQpzYW1wbGVkLmxpc3QgPSBzYW1wbGUoMTpsZW5ndGgoc3R1ZHkucG9wJEdyQXBwdiksIDQwMDApIA0KIyBzYW1wbGluZyB0aGUgbGlzdA0KU1JTLnNhbXBsZSA9IHN0dWR5LnBvcFtzYW1wbGVkLmxpc3QsXSAgICAgICAgICAgICAgICAgIA0KIyBleHRyYWN0IHRoZSBzYW1wbGluZyB1bml0cyAob2JzZXJ2YXRpb25zKQ0KIyMgZGltZW5zaW9uIGNoZWNrDQpkaW1lbnNpb24uU1JTID0gZGltKFNSUy5zYW1wbGUpDQpuYW1lcyhkaW1lbnNpb24uU1JTKSA9IGMoIlNpemUiLCAiVmFyLmNvdW50IikNCmthYmxlKHQoZGltZW5zaW9uLlNSUykpICAgIyBjaGVja2luZyB0aGUgc2FtcGxlIHNpemUNCmBgYA0KDQojIyBTeXN0ZW1hdGljIHNhbXBsaW5nDQoNCmBgYHtyfQ0KanVtcC5zaXplID0gZGltKHN0dWR5LnBvcClbMV0lLyU0MDAwICANCiMgZmluZCB0aGUganVtcCBzaXplIGluIHRoZSBzeXN0ZW1hdGljIHNhbXBsaW5nDQojIGp1bXAuc2l6ZQ0KcmFuZC5zdGFydGluZy5wdD1zYW1wbGUoMTpqdW1wLnNpemUsMSkgIyBmaW5kIHRoZSByYW5kb20gc3RhcnRpbmcgdmFsdWUNCnNhbXBsaW5nLmlkID0gc2VxKHJhbmQuc3RhcnRpbmcucHQsIGRpbShzdHVkeS5wb3ApWzFdLCBqdW1wLnNpemUpICAjIHNhbXBsaW5nIElEcw0KI2xlbmd0aChzYW1wbGluZy5pZCkNCnN5cy5zYW1wbGU9c3R1ZHkucG9wW3NhbXBsaW5nLmlkLF0gICAgDQojIGV4dHJhY3QgdGhlIHNhbXBsaW5nIHVuaXRzIG9mIHN5c3RlbWF0aWMgc2FtcGxlcw0Kc3lzLlNhbXBsZS5kaW0gPSBkaW0oc3lzLnNhbXBsZSkNCm5hbWVzKHN5cy5TYW1wbGUuZGltKSA9IGMoIlNpemUiLCAiVmFyLmNvdW50IikNCmthYmxlKHQoc3lzLlNhbXBsZS5kaW0pKQ0KYGBgDQoNCkJlY2F1c2UgdGhlIGp1bXAgc2l6ZSBpbnZvbHZlcyByb3VuZGluZyBlcnJvciBhbmQgdGhlIHBvcHVsYXRpb24gaXMgbGFyZ2UsIHRoZSBhY3R1YWwgc3lzdGVtYXRpYyBzYW1wbGUgc2l6ZSBpcyBzbGlnaHRseSBkaWZmZXJlbnQgZnJvbSB0aGUgdGFyZ2V0IHNpemUuIEluIHRoaXMgcmVwb3J0LCBJIHVzZWQgdGhlIGludGVnZXIgcGFydCBvZiB0aGUgYWN0dWFsIGp1bXAgc2l6ZS4gVGhlIGFjdHVhbCBzeXN0ZW1hdGljIHNhbXBsaW5nIHNpemUgaXMgc2xpZ2h0bHkgYmlnZ2VyIHRoYW4gdGhlIHRhcmdldCBzaXplLiBXZSBjYW4gdGFrZSBhd2F5IHNvbWUgcmVjb3JkcyByYW5kb20gZnJvbSB0aGUgc3lzdGVtYXRpYyBzYW1wbGUgdG8gbWFrZSB0aGUgc2l6ZSB0byBiZSBlcXVhbCB0byB0aGUgdGFyZ2V0IHNpemUuDQoNCiMjIFN0cmF0aWZpZWQgU2FtcGxpbmcNCg0KV2UgdGFrZSBhbiBTUlMgZnJvbSBlYWNoIHN0cmF0dW0uIFRoZSBzYW1wbGUgc2l6ZSBzaG91bGQgYmUgYXBwcm94aW1hdGVseSBwcm9wb3J0aW9uYWwgdG8gdGhlIHNpemUgb2YgdGhlIGNvcnJlc3BvbmRpbmcgc3RyYXR1bS4NCg0KRmlyc3QsIHdlIGNhbGN1bGF0ZSB0aGUgU1JTIHNpemUgZm9yIGVhY2ggc3RyYXR1bSBhbmQgdGhlbiB0YWtlIHRoZSBTUlMgZnJvbSB0aGUgY29ycmVzcG9uZGluZyBzdHJhdHVtLg0KDQpgYGB7cn0NCmZyZXEudGFibGUgPSB0YWJsZShzdHVkeS5wb3Akc3RyTkFJQ1MpICAjIGZyZXF1ZW5jeSB0YWJsZSBvZiBzdHJOQUlDUw0KcmVsLmZyZXEgPSBmcmVxLnRhYmxlL3N1bShmcmVxLnRhYmxlKSAgICMgcmVsYXRpdmUgZnJlcXVlbmN5IA0Kc3RyYXRhLnNpemUgPSByb3VuZChyZWwuZnJlcSo0MDAwKSAgICAgICMgc3RyYXRhIHNpemUgYWxsb2NhdGlvbg0Kc3RyYXRhLm5hbWVzPW5hbWVzKHN0cmF0YS5zaXplKSAgICAgICAgICMgZXh0cmFjdCBzdHJOQUlDUyBuYW1lcyBmb3IgYWNjdXJhY3kgY2hlY2tpbmcNCmBgYA0KDQpgYGB7cn0NCmthYmxlKHQoc3RyYXRhLnNpemUpKSAgIyBtYWtlIGEgbmljZS1sb29raW5nIHRhYmxlIHVzaW5nIGthYmxlKCkuDQpgYGANCg0KSW4gdGhlIGZvbGxvd2luZyBjb2RlIGNodW5rLCB3ZSB0YWtlIHN0cmF0aWZpZWQgc2FtcGxlcy4NCg0KYGBge3J9DQpzdHJhdGEuc2FtcGxlID0gc3R1ZHkucG9wWzEsXSAgICAjIGNyZWF0ZSBhIHJlZmVyZW5jZSBkYXRhIGZyYW1lDQpzdHJhdGEuc2FtcGxlJGFkZC5pZCA9IDEgICAjIGFkZCBhIHRlbXBvcmFyeSBJRCB0byBiZWNhdXNlIGluIHRoZSBsb29wDQogICAgICAgICAgICAgICAgICAgICAgICAgICAjIGkgPTIgdGVzdGluZyBhIHNpbmdsZSBpdGVyYXRpb24NCmZvciAoaSBpbiAxOmxlbmd0aChzdHJhdGEubmFtZXMpKXsNCiAgIGl0aC5zdHJhdGEubmFtZXMgPSBzdHJhdGEubmFtZXNbaV0gICAjIGV4dHJhY3QgZGF0YSBmcmFtZSBuYW1lcw0KICAgaXRoLnN0cmF0YS5zaXplID0gc3RyYXRhLnNpemVbaV0gICAgICMgYWxsb2NhdGVkIHN0cmF0dW0gc2l6ZQ0KICAgIyBUaGUgZm9sbG93aW5nIGNvZGUgaWRlbnRpZmllcyBvYnNlcnZhdGlvbnMgdG8gYmUgc2VsZWN0ZWQNCiAgIGl0aC5zYW1wbGluZy5pZCA9IHdoaWNoKHN0dWR5LnBvcCRzdHJOQUlDUz09aXRoLnN0cmF0YS5uYW1lcykgDQogICBpdGguc3RyYXRhID0gc3R1ZHkucG9wW2l0aC5zYW1wbGluZy5pZCxdICAjIGktdGggc3RyYXRpZmllZCBwb3B1bGF0aW9uDQogICBpdGguc3RyYXRhJGFkZC5pZCA9IDE6ZGltKGl0aC5zdHJhdGEpWzFdICAjIGFkZCBzYW1wbGluZyBsaXN0L2ZyYW1lDQogICAjIFRoZSBmb2xsb3dpbmcgY29kZSBnZW5lcmF0ZXMgYSBzdWJzZXQgb2YgcmFuZG9tIElEDQogICBpdGguc2FtcGxpbmcuaWQgPSBzYW1wbGUoMTpkaW0oaXRoLnN0cmF0YSlbMV0sIGl0aC5zdHJhdGEuc2l6ZSkgDQogICAjIyBDcmVhdGUgYSBzZWxlY3Rpb24gc3RhdHVzIC0tIHBheSBhdHRlbnRpb24gdG8gdGhlIG9wZXJhdG9yOiAlaW4lIA0KICAgaXRoLnNhbXBsZSA9aXRoLnN0cmF0YVtpdGguc3RyYXRhJGFkZC5pZCAlaW4laXRoLnNhbXBsaW5nLmlkLF0NCiAgICMjIGRpbShpdGguc2FtcGxlKSAgICAgICAgICQgY2hlY2sgdGhlIHNhbXBsZQ0KICAgc3RyYXRhLnNhbXBsZSA9IHJiaW5kKHN0cmF0YS5zYW1wbGUsIGl0aC5zYW1wbGUpICAjIHN0YWNrIGFsbCBkYXRhIGZyYW1lIQ0KIH0NCiAjIGRpbShzdHJhdGEuc2FtcGxlKQ0KIHN0cmF0LnNhbXBsZS5maW5hbCA9IHN0cmF0YS5zYW1wbGVbLTEsXSAgIyBkcm9wIHRoZSB0ZW1wb3Jhcnkgc3RyYXR1bSBJRA0KICNrYWJsZShoZWFkKHN0cmF0LnNhbXBsZS5maW5hbCkpICAgICAgICAgIyBhY2N1cmFjeSBjaGVjayENCmBgYA0KDQoNCiMgUGVyZm9ybWFuY2UgQW5hbHlzaXMgb2YgUmFuZG9tIFNhbXBsZXMNCg0KTmV4dCB3ZWVrLCB3ZSBwZXJmb3JtIGEgY29tcGFyYXRpdmUgYW5hbHlzaXMgb2YgdGhlIHRocmVlIHJhbmRvbSBzYW1wbGVzIHVzaW5nIHRoZSBiYXNlbGluZSBkZWZhdWx0IHJhdGVzLg0KDQoNCiMgQXNzaWdubWVudA0KDQpJbiB0aGlzIGFzc2lnbm1lbnQsIFlvdSBuZWVkIHRvIHRha2UgdGhyZWUgcmFuZG9tIHNhbXBsZXMgYXMgSSBkaWQgaW4gdGhpcyBub3RlOg0KDQoxLiAgU2ltcGxlIHJhbmRvbSBzYW1wbGUgKFNSUykuDQoNCjIuICBTeXN0ZW1hdGljIHJhbmRvbSBzYW1wbGU6IHlvdSBuZWVkIHRvIGNob29zZSBhIHJhbmRvbSBzdGFydGluZyBudW1iZXIuDQoNCjMuICBTdHJhdGlmaWVkIHNhbXBsZTogeW91IG5lZWQgYSBzdHJhdGlmaWNhdGlvbiB2YXJpYWJsZSB0byBzcGxpdCB0aGUgcG9wdWxhdGlvbi4NCg0KNC4gIENsdXN0ZXIgc2FtcGxpbmc6IHlvdSBuZWVkIHRvIChhKSBkZWZpbmUgYSBuZXcgdmVjdG9yIHdpdGggdW5pcXVlIHppcCBjb2RlcywgKGIpdGFrZSBhIHJhbmRvbSBzYW1wbGUgb2YgemlwIGNvZGVzLCAoYykgaW5jbHVkZSBhbGwgbG9hbnMgaW4gdGhlIHJhbmRvbWx5IHNlbGVjdGVkIHppcCBjb2RlcyB0byBnZXQgdGhlIGNsdXN0ZXIgc2FtcGxlLg0K