Predicting parole violators In many criminal justice systems around the world, inmates deemed not to be a threat to society are released from prison under the parole system prior to completing their sentence. They are still considered to be serving their sentence while on parole, and they can be returned to prison if they violate the terms of their parole.

Parole boards are charged with identifying which inmates are good candidates for release on parole. They seek to release inmates who will not commit additional crimes after release. In this problem, we will build and validate a model that predicts if an inmate will violate the terms of his or her parole. Such a model could be useful to a parole board when deciding to approve or deny an application for parole.

For this prediction task, we will use data from the United States 2004 National Corrections Reporting Program, a nationwide census of parole releases that occurred during 2004. We limited our focus to parolees who served no more than 6 months in prison and whose maximum sentence for all charges did not exceed 18 months. The dataset contains all such parolees who either successfully completed their term of parole during 2004 or those who violated the terms of their parole during that year. The dataset contains the following variables:


Section 1

1.1 - Loading the Dataset

Load the dataset parole.csv into a data frame called parole, and investigate it using the str() and summary() functions.

How many parolees are contained in the dataset?

setwd("D:/Data")
The working directory was changed to D:/Data inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
parole<-read.csv("Unit3/parole.csv",header = TRUE,sep = ",")
str(parole)
'data.frame':   675 obs. of  9 variables:
 $ male             : int  1 0 1 1 1 1 1 0 0 1 ...
 $ race             : int  1 1 2 1 2 2 1 1 1 2 ...
 $ age              : num  33.2 39.7 29.5 22.4 21.6 46.7 31 24.6 32.6 29.1 ...
 $ state            : int  1 1 1 1 1 1 1 1 1 1 ...
 $ time.served      : num  5.5 5.4 5.6 5.7 5.4 6 6 4.8 4.5 4.7 ...
 $ max.sentence     : int  18 12 12 18 12 18 18 12 13 12 ...
 $ multiple.offenses: int  0 0 0 0 0 0 0 0 0 0 ...
 $ crime            : int  4 3 3 1 1 4 3 1 3 2 ...
 $ violator         : int  0 0 0 0 0 0 0 0 0 0 ...
summary(parole)
      male             race            age            state        time.served   
 Min.   :0.0000   Min.   :1.000   Min.   :18.40   Min.   :1.000   Min.   :0.000  
 1st Qu.:1.0000   1st Qu.:1.000   1st Qu.:25.35   1st Qu.:2.000   1st Qu.:3.250  
 Median :1.0000   Median :1.000   Median :33.70   Median :3.000   Median :4.400  
 Mean   :0.8074   Mean   :1.424   Mean   :34.51   Mean   :2.887   Mean   :4.198  
 3rd Qu.:1.0000   3rd Qu.:2.000   3rd Qu.:42.55   3rd Qu.:4.000   3rd Qu.:5.200  
 Max.   :1.0000   Max.   :2.000   Max.   :67.00   Max.   :4.000   Max.   :6.000  
  max.sentence   multiple.offenses     crime          violator     
 Min.   : 1.00   Min.   :0.0000    Min.   :1.000   Min.   :0.0000  
 1st Qu.:12.00   1st Qu.:0.0000    1st Qu.:1.000   1st Qu.:0.0000  
 Median :12.00   Median :1.0000    Median :2.000   Median :0.0000  
 Mean   :13.06   Mean   :0.5363    Mean   :2.059   Mean   :0.1156  
 3rd Qu.:15.00   3rd Qu.:1.0000    3rd Qu.:3.000   3rd Qu.:0.0000  
 Max.   :18.00   Max.   :1.0000    Max.   :4.000   Max.   :1.0000  
nrow(parole)
[1] 675

1.2 - Loading the Dataset

How many of the parolees in the dataset violated the terms of their parole?

sum(parole$violator==1)
[1] 78

Section 2

2.1 - Preparing the Dataset

You should be familiar with unordered factors (if not, review the Week 2 homework problem “Reading Test Scores”). Which variables in this dataset are unordered factors with at least three levels? Select all that apply.

str(parole)
'data.frame':   675 obs. of  9 variables:
 $ male             : int  1 0 1 1 1 1 1 0 0 1 ...
 $ race             : int  1 1 2 1 2 2 1 1 1 2 ...
 $ age              : num  33.2 39.7 29.5 22.4 21.6 46.7 31 24.6 32.6 29.1 ...
 $ state            : int  1 1 1 1 1 1 1 1 1 1 ...
 $ time.served      : num  5.5 5.4 5.6 5.7 5.4 6 6 4.8 4.5 4.7 ...
 $ max.sentence     : int  18 12 12 18 12 18 18 12 13 12 ...
 $ multiple.offenses: int  0 0 0 0 0 0 0 0 0 0 ...
 $ crime            : int  4 3 3 1 1 4 3 1 3 2 ...
 $ violator         : int  0 0 0 0 0 0 0 0 0 0 ...
#crime,state

2.2 - Preparing the Dataset

n the last subproblem, we identified variables that are unordered factors with at least 3 levels, so we need to convert them to factors for our prediction problem (we introduced this idea in the “Reading Test Scores” problem last week). Using the as.factor() function, convert these variables to factors. Keep in mind that we are not changing the values, just the way R understands them (the values are still numbers).

How does the output of summary() change for a factor variable as compared to a numerical variable?

parole$state<-as.factor(parole$state)
parole$crime<-as.factor(parole$crime)
summary(parole)
      male             race            age        state    time.served     max.sentence  
 Min.   :0.0000   Min.   :1.000   Min.   :18.40   1:143   Min.   :0.000   Min.   : 1.00  
 1st Qu.:1.0000   1st Qu.:1.000   1st Qu.:25.35   2:120   1st Qu.:3.250   1st Qu.:12.00  
 Median :1.0000   Median :1.000   Median :33.70   3: 82   Median :4.400   Median :12.00  
 Mean   :0.8074   Mean   :1.424   Mean   :34.51   4:330   Mean   :4.198   Mean   :13.06  
 3rd Qu.:1.0000   3rd Qu.:2.000   3rd Qu.:42.55           3rd Qu.:5.200   3rd Qu.:15.00  
 Max.   :1.0000   Max.   :2.000   Max.   :67.00           Max.   :6.000   Max.   :18.00  
 multiple.offenses crime      violator     
 Min.   :0.0000    1:315   Min.   :0.0000  
 1st Qu.:0.0000    2:106   1st Qu.:0.0000  
 Median :1.0000    3:153   Median :0.0000  
 Mean   :0.5363    4:101   Mean   :0.1156  
 3rd Qu.:1.0000            3rd Qu.:0.0000  
 Max.   :1.0000            Max.   :1.0000  
#The output becomes similar to that of the table() function applied to that variable

Section 3

3.1 - Splitting into a Training and Testing Set

To ensure consistent training/testing set splits, run the following 5 lines of code (do not include the line numbers at the beginning):

  1. set.seed(144)

  2. library(caTools)

  3. split = sample.split(parole$violator, SplitRatio = 0.7)

  4. train = subset(parole, split == TRUE)

  5. test = subset(parole, split == FALSE)

Roughly what proportion of parolees have been allocated to the training and testing sets?

set.seed(144)
library(caTools)
split = sample.split(parole$violator, SplitRatio = 0.7)
train = subset(parole, split == TRUE)
test = subset(parole, split == FALSE)
#70% to the training set, 30% to the testing set

3.2 - Splitting into a Training and Testing Set

Now, suppose you re-ran lines [1]-[5] of Problem 3.1. What would you expect?

#The exact same training/testing set split as the first execution of [1]-[5]

If you instead ONLY re-ran lines [3]-[5], what would you expect?

#A different training/testing set split from the first execution of [1]-[5]

If you instead called set.seed() with a different number and then re-ran lines [3]-[5] of Problem 3.1, what would you expect?

#A different training/testing set split from the first execution of [1]-[5] 正确

Section 4

4.1 - Building a Logistic Regression Model

If you tested other training/testing set splits in the previous section, please re-run the original 5 lines of code to obtain the original split.

Using glm (and remembering the parameter family=“binomial”), train a logistic regression model on the training set. Your dependent variable is “violator”, and you should use all of the other variables as independent variables.

What variables are significant in this model? Significant variables should have a least one star, or should have a probability less than 0.05 (the column Pr(>|z|) in the summary output). Select all that apply.

model1 <- glm(violator ~.,data=train,family="binomial")
Warning message:
In strsplit(code, "\n", fixed = TRUE) :
  input string 1 is invalid in this locale
summary (model1)

Call:
glm(formula = violator ~ ., family = "binomial", data = train)

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-1.7041  -0.4236  -0.2719  -0.1690   2.8375  

Coefficients:
                    Estimate Std. Error z value Pr(>|z|)    
(Intercept)       -4.2411574  1.2938852  -3.278  0.00105 ** 
male               0.3869904  0.4379613   0.884  0.37690    
race               0.8867192  0.3950660   2.244  0.02480 *  
age               -0.0001756  0.0160852  -0.011  0.99129    
state2             0.4433007  0.4816619   0.920  0.35739    
state3             0.8349797  0.5562704   1.501  0.13335    
state4            -3.3967878  0.6115860  -5.554 2.79e-08 ***
time.served       -0.1238867  0.1204230  -1.029  0.30359    
max.sentence       0.0802954  0.0553747   1.450  0.14705    
multiple.offenses  1.6119919  0.3853050   4.184 2.87e-05 ***
crime2             0.6837143  0.5003550   1.366  0.17180    
crime3            -0.2781054  0.4328356  -0.643  0.52054    
crime4            -0.0117627  0.5713035  -0.021  0.98357    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 340.04  on 472  degrees of freedom
Residual deviance: 251.48  on 460  degrees of freedom
AIC: 277.48

Number of Fisher Scoring iterations: 6
#race,state4,multiple.offenses

4.2 - Building a Logistic Regression Model(***)

What can we say based on the coefficient of the multiple.offenses variable?

The following two properties might be useful to you when answering this question:

  1. If we have a coefficient c for a variable, then that means the log odds (or Logit) are increased by c for a unit increase in the variable.

  2. If we have a coefficient c for a variable, then that means the odds are multiplied by e^c for a unit increase in the variable.

#Our model predicts that a parolee who committed multiple offenses has 5.01 times higher odds of being a violator than a parolee who did not commit multiple offenses but is otherwise identical. 

4.3 - Building a Logistic Regression Model

Consider a parolee who is male, of white race, aged 50 years at prison release, from the state of Maryland, served 3 months, had a maximum sentence of 12 months, did not commit multiple offenses, and committed a larceny. Answer the following questions based on the model’s predictions for this individual. (HINT: You should use the coefficients of your model, the Logistic Response Function, and the Odds equation to solve this problem.)

According to the model, what are the odds this individual is a violator?

-4.2411574 + 0.3869904*1 + 0.8867192*1 - 0.0001756*50 + 0.4433007*0 + 0.8349797*0 - 3.3967878*0 - 0.1238867*3 + 0.0802954*12 + 1.6119919*0 + 0.6837143*1 - 0.2781054*0 - 0.0117627*0
[1] -1.700629
exp(-1.700629)
[1] 0.1825687

According to the model, what is the probability this individual is a violator?

1/(1+exp(-1.700629))
[1] 0.8456169

Section 5

5.1 - Evaluating the Model on the Testing Set

Use the predict() function to obtain the model’s predicted probabilities for parolees in the testing set, remembering to pass type=“response”.

What is the maximum predicted probability of a violation?

pre=predict(model1,newdata = test,type="response")
summary(pre)
    Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
0.002334 0.023777 0.057905 0.146576 0.147452 0.907279 
#0.907279

5.2 - Evaluating the Model on the Testing Set

In the following questions, evaluate the model’s predictions on the test set using a threshold of 0.5.

What is the model’s sensitivity?

table(test$violator,pre>=0.5)
   
    FALSE TRUE
  0   167   12
  1    11   12
12/(12+11)
[1] 0.5217391

What is the model’s specificity?

167/(12+167)
[1] 0.9329609

What is the model’s accuracy?

(12+167)/(167+12+11+12)
[1] 0.8861386

5.3 - Evaluating the Model on the Testing Set

What is the accuracy of a simple model that predicts that every parolee is a non-violator?

table(test$violator)

  0   1 
179  23 
179/(179+23)
[1] 0.8861386

5.4 - Evaluating the Model on the Testing Set

Consider a parole board using the model to predict whether parolees will be violators or not. The job of a parole board is to make sure that a prisoner is ready to be released into free society, and therefore parole boards tend to be particularily concerned about releasing prisoners who will violate their parole. Which of the following most likely describes their preferences and best course of action?

#The board assigns more cost to a false negative than a false positive, and should therefore use a logistic regression cutoff less than 0.5.

5.5 - Evaluating the Model on the Testing Set

Which of the following is the most accurate assessment of the value of the logistic regression model with a cutoff 0.5 to a parole board, based on the model’s accuracy as compared to the simple baseline model?

#The model is likely of value to the board, and using a different logistic regression cutoff is likely to improve the model's value.

5.6 - Evaluating the Model on the Testing Set

Using the ROCR package, what is the AUC value for the model?

library(ROCR)
pre_ROC = prediction(pre, test$violator)
as.numeric(performance(pre_ROC, "auc")@y.values)
[1] 0.8945834

5.7 - Evaluating the Model on the Testing Set

Describe the meaning of AUC in this context.

#The probability the model can correctly differentiate between a randomly selected parole violator and a randomly selected parole non-violator

Section 6

6.1 - Identifying Bias in Observational Data

Our goal has been to predict the outcome of a parole decision, and we used a publicly available dataset of parole releases for predictions. In this final problem, we’ll evaluate a potential source of bias associated with our analysis. It is always important to evaluate a dataset for possible sources of bias.

The dataset contains all individuals released from parole in 2004, either due to completing their parole term or violating the terms of their parole. However, it does not contain parolees who neither violated their parole nor completed their term in 2004, causing non-violators to be underrepresented. This is called “selection bias” or “selecting on the dependent variable,” because only a subset of all relevant parolees were included in our analysis, based on our dependent variable in this analysis (parole violation). How could we improve our dataset to best address selection bias?

#We should use a dataset tracking a group of parolees from the start of their parole until either they violated parole or they completed their term.
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpQcmVkaWN0aW5nIHBhcm9sZSB2aW9sYXRvcnMNCkluIG1hbnkgY3JpbWluYWwganVzdGljZSBzeXN0ZW1zIGFyb3VuZCB0aGUgd29ybGQsIGlubWF0ZXMgZGVlbWVkIG5vdCB0byBiZSBhIHRocmVhdCB0byBzb2NpZXR5IGFyZSByZWxlYXNlZCBmcm9tIHByaXNvbiB1bmRlciB0aGUgcGFyb2xlIHN5c3RlbSBwcmlvciB0byBjb21wbGV0aW5nIHRoZWlyIHNlbnRlbmNlLiBUaGV5IGFyZSBzdGlsbCBjb25zaWRlcmVkIHRvIGJlIHNlcnZpbmcgdGhlaXIgc2VudGVuY2Ugd2hpbGUgb24gcGFyb2xlLCBhbmQgdGhleSBjYW4gYmUgcmV0dXJuZWQgdG8gcHJpc29uIGlmIHRoZXkgdmlvbGF0ZSB0aGUgdGVybXMgb2YgdGhlaXIgcGFyb2xlLg0KDQpQYXJvbGUgYm9hcmRzIGFyZSBjaGFyZ2VkIHdpdGggaWRlbnRpZnlpbmcgd2hpY2ggaW5tYXRlcyBhcmUgZ29vZCBjYW5kaWRhdGVzIGZvciByZWxlYXNlIG9uIHBhcm9sZS4gVGhleSBzZWVrIHRvIHJlbGVhc2UgaW5tYXRlcyB3aG8gd2lsbCBub3QgY29tbWl0IGFkZGl0aW9uYWwgY3JpbWVzIGFmdGVyIHJlbGVhc2UuIEluIHRoaXMgcHJvYmxlbSwgd2Ugd2lsbCBidWlsZCBhbmQgdmFsaWRhdGUgYSBtb2RlbCB0aGF0IHByZWRpY3RzIGlmIGFuIGlubWF0ZSB3aWxsIHZpb2xhdGUgdGhlIHRlcm1zIG9mIGhpcyBvciBoZXIgcGFyb2xlLiBTdWNoIGEgbW9kZWwgY291bGQgYmUgdXNlZnVsIHRvIGEgcGFyb2xlIGJvYXJkIHdoZW4gZGVjaWRpbmcgdG8gYXBwcm92ZSBvciBkZW55IGFuIGFwcGxpY2F0aW9uIGZvciBwYXJvbGUuDQoNCkZvciB0aGlzIHByZWRpY3Rpb24gdGFzaywgd2Ugd2lsbCB1c2UgZGF0YSBmcm9tIHRoZSBVbml0ZWQgU3RhdGVzIDIwMDQgTmF0aW9uYWwgQ29ycmVjdGlvbnMgUmVwb3J0aW5nIFByb2dyYW0sIGEgbmF0aW9ud2lkZSBjZW5zdXMgb2YgcGFyb2xlIHJlbGVhc2VzIHRoYXQgb2NjdXJyZWQgZHVyaW5nIDIwMDQuIFdlIGxpbWl0ZWQgb3VyIGZvY3VzIHRvIHBhcm9sZWVzIHdobyBzZXJ2ZWQgbm8gbW9yZSB0aGFuIDYgbW9udGhzIGluIHByaXNvbiBhbmQgd2hvc2UgbWF4aW11bSBzZW50ZW5jZSBmb3IgYWxsIGNoYXJnZXMgZGlkIG5vdCBleGNlZWQgMTggbW9udGhzLiBUaGUgZGF0YXNldCBjb250YWlucyBhbGwgc3VjaCBwYXJvbGVlcyB3aG8gZWl0aGVyIHN1Y2Nlc3NmdWxseSBjb21wbGV0ZWQgdGhlaXIgdGVybSBvZiBwYXJvbGUgZHVyaW5nIDIwMDQgb3IgdGhvc2Ugd2hvIHZpb2xhdGVkIHRoZSB0ZXJtcyBvZiB0aGVpciBwYXJvbGUgZHVyaW5nIHRoYXQgeWVhci4gVGhlIGRhdGFzZXQgY29udGFpbnMgdGhlIGZvbGxvd2luZyB2YXJpYWJsZXM6DQoNCisgbWFsZTogMSBpZiB0aGUgcGFyb2xlZSBpcyBtYWxlLCAwIGlmIGZlbWFsZQ0KKyByYWNlOiAxIGlmIHRoZSBwYXJvbGVlIGlzIHdoaXRlLCAyIG90aGVyd2lzZQ0KKyBhZ2U6IHRoZSBwYXJvbGVlJ3MgYWdlIChpbiB5ZWFycykgd2hlbiBoZSBvciBzaGUgd2FzIHJlbGVhc2VkIGZyb20gcHJpc29uDQorIHN0YXRlOiBhIGNvZGUgZm9yIHRoZSBwYXJvbGVlJ3Mgc3RhdGUuIDIgaXMgS2VudHVja3ksIDMgaXMgTG91aXNpYW5hLCA0IGlzIFZpcmdpbmlhLCBhbmQgMSBpcyBhbnkgKyArIG90aGVyIHN0YXRlLiBUaGUgdGhyZWUgc3RhdGVzIHdlcmUgc2VsZWN0ZWQgZHVlIHRvIGhhdmluZyBhIGhpZ2ggcmVwcmVzZW50YXRpb24gaW4gdGhlIGRhdGFzZXQuDQorIHRpbWUuc2VydmVkOiB0aGUgbnVtYmVyIG9mIG1vbnRocyB0aGUgcGFyb2xlZSBzZXJ2ZWQgaW4gcHJpc29uIChsaW1pdGVkIGJ5IHRoZSBpbmNsdXNpb24gY3JpdGVyaWEgdG8gbm90IGV4Y2VlZCA2IG1vbnRocykuDQorIG1heC5zZW50ZW5jZTogdGhlIG1heGltdW0gc2VudGVuY2UgbGVuZ3RoIGZvciBhbGwgY2hhcmdlcywgaW4gbW9udGhzIChsaW1pdGVkIGJ5IHRoZSBpbmNsdXNpb24gY3JpdGVyaWEgdG8gbm90IGV4Y2VlZCAxOCBtb250aHMpLg0KKyBtdWx0aXBsZS5vZmZlbnNlczogMSBpZiB0aGUgcGFyb2xlZSB3YXMgaW5jYXJjZXJhdGVkIGZvciBtdWx0aXBsZSBvZmZlbnNlcywgMCBvdGhlcndpc2UuDQorIGNyaW1lOiBhIGNvZGUgZm9yIHRoZSBwYXJvbGVlJ3MgbWFpbiBjcmltZSBsZWFkaW5nIHRvIGluY2FyY2VyYXRpb24uIDIgaXMgbGFyY2VueSwgMyBpcyBkcnVnLXJlbGF0ZWQgY3JpbWUsIDQgaXMgZHJpdmluZy1yZWxhdGVkIGNyaW1lLCBhbmQgMSBpcyBhbnkgb3RoZXIgY3JpbWUuDQorIHZpb2xhdG9yOiAxIGlmIHRoZSBwYXJvbGVlIHZpb2xhdGVkIHRoZSBwYXJvbGUsIGFuZCAwIGlmIHRoZSBwYXJvbGVlIGNvbXBsZXRlZCB0aGUgcGFyb2xlIHdpdGhvdXQgdmlvbGF0aW9uLg0KDQotLS0NCg0KIyMjIFNlY3Rpb24gMQ0KIyMjIyAxLjEgLSBMb2FkaW5nIHRoZSBEYXRhc2V0DQoNCkxvYWQgdGhlIGRhdGFzZXQgcGFyb2xlLmNzdiBpbnRvIGEgZGF0YSBmcmFtZSBjYWxsZWQgcGFyb2xlLCBhbmQgaW52ZXN0aWdhdGUgaXQgdXNpbmcgdGhlIHN0cigpIGFuZCBzdW1tYXJ5KCkgZnVuY3Rpb25zLg0KDQpIb3cgbWFueSBwYXJvbGVlcyBhcmUgY29udGFpbmVkIGluIHRoZSBkYXRhc2V0Pw0KDQpgYGB7cn0NCnNldHdkKCJEOi9EYXRhIikNCnBhcm9sZTwtcmVhZC5jc3YoIlVuaXQzL3Bhcm9sZS5jc3YiLGhlYWRlciA9IFRSVUUsc2VwID0gIiwiKQ0Kc3RyKHBhcm9sZSkNCnN1bW1hcnkocGFyb2xlKQ0KbnJvdyhwYXJvbGUpDQpgYGANCiMjIyMgMS4yIC0gTG9hZGluZyB0aGUgRGF0YXNldA0KDQpIb3cgbWFueSBvZiB0aGUgcGFyb2xlZXMgaW4gdGhlIGRhdGFzZXQgdmlvbGF0ZWQgdGhlIHRlcm1zIG9mIHRoZWlyIHBhcm9sZT8NCg0KYGBge3J9DQpzdW0ocGFyb2xlJHZpb2xhdG9yPT0xKQ0KYGBgDQoNCg0KDQoNCiMjIyBTZWN0aW9uIDINCiMjIyMgMi4xIC0gUHJlcGFyaW5nIHRoZSBEYXRhc2V0DQoNCllvdSBzaG91bGQgYmUgZmFtaWxpYXIgd2l0aCB1bm9yZGVyZWQgZmFjdG9ycyAoaWYgbm90LCByZXZpZXcgdGhlIFdlZWsgMiBob21ld29yayBwcm9ibGVtICJSZWFkaW5nIFRlc3QgU2NvcmVzIikuIFdoaWNoIHZhcmlhYmxlcyBpbiB0aGlzIGRhdGFzZXQgYXJlIHVub3JkZXJlZCBmYWN0b3JzIHdpdGggYXQgbGVhc3QgdGhyZWUgbGV2ZWxzPyBTZWxlY3QgYWxsIHRoYXQgYXBwbHkuDQoNCmBgYHtyfQ0Kc3RyKHBhcm9sZSkNCiNjcmltZSxzdGF0ZQ0KYGBgDQojIyMjIDIuMiAtIFByZXBhcmluZyB0aGUgRGF0YXNldA0KDQpuIHRoZSBsYXN0IHN1YnByb2JsZW0sIHdlIGlkZW50aWZpZWQgdmFyaWFibGVzIHRoYXQgYXJlIHVub3JkZXJlZCBmYWN0b3JzIHdpdGggYXQgbGVhc3QgMyBsZXZlbHMsIHNvIHdlIG5lZWQgdG8gY29udmVydCB0aGVtIHRvIGZhY3RvcnMgZm9yIG91ciBwcmVkaWN0aW9uIHByb2JsZW0gKHdlIGludHJvZHVjZWQgdGhpcyBpZGVhIGluIHRoZSAiUmVhZGluZyBUZXN0IFNjb3JlcyIgcHJvYmxlbSBsYXN0IHdlZWspLiBVc2luZyB0aGUgYXMuZmFjdG9yKCkgZnVuY3Rpb24sIGNvbnZlcnQgdGhlc2UgdmFyaWFibGVzIHRvIGZhY3RvcnMuIEtlZXAgaW4gbWluZCB0aGF0IHdlIGFyZSBub3QgY2hhbmdpbmcgdGhlIHZhbHVlcywganVzdCB0aGUgd2F5IFIgdW5kZXJzdGFuZHMgdGhlbSAodGhlIHZhbHVlcyBhcmUgc3RpbGwgbnVtYmVycykuDQoNCkhvdyBkb2VzIHRoZSBvdXRwdXQgb2Ygc3VtbWFyeSgpIGNoYW5nZSBmb3IgYSBmYWN0b3IgdmFyaWFibGUgYXMgY29tcGFyZWQgdG8gYSBudW1lcmljYWwgdmFyaWFibGU/DQoNCmBgYHtyfQ0KcGFyb2xlJHN0YXRlPC1hcy5mYWN0b3IocGFyb2xlJHN0YXRlKQ0KcGFyb2xlJGNyaW1lPC1hcy5mYWN0b3IocGFyb2xlJGNyaW1lKQ0Kc3VtbWFyeShwYXJvbGUpDQoNCiNUaGUgb3V0cHV0IGJlY29tZXMgc2ltaWxhciB0byB0aGF0IG9mIHRoZSB0YWJsZSgpIGZ1bmN0aW9uIGFwcGxpZWQgdG8gdGhhdCB2YXJpYWJsZQ0KYGBgDQojIyMgU2VjdGlvbiAzDQojIyMjIDMuMSAtIFNwbGl0dGluZyBpbnRvIGEgVHJhaW5pbmcgYW5kIFRlc3RpbmcgU2V0DQoNClRvIGVuc3VyZSBjb25zaXN0ZW50IHRyYWluaW5nL3Rlc3Rpbmcgc2V0IHNwbGl0cywgcnVuIHRoZSBmb2xsb3dpbmcgNSBsaW5lcyBvZiBjb2RlIChkbyBub3QgaW5jbHVkZSB0aGUgbGluZSBudW1iZXJzIGF0IHRoZSBiZWdpbm5pbmcpOg0KDQoxKSBzZXQuc2VlZCgxNDQpDQoNCjIpIGxpYnJhcnkoY2FUb29scykNCg0KMykgc3BsaXQgPSBzYW1wbGUuc3BsaXQocGFyb2xlJHZpb2xhdG9yLCBTcGxpdFJhdGlvID0gMC43KQ0KDQo0KSB0cmFpbiA9IHN1YnNldChwYXJvbGUsIHNwbGl0ID09IFRSVUUpDQoNCjUpIHRlc3QgPSBzdWJzZXQocGFyb2xlLCBzcGxpdCA9PSBGQUxTRSkNCg0KUm91Z2hseSB3aGF0IHByb3BvcnRpb24gb2YgcGFyb2xlZXMgaGF2ZSBiZWVuIGFsbG9jYXRlZCB0byB0aGUgdHJhaW5pbmcgYW5kIHRlc3Rpbmcgc2V0cz8NCg0KYGBge3J9DQpzZXQuc2VlZCgxNDQpDQpsaWJyYXJ5KGNhVG9vbHMpDQpzcGxpdCA9IHNhbXBsZS5zcGxpdChwYXJvbGUkdmlvbGF0b3IsIFNwbGl0UmF0aW8gPSAwLjcpDQp0cmFpbiA9IHN1YnNldChwYXJvbGUsIHNwbGl0ID09IFRSVUUpDQp0ZXN0ID0gc3Vic2V0KHBhcm9sZSwgc3BsaXQgPT0gRkFMU0UpDQoNCiM3MCUgdG8gdGhlIHRyYWluaW5nIHNldCwgMzAlIHRvIHRoZSB0ZXN0aW5nIHNldA0KYGBgDQojIyMjIDMuMiAtIFNwbGl0dGluZyBpbnRvIGEgVHJhaW5pbmcgYW5kIFRlc3RpbmcgU2V0DQoNCk5vdywgc3VwcG9zZSB5b3UgcmUtcmFuIGxpbmVzIFsxXS1bNV0gb2YgUHJvYmxlbSAzLjEuIFdoYXQgd291bGQgeW91IGV4cGVjdD8NCmBgYHtyfQ0KI1RoZSBleGFjdCBzYW1lIHRyYWluaW5nL3Rlc3Rpbmcgc2V0IHNwbGl0IGFzIHRoZSBmaXJzdCBleGVjdXRpb24gb2YgWzFdLVs1XQ0KYGBgDQpJZiB5b3UgaW5zdGVhZCBPTkxZIHJlLXJhbiBsaW5lcyBbM10tWzVdLCB3aGF0IHdvdWxkIHlvdSBleHBlY3Q/DQpgYGB7cn0NCiNBIGRpZmZlcmVudCB0cmFpbmluZy90ZXN0aW5nIHNldCBzcGxpdCBmcm9tIHRoZSBmaXJzdCBleGVjdXRpb24gb2YgWzFdLVs1XQ0KYGBgDQpJZiB5b3UgaW5zdGVhZCBjYWxsZWQgc2V0LnNlZWQoKSB3aXRoIGEgZGlmZmVyZW50IG51bWJlciBhbmQgdGhlbiByZS1yYW4gbGluZXMgWzNdLVs1XSBvZiBQcm9ibGVtIDMuMSwgd2hhdCB3b3VsZCB5b3UgZXhwZWN0Pw0KYGBge3J9DQojQSBkaWZmZXJlbnQgdHJhaW5pbmcvdGVzdGluZyBzZXQgc3BsaXQgZnJvbSB0aGUgZmlyc3QgZXhlY3V0aW9uIG9mIFsxXS1bNV0g5q2j56GuDQpgYGANCg0KIyMjIFNlY3Rpb24gNA0KIyMjIyA0LjEgLSBCdWlsZGluZyBhIExvZ2lzdGljIFJlZ3Jlc3Npb24gTW9kZWwNCg0KSWYgeW91IHRlc3RlZCBvdGhlciB0cmFpbmluZy90ZXN0aW5nIHNldCBzcGxpdHMgaW4gdGhlIHByZXZpb3VzIHNlY3Rpb24sIHBsZWFzZSByZS1ydW4gdGhlIG9yaWdpbmFsIDUgbGluZXMgb2YgY29kZSB0byBvYnRhaW4gdGhlIG9yaWdpbmFsIHNwbGl0Lg0KDQpVc2luZyBnbG0gKGFuZCByZW1lbWJlcmluZyB0aGUgcGFyYW1ldGVyIGZhbWlseT0iYmlub21pYWwiKSwgdHJhaW4gYSBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsIG9uIHRoZSB0cmFpbmluZyBzZXQuIFlvdXIgZGVwZW5kZW50IHZhcmlhYmxlIGlzICJ2aW9sYXRvciIsIGFuZCB5b3Ugc2hvdWxkIHVzZSBhbGwgb2YgdGhlIG90aGVyIHZhcmlhYmxlcyBhcyBpbmRlcGVuZGVudCB2YXJpYWJsZXMuDQoNCldoYXQgdmFyaWFibGVzIGFyZSBzaWduaWZpY2FudCBpbiB0aGlzIG1vZGVsPyBTaWduaWZpY2FudCB2YXJpYWJsZXMgc2hvdWxkIGhhdmUgYSBsZWFzdCBvbmUgc3Rhciwgb3Igc2hvdWxkIGhhdmUgYSBwcm9iYWJpbGl0eSBsZXNzIHRoYW4gMC4wNSAodGhlIGNvbHVtbiBQcig+fHp8KSBpbiB0aGUgc3VtbWFyeSBvdXRwdXQpLiBTZWxlY3QgYWxsIHRoYXQgYXBwbHkuDQoNCmBgYHtyfQ0KbW9kZWwxIDwtIGdsbSh2aW9sYXRvciB+LixkYXRhPXRyYWluLGZhbWlseT0iYmlub21pYWwiKQ0Kc3VtbWFyeSAobW9kZWwxKQ0KI3JhY2Usc3RhdGU0LG11bHRpcGxlLm9mZmVuc2VzDQpgYGANCiMjIyMgNC4yIC0gQnVpbGRpbmcgYSBMb2dpc3RpYyBSZWdyZXNzaW9uIE1vZGVsKCoqKikNCg0KV2hhdCBjYW4gd2Ugc2F5IGJhc2VkIG9uIHRoZSBjb2VmZmljaWVudCBvZiB0aGUgbXVsdGlwbGUub2ZmZW5zZXMgdmFyaWFibGU/DQoNClRoZSBmb2xsb3dpbmcgdHdvIHByb3BlcnRpZXMgbWlnaHQgYmUgdXNlZnVsIHRvIHlvdSB3aGVuIGFuc3dlcmluZyB0aGlzIHF1ZXN0aW9uOg0KDQoxKSBJZiB3ZSBoYXZlIGEgY29lZmZpY2llbnQgYyBmb3IgYSB2YXJpYWJsZSwgdGhlbiB0aGF0IG1lYW5zIHRoZSBsb2cgb2RkcyAob3IgTG9naXQpIGFyZSBpbmNyZWFzZWQgYnkgYyBmb3IgYSB1bml0IGluY3JlYXNlIGluIHRoZSB2YXJpYWJsZS4NCg0KMikgSWYgd2UgaGF2ZSBhIGNvZWZmaWNpZW50IGMgZm9yIGEgdmFyaWFibGUsIHRoZW4gdGhhdCBtZWFucyB0aGUgb2RkcyBhcmUgbXVsdGlwbGllZCBieSBlXmMgZm9yIGEgdW5pdCBpbmNyZWFzZSBpbiB0aGUgdmFyaWFibGUuDQoNCmBgYHtyfQ0KI091ciBtb2RlbCBwcmVkaWN0cyB0aGF0IGEgcGFyb2xlZSB3aG8gY29tbWl0dGVkIG11bHRpcGxlIG9mZmVuc2VzIGhhcyA1LjAxIHRpbWVzIGhpZ2hlciBvZGRzIG9mIGJlaW5nIGEgdmlvbGF0b3IgdGhhbiBhIHBhcm9sZWUgd2hvIGRpZCBub3QgY29tbWl0IG11bHRpcGxlIG9mZmVuc2VzIGJ1dCBpcyBvdGhlcndpc2UgaWRlbnRpY2FsLiANCmBgYA0KDQojIyMjIDQuMyAtIEJ1aWxkaW5nIGEgTG9naXN0aWMgUmVncmVzc2lvbiBNb2RlbA0KDQpDb25zaWRlciBhIHBhcm9sZWUgd2hvIGlzIG1hbGUsIG9mIHdoaXRlIHJhY2UsIGFnZWQgNTAgeWVhcnMgYXQgcHJpc29uIHJlbGVhc2UsIGZyb20gdGhlIHN0YXRlIG9mIE1hcnlsYW5kLCBzZXJ2ZWQgMyBtb250aHMsIGhhZCBhIG1heGltdW0gc2VudGVuY2Ugb2YgMTIgbW9udGhzLCBkaWQgbm90IGNvbW1pdCBtdWx0aXBsZSBvZmZlbnNlcywgYW5kIGNvbW1pdHRlZCBhIGxhcmNlbnkuIEFuc3dlciB0aGUgZm9sbG93aW5nIHF1ZXN0aW9ucyBiYXNlZCBvbiB0aGUgbW9kZWwncyBwcmVkaWN0aW9ucyBmb3IgdGhpcyBpbmRpdmlkdWFsLiAoSElOVDogWW91IHNob3VsZCB1c2UgdGhlIGNvZWZmaWNpZW50cyBvZiB5b3VyIG1vZGVsLCB0aGUgTG9naXN0aWMgUmVzcG9uc2UgRnVuY3Rpb24sIGFuZCB0aGUgT2RkcyBlcXVhdGlvbiB0byBzb2x2ZSB0aGlzIHByb2JsZW0uKQ0KDQpBY2NvcmRpbmcgdG8gdGhlIG1vZGVsLCB3aGF0IGFyZSB0aGUgb2RkcyB0aGlzIGluZGl2aWR1YWwgaXMgYSB2aW9sYXRvcj8NCmBgYHtyfQ0KLTQuMjQxMTU3NCArIDAuMzg2OTkwNCoxICsgMC44ODY3MTkyKjEgLSAwLjAwMDE3NTYqNTAgKyAwLjQ0MzMwMDcqMCArIDAuODM0OTc5NyowIC0gMy4zOTY3ODc4KjAgLSAwLjEyMzg4NjcqMyArIDAuMDgwMjk1NCoxMiArIDEuNjExOTkxOSowICsgMC42ODM3MTQzKjEgLSAwLjI3ODEwNTQqMCAtIDAuMDExNzYyNyowDQpleHAoLTEuNzAwNjI5KQ0KDQpgYGANCg0KQWNjb3JkaW5nIHRvIHRoZSBtb2RlbCwgd2hhdCBpcyB0aGUgcHJvYmFiaWxpdHkgdGhpcyBpbmRpdmlkdWFsIGlzIGEgdmlvbGF0b3I/DQoNCmBgYHtyfQ0KMS8oMStleHAoLTEuNzAwNjI5KSkNCmBgYA0KIyMjIFNlY3Rpb24gNQ0KIyMjIyA1LjEgLSBFdmFsdWF0aW5nIHRoZSBNb2RlbCBvbiB0aGUgVGVzdGluZyBTZXQNCg0KVXNlIHRoZSBwcmVkaWN0KCkgZnVuY3Rpb24gdG8gb2J0YWluIHRoZSBtb2RlbCdzIHByZWRpY3RlZCBwcm9iYWJpbGl0aWVzIGZvciBwYXJvbGVlcyBpbiB0aGUgdGVzdGluZyBzZXQsIHJlbWVtYmVyaW5nIHRvIHBhc3MgdHlwZT0icmVzcG9uc2UiLg0KDQpXaGF0IGlzIHRoZSBtYXhpbXVtIHByZWRpY3RlZCBwcm9iYWJpbGl0eSBvZiBhIHZpb2xhdGlvbj8NCg0KYGBge3J9DQpwcmU9cHJlZGljdChtb2RlbDEsbmV3ZGF0YSA9IHRlc3QsdHlwZT0icmVzcG9uc2UiKQ0Kc3VtbWFyeShwcmUpDQojMC45MDcyNzkNCmBgYA0KIyMjIyA1LjIgLSBFdmFsdWF0aW5nIHRoZSBNb2RlbCBvbiB0aGUgVGVzdGluZyBTZXQNCg0KSW4gdGhlIGZvbGxvd2luZyBxdWVzdGlvbnMsIGV2YWx1YXRlIHRoZSBtb2RlbCdzIHByZWRpY3Rpb25zIG9uIHRoZSB0ZXN0IHNldCB1c2luZyBhIHRocmVzaG9sZCBvZiAwLjUuDQoNCldoYXQgaXMgdGhlIG1vZGVsJ3Mgc2Vuc2l0aXZpdHk/DQpgYGB7cn0NCnRhYmxlKHRlc3QkdmlvbGF0b3IscHJlPj0wLjUpDQoxMi8oMTIrMTEpDQpgYGANCldoYXQgaXMgdGhlIG1vZGVsJ3Mgc3BlY2lmaWNpdHk/DQpgYGB7cn0NCjE2Ny8oMTIrMTY3KQ0KYGBgDQoNCg0KV2hhdCBpcyB0aGUgbW9kZWwncyBhY2N1cmFjeT8NCmBgYHtyfQ0KKDEyKzE2NykvKDE2NysxMisxMSsxMikNCmBgYA0KIyMjIyA1LjMgLSBFdmFsdWF0aW5nIHRoZSBNb2RlbCBvbiB0aGUgVGVzdGluZyBTZXQNCg0KV2hhdCBpcyB0aGUgYWNjdXJhY3kgb2YgYSBzaW1wbGUgbW9kZWwgdGhhdCBwcmVkaWN0cyB0aGF0IGV2ZXJ5IHBhcm9sZWUgaXMgYSBub24tdmlvbGF0b3I/DQoNCmBgYHtyfQ0KdGFibGUodGVzdCR2aW9sYXRvcikNCjE3OS8oMTc5KzIzKQ0KYGBgDQojIyMjIDUuNCAtIEV2YWx1YXRpbmcgdGhlIE1vZGVsIG9uIHRoZSBUZXN0aW5nIFNldA0KDQpDb25zaWRlciBhIHBhcm9sZSBib2FyZCB1c2luZyB0aGUgbW9kZWwgdG8gcHJlZGljdCB3aGV0aGVyIHBhcm9sZWVzIHdpbGwgYmUgdmlvbGF0b3JzIG9yIG5vdC4gVGhlIGpvYiBvZiBhIHBhcm9sZSBib2FyZCBpcyB0byBtYWtlIHN1cmUgdGhhdCBhIHByaXNvbmVyIGlzIHJlYWR5IHRvIGJlIHJlbGVhc2VkIGludG8gZnJlZSBzb2NpZXR5LCBhbmQgdGhlcmVmb3JlIHBhcm9sZSBib2FyZHMgdGVuZCB0byBiZSBwYXJ0aWN1bGFyaWx5IGNvbmNlcm5lZCBhYm91dCByZWxlYXNpbmcgcHJpc29uZXJzIHdobyB3aWxsIHZpb2xhdGUgdGhlaXIgcGFyb2xlLiBXaGljaCBvZiB0aGUgZm9sbG93aW5nIG1vc3QgbGlrZWx5IGRlc2NyaWJlcyB0aGVpciBwcmVmZXJlbmNlcyBhbmQgYmVzdCBjb3Vyc2Ugb2YgYWN0aW9uPw0KDQpgYGB7cn0NCiNUaGUgYm9hcmQgYXNzaWducyBtb3JlIGNvc3QgdG8gYSBmYWxzZSBuZWdhdGl2ZSB0aGFuIGEgZmFsc2UgcG9zaXRpdmUsIGFuZCBzaG91bGQgdGhlcmVmb3JlIHVzZSBhIGxvZ2lzdGljIHJlZ3Jlc3Npb24gY3V0b2ZmIGxlc3MgdGhhbiAwLjUuDQpgYGANCg0KIyMjIyA1LjUgLSBFdmFsdWF0aW5nIHRoZSBNb2RlbCBvbiB0aGUgVGVzdGluZyBTZXQNCg0KV2hpY2ggb2YgdGhlIGZvbGxvd2luZyBpcyB0aGUgbW9zdCBhY2N1cmF0ZSBhc3Nlc3NtZW50IG9mIHRoZSB2YWx1ZSBvZiB0aGUgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbCB3aXRoIGEgY3V0b2ZmIDAuNSB0byBhIHBhcm9sZSBib2FyZCwgYmFzZWQgb24gdGhlIG1vZGVsJ3MgYWNjdXJhY3kgYXMgY29tcGFyZWQgdG8gdGhlIHNpbXBsZSBiYXNlbGluZSBtb2RlbD8NCg0KYGBge3J9DQojVGhlIG1vZGVsIGlzIGxpa2VseSBvZiB2YWx1ZSB0byB0aGUgYm9hcmQsIGFuZCB1c2luZyBhIGRpZmZlcmVudCBsb2dpc3RpYyByZWdyZXNzaW9uIGN1dG9mZiBpcyBsaWtlbHkgdG8gaW1wcm92ZSB0aGUgbW9kZWwncyB2YWx1ZS4NCmBgYA0KDQojIyMjIDUuNiAtIEV2YWx1YXRpbmcgdGhlIE1vZGVsIG9uIHRoZSBUZXN0aW5nIFNldA0KDQpVc2luZyB0aGUgUk9DUiBwYWNrYWdlLCB3aGF0IGlzIHRoZSBBVUMgdmFsdWUgZm9yIHRoZSBtb2RlbD8NCg0KYGBge3J9DQpsaWJyYXJ5KFJPQ1IpDQpwcmVfUk9DID0gcHJlZGljdGlvbihwcmUsIHRlc3QkdmlvbGF0b3IpDQphcy5udW1lcmljKHBlcmZvcm1hbmNlKHByZV9ST0MsICJhdWMiKUB5LnZhbHVlcykNCmBgYA0KIyMjIyA1LjcgLSBFdmFsdWF0aW5nIHRoZSBNb2RlbCBvbiB0aGUgVGVzdGluZyBTZXQNCg0KRGVzY3JpYmUgdGhlIG1lYW5pbmcgb2YgQVVDIGluIHRoaXMgY29udGV4dC4NCg0KYGBge3J9DQojVGhlIHByb2JhYmlsaXR5IHRoZSBtb2RlbCBjYW4gY29ycmVjdGx5IGRpZmZlcmVudGlhdGUgYmV0d2VlbiBhIHJhbmRvbWx5IHNlbGVjdGVkIHBhcm9sZSB2aW9sYXRvciBhbmQgYSByYW5kb21seSBzZWxlY3RlZCBwYXJvbGUgbm9uLXZpb2xhdG9yDQpgYGANCg0KIyMjIFNlY3Rpb24gNg0KDQojIyMjIDYuMSAtIElkZW50aWZ5aW5nIEJpYXMgaW4gT2JzZXJ2YXRpb25hbCBEYXRhDQoNCk91ciBnb2FsIGhhcyBiZWVuIHRvIHByZWRpY3QgdGhlIG91dGNvbWUgb2YgYSBwYXJvbGUgZGVjaXNpb24sIGFuZCB3ZSB1c2VkIGEgcHVibGljbHkgYXZhaWxhYmxlIGRhdGFzZXQgb2YgcGFyb2xlIHJlbGVhc2VzIGZvciBwcmVkaWN0aW9ucy4gSW4gdGhpcyBmaW5hbCBwcm9ibGVtLCB3ZSdsbCBldmFsdWF0ZSBhIHBvdGVudGlhbCBzb3VyY2Ugb2YgYmlhcyBhc3NvY2lhdGVkIHdpdGggb3VyIGFuYWx5c2lzLiBJdCBpcyBhbHdheXMgaW1wb3J0YW50IHRvIGV2YWx1YXRlIGEgZGF0YXNldCBmb3IgcG9zc2libGUgc291cmNlcyBvZiBiaWFzLg0KDQpUaGUgZGF0YXNldCBjb250YWlucyBhbGwgaW5kaXZpZHVhbHMgcmVsZWFzZWQgZnJvbSBwYXJvbGUgaW4gMjAwNCwgZWl0aGVyIGR1ZSB0byBjb21wbGV0aW5nIHRoZWlyIHBhcm9sZSB0ZXJtIG9yIHZpb2xhdGluZyB0aGUgdGVybXMgb2YgdGhlaXIgcGFyb2xlLiBIb3dldmVyLCBpdCBkb2VzIG5vdCBjb250YWluIHBhcm9sZWVzIHdobyBuZWl0aGVyIHZpb2xhdGVkIHRoZWlyIHBhcm9sZSBub3IgY29tcGxldGVkIHRoZWlyIHRlcm0gaW4gMjAwNCwgY2F1c2luZyBub24tdmlvbGF0b3JzIHRvIGJlIHVuZGVycmVwcmVzZW50ZWQuIFRoaXMgaXMgY2FsbGVkICJzZWxlY3Rpb24gYmlhcyIgb3IgInNlbGVjdGluZyBvbiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlLCIgYmVjYXVzZSBvbmx5IGEgc3Vic2V0IG9mIGFsbCByZWxldmFudCBwYXJvbGVlcyB3ZXJlIGluY2x1ZGVkIGluIG91ciBhbmFseXNpcywgYmFzZWQgb24gb3VyIGRlcGVuZGVudCB2YXJpYWJsZSBpbiB0aGlzIGFuYWx5c2lzIChwYXJvbGUgdmlvbGF0aW9uKS4gSG93IGNvdWxkIHdlIGltcHJvdmUgb3VyIGRhdGFzZXQgdG8gYmVzdCBhZGRyZXNzIHNlbGVjdGlvbiBiaWFzPw0KDQpgYGB7cn0NCiNXZSBzaG91bGQgdXNlIGEgZGF0YXNldCB0cmFja2luZyBhIGdyb3VwIG9mIHBhcm9sZWVzIGZyb20gdGhlIHN0YXJ0IG9mIHRoZWlyIHBhcm9sZSB1bnRpbCBlaXRoZXIgdGhleSB2aW9sYXRlZCBwYXJvbGUgb3IgdGhleSBjb21wbGV0ZWQgdGhlaXIgdGVybS4NCmBgYA0KDQo=