Exploratory Data
Analysis
First, we will read in the combined bank loan data sets.
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)
var.names = names(loan)
my.var = var.names[c(1,6,21,26)]
my.new.data = loan[1:15, my.var]
dim(my.new.data)
[1] 15 4
Addressing the
Missing Values
This data set contains some missing values and so we must address
these before continuing any further with our analysis of this data. For
this project, we will delete all of the observations which had a missing
value of MIS_Status.
colSums(is.na(loan))
LoanNr_ChkDgt Name City State
0 5 0 0
Zip Bank BankState NAICS
0 0 0 0
ApprovalDate ApprovalFY Term NoEmp
0 0 0 0
NewExist CreateJob RetainedJob FranchiseCode
136 0 0 0
UrbanRural RevLineCr LowDoc ChgOffDate
0 0 0 0
DisbursementDate DisbursementGross BalanceGross MIS_Status
0 0 0 0
ChgOffPrinGr GrAppv SBA_Appv
0 0 0
It turns out that the MIS_Status variable has zero missing
observations, so we do not have to delete any observations based upon a
missing value of MIS_Status.
In fact, the only variable with any missing observations is the
NewExist variable. We will go ahead and delete these missing
observations instead since the MIS_Status variable was all good. There
are 136 missing observations of this NewExist variable and we will
delete these missing observations.
We will create a new data set called “loan.noMissing” to represent
that it has no missing observations.
loan.noMissing <- na.omit(loan)
Let’s double check that we successfully removed all observations with
missing values from the data set.
colSums(is.na(loan.noMissing))
LoanNr_ChkDgt Name City State
0 0 0 0
Zip Bank BankState NAICS
0 0 0 0
ApprovalDate ApprovalFY Term NoEmp
0 0 0 0
NewExist CreateJob RetainedJob FranchiseCode
0 0 0 0
UrbanRural RevLineCr LowDoc ChgOffDate
0 0 0 0
DisbursementDate DisbursementGross BalanceGross MIS_Status
0 0 0 0
ChgOffPrinGr GrAppv SBA_Appv
0 0 0
As we can see, no variables have any more missing observations, so we
have successfully dealt with the missing value concern for our data
set.
Variable
Formatting
We will now change all of the currency related variables in this
combined bank loan data set to be regular, numeric variables. These
currency related variables include DisbursementGross, BalanceGross,
ChgOffPrinGr, GrAppv, and SBA_Appv. To do this, we will remove the
dollar sign and the commas from the observations of these currency
related variables.
currency <- c("DisbursementGross", "BalanceGross", "ChgOffPrinGr", "GrAppv", "SBA_Appv")
loan.updated <- loan.noMissing %>%
mutate(across(all_of(currency), ~ as.numeric(gsub("[$,]", "", .))))
Now, all of the currency related variables have been updated to be
represented as standard, numeric variables without commas or a dollar
sign. The new, updated variable data has been stored in a new data set
called “loan.updated”.
We can view a summary of these updated, numeric variables on currency
to ensure that these changes to remove the commas and dollar signs
properly worked.
summary(loan.updated[currency])
DisbursementGross BalanceGross ChgOffPrinGr GrAppv
Min. : 0 Min. : 0 Min. : 0 Min. : 200
1st Qu.: 42000 1st Qu.: 0 1st Qu.: 0 1st Qu.: 35000
Median : 100000 Median : 0 Median : 0 Median : 90000
Mean : 201142 Mean : 3 Mean : 13505 Mean : 192676
3rd Qu.: 238000 3rd Qu.: 0 3rd Qu.: 0 3rd Qu.: 225000
Max. :11446325 Max. :996262 Max. :3512596 Max. :5472000
SBA_Appv
Min. : 100
1st Qu.: 21250
Median : 61285
Mean : 149480
3rd Qu.: 175000
Max. :5472000
As we can see, the values of all of these currency variables are now
given as standard, numeric variables.
Combining Sparse
Categories
Now, we will take a look at one of the categorical variables from
this combined bank loan data set and combine its sparse categories in a
way that is meaningful. This will allow us to have new categories that
are fewer in number, and provide better meaningfulness for the
interpretation of this variable.
We will look at the categorical variable “NAICS”. This variable looks
at the North American Industry Classification System code of each
observation. This variable defines each observation by the specific
industry of which it is relevant to.
knitr::include_graphics("NAICS.png")

We will combined the observations of the NAICS variable into
categories based upon their official classification.
loan.updated<- loan.updated %>%
mutate(NAICS.combined = case_when(
NAICS %in% c("11") ~ "Agriculture",
NAICS %in% c("21") ~ "Mining",
NAICS %in% c("22") ~ "Utilities",
NAICS %in% c("23") ~ "Construction",
NAICS %in% c("31", "32", "33") ~ "Manufacturing",
NAICS %in% c("42") ~ "Wholesale Trade",
NAICS %in% c("48", "49") ~ "Transportation",
NAICS %in% c("51") ~ "Information",
NAICS %in% c("52") ~ "Finance",
NAICS %in% c("53") ~ "Real Estate",
NAICS %in% c("54") ~ "Professional Services",
NAICS %in% c("55") ~ "Management",
NAICS %in% c("56") ~ "Administrative Support",
NAICS %in% c("61") ~ "Educational Services",
NAICS %in% c("62") ~ "Healthcare",
NAICS %in% c("71") ~ "Arts",
NAICS %in% c("72") ~ "Food Services",
NAICS %in% c("81") ~ "Other Services",
NAICS %in% c("92") ~ "Public Administration"
)
)
Calculating the
Default Rates
Next, we will calculate the default rates of the NAICS.combined
categorical variable which we created in the previous part.
For this step, the value CHGOFF in MIS_Status is defined to be loan
default. The default rate will be the percentage of CHGOFF in
MIS_Status.
default.rates <- loan.updated %>%
group_by(NAICS.combined) %>%
summarise(total = n(),
defaults = sum(MIS_Status == "CHGOFF", na.rm = TRUE),
default.rates = defaults / total)
We can view the values of the default rates which we calculated.
default.rates
# A tibble: 1 × 4
NAICS.combined total defaults default.rates
<chr> <int> <int> <dbl>
1 <NA> 899023 157543 0.175
Now, we have successfully calculated the default rates for our
NAICS.combined variable which we created to group together the sparse
categories.
Discretizing the
GrAppv Variable
We will discretize the variable of GrAppv into five categories. This
variable represents the gross amount of the loan that has been approved
by the bank.
We will create these categories based upon the overall level of he
value of the GrAppv value. These subcategories will split the GrAppv
variable into five levels, “lowest”, “low”, “medium”, “high”, and
“highest” based upon the value of the gross amount of loan that has been
approved by the ban.
First, let’s look at a quick summary of the original GrAppv
variable.
summary(loan.updated$GrAppv)
Min. 1st Qu. Median Mean 3rd Qu. Max.
200 35000 90000 192676 225000 5472000
As we can see, the minimum value of the variable is $200, and the
maximum value is $5,472,000. The median value is $90,000 indicating that
the maximum value differs much more greatly from the median value than
the minimum value does.
We will split the GrAppv variable into five subcategories based upon
the value of each observation. We will create a new variable called
“GrAppv.dis” to represent the discretized version of the original GrAppv
variable.
loan.updated$GrAppv.dis <- cut(loan.updated$GrAppv,
breaks = 5,
labels = c("Lowest", "Low", "Medium", "High", "Highest"))
Now we have five subcategories of the GrAppv variable split up from
the lowest to the highest.
Density Curves
Lastly, we will draw the density curves of SBA_Appv for each of the
five sub-populations that were created in the previous part. We will
place these five density curves onto the same plot.
ggplot(loan.updated, aes(x = SBA_Appv, fill = GrAppv.dis)) +
geom_density(alpha = 0.5) +
labs(title = "Density Curves of SBA_Appv for the \n Five SubCategories of GrAppv",
x = "SBA_Appv", y = "Density")

In the graph, we can see the density curves of the SBA_Appv variable
for each of the five categories of GrAppv that we created in the
previous part. We can see that these five categories have been
color-coded by their respective rank of “lowest”, “low”, “medium”,
“high”, “or highest”.
LS0tDQp0aXRsZTogIkVEQSB3aXRoIHRoZSBDb21iaW5lZCBCYW5rIExvYW4gRGF0YSBTZXQiDQphdXRob3I6ICJKb3NpZSBHYWxsb3AiDQpkYXRlOiAiMjAyNS0wMi0yNCINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIGZpZ193aWR0aDogNg0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRvY19jb2xsYXBzZWQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHNtb290aF9zY3JvbGw6IHllcw0KICAgIHRoZW1lOiBsdW1lbg0KICB3b3JkX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBrZWVwX21kOiB5ZXMNCiAgcGRmX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KZWRpdG9yX29wdGlvbnM6IA0KICBjaHVua19vdXRwdXRfdHlwZTogY29uc29sZQ0KLS0tDQoNCmBgYHs9aHRtbH0NCg0KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4NCg0KLyogQ2FzY2FkaW5nIFN0eWxlIFNoZWV0cyAoQ1NTKSBpcyBhIHN0eWxlc2hlZXQgbGFuZ3VhZ2UgdXNlZCB0byBkZXNjcmliZSB0aGUgcHJlc2VudGF0aW9uIG9mIGEgZG9jdW1lbnQgd3JpdHRlbiBpbiBIVE1MIG9yIFhNTC4gaXQgaXMgYSBzaW1wbGUgbWVjaGFuaXNtIGZvciBhZGRpbmcgc3R5bGUgKGUuZy4sIGZvbnRzLCBjb2xvcnMsIHNwYWNpbmcpIHRvIFdlYiBkb2N1bWVudHMuICovDQoNCmgxLnRpdGxlIHsgIC8qIFRpdGxlIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiB0aGUgcmVwb3J0IHRpdGxlICovDQogIGZvbnQtc2l6ZTogMjRweDsNCiAgY29sb3I6IERhcmtSZWQ7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOw0KfQ0KaDQuYXV0aG9yIHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBhdXRob3JzICAqLw0KICBmb250LXNpemU6IDIwcHg7DQogIGZvbnQtZmFtaWx5OiBzeXN0ZW0tdWk7DQogIGNvbG9yOiBEYXJrUmVkOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQpoNC5kYXRlIHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciB0aGUgZGF0ZSAgKi8NCiAgZm9udC1zaXplOiAxOHB4Ow0KICBmb250LWZhbWlseTogc3lzdGVtLXVpOw0KICBjb2xvcjogRGFya0JsdWU7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmgxIHsgLyogSGVhZGVyIDEgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBsZXZlbCAxIHNlY3Rpb24gdGl0bGUgICovDQogICAgZm9udC1zaXplOiAyMnB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmgyIHsgLyogSGVhZGVyIDIgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBsZXZlbCAyIHNlY3Rpb24gdGl0bGUgKi8NCiAgICBmb250LXNpemU6IDIwcHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDMgeyAvKiBIZWFkZXIgMyAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgbGV2ZWwgMyBzZWN0aW9uIHRpdGxlICAqLw0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoNCB7IC8qIEhlYWRlciA0IC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiBsZXZlbCA0IHNlY3Rpb24gdGl0bGUgICovDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmJvZHkgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9DQoNCi5oaWdobGlnaHRtZSB7IGJhY2tncm91bmQtY29sb3I6eWVsbG93OyB9DQoNCnAgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9DQoNCjwvc3R5bGU+DQpgYGANCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KIyBEZXRlY3QsIGluc3RhbGwsIGFuZCBsb2FkIHBhY2thZ2VzIGlmIG5lZWRlZC4NCmlmICghcmVxdWlyZSgia25pdHIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KICAgbGlicmFyeShrbml0cikNCn0NCmlmICghcmVxdWlyZSgibGVhZmxldCIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJsZWFmbGV0IikNCiAgIGxpYnJhcnkobGVhZmxldCkNCn0NCmlmICghcmVxdWlyZSgiRW52U3RhdHMiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygiRW52U3RhdHMiKQ0KICAgbGlicmFyeShFbnZTdGF0cykNCn0NCmlmICghcmVxdWlyZSgiTUFTUyIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJNQVNTIikNCiAgIGxpYnJhcnkoTUFTUykNCn0NCmlmICghcmVxdWlyZSgicGh5dG9vbHMiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygicGh5dG9vbHMiKQ0KICAgbGlicmFyeShwaHl0b29scykNCn0NCmlmKCFyZXF1aXJlKCJkcGx5ciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJkcGx5ciIpDQogICBsaWJyYXJ5KGRwbHlyKQ0KfQ0KaWYoIXJlcXVpcmUoInRpZHl2ZXJzZSIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KICAgbGlicmFyeSh0aWR5dmVyc2UpDQp9DQppZighcmVxdWlyZSgiR0dhbGx5IikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoIkdHYWxseSIpDQogICBsaWJyYXJ5KEdHYWxseSkNCn0NCmlmKCFyZXF1aXJlKCJ1c2RtIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInVzZG0iKQ0KICAgbGlicmFyeSh1c2RtKQ0KfQ0KaWYoIXJlcXVpcmUoImNhciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJjYXIiKQ0KICAgbGlicmFyeShjYXIpDQp9DQppZiAoIXJlcXVpcmUoImJvb3QiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygiYm9vdCIpDQogICBsaWJyYXJ5KGJvb3QpDQp9DQppZighcmVxdWlyZSgicGFuZGVyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInBhbmRlciIpDQogICBsaWJyYXJ5KHBhbmRlcikNCn0NCmlmKCFyZXF1aXJlKCJtaWNlIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoIm1pY2UiKQ0KICAgbGlicmFyeShtaWNlKQ0KfQ0KaWYoIXJlcXVpcmUoIm1sYmVuY2giKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygibWxiZW5jaCIpDQogICBsaWJyYXJ5KG1sYmVuY2gpDQp9DQppZighcmVxdWlyZSgicHN5Y2giKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygicHN5Y2giKQ0KICAgbGlicmFyeShwc3ljaCkNCn0NCmlmKCFyZXF1aXJlKCJicm9vbS5taXhlZCIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJicm9vbS5taXhlZCIpDQogICBsaWJyYXJ5KGJyb29tLm1peGVkKQ0KfQ0KaWYoIXJlcXVpcmUoIkdHYWxseSIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJHR2FsbHkiKQ0KICAgbGlicmFyeShHR2FsbHkpDQp9DQppZighcmVxdWlyZSgiY2FyZXQiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygiY2FyZXQiKQ0KICAgbGlicmFyeShjYXJldCkNCn0NCmlmICghcmVxdWlyZSgicFJPQyIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJwUk9DIikNCiAgIGxpYnJhcnkocFJPQykNCn0NCiMgU3BlY2lmaWNhdGlvbnMgb2Ygb3V0cHV0cyBvZiBjb2RlIGluIGNvZGUgY2h1bmtzDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAjIGluY2x1ZGUgY29kZSBjaHVuayBpbiB0aGUgb3V0cHV0ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGUNCiAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsICAjIFNvbWV0aW1lcywgeW91ciBjb2RlIG1heSBwcm9kdWNlIGEgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG1lc3NhZ2VzLCB5b3UgY2FuIGNob29zZSB0byBpbmNsdWRlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgd2FybmluZyBtZXNzYWdlcyBpbiB0aGUgb3V0cHV0IGZpbGUuIA0KICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwgIA0KICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBUUlVFLCAgICMgeW91IGNhbiBhbHNvIGRlY2lkZSB3aGV0aGVyIHRvICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5jbHVkZSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHRoZSBvdXRwdXQgaW4gdGhlIG91dHB1dCBmaWxlLg0KICAgICAgICAgICAgICAgICAgIGNvbW1lbnQgPSBOQSAgICAgICMgU3VwcHJlc3MgaGFzaC10YWdzIGluIHRoZSBvdXRwdXQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cy4NCiAgICAgICAgICAgICAgICAgICAgICApICAgDQpgYGANCg0KDQojIEludHJvZHVjdGlvbg0KDQpJbiB0aGlzIGFzc2lnbm1lbnQsIHdlIHdpbGwgbG9vayBhdCBhIGRhdGEgc2V0IHdoaWNoIG9ic2VydmVkIGJhbmsgbG9hbiBkYXRhLiBXZSB3aWxsIGNvbmR1Y3QgZXhwbG9yYXRvcnkgZGF0YSBhbmFseXNpcyBzdGVwcyBpbiBvcmRlciB0byBhbmFseXplIGFuZCBwcmVwYXJlIHRoaXMgZGF0YSBmb3IgZnVydGhlciBhbmFseXNpcy4gV2Ugd2lsbCBhZGRyZXNzIGNvbmNlcm5zIHN1Y2ggYXMgcG90ZW50aWFsIG1pc3NpbmcgdmFsdWVzLCBhbG9uZyB3aXRoIGNyZWF0aW5nIGFuZCByZWRlZmluaW5nIHNvbWUgb2YgdGhlIHZhcmlhYmxlcyBpbiB0aGUgb3JpZ2luYWwgZGF0YSBzZXQgdG8gbWFrZSB0aGVtIG1vcmUgbWVhbmluZ2Z1bCBhbmQgcmVsZXZhbnQgZm9yIGZ1dHVyZSBhbmFseXNpcy4gDQoNCg0KIyMgRGF0YSBEZXNjcmlwdGlvbg0KDQpUaGlzIGRhdGEgc2V0IHdhcyBjb2xsZWN0ZWQgZnJvbSB0aGUgVS5TLiBTbWFsbCBCdXNpbmVzcyBBZG1pbmlzdHJhdGlvbiAoU0JBKSBvdmVyIHRoZSBzcGFuIG9mIHRoZSB5ZWFycyBmcm9tIDE5ODcgdGhyb3VnaCAyMDE0LiBUaGlzIGRhdGEgc2V0IGNvbnRhaW5zIDg5OSwxNjQgb2JzZXJ2YXRpb25zIG9mIDI3IGRpZmZlcmVudCB2YXJpYWJsZXMuIEVhY2ggb2YgdGhlc2Ugb2JzZXJ2YXRpb25zIHJlcHJlc2VudCBhIGxvYW4gd2hpY2ggd2FzIGd1YXJhbnRlZWQgYnkgdGhlIFNCQS4gDQoNCg0KDQojIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMNCg0KDQpGaXJzdCwgd2Ugd2lsbCByZWFkIGluIHRoZSBjb21iaW5lZCBiYW5rIGxvYW4gZGF0YSBzZXRzLg0KDQpgYGB7cn0NCmxvYW4wMSA9IHJlYWQuY3N2KCJodHRwczovL3Blbmdkc2NpLmdpdGh1Yi5pby9kYXRhc2V0cy9TQkFsb2FuL3cwNi1TQkFuYXRpb25hbDAxLmNzdiIsIGhlYWRlciA9IFRSVUUpWywgLTFdDQpsb2FuMDIgPSByZWFkLmNzdigiaHR0cHM6Ly9wZW5nZHNjaS5naXRodWIuaW8vZGF0YXNldHMvU0JBbG9hbi93MDYtU0JBbmF0aW9uYWwwMi5jc3YiLCBoZWFkZXIgPSBUUlVFKVssIC0xXQ0KbG9hbjAzID0gcmVhZC5jc3YoImh0dHBzOi8vcGVuZ2RzY2kuZ2l0aHViLmlvL2RhdGFzZXRzL1NCQWxvYW4vdzA2LVNCQW5hdGlvbmFsMDMuY3N2IiwgaGVhZGVyID0gVFJVRSlbLCAtMV0NCmxvYW4wNCA9IHJlYWQuY3N2KCJodHRwczovL3Blbmdkc2NpLmdpdGh1Yi5pby9kYXRhc2V0cy9TQkFsb2FuL3cwNi1TQkFuYXRpb25hbDA0LmNzdiIsIGhlYWRlciA9IFRSVUUpWywgLTFdDQpsb2FuMDUgPSByZWFkLmNzdigiaHR0cHM6Ly9wZW5nZHNjaS5naXRodWIuaW8vZGF0YXNldHMvU0JBbG9hbi93MDYtU0JBbmF0aW9uYWwwNS5jc3YiLCBoZWFkZXIgPSBUUlVFKVssIC0xXQ0KbG9hbjA2ID0gcmVhZC5jc3YoImh0dHBzOi8vcGVuZ2RzY2kuZ2l0aHViLmlvL2RhdGFzZXRzL1NCQWxvYW4vdzA2LVNCQW5hdGlvbmFsMDYuY3N2IiwgaGVhZGVyID0gVFJVRSlbLCAtMV0NCmxvYW4wNyA9IHJlYWQuY3N2KCJodHRwczovL3Blbmdkc2NpLmdpdGh1Yi5pby9kYXRhc2V0cy9TQkFsb2FuL3cwNi1TQkFuYXRpb25hbDA3LmNzdiIsIGhlYWRlciA9IFRSVUUpWywgLTFdDQpsb2FuMDggPSByZWFkLmNzdigiaHR0cHM6Ly9wZW5nZHNjaS5naXRodWIuaW8vZGF0YXNldHMvU0JBbG9hbi93MDYtU0JBbmF0aW9uYWwwOC5jc3YiLCBoZWFkZXIgPSBUUlVFKVssIC0xXQ0KbG9hbjA5ID0gcmVhZC5jc3YoImh0dHBzOi8vcGVuZ2RzY2kuZ2l0aHViLmlvL2RhdGFzZXRzL1NCQWxvYW4vdzA2LVNCQW5hdGlvbmFsMDkuY3N2IiwgaGVhZGVyID0gVFJVRSlbLCAtMV0NCmxvYW4gPSByYmluZChsb2FuMDEsIGxvYW4wMiwgbG9hbjAzLCBsb2FuMDQsIGxvYW4wNSwgbG9hbjA2LCBsb2FuMDcsIGxvYW4wOCwgbG9hbjA5KQ0KYGBgDQoNCmBgYHtyfQ0KdmFyLm5hbWVzID0gbmFtZXMobG9hbikNCm15LnZhciA9IHZhci5uYW1lc1tjKDEsNiwyMSwyNildDQpteS5uZXcuZGF0YSA9IGxvYW5bMToxNSwgbXkudmFyXQ0KZGltKG15Lm5ldy5kYXRhKQ0KYGBgDQoNCg0KDQojIyBBZGRyZXNzaW5nIHRoZSBNaXNzaW5nIFZhbHVlcw0KDQpUaGlzIGRhdGEgc2V0IGNvbnRhaW5zIHNvbWUgbWlzc2luZyB2YWx1ZXMgYW5kIHNvIHdlIG11c3QgYWRkcmVzcyB0aGVzZSBiZWZvcmUgY29udGludWluZyBhbnkgZnVydGhlciB3aXRoIG91ciBhbmFseXNpcyBvZiB0aGlzIGRhdGEuIEZvciB0aGlzIHByb2plY3QsIHdlIHdpbGwgZGVsZXRlIGFsbCBvZiB0aGUgb2JzZXJ2YXRpb25zIHdoaWNoIGhhZCBhIG1pc3NpbmcgdmFsdWUgb2YgTUlTX1N0YXR1cy4gDQoNCmBgYHtyfQ0KY29sU3Vtcyhpcy5uYShsb2FuKSkNCmBgYA0KDQpJdCB0dXJucyBvdXQgdGhhdCB0aGUgTUlTX1N0YXR1cyB2YXJpYWJsZSBoYXMgemVybyBtaXNzaW5nIG9ic2VydmF0aW9ucywgc28gd2UgZG8gbm90IGhhdmUgdG8gZGVsZXRlIGFueSBvYnNlcnZhdGlvbnMgYmFzZWQgdXBvbiBhIG1pc3NpbmcgdmFsdWUgb2YgTUlTX1N0YXR1cy4gDQoNCkluIGZhY3QsIHRoZSBvbmx5IHZhcmlhYmxlIHdpdGggYW55IG1pc3Npbmcgb2JzZXJ2YXRpb25zIGlzIHRoZSBOZXdFeGlzdCB2YXJpYWJsZS4gV2Ugd2lsbCBnbyBhaGVhZCBhbmQgZGVsZXRlIHRoZXNlIG1pc3Npbmcgb2JzZXJ2YXRpb25zIGluc3RlYWQgc2luY2UgdGhlIE1JU19TdGF0dXMgdmFyaWFibGUgd2FzIGFsbCBnb29kLiBUaGVyZSBhcmUgMTM2IG1pc3Npbmcgb2JzZXJ2YXRpb25zIG9mIHRoaXMgTmV3RXhpc3QgdmFyaWFibGUgYW5kIHdlIHdpbGwgZGVsZXRlIHRoZXNlIG1pc3Npbmcgb2JzZXJ2YXRpb25zLiANCg0KV2Ugd2lsbCBjcmVhdGUgYSBuZXcgZGF0YSBzZXQgY2FsbGVkICJsb2FuLm5vTWlzc2luZyIgdG8gcmVwcmVzZW50IHRoYXQgaXQgaGFzIG5vIG1pc3Npbmcgb2JzZXJ2YXRpb25zLg0KDQpgYGB7cn0NCmxvYW4ubm9NaXNzaW5nIDwtIG5hLm9taXQobG9hbikNCmBgYA0KDQpMZXQncyBkb3VibGUgY2hlY2sgdGhhdCB3ZSBzdWNjZXNzZnVsbHkgcmVtb3ZlZCBhbGwgb2JzZXJ2YXRpb25zIHdpdGggbWlzc2luZyB2YWx1ZXMgZnJvbSB0aGUgZGF0YSBzZXQuDQoNCmBgYHtyfQ0KY29sU3Vtcyhpcy5uYShsb2FuLm5vTWlzc2luZykpDQpgYGANCg0KQXMgd2UgY2FuIHNlZSwgbm8gdmFyaWFibGVzIGhhdmUgYW55IG1vcmUgbWlzc2luZyBvYnNlcnZhdGlvbnMsIHNvIHdlIGhhdmUgc3VjY2Vzc2Z1bGx5IGRlYWx0IHdpdGggdGhlIG1pc3NpbmcgdmFsdWUgY29uY2VybiBmb3Igb3VyIGRhdGEgc2V0LiANCg0KDQoNCiMjIFZhcmlhYmxlIEZvcm1hdHRpbmcNCg0KV2Ugd2lsbCBub3cgY2hhbmdlIGFsbCBvZiB0aGUgY3VycmVuY3kgcmVsYXRlZCB2YXJpYWJsZXMgaW4gdGhpcyBjb21iaW5lZCBiYW5rIGxvYW4gZGF0YSBzZXQgdG8gYmUgcmVndWxhciwgbnVtZXJpYyB2YXJpYWJsZXMuIFRoZXNlIGN1cnJlbmN5IHJlbGF0ZWQgdmFyaWFibGVzIGluY2x1ZGUgRGlzYnVyc2VtZW50R3Jvc3MsIEJhbGFuY2VHcm9zcywgQ2hnT2ZmUHJpbkdyLCBHckFwcHYsIGFuZCBTQkFfQXBwdi4gVG8gZG8gdGhpcywgd2Ugd2lsbCByZW1vdmUgdGhlIGRvbGxhciBzaWduIGFuZCB0aGUgY29tbWFzIGZyb20gdGhlIG9ic2VydmF0aW9ucyBvZiB0aGVzZSBjdXJyZW5jeSByZWxhdGVkIHZhcmlhYmxlcy4gDQoNCmBgYHtyfQ0KY3VycmVuY3kgPC0gYygiRGlzYnVyc2VtZW50R3Jvc3MiLCAiQmFsYW5jZUdyb3NzIiwgIkNoZ09mZlByaW5HciIsICJHckFwcHYiLCAiU0JBX0FwcHYiKQ0KDQpsb2FuLnVwZGF0ZWQgPC0gbG9hbi5ub01pc3NpbmcgJT4lDQogIG11dGF0ZShhY3Jvc3MoYWxsX29mKGN1cnJlbmN5KSwgfiBhcy5udW1lcmljKGdzdWIoIlskLF0iLCAiIiwgLikpKSkNCmBgYA0KDQpOb3csIGFsbCBvZiB0aGUgY3VycmVuY3kgcmVsYXRlZCB2YXJpYWJsZXMgaGF2ZSBiZWVuIHVwZGF0ZWQgdG8gYmUgcmVwcmVzZW50ZWQgYXMgc3RhbmRhcmQsIG51bWVyaWMgdmFyaWFibGVzIHdpdGhvdXQgY29tbWFzIG9yIGEgZG9sbGFyIHNpZ24uIFRoZSBuZXcsIHVwZGF0ZWQgdmFyaWFibGUgZGF0YSBoYXMgYmVlbiBzdG9yZWQgaW4gYSBuZXcgZGF0YSBzZXQgY2FsbGVkICJsb2FuLnVwZGF0ZWQiLiANCg0KV2UgY2FuIHZpZXcgYSBzdW1tYXJ5IG9mIHRoZXNlIHVwZGF0ZWQsIG51bWVyaWMgdmFyaWFibGVzIG9uIGN1cnJlbmN5IHRvIGVuc3VyZSB0aGF0IHRoZXNlIGNoYW5nZXMgdG8gcmVtb3ZlIHRoZSBjb21tYXMgYW5kIGRvbGxhciBzaWducyBwcm9wZXJseSB3b3JrZWQuIA0KDQpgYGB7cn0NCnN1bW1hcnkobG9hbi51cGRhdGVkW2N1cnJlbmN5XSkNCmBgYA0KDQpBcyB3ZSBjYW4gc2VlLCB0aGUgdmFsdWVzIG9mIGFsbCBvZiB0aGVzZSBjdXJyZW5jeSB2YXJpYWJsZXMgYXJlIG5vdyBnaXZlbiBhcyBzdGFuZGFyZCwgbnVtZXJpYyB2YXJpYWJsZXMuIA0KDQoNCg0KDQojIyBDb21iaW5pbmcgU3BhcnNlIENhdGVnb3JpZXMNCg0KTm93LCB3ZSB3aWxsIHRha2UgYSBsb29rIGF0IG9uZSBvZiB0aGUgY2F0ZWdvcmljYWwgdmFyaWFibGVzIGZyb20gdGhpcyBjb21iaW5lZCBiYW5rIGxvYW4gZGF0YSBzZXQgYW5kIGNvbWJpbmUgaXRzIHNwYXJzZSBjYXRlZ29yaWVzIGluIGEgd2F5IHRoYXQgaXMgbWVhbmluZ2Z1bC4gVGhpcyB3aWxsIGFsbG93IHVzIHRvIGhhdmUgbmV3IGNhdGVnb3JpZXMgdGhhdCBhcmUgZmV3ZXIgaW4gbnVtYmVyLCBhbmQgcHJvdmlkZSBiZXR0ZXIgbWVhbmluZ2Z1bG5lc3MgZm9yIHRoZSBpbnRlcnByZXRhdGlvbiBvZiB0aGlzIHZhcmlhYmxlLg0KDQpXZSB3aWxsIGxvb2sgYXQgdGhlIGNhdGVnb3JpY2FsIHZhcmlhYmxlICJOQUlDUyIuIFRoaXMgdmFyaWFibGUgbG9va3MgYXQgdGhlIE5vcnRoIEFtZXJpY2FuIEluZHVzdHJ5IENsYXNzaWZpY2F0aW9uIFN5c3RlbSBjb2RlIG9mIGVhY2ggb2JzZXJ2YXRpb24uIFRoaXMgdmFyaWFibGUgZGVmaW5lcyBlYWNoIG9ic2VydmF0aW9uIGJ5IHRoZSBzcGVjaWZpYyBpbmR1c3RyeSBvZiB3aGljaCBpdCBpcyByZWxldmFudCB0by4gDQoNCmBgYHtyfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIk5BSUNTLnBuZyIpDQpgYGANCg0KV2Ugd2lsbCBjb21iaW5lZCB0aGUgb2JzZXJ2YXRpb25zIG9mIHRoZSBOQUlDUyB2YXJpYWJsZSBpbnRvIGNhdGVnb3JpZXMgYmFzZWQgdXBvbiB0aGVpciBvZmZpY2lhbCBjbGFzc2lmaWNhdGlvbi4NCg0KYGBge3J9DQpsb2FuLnVwZGF0ZWQ8LSBsb2FuLnVwZGF0ZWQgJT4lDQogIG11dGF0ZShOQUlDUy5jb21iaW5lZCA9IGNhc2Vfd2hlbigNCiAgICBOQUlDUyAlaW4lIGMoIjExIikgfiAiQWdyaWN1bHR1cmUiLA0KICAgIE5BSUNTICVpbiUgYygiMjEiKSB+ICJNaW5pbmciLA0KICAgIE5BSUNTICVpbiUgYygiMjIiKSB+ICJVdGlsaXRpZXMiLA0KICAgIE5BSUNTICVpbiUgYygiMjMiKSB+ICJDb25zdHJ1Y3Rpb24iLA0KICAgIE5BSUNTICVpbiUgYygiMzEiLCAiMzIiLCAiMzMiKSB+ICJNYW51ZmFjdHVyaW5nIiwNCiAgICBOQUlDUyAlaW4lIGMoIjQyIikgfiAiV2hvbGVzYWxlIFRyYWRlIiwNCiAgICBOQUlDUyAlaW4lIGMoIjQ4IiwgIjQ5IikgfiAiVHJhbnNwb3J0YXRpb24iLA0KICAgIE5BSUNTICVpbiUgYygiNTEiKSB+ICJJbmZvcm1hdGlvbiIsDQogICAgTkFJQ1MgJWluJSBjKCI1MiIpIH4gIkZpbmFuY2UiLA0KICAgIE5BSUNTICVpbiUgYygiNTMiKSB+ICJSZWFsIEVzdGF0ZSIsDQogICAgTkFJQ1MgJWluJSBjKCI1NCIpIH4gIlByb2Zlc3Npb25hbCBTZXJ2aWNlcyIsDQogICAgTkFJQ1MgJWluJSBjKCI1NSIpIH4gIk1hbmFnZW1lbnQiLA0KICAgIE5BSUNTICVpbiUgYygiNTYiKSB+ICJBZG1pbmlzdHJhdGl2ZSBTdXBwb3J0IiwNCiAgICBOQUlDUyAlaW4lIGMoIjYxIikgfiAiRWR1Y2F0aW9uYWwgU2VydmljZXMiLA0KICAgIE5BSUNTICVpbiUgYygiNjIiKSB+ICJIZWFsdGhjYXJlIiwNCiAgICBOQUlDUyAlaW4lIGMoIjcxIikgfiAiQXJ0cyIsDQogICAgTkFJQ1MgJWluJSBjKCI3MiIpIH4gIkZvb2QgU2VydmljZXMiLA0KICAgIE5BSUNTICVpbiUgYygiODEiKSB+ICJPdGhlciBTZXJ2aWNlcyIsDQogICAgTkFJQ1MgJWluJSBjKCI5MiIpIH4gIlB1YmxpYyBBZG1pbmlzdHJhdGlvbiINCiAgKQ0KKQ0KYGBgDQoNCg0KDQoNCg0KDQojIyBDYWxjdWxhdGluZyB0aGUgRGVmYXVsdCBSYXRlcw0KDQpOZXh0LCB3ZSB3aWxsIGNhbGN1bGF0ZSB0aGUgZGVmYXVsdCByYXRlcyBvZiB0aGUgTkFJQ1MuY29tYmluZWQgY2F0ZWdvcmljYWwgdmFyaWFibGUgd2hpY2ggd2UgY3JlYXRlZCBpbiB0aGUgcHJldmlvdXMgcGFydC4gDQoNCkZvciB0aGlzIHN0ZXAsIHRoZSB2YWx1ZSBDSEdPRkYgaW4gTUlTX1N0YXR1cyBpcyBkZWZpbmVkIHRvIGJlIGxvYW4gZGVmYXVsdC4gVGhlIGRlZmF1bHQgcmF0ZSB3aWxsIGJlIHRoZSBwZXJjZW50YWdlIG9mIENIR09GRiBpbiBNSVNfU3RhdHVzLg0KDQpgYGB7cn0NCmRlZmF1bHQucmF0ZXMgPC0gbG9hbi51cGRhdGVkICU+JQ0KICBncm91cF9ieShOQUlDUy5jb21iaW5lZCkgJT4lDQogIHN1bW1hcmlzZSh0b3RhbCA9IG4oKSwNCiAgICAgICAgICAgIGRlZmF1bHRzID0gc3VtKE1JU19TdGF0dXMgPT0gIkNIR09GRiIsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBkZWZhdWx0LnJhdGVzID0gZGVmYXVsdHMgLyB0b3RhbCkNCmBgYA0KDQpXZSBjYW4gdmlldyB0aGUgdmFsdWVzIG9mIHRoZSBkZWZhdWx0IHJhdGVzIHdoaWNoIHdlIGNhbGN1bGF0ZWQuIA0KDQpgYGB7cn0NCmRlZmF1bHQucmF0ZXMNCmBgYA0KDQpOb3csIHdlIGhhdmUgc3VjY2Vzc2Z1bGx5IGNhbGN1bGF0ZWQgdGhlIGRlZmF1bHQgcmF0ZXMgZm9yIG91ciBOQUlDUy5jb21iaW5lZCB2YXJpYWJsZSB3aGljaCB3ZSBjcmVhdGVkIHRvIGdyb3VwIHRvZ2V0aGVyIHRoZSBzcGFyc2UgY2F0ZWdvcmllcy4gDQoNCg0KDQoNCiMjIERpc2NyZXRpemluZyB0aGUgR3JBcHB2IFZhcmlhYmxlDQoNCldlIHdpbGwgZGlzY3JldGl6ZSAgdGhlIHZhcmlhYmxlIG9mIEdyQXBwdiBpbnRvIGZpdmUgY2F0ZWdvcmllcy4gVGhpcyB2YXJpYWJsZSByZXByZXNlbnRzIHRoZSBncm9zcyBhbW91bnQgb2YgdGhlIGxvYW4gdGhhdCBoYXMgYmVlbiBhcHByb3ZlZCBieSB0aGUgYmFuay4NCg0KV2Ugd2lsbCBjcmVhdGUgdGhlc2UgY2F0ZWdvcmllcyBiYXNlZCB1cG9uIHRoZSBvdmVyYWxsIGxldmVsIG9mIGhlIHZhbHVlIG9mIHRoZSBHckFwcHYgdmFsdWUuIFRoZXNlIHN1YmNhdGVnb3JpZXMgd2lsbCBzcGxpdCB0aGUgR3JBcHB2IHZhcmlhYmxlIGludG8gZml2ZSBsZXZlbHMsICJsb3dlc3QiLCAibG93IiwgIm1lZGl1bSIsICJoaWdoIiwgYW5kICJoaWdoZXN0IiBiYXNlZCB1cG9uIHRoZSB2YWx1ZSBvZiB0aGUgZ3Jvc3MgYW1vdW50IG9mIGxvYW4gdGhhdCBoYXMgYmVlbiBhcHByb3ZlZCBieSB0aGUgYmFuLg0KDQpGaXJzdCwgbGV0J3MgbG9vayBhdCBhIHF1aWNrIHN1bW1hcnkgb2YgdGhlIG9yaWdpbmFsIEdyQXBwdiB2YXJpYWJsZS4NCg0KYGBge3J9DQpzdW1tYXJ5KGxvYW4udXBkYXRlZCRHckFwcHYpDQpgYGANCg0KQXMgd2UgY2FuIHNlZSwgdGhlIG1pbmltdW0gdmFsdWUgb2YgdGhlIHZhcmlhYmxlIGlzICQyMDAsIGFuZCB0aGUgbWF4aW11bSB2YWx1ZSBpcyAkNSw0NzIsMDAwLiBUaGUgbWVkaWFuIHZhbHVlIGlzICQ5MCwwMDAgaW5kaWNhdGluZyB0aGF0IHRoZSBtYXhpbXVtIHZhbHVlIGRpZmZlcnMgbXVjaCBtb3JlIGdyZWF0bHkgZnJvbSB0aGUgbWVkaWFuIHZhbHVlIHRoYW4gdGhlIG1pbmltdW0gdmFsdWUgZG9lcy4gDQoNCldlIHdpbGwgc3BsaXQgdGhlIEdyQXBwdiB2YXJpYWJsZSBpbnRvIGZpdmUgc3ViY2F0ZWdvcmllcyBiYXNlZCB1cG9uIHRoZSB2YWx1ZSBvZiBlYWNoIG9ic2VydmF0aW9uLiBXZSB3aWxsIGNyZWF0ZSBhIG5ldyB2YXJpYWJsZSBjYWxsZWQgIkdyQXBwdi5kaXMiIHRvIHJlcHJlc2VudCB0aGUgZGlzY3JldGl6ZWQgdmVyc2lvbiBvZiB0aGUgb3JpZ2luYWwgR3JBcHB2IHZhcmlhYmxlLiANCg0KYGBge3J9DQpsb2FuLnVwZGF0ZWQkR3JBcHB2LmRpcyA8LSBjdXQobG9hbi51cGRhdGVkJEdyQXBwdiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gNSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiTG93ZXN0IiwgIkxvdyIsICJNZWRpdW0iLCAiSGlnaCIsICJIaWdoZXN0IikpDQpgYGANCg0KTm93IHdlIGhhdmUgZml2ZSBzdWJjYXRlZ29yaWVzIG9mIHRoZSBHckFwcHYgdmFyaWFibGUgc3BsaXQgdXAgZnJvbSB0aGUgbG93ZXN0IHRvIHRoZSBoaWdoZXN0LiANCg0KDQoNCg0KIyMgRGVuc2l0eSBDdXJ2ZXMNCg0KTGFzdGx5LCB3ZSB3aWxsIGRyYXcgdGhlIGRlbnNpdHkgY3VydmVzIG9mIFNCQV9BcHB2IGZvciBlYWNoIG9mIHRoZSBmaXZlIHN1Yi1wb3B1bGF0aW9ucyB0aGF0IHdlcmUgY3JlYXRlZCBpbiB0aGUgcHJldmlvdXMgcGFydC4gV2Ugd2lsbCBwbGFjZSB0aGVzZSBmaXZlIGRlbnNpdHkgY3VydmVzIG9udG8gdGhlIHNhbWUgcGxvdC4gDQoNCmBgYHtyfQ0KZ2dwbG90KGxvYW4udXBkYXRlZCwgYWVzKHggPSBTQkFfQXBwdiwgZmlsbCA9IEdyQXBwdi5kaXMpKSArDQogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNSkgKw0KICBsYWJzKHRpdGxlID0gIkRlbnNpdHkgQ3VydmVzIG9mIFNCQV9BcHB2IGZvciB0aGUgXG4gRml2ZSBTdWJDYXRlZ29yaWVzIG9mIEdyQXBwdiIsDQogICAgICAgeCA9ICJTQkFfQXBwdiIsIHkgPSAiRGVuc2l0eSIpIA0KYGBgDQoNCkluIHRoZSBncmFwaCwgd2UgY2FuIHNlZSB0aGUgZGVuc2l0eSBjdXJ2ZXMgb2YgdGhlIFNCQV9BcHB2IHZhcmlhYmxlIGZvciBlYWNoIG9mIHRoZSBmaXZlIGNhdGVnb3JpZXMgb2YgR3JBcHB2IHRoYXQgd2UgY3JlYXRlZCBpbiB0aGUgcHJldmlvdXMgcGFydC4gV2UgY2FuIHNlZSB0aGF0IHRoZXNlIGZpdmUgY2F0ZWdvcmllcyBoYXZlIGJlZW4gY29sb3ItY29kZWQgYnkgdGhlaXIgcmVzcGVjdGl2ZSByYW5rIG9mICJsb3dlc3QiLCAibG93IiwgIm1lZGl1bSIsICJoaWdoIiwgIm9yIGhpZ2hlc3QiLg0KDQoNCiMgQ29uY2x1c2lvbg0KDQpXZSBoYXZlIGNvbXBsZXRlZCB0aGUgZGVzaXJlZCBleHBsb3JhdG9yeSBkYXRhIGFuYWx5c2lzIHN0ZXBzIGluY2x1ZGluZyBkZWFsaW5nIHdpdGggbWlzc2luZyB2YWx1ZXMgYXMgd2VsbCBhcyB1cGRhdGluZyBzb21lIG9mIHRoZSB2YXJpYWJsZXMgd2l0aGluIHRoZSBvcmlnaW5hbCBjb21iaW5lZCBiYW5rIGxvYW4gZGF0YSBzZXQuIFdlIG5vdyBoYXZlIGEgbmV3IGRhdGEgc2V0IGNhbGxlZCAibG9hbi51cGRhdGVkIiB3aXRoIGFsbCBvZiB0aGUgZGVzaXJlZCB1cGRhdGVzIHRvIHRoZSBkYXRhIHNldC4gDQo=