Macroeconimia II
Sebastián Alonso Sosa Pérez
Modelos de Regresión
Creado: 13-12-2020
En el siguiente post se vera como podemos descargar datos directamente del BCRP usando el Web Scraping y posteriormente se usara los difrenetes algoritmos de regresión los cuales son:
- Regresión lineal simple.
- Regresión polinomial.
- Maquinas de soporte vectorial para regresión (SVR).
- Arboles de desicion.
- Bosques aleatorios.
Además se vera como corregir la autocorrelación en la parte final.
Web Scraping
Paquetes a utilizar
ipak <- function(pkg){
new.pkg <- pkg[!(pkg %in% installed.packages()[, "Package"])]
if (length(new.pkg))
install.packages(new.pkg, dependencies = TRUE)
sapply(pkg, require, character.only = TRUE)
}
packages <- c("tidyverse","data.table", "XML","httr","xts")
ipak(packages)
Analísis de Regresión
Regresión Simple
datos=datos
modelo_r<- lm(Exportaciones~Tipo_de_cambio,data = datos)
linea<- predict(modelo_r,datos)
a1<-ggplot(datos,mapping = aes(y=Exportaciones,x=Tipo_de_cambio))+
geom_point(color="red")+geom_line(mapping = aes(x=Tipo_de_cambio,
y=linea))+theme_minimal()+
xlab("Tipo de cambio")+labs(title ="Regresión lineal")
E_c_M_1= (Exportaciones-linea)^2 %>% mean()
a1

Regresión polinomial
modelo_r<- lm(Exportaciones~poly(Tipo_de_cambio,2),data = datos)
linea_1<- predict(modelo_r,datos)
a2<-ggplot(datos,mapping = aes(y=Exportaciones,x=Tipo_de_cambio))+
geom_point(color="red")+geom_line(mapping = aes(x=Tipo_de_cambio,
y=linea_1))+theme_minimal()+
xlab("Tipo de cambio")+labs(title ="Regresión polinomica")
E_c_M_2= (Exportaciones-linea_1)^2 %>% mean()
a2

Maquinas de soporte vectorial
library(e1071)
modelo_r<- svm(Exportaciones~Tipo_de_cambio,data = datos)
linea_2<- predict(modelo_r,datos)
a3<-ggplot(datos,mapping = aes(y=Exportaciones,x=Tipo_de_cambio))+
geom_point(color="red")+geom_line(mapping = aes(x=Tipo_de_cambio,
y=linea_2))+theme_minimal()+
xlab("Tipo de cambio")+labs(title ="Maquina de soporte vectorial")
E_c_M_3= (Exportaciones-linea_2)^2 %>% mean()
a3

Arboles de decisión
library(rpart)
modelo_r<- rpart(Exportaciones~Tipo_de_cambio,data = datos)
linea_3<- predict(modelo_r,datos)
a4<-ggplot(datos,mapping = aes(y=Exportaciones,x=Tipo_de_cambio))+
geom_point(color="red")+geom_line(mapping = aes(x=Tipo_de_cambio,
y=linea_3))+theme_minimal()+
xlab("Tipo de cambio")+labs(title ="Arboles de desición")
E_c_M_4= mean((Exportaciones-linea_3)^2)
a4

Bosques aleatorios
# library(randomForest)
modelo_r<- randomForest(Exportaciones~Tipo_de_cambio,data = datos)
linea_4<- predict(modelo_r,datos)
a5<-ggplot(datos,mapping = aes(y=Exportaciones,x=Tipo_de_cambio))+
geom_point(color="red")+geom_line(mapping = aes(x=Tipo_de_cambio,
y=linea_4))+theme_minimal()+
xlab("Tipo de cambio")+labs(title ="Bosques Aleatorios")
E_c_M_5= (Exportaciones-linea_4)^2 %>% mean()
a5

Elección del mejor modelo

Nota: El mejor modelo es en el cual se aplico el metódo de Random forest pues presente un menor \(R^2\).
Corrección de la autocorrelación
Para ver si presenta autocorrelación usamos el test de durwin watson que nos permite ver si se presenta esto. Para corregirla se presenta las siguientes funciones.
Uso de la prueba de autocorrelación
modelo_r<- lm(Exportaciones~Tipo_de_cambio,data = datos)
summary(modelo_r)
##
## Call:
## lm(formula = Exportaciones ~ Tipo_de_cambio, data = datos)
##
## Residuals:
## Min 1Q Median 3Q Max
## -536.5 -200.2 -24.1 190.2 1006.0
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 14778.8 949.9 15.56 <2e-16 ***
## Tipo_de_cambio -4021.5 277.7 -14.48 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 286.6 on 84 degrees of freedom
## Multiple R-squared: 0.714, Adjusted R-squared: 0.7106
## F-statistic: 209.7 on 1 and 84 DF, p-value: < 2.2e-16
b<- modelo_r$residuals
acf(b)


Resultado: podemos ver que de forma gráfica se presenta autocorrelación
Ahora aplicamos una prueba formal
##
## Durbin-Watson test
##
## data: modelo_r
## DW = 0.5182, p-value < 2.2e-16
## alternative hypothesis: true autocorrelation is greater than 0
Podemos ver que el DW calculado es mayor a lo permitido así que podemos deducir que si presenta autocorrelación

Corrección
Agregando un resago
library(dynlm)
modelo_a<- dynlm(Exportaciones~Tipo_de_cambio+L(Exportaciones))
summary(modelo_a)
## Warning in summary.lm(modelo_a): essentially perfect fit: summary may be
## unreliable
##
## Time series regression with "numeric" data:
## Start = 1, End = 86
##
## Call:
## dynlm(formula = Exportaciones ~ Tipo_de_cambio + L(Exportaciones))
##
## Residuals:
## Min 1Q Median 3Q Max
## -1.073e-13 -2.086e-14 -9.510e-15 -6.000e-17 7.833e-13
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 6.417e-12 5.901e-13 1.087e+01 <2e-16 ***
## Tipo_de_cambio -1.762e-12 1.637e-13 -1.076e+01 <2e-16 ***
## L(Exportaciones) 1.000e+00 3.440e-17 2.907e+16 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 9.038e-14 on 83 degrees of freedom
## Multiple R-squared: 1, Adjusted R-squared: 1
## F-statistic: 1.477e+33 on 2 and 83 DF, p-value: < 2.2e-16
Analizando los resultados:


##
## Durbin-Watson test
##
## data: modelo_a
## DW = 2.0655, p-value = 0.5445
## alternative hypothesis: true autocorrelation is greater than 0
Nota: Ahora este indicador se aproxima a 2 así que podemos decir que no presenta acutocrrelación.
Algortimo de ourcurt
## Loading required package: lmtest
cor<-cochrane.orcutt(modelo_r)
summary.orcutt(cor)
## Call:
## lm(formula = Exportaciones ~ Tipo_de_cambio, data = datos)
##
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1021.77 2150.97 0.475 0.6360
## Tipo_de_cambio 137.68 629.46 0.219 0.8274
##
## Residual standard error: 165.273 on 83 degrees of freedom
## Multiple R-squared: 6e-04 , Adjusted R-squared: -0.0115
## F-statistic: 0 on 1 and 83 DF, p-value: < 8.274e-01
##
## Durbin-Watson statistic
## (original): 0.51820 , p-value: 1.866e-17
## (transformed): 2.77543 , p-value: 9.999e-01
LS0tDQpvdXRwdXQ6IA0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgICNjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBoaWdobGlnaHQ6IHplbmJ1cm4NCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRoZW1lOiBmbGF0bHkNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogIHBkZl9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KLS0tDQoNCjxjZW50ZXI+DQohW10oZG93bmxvYWQuanBnKQ0KPC9jZW50ZXI+DQo8Y2VudGVyPg0KICAgIDxiPk1hY3JvZWNvbmltaWEgSUk8L2I+PGJyPg0KICAgIDxiPlNlYmFzdGnDoW4gQWxvbnNvIFNvc2EgUMOpcmV6PC9iPg0KPGJyPg0KPGgxPk1vZGVsb3MgZGUgUmVncmVzacOzbjwvaDE+DQo8L2NlbnRlcj4NCjxjZW50ZXI+DQo8aT5DcmVhZG86ICAgICAxMy0xMi0yMDIwIA0KPC9jZW50ZXI+DQoNCkVuIGVsIHNpZ3VpZW50ZSBwb3N0IHNlIHZlcmEgY29tbyBwb2RlbW9zIGRlc2NhcmdhciBkYXRvcyBkaXJlY3RhbWVudGUgZGVsICoqQkNSUCoqIHVzYW5kbyBlbCAqKldlYiBTY3JhcGluZyoqIHkgcG9zdGVyaW9ybWVudGUgc2UgdXNhcmEgbG9zIGRpZnJlbmV0ZXMgYWxnb3JpdG1vcyBkZSByZWdyZXNpw7NuIGxvcyBjdWFsZXMgc29uOiANCg0KKiBSZWdyZXNpw7NuIGxpbmVhbCBzaW1wbGUuDQoqIFJlZ3Jlc2nDs24gcG9saW5vbWlhbC4gDQoqIE1hcXVpbmFzIGRlIHNvcG9ydGUgdmVjdG9yaWFsIHBhcmEgcmVncmVzacOzbiAoU1ZSKS4NCiogQXJib2xlcyBkZSBkZXNpY2lvbi4NCiogQm9zcXVlcyBhbGVhdG9yaW9zLg0KDQpBZGVtw6FzIHNlIHZlcmEgY29tbyBjb3JyZWdpciBsYSBhdXRvY29ycmVsYWNpw7NuIGVuIGxhIHBhcnRlIGZpbmFsLiANCg0KIyBXZWIgU2NyYXBpbmcNCg0KIyMgUGFxdWV0ZXMgYSB1dGlsaXphciANCg0KYGBge3IsZXZhbD1GQUxTRX0NCmlwYWsgPC0gZnVuY3Rpb24ocGtnKXsNCiAgbmV3LnBrZyA8LSBwa2dbIShwa2cgJWluJSBpbnN0YWxsZWQucGFja2FnZXMoKVssICJQYWNrYWdlIl0pXQ0KICBpZiAobGVuZ3RoKG5ldy5wa2cpKSANCiAgICBpbnN0YWxsLnBhY2thZ2VzKG5ldy5wa2csIGRlcGVuZGVuY2llcyA9IFRSVUUpDQogIHNhcHBseShwa2csIHJlcXVpcmUsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkNCn0NCnBhY2thZ2VzIDwtIGMoInRpZHl2ZXJzZSIsImRhdGEudGFibGUiLCAiWE1MIiwiaHR0ciIsInh0cyIpDQppcGFrKHBhY2thZ2VzKQ0KYGBgDQoNCiMjIEZ1bmNpw7NuIGRlIGV4dHJhY2Npw7NuDQoNCmBgYHtyLGV2YWw9RkFMU0V9DQoNCmV4dHJhY2Npb248LSBmdW5jdGlvbihjb2RpZ289TlVMTCxzdGFydD1OVUxMLGVuZD1OVUxMKXsNCiAgdmVjdG9yPC0gdmVjdG9yKCkNCiAgZGF0b3M8LSBOVUxMDQogIGZvcihpIGluIDE6bGVuZ3RoKGNvZGlnbykpew0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4PC0gIHBhc3RlMCgiaHR0cHM6Ly9lc3RhZGlzdGljYXMuYmNycC5nb2IucGUvZXN0YWRpc3RpY2FzL3Nlcmllcy9hcGkvIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29kaWdvW2ldLCAiL3htbC8iLHN0YXJ0LCIvIixlbmQpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9ialhNTCA8LSBodHRyOjpHRVQoZXgpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTF9wYXJzZVhNTCA8LSB4bWxQYXJzZShPYmpYTUwpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBMX1hNTCA8LSB4bWxUb0xpc3QoTF9wYXJzZVhNTCkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdF9CQ1JQIDwtIGRhdGEudGFibGU6OmRhdGEudGFibGUoKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciAoYSBpbiAxOmxlbmd0aChMX1hNTCRwZXJpb2RzKSl7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHRfdGVtcCA8LSBkYXRhLnRhYmxlKA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZT0gTF9YTUwkcGVyaW9kc1tbYV1dJHYpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHRfQkNSUCA8LSByYmluZChkdF9CQ1JQLGR0X3RlbXApDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlY3RvcltpXTwtIGR0X0JDUlBbLHNlcmllOj1hcy5udW1lcmljKHNlcmllKV0gDQogIH0NCiAgZm9yKGkgaW4gIDE6IGxlbmd0aChjb2RpZ28pKXsNCiAgICBkYXRvczwtIGNiaW5kKGRhdG9zLHZlY3RvcltbaV1dKQ0KICB9DQogIGRhdG9zPC0gYXMuZGF0YS5mcmFtZShkYXRvcykNCiAgbmFtZXMoZGF0b3MpPC0gY29kaWdvDQogIHJldHVybihkYXRvcykNCiAgfQ0KYGBgDQoNCiMjIyBQcnVlYmEgZGUgbGEgZnVuY2nDs24gDQoNCmBgYHtyLGV2YWw9RkFMU0V9DQpkYXRvczwtZXh0cmFjY2lvbihjKCJQTjAxNDg4Qk0iLCJQTjAxMjEwUE0iICksIjIwMDAtMSIsIjIwMDctMiIpDQpuYW1lcyhkYXRvcyk8LSBjKCJFeHBvcnRhY2lvbmVzIiwiVGlwb19kZV9jYW1iaW8iKQ0KYXR0YWNoKGRhdG9zKQ0KYGBgDQoNCiMjIyMgUmVwcmVzZW5ydGFjacOzbiBkZSBsb3MgcmVzdWx0YWRvcyANCg0KYGBge3IsZWNobz1GQUxTRSx3YXJuaW5nPVRSVUUsbWVzc2FnZT1UUlVFLGluY2x1ZGU9RkFMU0V9DQppcGFrIDwtIGZ1bmN0aW9uKHBrZyl7DQogIG5ldy5wa2cgPC0gcGtnWyEocGtnICVpbiUgaW5zdGFsbGVkLnBhY2thZ2VzKClbLCAiUGFja2FnZSJdKV0NCiAgaWYgKGxlbmd0aChuZXcucGtnKSkgDQogICAgaW5zdGFsbC5wYWNrYWdlcyhuZXcucGtnLCBkZXBlbmRlbmNpZXMgPSBUUlVFKQ0KICBzYXBwbHkocGtnLCByZXF1aXJlLCBjaGFyYWN0ZXIub25seSA9IFRSVUUpDQp9DQpwYWNrYWdlcyA8LSBjKCJ0aWR5dmVyc2UiLCJkYXRhLnRhYmxlIiwgIlhNTCIsImh0dHIiLCJ4dHMiKQ0KaXBhayhwYWNrYWdlcykNCmV4dHJhY2Npb248LSBmdW5jdGlvbihjb2RpZ289TlVMTCxzdGFydD1OVUxMLGVuZD1OVUxMKXsNCiAgdmVjdG9yPC0gdmVjdG9yKCkNCiAgZGF0b3M8LSBOVUxMDQogIGZvcihpIGluIDE6bGVuZ3RoKGNvZGlnbykpew0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4PC0gIHBhc3RlMCgiaHR0cHM6Ly9lc3RhZGlzdGljYXMuYmNycC5nb2IucGUvZXN0YWRpc3RpY2FzL3Nlcmllcy9hcGkvIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29kaWdvW2ldLCAiL3htbC8iLHN0YXJ0LCIvIixlbmQpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9ialhNTCA8LSBodHRyOjpHRVQoZXgpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTF9wYXJzZVhNTCA8LSB4bWxQYXJzZShPYmpYTUwpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBMX1hNTCA8LSB4bWxUb0xpc3QoTF9wYXJzZVhNTCkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdF9CQ1JQIDwtIGRhdGEudGFibGU6OmRhdGEudGFibGUoKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciAoYSBpbiAxOmxlbmd0aChMX1hNTCRwZXJpb2RzKSl7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHRfdGVtcCA8LSBkYXRhLnRhYmxlKA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZT0gTF9YTUwkcGVyaW9kc1tbYV1dJHYpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHRfQkNSUCA8LSByYmluZChkdF9CQ1JQLGR0X3RlbXApDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlY3RvcltpXTwtIGR0X0JDUlBbLHNlcmllOj1hcy5udW1lcmljKHNlcmllKV0gDQogIH0NCiAgZm9yKGkgaW4gIDE6IGxlbmd0aChjb2RpZ28pKXsNCiAgICBkYXRvczwtIGNiaW5kKGRhdG9zLHZlY3RvcltbaV1dKQ0KICB9DQogIGRhdG9zPC0gYXMuZGF0YS5mcmFtZShkYXRvcykNCiAgbmFtZXMoZGF0b3MpPC0gY29kaWdvDQogIHJldHVybihkYXRvcykNCiAgfQ0KZGF0b3M8LWV4dHJhY2Npb24oYygiUE4wMTQ4OEJNIiwiUE4wMTIxMFBNIiApLCIyMDAwLTEiLCIyMDA3LTIiKQ0KbmFtZXMoZGF0b3MpPC0gYygiRXhwb3J0YWNpb25lcyIsIlRpcG9fZGVfY2FtYmlvIikNCmF0dGFjaChkYXRvcykNCg0KYGBgDQpgYGB7cn0NCmRhdG9zICAlPiVyb3VuZChkaWdpdHMgPSAyKSAlPiUgRFQ6OmRhdGF0YWJsZSgpDQpgYGANCg0KDQojIEFuYWzDrXNpcyBkZSBSZWdyZXNpw7NuIA0KDQojIyBSZWdyZXNpw7NuIFNpbXBsZSANCg0KDQpgYGB7cixlY2hvPUZBTFNFLHdhcm5pbmc9VFJVRSxpbmNsdWRlPUZBTFNFfQ0KaXBhayA8LSBmdW5jdGlvbihwa2cpew0KICBuZXcucGtnIDwtIHBrZ1shKHBrZyAlaW4lIGluc3RhbGxlZC5wYWNrYWdlcygpWywgIlBhY2thZ2UiXSldDQogIGlmIChsZW5ndGgobmV3LnBrZykpIA0KICAgIGluc3RhbGwucGFja2FnZXMobmV3LnBrZywgZGVwZW5kZW5jaWVzID0gVFJVRSkNCiAgc2FwcGx5KHBrZywgcmVxdWlyZSwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKQ0KfQ0KcGFja2FnZXMgPC0gYygidGlkeXZlcnNlIiwiZGF0YS50YWJsZSIsICJYTUwiLCJodHRyIiwieHRzIikNCmlwYWsocGFja2FnZXMpDQpleHRyYWNjaW9uPC0gZnVuY3Rpb24oY29kaWdvPU5VTEwsc3RhcnQ9TlVMTCxlbmQ9TlVMTCl7DQogIHZlY3RvcjwtIHZlY3RvcigpDQogIGRhdG9zPC0gTlVMTA0KICBmb3IoaSBpbiAxOmxlbmd0aChjb2RpZ28pKXsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleDwtICBwYXN0ZTAoImh0dHBzOi8vZXN0YWRpc3RpY2FzLmJjcnAuZ29iLnBlL2VzdGFkaXN0aWNhcy9zZXJpZXMvYXBpLyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvZGlnb1tpXSwgIi94bWwvIixzdGFydCwiLyIsZW5kKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBPYmpYTUwgPC0gaHR0cjo6R0VUKGV4KQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIExfcGFyc2VYTUwgPC0geG1sUGFyc2UoT2JqWE1MKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTF9YTUwgPC0geG1sVG9MaXN0KExfcGFyc2VYTUwpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHRfQkNSUCA8LSBkYXRhLnRhYmxlOjpkYXRhLnRhYmxlKCkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3IgKGEgaW4gMTpsZW5ndGgoTF9YTUwkcGVyaW9kcykpew0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0X3RlbXAgPC0gZGF0YS50YWJsZSgNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWU9IExfWE1MJHBlcmlvZHNbW2FdXSR2KQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0X0JDUlAgPC0gcmJpbmQoZHRfQkNSUCxkdF90ZW1wKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZWN0b3JbaV08LSBkdF9CQ1JQWyxzZXJpZTo9YXMubnVtZXJpYyhzZXJpZSldIA0KICB9DQogIGZvcihpIGluICAxOiBsZW5ndGgoY29kaWdvKSl7DQogICAgZGF0b3M8LSBjYmluZChkYXRvcyx2ZWN0b3JbW2ldXSkNCiAgfQ0KICBkYXRvczwtIGFzLmRhdGEuZnJhbWUoZGF0b3MpDQogIG5hbWVzKGRhdG9zKTwtIGNvZGlnbw0KICByZXR1cm4oZGF0b3MpDQogIH0NCmRhdG9zPC1leHRyYWNjaW9uKGMoIlBOMDE0ODhCTSIsIlBOMDEyMTBQTSIgKSwiMjAwMC0xIiwiMjAwNy0yIikNCm5hbWVzKGRhdG9zKTwtIGMoIkV4cG9ydGFjaW9uZXMiLCJUaXBvX2RlX2NhbWJpbyIpDQphdHRhY2goZGF0b3MpDQpgYGANCg0KYGBge3J9DQpkYXRvcz1kYXRvcw0KbW9kZWxvX3I8LSBsbShFeHBvcnRhY2lvbmVzflRpcG9fZGVfY2FtYmlvLGRhdGEgPSBkYXRvcykNCmxpbmVhPC0gcHJlZGljdChtb2RlbG9fcixkYXRvcykgICAgDQphMTwtZ2dwbG90KGRhdG9zLG1hcHBpbmcgPSBhZXMoeT1FeHBvcnRhY2lvbmVzLHg9VGlwb19kZV9jYW1iaW8pKSsNCiAgICAgIGdlb21fcG9pbnQoY29sb3I9InJlZCIpK2dlb21fbGluZShtYXBwaW5nID0gYWVzKHg9VGlwb19kZV9jYW1iaW8sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PWxpbmVhKSkrdGhlbWVfbWluaW1hbCgpKw0KICAgeGxhYigiVGlwbyBkZSBjYW1iaW8iKStsYWJzKHRpdGxlID0iUmVncmVzacOzbiBsaW5lYWwiKQ0KRV9jX01fMT0gKEV4cG9ydGFjaW9uZXMtbGluZWEpXjIgJT4lIG1lYW4oKQ0KYTENCmBgYA0KDQoNCiMjIFJlZ3Jlc2nDs24gcG9saW5vbWlhbA0KDQpgYGB7cn0NCm1vZGVsb19yPC0gbG0oRXhwb3J0YWNpb25lc35wb2x5KFRpcG9fZGVfY2FtYmlvLDIpLGRhdGEgPSBkYXRvcykNCiAgICBsaW5lYV8xPC0gcHJlZGljdChtb2RlbG9fcixkYXRvcykgICAgDQogICAgYTI8LWdncGxvdChkYXRvcyxtYXBwaW5nID0gYWVzKHk9RXhwb3J0YWNpb25lcyx4PVRpcG9fZGVfY2FtYmlvKSkrDQogICAgICBnZW9tX3BvaW50KGNvbG9yPSJyZWQiKStnZW9tX2xpbmUobWFwcGluZyA9IGFlcyh4PVRpcG9fZGVfY2FtYmlvLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1saW5lYV8xKSkrdGhlbWVfbWluaW1hbCgpKw0KICAgICAgeGxhYigiVGlwbyBkZSBjYW1iaW8iKStsYWJzKHRpdGxlID0iUmVncmVzacOzbiBwb2xpbm9taWNhIikNCiAgICBFX2NfTV8yPSAoRXhwb3J0YWNpb25lcy1saW5lYV8xKV4yICU+JSBtZWFuKCkNCmEyICAgIA0KYGBgDQoNCiMjIE1hcXVpbmFzIGRlIHNvcG9ydGUgdmVjdG9yaWFsIA0KDQpgYGB7cn0NCmxpYnJhcnkoZTEwNzEpDQogICAgbW9kZWxvX3I8LSBzdm0oRXhwb3J0YWNpb25lc35UaXBvX2RlX2NhbWJpbyxkYXRhID0gZGF0b3MpDQogICAgbGluZWFfMjwtIHByZWRpY3QobW9kZWxvX3IsZGF0b3MpICAgIA0KICAgIGEzPC1nZ3Bsb3QoZGF0b3MsbWFwcGluZyA9IGFlcyh5PUV4cG9ydGFjaW9uZXMseD1UaXBvX2RlX2NhbWJpbykpKw0KICAgICAgZ2VvbV9wb2ludChjb2xvcj0icmVkIikrZ2VvbV9saW5lKG1hcHBpbmcgPSBhZXMoeD1UaXBvX2RlX2NhbWJpbywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9bGluZWFfMikpK3RoZW1lX21pbmltYWwoKSsNCiAgICB4bGFiKCJUaXBvIGRlIGNhbWJpbyIpK2xhYnModGl0bGUgPSJNYXF1aW5hIGRlIHNvcG9ydGUgdmVjdG9yaWFsIikNCiAgICANCiAgICBFX2NfTV8zPSAoRXhwb3J0YWNpb25lcy1saW5lYV8yKV4yICU+JSBtZWFuKCkNCmEzDQpgYGANCg0KIyMgQXJib2xlcyBkZSBkZWNpc2nDs24gDQoNCmBgYHtyfQ0KbGlicmFyeShycGFydCkNCiAgICBtb2RlbG9fcjwtIHJwYXJ0KEV4cG9ydGFjaW9uZXN+VGlwb19kZV9jYW1iaW8sZGF0YSA9IGRhdG9zKQ0KICAgIGxpbmVhXzM8LSBwcmVkaWN0KG1vZGVsb19yLGRhdG9zKSAgICANCiAgICBhNDwtZ2dwbG90KGRhdG9zLG1hcHBpbmcgPSBhZXMoeT1FeHBvcnRhY2lvbmVzLHg9VGlwb19kZV9jYW1iaW8pKSsNCiAgICAgIGdlb21fcG9pbnQoY29sb3I9InJlZCIpK2dlb21fbGluZShtYXBwaW5nID0gYWVzKHg9VGlwb19kZV9jYW1iaW8sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PWxpbmVhXzMpKSt0aGVtZV9taW5pbWFsKCkrDQogICAgICB4bGFiKCJUaXBvIGRlIGNhbWJpbyIpK2xhYnModGl0bGUgPSJBcmJvbGVzIGRlIGRlc2ljacOzbiIpDQogICAgRV9jX01fND0gbWVhbigoRXhwb3J0YWNpb25lcy1saW5lYV8zKV4yKQ0KICBhNA0KYGBgDQoNCiMjIEJvc3F1ZXMgYWxlYXRvcmlvcw0KDQpgYGB7cixpbmNsdWRlPUZBTFNFfQ0KbGlicmFyeShyYW5kb21Gb3Jlc3QpDQpgYGANCg0KDQpgYGB7cixtZXNzYWdlPVRSVUV9DQojIGxpYnJhcnkocmFuZG9tRm9yZXN0KQ0KICAgIG1vZGVsb19yPC0gcmFuZG9tRm9yZXN0KEV4cG9ydGFjaW9uZXN+VGlwb19kZV9jYW1iaW8sZGF0YSA9IGRhdG9zKQ0KICAgIGxpbmVhXzQ8LSBwcmVkaWN0KG1vZGVsb19yLGRhdG9zKSAgICANCiAgICBhNTwtZ2dwbG90KGRhdG9zLG1hcHBpbmcgPSBhZXMoeT1FeHBvcnRhY2lvbmVzLHg9VGlwb19kZV9jYW1iaW8pKSsNCiAgICAgIGdlb21fcG9pbnQoY29sb3I9InJlZCIpK2dlb21fbGluZShtYXBwaW5nID0gYWVzKHg9VGlwb19kZV9jYW1iaW8sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PWxpbmVhXzQpKSt0aGVtZV9taW5pbWFsKCkrDQogICAgICB4bGFiKCJUaXBvIGRlIGNhbWJpbyIpK2xhYnModGl0bGUgPSJCb3NxdWVzIEFsZWF0b3Jpb3MiKQ0KICAgIEVfY19NXzU9IChFeHBvcnRhY2lvbmVzLWxpbmVhXzQpXjIgJT4lIG1lYW4oKSAgICANCmE1DQpgYGANCg0KIyMgRWxlY2Npw7NuIGRlbCBtZWpvciBtb2RlbG8gDQpgYGB7cixpbmNsdWRlPUZBTFNFfQ0KcmVxdWlyZShncmlkRXh0cmEpDQoNCmBgYA0KDQoNCmBgYHtyLGVjaG89RkFMU0UsbWVzc2FnZT1UUlVFLHdhcm5pbmc9VFJVRX0NCmVycm9yZXM8LSBkYXRhLmZyYW1lKGVycm9yZXM9YyhFX2NfTV8xLEVfY19NXzIsRV9jX01fMyxFX2NfTV80LEVfY19NXzUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGV0aXF1ZXRhcz1jKCJyX2wiLCJyX3AiLCJzdm0iLCJ0cmVlIiwiZm9yZXN0IikpICAgDQphPC1nZ3Bsb3QoZXJyb3JlcyxtYXBwaW5nID0gYWVzKHg9MTo1LGVycm9yZXMsY29sb3I9ZXRpcXVldGFzKSkrZ2VvbV9wb2ludChzaXplPTQpDQphNjwtYSArIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImhvbmV5ZGV3MyIsIA0KICAgICAgICBsaW5ldHlwZSA9ICJkYXNoZWQiKSwgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiZG9kZ2VyYmx1ZTEiKSwgDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoY29sb3VyID0gImJsYWNrIiksIA0KICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEsIA0KICAgICAgICAgICAgZmFjZSA9ICJib2xkLml0YWxpYyIsIGNvbG91ciA9ICJibHVlNCIpLCANCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgDQogICAgICAgICAgICBmYWNlID0gImJvbGQiLCBjb2xvdXIgPSAiYnJvd24iKSwgDQogICAgICAgIGxlZ2VuZC5rZXkgPSBlbGVtZW50X3JlY3QobGluZXR5cGUgPSAiZG90dGVkIiksIA0KICAgICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChzaXplID0gMS4yLCANCiAgICAgICAgICAgIGxpbmV0eXBlID0gInNvbGlkIiksIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCANCiAgICAgICAgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIikgK2xhYnModGl0bGUgPSAiRWxlY2Npw7NuIGRlbCBtZWpvciBtb2RlbG8iLCANCiAgICAgICAgeCA9IE5VTEwsIGNvbG91ciA9ICJFcnJvcmVzIGN1YWRyYXRpY29zIikrdGhlbWVfbWluaW1hbCgpDQpncmlkLmFycmFuZ2UoYTEsYTIsYTMsYTQsYTUsYTYpDQpgYGANCg0KPiBOb3RhOiBFbCBtZWpvciBtb2RlbG8gZXMgZW4gZWwgY3VhbCBzZSBhcGxpY28gZWwgbWV0w7NkbyBkZSBSYW5kb20gZm9yZXN0IHB1ZXMgcHJlc2VudGUgdW4gbWVub3IgJFJeMiQuICANCg0KIyBDb3JyZWNjacOzbiBkZSBsYSBhdXRvY29ycmVsYWNpw7NuDQoNClBhcmEgdmVyIHNpIHByZXNlbnRhICoqYXV0b2NvcnJlbGFjacOzbioqIHVzYW1vcyBlbCB0ZXN0IGRlIGR1cndpbiB3YXRzb24gcXVlIG5vcyBwZXJtaXRlIHZlciBzaSBzZSBwcmVzZW50YSBlc3RvLiBQYXJhIGNvcnJlZ2lybGEgc2UgcHJlc2VudGEgbGFzIHNpZ3VpZW50ZXMgZnVuY2lvbmVzLiANCg0KYGBge3IsZWNobz1GQUxTRSx3YXJuaW5nPVRSVUUsaW5jbHVkZT1GQUxTRX0NCmlwYWsgPC0gZnVuY3Rpb24ocGtnKXsNCiAgbmV3LnBrZyA8LSBwa2dbIShwa2cgJWluJSBpbnN0YWxsZWQucGFja2FnZXMoKVssICJQYWNrYWdlIl0pXQ0KICBpZiAobGVuZ3RoKG5ldy5wa2cpKSANCiAgICBpbnN0YWxsLnBhY2thZ2VzKG5ldy5wa2csIGRlcGVuZGVuY2llcyA9IFRSVUUpDQogIHNhcHBseShwa2csIHJlcXVpcmUsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkNCn0NCnBhY2thZ2VzIDwtIGMoInRpZHl2ZXJzZSIsImRhdGEudGFibGUiLCAiWE1MIiwiaHR0ciIsInh0cyIpDQppcGFrKHBhY2thZ2VzKQ0KZXh0cmFjY2lvbjwtIGZ1bmN0aW9uKGNvZGlnbz1OVUxMLHN0YXJ0PU5VTEwsZW5kPU5VTEwpew0KICB2ZWN0b3I8LSB2ZWN0b3IoKQ0KICBkYXRvczwtIE5VTEwNCiAgZm9yKGkgaW4gMTpsZW5ndGgoY29kaWdvKSl7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXg8LSAgcGFzdGUwKCJodHRwczovL2VzdGFkaXN0aWNhcy5iY3JwLmdvYi5wZS9lc3RhZGlzdGljYXMvc2VyaWVzL2FwaS8iLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2RpZ29baV0sICIveG1sLyIsc3RhcnQsIi8iLGVuZCkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgT2JqWE1MIDwtIGh0dHI6OkdFVChleCkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBMX3BhcnNlWE1MIDwtIHhtbFBhcnNlKE9ialhNTCkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIExfWE1MIDwtIHhtbFRvTGlzdChMX3BhcnNlWE1MKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0X0JDUlAgPC0gZGF0YS50YWJsZTo6ZGF0YS50YWJsZSgpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yIChhIGluIDE6bGVuZ3RoKExfWE1MJHBlcmlvZHMpKXsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdF90ZW1wIDwtIGRhdGEudGFibGUoDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllPSBMX1hNTCRwZXJpb2RzW1thXV0kdikNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdF9CQ1JQIDwtIHJiaW5kKGR0X0JDUlAsZHRfdGVtcCkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVjdG9yW2ldPC0gZHRfQkNSUFssc2VyaWU6PWFzLm51bWVyaWMoc2VyaWUpXSANCiAgfQ0KICBmb3IoaSBpbiAgMTogbGVuZ3RoKGNvZGlnbykpew0KICAgIGRhdG9zPC0gY2JpbmQoZGF0b3MsdmVjdG9yW1tpXV0pDQogIH0NCiAgZGF0b3M8LSBhcy5kYXRhLmZyYW1lKGRhdG9zKQ0KICBuYW1lcyhkYXRvcyk8LSBjb2RpZ28NCiAgcmV0dXJuKGRhdG9zKQ0KICB9DQpkYXRvczwtZXh0cmFjY2lvbihjKCJQTjAxNDg4Qk0iLCJQTjAxMjEwUE0iICksIjIwMDAtMSIsIjIwMDctMiIpDQpuYW1lcyhkYXRvcyk8LSBjKCJFeHBvcnRhY2lvbmVzIiwiVGlwb19kZV9jYW1iaW8iKQ0KYXR0YWNoKGRhdG9zKQ0KYGBgDQoNCiMjIFVzbyBkZSBsYSBwcnVlYmEgZGUgYXV0b2NvcnJlbGFjacOzbiANCg0KYGBge3J9DQptb2RlbG9fcjwtIGxtKEV4cG9ydGFjaW9uZXN+VGlwb19kZV9jYW1iaW8sZGF0YSA9IGRhdG9zKQ0Kc3VtbWFyeShtb2RlbG9fcikNCmI8LSBtb2RlbG9fciRyZXNpZHVhbHMNCmFjZihiKQ0KcGFjZihiKQ0KYGBgDQoNCj4gUmVzdWx0YWRvOiBwb2RlbW9zIHZlciBxdWUgZGUgZm9ybWEgZ3LDoWZpY2Egc2UgcHJlc2VudGEgYXV0b2NvcnJlbGFjacOzbiANCg0KQWhvcmEgYXBsaWNhbW9zIHVuYSBwcnVlYmEgZm9ybWFsIA0KDQpgYGB7cn0NCmxtdGVzdDo6ZHd0ZXN0KG1vZGVsb19yKSANCmBgYA0KDQpQb2RlbW9zIHZlciBxdWUgZWwgKipEVyoqIGNhbGN1bGFkbyBlcyBtYXlvciBhIGxvIHBlcm1pdGlkbyBhc8OtIHF1ZSBwb2RlbW9zIGRlZHVjaXIgcXVlIHNpIHByZXNlbnRhIGF1dG9jb3JyZWxhY2nDs24gDQoNCiFbXShhYWFhYWEuanBnKQ0KDQojIyBDb3JyZWNjacOzbiANCg0KIyMjIEFncmVnYW5kbyB1biByZXNhZ28gDQoNCmBgYHtyfQ0KbGlicmFyeShkeW5sbSkgICAgICANCm1vZGVsb19hPC0gZHlubG0oRXhwb3J0YWNpb25lc35UaXBvX2RlX2NhbWJpbytMKEV4cG9ydGFjaW9uZXMpKSAgICAgIA0Kc3VtbWFyeShtb2RlbG9fYSkNCmM8LSBtb2RlbG9fYSRyZXNpZHVhbHMNCmBgYA0KDQpBbmFsaXphbmRvIGxvcyByZXN1bHRhZG9zOg0KDQpgYGB7cn0NCmFjZihjKQ0KcGFjZihjKQ0KbG10ZXN0Ojpkd3Rlc3QobW9kZWxvX2EpIA0KYGBgDQoNCj4gTm90YTogQWhvcmEgZXN0ZSBpbmRpY2Fkb3Igc2UgYXByb3hpbWEgYSAyIGFzw60gcXVlIHBvZGVtb3MgZGVjaXIgcXVlIG5vIHByZXNlbnRhIGFjdXRvY3JyZWxhY2nDs24uIA0KDQojIyMgQWxnb3J0aW1vIGRlIG91cmN1cnQNCg0KYGBge3J9DQpsaWJyYXJ5KG9yY3V0dCkgICAgICANCmNvcjwtY29jaHJhbmUub3JjdXR0KG1vZGVsb19yKQ0Kc3VtbWFyeS5vcmN1dHQoY29yKQ0KYGBgDQoNCg==