Introduction

Lending Club is a peer-to-peer lending company that matches borrowers with investors through an online platform. It services people that need personal loans between $1,000 and $40,000. Borrowers receive the full amount of the issued loan minus the origination fee, which is paid to the company. Investors purchase notes backed by the personal loans and pay Lending Club a service fee. The company shares data about all loans issued through its platform during certain time periods.

This analysis will focus on the Lending Club Loan Data from the first quarter of 2017. This document is generated using R Markdown. The code that powers the analysis is hidden by default but you can expand any section by clicking the Code button, like the one in the top right corner of this section. So far I have loaded in the actual data file and the data dictionary. I also performed some minor formatting to prepare for the rest of the analysis.

We’ll start off by running some broad summary statistics and using this information to clean up the data set. Once the data are reasonably formatted we will move on to visualizing the relationships between the variables.

Broad Summary Statistics and Scrubbing

Before we start any analysis or data scrubbing, let’s join in the data dicionary so we can have a quick reference to what the variables actually mean:

# Extracting all data column names and joining to data dictionary
loan_data_cols <- data.frame(Variable = colnames(loan_data),
                             stringsAsFactors = F)
data_dict$var <- trimws(data_dict$var)
mapping <- loan_data_cols %>% left_join(data_dict, by = c("Variable" = "var"))
colnames(mapping)[2] <- "Full Description"
# Formatting into interactive HTML table
lib_load("DT")
mapping <- sapply(mapping, trimws)
datatable(mapping)



We’ll start by taking a broad look at the different variable types in the data set. After dropping some empty and redacted columns we are left with 113 variables in total. There appear to be 94 continuous variables and 22 categorical variables. Let’s run some summary statistics on the continuous variables:

# Grabbing column types to see if they are categorical or contiunous
all_vars <- unlist(lapply(loan_data,class))
# Enters zero NAs for summary when there are none so the summary data structures can be combined
# Borrowed from: https://stackoverflow.com/questions/32011873/force-summary-to-report-the-number-of-nas-even-if-none
custom_summary <- function(var) {
  
  if(!any(is.na(var))) {
    res <- c(summary(var),"NA's"=0)
  } else {
    res <- summary(var)
  }
  return(res)
}
# Extracting continuous variables
cont_info <- lapply(loan_data[,all_vars == "numeric"], custom_summary) 
# Formatting summaries into uniform data structure and combining
cont_names <- names(all_vars[all_vars == "numeric"])
cont_info <- lapply(1:length(cont_info), function(inx) {
  
  new_vect <- c(cont_names[inx],round(cont_info[[inx]],2))
  
  names(new_vect)[1] <- "Var Name"
  
  new_vect
  
}); cont_info <- do.call(rbind,cont_info)
# Formatting into interactive HTML table
datatable(cont_info)



We see several variables that describe the loan such as the amount, payment, interest rate, and term. We also see some descriptive information on the borrower such as annual income, debt-to-income ratio (DTI), number of mortgage accounts, and total credit limit. It looks like dti, recoveries, and collection_recovery_fee have some data issues. The latter two are blank throughout the entire data set. The minimum and maximum values on dti seem completely off. We can plot the histograms of various dti ranges to get more reasonable bounds for the data:

# First cleaning up the blank variables
loan_data[,c("recoveries","collection_recovery_fee")] = NULL
# Plotting the density of dti under various cut-offs
dti_raw <- loan_data$dti
lib_load("ggplot2")
dens1 <- qplot(dti_raw, fill = I("dodgerblue4"), 
               alpha = I(0.4), col = I("grey29")) + xlab("dti full range") + ylab("Count")
dens2 <- qplot(dti_raw[dti_raw > 0 & dti_raw < 15], fill = I("dodgerblue4"), 
               alpha = I(0.4), col = I("grey29")) + xlab("0 < dti < 15") + ylab("Count")
dens3 <- qplot(dti_raw[dti_raw > 0 & dti_raw < 50], fill = I("dodgerblue4"), 
               alpha = I(0.7), col = I("grey29")) + xlab("0 < dti < 50") + ylab("Count")
dens4 <- qplot(dti_raw[dti_raw > 50 & dti_raw < 9999], fill = I("dodgerblue4"), 
               alpha = I(0.4), col = I("grey29")) + xlab("50 < dti < 9999") + ylab("Count")
# Combining density plots
lib_load("gridExtra")
lib_load("grid")
# Subjectively clipping range of dti
grid.arrange(dens1, dens2, dens3, dens4,
             top = textGrob("DTI Histograms (30 bins)"), 
             widths = c(4,4), heights = c(4,4))

# Clipping the range for dti
loan_data$dti[loan_data$dti < 0 | loan_data$dti > 50] = NA



Keeping the full range for dti doesn’t seem to make sense. The lower bound should always be zero since you can’t have less than no debt. The upper bound is a bit debatable. It appears that the majority of the density is captured between 0 and 50, which seems to be reasonable. We can subjectively drop everything outside of this range and convert those entries to missing values, which are represented as NA in the R language. This results in 411 missing entries.

Next, let’s take a look at the categorical variables. We’ll count the frequencies for the top four categories for each variable and lump everything else into a fifth category called Other. If there are less than four categories then we’ll just show all of the counts.

# Extracting categorical variables
cat_info <- lapply(1:sum(all_vars == "character"), function(inx) {
  
  Category <- loan_data[,names(all_vars[all_vars == "character"])[inx]]
  
  # Getting frequency counts and sorting in decreasing order
  counts_df <- data.frame(table(Category)) %>% arrange(desc(Freq))
  counts_df$Category <- as.character(counts_df$Category)
  
  # Summarizing only top 4 counts and lumping everything into a fifth category, Other
  if(nrow(counts_df) > 5) {
    
   counts_df$Freq[5] <- sum(counts_df$Freq[5:nrow(counts_df)])
   counts_df$Category[5] <- "Other"
   
   counts_df <- counts_df[1:5,]
  } 
    
  df <- data.frame(Name = names(all_vars[all_vars == "character"])[inx],
                   counts_df, stringsAsFactors = F)
  df$`Freq %` <- round(100*df$Freq/sum(df$Freq))
  
  df
  
}) %>% bind_rows()
# Saving example of an incorrectly tagged NA
bad_row <- which(loan_data$emp_title == ".")
# Formatting into interactive HTML table
datatable(cat_info)



We see some descriptive information on the loans such as the term, grade, and purpose. There are also some variables that describe the borrower such as employment title, state of residence, and number of accounts currently delinquent. Columns like earliest_cr_line can be converted to an integer that represents the years since that date, which would be more useful for modeling later. There are also entries that are tagged as empty spaces or dots that should really be NA. An example is row 22990 for emp_title, which is tagged as a period. Let’s clean these up.

# Fixing date columns
lib_load("lubridate")
lib_load("zoo")
# Earliest credit line is now the years since the given date
loan_data$earliest_cr_line <- difftime(as.yearmon(loan_data$issue_d, format = "%b-%Y"),
                                       as.yearmon(loan_data$earliest_cr_line, format = "%b-%Y"), 
                                       unit = "weeks")/52.25
loan_data$earliest_cr_line <- as.numeric(loan_data$earliest_cr_line)
loan_data$sec_app_earliest_cr_line <- difftime(as.yearmon(loan_data$issue_d, format = "%b-%Y"),
                                               as.yearmon(loan_data$sec_app_earliest_cr_line, format = "%b-%Y"), 
                                               unit = "weeks")/52.25
loan_data$sec_app_earliest_cr_line <- as.numeric(loan_data$sec_app_earliest_cr_line)
# Dropping columns that don't really add any info
loan_data[,c("pymnt_plan")] = NULL
# Coercing various entries to NA
loan_data[loan_data == "" | loan_data == "."] <- NA



Now that we have cleaned up the variables and correctly tagged missing values as NA, let’s take a look at the sparsity of various columns. Missing data can have strong impacts on predictive and inferential analysis. It’s important to understand any patterns in the sparsity, sometimes dropping incomplete observations can lead to a biased understanding of the data.

# Summarizing variables with lots of NAs
sparse_count <- lapply(1:ncol(loan_data), function(inx) {
  temp <- loan_data[,inx]
  
  Variable = colnames(loan_data)[inx]
  
  `NA %` = round(sum(is.na(temp))/length(temp)*100,2)
  
  `Full Name` = data_dict$desc[which(Variable == data_dict$var)[1]]
  df <- data.frame(Variable,`NA %`,`Full Name`,
                   check.names = F,
                   stringsAsFactors = F)
  
  return(df)
}) %>% bind_rows() %>% arrange(desc(`NA %`))
# Grabbing any variable with at least one NA
sparse_count <- sparse_count[sparse_count$`NA %` > 0,]
datatable(sparse_count)



It looks like a lot of the missing values are related to variables that deal with a second applicant. It doesn’t seem like these are critical to exploratory analysis or inference but we should still keep them in mind. We could explore different ways to impute some of the missing values, especially if we want to use the variables as part of a model for certain types of borrowers.

Visualzing Distributions

# Getting raw counts of continuous and categorical vars, then getting fully complete ones (no NAs)
cont <- sapply(loan_data, class) == "numeric"
cat <- sapply(loan_data, class) == "character"
cont_full <- sum(!(names(cont[cont == TRUE]) %in% sparse_count$Variable))
cat_full <- sum(!(names(cat[cat == TRUE]) %in% sparse_count$Variable))

At this point, we’re left with 65 continuous variables and 14 categorical variables with no NAs. The full data set contains 94 continuous variables and 19 categorical variables. We’ve also got 96779 observations, with each row representing a unique loan. It’s a bit difficult to think about this much data at once. A good first step is to create some plots to better understand the most important variables.

First, let’s try to break out the total loan volume in the first quarter of 2017. Let’s get a feel for who is borrowing the money, what they’re using it for, where they live, and their risk profiles.

# Cleaning up registered nurse double counting across loan_data
loan_data$emp_title[loan_data$emp_title %in% c("RN","Rn","rn","nurse","Nurse")] <- "Registered Nurse"
loan_data$emp_title[is.na(loan_data$emp_title)] <- "Not Available"
# Aggregating up total loans by emp_title
loan_by_emp <- loan_data %>% 
               group_by(emp_title) %>% 
               summarize(`Total Loans ($)` = sum(loan_amnt)) %>%
               arrange(desc(`Total Loans ($)`))
# Getting percentage information since we can only plot a subset
loan_by_emp$emp_title <- paste0(loan_by_emp$emp_title," - ",paste0(round(100*loan_by_emp$`Total Loans ($)`/sum(loan_by_emp$`Total Loans ($)`),1),"%"))
loan_by_emp_plot <- ggplot(loan_by_emp[1:10,], aes(x = reorder(emp_title,-`Total Loans ($)`), 
                                                   y = (`Total Loans ($)`)/1e6, 
                                                   fill = I("dodgerblue4"),
                                                   alpha = I(rep(0.7,10)),
                                                   col = I("grey29"))) + 
                    geom_bar(stat = "identity") +
                    theme(axis.text.x = element_text(angle = 55, hjust = 1)) +
                    xlab("Job Title - % of Total") +
                    ylab("Total Loans - Millions of $")
# Aggregating up by purpose
loan_by_purp <- loan_data %>% 
                group_by(title) %>% 
                summarize(`Total Loans ($)` = sum(loan_amnt)) %>%
                arrange(desc(`Total Loans ($)`))
# Getting percentage information
loan_by_purp$title <- paste0(loan_by_purp$title," - ",paste0(round(100*loan_by_purp$`Total Loans ($)`/sum(loan_by_purp$`Total Loans ($)`),1),"%"))
loan_by_purp_plot <- ggplot(loan_by_purp, aes(x = reorder(title,-`Total Loans ($)`), 
                                              y = (`Total Loans ($)`)/1e6, 
                                              fill = I("dodgerblue4"),
                                              alpha = I(rep(0.7,12)),
                                              col = I("grey29"))) + 
                     geom_bar(stat = "identity") +
                     theme(axis.text.x = element_text(angle = 55, hjust = 1)) +
                     xlab("Purpose") +
                     ylab(NULL)
grid.arrange(loan_by_emp_plot, loan_by_purp_plot,
             top = textGrob("Total Loans by Job Title and Purpose"),
             ncol = 2)



We can see that many of the job titles are actually missing, which could be because Lending Club chooses to hide that information to maintain the borrowers’ anonymity. Registered Nurse, Manager, Teacher, and Business Owner form the next largest categories. However, these only account for about 7.5% of the loan volume. This distribution has a strong right tail that stretches across the 33052 different job titles. The distribution of loan volume by purpose is actually the opposite of this. The vast majority of the loans have been taken out to consolidate debt. There are only 11 other purposes, which are all shown in the plot.

Now let’s take a look at what states the borrowers live in:

# Aggregating up by state
loan_by_state <- loan_data %>% 
                 group_by(addr_state) %>%
                 summarize(`Total Loans ($)` = sum(loan_amnt)/1e6) %>%
                 arrange(desc(`Total Loans ($)`))
colnames(loan_by_state) <- c("region","value")
# Getting summary percentage of top 4 regions
top4_states <- round(100*sum(loan_by_state$value[1:4])/sum(loan_by_state$value),1)
# Replacing out the state codes with their full names for plotting
lib_load("rgdal")
lib_load("choroplethrMaps")
lib_load("choroplethr")
data("state.regions")
loan_by_state$region <- sapply(loan_by_state$region, function(state_code) {
  
  inx <- grep(pattern = state_code, x = state.regions$abb)
  
  state.regions$region[inx]
  
})
# Plotting US map with values
state_choropleth(loan_by_state, title = "           Total Loan Volume by State - Millions $")



Most of the funds borrowed through Lending Club in the first quarter for 2017 went to people in California, Texas, New York, and Florida. These regions accounted for 38.2% of the volume during the period. This ranking actually mimics the ranking of those states’ economic output as measured by GDP. States with larger economies tend to have people who borrow more. It’s also interesting to note that Lending Club loans are currently not available in Iowa or West Virginia.

Finally, we can visualize various measures of the borrowers’ risk profiles. We can start off by taking a look at the distribution of the interest rate charged for each grade rating.

# Grabbing the means
cdat <- data.frame(tapply(loan_data$int_rate, loan_data$grade, mean))
rate_grade_dens <- ggplot(loan_data, aes(x = int_rate, fill = grade)) + 
                    geom_density(alpha = 0.6) +
                      geom_vline(data = cdat, aes(xintercept = cdat, colour =  factor(rownames(cdat))),
                                 linetype = "dashed", size = 1, show.legend = F) +
                      ylab(NULL) +
                      xlab("Interest Rate") + 
                      guides( fill = guide_legend(title = "Loan Grade")) + 
                      theme(axis.ticks.y = element_blank(), plot.title = element_text(hjust = 0.5)) + 
                      ggtitle("Interest Rate Distribution by Grade")
rate_grade_dens

The interest rate generally increases as the loan’s grade decreases, which is expected. However, these distributions appear to be quite lumpy, which points to the fact that there are various risk groups within each grade group. Let’s try to get a deeper look at these grade subgroups.

lib_load("moments")
## Generic function to create four descriptive plots for each loan grade --> Employment, State, Purpose, Amount
grade_plotter <- function(grade) {
  
  # Filtering for grade
  loan_data_tmp <- loan_data[loan_data$grade == grade,]
  ## Aggregating up total loans by job ##
  loan_by_emp <- loan_data_tmp %>% 
                 group_by(emp_title) %>% 
                 summarize(`Total Loans ($)` = sum(loan_amnt)) %>%
                 arrange(desc(`Total Loans ($)`))
  
  # Getting percentage information since we can only plot a subset
  loan_by_emp$emp_title <- paste0(loan_by_emp$emp_title," - ",paste0(round(100*loan_by_emp$`Total Loans ($)`/sum(loan_by_emp$`Total Loans ($)`),1),"%"))
  
  loan_by_emp_plot <- ggplot(loan_by_emp[1:10,], aes(x = reorder(emp_title,-`Total Loans ($)`), 
                                                     y = (`Total Loans ($)`)/1e6, 
                                                     fill = I("dodgerblue4"),
                                                     alpha = I(rep(0.7,10)),
                                                     col = I("grey29"))) + 
                      geom_bar(stat = "identity") +
                      theme(axis.text.x = element_text(angle = 55, hjust = 1)) +
                      xlab("Job Title - % of Total") +
                      ylab("Total Loans - Millions of $")
  
  ## Aggregating up total loans by purpose ##
  loan_by_purp <- loan_data_tmp %>% 
                  group_by(title) %>% 
                  summarize(`Total Loans ($)` = sum(loan_amnt)) %>%
                  arrange(desc(`Total Loans ($)`))
  # Getting percentage information
  loan_by_purp$title <- paste0(loan_by_purp$title," - ",paste0(round(100*loan_by_purp$`Total Loans ($)`/sum(loan_by_purp$`Total Loans ($)`),1),"%"))
  
  loan_by_purp_plot <- ggplot(loan_by_purp, aes(x = reorder(title,-`Total Loans ($)`), 
                                                y = (`Total Loans ($)`)/1e6, 
                                                fill = I("dodgerblue4"),
                                                alpha = I(rep(0.7,12)),
                                                col = I("grey29"))) + 
                     geom_bar(stat = "identity") +
                     theme(axis.text.x = element_text(angle = 55, hjust = 1)) +
                     xlab("Purpose") +
                     ylab(NULL)
  
  ## Aggregating up total loans by state ##
  loan_by_state <- loan_data_tmp %>% 
                   group_by(addr_state) %>% 
                   summarize(`Total Loans ($)` = sum(loan_amnt)) %>%
                   arrange(desc(`Total Loans ($)`))  
  
  # Finding full state names, capitalizing first letter of each one
  loan_by_state$addr_state <- sapply(loan_by_state$addr_state, function(state_code) {
    
    inx <- grep(pattern = state_code, x = state.regions$abb)
    
    state.regions$region[inx]
  
  }, USE.NAMES = F)
  
  # Borrowed from: https://stackoverflow.com/questions/6364783/capitalize-the-first-letter-of-both-words-in-a-two-word-string
  loan_by_state$addr_state <- sapply(loan_by_state$addr_state, function(state_name) {
    
    split <- strsplit(x=state_name, " ")[[1]]
    
      paste(toupper(substring(split, 1,1)), 
            substring(split, 2), sep="", collapse=" ")
  }, USE.NAMES = F)
  
  # Getting percentage information especially since we can only plot a subset
  loan_by_state$addr_state <- paste0(loan_by_state$addr_state," - ",paste0(round(100*loan_by_state$`Total Loans ($)`/sum(loan_by_state$`Total Loans ($)`),1),"%"))
  
  loan_by_state_plot <- ggplot(loan_by_state[1:10,], aes(x = reorder(addr_state,-`Total Loans ($)`), 
                                                         y = (`Total Loans ($)`)/1e6, 
                                                         fill = I("dodgerblue4"),
                                                         alpha = I(rep(0.7,10)),
                                                         col = I("grey29"))) + 
                    geom_bar(stat = "identity") +
                    theme(axis.text.x = element_text(angle = 55, hjust = 1)) +
                    xlab("State - % of Total") +
                    ylab("Total Loans - Millions of $")
  
  ## Aggregating up by loan amount ##
  loan_amnt_tmp <- loan_data_tmp$loan_amnt
  
  loan_amnt_hist <- qplot(loan_amnt_tmp, fill = I("dodgerblue4"), 
                           alpha = I(0.7), col = I("grey29")) + xlab("Loan Amount") + ylab("Count") + 
                            geom_vline(aes(xintercept = mean(loan_amnt_tmp)), 
                                       color = "dodgerblue4", 
                                       linetype = "dashed", 
                                       size = 2) +
                            annotate("text", x = Inf, y = Inf, 
                                     label = sprintf("\n Mean: %s  \n Average Deviation: %s   \n Skewness: %s   \n Kurtosis: %s   ",
                                                     round(mean(loan_amnt_tmp)),
                                                     round(mean(abs(loan_amnt_tmp-mean(loan_amnt_tmp)))),
                                                     round(skewness(loan_amnt_tmp),2),
                                                     round(kurtosis(loan_amnt_tmp),2)), 
                                     vjust = 1, hjust = 1)
  
  # Arranging plots into grid
  grid.arrange(loan_by_emp_plot, loan_by_purp_plot, loan_by_state_plot, loan_amnt_hist,
               widths = c(4,4), heights = c(4,3),   
               top = textGrob(sprintf("Grade %s Loan Volume by Employment, Purpose, State, and Counts",grade)))
  
  return(NULL)
}
# This seems to be a bug, but R errors out due on an obscure dplyr issue that is resolved with:
# 1) Restarting the R session at this point
# 2) Running library(ggplot2); library(dplyr); library(gridExtra); library(moments); library(grid)
# 3) Running the rest of the chunks

Grade A

null <- grid.draw(grade_plotter("A"))

Grade B

null <- grid.draw(grade_plotter("B"))

Grade C

null <- grid.draw(grade_plotter("C"))

Grade D

null <- grid.draw(grade_plotter("D"))

Grade E

null <- grid.draw(grade_plotter("E"))

Grade F

null <- grid.draw(grade_plotter("F"))

The relative orders of the purpose, state, and job title don’t change much between grades. The distribution of the loan size does shift to the right as the grade decreases. That is, people that are riskier tend to borrow more than those that are less risky. As the grade decreases there is a greater tendency to use the loan for debt consolidation. There are likely complex interactions amongst the variables in the full data set that better explain the differences in interest rates within grade groups. We’d likely need to build various models to try to capture what makes a borrower fall under a certain grade and what dictates the interest rate.

Summary

We’ve broken out the data set into continuous and categorical variables. These were scrubbed and analyzed for sparsity. Once we were comfortable with the data set, we moved on to visualizing the relationships between the variables. We broke out loan volume by state, job, and purpose. We also looked at the distribution of interest rate by loan grade and dived deeper into each grade’s statistics. Now that we have a reasonably clean data set and some aggregate information on the variables, we can move on to building models for inference and prediction.

LS0tDQp0aXRsZTogIkxlbmRpbmcgQ2x1YiBMb2FuIERhdGEgLSBFeHBsb3JhdG9yeSBBbmFseXNpcyINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgaHRtbF9kb2N1bWVudDogZGVmYXVsdA0KLS0tDQoNCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgcmVzdWx0cyA9ICdoaWRlJ30NCiMgVGhpcyBmdW5jdGlvbiBpbnN0YWxscyBhbnkgbGlicmFyaWVzIHRoYXQgYXJlIG1pc3NpbmcgYW5kIG5lZWRlZCBmb3IgdGhlIHNjcmlwdA0KbGliX2xvYWQgPC0gZnVuY3Rpb24ocGFja2FnZSkgew0KDQogIGlmKCEocGFja2FnZSAlaW4lIHJvd25hbWVzKGluc3RhbGxlZC5wYWNrYWdlcygpKSkpIHsNCiAgICANCiAgICAgIGNhdChzcHJpbnRmKCJUaGlzIHBvcnRpb24gb2YgdGhlIGNvZGUgcmVxdWlyZXMgdGhlICVzIGxpYnJhcnlcbkl0IGRvZXNuJ3QgbG9vayBsaWtlIHlvdSBoYXZlIGl0IGluc3RhbGxlZFxuV291bGQgeW91IGxpa2UgdG8gaW5zdGFsbCBpdCBub3c/IiwgDQogICAgICAgICAgICAgIHBhY2thZ2UpKQ0KICAgIA0KICAgICAgcmVzcG9uc2UgPC0gcmVhZGxpbmUocHJvbXB0ID0gIkVudGVyIFkgb3IgTjogIikNCiAgICANCiAgICAgIGlmKHRvdXBwZXIocmVzcG9uc2UpID09ICJZIikgew0KICAgICAgICBpbnN0YWxsLnBhY2thZ2VzKHBhY2thZ2UpDQogICAgICAgIGxpYnJhcnkocGFja2FnZSwgY2hhcmFjdGVyLm9ubHkgPSBUKQ0KICAgICAgICByZXR1cm4oY2F0KCJJbnN0YWxsZWQgYW5kIGxvYWRlZCBwYWNrYWdlIikpDQogICAgICB9DQogICAgICANCiAgICAgIGlmKHRvdXBwZXIocmVzcG9uc2UpID09ICJOIikgcmV0dXJuKGNhdCgiUGFja2FnZSBub3QgaW5zdGFsbGVkIikpDQogIH0gZWxzZQ0KICAgIHJldHVybihsaWJyYXJ5KHBhY2thZ2UsIGNoYXJhY3Rlci5vbmx5ID0gVCkpDQp9DQoNCiMgRG93bmxvYWRpbmcvbG9hZGluZyB0aGUgZGF0YSBmaWxlIGFuZCBkaWN0aW9uYXJ5DQpsaWJfbG9hZCgiZGF0YS50YWJsZSIpDQpsaWJfbG9hZCgib3Blbnhsc3giKQ0KbGliX2xvYWQoImRwbHlyIikNCg0KaWYoIWFsbChjKCJMb2FuU3RhdHNfMjAxN1ExLmNzdiIsIkxDRGF0YURpY3Rpb25hcnkueGxzeCIpICVpbiUgbGlzdC5maWxlcygiLi4vRGF0YSIpKSkgew0KDQogIGNhdCgiRG93bmxvYWRpbmcgYW5kIHJlYWRpbmcgaW4gZGF0YSIpDQogIA0KICAjIEdldHRpbmcgdGhlIGRhdGEgZmlsZXMNCiAgdGVtcCA8LSB0ZW1wZmlsZSgpDQogIGRvd25sb2FkLmZpbGUoImh0dHBzOi8vcmVzb3VyY2VzLmxlbmRpbmdjbHViLmNvbS9Mb2FuU3RhdHNfMjAxN1ExLmNzdi56aXAiLCB0ZW1wLCBtb2RlID0gIndiIikNCiAgdW56aXAoemlwZmlsZSA9IHRlbXAsIGZpbGVzID0gIkxvYW5TdGF0c18yMDE3UTEuY3N2IiwgZXhkaXIgPSAiLi4vRGF0YSIpDQogIGxvYW5fZGF0YSA8LSBmcmVhZCgiLi4vRGF0YS9Mb2FuU3RhdHNfMjAxN1ExLmNzdiIsIGRhdGEudGFibGUgPSBGKTsgcm0odGVtcCkNCg0KICBkb3dubG9hZC5maWxlKCJodHRwczovL3Jlc291cmNlcy5sZW5kaW5nY2x1Yi5jb20vTENEYXRhRGljdGlvbmFyeS54bHN4IiwgDQogICAgICAgICAgICAgICAgIi4uL0RhdGEvTENEYXRhRGljdGlvbmFyeS54bHN4IiwgbWV0aG9kID0gImN1cmwiKQ0KICANCiAgIyBEb3dubG9hZGluZyBhbmQgY29tYmluaW5nIHRoZSBkYXRhIGRpY3Rpb25hcnkgc3ByZWFkc2hlZXQNCiAgZGF0YV9kaWN0IDwtIGxpc3QocmVhZC54bHN4KCIuLi9EYXRhL0xDRGF0YURpY3Rpb25hcnkueGxzeCIsIHNoZWV0ID0gMSksDQogICAgICAgICAgICAgICAgICAgICByZWFkLnhsc3goIi4uL0RhdGEvTENEYXRhRGljdGlvbmFyeS54bHN4Iiwgc2hlZXQgPSAyKSwNCiAgICAgICAgICAgICAgICAgICAgIHJlYWQueGxzeCgiLi4vRGF0YS9MQ0RhdGFEaWN0aW9uYXJ5Lnhsc3giLCBzaGVldCA9IDMpKQ0KICANCiAgZGF0YV9kaWN0IDwtIGxhcHBseShkYXRhX2RpY3QsIGZ1bmN0aW9uKGRmKSB7IA0KICAgICAgICBjb2xuYW1lcyhkZikgPC0gYygidmFyIiwiZGVzYyIpIA0KICAgICAgICByZXR1cm4oZGYpDQogICAgICB9KSAlPiUgcmJpbmRsaXN0KCkgJT4lIHVuaXF1ZSgpDQogIA0KfSBlbHNlIHsNCiAgDQogIGNhdCgiTG9hZGluZyBpbiB0aGUgZGF0YSIpDQogIA0KICBsb2FuX2RhdGEgPC0gZnJlYWQoIi4uL0RhdGEvTG9hblN0YXRzXzIwMTdRMS5jc3YiLCBkYXRhLnRhYmxlID0gRikNCiAgDQogIGRhdGFfZGljdCA8LSBsaXN0KHJlYWQueGxzeCgiLi4vRGF0YS9MQ0RhdGFEaWN0aW9uYXJ5Lnhsc3giLCBzaGVldCA9IDEpLA0KICAgICAgICAgICAgICAgICAgIHJlYWQueGxzeCgiLi4vRGF0YS9MQ0RhdGFEaWN0aW9uYXJ5Lnhsc3giLCBzaGVldCA9IDIpLA0KICAgICAgICAgICAgICAgICAgIHJlYWQueGxzeCgiLi4vRGF0YS9MQ0RhdGFEaWN0aW9uYXJ5Lnhsc3giLCBzaGVldCA9IDMpKQ0KICANCiAgZGF0YV9kaWN0IDwtIGxhcHBseShkYXRhX2RpY3QsIGZ1bmN0aW9uKGRmKSB7IA0KICAgICAgICBjb2xuYW1lcyhkZikgPC0gYygidmFyIiwiZGVzYyIpIA0KICAgICAgICByZXR1cm4oZGYpDQogICAgICB9KSAlPiUgcmJpbmRsaXN0KCkgJT4lIHVuaXF1ZSgpDQp9DQoNCiMjIEJhc2ljIGRhdGEgc2NydWJiaW5nIGFoZWFkIG9mIGFuYWx5c2lzICMjDQoNCiMgRHJvcHBpbmcgYmxhbmsgb3IgcmVkYWN0ZWQgY29sdW1ucw0KbG9hbl9kYXRhWyxjKCJpZCIsIm1lbWJlcl9pZCIsInVybCIsImRlc2MiLCJ6aXBfY29kZSIsInBvbGljeV9jb2RlIildID0gTlVMTA0KDQojIEV4dHJhY3RpbmcgbnVtYmVycyBvdXQgb2Ygc3RyaW5ncyBhbmQgY29udmVydGluZyB0byB0aGUgbnVtZXJpYyB0eXBlDQpsb2FuX2RhdGFbLGMoImludF9yYXRlIiwicmV2b2xfdXRpbCIpXSA8LSBzYXBwbHkobG9hbl9kYXRhWyxjKCJpbnRfcmF0ZSIsInJldm9sX3V0aWwiKV0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KIGZ1bmN0aW9uKG1peGVkX3N0cmluZykgew0KICAgDQogIGdzdWIocGF0dGVybiA9ICJbXlxcZHwuXSsiLCByZXBsYWNlbWVudCA9ICIiLCB4ID0gbWl4ZWRfc3RyaW5nLCBwZXJsID0gVFJVRSkgJT4lIGFzLm51bWVyaWMoKQ0KICANCn0pDQoNCiMgTWFraW5nIGV2ZXJ5IG90aGVyIG5vbi1zdHJpbmcgYSBudW1lcmljIHZhbHVlDQpsb2FuX2RhdGFbLGMoMTozLDUsNiwxMiwyMCwyMSwyMzozMCwzMjo0MCw0Miw0NTo0Niw0ODo0OSw1MjoxMDYsMTA4OjExNildIDwtIA0KICBsb2FuX2RhdGFbLGMoMTozLDUsNiwxMiwyMCwyMSwyMzozMCwzMjo0MCw0Miw0NTo0Niw0ODo0OSw1MjoxMDYsMTA4OjExNildICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgIHNhcHBseShhcy5udW1lcmljKSANCg0KIyBUcmltbWluZyBsZWFkaW5nIGFuZCB0cmFpbGluZyB3aGl0ZXNwYWNlIGZyb20gY2hhcmFjdGVyIHZlY3RvcnMNCmxvYW5fZGF0YVssdW5saXN0KGxhcHBseShsb2FuX2RhdGEsY2xhc3MpKSA9PSAiY2hhcmFjdGVyIl0gPSBzYXBwbHkobG9hbl9kYXRhWyx1bmxpc3QobGFwcGx5KGxvYW5fZGF0YSxjbGFzcykpID09ICJjaGFyYWN0ZXIiXSwgdHJpbXdzKQ0KDQojIEdyYWJiaW5nIGFsbCBvZiB0aGUgY29sdW1uIGNsYXNzZXMNCmNvbF9jbGFzc2VzIDwtIHRhYmxlKHVubGlzdChsYXBwbHkobG9hbl9kYXRhLGNsYXNzKSkpDQpgYGANCg0KIyMgSW50cm9kdWN0aW9uDQoNCltMZW5kaW5nIENsdWJdKGh0dHBzOi8vd3d3LmxlbmRpbmdjbHViLmNvbS8pIGlzIGEgcGVlci10by1wZWVyIGxlbmRpbmcgY29tcGFueSB0aGF0IG1hdGNoZXMgYm9ycm93ZXJzIHdpdGggaW52ZXN0b3JzIHRocm91Z2ggYW4gb25saW5lIHBsYXRmb3JtLiBJdCBzZXJ2aWNlcyBwZW9wbGUgdGhhdCBuZWVkIHBlcnNvbmFsIGxvYW5zIGJldHdlZW4gJDEsMDAwIGFuZCAkNDAsMDAwLiBCb3Jyb3dlcnMgcmVjZWl2ZSB0aGUgZnVsbCBhbW91bnQgb2YgdGhlIGlzc3VlZCBsb2FuIG1pbnVzIHRoZSBvcmlnaW5hdGlvbiBmZWUsIHdoaWNoIGlzIHBhaWQgdG8gdGhlIGNvbXBhbnkuIEludmVzdG9ycyBwdXJjaGFzZSBub3RlcyBiYWNrZWQgYnkgdGhlIHBlcnNvbmFsIGxvYW5zIGFuZCBwYXkgTGVuZGluZyBDbHViIGEgc2VydmljZSBmZWUuIFRoZSBjb21wYW55IHNoYXJlcyBkYXRhIGFib3V0IGFsbCBsb2FucyBpc3N1ZWQgdGhyb3VnaCBpdHMgcGxhdGZvcm0gZHVyaW5nIGNlcnRhaW4gdGltZSBwZXJpb2RzLiANCg0KVGhpcyBhbmFseXNpcyB3aWxsIGZvY3VzIG9uIHRoZSBMZW5kaW5nIENsdWIgW0xvYW4gRGF0YV0oaHR0cHM6Ly93d3cubGVuZGluZ2NsdWIuY29tL2luZm8vZG93bmxvYWQtZGF0YS5hY3Rpb24pIGZyb20gdGhlIGZpcnN0IHF1YXJ0ZXIgb2YgMjAxNy4gVGhpcyBkb2N1bWVudCBpcyBnZW5lcmF0ZWQgdXNpbmcgW1IgTWFya2Rvd25dKGh0dHA6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20vKS4gVGhlIGNvZGUgdGhhdCBwb3dlcnMgdGhlIGFuYWx5c2lzIGlzIGhpZGRlbiBieSBkZWZhdWx0IGJ1dCB5b3UgY2FuIGV4cGFuZCBhbnkgc2VjdGlvbiBieSBjbGlja2luZyB0aGUgKipDb2RlKiogYnV0dG9uLCBsaWtlIHRoZSBvbmUgaW4gdGhlIHRvcCByaWdodCBjb3JuZXIgb2YgdGhpcyBzZWN0aW9uLiBTbyBmYXIgSSBoYXZlIGxvYWRlZCBpbiB0aGUgYWN0dWFsIGRhdGEgZmlsZSBhbmQgdGhlIGRhdGEgZGljdGlvbmFyeS4gSSBhbHNvIHBlcmZvcm1lZCBzb21lIG1pbm9yIGZvcm1hdHRpbmcgdG8gcHJlcGFyZSBmb3IgdGhlIHJlc3Qgb2YgdGhlIGFuYWx5c2lzLg0KDQpXZSdsbCBzdGFydCBvZmYgYnkgcnVubmluZyBzb21lIGJyb2FkIHN1bW1hcnkgc3RhdGlzdGljcyBhbmQgdXNpbmcgdGhpcyBpbmZvcm1hdGlvbiB0byBjbGVhbiB1cCB0aGUgZGF0YSBzZXQuIE9uY2UgdGhlIGRhdGEgYXJlIHJlYXNvbmFibHkgZm9ybWF0dGVkIHdlIHdpbGwgbW92ZSBvbiB0byB2aXN1YWxpemluZyB0aGUgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIHRoZSB2YXJpYWJsZXMuDQoNCiMjIEJyb2FkIFN1bW1hcnkgU3RhdGlzdGljcyBhbmQgU2NydWJiaW5nDQoNCkJlZm9yZSB3ZSBzdGFydCBhbnkgYW5hbHlzaXMgb3IgZGF0YSBzY3J1YmJpbmcsIGxldCdzIGpvaW4gaW4gdGhlIFtkYXRhIGRpY2lvbmFyeV0oaHR0cHM6Ly9yZXNvdXJjZXMubGVuZGluZ2NsdWIuY29tL0xDRGF0YURpY3Rpb25hcnkueGxzeCkgc28gd2UgY2FuIGhhdmUgYSBxdWljayByZWZlcmVuY2UgdG8gd2hhdCB0aGUgdmFyaWFibGVzIGFjdHVhbGx5IG1lYW46DQoNCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0NCiMgRXh0cmFjdGluZyBhbGwgZGF0YSBjb2x1bW4gbmFtZXMgYW5kIGpvaW5pbmcgdG8gZGF0YSBkaWN0aW9uYXJ5DQpsb2FuX2RhdGFfY29scyA8LSBkYXRhLmZyYW1lKFZhcmlhYmxlID0gY29sbmFtZXMobG9hbl9kYXRhKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEYpDQoNCmRhdGFfZGljdCR2YXIgPC0gdHJpbXdzKGRhdGFfZGljdCR2YXIpDQoNCm1hcHBpbmcgPC0gbG9hbl9kYXRhX2NvbHMgJT4lIGxlZnRfam9pbihkYXRhX2RpY3QsIGJ5ID0gYygiVmFyaWFibGUiID0gInZhciIpKQ0KDQpjb2xuYW1lcyhtYXBwaW5nKVsyXSA8LSAiRnVsbCBEZXNjcmlwdGlvbiINCg0KIyBGb3JtYXR0aW5nIGludG8gaW50ZXJhY3RpdmUgSFRNTCB0YWJsZQ0KbGliX2xvYWQoIkRUIikNCg0KbWFwcGluZyA8LSBzYXBwbHkobWFwcGluZywgdHJpbXdzKQ0KDQpkYXRhdGFibGUobWFwcGluZykNCmBgYA0KPGJyPjxicj4NCldlJ2xsIHN0YXJ0IGJ5IHRha2luZyBhIGJyb2FkIGxvb2sgYXQgdGhlIGRpZmZlcmVudCB2YXJpYWJsZSB0eXBlcyBpbiB0aGUgZGF0YSBzZXQuIEFmdGVyIGRyb3BwaW5nIHNvbWUgZW1wdHkgYW5kIHJlZGFjdGVkIGNvbHVtbnMgd2UgYXJlIGxlZnQgd2l0aCBgciBkaW0obG9hbl9kYXRhKVsyXWAgdmFyaWFibGVzIGluIHRvdGFsLiBUaGVyZSBhcHBlYXIgdG8gYmUgYHIgY29sX2NsYXNzZXNbJ251bWVyaWMnXWAgY29udGludW91cyB2YXJpYWJsZXMgYW5kIGByIGNvbF9jbGFzc2VzWydjaGFyYWN0ZXInXWAgY2F0ZWdvcmljYWwgdmFyaWFibGVzLiBMZXQncyBydW4gc29tZSBzdW1tYXJ5IHN0YXRpc3RpY3Mgb24gdGhlICoqY29udGludW91cyB2YXJpYWJsZXMqKjoNCg0KYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQ0KIyBHcmFiYmluZyBjb2x1bW4gdHlwZXMgdG8gc2VlIGlmIHRoZXkgYXJlIGNhdGVnb3JpY2FsIG9yIGNvbnRpdW5vdXMNCmFsbF92YXJzIDwtIHVubGlzdChsYXBwbHkobG9hbl9kYXRhLGNsYXNzKSkNCg0KIyBFbnRlcnMgemVybyBOQXMgZm9yIHN1bW1hcnkgd2hlbiB0aGVyZSBhcmUgbm9uZSBzbyB0aGUgc3VtbWFyeSBkYXRhIHN0cnVjdHVyZXMgY2FuIGJlIGNvbWJpbmVkDQojIEJvcnJvd2VkIGZyb206IGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzMyMDExODczL2ZvcmNlLXN1bW1hcnktdG8tcmVwb3J0LXRoZS1udW1iZXItb2YtbmFzLWV2ZW4taWYtbm9uZQ0KY3VzdG9tX3N1bW1hcnkgPC0gZnVuY3Rpb24odmFyKSB7DQogIA0KICBpZighYW55KGlzLm5hKHZhcikpKSB7DQogICAgcmVzIDwtIGMoc3VtbWFyeSh2YXIpLCJOQSdzIj0wKQ0KICB9IGVsc2Ugew0KICAgIHJlcyA8LSBzdW1tYXJ5KHZhcikNCiAgfQ0KICByZXR1cm4ocmVzKQ0KfQ0KDQojIEV4dHJhY3RpbmcgY29udGludW91cyB2YXJpYWJsZXMNCmNvbnRfaW5mbyA8LSBsYXBwbHkobG9hbl9kYXRhWyxhbGxfdmFycyA9PSAibnVtZXJpYyJdLCBjdXN0b21fc3VtbWFyeSkgDQoNCiMgRm9ybWF0dGluZyBzdW1tYXJpZXMgaW50byB1bmlmb3JtIGRhdGEgc3RydWN0dXJlIGFuZCBjb21iaW5pbmcNCmNvbnRfbmFtZXMgPC0gbmFtZXMoYWxsX3ZhcnNbYWxsX3ZhcnMgPT0gIm51bWVyaWMiXSkNCg0KY29udF9pbmZvIDwtIGxhcHBseSgxOmxlbmd0aChjb250X2luZm8pLCBmdW5jdGlvbihpbngpIHsNCiAgDQogIG5ld192ZWN0IDwtIGMoY29udF9uYW1lc1tpbnhdLHJvdW5kKGNvbnRfaW5mb1tbaW54XV0sMikpDQogIA0KICBuYW1lcyhuZXdfdmVjdClbMV0gPC0gIlZhciBOYW1lIg0KICANCiAgbmV3X3ZlY3QNCiAgDQp9KTsgY29udF9pbmZvIDwtIGRvLmNhbGwocmJpbmQsY29udF9pbmZvKQ0KDQojIEZvcm1hdHRpbmcgaW50byBpbnRlcmFjdGl2ZSBIVE1MIHRhYmxlDQpkYXRhdGFibGUoY29udF9pbmZvKQ0KYGBgDQo8YnI+PGJyPiAgIA0KDQpXZSBzZWUgc2V2ZXJhbCB2YXJpYWJsZXMgdGhhdCBkZXNjcmliZSB0aGUgbG9hbiBzdWNoIGFzIHRoZSBhbW91bnQsIHBheW1lbnQsIGludGVyZXN0IHJhdGUsIGFuZCB0ZXJtLiBXZSBhbHNvIHNlZSBzb21lIGRlc2NyaXB0aXZlIGluZm9ybWF0aW9uIG9uIHRoZSBib3Jyb3dlciBzdWNoIGFzIGFubnVhbCBpbmNvbWUsIGRlYnQtdG8taW5jb21lIHJhdGlvIChEVEkpLCBudW1iZXIgb2YgbW9ydGdhZ2UgYWNjb3VudHMsIGFuZCB0b3RhbCBjcmVkaXQgbGltaXQuIEl0IGxvb2tzIGxpa2UgKmR0aSosICpyZWNvdmVyaWVzKiwgYW5kICpjb2xsZWN0aW9uX3JlY292ZXJ5X2ZlZSogaGF2ZSBzb21lIGRhdGEgaXNzdWVzLiBUaGUgbGF0dGVyIHR3byBhcmUgYmxhbmsgdGhyb3VnaG91dCB0aGUgZW50aXJlIGRhdGEgc2V0LiBUaGUgbWluaW11bSBhbmQgbWF4aW11bSB2YWx1ZXMgb24gKmR0aSogc2VlbSBjb21wbGV0ZWx5IG9mZi4gV2UgY2FuIHBsb3QgdGhlIGhpc3RvZ3JhbXMgb2YgdmFyaW91cyAqZHRpKiByYW5nZXMgdG8gZ2V0IG1vcmUgcmVhc29uYWJsZSBib3VuZHMgZm9yIHRoZSBkYXRhOiAgDQoNCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgZmlnLndpZHRoID0gOSwgZmlnLmhlaWdodCA9IDUsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQ0KIyBGaXJzdCBjbGVhbmluZyB1cCB0aGUgYmxhbmsgdmFyaWFibGVzDQpsb2FuX2RhdGFbLGMoInJlY292ZXJpZXMiLCJjb2xsZWN0aW9uX3JlY292ZXJ5X2ZlZSIpXSA9IE5VTEwNCg0KIyBQbG90dGluZyB0aGUgZGVuc2l0eSBvZiBkdGkgdW5kZXIgdmFyaW91cyBjdXQtb2Zmcw0KZHRpX3JhdyA8LSBsb2FuX2RhdGEkZHRpDQoNCmxpYl9sb2FkKCJnZ3Bsb3QyIikNCg0KZGVuczEgPC0gcXBsb3QoZHRpX3JhdywgZmlsbCA9IEkoImRvZGdlcmJsdWU0IiksIA0KICAgICAgICAgICAgICAgYWxwaGEgPSBJKDAuNCksIGNvbCA9IEkoImdyZXkyOSIpKSArIHhsYWIoImR0aSBmdWxsIHJhbmdlIikgKyB5bGFiKCJDb3VudCIpDQoNCmRlbnMyIDwtIHFwbG90KGR0aV9yYXdbZHRpX3JhdyA+IDAgJiBkdGlfcmF3IDwgMTVdLCBmaWxsID0gSSgiZG9kZ2VyYmx1ZTQiKSwgDQogICAgICAgICAgICAgICBhbHBoYSA9IEkoMC40KSwgY29sID0gSSgiZ3JleTI5IikpICsgeGxhYigiMCA8IGR0aSA8IDE1IikgKyB5bGFiKCJDb3VudCIpDQoNCmRlbnMzIDwtIHFwbG90KGR0aV9yYXdbZHRpX3JhdyA+IDAgJiBkdGlfcmF3IDwgNTBdLCBmaWxsID0gSSgiZG9kZ2VyYmx1ZTQiKSwgDQogICAgICAgICAgICAgICBhbHBoYSA9IEkoMC43KSwgY29sID0gSSgiZ3JleTI5IikpICsgeGxhYigiMCA8IGR0aSA8IDUwIikgKyB5bGFiKCJDb3VudCIpDQoNCmRlbnM0IDwtIHFwbG90KGR0aV9yYXdbZHRpX3JhdyA+IDUwICYgZHRpX3JhdyA8IDk5OTldLCBmaWxsID0gSSgiZG9kZ2VyYmx1ZTQiKSwgDQogICAgICAgICAgICAgICBhbHBoYSA9IEkoMC40KSwgY29sID0gSSgiZ3JleTI5IikpICsgeGxhYigiNTAgPCBkdGkgPCA5OTk5IikgKyB5bGFiKCJDb3VudCIpDQoNCiMgQ29tYmluaW5nIGRlbnNpdHkgcGxvdHMNCmxpYl9sb2FkKCJncmlkRXh0cmEiKQ0KbGliX2xvYWQoImdyaWQiKQ0KDQojIFN1YmplY3RpdmVseSBjbGlwcGluZyByYW5nZSBvZiBkdGkNCmdyaWQuYXJyYW5nZShkZW5zMSwgZGVuczIsIGRlbnMzLCBkZW5zNCwNCiAgICAgICAgICAgICB0b3AgPSB0ZXh0R3JvYigiRFRJIEhpc3RvZ3JhbXMgKDMwIGJpbnMpIiksIA0KICAgICAgICAgICAgIHdpZHRocyA9IGMoNCw0KSwgaGVpZ2h0cyA9IGMoNCw0KSkNCg0KIyBDbGlwcGluZyB0aGUgcmFuZ2UgZm9yIGR0aQ0KbG9hbl9kYXRhJGR0aVtsb2FuX2RhdGEkZHRpIDwgMCB8IGxvYW5fZGF0YSRkdGkgPiA1MF0gPSBOQQ0KYGBgDQo8YnI+PGJyPg0KDQpLZWVwaW5nIHRoZSBmdWxsIHJhbmdlIGZvciAqZHRpKiBkb2Vzbid0IHNlZW0gdG8gbWFrZSBzZW5zZS4gVGhlIGxvd2VyIGJvdW5kIHNob3VsZCBhbHdheXMgYmUgemVybyBzaW5jZSB5b3UgY2FuJ3QgaGF2ZSBsZXNzIHRoYW4gbm8gZGVidC4gVGhlIHVwcGVyIGJvdW5kIGlzIGEgYml0IGRlYmF0YWJsZS4gSXQgYXBwZWFycyB0aGF0IHRoZSBtYWpvcml0eSBvZiB0aGUgZGVuc2l0eSBpcyBjYXB0dXJlZCBiZXR3ZWVuIDAgYW5kIDUwLCB3aGljaCBzZWVtcyB0byBiZSByZWFzb25hYmxlLiBXZSBjYW4gc3ViamVjdGl2ZWx5IGRyb3AgZXZlcnl0aGluZyBvdXRzaWRlIG9mIHRoaXMgcmFuZ2UgYW5kIGNvbnZlcnQgdGhvc2UgZW50cmllcyB0byBtaXNzaW5nIHZhbHVlcywgd2hpY2ggYXJlIHJlcHJlc2VudGVkIGFzICoqTkEqKiBpbiB0aGUgUiBsYW5ndWFnZS4gVGhpcyByZXN1bHRzIGluIGByIHN1bShpcy5uYShsb2FuX2RhdGEkZHRpKSlgIG1pc3NpbmcgZW50cmllcy4NCg0KTmV4dCwgbGV0J3MgdGFrZSBhIGxvb2sgYXQgdGhlICoqY2F0ZWdvcmljYWwgdmFyaWFibGVzKiouIFdlJ2xsIGNvdW50IHRoZSBmcmVxdWVuY2llcyBmb3IgdGhlIHRvcCBmb3VyIGNhdGVnb3JpZXMgZm9yIGVhY2ggdmFyaWFibGUgYW5kIGx1bXAgZXZlcnl0aGluZyBlbHNlIGludG8gYSBmaWZ0aCBjYXRlZ29yeSBjYWxsZWQgKk90aGVyKi4gSWYgdGhlcmUgYXJlIGxlc3MgdGhhbiBmb3VyIGNhdGVnb3JpZXMgdGhlbiB3ZSdsbCBqdXN0IHNob3cgYWxsIG9mIHRoZSBjb3VudHMuDQoNCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0NCiMgRXh0cmFjdGluZyBjYXRlZ29yaWNhbCB2YXJpYWJsZXMNCmNhdF9pbmZvIDwtIGxhcHBseSgxOnN1bShhbGxfdmFycyA9PSAiY2hhcmFjdGVyIiksIGZ1bmN0aW9uKGlueCkgew0KICANCiAgQ2F0ZWdvcnkgPC0gbG9hbl9kYXRhWyxuYW1lcyhhbGxfdmFyc1thbGxfdmFycyA9PSAiY2hhcmFjdGVyIl0pW2lueF1dDQogIA0KICAjIEdldHRpbmcgZnJlcXVlbmN5IGNvdW50cyBhbmQgc29ydGluZyBpbiBkZWNyZWFzaW5nIG9yZGVyDQogIGNvdW50c19kZiA8LSBkYXRhLmZyYW1lKHRhYmxlKENhdGVnb3J5KSkgJT4lIGFycmFuZ2UoZGVzYyhGcmVxKSkNCiAgY291bnRzX2RmJENhdGVnb3J5IDwtIGFzLmNoYXJhY3Rlcihjb3VudHNfZGYkQ2F0ZWdvcnkpDQogIA0KICAjIFN1bW1hcml6aW5nIG9ubHkgdG9wIDQgY291bnRzIGFuZCBsdW1waW5nIGV2ZXJ5dGhpbmcgaW50byBhIGZpZnRoIGNhdGVnb3J5LCBPdGhlcg0KICBpZihucm93KGNvdW50c19kZikgPiA1KSB7DQogICAgDQogICBjb3VudHNfZGYkRnJlcVs1XSA8LSBzdW0oY291bnRzX2RmJEZyZXFbNTpucm93KGNvdW50c19kZildKQ0KICAgY291bnRzX2RmJENhdGVnb3J5WzVdIDwtICJPdGhlciINCiAgIA0KICAgY291bnRzX2RmIDwtIGNvdW50c19kZlsxOjUsXQ0KICB9IA0KICAgIA0KICBkZiA8LSBkYXRhLmZyYW1lKE5hbWUgPSBuYW1lcyhhbGxfdmFyc1thbGxfdmFycyA9PSAiY2hhcmFjdGVyIl0pW2lueF0sDQogICAgICAgICAgICAgICAgICAgY291bnRzX2RmLCBzdHJpbmdzQXNGYWN0b3JzID0gRikNCg0KICBkZiRgRnJlcSAlYCA8LSByb3VuZCgxMDAqZGYkRnJlcS9zdW0oZGYkRnJlcSkpDQogIA0KICBkZg0KICANCn0pICU+JSBiaW5kX3Jvd3MoKQ0KDQojIFNhdmluZyBleGFtcGxlIG9mIGFuIGluY29ycmVjdGx5IHRhZ2dlZCBOQQ0KYmFkX3JvdyA8LSB3aGljaChsb2FuX2RhdGEkZW1wX3RpdGxlID09ICIuIikNCg0KIyBGb3JtYXR0aW5nIGludG8gaW50ZXJhY3RpdmUgSFRNTCB0YWJsZQ0KZGF0YXRhYmxlKGNhdF9pbmZvKQ0KYGBgDQo8YnI+PGJyPg0KDQpXZSBzZWUgc29tZSBkZXNjcmlwdGl2ZSBpbmZvcm1hdGlvbiBvbiB0aGUgbG9hbnMgc3VjaCBhcyB0aGUgdGVybSwgZ3JhZGUsIGFuZCBwdXJwb3NlLiBUaGVyZSBhcmUgYWxzbyBzb21lIHZhcmlhYmxlcyB0aGF0IGRlc2NyaWJlIHRoZSBib3Jyb3dlciBzdWNoIGFzIGVtcGxveW1lbnQgdGl0bGUsIHN0YXRlIG9mIHJlc2lkZW5jZSwgYW5kIG51bWJlciBvZiBhY2NvdW50cyBjdXJyZW50bHkgZGVsaW5xdWVudC4gQ29sdW1ucyBsaWtlICplYXJsaWVzdF9jcl9saW5lKiBjYW4gYmUgY29udmVydGVkIHRvIGFuIGludGVnZXIgdGhhdCByZXByZXNlbnRzIHRoZSB5ZWFycyBzaW5jZSB0aGF0IGRhdGUsIHdoaWNoIHdvdWxkIGJlIG1vcmUgdXNlZnVsIGZvciBtb2RlbGluZyBsYXRlci4gVGhlcmUgYXJlIGFsc28gZW50cmllcyB0aGF0IGFyZSB0YWdnZWQgYXMgZW1wdHkgc3BhY2VzIG9yIGRvdHMgdGhhdCBzaG91bGQgcmVhbGx5IGJlICoqTkEqKi4gQW4gZXhhbXBsZSBpcyByb3cgYHIgYmFkX3Jvd2AgZm9yICplbXBfdGl0bGUqLCB3aGljaCBpcyB0YWdnZWQgYXMgYSBwZXJpb2QuIExldCdzIGNsZWFuIHRoZXNlIHVwLiANCg0KYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQ0KIyBGaXhpbmcgZGF0ZSBjb2x1bW5zDQpsaWJfbG9hZCgibHVicmlkYXRlIikNCmxpYl9sb2FkKCJ6b28iKQ0KDQojIEVhcmxpZXN0IGNyZWRpdCBsaW5lIGlzIG5vdyB0aGUgeWVhcnMgc2luY2UgdGhlIGdpdmVuIGRhdGUNCmxvYW5fZGF0YSRlYXJsaWVzdF9jcl9saW5lIDwtIGRpZmZ0aW1lKGFzLnllYXJtb24obG9hbl9kYXRhJGlzc3VlX2QsIGZvcm1hdCA9ICIlYi0lWSIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXMueWVhcm1vbihsb2FuX2RhdGEkZWFybGllc3RfY3JfbGluZSwgZm9ybWF0ID0gIiViLSVZIiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5pdCA9ICJ3ZWVrcyIpLzUyLjI1DQoNCmxvYW5fZGF0YSRlYXJsaWVzdF9jcl9saW5lIDwtIGFzLm51bWVyaWMobG9hbl9kYXRhJGVhcmxpZXN0X2NyX2xpbmUpDQoNCmxvYW5fZGF0YSRzZWNfYXBwX2VhcmxpZXN0X2NyX2xpbmUgPC0gZGlmZnRpbWUoYXMueWVhcm1vbihsb2FuX2RhdGEkaXNzdWVfZCwgZm9ybWF0ID0gIiViLSVZIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLnllYXJtb24obG9hbl9kYXRhJHNlY19hcHBfZWFybGllc3RfY3JfbGluZSwgZm9ybWF0ID0gIiViLSVZIiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bml0ID0gIndlZWtzIikvNTIuMjUNCg0KbG9hbl9kYXRhJHNlY19hcHBfZWFybGllc3RfY3JfbGluZSA8LSBhcy5udW1lcmljKGxvYW5fZGF0YSRzZWNfYXBwX2VhcmxpZXN0X2NyX2xpbmUpDQoNCiMgRHJvcHBpbmcgY29sdW1ucyB0aGF0IGRvbid0IHJlYWxseSBhZGQgYW55IGluZm8NCmxvYW5fZGF0YVssYygicHltbnRfcGxhbiIpXSA9IE5VTEwNCg0KIyBDb2VyY2luZyB2YXJpb3VzIGVudHJpZXMgdG8gTkENCmxvYW5fZGF0YVtsb2FuX2RhdGEgPT0gIiIgfCBsb2FuX2RhdGEgPT0gIi4iXSA8LSBOQQ0KYGBgDQo8YnI+PGJyPg0KDQpOb3cgdGhhdCB3ZSBoYXZlIGNsZWFuZWQgdXAgdGhlIHZhcmlhYmxlcyBhbmQgY29ycmVjdGx5IHRhZ2dlZCBtaXNzaW5nIHZhbHVlcyBhcyAqKk5BKiosIGxldCdzIHRha2UgYSBsb29rIGF0IHRoZSBzcGFyc2l0eSBvZiB2YXJpb3VzIGNvbHVtbnMuIE1pc3NpbmcgZGF0YSBjYW4gaGF2ZSBzdHJvbmcgaW1wYWN0cyBvbiBwcmVkaWN0aXZlIGFuZCBpbmZlcmVudGlhbCBhbmFseXNpcy4gSXQncyBpbXBvcnRhbnQgdG8gdW5kZXJzdGFuZCBhbnkgcGF0dGVybnMgaW4gdGhlIHNwYXJzaXR5LCBzb21ldGltZXMgZHJvcHBpbmcgaW5jb21wbGV0ZSBvYnNlcnZhdGlvbnMgY2FuIGxlYWQgdG8gYSBiaWFzZWQgdW5kZXJzdGFuZGluZyBvZiB0aGUgZGF0YS4NCg0KYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQ0KIyBTdW1tYXJpemluZyB2YXJpYWJsZXMgd2l0aCBsb3RzIG9mIE5Bcw0Kc3BhcnNlX2NvdW50IDwtIGxhcHBseSgxOm5jb2wobG9hbl9kYXRhKSwgZnVuY3Rpb24oaW54KSB7DQoNCiAgdGVtcCA8LSBsb2FuX2RhdGFbLGlueF0NCiAgDQogIFZhcmlhYmxlID0gY29sbmFtZXMobG9hbl9kYXRhKVtpbnhdDQogIA0KICBgTkEgJWAgPSByb3VuZChzdW0oaXMubmEodGVtcCkpL2xlbmd0aCh0ZW1wKSoxMDAsMikNCiAgDQogIGBGdWxsIE5hbWVgID0gZGF0YV9kaWN0JGRlc2Nbd2hpY2goVmFyaWFibGUgPT0gZGF0YV9kaWN0JHZhcilbMV1dDQoNCiAgZGYgPC0gZGF0YS5mcmFtZShWYXJpYWJsZSxgTkEgJWAsYEZ1bGwgTmFtZWAsDQogICAgICAgICAgICAgICAgICAgY2hlY2submFtZXMgPSBGLA0KICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQ0KICANCiAgcmV0dXJuKGRmKQ0KfSkgJT4lIGJpbmRfcm93cygpICU+JSBhcnJhbmdlKGRlc2MoYE5BICVgKSkNCg0KIyBHcmFiYmluZyBhbnkgdmFyaWFibGUgd2l0aCBhdCBsZWFzdCBvbmUgTkENCnNwYXJzZV9jb3VudCA8LSBzcGFyc2VfY291bnRbc3BhcnNlX2NvdW50JGBOQSAlYCA+IDAsXQ0KDQpkYXRhdGFibGUoc3BhcnNlX2NvdW50KQ0KYGBgDQo8YnI+PGJyPg0KDQpJdCBsb29rcyBsaWtlIGEgbG90IG9mIHRoZSBtaXNzaW5nIHZhbHVlcyBhcmUgcmVsYXRlZCB0byB2YXJpYWJsZXMgdGhhdCBkZWFsIHdpdGggYSBzZWNvbmQgYXBwbGljYW50LiBJdCBkb2Vzbid0IHNlZW0gbGlrZSB0aGVzZSBhcmUgY3JpdGljYWwgdG8gZXhwbG9yYXRvcnkgYW5hbHlzaXMgb3IgaW5mZXJlbmNlIGJ1dCB3ZSBzaG91bGQgc3RpbGwga2VlcCB0aGVtIGluIG1pbmQuIFdlIGNvdWxkIGV4cGxvcmUgZGlmZmVyZW50IHdheXMgdG8gaW1wdXRlIHNvbWUgb2YgdGhlIG1pc3NpbmcgdmFsdWVzLCBlc3BlY2lhbGx5IGlmIHdlIHdhbnQgdG8gdXNlIHRoZSB2YXJpYWJsZXMgYXMgcGFydCBvZiBhIG1vZGVsIGZvciBjZXJ0YWluIHR5cGVzIG9mIGJvcnJvd2Vycy4NCg0KIyMgVmlzdWFsemluZyBEaXN0cmlidXRpb25zDQoNCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0NCiMgR2V0dGluZyByYXcgY291bnRzIG9mIGNvbnRpbnVvdXMgYW5kIGNhdGVnb3JpY2FsIHZhcnMsIHRoZW4gZ2V0dGluZyBmdWxseSBjb21wbGV0ZSBvbmVzIChubyBOQXMpDQpjb250IDwtIHNhcHBseShsb2FuX2RhdGEsIGNsYXNzKSA9PSAibnVtZXJpYyINCmNhdCA8LSBzYXBwbHkobG9hbl9kYXRhLCBjbGFzcykgPT0gImNoYXJhY3RlciINCg0KY29udF9mdWxsIDwtIHN1bSghKG5hbWVzKGNvbnRbY29udCA9PSBUUlVFXSkgJWluJSBzcGFyc2VfY291bnQkVmFyaWFibGUpKQ0KY2F0X2Z1bGwgPC0gc3VtKCEobmFtZXMoY2F0W2NhdCA9PSBUUlVFXSkgJWluJSBzcGFyc2VfY291bnQkVmFyaWFibGUpKQ0KYGBgDQoNCkF0IHRoaXMgcG9pbnQsIHdlJ3JlIGxlZnQgd2l0aCBgciBjb250X2Z1bGxgIGNvbnRpbnVvdXMgdmFyaWFibGVzIGFuZCBgciBjYXRfZnVsbGAgY2F0ZWdvcmljYWwgdmFyaWFibGVzIHdpdGggbm8gKipOQSoqcy4gVGhlIGZ1bGwgZGF0YSBzZXQgY29udGFpbnMgYHIgc3VtKGNvbnQpYCBjb250aW51b3VzIHZhcmlhYmxlcyBhbmQgYHIgc3VtKGNhdClgIGNhdGVnb3JpY2FsIHZhcmlhYmxlcy4gV2UndmUgYWxzbyBnb3QgYHIgbnJvdyhsb2FuX2RhdGEpYCBvYnNlcnZhdGlvbnMsIHdpdGggZWFjaCByb3cgcmVwcmVzZW50aW5nIGEgdW5pcXVlIGxvYW4uIEl0J3MgYSBiaXQgZGlmZmljdWx0IHRvIHRoaW5rIGFib3V0IHRoaXMgbXVjaCBkYXRhIGF0IG9uY2UuIEEgZ29vZCBmaXJzdCBzdGVwIGlzIHRvIGNyZWF0ZSBzb21lIHBsb3RzIHRvIGJldHRlciB1bmRlcnN0YW5kIHRoZSBtb3N0IGltcG9ydGFudCB2YXJpYWJsZXMuDQoNCkZpcnN0LCBsZXQncyB0cnkgdG8gYnJlYWsgb3V0IHRoZSB0b3RhbCBsb2FuIHZvbHVtZSBpbiB0aGUgZmlyc3QgcXVhcnRlciBvZiAyMDE3LiBMZXQncyBnZXQgYSBmZWVsIGZvciAqKndobyoqIGlzIGJvcnJvd2luZyB0aGUgbW9uZXksICoqd2hhdCoqIHRoZXkncmUgdXNpbmcgaXQgZm9yLCAqKndoZXJlKiogdGhleSBsaXZlLCBhbmQgdGhlaXIgKipyaXNrKiogcHJvZmlsZXMuDQoNCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgZmlnLndpZHRoID0gOSwgZmlnLmhlaWdodCA9IDUsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQ0KIyBDbGVhbmluZyB1cCByZWdpc3RlcmVkIG51cnNlIGRvdWJsZSBjb3VudGluZyBhY3Jvc3MgbG9hbl9kYXRhDQpsb2FuX2RhdGEkZW1wX3RpdGxlW2xvYW5fZGF0YSRlbXBfdGl0bGUgJWluJSBjKCJSTiIsIlJuIiwicm4iLCJudXJzZSIsIk51cnNlIildIDwtICJSZWdpc3RlcmVkIE51cnNlIg0KDQpsb2FuX2RhdGEkZW1wX3RpdGxlW2lzLm5hKGxvYW5fZGF0YSRlbXBfdGl0bGUpXSA8LSAiTm90IEF2YWlsYWJsZSINCg0KIyBBZ2dyZWdhdGluZyB1cCB0b3RhbCBsb2FucyBieSBlbXBfdGl0bGUNCmxvYW5fYnlfZW1wIDwtIGxvYW5fZGF0YSAlPiUgDQogICAgICAgICAgICAgICBncm91cF9ieShlbXBfdGl0bGUpICU+JSANCiAgICAgICAgICAgICAgIHN1bW1hcml6ZShgVG90YWwgTG9hbnMgKCQpYCA9IHN1bShsb2FuX2FtbnQpKSAlPiUNCiAgICAgICAgICAgICAgIGFycmFuZ2UoZGVzYyhgVG90YWwgTG9hbnMgKCQpYCkpDQoNCiMgR2V0dGluZyBwZXJjZW50YWdlIGluZm9ybWF0aW9uIHNpbmNlIHdlIGNhbiBvbmx5IHBsb3QgYSBzdWJzZXQNCmxvYW5fYnlfZW1wJGVtcF90aXRsZSA8LSBwYXN0ZTAobG9hbl9ieV9lbXAkZW1wX3RpdGxlLCIgLSAiLHBhc3RlMChyb3VuZCgxMDAqbG9hbl9ieV9lbXAkYFRvdGFsIExvYW5zICgkKWAvc3VtKGxvYW5fYnlfZW1wJGBUb3RhbCBMb2FucyAoJClgKSwxKSwiJSIpKQ0KDQpsb2FuX2J5X2VtcF9wbG90IDwtIGdncGxvdChsb2FuX2J5X2VtcFsxOjEwLF0sIGFlcyh4ID0gcmVvcmRlcihlbXBfdGl0bGUsLWBUb3RhbCBMb2FucyAoJClgKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gKGBUb3RhbCBMb2FucyAoJClgKS8xZTYsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IEkoImRvZGdlcmJsdWU0IiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IEkocmVwKDAuNywxMCkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gSSgiZ3JleTI5IikpKSArIA0KICAgICAgICAgICAgICAgICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKw0KICAgICAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDU1LCBoanVzdCA9IDEpKSArDQogICAgICAgICAgICAgICAgICAgIHhsYWIoIkpvYiBUaXRsZSAtICUgb2YgVG90YWwiKSArDQogICAgICAgICAgICAgICAgICAgIHlsYWIoIlRvdGFsIExvYW5zIC0gTWlsbGlvbnMgb2YgJCIpDQoNCiMgQWdncmVnYXRpbmcgdXAgYnkgcHVycG9zZQ0KbG9hbl9ieV9wdXJwIDwtIGxvYW5fZGF0YSAlPiUgDQogICAgICAgICAgICAgICAgZ3JvdXBfYnkodGl0bGUpICU+JSANCiAgICAgICAgICAgICAgICBzdW1tYXJpemUoYFRvdGFsIExvYW5zICgkKWAgPSBzdW0obG9hbl9hbW50KSkgJT4lDQogICAgICAgICAgICAgICAgYXJyYW5nZShkZXNjKGBUb3RhbCBMb2FucyAoJClgKSkNCg0KIyBHZXR0aW5nIHBlcmNlbnRhZ2UgaW5mb3JtYXRpb24NCmxvYW5fYnlfcHVycCR0aXRsZSA8LSBwYXN0ZTAobG9hbl9ieV9wdXJwJHRpdGxlLCIgLSAiLHBhc3RlMChyb3VuZCgxMDAqbG9hbl9ieV9wdXJwJGBUb3RhbCBMb2FucyAoJClgL3N1bShsb2FuX2J5X3B1cnAkYFRvdGFsIExvYW5zICgkKWApLDEpLCIlIikpDQoNCmxvYW5fYnlfcHVycF9wbG90IDwtIGdncGxvdChsb2FuX2J5X3B1cnAsIGFlcyh4ID0gcmVvcmRlcih0aXRsZSwtYFRvdGFsIExvYW5zICgkKWApLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gKGBUb3RhbCBMb2FucyAoJClgKS8xZTYsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBJKCJkb2RnZXJibHVlNCIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gSShyZXAoMC43LDEyKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gSSgiZ3JleTI5IikpKSArIA0KICAgICAgICAgICAgICAgICAgICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNTUsIGhqdXN0ID0gMSkpICsNCiAgICAgICAgICAgICAgICAgICAgIHhsYWIoIlB1cnBvc2UiKSArDQogICAgICAgICAgICAgICAgICAgICB5bGFiKE5VTEwpDQoNCmdyaWQuYXJyYW5nZShsb2FuX2J5X2VtcF9wbG90LCBsb2FuX2J5X3B1cnBfcGxvdCwNCiAgICAgICAgICAgICB0b3AgPSB0ZXh0R3JvYigiVG90YWwgTG9hbnMgYnkgSm9iIFRpdGxlIGFuZCBQdXJwb3NlIiksDQogICAgICAgICAgICAgbmNvbCA9IDIpDQpgYGANCjxicj48YnI+DQoNCldlIGNhbiBzZWUgdGhhdCBtYW55IG9mIHRoZSBqb2IgdGl0bGVzIGFyZSBhY3R1YWxseSBtaXNzaW5nLCB3aGljaCBjb3VsZCBiZSBiZWNhdXNlIExlbmRpbmcgQ2x1YiBjaG9vc2VzIHRvIGhpZGUgdGhhdCBpbmZvcm1hdGlvbiB0byBtYWludGFpbiB0aGUgYm9ycm93ZXJzJyBhbm9ueW1pdHkuIFJlZ2lzdGVyZWQgTnVyc2UsIE1hbmFnZXIsIFRlYWNoZXIsIGFuZCBCdXNpbmVzcyBPd25lciBmb3JtIHRoZSBuZXh0IGxhcmdlc3QgY2F0ZWdvcmllcy4gSG93ZXZlciwgdGhlc2Ugb25seSBhY2NvdW50IGZvciBhYm91dCA3LjUlIG9mIHRoZSBsb2FuIHZvbHVtZS4gVGhpcyBkaXN0cmlidXRpb24gaGFzIGEgc3Ryb25nIHJpZ2h0IHRhaWwgdGhhdCBzdHJldGNoZXMgYWNyb3NzIHRoZSBgciBucm93KGxvYW5fYnlfZW1wKWAgZGlmZmVyZW50IGpvYiB0aXRsZXMuIFRoZSBkaXN0cmlidXRpb24gb2YgbG9hbiB2b2x1bWUgYnkgKnB1cnBvc2UqIGlzIGFjdHVhbGx5IHRoZSBvcHBvc2l0ZSBvZiB0aGlzLiBUaGUgdmFzdCBtYWpvcml0eSBvZiB0aGUgbG9hbnMgaGF2ZSBiZWVuIHRha2VuIG91dCB0byBjb25zb2xpZGF0ZSBkZWJ0LiBUaGVyZSBhcmUgb25seSBgciBucm93KGxvYW5fYnlfcHVycCktMWAgb3RoZXIgcHVycG9zZXMsIHdoaWNoIGFyZSBhbGwgc2hvd24gaW4gdGhlIHBsb3QuDQoNCk5vdyBsZXQncyB0YWtlIGEgbG9vayBhdCB3aGF0IHN0YXRlcyB0aGUgYm9ycm93ZXJzIGxpdmUgaW46DQoNCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgZmlnLndpZHRoID0gOSwgZmlnLmhlaWdodCA9IDUsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQ0KIyBBZ2dyZWdhdGluZyB1cCBieSBzdGF0ZQ0KbG9hbl9ieV9zdGF0ZSA8LSBsb2FuX2RhdGEgJT4lIA0KICAgICAgICAgICAgICAgICBncm91cF9ieShhZGRyX3N0YXRlKSAlPiUNCiAgICAgICAgICAgICAgICAgc3VtbWFyaXplKGBUb3RhbCBMb2FucyAoJClgID0gc3VtKGxvYW5fYW1udCkvMWU2KSAlPiUNCiAgICAgICAgICAgICAgICAgYXJyYW5nZShkZXNjKGBUb3RhbCBMb2FucyAoJClgKSkNCg0KY29sbmFtZXMobG9hbl9ieV9zdGF0ZSkgPC0gYygicmVnaW9uIiwidmFsdWUiKQ0KDQojIEdldHRpbmcgc3VtbWFyeSBwZXJjZW50YWdlIG9mIHRvcCA0IHJlZ2lvbnMNCnRvcDRfc3RhdGVzIDwtIHJvdW5kKDEwMCpzdW0obG9hbl9ieV9zdGF0ZSR2YWx1ZVsxOjRdKS9zdW0obG9hbl9ieV9zdGF0ZSR2YWx1ZSksMSkNCg0KIyBSZXBsYWNpbmcgb3V0IHRoZSBzdGF0ZSBjb2RlcyB3aXRoIHRoZWlyIGZ1bGwgbmFtZXMgZm9yIHBsb3R0aW5nDQpsaWJfbG9hZCgicmdkYWwiKQ0KbGliX2xvYWQoImNob3JvcGxldGhyTWFwcyIpDQpsaWJfbG9hZCgiY2hvcm9wbGV0aHIiKQ0KDQpkYXRhKCJzdGF0ZS5yZWdpb25zIikNCg0KbG9hbl9ieV9zdGF0ZSRyZWdpb24gPC0gc2FwcGx5KGxvYW5fYnlfc3RhdGUkcmVnaW9uLCBmdW5jdGlvbihzdGF0ZV9jb2RlKSB7DQogIA0KICBpbnggPC0gZ3JlcChwYXR0ZXJuID0gc3RhdGVfY29kZSwgeCA9IHN0YXRlLnJlZ2lvbnMkYWJiKQ0KICANCiAgc3RhdGUucmVnaW9ucyRyZWdpb25baW54XQ0KICANCn0pDQoNCiMgUGxvdHRpbmcgVVMgbWFwIHdpdGggdmFsdWVzDQpzdGF0ZV9jaG9yb3BsZXRoKGxvYW5fYnlfc3RhdGUsIHRpdGxlID0gIiAgICAgICAgICAgVG90YWwgTG9hbiBWb2x1bWUgYnkgU3RhdGUgLSBNaWxsaW9ucyAkIikNCmBgYA0KPGJyPjxicj4NCg0KTW9zdCBvZiB0aGUgZnVuZHMgYm9ycm93ZWQgdGhyb3VnaCBMZW5kaW5nIENsdWIgaW4gdGhlIGZpcnN0IHF1YXJ0ZXIgZm9yIDIwMTcgd2VudCB0byBwZW9wbGUgaW4gQ2FsaWZvcm5pYSwgVGV4YXMsIE5ldyBZb3JrLCBhbmQgRmxvcmlkYS4gVGhlc2UgcmVnaW9ucyBhY2NvdW50ZWQgZm9yIGByIHRvcDRfc3RhdGVzYCUgb2YgdGhlIHZvbHVtZSBkdXJpbmcgdGhlIHBlcmlvZC4gVGhpcyByYW5raW5nIGFjdHVhbGx5IG1pbWljcyB0aGUgcmFua2luZyBvZiB0aG9zZSBzdGF0ZXMnIGVjb25vbWljIG91dHB1dCBhcyBbbWVhc3VyZWQgYnkgR0RQXShodHRwczovL3d3dy5iZWEuZ292L2lUYWJsZS9kcmlsbGRvd24uY2ZtP3JlcWlkPTcwJnN0ZXBudW09MTEmQXJlYVR5cGVLZXlHZHA9MSZHZW9GaXBzR2RwPVhYJkNsYXNzS2V5R2RwPW5haWNzJkNvbXBvbmVudEtleT0yMDAmSW5kdXN0cnlLZXk9MSZZZWFyR2RwPTIwMTYmWWVhckdkcEJlZ2luPS0xJlllYXJHZHBFbmQ9LTEmVW5pdE9mTWVhc3VyZUtleUdkcD1sZXZlbHMmUmFua0tleUdkcD0xJkRyaWxsPTEmblJhbmdlPTUpLiBTdGF0ZXMgd2l0aCBsYXJnZXIgZWNvbm9taWVzIHRlbmQgdG8gaGF2ZSBwZW9wbGUgd2hvIGJvcnJvdyBtb3JlLiBJdCdzIGFsc28gaW50ZXJlc3RpbmcgdG8gbm90ZSB0aGF0IExlbmRpbmcgQ2x1YiBsb2FucyBhcmUgY3VycmVudGx5IG5vdCBhdmFpbGFibGUgaW4gSW93YSBvciBXZXN0IFZpcmdpbmlhLg0KDQpGaW5hbGx5LCB3ZSBjYW4gdmlzdWFsaXplIHZhcmlvdXMgbWVhc3VyZXMgb2YgdGhlIGJvcnJvd2VycycgcmlzayBwcm9maWxlcy4gV2UgY2FuIHN0YXJ0IG9mZiBieSB0YWtpbmcgYSBsb29rIGF0IHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIGludGVyZXN0IHJhdGUgY2hhcmdlZCBmb3IgZWFjaCAqZ3JhZGUqIHJhdGluZy4NCg0KYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCBmaWcud2lkdGggPSA5LCBmaWcuaGVpZ2h0ID0gNSwgZmlnLmFsaWduID0gImNlbnRlciJ9DQojIEdyYWJiaW5nIHRoZSBtZWFucw0KY2RhdCA8LSBkYXRhLmZyYW1lKHRhcHBseShsb2FuX2RhdGEkaW50X3JhdGUsIGxvYW5fZGF0YSRncmFkZSwgbWVhbikpDQoNCnJhdGVfZ3JhZGVfZGVucyA8LSBnZ3Bsb3QobG9hbl9kYXRhLCBhZXMoeCA9IGludF9yYXRlLCBmaWxsID0gZ3JhZGUpKSArIA0KICAgICAgICAgICAgICAgICAgICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjYpICsNCiAgICAgICAgICAgICAgICAgICAgICBnZW9tX3ZsaW5lKGRhdGEgPSBjZGF0LCBhZXMoeGludGVyY2VwdCA9IGNkYXQsIGNvbG91ciA9ICBmYWN0b3Iocm93bmFtZXMoY2RhdCkpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmV0eXBlID0gImRhc2hlZCIsIHNpemUgPSAxLCBzaG93LmxlZ2VuZCA9IEYpICsNCiAgICAgICAgICAgICAgICAgICAgICB5bGFiKE5VTEwpICsNCiAgICAgICAgICAgICAgICAgICAgICB4bGFiKCJJbnRlcmVzdCBSYXRlIikgKyANCiAgICAgICAgICAgICAgICAgICAgICBndWlkZXMoIGZpbGwgPSBndWlkZV9sZWdlbmQodGl0bGUgPSAiTG9hbiBHcmFkZSIpKSArIA0KICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsgDQogICAgICAgICAgICAgICAgICAgICAgZ2d0aXRsZSgiSW50ZXJlc3QgUmF0ZSBEaXN0cmlidXRpb24gYnkgR3JhZGUiKQ0KDQpyYXRlX2dyYWRlX2RlbnMNCmBgYA0KDQpUaGUgaW50ZXJlc3QgcmF0ZSBnZW5lcmFsbHkgaW5jcmVhc2VzIGFzIHRoZSBsb2FuJ3MgZ3JhZGUgZGVjcmVhc2VzLCB3aGljaCBpcyBleHBlY3RlZC4gSG93ZXZlciwgdGhlc2UgZGlzdHJpYnV0aW9ucyBhcHBlYXIgdG8gYmUgcXVpdGUgbHVtcHksIHdoaWNoIHBvaW50cyB0byB0aGUgZmFjdCB0aGF0IHRoZXJlIGFyZSB2YXJpb3VzIHJpc2sgZ3JvdXBzIHdpdGhpbiBlYWNoIGdyYWRlIGdyb3VwLiBMZXQncyB0cnkgdG8gZ2V0IGEgZGVlcGVyIGxvb2sgYXQgdGhlc2UgKmdyYWRlKiBzdWJncm91cHMuDQoNCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0NCmxpYl9sb2FkKCJtb21lbnRzIikNCg0KIyMgR2VuZXJpYyBmdW5jdGlvbiB0byBjcmVhdGUgZm91ciBkZXNjcmlwdGl2ZSBwbG90cyBmb3IgZWFjaCBsb2FuIGdyYWRlIC0tPiBFbXBsb3ltZW50LCBTdGF0ZSwgUHVycG9zZSwgQW1vdW50DQpncmFkZV9wbG90dGVyIDwtIGZ1bmN0aW9uKGdyYWRlKSB7DQogIA0KICAjIEZpbHRlcmluZyBmb3IgZ3JhZGUNCiAgbG9hbl9kYXRhX3RtcCA8LSBsb2FuX2RhdGFbbG9hbl9kYXRhJGdyYWRlID09IGdyYWRlLF0NCg0KICAjIyBBZ2dyZWdhdGluZyB1cCB0b3RhbCBsb2FucyBieSBqb2IgIyMNCiAgbG9hbl9ieV9lbXAgPC0gbG9hbl9kYXRhX3RtcCAlPiUgDQogICAgICAgICAgICAgICAgIGdyb3VwX2J5KGVtcF90aXRsZSkgJT4lIA0KICAgICAgICAgICAgICAgICBzdW1tYXJpemUoYFRvdGFsIExvYW5zICgkKWAgPSBzdW0obG9hbl9hbW50KSkgJT4lDQogICAgICAgICAgICAgICAgIGFycmFuZ2UoZGVzYyhgVG90YWwgTG9hbnMgKCQpYCkpDQogIA0KICAjIEdldHRpbmcgcGVyY2VudGFnZSBpbmZvcm1hdGlvbiBzaW5jZSB3ZSBjYW4gb25seSBwbG90IGEgc3Vic2V0DQogIGxvYW5fYnlfZW1wJGVtcF90aXRsZSA8LSBwYXN0ZTAobG9hbl9ieV9lbXAkZW1wX3RpdGxlLCIgLSAiLHBhc3RlMChyb3VuZCgxMDAqbG9hbl9ieV9lbXAkYFRvdGFsIExvYW5zICgkKWAvc3VtKGxvYW5fYnlfZW1wJGBUb3RhbCBMb2FucyAoJClgKSwxKSwiJSIpKQ0KICANCiAgbG9hbl9ieV9lbXBfcGxvdCA8LSBnZ3Bsb3QobG9hbl9ieV9lbXBbMToxMCxdLCBhZXMoeCA9IHJlb3JkZXIoZW1wX3RpdGxlLC1gVG90YWwgTG9hbnMgKCQpYCksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gKGBUb3RhbCBMb2FucyAoJClgKS8xZTYsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gSSgiZG9kZ2VyYmx1ZTQiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSBJKHJlcCgwLjcsMTApKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gSSgiZ3JleTI5IikpKSArIA0KICAgICAgICAgICAgICAgICAgICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArDQogICAgICAgICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA1NSwgaGp1c3QgPSAxKSkgKw0KICAgICAgICAgICAgICAgICAgICAgIHhsYWIoIkpvYiBUaXRsZSAtICUgb2YgVG90YWwiKSArDQogICAgICAgICAgICAgICAgICAgICAgeWxhYigiVG90YWwgTG9hbnMgLSBNaWxsaW9ucyBvZiAkIikNCiAgDQogICMjIEFnZ3JlZ2F0aW5nIHVwIHRvdGFsIGxvYW5zIGJ5IHB1cnBvc2UgIyMNCiAgbG9hbl9ieV9wdXJwIDwtIGxvYW5fZGF0YV90bXAgJT4lIA0KICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkodGl0bGUpICU+JSANCiAgICAgICAgICAgICAgICAgIHN1bW1hcml6ZShgVG90YWwgTG9hbnMgKCQpYCA9IHN1bShsb2FuX2FtbnQpKSAlPiUNCiAgICAgICAgICAgICAgICAgIGFycmFuZ2UoZGVzYyhgVG90YWwgTG9hbnMgKCQpYCkpDQoNCiAgIyBHZXR0aW5nIHBlcmNlbnRhZ2UgaW5mb3JtYXRpb24NCiAgbG9hbl9ieV9wdXJwJHRpdGxlIDwtIHBhc3RlMChsb2FuX2J5X3B1cnAkdGl0bGUsIiAtICIscGFzdGUwKHJvdW5kKDEwMCpsb2FuX2J5X3B1cnAkYFRvdGFsIExvYW5zICgkKWAvc3VtKGxvYW5fYnlfcHVycCRgVG90YWwgTG9hbnMgKCQpYCksMSksIiUiKSkNCiAgDQogIGxvYW5fYnlfcHVycF9wbG90IDwtIGdncGxvdChsb2FuX2J5X3B1cnAsIGFlcyh4ID0gcmVvcmRlcih0aXRsZSwtYFRvdGFsIExvYW5zICgkKWApLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSAoYFRvdGFsIExvYW5zICgkKWApLzFlNiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gSSgiZG9kZ2VyYmx1ZTQiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gSShyZXAoMC43LDEyKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBJKCJncmV5MjkiKSkpICsgDQogICAgICAgICAgICAgICAgICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKw0KICAgICAgICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA1NSwgaGp1c3QgPSAxKSkgKw0KICAgICAgICAgICAgICAgICAgICAgeGxhYigiUHVycG9zZSIpICsNCiAgICAgICAgICAgICAgICAgICAgIHlsYWIoTlVMTCkNCiAgDQogICMjIEFnZ3JlZ2F0aW5nIHVwIHRvdGFsIGxvYW5zIGJ5IHN0YXRlICMjDQogIGxvYW5fYnlfc3RhdGUgPC0gbG9hbl9kYXRhX3RtcCAlPiUgDQogICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoYWRkcl9zdGF0ZSkgJT4lIA0KICAgICAgICAgICAgICAgICAgIHN1bW1hcml6ZShgVG90YWwgTG9hbnMgKCQpYCA9IHN1bShsb2FuX2FtbnQpKSAlPiUNCiAgICAgICAgICAgICAgICAgICBhcnJhbmdlKGRlc2MoYFRvdGFsIExvYW5zICgkKWApKSAgDQogIA0KICAjIEZpbmRpbmcgZnVsbCBzdGF0ZSBuYW1lcywgY2FwaXRhbGl6aW5nIGZpcnN0IGxldHRlciBvZiBlYWNoIG9uZQ0KICBsb2FuX2J5X3N0YXRlJGFkZHJfc3RhdGUgPC0gc2FwcGx5KGxvYW5fYnlfc3RhdGUkYWRkcl9zdGF0ZSwgZnVuY3Rpb24oc3RhdGVfY29kZSkgew0KICAgIA0KICAgIGlueCA8LSBncmVwKHBhdHRlcm4gPSBzdGF0ZV9jb2RlLCB4ID0gc3RhdGUucmVnaW9ucyRhYmIpDQogICAgDQogICAgc3RhdGUucmVnaW9ucyRyZWdpb25baW54XQ0KICANCiAgfSwgVVNFLk5BTUVTID0gRikNCiAgDQogICMgQm9ycm93ZWQgZnJvbTogaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvNjM2NDc4My9jYXBpdGFsaXplLXRoZS1maXJzdC1sZXR0ZXItb2YtYm90aC13b3Jkcy1pbi1hLXR3by13b3JkLXN0cmluZw0KICBsb2FuX2J5X3N0YXRlJGFkZHJfc3RhdGUgPC0gc2FwcGx5KGxvYW5fYnlfc3RhdGUkYWRkcl9zdGF0ZSwgZnVuY3Rpb24oc3RhdGVfbmFtZSkgew0KICAgIA0KICAgIHNwbGl0IDwtIHN0cnNwbGl0KHg9c3RhdGVfbmFtZSwgIiAiKVtbMV1dDQogICAgDQogICAgICBwYXN0ZSh0b3VwcGVyKHN1YnN0cmluZyhzcGxpdCwgMSwxKSksIA0KICAgICAgICAgICAgc3Vic3RyaW5nKHNwbGl0LCAyKSwgc2VwPSIiLCBjb2xsYXBzZT0iICIpDQogIH0sIFVTRS5OQU1FUyA9IEYpDQogIA0KICAjIEdldHRpbmcgcGVyY2VudGFnZSBpbmZvcm1hdGlvbiBlc3BlY2lhbGx5IHNpbmNlIHdlIGNhbiBvbmx5IHBsb3QgYSBzdWJzZXQNCiAgbG9hbl9ieV9zdGF0ZSRhZGRyX3N0YXRlIDwtIHBhc3RlMChsb2FuX2J5X3N0YXRlJGFkZHJfc3RhdGUsIiAtICIscGFzdGUwKHJvdW5kKDEwMCpsb2FuX2J5X3N0YXRlJGBUb3RhbCBMb2FucyAoJClgL3N1bShsb2FuX2J5X3N0YXRlJGBUb3RhbCBMb2FucyAoJClgKSwxKSwiJSIpKQ0KICANCiAgbG9hbl9ieV9zdGF0ZV9wbG90IDwtIGdncGxvdChsb2FuX2J5X3N0YXRlWzE6MTAsXSwgYWVzKHggPSByZW9yZGVyKGFkZHJfc3RhdGUsLWBUb3RhbCBMb2FucyAoJClgKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gKGBUb3RhbCBMb2FucyAoJClgKS8xZTYsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IEkoImRvZGdlcmJsdWU0IiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IEkocmVwKDAuNywxMCkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gSSgiZ3JleTI5IikpKSArIA0KICAgICAgICAgICAgICAgICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKw0KICAgICAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDU1LCBoanVzdCA9IDEpKSArDQogICAgICAgICAgICAgICAgICAgIHhsYWIoIlN0YXRlIC0gJSBvZiBUb3RhbCIpICsNCiAgICAgICAgICAgICAgICAgICAgeWxhYigiVG90YWwgTG9hbnMgLSBNaWxsaW9ucyBvZiAkIikNCiAgDQogICMjIEFnZ3JlZ2F0aW5nIHVwIGJ5IGxvYW4gYW1vdW50ICMjDQogIGxvYW5fYW1udF90bXAgPC0gbG9hbl9kYXRhX3RtcCRsb2FuX2FtbnQNCiAgDQogIGxvYW5fYW1udF9oaXN0IDwtIHFwbG90KGxvYW5fYW1udF90bXAsIGZpbGwgPSBJKCJkb2RnZXJibHVlNCIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gSSgwLjcpLCBjb2wgPSBJKCJncmV5MjkiKSkgKyB4bGFiKCJMb2FuIEFtb3VudCIpICsgeWxhYigiQ291bnQiKSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSBtZWFuKGxvYW5fYW1udF90bXApKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJkb2RnZXJibHVlNCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMikgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRlKCJ0ZXh0IiwgeCA9IEluZiwgeSA9IEluZiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBzcHJpbnRmKCJcbiBNZWFuOiAlcyAgXG4gQXZlcmFnZSBEZXZpYXRpb246ICVzICAgXG4gU2tld25lc3M6ICVzICAgXG4gS3VydG9zaXM6ICVzICAgIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm91bmQobWVhbihsb2FuX2FtbnRfdG1wKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvdW5kKG1lYW4oYWJzKGxvYW5fYW1udF90bXAtbWVhbihsb2FuX2FtbnRfdG1wKSkpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm91bmQoc2tld25lc3MobG9hbl9hbW50X3RtcCksMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvdW5kKGt1cnRvc2lzKGxvYW5fYW1udF90bXApLDIpKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmp1c3QgPSAxLCBoanVzdCA9IDEpDQogIA0KICAjIEFycmFuZ2luZyBwbG90cyBpbnRvIGdyaWQNCiAgZ3JpZC5hcnJhbmdlKGxvYW5fYnlfZW1wX3Bsb3QsIGxvYW5fYnlfcHVycF9wbG90LCBsb2FuX2J5X3N0YXRlX3Bsb3QsIGxvYW5fYW1udF9oaXN0LA0KICAgICAgICAgICAgICAgd2lkdGhzID0gYyg0LDQpLCBoZWlnaHRzID0gYyg0LDMpLCAgIA0KICAgICAgICAgICAgICAgdG9wID0gdGV4dEdyb2Ioc3ByaW50ZigiR3JhZGUgJXMgTG9hbiBWb2x1bWUgYnkgRW1wbG95bWVudCwgUHVycG9zZSwgU3RhdGUsIGFuZCBDb3VudHMiLGdyYWRlKSkpDQogIA0KICByZXR1cm4oTlVMTCkNCn0NCiMgVGhpcyBzZWVtcyB0byBiZSBhIGJ1ZywgYnV0IFIgZXJyb3JzIG91dCBkdWUgb24gYW4gb2JzY3VyZSBkcGx5ciBpc3N1ZSB0aGF0IGlzIHJlc29sdmVkIHdpdGg6DQojIDEpIFJlc3RhcnRpbmcgdGhlIFIgc2Vzc2lvbiBhdCB0aGlzIHBvaW50DQojIDIpIFJ1bm5pbmcgbGlicmFyeShnZ3Bsb3QyKTsgbGlicmFyeShkcGx5cik7IGxpYnJhcnkoZ3JpZEV4dHJhKTsgbGlicmFyeShtb21lbnRzKTsgbGlicmFyeShncmlkKQ0KIyAzKSBSdW5uaW5nIHRoZSByZXN0IG9mIHRoZSBjaHVua3MNCg0KYGBgDQoNCiMjIHsudGFic2V0IC50YWJzZXQtZmFkZX0NCg0KIyMjIEdyYWRlIEENCg0KYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDd9DQpudWxsIDwtIGdyaWQuZHJhdyhncmFkZV9wbG90dGVyKCJBIikpDQpgYGANCg0KIyMjIEdyYWRlIEINCg0KYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDd9DQpudWxsIDwtIGdyaWQuZHJhdyhncmFkZV9wbG90dGVyKCJCIikpDQpgYGANCg0KIyMjIEdyYWRlIEMNCg0KYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDd9DQpudWxsIDwtIGdyaWQuZHJhdyhncmFkZV9wbG90dGVyKCJDIikpDQpgYGANCg0KIyMjIEdyYWRlIEQNCg0KYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDd9DQpudWxsIDwtIGdyaWQuZHJhdyhncmFkZV9wbG90dGVyKCJEIikpDQpgYGANCg0KIyMjIEdyYWRlIEUNCg0KYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDd9DQpudWxsIDwtIGdyaWQuZHJhdyhncmFkZV9wbG90dGVyKCJFIikpDQpgYGANCg0KIyMjIEdyYWRlIEYNCg0KYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDd9DQpudWxsIDwtIGdyaWQuZHJhdyhncmFkZV9wbG90dGVyKCJGIikpDQpgYGANCiANCiMjIHsudGFic2V0IC50YWJzZXQtZmFkZX0NCg0KVGhlIHJlbGF0aXZlIG9yZGVycyBvZiB0aGUgcHVycG9zZSwgc3RhdGUsIGFuZCBqb2IgdGl0bGUgZG9uJ3QgY2hhbmdlIG11Y2ggYmV0d2VlbiBncmFkZXMuIFRoZSBkaXN0cmlidXRpb24gb2YgdGhlIGxvYW4gc2l6ZSBkb2VzIHNoaWZ0IHRvIHRoZSByaWdodCBhcyB0aGUgZ3JhZGUgZGVjcmVhc2VzLiBUaGF0IGlzLCBwZW9wbGUgdGhhdCBhcmUgcmlza2llciB0ZW5kIHRvIGJvcnJvdyBtb3JlIHRoYW4gdGhvc2UgdGhhdCBhcmUgbGVzcyByaXNreS4gQXMgdGhlIGdyYWRlIGRlY3JlYXNlcyB0aGVyZSBpcyBhIGdyZWF0ZXIgdGVuZGVuY3kgdG8gdXNlIHRoZSBsb2FuIGZvciBkZWJ0IGNvbnNvbGlkYXRpb24uIFRoZXJlIGFyZSBsaWtlbHkgY29tcGxleCBpbnRlcmFjdGlvbnMgYW1vbmdzdCB0aGUgdmFyaWFibGVzIGluIHRoZSBmdWxsIGRhdGEgc2V0IHRoYXQgYmV0dGVyIGV4cGxhaW4gdGhlIGRpZmZlcmVuY2VzIGluIGludGVyZXN0IHJhdGVzIHdpdGhpbiAqZ3JhZGUqIGdyb3Vwcy4gV2UnZCBsaWtlbHkgbmVlZCB0byBidWlsZCB2YXJpb3VzIG1vZGVscyB0byB0cnkgdG8gY2FwdHVyZSB3aGF0IG1ha2VzIGEgYm9ycm93ZXIgZmFsbCB1bmRlciBhIGNlcnRhaW4gZ3JhZGUgYW5kIHdoYXQgZGljdGF0ZXMgdGhlIGludGVyZXN0IHJhdGUuIA0KDQojIyBTdW1tYXJ5DQoNCldlJ3ZlIGJyb2tlbiBvdXQgdGhlIGRhdGEgc2V0IGludG8gY29udGludW91cyBhbmQgY2F0ZWdvcmljYWwgdmFyaWFibGVzLiBUaGVzZSB3ZXJlIHNjcnViYmVkIGFuZCBhbmFseXplZCBmb3Igc3BhcnNpdHkuIE9uY2Ugd2Ugd2VyZSBjb21mb3J0YWJsZSB3aXRoIHRoZSBkYXRhIHNldCwgd2UgbW92ZWQgb24gdG8gdmlzdWFsaXppbmcgdGhlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB0aGUgdmFyaWFibGVzLiBXZSBicm9rZSBvdXQgbG9hbiB2b2x1bWUgYnkgc3RhdGUsIGpvYiwgYW5kIHB1cnBvc2UuIFdlIGFsc28gbG9va2VkIGF0IHRoZSBkaXN0cmlidXRpb24gb2YgaW50ZXJlc3QgcmF0ZSBieSBsb2FuIGdyYWRlIGFuZCBkaXZlZCBkZWVwZXIgaW50byBlYWNoIGdyYWRlJ3Mgc3RhdGlzdGljcy4gTm93IHRoYXQgd2UgaGF2ZSBhIHJlYXNvbmFibHkgY2xlYW4gZGF0YSBzZXQgYW5kIHNvbWUgYWdncmVnYXRlIGluZm9ybWF0aW9uIG9uIHRoZSB2YXJpYWJsZXMsIHdlIGNhbiBtb3ZlIG9uIHRvIGJ1aWxkaW5nIG1vZGVscyBmb3IgaW5mZXJlbmNlIGFuZCBwcmVkaWN0aW9uLg==