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.
# Read in the dataset
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)
# dim(bankLoan)
#names(bankLoan)
## Remove NAs from MIS_status
library(tidyverse)
bankLoan <- loan
##convert dollars to numeric
##Variables DisbursementGross, BalanceGross, ChgOffPrinGr, GrAppv, SBA_Appv
colnames(bankLoan)
[1] "LoanNr_ChkDgt" "Name" "City"
[4] "State" "Zip" "Bank"
[7] "BankState" "NAICS" "ApprovalDate"
[10] "ApprovalFY" "Term" "NoEmp"
[13] "NewExist" "CreateJob" "RetainedJob"
[16] "FranchiseCode" "UrbanRural" "RevLineCr"
[19] "LowDoc" "ChgOffDate" "DisbursementDate"
[22] "DisbursementGross" "BalanceGross" "MIS_Status"
[25] "ChgOffPrinGr" "GrAppv" "SBA_Appv"
bankLoan$DisbursementGross <- as.numeric(gsub('[$,]', '', bankLoan$DisbursementGross))
bankLoan$BalanceGross <- as.numeric(gsub('[$,]', '', bankLoan$BalanceGross))
bankLoan$ChgOffPrinGr <- as.numeric(gsub('[$,]', '', bankLoan$ChgOffPrinGr))
bankLoan$GrAppv <- as.numeric(gsub('[$,]', '', bankLoan$GrAppv))
bankLoan$SBA_Appv <- as.numeric(gsub('[$,]', '', bankLoan$SBA_Appv))
Stratifcation
Variable
Here is the distribution of original Number of Employees variable.
This will help us make our groupings for this variable.
hist(bankLoan$NoEmp)

Combining
Categories
We now combine the number of employees the business has into
categories. We created a new variable NoEmpBin based off of NoEmp that
grouped it into five different categories. NoEmpBin will be our
operational stratification variable.
# Re-group the number of business employees
library(dplyr)
bankLoan <- bankLoan %>%
mutate( NoEmpBin = case_when(NoEmp <= 5 ~ '<=5',
NoEmp > 5 & NoEmp <= 25 ~ '6-25',
NoEmp > 25 & NoEmp <=50 ~ '26-50',
NoEmp > 50 & NoEmp <= 100 ~ '51-100',
NoEmp > 100 ~ '101+'))
Loan Default Rates By
Number of Employees
We now find the loan default rates by the number of employees defined
by the stratification variable NoEmpBin The loan default status can be
defined by the variable MIS_Status.
x.table = table(bankLoan$NoEmpBin, 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)
| <=5 |
1568 |
109463 |
412788 |
21.0 |
| 101+ |
36 |
419 |
6998 |
5.6 |
| 26-50 |
29 |
4619 |
48068 |
8.8 |
| 51-100 |
26 |
1301 |
18571 |
6.5 |
| 6-25 |
338 |
41756 |
253184 |
14.2 |
Study Population
Based on the above frequency distribution of the modified number of
employees bins.
study.pop = bankLoan
kable(t(table(bankLoan$NoEmpBin))) # Checking correctness operation
| 523819 |
7453 |
52716 |
19898 |
295278 |
So we have defined our study population!
Sampling Plans
In this section, we are implementing three sampling plans. In each
sampling plan, we select 4000 observations in the corresponding
samples.
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
Systematic
sampling
jump.size = dim(study.pop)[1]%/%4000
# find the jump size in the systematic sampling
# jump.size
rand.starting.pt=sample(2: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))
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.
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$NoEmpBin) # 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().
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$NoEmpBin==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!
Cluster Sampling
Here we will do a cluster sampling method based off of zip codes. We
will cluster the data by zip codes and then take a random sample of zip
codes. Our sample size is roughly around 4000.
#unique zip codes
unizip <- unique(study.pop$Zip)
#random sample of zip codes
# checking the sampling list variable
sampled.zip = sample(unizip, 170)
# join the data to the zip codes
cluster <- study.pop[study.pop$Zip %in% sampled.zip, ]
sys.clsuter = dim(cluster)
names(sys.clsuter) = c("Size", "Var.count")
kable(t(sys.clsuter))
LS0tDQp0aXRsZTogIkltcGxlbWVudGluZyBSYW1kb20gU2FtcGxpbmcgUGxhbnMgIg0KYXV0aG9yOiAiR2lhbm5hIExhRnJhbmNlIg0KZGF0ZTogIiAgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIHRvY19mbG9hdDogeWVzDQogICAgZmlnX3dpZHRoOiA2DQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBzbW9vdGhfc2Nyb2xsOiB0cnVlDQogICAgdGhlbWU6IHJlYWRhYmxlDQogICAgZmlnX2hlaWdodDogNA0KLS0tDQoNCmBgYHs9aHRtbH0NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQpoMS50aXRsZSB7DQogIGZvbnQtc2l6ZTogMjBweDsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KaDQuYXV0aG9yIHsgDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmg0LmRhdGUgeyANCiAgZm9udC1zaXplOiAxOHB4Ow0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQpoMSB7DQogICAgZm9udC1zaXplOiAyMnB4Ow0KICAgIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmgyIHsNCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KZGl2I1RPQyBsaSB7DQogICAgbGlzdC1zdHlsZTpub25lOw0KfQ0KPC9zdHlsZT4NCmBgYA0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQojIGNvZGUgY2h1bmsgc3BlY2lmaWVzIHdoZXRoZXIgdGhlIFIgY29kZSwgd2FybmluZ3MsIGFuZCBvdXRwdXQgDQojIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIG91dHB1dCBmaWxlcy4NCmlmICghcmVxdWlyZSgia25pdHIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KICAgbGlicmFyeShrbml0cikNCn0NCmlmICghcmVxdWlyZSgibGVzc1IiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygibGVzc1IiKQ0KICAgbGlicmFyeShsZXNzUikNCn0NCg0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5ncyA9IEZBTFNFLCAgIA0KICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBUUlVFLCAgIA0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkEpDQpgYGANCg0KDQojIEludHJvZHVjdGlvbg0KDQoNCkluIHRoaXMgbm90ZSwgSSB3aWxsIGludHJvZHVjZSB0aGUgc3RlcHMgZm9yIHRha2luZyByYW5kb20gc2FtcGxlcyBmcm9tIHRoZSBzdHVkeSBwb3B1bGF0aW9uLiBUaGUgQmFuayBsb2FkIGRhdGEgc2V0IGlzIHRyZWF0ZWQgYXMgYSBwb3B1bGF0aW9uLiBXZSB3aWxsIHVzZSB0aGlzIGRhdGEgc2V0IGFzIGEgcG9wdWxhdGlvbiB0byBpbXBsZW1lbnQgdmFyaW91cyBzYW1wbGluZyBwbGFucy4NCg0KVGhlIG9yaWdpbmFsIGRhdGEgc2V0IHdhcyBzcGxpdCBpbnRvIDkgc3Vic2V0cyB0aGF0IGFyZSBzdG9yZWQgb24gR2l0SHViLiBXZSBmaXJzdCBsb2FkIHRoZXNlIGRhdGEgc2V0cyB0byBSIGFuZCB0aGVuIGNvbWJpbmUgdGhlbSBhcyBhIHNpbmdsZSBkYXRhIHNldC4NCg0KYGBge3IgZGF0YXNldH0NCiMgUmVhZCBpbiB0aGUgZGF0YXNldA0KbG9hbjAxID0gcmVhZC5jc3YoImh0dHBzOi8vcGVuZ2RzY2kuZ2l0aHViLmlvL2RhdGFzZXRzL1NCQWxvYW4vdzA2LVNCQW5hdGlvbmFsMDEuY3N2IiwgaGVhZGVyID0gVFJVRSlbLCAtMV0NCmxvYW4wMiA9IHJlYWQuY3N2KCJodHRwczovL3Blbmdkc2NpLmdpdGh1Yi5pby9kYXRhc2V0cy9TQkFsb2FuL3cwNi1TQkFuYXRpb25hbDAyLmNzdiIsIGhlYWRlciA9IFRSVUUpWywgLTFdDQpsb2FuMDMgPSByZWFkLmNzdigiaHR0cHM6Ly9wZW5nZHNjaS5naXRodWIuaW8vZGF0YXNldHMvU0JBbG9hbi93MDYtU0JBbmF0aW9uYWwwMy5jc3YiLCBoZWFkZXIgPSBUUlVFKVssIC0xXQ0KbG9hbjA0ID0gcmVhZC5jc3YoImh0dHBzOi8vcGVuZ2RzY2kuZ2l0aHViLmlvL2RhdGFzZXRzL1NCQWxvYW4vdzA2LVNCQW5hdGlvbmFsMDQuY3N2IiwgaGVhZGVyID0gVFJVRSlbLCAtMV0NCmxvYW4wNSA9IHJlYWQuY3N2KCJodHRwczovL3Blbmdkc2NpLmdpdGh1Yi5pby9kYXRhc2V0cy9TQkFsb2FuL3cwNi1TQkFuYXRpb25hbDA1LmNzdiIsIGhlYWRlciA9IFRSVUUpWywgLTFdDQpsb2FuMDYgPSByZWFkLmNzdigiaHR0cHM6Ly9wZW5nZHNjaS5naXRodWIuaW8vZGF0YXNldHMvU0JBbG9hbi93MDYtU0JBbmF0aW9uYWwwNi5jc3YiLCBoZWFkZXIgPSBUUlVFKVssIC0xXQ0KbG9hbjA3ID0gcmVhZC5jc3YoImh0dHBzOi8vcGVuZ2RzY2kuZ2l0aHViLmlvL2RhdGFzZXRzL1NCQWxvYW4vdzA2LVNCQW5hdGlvbmFsMDcuY3N2IiwgaGVhZGVyID0gVFJVRSlbLCAtMV0NCmxvYW4wOCA9IHJlYWQuY3N2KCJodHRwczovL3Blbmdkc2NpLmdpdGh1Yi5pby9kYXRhc2V0cy9TQkFsb2FuL3cwNi1TQkFuYXRpb25hbDA4LmNzdiIsIGhlYWRlciA9IFRSVUUpWywgLTFdDQpsb2FuMDkgPSByZWFkLmNzdigiaHR0cHM6Ly9wZW5nZHNjaS5naXRodWIuaW8vZGF0YXNldHMvU0JBbG9hbi93MDYtU0JBbmF0aW9uYWwwOS5jc3YiLCBoZWFkZXIgPSBUUlVFKVssIC0xXQ0KbG9hbiA9IHJiaW5kKGxvYW4wMSwgbG9hbjAyLCBsb2FuMDMsIGxvYW4wNCwgbG9hbjA1LCBsb2FuMDYsIGxvYW4wNywgbG9hbjA4LCBsb2FuMDkpDQojIGRpbShiYW5rTG9hbikNCiNuYW1lcyhiYW5rTG9hbikNCmBgYA0KDQpgYGB7cn0NCiMjIFJlbW92ZSBOQXMgZnJvbSBNSVNfc3RhdHVzDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmJhbmtMb2FuIDwtIGxvYW4NCmBgYA0KDQpgYGB7cn0NCiMjY29udmVydCBkb2xsYXJzIHRvIG51bWVyaWMNCiMjVmFyaWFibGVzIERpc2J1cnNlbWVudEdyb3NzLCBCYWxhbmNlR3Jvc3MsIENoZ09mZlByaW5HciwgR3JBcHB2LCBTQkFfQXBwdg0KY29sbmFtZXMoYmFua0xvYW4pDQoNCmJhbmtMb2FuJERpc2J1cnNlbWVudEdyb3NzIDwtIGFzLm51bWVyaWMoZ3N1YignWyQsXScsICcnLCBiYW5rTG9hbiREaXNidXJzZW1lbnRHcm9zcykpDQpiYW5rTG9hbiRCYWxhbmNlR3Jvc3MgPC0gYXMubnVtZXJpYyhnc3ViKCdbJCxdJywgJycsIGJhbmtMb2FuJEJhbGFuY2VHcm9zcykpDQpiYW5rTG9hbiRDaGdPZmZQcmluR3IgPC0gYXMubnVtZXJpYyhnc3ViKCdbJCxdJywgJycsIGJhbmtMb2FuJENoZ09mZlByaW5HcikpDQpiYW5rTG9hbiRHckFwcHYgPC0gYXMubnVtZXJpYyhnc3ViKCdbJCxdJywgJycsIGJhbmtMb2FuJEdyQXBwdikpDQpiYW5rTG9hbiRTQkFfQXBwdiA8LSBhcy5udW1lcmljKGdzdWIoJ1skLF0nLCAnJywgYmFua0xvYW4kU0JBX0FwcHYpKQ0KDQpgYGANCg0KDQojIyBTdHJhdGlmY2F0aW9uIFZhcmlhYmxlDQoNCg0KSGVyZSBpcyB0aGUgZGlzdHJpYnV0aW9uIG9mIG9yaWdpbmFsIE51bWJlciBvZiBFbXBsb3llZXMgdmFyaWFibGUuIFRoaXMgd2lsbCBoZWxwIHVzIG1ha2Ugb3VyIGdyb3VwaW5ncyBmb3IgdGhpcyB2YXJpYWJsZS4NCg0KYGBge3IgZGF0YS1zaXplfQ0KaGlzdChiYW5rTG9hbiROb0VtcCkNCmBgYA0KDQoNCiMjIENvbWJpbmluZyBDYXRlZ29yaWVzDQoNCldlIG5vdyBjb21iaW5lIHRoZSBudW1iZXIgb2YgZW1wbG95ZWVzIHRoZSBidXNpbmVzcyBoYXMgaW50byBjYXRlZ29yaWVzLiBXZSBjcmVhdGVkIGEgbmV3IHZhcmlhYmxlIE5vRW1wQmluIGJhc2VkIG9mZiBvZiBOb0VtcCB0aGF0IGdyb3VwZWQgaXQgaW50byBmaXZlIGRpZmZlcmVudCBjYXRlZ29yaWVzLiBOb0VtcEJpbiB3aWxsIGJlIG91ciBvcGVyYXRpb25hbCBzdHJhdGlmaWNhdGlvbiB2YXJpYWJsZS4NCg0KDQpgYGB7cn0NCiMgUmUtZ3JvdXAgdGhlIG51bWJlciBvZiBidXNpbmVzcyBlbXBsb3llZXMNCmxpYnJhcnkoZHBseXIpDQpiYW5rTG9hbiA8LSBiYW5rTG9hbiAlPiUgDQogIG11dGF0ZSggTm9FbXBCaW4gPSBjYXNlX3doZW4oTm9FbXAgPD0gNSB+ICc8PTUnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5vRW1wID4gNSAmIE5vRW1wIDw9IDI1IH4gJzYtMjUnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5vRW1wID4gMjUgJiBOb0VtcCA8PTUwIH4gJzI2LTUwJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOb0VtcCA+IDUwICYgTm9FbXAgPD0gMTAwIH4gJzUxLTEwMCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTm9FbXAgPiAxMDAgIH4gJzEwMSsnKSkgDQoNCmBgYA0KDQoNCiMjIExvYW4gRGVmYXVsdCBSYXRlcyBCeSBOdW1iZXIgb2YgRW1wbG95ZWVzDQoNCldlIG5vdyBmaW5kIHRoZSBsb2FuIGRlZmF1bHQgcmF0ZXMgYnkgdGhlIG51bWJlciBvZiBlbXBsb3llZXMgZGVmaW5lZCBieSB0aGUgc3RyYXRpZmljYXRpb24gdmFyaWFibGUgTm9FbXBCaW4gVGhlIGxvYW4gZGVmYXVsdCBzdGF0dXMgY2FuIGJlIGRlZmluZWQgYnkgdGhlIHZhcmlhYmxlIE1JU19TdGF0dXMuDQoNCmBgYHtyfQ0KeC50YWJsZSA9IHRhYmxlKGJhbmtMb2FuJE5vRW1wQmluLCBiYW5rTG9hbiRNSVNfU3RhdHVzKQ0Kbm8ubGFiID0geC50YWJsZVssMV0gICMgZmlyc3QgY29sdW1uIGNvbnNpc3RzIG9mIHVua25vd24gZGVmYXVsdCBsYWJlbA0KZGVmYXVsdCA9IHgudGFibGVbLDJdDQpuby5kZWZhdWx0ID0geC50YWJsZVssM10NCmRlZmF1bHQucmF0ZSA9IHJvdW5kKDEwMCpkZWZhdWx0LyhkZWZhdWx0K25vLmRlZmF1bHQpLDEpDQpkZWZhdWx0LnN0YXR1cy5yYXRlID0gY2JpbmQobm8ubGFiID0gbm8ubGFiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgZGVmYXVsdCA9IGRlZmF1bHQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBuby5kZWZhdWx0ID0gbm8uZGVmYXVsdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZGVmYXVsdC5yYXRlPWRlZmF1bHQucmF0ZSkNCmthYmxlKGRlZmF1bHQuc3RhdHVzLnJhdGUpDQpgYGANCg0KIyMgU3R1ZHkgUG9wdWxhdGlvbg0KDQpCYXNlZCBvbiB0aGUgYWJvdmUgZnJlcXVlbmN5IGRpc3RyaWJ1dGlvbiBvZiB0aGUgbW9kaWZpZWQgbnVtYmVyIG9mIGVtcGxveWVlcyBiaW5zLg0KDQpgYGB7cn0NCnN0dWR5LnBvcCA9IGJhbmtMb2FuDQprYWJsZSh0KHRhYmxlKGJhbmtMb2FuJE5vRW1wQmluKSkpICMgQ2hlY2tpbmcgY29ycmVjdG5lc3Mgb3BlcmF0aW9uDQpgYGANCg0KU28gd2UgaGF2ZSBkZWZpbmVkIG91ciBzdHVkeSBwb3B1bGF0aW9uIQ0KDQojIFNhbXBsaW5nIFBsYW5zDQoNCkluIHRoaXMgc2VjdGlvbiwgd2UgYXJlIGltcGxlbWVudGluZyB0aHJlZSBzYW1wbGluZyBwbGFucy4gSW4gZWFjaCBzYW1wbGluZyBwbGFuLCB3ZSBzZWxlY3QgNDAwMCBvYnNlcnZhdGlvbnMgaW4gdGhlIGNvcnJlc3BvbmRpbmcgc2FtcGxlcy4NCg0KIyMgU2ltcGxlIFJhbmRvbSBTYW1wbGluZw0KDQpXZSBkZWZpbmUgYSBzYW1wbGluZyBsaXN0IGFuZCBhZGQgaXQgdG8gdGhlIHN0dWR5IHBvcHVsYXRpb24uDQoNCmBgYHtyfQ0Kc3R1ZHkucG9wJHNhbXBsaW5nLmZyYW1lID0gMTpsZW5ndGgoc3R1ZHkucG9wJEdyQXBwdikgICANCiMgc2FtcGxpbmcgbGlzdA0KIyBuYW1lcyhzdHVkeS5wb3ApICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KIyBjaGVja2luZyB0aGUgc2FtcGxpbmcgbGlzdCB2YXJpYWJsZQ0Kc2FtcGxlZC5saXN0ID0gc2FtcGxlKDE6bGVuZ3RoKHN0dWR5LnBvcCRHckFwcHYpLCA0MDAwKSANCiMgc2FtcGxpbmcgdGhlIGxpc3QNClNSUy5zYW1wbGUgPSBzdHVkeS5wb3Bbc2FtcGxlZC5saXN0LF0gICAgICAgICAgICAgICAgICANCiMgZXh0cmFjdCB0aGUgc2FtcGxpbmcgdW5pdHMgKG9ic2VydmF0aW9ucykNCiMjIGRpbWVuc2lvbiBjaGVjaw0KZGltZW5zaW9uLlNSUyA9IGRpbShTUlMuc2FtcGxlKQ0KbmFtZXMoZGltZW5zaW9uLlNSUykgPSBjKCJTaXplIiwgIlZhci5jb3VudCIpDQprYWJsZSh0KGRpbWVuc2lvbi5TUlMpKSAgICMgY2hlY2tpbmcgdGhlIHNhbXBsZSBzaXplDQpgYGANCg0KIyMgU3lzdGVtYXRpYyBzYW1wbGluZw0KDQpgYGB7cn0NCmp1bXAuc2l6ZSA9IGRpbShzdHVkeS5wb3ApWzFdJS8lNDAwMCAgDQojIGZpbmQgdGhlIGp1bXAgc2l6ZSBpbiB0aGUgc3lzdGVtYXRpYyBzYW1wbGluZw0KIyBqdW1wLnNpemUNCnJhbmQuc3RhcnRpbmcucHQ9c2FtcGxlKDI6anVtcC5zaXplLDEpICMgZmluZCB0aGUgcmFuZG9tIHN0YXJ0aW5nIHZhbHVlDQpzYW1wbGluZy5pZCA9IHNlcShyYW5kLnN0YXJ0aW5nLnB0LCBkaW0oc3R1ZHkucG9wKVsxXSwganVtcC5zaXplKSAgIyBzYW1wbGluZyBJRHMNCiNsZW5ndGgoc2FtcGxpbmcuaWQpDQpzeXMuc2FtcGxlPXN0dWR5LnBvcFtzYW1wbGluZy5pZCxdICAgIA0KIyBleHRyYWN0IHRoZSBzYW1wbGluZyB1bml0cyBvZiBzeXN0ZW1hdGljIHNhbXBsZXMNCnN5cy5TYW1wbGUuZGltID0gZGltKHN5cy5zYW1wbGUpDQpuYW1lcyhzeXMuU2FtcGxlLmRpbSkgPSBjKCJTaXplIiwgIlZhci5jb3VudCIpDQprYWJsZSh0KHN5cy5TYW1wbGUuZGltKSkNCmBgYA0KDQpCZWNhdXNlIHRoZSBqdW1wIHNpemUgaW52b2x2ZXMgcm91bmRpbmcgZXJyb3IgYW5kIHRoZSBwb3B1bGF0aW9uIGlzIGxhcmdlLCB0aGUgYWN0dWFsIHN5c3RlbWF0aWMgc2FtcGxlIHNpemUgaXMgc2xpZ2h0bHkgZGlmZmVyZW50IGZyb20gdGhlIHRhcmdldCBzaXplLiBJbiB0aGlzIHJlcG9ydCwgSSB1c2VkIHRoZSBpbnRlZ2VyIHBhcnQgb2YgdGhlIGFjdHVhbCBqdW1wIHNpemUuIFRoZSBhY3R1YWwgc3lzdGVtYXRpYyBzYW1wbGluZyBzaXplIGlzIHNsaWdodGx5IGJpZ2dlciB0aGFuIHRoZSB0YXJnZXQgc2l6ZS4gV2UgY2FuIHRha2UgYXdheSBzb21lIHJlY29yZHMgcmFuZG9tIGZyb20gdGhlIHN5c3RlbWF0aWMgc2FtcGxlIHRvIG1ha2UgdGhlIHNpemUgdG8gYmUgZXF1YWwgdG8gdGhlIHRhcmdldCBzaXplLg0KDQojIyBTdHJhdGlmaWVkIFNhbXBsaW5nDQoNCldlIHRha2UgYW4gU1JTIGZyb20gZWFjaCBzdHJhdHVtLiBUaGUgc2FtcGxlIHNpemUgc2hvdWxkIGJlIGFwcHJveGltYXRlbHkgcHJvcG9ydGlvbmFsIHRvIHRoZSBzaXplIG9mIHRoZSBjb3JyZXNwb25kaW5nIHN0cmF0dW0uDQoNCkZpcnN0LCB3ZSBjYWxjdWxhdGUgdGhlIFNSUyBzaXplIGZvciBlYWNoIHN0cmF0dW0gYW5kIHRoZW4gdGFrZSB0aGUgU1JTIGZyb20gdGhlIGNvcnJlc3BvbmRpbmcgc3RyYXR1bS4NCg0KYGBge3J9DQpmcmVxLnRhYmxlID0gdGFibGUoc3R1ZHkucG9wJE5vRW1wQmluKSAgIyBmcmVxdWVuY3kgdGFibGUgb2Ygc3RyTkFJQ1MNCnJlbC5mcmVxID0gZnJlcS50YWJsZS9zdW0oZnJlcS50YWJsZSkgICAjIHJlbGF0aXZlIGZyZXF1ZW5jeSANCnN0cmF0YS5zaXplID0gcm91bmQocmVsLmZyZXEqNDAwMCkgICAgICAjIHN0cmF0YSBzaXplIGFsbG9jYXRpb24NCnN0cmF0YS5uYW1lcz1uYW1lcyhzdHJhdGEuc2l6ZSkgICAgICAgICAjIGV4dHJhY3Qgc3RyTkFJQ1MgbmFtZXMgZm9yIGFjY3VyYWN5IGNoZWNraW5nDQpgYGANCg0KYGBge3J9DQprYWJsZSh0KHN0cmF0YS5zaXplKSkgICMgbWFrZSBhIG5pY2UtbG9va2luZyB0YWJsZSB1c2luZyBrYWJsZSgpLg0KYGBgDQoNCkluIHRoZSBmb2xsb3dpbmcgY29kZSBjaHVuaywgd2UgdGFrZSBzdHJhdGlmaWVkIHNhbXBsZXMuDQoNCmBgYHtyfQ0Kc3RyYXRhLnNhbXBsZSA9IHN0dWR5LnBvcFsxLF0gICAgIyBjcmVhdGUgYSByZWZlcmVuY2UgZGF0YSBmcmFtZQ0Kc3RyYXRhLnNhbXBsZSRhZGQuaWQgPSAxICAgIyBhZGQgYSB0ZW1wb3JhcnkgSUQgdG8gYmVjYXVzZSBpbiB0aGUgbG9vcA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBpID0yIHRlc3RpbmcgYSBzaW5nbGUgaXRlcmF0aW9uDQpmb3IgKGkgaW4gMTpsZW5ndGgoc3RyYXRhLm5hbWVzKSl7DQogICBpdGguc3RyYXRhLm5hbWVzID0gc3RyYXRhLm5hbWVzW2ldICAgIyBleHRyYWN0IGRhdGEgZnJhbWUgbmFtZXMNCiAgIGl0aC5zdHJhdGEuc2l6ZSA9IHN0cmF0YS5zaXplW2ldICAgICAjIGFsbG9jYXRlZCBzdHJhdHVtIHNpemUNCiAgICMgVGhlIGZvbGxvd2luZyBjb2RlIGlkZW50aWZpZXMgb2JzZXJ2YXRpb25zIHRvIGJlIHNlbGVjdGVkDQogICBpdGguc2FtcGxpbmcuaWQgPSB3aGljaChzdHVkeS5wb3AkTm9FbXBCaW49PWl0aC5zdHJhdGEubmFtZXMpIA0KICAgaXRoLnN0cmF0YSA9IHN0dWR5LnBvcFtpdGguc2FtcGxpbmcuaWQsXSAgIyBpLXRoIHN0cmF0aWZpZWQgcG9wdWxhdGlvbg0KICAgaXRoLnN0cmF0YSRhZGQuaWQgPSAxOmRpbShpdGguc3RyYXRhKVsxXSAgIyBhZGQgc2FtcGxpbmcgbGlzdC9mcmFtZQ0KICAgIyBUaGUgZm9sbG93aW5nIGNvZGUgZ2VuZXJhdGVzIGEgc3Vic2V0IG9mIHJhbmRvbSBJRA0KICAgaXRoLnNhbXBsaW5nLmlkID0gc2FtcGxlKDE6ZGltKGl0aC5zdHJhdGEpWzFdLCBpdGguc3RyYXRhLnNpemUpIA0KICAgIyMgQ3JlYXRlIGEgc2VsZWN0aW9uIHN0YXR1cyAtLSBwYXkgYXR0ZW50aW9uIHRvIHRoZSBvcGVyYXRvcjogJWluJSANCiAgIGl0aC5zYW1wbGUgPWl0aC5zdHJhdGFbaXRoLnN0cmF0YSRhZGQuaWQgJWluJWl0aC5zYW1wbGluZy5pZCxdDQogICAjIyBkaW0oaXRoLnNhbXBsZSkgICAgICAgICAkIGNoZWNrIHRoZSBzYW1wbGUNCiAgIHN0cmF0YS5zYW1wbGUgPSByYmluZChzdHJhdGEuc2FtcGxlLCBpdGguc2FtcGxlKSAgIyBzdGFjayBhbGwgZGF0YSBmcmFtZSENCiB9DQogIyBkaW0oc3RyYXRhLnNhbXBsZSkNCiBzdHJhdC5zYW1wbGUuZmluYWwgPSBzdHJhdGEuc2FtcGxlWy0xLF0gICMgZHJvcCB0aGUgdGVtcG9yYXJ5IHN0cmF0dW0gSUQNCiAja2FibGUoaGVhZChzdHJhdC5zYW1wbGUuZmluYWwpKSAgICAgICAgICMgYWNjdXJhY3kgY2hlY2shDQpgYGANCg0KIyMgQ2x1c3RlciBTYW1wbGluZw0KDQpIZXJlIHdlIHdpbGwgZG8gYSBjbHVzdGVyIHNhbXBsaW5nIG1ldGhvZCBiYXNlZCBvZmYgb2YgemlwIGNvZGVzLiBXZSB3aWxsIGNsdXN0ZXIgdGhlIGRhdGEgYnkgemlwIGNvZGVzIGFuZCB0aGVuIHRha2UgYSByYW5kb20gc2FtcGxlIG9mIHppcCBjb2Rlcy4gT3VyIHNhbXBsZSBzaXplIGlzIHJvdWdobHkgYXJvdW5kIDQwMDAuDQoNCmBgYHtyfQ0KI3VuaXF1ZSB6aXAgY29kZXMNCnVuaXppcCA8LSB1bmlxdWUoc3R1ZHkucG9wJFppcCkNCg0KI3JhbmRvbSBzYW1wbGUgb2YgemlwIGNvZGVzDQojIGNoZWNraW5nIHRoZSBzYW1wbGluZyBsaXN0IHZhcmlhYmxlDQpzYW1wbGVkLnppcCA9IHNhbXBsZSh1bml6aXAsIDE3MCkgDQoNCiMgam9pbiB0aGUgZGF0YSB0byB0aGUgemlwIGNvZGVzDQpjbHVzdGVyIDwtIHN0dWR5LnBvcFtzdHVkeS5wb3AkWmlwICVpbiUgc2FtcGxlZC56aXAsIF0NCg0Kc3lzLmNsc3V0ZXIgPSBkaW0oY2x1c3RlcikNCm5hbWVzKHN5cy5jbHN1dGVyKSA9IGMoIlNpemUiLCAiVmFyLmNvdW50IikNCmthYmxlKHQoc3lzLmNsc3V0ZXIpKQ0KDQpgYGANCg0KDQo=