Keywords: Logistic regression, Akaike Information Criterion (AIC), ROC curve, Area Under Curve (AUC), Sensitivity, Specificity, Misclassification Rate

GitHub Repository: MUSA5000-Logistic-Regression | Website

Introduction

Motor vehicle crashes remain one of the leading causes of injury and death in urban environments across the United States. Among these incidents, crashes involving alcohol-impaired drivers are particularly concerning because they account for a disproportionately high number of fatalities and severe injuries. According to national statistics, nearly one-third of all traffic-related deaths involve a driver under the influence of alcohol, underscoring the continued public health risks associated with impaired driving. In Philadelphia, where traffic density, roadway design, and neighborhood characteristics vary widely, it is especially important to understand the factors that contribute to alcohol-related crashes. By identifying these factors, city officials and public health professionals can design more targeted interventions to reduce the prevalence and severity of such incidents. This analysis uses crash data from Philadelphia covering the years 2008 to 2012 to investigate how various characteristics of crashes and neighborhoods are associated with the presence of a drinking driver.

This study explores the factors associated with DUI in traffic crashes in Philadelphia by examining a set of binary and continuous predictors. These include indicators of crash severity (Crashes resulted in fatality or major injury), risky driving behaviors (Crashes involved an overturned vehicle, speeding car and aggressive driving or Driver was using cell phone), driver demographics (Crashes involved at least one driver who was 16 or 17 years old and Crashes involved at least one driver who was at least 65 years old), and neighborhood-level socioeconomic characteristics (percentage with bachelor’s degree or more, Median household income). Among them, crashes resulting in fatalities or major injuries are more likely to involve alcohol, as intoxicated drivers have slower reaction times and poorer judgment. Behaviors such as speeding, aggressive driving, and overturning are more common in high-risk situations often associated with alcohol impairment. Distractions like cellphone use may not be directly linked to alcohol use, but they reflect a broader disregard for road safety that might overlap with impaired driving tendencies. Age also plays a role as younger drivers (ages 16–17) are less experienced and may be more prone to risk-taking, while older drivers (65+) typically show lower alcohol involvement because of health concerns or lifestyle differences. Beyond driver behavior, neighborhood-level characteristics such as education and income may also influence the likelihood of alcohol-involved crashes. Areas with higher percentages of college-educated residents may have greater awareness of drunk driving risks. Wealthier neighborhoods might also exhibit lower rates of alcohol-related crashes as they have access to greater availability of resources and support systems.

In this report, we use R to perform logistic regression analysis, examining the statistical relationships between the selected predictors and the likelihood that a crash involved a drinking driver across Philadelphia.

Method

Issues with OLS Regression

The OLS regression model can be expressed as following formula:

\[ y = \beta_0 + \beta_1x_1 + \beta_2x_2 + ... + \beta_kx_k + \epsilon \]

where:

  • \(y\) is the dependent variable
  • \(x_1, x_2, ..., x_k\) are the independent variables
  • \(\beta_0, \beta_1, \beta_2, ..., \beta_k\) are the coefficients
  • \(\epsilon\) is the error term

Using OLS regression to model binary outcomes can lead to several issues:

  • First, in the OLS regression, \(\beta_1\) is interpreted as the amount of the dependent variable \(y\) changes when \(x_1\) increases by one unit, holding all other variables constant. However, when the dependent variable is binary, a one unit increase in \(x_1\) results in \(\beta_1\) increase in \(y\) no longer makes sense, as \(y\) can change only from 0 to 1 or from 1 to 0. This leads to some interpretation issues.
  • Second, OLS regression assumes a linear relationship between the predictors and the dependent variable. With a binary dependent variable, this assumption no longer holds, as binary outcomes are inherently no linear.
  • Third, OLS also assumes normally distributed residuals. However, with binary outcome, the residuals are not normally distributed. Instead, they follow a binomial distribution.
  • Finally, OLS regression has another assumption of homoscedasticity, which means that the variance of the residuals is constant across all levels of the independent variables. However, with binary outcomes, this assumption is violated, as the variance of the residuals is not constant. It varies with the predicted probability, leading to heteroscedasticity.

All those violations of the OLS regression assumptions affect the validity of the model and the interpretation of the coefficients. In this way, we need to use a different approach to model binary outcomes.

Logistic Regression Concepts

Logistic regression provide a way for us to get around above-mentioned issues. Instead of predicting the the dependent variable \(y\) directly, logistic regression predicts the probability of the dependent variable \(y\) being equal to 1. This can be explained through the concept of odds. The odds of an event is a ratio that compares the likelihood of the event happening to the likelihood of it not happening. The odds of an event can be expressed as:

\[ \text{Odds} = \frac{\text{Probability of Event Happening}}{\text{Probability of Event Not Happening}} = \frac{p}{1 - p} \] Where \(p\) is the probability of the event happening. The odds can take any value from 0 to infinity, where 0 means the event will never happen and infinity means the event will always happen. For example, if there is a 60% of an event happening (probability\(p\)=0.6), the odds of the event would be:

\[ \text{Odds} = \frac{0.6}{1 - 0.6} = \frac{0.6}{0.4} = 1.5 \] This mean the vent is 1.5 times more likely to happen than not happening. In logistic regression, instead of predicting the probability of the event directly, we predict the log odds (also known as logit) of the outcome. The logit model with multiple predictors is expressed as:

\[ \log \left( \frac{p}{1 - p} \right) = \beta_0 + \beta_1 x_1 + \beta_2 x_2 + \dots + \beta_k x_k \] In our specific case, it can be written as: \[ \log \left( \frac{P(\text{DRINKING_D} = 1)}{1 - P(\text{DRINKING_D} = 1)} \right) = \beta_0 + \beta_1 \cdot \text{FATAL_OR_M} + \beta_2 \cdot \text{OVERTURNED} + \dots + \beta_9 \cdot \text{MEDHHINC} \]

Where:

  • \(P(\text{DRINKING_D} = 1)\) is the probability of a crash involving a drinking driver.
  • \(\log \left( \frac{P(\text{DRINKING_D} = 1)}{1 - P(\text{DRINKING_D} = 1)} \right)\) is the log-odds of drinking involvement.
  • \(\beta_0\) is the intercept of the model, representing the log-odds of drinking and drive involved when all predictors are zero
  • \(\beta_1, \beta_2, \dots, \beta_k\) are the coefficients of each predictor variable, indicating the change in log-odds for a one unit increase in each predictors, holdings other constant.

The predictor variable in the model is defined as follows:

  • FATAL_OR_M: whether the crash involved a fatality
  • OVERTURNED: whether the crash involved an overturned vehicle
  • CELL_PHONE: whether the driver was using a cell phone
  • SPEEDING: whether the crash involved speeding
  • AGGRESSIVE: whether the crash involved aggressive driving
  • DRIVER1617: whether the crash involved at least one driver aged 16 or 17
  • DRIVER65PLUS: whether the crash involved at least one driver aged 65 or older
  • PCTBACHMOR: percentage of the population with a bachelor’s degree or more
  • MEDHHINC: median household income in the area

Logistic Function: The logistic function is the inverse of the logit function, as shown in following graph. It takes the linear predictor (log-odds) and transforms it into a probability value between 0 and 1 [0,1]. This transformation is ideal for modeling binary outcomes as it transforms the linear combination of predictors into a probability value.

knitr::include_graphics("logisticvslogit.png")

The logistic function is defined as:

\[ P(Y = 1) = \frac{1}{1 + e^{-(\beta_0 + \beta_1 x_1 + \beta_2 x_2 + \dots + \beta_k x_k)}} \] In this specific case, it can be written as:

\[ P(\text{DRINKING_D} = 1) = \frac{1}{1 + e^{-(\beta_0 + \beta_1 \cdot \text{FATAL_OR_M} + \dots + \beta_9 \cdot \text{MEDHHINC})}} \] As shown in the graph above, the logistic function has an S-shaped curve with the following properties:

  • Outcome between 0 and 1 [0,1]: As the linear predictor approaches negative infinity, the probability approaches 0. As the linear predictor approaches positive infinity, the probability approaches 1. This means that the predicted probabilities will always be between 0 and 1, making it suitable for binary outcomes.
  • Symmetric around 0.5: The logistic function is symmetric around the point where the linear predictor equals 0.5. This means that when the linear predictor is equal to 0, the predicted probability is 0.5, indicating an equal chance of the event occurring or not occurring. This midpoint is useful in binary classification as it helps interpret probabilities around 50%.

Overall, the logistic function is the type of translator function we are ;ooking for. It works well for binary dependent variable because it restricts the predicted probabilities to the range of 0 and 1, which is essential for binary outcomes. Each coefficient \(\beta_i\) in the logistic regression model represents the effect of a predictor on the log-odds of the outcome, which can be transformed to interpret effects on probability.

Logistic Regression Hypothesis

For each predictors in our logistic regression model, we test whether the predictor has a statistically significant effect on the outcome variable.

The Null Hypothesis (\(H_0\)), which states that the predictor has no effect on the outcome variable. In other words, the coefficient of the predictor is equal to zero (\(\beta_i = 0\)), writtern as:

\[ H_0 : \beta_i = 0 \] The Alternative Hypothesis (\(H_a\)), which states that the predictor has an effect on the outcome variable. In other words, the coefficient of the predictor is not equal to zero (\(\beta_i \neq 0\)), writtern as:

\[ H_0 : \beta_i = 0 \]

To test these hypotheses, we use the Wald test, which is a statistical test used to assess the significance of individual coefficients(\(\beta_i\)) in a regression model. The Wald test statistic is calculated as:

\[ W_i = \frac{\hat{\beta}_i}{\sigma(\hat{\beta}_i)} \]

Where:

  • \(\hat{\beta}_i\) is the estimated coefficient for predictor \(i\)
  • \(\sigma(\hat{\beta}_i)\) is the standard error of the estimated coefficient

Under the null hypothesis, the Wald test statistic follows a standard normal distribution \(N(0, 1)\). Large values of the Wald test statistic indicate that \(\beta_i\) is significantly different from zero, suggesting that the predictor has a significant effect on the outcome variable. We can safely reject the null hypothesis.

However, rather than looking at the estimated beta coefficients (\(\beta\)), most statisticans still prefer to looks at odds Ratios, which is calculated by exponentiating the estimated coefficients (\(\beta\)). For example, if the odds ratio for a predictor is 1.6, it means that the odds of the outcome are 1.6 times higher for a one-unit increase in the predictor, holding all other predictors constant. This makes it easier to interpret the effect of each predictor on the outcome variable.

In addition, an odds ratio greater than1 indicates that the predictor is associated with an increase likelihood of the outcome, while an odds ratio less than 1 indicates that the predictor is associated with a decrease likelihood of the outcome. An odds ratio equal to 1 indicates no effect.

Logistic Regression Model Assessment

R-squared

In logistic regression, there are several ways to access the quality of the model fit. An R-squared value can be computed for logistic regression, but it differs from the R-squared used in ordinary least squares (OLS) regression. In OLS, R-squared represents the proportion of variance in the outcome explained by the model, and a higher R-squared generally indicates better model fit. However, this interpretation does not apply to logistic regression. This is because logistic regression models a binary outcome and uses maximum likelihood estimation (MLE) rather than minimizing the sum of squared residuals. In another word, there is no direct concept of variance in the dependent variable to be explained in the same way. Therefore, R-squared values in logistic regression are not directly comparable to OLS R² and are rarely used as primary indicators of model fit. Notably, the glm() function in R does not report an R-squared value by default, which reflects its limited interpretability. If an R-squared value is desired, one option is to use the rms package in R, which provides a version of Nagelkerke R². While this adjusted R-squared can offer some insight into model fit, it should be interpreted with caution, and the only safe conclusion is higher values are better.

Akaike Information Criterion (AIC)

The Akaike Information Criterion (AIC) is commonly used for model comparison in logistic regression as an alternative of R-squared. AIC is an estimator of prediction error and the relative quality of statistical models for a given dataset. It provides a principled approach to comparing candidate models by balancing goodness of fit with model complexity, penalizing models with more parameters to reduce the risk of overfitting. AIC is defined as:

\[ \text{AIC} = 2k - 2\ln(\hat{L}) \]

where:

  • \(k\) is the number of estimated parameters in the model
  • \(\hat{L}\) is the maximum value of the likelihood function for the model

A lower AIC value suggests a better fit, as they balance the trade-off between model complexity and goodness of fit.

Specificity, Sensitivity and Misclassification Rate

In logistic regression, residuals (Errors) are defined as the difference between the observed and predicted values, similar to linear regression. However, in logistic regression, the predicted values are probabilities, not direct values of the dependent variable. Specifically, the predicted value \(\hat{y}_i\) is the estimated probability that \(Y = 1\) for the \(i\)-th observation.

The residuals in logistic regression are defined as:

\[ \epsilon_i = y_i - \hat{y}_i \]

Where:

  • \(y_i\) is the actual observed value (either 0 or 1).

  • \(\hat{y}_i\) is the predicted probability that \(Y = 1\) for the \(i\)-th observation.

The predicted probabilities \(\text{P(y=1)}\) =\(\hat{y}_i\) are calculated using the logistic function:

\[ \text{P(y=1)}=\hat{y}_i = \frac{e^{(\hat{\beta}_0 + \hat{\beta}_1 x_{1i} + \hat{\beta}_2 x_{2i} + \cdots + \hat{\beta}_p x_{pi})}}{1 + e^{(\hat{\beta}_0 + \hat{\beta}_1 x_{1i} + \hat{\beta}_2 x_{2i} + \cdots + \hat{\beta}_p x_{pi})}}= \frac{1}{1 + \exp(-\hat{\beta}_0 - \hat{\beta}_1x_1 - \dots - \hat{\beta}_kx_k)} \]

Where:

  • \(\hat{y}_i\) is the estimated probability that \(Y = 1\) for the \(i\)-th observation.

  • \(\hat{\beta}_0, \hat{\beta}_1, \dots, \hat{\beta}_p\) are the estimated coefficients obtained from the logistic regression model.

  • \(x_{1i}, x_{2i}, \dots, x_{pi}\) are the values of the predictor variables for observation \(i\).

After obtaining the predicted probabilities, we apply a threshold (cut-off) value to classify predictions into binary outcomes (e.g. \(\hat{y}\)>0.5 as y= 1, and \(\hat{y}\)<0.5 as y=0). The choice of cut-off value can significantly impact the model’s performance. The default cut-off value is 0.5, but it can be adjusted based on the specific context and goals of the analysis.

To assess predictive performance and different cut-off values, we use metrics such as sensitivity, specificity and misclassification rate. These metrics are derived from the predicted values of \(\hat{y}\), which in logistic regression represent the estimated probability that \(Y = 1\).

  • Sensitivity (also called recall or the true positive rate) measures the proportion of actual positives correctly predicted and is complementary to the false negative rate:

\[ \text{Sensitivity} = \frac{TP}{TP + FN} \]

  • Higher sensitivity is better, especially when failing to detect true positives is costly.

  • Specificity (the true negative rate) measures the proportion of actual negatives correctly predicted and is complementary to the false positive rate:

\[ \text{Specificity} = \frac{TN}{TN + FP} \]

  • Higher specificity is better when false positives are particularly problematic.

  • The correct classification rate is the proportion of all predictions that are correct:

\[ \text{Correct Classification Rate} = \frac{TP + TN}{\text{Total}} \]

  • A higher correct classification rate indicates better model performance.

  • The misclassification rate is the proportion of all predictions that are incorrect:

\[ \text{Misclassification Rate} = 1 - \text{Correct Classification Rate} \]

  • Lower values of the misclassification rate indicate better performance, as it reflects the lower proportion of incorrect predictions.

Using different cut-off values allows for a trade-off between sensitivity and specificity. For example, a lower cut-off value may increase sensitivity but decrease specificity, while a higher cut-off value may increase specificity but decrease sensitivity. For example, if the cutoff value = 0.7, the model will classify a crash as involving a drinking driver only if the predicted probability is greater than 0.7. This may lead to fewer false positives (higher specificity) but more false negatives (lower sensitivity). Conversely, if the cut-off value = 0.3, the model will classify a crash as involving a drinking driver if the predicted probability is greater than 0.3, leading to more false positives (lower specificity) but fewer false negatives (higher sensitivity). The choice of cut-off value should be based on the specific context and goals of the analysis, considering the consequences of false positives and false negatives.

Receiver Operating Characteristic (ROC) Curve

One way to plot sensitivity (true positive rate) against \(1 -\) specificity (false positive rate) is through the Receiver Operating Characteristic (ROC) curve. The ROC curve is a graphical representation that helps assess the predictive quality of the model by comparing sensitivity and specificity across various thresholds. ROC Curves will be to the left of the 45 degree line.

A best cut-off value may be determined by optimizing the balance between sensitivity and specificity. There are a couple of ways to identify the optimal probability cut-off based on the ROC curve:

  • We can calculate the Youden Index, which defined as:

\[ J = \text{Sensitivity} + \text{Specificity} - 1 \] The best cut-off can be found where the Youden Index is maximized.

  • The second approaches involve calculate the Minimum Distance. A cut-off where the ROC curve has the minimum distance from the upper-left corner of the graph, where both specificity and sensitivity are equal to 1. In this case, we are minimizing the distance from the upper left corner, where \(y = \text{Sensitivity} = \text{True Positive Rate} = \text{tpr} = 1\) and \(x = 1 - \text{Specificity} = \text{False Positive Rate} = \text{fpr} = 0\). The formula used to calculate the distance is:

\[ d = (x - 0)^2 + (y - 1)^2 \]

For this report, we will be using the minimum distance approach to determine the optimal cut-off value.

Area Under the ROC Curve (AUC)

Based on the ROC curve, we can calculate the Area Under Curve (AUC) to quantify the model’s performance. Area Under the ROC Curve (AUC) means how well the model predicts \(Y = 1\) responses as 1’s and \(Y = 0\) responses as 0’s. Higher AUC values indicate that we can find a cut-off value for which both sensitivity and specificity are relatively high. The possible values for AUC range between 0.5 (Area under the 45-degree line, means no discrimination between classes, equivalent to random guessing) and 1 (Area of the entire box means perfect prediction). The AUC value may be interpreted as the probability that the \(\hat{y}\) for observation 1 (where \(y = 1\)) will be higher than the \(\hat{y}\) for observation 2 (where \(y = 0\)). A rough guide for classifying the accuracy based on AUC is:

  • AUC = 0.90–1.00: Excellent
  • AUC = 0.80–0.89: Good
  • AUC = 0.70–0.79: Fair
  • AUC = 0.60–0.69: Poor
  • AUC < 0.60: Failing

We can generally consider an AUC value greater than 0.7 as acceptable.

Logistic Regression Assumptions

Logistic regression shares some assumptions with OLS regression, but it also has unique assumptions that accommodate the binary nature of the dependent variable. The key assumptions of logistic regression include:

  • First, just like OLS regression, logistic regression assumes that observations are independent of each other. This means that each data point should not influence another, without spatial and time autocorrelation.
  • Second, similar to OLS regression, logistic regression assumes that there is no severe multicollinearity among the independent variables. Multicollinearity occurs when two or more independent variables are highly correlated, making it difficult to determine the individual effect of each variable on the dependent variable and instability in the coefficient estimates.
  • Third, unless the OLS regression, logistic regression does not assumes homoscedasticity. In OLS regression, the residuals should have constant variance across all levels of the independent variables (homoscedasticity). However, in logistic regression, this assumption is not required because the model uses a different error structure (binomial distribution).
  • Forth, in OLS, we assume that the residuals are normally distributed. In logistic regression, however, the errors do not need to follow a normal distribution because the model uses a binomial distribution instead of normal distribution. This is one of the key differences between OLS and logistic regression.
  • Lastly, logistic regression does not assume a linear relationship between the independent variables and the dependent variable.
  • Instead, dependent variable for logistic regression must be binary (0 or 1). Logistic regression assumes that the log odds of the dependent variable being 1 is linearly related to the each independent variable. This is a unique assumptions of logistic regression that does not apply to OLS regression.
  • In addition, logistic regression requires a sample size of at least 50 per predictors, as logistic regression uses Maximum Likelihood Estimation (MLE) to estimate the coefficients.

Exploratory Analysis

Before running logistic regression, we need to conduct exploratory analyses to better understand the relationship between the dependent variable (which is the drinking driver indicator DRINKING_D in the report) and potential predictors. These analyses help identify statistically significant associations and guide the selection of appropriate variables for the regression model.

For binary predictors, we examine the distribution across groups using cross-tabulations and assess significance using the Chi-Square test. For continuous predictors, we compare group means and standard deviations and use the independent samples t-test to determine whether the differences are statistically meaningful.

Binary Predictors

We first examine the relationship between the dependent variable and binary predictors through cross-tabulations. Cross-tabulations allow us to explore the distribution of observations across the different dependent variables.

To formally test whether a statistically significant association exists between the dependent variable and each binary predictor, we use the Chi-Square test. The Chi-Square statistic is derived from the sum of squared differences between observed and expected frequencies, normalized by the expected frequencies. The degrees of freedom (df) for the test can be calculated as \((R-1)(C-1)\), where \(R\) is the number of rows and \(C\) is the number of columns in the cross-tabulation table, representing the number of categories in each of the two variables being analyzed. The hypotheses are as follows:

  • Null Hypothesis (H0): The proportions of different category of predictors are the same for drinking and non-drinking drivers. There is no association between the binary predictor and the dependent variable (DRINKING_D)

  • Alternative Hypothesis (Ha): The proportions of different category of predictos differ between drinking and non-drinking drivers. There is an association between the binary predictor and the dependent variable (DRINKING_D)

If the p-value is below 0.05, we reject the null hypothesis and conclude that there is a statistically significant association between the two categorical variables.

Continuous Predictors

For continuous predictors, we first examine the continuous predictors by comparing their means and standard deviations for the two groups of the dependent variable (in this report, those with and without drinking drivers in crashes). This allows us to compare the distributions of the predictor across groups.

Then, we use the independent samples t-test to assess whether the observed differences in means are statistically significant. The hypotheses for the t-test are:

  • Null Hypothesis (H0): The average values of the continuous predictor are the same for crashes that involve drinking drivers and those that do not. There is no significant difference in the means of the continuous predictor for crashes that involved alcohol and those that did not.

  • Alternative Hypothesis (Ha): The average values of the continuous predictor are different for crashes that involve drinking drivers and those that do not. There is a significant difference in the means of the continuous predictor for crashes that involved alcohol and those that did not.

If the p-value of t-test is below 0.05, we reject the null hypothesis in favor of the alternative, indicating that the mean of the continuous predictor significantly differs between the two groups.

By performing these exploratory analyses, we can identify which predictors exhibit significant associations with the dependent variable and should be considered in the logistic regression model.

Results

Exploratory Analyses

Dependent Variable

In the report, the dependent variable is DRINKING_D, indicating whether a crash involved a drinking driver. Of the 53,260 recorded crashes in Philadelphia from 2008 to 2012, we excluded 9,896 crashes that occurred in non-residential block groups, where median household income and vacancy rates are 0. This leaves 43,364 crashes that took place in Philadelphia’s residential block groups.

depetab <- prop.table(table(crashes$DRINKING_D))
deptab <- as.data.frame(depetab)
colnames(deptab) <- c("DRINKING_D", "Proportion")
deptab %>%
  kable("html", escape = FALSE, align = "cc") %>%
  kable_styling(full_width = FALSE, position = "center", fixed_thead = TRUE)
DRINKING_D Proportion
0 0.943
1 0.057

We see that there are 2,485 (5.73%) crashes that involved a drunk driver, and 40,879 (94.27%) crashes that did not involve a drunk driver. That is, the probability of a crash involving drinking drivers can be calculated using the formula:

\[ \text{Probability(Drinking Drivers)} = \frac{\text{Number of Crashes Involving Drinking Driver}}{\text{Total Number of Crashes}} = \frac{2485}{43364} \approx 0.0573 \]

The odds of a crash involving drinking drivers can be calculated using the formula:

\[ \text{Odds(Drinking Drivers)} = \frac{\text{Number of Crashes Involving Drinking Driver}}{\text{Number of Crashes Not Involving Drinking Drivers}} = \frac{2485}{40879} \approx 0.0608 \]

This suggests that while the overall probability of a crash being alcohol-related is relatively low, the odds still warrant attention, especially given the serious consequences often associated with such incidents.

Independent Variables - Binary

Then, let’s take a look at binary independent variables FATAL_OR_M,OVERTURNED, CELL_PHONE, SPEEDING, AGGRESSIVE, DRIVER1617, and DRIVER65PLUS.

# Load required library
library(gmodels)

# Ensure binary variables are factors
crashes$DRINKING_D <- as.factor(crashes$DRINKING_D)
binary_vars <- c("FATAL_OR_M", "OVERTURNED", "CELL_PHONE", "SPEEDING",
                 "AGGRESSIVE", "DRIVER1617", "DRIVER65PLUS")
crashes[binary_vars] <- lapply(crashes[binary_vars], as.factor)

# Define function to extract Chi-Square test results and percentages
extract_chi2_results <- function(dep_var, pred_var) {
  crosstab <- table(dep_var, pred_var)

  # Total counts per group
  total_no_alcohol <- sum(crosstab[1, ])
  total_alcohol <- sum(crosstab[2, ])

  # Count of "1"s
  no_alcohol_1_count <- crosstab[1, "1"]
  alcohol_1_count <- crosstab[2, "1"]

  # Percentages
  percent_no_alcohol <- 100 * crosstab[1, "1"] / total_no_alcohol
  percent_alcohol <- 100 * crosstab[2, "1"] / total_alcohol

  # Chi-square test without Yates correction
  chi2_test <- suppressWarnings(chisq.test(crosstab, correct = FALSE))

  # Output list
  return(list(
    crosstab = crosstab,
    no_alcohol_1_count = no_alcohol_1_count,
    alcohol_1_count = alcohol_1_count,
    percent_no_alcohol = percent_no_alcohol,
    percent_alcohol = percent_alcohol,
    total_n = sum(crosstab[, "1"]),
    chi2_stat = chi2_test$statistic,
    df = chi2_test$parameter,
    p_value = chi2_test$p.value
  ))
}

# Initialize results table
all_results <- data.frame(
  Variable = binary_vars,
  Description = c(
    "Crash resulted in fatality or major injury",
    "Crash involved an overturned vehicle",
    "Driver was using cell phone",
    "Crash involved speeding car",
    "Crash involved aggressive driving",
    "Crash involved at least one driver aged 16–17",
    "Crash involved at least one driver aged 65+"
  ),
  No_Alcohol_N = NA,
  No_Alcohol_Percent = NA,
  Alcohol_N = NA,
  Alcohol_Percent = NA,
  Total_N = NA,
  Chi2_Stat = NA,
  DF = NA,
  P_Value = NA
)

# Loop through variables and populate result table
for (i in seq_along(binary_vars)) {
  var <- binary_vars[i]
  result <- extract_chi2_results(crashes$DRINKING_D, crashes[[var]])

  all_results$No_Alcohol_N[i] <- result$no_alcohol_1_count
  all_results$No_Alcohol_Percent[i] <- round(result$percent_no_alcohol, 1)
  all_results$Alcohol_N[i] <- result$alcohol_1_count
  all_results$Alcohol_Percent[i] <- round(result$percent_alcohol, 1)
  all_results$Total_N[i] <- result$total_n
  all_results$Chi2_Stat[i] <- round(result$chi2_stat, 2)
  all_results$DF[i] <- result$df
  all_results$P_Value[i] <- format.pval(result$p_value, digits = 3, eps = 0.05)
}
## print

library(knitr)
library(kableExtra)

kable(all_results[, c("Variable", "Description",
                      "No_Alcohol_N", "No_Alcohol_Percent",
                      "Alcohol_N", "Alcohol_Percent",
                      "Total_N", "Chi2_Stat", "DF", "P_Value")],
      format = "html",
      col.names = c("Variable", "Description",
                    "N", "%", "N", "%", "N",
                    "Chi2 Stat", "DF", "χ² p-value"),
      caption = "Cross-Tabulation and Chi-Square Test Results") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                full_width = F,
                position = "center") %>%
  column_spec(1, bold = TRUE, width = "10em") %>%
  column_spec(2, bold = FALSE, width = "40em") %>%
  column_spec(3:7, width = "7em") %>%
  column_spec(8:10, width = "8em") %>%
  add_header_above(c(" " = 2,
                     "No Alcohol Involved (DRINKING_D = 0)" = 2,
                     "Alcohol Involved (DRINKING_D = 1)" = 2,
                     "Total" = 1,
                     "Chi-Square Test Results" = 3))
Cross-Tabulation and Chi-Square Test Results
No Alcohol Involved (DRINKING_D = 0)
Alcohol Involved (DRINKING_D = 1)
Total
Chi-Square Test Results
Variable Description N % N % N Chi2 Stat DF χ² p-value
FATAL_OR_M Crash resulted in fatality or major injury 1181 2.9 188 7.6 1369 167.56 1 <0.05
OVERTURNED Crash involved an overturned vehicle 612 1.5 110 4.4 722 122.79 1 <0.05
CELL_PHONE Driver was using cell phone 426 1.0 28 1.1 454 0.16 1 0.687
SPEEDING Crash involved speeding car 1261 3.1 260 10.5 1521 376.78 1 <0.05
AGGRESSIVE Crash involved aggressive driving 18522 45.3 916 36.9 19438 67.60 1 <0.05
DRIVER1617 Crash involved at least one driver aged 16–17 674 1.6 12 0.5 686 20.45 1 <0.05
DRIVER65PLUS Crash involved at least one driver aged 65+ 4237 10.4 119 4.8 4356 80.60 1 <0.05

The table above provides a cross-tabulation of the dependent variable with each of the binary predictors. We use the Chi-Square test, which is a statistical method used to evaluate whether there is a significant association between two categorical variables. This test compares the observed frequencies in each category with the expected frequencies under the assumption that the variables are independent. As usual, a high value of the \(\chi^2\) statistic, and a p-value lower than 0.05, suggest that there is evidence to reject the null hypothesis in favor of the alternative, indicating an association between drunk driving and crash outcomes.

Here, we apply the Chi-Square test to explore the association between drinking driver indicators in crashes DRINKING_D and various binary crash-related characteristics. The hypotheses and results are summarized below:

Crash resulted in fatality or major injury FATAL_OR_M

  • Null Hypothesis (H0): The proportions of crashes resulting in fatality or major injury are the same for drinking and non-drinking drivers.

  • Alternative Hypothesis (Ha): The proportions of crashes resulting in fatality or major injury differ between drinking and non-drinking drivers.

Among crashes involving drinking drivers, 7.6% resulted in fatality or major injury, compared to only 2.9% of crashes involving non-drinking drivers. The P-value of Chi-Square statistic is less than 0.05, indicating a significant association between drinking drivers and crash severity. Therefore, we reject the null hypothesis in favor of the alternative hypothesis.

Crash involved an overturned vehicle OVERTURNED

  • Null Hypothesis (H0): The proportions of crashes involving overturned vehicles are the same for drinking and non-drinking drivers.

  • Alternative Hypothesis (Ha): The proportions of crashes involving overturned vehicles differ between drinking and non-drinking drivers.

Among crashes involving drinking drivers, 4.4% involved an overturned vehicle, compared to only 1.5% of crashes involving non-drinking drivers. The P-value of Chi-Square statistic is less than 0.05,, indicating a significant association between drinking drivers and overturned crashes. Therefore, we reject the null hypothesis in favor of the alternative hypothesis.

Driver was using cell phone CELL_PHONE

  • Null Hypothesis (H0): The proportions of crashes involving cell phone use are the same for drinking and non-drinking drivers.

  • Alternative Hypothesis (Ha): The proportions of crashes involving cell phone use differ between drinking and non-drinking drivers.

Among crashes involving drinking drivers, 1.0% involved cell phone use, compared to 1.1% of crashes involving non-drinking drivers. The P-value of Chi-Square statistic is more than 0.05,, suggesting no significant association with drinking driver indicators. Therefore, we fail to reject the null hypothesis.

Crash involved speeding car SPEEDING

  • Null Hypothesis (H0): The proportions of crashes involving speeding cars are the same for drinking and non-drinking drivers.

  • Alternative Hypothesis (Ha): The proportions of crashes involving speeding cars differ between drinking and non-drinking drivers.

Among crashes involving drinking drivers, 10.5% involved speeding, compared to only 3.1% of crashes involving non-drinking drivers. The P-value of Chi-Square statistic is less than 0.05,, indicating a strong link between drinking drivers and speeding. Therefore, we reject the null hypothesis in favor of the alternative hypothesis.

Crash involved aggressive driving AGGRESSIVE

  • Null Hypothesis (H0): The proportions of crashes involving aggressive driving are the same for drinking and non-drinking drivers.

  • Alternative Hypothesis (Ha): The proportions of crashes involving aggressive driving differ between drinking and non-drinking drivers.

Among crashes involving drinking drivers, 63.1% involved aggressive driving, compared to 54.7% of crashes involving non-drinking drivers. The P-value of Chi-Square statistic is less than 0.05,indicating he association is statistically significant. Therefore, we reject the null hypothesis in favor of the alternative hypothesis.

Crash involved at least one driver aged 16–17 DRIVER1617

  • Null Hypothesis (H0): The proportions of crashes involving at least one driver aged 16-17 are the same for drinking and non-drinking drivers.

  • Alternative Hypothesis (Ha): The proportions of crashes involving at least one driver aged 16-17 differ between drinking and non-drinking drivers.

Among crashes involving drinking drivers, 0.5% involved at least one teenage driver (16–17 years old), compared to 1.6% of crashes involving non-drinking drivers. The Chi-Square statistic is 19.71 (p < 0.001), indicating a significant association. Therefore, we reject the null hypothesis in favor of the alternative hypothesis.

Crash involved at least one driver aged 65 or older DRIVER65PLUS

  • Null Hypothesis (H0): The proportions of crashes involving at least one driver aged 65 or older are the same for drinking and non-drinking drivers.

  • Alternative Hypothesis (Ha): The proportions of crashes involving at least one driver aged 65 or older differ between drinking and non-drinking drivers.

Among crashes involving drinking drivers, 5.2% involved at least one driver aged 65 or older, compared to 10.4% of crashes involving non-drinking drivers. The Chi-Square statistic is 79.99 (p < 0.001), indicating a statistically significant relationship between alcohol involvement and older drivers.. Therefore, we reject the null hypothesis in favor of the alternative hypothesis.

The Chi-Square test results indicate significant associations between drinking driver indicators and most crash-related variables, with the exception of cell phone use, where no significant relationship was found. For all other variables, we reject the null hypothesis in favor of the alternative hypothesis, confirming the presence of significant associations.

Independent Variables - Continuous

Then, we examine the relationship between our binary dependent variable DRINKING_D and continuous predictors PCTBACHMOR and MEDHHINC.

continuous_vars <- c("PCTBACHMOR", "MEDHHINC")

results_list <- list()

for (var in continuous_vars) {
  means <- tapply(crashes[[var]], crashes$DRINKING_D, mean, na.rm = TRUE)
  sds   <- tapply(crashes[[var]], crashes$DRINKING_D, sd, na.rm = TRUE)
  t_test_result <- t.test(crashes[[var]] ~ crashes$DRINKING_D)

  description <- ifelse(var == "PCTBACHMOR", "Percentage of population with bachelor's degree or more",
                        ifelse(var == "MEDHHINC", "Median household income", NA))

  results_list[[var]] <- data.frame(
    Variable         = var,
    Description      = description,
    Mean_No_Alcohol  = means["0"],
    SD_No_Alcohol    = sds["0"],
    Mean_Alcohol     = means["1"],
    SD_Alcohol       = sds["1"],
    T_Statistic      = t_test_result$statistic,
    DF               = t_test_result$parameter,
    P_Value          = t_test_result$p.value
  )
}

continuous_summary <- do.call(rbind, results_list)
row.names(continuous_summary) <- NULL

# print
kable(continuous_summary[, c("Variable", "Description", "Mean_No_Alcohol", "SD_No_Alcohol",
                             "Mean_Alcohol", "SD_Alcohol",
                             "T_Statistic", "DF", "P_Value")],
      format = "html",
      col.names = c("Variable", "Description",
                    "Mean", "SD",
                    "Mean", "SD",
                    "t Stat", "DF", "p-value"),
      caption = "Summary of Continuous Variables") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                full_width = F,
                position = "center") %>%
  column_spec(1, bold = TRUE, width = "10em") %>%
  column_spec(2, bold = FALSE, width = "40em") %>%
  column_spec(3:4, width = "7em") %>%
  column_spec(5:6, width = "7em") %>%
  column_spec(7:9, width = "8em") %>%
  add_header_above(c(" " = 2,
                     "No Alcohol Involved (DRINKING_D = 0)" = 2,
                     "Alcohol Involved (DRINKING_D = 1)" = 2,
                     "T-Test Results" = 3))
Summary of Continuous Variables
No Alcohol Involved (DRINKING_D = 0)
Alcohol Involved (DRINKING_D = 1)
T-Test Results
Variable Description Mean SD Mean SD t Stat DF p-value
PCTBACHMOR Percentage of population with bachelor’s degree or more 16.6 18.2 16.6 18.7 -0.108 2778 0.914
MEDHHINC Median household income 31483.1 16930.1 31998.8 17810.5 -1.405 2764 0.160

We first look at the means and standard deviations (SD) of these variables for crashes that involve alcohol and those that do not. Then, we use the independent samples t-test to assess whether there is a significant association between the dependent variable and each of the continuous predictors. The t-test results include the t-statistic, degrees of freedom, and p-value.

Percentage of Population with Bachelor’s Degree or More PCTBACHMOR

  • Null Hypothesis (H0): The average values of the variable PCTBACHMOR are the same for crashes that involve drunk drivers and crashes that don’t.

  • Alternative Hypothesis (Ha): The average values of the variable PCTBACHMOR are different for crashes that involve drunk drivers and crashes that don’t.

Since the p-value is much greater than the 0.05 significance threshold (p = 0.914), we fail to reject the null hypothesis. This suggests there is no significant difference in the mean percentage of the population with a bachelor’s degree or more between crashes involving drinking and non-drinking drivers.

Median Household Income MEDHHINC

  • Null Hypothesis (H0): The average values of the variable MEDHHINC are the same for crashes that involve drunk drivers and crashes that don’t..

  • Alternative Hypothesis (Ha): The average values of the variable MEDHHINC are different for crashes that involve drunk drivers and crashes that don’t.

Since the p-value is greater than 0.05 (p = 0.160), we fail to reject the null hypothesis. There is no significant difference in median household income between crashes involving drinking and non-drinking drivers.

For both continuous predictors, PCTBACHMOR and MEDHHINC, the p-values from the t-tests are above the 0.05 significance threshold, indicating that there is no statistically significant difference between the two groups (drinking and non-drinking drivers) for these continuous variables. Therefore, we fail to reject the null hypothesis in both cases, meaning there is no significant association between alcohol involvement in crashes and these continuous predictors.

Logistic Regression Assumptions

Based on the correlation matrix and exploitative analysis result, most logistic regression assumptions are met. First, The binary dependent variable , DRINKING_D, fulfills the requirement for a binary variable (0 and 1). Second, the independence of observation is satisfied, as each crash is considered an independent event. Third, the assumption of no perfect multicollinearity is also met, as the correlation matrix shows low pairwise pearson correlations between predictors, with only the highest correlation being 0.48 between percent with bachelor’s degree and median household income. These correlation coefficients are all below 0.5, indicating that there is no perfect multicollinearity among the predictors. These correlation are not high enough to cause instability in the model. Additionally, the large sample size of over 43,300 observations ensure the model meet the assumption for sufficient sample size.

However, there is a potential violation in the assumption of linearity of log odds for continuous predictors, as high p-values in t-test suggest weal or non-linear relationships between percent with bachelor’s degree and median household income and the dependent variable.

Using Pearson correlation to measure associations between binary predictors have several limitations, as Pearson’s correlation is most appropriate for continuous normally distributed variables. For binary variables which only has two values (0 and 1), Person correlation can lead to less meaningful or interpretable correlation values, as the measure does not fully capture the association between two binary variables. Furthermore, Pearson correlation may underestimate or fail to reflect non-linear relationships that could potentially exist among binary variable.

Multicollinearity occurs when two or more predictor variables are highly correlated, potentially inflating standard errors and destabilizing coefficient estimates. An examination of our dataset’s correlation matrix reveals only low pairwise correlations with the highest of 0.48 between the percentage of residents with a bachelor’s degree and median household income. This value falls well below the conventional threshold of 0.7, indicating that our model is unlikely to suffer from coefficient instability due to collinear predictors. While Pearson’s correlation is not the optimal metric for binary variables, it nonetheless confirms the absence of any problematic multicollinearity in this analysis.

crashes <- crashes %>%
  mutate(across(c(FATAL_OR_M, OVERTURNED, CELL_PHONE, SPEEDING,
                  AGGRESSIVE, DRIVER1617, DRIVER65PLUS),
                ~ as.numeric(as.character(.))))

cor_matrix <- cor(crashes %>% dplyr::select(-c(CRN, DRINKING_D, AREAKEY, COLLISION_)), use = "pairwise.complete.obs", method = "pearson")


custom_label <- c(
  "Crash resulted in fatality or major injury" = "FATAL_OR_M",
  "Crash involved an overturned vehicle" = "OVERTURNED",
  "Driver was using cell phone" = "CELL_PHONE",
  "Crash involved speeding car" = "SPEEDING",
  "Crash involved aggressive driving" = "AGGRESSIVE",
  "Crash involved at least one driver 16 or 17 years old" = "DRIVER1617",
  "Crash involved at least one driver over 65 years old" = "DRIVER65PLUS",
  "% with bachelor’s degree" = "PCTBACHMOR",
  "Median household income" = "MEDHHINC"
)


rownames(cor_matrix) <- names(custom_label)
colnames(cor_matrix) <- names(custom_label)

ggcorrplot(cor_matrix,
           type = "lower",
           lab = TRUE,
           lab_size = 3,
           colors = c("#001219", "white", "#9b2226")) +
  labs(title = "Correlation Matrix for all Predictor Variables") +
  theme(plot.subtitle = element_text(size = 9, face = "italic"),
        plot.title = element_text(size = 12, face = "bold"),
        axis.text.x = element_text(size = 7),
        axis.text.y = element_text(size = 7),
        axis.title = element_text(size = 8))

logistic regression results

Our first logistic regression model includes all the predictors and presented the results of it below:

  • FATAL_OR_M: The presence of a fatality or major injury significant increases the odds of a drinking related crash, with an odds ratio of 2.257 (95% confident interval: 1.91 to 2.65) and a highly significant p-value (p < 0.001). This suggests that these types of crashes are more than double the odds of being associated with drinking drivers.
  • OVERTURNED: Overturned vehicles significantly increase the likelihood of it being a drinking related crash with and odd ratio of 2.532 (95% confident interval: 2.04 to 3.12) and a highly significant p-value (p < 0.001). This result implies that overturned vehicles are strongly associated with a drinking-driver incurred crashes.
  • CELL_PHONE: The use of celphone during a crash shows no statistically significent effect on the odds of a drinking-related crash, as the p-value is greater than 0.05 (P=0.881). The odd ratio close to 1 (OR=1.03, 95% confident interval: 0.68 to 1.49) indicates that use of cellphone no significantly meaning affect the odds of a drinking-related crash.
  • SPEEDING: Speeding is a highly significant predictor, with an odd ratio of 4.66 (95% confident interval: 3.97 to 5.45) and a p-value less than 0.001. This indicates that crashes involving speeding are more than four times as likely to involve alcohol.
  • AGGRESSIVE: Aggressive driving is associated with lower odds of drinking-related crashes, with an odds ratio of 0.551 (95% confident interval: 0.50 to 0.60) and a highly significant p-value (p < 0.001). This suggests that aggressive driving is less likely to be associated with drinking drivers.
  • DRIVER1617: Incidents involving drivers aged 16-17 are significantly less likely to associate with drinking-related crashes, with an odds ratio of 0.278 (95% confident interval: 0.148 to 0.471) and a highly significant p-value (p < 0.001). This probably caused by the fact that the drinking age in the US is 21, and drivers aged 16-17 are not legally allowed to drink alcohol.
  • DRIVER65PLUS: Incidents involving drivers aged 65 or older are also show significantly lower odds of drinking-related, with an odds ratio of 0.461 (95% confident interval: 0.38 to 0.55) and a highly significant p-value (p < 0.001). This suggests that older drivers are less likely to be involved in drinking-related crashes.
  • PCTBACHMOR: The percentage of the population with a bachelor’s degree or more shows no significant effect on the odds of a drinking-related crash, with an odds ratio of 1.000 (95% confident interval: 0.99 to 1.00) and a p-value greater than 0.05 (p = 0.775). This suggests that the educational attainment of the population does not significantly affect the likelihood of drinking-related crashes.
  • MEDHHINC: The median household income shows has a very slight statistically significant effect on the likelihood of drinking-related crash, with p-value <0.05 (p= 0.036) and an odds ratio of 1.000 (95% confident interval: 1.00 to 1.00). This suggests that higher median household income is associated with a very slight negligible effect in the odds of drinking-related crashes.

In summary, FATAL_OR_M, OVERTURNED, SPEEDING, AGGRESSIVE, DRIVER1617, and DRIVER65PLUS are the most significant predictors of drinking-related crashes (P<0.001), while CELL_PHONE and PCTBACHMOR show no significant effect. Among those, FATAL_OR_M, OVERTURNED, and SPEEDING are the most significant predictors associated with drinking-related crashes, with odds ratios greater than 2.5. The predictor MEDHHINC is marginally significant and has minimal effect on the odds of drinking-related crashes.

logit <- glm(DRINKING_D ~ FATAL_OR_M + OVERTURNED + CELL_PHONE + SPEEDING + AGGRESSIVE + DRIVER1617 + DRIVER65PLUS + PCTBACHMOR + MEDHHINC, data = crashes, family = binomial)

logitoutput <- summary(logit)
logitcoeff <- logitoutput$coefficients
or_ci <- exp(cbind(OR = coef(logit), confint(logit)))
## Waiting for profiling to be done...
logitcoeff[, "Pr(>|z|)"] <- round(logitcoeff[, "Pr(>|z|)"], 4)
final_output <- cbind(logitcoeff, or_ci)
final_output %>%
kable("html", escape = FALSE, align = "cccccc") %>%
kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width        = FALSE,
    position          = "center"
  )
Estimate Std. Error z value Pr(>|z|) OR 2.5 % 97.5 %
(Intercept) -2.733 0.046 -59.563 0.000 0.065 0.059 0.071
FATAL_OR_M 0.814 0.084 9.713 0.000 2.257 1.910 2.653
OVERTURNED 0.929 0.109 8.509 0.000 2.532 2.035 3.122
CELL_PHONE 0.030 0.198 0.149 0.881 1.030 0.684 1.488
SPEEDING 1.539 0.081 19.107 0.000 4.660 3.974 5.450
AGGRESSIVE -0.597 0.048 -12.493 0.000 0.551 0.501 0.604
DRIVER1617 -1.280 0.293 -4.367 0.000 0.278 0.148 0.471
DRIVER65PLUS -0.775 0.096 -8.081 0.000 0.461 0.380 0.553
PCTBACHMOR 0.000 0.001 -0.286 0.775 1.000 0.997 1.002
MEDHHINC 0.000 0.000 2.091 0.036 1.000 1.000 1.000

Then, we test different cutoff threshold to see the model overall performance through the specificity, sensitivity, and misclassficiantion rate. The table below presents the specificity, sensitivity, and misclassification rates for various probability cut-offs in predicting the likelihood of a drinking-related crash.

The probability cut-off value of 0.50 yields the lowest misclassfication rate of 0.057. At this threshold, specificity is maximized at 1, but sensitivity is relative low at 0.02. This indicate the model capture relatively few true positive cases of drinking-related crashes, but it is very good at identifying non-drinking related crashes.

The highest misclassfication rate occurs at the cut-off of 0.02 with a rate of 0.889. At this threshold, sensitivity is high at 0.899, capturing a high proportion of true positive cases, but specificity is very low at 0.058. This indicates that the model misclassifies a large number of non-drinking related crashes as drinking-related crashes.

cutoffs <- c(0.02, 0.03, 0.05, 0.07, 0.08, 0.09, 0.10, 0.15, 0.20, 0.50)
results <- data.frame(
  Cutoff = cutoffs,
  Sensitivity = NA_real_,
  Specificity = NA_real_,
  MisclassificationRate = NA_real_
)

#–– 3. Pull out true labels and predicted probabilities
labels      <- crashes$DRINKING_D
predictions <- fitted(logit)   # or logit$fitted.values

#–– 4. Metric‐calculation function
calculate_metrics <- function(cutoff, labels, preds) {
  preds_bin <- ifelse(preds >= cutoff, 1, 0)
  tp  <- sum(preds_bin == 1 & labels == 1)
  tn  <- sum(preds_bin == 0 & labels == 0)
  fp  <- sum(preds_bin == 1 & labels == 0)
  fn  <- sum(preds_bin == 0 & labels == 1)
  sens <- tp / (tp + fn)
  spec <- tn / (tn + fp)
  mis  <- (fp + fn) / length(labels)
  c(Sensitivity = sens,
    Specificity = spec,
    MisclassificationRate = mis)
}

#–– 5. Populate results table
for (i in seq_along(cutoffs)) {
  results[i, 2:4] <- calculate_metrics(cutoffs[i], labels, predictions)
}

#–– 6. Render as a styled kable
results %>%
  kable(
    caption = "Model Performance Metrics Across Probability Cutoffs",
    digits  = 3,
    align   = c("c","c","c","c")
  ) %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width        = FALSE,
    position          = "center"
  )
Model Performance Metrics Across Probability Cutoffs
Cutoff Sensitivity Specificity MisclassificationRate
0.02 0.984 0.058 0.889
0.03 0.981 0.064 0.884
0.05 0.735 0.469 0.516
0.07 0.221 0.914 0.126
0.08 0.185 0.939 0.105
0.09 0.168 0.946 0.099
0.10 0.164 0.948 0.097
0.15 0.104 0.972 0.078
0.20 0.023 0.995 0.060
0.50 0.002 1.000 0.057

The ROC curve below show the trade of between sensitivity and specificity across various cut-offs threshold for the logistic regression model. An ideal model would reach the top-left corner of the ROC space, where sensitivity and specificity all equal to one, which would mean perfect classifications. Our ROC curve lies beneath the ideal point, indicating trade-offs between sensitivity and specificity at each cut-off.

ggplot(roc, aes(d = labels, m = predictions)) +
  geom_roc(n.cuts = 50, labels = FALSE, colour = "#283d3b") +
  labs(title = "ROC Curve") +
  style_roc(theme = theme_grey) +
  geom_abline(slope = 1, intercept = 0, size = 1, color = "#c44536") +
  theme(
    plot.subtitle = element_text(size = 9, face = "italic"),
    plot.title = element_text(size = 12, face = "bold"),
    axis.text.x = element_text(size = 8),
    axis.text.y = element_text(size = 8),
    axis.title = element_text(size = 9),
    panel.background = element_blank(),
    panel.border = element_rect(colour = "grey", fill = NA, linewidth = 0.8)
  )

We calculated the optimal cut-off by minimizing the Euclidean distance from the ROC curve to the top-left corner of the ROC space, which represents the ideal point where both sensitivity and specificity are equal to 1. This cut-off of 0.064 provides a balance approaches between specificity and sensitivity, with a sensitivity of 0.661 and specificity of 0.545.

pred <- prediction(roc$predictions, roc$labels)
roc.perf <- performance(pred, measure = "tpr", x.measure = "fpr")

opt.cut <- function(perf, pred) {
  cut.ind <- mapply(FUN = function(x, y, p) {
    d <- (x - 0)^2 + (y - 1)^2
    ind <- which(d == min(d))
    c(sensitivity = y[[ind]], specificity = 1 - x[[ind]], cutoff = p[[ind]])
  }, perf@x.values, perf@y.values, pred@cutoffs)

  cut.df <- data.frame(
    sensitivity = cut.ind[1, ],
    specificity = cut.ind[2, ],
    cutoff = cut.ind[3, ]
  )
  rownames(cut.df) <- NULL
  return(cut.df)
}

optimal_cutoffs_df <- opt.cut(roc.perf, pred)
optimal_cutoffs_df %>%
  kable("html", escape = FALSE, align = "ccc") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width        = FALSE,
    position          = "center"
  )
sensitivity specificity cutoff
0.661 0.545 0.064

In the above section, the optimal cut-off based on the minimum misclassification rate was 0.50, which yielded a misclassfication rate of 0.057. This threshold focused more on prioritizing specificity (1.00), but resulting in low sensitivity (0.02). In contrast, the optimal cut-off based on the ROC curve was 0.064, which provided a balance between sensitivity (0.661) and specificity (0.545). This cut-off is more suitable for practical applications where both false positives and false negatives are important to consider.

The AREA Under the ROC Curve (AUC) for our model is 0.640 suggests that the model has poor discrimination based on the metrix provided in the method section. The AUC value mean that if we randomly select one positive case and negative case, the model has a 64% chance of correctly ranking the positive case higher than the negative case. In practical, this indicates that while the model is able to distinguish between crashes with and without alcohol involvement to some extent, its performance is limited and may misclassify a substantial number of observations.

auc.perf <-  performance(pred, measure ="auc")
auc.value <- auc.perf@y.values
cat(sprintf("AUC: %.3f\n", auc.value))
## AUC: 0.640

The second logistic model we ran only includes the binary predictors. PCTBACHMOR and MEDHHINC were not included as they were not statistically significant predictors in the first model. However, in the second model, the exclusion of these two predictors did not lead to any predictors becoming significant or any previous significant predictors becoming non-significant. The odds ratios (OR) for the binary predictors in both models are very similar, suggesting that removing PCTBACHMOR and MEDHHINC had little impact on the estimated effects of the other variables.

logit2 <- glm(DRINKING_D ~ FATAL_OR_M + OVERTURNED + CELL_PHONE + SPEEDING + AGGRESSIVE + DRIVER1617 + DRIVER65PLUS, data = crashes, family = binomial)

logitoutput2 <- summary(logit2)
logitcoeff2 <- logitoutput2$coefficients
or_ci2 <- exp(cbind(OR = coef(logit2), confint(logit2)))
## Waiting for profiling to be done...
logitcoeff2[, "Pr(>|z|)"] <- round(logitcoeff2[, "Pr(>|z|)"], 4)
final_output2 <- cbind(logitcoeff2, or_ci2)
final_output2 %>%
  kable("html", escape = FALSE, align = "cccccc") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width        = FALSE,
    position          = "center"
  )
Estimate Std. Error z value Pr(>|z|) OR 2.5 % 97.5 %
(Intercept) -2.652 0.028 -96.324 0.000 0.071 0.067 0.074
FATAL_OR_M 0.809 0.084 9.662 0.000 2.246 1.901 2.640
OVERTURNED 0.940 0.109 8.619 0.000 2.559 2.057 3.156
CELL_PHONE 0.031 0.198 0.157 0.875 1.032 0.685 1.491
SPEEDING 1.540 0.081 19.128 0.000 4.666 3.980 5.457
AGGRESSIVE -0.594 0.048 -12.433 0.000 0.552 0.503 0.606
DRIVER1617 -1.272 0.293 -4.338 0.000 0.280 0.149 0.475
DRIVER65PLUS -0.766 0.096 -8.004 0.000 0.465 0.383 0.558

The Akaike Information Criterion (AIC) for both models is 18360. AIC is a measure of model quality that balances goodness of fit with model complexity. Since the AIC is the same for both models, it suggests that the second model (with only binary predictors) is just as good as the first model (with all predictors) in terms of explaining the data. This indicates that the additional complexity of including PCTBACHMOR and MEDHHINC in the first model does not provide a significant improvement in model fit, and thus, the simpler model with only binary predictors is preferred.

aic_table <- AIC(logit, logit2)
colnames(aic_table) <- c("Degree of Freedom", "AIC")
rownames(aic_table) <- c("Model 1: All Predictors", "Model 2: Binary Predictors Only")
aic_table %>%
  kable("html", escape = FALSE, align = "cc") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width        = FALSE,
    position          = "center"
  )
Degree of Freedom AIC
Model 1: All Predictors 10 18360
Model 2: Binary Predictors Only 8 18360

Discussion

In this paper, we examined over 43,000 motor vehicle crashes in Philadelphia from 2008 to 2012 to identify which factors were associated with alcohol involvement using logistic regression. We explored a mix of binary crash-level indicators and neighborhood-level continuous predictors to assess their relationship with the likelihood that a crash involved a drinking driver.

Several variables emerged as strong predictors of alcohol-involved crashes. Crashes that resulted in fatalities or major injuries, involved overturned vehicles, or involved speeding were significantly more likely to include a drinking driver. On the other hand, the presence of aggressive driving, teenage drivers, and elderly drivers were all significantly associated with lower odds of alcohol involvement. Cell phone use showed no significant association, nor did the neighborhood-level variables—percentage of residents with a bachelor’s degree and median household income.

While many results aligned with expectations—particularly the strong links between alcohol involvement and speeding or severe crashes—the lack of significance for socioeconomic predictors was somewhat unexpected. It suggests that while neighborhood context is often important in shaping health and safety outcomes, it may play a more limited role in predicting whether an individual crash involved alcohol. Similarly, the inverse relationship between aggressive driving and alcohol involvement may reflect different behavioral risk profiles, where alcohol impairment substitutes, rather than coincides with, certain forms of recklessness.

Logistic regression was an appropriate modeling choice given the binary outcome and the large, independent dataset. However, since only 5.7% of crashes involved a drinking driver, the problem qualifies as a rare event scenario. In such cases, alternative approaches like rare event logistic regression, as proposed by Paul Allison, may offer improved parameter estimates and better classification performance, especially for policy applications that require accurate identification of low-probability events.

This analysis has several limitations. The dataset does not include contextual factors such as time of day, proximity to bars, or day of the week, which could provide additional explanatory power. Pearson correlation was used to assess multicollinearity, but it is not ideal for binary variables and may overlook more complex interactions. Although multicollinearity was not a concern, the model’s AUC of 0.64 indicates limited predictive ability—adequate for identifying general associations but insufficient for high-stakes prediction. Lastly, underreporting of alcohol use or misclassification in crash records could affect the reliability of the outcome variable.

LS0tCnRpdGxlOiAiVGhlIEFwcGxpY2F0aW9uIG9mIExvZ2lzdGljIFJlZ3Jlc3Npb24gdG8gRXhhbWluZSB0aGUgUHJlZGljdG9ycyBvZiBDYXIgQ3Jhc2hlcyBDYXVzZWQgYnkgQWxjb2hvbCIKYXV0aG9yOiAiWmhhbmNoYW8gWWFuZywgSGFveXUgWmh1LCBLYXZhbmEgUmFqdSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRoZW1lOiBmbGF0bHkKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGNvZGVfZG93bmxvYWQ6IHllcwogICAgbWF0aGpheDogZGVmYXVsdAotLS0KCktleXdvcmRzOiBMb2dpc3RpYyByZWdyZXNzaW9uLCBBa2Fpa2UgSW5mb3JtYXRpb24gQ3JpdGVyaW9uIChBSUMpLCBST0MgY3VydmUsIEFyZWEgVW5kZXIgQ3VydmUgKEFVQyksIFNlbnNpdGl2aXR5LCBTcGVjaWZpY2l0eSwgTWlzY2xhc3NpZmljYXRpb24gUmF0ZQoKR2l0SHViIFJlcG9zaXRvcnk6IFtNVVNBNTAwMC1Mb2dpc3RpYy1SZWdyZXNzaW9uXShodHRwczovL2dpdGh1Yi5jb20vTVVTQS1aaGFuY2hhby9NVVNBNTAwMC1Mb2dpc3RpYy1SZWdyZXNzaW9uKSBcfApbV2Vic2l0ZV0oaHR0cHM6Ly9tdXNhLXpoYW5jaGFvLmdpdGh1Yi5pby9NVVNBNTAwMC1Mb2dpc3RpYy1SZWdyZXNzaW9uLykKCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCgpvcHRpb25zKHNjaXBlbj05OTkpCm9wdGlvbnMoZGlnaXRzID0gMykKCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KGhlcmUpCmxpYnJhcnkoa2FibGVFeHRyYSkKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkoZ21vZGVscykKbGlicmFyeShnZ2NvcnJwbG90KQpsaWJyYXJ5KFJPQ1IpCmxpYnJhcnkocGxvdFJPQykKCmxpYnJhcnkoYW9kKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ21vZGVscykKbGlicmFyeShubmV0KQpsaWJyYXJ5KERBQUcpCmxpYnJhcnkoUk9DUikKbGlicmFyeSh4dGFibGUpCmBgYAoKYGBge3IsIGluY2x1ZGU9RkFMU0V9CmNyYXNoZXMgPC0gcmVhZC5jc3YoImRhdGEvTG9naXN0aWNfUmVncmVzc2lvbl9EYXRhLmNzdiIpCmBgYAoKIyBJbnRyb2R1Y3Rpb24KCk1vdG9yIHZlaGljbGUgY3Jhc2hlcyByZW1haW4gb25lIG9mIHRoZSBsZWFkaW5nIGNhdXNlcyBvZiBpbmp1cnkgYW5kIGRlYXRoIGluIHVyYmFuIGVudmlyb25tZW50cyBhY3Jvc3MgdGhlIFVuaXRlZCBTdGF0ZXMuIEFtb25nIHRoZXNlIGluY2lkZW50cywgKipjcmFzaGVzIGludm9sdmluZyBhbGNvaG9sLWltcGFpcmVkIGRyaXZlcnMgYXJlIHBhcnRpY3VsYXJseSBjb25jZXJuaW5nIGJlY2F1c2UgdGhleSBhY2NvdW50IGZvciBhIGRpc3Byb3BvcnRpb25hdGVseSBoaWdoIG51bWJlciBvZiBmYXRhbGl0aWVzIGFuZCBzZXZlcmUgaW5qdXJpZXMqKi4gQWNjb3JkaW5nIHRvIG5hdGlvbmFsIHN0YXRpc3RpY3MsIG5lYXJseSBvbmUtdGhpcmQgb2YgYWxsIHRyYWZmaWMtcmVsYXRlZCBkZWF0aHMgaW52b2x2ZSBhIGRyaXZlciB1bmRlciB0aGUgaW5mbHVlbmNlIG9mIGFsY29ob2wsIHVuZGVyc2NvcmluZyB0aGUgY29udGludWVkIHB1YmxpYyBoZWFsdGggcmlza3MgYXNzb2NpYXRlZCB3aXRoIGltcGFpcmVkIGRyaXZpbmcuIEluIFBoaWxhZGVscGhpYSwgd2hlcmUgdHJhZmZpYyBkZW5zaXR5LCByb2Fkd2F5IGRlc2lnbiwgYW5kIG5laWdoYm9yaG9vZCBjaGFyYWN0ZXJpc3RpY3MgdmFyeSB3aWRlbHksIGl0IGlzIGVzcGVjaWFsbHkgaW1wb3J0YW50IHRvIHVuZGVyc3RhbmQgdGhlIGZhY3RvcnMgdGhhdCBjb250cmlidXRlIHRvIGFsY29ob2wtcmVsYXRlZCBjcmFzaGVzLiBCeSBpZGVudGlmeWluZyB0aGVzZSBmYWN0b3JzLCBjaXR5IG9mZmljaWFscyBhbmQgcHVibGljIGhlYWx0aCBwcm9mZXNzaW9uYWxzIGNhbiBkZXNpZ24gbW9yZSB0YXJnZXRlZCBpbnRlcnZlbnRpb25zIHRvIHJlZHVjZSB0aGUgcHJldmFsZW5jZSBhbmQgc2V2ZXJpdHkgb2Ygc3VjaCBpbmNpZGVudHMuIFRoaXMgYW5hbHlzaXMgdXNlcyBjcmFzaCBkYXRhIGZyb20gUGhpbGFkZWxwaGlhIGNvdmVyaW5nIHRoZSB5ZWFycyAyMDA4IHRvIDIwMTIgdG8gaW52ZXN0aWdhdGUgaG93IHZhcmlvdXMgY2hhcmFjdGVyaXN0aWNzIG9mIGNyYXNoZXMgYW5kIG5laWdoYm9yaG9vZHMgYXJlIGFzc29jaWF0ZWQgd2l0aCB0aGUgcHJlc2VuY2Ugb2YgYSBkcmlua2luZyBkcml2ZXIuCgpUaGlzIHN0dWR5IGV4cGxvcmVzIHRoZSBmYWN0b3JzIGFzc29jaWF0ZWQgd2l0aCBEVUkgaW4gdHJhZmZpYyBjcmFzaGVzIGluIFBoaWxhZGVscGhpYSBieSBleGFtaW5pbmcgYSBzZXQgb2YgYmluYXJ5IGFuZCBjb250aW51b3VzIHByZWRpY3RvcnMuIFRoZXNlIGluY2x1ZGUgaW5kaWNhdG9ycyBvZiAqKmNyYXNoIHNldmVyaXR5KiogKENyYXNoZXMgcmVzdWx0ZWQgaW4gZmF0YWxpdHkgb3IgbWFqb3IgaW5qdXJ5KSwgKipyaXNreSBkcml2aW5nIGJlaGF2aW9ycyoqIChDcmFzaGVzIGludm9sdmVkIGFuIG92ZXJ0dXJuZWQgdmVoaWNsZSwgc3BlZWRpbmcgY2FyIGFuZCBhZ2dyZXNzaXZlIGRyaXZpbmcgb3IgRHJpdmVyIHdhcyB1c2luZyBjZWxsIHBob25lKSwgKipkcml2ZXIgZGVtb2dyYXBoaWNzKiogKENyYXNoZXMgaW52b2x2ZWQgYXQgbGVhc3Qgb25lIGRyaXZlciB3aG8gd2FzIDE2IG9yIDE3IHllYXJzIG9sZCBhbmQgQ3Jhc2hlcyBpbnZvbHZlZCBhdCBsZWFzdCBvbmUgZHJpdmVyIHdobyB3YXMgYXQgbGVhc3QgNjUgeWVhcnMgb2xkKSwgYW5kICoqbmVpZ2hib3Job29kLWxldmVsIHNvY2lvZWNvbm9taWMgY2hhcmFjdGVyaXN0aWNzKiogKHBlcmNlbnRhZ2Ugd2l0aCBiYWNoZWxvcuKAmXMgZGVncmVlIG9yIG1vcmUsIE1lZGlhbiBob3VzZWhvbGQgaW5jb21lKS4gQW1vbmcgdGhlbSwgY3Jhc2hlcyByZXN1bHRpbmcgaW4gZmF0YWxpdGllcyBvciBtYWpvciBpbmp1cmllcyBhcmUgbW9yZSBsaWtlbHkgdG8gaW52b2x2ZSBhbGNvaG9sLCBhcyBpbnRveGljYXRlZCBkcml2ZXJzIGhhdmUgc2xvd2VyIHJlYWN0aW9uIHRpbWVzIGFuZCBwb29yZXIganVkZ21lbnQuIEJlaGF2aW9ycyBzdWNoIGFzIHNwZWVkaW5nLCBhZ2dyZXNzaXZlIGRyaXZpbmcsIGFuZCBvdmVydHVybmluZyBhcmUgbW9yZSBjb21tb24gaW4gaGlnaC1yaXNrIHNpdHVhdGlvbnMgb2Z0ZW4gYXNzb2NpYXRlZCB3aXRoIGFsY29ob2wgaW1wYWlybWVudC4gRGlzdHJhY3Rpb25zIGxpa2UgY2VsbHBob25lIHVzZSBtYXkgbm90IGJlIGRpcmVjdGx5IGxpbmtlZCB0byBhbGNvaG9sIHVzZSwgYnV0IHRoZXkgcmVmbGVjdCBhIGJyb2FkZXIgZGlzcmVnYXJkIGZvciByb2FkIHNhZmV0eSB0aGF0IG1pZ2h0IG92ZXJsYXAgd2l0aCBpbXBhaXJlZCBkcml2aW5nIHRlbmRlbmNpZXMuIEFnZSBhbHNvIHBsYXlzIGEgcm9sZSBhcyB5b3VuZ2VyIGRyaXZlcnMgKGFnZXMgMTbigJMxNykgYXJlIGxlc3MgZXhwZXJpZW5jZWQgYW5kIG1heSBiZSBtb3JlIHByb25lIHRvIHJpc2stdGFraW5nLCB3aGlsZSBvbGRlciBkcml2ZXJzICg2NSspIHR5cGljYWxseSBzaG93IGxvd2VyIGFsY29ob2wgaW52b2x2ZW1lbnQgYmVjYXVzZSBvZiBoZWFsdGggY29uY2VybnMgb3IgbGlmZXN0eWxlIGRpZmZlcmVuY2VzLiBCZXlvbmQgZHJpdmVyIGJlaGF2aW9yLCBuZWlnaGJvcmhvb2QtbGV2ZWwgY2hhcmFjdGVyaXN0aWNzIHN1Y2ggYXMgZWR1Y2F0aW9uIGFuZCBpbmNvbWUgbWF5IGFsc28gaW5mbHVlbmNlIHRoZSBsaWtlbGlob29kIG9mIGFsY29ob2wtaW52b2x2ZWQgY3Jhc2hlcy4gQXJlYXMgd2l0aCBoaWdoZXIgcGVyY2VudGFnZXMgb2YgY29sbGVnZS1lZHVjYXRlZCByZXNpZGVudHMgbWF5IGhhdmUgZ3JlYXRlciBhd2FyZW5lc3Mgb2YgZHJ1bmsgZHJpdmluZyByaXNrcy4gV2VhbHRoaWVyIG5laWdoYm9yaG9vZHMgbWlnaHQgYWxzbyBleGhpYml0IGxvd2VyIHJhdGVzIG9mIGFsY29ob2wtcmVsYXRlZCBjcmFzaGVzIGFzIHRoZXkgaGF2ZSBhY2Nlc3MgdG8gZ3JlYXRlciBhdmFpbGFiaWxpdHkgb2YgcmVzb3VyY2VzIGFuZCBzdXBwb3J0IHN5c3RlbXMuCgpJbiB0aGlzIHJlcG9ydCwgd2UgdXNlIFIgdG8gcGVyZm9ybSAqKmxvZ2lzdGljIHJlZ3Jlc3Npb24gYW5hbHlzaXMqKiwgZXhhbWluaW5nIHRoZSBzdGF0aXN0aWNhbCByZWxhdGlvbnNoaXBzIGJldHdlZW4gdGhlIHNlbGVjdGVkIHByZWRpY3RvcnMgYW5kIHRoZSBsaWtlbGlob29kIHRoYXQgYSBjcmFzaCBpbnZvbHZlZCBhIGRyaW5raW5nIGRyaXZlciBhY3Jvc3MgUGhpbGFkZWxwaGlhLgoKIyBNZXRob2QKCiMjIElzc3VlcyB3aXRoIE9MUyBSZWdyZXNzaW9uCgpUaGUgT0xTIHJlZ3Jlc3Npb24gbW9kZWwgY2FuIGJlIGV4cHJlc3NlZCBhcyBmb2xsb3dpbmcgZm9ybXVsYToKCiQkCnkgPSBcYmV0YV8wICsgXGJldGFfMXhfMSArIFxiZXRhXzJ4XzIgKyAuLi4gKyBcYmV0YV9reF9rICsgXGVwc2lsb24KJCQKCndoZXJlOgoKLSBcKHlcKSBpcyB0aGUgZGVwZW5kZW50IHZhcmlhYmxlCi0gXCh4XzEsIHhfMiwgLi4uLCB4X2tcKSBhcmUgdGhlIGluZGVwZW5kZW50IHZhcmlhYmxlcwotIFwoXGJldGFfMCwgXGJldGFfMSwgXGJldGFfMiwgLi4uLCBcYmV0YV9rXCkgYXJlIHRoZSBjb2VmZmljaWVudHMKLSBcKFxlcHNpbG9uXCkgaXMgdGhlIGVycm9yIHRlcm0KClVzaW5nIE9MUyByZWdyZXNzaW9uIHRvIG1vZGVsIGJpbmFyeSBvdXRjb21lcyBjYW4gbGVhZCB0byBzZXZlcmFsIGlzc3VlczoKCi0gRmlyc3QsIGluIHRoZSBPTFMgcmVncmVzc2lvbiwgXChcYmV0YV8xXCkgaXMgaW50ZXJwcmV0ZWQgYXMgdGhlIGFtb3VudCBvZiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIFwoeVwpIGNoYW5nZXMgd2hlbiBcKHhfMVwpIGluY3JlYXNlcyBieSBvbmUgdW5pdCwgaG9sZGluZyBhbGwgb3RoZXIgdmFyaWFibGVzIGNvbnN0YW50LiBIb3dldmVyLCB3aGVuIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgaXMgYmluYXJ5LCBhIG9uZSB1bml0IGluY3JlYXNlIGluIFwoeF8xXCkgcmVzdWx0cyBpbiBcKFxiZXRhXzFcKSBpbmNyZWFzZSBpbiBcKHlcKSBubyBsb25nZXIgbWFrZXMgc2Vuc2UsIGFzIFwoeVwpIGNhbiBjaGFuZ2Ugb25seSBmcm9tIDAgdG8gMSBvciBmcm9tIDEgdG8gMC4gVGhpcyBsZWFkcyB0byBzb21lIGludGVycHJldGF0aW9uIGlzc3Vlcy4KLSBTZWNvbmQsIE9MUyByZWdyZXNzaW9uIGFzc3VtZXMgYSBsaW5lYXIgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHByZWRpY3RvcnMgYW5kIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUuIFdpdGggYSBiaW5hcnkgZGVwZW5kZW50IHZhcmlhYmxlLCB0aGlzIGFzc3VtcHRpb24gbm8gbG9uZ2VyIGhvbGRzLCBhcyBiaW5hcnkgb3V0Y29tZXMgYXJlIGluaGVyZW50bHkgbm8gbGluZWFyLgotIFRoaXJkLCBPTFMgYWxzbyBhc3N1bWVzIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIHJlc2lkdWFscy4gSG93ZXZlciwgd2l0aCBiaW5hcnkgb3V0Y29tZSwgdGhlIHJlc2lkdWFscyBhcmUgbm90IG5vcm1hbGx5IGRpc3RyaWJ1dGVkLiBJbnN0ZWFkLCB0aGV5IGZvbGxvdyBhIGJpbm9taWFsIGRpc3RyaWJ1dGlvbi4KLSBGaW5hbGx5LCBPTFMgcmVncmVzc2lvbiBoYXMgYW5vdGhlciBhc3N1bXB0aW9uIG9mIGhvbW9zY2VkYXN0aWNpdHksIHdoaWNoIG1lYW5zIHRoYXQgdGhlIHZhcmlhbmNlIG9mIHRoZSByZXNpZHVhbHMgaXMgY29uc3RhbnQgYWNyb3NzIGFsbCBsZXZlbHMgb2YgdGhlIGluZGVwZW5kZW50IHZhcmlhYmxlcy4gSG93ZXZlciwgd2l0aCBiaW5hcnkgb3V0Y29tZXMsIHRoaXMgYXNzdW1wdGlvbiBpcyB2aW9sYXRlZCwgYXMgdGhlIHZhcmlhbmNlIG9mIHRoZSByZXNpZHVhbHMgaXMgbm90IGNvbnN0YW50LiBJdCB2YXJpZXMgd2l0aCB0aGUgcHJlZGljdGVkIHByb2JhYmlsaXR5LCBsZWFkaW5nIHRvIGhldGVyb3NjZWRhc3RpY2l0eS4KCkFsbCB0aG9zZSB2aW9sYXRpb25zIG9mIHRoZSBPTFMgcmVncmVzc2lvbiBhc3N1bXB0aW9ucyBhZmZlY3QgdGhlIHZhbGlkaXR5IG9mIHRoZSBtb2RlbCBhbmQgdGhlIGludGVycHJldGF0aW9uIG9mIHRoZSBjb2VmZmljaWVudHMuIEluIHRoaXMgd2F5LCB3ZSBuZWVkIHRvIHVzZSBhIGRpZmZlcmVudCBhcHByb2FjaCB0byBtb2RlbCBiaW5hcnkgb3V0Y29tZXMuCgojIyBMb2dpc3RpYyBSZWdyZXNzaW9uIENvbmNlcHRzCgpMb2dpc3RpYyByZWdyZXNzaW9uIHByb3ZpZGUgYSB3YXkgZm9yIHVzIHRvIGdldCBhcm91bmQgYWJvdmUtbWVudGlvbmVkIGlzc3Vlcy4gSW5zdGVhZCBvZiBwcmVkaWN0aW5nIHRoZSB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIFwoeVwpIGRpcmVjdGx5LCBsb2dpc3RpYyByZWdyZXNzaW9uIHByZWRpY3RzIHRoZSBwcm9iYWJpbGl0eSBvZiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIFwoeVwpIGJlaW5nIGVxdWFsIHRvIDEuIFRoaXMgY2FuIGJlIGV4cGxhaW5lZCB0aHJvdWdoIHRoZSBjb25jZXB0IG9mIG9kZHMuIFRoZSAqKm9kZHMqKiBvZiBhbiBldmVudCBpcyBhIHJhdGlvIHRoYXQgY29tcGFyZXMgdGhlIGxpa2VsaWhvb2Qgb2YgdGhlIGV2ZW50IGhhcHBlbmluZyB0byB0aGUgbGlrZWxpaG9vZCBvZiBpdCBub3QgaGFwcGVuaW5nLiBUaGUgb2RkcyBvZiBhbiBldmVudCBjYW4gYmUgZXhwcmVzc2VkIGFzOgoKJCQKXHRleHR7T2Rkc30gPSBcZnJhY3tcdGV4dHtQcm9iYWJpbGl0eSBvZiBFdmVudCBIYXBwZW5pbmd9fXtcdGV4dHtQcm9iYWJpbGl0eSBvZiBFdmVudCBOb3QgSGFwcGVuaW5nfX0gPSBcZnJhY3twfXsxIC0gcH0KJCQKV2hlcmUgXChwXCkgaXMgdGhlIHByb2JhYmlsaXR5IG9mIHRoZSBldmVudCBoYXBwZW5pbmcuIFRoZSBvZGRzIGNhbiB0YWtlIGFueSB2YWx1ZSBmcm9tIDAgdG8gaW5maW5pdHksIHdoZXJlIDAgbWVhbnMgdGhlIGV2ZW50IHdpbGwgbmV2ZXIgaGFwcGVuIGFuZCBpbmZpbml0eSBtZWFucyB0aGUgZXZlbnQgd2lsbCBhbHdheXMgaGFwcGVuLiBGb3IgZXhhbXBsZSwgaWYgdGhlcmUgaXMgYSA2MCUgb2YgYW4gZXZlbnQgaGFwcGVuaW5nIChwcm9iYWJpbGl0eVwocFwpPTAuNiksIHRoZSBvZGRzIG9mIHRoZSBldmVudCB3b3VsZCBiZToKCiQkClx0ZXh0e09kZHN9ID0gXGZyYWN7MC42fXsxIC0gMC42fSA9IFxmcmFjezAuNn17MC40fSA9IDEuNQokJApUaGlzIG1lYW4gdGhlIHZlbnQgaXMgMS41IHRpbWVzIG1vcmUgbGlrZWx5IHRvIGhhcHBlbiB0aGFuIG5vdCBoYXBwZW5pbmcuIEluIGxvZ2lzdGljIHJlZ3Jlc3Npb24sIGluc3RlYWQgb2YgcHJlZGljdGluZyB0aGUgcHJvYmFiaWxpdHkgb2YgdGhlIGV2ZW50IGRpcmVjdGx5LCB3ZSBwcmVkaWN0IHRoZSAqKmxvZyBvZGRzKiogKGFsc28ga25vd24gYXMgKipsb2dpdCoqKSBvZiB0aGUgb3V0Y29tZS4gVGhlIGxvZ2l0IG1vZGVsIHdpdGggbXVsdGlwbGUgcHJlZGljdG9ycyBpcyBleHByZXNzZWQgYXM6CgokJApcbG9nIFxsZWZ0KCBcZnJhY3twfXsxIC0gcH0gXHJpZ2h0KSA9IFxiZXRhXzAgKyBcYmV0YV8xIHhfMSArIFxiZXRhXzIgeF8yICsgXGRvdHMgKyBcYmV0YV9rIHhfawokJApJbiBvdXIgc3BlY2lmaWMgY2FzZSwgaXQgY2FuIGJlIHdyaXR0ZW4gYXM6CiQkClxsb2cgXGxlZnQoIFxmcmFje1AoXHRleHR7RFJJTktJTkdfRH0gPSAxKX17MSAtIFAoXHRleHR7RFJJTktJTkdfRH0gPSAxKX0gXHJpZ2h0KSA9IFxiZXRhXzAgKyBcYmV0YV8xIFxjZG90IFx0ZXh0e0ZBVEFMX09SX019ICsgXGJldGFfMiBcY2RvdCBcdGV4dHtPVkVSVFVSTkVEfSArIFxkb3RzICsgXGJldGFfOSBcY2RvdCBcdGV4dHtNRURISElOQ30KJCQKCldoZXJlOgoKLSBcKFAoXHRleHR7RFJJTktJTkdfRH0gPSAxKVwpIGlzIHRoZSBwcm9iYWJpbGl0eSBvZiBhIGNyYXNoIGludm9sdmluZyBhIGRyaW5raW5nIGRyaXZlci4KLSAgXCggXGxvZyBcbGVmdCggXGZyYWN7UChcdGV4dHtEUklOS0lOR19EfSA9IDEpfXsxIC0gUChcdGV4dHtEUklOS0lOR19EfSA9IDEpfSBccmlnaHQpIFwpIGlzIHRoZSBsb2ctb2RkcyBvZiBkcmlua2luZyBpbnZvbHZlbWVudC4KLSBcKCBcYmV0YV8wIFwpIGlzIHRoZSBpbnRlcmNlcHQgb2YgdGhlIG1vZGVsLCByZXByZXNlbnRpbmcgdGhlIGxvZy1vZGRzIG9mIGRyaW5raW5nIGFuZCBkcml2ZSBpbnZvbHZlZCB3aGVuIGFsbCBwcmVkaWN0b3JzIGFyZSB6ZXJvCi0gXCggXGJldGFfMSwgXGJldGFfMiwgXGRvdHMsIFxiZXRhX2sgXCkgYXJlIHRoZSBjb2VmZmljaWVudHMgb2YgZWFjaCBwcmVkaWN0b3IgdmFyaWFibGUsIGluZGljYXRpbmcgdGhlIGNoYW5nZSBpbiBsb2ctb2RkcyBmb3IgYSBvbmUgdW5pdCBpbmNyZWFzZSBpbiBlYWNoIHByZWRpY3RvcnMsIGhvbGRpbmdzIG90aGVyIGNvbnN0YW50LgoKVGhlIHByZWRpY3RvciB2YXJpYWJsZSBpbiB0aGUgbW9kZWwgaXMgZGVmaW5lZCBhcyBmb2xsb3dzOgoKLSBgRkFUQUxfT1JfTWA6IHdoZXRoZXIgdGhlIGNyYXNoIGludm9sdmVkIGEgZmF0YWxpdHkKLSBgT1ZFUlRVUk5FRGA6IHdoZXRoZXIgdGhlIGNyYXNoIGludm9sdmVkIGFuIG92ZXJ0dXJuZWQgdmVoaWNsZQotIGBDRUxMX1BIT05FYDogd2hldGhlciB0aGUgZHJpdmVyIHdhcyB1c2luZyBhIGNlbGwgcGhvbmUKLSBgU1BFRURJTkdgOiB3aGV0aGVyIHRoZSBjcmFzaCBpbnZvbHZlZCBzcGVlZGluZwotIGBBR0dSRVNTSVZFYDogd2hldGhlciB0aGUgY3Jhc2ggaW52b2x2ZWQgYWdncmVzc2l2ZSBkcml2aW5nCi0gYERSSVZFUjE2MTdgOiB3aGV0aGVyIHRoZSBjcmFzaCBpbnZvbHZlZCBhdCBsZWFzdCBvbmUgZHJpdmVyIGFnZWQgMTYgb3IgMTcKLSBgRFJJVkVSNjVQTFVTYDogd2hldGhlciB0aGUgY3Jhc2ggaW52b2x2ZWQgYXQgbGVhc3Qgb25lIGRyaXZlciBhZ2VkIDY1IG9yIG9sZGVyCi0gYFBDVEJBQ0hNT1JgOiBwZXJjZW50YWdlIG9mIHRoZSBwb3B1bGF0aW9uIHdpdGggYSBiYWNoZWxvcidzIGRlZ3JlZSBvciBtb3JlCi0gYE1FREhISU5DYDogbWVkaWFuIGhvdXNlaG9sZCBpbmNvbWUgaW4gdGhlIGFyZWEKCkxvZ2lzdGljIEZ1bmN0aW9uOiBUaGUgbG9naXN0aWMgZnVuY3Rpb24gaXMgdGhlICoqaW52ZXJzZSBvZiB0aGUgbG9naXQgZnVuY3Rpb24qKiwgYXMgc2hvd24gaW4gZm9sbG93aW5nIGdyYXBoLiBJdCB0YWtlcyB0aGUgbGluZWFyIHByZWRpY3RvciAobG9nLW9kZHMpIGFuZCB0cmFuc2Zvcm1zIGl0IGludG8gYSBwcm9iYWJpbGl0eSB2YWx1ZSBiZXR3ZWVuIDAgYW5kIDEgWzAsMV0uIFRoaXMgdHJhbnNmb3JtYXRpb24gaXMgaWRlYWwgZm9yIG1vZGVsaW5nIGJpbmFyeSBvdXRjb21lcyBhcyBpdCB0cmFuc2Zvcm1zIHRoZSBsaW5lYXIgY29tYmluYXRpb24gb2YgcHJlZGljdG9ycyBpbnRvIGEgcHJvYmFiaWxpdHkgdmFsdWUuCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImxvZ2lzdGljdnNsb2dpdC5wbmciKQpgYGAKClRoZSBsb2dpc3RpYyBmdW5jdGlvbiBpcyBkZWZpbmVkIGFzOgoKJCQKUChZID0gMSkgPSBcZnJhY3sxfXsxICsgZV57LShcYmV0YV8wICsgXGJldGFfMSB4XzEgICsgXGJldGFfMiB4XzIgKyAgXGRvdHMgKyBcYmV0YV9rIHhfayl9fQokJApJbiB0aGlzIHNwZWNpZmljIGNhc2UsIGl0IGNhbiBiZSB3cml0dGVuIGFzOgoKJCQKUChcdGV4dHtEUklOS0lOR19EfSA9IDEpID0gXGZyYWN7MX17MSArIGVeey0oXGJldGFfMCArIFxiZXRhXzEgXGNkb3QgXHRleHR7RkFUQUxfT1JfTX0gKyBcZG90cyArIFxiZXRhXzkgXGNkb3QgXHRleHR7TUVESEhJTkN9KX19CiQkCkFzIHNob3duIGluIHRoZSBncmFwaCBhYm92ZSwgdGhlIGxvZ2lzdGljIGZ1bmN0aW9uIGhhcyBhbiAqKlMtc2hhcGVkIGN1cnZlKiogd2l0aCB0aGUgZm9sbG93aW5nIHByb3BlcnRpZXM6CgotICoqT3V0Y29tZSBiZXR3ZWVuIDAgYW5kIDEgWzAsMV0qKjogQXMgdGhlIGxpbmVhciBwcmVkaWN0b3IgYXBwcm9hY2hlcyBuZWdhdGl2ZSBpbmZpbml0eSwgdGhlIHByb2JhYmlsaXR5IGFwcHJvYWNoZXMgMC4gQXMgdGhlIGxpbmVhciBwcmVkaWN0b3IgYXBwcm9hY2hlcyBwb3NpdGl2ZSBpbmZpbml0eSwgdGhlIHByb2JhYmlsaXR5IGFwcHJvYWNoZXMgMS4gVGhpcyBtZWFucyB0aGF0IHRoZSBwcmVkaWN0ZWQgcHJvYmFiaWxpdGllcyB3aWxsIGFsd2F5cyBiZSBiZXR3ZWVuIDAgYW5kIDEsIG1ha2luZyBpdCBzdWl0YWJsZSBmb3IgYmluYXJ5IG91dGNvbWVzLgotICoqU3ltbWV0cmljIGFyb3VuZCAwLjUqKjogVGhlIGxvZ2lzdGljIGZ1bmN0aW9uIGlzIHN5bW1ldHJpYyBhcm91bmQgdGhlIHBvaW50IHdoZXJlIHRoZSBsaW5lYXIgcHJlZGljdG9yIGVxdWFscyAwLjUuIFRoaXMgbWVhbnMgdGhhdCB3aGVuIHRoZSBsaW5lYXIgcHJlZGljdG9yIGlzIGVxdWFsIHRvIDAsIHRoZSBwcmVkaWN0ZWQgcHJvYmFiaWxpdHkgaXMgMC41LCBpbmRpY2F0aW5nIGFuIGVxdWFsIGNoYW5jZSBvZiB0aGUgZXZlbnQgb2NjdXJyaW5nIG9yIG5vdCBvY2N1cnJpbmcuIFRoaXMgbWlkcG9pbnQgaXMgdXNlZnVsIGluIGJpbmFyeSBjbGFzc2lmaWNhdGlvbiBhcyBpdCBoZWxwcyBpbnRlcnByZXQgcHJvYmFiaWxpdGllcyBhcm91bmQgNTAlLgoKT3ZlcmFsbCwgdGhlIGxvZ2lzdGljIGZ1bmN0aW9uIGlzIHRoZSB0eXBlIG9mIHRyYW5zbGF0b3IgZnVuY3Rpb24gd2UgYXJlIDtvb2tpbmcgZm9yLiBJdCB3b3JrcyB3ZWxsIGZvciBiaW5hcnkgZGVwZW5kZW50IHZhcmlhYmxlIGJlY2F1c2UgaXQgcmVzdHJpY3RzIHRoZSBwcmVkaWN0ZWQgcHJvYmFiaWxpdGllcyB0byB0aGUgcmFuZ2Ugb2YgMCBhbmQgMSwgd2hpY2ggaXMgZXNzZW50aWFsIGZvciBiaW5hcnkgb3V0Y29tZXMuIEVhY2ggY29lZmZpY2llbnQgXChcYmV0YV9pXCkgaW4gdGhlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwgcmVwcmVzZW50cyB0aGUgZWZmZWN0IG9mIGEgcHJlZGljdG9yIG9uIHRoZSBsb2ctb2RkcyBvZiB0aGUgb3V0Y29tZSwgd2hpY2ggY2FuIGJlIHRyYW5zZm9ybWVkIHRvIGludGVycHJldCBlZmZlY3RzIG9uIHByb2JhYmlsaXR5LgoKIyMgTG9naXN0aWMgUmVncmVzc2lvbiBIeXBvdGhlc2lzCgpGb3IgZWFjaCBwcmVkaWN0b3JzIGluIG91ciBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsLCB3ZSB0ZXN0IHdoZXRoZXIgdGhlIHByZWRpY3RvciBoYXMgYSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGVmZmVjdCBvbiB0aGUgb3V0Y29tZSB2YXJpYWJsZS4KClRoZSAqKk51bGwgSHlwb3RoZXNpcyAoXCggSF8wIFwpKSwgd2hpY2ggc3RhdGVzIHRoYXQgdGhlIHByZWRpY3RvciBoYXMgbm8gZWZmZWN0IG9uIHRoZSBvdXRjb21lIHZhcmlhYmxlKiouIEluIG90aGVyIHdvcmRzLCB0aGUgY29lZmZpY2llbnQgb2YgdGhlIHByZWRpY3RvciBpcyBlcXVhbCB0byB6ZXJvIChcKCBcYmV0YV9pID0gMCBcKSksIHdyaXR0ZXJuIGFzOgoKJCQKSF8wIDogXGJldGFfaSA9IDAKJCQKVGhlICoqQWx0ZXJuYXRpdmUgSHlwb3RoZXNpcyAoXCggSF9hIFwpKSwgd2hpY2ggc3RhdGVzIHRoYXQgdGhlIHByZWRpY3RvciBoYXMgYW4gZWZmZWN0IG9uIHRoZSBvdXRjb21lIHZhcmlhYmxlKiouIEluIG90aGVyIHdvcmRzLCB0aGUgY29lZmZpY2llbnQgb2YgdGhlIHByZWRpY3RvciBpcyBub3QgZXF1YWwgdG8gemVybyAoXCggXGJldGFfaSBcbmVxIDAgXCkpLCB3cml0dGVybiBhczoKCiQkCkhfMCA6IFxiZXRhX2kgPSAwCiQkCgpUbyB0ZXN0IHRoZXNlIGh5cG90aGVzZXMsIHdlIHVzZSB0aGUgKipXYWxkIHRlc3QqKiwgd2hpY2ggaXMgYSBzdGF0aXN0aWNhbCB0ZXN0IHVzZWQgdG8gYXNzZXNzIHRoZSBzaWduaWZpY2FuY2Ugb2YgaW5kaXZpZHVhbCBjb2VmZmljaWVudHMoXCggXGJldGFfaSBcKSkgaW4gYSByZWdyZXNzaW9uIG1vZGVsLiBUaGUgV2FsZCB0ZXN0IHN0YXRpc3RpYyBpcyBjYWxjdWxhdGVkIGFzOgoKJCQKV19pID0gXGZyYWN7XGhhdHtcYmV0YX1faX17XHNpZ21hKFxoYXR7XGJldGF9X2kpfQokJAoKV2hlcmU6CgotIFwoIFxoYXR7XGJldGF9X2kgXCkgaXMgdGhlIGVzdGltYXRlZCBjb2VmZmljaWVudCBmb3IgcHJlZGljdG9yIFwoIGkgXCkKLSBcKCBcc2lnbWEoXGhhdHtcYmV0YX1faSkgXCkgaXMgdGhlIHN0YW5kYXJkIGVycm9yIG9mIHRoZSBlc3RpbWF0ZWQgY29lZmZpY2llbnQKClVuZGVyIHRoZSBudWxsIGh5cG90aGVzaXMsIHRoZSBXYWxkIHRlc3Qgc3RhdGlzdGljIGZvbGxvd3MgYSBzdGFuZGFyZCBub3JtYWwgZGlzdHJpYnV0aW9uIFwoIE4oMCwgMSkgXCkuIExhcmdlIHZhbHVlcyBvZiB0aGUgV2FsZCB0ZXN0IHN0YXRpc3RpYyBpbmRpY2F0ZSB0aGF0IFwoIFxiZXRhX2kgXCkgaXMgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgZnJvbSB6ZXJvLCBzdWdnZXN0aW5nIHRoYXQgdGhlIHByZWRpY3RvciBoYXMgYSBzaWduaWZpY2FudCBlZmZlY3Qgb24gdGhlIG91dGNvbWUgdmFyaWFibGUuIFdlIGNhbiBzYWZlbHkgcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMuCgpIb3dldmVyLCByYXRoZXIgdGhhbiBsb29raW5nIGF0IHRoZSBlc3RpbWF0ZWQgYmV0YSBjb2VmZmljaWVudHMgKFwoIFxiZXRhIFwpKSwgbW9zdCBzdGF0aXN0aWNhbnMgc3RpbGwgcHJlZmVyIHRvIGxvb2tzIGF0ICoqb2RkcyBSYXRpb3MqKiwgd2hpY2ggaXMgY2FsY3VsYXRlZCBieSBleHBvbmVudGlhdGluZyB0aGUgZXN0aW1hdGVkIGNvZWZmaWNpZW50cyAoXCggXGJldGEgXCkpLiBGb3IgZXhhbXBsZSwgaWYgdGhlIG9kZHMgcmF0aW8gZm9yIGEgcHJlZGljdG9yIGlzIDEuNiwgaXQgbWVhbnMgdGhhdCB0aGUgb2RkcyBvZiB0aGUgb3V0Y29tZSBhcmUgMS42IHRpbWVzIGhpZ2hlciBmb3IgYSBvbmUtdW5pdCBpbmNyZWFzZSBpbiB0aGUgcHJlZGljdG9yLCBob2xkaW5nIGFsbCBvdGhlciBwcmVkaWN0b3JzIGNvbnN0YW50LiBUaGlzIG1ha2VzIGl0IGVhc2llciB0byBpbnRlcnByZXQgdGhlIGVmZmVjdCBvZiBlYWNoIHByZWRpY3RvciBvbiB0aGUgb3V0Y29tZSB2YXJpYWJsZS4KCkluIGFkZGl0aW9uLCBhbiBvZGRzIHJhdGlvIGdyZWF0ZXIgdGhhbjEgaW5kaWNhdGVzIHRoYXQgdGhlIHByZWRpY3RvciBpcyBhc3NvY2lhdGVkIHdpdGggYW4gaW5jcmVhc2UgbGlrZWxpaG9vZCBvZiB0aGUgb3V0Y29tZSwgd2hpbGUgYW4gb2RkcyByYXRpbyBsZXNzIHRoYW4gMSBpbmRpY2F0ZXMgdGhhdCB0aGUgcHJlZGljdG9yIGlzIGFzc29jaWF0ZWQgd2l0aCBhIGRlY3JlYXNlIGxpa2VsaWhvb2Qgb2YgdGhlIG91dGNvbWUuIEFuIG9kZHMgcmF0aW8gZXF1YWwgdG8gMSBpbmRpY2F0ZXMgbm8gZWZmZWN0LgoKCiMjIExvZ2lzdGljIFJlZ3Jlc3Npb24gTW9kZWwgQXNzZXNzbWVudAoKIyMjIFItc3F1YXJlZAoKSW4gbG9naXN0aWMgcmVncmVzc2lvbiwgdGhlcmUgYXJlIHNldmVyYWwgd2F5cyB0byBhY2Nlc3MgdGhlIHF1YWxpdHkgb2YgdGhlIG1vZGVsIGZpdC4gQW4gKipSLXNxdWFyZWQqKiB2YWx1ZSBjYW4gYmUgY29tcHV0ZWQgZm9yIGxvZ2lzdGljIHJlZ3Jlc3Npb24sIGJ1dCBpdCBkaWZmZXJzIGZyb20gdGhlIFItc3F1YXJlZCB1c2VkIGluIG9yZGluYXJ5IGxlYXN0IHNxdWFyZXMgKE9MUykgcmVncmVzc2lvbi4gSW4gT0xTLCBSLXNxdWFyZWQgcmVwcmVzZW50cyB0aGUgcHJvcG9ydGlvbiBvZiB2YXJpYW5jZSBpbiB0aGUgb3V0Y29tZSBleHBsYWluZWQgYnkgdGhlIG1vZGVsLCBhbmQgYSBoaWdoZXIgUi1zcXVhcmVkIGdlbmVyYWxseSBpbmRpY2F0ZXMgYmV0dGVyIG1vZGVsIGZpdC4gSG93ZXZlciwgdGhpcyBpbnRlcnByZXRhdGlvbiAqKmRvZXMgbm90IGFwcGx5KiogdG8gbG9naXN0aWMgcmVncmVzc2lvbi4gVGhpcyBpcyBiZWNhdXNlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWxzIGEgYmluYXJ5IG91dGNvbWUgYW5kIHVzZXMgKiptYXhpbXVtIGxpa2VsaWhvb2QgZXN0aW1hdGlvbiAoTUxFKSoqIHJhdGhlciB0aGFuIG1pbmltaXppbmcgdGhlIHN1bSBvZiBzcXVhcmVkIHJlc2lkdWFscy4gSW4gYW5vdGhlciB3b3JkLCB0aGVyZSBpcyBubyBkaXJlY3QgY29uY2VwdCBvZiB2YXJpYW5jZSBpbiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIHRvIGJlIGV4cGxhaW5lZCBpbiB0aGUgc2FtZSB3YXkuIFRoZXJlZm9yZSwgUi1zcXVhcmVkIHZhbHVlcyBpbiBsb2dpc3RpYyByZWdyZXNzaW9uIGFyZSBub3QgZGlyZWN0bHkgY29tcGFyYWJsZSB0byBPTFMgUsKyIGFuZCBhcmUgKipyYXJlbHkgdXNlZCBhcyBwcmltYXJ5IGluZGljYXRvcnMgb2YgbW9kZWwgZml0KiouIE5vdGFibHksIHRoZSBgZ2xtKClgIGZ1bmN0aW9uIGluICoqUioqIGRvZXMgKipub3QgcmVwb3J0IGFuIFItc3F1YXJlZCB2YWx1ZSBieSBkZWZhdWx0KiosIHdoaWNoIHJlZmxlY3RzIGl0cyBsaW1pdGVkIGludGVycHJldGFiaWxpdHkuIElmIGFuIFItc3F1YXJlZCB2YWx1ZSBpcyBkZXNpcmVkLCBvbmUgb3B0aW9uIGlzIHRvIHVzZSB0aGUgYHJtc2AgcGFja2FnZSBpbiBSLCB3aGljaCBwcm92aWRlcyBhIHZlcnNpb24gb2YgKipOYWdlbGtlcmtlIFLCsioqLiBXaGlsZSB0aGlzIGFkanVzdGVkIFItc3F1YXJlZCBjYW4gb2ZmZXIgc29tZSBpbnNpZ2h0IGludG8gbW9kZWwgZml0LCBpdCBzaG91bGQgYmUgaW50ZXJwcmV0ZWQgd2l0aCBjYXV0aW9uLCBhbmQgdGhlIG9ubHkgc2FmZSBjb25jbHVzaW9uIGlzICoqaGlnaGVyIHZhbHVlcyBhcmUgYmV0dGVyKiouCgojIyMgQWthaWtlIEluZm9ybWF0aW9uIENyaXRlcmlvbiAoQUlDKQoKVGhlICoqQWthaWtlIEluZm9ybWF0aW9uIENyaXRlcmlvbiAoQUlDKSoqIGlzIGNvbW1vbmx5IHVzZWQgZm9yIG1vZGVsIGNvbXBhcmlzb24gaW4gbG9naXN0aWMgcmVncmVzc2lvbiBhcyBhbiBhbHRlcm5hdGl2ZSBvZiBSLXNxdWFyZWQuIEFJQyBpcyBhbiBlc3RpbWF0b3Igb2YgcHJlZGljdGlvbiBlcnJvciBhbmQgdGhlICoqcmVsYXRpdmUgcXVhbGl0eSBvZiBzdGF0aXN0aWNhbCBtb2RlbHMqKiBmb3IgYSBnaXZlbiBkYXRhc2V0LiBJdCBwcm92aWRlcyBhIHByaW5jaXBsZWQgYXBwcm9hY2ggdG8gY29tcGFyaW5nIGNhbmRpZGF0ZSBtb2RlbHMgYnkgYmFsYW5jaW5nICoqZ29vZG5lc3Mgb2YgZml0Kiogd2l0aCAqKm1vZGVsIGNvbXBsZXhpdHkqKiwgcGVuYWxpemluZyBtb2RlbHMgd2l0aCBtb3JlIHBhcmFtZXRlcnMgdG8gcmVkdWNlIHRoZSByaXNrIG9mIG92ZXJmaXR0aW5nLiBBSUMgaXMgZGVmaW5lZCBhczoKCiQkClx0ZXh0e0FJQ30gPSAyayAtIDJcbG4oXGhhdHtMfSkKJCQKCndoZXJlOgoKLSAqXCggayBcKSogaXMgdGhlIG51bWJlciBvZiBlc3RpbWF0ZWQgcGFyYW1ldGVycyBpbiB0aGUgbW9kZWwKLSAqXCggXGhhdHtMfSBcKSAqIGlzIHRoZSBtYXhpbXVtIHZhbHVlIG9mIHRoZSBsaWtlbGlob29kIGZ1bmN0aW9uIGZvciB0aGUgbW9kZWwKCkEgKipsb3dlciBBSUMqKiB2YWx1ZSBzdWdnZXN0cyBhICoqYmV0dGVyIGZpdCoqLCBhcyB0aGV5IGJhbGFuY2UgdGhlIHRyYWRlLW9mZiBiZXR3ZWVuIG1vZGVsIGNvbXBsZXhpdHkgYW5kIGdvb2RuZXNzIG9mIGZpdC4KCiMjIyBTcGVjaWZpY2l0eSwgU2Vuc2l0aXZpdHkgYW5kIE1pc2NsYXNzaWZpY2F0aW9uIFJhdGUKCkluIGxvZ2lzdGljIHJlZ3Jlc3Npb24sIHJlc2lkdWFscyAoRXJyb3JzKSBhcmUgZGVmaW5lZCBhcyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBvYnNlcnZlZCBhbmQgcHJlZGljdGVkIHZhbHVlcywgc2ltaWxhciB0byBsaW5lYXIgcmVncmVzc2lvbi4gSG93ZXZlciwgaW4gbG9naXN0aWMgcmVncmVzc2lvbiwgdGhlIHByZWRpY3RlZCB2YWx1ZXMgYXJlIHByb2JhYmlsaXRpZXMsIG5vdCBkaXJlY3QgdmFsdWVzIG9mIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUuIFNwZWNpZmljYWxseSwgdGhlIHByZWRpY3RlZCB2YWx1ZSBcKCBcaGF0e3l9X2kgXCkgaXMgdGhlIGVzdGltYXRlZCBwcm9iYWJpbGl0eSB0aGF0IFwoIFkgPSAxIFwpIGZvciB0aGUgXCggaSBcKS10aCBvYnNlcnZhdGlvbi4KClRoZSByZXNpZHVhbHMgaW4gbG9naXN0aWMgcmVncmVzc2lvbiBhcmUgZGVmaW5lZCBhczoKCiQkClxlcHNpbG9uX2kgPSB5X2kgLSBcaGF0e3l9X2kKJCQKCldoZXJlOgoKLSBcKCB5X2kgXCkgaXMgdGhlIGFjdHVhbCBvYnNlcnZlZCB2YWx1ZSAoZWl0aGVyIDAgb3IgMSkuCgotIFwoIFxoYXR7eX1faSBcKSBpcyB0aGUgcHJlZGljdGVkIHByb2JhYmlsaXR5IHRoYXQgXCggWSA9IDEgXCkgZm9yIHRoZSBcKCBpIFwpLXRoIG9ic2VydmF0aW9uLgoKVGhlIHByZWRpY3RlZCBwcm9iYWJpbGl0aWVzICRcdGV4dHtQKHk9MSl9JCA9XCggXGhhdHt5fV9pIFwpIGFyZSBjYWxjdWxhdGVkIHVzaW5nIHRoZSBsb2dpc3RpYyBmdW5jdGlvbjoKCiQkClx0ZXh0e1AoeT0xKX09XGhhdHt5fV9pID0gXGZyYWN7ZV57KFxoYXR7XGJldGF9XzAgKyBcaGF0e1xiZXRhfV8xIHhfezFpfSArIFxoYXR7XGJldGF9XzIgeF97Mml9ICsgXGNkb3RzICsgXGhhdHtcYmV0YX1fcCB4X3twaX0pfX17MSArIGVeeyhcaGF0e1xiZXRhfV8wICsgXGhhdHtcYmV0YX1fMSB4X3sxaX0gKyBcaGF0e1xiZXRhfV8yIHhfezJpfSArIFxjZG90cyArIFxoYXR7XGJldGF9X3AgeF97cGl9KX19PSBcZnJhY3sxfXsxICsgXGV4cCgtXGhhdHtcYmV0YX1fMCAtIFxoYXR7XGJldGF9XzF4XzEgLSBcZG90cyAtIFxoYXR7XGJldGF9X2t4X2spfQokJAoKV2hlcmU6CgotIFwoIFxoYXR7eX1faSBcKSBpcyB0aGUgZXN0aW1hdGVkIHByb2JhYmlsaXR5IHRoYXQgXCggWSA9IDEgXCkgZm9yIHRoZSBcKCBpIFwpLXRoIG9ic2VydmF0aW9uLgoKLSBcKCBcaGF0e1xiZXRhfV8wLCBcaGF0e1xiZXRhfV8xLCBcZG90cywgXGhhdHtcYmV0YX1fcCBcKSBhcmUgdGhlIGVzdGltYXRlZCBjb2VmZmljaWVudHMgb2J0YWluZWQgZnJvbSB0aGUgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbC4KCi0gXCggeF97MWl9LCB4X3syaX0sIFxkb3RzLCB4X3twaX0gXCkgYXJlIHRoZSB2YWx1ZXMgb2YgdGhlIHByZWRpY3RvciB2YXJpYWJsZXMgZm9yIG9ic2VydmF0aW9uIFwoIGkgXCkuCgpBZnRlciBvYnRhaW5pbmcgdGhlIHByZWRpY3RlZCBwcm9iYWJpbGl0aWVzLCB3ZSBhcHBseSBhIHRocmVzaG9sZCAoY3V0LW9mZikgdmFsdWUgdG8gY2xhc3NpZnkgcHJlZGljdGlvbnMgaW50byBiaW5hcnkgb3V0Y29tZXMgKGUuZy4gXCggXGhhdHt5fVwpPjAuNSBhcyB5PSAxLCBhbmQgXCggXGhhdHt5fVwpPDAuNSBhcyB5PTApLiBUaGUgY2hvaWNlIG9mIGN1dC1vZmYgdmFsdWUgY2FuIHNpZ25pZmljYW50bHkgaW1wYWN0IHRoZSBtb2RlbCdzIHBlcmZvcm1hbmNlLiBUaGUgZGVmYXVsdCBjdXQtb2ZmIHZhbHVlIGlzIDAuNSwgYnV0IGl0IGNhbiBiZSBhZGp1c3RlZCBiYXNlZCBvbiB0aGUgc3BlY2lmaWMgY29udGV4dCBhbmQgZ29hbHMgb2YgdGhlIGFuYWx5c2lzLgoKVG8gYXNzZXNzIHByZWRpY3RpdmUgcGVyZm9ybWFuY2UgYW5kIGRpZmZlcmVudCBjdXQtb2ZmIHZhbHVlcywgd2UgdXNlIG1ldHJpY3Mgc3VjaCBhcyAqKnNlbnNpdGl2aXR5KiosICoqc3BlY2lmaWNpdHkqKiBhbmQgKiptaXNjbGFzc2lmaWNhdGlvbiByYXRlKiouIFRoZXNlIG1ldHJpY3MgYXJlIGRlcml2ZWQgZnJvbSB0aGUgcHJlZGljdGVkIHZhbHVlcyBvZiBcKCBcaGF0e3l9IFwpLCB3aGljaCBpbiBsb2dpc3RpYyByZWdyZXNzaW9uIHJlcHJlc2VudCB0aGUgZXN0aW1hdGVkIHByb2JhYmlsaXR5IHRoYXQgXCggWSA9IDEgXCkuCgotICoqU2Vuc2l0aXZpdHkqKiAoYWxzbyBjYWxsZWQgcmVjYWxsIG9yIHRoZSB0cnVlIHBvc2l0aXZlIHJhdGUpIG1lYXN1cmVzIHRoZSBwcm9wb3J0aW9uIG9mIGFjdHVhbCBwb3NpdGl2ZXMgY29ycmVjdGx5IHByZWRpY3RlZCBhbmQgaXMgY29tcGxlbWVudGFyeSB0byB0aGUgZmFsc2UgbmVnYXRpdmUgcmF0ZToKCiQkClx0ZXh0e1NlbnNpdGl2aXR5fSA9IFxmcmFje1RQfXtUUCArIEZOfQokJAoKLSBIaWdoZXIgc2Vuc2l0aXZpdHkgaXMgYmV0dGVyLCBlc3BlY2lhbGx5IHdoZW4gZmFpbGluZyB0byBkZXRlY3QgdHJ1ZSBwb3NpdGl2ZXMgaXMgY29zdGx5LgoKLSAqKlNwZWNpZmljaXR5KiogKHRoZSB0cnVlIG5lZ2F0aXZlIHJhdGUpIG1lYXN1cmVzIHRoZSBwcm9wb3J0aW9uIG9mIGFjdHVhbCBuZWdhdGl2ZXMgY29ycmVjdGx5IHByZWRpY3RlZCBhbmQgaXMgY29tcGxlbWVudGFyeSB0byB0aGUgZmFsc2UgcG9zaXRpdmUgcmF0ZToKCiQkClx0ZXh0e1NwZWNpZmljaXR5fSA9IFxmcmFje1ROfXtUTiArIEZQfQokJAoKLSBIaWdoZXIgc3BlY2lmaWNpdHkgaXMgYmV0dGVyIHdoZW4gZmFsc2UgcG9zaXRpdmVzIGFyZSBwYXJ0aWN1bGFybHkgcHJvYmxlbWF0aWMuCgotIFRoZSAqKmNvcnJlY3QgY2xhc3NpZmljYXRpb24gcmF0ZSoqIGlzIHRoZSBwcm9wb3J0aW9uIG9mIGFsbCBwcmVkaWN0aW9ucyB0aGF0IGFyZSBjb3JyZWN0OgoKJCQKXHRleHR7Q29ycmVjdCBDbGFzc2lmaWNhdGlvbiBSYXRlfSA9IFxmcmFje1RQICsgVE59e1x0ZXh0e1RvdGFsfX0KJCQKCi0gQSBoaWdoZXIgY29ycmVjdCBjbGFzc2lmaWNhdGlvbiByYXRlIGluZGljYXRlcyBiZXR0ZXIgbW9kZWwgcGVyZm9ybWFuY2UuCgotIFRoZSAqKm1pc2NsYXNzaWZpY2F0aW9uIHJhdGUqKiBpcyB0aGUgcHJvcG9ydGlvbiBvZiBhbGwgcHJlZGljdGlvbnMgdGhhdCBhcmUgaW5jb3JyZWN0OgoKJCQKXHRleHR7TWlzY2xhc3NpZmljYXRpb24gUmF0ZX0gPSAxIC0gXHRleHR7Q29ycmVjdCBDbGFzc2lmaWNhdGlvbiBSYXRlfQokJAoKLSBMb3dlciB2YWx1ZXMgb2YgdGhlIG1pc2NsYXNzaWZpY2F0aW9uIHJhdGUgaW5kaWNhdGUgYmV0dGVyIHBlcmZvcm1hbmNlLCBhcyBpdCByZWZsZWN0cyB0aGUgbG93ZXIgcHJvcG9ydGlvbiBvZiBpbmNvcnJlY3QgcHJlZGljdGlvbnMuCgpVc2luZyAqKmRpZmZlcmVudCBjdXQtb2ZmIHZhbHVlcyoqIGFsbG93cyBmb3IgYSAqKnRyYWRlLW9mZiBiZXR3ZWVuIHNlbnNpdGl2aXR5IGFuZCBzcGVjaWZpY2l0eSoqLiBGb3IgZXhhbXBsZSwgYSBsb3dlciBjdXQtb2ZmIHZhbHVlIG1heSBpbmNyZWFzZSBzZW5zaXRpdml0eSBidXQgZGVjcmVhc2Ugc3BlY2lmaWNpdHksIHdoaWxlIGEgaGlnaGVyIGN1dC1vZmYgdmFsdWUgbWF5IGluY3JlYXNlIHNwZWNpZmljaXR5IGJ1dCBkZWNyZWFzZSBzZW5zaXRpdml0eS4gRm9yIGV4YW1wbGUsIGlmIHRoZSBjdXRvZmYgdmFsdWUgPSAwLjcsIHRoZSBtb2RlbCB3aWxsIGNsYXNzaWZ5IGEgY3Jhc2ggYXMgaW52b2x2aW5nIGEgZHJpbmtpbmcgZHJpdmVyIG9ubHkgaWYgdGhlIHByZWRpY3RlZCBwcm9iYWJpbGl0eSBpcyBncmVhdGVyIHRoYW4gMC43LiBUaGlzIG1heSBsZWFkIHRvIGZld2VyIGZhbHNlIHBvc2l0aXZlcyAoaGlnaGVyIHNwZWNpZmljaXR5KSBidXQgbW9yZSBmYWxzZSBuZWdhdGl2ZXMgKGxvd2VyIHNlbnNpdGl2aXR5KS4gQ29udmVyc2VseSwgaWYgdGhlIGN1dC1vZmYgdmFsdWUgPSAwLjMsIHRoZSBtb2RlbCB3aWxsIGNsYXNzaWZ5IGEgY3Jhc2ggYXMgaW52b2x2aW5nIGEgZHJpbmtpbmcgZHJpdmVyIGlmIHRoZSBwcmVkaWN0ZWQgcHJvYmFiaWxpdHkgaXMgZ3JlYXRlciB0aGFuIDAuMywgbGVhZGluZyB0byBtb3JlIGZhbHNlIHBvc2l0aXZlcyAobG93ZXIgc3BlY2lmaWNpdHkpIGJ1dCBmZXdlciBmYWxzZSBuZWdhdGl2ZXMgKGhpZ2hlciBzZW5zaXRpdml0eSkuIFRoZSBjaG9pY2Ugb2YgY3V0LW9mZiB2YWx1ZSBzaG91bGQgYmUgYmFzZWQgb24gdGhlIHNwZWNpZmljIGNvbnRleHQgYW5kIGdvYWxzIG9mIHRoZSBhbmFseXNpcywgY29uc2lkZXJpbmcgdGhlIGNvbnNlcXVlbmNlcyBvZiBmYWxzZSBwb3NpdGl2ZXMgYW5kIGZhbHNlIG5lZ2F0aXZlcy4KCiMjIyAqKlJlY2VpdmVyIE9wZXJhdGluZyBDaGFyYWN0ZXJpc3RpYyAoUk9DKSBDdXJ2ZSoqCgpPbmUgd2F5IHRvIHBsb3Qgc2Vuc2l0aXZpdHkgKHRydWUgcG9zaXRpdmUgcmF0ZSkgYWdhaW5zdCBcKCAxIC0gXCkgc3BlY2lmaWNpdHkgKGZhbHNlIHBvc2l0aXZlIHJhdGUpIGlzIHRocm91Z2ggdGhlICoqUmVjZWl2ZXIgT3BlcmF0aW5nIENoYXJhY3RlcmlzdGljIChST0MpIGN1cnZlKiouIFRoZSBST0MgY3VydmUgaXMgYSBncmFwaGljYWwgcmVwcmVzZW50YXRpb24gdGhhdCBoZWxwcyBhc3Nlc3MgdGhlIHByZWRpY3RpdmUgcXVhbGl0eSBvZiB0aGUgbW9kZWwgYnkgY29tcGFyaW5nIHNlbnNpdGl2aXR5IGFuZCBzcGVjaWZpY2l0eSBhY3Jvc3MgdmFyaW91cyB0aHJlc2hvbGRzLiBST0MgQ3VydmVzIHdpbGwgYmUgdG8gdGhlIGxlZnQgb2YgdGhlIDQ1IGRlZ3JlZSBsaW5lLgoKQSBiZXN0IGN1dC1vZmYgdmFsdWUgbWF5IGJlIGRldGVybWluZWQgYnkgb3B0aW1pemluZyB0aGUgYmFsYW5jZSBiZXR3ZWVuIHNlbnNpdGl2aXR5IGFuZCBzcGVjaWZpY2l0eS4gVGhlcmUgYXJlIGEgY291cGxlIG9mIHdheXMgdG8gaWRlbnRpZnkgdGhlICoqb3B0aW1hbCBwcm9iYWJpbGl0eSBjdXQtb2ZmKiogYmFzZWQgb24gdGhlIFJPQyBjdXJ2ZToKCi0gV2UgY2FuIGNhbGN1bGF0ZSB0aGUgKipZb3VkZW4gSW5kZXgqKiwgd2hpY2ggZGVmaW5lZCBhczoKCiQkCkogPSBcdGV4dHtTZW5zaXRpdml0eX0gKyBcdGV4dHtTcGVjaWZpY2l0eX0gLSAxCiQkClRoZSBiZXN0IGN1dC1vZmYgY2FuIGJlIGZvdW5kICB3aGVyZSB0aGUgWW91ZGVuIEluZGV4IGlzIG1heGltaXplZC4KCi0gVGhlIHNlY29uZCBhcHByb2FjaGVzIGludm9sdmUgY2FsY3VsYXRlIHRoZSAqKk1pbmltdW0gRGlzdGFuY2UqKi4gQSBjdXQtb2ZmIHdoZXJlIHRoZSBST0MgY3VydmUgaGFzIHRoZSBtaW5pbXVtIGRpc3RhbmNlIGZyb20gdGhlIHVwcGVyLWxlZnQgY29ybmVyIG9mIHRoZSBncmFwaCwgd2hlcmUgYm90aCBzcGVjaWZpY2l0eSBhbmQgc2Vuc2l0aXZpdHkgYXJlIGVxdWFsIHRvIDEuICBJbiB0aGlzIGNhc2UsIHdlIGFyZSBtaW5pbWl6aW5nIHRoZSBkaXN0YW5jZSBmcm9tIHRoZSB1cHBlciBsZWZ0IGNvcm5lciwgd2hlcmUgXCh5ID0gXHRleHR7U2Vuc2l0aXZpdHl9ID0gXHRleHR7VHJ1ZSBQb3NpdGl2ZSBSYXRlfSA9IFx0ZXh0e3Rwcn0gPSAxXCkgYW5kIFwoeCA9IDEgLSBcdGV4dHtTcGVjaWZpY2l0eX0gPSBcdGV4dHtGYWxzZSBQb3NpdGl2ZSBSYXRlfSA9IFx0ZXh0e2Zwcn0gPSAwXCkuIFRoZSBmb3JtdWxhIHVzZWQgdG8gY2FsY3VsYXRlIHRoZSBkaXN0YW5jZSBpczoKCiQkCmQgPSAoeCAtIDApXjIgKyAoeSAtIDEpXjIKJCQKCkZvciB0aGlzIHJlcG9ydCwgd2Ugd2lsbCBiZSB1c2luZyB0aGUgKiptaW5pbXVtIGRpc3RhbmNlKiogYXBwcm9hY2ggdG8gZGV0ZXJtaW5lIHRoZSBvcHRpbWFsIGN1dC1vZmYgdmFsdWUuCgoKIyMjICoqQXJlYSBVbmRlciB0aGUgUk9DIEN1cnZlIChBVUMpKioKCkJhc2VkIG9uIHRoZSBST0MgY3VydmUsIHdlIGNhbiBjYWxjdWxhdGUgdGhlICoqQXJlYSBVbmRlciBDdXJ2ZSAoQVVDKSoqIHRvIHF1YW50aWZ5IHRoZSBtb2RlbCdzIHBlcmZvcm1hbmNlLiBBcmVhIFVuZGVyIHRoZSBST0MgQ3VydmUgKEFVQykgIG1lYW5zIGhvdyB3ZWxsIHRoZSBtb2RlbCBwcmVkaWN0cyBcKCBZID0gMSBcKSByZXNwb25zZXMgYXMgMeKAmXMgYW5kIFwoIFkgPSAwIFwpIHJlc3BvbnNlcyBhcyAw4oCZcy4gSGlnaGVyIEFVQyB2YWx1ZXMgaW5kaWNhdGUgdGhhdCB3ZSBjYW4gZmluZCBhIGN1dC1vZmYgdmFsdWUgZm9yIHdoaWNoIGJvdGggc2Vuc2l0aXZpdHkgYW5kIHNwZWNpZmljaXR5IGFyZSByZWxhdGl2ZWx5IGhpZ2guIFRoZSBwb3NzaWJsZSB2YWx1ZXMgZm9yIEFVQyByYW5nZSBiZXR3ZWVuICoqMC41KiogKEFyZWEgdW5kZXIgdGhlIDQ1LWRlZ3JlZSBsaW5lLCBtZWFucyBubyBkaXNjcmltaW5hdGlvbiBiZXR3ZWVuIGNsYXNzZXMsIGVxdWl2YWxlbnQgdG8gcmFuZG9tIGd1ZXNzaW5nKSBhbmQgKioxKiogKEFyZWEgb2YgdGhlIGVudGlyZSBib3ggbWVhbnMgcGVyZmVjdCBwcmVkaWN0aW9uKS4gVGhlIEFVQyB2YWx1ZSBtYXkgYmUgaW50ZXJwcmV0ZWQgYXMgdGhlIHByb2JhYmlsaXR5IHRoYXQgdGhlIFwoIFxoYXR7eX0gXCkgZm9yIG9ic2VydmF0aW9uIDEgKHdoZXJlIFwoIHkgPSAxIFwpKSB3aWxsIGJlIGhpZ2hlciB0aGFuIHRoZSBcKCBcaGF0e3l9IFwpIGZvciBvYnNlcnZhdGlvbiAyICh3aGVyZSBcKCB5ID0gMCBcKSkuIEEgcm91Z2ggZ3VpZGUgZm9yIGNsYXNzaWZ5aW5nIHRoZSBhY2N1cmFjeSBiYXNlZCBvbiBBVUMgaXM6CgotICoqQVVDID0gMC45MOKAkzEuMDAqKjogRXhjZWxsZW50Ci0gKipBVUMgPSAwLjgw4oCTMC44OSoqOiBHb29kCi0gKipBVUMgPSAwLjcw4oCTMC43OSoqOiBGYWlyCi0gKipBVUMgPSAwLjYw4oCTMC42OSoqOiBQb29yCi0gKipBVUMgPCAwLjYwKio6IEZhaWxpbmcKCldlIGNhbiBnZW5lcmFsbHkgY29uc2lkZXIgYW4gQVVDIHZhbHVlICoqZ3JlYXRlciB0aGFuIDAuNyBhcyBhY2NlcHRhYmxlKiouCgojIyBMb2dpc3RpYyBSZWdyZXNzaW9uIEFzc3VtcHRpb25zCgpMb2dpc3RpYyByZWdyZXNzaW9uIHNoYXJlcyBzb21lIGFzc3VtcHRpb25zIHdpdGggT0xTIHJlZ3Jlc3Npb24sIGJ1dCBpdCBhbHNvIGhhcyB1bmlxdWUgYXNzdW1wdGlvbnMgdGhhdCBhY2NvbW1vZGF0ZSB0aGUgYmluYXJ5IG5hdHVyZSBvZiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlLiBUaGUga2V5IGFzc3VtcHRpb25zIG9mIGxvZ2lzdGljIHJlZ3Jlc3Npb24gaW5jbHVkZToKCi0gRmlyc3QsIGp1c3QgbGlrZSBPTFMgcmVncmVzc2lvbiwgbG9naXN0aWMgcmVncmVzc2lvbiBhc3N1bWVzIHRoYXQgKipvYnNlcnZhdGlvbnMgYXJlIGluZGVwZW5kZW50Kiogb2YgZWFjaCBvdGhlci4gVGhpcyBtZWFucyB0aGF0IGVhY2ggZGF0YSBwb2ludCBzaG91bGQgbm90IGluZmx1ZW5jZSBhbm90aGVyLCB3aXRob3V0IHNwYXRpYWwgYW5kIHRpbWUgYXV0b2NvcnJlbGF0aW9uLgotIFNlY29uZCwgc2ltaWxhciB0byBPTFMgcmVncmVzc2lvbiwgbG9naXN0aWMgcmVncmVzc2lvbiBhc3N1bWVzIHRoYXQgdGhlcmUgaXMgKipubyBzZXZlcmUgbXVsdGljb2xsaW5lYXJpdHkqKiBhbW9uZyB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGVzLiBNdWx0aWNvbGxpbmVhcml0eSBvY2N1cnMgd2hlbiB0d28gb3IgbW9yZSBpbmRlcGVuZGVudCB2YXJpYWJsZXMgYXJlIGhpZ2hseSBjb3JyZWxhdGVkLCBtYWtpbmcgaXQgZGlmZmljdWx0IHRvIGRldGVybWluZSB0aGUgaW5kaXZpZHVhbCBlZmZlY3Qgb2YgZWFjaCB2YXJpYWJsZSBvbiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIGFuZCBpbnN0YWJpbGl0eSBpbiB0aGUgY29lZmZpY2llbnQgZXN0aW1hdGVzLgotIFRoaXJkLCB1bmxlc3MgdGhlIE9MUyByZWdyZXNzaW9uLCBsb2dpc3RpYyByZWdyZXNzaW9uICoqZG9lcyBub3QqKiBhc3N1bWVzICoqaG9tb3NjZWRhc3RpY2l0eSoqLiBJbiBPTFMgcmVncmVzc2lvbiwgdGhlIHJlc2lkdWFscyBzaG91bGQgaGF2ZSBjb25zdGFudCB2YXJpYW5jZSBhY3Jvc3MgYWxsIGxldmVscyBvZiB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGVzIChob21vc2NlZGFzdGljaXR5KS4gSG93ZXZlciwgaW4gbG9naXN0aWMgcmVncmVzc2lvbiwgdGhpcyBhc3N1bXB0aW9uIGlzIG5vdCByZXF1aXJlZCBiZWNhdXNlIHRoZSBtb2RlbCB1c2VzIGEgZGlmZmVyZW50IGVycm9yIHN0cnVjdHVyZSAoYmlub21pYWwgZGlzdHJpYnV0aW9uKS4KLSBGb3J0aCwgaW4gT0xTLCB3ZSBhc3N1bWUgdGhhdCB0aGUgcmVzaWR1YWxzIGFyZSAqKm5vcm1hbGx5IGRpc3RyaWJ1dGVkKiouIEluIGxvZ2lzdGljIHJlZ3Jlc3Npb24sIGhvd2V2ZXIsICoqdGhlIGVycm9ycyBkbyBub3QgbmVlZCB0byBmb2xsb3cgYSBub3JtYWwgZGlzdHJpYnV0aW9uKiogYmVjYXVzZSB0aGUgbW9kZWwgdXNlcyBhIGJpbm9taWFsIGRpc3RyaWJ1dGlvbiBpbnN0ZWFkIG9mIG5vcm1hbCBkaXN0cmlidXRpb24uIFRoaXMgaXMgb25lIG9mIHRoZSBrZXkgZGlmZmVyZW5jZXMgYmV0d2VlbiBPTFMgYW5kIGxvZ2lzdGljIHJlZ3Jlc3Npb24uCi0gIExhc3RseSwgbG9naXN0aWMgcmVncmVzc2lvbiAqKmRvZXMgbm90KiogYXNzdW1lIGEgKipsaW5lYXIgcmVsYXRpb25zaGlwKiogYmV0d2VlbiB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGVzIGFuZCB0aGUgZGVwZW5kZW50IHZhcmlhYmxlLgotIEluc3RlYWQsIGRlcGVuZGVudCB2YXJpYWJsZSBmb3IgbG9naXN0aWMgcmVncmVzc2lvbiBtdXN0IGJlICoqYmluYXJ5KiogKDAgb3IgMSkuIExvZ2lzdGljIHJlZ3Jlc3Npb24gYXNzdW1lcyB0aGF0IHRoZSBsb2cgb2RkcyBvZiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIGJlaW5nIDEgaXMgbGluZWFybHkgcmVsYXRlZCB0byB0aGUgZWFjaCBpbmRlcGVuZGVudCB2YXJpYWJsZS4gKipUaGlzIGlzIGEgdW5pcXVlIGFzc3VtcHRpb25zIG9mIGxvZ2lzdGljIHJlZ3Jlc3Npb24gdGhhdCBkb2VzIG5vdCBhcHBseSB0byBPTFMgcmVncmVzc2lvbioqLgotIEluIGFkZGl0aW9uLCBsb2dpc3RpYyByZWdyZXNzaW9uIHJlcXVpcmVzIGEgc2FtcGxlIHNpemUgb2YgYXQgbGVhc3QgNTAgcGVyIHByZWRpY3RvcnMsIGFzIGxvZ2lzdGljIHJlZ3Jlc3Npb24gdXNlcyBNYXhpbXVtIExpa2VsaWhvb2QgRXN0aW1hdGlvbiAoTUxFKSB0byBlc3RpbWF0ZSB0aGUgY29lZmZpY2llbnRzLgoKCiMjIEV4cGxvcmF0b3J5IEFuYWx5c2lzCgpCZWZvcmUgcnVubmluZyBsb2dpc3RpYyByZWdyZXNzaW9uLCB3ZSBuZWVkIHRvIGNvbmR1Y3QgZXhwbG9yYXRvcnkgYW5hbHlzZXMgdG8gYmV0dGVyIHVuZGVyc3RhbmQgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgKHdoaWNoIGlzIHRoZSBkcmlua2luZyBkcml2ZXIgaW5kaWNhdG9yIGBEUklOS0lOR19EYCBpbiB0aGUgcmVwb3J0KSBhbmQgcG90ZW50aWFsIHByZWRpY3RvcnMuIFRoZXNlIGFuYWx5c2VzIGhlbHAgaWRlbnRpZnkgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBhc3NvY2lhdGlvbnMgYW5kIGd1aWRlIHRoZSBzZWxlY3Rpb24gb2YgYXBwcm9wcmlhdGUgdmFyaWFibGVzIGZvciB0aGUgcmVncmVzc2lvbiBtb2RlbC4KCkZvciBiaW5hcnkgcHJlZGljdG9ycywgd2UgZXhhbWluZSB0aGUgZGlzdHJpYnV0aW9uIGFjcm9zcyBncm91cHMgdXNpbmcgKipjcm9zcy10YWJ1bGF0aW9ucyoqIGFuZCBhc3Nlc3Mgc2lnbmlmaWNhbmNlIHVzaW5nIHRoZSAqKkNoaS1TcXVhcmUgdGVzdCoqLiBGb3IgY29udGludW91cyBwcmVkaWN0b3JzLCB3ZSBjb21wYXJlIGdyb3VwICoqbWVhbnMgYW5kIHN0YW5kYXJkIGRldmlhdGlvbnMqKiBhbmQgdXNlIHRoZSAqKmluZGVwZW5kZW50IHNhbXBsZXMgdC10ZXN0KiogdG8gZGV0ZXJtaW5lIHdoZXRoZXIgdGhlIGRpZmZlcmVuY2VzIGFyZSBzdGF0aXN0aWNhbGx5IG1lYW5pbmdmdWwuCgojIyMgQmluYXJ5IFByZWRpY3RvcnMKCldlIGZpcnN0IGV4YW1pbmUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgYW5kIGJpbmFyeSBwcmVkaWN0b3JzIHRocm91Z2ggY3Jvc3MtdGFidWxhdGlvbnMuICoqQ3Jvc3MtdGFidWxhdGlvbnMgYWxsb3cgdXMgdG8gZXhwbG9yZSB0aGUgZGlzdHJpYnV0aW9uIG9mIG9ic2VydmF0aW9ucyBhY3Jvc3MgdGhlIGRpZmZlcmVudCBkZXBlbmRlbnQgdmFyaWFibGVzLioqCgpUbyBmb3JtYWxseSB0ZXN0IHdoZXRoZXIgYSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGFzc29jaWF0aW9uIGV4aXN0cyBiZXR3ZWVuIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgYW5kIGVhY2ggYmluYXJ5IHByZWRpY3Rvciwgd2UgdXNlIHRoZSAqKkNoaS1TcXVhcmUgdGVzdCoqLiBUaGUgQ2hpLVNxdWFyZSBzdGF0aXN0aWMgaXMgZGVyaXZlZCBmcm9tIHRoZSBzdW0gb2Ygc3F1YXJlZCBkaWZmZXJlbmNlcyBiZXR3ZWVuIG9ic2VydmVkIGFuZCBleHBlY3RlZCBmcmVxdWVuY2llcywgbm9ybWFsaXplZCBieSB0aGUgZXhwZWN0ZWQgZnJlcXVlbmNpZXMuIFRoZSBkZWdyZWVzIG9mIGZyZWVkb20gKGRmKSBmb3IgdGhlIHRlc3QgY2FuIGJlIGNhbGN1bGF0ZWQgYXMgXCgoUi0xKShDLTEpXCksIHdoZXJlIFwoUlwpIGlzIHRoZSBudW1iZXIgb2Ygcm93cyBhbmQgXChDXCkgaXMgdGhlIG51bWJlciBvZiBjb2x1bW5zIGluIHRoZSBjcm9zcy10YWJ1bGF0aW9uIHRhYmxlLCByZXByZXNlbnRpbmcgdGhlIG51bWJlciBvZiBjYXRlZ29yaWVzIGluIGVhY2ggb2YgdGhlIHR3byB2YXJpYWJsZXMgYmVpbmcgYW5hbHl6ZWQuIFRoZSBoeXBvdGhlc2VzIGFyZSBhcyBmb2xsb3dzOgoKLSAqKk51bGwgSHlwb3RoZXNpcyAoSDApOioqICBUaGUgcHJvcG9ydGlvbnMgb2YgZGlmZmVyZW50IGNhdGVnb3J5IG9mIHByZWRpY3RvcnMgYXJlIHRoZSBzYW1lIGZvciBkcmlua2luZyBhbmQgbm9uLWRyaW5raW5nIGRyaXZlcnMuIFRoZXJlIGlzIG5vIGFzc29jaWF0aW9uIGJldHdlZW4gdGhlIGJpbmFyeSBwcmVkaWN0b3IgYW5kIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgKERSSU5LSU5HX0QpCgotICoqQWx0ZXJuYXRpdmUgSHlwb3RoZXNpcyAoSGEpOioqIFRoZSBwcm9wb3J0aW9ucyBvZiBkaWZmZXJlbnQgY2F0ZWdvcnkgb2YgcHJlZGljdG9zIGRpZmZlciBiZXR3ZWVuIGRyaW5raW5nIGFuZCBub24tZHJpbmtpbmcgZHJpdmVycy4gVGhlcmUgaXMgYW4gYXNzb2NpYXRpb24gYmV0d2VlbiB0aGUgYmluYXJ5IHByZWRpY3RvciBhbmQgdGhlIGRlcGVuZGVudCB2YXJpYWJsZSAoRFJJTktJTkdfRCkKCklmIHRoZSBwLXZhbHVlIGlzIGJlbG93IDAuMDUsIHdlIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzIGFuZCBjb25jbHVkZSB0aGF0IHRoZXJlIGlzIGEgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBhc3NvY2lhdGlvbiBiZXR3ZWVuIHRoZSB0d28gY2F0ZWdvcmljYWwgdmFyaWFibGVzLgoKIyMjIENvbnRpbnVvdXMgUHJlZGljdG9ycwoKRm9yIGNvbnRpbnVvdXMgcHJlZGljdG9ycywgd2UgZmlyc3QgZXhhbWluZSB0aGUgY29udGludW91cyBwcmVkaWN0b3JzIGJ5IGNvbXBhcmluZyB0aGVpciAqKm1lYW5zIGFuZCBzdGFuZGFyZCBkZXZpYXRpb25zKiogZm9yIHRoZSB0d28gZ3JvdXBzIG9mIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgIChpbiB0aGlzIHJlcG9ydCwgdGhvc2Ugd2l0aCBhbmQgd2l0aG91dCBkcmlua2luZyBkcml2ZXJzIGluIGNyYXNoZXMpLiBUaGlzIGFsbG93cyB1cyB0byBjb21wYXJlIHRoZSBkaXN0cmlidXRpb25zIG9mIHRoZSBwcmVkaWN0b3IgYWNyb3NzIGdyb3Vwcy4KClRoZW4sIHdlIHVzZSB0aGUgKippbmRlcGVuZGVudCBzYW1wbGVzIHQtdGVzdCoqIHRvIGFzc2VzcyB3aGV0aGVyIHRoZSBvYnNlcnZlZCBkaWZmZXJlbmNlcyBpbiBtZWFucyBhcmUgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudC4gVGhlIGh5cG90aGVzZXMgZm9yIHRoZSB0LXRlc3QgYXJlOgoKLSAqKk51bGwgSHlwb3RoZXNpcyAoSDApOioqIFRoZSBhdmVyYWdlIHZhbHVlcyBvZiB0aGUgY29udGludW91cyBwcmVkaWN0b3IgYXJlIHRoZSBzYW1lIGZvciBjcmFzaGVzIHRoYXQgaW52b2x2ZSBkcmlua2luZyBkcml2ZXJzIGFuZCB0aG9zZSB0aGF0IGRvIG5vdC4gVGhlcmUgaXMgbm8gc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBpbiB0aGUgbWVhbnMgb2YgdGhlIGNvbnRpbnVvdXMgcHJlZGljdG9yIGZvciBjcmFzaGVzIHRoYXQgaW52b2x2ZWQgYWxjb2hvbCBhbmQgdGhvc2UgdGhhdCBkaWQgbm90LgoKLSAqKkFsdGVybmF0aXZlIEh5cG90aGVzaXMgKEhhKToqKiBUaGUgYXZlcmFnZSB2YWx1ZXMgb2YgdGhlIGNvbnRpbnVvdXMgcHJlZGljdG9yIGFyZSBkaWZmZXJlbnQgZm9yIGNyYXNoZXMgdGhhdCBpbnZvbHZlIGRyaW5raW5nIGRyaXZlcnMgYW5kIHRob3NlIHRoYXQgZG8gbm90LiBUaGVyZSBpcyBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgaW4gdGhlIG1lYW5zIG9mIHRoZSBjb250aW51b3VzIHByZWRpY3RvciBmb3IgY3Jhc2hlcyB0aGF0IGludm9sdmVkIGFsY29ob2wgYW5kIHRob3NlIHRoYXQgZGlkIG5vdC4KCklmIHRoZSBwLXZhbHVlIG9mIHQtdGVzdCBpcyBiZWxvdyAwLjA1LCB3ZSByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBpbiBmYXZvciBvZiB0aGUgYWx0ZXJuYXRpdmUsIGluZGljYXRpbmcgdGhhdCB0aGUgbWVhbiBvZiB0aGUgY29udGludW91cyBwcmVkaWN0b3Igc2lnbmlmaWNhbnRseSBkaWZmZXJzIGJldHdlZW4gdGhlIHR3byBncm91cHMuCgpCeSBwZXJmb3JtaW5nIHRoZXNlIGV4cGxvcmF0b3J5IGFuYWx5c2VzLCB3ZSBjYW4gaWRlbnRpZnkgd2hpY2ggcHJlZGljdG9ycyBleGhpYml0IHNpZ25pZmljYW50IGFzc29jaWF0aW9ucyB3aXRoIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgYW5kIHNob3VsZCBiZSBjb25zaWRlcmVkIGluIHRoZSBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsLgoKIyBSZXN1bHRzCgojIyBFeHBsb3JhdG9yeSBBbmFseXNlcwoKIyMjIERlcGVuZGVudCBWYXJpYWJsZQoKSW4gdGhlIHJlcG9ydCwgdGhlIGRlcGVuZGVudCB2YXJpYWJsZSBpcyBgRFJJTktJTkdfRGAsIGluZGljYXRpbmcgd2hldGhlciBhIGNyYXNoIGludm9sdmVkIGEgZHJpbmtpbmcgZHJpdmVyLiBPZiB0aGUgNTMsMjYwIHJlY29yZGVkIGNyYXNoZXMgaW4gUGhpbGFkZWxwaGlhIGZyb20gMjAwOCB0byAyMDEyLCB3ZSBleGNsdWRlZCA5LDg5NiBjcmFzaGVzIHRoYXQgb2NjdXJyZWQgaW4gbm9uLXJlc2lkZW50aWFsIGJsb2NrIGdyb3Vwcywgd2hlcmUgbWVkaWFuIGhvdXNlaG9sZCBpbmNvbWUgYW5kIHZhY2FuY3kgcmF0ZXMgYXJlIDAuIFRoaXMgbGVhdmVzIDQzLDM2NCBjcmFzaGVzIHRoYXQgdG9vayBwbGFjZSBpbiBQaGlsYWRlbHBoaWHigJlzIHJlc2lkZW50aWFsIGJsb2NrIGdyb3Vwcy4KCmBgYHtyfQpkZXBldGFiIDwtIHByb3AudGFibGUodGFibGUoY3Jhc2hlcyREUklOS0lOR19EKSkKZGVwdGFiIDwtIGFzLmRhdGEuZnJhbWUoZGVwZXRhYikKY29sbmFtZXMoZGVwdGFiKSA8LSBjKCJEUklOS0lOR19EIiwgIlByb3BvcnRpb24iKQpkZXB0YWIgJT4lCiAga2FibGUoImh0bWwiLCBlc2NhcGUgPSBGQUxTRSwgYWxpZ24gPSAiY2MiKSAlPiUKICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGQUxTRSwgcG9zaXRpb24gPSAiY2VudGVyIiwgZml4ZWRfdGhlYWQgPSBUUlVFKQpgYGAKCldlIHNlZSB0aGF0IHRoZXJlIGFyZSAyLDQ4NSAoNS43MyUpIGNyYXNoZXMgdGhhdCBpbnZvbHZlZCBhIGRydW5rIGRyaXZlciwgYW5kIDQwLDg3OSAoOTQuMjclKSBjcmFzaGVzIHRoYXQgZGlkIG5vdCBpbnZvbHZlIGEgZHJ1bmsgZHJpdmVyLiBUaGF0IGlzLCB0aGUgcHJvYmFiaWxpdHkgb2YgYSBjcmFzaCBpbnZvbHZpbmcgZHJpbmtpbmcgZHJpdmVycyBjYW4gYmUgY2FsY3VsYXRlZCB1c2luZyB0aGUgZm9ybXVsYToKCiQkClx0ZXh0e1Byb2JhYmlsaXR5KERyaW5raW5nIERyaXZlcnMpfSA9IFxmcmFje1x0ZXh0e051bWJlciBvZiBDcmFzaGVzIEludm9sdmluZyBEcmlua2luZyBEcml2ZXJ9fXtcdGV4dHtUb3RhbCBOdW1iZXIgb2YgQ3Jhc2hlc319ID0gXGZyYWN7MjQ4NX17NDMzNjR9IFxhcHByb3ggMC4wNTczCiQkCgpUaGUgb2RkcyBvZiBhIGNyYXNoIGludm9sdmluZyBkcmlua2luZyBkcml2ZXJzIGNhbiBiZSBjYWxjdWxhdGVkIHVzaW5nIHRoZSBmb3JtdWxhOgoKJCQKXHRleHR7T2RkcyhEcmlua2luZyBEcml2ZXJzKX0gPSBcZnJhY3tcdGV4dHtOdW1iZXIgb2YgQ3Jhc2hlcyBJbnZvbHZpbmcgRHJpbmtpbmcgRHJpdmVyfX17XHRleHR7TnVtYmVyIG9mIENyYXNoZXMgTm90IEludm9sdmluZyBEcmlua2luZyBEcml2ZXJzfX0gPSBcZnJhY3syNDg1fXs0MDg3OX0gXGFwcHJveCAwLjA2MDgKJCQKClRoaXMgc3VnZ2VzdHMgdGhhdCB3aGlsZSB0aGUgb3ZlcmFsbCBwcm9iYWJpbGl0eSBvZiBhIGNyYXNoIGJlaW5nIGFsY29ob2wtcmVsYXRlZCBpcyByZWxhdGl2ZWx5IGxvdywgdGhlIG9kZHMgc3RpbGwgd2FycmFudCBhdHRlbnRpb24sIGVzcGVjaWFsbHkgZ2l2ZW4gdGhlIHNlcmlvdXMgY29uc2VxdWVuY2VzIG9mdGVuIGFzc29jaWF0ZWQgd2l0aCBzdWNoIGluY2lkZW50cy4KCgojIyMgSW5kZXBlbmRlbnQgVmFyaWFibGVzIC0gQmluYXJ5CgpUaGVuLCBsZXQncyB0YWtlIGEgbG9vayBhdCBiaW5hcnkgaW5kZXBlbmRlbnQgdmFyaWFibGVzIGBGQVRBTF9PUl9NYCxgIE9WRVJUVVJORURgLCBgQ0VMTF9QSE9ORWAsIGBTUEVFRElOR2AsIGBBR0dSRVNTSVZFYCwgYERSSVZFUjE2MTdgLCBhbmQgYERSSVZFUjY1UExVU2AuCgpgYGB7cn0KIyBMb2FkIHJlcXVpcmVkIGxpYnJhcnkKbGlicmFyeShnbW9kZWxzKQoKIyBFbnN1cmUgYmluYXJ5IHZhcmlhYmxlcyBhcmUgZmFjdG9ycwpjcmFzaGVzJERSSU5LSU5HX0QgPC0gYXMuZmFjdG9yKGNyYXNoZXMkRFJJTktJTkdfRCkKYmluYXJ5X3ZhcnMgPC0gYygiRkFUQUxfT1JfTSIsICJPVkVSVFVSTkVEIiwgIkNFTExfUEhPTkUiLCAiU1BFRURJTkciLAogICAgICAgICAgICAgICAgICJBR0dSRVNTSVZFIiwgIkRSSVZFUjE2MTciLCAiRFJJVkVSNjVQTFVTIikKY3Jhc2hlc1tiaW5hcnlfdmFyc10gPC0gbGFwcGx5KGNyYXNoZXNbYmluYXJ5X3ZhcnNdLCBhcy5mYWN0b3IpCgojIERlZmluZSBmdW5jdGlvbiB0byBleHRyYWN0IENoaS1TcXVhcmUgdGVzdCByZXN1bHRzIGFuZCBwZXJjZW50YWdlcwpleHRyYWN0X2NoaTJfcmVzdWx0cyA8LSBmdW5jdGlvbihkZXBfdmFyLCBwcmVkX3ZhcikgewogIGNyb3NzdGFiIDwtIHRhYmxlKGRlcF92YXIsIHByZWRfdmFyKQoKICAjIFRvdGFsIGNvdW50cyBwZXIgZ3JvdXAKICB0b3RhbF9ub19hbGNvaG9sIDwtIHN1bShjcm9zc3RhYlsxLCBdKQogIHRvdGFsX2FsY29ob2wgPC0gc3VtKGNyb3NzdGFiWzIsIF0pCgogICMgQ291bnQgb2YgIjEicwogIG5vX2FsY29ob2xfMV9jb3VudCA8LSBjcm9zc3RhYlsxLCAiMSJdCiAgYWxjb2hvbF8xX2NvdW50IDwtIGNyb3NzdGFiWzIsICIxIl0KCiAgIyBQZXJjZW50YWdlcwogIHBlcmNlbnRfbm9fYWxjb2hvbCA8LSAxMDAgKiBjcm9zc3RhYlsxLCAiMSJdIC8gdG90YWxfbm9fYWxjb2hvbAogIHBlcmNlbnRfYWxjb2hvbCA8LSAxMDAgKiBjcm9zc3RhYlsyLCAiMSJdIC8gdG90YWxfYWxjb2hvbAoKICAjIENoaS1zcXVhcmUgdGVzdCB3aXRob3V0IFlhdGVzIGNvcnJlY3Rpb24KICBjaGkyX3Rlc3QgPC0gc3VwcHJlc3NXYXJuaW5ncyhjaGlzcS50ZXN0KGNyb3NzdGFiLCBjb3JyZWN0ID0gRkFMU0UpKQoKICAjIE91dHB1dCBsaXN0CiAgcmV0dXJuKGxpc3QoCiAgICBjcm9zc3RhYiA9IGNyb3NzdGFiLAogICAgbm9fYWxjb2hvbF8xX2NvdW50ID0gbm9fYWxjb2hvbF8xX2NvdW50LAogICAgYWxjb2hvbF8xX2NvdW50ID0gYWxjb2hvbF8xX2NvdW50LAogICAgcGVyY2VudF9ub19hbGNvaG9sID0gcGVyY2VudF9ub19hbGNvaG9sLAogICAgcGVyY2VudF9hbGNvaG9sID0gcGVyY2VudF9hbGNvaG9sLAogICAgdG90YWxfbiA9IHN1bShjcm9zc3RhYlssICIxIl0pLAogICAgY2hpMl9zdGF0ID0gY2hpMl90ZXN0JHN0YXRpc3RpYywKICAgIGRmID0gY2hpMl90ZXN0JHBhcmFtZXRlciwKICAgIHBfdmFsdWUgPSBjaGkyX3Rlc3QkcC52YWx1ZQogICkpCn0KCiMgSW5pdGlhbGl6ZSByZXN1bHRzIHRhYmxlCmFsbF9yZXN1bHRzIDwtIGRhdGEuZnJhbWUoCiAgVmFyaWFibGUgPSBiaW5hcnlfdmFycywKICBEZXNjcmlwdGlvbiA9IGMoCiAgICAiQ3Jhc2ggcmVzdWx0ZWQgaW4gZmF0YWxpdHkgb3IgbWFqb3IgaW5qdXJ5IiwKICAgICJDcmFzaCBpbnZvbHZlZCBhbiBvdmVydHVybmVkIHZlaGljbGUiLAogICAgIkRyaXZlciB3YXMgdXNpbmcgY2VsbCBwaG9uZSIsCiAgICAiQ3Jhc2ggaW52b2x2ZWQgc3BlZWRpbmcgY2FyIiwKICAgICJDcmFzaCBpbnZvbHZlZCBhZ2dyZXNzaXZlIGRyaXZpbmciLAogICAgIkNyYXNoIGludm9sdmVkIGF0IGxlYXN0IG9uZSBkcml2ZXIgYWdlZCAxNuKAkzE3IiwKICAgICJDcmFzaCBpbnZvbHZlZCBhdCBsZWFzdCBvbmUgZHJpdmVyIGFnZWQgNjUrIgogICksCiAgTm9fQWxjb2hvbF9OID0gTkEsCiAgTm9fQWxjb2hvbF9QZXJjZW50ID0gTkEsCiAgQWxjb2hvbF9OID0gTkEsCiAgQWxjb2hvbF9QZXJjZW50ID0gTkEsCiAgVG90YWxfTiA9IE5BLAogIENoaTJfU3RhdCA9IE5BLAogIERGID0gTkEsCiAgUF9WYWx1ZSA9IE5BCikKCiMgTG9vcCB0aHJvdWdoIHZhcmlhYmxlcyBhbmQgcG9wdWxhdGUgcmVzdWx0IHRhYmxlCmZvciAoaSBpbiBzZXFfYWxvbmcoYmluYXJ5X3ZhcnMpKSB7CiAgdmFyIDwtIGJpbmFyeV92YXJzW2ldCiAgcmVzdWx0IDwtIGV4dHJhY3RfY2hpMl9yZXN1bHRzKGNyYXNoZXMkRFJJTktJTkdfRCwgY3Jhc2hlc1tbdmFyXV0pCgogIGFsbF9yZXN1bHRzJE5vX0FsY29ob2xfTltpXSA8LSByZXN1bHQkbm9fYWxjb2hvbF8xX2NvdW50CiAgYWxsX3Jlc3VsdHMkTm9fQWxjb2hvbF9QZXJjZW50W2ldIDwtIHJvdW5kKHJlc3VsdCRwZXJjZW50X25vX2FsY29ob2wsIDEpCiAgYWxsX3Jlc3VsdHMkQWxjb2hvbF9OW2ldIDwtIHJlc3VsdCRhbGNvaG9sXzFfY291bnQKICBhbGxfcmVzdWx0cyRBbGNvaG9sX1BlcmNlbnRbaV0gPC0gcm91bmQocmVzdWx0JHBlcmNlbnRfYWxjb2hvbCwgMSkKICBhbGxfcmVzdWx0cyRUb3RhbF9OW2ldIDwtIHJlc3VsdCR0b3RhbF9uCiAgYWxsX3Jlc3VsdHMkQ2hpMl9TdGF0W2ldIDwtIHJvdW5kKHJlc3VsdCRjaGkyX3N0YXQsIDIpCiAgYWxsX3Jlc3VsdHMkREZbaV0gPC0gcmVzdWx0JGRmCiAgYWxsX3Jlc3VsdHMkUF9WYWx1ZVtpXSA8LSBmb3JtYXQucHZhbChyZXN1bHQkcF92YWx1ZSwgZGlnaXRzID0gMywgZXBzID0gMC4wNSkKfQoKYGBgCgpgYGB7cn0KIyMgcHJpbnQKCmxpYnJhcnkoa25pdHIpCmxpYnJhcnkoa2FibGVFeHRyYSkKCmthYmxlKGFsbF9yZXN1bHRzWywgYygiVmFyaWFibGUiLCAiRGVzY3JpcHRpb24iLAogICAgICAgICAgICAgICAgICAgICAgIk5vX0FsY29ob2xfTiIsICJOb19BbGNvaG9sX1BlcmNlbnQiLAogICAgICAgICAgICAgICAgICAgICAgIkFsY29ob2xfTiIsICJBbGNvaG9sX1BlcmNlbnQiLAogICAgICAgICAgICAgICAgICAgICAgIlRvdGFsX04iLCAiQ2hpMl9TdGF0IiwgIkRGIiwgIlBfVmFsdWUiKV0sCiAgICAgIGZvcm1hdCA9ICJodG1sIiwKICAgICAgY29sLm5hbWVzID0gYygiVmFyaWFibGUiLCAiRGVzY3JpcHRpb24iLAogICAgICAgICAgICAgICAgICAgICJOIiwgIiUiLCAiTiIsICIlIiwgIk4iLAogICAgICAgICAgICAgICAgICAgICJDaGkyIFN0YXQiLCAiREYiLCAiz4fCsiBwLXZhbHVlIiksCiAgICAgIGNhcHRpb24gPSAiQ3Jvc3MtVGFidWxhdGlvbiBhbmQgQ2hpLVNxdWFyZSBUZXN0IFJlc3VsdHMiKSAlPiUKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiKSwKICAgICAgICAgICAgICAgIGZ1bGxfd2lkdGggPSBGLAogICAgICAgICAgICAgICAgcG9zaXRpb24gPSAiY2VudGVyIikgJT4lCiAgY29sdW1uX3NwZWMoMSwgYm9sZCA9IFRSVUUsIHdpZHRoID0gIjEwZW0iKSAlPiUKICBjb2x1bW5fc3BlYygyLCBib2xkID0gRkFMU0UsIHdpZHRoID0gIjQwZW0iKSAlPiUKICBjb2x1bW5fc3BlYygzOjcsIHdpZHRoID0gIjdlbSIpICU+JQogIGNvbHVtbl9zcGVjKDg6MTAsIHdpZHRoID0gIjhlbSIpICU+JQogIGFkZF9oZWFkZXJfYWJvdmUoYygiICIgPSAyLAogICAgICAgICAgICAgICAgICAgICAiTm8gQWxjb2hvbCBJbnZvbHZlZCAoRFJJTktJTkdfRCA9IDApIiA9IDIsCiAgICAgICAgICAgICAgICAgICAgICJBbGNvaG9sIEludm9sdmVkIChEUklOS0lOR19EID0gMSkiID0gMiwKICAgICAgICAgICAgICAgICAgICAgIlRvdGFsIiA9IDEsCiAgICAgICAgICAgICAgICAgICAgICJDaGktU3F1YXJlIFRlc3QgUmVzdWx0cyIgPSAzKSkKCmBgYApUaGUgdGFibGUgYWJvdmUgcHJvdmlkZXMgYSBjcm9zcy10YWJ1bGF0aW9uIG9mIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgd2l0aCBlYWNoIG9mIHRoZSBiaW5hcnkgcHJlZGljdG9ycy4gV2UgdXNlIHRoZSAqKkNoaS1TcXVhcmUgdGVzdCoqLCB3aGljaCBpcyBhIHN0YXRpc3RpY2FsIG1ldGhvZCB1c2VkIHRvIGV2YWx1YXRlIHdoZXRoZXIgdGhlcmUgaXMgYSBzaWduaWZpY2FudCBhc3NvY2lhdGlvbiBiZXR3ZWVuIHR3byBjYXRlZ29yaWNhbCB2YXJpYWJsZXMuIFRoaXMgdGVzdCBjb21wYXJlcyB0aGUgb2JzZXJ2ZWQgZnJlcXVlbmNpZXMgaW4gZWFjaCBjYXRlZ29yeSB3aXRoIHRoZSBleHBlY3RlZCBmcmVxdWVuY2llcyB1bmRlciB0aGUgYXNzdW1wdGlvbiB0aGF0IHRoZSB2YXJpYWJsZXMgYXJlIGluZGVwZW5kZW50LiBBcyB1c3VhbCwgYSBoaWdoIHZhbHVlIG9mIHRoZSAkXGNoaV4yJCBzdGF0aXN0aWMsIGFuZCBhIHAtdmFsdWUgbG93ZXIgdGhhbiAwLjA1LCBzdWdnZXN0IHRoYXQgdGhlcmUgaXMgZXZpZGVuY2UgdG8gcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgaW4gZmF2b3Igb2YgdGhlIGFsdGVybmF0aXZlLCBpbmRpY2F0aW5nIGFuIGFzc29jaWF0aW9uIGJldHdlZW4gZHJ1bmsgZHJpdmluZyBhbmQgY3Jhc2ggb3V0Y29tZXMuCgpIZXJlLCB3ZSBhcHBseSB0aGUgQ2hpLVNxdWFyZSB0ZXN0IHRvIGV4cGxvcmUgdGhlIGFzc29jaWF0aW9uIGJldHdlZW4gZHJpbmtpbmcgZHJpdmVyIGluZGljYXRvcnMgaW4gY3Jhc2hlcyBgRFJJTktJTkdfRGAgYW5kIHZhcmlvdXMgYmluYXJ5IGNyYXNoLXJlbGF0ZWQgY2hhcmFjdGVyaXN0aWNzLiBUaGUgaHlwb3RoZXNlcyBhbmQgcmVzdWx0cyBhcmUgc3VtbWFyaXplZCBiZWxvdzoKCioqQ3Jhc2ggcmVzdWx0ZWQgaW4gZmF0YWxpdHkgb3IgbWFqb3IgaW5qdXJ5KiogYEZBVEFMX09SX01gCgotICoqTnVsbCBIeXBvdGhlc2lzIChIMCk6KiogVGhlIHByb3BvcnRpb25zIG9mIGNyYXNoZXMgcmVzdWx0aW5nIGluIGZhdGFsaXR5IG9yIG1ham9yIGluanVyeSBhcmUgdGhlIHNhbWUgZm9yIGRyaW5raW5nIGFuZCBub24tZHJpbmtpbmcgZHJpdmVycy4KCi0gKipBbHRlcm5hdGl2ZSBIeXBvdGhlc2lzIChIYSk6KiogVGhlIHByb3BvcnRpb25zIG9mIGNyYXNoZXMgcmVzdWx0aW5nIGluIGZhdGFsaXR5IG9yIG1ham9yIGluanVyeSBkaWZmZXIgYmV0d2VlbiBkcmlua2luZyBhbmQgbm9uLWRyaW5raW5nIGRyaXZlcnMuCgpBbW9uZyBjcmFzaGVzIGludm9sdmluZyBkcmlua2luZyBkcml2ZXJzLCA3LjYlIHJlc3VsdGVkIGluIGZhdGFsaXR5IG9yIG1ham9yIGluanVyeSwgY29tcGFyZWQgdG8gb25seSAyLjklIG9mIGNyYXNoZXMgaW52b2x2aW5nIG5vbi1kcmlua2luZyBkcml2ZXJzLiBUaGUgUC12YWx1ZSBvZiBDaGktU3F1YXJlIHN0YXRpc3RpYyBpcyBsZXNzIHRoYW4gMC4wNSwgaW5kaWNhdGluZyBhIHNpZ25pZmljYW50IGFzc29jaWF0aW9uIGJldHdlZW4gZHJpbmtpbmcgZHJpdmVycyBhbmQgY3Jhc2ggc2V2ZXJpdHkuIFRoZXJlZm9yZSwgd2UgcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgaW4gZmF2b3Igb2YgdGhlIGFsdGVybmF0aXZlIGh5cG90aGVzaXMuCgoqKkNyYXNoIGludm9sdmVkIGFuIG92ZXJ0dXJuZWQgdmVoaWNsZSoqIGBPVkVSVFVSTkVEYAoKLSAqKk51bGwgSHlwb3RoZXNpcyAoSDApOioqIFRoZSBwcm9wb3J0aW9ucyBvZiBjcmFzaGVzIGludm9sdmluZyBvdmVydHVybmVkIHZlaGljbGVzIGFyZSB0aGUgc2FtZSBmb3IgZHJpbmtpbmcgYW5kIG5vbi1kcmlua2luZyBkcml2ZXJzLgoKLSAqKkFsdGVybmF0aXZlIEh5cG90aGVzaXMgKEhhKToqKiBUaGUgcHJvcG9ydGlvbnMgb2YgY3Jhc2hlcyBpbnZvbHZpbmcgb3ZlcnR1cm5lZCB2ZWhpY2xlcyBkaWZmZXIgYmV0d2VlbiBkcmlua2luZyBhbmQgbm9uLWRyaW5raW5nIGRyaXZlcnMuCgpBbW9uZyBjcmFzaGVzIGludm9sdmluZyBkcmlua2luZyBkcml2ZXJzLCA0LjQlIGludm9sdmVkIGFuIG92ZXJ0dXJuZWQgdmVoaWNsZSwgY29tcGFyZWQgdG8gb25seSAxLjUlIG9mIGNyYXNoZXMgaW52b2x2aW5nIG5vbi1kcmlua2luZyBkcml2ZXJzLiBUaGUgUC12YWx1ZSBvZiBDaGktU3F1YXJlIHN0YXRpc3RpYyBpcyBsZXNzIHRoYW4gMC4wNSwsIGluZGljYXRpbmcgYSBzaWduaWZpY2FudCBhc3NvY2lhdGlvbiBiZXR3ZWVuIGRyaW5raW5nIGRyaXZlcnMgYW5kIG92ZXJ0dXJuZWQgY3Jhc2hlcy4gVGhlcmVmb3JlLCB3ZSByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBpbiBmYXZvciBvZiB0aGUgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcy4KCioqRHJpdmVyIHdhcyB1c2luZyBjZWxsIHBob25lKiogYENFTExfUEhPTkVgCgotICoqTnVsbCBIeXBvdGhlc2lzIChIMCk6KiogVGhlIHByb3BvcnRpb25zIG9mIGNyYXNoZXMgaW52b2x2aW5nIGNlbGwgcGhvbmUgdXNlIGFyZSB0aGUgc2FtZSBmb3IgZHJpbmtpbmcgYW5kIG5vbi1kcmlua2luZyBkcml2ZXJzLgoKLSAqKkFsdGVybmF0aXZlIEh5cG90aGVzaXMgKEhhKToqKiBUaGUgcHJvcG9ydGlvbnMgb2YgY3Jhc2hlcyBpbnZvbHZpbmcgY2VsbCBwaG9uZSB1c2UgZGlmZmVyIGJldHdlZW4gZHJpbmtpbmcgYW5kIG5vbi1kcmlua2luZyBkcml2ZXJzLgoKQW1vbmcgY3Jhc2hlcyBpbnZvbHZpbmcgZHJpbmtpbmcgZHJpdmVycywgMS4wJSBpbnZvbHZlZCBjZWxsIHBob25lIHVzZSwgY29tcGFyZWQgdG8gMS4xJSBvZiBjcmFzaGVzIGludm9sdmluZyBub24tZHJpbmtpbmcgZHJpdmVycy4gVGhlIFAtdmFsdWUgb2YgQ2hpLVNxdWFyZSBzdGF0aXN0aWMgaXMgbW9yZSB0aGFuIDAuMDUsLCBzdWdnZXN0aW5nIG5vIHNpZ25pZmljYW50IGFzc29jaWF0aW9uIHdpdGggZHJpbmtpbmcgZHJpdmVyIGluZGljYXRvcnMuIFRoZXJlZm9yZSwgd2UgZmFpbCB0byByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcy4KCioqQ3Jhc2ggaW52b2x2ZWQgc3BlZWRpbmcgY2FyKiogYFNQRUVESU5HYAoKLSAqKk51bGwgSHlwb3RoZXNpcyAoSDApOioqIFRoZSBwcm9wb3J0aW9ucyBvZiBjcmFzaGVzIGludm9sdmluZyBzcGVlZGluZyBjYXJzIGFyZSB0aGUgc2FtZSBmb3IgZHJpbmtpbmcgYW5kIG5vbi1kcmlua2luZyBkcml2ZXJzLgoKLSAqKkFsdGVybmF0aXZlIEh5cG90aGVzaXMgKEhhKToqKiBUaGUgcHJvcG9ydGlvbnMgb2YgY3Jhc2hlcyBpbnZvbHZpbmcgc3BlZWRpbmcgY2FycyBkaWZmZXIgYmV0d2VlbiBkcmlua2luZyBhbmQgbm9uLWRyaW5raW5nIGRyaXZlcnMuCgpBbW9uZyBjcmFzaGVzIGludm9sdmluZyBkcmlua2luZyBkcml2ZXJzLCAxMC41JSBpbnZvbHZlZCBzcGVlZGluZywgY29tcGFyZWQgdG8gb25seSAzLjElIG9mIGNyYXNoZXMgaW52b2x2aW5nIG5vbi1kcmlua2luZyBkcml2ZXJzLiBUaGUgUC12YWx1ZSBvZiBDaGktU3F1YXJlIHN0YXRpc3RpYyBpcyBsZXNzIHRoYW4gMC4wNSwsIGluZGljYXRpbmcgYSBzdHJvbmcgbGluayBiZXR3ZWVuIGRyaW5raW5nIGRyaXZlcnMgYW5kIHNwZWVkaW5nLiBUaGVyZWZvcmUsIHdlIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzIGluIGZhdm9yIG9mIHRoZSBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzLgoKKipDcmFzaCBpbnZvbHZlZCBhZ2dyZXNzaXZlIGRyaXZpbmcqKiBgQUdHUkVTU0lWRWAKCi0gKipOdWxsIEh5cG90aGVzaXMgKEgwKToqKiBUaGUgcHJvcG9ydGlvbnMgb2YgY3Jhc2hlcyBpbnZvbHZpbmcgYWdncmVzc2l2ZSBkcml2aW5nIGFyZSB0aGUgc2FtZSBmb3IgZHJpbmtpbmcgYW5kIG5vbi1kcmlua2luZyBkcml2ZXJzLgoKLSAqKkFsdGVybmF0aXZlIEh5cG90aGVzaXMgKEhhKToqKiBUaGUgcHJvcG9ydGlvbnMgb2YgY3Jhc2hlcyBpbnZvbHZpbmcgYWdncmVzc2l2ZSBkcml2aW5nIGRpZmZlciBiZXR3ZWVuIGRyaW5raW5nIGFuZCBub24tZHJpbmtpbmcgZHJpdmVycy4KCkFtb25nIGNyYXNoZXMgaW52b2x2aW5nIGRyaW5raW5nIGRyaXZlcnMsIDYzLjElIGludm9sdmVkIGFnZ3Jlc3NpdmUgZHJpdmluZywgY29tcGFyZWQgdG8gNTQuNyUgb2YgY3Jhc2hlcyBpbnZvbHZpbmcgbm9uLWRyaW5raW5nIGRyaXZlcnMuIFRoZSBQLXZhbHVlIG9mIENoaS1TcXVhcmUgc3RhdGlzdGljIGlzIGxlc3MgdGhhbiAwLjA1LGluZGljYXRpbmcgaGUgYXNzb2NpYXRpb24gaXMgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudC4gVGhlcmVmb3JlLCB3ZSByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBpbiBmYXZvciBvZiB0aGUgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcy4KCioqQ3Jhc2ggaW52b2x2ZWQgYXQgbGVhc3Qgb25lIGRyaXZlciBhZ2VkIDE24oCTMTcqKiBgRFJJVkVSMTYxN2AKCi0gKipOdWxsIEh5cG90aGVzaXMgKEgwKToqKiBUaGUgcHJvcG9ydGlvbnMgb2YgY3Jhc2hlcyBpbnZvbHZpbmcgYXQgbGVhc3Qgb25lIGRyaXZlciBhZ2VkIDE2LTE3IGFyZSB0aGUgc2FtZSBmb3IgZHJpbmtpbmcgYW5kIG5vbi1kcmlua2luZyBkcml2ZXJzLgoKLSAqKkFsdGVybmF0aXZlIEh5cG90aGVzaXMgKEhhKToqKiBUaGUgcHJvcG9ydGlvbnMgb2YgY3Jhc2hlcyBpbnZvbHZpbmcgYXQgbGVhc3Qgb25lIGRyaXZlciBhZ2VkIDE2LTE3IGRpZmZlciBiZXR3ZWVuIGRyaW5raW5nIGFuZCBub24tZHJpbmtpbmcgZHJpdmVycy4KCkFtb25nIGNyYXNoZXMgaW52b2x2aW5nIGRyaW5raW5nIGRyaXZlcnMsIDAuNSUgaW52b2x2ZWQgYXQgbGVhc3Qgb25lIHRlZW5hZ2UgZHJpdmVyICgxNuKAkzE3IHllYXJzIG9sZCksIGNvbXBhcmVkIHRvIDEuNiUgb2YgY3Jhc2hlcyBpbnZvbHZpbmcgbm9uLWRyaW5raW5nIGRyaXZlcnMuIFRoZSBDaGktU3F1YXJlIHN0YXRpc3RpYyBpcyAqKjE5LjcxKiogKHAgPCAwLjAwMSksIGluZGljYXRpbmcgYSBzaWduaWZpY2FudCBhc3NvY2lhdGlvbi4gVGhlcmVmb3JlLCB3ZSByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBpbiBmYXZvciBvZiB0aGUgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcy4KCioqQ3Jhc2ggaW52b2x2ZWQgYXQgbGVhc3Qgb25lIGRyaXZlciBhZ2VkIDY1IG9yIG9sZGVyKiogYERSSVZFUjY1UExVU2AKCi0gKipOdWxsIEh5cG90aGVzaXMgKEgwKToqKiBUaGUgcHJvcG9ydGlvbnMgb2YgY3Jhc2hlcyBpbnZvbHZpbmcgYXQgbGVhc3Qgb25lIGRyaXZlciBhZ2VkIDY1IG9yIG9sZGVyIGFyZSB0aGUgc2FtZSBmb3IgZHJpbmtpbmcgYW5kIG5vbi1kcmlua2luZyBkcml2ZXJzLgoKLSAqKkFsdGVybmF0aXZlIEh5cG90aGVzaXMgKEhhKToqKiBUaGUgcHJvcG9ydGlvbnMgb2YgY3Jhc2hlcyBpbnZvbHZpbmcgYXQgbGVhc3Qgb25lIGRyaXZlciBhZ2VkIDY1IG9yIG9sZGVyIGRpZmZlciBiZXR3ZWVuIGRyaW5raW5nIGFuZCBub24tZHJpbmtpbmcgZHJpdmVycy4KCkFtb25nIGNyYXNoZXMgaW52b2x2aW5nIGRyaW5raW5nIGRyaXZlcnMsIDUuMiUgaW52b2x2ZWQgYXQgbGVhc3Qgb25lIGRyaXZlciBhZ2VkIDY1IG9yIG9sZGVyLCBjb21wYXJlZCB0byAxMC40JSBvZiBjcmFzaGVzIGludm9sdmluZyBub24tZHJpbmtpbmcgZHJpdmVycy4gVGhlIENoaS1TcXVhcmUgc3RhdGlzdGljIGlzICoqNzkuOTkqKiAocCA8IDAuMDAxKSwgaW5kaWNhdGluZyBhIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgcmVsYXRpb25zaGlwIGJldHdlZW4gYWxjb2hvbCBpbnZvbHZlbWVudCBhbmQgb2xkZXIgZHJpdmVycy4uIFRoZXJlZm9yZSwgd2UgcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgaW4gZmF2b3Igb2YgdGhlIGFsdGVybmF0aXZlIGh5cG90aGVzaXMuCgpUaGUgQ2hpLVNxdWFyZSB0ZXN0IHJlc3VsdHMgaW5kaWNhdGUgKipzaWduaWZpY2FudCBhc3NvY2lhdGlvbnMqKiBiZXR3ZWVuIGRyaW5raW5nIGRyaXZlciBpbmRpY2F0b3JzIGFuZCBtb3N0IGNyYXNoLXJlbGF0ZWQgdmFyaWFibGVzLCB3aXRoIHRoZSBleGNlcHRpb24gb2YgY2VsbCBwaG9uZSB1c2UsIHdoZXJlIG5vIHNpZ25pZmljYW50IHJlbGF0aW9uc2hpcCB3YXMgZm91bmQuIEZvciBhbGwgb3RoZXIgdmFyaWFibGVzLCB3ZSByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBpbiBmYXZvciBvZiB0aGUgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcywgY29uZmlybWluZyB0aGUgcHJlc2VuY2Ugb2Ygc2lnbmlmaWNhbnQgYXNzb2NpYXRpb25zLgoKIyMjIEluZGVwZW5kZW50IFZhcmlhYmxlcyAtIENvbnRpbnVvdXMKClRoZW4sIHdlIGV4YW1pbmUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIG91ciBiaW5hcnkgZGVwZW5kZW50IHZhcmlhYmxlIGBEUklOS0lOR19EYCBhbmQgY29udGludW91cyBwcmVkaWN0b3JzIGBQQ1RCQUNITU9SYCBhbmQgYE1FREhISU5DYC4KCmBgYHtyfQoKY29udGludW91c192YXJzIDwtIGMoIlBDVEJBQ0hNT1IiLCAiTUVESEhJTkMiKQoKcmVzdWx0c19saXN0IDwtIGxpc3QoKQoKZm9yICh2YXIgaW4gY29udGludW91c192YXJzKSB7CiAgbWVhbnMgPC0gdGFwcGx5KGNyYXNoZXNbW3Zhcl1dLCBjcmFzaGVzJERSSU5LSU5HX0QsIG1lYW4sIG5hLnJtID0gVFJVRSkKICBzZHMgICA8LSB0YXBwbHkoY3Jhc2hlc1tbdmFyXV0sIGNyYXNoZXMkRFJJTktJTkdfRCwgc2QsIG5hLnJtID0gVFJVRSkKICB0X3Rlc3RfcmVzdWx0IDwtIHQudGVzdChjcmFzaGVzW1t2YXJdXSB+IGNyYXNoZXMkRFJJTktJTkdfRCkKCiAgZGVzY3JpcHRpb24gPC0gaWZlbHNlKHZhciA9PSAiUENUQkFDSE1PUiIsICJQZXJjZW50YWdlIG9mIHBvcHVsYXRpb24gd2l0aCBiYWNoZWxvcidzIGRlZ3JlZSBvciBtb3JlIiwKICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHZhciA9PSAiTUVESEhJTkMiLCAiTWVkaWFuIGhvdXNlaG9sZCBpbmNvbWUiLCBOQSkpCgogIHJlc3VsdHNfbGlzdFtbdmFyXV0gPC0gZGF0YS5mcmFtZSgKICAgIFZhcmlhYmxlICAgICAgICAgPSB2YXIsCiAgICBEZXNjcmlwdGlvbiAgICAgID0gZGVzY3JpcHRpb24sCiAgICBNZWFuX05vX0FsY29ob2wgID0gbWVhbnNbIjAiXSwKICAgIFNEX05vX0FsY29ob2wgICAgPSBzZHNbIjAiXSwKICAgIE1lYW5fQWxjb2hvbCAgICAgPSBtZWFuc1siMSJdLAogICAgU0RfQWxjb2hvbCAgICAgICA9IHNkc1siMSJdLAogICAgVF9TdGF0aXN0aWMgICAgICA9IHRfdGVzdF9yZXN1bHQkc3RhdGlzdGljLAogICAgREYgICAgICAgICAgICAgICA9IHRfdGVzdF9yZXN1bHQkcGFyYW1ldGVyLAogICAgUF9WYWx1ZSAgICAgICAgICA9IHRfdGVzdF9yZXN1bHQkcC52YWx1ZQogICkKfQoKY29udGludW91c19zdW1tYXJ5IDwtIGRvLmNhbGwocmJpbmQsIHJlc3VsdHNfbGlzdCkKcm93Lm5hbWVzKGNvbnRpbnVvdXNfc3VtbWFyeSkgPC0gTlVMTAoKIyBwcmludAprYWJsZShjb250aW51b3VzX3N1bW1hcnlbLCBjKCJWYXJpYWJsZSIsICJEZXNjcmlwdGlvbiIsICJNZWFuX05vX0FsY29ob2wiLCAiU0RfTm9fQWxjb2hvbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1lYW5fQWxjb2hvbCIsICJTRF9BbGNvaG9sIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVF9TdGF0aXN0aWMiLCAiREYiLCAiUF9WYWx1ZSIpXSwKICAgICAgZm9ybWF0ID0gImh0bWwiLAogICAgICBjb2wubmFtZXMgPSBjKCJWYXJpYWJsZSIsICJEZXNjcmlwdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgIk1lYW4iLCAiU0QiLAogICAgICAgICAgICAgICAgICAgICJNZWFuIiwgIlNEIiwKICAgICAgICAgICAgICAgICAgICAidCBTdGF0IiwgIkRGIiwgInAtdmFsdWUiKSwKICAgICAgY2FwdGlvbiA9ICJTdW1tYXJ5IG9mIENvbnRpbnVvdXMgVmFyaWFibGVzIikgJT4lCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIiksCiAgICAgICAgICAgICAgICBmdWxsX3dpZHRoID0gRiwKICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gImNlbnRlciIpICU+JQogIGNvbHVtbl9zcGVjKDEsIGJvbGQgPSBUUlVFLCB3aWR0aCA9ICIxMGVtIikgJT4lCiAgY29sdW1uX3NwZWMoMiwgYm9sZCA9IEZBTFNFLCB3aWR0aCA9ICI0MGVtIikgJT4lCiAgY29sdW1uX3NwZWMoMzo0LCB3aWR0aCA9ICI3ZW0iKSAlPiUKICBjb2x1bW5fc3BlYyg1OjYsIHdpZHRoID0gIjdlbSIpICU+JQogIGNvbHVtbl9zcGVjKDc6OSwgd2lkdGggPSAiOGVtIikgJT4lCiAgYWRkX2hlYWRlcl9hYm92ZShjKCIgIiA9IDIsCiAgICAgICAgICAgICAgICAgICAgICJObyBBbGNvaG9sIEludm9sdmVkIChEUklOS0lOR19EID0gMCkiID0gMiwKICAgICAgICAgICAgICAgICAgICAgIkFsY29ob2wgSW52b2x2ZWQgKERSSU5LSU5HX0QgPSAxKSIgPSAyLAogICAgICAgICAgICAgICAgICAgICAiVC1UZXN0IFJlc3VsdHMiID0gMykpCgpgYGAKCldlIGZpcnN0IGxvb2sgYXQgdGhlICoqbWVhbnMqKiBhbmQgKipzdGFuZGFyZCBkZXZpYXRpb25zICAoU0QpICoqIG9mIHRoZXNlIHZhcmlhYmxlcyBmb3IgY3Jhc2hlcyB0aGF0IGludm9sdmUgYWxjb2hvbCBhbmQgdGhvc2UgdGhhdCBkbyBub3QuIFRoZW4sIHdlIHVzZSB0aGUgaW5kZXBlbmRlbnQgc2FtcGxlcyB0LXRlc3QgdG8gYXNzZXNzIHdoZXRoZXIgdGhlcmUgaXMgYSBzaWduaWZpY2FudCBhc3NvY2lhdGlvbiBiZXR3ZWVuIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgYW5kIGVhY2ggb2YgdGhlIGNvbnRpbnVvdXMgcHJlZGljdG9ycy4gVGhlIHQtdGVzdCByZXN1bHRzIGluY2x1ZGUgdGhlIHQtc3RhdGlzdGljLCBkZWdyZWVzIG9mIGZyZWVkb20sIGFuZCBwLXZhbHVlLgoKKipQZXJjZW50YWdlIG9mIFBvcHVsYXRpb24gd2l0aCBCYWNoZWxvcidzIERlZ3JlZSBvciBNb3JlKiogYFBDVEJBQ0hNT1JgCgotICoqTnVsbCBIeXBvdGhlc2lzIChIMCk6KiogVGhlIGF2ZXJhZ2UgdmFsdWVzIG9mIHRoZSB2YXJpYWJsZSBQQ1RCQUNITU9SIGFyZSB0aGUgc2FtZSBmb3IgY3Jhc2hlcyB0aGF0IGludm9sdmUgZHJ1bmsgZHJpdmVycyBhbmQgY3Jhc2hlcyB0aGF0IGRvbid0LgoKLSAqKkFsdGVybmF0aXZlIEh5cG90aGVzaXMgKEhhKToqKiBUaGUgYXZlcmFnZSB2YWx1ZXMgb2YgdGhlIHZhcmlhYmxlIFBDVEJBQ0hNT1IgYXJlIGRpZmZlcmVudCBmb3IgY3Jhc2hlcyB0aGF0IGludm9sdmUgZHJ1bmsgZHJpdmVycyBhbmQgY3Jhc2hlcyB0aGF0IGRvbid0LgoKU2luY2UgdGhlIHAtdmFsdWUgaXMgKiptdWNoIGdyZWF0ZXIgdGhhbiB0aGUgMC4wNSoqIHNpZ25pZmljYW5jZSB0aHJlc2hvbGQgKHAgPSAwLjkxNCksIHdlIGZhaWwgdG8gcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMuIFRoaXMgc3VnZ2VzdHMgdGhlcmUgaXMgbm8gc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBpbiB0aGUgbWVhbiBwZXJjZW50YWdlIG9mIHRoZSBwb3B1bGF0aW9uIHdpdGggYSBiYWNoZWxvcidzIGRlZ3JlZSBvciBtb3JlIGJldHdlZW4gY3Jhc2hlcyBpbnZvbHZpbmcgZHJpbmtpbmcgYW5kIG5vbi1kcmlua2luZyBkcml2ZXJzLgoKKipNZWRpYW4gSG91c2Vob2xkIEluY29tZSoqIGBNRURISElOQ2AKCi0gKipOdWxsIEh5cG90aGVzaXMgKEgwKToqKiBUaGUgYXZlcmFnZSB2YWx1ZXMgb2YgdGhlIHZhcmlhYmxlIE1FREhISU5DIGFyZSB0aGUgc2FtZSBmb3IgY3Jhc2hlcyB0aGF0IGludm9sdmUgZHJ1bmsgZHJpdmVycyBhbmQgY3Jhc2hlcyB0aGF0IGRvbid0Li4KCi0gKipBbHRlcm5hdGl2ZSBIeXBvdGhlc2lzIChIYSk6KiogVGhlIGF2ZXJhZ2UgdmFsdWVzIG9mIHRoZSB2YXJpYWJsZSBNRURISElOQyBhcmUgZGlmZmVyZW50IGZvciBjcmFzaGVzIHRoYXQgaW52b2x2ZSBkcnVuayBkcml2ZXJzIGFuZCBjcmFzaGVzIHRoYXQgZG9uJ3QuCgpTaW5jZSB0aGUgcC12YWx1ZSBpcyBncmVhdGVyIHRoYW4gMC4wNSAocCA9IDAuMTYwKSwgd2UgZmFpbCB0byByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcy4gVGhlcmUgaXMgbm8gc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBpbiBtZWRpYW4gaG91c2Vob2xkIGluY29tZSBiZXR3ZWVuIGNyYXNoZXMgaW52b2x2aW5nIGRyaW5raW5nIGFuZCBub24tZHJpbmtpbmcgZHJpdmVycy4KCkZvciBib3RoIGNvbnRpbnVvdXMgcHJlZGljdG9ycywgYFBDVEJBQ0hNT1JgIGFuZCBgTUVESEhJTkNgLCB0aGUgcC12YWx1ZXMgZnJvbSB0aGUgdC10ZXN0cyBhcmUgYWJvdmUgdGhlIDAuMDUgc2lnbmlmaWNhbmNlIHRocmVzaG9sZCwgaW5kaWNhdGluZyB0aGF0IHRoZXJlIGlzIG5vIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSB0d28gZ3JvdXBzIChkcmlua2luZyBhbmQgbm9uLWRyaW5raW5nIGRyaXZlcnMpIGZvciB0aGVzZSBjb250aW51b3VzIHZhcmlhYmxlcy4gVGhlcmVmb3JlLCB3ZSBmYWlsIHRvIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzIGluIGJvdGggY2FzZXMsIG1lYW5pbmcgdGhlcmUgaXMgbm8gc2lnbmlmaWNhbnQgYXNzb2NpYXRpb24gYmV0d2VlbiBhbGNvaG9sIGludm9sdmVtZW50IGluIGNyYXNoZXMgYW5kIHRoZXNlIGNvbnRpbnVvdXMgcHJlZGljdG9ycy4KCiMjIExvZ2lzdGljIFJlZ3Jlc3Npb24gQXNzdW1wdGlvbnMKQmFzZWQgb24gdGhlIGNvcnJlbGF0aW9uIG1hdHJpeCBhbmQgZXhwbG9pdGF0aXZlIGFuYWx5c2lzIHJlc3VsdCwgbW9zdCBsb2dpc3RpYyByZWdyZXNzaW9uIGFzc3VtcHRpb25zIGFyZSBtZXQuIEZpcnN0LCBUaGUgYmluYXJ5IGRlcGVuZGVudCB2YXJpYWJsZSAsIERSSU5LSU5HX0QsIGZ1bGZpbGxzIHRoZSByZXF1aXJlbWVudCBmb3IgYSBiaW5hcnkgdmFyaWFibGUgKDAgYW5kIDEpLiBTZWNvbmQsIHRoZSBpbmRlcGVuZGVuY2Ugb2Ygb2JzZXJ2YXRpb24gaXMgc2F0aXNmaWVkLCBhcyBlYWNoIGNyYXNoIGlzIGNvbnNpZGVyZWQgYW4gaW5kZXBlbmRlbnQgZXZlbnQuIFRoaXJkLCB0aGUgYXNzdW1wdGlvbiBvZiBubyBwZXJmZWN0IG11bHRpY29sbGluZWFyaXR5IGlzIGFsc28gbWV0LCBhcyB0aGUgY29ycmVsYXRpb24gbWF0cml4IHNob3dzIGxvdyBwYWlyd2lzZSBwZWFyc29uIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIHByZWRpY3RvcnMsIHdpdGggb25seSB0aGUgaGlnaGVzdCBjb3JyZWxhdGlvbiBiZWluZyAwLjQ4IGJldHdlZW4gKipwZXJjZW50IHdpdGggYmFjaGVsb3IncyBkZWdyZWUgYW5kIG1lZGlhbiBob3VzZWhvbGQgaW5jb21lKiouIFRoZXNlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50cyBhcmUgYWxsIGJlbG93IDAuNSwgaW5kaWNhdGluZyB0aGF0IHRoZXJlIGlzIG5vIHBlcmZlY3QgbXVsdGljb2xsaW5lYXJpdHkgYW1vbmcgdGhlIHByZWRpY3RvcnMuIFRoZXNlIGNvcnJlbGF0aW9uIGFyZSBub3QgaGlnaCBlbm91Z2ggdG8gY2F1c2UgaW5zdGFiaWxpdHkgaW4gdGhlIG1vZGVsLiBBZGRpdGlvbmFsbHksIHRoZSBsYXJnZSBzYW1wbGUgc2l6ZSBvZiBvdmVyIDQzLDMwMCBvYnNlcnZhdGlvbnMgZW5zdXJlIHRoZSBtb2RlbCBtZWV0IHRoZSBhc3N1bXB0aW9uIGZvciBzdWZmaWNpZW50IHNhbXBsZSBzaXplLgoKSG93ZXZlciwgdGhlcmUgaXMgYSBwb3RlbnRpYWwgdmlvbGF0aW9uIGluIHRoZSBhc3N1bXB0aW9uIG9mIGxpbmVhcml0eSBvZiBsb2cgb2RkcyBmb3IgY29udGludW91cyBwcmVkaWN0b3JzLCBhcyBoaWdoIHAtdmFsdWVzIGluIHQtdGVzdCBzdWdnZXN0IHdlYWwgb3Igbm9uLWxpbmVhciByZWxhdGlvbnNoaXBzIGJldHdlZW4gKipwZXJjZW50IHdpdGggYmFjaGVsb3IncyBkZWdyZWUgYW5kIG1lZGlhbiBob3VzZWhvbGQgaW5jb21lKiogYW5kIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUuCgpVc2luZyBQZWFyc29uIGNvcnJlbGF0aW9uIHRvIG1lYXN1cmUgYXNzb2NpYXRpb25zIGJldHdlZW4gYmluYXJ5IHByZWRpY3RvcnMgaGF2ZSBzZXZlcmFsIGxpbWl0YXRpb25zLCBhcyBQZWFyc29uJ3MgY29ycmVsYXRpb24gaXMgbW9zdCBhcHByb3ByaWF0ZSBmb3IgY29udGludW91cyBub3JtYWxseSBkaXN0cmlidXRlZCB2YXJpYWJsZXMuIEZvciBiaW5hcnkgdmFyaWFibGVzIHdoaWNoIG9ubHkgaGFzIHR3byB2YWx1ZXMgKDAgYW5kIDEpLCBQZXJzb24gY29ycmVsYXRpb24gY2FuIGxlYWQgdG8gbGVzcyBtZWFuaW5nZnVsIG9yIGludGVycHJldGFibGUgY29ycmVsYXRpb24gdmFsdWVzLCBhcyB0aGUgbWVhc3VyZSBkb2VzIG5vdCBmdWxseSBjYXB0dXJlIHRoZSBhc3NvY2lhdGlvbiBiZXR3ZWVuIHR3byBiaW5hcnkgdmFyaWFibGVzLiBGdXJ0aGVybW9yZSwgUGVhcnNvbiBjb3JyZWxhdGlvbiBtYXkgdW5kZXJlc3RpbWF0ZSBvciBmYWlsIHRvIHJlZmxlY3Qgbm9uLWxpbmVhciByZWxhdGlvbnNoaXBzIHRoYXQgY291bGQgcG90ZW50aWFsbHkgZXhpc3QgYW1vbmcgYmluYXJ5IHZhcmlhYmxlLgoKKipNdWx0aWNvbGxpbmVhcml0eSBvY2N1cnMgd2hlbiB0d28gb3IgbW9yZSBwcmVkaWN0b3IgdmFyaWFibGVzIGFyZSBoaWdobHkgY29ycmVsYXRlZCwgcG90ZW50aWFsbHkgaW5mbGF0aW5nIHN0YW5kYXJkIGVycm9ycyBhbmQgZGVzdGFiaWxpemluZyBjb2VmZmljaWVudCBlc3RpbWF0ZXMuKiogQW4gZXhhbWluYXRpb24gb2Ygb3VyIGRhdGFzZXTigJlzIGNvcnJlbGF0aW9uIG1hdHJpeCByZXZlYWxzIG9ubHkgbG93IHBhaXJ3aXNlIGNvcnJlbGF0aW9ucyB3aXRoIHRoZSAqKmhpZ2hlc3Qgb2YgMC40OCoqIGJldHdlZW4gdGhlIHBlcmNlbnRhZ2Ugb2YgcmVzaWRlbnRzIHdpdGggYSBiYWNoZWxvcuKAmXMgZGVncmVlIGFuZCBtZWRpYW4gaG91c2Vob2xkIGluY29tZS4gVGhpcyB2YWx1ZSBmYWxscyB3ZWxsICoqYmVsb3cgdGhlIGNvbnZlbnRpb25hbCB0aHJlc2hvbGQgb2YgMC43KiosIGluZGljYXRpbmcgdGhhdCBvdXIgbW9kZWwgaXMgdW5saWtlbHkgdG8gc3VmZmVyIGZyb20gY29lZmZpY2llbnQgaW5zdGFiaWxpdHkgZHVlIHRvIGNvbGxpbmVhciBwcmVkaWN0b3JzLiBXaGlsZSBQZWFyc29u4oCZcyBjb3JyZWxhdGlvbiBpcyBub3QgdGhlIG9wdGltYWwgbWV0cmljIGZvciBiaW5hcnkgdmFyaWFibGVzLCBpdCBub25ldGhlbGVzcyBjb25maXJtcyB0aGUgYWJzZW5jZSBvZiBhbnkgcHJvYmxlbWF0aWMgbXVsdGljb2xsaW5lYXJpdHkgaW4gdGhpcyBhbmFseXNpcy4KCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02fQoKY3Jhc2hlcyA8LSBjcmFzaGVzICU+JQogIG11dGF0ZShhY3Jvc3MoYyhGQVRBTF9PUl9NLCBPVkVSVFVSTkVELCBDRUxMX1BIT05FLCBTUEVFRElORywKICAgICAgICAgICAgICAgICAgQUdHUkVTU0lWRSwgRFJJVkVSMTYxNywgRFJJVkVSNjVQTFVTKSwKICAgICAgICAgICAgICAgIH4gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoLikpKSkKCmNvcl9tYXRyaXggPC0gY29yKGNyYXNoZXMgJT4lIGRwbHlyOjpzZWxlY3QoLWMoQ1JOLCBEUklOS0lOR19ELCBBUkVBS0VZLCBDT0xMSVNJT05fKSksIHVzZSA9ICJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiLCBtZXRob2QgPSAicGVhcnNvbiIpCgoKY3VzdG9tX2xhYmVsIDwtIGMoCiAgIkNyYXNoIHJlc3VsdGVkIGluIGZhdGFsaXR5IG9yIG1ham9yIGluanVyeSIgPSAiRkFUQUxfT1JfTSIsCiAgIkNyYXNoIGludm9sdmVkIGFuIG92ZXJ0dXJuZWQgdmVoaWNsZSIgPSAiT1ZFUlRVUk5FRCIsCiAgIkRyaXZlciB3YXMgdXNpbmcgY2VsbCBwaG9uZSIgPSAiQ0VMTF9QSE9ORSIsCiAgIkNyYXNoIGludm9sdmVkIHNwZWVkaW5nIGNhciIgPSAiU1BFRURJTkciLAogICJDcmFzaCBpbnZvbHZlZCBhZ2dyZXNzaXZlIGRyaXZpbmciID0gIkFHR1JFU1NJVkUiLAogICJDcmFzaCBpbnZvbHZlZCBhdCBsZWFzdCBvbmUgZHJpdmVyIDE2IG9yIDE3IHllYXJzIG9sZCIgPSAiRFJJVkVSMTYxNyIsCiAgIkNyYXNoIGludm9sdmVkIGF0IGxlYXN0IG9uZSBkcml2ZXIgb3ZlciA2NSB5ZWFycyBvbGQiID0gIkRSSVZFUjY1UExVUyIsCiAgIiUgd2l0aCBiYWNoZWxvcuKAmXMgZGVncmVlIiA9ICJQQ1RCQUNITU9SIiwKICAiTWVkaWFuIGhvdXNlaG9sZCBpbmNvbWUiID0gIk1FREhISU5DIgopCgoKcm93bmFtZXMoY29yX21hdHJpeCkgPC0gbmFtZXMoY3VzdG9tX2xhYmVsKQpjb2xuYW1lcyhjb3JfbWF0cml4KSA8LSBuYW1lcyhjdXN0b21fbGFiZWwpCgpnZ2NvcnJwbG90KGNvcl9tYXRyaXgsCiAgICAgICAgICAgdHlwZSA9ICJsb3dlciIsCiAgICAgICAgICAgbGFiID0gVFJVRSwKICAgICAgICAgICBsYWJfc2l6ZSA9IDMsCiAgICAgICAgICAgY29sb3JzID0gYygiIzAwMTIxOSIsICJ3aGl0ZSIsICIjOWIyMjI2IikpICsKICBsYWJzKHRpdGxlID0gIkNvcnJlbGF0aW9uIE1hdHJpeCBmb3IgYWxsIFByZWRpY3RvciBWYXJpYWJsZXMiKSArCiAgdGhlbWUocGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSwgZmFjZSA9ICJpdGFsaWMiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA3KSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSkKCmBgYAoKIyMgbG9naXN0aWMgcmVncmVzc2lvbiByZXN1bHRzCgpPdXIgZmlyc3QgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbCBpbmNsdWRlcyBhbGwgdGhlIHByZWRpY3RvcnMgYW5kIHByZXNlbnRlZCB0aGUgcmVzdWx0cyBvZiBpdCBiZWxvdzoKCi0gKipGQVRBTF9PUl9NKio6IFRoZSBwcmVzZW5jZSBvZiBhIGZhdGFsaXR5IG9yIG1ham9yIGluanVyeSBzaWduaWZpY2FudCBpbmNyZWFzZXMgdGhlIG9kZHMgb2YgYSBkcmlua2luZyByZWxhdGVkIGNyYXNoLCB3aXRoIGFuIG9kZHMgcmF0aW8gb2YgMi4yNTcgKDk1JSBjb25maWRlbnQgaW50ZXJ2YWw6IDEuOTEgdG8gMi42NSkgYW5kIGEgaGlnaGx5IHNpZ25pZmljYW50IHAtdmFsdWUgKHAgPCAwLjAwMSkuIFRoaXMgc3VnZ2VzdHMgdGhhdCB0aGVzZSB0eXBlcyBvZiBjcmFzaGVzIGFyZSBtb3JlIHRoYW4gZG91YmxlIHRoZSBvZGRzIG9mIGJlaW5nIGFzc29jaWF0ZWQgd2l0aCBkcmlua2luZyBkcml2ZXJzLgotICoqT1ZFUlRVUk5FRCoqOiBPdmVydHVybmVkIHZlaGljbGVzIHNpZ25pZmljYW50bHkgaW5jcmVhc2UgdGhlIGxpa2VsaWhvb2Qgb2YgaXQgYmVpbmcgYSBkcmlua2luZyByZWxhdGVkIGNyYXNoIHdpdGggYW5kIG9kZCByYXRpbyBvZiAyLjUzMiAoOTUlIGNvbmZpZGVudCBpbnRlcnZhbDogMi4wNCB0byAzLjEyKSBhbmQgYSBoaWdobHkgc2lnbmlmaWNhbnQgcC12YWx1ZSAocCA8IDAuMDAxKS4gVGhpcyByZXN1bHQgaW1wbGllcyB0aGF0IG92ZXJ0dXJuZWQgdmVoaWNsZXMgYXJlIHN0cm9uZ2x5IGFzc29jaWF0ZWQgd2l0aCBhIGRyaW5raW5nLWRyaXZlciBpbmN1cnJlZCBjcmFzaGVzLgotICoqQ0VMTF9QSE9ORSoqOiBUaGUgdXNlIG9mIGNlbHBob25lIGR1cmluZyBhIGNyYXNoIHNob3dzIG5vIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNlbnQgZWZmZWN0IG9uIHRoZSBvZGRzIG9mIGEgZHJpbmtpbmctcmVsYXRlZCBjcmFzaCwgYXMgdGhlICoqcC12YWx1ZSBpcyBncmVhdGVyIHRoYW4gMC4wNSAoUD0wLjg4MSkqKi4gVGhlIG9kZCByYXRpbyBjbG9zZSB0byAxIChPUj0xLjAzLCA5NSUgY29uZmlkZW50IGludGVydmFsOiAwLjY4IHRvIDEuNDkpIGluZGljYXRlcyB0aGF0IHVzZSBvZiBjZWxscGhvbmUgbm8gc2lnbmlmaWNhbnRseSBtZWFuaW5nIGFmZmVjdCB0aGUgb2RkcyBvZiBhIGRyaW5raW5nLXJlbGF0ZWQgY3Jhc2guCi0gKipTUEVFRElORyoqOiBTcGVlZGluZyBpcyBhIGhpZ2hseSBzaWduaWZpY2FudCBwcmVkaWN0b3IsIHdpdGggYW4gb2RkIHJhdGlvIG9mIDQuNjYgKDk1JSBjb25maWRlbnQgaW50ZXJ2YWw6IDMuOTcgdG8gNS40NSkgYW5kIGEgcC12YWx1ZSBsZXNzIHRoYW4gMC4wMDEuIFRoaXMgaW5kaWNhdGVzIHRoYXQgY3Jhc2hlcyBpbnZvbHZpbmcgc3BlZWRpbmcgYXJlIG1vcmUgdGhhbiBmb3VyIHRpbWVzIGFzIGxpa2VseSB0byBpbnZvbHZlIGFsY29ob2wuCi0gKipBR0dSRVNTSVZFKio6IEFnZ3Jlc3NpdmUgZHJpdmluZyBpcyBhc3NvY2lhdGVkIHdpdGggbG93ZXIgb2RkcyBvZiBkcmlua2luZy1yZWxhdGVkIGNyYXNoZXMsIHdpdGggYW4gb2RkcyByYXRpbyBvZiAwLjU1MSAoOTUlIGNvbmZpZGVudCBpbnRlcnZhbDogMC41MCB0byAwLjYwKSBhbmQgYSBoaWdobHkgc2lnbmlmaWNhbnQgcC12YWx1ZSAocCA8IDAuMDAxKS4gVGhpcyBzdWdnZXN0cyB0aGF0IGFnZ3Jlc3NpdmUgZHJpdmluZyBpcyBsZXNzIGxpa2VseSB0byBiZSBhc3NvY2lhdGVkIHdpdGggZHJpbmtpbmcgZHJpdmVycy4KLSAqKkRSSVZFUjE2MTcqKjogSW5jaWRlbnRzIGludm9sdmluZyBkcml2ZXJzIGFnZWQgMTYtMTcgYXJlIHNpZ25pZmljYW50bHkgbGVzcyBsaWtlbHkgdG8gYXNzb2NpYXRlIHdpdGggZHJpbmtpbmctcmVsYXRlZCBjcmFzaGVzLCB3aXRoIGFuIG9kZHMgcmF0aW8gb2YgMC4yNzggKDk1JSBjb25maWRlbnQgaW50ZXJ2YWw6IDAuMTQ4IHRvIDAuNDcxKSBhbmQgYSBoaWdobHkgc2lnbmlmaWNhbnQgcC12YWx1ZSAocCA8IDAuMDAxKS4gVGhpcyBwcm9iYWJseSBjYXVzZWQgYnkgdGhlIGZhY3QgdGhhdCB0aGUgZHJpbmtpbmcgYWdlIGluIHRoZSBVUyBpcyAyMSwgYW5kIGRyaXZlcnMgYWdlZCAxNi0xNyBhcmUgbm90IGxlZ2FsbHkgYWxsb3dlZCB0byBkcmluayBhbGNvaG9sLgotICoqRFJJVkVSNjVQTFVTKio6IEluY2lkZW50cyBpbnZvbHZpbmcgZHJpdmVycyBhZ2VkIDY1IG9yIG9sZGVyIGFyZSBhbHNvIHNob3cgc2lnbmlmaWNhbnRseSBsb3dlciBvZGRzIG9mIGRyaW5raW5nLXJlbGF0ZWQsIHdpdGggYW4gb2RkcyByYXRpbyBvZiAwLjQ2MSAoOTUlIGNvbmZpZGVudCBpbnRlcnZhbDogMC4zOCB0byAwLjU1KSBhbmQgYSBoaWdobHkgc2lnbmlmaWNhbnQgcC12YWx1ZSAocCA8IDAuMDAxKS4gVGhpcyBzdWdnZXN0cyB0aGF0IG9sZGVyIGRyaXZlcnMgYXJlIGxlc3MgbGlrZWx5IHRvIGJlIGludm9sdmVkIGluIGRyaW5raW5nLXJlbGF0ZWQgY3Jhc2hlcy4KLSAqKlBDVEJBQ0hNT1IqKjogVGhlIHBlcmNlbnRhZ2Ugb2YgdGhlIHBvcHVsYXRpb24gd2l0aCBhIGJhY2hlbG9yJ3MgZGVncmVlIG9yIG1vcmUgc2hvd3Mgbm8gc2lnbmlmaWNhbnQgZWZmZWN0IG9uIHRoZSBvZGRzIG9mIGEgZHJpbmtpbmctcmVsYXRlZCBjcmFzaCwgd2l0aCBhbiBvZGRzIHJhdGlvIG9mIDEuMDAwICg5NSUgY29uZmlkZW50IGludGVydmFsOiAwLjk5IHRvIDEuMDApIGFuZCBhIHAtdmFsdWUgZ3JlYXRlciB0aGFuIDAuMDUgKHAgPSAwLjc3NSkuIFRoaXMgc3VnZ2VzdHMgdGhhdCB0aGUgZWR1Y2F0aW9uYWwgYXR0YWlubWVudCBvZiB0aGUgcG9wdWxhdGlvbiBkb2VzIG5vdCBzaWduaWZpY2FudGx5IGFmZmVjdCB0aGUgbGlrZWxpaG9vZCBvZiBkcmlua2luZy1yZWxhdGVkIGNyYXNoZXMuCi0gKipNRURISElOQyoqOiBUaGUgbWVkaWFuIGhvdXNlaG9sZCBpbmNvbWUgc2hvd3MgaGFzIGEgdmVyeSBzbGlnaHQgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBlZmZlY3Qgb24gdGhlIGxpa2VsaWhvb2Qgb2YgZHJpbmtpbmctcmVsYXRlZCBjcmFzaCwgd2l0aCBwLXZhbHVlIDwwLjA1IChwPSAwLjAzNikgYW5kIGFuIG9kZHMgcmF0aW8gb2YgMS4wMDAgKDk1JSBjb25maWRlbnQgaW50ZXJ2YWw6IDEuMDAgdG8gMS4wMCkuIFRoaXMgc3VnZ2VzdHMgdGhhdCBoaWdoZXIgbWVkaWFuIGhvdXNlaG9sZCBpbmNvbWUgaXMgYXNzb2NpYXRlZCB3aXRoIGEgdmVyeSBzbGlnaHQgbmVnbGlnaWJsZSBlZmZlY3QgaW4gdGhlIG9kZHMgb2YgZHJpbmtpbmctcmVsYXRlZCBjcmFzaGVzLgoKSW4gc3VtbWFyeSwgYEZBVEFMX09SX01gLCBgT1ZFUlRVUk5FRGAsIGBTUEVFRElOR2AsIGBBR0dSRVNTSVZFYCwgYERSSVZFUjE2MTdgLCBhbmQgYERSSVZFUjY1UExVU2AgYXJlIHRoZSBtb3N0IHNpZ25pZmljYW50IHByZWRpY3RvcnMgb2YgZHJpbmtpbmctcmVsYXRlZCBjcmFzaGVzIChQPDAuMDAxKSwgd2hpbGUgYENFTExfUEhPTkVgIGFuZCBgUENUQkFDSE1PUmAgc2hvdyBubyBzaWduaWZpY2FudCBlZmZlY3QuIEFtb25nIHRob3NlLCBgRkFUQUxfT1JfTWAsIGBPVkVSVFVSTkVEYCwgYW5kIGBTUEVFRElOR2AgYXJlIHRoZSBtb3N0IHNpZ25pZmljYW50IHByZWRpY3RvcnMgYXNzb2NpYXRlZCB3aXRoIGRyaW5raW5nLXJlbGF0ZWQgY3Jhc2hlcywgd2l0aCBvZGRzIHJhdGlvcyBncmVhdGVyIHRoYW4gMi41LiBUaGUgcHJlZGljdG9yIGBNRURISElOQ2AgaXMgbWFyZ2luYWxseSBzaWduaWZpY2FudCBhbmQgaGFzIG1pbmltYWwgZWZmZWN0IG9uIHRoZSBvZGRzIG9mIGRyaW5raW5nLXJlbGF0ZWQgY3Jhc2hlcy4KYGBge3J9CmxvZ2l0IDwtIGdsbShEUklOS0lOR19EIH4gRkFUQUxfT1JfTSArIE9WRVJUVVJORUQgKyBDRUxMX1BIT05FICsgU1BFRURJTkcgKyBBR0dSRVNTSVZFICsgRFJJVkVSMTYxNyArIERSSVZFUjY1UExVUyArIFBDVEJBQ0hNT1IgKyBNRURISElOQywgZGF0YSA9IGNyYXNoZXMsIGZhbWlseSA9IGJpbm9taWFsKQoKbG9naXRvdXRwdXQgPC0gc3VtbWFyeShsb2dpdCkKbG9naXRjb2VmZiA8LSBsb2dpdG91dHB1dCRjb2VmZmljaWVudHMKb3JfY2kgPC0gZXhwKGNiaW5kKE9SID0gY29lZihsb2dpdCksIGNvbmZpbnQobG9naXQpKSkKbG9naXRjb2VmZlssICJQcig+fHp8KSJdIDwtIHJvdW5kKGxvZ2l0Y29lZmZbLCAiUHIoPnx6fCkiXSwgNCkKZmluYWxfb3V0cHV0IDwtIGNiaW5kKGxvZ2l0Y29lZmYsIG9yX2NpKQpmaW5hbF9vdXRwdXQgJT4lCmthYmxlKCJodG1sIiwgZXNjYXBlID0gRkFMU0UsIGFsaWduID0gImNjY2NjYyIpICU+JQprYWJsZV9zdHlsaW5nKAogICAgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIpLAogICAgZnVsbF93aWR0aCAgICAgICAgPSBGQUxTRSwKICAgIHBvc2l0aW9uICAgICAgICAgID0gImNlbnRlciIKICApCmBgYAoKVGhlbiwgd2UgdGVzdCBkaWZmZXJlbnQgY3V0b2ZmIHRocmVzaG9sZCB0byBzZWUgdGhlIG1vZGVsIG92ZXJhbGwgcGVyZm9ybWFuY2UgdGhyb3VnaCB0aGUgc3BlY2lmaWNpdHksIHNlbnNpdGl2aXR5LCBhbmQgbWlzY2xhc3NmaWNpYW50aW9uIHJhdGUuIFRoZSB0YWJsZSBiZWxvdyBwcmVzZW50cyB0aGUgc3BlY2lmaWNpdHksIHNlbnNpdGl2aXR5LCBhbmQgbWlzY2xhc3NpZmljYXRpb24gcmF0ZXMgZm9yIHZhcmlvdXMgcHJvYmFiaWxpdHkgY3V0LW9mZnMgaW4gcHJlZGljdGluZyB0aGUgbGlrZWxpaG9vZCBvZiBhIGRyaW5raW5nLXJlbGF0ZWQgY3Jhc2guCgpUaGUgcHJvYmFiaWxpdHkgY3V0LW9mZiB2YWx1ZSBvZiAwLjUwIHlpZWxkcyB0aGUgbG93ZXN0IG1pc2NsYXNzZmljYXRpb24gcmF0ZSBvZiAwLjA1Ny4gQXQgdGhpcyB0aHJlc2hvbGQsIHNwZWNpZmljaXR5IGlzIG1heGltaXplZCBhdCAxLCBidXQgc2Vuc2l0aXZpdHkgaXMgcmVsYXRpdmUgbG93IGF0IDAuMDIuIFRoaXMgaW5kaWNhdGUgdGhlIG1vZGVsIGNhcHR1cmUgcmVsYXRpdmVseSBmZXcgdHJ1ZSBwb3NpdGl2ZSBjYXNlcyBvZiBkcmlua2luZy1yZWxhdGVkIGNyYXNoZXMsIGJ1dCBpdCBpcyB2ZXJ5IGdvb2QgYXQgaWRlbnRpZnlpbmcgbm9uLWRyaW5raW5nIHJlbGF0ZWQgY3Jhc2hlcy4KClRoZSBoaWdoZXN0IG1pc2NsYXNzZmljYXRpb24gcmF0ZSBvY2N1cnMgYXQgdGhlIGN1dC1vZmYgb2YgMC4wMiB3aXRoIGEgcmF0ZSBvZiAwLjg4OS4gQXQgdGhpcyB0aHJlc2hvbGQsIHNlbnNpdGl2aXR5IGlzIGhpZ2ggYXQgMC44OTksIGNhcHR1cmluZyBhIGhpZ2ggcHJvcG9ydGlvbiBvZiB0cnVlIHBvc2l0aXZlIGNhc2VzLCBidXQgc3BlY2lmaWNpdHkgaXMgdmVyeSBsb3cgYXQgMC4wNTguIFRoaXMgaW5kaWNhdGVzIHRoYXQgdGhlIG1vZGVsIG1pc2NsYXNzaWZpZXMgYSBsYXJnZSBudW1iZXIgb2Ygbm9uLWRyaW5raW5nIHJlbGF0ZWQgY3Jhc2hlcyBhcyBkcmlua2luZy1yZWxhdGVkIGNyYXNoZXMuCgpgYGB7cn0KY3V0b2ZmcyA8LSBjKDAuMDIsIDAuMDMsIDAuMDUsIDAuMDcsIDAuMDgsIDAuMDksIDAuMTAsIDAuMTUsIDAuMjAsIDAuNTApCnJlc3VsdHMgPC0gZGF0YS5mcmFtZSgKICBDdXRvZmYgPSBjdXRvZmZzLAogIFNlbnNpdGl2aXR5ID0gTkFfcmVhbF8sCiAgU3BlY2lmaWNpdHkgPSBOQV9yZWFsXywKICBNaXNjbGFzc2lmaWNhdGlvblJhdGUgPSBOQV9yZWFsXwopCgoj4oCT4oCTIDMuIFB1bGwgb3V0IHRydWUgbGFiZWxzIGFuZCBwcmVkaWN0ZWQgcHJvYmFiaWxpdGllcwpsYWJlbHMgICAgICA8LSBjcmFzaGVzJERSSU5LSU5HX0QKcHJlZGljdGlvbnMgPC0gZml0dGVkKGxvZ2l0KSAgICMgb3IgbG9naXQkZml0dGVkLnZhbHVlcwoKI+KAk+KAkyA0LiBNZXRyaWPigJBjYWxjdWxhdGlvbiBmdW5jdGlvbgpjYWxjdWxhdGVfbWV0cmljcyA8LSBmdW5jdGlvbihjdXRvZmYsIGxhYmVscywgcHJlZHMpIHsKICBwcmVkc19iaW4gPC0gaWZlbHNlKHByZWRzID49IGN1dG9mZiwgMSwgMCkKICB0cCAgPC0gc3VtKHByZWRzX2JpbiA9PSAxICYgbGFiZWxzID09IDEpCiAgdG4gIDwtIHN1bShwcmVkc19iaW4gPT0gMCAmIGxhYmVscyA9PSAwKQogIGZwICA8LSBzdW0ocHJlZHNfYmluID09IDEgJiBsYWJlbHMgPT0gMCkKICBmbiAgPC0gc3VtKHByZWRzX2JpbiA9PSAwICYgbGFiZWxzID09IDEpCiAgc2VucyA8LSB0cCAvICh0cCArIGZuKQogIHNwZWMgPC0gdG4gLyAodG4gKyBmcCkKICBtaXMgIDwtIChmcCArIGZuKSAvIGxlbmd0aChsYWJlbHMpCiAgYyhTZW5zaXRpdml0eSA9IHNlbnMsCiAgICBTcGVjaWZpY2l0eSA9IHNwZWMsCiAgICBNaXNjbGFzc2lmaWNhdGlvblJhdGUgPSBtaXMpCn0KCiPigJPigJMgNS4gUG9wdWxhdGUgcmVzdWx0cyB0YWJsZQpmb3IgKGkgaW4gc2VxX2Fsb25nKGN1dG9mZnMpKSB7CiAgcmVzdWx0c1tpLCAyOjRdIDwtIGNhbGN1bGF0ZV9tZXRyaWNzKGN1dG9mZnNbaV0sIGxhYmVscywgcHJlZGljdGlvbnMpCn0KCiPigJPigJMgNi4gUmVuZGVyIGFzIGEgc3R5bGVkIGthYmxlCnJlc3VsdHMgJT4lCiAga2FibGUoCiAgICBjYXB0aW9uID0gIk1vZGVsIFBlcmZvcm1hbmNlIE1ldHJpY3MgQWNyb3NzIFByb2JhYmlsaXR5IEN1dG9mZnMiLAogICAgZGlnaXRzICA9IDMsCiAgICBhbGlnbiAgID0gYygiYyIsImMiLCJjIiwiYyIpCiAgKSAlPiUKICBrYWJsZV9zdHlsaW5nKAogICAgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIpLAogICAgZnVsbF93aWR0aCAgICAgICAgPSBGQUxTRSwKICAgIHBvc2l0aW9uICAgICAgICAgID0gImNlbnRlciIKICApCmBgYAoKVGhlIFJPQyBjdXJ2ZSBiZWxvdyBzaG93IHRoZSB0cmFkZSBvZiBiZXR3ZWVuIHNlbnNpdGl2aXR5IGFuZCBzcGVjaWZpY2l0eSBhY3Jvc3MgdmFyaW91cyBjdXQtb2ZmcyB0aHJlc2hvbGQgZm9yIHRoZSBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsLiBBbiBpZGVhbCBtb2RlbCB3b3VsZCByZWFjaCB0aGUgdG9wLWxlZnQgY29ybmVyIG9mIHRoZSBST0Mgc3BhY2UsIHdoZXJlIHNlbnNpdGl2aXR5IGFuZCBzcGVjaWZpY2l0eSBhbGwgZXF1YWwgdG8gb25lLCB3aGljaCB3b3VsZCBtZWFuIHBlcmZlY3QgY2xhc3NpZmljYXRpb25zLiBPdXIgUk9DIGN1cnZlIGxpZXMgYmVuZWF0aCB0aGUgaWRlYWwgcG9pbnQsIGluZGljYXRpbmcgdHJhZGUtb2ZmcyBiZXR3ZWVuIHNlbnNpdGl2aXR5IGFuZCBzcGVjaWZpY2l0eSBhdCBlYWNoIGN1dC1vZmYuCmBgYHtyIHJvYyBtZWFzdXJlcywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KCmZpdCA8LSBsb2dpdCRmaXR0ZWQKYSA8LSBjYmluZChjcmFzaGVzJERSSU5LSU5HX0QsIGZpdCkKY29sbmFtZXMoYSkgPC0gYygibGFiZWxzIiwgInByZWRpY3Rpb25zIikKcm9jIDwtIGFzLmRhdGEuZnJhbWUoYSkKYGBgCgoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmdncGxvdChyb2MsIGFlcyhkID0gbGFiZWxzLCBtID0gcHJlZGljdGlvbnMpKSArCiAgZ2VvbV9yb2Mobi5jdXRzID0gNTAsIGxhYmVscyA9IEZBTFNFLCBjb2xvdXIgPSAiIzI4M2QzYiIpICsKICBsYWJzKHRpdGxlID0gIlJPQyBDdXJ2ZSIpICsKICBzdHlsZV9yb2ModGhlbWUgPSB0aGVtZV9ncmV5KSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBzaXplID0gMSwgY29sb3IgPSAiI2M0NDUzNiIpICsKICB0aGVtZSgKICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDksIGZhY2UgPSAiaXRhbGljIiksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSwKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXkiLCBmaWxsID0gTkEsIGxpbmV3aWR0aCA9IDAuOCkKICApCmBgYAoKV2UgY2FsY3VsYXRlZCB0aGUgb3B0aW1hbCBjdXQtb2ZmIGJ5IG1pbmltaXppbmcgdGhlIEV1Y2xpZGVhbiBkaXN0YW5jZSBmcm9tIHRoZSBST0MgY3VydmUgdG8gdGhlIHRvcC1sZWZ0IGNvcm5lciBvZiB0aGUgUk9DIHNwYWNlLCB3aGljaCByZXByZXNlbnRzIHRoZSBpZGVhbCBwb2ludCB3aGVyZSBib3RoIHNlbnNpdGl2aXR5IGFuZCBzcGVjaWZpY2l0eSBhcmUgZXF1YWwgdG8gMS4gVGhpcyBjdXQtb2ZmIG9mIDAuMDY0IHByb3ZpZGVzIGEgYmFsYW5jZSBhcHByb2FjaGVzIGJldHdlZW4gc3BlY2lmaWNpdHkgYW5kIHNlbnNpdGl2aXR5LCB3aXRoIGEgc2Vuc2l0aXZpdHkgb2YgMC42NjEgYW5kIHNwZWNpZmljaXR5IG9mIDAuNTQ1LgpgYGB7cn0KcHJlZCA8LSBwcmVkaWN0aW9uKHJvYyRwcmVkaWN0aW9ucywgcm9jJGxhYmVscykKcm9jLnBlcmYgPC0gcGVyZm9ybWFuY2UocHJlZCwgbWVhc3VyZSA9ICJ0cHIiLCB4Lm1lYXN1cmUgPSAiZnByIikKCm9wdC5jdXQgPC0gZnVuY3Rpb24ocGVyZiwgcHJlZCkgewogIGN1dC5pbmQgPC0gbWFwcGx5KEZVTiA9IGZ1bmN0aW9uKHgsIHksIHApIHsKICAgIGQgPC0gKHggLSAwKV4yICsgKHkgLSAxKV4yCiAgICBpbmQgPC0gd2hpY2goZCA9PSBtaW4oZCkpCiAgICBjKHNlbnNpdGl2aXR5ID0geVtbaW5kXV0sIHNwZWNpZmljaXR5ID0gMSAtIHhbW2luZF1dLCBjdXRvZmYgPSBwW1tpbmRdXSkKICB9LCBwZXJmQHgudmFsdWVzLCBwZXJmQHkudmFsdWVzLCBwcmVkQGN1dG9mZnMpCgogIGN1dC5kZiA8LSBkYXRhLmZyYW1lKAogICAgc2Vuc2l0aXZpdHkgPSBjdXQuaW5kWzEsIF0sCiAgICBzcGVjaWZpY2l0eSA9IGN1dC5pbmRbMiwgXSwKICAgIGN1dG9mZiA9IGN1dC5pbmRbMywgXQogICkKICByb3duYW1lcyhjdXQuZGYpIDwtIE5VTEwKICByZXR1cm4oY3V0LmRmKQp9CgpvcHRpbWFsX2N1dG9mZnNfZGYgPC0gb3B0LmN1dChyb2MucGVyZiwgcHJlZCkKb3B0aW1hbF9jdXRvZmZzX2RmICU+JQogIGthYmxlKCJodG1sIiwgZXNjYXBlID0gRkFMU0UsIGFsaWduID0gImNjYyIpICU+JQogIGthYmxlX3N0eWxpbmcoCiAgICBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIiksCiAgICBmdWxsX3dpZHRoICAgICAgICA9IEZBTFNFLAogICAgcG9zaXRpb24gICAgICAgICAgPSAiY2VudGVyIgogICkKYGBgCgpJbiB0aGUgYWJvdmUgc2VjdGlvbiwgdGhlIG9wdGltYWwgY3V0LW9mZiBiYXNlZCBvbiB0aGUgbWluaW11bSBtaXNjbGFzc2lmaWNhdGlvbiByYXRlIHdhcyAwLjUwLCB3aGljaCB5aWVsZGVkIGEgbWlzY2xhc3NmaWNhdGlvbiByYXRlIG9mIDAuMDU3LiBUaGlzIHRocmVzaG9sZCBmb2N1c2VkIG1vcmUgb24gcHJpb3JpdGl6aW5nIHNwZWNpZmljaXR5ICgxLjAwKSwgYnV0IHJlc3VsdGluZyBpbiBsb3cgc2Vuc2l0aXZpdHkgKDAuMDIpLiBJbiBjb250cmFzdCwgdGhlIG9wdGltYWwgY3V0LW9mZiBiYXNlZCBvbiB0aGUgUk9DIGN1cnZlIHdhcyAwLjA2NCwgd2hpY2ggcHJvdmlkZWQgYSBiYWxhbmNlIGJldHdlZW4gc2Vuc2l0aXZpdHkgKDAuNjYxKSBhbmQgc3BlY2lmaWNpdHkgKDAuNTQ1KS4gVGhpcyBjdXQtb2ZmIGlzIG1vcmUgc3VpdGFibGUgZm9yIHByYWN0aWNhbCBhcHBsaWNhdGlvbnMgd2hlcmUgYm90aCBmYWxzZSBwb3NpdGl2ZXMgYW5kIGZhbHNlIG5lZ2F0aXZlcyBhcmUgaW1wb3J0YW50IHRvIGNvbnNpZGVyLgoKVGhlIEFSRUEgVW5kZXIgdGhlIFJPQyBDdXJ2ZSAoQVVDKSBmb3Igb3VyIG1vZGVsIGlzIDAuNjQwIHN1Z2dlc3RzIHRoYXQgdGhlIG1vZGVsIGhhcyBwb29yIGRpc2NyaW1pbmF0aW9uIGJhc2VkIG9uIHRoZSBtZXRyaXggcHJvdmlkZWQgaW4gdGhlIG1ldGhvZCBzZWN0aW9uLiBUaGUgQVVDIHZhbHVlIG1lYW4gdGhhdCBpZiB3ZSByYW5kb21seSBzZWxlY3Qgb25lIHBvc2l0aXZlIGNhc2UgYW5kIG5lZ2F0aXZlIGNhc2UsIHRoZSBtb2RlbCBoYXMgYSA2NCUgY2hhbmNlIG9mIGNvcnJlY3RseSByYW5raW5nIHRoZSBwb3NpdGl2ZSBjYXNlIGhpZ2hlciB0aGFuIHRoZSBuZWdhdGl2ZSBjYXNlLiBJbiBwcmFjdGljYWwsIHRoaXMgaW5kaWNhdGVzIHRoYXQgd2hpbGUgdGhlIG1vZGVsIGlzIGFibGUgdG8gZGlzdGluZ3Vpc2ggYmV0d2VlbiBjcmFzaGVzIHdpdGggYW5kIHdpdGhvdXQgYWxjb2hvbCBpbnZvbHZlbWVudCB0byBzb21lIGV4dGVudCwgaXRzIHBlcmZvcm1hbmNlIGlzIGxpbWl0ZWQgYW5kIG1heSBtaXNjbGFzc2lmeSBhIHN1YnN0YW50aWFsIG51bWJlciBvZiBvYnNlcnZhdGlvbnMuCgpgYGB7cn0KYXVjLnBlcmYgPC0gIHBlcmZvcm1hbmNlKHByZWQsIG1lYXN1cmUgPSJhdWMiKQphdWMudmFsdWUgPC0gYXVjLnBlcmZAeS52YWx1ZXMKY2F0KHNwcmludGYoIkFVQzogJS4zZlxuIiwgYXVjLnZhbHVlKSkKYGBgCgpUaGUgc2Vjb25kIGxvZ2lzdGljIG1vZGVsIHdlIHJhbiBvbmx5IGluY2x1ZGVzIHRoZSBiaW5hcnkgcHJlZGljdG9ycy4gUENUQkFDSE1PUiBhbmQgTUVESEhJTkMgd2VyZSBub3QgaW5jbHVkZWQgYXMgdGhleSB3ZXJlIG5vdCBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IHByZWRpY3RvcnMgaW4gdGhlIGZpcnN0IG1vZGVsLiBIb3dldmVyLCBpbiB0aGUgc2Vjb25kIG1vZGVsLCB0aGUgZXhjbHVzaW9uIG9mIHRoZXNlIHR3byBwcmVkaWN0b3JzIGRpZCBub3QgbGVhZCB0byBhbnkgcHJlZGljdG9ycyBiZWNvbWluZyBzaWduaWZpY2FudCBvciBhbnkgcHJldmlvdXMgc2lnbmlmaWNhbnQgcHJlZGljdG9ycyBiZWNvbWluZyBub24tc2lnbmlmaWNhbnQuIFRoZSBvZGRzIHJhdGlvcyAoT1IpIGZvciB0aGUgYmluYXJ5IHByZWRpY3RvcnMgaW4gYm90aCBtb2RlbHMgYXJlIHZlcnkgc2ltaWxhciwgc3VnZ2VzdGluZyB0aGF0IHJlbW92aW5nIFBDVEJBQ0hNT1IgYW5kIE1FREhISU5DIGhhZCBsaXR0bGUgaW1wYWN0IG9uIHRoZSBlc3RpbWF0ZWQgZWZmZWN0cyBvZiB0aGUgb3RoZXIgdmFyaWFibGVzLgpgYGB7cn0KbG9naXQyIDwtIGdsbShEUklOS0lOR19EIH4gRkFUQUxfT1JfTSArIE9WRVJUVVJORUQgKyBDRUxMX1BIT05FICsgU1BFRURJTkcgKyBBR0dSRVNTSVZFICsgRFJJVkVSMTYxNyArIERSSVZFUjY1UExVUywgZGF0YSA9IGNyYXNoZXMsIGZhbWlseSA9IGJpbm9taWFsKQoKbG9naXRvdXRwdXQyIDwtIHN1bW1hcnkobG9naXQyKQpsb2dpdGNvZWZmMiA8LSBsb2dpdG91dHB1dDIkY29lZmZpY2llbnRzCm9yX2NpMiA8LSBleHAoY2JpbmQoT1IgPSBjb2VmKGxvZ2l0MiksIGNvbmZpbnQobG9naXQyKSkpCmxvZ2l0Y29lZmYyWywgIlByKD58enwpIl0gPC0gcm91bmQobG9naXRjb2VmZjJbLCAiUHIoPnx6fCkiXSwgNCkKZmluYWxfb3V0cHV0MiA8LSBjYmluZChsb2dpdGNvZWZmMiwgb3JfY2kyKQpmaW5hbF9vdXRwdXQyICU+JQogIGthYmxlKCJodG1sIiwgZXNjYXBlID0gRkFMU0UsIGFsaWduID0gImNjY2NjYyIpICU+JQogIGthYmxlX3N0eWxpbmcoCiAgICBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIiksCiAgICBmdWxsX3dpZHRoICAgICAgICA9IEZBTFNFLAogICAgcG9zaXRpb24gICAgICAgICAgPSAiY2VudGVyIgogICkKYGBgClRoZSBBa2Fpa2UgSW5mb3JtYXRpb24gQ3JpdGVyaW9uIChBSUMpIGZvciBib3RoIG1vZGVscyBpcyAxODM2MC4gQUlDIGlzIGEgbWVhc3VyZSBvZiBtb2RlbCBxdWFsaXR5IHRoYXQgYmFsYW5jZXMgZ29vZG5lc3Mgb2YgZml0IHdpdGggbW9kZWwgY29tcGxleGl0eS4gU2luY2UgdGhlIEFJQyBpcyB0aGUgc2FtZSBmb3IgYm90aCBtb2RlbHMsIGl0IHN1Z2dlc3RzIHRoYXQgdGhlIHNlY29uZCBtb2RlbCAod2l0aCBvbmx5IGJpbmFyeSBwcmVkaWN0b3JzKSBpcyBqdXN0IGFzIGdvb2QgYXMgdGhlIGZpcnN0IG1vZGVsICh3aXRoIGFsbCBwcmVkaWN0b3JzKSBpbiB0ZXJtcyBvZiBleHBsYWluaW5nIHRoZSBkYXRhLiBUaGlzIGluZGljYXRlcyB0aGF0IHRoZSBhZGRpdGlvbmFsIGNvbXBsZXhpdHkgb2YgaW5jbHVkaW5nIFBDVEJBQ0hNT1IgYW5kIE1FREhISU5DIGluIHRoZSBmaXJzdCBtb2RlbCBkb2VzIG5vdCBwcm92aWRlIGEgc2lnbmlmaWNhbnQgaW1wcm92ZW1lbnQgaW4gbW9kZWwgZml0LCBhbmQgdGh1cywgdGhlIHNpbXBsZXIgbW9kZWwgd2l0aCBvbmx5IGJpbmFyeSBwcmVkaWN0b3JzIGlzIHByZWZlcnJlZC4KCmBgYHtyfQphaWNfdGFibGUgPC0gQUlDKGxvZ2l0LCBsb2dpdDIpCmNvbG5hbWVzKGFpY190YWJsZSkgPC0gYygiRGVncmVlIG9mIEZyZWVkb20iLCAiQUlDIikKcm93bmFtZXMoYWljX3RhYmxlKSA8LSBjKCJNb2RlbCAxOiBBbGwgUHJlZGljdG9ycyIsICJNb2RlbCAyOiBCaW5hcnkgUHJlZGljdG9ycyBPbmx5IikKYWljX3RhYmxlICU+JQogIGthYmxlKCJodG1sIiwgZXNjYXBlID0gRkFMU0UsIGFsaWduID0gImNjIikgJT4lCiAga2FibGVfc3R5bGluZygKICAgIGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiKSwKICAgIGZ1bGxfd2lkdGggICAgICAgID0gRkFMU0UsCiAgICBwb3NpdGlvbiAgICAgICAgICA9ICJjZW50ZXIiCiAgKQpgYGAKCiMgRGlzY3Vzc2lvbgoKSW4gdGhpcyBwYXBlciwgd2UgZXhhbWluZWQgb3ZlciA0MywwMDAgbW90b3IgdmVoaWNsZSBjcmFzaGVzIGluIFBoaWxhZGVscGhpYSBmcm9tIDIwMDggdG8gMjAxMiB0byBpZGVudGlmeSB3aGljaCBmYWN0b3JzIHdlcmUgYXNzb2NpYXRlZCB3aXRoIGFsY29ob2wgaW52b2x2ZW1lbnQgdXNpbmcgbG9naXN0aWMgcmVncmVzc2lvbi4gV2UgZXhwbG9yZWQgYSBtaXggb2YgYmluYXJ5IGNyYXNoLWxldmVsIGluZGljYXRvcnMgYW5kIG5laWdoYm9yaG9vZC1sZXZlbCBjb250aW51b3VzIHByZWRpY3RvcnMgdG8gYXNzZXNzIHRoZWlyIHJlbGF0aW9uc2hpcCB3aXRoIHRoZSBsaWtlbGlob29kIHRoYXQgYSBjcmFzaCBpbnZvbHZlZCBhIGRyaW5raW5nIGRyaXZlci4KCioqU2V2ZXJhbCB2YXJpYWJsZXMgZW1lcmdlZCBhcyBzdHJvbmcgcHJlZGljdG9ycyBvZiBhbGNvaG9sLWludm9sdmVkIGNyYXNoZXMuKiogQ3Jhc2hlcyB0aGF0IHJlc3VsdGVkIGluIGZhdGFsaXRpZXMgb3IgbWFqb3IgaW5qdXJpZXMsIGludm9sdmVkIG92ZXJ0dXJuZWQgdmVoaWNsZXMsIG9yIGludm9sdmVkIHNwZWVkaW5nIHdlcmUgc2lnbmlmaWNhbnRseSBtb3JlIGxpa2VseSB0byBpbmNsdWRlIGEgZHJpbmtpbmcgZHJpdmVyLiBPbiB0aGUgb3RoZXIgaGFuZCwgdGhlIHByZXNlbmNlIG9mIGFnZ3Jlc3NpdmUgZHJpdmluZywgdGVlbmFnZSBkcml2ZXJzLCBhbmQgZWxkZXJseSBkcml2ZXJzIHdlcmUgYWxsIHNpZ25pZmljYW50bHkgYXNzb2NpYXRlZCB3aXRoIGxvd2VyIG9kZHMgb2YgYWxjb2hvbCBpbnZvbHZlbWVudC4gQ2VsbCBwaG9uZSB1c2Ugc2hvd2VkIG5vIHNpZ25pZmljYW50IGFzc29jaWF0aW9uLCBub3IgZGlkIHRoZSBuZWlnaGJvcmhvb2QtbGV2ZWwgdmFyaWFibGVz4oCUcGVyY2VudGFnZSBvZiByZXNpZGVudHMgd2l0aCBhIGJhY2hlbG9y4oCZcyBkZWdyZWUgYW5kIG1lZGlhbiBob3VzZWhvbGQgaW5jb21lLgoKV2hpbGUgbWFueSByZXN1bHRzIGFsaWduZWQgd2l0aCBleHBlY3RhdGlvbnPigJRwYXJ0aWN1bGFybHkgdGhlIHN0cm9uZyBsaW5rcyBiZXR3ZWVuIGFsY29ob2wgaW52b2x2ZW1lbnQgYW5kIHNwZWVkaW5nIG9yIHNldmVyZSBjcmFzaGVz4oCUdGhlIGxhY2sgb2Ygc2lnbmlmaWNhbmNlIGZvciBzb2Npb2Vjb25vbWljIHByZWRpY3RvcnMgd2FzIHNvbWV3aGF0IHVuZXhwZWN0ZWQuIEl0IHN1Z2dlc3RzIHRoYXQgd2hpbGUgbmVpZ2hib3Job29kIGNvbnRleHQgaXMgb2Z0ZW4gaW1wb3J0YW50IGluIHNoYXBpbmcgaGVhbHRoIGFuZCBzYWZldHkgb3V0Y29tZXMsIGl0IG1heSBwbGF5IGEgbW9yZSBsaW1pdGVkIHJvbGUgaW4gcHJlZGljdGluZyB3aGV0aGVyIGFuIGluZGl2aWR1YWwgY3Jhc2ggaW52b2x2ZWQgYWxjb2hvbC4gU2ltaWxhcmx5LCB0aGUgaW52ZXJzZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBhZ2dyZXNzaXZlIGRyaXZpbmcgYW5kIGFsY29ob2wgaW52b2x2ZW1lbnQgbWF5IHJlZmxlY3QgZGlmZmVyZW50IGJlaGF2aW9yYWwgcmlzayBwcm9maWxlcywgd2hlcmUgYWxjb2hvbCBpbXBhaXJtZW50IHN1YnN0aXR1dGVzLCByYXRoZXIgdGhhbiBjb2luY2lkZXMgd2l0aCwgY2VydGFpbiBmb3JtcyBvZiByZWNrbGVzc25lc3MuCgpMb2dpc3RpYyByZWdyZXNzaW9uIHdhcyBhbiBhcHByb3ByaWF0ZSBtb2RlbGluZyBjaG9pY2UgZ2l2ZW4gdGhlIGJpbmFyeSBvdXRjb21lIGFuZCB0aGUgbGFyZ2UsIGluZGVwZW5kZW50IGRhdGFzZXQuIEhvd2V2ZXIsIHNpbmNlIG9ubHkgNS43JSBvZiBjcmFzaGVzIGludm9sdmVkIGEgZHJpbmtpbmcgZHJpdmVyLCB0aGUgcHJvYmxlbSBxdWFsaWZpZXMgYXMgYSByYXJlIGV2ZW50IHNjZW5hcmlvLiBJbiBzdWNoIGNhc2VzLCBhbHRlcm5hdGl2ZSBhcHByb2FjaGVzIGxpa2UgcmFyZSBldmVudCBsb2dpc3RpYyByZWdyZXNzaW9uLCBhcyBwcm9wb3NlZCBieSBQYXVsIEFsbGlzb24sIG1heSBvZmZlciBpbXByb3ZlZCBwYXJhbWV0ZXIgZXN0aW1hdGVzIGFuZCBiZXR0ZXIgY2xhc3NpZmljYXRpb24gcGVyZm9ybWFuY2UsIGVzcGVjaWFsbHkgZm9yIHBvbGljeSBhcHBsaWNhdGlvbnMgdGhhdCByZXF1aXJlIGFjY3VyYXRlIGlkZW50aWZpY2F0aW9uIG9mIGxvdy1wcm9iYWJpbGl0eSBldmVudHMuCgoqKlRoaXMgYW5hbHlzaXMgaGFzIHNldmVyYWwgbGltaXRhdGlvbnMuKiogVGhlIGRhdGFzZXQgZG9lcyBub3QgaW5jbHVkZSBjb250ZXh0dWFsIGZhY3RvcnMgc3VjaCBhcyB0aW1lIG9mIGRheSwgcHJveGltaXR5IHRvIGJhcnMsIG9yIGRheSBvZiB0aGUgd2Vlaywgd2hpY2ggY291bGQgcHJvdmlkZSBhZGRpdGlvbmFsIGV4cGxhbmF0b3J5IHBvd2VyLiBQZWFyc29uIGNvcnJlbGF0aW9uIHdhcyB1c2VkIHRvIGFzc2VzcyBtdWx0aWNvbGxpbmVhcml0eSwgYnV0IGl0IGlzIG5vdCBpZGVhbCBmb3IgYmluYXJ5IHZhcmlhYmxlcyBhbmQgbWF5IG92ZXJsb29rIG1vcmUgY29tcGxleCBpbnRlcmFjdGlvbnMuIEFsdGhvdWdoIG11bHRpY29sbGluZWFyaXR5IHdhcyBub3QgYSBjb25jZXJuLCB0aGUgbW9kZWwncyBBVUMgb2YgMC42NCBpbmRpY2F0ZXMgbGltaXRlZCBwcmVkaWN0aXZlIGFiaWxpdHnigJRhZGVxdWF0ZSBmb3IgaWRlbnRpZnlpbmcgZ2VuZXJhbCBhc3NvY2lhdGlvbnMgYnV0IGluc3VmZmljaWVudCBmb3IgaGlnaC1zdGFrZXMgcHJlZGljdGlvbi4gTGFzdGx5LCB1bmRlcnJlcG9ydGluZyBvZiBhbGNvaG9sIHVzZSBvciBtaXNjbGFzc2lmaWNhdGlvbiBpbiBjcmFzaCByZWNvcmRzIGNvdWxkIGFmZmVjdCB0aGUgcmVsaWFiaWxpdHkgb2YgdGhlIG91dGNvbWUgdmFyaWFibGUuCg==