Pregunta 01
Use el conjunto de datos casoEF.csv.
Se desea utilizar un Analisis de Regresion Lineal Multiple Utilice solo los datos de las personas pertenecientes a la región A y la(s) variable(s) predictora(s) significativa(s) a un nivel de significacion de 0.01.
Antes de correr su funcion, donde crea conveniente fije: RNGkind(sample.kind=“Rounding”) set.seed(55) En todos los casos presente sus resultados con aproximacion a 3 decimales.
Filtro de datos, region A
datosA <-
datos %>%
dplyr::filter( region %in% c('A') ) %>%
dplyr::select(-c(region))
Valor de semilla
semilla <- 55
El valor del error de prediccion es
lm01 <- lm(formula = peso ~ ., data = datosA)
summary(lm01)
##
## Call:
## lm(formula = peso ~ ., data = datosA)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.6925 -0.1955 0.0163 0.1636 0.8128
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -1.242e+02 2.181e+01 -5.696 6.89e-08 ***
## genero -2.001e-02 5.022e-02 -0.398 0.691
## edad 7.895e-04 3.072e-03 0.257 0.798
## calorias 8.558e-02 1.504e-02 5.689 7.11e-08 ***
## estatura 9.369e-02 1.015e-01 0.923 0.358
## ejercicios 1.600e-01 3.610e-02 4.432 1.86e-05 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.3019 on 141 degrees of freedom
## Multiple R-squared: 0.9989, Adjusted R-squared: 0.9989
## F-statistic: 2.54e+04 on 5 and 141 DF, p-value: < 2.2e-16
data.sig <-
datosA %>%
dplyr::select(c(peso, calorias, ejercicios))
# Variables significativas: Calorias y ejercicios
lm02 <- lm(formula = peso ~ ., data = data.sig)
VEP <- mean( (lm02$residuals)^2 );VEP
## [1] 0.088063
Error de prediccion usando PRESS
PRESSp<-function(datos,y){
datos<-as.matrix(datos)
n<-nrow(datos)
resi<-lm(datos[,y]~datos[,-y])$res
APE<-sum(resi^2)/n
resid<-c()
for(i in 1:n){
betase<-lm(datos[-i,y]~datos[-i,-y])$coe
xi<-c(1,datos[i,-y])
yest<-sum(betase*xi)
resid[i]<-datos[i,y]-yest
}
pressp<-sum(resid^2)/n
return(list(APE=APE,pressp=pressp))
}
RNGkind(sample.kind='Rounding')
set.seed(semilla)
PRESSp(datos = data.sig, y = 1)
## $APE
## [1] 0.088063
##
## $pressp
## [1] 0.09103554
Error de prediccion usando validacion cruzada
crossval<-function(datos,K,r,d){
datos<-as.matrix(datos)
n<-nrow(datos)
EVC<-c()
resid<-c()
subm<-floor(n/K)
resi<-lm(datos[,d]~datos[,-d])$res
APE<-sum(resi^2)/n
for(i in 1:r){
indices<-sample(n,n)
azar<-datos[indices,]
for(j in 1:K){
unid<- ((j-1)*subm+1):(subm*j)
if (j==K)
{
unid<-((j-1)*subm+1):n
}
datosp<-azar[unid,]
datose<-azar[-unid,]
ye<-datose[,d]
xe<-datose[,-d]
betas<-lm(ye~xe)$coef
datosp1<-cbind(1,datosp[,-d])
estim<-datosp1%*%betas
resid[j]<-sum((datosp[,d]-estim)^2)
}
EVC[i]<-sum(resid)/n
}
EVCP<-mean(EVC)
cvEVC<-sd(EVC)*100/EVCP
sesgo<-EVCP-APE
return(list(APE=APE,EVCP=EVCP,EVCsd = sd(EVC), cvEVC=cvEVC,sesgo=sesgo))
}
RNGkind(sample.kind="Rounding")
set.seed(semilla)
crossval(datos = data.sig, K = 7, r = 27, d = 1)
## $APE
## [1] 0.088063
##
## $EVCP
## [1] 0.09130565
##
## $EVCsd
## [1] 0.0009864908
##
## $cvEVC
## [1] 1.080427
##
## $sesgo
## [1] 0.003242647
kopt<-function(datos,K,r,d){
resul<-c()
t<-length(K)
for(i in 1:t){
resul[i]<-system.time(crossval(datos,K[i],r,d))[3]
}
plot(K,resul,type="b",col=4)
return(resul)
}
ks<-c(3,5,7,10,12,14)
RNGkind(sample.kind="Rounding")
set.seed(semilla)
kopt(data.sig,ks,80,1)

## [1] 0.11 0.19 0.26 0.37 0.43 0.51
Error de prediccion con validacion cruzada generalizada
vcg<-function(datos,y){
datos<-as.matrix(datos)
n<-nrow(datos)
modelo<-lm(datos[,y]~datos[,-y])
resi<-modelo$res
APE<-sum(resi^2)/n
Hp<-hatvalues(modelo)
vcg<-APE/(1-sum(Hp)/n)^2
return(list(APE=APE,vcg=vcg))
}
vcg(datos = data.sig, y = 1)
## $APE
## [1] 0.088063
##
## $vcg
## [1] 0.09177051
Error de prediccion con Bootstrap simple
bs<-function(datos,B,y){
datos<-as.matrix(datos)
n<-nrow(datos)
modelo<-lm(datos[,y]~datos[,-y])
resi<-modelo$res
APE<-sum(resi^2)/n
bootape<-c()
for(i in 1:B){
indices<-sample(n,n,T)
modelob<-lm(datos[indices,y]~datos[indices,-y])$coe
yest<-cbind(1,datos[,-y])%*%modelob
bootape[i]<-sum((yest-datos[,y])^2)/n
}
EPBS<-mean(bootape)
return(list(APE=APE,EPBS=EPBS))
}
RNGkind(sample.kind="Rounding")
set.seed(semilla)
bs(datos = data.sig, B = 148, y = 1)
## $APE
## [1] 0.088063
##
## $EPBS
## [1] 0.08948012
Error de prediccion con Bootstrap refinado
br<-function(datos,B,y){
datos<-as.matrix(datos)
n<-nrow(datos)
modelo<-lm(datos[,y]~datos[,-y])
resi<-modelo$res
APE<-sum(resi^2)/n
bootape1<-c()
bootape2<-c()
for(i in 1:B){
indices<-sample(n,n,T)
modelob<-lm(datos[indices,y]~datos[indices,-y])
coeboot<-modelob$coe
resboot<-modelob$res
yest<-cbind(1,datos[,-y])%*%coeboot
bootape1[i]<-sum((yest-datos[,y])^2)/n
bootape2[i]<-sum(resboot^2)/n
}
APE1<-mean(bootape1)
APE2<-mean(bootape2)
BR<-APE+APE1-APE2
return(list(APE=APE,EPBS=APE1,EPBR=BR))
}
RNGkind(sample.kind = "Rounding")
set.seed(semilla)
br(datos = data.sig, B = 148, y = 1)
## $APE
## [1] 0.088063
##
## $EPBS
## [1] 0.08948012
##
## $EPBR
## [1] 0.09050549
Pregunta 02
Considere solo los datos de la región A.
Se desea aplicar un Analisis de Regresion Lineal Simple para explicar el peso de una persona en funcion de la variable predictora edad. Considere como estadistico de interés a la pendiente de la recta.
Antes de correr su funcion, donde crea conveniente fije: RNGkind(sample.kind=“Rounding”) set.seed(89)
En todos los casos presente sus resultados con aproximacion a 3 decimales.
datos02 <-
dplyr::select(datosA, c(peso, edad))
Semilla
semilla02 <- 89
# Jackknife
jack2.2<-function(datos,estadistico,...){
n<-nrow(datos)
estjack<-c()
for(i in 1:n){
estjack[i]<-estadistico(datos[-i,],...)
}
esjack<-mean(estjack)
eejack<-(n-1)*sd(estjack)/sqrt(n)
resu<-c(esjack, eejack)
return(resu)
}
# Intervalo de confianza Jackknife
jack2.2.ic<-function(datos,B,conf,estadistico,...){
alfa<-1-conf
n<-nrow(datos)
estjack1<-matrix(0,B,2)
for(i in 1:B){
indices<-sample(n,n,T)
mboot<-datos[indices,]
estjack1[i,]<-jack2.2(mboot,estadistico,...)
}
esta<-estadistico(datos,...)
eejackm<-jack2.2(datos,estadistico,...)[2]
pivot<-(estjack1[,1]-esta)/estjack1[,2]
LI.me<-esta-qnorm(1-alfa/2)*eejackm
LS.me<-esta+qnorm(1-alfa/2)*eejackm
ME<-c(LI.me,LS.me)
LI.mes<-esta+quantile(pivot,alfa/2)*eejackm
LS.mes<-esta+quantile(pivot,1-alfa/2)*eejackm
MES<-c(LI.mes,LS.mes)
return(list(ME=ME,MES=MES))
}
lm.pend <- function(datos) {
datos.matrix <- as.matrix(datos)
pendiente <- lm(datos.matrix[, 1] ~ datos.matrix[, -1])$coefficients[2]
return(pendiente)
}
RNGkind(sample.kind = "Rounding")
set.seed(semilla02)
jack2.2.ic(datos02, B = 148, conf = 0.94, lm.pend)
## $ME
## datos.matrix[, -1] datos.matrix[, -1]
## -0.1734490 0.1671998
##
## $MES
## datos.matrix[, -1] datos.matrix[, -1]
## -0.1994212 0.1621976
# system.time(jack2.2.ic(datos02, B = 148, conf = 0.94, lm.pend))[3]
BCA
bca <- function(datos,B,conf,estadistico,...){
alfa<-1-conf
n<-nrow(datos)
estb<-c()
estjack<-c()
esta<-estadistico(datos,...)
for(i in 1:B){
estb[i]<-estadistico(dplyr::sample_n(tbl = datos, size = n, replace = T), ...)
}
z0 <- qnorm(mean(estb < esta))
for(j in 1:n){
estjack[j]<-estadistico(datos[-j, ],...)
}
num<-sum((mean(estjack)-estjack)^3)
den<-6*((sum((mean(estjack)-estjack)^2))^1.5)
a<-num/den
alfa1<-pnorm(z0+(z0+qnorm(alfa/2))/(1-a*(z0+qnorm(alfa/2))))
alfa2<-pnorm(z0+(z0+qnorm(1-alfa/2))/(1-a*(z0+qnorm(1-alfa/2))))
LI<-quantile(estb,alfa1)
LS<-quantile(estb,alfa2)
lim<-c(LI,LS)
return(lim)
}
RNGkind(sample.kind = "Rounding")
set.seed(semilla02)
bca(datos = datos02, B = 148, conf = 0.94, estadistico = lm.pend)
## 6.302328% 98.73415%
## -0.1340222 0.1932282
Jacknife despues de bootstrap
boot2<-function(datos,B,estadistico,...){
n<-nrow(datos)
estboot<-c()
for(i in 1:B){
indices<-sample(n,n,T)
estboot[i]<-estadistico(datos[indices,],...)
}
esta<-estadistico(datos,...)
esboot<-mean(estboot)
eeboot<-sd(estboot)
seboot<-(esboot-esta)
return(list(esboot=esboot,eeboot=eeboot,seboot=seboot))
}
jdb<-function(datos,B,estadistico,...){
n<-nrow(datos)
medi<-c()
for(i in 1:n){
medi[i]<-boot2(datos[-i,],B,estadistico,...)$seboot
}
vari<-(n-1)^2*var(medi)/n
return(vari)
}
RNGkind(sample.kind = "Rounding")
set.seed(semilla02)
jdb(datos = datos02, B = 148, estadistico = lm.pend)
## [1] 0.008337628
LS0tDQp0aXRsZTogIlNpbXVsYWNyb19Qb3JyYXMiDQphdXRob3I6ICJDYXJsbyBWZWdhIg0KZGF0ZTogIjcvMjQvMjAyMSINCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBtZXNzYWdlID0gRiwgZXJyb3IgPSBGLCB3YXJuaW5nID0gRikNCmBgYA0KDQojIyMgTGlicmVyaWFzIG5lY2VzYXJpYXMNCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpgYGANCg0KIyMjIExlY3R1cmEgZGUgZGF0b3MNCmBgYHtyfQ0KY2Fzb0VGIDwtIHJlYWR4bDo6cmVhZF9leGNlbChwYXRoID0gJ0Nhc28gRUYueGxzeCcpDQoNCmRhdG9zIDwtIA0KICBjYXNvRUYgJT4lIA0KICBkcGx5cjo6bXV0YXRlKGdlbmVybyA9IGRwbHlyOjpyZWNvZGUoZ2VuZXJvLCAnZmVtZW5pbm8nID0gMCwgJ21hc2N1bGlubycgPSAxKSkNCg0KYGBgDQoNCg0KIyMjIFByZWd1bnRhIDAxDQoNClVzZSBlbCBjb25qdW50byBkZSBkYXRvcyBjYXNvRUYuY3N2Lg0KDQpTZSBkZXNlYSB1dGlsaXphciB1biBBbmFsaXNpcyBkZSBSZWdyZXNpb24gTGluZWFsIE11bHRpcGxlDQpVdGlsaWNlIHNvbG8gbG9zIGRhdG9zIGRlIGxhcyBwZXJzb25hcyBwZXJ0ZW5lY2llbnRlcyBhIGxhIHJlZ2nDs24gQSB5IGxhKHMpIHZhcmlhYmxlKHMpIHByZWRpY3RvcmEocykgc2lnbmlmaWNhdGl2YShzKSBhIHVuIG5pdmVsIGRlIHNpZ25pZmljYWNpb24gZGUgMC4wMS4NCg0KQW50ZXMgZGUgY29ycmVyIHN1IGZ1bmNpb24sIGRvbmRlIGNyZWEgY29udmVuaWVudGUgZmlqZToNClJOR2tpbmQoc2FtcGxlLmtpbmQ94oCcUm91bmRpbmfigJ0pDQpzZXQuc2VlZCg1NSkNCkVuIHRvZG9zIGxvcyBjYXNvcyBwcmVzZW50ZSBzdXMgcmVzdWx0YWRvcyBjb24gYXByb3hpbWFjaW9uIGEgMyBkZWNpbWFsZXMuDQoNCiMjIyMgRmlsdHJvIGRlIGRhdG9zLCByZWdpb24gQQ0KYGBge3J9DQpkYXRvc0EgPC0gDQogIGRhdG9zICU+JSANCiAgZHBseXI6OmZpbHRlciggcmVnaW9uICVpbiUgYygnQScpICkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC1jKHJlZ2lvbikpDQpgYGANCg0KIyMjIyBWYWxvciBkZSBzZW1pbGxhDQpgYGB7cn0NCnNlbWlsbGEgPC0gNTUNCmBgYA0KDQoNCiMjIyMgRWwgdmFsb3IgZGVsIGVycm9yIGRlIHByZWRpY2Npb24gZXMNCmBgYHtyfQ0KbG0wMSA8LSBsbShmb3JtdWxhID0gcGVzbyB+IC4sIGRhdGEgPSBkYXRvc0EpDQpzdW1tYXJ5KGxtMDEpDQoNCmRhdGEuc2lnIDwtIA0KICBkYXRvc0EgJT4lIA0KICBkcGx5cjo6c2VsZWN0KGMocGVzbywgY2Fsb3JpYXMsIGVqZXJjaWNpb3MpKQ0KDQojIFZhcmlhYmxlcyBzaWduaWZpY2F0aXZhczogQ2Fsb3JpYXMgeSBlamVyY2ljaW9zDQpsbTAyIDwtIGxtKGZvcm11bGEgPSBwZXNvIH4gLiwgZGF0YSA9IGRhdGEuc2lnKQ0KVkVQIDwtIG1lYW4oIChsbTAyJHJlc2lkdWFscyleMiApO1ZFUA0KDQpgYGANCg0KIyMjIyBFcnJvciBkZSBwcmVkaWNjaW9uIHVzYW5kbyBQUkVTUw0KYGBge3J9DQoNClBSRVNTcDwtZnVuY3Rpb24oZGF0b3MseSl7DQogIGRhdG9zPC1hcy5tYXRyaXgoZGF0b3MpDQogIG48LW5yb3coZGF0b3MpDQogIHJlc2k8LWxtKGRhdG9zWyx5XX5kYXRvc1ssLXldKSRyZXMNCiAgQVBFPC1zdW0ocmVzaV4yKS9uDQogIHJlc2lkPC1jKCkNCiAgZm9yKGkgaW4gMTpuKXsNCiAgICBiZXRhc2U8LWxtKGRhdG9zWy1pLHldfmRhdG9zWy1pLC15XSkkY29lDQogICAgeGk8LWMoMSxkYXRvc1tpLC15XSkNCiAgICB5ZXN0PC1zdW0oYmV0YXNlKnhpKQ0KICAgIHJlc2lkW2ldPC1kYXRvc1tpLHldLXllc3QNCiAgfQ0KICBwcmVzc3A8LXN1bShyZXNpZF4yKS9uDQogIHJldHVybihsaXN0KEFQRT1BUEUscHJlc3NwPXByZXNzcCkpDQp9DQoNClJOR2tpbmQoc2FtcGxlLmtpbmQ9J1JvdW5kaW5nJykNCnNldC5zZWVkKHNlbWlsbGEpDQpQUkVTU3AoZGF0b3MgPSBkYXRhLnNpZywgeSA9IDEpDQoNCmBgYA0KDQojIyMjIEVycm9yIGRlIHByZWRpY2Npb24gdXNhbmRvIHZhbGlkYWNpb24gY3J1emFkYQ0KYGBge3J9DQoNCmNyb3NzdmFsPC1mdW5jdGlvbihkYXRvcyxLLHIsZCl7DQogIGRhdG9zPC1hcy5tYXRyaXgoZGF0b3MpDQogIG48LW5yb3coZGF0b3MpDQogIEVWQzwtYygpDQogIHJlc2lkPC1jKCkNCiAgc3VibTwtZmxvb3Iobi9LKQ0KICByZXNpPC1sbShkYXRvc1ssZF1+ZGF0b3NbLC1kXSkkcmVzDQogIEFQRTwtc3VtKHJlc2leMikvbg0KICBmb3IoaSBpbiAxOnIpew0KICAgIGluZGljZXM8LXNhbXBsZShuLG4pDQogICAgYXphcjwtZGF0b3NbaW5kaWNlcyxdDQogICAgDQogICAgZm9yKGogaW4gMTpLKXsNCiAgICAgIHVuaWQ8LSAoKGotMSkqc3VibSsxKTooc3VibSpqKQ0KICAgICAgaWYgKGo9PUspDQogICAgICB7DQogICAgICAgIHVuaWQ8LSgoai0xKSpzdWJtKzEpOm4NCiAgICAgIH0NCiAgICAgZGF0b3NwPC1hemFyW3VuaWQsXQ0KICAgICBkYXRvc2U8LWF6YXJbLXVuaWQsXQ0KICAgICB5ZTwtZGF0b3NlWyxkXQ0KICAgICB4ZTwtZGF0b3NlWywtZF0NCiAgICAgYmV0YXM8LWxtKHllfnhlKSRjb2VmDQogICAgIGRhdG9zcDE8LWNiaW5kKDEsZGF0b3NwWywtZF0pDQogICAgIGVzdGltPC1kYXRvc3AxJSolYmV0YXMNCiAgICAgcmVzaWRbal08LXN1bSgoZGF0b3NwWyxkXS1lc3RpbSleMikNCiAgICB9DQogICAgRVZDW2ldPC1zdW0ocmVzaWQpL24NCiAgfQ0KICBFVkNQPC1tZWFuKEVWQykNCiAgY3ZFVkM8LXNkKEVWQykqMTAwL0VWQ1ANCiAgc2VzZ288LUVWQ1AtQVBFDQogIHJldHVybihsaXN0KEFQRT1BUEUsRVZDUD1FVkNQLEVWQ3NkID0gc2QoRVZDKSwgY3ZFVkM9Y3ZFVkMsc2VzZ289c2VzZ28pKQ0KfQ0KDQpSTkdraW5kKHNhbXBsZS5raW5kPSJSb3VuZGluZyIpDQpzZXQuc2VlZChzZW1pbGxhKQ0KY3Jvc3N2YWwoZGF0b3MgPSBkYXRhLnNpZywgSyA9IDcsIHIgPSAyNywgZCA9IDEpDQoNCmtvcHQ8LWZ1bmN0aW9uKGRhdG9zLEsscixkKXsNCiAgcmVzdWw8LWMoKQ0KICB0PC1sZW5ndGgoSykNCiAgZm9yKGkgaW4gMTp0KXsNCiAgICByZXN1bFtpXTwtc3lzdGVtLnRpbWUoY3Jvc3N2YWwoZGF0b3MsS1tpXSxyLGQpKVszXQ0KICB9DQogIHBsb3QoSyxyZXN1bCx0eXBlPSJiIixjb2w9NCkNCiAgcmV0dXJuKHJlc3VsKQ0KfQ0KDQprczwtYygzLDUsNywxMCwxMiwxNCkNClJOR2tpbmQoc2FtcGxlLmtpbmQ9IlJvdW5kaW5nIikNCnNldC5zZWVkKHNlbWlsbGEpDQprb3B0KGRhdGEuc2lnLGtzLDgwLDEpDQoNCmBgYA0KDQojIyMjIEVycm9yIGRlIHByZWRpY2Npb24gY29uIHZhbGlkYWNpb24gY3J1emFkYSBnZW5lcmFsaXphZGENCmBgYHtyfQ0KDQp2Y2c8LWZ1bmN0aW9uKGRhdG9zLHkpew0KICBkYXRvczwtYXMubWF0cml4KGRhdG9zKQ0KICBuPC1ucm93KGRhdG9zKQ0KICBtb2RlbG88LWxtKGRhdG9zWyx5XX5kYXRvc1ssLXldKQ0KICByZXNpPC1tb2RlbG8kcmVzDQogIEFQRTwtc3VtKHJlc2leMikvbg0KICBIcDwtaGF0dmFsdWVzKG1vZGVsbykNCiAgdmNnPC1BUEUvKDEtc3VtKEhwKS9uKV4yDQogIHJldHVybihsaXN0KEFQRT1BUEUsdmNnPXZjZykpDQp9DQoNCnZjZyhkYXRvcyA9IGRhdGEuc2lnLCB5ID0gMSkNCg0KYGBgDQoNCiMjIyMgRXJyb3IgZGUgcHJlZGljY2lvbiBjb24gQm9vdHN0cmFwIHNpbXBsZQ0KYGBge3J9DQoNCmJzPC1mdW5jdGlvbihkYXRvcyxCLHkpew0KICBkYXRvczwtYXMubWF0cml4KGRhdG9zKQ0KICBuPC1ucm93KGRhdG9zKQ0KICBtb2RlbG88LWxtKGRhdG9zWyx5XX5kYXRvc1ssLXldKQ0KICByZXNpPC1tb2RlbG8kcmVzDQogIEFQRTwtc3VtKHJlc2leMikvbg0KICBib290YXBlPC1jKCkNCiAgZm9yKGkgaW4gMTpCKXsNCiAgICBpbmRpY2VzPC1zYW1wbGUobixuLFQpDQogICAgbW9kZWxvYjwtbG0oZGF0b3NbaW5kaWNlcyx5XX5kYXRvc1tpbmRpY2VzLC15XSkkY29lDQogICAgeWVzdDwtY2JpbmQoMSxkYXRvc1ssLXldKSUqJW1vZGVsb2INCiAgICBib290YXBlW2ldPC1zdW0oKHllc3QtZGF0b3NbLHldKV4yKS9uDQogIH0NCiAgRVBCUzwtbWVhbihib290YXBlKQ0KICByZXR1cm4obGlzdChBUEU9QVBFLEVQQlM9RVBCUykpDQp9DQoNClJOR2tpbmQoc2FtcGxlLmtpbmQ9IlJvdW5kaW5nIikNCnNldC5zZWVkKHNlbWlsbGEpDQpicyhkYXRvcyA9IGRhdGEuc2lnLCBCID0gMTQ4LCB5ID0gMSkNCg0KYGBgDQoNCiMjIyMgRXJyb3IgZGUgcHJlZGljY2lvbiBjb24gQm9vdHN0cmFwIHJlZmluYWRvDQpgYGB7cn0NCg0KYnI8LWZ1bmN0aW9uKGRhdG9zLEIseSl7DQogIGRhdG9zPC1hcy5tYXRyaXgoZGF0b3MpDQogIG48LW5yb3coZGF0b3MpDQogIG1vZGVsbzwtbG0oZGF0b3NbLHldfmRhdG9zWywteV0pDQogIHJlc2k8LW1vZGVsbyRyZXMNCiAgQVBFPC1zdW0ocmVzaV4yKS9uDQogIGJvb3RhcGUxPC1jKCkNCiAgYm9vdGFwZTI8LWMoKQ0KICBmb3IoaSBpbiAxOkIpew0KICAgIGluZGljZXM8LXNhbXBsZShuLG4sVCkNCiAgICBtb2RlbG9iPC1sbShkYXRvc1tpbmRpY2VzLHldfmRhdG9zW2luZGljZXMsLXldKQ0KICAgIGNvZWJvb3Q8LW1vZGVsb2IkY29lDQogICAgcmVzYm9vdDwtbW9kZWxvYiRyZXMNCiAgICB5ZXN0PC1jYmluZCgxLGRhdG9zWywteV0pJSolY29lYm9vdA0KICAgIGJvb3RhcGUxW2ldPC1zdW0oKHllc3QtZGF0b3NbLHldKV4yKS9uDQogICAgYm9vdGFwZTJbaV08LXN1bShyZXNib290XjIpL24NCiAgfQ0KICBBUEUxPC1tZWFuKGJvb3RhcGUxKQ0KICBBUEUyPC1tZWFuKGJvb3RhcGUyKQ0KICBCUjwtQVBFK0FQRTEtQVBFMg0KICByZXR1cm4obGlzdChBUEU9QVBFLEVQQlM9QVBFMSxFUEJSPUJSKSkNCn0NCg0KUk5Ha2luZChzYW1wbGUua2luZCA9ICJSb3VuZGluZyIpDQpzZXQuc2VlZChzZW1pbGxhKQ0KYnIoZGF0b3MgPSBkYXRhLnNpZywgQiA9IDE0OCwgeSA9IDEpDQoNCmBgYA0KDQojIyMjIEVycm9yIGRlIHByZWRpY2Npb24gbWVkaWFudGUgQm9vdHN0cmFwDQpgYGB7cn0NCg0KYm9vdDAuNjMyPC1mdW5jdGlvbihkYXRhLEIsZCkNCnsNCiAgZGF0YTwtYXMubWF0cml4KGRhdGEpDQogIG48LWRpbShkYXRhKVsxXQ0KICBwPC1kaW0oZGF0YSlbMl0NCiAgeTwtZGF0YVssZF0NCiAgeDwtZGF0YVssLWRdDQogIHJlZzwtbG0oeX54KQ0KICBBUEU8LXN1bShyZWckcmVzaV4yKS9uDQogIG9uZTwtcmVwKDEsbikNCiAgeDE8LWNiaW5kKG9uZSx4KQ0KICBiZXRhczwtbWF0cml4KDAsQixwKQ0KICBpbmRpY2VzPC1tYXRyaXgoMCxCLG4pDQogIHJlc2lkMmI8LXJlcCgwLG4pDQogIGZvcihpIGluIDE6Qil7DQogICAgaW5kPC1zYW1wbGUoMTpuLG4scmVwbGFjZT1UUlVFKQ0KICAgIGluZGljZXNbaSxdPC1pbmQNCiAgICBiZXRhc1tpLF08LWxtKHlbaW5kXX54W2luZCxdKSRjb2VmDQogIH0NCiAgZm9yKHIgaW4gMTpuKXsNCiAgICBjMTwtMA0KICAgIGluZGljZXMyPC1tYXRyaXgoMCxCLG4pDQogICAgSUQ9cmVwKDAsQikNCiAgICBmb3IoaSBpbiAxOkIpew0KICAgICAgZm9yKGogaW4gMTpuKXsNCiAgICAgICAgaWYoaW5kaWNlc1tpLGpdPT1yKSBpbmRpY2VzMltpLGpdPTENCiAgICAgIH0NCiAgICB9DQogICAgaW5kPC1hcHBseShpbmRpY2VzMiwxLHN1bSkNCiAgICBmb3IoaSBpbiAxOkIpIGlmKGluZFtpXT09MCkgSURbaV09MQ0KICAgIG4xPC1zdW0oSUQpDQogICAgdjwtcmVwKDAsbjEpDQogICAgZm9yKGkgaW4gMTpCKXsNCiAgICAgIGlmKElEW2ldPT0xKSB7DQogICAgICAgIGMxPWMxKzENCiAgICAgICAgdltjMV09aQ0KICAgICAgfQ0KICAgIH0NCiAgICByZXNpMjwtbWF0cml4KDAsbjEsbikNCiAgICBmb3IodSBpbiAxOm4xKXsNCiAgICAgIGJldGFzMTwtYmV0YXNbdlt1XSxdDQogICAgICB5cDwteDElKiViZXRhczENCiAgICAgIHJlc2k8LSh5LXlwKQ0KICAgICAgcmVzaTJbdSxdPC1yZXNpXjINCiAgICB9DQogICAgcmVzaWRiPC1hcHBseShyZXNpMiwxLHN1bSkNCiAgICByZXNpZDJiW3JdPC1tZWFuKHJlc2lkYikNCiAgfQ0KICBlMDwtbWVhbihyZXNpZDJiKS9uDQogIGUwLjYzMjwtMC4zNjgqQVBFKzAuNjMyKmUwDQogIHJldHVybihsaXN0KEFQRT1BUEUsZTA9ZTAsZTAuNjMyPWUwLjYzMikpDQp9DQoNClJOR2tpbmQoc2FtcGxlLmtpbmQgPSJSb3VuZGluZyIpDQpzZXQuc2VlZChzZW1pbGxhKQ0KYm9vdDAuNjMyKGRhdGEgPSBkYXRhLnNpZywgQiA9IDE0OCwgZCA9IDEpDQoNCmBgYA0KDQojIyMgUHJlZ3VudGEgMDINCg0KQ29uc2lkZXJlIHNvbG8gbG9zIGRhdG9zIGRlIGxhIHJlZ2nDs24gQS4NCg0KU2UgZGVzZWEgYXBsaWNhciB1biBBbmFsaXNpcyBkZSBSZWdyZXNpb24gTGluZWFsIFNpbXBsZSBwYXJhIGV4cGxpY2FyIGVsIHBlc28gZGUgdW5hIHBlcnNvbmEgZW4gZnVuY2lvbiBkZSBsYSB2YXJpYWJsZSBwcmVkaWN0b3JhIGVkYWQuIENvbnNpZGVyZSBjb21vIGVzdGFkaXN0aWNvIGRlIGludGVyw6lzIGEgbGEgcGVuZGllbnRlIGRlIGxhIHJlY3RhLg0KDQpBbnRlcyBkZSBjb3JyZXIgc3UgZnVuY2lvbiwgZG9uZGUgY3JlYSBjb252ZW5pZW50ZSBmaWplOg0KUk5Ha2luZChzYW1wbGUua2luZD3igJxSb3VuZGluZ+KAnSkNCnNldC5zZWVkKDg5KQ0KDQpFbiB0b2RvcyBsb3MgY2Fzb3MgcHJlc2VudGUgc3VzIHJlc3VsdGFkb3MgY29uIGFwcm94aW1hY2lvbiBhIDMgZGVjaW1hbGVzLg0KDQpgYGB7cn0NCmRhdG9zMDIgPC0gDQogIGRwbHlyOjpzZWxlY3QoZGF0b3NBLCBjKHBlc28sIGVkYWQpKQ0KYGBgDQoNCiMjIyMgU2VtaWxsYQ0KYGBge3J9DQpzZW1pbGxhMDIgPC0gODkNCmBgYA0KDQpgYGB7cn0NCiMgSmFja2tuaWZlDQpqYWNrMi4yPC1mdW5jdGlvbihkYXRvcyxlc3RhZGlzdGljbywuLi4pew0KICBuPC1ucm93KGRhdG9zKQ0KICBlc3RqYWNrPC1jKCkNCiAgZm9yKGkgaW4gMTpuKXsNCiAgICBlc3RqYWNrW2ldPC1lc3RhZGlzdGljbyhkYXRvc1staSxdLC4uLikNCiAgfQ0KICBlc2phY2s8LW1lYW4oZXN0amFjaykNCiAgZWVqYWNrPC0obi0xKSpzZChlc3RqYWNrKS9zcXJ0KG4pDQogIHJlc3U8LWMoZXNqYWNrLCBlZWphY2spDQogIHJldHVybihyZXN1KSANCn0NCg0KIyBJbnRlcnZhbG8gZGUgY29uZmlhbnphIEphY2trbmlmZQ0KamFjazIuMi5pYzwtZnVuY3Rpb24oZGF0b3MsQixjb25mLGVzdGFkaXN0aWNvLC4uLil7DQogIGFsZmE8LTEtY29uZg0KICBuPC1ucm93KGRhdG9zKQ0KICBlc3RqYWNrMTwtbWF0cml4KDAsQiwyKQ0KICAgIGZvcihpIGluIDE6Qil7DQogICAgaW5kaWNlczwtc2FtcGxlKG4sbixUKQ0KICAgIG1ib290PC1kYXRvc1tpbmRpY2VzLF0NCiAgICBlc3RqYWNrMVtpLF08LWphY2syLjIobWJvb3QsZXN0YWRpc3RpY28sLi4uKQ0KICAgIH0NCiAgZXN0YTwtZXN0YWRpc3RpY28oZGF0b3MsLi4uKQ0KICBlZWphY2ttPC1qYWNrMi4yKGRhdG9zLGVzdGFkaXN0aWNvLC4uLilbMl0NCiAgcGl2b3Q8LShlc3RqYWNrMVssMV0tZXN0YSkvZXN0amFjazFbLDJdDQogIExJLm1lPC1lc3RhLXFub3JtKDEtYWxmYS8yKSplZWphY2ttDQogIExTLm1lPC1lc3RhK3Fub3JtKDEtYWxmYS8yKSplZWphY2ttDQogIE1FPC1jKExJLm1lLExTLm1lKQ0KICBMSS5tZXM8LWVzdGErcXVhbnRpbGUocGl2b3QsYWxmYS8yKSplZWphY2ttDQogIExTLm1lczwtZXN0YStxdWFudGlsZShwaXZvdCwxLWFsZmEvMikqZWVqYWNrbQ0KICBNRVM8LWMoTEkubWVzLExTLm1lcykNCiAgcmV0dXJuKGxpc3QoTUU9TUUsTUVTPU1FUykpDQp9DQoNCmxtLnBlbmQgPC0gZnVuY3Rpb24oZGF0b3MpIHsNCiAgDQogIGRhdG9zLm1hdHJpeCA8LSBhcy5tYXRyaXgoZGF0b3MpDQogIHBlbmRpZW50ZSA8LSBsbShkYXRvcy5tYXRyaXhbLCAxXSB+IGRhdG9zLm1hdHJpeFssIC0xXSkkY29lZmZpY2llbnRzWzJdDQogIHJldHVybihwZW5kaWVudGUpDQogIA0KfQ0KDQpSTkdraW5kKHNhbXBsZS5raW5kID0gIlJvdW5kaW5nIikNCnNldC5zZWVkKHNlbWlsbGEwMikNCmphY2syLjIuaWMoZGF0b3MwMiwgQiA9IDE0OCwgY29uZiA9IDAuOTQsIGxtLnBlbmQpDQoNCiMgc3lzdGVtLnRpbWUoamFjazIuMi5pYyhkYXRvczAyLCBCID0gMTQ4LCBjb25mID0gMC45NCwgbG0ucGVuZCkpWzNdDQoNCmBgYA0KDQojIyMjIEJDQQ0KYGBge3J9DQoNCmJjYSA8LSBmdW5jdGlvbihkYXRvcyxCLGNvbmYsZXN0YWRpc3RpY28sLi4uKXsNCiAgYWxmYTwtMS1jb25mDQogIG48LW5yb3coZGF0b3MpDQogIGVzdGI8LWMoKQ0KICBlc3RqYWNrPC1jKCkNCiAgZXN0YTwtZXN0YWRpc3RpY28oZGF0b3MsLi4uKQ0KICBmb3IoaSBpbiAxOkIpew0KICAgZXN0YltpXTwtZXN0YWRpc3RpY28oZHBseXI6OnNhbXBsZV9uKHRibCA9IGRhdG9zLCBzaXplID0gbiwgcmVwbGFjZSA9IFQpLCAuLi4pDQogIH0NCiAgejAgPC0gcW5vcm0obWVhbihlc3RiIDwgZXN0YSkpDQogIA0KICBmb3IoaiBpbiAxOm4pew0KICAgIGVzdGphY2tbal08LWVzdGFkaXN0aWNvKGRhdG9zWy1qLCBdLC4uLikNCiAgfQ0KICANCiAgbnVtPC1zdW0oKG1lYW4oZXN0amFjayktZXN0amFjayleMykNCiAgZGVuPC02Kigoc3VtKChtZWFuKGVzdGphY2spLWVzdGphY2spXjIpKV4xLjUpDQogIGE8LW51bS9kZW4NCiAgYWxmYTE8LXBub3JtKHowKyh6MCtxbm9ybShhbGZhLzIpKS8oMS1hKih6MCtxbm9ybShhbGZhLzIpKSkpDQogIGFsZmEyPC1wbm9ybSh6MCsoejArcW5vcm0oMS1hbGZhLzIpKS8oMS1hKih6MCtxbm9ybSgxLWFsZmEvMikpKSkNCiAgTEk8LXF1YW50aWxlKGVzdGIsYWxmYTEpDQogIExTPC1xdWFudGlsZShlc3RiLGFsZmEyKQ0KICBsaW08LWMoTEksTFMpDQogIHJldHVybihsaW0pDQp9DQoNCg0KUk5Ha2luZChzYW1wbGUua2luZCA9ICJSb3VuZGluZyIpDQpzZXQuc2VlZChzZW1pbGxhMDIpDQpiY2EoZGF0b3MgPSBkYXRvczAyLCBCID0gMTQ4LCBjb25mID0gMC45NCwgZXN0YWRpc3RpY28gPSBsbS5wZW5kKQ0KDQpgYGANCg0KIyMjIyBKYWNrbmlmZSBkZXNwdWVzIGRlIGJvb3RzdHJhcA0KYGBge3J9DQoNCmJvb3QyPC1mdW5jdGlvbihkYXRvcyxCLGVzdGFkaXN0aWNvLC4uLil7DQogIG48LW5yb3coZGF0b3MpDQogIGVzdGJvb3Q8LWMoKQ0KICBmb3IoaSBpbiAxOkIpew0KICAgIGluZGljZXM8LXNhbXBsZShuLG4sVCkNCiAgICBlc3Rib290W2ldPC1lc3RhZGlzdGljbyhkYXRvc1tpbmRpY2VzLF0sLi4uKQ0KICB9DQogIGVzdGE8LWVzdGFkaXN0aWNvKGRhdG9zLC4uLikNCiAgZXNib290PC1tZWFuKGVzdGJvb3QpDQogIGVlYm9vdDwtc2QoZXN0Ym9vdCkNCiAgc2Vib290PC0oZXNib290LWVzdGEpDQogIHJldHVybihsaXN0KGVzYm9vdD1lc2Jvb3QsZWVib290PWVlYm9vdCxzZWJvb3Q9c2Vib290KSkgDQp9DQoNCmpkYjwtZnVuY3Rpb24oZGF0b3MsQixlc3RhZGlzdGljbywuLi4pew0KICBuPC1ucm93KGRhdG9zKQ0KICBtZWRpPC1jKCkNCiAgZm9yKGkgaW4gMTpuKXsNCiAgICBtZWRpW2ldPC1ib290MihkYXRvc1staSxdLEIsZXN0YWRpc3RpY28sLi4uKSRzZWJvb3QNCiAgfQ0KICB2YXJpPC0obi0xKV4yKnZhcihtZWRpKS9uDQogIHJldHVybih2YXJpKQ0KfQ0KDQpSTkdraW5kKHNhbXBsZS5raW5kID0gIlJvdW5kaW5nIikNCnNldC5zZWVkKHNlbWlsbGEwMikNCmpkYihkYXRvcyA9IGRhdG9zMDIsIEIgPSAxNDgsIGVzdGFkaXN0aWNvID0gbG0ucGVuZCkNCg0KDQpgYGANCg0K