Librerias necesarias

library(tidyverse)

Lectura de datos

casoEF <- readxl::read_excel(path = 'Caso EF.xlsx')

datos <- 
  casoEF %>% 
  dplyr::mutate(genero = dplyr::recode(genero, 'femenino' = 0, 'masculino' = 1))

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

Error de prediccion mediante Bootstrap

boot0.632<-function(data,B,d)
{
  data<-as.matrix(data)
  n<-dim(data)[1]
  p<-dim(data)[2]
  y<-data[,d]
  x<-data[,-d]
  reg<-lm(y~x)
  APE<-sum(reg$resi^2)/n
  one<-rep(1,n)
  x1<-cbind(one,x)
  betas<-matrix(0,B,p)
  indices<-matrix(0,B,n)
  resid2b<-rep(0,n)
  for(i in 1:B){
    ind<-sample(1:n,n,replace=TRUE)
    indices[i,]<-ind
    betas[i,]<-lm(y[ind]~x[ind,])$coef
  }
  for(r in 1:n){
    c1<-0
    indices2<-matrix(0,B,n)
    ID=rep(0,B)
    for(i in 1:B){
      for(j in 1:n){
        if(indices[i,j]==r) indices2[i,j]=1
      }
    }
    ind<-apply(indices2,1,sum)
    for(i in 1:B) if(ind[i]==0) ID[i]=1
    n1<-sum(ID)
    v<-rep(0,n1)
    for(i in 1:B){
      if(ID[i]==1) {
        c1=c1+1
        v[c1]=i
      }
    }
    resi2<-matrix(0,n1,n)
    for(u in 1:n1){
      betas1<-betas[v[u],]
      yp<-x1%*%betas1
      resi<-(y-yp)
      resi2[u,]<-resi^2
    }
    residb<-apply(resi2,1,sum)
    resid2b[r]<-mean(residb)
  }
  e0<-mean(resid2b)/n
  e0.632<-0.368*APE+0.632*e0
  return(list(APE=APE,e0=e0,e0.632=e0.632))
}

RNGkind(sample.kind ="Rounding")
set.seed(semilla)
boot0.632(data = data.sig, B = 148, d = 1)
## $APE
## [1] 0.088063
## 
## $e0
## [1] 0.08948808
## 
## $e0.632
## [1] 0.08896365

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