1 Read in Bank Loan Default Dataset

Read in dataset.

bank <- read.csv("BankLoanDefaultDataset.csv")

Below looks at each variable and see what type they all are.

str(bank)
'data.frame':   1000 obs. of  16 variables:
 $ Default         : int  0 0 0 1 1 0 0 0 0 1 ...
 $ Checking_amount : int  988 458 158 300 63 1071 -192 172 585 189 ...
 $ Term            : int  15 15 14 25 24 20 13 16 20 19 ...
 $ Credit_score    : int  796 813 756 737 662 828 856 763 778 649 ...
 $ Gender          : chr  "Female" "Female" "Female" "Female" ...
 $ Marital_status  : chr  "Single" "Single" "Single" "Single" ...
 $ Car_loan        : int  1 1 0 0 0 1 1 1 1 1 ...
 $ Personal_loan   : int  0 0 1 0 0 0 0 0 0 0 ...
 $ Home_loan       : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Education_loan  : int  0 0 0 1 1 0 0 0 0 0 ...
 $ Emp_status      : chr  "employed" "employed" "employed" "employed" ...
 $ Amount          : int  1536 947 1678 1804 1184 475 626 1224 1162 786 ...
 $ Saving_amount   : int  3455 3600 3093 2449 2867 3282 3398 3022 3475 2711 ...
 $ Emp_duration    : int  12 25 43 0 4 12 11 12 12 0 ...
 $ Age             : int  38 36 34 29 30 32 38 36 36 29 ...
 $ No_of_credit_acc: int  1 1 1 1 1 2 1 1 1 1 ...

Below looks at the top few rows of dataset.

head(bank)
  Default Checking_amount Term Credit_score Gender Marital_status Car_loan
1       0             988   15          796 Female         Single        1
2       0             458   15          813 Female         Single        1
3       0             158   14          756 Female         Single        0
4       1             300   25          737 Female         Single        0
5       1              63   24          662 Female         Single        0
6       0            1071   20          828   Male        Married        1
  Personal_loan Home_loan Education_loan Emp_status Amount Saving_amount
1             0         0              0   employed   1536          3455
2             0         0              0   employed    947          3600
3             1         0              0   employed   1678          3093
4             0         0              1   employed   1804          2449
5             0         0              1 unemployed   1184          2867
6             0         0              0   employed    475          3282
  Emp_duration Age No_of_credit_acc
1           12  38                1
2           25  36                1
3           43  34                1
4            0  29                1
5            4  30                1
6           12  32                2

1.1 Create Missing Values

The original dataset does not have any missing values so I needed to manually create them.

gender.missing.id <- sample(1:1000, 20 , replace = FALSE)
Marital.missing.id <- sample(1:1000, 20, replace = FALSE)
emp.status.missing.id <- sample(1:1000, 20, replace = FALSE)
credit.missing.id <- sample(1:1000, 20, replace = FALSE)
amount.missing.id <- sample(1:1000, 20, replace = FALSE)
emp.duration.missing.id <- sample(1:1000, 20, replace = FALSE)
check.amt.missing.id <- sample(1:1000, 20, replace = FALSE)
age.missing.id <- sample(1:1000, 20, replace = FALSE)

bank$Gender[gender.missing.id] <- NA
bank$Marital_status[Marital.missing.id] <- NA
bank$Emp_status[emp.status.missing.id] <- NA
bank$Credit_score[credit.missing.id] <- NA
bank$Amount[amount.missing.id] <- NA
bank$Emp_duration[emp.duration.missing.id] <- NA
bank$Checking_amount[check.amt.missing.id] <- NA
bank$Age[age.missing.id] <- NA

2 Description and Purpose of Dataset and Analytic Tasks

This dataset is titled “Bank Loan Default Dataset” and shows various explanatory variables and one target/response variable (Default). The purpose of collecting this dataset is to see what factors may cause peoples loans to be in default or not. This dataset was collected from your Course Project Data Repository. This dataset contains 1000 observations and 16 variables (15 feature variables and 1 target variable). The Checking_amount is a numerical variable that shows the amount of money in ones checking account. The Saving_amount is a numerical variable that shows the amount of money in ones saving account. The term (numerical) is the duration of the loan term. The credit_score (numerical) shows ones credit score. The gender (categorical) consists of male and female. The marital_status (categorical) consists of married or single. The car_loan, personal_loan, home_loan, and education_loan (all categorical/binary) shows if people have loans in any of those areas. The emp_status (categorical) consists of unemployed or employed. The amount (numerical) shows the amount of the loan. The emp_duration (num) shows length of employment in months. Age (num) shows age and no_of_credit_account (num) shows number of credit accounts. The overall goal of this project is to see how significant the feature variables are in predicting if ones loan will be in default (1 if default, 0 if not). The first part of the project is doing EDA.

The original dataset did not have any missing values so I needed to manually create them. For this dataset, the variables Gender, Marital_status, Emp_status, credit_score, amount, emp_duration, checking_amount, and age have missing values. Missing numerical values can be resolved by imputing the mean. Missing categorical values can be resolved by imputing the mode.

3 Distribution of Individual Features

This section will show the distribution of each individual feature. Some features will have missing values and can be resolved by imputing the mean or mode.

The below figure shows the distribution of the Gender variable. There are significantly more males than females.

ggplot(bank, aes(x = Gender)) + 
  
  geom_bar() +
  labs(title = "Gender")

The below figure shows the distribution of the Marital_status variable. Married and single people have similar counts.

ggplot(bank, aes(x = Marital_status)) + 
  
  geom_bar() +
  labs(title = "Marital_status")

The below figure shows the distribution of the Emp_status variable. There are significantly more unemployed than employed.

ggplot(bank, aes(x = Emp_status)) + 
  
  geom_bar() +
  labs(title = "Emp_status")

The below figure shows the distribution of the car loan variable. There are significantly more that do not have a car loan than those that do.

ggplot(bank, aes(x = Car_loan)) + 
  
  geom_bar() +
  labs(title = "Car_loan")

The below figure shows the distribution of the personal loan variable. Those that have a personal loan and those that do not have similar counts.

ggplot(bank, aes(x = Personal_loan)) + 
  
  geom_bar() +
  labs(title = "Personal_loan")

The below figure shows the distribution of the education loan variable. There are significantly more that do not have an education loan than those that do.

ggplot(bank, aes(x = Education_loan)) + 
  
  geom_bar() +
  labs(title = "Education_loan")

The below figure shows the distribution of the home loan variable. There are significantly more that do not have a home loan than those that do.

ggplot(bank, aes(x = Home_loan)) + 
  
  geom_bar() +
  labs(title = "Home_loan")

The below figure shows the distribution of the credit score variable. There are no alarming trends outside of a couple anomalies.

ggplot(data = bank, aes(x = Credit_score)) + 
  geom_boxplot() + 
  
  labs(title = "Credit_score")

The below figure shows the distribution of the checking amount variable. There are no alarming trends.

ggplot(data = bank, aes(x = Checking_amount)) + 
  geom_boxplot() + 
  
  labs(title = "Checking_amount")

The below figure shows the distribution of the term variable. There are no alarming trends.

ggplot(data = bank, aes(x = Term)) + 
  geom_boxplot() + 
  
  labs(title = "Term")

The below figure shows the distribution of the amount variable. There are no alarming trends.

ggplot(data = bank, aes(x = Amount)) + 
  geom_boxplot() + 
  
  labs(title = "Amount")

The below figure shows the distribution of the Saving amount variable. There are no alarming trends.

ggplot(data = bank, aes(x = Saving_amount)) + 
  geom_boxplot() + 
  
  labs(title = "Saving amount")

The below figure shows the distribution of the Emp_duration variable. There are no alarming trends.

ggplot(data = bank, aes(x = Emp_duration)) + 
  geom_boxplot() + 
  
  labs(title = "Emp duration")

The below figure shows the distribution of the age variable. There are no alarming trends.

ggplot(data = bank, aes(x = Age)) + 
  geom_boxplot() + 
  
  labs(title = "Age")

The below figure shows the distribution of the No_of_credit_acc variable. This variable seems to be heavily skewed.

ggplot(data = bank, aes(x = No_of_credit_acc)) + 
  geom_boxplot() + 
  
  labs(title = "No_of_credit_acc")

4 One Categorical Feature and One Numerical feature Graphs

In this section, we will show the relationship between one categorical feature and one numerical feature.

The below figure shows the relationship between credit score and gender. Based on the graph, the credit score ranges look to be similar across both genders. There are some anomalies but I do not believe that they will have a significant effect on the analysis. There are missing values but they can be resolved using imputation.

ggplot(bank, aes(x=Credit_score, y=Gender, fill=Gender)) +
  geom_boxplot() + theme(legend.position="none")+
ggtitle("Credit Score by Gender")

The below figure shows the relationship between loan amount and gender. Based on the graph, the loan amount ranges look to be similar across both genders. There are some anomalies but I do not believe that they will have a significant effect on the analysis. There are missing values but they can be resolved using imputation.

ggplot(bank, aes(x=Amount, y=Gender, fill=Gender)) +
  geom_boxplot() + theme(legend.position="none")+
ggtitle("Amount by Gender")

The below figure shows the relationship between Employment duration and gender. Based on the graph, it seems like males have a longer employment duration than females. There are missing values but they can be resolved using imputation.

ggplot(bank, aes(x=Emp_duration, y=Gender, fill=Gender)) +
  geom_boxplot() + theme(legend.position="none")+
ggtitle("Employment duration by Gender")

The below figure shows the relationship between Age and gender. Based on the graph, the Age ranges look to be similar across both genders. There are some anomalies but I do not believe that they will have a significant effect on the analysis. There are missing values but they can be resolved using imputation.

ggplot(bank, aes(x=Age, y=Gender, fill=Gender)) +
  geom_boxplot() + theme(legend.position="none")+
ggtitle("Age by Gender")

The below figure shows the relationship between marital status and credit score. Based on the graph, the credit score ranges look to be similar across both single and married people. There are some anomalies but I do not believe that they will have a significant effect on the analysis. There are missing values but they can be resolved using imputation.

ggplot(bank, aes(x=Credit_score, y=Marital_status, fill=Marital_status)) +
  geom_boxplot() + theme(legend.position="none")+
ggtitle("Credit Score by Marital status")

The below figure shows the relationship between loan amount and marital status. Based on the graph, the loan amount ranges look to be similar across both marital statuses. There are some anomalies but I do not believe that they will have a significant effect on the analysis. There are missing values but they can be resolved using imputation.

ggplot(bank, aes(x=Amount, y=Marital_status, fill=Marital_status)) +
  geom_boxplot() + theme(legend.position="none")+
ggtitle("Amount by Marital status")

The below figure shows the relationship between marital status and employment duration. Based on the graph, it seems like married people have longer employment duration than single people. There are missing values but they can be resolved using imputation.

ggplot(bank, aes(x=Emp_duration, y=Marital_status, fill=Marital_status)) +
  geom_boxplot() + theme(legend.position="none")+
ggtitle("Employment duration by Marital status")

The below figure shows the relationship between Age and marital status. Based on the graph, the Age ranges look to be similar across both marital statuses. There are some anomalies but I do not believe that they will have a significant effect on the analysis. There are missing values but they can be resolved using imputation.

ggplot(bank, aes(x=Age, y=Marital_status, fill=Marital_status)) +
  geom_boxplot() + theme(legend.position="none")+
ggtitle("age by Marital status")

The below figure shows the relationship between credit score and employment status. Based on the graph, the credit score ranges look to be similar across both employed and unemployed people. There seems to be more anomalies for unemployed people but I do not believe that they will have a significant effect on the analysis. There are missing values but they can be resolved using imputation.

ggplot(bank, aes(x=Credit_score, y=Emp_status, fill=Emp_status)) +
  geom_boxplot() + theme(legend.position="none")+
ggtitle("Credit Score by Employment status")

The below figure shows the relationship between loan amount and employment status. Based on the graph, the loan amount ranges look to be similar across both employed/unemployed. Again there seems to be more anomalies for unemployed people than employed. There are missing values but they can be resolved using imputation.

ggplot(bank, aes(x=Amount, y=Emp_status, fill=Emp_status)) +
  geom_boxplot() + theme(legend.position="none")+
ggtitle("Amount by Employment status")

The below figure shows the relationship between employment duration and employment status. Based on the graph, it seems like unemployed people have longer and more varied employment duration than employed people. There are missing values but they can be resolved using imputation.

ggplot(bank, aes(x=Emp_duration, y=Emp_status, fill=Emp_status)) +
  geom_boxplot() + theme(legend.position="none")+
ggtitle("Employment duration by employment status")

The below figure shows the relationship between Age and employment status. Based on the graph, the Age ranges look to be similar across both statuses. There are some anomalies but I do not believe that they will have a significant effect on the analysis. There are missing values but they can be resolved using imputation.

ggplot(bank, aes(x=Age, y=Emp_status, fill=Emp_status)) +
  geom_boxplot() + theme(legend.position="none")+
ggtitle("age by employment status")

The below figure shows the relationship between Age and car loan. Based on the graph, the Age ranges look to be similar across both those who own a car loan and those who do not.

# convert car, home, personal, and education loans into categorical to use for EDA purposes
 bank$Car_loan <- as.factor(bank$Car_loan)
 bank$Personal_loan <- as.factor(bank$Personal_loan)
 bank$Home_loan <- as.factor(bank$Home_loan)
 bank$Education_loan <- as.factor(bank$Education_loan)
 
ggplot(bank, aes(x=Age, y=Car_loan, fill=Car_loan)) +
  geom_boxplot() + theme(legend.position="none")+
ggtitle("age by car loan")

The below figure shows the relationship between Age and personal loan. Based on the graph, the Age ranges look to be similar across all those that have a personal loan or not.

ggplot(bank, aes(x=Age, y=Personal_loan, fill=Personal_loan)) +
  geom_boxplot() + theme(legend.position="none")+
ggtitle("age by personal_loan")

The below figure shows the relationship between Age and home loan. Based on the graph, the Age ranges look to be similar across all those that have a home loan or not.

ggplot(bank, aes(x=Age, y=Home_loan, fill=Home_loan)) +
  geom_boxplot() + theme(legend.position="none")+
ggtitle("age by home_loan")

The below figure shows the relationship between Age and education loan. Based on the graph, it seems like younger people have an education loan and older people do not.

ggplot(bank, aes(x=Age, y=Education_loan, fill=Education_loan)) +
  geom_boxplot() + theme(legend.position="none")+
ggtitle("age by education loan")

5 Two numerical feature variables graphs

Next, we will examine the relationship between two numerical features.

The below graph shows employment duration and credit score. Based on the graph, it seems like regardless of the employment duration, the majority of the credit scores seem to fall in the 700-900 range.

ggplot(data = bank, aes(x = Credit_score, y = Emp_duration)) +
  geom_point() + 
  ggtitle("Employment Duration vs Credit Score")

The below graph shows employment duration and loan amount. There does not seem to be any patterns based on this graph.

ggplot(data = bank, aes(x = Amount, y = Emp_duration)) +
  geom_point() + 
  ggtitle("Employment Duration vs Loan Amount")

The below graph shows employment duration and age. There does not seem to be any patterns based on this graph.

ggplot(data = bank, aes(x = Age, y = Emp_duration)) +
  geom_point() + 
  ggtitle("Employment Duration vs Age")

The below graph shows age and Credit score. Again, it seems like regardless of age, most of the credit scores seem to fall in that 700-900 range.

ggplot(data = bank, aes(x = Age, y = Credit_score)) +
  geom_point() + 
  ggtitle("Age vs credit score")

The below graph shows checking amount and saving amount. There does not seem to be any correlation between these two variables.

ggplot(data = bank, aes(x = Checking_amount, y = Saving_amount)) +
  geom_point() + 
  ggtitle("Checking amount vs savings Amount")

The below graph shows age and loan amount. It seems like regardless of age, most of the loan amounts seem to fall in a certain range.

ggplot(data = bank, aes(x = Age, y = Amount)) +
  geom_point() + 
  ggtitle("age vs Loan Amount")

The below graph shows credit score and loan amount. It seems like most of the points are clumped together.

ggplot(data = bank, aes(x = Credit_score, y = Amount)) +
  geom_point() + 
  ggtitle("credit score vs Loan Amount")

6 Two categorical feature variables graphs

This section shows the relationships between two categorical features.

The below graph shows Gender and Employment status. It seems like the amount of employed and unemployed females are similar but there are significantly more unemployed males than employed.

ggplot(bank, aes(Gender, ..count..)) + geom_bar(aes(fill = Emp_status), position = "dodge")+ggtitle("gender vs employment status")

The below graph shows Gender and marital status. It seems like all females are single and there are significantly more married males than single.

ggplot(bank, aes(Gender, ..count..)) + geom_bar(aes(fill = Marital_status), position = "dodge")+ggtitle("gender vs marital status")

The below graph shows employment status and marital status. It seems like the amount of employed and unemployed people are relatively similar but for married people, there are significantly more who are unemployed.

ggplot(bank, aes(Marital_status, ..count..)) + geom_bar(aes(fill = Emp_status), position = "dodge")+ggtitle("marital status vs enployment status")

The below graph shows gender and car loan. It seems like for both males and females, there are significantly more that do not have car loans than those that do.

ggplot(bank, aes(Gender, ..count..)) + geom_bar(aes(fill = Car_loan), position = "dodge")+ggtitle("gender vs car loan")

The below graph shows gender and education loan. It seems like for both males and females, there are significantly more that do not have education loans than those that do.

ggplot(bank, aes(Gender, ..count..)) + geom_bar(aes(fill = Education_loan), position = "dodge")+ggtitle("Gender vs education Loan")

The below graph shows gender and personal loan. It seems like for both males and females, the amounts that who have personal loans and those that do not are relatively similar.

ggplot(bank, aes(Gender, ..count..)) + geom_bar(aes(fill = Personal_loan), position = "dodge")+ggtitle("Gender vs personal Loan")

The below graph shows gender and home loan. It seems like for both males and females, there are significantly more that do not have home loans than those that do.

ggplot(bank, aes(Gender, ..count..)) + geom_bar(aes(fill = Home_loan), position = "dodge")+ggtitle("Gender vs home Loan")

LS0tDQp0aXRsZTogIkJhbmsgTG9hbiBEZWZhdWx0IERhdGFzZXQiDQphdXRob3I6ICJFcmljIFpodSINCmRhdGU6ICIyMDI1LTAyLTA1Ig0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIHRvY19mbG9hdDogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMNCiAgICB0aGVtZTogbHVtZW4NCiAgcGRmX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IG5vDQogICAgZmlnX3dpZHRoOiAzDQogICAgZmlnX2hlaWdodDogMw0KZWRpdG9yX29wdGlvbnM6IA0KICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lDQotLS0NCg0KDQpgYGB7PWh0bWx9DQoNCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoNCi8qIENhc2NhZGluZyBTdHlsZSBTaGVldHMgKENTUykgaXMgYSBzdHlsZXNoZWV0IGxhbmd1YWdlIHVzZWQgdG8gZGVzY3JpYmUgdGhlIHByZXNlbnRhdGlvbiBvZiBhIGRvY3VtZW50IHdyaXR0ZW4gaW4gSFRNTCBvciBYTUwuIGl0IGlzIGEgc2ltcGxlIG1lY2hhbmlzbSBmb3IgYWRkaW5nIHN0eWxlIChlLmcuLCBmb250cywgY29sb3JzLCBzcGFjaW5nKSB0byBXZWIgZG9jdW1lbnRzLiAqLw0KDQpoMS50aXRsZSB7ICAvKiBUaXRsZSAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgdGhlIHJlcG9ydCB0aXRsZSAqLw0KICBmb250LXNpemU6IDI0cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBjb2xvcjogbmF2eTsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KICBmb250LWZhbWlseTogIkdpbGwgU2FucyIsIHNhbnMtc2VyaWY7DQp9DQpoNC5hdXRob3IgeyAvKiBIZWFkZXIgNCAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgZm9yIGF1dGhvcnMgICovDQogIGZvbnQtc2l6ZTogMThweDsNCiAgZm9udC1mYW1pbHk6IHN5c3RlbS11aTsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGNvbG9yOiBuYXZ5Ow0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQpoNC5kYXRlIHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciB0aGUgZGF0ZSAgKi8NCiAgZm9udC1zaXplOiAxOHB4Ow0KICBmb250LWZhbWlseTogc3lzdGVtLXVpOw0KICBjb2xvcjogRGFya0JsdWU7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQp9DQpoMSB7IC8qIEhlYWRlciAxIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgbGV2ZWwgMSBzZWN0aW9uIHRpdGxlICAqLw0KICAgIGZvbnQtc2l6ZTogMjBweDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBjZW50ZXI7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQp9DQpoMiB7IC8qIEhlYWRlciAyIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgbGV2ZWwgMiBzZWN0aW9uIHRpdGxlICovDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQp9DQoNCmgzIHsgLyogSGVhZGVyIDMgLSBmb250IHNwZWNpZmljYXRpb25zIG9mIGxldmVsIDMgc2VjdGlvbiB0aXRsZSAgKi8NCiAgICBmb250LXNpemU6IDE2cHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDQgeyAvKiBIZWFkZXIgNCAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgbGV2ZWwgNCBzZWN0aW9uIHRpdGxlICAqLw0KICAgIGZvbnQtc2l6ZTogMTRweDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpib2R5IHsgYmFja2dyb3VuZC1jb2xvcjp3aGl0ZTsgfQ0KDQouaGlnaGxpZ2h0bWUgeyBiYWNrZ3JvdW5kLWNvbG9yOnllbGxvdzsgfQ0KDQpwIHsgYmFja2dyb3VuZC1jb2xvcjp3aGl0ZTsgfQ0KDQo8L3N0eWxlPg0KYGBgDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KIyBjb2RlIGNodW5rIHNwZWNpZmllcyB3aGV0aGVyIHRoZSBSIGNvZGUsIHdhcm5pbmdzLCBhbmQgb3V0cHV0IA0KIyB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBvdXRwdXQgZmlsZXMuDQppZiAoIXJlcXVpcmUoImtuaXRyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikNCiAgIGxpYnJhcnkoa25pdHIpDQp9DQppZiAoIXJlcXVpcmUoInRpZHl2ZXJzZSIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQp9DQppZiAoIXJlcXVpcmUoInJlYWR4bCIpKSB7ICMgU1ZNIG1ldGhvZG9sb2d5DQogICBpbnN0YWxsLnBhY2thZ2VzKCJyZWFkeGwiKQ0KbGlicmFyeShyZWFkeGwpDQp9DQppZiAoIXJlcXVpcmUoImdncGxvdDIiKSkgeyAjIFNWTSBtZXRob2RvbG9neQ0KICAgaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpDQpsaWJyYXJ5KGdncGxvdDIpDQp9DQppZiAoIXJlcXVpcmUoIklTTFIiKSkgeyAjIGNvbnRhaW5zIGV4YW1wbGUgZGF0YSBzZXQgIktoYW4iDQogICBpbnN0YWxsLnBhY2thZ2VzKCJJU0xSIikNCmxpYnJhcnkoSVNMUikNCn0NCmlmICghcmVxdWlyZSgiUkNvbG9yQnJld2VyIikpIHsgIyBjdXN0b21pemVkIGNvbG9yaW5nIG9mIHBsb3RzDQogICBpbnN0YWxsLnBhY2thZ2VzKCJSQ29sb3JCcmV3ZXIiKQ0KbGlicmFyeShSQ29sb3JCcmV3ZXIpDQp9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAgICAgICMgaW5jbHVkZSBjb2RlIGNodW5rIGluIHRoZSBvdXRwdXQgZmlsZQ0KICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwgICAjIHNvbWV0aW1lcywgeW91IGNvZGUgbWF5IHByb2R1Y2Ugd2FybmluZyBtZXNzYWdlcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB5b3UgY2FuIGNob29zZSB0byBpbmNsdWRlIHRoZSB3YXJuaW5nIG1lc3NhZ2VzIGluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhlIG91dHB1dCBmaWxlLiANCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHRzID0gVFJVRSwgICAgIyB5b3UgY2FuIGFsc28gZGVjaWRlIHdoZXRoZXIgdG8gaW5jbHVkZSB0aGUgb3V0cHV0DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgaW4gdGhlIG91dHB1dCBmaWxlLg0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkENCiAgICAgICAgICAgICAgICAgICAgICApICANCmBgYA0KDQoNCg0KDQojIFJlYWQgaW4gQmFuayBMb2FuIERlZmF1bHQgRGF0YXNldA0KDQpSZWFkIGluIGRhdGFzZXQuDQoNCmBgYHtyfQ0KYmFuayA8LSByZWFkLmNzdigiQmFua0xvYW5EZWZhdWx0RGF0YXNldC5jc3YiKQ0KYGBgDQoNCkJlbG93IGxvb2tzIGF0IGVhY2ggdmFyaWFibGUgYW5kIHNlZSB3aGF0IHR5cGUgdGhleSBhbGwgYXJlLg0KDQpgYGB7cn0NCnN0cihiYW5rKQ0KYGBgDQoNCkJlbG93IGxvb2tzIGF0IHRoZSB0b3AgZmV3IHJvd3Mgb2YgZGF0YXNldC4NCg0KYGBge3J9DQpoZWFkKGJhbmspDQpgYGANCg0KDQojIyBDcmVhdGUgTWlzc2luZyBWYWx1ZXMNCg0KVGhlIG9yaWdpbmFsIGRhdGFzZXQgZG9lcyBub3QgaGF2ZSBhbnkgbWlzc2luZyB2YWx1ZXMgc28gSSBuZWVkZWQgdG8gbWFudWFsbHkgY3JlYXRlIHRoZW0uDQoNCmBgYHtyfQ0KZ2VuZGVyLm1pc3NpbmcuaWQgPC0gc2FtcGxlKDE6MTAwMCwgMjAgLCByZXBsYWNlID0gRkFMU0UpDQpNYXJpdGFsLm1pc3NpbmcuaWQgPC0gc2FtcGxlKDE6MTAwMCwgMjAsIHJlcGxhY2UgPSBGQUxTRSkNCmVtcC5zdGF0dXMubWlzc2luZy5pZCA8LSBzYW1wbGUoMToxMDAwLCAyMCwgcmVwbGFjZSA9IEZBTFNFKQ0KY3JlZGl0Lm1pc3NpbmcuaWQgPC0gc2FtcGxlKDE6MTAwMCwgMjAsIHJlcGxhY2UgPSBGQUxTRSkNCmFtb3VudC5taXNzaW5nLmlkIDwtIHNhbXBsZSgxOjEwMDAsIDIwLCByZXBsYWNlID0gRkFMU0UpDQplbXAuZHVyYXRpb24ubWlzc2luZy5pZCA8LSBzYW1wbGUoMToxMDAwLCAyMCwgcmVwbGFjZSA9IEZBTFNFKQ0KY2hlY2suYW10Lm1pc3NpbmcuaWQgPC0gc2FtcGxlKDE6MTAwMCwgMjAsIHJlcGxhY2UgPSBGQUxTRSkNCmFnZS5taXNzaW5nLmlkIDwtIHNhbXBsZSgxOjEwMDAsIDIwLCByZXBsYWNlID0gRkFMU0UpDQoNCmJhbmskR2VuZGVyW2dlbmRlci5taXNzaW5nLmlkXSA8LSBOQQ0KYmFuayRNYXJpdGFsX3N0YXR1c1tNYXJpdGFsLm1pc3NpbmcuaWRdIDwtIE5BDQpiYW5rJEVtcF9zdGF0dXNbZW1wLnN0YXR1cy5taXNzaW5nLmlkXSA8LSBOQQ0KYmFuayRDcmVkaXRfc2NvcmVbY3JlZGl0Lm1pc3NpbmcuaWRdIDwtIE5BDQpiYW5rJEFtb3VudFthbW91bnQubWlzc2luZy5pZF0gPC0gTkENCmJhbmskRW1wX2R1cmF0aW9uW2VtcC5kdXJhdGlvbi5taXNzaW5nLmlkXSA8LSBOQQ0KYmFuayRDaGVja2luZ19hbW91bnRbY2hlY2suYW10Lm1pc3NpbmcuaWRdIDwtIE5BDQpiYW5rJEFnZVthZ2UubWlzc2luZy5pZF0gPC0gTkENCg0KDQoNCmBgYA0KDQojIERlc2NyaXB0aW9uIGFuZCBQdXJwb3NlIG9mIERhdGFzZXQgYW5kIEFuYWx5dGljIFRhc2tzDQoNClRoaXMgZGF0YXNldCBpcyB0aXRsZWQgIkJhbmsgTG9hbiBEZWZhdWx0IERhdGFzZXQiIGFuZCBzaG93cyB2YXJpb3VzIGV4cGxhbmF0b3J5IHZhcmlhYmxlcyBhbmQgb25lIHRhcmdldC9yZXNwb25zZSB2YXJpYWJsZSAoRGVmYXVsdCkuIFRoZSBwdXJwb3NlIG9mIGNvbGxlY3RpbmcgdGhpcyBkYXRhc2V0IGlzIHRvIHNlZSB3aGF0IGZhY3RvcnMgbWF5IGNhdXNlIHBlb3BsZXMgbG9hbnMgdG8gYmUgaW4gZGVmYXVsdCBvciBub3QuIFRoaXMgZGF0YXNldCB3YXMgY29sbGVjdGVkIGZyb20geW91ciBDb3Vyc2UgUHJvamVjdCBEYXRhIFJlcG9zaXRvcnkuIFRoaXMgZGF0YXNldCBjb250YWlucyAxMDAwIG9ic2VydmF0aW9ucyBhbmQgMTYgdmFyaWFibGVzICgxNSBmZWF0dXJlIHZhcmlhYmxlcyBhbmQgMSB0YXJnZXQgdmFyaWFibGUpLiBUaGUgQ2hlY2tpbmdfYW1vdW50IGlzIGEgbnVtZXJpY2FsIHZhcmlhYmxlIHRoYXQgc2hvd3MgdGhlIGFtb3VudCBvZiBtb25leSBpbiBvbmVzIGNoZWNraW5nIGFjY291bnQuIFRoZSBTYXZpbmdfYW1vdW50IGlzIGEgbnVtZXJpY2FsIHZhcmlhYmxlIHRoYXQgc2hvd3MgdGhlIGFtb3VudCBvZiBtb25leSBpbiBvbmVzIHNhdmluZyBhY2NvdW50LiBUaGUgdGVybSAobnVtZXJpY2FsKSBpcyB0aGUgZHVyYXRpb24gb2YgdGhlIGxvYW4gdGVybS4gVGhlIGNyZWRpdF9zY29yZSAobnVtZXJpY2FsKSBzaG93cyBvbmVzIGNyZWRpdCBzY29yZS4gVGhlIGdlbmRlciAoY2F0ZWdvcmljYWwpIGNvbnNpc3RzIG9mIG1hbGUgYW5kIGZlbWFsZS4gVGhlIG1hcml0YWxfc3RhdHVzIChjYXRlZ29yaWNhbCkgY29uc2lzdHMgb2YgbWFycmllZCBvciBzaW5nbGUuIFRoZSBjYXJfbG9hbiwgcGVyc29uYWxfbG9hbiwgaG9tZV9sb2FuLCBhbmQgZWR1Y2F0aW9uX2xvYW4gKGFsbCBjYXRlZ29yaWNhbC9iaW5hcnkpIHNob3dzIGlmIHBlb3BsZSBoYXZlIGxvYW5zIGluIGFueSBvZiB0aG9zZSBhcmVhcy4gVGhlIGVtcF9zdGF0dXMgKGNhdGVnb3JpY2FsKSBjb25zaXN0cyBvZiB1bmVtcGxveWVkIG9yIGVtcGxveWVkLiBUaGUgYW1vdW50IChudW1lcmljYWwpIHNob3dzIHRoZSBhbW91bnQgb2YgdGhlIGxvYW4uIFRoZSBlbXBfZHVyYXRpb24gKG51bSkgc2hvd3MgbGVuZ3RoIG9mIGVtcGxveW1lbnQgaW4gbW9udGhzLiBBZ2UgKG51bSkgc2hvd3MgYWdlIGFuZCBub19vZl9jcmVkaXRfYWNjb3VudCAobnVtKSBzaG93cyBudW1iZXIgb2YgY3JlZGl0IGFjY291bnRzLiBUaGUgb3ZlcmFsbCBnb2FsIG9mIHRoaXMgcHJvamVjdCBpcyB0byBzZWUgaG93IHNpZ25pZmljYW50IHRoZSBmZWF0dXJlIHZhcmlhYmxlcyBhcmUgaW4gcHJlZGljdGluZyBpZiBvbmVzIGxvYW4gd2lsbCBiZSBpbiBkZWZhdWx0ICgxIGlmIGRlZmF1bHQsIDAgaWYgbm90KS4gVGhlIGZpcnN0IHBhcnQgb2YgdGhlIHByb2plY3QgaXMgZG9pbmcgRURBLg0KDQpUaGUgb3JpZ2luYWwgZGF0YXNldCBkaWQgbm90IGhhdmUgYW55IG1pc3NpbmcgdmFsdWVzIHNvIEkgbmVlZGVkIHRvIG1hbnVhbGx5IGNyZWF0ZSB0aGVtLiBGb3IgdGhpcyBkYXRhc2V0LCB0aGUgdmFyaWFibGVzIEdlbmRlciwgTWFyaXRhbF9zdGF0dXMsIEVtcF9zdGF0dXMsIGNyZWRpdF9zY29yZSwgYW1vdW50LCBlbXBfZHVyYXRpb24sIGNoZWNraW5nX2Ftb3VudCwgYW5kIGFnZSBoYXZlIG1pc3NpbmcgdmFsdWVzLiBNaXNzaW5nIG51bWVyaWNhbCB2YWx1ZXMgY2FuIGJlIHJlc29sdmVkIGJ5IGltcHV0aW5nIHRoZSBtZWFuLiBNaXNzaW5nIGNhdGVnb3JpY2FsIHZhbHVlcyBjYW4gYmUgcmVzb2x2ZWQgYnkgaW1wdXRpbmcgdGhlIG1vZGUuDQoNCiMgRGlzdHJpYnV0aW9uIG9mIEluZGl2aWR1YWwgRmVhdHVyZXMNCg0KVGhpcyBzZWN0aW9uIHdpbGwgc2hvdyB0aGUgZGlzdHJpYnV0aW9uIG9mIGVhY2ggaW5kaXZpZHVhbCBmZWF0dXJlLiBTb21lIGZlYXR1cmVzIHdpbGwgaGF2ZSBtaXNzaW5nIHZhbHVlcyBhbmQgY2FuIGJlIHJlc29sdmVkIGJ5IGltcHV0aW5nIHRoZSBtZWFuIG9yIG1vZGUuDQoNClRoZSBiZWxvdyBmaWd1cmUgc2hvd3MgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgR2VuZGVyIHZhcmlhYmxlLiBUaGVyZSBhcmUgc2lnbmlmaWNhbnRseSBtb3JlIG1hbGVzIHRoYW4gZmVtYWxlcy4NCg0KYGBge3J9DQpnZ3Bsb3QoYmFuaywgYWVzKHggPSBHZW5kZXIpKSArIA0KICANCiAgZ2VvbV9iYXIoKSArDQogIGxhYnModGl0bGUgPSAiR2VuZGVyIikNCmBgYA0KDQpUaGUgYmVsb3cgZmlndXJlIHNob3dzIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIE1hcml0YWxfc3RhdHVzIHZhcmlhYmxlLiBNYXJyaWVkIGFuZCBzaW5nbGUgcGVvcGxlIGhhdmUgc2ltaWxhciBjb3VudHMuDQoNCmBgYHtyfQ0KZ2dwbG90KGJhbmssIGFlcyh4ID0gTWFyaXRhbF9zdGF0dXMpKSArIA0KICANCiAgZ2VvbV9iYXIoKSArDQogIGxhYnModGl0bGUgPSAiTWFyaXRhbF9zdGF0dXMiKQ0KYGBgDQoNClRoZSBiZWxvdyBmaWd1cmUgc2hvd3MgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgRW1wX3N0YXR1cyB2YXJpYWJsZS4gVGhlcmUgYXJlIHNpZ25pZmljYW50bHkgbW9yZSB1bmVtcGxveWVkIHRoYW4gZW1wbG95ZWQuDQoNCmBgYHtyfQ0KZ2dwbG90KGJhbmssIGFlcyh4ID0gRW1wX3N0YXR1cykpICsgDQogIA0KICBnZW9tX2JhcigpICsNCiAgbGFicyh0aXRsZSA9ICJFbXBfc3RhdHVzIikNCmBgYA0KDQoNClRoZSBiZWxvdyBmaWd1cmUgc2hvd3MgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgY2FyIGxvYW4gdmFyaWFibGUuIFRoZXJlIGFyZSBzaWduaWZpY2FudGx5IG1vcmUgdGhhdCBkbyBub3QgaGF2ZSBhIGNhciBsb2FuIHRoYW4gdGhvc2UgdGhhdCBkby4NCg0KYGBge3J9DQpnZ3Bsb3QoYmFuaywgYWVzKHggPSBDYXJfbG9hbikpICsgDQogIA0KICBnZW9tX2JhcigpICsNCiAgbGFicyh0aXRsZSA9ICJDYXJfbG9hbiIpDQpgYGANCg0KVGhlIGJlbG93IGZpZ3VyZSBzaG93cyB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBwZXJzb25hbCBsb2FuIHZhcmlhYmxlLiBUaG9zZSB0aGF0IGhhdmUgYSBwZXJzb25hbCBsb2FuIGFuZCB0aG9zZSB0aGF0IGRvIG5vdCBoYXZlIHNpbWlsYXIgY291bnRzLg0KDQpgYGB7cn0NCmdncGxvdChiYW5rLCBhZXMoeCA9IFBlcnNvbmFsX2xvYW4pKSArIA0KICANCiAgZ2VvbV9iYXIoKSArDQogIGxhYnModGl0bGUgPSAiUGVyc29uYWxfbG9hbiIpDQpgYGANCg0KVGhlIGJlbG93IGZpZ3VyZSBzaG93cyB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBlZHVjYXRpb24gbG9hbiB2YXJpYWJsZS4gVGhlcmUgYXJlIHNpZ25pZmljYW50bHkgbW9yZSB0aGF0IGRvIG5vdCBoYXZlIGFuIGVkdWNhdGlvbiBsb2FuIHRoYW4gdGhvc2UgdGhhdCBkby4NCg0KYGBge3J9DQpnZ3Bsb3QoYmFuaywgYWVzKHggPSBFZHVjYXRpb25fbG9hbikpICsgDQogIA0KICBnZW9tX2JhcigpICsNCiAgbGFicyh0aXRsZSA9ICJFZHVjYXRpb25fbG9hbiIpDQpgYGANCg0KVGhlIGJlbG93IGZpZ3VyZSBzaG93cyB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBob21lIGxvYW4gdmFyaWFibGUuIFRoZXJlIGFyZSBzaWduaWZpY2FudGx5IG1vcmUgdGhhdCBkbyBub3QgaGF2ZSBhIGhvbWUgbG9hbiB0aGFuIHRob3NlIHRoYXQgZG8uDQoNCmBgYHtyfQ0KZ2dwbG90KGJhbmssIGFlcyh4ID0gSG9tZV9sb2FuKSkgKyANCiAgDQogIGdlb21fYmFyKCkgKw0KICBsYWJzKHRpdGxlID0gIkhvbWVfbG9hbiIpDQpgYGANCg0KVGhlIGJlbG93IGZpZ3VyZSBzaG93cyB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBjcmVkaXQgc2NvcmUgdmFyaWFibGUuIFRoZXJlIGFyZSBubyBhbGFybWluZyB0cmVuZHMgb3V0c2lkZSBvZiBhIGNvdXBsZSBhbm9tYWxpZXMuDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBiYW5rLCBhZXMoeCA9IENyZWRpdF9zY29yZSkpICsgDQogIGdlb21fYm94cGxvdCgpICsgDQogIA0KICBsYWJzKHRpdGxlID0gIkNyZWRpdF9zY29yZSIpDQpgYGANCg0KVGhlIGJlbG93IGZpZ3VyZSBzaG93cyB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBjaGVja2luZyBhbW91bnQgdmFyaWFibGUuIFRoZXJlIGFyZSBubyBhbGFybWluZyB0cmVuZHMuDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBiYW5rLCBhZXMoeCA9IENoZWNraW5nX2Ftb3VudCkpICsgDQogIGdlb21fYm94cGxvdCgpICsgDQogIA0KICBsYWJzKHRpdGxlID0gIkNoZWNraW5nX2Ftb3VudCIpDQpgYGANCg0KVGhlIGJlbG93IGZpZ3VyZSBzaG93cyB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSB0ZXJtIHZhcmlhYmxlLiBUaGVyZSBhcmUgbm8gYWxhcm1pbmcgdHJlbmRzLg0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gYmFuaywgYWVzKHggPSBUZXJtKSkgKyANCiAgZ2VvbV9ib3hwbG90KCkgKyANCiAgDQogIGxhYnModGl0bGUgPSAiVGVybSIpDQoNCmBgYA0KDQpUaGUgYmVsb3cgZmlndXJlIHNob3dzIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIGFtb3VudCB2YXJpYWJsZS4gVGhlcmUgYXJlIG5vIGFsYXJtaW5nIHRyZW5kcy4NCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IGJhbmssIGFlcyh4ID0gQW1vdW50KSkgKyANCiAgZ2VvbV9ib3hwbG90KCkgKyANCiAgDQogIGxhYnModGl0bGUgPSAiQW1vdW50IikNCmBgYA0KDQpUaGUgYmVsb3cgZmlndXJlIHNob3dzIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIFNhdmluZyBhbW91bnQgdmFyaWFibGUuIFRoZXJlIGFyZSBubyBhbGFybWluZyB0cmVuZHMuDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBiYW5rLCBhZXMoeCA9IFNhdmluZ19hbW91bnQpKSArIA0KICBnZW9tX2JveHBsb3QoKSArIA0KICANCiAgbGFicyh0aXRsZSA9ICJTYXZpbmcgYW1vdW50IikNCmBgYA0KDQpUaGUgYmVsb3cgZmlndXJlIHNob3dzIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIEVtcF9kdXJhdGlvbiB2YXJpYWJsZS4gVGhlcmUgYXJlIG5vIGFsYXJtaW5nIHRyZW5kcy4NCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IGJhbmssIGFlcyh4ID0gRW1wX2R1cmF0aW9uKSkgKyANCiAgZ2VvbV9ib3hwbG90KCkgKyANCiAgDQogIGxhYnModGl0bGUgPSAiRW1wIGR1cmF0aW9uIikNCmBgYA0KDQpUaGUgYmVsb3cgZmlndXJlIHNob3dzIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIGFnZSB2YXJpYWJsZS4gVGhlcmUgYXJlIG5vIGFsYXJtaW5nIHRyZW5kcy4NCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IGJhbmssIGFlcyh4ID0gQWdlKSkgKyANCiAgZ2VvbV9ib3hwbG90KCkgKyANCiAgDQogIGxhYnModGl0bGUgPSAiQWdlIikNCmBgYA0KDQpUaGUgYmVsb3cgZmlndXJlIHNob3dzIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIE5vX29mX2NyZWRpdF9hY2MgdmFyaWFibGUuIFRoaXMgdmFyaWFibGUgc2VlbXMgdG8gYmUgaGVhdmlseSBza2V3ZWQuDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBiYW5rLCBhZXMoeCA9IE5vX29mX2NyZWRpdF9hY2MpKSArIA0KICBnZW9tX2JveHBsb3QoKSArIA0KICANCiAgbGFicyh0aXRsZSA9ICJOb19vZl9jcmVkaXRfYWNjIikNCmBgYA0KDQojIE9uZSBDYXRlZ29yaWNhbCBGZWF0dXJlIGFuZCBPbmUgTnVtZXJpY2FsIGZlYXR1cmUgR3JhcGhzDQoNCkluIHRoaXMgc2VjdGlvbiwgd2Ugd2lsbCBzaG93IHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBvbmUgY2F0ZWdvcmljYWwgZmVhdHVyZSBhbmQgb25lIG51bWVyaWNhbCBmZWF0dXJlLg0KDQpUaGUgYmVsb3cgZmlndXJlIHNob3dzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBjcmVkaXQgc2NvcmUgYW5kIGdlbmRlci4gQmFzZWQgb24gdGhlIGdyYXBoLCB0aGUgY3JlZGl0IHNjb3JlIHJhbmdlcyBsb29rIHRvIGJlIHNpbWlsYXIgYWNyb3NzIGJvdGggZ2VuZGVycy4gVGhlcmUgYXJlIHNvbWUgYW5vbWFsaWVzIGJ1dCBJIGRvIG5vdCBiZWxpZXZlIHRoYXQgdGhleSB3aWxsIGhhdmUgYSBzaWduaWZpY2FudCBlZmZlY3Qgb24gdGhlIGFuYWx5c2lzLiBUaGVyZSBhcmUgbWlzc2luZyB2YWx1ZXMgYnV0IHRoZXkgY2FuIGJlIHJlc29sdmVkIHVzaW5nIGltcHV0YXRpb24uDQoNCmBgYHtyfQ0KZ2dwbG90KGJhbmssIGFlcyh4PUNyZWRpdF9zY29yZSwgeT1HZW5kZXIsIGZpbGw9R2VuZGVyKSkgKw0KICBnZW9tX2JveHBsb3QoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpKw0KZ2d0aXRsZSgiQ3JlZGl0IFNjb3JlIGJ5IEdlbmRlciIpDQpgYGANCg0KVGhlIGJlbG93IGZpZ3VyZSBzaG93cyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gbG9hbiBhbW91bnQgYW5kIGdlbmRlci4gQmFzZWQgb24gdGhlIGdyYXBoLCB0aGUgbG9hbiBhbW91bnQgcmFuZ2VzIGxvb2sgdG8gYmUgc2ltaWxhciBhY3Jvc3MgYm90aCBnZW5kZXJzLiBUaGVyZSBhcmUgc29tZSBhbm9tYWxpZXMgYnV0IEkgZG8gbm90IGJlbGlldmUgdGhhdCB0aGV5IHdpbGwgaGF2ZSBhIHNpZ25pZmljYW50IGVmZmVjdCBvbiB0aGUgYW5hbHlzaXMuIFRoZXJlIGFyZSBtaXNzaW5nIHZhbHVlcyBidXQgdGhleSBjYW4gYmUgcmVzb2x2ZWQgdXNpbmcgaW1wdXRhdGlvbi4NCg0KYGBge3J9DQpnZ3Bsb3QoYmFuaywgYWVzKHg9QW1vdW50LCB5PUdlbmRlciwgZmlsbD1HZW5kZXIpKSArDQogIGdlb21fYm94cGxvdCgpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikrDQpnZ3RpdGxlKCJBbW91bnQgYnkgR2VuZGVyIikNCmBgYA0KDQpUaGUgYmVsb3cgZmlndXJlIHNob3dzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBFbXBsb3ltZW50IGR1cmF0aW9uIGFuZCBnZW5kZXIuIEJhc2VkIG9uIHRoZSBncmFwaCwgaXQgc2VlbXMgbGlrZSBtYWxlcyBoYXZlIGEgbG9uZ2VyIGVtcGxveW1lbnQgZHVyYXRpb24gdGhhbiBmZW1hbGVzLiBUaGVyZSBhcmUgbWlzc2luZyB2YWx1ZXMgYnV0IHRoZXkgY2FuIGJlIHJlc29sdmVkIHVzaW5nIGltcHV0YXRpb24uDQoNCmBgYHtyfQ0KZ2dwbG90KGJhbmssIGFlcyh4PUVtcF9kdXJhdGlvbiwgeT1HZW5kZXIsIGZpbGw9R2VuZGVyKSkgKw0KICBnZW9tX2JveHBsb3QoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpKw0KZ2d0aXRsZSgiRW1wbG95bWVudCBkdXJhdGlvbiBieSBHZW5kZXIiKQ0KYGBgDQoNClRoZSBiZWxvdyBmaWd1cmUgc2hvd3MgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIEFnZSBhbmQgZ2VuZGVyLiBCYXNlZCBvbiB0aGUgZ3JhcGgsIHRoZSBBZ2UgcmFuZ2VzIGxvb2sgdG8gYmUgc2ltaWxhciBhY3Jvc3MgYm90aCBnZW5kZXJzLiBUaGVyZSBhcmUgc29tZSBhbm9tYWxpZXMgYnV0IEkgZG8gbm90IGJlbGlldmUgdGhhdCB0aGV5IHdpbGwgaGF2ZSBhIHNpZ25pZmljYW50IGVmZmVjdCBvbiB0aGUgYW5hbHlzaXMuIFRoZXJlIGFyZSBtaXNzaW5nIHZhbHVlcyBidXQgdGhleSBjYW4gYmUgcmVzb2x2ZWQgdXNpbmcgaW1wdXRhdGlvbi4NCg0KYGBge3J9DQpnZ3Bsb3QoYmFuaywgYWVzKHg9QWdlLCB5PUdlbmRlciwgZmlsbD1HZW5kZXIpKSArDQogIGdlb21fYm94cGxvdCgpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikrDQpnZ3RpdGxlKCJBZ2UgYnkgR2VuZGVyIikNCmBgYA0KDQpUaGUgYmVsb3cgZmlndXJlIHNob3dzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBtYXJpdGFsIHN0YXR1cyBhbmQgY3JlZGl0IHNjb3JlLiBCYXNlZCBvbiB0aGUgZ3JhcGgsIHRoZSBjcmVkaXQgc2NvcmUgcmFuZ2VzIGxvb2sgdG8gYmUgc2ltaWxhciBhY3Jvc3MgYm90aCBzaW5nbGUgYW5kIG1hcnJpZWQgcGVvcGxlLiBUaGVyZSBhcmUgc29tZSBhbm9tYWxpZXMgYnV0IEkgZG8gbm90IGJlbGlldmUgdGhhdCB0aGV5IHdpbGwgaGF2ZSBhIHNpZ25pZmljYW50IGVmZmVjdCBvbiB0aGUgYW5hbHlzaXMuIFRoZXJlIGFyZSBtaXNzaW5nIHZhbHVlcyBidXQgdGhleSBjYW4gYmUgcmVzb2x2ZWQgdXNpbmcgaW1wdXRhdGlvbi4NCg0KYGBge3J9DQpnZ3Bsb3QoYmFuaywgYWVzKHg9Q3JlZGl0X3Njb3JlLCB5PU1hcml0YWxfc3RhdHVzLCBmaWxsPU1hcml0YWxfc3RhdHVzKSkgKw0KICBnZW9tX2JveHBsb3QoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpKw0KZ2d0aXRsZSgiQ3JlZGl0IFNjb3JlIGJ5IE1hcml0YWwgc3RhdHVzIikNCmBgYA0KDQpUaGUgYmVsb3cgZmlndXJlIHNob3dzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBsb2FuIGFtb3VudCBhbmQgbWFyaXRhbCBzdGF0dXMuIEJhc2VkIG9uIHRoZSBncmFwaCwgdGhlIGxvYW4gYW1vdW50IHJhbmdlcyBsb29rIHRvIGJlIHNpbWlsYXIgYWNyb3NzIGJvdGggbWFyaXRhbCBzdGF0dXNlcy4gVGhlcmUgYXJlIHNvbWUgYW5vbWFsaWVzIGJ1dCBJIGRvIG5vdCBiZWxpZXZlIHRoYXQgdGhleSB3aWxsIGhhdmUgYSBzaWduaWZpY2FudCBlZmZlY3Qgb24gdGhlIGFuYWx5c2lzLiBUaGVyZSBhcmUgbWlzc2luZyB2YWx1ZXMgYnV0IHRoZXkgY2FuIGJlIHJlc29sdmVkIHVzaW5nIGltcHV0YXRpb24uDQoNCmBgYHtyfQ0KZ2dwbG90KGJhbmssIGFlcyh4PUFtb3VudCwgeT1NYXJpdGFsX3N0YXR1cywgZmlsbD1NYXJpdGFsX3N0YXR1cykpICsNCiAgZ2VvbV9ib3hwbG90KCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSsNCmdndGl0bGUoIkFtb3VudCBieSBNYXJpdGFsIHN0YXR1cyIpDQpgYGANCg0KVGhlIGJlbG93IGZpZ3VyZSBzaG93cyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gbWFyaXRhbCBzdGF0dXMgYW5kIGVtcGxveW1lbnQgZHVyYXRpb24uIEJhc2VkIG9uIHRoZSBncmFwaCwgaXQgc2VlbXMgbGlrZSBtYXJyaWVkIHBlb3BsZSBoYXZlIGxvbmdlciBlbXBsb3ltZW50IGR1cmF0aW9uIHRoYW4gc2luZ2xlIHBlb3BsZS4gVGhlcmUgYXJlIG1pc3NpbmcgdmFsdWVzIGJ1dCB0aGV5IGNhbiBiZSByZXNvbHZlZCB1c2luZyBpbXB1dGF0aW9uLg0KDQpgYGB7cn0NCmdncGxvdChiYW5rLCBhZXMoeD1FbXBfZHVyYXRpb24sIHk9TWFyaXRhbF9zdGF0dXMsIGZpbGw9TWFyaXRhbF9zdGF0dXMpKSArDQogIGdlb21fYm94cGxvdCgpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikrDQpnZ3RpdGxlKCJFbXBsb3ltZW50IGR1cmF0aW9uIGJ5IE1hcml0YWwgc3RhdHVzIikNCmBgYA0KDQpUaGUgYmVsb3cgZmlndXJlIHNob3dzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBBZ2UgYW5kIG1hcml0YWwgc3RhdHVzLiBCYXNlZCBvbiB0aGUgZ3JhcGgsIHRoZSBBZ2UgcmFuZ2VzIGxvb2sgdG8gYmUgc2ltaWxhciBhY3Jvc3MgYm90aCBtYXJpdGFsIHN0YXR1c2VzLiBUaGVyZSBhcmUgc29tZSBhbm9tYWxpZXMgYnV0IEkgZG8gbm90IGJlbGlldmUgdGhhdCB0aGV5IHdpbGwgaGF2ZSBhIHNpZ25pZmljYW50IGVmZmVjdCBvbiB0aGUgYW5hbHlzaXMuIFRoZXJlIGFyZSBtaXNzaW5nIHZhbHVlcyBidXQgdGhleSBjYW4gYmUgcmVzb2x2ZWQgdXNpbmcgaW1wdXRhdGlvbi4NCg0KYGBge3J9DQpnZ3Bsb3QoYmFuaywgYWVzKHg9QWdlLCB5PU1hcml0YWxfc3RhdHVzLCBmaWxsPU1hcml0YWxfc3RhdHVzKSkgKw0KICBnZW9tX2JveHBsb3QoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpKw0KZ2d0aXRsZSgiYWdlIGJ5IE1hcml0YWwgc3RhdHVzIikNCmBgYA0KDQpUaGUgYmVsb3cgZmlndXJlIHNob3dzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBjcmVkaXQgc2NvcmUgYW5kIGVtcGxveW1lbnQgc3RhdHVzLiBCYXNlZCBvbiB0aGUgZ3JhcGgsIHRoZSBjcmVkaXQgc2NvcmUgcmFuZ2VzIGxvb2sgdG8gYmUgc2ltaWxhciBhY3Jvc3MgYm90aCBlbXBsb3llZCBhbmQgdW5lbXBsb3llZCBwZW9wbGUuIFRoZXJlIHNlZW1zIHRvIGJlIG1vcmUgYW5vbWFsaWVzIGZvciB1bmVtcGxveWVkIHBlb3BsZSBidXQgSSBkbyBub3QgYmVsaWV2ZSB0aGF0IHRoZXkgd2lsbCBoYXZlIGEgc2lnbmlmaWNhbnQgZWZmZWN0IG9uIHRoZSBhbmFseXNpcy4gVGhlcmUgYXJlIG1pc3NpbmcgdmFsdWVzIGJ1dCB0aGV5IGNhbiBiZSByZXNvbHZlZCB1c2luZyBpbXB1dGF0aW9uLg0KDQpgYGB7cn0NCmdncGxvdChiYW5rLCBhZXMoeD1DcmVkaXRfc2NvcmUsIHk9RW1wX3N0YXR1cywgZmlsbD1FbXBfc3RhdHVzKSkgKw0KICBnZW9tX2JveHBsb3QoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpKw0KZ2d0aXRsZSgiQ3JlZGl0IFNjb3JlIGJ5IEVtcGxveW1lbnQgc3RhdHVzIikNCmBgYA0KDQpUaGUgYmVsb3cgZmlndXJlIHNob3dzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBsb2FuIGFtb3VudCBhbmQgZW1wbG95bWVudCBzdGF0dXMuIEJhc2VkIG9uIHRoZSBncmFwaCwgdGhlIGxvYW4gYW1vdW50IHJhbmdlcyBsb29rIHRvIGJlIHNpbWlsYXIgYWNyb3NzIGJvdGggZW1wbG95ZWQvdW5lbXBsb3llZC4gQWdhaW4gdGhlcmUgc2VlbXMgdG8gYmUgbW9yZSBhbm9tYWxpZXMgZm9yIHVuZW1wbG95ZWQgcGVvcGxlIHRoYW4gZW1wbG95ZWQuIFRoZXJlIGFyZSBtaXNzaW5nIHZhbHVlcyBidXQgdGhleSBjYW4gYmUgcmVzb2x2ZWQgdXNpbmcgaW1wdXRhdGlvbi4NCg0KYGBge3J9DQpnZ3Bsb3QoYmFuaywgYWVzKHg9QW1vdW50LCB5PUVtcF9zdGF0dXMsIGZpbGw9RW1wX3N0YXR1cykpICsNCiAgZ2VvbV9ib3hwbG90KCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSsNCmdndGl0bGUoIkFtb3VudCBieSBFbXBsb3ltZW50IHN0YXR1cyIpDQpgYGANCg0KVGhlIGJlbG93IGZpZ3VyZSBzaG93cyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gZW1wbG95bWVudCBkdXJhdGlvbiBhbmQgZW1wbG95bWVudCBzdGF0dXMuIEJhc2VkIG9uIHRoZSBncmFwaCwgaXQgc2VlbXMgbGlrZSB1bmVtcGxveWVkIHBlb3BsZSBoYXZlIGxvbmdlciBhbmQgbW9yZSB2YXJpZWQgZW1wbG95bWVudCBkdXJhdGlvbiB0aGFuIGVtcGxveWVkIHBlb3BsZS4gVGhlcmUgYXJlIG1pc3NpbmcgdmFsdWVzIGJ1dCB0aGV5IGNhbiBiZSByZXNvbHZlZCB1c2luZyBpbXB1dGF0aW9uLg0KDQpgYGB7cn0NCmdncGxvdChiYW5rLCBhZXMoeD1FbXBfZHVyYXRpb24sIHk9RW1wX3N0YXR1cywgZmlsbD1FbXBfc3RhdHVzKSkgKw0KICBnZW9tX2JveHBsb3QoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpKw0KZ2d0aXRsZSgiRW1wbG95bWVudCBkdXJhdGlvbiBieSBlbXBsb3ltZW50IHN0YXR1cyIpDQpgYGANCg0KVGhlIGJlbG93IGZpZ3VyZSBzaG93cyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gQWdlIGFuZCBlbXBsb3ltZW50IHN0YXR1cy4gQmFzZWQgb24gdGhlIGdyYXBoLCB0aGUgQWdlIHJhbmdlcyBsb29rIHRvIGJlIHNpbWlsYXIgYWNyb3NzIGJvdGggc3RhdHVzZXMuIFRoZXJlIGFyZSBzb21lIGFub21hbGllcyBidXQgSSBkbyBub3QgYmVsaWV2ZSB0aGF0IHRoZXkgd2lsbCBoYXZlIGEgc2lnbmlmaWNhbnQgZWZmZWN0IG9uIHRoZSBhbmFseXNpcy4gVGhlcmUgYXJlIG1pc3NpbmcgdmFsdWVzIGJ1dCB0aGV5IGNhbiBiZSByZXNvbHZlZCB1c2luZyBpbXB1dGF0aW9uLg0KDQpgYGB7cn0NCmdncGxvdChiYW5rLCBhZXMoeD1BZ2UsIHk9RW1wX3N0YXR1cywgZmlsbD1FbXBfc3RhdHVzKSkgKw0KICBnZW9tX2JveHBsb3QoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpKw0KZ2d0aXRsZSgiYWdlIGJ5IGVtcGxveW1lbnQgc3RhdHVzIikNCmBgYA0KDQpUaGUgYmVsb3cgZmlndXJlIHNob3dzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBBZ2UgYW5kIGNhciBsb2FuLiBCYXNlZCBvbiB0aGUgZ3JhcGgsIHRoZSBBZ2UgcmFuZ2VzIGxvb2sgdG8gYmUgc2ltaWxhciBhY3Jvc3MgYm90aCB0aG9zZSB3aG8gb3duIGEgY2FyIGxvYW4gYW5kIHRob3NlIHdobyBkbyBub3QuDQoNCmBgYHtyfQ0KIyBjb252ZXJ0IGNhciwgaG9tZSwgcGVyc29uYWwsIGFuZCBlZHVjYXRpb24gbG9hbnMgaW50byBjYXRlZ29yaWNhbCB0byB1c2UgZm9yIEVEQSBwdXJwb3Nlcw0KIGJhbmskQ2FyX2xvYW4gPC0gYXMuZmFjdG9yKGJhbmskQ2FyX2xvYW4pDQogYmFuayRQZXJzb25hbF9sb2FuIDwtIGFzLmZhY3RvcihiYW5rJFBlcnNvbmFsX2xvYW4pDQogYmFuayRIb21lX2xvYW4gPC0gYXMuZmFjdG9yKGJhbmskSG9tZV9sb2FuKQ0KIGJhbmskRWR1Y2F0aW9uX2xvYW4gPC0gYXMuZmFjdG9yKGJhbmskRWR1Y2F0aW9uX2xvYW4pDQogDQpnZ3Bsb3QoYmFuaywgYWVzKHg9QWdlLCB5PUNhcl9sb2FuLCBmaWxsPUNhcl9sb2FuKSkgKw0KICBnZW9tX2JveHBsb3QoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpKw0KZ2d0aXRsZSgiYWdlIGJ5IGNhciBsb2FuIikNCmBgYA0KDQpUaGUgYmVsb3cgZmlndXJlIHNob3dzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBBZ2UgYW5kIHBlcnNvbmFsIGxvYW4uIEJhc2VkIG9uIHRoZSBncmFwaCwgdGhlIEFnZSByYW5nZXMgbG9vayB0byBiZSBzaW1pbGFyIGFjcm9zcyBhbGwgdGhvc2UgdGhhdCBoYXZlIGEgcGVyc29uYWwgbG9hbiBvciBub3QuDQoNCmBgYHtyfQ0KZ2dwbG90KGJhbmssIGFlcyh4PUFnZSwgeT1QZXJzb25hbF9sb2FuLCBmaWxsPVBlcnNvbmFsX2xvYW4pKSArDQogIGdlb21fYm94cGxvdCgpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikrDQpnZ3RpdGxlKCJhZ2UgYnkgcGVyc29uYWxfbG9hbiIpDQpgYGANCg0KVGhlIGJlbG93IGZpZ3VyZSBzaG93cyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gQWdlIGFuZCBob21lIGxvYW4uIEJhc2VkIG9uIHRoZSBncmFwaCwgdGhlIEFnZSByYW5nZXMgbG9vayB0byBiZSBzaW1pbGFyIGFjcm9zcyBhbGwgdGhvc2UgdGhhdCBoYXZlIGEgaG9tZSBsb2FuIG9yIG5vdC4NCg0KYGBge3J9DQpnZ3Bsb3QoYmFuaywgYWVzKHg9QWdlLCB5PUhvbWVfbG9hbiwgZmlsbD1Ib21lX2xvYW4pKSArDQogIGdlb21fYm94cGxvdCgpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikrDQpnZ3RpdGxlKCJhZ2UgYnkgaG9tZV9sb2FuIikNCmBgYA0KDQpUaGUgYmVsb3cgZmlndXJlIHNob3dzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBBZ2UgYW5kIGVkdWNhdGlvbiBsb2FuLiBCYXNlZCBvbiB0aGUgZ3JhcGgsIGl0IHNlZW1zIGxpa2UgeW91bmdlciBwZW9wbGUgaGF2ZSBhbiBlZHVjYXRpb24gbG9hbiBhbmQgb2xkZXIgcGVvcGxlIGRvIG5vdC4NCmBgYHtyfQ0KZ2dwbG90KGJhbmssIGFlcyh4PUFnZSwgeT1FZHVjYXRpb25fbG9hbiwgZmlsbD1FZHVjYXRpb25fbG9hbikpICsNCiAgZ2VvbV9ib3hwbG90KCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSsNCmdndGl0bGUoImFnZSBieSBlZHVjYXRpb24gbG9hbiIpDQpgYGANCg0KIyBUd28gbnVtZXJpY2FsIGZlYXR1cmUgdmFyaWFibGVzIGdyYXBocw0KDQpOZXh0LCB3ZSB3aWxsIGV4YW1pbmUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHR3byBudW1lcmljYWwgZmVhdHVyZXMuDQoNClRoZSBiZWxvdyBncmFwaCBzaG93cyBlbXBsb3ltZW50IGR1cmF0aW9uIGFuZCBjcmVkaXQgc2NvcmUuIEJhc2VkIG9uIHRoZSBncmFwaCwgaXQgc2VlbXMgbGlrZSByZWdhcmRsZXNzIG9mIHRoZSBlbXBsb3ltZW50IGR1cmF0aW9uLCB0aGUgbWFqb3JpdHkgb2YgdGhlIGNyZWRpdCBzY29yZXMgc2VlbSB0byBmYWxsIGluIHRoZSA3MDAtOTAwIHJhbmdlLg0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gYmFuaywgYWVzKHggPSBDcmVkaXRfc2NvcmUsIHkgPSBFbXBfZHVyYXRpb24pKSArDQogIGdlb21fcG9pbnQoKSArIA0KICBnZ3RpdGxlKCJFbXBsb3ltZW50IER1cmF0aW9uIHZzIENyZWRpdCBTY29yZSIpDQpgYGANCg0KVGhlIGJlbG93IGdyYXBoIHNob3dzIGVtcGxveW1lbnQgZHVyYXRpb24gYW5kIGxvYW4gYW1vdW50LiBUaGVyZSBkb2VzIG5vdCBzZWVtIHRvIGJlIGFueSBwYXR0ZXJucyBiYXNlZCBvbiB0aGlzIGdyYXBoLg0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gYmFuaywgYWVzKHggPSBBbW91bnQsIHkgPSBFbXBfZHVyYXRpb24pKSArDQogIGdlb21fcG9pbnQoKSArIA0KICBnZ3RpdGxlKCJFbXBsb3ltZW50IER1cmF0aW9uIHZzIExvYW4gQW1vdW50IikNCmBgYA0KDQpUaGUgYmVsb3cgZ3JhcGggc2hvd3MgZW1wbG95bWVudCBkdXJhdGlvbiBhbmQgYWdlLiBUaGVyZSBkb2VzIG5vdCBzZWVtIHRvIGJlIGFueSBwYXR0ZXJucyBiYXNlZCBvbiB0aGlzIGdyYXBoLg0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gYmFuaywgYWVzKHggPSBBZ2UsIHkgPSBFbXBfZHVyYXRpb24pKSArDQogIGdlb21fcG9pbnQoKSArIA0KICBnZ3RpdGxlKCJFbXBsb3ltZW50IER1cmF0aW9uIHZzIEFnZSIpDQpgYGANCg0KVGhlIGJlbG93IGdyYXBoIHNob3dzIGFnZSBhbmQgQ3JlZGl0IHNjb3JlLiBBZ2FpbiwgaXQgc2VlbXMgbGlrZSByZWdhcmRsZXNzIG9mIGFnZSwgbW9zdCBvZiB0aGUgY3JlZGl0IHNjb3JlcyBzZWVtIHRvIGZhbGwgaW4gdGhhdCA3MDAtOTAwIHJhbmdlLg0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gYmFuaywgYWVzKHggPSBBZ2UsIHkgPSBDcmVkaXRfc2NvcmUpKSArDQogIGdlb21fcG9pbnQoKSArIA0KICBnZ3RpdGxlKCJBZ2UgdnMgY3JlZGl0IHNjb3JlIikNCmBgYA0KDQpUaGUgYmVsb3cgZ3JhcGggc2hvd3MgY2hlY2tpbmcgYW1vdW50IGFuZCBzYXZpbmcgYW1vdW50LiBUaGVyZSBkb2VzIG5vdCBzZWVtIHRvIGJlIGFueSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZXNlIHR3byB2YXJpYWJsZXMuDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBiYW5rLCBhZXMoeCA9IENoZWNraW5nX2Ftb3VudCwgeSA9IFNhdmluZ19hbW91bnQpKSArDQogIGdlb21fcG9pbnQoKSArIA0KICBnZ3RpdGxlKCJDaGVja2luZyBhbW91bnQgdnMgc2F2aW5ncyBBbW91bnQiKQ0KYGBgDQoNClRoZSBiZWxvdyBncmFwaCBzaG93cyBhZ2UgYW5kIGxvYW4gYW1vdW50LiBJdCBzZWVtcyBsaWtlIHJlZ2FyZGxlc3Mgb2YgYWdlLCBtb3N0IG9mIHRoZSBsb2FuIGFtb3VudHMgc2VlbSB0byBmYWxsIGluIGEgY2VydGFpbiByYW5nZS4NCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IGJhbmssIGFlcyh4ID0gQWdlLCB5ID0gQW1vdW50KSkgKw0KICBnZW9tX3BvaW50KCkgKyANCiAgZ2d0aXRsZSgiYWdlIHZzIExvYW4gQW1vdW50IikNCmBgYA0KDQpUaGUgYmVsb3cgZ3JhcGggc2hvd3MgY3JlZGl0IHNjb3JlIGFuZCBsb2FuIGFtb3VudC4gSXQgc2VlbXMgbGlrZSBtb3N0IG9mIHRoZSBwb2ludHMgYXJlIGNsdW1wZWQgdG9nZXRoZXIuDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBiYW5rLCBhZXMoeCA9IENyZWRpdF9zY29yZSwgeSA9IEFtb3VudCkpICsNCiAgZ2VvbV9wb2ludCgpICsgDQogIGdndGl0bGUoImNyZWRpdCBzY29yZSB2cyBMb2FuIEFtb3VudCIpDQpgYGANCg0KDQojIFR3byBjYXRlZ29yaWNhbCBmZWF0dXJlIHZhcmlhYmxlcyBncmFwaHMNCg0KVGhpcyBzZWN0aW9uIHNob3dzIHRoZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gdHdvIGNhdGVnb3JpY2FsIGZlYXR1cmVzLg0KDQpUaGUgYmVsb3cgZ3JhcGggc2hvd3MgR2VuZGVyIGFuZCBFbXBsb3ltZW50IHN0YXR1cy4gSXQgc2VlbXMgbGlrZSB0aGUgYW1vdW50IG9mIGVtcGxveWVkIGFuZCB1bmVtcGxveWVkIGZlbWFsZXMgYXJlIHNpbWlsYXIgYnV0IHRoZXJlIGFyZSBzaWduaWZpY2FudGx5IG1vcmUgdW5lbXBsb3llZCBtYWxlcyB0aGFuIGVtcGxveWVkLg0KDQpgYGB7cn0NCmdncGxvdChiYW5rLCBhZXMoR2VuZGVyLCAuLmNvdW50Li4pKSArIGdlb21fYmFyKGFlcyhmaWxsID0gRW1wX3N0YXR1cyksIHBvc2l0aW9uID0gImRvZGdlIikrZ2d0aXRsZSgiZ2VuZGVyIHZzIGVtcGxveW1lbnQgc3RhdHVzIikNCmBgYA0KDQpUaGUgYmVsb3cgZ3JhcGggc2hvd3MgR2VuZGVyIGFuZCBtYXJpdGFsIHN0YXR1cy4gSXQgc2VlbXMgbGlrZSBhbGwgZmVtYWxlcyBhcmUgc2luZ2xlIGFuZCB0aGVyZSBhcmUgc2lnbmlmaWNhbnRseSBtb3JlIG1hcnJpZWQgbWFsZXMgdGhhbiBzaW5nbGUuDQoNCmBgYHtyfQ0KZ2dwbG90KGJhbmssIGFlcyhHZW5kZXIsIC4uY291bnQuLikpICsgZ2VvbV9iYXIoYWVzKGZpbGwgPSBNYXJpdGFsX3N0YXR1cyksIHBvc2l0aW9uID0gImRvZGdlIikrZ2d0aXRsZSgiZ2VuZGVyIHZzIG1hcml0YWwgc3RhdHVzIikNCmBgYA0KDQpUaGUgYmVsb3cgZ3JhcGggc2hvd3MgZW1wbG95bWVudCBzdGF0dXMgYW5kIG1hcml0YWwgc3RhdHVzLiBJdCBzZWVtcyBsaWtlIHRoZSBhbW91bnQgb2YgZW1wbG95ZWQgYW5kIHVuZW1wbG95ZWQgcGVvcGxlIGFyZSByZWxhdGl2ZWx5IHNpbWlsYXIgYnV0IGZvciBtYXJyaWVkIHBlb3BsZSwgdGhlcmUgYXJlIHNpZ25pZmljYW50bHkgbW9yZSB3aG8gYXJlIHVuZW1wbG95ZWQuDQoNCmBgYHtyfQ0KZ2dwbG90KGJhbmssIGFlcyhNYXJpdGFsX3N0YXR1cywgLi5jb3VudC4uKSkgKyBnZW9tX2JhcihhZXMoZmlsbCA9IEVtcF9zdGF0dXMpLCBwb3NpdGlvbiA9ICJkb2RnZSIpK2dndGl0bGUoIm1hcml0YWwgc3RhdHVzIHZzIGVucGxveW1lbnQgc3RhdHVzIikNCmBgYA0KDQpUaGUgYmVsb3cgZ3JhcGggc2hvd3MgZ2VuZGVyIGFuZCBjYXIgbG9hbi4gSXQgc2VlbXMgbGlrZSBmb3IgYm90aCBtYWxlcyBhbmQgZmVtYWxlcywgdGhlcmUgYXJlIHNpZ25pZmljYW50bHkgbW9yZSB0aGF0IGRvIG5vdCBoYXZlIGNhciBsb2FucyB0aGFuIHRob3NlIHRoYXQgZG8uDQoNCmBgYHtyfQ0KZ2dwbG90KGJhbmssIGFlcyhHZW5kZXIsIC4uY291bnQuLikpICsgZ2VvbV9iYXIoYWVzKGZpbGwgPSBDYXJfbG9hbiksIHBvc2l0aW9uID0gImRvZGdlIikrZ2d0aXRsZSgiZ2VuZGVyIHZzIGNhciBsb2FuIikNCmBgYA0KDQpUaGUgYmVsb3cgZ3JhcGggc2hvd3MgZ2VuZGVyIGFuZCBlZHVjYXRpb24gbG9hbi4gSXQgc2VlbXMgbGlrZSBmb3IgYm90aCBtYWxlcyBhbmQgZmVtYWxlcywgdGhlcmUgYXJlIHNpZ25pZmljYW50bHkgbW9yZSB0aGF0IGRvIG5vdCBoYXZlIGVkdWNhdGlvbiBsb2FucyB0aGFuIHRob3NlIHRoYXQgZG8uDQoNCmBgYHtyfQ0KZ2dwbG90KGJhbmssIGFlcyhHZW5kZXIsIC4uY291bnQuLikpICsgZ2VvbV9iYXIoYWVzKGZpbGwgPSBFZHVjYXRpb25fbG9hbiksIHBvc2l0aW9uID0gImRvZGdlIikrZ2d0aXRsZSgiR2VuZGVyIHZzIGVkdWNhdGlvbiBMb2FuIikNCmBgYA0KDQpUaGUgYmVsb3cgZ3JhcGggc2hvd3MgZ2VuZGVyIGFuZCBwZXJzb25hbCBsb2FuLiBJdCBzZWVtcyBsaWtlIGZvciBib3RoIG1hbGVzIGFuZCBmZW1hbGVzLCB0aGUgYW1vdW50cyB0aGF0IHdobyBoYXZlIHBlcnNvbmFsIGxvYW5zIGFuZCB0aG9zZSB0aGF0IGRvIG5vdCBhcmUgcmVsYXRpdmVseSBzaW1pbGFyLg0KDQpgYGB7cn0NCmdncGxvdChiYW5rLCBhZXMoR2VuZGVyLCAuLmNvdW50Li4pKSArIGdlb21fYmFyKGFlcyhmaWxsID0gUGVyc29uYWxfbG9hbiksIHBvc2l0aW9uID0gImRvZGdlIikrZ2d0aXRsZSgiR2VuZGVyIHZzIHBlcnNvbmFsIExvYW4iKQ0KYGBgDQoNClRoZSBiZWxvdyBncmFwaCBzaG93cyBnZW5kZXIgYW5kIGhvbWUgbG9hbi4gSXQgc2VlbXMgbGlrZSBmb3IgYm90aCBtYWxlcyBhbmQgZmVtYWxlcywgdGhlcmUgYXJlIHNpZ25pZmljYW50bHkgbW9yZSB0aGF0IGRvIG5vdCBoYXZlIGhvbWUgbG9hbnMgdGhhbiB0aG9zZSB0aGF0IGRvLg0KDQpgYGB7cn0NCmdncGxvdChiYW5rLCBhZXMoR2VuZGVyLCAuLmNvdW50Li4pKSArIGdlb21fYmFyKGFlcyhmaWxsID0gSG9tZV9sb2FuKSwgcG9zaXRpb24gPSAiZG9kZ2UiKStnZ3RpdGxlKCJHZW5kZXIgdnMgaG9tZSBMb2FuIikNCg0KYGBgDQo=