Introduction
議題:用申請假釋者的屬性,預測他會不會違反假釋規定
學習重點:
- 設定隨機種子set.seed(),依比例分割資料
- 從邏輯式回歸的係數推算自變數的邊際效果
- 勝率和機率、勝率比和機率差 之間的換算
- 臨界機率對混淆矩陣(期望報酬)的影響payoff = matrix(c(0,-100,-10,-50),2,2); payoff
- AUC的實質意義payoff = matrix(c(100, -80, -20, 100),2,2); payoff
- 如何(從報酬矩陣)決定臨界機率
- 什麼是抽樣偏差,如何避免、如何修正
1 資料處理 Loading the Dataset
【1.1 讀進資料】How many parolees are contained in the dataset?
P = read.csv("data/parole.csv")
nrow(P)
[1] 675
【1.2 底線機率】How many of the parolees in the dataset violated the terms of their parole?
nrow(subset(P,P$violator == 1))
[1] 78
2 整理資料框 Creating Our Prediction Model
【2.1 類別變數】Which variables in this dataset are unordered factors with at least three levels?
#state,crime
P$state %<>% as.factor
P$crime %<>% as.factor
【2.2 資料框摘要】How does the output of summary() change for a factor variable as compared to a numerical variable?
summary(P)
male race age state
Min. :0.000 Min. :1.00 Min. :18.4 1:143
1st Qu.:1.000 1st Qu.:1.00 1st Qu.:25.4 2:120
Median :1.000 Median :1.00 Median :33.7 3: 82
Mean :0.807 Mean :1.42 Mean :34.5 4:330
3rd Qu.:1.000 3rd Qu.:2.00 3rd Qu.:42.5
Max. :1.000 Max. :2.00 Max. :67.0
time.served max.sentence multiple.offenses crime
Min. :0.00 Min. : 1.0 Min. :0.000 1:315
1st Qu.:3.25 1st Qu.:12.0 1st Qu.:0.000 2:106
Median :4.40 Median :12.0 Median :1.000 3:153
Mean :4.20 Mean :13.1 Mean :0.536 4:101
3rd Qu.:5.20 3rd Qu.:15.0 3rd Qu.:1.000
Max. :6.00 Max. :18.0 Max. :1.000
violator
Min. :0.000
1st Qu.:0.000
Median :0.000
Mean :0.116
3rd Qu.:0.000
Max. :1.000
#The output becomes similar to that of the table() function applied to that variable correct
3 資料分割 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):
set.seed(144)
library(caTools)
split = sample.split(parole$violator, SplitRatio = 0.7)
train = subset(parole, split == TRUE)
test = subset(parole, split == FALSE)
【3.1 指定隨機種子、依比例分割資料】Roughly what proportion of parolees have been allocated to the training and testing sets?
set.seed(144)
library(caTools)
split = sample.split(P$violator,SplitRatio = 0.7)
TR = subset(P,split == TRUE)
TS = subset(P,split == FALSE)
#70% to the training set, 30% to the testing set
【3.2 隨機種子的功用】Now, suppose you re-ran lines [1]-[5] of Problem 3.1. What would you expect? If you instead ONLY re-ran lines [3]-[5], what would you expect? 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?
#The exact same training/testing set split as the first execution of [1]-[5]
#A different training/testing set split from the first execution of [1]-[5]
#A different training/testing set split from the first execution of [1]-[5]
4 建立模型 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.
【4.1 顯著性】What variables are significant in this model?
glm1 = glm(violator~.,data=TR,family = binomial)
summary(glm1)
Call:
glm(formula = violator ~ ., family = binomial, data = TR)
Deviance Residuals:
Min 1Q Median 3Q Max
-1.704 -0.424 -0.272 -0.169 2.837
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) -4.241157 1.293885 -3.28 0.001 **
male 0.386990 0.437961 0.88 0.377
race 0.886719 0.395066 2.24 0.025 *
age -0.000176 0.016085 -0.01 0.991
state2 0.443301 0.481662 0.92 0.357
state3 0.834980 0.556270 1.50 0.133
state4 -3.396788 0.611586 -5.55 0.000000028 ***
time.served -0.123887 0.120423 -1.03 0.304
max.sentence 0.080295 0.055375 1.45 0.147
multiple.offenses 1.611992 0.385305 4.18 0.000028683 ***
crime2 0.683714 0.500355 1.37 0.172
crime3 -0.278105 0.432836 -0.64 0.521
crime4 -0.011763 0.571304 -0.02 0.984
---
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.5
Number of Fisher Scoring iterations: 6
#race,state4,multiple.offeses
【4.2 從回歸係數估計邊際效用】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:
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.
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.
exp(1.611992) #exp(multiple.offenses的estimate)
[1] 5.013
#將logit轉回odd
# 5.013
#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.
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.)
【4.3 從預測值估計勝率和機率】According to the model, what are the odds this individual is a violator? What is the probability this individual is a violator?
#log(odds) or logit = -4.241157 + 0.386990*male + 0.886719* race + (-0.000176)*age + 0.4433007*state2 + 0.8349797*state3 - 3.3967878*state4 - 0.1238867*time.served + 0.0802954*max.sentence + 1.6119919*multiple.offenses + 0.6837143*crime2 - 0.2781054*crime3 - 0.0117627*crime4
male=1; race=1; age=50; state2=0; state3=0; state4=0; time.served=3; max.sentence=12; multiple.offenses=0; crime2=1; crime3=0; crime4=0
logit = -4.241157 + 0.386990*male + 0.886719* race + (-0.000176)*age + 0.4433007*state2 + 0.8349797*state3 - 3.3967878*state4 - 0.1238867*time.served + 0.0802954*max.sentence + 1.6119919*multiple.offenses + 0.6837143*crime2 - 0.2781054*crime3 - 0.0117627*crime4
odd = exp(logit);odd
[1] 0.1826
p = 1/1+odd ; p
[1] 1.183
5 驗證模型 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”.
【5.1 從測試資料預測機率】What is the maximum predicted probability of a violation?
pred = predict(glm1,TS,type="response")
max(pred)
[1] 0.9073
Use the predict() function to obtain the model’s predicted probabilities for parolees in the testing set, remembering to pass type=“response”.
【5.2 從混淆矩陣計算敏感性、明確性、正確率】What is the model’s sensitivity, specificity, accuracy?
A = table(actual = TS$violator , pred = pred >= 0.5);A
pred
actual FALSE TRUE
0 167 12
1 11 12
sen = 12/(11+12);sen
[1] 0.5217
spec = 167/(167+12);spec
[1] 0.933
acc = sum(diag(A))/sum(A);acc
[1] 0.8861
【5.3 底線機率】What is the accuracy of a simple model that predicts that every parolee is a non-violator?
table(TS$violator) #在test里non-violator有179
0 1
179 23
#如果全部都視為non
ACC = 179/(179+23) ; ACC
[1] 0.8861
【5.4 根據報償矩陣調整臨界機率】 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 正確率 vs 辨識率】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 計算辨識率】Using the ROCR package, what is the AUC value for the model?
library(ROCR)
preds = prediction(pred, TS$violator)
as.numeric(performance(preds, "auc")@y.values)
[1] 0.8946
【5.7 辨識率的定義】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.
#
6 抽樣偏差 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).
【6.1 如何避免、診斷、修正抽樣偏差】How could we improve our dataset to best address selection bias?
#因為TEST資料集只限於某個年份,但忽略了他在之後假釋期間的後續動向,沒有完整記錄
#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.
LS0tCnRpdGxlOiAiQVMzLTIgUHJlZGljdGluZyBQYXJvbGUgVmlvbGF0b3JzIgphdXRob3I6ICLpmbPpn7vljYkgQjAzNDAyMDAyNyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3IgZWNobz1ULCBtZXNzYWdlPUYsIGNhY2hlPUYsIHdhcm5pbmc9Rn0Kcm0obGlzdD1scyhhbGw9VCkpCm9wdGlvbnMoZGlnaXRzPTQsIHNjaXBlbj0xMikKbGlicmFyeShtYWdyaXR0cikKYGBgCgotIC0gLQoKIyMjIEludHJvZHVjdGlvbgoKKirorbDpoYzvvJrnlKjnlLPoq4vlgYfph4vogIXnmoTlsazmgKfvvIzpoJDmuKzku5bmnIPkuI3mnIPpgZXlj43lgYfph4vopo/lrpoqKgoKKirlrbjnv5Lph43pu57vvJoqKgoKKyDoqK3lrprpmqjmqZ/nqK7lrZBzZXQuc2VlZCgp77yM5L6d5q+U5L6L5YiG5Ymy6LOH5paZCisg5b6e6YKP6Lyv5byP5Zue5q2455qE5L+C5pW45o6o566X6Ieq6K6K5pW455qE6YKK6Zqb5pWI5p6cCisg5Yud546H5ZKM5qmf546H44CB5Yud546H5q+U5ZKM5qmf546H5beuIOS5i+mWk+eahOaPm+eulyAKKyDoh6jnlYzmqZ/njoflsI3mt7fmt4bnn6npmaMo5pyf5pyb5aCx6YWsKeeahOW9semfv3BheW9mZiA9IG1hdHJpeChjKDAsLTEwMCwtMTAsLTUwKSwyLDIpOyBwYXlvZmYKKyBBVUPnmoTlr6bos6rmhI/nvqlwYXlvZmYgPSBtYXRyaXgoYygxMDAsIC04MCwgLTIwLCAxMDApLDIsMik7IHBheW9mZgorIOWmguS9lSjlvp7loLHphaznn6npmaMp5rG65a6a6Ieo55WM5qmf546HIAorIOS7gOm6vOaYr+aKveaoo+WBj+W3rizlpoLkvZXpgb/lhY3jgIHlpoLkvZXkv67mraMKCjxicj4KCi0gLSAtCgojIyMjIDEg6LOH5paZ6JmV55CGIExvYWRpbmcgdGhlIERhdGFzZXQKCuOAkCoqMS4xIOiugOmAsuizh+aWmSoq44CRSG93IG1hbnkgcGFyb2xlZXMgYXJlIGNvbnRhaW5lZCBpbiB0aGUgZGF0YXNldD8KYGBge3J9ClAgPSByZWFkLmNzdigiZGF0YS9wYXJvbGUuY3N2IikKbnJvdyhQKQpgYGAKCuOAkCoqMS4yIOW6lee3muapn+eOhyoq44CRSG93IG1hbnkgb2YgdGhlIHBhcm9sZWVzIGluIHRoZSBkYXRhc2V0IHZpb2xhdGVkIHRoZSB0ZXJtcyBvZiB0aGVpciBwYXJvbGU/CmBgYHtyfQpucm93KHN1YnNldChQLFAkdmlvbGF0b3IgPT0gMSkpCmBgYAo8YnI+CgotIC0gLQoKIyMjIyAyIOaVtOeQhuizh+aWmeahhiBDcmVhdGluZyBPdXIgUHJlZGljdGlvbiBNb2RlbAoK44CQKioyLjEg6aGe5Yil6K6K5pW4KirjgJFXaGljaCB2YXJpYWJsZXMgaW4gdGhpcyBkYXRhc2V0IGFyZSB1bm9yZGVyZWQgZmFjdG9ycyB3aXRoIGF0IGxlYXN0IHRocmVlIGxldmVscz8gCmBgYHtyfQojc3RhdGUsY3JpbWUKClAkc3RhdGUgJTw+JSBhcy5mYWN0b3IKUCRjcmltZSAlPD4lIGFzLmZhY3RvcgoKCmBgYAoK44CQKioyLjIg6LOH5paZ5qGG5pGY6KaBKirjgJFIb3cgZG9lcyB0aGUgb3V0cHV0IG9mIGBzdW1tYXJ5KClgIGNoYW5nZSBmb3IgYSBmYWN0b3IgdmFyaWFibGUgYXMgY29tcGFyZWQgdG8gYSBudW1lcmljYWwgdmFyaWFibGU/IApgYGB7cn0Kc3VtbWFyeShQKQoKI1RoZSBvdXRwdXQgYmVjb21lcyBzaW1pbGFyIHRvIHRoYXQgb2YgdGhlIHRhYmxlKCkgZnVuY3Rpb24gYXBwbGllZCB0byB0aGF0IHZhcmlhYmxlIGNvcnJlY3QKYGBgCjxicj4KCi0gLSAtCgojIyMjIDMg6LOH5paZ5YiG5YmyIFNwbGl0dGluZyBpbnRvIGEgVHJhaW5pbmcgYW5kIFRlc3RpbmcgU2V0CgoKVG8gZW5zdXJlIGNvbnNpc3RlbnQgdHJhaW5pbmcvdGVzdGluZyBzZXQgc3BsaXRzLCBydW4gdGhlIGZvbGxvd2luZyA1IGxpbmVzIG9mIGNvZGUgKGRvIG5vdCBpbmNsdWRlIHRoZSBsaW5lIG51bWJlcnMgYXQgdGhlIGJlZ2lubmluZyk6CgoxKSBzZXQuc2VlZCgxNDQpCgoyKSBsaWJyYXJ5KGNhVG9vbHMpCgozKSBzcGxpdCA9IHNhbXBsZS5zcGxpdChwYXJvbGUkdmlvbGF0b3IsIFNwbGl0UmF0aW8gPSAwLjcpCgo0KSB0cmFpbiA9IHN1YnNldChwYXJvbGUsIHNwbGl0ID09IFRSVUUpCgo1KSB0ZXN0ID0gc3Vic2V0KHBhcm9sZSwgc3BsaXQgPT0gRkFMU0UpCgrjgJAqKjMuMSDmjIflrprpmqjmqZ/nqK7lrZDjgIHkvp3mr5TkvovliIblibLos4fmlpkqKuOAkVJvdWdobHkgd2hhdCBwcm9wb3J0aW9uIG9mIHBhcm9sZWVzIGhhdmUgYmVlbiBhbGxvY2F0ZWQgdG8gdGhlIHRyYWluaW5nIGFuZCB0ZXN0aW5nIHNldHM/CmBgYHtyfQoKc2V0LnNlZWQoMTQ0KQpsaWJyYXJ5KGNhVG9vbHMpCnNwbGl0ID0gc2FtcGxlLnNwbGl0KFAkdmlvbGF0b3IsU3BsaXRSYXRpbyA9IDAuNykKVFIgPSBzdWJzZXQoUCxzcGxpdCA9PSBUUlVFKQpUUyA9IHN1YnNldChQLHNwbGl0ID09IEZBTFNFKQoKCmBgYAoKYGBge3J9CiM3MCUgdG8gdGhlIHRyYWluaW5nIHNldCwgMzAlIHRvIHRoZSB0ZXN0aW5nIHNldAoKYGBgCgrjgJAqKjMuMiDpmqjmqZ/nqK7lrZDnmoTlip/nlKgqKuOAkU5vdywgc3VwcG9zZSB5b3UgcmUtcmFuIGxpbmVzIFsxXS1bNV0gb2YgUHJvYmxlbSAzLjEuIFdoYXQgd291bGQgeW91IGV4cGVjdD8gSWYgeW91IGluc3RlYWQgT05MWSByZS1yYW4gbGluZXMgWzNdLVs1XSwgd2hhdCB3b3VsZCB5b3UgZXhwZWN0PyBJZiB5b3UgaW5zdGVhZCBjYWxsZWQgc2V0LnNlZWQoKSB3aXRoIGEgZGlmZmVyZW50IG51bWJlciBhbmQgdGhlbiByZS1yYW4gbGluZXMgWzNdLVs1XSBvZiBQcm9ibGVtIDMuMSwgd2hhdCB3b3VsZCB5b3UgZXhwZWN0PwpgYGB7cn0KCiNUaGUgZXhhY3Qgc2FtZSB0cmFpbmluZy90ZXN0aW5nIHNldCBzcGxpdCBhcyB0aGUgZmlyc3QgZXhlY3V0aW9uIG9mIFsxXS1bNV0KCiNBIGRpZmZlcmVudCB0cmFpbmluZy90ZXN0aW5nIHNldCBzcGxpdCBmcm9tIHRoZSBmaXJzdCBleGVjdXRpb24gb2YgWzFdLVs1XQoKI0EgZGlmZmVyZW50IHRyYWluaW5nL3Rlc3Rpbmcgc2V0IHNwbGl0IGZyb20gdGhlIGZpcnN0IGV4ZWN1dGlvbiBvZiBbMV0tWzVdCgoKYGBgCjxicj4KCi0gLSAtCgojIyMjIDQg5bu656uL5qih5Z6LIEJ1aWxkaW5nIGEgTG9naXN0aWMgUmVncmVzc2lvbiBNb2RlbAoKSWYgeW91IHRlc3RlZCBvdGhlciB0cmFpbmluZy90ZXN0aW5nIHNldCBzcGxpdHMgaW4gdGhlIHByZXZpb3VzIHNlY3Rpb24sIHBsZWFzZSByZS1ydW4gdGhlIG9yaWdpbmFsIDUgbGluZXMgb2YgY29kZSB0byBvYnRhaW4gdGhlIG9yaWdpbmFsIHNwbGl0LgoKVXNpbmcgZ2xtIChhbmQgcmVtZW1iZXJpbmcgdGhlIHBhcmFtZXRlciBmYW1pbHk9ImJpbm9taWFsIiksIHRyYWluIGEgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbCBvbiB0aGUgdHJhaW5pbmcgc2V0LiBZb3VyIGRlcGVuZGVudCB2YXJpYWJsZSBpcyAidmlvbGF0b3IiLCBhbmQgeW91IHNob3VsZCB1c2UgYWxsIG9mIHRoZSBvdGhlciB2YXJpYWJsZXMgYXMgaW5kZXBlbmRlbnQgdmFyaWFibGVzLgoKV2hhdCB2YXJpYWJsZXMgYXJlIHNpZ25pZmljYW50IGluIHRoaXMgbW9kZWw/IFNpZ25pZmljYW50IHZhcmlhYmxlcyBzaG91bGQgaGF2ZSBhIGxlYXN0IG9uZSBzdGFyLCBvciBzaG91bGQgaGF2ZSBhIHByb2JhYmlsaXR5IGxlc3MgdGhhbiAwLjA1ICh0aGUgY29sdW1uIFByKD58enwpIGluIHRoZSBzdW1tYXJ5IG91dHB1dCkuIFNlbGVjdCBhbGwgdGhhdCBhcHBseS4KCuOAkCoqNC4xIOmhr+iRl+aApyoq44CRV2hhdCB2YXJpYWJsZXMgYXJlIHNpZ25pZmljYW50IGluIHRoaXMgbW9kZWw/CmBgYHtyfQpnbG0xID0gZ2xtKHZpb2xhdG9yfi4sZGF0YT1UUixmYW1pbHkgPSBiaW5vbWlhbCkKc3VtbWFyeShnbG0xKQoKI3JhY2Usc3RhdGU0LG11bHRpcGxlLm9mZmVzZXMKCmBgYAoKCuOAkCoqNC4yIOW+nuWbnuatuOS/guaVuOS8sOioiOmCiumam+aViOeUqCoq44CRV2hhdCBjYW4gd2Ugc2F5IGJhc2VkIG9uIHRoZSBjb2VmZmljaWVudCBvZiB0aGUgYG11bHRpcGxlLm9mZmVuc2VzYCB2YXJpYWJsZT8KClRoZSBmb2xsb3dpbmcgdHdvIHByb3BlcnRpZXMgbWlnaHQgYmUgdXNlZnVsIHRvIHlvdSB3aGVuIGFuc3dlcmluZyB0aGlzIHF1ZXN0aW9uOgoKMSkgSWYgd2UgaGF2ZSBhIGNvZWZmaWNpZW50IGMgZm9yIGEgdmFyaWFibGUsIHRoZW4gdGhhdCBtZWFucyB0aGUgbG9nIG9kZHMgKG9yIExvZ2l0KSBhcmUgaW5jcmVhc2VkIGJ5IGMgZm9yIGEgdW5pdCBpbmNyZWFzZSBpbiB0aGUgdmFyaWFibGUuCgoyKSBJZiB3ZSBoYXZlIGEgY29lZmZpY2llbnQgYyBmb3IgYSB2YXJpYWJsZSwgdGhlbiB0aGF0IG1lYW5zIHRoZSBvZGRzIGFyZSBtdWx0aXBsaWVkIGJ5IGVeYyBmb3IgYSB1bml0IGluY3JlYXNlIGluIHRoZSB2YXJpYWJsZS4KYGBge3J9CgpleHAoMS42MTE5OTIpICAjZXhwKG11bHRpcGxlLm9mZmVuc2Vz55qEZXN0aW1hdGUpIAoj5bCHbG9naXTovYnlm55vZGQKIyA1LjAxMwoKI091ciBtb2RlbCBwcmVkaWN0cyB0aGF0IGEgcGFyb2xlZSB3aG8gY29tbWl0dGVkIG11bHRpcGxlIG9mZmVuc2VzIGhhcyA1LjAxIHRpbWVzIGhpZ2hlciBvZGRzIG9mIGJlaW5nIGEgdmlvbGF0b3IgdGhhbiBhIHBhcm9sZWUgd2hvIGRpZCBub3QgY29tbWl0IG11bHRpcGxlIG9mZmVuc2VzIGJ1dCBpcyBvdGhlcndpc2UgaWRlbnRpY2FsLgoKCmBgYAoKQ29uc2lkZXIgYSBwYXJvbGVlIHdobyBpcyBtYWxlLCBvZiB3aGl0ZSByYWNlLCBhZ2VkIDUwIHllYXJzIGF0IHByaXNvbiByZWxlYXNlLCBmcm9tIHRoZSBzdGF0ZSBvZiBNYXJ5bGFuZCwgc2VydmVkIDMgbW9udGhzLCBoYWQgYSBtYXhpbXVtIHNlbnRlbmNlIG9mIDEyIG1vbnRocywgZGlkIG5vdCBjb21taXQgbXVsdGlwbGUgb2ZmZW5zZXMsIGFuZCBjb21taXR0ZWQgYSBsYXJjZW55LiBBbnN3ZXIgdGhlIGZvbGxvd2luZyBxdWVzdGlvbnMgYmFzZWQgb24gdGhlIG1vZGVsJ3MgcHJlZGljdGlvbnMgZm9yIHRoaXMgaW5kaXZpZHVhbC4gKEhJTlQ6IFlvdSBzaG91bGQgdXNlIHRoZSBjb2VmZmljaWVudHMgb2YgeW91ciBtb2RlbCwgdGhlIExvZ2lzdGljIFJlc3BvbnNlIEZ1bmN0aW9uLCBhbmQgdGhlIE9kZHMgZXF1YXRpb24gdG8gc29sdmUgdGhpcyBwcm9ibGVtLikKCuOAkCoqNC4zIOW+numgkOa4rOWAvOS8sOioiOWLneeOh+WSjOapn+eOhyoq44CRQWNjb3JkaW5nIHRvIHRoZSBtb2RlbCwgd2hhdCBhcmUgdGhlIG9kZHMgdGhpcyBpbmRpdmlkdWFsIGlzIGEgdmlvbGF0b3I/ICBXaGF0IGlzIHRoZSBwcm9iYWJpbGl0eSB0aGlzIGluZGl2aWR1YWwgaXMgYSB2aW9sYXRvcj8KYGBge3J9CiNsb2cob2Rkcykgb3IgbG9naXQgPSAgIC00LjI0MTE1NyArIDAuMzg2OTkwKm1hbGUgKyAwLjg4NjcxOSogcmFjZSArICgtMC4wMDAxNzYpKmFnZSArIDAuNDQzMzAwNypzdGF0ZTIgKyAwLjgzNDk3OTcqc3RhdGUzIC0gMy4zOTY3ODc4KnN0YXRlNCAtIDAuMTIzODg2Nyp0aW1lLnNlcnZlZCArIDAuMDgwMjk1NCptYXguc2VudGVuY2UgKyAxLjYxMTk5MTkqbXVsdGlwbGUub2ZmZW5zZXMgKyAwLjY4MzcxNDMqY3JpbWUyIC0gMC4yNzgxMDU0KmNyaW1lMyAtIDAuMDExNzYyNypjcmltZTQKCm1hbGU9MTsgcmFjZT0xOyBhZ2U9NTA7IHN0YXRlMj0wOyBzdGF0ZTM9MDsgc3RhdGU0PTA7IHRpbWUuc2VydmVkPTM7IG1heC5zZW50ZW5jZT0xMjsgbXVsdGlwbGUub2ZmZW5zZXM9MDsgY3JpbWUyPTE7IGNyaW1lMz0wOyBjcmltZTQ9MAoKbG9naXQgPSAtNC4yNDExNTcgKyAwLjM4Njk5MCptYWxlICsgMC44ODY3MTkqIHJhY2UgKyAoLTAuMDAwMTc2KSphZ2UgKyAwLjQ0MzMwMDcqc3RhdGUyICsgMC44MzQ5Nzk3KnN0YXRlMyAtIDMuMzk2Nzg3OCpzdGF0ZTQgLSAwLjEyMzg4NjcqdGltZS5zZXJ2ZWQgKyAwLjA4MDI5NTQqbWF4LnNlbnRlbmNlICsgMS42MTE5OTE5Km11bHRpcGxlLm9mZmVuc2VzICsgMC42ODM3MTQzKmNyaW1lMiAtIDAuMjc4MTA1NCpjcmltZTMgLSAwLjAxMTc2MjcqY3JpbWU0CgoKb2RkID0gZXhwKGxvZ2l0KTtvZGQKcCA9IDEvMStvZGQgOyBwCgpgYGAKPGJyPgoKLSAtIC0KCiMjIyMgNSDpqZforYnmqKHlnosgRXZhbHVhdGluZyB0aGUgTW9kZWwgb24gdGhlIFRlc3RpbmcgU2V0ClVzZSB0aGUgcHJlZGljdCgpIGZ1bmN0aW9uIHRvIG9idGFpbiB0aGUgbW9kZWwncyBwcmVkaWN0ZWQgcHJvYmFiaWxpdGllcyBmb3IgcGFyb2xlZXMgaW4gdGhlIHRlc3Rpbmcgc2V0LCByZW1lbWJlcmluZyB0byBwYXNzIHR5cGU9InJlc3BvbnNlIi4KCuOAkCoqNS4xIOW+nua4rOippuizh+aWmemgkOa4rOapn+eOhyoq44CRV2hhdCBpcyB0aGUgbWF4aW11bSBwcmVkaWN0ZWQgcHJvYmFiaWxpdHkgb2YgYSB2aW9sYXRpb24/CmBgYHtyfQpwcmVkID0gcHJlZGljdChnbG0xLFRTLHR5cGU9InJlc3BvbnNlIikKbWF4KHByZWQpCgpgYGAKClVzZSB0aGUgcHJlZGljdCgpIGZ1bmN0aW9uIHRvIG9idGFpbiB0aGUgbW9kZWwncyBwcmVkaWN0ZWQgcHJvYmFiaWxpdGllcyBmb3IgcGFyb2xlZXMgaW4gdGhlIHRlc3Rpbmcgc2V0LCByZW1lbWJlcmluZyB0byBwYXNzIHR5cGU9InJlc3BvbnNlIi4KCuOAkCoqNS4yIOW+nua3t+a3huefqemZo+ioiOeul+aVj+aEn+aAp+OAgeaYjueiuuaAp+OAgeato+eiuueOhyoq44CRV2hhdCBpcyB0aGUgbW9kZWwncyBgc2Vuc2l0aXZpdHlgLCBgc3BlY2lmaWNpdHlgLCBgYWNjdXJhY3lgPwpgYGB7cn0KQSA9IHRhYmxlKGFjdHVhbCA9IFRTJHZpb2xhdG9yICwgcHJlZCA9IHByZWQgPj0gMC41KTtBCgpzZW4gID0gMTIvKDExKzEyKTtzZW4Kc3BlYyA9IDE2Ny8oMTY3KzEyKTtzcGVjCmFjYyA9IHN1bShkaWFnKEEpKS9zdW0oQSk7YWNjCgpgYGAKCuOAkCoqNS4zIOW6lee3muapn+eOhyoq44CRV2hhdCBpcyB0aGUgYWNjdXJhY3kgb2YgYSBzaW1wbGUgbW9kZWwgdGhhdCBwcmVkaWN0cyB0aGF0IGV2ZXJ5IHBhcm9sZWUgaXMgYSBub24tdmlvbGF0b3I/CmBgYHtyfQp0YWJsZShUUyR2aW9sYXRvcikgI+WcqHRlc3Tph4xub24tdmlvbGF0b3LmnIkxNzkKI+WmguaenOWFqOmDqOmDveimlueCum5vbgpBQ0MgPSAxNzkvKDE3OSsyMykgOyBBQ0MKYGBgCgrjgJAqKjUuNCDmoLnmk5rloLHlhJ/nn6npmaPoqr/mlbToh6jnlYzmqZ/njocqKuOAkQpDb25zaWRlciBhIHBhcm9sZSBib2FyZCB1c2luZyB0aGUgbW9kZWwgdG8gcHJlZGljdCB3aGV0aGVyIHBhcm9sZWVzIHdpbGwgYmUgdmlvbGF0b3JzIG9yIG5vdC4gVGhlIGpvYiBvZiBhIHBhcm9sZSBib2FyZCBpcyB0byBtYWtlIHN1cmUgdGhhdCBhIHByaXNvbmVyIGlzIHJlYWR5IHRvIGJlIHJlbGVhc2VkIGludG8gZnJlZSBzb2NpZXR5LCBhbmQgdGhlcmVmb3JlIHBhcm9sZSBib2FyZHMgdGVuZCB0byBiZSBwYXJ0aWN1bGFyaWx5IGNvbmNlcm5lZCBhYm91dCByZWxlYXNpbmcgcHJpc29uZXJzIHdobyB3aWxsIHZpb2xhdGUgdGhlaXIgcGFyb2xlCgpXaGljaCBvZiB0aGUgZm9sbG93aW5nIG1vc3QgbGlrZWx5IGRlc2NyaWJlcyB0aGVpciBwcmVmZXJlbmNlcyBhbmQgYmVzdCBjb3Vyc2Ugb2YgYWN0aW9uPwpgYGB7cn0KI1RoZSBib2FyZCBhc3NpZ25zIG1vcmUgY29zdCB0byBhIGZhbHNlIG5lZ2F0aXZlIHRoYW4gYSBmYWxzZSBwb3NpdGl2ZSwgYW5kIHNob3VsZCB0aGVyZWZvcmUgdXNlIGEgbG9naXN0aWMgcmVncmVzc2lvbiBjdXRvZmYgbGVzcyB0aGFuIDAuNS4KCmBgYAoK44CQKio1LjUg5q2j56K6546HIHZzIOi+qOitmOeOhyoq44CRV2hpY2ggb2YgdGhlIGZvbGxvd2luZyBpcyB0aGUgbW9zdCBhY2N1cmF0ZSBhc3Nlc3NtZW50IG9mIHRoZSB2YWx1ZSBvZiB0aGUgbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbCB3aXRoIGEgY3V0b2ZmIDAuNSB0byBhIHBhcm9sZSBib2FyZCwgYmFzZWQgb24gdGhlIG1vZGVsJ3MgYWNjdXJhY3kgYXMgY29tcGFyZWQgdG8gdGhlIHNpbXBsZSBiYXNlbGluZSBtb2RlbD8KYGBge3J9CiNUaGUgbW9kZWwgaXMgbGlrZWx5IG9mIHZhbHVlIHRvIHRoZSBib2FyZCwgYW5kIHVzaW5nIGEgZGlmZmVyZW50IGxvZ2lzdGljIHJlZ3Jlc3Npb24gY3V0b2ZmIGlzIGxpa2VseSB0byBpbXByb3ZlIHRoZSBtb2RlbCdzIHZhbHVlLgoKYGBgCgrjgJAqKjUuNiDoqIjnrpfovqjorZjnjocqKuOAkVVzaW5nIHRoZSBgUk9DUmAgcGFja2FnZSwgd2hhdCBpcyB0aGUgQVVDIHZhbHVlIGZvciB0aGUgbW9kZWw/CmBgYHtyfQpsaWJyYXJ5KFJPQ1IpCgpwcmVkcyA9IHByZWRpY3Rpb24ocHJlZCwgVFMkdmlvbGF0b3IpCmFzLm51bWVyaWMocGVyZm9ybWFuY2UocHJlZHMsICJhdWMiKUB5LnZhbHVlcykKCmBgYAoK44CQKio1Ljcg6L6o6K2Y546H55qE5a6a576pKirjgJFEZXNjcmliZSB0aGUgbWVhbmluZyBvZiBBVUMgaW4gdGhpcyBjb250ZXh0LgpgYGB7cn0KI1RoZSBwcm9iYWJpbGl0eSB0aGUgbW9kZWwgY2FuIGNvcnJlY3RseSBkaWZmZXJlbnRpYXRlIGJldHdlZW4gYSByYW5kb21seSBzZWxlY3RlZCBwYXJvbGUgdmlvbGF0b3IgYW5kIGEgcmFuZG9tbHkgc2VsZWN0ZWQgcGFyb2xlIG5vbi12aW9sYXRvci4KCiMKCmBgYAo8YnI+CgotIC0gLQoKIyMjIyA2IOaKveaoo+WBj+W3riBJZGVudGlmeWluZyBCaWFzIGluIE9ic2VydmF0aW9uYWwgRGF0YQoKT3VyIGdvYWwgaGFzIGJlZW4gdG8gcHJlZGljdCB0aGUgb3V0Y29tZSBvZiBhIHBhcm9sZSBkZWNpc2lvbiwgYW5kIHdlIHVzZWQgYSBwdWJsaWNseSBhdmFpbGFibGUgZGF0YXNldCBvZiBwYXJvbGUgcmVsZWFzZXMgZm9yIHByZWRpY3Rpb25zLiBJbiB0aGlzIGZpbmFsIHByb2JsZW0sIHdlJ2xsIGV2YWx1YXRlIGEgcG90ZW50aWFsIHNvdXJjZSBvZiBiaWFzIGFzc29jaWF0ZWQgd2l0aCBvdXIgYW5hbHlzaXMuIEl0IGlzIGFsd2F5cyBpbXBvcnRhbnQgdG8gZXZhbHVhdGUgYSBkYXRhc2V0IGZvciBwb3NzaWJsZSBzb3VyY2VzIG9mIGJpYXMuCgpUaGUgZGF0YXNldCBjb250YWlucyBhbGwgaW5kaXZpZHVhbHMgcmVsZWFzZWQgZnJvbSBwYXJvbGUgaW4gMjAwNCwgZWl0aGVyIGR1ZSB0byBjb21wbGV0aW5nIHRoZWlyIHBhcm9sZSB0ZXJtIG9yIHZpb2xhdGluZyB0aGUgdGVybXMgb2YgdGhlaXIgcGFyb2xlLiBIb3dldmVyLCBpdCBkb2VzIG5vdCBjb250YWluIHBhcm9sZWVzIHdobyBuZWl0aGVyIHZpb2xhdGVkIHRoZWlyIHBhcm9sZSBub3IgY29tcGxldGVkIHRoZWlyIHRlcm0gaW4gMjAwNCwgY2F1c2luZyBub24tdmlvbGF0b3JzIHRvIGJlIHVuZGVycmVwcmVzZW50ZWQuIFRoaXMgaXMgY2FsbGVkICJzZWxlY3Rpb24gYmlhcyIgb3IgInNlbGVjdGluZyBvbiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlLCIgYmVjYXVzZSBvbmx5IGEgc3Vic2V0IG9mIGFsbCByZWxldmFudCBwYXJvbGVlcyB3ZXJlIGluY2x1ZGVkIGluIG91ciBhbmFseXNpcywgYmFzZWQgb24gb3VyIGRlcGVuZGVudCB2YXJpYWJsZSBpbiB0aGlzIGFuYWx5c2lzIChwYXJvbGUgdmlvbGF0aW9uKS4KCuOAkCoqNi4xIOWmguS9lemBv+WFjeOAgeiouuaWt+OAgeS/ruato+aKveaoo+WBj+W3rioq44CRSG93IGNvdWxkIHdlIGltcHJvdmUgb3VyIGRhdGFzZXQgdG8gYmVzdCBhZGRyZXNzIHNlbGVjdGlvbiBiaWFzPwpgYGB7cn0KCiPlm6DngrpURVNU6LOH5paZ6ZuG5Y+q6ZmQ5pa85p+Q5YCL5bm05Lu977yM5L2G5b+955Wl5LqG5LuW5Zyo5LmL5b6M5YGH6YeL5pyf6ZaT55qE5b6M57qM5YuV5ZCR77yM5rKS5pyJ5a6M5pW06KiY6YyECgojV2Ugc2hvdWxkIHVzZSBhIGRhdGFzZXQgdHJhY2tpbmcgYSBncm91cCBvZiBwYXJvbGVlcyBmcm9tIHRoZSBzdGFydCBvZiB0aGVpciBwYXJvbGUgdW50aWwgZWl0aGVyIHRoZXkgdmlvbGF0ZWQgcGFyb2xlIG9yIHRoZXkgY29tcGxldGVkIHRoZWlyIHRlcm0uCgpgYGAKPGJyPgoKLSAtIC0KCjxicj48YnI+PGJyPgo=