Scenario

The Governor of Georgia wants to replace subjective parole decisions with a consistent, data-driven policy. You’ve been hired to develop a logistic regression model to predict the risk of recidivism — and recommend a cutoff value that will be adopted statewide.

Sensitivity vs. Specificity

  • Sensitivity: Sensitivity represents the proportion of actual positive cases that the model correctly identifies as positive. A high sensitivity indicates the model has a low rate of false negatives, meaning it more accurately identifies individuals who belong to the positive case. In this specific scenario, sensitivity measures the percentage of recidivists that are correctly predicted as recidivists.In other words, the model detects well on individuals who are likely to re-offend.
  • Specificity: Specificity measures the proportion of actual negative cases that the model correctly predicts as negative. A high specificity indicates the model has a low rate of false positives, meaning identifies individuals who do not belong to the positive case. In this specific scenario, specificity measures the percentage of non-recidivists that are correctly predicted as non-recidivists. In other words, the model detects well on individuals who are unlikely to re-offend.

In my opinion, sensitivity should be prioritized over specificity in this scenario. In parole reform, the primary goal is to reduce recidivism and ensure that individuals released from prison do not pose a threat to public safety. Prioritizing sensitivity means that we take extra caution by keeping those who are likely to re-offend in custody, even if it detains some individuals who might not actually commit another crime. The government could then offer compensation to those later proven innocent after the jury and trial.

In a different scenario, specificity may be more important than the sensitivity. For example, some crucial resources like prison are limited or government is losing trust from the public as too many innocent people was detained. In this case, the government may want to prioritize specificity to ensure that individuals who are not likely to re-offend are not unnecessarily detained. This would help maintain public trust and ensure that resources are allocated efficiently.

Data exploration and Data cleaning

Data cleaning

recidivism_ga <- data %>%
  mutate(recidivism_yes = if_else(Recidivism_Within_3years == "true", 1, 0))

recidivism_ga <- na.omit(recidivism_ga)

Training and Testing Partition

I random split the data into training and testing sets. The training set is used to train the model, while the testing set is used to evaluate the model’s performance. I use 70% of the data for training and 30% for testing.

set.seed(1234)
trainIndex <- createDataPartition(as.factor(recidivism_ga$recidivism_yes), p = 0.7, list = FALSE)
train <- recidivism_ga[trainIndex, ]
test <- recidivism_ga[-trainIndex, ]

Key predictors

  • Age at Release: Age at release is a significant predictor of recidivism. Younger individuals are more likely to re-offend compared to older individuals.

  • Gang Affiliated: Gang affiliation is a significant predictor of recidivism. Individuals who are affiliated with gangs are more likely to re-offend compared to those who are not.

  • Percent Days Employed: Percent days employed is a significant predictor of recidivism. Individuals who are employed for a higher percentage of days are less likely to re-offend compared to those who are unemployed.

  • Education Level: Education level is a significant predictor of recidivism. Individuals with higher education levels are less likely to re-offend compared to those with lower education levels.

  • Prison Offense: Prison offense is a significant predictor of recidivism. Individuals with more serious offenses like murder are more likely to re-offend compared to those with less serious offenses.

Final Model

After testing several key predictors, I got the final model as following:

model <- glm(recidivism_yes ~ Age_at_Release + Gang_Affiliated + Percent_Days_Employed
             + Prison_Offense + Education_Level ,
             data = train, family = "binomial")
coeff_table <- summary(model)$coefficients

# Calculate the Odds Ratios by exponentiating the coefficient estimates
odds_ratio <- exp(coeff_table[, "Estimate"])

# Append the odds_ratio as a new column to your coefficients table
coeff_table <- cbind(coeff_table, Odds_Ratio = odds_ratio)

kable(coeff_table,
      caption = "Logistic Regression Coefficient Summary",
      digits = 3)
Logistic Regression Coefficient Summary
Estimate Std. Error z value Pr(>|z|) Odds_Ratio
(Intercept) 0.481 0.108 4.470 0.000 1.617
Age_at_Release23-27 -0.032 0.081 -0.400 0.689 0.968
Age_at_Release28-32 -0.100 0.082 -1.222 0.222 0.905
Age_at_Release33-37 -0.169 0.084 -2.006 0.045 0.845
Age_at_Release38-42 -0.296 0.089 -3.331 0.001 0.744
Age_at_Release43-47 -0.427 0.091 -4.669 0.000 0.652
Age_at_Release48 or older -0.783 0.087 -8.966 0.000 0.457
Gang_Affiliatedfalse 0.464 0.056 8.271 0.000 1.590
Gang_Affiliatedtrue 1.318 0.078 16.918 0.000 3.735
Percent_Days_Employed -1.375 0.046 -29.579 0.000 0.253
Prison_OffenseDrug -0.019 0.066 -0.279 0.780 0.982
Prison_OffenseOther 0.196 0.077 2.543 0.011 1.217
Prison_OffenseProperty 0.339 0.062 5.427 0.000 1.403
Prison_OffenseViolent/Non-Sex -0.111 0.066 -1.684 0.092 0.895
Prison_OffenseViolent/Sex -0.932 0.116 -8.004 0.000 0.394
Education_LevelHigh School Diploma 0.361 0.052 6.890 0.000 1.434
Education_LevelLess than HS diploma 0.199 0.054 3.672 0.000 1.220

Interpretation of the coefficients

  • Age at Release: Age at release 43-47: An odd ratio 0.652 indicates that individuals aged 43-47 are approximately 0.65 times of the odds of recidivism compared to individuals aged 18-22 (the reference category). In other words, older individuals is associated with a lower likelihood of recidivism as the odd ratio less than 1.
  • Gang Affiliated: Yes: An odd ratio 3.735 indicates that individuals who are gang affiliated are approximately 3.735 times of the odds of recidivism compared to individuals who are unknown. In other words, gang affiliation is associated with a higher likelihood of recidivism as the odd ratio greater than 1.
  • Percent Days Employed: An odd ratio 0.253 indicates that individuals with a 1% increase in the percentage of days employed are approximately 0.253 times of the odds of recidivism compared to individuals with a lower percentage of days employed. In other words, higher employment is associated with a lower likelihood of recidivism as the odd ratio less than 1.
  • Education Level: less than high school diploma: An odd ratio 1.220 indicates that individuals with less than a high school diploma are approximately 1.220 times of the odds of recidivism compared to individuals with a bachelor degree (the reference category). In other words, lower education level is associated with a higher likelihood of recidivism as the odd ratio greater than 1.

Cuteoff Exploration

In this section, I test different thresholds to see how the model performs. I use 0.25, 0.5, and 0.75 as the thresholds to see how the model performs. Different thresholds lead to different balance between sensitivity and specificity. I use the confusion matrix to evaluate the model performance at different thresholds.

Threshold 0.25 and model evaluation

Confusion matrix for the threshold 0.25 is shown below. The model has a sensitivity of 0.99, specificity of 0.06, and a 0.598 overall precision. This model presents a high sensitivity, meaning it is very good at identifying individuals who are likely to re-offend (true positive). However, the specificity is low, indicating that many individuals who are not likely to re-offend are incorrectly classified as recidivists (true negative). This model is useful for identifying high-risk individuals but may lead to unnecessary detentions of low-risk individuals.

test_probs1 <- predict(model, newdata = test, type = "response")
threshold1 <- 0.25
test_preds1 <- ifelse(test_probs1 > threshold1, 1, 0)
confusionMatrix(as.factor(test_preds1), as.factor(test$recidivism_yes), positive = "1")
## Confusion Matrix and Statistics
##
##           Reference
## Prediction    0    1
##          0  156   29
##          1 2320 3337
##
##                Accuracy : 0.5979
##                  95% CI : (0.5852, 0.6105)
##     No Information Rate : 0.5762
##     P-Value [Acc > NIR] : 0.0003946
##
##                   Kappa : 0.062
##
##  Mcnemar's Test P-Value : < 0.00000000000000022
##
##             Sensitivity : 0.9914
##             Specificity : 0.0630
##          Pos Pred Value : 0.5899
##          Neg Pred Value : 0.8432
##              Prevalence : 0.5762
##          Detection Rate : 0.5712
##    Detection Prevalence : 0.9683
##       Balanced Accuracy : 0.5272
##
##        'Positive' Class : 1
## 

Threshold 0.5 and model evaluation

Confusion matrix for the threshold 0.5 is shown below. In contrast with the first one, the 0.5 threshold provide a balance between the sensitivity and specificity. Thus, the model also has a better precision in overall prediction. The model has a sensitivity of 0.75, specificity of 0.5400 , and a 0.666 overall precision.

test_probs2 <- predict(model, newdata = test, type = "response")
threshold2 <- 0.5
test_preds2 <- ifelse(test_probs2 > threshold2, 1, 0)
confusionMatrix(as.factor(test_preds2), as.factor(test$recidivism_yes), positive = "1")
## Confusion Matrix and Statistics
##
##           Reference
## Prediction    0    1
##          0 1337  809
##          1 1139 2557
##
##                Accuracy : 0.6666
##                  95% CI : (0.6543, 0.6786)
##     No Information Rate : 0.5762
##     P-Value [Acc > NIR] : < 0.00000000000000022
##
##                   Kappa : 0.305
##
##  Mcnemar's Test P-Value : 0.00000000000009041
##
##             Sensitivity : 0.7597
##             Specificity : 0.5400
##          Pos Pred Value : 0.6918
##          Neg Pred Value : 0.6230
##              Prevalence : 0.5762
##          Detection Rate : 0.4377
##    Detection Prevalence : 0.6327
##       Balanced Accuracy : 0.6498
##
##        'Positive' Class : 1
## 

Threshold 0.75 and model evaluation

Confusion matrix for the threshold 0.75 is shown below. The model has a sensitivity of 0.28, specificity of 0.90, and a 0.54 overall precision. This model presents a high specificity, meaning it is very good at identifying individuals who are not likely to re-offend (true negative). However, the sensitivity is low, indicating that many individuals who are likely to re-offend are incorrectly classified as non-recidivists (true positive). This model is useful for identifying low-risk individuals but may lead to release of high-risk individuals who likely to re-offend.

test_probs3 <- predict(model, newdata = test, type = "response")
threshold3 <- 0.75
test_preds3 <- ifelse(test_probs3 > threshold3, 1, 0)
confusionMatrix(as.factor(test_preds3), as.factor(test$recidivism_yes), positive = "1")
## Confusion Matrix and Statistics
##
##           Reference
## Prediction    0    1
##          0 2240 2439
##          1  236  927
##
##                Accuracy : 0.5421
##                  95% CI : (0.5292, 0.5549)
##     No Information Rate : 0.5762
##     P-Value [Acc > NIR] : 1
##
##                   Kappa : 0.1611
##
##  Mcnemar's Test P-Value : <0.0000000000000002
##
##             Sensitivity : 0.2754
##             Specificity : 0.9047
##          Pos Pred Value : 0.7971
##          Neg Pred Value : 0.4787
##              Prevalence : 0.5762
##          Detection Rate : 0.1587
##    Detection Prevalence : 0.1991
##       Balanced Accuracy : 0.5900
##
##        'Positive' Class : 1
## 

Threshold Comparison and AUC

Overall, adjust the threshold adjusts the balance between sensitivity and specificity. In general, when set the threshold bigger, the sensitivity decreases and the specificity increases. The threshold of 0.25 provides a high sensitivity but low specificity. The threshold of 0.5 provides a balance between sensitivity and specificity. The threshold of 0.75 provides a high specificity but low sensitivity. In this specific case, I would prefer to the first or the second model threshold, as the first priority is to prevent the criminal to re-offend and efficient using our limited detention spaces.

Comparison of Model Performance at Different Thresholds
Threshold Accuracy Sensitivity Specificity
Threshold 1 0.25 0.598 0.991 0.063
Threshold 2 0.50 0.667 0.760 0.540
Threshold 3 0.75 0.542 0.275 0.905

The overall AUC of the model is 0.75, which indicates that the model has a good ability to distinguish between recidivists and non-recidivists. It also shows the different cut-off values and their corresponding sensitivity and specificity.

roc_obj <- roc(test$recidivism_yes, test_probs2)
plot(roc_obj, col = "blue", main = "ROC Curve with AUC", print.auc = TRUE, print.auc.x = 0.5, print.auc.y = 0.3)

Equity Audit by Race and Age Group

Equity Audit by Race

Our model didn’t include the race as predictors to avoid bias. However, the results of the matrix still indicate that the model perform dramatically differently regarding people from different race group.

As shown in the table below, the model perform similarly in overall precision (around 70%). However, the model has a relative high sensitivity and low specificity in predicting the black population than the white population. The model has a sensitivity of 0.802 and specificity of 0.486 which indicates the black population group are more likely to be misclassified as recidivists (higher true positive). Black population are more likely to detained rather than release. In contrast, the model has a sensitivity of 0.70 and specificity of 0.61 in predicting the white population group. This indicates that the chances for white population to be misclassfied as recidivists is lower than black population. Although we didn;t include any race related predictors in the model, the model still present a bias against the black population group.

group_metric_summary <- test %>%
  mutate(pred = test_preds2, prob = test_probs2) %>%
  group_by(Race) %>%
  summarise(
    Sensitivity = round(sum(pred == 1 & recidivism_yes == 1) / sum(recidivism_yes == 1), 3),
    Specificity = round(sum(pred == 0 & recidivism_yes == 0) / sum(recidivism_yes == 0), 3),
    Precision   = round(sum(pred == 1 & recidivism_yes == 1) / sum(pred == 1), 3),
    Number = n()
  )
kable(group_metric_summary, caption = "Equity Audit by Race")
Equity Audit by Race
Race Sensitivity Specificity Precision Number
BLACK 0.802 0.486 0.690 3364
WHITE 0.700 0.609 0.695 2478

Equity Audit by Age Group

The model include the age group as a predictors as younger population are more likely to re-offend. For the precision,the model perform well when the people age is younger than older, as indicated by high precision rate (0.71 vs 0.55). In addition, younger population group has a relative higher sensitivity and lower specificity than older population group. The model has a sensitivity of 0.903 and specificity of 0.176 in predicting the younger population group (18-22). This indicates that the younger population group are more likely to be misclassified as recidivists (higher true positive). In other words, younger population group are more likely to be detained rather than release. In contrast, the model has a sensitivity of 0.503 and specificity of 0.709 in predicting the older population group (48 or older). This indicates that the chances for older population to be misclassfied as non-recidivists is higher. In other words, older population group are more likely to be release rather than detained. This also indicates the model is potentially biased against the younger population group and have more room to improve.

group_metric_summary2 <- test %>%
  mutate(pred = test_preds2, prob = test_probs2) %>%
  group_by(Age_at_Release) %>%
  summarise(
    Sensitivity = round(sum(pred == 1 & recidivism_yes == 1) / sum(recidivism_yes == 1), 3),
    Specificity = round(sum(pred == 0 & recidivism_yes == 0) / sum(recidivism_yes == 0), 3),
    Precision   = round(sum(pred == 1 & recidivism_yes == 1) / sum(pred == 1), 3),
    Number = n()
  )

kable(group_metric_summary2 %>% rename(Age=Age_at_Release), caption = "Equity Audit by Age Group")
Equity Audit by Age Group
Age Sensitivity Specificity Precision Number
18-22 0.903 0.176 0.716 488
23-27 0.869 0.399 0.736 1185
28-32 0.824 0.453 0.710 1166
33-37 0.738 0.501 0.652 1009
38-42 0.643 0.669 0.692 606
43-47 0.606 0.721 0.687 620
48 or older 0.503 0.709 0.555 768

Cost-Benefit Analysis

Step 1; Estimate the cost

Scnerio 1: Cost of recidivism (released and then reoffernds)

A false negative occurs when an individual is predicted to be low risks and released. However, then commits another offense after release. There are two major costs associated with this scenario: - Direct Criminal Justice Costs: This includes the costs associated with criminal justice system, including police investigation, prosecutions, and trail-related expenses. - Victim and Social Costs: this includes the costs associated with the crime itself, including property damage, medical expenses, lost productivity, and even people lose their life. In addition, there are additional social influences , like people lose trusts to the justice system, a places where the crime happen faces economic decline, and the community is less safe. - Total Cost: The total cost of recidivism is the sum of the direct criminal justice costs and the victim and social costs is hard to estimate. The average cost of recidivism is estimated to be around $100,000 per individual, but also varies between crime types.

Scenario 2: Cost of false positive (detained someone in jail unnecessarily)

A false positive occurs when an individual is predicted to be high risks and detained. However, they were misclassfied as high risks and not likely to re-offense. Only one costs associated with this scenario: - Cost of Detention: This includes the costs associated with detaining an individual in jail, including housing, food, medical care, and other expenses. The average cost of detention is estimated to be around $30,000 per year per individual. Depends on prosecution timeline, the average time in jail for suspect waiting for trail is also varies.

Step 2: Estimate the benefits

Scenario 1: Benefits of preventing recidivism

The benefits of preventing recidivism to make sure the individuals who are likely to re-offend are not released include: - Avoid extra cost of re-offense - Community become safer

Scenario 2: Benefits of releasing low-risk individuals

The benefits of releasing low-risk individuals include: - Government save costs on extra detention costs - People are released can create economic benefits to the society (go to work and make money)

Step 3: Balancing costs and cutoff

The best way to balance the costs is to minimize the total costs. Basically, the total costs is the sum of the costs associated with false negatives and false positives. The total cost can be calculated as follows: \[ \text{Total Cost} = \left( FNR \cdot \text{Cost}_{\text{Recidivism}} \right) + \left( FPR \cdot \text{Cost}_{\text{Detention}} \right) \] Where: - FNR: False Negative Rate - FPR: False Positive Rate - Cost_Recidivism: Cost of recidivism - Cost_Detention: Cost of detention

Since the costs associated with false negative are roughly 3- 3.5 times higher than the false positive, the cutoff should set to be more conservatively (less than 0.5 and greater 0.25).

Policy recommendation

I recommend the government to set the cutoff threshold to 0.5 for following reason:

  • Overall performance: A threshold of 0.5 optimally balances sensitivity and specificity, delivering significantly enhanced precision compared to both 0.25 and 0.75. This balance ensures that the system accurately identifies cases without an excessive rate of misclassification.
  • Economic benefits: The threshold of 0.5 provides a balance between the costs associated with false negatives and false positives. The government can save costs on extra detention costs and avoid the costs associated with recidivism.
  • Equity between different groups: The threshold of 0.5 provides a general balance between specificity and sensitivity between racial group. First, the model not include the racial group as a predictors to avoid racial bias.Second, although the black population is more likely to be detained based on the model performance, the threshold of 0.5 provides a generalize balance between detention and release (0.802 vs. 0.486). Since the cost associate the false release would be higher, the difference between sensitivity and specificity is acceptable. In addition, since age group at release are included as a predictors, the younger age group are more likely to be detained based on the model performance. However, younger generation is more likely to re-offend based on the data, the model is acceptable.

This evidence-based threshold ensures that the government not only achieves optimal performance and cost savings but also upholds principles of fairness and equity.

LS0tCnRpdGxlOiAiQXNzaWdubWVudCA0OiAgTG9naXN0aWMgUmVncmVzc2lvbiBmb3IgUGFyb2xlIFJlZm9ybSIKYXV0aG9yOiAiWmhhbmNoYW8gWWFuZyIKZGF0ZTogJ2ByIFN5cy5EYXRlKClgJwpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRoZW1lOiBjZXJ1bGVhbgogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgdG9jOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGNvZGVfZG93bmxvYWQ6IHllcwogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IHRydWUKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpvcHRpb25zKHNjaXBlbiA9IDk5OSkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoY2FyZXQpCmxpYnJhcnkocFJPQykKbGlicmFyeShrbml0cikKbGlicmFyeShrYWJsZUV4dHJhKQoKZGF0YTwtcmVhZC5jc3YoImRhdGEvTklKX3NfUmVjaWRpdmlzbV9DaGFsbGVuZ2VfRnVsbF9EYXRhc2V0XzIwMjQwNDA3LmNzdiIpCmBgYAoKIyBTY2VuYXJpbwoKVGhlIEdvdmVybm9yIG9mIEdlb3JnaWEgd2FudHMgdG8gcmVwbGFjZSBzdWJqZWN0aXZlIHBhcm9sZSBkZWNpc2lvbnMgd2l0aCBhIGNvbnNpc3RlbnQsIGRhdGEtZHJpdmVuIHBvbGljeS4gWW914oCZdmUgYmVlbiBoaXJlZCB0byBkZXZlbG9wIGEgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbCB0byBwcmVkaWN0IHRoZSByaXNrIG9mIHJlY2lkaXZpc20g4oCUIGFuZCByZWNvbW1lbmQgYSBjdXRvZmYgdmFsdWUgdGhhdCB3aWxsIGJlIGFkb3B0ZWQgc3RhdGV3aWRlLgoKIyBTZW5zaXRpdml0eSB2cy4gU3BlY2lmaWNpdHkKCi0gU2Vuc2l0aXZpdHk6IFNlbnNpdGl2aXR5IHJlcHJlc2VudHMgdGhlIHByb3BvcnRpb24gb2YgYWN0dWFsIHBvc2l0aXZlIGNhc2VzIHRoYXQgdGhlIG1vZGVsIGNvcnJlY3RseSBpZGVudGlmaWVzIGFzIHBvc2l0aXZlLiBBIGhpZ2ggc2Vuc2l0aXZpdHkgaW5kaWNhdGVzIHRoZSBtb2RlbCBoYXMgYSBsb3cgcmF0ZSBvZiBmYWxzZSBuZWdhdGl2ZXMsIG1lYW5pbmcgaXQgbW9yZSBhY2N1cmF0ZWx5IGlkZW50aWZpZXMgaW5kaXZpZHVhbHMgd2hvIGJlbG9uZyB0byB0aGUgcG9zaXRpdmUgY2FzZS4gSW4gdGhpcyBzcGVjaWZpYyBzY2VuYXJpbywgc2Vuc2l0aXZpdHkgbWVhc3VyZXMgdGhlIHBlcmNlbnRhZ2Ugb2YgcmVjaWRpdmlzdHMgdGhhdCBhcmUgY29ycmVjdGx5IHByZWRpY3RlZCBhcyByZWNpZGl2aXN0cy5JbiBvdGhlciB3b3JkcywgdGhlIG1vZGVsIGRldGVjdHMgd2VsbCBvbiBpbmRpdmlkdWFscyB3aG8gYXJlIGxpa2VseSB0byByZS1vZmZlbmQuCi0gU3BlY2lmaWNpdHk6IFNwZWNpZmljaXR5IG1lYXN1cmVzIHRoZSBwcm9wb3J0aW9uIG9mIGFjdHVhbCBuZWdhdGl2ZSBjYXNlcyB0aGF0IHRoZSBtb2RlbCBjb3JyZWN0bHkgcHJlZGljdHMgYXMgbmVnYXRpdmUuIEEgaGlnaCBzcGVjaWZpY2l0eSBpbmRpY2F0ZXMgdGhlIG1vZGVsIGhhcyBhIGxvdyByYXRlIG9mIGZhbHNlIHBvc2l0aXZlcywgbWVhbmluZyBpZGVudGlmaWVzIGluZGl2aWR1YWxzIHdobyBkbyBub3QgYmVsb25nIHRvIHRoZSBwb3NpdGl2ZSBjYXNlLiBJbiB0aGlzIHNwZWNpZmljIHNjZW5hcmlvLCBzcGVjaWZpY2l0eSBtZWFzdXJlcyB0aGUgcGVyY2VudGFnZSBvZiBub24tcmVjaWRpdmlzdHMgdGhhdCBhcmUgY29ycmVjdGx5IHByZWRpY3RlZCBhcyBub24tcmVjaWRpdmlzdHMuIEluIG90aGVyIHdvcmRzLCB0aGUgbW9kZWwgZGV0ZWN0cyB3ZWxsIG9uIGluZGl2aWR1YWxzIHdobyBhcmUgdW5saWtlbHkgdG8gcmUtb2ZmZW5kLgoKSW4gbXkgb3Bpbmlvbiwgc2Vuc2l0aXZpdHkgc2hvdWxkIGJlIHByaW9yaXRpemVkIG92ZXIgc3BlY2lmaWNpdHkgaW4gdGhpcyBzY2VuYXJpby4gSW4gcGFyb2xlIHJlZm9ybSwgdGhlIHByaW1hcnkgZ29hbCBpcyB0byByZWR1Y2UgcmVjaWRpdmlzbSBhbmQgZW5zdXJlIHRoYXQgaW5kaXZpZHVhbHMgcmVsZWFzZWQgZnJvbSBwcmlzb24gZG8gbm90IHBvc2UgYSB0aHJlYXQgdG8gcHVibGljIHNhZmV0eS4gUHJpb3JpdGl6aW5nIHNlbnNpdGl2aXR5IG1lYW5zIHRoYXQgd2UgdGFrZSBleHRyYSBjYXV0aW9uIGJ5IGtlZXBpbmcgdGhvc2Ugd2hvIGFyZSBsaWtlbHkgdG8gcmUtb2ZmZW5kIGluIGN1c3RvZHksIGV2ZW4gaWYgaXQgZGV0YWlucyBzb21lIGluZGl2aWR1YWxzIHdobyBtaWdodCBub3QgYWN0dWFsbHkgY29tbWl0IGFub3RoZXIgY3JpbWUuIFRoZSBnb3Zlcm5tZW50IGNvdWxkIHRoZW4gb2ZmZXIgY29tcGVuc2F0aW9uIHRvIHRob3NlIGxhdGVyIHByb3ZlbiBpbm5vY2VudCBhZnRlciB0aGUganVyeSBhbmQgdHJpYWwuCgpJbiBhIGRpZmZlcmVudCBzY2VuYXJpbywgc3BlY2lmaWNpdHkgbWF5IGJlIG1vcmUgaW1wb3J0YW50IHRoYW4gdGhlIHNlbnNpdGl2aXR5LiBGb3IgZXhhbXBsZSwgc29tZSBjcnVjaWFsIHJlc291cmNlcyBsaWtlIHByaXNvbiBhcmUgbGltaXRlZCBvciBnb3Zlcm5tZW50IGlzIGxvc2luZyB0cnVzdCBmcm9tIHRoZSBwdWJsaWMgYXMgdG9vIG1hbnkgaW5ub2NlbnQgcGVvcGxlIHdhcyBkZXRhaW5lZC4gSW4gdGhpcyBjYXNlLCB0aGUgZ292ZXJubWVudCBtYXkgd2FudCB0byBwcmlvcml0aXplIHNwZWNpZmljaXR5IHRvIGVuc3VyZSB0aGF0IGluZGl2aWR1YWxzIHdobyBhcmUgbm90IGxpa2VseSB0byByZS1vZmZlbmQgYXJlIG5vdCB1bm5lY2Vzc2FyaWx5IGRldGFpbmVkLiBUaGlzIHdvdWxkIGhlbHAgbWFpbnRhaW4gcHVibGljIHRydXN0IGFuZCBlbnN1cmUgdGhhdCByZXNvdXJjZXMgYXJlIGFsbG9jYXRlZCBlZmZpY2llbnRseS4KCiMgRGF0YSBleHBsb3JhdGlvbiBhbmQgRGF0YSBjbGVhbmluZwoKIyMgRGF0YSBjbGVhbmluZwoKYGBge3J9CnJlY2lkaXZpc21fZ2EgPC0gZGF0YSAlPiUKICBtdXRhdGUocmVjaWRpdmlzbV95ZXMgPSBpZl9lbHNlKFJlY2lkaXZpc21fV2l0aGluXzN5ZWFycyA9PSAidHJ1ZSIsIDEsIDApKQoKcmVjaWRpdmlzbV9nYSA8LSBuYS5vbWl0KHJlY2lkaXZpc21fZ2EpCmBgYAoKIyMgVHJhaW5pbmcgYW5kIFRlc3RpbmcgUGFydGl0aW9uCgpJIHJhbmRvbSBzcGxpdCB0aGUgZGF0YSBpbnRvIHRyYWluaW5nIGFuZCB0ZXN0aW5nIHNldHMuIFRoZSB0cmFpbmluZyBzZXQgaXMgdXNlZCB0byB0cmFpbiB0aGUgbW9kZWwsIHdoaWxlIHRoZSB0ZXN0aW5nIHNldCBpcyB1c2VkIHRvIGV2YWx1YXRlIHRoZSBtb2RlbCdzIHBlcmZvcm1hbmNlLiBJIHVzZSA3MCUgb2YgdGhlIGRhdGEgZm9yIHRyYWluaW5nIGFuZCAzMCUgZm9yIHRlc3RpbmcuCgpgYGB7cn0Kc2V0LnNlZWQoMTIzNCkKdHJhaW5JbmRleCA8LSBjcmVhdGVEYXRhUGFydGl0aW9uKGFzLmZhY3RvcihyZWNpZGl2aXNtX2dhJHJlY2lkaXZpc21feWVzKSwgcCA9IDAuNywgbGlzdCA9IEZBTFNFKQp0cmFpbiA8LSByZWNpZGl2aXNtX2dhW3RyYWluSW5kZXgsIF0KdGVzdCA8LSByZWNpZGl2aXNtX2dhWy10cmFpbkluZGV4LCBdCmBgYAoKIyMgS2V5IHByZWRpY3RvcnMKCi0gKipBZ2UgYXQgUmVsZWFzZSoqOiBBZ2UgYXQgcmVsZWFzZSBpcyBhIHNpZ25pZmljYW50IHByZWRpY3RvciBvZiByZWNpZGl2aXNtLiBZb3VuZ2VyIGluZGl2aWR1YWxzIGFyZSBtb3JlIGxpa2VseSB0byByZS1vZmZlbmQgY29tcGFyZWQgdG8gb2xkZXIgaW5kaXZpZHVhbHMuCgpgYGB7ciwgZWNobz1GQUxTRSwgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NH0KZ2dwbG90KHJlY2lkaXZpc21fZ2EsIGFlcyh4ID0gQWdlX2F0X1JlbGVhc2UsIGZpbGwgPSBmYWN0b3IocmVjaWRpdmlzbV95ZXMpKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiY291bnQiLCBwb3NpdGlvbiA9ICJkb2RnZSIsIGFscGhhID0gMC41KSArCiAgbGFicyh0aXRsZSA9ICJBZ2UgYXQgUmVsZWFzZSB2cyBSZWNpZGl2aXNtIiwKICAgICAgIHggPSAiQWdlIGF0IFJlbGVhc2UiLAogICAgICAgeSA9ICJDb3VudCIsCiAgICAgICBmaWxsID0gIlJlY2lkaXZpc20iKSArCiAgdGhlbWVfbWluaW1hbCgpCgoKYGBgCgotICoqR2FuZyBBZmZpbGlhdGVkKio6IEdhbmcgYWZmaWxpYXRpb24gaXMgYSBzaWduaWZpY2FudCBwcmVkaWN0b3Igb2YgcmVjaWRpdmlzbS4gSW5kaXZpZHVhbHMgd2hvIGFyZSBhZmZpbGlhdGVkIHdpdGggZ2FuZ3MgYXJlIG1vcmUgbGlrZWx5IHRvIHJlLW9mZmVuZCBjb21wYXJlZCB0byB0aG9zZSB3aG8gYXJlIG5vdC4KCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD00fQpnZ3Bsb3QocmVjaWRpdmlzbV9nYSwgYWVzKHggPSBHYW5nX0FmZmlsaWF0ZWQsIGZpbGwgPSBmYWN0b3IocmVjaWRpdmlzbV95ZXMpKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiY291bnQiLCBwb3NpdGlvbiA9ICJkb2RnZSIsIGFscGhhID0gMC41KSArCiAgbGFicyh0aXRsZSA9ICJHYW5nIEFmZmlsaWF0ZWQgdnMgUmVjaWRpdmlzbSIsCiAgICAgICB4ID0gIkdhbmcgQWZmaWxpYXRlZCIsCiAgICAgICB5ID0gIkNvdW50IiwKICAgICAgIGZpbGwgPSAiUmVjaWRpdmlzbSIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgotICoqUGVyY2VudCBEYXlzIEVtcGxveWVkKio6IFBlcmNlbnQgZGF5cyBlbXBsb3llZCBpcyBhIHNpZ25pZmljYW50IHByZWRpY3RvciBvZiByZWNpZGl2aXNtLiBJbmRpdmlkdWFscyB3aG8gYXJlIGVtcGxveWVkIGZvciBhIGhpZ2hlciBwZXJjZW50YWdlIG9mIGRheXMgYXJlIGxlc3MgbGlrZWx5IHRvIHJlLW9mZmVuZCBjb21wYXJlZCB0byB0aG9zZSB3aG8gYXJlIHVuZW1wbG95ZWQuCgpgYGB7ciwgZWNobz1GQUxTRSwgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NH0KZ2dwbG90KHJlY2lkaXZpc21fZ2EsIGFlcyh4ID0gZmFjdG9yKHJlY2lkaXZpc21feWVzKSwgeSA9IFBlcmNlbnRfRGF5c19FbXBsb3llZCwgZmlsbCA9IGZhY3RvcihyZWNpZGl2aXNtX3llcykpKSArCiAgZ2VvbV9ib3hwbG90KHdpZHRoPTAuMikgKwogIGxhYnModGl0bGUgPSAiUGVyY2VudCBEYXlzIEVtcGxveWVkIHZzIFJlY2lkaXZpc20iLAogICAgICAgeCA9ICJSZWNpZGl2aXNtIiwKICAgICAgIHkgPSAiUGVyY2VudCBEYXlzIEVtcGxveWVkIikgKwogIHRoZW1lX21pbmltYWwoKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKLSAqKkVkdWNhdGlvbiBMZXZlbCoqOiBFZHVjYXRpb24gbGV2ZWwgaXMgYSBzaWduaWZpY2FudCBwcmVkaWN0b3Igb2YgcmVjaWRpdmlzbS4gSW5kaXZpZHVhbHMgd2l0aCBoaWdoZXIgZWR1Y2F0aW9uIGxldmVscyBhcmUgbGVzcyBsaWtlbHkgdG8gcmUtb2ZmZW5kIGNvbXBhcmVkIHRvIHRob3NlIHdpdGggbG93ZXIgZWR1Y2F0aW9uIGxldmVscy4KYGBge3IsIGVjaG89RkFMU0UsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTR9CmdncGxvdChyZWNpZGl2aXNtX2dhLCBhZXMoeCA9IEVkdWNhdGlvbl9MZXZlbCwgZmlsbCA9IGZhY3RvcihyZWNpZGl2aXNtX3llcykpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJjb3VudCIsIHBvc2l0aW9uID0gImRvZGdlIiwgYWxwaGEgPSAwLjUpICsKICBsYWJzKHRpdGxlID0gIkVkdWNhdGlvbiBMZXZlbCB2cyBSZWNpZGl2aXNtIiwKICAgICAgIHggPSAiRWR1Y2F0aW9uIExldmVsIiwKICAgICAgIHkgPSAiQ291bnQiLAogICAgICAgZmlsbCA9ICJSZWNpZGl2aXNtIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCi0gKipQcmlzb24gT2ZmZW5zZSoqOiBQcmlzb24gb2ZmZW5zZSBpcyBhIHNpZ25pZmljYW50IHByZWRpY3RvciBvZiByZWNpZGl2aXNtLiBJbmRpdmlkdWFscyB3aXRoIG1vcmUgc2VyaW91cyBvZmZlbnNlcyBsaWtlIG11cmRlciBhcmUgbW9yZSBsaWtlbHkgdG8gcmUtb2ZmZW5kIGNvbXBhcmVkIHRvIHRob3NlIHdpdGggbGVzcyBzZXJpb3VzIG9mZmVuc2VzLgpgYGB7ciwgZWNobz1GQUxTRSwgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NH0KZ2dwbG90KHJlY2lkaXZpc21fZ2EsIGFlcyh4ID0gUHJpc29uX09mZmVuc2UsIGZpbGwgPSBmYWN0b3IocmVjaWRpdmlzbV95ZXMpKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiY291bnQiLCBwb3NpdGlvbiA9ICJkb2RnZSIsIGFscGhhID0gMC41KSArCiAgbGFicyh0aXRsZSA9ICJFZHVjYXRpb24gTGV2ZWwgdnMgUmVjaWRpdmlzbSIsCiAgICAgICB4ID0gIkVkdWNhdGlvbiBMZXZlbCIsCiAgICAgICB5ID0gIkNvdW50IiwKICAgICAgIGZpbGwgPSAiUmVjaWRpdmlzbSIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgojIyBGaW5hbCBNb2RlbAoKQWZ0ZXIgdGVzdGluZyBzZXZlcmFsIGtleSBwcmVkaWN0b3JzLCBJIGdvdCB0aGUgZmluYWwgbW9kZWwgYXMgZm9sbG93aW5nOgoKYGBge3Isd2FybmluZz1GQUxTRX0KbW9kZWwgPC0gZ2xtKHJlY2lkaXZpc21feWVzIH4gQWdlX2F0X1JlbGVhc2UgKyBHYW5nX0FmZmlsaWF0ZWQgKyBQZXJjZW50X0RheXNfRW1wbG95ZWQKICAgICAgICAgICAgICsgUHJpc29uX09mZmVuc2UgKyBFZHVjYXRpb25fTGV2ZWwgLAogICAgICAgICAgICAgZGF0YSA9IHRyYWluLCBmYW1pbHkgPSAiYmlub21pYWwiKQpgYGAKYGBge3J9CmNvZWZmX3RhYmxlIDwtIHN1bW1hcnkobW9kZWwpJGNvZWZmaWNpZW50cwoKIyBDYWxjdWxhdGUgdGhlIE9kZHMgUmF0aW9zIGJ5IGV4cG9uZW50aWF0aW5nIHRoZSBjb2VmZmljaWVudCBlc3RpbWF0ZXMKb2Rkc19yYXRpbyA8LSBleHAoY29lZmZfdGFibGVbLCAiRXN0aW1hdGUiXSkKCiMgQXBwZW5kIHRoZSBvZGRzX3JhdGlvIGFzIGEgbmV3IGNvbHVtbiB0byB5b3VyIGNvZWZmaWNpZW50cyB0YWJsZQpjb2VmZl90YWJsZSA8LSBjYmluZChjb2VmZl90YWJsZSwgT2Rkc19SYXRpbyA9IG9kZHNfcmF0aW8pCgprYWJsZShjb2VmZl90YWJsZSwKICAgICAgY2FwdGlvbiA9ICJMb2dpc3RpYyBSZWdyZXNzaW9uIENvZWZmaWNpZW50IFN1bW1hcnkiLAogICAgICBkaWdpdHMgPSAzKQpgYGAKCiMjIyBJbnRlcnByZXRhdGlvbiBvZiB0aGUgY29lZmZpY2llbnRzCgotICoqQWdlIGF0IFJlbGVhc2U6IEFnZSBhdCByZWxlYXNlIDQzLTQ3Kio6IEFuIG9kZCByYXRpbyAwLjY1MiBpbmRpY2F0ZXMgdGhhdCBpbmRpdmlkdWFscyBhZ2VkIDQzLTQ3IGFyZSBhcHByb3hpbWF0ZWx5IDAuNjUgdGltZXMgb2YgdGhlIG9kZHMgb2YgcmVjaWRpdmlzbSBjb21wYXJlZCB0byBpbmRpdmlkdWFscyBhZ2VkIDE4LTIyICh0aGUgcmVmZXJlbmNlIGNhdGVnb3J5KS4gSW4gb3RoZXIgd29yZHMsIG9sZGVyIGluZGl2aWR1YWxzIGlzIGFzc29jaWF0ZWQgd2l0aCBhIGxvd2VyIGxpa2VsaWhvb2Qgb2YgcmVjaWRpdmlzbSBhcyB0aGUgb2RkIHJhdGlvIGxlc3MgdGhhbiAxLgotICoqR2FuZyBBZmZpbGlhdGVkOiBZZXMqKjogQW4gb2RkIHJhdGlvIDMuNzM1IGluZGljYXRlcyB0aGF0IGluZGl2aWR1YWxzIHdobyBhcmUgZ2FuZyBhZmZpbGlhdGVkIGFyZSBhcHByb3hpbWF0ZWx5IDMuNzM1IHRpbWVzIG9mIHRoZSBvZGRzIG9mIHJlY2lkaXZpc20gY29tcGFyZWQgdG8gaW5kaXZpZHVhbHMgd2hvIGFyZSB1bmtub3duLiBJbiBvdGhlciB3b3JkcywgZ2FuZyBhZmZpbGlhdGlvbiBpcyBhc3NvY2lhdGVkIHdpdGggYSBoaWdoZXIgbGlrZWxpaG9vZCBvZiByZWNpZGl2aXNtIGFzIHRoZSBvZGQgcmF0aW8gZ3JlYXRlciB0aGFuIDEuCi0gKipQZXJjZW50IERheXMgRW1wbG95ZWQqKjogQW4gb2RkIHJhdGlvIDAuMjUzIGluZGljYXRlcyB0aGF0IGluZGl2aWR1YWxzIHdpdGggYSAxJSBpbmNyZWFzZSBpbiB0aGUgcGVyY2VudGFnZSBvZiBkYXlzIGVtcGxveWVkIGFyZSBhcHByb3hpbWF0ZWx5IDAuMjUzIHRpbWVzIG9mIHRoZSBvZGRzIG9mIHJlY2lkaXZpc20gY29tcGFyZWQgdG8gaW5kaXZpZHVhbHMgd2l0aCBhIGxvd2VyIHBlcmNlbnRhZ2Ugb2YgZGF5cyBlbXBsb3llZC4gSW4gb3RoZXIgd29yZHMsIGhpZ2hlciBlbXBsb3ltZW50IGlzIGFzc29jaWF0ZWQgd2l0aCBhIGxvd2VyIGxpa2VsaWhvb2Qgb2YgcmVjaWRpdmlzbSBhcyB0aGUgb2RkIHJhdGlvIGxlc3MgdGhhbiAxLgotICoqRWR1Y2F0aW9uIExldmVsOiBsZXNzIHRoYW4gaGlnaCBzY2hvb2wgZGlwbG9tYSoqOiBBbiBvZGQgcmF0aW8gMS4yMjAgaW5kaWNhdGVzIHRoYXQgaW5kaXZpZHVhbHMgd2l0aCBsZXNzIHRoYW4gYSBoaWdoIHNjaG9vbCBkaXBsb21hIGFyZSBhcHByb3hpbWF0ZWx5IDEuMjIwIHRpbWVzIG9mIHRoZSBvZGRzIG9mIHJlY2lkaXZpc20gY29tcGFyZWQgdG8gaW5kaXZpZHVhbHMgd2l0aCBhIGJhY2hlbG9yIGRlZ3JlZSAodGhlIHJlZmVyZW5jZSBjYXRlZ29yeSkuIEluIG90aGVyIHdvcmRzLCBsb3dlciBlZHVjYXRpb24gbGV2ZWwgaXMgYXNzb2NpYXRlZCB3aXRoIGEgaGlnaGVyIGxpa2VsaWhvb2Qgb2YgcmVjaWRpdmlzbSBhcyB0aGUgb2RkIHJhdGlvIGdyZWF0ZXIgdGhhbiAxLgoKIyBDdXRlb2ZmIEV4cGxvcmF0aW9uCkluIHRoaXMgc2VjdGlvbiwgSSB0ZXN0IGRpZmZlcmVudCB0aHJlc2hvbGRzIHRvIHNlZSBob3cgdGhlIG1vZGVsIHBlcmZvcm1zLiBJIHVzZSAwLjI1LCAwLjUsIGFuZCAwLjc1IGFzIHRoZSB0aHJlc2hvbGRzIHRvIHNlZSBob3cgdGhlIG1vZGVsIHBlcmZvcm1zLiBEaWZmZXJlbnQgdGhyZXNob2xkcyBsZWFkIHRvIGRpZmZlcmVudCBiYWxhbmNlIGJldHdlZW4gc2Vuc2l0aXZpdHkgYW5kIHNwZWNpZmljaXR5LiBJIHVzZSB0aGUgY29uZnVzaW9uIG1hdHJpeCB0byBldmFsdWF0ZSB0aGUgbW9kZWwgcGVyZm9ybWFuY2UgYXQgZGlmZmVyZW50IHRocmVzaG9sZHMuCgojIyBUaHJlc2hvbGQgMC4yNSBhbmQgbW9kZWwgZXZhbHVhdGlvbgoKQ29uZnVzaW9uIG1hdHJpeCBmb3IgdGhlIHRocmVzaG9sZCAwLjI1IGlzIHNob3duIGJlbG93LiBUaGUgbW9kZWwgaGFzIGEgc2Vuc2l0aXZpdHkgb2YgMC45OSwgc3BlY2lmaWNpdHkgb2YgMC4wNiwgYW5kIGEgMC41OTggb3ZlcmFsbCBwcmVjaXNpb24uIFRoaXMgbW9kZWwgcHJlc2VudHMgYSBoaWdoIHNlbnNpdGl2aXR5LCBtZWFuaW5nIGl0IGlzIHZlcnkgZ29vZCBhdCBpZGVudGlmeWluZyBpbmRpdmlkdWFscyB3aG8gYXJlIGxpa2VseSB0byByZS1vZmZlbmQgKHRydWUgcG9zaXRpdmUpLiBIb3dldmVyLCB0aGUgc3BlY2lmaWNpdHkgaXMgbG93LCBpbmRpY2F0aW5nIHRoYXQgbWFueSBpbmRpdmlkdWFscyB3aG8gYXJlIG5vdCBsaWtlbHkgdG8gcmUtb2ZmZW5kIGFyZSBpbmNvcnJlY3RseSBjbGFzc2lmaWVkIGFzIHJlY2lkaXZpc3RzICh0cnVlIG5lZ2F0aXZlKS4gVGhpcyBtb2RlbCBpcyB1c2VmdWwgZm9yIGlkZW50aWZ5aW5nIGhpZ2gtcmlzayBpbmRpdmlkdWFscyBidXQgbWF5IGxlYWQgdG8gdW5uZWNlc3NhcnkgZGV0ZW50aW9ucyBvZiBsb3ctcmlzayBpbmRpdmlkdWFscy4KCmBgYHtyLCBtZWFzc2FnZT1GQUxTRX0KdGVzdF9wcm9iczEgPC0gcHJlZGljdChtb2RlbCwgbmV3ZGF0YSA9IHRlc3QsIHR5cGUgPSAicmVzcG9uc2UiKQp0aHJlc2hvbGQxIDwtIDAuMjUKdGVzdF9wcmVkczEgPC0gaWZlbHNlKHRlc3RfcHJvYnMxID4gdGhyZXNob2xkMSwgMSwgMCkKY29uZnVzaW9uTWF0cml4KGFzLmZhY3Rvcih0ZXN0X3ByZWRzMSksIGFzLmZhY3Rvcih0ZXN0JHJlY2lkaXZpc21feWVzKSwgcG9zaXRpdmUgPSAiMSIpCmBgYAoKIyMgVGhyZXNob2xkIDAuNSBhbmQgbW9kZWwgZXZhbHVhdGlvbgoKQ29uZnVzaW9uIG1hdHJpeCBmb3IgdGhlIHRocmVzaG9sZCAwLjUgaXMgc2hvd24gYmVsb3cuIEluIGNvbnRyYXN0IHdpdGggdGhlIGZpcnN0IG9uZSwgdGhlIDAuNSB0aHJlc2hvbGQgcHJvdmlkZSBhIGJhbGFuY2UgYmV0d2VlbiB0aGUgc2Vuc2l0aXZpdHkgYW5kIHNwZWNpZmljaXR5LiAgVGh1cywgdGhlIG1vZGVsIGFsc28gaGFzIGEgYmV0dGVyIHByZWNpc2lvbiBpbiBvdmVyYWxsIHByZWRpY3Rpb24uIFRoZSBtb2RlbCBoYXMgYSBzZW5zaXRpdml0eSBvZiAwLjc1LCBzcGVjaWZpY2l0eSBvZiAwLjU0MDAgLCBhbmQgYSAwLjY2NiBvdmVyYWxsIHByZWNpc2lvbi4KCmBgYHtyfQp0ZXN0X3Byb2JzMiA8LSBwcmVkaWN0KG1vZGVsLCBuZXdkYXRhID0gdGVzdCwgdHlwZSA9ICJyZXNwb25zZSIpCnRocmVzaG9sZDIgPC0gMC41CnRlc3RfcHJlZHMyIDwtIGlmZWxzZSh0ZXN0X3Byb2JzMiA+IHRocmVzaG9sZDIsIDEsIDApCmNvbmZ1c2lvbk1hdHJpeChhcy5mYWN0b3IodGVzdF9wcmVkczIpLCBhcy5mYWN0b3IodGVzdCRyZWNpZGl2aXNtX3llcyksIHBvc2l0aXZlID0gIjEiKQpgYGAKCiMjIFRocmVzaG9sZCAwLjc1IGFuZCBtb2RlbCBldmFsdWF0aW9uCgpDb25mdXNpb24gbWF0cml4IGZvciB0aGUgdGhyZXNob2xkIDAuNzUgaXMgc2hvd24gYmVsb3cuIFRoZSBtb2RlbCBoYXMgYSBzZW5zaXRpdml0eSBvZiAwLjI4LCBzcGVjaWZpY2l0eSBvZiAwLjkwLCBhbmQgYSAwLjU0IG92ZXJhbGwgcHJlY2lzaW9uLiBUaGlzIG1vZGVsIHByZXNlbnRzIGEgaGlnaCBzcGVjaWZpY2l0eSwgbWVhbmluZyBpdCBpcyB2ZXJ5IGdvb2QgYXQgaWRlbnRpZnlpbmcgaW5kaXZpZHVhbHMgd2hvIGFyZSBub3QgbGlrZWx5IHRvIHJlLW9mZmVuZCAodHJ1ZSBuZWdhdGl2ZSkuIEhvd2V2ZXIsIHRoZSBzZW5zaXRpdml0eSBpcyBsb3csIGluZGljYXRpbmcgdGhhdCBtYW55IGluZGl2aWR1YWxzIHdobyBhcmUgbGlrZWx5IHRvIHJlLW9mZmVuZCBhcmUgaW5jb3JyZWN0bHkgY2xhc3NpZmllZCBhcyBub24tcmVjaWRpdmlzdHMgKHRydWUgcG9zaXRpdmUpLiBUaGlzIG1vZGVsIGlzIHVzZWZ1bCBmb3IgaWRlbnRpZnlpbmcgbG93LXJpc2sgaW5kaXZpZHVhbHMgYnV0IG1heSBsZWFkIHRvIHJlbGVhc2Ugb2YgaGlnaC1yaXNrIGluZGl2aWR1YWxzIHdobyBsaWtlbHkgdG8gcmUtb2ZmZW5kLgoKYGBge3J9CnRlc3RfcHJvYnMzIDwtIHByZWRpY3QobW9kZWwsIG5ld2RhdGEgPSB0ZXN0LCB0eXBlID0gInJlc3BvbnNlIikKdGhyZXNob2xkMyA8LSAwLjc1CnRlc3RfcHJlZHMzIDwtIGlmZWxzZSh0ZXN0X3Byb2JzMyA+IHRocmVzaG9sZDMsIDEsIDApCmNvbmZ1c2lvbk1hdHJpeChhcy5mYWN0b3IodGVzdF9wcmVkczMpLCBhcy5mYWN0b3IodGVzdCRyZWNpZGl2aXNtX3llcyksIHBvc2l0aXZlID0gIjEiKQpgYGAKCiMjIFRocmVzaG9sZCBDb21wYXJpc29uIGFuZCBBVUMKCk92ZXJhbGwsIGFkanVzdCB0aGUgdGhyZXNob2xkIGFkanVzdHMgdGhlIGJhbGFuY2UgYmV0d2VlbiBzZW5zaXRpdml0eSBhbmQgc3BlY2lmaWNpdHkuIEluIGdlbmVyYWwsIHdoZW4gc2V0IHRoZSB0aHJlc2hvbGQgYmlnZ2VyLCB0aGUgc2Vuc2l0aXZpdHkgZGVjcmVhc2VzIGFuZCB0aGUgc3BlY2lmaWNpdHkgaW5jcmVhc2VzLiBUaGUgdGhyZXNob2xkIG9mIDAuMjUgcHJvdmlkZXMgYSBoaWdoIHNlbnNpdGl2aXR5IGJ1dCBsb3cgc3BlY2lmaWNpdHkuIFRoZSB0aHJlc2hvbGQgb2YgMC41IHByb3ZpZGVzIGEgYmFsYW5jZSBiZXR3ZWVuIHNlbnNpdGl2aXR5IGFuZCBzcGVjaWZpY2l0eS4gVGhlIHRocmVzaG9sZCBvZiAwLjc1IHByb3ZpZGVzIGEgaGlnaCBzcGVjaWZpY2l0eSBidXQgbG93IHNlbnNpdGl2aXR5LiBJbiB0aGlzIHNwZWNpZmljIGNhc2UsIEkgd291bGQgcHJlZmVyIHRvIHRoZSBmaXJzdCBvciB0aGUgc2Vjb25kIG1vZGVsIHRocmVzaG9sZCwgYXMgdGhlIGZpcnN0IHByaW9yaXR5IGlzIHRvIHByZXZlbnQgdGhlIGNyaW1pbmFsIHRvIHJlLW9mZmVuZCBhbmQgZWZmaWNpZW50IHVzaW5nIG91ciBsaW1pdGVkIGRldGVudGlvbiBzcGFjZXMuCgpgYGB7ciwgZWNobz1GQUxTRX0KIyBMb2FkIHJlcXVpcmVkIGxpYnJhcnkKbGlicmFyeShjYXJldCkKbGlicmFyeShrbml0cikKCiMgQXNzdW1lIHlvdXIgbW9kZWwgaGFzIGJlZW4gdHJhaW5lZCBhbmQgeW91IGFscmVhZHkgaGF2ZSB0ZXN0X3Byb2JzMyBjb21wdXRlZCBhczoKdGVzdF9wcm9iczQgPC0gcHJlZGljdChtb2RlbCwgbmV3ZGF0YSA9IHRlc3QsIHR5cGUgPSAicmVzcG9uc2UiKQoKIyBEZWZpbmUgdGhlIHRocmVzaG9sZHMgd2Ugd2FudCB0byBjb21wYXJlCnRocmVzaG9sZHMgPC0gYygwLjI1LCAwLjUsIDAuNzUpCgojIEluaXRpYWxpemUgYW4gZW1wdHkgZGF0YSBmcmFtZSB0byBzdG9yZSB0aGUgcGVyZm9ybWFuY2UgbWV0cmljcwpyZXN1bHRzIDwtIGRhdGEuZnJhbWUoVGhyZXNob2xkID0gbnVtZXJpYygpLAogICAgICAgICAgICAgICAgICAgICAgQWNjdXJhY3kgPSBudW1lcmljKCksCiAgICAgICAgICAgICAgICAgICAgICBTZW5zaXRpdml0eSA9IG51bWVyaWMoKSwKICAgICAgICAgICAgICAgICAgICAgIFNwZWNpZmljaXR5ID0gbnVtZXJpYygpLAogICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQoKIyBMb29wIG92ZXIgZWFjaCB0aHJlc2hvbGQKZm9yKHRoIGluIHRocmVzaG9sZHMpIHsKICAjIENyZWF0ZSBwcmVkaWN0ZWQgY2xhc3NlcyBiYXNlZCBvbiB0aGUgY3VycmVudCB0aHJlc2hvbGQKICB0ZXN0X3ByZWRzIDwtIGlmZWxzZSh0ZXN0X3Byb2JzNCA+IHRoLCAxLCAwKQoKICAjIEdldCB0aGUgY29uZnVzaW9uIG1hdHJpeCBmb3IgdGhlIGN1cnJlbnQgdGhyZXNob2xkCiAgY20gPC0gY29uZnVzaW9uTWF0cml4KGFzLmZhY3Rvcih0ZXN0X3ByZWRzKSwgYXMuZmFjdG9yKHRlc3QkcmVjaWRpdmlzbV95ZXMpLCBwb3NpdGl2ZSA9ICIxIikKCiAgIyBBcHBlbmQgdGhlIG1ldHJpY3MgdG8gdGhlIHJlc3VsdHMgZGF0YSBmcmFtZQogIHJlc3VsdHMgPC0gcmJpbmQocmVzdWx0cywKICAgICAgICAgICAgICAgICAgIGRhdGEuZnJhbWUoVGhyZXNob2xkID0gdGgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFjY3VyYWN5ID0gcm91bmQoY20kb3ZlcmFsbFsiQWNjdXJhY3kiXSwgMyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNlbnNpdGl2aXR5ID0gcm91bmQoY20kYnlDbGFzc1siU2Vuc2l0aXZpdHkiXSwgMyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNwZWNpZmljaXR5ID0gcm91bmQoY20kYnlDbGFzc1siU3BlY2lmaWNpdHkiXSwgMykpKQp9CnJvdy5uYW1lcyhyZXN1bHRzKSA8LSBjKCJUaHJlc2hvbGQgMSIsICJUaHJlc2hvbGQgMiIsICJUaHJlc2hvbGQgMyIpCiMgRGlzcGxheSB0aGUgcmVzdWx0cyBpbiBhIG5pY2UgdGFibGUKa2FibGUocmVzdWx0cywgY2FwdGlvbiA9ICJDb21wYXJpc29uIG9mIE1vZGVsIFBlcmZvcm1hbmNlIGF0IERpZmZlcmVudCBUaHJlc2hvbGRzIikKCmBgYAoKVGhlIG92ZXJhbGwgQVVDIG9mIHRoZSBtb2RlbCBpcyAwLjc1LCB3aGljaCBpbmRpY2F0ZXMgdGhhdCB0aGUgbW9kZWwgaGFzIGEgZ29vZCBhYmlsaXR5IHRvIGRpc3Rpbmd1aXNoIGJldHdlZW4gcmVjaWRpdmlzdHMgYW5kIG5vbi1yZWNpZGl2aXN0cy4gSXQgYWxzbyBzaG93cyB0aGUgZGlmZmVyZW50IGN1dC1vZmYgdmFsdWVzIGFuZCB0aGVpciBjb3JyZXNwb25kaW5nIHNlbnNpdGl2aXR5IGFuZCBzcGVjaWZpY2l0eS4KCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQpyb2Nfb2JqIDwtIHJvYyh0ZXN0JHJlY2lkaXZpc21feWVzLCB0ZXN0X3Byb2JzMikKcGxvdChyb2Nfb2JqLCBjb2wgPSAiYmx1ZSIsIG1haW4gPSAiUk9DIEN1cnZlIHdpdGggQVVDIiwgcHJpbnQuYXVjID0gVFJVRSwgcHJpbnQuYXVjLnggPSAwLjUsIHByaW50LmF1Yy55ID0gMC4zKQpgYGAKCiMgRXF1aXR5IEF1ZGl0IGJ5IFJhY2UgYW5kIEFnZSBHcm91cAoKIyMgRXF1aXR5IEF1ZGl0IGJ5IFJhY2UKCk91ciBtb2RlbCBkaWRuJ3QgaW5jbHVkZSB0aGUgcmFjZSBhcyBwcmVkaWN0b3JzIHRvIGF2b2lkIGJpYXMuIEhvd2V2ZXIsIHRoZSByZXN1bHRzIG9mIHRoZSBtYXRyaXggc3RpbGwgaW5kaWNhdGUgdGhhdCB0aGUgbW9kZWwgcGVyZm9ybSBkcmFtYXRpY2FsbHkgZGlmZmVyZW50bHkgcmVnYXJkaW5nIHBlb3BsZSBmcm9tIGRpZmZlcmVudCByYWNlIGdyb3VwLgoKQXMgc2hvd24gaW4gdGhlIHRhYmxlIGJlbG93LCB0aGUgbW9kZWwgcGVyZm9ybSBzaW1pbGFybHkgaW4gb3ZlcmFsbCBwcmVjaXNpb24gKGFyb3VuZCA3MCUpLiBIb3dldmVyLCB0aGUgbW9kZWwgaGFzIGEgcmVsYXRpdmUgaGlnaCBzZW5zaXRpdml0eSBhbmQgbG93IHNwZWNpZmljaXR5IGluIHByZWRpY3RpbmcgdGhlIGJsYWNrIHBvcHVsYXRpb24gdGhhbiB0aGUgd2hpdGUgcG9wdWxhdGlvbi4gVGhlIG1vZGVsIGhhcyBhIHNlbnNpdGl2aXR5IG9mIDAuODAyIGFuZCBzcGVjaWZpY2l0eSBvZiAwLjQ4NiB3aGljaCBpbmRpY2F0ZXMgdGhlIGJsYWNrIHBvcHVsYXRpb24gZ3JvdXAgYXJlIG1vcmUgbGlrZWx5IHRvIGJlIG1pc2NsYXNzaWZpZWQgYXMgcmVjaWRpdmlzdHMgKGhpZ2hlciB0cnVlIHBvc2l0aXZlKS4gQmxhY2sgcG9wdWxhdGlvbiBhcmUgbW9yZSBsaWtlbHkgdG8gZGV0YWluZWQgcmF0aGVyIHRoYW4gcmVsZWFzZS4gSW4gY29udHJhc3QsIHRoZSBtb2RlbCBoYXMgYSBzZW5zaXRpdml0eSBvZiAwLjcwIGFuZCBzcGVjaWZpY2l0eSBvZiAwLjYxIGluIHByZWRpY3RpbmcgdGhlIHdoaXRlIHBvcHVsYXRpb24gZ3JvdXAuIFRoaXMgaW5kaWNhdGVzIHRoYXQgdGhlIGNoYW5jZXMgZm9yIHdoaXRlIHBvcHVsYXRpb24gdG8gYmUgbWlzY2xhc3NmaWVkIGFzIHJlY2lkaXZpc3RzIGlzIGxvd2VyIHRoYW4gYmxhY2sgcG9wdWxhdGlvbi4gQWx0aG91Z2ggd2UgZGlkbjt0IGluY2x1ZGUgYW55IHJhY2UgcmVsYXRlZCBwcmVkaWN0b3JzIGluIHRoZSBtb2RlbCwgdGhlIG1vZGVsIHN0aWxsIHByZXNlbnQgYSBiaWFzIGFnYWluc3QgdGhlIGJsYWNrIHBvcHVsYXRpb24gZ3JvdXAuCgpgYGB7cn0KZ3JvdXBfbWV0cmljX3N1bW1hcnkgPC0gdGVzdCAlPiUKICBtdXRhdGUocHJlZCA9IHRlc3RfcHJlZHMyLCBwcm9iID0gdGVzdF9wcm9iczIpICU+JQogIGdyb3VwX2J5KFJhY2UpICU+JQogIHN1bW1hcmlzZSgKICAgIFNlbnNpdGl2aXR5ID0gcm91bmQoc3VtKHByZWQgPT0gMSAmIHJlY2lkaXZpc21feWVzID09IDEpIC8gc3VtKHJlY2lkaXZpc21feWVzID09IDEpLCAzKSwKICAgIFNwZWNpZmljaXR5ID0gcm91bmQoc3VtKHByZWQgPT0gMCAmIHJlY2lkaXZpc21feWVzID09IDApIC8gc3VtKHJlY2lkaXZpc21feWVzID09IDApLCAzKSwKICAgIFByZWNpc2lvbiAgID0gcm91bmQoc3VtKHByZWQgPT0gMSAmIHJlY2lkaXZpc21feWVzID09IDEpIC8gc3VtKHByZWQgPT0gMSksIDMpLAogICAgTnVtYmVyID0gbigpCiAgKQprYWJsZShncm91cF9tZXRyaWNfc3VtbWFyeSwgY2FwdGlvbiA9ICJFcXVpdHkgQXVkaXQgYnkgUmFjZSIpCmBgYAoKIyMgRXF1aXR5IEF1ZGl0IGJ5IEFnZSBHcm91cAoKVGhlIG1vZGVsIGluY2x1ZGUgdGhlIGFnZSBncm91cCBhcyBhIHByZWRpY3RvcnMgYXMgeW91bmdlciBwb3B1bGF0aW9uIGFyZSBtb3JlIGxpa2VseSB0byByZS1vZmZlbmQuIEZvciB0aGUgcHJlY2lzaW9uLHRoZSBtb2RlbCBwZXJmb3JtIHdlbGwgd2hlbiB0aGUgcGVvcGxlIGFnZSBpcyB5b3VuZ2VyIHRoYW4gb2xkZXIsIGFzIGluZGljYXRlZCBieSBoaWdoIHByZWNpc2lvbiByYXRlICgwLjcxIHZzIDAuNTUpLiBJbiBhZGRpdGlvbiwgeW91bmdlciBwb3B1bGF0aW9uIGdyb3VwIGhhcyBhIHJlbGF0aXZlIGhpZ2hlciBzZW5zaXRpdml0eSBhbmQgbG93ZXIgc3BlY2lmaWNpdHkgdGhhbiBvbGRlciBwb3B1bGF0aW9uIGdyb3VwLiBUaGUgbW9kZWwgaGFzIGEgc2Vuc2l0aXZpdHkgb2YgMC45MDMgYW5kIHNwZWNpZmljaXR5IG9mIDAuMTc2IGluIHByZWRpY3RpbmcgdGhlIHlvdW5nZXIgcG9wdWxhdGlvbiBncm91cCAoMTgtMjIpLiBUaGlzIGluZGljYXRlcyB0aGF0IHRoZSB5b3VuZ2VyIHBvcHVsYXRpb24gZ3JvdXAgYXJlIG1vcmUgbGlrZWx5IHRvIGJlIG1pc2NsYXNzaWZpZWQgYXMgcmVjaWRpdmlzdHMgKGhpZ2hlciB0cnVlIHBvc2l0aXZlKS4gSW4gb3RoZXIgd29yZHMsIHlvdW5nZXIgcG9wdWxhdGlvbiBncm91cCBhcmUgbW9yZSBsaWtlbHkgdG8gYmUgZGV0YWluZWQgcmF0aGVyIHRoYW4gcmVsZWFzZS4gSW4gY29udHJhc3QsIHRoZSBtb2RlbCBoYXMgYSBzZW5zaXRpdml0eSBvZiAwLjUwMyBhbmQgc3BlY2lmaWNpdHkgb2YgMC43MDkgIGluIHByZWRpY3RpbmcgdGhlIG9sZGVyIHBvcHVsYXRpb24gZ3JvdXAgKDQ4IG9yIG9sZGVyKS4gVGhpcyBpbmRpY2F0ZXMgdGhhdCB0aGUgY2hhbmNlcyBmb3Igb2xkZXIgcG9wdWxhdGlvbiB0byBiZSBtaXNjbGFzc2ZpZWQgYXMgbm9uLXJlY2lkaXZpc3RzIGlzIGhpZ2hlci4gSW4gb3RoZXIgd29yZHMsIG9sZGVyIHBvcHVsYXRpb24gZ3JvdXAgYXJlIG1vcmUgbGlrZWx5IHRvIGJlIHJlbGVhc2UgcmF0aGVyIHRoYW4gZGV0YWluZWQuIFRoaXMgYWxzbyBpbmRpY2F0ZXMgdGhlIG1vZGVsIGlzIHBvdGVudGlhbGx5IGJpYXNlZCBhZ2FpbnN0IHRoZSB5b3VuZ2VyIHBvcHVsYXRpb24gZ3JvdXAgYW5kIGhhdmUgbW9yZSByb29tIHRvIGltcHJvdmUuCgpgYGB7cn0KZ3JvdXBfbWV0cmljX3N1bW1hcnkyIDwtIHRlc3QgJT4lCiAgbXV0YXRlKHByZWQgPSB0ZXN0X3ByZWRzMiwgcHJvYiA9IHRlc3RfcHJvYnMyKSAlPiUKICBncm91cF9ieShBZ2VfYXRfUmVsZWFzZSkgJT4lCiAgc3VtbWFyaXNlKAogICAgU2Vuc2l0aXZpdHkgPSByb3VuZChzdW0ocHJlZCA9PSAxICYgcmVjaWRpdmlzbV95ZXMgPT0gMSkgLyBzdW0ocmVjaWRpdmlzbV95ZXMgPT0gMSksIDMpLAogICAgU3BlY2lmaWNpdHkgPSByb3VuZChzdW0ocHJlZCA9PSAwICYgcmVjaWRpdmlzbV95ZXMgPT0gMCkgLyBzdW0ocmVjaWRpdmlzbV95ZXMgPT0gMCksIDMpLAogICAgUHJlY2lzaW9uICAgPSByb3VuZChzdW0ocHJlZCA9PSAxICYgcmVjaWRpdmlzbV95ZXMgPT0gMSkgLyBzdW0ocHJlZCA9PSAxKSwgMyksCiAgICBOdW1iZXIgPSBuKCkKICApCgprYWJsZShncm91cF9tZXRyaWNfc3VtbWFyeTIgJT4lIHJlbmFtZShBZ2U9QWdlX2F0X1JlbGVhc2UpLCBjYXB0aW9uID0gIkVxdWl0eSBBdWRpdCBieSBBZ2UgR3JvdXAiKQoKYGBgCgojIENvc3QtQmVuZWZpdCBBbmFseXNpcwoKIyMgU3RlcCAxOyBFc3RpbWF0ZSB0aGUgY29zdAoKIyMjIFNjbmVyaW8gMTogQ29zdCBvZiByZWNpZGl2aXNtIChyZWxlYXNlZCBhbmQgdGhlbiByZW9mZmVybmRzKQoKQSBmYWxzZSBuZWdhdGl2ZSBvY2N1cnMgd2hlbiBhbiBpbmRpdmlkdWFsIGlzIHByZWRpY3RlZCB0byBiZSBsb3cgcmlza3MgYW5kIHJlbGVhc2VkLiBIb3dldmVyLCB0aGVuIGNvbW1pdHMgYW5vdGhlciBvZmZlbnNlIGFmdGVyIHJlbGVhc2UuIFRoZXJlIGFyZSB0d28gbWFqb3IgY29zdHMgYXNzb2NpYXRlZCB3aXRoIHRoaXMgc2NlbmFyaW86Ci0gKipEaXJlY3QgQ3JpbWluYWwgSnVzdGljZSBDb3N0cyoqOiBUaGlzIGluY2x1ZGVzIHRoZSBjb3N0cyBhc3NvY2lhdGVkIHdpdGggY3JpbWluYWwganVzdGljZSBzeXN0ZW0sIGluY2x1ZGluZyBwb2xpY2UgaW52ZXN0aWdhdGlvbiwgcHJvc2VjdXRpb25zLCBhbmQgdHJhaWwtcmVsYXRlZCBleHBlbnNlcy4KLSAqKlZpY3RpbSBhbmQgU29jaWFsIENvc3RzKio6IHRoaXMgaW5jbHVkZXMgdGhlIGNvc3RzIGFzc29jaWF0ZWQgd2l0aCB0aGUgY3JpbWUgaXRzZWxmLCBpbmNsdWRpbmcgcHJvcGVydHkgZGFtYWdlLCBtZWRpY2FsIGV4cGVuc2VzLCBsb3N0IHByb2R1Y3Rpdml0eSwgYW5kIGV2ZW4gcGVvcGxlIGxvc2UgdGhlaXIgbGlmZS4gSW4gYWRkaXRpb24sIHRoZXJlIGFyZSBhZGRpdGlvbmFsIHNvY2lhbCBpbmZsdWVuY2VzICwgbGlrZSBwZW9wbGUgbG9zZSB0cnVzdHMgdG8gdGhlIGp1c3RpY2Ugc3lzdGVtLCBhIHBsYWNlcyB3aGVyZSB0aGUgY3JpbWUgaGFwcGVuIGZhY2VzIGVjb25vbWljIGRlY2xpbmUsIGFuZCB0aGUgY29tbXVuaXR5IGlzIGxlc3Mgc2FmZS4KLSAqKlRvdGFsIENvc3QqKjogVGhlIHRvdGFsIGNvc3Qgb2YgcmVjaWRpdmlzbSBpcyB0aGUgc3VtIG9mIHRoZSBkaXJlY3QgY3JpbWluYWwganVzdGljZSBjb3N0cyBhbmQgdGhlIHZpY3RpbSBhbmQgc29jaWFsIGNvc3RzIGlzIGhhcmQgdG8gZXN0aW1hdGUuIFRoZSBhdmVyYWdlIGNvc3Qgb2YgcmVjaWRpdmlzbSBpcyBlc3RpbWF0ZWQgdG8gYmUgYXJvdW5kICQxMDAsMDAwIHBlciBpbmRpdmlkdWFsLCBidXQgYWxzbyB2YXJpZXMgYmV0d2VlbiBjcmltZSB0eXBlcy4KCiMjIyBTY2VuYXJpbyAyOiBDb3N0IG9mIGZhbHNlIHBvc2l0aXZlIChkZXRhaW5lZCBzb21lb25lIGluIGphaWwgdW5uZWNlc3NhcmlseSkKCkEgZmFsc2UgcG9zaXRpdmUgb2NjdXJzIHdoZW4gYW4gaW5kaXZpZHVhbCBpcyBwcmVkaWN0ZWQgdG8gYmUgaGlnaCByaXNrcyBhbmQgZGV0YWluZWQuIEhvd2V2ZXIsIHRoZXkgd2VyZSBtaXNjbGFzc2ZpZWQgYXMgaGlnaCByaXNrcyBhbmQgbm90IGxpa2VseSB0byByZS1vZmZlbnNlLiBPbmx5IG9uZSBjb3N0cyBhc3NvY2lhdGVkIHdpdGggdGhpcyBzY2VuYXJpbzoKLSAqKkNvc3Qgb2YgRGV0ZW50aW9uKio6IFRoaXMgaW5jbHVkZXMgdGhlIGNvc3RzIGFzc29jaWF0ZWQgd2l0aCBkZXRhaW5pbmcgYW4gaW5kaXZpZHVhbCBpbiBqYWlsLCBpbmNsdWRpbmcgaG91c2luZywgZm9vZCwgbWVkaWNhbCBjYXJlLCBhbmQgb3RoZXIgZXhwZW5zZXMuIFRoZSBhdmVyYWdlIGNvc3Qgb2YgZGV0ZW50aW9uIGlzIGVzdGltYXRlZCB0byBiZSBhcm91bmQgJDMwLDAwMCBwZXIgeWVhciBwZXIgaW5kaXZpZHVhbC4gRGVwZW5kcyBvbiBwcm9zZWN1dGlvbiB0aW1lbGluZSwgdGhlIGF2ZXJhZ2UgdGltZSBpbiBqYWlsIGZvciBzdXNwZWN0IHdhaXRpbmcgZm9yIHRyYWlsIGlzIGFsc28gdmFyaWVzLgoKIyMgU3RlcCAyOiBFc3RpbWF0ZSB0aGUgYmVuZWZpdHMKCiMjIyBTY2VuYXJpbyAxOiBCZW5lZml0cyBvZiBwcmV2ZW50aW5nIHJlY2lkaXZpc20KClRoZSBiZW5lZml0cyBvZiBwcmV2ZW50aW5nIHJlY2lkaXZpc20gdG8gbWFrZSBzdXJlIHRoZSBpbmRpdmlkdWFscyB3aG8gYXJlIGxpa2VseSB0byByZS1vZmZlbmQgYXJlIG5vdCByZWxlYXNlZCBpbmNsdWRlOgotIEF2b2lkIGV4dHJhIGNvc3Qgb2YgcmUtb2ZmZW5zZQotIENvbW11bml0eSBiZWNvbWUgc2FmZXIKCiMjIyBTY2VuYXJpbyAyOiBCZW5lZml0cyBvZiByZWxlYXNpbmcgbG93LXJpc2sgaW5kaXZpZHVhbHMKClRoZSBiZW5lZml0cyBvZiByZWxlYXNpbmcgbG93LXJpc2sgaW5kaXZpZHVhbHMgaW5jbHVkZToKLSBHb3Zlcm5tZW50IHNhdmUgY29zdHMgb24gZXh0cmEgZGV0ZW50aW9uIGNvc3RzCi0gUGVvcGxlIGFyZSByZWxlYXNlZCBjYW4gY3JlYXRlIGVjb25vbWljIGJlbmVmaXRzIHRvIHRoZSBzb2NpZXR5IChnbyB0byB3b3JrIGFuZCBtYWtlIG1vbmV5KQoKIyMgU3RlcCAzOiBCYWxhbmNpbmcgY29zdHMgYW5kIGN1dG9mZgoKVGhlIGJlc3Qgd2F5IHRvIGJhbGFuY2UgdGhlIGNvc3RzIGlzIHRvIG1pbmltaXplIHRoZSB0b3RhbCBjb3N0cy4gQmFzaWNhbGx5LCB0aGUgdG90YWwgY29zdHMgaXMgdGhlIHN1bSBvZiB0aGUgY29zdHMgYXNzb2NpYXRlZCB3aXRoIGZhbHNlIG5lZ2F0aXZlcyBhbmQgZmFsc2UgcG9zaXRpdmVzLiBUaGUgdG90YWwgY29zdCBjYW4gYmUgY2FsY3VsYXRlZCBhcyBmb2xsb3dzOgokJApcdGV4dHtUb3RhbCBDb3N0fSA9IFxsZWZ0KCBGTlIgXGNkb3QgXHRleHR7Q29zdH1fe1x0ZXh0e1JlY2lkaXZpc219fSBccmlnaHQpICsgXGxlZnQoIEZQUiBcY2RvdCBcdGV4dHtDb3N0fV97XHRleHR7RGV0ZW50aW9ufX0gXHJpZ2h0KQokJApXaGVyZToKLSBGTlI6IEZhbHNlIE5lZ2F0aXZlIFJhdGUKLSBGUFI6IEZhbHNlIFBvc2l0aXZlIFJhdGUKLSBDb3N0X1JlY2lkaXZpc206IENvc3Qgb2YgcmVjaWRpdmlzbQotIENvc3RfRGV0ZW50aW9uOiBDb3N0IG9mIGRldGVudGlvbgoKU2luY2UgdGhlIGNvc3RzIGFzc29jaWF0ZWQgd2l0aCBmYWxzZSBuZWdhdGl2ZSBhcmUgcm91Z2hseSAzLSAzLjUgdGltZXMgaGlnaGVyIHRoYW4gdGhlIGZhbHNlIHBvc2l0aXZlLCB0aGUgY3V0b2ZmIHNob3VsZCBzZXQgdG8gYmUgbW9yZSBjb25zZXJ2YXRpdmVseSAobGVzcyB0aGFuIDAuNSBhbmQgZ3JlYXRlciAwLjI1KS4KCiMgUG9saWN5IHJlY29tbWVuZGF0aW9uCgpJIHJlY29tbWVuZCB0aGUgZ292ZXJubWVudCB0byBzZXQgdGhlIGN1dG9mZiB0aHJlc2hvbGQgdG8gMC41IGZvciBmb2xsb3dpbmcgcmVhc29uOgoKLSAqKk92ZXJhbGwgcGVyZm9ybWFuY2UqKjogQSB0aHJlc2hvbGQgb2YgMC41IG9wdGltYWxseSBiYWxhbmNlcyBzZW5zaXRpdml0eSBhbmQgc3BlY2lmaWNpdHksIGRlbGl2ZXJpbmcgc2lnbmlmaWNhbnRseSBlbmhhbmNlZCBwcmVjaXNpb24gY29tcGFyZWQgdG8gYm90aCAwLjI1IGFuZCAwLjc1LiBUaGlzIGJhbGFuY2UgZW5zdXJlcyB0aGF0IHRoZSBzeXN0ZW0gYWNjdXJhdGVseSBpZGVudGlmaWVzIGNhc2VzIHdpdGhvdXQgYW4gZXhjZXNzaXZlIHJhdGUgb2YgbWlzY2xhc3NpZmljYXRpb24uCi0gKipFY29ub21pYyBiZW5lZml0cyoqOiBUaGUgdGhyZXNob2xkIG9mIDAuNSBwcm92aWRlcyBhIGJhbGFuY2UgYmV0d2VlbiB0aGUgY29zdHMgYXNzb2NpYXRlZCB3aXRoIGZhbHNlIG5lZ2F0aXZlcyBhbmQgZmFsc2UgcG9zaXRpdmVzLiBUaGUgZ292ZXJubWVudCBjYW4gc2F2ZSBjb3N0cyBvbiBleHRyYSBkZXRlbnRpb24gY29zdHMgYW5kIGF2b2lkIHRoZSBjb3N0cyBhc3NvY2lhdGVkIHdpdGggcmVjaWRpdmlzbS4KLSAqKkVxdWl0eSBiZXR3ZWVuIGRpZmZlcmVudCBncm91cHMqKjogVGhlIHRocmVzaG9sZCBvZiAwLjUgcHJvdmlkZXMgYSBnZW5lcmFsIGJhbGFuY2UgYmV0d2VlbiBzcGVjaWZpY2l0eSBhbmQgc2Vuc2l0aXZpdHkgYmV0d2VlbiByYWNpYWwgZ3JvdXAuIEZpcnN0LCB0aGUgbW9kZWwgbm90IGluY2x1ZGUgdGhlIHJhY2lhbCBncm91cCBhcyBhIHByZWRpY3RvcnMgdG8gYXZvaWQgcmFjaWFsIGJpYXMuU2Vjb25kLCBhbHRob3VnaCB0aGUgYmxhY2sgcG9wdWxhdGlvbiBpcyBtb3JlIGxpa2VseSB0byBiZSBkZXRhaW5lZCBiYXNlZCBvbiB0aGUgbW9kZWwgcGVyZm9ybWFuY2UsIHRoZSB0aHJlc2hvbGQgb2YgMC41IHByb3ZpZGVzIGEgZ2VuZXJhbGl6ZSBiYWxhbmNlIGJldHdlZW4gZGV0ZW50aW9uIGFuZCByZWxlYXNlICgwLjgwMiB2cy4gMC40ODYpLiBTaW5jZSB0aGUgY29zdCBhc3NvY2lhdGUgdGhlIGZhbHNlIHJlbGVhc2Ugd291bGQgYmUgaGlnaGVyLCB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHNlbnNpdGl2aXR5IGFuZCBzcGVjaWZpY2l0eSBpcyBhY2NlcHRhYmxlLiBJbiBhZGRpdGlvbiwgc2luY2UgYWdlIGdyb3VwIGF0IHJlbGVhc2UgYXJlIGluY2x1ZGVkIGFzIGEgcHJlZGljdG9ycywgdGhlIHlvdW5nZXIgYWdlIGdyb3VwIGFyZSBtb3JlIGxpa2VseSB0byBiZSBkZXRhaW5lZCBiYXNlZCBvbiB0aGUgbW9kZWwgcGVyZm9ybWFuY2UuIEhvd2V2ZXIsIHlvdW5nZXIgZ2VuZXJhdGlvbiBpcyBtb3JlIGxpa2VseSB0byByZS1vZmZlbmQgYmFzZWQgb24gdGhlIGRhdGEsIHRoZSBtb2RlbCBpcyBhY2NlcHRhYmxlLgoKVGhpcyBldmlkZW5jZS1iYXNlZCB0aHJlc2hvbGQgZW5zdXJlcyB0aGF0IHRoZSBnb3Zlcm5tZW50IG5vdCBvbmx5IGFjaGlldmVzIG9wdGltYWwgcGVyZm9ybWFuY2UgYW5kIGNvc3Qgc2F2aW5ncyBidXQgYWxzbyB1cGhvbGRzIHByaW5jaXBsZXMgb2YgZmFpcm5lc3MgYW5kIGVxdWl0eS4=