Introduction

The primary purpose of this assignment is to predict the likelihood of an auto insurance customer being involved in an accident. First, missing data is accounted for and, where possible, null values and outliers are imputed using variable-specific regression tree models. Then three logistic regression and probit models are fit and evaluated. Additionally, a boosted classification tree model is developed to attempt to improve predictive accuracy. Finally, R code is provided to score a fresh data file and make predictions for teams not included in the original sample. All code used in the development of this project can be found here.

Exploratory Data Analysis and Prep

Missing Data

The dataset includes information on 8,161 insurance customers. The variables included are listed below as well as their theoretical effects.

VARIABLE NAME DEFINITION THEORETICAL EFFECT
INDEX Identification Variable (do not use) None
TARGET_FLAG Was Car in a crash? 1=YES 0=NO None
TARGET_AMT If car was in a crash, what was the cost None
AGE Age of Driver Very young people tend to be risky. Maybe very old people also.
BLUEBOOK Value of Vehicle Unknown effect on probability of collision, but probably effect the payout if there is a crash
CAR_AGE Vehicle Age Unknown effect on probability of collision, but probably effect the payout if there is a crash
CAR_TYPE Type of Car Unknown effect on probability of collision, but probably effect the payout if there is a crash
CAR_USE Vehicle Use Commercial vehicles are driven more, so might increase probability of collision
CLM_FREQ #Claims(Past 5 Years) The more claims you filed in the past, the more you are likely to file in the future
EDUCATION Max Education Level Unknown effect, but in theory more educated people tend to drive more safely
HOMEKIDS #Children @Home Unknown effect
HOME_VAL Home Value In theory, home owners tend to drive more responsibly
INCOME Income In theory, rich people tend to get into fewer crashes
JOB Job Category In theory, white collar jobs tend to be safer
KIDSDRIV #Driving Children When teenagers drive your car, you are more likely to get into crashes
MSTATUS Marital Status In theory, married people drive more safely
MVR_PTS Motor Vehicle Record Points If you get lots of traffic tickets, you tend to get into more crashes
OLDCLAIM Total Claims(Past 5 Years) If your total payout over the past five years was high, this suggests future payouts will be high
PARENT1 Single Parent Unknown effect
RED_CAR A Red Car Urban legend says that red cars (especially red sports cars) are more risky. Is that true?
REVOKED License Revoked (Past 7 Years) If your license was revoked in the past 7 years, you probably are a more risky driver.
SEX Gender Urban legend says that women have less crashes then men. Is that true?
TIF Time in Force People who have been customers for a long time are usually more safe.
TRAVTIME Distance to Work Long drives to work usually suggest greater risk
URBANICITY Home/Work Area Unknown
YOJ Years on Job People who stay at a job for a long time are usually more safe

Some basic explanatory plots and correlations are presented below. 26% of customers have been involved in an accident. Many of the variables follow a nice, normal distribution like age and tragel time. But others, like home value, and income are positively skewed. The data will need to be appropriately transformed to be useful for predictive purposes. No single numeric variable has an incredibly high correlation with claim likelihood, but number of past claims and moving violation points are closest - explaining about 20% of the variation in crashes.

  target_flag        kidsdriv           age           homekids           yoj      
 Min.   :0.0000   Min.   :0.0000   Min.   :16.00   Min.   :0.0000   Min.   : 0.0  
 1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:39.00   1st Qu.:0.0000   1st Qu.: 9.0  
 Median :0.0000   Median :0.0000   Median :45.00   Median :0.0000   Median :11.0  
 Mean   :0.2638   Mean   :0.1711   Mean   :44.79   Mean   :0.7212   Mean   :10.5  
 3rd Qu.:1.0000   3rd Qu.:0.0000   3rd Qu.:51.00   3rd Qu.:1.0000   3rd Qu.:13.0  
 Max.   :1.0000   Max.   :4.0000   Max.   :81.00   Max.   :5.0000   Max.   :23.0  
                                   NA's   :6                        NA's   :454   
     income          home_val         travtime         bluebook          tif        
 Min.   :     0   Min.   :     0   Min.   :  5.00   Min.   : 1500   Min.   : 1.000  
 1st Qu.: 28097   1st Qu.:     0   1st Qu.: 22.00   1st Qu.: 9280   1st Qu.: 1.000  
 Median : 54028   Median :161160   Median : 33.00   Median :14440   Median : 4.000  
 Mean   : 61898   Mean   :154867   Mean   : 33.49   Mean   :15710   Mean   : 5.351  
 3rd Qu.: 85986   3rd Qu.:238724   3rd Qu.: 44.00   3rd Qu.:20850   3rd Qu.: 7.000  
 Max.   :367030   Max.   :885282   Max.   :142.00   Max.   :69740   Max.   :25.000  
 NA's   :445      NA's   :464                                                       
    oldclaim        clm_freq         mvr_pts          car_age      
 Min.   :    0   Min.   :0.0000   Min.   : 0.000   Min.   :-3.000  
 1st Qu.:    0   1st Qu.:0.0000   1st Qu.: 0.000   1st Qu.: 1.000  
 Median :    0   Median :0.0000   Median : 1.000   Median : 8.000  
 Mean   : 4037   Mean   :0.7986   Mean   : 1.696   Mean   : 8.328  
 3rd Qu.: 4636   3rd Qu.:2.0000   3rd Qu.: 3.000   3rd Qu.:12.000  
 Max.   :57037   Max.   :5.0000   Max.   :13.000   Max.   :28.000  
                                                   NA's   :510     

The data is largely complete. The variables with the most null values are only 5-6% incomplete.

Regression and classification trees are used to impute missing values. Additionally, outlier variables are deleted and imputed using the same methods. Binary flags are generated for values imputed for each possible reason. Finally, all values are scaled and centered to stabilize model estimates.

Model Development

Three models are developed as part of this project - a logistic regression model using heuristic variable selection, a logistic regression model with variables selected through a bi-directional stepwise process meant to minimize AIC, and a probit regression model using the same variable selection technique.

Heuristic Logistic

The first model developed is a logistic regression model taking all inputs where the data dictionary contains some theoretical impact on accident likelihood. Logistic regression models work similarly to OLS regression models, but the OLS formula is transformed and inverted to produce probabilities of binary outcomes rather than point estimates of a continuous variable1.

Performance

Figures 2.1 and 2.2 illustrate a troubling tendency to return incorrectly low accident probabilities. Too many innacurately low predictions could lead to the company taking on more claims than premiums. Additionally, those records with high probability scores (in the 90s) don’t tend to have more accidents than some lower score groupings on aggregate (in the 70s and 80s).

Ignoring unknown parameters: weight

Model Composition

The strongest variable in the model is whether or not a customer’s driver’s license has been revoked in the past seven years. Kid drivers and a preponderance of moving violation points also contribute to claim likelihood which makes sense. Almost all variable coefficients are significant and perform according to the assumptions made in the data dictionary.

Bidirectional Variable Selection Logistic Regression

The second model tested is a logistic regression model developed with a backward variable selection process. Starting with a logit model using all possible variables the model iteratively works through possible sets of predictor variables, adding and dropping variables to minimize AIC23. It’s a computationally expensive process, which could become a factor in production decisions. However, the gains to predictive accuracy may be worthwhile.

Performance

Figure 3.1 looks nearly identical to 2.1 - especially the distributions of scores for claimants which skew too low. The cumulative density plot (Figure 3.3) looks slightly more skewed than that in 2.3. But the predictive accuracy illustrated in Figure 3.2 demonstrates significany improvement over the heursitc model.

Model Composition

Many of the variables selected through the stepwise process perform similarly to the assumptions laid out in the data dictionary. Some of the variable coefficients (like missing age data, SUV ownership, and presence of kids in the household) are not significant, but they’re left in the model to minimize AIC.

Bidirectional Variable Selection Probit Regression

The Probit model uses the probit link function to modify OLS regression for classification purposes (similar to the logit process but with different transformations). In this case, the models performed similarly. A bi-directional stepwise variable selection technique is used to select a subset of variables that minimizes AIC. Then the winning model is iteratively applied to subsamples of the data and the average predicted values are calculated for each record.

Performance

Similar to the bi-directional logistic regression model, too many non-accident predictions are clearly a problem in this data set. Figures 4.1 and 4.3 illustrate the relative success of the model at positively identifying non-accident cases but also that a significantly high number of cases where accidents did received low scores. One bright spot in this model compared to the previous models is Figure 4.2 which illustrates that as scores go up (in aggregate) accident likelihood does tend to go up as well.

Model Composition

The probit model coefficients behave similarly to the stepwise logistic regression model. Again, regardless of statistical significance, the variables selected through the AIC minimization process are retained in the model.

Model Evaluation

The three models are evaluated based on the McFadden Pseudo \(R^2\) statistic, the Kolmagorov - Smirnov (KS) statistic, area under the curve (AUC), and Root-Mean Squared Error (RMSE). All calculations are cross-validated using 1,000 iterations of sampled model training and out-of-sample model testing.

McFadden offers a stand-in for the kind of \(R^2\) used to evaluate OLS regression models4. The Probit model explains the greatest amount of variance followed closely by the bi-directional logit model. The heuristic logit model trailed significantly.

The KS statistic compares the cumulative distribution of the model predictions to the ideal distribution for that data. In this case, the heuristic model performed best of all three. While the KS-statistic is a more formal test for appropriateness of the cumulative distribution curve, Figures 2.3, 3.3, and 4.3 all indicated significant depression of scores towards lower-end probabilities than were appropriate. The heuristic model was the closest by appearance to the ideal distribution and the KS-statistic confirms that hunch.

AUC “relates the hit rate to the false alarm rate” in classification modeling 5. The heuristic model was far, far behind on this model and produced highly unstable scores. For production purposes, consistent scores will ease adoption of the model, so to the extent that political concerns factor into model selection, the inconsistency inthe AUC measures for the heuristic model are problematic.

Finally, cross-validated RMSE tests hold-out sample predictions against known values. The bidirectional logit model slightly outperforms the bidirectional probit model, but not by any significant margin. That said, the heuristic model lags significantly.

Step-wise variable selection is a computationally expensive process, but the gains in predictive accuracy more than justify the added time required to train these models. Both logistic regression and probit regression are easy enough to explain to management if the predictions are correct. Therefore the winning model is the Bidirectional Stepwise Probit method.

Appendices

Appendix A: Code to Process New Data

The below function (and package dependencies) take a file of new data and returns a file with the index, predicted likelihood of a claim, and a rough estimate of likely claim cost. The cost estimate is the median value of claims.

library(tidyverse)
library(yaztheme)
library(reshape2)
library(ggridges)
library(randomForest)
library(moments)
library(mice)
library(MASS)
library(dummies)
library(dplyr)

score_creator <- function(infile){
  train <- read_csv(infile)%>%
    mutate(INCOME = as.numeric(gsub('[$,]','',INCOME)),
           HOME_VAL = as.numeric(gsub('[$,]','',HOME_VAL)),
           BLUEBOOK = as.numeric(gsub('[$,]','',BLUEBOOK)),
           OLDCLAIM = as.numeric(gsub('[$,]','',OLDCLAIM)),
           PARENT1 = tolower(gsub('[z_<]','', PARENT1)),
           MSTATUS = tolower(gsub('[z_<]','', MSTATUS)),
           SEX = tolower(gsub('[z_<]','', SEX)),
           EDUCATION = tolower(gsub('[z_<]','', EDUCATION)),
           JOB = tolower(gsub('[z_<]','', JOB)),
           CAR_USE = tolower(gsub('[z_<]','', CAR_USE)),
           CAR_TYPE = tolower(gsub('[z_<]','', CAR_TYPE)),
           RED_CAR = tolower(gsub('[z_<]','', RED_CAR)),
           REVOKED = tolower(gsub('[z_<]','', REVOKED)),
           URBANICITY = tolower(gsub('[z_<]','', URBANICITY)))

  colnames(train) <- tolower(colnames(train))
  
  train.flagged <- train%>%
    mutate_all(funs(na.flag = ifelse(is.na(.),1,0)))
  int_df <- train.flagged%>%
    dplyr::select(-index, -target_flag, -target_amt)%>%
    dplyr::select_if(is.numeric)
  # md.pattern(int_df)
  cleaned_cols <- list()
  for(c in colnames(train%>%
                    dplyr::select(-index, -target_flag, -target_amt, -kidsdriv)%>%
                    dplyr::select_if(is.numeric))){
    column <- train.flagged%>%select_(col = c)
    iqr <- quantile(column$col, na.rm = T)[4] - quantile(column$col, na.rm = T)[2]
    low <- quantile(column$col, na.rm = T)[2] - iqr
    high <- quantile(column$col, na.rm = T)[4] + iqr
    
    vals <- c()
    for(i in seq(1:nrow(int_df))){
      ifelse(between(column$col[i], low - (1.5*iqr), high + (1.5*iqr)),
             vals[i] <- column$col[i], 
             ifelse(is.na(column$col[i]), vals[i] <- NA, vals[i] <- NA))
    }
    
    ifelse(length(vals) == nrow(int_df),
           cleaned_cols[[c]] <- vals, 
           cleaned_cols[[c]] <- c(vals,NA))
  }
  
  df2 <- bind_cols(
    bind_cols(cleaned_cols)%>%
      # select(-kidsdriv)%>%
      scale(center = TRUE)%>%
      data.frame(),
    train.flagged%>%
      dplyr::select(ends_with('na.flag'), kidsdriv),
    train%>%dplyr::select_if(is.character)
    )
  
  df3 <- df2%>%
    mutate(
      kidsdriv_out.flag = ifelse(is.na(kidsdriv) & kidsdriv_na.flag ==0,1,0),
      age_out.flag = ifelse(is.na(age) & age_na.flag ==0,1,0),
      homekids_out.flag = ifelse(is.na(homekids) & homekids_na.flag ==0,1,0),
      yoj_out.flag = ifelse(is.na(yoj) & yoj_na.flag ==0,1,0),
      income_out.flag = ifelse(is.na(income) & income_na.flag ==0,1,0),
      parent1_out.flag = ifelse(is.na(parent1) & parent1_na.flag ==0,1,0),
      home_val_out.flag = ifelse(is.na(home_val) & home_val_na.flag ==0,1,0),
      mstatus_out.flag = ifelse(is.na(mstatus) & mstatus_na.flag ==0,1,0),
      sex_out.flag = ifelse(is.na(sex) & sex_na.flag ==0,1,0),
      education_out.flag = ifelse(is.na(education) & education_na.flag ==0,1,0),
      job_out.flag = ifelse(is.na(job) & job_na.flag ==0,1,0),
      travtime_out.flag = ifelse(is.na(travtime) & travtime_na.flag ==0,1,0),
      car_use_out.flag = ifelse(is.na(car_use) & car_use_na.flag ==0,1,0),
      bluebook_out.flag = ifelse(is.na(bluebook) & bluebook_na.flag ==0,1,0),
      tif_out.flag = ifelse(is.na(tif) & tif_na.flag ==0,1,0),
      car_type_out.flag = ifelse(is.na(car_type) & car_type_na.flag ==0,1,0),
      red_car_out.flag = ifelse(is.na(red_car) & red_car_na.flag ==0,1,0),
      oldclaim_out.flag = ifelse(is.na(oldclaim) & oldclaim_na.flag ==0,1,0),
      clm_freq_out.flag = ifelse(is.na(clm_freq) & clm_freq_na.flag ==0,1,0),
      revoked_out.flag = ifelse(is.na(revoked) & revoked_na.flag ==0,1,0),
      mvr_pts_out.flag = ifelse(is.na(mvr_pts) & mvr_pts_na.flag ==0,1,0),
      car_age_out.flag = ifelse(is.na(car_age) & car_age_na.flag ==0,1,0),
      urbanicity_out.flag = ifelse(is.na(urbanicity) & urbanicity_na.flag ==0,1,0)
  )
  
  temp_df <- mice(df3, method = 'cart', maxit = 1)
  train_clean <- complete(temp_df)%>%
    bind_cols(train%>%dplyr::select(index, target_flag, target_amt))

  data.for.stepaic <- train_clean%>%
    dplyr::select(-index_na.flag, -target_flag_na.flag, -target_amt_na.flag, 
           -target_amt)%>%
    dplyr::select_if(is.numeric)%>%
    bind_cols(
      dummy.data.frame(train_clean%>%select_if(is.character))
    )
  
  med.claim <- 4104.00

  prob.preds <- data.frame(
    P_TARGET_FLAG = predict(model.prob, data.for.stepaic, type="response")
    )%>%
    bind_cols(data.for.stepaic)%>%
    mutate(P_TARGET_AMT = med.claim)%>%
    dplyr::select(INDEX = index, P_TARGET_FLAG, P_TARGET_AMT)

  return(prob.preds)
}
test_data <- score_creator('logit_insurance_test.csv')
write.csv(x = test_data, file = 'yazman_insurance_test.csv')

Sources


  1. Hoffmann, John P. Generalized Linear Models: an Applied Approach. Pearson/Allyn & Bacon, 2004.

  2. https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4842399/

  3. James, Gareth, et al. An Introduction to Statistical Learning with Applications in R. Springer, 2017.

  4. https://mathewanalytics.com/2015/09/02/logistic-regression-in-r-part-two/

  5. https://www.kdnuggets.com/2010/09/pub-is-auc-the-best-measure.html

LS0tDQp0aXRsZTogIlVuaXQgMjogTG9naXN0aWMgUmVncmVzc2lvbiBhbmQgQXV0byBJbnN1cmFuY2UgQ2xhaW1zIg0KYXV0aG9yOiAnSm9zaCBZYXptYW4nDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KIyBJbnRyb2R1Y3Rpb24NClRoZSBwcmltYXJ5IHB1cnBvc2Ugb2YgdGhpcyBhc3NpZ25tZW50IGlzIHRvIHByZWRpY3QgdGhlIGxpa2VsaWhvb2Qgb2YgYW4gYXV0byBpbnN1cmFuY2UgY3VzdG9tZXIgYmVpbmcgaW52b2x2ZWQgaW4gYW4gYWNjaWRlbnQuIEZpcnN0LCBtaXNzaW5nIGRhdGEgaXMgYWNjb3VudGVkIGZvciBhbmQsIHdoZXJlIHBvc3NpYmxlLCBudWxsIHZhbHVlcyBhbmQgb3V0bGllcnMgYXJlIGltcHV0ZWQgdXNpbmcgdmFyaWFibGUtc3BlY2lmaWMgcmVncmVzc2lvbiB0cmVlIG1vZGVscy4gVGhlbiB0aHJlZSBsb2dpc3RpYyByZWdyZXNzaW9uIGFuZCBwcm9iaXQgbW9kZWxzIGFyZSBmaXQgYW5kIGV2YWx1YXRlZC4gQWRkaXRpb25hbGx5LCBhIGJvb3N0ZWQgY2xhc3NpZmljYXRpb24gdHJlZSBtb2RlbCBpcyBkZXZlbG9wZWQgdG8gYXR0ZW1wdCB0byBpbXByb3ZlIHByZWRpY3RpdmUgYWNjdXJhY3kuIEZpbmFsbHksIGBSYCBjb2RlIGlzIHByb3ZpZGVkIHRvIHNjb3JlIGEgZnJlc2ggZGF0YSBmaWxlIGFuZCBtYWtlIHByZWRpY3Rpb25zIGZvciB0ZWFtcyBub3QgaW5jbHVkZWQgaW4gdGhlIG9yaWdpbmFsIHNhbXBsZS4gQWxsIGNvZGUgdXNlZCBpbiB0aGUgZGV2ZWxvcG1lbnQgb2YgdGhpcyBwcm9qZWN0IGNhbiBiZSBmb3VuZCBbaGVyZV0oaHR0cHM6Ly9naXRodWIuY29tL2pvc2h5YXptYW4vbm9ydGh3ZXN0ZXJuL3RyZWUvbWFzdGVyL3ByZWRpY3QtNDExL2F1dG8taW5zdXJhbmNlKS4gDQoNCiMjIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMgYW5kIFByZXANCiMjIyBNaXNzaW5nIERhdGENClRoZSBkYXRhc2V0IGluY2x1ZGVzIGluZm9ybWF0aW9uIG9uIDgsMTYxIGluc3VyYW5jZSBjdXN0b21lcnMuIFRoZSB2YXJpYWJsZXMgaW5jbHVkZWQgYXJlIGxpc3RlZCBiZWxvdyBhcyB3ZWxsIGFzIHRoZWlyIHRoZW9yZXRpY2FsIGVmZmVjdHMuDQoNCmBgYHtyLCBlY2hvID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFKQ0Kc2V0d2QoJ0M6L1VzZXJzL2pvc2h5L0dvb2dsZSBEcml2ZS9ub3J0aHdlc3Rlcm4vUFJFRElDVC00MTEvZ2VuZXJhbC1kb2NzL21vbmV5YmFsbC8nKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHlhenRoZW1lKQ0KbGlicmFyeShyZXNoYXBlMikNCmxpYnJhcnkoZ2dyaWRnZXMpDQojIGxpYnJhcnkocmFuZG9tRm9yZXN0KQ0KIyBsaWJyYXJ5KG1vbWVudHMpDQpsaWJyYXJ5KHJlYWR4bCkNCnRyYWluIDwtIHJlYWRfY3N2KCdsb2dpdF9pbnN1cmFuY2UuY3N2JyklPiUNCiAgbXV0YXRlKElOQ09NRSA9IGFzLm51bWVyaWMoZ3N1YignWyQsXScsJycsSU5DT01FKSksDQogICAgICAgICBIT01FX1ZBTCA9IGFzLm51bWVyaWMoZ3N1YignWyQsXScsJycsSE9NRV9WQUwpKSwNCiAgICAgICAgIEJMVUVCT09LID0gYXMubnVtZXJpYyhnc3ViKCdbJCxdJywnJyxCTFVFQk9PSykpLA0KICAgICAgICAgT0xEQ0xBSU0gPSBhcy5udW1lcmljKGdzdWIoJ1skLF0nLCcnLE9MRENMQUlNKSksDQogICAgICAgICBQQVJFTlQxID0gdG9sb3dlcihnc3ViKCdbel88XScsJycsIFBBUkVOVDEpKSwNCiAgICAgICAgIE1TVEFUVVMgPSB0b2xvd2VyKGdzdWIoJ1t6XzxdJywnJywgTVNUQVRVUykpLA0KICAgICAgICAgU0VYID0gdG9sb3dlcihnc3ViKCdbel88XScsJycsIFNFWCkpLA0KICAgICAgICAgRURVQ0FUSU9OID0gdG9sb3dlcihnc3ViKCdbel88XScsJycsIEVEVUNBVElPTikpLA0KICAgICAgICAgSk9CID0gdG9sb3dlcihnc3ViKCdbel88XScsJycsIEpPQikpLA0KICAgICAgICAgQ0FSX1VTRSA9IHRvbG93ZXIoZ3N1YignW3pfPF0nLCcnLCBDQVJfVVNFKSksDQogICAgICAgICBDQVJfVFlQRSA9IHRvbG93ZXIoZ3N1YignW3pfPF0nLCcnLCBDQVJfVFlQRSkpLA0KICAgICAgICAgUkVEX0NBUiA9IHRvbG93ZXIoZ3N1YignW3pfPF0nLCcnLCBSRURfQ0FSKSksDQogICAgICAgICBSRVZPS0VEID0gdG9sb3dlcihnc3ViKCdbel88XScsJycsIFJFVk9LRUQpKSwNCiAgICAgICAgIFVSQkFOSUNJVFkgPSB0b2xvd2VyKGdzdWIoJ1t6XzxdJywnJywgVVJCQU5JQ0lUWSkpKQ0KY29sbmFtZXModHJhaW4pIDwtIHRvbG93ZXIoY29sbmFtZXModHJhaW4pKQ0KZGljdCA8LSByZWFkX3hsc3goJ0RhdGFEaWN0aW9uYXJ5X0luc3VyYW5jZS54bHN4JykNCmtuaXRyOjprYWJsZShkaWN0LCBmb3JtYXQgPSAncGFuZG9jJykNCiMgdGVzdCA8LSByZWFkX2NzdignbG9naXRfaW5zdXJhbmNlX3Rlc3QuY3N2JykNCmBgYA0KDQpTb21lIGJhc2ljIGV4cGxhbmF0b3J5IHBsb3RzIGFuZCBjb3JyZWxhdGlvbnMgYXJlIHByZXNlbnRlZCBiZWxvdy4gMjYlIG9mIGN1c3RvbWVycyBoYXZlIGJlZW4gaW52b2x2ZWQgaW4gYW4gYWNjaWRlbnQuIE1hbnkgb2YgdGhlIHZhcmlhYmxlcyBmb2xsb3cgYSBuaWNlLCBub3JtYWwgZGlzdHJpYnV0aW9uIGxpa2UgYWdlIGFuZCB0cmFnZWwgdGltZS4gQnV0IG90aGVycywgbGlrZSBob21lIHZhbHVlLCBhbmQgaW5jb21lIGFyZSBwb3NpdGl2ZWx5IHNrZXdlZC4gVGhlIGRhdGEgd2lsbCBuZWVkIHRvIGJlIGFwcHJvcHJpYXRlbHkgdHJhbnNmb3JtZWQgdG8gYmUgdXNlZnVsIGZvciBwcmVkaWN0aXZlIHB1cnBvc2VzLiBObyBzaW5nbGUgbnVtZXJpYyB2YXJpYWJsZSBoYXMgYW4gaW5jcmVkaWJseSBoaWdoIGNvcnJlbGF0aW9uIHdpdGggY2xhaW0gbGlrZWxpaG9vZCwgYnV0IG51bWJlciBvZiBwYXN0IGNsYWltcyBhbmQgbW92aW5nIHZpb2xhdGlvbiBwb2ludHMgYXJlIGNsb3Nlc3QgLSBleHBsYWluaW5nIGFib3V0IDIwJSBvZiB0aGUgdmFyaWF0aW9uIGluIGNyYXNoZXMuIA0KYGBge3IsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZT1GQUxTRSwgZmlnLndpZHRoPTEyfQ0Kc3VtbWFyeSh0cmFpbl9mb3Jfc3VtJT4lZHBseXI6OnNlbGVjdCgtaW5kZXgsIC10YXJnZXRfYW10KSU+JXNlbGVjdF9pZihpcy5udW1lcmljKSkNCmBgYA0KDQpUaGUgZGF0YSBpcyBsYXJnZWx5IGNvbXBsZXRlLiBUaGUgdmFyaWFibGVzIHdpdGggdGhlIG1vc3QgbnVsbCB2YWx1ZXMgYXJlIG9ubHkgNS02JSBpbmNvbXBsZXRlLiANCmBgYHtyfQ0KIyMgWW91ciBmaXJzdCBzdGVwIGlzIHRvIHR1cm4gb3V0bGllcnMgaW50byBudWxsIHZhbHVlcyANCm51bGxzIDwtIGRhdGEuZnJhbWUoY29sID0gYXMuY2hhcmFjdGVyKGNvbG5hbWVzKHRyYWluKSksIA0KICAgICAgICAgICAgICAgICAgICBwY3RfbnVsbCA9IGNvbFN1bXMoaXMubmEodHJhaW4pKSoxMDAvKGNvbFN1bXMoaXMubmEodHJhaW4pKStjb2xTdW1zKCFpcy5uYSh0cmFpbikpKSklPiUNCiAgZmlsdGVyKGNvbCAhPSAnSU5ERVgnKQ0KZ2dwbG90KG51bGxzLCBhZXMoeCA9IGNvbCwgeSA9IHBjdF9udWxsKSkrDQogIGdlb21fYmFyKGZpbGwgPSB5YXpfY29sc1sxXSwgc3RhdCA9ICdpZGVudGl0eScpKw0KICBjb29yZF9mbGlwKCkrDQogIGxhYnModGl0bGUgPSAnRmlndXJlIDE6IERpc3RyaWJ1dGlvbiBvZiBNaXNzaW5nIERhdGEnLA0KICAgICAgIHggPSBlbGVtZW50X2JsYW5rKCksIHkgPSAnUGVyY2VudCBvZiBJbmZvcm1hdGlvbiBNaXNzaW5nJykrDQogIHRoZW1lX3lheigpKw0KICB5bGltKDAsMTAwKQ0KYGBgDQoNClJlZ3Jlc3Npb24gYW5kIGNsYXNzaWZpY2F0aW9uIHRyZWVzIGFyZSB1c2VkIHRvIGltcHV0ZSBtaXNzaW5nIHZhbHVlcy4gQWRkaXRpb25hbGx5LCBvdXRsaWVyIHZhcmlhYmxlcyBhcmUgZGVsZXRlZCBhbmQgaW1wdXRlZCB1c2luZyB0aGUgc2FtZSBtZXRob2RzLiBCaW5hcnkgZmxhZ3MgYXJlIGdlbmVyYXRlZCBmb3IgdmFsdWVzIGltcHV0ZWQgZm9yIGVhY2ggcG9zc2libGUgcmVhc29uLiBGaW5hbGx5LCBhbGwgdmFsdWVzIGFyZSBzY2FsZWQgYW5kIGNlbnRlcmVkIHRvIHN0YWJpbGl6ZSBtb2RlbCBlc3RpbWF0ZXMuDQpgYGB7cn0NCmNvbG5hbWVzKHRyYWluKSA8LSB0b2xvd2VyKGNvbG5hbWVzKHRyYWluKSkNCg0KdHJhaW4uZmxhZ2dlZCA8LSB0cmFpbiU+JQ0KICBtdXRhdGVfYWxsKGZ1bnMobmEuZmxhZyA9IGlmZWxzZShpcy5uYSguKSwxLDApKSkNCmludF9kZiA8LSB0cmFpbi5mbGFnZ2VkJT4lDQogIGRwbHlyOjpzZWxlY3QoLWluZGV4LCAtdGFyZ2V0X2ZsYWcsIC10YXJnZXRfYW10KSU+JQ0KICBkcGx5cjo6c2VsZWN0X2lmKGlzLm51bWVyaWMpDQojIG1kLnBhdHRlcm4oaW50X2RmKQ0KY2xlYW5lZF9jb2xzIDwtIGxpc3QoKQ0KZm9yKGMgaW4gY29sbmFtZXModHJhaW4lPiUNCiAgICAgICAgICAgICAgICAgIGRwbHlyOjpzZWxlY3QoLWluZGV4LCAtdGFyZ2V0X2ZsYWcsIC10YXJnZXRfYW10LCAta2lkc2RyaXYpJT4lDQogICAgICAgICAgICAgICAgICBkcGx5cjo6c2VsZWN0X2lmKGlzLm51bWVyaWMpKSl7DQogIGNvbHVtbiA8LSB0cmFpbi5mbGFnZ2VkJT4lc2VsZWN0Xyhjb2wgPSBjKQ0KICBpcXIgPC0gcXVhbnRpbGUoY29sdW1uJGNvbCwgbmEucm0gPSBUKVs0XSAtIHF1YW50aWxlKGNvbHVtbiRjb2wsIG5hLnJtID0gVClbMl0NCiAgbG93IDwtIHF1YW50aWxlKGNvbHVtbiRjb2wsIG5hLnJtID0gVClbMl0gLSBpcXINCiAgaGlnaCA8LSBxdWFudGlsZShjb2x1bW4kY29sLCBuYS5ybSA9IFQpWzRdICsgaXFyDQogIA0KICB2YWxzIDwtIGMoKQ0KICBmb3IoaSBpbiBzZXEoMTpucm93KGludF9kZikpKXsNCiAgICBpZmVsc2UoYmV0d2Vlbihjb2x1bW4kY29sW2ldLCBsb3cgLSAoMS41KmlxciksIGhpZ2ggKyAoMS41KmlxcikpLA0KICAgICAgICAgICB2YWxzW2ldIDwtIGNvbHVtbiRjb2xbaV0sIA0KICAgICAgICAgICBpZmVsc2UoaXMubmEoY29sdW1uJGNvbFtpXSksIHZhbHNbaV0gPC0gTkEsIHZhbHNbaV0gPC0gTkEpKQ0KICB9DQogIA0KICBpZmVsc2UobGVuZ3RoKHZhbHMpID09IG5yb3coaW50X2RmKSwNCiAgICAgICAgIGNsZWFuZWRfY29sc1tbY11dIDwtIHZhbHMsIA0KICAgICAgICAgY2xlYW5lZF9jb2xzW1tjXV0gPC0gYyh2YWxzLE5BKSkNCn0NCg0KZGYyIDwtIGJpbmRfY29scygNCiAgYmluZF9jb2xzKGNsZWFuZWRfY29scyklPiUNCiAgICAjIHNlbGVjdCgta2lkc2RyaXYpJT4lDQogICAgc2NhbGUoY2VudGVyID0gVFJVRSklPiUNCiAgICBkYXRhLmZyYW1lKCksDQogIHRyYWluLmZsYWdnZWQlPiUNCiAgICBkcGx5cjo6c2VsZWN0KGVuZHNfd2l0aCgnbmEuZmxhZycpLCBraWRzZHJpdiksDQogIHRyYWluJT4lZHBseXI6OnNlbGVjdF9pZihpcy5jaGFyYWN0ZXIpDQogICkNCg0KZGYzIDwtIGRmMiU+JQ0KICBtdXRhdGUoDQogICAga2lkc2RyaXZfb3V0LmZsYWcgPSBpZmVsc2UoaXMubmEoa2lkc2RyaXYpICYga2lkc2RyaXZfbmEuZmxhZyA9PTAsMSwwKSwNCiAgICBhZ2Vfb3V0LmZsYWcgPSBpZmVsc2UoaXMubmEoYWdlKSAmIGFnZV9uYS5mbGFnID09MCwxLDApLA0KICAgIGhvbWVraWRzX291dC5mbGFnID0gaWZlbHNlKGlzLm5hKGhvbWVraWRzKSAmIGhvbWVraWRzX25hLmZsYWcgPT0wLDEsMCksDQogICAgeW9qX291dC5mbGFnID0gaWZlbHNlKGlzLm5hKHlvaikgJiB5b2pfbmEuZmxhZyA9PTAsMSwwKSwNCiAgICBpbmNvbWVfb3V0LmZsYWcgPSBpZmVsc2UoaXMubmEoaW5jb21lKSAmIGluY29tZV9uYS5mbGFnID09MCwxLDApLA0KICAgIHBhcmVudDFfb3V0LmZsYWcgPSBpZmVsc2UoaXMubmEocGFyZW50MSkgJiBwYXJlbnQxX25hLmZsYWcgPT0wLDEsMCksDQogICAgaG9tZV92YWxfb3V0LmZsYWcgPSBpZmVsc2UoaXMubmEoaG9tZV92YWwpICYgaG9tZV92YWxfbmEuZmxhZyA9PTAsMSwwKSwNCiAgICBtc3RhdHVzX291dC5mbGFnID0gaWZlbHNlKGlzLm5hKG1zdGF0dXMpICYgbXN0YXR1c19uYS5mbGFnID09MCwxLDApLA0KICAgIHNleF9vdXQuZmxhZyA9IGlmZWxzZShpcy5uYShzZXgpICYgc2V4X25hLmZsYWcgPT0wLDEsMCksDQogICAgZWR1Y2F0aW9uX291dC5mbGFnID0gaWZlbHNlKGlzLm5hKGVkdWNhdGlvbikgJiBlZHVjYXRpb25fbmEuZmxhZyA9PTAsMSwwKSwNCiAgICBqb2Jfb3V0LmZsYWcgPSBpZmVsc2UoaXMubmEoam9iKSAmIGpvYl9uYS5mbGFnID09MCwxLDApLA0KICAgIHRyYXZ0aW1lX291dC5mbGFnID0gaWZlbHNlKGlzLm5hKHRyYXZ0aW1lKSAmIHRyYXZ0aW1lX25hLmZsYWcgPT0wLDEsMCksDQogICAgY2FyX3VzZV9vdXQuZmxhZyA9IGlmZWxzZShpcy5uYShjYXJfdXNlKSAmIGNhcl91c2VfbmEuZmxhZyA9PTAsMSwwKSwNCiAgICBibHVlYm9va19vdXQuZmxhZyA9IGlmZWxzZShpcy5uYShibHVlYm9vaykgJiBibHVlYm9va19uYS5mbGFnID09MCwxLDApLA0KICAgIHRpZl9vdXQuZmxhZyA9IGlmZWxzZShpcy5uYSh0aWYpICYgdGlmX25hLmZsYWcgPT0wLDEsMCksDQogICAgY2FyX3R5cGVfb3V0LmZsYWcgPSBpZmVsc2UoaXMubmEoY2FyX3R5cGUpICYgY2FyX3R5cGVfbmEuZmxhZyA9PTAsMSwwKSwNCiAgICByZWRfY2FyX291dC5mbGFnID0gaWZlbHNlKGlzLm5hKHJlZF9jYXIpICYgcmVkX2Nhcl9uYS5mbGFnID09MCwxLDApLA0KICAgIG9sZGNsYWltX291dC5mbGFnID0gaWZlbHNlKGlzLm5hKG9sZGNsYWltKSAmIG9sZGNsYWltX25hLmZsYWcgPT0wLDEsMCksDQogICAgY2xtX2ZyZXFfb3V0LmZsYWcgPSBpZmVsc2UoaXMubmEoY2xtX2ZyZXEpICYgY2xtX2ZyZXFfbmEuZmxhZyA9PTAsMSwwKSwNCiAgICByZXZva2VkX291dC5mbGFnID0gaWZlbHNlKGlzLm5hKHJldm9rZWQpICYgcmV2b2tlZF9uYS5mbGFnID09MCwxLDApLA0KICAgIG12cl9wdHNfb3V0LmZsYWcgPSBpZmVsc2UoaXMubmEobXZyX3B0cykgJiBtdnJfcHRzX25hLmZsYWcgPT0wLDEsMCksDQogICAgY2FyX2FnZV9vdXQuZmxhZyA9IGlmZWxzZShpcy5uYShjYXJfYWdlKSAmIGNhcl9hZ2VfbmEuZmxhZyA9PTAsMSwwKSwNCiAgICB1cmJhbmljaXR5X291dC5mbGFnID0gaWZlbHNlKGlzLm5hKHVyYmFuaWNpdHkpICYgdXJiYW5pY2l0eV9uYS5mbGFnID09MCwxLDApDQopDQoNCmxpYnJhcnkobWljZSkNCnRlbXBfZGYgPC0gbWljZShkZjMsIG1ldGhvZCA9ICdjYXJ0JywgbWF4aXQgPSAxKQ0KdHJhaW5fY2xlYW4gPC0gY29tcGxldGUodGVtcF9kZiklPiUNCiAgYmluZF9jb2xzKHRyYWluJT4lZHBseXI6OnNlbGVjdChpbmRleCwgdGFyZ2V0X2ZsYWcsIHRhcmdldF9hbXQpKQ0KYGBgDQoNCiMgTW9kZWwgRGV2ZWxvcG1lbnQNClRocmVlIG1vZGVscyBhcmUgZGV2ZWxvcGVkIGFzIHBhcnQgb2YgdGhpcyBwcm9qZWN0IC0gYSBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsIHVzaW5nIGhldXJpc3RpYyB2YXJpYWJsZSBzZWxlY3Rpb24sIGEgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbCB3aXRoIHZhcmlhYmxlcyBzZWxlY3RlZCB0aHJvdWdoIGEgYmktZGlyZWN0aW9uYWwgc3RlcHdpc2UgcHJvY2VzcyBtZWFudCB0byBtaW5pbWl6ZSBBSUMsIGFuZCBhIHByb2JpdCByZWdyZXNzaW9uIG1vZGVsIHVzaW5nIHRoZSBzYW1lIHZhcmlhYmxlIHNlbGVjdGlvbiB0ZWNobmlxdWUuDQoNCiMjIEhldXJpc3RpYyBMb2dpc3RpYw0KVGhlIGZpcnN0IG1vZGVsIGRldmVsb3BlZCBpcyBhIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwgdGFraW5nIGFsbCBpbnB1dHMgd2hlcmUgdGhlIGRhdGEgZGljdGlvbmFyeSBjb250YWlucyBzb21lIHRoZW9yZXRpY2FsIGltcGFjdCBvbiBhY2NpZGVudCBsaWtlbGlob29kLiBMb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVscyB3b3JrIHNpbWlsYXJseSB0byBPTFMgcmVncmVzc2lvbiBtb2RlbHMsIGJ1dCB0aGUgT0xTIGZvcm11bGEgaXMgdHJhbnNmb3JtZWQgYW5kIGludmVydGVkIHRvIHByb2R1Y2UgcHJvYmFiaWxpdGllcyBvZiBiaW5hcnkgb3V0Y29tZXMgcmF0aGVyIHRoYW4gcG9pbnQgZXN0aW1hdGVzIG9mIGEgY29udGludW91cyB2YXJpYWJsZVteMV0uDQoNCiMjIyBQZXJmb3JtYW5jZQ0KRmlndXJlcyAyLjEgYW5kIDIuMiBpbGx1c3RyYXRlIGEgdHJvdWJsaW5nIHRlbmRlbmN5IHRvIHJldHVybiBpbmNvcnJlY3RseSBsb3cgYWNjaWRlbnQgcHJvYmFiaWxpdGllcy4gVG9vIG1hbnkgaW5uYWN1cmF0ZWx5IGxvdyBwcmVkaWN0aW9ucyBjb3VsZCBsZWFkIHRvIHRoZSBjb21wYW55IHRha2luZyBvbiBtb3JlIGNsYWltcyB0aGFuIHByZW1pdW1zLiAgQWRkaXRpb25hbGx5LCB0aG9zZSByZWNvcmRzIHdpdGggaGlnaCBwcm9iYWJpbGl0eSBzY29yZXMgKGluIHRoZSA5MHMpIGRvbid0IHRlbmQgdG8gaGF2ZSBtb3JlIGFjY2lkZW50cyB0aGFuIHNvbWUgbG93ZXIgc2NvcmUgZ3JvdXBpbmdzIG9uIGFnZ3JlZ2F0ZSAoaW4gdGhlIDcwcyBhbmQgODBzKS4gDQpgYGB7ciwgZWNobz1GQUxTRSwgZmlnLmhlaWdodCA9IDMsIGZpZy53aWR0aD0gMTF9DQptZXRob2RbMV0gPC0gJ0hldXJpc3RpYycNCg0KcHJlZHMubGlzdCA8LSBsaXN0KCkNCm1jZmFkZGVucnNxIDwtIGMoKQ0Ka3Muc3RhdCA8LSBjKCkNCmF1YyA8LSBjKCkNCnJtc2UgPC0gYygpDQoNCmZvcihpIGluIDE6MTAwMCl7DQogIHRyYWluLnRlbXAgPC0gc2FtcGxlX2ZyYWModHJhaW5fY2xlYW4sIC44LCByZXBsYWNlID0gVFJVRSkNCiAgdGVzdC50ZW1wIDwtIHRyYWluX2NsZWFuJT4lZmlsdGVyKCFpbmRleCAlaW4lIHRyYWluLnRlbXAkaW5kZXgpDQogIA0KICBtb2RlbC5sb2cxIDwtIGdsbSh0YXJnZXRfZmxhZyB+IGFnZSArIGNhcl91c2UgKyBjbG1fZnJlcSArIGhvbWVfdmFsICsgDQogICAgICAgICAgICAgICAgICAgICAgam9iICsga2lkc2RyaXYgKyBtdnJfcHRzICsgb2xkY2xhaW0gKyByZWRfY2FyICsgDQogICAgICAgICAgICAgICAgICAgICAgcmV2b2tlZCArIHNleCArIHRpZiArIHRyYXZ0aW1lICsgeW9qLCANCiAgICAgICAgICAgICAgICAgICAgdHJhaW4udGVtcCwgZmFtaWx5PWJpbm9taWFsKCJsb2dpdCIpKQ0KICANCiAgcHJlZHMgPC0gcHJlZGljdChtb2RlbC5sb2cxLCB0ZXN0LnRlbXAsIHR5cGU9InJlc3BvbnNlIikNCiAgDQogIGxvZzEucHJlZHMgPC0gZGF0YS5mcmFtZSgNCiAgICBpbmRleCA9IHRlc3QudGVtcCRpbmRleCwNCiAgICBhY3R1YWwgPSB0ZXN0LnRlbXAkdGFyZ2V0X2ZsYWcsDQogICAgcHJlZHMNCiAgICApJT4lDQogICAgbXV0YXRlKHJlc2lkdWFsID0gcHJlZHMgLSBhY3R1YWwpDQogIHByZWRzLmxpc3RbW2ldXSA8LSBsb2cxLnByZWRzDQogIA0KICBtY2ZhZGRlbnJzcVtpXSA8LSBhcy5udW1lcmljKHBzY2w6OnBSMihtb2RlbC5sb2cxKVs0XSkNCiAga3Muc3RhdFtpXSA8LSBrcy50ZXN0KHByZWRzLCAicG5vcm0iLCAxLCAyKSRzdGF0aXN0aWMNCiAgYXVjW2ldIDwtIHBST0M6OnJvYyh0YXJnZXRfZmxhZyB+IHByZWRzLCBkYXRhID0gdGVzdC50ZW1wKSRhdWNbMV0NCiAgcm1zZVtpXSA8LSBzcXJ0KG1lYW4obG9nMS5wcmVkcyRyZXNpZHVhbF4yLCBuYS5ybSA9IFQpKQ0KfQ0KDQpib290LmxvZzEucHJlZHMgIDwtIGJpbmRfcm93cyhwcmVkcy5saXN0KQ0KDQpsb2cxZ29mIDwtIGRhdGEuZnJhbWUobWNmYWRkZW5yc3EsIGtzLnN0YXQsIGF1Yywgcm1zZSklPiUNCiAgbXV0YXRlKG1ldGhvZCA9IG1ldGhvZFsxXSkNCg0KbG9nLmRpc3QgPC0gZ2dwbG90KGJvb3QubG9nMS5wcmVkcyU+JQ0KICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoaW5kZXgsIGFjdHVhbCklPiUNCiAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZShtZWFuLnByZWQgPSBtZWFuKHByZWRzLCBuYS5ybSA9IFQpKSU+JQ0KICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKHJlc2lkdWFsID0gbWVhbi5wcmVkIC0gYWN0dWFsKSwgDQogICAgICAgICAgICAgICAgICAgYWVzKHggPSBtZWFuLnByZWQsIGZpbGwgPSBhcy5jaGFyYWN0ZXIoYWN0dWFsKSkpKw0KICAgIGdlb21fZGVuc2l0eShhbHBoYSA9IC43NSkrDQogICAgbGFicyh0aXRsZSA9ICdGaWcgMi4xOiBMb2cuIFJlZyBEb25hdGlvbiBQcm9wLicsDQogICAgICAgICB5ID0gJ0ZyZXF1ZW5jeScsDQogICAgICAgICB4ID0gJ0NsYWltIExpa2VsaWhvb2QgU2NvcmUnLA0KICAgICAgICAgc3VidGl0bGUgPSAnUHJlZGljdGVkIHZzLiBBY3R1YWwnKSsNCiAgICB0aGVtZV95YXooYmFzZV9zaXplID0gMTApKw0KICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHlhel9jb2xzWzQ6NV0sIA0KICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAnVmFsaWRhdGVkIENsYXNzaWZpY2F0aW9uJywgDQogICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygnTm8gQ2xhaW0nLCdDbGFpbWFudCcpKQ0KDQpsb2cucmlkZ2VzIDwtIGdncGxvdChib290LmxvZzEucHJlZHMlPiUNCiAgICAgICAgIGdyb3VwX2J5KHJvdW5kZWQgPSBhcy5udW1lcmljKHN1YnN0cihhcy5jaGFyYWN0ZXIocHJlZHMpLDEsMykpKSU+JQ0KICAgICAgICAgbXV0YXRlKHBjdF9ncm91cGVkID0gbWVhbihhY3R1YWwsIG5hLnJtID1UKSwNCiAgICAgICAgICAgICAgICBncm91cF9uID0gbigpKSU+JQ0KICAgICAgICAgdW5ncm91cCgpJT4lDQogICAgICAgICBmaWx0ZXIoIWlzLm5hKHJvdW5kZWQpKSwgDQogICAgICAgYWVzKHggPSBwY3RfZ3JvdXBlZCwgeSA9IHJlb3JkZXIoYXMuY2hhcmFjdGVyKHJvdW5kZWQpLCByb3VuZGVkKSwNCiAgICAgICAgICAgYWxwaGEgPSBncm91cF9uKSkrDQogIGdlb21fZGVuc2l0eV9yaWRnZXMoZmlsbCA9IHlhel9jb2xzWzFdLCB3ZWlnaHQgPSAuNSkrDQogIHRoZW1lX3lheigpKw0KICBsYWJzKHRpdGxlID0gJ0ZpZyAyLjI6IExvZy4gUmVnLiBTY29yZSBBY2N1cmFjeScsDQogICAgICAgICB5ID0gJ1ByZWRpY3RlZCBQcm9iYWJpbGl0eScsDQogICAgICAgICB4ID0gJ1Byb3BvcnRpb24gV2hvIEFyZSBDbGFpbWFudHMnLA0KICAgICAgICAgc3VidGl0bGUgPSBwYXN0ZTAoJ1ByZWRpY3RlZCB2YWx1ZXMgaW4gdGhlIHZlcmlmaWNhdGlvbiBzZXQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1xuKERhcmtlciBwbG90cyBpbmRpY2F0ZSBncmVhdGVyIGZyZXF1ZW5jaWVzKS4nKSkrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdub25lJykrDQogIHhsaW0oMCwxKQ0KDQojIERpc3BsYXkgdGhlIGRpc3RyaWJ1dGlvbiBvZiByZXNpZHVhbHMNCmxvZzEuZWNkZiA8LSBnZ3Bsb3QoYm9vdC5sb2cxLnByZWRzJT4lDQogICAgICAgICAgICAgICAgICAgICBncm91cF9ieShpbmRleCwgYWN0dWFsKSU+JQ0KICAgICAgICAgICAgICAgICAgICAgc3VtbWFyaXNlKG1lYW4ucHJlZCA9IG1lYW4ocHJlZHMsIG5hLnJtID0gVCkpLCANCiAgICAgICAgICAgICAgICAgICBhZXMoeCA9IG1lYW4ucHJlZCkpKw0KICBzdGF0X2VjZGYoZ2VvbSA9ICdwb2ludCcsIGNvbG9yID0geWF6X2NvbHNbMV0pKw0KICB0aGVtZV95YXooKSsNCiAgbGFicyh0aXRsZSA9ICdGaWcgMi4zOiBIZXVyaXN0aWMgRUNERicsDQogICAgICAgeSA9ICdBY2NpZGVudCBGcmVxdWVuY3knLCB4ID0gJ0FjY2lkZW50IFByb2JhYmlsaXR5JywNCiAgICAgICBzdWJ0aXRsZSA9ICcgJykNCg0KDQpncmlkLmFycmFuZ2UobG9nLmRpc3QsIGxvZy5yaWRnZXMsIGxvZzEuZWNkZixucm93ID0gMSkNCmBgYA0KDQojIyMgTW9kZWwgQ29tcG9zaXRpb24NClRoZSBzdHJvbmdlc3QgdmFyaWFibGUgaW4gdGhlIG1vZGVsIGlzIHdoZXRoZXIgb3Igbm90IGEgY3VzdG9tZXIncyBkcml2ZXIncyBsaWNlbnNlIGhhcyBiZWVuIHJldm9rZWQgaW4gdGhlIHBhc3Qgc2V2ZW4geWVhcnMuIEtpZCBkcml2ZXJzIGFuZCBhIHByZXBvbmRlcmFuY2Ugb2YgbW92aW5nIHZpb2xhdGlvbiBwb2ludHMgYWxzbyBjb250cmlidXRlIHRvIGNsYWltIGxpa2VsaWhvb2Qgd2hpY2ggbWFrZXMgc2Vuc2UuIEFsbW9zdCBhbGwgdmFyaWFibGUgY29lZmZpY2llbnRzIGFyZSBzaWduaWZpY2FudCBhbmQgcGVyZm9ybSBhY2NvcmRpbmcgdG8gdGhlIGFzc3VtcHRpb25zIG1hZGUgaW4gdGhlIGRhdGEgZGljdGlvbmFyeS4NCg0KYGBge3J9DQptb2RlbC5sb2cxIDwtIGdsbSh0YXJnZXRfZmxhZyB+IGFnZSArIGNhcl91c2UgKyBjbG1fZnJlcSArIGhvbWVfdmFsICsgDQogICAgICAgICAgICAgICAgICAgICAgam9iICsga2lkc2RyaXYgKyBtdnJfcHRzICsgb2xkY2xhaW0gKyByZWRfY2FyICsgDQogICAgICAgICAgICAgICAgICAgICAgcmV2b2tlZCArIHNleCArIHRpZiArIHRyYXZ0aW1lICsgeW9qLCANCiAgICAgICAgICAgICAgICAgICAgdHJhaW5fY2xlYW4sIGZhbWlseT1iaW5vbWlhbCgibG9naXQiKSkNCg0KbW9kLmxvZzEucGFydHMgPC0gc3VtbWFyeShtb2RlbC5sb2cxKSRjb2VmZmljaWVudHMlPiUNCiAgZGF0YS5mcmFtZSgpJT4lDQogIGJpbmRfY29scyhkYXRhLmZyYW1lKHZhcnMgPSByb3duYW1lcyhzdW1tYXJ5KG1vZGVsLmxvZzEpJGNvZWZmaWNpZW50cykpKSU+JQ0KICBkcGx5cjo6c2VsZWN0KGVzdCA9IEVzdGltYXRlLCBzZSA9IFN0ZC4uRXJyb3IsIHAgPSBQci4uLnouLiwgdmFycykNCg0KZ2dwbG90KG1vZC5sb2cxLnBhcnRzLCBhZXMoeCA9IHJlb3JkZXIodmFycywgZXN0KSwgeSA9IGVzdCwgY29sb3IgPSBwKSkrDQogIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBlc3QgLSBzZSwgeW1heCA9IGVzdCArIHNlKSwNCiAgICAgICAgICAgICAgICB3aWR0aCA9IDAsIHNpemUgPSAyKSsNCiAgbGFicyh5ID0gJ0NvZWZmaWNpZW50IEVzdGltYXRlICgrLSAxIFN0YW5kYXJkIEVycm9yKScsDQogICAgICAgdGl0bGUgPSAnTW9kZWwgQ29lZmZpY2llbnQgRXN0aW1hdGVzJywNCiAgICAgICB4ID0gZWxlbWVudF9ibGFuaygpKSsNCiAgdGhlbWVfeWF6KCkrDQogIGNvb3JkX2ZsaXAoKSsNCiAgc2NhbGVfY29sb3JfY29udGludW91cyhoaWdoID0geWF6X2NvbHNbNF0sIGxvdyA9IHlhel9jb2xzWzNdLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoMCwgLjAwMSwgLjAxLCAuMDUsIC4xKSxndWlkZSA9ICdsZWdlbmQnKSsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAnZGFzaGVkJykNCmBgYA0KDQojIyBCaWRpcmVjdGlvbmFsIFZhcmlhYmxlIFNlbGVjdGlvbiBMb2dpc3RpYyBSZWdyZXNzaW9uDQpUaGUgc2Vjb25kIG1vZGVsIHRlc3RlZCBpcyBhIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwgZGV2ZWxvcGVkIHdpdGggYSBiYWNrd2FyZCB2YXJpYWJsZSBzZWxlY3Rpb24gcHJvY2Vzcy4gU3RhcnRpbmcgd2l0aCBhIGxvZ2l0IG1vZGVsIHVzaW5nIGFsbCBwb3NzaWJsZSB2YXJpYWJsZXMgdGhlIG1vZGVsIGl0ZXJhdGl2ZWx5IHdvcmtzIHRocm91Z2ggcG9zc2libGUgc2V0cyBvZiBwcmVkaWN0b3IgdmFyaWFibGVzLCBhZGRpbmcgYW5kIGRyb3BwaW5nIHZhcmlhYmxlcyB0byBtaW5pbWl6ZSBBSUNbXjJdW14zXS4gSXQncyBhIGNvbXB1dGF0aW9uYWxseSBleHBlbnNpdmUgcHJvY2Vzcywgd2hpY2ggY291bGQgYmVjb21lIGEgZmFjdG9yIGluIHByb2R1Y3Rpb24gZGVjaXNpb25zLiBIb3dldmVyLCB0aGUgZ2FpbnMgdG8gcHJlZGljdGl2ZSBhY2N1cmFjeSBtYXkgYmUgd29ydGh3aGlsZS4gDQoNCiMjIyBQZXJmb3JtYW5jZQ0KRmlndXJlIDMuMSBsb29rcyBuZWFybHkgaWRlbnRpY2FsIHRvIDIuMSAtIGVzcGVjaWFsbHkgdGhlIGRpc3RyaWJ1dGlvbnMgb2Ygc2NvcmVzIGZvciBjbGFpbWFudHMgd2hpY2ggc2tldyB0b28gbG93LiBUaGUgY3VtdWxhdGl2ZSBkZW5zaXR5IHBsb3QgKEZpZ3VyZSAzLjMpIGxvb2tzIHNsaWdodGx5IG1vcmUgc2tld2VkIHRoYW4gdGhhdCBpbiAyLjMuIEJ1dCB0aGUgcHJlZGljdGl2ZSBhY2N1cmFjeSBpbGx1c3RyYXRlZCBpbiBGaWd1cmUgMy4yIGRlbW9uc3RyYXRlcyBzaWduaWZpY2FueSBpbXByb3ZlbWVudCBvdmVyIHRoZSBoZXVyc2l0YyBtb2RlbC4gDQpgYGB7ciwgZWNobz1GQUxTRSwgZmlnLmhlaWdodCA9IDMsIGZpZy53aWR0aD0gMTF9DQojIFR1dG9yaWFsOiBodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3BtYy9hcnRpY2xlcy9QTUM0ODQyMzk5Lw0KbGlicmFyeShNQVNTKQ0KbGlicmFyeShkdW1taWVzKQ0KDQpkYXRhLmZvci5zdGVwYWljIDwtIHRyYWluX2NsZWFuJT4lDQogIGRwbHlyOjpzZWxlY3QoLWluZGV4X25hLmZsYWcsIC10YXJnZXRfZmxhZ19uYS5mbGFnLCAtdGFyZ2V0X2FtdF9uYS5mbGFnLCANCiAgICAgICAgIC10YXJnZXRfYW10LCAtaW5kZXgpJT4lDQogIHNlbGVjdF9pZihpcy5udW1lcmljKSU+JQ0KICBiaW5kX2NvbHMoDQogICAgZHVtbXkuZGF0YS5mcmFtZSh0cmFpbl9jbGVhbiU+JXNlbGVjdF9pZihpcy5jaGFyYWN0ZXIpKQ0KICApDQoNCmZ1bGwubW9kIDwtIGdsbSh0YXJnZXRfZmxhZ34uLCBkYXRhID0gZGF0YS5mb3Iuc3RlcGFpYywgZmFtaWx5ID0gYmlub21pYWwpDQoNCnN0ZXAgPC0gc3RlcEFJQyhmdWxsLm1vZCwgdHJhY2UgPSBULCBkaXJlY3Rpb24gPSAnYm90aCcpDQojIHByaW50IHRoZSBmb3JtdWxhIGFuZCBib290c3RyYXAgaXQhDQojIHBhc3RlMCgnZ2xtKHRhcmdldF9mbGFnficsIHBhc3RlKG5hbWVzKHN0ZXAkY29lZmZpY2llbnRzKVstMV0sIGNvbGxhcHNlID0gJysnKSwNCiMgICAgICAgICcsIGRhdGEgPSB0cmFpbi50ZW1wKSwgZmFtaWx5PWJpbm9taWFsKCJsb2dpdCIpJykpKQ0KDQptZXRob2RbMl0gPC0gJ0JpZGlyZWN0aW9uYWwgU3RlcHdpc2UgKExvZ2l0KScNCg0KcHJlZHMubGlzdC4yIDwtIGxpc3QoKQ0KbWNmYWRkZW5yc3EgPC0gYygpDQprcy5zdGF0IDwtIGMoKQ0KYXVjIDwtIGMoKQ0Kcm1zZSA8LSBjKCkNCg0KZm9yKGkgaW4gMToxMDAwKXsNCiAgdHJhaW4udGVtcCA8LSBzYW1wbGVfZnJhYyhkYXRhLmZvci5zdGVwYWljLCAuOCwgcmVwbGFjZSA9IFRSVUUpDQogIHRlc3QudGVtcCA8LSBkYXRhLmZvci5zdGVwYWljJT4lDQogICAgYmluZF9jb2xzKGRhdGEuZnJhbWUoaW5kZXggPSB0cmFpbl9jbGVhbiRpbmRleCkpJT4lDQogICAgZmlsdGVyKCFpbmRleCAlaW4lIHRyYWluLnRlbXAkaW5kZXgpDQogIA0KICBtb2RlbC5sb2cyIDwtIGdsbSh0YXJnZXRfZmxhZ35ob21la2lkcyt5b2oraW5jb21lK2hvbWVfdmFsK3RyYXZ0aW1lK2JsdWVib29rK3RpZitvbGRjbGFpbSsNCiAgICAgICAgICAgICAgICAgICAgICBjbG1fZnJlcSttdnJfcHRzK2FnZV9uYS5mbGFnK2tpZHNkcml2K29sZGNsYWltX291dC5mbGFnK212cl9wdHNfb3V0LmZsYWcrDQogICAgICAgICAgICAgICAgICAgICAgcGFyZW50MW5vK21zdGF0dXNubytgZWR1Y2F0aW9uaGlnaCBzY2hvb2xgK2Bqb2JibHVlIGNvbGxhcmArDQogICAgICAgICAgICAgICAgICAgICAgam9iY2xlcmljYWwram9iZG9jdG9yK2pvYm1hbmFnZXIrY2FyX3VzZWNvbW1lcmNpYWwrY2FyX3R5cGVtaW5pdmFuKw0KICAgICAgICAgICAgICAgICAgICAgIGBjYXJfdHlwZXNwb3J0cyBjYXJgK2Nhcl90eXBlc3V2K3Jldm9rZWRubysNCiAgICAgICAgICAgICAgICAgICAgICBgdXJiYW5pY2l0eWhpZ2hseSBydXJhbC8gcnVyYWxgLCANCiAgICAgICAgICAgICAgICAgICAgdHJhaW4udGVtcCwgZmFtaWx5PWJpbm9taWFsKCJsb2dpdCIpKQ0KICANCiAgcHJlZHMgPC0gcHJlZGljdChtb2RlbC5sb2cyLCB0ZXN0LnRlbXAsIHR5cGU9InJlc3BvbnNlIikNCg0KICBsb2cyLnByZWRzIDwtIGRhdGEuZnJhbWUoDQogICAgaW5kZXggPSB0ZXN0LnRlbXAkaW5kZXgsDQogICAgYWN0dWFsID0gdGVzdC50ZW1wJHRhcmdldF9mbGFnLA0KICAgIHByZWRzDQogICAgKSU+JQ0KICAgIG11dGF0ZShyZXNpZHVhbCA9IHByZWRzIC0gYWN0dWFsKQ0KICBwcmVkcy5saXN0LjJbW2ldXSA8LSBsb2cxLnByZWRzDQogIA0KICBtY2ZhZGRlbnJzcVtpXSA8LSBhcy5udW1lcmljKHBzY2w6OnBSMihtb2RlbC5sb2cyKVs0XSkNCiAga3Muc3RhdFtpXSA8LSBrcy50ZXN0KHByZWRzLCAicG5vcm0iLCAxLCAyKSRzdGF0aXN0aWMNCiAgYXVjW2ldIDwtIHBST0M6OnJvYyh0YXJnZXRfZmxhZyB+IHByZWRzLCBkYXRhID0gdGVzdC50ZW1wKSRhdWNbMV0NCiAgcm1zZVtpXSA8LSBzcXJ0KG1lYW4obG9nMi5wcmVkcyRyZXNpZHVhbF4yLCBuYS5ybSA9IFQpKQ0KfQ0KDQpib290LmxvZzIucHJlZHMgIDwtIGJpbmRfcm93cyhwcmVkcy5saXN0LjIpDQoNCmxvZzJnb2YgPC0gZGF0YS5mcmFtZShtY2ZhZGRlbnJzcSwga3Muc3RhdCwgYXVjLCBybXNlKSU+JQ0KICBtdXRhdGUobWV0aG9kID0gbWV0aG9kWzJdKQ0KDQpsb2cyLmRpc3QgPC0gZ2dwbG90KGJvb3QubG9nMi5wcmVkcyU+JQ0KICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoaW5kZXgsIGFjdHVhbCklPiUNCiAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZShtZWFuLnByZWQgPSBtZWFuKHByZWRzLCBuYS5ybSA9IFQpKSU+JQ0KICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKHJlc2lkdWFsID0gbWVhbi5wcmVkIC0gYWN0dWFsKSwgDQogICAgICAgICAgICAgICAgICAgYWVzKHggPSBtZWFuLnByZWQsIGZpbGwgPSBhcy5jaGFyYWN0ZXIoYWN0dWFsKSkpKw0KICAgIGdlb21fZGVuc2l0eShhbHBoYSA9IC43NSkrDQogICAgbGFicyh0aXRsZSA9ICdGaWcgMy4xOiBCaS1TdGVwIEFjY2lkZW50IFByb3AuJywNCiAgICAgICAgIHkgPSAnRnJlcXVlbmN5JywNCiAgICAgICAgIHggPSAnQ2xhaW0gTGlrZWxpaG9vZCBTY29yZScsDQogICAgICAgICBzdWJ0aXRsZSA9ICdQcmVkaWN0ZWQgdnMuIEFjdHVhbCcpKw0KICAgIHRoZW1lX3lheihiYXNlX3NpemUgPSAxMCkrDQogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0geWF6X2NvbHNbNDo1XSwgDQogICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICdWYWxpZGF0ZWQgQ2xhc3NpZmljYXRpb24nLCANCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCdObyBDbGFpbScsJ0NsYWltYW50JykpDQoNCmxvZzIucmlkZ2VzIDwtIGdncGxvdChib290LmxvZzIucHJlZHMlPiUNCiAgICAgICAgIGdyb3VwX2J5KHJvdW5kZWQgPSBhcy5udW1lcmljKHN1YnN0cihhcy5jaGFyYWN0ZXIocHJlZHMpLDEsMykpKSU+JQ0KICAgICAgICAgbXV0YXRlKHBjdF9ncm91cGVkID0gbWVhbihhY3R1YWwsIG5hLnJtID1UKSwNCiAgICAgICAgICAgICAgICBncm91cF9uID0gbigpKSU+JQ0KICAgICAgICAgdW5ncm91cCgpJT4lDQogICAgICAgICBmaWx0ZXIoIWlzLm5hKHJvdW5kZWQpKSwgDQogICAgICAgYWVzKHggPSBwY3RfZ3JvdXBlZCwgeSA9IHJlb3JkZXIoYXMuY2hhcmFjdGVyKHJvdW5kZWQpLCByb3VuZGVkKSwNCiAgICAgICAgICAgYWxwaGEgPSBncm91cF9uKSkrDQogIGdlb21fZGVuc2l0eV9yaWRnZXMoZmlsbCA9IHlhel9jb2xzWzFdLCB3ZWlnaHQgPSAuNSkrDQogIHRoZW1lX3lheigpKw0KICBsYWJzKHRpdGxlID0gJ0ZpZyAzLjI6IEJpLVN0ZXAgU2NvcmUgQWNjdXJhY3knLA0KICAgICAgICAgeSA9ICdQcmVkaWN0ZWQgUHJvYmFiaWxpdHknLA0KICAgICAgICAgeCA9ICdQcm9wb3J0aW9uIFdobyBBcmUgQ2xhaW1hbnRzJywNCiAgICAgICAgIHN1YnRpdGxlID0gcGFzdGUwKCdQcmVkaWN0ZWQgdmFsdWVzIGluIHRoZSB2ZXJpZmljYXRpb24gc2V0JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICdcbihEYXJrZXIgcGxvdHMgaW5kaWNhdGUgZ3JlYXRlciBmcmVxdWVuY2llcykuJykpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAnbm9uZScpKw0KICB4bGltKDAsMSkNCg0KbG9nMi5lY2RmIDwtIGdncGxvdChib290LmxvZzIucHJlZHMlPiUNCiAgICAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KGluZGV4LCBhY3R1YWwpJT4lDQogICAgICAgICAgICAgICAgICAgICBzdW1tYXJpc2UobWVhbi5wcmVkID0gbWVhbihwcmVkcywgbmEucm0gPSBUKSksIA0KICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gbWVhbi5wcmVkKSkrDQogIHN0YXRfZWNkZihnZW9tID0gJ3BvaW50JywgY29sb3IgPSB5YXpfY29sc1sxXSkrDQogIHRoZW1lX3lheigpKw0KICBsYWJzKHRpdGxlID0gJ0ZpZyAzLjM6IEJpLVN0ZXAgRUNERicsDQogICAgICAgeSA9ICdBY2NpZGVudCBGcmVxdWVuY3knLCB4ID0gJ0FjY2lkZW50IFByb2JhYmlsaXR5JywNCiAgICAgICBzdWJ0aXRsZSA9ICcgJykNCg0KDQpncmlkLmFycmFuZ2UobG9nMi5kaXN0LCBsb2cyLnJpZGdlcywgbG9nMi5lY2RmLCBucm93ID0gMSkNCmBgYA0KDQojIyMgTW9kZWwgQ29tcG9zaXRpb24NCk1hbnkgb2YgdGhlIHZhcmlhYmxlcyBzZWxlY3RlZCB0aHJvdWdoIHRoZSBzdGVwd2lzZSBwcm9jZXNzIHBlcmZvcm0gc2ltaWxhcmx5IHRvIHRoZSBhc3N1bXB0aW9ucyBsYWlkIG91dCBpbiB0aGUgZGF0YSBkaWN0aW9uYXJ5LiBTb21lIG9mIHRoZSB2YXJpYWJsZSBjb2VmZmljaWVudHMgKGxpa2UgbWlzc2luZyBhZ2UgZGF0YSwgU1VWIG93bmVyc2hpcCwgYW5kIHByZXNlbmNlIG9mIGtpZHMgaW4gdGhlIGhvdXNlaG9sZCkgYXJlIG5vdCBzaWduaWZpY2FudCwgYnV0IHRoZXkncmUgbGVmdCBpbiB0aGUgbW9kZWwgdG8gbWluaW1pemUgQUlDLg0KDQpgYGB7cn0NCm1vZGVsLmxvZzIgPC0gZ2xtKHRhcmdldF9mbGFnfmhvbWVraWRzK3lvaitpbmNvbWUraG9tZV92YWwrdHJhdnRpbWUrYmx1ZWJvb2srdGlmK29sZGNsYWltKw0KICAgICAgICAgICAgICAgICAgICAgIGNsbV9mcmVxK212cl9wdHMrYWdlX25hLmZsYWcra2lkc2RyaXYrb2xkY2xhaW1fb3V0LmZsYWcrbXZyX3B0c19vdXQuZmxhZysNCiAgICAgICAgICAgICAgICAgICAgICBwYXJlbnQxbm8rbXN0YXR1c25vK2BlZHVjYXRpb25oaWdoIHNjaG9vbGArYGpvYmJsdWUgY29sbGFyYCsNCiAgICAgICAgICAgICAgICAgICAgICBqb2JjbGVyaWNhbCtqb2Jkb2N0b3Iram9ibWFuYWdlcitjYXJfdXNlY29tbWVyY2lhbCtjYXJfdHlwZW1pbml2YW4rDQogICAgICAgICAgICAgICAgICAgICAgYGNhcl90eXBlc3BvcnRzIGNhcmArY2FyX3R5cGVzdXYrcmV2b2tlZG5vKw0KICAgICAgICAgICAgICAgICAgICAgIGB1cmJhbmljaXR5aGlnaGx5IHJ1cmFsLyBydXJhbGAsIA0KICAgICAgICAgICAgICAgICAgICBkYXRhLmZvci5zdGVwYWljLCBmYW1pbHk9Ymlub21pYWwoImxvZ2l0IikpDQoNCm1vZGVsLmxvZzIucGFydHMgPC0gc3VtbWFyeShtb2RlbC5sb2cyKSRjb2VmZmljaWVudHMlPiUNCiAgZGF0YS5mcmFtZSgpJT4lDQogIGJpbmRfY29scyhkYXRhLmZyYW1lKHZhcnMgPSByb3duYW1lcyhzdW1tYXJ5KG1vZGVsLmxvZzIpJGNvZWZmaWNpZW50cykpKSU+JQ0KICBkcGx5cjo6c2VsZWN0KGVzdCA9IEVzdGltYXRlLCBzZSA9IFN0ZC4uRXJyb3IsIHAgPSBQci4uLnouLiwgdmFycykNCg0KZ2dwbG90KG1vZGVsLmxvZzIucGFydHMsIGFlcyh4ID0gcmVvcmRlcih2YXJzLCBlc3QpLCB5ID0gZXN0LCBjb2xvciA9IHApKSsNCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IGVzdCAtIHNlLCB5bWF4ID0gZXN0ICsgc2UpLA0KICAgICAgICAgICAgICAgIHdpZHRoID0gMCwgc2l6ZSA9IDIpKw0KICBsYWJzKHkgPSAnQ29lZmZpY2llbnQgRXN0aW1hdGUgKCstIDEgU3RhbmRhcmQgRXJyb3IpJywNCiAgICAgICB0aXRsZSA9ICdNb2RlbCBDb2VmZmljaWVudCBFc3RpbWF0ZXMnLA0KICAgICAgIHggPSBlbGVtZW50X2JsYW5rKCkpKw0KICB0aGVtZV95YXooKSsNCiAgY29vcmRfZmxpcCgpKw0KICBzY2FsZV9jb2xvcl9jb250aW51b3VzKGhpZ2ggPSB5YXpfY29sc1s0XSwgbG93ID0geWF6X2NvbHNbM10sDQogICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gYygwLCAuMDAxLCAuMDEsIC4wNSwgLjEsIDEpLGd1aWRlID0gJ2xlZ2VuZCcpKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICdkYXNoZWQnKQ0KYGBgDQoNCiMjIEJpZGlyZWN0aW9uYWwgVmFyaWFibGUgU2VsZWN0aW9uIFByb2JpdCBSZWdyZXNzaW9uDQpUaGUgUHJvYml0IG1vZGVsIHVzZXMgdGhlIHByb2JpdCBsaW5rIGZ1bmN0aW9uIHRvIG1vZGlmeSBPTFMgcmVncmVzc2lvbiBmb3IgY2xhc3NpZmljYXRpb24gcHVycG9zZXMgKHNpbWlsYXIgdG8gdGhlIGxvZ2l0IHByb2Nlc3MgYnV0IHdpdGggZGlmZmVyZW50IHRyYW5zZm9ybWF0aW9ucykuIEluIHRoaXMgY2FzZSwgdGhlIG1vZGVscyBwZXJmb3JtZWQgc2ltaWxhcmx5LiBBIGJpLWRpcmVjdGlvbmFsIHN0ZXB3aXNlIHZhcmlhYmxlIHNlbGVjdGlvbiB0ZWNobmlxdWUgaXMgdXNlZCB0byBzZWxlY3QgYSBzdWJzZXQgb2YgdmFyaWFibGVzIHRoYXQgbWluaW1pemVzIEFJQy4gVGhlbiB0aGUgd2lubmluZyBtb2RlbCBpcyBpdGVyYXRpdmVseSBhcHBsaWVkIHRvIHN1YnNhbXBsZXMgb2YgdGhlIGRhdGEgYW5kIHRoZSBhdmVyYWdlIHByZWRpY3RlZCB2YWx1ZXMgYXJlIGNhbGN1bGF0ZWQgZm9yIGVhY2ggcmVjb3JkLg0KDQojIyMgUGVyZm9ybWFuY2UNClNpbWlsYXIgdG8gdGhlIGJpLWRpcmVjdGlvbmFsIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwsIHRvbyBtYW55IG5vbi1hY2NpZGVudCBwcmVkaWN0aW9ucyBhcmUgY2xlYXJseSBhIHByb2JsZW0gaW4gdGhpcyBkYXRhIHNldC4gRmlndXJlcyA0LjEgYW5kIDQuMyBpbGx1c3RyYXRlIHRoZSByZWxhdGl2ZSBzdWNjZXNzIG9mIHRoZSBtb2RlbCBhdCBwb3NpdGl2ZWx5IGlkZW50aWZ5aW5nIG5vbi1hY2NpZGVudCBjYXNlcyBidXQgYWxzbyB0aGF0IGEgc2lnbmlmaWNhbnRseSBoaWdoIG51bWJlciBvZiBjYXNlcyB3aGVyZSBhY2NpZGVudHMgZGlkIHJlY2VpdmVkIGxvdyBzY29yZXMuIE9uZSBicmlnaHQgc3BvdCBpbiB0aGlzIG1vZGVsIGNvbXBhcmVkIHRvIHRoZSBwcmV2aW91cyBtb2RlbHMgaXMgRmlndXJlIDQuMiB3aGljaCBpbGx1c3RyYXRlcyB0aGF0IGFzIHNjb3JlcyBnbyB1cCAoaW4gYWdncmVnYXRlKSBhY2NpZGVudCBsaWtlbGlob29kIGRvZXMgdGVuZCB0byBnbyB1cCBhcyB3ZWxsLiANCg0KYGBge3IgcHJvYml0LCBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD0xMSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgVHV0b3JpYWw6IGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvcG1jL2FydGljbGVzL1BNQzQ4NDIzOTkvDQpmdWxsLm1vZCA8LSBnbG0odGFyZ2V0X2ZsYWd+LiwgZGF0YSA9IGRhdGEuZm9yLnN0ZXBhaWMsIGZhbWlseSA9IGJpbm9taWFsKCJwcm9iaXQiKSkNCg0Kc3RlcCA8LSBzdGVwQUlDKGZ1bGwubW9kLCB0cmFjZSA9IFQsIGRpcmVjdGlvbiA9ICdib3RoJykNCiMgcHJpbnQgdGhlIGZvcm11bGEgYW5kIGJvb3RzdHJhcCBpdCENCiMgcGFzdGUwKCdnbG0odGFyZ2V0X2ZsYWd+JywgcGFzdGUobmFtZXMoc3RlcCRjb2VmZmljaWVudHMpWy0xXSwgY29sbGFwc2UgPSAnKycpLA0KIyAgICAgICAgJywgZGF0YSA9IHRyYWluLnRlbXApLCBmYW1pbHk9Ymlub21pYWwoImxvZ2l0IiknKSkpDQoNCm1ldGhvZFszXSA8LSAnQmlkaXJlY3Rpb25hbCBTdGVwd2lzZSAoUHJvYml0KScNCg0KcHJlZHMubGlzdC4zIDwtIGxpc3QoKQ0KbWNmYWRkZW5yc3EgPC0gYygpDQprcy5zdGF0IDwtIGMoKQ0KYXVjIDwtIGMoKQ0Kcm1zZSA8LSBjKCkNCg0KZm9yKGkgaW4gMToxMDAwKXsNCiAgdHJhaW4udGVtcCA8LSBzYW1wbGVfZnJhYyhkYXRhLmZvci5zdGVwYWljLCAuOCwgcmVwbGFjZSA9IFRSVUUpDQogIHRlc3QudGVtcCA8LSBkYXRhLmZvci5zdGVwYWljJT4lDQogICAgYmluZF9jb2xzKGRhdGEuZnJhbWUoaW5kZXggPSB0cmFpbl9jbGVhbiRpbmRleCkpJT4lDQogICAgZmlsdGVyKCFpbmRleCAlaW4lIHRyYWluLnRlbXAkaW5kZXgpDQogIA0KICBtb2RlbC5wcm9iIDwtIGdsbSh0YXJnZXRfZmxhZ35ob21la2lkcyt5b2oraW5jb21lK2hvbWVfdmFsK3RyYXZ0aW1lK2JsdWVib29rK3RpZitvbGRjbGFpbSsNCiAgICAgICAgICAgICAgICAgICAgICBjbG1fZnJlcSttdnJfcHRzK2FnZV9uYS5mbGFnK2tpZHNkcml2K29sZGNsYWltX291dC5mbGFnK212cl9wdHNfb3V0LmZsYWcrDQogICAgICAgICAgICAgICAgICAgICAgcGFyZW50MW5vK21zdGF0dXNubytgZWR1Y2F0aW9uaGlnaCBzY2hvb2xgK2Bqb2JibHVlIGNvbGxhcmArDQogICAgICAgICAgICAgICAgICAgICAgam9iY2xlcmljYWwram9iZG9jdG9yK2pvYm1hbmFnZXIrY2FyX3VzZWNvbW1lcmNpYWwrY2FyX3R5cGVtaW5pdmFuKw0KICAgICAgICAgICAgICAgICAgICAgIGBjYXJfdHlwZXNwb3J0cyBjYXJgK2Nhcl90eXBlc3V2K3Jldm9rZWRubysNCiAgICAgICAgICAgICAgICAgICAgICBgdXJiYW5pY2l0eWhpZ2hseSBydXJhbC8gcnVyYWxgLCANCiAgICAgICAgICAgICAgICAgICAgdHJhaW4udGVtcCwgZmFtaWx5PWJpbm9taWFsKCJwcm9iaXQiKSkNCiAgDQogIHByZWRzIDwtIHByZWRpY3QobW9kZWwucHJvYiwgdGVzdC50ZW1wLCB0eXBlPSJyZXNwb25zZSIpDQogIA0KICBwcm9iLnByZWRzIDwtIGRhdGEuZnJhbWUoDQogICAgaW5kZXggPSB0ZXN0LnRlbXAkaW5kZXgsDQogICAgYWN0dWFsID0gdGVzdC50ZW1wJHRhcmdldF9mbGFnLA0KICAgIHByZWRzDQogICAgKSU+JQ0KICAgIG11dGF0ZShyZXNpZHVhbCA9IHByZWRzIC0gYWN0dWFsKQ0KICBwcmVkcy5saXN0LjNbW2ldXSA8LSBwcm9iLnByZWRzDQogIA0KICBtY2ZhZGRlbnJzcVtpXSA8LSBhcy5udW1lcmljKHBzY2w6OnBSMihtb2RlbC5sb2cyKVs0XSkNCiAga3Muc3RhdFtpXSA8LSBrcy50ZXN0KHByZWRzLCAicG5vcm0iLCAxLCAyKSRzdGF0aXN0aWMNCiAgYXVjW2ldIDwtIHBST0M6OnJvYyh0YXJnZXRfZmxhZyB+IHByZWRzLCBkYXRhID0gdGVzdC50ZW1wKSRhdWNbMV0NCiAgcm1zZVtpXSA8LSBzcXJ0KG1lYW4obG9nMi5wcmVkcyRyZXNpZHVhbF4yLCBuYS5ybSA9IFQpKQ0KfQ0KDQpib290LnByb2IucHJlZHMgIDwtIGJpbmRfcm93cyhwcmVkcy5saXN0LjMpDQpwcm9wZ29mIDwtIGRhdGEuZnJhbWUobWNmYWRkZW5yc3EsIGtzLnN0YXQsIGF1Yywgcm1zZSklPiUNCiAgbXV0YXRlKG1ldGhvZCA9IG1ldGhvZFszXSkNCg0KcHJvYi5kaXN0IDwtIGdncGxvdChib290LnByb2IucHJlZHMlPiUNCiAgICAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KGluZGV4LCBhY3R1YWwpJT4lDQogICAgICAgICAgICAgICAgICAgICBzdW1tYXJpc2UobWVhbi5wcmVkID0gbWVhbihwcmVkcywgbmEucm0gPSBUKSklPiUNCiAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShyZXNpZHVhbCA9IG1lYW4ucHJlZCAtIGFjdHVhbCksIA0KICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gbWVhbi5wcmVkLCBmaWxsID0gYXMuY2hhcmFjdGVyKGFjdHVhbCkpKSsNCiAgICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAuNzUpKw0KICAgIGxhYnModGl0bGUgPSAnRmlnIDQuMTogUHJvYml0IEFjY2lkZW50IFByb3AuJywNCiAgICAgICAgIHkgPSAnRnJlcXVlbmN5JywNCiAgICAgICAgIHggPSAnQ2xhaW0gTGlrZWxpaG9vZCBTY29yZScsDQogICAgICAgICBzdWJ0aXRsZSA9ICdQcmVkaWN0ZWQgdnMuIEFjdHVhbCcpKw0KICAgIHRoZW1lX3lheihiYXNlX3NpemUgPSAxMCkrDQogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0geWF6X2NvbHNbNDo1XSwgDQogICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICdWYWxpZGF0ZWQgQ2xhc3NpZmljYXRpb24nLCANCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCdObyBDbGFpbScsJ0NsYWltYW50JykpDQoNCnByb2IucmlkZ2VzIDwtIGdncGxvdChib290LnByb2IucHJlZHMlPiUNCiAgICAgICAgIGdyb3VwX2J5KHJvdW5kZWQgPSBhcy5udW1lcmljKHN1YnN0cihhcy5jaGFyYWN0ZXIocHJlZHMpLDEsMykpKSU+JQ0KICAgICAgICAgICBtdXRhdGUocGN0X2dyb3VwZWQgPSBtZWFuKGFjdHVhbCwgbmEucm0gPVQpLA0KICAgICAgICAgICAgICAgICAgZ3JvdXBfbiA9IG4oKSklPiUNCiAgICAgICAgICAgdW5ncm91cCgpJT4lDQogICAgICAgICAgIGZpbHRlcighaXMubmEocm91bmRlZCksDQogICAgICAgICAgICAgICAgICByb3VuZGVkIDwgMSksIA0KICAgICAgIGFlcyh4ID0gcGN0X2dyb3VwZWQsIHkgPSByZW9yZGVyKGFzLmNoYXJhY3Rlcihyb3VuZGVkKSwgcm91bmRlZCksDQogICAgICAgICAgIGFscGhhID0gZ3JvdXBfbikpKw0KICBnZW9tX2RlbnNpdHlfcmlkZ2VzKGZpbGwgPSB5YXpfY29sc1sxXSwgd2VpZ2h0ID0gLjUpKw0KICB0aGVtZV95YXooKSsNCiAgbGFicyh0aXRsZSA9ICdGaWcgNC4yOiBQcm9iaXQgU2NvcmUgQWNjdXJhY3knLA0KICAgICAgICAgeSA9ICdQcmVkaWN0ZWQgUHJvYmFiaWxpdHknLA0KICAgICAgICAgeCA9ICdQcm9wb3J0aW9uIFdobyBBcmUgQ2xhaW1hbnRzJywNCiAgICAgICAgIHN1YnRpdGxlID0gcGFzdGUwKCdQcmVkaWN0ZWQgdmFsdWVzIGluIHRoZSB2ZXJpZmljYXRpb24gc2V0JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICdcbihEYXJrZXIgcGxvdHMgaW5kaWNhdGUgZ3JlYXRlciBmcmVxdWVuY2llcykuJykpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAnbm9uZScpKw0KICB4bGltKDAsMSkNCg0KcHJvYi5lY2RmIDwtIGdncGxvdChib290LnByb2IucHJlZHMlPiUNCiAgICAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KGluZGV4LCBhY3R1YWwpJT4lDQogICAgICAgICAgICAgICAgICAgICBzdW1tYXJpc2UobWVhbi5wcmVkID0gbWVhbihwcmVkcywgbmEucm0gPSBUKSksIA0KICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gbWVhbi5wcmVkKSkrDQogIHN0YXRfZWNkZihnZW9tID0gJ3BvaW50JywgY29sb3IgPSB5YXpfY29sc1sxXSkrDQogIHRoZW1lX3lheigpKw0KICBsYWJzKHRpdGxlID0gJ0ZpZyA0LjM6IFByb2JpdCBFQ0RGJywNCiAgICAgICB5ID0gJ0FjY2lkZW50IEZyZXF1ZW5jeScsIHggPSAnQWNjaWRlbnQgUHJvYmFiaWxpdHknLA0KICAgICAgIHN1YnRpdGxlID0gJyAnKQ0KDQpncmlkLmFycmFuZ2UocHJvYi5kaXN0LCBwcm9iLnJpZGdlcywgcHJvYi5lY2RmLCBucm93ID0gMSkNCmBgYA0KDQojIyMgTW9kZWwgQ29tcG9zaXRpb24NClRoZSBwcm9iaXQgbW9kZWwgY29lZmZpY2llbnRzIGJlaGF2ZSBzaW1pbGFybHkgdG8gdGhlIHN0ZXB3aXNlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwuIEFnYWluLCByZWdhcmRsZXNzIG9mIHN0YXRpc3RpY2FsIHNpZ25pZmljYW5jZSwgdGhlIHZhcmlhYmxlcyBzZWxlY3RlZCB0aHJvdWdoIHRoZSBBSUMgbWluaW1pemF0aW9uIHByb2Nlc3MgYXJlIHJldGFpbmVkIGluIHRoZSBtb2RlbC4NCg0KYGBge3J9DQptb2RlbC5wcm9iIDwtIGdsbSh0YXJnZXRfZmxhZ35ob21la2lkcyt5b2oraW5jb21lK2hvbWVfdmFsK3RyYXZ0aW1lK2JsdWVib29rK3RpZitvbGRjbGFpbSsNCiAgICAgICAgICAgICAgICAgICAgICBjbG1fZnJlcSttdnJfcHRzK2FnZV9uYS5mbGFnK2tpZHNkcml2K29sZGNsYWltX291dC5mbGFnK212cl9wdHNfb3V0LmZsYWcrDQogICAgICAgICAgICAgICAgICAgICAgcGFyZW50MW5vK21zdGF0dXNubytgZWR1Y2F0aW9uaGlnaCBzY2hvb2xgK2Bqb2JibHVlIGNvbGxhcmArDQogICAgICAgICAgICAgICAgICAgICAgam9iY2xlcmljYWwram9iZG9jdG9yK2pvYm1hbmFnZXIrY2FyX3VzZWNvbW1lcmNpYWwrY2FyX3R5cGVtaW5pdmFuKw0KICAgICAgICAgICAgICAgICAgICAgIGBjYXJfdHlwZXNwb3J0cyBjYXJgK2Nhcl90eXBlc3V2K3Jldm9rZWRubysNCiAgICAgICAgICAgICAgICAgICAgICBgdXJiYW5pY2l0eWhpZ2hseSBydXJhbC8gcnVyYWxgLCANCiAgICAgICAgICAgICAgICAgICAgZGF0YS5mb3Iuc3RlcGFpYywgZmFtaWx5PWJpbm9taWFsKCJwcm9iaXQiKSkNCg0KbW9kZWwucHJvYi5wYXJ0cyA8LSBzdW1tYXJ5KG1vZGVsLnByb2IpJGNvZWZmaWNpZW50cyU+JQ0KICBkYXRhLmZyYW1lKCklPiUNCiAgYmluZF9jb2xzKGRhdGEuZnJhbWUodmFycyA9IHJvd25hbWVzKHN1bW1hcnkobW9kZWwucHJvYikkY29lZmZpY2llbnRzKSkpJT4lDQogIGRwbHlyOjpzZWxlY3QoZXN0ID0gRXN0aW1hdGUsIHNlID0gU3RkLi5FcnJvciwgcCA9IFByLi4uei4uLCB2YXJzKQ0KDQpnZ3Bsb3QobW9kZWwucHJvYi5wYXJ0cywgYWVzKHggPSByZW9yZGVyKHZhcnMsIGVzdCksIHkgPSBlc3QsIGNvbG9yID0gcCkpKw0KICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gZXN0IC0gc2UsIHltYXggPSBlc3QgKyBzZSksDQogICAgICAgICAgICAgICAgd2lkdGggPSAwLCBzaXplID0gMikrDQogIGxhYnMoeSA9ICdDb2VmZmljaWVudCBFc3RpbWF0ZSAoKy0gMSBTdGFuZGFyZCBFcnJvciknLA0KICAgICAgIHRpdGxlID0gJ01vZGVsIENvZWZmaWNpZW50IEVzdGltYXRlcycsDQogICAgICAgeCA9IGVsZW1lbnRfYmxhbmsoKSkrDQogIHRoZW1lX3lheigpKw0KICBjb29yZF9mbGlwKCkrDQogIHNjYWxlX2NvbG9yX2NvbnRpbnVvdXMoaGlnaCA9IHlhel9jb2xzWzRdLCBsb3cgPSB5YXpfY29sc1szXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBjKDAsIC4wMDEsIC4wMSwgLjA1LCAuMSwgMSksZ3VpZGUgPSAnbGVnZW5kJykrDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gJ2Rhc2hlZCcpDQpgYGANCg0KIyMgTW9kZWwgRXZhbHVhdGlvbg0KVGhlIHRocmVlIG1vZGVscyBhcmUgZXZhbHVhdGVkIGJhc2VkIG9uIHRoZSBNY0ZhZGRlbiBQc2V1ZG8gJFJeMiQgc3RhdGlzdGljLCB0aGUgS29sbWFnb3JvdiAtIFNtaXJub3YgKEtTKSBzdGF0aXN0aWMsIGFyZWEgdW5kZXIgdGhlIGN1cnZlIChBVUMpLCBhbmQgUm9vdC1NZWFuIFNxdWFyZWQgRXJyb3IgKFJNU0UpLiBBbGwgY2FsY3VsYXRpb25zIGFyZSBjcm9zcy12YWxpZGF0ZWQgdXNpbmcgMSwwMDAgaXRlcmF0aW9ucyBvZiBzYW1wbGVkIG1vZGVsIHRyYWluaW5nIGFuZCBvdXQtb2Ytc2FtcGxlIG1vZGVsIHRlc3RpbmcuDQoNCk1jRmFkZGVuIG9mZmVycyBhIHN0YW5kLWluIGZvciB0aGUga2luZCBvZiAkUl4yJCB1c2VkIHRvIGV2YWx1YXRlIE9MUyByZWdyZXNzaW9uIG1vZGVsc1teNF0uIFRoZSBQcm9iaXQgbW9kZWwgZXhwbGFpbnMgdGhlIGdyZWF0ZXN0IGFtb3VudCBvZiB2YXJpYW5jZSBmb2xsb3dlZCBjbG9zZWx5IGJ5IHRoZSBiaS1kaXJlY3Rpb25hbCBsb2dpdCBtb2RlbC4gVGhlIGhldXJpc3RpYyBsb2dpdCBtb2RlbCB0cmFpbGVkIHNpZ25pZmljYW50bHkuDQoNClRoZSBLUyBzdGF0aXN0aWMgY29tcGFyZXMgdGhlIGN1bXVsYXRpdmUgZGlzdHJpYnV0aW9uIG9mIHRoZSBtb2RlbCBwcmVkaWN0aW9ucyB0byB0aGUgaWRlYWwgZGlzdHJpYnV0aW9uIGZvciB0aGF0IGRhdGEuIEluIHRoaXMgY2FzZSwgdGhlIGhldXJpc3RpYyBtb2RlbCBwZXJmb3JtZWQgYmVzdCBvZiBhbGwgdGhyZWUuIFdoaWxlIHRoZSBLUy1zdGF0aXN0aWMgaXMgYSBtb3JlIGZvcm1hbCB0ZXN0IGZvciBhcHByb3ByaWF0ZW5lc3Mgb2YgdGhlIGN1bXVsYXRpdmUgZGlzdHJpYnV0aW9uIGN1cnZlLCBGaWd1cmVzIDIuMywgMy4zLCBhbmQgNC4zIGFsbCBpbmRpY2F0ZWQgc2lnbmlmaWNhbnQgZGVwcmVzc2lvbiBvZiBzY29yZXMgdG93YXJkcyBsb3dlci1lbmQgcHJvYmFiaWxpdGllcyB0aGFuIHdlcmUgYXBwcm9wcmlhdGUuIFRoZSBoZXVyaXN0aWMgbW9kZWwgd2FzIHRoZSBjbG9zZXN0IGJ5IGFwcGVhcmFuY2UgdG8gdGhlIGlkZWFsIGRpc3RyaWJ1dGlvbiBhbmQgdGhlIEtTLXN0YXRpc3RpYyBjb25maXJtcyB0aGF0IGh1bmNoLiANCg0KQVVDICJyZWxhdGVzIHRoZSBoaXQgcmF0ZSB0byB0aGUgZmFsc2UgYWxhcm0gcmF0ZSIgaW4gY2xhc3NpZmljYXRpb24gbW9kZWxpbmcgW141XS4gVGhlIGhldXJpc3RpYyBtb2RlbCB3YXMgZmFyLCBmYXIgYmVoaW5kIG9uIHRoaXMgbW9kZWwgYW5kIHByb2R1Y2VkIGhpZ2hseSB1bnN0YWJsZSBzY29yZXMuIEZvciBwcm9kdWN0aW9uIHB1cnBvc2VzLCBjb25zaXN0ZW50IHNjb3JlcyB3aWxsIGVhc2UgYWRvcHRpb24gb2YgdGhlIG1vZGVsLCBzbyB0byB0aGUgZXh0ZW50IHRoYXQgcG9saXRpY2FsIGNvbmNlcm5zIGZhY3RvciBpbnRvIG1vZGVsIHNlbGVjdGlvbiwgdGhlIGluY29uc2lzdGVuY3kgaW50aGUgQVVDIG1lYXN1cmVzIGZvciB0aGUgaGV1cmlzdGljIG1vZGVsIGFyZSBwcm9ibGVtYXRpYy4gDQoNCkZpbmFsbHksIGNyb3NzLXZhbGlkYXRlZCBSTVNFIHRlc3RzIGhvbGQtb3V0IHNhbXBsZSBwcmVkaWN0aW9ucyBhZ2FpbnN0IGtub3duIHZhbHVlcy4gVGhlIGJpZGlyZWN0aW9uYWwgbG9naXQgbW9kZWwgc2xpZ2h0bHkgb3V0cGVyZm9ybXMgdGhlIGJpZGlyZWN0aW9uYWwgcHJvYml0IG1vZGVsLCBidXQgbm90IGJ5IGFueSBzaWduaWZpY2FudCBtYXJnaW4uIFRoYXQgc2FpZCwgdGhlIGhldXJpc3RpYyBtb2RlbCBsYWdzIHNpZ25pZmljYW50bHkuIA0KDQpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTV9DQpnb2ZfY29tYiA8LSBiaW5kX3Jvd3MobG9nMWdvZiwgbG9nMmdvZiwgcHJvcGdvZikNCg0KbWNmYWRkZW5yc3EucGxvdCA8LSBnZ3Bsb3QoZ29mX2NvbWIsIGFlcyh4ID0gbWNmYWRkZW5yc3EsIHkgPSBtZXRob2QpKSsNCiAgZ2VvbV9kZW5zaXR5X3JpZGdlcyhmaWxsID0geWF6X2NvbHNbNV0sIGFscGhhID0gLjcpKw0KICBsYWJzKHRpdGxlID0gZXhwcmVzc2lvbihwYXN0ZSgiTWNGYWRkZW4ncyAiLCBSXnsyfSkpLA0KICAgICAgIHggPSBleHByZXNzaW9uKHBhc3RlKCJNY0ZhZGRlbidzICIsIFJeezJ9KSksDQogICAgICAgeSA9IGVsZW1lbnRfYmxhbmsoKSkrDQogIHRoZW1lX3lheigpDQprc3Rlc3QucGxvdCA8LSBnZ3Bsb3QoZ29mX2NvbWIsIGFlcyh4ID0ga3Muc3RhdCwgeSA9IG1ldGhvZCkpKw0KICBnZW9tX2RlbnNpdHlfcmlkZ2VzKGZpbGwgPSB5YXpfY29sc1s1XSwgYWxwaGEgPSAuNykrDQogIGxhYnModGl0bGUgPSAnS1MgLSBUZXN0JywNCiAgICAgICB4ID0gJ0tTIC0gU3RhdGlzdGljJywNCiAgICAgICB5ID0gZWxlbWVudF9ibGFuaygpKSsNCiAgdGhlbWVfeWF6KCkNCmF1Yy5wbG90IDwtIGdncGxvdChnb2ZfY29tYiwgYWVzKHggPSBhdWMsIHkgPSBtZXRob2QpKSsNCiAgZ2VvbV9kZW5zaXR5X3JpZGdlcyhmaWxsID0geWF6X2NvbHNbNV0sIGFscGhhID0gLjcpKw0KICBsYWJzKHRpdGxlID0gJ0FyZWEgVW5kZXIgKFJPQyknLA0KICAgICAgIHggPSAnQVVDJywNCiAgICAgICB5ID0gZWxlbWVudF9ibGFuaygpKSsNCiAgdGhlbWVfeWF6KCkNCnJtc2UucGxvdCA8LSBnZ3Bsb3QoZ29mX2NvbWIsIGFlcyh4ID0gcm1zZSwgeSA9IG1ldGhvZCkpKw0KICBnZW9tX2RlbnNpdHlfcmlkZ2VzKGZpbGwgPSB5YXpfY29sc1s1XSwgYWxwaGEgPSAuNykrDQogIGxhYnModGl0bGUgPSAnUk1TRScsDQogICAgICAgeCA9ICdSTVNFJywNCiAgICAgICB5ID0gZWxlbWVudF9ibGFuaygpKSsNCiAgdGhlbWVfeWF6KCkNCg0KZ3JpZC5hcnJhbmdlKG1jZmFkZGVucnNxLnBsb3QsIGtzdGVzdC5wbG90LCBhdWMucGxvdCwgcm1zZS5wbG90LA0KICAgICAgICAgICAgIG5yb3cgPSAyKQ0KYGBgDQoNClN0ZXAtd2lzZSB2YXJpYWJsZSBzZWxlY3Rpb24gaXMgYSBjb21wdXRhdGlvbmFsbHkgZXhwZW5zaXZlIHByb2Nlc3MsIGJ1dCB0aGUgZ2FpbnMgaW4gcHJlZGljdGl2ZSBhY2N1cmFjeSBtb3JlIHRoYW4ganVzdGlmeSB0aGUgYWRkZWQgdGltZSByZXF1aXJlZCB0byB0cmFpbiB0aGVzZSBtb2RlbHMuIEJvdGggbG9naXN0aWMgcmVncmVzc2lvbiBhbmQgcHJvYml0IHJlZ3Jlc3Npb24gYXJlIGVhc3kgZW5vdWdoIHRvIGV4cGxhaW4gdG8gbWFuYWdlbWVudCBpZiB0aGUgcHJlZGljdGlvbnMgYXJlIGNvcnJlY3QuIFRoZXJlZm9yZSB0aGUgd2lubmluZyBtb2RlbCBpcyB0aGUgQmlkaXJlY3Rpb25hbCBTdGVwd2lzZSBQcm9iaXQgbWV0aG9kLg0KDQojIEFwcGVuZGljZXMNCiMjIEFwcGVuZGl4IEE6IENvZGUgdG8gUHJvY2VzcyBOZXcgRGF0YQ0KVGhlIGJlbG93IGZ1bmN0aW9uIChhbmQgcGFja2FnZSBkZXBlbmRlbmNpZXMpIHRha2UgYSBmaWxlIG9mIG5ldyBkYXRhIGFuZCByZXR1cm5zIGEgZmlsZSB3aXRoIHRoZSBpbmRleCwgcHJlZGljdGVkIGxpa2VsaWhvb2Qgb2YgYSBjbGFpbSwgYW5kIGEgcm91Z2ggZXN0aW1hdGUgb2YgbGlrZWx5IGNsYWltIGNvc3QuIFRoZSBjb3N0IGVzdGltYXRlIGlzIHRoZSBtZWRpYW4gdmFsdWUgb2YgY2xhaW1zLg0KYGBge3IsIGVjaG89VH0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeSh5YXp0aGVtZSkNCmxpYnJhcnkocmVzaGFwZTIpDQpsaWJyYXJ5KGdncmlkZ2VzKQ0KbGlicmFyeShyYW5kb21Gb3Jlc3QpDQpsaWJyYXJ5KG1vbWVudHMpDQpsaWJyYXJ5KG1pY2UpDQpsaWJyYXJ5KE1BU1MpDQpsaWJyYXJ5KGR1bW1pZXMpDQpsaWJyYXJ5KGRwbHlyKQ0KDQpzY29yZV9jcmVhdG9yIDwtIGZ1bmN0aW9uKGluZmlsZSl7DQogIHRyYWluIDwtIHJlYWRfY3N2KGluZmlsZSklPiUNCiAgICBtdXRhdGUoSU5DT01FID0gYXMubnVtZXJpYyhnc3ViKCdbJCxdJywnJyxJTkNPTUUpKSwNCiAgICAgICAgICAgSE9NRV9WQUwgPSBhcy5udW1lcmljKGdzdWIoJ1skLF0nLCcnLEhPTUVfVkFMKSksDQogICAgICAgICAgIEJMVUVCT09LID0gYXMubnVtZXJpYyhnc3ViKCdbJCxdJywnJyxCTFVFQk9PSykpLA0KICAgICAgICAgICBPTERDTEFJTSA9IGFzLm51bWVyaWMoZ3N1YignWyQsXScsJycsT0xEQ0xBSU0pKSwNCiAgICAgICAgICAgUEFSRU5UMSA9IHRvbG93ZXIoZ3N1YignW3pfPF0nLCcnLCBQQVJFTlQxKSksDQogICAgICAgICAgIE1TVEFUVVMgPSB0b2xvd2VyKGdzdWIoJ1t6XzxdJywnJywgTVNUQVRVUykpLA0KICAgICAgICAgICBTRVggPSB0b2xvd2VyKGdzdWIoJ1t6XzxdJywnJywgU0VYKSksDQogICAgICAgICAgIEVEVUNBVElPTiA9IHRvbG93ZXIoZ3N1YignW3pfPF0nLCcnLCBFRFVDQVRJT04pKSwNCiAgICAgICAgICAgSk9CID0gdG9sb3dlcihnc3ViKCdbel88XScsJycsIEpPQikpLA0KICAgICAgICAgICBDQVJfVVNFID0gdG9sb3dlcihnc3ViKCdbel88XScsJycsIENBUl9VU0UpKSwNCiAgICAgICAgICAgQ0FSX1RZUEUgPSB0b2xvd2VyKGdzdWIoJ1t6XzxdJywnJywgQ0FSX1RZUEUpKSwNCiAgICAgICAgICAgUkVEX0NBUiA9IHRvbG93ZXIoZ3N1YignW3pfPF0nLCcnLCBSRURfQ0FSKSksDQogICAgICAgICAgIFJFVk9LRUQgPSB0b2xvd2VyKGdzdWIoJ1t6XzxdJywnJywgUkVWT0tFRCkpLA0KICAgICAgICAgICBVUkJBTklDSVRZID0gdG9sb3dlcihnc3ViKCdbel88XScsJycsIFVSQkFOSUNJVFkpKSkNCg0KICBjb2xuYW1lcyh0cmFpbikgPC0gdG9sb3dlcihjb2xuYW1lcyh0cmFpbikpDQogIA0KICB0cmFpbi5mbGFnZ2VkIDwtIHRyYWluJT4lDQogICAgbXV0YXRlX2FsbChmdW5zKG5hLmZsYWcgPSBpZmVsc2UoaXMubmEoLiksMSwwKSkpDQogIGludF9kZiA8LSB0cmFpbi5mbGFnZ2VkJT4lDQogICAgZHBseXI6OnNlbGVjdCgtaW5kZXgsIC10YXJnZXRfZmxhZywgLXRhcmdldF9hbXQpJT4lDQogICAgZHBseXI6OnNlbGVjdF9pZihpcy5udW1lcmljKQ0KICAjIG1kLnBhdHRlcm4oaW50X2RmKQ0KICBjbGVhbmVkX2NvbHMgPC0gbGlzdCgpDQogIGZvcihjIGluIGNvbG5hbWVzKHRyYWluJT4lDQogICAgICAgICAgICAgICAgICAgIGRwbHlyOjpzZWxlY3QoLWluZGV4LCAtdGFyZ2V0X2ZsYWcsIC10YXJnZXRfYW10LCAta2lkc2RyaXYpJT4lDQogICAgICAgICAgICAgICAgICAgIGRwbHlyOjpzZWxlY3RfaWYoaXMubnVtZXJpYykpKXsNCiAgICBjb2x1bW4gPC0gdHJhaW4uZmxhZ2dlZCU+JXNlbGVjdF8oY29sID0gYykNCiAgICBpcXIgPC0gcXVhbnRpbGUoY29sdW1uJGNvbCwgbmEucm0gPSBUKVs0XSAtIHF1YW50aWxlKGNvbHVtbiRjb2wsIG5hLnJtID0gVClbMl0NCiAgICBsb3cgPC0gcXVhbnRpbGUoY29sdW1uJGNvbCwgbmEucm0gPSBUKVsyXSAtIGlxcg0KICAgIGhpZ2ggPC0gcXVhbnRpbGUoY29sdW1uJGNvbCwgbmEucm0gPSBUKVs0XSArIGlxcg0KICAgIA0KICAgIHZhbHMgPC0gYygpDQogICAgZm9yKGkgaW4gc2VxKDE6bnJvdyhpbnRfZGYpKSl7DQogICAgICBpZmVsc2UoYmV0d2Vlbihjb2x1bW4kY29sW2ldLCBsb3cgLSAoMS41KmlxciksIGhpZ2ggKyAoMS41KmlxcikpLA0KICAgICAgICAgICAgIHZhbHNbaV0gPC0gY29sdW1uJGNvbFtpXSwgDQogICAgICAgICAgICAgaWZlbHNlKGlzLm5hKGNvbHVtbiRjb2xbaV0pLCB2YWxzW2ldIDwtIE5BLCB2YWxzW2ldIDwtIE5BKSkNCiAgICB9DQogICAgDQogICAgaWZlbHNlKGxlbmd0aCh2YWxzKSA9PSBucm93KGludF9kZiksDQogICAgICAgICAgIGNsZWFuZWRfY29sc1tbY11dIDwtIHZhbHMsIA0KICAgICAgICAgICBjbGVhbmVkX2NvbHNbW2NdXSA8LSBjKHZhbHMsTkEpKQ0KICB9DQogIA0KICBkZjIgPC0gYmluZF9jb2xzKA0KICAgIGJpbmRfY29scyhjbGVhbmVkX2NvbHMpJT4lDQogICAgICAjIHNlbGVjdCgta2lkc2RyaXYpJT4lDQogICAgICBzY2FsZShjZW50ZXIgPSBUUlVFKSU+JQ0KICAgICAgZGF0YS5mcmFtZSgpLA0KICAgIHRyYWluLmZsYWdnZWQlPiUNCiAgICAgIGRwbHlyOjpzZWxlY3QoZW5kc193aXRoKCduYS5mbGFnJyksIGtpZHNkcml2KSwNCiAgICB0cmFpbiU+JWRwbHlyOjpzZWxlY3RfaWYoaXMuY2hhcmFjdGVyKQ0KICAgICkNCiAgDQogIGRmMyA8LSBkZjIlPiUNCiAgICBtdXRhdGUoDQogICAgICBraWRzZHJpdl9vdXQuZmxhZyA9IGlmZWxzZShpcy5uYShraWRzZHJpdikgJiBraWRzZHJpdl9uYS5mbGFnID09MCwxLDApLA0KICAgICAgYWdlX291dC5mbGFnID0gaWZlbHNlKGlzLm5hKGFnZSkgJiBhZ2VfbmEuZmxhZyA9PTAsMSwwKSwNCiAgICAgIGhvbWVraWRzX291dC5mbGFnID0gaWZlbHNlKGlzLm5hKGhvbWVraWRzKSAmIGhvbWVraWRzX25hLmZsYWcgPT0wLDEsMCksDQogICAgICB5b2pfb3V0LmZsYWcgPSBpZmVsc2UoaXMubmEoeW9qKSAmIHlval9uYS5mbGFnID09MCwxLDApLA0KICAgICAgaW5jb21lX291dC5mbGFnID0gaWZlbHNlKGlzLm5hKGluY29tZSkgJiBpbmNvbWVfbmEuZmxhZyA9PTAsMSwwKSwNCiAgICAgIHBhcmVudDFfb3V0LmZsYWcgPSBpZmVsc2UoaXMubmEocGFyZW50MSkgJiBwYXJlbnQxX25hLmZsYWcgPT0wLDEsMCksDQogICAgICBob21lX3ZhbF9vdXQuZmxhZyA9IGlmZWxzZShpcy5uYShob21lX3ZhbCkgJiBob21lX3ZhbF9uYS5mbGFnID09MCwxLDApLA0KICAgICAgbXN0YXR1c19vdXQuZmxhZyA9IGlmZWxzZShpcy5uYShtc3RhdHVzKSAmIG1zdGF0dXNfbmEuZmxhZyA9PTAsMSwwKSwNCiAgICAgIHNleF9vdXQuZmxhZyA9IGlmZWxzZShpcy5uYShzZXgpICYgc2V4X25hLmZsYWcgPT0wLDEsMCksDQogICAgICBlZHVjYXRpb25fb3V0LmZsYWcgPSBpZmVsc2UoaXMubmEoZWR1Y2F0aW9uKSAmIGVkdWNhdGlvbl9uYS5mbGFnID09MCwxLDApLA0KICAgICAgam9iX291dC5mbGFnID0gaWZlbHNlKGlzLm5hKGpvYikgJiBqb2JfbmEuZmxhZyA9PTAsMSwwKSwNCiAgICAgIHRyYXZ0aW1lX291dC5mbGFnID0gaWZlbHNlKGlzLm5hKHRyYXZ0aW1lKSAmIHRyYXZ0aW1lX25hLmZsYWcgPT0wLDEsMCksDQogICAgICBjYXJfdXNlX291dC5mbGFnID0gaWZlbHNlKGlzLm5hKGNhcl91c2UpICYgY2FyX3VzZV9uYS5mbGFnID09MCwxLDApLA0KICAgICAgYmx1ZWJvb2tfb3V0LmZsYWcgPSBpZmVsc2UoaXMubmEoYmx1ZWJvb2spICYgYmx1ZWJvb2tfbmEuZmxhZyA9PTAsMSwwKSwNCiAgICAgIHRpZl9vdXQuZmxhZyA9IGlmZWxzZShpcy5uYSh0aWYpICYgdGlmX25hLmZsYWcgPT0wLDEsMCksDQogICAgICBjYXJfdHlwZV9vdXQuZmxhZyA9IGlmZWxzZShpcy5uYShjYXJfdHlwZSkgJiBjYXJfdHlwZV9uYS5mbGFnID09MCwxLDApLA0KICAgICAgcmVkX2Nhcl9vdXQuZmxhZyA9IGlmZWxzZShpcy5uYShyZWRfY2FyKSAmIHJlZF9jYXJfbmEuZmxhZyA9PTAsMSwwKSwNCiAgICAgIG9sZGNsYWltX291dC5mbGFnID0gaWZlbHNlKGlzLm5hKG9sZGNsYWltKSAmIG9sZGNsYWltX25hLmZsYWcgPT0wLDEsMCksDQogICAgICBjbG1fZnJlcV9vdXQuZmxhZyA9IGlmZWxzZShpcy5uYShjbG1fZnJlcSkgJiBjbG1fZnJlcV9uYS5mbGFnID09MCwxLDApLA0KICAgICAgcmV2b2tlZF9vdXQuZmxhZyA9IGlmZWxzZShpcy5uYShyZXZva2VkKSAmIHJldm9rZWRfbmEuZmxhZyA9PTAsMSwwKSwNCiAgICAgIG12cl9wdHNfb3V0LmZsYWcgPSBpZmVsc2UoaXMubmEobXZyX3B0cykgJiBtdnJfcHRzX25hLmZsYWcgPT0wLDEsMCksDQogICAgICBjYXJfYWdlX291dC5mbGFnID0gaWZlbHNlKGlzLm5hKGNhcl9hZ2UpICYgY2FyX2FnZV9uYS5mbGFnID09MCwxLDApLA0KICAgICAgdXJiYW5pY2l0eV9vdXQuZmxhZyA9IGlmZWxzZShpcy5uYSh1cmJhbmljaXR5KSAmIHVyYmFuaWNpdHlfbmEuZmxhZyA9PTAsMSwwKQ0KICApDQogIA0KICB0ZW1wX2RmIDwtIG1pY2UoZGYzLCBtZXRob2QgPSAnY2FydCcsIG1heGl0ID0gMSkNCiAgdHJhaW5fY2xlYW4gPC0gY29tcGxldGUodGVtcF9kZiklPiUNCiAgICBiaW5kX2NvbHModHJhaW4lPiVkcGx5cjo6c2VsZWN0KGluZGV4LCB0YXJnZXRfZmxhZywgdGFyZ2V0X2FtdCkpDQoNCiAgZGF0YS5mb3Iuc3RlcGFpYyA8LSB0cmFpbl9jbGVhbiU+JQ0KICAgIGRwbHlyOjpzZWxlY3QoLWluZGV4X25hLmZsYWcsIC10YXJnZXRfZmxhZ19uYS5mbGFnLCAtdGFyZ2V0X2FtdF9uYS5mbGFnLCANCiAgICAgICAgICAgLXRhcmdldF9hbXQpJT4lDQogICAgZHBseXI6OnNlbGVjdF9pZihpcy5udW1lcmljKSU+JQ0KICAgIGJpbmRfY29scygNCiAgICAgIGR1bW15LmRhdGEuZnJhbWUodHJhaW5fY2xlYW4lPiVzZWxlY3RfaWYoaXMuY2hhcmFjdGVyKSkNCiAgICApDQogIA0KICBtZWQuY2xhaW0gPC0gNDEwNC4wMA0KDQogIHByb2IucHJlZHMgPC0gZGF0YS5mcmFtZSgNCiAgICBQX1RBUkdFVF9GTEFHID0gcHJlZGljdChtb2RlbC5wcm9iLCBkYXRhLmZvci5zdGVwYWljLCB0eXBlPSJyZXNwb25zZSIpDQogICAgKSU+JQ0KICAgIGJpbmRfY29scyhkYXRhLmZvci5zdGVwYWljKSU+JQ0KICAgIG11dGF0ZShQX1RBUkdFVF9BTVQgPSBtZWQuY2xhaW0pJT4lDQogICAgZHBseXI6OnNlbGVjdChJTkRFWCA9IGluZGV4LCBQX1RBUkdFVF9GTEFHLCBQX1RBUkdFVF9BTVQpDQoNCiAgcmV0dXJuKHByb2IucHJlZHMpDQp9DQpgYGANCg0KYGBge3IsIGVjaG8gPSBUUlVFfQ0KdGVzdF9kYXRhIDwtIHNjb3JlX2NyZWF0b3IoJ2xvZ2l0X2luc3VyYW5jZV90ZXN0LmNzdicpDQp3cml0ZS5jc3YoeCA9IHRlc3RfZGF0YSwgZmlsZSA9ICd5YXptYW5faW5zdXJhbmNlX3Rlc3QuY3N2JykNCmBgYA0KDQojIFNvdXJjZXMNClteMV06IEhvZmZtYW5uLCBKb2huIFAuIEdlbmVyYWxpemVkIExpbmVhciBNb2RlbHM6IGFuIEFwcGxpZWQgQXBwcm9hY2guIFBlYXJzb24vQWxseW4gJiBCYWNvbiwgMjAwNC4NClteMl06IGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvcG1jL2FydGljbGVzL1BNQzQ4NDIzOTkvDQpbXjNdOiBKYW1lcywgR2FyZXRoLCBldCBhbC4gQW4gSW50cm9kdWN0aW9uIHRvIFN0YXRpc3RpY2FsIExlYXJuaW5nIHdpdGggQXBwbGljYXRpb25zIGluIFIuIFNwcmluZ2VyLCAyMDE3Lg0KW140XTogaHR0cHM6Ly9tYXRoZXdhbmFseXRpY3MuY29tLzIwMTUvMDkvMDIvbG9naXN0aWMtcmVncmVzc2lvbi1pbi1yLXBhcnQtdHdvLw0KW141XTogaHR0cHM6Ly93d3cua2RudWdnZXRzLmNvbS8yMDEwLzA5L3B1Yi1pcy1hdWMtdGhlLWJlc3QtbWVhc3VyZS5odG1s