1 Introduction

In this assignment, we will look at a data set which observed bank loan data. We will conduct exploratory data analysis steps in order to analyze and prepare this data for further analysis. We will address concerns such as potential missing values, along with creating and redefining some of the variables in the original data set to make them more meaningful and relevant for future analysis.

1.1 Data Description

This data set was collected from the U.S. Small Business Administration (SBA) over the span of the years from 1987 through 2014. This data set contains 899,164 observations of 27 different variables. Each of these observations represent a loan which was guaranteed by the SBA.

2 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

2.1 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.

2.2 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.

2.3 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"
  )
)

2.4 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.

2.5 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.

2.6 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”.

3 Conclusion

We have completed the desired exploratory data analysis steps including dealing with missing values as well as updating some of the variables within the original combined bank loan data set. We now have a new data set called “loan.updated” with all of the desired updates to the data set.

LS0tDQp0aXRsZTogIkVEQSB3aXRoIHRoZSBDb21iaW5lZCBCYW5rIExvYW4gRGF0YSBTZXQiDQphdXRob3I6ICJKb3NpZSBHYWxsb3AiDQpkYXRlOiAiMjAyNS0wMi0yNCINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIGZpZ193aWR0aDogNg0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRvY19jb2xsYXBzZWQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHNtb290aF9zY3JvbGw6IHllcw0KICAgIHRoZW1lOiBsdW1lbg0KICB3b3JkX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBrZWVwX21kOiB5ZXMNCiAgcGRmX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KZWRpdG9yX29wdGlvbnM6IA0KICBjaHVua19vdXRwdXRfdHlwZTogY29uc29sZQ0KLS0tDQoNCmBgYHs9aHRtbH0NCg0KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4NCg0KLyogQ2FzY2FkaW5nIFN0eWxlIFNoZWV0cyAoQ1NTKSBpcyBhIHN0eWxlc2hlZXQgbGFuZ3VhZ2UgdXNlZCB0byBkZXNjcmliZSB0aGUgcHJlc2VudGF0aW9uIG9mIGEgZG9jdW1lbnQgd3JpdHRlbiBpbiBIVE1MIG9yIFhNTC4gaXQgaXMgYSBzaW1wbGUgbWVjaGFuaXNtIGZvciBhZGRpbmcgc3R5bGUgKGUuZy4sIGZvbnRzLCBjb2xvcnMsIHNwYWNpbmcpIHRvIFdlYiBkb2N1bWVudHMuICovDQoNCmgxLnRpdGxlIHsgIC8qIFRpdGxlIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiB0aGUgcmVwb3J0IHRpdGxlICovDQogIGZvbnQtc2l6ZTogMjRweDsNCiAgY29sb3I6IERhcmtSZWQ7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOw0KfQ0KaDQuYXV0aG9yIHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBhdXRob3JzICAqLw0KICBmb250LXNpemU6IDIwcHg7DQogIGZvbnQtZmFtaWx5OiBzeXN0ZW0tdWk7DQogIGNvbG9yOiBEYXJrUmVkOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQpoNC5kYXRlIHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciB0aGUgZGF0ZSAgKi8NCiAgZm9udC1zaXplOiAxOHB4Ow0KICBmb250LWZhbWlseTogc3lzdGVtLXVpOw0KICBjb2xvcjogRGFya0JsdWU7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmgxIHsgLyogSGVhZGVyIDEgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBsZXZlbCAxIHNlY3Rpb24gdGl0bGUgICovDQogICAgZm9udC1zaXplOiAyMnB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmgyIHsgLyogSGVhZGVyIDIgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBsZXZlbCAyIHNlY3Rpb24gdGl0bGUgKi8NCiAgICBmb250LXNpemU6IDIwcHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDMgeyAvKiBIZWFkZXIgMyAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgbGV2ZWwgMyBzZWN0aW9uIHRpdGxlICAqLw0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoNCB7IC8qIEhlYWRlciA0IC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiBsZXZlbCA0IHNlY3Rpb24gdGl0bGUgICovDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmJvZHkgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9DQoNCi5oaWdobGlnaHRtZSB7IGJhY2tncm91bmQtY29sb3I6eWVsbG93OyB9DQoNCnAgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9DQoNCjwvc3R5bGU+DQpgYGANCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KIyBEZXRlY3QsIGluc3RhbGwsIGFuZCBsb2FkIHBhY2thZ2VzIGlmIG5lZWRlZC4NCmlmICghcmVxdWlyZSgia25pdHIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KICAgbGlicmFyeShrbml0cikNCn0NCmlmICghcmVxdWlyZSgibGVhZmxldCIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJsZWFmbGV0IikNCiAgIGxpYnJhcnkobGVhZmxldCkNCn0NCmlmICghcmVxdWlyZSgiRW52U3RhdHMiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygiRW52U3RhdHMiKQ0KICAgbGlicmFyeShFbnZTdGF0cykNCn0NCmlmICghcmVxdWlyZSgiTUFTUyIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJNQVNTIikNCiAgIGxpYnJhcnkoTUFTUykNCn0NCmlmICghcmVxdWlyZSgicGh5dG9vbHMiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygicGh5dG9vbHMiKQ0KICAgbGlicmFyeShwaHl0b29scykNCn0NCmlmKCFyZXF1aXJlKCJkcGx5ciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJkcGx5ciIpDQogICBsaWJyYXJ5KGRwbHlyKQ0KfQ0KaWYoIXJlcXVpcmUoInRpZHl2ZXJzZSIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KICAgbGlicmFyeSh0aWR5dmVyc2UpDQp9DQppZighcmVxdWlyZSgiR0dhbGx5IikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoIkdHYWxseSIpDQogICBsaWJyYXJ5KEdHYWxseSkNCn0NCmlmKCFyZXF1aXJlKCJ1c2RtIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInVzZG0iKQ0KICAgbGlicmFyeSh1c2RtKQ0KfQ0KaWYoIXJlcXVpcmUoImNhciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJjYXIiKQ0KICAgbGlicmFyeShjYXIpDQp9DQppZiAoIXJlcXVpcmUoImJvb3QiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygiYm9vdCIpDQogICBsaWJyYXJ5KGJvb3QpDQp9DQppZighcmVxdWlyZSgicGFuZGVyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInBhbmRlciIpDQogICBsaWJyYXJ5KHBhbmRlcikNCn0NCmlmKCFyZXF1aXJlKCJtaWNlIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoIm1pY2UiKQ0KICAgbGlicmFyeShtaWNlKQ0KfQ0KaWYoIXJlcXVpcmUoIm1sYmVuY2giKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygibWxiZW5jaCIpDQogICBsaWJyYXJ5KG1sYmVuY2gpDQp9DQppZighcmVxdWlyZSgicHN5Y2giKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygicHN5Y2giKQ0KICAgbGlicmFyeShwc3ljaCkNCn0NCmlmKCFyZXF1aXJlKCJicm9vbS5taXhlZCIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJicm9vbS5taXhlZCIpDQogICBsaWJyYXJ5KGJyb29tLm1peGVkKQ0KfQ0KaWYoIXJlcXVpcmUoIkdHYWxseSIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJHR2FsbHkiKQ0KICAgbGlicmFyeShHR2FsbHkpDQp9DQppZighcmVxdWlyZSgiY2FyZXQiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygiY2FyZXQiKQ0KICAgbGlicmFyeShjYXJldCkNCn0NCmlmICghcmVxdWlyZSgicFJPQyIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJwUk9DIikNCiAgIGxpYnJhcnkocFJPQykNCn0NCiMgU3BlY2lmaWNhdGlvbnMgb2Ygb3V0cHV0cyBvZiBjb2RlIGluIGNvZGUgY2h1bmtzDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAjIGluY2x1ZGUgY29kZSBjaHVuayBpbiB0aGUgb3V0cHV0ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGUNCiAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsICAjIFNvbWV0aW1lcywgeW91ciBjb2RlIG1heSBwcm9kdWNlIGEgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG1lc3NhZ2VzLCB5b3UgY2FuIGNob29zZSB0byBpbmNsdWRlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgd2FybmluZyBtZXNzYWdlcyBpbiB0aGUgb3V0cHV0IGZpbGUuIA0KICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwgIA0KICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBUUlVFLCAgICMgeW91IGNhbiBhbHNvIGRlY2lkZSB3aGV0aGVyIHRvICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5jbHVkZSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHRoZSBvdXRwdXQgaW4gdGhlIG91dHB1dCBmaWxlLg0KICAgICAgICAgICAgICAgICAgIGNvbW1lbnQgPSBOQSAgICAgICMgU3VwcHJlc3MgaGFzaC10YWdzIGluIHRoZSBvdXRwdXQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cy4NCiAgICAgICAgICAgICAgICAgICAgICApICAgDQpgYGANCg0KDQojIEludHJvZHVjdGlvbg0KDQpJbiB0aGlzIGFzc2lnbm1lbnQsIHdlIHdpbGwgbG9vayBhdCBhIGRhdGEgc2V0IHdoaWNoIG9ic2VydmVkIGJhbmsgbG9hbiBkYXRhLiBXZSB3aWxsIGNvbmR1Y3QgZXhwbG9yYXRvcnkgZGF0YSBhbmFseXNpcyBzdGVwcyBpbiBvcmRlciB0byBhbmFseXplIGFuZCBwcmVwYXJlIHRoaXMgZGF0YSBmb3IgZnVydGhlciBhbmFseXNpcy4gV2Ugd2lsbCBhZGRyZXNzIGNvbmNlcm5zIHN1Y2ggYXMgcG90ZW50aWFsIG1pc3NpbmcgdmFsdWVzLCBhbG9uZyB3aXRoIGNyZWF0aW5nIGFuZCByZWRlZmluaW5nIHNvbWUgb2YgdGhlIHZhcmlhYmxlcyBpbiB0aGUgb3JpZ2luYWwgZGF0YSBzZXQgdG8gbWFrZSB0aGVtIG1vcmUgbWVhbmluZ2Z1bCBhbmQgcmVsZXZhbnQgZm9yIGZ1dHVyZSBhbmFseXNpcy4gDQoNCg0KIyMgRGF0YSBEZXNjcmlwdGlvbg0KDQpUaGlzIGRhdGEgc2V0IHdhcyBjb2xsZWN0ZWQgZnJvbSB0aGUgVS5TLiBTbWFsbCBCdXNpbmVzcyBBZG1pbmlzdHJhdGlvbiAoU0JBKSBvdmVyIHRoZSBzcGFuIG9mIHRoZSB5ZWFycyBmcm9tIDE5ODcgdGhyb3VnaCAyMDE0LiBUaGlzIGRhdGEgc2V0IGNvbnRhaW5zIDg5OSwxNjQgb2JzZXJ2YXRpb25zIG9mIDI3IGRpZmZlcmVudCB2YXJpYWJsZXMuIEVhY2ggb2YgdGhlc2Ugb2JzZXJ2YXRpb25zIHJlcHJlc2VudCBhIGxvYW4gd2hpY2ggd2FzIGd1YXJhbnRlZWQgYnkgdGhlIFNCQS4gDQoNCg0KDQojIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMNCg0KDQpGaXJzdCwgd2Ugd2lsbCByZWFkIGluIHRoZSBjb21iaW5lZCBiYW5rIGxvYW4gZGF0YSBzZXRzLg0KDQpgYGB7cn0NCmxvYW4wMSA9IHJlYWQuY3N2KCJodHRwczovL3Blbmdkc2NpLmdpdGh1Yi5pby9kYXRhc2V0cy9TQkFsb2FuL3cwNi1TQkFuYXRpb25hbDAxLmNzdiIsIGhlYWRlciA9IFRSVUUpWywgLTFdDQpsb2FuMDIgPSByZWFkLmNzdigiaHR0cHM6Ly9wZW5nZHNjaS5naXRodWIuaW8vZGF0YXNldHMvU0JBbG9hbi93MDYtU0JBbmF0aW9uYWwwMi5jc3YiLCBoZWFkZXIgPSBUUlVFKVssIC0xXQ0KbG9hbjAzID0gcmVhZC5jc3YoImh0dHBzOi8vcGVuZ2RzY2kuZ2l0aHViLmlvL2RhdGFzZXRzL1NCQWxvYW4vdzA2LVNCQW5hdGlvbmFsMDMuY3N2IiwgaGVhZGVyID0gVFJVRSlbLCAtMV0NCmxvYW4wNCA9IHJlYWQuY3N2KCJodHRwczovL3Blbmdkc2NpLmdpdGh1Yi5pby9kYXRhc2V0cy9TQkFsb2FuL3cwNi1TQkFuYXRpb25hbDA0LmNzdiIsIGhlYWRlciA9IFRSVUUpWywgLTFdDQpsb2FuMDUgPSByZWFkLmNzdigiaHR0cHM6Ly9wZW5nZHNjaS5naXRodWIuaW8vZGF0YXNldHMvU0JBbG9hbi93MDYtU0JBbmF0aW9uYWwwNS5jc3YiLCBoZWFkZXIgPSBUUlVFKVssIC0xXQ0KbG9hbjA2ID0gcmVhZC5jc3YoImh0dHBzOi8vcGVuZ2RzY2kuZ2l0aHViLmlvL2RhdGFzZXRzL1NCQWxvYW4vdzA2LVNCQW5hdGlvbmFsMDYuY3N2IiwgaGVhZGVyID0gVFJVRSlbLCAtMV0NCmxvYW4wNyA9IHJlYWQuY3N2KCJodHRwczovL3Blbmdkc2NpLmdpdGh1Yi5pby9kYXRhc2V0cy9TQkFsb2FuL3cwNi1TQkFuYXRpb25hbDA3LmNzdiIsIGhlYWRlciA9IFRSVUUpWywgLTFdDQpsb2FuMDggPSByZWFkLmNzdigiaHR0cHM6Ly9wZW5nZHNjaS5naXRodWIuaW8vZGF0YXNldHMvU0JBbG9hbi93MDYtU0JBbmF0aW9uYWwwOC5jc3YiLCBoZWFkZXIgPSBUUlVFKVssIC0xXQ0KbG9hbjA5ID0gcmVhZC5jc3YoImh0dHBzOi8vcGVuZ2RzY2kuZ2l0aHViLmlvL2RhdGFzZXRzL1NCQWxvYW4vdzA2LVNCQW5hdGlvbmFsMDkuY3N2IiwgaGVhZGVyID0gVFJVRSlbLCAtMV0NCmxvYW4gPSByYmluZChsb2FuMDEsIGxvYW4wMiwgbG9hbjAzLCBsb2FuMDQsIGxvYW4wNSwgbG9hbjA2LCBsb2FuMDcsIGxvYW4wOCwgbG9hbjA5KQ0KYGBgDQoNCmBgYHtyfQ0KdmFyLm5hbWVzID0gbmFtZXMobG9hbikNCm15LnZhciA9IHZhci5uYW1lc1tjKDEsNiwyMSwyNildDQpteS5uZXcuZGF0YSA9IGxvYW5bMToxNSwgbXkudmFyXQ0KZGltKG15Lm5ldy5kYXRhKQ0KYGBgDQoNCg0KDQojIyBBZGRyZXNzaW5nIHRoZSBNaXNzaW5nIFZhbHVlcw0KDQpUaGlzIGRhdGEgc2V0IGNvbnRhaW5zIHNvbWUgbWlzc2luZyB2YWx1ZXMgYW5kIHNvIHdlIG11c3QgYWRkcmVzcyB0aGVzZSBiZWZvcmUgY29udGludWluZyBhbnkgZnVydGhlciB3aXRoIG91ciBhbmFseXNpcyBvZiB0aGlzIGRhdGEuIEZvciB0aGlzIHByb2plY3QsIHdlIHdpbGwgZGVsZXRlIGFsbCBvZiB0aGUgb2JzZXJ2YXRpb25zIHdoaWNoIGhhZCBhIG1pc3NpbmcgdmFsdWUgb2YgTUlTX1N0YXR1cy4gDQoNCmBgYHtyfQ0KY29sU3Vtcyhpcy5uYShsb2FuKSkNCmBgYA0KDQpJdCB0dXJucyBvdXQgdGhhdCB0aGUgTUlTX1N0YXR1cyB2YXJpYWJsZSBoYXMgemVybyBtaXNzaW5nIG9ic2VydmF0aW9ucywgc28gd2UgZG8gbm90IGhhdmUgdG8gZGVsZXRlIGFueSBvYnNlcnZhdGlvbnMgYmFzZWQgdXBvbiBhIG1pc3NpbmcgdmFsdWUgb2YgTUlTX1N0YXR1cy4gDQoNCkluIGZhY3QsIHRoZSBvbmx5IHZhcmlhYmxlIHdpdGggYW55IG1pc3Npbmcgb2JzZXJ2YXRpb25zIGlzIHRoZSBOZXdFeGlzdCB2YXJpYWJsZS4gV2Ugd2lsbCBnbyBhaGVhZCBhbmQgZGVsZXRlIHRoZXNlIG1pc3Npbmcgb2JzZXJ2YXRpb25zIGluc3RlYWQgc2luY2UgdGhlIE1JU19TdGF0dXMgdmFyaWFibGUgd2FzIGFsbCBnb29kLiBUaGVyZSBhcmUgMTM2IG1pc3Npbmcgb2JzZXJ2YXRpb25zIG9mIHRoaXMgTmV3RXhpc3QgdmFyaWFibGUgYW5kIHdlIHdpbGwgZGVsZXRlIHRoZXNlIG1pc3Npbmcgb2JzZXJ2YXRpb25zLiANCg0KV2Ugd2lsbCBjcmVhdGUgYSBuZXcgZGF0YSBzZXQgY2FsbGVkICJsb2FuLm5vTWlzc2luZyIgdG8gcmVwcmVzZW50IHRoYXQgaXQgaGFzIG5vIG1pc3Npbmcgb2JzZXJ2YXRpb25zLg0KDQpgYGB7cn0NCmxvYW4ubm9NaXNzaW5nIDwtIG5hLm9taXQobG9hbikNCmBgYA0KDQpMZXQncyBkb3VibGUgY2hlY2sgdGhhdCB3ZSBzdWNjZXNzZnVsbHkgcmVtb3ZlZCBhbGwgb2JzZXJ2YXRpb25zIHdpdGggbWlzc2luZyB2YWx1ZXMgZnJvbSB0aGUgZGF0YSBzZXQuDQoNCmBgYHtyfQ0KY29sU3Vtcyhpcy5uYShsb2FuLm5vTWlzc2luZykpDQpgYGANCg0KQXMgd2UgY2FuIHNlZSwgbm8gdmFyaWFibGVzIGhhdmUgYW55IG1vcmUgbWlzc2luZyBvYnNlcnZhdGlvbnMsIHNvIHdlIGhhdmUgc3VjY2Vzc2Z1bGx5IGRlYWx0IHdpdGggdGhlIG1pc3NpbmcgdmFsdWUgY29uY2VybiBmb3Igb3VyIGRhdGEgc2V0LiANCg0KDQoNCiMjIFZhcmlhYmxlIEZvcm1hdHRpbmcNCg0KV2Ugd2lsbCBub3cgY2hhbmdlIGFsbCBvZiB0aGUgY3VycmVuY3kgcmVsYXRlZCB2YXJpYWJsZXMgaW4gdGhpcyBjb21iaW5lZCBiYW5rIGxvYW4gZGF0YSBzZXQgdG8gYmUgcmVndWxhciwgbnVtZXJpYyB2YXJpYWJsZXMuIFRoZXNlIGN1cnJlbmN5IHJlbGF0ZWQgdmFyaWFibGVzIGluY2x1ZGUgRGlzYnVyc2VtZW50R3Jvc3MsIEJhbGFuY2VHcm9zcywgQ2hnT2ZmUHJpbkdyLCBHckFwcHYsIGFuZCBTQkFfQXBwdi4gVG8gZG8gdGhpcywgd2Ugd2lsbCByZW1vdmUgdGhlIGRvbGxhciBzaWduIGFuZCB0aGUgY29tbWFzIGZyb20gdGhlIG9ic2VydmF0aW9ucyBvZiB0aGVzZSBjdXJyZW5jeSByZWxhdGVkIHZhcmlhYmxlcy4gDQoNCmBgYHtyfQ0KY3VycmVuY3kgPC0gYygiRGlzYnVyc2VtZW50R3Jvc3MiLCAiQmFsYW5jZUdyb3NzIiwgIkNoZ09mZlByaW5HciIsICJHckFwcHYiLCAiU0JBX0FwcHYiKQ0KDQpsb2FuLnVwZGF0ZWQgPC0gbG9hbi5ub01pc3NpbmcgJT4lDQogIG11dGF0ZShhY3Jvc3MoYWxsX29mKGN1cnJlbmN5KSwgfiBhcy5udW1lcmljKGdzdWIoIlskLF0iLCAiIiwgLikpKSkNCmBgYA0KDQpOb3csIGFsbCBvZiB0aGUgY3VycmVuY3kgcmVsYXRlZCB2YXJpYWJsZXMgaGF2ZSBiZWVuIHVwZGF0ZWQgdG8gYmUgcmVwcmVzZW50ZWQgYXMgc3RhbmRhcmQsIG51bWVyaWMgdmFyaWFibGVzIHdpdGhvdXQgY29tbWFzIG9yIGEgZG9sbGFyIHNpZ24uIFRoZSBuZXcsIHVwZGF0ZWQgdmFyaWFibGUgZGF0YSBoYXMgYmVlbiBzdG9yZWQgaW4gYSBuZXcgZGF0YSBzZXQgY2FsbGVkICJsb2FuLnVwZGF0ZWQiLiANCg0KV2UgY2FuIHZpZXcgYSBzdW1tYXJ5IG9mIHRoZXNlIHVwZGF0ZWQsIG51bWVyaWMgdmFyaWFibGVzIG9uIGN1cnJlbmN5IHRvIGVuc3VyZSB0aGF0IHRoZXNlIGNoYW5nZXMgdG8gcmVtb3ZlIHRoZSBjb21tYXMgYW5kIGRvbGxhciBzaWducyBwcm9wZXJseSB3b3JrZWQuIA0KDQpgYGB7cn0NCnN1bW1hcnkobG9hbi51cGRhdGVkW2N1cnJlbmN5XSkNCmBgYA0KDQpBcyB3ZSBjYW4gc2VlLCB0aGUgdmFsdWVzIG9mIGFsbCBvZiB0aGVzZSBjdXJyZW5jeSB2YXJpYWJsZXMgYXJlIG5vdyBnaXZlbiBhcyBzdGFuZGFyZCwgbnVtZXJpYyB2YXJpYWJsZXMuIA0KDQoNCg0KDQojIyBDb21iaW5pbmcgU3BhcnNlIENhdGVnb3JpZXMNCg0KTm93LCB3ZSB3aWxsIHRha2UgYSBsb29rIGF0IG9uZSBvZiB0aGUgY2F0ZWdvcmljYWwgdmFyaWFibGVzIGZyb20gdGhpcyBjb21iaW5lZCBiYW5rIGxvYW4gZGF0YSBzZXQgYW5kIGNvbWJpbmUgaXRzIHNwYXJzZSBjYXRlZ29yaWVzIGluIGEgd2F5IHRoYXQgaXMgbWVhbmluZ2Z1bC4gVGhpcyB3aWxsIGFsbG93IHVzIHRvIGhhdmUgbmV3IGNhdGVnb3JpZXMgdGhhdCBhcmUgZmV3ZXIgaW4gbnVtYmVyLCBhbmQgcHJvdmlkZSBiZXR0ZXIgbWVhbmluZ2Z1bG5lc3MgZm9yIHRoZSBpbnRlcnByZXRhdGlvbiBvZiB0aGlzIHZhcmlhYmxlLg0KDQpXZSB3aWxsIGxvb2sgYXQgdGhlIGNhdGVnb3JpY2FsIHZhcmlhYmxlICJOQUlDUyIuIFRoaXMgdmFyaWFibGUgbG9va3MgYXQgdGhlIE5vcnRoIEFtZXJpY2FuIEluZHVzdHJ5IENsYXNzaWZpY2F0aW9uIFN5c3RlbSBjb2RlIG9mIGVhY2ggb2JzZXJ2YXRpb24uIFRoaXMgdmFyaWFibGUgZGVmaW5lcyBlYWNoIG9ic2VydmF0aW9uIGJ5IHRoZSBzcGVjaWZpYyBpbmR1c3RyeSBvZiB3aGljaCBpdCBpcyByZWxldmFudCB0by4gDQoNCmBgYHtyfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIk5BSUNTLnBuZyIpDQpgYGANCg0KV2Ugd2lsbCBjb21iaW5lZCB0aGUgb2JzZXJ2YXRpb25zIG9mIHRoZSBOQUlDUyB2YXJpYWJsZSBpbnRvIGNhdGVnb3JpZXMgYmFzZWQgdXBvbiB0aGVpciBvZmZpY2lhbCBjbGFzc2lmaWNhdGlvbi4NCg0KYGBge3J9DQpsb2FuLnVwZGF0ZWQ8LSBsb2FuLnVwZGF0ZWQgJT4lDQogIG11dGF0ZShOQUlDUy5jb21iaW5lZCA9IGNhc2Vfd2hlbigNCiAgICBOQUlDUyAlaW4lIGMoIjExIikgfiAiQWdyaWN1bHR1cmUiLA0KICAgIE5BSUNTICVpbiUgYygiMjEiKSB+ICJNaW5pbmciLA0KICAgIE5BSUNTICVpbiUgYygiMjIiKSB+ICJVdGlsaXRpZXMiLA0KICAgIE5BSUNTICVpbiUgYygiMjMiKSB+ICJDb25zdHJ1Y3Rpb24iLA0KICAgIE5BSUNTICVpbiUgYygiMzEiLCAiMzIiLCAiMzMiKSB+ICJNYW51ZmFjdHVyaW5nIiwNCiAgICBOQUlDUyAlaW4lIGMoIjQyIikgfiAiV2hvbGVzYWxlIFRyYWRlIiwNCiAgICBOQUlDUyAlaW4lIGMoIjQ4IiwgIjQ5IikgfiAiVHJhbnNwb3J0YXRpb24iLA0KICAgIE5BSUNTICVpbiUgYygiNTEiKSB+ICJJbmZvcm1hdGlvbiIsDQogICAgTkFJQ1MgJWluJSBjKCI1MiIpIH4gIkZpbmFuY2UiLA0KICAgIE5BSUNTICVpbiUgYygiNTMiKSB+ICJSZWFsIEVzdGF0ZSIsDQogICAgTkFJQ1MgJWluJSBjKCI1NCIpIH4gIlByb2Zlc3Npb25hbCBTZXJ2aWNlcyIsDQogICAgTkFJQ1MgJWluJSBjKCI1NSIpIH4gIk1hbmFnZW1lbnQiLA0KICAgIE5BSUNTICVpbiUgYygiNTYiKSB+ICJBZG1pbmlzdHJhdGl2ZSBTdXBwb3J0IiwNCiAgICBOQUlDUyAlaW4lIGMoIjYxIikgfiAiRWR1Y2F0aW9uYWwgU2VydmljZXMiLA0KICAgIE5BSUNTICVpbiUgYygiNjIiKSB+ICJIZWFsdGhjYXJlIiwNCiAgICBOQUlDUyAlaW4lIGMoIjcxIikgfiAiQXJ0cyIsDQogICAgTkFJQ1MgJWluJSBjKCI3MiIpIH4gIkZvb2QgU2VydmljZXMiLA0KICAgIE5BSUNTICVpbiUgYygiODEiKSB+ICJPdGhlciBTZXJ2aWNlcyIsDQogICAgTkFJQ1MgJWluJSBjKCI5MiIpIH4gIlB1YmxpYyBBZG1pbmlzdHJhdGlvbiINCiAgKQ0KKQ0KYGBgDQoNCg0KDQoNCg0KDQojIyBDYWxjdWxhdGluZyB0aGUgRGVmYXVsdCBSYXRlcw0KDQpOZXh0LCB3ZSB3aWxsIGNhbGN1bGF0ZSB0aGUgZGVmYXVsdCByYXRlcyBvZiB0aGUgTkFJQ1MuY29tYmluZWQgY2F0ZWdvcmljYWwgdmFyaWFibGUgd2hpY2ggd2UgY3JlYXRlZCBpbiB0aGUgcHJldmlvdXMgcGFydC4gDQoNCkZvciB0aGlzIHN0ZXAsIHRoZSB2YWx1ZSBDSEdPRkYgaW4gTUlTX1N0YXR1cyBpcyBkZWZpbmVkIHRvIGJlIGxvYW4gZGVmYXVsdC4gVGhlIGRlZmF1bHQgcmF0ZSB3aWxsIGJlIHRoZSBwZXJjZW50YWdlIG9mIENIR09GRiBpbiBNSVNfU3RhdHVzLg0KDQpgYGB7cn0NCmRlZmF1bHQucmF0ZXMgPC0gbG9hbi51cGRhdGVkICU+JQ0KICBncm91cF9ieShOQUlDUy5jb21iaW5lZCkgJT4lDQogIHN1bW1hcmlzZSh0b3RhbCA9IG4oKSwNCiAgICAgICAgICAgIGRlZmF1bHRzID0gc3VtKE1JU19TdGF0dXMgPT0gIkNIR09GRiIsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBkZWZhdWx0LnJhdGVzID0gZGVmYXVsdHMgLyB0b3RhbCkNCmBgYA0KDQpXZSBjYW4gdmlldyB0aGUgdmFsdWVzIG9mIHRoZSBkZWZhdWx0IHJhdGVzIHdoaWNoIHdlIGNhbGN1bGF0ZWQuIA0KDQpgYGB7cn0NCmRlZmF1bHQucmF0ZXMNCmBgYA0KDQpOb3csIHdlIGhhdmUgc3VjY2Vzc2Z1bGx5IGNhbGN1bGF0ZWQgdGhlIGRlZmF1bHQgcmF0ZXMgZm9yIG91ciBOQUlDUy5jb21iaW5lZCB2YXJpYWJsZSB3aGljaCB3ZSBjcmVhdGVkIHRvIGdyb3VwIHRvZ2V0aGVyIHRoZSBzcGFyc2UgY2F0ZWdvcmllcy4gDQoNCg0KDQoNCiMjIERpc2NyZXRpemluZyB0aGUgR3JBcHB2IFZhcmlhYmxlDQoNCldlIHdpbGwgZGlzY3JldGl6ZSAgdGhlIHZhcmlhYmxlIG9mIEdyQXBwdiBpbnRvIGZpdmUgY2F0ZWdvcmllcy4gVGhpcyB2YXJpYWJsZSByZXByZXNlbnRzIHRoZSBncm9zcyBhbW91bnQgb2YgdGhlIGxvYW4gdGhhdCBoYXMgYmVlbiBhcHByb3ZlZCBieSB0aGUgYmFuay4NCg0KV2Ugd2lsbCBjcmVhdGUgdGhlc2UgY2F0ZWdvcmllcyBiYXNlZCB1cG9uIHRoZSBvdmVyYWxsIGxldmVsIG9mIGhlIHZhbHVlIG9mIHRoZSBHckFwcHYgdmFsdWUuIFRoZXNlIHN1YmNhdGVnb3JpZXMgd2lsbCBzcGxpdCB0aGUgR3JBcHB2IHZhcmlhYmxlIGludG8gZml2ZSBsZXZlbHMsICJsb3dlc3QiLCAibG93IiwgIm1lZGl1bSIsICJoaWdoIiwgYW5kICJoaWdoZXN0IiBiYXNlZCB1cG9uIHRoZSB2YWx1ZSBvZiB0aGUgZ3Jvc3MgYW1vdW50IG9mIGxvYW4gdGhhdCBoYXMgYmVlbiBhcHByb3ZlZCBieSB0aGUgYmFuLg0KDQpGaXJzdCwgbGV0J3MgbG9vayBhdCBhIHF1aWNrIHN1bW1hcnkgb2YgdGhlIG9yaWdpbmFsIEdyQXBwdiB2YXJpYWJsZS4NCg0KYGBge3J9DQpzdW1tYXJ5KGxvYW4udXBkYXRlZCRHckFwcHYpDQpgYGANCg0KQXMgd2UgY2FuIHNlZSwgdGhlIG1pbmltdW0gdmFsdWUgb2YgdGhlIHZhcmlhYmxlIGlzICQyMDAsIGFuZCB0aGUgbWF4aW11bSB2YWx1ZSBpcyAkNSw0NzIsMDAwLiBUaGUgbWVkaWFuIHZhbHVlIGlzICQ5MCwwMDAgaW5kaWNhdGluZyB0aGF0IHRoZSBtYXhpbXVtIHZhbHVlIGRpZmZlcnMgbXVjaCBtb3JlIGdyZWF0bHkgZnJvbSB0aGUgbWVkaWFuIHZhbHVlIHRoYW4gdGhlIG1pbmltdW0gdmFsdWUgZG9lcy4gDQoNCldlIHdpbGwgc3BsaXQgdGhlIEdyQXBwdiB2YXJpYWJsZSBpbnRvIGZpdmUgc3ViY2F0ZWdvcmllcyBiYXNlZCB1cG9uIHRoZSB2YWx1ZSBvZiBlYWNoIG9ic2VydmF0aW9uLiBXZSB3aWxsIGNyZWF0ZSBhIG5ldyB2YXJpYWJsZSBjYWxsZWQgIkdyQXBwdi5kaXMiIHRvIHJlcHJlc2VudCB0aGUgZGlzY3JldGl6ZWQgdmVyc2lvbiBvZiB0aGUgb3JpZ2luYWwgR3JBcHB2IHZhcmlhYmxlLiANCg0KYGBge3J9DQpsb2FuLnVwZGF0ZWQkR3JBcHB2LmRpcyA8LSBjdXQobG9hbi51cGRhdGVkJEdyQXBwdiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gNSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiTG93ZXN0IiwgIkxvdyIsICJNZWRpdW0iLCAiSGlnaCIsICJIaWdoZXN0IikpDQpgYGANCg0KTm93IHdlIGhhdmUgZml2ZSBzdWJjYXRlZ29yaWVzIG9mIHRoZSBHckFwcHYgdmFyaWFibGUgc3BsaXQgdXAgZnJvbSB0aGUgbG93ZXN0IHRvIHRoZSBoaWdoZXN0LiANCg0KDQoNCg0KIyMgRGVuc2l0eSBDdXJ2ZXMNCg0KTGFzdGx5LCB3ZSB3aWxsIGRyYXcgdGhlIGRlbnNpdHkgY3VydmVzIG9mIFNCQV9BcHB2IGZvciBlYWNoIG9mIHRoZSBmaXZlIHN1Yi1wb3B1bGF0aW9ucyB0aGF0IHdlcmUgY3JlYXRlZCBpbiB0aGUgcHJldmlvdXMgcGFydC4gV2Ugd2lsbCBwbGFjZSB0aGVzZSBmaXZlIGRlbnNpdHkgY3VydmVzIG9udG8gdGhlIHNhbWUgcGxvdC4gDQoNCmBgYHtyfQ0KZ2dwbG90KGxvYW4udXBkYXRlZCwgYWVzKHggPSBTQkFfQXBwdiwgZmlsbCA9IEdyQXBwdi5kaXMpKSArDQogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNSkgKw0KICBsYWJzKHRpdGxlID0gIkRlbnNpdHkgQ3VydmVzIG9mIFNCQV9BcHB2IGZvciB0aGUgXG4gRml2ZSBTdWJDYXRlZ29yaWVzIG9mIEdyQXBwdiIsDQogICAgICAgeCA9ICJTQkFfQXBwdiIsIHkgPSAiRGVuc2l0eSIpIA0KYGBgDQoNCkluIHRoZSBncmFwaCwgd2UgY2FuIHNlZSB0aGUgZGVuc2l0eSBjdXJ2ZXMgb2YgdGhlIFNCQV9BcHB2IHZhcmlhYmxlIGZvciBlYWNoIG9mIHRoZSBmaXZlIGNhdGVnb3JpZXMgb2YgR3JBcHB2IHRoYXQgd2UgY3JlYXRlZCBpbiB0aGUgcHJldmlvdXMgcGFydC4gV2UgY2FuIHNlZSB0aGF0IHRoZXNlIGZpdmUgY2F0ZWdvcmllcyBoYXZlIGJlZW4gY29sb3ItY29kZWQgYnkgdGhlaXIgcmVzcGVjdGl2ZSByYW5rIG9mICJsb3dlc3QiLCAibG93IiwgIm1lZGl1bSIsICJoaWdoIiwgIm9yIGhpZ2hlc3QiLg0KDQoNCiMgQ29uY2x1c2lvbg0KDQpXZSBoYXZlIGNvbXBsZXRlZCB0aGUgZGVzaXJlZCBleHBsb3JhdG9yeSBkYXRhIGFuYWx5c2lzIHN0ZXBzIGluY2x1ZGluZyBkZWFsaW5nIHdpdGggbWlzc2luZyB2YWx1ZXMgYXMgd2VsbCBhcyB1cGRhdGluZyBzb21lIG9mIHRoZSB2YXJpYWJsZXMgd2l0aGluIHRoZSBvcmlnaW5hbCBjb21iaW5lZCBiYW5rIGxvYW4gZGF0YSBzZXQuIFdlIG5vdyBoYXZlIGEgbmV3IGRhdGEgc2V0IGNhbGxlZCAibG9hbi51cGRhdGVkIiB3aXRoIGFsbCBvZiB0aGUgZGVzaXJlZCB1cGRhdGVzIHRvIHRoZSBkYXRhIHNldC4gDQo=