老師原本模型 取 log 分成 TR2 & TS2
rm(list=ls(all=TRUE))
load("data/tf2.rdata")
n = nrow(A2)
set.seed(2018); spl2 = 1:n %in% sample(1:n, round(0.7*n))
A2 = subset(A, A$buy) %>% mutate_at(c("m","rev","amount"), log10)
TR2 = subset(A2, spl2)
TS2 = subset(A2, !spl2)
lm1 = lm(amount ~ ., TR2[,c(2:6,8:10)])
pred = predict(lm1, TS2)
r2.tr = summary(lm1)$r.sq
SST = sum((TS2$amount - mean(TR2$amount))^ 2)
SSE = sum((predict(lm1, TS2) - TS2$amount)^2)
r2.ts = 1 - (SSE/SST)
c(r2.tr, r2.ts)
[1] 0.2909908 0.2575966
嘗試增加變數,再分TR2 & TS2
A2$aa = A2$f*A2$m^2*A2$r^2
A2$uu = A2$f*A2$r
A2$dd = A2$m*A2$r^2
A2$cc = A2$s*A2$f
A2$bb = A2$s*A2$m^0.5
A2$vv = A2$m*A2$f^4
A2$ii = A2$f*A2$f^0.5
A2$pp = A2$r*A2$r^2
A2$jj = (A2$s-A2$r)^2*A2$m^2
A2$FF = (A2$s-A2$r)^2*A2$f*A2$s^3
TR2 = subset(A2, spl2)
TS2 = subset(A2, !spl2)
cx=c(2:10, 12:21)
colnames(TR2[,cx])
[1] "r" "s" "f" "m" "rev" "raw" "age"
[8] "area" "amount" "aa" "uu" "dd" "cc" "bb"
[15] "vv" "ii" "pp" "jj" "FF"
lm1 = lm(amount ~ ., TR2[,cx])
summary(lm1)
Call:
lm(formula = amount ~ ., data = TR2[, cx])
Residuals:
Min 1Q Median 3Q Max
-1.83854 -0.22761 0.04917 0.27798 1.51672
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.816e+00 1.064e-01 17.060 < 2e-16 ***
r 5.197e-03 1.141e-03 4.556 5.29e-06 ***
s -2.449e-02 3.093e-03 -7.917 2.72e-15 ***
f 2.419e-02 3.619e-02 0.668 0.50387
m 2.716e-01 1.224e-01 2.220 0.02647 *
rev 3.381e-02 1.195e-01 0.283 0.77729
raw 4.281e-05 9.955e-06 4.301 1.72e-05 ***
ageB 7.397e-02 2.490e-02 2.971 0.00298 **
ageC 1.186e-01 2.285e-02 5.191 2.14e-07 ***
ageD 1.235e-01 2.254e-02 5.478 4.43e-08 ***
ageE 1.323e-01 2.305e-02 5.738 9.86e-09 ***
ageF 1.065e-01 2.405e-02 4.429 9.56e-06 ***
ageG 7.922e-02 2.625e-02 3.018 0.00255 **
ageH 7.100e-02 3.096e-02 2.293 0.02185 *
ageI 7.207e-02 3.181e-02 2.266 0.02348 *
ageJ -2.037e-02 2.797e-02 -0.728 0.46651
ageK 1.126e-01 3.926e-02 2.867 0.00415 **
areaB 8.270e-02 4.312e-02 1.918 0.05513 .
areaC 4.041e-02 3.502e-02 1.154 0.24859
areaD -9.158e-03 3.682e-02 -0.249 0.80359
areaE 6.240e-03 3.228e-02 0.193 0.84670
areaF 1.429e-02 3.250e-02 0.440 0.66027
areaG 2.310e-02 3.463e-02 0.667 0.50479
areaH 1.376e-02 3.854e-02 0.357 0.72100
aa 6.068e-07 5.277e-07 1.150 0.25023
uu -1.264e-03 2.936e-04 -4.306 1.68e-05 ***
dd -3.612e-05 7.385e-06 -4.891 1.02e-06 ***
cc 7.126e-04 3.405e-04 2.093 0.03639 *
bb 1.417e-02 1.976e-03 7.173 7.92e-13 ***
vv 2.259e-08 1.662e-08 1.360 0.17401
ii -8.650e-03 3.033e-03 -2.852 0.00436 **
pp 7.185e-07 1.653e-07 4.345 1.41e-05 ***
jj -1.670e-06 1.089e-06 -1.534 0.12502
FF -2.082e-12 1.674e-12 -1.244 0.21351
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.4174 on 9235 degrees of freedom
Multiple R-squared: 0.3058, Adjusted R-squared: 0.3033
F-statistic: 123.3 on 33 and 9235 DF, p-value: < 2.2e-16
r2.tr = summary(lm1)$r.sq
SST = sum((TS2$amount - mean(TR2$amount))^ 2)
SSE = sum((predict(lm1, TS2) - TS2$amount)^2)
r2.ts = 1 - (SSE/SST)
c(r2.tr, r2.ts)
[1] 0.3057826 0.2775772
#0.2772139
A2新增變數加入Training Testing
TR2 = subset(A2, spl2)
TS2 = subset(A2, !spl2)
cx=c(2:10, 12:23)
colnames(TR2[,cx])
[1] "r" "s" "f" "m" "rev"
[6] "raw" "age" "area" "amount" "aa"
[11] "uu" "dd" "cc" "bb" "vv"
[16] "ii" "pp" "jj" "FF" "amount_m1"
[21] "items_m1"
lm1 = lm(amount ~ ., TR2[,cx])
summary(lm1)
Call:
lm(formula = amount ~ ., data = TR2[, cx])
Residuals:
Min 1Q Median 3Q Max
-1.85417 -0.22684 0.04689 0.27720 1.51675
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.799e+00 1.088e-01 16.530 < 2e-16 ***
r 5.168e-03 1.195e-03 4.325 1.54e-05 ***
s -2.379e-02 3.155e-03 -7.542 5.08e-14 ***
f 1.625e-02 3.622e-02 0.449 0.653685
m 2.622e-01 1.223e-01 2.144 0.032080 *
rev 5.165e-02 1.199e-01 0.431 0.666572
raw 4.835e-05 1.179e-05 4.099 4.18e-05 ***
ageB 7.350e-02 2.488e-02 2.955 0.003138 **
ageC 1.181e-01 2.283e-02 5.171 2.38e-07 ***
ageD 1.223e-01 2.253e-02 5.428 5.84e-08 ***
ageE 1.297e-01 2.304e-02 5.631 1.85e-08 ***
ageF 1.038e-01 2.404e-02 4.317 1.60e-05 ***
ageG 7.767e-02 2.623e-02 2.962 0.003068 **
ageH 6.980e-02 3.093e-02 2.256 0.024073 *
ageI 7.282e-02 3.179e-02 2.291 0.021989 *
ageJ -2.116e-02 2.795e-02 -0.757 0.449003
ageK 1.127e-01 3.923e-02 2.873 0.004072 **
areaB 8.299e-02 4.308e-02 1.927 0.054070 .
areaC 3.967e-02 3.499e-02 1.134 0.257031
areaD -8.264e-03 3.679e-02 -0.225 0.822295
areaE 4.430e-03 3.225e-02 0.137 0.890744
areaF 1.264e-02 3.247e-02 0.389 0.697022
areaG 2.361e-02 3.460e-02 0.682 0.494948
areaH 1.404e-02 3.851e-02 0.365 0.715413
aa 5.373e-07 5.281e-07 1.018 0.308913
uu -1.225e-03 2.957e-04 -4.144 3.45e-05 ***
dd -3.543e-05 7.381e-06 -4.800 1.61e-06 ***
cc 7.364e-04 3.409e-04 2.161 0.030759 *
bb 1.366e-02 2.033e-03 6.721 1.92e-11 ***
vv 1.286e-08 1.676e-08 0.767 0.442955
ii -7.657e-03 3.044e-03 -2.515 0.011919 *
pp 7.111e-07 1.655e-07 4.296 1.76e-05 ***
jj -1.459e-06 1.115e-06 -1.309 0.190518
FF -2.299e-12 1.673e-12 -1.374 0.169327
amount_m1 -1.679e-05 4.897e-06 -3.428 0.000611 ***
items_m1 2.571e-03 6.205e-04 4.143 3.46e-05 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.417 on 9233 degrees of freedom
Multiple R-squared: 0.3072, Adjusted R-squared: 0.3045
F-statistic: 117 on 35 and 9233 DF, p-value: < 2.2e-16
r2.tr = summary(lm1)$r.sq
SST = sum((TS2$amount - mean(TR2$amount))^ 2)
SSE = sum((predict(lm1, TS2) - TS2$amount)^2)
r2.ts = 1 - (SSE/SST)
c(r2.tr, r2.ts)
[1] 0.3071653 0.2792819
#0.2793
2.嘗試先集群再LM
LTR = TR2[,c(2,4,5)] ##r,f,m
LTS = TS2[,c(2,4,5)]
library(caret)
preproc = preProcess(LTR)
NTR = predict(preproc, LTR) ##標準化資料
NTS = predict(preproc, LTS)
km <- kmeans(NTR,5)
library(flexclust)
km.kcca = as.kcca(km,NTR) ##拿TR2做分群
CTR = predict(km.kcca)
CTS = predict(km.kcca, newdata=NTS) ##預測TS2群
拿分群做回歸
apple = split(TR2, CTR)
M = lapply(1:5, function(x)
lm(amount ~ ., data = apple[[x]][,c(2:7,10,12:23)]))
預測log(amount)
Pred = lapply(1:5, function(i)
predict(M[[i]], TS2[CTS==i,]) )
prediction from a rank-deficient fit may be misleading
t = do.call(c, split(TS2$amount,CTS))
y = do.call(c, Pred)
計算R^2
SST = sum((TS2$amount - mean(TR2$amount))^ 2)
SSE = sum((y - t)^2)
r2.ts = 1 - (SSE/SST)
r2.ts
[1] 0.2616883
cor(TR2[,c(2:7,10,12:23)])
r s f m rev
r 1.00000000 0.09280689 -0.40129374 -0.081126640 -0.44027271
s 0.09280689 1.00000000 0.42269893 -0.038503261 0.37382516
f -0.40129374 0.42269893 1.00000000 -0.052591356 0.53746879
m -0.08112664 -0.03850326 -0.05259136 1.000000000 0.73023789
rev -0.44027271 0.37382516 0.53746879 0.730237893 1.00000000
raw -0.29568266 0.27730825 0.58067392 0.444250605 0.69106801
amount -0.15318868 0.11573180 0.26075411 0.448832752 0.49819086
aa 0.73885222 0.23988889 -0.15141996 0.129895002 -0.01798996
uu 0.45421111 0.41233382 0.20091882 -0.093705354 0.10175458
dd 0.94090159 0.13572184 -0.32432534 0.055867743 -0.29336220
cc -0.35813848 0.48208952 0.99335208 -0.053482978 0.52699089
bb 0.07156626 0.97702793 0.40478867 0.160789068 0.51390410
vv -0.08120938 0.08234599 0.56792007 -0.008137503 0.16138921
ii -0.29750436 0.31169698 0.96107444 -0.049063048 0.43032686
pp 0.89744937 0.16148585 -0.28441875 -0.076304783 -0.36618575
jj -0.61988527 0.61834594 0.58949999 0.220160172 0.68107758
FF -0.35556936 0.39572205 0.95126182 -0.042927934 0.45918225
amount_m1 -0.07099274 0.13250769 0.40762238 0.375026779 0.47183446
items_m1 -0.07773565 0.16806445 0.50023232 0.271614719 0.43343367
raw amount aa uu dd
r -0.29568266 -0.153188684 0.73885222 0.454211113 0.94090159
s 0.27730825 0.115731805 0.23988889 0.412333822 0.13572184
f 0.58067392 0.260754113 -0.15141996 0.200918822 -0.32432534
m 0.44425061 0.448832752 0.12989500 -0.093705354 0.05586774
rev 0.69106801 0.498190855 -0.01798996 0.101754584 -0.29336220
raw 1.00000000 0.421625952 -0.06731293 0.063309711 -0.21378675
amount 0.42162595 1.000000000 -0.00180071 -0.009755721 -0.06830873
aa -0.06731293 -0.001800710 1.00000000 0.753791502 0.75091862
uu 0.06330971 -0.009755721 0.75379150 1.000000000 0.35916408
dd -0.21378675 -0.068308730 0.75091862 0.359164076 1.00000000
cc 0.57852509 0.259085976 -0.11901949 0.224913468 -0.28322191
bb 0.37057984 0.208395242 0.26543145 0.384065368 0.14421903
vv 0.36043920 0.132637142 -0.04356514 0.036113917 -0.05309565
ii 0.54955750 0.241391578 -0.12293414 0.155115137 -0.22846113
pp -0.21288031 -0.108296885 0.64532873 0.303325579 0.95401175
jj 0.59298064 0.305639127 -0.37252335 -0.119131389 -0.51814039
FF 0.55855316 0.253255869 -0.19688190 0.066773206 -0.26928466
amount_m1 0.74927260 0.319771668 -0.01261175 0.007903888 -0.01865575
items_m1 0.67853640 0.311077080 -0.01669654 0.027278846 -0.02135074
cc bb vv ii pp
r -0.35813848 0.07156626 -0.081209378 -0.29750436 0.897449375
s 0.48208952 0.97702793 0.082345995 0.31169698 0.161485854
f 0.99335208 0.40478867 0.567920071 0.96107444 -0.284418746
m -0.05348298 0.16078907 -0.008137503 -0.04906305 -0.076304783
rev 0.52699089 0.51390410 0.161389208 0.43032686 -0.366185746
raw 0.57852509 0.37057984 0.360439203 0.54955750 -0.212880308
amount 0.25908598 0.20839524 0.132637142 0.24139158 -0.108296885
aa -0.11901949 0.26543145 -0.043565137 -0.12293414 0.645328733
uu 0.22491347 0.38406537 0.036113917 0.15511514 0.303325579
dd -0.28322191 0.14421903 -0.053095651 -0.22846113 0.954011750
cc 1.00000000 0.46279346 0.569576385 0.95804383 -0.244884522
bb 0.46279346 1.00000000 0.079370124 0.29576266 0.137911969
vv 0.56957638 0.07937012 1.000000000 0.73453682 -0.042572013
ii 0.95804383 0.29576266 0.734536822 1.00000000 -0.195318561
pp -0.24488452 0.13791197 -0.042572013 -0.19531856 1.000000000
jj 0.61154559 0.66406621 0.142146860 0.45316346 -0.460465063
FF 0.96745798 0.37985761 0.617988624 0.95406941 -0.226752835
amount_m1 0.40196061 0.20261448 0.339104065 0.42714038 -0.008194315
items_m1 0.49531676 0.21831856 0.451695695 0.53121837 -0.008228728
jj FF amount_m1 items_m1
r -0.6198853 -0.35556936 -0.070992738 -0.077735651
s 0.6183459 0.39572205 0.132507692 0.168064445
f 0.5895000 0.95126182 0.407622380 0.500232322
m 0.2201602 -0.04292793 0.375026779 0.271614719
rev 0.6810776 0.45918225 0.471834464 0.433433673
raw 0.5929806 0.55855316 0.749272604 0.678536397
amount 0.3056391 0.25325587 0.319771668 0.311077080
aa -0.3725233 -0.19688190 -0.012611751 -0.016696538
uu -0.1191314 0.06677321 0.007903888 0.027278846
dd -0.5181404 -0.26928466 -0.018655749 -0.021350742
cc 0.6115456 0.96745798 0.401960609 0.495316755
bb 0.6640662 0.37985761 0.202614476 0.218318564
vv 0.1421469 0.61798862 0.339104065 0.451695695
ii 0.4531635 0.95406941 0.427140381 0.531218371
pp -0.4604651 -0.22675284 -0.008194315 -0.008228728
jj 1.0000000 0.58762774 0.333491636 0.327896928
FF 0.5876277 1.00000000 0.411214247 0.507448063
amount_m1 0.3334916 0.41121425 1.000000000 0.832241010
items_m1 0.3278969 0.50744806 0.832241010 1.000000000
apple = split(TR2, CTR)
M = lapply(1:5, function(x)
lm(amount ~ ., data = apple[[x]][,c(2:6,10,13,14,17,18,20)]))
Pred = lapply(1:5, function(i)
predict(M[[i]], TS2[CTS==i,]) )
t = do.call(c, split(TS2$amount,CTS))
y = do.call(c, Pred)
SST = sum((TS2$amount - mean(TR2$amount))^ 2)
SSE = sum((y - t)^2)
r2.ts = 1 - (SSE/SST)
r2.ts
[1] 0.2638244
交叉驗證~~
ctrl = trainControl(
method="repeatedcv", number=10, # 10-fold, Repeated CV
savePredictions = "final", classProbs=TRUE,
summaryFunction=twoClassSummary)
ctrl2 = trainControl(
method="repeatedcv", number=10, # 10-fold, Repeated CV
savePredictions = "final")
ctrl$repeats = 2
set.seed(2)
cv.lm2 = train(
amount ~ ., data=TR2[,c(2:10, 12:23)], method="lm",
trControl=ctrl2, metric="Rsquared",
tuneGrid = expand.grid( intercept = seq(1,2,0.01) )
)
plot(cv.lm2)

cv.lm2$results
summary(cv.lm2)
Call:
lm(formula = .outcome ~ ., data = dat)
Residuals:
Min 1Q Median 3Q Max
-1.85417 -0.22684 0.04689 0.27720 1.51675
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.799e+00 1.088e-01 16.530 < 2e-16 ***
r 5.168e-03 1.195e-03 4.325 1.54e-05 ***
s -2.379e-02 3.155e-03 -7.542 5.08e-14 ***
f 1.625e-02 3.622e-02 0.449 0.653685
m 2.622e-01 1.223e-01 2.144 0.032080 *
rev 5.165e-02 1.199e-01 0.431 0.666572
raw 4.835e-05 1.179e-05 4.099 4.18e-05 ***
ageB 7.350e-02 2.488e-02 2.955 0.003138 **
ageC 1.181e-01 2.283e-02 5.171 2.38e-07 ***
ageD 1.223e-01 2.253e-02 5.428 5.84e-08 ***
ageE 1.297e-01 2.304e-02 5.631 1.85e-08 ***
ageF 1.038e-01 2.404e-02 4.317 1.60e-05 ***
ageG 7.767e-02 2.623e-02 2.962 0.003068 **
ageH 6.980e-02 3.093e-02 2.256 0.024073 *
ageI 7.282e-02 3.179e-02 2.291 0.021989 *
ageJ -2.116e-02 2.795e-02 -0.757 0.449003
ageK 1.127e-01 3.923e-02 2.873 0.004072 **
areaB 8.299e-02 4.308e-02 1.927 0.054070 .
areaC 3.967e-02 3.499e-02 1.134 0.257031
areaD -8.264e-03 3.679e-02 -0.225 0.822295
areaE 4.430e-03 3.225e-02 0.137 0.890744
areaF 1.264e-02 3.247e-02 0.389 0.697022
areaG 2.361e-02 3.460e-02 0.682 0.494948
areaH 1.404e-02 3.851e-02 0.365 0.715413
aa 5.373e-07 5.281e-07 1.018 0.308913
uu -1.225e-03 2.957e-04 -4.144 3.45e-05 ***
dd -3.543e-05 7.381e-06 -4.800 1.61e-06 ***
cc 7.364e-04 3.409e-04 2.161 0.030759 *
bb 1.366e-02 2.033e-03 6.721 1.92e-11 ***
vv 1.286e-08 1.676e-08 0.767 0.442955
ii -7.657e-03 3.044e-03 -2.515 0.011919 *
pp 7.111e-07 1.655e-07 4.296 1.76e-05 ***
jj -1.459e-06 1.115e-06 -1.309 0.190518
FF -2.299e-12 1.673e-12 -1.374 0.169327
amount_m1 -1.679e-05 4.897e-06 -3.428 0.000611 ***
items_m1 2.571e-03 6.205e-04 4.143 3.46e-05 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.417 on 9233 degrees of freedom
Multiple R-squared: 0.3072, Adjusted R-squared: 0.3045
F-statistic: 117 on 35 and 9233 DF, p-value: < 2.2e-16
結論
### 一般直接線性有時比群集再線性更有效
### 透過交叉驗證可以說明我們資料不只對TEST DATA 有效 ~~~
LS0tDQp0aXRsZTogIuacn+S4reWwj+e1hOertuizvSwgVGEtRmVuZyINCmF1dGhvcjogIuesrOS4gOe1hC3lionogrLpipjjgIHnjovmt6/kvbPjgIHpu4Pmn4/ono3jgIHkvZnmm5zlu7fjgIHmnpfkv57kvLbjgIHpmbPmraPorIAiDQpkYXRlOiAiYHIgU3lzLnRpbWUoKWAiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQo8ZGl2IGlkPSJteVNpZGVuYXYiIGNsYXNzPSJzaWRlbmF2Ij4NCiAgPGEgaHJlZj0iI2dsbSIgaWQ9ImFib3V0Ij7lu7rnq4vmqKHlnos8L2E+DQogIDxhIGhyZWY9IiNDbHVzdCIgaWQ9ImJsb2ciPumbhue+pOWIhuaekDwvYT4NCiAgPGEgaHJlZj0iI0NWIiBpZD0icHJvamVjdHMiPuS6pOWPiempl+itiTwvYT4NCiAgPGEgaHJlZj0iI0NMIiBpZD0iY29udGFjdCI+57WQ6KuWPC9hPg0KPC9kaXY+DQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoY2FUb29scykNCmxpYnJhcnkoTWF0cml4KQ0KbGlicmFyeShycGFydCkNCmxpYnJhcnkocnBhcnQucGxvdCkNCmxpYnJhcnkoY2FyZXQpDQpsaWJyYXJ5KGRvUGFyYWxsZWwpDQpgYGANCg0KIyMjIDxzcGFuIGlkPSdnbG0nPuiAgeW4q+WOn+acrOaooeWeiyDlj5YgbG9nIOWIhuaIkCBUUjIgJiBUUzI8L3NwYW4+DQoNCmBgYHtyfQ0Kcm0obGlzdD1scyhhbGw9VFJVRSkpDQpsb2FkKCJkYXRhL3RmMi5yZGF0YSIpDQpuID0gbnJvdyhBMikNCnNldC5zZWVkKDIwMTgpOyBzcGwyID0gMTpuICVpbiUgc2FtcGxlKDE6biwgcm91bmQoMC43Km4pKQ0KQTIgPSBzdWJzZXQoQSwgQSRidXkpICU+JSBtdXRhdGVfYXQoYygibSIsInJldiIsImFtb3VudCIpLCBsb2cxMCkNClRSMiA9IHN1YnNldChBMiwgc3BsMikNClRTMiA9IHN1YnNldChBMiwgIXNwbDIpDQpsbTEgPSBsbShhbW91bnQgfiAuLCBUUjJbLGMoMjo2LDg6MTApXSkNCnByZWQgPSAgcHJlZGljdChsbTEsIFRTMikNCnIyLnRyID0gc3VtbWFyeShsbTEpJHIuc3ENClNTVCA9IHN1bSgoVFMyJGFtb3VudCAtIG1lYW4oVFIyJGFtb3VudCkpXiAyKQ0KU1NFID0gc3VtKChwcmVkaWN0KGxtMSwgVFMyKSAtICBUUzIkYW1vdW50KV4yKQ0KcjIudHMgPSAxIC0gKFNTRS9TU1QpDQpjKHIyLnRyLCByMi50cykNCmBgYA0KDQojIyMgPHNwYW4gaWQ9J0FkZF94Jz7lmJfoqablop7liqDorormlbgs5YaN5YiGVFIyICYgVFMyPC9zcGFuPg0KDQpgYGB7cn0NCkEyJGFhID0gQTIkZipBMiRtXjIqQTIkcl4yDQpBMiR1dSA9IEEyJGYqQTIkcg0KQTIkZGQgPSBBMiRtKkEyJHJeMg0KQTIkY2MgPSBBMiRzKkEyJGYNCkEyJGJiID0gQTIkcypBMiRtXjAuNQ0KQTIkdnYgPSBBMiRtKkEyJGZeNA0KQTIkaWkgPSBBMiRmKkEyJGZeMC41DQpBMiRwcCA9IEEyJHIqQTIkcl4yDQpBMiRqaiA9IChBMiRzLUEyJHIpXjIqQTIkbV4yDQpBMiRGRiA9IChBMiRzLUEyJHIpXjIqQTIkZipBMiRzXjMNClRSMiA9IHN1YnNldChBMiwgc3BsMikNClRTMiA9IHN1YnNldChBMiwgIXNwbDIpDQpgYGANCg0KYGBge3J9DQpjeD1jKDI6MTAsIDEyOjIxKQ0KY29sbmFtZXMoVFIyWyxjeF0pDQpsbTEgPSBsbShhbW91bnQgfiAuLCBUUjJbLGN4XSkNCnN1bW1hcnkobG0xKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCnIyLnRyID0gc3VtbWFyeShsbTEpJHIuc3ENClNTVCA9IHN1bSgoVFMyJGFtb3VudCAtIG1lYW4oVFIyJGFtb3VudCkpXiAyKQ0KU1NFID0gc3VtKChwcmVkaWN0KGxtMSwgVFMyKSAtICBUUzIkYW1vdW50KV4yKQ0KcjIudHMgPSAxIC0gKFNTRS9TU1QpDQpjKHIyLnRyLCByMi50cykNCiMwLjI3NzIxMzkNCmBgYA0KDQoNCiMgIOWKoOWFpeiuiuaVuA0KDQpgYGB7cn0NCmxpYnJhcnkobHVicmlkYXRlKQ0KDQoj6aGn5a6i5ZyoMeaciOeahOa2iOiyuw0KSmFuID0gZmlsdGVyKFgsIG1vbnRoKGRhdGUpPT0xICkgJT4lIA0KICBncm91cF9ieShjdXN0KSAlPiUgDQogIHN1bW1hcmlzZSgNCiAgICBhbW91bnRfbTEgPSBzdW0odG90YWwpLA0KICAgIGl0ZW1zX20xPXN1bShpdGVtcyksDQogICAgcGllY2VzX20xPXN1bShwaWVjZXMpLA0KICAgIGdyb3NzX20xPXN1bShncm9zcyksDQogICAgcHJpY2VfbTE9c3VtKGdyb3NzKQ0KICApIA0KSmFuDQoNCmBgYA0KDQoj5Yqg5YWl6K6K5pW45YiwQTINCmBgYHtyfQ0KDQpBMiA9IG1lcmdlKEEyLCBKYW4sIGJ5PSJjdXN0IiwgYWxsLng9VCkNCkEyDQpgYGANCg0KPGJyPjxicj48YnI+PGhyPjxicj48YnI+PGJyPg0KDQoj5aGr6KOcTkENCg0KYGBge3J9DQojIyMjIyDnlKjlubPlnYflgLzloavoo5xOQQ0KZm9yKGkgaW4gMjI6MjYpew0KICBtZWFuX2NvbCA8LSBtZWFuKEEyWywgaV0sIG5hLnJtID0gVCkgICMgbWVhbiBvZiBjb2wgaXRoDQogIG5hLnJvd3MgPC0gaXMubmEoQTJbLCBpXSkgICAjY29sIGl0aCBuYSBkYXRhDQogIEEyW25hLnJvd3MsIGldIDwtIG1lYW5fY29sDQp9DQpBMg0KYGBgDQoNCg0KDQoNCg0KI0Ey5paw5aKe6K6K5pW45Yqg5YWlVHJhaW5pbmcgVGVzdGluZw0KYGBge3J9DQpUUjIgPSBzdWJzZXQoQTIsIHNwbDIpDQpUUzIgPSBzdWJzZXQoQTIsICFzcGwyKQ0KYGBgDQoNCg0KDQoNCg0KDQpgYGB7cn0NCmN4PWMoMjoxMCwgMTI6MjMpDQpjb2xuYW1lcyhUUjJbLGN4XSkNCmxtMSA9IGxtKGFtb3VudCB+IC4sIFRSMlssY3hdKQ0Kc3VtbWFyeShsbTEpDQpgYGANCg0KYGBge3J9DQpyMi50ciA9IHN1bW1hcnkobG0xKSRyLnNxDQpTU1QgPSBzdW0oKFRTMiRhbW91bnQgLSBtZWFuKFRSMiRhbW91bnQpKV4gMikNClNTRSA9IHN1bSgocHJlZGljdChsbTEsIFRTMikgLSAgVFMyJGFtb3VudCleMikNCnIyLnRzID0gMSAtIChTU0UvU1NUKQ0KYyhyMi50ciwgcjIudHMpDQojMC4yNzkzDQpgYGANCg0KDQojIyMgIDxzcGFuIGlkPSdDbHVzdCc+Mi7lmJfoqablhYjpm4bnvqTlho1MTTwvc3Bhbj4NCg0KYGBge3J9DQpMVFIgPSBUUjJbLGMoMiw0LDUpXSAgICMjcixmLG0NCkxUUyA9IFRTMlssYygyLDQsNSldDQpsaWJyYXJ5KGNhcmV0KQ0KcHJlcHJvYyA9IHByZVByb2Nlc3MoTFRSKQ0KTlRSID0gcHJlZGljdChwcmVwcm9jLCBMVFIpICMj5qiZ5rqW5YyW6LOH5paZDQpOVFMgPSBwcmVkaWN0KHByZXByb2MsIExUUykNCmBgYA0KDQpgYGB7cn0NCmttIDwtIGttZWFucyhOVFIsNSkNCmxpYnJhcnkoZmxleGNsdXN0KQ0Ka20ua2NjYSA9IGFzLmtjY2Eoa20sTlRSKSAgIyPmi79UUjLlgZrliIbnvqQNCkNUUiA9IHByZWRpY3Qoa20ua2NjYSkgICAgIA0KQ1RTID0gcHJlZGljdChrbS5rY2NhLCBuZXdkYXRhPU5UUykgICAjI+mgkOa4rFRTMue+pA0KYGBgDQoNCiMjIyDmi7/liIbnvqTlgZrlm57mrbgNCg0KYGBge3J9DQphcHBsZSA9IHNwbGl0KFRSMiwgQ1RSKQ0KTSA9IGxhcHBseSgxOjUsIGZ1bmN0aW9uKHgpIA0KICBsbShhbW91bnQgfiAuLCBkYXRhID0gYXBwbGVbW3hdXVssYygyOjcsMTAsMTI6MjMpXSkpDQpgYGANCg0KIyMjIOmgkOa4rGxvZyhhbW91bnQpDQoNCmBgYHtyfQ0KUHJlZCA9IGxhcHBseSgxOjUsIGZ1bmN0aW9uKGkpIA0KICBwcmVkaWN0KE1bW2ldXSwgVFMyW0NUUz09aSxdKSApDQpgYGANCg0KDQpgYGB7cn0NCnQgPSBkby5jYWxsKGMsIHNwbGl0KFRTMiRhbW91bnQsQ1RTKSkNCnkgPSBkby5jYWxsKGMsIFByZWQpDQpgYGANCg0KIyMjIOioiOeul1JeMg0KDQpgYGB7cn0NClNTVCA9IHN1bSgoVFMyJGFtb3VudCAtIG1lYW4oVFIyJGFtb3VudCkpXiAyKQ0KU1NFID0gc3VtKCh5IC0gdCleMikNCnIyLnRzID0gMSAtIChTU0UvU1NUKQ0KcjIudHMNCmBgYA0KDQpgYGB7cn0NCmNvcihUUjJbLGMoMjo3LDEwLDEyOjIzKV0pDQpgYGANCg0KYGBge3J9DQphcHBsZSA9IHNwbGl0KFRSMiwgQ1RSKQ0KTSA9IGxhcHBseSgxOjUsIGZ1bmN0aW9uKHgpIA0KICBsbShhbW91bnQgfiAuLCBkYXRhID0gYXBwbGVbW3hdXVssYygyOjYsMTAsMTMsMTQsMTcsMTgsMjApXSkpDQpgYGANCg0KYGBge3J9DQpQcmVkID0gbGFwcGx5KDE6NSwgZnVuY3Rpb24oaSkgDQogIHByZWRpY3QoTVtbaV1dLCBUUzJbQ1RTPT1pLF0pICkNCmBgYA0KDQpgYGB7cn0NCnQgPSBkby5jYWxsKGMsIHNwbGl0KFRTMiRhbW91bnQsQ1RTKSkNCnkgPSBkby5jYWxsKGMsIFByZWQpDQoNCmBgYA0KDQpgYGB7cn0NClNTVCA9IHN1bSgoVFMyJGFtb3VudCAtIG1lYW4oVFIyJGFtb3VudCkpXiAyKQ0KU1NFID0gc3VtKCh5IC0gdCleMikNCnIyLnRzID0gMSAtIChTU0UvU1NUKQ0KcjIudHMNCmBgYA0KDQoNCiMjIyA8c3BhbiBpZD0nQ1YnPuS6pOWPiempl+itiX5+PC9zcGFuPg0KDQpgYGB7cn0NCmN0cmwgPSB0cmFpbkNvbnRyb2woDQogIG1ldGhvZD0icmVwZWF0ZWRjdiIsIG51bWJlcj0xMCwgICAgIyAxMC1mb2xkLCBSZXBlYXRlZCBDVg0KICBzYXZlUHJlZGljdGlvbnMgPSAiZmluYWwiLCBjbGFzc1Byb2JzPVRSVUUsDQogIHN1bW1hcnlGdW5jdGlvbj10d29DbGFzc1N1bW1hcnkpDQpgYGANCg0KYGBge3J9DQpjdHJsMiA9IHRyYWluQ29udHJvbCgNCiAgbWV0aG9kPSJyZXBlYXRlZGN2IiwgbnVtYmVyPTEwLCAgICAjIDEwLWZvbGQsIFJlcGVhdGVkIENWDQogIHNhdmVQcmVkaWN0aW9ucyA9ICJmaW5hbCIpDQpgYGANCg0KDQoNCmBgYHtyfQ0KY3RybCRyZXBlYXRzID0gMg0Kc2V0LnNlZWQoMikNCmN2LmxtMiA9IHRyYWluKA0KICBhbW91bnQgfiAuLCBkYXRhPVRSMlssYygyOjEwLCAxMjoyMyldLCBtZXRob2Q9ImxtIiwgDQogIHRyQ29udHJvbD1jdHJsMiwgbWV0cmljPSJSc3F1YXJlZCIsDQogICAgdHVuZUdyaWQgPSBleHBhbmQuZ3JpZCggaW50ZXJjZXB0ID0gc2VxKDEsMiwwLjAxKSApIA0KICApDQpwbG90KGN2LmxtMikNCmBgYA0KDQpgYGB7cn0NCmN2LmxtMiRyZXN1bHRzDQpgYGANCg0KYGBge3J9DQpzdW1tYXJ5KGN2LmxtMikNCmBgYA0KDQojIyMgPHNwYW4gaWQ9ICdDTCc+57WQ6KuWPC9zcGFuPg0KDQpgYGB7cn0NCiMjIyDkuIDoiKznm7TmjqXnt5rmgKfmnInmmYLmr5TnvqTpm4blho3nt5rmgKfmm7TmnInmlYgNCiMjIyDpgI/pgY7kuqTlj4npqZforYnlj6/ku6XoqqrmmI7miJHlgJHos4fmlpnkuI3lj6rlsI1URVNUIERBVEEg5pyJ5pWIIH5+fg0KYGBgDQoNCg0KPGJyPjxicj48YnI+PGJyPjxocj48YnI+PGJyPjxicj4NCg0KPHN0eWxlPg0KLmNhcHRpb24gew0KICBjb2xvcjogIzc3NzsNCiAgbWFyZ2luLXRvcDogMTBweDsNCn0NCnAgY29kZSB7DQogIHdoaXRlLXNwYWNlOiBpbmhlcml0Ow0KfQ0KcHJlIHsNCiAgd29yZC1icmVhazogbm9ybWFsOw0KICB3b3JkLXdyYXA6IG5vcm1hbDsNCiAgbGluZS1oZWlnaHQ6IDE7DQp9DQpwcmUgY29kZSB7DQogIHdoaXRlLXNwYWNlOiBpbmhlcml0Ow0KfQ0KcCxsaSB7DQogIGZvbnQtZmFtaWx5OiAiVHJlYnVjaGV0IE1TIiwgIuW+rui7n+ato+m7kemrlCIsICJNaWNyb3NvZnQgSmhlbmdIZWkiOw0KfQ0KDQoucnsNCiAgbGluZS1oZWlnaHQ6IDEuMjsNCn0NCg0KdGl0bGV7DQogIGNvbG9yOiAjY2MwMDAwOw0KICBmb250LWZhbWlseTogIlRyZWJ1Y2hldCBNUyIsICLlvq7ou5/mraPpu5Hpq5QiLCAiTWljcm9zb2Z0IEpoZW5nSGVpIjsNCn0NCg0KYm9keXsNCiAgZm9udC1mYW1pbHk6ICJUcmVidWNoZXQgTVMiLCAi5b6u6Luf5q2j6buR6auUIiwgIk1pY3Jvc29mdCBKaGVuZ0hlaSI7DQp9DQoNCmgxLGgyLGgzLGg0LGg1ew0KICBjb2xvcjogIzAwODgwMDsNCiAgZm9udC1mYW1pbHk6ICJUcmVidWNoZXQgTVMiLCAi5b6u6Luf5q2j6buR6auUIiwgIk1pY3Jvc29mdCBKaGVuZ0hlaSI7DQp9DQoNCmgzew0KICBjb2xvcjogI2IzNmIwMDsNCiAgYmFja2dyb3VuZDogI2ZmZTBiMzsNCiAgbGluZS1oZWlnaHQ6IDI7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KfQ0KDQpoNXsNCiAgY29sb3I6ICMwMDYwMDA7DQogIGJhY2tncm91bmQ6ICNmZmZmZTA7DQogIGxpbmUtaGVpZ2h0OiAyOw0KICBmb250LXdlaWdodDogYm9sZDsNCn0NCmg2ew0KICBjb2xvcjogIzAwNjAwMDsNCiAgYmFja2dyb3VuZDogIzAwZmZmZjsNCiAgbGluZS1oZWlnaHQ6IDI7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KDQp9DQplbXsNCiAgY29sb3I6ICNGRkVBNkM7DQogIGJhY2tncm91bmQ6ICM3RDdEN0Q7DQogIH0NCiAgDQp0YWJsZSwgdGgsIHRkIHsNCiAgICBib3JkZXI6IDFweCBzb2xpZCBibGFjazsNCn0NCg0KDQojbXlTaWRlbmF2IGEgew0KICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTsNCiAgICBsZWZ0OiAtMTUwcHg7DQogICAgdHJhbnNpdGlvbjogMC4zczsNCiAgICBwYWRkaW5nOiAxNXB4Ow0KICAgIHdpZHRoOiAxNTBweDsNCiAgICB0ZXh0LWRlY29yYXRpb246IG5vbmU7DQogICAgZm9udC1zaXplOiAyMHB4Ow0KICAgIGNvbG9yOiB3aGl0ZTsNCiAgICBib3JkZXItcmFkaXVzOiAwIDVweCA1cHggMDsNCn0NCiNteVNpZGVuYXZ7DQogICAgdG9wOi0xMHB4Ow0KICAgIHBvc2l0aW9uOiBmaXhlZDsNCn0NCiNteVNpZGVuYXYgYTpob3ZlciB7DQogICAgbGVmdDogLTIwcHg7DQp9DQoNCiNhYm91dCB7DQogICAgdG9wOiAyMHB4Ow0KICAgIGJhY2tncm91bmQtY29sb3I6ICM0Q0FGNTA7DQp9DQoNCiNibG9nIHsNCiAgICB0b3A6IDgwcHg7DQogICAgYmFja2dyb3VuZC1jb2xvcjogIzIxOTZGMzsNCn0NCg0KI3Byb2plY3RzIHsNCiAgICB0b3A6IDE0MHB4Ow0KICAgIGJhY2tncm91bmQtY29sb3I6ICNmNDQzMzY7DQp9DQoNCiNjb250YWN0IHsNCiAgICB0b3A6IDIwMHB4Ow0KICAgIGJhY2tncm91bmQtY29sb3I6ICM1NTUNCn0NCg0KPC9zdHlsZT4NCg0KDQoNCg0KDQo=