演習の概要

注意事項

  • 慶應義塾大学SFCで開講している「統計解析」の授業履修者向けの演習用ページです。
  • 必ずしも全てのバージョンのRやOSで動作確認を行っていません。この演習用ページを作成している段階では、R3.6.0を使っています。
  • Rの更新などにより、Rコードなどを予告無しに変更する場合があります。

データ分析の準備

パッケージのインストール

  • 今回の演習では、以下のパッケージを使います。
install.packages("ggplot2")
install.packages("glmnet")
install.packages("lars")
library(ggplot2)
library(glmnet)
library(lars)

モデル推定

データの読み込み

  • 今回の演習では、larsパッケージに含まれるdiabetesデータを用います。
data("diabetes")
head(diabetes)

線形回帰モデル

  • まず重回帰モデルを推定します。
dia.lm <- lm(y~x, data=diabetes)
summary(dia.lm)

Call:
lm(formula = y ~ x, data = diabetes)

Residuals:
     Min       1Q   Median       3Q      Max 
-155.829  -38.534   -0.227   37.806  151.355 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  152.133      2.576  59.061  < 2e-16 ***
xage         -10.012     59.749  -0.168 0.867000    
xsex        -239.819     61.222  -3.917 0.000104 ***
xbmi         519.840     66.534   7.813 4.30e-14 ***
xmap         324.390     65.422   4.958 1.02e-06 ***
xtc         -792.184    416.684  -1.901 0.057947 .  
xldl         476.746    339.035   1.406 0.160389    
xhdl         101.045    212.533   0.475 0.634721    
xtch         177.064    161.476   1.097 0.273456    
xltg         751.279    171.902   4.370 1.56e-05 ***
xglu          67.625     65.984   1.025 0.305998    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 54.15 on 431 degrees of freedom
Multiple R-squared:  0.5177,    Adjusted R-squared:  0.5066 
F-statistic: 46.27 on 10 and 431 DF,  p-value: < 2.2e-16

Ridge回帰モデル

  • Ridge回帰モデルとLasso回帰モデルは、glmnetパッケージのglmnet()関数を用いて推定します。
  • Ridge回帰モデルは、glmnet()関数の引数alpha=0を指定して推定します。
dia.ridge <- glmnet(diabetes$x, diabetes$y, 
                    # family="gaussian", 
                    alpha=0)
  • 回帰係数と\(log(\lambda)\)との関係を可視化します。
plot(dia.ridge, label=TRUE)

  • 回帰係数と\(\lambda\)との関係を可視化します。
plot(dia.ridge, xvar="lambda", label=TRUE)

  • クロスバリデーションによって、最適な\(\lambda\)を決定します。
dia.ridge.cv <- cv.glmnet(diabetes$x, diabetes$y, 
                    # family="gaussian", 
                    alpha=0)
  • クロスバリデーションの結果を可視化します。
plot(dia.ridge.cv)

  • 左側の縦点線が、MSEが最小となる\(log(\lambda)\)となります。
  • Cross-varidated errorの最小値、\(\lambda\)の最小値、及びその対数値は以下の通りになります。
min(dia.ridge.cv$cvm)
[1] 3009.391
dia.ridge.cv$lambda.min
[1] 4.516003
log(dia.ridge.cv$lambda.min)
[1] 1.507627
  • 選ばれた\(\lambda\)を、ペナルティと推定値のグラフに描き入れます。
plot(dia.ridge, xvar="lambda", label=TRUE)
abline(v=log(dia.ridge.cv$lambda.min), lty=2)

  • MSEが最小となる時の\(\lambda\)に対応するパラメータを出力します。
coef(dia.ridge.cv, s="lambda.min")
11 x 1 sparse Matrix of class "dgCMatrix"
                      1
(Intercept)  152.133484
age           -1.963374
sex         -218.701018
bmi          504.476167
map          309.708936
tc          -119.907209
ldl          -49.703556
hdl         -180.454315
tch          113.546639
ltg          472.886004
glu           80.608255
  • MSEが最小となるときのMSEの上側\(1se\)となるときの\(\lambda\)に対応するパラメータを出力します。
coef(dia.ridge.cv, s="lambda.1se")
11 x 1 sparse Matrix of class "dgCMatrix"
                       1
(Intercept)  152.1334842
age           26.7106843
sex          -99.2102956
bmi          333.5263290
map          217.0738406
tc            -0.7188819
ldl          -39.5932668
hdl         -160.6401985
tch          119.7418295
ltg          285.4877726
glu          112.9543267
  • 推定したパラメータによる予測値を出力します。
pred_dia.ridge.cv <- predict(dia.ridge.cv, s="lambda.min", newx=diabetes$x)
head(pred_dia.ridge.cv)
             1
[1,] 201.43621
[2,]  72.08768
[3,] 173.52631
[4,] 162.54031
[5,] 128.40638
[6,] 104.37765

Lasso回帰モデル

  • Lasso回帰モデルは、glmnet()関数の引数alpha=1を指定して推定します。
dia.lasso <- glmnet(diabetes$x, diabetes$y, 
                    # family="gaussian", 
                    alpha=1)
  • 回帰係数と\(log(\lambda)\)との関係を可視化します。
plot(dia.lasso, label=TRUE)

  • 回帰係数と\(\lambda\)との関係を可視化します。
plot(dia.lasso, xvar="lambda", label=TRUE)

  • クロスバリデーションによって、最適な\(\lambda\)を決定します。
dia.lasso.cv <- cv.glmnet(diabetes$x, diabetes$y, 
                          # family="gaussian", 
                          alpha=1)
  • クロスバリデーションの結果を可視化します。
plot(dia.lasso.cv)

  • 左側の縦点線が、MSEが最小となる\(log(\lambda)\)となります。
  • Cross-varidated errorの最小値、\(\lambda\)の最小値、及びその対数値は以下の通りになります。
min(dia.lasso.cv$cvm)
[1] 2986.619
dia.lasso.cv$lambda.min
[1] 0.0735996
log(dia.lasso.cv$lambda.min)
[1] -2.609116
  • 選ばれた\(\lambda\)を、ペナルティと推定値のグラフに描き入れます。
plot(dia.lasso, xvar="lambda", label=TRUE)
abline(v=log(dia.lasso.cv$lambda.min), lty=2)

  • MSEが最小となる時の\(\lambda\)に対応するパラメータを出力します。
coef(dia.lasso.cv, s="lambda.min")
11 x 1 sparse Matrix of class "dgCMatrix"
                     1
(Intercept)  152.13348
age           -6.62609
sex         -235.98713
bmi          522.13081
map          321.24746
tc          -565.68036
ldl          298.49852
hdl            .      
tch          145.55907
ltg          667.99392
glu           66.80703
  • MSEが最小となるときのMSEの上側\(1se\)となるときの\(\lambda\)に対応するパラメータを出力します。
coef(dia.lasso.cv, s="lambda.1se")
11 x 1 sparse Matrix of class "dgCMatrix"
                      1
(Intercept)  152.133484
age            .       
sex          -82.922210
bmi          511.428467
map          238.119244
tc             .       
ldl            .       
hdl         -175.401082
tch            .       
ltg          451.053356
glu            2.612794
  • 推定したパラメータによる予測値を出力します。
pred_dia.lasso.cv <- predict(dia.lasso.cv, s="lambda.min", newx=diabetes$x)

EN回帰モデル

  • EN回帰モデルは、glmnet()関数の引数alphaの値を0〜1の間で指定して推定します。ここではalpha=0.5とします。
dia.EN <- glmnet(diabetes$x, diabetes$y, 
                    # family="gaussian", 
                    alpha=0.5)
  • 回帰係数と\(log(\lambda)\)との関係を可視化します。
plot(dia.EN, label=TRUE)

  • 回帰係数と\(\lambda\)との関係を可視化します。
plot(dia.EN, xvar="lambda", label=TRUE)

  • クロスバリデーションによって、最適な\(\lambda\)を決定します。
dia.EN.cv <- cv.glmnet(diabetes$x, diabetes$y, 
                          # family="gaussian", 
                          alpha=0.5)
  • クロスバリデーションの結果を可視化します。
plot(dia.EN.cv)

  • 左側の縦点線が、MSEが最小となる\(log(\lambda)\)となります。
  • Cross-varidated errorの最小値、\(\lambda\)の最小値、及びその対数値は以下の通りになります。
min(dia.EN.cv$cvm)
[1] 2996.299
dia.EN.cv$lambda.min
[1] 1.506629
log(dia.EN.cv$lambda.min)
[1] 0.409875
  • 選ばれた\(\lambda\)を、ペナルティと推定値のグラフに描き入れます。
plot(dia.EN, xvar="lambda", label=TRUE)
abline(v=log(dia.EN.cv$lambda.min), lty=2)

  • MSEが最小となる時の\(\lambda\)に対応するパラメータを出力します。
coef(dia.EN.cv, s="lambda.min")
11 x 1 sparse Matrix of class "dgCMatrix"
                     1
(Intercept)  152.13348
age            .      
sex         -203.45857
bmi          519.20505
map          300.63375
tc          -123.93250
ldl            .      
hdl         -205.28618
tch           30.94044
ltg          510.96600
glu           59.80693
  • MSEが最小となるときのMSEの上側\(1se\)となるときの\(\lambda\)に対応するパラメータを出力します。
coef(dia.EN.cv, s="lambda.1se")
11 x 1 sparse Matrix of class "dgCMatrix"
                      1
(Intercept)  152.133484
age            .       
sex          -11.219144
bmi          475.321772
map          201.859709
tc             .       
ldl            .       
hdl         -132.714852
tch            .       
ltg          416.987550
glu            4.915767
  • 推定したパラメータによる予測値を出力します。
pred_dia.EN.cv <- predict(dia.EN.cv, s="lambda.min", newx=diabetes$x)
head(pred_dia.EN.cv)
             1
[1,] 203.85801
[2,]  70.69643
[3,] 175.32245
[4,] 162.15954
[5,] 127.52535
[6,] 105.15072
  • 今回の演習は以上です。
LS0tCnRpdGxlOiAi57Wx6KiI6Kej5p6QUua8lOe/kjkiCiNhdXRob3I6ICJUb21veXVraSBGdXJ1dGFuaSIKI2RhdGU6ICIyMDE5LzgvMTQiCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDogZGVmYXVsdAotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmtuaXRyOjpvcHRzX2NodW5rJHNldChjYWNoZSA9IFRSVUUpCmtuaXRyOjpvcHRzX2NodW5rJHNldChlcnJvciA9IFRSVUUpCmBgYAoKIyMg5ryU57+S44Gu5qaC6KaBCi0gTGFzc2/lm57luLDjg6Ljg4fjg6vjgIFSaWRnZeWbnuW4sOODouODh+ODqwoKIyMjIOazqOaEj+S6i+mghQotIOaFtuaHiee+qeWhvuWkp+WtplNGQ+OBp+mWi+ism+OBl+OBpuOBhOOCi+OAjOe1seioiOino+aekOOAjeOBruaOiOalreWxpeS/ruiAheWQkeOBkeOBrua8lOe/kueUqOODmuODvOOCuOOBp+OBmeOAggotIOW/heOBmuOBl+OCguWFqOOBpuOBruODkOODvOOCuOODp+ODs+OBrlLjgoRPU+OBp+WLleS9nOeiuuiqjeOCkuihjOOBo+OBpuOBhOOBvuOBm+OCk+OAguOBk+OBrua8lOe/kueUqOODmuODvOOCuOOCkuS9nOaIkOOBl+OBpuOBhOOCi+autemajuOBp+OBr+OAgVIzLjYuMOOCkuS9v+OBo+OBpuOBhOOBvuOBmeOAggotIFLjga7mm7TmlrDjgarjganjgavjgojjgorjgIFS44Kz44O844OJ44Gq44Gp44KS5LqI5ZGK54Sh44GX44Gr5aSJ5pu044GZ44KL5aC05ZCI44GM44GC44KK44G+44GZ44CCIAoKIyMg44OH44O844K/5YiG5p6Q44Gu5rqW5YKZCiMjIyDjg5Hjg4PjgrHjg7zjgrjjga7jgqTjg7Pjgrnjg4jjg7zjg6sKLSDku4rlm57jga7mvJTnv5Ljgafjga/jgIHku6XkuIvjga7jg5Hjg4PjgrHjg7zjgrjjgpLkvb/jgYTjgb7jgZnjgIIKYGBge3IgaW5zdGFsbC5wYWNrYWdlcywgZXZhbD1GQUxTRX0KaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpCmluc3RhbGwucGFja2FnZXMoImdsbW5ldCIpCmluc3RhbGwucGFja2FnZXMoImxhcnMiKQpgYGAKCmBgYHtyIGxpYnJhcnksIGV2YWw9RkFMU0V9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnbG1uZXQpCmxpYnJhcnkobGFycykKYGBgCgojIyDjg6Ljg4fjg6vmjqjlrpoKIyMjIOODh+ODvOOCv+OBruiqreOBv+i+vOOBvwotIOS7iuWbnuOBrua8lOe/kuOBp+OBr+OAgWBsYXJzYOODkeODg+OCseODvOOCuOOBq+WQq+OBvuOCjOOCi2BkaWFiZXRlc2Djg4fjg7zjgr/jgpLnlKjjgYTjgb7jgZnjgIIKYGBge3IgZGlhYmV0ZXN9CmRhdGEoImRpYWJldGVzIikKaGVhZChkaWFiZXRlcykKYGBgCgojIyMg57ea5b2i5Zue5biw44Oi44OH44OrCi0g44G+44Ga6YeN5Zue5biw44Oi44OH44Or44KS5o6o5a6a44GX44G+44GZ44CCCmBgYHtyIGRpYS5sbX0KZGlhLmxtIDwtIGxtKHl+eCwgZGF0YT1kaWFiZXRlcykKc3VtbWFyeShkaWEubG0pCmBgYAoKIyMjIFJpZGdl5Zue5biw44Oi44OH44OrCi0gUmlkZ2Xlm57luLDjg6Ljg4fjg6vjgahMYXNzb+WbnuW4sOODouODh+ODq+OBr+OAgWBnbG1uZXRg44OR44OD44Kx44O844K444GuYGdsbW5ldCgpYOmWouaVsOOCkueUqOOBhOOBpuaOqOWumuOBl+OBvuOBmeOAggotIFJpZGdl5Zue5biw44Oi44OH44Or44Gv44CBYGdsbW5ldCgpYOmWouaVsOOBruW8leaVsGBhbHBoYT0wYOOCkuaMh+WumuOBl+OBpuaOqOWumuOBl+OBvuOBmeOAggpgYGB7ciBjb2EucmlkZ2V9CmRpYS5yaWRnZSA8LSBnbG1uZXQoZGlhYmV0ZXMkeCwgZGlhYmV0ZXMkeSwgCiAgICAgICAgICAgICAgICAgICAgIyBmYW1pbHk9ImdhdXNzaWFuIiwgCiAgICAgICAgICAgICAgICAgICAgYWxwaGE9MCkKYGBgCi0g5Zue5biw5L+C5pWw44GoJGxvZyhcbGFtYmRhKSTjgajjga7plqLkv4LjgpLlj6/oppbljJbjgZfjgb7jgZnjgIIKYGBge3IgZGlhLnJpZGdlLnBsb3QxfQpwbG90KGRpYS5yaWRnZSwgbGFiZWw9VFJVRSkKYGBgCi0g5Zue5biw5L+C5pWw44GoJFxsYW1iZGEk44Go44Gu6Zai5L+C44KS5Y+v6KaW5YyW44GX44G+44GZ44CCCmBgYHtyIGRpYS5yaWRnZS5wbG90Mn0KcGxvdChkaWEucmlkZ2UsIHh2YXI9ImxhbWJkYSIsIGxhYmVsPVRSVUUpCmBgYAotIOOCr+ODreOCueODkOODquODh+ODvOOCt+ODp+ODs+OBq+OCiOOBo+OBpuOAgeacgOmBqeOBqiRcbGFtYmRhJOOCkuaxuuWumuOBl+OBvuOBmeOAggpgYGB7ciBkaWEucmlkZ2UuY3Z9CmRpYS5yaWRnZS5jdiA8LSBjdi5nbG1uZXQoZGlhYmV0ZXMkeCwgZGlhYmV0ZXMkeSwgCiAgICAgICAgICAgICAgICAgICAgIyBmYW1pbHk9ImdhdXNzaWFuIiwgCiAgICAgICAgICAgICAgICAgICAgYWxwaGE9MCkKYGBgCi0g44Kv44Ot44K544OQ44Oq44OH44O844K344On44Oz44Gu57WQ5p6c44KS5Y+v6KaW5YyW44GX44G+44GZ44CCCmBgYHtyIGRpYS5yaWRnZS5jdi5wbG90fQpwbG90KGRpYS5yaWRnZS5jdikKYGBgCi0g5bem5YG044Gu57im54K557ea44GM44CBTVNF44GM5pyA5bCP44Go44Gq44KLJGxvZyhcbGFtYmRhKSTjgajjgarjgorjgb7jgZnjgIIKLSBDcm9zcy12YXJpZGF0ZWQgZXJyb3Ljga7mnIDlsI/lgKTjgIEkXGxhbWJkYSTjga7mnIDlsI/lgKTjgIHlj4rjgbPjgZ3jga7lr77mlbDlgKTjga/ku6XkuIvjga7pgJrjgorjgavjgarjgorjgb7jgZnjgIIKYGBge3IgZGlhLnJpZGdlLmN2Lm1zZX0KbWluKGRpYS5yaWRnZS5jdiRjdm0pCmRpYS5yaWRnZS5jdiRsYW1iZGEubWluCmxvZyhkaWEucmlkZ2UuY3YkbGFtYmRhLm1pbikKYGBgCi0g6YG444Gw44KM44GfJFxsYW1iZGEk44KS44CB44Oa44OK44Or44OG44Kj44Go5o6o5a6a5YCk44Gu44Kw44Op44OV44Gr5o+P44GN5YWl44KM44G+44GZ44CCCmBgYHtyIGRpYS5yaWRnZS5jdi5wbG90M30KcGxvdChkaWEucmlkZ2UsIHh2YXI9ImxhbWJkYSIsIGxhYmVsPVRSVUUpCmFibGluZSh2PWxvZyhkaWEucmlkZ2UuY3YkbGFtYmRhLm1pbiksIGx0eT0yKQpgYGAKLSBNU0XjgYzmnIDlsI/jgajjgarjgovmmYLjga4kXGxhbWJkYSTjgavlr77lv5zjgZnjgovjg5Hjg6njg6Hjg7zjgr/jgpLlh7rlipvjgZfjgb7jgZnjgIIKYGBge3IgZGlhLnJpZGdlLmN2LmxhbWJkYS5taW59CmNvZWYoZGlhLnJpZGdlLmN2LCBzPSJsYW1iZGEubWluIikKYGBgCi0gTVNF44GM5pyA5bCP44Go44Gq44KL44Go44GN44GuTVNF44Gu5LiK5YG0JDFzZSTjgajjgarjgovjgajjgY3jga4kXGxhbWJkYSTjgavlr77lv5zjgZnjgovjg5Hjg6njg6Hjg7zjgr/jgpLlh7rlipvjgZfjgb7jgZnjgIIKYGBge3IgZGlhLnJpZGdlLmN2LmxhbWJkYS4xc2V9CmNvZWYoZGlhLnJpZGdlLmN2LCBzPSJsYW1iZGEuMXNlIikKYGBgCi0g5o6o5a6a44GX44Gf44OR44Op44Oh44O844K/44Gr44KI44KL5LqI5ris5YCk44KS5Ye65Yqb44GX44G+44GZ44CCCmBgYHtyIGRpYS5yaWRnZS5jdi5sYW1iZGEubWluLnByZWRpY3R9CnByZWRfZGlhLnJpZGdlLmN2IDwtIHByZWRpY3QoZGlhLnJpZGdlLmN2LCBzPSJsYW1iZGEubWluIiwgbmV3eD1kaWFiZXRlcyR4KQpoZWFkKHByZWRfZGlhLnJpZGdlLmN2KQpgYGAKCiMjIyBMYXNzb+WbnuW4sOODouODh+ODqwotIExhc3Nv5Zue5biw44Oi44OH44Or44Gv44CBYGdsbW5ldCgpYOmWouaVsOOBruW8leaVsGBhbHBoYT0xYOOCkuaMh+WumuOBl+OBpuaOqOWumuOBl+OBvuOBmeOAggpgYGB7ciBjb2EubGFzc299CmRpYS5sYXNzbyA8LSBnbG1uZXQoZGlhYmV0ZXMkeCwgZGlhYmV0ZXMkeSwgCiAgICAgICAgICAgICAgICAgICAgIyBmYW1pbHk9ImdhdXNzaWFuIiwgCiAgICAgICAgICAgICAgICAgICAgYWxwaGE9MSkKYGBgCi0g5Zue5biw5L+C5pWw44GoJGxvZyhcbGFtYmRhKSTjgajjga7plqLkv4LjgpLlj6/oppbljJbjgZfjgb7jgZnjgIIKYGBge3IgZGlhLmxhc3NvLnBsb3QxfQpwbG90KGRpYS5sYXNzbywgbGFiZWw9VFJVRSkKYGBgCi0g5Zue5biw5L+C5pWw44GoJFxsYW1iZGEk44Go44Gu6Zai5L+C44KS5Y+v6KaW5YyW44GX44G+44GZ44CCCmBgYHtyIGRpYS5sYXNzby5wbG90Mn0KcGxvdChkaWEubGFzc28sIHh2YXI9ImxhbWJkYSIsIGxhYmVsPVRSVUUpCmBgYAotIOOCr+ODreOCueODkOODquODh+ODvOOCt+ODp+ODs+OBq+OCiOOBo+OBpuOAgeacgOmBqeOBqiRcbGFtYmRhJOOCkuaxuuWumuOBl+OBvuOBmeOAggpgYGB7ciBkaWEubGFzc28uY3Z9CmRpYS5sYXNzby5jdiA8LSBjdi5nbG1uZXQoZGlhYmV0ZXMkeCwgZGlhYmV0ZXMkeSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIyBmYW1pbHk9ImdhdXNzaWFuIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGE9MSkKYGBgCi0g44Kv44Ot44K544OQ44Oq44OH44O844K344On44Oz44Gu57WQ5p6c44KS5Y+v6KaW5YyW44GX44G+44GZ44CCCmBgYHtyIGRpYS5sYXNzby5jdi5wbG90fQpwbG90KGRpYS5sYXNzby5jdikKYGBgCi0g5bem5YG044Gu57im54K557ea44GM44CBTVNF44GM5pyA5bCP44Go44Gq44KLJGxvZyhcbGFtYmRhKSTjgajjgarjgorjgb7jgZnjgIIKLSBDcm9zcy12YXJpZGF0ZWQgZXJyb3Ljga7mnIDlsI/lgKTjgIEkXGxhbWJkYSTjga7mnIDlsI/lgKTjgIHlj4rjgbPjgZ3jga7lr77mlbDlgKTjga/ku6XkuIvjga7pgJrjgorjgavjgarjgorjgb7jgZnjgIIKYGBge3IgZGlhLmxhc3NvLmN2Lm1zZX0KbWluKGRpYS5sYXNzby5jdiRjdm0pCmRpYS5sYXNzby5jdiRsYW1iZGEubWluCmxvZyhkaWEubGFzc28uY3YkbGFtYmRhLm1pbikKYGBgCi0g6YG444Gw44KM44GfJFxsYW1iZGEk44KS44CB44Oa44OK44Or44OG44Kj44Go5o6o5a6a5YCk44Gu44Kw44Op44OV44Gr5o+P44GN5YWl44KM44G+44GZ44CCCmBgYHtyIGRpYS5sYXNzby5jdi5wbG90M30KcGxvdChkaWEubGFzc28sIHh2YXI9ImxhbWJkYSIsIGxhYmVsPVRSVUUpCmFibGluZSh2PWxvZyhkaWEubGFzc28uY3YkbGFtYmRhLm1pbiksIGx0eT0yKQpgYGAKLSBNU0XjgYzmnIDlsI/jgajjgarjgovmmYLjga4kXGxhbWJkYSTjgavlr77lv5zjgZnjgovjg5Hjg6njg6Hjg7zjgr/jgpLlh7rlipvjgZfjgb7jgZnjgIIKYGBge3IgZGlhLmxhc3NvLmN2LmxhbWJkYS5taW59CmNvZWYoZGlhLmxhc3NvLmN2LCBzPSJsYW1iZGEubWluIikKYGBgCi0gTVNF44GM5pyA5bCP44Go44Gq44KL44Go44GN44GuTVNF44Gu5LiK5YG0JDFzZSTjgajjgarjgovjgajjgY3jga4kXGxhbWJkYSTjgavlr77lv5zjgZnjgovjg5Hjg6njg6Hjg7zjgr/jgpLlh7rlipvjgZfjgb7jgZnjgIIKYGBge3IgZGlhLmxhc3NvLmN2LmxhbWJkYS4xc2V9CmNvZWYoZGlhLmxhc3NvLmN2LCBzPSJsYW1iZGEuMXNlIikKYGBgCi0g5o6o5a6a44GX44Gf44OR44Op44Oh44O844K/44Gr44KI44KL5LqI5ris5YCk44KS5Ye65Yqb44GX44G+44GZ44CCCmBgYHtyIGRpYS5sYXNzby5jdi5sYW1iZGEubWluLnByZWRpY3R9CnByZWRfZGlhLmxhc3NvLmN2IDwtIHByZWRpY3QoZGlhLmxhc3NvLmN2LCBzPSJsYW1iZGEubWluIiwgbmV3eD1kaWFiZXRlcyR4KQpoZWFkKHByZWRfZGlhLmxhc3NvLmN2KQpgYGAKCiMjIyBFTuWbnuW4sOODouODh+ODqwotIEVO5Zue5biw44Oi44OH44Or44Gv44CBYGdsbW5ldCgpYOmWouaVsOOBruW8leaVsGBhbHBoYWDjga7lgKTjgpIw44CcMeOBrumWk+OBp+aMh+WumuOBl+OBpuaOqOWumuOBl+OBvuOBmeOAguOBk+OBk+OBp+OBr2BhbHBoYT0wLjVg44Go44GX44G+44GZ44CCCmBgYHtyIGNvYS5lbn0KZGlhLkVOIDwtIGdsbW5ldChkaWFiZXRlcyR4LCBkaWFiZXRlcyR5LCAKICAgICAgICAgICAgICAgICAgICAjIGZhbWlseT0iZ2F1c3NpYW4iLCAKICAgICAgICAgICAgICAgICAgICBhbHBoYT0wLjUpCmBgYAotIOWbnuW4sOS/guaVsOOBqCRsb2coXGxhbWJkYSkk44Go44Gu6Zai5L+C44KS5Y+v6KaW5YyW44GX44G+44GZ44CCCmBgYHtyIGRpYS5lbi5wbG90MX0KcGxvdChkaWEuRU4sIGxhYmVsPVRSVUUpCmBgYAotIOWbnuW4sOS/guaVsOOBqCRcbGFtYmRhJOOBqOOBrumWouS/guOCkuWPr+imluWMluOBl+OBvuOBmeOAggpgYGB7ciBkaWEuZW4ucGxvdDJ9CnBsb3QoZGlhLkVOLCB4dmFyPSJsYW1iZGEiLCBsYWJlbD1UUlVFKQpgYGAKLSDjgq/jg63jgrnjg5Djg6rjg4fjg7zjgrfjg6fjg7PjgavjgojjgaPjgabjgIHmnIDpganjgaokXGxhbWJkYSTjgpLmsbrlrprjgZfjgb7jgZnjgIIKYGBge3IgZGlhLmVuLmN2fQpkaWEuRU4uY3YgPC0gY3YuZ2xtbmV0KGRpYWJldGVzJHgsIGRpYWJldGVzJHksIAogICAgICAgICAgICAgICAgICAgICAgICAgICMgZmFtaWx5PSJnYXVzc2lhbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhPTAuNSkKYGBgCi0g44Kv44Ot44K544OQ44Oq44OH44O844K344On44Oz44Gu57WQ5p6c44KS5Y+v6KaW5YyW44GX44G+44GZ44CCCmBgYHtyIGRpYS5lbi5jdi5wbG90fQpwbG90KGRpYS5FTi5jdikKYGBgCi0g5bem5YG044Gu57im54K557ea44GM44CBTVNF44GM5pyA5bCP44Go44Gq44KLJGxvZyhcbGFtYmRhKSTjgajjgarjgorjgb7jgZnjgIIKLSBDcm9zcy12YXJpZGF0ZWQgZXJyb3Ljga7mnIDlsI/lgKTjgIEkXGxhbWJkYSTjga7mnIDlsI/lgKTjgIHlj4rjgbPjgZ3jga7lr77mlbDlgKTjga/ku6XkuIvjga7pgJrjgorjgavjgarjgorjgb7jgZnjgIIKYGBge3IgZGlhLmVuLmN2Lm1zZX0KbWluKGRpYS5FTi5jdiRjdm0pCmRpYS5FTi5jdiRsYW1iZGEubWluCmxvZyhkaWEuRU4uY3YkbGFtYmRhLm1pbikKYGBgCi0g6YG444Gw44KM44GfJFxsYW1iZGEk44KS44CB44Oa44OK44Or44OG44Kj44Go5o6o5a6a5YCk44Gu44Kw44Op44OV44Gr5o+P44GN5YWl44KM44G+44GZ44CCCmBgYHtyIGRpYS5lbi5jdi5wbG90M30KcGxvdChkaWEuRU4sIHh2YXI9ImxhbWJkYSIsIGxhYmVsPVRSVUUpCmFibGluZSh2PWxvZyhkaWEuRU4uY3YkbGFtYmRhLm1pbiksIGx0eT0yKQpgYGAKLSBNU0XjgYzmnIDlsI/jgajjgarjgovmmYLjga4kXGxhbWJkYSTjgavlr77lv5zjgZnjgovjg5Hjg6njg6Hjg7zjgr/jgpLlh7rlipvjgZfjgb7jgZnjgIIKYGBge3IgZGlhLmVuLmN2LmxhbWJkYS5taW59CmNvZWYoZGlhLkVOLmN2LCBzPSJsYW1iZGEubWluIikKYGBgCi0gTVNF44GM5pyA5bCP44Go44Gq44KL44Go44GN44GuTVNF44Gu5LiK5YG0JDFzZSTjgajjgarjgovjgajjgY3jga4kXGxhbWJkYSTjgavlr77lv5zjgZnjgovjg5Hjg6njg6Hjg7zjgr/jgpLlh7rlipvjgZfjgb7jgZnjgIIKYGBge3IgZGlhLmVuLmN2LmxhbWJkYS4xc2V9CmNvZWYoZGlhLkVOLmN2LCBzPSJsYW1iZGEuMXNlIikKYGBgCi0g5o6o5a6a44GX44Gf44OR44Op44Oh44O844K/44Gr44KI44KL5LqI5ris5YCk44KS5Ye65Yqb44GX44G+44GZ44CCCmBgYHtyIGRpYS5lbi5jdi5sYW1iZGEubWluLnByZWRpY3R9CnByZWRfZGlhLkVOLmN2IDwtIHByZWRpY3QoZGlhLkVOLmN2LCBzPSJsYW1iZGEubWluIiwgbmV3eD1kaWFiZXRlcyR4KQpoZWFkKHByZWRfZGlhLkVOLmN2KQpgYGAKCi0g5LuK5Zue44Gu5ryU57+S44Gv5Lul5LiK44Gn44GZ44CC