# Load data, required packages, and functions
library(NHANES)
library(caret)
library(ggplot2)
library(dplyr)
library(splines)
library(broom)
library(gridExtra)
library(randomForest)
library(rpart.plot)
data(NHANES)


twoClassSummaryCustom <- function (data, lev = NULL, model = NULL) {
    if (length(lev) > 2) {
        stop(paste("Your outcome has", length(lev), "levels. The twoClassSummary() function isn't appropriate."))
    }
    caret:::requireNamespaceQuietStop("pROC")
    if (!all(levels(data[, "pred"]) == lev)) {
        stop("levels of observed and predicted data do not match")
    }
    rocObject <- try(pROC::roc(data$obs, data[, lev[1]], direction = ">", 
        quiet = TRUE), silent = TRUE)
    rocAUC <- if (inherits(rocObject, "try-error")) 
        NA
    else rocObject$auc
    out <- c(rocAUC, sensitivity(data[, "pred"], data[, "obs"], 
        lev[1]), specificity(data[, "pred"], data[, "obs"], lev[2]))
    out2 <- postResample(data[, "pred"], data[, "obs"])
    out <- c(out, out2[1])
    names(out) <- c("AUC", "Sens", "Spec", "Accuracy")
    out
}
# Any code to clean the data
testNHANES <- NHANES %>% 
  select(Age, Gender, Weight, Height, Pulse, TotChol, PhysActive, BPSysAve) %>% 
  filter(!is.na(Age), !is.na(Gender), !is.na(Weight), !is.na(Height), !is.na(Pulse), !is.na(TotChol), !is.na(PhysActive), !is.na(BPSysAve)) 

testNHANES2 <- NHANES %>% 
  select(Age, Gender, Weight, Height, Pulse, TotChol, PhysActive, BPSysAve, Diabetes) %>% 
  filter(!is.na(Age), !is.na(Gender), !is.na(Weight), !is.na(Height), !is.na(Pulse), !is.na(TotChol), !is.na(PhysActive), !is.na(BPSysAve), !is.na(Diabetes)) 

Data Context

NHANES is an observational study funded and conducted by the CDC, specifically its National Center for Health Statistics (NCHS) branch. The study, which began in the early 1960s, is an annual survey administered to a nationally representative sample of about 5,000 non-institutionalized persons from around the country. To ensure that its sample is as accurate as possible, NHANES uses a complex, multistage probability sampling design to select a cohort representative of the non-institutionalized population of the US. I will only be looking at the NHANES data provided for years between 2009-2012. In addition to being asked a variety of questions about demographic and socioeconomic information, participants undergo a health interview and examination. This involves taking health measurements in a specially designed and equipped mobile center that travels with the NCHS to locations throughout the country. In total, information about 76 unique variables is collected by a team of physicians, medical technicians, and dietary/health interviewers about a range of health bio-markers and behavioral tendencies. The data that is collected gives valuable insight into the distribution of health problems and risk factors in the U.S. population. This gives researchers important clues about the causes of disease and allows policymakers to detect the extent to which various health problems have changed temporally in the U.S. population (CDC, 2020).

Research Questions

  • Regression Task:
    • In this report, I wanted to answer the question: How well can average systolic blood pressure (measured in mm Hg) be predicted/modeled by a range of other biological, demographic, and health markers such as age, weight, cholesterol, and others?
  • Classification Task:
    • The research question I attempted to address in this report using classification methods was concerned with modeling the likelihood of and individual having diabetes. Specifically, I asked: How well can various health variables such as age, weight, physical activity levels, and others predict the likelihood of an individual to have diabetes?


Regression Analysis


Methods

Investigation 1: Ignoring Nonlinearity


Models Used:
To begin addressing my regression research questions, I used multiple different regression modeling methods that do not account for any nonlinearity in the relationship between predictors and the outcome. The first model I created used the ordinary least squares regression method. The second model I created used subset selection methods. Specifically, I used the backward stepwise subset selection method. The final model I built used LASSO linear regression methods. Collapse code to view how I fit these models.

# OLS Regression
set.seed(123)
OLS_mod2 <- train(
    BPSysAve ~ .,
    data = testNHANES,
    method = "lm",
    trControl = trainControl(method = "cv", number = 8, selectionFunction = "oneSE"),
    metric = "MAE",
    na.action = na.omit
)
  
# Subset Selection (Backward Stepwise)
set.seed(123)

Backward_Stepwise_mod <- train(
    BPSysAve ~ .,
    data = testNHANES,
    method = "leapBackward",
    tuneGrid = data.frame(nvmax = 1:7),
    trControl = trainControl(method = "cv", number = 8, selectionFunction = "oneSE"),
    metric = "MAE",
    na.action = na.omit
)

# LASSO 
set.seed(123)

LASSO_mod <- train(
    BPSysAve ~ .,
    data = testNHANES,
    method = "glmnet",
    trControl = trainControl(method = "cv", number = 8, selectionFunction = "oneSE"),
    tuneGrid = data.frame(alpha = 1, lambda = seq(0, 10, length.out = 100)),
    metric = "MAE",
    na.action = na.omit
)
  • Ordinary Least Squares Regression Evaluation:
    • To evaluate the OLS model, I primarily relied on quantitative evaluation metrics. Specifically, I used mean absolute error (MAE) to estimate test performance. The ordinary least squares regression model produced systolic blood pressure estimates that were, on average, off by 10.807 mm Hg and had a standard deviation of 0.299.
#OLS Evaluation 
OLS_mod2$results


  • Backward Stepwise Selection Evaluation:
    • Similar to the OLS model, I used MAE as one way to evaluate the the subset selection model. Because the subset selection method attempts to find which subset of predictors produces the best model, MAE estimates are produced for every subset size. I used a plot comparing subset size and MAE to get an initial idea of which subset produced the lowest error. I then confirmed the best tune by looking at the caret model output, which showed that the best backward stepwise selection model produced systolic blood pressure predictions that were off by about 10.856 mm Hg on average and had a MAE SD of 0.286.
# Subset Selection Evaluation 

plot(Backward_Stepwise_mod)

Backward_Stepwise_mod$results
mean(Backward_Stepwise_mod$resample$MAE)
## [1] 10.85571


  • LASSO Linear Regression Evaluation:
    • LASSO methods also fit many models, though this time at different values of lambda (the tuning parameter). To begin to determine which value of lambda produces a model with the lowest MAE, I looked at a plot of lambda vs. MAE. I then confirmed the best tune by looking at the caret model output, which showed that the LASSO model with the lowest MAE produced systolic blood pressure estimates that were off by about 10.899 mm Hg on average and a MAE SD of 0.285.
#LASSO Evaluation 

plot(LASSO_mod)

head(LASSO_mod$results, 8)
LASSO_mod$bestTune
ggplot(LASSO_mod$results, aes(x = lambda)) +
    geom_pointrange(aes(y = MAE, ymin = MAE-MAESD, ymax = MAE+MAESD)) +
    theme_classic() +
    geom_vline(xintercept = 0.505, color = "red") +
    labs(x = "lambda", y = "MAE +/- 1SD")

mean(LASSO_mod$resample$MAE)
## [1] 10.89853


By considering multiple methods of linear regression modeling, I was able to begin gathering a sense of how well my various predictor variables are able to actually predict blood pressure. I was also able to see if different modeling methods produced different results that could be important to consider. None of these models considered potential non-linear relationships between predictors and the outcome, so that is something I turn to next.

Investigation 2: Accounting for Nonlinearity


To check to see if any quantitative predictors might be better modeled with nonlinear relationships, I constructed residual plots to evaluate their relationships.


For each of the models I fit above, I created residual plots of each of the quantitative predictors. The various sets of plots seen below compare these different residual plots produced from the different models against each other. Also included in the set of graphs is a plot comparing the quantitative predictor to blood pressure from the training data. The final set of plots is an overall residual vs predicted graph for each of the models I fit in investigation 1.

# Residual Plot

set.seed(123)

OLS_mod_data <- testNHANES %>% 
  mutate(pred = predict(OLS_mod2, newdata = testNHANES), 
         resid = BPSysAve - pred)

p1 <- ggplot(OLS_mod_data, aes(x = Age, y = resid)) +
      geom_point() +
      geom_smooth() +
      geom_hline(yintercept = 0, color = "red")

p2 <- ggplot(OLS_mod_data, aes(x = Weight, y = resid)) +
      geom_point() +
      geom_smooth() +
      geom_hline(yintercept = 0, color = "red")

p3 <- ggplot(OLS_mod_data, aes(x = Height, y = resid)) +
      geom_point() +
      geom_smooth() +
      geom_hline(yintercept = 0, color = "red")

p4 <- ggplot(OLS_mod_data, aes(x = Pulse, y = resid)) +
      geom_point() +
      geom_smooth() +
      geom_hline(yintercept = 0, color = "red")

p5 <- ggplot(OLS_mod_data, aes(x = TotChol, y = resid)) +
      geom_point() +
      geom_smooth() +
      geom_hline(yintercept = 0, color = "red")

p6 <- ggplot(OLS_mod_data, aes(x = pred, y = resid)) +
      geom_point() +
      geom_smooth() +
      geom_hline(yintercept = 0, color = "red")


Backward_Stepwise_mod_data <- testNHANES %>% 
  mutate(pred = predict(Backward_Stepwise_mod, newdata = testNHANES), 
         resid = BPSysAve - pred)

q1 <- ggplot(Backward_Stepwise_mod_data, aes(x = Age, y = resid)) +
      geom_point() +
      geom_smooth() +
      geom_hline(yintercept = 0, color = "red")

q2 <- ggplot(Backward_Stepwise_mod_data, aes(x = Weight, y = resid)) +
      geom_point() +
      geom_smooth() +
      geom_hline(yintercept = 0, color = "red")

q3 <- ggplot(Backward_Stepwise_mod_data, aes(x = Height, y = resid)) +
      geom_point() +
      geom_smooth() +
      geom_hline(yintercept = 0, color = "red")

q4 <- ggplot(Backward_Stepwise_mod_data, aes(x = Pulse, y = resid)) +
      geom_point() +
      geom_smooth() +
      geom_hline(yintercept = 0, color = "red")

q5 <- ggplot(Backward_Stepwise_mod_data, aes(x = TotChol, y = resid)) +
      geom_point() +
      geom_smooth() +
      geom_hline(yintercept = 0, color = "red")

q6 <- ggplot(Backward_Stepwise_mod_data, aes(x = pred, y = resid)) +
      geom_point() +
      geom_smooth() +
      geom_hline(yintercept = 0, color = "red")


LASSO_mod_data <- testNHANES %>% 
  mutate(pred = predict(LASSO_mod, newdata = testNHANES), 
         resid = BPSysAve - pred)

r1 <- ggplot(LASSO_mod_data, aes(x = Age, y = resid)) +
      geom_point() +
      geom_smooth() +
      geom_hline(yintercept = 0, color = "red")

r2 <- ggplot(LASSO_mod_data, aes(x = Weight, y = resid)) +
      geom_point() +
      geom_smooth() +
      geom_hline(yintercept = 0, color = "red")

r3 <- ggplot(LASSO_mod_data, aes(x = Height, y = resid)) +
      geom_point() +
      geom_smooth() +
      geom_hline(yintercept = 0, color = "red")

r4 <- ggplot(LASSO_mod_data, aes(x = Pulse, y = resid)) +
      geom_point() +
      geom_smooth() +
      geom_hline(yintercept = 0, color = "red")

r5 <- ggplot(LASSO_mod_data, aes(x = TotChol, y = resid)) +
      geom_point() +
      geom_smooth() +
      geom_hline(yintercept = 0, color = "red")

r6 <- ggplot(LASSO_mod_data, aes(x = pred, y = resid)) +
      geom_point() +
      geom_smooth() +
      geom_hline(yintercept = 0, color = "red")


s1 <- testNHANES %>% 
  ggplot(aes(x = Age, y = BPSysAve)) +
  geom_point() +
  geom_smooth(color = "blue", se = FALSE) +
  geom_smooth(method = "lm", color = "red", se = FALSE)

s2 <- testNHANES %>% 
  ggplot(aes(x = Weight, y = BPSysAve)) +
  geom_point() +
  geom_smooth(color = "blue", se = FALSE) +
  geom_smooth(method = "lm", color = "red", se = FALSE)

s3 <- testNHANES %>% 
  ggplot(aes(x = Height, y = BPSysAve)) +
  geom_point() +
  geom_smooth(color = "blue", se = FALSE) +
  geom_smooth(method = "lm", color = "red", se = FALSE)

s4 <- testNHANES %>% 
  ggplot(aes(x = Pulse, y = BPSysAve)) +
  geom_point() +
  geom_smooth(color = "blue", se = FALSE) +
  geom_smooth(method = "lm", color = "red", se = FALSE)

s5 <- testNHANES %>% 
  ggplot(aes(x = TotChol, y = BPSysAve)) +
  geom_point() +
  geom_smooth(color = "blue", se = FALSE) +
  geom_smooth(method = "lm", color = "red", se = FALSE)
grid.arrange(p1, q1, r1, s1, nrow = 2, ncol = 2)

grid.arrange(p2, q2, r2, s2, nrow = 2, ncol = 2)

grid.arrange(p3, q3, r3, s3, nrow = 2, ncol = 2)

grid.arrange(p4, q4, r4, s4, nrow = 2, ncol = 2)

grid.arrange(p5, q5, r5, s5, nrow = 2, ncol = 2)

grid.arrange(p6, q6, r6, nrow = 2, ncol = 2)

  • Residual Plots Evaluation:
    • Based on the residual plots above, it seems as if none of the quantitative predictors would necessarily be better modeled with nonlinear relationships. Each of the residual plots created across the three models had lines of best fit that fell smoothly along the x-axis. This suggests that these quantitative predictors have fairly linear relationships with average systolic blood pressure in this dataset. This is confirmed by creating plots comparing each of the quantitative predictors to the quantitative outcome variable– average systolic blood pressure. We can compare two best fit lines, one as a linear fit and the other as a local regression, for each of these plots. While there is some nonlinearity, the local regression line of best fit still follows fairly closely to the linear regression line.



Creating Models with Natural Splines:
Even if it seems like none of the quantitative predictors would necessarily be better modeled with nonlinear relationships, I can confirm my assumptions and maybe learn more by fitting new, updated models of the subset selection and LASSO methods using natural splines. See code below to view the fitting process.

# Stepwise Selection 
set.seed(123)

NS_Backward_Stepwise_mod <- train(
    BPSysAve ~ Gender + PhysActive + ns(Age, 3) + ns(Weight, 3) + ns(Height, 3) + ns(Pulse, 3) + ns(TotChol, 3),
    data = testNHANES,
    method = "leapBackward",
    tuneGrid = data.frame(nvmax = 1:7),
    trControl = trainControl(method = "cv", number = 8, selectionFunction = "oneSE"),
    metric = "MAE",
    na.action = na.omit
)


# LASSO 
set.seed(123)

NS_LASSO_mod <- train(
    BPSysAve ~ Gender + PhysActive + ns(Age, 3) + ns(Weight, 3) + ns(Height, 3) + ns(Pulse, 3) + ns(TotChol, 3),
    data = testNHANES,
    method = "glmnet",
    trControl = trainControl(method = "cv", number = 8, selectionFunction = "oneSE"),
    tuneGrid = data.frame(alpha = 1, lambda = seq(0, 10, length.out = 100)),
    metric = "MAE",
    na.action = na.omit
)


  • Natural Spline Backward Stepwise Selection Evaluation:
    • Same as the original subset selection process, I determined which subset size produced the best MAE. This natural splines subset selection model identified that a model with a subset size of 6 was best and produced average systolic blood pressure estimates that were, on average, off by about 10.723 mm Hg and a MAE SD of 0.267.
NS_Backward_Stepwise_mod$bestTune
NS_Backward_Stepwise_mod$results


  • Natural Spline LASSO Evaluation:
    • Just like the other natural splines model, evaluating this method required finding which value of lambda produced a model fit with the lowest MAE. The model with the best lambda produced average systolic blood pressure estimates that were, on average, off by about 10.756 and had an MAE SD of 0.251.
NS_LASSO_mod$bestTune
head(NS_LASSO_mod$results)
ggplot(NS_LASSO_mod$results, aes(x = lambda)) +
    geom_pointrange(aes(y = MAE, ymin = MAE-MAESD, ymax = MAE+MAESD)) +
    theme_classic() +
    geom_vline(xintercept = 0.404   , color = "red") +
    labs(x = "lambda", y = "MAE +/- 1SD")


To get a further sense of whether there is significant difference between the models, I can also consider how the variable importance compare among them.


Variable Importance


First, let’s address just the models that didn’t consider nonlinearity.


  • Backward Stepwise Subset Selection Variable Importance:
    • The backward stepwise model selected a model with three variables as the best, simplest model. The first variable identified by this method was age, followed by gender (a categorical predictor), and the third was weight. We could interpret this to mean that these three variables are the most important, in that order. The plot below helps us see that the model with a subset size of 3 is the best, simplest model. The caret readout below shows us the order in which variables were added, and we can interpret this as a level of importance.
# Stepwise Variable Importance 

plot(Backward_Stepwise_mod)

summary(Backward_Stepwise_mod)
## Subset selection object
## 7 Variables  (and intercept)
##               Forced in Forced out
## Age               FALSE      FALSE
## Gendermale        FALSE      FALSE
## Weight            FALSE      FALSE
## Height            FALSE      FALSE
## Pulse             FALSE      FALSE
## TotChol           FALSE      FALSE
## PhysActiveYes     FALSE      FALSE
## 1 subsets of each size up to 3
## Selection Algorithm: backward
##          Age Gendermale Weight Height Pulse TotChol PhysActiveYes
## 1  ( 1 ) "*" " "        " "    " "    " "   " "     " "          
## 2  ( 1 ) "*" "*"        " "    " "    " "   " "     " "          
## 3  ( 1 ) "*" "*"        "*"    " "    " "   " "     " "


  • LASSO Regression Variable Importance:
    • To get a sense of variable importance for the LASSO method, I looked at a plot of its coefficient paths. Variables whose coefficients were set to 0 last can be viewed as the most important as they were able to withstand the largest penalties. The table below provides a quantitative value relative to the distance traveled by each coefficient before being set to 0. The order in which the variable appears on the list corresponds to its relative importance. Similar to the stepwise method, age could be viewed as the most important predictor because it was the last variable to have its coefficient set to 0. Weight was the second to last variable whose coefficients were set to 0 by lambda, and gender was the third to last. I have good reason to believe that these are indeed the three most important variables then as both methods corroborated the others findings.
# LASSO Variable Importance 

plot(LASSO_mod$finalModel, xvar = "lambda", label = TRUE, col = rainbow(20))

# Create a boolean matrix (predictors x lambdas) of variable exclusion
bool_predictor_exclude <- LASSO_mod$finalModel$beta==0

# Loop over each variable
var_imp <- sapply(seq_len(nrow(bool_predictor_exclude)), function(row) {
    # Extract coefficient path (sorted from highest to lowest lambda)
    this_coeff_path <- bool_predictor_exclude[row,]
    # Compute and return the # of lambdas until this variable is out forever
    ncol(bool_predictor_exclude)-which.min(this_coeff_path)+1
})

# Create a dataset of this information and sort
var_imp_data <- tibble(
    var_name = rownames(bool_predictor_exclude),
    var_imp = var_imp
)
var_imp_data %>% arrange(desc(var_imp))


The variable importance analyses for both the linear stepwise and LASSO methods yielded similar results. While the variable importance order was not exactly the same between the two models, they still agreed about the top 3 being the same and the difference is likely negligible. This didn’t surprise me greatly as these are all biological indicators that I would’ve guessed with little background knowledge. I chose these predictor variables with blood pressure already in mind, and these results confirm my initial suspicions.


  • Natural Splines Stepwise Variable Importance:
    • The first model I fit with the stepwise method that didn’t consider nonlinearity produced a ‘best’ model with three variables. The backward stepwise model that did consider nonlinearity, however, produced a ‘best’ model that included 6 variables. Various transformations of age, gender, and weight continued to be identified as the most important, though this newer model also identified cholesterol in its final model as well. It should be noted, though, that cholesterol could be viewed as the least important predictor among those selected by the model. You can view the summary readout below to see the full selection process as it relates to variable importance.
plot(NS_Backward_Stepwise_mod)

summary(NS_Backward_Stepwise_mod)
## Subset selection object
## 17 Variables  (and intercept)
##                 Forced in Forced out
## Gendermale          FALSE      FALSE
## PhysActiveYes       FALSE      FALSE
## ns(Age, 3)1         FALSE      FALSE
## ns(Age, 3)2         FALSE      FALSE
## ns(Age, 3)3         FALSE      FALSE
## ns(Weight, 3)1      FALSE      FALSE
## ns(Weight, 3)2      FALSE      FALSE
## ns(Weight, 3)3      FALSE      FALSE
## ns(Height, 3)1      FALSE      FALSE
## ns(Height, 3)2      FALSE      FALSE
## ns(Height, 3)3      FALSE      FALSE
## ns(Pulse, 3)1       FALSE      FALSE
## ns(Pulse, 3)2       FALSE      FALSE
## ns(Pulse, 3)3       FALSE      FALSE
## ns(TotChol, 3)1     FALSE      FALSE
## ns(TotChol, 3)2     FALSE      FALSE
## ns(TotChol, 3)3     FALSE      FALSE
## 1 subsets of each size up to 6
## Selection Algorithm: backward
##          Gendermale PhysActiveYes ns(Age, 3)1 ns(Age, 3)2 ns(Age, 3)3
## 1  ( 1 ) " "        " "           " "         " "         "*"        
## 2  ( 1 ) " "        " "           " "         "*"         "*"        
## 3  ( 1 ) " "        " "           "*"         "*"         "*"        
## 4  ( 1 ) "*"        " "           "*"         "*"         "*"        
## 5  ( 1 ) "*"        " "           "*"         "*"         "*"        
## 6  ( 1 ) "*"        " "           "*"         "*"         "*"        
##          ns(Weight, 3)1 ns(Weight, 3)2 ns(Weight, 3)3 ns(Height, 3)1
## 1  ( 1 ) " "            " "            " "            " "           
## 2  ( 1 ) " "            " "            " "            " "           
## 3  ( 1 ) " "            " "            " "            " "           
## 4  ( 1 ) " "            " "            " "            " "           
## 5  ( 1 ) "*"            " "            " "            " "           
## 6  ( 1 ) "*"            " "            " "            " "           
##          ns(Height, 3)2 ns(Height, 3)3 ns(Pulse, 3)1 ns(Pulse, 3)2
## 1  ( 1 ) " "            " "            " "           " "          
## 2  ( 1 ) " "            " "            " "           " "          
## 3  ( 1 ) " "            " "            " "           " "          
## 4  ( 1 ) " "            " "            " "           " "          
## 5  ( 1 ) " "            " "            " "           " "          
## 6  ( 1 ) " "            " "            " "           " "          
##          ns(Pulse, 3)3 ns(TotChol, 3)1 ns(TotChol, 3)2 ns(TotChol, 3)3
## 1  ( 1 ) " "           " "             " "             " "            
## 2  ( 1 ) " "           " "             " "             " "            
## 3  ( 1 ) " "           " "             " "             " "            
## 4  ( 1 ) " "           " "             " "             " "            
## 5  ( 1 ) " "           " "             " "             " "            
## 6  ( 1 ) " "           "*"             " "             " "


  • Natural Splines LASSO Variable Importance:
    • The LASSO model considering nonlinearity similarly produced a final model with more predictors than the original that didn’t consider nonlinearity. This new model includes age, gender, weight, pulse, and total cholesterol. In terms of variable importance, this new LASSO model shakes things up some. Age, weight, and gender continue to be among the most important, though this new model identifies total cholesterol as also being among the most important. This suggests that considering nonlinearity for cholesterol might reduce test error for this model.
coef(NS_LASSO_mod$finalModel, NS_LASSO_mod$bestTune$lambda)
## 18 x 1 sparse Matrix of class "dgCMatrix"
##                         s1
## (Intercept)     109.200977
## Gendermale        3.095061
## PhysActiveYes     .       
## ns(Age, 3)1       6.334863
## ns(Age, 3)2      22.569763
## ns(Age, 3)3      23.931616
## ns(Weight, 3)1    8.265070
## ns(Weight, 3)2    1.990105
## ns(Weight, 3)3    .       
## ns(Height, 3)1    .       
## ns(Height, 3)2    .       
## ns(Height, 3)3    .       
## ns(Pulse, 3)1     .       
## ns(Pulse, 3)2     .       
## ns(Pulse, 3)3     2.784817
## ns(TotChol, 3)1   8.057782
## ns(TotChol, 3)2   .       
## ns(TotChol, 3)3   .
plot(NS_LASSO_mod$finalModel, xvar = "lambda", label = TRUE, col = rainbow(20))

# Create a boolean matrix (predictors x lambdas) of variable exclusion
bool_predictor_exclude2 <- NS_LASSO_mod$finalModel$beta==0

# Loop over each variable
var_imp2 <- sapply(seq_len(nrow(bool_predictor_exclude2)), function(row) {
    # Extract coefficient path (sorted from highest to lowest lambda)
    this_coeff_path2 <- bool_predictor_exclude2[row,]
    # Compute and return the # of lambdas until this variable is out forever
    ncol(bool_predictor_exclude2)-which.min(this_coeff_path2)+1
})

# Create a dataset of this information and sort
var_imp_data2 <- tibble(
    var_name = rownames(bool_predictor_exclude),
    var_imp = var_imp
)
var_imp_data2 %>% arrange(desc(var_imp))


Summary


GAM LOESS Model
By calculating and noting all my models’ variable importance thus far, I’ve been able to see a pattern emerge. Three variables in particular are present across all linear and nonlinear models. These three variables are age, weight, and gender. I can use these three particular variables to fit a GAM using LOESS terms to further investigate how other modeling methods improve (or don’t improve) test accuracy. I fit this model below, refer to the code to see specifics of the fitting process.


# GAM LOESS

set.seed(123)
gam_mod <- train(
    BPSysAve ~ Age + Weight + Gender,
    data = testNHANES,
    method = "gamLoess",
    tuneGrid = data.frame(degree = 1, span = seq(0.1, 0.9, by = 0.1)),
    trControl = trainControl(method = "cv", number = 8, selectionFunction = "oneSE"),
    metric = "MAE",
    na.action = na.omit
)
  • GAM LOESS Model Evaluation:
    • To evaluate my LOESS GAM, I had to first identify which span produced the lowest MAE. In this case, the best span was 0.1, and the average systolic blood pressure estimates produced by the model were, on average, off by 10.666 mm Hg and had an MAE SD of 0.243. This estimate is very comparable to the estimates of the other models fit above. The estimate function plots of each predictor below tell us some limited information; mainly that the quantitative predictors are mostly linear, though they might benefit from being fit in a nonlinear regression method as well. This LOESS GAM corroborates the conclusions I drew from the other models. We can feel some confidence in assuming that within this training data weight, gender, and age are able to help explain some variance in average systolic blood pressure.
plot(gam_mod)

gam_mod$bestTune
gam_mod$results %>%
    filter(span==gam_mod$bestTune$span)
par(mfrow = c(3,4)) # Sets up a grid of plots
plot(gam_mod$finalModel, se = TRUE) # Dashed lines are +/- 2 SEs


Model Comparison:
Now having fit a range of different models, I can compare them to determine which of them is ‘best’.


MAE and Uncertainty
Below are the MAE and MAE SD estimates for each of the methods’ “best” model– the simplest model with the lowest MAE.


  • Ordinary Least Squares
OLS_mod2$results


  • Backward Stepwise Subset Selection
Backward_Stepwise_mod$results %>%
    filter(nvmax==Backward_Stepwise_mod$bestTune$nvmax)


  • LASSO Linear Regression
LASSO_mod$results %>% 
  filter(lambda == LASSO_mod$bestTune$lambda)


  • Natural Splines Backward Stepwise Subset Selection
NS_Backward_Stepwise_mod$results %>% 
  filter(nvmax == NS_Backward_Stepwise_mod$bestTune$nvmax)


  • Natural Splines LASSO Regression
NS_LASSO_mod$results %>% 
  filter(lambda == NS_LASSO_mod$bestTune$lambda)


  • LOESS GAM
gam_mod$results %>% 
  filter(span == gam_mod$bestTune$span)


We can see from the readouts above that across the various models, MAE ranges from as low as 10.666 to as high as 10.899. The uncertainty across these MAE estimates are all fairly close to each other as well. With that in mind, none of these test error estimates are all that far away from each other. Moreover, in the context of average systolic blood pressure, a mater of 0.2 mm Hg difference across models is negligible. Overall though, none of these models seem particularly useful in a practical sense. Systolic blood pressure predictions that are off, on average, by about 10 mm Hg are not as useful as they could be in a clinical setting. I can feel somewhat certain, though, that given the predictors I looked at, the estimates won’t change significantly across different regression methods.


We saw from the residual plots above that, across all the different linear regression models, the trend lines sat nicely along the x-axis. This implies that linear regression, as opposed to a non-linear method, was an appropriate choice in modeling method as there are no systematic biases present in the trend. Stated differently, we can infer from this observed pattern that the quanntitative predictors plotted have fairly linear relationships with average systolic blood pressure in this dataset. I further confirmed this by creating plots comparing each of the quantitative predictors to average systolic blood pressure– these were the bottom right plots in the series of graphs. I also comparde two best fit lines, one as a linear fit and the other as a local regression, for each of these plots. While there is some nonlinearity, the local regression line of best fit still follows fairly closely to the linear regression line. Cumulatively, this suggests to me that linear regression is a suitable option for this regression task.


Across all the models I fit, I was able to get a sense of which variables were most important to the models. As I discussed above, mostly the same variables appeared at the top of the list– age, weight, and gender. While the order of these variables shifted slightly occasionally, the consistence presence of the same predictors made me feel confident that these models were fairly similar. Contextually, this makes sense as biological studies have suggested causal relationships between blood pressure and these predictors. Knowing this is the case and seeing that estimates across different models were fairly similar, I’m able to weigh the benefits and disadvantages of these models to determine which is the best.


Overall Most Preferable Model:

To determine the ‘best’, most preferable model I’ve created so far, I’m focusing mainly on striking a balance between predictive accuracy and interpretability. Thinking first about predictive accuracy, the models I produced all had mean absolute errors that were close to each other. Their error SDs were all fairly uniform as well, so it doesn’t seem as if one model has more tightly grouped/variable estimates than another. Because of this, I’m inclined to believe the differences in test error are likely negligible. With this in mind, I would be more partial towards a method that is simple and easy to interpret. So despite the LOESS GAM producing the lowest MAE (10.677), we lose a lot of interpretability as a result. I think sacrificing interpretabililty for a (contextually) very small decrease in test error is not very worthwhile. For this reason in particular, I think the backward stepwise model is the best, most preferable model of the ones I created. Its few variables combined with its easy interpretation make it particularly appealing. It is slightly less accurate than the other models (its systolic blood pressure estimates were off, on average, by 10.855 mm Hg and the MAE SD is estimated to be 0.286), but still falls within one SD of any of the other models’ test errors. It also gives a fairly clear way of understanding variable importance which can be useful in thinking about interpretations. We can see from the residual plots below that this model doesn’t have any glaring systematic biases that aren’t being addressed. Trend lines fit nicely along the x-axis and quantitative predictors have linear relationships with average systolic blood pressure. Overall, the model performs well and it is simple and interpretable– just what I wanted.

grid.arrange(q1, q2, q3, q4, q5, q6, nrow = 3, ncol = 2)



Classification Analysis


Methods


Models Used:
I created two models using two different methods to address my classification research question. The first model I created used LASSO logistic regression. The second model I created used random forest/bagging methods. Collapse the code to see the fitting process for my LASSO logistic regression model.

# LASSO Logistic Regression 

set.seed(253)
logistic_mod <- train(
    Diabetes ~ Age + Gender + Weight + Height + Pulse + TotChol + PhysActive + BPSysAve,
    data = testNHANES2,
    method = "glmnet",
    family = "binomial",
    tuneGrid = data.frame(alpha = 1, lambda = seq(0, .1, length.out = 100)),
    trControl = trainControl(method = "cv", number = 10, selectionFunction = "oneSE", classProbs = TRUE, summaryFunction = twoClassSummaryCustom),
    metric = "AUC",
    na.action = na.omit
)

# Bagging and Random Forests 
set.seed(253)
rf_mod <- train(
    Diabetes ~ Age + Gender + Weight + Height + Pulse + TotChol + PhysActive + BPSysAve,
    data = testNHANES2,
    method = "rf",
    tuneGrid = data.frame(mtry = c(0:8)),
    trControl = trainControl(method = "oob", selectionFunction = "best"),
    metric = "AUC",
    ntree = 1000, 
    na.action = na.omit
)


  • LASSO Logistic Regression Evaluation:
    • To evaluate the LASSO logistic regression model, I utilized a number of techniques. To begin, I looked at a plot of lambda vs AUC to get a sense of which lambda produced the best model. I confirmed this by checking the caret results and final model outputs to confirm which value of lambda produced the model with the highest AUC. The lambda that produced the best, most simple model had an AUC of 0.806. From there, I checked the best LASSO model’s sensitivity, specificity, overall accuracy, and corresponding measures of uncertainty for accuracy (SDs). The caret readout reports that the best tune model has a sensitivity of .999, a specificity of .005, and an overall accuracy of 91%. In context, this means that the model is able to accurately predict someone’s diabetes status about 91% of the time. I also calculated the NIR for the training data to further contextualize my results. The NIR is 91%, which is very high and suggests that the model could do fairly well simply by predicting someone isn’t diabetic every time. Predicted probability boxplots were made to confirm measures of sensitivity and specificity– see discussion below for issues relating to specificity and sensitivity.
# Lambda vs. AUC
plot(logistic_mod)

# Best Tune Metrics
logistic_mod$results %>%
    filter(lambda==logistic_mod$bestTune$lambda) # ARE SENS AND SPEC SWITCHED HERE? 
# NIR Metric
testNHANES2 %>% 
  count(Diabetes)
6848/(6848+673)
## [1] 0.9105172
# LASSO Logistic Model Predicted Probability Boxplots
lasso_logistic_mod_data <- testNHANES2 %>%
    mutate(prob_pred = predict(logistic_mod, newdata = testNHANES2, type = "prob"))

lasso_logistic_mod_data %>% 
  ggplot(aes(x = Diabetes, y = prob_pred$Yes)) +
  geom_boxplot() +
  geom_hline(yintercept = .5, color = 'red') +
  theme_classic() +
  labs(x = 'Diabetes Status', y = 'Predicted Probability of Being Diabetic (DiabetesYes)')

# Checking Predictions (see confusion matrix below)

lasso_logistic_mod_data %>% 
  mutate(PredictDiabetesYes = prob_pred$Yes > .5) %>%  #if I change this to prob_pred$No > .5, the sensitivity and specificity measures match the caret results readout, but aren't we modeling the probability of someone having diabetes (when y=1)?
  count(Diabetes, PredictDiabetesYes)
# Confirming Predictions with Training Logistic Model + Predicted Probability Boxplots
training_logistic_mod <- testNHANES2 %>% 
  with(glm(Diabetes ~ Age + Gender + Weight + Height + Pulse + TotChol + PhysActive + BPSysAve, family = binomial))

augment(training_logistic_mod, type.predict = 'response') %>%
  ggplot(aes(x = factor(Diabetes), y = .fitted)) + #replace ... with outcome variable name
  geom_boxplot() +
  labs(x = 'Diabetic', y = 'Predicted Probability of Outcome') + 
  theme_classic()

logistic_mod_data_copy <- testNHANES2 %>% 
  mutate(pred = predict(logistic_mod, newdata = testNHANES2))
Confusion Matrix: 

             Actual +    Actual -
Predict +       4 (TP)      1 (FP)
Predict -      669 (FN)   6847 (TN)


Notes on LASSO Logistic Model Accuracy Measures

Sensitivity = TP/(TP + FN) = 4/(4 + 669) = 0.005943536

Specificity = TN/(TN + FP) = 6847/(6847 + 1) = 0.999854

We can see that the calculations above (which are admittedly from the training data) that they are switched from what is reported in the caret ‘results’ readout. If I change it so that we are modeling the probability of someone not having diabetes, as opposed to the opposite, the sensitivity and specificity would match the caret results readout. Even if the measures above are from the training data, it still provides compelling evidence that the caret readout is switched so you should keep that in mind.


  • Bagging/Random Forest Evaluation:
    • To evaluate the random forest model, I produced a plot of the number of randomly selected predictors vs the Out of Bag Accuracy. I used the caret results output to confirm this information. I lastly used the caret final model output to tell me the optimal random number of predictors to use based on estimated OOB error rates– in this case the optimal number of random variables was only 2 and this produced an error rate of 4.65%. This output also provides a matrix that can be used to calculate sensitivity and specificity. The class error is associated with these measures.
# Bagging and Random Forests Evaluation 

# OOB Accuracy vs. No.Randomly Selected Predictors
plot(rf_mod)

# Accuracy Metrics
rf_mod$results
rf_mod$finalModel
## 
## Call:
##  randomForest(x = x, y = y, ntree = 1000, mtry = min(param$mtry,      ncol(x))) 
##                Type of random forest: classification
##                      Number of trees: 1000
## No. of variables tried at each split: 2
## 
##         OOB estimate of  error rate: 4.65%
## Confusion matrix:
##       No Yes class.error
## No  6828  20 0.002920561
## Yes  330 343 0.490341753


These two methods were used as a way of gauging whether variables I believed to be potential indicators of diabetes were actually good predictors. The different methods allowed me to come at this question from slightly different angles and ultimately produced different results as will be discussed below.


Variable Importance


  • LASSO Logistic Regression Variable Importance:
    • I used coefficient path plots to show how quickly the various predictors are set to 0 by lambda at differing rates. I understood the predictors who took the longest to be set to 0 as being the most important in terms of its predictive power. This was confirmed by computing the distances traveled by the various predictors before being set to 0. From the list that was produced, we can see that age and weight were two of the most important predictors in the model. Cholesterol, blood pressure, height, and pulse were also fairly similarly ranked in importance. This does make sense to me in the context of the data and the classification questions. I think many people think of weight as being the primary indicator of diabetes status, and the other predictors often have associated changes with regards to weight. It should be noted that the predictors in the model were hand chosen for this reason, so it’s possible there are other variables that were not explored that could be even more important in modeling diabetes status.
# LASSO Logistic Regression

plot(logistic_mod$finalModel, xvar = "lambda", label = TRUE, col = rainbow(20))

rownames(logistic_mod$finalModel$beta) 
## [1] "Age"           "Gendermale"    "Weight"        "Height"       
## [5] "Pulse"         "TotChol"       "PhysActiveYes" "BPSysAve"
# Create a boolean matrix (predictors x lambdas) of variable exclusion
bool_predictor_exclude3 <- logistic_mod$finalModel$beta==0

# Loop over each variable
var_imp3 <- sapply(seq_len(nrow(bool_predictor_exclude3)), function(row) {
    # Extract coefficient path (sorted from highest to lowest lambda)
    this_coeff_path3 <- bool_predictor_exclude3[row,]
    # Compute and return the # of lambdas until this variable is out forever
    ncol(bool_predictor_exclude3)-which.min(this_coeff_path3)+1
})

# Create a dataset of this information and sort
var_imp_data3 <- tibble(
    var_name = rownames(bool_predictor_exclude3),
    var_imp3 = var_imp3
)

var_imp_data3 %>% arrange(desc(var_imp3))


  • Bagging/Random Forest Variable Importance:
    • To determine variable importance for this method, I computed cumulative mean decrease in impurity over all splits in the forest. This produces a neat, ranked list of variables that show which variables reduced impurity most over the tree making process. We understand the predictor that reduces impurity most as the most important. My random forest model estimates that weight and age (similar to the logistic model) are the most important predictors. Also similar to the first method discussed above, cholesterol, height, blood pressure, and pulse are predictors that reduced impurity in splits at fairly significant levels. This reinforces what we discerned from the logistic regression model and further solidifies our understanding that these predictors can be helpful in predicting diabetes status in our data. Interestingly, the order of importance is slightly different between the random forest and logistic regression models. This might be explained simply by standard error in the estimates or by the differing approaches in the two methods.
# Bagging and Random Forests 
var_imp_rf <- randomForest::importance(rf_mod$finalModel)

var_imp_rf <- data.frame(
        predictor = rownames(var_imp_rf),
        MeanDecreaseGini = var_imp_rf[,"MeanDecreaseGini"]
    ) %>%
    arrange(desc(MeanDecreaseGini))

head(var_imp_rf, 8)


Summary



Model Comparison:
Now having fit a range of different models, I can compare them to determine which of them is ‘best.’


Error Metrics and Accuracy: Below are error metrics and various accuracy estimates for each of the methods’ “best” model– the simplest model with the highest AUC.


  • LASSO Logistic Regression Model
logistic_mod$results %>%
    filter(lambda==logistic_mod$bestTune$lambda)


  • Bagging/Random Forest Model
rf_mod$results %>% 
  filter(mtry == 2)
rf_mod$finalModel
## 
## Call:
##  randomForest(x = x, y = y, ntree = 1000, mtry = min(param$mtry,      ncol(x))) 
##                Type of random forest: classification
##                      Number of trees: 1000
## No. of variables tried at each split: 2
## 
##         OOB estimate of  error rate: 4.65%
## Confusion matrix:
##       No Yes class.error
## No  6828  20 0.002920561
## Yes  330 343 0.490341753


Let’s compare the models to each other best we can.


The LASSO logistic model produced an AUC of .806 and the AUC SD is reported as .035. Other corresponding measures of accuracy from this model include the overall accuracy, sensitivity, and specificity. The overall accuracy is reported to be 91% and the sensitivity and specificity are .999 and .006 respectively. Sensitivity SD measures .0004 and and specificity SD is estimated to be .0007, so there is very little variation in estimates and not a major concern for us. It should be noted that sensitivity and specificity are likely switched here, please see the discussion above for details. Assuming that sensitivity and specificity are indeed switched here, we can see that this model does a very poor job of predicting those with diabetes. Even despite only being able to accurately predict those with diabetes less than 1% of the time, the overall accuracy of the model is fairly high. Why is this? I have reason to believe that this model is still so accurate because of the no-information rate of the data. The NIR is 91%, which is very high. This would imply that if the model were to simply predict the majority classifier (in this case non diabetic) every time, the model would still be accurate 91% of the time. This is exactly what we see in our overall accuracy measure above.


Now to turn to the bagging/random forest model, this model cannot be evaluated in the exact same ways but we can get an overall sense of accuracy. The best tune of the random forest model was able to predict cases’ diabetes status 95% of the time. Compared to the LASSO logistic model, the random forest model was much better at predicting when cases actually had diabetes. This is only by relative means though. The random forest model still has an out of bag error estimate of about 50% when it comes to predicting when a case actually does have diabetes. The model does a much better job of predicting when people aren’t diabetic, though. The model produced a out of bag error of less than 1% when it comes to predicting cases that are actually non-diabetic. The model has an overall out of bag error estimate of 4.65%. So, in a broad sense, this model is very accurate at predicting non-diabetic when a case really isn’t diabetic but it is only able to accurately predict diabetes for people who are actually diabetic about 50% of the time.



Overall Most Preferable Model:

After having compared the LASSO logistic regression and bagging/random forest model, I am able to make an informed decision about which of these models is more preferable. I can base this decision on accuracy metrics, interpretability of the estimates, and the usefulness of these models in context of the data. With these aspects in mind, it is clear to me that the random forest model is the more preferable of the two. The random forest model’s overall accuracy (95%) is higher than the LASSO logistic regression model (91%). The random forest model also produces better sensitivity and specificity measures than the logistic model. The logistic model particularly fails at making good predictions for people who are diabetic. While the random forest model is still fairly bad at doing the same thing (it only is accurate predicting diabetes among those who are actually diabetic ~50% of the time), but it is significantly better than the logistic model. In the context of the data, I believe it is more important for a predictive model to be able to identify when a disease is actually present than it is for the model to identify when a disease isn’t. What good is the model if it can only confirm that people aren’t diabetic? It might have some benefits, but when specificity is so high, I’d hope for sensitivity to also be high. So, this aspect weighed heavily in my mind in reasoning which model is preferable. One potential advantage that I had to overlook for the logistic model is its interpretability. The coefficient estimates produced by the logistic model are very easily interpreted, and this has benefits in explaining how certain variables are related to the odds of having diabetes. Nonetheless, the random forest model can be interpreted in broad strokes and its overall higher accuracy measures make it an obvious choice. While I don’t know for certain, I’d imagine that an overall accuracy of 95% for a predictive model in a clinical setting would be somewhat worthwhile. Obviously it’d be ideal to have that number higher, but considering the limited number of predictors I used, I’m somewhat satisfied with seeing this figure as high as it is. As discussed above, the no-information rate is fairly high for this particular classification task, and being above that figure in overall accuracy is a good threshold to have passed. See the readouts below to confirm the error estimates.

rf_mod$finalModel
## 
## Call:
##  randomForest(x = x, y = y, ntree = 1000, mtry = min(param$mtry,      ncol(x))) 
##                Type of random forest: classification
##                      Number of trees: 1000
## No. of variables tried at each split: 2
## 
##         OOB estimate of  error rate: 4.65%
## Confusion matrix:
##       No Yes class.error
## No  6828  20 0.002920561
## Yes  330 343 0.490341753


Societal Impact


When performing statistical research such as this, it’s important to recognize if any harms may come from your analyses and/or how the data was collected. I find it worth mentioning in this report a few things worth your consideration. Namely, while NHANES’ sample collection methods seem fairly rigorous, one key issue I have with it is the exclusion of institutionalized populations from the data. The absence of this population means that health phenomena specific to them isn’t reflected in this data. And because NHANES informs public policy and funding, these individuals’ needs will likely go to the wayside. I also feel it’s important to contextualize that this data is about a decade old and this analysis reflects on this snapshot in time, and it shouldn’t be extrapolated to today. These are just a few examples, and there are surely more implications that are worth expanding on in a different setting, but hopefully this makes you think a bit more critically about the implications of this analysis.

LS0tCnRpdGxlOiAnU1RBVCAyNTM6IEZpbmFsIFByb2plY3QnCmF1dGhvcjogIkdhYnJpZWwgUmV5bm9sZHMiCmRhdGU6ICI1LzMvMjAyMSIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OgogICAga2VlcF9tZDogVFJVRQogICAgdG9jOiBUUlVFCiAgICB0b2NfZmxvYXQ6IFRSVUUKICAgIGRmX3ByaW50OiBwYWdlZAogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBoaWRlIAogICAgdGhlbWU6IHlldGkKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBlcnJvcj1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSkKYGBgCgpgYGB7ciBMb2FkIERhdGEsIFBhY2thZ2VzLCBGdW5jdGlvbnN9CiMgTG9hZCBkYXRhLCByZXF1aXJlZCBwYWNrYWdlcywgYW5kIGZ1bmN0aW9ucwpsaWJyYXJ5KE5IQU5FUykKbGlicmFyeShjYXJldCkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHNwbGluZXMpCmxpYnJhcnkoYnJvb20pCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KHJhbmRvbUZvcmVzdCkKbGlicmFyeShycGFydC5wbG90KQpkYXRhKE5IQU5FUykKCgp0d29DbGFzc1N1bW1hcnlDdXN0b20gPC0gZnVuY3Rpb24gKGRhdGEsIGxldiA9IE5VTEwsIG1vZGVsID0gTlVMTCkgewogICAgaWYgKGxlbmd0aChsZXYpID4gMikgewogICAgICAgIHN0b3AocGFzdGUoIllvdXIgb3V0Y29tZSBoYXMiLCBsZW5ndGgobGV2KSwgImxldmVscy4gVGhlIHR3b0NsYXNzU3VtbWFyeSgpIGZ1bmN0aW9uIGlzbid0IGFwcHJvcHJpYXRlLiIpKQogICAgfQogICAgY2FyZXQ6OjpyZXF1aXJlTmFtZXNwYWNlUXVpZXRTdG9wKCJwUk9DIikKICAgIGlmICghYWxsKGxldmVscyhkYXRhWywgInByZWQiXSkgPT0gbGV2KSkgewogICAgICAgIHN0b3AoImxldmVscyBvZiBvYnNlcnZlZCBhbmQgcHJlZGljdGVkIGRhdGEgZG8gbm90IG1hdGNoIikKICAgIH0KICAgIHJvY09iamVjdCA8LSB0cnkocFJPQzo6cm9jKGRhdGEkb2JzLCBkYXRhWywgbGV2WzFdXSwgZGlyZWN0aW9uID0gIj4iLCAKICAgICAgICBxdWlldCA9IFRSVUUpLCBzaWxlbnQgPSBUUlVFKQogICAgcm9jQVVDIDwtIGlmIChpbmhlcml0cyhyb2NPYmplY3QsICJ0cnktZXJyb3IiKSkgCiAgICAgICAgTkEKICAgIGVsc2Ugcm9jT2JqZWN0JGF1YwogICAgb3V0IDwtIGMocm9jQVVDLCBzZW5zaXRpdml0eShkYXRhWywgInByZWQiXSwgZGF0YVssICJvYnMiXSwgCiAgICAgICAgbGV2WzFdKSwgc3BlY2lmaWNpdHkoZGF0YVssICJwcmVkIl0sIGRhdGFbLCAib2JzIl0sIGxldlsyXSkpCiAgICBvdXQyIDwtIHBvc3RSZXNhbXBsZShkYXRhWywgInByZWQiXSwgZGF0YVssICJvYnMiXSkKICAgIG91dCA8LSBjKG91dCwgb3V0MlsxXSkKICAgIG5hbWVzKG91dCkgPC0gYygiQVVDIiwgIlNlbnMiLCAiU3BlYyIsICJBY2N1cmFjeSIpCiAgICBvdXQKfQpgYGAKCmBgYHtyIERhdGEgQ2xlYW5pbmd9CiMgQW55IGNvZGUgdG8gY2xlYW4gdGhlIGRhdGEKdGVzdE5IQU5FUyA8LSBOSEFORVMgJT4lIAogIHNlbGVjdChBZ2UsIEdlbmRlciwgV2VpZ2h0LCBIZWlnaHQsIFB1bHNlLCBUb3RDaG9sLCBQaHlzQWN0aXZlLCBCUFN5c0F2ZSkgJT4lIAogIGZpbHRlcighaXMubmEoQWdlKSwgIWlzLm5hKEdlbmRlciksICFpcy5uYShXZWlnaHQpLCAhaXMubmEoSGVpZ2h0KSwgIWlzLm5hKFB1bHNlKSwgIWlzLm5hKFRvdENob2wpLCAhaXMubmEoUGh5c0FjdGl2ZSksICFpcy5uYShCUFN5c0F2ZSkpIAoKdGVzdE5IQU5FUzIgPC0gTkhBTkVTICU+JSAKICBzZWxlY3QoQWdlLCBHZW5kZXIsIFdlaWdodCwgSGVpZ2h0LCBQdWxzZSwgVG90Q2hvbCwgUGh5c0FjdGl2ZSwgQlBTeXNBdmUsIERpYWJldGVzKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShBZ2UpLCAhaXMubmEoR2VuZGVyKSwgIWlzLm5hKFdlaWdodCksICFpcy5uYShIZWlnaHQpLCAhaXMubmEoUHVsc2UpLCAhaXMubmEoVG90Q2hvbCksICFpcy5uYShQaHlzQWN0aXZlKSwgIWlzLm5hKEJQU3lzQXZlKSwgIWlzLm5hKERpYWJldGVzKSkgCmBgYAoKIyAqKkRhdGEgQ29udGV4dCoqCgpOSEFORVMgaXMgYW4gb2JzZXJ2YXRpb25hbCBzdHVkeSBmdW5kZWQgYW5kIGNvbmR1Y3RlZCBieSB0aGUgQ0RDLCBzcGVjaWZpY2FsbHkgaXRzIE5hdGlvbmFsIENlbnRlciBmb3IgSGVhbHRoIFN0YXRpc3RpY3MgKE5DSFMpIGJyYW5jaC4gVGhlIHN0dWR5LCB3aGljaCBiZWdhbiBpbiB0aGUgZWFybHkgMTk2MHMsIGlzIGFuIGFubnVhbCBzdXJ2ZXkgYWRtaW5pc3RlcmVkIHRvIGEgbmF0aW9uYWxseSByZXByZXNlbnRhdGl2ZSBzYW1wbGUgb2YgYWJvdXQgNSwwMDAgbm9uLWluc3RpdHV0aW9uYWxpemVkIHBlcnNvbnMgZnJvbSBhcm91bmQgdGhlIGNvdW50cnkuIFRvIGVuc3VyZSB0aGF0IGl0cyBzYW1wbGUgaXMgYXMgYWNjdXJhdGUgYXMgcG9zc2libGUsIE5IQU5FUyB1c2VzIGEgY29tcGxleCwgbXVsdGlzdGFnZSBwcm9iYWJpbGl0eSBzYW1wbGluZyBkZXNpZ24gdG8gc2VsZWN0IGEgY29ob3J0IHJlcHJlc2VudGF0aXZlIG9mIHRoZSBub24taW5zdGl0dXRpb25hbGl6ZWQgcG9wdWxhdGlvbiBvZiB0aGUgVVMuIEkgd2lsbCBvbmx5IGJlIGxvb2tpbmcgYXQgdGhlIE5IQU5FUyBkYXRhIHByb3ZpZGVkIGZvciB5ZWFycyBiZXR3ZWVuIDIwMDktMjAxMi4gSW4gYWRkaXRpb24gdG8gYmVpbmcgYXNrZWQgYSB2YXJpZXR5IG9mIHF1ZXN0aW9ucyBhYm91dCBkZW1vZ3JhcGhpYyBhbmQgc29jaW9lY29ub21pYyBpbmZvcm1hdGlvbiwgcGFydGljaXBhbnRzIHVuZGVyZ28gYSBoZWFsdGggaW50ZXJ2aWV3IGFuZCBleGFtaW5hdGlvbi4gVGhpcyBpbnZvbHZlcyB0YWtpbmcgaGVhbHRoIG1lYXN1cmVtZW50cyBpbiBhIHNwZWNpYWxseSBkZXNpZ25lZCBhbmQgZXF1aXBwZWQgbW9iaWxlIGNlbnRlciB0aGF0IHRyYXZlbHMgd2l0aCB0aGUgTkNIUyB0byBsb2NhdGlvbnMgdGhyb3VnaG91dCB0aGUgY291bnRyeS4gSW4gdG90YWwsIGluZm9ybWF0aW9uIGFib3V0IDc2IHVuaXF1ZSB2YXJpYWJsZXMgaXMgY29sbGVjdGVkIGJ5IGEgdGVhbSBvZiBwaHlzaWNpYW5zLCBtZWRpY2FsIHRlY2huaWNpYW5zLCBhbmQgZGlldGFyeS9oZWFsdGggaW50ZXJ2aWV3ZXJzIGFib3V0IGEgcmFuZ2Ugb2YgaGVhbHRoIGJpby1tYXJrZXJzIGFuZCBiZWhhdmlvcmFsIHRlbmRlbmNpZXMuIFRoZSBkYXRhIHRoYXQgaXMgY29sbGVjdGVkIGdpdmVzIHZhbHVhYmxlIGluc2lnaHQgaW50byB0aGUgZGlzdHJpYnV0aW9uIG9mIGhlYWx0aCBwcm9ibGVtcyBhbmQgcmlzayBmYWN0b3JzIGluIHRoZSBVLlMuIHBvcHVsYXRpb24uIFRoaXMgZ2l2ZXMgcmVzZWFyY2hlcnMgaW1wb3J0YW50IGNsdWVzIGFib3V0IHRoZSBjYXVzZXMgb2YgZGlzZWFzZSBhbmQgYWxsb3dzIHBvbGljeW1ha2VycyB0byBkZXRlY3QgdGhlIGV4dGVudCB0byB3aGljaCB2YXJpb3VzIGhlYWx0aCBwcm9ibGVtcyBoYXZlIGNoYW5nZWQgdGVtcG9yYWxseSBpbiB0aGUgVS5TLiBwb3B1bGF0aW9uIChDREMsIDIwMjApLgoKCiMgKipSZXNlYXJjaCBRdWVzdGlvbnMqKiAKCiogUmVncmVzc2lvbiBUYXNrOiAKICAgICsgSW4gdGhpcyByZXBvcnQsIEkgd2FudGVkIHRvIGFuc3dlciB0aGUgcXVlc3Rpb246IEhvdyB3ZWxsIGNhbiBhdmVyYWdlIHN5c3RvbGljIGJsb29kIHByZXNzdXJlIChtZWFzdXJlZCBpbiBtbSBIZykgYmUgcHJlZGljdGVkL21vZGVsZWQgYnkgYSByYW5nZSBvZiBvdGhlciBiaW9sb2dpY2FsLCBkZW1vZ3JhcGhpYywgYW5kIGhlYWx0aCBtYXJrZXJzIHN1Y2ggYXMgYWdlLCB3ZWlnaHQsIGNob2xlc3Rlcm9sLCBhbmQgb3RoZXJzPyAKCiogQ2xhc3NpZmljYXRpb24gVGFzazoKICAgICsgVGhlIHJlc2VhcmNoIHF1ZXN0aW9uIEkgYXR0ZW1wdGVkIHRvIGFkZHJlc3MgaW4gdGhpcyByZXBvcnQgdXNpbmcgY2xhc3NpZmljYXRpb24gbWV0aG9kcyB3YXMgY29uY2VybmVkIHdpdGggbW9kZWxpbmcgdGhlIGxpa2VsaWhvb2Qgb2YgYW5kIGluZGl2aWR1YWwgaGF2aW5nIGRpYWJldGVzLiBTcGVjaWZpY2FsbHksIEkgYXNrZWQ6IEhvdyB3ZWxsIGNhbiB2YXJpb3VzIGhlYWx0aCB2YXJpYWJsZXMgc3VjaCBhcyBhZ2UsIHdlaWdodCwgcGh5c2ljYWwgYWN0aXZpdHkgbGV2ZWxzLCBhbmQgb3RoZXJzIHByZWRpY3QgdGhlIGxpa2VsaWhvb2Qgb2YgYW4gaW5kaXZpZHVhbCB0byBoYXZlIGRpYWJldGVzPyAKICAgIAo8YnIgLz4gIAogIAojICoqUmVncmVzc2lvbiBBbmFseXNpcyoqIAoKPGJyIC8+CgojIyBNZXRob2RzCgojIyMgSW52ZXN0aWdhdGlvbiAxOiBJZ25vcmluZyBOb25saW5lYXJpdHkgCgo8YnIgLz4KCioqTW9kZWxzIFVzZWQ6KiogPGJyIC8+ClRvIGJlZ2luIGFkZHJlc3NpbmcgbXkgcmVncmVzc2lvbiByZXNlYXJjaCBxdWVzdGlvbnMsIEkgdXNlZCBtdWx0aXBsZSBkaWZmZXJlbnQgcmVncmVzc2lvbiBtb2RlbGluZyBtZXRob2RzIHRoYXQgZG8gbm90IGFjY291bnQgZm9yIGFueSBub25saW5lYXJpdHkgaW4gdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHByZWRpY3RvcnMgYW5kIHRoZSBvdXRjb21lLiBUaGUgZmlyc3QgbW9kZWwgSSBjcmVhdGVkIHVzZWQgdGhlIG9yZGluYXJ5IGxlYXN0IHNxdWFyZXMgcmVncmVzc2lvbiBtZXRob2QuIFRoZSBzZWNvbmQgbW9kZWwgSSBjcmVhdGVkIHVzZWQgc3Vic2V0IHNlbGVjdGlvbiBtZXRob2RzLiBTcGVjaWZpY2FsbHksIEkgdXNlZCB0aGUgYmFja3dhcmQgc3RlcHdpc2Ugc3Vic2V0IHNlbGVjdGlvbiBtZXRob2QuIFRoZSBmaW5hbCBtb2RlbCBJIGJ1aWx0IHVzZWQgTEFTU08gbGluZWFyIHJlZ3Jlc3Npb24gbWV0aG9kcy4gQ29sbGFwc2UgY29kZSB0byB2aWV3IGhvdyBJIGZpdCB0aGVzZSBtb2RlbHMuIAoKYGBge3IgUmVncmVzc2lvbiBNb2RlbCBGaXR0aW5nfQojIE9MUyBSZWdyZXNzaW9uCnNldC5zZWVkKDEyMykKT0xTX21vZDIgPC0gdHJhaW4oCiAgICBCUFN5c0F2ZSB+IC4sCiAgICBkYXRhID0gdGVzdE5IQU5FUywKICAgIG1ldGhvZCA9ICJsbSIsCiAgICB0ckNvbnRyb2wgPSB0cmFpbkNvbnRyb2wobWV0aG9kID0gImN2IiwgbnVtYmVyID0gOCwgc2VsZWN0aW9uRnVuY3Rpb24gPSAib25lU0UiKSwKICAgIG1ldHJpYyA9ICJNQUUiLAogICAgbmEuYWN0aW9uID0gbmEub21pdAopCiAgCiMgU3Vic2V0IFNlbGVjdGlvbiAoQmFja3dhcmQgU3RlcHdpc2UpCnNldC5zZWVkKDEyMykKCkJhY2t3YXJkX1N0ZXB3aXNlX21vZCA8LSB0cmFpbigKICAgIEJQU3lzQXZlIH4gLiwKICAgIGRhdGEgPSB0ZXN0TkhBTkVTLAogICAgbWV0aG9kID0gImxlYXBCYWNrd2FyZCIsCiAgICB0dW5lR3JpZCA9IGRhdGEuZnJhbWUobnZtYXggPSAxOjcpLAogICAgdHJDb250cm9sID0gdHJhaW5Db250cm9sKG1ldGhvZCA9ICJjdiIsIG51bWJlciA9IDgsIHNlbGVjdGlvbkZ1bmN0aW9uID0gIm9uZVNFIiksCiAgICBtZXRyaWMgPSAiTUFFIiwKICAgIG5hLmFjdGlvbiA9IG5hLm9taXQKKQoKIyBMQVNTTyAKc2V0LnNlZWQoMTIzKQoKTEFTU09fbW9kIDwtIHRyYWluKAogICAgQlBTeXNBdmUgfiAuLAogICAgZGF0YSA9IHRlc3ROSEFORVMsCiAgICBtZXRob2QgPSAiZ2xtbmV0IiwKICAgIHRyQ29udHJvbCA9IHRyYWluQ29udHJvbChtZXRob2QgPSAiY3YiLCBudW1iZXIgPSA4LCBzZWxlY3Rpb25GdW5jdGlvbiA9ICJvbmVTRSIpLAogICAgdHVuZUdyaWQgPSBkYXRhLmZyYW1lKGFscGhhID0gMSwgbGFtYmRhID0gc2VxKDAsIDEwLCBsZW5ndGgub3V0ID0gMTAwKSksCiAgICBtZXRyaWMgPSAiTUFFIiwKICAgIG5hLmFjdGlvbiA9IG5hLm9taXQKKQpgYGAKCiogKipPcmRpbmFyeSBMZWFzdCBTcXVhcmVzIFJlZ3Jlc3Npb24gRXZhbHVhdGlvbjoqKgogICAgKyBUbyBldmFsdWF0ZSB0aGUgT0xTIG1vZGVsLCBJIHByaW1hcmlseSByZWxpZWQgb24gcXVhbnRpdGF0aXZlIGV2YWx1YXRpb24gbWV0cmljcy4gU3BlY2lmaWNhbGx5LCBJIHVzZWQgbWVhbiBhYnNvbHV0ZSBlcnJvciAoTUFFKSB0byBlc3RpbWF0ZSB0ZXN0IHBlcmZvcm1hbmNlLiBUaGUgb3JkaW5hcnkgbGVhc3Qgc3F1YXJlcyByZWdyZXNzaW9uIG1vZGVsIHByb2R1Y2VkIHN5c3RvbGljIGJsb29kIHByZXNzdXJlIGVzdGltYXRlcyB0aGF0IHdlcmUsIG9uIGF2ZXJhZ2UsIG9mZiBieSAxMC44MDcgbW0gSGcgYW5kIGhhZCBhIHN0YW5kYXJkIGRldmlhdGlvbiBvZiAwLjI5OS4KCmBgYHtyfQojT0xTIEV2YWx1YXRpb24gCk9MU19tb2QyJHJlc3VsdHMKYGBgCgo8YnIgLz4KCiogKipCYWNrd2FyZCBTdGVwd2lzZSBTZWxlY3Rpb24gRXZhbHVhdGlvbjoqKiAKICAgICsgU2ltaWxhciB0byB0aGUgT0xTIG1vZGVsLCBJIHVzZWQgTUFFIGFzIG9uZSB3YXkgdG8gZXZhbHVhdGUgdGhlIHRoZSBzdWJzZXQgc2VsZWN0aW9uIG1vZGVsLiBCZWNhdXNlIHRoZSBzdWJzZXQgc2VsZWN0aW9uIG1ldGhvZCBhdHRlbXB0cyB0byBmaW5kIHdoaWNoIHN1YnNldCBvZiBwcmVkaWN0b3JzIHByb2R1Y2VzIHRoZSBiZXN0IG1vZGVsLCBNQUUgZXN0aW1hdGVzIGFyZSBwcm9kdWNlZCBmb3IgZXZlcnkgc3Vic2V0IHNpemUuIEkgdXNlZCBhIHBsb3QgY29tcGFyaW5nIHN1YnNldCBzaXplIGFuZCBNQUUgdG8gZ2V0IGFuIGluaXRpYWwgaWRlYSBvZiB3aGljaCBzdWJzZXQgcHJvZHVjZWQgdGhlIGxvd2VzdCBlcnJvci4gSSB0aGVuIGNvbmZpcm1lZCB0aGUgYmVzdCB0dW5lIGJ5IGxvb2tpbmcgYXQgdGhlIGNhcmV0IG1vZGVsIG91dHB1dCwgd2hpY2ggc2hvd2VkIHRoYXQgdGhlIGJlc3QgYmFja3dhcmQgc3RlcHdpc2Ugc2VsZWN0aW9uIG1vZGVsIHByb2R1Y2VkIHN5c3RvbGljIGJsb29kIHByZXNzdXJlIHByZWRpY3Rpb25zIHRoYXQgd2VyZSBvZmYgYnkgYWJvdXQgMTAuODU2IG1tIEhnIG9uIGF2ZXJhZ2UgYW5kIGhhZCBhIE1BRSBTRCBvZiAwLjI4Ni4gCgpgYGB7cn0KIyBTdWJzZXQgU2VsZWN0aW9uIEV2YWx1YXRpb24gCgpwbG90KEJhY2t3YXJkX1N0ZXB3aXNlX21vZCkKQmFja3dhcmRfU3RlcHdpc2VfbW9kJHJlc3VsdHMKbWVhbihCYWNrd2FyZF9TdGVwd2lzZV9tb2QkcmVzYW1wbGUkTUFFKQpgYGAKPGJyIC8+CgoqICoqTEFTU08gTGluZWFyIFJlZ3Jlc3Npb24gRXZhbHVhdGlvbjoqKiAKICAgICsgTEFTU08gbWV0aG9kcyBhbHNvIGZpdCBtYW55IG1vZGVscywgdGhvdWdoIHRoaXMgdGltZSBhdCBkaWZmZXJlbnQgdmFsdWVzIG9mIGxhbWJkYSAodGhlIHR1bmluZyBwYXJhbWV0ZXIpLiBUbyBiZWdpbiB0byBkZXRlcm1pbmUgd2hpY2ggdmFsdWUgb2YgbGFtYmRhIHByb2R1Y2VzIGEgbW9kZWwgd2l0aCB0aGUgbG93ZXN0IE1BRSwgSSBsb29rZWQgYXQgYSBwbG90IG9mIGxhbWJkYSB2cy4gTUFFLiBJIHRoZW4gY29uZmlybWVkIHRoZSBiZXN0IHR1bmUgYnkgbG9va2luZyBhdCB0aGUgY2FyZXQgbW9kZWwgb3V0cHV0LCB3aGljaCBzaG93ZWQgdGhhdCB0aGUgTEFTU08gbW9kZWwgd2l0aCB0aGUgbG93ZXN0IE1BRSBwcm9kdWNlZCBzeXN0b2xpYyBibG9vZCBwcmVzc3VyZSBlc3RpbWF0ZXMgdGhhdCB3ZXJlIG9mZiBieSBhYm91dCAxMC44OTkgbW0gSGcgb24gYXZlcmFnZSBhbmQgYSBNQUUgU0Qgb2YgMC4yODUuCgpgYGB7cn0KI0xBU1NPIEV2YWx1YXRpb24gCgpwbG90KExBU1NPX21vZCkKaGVhZChMQVNTT19tb2QkcmVzdWx0cywgOCkKTEFTU09fbW9kJGJlc3RUdW5lCmdncGxvdChMQVNTT19tb2QkcmVzdWx0cywgYWVzKHggPSBsYW1iZGEpKSArCiAgICBnZW9tX3BvaW50cmFuZ2UoYWVzKHkgPSBNQUUsIHltaW4gPSBNQUUtTUFFU0QsIHltYXggPSBNQUUrTUFFU0QpKSArCiAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMC41MDUsIGNvbG9yID0gInJlZCIpICsKICAgIGxhYnMoeCA9ICJsYW1iZGEiLCB5ID0gIk1BRSArLy0gMVNEIikKbWVhbihMQVNTT19tb2QkcmVzYW1wbGUkTUFFKQoKYGBgCgo8YnIgLz4KCkJ5IGNvbnNpZGVyaW5nIG11bHRpcGxlIG1ldGhvZHMgb2YgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWxpbmcsIEkgd2FzIGFibGUgdG8gYmVnaW4gZ2F0aGVyaW5nIGEgc2Vuc2Ugb2YgaG93IHdlbGwgbXkgdmFyaW91cyBwcmVkaWN0b3IgdmFyaWFibGVzIGFyZSBhYmxlIHRvIGFjdHVhbGx5IHByZWRpY3QgYmxvb2QgcHJlc3N1cmUuIEkgd2FzIGFsc28gYWJsZSB0byBzZWUgaWYgZGlmZmVyZW50IG1vZGVsaW5nIG1ldGhvZHMgcHJvZHVjZWQgZGlmZmVyZW50IHJlc3VsdHMgdGhhdCBjb3VsZCBiZSBpbXBvcnRhbnQgdG8gY29uc2lkZXIuIE5vbmUgb2YgdGhlc2UgbW9kZWxzIGNvbnNpZGVyZWQgcG90ZW50aWFsIG5vbi1saW5lYXIgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIHByZWRpY3RvcnMgYW5kIHRoZSBvdXRjb21lLCBzbyB0aGF0IGlzIHNvbWV0aGluZyBJIHR1cm4gdG8gbmV4dC4gCgoKIyMjIEludmVzdGlnYXRpb24gMjogQWNjb3VudGluZyBmb3IgTm9ubGluZWFyaXR5IAoKPGJyIC8+CgpUbyBjaGVjayB0byBzZWUgaWYgYW55IHF1YW50aXRhdGl2ZSBwcmVkaWN0b3JzIG1pZ2h0IGJlIGJldHRlciBtb2RlbGVkIHdpdGggbm9ubGluZWFyIHJlbGF0aW9uc2hpcHMsIEkgY29uc3RydWN0ZWQgcmVzaWR1YWwgcGxvdHMgdG8gZXZhbHVhdGUgdGhlaXIgcmVsYXRpb25zaGlwcy4gCgo8YnIgLz4KCkZvciBlYWNoIG9mIHRoZSBtb2RlbHMgSSBmaXQgYWJvdmUsIEkgY3JlYXRlZCByZXNpZHVhbCBwbG90cyBvZiBlYWNoIG9mIHRoZSBxdWFudGl0YXRpdmUgcHJlZGljdG9ycy4gVGhlIHZhcmlvdXMgc2V0cyBvZiBwbG90cyBzZWVuIGJlbG93IGNvbXBhcmUgdGhlc2UgZGlmZmVyZW50IHJlc2lkdWFsIHBsb3RzIHByb2R1Y2VkIGZyb20gdGhlIGRpZmZlcmVudCBtb2RlbHMgYWdhaW5zdCBlYWNoIG90aGVyLiBBbHNvIGluY2x1ZGVkIGluIHRoZSBzZXQgb2YgZ3JhcGhzIGlzIGEgcGxvdCBjb21wYXJpbmcgdGhlIHF1YW50aXRhdGl2ZSBwcmVkaWN0b3IgdG8gYmxvb2QgcHJlc3N1cmUgZnJvbSB0aGUgdHJhaW5pbmcgZGF0YS4gVGhlIGZpbmFsIHNldCBvZiBwbG90cyBpcyBhbiBvdmVyYWxsIHJlc2lkdWFsIHZzIHByZWRpY3RlZCBncmFwaCBmb3IgZWFjaCBvZiB0aGUgbW9kZWxzIEkgZml0IGluIGludmVzdGlnYXRpb24gMS4gICAKCmBgYHtyfQojIFJlc2lkdWFsIFBsb3QKCnNldC5zZWVkKDEyMykKCk9MU19tb2RfZGF0YSA8LSB0ZXN0TkhBTkVTICU+JSAKICBtdXRhdGUocHJlZCA9IHByZWRpY3QoT0xTX21vZDIsIG5ld2RhdGEgPSB0ZXN0TkhBTkVTKSwgCiAgICAgICAgIHJlc2lkID0gQlBTeXNBdmUgLSBwcmVkKQoKcDEgPC0gZ2dwbG90KE9MU19tb2RfZGF0YSwgYWVzKHggPSBBZ2UsIHkgPSByZXNpZCkpICsKICAgICAgZ2VvbV9wb2ludCgpICsKICAgICAgZ2VvbV9zbW9vdGgoKSArCiAgICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGNvbG9yID0gInJlZCIpCgpwMiA8LSBnZ3Bsb3QoT0xTX21vZF9kYXRhLCBhZXMoeCA9IFdlaWdodCwgeSA9IHJlc2lkKSkgKwogICAgICBnZW9tX3BvaW50KCkgKwogICAgICBnZW9tX3Ntb290aCgpICsKICAgICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3IgPSAicmVkIikKCnAzIDwtIGdncGxvdChPTFNfbW9kX2RhdGEsIGFlcyh4ID0gSGVpZ2h0LCB5ID0gcmVzaWQpKSArCiAgICAgIGdlb21fcG9pbnQoKSArCiAgICAgIGdlb21fc21vb3RoKCkgKwogICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICJyZWQiKQoKcDQgPC0gZ2dwbG90KE9MU19tb2RfZGF0YSwgYWVzKHggPSBQdWxzZSwgeSA9IHJlc2lkKSkgKwogICAgICBnZW9tX3BvaW50KCkgKwogICAgICBnZW9tX3Ntb290aCgpICsKICAgICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3IgPSAicmVkIikKCnA1IDwtIGdncGxvdChPTFNfbW9kX2RhdGEsIGFlcyh4ID0gVG90Q2hvbCwgeSA9IHJlc2lkKSkgKwogICAgICBnZW9tX3BvaW50KCkgKwogICAgICBnZW9tX3Ntb290aCgpICsKICAgICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3IgPSAicmVkIikKCnA2IDwtIGdncGxvdChPTFNfbW9kX2RhdGEsIGFlcyh4ID0gcHJlZCwgeSA9IHJlc2lkKSkgKwogICAgICBnZW9tX3BvaW50KCkgKwogICAgICBnZW9tX3Ntb290aCgpICsKICAgICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3IgPSAicmVkIikKCgpCYWNrd2FyZF9TdGVwd2lzZV9tb2RfZGF0YSA8LSB0ZXN0TkhBTkVTICU+JSAKICBtdXRhdGUocHJlZCA9IHByZWRpY3QoQmFja3dhcmRfU3RlcHdpc2VfbW9kLCBuZXdkYXRhID0gdGVzdE5IQU5FUyksIAogICAgICAgICByZXNpZCA9IEJQU3lzQXZlIC0gcHJlZCkKCnExIDwtIGdncGxvdChCYWNrd2FyZF9TdGVwd2lzZV9tb2RfZGF0YSwgYWVzKHggPSBBZ2UsIHkgPSByZXNpZCkpICsKICAgICAgZ2VvbV9wb2ludCgpICsKICAgICAgZ2VvbV9zbW9vdGgoKSArCiAgICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGNvbG9yID0gInJlZCIpCgpxMiA8LSBnZ3Bsb3QoQmFja3dhcmRfU3RlcHdpc2VfbW9kX2RhdGEsIGFlcyh4ID0gV2VpZ2h0LCB5ID0gcmVzaWQpKSArCiAgICAgIGdlb21fcG9pbnQoKSArCiAgICAgIGdlb21fc21vb3RoKCkgKwogICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICJyZWQiKQoKcTMgPC0gZ2dwbG90KEJhY2t3YXJkX1N0ZXB3aXNlX21vZF9kYXRhLCBhZXMoeCA9IEhlaWdodCwgeSA9IHJlc2lkKSkgKwogICAgICBnZW9tX3BvaW50KCkgKwogICAgICBnZW9tX3Ntb290aCgpICsKICAgICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3IgPSAicmVkIikKCnE0IDwtIGdncGxvdChCYWNrd2FyZF9TdGVwd2lzZV9tb2RfZGF0YSwgYWVzKHggPSBQdWxzZSwgeSA9IHJlc2lkKSkgKwogICAgICBnZW9tX3BvaW50KCkgKwogICAgICBnZW9tX3Ntb290aCgpICsKICAgICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3IgPSAicmVkIikKCnE1IDwtIGdncGxvdChCYWNrd2FyZF9TdGVwd2lzZV9tb2RfZGF0YSwgYWVzKHggPSBUb3RDaG9sLCB5ID0gcmVzaWQpKSArCiAgICAgIGdlb21fcG9pbnQoKSArCiAgICAgIGdlb21fc21vb3RoKCkgKwogICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICJyZWQiKQoKcTYgPC0gZ2dwbG90KEJhY2t3YXJkX1N0ZXB3aXNlX21vZF9kYXRhLCBhZXMoeCA9IHByZWQsIHkgPSByZXNpZCkpICsKICAgICAgZ2VvbV9wb2ludCgpICsKICAgICAgZ2VvbV9zbW9vdGgoKSArCiAgICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGNvbG9yID0gInJlZCIpCgoKTEFTU09fbW9kX2RhdGEgPC0gdGVzdE5IQU5FUyAlPiUgCiAgbXV0YXRlKHByZWQgPSBwcmVkaWN0KExBU1NPX21vZCwgbmV3ZGF0YSA9IHRlc3ROSEFORVMpLCAKICAgICAgICAgcmVzaWQgPSBCUFN5c0F2ZSAtIHByZWQpCgpyMSA8LSBnZ3Bsb3QoTEFTU09fbW9kX2RhdGEsIGFlcyh4ID0gQWdlLCB5ID0gcmVzaWQpKSArCiAgICAgIGdlb21fcG9pbnQoKSArCiAgICAgIGdlb21fc21vb3RoKCkgKwogICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICJyZWQiKQoKcjIgPC0gZ2dwbG90KExBU1NPX21vZF9kYXRhLCBhZXMoeCA9IFdlaWdodCwgeSA9IHJlc2lkKSkgKwogICAgICBnZW9tX3BvaW50KCkgKwogICAgICBnZW9tX3Ntb290aCgpICsKICAgICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3IgPSAicmVkIikKCnIzIDwtIGdncGxvdChMQVNTT19tb2RfZGF0YSwgYWVzKHggPSBIZWlnaHQsIHkgPSByZXNpZCkpICsKICAgICAgZ2VvbV9wb2ludCgpICsKICAgICAgZ2VvbV9zbW9vdGgoKSArCiAgICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGNvbG9yID0gInJlZCIpCgpyNCA8LSBnZ3Bsb3QoTEFTU09fbW9kX2RhdGEsIGFlcyh4ID0gUHVsc2UsIHkgPSByZXNpZCkpICsKICAgICAgZ2VvbV9wb2ludCgpICsKICAgICAgZ2VvbV9zbW9vdGgoKSArCiAgICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGNvbG9yID0gInJlZCIpCgpyNSA8LSBnZ3Bsb3QoTEFTU09fbW9kX2RhdGEsIGFlcyh4ID0gVG90Q2hvbCwgeSA9IHJlc2lkKSkgKwogICAgICBnZW9tX3BvaW50KCkgKwogICAgICBnZW9tX3Ntb290aCgpICsKICAgICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3IgPSAicmVkIikKCnI2IDwtIGdncGxvdChMQVNTT19tb2RfZGF0YSwgYWVzKHggPSBwcmVkLCB5ID0gcmVzaWQpKSArCiAgICAgIGdlb21fcG9pbnQoKSArCiAgICAgIGdlb21fc21vb3RoKCkgKwogICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICJyZWQiKQoKCnMxIDwtIHRlc3ROSEFORVMgJT4lIAogIGdncGxvdChhZXMoeCA9IEFnZSwgeSA9IEJQU3lzQXZlKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgoY29sb3IgPSAiYmx1ZSIsIHNlID0gRkFMU0UpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBjb2xvciA9ICJyZWQiLCBzZSA9IEZBTFNFKQoKczIgPC0gdGVzdE5IQU5FUyAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gV2VpZ2h0LCB5ID0gQlBTeXNBdmUpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aChjb2xvciA9ICJibHVlIiwgc2UgPSBGQUxTRSkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbG9yID0gInJlZCIsIHNlID0gRkFMU0UpCgpzMyA8LSB0ZXN0TkhBTkVTICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBIZWlnaHQsIHkgPSBCUFN5c0F2ZSkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKGNvbG9yID0gImJsdWUiLCBzZSA9IEZBTFNFKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sb3IgPSAicmVkIiwgc2UgPSBGQUxTRSkKCnM0IDwtIHRlc3ROSEFORVMgJT4lIAogIGdncGxvdChhZXMoeCA9IFB1bHNlLCB5ID0gQlBTeXNBdmUpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aChjb2xvciA9ICJibHVlIiwgc2UgPSBGQUxTRSkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbG9yID0gInJlZCIsIHNlID0gRkFMU0UpCgpzNSA8LSB0ZXN0TkhBTkVTICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBUb3RDaG9sLCB5ID0gQlBTeXNBdmUpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aChjb2xvciA9ICJibHVlIiwgc2UgPSBGQUxTRSkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbG9yID0gInJlZCIsIHNlID0gRkFMU0UpCmBgYAoKYGBge3IgR3JpZEV4dHJhfQpncmlkLmFycmFuZ2UocDEsIHExLCByMSwgczEsIG5yb3cgPSAyLCBuY29sID0gMikKCmdyaWQuYXJyYW5nZShwMiwgcTIsIHIyLCBzMiwgbnJvdyA9IDIsIG5jb2wgPSAyKQoKZ3JpZC5hcnJhbmdlKHAzLCBxMywgcjMsIHMzLCBucm93ID0gMiwgbmNvbCA9IDIpCgpncmlkLmFycmFuZ2UocDQsIHE0LCByNCwgczQsIG5yb3cgPSAyLCBuY29sID0gMikKCmdyaWQuYXJyYW5nZShwNSwgcTUsIHI1LCBzNSwgbnJvdyA9IDIsIG5jb2wgPSAyKQoKZ3JpZC5hcnJhbmdlKHA2LCBxNiwgcjYsIG5yb3cgPSAyLCBuY29sID0gMikKYGBgCgoKKiAqKlJlc2lkdWFsIFBsb3RzIEV2YWx1YXRpb246KiogCiAgICArIEJhc2VkIG9uIHRoZSByZXNpZHVhbCBwbG90cyBhYm92ZSwgaXQgc2VlbXMgYXMgaWYgbm9uZSBvZiB0aGUgcXVhbnRpdGF0aXZlIHByZWRpY3RvcnMgd291bGQgbmVjZXNzYXJpbHkgYmUgYmV0dGVyIG1vZGVsZWQgd2l0aCBub25saW5lYXIgcmVsYXRpb25zaGlwcy4gRWFjaCBvZiB0aGUgcmVzaWR1YWwgcGxvdHMgY3JlYXRlZCBhY3Jvc3MgdGhlIHRocmVlIG1vZGVscyBoYWQgbGluZXMgb2YgYmVzdCBmaXQgdGhhdCBmZWxsIHNtb290aGx5IGFsb25nIHRoZSB4LWF4aXMuIFRoaXMgc3VnZ2VzdHMgdGhhdCB0aGVzZSBxdWFudGl0YXRpdmUgcHJlZGljdG9ycyBoYXZlIGZhaXJseSBsaW5lYXIgcmVsYXRpb25zaGlwcyB3aXRoIGF2ZXJhZ2Ugc3lzdG9saWMgYmxvb2QgcHJlc3N1cmUgaW4gdGhpcyBkYXRhc2V0LiBUaGlzIGlzIGNvbmZpcm1lZCBieSBjcmVhdGluZyBwbG90cyBjb21wYXJpbmcgZWFjaCBvZiB0aGUgcXVhbnRpdGF0aXZlIHByZWRpY3RvcnMgdG8gdGhlIHF1YW50aXRhdGl2ZSBvdXRjb21lIHZhcmlhYmxlLS0gYXZlcmFnZSBzeXN0b2xpYyBibG9vZCBwcmVzc3VyZS4gV2UgY2FuIGNvbXBhcmUgdHdvIGJlc3QgZml0IGxpbmVzLCBvbmUgYXMgYSBsaW5lYXIgZml0IGFuZCB0aGUgb3RoZXIgYXMgYSBsb2NhbCByZWdyZXNzaW9uLCBmb3IgZWFjaCBvZiB0aGVzZSBwbG90cy4gV2hpbGUgdGhlcmUgaXMgc29tZSBub25saW5lYXJpdHksIHRoZSBsb2NhbCByZWdyZXNzaW9uIGxpbmUgb2YgYmVzdCBmaXQgc3RpbGwgZm9sbG93cyBmYWlybHkgY2xvc2VseSB0byB0aGUgbGluZWFyIHJlZ3Jlc3Npb24gbGluZS4KCjxiciAvPgo8YnIgLz4KCioqQ3JlYXRpbmcgTW9kZWxzIHdpdGggTmF0dXJhbCBTcGxpbmVzOioqIDxiciAvPiAKRXZlbiBpZiBpdCBzZWVtcyBsaWtlIG5vbmUgb2YgdGhlIHF1YW50aXRhdGl2ZSBwcmVkaWN0b3JzIHdvdWxkIG5lY2Vzc2FyaWx5IGJlIGJldHRlciBtb2RlbGVkIHdpdGggbm9ubGluZWFyIHJlbGF0aW9uc2hpcHMsIEkgY2FuIGNvbmZpcm0gbXkgYXNzdW1wdGlvbnMgYW5kIG1heWJlIGxlYXJuIG1vcmUgYnkgZml0dGluZyBuZXcsIHVwZGF0ZWQgbW9kZWxzIG9mIHRoZSBzdWJzZXQgc2VsZWN0aW9uIGFuZCBMQVNTTyBtZXRob2RzIHVzaW5nIG5hdHVyYWwgc3BsaW5lcy4gU2VlIGNvZGUgYmVsb3cgdG8gdmlldyB0aGUgZml0dGluZyBwcm9jZXNzLiAKCmBgYHtyfQojIFN0ZXB3aXNlIFNlbGVjdGlvbiAKc2V0LnNlZWQoMTIzKQoKTlNfQmFja3dhcmRfU3RlcHdpc2VfbW9kIDwtIHRyYWluKAogICAgQlBTeXNBdmUgfiBHZW5kZXIgKyBQaHlzQWN0aXZlICsgbnMoQWdlLCAzKSArIG5zKFdlaWdodCwgMykgKyBucyhIZWlnaHQsIDMpICsgbnMoUHVsc2UsIDMpICsgbnMoVG90Q2hvbCwgMyksCiAgICBkYXRhID0gdGVzdE5IQU5FUywKICAgIG1ldGhvZCA9ICJsZWFwQmFja3dhcmQiLAogICAgdHVuZUdyaWQgPSBkYXRhLmZyYW1lKG52bWF4ID0gMTo3KSwKICAgIHRyQ29udHJvbCA9IHRyYWluQ29udHJvbChtZXRob2QgPSAiY3YiLCBudW1iZXIgPSA4LCBzZWxlY3Rpb25GdW5jdGlvbiA9ICJvbmVTRSIpLAogICAgbWV0cmljID0gIk1BRSIsCiAgICBuYS5hY3Rpb24gPSBuYS5vbWl0CikKCgojIExBU1NPIApzZXQuc2VlZCgxMjMpCgpOU19MQVNTT19tb2QgPC0gdHJhaW4oCiAgICBCUFN5c0F2ZSB+IEdlbmRlciArIFBoeXNBY3RpdmUgKyBucyhBZ2UsIDMpICsgbnMoV2VpZ2h0LCAzKSArIG5zKEhlaWdodCwgMykgKyBucyhQdWxzZSwgMykgKyBucyhUb3RDaG9sLCAzKSwKICAgIGRhdGEgPSB0ZXN0TkhBTkVTLAogICAgbWV0aG9kID0gImdsbW5ldCIsCiAgICB0ckNvbnRyb2wgPSB0cmFpbkNvbnRyb2wobWV0aG9kID0gImN2IiwgbnVtYmVyID0gOCwgc2VsZWN0aW9uRnVuY3Rpb24gPSAib25lU0UiKSwKICAgIHR1bmVHcmlkID0gZGF0YS5mcmFtZShhbHBoYSA9IDEsIGxhbWJkYSA9IHNlcSgwLCAxMCwgbGVuZ3RoLm91dCA9IDEwMCkpLAogICAgbWV0cmljID0gIk1BRSIsCiAgICBuYS5hY3Rpb24gPSBuYS5vbWl0CikKCmBgYAo8YnIgLz4KCiogKipOYXR1cmFsIFNwbGluZSBCYWNrd2FyZCBTdGVwd2lzZSBTZWxlY3Rpb24gRXZhbHVhdGlvbjoqKiAKICAgICsgU2FtZSBhcyB0aGUgb3JpZ2luYWwgc3Vic2V0IHNlbGVjdGlvbiBwcm9jZXNzLCBJIGRldGVybWluZWQgd2hpY2ggc3Vic2V0IHNpemUgcHJvZHVjZWQgdGhlIGJlc3QgTUFFLiBUaGlzIG5hdHVyYWwgc3BsaW5lcyBzdWJzZXQgc2VsZWN0aW9uIG1vZGVsIGlkZW50aWZpZWQgdGhhdCBhIG1vZGVsIHdpdGggYSBzdWJzZXQgc2l6ZSBvZiA2IHdhcyBiZXN0IGFuZCBwcm9kdWNlZCBhdmVyYWdlIHN5c3RvbGljIGJsb29kIHByZXNzdXJlIGVzdGltYXRlcyB0aGF0IHdlcmUsIG9uIGF2ZXJhZ2UsIG9mZiBieSBhYm91dCAxMC43MjMgbW0gSGcgYW5kIGEgTUFFIFNEIG9mIDAuMjY3LiAKCmBgYHtyfQpOU19CYWNrd2FyZF9TdGVwd2lzZV9tb2QkYmVzdFR1bmUKTlNfQmFja3dhcmRfU3RlcHdpc2VfbW9kJHJlc3VsdHMKYGBgCjxiciAvPgoKKiAqKk5hdHVyYWwgU3BsaW5lIExBU1NPIEV2YWx1YXRpb246KiogCiAgICArIEp1c3QgbGlrZSB0aGUgb3RoZXIgbmF0dXJhbCBzcGxpbmVzIG1vZGVsLCBldmFsdWF0aW5nIHRoaXMgbWV0aG9kIHJlcXVpcmVkIGZpbmRpbmcgd2hpY2ggdmFsdWUgb2YgbGFtYmRhIHByb2R1Y2VkIGEgIG1vZGVsIGZpdCB3aXRoIHRoZSBsb3dlc3QgTUFFLiBUaGUgbW9kZWwgd2l0aCB0aGUgYmVzdCBsYW1iZGEgcHJvZHVjZWQgYXZlcmFnZSBzeXN0b2xpYyBibG9vZCBwcmVzc3VyZSBlc3RpbWF0ZXMgdGhhdCB3ZXJlLCBvbiBhdmVyYWdlLCBvZmYgYnkgYWJvdXQgMTAuNzU2IGFuZCBoYWQgYW4gTUFFIFNEIG9mIDAuMjUxLiAKCmBgYHtyfQpOU19MQVNTT19tb2QkYmVzdFR1bmUKaGVhZChOU19MQVNTT19tb2QkcmVzdWx0cykKZ2dwbG90KE5TX0xBU1NPX21vZCRyZXN1bHRzLCBhZXMoeCA9IGxhbWJkYSkpICsKICAgIGdlb21fcG9pbnRyYW5nZShhZXMoeSA9IE1BRSwgeW1pbiA9IE1BRS1NQUVTRCwgeW1heCA9IE1BRStNQUVTRCkpICsKICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLjQwNAksIGNvbG9yID0gInJlZCIpICsKICAgIGxhYnMoeCA9ICJsYW1iZGEiLCB5ID0gIk1BRSArLy0gMVNEIikKYGBgCgo8YnIgLz4KClRvIGdldCBhIGZ1cnRoZXIgc2Vuc2Ugb2Ygd2hldGhlciB0aGVyZSBpcyBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIG1vZGVscywgSSBjYW4gYWxzbyBjb25zaWRlciBob3cgdGhlIHZhcmlhYmxlIGltcG9ydGFuY2UgY29tcGFyZSBhbW9uZyB0aGVtLiAKCgo8YnIgLz4KCgojIyBWYXJpYWJsZSBJbXBvcnRhbmNlIAoKPGJyIC8+CgpGaXJzdCwgbGV0J3MgYWRkcmVzcyBqdXN0IHRoZSBtb2RlbHMgdGhhdCBkaWRuJ3QgY29uc2lkZXIgbm9ubGluZWFyaXR5LiAKCjxiciAvPgoKKiAqKkJhY2t3YXJkIFN0ZXB3aXNlIFN1YnNldCBTZWxlY3Rpb24gVmFyaWFibGUgSW1wb3J0YW5jZToqKiAKICAgICsgVGhlIGJhY2t3YXJkIHN0ZXB3aXNlIG1vZGVsIHNlbGVjdGVkIGEgbW9kZWwgd2l0aCB0aHJlZSB2YXJpYWJsZXMgYXMgdGhlIGJlc3QsIHNpbXBsZXN0IG1vZGVsLiBUaGUgZmlyc3QgdmFyaWFibGUgaWRlbnRpZmllZCBieSB0aGlzIG1ldGhvZCB3YXMgYWdlLCBmb2xsb3dlZCBieSBnZW5kZXIgKGEgY2F0ZWdvcmljYWwgcHJlZGljdG9yKSwgYW5kIHRoZSB0aGlyZCB3YXMgd2VpZ2h0LiBXZSBjb3VsZCBpbnRlcnByZXQgdGhpcyB0byBtZWFuIHRoYXQgdGhlc2UgdGhyZWUgdmFyaWFibGVzIGFyZSB0aGUgbW9zdCBpbXBvcnRhbnQsIGluIHRoYXQgb3JkZXIuIFRoZSBwbG90IGJlbG93ICBoZWxwcyB1cyBzZWUgdGhhdCB0aGUgbW9kZWwgd2l0aCBhIHN1YnNldCBzaXplIG9mIDMgaXMgdGhlIGJlc3QsIHNpbXBsZXN0IG1vZGVsLiBUaGUgY2FyZXQgcmVhZG91dCBiZWxvdyBzaG93cyB1cyB0aGUgb3JkZXIgaW4gd2hpY2ggdmFyaWFibGVzIHdlcmUgYWRkZWQsIGFuZCB3ZSBjYW4gaW50ZXJwcmV0IHRoaXMgYXMgYSBsZXZlbCBvZiBpbXBvcnRhbmNlLiAKCmBgYHtyfQojIFN0ZXB3aXNlIFZhcmlhYmxlIEltcG9ydGFuY2UgCgpwbG90KEJhY2t3YXJkX1N0ZXB3aXNlX21vZCkKc3VtbWFyeShCYWNrd2FyZF9TdGVwd2lzZV9tb2QpCmBgYAoKPGJyIC8+CgoqICoqTEFTU08gUmVncmVzc2lvbiBWYXJpYWJsZSBJbXBvcnRhbmNlOioqIAogICAgKyBUbyBnZXQgYSBzZW5zZSBvZiB2YXJpYWJsZSBpbXBvcnRhbmNlIGZvciB0aGUgTEFTU08gbWV0aG9kLCBJIGxvb2tlZCBhdCBhIHBsb3Qgb2YgaXRzIGNvZWZmaWNpZW50IHBhdGhzLiBWYXJpYWJsZXMgd2hvc2UgY29lZmZpY2llbnRzIHdlcmUgc2V0IHRvIDAgbGFzdCBjYW4gYmUgdmlld2VkIGFzIHRoZSBtb3N0IGltcG9ydGFudCBhcyB0aGV5IHdlcmUgYWJsZSB0byB3aXRoc3RhbmQgdGhlIGxhcmdlc3QgcGVuYWx0aWVzLiBUaGUgdGFibGUgYmVsb3cgcHJvdmlkZXMgYSBxdWFudGl0YXRpdmUgdmFsdWUgcmVsYXRpdmUgdG8gdGhlIGRpc3RhbmNlIHRyYXZlbGVkIGJ5IGVhY2ggY29lZmZpY2llbnQgYmVmb3JlIGJlaW5nIHNldCB0byAwLiBUaGUgb3JkZXIgaW4gd2hpY2ggdGhlIHZhcmlhYmxlIGFwcGVhcnMgb24gdGhlIGxpc3QgY29ycmVzcG9uZHMgdG8gaXRzIHJlbGF0aXZlIGltcG9ydGFuY2UuIFNpbWlsYXIgdG8gdGhlIHN0ZXB3aXNlIG1ldGhvZCwgYWdlIGNvdWxkIGJlIHZpZXdlZCBhcyB0aGUgbW9zdCBpbXBvcnRhbnQgcHJlZGljdG9yIGJlY2F1c2UgaXQgd2FzIHRoZSBsYXN0IHZhcmlhYmxlIHRvIGhhdmUgaXRzIGNvZWZmaWNpZW50IHNldCB0byAwLiBXZWlnaHQgd2FzIHRoZSBzZWNvbmQgdG8gbGFzdCB2YXJpYWJsZSB3aG9zZSBjb2VmZmljaWVudHMgd2VyZSBzZXQgdG8gMCBieSBsYW1iZGEsIGFuZCBnZW5kZXIgd2FzIHRoZSB0aGlyZCB0byBsYXN0LiBJIGhhdmUgZ29vZCByZWFzb24gdG8gYmVsaWV2ZSB0aGF0IHRoZXNlIGFyZSBpbmRlZWQgdGhlIHRocmVlIG1vc3QgaW1wb3J0YW50IHZhcmlhYmxlcyB0aGVuIGFzIGJvdGggbWV0aG9kcyBjb3Jyb2JvcmF0ZWQgdGhlIG90aGVycyBmaW5kaW5ncy4gCgpgYGB7cn0KIyBMQVNTTyBWYXJpYWJsZSBJbXBvcnRhbmNlIAoKcGxvdChMQVNTT19tb2QkZmluYWxNb2RlbCwgeHZhciA9ICJsYW1iZGEiLCBsYWJlbCA9IFRSVUUsIGNvbCA9IHJhaW5ib3coMjApKQoKIyBDcmVhdGUgYSBib29sZWFuIG1hdHJpeCAocHJlZGljdG9ycyB4IGxhbWJkYXMpIG9mIHZhcmlhYmxlIGV4Y2x1c2lvbgpib29sX3ByZWRpY3Rvcl9leGNsdWRlIDwtIExBU1NPX21vZCRmaW5hbE1vZGVsJGJldGE9PTAKCiMgTG9vcCBvdmVyIGVhY2ggdmFyaWFibGUKdmFyX2ltcCA8LSBzYXBwbHkoc2VxX2xlbihucm93KGJvb2xfcHJlZGljdG9yX2V4Y2x1ZGUpKSwgZnVuY3Rpb24ocm93KSB7CiAgICAjIEV4dHJhY3QgY29lZmZpY2llbnQgcGF0aCAoc29ydGVkIGZyb20gaGlnaGVzdCB0byBsb3dlc3QgbGFtYmRhKQogICAgdGhpc19jb2VmZl9wYXRoIDwtIGJvb2xfcHJlZGljdG9yX2V4Y2x1ZGVbcm93LF0KICAgICMgQ29tcHV0ZSBhbmQgcmV0dXJuIHRoZSAjIG9mIGxhbWJkYXMgdW50aWwgdGhpcyB2YXJpYWJsZSBpcyBvdXQgZm9yZXZlcgogICAgbmNvbChib29sX3ByZWRpY3Rvcl9leGNsdWRlKS13aGljaC5taW4odGhpc19jb2VmZl9wYXRoKSsxCn0pCgojIENyZWF0ZSBhIGRhdGFzZXQgb2YgdGhpcyBpbmZvcm1hdGlvbiBhbmQgc29ydAp2YXJfaW1wX2RhdGEgPC0gdGliYmxlKAogICAgdmFyX25hbWUgPSByb3duYW1lcyhib29sX3ByZWRpY3Rvcl9leGNsdWRlKSwKICAgIHZhcl9pbXAgPSB2YXJfaW1wCikKdmFyX2ltcF9kYXRhICU+JSBhcnJhbmdlKGRlc2ModmFyX2ltcCkpCmBgYAo8YnIgLz4KClRoZSB2YXJpYWJsZSBpbXBvcnRhbmNlIGFuYWx5c2VzIGZvciBib3RoIHRoZSBsaW5lYXIgc3RlcHdpc2UgYW5kIExBU1NPIG1ldGhvZHMgeWllbGRlZCBzaW1pbGFyIHJlc3VsdHMuIFdoaWxlIHRoZSB2YXJpYWJsZSBpbXBvcnRhbmNlIG9yZGVyIHdhcyBub3QgZXhhY3RseSB0aGUgc2FtZSBiZXR3ZWVuIHRoZSB0d28gbW9kZWxzLCB0aGV5IHN0aWxsIGFncmVlZCBhYm91dCB0aGUgdG9wIDMgYmVpbmcgdGhlIHNhbWUgYW5kIHRoZSBkaWZmZXJlbmNlIGlzIGxpa2VseSBuZWdsaWdpYmxlLiBUaGlzIGRpZG4ndCBzdXJwcmlzZSBtZSBncmVhdGx5IGFzIHRoZXNlIGFyZSBhbGwgYmlvbG9naWNhbCBpbmRpY2F0b3JzIHRoYXQgSSB3b3VsZCd2ZSBndWVzc2VkIHdpdGggbGl0dGxlIGJhY2tncm91bmQga25vd2xlZGdlLiBJIGNob3NlIHRoZXNlIHByZWRpY3RvciB2YXJpYWJsZXMgd2l0aCBibG9vZCBwcmVzc3VyZSBhbHJlYWR5IGluIG1pbmQsIGFuZCB0aGVzZSByZXN1bHRzIGNvbmZpcm0gbXkgaW5pdGlhbCBzdXNwaWNpb25zLiAKCjxiciAvPiAKCiogKipOYXR1cmFsIFNwbGluZXMgU3RlcHdpc2UgVmFyaWFibGUgSW1wb3J0YW5jZToqKiAKICAgICsgVGhlIGZpcnN0IG1vZGVsIEkgZml0IHdpdGggdGhlIHN0ZXB3aXNlIG1ldGhvZCB0aGF0IGRpZG4ndCBjb25zaWRlciBub25saW5lYXJpdHkgcHJvZHVjZWQgYSAnYmVzdCcgbW9kZWwgd2l0aCB0aHJlZSB2YXJpYWJsZXMuIFRoZSBiYWNrd2FyZCBzdGVwd2lzZSBtb2RlbCB0aGF0IGRpZCBjb25zaWRlciBub25saW5lYXJpdHksIGhvd2V2ZXIsIHByb2R1Y2VkIGEgJ2Jlc3QnIG1vZGVsIHRoYXQgaW5jbHVkZWQgNiB2YXJpYWJsZXMuIFZhcmlvdXMgdHJhbnNmb3JtYXRpb25zIG9mIGFnZSwgZ2VuZGVyLCBhbmQgd2VpZ2h0IGNvbnRpbnVlZCB0byBiZSBpZGVudGlmaWVkIGFzIHRoZSBtb3N0IGltcG9ydGFudCwgdGhvdWdoIHRoaXMgbmV3ZXIgbW9kZWwgYWxzbyBpZGVudGlmaWVkIGNob2xlc3Rlcm9sIGluIGl0cyBmaW5hbCBtb2RlbCBhcyB3ZWxsLiBJdCBzaG91bGQgYmUgbm90ZWQsIHRob3VnaCwgdGhhdCBjaG9sZXN0ZXJvbCBjb3VsZCBiZSB2aWV3ZWQgYXMgdGhlIGxlYXN0IGltcG9ydGFudCBwcmVkaWN0b3IgYW1vbmcgdGhvc2Ugc2VsZWN0ZWQgYnkgdGhlIG1vZGVsLiBZb3UgY2FuIHZpZXcgdGhlIHN1bW1hcnkgcmVhZG91dCBiZWxvdyB0byBzZWUgdGhlIGZ1bGwgc2VsZWN0aW9uIHByb2Nlc3MgYXMgaXQgcmVsYXRlcyB0byB2YXJpYWJsZSBpbXBvcnRhbmNlLiAKCmBgYHtyfQpwbG90KE5TX0JhY2t3YXJkX1N0ZXB3aXNlX21vZCkKc3VtbWFyeShOU19CYWNrd2FyZF9TdGVwd2lzZV9tb2QpCmBgYAoKPGJyIC8+IAoKKiAqKk5hdHVyYWwgU3BsaW5lcyBMQVNTTyBWYXJpYWJsZSBJbXBvcnRhbmNlOioqIAogICAgKyBUaGUgTEFTU08gbW9kZWwgY29uc2lkZXJpbmcgbm9ubGluZWFyaXR5IHNpbWlsYXJseSBwcm9kdWNlZCBhIGZpbmFsIG1vZGVsIHdpdGggbW9yZSBwcmVkaWN0b3JzIHRoYW4gdGhlIG9yaWdpbmFsIHRoYXQgZGlkbid0IGNvbnNpZGVyIG5vbmxpbmVhcml0eS4gVGhpcyBuZXcgbW9kZWwgaW5jbHVkZXMgYWdlLCBnZW5kZXIsIHdlaWdodCwgcHVsc2UsIGFuZCB0b3RhbCBjaG9sZXN0ZXJvbC4gSW4gdGVybXMgb2YgdmFyaWFibGUgaW1wb3J0YW5jZSwgdGhpcyBuZXcgTEFTU08gbW9kZWwgc2hha2VzIHRoaW5ncyB1cCBzb21lLiBBZ2UsIHdlaWdodCwgYW5kIGdlbmRlciBjb250aW51ZSB0byBiZSBhbW9uZyB0aGUgbW9zdCBpbXBvcnRhbnQsIHRob3VnaCB0aGlzIG5ldyBtb2RlbCBpZGVudGlmaWVzIHRvdGFsIGNob2xlc3Rlcm9sIGFzIGFsc28gYmVpbmcgYW1vbmcgdGhlIG1vc3QgaW1wb3J0YW50LiBUaGlzIHN1Z2dlc3RzIHRoYXQgY29uc2lkZXJpbmcgbm9ubGluZWFyaXR5IGZvciBjaG9sZXN0ZXJvbCBtaWdodCByZWR1Y2UgdGVzdCBlcnJvciBmb3IgdGhpcyBtb2RlbC4KCmBgYHtyfQpjb2VmKE5TX0xBU1NPX21vZCRmaW5hbE1vZGVsLCBOU19MQVNTT19tb2QkYmVzdFR1bmUkbGFtYmRhKQpwbG90KE5TX0xBU1NPX21vZCRmaW5hbE1vZGVsLCB4dmFyID0gImxhbWJkYSIsIGxhYmVsID0gVFJVRSwgY29sID0gcmFpbmJvdygyMCkpCgojIENyZWF0ZSBhIGJvb2xlYW4gbWF0cml4IChwcmVkaWN0b3JzIHggbGFtYmRhcykgb2YgdmFyaWFibGUgZXhjbHVzaW9uCmJvb2xfcHJlZGljdG9yX2V4Y2x1ZGUyIDwtIE5TX0xBU1NPX21vZCRmaW5hbE1vZGVsJGJldGE9PTAKCiMgTG9vcCBvdmVyIGVhY2ggdmFyaWFibGUKdmFyX2ltcDIgPC0gc2FwcGx5KHNlcV9sZW4obnJvdyhib29sX3ByZWRpY3Rvcl9leGNsdWRlMikpLCBmdW5jdGlvbihyb3cpIHsKICAgICMgRXh0cmFjdCBjb2VmZmljaWVudCBwYXRoIChzb3J0ZWQgZnJvbSBoaWdoZXN0IHRvIGxvd2VzdCBsYW1iZGEpCiAgICB0aGlzX2NvZWZmX3BhdGgyIDwtIGJvb2xfcHJlZGljdG9yX2V4Y2x1ZGUyW3JvdyxdCiAgICAjIENvbXB1dGUgYW5kIHJldHVybiB0aGUgIyBvZiBsYW1iZGFzIHVudGlsIHRoaXMgdmFyaWFibGUgaXMgb3V0IGZvcmV2ZXIKICAgIG5jb2woYm9vbF9wcmVkaWN0b3JfZXhjbHVkZTIpLXdoaWNoLm1pbih0aGlzX2NvZWZmX3BhdGgyKSsxCn0pCgojIENyZWF0ZSBhIGRhdGFzZXQgb2YgdGhpcyBpbmZvcm1hdGlvbiBhbmQgc29ydAp2YXJfaW1wX2RhdGEyIDwtIHRpYmJsZSgKICAgIHZhcl9uYW1lID0gcm93bmFtZXMoYm9vbF9wcmVkaWN0b3JfZXhjbHVkZSksCiAgICB2YXJfaW1wID0gdmFyX2ltcAopCnZhcl9pbXBfZGF0YTIgJT4lIGFycmFuZ2UoZGVzYyh2YXJfaW1wKSkKYGBgCgo8YnIgLz4KCgojIyBTdW1tYXJ5IAoKPGJyIC8+CgoqKkdBTSBMT0VTUyBNb2RlbCoqIDxiciAvPgpCeSBjYWxjdWxhdGluZyBhbmQgbm90aW5nIGFsbCBteSBtb2RlbHMnIHZhcmlhYmxlIGltcG9ydGFuY2UgdGh1cyBmYXIsIEkndmUgYmVlbiBhYmxlIHRvIHNlZSBhIHBhdHRlcm4gZW1lcmdlLiBUaHJlZSB2YXJpYWJsZXMgaW4gcGFydGljdWxhciBhcmUgcHJlc2VudCBhY3Jvc3MgYWxsIGxpbmVhciBhbmQgbm9ubGluZWFyIG1vZGVscy4gVGhlc2UgdGhyZWUgdmFyaWFibGVzIGFyZSBhZ2UsIHdlaWdodCwgYW5kIGdlbmRlci4gSSBjYW4gdXNlIHRoZXNlIHRocmVlIHBhcnRpY3VsYXIgdmFyaWFibGVzIHRvIGZpdCBhIEdBTSB1c2luZyBMT0VTUyB0ZXJtcyB0byBmdXJ0aGVyIGludmVzdGlnYXRlIGhvdyBvdGhlciBtb2RlbGluZyBtZXRob2RzIGltcHJvdmUgKG9yIGRvbid0IGltcHJvdmUpIHRlc3QgYWNjdXJhY3kuIEkgZml0IHRoaXMgbW9kZWwgYmVsb3csIHJlZmVyIHRvIHRoZSBjb2RlIHRvIHNlZSBzcGVjaWZpY3Mgb2YgdGhlIGZpdHRpbmcgcHJvY2Vzcy4KCjxiciAvPgoKYGBge3IsIHdhcm5pbmc9RkFMU0V9CiMgR0FNIExPRVNTCgpzZXQuc2VlZCgxMjMpCmdhbV9tb2QgPC0gdHJhaW4oCiAgICBCUFN5c0F2ZSB+IEFnZSArIFdlaWdodCArIEdlbmRlciwKICAgIGRhdGEgPSB0ZXN0TkhBTkVTLAogICAgbWV0aG9kID0gImdhbUxvZXNzIiwKICAgIHR1bmVHcmlkID0gZGF0YS5mcmFtZShkZWdyZWUgPSAxLCBzcGFuID0gc2VxKDAuMSwgMC45LCBieSA9IDAuMSkpLAogICAgdHJDb250cm9sID0gdHJhaW5Db250cm9sKG1ldGhvZCA9ICJjdiIsIG51bWJlciA9IDgsIHNlbGVjdGlvbkZ1bmN0aW9uID0gIm9uZVNFIiksCiAgICBtZXRyaWMgPSAiTUFFIiwKICAgIG5hLmFjdGlvbiA9IG5hLm9taXQKKQpgYGAKCgoqICoqR0FNIExPRVNTIE1vZGVsIEV2YWx1YXRpb246KiogCiAgICArIFRvIGV2YWx1YXRlIG15IExPRVNTIEdBTSwgSSBoYWQgdG8gZmlyc3QgaWRlbnRpZnkgd2hpY2ggc3BhbiBwcm9kdWNlZCB0aGUgbG93ZXN0IE1BRS4gSW4gdGhpcyBjYXNlLCB0aGUgYmVzdCBzcGFuIHdhcyAwLjEsIGFuZCB0aGUgYXZlcmFnZSBzeXN0b2xpYyBibG9vZCBwcmVzc3VyZSBlc3RpbWF0ZXMgcHJvZHVjZWQgYnkgdGhlIG1vZGVsIHdlcmUsIG9uIGF2ZXJhZ2UsIG9mZiBieSAxMC42NjYgbW0gSGcgYW5kIGhhZCBhbiBNQUUgU0Qgb2YgMC4yNDMuIFRoaXMgZXN0aW1hdGUgaXMgdmVyeSBjb21wYXJhYmxlIHRvIHRoZSBlc3RpbWF0ZXMgb2YgdGhlIG90aGVyIG1vZGVscyBmaXQgYWJvdmUuIFRoZSBlc3RpbWF0ZSBmdW5jdGlvbiBwbG90cyBvZiBlYWNoIHByZWRpY3RvciBiZWxvdyB0ZWxsIHVzIHNvbWUgbGltaXRlZCBpbmZvcm1hdGlvbjsgbWFpbmx5IHRoYXQgdGhlIHF1YW50aXRhdGl2ZSBwcmVkaWN0b3JzIGFyZSBtb3N0bHkgbGluZWFyLCB0aG91Z2ggdGhleSBtaWdodCBiZW5lZml0IGZyb20gYmVpbmcgZml0IGluIGEgbm9ubGluZWFyIHJlZ3Jlc3Npb24gbWV0aG9kIGFzIHdlbGwuIFRoaXMgTE9FU1MgR0FNIGNvcnJvYm9yYXRlcyB0aGUgY29uY2x1c2lvbnMgSSBkcmV3IGZyb20gdGhlIG90aGVyIG1vZGVscy4gV2UgY2FuIGZlZWwgc29tZSBjb25maWRlbmNlIGluIGFzc3VtaW5nIHRoYXQgd2l0aGluIHRoaXMgdHJhaW5pbmcgZGF0YSB3ZWlnaHQsIGdlbmRlciwgYW5kIGFnZSBhcmUgYWJsZSB0byBoZWxwIGV4cGxhaW4gc29tZSB2YXJpYW5jZSBpbiBhdmVyYWdlIHN5c3RvbGljIGJsb29kIHByZXNzdXJlLiAKICAgIAoKYGBge3J9CnBsb3QoZ2FtX21vZCkKZ2FtX21vZCRiZXN0VHVuZQpnYW1fbW9kJHJlc3VsdHMgJT4lCiAgICBmaWx0ZXIoc3Bhbj09Z2FtX21vZCRiZXN0VHVuZSRzcGFuKQoKcGFyKG1mcm93ID0gYygzLDQpKSAjIFNldHMgdXAgYSBncmlkIG9mIHBsb3RzCnBsb3QoZ2FtX21vZCRmaW5hbE1vZGVsLCBzZSA9IFRSVUUpICMgRGFzaGVkIGxpbmVzIGFyZSArLy0gMiBTRXMKYGBgCgo8YnIgLz4gCgoqKk1vZGVsIENvbXBhcmlzb246KiogPGJyIC8+IApOb3cgaGF2aW5nIGZpdCBhIHJhbmdlIG9mIGRpZmZlcmVudCBtb2RlbHMsIEkgY2FuIGNvbXBhcmUgdGhlbSB0byBkZXRlcm1pbmUgd2hpY2ggb2YgdGhlbSBpcyAnYmVzdCcuIAoKPGJyIC8+IAoKKipNQUUgYW5kIFVuY2VydGFpbnR5KiogPGJyIC8+IApCZWxvdyBhcmUgdGhlIE1BRSBhbmQgTUFFIFNEIGVzdGltYXRlcyBmb3IgZWFjaCBvZiB0aGUgbWV0aG9kcycgImJlc3QiIG1vZGVsLS0gdGhlIHNpbXBsZXN0IG1vZGVsIHdpdGggdGhlIGxvd2VzdCBNQUUuIAoKPGJyIC8+CgoqIE9yZGluYXJ5IExlYXN0IFNxdWFyZXMgCmBgYHtyfQpPTFNfbW9kMiRyZXN1bHRzCmBgYAo8YnIgLz4gCgoqIEJhY2t3YXJkIFN0ZXB3aXNlIFN1YnNldCBTZWxlY3Rpb24gCmBgYHtyfQpCYWNrd2FyZF9TdGVwd2lzZV9tb2QkcmVzdWx0cyAlPiUKICAgIGZpbHRlcihudm1heD09QmFja3dhcmRfU3RlcHdpc2VfbW9kJGJlc3RUdW5lJG52bWF4KQpgYGAKPGJyIC8+IAoKKiBMQVNTTyBMaW5lYXIgUmVncmVzc2lvbiAKYGBge3J9CkxBU1NPX21vZCRyZXN1bHRzICU+JSAKICBmaWx0ZXIobGFtYmRhID09IExBU1NPX21vZCRiZXN0VHVuZSRsYW1iZGEpCmBgYAo8YnIgLz4gCgoqIE5hdHVyYWwgU3BsaW5lcyBCYWNrd2FyZCBTdGVwd2lzZSBTdWJzZXQgU2VsZWN0aW9uIApgYGB7cn0KTlNfQmFja3dhcmRfU3RlcHdpc2VfbW9kJHJlc3VsdHMgJT4lIAogIGZpbHRlcihudm1heCA9PSBOU19CYWNrd2FyZF9TdGVwd2lzZV9tb2QkYmVzdFR1bmUkbnZtYXgpCmBgYAo8YnIgLz4gCgoqIE5hdHVyYWwgU3BsaW5lcyBMQVNTTyBSZWdyZXNzaW9uIApgYGB7cn0KTlNfTEFTU09fbW9kJHJlc3VsdHMgJT4lIAogIGZpbHRlcihsYW1iZGEgPT0gTlNfTEFTU09fbW9kJGJlc3RUdW5lJGxhbWJkYSkKYGBgCjxiciAvPiAKCiogTE9FU1MgR0FNCmBgYHtyfQpnYW1fbW9kJHJlc3VsdHMgJT4lIAogIGZpbHRlcihzcGFuID09IGdhbV9tb2QkYmVzdFR1bmUkc3BhbikKYGBgCjxiciAvPgoKV2UgY2FuIHNlZSBmcm9tIHRoZSByZWFkb3V0cyBhYm92ZSB0aGF0IGFjcm9zcyB0aGUgdmFyaW91cyBtb2RlbHMsIE1BRSByYW5nZXMgZnJvbSBhcyBsb3cgYXMgMTAuNjY2IHRvIGFzIGhpZ2ggYXMgMTAuODk5LiBUaGUgdW5jZXJ0YWludHkgYWNyb3NzIHRoZXNlIE1BRSBlc3RpbWF0ZXMgYXJlIGFsbCBmYWlybHkgY2xvc2UgdG8gZWFjaCBvdGhlciBhcyB3ZWxsLiBXaXRoIHRoYXQgaW4gbWluZCwgbm9uZSBvZiB0aGVzZSB0ZXN0IGVycm9yIGVzdGltYXRlcyBhcmUgYWxsIHRoYXQgZmFyIGF3YXkgZnJvbSBlYWNoIG90aGVyLiBNb3Jlb3ZlciwgaW4gdGhlIGNvbnRleHQgb2YgYXZlcmFnZSBzeXN0b2xpYyBibG9vZCBwcmVzc3VyZSwgYSBtYXRlciBvZiAwLjIgbW0gSGcgZGlmZmVyZW5jZSBhY3Jvc3MgbW9kZWxzIGlzIG5lZ2xpZ2libGUuIE92ZXJhbGwgdGhvdWdoLCBub25lIG9mIHRoZXNlIG1vZGVscyBzZWVtIHBhcnRpY3VsYXJseSB1c2VmdWwgaW4gYSBwcmFjdGljYWwgc2Vuc2UuIFN5c3RvbGljIGJsb29kIHByZXNzdXJlIHByZWRpY3Rpb25zIHRoYXQgYXJlIG9mZiwgb24gYXZlcmFnZSwgYnkgYWJvdXQgMTAgbW0gSGcgYXJlIG5vdCBhcyB1c2VmdWwgYXMgdGhleSBjb3VsZCBiZSBpbiBhIGNsaW5pY2FsIHNldHRpbmcuIEkgY2FuIGZlZWwgc29tZXdoYXQgY2VydGFpbiwgdGhvdWdoLCB0aGF0IGdpdmVuIHRoZSBwcmVkaWN0b3JzIEkgbG9va2VkIGF0LCB0aGUgZXN0aW1hdGVzIHdvbid0IGNoYW5nZSBzaWduaWZpY2FudGx5IGFjcm9zcyBkaWZmZXJlbnQgcmVncmVzc2lvbiBtZXRob2RzLiAgCgo8YnIgLz4gCgpXZSBzYXcgZnJvbSB0aGUgcmVzaWR1YWwgcGxvdHMgYWJvdmUgdGhhdCwgYWNyb3NzIGFsbCB0aGUgZGlmZmVyZW50IGxpbmVhciByZWdyZXNzaW9uIG1vZGVscywgdGhlIHRyZW5kIGxpbmVzIHNhdCBuaWNlbHkgYWxvbmcgdGhlIHgtYXhpcy4gVGhpcyBpbXBsaWVzIHRoYXQgbGluZWFyIHJlZ3Jlc3Npb24sIGFzIG9wcG9zZWQgdG8gYSBub24tbGluZWFyIG1ldGhvZCwgd2FzIGFuIGFwcHJvcHJpYXRlIGNob2ljZSBpbiBtb2RlbGluZyBtZXRob2QgYXMgdGhlcmUgYXJlIG5vIHN5c3RlbWF0aWMgYmlhc2VzIHByZXNlbnQgaW4gdGhlIHRyZW5kLiBTdGF0ZWQgZGlmZmVyZW50bHksIHdlIGNhbiBpbmZlciBmcm9tIHRoaXMgb2JzZXJ2ZWQgcGF0dGVybiB0aGF0IHRoZSBxdWFubnRpdGF0aXZlIHByZWRpY3RvcnMgcGxvdHRlZCBoYXZlIGZhaXJseSBsaW5lYXIgcmVsYXRpb25zaGlwcyB3aXRoIGF2ZXJhZ2Ugc3lzdG9saWMgYmxvb2QgcHJlc3N1cmUgaW4gdGhpcyBkYXRhc2V0LiBJIGZ1cnRoZXIgY29uZmlybWVkIHRoaXMgYnkgY3JlYXRpbmcgcGxvdHMgY29tcGFyaW5nIGVhY2ggb2YgdGhlIHF1YW50aXRhdGl2ZSBwcmVkaWN0b3JzIHRvIGF2ZXJhZ2Ugc3lzdG9saWMgYmxvb2QgcHJlc3N1cmUtLSB0aGVzZSB3ZXJlIHRoZSBib3R0b20gcmlnaHQgcGxvdHMgaW4gdGhlIHNlcmllcyBvZiBncmFwaHMuIEkgYWxzbyBjb21wYXJkZSB0d28gYmVzdCBmaXQgbGluZXMsIG9uZSBhcyBhIGxpbmVhciBmaXQgYW5kIHRoZSBvdGhlciBhcyBhIGxvY2FsIHJlZ3Jlc3Npb24sIGZvciBlYWNoIG9mIHRoZXNlIHBsb3RzLiBXaGlsZSB0aGVyZSBpcyBzb21lIG5vbmxpbmVhcml0eSwgdGhlIGxvY2FsIHJlZ3Jlc3Npb24gbGluZSBvZiBiZXN0IGZpdCBzdGlsbCBmb2xsb3dzIGZhaXJseSBjbG9zZWx5IHRvIHRoZSBsaW5lYXIgcmVncmVzc2lvbiBsaW5lLiBDdW11bGF0aXZlbHksIHRoaXMgc3VnZ2VzdHMgdG8gbWUgdGhhdCBsaW5lYXIgcmVncmVzc2lvbiBpcyBhIHN1aXRhYmxlIG9wdGlvbiBmb3IgdGhpcyByZWdyZXNzaW9uIHRhc2suIAoKPGJyIC8+IAoKQWNyb3NzIGFsbCB0aGUgbW9kZWxzIEkgZml0LCBJIHdhcyBhYmxlIHRvIGdldCBhIHNlbnNlIG9mIHdoaWNoIHZhcmlhYmxlcyB3ZXJlIG1vc3QgaW1wb3J0YW50IHRvIHRoZSBtb2RlbHMuIEFzIEkgZGlzY3Vzc2VkIGFib3ZlLCBtb3N0bHkgdGhlIHNhbWUgdmFyaWFibGVzIGFwcGVhcmVkIGF0IHRoZSB0b3Agb2YgdGhlIGxpc3QtLSBhZ2UsIHdlaWdodCwgYW5kIGdlbmRlci4gV2hpbGUgdGhlIG9yZGVyIG9mIHRoZXNlIHZhcmlhYmxlcyBzaGlmdGVkIHNsaWdodGx5IG9jY2FzaW9uYWxseSwgdGhlIGNvbnNpc3RlbmNlIHByZXNlbmNlIG9mIHRoZSBzYW1lIHByZWRpY3RvcnMgbWFkZSBtZSBmZWVsIGNvbmZpZGVudCB0aGF0IHRoZXNlIG1vZGVscyB3ZXJlIGZhaXJseSBzaW1pbGFyLiBDb250ZXh0dWFsbHksIHRoaXMgbWFrZXMgc2Vuc2UgYXMgYmlvbG9naWNhbCBzdHVkaWVzIGhhdmUgc3VnZ2VzdGVkIGNhdXNhbCByZWxhdGlvbnNoaXBzIGJldHdlZW4gYmxvb2QgcHJlc3N1cmUgYW5kIHRoZXNlIHByZWRpY3RvcnMuIEtub3dpbmcgdGhpcyBpcyB0aGUgY2FzZSBhbmQgc2VlaW5nIHRoYXQgZXN0aW1hdGVzIGFjcm9zcyBkaWZmZXJlbnQgbW9kZWxzIHdlcmUgZmFpcmx5IHNpbWlsYXIsIEknbSBhYmxlIHRvIHdlaWdoIHRoZSBiZW5lZml0cyBhbmQgZGlzYWR2YW50YWdlcyBvZiB0aGVzZSBtb2RlbHMgdG8gZGV0ZXJtaW5lIHdoaWNoIGlzIHRoZSBiZXN0LiAKCjxiciAvPiAKCgoqKk92ZXJhbGwgTW9zdCBQcmVmZXJhYmxlIE1vZGVsOioqIDxiciAvPiAKClRvIGRldGVybWluZSB0aGUg4oCYYmVzdOKAmSwgbW9zdCBwcmVmZXJhYmxlIG1vZGVsIEnigJl2ZSBjcmVhdGVkIHNvIGZhciwgSeKAmW0gZm9jdXNpbmcgbWFpbmx5IG9uIHN0cmlraW5nIGEgYmFsYW5jZSBiZXR3ZWVuIHByZWRpY3RpdmUgYWNjdXJhY3kgYW5kIGludGVycHJldGFiaWxpdHkuIFRoaW5raW5nIGZpcnN0IGFib3V0IHByZWRpY3RpdmUgYWNjdXJhY3ksIHRoZSBtb2RlbHMgSSBwcm9kdWNlZCBhbGwgaGFkIG1lYW4gYWJzb2x1dGUgZXJyb3JzIHRoYXQgd2VyZSBjbG9zZSB0byBlYWNoIG90aGVyLiBUaGVpciBlcnJvciBTRHMgd2VyZSBhbGwgZmFpcmx5IHVuaWZvcm0gYXMgd2VsbCwgc28gaXQgZG9lc24ndCBzZWVtIGFzIGlmIG9uZSBtb2RlbCBoYXMgbW9yZSB0aWdodGx5IGdyb3VwZWQvdmFyaWFibGUgZXN0aW1hdGVzIHRoYW4gYW5vdGhlci4gQmVjYXVzZSBvZiB0aGlzLCBJJ20gaW5jbGluZWQgdG8gYmVsaWV2ZSB0aGUgZGlmZmVyZW5jZXMgaW4gdGVzdCBlcnJvciBhcmUgbGlrZWx5IG5lZ2xpZ2libGUuIFdpdGggdGhpcyBpbiBtaW5kLCBJIHdvdWxkIGJlIG1vcmUgcGFydGlhbCB0b3dhcmRzIGEgbWV0aG9kIHRoYXQgaXMgc2ltcGxlIGFuZCBlYXN5IHRvIGludGVycHJldC4gU28gZGVzcGl0ZSB0aGUgTE9FU1MgR0FNIHByb2R1Y2luZyB0aGUgbG93ZXN0IE1BRSAoMTAuNjc3KSwgd2UgbG9zZSBhIGxvdCBvZiBpbnRlcnByZXRhYmlsaXR5IGFzIGEgcmVzdWx0LiBJIHRoaW5rIHNhY3JpZmljaW5nIGludGVycHJldGFiaWxpbHR5IGZvciBhIChjb250ZXh0dWFsbHkpIHZlcnkgc21hbGwgZGVjcmVhc2UgaW4gdGVzdCBlcnJvciBpcyBub3QgdmVyeSB3b3J0aHdoaWxlLiBGb3IgdGhpcyByZWFzb24gaW4gcGFydGljdWxhciwgSSB0aGluayB0aGUgYmFja3dhcmQgc3RlcHdpc2UgbW9kZWwgaXMgdGhlIGJlc3QsIG1vc3QgcHJlZmVyYWJsZSBtb2RlbCBvZiB0aGUgb25lcyBJIGNyZWF0ZWQuIEl0cyBmZXcgdmFyaWFibGVzIGNvbWJpbmVkIHdpdGggaXRzIGVhc3kgaW50ZXJwcmV0YXRpb24gbWFrZSBpdCBwYXJ0aWN1bGFybHkgYXBwZWFsaW5nLiBJdCBpcyBzbGlnaHRseSBsZXNzIGFjY3VyYXRlIHRoYW4gdGhlIG90aGVyIG1vZGVscyAoaXRzIHN5c3RvbGljIGJsb29kIHByZXNzdXJlIGVzdGltYXRlcyB3ZXJlIG9mZiwgb24gYXZlcmFnZSwgYnkgMTAuODU1IG1tIEhnIGFuZCB0aGUgTUFFIFNEIGlzIGVzdGltYXRlZCB0byBiZSAwLjI4NiksIGJ1dCBzdGlsbCBmYWxscyB3aXRoaW4gb25lIFNEIG9mIGFueSBvZiB0aGUgb3RoZXIgbW9kZWxz4oCZIHRlc3QgZXJyb3JzLiBJdCBhbHNvIGdpdmVzIGEgZmFpcmx5IGNsZWFyIHdheSBvZiB1bmRlcnN0YW5kaW5nIHZhcmlhYmxlIGltcG9ydGFuY2Ugd2hpY2ggY2FuIGJlIHVzZWZ1bCBpbiB0aGlua2luZyBhYm91dCBpbnRlcnByZXRhdGlvbnMuIFdlIGNhbiBzZWUgZnJvbSB0aGUgcmVzaWR1YWwgcGxvdHMgYmVsb3cgdGhhdCB0aGlzIG1vZGVsIGRvZXNuJ3QgaGF2ZSBhbnkgZ2xhcmluZyBzeXN0ZW1hdGljIGJpYXNlcyB0aGF0IGFyZW4ndCBiZWluZyBhZGRyZXNzZWQuIFRyZW5kIGxpbmVzIGZpdCBuaWNlbHkgYWxvbmcgdGhlIHgtYXhpcyBhbmQgcXVhbnRpdGF0aXZlIHByZWRpY3RvcnMgaGF2ZSBsaW5lYXIgcmVsYXRpb25zaGlwcyB3aXRoIGF2ZXJhZ2Ugc3lzdG9saWMgYmxvb2QgcHJlc3N1cmUuIE92ZXJhbGwsIHRoZSBtb2RlbCBwZXJmb3JtcyB3ZWxsIGFuZCBpdCBpcyBzaW1wbGUgYW5kIGludGVycHJldGFibGUtLSBqdXN0IHdoYXQgSSB3YW50ZWQuIAoKYGBge3J9CmdyaWQuYXJyYW5nZShxMSwgcTIsIHEzLCBxNCwgcTUsIHE2LCBucm93ID0gMywgbmNvbCA9IDIpCmBgYAogPGJyIC8+IAogPGJyIC8+CgojICoqQ2xhc3NpZmljYXRpb24gQW5hbHlzaXMqKiAKCjxiciAvPiAKCiMjIE1ldGhvZHMKCjxiciAvPiAKCioqTW9kZWxzIFVzZWQ6KiogPGJyIC8+IApJIGNyZWF0ZWQgdHdvIG1vZGVscyB1c2luZyB0d28gZGlmZmVyZW50IG1ldGhvZHMgdG8gYWRkcmVzcyBteSBjbGFzc2lmaWNhdGlvbiByZXNlYXJjaCBxdWVzdGlvbi4gVGhlIGZpcnN0IG1vZGVsIEkgY3JlYXRlZCB1c2VkIExBU1NPIGxvZ2lzdGljIHJlZ3Jlc3Npb24uIFRoZSBzZWNvbmQgbW9kZWwgSSBjcmVhdGVkIHVzZWQgcmFuZG9tIGZvcmVzdC9iYWdnaW5nIG1ldGhvZHMuIENvbGxhcHNlIHRoZSBjb2RlIHRvIHNlZSB0aGUgZml0dGluZyBwcm9jZXNzIGZvciBteSBMQVNTTyBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsLiAKCmBgYHtyfQojIExBU1NPIExvZ2lzdGljIFJlZ3Jlc3Npb24gCgpzZXQuc2VlZCgyNTMpCmxvZ2lzdGljX21vZCA8LSB0cmFpbigKICAgIERpYWJldGVzIH4gQWdlICsgR2VuZGVyICsgV2VpZ2h0ICsgSGVpZ2h0ICsgUHVsc2UgKyBUb3RDaG9sICsgUGh5c0FjdGl2ZSArIEJQU3lzQXZlLAogICAgZGF0YSA9IHRlc3ROSEFORVMyLAogICAgbWV0aG9kID0gImdsbW5ldCIsCiAgICBmYW1pbHkgPSAiYmlub21pYWwiLAogICAgdHVuZUdyaWQgPSBkYXRhLmZyYW1lKGFscGhhID0gMSwgbGFtYmRhID0gc2VxKDAsIC4xLCBsZW5ndGgub3V0ID0gMTAwKSksCiAgICB0ckNvbnRyb2wgPSB0cmFpbkNvbnRyb2wobWV0aG9kID0gImN2IiwgbnVtYmVyID0gMTAsIHNlbGVjdGlvbkZ1bmN0aW9uID0gIm9uZVNFIiwgY2xhc3NQcm9icyA9IFRSVUUsIHN1bW1hcnlGdW5jdGlvbiA9IHR3b0NsYXNzU3VtbWFyeUN1c3RvbSksCiAgICBtZXRyaWMgPSAiQVVDIiwKICAgIG5hLmFjdGlvbiA9IG5hLm9taXQKKQoKIyBCYWdnaW5nIGFuZCBSYW5kb20gRm9yZXN0cyAKc2V0LnNlZWQoMjUzKQpyZl9tb2QgPC0gdHJhaW4oCiAgICBEaWFiZXRlcyB+IEFnZSArIEdlbmRlciArIFdlaWdodCArIEhlaWdodCArIFB1bHNlICsgVG90Q2hvbCArIFBoeXNBY3RpdmUgKyBCUFN5c0F2ZSwKICAgIGRhdGEgPSB0ZXN0TkhBTkVTMiwKICAgIG1ldGhvZCA9ICJyZiIsCiAgICB0dW5lR3JpZCA9IGRhdGEuZnJhbWUobXRyeSA9IGMoMDo4KSksCiAgICB0ckNvbnRyb2wgPSB0cmFpbkNvbnRyb2wobWV0aG9kID0gIm9vYiIsIHNlbGVjdGlvbkZ1bmN0aW9uID0gImJlc3QiKSwKICAgIG1ldHJpYyA9ICJBVUMiLAogICAgbnRyZWUgPSAxMDAwLCAKICAgIG5hLmFjdGlvbiA9IG5hLm9taXQKKQpgYGAKCjxici8+CgoqICoqTEFTU08gTG9naXN0aWMgUmVncmVzc2lvbiBFdmFsdWF0aW9uOioqIDxici8+CiAgICArIFRvIGV2YWx1YXRlIHRoZSBMQVNTTyBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsLCBJIHV0aWxpemVkIGEgbnVtYmVyIG9mIHRlY2huaXF1ZXMuIFRvIGJlZ2luLCBJIGxvb2tlZCBhdCBhIHBsb3Qgb2YgbGFtYmRhIHZzIEFVQyB0byBnZXQgYSBzZW5zZSBvZiB3aGljaCBsYW1iZGEgcHJvZHVjZWQgdGhlIGJlc3QgbW9kZWwuIEkgY29uZmlybWVkIHRoaXMgYnkgY2hlY2tpbmcgdGhlIGNhcmV0IHJlc3VsdHMgYW5kIGZpbmFsIG1vZGVsIG91dHB1dHMgdG8gY29uZmlybSB3aGljaCB2YWx1ZSBvZiBsYW1iZGEgcHJvZHVjZWQgdGhlIG1vZGVsIHdpdGggdGhlIGhpZ2hlc3QgQVVDLiBUaGUgbGFtYmRhIHRoYXQgcHJvZHVjZWQgdGhlIGJlc3QsIG1vc3Qgc2ltcGxlIG1vZGVsIGhhZCBhbiBBVUMgb2YgMC44MDYuIEZyb20gdGhlcmUsIEkgY2hlY2tlZCB0aGUgYmVzdCBMQVNTTyBtb2RlbCdzIHNlbnNpdGl2aXR5LCBzcGVjaWZpY2l0eSwgb3ZlcmFsbCBhY2N1cmFjeSwgYW5kIGNvcnJlc3BvbmRpbmcgbWVhc3VyZXMgb2YgdW5jZXJ0YWludHkgZm9yIGFjY3VyYWN5IChTRHMpLiBUaGUgY2FyZXQgcmVhZG91dCByZXBvcnRzIHRoYXQgdGhlIGJlc3QgdHVuZSBtb2RlbCBoYXMgYSBzZW5zaXRpdml0eSBvZiAuOTk5LCBhIHNwZWNpZmljaXR5IG9mIC4wMDUsIGFuZCBhbiBvdmVyYWxsIGFjY3VyYWN5IG9mIDkxJS4gSW4gY29udGV4dCwgdGhpcyBtZWFucyB0aGF0IHRoZSBtb2RlbCBpcyBhYmxlIHRvIGFjY3VyYXRlbHkgcHJlZGljdCBzb21lb25lJ3MgZGlhYmV0ZXMgc3RhdHVzIGFib3V0IDkxJSBvZiB0aGUgdGltZS4gSSBhbHNvIGNhbGN1bGF0ZWQgdGhlIE5JUiBmb3IgdGhlIHRyYWluaW5nIGRhdGEgdG8gZnVydGhlciBjb250ZXh0dWFsaXplIG15IHJlc3VsdHMuIFRoZSBOSVIgaXMgOTElLCB3aGljaCBpcyB2ZXJ5IGhpZ2ggYW5kIHN1Z2dlc3RzIHRoYXQgdGhlIG1vZGVsIGNvdWxkIGRvIGZhaXJseSB3ZWxsIHNpbXBseSBieSBwcmVkaWN0aW5nIHNvbWVvbmUgaXNuJ3QgZGlhYmV0aWMgZXZlcnkgdGltZS4gUHJlZGljdGVkIHByb2JhYmlsaXR5IGJveHBsb3RzIHdlcmUgbWFkZSB0byBjb25maXJtIG1lYXN1cmVzIG9mIHNlbnNpdGl2aXR5IGFuZCBzcGVjaWZpY2l0eS0tIHNlZSBkaXNjdXNzaW9uIGJlbG93IGZvciBpc3N1ZXMgcmVsYXRpbmcgdG8gc3BlY2lmaWNpdHkgYW5kIHNlbnNpdGl2aXR5LiAKCmBgYHtyfQojIExhbWJkYSB2cy4gQVVDCnBsb3QobG9naXN0aWNfbW9kKQoKIyBCZXN0IFR1bmUgTWV0cmljcwpsb2dpc3RpY19tb2QkcmVzdWx0cyAlPiUKICAgIGZpbHRlcihsYW1iZGE9PWxvZ2lzdGljX21vZCRiZXN0VHVuZSRsYW1iZGEpICMgQVJFIFNFTlMgQU5EIFNQRUMgU1dJVENIRUQgSEVSRT8gCgojIE5JUiBNZXRyaWMKdGVzdE5IQU5FUzIgJT4lIAogIGNvdW50KERpYWJldGVzKQoKNjg0OC8oNjg0OCs2NzMpCgojIExBU1NPIExvZ2lzdGljIE1vZGVsIFByZWRpY3RlZCBQcm9iYWJpbGl0eSBCb3hwbG90cwpsYXNzb19sb2dpc3RpY19tb2RfZGF0YSA8LSB0ZXN0TkhBTkVTMiAlPiUKICAgIG11dGF0ZShwcm9iX3ByZWQgPSBwcmVkaWN0KGxvZ2lzdGljX21vZCwgbmV3ZGF0YSA9IHRlc3ROSEFORVMyLCB0eXBlID0gInByb2IiKSkKCmxhc3NvX2xvZ2lzdGljX21vZF9kYXRhICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBEaWFiZXRlcywgeSA9IHByb2JfcHJlZCRZZXMpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IC41LCBjb2xvciA9ICdyZWQnKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBsYWJzKHggPSAnRGlhYmV0ZXMgU3RhdHVzJywgeSA9ICdQcmVkaWN0ZWQgUHJvYmFiaWxpdHkgb2YgQmVpbmcgRGlhYmV0aWMgKERpYWJldGVzWWVzKScpCgoKIyBDaGVja2luZyBQcmVkaWN0aW9ucyAoc2VlIGNvbmZ1c2lvbiBtYXRyaXggYmVsb3cpCgpsYXNzb19sb2dpc3RpY19tb2RfZGF0YSAlPiUgCiAgbXV0YXRlKFByZWRpY3REaWFiZXRlc1llcyA9IHByb2JfcHJlZCRZZXMgPiAuNSkgJT4lICAjaWYgSSBjaGFuZ2UgdGhpcyB0byBwcm9iX3ByZWQkTm8gPiAuNSwgdGhlIHNlbnNpdGl2aXR5IGFuZCBzcGVjaWZpY2l0eSBtZWFzdXJlcyBtYXRjaCB0aGUgY2FyZXQgcmVzdWx0cyByZWFkb3V0LCBidXQgYXJlbid0IHdlIG1vZGVsaW5nIHRoZSBwcm9iYWJpbGl0eSBvZiBzb21lb25lIGhhdmluZyBkaWFiZXRlcyAod2hlbiB5PTEpPwogIGNvdW50KERpYWJldGVzLCBQcmVkaWN0RGlhYmV0ZXNZZXMpCgojIENvbmZpcm1pbmcgUHJlZGljdGlvbnMgd2l0aCBUcmFpbmluZyBMb2dpc3RpYyBNb2RlbCArIFByZWRpY3RlZCBQcm9iYWJpbGl0eSBCb3hwbG90cwp0cmFpbmluZ19sb2dpc3RpY19tb2QgPC0gdGVzdE5IQU5FUzIgJT4lIAogIHdpdGgoZ2xtKERpYWJldGVzIH4gQWdlICsgR2VuZGVyICsgV2VpZ2h0ICsgSGVpZ2h0ICsgUHVsc2UgKyBUb3RDaG9sICsgUGh5c0FjdGl2ZSArIEJQU3lzQXZlLCBmYW1pbHkgPSBiaW5vbWlhbCkpCgphdWdtZW50KHRyYWluaW5nX2xvZ2lzdGljX21vZCwgdHlwZS5wcmVkaWN0ID0gJ3Jlc3BvbnNlJykgJT4lCiAgZ2dwbG90KGFlcyh4ID0gZmFjdG9yKERpYWJldGVzKSwgeSA9IC5maXR0ZWQpKSArICNyZXBsYWNlIC4uLiB3aXRoIG91dGNvbWUgdmFyaWFibGUgbmFtZQogIGdlb21fYm94cGxvdCgpICsKICBsYWJzKHggPSAnRGlhYmV0aWMnLCB5ID0gJ1ByZWRpY3RlZCBQcm9iYWJpbGl0eSBvZiBPdXRjb21lJykgKyAKICB0aGVtZV9jbGFzc2ljKCkKCmxvZ2lzdGljX21vZF9kYXRhX2NvcHkgPC0gdGVzdE5IQU5FUzIgJT4lIAogIG11dGF0ZShwcmVkID0gcHJlZGljdChsb2dpc3RpY19tb2QsIG5ld2RhdGEgPSB0ZXN0TkhBTkVTMikpCmBgYApgYGAKQ29uZnVzaW9uIE1hdHJpeDogCgogICAgICAgICAgICAgQWN0dWFsICsgICAgQWN0dWFsIC0KUHJlZGljdCArICAgICAgIDQgKFRQKSAgICAgIDEgKEZQKQpQcmVkaWN0IC0gICAgICA2NjkgKEZOKSAgIDY4NDcgKFROKQoKYGBgCjxiciAvPiAKCioqTm90ZXMgb24gTEFTU08gTG9naXN0aWMgTW9kZWwgQWNjdXJhY3kgTWVhc3VyZXMqKgoKU2Vuc2l0aXZpdHkgPSBUUC8oVFAgKyBGTikgPSA0Lyg0ICsgNjY5KSA9IDAuMDA1OTQzNTM2CgpTcGVjaWZpY2l0eSA9IFROLyhUTiArIEZQKSA9IDY4NDcvKDY4NDcgKyAxKSA9IDAuOTk5ODU0CgpXZSBjYW4gc2VlIHRoYXQgdGhlIGNhbGN1bGF0aW9ucyBhYm92ZSAod2hpY2ggYXJlIGFkbWl0dGVkbHkgZnJvbSB0aGUgdHJhaW5pbmcgZGF0YSkgdGhhdCB0aGV5IGFyZSBzd2l0Y2hlZCBmcm9tIHdoYXQgaXMgcmVwb3J0ZWQgaW4gdGhlIGNhcmV0ICdyZXN1bHRzJyByZWFkb3V0LiBJZiBJIGNoYW5nZSBpdCBzbyB0aGF0IHdlIGFyZSBtb2RlbGluZyB0aGUgcHJvYmFiaWxpdHkgb2Ygc29tZW9uZSBub3QgaGF2aW5nIGRpYWJldGVzLCBhcyBvcHBvc2VkIHRvIHRoZSBvcHBvc2l0ZSwgdGhlIHNlbnNpdGl2aXR5IGFuZCBzcGVjaWZpY2l0eSB3b3VsZCBtYXRjaCB0aGUgY2FyZXQgcmVzdWx0cyByZWFkb3V0LiBFdmVuIGlmIHRoZSBtZWFzdXJlcyBhYm92ZSBhcmUgZnJvbSB0aGUgdHJhaW5pbmcgZGF0YSwgaXQgc3RpbGwgcHJvdmlkZXMgY29tcGVsbGluZyBldmlkZW5jZSB0aGF0IHRoZSBjYXJldCByZWFkb3V0IGlzIHN3aXRjaGVkIHNvIHlvdSBzaG91bGQga2VlcCB0aGF0IGluIG1pbmQuIAoKPGJyIC8+IAoKKiAqKkJhZ2dpbmcvUmFuZG9tIEZvcmVzdCBFdmFsdWF0aW9uOioqIAogICAgKyBUbyBldmFsdWF0ZSB0aGUgcmFuZG9tIGZvcmVzdCBtb2RlbCwgSSBwcm9kdWNlZCBhIHBsb3Qgb2YgdGhlIG51bWJlciBvZiByYW5kb21seSBzZWxlY3RlZCBwcmVkaWN0b3JzIHZzIHRoZSBPdXQgb2YgQmFnIEFjY3VyYWN5LiBJIHVzZWQgdGhlIGNhcmV0IHJlc3VsdHMgb3V0cHV0IHRvIGNvbmZpcm0gdGhpcyBpbmZvcm1hdGlvbi4gSSBsYXN0bHkgdXNlZCB0aGUgY2FyZXQgZmluYWwgbW9kZWwgb3V0cHV0IHRvIHRlbGwgbWUgdGhlIG9wdGltYWwgcmFuZG9tIG51bWJlciBvZiBwcmVkaWN0b3JzIHRvIHVzZSBiYXNlZCBvbiBlc3RpbWF0ZWQgT09CIGVycm9yIHJhdGVzLS0gaW4gdGhpcyBjYXNlIHRoZSBvcHRpbWFsIG51bWJlciBvZiByYW5kb20gdmFyaWFibGVzIHdhcyBvbmx5IDIgYW5kIHRoaXMgcHJvZHVjZWQgYW4gZXJyb3IgcmF0ZSBvZiA0LjY1JS4gVGhpcyBvdXRwdXQgYWxzbyBwcm92aWRlcyBhIG1hdHJpeCB0aGF0IGNhbiBiZSB1c2VkIHRvIGNhbGN1bGF0ZSBzZW5zaXRpdml0eSBhbmQgc3BlY2lmaWNpdHkuIFRoZSBjbGFzcyBlcnJvciBpcyBhc3NvY2lhdGVkIHdpdGggdGhlc2UgbWVhc3VyZXMuCiAgICAKYGBge3J9CiMgQmFnZ2luZyBhbmQgUmFuZG9tIEZvcmVzdHMgRXZhbHVhdGlvbiAKCiMgT09CIEFjY3VyYWN5IHZzLiBOby5SYW5kb21seSBTZWxlY3RlZCBQcmVkaWN0b3JzCnBsb3QocmZfbW9kKQoKIyBBY2N1cmFjeSBNZXRyaWNzCnJmX21vZCRyZXN1bHRzCnJmX21vZCRmaW5hbE1vZGVsCmBgYAoKPGJyIC8+IAoKVGhlc2UgdHdvIG1ldGhvZHMgd2VyZSB1c2VkIGFzIGEgd2F5IG9mIGdhdWdpbmcgd2hldGhlciB2YXJpYWJsZXMgSSBiZWxpZXZlZCB0byBiZSBwb3RlbnRpYWwgaW5kaWNhdG9ycyBvZiBkaWFiZXRlcyB3ZXJlIGFjdHVhbGx5IGdvb2QgcHJlZGljdG9ycy4gVGhlIGRpZmZlcmVudCBtZXRob2RzIGFsbG93ZWQgbWUgdG8gY29tZSBhdCB0aGlzIHF1ZXN0aW9uIGZyb20gc2xpZ2h0bHkgZGlmZmVyZW50IGFuZ2xlcyBhbmQgdWx0aW1hdGVseSBwcm9kdWNlZCBkaWZmZXJlbnQgcmVzdWx0cyBhcyB3aWxsIGJlIGRpc2N1c3NlZCBiZWxvdy4gCgo8YnIgLz4gCgojIyBWYXJpYWJsZSBJbXBvcnRhbmNlIAoKPGJyIC8+IAoKKiAqKkxBU1NPIExvZ2lzdGljIFJlZ3Jlc3Npb24gVmFyaWFibGUgSW1wb3J0YW5jZToqKiAKICAgICsgSSB1c2VkIGNvZWZmaWNpZW50IHBhdGggcGxvdHMgdG8gc2hvdyBob3cgcXVpY2tseSB0aGUgdmFyaW91cyBwcmVkaWN0b3JzIGFyZSBzZXQgdG8gMCBieSBsYW1iZGEgYXQgZGlmZmVyaW5nIHJhdGVzLiBJIHVuZGVyc3Rvb2QgdGhlIHByZWRpY3RvcnMgd2hvIHRvb2sgdGhlIGxvbmdlc3QgdG8gYmUgc2V0IHRvIDAgYXMgYmVpbmcgdGhlIG1vc3QgaW1wb3J0YW50IGluIHRlcm1zIG9mIGl0cyBwcmVkaWN0aXZlIHBvd2VyLiBUaGlzIHdhcyBjb25maXJtZWQgYnkgY29tcHV0aW5nIHRoZSBkaXN0YW5jZXMgdHJhdmVsZWQgYnkgdGhlIHZhcmlvdXMgcHJlZGljdG9ycyBiZWZvcmUgYmVpbmcgc2V0IHRvIDAuIEZyb20gdGhlIGxpc3QgdGhhdCB3YXMgcHJvZHVjZWQsIHdlIGNhbiBzZWUgdGhhdCBhZ2UgYW5kIHdlaWdodCB3ZXJlIHR3byBvZiB0aGUgbW9zdCBpbXBvcnRhbnQgcHJlZGljdG9ycyBpbiB0aGUgbW9kZWwuIENob2xlc3Rlcm9sLCBibG9vZCBwcmVzc3VyZSwgaGVpZ2h0LCBhbmQgcHVsc2Ugd2VyZSBhbHNvIGZhaXJseSBzaW1pbGFybHkgcmFua2VkIGluIGltcG9ydGFuY2UuIFRoaXMgZG9lcyBtYWtlIHNlbnNlIHRvIG1lIGluIHRoZSBjb250ZXh0IG9mIHRoZSBkYXRhIGFuZCB0aGUgY2xhc3NpZmljYXRpb24gcXVlc3Rpb25zLiBJIHRoaW5rIG1hbnkgcGVvcGxlIHRoaW5rIG9mIHdlaWdodCBhcyBiZWluZyB0aGUgcHJpbWFyeSBpbmRpY2F0b3Igb2YgZGlhYmV0ZXMgc3RhdHVzLCBhbmQgdGhlIG90aGVyIHByZWRpY3RvcnMgb2Z0ZW4gaGF2ZSBhc3NvY2lhdGVkIGNoYW5nZXMgd2l0aCByZWdhcmRzIHRvIHdlaWdodC4gSXQgc2hvdWxkIGJlIG5vdGVkIHRoYXQgdGhlIHByZWRpY3RvcnMgaW4gdGhlIG1vZGVsIHdlcmUgaGFuZCBjaG9zZW4gZm9yIHRoaXMgcmVhc29uLCBzbyBpdCdzIHBvc3NpYmxlIHRoZXJlIGFyZSBvdGhlciB2YXJpYWJsZXMgdGhhdCB3ZXJlIG5vdCBleHBsb3JlZCB0aGF0IGNvdWxkIGJlIGV2ZW4gbW9yZSBpbXBvcnRhbnQgaW4gbW9kZWxpbmcgZGlhYmV0ZXMgc3RhdHVzLiAKICAgIApgYGB7cn0KIyBMQVNTTyBMb2dpc3RpYyBSZWdyZXNzaW9uCgpwbG90KGxvZ2lzdGljX21vZCRmaW5hbE1vZGVsLCB4dmFyID0gImxhbWJkYSIsIGxhYmVsID0gVFJVRSwgY29sID0gcmFpbmJvdygyMCkpCnJvd25hbWVzKGxvZ2lzdGljX21vZCRmaW5hbE1vZGVsJGJldGEpIAoKIyBDcmVhdGUgYSBib29sZWFuIG1hdHJpeCAocHJlZGljdG9ycyB4IGxhbWJkYXMpIG9mIHZhcmlhYmxlIGV4Y2x1c2lvbgpib29sX3ByZWRpY3Rvcl9leGNsdWRlMyA8LSBsb2dpc3RpY19tb2QkZmluYWxNb2RlbCRiZXRhPT0wCgojIExvb3Agb3ZlciBlYWNoIHZhcmlhYmxlCnZhcl9pbXAzIDwtIHNhcHBseShzZXFfbGVuKG5yb3coYm9vbF9wcmVkaWN0b3JfZXhjbHVkZTMpKSwgZnVuY3Rpb24ocm93KSB7CiAgICAjIEV4dHJhY3QgY29lZmZpY2llbnQgcGF0aCAoc29ydGVkIGZyb20gaGlnaGVzdCB0byBsb3dlc3QgbGFtYmRhKQogICAgdGhpc19jb2VmZl9wYXRoMyA8LSBib29sX3ByZWRpY3Rvcl9leGNsdWRlM1tyb3csXQogICAgIyBDb21wdXRlIGFuZCByZXR1cm4gdGhlICMgb2YgbGFtYmRhcyB1bnRpbCB0aGlzIHZhcmlhYmxlIGlzIG91dCBmb3JldmVyCiAgICBuY29sKGJvb2xfcHJlZGljdG9yX2V4Y2x1ZGUzKS13aGljaC5taW4odGhpc19jb2VmZl9wYXRoMykrMQp9KQoKIyBDcmVhdGUgYSBkYXRhc2V0IG9mIHRoaXMgaW5mb3JtYXRpb24gYW5kIHNvcnQKdmFyX2ltcF9kYXRhMyA8LSB0aWJibGUoCiAgICB2YXJfbmFtZSA9IHJvd25hbWVzKGJvb2xfcHJlZGljdG9yX2V4Y2x1ZGUzKSwKICAgIHZhcl9pbXAzID0gdmFyX2ltcDMKKQoKdmFyX2ltcF9kYXRhMyAlPiUgYXJyYW5nZShkZXNjKHZhcl9pbXAzKSkKYGBgCgo8YnIgLz4gCgoqICoqQmFnZ2luZy9SYW5kb20gRm9yZXN0IFZhcmlhYmxlIEltcG9ydGFuY2U6KiogCiAgICArIFRvIGRldGVybWluZSB2YXJpYWJsZSBpbXBvcnRhbmNlIGZvciB0aGlzIG1ldGhvZCwgSSBjb21wdXRlZCBjdW11bGF0aXZlIG1lYW4gZGVjcmVhc2UgaW4gaW1wdXJpdHkgb3ZlciBhbGwgc3BsaXRzIGluIHRoZSBmb3Jlc3QuIFRoaXMgcHJvZHVjZXMgYSBuZWF0LCByYW5rZWQgbGlzdCBvZiB2YXJpYWJsZXMgdGhhdCBzaG93IHdoaWNoIHZhcmlhYmxlcyByZWR1Y2VkIGltcHVyaXR5IG1vc3Qgb3ZlciB0aGUgdHJlZSBtYWtpbmcgcHJvY2Vzcy4gV2UgdW5kZXJzdGFuZCB0aGUgcHJlZGljdG9yIHRoYXQgcmVkdWNlcyBpbXB1cml0eSBtb3N0IGFzIHRoZSBtb3N0IGltcG9ydGFudC4gTXkgcmFuZG9tIGZvcmVzdCBtb2RlbCBlc3RpbWF0ZXMgdGhhdCB3ZWlnaHQgYW5kIGFnZSAoc2ltaWxhciB0byB0aGUgbG9naXN0aWMgbW9kZWwpIGFyZSB0aGUgbW9zdCBpbXBvcnRhbnQgcHJlZGljdG9ycy4gQWxzbyBzaW1pbGFyIHRvIHRoZSBmaXJzdCBtZXRob2QgZGlzY3Vzc2VkIGFib3ZlLCBjaG9sZXN0ZXJvbCwgaGVpZ2h0LCBibG9vZCBwcmVzc3VyZSwgYW5kIHB1bHNlIGFyZSBwcmVkaWN0b3JzIHRoYXQgcmVkdWNlZCBpbXB1cml0eSBpbiBzcGxpdHMgYXQgZmFpcmx5IHNpZ25pZmljYW50IGxldmVscy4gVGhpcyByZWluZm9yY2VzIHdoYXQgd2UgZGlzY2VybmVkIGZyb20gdGhlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwgYW5kIGZ1cnRoZXIgc29saWRpZmllcyBvdXIgdW5kZXJzdGFuZGluZyB0aGF0IHRoZXNlIHByZWRpY3RvcnMgY2FuIGJlIGhlbHBmdWwgaW4gcHJlZGljdGluZyBkaWFiZXRlcyBzdGF0dXMgaW4gb3VyIGRhdGEuIEludGVyZXN0aW5nbHksIHRoZSBvcmRlciBvZiBpbXBvcnRhbmNlIGlzIHNsaWdodGx5IGRpZmZlcmVudCBiZXR3ZWVuIHRoZSByYW5kb20gZm9yZXN0IGFuZCBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVscy4gVGhpcyBtaWdodCBiZSBleHBsYWluZWQgc2ltcGx5IGJ5IHN0YW5kYXJkIGVycm9yIGluIHRoZSBlc3RpbWF0ZXMgb3IgYnkgdGhlIGRpZmZlcmluZyBhcHByb2FjaGVzIGluIHRoZSB0d28gbWV0aG9kcy4KICAgIApgYGB7cn0KIyBCYWdnaW5nIGFuZCBSYW5kb20gRm9yZXN0cyAKdmFyX2ltcF9yZiA8LSByYW5kb21Gb3Jlc3Q6OmltcG9ydGFuY2UocmZfbW9kJGZpbmFsTW9kZWwpCgp2YXJfaW1wX3JmIDwtIGRhdGEuZnJhbWUoCiAgICAgICAgcHJlZGljdG9yID0gcm93bmFtZXModmFyX2ltcF9yZiksCiAgICAgICAgTWVhbkRlY3JlYXNlR2luaSA9IHZhcl9pbXBfcmZbLCJNZWFuRGVjcmVhc2VHaW5pIl0KICAgICkgJT4lCiAgICBhcnJhbmdlKGRlc2MoTWVhbkRlY3JlYXNlR2luaSkpCgpoZWFkKHZhcl9pbXBfcmYsIDgpCmBgYAoKPGJyIC8+IAoKIyMgU3VtbWFyeSAKCjxiciAvPgo8YnIgLz4KCioqTW9kZWwgQ29tcGFyaXNvbjoqKiA8YnIgLz4gCk5vdyBoYXZpbmcgZml0IGEgcmFuZ2Ugb2YgZGlmZmVyZW50IG1vZGVscywgSSBjYW4gY29tcGFyZSB0aGVtIHRvIGRldGVybWluZSB3aGljaCBvZiB0aGVtIGlzICdiZXN0LicgCgo8YnIgLz4gCgpFcnJvciBNZXRyaWNzIGFuZCBBY2N1cmFjeTogQmVsb3cgYXJlIGVycm9yIG1ldHJpY3MgYW5kIHZhcmlvdXMgYWNjdXJhY3kgZXN0aW1hdGVzIGZvciBlYWNoIG9mIHRoZSBtZXRob2RzJyAiYmVzdCIgbW9kZWwtLSB0aGUgc2ltcGxlc3QgbW9kZWwgd2l0aCB0aGUgaGlnaGVzdCBBVUMuICAKCjxiciAvPgoKKiBMQVNTTyBMb2dpc3RpYyBSZWdyZXNzaW9uIE1vZGVsIApgYGB7cn0KbG9naXN0aWNfbW9kJHJlc3VsdHMgJT4lCiAgICBmaWx0ZXIobGFtYmRhPT1sb2dpc3RpY19tb2QkYmVzdFR1bmUkbGFtYmRhKQpgYGAKCjxiciAvPiAKCiogQmFnZ2luZy9SYW5kb20gRm9yZXN0IE1vZGVsIApgYGB7cn0KcmZfbW9kJHJlc3VsdHMgJT4lIAogIGZpbHRlcihtdHJ5ID09IDIpCnJmX21vZCRmaW5hbE1vZGVsCmBgYAoKPGJyIC8+IAoKTGV0J3MgY29tcGFyZSB0aGUgbW9kZWxzIHRvIGVhY2ggb3RoZXIgYmVzdCB3ZSBjYW4uIAoKPGJyIC8+IAoKVGhlIExBU1NPIGxvZ2lzdGljIG1vZGVsIHByb2R1Y2VkIGFuIEFVQyBvZiAuODA2IGFuZCB0aGUgQVVDIFNEIGlzIHJlcG9ydGVkIGFzIC4wMzUuIE90aGVyIGNvcnJlc3BvbmRpbmcgbWVhc3VyZXMgb2YgYWNjdXJhY3kgZnJvbSB0aGlzIG1vZGVsIGluY2x1ZGUgdGhlIG92ZXJhbGwgYWNjdXJhY3ksIHNlbnNpdGl2aXR5LCBhbmQgc3BlY2lmaWNpdHkuIFRoZSBvdmVyYWxsIGFjY3VyYWN5IGlzIHJlcG9ydGVkIHRvIGJlIDkxJSBhbmQgdGhlIHNlbnNpdGl2aXR5IGFuZCBzcGVjaWZpY2l0eSBhcmUgLjk5OSBhbmQgLjAwNiByZXNwZWN0aXZlbHkuIFNlbnNpdGl2aXR5IFNEIG1lYXN1cmVzIC4wMDA0IGFuZCBhbmQgc3BlY2lmaWNpdHkgU0QgaXMgZXN0aW1hdGVkIHRvIGJlIC4wMDA3LCBzbyB0aGVyZSBpcyB2ZXJ5IGxpdHRsZSB2YXJpYXRpb24gaW4gZXN0aW1hdGVzIGFuZCBub3QgYSBtYWpvciBjb25jZXJuIGZvciB1cy4gSXQgc2hvdWxkIGJlIG5vdGVkIHRoYXQgc2Vuc2l0aXZpdHkgYW5kIHNwZWNpZmljaXR5IGFyZSBsaWtlbHkgc3dpdGNoZWQgaGVyZSwgcGxlYXNlIHNlZSB0aGUgZGlzY3Vzc2lvbiBhYm92ZSBmb3IgZGV0YWlscy4gQXNzdW1pbmcgdGhhdCBzZW5zaXRpdml0eSBhbmQgc3BlY2lmaWNpdHkgYXJlIGluZGVlZCBzd2l0Y2hlZCBoZXJlLCB3ZSBjYW4gc2VlIHRoYXQgdGhpcyBtb2RlbCBkb2VzIGEgdmVyeSBwb29yIGpvYiBvZiBwcmVkaWN0aW5nIHRob3NlIHdpdGggZGlhYmV0ZXMuIEV2ZW4gZGVzcGl0ZSBvbmx5IGJlaW5nIGFibGUgdG8gYWNjdXJhdGVseSBwcmVkaWN0IHRob3NlIHdpdGggZGlhYmV0ZXMgbGVzcyB0aGFuIDElIG9mIHRoZSB0aW1lLCB0aGUgb3ZlcmFsbCBhY2N1cmFjeSBvZiB0aGUgbW9kZWwgaXMgZmFpcmx5IGhpZ2guIFdoeSBpcyB0aGlzPyBJIGhhdmUgcmVhc29uIHRvIGJlbGlldmUgdGhhdCB0aGlzIG1vZGVsIGlzIHN0aWxsIHNvIGFjY3VyYXRlIGJlY2F1c2Ugb2YgdGhlIG5vLWluZm9ybWF0aW9uIHJhdGUgb2YgdGhlIGRhdGEuIFRoZSBOSVIgaXMgOTElLCB3aGljaCBpcyB2ZXJ5IGhpZ2guIFRoaXMgd291bGQgaW1wbHkgdGhhdCBpZiB0aGUgbW9kZWwgd2VyZSB0byBzaW1wbHkgcHJlZGljdCB0aGUgbWFqb3JpdHkgY2xhc3NpZmllciAoaW4gdGhpcyBjYXNlIG5vbiBkaWFiZXRpYykgZXZlcnkgdGltZSwgdGhlIG1vZGVsIHdvdWxkIHN0aWxsIGJlIGFjY3VyYXRlIDkxJSBvZiB0aGUgdGltZS4gVGhpcyBpcyBleGFjdGx5IHdoYXQgd2Ugc2VlIGluIG91ciBvdmVyYWxsIGFjY3VyYWN5IG1lYXN1cmUgYWJvdmUuICAKCjxiciAvPiAKCk5vdyB0byB0dXJuIHRvIHRoZSBiYWdnaW5nL3JhbmRvbSBmb3Jlc3QgbW9kZWwsIHRoaXMgbW9kZWwgY2Fubm90IGJlIGV2YWx1YXRlZCBpbiB0aGUgZXhhY3Qgc2FtZSB3YXlzIGJ1dCB3ZSBjYW4gZ2V0IGFuIG92ZXJhbGwgc2Vuc2Ugb2YgYWNjdXJhY3kuIFRoZSBiZXN0IHR1bmUgb2YgdGhlIHJhbmRvbSBmb3Jlc3QgbW9kZWwgd2FzIGFibGUgdG8gcHJlZGljdCBjYXNlcycgZGlhYmV0ZXMgc3RhdHVzIDk1JSBvZiB0aGUgdGltZS4gQ29tcGFyZWQgdG8gdGhlIExBU1NPIGxvZ2lzdGljIG1vZGVsLCB0aGUgcmFuZG9tIGZvcmVzdCBtb2RlbCB3YXMgbXVjaCBiZXR0ZXIgYXQgcHJlZGljdGluZyB3aGVuIGNhc2VzIGFjdHVhbGx5IGhhZCBkaWFiZXRlcy4gVGhpcyBpcyBvbmx5IGJ5IHJlbGF0aXZlIG1lYW5zIHRob3VnaC4gVGhlIHJhbmRvbSBmb3Jlc3QgbW9kZWwgc3RpbGwgaGFzIGFuIG91dCBvZiBiYWcgZXJyb3IgZXN0aW1hdGUgb2YgYWJvdXQgNTAlIHdoZW4gaXQgY29tZXMgdG8gcHJlZGljdGluZyB3aGVuIGEgY2FzZSBhY3R1YWxseSBkb2VzIGhhdmUgZGlhYmV0ZXMuIFRoZSBtb2RlbCBkb2VzIGEgbXVjaCBiZXR0ZXIgam9iIG9mIHByZWRpY3Rpbmcgd2hlbiBwZW9wbGUgYXJlbid0IGRpYWJldGljLCB0aG91Z2guIFRoZSBtb2RlbCBwcm9kdWNlZCBhIG91dCBvZiBiYWcgZXJyb3Igb2YgbGVzcyB0aGFuIDElIHdoZW4gaXQgY29tZXMgdG8gcHJlZGljdGluZyBjYXNlcyB0aGF0IGFyZSBhY3R1YWxseSBub24tZGlhYmV0aWMuIFRoZSBtb2RlbCBoYXMgYW4gb3ZlcmFsbCBvdXQgb2YgYmFnIGVycm9yIGVzdGltYXRlIG9mIDQuNjUlLiBTbywgaW4gYSBicm9hZCBzZW5zZSwgdGhpcyBtb2RlbCBpcyB2ZXJ5IGFjY3VyYXRlIGF0IHByZWRpY3Rpbmcgbm9uLWRpYWJldGljIHdoZW4gYSBjYXNlIHJlYWxseSBpc24ndCBkaWFiZXRpYyBidXQgaXQgaXMgb25seSBhYmxlIHRvIGFjY3VyYXRlbHkgcHJlZGljdCBkaWFiZXRlcyBmb3IgcGVvcGxlIHdobyBhcmUgYWN0dWFsbHkgZGlhYmV0aWMgYWJvdXQgNTAlIG9mIHRoZSB0aW1lLiAKCjxiciAvPgo8YnIgLz4KCioqT3ZlcmFsbCBNb3N0IFByZWZlcmFibGUgTW9kZWw6KiogPGJyIC8+IAoKQWZ0ZXIgaGF2aW5nIGNvbXBhcmVkIHRoZSBMQVNTTyBsb2dpc3RpYyByZWdyZXNzaW9uIGFuZCBiYWdnaW5nL3JhbmRvbSBmb3Jlc3QgbW9kZWwsIEkgYW0gYWJsZSB0byBtYWtlIGFuIGluZm9ybWVkIGRlY2lzaW9uIGFib3V0IHdoaWNoIG9mIHRoZXNlIG1vZGVscyBpcyBtb3JlIHByZWZlcmFibGUuIEkgY2FuIGJhc2UgdGhpcyBkZWNpc2lvbiBvbiBhY2N1cmFjeSBtZXRyaWNzLCBpbnRlcnByZXRhYmlsaXR5IG9mIHRoZSBlc3RpbWF0ZXMsIGFuZCB0aGUgdXNlZnVsbmVzcyBvZiB0aGVzZSBtb2RlbHMgaW4gY29udGV4dCBvZiB0aGUgZGF0YS4gV2l0aCB0aGVzZSBhc3BlY3RzIGluIG1pbmQsIGl0IGlzIGNsZWFyIHRvIG1lIHRoYXQgdGhlIHJhbmRvbSBmb3Jlc3QgbW9kZWwgaXMgdGhlIG1vcmUgcHJlZmVyYWJsZSBvZiB0aGUgdHdvLiBUaGUgcmFuZG9tIGZvcmVzdCBtb2RlbCdzIG92ZXJhbGwgYWNjdXJhY3kgKDk1JSkgaXMgaGlnaGVyIHRoYW4gdGhlIExBU1NPIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwgKDkxJSkuIFRoZSByYW5kb20gZm9yZXN0IG1vZGVsIGFsc28gcHJvZHVjZXMgYmV0dGVyIHNlbnNpdGl2aXR5IGFuZCBzcGVjaWZpY2l0eSBtZWFzdXJlcyB0aGFuIHRoZSBsb2dpc3RpYyBtb2RlbC4gVGhlIGxvZ2lzdGljIG1vZGVsIHBhcnRpY3VsYXJseSBmYWlscyBhdCBtYWtpbmcgZ29vZCBwcmVkaWN0aW9ucyBmb3IgcGVvcGxlIHdobyBhcmUgZGlhYmV0aWMuIFdoaWxlIHRoZSByYW5kb20gZm9yZXN0IG1vZGVsIGlzIHN0aWxsIGZhaXJseSBiYWQgYXQgZG9pbmcgdGhlIHNhbWUgdGhpbmcgKGl0IG9ubHkgaXMgYWNjdXJhdGUgcHJlZGljdGluZyBkaWFiZXRlcyBhbW9uZyB0aG9zZSB3aG8gYXJlIGFjdHVhbGx5IGRpYWJldGljIH41MCUgb2YgdGhlIHRpbWUpLCBidXQgaXQgaXMgc2lnbmlmaWNhbnRseSBiZXR0ZXIgdGhhbiB0aGUgbG9naXN0aWMgbW9kZWwuIEluIHRoZSBjb250ZXh0IG9mIHRoZSBkYXRhLCBJIGJlbGlldmUgaXQgaXMgbW9yZSBpbXBvcnRhbnQgZm9yIGEgcHJlZGljdGl2ZSBtb2RlbCB0byBiZSBhYmxlIHRvIGlkZW50aWZ5IHdoZW4gYSBkaXNlYXNlIGlzIGFjdHVhbGx5IHByZXNlbnQgdGhhbiBpdCBpcyBmb3IgdGhlIG1vZGVsIHRvIGlkZW50aWZ5IHdoZW4gYSBkaXNlYXNlIGlzbid0LiBXaGF0IGdvb2QgaXMgdGhlIG1vZGVsIGlmIGl0IGNhbiBvbmx5IGNvbmZpcm0gdGhhdCBwZW9wbGUgYXJlbid0IGRpYWJldGljPyBJdCBtaWdodCBoYXZlIHNvbWUgYmVuZWZpdHMsIGJ1dCB3aGVuIHNwZWNpZmljaXR5IGlzIHNvIGhpZ2gsIEknZCBob3BlIGZvciBzZW5zaXRpdml0eSB0byBhbHNvIGJlIGhpZ2guIFNvLCB0aGlzIGFzcGVjdCB3ZWlnaGVkIGhlYXZpbHkgaW4gbXkgbWluZCBpbiByZWFzb25pbmcgd2hpY2ggbW9kZWwgaXMgcHJlZmVyYWJsZS4gT25lIHBvdGVudGlhbCBhZHZhbnRhZ2UgdGhhdCBJIGhhZCB0byBvdmVybG9vayBmb3IgdGhlIGxvZ2lzdGljIG1vZGVsIGlzIGl0cyBpbnRlcnByZXRhYmlsaXR5LiBUaGUgY29lZmZpY2llbnQgZXN0aW1hdGVzIHByb2R1Y2VkIGJ5IHRoZSBsb2dpc3RpYyBtb2RlbCBhcmUgdmVyeSBlYXNpbHkgaW50ZXJwcmV0ZWQsIGFuZCB0aGlzIGhhcyBiZW5lZml0cyBpbiBleHBsYWluaW5nIGhvdyBjZXJ0YWluIHZhcmlhYmxlcyBhcmUgcmVsYXRlZCB0byB0aGUgb2RkcyBvZiBoYXZpbmcgZGlhYmV0ZXMuIE5vbmV0aGVsZXNzLCB0aGUgcmFuZG9tIGZvcmVzdCBtb2RlbCBjYW4gYmUgaW50ZXJwcmV0ZWQgaW4gYnJvYWQgc3Ryb2tlcyBhbmQgaXRzIG92ZXJhbGwgaGlnaGVyIGFjY3VyYWN5IG1lYXN1cmVzIG1ha2UgaXQgYW4gb2J2aW91cyBjaG9pY2UuIFdoaWxlIEkgZG9uJ3Qga25vdyBmb3IgY2VydGFpbiwgSSdkIGltYWdpbmUgdGhhdCBhbiBvdmVyYWxsIGFjY3VyYWN5IG9mIDk1JSBmb3IgYSBwcmVkaWN0aXZlIG1vZGVsIGluIGEgY2xpbmljYWwgc2V0dGluZyB3b3VsZCBiZSBzb21ld2hhdCB3b3J0aHdoaWxlLiBPYnZpb3VzbHkgaXQnZCBiZSBpZGVhbCB0byBoYXZlIHRoYXQgbnVtYmVyIGhpZ2hlciwgYnV0IGNvbnNpZGVyaW5nIHRoZSBsaW1pdGVkIG51bWJlciBvZiBwcmVkaWN0b3JzIEkgdXNlZCwgSSdtIHNvbWV3aGF0IHNhdGlzZmllZCB3aXRoIHNlZWluZyB0aGlzIGZpZ3VyZSBhcyBoaWdoIGFzIGl0IGlzLiBBcyBkaXNjdXNzZWQgYWJvdmUsIHRoZSBuby1pbmZvcm1hdGlvbiByYXRlIGlzIGZhaXJseSBoaWdoIGZvciB0aGlzIHBhcnRpY3VsYXIgY2xhc3NpZmljYXRpb24gdGFzaywgYW5kIGJlaW5nIGFib3ZlIHRoYXQgZmlndXJlIGluIG92ZXJhbGwgYWNjdXJhY3kgaXMgYSBnb29kIHRocmVzaG9sZCB0byBoYXZlIHBhc3NlZC4gU2VlIHRoZSByZWFkb3V0cyBiZWxvdyB0byBjb25maXJtIHRoZSBlcnJvciBlc3RpbWF0ZXMuIAoKYGBge3J9CnJmX21vZCRmaW5hbE1vZGVsCmBgYAoKPGJyIC8+CgojICoqU29jaWV0YWwgSW1wYWN0KiogCgo8YnIgLz4KCldoZW4gcGVyZm9ybWluZyBzdGF0aXN0aWNhbCByZXNlYXJjaCBzdWNoIGFzIHRoaXMsIGl0J3MgaW1wb3J0YW50IHRvIHJlY29nbml6ZSBpZiBhbnkgaGFybXMgbWF5IGNvbWUgZnJvbSB5b3VyIGFuYWx5c2VzIGFuZC9vciBob3cgdGhlIGRhdGEgd2FzIGNvbGxlY3RlZC4gSSBmaW5kIGl0IHdvcnRoIG1lbnRpb25pbmcgaW4gdGhpcyByZXBvcnQgYSBmZXcgdGhpbmdzIHdvcnRoIHlvdXIgY29uc2lkZXJhdGlvbi4gTmFtZWx5LCB3aGlsZSBOSEFORVPigJkgc2FtcGxlIGNvbGxlY3Rpb24gbWV0aG9kcyBzZWVtIGZhaXJseSByaWdvcm91cywgb25lIGtleSBpc3N1ZSBJIGhhdmUgd2l0aCBpdCBpcyB0aGUgZXhjbHVzaW9uIG9mIGluc3RpdHV0aW9uYWxpemVkIHBvcHVsYXRpb25zIGZyb20gdGhlIGRhdGEuIFRoZSBhYnNlbmNlIG9mIHRoaXMgcG9wdWxhdGlvbiBtZWFucyB0aGF0IGhlYWx0aCBwaGVub21lbmEgc3BlY2lmaWMgdG8gdGhlbSBpc27igJl0IHJlZmxlY3RlZCBpbiB0aGlzIGRhdGEuIEFuZCBiZWNhdXNlIE5IQU5FUyBpbmZvcm1zIHB1YmxpYyBwb2xpY3kgYW5kIGZ1bmRpbmcsIHRoZXNlIGluZGl2aWR1YWxz4oCZIG5lZWRzIHdpbGwgbGlrZWx5IGdvIHRvIHRoZSB3YXlzaWRlLiBJIGFsc28gZmVlbCBpdOKAmXMgaW1wb3J0YW50IHRvIGNvbnRleHR1YWxpemUgdGhhdCB0aGlzIGRhdGEgaXMgYWJvdXQgYSBkZWNhZGUgb2xkIGFuZCB0aGlzIGFuYWx5c2lzIHJlZmxlY3RzIG9uIHRoaXMgc25hcHNob3QgaW4gdGltZSwgYW5kIGl0IHNob3VsZG7igJl0IGJlIGV4dHJhcG9sYXRlZCB0byB0b2RheS4gVGhlc2UgYXJlIGp1c3QgYSBmZXcgZXhhbXBsZXMsIGFuZCB0aGVyZSBhcmUgc3VyZWx5IG1vcmUgaW1wbGljYXRpb25zIHRoYXQgYXJlIHdvcnRoIGV4cGFuZGluZyBvbiBpbiBhIGRpZmZlcmVudCBzZXR0aW5nLCBidXQgaG9wZWZ1bGx5IHRoaXMgbWFrZXMgeW91IHRoaW5rIGEgYml0IG1vcmUgY3JpdGljYWxseSBhYm91dCB0aGUgaW1wbGljYXRpb25zIG9mIHRoaXMgYW5hbHlzaXMu