データ分析の準備
パッケージのインストール
install.packages("dplyr")
install.packages("magrittr")
install.packages("ggplot2")
install.packages("car")
library(dplyr)
library(magrittr)
library(ggplot2)
library(car)
データのダウンロード
install.packages("titanic")
library(titanic)
effects
ライブラリのTitanicSurvival
データも利用できます。
- 演習用データにも含まれています。
データの読み込み
- 使用するデータには、欠損値が含まれます。欠損値は、
NA
で定義されている場合と、空白となっている場合の両方があるので、na.strings=(c("NA", ""))
により欠損値を定義します。
kakei <- read.csv("./フォルダを指定/train.csv", stringsAsFactors = F,na.strings=(c("NA", "")))
head(train)
summary(train)
PassengerId Survived Pclass Name Sex
Min. : 1.0 Min. :0.0000 Min. :1.000 Length:891 Length:891
1st Qu.:223.5 1st Qu.:0.0000 1st Qu.:2.000 Class :character Class :character
Median :446.0 Median :0.0000 Median :3.000 Mode :character Mode :character
Mean :446.0 Mean :0.3838 Mean :2.309
3rd Qu.:668.5 3rd Qu.:1.0000 3rd Qu.:3.000
Max. :891.0 Max. :1.0000 Max. :3.000
Age SibSp Parch Ticket Fare
Min. : 0.42 Min. :0.000 Min. :0.0000 Length:891 Min. : 0.00
1st Qu.:20.12 1st Qu.:0.000 1st Qu.:0.0000 Class :character 1st Qu.: 7.91
Median :28.00 Median :0.000 Median :0.0000 Mode :character Median : 14.45
Mean :29.70 Mean :0.523 Mean :0.3816 Mean : 32.20
3rd Qu.:38.00 3rd Qu.:1.000 3rd Qu.:0.0000 3rd Qu.: 31.00
Max. :80.00 Max. :8.000 Max. :6.0000 Max. :512.33
NA's :177
Cabin Embarked
Length:891 Length:891
Class :character Class :character
Mode :character Mode :character
欠損値の処理
summary()
関数だけでは欠損値の状況がわかりにくいので、以下の方法で欠損値を把握します。
na_count_train <- sapply(train, function(y) sum(is.na(y)))
na_count_train
PassengerId Survived Pclass Name Sex Age SibSp
0 0 0 0 0 177 0
Parch Ticket Fare Cabin Embarked
0 0 0 687 2
- 欠損値の処理には、主に欠損値を除去する方法と、何らかの方法で欠損値に値を代入する方法とがあります。ここでは、欠損値を除去する方法を採用することにします。
na.omit()
関数で欠損値を除去します。欠損値を除去したデータを、train2
とします。
train2 <- na.omit(train)
summary(train2)
PassengerId Survived Pclass Name Sex Age
Min. : 2.0 0: 60 1:158 Length:183 female:88 Min. : 0.92
1st Qu.:263.5 1:123 2: 15 Class :character male :95 1st Qu.:24.00
Median :457.0 3: 10 Mode :character Median :36.00
Mean :455.4 Mean :35.67
3rd Qu.:676.0 3rd Qu.:47.50
Max. :890.0 Max. :80.00
SibSp Parch Ticket Fare
Min. :0.0000 Min. :0.0000 Length:183 Min. : 0.00
1st Qu.:0.0000 1st Qu.:0.0000 Class :character 1st Qu.: 29.70
Median :0.0000 Median :0.0000 Mode :character Median : 57.00
Mean :0.4645 Mean :0.4754 Mean : 78.68
3rd Qu.:1.0000 3rd Qu.:1.0000 3rd Qu.: 90.00
Max. :3.0000 Max. :4.0000 Max. :512.33
Cabin Embarked CabinLetter CabinNumber Title
Length:183 Length:183 C :51 6 : 6 Mr :81
Class :character Class :character B :43 33 : 6 Miss :44
Mode :character Mode :character D :31 2 : 5 Mrs :38
E :30 20 : 5 Master : 7
A :12 22 : 5 Dr : 3
F :11 (Other):149 Major : 2
(Other): 5 NA's : 7 (Other): 8
Surname
Carter : 4
Fortune : 4
Allison : 3
Graham : 3
Navratil: 3
Newell : 3
(Other) :163
head(train2)
変数の変換
- 以下の要領で、いくつかの変数をファクター変数に変換します。
- 変数の変換は、このサイトを参考にしました。
train2$Survived <- factor(train2$Survived)
train2$Pclass <- factor(train2$Pclass)
train2$Sex <- factor(train2$Sex)
train2$CabinLetter = factor(substr(train2$Cabin, 1, 1))
train2$CabinNumber = factor(as.numeric(substr(train2$Cabin, 2, 4)))
train2$Title = factor(gsub('(.*, )|(\\..*)', '', train2$Name))
train2$Surname <- factor(sapply(train2$Name, function(x){x=as.character(x); strsplit(x, split = '[,.]')[[1]][1];}))
train2$CabinNumber = factor(train2$CabinNumber)
モデルの推定
ロジスティック回帰モデルの推定
glm()
関数を用いてロジスティック回帰モデルを推定します。リンク関数をfamily=binomial(link='logit')
と指定します。
glm.logit1 <- glm(Survived~Pclass+Sex+Age+SibSp+Parch+Fare+Embarked+CabinLetter+Title,
data=train2, family=binomial(link='logit'))
summary(glm.logit1)
Call:
glm(formula = Survived ~ Pclass + Sex + Age + SibSp + Parch +
Fare + Embarked + CabinLetter + Title, family = binomial(link = "logit"),
data = train2)
Deviance Residuals:
Min 1Q Median 3Q Max
-2.3499 -0.6664 0.1865 0.3934 1.9563
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 2.044e+00 9.224e+03 0.000 1.000
Pclass2 -6.710e-01 1.260e+00 -0.533 0.594
Pclass3 -1.754e-01 1.582e+00 -0.111 0.912
Sexmale -1.781e+01 6.523e+03 -0.003 0.998
Age -2.859e-02 1.826e-02 -1.566 0.117
SibSp 2.954e-01 4.173e-01 0.708 0.479
Parch -5.683e-01 4.055e-01 -1.401 0.161
Fare 3.542e-03 3.559e-03 0.995 0.320
EmbarkedQ -2.064e+00 2.109e+00 -0.979 0.328
EmbarkedS -5.330e-01 5.433e-01 -0.981 0.327
CabinLetterB -2.400e-01 9.574e-01 -0.251 0.802
CabinLetterC -1.025e+00 9.397e-01 -1.091 0.275
CabinLetterD 3.513e-01 9.649e-01 0.364 0.716
CabinLetterE 6.872e-01 9.481e-01 0.725 0.469
CabinLetterF -1.054e+00 1.775e+00 -0.594 0.552
CabinLetterG -3.070e+00 2.246e+00 -1.367 0.172
CabinLetterT -1.783e+01 6.523e+03 -0.003 0.998
TitleCol 3.581e+01 9.224e+03 0.004 0.997
TitleDr 1.801e+01 6.523e+03 0.003 0.998
TitleLady 1.746e+01 1.130e+04 0.002 0.999
TitleMajor 1.822e+01 6.523e+03 0.003 0.998
TitleMaster 3.627e+01 6.955e+03 0.005 0.996
TitleMiss 2.570e+00 9.224e+03 0.000 1.000
TitleMlle 1.769e+01 1.028e+04 0.002 0.999
TitleMme 1.720e+01 1.130e+04 0.002 0.999
TitleMr 1.673e+01 6.523e+03 0.003 0.998
TitleMrs 2.761e+00 9.224e+03 0.000 1.000
TitleSir 3.524e+01 9.224e+03 0.004 0.997
Titlethe Countess 1.793e+01 1.130e+04 0.002 0.999
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 231.55 on 182 degrees of freedom
Residual deviance: 132.99 on 154 degrees of freedom
AIC: 190.99
Number of Fisher Scoring iterations: 17
car
パッケージのvif()
関数を使ってVIFを確認します。
car::vif(glm.logit1)
GVIF Df GVIF^(1/(2*Df))
Pclass 5.672965e+00 2 1.543308
Sex 1.533092e+08 1 12381.807908
Age 1.431840e+00 1 1.196595
SibSp 1.350778e+00 1 1.162230
Parch 1.523750e+00 1 1.234403
Fare 1.647715e+00 1 1.283634
Embarked 2.086932e+00 2 1.201924
CabinLetter 1.096882e+01 7 1.186580
Title 2.666478e+08 12 2.244299
glm.logit2 <- glm(Survived~Pclass+Sex+Age+SibSp+Parch+Fare+Embarked,
data=train2, family=binomial(link='logit'))
summary(glm.logit2)
Call:
glm(formula = Survived ~ Pclass + Sex + Age + SibSp + Parch +
Fare + Embarked, family = binomial(link = "logit"), data = train2)
Deviance Residuals:
Min 1Q Median 3Q Max
-2.6730 -0.7700 0.3052 0.5401 2.0412
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 4.451473 0.941136 4.730 2.25e-06 ***
Pclass2 0.059891 0.845412 0.071 0.94352
Pclass3 -1.512335 0.925014 -1.635 0.10206
Sexmale -2.904210 0.503842 -5.764 8.21e-09 ***
Age -0.039658 0.014788 -2.682 0.00732 **
SibSp 0.176325 0.356422 0.495 0.62081
Parch -0.438347 0.323717 -1.354 0.17570
Fare 0.001621 0.003024 0.536 0.59188
EmbarkedQ -1.882895 1.972139 -0.955 0.33971
EmbarkedS -0.373572 0.448718 -0.833 0.40511
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 231.55 on 182 degrees of freedom
Residual deviance: 159.76 on 173 degrees of freedom
AIC: 179.76
Number of Fisher Scoring iterations: 5
ロジスティック回帰モデルのオッズ比と95%信頼区間
exp(coef(glm.logit2))
(Intercept) Pclass2 Pclass3 Sexmale Age SibSp Parch
85.75313507 1.06172061 0.22039485 0.05479204 0.96111781 1.19282621 0.64510159
Fare EmbarkedQ EmbarkedS
1.00162224 0.15214902 0.68827120
exp(confint(glm.logit2))
Waiting for profiling to be done...
2.5 % 97.5 %
(Intercept) 15.265845913 624.2027347
Pclass2 0.214503960 6.3519834
Pclass3 0.033190848 1.2950601
Sexmale 0.018429484 0.1366699
Age 0.932319986 0.9883203
SibSp 0.599045274 2.4548105
Parch 0.332704463 1.1927129
Fare 0.995873242 1.0086291
EmbarkedQ 0.002980473 7.9613402
EmbarkedS 0.281694081 1.6530164
library(broom)
broom::tidy(glm.logit2, conf.int = TRUE, exponentiate = TRUE)
モデルを用いた予測と的中率
predict()
関数を用いてモデル上の(理論的な)生存確率を予測できます。
predict(glm.logit2, type="response")
2 4 7 11 12 22 24 28
0.96217871 0.95037004 0.29239251 0.89770494 0.86065670 0.47658486 0.53016350 0.62216968
53 55 63 67 76 89 93 97
0.94315564 0.20287680 0.42572841 0.95278692 0.21120090 0.96246937 0.40730786 0.22929355
98 103 111 119 124 125 137 138
0.57431375 0.50694849 0.35298097 0.63606581 0.94634176 0.21739232 0.92345909 0.49218310
140 149 152 171 175 178 184 194
0.67345220 0.25951368 0.97039320 0.23305068 0.34890716 0.92519356 0.76340557 0.70986489
195 196 206 210 216 219 225 231
0.93999469 0.91596858 0.88744061 0.50279481 0.97293304 0.96463648 0.49722097 0.95264151
246 249 252 253 258 263 264 269
0.17050350 0.38449735 0.76321952 0.22407266 0.95383910 0.26474381 0.39827886 0.83035193
270 274 276 292 293 298 300 306
0.94832444 0.42304140 0.86785423 0.98239695 0.54991420 0.97191044 0.91919235 0.66429339
308 310 311 312 319 320 326 328
0.98417365 0.96623564 0.97428094 0.97439103 0.90370053 0.94380722 0.96244339 0.93884075
330 332 333 337 338 340 341 342
0.96989722 0.35788266 0.37216944 0.57636739 0.95450096 0.36507820 0.71796431 0.96101026
346 357 367 370 371 378 391 394
0.96109925 0.94563939 0.91453239 0.97371202 0.69466017 0.48565882 0.31867519 0.98014545
395 413 430 431 435 436 439 446
0.68225218 0.82949650 0.16872907 0.52654836 0.36765518 0.95332851 0.07479936 0.56735021
450 453 454 457 461 463 474 485
0.30172375 0.59928678 0.48119958 0.20406753 0.33472918 0.34799955 0.97395598 0.70677314
487 488 493 497 499 505 506 513
0.95311640 0.33075394 0.27726322 0.93170088 0.93287565 0.97297452 0.76607104 0.44734633
516 517 521 524 537 540 541 545
0.34635401 0.94302225 0.95433612 0.91389439 0.36172209 0.94172451 0.86859499 0.47830871
551 557 559 572 573 578 582 584
0.54391409 0.94204514 0.91669848 0.91774579 0.44738641 0.94257643 0.94388022 0.54602025
586 588 592 600 610 619 622 626
0.93191362 0.27570251 0.93657857 0.46819538 0.93936434 0.98123240 0.44264203 0.23270922
628 631 633 642 646 648 660 663
0.96679997 0.12451568 0.58118388 0.97371202 0.48609413 0.35067827 0.19061746 0.34326580
672 680 682 690 691 699 700 701
0.55104568 0.62519662 0.64585323 0.96730340 0.55304988 0.38265782 0.12005676 0.98638333
702 708 711 713 716 717 718 725
0.45717018 0.38951575 0.97287808 0.38478327 0.25355294 0.96488088 0.95622946 0.59032589
731 738 742 743 746 749 752 760
0.96339831 0.72902281 0.51252913 0.97124858 0.14813215 0.66431408 0.26998064 0.94830852
764 766 773 780 782 783 790 797
0.89513902 0.91356941 0.86924370 0.90693807 0.97521520 0.51804898 0.46290784 0.89813513
803 807 810 821 824 836 854 858
0.55764023 0.40782032 0.95398030 0.87047937 0.74586244 0.94145169 0.95559087 0.30877612
863 868 872 873 880 888 890
0.90170655 0.50653286 0.88464021 0.46831027 0.87292303 0.96685064 0.63755655
- 生存者の的中率は、以下のようにして計算できます。モデル
glm.logit2
を用いた場合には、的中率が77.596%となりました。
train3 <- train2 %>%
dplyr::mutate(predict=predict(glm.logit2, type="response"),
survive=dplyr::if_else(predict > 0.5, 1, 0))
sum(train3$Survived == train3$survive)/nrow(train3)*100
[1] 77.59563
プロビット回帰モデルの推定
glm()
関数を用いてロジスティック回帰モデルを推定します。リンク関数をfamily=binomial(link='probit')
と指定します。
glm.probit2 <- glm(Survived~Pclass+Sex+Age+SibSp+Parch+Fare+Embarked,
data=train2, family=binomial(link='probit'))
summary(glm.probit2)
Call:
glm(formula = Survived ~ Pclass + Sex + Age + SibSp + Parch +
Fare + Embarked, family = binomial(link = "probit"), data = train2)
Deviance Residuals:
Min 1Q Median 3Q Max
-2.7068 -0.7768 0.2880 0.5752 1.9984
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 2.530143 0.512473 4.937 7.93e-07 ***
Pclass2 0.066280 0.481734 0.138 0.89057
Pclass3 -0.846859 0.520452 -1.627 0.10370
Sexmale -1.668207 0.261009 -6.391 1.64e-10 ***
Age -0.022104 0.008376 -2.639 0.00831 **
SibSp 0.108097 0.203716 0.531 0.59568
Parch -0.292705 0.183126 -1.598 0.10996
Fare 0.001098 0.001785 0.615 0.53827
EmbarkedQ -1.106024 1.082945 -1.021 0.30711
EmbarkedS -0.226086 0.260391 -0.868 0.38526
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 231.55 on 182 degrees of freedom
Residual deviance: 159.74 on 173 degrees of freedom
AIC: 179.74
Number of Fisher Scoring iterations: 6
補対数対数モデルの推定
glm()
関数を用いてロジスティック回帰モデルを推定します。リンク関数をfamily = binomial('cloglog')
と指定します。
glm.cloglog2 <- glm(Survived~Pclass+Sex+Age+SibSp+Parch+Fare+Embarked,
data=train2, family=binomial(link='cloglog'))
summary(glm.cloglog2)
Call:
glm(formula = Survived ~ Pclass + Sex + Age + SibSp + Parch +
Fare + Embarked, family = binomial(link = "cloglog"), data = train2)
Deviance Residuals:
Min 1Q Median 3Q Max
-2.7479 -0.8394 0.2412 0.6222 1.7647
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.988022 0.499628 3.979 6.92e-05 ***
Pclass2 0.103065 0.451284 0.228 0.8193
Pclass3 -0.912063 0.562415 -1.622 0.1049
Sexmale -1.591601 0.237599 -6.699 2.10e-11 ***
Age -0.020518 0.008776 -2.338 0.0194 *
SibSp 0.106497 0.191274 0.557 0.5777
Parch -0.351570 0.186834 -1.882 0.0599 .
Fare 0.001433 0.001677 0.854 0.3929
EmbarkedQ -0.916746 1.082665 -0.847 0.3971
EmbarkedS -0.238959 0.260193 -0.918 0.3584
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 231.55 on 182 degrees of freedom
Residual deviance: 159.98 on 173 degrees of freedom
AIC: 179.98
Number of Fisher Scoring iterations: 9
LS0tCnRpdGxlOiAi57Wx6KiI6Kej5p6QUua8lOe/kjQiCiNhdXRob3I6ICJUb21veXVraSBGdXJ1dGFuaSIKI2RhdGU6ICIyMDE5LzgvOSIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKa25pdHI6Om9wdHNfY2h1bmskc2V0KGNhY2hlID0gVFJVRSkKa25pdHI6Om9wdHNfY2h1bmskc2V0KGVycm9yID0gVFJVRSkKYGBgCgojIyDmvJTnv5Ljga7mpoLopoEKLSDjg63jgrjjgrnjg4bjgqPjg4Pjgq/lm57luLDjg6Ljg4fjg6vjgIHjg5fjg63jg5Pjg4Pjg4jlm57luLDjg6Ljg4fjg6vjgIHoo5zlr77mlbDlr77mlbDjg6Ljg4fjg6sKCiMjIyDms6jmhI/kuovpoIUKLSDmhbbmh4nnvqnlob7lpKflraZTRkPjgafplovorJvjgZfjgabjgYTjgovjgIzntbHoqIjop6PmnpDjgI3jga7mjojmpa3lsaXkv67ogIXlkJHjgZHjga7mvJTnv5LnlKjjg5rjg7zjgrjjgafjgZnjgIIKLSDlv4XjgZrjgZfjgoLlhajjgabjga7jg5Djg7zjgrjjg6fjg7Pjga5S44KET1Pjgafli5XkvZznorroqo3jgpLooYzjgaPjgabjgYTjgb7jgZvjgpPjgILjgZPjga7mvJTnv5LnlKjjg5rjg7zjgrjjgpLkvZzmiJDjgZfjgabjgYTjgovmrrXpmo7jgafjga/jgIFSMy42LjDjgpLkvb/jgaPjgabjgYTjgb7jgZnjgIIKLSBS44Gu5pu05paw44Gq44Gp44Gr44KI44KK44CBUuOCs+ODvOODieOBquOBqeOCkuS6iOWRiueEoeOBl+OBq+WkieabtOOBmeOCi+WgtOWQiOOBjOOBguOCiuOBvuOBmeOAgiAKCiMjIOODh+ODvOOCv+WIhuaekOOBrua6luWCmQojIyMg44OR44OD44Kx44O844K444Gu44Kk44Oz44K544OI44O844OrCi0g5LuK5Zue44Gu5ryU57+S44Gn44Gv44CB5Lul5LiL44Gu44OR44OD44Kx44O844K444KS5L2/44GE44G+44GZ44CCCmBgYHtyIGluc3RhbGwucGFja2FnZXMsIGV2YWw9RkFMU0V9Cmluc3RhbGwucGFja2FnZXMoImRwbHlyIikKaW5zdGFsbC5wYWNrYWdlcygibWFncml0dHIiKQppbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QyIikKaW5zdGFsbC5wYWNrYWdlcygiY2FyIikKYGBgCgpgYGB7ciBsaWJyYXJ5LCBldmFsPUZBTFNFfQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KG1hZ3JpdHRyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoY2FyKQpgYGAKCiMjIyDjg4fjg7zjgr/jga7jg4Djgqbjg7Pjg63jg7zjg4kKLSDku4rlm57jga7mvJTnv5LjgafnlKjjgYTjgovjg4fjg7zjgr/jga/jgIFUaXRhbmlj44Gu55Sf5a2Y6ICF5oOF5aCx44OH44O844K/44Gn44GZ44CCCi0ga2FnZ2xl44GuW1RpdGFuaWM6IE1hY2hpbmUgTGVhcm5pbmcgZnJvbSBEaXNhc3Rlcl0oaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9jL3RpdGFuaWMvZGF0YSnjgYvjgonjg4Djgqbjg7Pjg63jg7zjg4njgafjgY3jgb7jgZnjgIIKLSBS44GuYHRpdGFuaWNg44Op44Kk44OW44Op44Oq44GL44KJ44KC5Yip55So44Gn44GN44G+44GZ44CCCmBgYHtyIGxpYnJhcnl0aXRhbmljLCBldmFsPUZBTFNFfQppbnN0YWxsLnBhY2thZ2VzKCJ0aXRhbmljIikKbGlicmFyeSh0aXRhbmljKQpgYGAKLSBgZWZmZWN0c2Djg6njgqTjg5bjg6njg6rjga5gVGl0YW5pY1N1cnZpdmFsYOODh+ODvOOCv+OCguWIqeeUqOOBp+OBjeOBvuOBmeOAggotIFvmvJTnv5LnlKjjg4fjg7zjgr9dKGh0dHA6Ly93ZWIuc2ZjLmtlaW8uYWMuanAvfm1hdW56L0RTQjE5L0RTQmRhdGEuemlwKeOBq+OCguWQq+OBvuOCjOOBpuOBhOOBvuOBmeOAggoKIyMjIOODh+ODvOOCv+OBruiqreOBv+i+vOOBvwotIOS9v+eUqOOBmeOCi+ODh+ODvOOCv+OBq+OBr+OAgeasoOaQjeWApOOBjOWQq+OBvuOCjOOBvuOBmeOAguasoOaQjeWApOOBr+OAgWBOQWDjgaflrprnvqnjgZXjgozjgabjgYTjgovloLTlkIjjgajjgIHnqbrnmb3jgajjgarjgaPjgabjgYTjgovloLTlkIjjga7kuKHmlrnjgYzjgYLjgovjga7jgafjgIFgbmEuc3RyaW5ncz0oYygiTkEiLCAiIikpYOOBq+OCiOOCiuasoOaQjeWApOOCkuWumue+qeOBl+OBvuOBmeOAggoKYGBge3IgcmVhZGRhdGExLCBlY2hvPVRSVUUsIGV2YWw9RkFMU0UsIG1lc3NhZ2U9VFJVRSwgd2FybmluZz1UUlVFfQprYWtlaSA8LSByZWFkLmNzdigiLi/jg5Xjgqnjg6vjg4DjgpLmjIflrpovdHJhaW4uY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEYsbmEuc3RyaW5ncz0oYygiTkEiLCAiIikpKQpgYGAKCmBgYHtyIHJlYWRkYXRhMiwgZWNobz1GQUxTRSwgZXZhbD1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQprYWtlaSA8LSByZWFkLmNzdigifi9Hb29nbGUgRHJpdmUgRmlsZSBTdHJlYW0v44Oe44Kk44OI44KZ44Op44Kk44OV44KZL0xlY3R1cmUgJiBFeGNlY2lzZS8yMDE5XzIwNF/np4vjg7vntbHoqIjop6PmnpAv5o6I5qWt6LOH5paZUm1kXzIwMTkwODA5L0RTQmRhdGEvdHJhaW4uY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEYsbmEuc3RyaW5ncz0oYygiTkEiLCAiIikpKQpgYGAKCmBgYHtyIGhlYWRzdW0xfQpoZWFkKHRyYWluKQpzdW1tYXJ5KHRyYWluKQpgYGAKCiMjIyDmrKDmkI3lgKTjga7lh6bnkIYKLSBgc3VtbWFyeSgpYOmWouaVsOOBoOOBkeOBp+OBr+asoOaQjeWApOOBrueKtuazgeOBjOOCj+OBi+OCiuOBq+OBj+OBhOOBruOBp+OAgeS7peS4i+OBruaWueazleOBp+asoOaQjeWApOOCkuaKiuaPoeOBl+OBvuOBmeOAggpgYGB7ciBuYV9jb3VudH0KbmFfY291bnRfdHJhaW4gPC0gc2FwcGx5KHRyYWluLCBmdW5jdGlvbih5KSBzdW0oaXMubmEoeSkpKQpuYV9jb3VudF90cmFpbgpgYGAKLSDmrKDmkI3lgKTjga7lh6bnkIbjgavjga/jgIHkuLvjgavmrKDmkI3lgKTjgpLpmaTljrvjgZnjgovmlrnms5XjgajjgIHkvZXjgonjgYvjga7mlrnms5XjgafmrKDmkI3lgKTjgavlgKTjgpLku6PlhaXjgZnjgovmlrnms5XjgajjgYzjgYLjgorjgb7jgZnjgILjgZPjgZPjgafjga/jgIHmrKDmkI3lgKTjgpLpmaTljrvjgZnjgovmlrnms5XjgpLmjqHnlKjjgZnjgovjgZPjgajjgavjgZfjgb7jgZnjgIIKLSBgbmEub21pdCgpYOmWouaVsOOBp+asoOaQjeWApOOCkumZpOWOu+OBl+OBvuOBmeOAguasoOaQjeWApOOCkumZpOWOu+OBl+OBn+ODh+ODvOOCv+OCkuOAgWB0cmFpbjJg44Go44GX44G+44GZ44CCCmBgYHtuYS5vbWl0LCBldmFsPUZBTFNFfQp0cmFpbjIgPC0gbmEub21pdCh0cmFpbikKYGBgCi0g5qyg5pCN5YCk6Zmk5Y675b6M44Gu44OH44O844K/44Gv5Lul5LiL44Gu44KI44GG44Gr44Gq44KK44G+44GZ44CCCmBgYHtyIGhlYWRzdW0yfQpzdW1tYXJ5KHRyYWluMikKaGVhZCh0cmFpbjIpCmBgYAoKIyMjIOWkieaVsOOBruWkieaPmwotIOS7peS4i+OBruimgemgmOOBp+OAgeOBhOOBj+OBpOOBi+OBruWkieaVsOOCkuODleOCoeOCr+OCv+ODvOWkieaVsOOBq+WkieaPm+OBl+OBvuOBmeOAggotIOWkieaVsOOBruWkieaPm+OBr+OAgVvjgZPjga7jgrXjgqTjg4hdKGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vaWdiYXRvdi90aXRhbmljLWRhdGEtZXhwbG9yYXRpb24td2l0aC1nbG0p44KS5Y+C6ICD44Gr44GX44G+44GX44Gf44CCCmBgYHtyIHRyYWluMl90cmFuc2Zvcm0sIGVjaG89VFJVRSwgd2FybmluZz1UUlVFfQp0cmFpbjIkU3Vydml2ZWQgPC0gZmFjdG9yKHRyYWluMiRTdXJ2aXZlZCkKdHJhaW4yJFBjbGFzcyA8LSBmYWN0b3IodHJhaW4yJFBjbGFzcykKdHJhaW4yJFNleCA8LSBmYWN0b3IodHJhaW4yJFNleCkKdHJhaW4yJENhYmluTGV0dGVyID0gZmFjdG9yKHN1YnN0cih0cmFpbjIkQ2FiaW4sIDEsIDEpKQp0cmFpbjIkQ2FiaW5OdW1iZXIgPSBmYWN0b3IoYXMubnVtZXJpYyhzdWJzdHIodHJhaW4yJENhYmluLCAyLCA0KSkpCnRyYWluMiRUaXRsZSA9IGZhY3Rvcihnc3ViKCcoLiosICl8KFxcLi4qKScsICcnLCB0cmFpbjIkTmFtZSkpCnRyYWluMiRTdXJuYW1lIDwtIGZhY3RvcihzYXBwbHkodHJhaW4yJE5hbWUsIGZ1bmN0aW9uKHgpe3g9YXMuY2hhcmFjdGVyKHgpOyBzdHJzcGxpdCh4LCBzcGxpdCA9ICdbLC5dJylbWzFdXVsxXTt9KSkKdHJhaW4yJENhYmluTnVtYmVyID0gZmFjdG9yKHRyYWluMiRDYWJpbk51bWJlcikKYGBgCgoKIyMg44Oi44OH44Or44Gu5o6o5a6aCiMjIyDjg63jgrjjgrnjg4bjgqPjg4Pjgq/lm57luLDjg6Ljg4fjg6vjga7mjqjlrpoKLSBgZ2xtKClg6Zai5pWw44KS55So44GE44Gm44Ot44K444K544OG44Kj44OD44Kv5Zue5biw44Oi44OH44Or44KS5o6o5a6a44GX44G+44GZ44CC44Oq44Oz44Kv6Zai5pWw44KSYGZhbWlseT1iaW5vbWlhbChsaW5rPSdsb2dpdCcpYOOBqOaMh+WumuOBl+OBvuOBmeOAggoKYGBge3IgZ2xtLmxvZ2l0MX0KZ2xtLmxvZ2l0MSA8LSBnbG0oU3Vydml2ZWR+UGNsYXNzK1NleCtBZ2UrU2liU3ArUGFyY2grRmFyZStFbWJhcmtlZCtDYWJpbkxldHRlcitUaXRsZSwKICAgICAgICAgICAgZGF0YT10cmFpbjIsIGZhbWlseT1iaW5vbWlhbChsaW5rPSdsb2dpdCcpKQpzdW1tYXJ5KGdsbS5sb2dpdDEpCmBgYAotIGBjYXJg44OR44OD44Kx44O844K444GuYHZpZigpYOmWouaVsOOCkuS9v+OBo+OBplZJRuOCkueiuuiqjeOBl+OBvuOBmeOAggpgYGB7ciB2aWYxfQpjYXI6OnZpZihnbG0ubG9naXQxKQpgYGAKCi0g44Gd44GT44Gn5qyh44Gr44CB5qyh5byP44Gu44Oi44OH44Or44KS5o6o5a6a44GX44G+44GZ44CCCmBgYHtyIGdsbS5sb2dpdDJ9CmdsbS5sb2dpdDIgPC0gZ2xtKFN1cnZpdmVkflBjbGFzcytTZXgrQWdlK1NpYlNwK1BhcmNoK0ZhcmUrRW1iYXJrZWQsCiAgICAgICAgICAgIGRhdGE9dHJhaW4yLCBmYW1pbHk9Ymlub21pYWwobGluaz0nbG9naXQnKSkKc3VtbWFyeShnbG0ubG9naXQyKQpgYGAKIyMjIOODreOCuOOCueODhuOCo+ODg+OCr+WbnuW4sOODouODh+ODq+OBruOCquODg+OCuuavlOOBqDk1JeS/oemgvOWMuumWkwotIOOCquODg+OCuuavlOOBr+S7peS4i+OBruOCiOOBhuOBq+OBl+OBpuWHuuWKm+OBp+OBjeOBvuOBmeOAggpgYGB7ciBnbG0ubG9naXQyLm9kZHN9CmV4cChjb2VmKGdsbS5sb2dpdDIpKQpgYGAKLSA5NSXkv6HpoLzljLrplpPjga/ku6XkuIvjga7jgojjgYbjgavjgZfjgablh7rlipvjgafjgY3jgb7jgZnjgIIKYGBge3IgZ2xtLmxvZ2l0Mi5jaX0KZXhwKGNvbmZpbnQoZ2xtLmxvZ2l0MikpCmBgYAoKLSDku6XkuIvjga7mlrnms5XjgafjgoLlh7rlipvjgafjgY3jgb7jgZnjgIIKYGBge3IgZ2xtLmxvZ2l0Mi5icm9vbX0KbGlicmFyeShicm9vbSkKYnJvb206OnRpZHkoZ2xtLmxvZ2l0MiwgY29uZi5pbnQgPSBUUlVFLCBleHBvbmVudGlhdGUgPSBUUlVFKQpgYGAKCiMjIyDjg6Ljg4fjg6vjgpLnlKjjgYTjgZ/kuojmuKzjgajnmoTkuK3njocKLSBgcHJlZGljdCgpYOmWouaVsOOCkueUqOOBhOOBpuODouODh+ODq+S4iuOBru+8iOeQhuirlueahOOBqu+8ieeUn+WtmOeiuueOh+OCkuS6iOa4rOOBp+OBjeOBvuOBmeOAggpgYGB7ciBnbG0ubG9naXQyLnByZWQxfQpwcmVkaWN0KGdsbS5sb2dpdDIsIHR5cGU9InJlc3BvbnNlIikKYGBgCi0g55Sf5a2Y6ICF44Gu55qE5Lit546H44Gv44CB5Lul5LiL44Gu44KI44GG44Gr44GX44Gm6KiI566X44Gn44GN44G+44GZ44CC44Oi44OH44OrYGdsbS5sb2dpdDJg44KS55So44GE44Gf5aC05ZCI44Gr44Gv44CB55qE5Lit546H44GMNzcuNTk2JeOBqOOBquOCiuOBvuOBl+OBn+OAggpgYGB7ciBnbG0ubG9naXQyLmhpdFJ9CnRyYWluMyA8LSB0cmFpbjIgJT4lCiAgZHBseXI6Om11dGF0ZShwcmVkaWN0PXByZWRpY3QoZ2xtLmxvZ2l0MiwgdHlwZT0icmVzcG9uc2UiKSwKICAgICAgICAgc3Vydml2ZT1kcGx5cjo6aWZfZWxzZShwcmVkaWN0ID4gMC41LCAxLCAwKSkKc3VtKHRyYWluMyRTdXJ2aXZlZCA9PSB0cmFpbjMkc3Vydml2ZSkvbnJvdyh0cmFpbjMpKjEwMApgYGAKCiMjIyDjg5fjg63jg5Pjg4Pjg4jlm57luLDjg6Ljg4fjg6vjga7mjqjlrpoKLSBgZ2xtKClg6Zai5pWw44KS55So44GE44Gm44Ot44K444K544OG44Kj44OD44Kv5Zue5biw44Oi44OH44Or44KS5o6o5a6a44GX44G+44GZ44CC44Oq44Oz44Kv6Zai5pWw44KSYGZhbWlseT1iaW5vbWlhbChsaW5rPSdwcm9iaXQnKWDjgajmjIflrprjgZfjgb7jgZnjgIIKCmBgYHtyIGdsbS5wcm9iaXQyfQpnbG0ucHJvYml0MiA8LSBnbG0oU3Vydml2ZWR+UGNsYXNzK1NleCtBZ2UrU2liU3ArUGFyY2grRmFyZStFbWJhcmtlZCwKICAgICAgICAgICAgICAgICAgZGF0YT10cmFpbjIsIGZhbWlseT1iaW5vbWlhbChsaW5rPSdwcm9iaXQnKSkKc3VtbWFyeShnbG0ucHJvYml0MikKYGBgCgojIyMg6KOc5a++5pWw5a++5pWw44Oi44OH44Or44Gu5o6o5a6aCi0gYGdsbSgpYOmWouaVsOOCkueUqOOBhOOBpuODreOCuOOCueODhuOCo+ODg+OCr+WbnuW4sOODouODh+ODq+OCkuaOqOWumuOBl+OBvuOBmeOAguODquODs+OCr+mWouaVsOOCkmBmYW1pbHkgPSBiaW5vbWlhbCgnY2xvZ2xvZycpYOOBqOaMh+WumuOBl+OBvuOBmeOAggpgYGB7ciBnbG0uY2xvZ2xvZzJ9CmdsbS5jbG9nbG9nMiA8LSBnbG0oU3Vydml2ZWR+UGNsYXNzK1NleCtBZ2UrU2liU3ArUGFyY2grRmFyZStFbWJhcmtlZCwKICAgICAgICAgICAgICAgICAgIGRhdGE9dHJhaW4yLCBmYW1pbHk9Ymlub21pYWwobGluaz0nY2xvZ2xvZycpKQpzdW1tYXJ5KGdsbS5jbG9nbG9nMikKYGBgCg==