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
(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 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
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
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=