Version 2.0 | First Created Nov 4, 2024 | Updated Nov 11, 2024

Keywords: t-test, chi-square, multiple logistic regression, ROC, sensitivity, specificity, odds ratio

GitHub Repository: CPLN671-Logit-Regression

Introduction

Alcohol-impaired driving is a significant public safety issue in the United States, with nearly 30 fatalities each day attributed to it, along with countless injuries and an annual economic burden exceeding $59 billion. Understand the back reason of drunk driving, and what factors can be associated with drunk driving is essential to tackling this problem and ease the safety issue. Here we are using Philadelphia as our study area.

In this analysis, we aim to identify predictors associated with drunk driving. Here, our dependent variable is whether or not the driver was drunk, and we use several independent variables to predict this outcome. These predictors include factors such as whether the crash resulted in a fatality or major injury, involved an overturned vehicle, or involved a driver using a cell phone. Additional behavioral factors like speeding, aggressive driving, and the presence of an immature driver (defined as at least one driver aged 16 or 17) or a senior driver (defined as at least one driver aged 65 or older) are also included. Furthermore, socio-economic indicators from the crash location, such as the percentage of individuals with at least a bachelor’s degree and the median household income within the census block group, are considered. By analyzing these variables, we aim to better understand the factors that correlate with drunk driving incidents.

Some of the predictors in this analysis include crashes involving fatalities or major injuries, overturned vehicles, cell phone use, speeding, and aggressive driving. These factors may be associated with drunk driving because they reflect behaviors and outcomes often connected to the impaired judgment and slowed reaction times that result from alcohol consumption. For instance, alcohol impairment increases the likelihood of severe crashes resulting in fatalities or major injuries, as impaired drivers are less able to respond to sudden changes on the road. Overturned vehicles are also more common in drunk-driving incidents, as alcohol can lead to a loss of vehicle control. Additionally, cell phone use, which is already a risky behavior, becomes even more dangerous when combined with alcohol impairment, as drunk drivers may be more prone to engage in distractions. Speeding is another common factor, as alcohol reduces inhibitions, leading drivers to ignore speed limits and traffic laws. Aggressive driving is also heightened by alcohol, which can increase aggression and lead to risky behaviors like tailgating or cutting off other vehicles. Altogether, these predictors capture patterns of behavior that are more likely when alcohol impairs a driver’s mental and physical abilities, leading to a greater likelihood of severe accidents.

These predictors, \(\text{DRIVER1617}\) (crash involving a driver aged 16 or 17) and \(\text{DRIVER65PLUS}\) (crash involving a driver aged 65 or older), might be associated with drunk driving due to age-related factors in behavior and ability. Younger drivers, especially those aged 16 or 17, may be more prone to risky behaviors, including experimenting with alcohol, due to lower experience levels and a tendency toward risk-taking. This age group may lack the experience and judgment to handle alcohol’s effects, making them more susceptible to involvement in drunk-driving crashes. On the other hand, older drivers, represented by DRIVER65PLUS, may also be affected by alcohol impairment differently. While they may not engage in risky behavior as frequently, alcohol can significantly impair their reaction times and decision-making abilities, which may already be slower due to age. This age group might also be more vulnerable to the effects of even small amounts of alcohol, leading to a higher risk of accidents when impaired. Together, these predictors help capture how different age groups may be uniquely vulnerable to the risks associated with drunk driving.

The predictors \(\text{PCTBACHMOR}\) (the percentage of individuals aged 25 or older with at least a bachelor’s degree) and \(\text{MEDHHINC}\) (median household income) might be associated with drunk driving as they reflect socio-economic characteristics of the area where crashes occur. Areas with higher education levels, indicated by a greater percentage of individuals with bachelor’s degrees, may have lower instances of drunk driving due to increased awareness of the risks associated with impaired driving and potentially stronger adherence to safety practices. Conversely, areas with lower education levels might see higher rates of alcohol-related incidents due to various socio-economic stressors or a lack of access to alternative transportation options. Similarly, median household income can play a role in influencing drunk driving patterns. Lower-income areas may experience higher rates of alcohol-impaired driving if public transportation options are limited, making driving the primary mode of transport regardless of impairment. On the other hand, higher-income areas might have better access to ridesharing services or designated driver options, potentially reducing the likelihood of drunk driving. By examining these socio-economic indicators, we can gain insight into how community characteristics might influence the prevalence of drunk driving incidents.

To conduct this analysis, we will use logistic regression in R to evaluate the relationship between these predictors and the likelihood of drunk driving.

Methods

Issues with OLS

Using Ordinary Least Squares (OLS) regression for a binary dependent variable poses several issues. First, recall below the equation of OLS regression:

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

Here, \(\beta_1\) is interpreted as the amount by which the dependent variable \(y\) changes for a one-unit change in the independent variable \(x_1\), 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 if we use OLS regression for binary dependent variables.

Second, OLS regression assumes a linear relationship between the independent variables and the dependent variable. With a binary dependent variable, this assumption does not hold, as binary outcomes (0 or 1) are inherently nonlinear. Third, OLS assumes normally distributed residuals (errors), but with a binary outcome, the residuals are not normally distributed. Instead, they follow a binomial distribution. This makes OLS estimation inefficient, as it cannot account for the specific distribution of binary outcomes. On top of these, with binary data, the variance of the error term is not constant; it varies with the predicted probability, leading to heteroscedasticity. This affects the reliability of standard errors and confidence intervals in OLS regression, leading to potentially incorrect inferences. The assumpstions that apply to logistic regression will be elaborated below.

Logistic Regression Concepts

Logistic regression provides a way for us to get around the above-mentioned issues. Instead of predicting the \(y\) value, we predict the probability of \(y\) being 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. Mathematically, odds are calculated as:

\[ \text{Odds} = \frac{\text{Probability of Event Happening}}{\text{Probability of Event Not Happening}} = \frac{p}{1 - p} \] For example, if there is a 70% chance of an event happening (probability \(p = 0.7\)), the odds would be:

\[ \text{Odds} = \frac{0.7}{1 - 0.7} = \frac{0.7}{0.3} = 2.33 \]

This means the event is 2.33 times more likely to happen than not happen. In logistic regression, instead of predicting the probability directly, we predict the log-odds (also called the logit) of the outcome. The logit model with multiple predictors is given by:

\[ \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 that drinking was involved in a crash. \(\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, representing the log-odds of drinking being involved when all predictors are zero. \(\beta_1, \beta_2, \dots, \beta_9\) are the coefficients for each predictor variable, indicating the change in log-odds for a one-unit increase in each predictor.

The predictor variable in the model is defined as follows:

  • FATAL_OR_M: Indicator for whether the crash involved a fatality.

  • OVERTURNED: Indicator for whether the crash involved an overturned vehicle.

  • CELL_PHONE: Indicator for whether a cell phone was in use.

  • SPEEDING: Indicator for whether speeding was a factor in the crash.

  • AGGRESSIVE: Indicator for whether aggressive driving was involved.

  • DRIVER1617: Indicator for whether the driver was between 16-17 years old.

  • DRIVER65PLUS: Indicator for whether the driver was 65 years or older.

  • PCTBACHMOR: Percentage of people in the area with a bachelor’s degree or more.

  • MEDHHINC: Median household income in the area.

The Logistic Function: The logistic function is the inverse of the logit function. It takes the linear predictor (log-odds) and converts it back to a probability, ensuring that the output is within the range \([0, 1]\). This transformation is ideal for modeling binary outcomes because it naturally maps any linear predictor onto a probability scale. The logistic function is given by:

\[ P(\text{DRINKING_D} = 1) = \frac{1}{1 + e^{-(\beta_0 + \beta_1 \cdot \text{FATAL_OR_M} + \dots + \beta_9 \cdot \text{MEDHHINC})}} \]

The logistic function is the type of translator function we are looking for. It has an S-shaped (sigmoid) curve with the following properties:

  • Bounded Output: As the linear predictor approaches \(+\infty\), the probability \(P(\text{DRINKING\_D} = 1)\) approaches 1. As the predictor approaches \(-\infty\), the probability approaches 0, ensuring the output is within the valid probability range \([0, 1]\).

  • Symmetry: The logistic function is symmetric around 0.5, meaning that when the linear predictor is 0 (i.e., \(\beta_0 + \beta_1 \cdot \text{FATAL_OR_M} + \dots + \beta_9 \cdot \text{MEDHHINC} = 0\)), the probability is 0.5. This midpoint is useful in binary classification as it helps interpret probabilities around 50%.

Overall, it works well for binary models because it restricts predicted probabilities to a range of 0 and 1, which is required in binary classification tasks.Each coefficient \(\beta_i\) represents the effect of a predictor on the log-odds of the outcome, which can be transformed to interpret effects on probabilities.

Logistic Regression Hypothesis

For each predictor in our logistic regression model, we want to test whether the predictor has a statistically significant effect on the likelihood of the outcome.

The Null Hypothesis (\(H_0\)), which states that the predictor has no effect on the outcome, can be written as:

\[ H_0 : \beta_i = 0 \]

The Alternative Hypothesis (\(H_a\)) which states that the predictor has significant effect on the outcome, can be written as:

\[ H_a : \beta_i \neq 0 \]

To test these hypotheses, we use the Wald statistic for each coefficient \(\beta_i\). The Wald statistic is calculated as:

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

where \(\hat{\beta}_i\) is the estimated coefficient for predictor, and \(\sigma(\hat{\beta}_i)\) is the standard error of this estimate. Under the null hypothesis, the Wald statistic approximately follows a standard normal distribution \(N(0, 1)\). Large values of \(|W_i|\) indicate that \(\beta_i\) is significantly different from zero, leading us to reject the null hypothesis.

However, rather than looking at the estimated \(\beta\) coefficients, most statisticians still prefer to look at odds ratios. The odds ratio is calculated by exponentiating the coefficients. For example, if the odds ratio for a predictor is 1.5, it means that the odds of the outcome happening are 1.5 times higher for a one-unit increase in the predictor. An odds ratio greater than 1 indicates that the predictor is associated with an increased likelihood of the outcome, while an odds ratio less than 1 indicates a decreased likelihood.

Logistic Regression Model Assessment

In logistic regression, there are several ways to assess the quality of the model fit. While \(R^2\) is commonly used in OLS to measure the proportion of variance explained by the model, it is not directly applicable to logistic regression. Although a pseudo-\(R^2\) statistic can be calculated for logistic regression (e.g., McFadden’s \(R^2\)), it does not have the same interpretation as in OLS regression and is not as widely used for model assessment.

A better alternative for comparing models is the Akaike Information Criterion (AIC). The AIC is a measure that penalizes models for complexity (i.e., the number of predictors) and rewards goodness of fit. It is defined as:

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

where \(k\) is the number of parameters in the model, and \(\hat{L}\) is the maximum likelihood of the model. Lower AIC values indicate a better fit, as they balance the trade-off between model complexity and goodness of fit.

An even better way to assess the quality of the model is to compute the specificity, sensitivity and the misclassification rate, and then the AUC value. To do that, we first need to calculate the predicted values of \(y\). The predicted values \(\hat{y}\) are calculated as:

\[ \text{P(y=1)} = \hat{y} = \frac{1}{1 + \exp(-\hat{\beta}_0 - \hat{\beta}_1x_1 - \dots - \hat{\beta}_kx_k)} \] where \(\hat{y}\) represents the predicted probability of the outcome being \(y = 1\).

After obtaining the predicted probabilities, we apply a threshold (cut-off) to classify predictions into binary outcomes (e.g. classify \(\hat{y} > 0.5\) as \(y = 1\), and \(\hat{y} \leq 0.5\) as \(y = 0\)). It is important to note that the choice of cut-off value (i.e., threshold for classifying \(y = 1\)) impacts the specificity, sensitivity, and misclassification rate. The default threshold of 0.5 may not always be optimal. Using different cut-offs allows for a trade-off between sensitivity and specificity. For example, a lower cut-off might increase sensitivity at the expense of specificity, and vice versa.

Then, we could calculate the sensitivity and specificity of the model. Sensitivity is the proportion of true positives (actual positives correctly predicted as positives), while specificity is the proportion of true negatives (actual negatives correctly predicted as negatives). The misclassification rate is the proportion of incorrect predictions made by the model. They are calculated as:

\[ \text{Sensitivity} = \frac{TP}{TP + FN} \] where \(TP\) is the number of true positives and \(FN\) is the number of false negatives. Higher sensitivity values are better, as they indicate that the model is good at identifying the positive class.

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

where \(TN\) is the number of true negatives and \(FP\) is the number of false positives. Higher specificity values are better, as they indicate that the model is good at identifying the negative class.

\[ \text{Misclassification Rate} = \frac{FP + FN}{TP + TN + FP + FN} \]

Lower misclassification rates are better, as they indicate fewer errors in classification.

Different cutoff can lead to different sensitivity, specificity and misclassification rates.To determine the optimal cut-off for classification, we can calculate the Youden’s Index, which is defined as:

\[ J = \text{Sensitivity} + \text{Specificity} - 1 \] Alternatively, we can use the ROC curve to visualize the trade-off between sensitivity and specificity at different cut-off values, and find a cut-off for which the ROC curve has the minimum distance from the upper left corner of the graph (the point at which sensitivity and specificity are both 1). We implement this

To provide more cotext, the ROC curve is then a graphical representation of a classifier’s performance, plotting sensitivity (true positive rate) on the y-axis against 1 - specificity (false positive rate) on the x-axis for different threshold values. The ROC curve helps visualize the trade-off between sensitivity and specificity at various cut-offs.

Based on the ROC curve, we can calculate the Area Under the Curve (AUC) to quantify the model’s performance. Area under ROC Curve is a measure of prediction accuracy of the model (how well a model predicts 1 responses as 1’s and 0 responses as 0’s). The AUC ranges from 0 to 1, with higher values indicating better model performance. An AUC of 0.5 suggests that the model is no better than random guessing, while an AUC of 1 indicates perfect classification. Higher AUCs mean that we can find a cut-off value for which both sensitivity and specificity of the model are relatively high. Typically:

  • \(\text{AUC} = 1\): Perfect model
  • \(\text{AUC} = 0.9\): Excellent model
  • \(\text{AUC} = 0.8\): Good model
  • \(\text{AUC} = 0.7\): Fair model
  • \(\text{AUC} = 0.5\): Poor model (random classifier)
  • \(\text{AUC} < 0.5\): Failing model (worse than random)

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. Below, we outline which assumptions of OLS regression also hold for logistic regression and which do not.

First, just like in OLS regression, logistic regression assumes that observations are independent of each other. This means that each data point (or case) should not influence another.

Second, similar to OLS regression, logistic regression assumes that there is no perfect multicollinearity among the independent variables. Perfect multicollinearity means that one predictor is an exact linear combination of others, which can lead to instability in the model coefficients.

Third, OLS regression assumes homoscedasticity, meaning the residuals (errors) have constant variance across all levels of the independent variables. In logistic regression, this assumption does not apply because the error terms are not normally distributed; instead, they follow a binomial distribution.

Fourth, 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 for the response variable.

And lastly, logistic regression does not assume a linear relationship between the dependent variable and each independent variable, unlike OLS regression. Instead, dependent variable must be binary. Logistic regression assumes that the log odds of the dependent variable being 1 is linearly related to each independent variable. This is a unique assumption of logistic regression that does not apply to OLS regression.

As a special note, logistic regression requires a sample size of at least 50. This is because logistic regression uses Maximum Likelihood Estimation (MLE) to estimate regression coefficients, which requires a larger sample size than OLS regression.

Exploratory Analysis Ideas

Before running logistic regression, we also need to conduct exploratory analyses to understand the relationships between the dependent variable and the predictors.

For binary predictors, we run cross-tabulations with the dependent variable, which in this case is \(\text{DRINKING_D}\). This provides us with counts for each combination of values for \(\text{DRINKING_D}\) and a binary predictor, allowing us to observe potential associations. The Chi-Square test is the appropriate statistical test for assessing associations between two categorical variables. The null hypothesis \(H_0\) for the Chi-Square test is that:

\[ H_0: \text{There is no association between the binary predictor and DRINKING_D.} \]

The alternative hypothesis is that:

\[ H_a: \text{There is an association between the binary predictor and DRINKING\_D.} \]

For continuous predictors, we calculate the means of the continuous predictors for both values of the dependent variable. We compare the mean values of \(\text{PCTBACHMOR}\) and \(\text{MEDHHINC}\) for crashes involving alcohol versus those that didn’t. The independent samples t-test is used to test whether there is a significant difference in mean values of a continuous predictor between two groups of a binary outcome. The null hypothesis \(H_0\) for the t-test is that:

\[ H_0: \text{There is no difference in the means of the continuous predictor for crashes that involved alcohol and those that did not.} \]

The alternative hypothesis is that:

\[ H_a: \text{There is a significant difference in the means of the continuous predictor for crashes that involved alcohol and those that did not.} \]

Results

Exploratory Analysis

We begin our analysis by examining the distribution of the dependent variable, \(\text{DRINKING_D}\). The tabulation shows that the majority of crashes do not involve alcohol impairment. The tabulation of the dependent variable, \(\text{DRINKING_D}\), shows that the majority of crashes do not involve alcohol impairment. Specifically, 94.3% of crashes (proportion = 0.943) are categorized as not involving drunk driving, while only 5.7% of crashes (proportion = 0.057) involve a drunk driver. This indicates that alcohol-related crashes constitute a relatively small proportion of the overall crash data. The skewed distribution of the dependent variable suggests that drunk driving incidents are relatively rare compared to non-alcohol-related crashes, which is an important consideration for model performance and evaluation, as it may impact the model’s ability to accurately predict alcohol involvement.

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

The table below provides a cross-tabulation of the dependent variable with each of the binary predictors. It shows that among crashes without alcohol involvement, 2.89% resulted in fatality or major injury. Yet, the percentage is higher at 7.57% when alcohol is involved. While 1.50% of non-alcohol-related crashes involved an overturned vehicle, 4.43% of alcohol-related crashes did. Speeding is involved in 3.08% of non-alcohol-related crashes and 10.46% of alcohol-related crashes. Similarly, aggressive driving is more common in alcohol-related crashes (36.86%) than in non-alcohol-related crashes (45.31%). As for driving age, 1.65% of non-alcohol-related crashes involve very young drivers, while this drops to 0.48% in alcohol-related crashes. 10.37% of non-alcohol-related crashes involve older drivers, compared to 4.79% of alcohol-related crashes. However, cell phone use is similar across both alcohol-involved and non-alcohol-involved crashes.

extract_crosstab_values <- function(var1, var2) {

  crosstab <- CrossTable(var1, var2, prop.r = FALSE, prop.chisq = FALSE, chisq = FALSE, prop.t = FALSE)
  
  value_1 <- crosstab$t["1", "1"]                                   # Count where DRINKING_D = 1, other variable = 1
  value_2 <- (crosstab$t["1", "1"] / sum(crosstab$t["1",])) * 100   # Pct where DRINKING_D = 1, other variable = 1
  value_3 <- crosstab$t["0", "1"]                                   # Count where DRINKING_D = 0, other variable = 1
  value_4 <- (crosstab$t["0", "1"] / sum(crosstab$t["0",])) * 100   # Pct where DRINKING_D = 0, other variable = 1
  value_5 <- crosstab$t["1", "1"] + crosstab$t["0", "1"]            # Total count where other variable = 1

  return(c(Value1 = value_1, Value2 = value_2, Value3 = value_3, Value4 = value_4, Value5 = value_5))
}

tabulation <- data.frame(
  Variable = character(),
  Value1 = numeric(),
  Value2 = numeric(),
  Value3 = numeric(),
  Value4 = numeric(),
  Value5 = numeric()
)

descriptions <- c(
  FATAL_OR_M = "Crash resulted in fatality or major injury",
  OVERTURNED = "Crash involved an overturned vehicle",
  CELL_PHONE = "Driver was using cell phone",
  SPEEDING = "Crash involved speeding car",
  AGGRESSIVE = "Crash involved aggressive driving",
  DRIVER1617 = "Crash involved at least one driver 16 or 17 years old",
  DRIVER65PLUS = "Crash involved at least one driver over 65 years old"
)

variables <- c("FATAL_OR_M", "OVERTURNED", "CELL_PHONE", "SPEEDING", "AGGRESSIVE", "DRIVER1617", "DRIVER65PLUS")

for (var in variables) {
  values <- extract_crosstab_values(crashes$DRINKING_D, crashes[[var]])
  
  tabulation <- rbind(
    tabulation,
    data.frame(Variable = paste0(var, ": ", descriptions[[var]]), t(values))
  )
}

colnames(tabulation) <- c("", "N", "%", "N ", "% ", "N  ")
tabulation %>%
  kable("html", escape = FALSE, align = "lccccc") %>%
  kable_styling(full_width = FALSE, position = "center", fixed_thead = TRUE) %>%
  column_spec(1, width = "30em") %>%    
  column_spec(2, width = "5em") %>%
  column_spec(3, width = "5em") %>%
  column_spec(4, width = "5em") %>%
  column_spec(5, width = "5em") %>%
  column_spec(6, width = "5em") %>%
  add_header_above(c(" " = 1, "DRINKING_D = 1" = 2, "DRINKING_D = 0" = 2, " " = 1)) %>% 
  add_header_above(c(" " = 1, "Alcohol Involved" = 2, "No Alcohol" = 2, "Total" = 1))
Alcohol Involved
No Alcohol
Total
DRINKING_D = 1
DRINKING_D = 0
N % N % N
FATAL_OR_M: Crash resulted in fatality or major injury 188 7.565 1181 2.89 1369
OVERTURNED: Crash involved an overturned vehicle 110 4.427 612 1.50 722
CELL_PHONE: Driver was using cell phone 28 1.127 426 1.04 454
SPEEDING: Crash involved speeding car 260 10.463 1261 3.08 1521
AGGRESSIVE: Crash involved aggressive driving 916 36.861 18522 45.31 19438
DRIVER1617: Crash involved at least one driver 16 or 17 years old 12 0.483 674 1.65 686
DRIVER65PLUS: Crash involved at least one driver over 65 years old 119 4.789 4237 10.37 4356

The results of the Chi-Square test indicate significant associations between most of the binary predictors and alcohol involvement in crashes, with the exception of \(\text{CELL_PHONE}\). For example, \(\text{FATAL_OR_M}\) showed a highly significant association, with a Chi-Square statistic of 167.56 and a highly significant \(p < 0.0001\), suggesting that severe crashes are more likely to involve alcohol. Likewise, \(\text{OVERTURNED}\) also had a significant association (Chi-Square = 122.79, df =1) with \(p < 0.0001\), indicating that overturned vehicles are more frequently associated with alcohol impairment. The remaining predictors, \(\text{SPEEDING}\), \(\text{AGGRESSIVE}\), \(\text{DRIVER1617}\), and \(\text{DRIVER65PLUS}\) also showed significant associations with alcohol involvement, with Chi-Square statistics ranging from 20.45 to 376.78 and \(p < 0.0001\). These results suggest that crashes involving fatalities, overturned vehicles, speeding, aggressive driving, and certain driver age groups are more likely to involve alcohol impairment. Therefore, we could reject the null hypothesis for these predictors and conclude that they are significantly associated with alcohol involvement in crashes.

However, the predictor \(\text{CELL_PHONE}\) did not show a significant association with alcohol involvement, with a Chi-Square statistic of 0.16 and \(p > 0.5\). This suggests that cell phone use is not strongly associated with alcohol-related crashes in this dataset. We can retain the null hypothesis for this predictor and conclude that there is no significant association between cell phone use and alcohol involvement in crashes.

tabulation$Chi_squared <- NA  
tabulation$p_value <- NA

for (i in seq_along(variables)) {
  var <- variables[i]
  chi_test <- chisq.test(table(crashes$DRINKING_D, crashes[[var]]), correct = FALSE)
  tabulation$Chi_squared[i] <- round(chi_test$statistic, 2)
  tabulation$p_value[i] <- round(chi_test$p.value, 5)
}

tabulation %>%
  kable("html", escape = FALSE, align = "lcccccc") %>%
  kable_styling(full_width = FALSE, position = "center", fixed_thead = TRUE) %>%
  column_spec(1, width = "50em") %>%
  column_spec(2, width = "5em") %>%
  column_spec(3, width = "5em") %>%
  column_spec(4, width = "5em") %>%
  column_spec(5, width = "5em") %>%
  column_spec(6, width = "5em") %>%
  column_spec(7, width = "5em") %>%
  column_spec(8, width = "5em") %>%
  add_header_above(c(" " = 1, "DRINKING_D = 0" = 2, "DRINKING_D = 1" = 2, " " = 1, " " = 2)) %>% 
  add_header_above(c(" " = 1, "No Alcohol" = 2, "Alcohol Involved" = 2, "Total" = 1, "χ2 Test" = 2))
No Alcohol
Alcohol Involved
Total
χ2 Test
DRINKING_D = 0
DRINKING_D = 1
N % N % N Chi_squared p_value
FATAL_OR_M: Crash resulted in fatality or major injury 188 7.565 1181 2.89 1369 167.56 0.000
OVERTURNED: Crash involved an overturned vehicle 110 4.427 612 1.50 722 122.79 0.000
CELL_PHONE: Driver was using cell phone 28 1.127 426 1.04 454 0.16 0.687
SPEEDING: Crash involved speeding car 260 10.463 1261 3.08 1521 376.78 0.000
AGGRESSIVE: Crash involved aggressive driving 916 36.861 18522 45.31 19438 67.60 0.000
DRIVER1617: Crash involved at least one driver 16 or 17 years old 12 0.483 674 1.65 686 20.45 0.000
DRIVER65PLUS: Crash involved at least one driver over 65 years old 119 4.789 4237 10.37 4356 80.60 0.000

We also looked at the mean and standard deviation of the continuous predictors, \(\text{PCTBACHMOR}\) and \(\text{MEDHHINC}\), for crashes involving and not involving alcohol. The mean percentage of people with a bachelor’s degree or more is identical for both non-alcohol and alcohol-involved crashes, at 16.6%. The standard deviation is slightly higher in the alcohol-involved group (18.7 vs. 18.2). This suggests that educational attainment, as measured by the percentage of individuals with a bachelor’s degree or more, does not vary significantly between areas where crashes involve alcohol and those where they do not.The median household income is slightly higher in alcohol-involved crashes with a mean of $31,998.8, compared to $31,483.1 in non-alcohol-related crashes. The standard deviation is also higher for the alcohol-involved group (17,810.5 vs. 16,930.1). This also means that income level may not be a strong differentiator for alcohol involvement in crashes.

mean_pctbachmor <- tapply(crashes$PCTBACHMOR, crashes$DRINKING_D, mean)
sd_pctbachmor <- tapply(crashes$PCTBACHMOR, crashes$DRINKING_D, sd)
mean_medhhinc <- tapply(crashes$MEDHHINC, crashes$DRINKING_D, mean)
sd_medhhinc <- tapply(crashes$MEDHHINC, crashes$DRINKING_D, sd)

tabulation_cont <- data.frame(
  Variable = c("PCTBACHMOR: % with bachelor’s degree or more", "MEDHHINC: Median household income"),
  Value1 = c(mean_pctbachmor["0"], mean_medhhinc["0"]),  # Mean for DRINKING_D = 0
  Value2 = c(sd_pctbachmor["0"], sd_medhhinc["0"]),       # SD for DRINKING_D = 0
  Value3 = c(mean_pctbachmor["1"], mean_medhhinc["1"]),  # Mean for DRINKING_D = 1
  Value4 = c(sd_pctbachmor["1"], sd_medhhinc["1"])        # SD for DRINKING_D = 1
)

colnames(tabulation_cont) <- c("", "Mean", "SD", "Mean ", "SD ")

tabulation_cont %>%
  kable("html", escape = FALSE, align = "lcccccc") %>%
  kable_styling(full_width = FALSE, position = "center", fixed_thead = TRUE) %>%
  add_header_above(c(" " = 1, "DRINKING_D = 0" = 2, "DRINKING_D = 1" = 2)) %>% 
  add_header_above(c(" " = 1, "No Alcohol" = 2, "Alcohol Involved" = 2))
No Alcohol
Alcohol Involved
DRINKING_D = 0
DRINKING_D = 1
Mean SD Mean SD
PCTBACHMOR: % with bachelor’s degree or more 16.6 18.2 16.6 18.7
MEDHHINC: Median household income 31483.1 16930.1 31998.8 17810.5

The independent samples t-test results for the continuous predictors provide more insight into whether these socio-economic factors are significantly associated with alcohol involvement in crashes.

For \(\text{PCTBACHMOR}\), the t-test yields a p-value of 0.914, which is far greater than the conventional significance level of 0.05. This indicates that there is no statistically significant difference in the mean educational attainment between crashes involving alcohol and those that do not. Therefore, we fail to reject the null hypothesis, suggesting that educational attainment does not have a significant association with alcohol involvement in crashes.

Similarly, for \(\text{MEDHHINC}\), the t-test produces a p-value of 0.160, which also exceeds the 0.05 threshold. Although there is a small difference in mean income between the two groups, this difference is not statistically significant. Consequently, we again fail to reject the null hypothesis, implying that median household income is not significantly associated with alcohol involvement in crashes.

As such, the t-test results demonstrate that neither \(\text{PCTBACHMOR}\) nor \(\text{MEDHHINC}\) shows a significant association with alcohol involvement in crashes. Thus, we cannot conclude that socio-economic factors, as measured by educational attainment and income levels, have a meaningful impact on the likelihood of alcohol involvement in traffic incidents. This lack of significance suggests that other variables, such as driver behavior or crash-specific characteristics, may be more relevant in understanding alcohol-related crashes.

pval_pctbachmor <- t.test(crashes$PCTBACHMOR ~ crashes$DRINKING_D)$p.value
pval_medhhinc <- t.test(crashes$MEDHHINC ~ crashes$DRINKING_D)$p.value
tabulation_cont$`t-test p-value` <- c(pval_pctbachmor, pval_medhhinc)  

tabulation_cont %>%
  kable("html", escape = FALSE, align = "lcccccc") %>%
  kable_styling(full_width = FALSE, position = "center", fixed_thead = TRUE) %>%
  add_header_above(c(" " = 1, "DRINKING_D = 0" = 2, "DRINKING_D = 1" = 2, " " =  1)) %>% 
  add_header_above(c(" " = 1, "No Alcohol" = 2, "Alcohol Involved" = 2, " " = 1))
No Alcohol
Alcohol Involved
DRINKING_D = 0
DRINKING_D = 1
Mean SD Mean SD t-test p-value
PCTBACHMOR: % with bachelor’s degree or more 16.6 18.2 16.6 18.7 0.914
MEDHHINC: Median household income 31483.1 16930.1 31998.8 17810.5 0.160

Regression Assumptions

Based on the correlation matrix and prior information, most logistic regression assumptions for analyzing drunk driving crashes are met. The binary outcome variable, \(\text{DRINKING_D}\), fulfills the requirement for a binary dependent variable, and the independence of observations is largely satisfied, as each crash is considered a separate event. The assumption of no perfect multicollinearity is also met, as the correlation matrix shows low pairwise correlations between predictor variables, with the highest being 0.48 between % with Bachelor’s Degree and Median Household Income, and a mild correlation (0.21) between Crash Involved Speeding Car and Crash Involved Aggressive Driving. These correlations are not high enough to cause instability in the model. Additionally, the large sample size of over 43,000 observations ensures stable estimates, meeting 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-tests suggest weak or non-linear relationships between % with Bachelor’s Degree and Median Household Income and the outcome variable.

Using Pearson correlations to measure associations between binary predictors can have limitations, as Pearson’s correlation coefficient is most appropriate for continuous, normally distributed data. Binary variables, which only take on two values (e.g., 0 and 1), can lead to less meaningful or interpretable correlation values, as the measure does not fully capture the potential association between two binary variables. Additionally, Pearson correlations may underestimate or fail to reflect non-linear relationships that could exist among binary predictors.

In terms of multicollinearity, which we define as the presence of high correlation between two or more predictor variables that could lead to instability in the model’s coefficient estimates, there is no evidence of multicollinearity in this dataset. The correlation matrix shows low pairwise correlations between the predictors, with the highest correlation being 0.48 between % with Bachelor’s Degree and Median Household Income. This value falls below commonly accepted thresholds for multicollinearity (typically 0.7 or higher), suggesting that the model is unlikely to suffer from instability due to collinear predictors. Therefore, while the Pearson correlation may not be the most precise measure for binary predictors, it does not indicate any problematic levels of multicollinearity in this analysis.

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("#283d3b", "white", "#c44536")) +
  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))

Regression Analysis

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

FATAL_OR_M: The presence of a fatality or major injury significantly increases the odds of a drinking-related crash, with an odds ratio of 2.257 (95% CI: 1.910 to 2.653) and a highly significant \(p < 0.0001\), suggesting that these types of incidents more than double the odds of it there being a drunk driver.

OVERTURNED: Overturned vehicles significantly increase the likelihood of it being a drinking-related crash, with an odds ratio of 2.532 (95% CI: 2.035 to 3.122) and a highly significant \(p < 0.0001\). This result implies that overturned vehicles are strongly associated with a drinking-driver incurred crashes.

CELL_PHONE: The use of a cellphone during a crash shows no statistically significant effect on the odds of a drinking-related crash (\(p = 0.881\)), with an odds ratio close to 1 (OR = 1.030, 95% CI: 0.684 to 1.488), indicating no significantly meaningful association.

SPEEDING: Speeding is a highly significant predictor, with an odds ratio of 4.660 (95% CI: 3.974 to 5.450), and \(p < 0.0001\), indicating that crashes involving speeding are more than four times as likely to involve alcohol.

AGGRESSIVE: Aggressive driving is associated with lower odds of a drinking-related crash, with an odds ratio of 0.551 (95% CI: 0.501 to 0.604), and \(p < 0.0001\), suggesting that aggressive driving incidents are less likely to involve alcohol.

DRIVER1617: Incidents involving drivers aged 16-17 are significantly less likely to be drinking-related (OR = 0.278, 95% CI: 0.148 to 0.471), with a significant \(p < 0.0001\), possibly reflecting the influence of drinking laws for younger drivers.

DRIVER65PLUS: Incidents involving drivers aged 65 and above also show significantly lower odds of being drinking-related, with an odds ratio of 0.461 (95% CI: 0.380 to 0.553), and \(p < 0.0001\), indicating that older drivers are less likely to be involved in alcohol-related crashes.

PCTBACHMOR: The percentage of people with a bachelor’s degree or higher in the area does not significantly impact the odds of a drinking-related crash (\(p = 0.775\)) that occur there, with an odds ratio near 1 (OR = 1.000, 95% CI: 0.997 to 1.002).

MEDHHINC: Median household income has a very slight, statistically significant positive effect on the likelihood of a drinking-related crash there, with \(p = 0.036\), but the effect size is negligible, as shown by the confidence interval limits around 1 (OR = 1.000).

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

summary(logit)
## 
## Call:
## glm(formula = DRINKING_D ~ FATAL_OR_M + OVERTURNED + CELL_PHONE + 
##     SPEEDING + AGGRESSIVE + DRIVER1617 + DRIVER65PLUS + PCTBACHMOR + 
##     MEDHHINC, family = binomial, data = crashes)
## 
## Coefficients:
##                 Estimate  Std. Error z value             Pr(>|z|)    
## (Intercept)  -2.73250662  0.04587566  -59.56 < 0.0000000000000002 ***
## FATAL_OR_M    0.81401380  0.08380692    9.71 < 0.0000000000000002 ***
## OVERTURNED    0.92892138  0.10916632    8.51 < 0.0000000000000002 ***
## CELL_PHONE    0.02955008  0.19777782    0.15                0.881    
## SPEEDING      1.53897567  0.08054589   19.11 < 0.0000000000000002 ***
## AGGRESSIVE   -0.59691595  0.04777924  -12.49 < 0.0000000000000002 ***
## DRIVER1617   -1.28029596  0.29314717   -4.37  0.00001257244712793 ***
## DRIVER65PLUS -0.77466464  0.09585832   -8.08  0.00000000000000064 ***
## PCTBACHMOR   -0.00037063  0.00129639   -0.29                0.775    
## MEDHHINC      0.00000280  0.00000134    2.09                0.036 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 19036  on 43363  degrees of freedom
## Residual deviance: 18340  on 43354  degrees of freedom
## AIC: 18360
## 
## Number of Fisher Scoring iterations: 6

As a quick summary, predictor that are highly significant \(p < 0.001\) are FATAL_OR_M, OVERTURNED, SPEEDING, AGGRESSIVE, DRIVER1617, and DRIVER65PLUS. Among which those that increase the odds of an incident that includes drunk driving are FATAL_OR_M, OVERTURNED, and SPEEDING. On the other hand, predictors that are not significant are CELL_PHONE and PCTBACHMOR. The predictor MEDHHINC is marginally significant (\(p = 0.036\)).

logitoutput <- summary(logit)
logitcoeff <- logitoutput$coefficients
or_ci <- exp(cbind(OR = coef(logit), confint(logit)))
logitcoeff[, "Pr(>|z|)"] <- round(logitcoeff[, "Pr(>|z|)"], 4)
final_output <- cbind(logitcoeff, or_ci)
final_output %>% 
  kable("html", escape = FALSE, align = "cccccc") %>%
  kable_styling(full_width = FALSE, position = "center", fixed_thead = TRUE)
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

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 lowest and highest misclassification rates highlight the effectiveness of each cut-off.

The probability cut-off of 0.50 yields the lowest misclassification rate of 0.057. At this threshold, specificity is maximized at 1.000, but sensitivity is very low (0.002), meaning that the model captures very few true positives, sacrificing sensitivity for high specificity.

The highest misclassification rate occurs at the cut-off of 0.02 with a rate of 0.889. At this threshold, sensitivity is high (0.984), capturing nearly all true positives, but specificity is very low (0.058), resulting in a high rate of false positives.

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,
  Specificity = NA,
  MisclassificationRate = NA
)

calculate_metrics <- function(cutoff, labels, predictions) {
  predicted_labels <- ifelse(predictions >= cutoff, 1, 0)
  
  tp <- sum(predicted_labels == 1 & labels == 1) # True positives
  tn <- sum(predicted_labels == 0 & labels == 0) # True negatives
  fp <- sum(predicted_labels == 1 & labels == 0) # False positives
  fn <- sum(predicted_labels == 0 & labels == 1) # False negatives
  
  # Sensitivity: True positive rate
  sensitivity <- tp / (tp + fn)
  
  # Specificity: True negative rate
  specificity <- tn / (tn + fp)
  
  # Misclassification rate
  misclassification_rate <- (fp + fn) / length(labels)
  
  return(c(sensitivity, specificity, misclassification_rate))
}

for (i in seq_along(cutoffs)) {
  metrics <- calculate_metrics(cutoffs[i], roc$labels, roc$predictions)
  results$Sensitivity[i] <- metrics[1]
  results$Specificity[i] <- metrics[2]
  results$MisclassificationRate[i] <- metrics[3]
}

results %>% 
  kable("html", escape = FALSE, align = "cccc") %>%
  kable_styling(full_width = FALSE, position = "center", fixed_thead = TRUE)
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

We plotted the ROC curve to show the tradeoff between sensitivity (True Positive Rate) and specificity (1 - False Positive Rate) across various probability cut-offs for the logistic regression model. An ideal model would reach the top-left corner of the ROC space (sensitivity = 1, specificity = 1), which would mean perfect discrimination between the two classes. Our ROC curve, however, lies beneath this 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)
  )

Using the function opt.cut, we calculated the optimal cut-off by minimizing the Euclidean distance from the ROC curve to the point (0, 1) — the top-left corner of the ROC space, which represents perfect sensitivity and specificity. This cut-off of 0.064 provides a balanced approach, achieving a sensitivity of 0.661 and specificity of 0.545.

In the above section, the optimal cut-off selected based on the minimum misclassification rate was 0.50, which yielded a misclassification rate of 0.057. This threshold focused on reducing the overall number of misclassified observations, prioritizing high specificity (1.000) but resulting in low sensitivity (0.002). In contrast, the cut-off of 0.064 identified through the ROC analysis aims to balance both sensitivity and specificity, achieving a moderate level for each metric rather than prioritizing one over the other. This cut-off might be more suitable for applications where both true positive and true negative rates are equally important.

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(full_width = FALSE, position = "center", fixed_thead = TRUE)
sensitivity specificity cutoff
0.661 0.545 0.064

The Area Under the ROC Curve (AUC) for our model is 0.640. An AUC of 0.640 suggests that the model has poor discrimination (generally, a model with an AUC between 0.6 and 0.7 is considered to have poor discrimination). Specifically, the AUC value means that if we randomly select one positive case and one negative case, the model has a 64% chance of correctly ranking the positive case higher in terms of predicted probability than the negative case. In practical terms, 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 regression model we ran includes only the binary predictors. In the first model, \(\text{PCTBACHMOR}\) and \(\text{MEDHHINC}\) were not statistically significant predictors of \(\text{DRINKING_D}\), as their \(p < 0.05\). However, in the reduced model, the exclusion of these two predictors did not lead to any new predictors becoming significant or any previously significant predictors becoming insignificant.

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

summary(logit2)
## 
## Call:
## glm(formula = DRINKING_D ~ FATAL_OR_M + OVERTURNED + CELL_PHONE + 
##     SPEEDING + AGGRESSIVE + DRIVER1617 + DRIVER65PLUS, family = binomial, 
##     data = crashes)
## 
## Coefficients:
##              Estimate Std. Error z value             Pr(>|z|)    
## (Intercept)   -2.6519     0.0275  -96.32 < 0.0000000000000002 ***
## FATAL_OR_M     0.8093     0.0838    9.66 < 0.0000000000000002 ***
## OVERTURNED     0.9398     0.1090    8.62 < 0.0000000000000002 ***
## CELL_PHONE     0.0311     0.1978    0.16                 0.88    
## SPEEDING       1.5403     0.0805   19.13 < 0.0000000000000002 ***
## AGGRESSIVE    -0.5936     0.0477  -12.43 < 0.0000000000000002 ***
## DRIVER1617    -1.2716     0.2931   -4.34   0.0000143637414327 ***
## DRIVER65PLUS  -0.7665     0.0958   -8.00   0.0000000000000012 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 19036  on 43363  degrees of freedom
## Residual deviance: 18344  on 43356  degrees of freedom
## AIC: 18360
## 
## Number of Fisher Scoring iterations: 6

The odds ratios (OR) for the binary predictors in both models are very similar, suggesting that removing \(\text{PCTBACHMOR}\) and \(\text{MEDHHINC}\) had little impact on the estimated effects of the other variables.

logitoutput2 <- summary(logit2)
logitcoeff2 <- logitoutput2$coefficients
or_ci2 <- exp(cbind(OR = coef(logit2), confint(logit2)))
logitcoeff2[, "Pr(>|z|)"] <- round(logitcoeff2[, "Pr(>|z|)"], 4)
final_output2 <- cbind(logitcoeff2, or_ci2)
final_output2 %>% 
  kable("html", escape = FALSE, align = "cccccc") %>%
  kable_styling(full_width = FALSE, position = "center", fixed_thead = TRUE)
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 . AIC is a measure of model quality that balances goodness of fit with model complexity (penalizing additional parameters). Since the AIC is the same in both models, neither model is superior in terms of fit. Given that the first model includes two additional predictors that are not statistically significant and does not improve the AIC, the reduced model (binary predictors only) is preferable for its simplicity.

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(full_width = FALSE, position = "center", fixed_thead = TRUE)
Degree of Freedom AIC
Model 1: All Predictors 10 18360
Model 2: Binary Predictors Only 8 18360

Discussion

In this study, a logistic regression analysis was conducted to examine factors associated with alcohol involvement in vehicular crashes in Philadelphia. The analysis included a variety of predictors, encompassing crash characteristics (such as whether the crash resulted in a fatality or major injury, involved an overturned vehicle, or involved cell phone use), driver behaviors (including speeding, aggressive driving, and the age of drivers involved), and socio-economic variables from the crash locations (such as the percentage of individuals with a bachelor’s degree or higher and median household income). The primary objective was to identify significant predictors of alcohol-related crashes and gain insight into the relationships between these factors and the likelihood of drunk driving incidents.

The results indicate that several crash characteristics and driver behaviors are significant predictors of alcohol involvement. Specifically, \(\text{FATAL_OR_M}\) (whether the crash resulted in a fatality or major injury), \(\text{OVERTURNED}\) (whether the crash involved an overturned vehicle), and ( ) are all positively and significantly associated with alcohol involvement. For instance, crashes involving speeding were found to be more than four times as likely to involve a drunk driver, highlighting the strong connection between risky driving behaviors and alcohol impairment. In contrast, ( ) (use of a cell phone during the crash) and \(\text{PCTBACHMOR}\) (percentage of individuals with a bachelor’s degree or higher) did not show a significant association with alcohol involvement, suggesting that these factors do not substantially influence the likelihood of a crash involving alcohol. \(\text{MEDHHINC}\) (median household income) demonstrated a marginally significant effect, but the impact was negligible, indicating that income levels do not play a meaningful role in alcohol-related crash risk.

The findings are somewhat surprising. While the significance of variables like \(\text{SPEEDING}\) and \(\text{FATAL_OR_M}\) matches our expectations, the lack of a significant association for \(\text{CELL_PHONE}\) use is unexpected. It was anticipated that cell phone use, an already high-risk behavior, would have an amplified effect when combined with alcohol impairment, but the data did not support this assumption. Similarly, the limited impact of socio-economic variables was unforeseen. Although it was hypothesized that areas with lower educational attainment or income levels might experience higher rates of alcohol-related crashes due to various socio-economic stressors, the analysis did not find meaningful associations. Nevertheless, the significant predictors, such as speeding and crash severity, align with expectations, reinforcing the understanding that alcohol impairment exacerbates the risk of severe and reckless driving behaviors.

The application of logistic regression is appropriate in this context, given its suitability for modeling a binary dependent variable. However, considering the rarity of the event of interest—only 5.7% of crashes involved alcohol—there may be limitations to this approach. Methods for modeling rare events, as proposed by Paul Allison, such as penalized likelihood approaches, could be more effective. These methods may yield more reliable and efficient estimates when dealing with infrequent outcomes, addressing potential biases and enhancing the model’s performance.

This analysis has several limitations. The relatively small proportion of alcohol-involved crashes may affect the robustness and stability of the model estimates. Employing rare event modeling techniques could improve the reliability of the findings. Additionally, unobserved confounding variables, such as time of day, road conditions, or proximity to alcohol-serving establishments, may influence crash outcomes but were not included in the model. The binary nature of many predictors may also oversimplify complex driving behaviors or socio-economic conditions, limiting the model’s ability to capture nuances. Finally, while socio-economic factors did not emerge as significant predictors, this does not rule out their potential importance in a broader context or when analyzed with more granular data. Future research could address these limitations by incorporating additional contextual variables, utilizing alternative modeling methods, and expanding the analysis to other geographic areas to validate and extend these findings.

LS0tCnRpdGxlOiAiUHJlZGljdGluZyBDYXIgQ3Jhc2hlcyBDYXVzZWQgYnkgQWxjb2hvbCBVc2luZyBMb2dpc3RpYyBSZWdyZXNzaW9uIgphdXRob3I6ICJFbWlseSBaaG91LCBaaXlpIEd1bywgRW1tYSBKaWFuZyIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRoZW1lOiBzaW1wbGV4CiAgICBtYXRoamF4OiBkZWZhdWx0CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgY29kZV9kb3dubG9hZDogeWVzCgplZGl0b3Jfb3B0aW9uczoKICBtYXJrZG93bjoKICAgIHdyYXA6IHNlbnRlbmNlCi0tLQoKVmVyc2lvbiAyLjAgfCBGaXJzdCBDcmVhdGVkIE5vdiA0LCAyMDI0IHwgVXBkYXRlZCBOb3YgMTEsIDIwMjQKCktleXdvcmRzOiB0LXRlc3QsIGNoaS1zcXVhcmUsIG11bHRpcGxlIGxvZ2lzdGljIHJlZ3Jlc3Npb24sIFJPQywgc2Vuc2l0aXZpdHksIHNwZWNpZmljaXR5LCBvZGRzIHJhdGlvCgpHaXRIdWIgUmVwb3NpdG9yeTogW0NQTE42NzEtTG9naXQtUmVncmVzc2lvbl0oaHR0cHM6Ly9naXRodWIuY29tL2VtaWx5emhvdTExMi9DUExONjcxLUxvZ2l0LVJlZ3Jlc3Npb24pCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCgpgYGB7ciBsb2FkIHBhY2thZ2VzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQoKb3B0aW9ucyhzY2lwZW49OTk5KQpvcHRpb25zKGRpZ2l0cyA9IDMpCgpwYWNrYWdlcyA8LSBjKCJ0aWR5dmVyc2UiLCAic2YiLCAiaGVyZSIsICJnZ3Bsb3QyIiwgImthYmxlRXh0cmEiLCAicGF0Y2h3b3JrIiwgImdtb2RlbHMiLCAiZ2djb3JycGxvdCIsICJST0NSIiwgInBsb3RST0MiKQoKcGFja2FnZS5jaGVjayA8LSBsYXBwbHkoCiAgcGFja2FnZXMsCiAgRlVOID0gZnVuY3Rpb24oeCkgewogICAgaWYgKCFyZXF1aXJlKHgsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkpIHsKICAgICAgaW5zdGFsbC5wYWNrYWdlcyh4LCBkZXBlbmRlbmNpZXMgPSBUUlVFLCBxdWlldGx5PVRSVUUpCiAgICAgIGxpYnJhcnkoeCwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKQogICAgfQogIH0KKQoKYGBgCgoKYGBge3IgbG9hZCBkYXRhLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQoKY3Jhc2hlcyA8LSByZWFkLmNzdihoZXJlKCJkYXRhIiwgIkxvZ2lzdGljUmVncmVzc2lvbkRhdGEuY3N2IikpCgpgYGAKCgojIEludHJvZHVjdGlvbgoKQWxjb2hvbC1pbXBhaXJlZCBkcml2aW5nIGlzIGEgc2lnbmlmaWNhbnQgcHVibGljIHNhZmV0eSBpc3N1ZSBpbiB0aGUgVW5pdGVkIFN0YXRlcywgd2l0aCBuZWFybHkgMzAgZmF0YWxpdGllcyBlYWNoIGRheSBhdHRyaWJ1dGVkIHRvIGl0LCBhbG9uZyB3aXRoIGNvdW50bGVzcyBpbmp1cmllcyBhbmQgYW4gYW5udWFsIGVjb25vbWljIGJ1cmRlbiBleGNlZWRpbmcgJDU5IGJpbGxpb24uIFVuZGVyc3RhbmQgdGhlIGJhY2sgcmVhc29uIG9mIGRydW5rIGRyaXZpbmcsIGFuZCB3aGF0IGZhY3RvcnMgY2FuIGJlIGFzc29jaWF0ZWQgd2l0aCBkcnVuayBkcml2aW5nIGlzIGVzc2VudGlhbCB0byB0YWNrbGluZyB0aGlzIHByb2JsZW0gYW5kIGVhc2UgdGhlIHNhZmV0eSBpc3N1ZS4gSGVyZSB3ZSBhcmUgdXNpbmcgUGhpbGFkZWxwaGlhIGFzIG91ciBzdHVkeSBhcmVhLgoKSW4gdGhpcyBhbmFseXNpcywgd2UgYWltIHRvIGlkZW50aWZ5IHByZWRpY3RvcnMgYXNzb2NpYXRlZCB3aXRoIGRydW5rIGRyaXZpbmcuIEhlcmUsIG91ciBkZXBlbmRlbnQgdmFyaWFibGUgaXMgd2hldGhlciBvciBub3QgdGhlIGRyaXZlciB3YXMgZHJ1bmssIGFuZCB3ZSB1c2Ugc2V2ZXJhbCBpbmRlcGVuZGVudCB2YXJpYWJsZXMgdG8gcHJlZGljdCB0aGlzIG91dGNvbWUuIFRoZXNlIHByZWRpY3RvcnMgaW5jbHVkZSBmYWN0b3JzIHN1Y2ggYXMgd2hldGhlciB0aGUgY3Jhc2ggcmVzdWx0ZWQgaW4gYSBmYXRhbGl0eSBvciBtYWpvciBpbmp1cnksIGludm9sdmVkIGFuIG92ZXJ0dXJuZWQgdmVoaWNsZSwgb3IgaW52b2x2ZWQgYSBkcml2ZXIgdXNpbmcgYSBjZWxsIHBob25lLiBBZGRpdGlvbmFsIGJlaGF2aW9yYWwgZmFjdG9ycyBsaWtlIHNwZWVkaW5nLCBhZ2dyZXNzaXZlIGRyaXZpbmcsIGFuZCB0aGUgcHJlc2VuY2Ugb2YgYW4gaW1tYXR1cmUgZHJpdmVyIChkZWZpbmVkIGFzIGF0IGxlYXN0IG9uZSBkcml2ZXIgYWdlZCAxNiBvciAxNykgb3IgYSBzZW5pb3IgZHJpdmVyIChkZWZpbmVkIGFzIGF0IGxlYXN0IG9uZSBkcml2ZXIgYWdlZCA2NSBvciBvbGRlcikgYXJlIGFsc28gaW5jbHVkZWQuIEZ1cnRoZXJtb3JlLCBzb2Npby1lY29ub21pYyBpbmRpY2F0b3JzIGZyb20gdGhlIGNyYXNoIGxvY2F0aW9uLCBzdWNoIGFzIHRoZSBwZXJjZW50YWdlIG9mIGluZGl2aWR1YWxzIHdpdGggYXQgbGVhc3QgYSBiYWNoZWxvcuKAmXMgZGVncmVlIGFuZCB0aGUgbWVkaWFuIGhvdXNlaG9sZCBpbmNvbWUgd2l0aGluIHRoZSBjZW5zdXMgYmxvY2sgZ3JvdXAsIGFyZSBjb25zaWRlcmVkLiBCeSBhbmFseXppbmcgdGhlc2UgdmFyaWFibGVzLCB3ZSBhaW0gdG8gYmV0dGVyIHVuZGVyc3RhbmQgdGhlIGZhY3RvcnMgdGhhdCBjb3JyZWxhdGUgd2l0aCBkcnVuayBkcml2aW5nIGluY2lkZW50cy4KClNvbWUgb2YgdGhlIHByZWRpY3RvcnMgaW4gdGhpcyBhbmFseXNpcyBpbmNsdWRlIGNyYXNoZXMgaW52b2x2aW5nIGZhdGFsaXRpZXMgb3IgbWFqb3IgaW5qdXJpZXMsIG92ZXJ0dXJuZWQgdmVoaWNsZXMsIGNlbGwgcGhvbmUgdXNlLCBzcGVlZGluZywgYW5kIGFnZ3Jlc3NpdmUgZHJpdmluZy4gVGhlc2UgZmFjdG9ycyBtYXkgYmUgYXNzb2NpYXRlZCB3aXRoIGRydW5rIGRyaXZpbmcgYmVjYXVzZSB0aGV5IHJlZmxlY3QgYmVoYXZpb3JzIGFuZCBvdXRjb21lcyBvZnRlbiBjb25uZWN0ZWQgdG8gdGhlIGltcGFpcmVkIGp1ZGdtZW50IGFuZCBzbG93ZWQgcmVhY3Rpb24gdGltZXMgdGhhdCByZXN1bHQgZnJvbSBhbGNvaG9sIGNvbnN1bXB0aW9uLiBGb3IgaW5zdGFuY2UsIGFsY29ob2wgaW1wYWlybWVudCBpbmNyZWFzZXMgdGhlIGxpa2VsaWhvb2Qgb2Ygc2V2ZXJlIGNyYXNoZXMgcmVzdWx0aW5nIGluIGZhdGFsaXRpZXMgb3IgbWFqb3IgaW5qdXJpZXMsIGFzIGltcGFpcmVkIGRyaXZlcnMgYXJlIGxlc3MgYWJsZSB0byByZXNwb25kIHRvIHN1ZGRlbiBjaGFuZ2VzIG9uIHRoZSByb2FkLiBPdmVydHVybmVkIHZlaGljbGVzIGFyZSBhbHNvIG1vcmUgY29tbW9uIGluIGRydW5rLWRyaXZpbmcgaW5jaWRlbnRzLCBhcyBhbGNvaG9sIGNhbiBsZWFkIHRvIGEgbG9zcyBvZiB2ZWhpY2xlIGNvbnRyb2wuIEFkZGl0aW9uYWxseSwgY2VsbCBwaG9uZSB1c2UsIHdoaWNoIGlzIGFscmVhZHkgYSByaXNreSBiZWhhdmlvciwgYmVjb21lcyBldmVuIG1vcmUgZGFuZ2Vyb3VzIHdoZW4gY29tYmluZWQgd2l0aCBhbGNvaG9sIGltcGFpcm1lbnQsIGFzIGRydW5rIGRyaXZlcnMgbWF5IGJlIG1vcmUgcHJvbmUgdG8gZW5nYWdlIGluIGRpc3RyYWN0aW9ucy4gU3BlZWRpbmcgaXMgYW5vdGhlciBjb21tb24gZmFjdG9yLCBhcyBhbGNvaG9sIHJlZHVjZXMgaW5oaWJpdGlvbnMsIGxlYWRpbmcgZHJpdmVycyB0byBpZ25vcmUgc3BlZWQgbGltaXRzIGFuZCB0cmFmZmljIGxhd3MuIEFnZ3Jlc3NpdmUgZHJpdmluZyBpcyBhbHNvIGhlaWdodGVuZWQgYnkgYWxjb2hvbCwgd2hpY2ggY2FuIGluY3JlYXNlIGFnZ3Jlc3Npb24gYW5kIGxlYWQgdG8gcmlza3kgYmVoYXZpb3JzIGxpa2UgdGFpbGdhdGluZyBvciBjdXR0aW5nIG9mZiBvdGhlciB2ZWhpY2xlcy4gQWx0b2dldGhlciwgdGhlc2UgcHJlZGljdG9ycyBjYXB0dXJlIHBhdHRlcm5zIG9mIGJlaGF2aW9yIHRoYXQgYXJlIG1vcmUgbGlrZWx5IHdoZW4gYWxjb2hvbCBpbXBhaXJzIGEgZHJpdmVy4oCZcyBtZW50YWwgYW5kIHBoeXNpY2FsIGFiaWxpdGllcywgbGVhZGluZyB0byBhIGdyZWF0ZXIgbGlrZWxpaG9vZCBvZiBzZXZlcmUgYWNjaWRlbnRzLgoKVGhlc2UgcHJlZGljdG9ycywgXCggXHRleHR7RFJJVkVSMTYxN31cKSAoY3Jhc2ggaW52b2x2aW5nIGEgZHJpdmVyIGFnZWQgMTYgb3IgMTcpIGFuZCBcKCBcdGV4dHtEUklWRVI2NVBMVVN9XCkKIChjcmFzaCBpbnZvbHZpbmcgYSBkcml2ZXIgYWdlZCA2NSBvciBvbGRlciksIG1pZ2h0IGJlIGFzc29jaWF0ZWQgd2l0aCBkcnVuayBkcml2aW5nIGR1ZSB0byBhZ2UtcmVsYXRlZCBmYWN0b3JzIGluIGJlaGF2aW9yIGFuZCBhYmlsaXR5LiBZb3VuZ2VyIGRyaXZlcnMsIGVzcGVjaWFsbHkgdGhvc2UgYWdlZCAxNiBvciAxNywgbWF5IGJlIG1vcmUgcHJvbmUgdG8gcmlza3kgYmVoYXZpb3JzLCBpbmNsdWRpbmcgZXhwZXJpbWVudGluZyB3aXRoIGFsY29ob2wsIGR1ZSB0byBsb3dlciBleHBlcmllbmNlIGxldmVscyBhbmQgYSB0ZW5kZW5jeSB0b3dhcmQgcmlzay10YWtpbmcuIFRoaXMgYWdlIGdyb3VwIG1heSBsYWNrIHRoZSBleHBlcmllbmNlIGFuZCBqdWRnbWVudCB0byBoYW5kbGUgYWxjb2hvbCdzIGVmZmVjdHMsIG1ha2luZyB0aGVtIG1vcmUgc3VzY2VwdGlibGUgdG8gaW52b2x2ZW1lbnQgaW4gZHJ1bmstZHJpdmluZyBjcmFzaGVzLiBPbiB0aGUgb3RoZXIgaGFuZCwgb2xkZXIgZHJpdmVycywgcmVwcmVzZW50ZWQgYnkgRFJJVkVSNjVQTFVTLCBtYXkgYWxzbyBiZSBhZmZlY3RlZCBieSBhbGNvaG9sIGltcGFpcm1lbnQgZGlmZmVyZW50bHkuIFdoaWxlIHRoZXkgbWF5IG5vdCBlbmdhZ2UgaW4gcmlza3kgYmVoYXZpb3IgYXMgZnJlcXVlbnRseSwgYWxjb2hvbCBjYW4gc2lnbmlmaWNhbnRseSBpbXBhaXIgdGhlaXIgcmVhY3Rpb24gdGltZXMgYW5kIGRlY2lzaW9uLW1ha2luZyBhYmlsaXRpZXMsIHdoaWNoIG1heSBhbHJlYWR5IGJlIHNsb3dlciBkdWUgdG8gYWdlLiBUaGlzIGFnZSBncm91cCBtaWdodCBhbHNvIGJlIG1vcmUgdnVsbmVyYWJsZSB0byB0aGUgZWZmZWN0cyBvZiBldmVuIHNtYWxsIGFtb3VudHMgb2YgYWxjb2hvbCwgbGVhZGluZyB0byBhIGhpZ2hlciByaXNrIG9mIGFjY2lkZW50cyB3aGVuIGltcGFpcmVkLiBUb2dldGhlciwgdGhlc2UgcHJlZGljdG9ycyBoZWxwIGNhcHR1cmUgaG93IGRpZmZlcmVudCBhZ2UgZ3JvdXBzIG1heSBiZSB1bmlxdWVseSB2dWxuZXJhYmxlIHRvIHRoZSByaXNrcyBhc3NvY2lhdGVkIHdpdGggZHJ1bmsgZHJpdmluZy4KClRoZSBwcmVkaWN0b3JzIFwoIFx0ZXh0e1BDVEJBQ0hNT1J9XCkgKHRoZSBwZXJjZW50YWdlIG9mIGluZGl2aWR1YWxzIGFnZWQgMjUgb3Igb2xkZXIgd2l0aCBhdCBsZWFzdCBhIGJhY2hlbG9y4oCZcyBkZWdyZWUpIGFuZCBcKCBcdGV4dHtNRURISElOQ31cKSAobWVkaWFuIGhvdXNlaG9sZCBpbmNvbWUpIG1pZ2h0IGJlIGFzc29jaWF0ZWQgd2l0aCBkcnVuayBkcml2aW5nIGFzIHRoZXkgcmVmbGVjdCBzb2Npby1lY29ub21pYyBjaGFyYWN0ZXJpc3RpY3Mgb2YgdGhlIGFyZWEgd2hlcmUgY3Jhc2hlcyBvY2N1ci4gQXJlYXMgd2l0aCBoaWdoZXIgZWR1Y2F0aW9uIGxldmVscywgaW5kaWNhdGVkIGJ5IGEgZ3JlYXRlciBwZXJjZW50YWdlIG9mIGluZGl2aWR1YWxzIHdpdGggYmFjaGVsb3LigJlzIGRlZ3JlZXMsIG1heSBoYXZlIGxvd2VyIGluc3RhbmNlcyBvZiBkcnVuayBkcml2aW5nIGR1ZSB0byBpbmNyZWFzZWQgYXdhcmVuZXNzIG9mIHRoZSByaXNrcyBhc3NvY2lhdGVkIHdpdGggaW1wYWlyZWQgZHJpdmluZyBhbmQgcG90ZW50aWFsbHkgc3Ryb25nZXIgYWRoZXJlbmNlIHRvIHNhZmV0eSBwcmFjdGljZXMuIENvbnZlcnNlbHksIGFyZWFzIHdpdGggbG93ZXIgZWR1Y2F0aW9uIGxldmVscyBtaWdodCBzZWUgaGlnaGVyIHJhdGVzIG9mIGFsY29ob2wtcmVsYXRlZCBpbmNpZGVudHMgZHVlIHRvIHZhcmlvdXMgc29jaW8tZWNvbm9taWMgc3RyZXNzb3JzIG9yIGEgbGFjayBvZiBhY2Nlc3MgdG8gYWx0ZXJuYXRpdmUgdHJhbnNwb3J0YXRpb24gb3B0aW9ucy4gU2ltaWxhcmx5LCBtZWRpYW4gaG91c2Vob2xkIGluY29tZSBjYW4gcGxheSBhIHJvbGUgaW4gaW5mbHVlbmNpbmcgZHJ1bmsgZHJpdmluZyBwYXR0ZXJucy4gTG93ZXItaW5jb21lIGFyZWFzIG1heSBleHBlcmllbmNlIGhpZ2hlciByYXRlcyBvZiBhbGNvaG9sLWltcGFpcmVkIGRyaXZpbmcgaWYgcHVibGljIHRyYW5zcG9ydGF0aW9uIG9wdGlvbnMgYXJlIGxpbWl0ZWQsIG1ha2luZyBkcml2aW5nIHRoZSBwcmltYXJ5IG1vZGUgb2YgdHJhbnNwb3J0IHJlZ2FyZGxlc3Mgb2YgaW1wYWlybWVudC4gT24gdGhlIG90aGVyIGhhbmQsIGhpZ2hlci1pbmNvbWUgYXJlYXMgbWlnaHQgaGF2ZSBiZXR0ZXIgYWNjZXNzIHRvIHJpZGVzaGFyaW5nIHNlcnZpY2VzIG9yIGRlc2lnbmF0ZWQgZHJpdmVyIG9wdGlvbnMsIHBvdGVudGlhbGx5IHJlZHVjaW5nIHRoZSBsaWtlbGlob29kIG9mIGRydW5rIGRyaXZpbmcuIEJ5IGV4YW1pbmluZyB0aGVzZSBzb2Npby1lY29ub21pYyBpbmRpY2F0b3JzLCB3ZSBjYW4gZ2FpbiBpbnNpZ2h0IGludG8gaG93IGNvbW11bml0eSBjaGFyYWN0ZXJpc3RpY3MgbWlnaHQgaW5mbHVlbmNlIHRoZSBwcmV2YWxlbmNlIG9mIGRydW5rIGRyaXZpbmcgaW5jaWRlbnRzLgoKVG8gY29uZHVjdCB0aGlzIGFuYWx5c2lzLCB3ZSB3aWxsIHVzZSBsb2dpc3RpYyByZWdyZXNzaW9uIGluIFIgdG8gZXZhbHVhdGUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZXNlIHByZWRpY3RvcnMgYW5kIHRoZSBsaWtlbGlob29kIG9mIGRydW5rIGRyaXZpbmcuIAoKCiMgTWV0aG9kcwoKIyMgSXNzdWVzIHdpdGggT0xTCgpVc2luZyBPcmRpbmFyeSBMZWFzdCBTcXVhcmVzIChPTFMpIHJlZ3Jlc3Npb24gZm9yIGEgYmluYXJ5IGRlcGVuZGVudCB2YXJpYWJsZSBwb3NlcyBzZXZlcmFsIGlzc3Vlcy4gRmlyc3QsIHJlY2FsbCBiZWxvdyB0aGUgZXF1YXRpb24gb2YgT0xTIHJlZ3Jlc3Npb246IAoKJCQKeSA9IFxiZXRhXzAgKyBcYmV0YV8xeF8xICsgXGJldGFfMnhfMiArIC4uLiArIFxiZXRhX2t4X2sgKyBcZXBzaWxvbgokJAoKSGVyZSwgXCggXGJldGFfMSBcKSBpcyBpbnRlcnByZXRlZCBhcyB0aGUgYW1vdW50IGJ5IHdoaWNoIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgXCggeSBcKSBjaGFuZ2VzIGZvciBhIG9uZS11bml0IGNoYW5nZSBpbiB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGUgXCggeF8xIFwpLCBob2xkaW5nIGFsbCBvdGhlciB2YXJpYWJsZXMgY29uc3RhbnQuIEhvd2V2ZXIsIHdoZW4gdGhlIGRlcGVuZGVudCB2YXJpYWJsZSBpcyBiaW5hcnksIGEgb25lIHVuaXQgaW5jcmVhc2UgaW4gXCggeF8xIFwpIHJlc3VsdHMgaW4gXCggXGJldGFfMSBcKSBpbmNyZWFzZSBpbiBcKCB5IFwpIG5vIGxvbmdlciBtYWtlcyBzZW5zZSwgYXMgXCggeSBcKSBjYW4gY2hhbmdlIG9ubHkgZnJvbSAwIHRvIDEgb3IgZnJvbSAxIHRvIDAuIFRoaXMgbGVhZHMgdG8gc29tZSBpbnRlcnByZXRhdGlvbiBpc3N1ZXMgaWYgd2UgdXNlIE9MUyByZWdyZXNzaW9uIGZvciBiaW5hcnkgZGVwZW5kZW50IHZhcmlhYmxlcy4KClNlY29uZCwgT0xTIHJlZ3Jlc3Npb24gYXNzdW1lcyBhIGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGVzIGFuZCB0aGUgZGVwZW5kZW50IHZhcmlhYmxlLiBXaXRoIGEgYmluYXJ5IGRlcGVuZGVudCB2YXJpYWJsZSwgdGhpcyBhc3N1bXB0aW9uIGRvZXMgbm90IGhvbGQsIGFzIGJpbmFyeSBvdXRjb21lcyAoMCBvciAxKSBhcmUgaW5oZXJlbnRseSBub25saW5lYXIuIFRoaXJkLCBPTFMgYXNzdW1lcyBub3JtYWxseSBkaXN0cmlidXRlZCByZXNpZHVhbHMgKGVycm9ycyksIGJ1dCB3aXRoIGEgYmluYXJ5IG91dGNvbWUsIHRoZSByZXNpZHVhbHMgYXJlIG5vdCBub3JtYWxseSBkaXN0cmlidXRlZC4gSW5zdGVhZCwgdGhleSBmb2xsb3cgYSBiaW5vbWlhbCBkaXN0cmlidXRpb24uIFRoaXMgbWFrZXMgT0xTIGVzdGltYXRpb24gaW5lZmZpY2llbnQsIGFzIGl0IGNhbm5vdCBhY2NvdW50IGZvciB0aGUgc3BlY2lmaWMgZGlzdHJpYnV0aW9uIG9mIGJpbmFyeSBvdXRjb21lcy4gT24gdG9wIG9mIHRoZXNlLCB3aXRoIGJpbmFyeSBkYXRhLCB0aGUgdmFyaWFuY2Ugb2YgdGhlIGVycm9yIHRlcm0gaXMgbm90IGNvbnN0YW50OyBpdCB2YXJpZXMgd2l0aCB0aGUgcHJlZGljdGVkIHByb2JhYmlsaXR5LCBsZWFkaW5nIHRvIGhldGVyb3NjZWRhc3RpY2l0eS4gVGhpcyBhZmZlY3RzIHRoZSByZWxpYWJpbGl0eSBvZiBzdGFuZGFyZCBlcnJvcnMgYW5kIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGluIE9MUyByZWdyZXNzaW9uLCBsZWFkaW5nIHRvIHBvdGVudGlhbGx5IGluY29ycmVjdCBpbmZlcmVuY2VzLiBUaGUgYXNzdW1wc3Rpb25zIHRoYXQgYXBwbHkgdG8gbG9naXN0aWMgcmVncmVzc2lvbiB3aWxsIGJlIGVsYWJvcmF0ZWQgYmVsb3cuIAoKIyMgTG9naXN0aWMgUmVncmVzc2lvbiBDb25jZXB0cwoKTG9naXN0aWMgcmVncmVzc2lvbiBwcm92aWRlcyBhIHdheSBmb3IgdXMgdG8gZ2V0IGFyb3VuZCB0aGUgYWJvdmUtbWVudGlvbmVkIGlzc3Vlcy4gSW5zdGVhZCBvZiBwcmVkaWN0aW5nIHRoZSBcKCB5IFwpIHZhbHVlLCB3ZSBwcmVkaWN0IHRoZSBwcm9iYWJpbGl0eSBvZiBcKCB5IFwpIGJlaW5nIDEuIFRoaXMgY2FuIGJlIGV4cGxhaW5lZCB0aHJvdWdoIHRoZSBjb25jZXB0IG9mIG9kZHMuIFRoZSAqKm9kZHMqKiBvZiBhbiBldmVudCBpcyBhIHJhdGlvIHRoYXQgY29tcGFyZXMgdGhlIGxpa2VsaWhvb2Qgb2YgdGhlIGV2ZW50IGhhcHBlbmluZyB0byB0aGUgbGlrZWxpaG9vZCBvZiBpdCBub3QgaGFwcGVuaW5nLiBNYXRoZW1hdGljYWxseSwgb2RkcyBhcmUgY2FsY3VsYXRlZCBhczoKCiQkClx0ZXh0e09kZHN9ID0gXGZyYWN7XHRleHR7UHJvYmFiaWxpdHkgb2YgRXZlbnQgSGFwcGVuaW5nfX17XHRleHR7UHJvYmFiaWxpdHkgb2YgRXZlbnQgTm90IEhhcHBlbmluZ319ID0gXGZyYWN7cH17MSAtIHB9CiQkCkZvciBleGFtcGxlLCBpZiB0aGVyZSBpcyBhIDcwJSBjaGFuY2Ugb2YgYW4gZXZlbnQgaGFwcGVuaW5nIChwcm9iYWJpbGl0eSBcKCBwID0gMC43IFwpKSwgdGhlIG9kZHMgd291bGQgYmU6CgokJApcdGV4dHtPZGRzfSA9IFxmcmFjezAuN317MSAtIDAuN30gPSBcZnJhY3swLjd9ezAuM30gPSAyLjMzCiQkCgpUaGlzIG1lYW5zIHRoZSBldmVudCBpcyAyLjMzIHRpbWVzIG1vcmUgbGlrZWx5IHRvIGhhcHBlbiB0aGFuIG5vdCBoYXBwZW4uIEluIGxvZ2lzdGljIHJlZ3Jlc3Npb24sIGluc3RlYWQgb2YgcHJlZGljdGluZyB0aGUgcHJvYmFiaWxpdHkgZGlyZWN0bHksIHdlIHByZWRpY3QgdGhlICoqbG9nLW9kZHMqKiAoYWxzbyBjYWxsZWQgdGhlICoqbG9naXQqKikgb2YgdGhlIG91dGNvbWUuIFRoZSBsb2dpdCBtb2RlbCB3aXRoIG11bHRpcGxlIHByZWRpY3RvcnMgaXMgZ2l2ZW4gYnk6CgokJApcbG9nIFxsZWZ0KCBcZnJhY3twfXsxIC0gcH0gXHJpZ2h0KSA9IFxiZXRhXzAgKyBcYmV0YV8xIHhfMSArIFxiZXRhXzIgeF8yICsgXGRvdHMgKyBcYmV0YV9rIHhfawokJApJbiBvdXIgc3BlY2lmaWMgY2FzZSwgaXQgY2FuIGJlIHdyaXR0ZW4gYXM6IAoKJCQKXGxvZyBcbGVmdCggXGZyYWN7UChcdGV4dHtEUklOS0lOR19EfSA9IDEpfXsxIC0gUChcdGV4dHtEUklOS0lOR19EfSA9IDEpfSBccmlnaHQpID0gXGJldGFfMCArIFxiZXRhXzEgXGNkb3QgXHRleHR7RkFUQUxfT1JfTX0gKyBcYmV0YV8yIFxjZG90IFx0ZXh0e09WRVJUVVJORUR9ICsgXGRvdHMgKyBcYmV0YV85IFxjZG90IFx0ZXh0e01FREhISU5DfQokJAoKd2hlcmUgXCggUChcdGV4dHtEUklOS0lOR19EfSA9IDEpIFwpIGlzIHRoZSBwcm9iYWJpbGl0eSB0aGF0IGRyaW5raW5nIHdhcyBpbnZvbHZlZCBpbiBhIGNyYXNoLiBcKCBcbG9nIFxsZWZ0KCBcZnJhY3tQKFx0ZXh0e0RSSU5LSU5HX0R9ID0gMSl9ezEgLSBQKFx0ZXh0e0RSSU5LSU5HX0R9ID0gMSl9IFxyaWdodCkgXCkgaXMgdGhlIGxvZy1vZGRzIG9mIGRyaW5raW5nIGludm9sdmVtZW50LiBcKCBcYmV0YV8wIFwpIGlzIHRoZSBpbnRlcmNlcHQsIHJlcHJlc2VudGluZyB0aGUgbG9nLW9kZHMgb2YgZHJpbmtpbmcgYmVpbmcgaW52b2x2ZWQgd2hlbiBhbGwgcHJlZGljdG9ycyBhcmUgemVyby4gXCggXGJldGFfMSwgXGJldGFfMiwgXGRvdHMsIFxiZXRhXzkgXCkgYXJlIHRoZSBjb2VmZmljaWVudHMgZm9yIGVhY2ggcHJlZGljdG9yIHZhcmlhYmxlLCBpbmRpY2F0aW5nIHRoZSBjaGFuZ2UgaW4gbG9nLW9kZHMgZm9yIGEgb25lLXVuaXQgaW5jcmVhc2UgaW4gZWFjaCBwcmVkaWN0b3IuCgpUaGUgcHJlZGljdG9yIHZhcmlhYmxlIGluIHRoZSBtb2RlbCBpcyBkZWZpbmVkIGFzIGZvbGxvd3M6CgotICoqRkFUQUxfT1JfTSoqOiBJbmRpY2F0b3IgZm9yIHdoZXRoZXIgdGhlIGNyYXNoIGludm9sdmVkIGEgZmF0YWxpdHkuCgotICoqT1ZFUlRVUk5FRCoqOiBJbmRpY2F0b3IgZm9yIHdoZXRoZXIgdGhlIGNyYXNoIGludm9sdmVkIGFuIG92ZXJ0dXJuZWQgdmVoaWNsZS4KCi0gKipDRUxMX1BIT05FKio6IEluZGljYXRvciBmb3Igd2hldGhlciBhIGNlbGwgcGhvbmUgd2FzIGluIHVzZS4KCi0gKipTUEVFRElORyoqOiBJbmRpY2F0b3IgZm9yIHdoZXRoZXIgc3BlZWRpbmcgd2FzIGEgZmFjdG9yIGluIHRoZSBjcmFzaC4KCi0gKipBR0dSRVNTSVZFKio6IEluZGljYXRvciBmb3Igd2hldGhlciBhZ2dyZXNzaXZlIGRyaXZpbmcgd2FzIGludm9sdmVkLgoKLSAqKkRSSVZFUjE2MTcqKjogSW5kaWNhdG9yIGZvciB3aGV0aGVyIHRoZSBkcml2ZXIgd2FzIGJldHdlZW4gMTYtMTcgeWVhcnMgb2xkLgoKLSAqKkRSSVZFUjY1UExVUyoqOiBJbmRpY2F0b3IgZm9yIHdoZXRoZXIgdGhlIGRyaXZlciB3YXMgNjUgeWVhcnMgb3Igb2xkZXIuCgotICoqUENUQkFDSE1PUioqOiBQZXJjZW50YWdlIG9mIHBlb3BsZSBpbiB0aGUgYXJlYSB3aXRoIGEgYmFjaGVsb3IncyBkZWdyZWUgb3IgbW9yZS4KCi0gKipNRURISElOQyoqOiBNZWRpYW4gaG91c2Vob2xkIGluY29tZSBpbiB0aGUgYXJlYS4KClRoZSAqKkxvZ2lzdGljIEZ1bmN0aW9uKio6IFRoZSBsb2dpc3RpYyBmdW5jdGlvbiBpcyB0aGUgKippbnZlcnNlKiogb2YgdGhlIGxvZ2l0IGZ1bmN0aW9uLiBJdCB0YWtlcyB0aGUgbGluZWFyIHByZWRpY3RvciAobG9nLW9kZHMpIGFuZCBjb252ZXJ0cyBpdCBiYWNrIHRvIGEgcHJvYmFiaWxpdHksIGVuc3VyaW5nIHRoYXQgdGhlIG91dHB1dCBpcyB3aXRoaW4gdGhlIHJhbmdlIFwoIFswLCAxXSBcKS4gVGhpcyB0cmFuc2Zvcm1hdGlvbiBpcyBpZGVhbCBmb3IgbW9kZWxpbmcgYmluYXJ5IG91dGNvbWVzIGJlY2F1c2UgaXQgbmF0dXJhbGx5IG1hcHMgYW55IGxpbmVhciBwcmVkaWN0b3Igb250byBhIHByb2JhYmlsaXR5IHNjYWxlLiBUaGUgbG9naXN0aWMgZnVuY3Rpb24gaXMgZ2l2ZW4gYnk6CgokJApQKFx0ZXh0e0RSSU5LSU5HX0R9ID0gMSkgPSBcZnJhY3sxfXsxICsgZV57LShcYmV0YV8wICsgXGJldGFfMSBcY2RvdCBcdGV4dHtGQVRBTF9PUl9NfSArIFxkb3RzICsgXGJldGFfOSBcY2RvdCBcdGV4dHtNRURISElOQ30pfX0KJCQKClRoZSBsb2dpc3RpYyBmdW5jdGlvbiBpcyB0aGUgdHlwZSBvZiB0cmFuc2xhdG9yIGZ1bmN0aW9uIHdlIGFyZSBsb29raW5nIGZvci4gSXQgaGFzIGFuICoqUy1zaGFwZWQgKHNpZ21vaWQpIGN1cnZlKiogd2l0aCB0aGUgZm9sbG93aW5nIHByb3BlcnRpZXM6CgotICoqQm91bmRlZCBPdXRwdXQqKjogQXMgdGhlIGxpbmVhciBwcmVkaWN0b3IgYXBwcm9hY2hlcyBcKCArXGluZnR5IFwpLCB0aGUgcHJvYmFiaWxpdHkgXCggUChcdGV4dHtEUklOS0lOR1xfRH0gPSAxKSBcKSBhcHByb2FjaGVzIDEuIEFzIHRoZSBwcmVkaWN0b3IgYXBwcm9hY2hlcyBcKCAtXGluZnR5IFwpLCB0aGUgcHJvYmFiaWxpdHkgYXBwcm9hY2hlcyAwLCBlbnN1cmluZyB0aGUgb3V0cHV0IGlzIHdpdGhpbiB0aGUgdmFsaWQgcHJvYmFiaWxpdHkgcmFuZ2UgXChbMCwgMV1cKS4KICAKLSAqKlN5bW1ldHJ5Kio6IFRoZSBsb2dpc3RpYyBmdW5jdGlvbiBpcyBzeW1tZXRyaWMgYXJvdW5kIDAuNSwgbWVhbmluZyB0aGF0IHdoZW4gdGhlIGxpbmVhciBwcmVkaWN0b3IgaXMgMCAoaS5lLiwgXCggXGJldGFfMCArIFxiZXRhXzEgXGNkb3QgXHRleHR7RkFUQUxfT1JfTX0gKyBcZG90cyArIFxiZXRhXzkgXGNkb3QgXHRleHR7TUVESEhJTkN9ID0gMCBcKSksIHRoZSBwcm9iYWJpbGl0eSBpcyAwLjUuIFRoaXMgbWlkcG9pbnQgaXMgdXNlZnVsIGluIGJpbmFyeSBjbGFzc2lmaWNhdGlvbiBhcyBpdCBoZWxwcyBpbnRlcnByZXQgcHJvYmFiaWxpdGllcyBhcm91bmQgNTAlLgoKT3ZlcmFsbCwgaXQgd29ya3MgIHdlbGwgZm9yIGJpbmFyeSBtb2RlbHMgYmVjYXVzZSBpdCByZXN0cmljdHMgcHJlZGljdGVkIHByb2JhYmlsaXRpZXMgdG8gYSByYW5nZSBvZiAwIGFuZCAxLCB3aGljaCBpcyByZXF1aXJlZCBpbiBiaW5hcnkgY2xhc3NpZmljYXRpb24gdGFza3MuRWFjaCBjb2VmZmljaWVudCBcKCBcYmV0YV9pIFwpIHJlcHJlc2VudHMgdGhlIGVmZmVjdCBvZiBhIHByZWRpY3RvciBvbiB0aGUgbG9nLW9kZHMgb2YgdGhlIG91dGNvbWUsIHdoaWNoIGNhbiBiZSB0cmFuc2Zvcm1lZCB0byBpbnRlcnByZXQgZWZmZWN0cyBvbiBwcm9iYWJpbGl0aWVzLgogIAoKIyMgTG9naXN0aWMgUmVncmVzc2lvbiBIeXBvdGhlc2lzCgpGb3IgZWFjaCBwcmVkaWN0b3IgaW4gb3VyIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwsIHdlIHdhbnQgdG8gdGVzdCB3aGV0aGVyIHRoZSBwcmVkaWN0b3IgaGFzIGEgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBlZmZlY3Qgb24gdGhlIGxpa2VsaWhvb2Qgb2YgdGhlIG91dGNvbWUuIAoKVGhlICAqKk51bGwgSHlwb3RoZXNpcyoqIChcKCBIXzAgXCkpLCB3aGljaCBzdGF0ZXMgdGhhdCB0aGUgcHJlZGljdG9yIGhhcyBubyBlZmZlY3Qgb24gdGhlIG91dGNvbWUsIGNhbiBiZSB3cml0dGVuIGFzOiAKCiQkCkhfMCA6IFxiZXRhX2kgPSAwCiQkCgpUaGUgKipBbHRlcm5hdGl2ZSBIeXBvdGhlc2lzKiogKFwoIEhfYSBcKSkgd2hpY2ggc3RhdGVzIHRoYXQgdGhlIHByZWRpY3RvciBoYXMgc2lnbmlmaWNhbnQgZWZmZWN0IG9uIHRoZSBvdXRjb21lLCBjYW4gYmUgd3JpdHRlbiBhczogCgokJApIX2EgOiBcYmV0YV9pIFxuZXEgMAokJAoKVG8gdGVzdCB0aGVzZSBoeXBvdGhlc2VzLCB3ZSB1c2UgdGhlICoqV2FsZCBzdGF0aXN0aWMqKiBmb3IgZWFjaCBjb2VmZmljaWVudCBcKCBcYmV0YV9pIFwpLiBUaGUgV2FsZCBzdGF0aXN0aWMgaXMgY2FsY3VsYXRlZCBhczoKCiQkCldfaSA9IFxmcmFje1xoYXR7XGJldGF9X2l9e1xzaWdtYShcaGF0e1xiZXRhfV9pKX0KJCQKCndoZXJlIFwoIFxoYXR7XGJldGF9X2kgXCkgaXMgdGhlIGVzdGltYXRlZCBjb2VmZmljaWVudCBmb3IgcHJlZGljdG9yLCBhbmQgXCggXHNpZ21hKFxoYXR7XGJldGF9X2kpIFwpIGlzIHRoZSBzdGFuZGFyZCBlcnJvciBvZiB0aGlzIGVzdGltYXRlLiBVbmRlciB0aGUgbnVsbCBoeXBvdGhlc2lzLCB0aGUgV2FsZCBzdGF0aXN0aWMgYXBwcm94aW1hdGVseSBmb2xsb3dzIGEgc3RhbmRhcmQgbm9ybWFsIGRpc3RyaWJ1dGlvbiBcKCBOKDAsIDEpIFwpLiBMYXJnZSB2YWx1ZXMgb2YgXCggfFdfaXwgXCkgaW5kaWNhdGUgdGhhdCBcKCBcYmV0YV9pIFwpIGlzIHNpZ25pZmljYW50bHkgZGlmZmVyZW50IGZyb20gemVybywgbGVhZGluZyB1cyB0byByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcy4KCkhvd2V2ZXIsIHJhdGhlciB0aGFuIGxvb2tpbmcgYXQgdGhlIGVzdGltYXRlZCBcKCBcYmV0YSBcKSBjb2VmZmljaWVudHMsIG1vc3Qgc3RhdGlzdGljaWFucyBzdGlsbCBwcmVmZXIgdG8gbG9vayBhdCAqKm9kZHMgcmF0aW9zKiouIFRoZSBvZGRzIHJhdGlvIGlzIGNhbGN1bGF0ZWQgYnkgZXhwb25lbnRpYXRpbmcgdGhlIGNvZWZmaWNpZW50cy4gRm9yIGV4YW1wbGUsIGlmIHRoZSBvZGRzIHJhdGlvIGZvciBhIHByZWRpY3RvciBpcyAxLjUsIGl0IG1lYW5zIHRoYXQgdGhlIG9kZHMgb2YgdGhlIG91dGNvbWUgaGFwcGVuaW5nIGFyZSAxLjUgdGltZXMgaGlnaGVyIGZvciBhIG9uZS11bml0IGluY3JlYXNlIGluIHRoZSBwcmVkaWN0b3IuIEFuIG9kZHMgcmF0aW8gZ3JlYXRlciB0aGFuIDEgaW5kaWNhdGVzIHRoYXQgdGhlIHByZWRpY3RvciBpcyBhc3NvY2lhdGVkIHdpdGggYW4gaW5jcmVhc2VkIGxpa2VsaWhvb2Qgb2YgdGhlIG91dGNvbWUsIHdoaWxlIGFuIG9kZHMgcmF0aW8gbGVzcyB0aGFuIDEgaW5kaWNhdGVzIGEgZGVjcmVhc2VkIGxpa2VsaWhvb2QuCgojIyBMb2dpc3RpYyBSZWdyZXNzaW9uIE1vZGVsIEFzc2Vzc21lbnQKIApJbiBsb2dpc3RpYyByZWdyZXNzaW9uLCB0aGVyZSBhcmUgc2V2ZXJhbCB3YXlzIHRvIGFzc2VzcyB0aGUgcXVhbGl0eSBvZiB0aGUgbW9kZWwgZml0LiBXaGlsZSBcKCBSXjIgXCkgaXMgY29tbW9ubHkgdXNlZCBpbiBPTFMgdG8gbWVhc3VyZSB0aGUgcHJvcG9ydGlvbiBvZiB2YXJpYW5jZSBleHBsYWluZWQgYnkgdGhlIG1vZGVsLCBpdCBpcyBub3QgZGlyZWN0bHkgYXBwbGljYWJsZSB0byBsb2dpc3RpYyByZWdyZXNzaW9uLiBBbHRob3VnaCBhIHBzZXVkby1cKCBSXjIgXCkgc3RhdGlzdGljIGNhbiBiZSBjYWxjdWxhdGVkIGZvciBsb2dpc3RpYyByZWdyZXNzaW9uIChlLmcuLCBNY0ZhZGRlbidzIFwoIFJeMiBcKSksIGl0IGRvZXMgbm90IGhhdmUgdGhlIHNhbWUgaW50ZXJwcmV0YXRpb24gYXMgaW4gT0xTIHJlZ3Jlc3Npb24gYW5kIGlzIG5vdCBhcyB3aWRlbHkgdXNlZCBmb3IgbW9kZWwgYXNzZXNzbWVudC4KCkEgYmV0dGVyIGFsdGVybmF0aXZlIGZvciBjb21wYXJpbmcgbW9kZWxzIGlzIHRoZSAqKkFrYWlrZSBJbmZvcm1hdGlvbiBDcml0ZXJpb24qKiAoQUlDKS4gVGhlIEFJQyBpcyBhIG1lYXN1cmUgdGhhdCBwZW5hbGl6ZXMgbW9kZWxzIGZvciBjb21wbGV4aXR5IChpLmUuLCB0aGUgbnVtYmVyIG9mIHByZWRpY3RvcnMpIGFuZCByZXdhcmRzIGdvb2RuZXNzIG9mIGZpdC4gSXQgaXMgZGVmaW5lZCBhczoKCiQkClx0ZXh0e0FJQ30gPSAyayAtIDJcbG4oXGhhdHtMfSkKJCQKCndoZXJlIFwoIGsgXCkgaXMgdGhlIG51bWJlciBvZiBwYXJhbWV0ZXJzIGluIHRoZSBtb2RlbCwgYW5kIFwoIFxoYXR7TH0gXCkgaXMgdGhlIG1heGltdW0gbGlrZWxpaG9vZCBvZiB0aGUgbW9kZWwuIExvd2VyIEFJQyB2YWx1ZXMgaW5kaWNhdGUgYSBiZXR0ZXIgZml0LCBhcyB0aGV5IGJhbGFuY2UgdGhlIHRyYWRlLW9mZiBiZXR3ZWVuIG1vZGVsIGNvbXBsZXhpdHkgYW5kIGdvb2RuZXNzIG9mIGZpdC4KCkFuIGV2ZW4gYmV0dGVyIHdheSB0byBhc3Nlc3MgdGhlIHF1YWxpdHkgb2YgdGhlIG1vZGVsIGlzIHRvIGNvbXB1dGUgdGhlIHNwZWNpZmljaXR5LCBzZW5zaXRpdml0eSBhbmQgdGhlIG1pc2NsYXNzaWZpY2F0aW9uIHJhdGUsIGFuZCB0aGVuIHRoZSBBVUMgdmFsdWUuIFRvIGRvIHRoYXQsIHdlIGZpcnN0IG5lZWQgdG8gY2FsY3VsYXRlIHRoZSBwcmVkaWN0ZWQgdmFsdWVzIG9mIFwoIHkgXCkuIFRoZSBwcmVkaWN0ZWQgdmFsdWVzIFwoIFxoYXR7eX0gXCkgYXJlIGNhbGN1bGF0ZWQgYXM6CgoKJCQKXHRleHR7UCh5PTEpfSA9IFxoYXR7eX0gPSBcZnJhY3sxfXsxICsgXGV4cCgtXGhhdHtcYmV0YX1fMCAtIFxoYXR7XGJldGF9XzF4XzEgLSBcZG90cyAtIFxoYXR7XGJldGF9X2t4X2spfQokJAp3aGVyZSBcKCBcaGF0e3l9IFwpIHJlcHJlc2VudHMgdGhlIHByZWRpY3RlZCBwcm9iYWJpbGl0eSBvZiB0aGUgb3V0Y29tZSBiZWluZyBcKCB5ID0gMSBcKS4KCkFmdGVyIG9idGFpbmluZyB0aGUgcHJlZGljdGVkIHByb2JhYmlsaXRpZXMsIHdlIGFwcGx5IGEgdGhyZXNob2xkIChjdXQtb2ZmKSB0byBjbGFzc2lmeSBwcmVkaWN0aW9ucyBpbnRvIGJpbmFyeSBvdXRjb21lcyAoZS5nLiBjbGFzc2lmeSBcKCBcaGF0e3l9ID4gMC41IFwpIGFzIFwoIHkgPSAxIFwpLCBhbmQgXCggXGhhdHt5fSBcbGVxIDAuNSBcKSBhcyBcKCB5ID0gMCBcKSkuIEl0IGlzIGltcG9ydGFudCB0byBub3RlIHRoYXQgdGhlIGNob2ljZSBvZiBjdXQtb2ZmIHZhbHVlIChpLmUuLCB0aHJlc2hvbGQgZm9yIGNsYXNzaWZ5aW5nIFwoIHkgPSAxIFwpKSBpbXBhY3RzIHRoZSBzcGVjaWZpY2l0eSwgc2Vuc2l0aXZpdHksIGFuZCBtaXNjbGFzc2lmaWNhdGlvbiByYXRlLiBUaGUgZGVmYXVsdCB0aHJlc2hvbGQgb2YgMC41IG1heSBub3QgYWx3YXlzIGJlIG9wdGltYWwuIFVzaW5nIGRpZmZlcmVudCBjdXQtb2ZmcyBhbGxvd3MgZm9yIGEgdHJhZGUtb2ZmIGJldHdlZW4gc2Vuc2l0aXZpdHkgYW5kIHNwZWNpZmljaXR5LiBGb3IgZXhhbXBsZSwgYSBsb3dlciBjdXQtb2ZmIG1pZ2h0IGluY3JlYXNlIHNlbnNpdGl2aXR5IGF0IHRoZSBleHBlbnNlIG9mIHNwZWNpZmljaXR5LCBhbmQgdmljZSB2ZXJzYS4gCgpUaGVuLCB3ZSBjb3VsZCBjYWxjdWxhdGUgdGhlICoqc2Vuc2l0aXZpdHkqKiBhbmQgKipzcGVjaWZpY2l0eSoqIG9mIHRoZSBtb2RlbC4gU2Vuc2l0aXZpdHkgaXMgdGhlIHByb3BvcnRpb24gb2YgdHJ1ZSBwb3NpdGl2ZXMgKGFjdHVhbCBwb3NpdGl2ZXMgY29ycmVjdGx5IHByZWRpY3RlZCBhcyBwb3NpdGl2ZXMpLCB3aGlsZSBzcGVjaWZpY2l0eSBpcyB0aGUgcHJvcG9ydGlvbiBvZiB0cnVlIG5lZ2F0aXZlcyAoYWN0dWFsIG5lZ2F0aXZlcyBjb3JyZWN0bHkgcHJlZGljdGVkIGFzIG5lZ2F0aXZlcykuIFRoZSAqKm1pc2NsYXNzaWZpY2F0aW9uIHJhdGUqKiBpcyB0aGUgcHJvcG9ydGlvbiBvZiBpbmNvcnJlY3QgcHJlZGljdGlvbnMgbWFkZSBieSB0aGUgbW9kZWwuIFRoZXkgYXJlIGNhbGN1bGF0ZWQgYXM6CgokJApcdGV4dHtTZW5zaXRpdml0eX0gPSBcZnJhY3tUUH17VFAgKyBGTn0KJCQKd2hlcmUgXCggVFAgXCkgaXMgdGhlIG51bWJlciBvZiB0cnVlIHBvc2l0aXZlcyBhbmQgXCggRk4gXCkgaXMgdGhlIG51bWJlciBvZiBmYWxzZSBuZWdhdGl2ZXMuIEhpZ2hlciBzZW5zaXRpdml0eSB2YWx1ZXMgYXJlIGJldHRlciwgYXMgdGhleSBpbmRpY2F0ZSB0aGF0IHRoZSBtb2RlbCBpcyBnb29kIGF0IGlkZW50aWZ5aW5nIHRoZSBwb3NpdGl2ZSBjbGFzcy4KCiQkClx0ZXh0e1NwZWNpZmljaXR5fSA9IFxmcmFje1ROfXtUTiArIEZQfQokJAoKd2hlcmUgXCggVE4gXCkgaXMgdGhlIG51bWJlciBvZiB0cnVlIG5lZ2F0aXZlcyBhbmQgXCggRlAgXCkgaXMgdGhlIG51bWJlciBvZiBmYWxzZSBwb3NpdGl2ZXMuIEhpZ2hlciBzcGVjaWZpY2l0eSB2YWx1ZXMgYXJlIGJldHRlciwgYXMgdGhleSBpbmRpY2F0ZSB0aGF0IHRoZSBtb2RlbCBpcyBnb29kIGF0IGlkZW50aWZ5aW5nIHRoZSBuZWdhdGl2ZSBjbGFzcy4KCiQkClx0ZXh0e01pc2NsYXNzaWZpY2F0aW9uIFJhdGV9ID0gXGZyYWN7RlAgKyBGTn17VFAgKyBUTiArIEZQICsgRk59CiQkCgpMb3dlciBtaXNjbGFzc2lmaWNhdGlvbiByYXRlcyBhcmUgYmV0dGVyLCBhcyB0aGV5IGluZGljYXRlIGZld2VyIGVycm9ycyBpbiBjbGFzc2lmaWNhdGlvbi4KCkRpZmZlcmVudCBjdXRvZmYgY2FuIGxlYWQgdG8gZGlmZmVyZW50IHNlbnNpdGl2aXR5LCBzcGVjaWZpY2l0eSBhbmQgbWlzY2xhc3NpZmljYXRpb24gcmF0ZXMuVG8gZGV0ZXJtaW5lIHRoZSBvcHRpbWFsIGN1dC1vZmYgZm9yIGNsYXNzaWZpY2F0aW9uLCB3ZSBjYW4gY2FsY3VsYXRlIHRoZSAqKllvdWRlbidzIEluZGV4KiosIHdoaWNoIGlzIGRlZmluZWQgYXM6CgokJApKID0gXHRleHR7U2Vuc2l0aXZpdHl9ICsgXHRleHR7U3BlY2lmaWNpdHl9IC0gMQokJApBbHRlcm5hdGl2ZWx5LCB3ZSBjYW4gdXNlIHRoZSAqKlJPQyBjdXJ2ZSoqIHRvIHZpc3VhbGl6ZSB0aGUgdHJhZGUtb2ZmIGJldHdlZW4gc2Vuc2l0aXZpdHkgYW5kIHNwZWNpZmljaXR5IGF0IGRpZmZlcmVudCBjdXQtb2ZmIHZhbHVlcywgYW5kIGZpbmQgYSBjdXQtb2ZmIGZvciB3aGljaCB0aGUgUk9DIGN1cnZlIGhhcyB0aGUgbWluaW11bSBkaXN0YW5jZSBmcm9tIHRoZSB1cHBlciBsZWZ0IGNvcm5lciBvZiB0aGUgZ3JhcGggKHRoZSBwb2ludCBhdCB3aGljaCBzZW5zaXRpdml0eSBhbmQgc3BlY2lmaWNpdHkgYXJlIGJvdGggMSkuIFdlIGltcGxlbWVudCB0aGlzIAoKVG8gcHJvdmlkZSBtb3JlIGNvdGV4dCwgdGhlICoqUk9DIGN1cnZlKiogaXMgdGhlbiBhIGdyYXBoaWNhbCByZXByZXNlbnRhdGlvbiBvZiBhIGNsYXNzaWZpZXIncyBwZXJmb3JtYW5jZSwgcGxvdHRpbmcgKipzZW5zaXRpdml0eSoqICh0cnVlIHBvc2l0aXZlIHJhdGUpIG9uIHRoZSB5LWF4aXMgYWdhaW5zdCAqKjEgLSBzcGVjaWZpY2l0eSoqIChmYWxzZSBwb3NpdGl2ZSByYXRlKSBvbiB0aGUgeC1heGlzIGZvciBkaWZmZXJlbnQgdGhyZXNob2xkIHZhbHVlcy4gVGhlIFJPQyBjdXJ2ZSBoZWxwcyB2aXN1YWxpemUgdGhlIHRyYWRlLW9mZiBiZXR3ZWVuIHNlbnNpdGl2aXR5IGFuZCBzcGVjaWZpY2l0eSBhdCB2YXJpb3VzIGN1dC1vZmZzLiAKCkJhc2VkIG9uIHRoZSBST0MgY3VydmUsIHdlIGNhbiBjYWxjdWxhdGUgdGhlICoqQXJlYSBVbmRlciB0aGUgQ3VydmUqKiAoQVVDKSB0byBxdWFudGlmeSB0aGUgbW9kZWwncyBwZXJmb3JtYW5jZS4gQXJlYSB1bmRlciBST0MgQ3VydmUgaXMgYSBtZWFzdXJlIG9mIHByZWRpY3Rpb24gYWNjdXJhY3kgb2YgdGhlIG1vZGVsIChob3cgd2VsbCBhIG1vZGVsIHByZWRpY3RzIDEgcmVzcG9uc2VzIGFzIDHigJlzIGFuZCAwIHJlc3BvbnNlcyBhcyAw4oCZcykuIFRoZSBBVUMgcmFuZ2VzIGZyb20gMCB0byAxLCB3aXRoIGhpZ2hlciB2YWx1ZXMgaW5kaWNhdGluZyBiZXR0ZXIgbW9kZWwgcGVyZm9ybWFuY2UuIEFuIEFVQyBvZiAwLjUgc3VnZ2VzdHMgdGhhdCB0aGUgbW9kZWwgaXMgbm8gYmV0dGVyIHRoYW4gcmFuZG9tIGd1ZXNzaW5nLCB3aGlsZSBhbiBBVUMgb2YgMSBpbmRpY2F0ZXMgcGVyZmVjdCBjbGFzc2lmaWNhdGlvbi4gSGlnaGVyIEFVQ3MgbWVhbiB0aGF0IHdlIGNhbiBmaW5kIGEgY3V0LW9mZiB2YWx1ZSBmb3Igd2hpY2ggYm90aCBzZW5zaXRpdml0eSBhbmQgc3BlY2lmaWNpdHkgb2YgdGhlIG1vZGVsIGFyZSByZWxhdGl2ZWx5IGhpZ2guIFR5cGljYWxseTogCgotIFwoIFx0ZXh0e0FVQ30gPSAxIFwpOiBQZXJmZWN0IG1vZGVsCi0gXCggXHRleHR7QVVDfSA9IDAuOSBcKTogRXhjZWxsZW50IG1vZGVsCi0gXCggXHRleHR7QVVDfSA9IDAuOCBcKTogR29vZCBtb2RlbAotIFwoIFx0ZXh0e0FVQ30gPSAwLjcgXCk6IEZhaXIgbW9kZWwKLSBcKCBcdGV4dHtBVUN9ID0gMC41IFwpOiBQb29yIG1vZGVsIChyYW5kb20gY2xhc3NpZmllcikKLSBcKCBcdGV4dHtBVUN9IDwgMC41IFwpOiBGYWlsaW5nIG1vZGVsICh3b3JzZSB0aGFuIHJhbmRvbSkKCiMjIExvZ2lzdGljIFJlZ3Jlc3Npb24gQXNzdW1wdGlvbnMKCkxvZ2lzdGljIHJlZ3Jlc3Npb24gc2hhcmVzIHNvbWUgYXNzdW1wdGlvbnMgd2l0aCBPTFMgcmVncmVzc2lvbiwgYnV0IGl0IGFsc28gaGFzIHVuaXF1ZSBhc3N1bXB0aW9ucyB0aGF0IGFjY29tbW9kYXRlIHRoZSBiaW5hcnkgbmF0dXJlIG9mIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUuIEJlbG93LCB3ZSBvdXRsaW5lIHdoaWNoIGFzc3VtcHRpb25zIG9mIE9MUyByZWdyZXNzaW9uIGFsc28gaG9sZCBmb3IgbG9naXN0aWMgcmVncmVzc2lvbiBhbmQgd2hpY2ggZG8gbm90LgoKRmlyc3QsIGp1c3QgbGlrZSBpbiBPTFMgcmVncmVzc2lvbiwgbG9naXN0aWMgcmVncmVzc2lvbiBhc3N1bWVzIHRoYXQgKipvYnNlcnZhdGlvbnMgYXJlIGluZGVwZW5kZW50Kiogb2YgZWFjaCBvdGhlci4gVGhpcyBtZWFucyB0aGF0IGVhY2ggZGF0YSBwb2ludCAob3IgY2FzZSkgc2hvdWxkIG5vdCBpbmZsdWVuY2UgYW5vdGhlci4KClNlY29uZCwgc2ltaWxhciB0byBPTFMgcmVncmVzc2lvbiwgbG9naXN0aWMgcmVncmVzc2lvbiBhc3N1bWVzIHRoYXQgdGhlcmUgaXMgKipubyBwZXJmZWN0IG11bHRpY29sbGluZWFyaXR5KiogYW1vbmcgdGhlIGluZGVwZW5kZW50IHZhcmlhYmxlcy4gUGVyZmVjdCBtdWx0aWNvbGxpbmVhcml0eSBtZWFucyB0aGF0IG9uZSBwcmVkaWN0b3IgaXMgYW4gZXhhY3QgbGluZWFyIGNvbWJpbmF0aW9uIG9mIG90aGVycywgd2hpY2ggY2FuIGxlYWQgdG8gaW5zdGFiaWxpdHkgaW4gdGhlIG1vZGVsIGNvZWZmaWNpZW50cy4KClRoaXJkLCBPTFMgcmVncmVzc2lvbiBhc3N1bWVzICoqaG9tb3NjZWRhc3RpY2l0eSoqLCBtZWFuaW5nIHRoZSByZXNpZHVhbHMgKGVycm9ycykgaGF2ZSBjb25zdGFudCB2YXJpYW5jZSBhY3Jvc3MgYWxsIGxldmVscyBvZiB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGVzLiBJbiBsb2dpc3RpYyByZWdyZXNzaW9uLCB0aGlzIGFzc3VtcHRpb24gZG9lcyBub3QgYXBwbHkgYmVjYXVzZSB0aGUgZXJyb3IgdGVybXMgYXJlIG5vdCBub3JtYWxseSBkaXN0cmlidXRlZDsgaW5zdGVhZCwgdGhleSBmb2xsb3cgYSBiaW5vbWlhbCBkaXN0cmlidXRpb24uCgpGb3VydGgsIGluIE9MUywgd2UgYXNzdW1lIHRoYXQgdGhlIHJlc2lkdWFscyBhcmUgKipub3JtYWxseSBkaXN0cmlidXRlZCoqLiBJbiBsb2dpc3RpYyByZWdyZXNzaW9uLCBob3dldmVyLCB0aGUgZXJyb3JzIGRvIG5vdCBuZWVkIHRvIGZvbGxvdyBhIG5vcm1hbCBkaXN0cmlidXRpb24gYmVjYXVzZSB0aGUgbW9kZWwgdXNlcyBhIGJpbm9taWFsIGRpc3RyaWJ1dGlvbiBpbnN0ZWFkIG9mIG5vcm1hbCBkaXN0cmlidXRpb24gZm9yIHRoZSByZXNwb25zZSB2YXJpYWJsZS4KCkFuZCBsYXN0bHksIGxvZ2lzdGljIHJlZ3Jlc3Npb24gZG9lcyBub3QgYXNzdW1lIGEgKipsaW5lYXIgcmVsYXRpb25zaGlwKiogYmV0d2VlbiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIGFuZCBlYWNoIGluZGVwZW5kZW50IHZhcmlhYmxlLCB1bmxpa2UgT0xTIHJlZ3Jlc3Npb24uIEluc3RlYWQsIGRlcGVuZGVudCB2YXJpYWJsZSBtdXN0IGJlIGJpbmFyeS4gTG9naXN0aWMgcmVncmVzc2lvbiBhc3N1bWVzIHRoYXQgdGhlIGxvZyBvZGRzIG9mIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgYmVpbmcgMSBpcyBsaW5lYXJseSByZWxhdGVkIHRvIGVhY2ggaW5kZXBlbmRlbnQgdmFyaWFibGUuIFRoaXMgaXMgYSB1bmlxdWUgYXNzdW1wdGlvbiBvZiBsb2dpc3RpYyByZWdyZXNzaW9uIHRoYXQgZG9lcyBub3QgYXBwbHkgdG8gT0xTIHJlZ3Jlc3Npb24uCgpBcyBhIHNwZWNpYWwgbm90ZSwgbG9naXN0aWMgcmVncmVzc2lvbiByZXF1aXJlcyBhIHNhbXBsZSBzaXplIG9mIGF0IGxlYXN0IDUwLiBUaGlzIGlzIGJlY2F1c2UgbG9naXN0aWMgcmVncmVzc2lvbiB1c2VzIE1heGltdW0gTGlrZWxpaG9vZCBFc3RpbWF0aW9uIChNTEUpIHRvIGVzdGltYXRlIHJlZ3Jlc3Npb24gY29lZmZpY2llbnRzLCB3aGljaCByZXF1aXJlcyBhIGxhcmdlciBzYW1wbGUgc2l6ZSB0aGFuIE9MUyByZWdyZXNzaW9uLiAKCiMjIEV4cGxvcmF0b3J5IEFuYWx5c2lzIElkZWFzCiAKQmVmb3JlIHJ1bm5pbmcgbG9naXN0aWMgcmVncmVzc2lvbiwgd2UgYWxzbyBuZWVkIHRvIGNvbmR1Y3QgZXhwbG9yYXRvcnkgYW5hbHlzZXMgdG8gdW5kZXJzdGFuZCB0aGUgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgYW5kIHRoZSBwcmVkaWN0b3JzLiAKCkZvciBiaW5hcnkgcHJlZGljdG9ycywgd2UgcnVuIGNyb3NzLXRhYnVsYXRpb25zIHdpdGggdGhlIGRlcGVuZGVudCB2YXJpYWJsZSwgd2hpY2ggaW4gdGhpcyBjYXNlIGlzIFwoIFx0ZXh0e0RSSU5LSU5HX0R9XCkuIFRoaXMgcHJvdmlkZXMgdXMgd2l0aCBjb3VudHMgZm9yIGVhY2ggY29tYmluYXRpb24gb2YgdmFsdWVzIGZvciBcKCBcdGV4dHtEUklOS0lOR19EfVwpIGFuZCBhIGJpbmFyeSBwcmVkaWN0b3IsIGFsbG93aW5nIHVzIHRvIG9ic2VydmUgcG90ZW50aWFsIGFzc29jaWF0aW9ucy4gVGhlICoqQ2hpLVNxdWFyZSB0ZXN0KiogaXMgdGhlIGFwcHJvcHJpYXRlIHN0YXRpc3RpY2FsIHRlc3QgZm9yIGFzc2Vzc2luZyBhc3NvY2lhdGlvbnMgYmV0d2VlbiB0d28gY2F0ZWdvcmljYWwgdmFyaWFibGVzLiBUaGUgbnVsbCBoeXBvdGhlc2lzIFwoIEhfMCBcKSBmb3IgdGhlIENoaS1TcXVhcmUgdGVzdCBpcyB0aGF0OiAKCiQkCkhfMDogXHRleHR7VGhlcmUgaXMgbm8gYXNzb2NpYXRpb24gYmV0d2VlbiB0aGUgYmluYXJ5IHByZWRpY3RvciBhbmQgRFJJTktJTkdfRC59CiQkCgpUaGUgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcyBpcyB0aGF0OiAKCiQkCkhfYTogXHRleHR7VGhlcmUgaXMgYW4gYXNzb2NpYXRpb24gYmV0d2VlbiB0aGUgYmluYXJ5IHByZWRpY3RvciBhbmQgRFJJTktJTkdcX0QufQokJAoKRm9yIGNvbnRpbnVvdXMgcHJlZGljdG9ycywgd2UgY2FsY3VsYXRlIHRoZSBtZWFucyBvZiB0aGUgY29udGludW91cyBwcmVkaWN0b3JzIGZvciBib3RoIHZhbHVlcyBvZiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlLiBXZSBjb21wYXJlIHRoZSBtZWFuIHZhbHVlcyBvZiBcKCBcdGV4dHtQQ1RCQUNITU9SfVwpIGFuZCBcKCBcdGV4dHtNRURISElOQ31cKSBmb3IgY3Jhc2hlcyBpbnZvbHZpbmcgYWxjb2hvbCB2ZXJzdXMgdGhvc2UgdGhhdCBkaWRu4oCZdC4gVGhlICoqaW5kZXBlbmRlbnQgc2FtcGxlcyB0LXRlc3QqKiBpcyB1c2VkIHRvIHRlc3Qgd2hldGhlciB0aGVyZSBpcyBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgaW4gbWVhbiB2YWx1ZXMgb2YgYSBjb250aW51b3VzIHByZWRpY3RvciBiZXR3ZWVuIHR3byBncm91cHMgb2YgYSBiaW5hcnkgb3V0Y29tZS4gIFRoZSBudWxsIGh5cG90aGVzaXMgXCggSF8wIFwpIGZvciB0aGUgdC10ZXN0IGlzIHRoYXQ6IAoKJCQKSF8wOiBcdGV4dHtUaGVyZSBpcyBubyBkaWZmZXJlbmNlIGluIHRoZSBtZWFucyBvZiB0aGUgY29udGludW91cyBwcmVkaWN0b3IgZm9yIGNyYXNoZXMgdGhhdCBpbnZvbHZlZCBhbGNvaG9sIGFuZCB0aG9zZSB0aGF0IGRpZCBub3QufQokJAoKVGhlIGFsdGVybmF0aXZlIGh5cG90aGVzaXMgaXMgdGhhdDogCgokJApIX2E6IFx0ZXh0e1RoZXJlIGlzIGEgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBpbiB0aGUgbWVhbnMgb2YgdGhlIGNvbnRpbnVvdXMgcHJlZGljdG9yIGZvciBjcmFzaGVzIHRoYXQgaW52b2x2ZWQgYWxjb2hvbCBhbmQgdGhvc2UgdGhhdCBkaWQgbm90Ln0KJCQKCgojIFJlc3VsdHMgCgojIyBFeHBsb3JhdG9yeSBBbmFseXNpcwoKV2UgYmVnaW4gb3VyIGFuYWx5c2lzIGJ5IGV4YW1pbmluZyB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUsIFwoIFx0ZXh0e0RSSU5LSU5HX0R9IFwpLiBUaGUgdGFidWxhdGlvbiBzaG93cyB0aGF0IHRoZSBtYWpvcml0eSBvZiBjcmFzaGVzIGRvIG5vdCBpbnZvbHZlIGFsY29ob2wgaW1wYWlybWVudC4gVGhlIHRhYnVsYXRpb24gb2YgdGhlIGRlcGVuZGVudCB2YXJpYWJsZSwgXCggXHRleHR7RFJJTktJTkdfRH0gXCksIHNob3dzIHRoYXQgdGhlIG1ham9yaXR5IG9mIGNyYXNoZXMgZG8gbm90IGludm9sdmUgYWxjb2hvbCBpbXBhaXJtZW50LiBTcGVjaWZpY2FsbHksIDk0LjMlIG9mIGNyYXNoZXMgKHByb3BvcnRpb24gPSAwLjk0MykgYXJlIGNhdGVnb3JpemVkIGFzIG5vdCBpbnZvbHZpbmcgZHJ1bmsgZHJpdmluZywgd2hpbGUgb25seSA1LjclIG9mIGNyYXNoZXMgKHByb3BvcnRpb24gPSAwLjA1NykgaW52b2x2ZSBhIGRydW5rIGRyaXZlci4gVGhpcyBpbmRpY2F0ZXMgdGhhdCBhbGNvaG9sLXJlbGF0ZWQgY3Jhc2hlcyBjb25zdGl0dXRlIGEgcmVsYXRpdmVseSBzbWFsbCBwcm9wb3J0aW9uIG9mIHRoZSBvdmVyYWxsIGNyYXNoIGRhdGEuIFRoZSBza2V3ZWQgZGlzdHJpYnV0aW9uIG9mIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgc3VnZ2VzdHMgdGhhdCBkcnVuayBkcml2aW5nIGluY2lkZW50cyBhcmUgcmVsYXRpdmVseSByYXJlIGNvbXBhcmVkIHRvIG5vbi1hbGNvaG9sLXJlbGF0ZWQgY3Jhc2hlcywgd2hpY2ggaXMgYW4gaW1wb3J0YW50IGNvbnNpZGVyYXRpb24gZm9yIG1vZGVsIHBlcmZvcm1hbmNlIGFuZCBldmFsdWF0aW9uLCBhcyBpdCBtYXkgaW1wYWN0IHRoZSBtb2RlbCdzIGFiaWxpdHkgdG8gYWNjdXJhdGVseSBwcmVkaWN0IGFsY29ob2wgaW52b2x2ZW1lbnQuCgoKYGBge3IgZGVwZWRlbnQgY3Jvc3N0YWJ1bGF0aW9uLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKZGVwZXRhYiA8LSBwcm9wLnRhYmxlKHRhYmxlKGNyYXNoZXMkRFJJTktJTkdfRCkpCmRlcHRhYiA8LSBhcy5kYXRhLmZyYW1lKGRlcGV0YWIpCmNvbG5hbWVzKGRlcHRhYikgPC0gYygiRFJJTktJTkdfRCIsICJQcm9wb3J0aW9uIikKZGVwdGFiICU+JSAKICBrYWJsZSgiaHRtbCIsIGVzY2FwZSA9IEZBTFNFLCBhbGlnbiA9ICJjYyIpICU+JQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFLCBwb3NpdGlvbiA9ICJjZW50ZXIiLCBmaXhlZF90aGVhZCA9IFRSVUUpCgpgYGAKCgpUaGUgdGFibGUgYmVsb3cgcHJvdmlkZXMgYSBjcm9zcy10YWJ1bGF0aW9uIG9mIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgd2l0aCBlYWNoIG9mIHRoZSBiaW5hcnkgcHJlZGljdG9ycy4gSXQgc2hvd3MgdGhhdCBhbW9uZyBjcmFzaGVzIHdpdGhvdXQgYWxjb2hvbCBpbnZvbHZlbWVudCwgMi44OSUgcmVzdWx0ZWQgaW4gZmF0YWxpdHkgb3IgbWFqb3IgaW5qdXJ5LiBZZXQsIHRoZSBwZXJjZW50YWdlIGlzIGhpZ2hlciBhdCA3LjU3JSB3aGVuIGFsY29ob2wgaXMgaW52b2x2ZWQuIFdoaWxlIDEuNTAlIG9mIG5vbi1hbGNvaG9sLXJlbGF0ZWQgY3Jhc2hlcyBpbnZvbHZlZCBhbiBvdmVydHVybmVkIHZlaGljbGUsIDQuNDMlIG9mIGFsY29ob2wtcmVsYXRlZCBjcmFzaGVzIGRpZC4gU3BlZWRpbmcgaXMgaW52b2x2ZWQgaW4gMy4wOCUgb2Ygbm9uLWFsY29ob2wtcmVsYXRlZCBjcmFzaGVzIGFuZCAxMC40NiUgb2YgYWxjb2hvbC1yZWxhdGVkIGNyYXNoZXMuIFNpbWlsYXJseSwgYWdncmVzc2l2ZSBkcml2aW5nIGlzIG1vcmUgY29tbW9uIGluIGFsY29ob2wtcmVsYXRlZCBjcmFzaGVzICgzNi44NiUpIHRoYW4gaW4gbm9uLWFsY29ob2wtcmVsYXRlZCBjcmFzaGVzICg0NS4zMSUpLiBBcyBmb3IgZHJpdmluZyBhZ2UsIDEuNjUlIG9mIG5vbi1hbGNvaG9sLXJlbGF0ZWQgY3Jhc2hlcyBpbnZvbHZlIHZlcnkgeW91bmcgZHJpdmVycywgd2hpbGUgdGhpcyBkcm9wcyB0byAwLjQ4JSBpbiBhbGNvaG9sLXJlbGF0ZWQgY3Jhc2hlcy4gMTAuMzclIG9mIG5vbi1hbGNvaG9sLXJlbGF0ZWQgY3Jhc2hlcyBpbnZvbHZlIG9sZGVyIGRyaXZlcnMsIGNvbXBhcmVkIHRvIDQuNzklIG9mIGFsY29ob2wtcmVsYXRlZCBjcmFzaGVzLiBIb3dldmVyLCBjZWxsIHBob25lIHVzZSBpcyBzaW1pbGFyIGFjcm9zcyBib3RoIGFsY29ob2wtaW52b2x2ZWQgYW5kIG5vbi1hbGNvaG9sLWludm9sdmVkIGNyYXNoZXMuIAoKCmBgYHtyIGNyb3NzdGFidWxhdGlvbiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1UUlVFLCByZXN1bHRzPSdoaWRlJ30KCmV4dHJhY3RfY3Jvc3N0YWJfdmFsdWVzIDwtIGZ1bmN0aW9uKHZhcjEsIHZhcjIpIHsKCiAgY3Jvc3N0YWIgPC0gQ3Jvc3NUYWJsZSh2YXIxLCB2YXIyLCBwcm9wLnIgPSBGQUxTRSwgcHJvcC5jaGlzcSA9IEZBTFNFLCBjaGlzcSA9IEZBTFNFLCBwcm9wLnQgPSBGQUxTRSkKICAKICB2YWx1ZV8xIDwtIGNyb3NzdGFiJHRbIjEiLCAiMSJdICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIENvdW50IHdoZXJlIERSSU5LSU5HX0QgPSAxLCBvdGhlciB2YXJpYWJsZSA9IDEKICB2YWx1ZV8yIDwtIChjcm9zc3RhYiR0WyIxIiwgIjEiXSAvIHN1bShjcm9zc3RhYiR0WyIxIixdKSkgKiAxMDAgICAjIFBjdCB3aGVyZSBEUklOS0lOR19EID0gMSwgb3RoZXIgdmFyaWFibGUgPSAxCiAgdmFsdWVfMyA8LSBjcm9zc3RhYiR0WyIwIiwgIjEiXSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBDb3VudCB3aGVyZSBEUklOS0lOR19EID0gMCwgb3RoZXIgdmFyaWFibGUgPSAxCiAgdmFsdWVfNCA8LSAoY3Jvc3N0YWIkdFsiMCIsICIxIl0gLyBzdW0oY3Jvc3N0YWIkdFsiMCIsXSkpICogMTAwICAgIyBQY3Qgd2hlcmUgRFJJTktJTkdfRCA9IDAsIG90aGVyIHZhcmlhYmxlID0gMQogIHZhbHVlXzUgPC0gY3Jvc3N0YWIkdFsiMSIsICIxIl0gKyBjcm9zc3RhYiR0WyIwIiwgIjEiXSAgICAgICAgICAgICMgVG90YWwgY291bnQgd2hlcmUgb3RoZXIgdmFyaWFibGUgPSAxCgogIHJldHVybihjKFZhbHVlMSA9IHZhbHVlXzEsIFZhbHVlMiA9IHZhbHVlXzIsIFZhbHVlMyA9IHZhbHVlXzMsIFZhbHVlNCA9IHZhbHVlXzQsIFZhbHVlNSA9IHZhbHVlXzUpKQp9Cgp0YWJ1bGF0aW9uIDwtIGRhdGEuZnJhbWUoCiAgVmFyaWFibGUgPSBjaGFyYWN0ZXIoKSwKICBWYWx1ZTEgPSBudW1lcmljKCksCiAgVmFsdWUyID0gbnVtZXJpYygpLAogIFZhbHVlMyA9IG51bWVyaWMoKSwKICBWYWx1ZTQgPSBudW1lcmljKCksCiAgVmFsdWU1ID0gbnVtZXJpYygpCikKCmRlc2NyaXB0aW9ucyA8LSBjKAogIEZBVEFMX09SX00gPSAiQ3Jhc2ggcmVzdWx0ZWQgaW4gZmF0YWxpdHkgb3IgbWFqb3IgaW5qdXJ5IiwKICBPVkVSVFVSTkVEID0gIkNyYXNoIGludm9sdmVkIGFuIG92ZXJ0dXJuZWQgdmVoaWNsZSIsCiAgQ0VMTF9QSE9ORSA9ICJEcml2ZXIgd2FzIHVzaW5nIGNlbGwgcGhvbmUiLAogIFNQRUVESU5HID0gIkNyYXNoIGludm9sdmVkIHNwZWVkaW5nIGNhciIsCiAgQUdHUkVTU0lWRSA9ICJDcmFzaCBpbnZvbHZlZCBhZ2dyZXNzaXZlIGRyaXZpbmciLAogIERSSVZFUjE2MTcgPSAiQ3Jhc2ggaW52b2x2ZWQgYXQgbGVhc3Qgb25lIGRyaXZlciAxNiBvciAxNyB5ZWFycyBvbGQiLAogIERSSVZFUjY1UExVUyA9ICJDcmFzaCBpbnZvbHZlZCBhdCBsZWFzdCBvbmUgZHJpdmVyIG92ZXIgNjUgeWVhcnMgb2xkIgopCgp2YXJpYWJsZXMgPC0gYygiRkFUQUxfT1JfTSIsICJPVkVSVFVSTkVEIiwgIkNFTExfUEhPTkUiLCAiU1BFRURJTkciLCAiQUdHUkVTU0lWRSIsICJEUklWRVIxNjE3IiwgIkRSSVZFUjY1UExVUyIpCgpmb3IgKHZhciBpbiB2YXJpYWJsZXMpIHsKICB2YWx1ZXMgPC0gZXh0cmFjdF9jcm9zc3RhYl92YWx1ZXMoY3Jhc2hlcyREUklOS0lOR19ELCBjcmFzaGVzW1t2YXJdXSkKICAKICB0YWJ1bGF0aW9uIDwtIHJiaW5kKAogICAgdGFidWxhdGlvbiwKICAgIGRhdGEuZnJhbWUoVmFyaWFibGUgPSBwYXN0ZTAodmFyLCAiOiAiLCBkZXNjcmlwdGlvbnNbW3Zhcl1dKSwgdCh2YWx1ZXMpKQogICkKfQoKY29sbmFtZXModGFidWxhdGlvbikgPC0gYygiIiwgIk4iLCAiJSIsICJOICIsICIlICIsICJOICAiKQoKYGBgCgoKYGBge3IgdGFidWxhdGlvbiB0YWJsZSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCnRhYnVsYXRpb24gJT4lCiAga2FibGUoImh0bWwiLCBlc2NhcGUgPSBGQUxTRSwgYWxpZ24gPSAibGNjY2NjIikgJT4lCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRkFMU0UsIHBvc2l0aW9uID0gImNlbnRlciIsIGZpeGVkX3RoZWFkID0gVFJVRSkgJT4lCiAgY29sdW1uX3NwZWMoMSwgd2lkdGggPSAiMzBlbSIpICU+JSAgICAKICBjb2x1bW5fc3BlYygyLCB3aWR0aCA9ICI1ZW0iKSAlPiUKICBjb2x1bW5fc3BlYygzLCB3aWR0aCA9ICI1ZW0iKSAlPiUKICBjb2x1bW5fc3BlYyg0LCB3aWR0aCA9ICI1ZW0iKSAlPiUKICBjb2x1bW5fc3BlYyg1LCB3aWR0aCA9ICI1ZW0iKSAlPiUKICBjb2x1bW5fc3BlYyg2LCB3aWR0aCA9ICI1ZW0iKSAlPiUKICBhZGRfaGVhZGVyX2Fib3ZlKGMoIiAiID0gMSwgIkRSSU5LSU5HX0QgPSAxIiA9IDIsICJEUklOS0lOR19EID0gMCIgPSAyLCAiICIgPSAxKSkgJT4lIAogIGFkZF9oZWFkZXJfYWJvdmUoYygiICIgPSAxLCAiQWxjb2hvbCBJbnZvbHZlZCIgPSAyLCAiTm8gQWxjb2hvbCIgPSAyLCAiVG90YWwiID0gMSkpCgpgYGAKClRoZSByZXN1bHRzIG9mIHRoZSBDaGktU3F1YXJlIHRlc3QgaW5kaWNhdGUgc2lnbmlmaWNhbnQgYXNzb2NpYXRpb25zIGJldHdlZW4gbW9zdCBvZiB0aGUgYmluYXJ5IHByZWRpY3RvcnMgYW5kIGFsY29ob2wgaW52b2x2ZW1lbnQgaW4gY3Jhc2hlcywgd2l0aCB0aGUgZXhjZXB0aW9uIG9mIFwoIFx0ZXh0e0NFTExfUEhPTkV9IFwpLiBGb3IgZXhhbXBsZSwgXCggXHRleHR7RkFUQUxfT1JfTX0gXCkKc2hvd2VkIGEgaGlnaGx5IHNpZ25pZmljYW50IGFzc29jaWF0aW9uLCB3aXRoIGEgQ2hpLVNxdWFyZSBzdGF0aXN0aWMgb2YgMTY3LjU2IGFuZCBhIGhpZ2hseSBzaWduaWZpY2FudCBcKHAgPCAwLjAwMDFcKSwgc3VnZ2VzdGluZyB0aGF0IHNldmVyZSBjcmFzaGVzIGFyZSBtb3JlIGxpa2VseSB0byBpbnZvbHZlIGFsY29ob2wuIExpa2V3aXNlLCBcKCBcdGV4dHtPVkVSVFVSTkVEfSBcKSBhbHNvIGhhZCBhIHNpZ25pZmljYW50IGFzc29jaWF0aW9uIChDaGktU3F1YXJlID0gMTIyLjc5LCBkZiA9MSkgd2l0aCBcKHAgPCAwLjAwMDFcKSwgaW5kaWNhdGluZyB0aGF0IG92ZXJ0dXJuZWQgdmVoaWNsZXMgYXJlIG1vcmUgZnJlcXVlbnRseSBhc3NvY2lhdGVkIHdpdGggYWxjb2hvbCBpbXBhaXJtZW50LiBUaGUgcmVtYWluaW5nIHByZWRpY3RvcnMsIFwoIFx0ZXh0e1NQRUVESU5HfSBcKSwgXCggXHRleHR7QUdHUkVTU0lWRX0gXCksIFwoIFx0ZXh0e0RSSVZFUjE2MTd9IFwpLCBhbmQgXChcdGV4dHtEUklWRVI2NVBMVVN9IFwpIGFsc28gc2hvd2VkIHNpZ25pZmljYW50IGFzc29jaWF0aW9ucyB3aXRoIGFsY29ob2wgaW52b2x2ZW1lbnQsIHdpdGggQ2hpLVNxdWFyZSBzdGF0aXN0aWNzIHJhbmdpbmcgZnJvbSAyMC40NSB0byAzNzYuNzggYW5kIFwocCA8IDAuMDAwMVwpLiBUaGVzZSByZXN1bHRzIHN1Z2dlc3QgdGhhdCBjcmFzaGVzIGludm9sdmluZyBmYXRhbGl0aWVzLCBvdmVydHVybmVkIHZlaGljbGVzLCBzcGVlZGluZywgYWdncmVzc2l2ZSBkcml2aW5nLCBhbmQgY2VydGFpbiBkcml2ZXIgYWdlIGdyb3VwcyBhcmUgbW9yZSBsaWtlbHkgdG8gaW52b2x2ZSBhbGNvaG9sIGltcGFpcm1lbnQuIFRoZXJlZm9yZSwgd2UgY291bGQgcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgZm9yIHRoZXNlIHByZWRpY3RvcnMgYW5kIGNvbmNsdWRlIHRoYXQgdGhleSBhcmUgc2lnbmlmaWNhbnRseSBhc3NvY2lhdGVkIHdpdGggYWxjb2hvbCBpbnZvbHZlbWVudCBpbiBjcmFzaGVzLgoKSG93ZXZlciwgdGhlIHByZWRpY3RvciBcKCBcdGV4dHtDRUxMX1BIT05FfSBcKSBkaWQgbm90IHNob3cgYSBzaWduaWZpY2FudCBhc3NvY2lhdGlvbiB3aXRoIGFsY29ob2wgaW52b2x2ZW1lbnQsIHdpdGggYSBDaGktU3F1YXJlIHN0YXRpc3RpYyBvZiAwLjE2IGFuZCBcKHAgPiAwLjVcKS4gVGhpcyBzdWdnZXN0cyB0aGF0IGNlbGwgcGhvbmUgdXNlIGlzIG5vdCBzdHJvbmdseSBhc3NvY2lhdGVkIHdpdGggYWxjb2hvbC1yZWxhdGVkIGNyYXNoZXMgaW4gdGhpcyBkYXRhc2V0LiBXZSBjYW4gcmV0YWluIHRoZSBudWxsIGh5cG90aGVzaXMgZm9yIHRoaXMgcHJlZGljdG9yIGFuZCBjb25jbHVkZSB0aGF0IHRoZXJlIGlzIG5vIHNpZ25pZmljYW50IGFzc29jaWF0aW9uIGJldHdlZW4gY2VsbCBwaG9uZSB1c2UgYW5kIGFsY29ob2wgaW52b2x2ZW1lbnQgaW4gY3Jhc2hlcy4KCgpgYGB7ciB0YWJ1bGF0aW9uIHRhYmxlIGNoaS1zcSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCnRhYnVsYXRpb24kQ2hpX3NxdWFyZWQgPC0gTkEgIAp0YWJ1bGF0aW9uJHBfdmFsdWUgPC0gTkEKCmZvciAoaSBpbiBzZXFfYWxvbmcodmFyaWFibGVzKSkgewogIHZhciA8LSB2YXJpYWJsZXNbaV0KICBjaGlfdGVzdCA8LSBjaGlzcS50ZXN0KHRhYmxlKGNyYXNoZXMkRFJJTktJTkdfRCwgY3Jhc2hlc1tbdmFyXV0pLCBjb3JyZWN0ID0gRkFMU0UpCiAgdGFidWxhdGlvbiRDaGlfc3F1YXJlZFtpXSA8LSByb3VuZChjaGlfdGVzdCRzdGF0aXN0aWMsIDIpCiAgdGFidWxhdGlvbiRwX3ZhbHVlW2ldIDwtIHJvdW5kKGNoaV90ZXN0JHAudmFsdWUsIDUpCn0KCnRhYnVsYXRpb24gJT4lCiAga2FibGUoImh0bWwiLCBlc2NhcGUgPSBGQUxTRSwgYWxpZ24gPSAibGNjY2NjYyIpICU+JQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFLCBwb3NpdGlvbiA9ICJjZW50ZXIiLCBmaXhlZF90aGVhZCA9IFRSVUUpICU+JQogIGNvbHVtbl9zcGVjKDEsIHdpZHRoID0gIjUwZW0iKSAlPiUKICBjb2x1bW5fc3BlYygyLCB3aWR0aCA9ICI1ZW0iKSAlPiUKICBjb2x1bW5fc3BlYygzLCB3aWR0aCA9ICI1ZW0iKSAlPiUKICBjb2x1bW5fc3BlYyg0LCB3aWR0aCA9ICI1ZW0iKSAlPiUKICBjb2x1bW5fc3BlYyg1LCB3aWR0aCA9ICI1ZW0iKSAlPiUKICBjb2x1bW5fc3BlYyg2LCB3aWR0aCA9ICI1ZW0iKSAlPiUKICBjb2x1bW5fc3BlYyg3LCB3aWR0aCA9ICI1ZW0iKSAlPiUKICBjb2x1bW5fc3BlYyg4LCB3aWR0aCA9ICI1ZW0iKSAlPiUKICBhZGRfaGVhZGVyX2Fib3ZlKGMoIiAiID0gMSwgIkRSSU5LSU5HX0QgPSAwIiA9IDIsICJEUklOS0lOR19EID0gMSIgPSAyLCAiICIgPSAxLCAiICIgPSAyKSkgJT4lIAogIGFkZF9oZWFkZXJfYWJvdmUoYygiICIgPSAxLCAiTm8gQWxjb2hvbCIgPSAyLCAiQWxjb2hvbCBJbnZvbHZlZCIgPSAyLCAiVG90YWwiID0gMSwgIs+HMiBUZXN0IiA9IDIpKQpgYGAKCgpXZSBhbHNvIGxvb2tlZCBhdCB0aGUgbWVhbiBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIHRoZSBjb250aW51b3VzIHByZWRpY3RvcnMsIFwoIFx0ZXh0e1BDVEJBQ0hNT1J9IFwpIGFuZCBcKCBcdGV4dHtNRURISElOQ30gXCksIGZvciBjcmFzaGVzIGludm9sdmluZyBhbmQgbm90IGludm9sdmluZyBhbGNvaG9sLiBUaGUgbWVhbiBwZXJjZW50YWdlIG9mIHBlb3BsZSB3aXRoIGEgYmFjaGVsb3LigJlzIGRlZ3JlZSBvciBtb3JlIGlzIGlkZW50aWNhbCBmb3IgYm90aCBub24tYWxjb2hvbCBhbmQgYWxjb2hvbC1pbnZvbHZlZCBjcmFzaGVzLCBhdCAxNi42JS4gVGhlIHN0YW5kYXJkIGRldmlhdGlvbiBpcyBzbGlnaHRseSBoaWdoZXIgaW4gdGhlIGFsY29ob2wtaW52b2x2ZWQgZ3JvdXAgKDE4LjcgdnMuIDE4LjIpLiBUaGlzIHN1Z2dlc3RzIHRoYXQgZWR1Y2F0aW9uYWwgYXR0YWlubWVudCwgYXMgbWVhc3VyZWQgYnkgdGhlIHBlcmNlbnRhZ2Ugb2YgaW5kaXZpZHVhbHMgd2l0aCBhIGJhY2hlbG9y4oCZcyBkZWdyZWUgb3IgbW9yZSwgZG9lcyBub3QgdmFyeSBzaWduaWZpY2FudGx5IGJldHdlZW4gYXJlYXMgd2hlcmUgY3Jhc2hlcyBpbnZvbHZlIGFsY29ob2wgYW5kIHRob3NlIHdoZXJlIHRoZXkgZG8gbm90LlRoZSBtZWRpYW4gaG91c2Vob2xkIGluY29tZSBpcyBzbGlnaHRseSBoaWdoZXIgaW4gYWxjb2hvbC1pbnZvbHZlZCBjcmFzaGVzIHdpdGggYSBtZWFuIG9mIFwkMzEsOTk4LjgsIGNvbXBhcmVkIHRvIFwkMzEsNDgzLjEgaW4gbm9uLWFsY29ob2wtcmVsYXRlZCBjcmFzaGVzLiBUaGUgc3RhbmRhcmQgZGV2aWF0aW9uIGlzIGFsc28gaGlnaGVyIGZvciB0aGUgYWxjb2hvbC1pbnZvbHZlZCBncm91cCAoMTcsODEwLjUgdnMuIDE2LDkzMC4xKS4gVGhpcyBhbHNvIG1lYW5zIHRoYXQgaW5jb21lIGxldmVsIG1heSBub3QgYmUgYSBzdHJvbmcgZGlmZmVyZW50aWF0b3IgZm9yIGFsY29ob2wgaW52b2x2ZW1lbnQgaW4gY3Jhc2hlcy4KCgoKYGBge3IgdGFidWxhdGlvbiBjb250LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKbWVhbl9wY3RiYWNobW9yIDwtIHRhcHBseShjcmFzaGVzJFBDVEJBQ0hNT1IsIGNyYXNoZXMkRFJJTktJTkdfRCwgbWVhbikKc2RfcGN0YmFjaG1vciA8LSB0YXBwbHkoY3Jhc2hlcyRQQ1RCQUNITU9SLCBjcmFzaGVzJERSSU5LSU5HX0QsIHNkKQptZWFuX21lZGhoaW5jIDwtIHRhcHBseShjcmFzaGVzJE1FREhISU5DLCBjcmFzaGVzJERSSU5LSU5HX0QsIG1lYW4pCnNkX21lZGhoaW5jIDwtIHRhcHBseShjcmFzaGVzJE1FREhISU5DLCBjcmFzaGVzJERSSU5LSU5HX0QsIHNkKQoKdGFidWxhdGlvbl9jb250IDwtIGRhdGEuZnJhbWUoCiAgVmFyaWFibGUgPSBjKCJQQ1RCQUNITU9SOiAlIHdpdGggYmFjaGVsb3LigJlzIGRlZ3JlZSBvciBtb3JlIiwgIk1FREhISU5DOiBNZWRpYW4gaG91c2Vob2xkIGluY29tZSIpLAogIFZhbHVlMSA9IGMobWVhbl9wY3RiYWNobW9yWyIwIl0sIG1lYW5fbWVkaGhpbmNbIjAiXSksICAjIE1lYW4gZm9yIERSSU5LSU5HX0QgPSAwCiAgVmFsdWUyID0gYyhzZF9wY3RiYWNobW9yWyIwIl0sIHNkX21lZGhoaW5jWyIwIl0pLCAgICAgICAjIFNEIGZvciBEUklOS0lOR19EID0gMAogIFZhbHVlMyA9IGMobWVhbl9wY3RiYWNobW9yWyIxIl0sIG1lYW5fbWVkaGhpbmNbIjEiXSksICAjIE1lYW4gZm9yIERSSU5LSU5HX0QgPSAxCiAgVmFsdWU0ID0gYyhzZF9wY3RiYWNobW9yWyIxIl0sIHNkX21lZGhoaW5jWyIxIl0pICAgICAgICAjIFNEIGZvciBEUklOS0lOR19EID0gMQopCgpjb2xuYW1lcyh0YWJ1bGF0aW9uX2NvbnQpIDwtIGMoIiIsICJNZWFuIiwgIlNEIiwgIk1lYW4gIiwgIlNEICIpCgp0YWJ1bGF0aW9uX2NvbnQgJT4lCiAga2FibGUoImh0bWwiLCBlc2NhcGUgPSBGQUxTRSwgYWxpZ24gPSAibGNjY2NjYyIpICU+JQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFLCBwb3NpdGlvbiA9ICJjZW50ZXIiLCBmaXhlZF90aGVhZCA9IFRSVUUpICU+JQogIGFkZF9oZWFkZXJfYWJvdmUoYygiICIgPSAxLCAiRFJJTktJTkdfRCA9IDAiID0gMiwgIkRSSU5LSU5HX0QgPSAxIiA9IDIpKSAlPiUgCiAgYWRkX2hlYWRlcl9hYm92ZShjKCIgIiA9IDEsICJObyBBbGNvaG9sIiA9IDIsICJBbGNvaG9sIEludm9sdmVkIiA9IDIpKQpgYGAKClRoZSBpbmRlcGVuZGVudCBzYW1wbGVzIHQtdGVzdCByZXN1bHRzIGZvciB0aGUgY29udGludW91cyBwcmVkaWN0b3JzIHByb3ZpZGUgbW9yZSBpbnNpZ2h0IGludG8gd2hldGhlciB0aGVzZSBzb2Npby1lY29ub21pYyBmYWN0b3JzIGFyZSBzaWduaWZpY2FudGx5IGFzc29jaWF0ZWQgd2l0aCBhbGNvaG9sIGludm9sdmVtZW50IGluIGNyYXNoZXMuCgpGb3IgXCggXHRleHR7UENUQkFDSE1PUn0gXCksIHRoZSB0LXRlc3QgeWllbGRzIGEgcC12YWx1ZSBvZiAwLjkxNCwgd2hpY2ggaXMgZmFyIGdyZWF0ZXIgdGhhbiB0aGUgY29udmVudGlvbmFsIHNpZ25pZmljYW5jZSBsZXZlbCBvZiAwLjA1LiBUaGlzIGluZGljYXRlcyB0aGF0IHRoZXJlIGlzIG5vIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBpbiB0aGUgbWVhbiBlZHVjYXRpb25hbCBhdHRhaW5tZW50IGJldHdlZW4gY3Jhc2hlcyBpbnZvbHZpbmcgYWxjb2hvbCBhbmQgdGhvc2UgdGhhdCBkbyBub3QuIFRoZXJlZm9yZSwgd2UgZmFpbCB0byByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcywgc3VnZ2VzdGluZyB0aGF0IGVkdWNhdGlvbmFsIGF0dGFpbm1lbnQgZG9lcyBub3QgaGF2ZSBhIHNpZ25pZmljYW50IGFzc29jaWF0aW9uIHdpdGggYWxjb2hvbCBpbnZvbHZlbWVudCBpbiBjcmFzaGVzLgoKU2ltaWxhcmx5LCBmb3IgXCggXHRleHR7TUVESEhJTkN9IFwpLCB0aGUgdC10ZXN0IHByb2R1Y2VzIGEgcC12YWx1ZSBvZiAwLjE2MCwgd2hpY2ggYWxzbyBleGNlZWRzIHRoZSAwLjA1IHRocmVzaG9sZC4gQWx0aG91Z2ggdGhlcmUgaXMgYSBzbWFsbCBkaWZmZXJlbmNlIGluIG1lYW4gaW5jb21lIGJldHdlZW4gdGhlIHR3byBncm91cHMsIHRoaXMgZGlmZmVyZW5jZSBpcyBub3Qgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudC4gQ29uc2VxdWVudGx5LCB3ZSBhZ2FpbiBmYWlsIHRvIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzLCBpbXBseWluZyB0aGF0IG1lZGlhbiBob3VzZWhvbGQgaW5jb21lIGlzIG5vdCBzaWduaWZpY2FudGx5IGFzc29jaWF0ZWQgd2l0aCBhbGNvaG9sIGludm9sdmVtZW50IGluIGNyYXNoZXMuCgpBcyBzdWNoLCB0aGUgdC10ZXN0IHJlc3VsdHMgZGVtb25zdHJhdGUgdGhhdCBuZWl0aGVyIFwoIFx0ZXh0e1BDVEJBQ0hNT1J9IFwpIG5vciBcKCBcdGV4dHtNRURISElOQ30gXCkgc2hvd3MgYSBzaWduaWZpY2FudCBhc3NvY2lhdGlvbiB3aXRoIGFsY29ob2wgaW52b2x2ZW1lbnQgaW4gY3Jhc2hlcy4gVGh1cywgd2UgY2Fubm90IGNvbmNsdWRlIHRoYXQgc29jaW8tZWNvbm9taWMgZmFjdG9ycywgYXMgbWVhc3VyZWQgYnkgZWR1Y2F0aW9uYWwgYXR0YWlubWVudCBhbmQgaW5jb21lIGxldmVscywgaGF2ZSBhIG1lYW5pbmdmdWwgaW1wYWN0IG9uIHRoZSBsaWtlbGlob29kIG9mIGFsY29ob2wgaW52b2x2ZW1lbnQgaW4gdHJhZmZpYyBpbmNpZGVudHMuIFRoaXMgbGFjayBvZiBzaWduaWZpY2FuY2Ugc3VnZ2VzdHMgdGhhdCBvdGhlciB2YXJpYWJsZXMsIHN1Y2ggYXMgZHJpdmVyIGJlaGF2aW9yIG9yIGNyYXNoLXNwZWNpZmljIGNoYXJhY3RlcmlzdGljcywgbWF5IGJlIG1vcmUgcmVsZXZhbnQgaW4gdW5kZXJzdGFuZGluZyBhbGNvaG9sLXJlbGF0ZWQgY3Jhc2hlcy4KCmBgYHtyIHRhYnVsYXRpb24gY29udCB0LXRlc3QsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpwdmFsX3BjdGJhY2htb3IgPC0gdC50ZXN0KGNyYXNoZXMkUENUQkFDSE1PUiB+IGNyYXNoZXMkRFJJTktJTkdfRCkkcC52YWx1ZQpwdmFsX21lZGhoaW5jIDwtIHQudGVzdChjcmFzaGVzJE1FREhISU5DIH4gY3Jhc2hlcyREUklOS0lOR19EKSRwLnZhbHVlCnRhYnVsYXRpb25fY29udCRgdC10ZXN0IHAtdmFsdWVgIDwtIGMocHZhbF9wY3RiYWNobW9yLCBwdmFsX21lZGhoaW5jKSAgCgp0YWJ1bGF0aW9uX2NvbnQgJT4lCiAga2FibGUoImh0bWwiLCBlc2NhcGUgPSBGQUxTRSwgYWxpZ24gPSAibGNjY2NjYyIpICU+JQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFLCBwb3NpdGlvbiA9ICJjZW50ZXIiLCBmaXhlZF90aGVhZCA9IFRSVUUpICU+JQogIGFkZF9oZWFkZXJfYWJvdmUoYygiICIgPSAxLCAiRFJJTktJTkdfRCA9IDAiID0gMiwgIkRSSU5LSU5HX0QgPSAxIiA9IDIsICIgIiA9ICAxKSkgJT4lIAogIGFkZF9oZWFkZXJfYWJvdmUoYygiICIgPSAxLCAiTm8gQWxjb2hvbCIgPSAyLCAiQWxjb2hvbCBJbnZvbHZlZCIgPSAyLCAiICIgPSAxKSkKYGBgCgojIyBSZWdyZXNzaW9uIEFzc3VtcHRpb25zCgpCYXNlZCBvbiB0aGUgY29ycmVsYXRpb24gbWF0cml4IGFuZCBwcmlvciBpbmZvcm1hdGlvbiwgbW9zdCBsb2dpc3RpYyByZWdyZXNzaW9uIGFzc3VtcHRpb25zIGZvciBhbmFseXppbmcgZHJ1bmsgZHJpdmluZyBjcmFzaGVzIGFyZSBtZXQuIFRoZSBiaW5hcnkgb3V0Y29tZSB2YXJpYWJsZSwgXCggXHRleHR7RFJJTktJTkdfRH0gXCksIGZ1bGZpbGxzIHRoZSByZXF1aXJlbWVudCBmb3IgYSBiaW5hcnkgZGVwZW5kZW50IHZhcmlhYmxlLCBhbmQgdGhlIGluZGVwZW5kZW5jZSBvZiBvYnNlcnZhdGlvbnMgaXMgbGFyZ2VseSBzYXRpc2ZpZWQsIGFzIGVhY2ggY3Jhc2ggaXMgY29uc2lkZXJlZCBhIHNlcGFyYXRlIGV2ZW50LiBUaGUgYXNzdW1wdGlvbiBvZiBubyBwZXJmZWN0IG11bHRpY29sbGluZWFyaXR5IGlzIGFsc28gbWV0LCBhcyB0aGUgY29ycmVsYXRpb24gbWF0cml4IHNob3dzIGxvdyBwYWlyd2lzZSBjb3JyZWxhdGlvbnMgYmV0d2VlbiBwcmVkaWN0b3IgdmFyaWFibGVzLCB3aXRoIHRoZSBoaWdoZXN0IGJlaW5nIDAuNDggYmV0d2VlbiAqKiUgd2l0aCBCYWNoZWxvcuKAmXMgRGVncmVlKiogYW5kICoqTWVkaWFuIEhvdXNlaG9sZCBJbmNvbWUqKiwgYW5kIGEgbWlsZCBjb3JyZWxhdGlvbiAoMC4yMSkgYmV0d2VlbiAqKkNyYXNoIEludm9sdmVkIFNwZWVkaW5nIENhcioqIGFuZCAqKkNyYXNoIEludm9sdmVkIEFnZ3Jlc3NpdmUgRHJpdmluZyoqLiBUaGVzZSBjb3JyZWxhdGlvbnMgYXJlIG5vdCBoaWdoIGVub3VnaCB0byBjYXVzZSBpbnN0YWJpbGl0eSBpbiB0aGUgbW9kZWwuIEFkZGl0aW9uYWxseSwgdGhlIGxhcmdlIHNhbXBsZSBzaXplIG9mIG92ZXIgNDMsMDAwIG9ic2VydmF0aW9ucyBlbnN1cmVzIHN0YWJsZSBlc3RpbWF0ZXMsIG1lZXRpbmcgdGhlIGFzc3VtcHRpb24gZm9yIHN1ZmZpY2llbnQgc2FtcGxlIHNpemUuIEhvd2V2ZXIsIHRoZXJlIGlzIGEgcG90ZW50aWFsIHZpb2xhdGlvbiBpbiB0aGUgYXNzdW1wdGlvbiBvZiBsaW5lYXJpdHkgb2YgbG9nIG9kZHMgZm9yIGNvbnRpbnVvdXMgcHJlZGljdG9ycywgYXMgaGlnaCBwLXZhbHVlcyBpbiB0LXRlc3RzIHN1Z2dlc3Qgd2VhayBvciBub24tbGluZWFyIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiAqKiUgd2l0aCBCYWNoZWxvcuKAmXMgRGVncmVlKiogYW5kICoqTWVkaWFuIEhvdXNlaG9sZCBJbmNvbWUqKiBhbmQgdGhlIG91dGNvbWUgdmFyaWFibGUuIAoKVXNpbmcgUGVhcnNvbiBjb3JyZWxhdGlvbnMgdG8gbWVhc3VyZSBhc3NvY2lhdGlvbnMgYmV0d2VlbiBiaW5hcnkgcHJlZGljdG9ycyBjYW4gaGF2ZSBsaW1pdGF0aW9ucywgYXMgUGVhcnNvbuKAmXMgY29ycmVsYXRpb24gY29lZmZpY2llbnQgaXMgbW9zdCBhcHByb3ByaWF0ZSBmb3IgY29udGludW91cywgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgZGF0YS4gQmluYXJ5IHZhcmlhYmxlcywgd2hpY2ggb25seSB0YWtlIG9uIHR3byB2YWx1ZXMgKGUuZy4sIDAgYW5kIDEpLCBjYW4gbGVhZCB0byBsZXNzIG1lYW5pbmdmdWwgb3IgaW50ZXJwcmV0YWJsZSBjb3JyZWxhdGlvbiB2YWx1ZXMsIGFzIHRoZSBtZWFzdXJlIGRvZXMgbm90IGZ1bGx5IGNhcHR1cmUgdGhlIHBvdGVudGlhbCBhc3NvY2lhdGlvbiBiZXR3ZWVuIHR3byBiaW5hcnkgdmFyaWFibGVzLiBBZGRpdGlvbmFsbHksIFBlYXJzb24gY29ycmVsYXRpb25zIG1heSB1bmRlcmVzdGltYXRlIG9yIGZhaWwgdG8gcmVmbGVjdCBub24tbGluZWFyIHJlbGF0aW9uc2hpcHMgdGhhdCBjb3VsZCBleGlzdCBhbW9uZyBiaW5hcnkgcHJlZGljdG9ycy4KCkluIHRlcm1zIG9mIG11bHRpY29sbGluZWFyaXR5LCB3aGljaCB3ZSBkZWZpbmUgYXMgdGhlIHByZXNlbmNlIG9mIGhpZ2ggY29ycmVsYXRpb24gYmV0d2VlbiB0d28gb3IgbW9yZSBwcmVkaWN0b3IgdmFyaWFibGVzIHRoYXQgY291bGQgbGVhZCB0byBpbnN0YWJpbGl0eSBpbiB0aGUgbW9kZWzigJlzIGNvZWZmaWNpZW50IGVzdGltYXRlcywgdGhlcmUgaXMgbm8gZXZpZGVuY2Ugb2YgbXVsdGljb2xsaW5lYXJpdHkgaW4gdGhpcyBkYXRhc2V0LiBUaGUgY29ycmVsYXRpb24gbWF0cml4IHNob3dzIGxvdyBwYWlyd2lzZSBjb3JyZWxhdGlvbnMgYmV0d2VlbiB0aGUgcHJlZGljdG9ycywgd2l0aCB0aGUgaGlnaGVzdCBjb3JyZWxhdGlvbiBiZWluZyAwLjQ4IGJldHdlZW4gKiolIHdpdGggQmFjaGVsb3LigJlzIERlZ3JlZSoqIGFuZCAqKk1lZGlhbiBIb3VzZWhvbGQgSW5jb21lKiouIFRoaXMgdmFsdWUgZmFsbHMgYmVsb3cgY29tbW9ubHkgYWNjZXB0ZWQgdGhyZXNob2xkcyBmb3IgbXVsdGljb2xsaW5lYXJpdHkgKHR5cGljYWxseSAwLjcgb3IgaGlnaGVyKSwgc3VnZ2VzdGluZyB0aGF0IHRoZSBtb2RlbCBpcyB1bmxpa2VseSB0byBzdWZmZXIgZnJvbSBpbnN0YWJpbGl0eSBkdWUgdG8gY29sbGluZWFyIHByZWRpY3RvcnMuIFRoZXJlZm9yZSwgd2hpbGUgdGhlIFBlYXJzb24gY29ycmVsYXRpb24gbWF5IG5vdCBiZSB0aGUgbW9zdCBwcmVjaXNlIG1lYXN1cmUgZm9yIGJpbmFyeSBwcmVkaWN0b3JzLCBpdCBkb2VzIG5vdCBpbmRpY2F0ZSBhbnkgcHJvYmxlbWF0aWMgbGV2ZWxzIG9mIG11bHRpY29sbGluZWFyaXR5IGluIHRoaXMgYW5hbHlzaXMuCgo8ZGl2IHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7Ij4KCmBgYHtyIGNvciBtYXRyaXgsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTd9Cgpjb3JfbWF0cml4IDwtIGNvcihjcmFzaGVzICU+JSBkcGx5cjo6c2VsZWN0KC1jKENSTiwgRFJJTktJTkdfRCwgQVJFQUtFWSwgQ09MTElTSU9OXykpLCB1c2UgPSAicGFpcndpc2UuY29tcGxldGUub2JzIiwgbWV0aG9kID0gInBlYXJzb24iKQoKCmN1c3RvbV9sYWJlbCA8LSBjKAogICJDcmFzaCByZXN1bHRlZCBpbiBmYXRhbGl0eSBvciBtYWpvciBpbmp1cnkiID0gIkZBVEFMX09SX00iLAogICJDcmFzaCBpbnZvbHZlZCBhbiBvdmVydHVybmVkIHZlaGljbGUiID0gIk9WRVJUVVJORUQiLAogICJEcml2ZXIgd2FzIHVzaW5nIGNlbGwgcGhvbmUiID0gIkNFTExfUEhPTkUiLAogICJDcmFzaCBpbnZvbHZlZCBzcGVlZGluZyBjYXIiID0gIlNQRUVESU5HIiwKICAiQ3Jhc2ggaW52b2x2ZWQgYWdncmVzc2l2ZSBkcml2aW5nIiA9ICJBR0dSRVNTSVZFIiwKICAiQ3Jhc2ggaW52b2x2ZWQgYXQgbGVhc3Qgb25lIGRyaXZlciAxNiBvciAxNyB5ZWFycyBvbGQiID0gIkRSSVZFUjE2MTciLAogICJDcmFzaCBpbnZvbHZlZCBhdCBsZWFzdCBvbmUgZHJpdmVyIG92ZXIgNjUgeWVhcnMgb2xkIiA9ICJEUklWRVI2NVBMVVMiLAogICIlIHdpdGggYmFjaGVsb3LigJlzIGRlZ3JlZSIgPSAiUENUQkFDSE1PUiIsCiAgIk1lZGlhbiBob3VzZWhvbGQgaW5jb21lIiA9ICJNRURISElOQyIKKQoKCnJvd25hbWVzKGNvcl9tYXRyaXgpIDwtIG5hbWVzKGN1c3RvbV9sYWJlbCkKY29sbmFtZXMoY29yX21hdHJpeCkgPC0gbmFtZXMoY3VzdG9tX2xhYmVsKQoKZ2djb3JycGxvdChjb3JfbWF0cml4LCAKICAgICAgICAgICB0eXBlID0gImxvd2VyIiwgCiAgICAgICAgICAgbGFiID0gVFJVRSwgCiAgICAgICAgICAgbGFiX3NpemUgPSAzLCAKICAgICAgICAgICBjb2xvcnMgPSBjKCIjMjgzZDNiIiwgIndoaXRlIiwgIiNjNDQ1MzYiKSkgKwogIGxhYnModGl0bGUgPSAiQ29ycmVsYXRpb24gTWF0cml4IGZvciBhbGwgUHJlZGljdG9yIFZhcmlhYmxlcyIpICsKICB0aGVtZShwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LCBmYWNlID0gIml0YWxpYyIpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwgCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA3KSwgCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOCkpCmBgYAoKPC9kaXY+CgojIyBSZWdyZXNzaW9uIEFuYWx5c2lzCgpPdXIgZmlyc3QgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbCBpbmNsdWRlcyBhbGwgcHJlZGljdG9ycyBhbmQgdGhlIHJlc3VsdHMgb2YgaXQgaXMgcHJlc2VudGVkIGJlbG93LiAKCioqRkFUQUxfT1JfTSoqOiBUaGUgcHJlc2VuY2Ugb2YgYSBmYXRhbGl0eSBvciBtYWpvciBpbmp1cnkgc2lnbmlmaWNhbnRseSBpbmNyZWFzZXMgdGhlIG9kZHMgb2YgYSBkcmlua2luZy1yZWxhdGVkIGNyYXNoLCB3aXRoIGFuIG9kZHMgcmF0aW8gb2YgMi4yNTcgKDk1JSBDSTogMS45MTAgdG8gMi42NTMpIGFuZCBhIGhpZ2hseSBzaWduaWZpY2FudCBcKHAgPCAwLjAwMDFcKSwgc3VnZ2VzdGluZyB0aGF0IHRoZXNlIHR5cGVzIG9mIGluY2lkZW50cyBtb3JlIHRoYW4gZG91YmxlIHRoZSBvZGRzIG9mIGl0IHRoZXJlIGJlaW5nIGEgZHJ1bmsgZHJpdmVyLiAKCioqT1ZFUlRVUk5FRCoqOiBPdmVydHVybmVkIHZlaGljbGVzIHNpZ25pZmljYW50bHkgaW5jcmVhc2UgdGhlIGxpa2VsaWhvb2Qgb2YgaXQgYmVpbmcgYSBkcmlua2luZy1yZWxhdGVkIGNyYXNoLCB3aXRoIGFuIG9kZHMgcmF0aW8gb2YgMi41MzIgKDk1JSBDSTogMi4wMzUgdG8gMy4xMjIpIGFuZCBhIGhpZ2hseSBzaWduaWZpY2FudCBcKHAgPCAwLjAwMDFcKS4gVGhpcyByZXN1bHQgaW1wbGllcyB0aGF0IG92ZXJ0dXJuZWQgdmVoaWNsZXMgYXJlIHN0cm9uZ2x5IGFzc29jaWF0ZWQgd2l0aCBhIGRyaW5raW5nLWRyaXZlciBpbmN1cnJlZCBjcmFzaGVzLgoKKipDRUxMX1BIT05FKio6IFRoZSB1c2Ugb2YgYSBjZWxscGhvbmUgZHVyaW5nIGEgY3Jhc2ggc2hvd3Mgbm8gc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBlZmZlY3Qgb24gdGhlIG9kZHMgb2YgYSBkcmlua2luZy1yZWxhdGVkIGNyYXNoIChcKHAgPSAwLjg4MVwpKSwgd2l0aCBhbiBvZGRzIHJhdGlvIGNsb3NlIHRvIDEgKE9SID0gMS4wMzAsIDk1JSBDSTogMC42ODQgdG8gMS40ODgpLCBpbmRpY2F0aW5nIG5vIHNpZ25pZmljYW50bHkgbWVhbmluZ2Z1bCBhc3NvY2lhdGlvbi4KCioqU1BFRURJTkcqKjogU3BlZWRpbmcgaXMgYSBoaWdobHkgc2lnbmlmaWNhbnQgcHJlZGljdG9yLCB3aXRoIGFuIG9kZHMgcmF0aW8gb2YgNC42NjAgKDk1JSBDSTogMy45NzQgdG8gNS40NTApLCBhbmQgXChwIDwgMC4wMDAxXCksIGluZGljYXRpbmcgdGhhdCBjcmFzaGVzIGludm9sdmluZyBzcGVlZGluZyBhcmUgbW9yZSB0aGFuIGZvdXIgdGltZXMgYXMgbGlrZWx5IHRvIGludm9sdmUgYWxjb2hvbC4KCioqQUdHUkVTU0lWRSoqOiBBZ2dyZXNzaXZlIGRyaXZpbmcgaXMgYXNzb2NpYXRlZCB3aXRoIGxvd2VyIG9kZHMgb2YgYSBkcmlua2luZy1yZWxhdGVkIGNyYXNoLCB3aXRoIGFuIG9kZHMgcmF0aW8gb2YgMC41NTEgKDk1JSBDSTogMC41MDEgdG8gMC42MDQpLCBhbmQgXChwIDwgMC4wMDAxXCksIHN1Z2dlc3RpbmcgdGhhdCBhZ2dyZXNzaXZlIGRyaXZpbmcgaW5jaWRlbnRzIGFyZSBsZXNzIGxpa2VseSB0byBpbnZvbHZlIGFsY29ob2wuCgoqKkRSSVZFUjE2MTcqKjogSW5jaWRlbnRzIGludm9sdmluZyBkcml2ZXJzIGFnZWQgMTYtMTcgYXJlIHNpZ25pZmljYW50bHkgbGVzcyBsaWtlbHkgdG8gYmUgZHJpbmtpbmctcmVsYXRlZCAoT1IgPSAwLjI3OCwgOTUlIENJOiAwLjE0OCB0byAwLjQ3MSksIHdpdGggYSBzaWduaWZpY2FudCBcKHAgPCAwLjAwMDFcKSwgcG9zc2libHkgcmVmbGVjdGluZyB0aGUgaW5mbHVlbmNlIG9mIGRyaW5raW5nIGxhd3MgZm9yIHlvdW5nZXIgZHJpdmVycy4KCioqRFJJVkVSNjVQTFVTKio6IEluY2lkZW50cyBpbnZvbHZpbmcgZHJpdmVycyBhZ2VkIDY1IGFuZCBhYm92ZSBhbHNvIHNob3cgc2lnbmlmaWNhbnRseSBsb3dlciBvZGRzIG9mIGJlaW5nIGRyaW5raW5nLXJlbGF0ZWQsIHdpdGggYW4gb2RkcyByYXRpbyBvZiAwLjQ2MSAoOTUlIENJOiAwLjM4MCB0byAwLjU1MyksIGFuZCBcKHAgPCAwLjAwMDFcKSwgaW5kaWNhdGluZyB0aGF0IG9sZGVyIGRyaXZlcnMgYXJlIGxlc3MgbGlrZWx5IHRvIGJlIGludm9sdmVkIGluIGFsY29ob2wtcmVsYXRlZCBjcmFzaGVzLgoKKipQQ1RCQUNITU9SKio6IFRoZSBwZXJjZW50YWdlIG9mIHBlb3BsZSB3aXRoIGEgYmFjaGVsb3LigJlzIGRlZ3JlZSBvciBoaWdoZXIgaW4gdGhlIGFyZWEgZG9lcyBub3Qgc2lnbmlmaWNhbnRseSBpbXBhY3QgdGhlIG9kZHMgb2YgYSBkcmlua2luZy1yZWxhdGVkIGNyYXNoIChcKHAgPSAwLjc3NVwpKSB0aGF0IG9jY3VyIHRoZXJlLCB3aXRoIGFuIG9kZHMgcmF0aW8gbmVhciAxIChPUiA9IDEuMDAwLCA5NSUgQ0k6IDAuOTk3IHRvIDEuMDAyKS4KCioqTUVESEhJTkMqKjogTWVkaWFuIGhvdXNlaG9sZCBpbmNvbWUgaGFzIGEgdmVyeSBzbGlnaHQsIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgcG9zaXRpdmUgZWZmZWN0IG9uIHRoZSBsaWtlbGlob29kIG9mIGEgZHJpbmtpbmctcmVsYXRlZCBjcmFzaCB0aGVyZSwgd2l0aCBcKHAgPSAwLjAzNlwpLCBidXQgdGhlIGVmZmVjdCBzaXplIGlzIG5lZ2xpZ2libGUsIGFzIHNob3duIGJ5IHRoZSBjb25maWRlbmNlIGludGVydmFsIGxpbWl0cyBhcm91bmQgMSAoT1IgPSAxLjAwMCkuCgoKYGBge3IgbG9naXQgMSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCmxvZ2l0IDwtIGdsbShEUklOS0lOR19EIH4gRkFUQUxfT1JfTSArIE9WRVJUVVJORUQgKyBDRUxMX1BIT05FICsgU1BFRURJTkcgKyBBR0dSRVNTSVZFICsgRFJJVkVSMTYxNyArIERSSVZFUjY1UExVUyArIFBDVEJBQ0hNT1IgKyBNRURISElOQywgZGF0YSA9IGNyYXNoZXMsIGZhbWlseSA9IGJpbm9taWFsKQoKc3VtbWFyeShsb2dpdCkKCmBgYAoKQXMgYSBxdWljayBzdW1tYXJ5LCBwcmVkaWN0b3IgdGhhdCBhcmUgaGlnaGx5IHNpZ25pZmljYW50IFwocCA8IDAuMDAxXCkgYXJlICoqRkFUQUxfT1JfTSoqLCAqKk9WRVJUVVJORUQqKiwgKipTUEVFRElORyoqLCAqKkFHR1JFU1NJVkUqKiwgKipEUklWRVIxNjE3KiosIGFuZCAqKkRSSVZFUjY1UExVUyoqLiBBbW9uZyB3aGljaCB0aG9zZSB0aGF0IGluY3JlYXNlIHRoZSBvZGRzIG9mIGFuIGluY2lkZW50IHRoYXQgaW5jbHVkZXMgZHJ1bmsgZHJpdmluZyBhcmUgKipGQVRBTF9PUl9NKiosICoqT1ZFUlRVUk5FRCoqLCBhbmQgKipTUEVFRElORyoqLiBPbiB0aGUgb3RoZXIgaGFuZCwgcHJlZGljdG9ycyB0aGF0IGFyZSBub3Qgc2lnbmlmaWNhbnQgYXJlICoqQ0VMTF9QSE9ORSoqIGFuZCAqKlBDVEJBQ0hNT1IqKi4gVGhlIHByZWRpY3RvciAqKk1FREhISU5DKiogaXMgbWFyZ2luYWxseSBzaWduaWZpY2FudCAoXChwID0gMC4wMzZcKSkuCgpgYGB7ciByZXBvcnQgcmVzdWx0LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQoKbG9naXRvdXRwdXQgPC0gc3VtbWFyeShsb2dpdCkKbG9naXRjb2VmZiA8LSBsb2dpdG91dHB1dCRjb2VmZmljaWVudHMKb3JfY2kgPC0gZXhwKGNiaW5kKE9SID0gY29lZihsb2dpdCksIGNvbmZpbnQobG9naXQpKSkKbG9naXRjb2VmZlssICJQcig+fHp8KSJdIDwtIHJvdW5kKGxvZ2l0Y29lZmZbLCAiUHIoPnx6fCkiXSwgNCkKZmluYWxfb3V0cHV0IDwtIGNiaW5kKGxvZ2l0Y29lZmYsIG9yX2NpKQpmaW5hbF9vdXRwdXQgJT4lIAogIGthYmxlKCJodG1sIiwgZXNjYXBlID0gRkFMU0UsIGFsaWduID0gImNjY2NjYyIpICU+JQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFLCBwb3NpdGlvbiA9ICJjZW50ZXIiLCBmaXhlZF90aGVhZCA9IFRSVUUpCgpgYGAKClRoZSB0YWJsZSBiZWxvdyBwcmVzZW50cyB0aGUgc3BlY2lmaWNpdHksIHNlbnNpdGl2aXR5LCBhbmQgbWlzY2xhc3NpZmljYXRpb24gcmF0ZXMgZm9yIHZhcmlvdXMgcHJvYmFiaWxpdHkgY3V0LW9mZnMgaW4gcHJlZGljdGluZyB0aGUgbGlrZWxpaG9vZCBvZiBhIGRyaW5raW5nLXJlbGF0ZWQgY3Jhc2guIFRoZSBsb3dlc3QgYW5kIGhpZ2hlc3QgbWlzY2xhc3NpZmljYXRpb24gcmF0ZXMgaGlnaGxpZ2h0IHRoZSBlZmZlY3RpdmVuZXNzIG9mIGVhY2ggY3V0LW9mZi4KCmBgYHtyIHJvYyBtZWFzdXJlcywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KCmZpdCA8LSBsb2dpdCRmaXR0ZWQgICAKYSA8LSBjYmluZChjcmFzaGVzJERSSU5LSU5HX0QsIGZpdCkKY29sbmFtZXMoYSkgPC0gYygibGFiZWxzIiwgInByZWRpY3Rpb25zIikKcm9jIDwtIGFzLmRhdGEuZnJhbWUoYSkKCmBgYAoKVGhlIHByb2JhYmlsaXR5IGN1dC1vZmYgb2YgMC41MCB5aWVsZHMgdGhlIGxvd2VzdCBtaXNjbGFzc2lmaWNhdGlvbiByYXRlIG9mIDAuMDU3LiBBdCB0aGlzIHRocmVzaG9sZCwgc3BlY2lmaWNpdHkgaXMgbWF4aW1pemVkIGF0IDEuMDAwLCBidXQgc2Vuc2l0aXZpdHkgaXMgdmVyeSBsb3cgKDAuMDAyKSwgbWVhbmluZyB0aGF0IHRoZSBtb2RlbCBjYXB0dXJlcyB2ZXJ5IGZldyB0cnVlIHBvc2l0aXZlcywgc2FjcmlmaWNpbmcgc2Vuc2l0aXZpdHkgZm9yIGhpZ2ggc3BlY2lmaWNpdHkuCgpUaGUgaGlnaGVzdCBtaXNjbGFzc2lmaWNhdGlvbiByYXRlIG9jY3VycyBhdCB0aGUgY3V0LW9mZiBvZiAwLjAyIHdpdGggYSByYXRlIG9mIDAuODg5LiBBdCB0aGlzIHRocmVzaG9sZCwgc2Vuc2l0aXZpdHkgaXMgaGlnaCAoMC45ODQpLCBjYXB0dXJpbmcgbmVhcmx5IGFsbCB0cnVlIHBvc2l0aXZlcywgYnV0IHNwZWNpZmljaXR5IGlzIHZlcnkgbG93ICgwLjA1OCksIHJlc3VsdGluZyBpbiBhIGhpZ2ggcmF0ZSBvZiBmYWxzZSBwb3NpdGl2ZXMuCgpgYGB7ciBjYWxjdWxhdGUgbWVhc3VyZXMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpjdXRvZmZzIDwtIGMoMC4wMiwgMC4wMywgMC4wNSwgMC4wNywgMC4wOCwgMC4wOSwgMC4xMCwgMC4xNSwgMC4yMCwgMC41MCkKcmVzdWx0cyA8LSBkYXRhLmZyYW1lKAogIEN1dG9mZiA9IGN1dG9mZnMsCiAgU2Vuc2l0aXZpdHkgPSBOQSwKICBTcGVjaWZpY2l0eSA9IE5BLAogIE1pc2NsYXNzaWZpY2F0aW9uUmF0ZSA9IE5BCikKCmNhbGN1bGF0ZV9tZXRyaWNzIDwtIGZ1bmN0aW9uKGN1dG9mZiwgbGFiZWxzLCBwcmVkaWN0aW9ucykgewogIHByZWRpY3RlZF9sYWJlbHMgPC0gaWZlbHNlKHByZWRpY3Rpb25zID49IGN1dG9mZiwgMSwgMCkKICAKICB0cCA8LSBzdW0ocHJlZGljdGVkX2xhYmVscyA9PSAxICYgbGFiZWxzID09IDEpICMgVHJ1ZSBwb3NpdGl2ZXMKICB0biA8LSBzdW0ocHJlZGljdGVkX2xhYmVscyA9PSAwICYgbGFiZWxzID09IDApICMgVHJ1ZSBuZWdhdGl2ZXMKICBmcCA8LSBzdW0ocHJlZGljdGVkX2xhYmVscyA9PSAxICYgbGFiZWxzID09IDApICMgRmFsc2UgcG9zaXRpdmVzCiAgZm4gPC0gc3VtKHByZWRpY3RlZF9sYWJlbHMgPT0gMCAmIGxhYmVscyA9PSAxKSAjIEZhbHNlIG5lZ2F0aXZlcwogIAogICMgU2Vuc2l0aXZpdHk6IFRydWUgcG9zaXRpdmUgcmF0ZQogIHNlbnNpdGl2aXR5IDwtIHRwIC8gKHRwICsgZm4pCiAgCiAgIyBTcGVjaWZpY2l0eTogVHJ1ZSBuZWdhdGl2ZSByYXRlCiAgc3BlY2lmaWNpdHkgPC0gdG4gLyAodG4gKyBmcCkKICAKICAjIE1pc2NsYXNzaWZpY2F0aW9uIHJhdGUKICBtaXNjbGFzc2lmaWNhdGlvbl9yYXRlIDwtIChmcCArIGZuKSAvIGxlbmd0aChsYWJlbHMpCiAgCiAgcmV0dXJuKGMoc2Vuc2l0aXZpdHksIHNwZWNpZmljaXR5LCBtaXNjbGFzc2lmaWNhdGlvbl9yYXRlKSkKfQoKZm9yIChpIGluIHNlcV9hbG9uZyhjdXRvZmZzKSkgewogIG1ldHJpY3MgPC0gY2FsY3VsYXRlX21ldHJpY3MoY3V0b2Zmc1tpXSwgcm9jJGxhYmVscywgcm9jJHByZWRpY3Rpb25zKQogIHJlc3VsdHMkU2Vuc2l0aXZpdHlbaV0gPC0gbWV0cmljc1sxXQogIHJlc3VsdHMkU3BlY2lmaWNpdHlbaV0gPC0gbWV0cmljc1syXQogIHJlc3VsdHMkTWlzY2xhc3NpZmljYXRpb25SYXRlW2ldIDwtIG1ldHJpY3NbM10KfQoKcmVzdWx0cyAlPiUgCiAga2FibGUoImh0bWwiLCBlc2NhcGUgPSBGQUxTRSwgYWxpZ24gPSAiY2NjYyIpICU+JQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFLCBwb3NpdGlvbiA9ICJjZW50ZXIiLCBmaXhlZF90aGVhZCA9IFRSVUUpCmBgYAoKCldlIHBsb3R0ZWQgdGhlIFJPQyBjdXJ2ZSB0byBzaG93IHRoZSB0cmFkZW9mZiBiZXR3ZWVuIHNlbnNpdGl2aXR5IChUcnVlIFBvc2l0aXZlIFJhdGUpIGFuZCBzcGVjaWZpY2l0eSAoMSAtIEZhbHNlIFBvc2l0aXZlIFJhdGUpIGFjcm9zcyB2YXJpb3VzIHByb2JhYmlsaXR5IGN1dC1vZmZzIGZvciB0aGUgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbC4gQW4gaWRlYWwgbW9kZWwgd291bGQgcmVhY2ggdGhlIHRvcC1sZWZ0IGNvcm5lciBvZiB0aGUgUk9DIHNwYWNlIChzZW5zaXRpdml0eSA9IDEsIHNwZWNpZmljaXR5ID0gMSksIHdoaWNoIHdvdWxkIG1lYW4gcGVyZmVjdCBkaXNjcmltaW5hdGlvbiBiZXR3ZWVuIHRoZSB0d28gY2xhc3Nlcy4gT3VyIFJPQyBjdXJ2ZSwgaG93ZXZlciwgbGllcyBiZW5lYXRoIHRoaXMgaWRlYWwgcG9pbnQsIGluZGljYXRpbmcgdHJhZGUtb2ZmcyBiZXR3ZWVuIHNlbnNpdGl2aXR5IGFuZCBzcGVjaWZpY2l0eSBhdCBlYWNoIGN1dC1vZmYuCgo8ZGl2IHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7Ij4KCmBgYHtyIHJvYyBjdXJ2ZSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCmdncGxvdChyb2MsIGFlcyhkID0gbGFiZWxzLCBtID0gcHJlZGljdGlvbnMpKSArCiAgZ2VvbV9yb2Mobi5jdXRzID0gNTAsIGxhYmVscyA9IEZBTFNFLCBjb2xvdXIgPSAiIzI4M2QzYiIpICsKICBsYWJzKHRpdGxlID0gIlJPQyBDdXJ2ZSIpICsKICBzdHlsZV9yb2ModGhlbWUgPSB0aGVtZV9ncmV5KSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBzaXplID0gMSwgY29sb3IgPSAiI2M0NDUzNiIpICsKICB0aGVtZSgKICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDksIGZhY2UgPSAiaXRhbGljIiksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksIAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLCAKICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpLCAKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXkiLCBmaWxsID0gTkEsIGxpbmV3aWR0aCA9IDAuOCkKICApCmBgYAo8L2Rpdj4KClVzaW5nIHRoZSBmdW5jdGlvbiBgb3B0LmN1dGAsIHdlIGNhbGN1bGF0ZWQgdGhlIG9wdGltYWwgY3V0LW9mZiBieSBtaW5pbWl6aW5nIHRoZSBFdWNsaWRlYW4gZGlzdGFuY2UgZnJvbSB0aGUgUk9DIGN1cnZlIHRvIHRoZSBwb2ludCAoMCwgMSkg4oCUIHRoZSB0b3AtbGVmdCBjb3JuZXIgb2YgdGhlIFJPQyBzcGFjZSwgd2hpY2ggcmVwcmVzZW50cyBwZXJmZWN0IHNlbnNpdGl2aXR5IGFuZCBzcGVjaWZpY2l0eS4gVGhpcyBjdXQtb2ZmIG9mIDAuMDY0IHByb3ZpZGVzIGEgYmFsYW5jZWQgYXBwcm9hY2gsIGFjaGlldmluZyBhIHNlbnNpdGl2aXR5IG9mIDAuNjYxIGFuZCBzcGVjaWZpY2l0eSBvZiAwLjU0NS4KCkluIHRoZSBhYm92ZSBzZWN0aW9uLCB0aGUgb3B0aW1hbCBjdXQtb2ZmIHNlbGVjdGVkIGJhc2VkIG9uIHRoZSBtaW5pbXVtIG1pc2NsYXNzaWZpY2F0aW9uIHJhdGUgd2FzIDAuNTAsIHdoaWNoIHlpZWxkZWQgYSBtaXNjbGFzc2lmaWNhdGlvbiByYXRlIG9mIDAuMDU3LiBUaGlzIHRocmVzaG9sZCBmb2N1c2VkIG9uIHJlZHVjaW5nIHRoZSBvdmVyYWxsIG51bWJlciBvZiBtaXNjbGFzc2lmaWVkIG9ic2VydmF0aW9ucywgcHJpb3JpdGl6aW5nIGhpZ2ggc3BlY2lmaWNpdHkgKDEuMDAwKSBidXQgcmVzdWx0aW5nIGluIGxvdyBzZW5zaXRpdml0eSAoMC4wMDIpLiBJbiBjb250cmFzdCwgdGhlIGN1dC1vZmYgb2YgMC4wNjQgaWRlbnRpZmllZCB0aHJvdWdoIHRoZSBST0MgYW5hbHlzaXMgYWltcyB0byBiYWxhbmNlIGJvdGggc2Vuc2l0aXZpdHkgYW5kIHNwZWNpZmljaXR5LCBhY2hpZXZpbmcgYSBtb2RlcmF0ZSBsZXZlbCBmb3IgZWFjaCBtZXRyaWMgcmF0aGVyIHRoYW4gcHJpb3JpdGl6aW5nIG9uZSBvdmVyIHRoZSBvdGhlci4gVGhpcyBjdXQtb2ZmIG1pZ2h0IGJlIG1vcmUgc3VpdGFibGUgZm9yIGFwcGxpY2F0aW9ucyB3aGVyZSBib3RoIHRydWUgcG9zaXRpdmUgYW5kIHRydWUgbmVnYXRpdmUgcmF0ZXMgYXJlIGVxdWFsbHkgaW1wb3J0YW50LiAKCmBgYHtyIG1lYXN1cmUgb3B0aW1hbCBjdXQtb2ZmLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKcHJlZCA8LSBwcmVkaWN0aW9uKHJvYyRwcmVkaWN0aW9ucywgcm9jJGxhYmVscykKcm9jLnBlcmYgPC0gcGVyZm9ybWFuY2UocHJlZCwgbWVhc3VyZSA9ICJ0cHIiLCB4Lm1lYXN1cmUgPSAiZnByIikKCm9wdC5jdXQgPC0gZnVuY3Rpb24ocGVyZiwgcHJlZCkgewogIGN1dC5pbmQgPC0gbWFwcGx5KEZVTiA9IGZ1bmN0aW9uKHgsIHksIHApIHsKICAgIGQgPC0gKHggLSAwKV4yICsgKHkgLSAxKV4yCiAgICBpbmQgPC0gd2hpY2goZCA9PSBtaW4oZCkpCiAgICBjKHNlbnNpdGl2aXR5ID0geVtbaW5kXV0sIHNwZWNpZmljaXR5ID0gMSAtIHhbW2luZF1dLCBjdXRvZmYgPSBwW1tpbmRdXSkKICB9LCBwZXJmQHgudmFsdWVzLCBwZXJmQHkudmFsdWVzLCBwcmVkQGN1dG9mZnMpCiAgCiAgY3V0LmRmIDwtIGRhdGEuZnJhbWUoCiAgICBzZW5zaXRpdml0eSA9IGN1dC5pbmRbMSwgXSwKICAgIHNwZWNpZmljaXR5ID0gY3V0LmluZFsyLCBdLAogICAgY3V0b2ZmID0gY3V0LmluZFszLCBdCiAgKQogIHJvd25hbWVzKGN1dC5kZikgPC0gTlVMTAogIHJldHVybihjdXQuZGYpCn0KCm9wdGltYWxfY3V0b2Zmc19kZiA8LSBvcHQuY3V0KHJvYy5wZXJmLCBwcmVkKQpvcHRpbWFsX2N1dG9mZnNfZGYgJT4lIAogIGthYmxlKCJodG1sIiwgZXNjYXBlID0gRkFMU0UsIGFsaWduID0gImNjYyIpICU+JQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFLCBwb3NpdGlvbiA9ICJjZW50ZXIiLCBmaXhlZF90aGVhZCA9IFRSVUUpCgoKYGBgCgpUaGUgQXJlYSBVbmRlciB0aGUgUk9DIEN1cnZlIChBVUMpIGZvciBvdXIgbW9kZWwgaXMgMC42NDAuIEFuIEFVQyBvZiAwLjY0MCBzdWdnZXN0cyB0aGF0IHRoZSBtb2RlbCBoYXMgcG9vciBkaXNjcmltaW5hdGlvbiAoZ2VuZXJhbGx5LCBhIG1vZGVsIHdpdGggYW4gQVVDIGJldHdlZW4gMC42IGFuZCAwLjcgaXMgY29uc2lkZXJlZCB0byBoYXZlIHBvb3IgZGlzY3JpbWluYXRpb24pLiBTcGVjaWZpY2FsbHksIHRoZSBBVUMgdmFsdWUgbWVhbnMgdGhhdCBpZiB3ZSByYW5kb21seSBzZWxlY3Qgb25lIHBvc2l0aXZlIGNhc2UgYW5kIG9uZSBuZWdhdGl2ZSBjYXNlLCB0aGUgbW9kZWwgaGFzIGEgNjQlIGNoYW5jZSBvZiBjb3JyZWN0bHkgcmFua2luZyB0aGUgcG9zaXRpdmUgY2FzZSBoaWdoZXIgaW4gdGVybXMgb2YgcHJlZGljdGVkIHByb2JhYmlsaXR5IHRoYW4gdGhlIG5lZ2F0aXZlIGNhc2UuIEluIHByYWN0aWNhbCB0ZXJtcywgdGhpcyBpbmRpY2F0ZXMgdGhhdCB3aGlsZSB0aGUgbW9kZWwgaXMgYWJsZSB0byBkaXN0aW5ndWlzaCBiZXR3ZWVuIGNyYXNoZXMgd2l0aCBhbmQgd2l0aG91dCBhbGNvaG9sIGludm9sdmVtZW50IHRvIHNvbWUgZXh0ZW50LCBpdHMgcGVyZm9ybWFuY2UgaXMgbGltaXRlZCBhbmQgbWF5IG1pc2NsYXNzaWZ5IGEgc3Vic3RhbnRpYWwgbnVtYmVyIG9mIG9ic2VydmF0aW9ucy4gCgoKYGBge3IgYXVjLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKYXVjLnBlcmYgPC0gIHBlcmZvcm1hbmNlKHByZWQsIG1lYXN1cmUgPSJhdWMiKQphdWMudmFsdWUgPC0gYXVjLnBlcmZAeS52YWx1ZXMKY2F0KHNwcmludGYoIkFVQzogJS4zZlxuIiwgYXVjLnZhbHVlKSkKCmBgYAoKVGhlIHNlY29uZCBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsIHdlIHJhbiBpbmNsdWRlcyBvbmx5IHRoZSBiaW5hcnkgcHJlZGljdG9ycy4gSW4gdGhlIGZpcnN0IG1vZGVsLCBcKCBcdGV4dHtQQ1RCQUNITU9SfVwpIGFuZCBcKCBcdGV4dHtNRURISElOQ31cKSB3ZXJlIG5vdCBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IHByZWRpY3RvcnMgb2YgXCggXHRleHR7RFJJTktJTkdfRH1cKSwgYXMgdGhlaXIgXChwIDwgMC4wNVwpLiBIb3dldmVyLCBpbiB0aGUgcmVkdWNlZCBtb2RlbCwgdGhlIGV4Y2x1c2lvbiBvZiB0aGVzZSB0d28gcHJlZGljdG9ycyBkaWQgbm90IGxlYWQgdG8gYW55IG5ldyBwcmVkaWN0b3JzIGJlY29taW5nIHNpZ25pZmljYW50IG9yIGFueSBwcmV2aW91c2x5IHNpZ25pZmljYW50IHByZWRpY3RvcnMgYmVjb21pbmcgaW5zaWduaWZpY2FudC4KCgpgYGB7ciBsb2dpdCAyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKbG9naXQyIDwtIGdsbShEUklOS0lOR19EIH4gRkFUQUxfT1JfTSArIE9WRVJUVVJORUQgKyBDRUxMX1BIT05FICsgU1BFRURJTkcgKyBBR0dSRVNTSVZFICsgRFJJVkVSMTYxNyArIERSSVZFUjY1UExVUywgZGF0YSA9IGNyYXNoZXMsIGZhbWlseSA9IGJpbm9taWFsKQoKc3VtbWFyeShsb2dpdDIpCgpgYGAKClRoZSBvZGRzIHJhdGlvcyAoT1IpIGZvciB0aGUgYmluYXJ5IHByZWRpY3RvcnMgaW4gYm90aCBtb2RlbHMgYXJlIHZlcnkgc2ltaWxhciwgc3VnZ2VzdGluZyB0aGF0IHJlbW92aW5nIFwoIFx0ZXh0e1BDVEJBQ0hNT1J9XCkgYW5kIFwoIFx0ZXh0e01FREhISU5DfVwpIGhhZCBsaXR0bGUgaW1wYWN0IG9uIHRoZSBlc3RpbWF0ZWQgZWZmZWN0cyBvZiB0aGUgb3RoZXIgdmFyaWFibGVzLgoKYGBge3IgcmVwb3J0IHJlc3VsdCBmb3Igc2Vjb25kIHJlZywgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KCmxvZ2l0b3V0cHV0MiA8LSBzdW1tYXJ5KGxvZ2l0MikKbG9naXRjb2VmZjIgPC0gbG9naXRvdXRwdXQyJGNvZWZmaWNpZW50cwpvcl9jaTIgPC0gZXhwKGNiaW5kKE9SID0gY29lZihsb2dpdDIpLCBjb25maW50KGxvZ2l0MikpKQpsb2dpdGNvZWZmMlssICJQcig+fHp8KSJdIDwtIHJvdW5kKGxvZ2l0Y29lZmYyWywgIlByKD58enwpIl0sIDQpCmZpbmFsX291dHB1dDIgPC0gY2JpbmQobG9naXRjb2VmZjIsIG9yX2NpMikKZmluYWxfb3V0cHV0MiAlPiUgCiAga2FibGUoImh0bWwiLCBlc2NhcGUgPSBGQUxTRSwgYWxpZ24gPSAiY2NjY2NjIikgJT4lCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRkFMU0UsIHBvc2l0aW9uID0gImNlbnRlciIsIGZpeGVkX3RoZWFkID0gVFJVRSkKCgpgYGAKClRoZSBBa2Fpa2UgSW5mb3JtYXRpb24gQ3JpdGVyaW9uIChBSUMpIGZvciBib3RoIG1vZGVscyBpcyBcdGV4dGJmezE4MzYwfS4gQUlDIGlzIGEgbWVhc3VyZSBvZiBtb2RlbCBxdWFsaXR5IHRoYXQgYmFsYW5jZXMgZ29vZG5lc3Mgb2YgZml0IHdpdGggbW9kZWwgY29tcGxleGl0eSAocGVuYWxpemluZyBhZGRpdGlvbmFsIHBhcmFtZXRlcnMpLiBTaW5jZSB0aGUgQUlDIGlzIHRoZSBzYW1lIGluIGJvdGggbW9kZWxzLCBuZWl0aGVyIG1vZGVsIGlzIHN1cGVyaW9yIGluIHRlcm1zIG9mIGZpdC4gR2l2ZW4gdGhhdCB0aGUgZmlyc3QgbW9kZWwgaW5jbHVkZXMgdHdvIGFkZGl0aW9uYWwgcHJlZGljdG9ycyB0aGF0IGFyZSBub3Qgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBhbmQgZG9lcyBub3QgaW1wcm92ZSB0aGUgQUlDLCB0aGUgcmVkdWNlZCBtb2RlbCAoYmluYXJ5IHByZWRpY3RvcnMgb25seSkgaXMgcHJlZmVyYWJsZSBmb3IgaXRzIHNpbXBsaWNpdHkuIAoKYGBge3IgY29tcGFyaXNvbiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCmFpY190YWJsZSA8LSBBSUMobG9naXQsIGxvZ2l0MikKY29sbmFtZXMoYWljX3RhYmxlKSA8LSBjKCJEZWdyZWUgb2YgRnJlZWRvbSIsICJBSUMiKQpyb3duYW1lcyhhaWNfdGFibGUpIDwtIGMoIk1vZGVsIDE6IEFsbCBQcmVkaWN0b3JzIiwgIk1vZGVsIDI6IEJpbmFyeSBQcmVkaWN0b3JzIE9ubHkiKQphaWNfdGFibGUgJT4lIAogIGthYmxlKCJodG1sIiwgZXNjYXBlID0gRkFMU0UsIGFsaWduID0gImNjIikgJT4lCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRkFMU0UsIHBvc2l0aW9uID0gImNlbnRlciIsIGZpeGVkX3RoZWFkID0gVFJVRSkKYGBgCgojIERpc2N1c3Npb24KCkluIHRoaXMgc3R1ZHksIGEgbG9naXN0aWMgcmVncmVzc2lvbiBhbmFseXNpcyB3YXMgY29uZHVjdGVkIHRvIGV4YW1pbmUgZmFjdG9ycyBhc3NvY2lhdGVkIHdpdGggYWxjb2hvbCBpbnZvbHZlbWVudCBpbiB2ZWhpY3VsYXIgY3Jhc2hlcyBpbiBQaGlsYWRlbHBoaWEuIFRoZSBhbmFseXNpcyBpbmNsdWRlZCBhIHZhcmlldHkgb2YgcHJlZGljdG9ycywgZW5jb21wYXNzaW5nIGNyYXNoIGNoYXJhY3RlcmlzdGljcyAoc3VjaCBhcyB3aGV0aGVyIHRoZSBjcmFzaCByZXN1bHRlZCBpbiBhIGZhdGFsaXR5IG9yIG1ham9yIGluanVyeSwgaW52b2x2ZWQgYW4gb3ZlcnR1cm5lZCB2ZWhpY2xlLCBvciBpbnZvbHZlZCBjZWxsIHBob25lIHVzZSksIGRyaXZlciBiZWhhdmlvcnMgKGluY2x1ZGluZyBzcGVlZGluZywgYWdncmVzc2l2ZSBkcml2aW5nLCBhbmQgdGhlIGFnZSBvZiBkcml2ZXJzIGludm9sdmVkKSwgYW5kIHNvY2lvLWVjb25vbWljIHZhcmlhYmxlcyBmcm9tIHRoZSBjcmFzaCBsb2NhdGlvbnMgKHN1Y2ggYXMgdGhlIHBlcmNlbnRhZ2Ugb2YgaW5kaXZpZHVhbHMgd2l0aCBhIGJhY2hlbG9y4oCZcyBkZWdyZWUgb3IgaGlnaGVyIGFuZCBtZWRpYW4gaG91c2Vob2xkIGluY29tZSkuIFRoZSBwcmltYXJ5IG9iamVjdGl2ZSB3YXMgdG8gaWRlbnRpZnkgc2lnbmlmaWNhbnQgcHJlZGljdG9ycyBvZiBhbGNvaG9sLXJlbGF0ZWQgY3Jhc2hlcyBhbmQgZ2FpbiBpbnNpZ2h0IGludG8gdGhlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB0aGVzZSBmYWN0b3JzIGFuZCB0aGUgbGlrZWxpaG9vZCBvZiBkcnVuayBkcml2aW5nIGluY2lkZW50cy4KClRoZSByZXN1bHRzIGluZGljYXRlIHRoYXQgc2V2ZXJhbCBjcmFzaCBjaGFyYWN0ZXJpc3RpY3MgYW5kIGRyaXZlciBiZWhhdmlvcnMgYXJlIHNpZ25pZmljYW50IHByZWRpY3RvcnMgb2YgYWxjb2hvbCBpbnZvbHZlbWVudC4gU3BlY2lmaWNhbGx5LCBcKCBcdGV4dHtGQVRBTF9PUl9NfSBcKSAod2hldGhlciB0aGUgY3Jhc2ggcmVzdWx0ZWQgaW4gYSBmYXRhbGl0eSBvciBtYWpvciBpbmp1cnkpLCBcKFx0ZXh0e09WRVJUVVJORUR9IFwpICh3aGV0aGVyIHRoZSBjcmFzaCBpbnZvbHZlZCBhbiBvdmVydHVybmVkIHZlaGljbGUpLCBhbmQgKCBcdGV4dHtTUEVFRElOR30gXCkgYXJlIGFsbCBwb3NpdGl2ZWx5IGFuZCBzaWduaWZpY2FudGx5IGFzc29jaWF0ZWQgd2l0aCBhbGNvaG9sIGludm9sdmVtZW50LiBGb3IgaW5zdGFuY2UsIGNyYXNoZXMgaW52b2x2aW5nIHNwZWVkaW5nIHdlcmUgZm91bmQgdG8gYmUgbW9yZSB0aGFuIGZvdXIgdGltZXMgYXMgbGlrZWx5IHRvIGludm9sdmUgYSBkcnVuayBkcml2ZXIsIGhpZ2hsaWdodGluZyB0aGUgc3Ryb25nIGNvbm5lY3Rpb24gYmV0d2VlbiByaXNreSBkcml2aW5nIGJlaGF2aW9ycyBhbmQgYWxjb2hvbCBpbXBhaXJtZW50LiBJbiBjb250cmFzdCwgKCBcdGV4dHtDRUxMX1BIT05FfSBcKSAodXNlIG9mIGEgY2VsbCBwaG9uZSBkdXJpbmcgdGhlIGNyYXNoKSBhbmQgXCggXHRleHR7UENUQkFDSE1PUn0gXCkgKHBlcmNlbnRhZ2Ugb2YgaW5kaXZpZHVhbHMgd2l0aCBhIGJhY2hlbG9y4oCZcyBkZWdyZWUgb3IgaGlnaGVyKSBkaWQgbm90IHNob3cgYSBzaWduaWZpY2FudCBhc3NvY2lhdGlvbiB3aXRoIGFsY29ob2wgaW52b2x2ZW1lbnQsIHN1Z2dlc3RpbmcgdGhhdCB0aGVzZSBmYWN0b3JzIGRvIG5vdCBzdWJzdGFudGlhbGx5IGluZmx1ZW5jZSB0aGUgbGlrZWxpaG9vZCBvZiBhIGNyYXNoIGludm9sdmluZyBhbGNvaG9sLiBcKCBcdGV4dHtNRURISElOQ30gXCkgKG1lZGlhbiBob3VzZWhvbGQgaW5jb21lKSBkZW1vbnN0cmF0ZWQgYSBtYXJnaW5hbGx5IHNpZ25pZmljYW50IGVmZmVjdCwgYnV0IHRoZSBpbXBhY3Qgd2FzIG5lZ2xpZ2libGUsIGluZGljYXRpbmcgdGhhdCBpbmNvbWUgbGV2ZWxzIGRvIG5vdCBwbGF5IGEgbWVhbmluZ2Z1bCByb2xlIGluIGFsY29ob2wtcmVsYXRlZCBjcmFzaCByaXNrLgoKVGhlIGZpbmRpbmdzIGFyZSBzb21ld2hhdCBzdXJwcmlzaW5nLiBXaGlsZSB0aGUgc2lnbmlmaWNhbmNlIG9mIHZhcmlhYmxlcyBsaWtlIFwoIFx0ZXh0e1NQRUVESU5HfSBcKSBhbmQgXCggXHRleHR7RkFUQUxfT1JfTX0gXCkgbWF0Y2hlcyBvdXIgZXhwZWN0YXRpb25zLCB0aGUgbGFjayBvZiBhIHNpZ25pZmljYW50IGFzc29jaWF0aW9uIGZvciBcKFx0ZXh0e0NFTExfUEhPTkV9IFwpIHVzZSBpcyB1bmV4cGVjdGVkLiBJdCB3YXMgYW50aWNpcGF0ZWQgdGhhdCBjZWxsIHBob25lIHVzZSwgYW4gYWxyZWFkeSBoaWdoLXJpc2sgYmVoYXZpb3IsIHdvdWxkIGhhdmUgYW4gYW1wbGlmaWVkIGVmZmVjdCB3aGVuIGNvbWJpbmVkIHdpdGggYWxjb2hvbCBpbXBhaXJtZW50LCBidXQgdGhlIGRhdGEgZGlkIG5vdCBzdXBwb3J0IHRoaXMgYXNzdW1wdGlvbi4gU2ltaWxhcmx5LCB0aGUgbGltaXRlZCBpbXBhY3Qgb2Ygc29jaW8tZWNvbm9taWMgdmFyaWFibGVzIHdhcyB1bmZvcmVzZWVuLiBBbHRob3VnaCBpdCB3YXMgaHlwb3RoZXNpemVkIHRoYXQgYXJlYXMgd2l0aCBsb3dlciBlZHVjYXRpb25hbCBhdHRhaW5tZW50IG9yIGluY29tZSBsZXZlbHMgbWlnaHQgZXhwZXJpZW5jZSBoaWdoZXIgcmF0ZXMgb2YgYWxjb2hvbC1yZWxhdGVkIGNyYXNoZXMgZHVlIHRvIHZhcmlvdXMgc29jaW8tZWNvbm9taWMgc3RyZXNzb3JzLCB0aGUgYW5hbHlzaXMgZGlkIG5vdCBmaW5kIG1lYW5pbmdmdWwgYXNzb2NpYXRpb25zLiBOZXZlcnRoZWxlc3MsIHRoZSBzaWduaWZpY2FudCBwcmVkaWN0b3JzLCBzdWNoIGFzIHNwZWVkaW5nIGFuZCBjcmFzaCBzZXZlcml0eSwgYWxpZ24gd2l0aCBleHBlY3RhdGlvbnMsIHJlaW5mb3JjaW5nIHRoZSB1bmRlcnN0YW5kaW5nIHRoYXQgYWxjb2hvbCBpbXBhaXJtZW50IGV4YWNlcmJhdGVzIHRoZSByaXNrIG9mIHNldmVyZSBhbmQgcmVja2xlc3MgZHJpdmluZyBiZWhhdmlvcnMuCgpUaGUgYXBwbGljYXRpb24gb2YgbG9naXN0aWMgcmVncmVzc2lvbiBpcyBhcHByb3ByaWF0ZSBpbiB0aGlzIGNvbnRleHQsIGdpdmVuIGl0cyBzdWl0YWJpbGl0eSBmb3IgbW9kZWxpbmcgYSBiaW5hcnkgZGVwZW5kZW50IHZhcmlhYmxlLiBIb3dldmVyLCBjb25zaWRlcmluZyB0aGUgcmFyaXR5IG9mIHRoZSBldmVudCBvZiBpbnRlcmVzdOKAlG9ubHkgNS43JSBvZiBjcmFzaGVzIGludm9sdmVkIGFsY29ob2zigJR0aGVyZSBtYXkgYmUgbGltaXRhdGlvbnMgdG8gdGhpcyBhcHByb2FjaC4gTWV0aG9kcyBmb3IgbW9kZWxpbmcgcmFyZSBldmVudHMsIGFzIHByb3Bvc2VkIGJ5IFBhdWwgQWxsaXNvbiwgc3VjaCBhcyBwZW5hbGl6ZWQgbGlrZWxpaG9vZCBhcHByb2FjaGVzLCBjb3VsZCBiZSBtb3JlIGVmZmVjdGl2ZS4gVGhlc2UgbWV0aG9kcyBtYXkgeWllbGQgbW9yZSByZWxpYWJsZSBhbmQgZWZmaWNpZW50IGVzdGltYXRlcyB3aGVuIGRlYWxpbmcgd2l0aCBpbmZyZXF1ZW50IG91dGNvbWVzLCBhZGRyZXNzaW5nIHBvdGVudGlhbCBiaWFzZXMgYW5kIGVuaGFuY2luZyB0aGUgbW9kZWwncyBwZXJmb3JtYW5jZS4KClRoaXMgYW5hbHlzaXMgaGFzIHNldmVyYWwgbGltaXRhdGlvbnMuIFRoZSByZWxhdGl2ZWx5IHNtYWxsIHByb3BvcnRpb24gb2YgYWxjb2hvbC1pbnZvbHZlZCBjcmFzaGVzIG1heSBhZmZlY3QgdGhlIHJvYnVzdG5lc3MgYW5kIHN0YWJpbGl0eSBvZiB0aGUgbW9kZWwgZXN0aW1hdGVzLiBFbXBsb3lpbmcgcmFyZSBldmVudCBtb2RlbGluZyB0ZWNobmlxdWVzIGNvdWxkIGltcHJvdmUgdGhlIHJlbGlhYmlsaXR5IG9mIHRoZSBmaW5kaW5ncy4gQWRkaXRpb25hbGx5LCB1bm9ic2VydmVkIGNvbmZvdW5kaW5nIHZhcmlhYmxlcywgc3VjaCBhcyB0aW1lIG9mIGRheSwgcm9hZCBjb25kaXRpb25zLCBvciBwcm94aW1pdHkgdG8gYWxjb2hvbC1zZXJ2aW5nIGVzdGFibGlzaG1lbnRzLCBtYXkgaW5mbHVlbmNlIGNyYXNoIG91dGNvbWVzIGJ1dCB3ZXJlIG5vdCBpbmNsdWRlZCBpbiB0aGUgbW9kZWwuIFRoZSBiaW5hcnkgbmF0dXJlIG9mIG1hbnkgcHJlZGljdG9ycyBtYXkgYWxzbyBvdmVyc2ltcGxpZnkgY29tcGxleCBkcml2aW5nIGJlaGF2aW9ycyBvciBzb2Npby1lY29ub21pYyBjb25kaXRpb25zLCBsaW1pdGluZyB0aGUgbW9kZWwncyBhYmlsaXR5IHRvIGNhcHR1cmUgbnVhbmNlcy4gRmluYWxseSwgd2hpbGUgc29jaW8tZWNvbm9taWMgZmFjdG9ycyBkaWQgbm90IGVtZXJnZSBhcyBzaWduaWZpY2FudCBwcmVkaWN0b3JzLCB0aGlzIGRvZXMgbm90IHJ1bGUgb3V0IHRoZWlyIHBvdGVudGlhbCBpbXBvcnRhbmNlIGluIGEgYnJvYWRlciBjb250ZXh0IG9yIHdoZW4gYW5hbHl6ZWQgd2l0aCBtb3JlIGdyYW51bGFyIGRhdGEuIEZ1dHVyZSByZXNlYXJjaCBjb3VsZCBhZGRyZXNzIHRoZXNlIGxpbWl0YXRpb25zIGJ5IGluY29ycG9yYXRpbmcgYWRkaXRpb25hbCBjb250ZXh0dWFsIHZhcmlhYmxlcywgdXRpbGl6aW5nIGFsdGVybmF0aXZlIG1vZGVsaW5nIG1ldGhvZHMsIGFuZCBleHBhbmRpbmcgdGhlIGFuYWx5c2lzIHRvIG90aGVyIGdlb2dyYXBoaWMgYXJlYXMgdG8gdmFsaWRhdGUgYW5kIGV4dGVuZCB0aGVzZSBmaW5kaW5ncy4=