1 Introduction

This report details an Exploratory Data Analysis (EDA) and perform feature engineering on the bank loan defaults dataset.

1.1 Problem Statements and Objectives

Based on the dataset, we aim to address two primary practical questions:

  1. Classification Problem: What are the key characteristics of a loan applicant that influence their likelihood of defaulting on a loan?

    • Analytical Question: Can we build a model to predict whether a customer will Default (1) or not Default (0)?
  2. Regression Problem: What customer and loan characteristics are associated with the total loan Amount requested?

    • Analytical Question: Can we build a model to predict the loan Amount a customer will request?

2 Data Description

2.1 Data Source and Collection

The data is from the BankLoanDefaultDataset.csv file. It is a dataset containing information on 1,000 loan applicants.

SOURCE: Book - Applied Analytics through Case Studies Using SAS and R, Deepti Gupta by APress, ISBN - 978-1-4842-3525-6

2.2 Dataset Overview

The dataset contains 1,000 observations and 16 variables. We will first load the data and inspect its structure.

# load dataset
setwd("/Users/jeffery/Library/Mobile Documents/com~apple~CloudDocs/Documents/Documents - jMacP/WCUPA/Classes/Fall 2025/STA551/Homework/Data")
loan_data <- read.csv("BankLoanDefaultDataset.csv")

# set dimensions for displaying variable definitions
cat("Dimensions:", dim(loan_data)[1], "rows and", dim(loan_data)[2], "columns\n")
Dimensions: 1000 rows and 16 columns
str(loan_data)
'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 ...

2.3 Variables

The dataset includes a target variable, Default, and 15 predictor variables.

Variable Name Description
Default Target Variable: 1 for default, 0 for non-default
Checking_amount Amount in the checking account
Term Loan term in months
Credit_score Applicant’s credit score
Gender Applicant’s gender (Male/Female)
Marital_status Applicant’s marital status (Single/Married)
Car_loan 1 if applicant has a car loan, 0 otherwise
Personal_loan 1 if applicant has a personal loan, 0 otherwise
Home_loan 1 if applicant has a home loan, 0 otherwise
Education_loan 1 if applicant has an education loan, 0 otherwise
Emp_status Employment status (Employed/Unemployed)
Amount The loan amount requested
Saving_amount Amount in the savings account
Emp_duration Employment duration in months
Age Applicant’s age in years
No_of_credit_acc Number of credit accounts

3 Exploratory Data Analysis and Feature Engineering

We will now perform EDA to clean the data, show variable relationships and prepare for modeling.

3.1 Data Cleaning

3.1.1 Missing Values and Duplicates

First we check for any missing values or duplicated rows.

# check for missing values
cat("Total missing values:", sum(is.na(loan_data)), "\n")
Total missing values: 0 
# check for duplicated rows
cat("Total duplicated rows:", sum(duplicated(loan_data)), "\n")
Total duplicated rows: 0 

The data is clean with no missing values or duplicate entries.

3.1.2 Inspecting Data Issues

The Checking_amount column has negative values which likely represent overdrafts. To simplify, we set negative values to 0.

# Show summary to identify the issue
summary(loan_data$Checking_amount)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 -665.0   164.8   351.5   362.4   553.5  1319.0 
# Create a copy to modify
loan_data_cleaned <- loan_data
# Use base R indexing to find negative values and set them to 0
loan_data_cleaned$Checking_amount[loan_data_cleaned$Checking_amount < 0] <- 0

cat("\nSummary of Checking_amount after correction:\n")

Summary of Checking_amount after correction:
summary(loan_data_cleaned$Checking_amount)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
    0.0   164.8   351.5   377.4   553.5  1319.0 

3.2 Individual Variable Analysis

We will visualize the distribution of individual variables using basic plots.

3.2.1 Numerical Variable Distributions

# Set up a 2x2 plotting area
par(mfrow = c(2, 2))

# Basic histograms
hist(loan_data_cleaned$Credit_score, main = "Distribution of Credit Score", xlab = "Credit Score", col = "lightblue")
hist(loan_data_cleaned$Age, main = "Distribution of Age", xlab = "Age (years)", col = "green")
hist(loan_data_cleaned$Amount, main = "Distribution of Loan Amount", xlab = "Amount", col = "pink")
hist(loan_data_cleaned$Saving_amount, main = "Distribution of Saving Amount", xlab = "Saving Amount", col = "yellow")
Distributions of Key Numerical Variables

Distributions of Key Numerical Variables

# Reset plotting area to default
par(mfrow = c(1, 1))

Observations: Credit_score and Age are approximately normally distributed. Financial variables like Amount and Saving_amount are skewed to the right.

3.2.2 Categorical Variable Distributions

# Set up a 2x2 plotting area
par(mfrow = c(2, 2))

# Basic bar plots
barplot(table(loan_data_cleaned$Default), main = "Loan Default Counts", col=c("darkgreen", "darkred"))
barplot(table(loan_data_cleaned$Gender), main = "Gender Distribution", col=c("pink", "lightblue"))
barplot(table(loan_data_cleaned$Marital_status), main = "Marital Status", col=c("orange", "purple"))
barplot(table(loan_data_cleaned$Emp_status), main = "Employment Status", col=c("gray", "brown"))
Distributions of Categorical & Target Variables

Distributions of Categorical & Target Variables

# Reset plotting area
par(mfrow = c(1, 1))

Observations: There are more non-defaulters (0) than defaulters (1).

3.3 Relationships between Variables

Now we explore relationships between variables using simple comparisons.

3.3.1 Relationship with Default

We use boxplots to compare numerical variables between the default and non-default applicants.

# Set up a 1x2 plotting area
par(mfrow = c(1, 2))

# basic boxplots
boxplot(Credit_score ~ Default, data = loan_data_cleaned,
        main = "Credit Score by Default",
        xlab = "Default (0=No, 1=Yes)", ylab = "Credit Score",
        col = c("darkgreen", "darkred"))

boxplot(Amount ~ Default, data = loan_data_cleaned,
        main = "Loan Amount by Default",
        xlab = "Default (0=No, 1=Yes)", ylab = "Loan Amount",
        col = c("darkgreen", "darkred"))
Credit Score and Loan Amount by Default Status

Credit Score and Loan Amount by Default Status

# Reset plotting area
par(mfrow = c(1, 1))

Observations: Customers who defaulted tend to have lower credit scores.

3.3.2 Relationship with Amount

To explore predictors for the regression problem, we can see how Amount relates to categorical variables.

# Set up a 1x2 plotting area
par(mfrow = c(1, 2))

# boxplots comparing Amount against categorical variables
boxplot(Amount ~ Emp_status, data = loan_data_cleaned,
        main = "Loan Amount by Employment Status",
        xlab = "Employment Status", ylab = "Loan Amount",
        col = c("gray", "brown"))

boxplot(Amount ~ Marital_status, data = loan_data_cleaned,
        main = "Loan Amount by Marital Status",
        xlab = "Marital Status", ylab = "Loan Amount",
        col = c("orange", "purple"))
Loan Amount by Employment and Marital Status

Loan Amount by Employment and Marital Status

# Reset plotting area
par(mfrow = c(1, 1))

Observations: The requested loan amount does not appear to differ significantly between these groups, suggesting they may not be strong predictors on their own for the regression problem.


4 Creating the Analytical Dataset

We will now perform feature engineering to create the final dataset for modeling.

Steps:

  1. Convert Categorical Variables: Gender, Marital_status, and Emp_status will be converted into factors, then into numerical dummy variables.
  2. Standardize Numerical Variables: We will scale numerical predictors to have a mean of 0 and a standard deviation of 1.
# Start with the cleaned data
analytical_data <- loan_data_cleaned

# 1. Convert character columns to factors
analytical_data$Gender <- as.factor(analytical_data$Gender)
analytical_data$Marital_status <- as.factor(analytical_data$Marital_status)
analytical_data$Emp_status <- as.factor(analytical_data$Emp_status)

# 2. Identify numeric predictors to be scaled
vars_to_scale <- c("Checking_amount", "Term", "Credit_score", "Amount",
                   "Saving_amount", "Emp_duration", "Age", "No_of_credit_acc")
scaled_data <- scale(analytical_data[, vars_to_scale])
colnames(scaled_data) <- paste0(vars_to_scale, "_scaled") # Add suffix to scaled columns

# 3. One-hot encode categorical variables using model.matrix
dummy_vars <- model.matrix(~ Gender + Marital_status + Emp_status - 1, data = analytical_data)

# 4. Combine everything into the final analytical dataset
binary_vars <- analytical_data[, c("Car_loan", "Personal_loan", "Home_loan", "Education_loan", "Default")]
analytical_data_final <- cbind(scaled_data, dummy_vars, binary_vars)

# Display the first few rows and structure of the final dataset
cat("First 6 rows of the final analytical dataset:\n")
First 6 rows of the final analytical dataset:
head(as.data.frame(analytical_data_final))
  Checking_amount_scaled Term_scaled Credit_score_scaled Amount_scaled
1              2.2191098  -0.8686751          0.45805485     1.0378255
2              0.2930295  -0.8686751          0.67725070    -0.8885616
3             -0.7972046  -1.1772630         -0.05770008     1.5022517
4             -0.2811605   2.2172044         -0.30268368     1.9143481
5             -1.1424454   1.9086164         -1.26972418    -0.1134279
6              2.5207412   0.6742647          0.87065880    -2.4322878
  Saving_amount_scaled Emp_duration_scaled Age_scaled No_of_credit_acc_scaled
1            0.8120577          -0.9901873  1.6591037              -0.9355765
2            1.2390938          -0.6459033  1.1704853              -0.9355765
3           -0.2540600          -0.1692024  0.6818669              -0.9355765
4           -2.1506893          -1.3079880 -0.5396790              -0.9355765
5           -0.9196473          -1.2020544 -0.2953698              -0.9355765
6            0.3025595          -0.9901873  0.1932486              -0.3304170
  GenderFemale GenderMale Marital_statusSingle Emp_statusunemployed Car_loan
1            1          0                    1                    0        1
2            1          0                    1                    0        1
3            1          0                    1                    0        0
4            1          0                    1                    0        0
5            1          0                    1                    1        0
6            0          1                    0                    0        1
  Personal_loan Home_loan Education_loan Default
1             0         0              0       0
2             0         0              0       0
3             1         0              0       0
4             0         0              1       1
5             0         0              1       1
6             0         0              0       0

5 Wrapping Feature Engineering Code

To make these steps reusable, we can wrap them in a function.

create_analytical_features <- function(raw_data) {
  # Step 1: Clean data
  data_cleaned <- raw_data
  data_cleaned$Checking_amount[data_cleaned$Checking_amount < 0] <- 0
  
  # Step 2: Convert to factors
  data_cleaned$Gender <- as.factor(data_cleaned$Gender)
  data_cleaned$Marital_status <- as.factor(data_cleaned$Marital_status)
  data_cleaned$Emp_status <- as.factor(data_cleaned$Emp_status)
  
  # Step 3: Scale numerical predictors
  vars_to_scale <- c("Checking_amount", "Term", "Credit_score", "Amount",
                     "Saving_amount", "Emp_duration", "Age", "No_of_credit_acc")
  scaled_data <- scale(data_cleaned[, vars_to_scale])
  colnames(scaled_data) <- paste0(vars_to_scale, "_scaled")
  
  # Step 4: Create dummy variables
  dummy_vars <- model.matrix(~ Gender + Marital_status + Emp_status - 1, data = data_cleaned)
  
  # Step 5: Combine all parts
  binary_vars <- data_cleaned[, c("Car_loan", "Personal_loan", "Home_loan", "Education_loan", "Default")]
  final_data <- cbind(scaled_data, dummy_vars, binary_vars)
  
  return(as.data.frame(final_data))
}

# Example of using the function
analytical_data_from_function <- create_analytical_features(loan_data)
cat("First 3 rows of data processed by the function:\n")
First 3 rows of data processed by the function:
head(analytical_data_from_function, 3)
  Checking_amount_scaled Term_scaled Credit_score_scaled Amount_scaled
1              2.2191098  -0.8686751          0.45805485     1.0378255
2              0.2930295  -0.8686751          0.67725070    -0.8885616
3             -0.7972046  -1.1772630         -0.05770008     1.5022517
  Saving_amount_scaled Emp_duration_scaled Age_scaled No_of_credit_acc_scaled
1            0.8120577          -0.9901873  1.6591037              -0.9355765
2            1.2390938          -0.6459033  1.1704853              -0.9355765
3           -0.2540600          -0.1692024  0.6818669              -0.9355765
  GenderFemale GenderMale Marital_statusSingle Emp_statusunemployed Car_loan
1            1          0                    1                    0        1
2            1          0                    1                    0        1
3            1          0                    1                    0        0
  Personal_loan Home_loan Education_loan Default
1             0         0              0       0
2             0         0              0       0
3             1         0              0       0

6 Conclusion and Next Steps

This concludes our analysis of the bank loan defaults dataset. Key findings include the importance of Credit_score in predicting defaults and the nature of the Default variable. We performed feature engineering to scale numerical predictors and encode categorical variables, resulting in a clean dataset ready for part II. The entire process was wrapped in a function to ensure it can be reused consistently. The project is now prepared for Part II which will focus on building and evaluating predictive models.

LS0tCnRpdGxlOiAnUHJvamVjdCBPbmU6IEVEQSBhbmQgRmVhdHVyZSBFbmdpbmVlcmluZyBmb3IgTG9hbiBEZWZhdWx0IFByZWRpY3Rpb24nCmF1dGhvcjogJ0plZmZlcnkgRGVsdmEnCmRhdGU6ICJPY3RvYmVyIDEsIDIwMjUiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgICB0b2NfZGVwdGg6IDQKICAgIGZpZ193aWR0aDogOAogICAgZmlnX2hlaWdodDogNQogICAgZmlnX2NhcHRpb246IHllcwogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRvY19jb2xsYXBzZWQ6IHllcwogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKICAgIHNtb290aF9zY3JvbGw6IHllcwogICAgdGhlbWU6IGx1bWVuCiAgICBoaWdobGlnaHQ6IHRhbmdvCi0tLQoKYGBge2NzcywgZWNobyA9IEZBTFNFfQpoMS50aXRsZSB7CiAgZm9udC1zaXplOiAyNHB4OwogIGZvbnQtd2VpZ2h0OiBib2xkOwogIGNvbG9yOiBEYXJrUmVkOwogIHRleHQtYWxpZ246IGNlbnRlcjsKfQpoNC5hdXRob3IsIGg0LmRhdGUgewogIGZvbnQtc2l6ZTogMThweDsKICBmb250LXdlaWdodDogYm9sZDsKICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICBjb2xvcjogRGFya0JsdWU7CiAgdGV4dC1hbGlnbjogY2VudGVyOwp9CmgxIHsKICAgIGZvbnQtc2l6ZTogMjBweDsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogZGFya3JlZDsKICAgIHRleHQtYWxpZ246IGNlbnRlcjsKfQpoMiB7CiAgICBmb250LXNpemU6IDE4cHg7CiAgICBmb250LXdlaWdodDogYm9sZDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IG5hdnk7CiAgICB0ZXh0LWFsaWduOiBsZWZ0Owp9CmgzIHsKICAgIGZvbnQtc2l6ZTogMTZweDsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogbmF2eTsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KLmhlYWRlci1zZWN0aW9uLW51bWJlcjo6YWZ0ZXIgewogIGNvbnRlbnQ6ICIuIjsKfQpgYGAKCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQppZiAoIXJlcXVpcmUoImtuaXRyIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQogICBsaWJyYXJ5KGtuaXRyKQp9Cgprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHRzID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIGNvbW1lbnQgPSBOQQogICAgICAgICAgICAgICAgICAgICAgKQpgYGAKCiMgSW50cm9kdWN0aW9uCgpUaGlzIHJlcG9ydCBkZXRhaWxzIGFuIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMgKEVEQSkgYW5kIHBlcmZvcm0gZmVhdHVyZSBlbmdpbmVlcmluZyBvbiB0aGUgYmFuayBsb2FuIGRlZmF1bHRzIGRhdGFzZXQuCgojIyBQcm9ibGVtIFN0YXRlbWVudHMgYW5kIE9iamVjdGl2ZXMKCkJhc2VkIG9uIHRoZSBkYXRhc2V0LCB3ZSBhaW0gdG8gYWRkcmVzcyB0d28gcHJpbWFyeSBwcmFjdGljYWwgcXVlc3Rpb25zOgoKMS4gICoqQ2xhc3NpZmljYXRpb24gUHJvYmxlbToqKiBXaGF0IGFyZSB0aGUga2V5IGNoYXJhY3RlcmlzdGljcyBvZiBhIGxvYW4gYXBwbGljYW50IHRoYXQgaW5mbHVlbmNlIHRoZWlyIGxpa2VsaWhvb2Qgb2YgZGVmYXVsdGluZyBvbiBhIGxvYW4/CgogICAgICAqICoqQW5hbHl0aWNhbCBRdWVzdGlvbjoqKiBDYW4gd2UgYnVpbGQgYSAgbW9kZWwgdG8gIHByZWRpY3Qgd2hldGhlciBhIGN1c3RvbWVyIHdpbGwgYERlZmF1bHRgICgxKSBvciBub3QgYERlZmF1bHRgICgwKT8KCjIuICAqKlJlZ3Jlc3Npb24gUHJvYmxlbToqKiBXaGF0IGN1c3RvbWVyIGFuZCBsb2FuIGNoYXJhY3RlcmlzdGljcyBhcmUgYXNzb2NpYXRlZCB3aXRoIHRoZSB0b3RhbCBsb2FuIGBBbW91bnRgIHJlcXVlc3RlZD8KCiAgICAgICogKipBbmFseXRpY2FsIFF1ZXN0aW9uOioqIENhbiB3ZSBidWlsZCBhIG1vZGVsIHRvIHByZWRpY3QgdGhlIGxvYW4gYEFtb3VudGAgYSBjdXN0b21lciB3aWxsIHJlcXVlc3Q/CgotLS0tLQoKIyBEYXRhIERlc2NyaXB0aW9uCgojIyBEYXRhIFNvdXJjZSBhbmQgQ29sbGVjdGlvbgoKVGhlIGRhdGEgaXMgZnJvbSB0aGUgYEJhbmtMb2FuRGVmYXVsdERhdGFzZXQuY3N2YCBmaWxlLiBJdCBpcyBhIGRhdGFzZXQgY29udGFpbmluZyBpbmZvcm1hdGlvbiBvbiAxLDAwMCBsb2FuIGFwcGxpY2FudHMuCgpTT1VSQ0U6IEJvb2sgLSBBcHBsaWVkIEFuYWx5dGljcyB0aHJvdWdoIENhc2UgU3R1ZGllcyBVc2luZyBTQVMgYW5kIFIsIERlZXB0aSBHdXB0YSBieSBBUHJlc3MsIElTQk4gLSA5NzgtMS00ODQyLTM1MjUtNgoKIyMgRGF0YXNldCBPdmVydmlldwoKVGhlIGRhdGFzZXQgY29udGFpbnMgMSwwMDAgb2JzZXJ2YXRpb25zIGFuZCAxNiB2YXJpYWJsZXMuIFdlIHdpbGwgZmlyc3QgbG9hZCB0aGUgZGF0YSBhbmQgaW5zcGVjdCBpdHMgc3RydWN0dXJlLgoKYGBge3IgbG9hZC1hbmQtaW5zcGVjdC1kYXRhfQojIGxvYWQgZGF0YXNldApzZXR3ZCgiL1VzZXJzL2plZmZlcnkvTGlicmFyeS9Nb2JpbGUgRG9jdW1lbnRzL2NvbX5hcHBsZX5DbG91ZERvY3MvRG9jdW1lbnRzL0RvY3VtZW50cyAtIGpNYWNQL1dDVVBBL0NsYXNzZXMvRmFsbCAyMDI1L1NUQTU1MS9Ib21ld29yay9EYXRhIikKbG9hbl9kYXRhIDwtIHJlYWQuY3N2KCJCYW5rTG9hbkRlZmF1bHREYXRhc2V0LmNzdiIpCgojIHNldCBkaW1lbnNpb25zIGZvciBkaXNwbGF5aW5nIHZhcmlhYmxlIGRlZmluaXRpb25zCmNhdCgiRGltZW5zaW9uczoiLCBkaW0obG9hbl9kYXRhKVsxXSwgInJvd3MgYW5kIiwgZGltKGxvYW5fZGF0YSlbMl0sICJjb2x1bW5zXG4iKQpzdHIobG9hbl9kYXRhKQpgYGAKCiMjIFZhcmlhYmxlcwoKVGhlIGRhdGFzZXQgaW5jbHVkZXMgYSB0YXJnZXQgdmFyaWFibGUsIGBEZWZhdWx0YCwgYW5kIDE1IHByZWRpY3RvciB2YXJpYWJsZXMuCgp8IFZhcmlhYmxlIE5hbWUgICAgIHwgRGVzY3JpcHRpb24gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfC0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18CnwgYERlZmF1bHRgICAgICAgICAgfCBUYXJnZXQgVmFyaWFibGU6IDEgZm9yIGRlZmF1bHQsIDAgZm9yIG5vbi1kZWZhdWx0ICAgICAgICAgfAp8IGBDaGVja2luZ19hbW91bnRgIHwgQW1vdW50IGluIHRoZSBjaGVja2luZyBhY2NvdW50ICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgVGVybWAgICAgICAgICAgICB8IExvYW4gdGVybSBpbiBtb250aHMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgYENyZWRpdF9zY29yZWAgICAgfCBBcHBsaWNhbnQncyBjcmVkaXQgc2NvcmUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IGBHZW5kZXJgICAgICAgICAgIHwgQXBwbGljYW50J3MgZ2VuZGVyIChNYWxlL0ZlbWFsZSkgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgTWFyaXRhbF9zdGF0dXNgICB8IEFwcGxpY2FudCdzIG1hcml0YWwgc3RhdHVzIChTaW5nbGUvTWFycmllZCkgICAgICAgICAgICAgICB8CnwgYENhcl9sb2FuYCAgICAgICAgfCAxIGlmIGFwcGxpY2FudCBoYXMgYSBjYXIgbG9hbiwgMCBvdGhlcndpc2UgICAgICAgICAgICAgICAgfAp8IGBQZXJzb25hbF9sb2FuYCAgIHwgMSBpZiBhcHBsaWNhbnQgaGFzIGEgcGVyc29uYWwgbG9hbiwgMCBvdGhlcndpc2UgICAgICAgICAgIHwKfCBgSG9tZV9sb2FuYCAgICAgICB8IDEgaWYgYXBwbGljYW50IGhhcyBhIGhvbWUgbG9hbiwgMCBvdGhlcndpc2UgICAgICAgICAgICAgICB8CnwgYEVkdWNhdGlvbl9sb2FuYCAgfCAxIGlmIGFwcGxpY2FudCBoYXMgYW4gZWR1Y2F0aW9uIGxvYW4sIDAgb3RoZXJ3aXNlICAgICAgICAgfAp8IGBFbXBfc3RhdHVzYCAgICAgIHwgRW1wbG95bWVudCBzdGF0dXMgKEVtcGxveWVkL1VuZW1wbG95ZWQpICAgICAgICAgICAgICAgICAgIHwKfCBgQW1vdW50YCAgICAgICAgICB8IFRoZSBsb2FuIGFtb3VudCByZXF1ZXN0ZWQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgYFNhdmluZ19hbW91bnRgICAgfCBBbW91bnQgaW4gdGhlIHNhdmluZ3MgYWNjb3VudCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IGBFbXBfZHVyYXRpb25gICAgIHwgRW1wbG95bWVudCBkdXJhdGlvbiBpbiBtb250aHMgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgQWdlYCAgICAgICAgICAgICB8IEFwcGxpY2FudCdzIGFnZSBpbiB5ZWFycyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgYE5vX29mX2NyZWRpdF9hY2NgfCBOdW1iZXIgb2YgY3JlZGl0IGFjY291bnRzICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAoKLS0tLS0KCiMgRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcyBhbmQgRmVhdHVyZSBFbmdpbmVlcmluZwoKV2Ugd2lsbCBub3cgcGVyZm9ybSBFREEgdG8gY2xlYW4gdGhlIGRhdGEsIHNob3cgdmFyaWFibGUgcmVsYXRpb25zaGlwcyBhbmQgcHJlcGFyZSBmb3IgbW9kZWxpbmcuCgojIyBEYXRhIENsZWFuaW5nCgojIyMgTWlzc2luZyBWYWx1ZXMgYW5kIER1cGxpY2F0ZXMKCkZpcnN0IHdlIGNoZWNrIGZvciBhbnkgbWlzc2luZyB2YWx1ZXMgb3IgZHVwbGljYXRlZCByb3dzLgoKYGBge3IgY2hlY2stZHVwbGljYXRlc30KIyBjaGVjayBmb3IgbWlzc2luZyB2YWx1ZXMKY2F0KCJUb3RhbCBtaXNzaW5nIHZhbHVlczoiLCBzdW0oaXMubmEobG9hbl9kYXRhKSksICJcbiIpCgojIGNoZWNrIGZvciBkdXBsaWNhdGVkIHJvd3MKY2F0KCJUb3RhbCBkdXBsaWNhdGVkIHJvd3M6Iiwgc3VtKGR1cGxpY2F0ZWQobG9hbl9kYXRhKSksICJcbiIpCmBgYAoKVGhlIGRhdGEgaXMgY2xlYW4gd2l0aCBubyBtaXNzaW5nIHZhbHVlcyBvciBkdXBsaWNhdGUgZW50cmllcy4KCiMjIyBJbnNwZWN0aW5nIERhdGEgSXNzdWVzCgpUaGUgYENoZWNraW5nX2Ftb3VudGAgY29sdW1uIGhhcyBuZWdhdGl2ZSB2YWx1ZXMgd2hpY2ggbGlrZWx5IHJlcHJlc2VudCBvdmVyZHJhZnRzLiBUbyBzaW1wbGlmeSwgd2Ugc2V0IG5lZ2F0aXZlIHZhbHVlcyB0byAwLgoKYGBge3IgZml4LW5lZ2F0aXZlc30KIyBTaG93IHN1bW1hcnkgdG8gaWRlbnRpZnkgdGhlIGlzc3VlCnN1bW1hcnkobG9hbl9kYXRhJENoZWNraW5nX2Ftb3VudCkKCiMgQ3JlYXRlIGEgY29weSB0byBtb2RpZnkKbG9hbl9kYXRhX2NsZWFuZWQgPC0gbG9hbl9kYXRhCiMgVXNlIGJhc2UgUiBpbmRleGluZyB0byBmaW5kIG5lZ2F0aXZlIHZhbHVlcyBhbmQgc2V0IHRoZW0gdG8gMApsb2FuX2RhdGFfY2xlYW5lZCRDaGVja2luZ19hbW91bnRbbG9hbl9kYXRhX2NsZWFuZWQkQ2hlY2tpbmdfYW1vdW50IDwgMF0gPC0gMAoKY2F0KCJcblN1bW1hcnkgb2YgQ2hlY2tpbmdfYW1vdW50IGFmdGVyIGNvcnJlY3Rpb246XG4iKQpzdW1tYXJ5KGxvYW5fZGF0YV9jbGVhbmVkJENoZWNraW5nX2Ftb3VudCkKYGBgCgojIyBJbmRpdmlkdWFsIFZhcmlhYmxlIEFuYWx5c2lzCgpXZSB3aWxsIHZpc3VhbGl6ZSB0aGUgZGlzdHJpYnV0aW9uIG9mIGluZGl2aWR1YWwgdmFyaWFibGVzIHVzaW5nIGJhc2ljIHBsb3RzLgoKIyMjIE51bWVyaWNhbCBWYXJpYWJsZSBEaXN0cmlidXRpb25zCgpgYGB7ciBwbG90LW51bWVyaWMtZGlzdHJpYnV0aW9ucywgZmlnLmNhcD0iRGlzdHJpYnV0aW9ucyBvZiBLZXkgTnVtZXJpY2FsIFZhcmlhYmxlcyJ9CiMgU2V0IHVwIGEgMngyIHBsb3R0aW5nIGFyZWEKcGFyKG1mcm93ID0gYygyLCAyKSkKCiMgQmFzaWMgaGlzdG9ncmFtcwpoaXN0KGxvYW5fZGF0YV9jbGVhbmVkJENyZWRpdF9zY29yZSwgbWFpbiA9ICJEaXN0cmlidXRpb24gb2YgQ3JlZGl0IFNjb3JlIiwgeGxhYiA9ICJDcmVkaXQgU2NvcmUiLCBjb2wgPSAibGlnaHRibHVlIikKaGlzdChsb2FuX2RhdGFfY2xlYW5lZCRBZ2UsIG1haW4gPSAiRGlzdHJpYnV0aW9uIG9mIEFnZSIsIHhsYWIgPSAiQWdlICh5ZWFycykiLCBjb2wgPSAiZ3JlZW4iKQpoaXN0KGxvYW5fZGF0YV9jbGVhbmVkJEFtb3VudCwgbWFpbiA9ICJEaXN0cmlidXRpb24gb2YgTG9hbiBBbW91bnQiLCB4bGFiID0gIkFtb3VudCIsIGNvbCA9ICJwaW5rIikKaGlzdChsb2FuX2RhdGFfY2xlYW5lZCRTYXZpbmdfYW1vdW50LCBtYWluID0gIkRpc3RyaWJ1dGlvbiBvZiBTYXZpbmcgQW1vdW50IiwgeGxhYiA9ICJTYXZpbmcgQW1vdW50IiwgY29sID0gInllbGxvdyIpCgojIFJlc2V0IHBsb3R0aW5nIGFyZWEgdG8gZGVmYXVsdApwYXIobWZyb3cgPSBjKDEsIDEpKQpgYGAKCioqT2JzZXJ2YXRpb25zOioqIGBDcmVkaXRfc2NvcmVgIGFuZCBgQWdlYCBhcmUgYXBwcm94aW1hdGVseSBub3JtYWxseSBkaXN0cmlidXRlZC4gRmluYW5jaWFsIHZhcmlhYmxlcyBsaWtlIGBBbW91bnRgIGFuZCBgU2F2aW5nX2Ftb3VudGAgYXJlIHNrZXdlZCB0byB0aGUgcmlnaHQuCgojIyMgQ2F0ZWdvcmljYWwgVmFyaWFibGUgRGlzdHJpYnV0aW9ucwoKYGBge3IgcGxvdC1jYXRlZ29yaWNhbC1kaXN0cmlidXRpb25zLCBmaWcuY2FwPSJEaXN0cmlidXRpb25zIG9mIENhdGVnb3JpY2FsICYgVGFyZ2V0IFZhcmlhYmxlcyJ9CiMgU2V0IHVwIGEgMngyIHBsb3R0aW5nIGFyZWEKcGFyKG1mcm93ID0gYygyLCAyKSkKCiMgQmFzaWMgYmFyIHBsb3RzCmJhcnBsb3QodGFibGUobG9hbl9kYXRhX2NsZWFuZWQkRGVmYXVsdCksIG1haW4gPSAiTG9hbiBEZWZhdWx0IENvdW50cyIsIGNvbD1jKCJkYXJrZ3JlZW4iLCAiZGFya3JlZCIpKQpiYXJwbG90KHRhYmxlKGxvYW5fZGF0YV9jbGVhbmVkJEdlbmRlciksIG1haW4gPSAiR2VuZGVyIERpc3RyaWJ1dGlvbiIsIGNvbD1jKCJwaW5rIiwgImxpZ2h0Ymx1ZSIpKQpiYXJwbG90KHRhYmxlKGxvYW5fZGF0YV9jbGVhbmVkJE1hcml0YWxfc3RhdHVzKSwgbWFpbiA9ICJNYXJpdGFsIFN0YXR1cyIsIGNvbD1jKCJvcmFuZ2UiLCAicHVycGxlIikpCmJhcnBsb3QodGFibGUobG9hbl9kYXRhX2NsZWFuZWQkRW1wX3N0YXR1cyksIG1haW4gPSAiRW1wbG95bWVudCBTdGF0dXMiLCBjb2w9YygiZ3JheSIsICJicm93biIpKQoKIyBSZXNldCBwbG90dGluZyBhcmVhCnBhcihtZnJvdyA9IGMoMSwgMSkpCmBgYAoKKipPYnNlcnZhdGlvbnM6KiogVGhlcmUgYXJlIG1vcmUgbm9uLWRlZmF1bHRlcnMgKDApIHRoYW4gZGVmYXVsdGVycyAoMSkuCgojIyBSZWxhdGlvbnNoaXBzIGJldHdlZW4gVmFyaWFibGVzCgpOb3cgd2UgZXhwbG9yZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gdmFyaWFibGVzIHVzaW5nIHNpbXBsZSBjb21wYXJpc29ucy4KCiMjIyBSZWxhdGlvbnNoaXAgd2l0aCBgRGVmYXVsdGAKCldlIHVzZSBib3hwbG90cyB0byBjb21wYXJlIG51bWVyaWNhbCB2YXJpYWJsZXMgYmV0d2VlbiB0aGUgZGVmYXVsdCBhbmQgbm9uLWRlZmF1bHQgYXBwbGljYW50cy4KCmBgYHtyIHBsb3QtYml2YXJpYXRlLWRlZmF1bHQsIGZpZy5jYXA9IkNyZWRpdCBTY29yZSBhbmQgTG9hbiBBbW91bnQgYnkgRGVmYXVsdCBTdGF0dXMifQojIFNldCB1cCBhIDF4MiBwbG90dGluZyBhcmVhCnBhcihtZnJvdyA9IGMoMSwgMikpCgojIGJhc2ljIGJveHBsb3RzCmJveHBsb3QoQ3JlZGl0X3Njb3JlIH4gRGVmYXVsdCwgZGF0YSA9IGxvYW5fZGF0YV9jbGVhbmVkLAogICAgICAgIG1haW4gPSAiQ3JlZGl0IFNjb3JlIGJ5IERlZmF1bHQiLAogICAgICAgIHhsYWIgPSAiRGVmYXVsdCAoMD1ObywgMT1ZZXMpIiwgeWxhYiA9ICJDcmVkaXQgU2NvcmUiLAogICAgICAgIGNvbCA9IGMoImRhcmtncmVlbiIsICJkYXJrcmVkIikpCgpib3hwbG90KEFtb3VudCB+IERlZmF1bHQsIGRhdGEgPSBsb2FuX2RhdGFfY2xlYW5lZCwKICAgICAgICBtYWluID0gIkxvYW4gQW1vdW50IGJ5IERlZmF1bHQiLAogICAgICAgIHhsYWIgPSAiRGVmYXVsdCAoMD1ObywgMT1ZZXMpIiwgeWxhYiA9ICJMb2FuIEFtb3VudCIsCiAgICAgICAgY29sID0gYygiZGFya2dyZWVuIiwgImRhcmtyZWQiKSkKICAgICAgICAKIyBSZXNldCBwbG90dGluZyBhcmVhCnBhcihtZnJvdyA9IGMoMSwgMSkpCmBgYAoKKipPYnNlcnZhdGlvbnM6KiogQ3VzdG9tZXJzIHdobyBkZWZhdWx0ZWQgdGVuZCB0byBoYXZlIGxvd2VyIGNyZWRpdCBzY29yZXMuCgojIyMgUmVsYXRpb25zaGlwIHdpdGggYEFtb3VudGAKClRvIGV4cGxvcmUgcHJlZGljdG9ycyBmb3IgdGhlIHJlZ3Jlc3Npb24gcHJvYmxlbSwgd2UgY2FuIHNlZSBob3cgYEFtb3VudGAgcmVsYXRlcyB0byBjYXRlZ29yaWNhbCB2YXJpYWJsZXMuCgpgYGB7ciBwbG90LXJlbGF0aW9uc2hpcC1hbW91bnQsIGZpZy5jYXA9IkxvYW4gQW1vdW50IGJ5IEVtcGxveW1lbnQgYW5kIE1hcml0YWwgU3RhdHVzIn0KIyBTZXQgdXAgYSAxeDIgcGxvdHRpbmcgYXJlYQpwYXIobWZyb3cgPSBjKDEsIDIpKQoKIyBib3hwbG90cyBjb21wYXJpbmcgQW1vdW50IGFnYWluc3QgY2F0ZWdvcmljYWwgdmFyaWFibGVzCmJveHBsb3QoQW1vdW50IH4gRW1wX3N0YXR1cywgZGF0YSA9IGxvYW5fZGF0YV9jbGVhbmVkLAogICAgICAgIG1haW4gPSAiTG9hbiBBbW91bnQgYnkgRW1wbG95bWVudCBTdGF0dXMiLAogICAgICAgIHhsYWIgPSAiRW1wbG95bWVudCBTdGF0dXMiLCB5bGFiID0gIkxvYW4gQW1vdW50IiwKICAgICAgICBjb2wgPSBjKCJncmF5IiwgImJyb3duIikpCgpib3hwbG90KEFtb3VudCB+IE1hcml0YWxfc3RhdHVzLCBkYXRhID0gbG9hbl9kYXRhX2NsZWFuZWQsCiAgICAgICAgbWFpbiA9ICJMb2FuIEFtb3VudCBieSBNYXJpdGFsIFN0YXR1cyIsCiAgICAgICAgeGxhYiA9ICJNYXJpdGFsIFN0YXR1cyIsIHlsYWIgPSAiTG9hbiBBbW91bnQiLAogICAgICAgIGNvbCA9IGMoIm9yYW5nZSIsICJwdXJwbGUiKSkKICAgICAgICAKIyBSZXNldCBwbG90dGluZyBhcmVhCnBhcihtZnJvdyA9IGMoMSwgMSkpCmBgYAoKKipPYnNlcnZhdGlvbnM6KiogVGhlIHJlcXVlc3RlZCBsb2FuIGFtb3VudCBkb2VzIG5vdCBhcHBlYXIgdG8gZGlmZmVyIHNpZ25pZmljYW50bHkgYmV0d2VlbiB0aGVzZSBncm91cHMsIHN1Z2dlc3RpbmcgdGhleSBtYXkgbm90IGJlIHN0cm9uZyBwcmVkaWN0b3JzIG9uIHRoZWlyIG93biBmb3IgdGhlIHJlZ3Jlc3Npb24gcHJvYmxlbS4KCi0tLS0tCgojIENyZWF0aW5nIHRoZSBBbmFseXRpY2FsIERhdGFzZXQKCldlIHdpbGwgbm93IHBlcmZvcm0gZmVhdHVyZSBlbmdpbmVlcmluZyB0byBjcmVhdGUgdGhlIGZpbmFsIGRhdGFzZXQgZm9yIG1vZGVsaW5nLgoKKipTdGVwczoqKgoKMS4gICoqQ29udmVydCBDYXRlZ29yaWNhbCBWYXJpYWJsZXM6KiogYEdlbmRlcmAsIGBNYXJpdGFsX3N0YXR1c2AsIGFuZCBgRW1wX3N0YXR1c2Agd2lsbCBiZSBjb252ZXJ0ZWQgaW50byBmYWN0b3JzLCB0aGVuIGludG8gbnVtZXJpY2FsIGR1bW15IHZhcmlhYmxlcy4KMi4gICoqU3RhbmRhcmRpemUgTnVtZXJpY2FsIFZhcmlhYmxlczoqKiBXZSB3aWxsIHNjYWxlIG51bWVyaWNhbCBwcmVkaWN0b3JzIHRvIGhhdmUgYSBtZWFuIG9mIDAgYW5kIGEgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIDEuCgo8IS0tIGVuZCBsaXN0IC0tPgoKYGBge3IgY3JlYXRlLWFuYWx5dGljYWwtZGF0YX0KIyBTdGFydCB3aXRoIHRoZSBjbGVhbmVkIGRhdGEKYW5hbHl0aWNhbF9kYXRhIDwtIGxvYW5fZGF0YV9jbGVhbmVkCgojIDEuIENvbnZlcnQgY2hhcmFjdGVyIGNvbHVtbnMgdG8gZmFjdG9ycwphbmFseXRpY2FsX2RhdGEkR2VuZGVyIDwtIGFzLmZhY3RvcihhbmFseXRpY2FsX2RhdGEkR2VuZGVyKQphbmFseXRpY2FsX2RhdGEkTWFyaXRhbF9zdGF0dXMgPC0gYXMuZmFjdG9yKGFuYWx5dGljYWxfZGF0YSRNYXJpdGFsX3N0YXR1cykKYW5hbHl0aWNhbF9kYXRhJEVtcF9zdGF0dXMgPC0gYXMuZmFjdG9yKGFuYWx5dGljYWxfZGF0YSRFbXBfc3RhdHVzKQoKIyAyLiBJZGVudGlmeSBudW1lcmljIHByZWRpY3RvcnMgdG8gYmUgc2NhbGVkCnZhcnNfdG9fc2NhbGUgPC0gYygiQ2hlY2tpbmdfYW1vdW50IiwgIlRlcm0iLCAiQ3JlZGl0X3Njb3JlIiwgIkFtb3VudCIsCiAgICAgICAgICAgICAgICAgICAiU2F2aW5nX2Ftb3VudCIsICJFbXBfZHVyYXRpb24iLCAiQWdlIiwgIk5vX29mX2NyZWRpdF9hY2MiKQpzY2FsZWRfZGF0YSA8LSBzY2FsZShhbmFseXRpY2FsX2RhdGFbLCB2YXJzX3RvX3NjYWxlXSkKY29sbmFtZXMoc2NhbGVkX2RhdGEpIDwtIHBhc3RlMCh2YXJzX3RvX3NjYWxlLCAiX3NjYWxlZCIpICMgQWRkIHN1ZmZpeCB0byBzY2FsZWQgY29sdW1ucwoKIyAzLiBPbmUtaG90IGVuY29kZSBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgdXNpbmcgbW9kZWwubWF0cml4CmR1bW15X3ZhcnMgPC0gbW9kZWwubWF0cml4KH4gR2VuZGVyICsgTWFyaXRhbF9zdGF0dXMgKyBFbXBfc3RhdHVzIC0gMSwgZGF0YSA9IGFuYWx5dGljYWxfZGF0YSkKCiMgNC4gQ29tYmluZSBldmVyeXRoaW5nIGludG8gdGhlIGZpbmFsIGFuYWx5dGljYWwgZGF0YXNldApiaW5hcnlfdmFycyA8LSBhbmFseXRpY2FsX2RhdGFbLCBjKCJDYXJfbG9hbiIsICJQZXJzb25hbF9sb2FuIiwgIkhvbWVfbG9hbiIsICJFZHVjYXRpb25fbG9hbiIsICJEZWZhdWx0IildCmFuYWx5dGljYWxfZGF0YV9maW5hbCA8LSBjYmluZChzY2FsZWRfZGF0YSwgZHVtbXlfdmFycywgYmluYXJ5X3ZhcnMpCgojIERpc3BsYXkgdGhlIGZpcnN0IGZldyByb3dzIGFuZCBzdHJ1Y3R1cmUgb2YgdGhlIGZpbmFsIGRhdGFzZXQKY2F0KCJGaXJzdCA2IHJvd3Mgb2YgdGhlIGZpbmFsIGFuYWx5dGljYWwgZGF0YXNldDpcbiIpCmhlYWQoYXMuZGF0YS5mcmFtZShhbmFseXRpY2FsX2RhdGFfZmluYWwpKQpgYGAKCi0tLS0tCgojIFdyYXBwaW5nIEZlYXR1cmUgRW5naW5lZXJpbmcgQ29kZQoKVG8gbWFrZSB0aGVzZSBzdGVwcyByZXVzYWJsZSwgd2UgY2FuIHdyYXAgdGhlbSBpbiBhIGZ1bmN0aW9uLgoKYGBge3Igd3JhcC1mZWF0dXJlLWVuZ2luZWVyaW5nLWZ1bmN0aW9ufQpjcmVhdGVfYW5hbHl0aWNhbF9mZWF0dXJlcyA8LSBmdW5jdGlvbihyYXdfZGF0YSkgewogICMgU3RlcCAxOiBDbGVhbiBkYXRhCiAgZGF0YV9jbGVhbmVkIDwtIHJhd19kYXRhCiAgZGF0YV9jbGVhbmVkJENoZWNraW5nX2Ftb3VudFtkYXRhX2NsZWFuZWQkQ2hlY2tpbmdfYW1vdW50IDwgMF0gPC0gMAogIAogICMgU3RlcCAyOiBDb252ZXJ0IHRvIGZhY3RvcnMKICBkYXRhX2NsZWFuZWQkR2VuZGVyIDwtIGFzLmZhY3RvcihkYXRhX2NsZWFuZWQkR2VuZGVyKQogIGRhdGFfY2xlYW5lZCRNYXJpdGFsX3N0YXR1cyA8LSBhcy5mYWN0b3IoZGF0YV9jbGVhbmVkJE1hcml0YWxfc3RhdHVzKQogIGRhdGFfY2xlYW5lZCRFbXBfc3RhdHVzIDwtIGFzLmZhY3RvcihkYXRhX2NsZWFuZWQkRW1wX3N0YXR1cykKICAKICAjIFN0ZXAgMzogU2NhbGUgbnVtZXJpY2FsIHByZWRpY3RvcnMKICB2YXJzX3RvX3NjYWxlIDwtIGMoIkNoZWNraW5nX2Ftb3VudCIsICJUZXJtIiwgIkNyZWRpdF9zY29yZSIsICJBbW91bnQiLAogICAgICAgICAgICAgICAgICAgICAiU2F2aW5nX2Ftb3VudCIsICJFbXBfZHVyYXRpb24iLCAiQWdlIiwgIk5vX29mX2NyZWRpdF9hY2MiKQogIHNjYWxlZF9kYXRhIDwtIHNjYWxlKGRhdGFfY2xlYW5lZFssIHZhcnNfdG9fc2NhbGVdKQogIGNvbG5hbWVzKHNjYWxlZF9kYXRhKSA8LSBwYXN0ZTAodmFyc190b19zY2FsZSwgIl9zY2FsZWQiKQogIAogICMgU3RlcCA0OiBDcmVhdGUgZHVtbXkgdmFyaWFibGVzCiAgZHVtbXlfdmFycyA8LSBtb2RlbC5tYXRyaXgofiBHZW5kZXIgKyBNYXJpdGFsX3N0YXR1cyArIEVtcF9zdGF0dXMgLSAxLCBkYXRhID0gZGF0YV9jbGVhbmVkKQogIAogICMgU3RlcCA1OiBDb21iaW5lIGFsbCBwYXJ0cwogIGJpbmFyeV92YXJzIDwtIGRhdGFfY2xlYW5lZFssIGMoIkNhcl9sb2FuIiwgIlBlcnNvbmFsX2xvYW4iLCAiSG9tZV9sb2FuIiwgIkVkdWNhdGlvbl9sb2FuIiwgIkRlZmF1bHQiKV0KICBmaW5hbF9kYXRhIDwtIGNiaW5kKHNjYWxlZF9kYXRhLCBkdW1teV92YXJzLCBiaW5hcnlfdmFycykKICAKICByZXR1cm4oYXMuZGF0YS5mcmFtZShmaW5hbF9kYXRhKSkKfQoKIyBFeGFtcGxlIG9mIHVzaW5nIHRoZSBmdW5jdGlvbgphbmFseXRpY2FsX2RhdGFfZnJvbV9mdW5jdGlvbiA8LSBjcmVhdGVfYW5hbHl0aWNhbF9mZWF0dXJlcyhsb2FuX2RhdGEpCmNhdCgiRmlyc3QgMyByb3dzIG9mIGRhdGEgcHJvY2Vzc2VkIGJ5IHRoZSBmdW5jdGlvbjpcbiIpCmhlYWQoYW5hbHl0aWNhbF9kYXRhX2Zyb21fZnVuY3Rpb24sIDMpCmBgYAoKLS0tLS0KCiMgQ29uY2x1c2lvbiBhbmQgTmV4dCBTdGVwcwoKVGhpcyBjb25jbHVkZXMgb3VyIGFuYWx5c2lzIG9mIHRoZSBiYW5rIGxvYW4gZGVmYXVsdHMgZGF0YXNldC4gS2V5IGZpbmRpbmdzIGluY2x1ZGUgdGhlIGltcG9ydGFuY2Ugb2YgYENyZWRpdF9zY29yZWAgaW4gcHJlZGljdGluZyBkZWZhdWx0cyBhbmQgdGhlIG5hdHVyZSBvZiB0aGUgYERlZmF1bHRgIHZhcmlhYmxlLiBXZSBwZXJmb3JtZWQgZmVhdHVyZSBlbmdpbmVlcmluZyB0byBzY2FsZSBudW1lcmljYWwgcHJlZGljdG9ycyBhbmQgZW5jb2RlIGNhdGVnb3JpY2FsIHZhcmlhYmxlcywgcmVzdWx0aW5nIGluIGEgY2xlYW4gZGF0YXNldCByZWFkeSBmb3IgcGFydCBJSS4gVGhlIGVudGlyZSBwcm9jZXNzIHdhcyB3cmFwcGVkIGluIGEgZnVuY3Rpb24gdG8gZW5zdXJlIGl0IGNhbiBiZSByZXVzZWQgY29uc2lzdGVudGx5LiBUaGUgcHJvamVjdCBpcyBub3cgcHJlcGFyZWQgZm9yIFBhcnQgSUkgd2hpY2ggd2lsbCBmb2N1cyBvbiBidWlsZGluZyBhbmQgZXZhbHVhdGluZyBwcmVkaWN0aXZlIG1vZGVscy4K