Descargamos los datos, la mayorÃa están cargadas en GitHub:
library(downloader)
library(dplyr)
Attaching package: ‘dplyr’
The following objects are masked from ‘package:stats’:
filter, lag
The following objects are masked from ‘package:base’:
intersect, setdiff, setequal, union
library(readr)
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
method from
print.tbl_lazy
print.tbl_sql
── Attaching packages ─────────────────────────────────────────────────────────────── tidyverse 1.3.2 ──
✔ ggplot2 3.4.0 ✔ purrr 1.0.1
✔ tibble 3.1.8 ✔ stringr 1.5.0
✔ tidyr 1.3.0 ✔ forcats 1.0.0
── Conflicts ────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
library(ggplot2)
url<-"https://raw.githubusercontent.com/carloscarrillol/ENIGH/main/agro.csv"
name<-basename(url)
if(!file.exists(name))download(url,name)
agro<-read.csv(name)
url<-"https://raw.githubusercontent.com/carloscarrillol/ENIGH/main/agroconsumo.csv"
name<-basename(url)
if(!file.exists(name))download(url,name)
agro_consumo<-read.csv(name)
url<-"https://raw.githubusercontent.com/carloscarrillol/ENIGH/main/agrogasto.csv"
name<-basename(url)
if(!file.exists(name))download(url,name)
agro_gasto<-read.csv(name)
url<-"https://raw.githubusercontent.com/carloscarrillol/ENIGH/main/agroproductos.csv"
name<-basename(url)
if(!file.exists(name))download(url,name)
agro_prod<-read.csv(name)
url<-"https://raw.githubusercontent.com/carloscarrillol/ENIGH/main/erogaciones.csv"
name<-basename(url)
if(!file.exists(name))download(url,name)
eroga<-read.csv(name)
url<-"https://raw.githubusercontent.com/carloscarrillol/ENIGH/main/gastotarjetas.csv"
name<-basename(url)
if(!file.exists(name))download(url,name)
gastos_tarj<-read.csv(name)
url<-"https://raw.githubusercontent.com/carloscarrillol/ENIGH/main/ingresos_jcf.csv"
name<-basename(url)
if(!file.exists(name))download(url,name)
ingresos_jcf<-read.csv(name)
url<-"https://raw.githubusercontent.com/carloscarrillol/ENIGH/main/noagro.csv"
name<-basename(url)
if(!file.exists(name))download(url,name)
no_agro<-read.csv(name)
url<-"https://raw.githubusercontent.com/carloscarrillol/ENIGH/main/noagroimportes.csv"
name<-basename(url)
if(!file.exists(name))download(url,name)
no_agro_importes<-read.csv(name)
url<-"https://raw.githubusercontent.com/carloscarrillol/ENIGH/main/trabajos.csv"
name<-basename(url)
if(!file.exists(name))download(url,name)
trabajos<-read.csv(name)
url<-"https://raw.githubusercontent.com/carloscarrillol/ENIGH/main/viviendas.csv"
name<-basename(url)
if(!file.exists(name))download(url,name)
viviendas<-read.csv(name)
#Los añadà desde mi computadora porque están demasiado pesados para subirlos a Git
gastos_per<-read.csv("gastospersona.csv")
con_hogar<-read.csv("concentradohogar.csv")
hogares<-read.csv("hogares.csv")
ingresos<-read.csv("ingresos.csv")
poblacion<-read.csv("poblacion.csv")
gastos_hogar<-read.csv("gastoshogar.csv")
Para el primer indicador de pobreza vamos a identificar de manera genérica, para la población rural, de manera siguiente: \[\textit{Indice de Pobreza por ingreso}_{i}=\frac{\textit{Valor del ingreso}_{i}+\textit{Valor del apoyo}_{ji}}{\textit{Valor del consumo}_{i}+\textit{Valor de los gastos}_{i}}\] AGRO
Gasto y Consumo:
indice<-select(agro_consumo,folioviv)
indice_Agro_Gasto<-semi_join(agro_gasto,indice,by="folioviv")
Indice_Agro_Gasto_Agregado <- aggregate(gasto ~ folioviv, data = indice_Agro_Gasto, sum)
indice_Agro_Consumo<-semi_join(agro_consumo,indice,by="folioviv")
Indice_Agro_Consumo_Agregado <- aggregate(valestim ~ folioviv, data = indice_Agro_Consumo, sum)
Indice_Agro_Pas<-merge(Indice_Agro_Consumo_Agregado,Indice_Agro_Gasto_Agregado, by="folioviv",all=T)
Indice_Agro_Pas$gasto<-ifelse(is.na(Indice_Agro_Pas$gasto),0,Indice_Agro_Pas$gasto)
#--------------
Gasto_Hog<-semi_join(gastos_hogar, indice, by="folioviv")
Gasto_Hog$gasto_tri<-ifelse(is.na(Gasto_Hog$gasto_tri),0,Gasto_Hog$gasto_tri)
Gasto_Hog<-aggregate(gasto_tri ~ folioviv, data = Gasto_Hog, sum)
Gasto_Hog$gasto_tri<-Gasto_Hog$gasto_tri/3
Indice_Agro_Pas<-merge(Gasto_Hog, Indice_Agro_Pas, by="folioviv", all=T)
#--------------
n<-nrow(Indice_Agro_Pas)
suma<-matrix(rep(0,n),ncol=1)
for(i in 1:n){
suma[i]=Indice_Agro_Pas$valestim[i]+Indice_Agro_Pas$gasto[i]+Indice_Agro_Pas$gasto_tri[i]
suma
}
Indice_Agro_Pas<-data.frame(Indice_Agro_Pas,suma)
Ingresos:
Indice_Agro_Prod<-semi_join(agro_prod,indice, by="folioviv")
Indice_Agro_Prod_Agregado<-aggregate(valor ~ folioviv, data = Indice_Agro_Prod, sum)
Indice_Agro<-semi_join(agro,indice,by="folioviv")
Indice_Agro_Apoyo<-filter(Indice_Agro,apoyo==1|proagro>=1|
progan>=1|nvo_apoyo==1)
Indice_Agro_Apoyo$apoyo_1<-ifelse(is.na(Indice_Agro_Apoyo$apoyo_1),0,Indice_Agro_Apoyo$apoyo_1)
Indice_Agro_Apoyo$apoyo_2<-ifelse(is.na(Indice_Agro_Apoyo$apoyo_2),0,Indice_Agro_Apoyo$apoyo_2)
Indice_Agro_Apoyo$apoyo_3<-ifelse(is.na(Indice_Agro_Apoyo$apoyo_3),0,Indice_Agro_Apoyo$apoyo_3)
Indice_Agro_Apoyo$apoyo_4<-ifelse(is.na(Indice_Agro_Apoyo$apoyo_4),0,Indice_Agro_Apoyo$apoyo_4)
Indice_Agro_Apoyo$apoyo_5<-ifelse(is.na(Indice_Agro_Apoyo$apoyo_5),0,Indice_Agro_Apoyo$apoyo_5)
Indice_Agro_Apoyo$apoyo_6<-ifelse(is.na(Indice_Agro_Apoyo$apoyo_6),0,Indice_Agro_Apoyo$apoyo_6)
Indice_Agro_Apoyo$apoyo_7<-ifelse(is.na(Indice_Agro_Apoyo$apoyo_7),0,Indice_Agro_Apoyo$apoyo_7)
Indice_Agro_Apoyo$apoyo_8<-ifelse(is.na(Indice_Agro_Apoyo$apoyo_8),0,Indice_Agro_Apoyo$apoyo_8)
Indice_Agro_Apoyo$proagro<-ifelse(is.na(Indice_Agro_Apoyo$proagro),0,Indice_Agro_Apoyo$proagro)
Indice_Agro_Apoyo$nvo_cant1<-ifelse(is.na(Indice_Agro_Apoyo$nvo_cant1),0,Indice_Agro_Apoyo$nvo_cant1)
Indice_Agro_Apoyo$nvo_cant2<-ifelse(is.na(Indice_Agro_Apoyo$nvo_cant2),0,Indice_Agro_Apoyo$nvo_cant2)
Indice_Agro_Apoyo$nvo_cant3<-ifelse(is.na(Indice_Agro_Apoyo$nvo_cant3),0,Indice_Agro_Apoyo$nvo_cant3)
Indice_Agro_Apoyo$progan<-ifelse(is.na(Indice_Agro_Apoyo$progan),0,Indice_Agro_Apoyo$progan)
Indice_Agro_Apoyo<-select(Indice_Agro_Apoyo,folioviv,apoyo_1,apoyo_2,
apoyo_3,apoyo_4,apoyo_5,apoyo_6,apoyo_7,apoyo_8,
nvo_cant1,nvo_cant2,nvo_cant3,proagro,progan)
n<-nrow(Indice_Agro_Apoyo)
apoyo<-matrix(rep(0,n),ncol=1)
for(i in 1:n){
apoyo[i]=sum(Indice_Agro_Apoyo[i,])-Indice_Agro_Apoyo$folioviv[i]
apoyo
}
Indice_Agro_Apoyo<-data.frame(Indice_Agro_Apoyo,apoyo)
Indice_Agro_Act<-merge(Indice_Agro_Prod_Agregado,Indice_Agro_Apoyo, by="folioviv",all=T)
Indice_Agro_Act$apoyo_1<-ifelse(is.na(Indice_Agro_Act$apoyo_1),0,Indice_Agro_Act$apoyo_1)
Indice_Agro_Act$apoyo_2<-ifelse(is.na(Indice_Agro_Act$apoyo_2),0,Indice_Agro_Act$apoyo_2)
Indice_Agro_Act$apoyo_3<-ifelse(is.na(Indice_Agro_Act$apoyo_3),0,Indice_Agro_Act$apoyo_3)
Indice_Agro_Act$apoyo_4<-ifelse(is.na(Indice_Agro_Act$apoyo_4),0,Indice_Agro_Act$apoyo_4)
Indice_Agro_Act$apoyo_5<-ifelse(is.na(Indice_Agro_Act$apoyo_5),0,Indice_Agro_Act$apoyo_5)
Indice_Agro_Act$apoyo_6<-ifelse(is.na(Indice_Agro_Act$apoyo_6),0,Indice_Agro_Act$apoyo_6)
Indice_Agro_Act$apoyo_7<-ifelse(is.na(Indice_Agro_Act$apoyo_7),0,Indice_Agro_Act$apoyo_7)
Indice_Agro_Act$apoyo_8<-ifelse(is.na(Indice_Agro_Act$apoyo_8),0,Indice_Agro_Act$apoyo_8)
Indice_Agro_Act$nvo_cant1<-ifelse(is.na(Indice_Agro_Act$nvo_cant1),0,Indice_Agro_Act$nvo_cant1)
Indice_Agro_Act$nvo_cant2<-ifelse(is.na(Indice_Agro_Act$nvo_cant2),0,Indice_Agro_Act$nvo_cant2)
Indice_Agro_Act$nvo_cant3<-ifelse(is.na(Indice_Agro_Act$nvo_cant3),0,Indice_Agro_Act$nvo_cant3)
Indice_Agro_Act$proagro<-ifelse(is.na(Indice_Agro_Act$proagro),0,Indice_Agro_Act$proagro)
Indice_Agro_Act$progan<-ifelse(is.na(Indice_Agro_Act$progan),0,Indice_Agro_Act$progan)
Indice_Agro_Act$apoyo<-ifelse(is.na(Indice_Agro_Act$apoyo),0,Indice_Agro_Act$apoyo)
Indice_Agro_Act<-select(Indice_Agro_Act,folioviv,valor,apoyo)
n<-nrow(Indice_Agro_Act)
suma<-matrix(rep(0,n),ncol=1)
for(i in 1:n){
suma[i]=Indice_Agro_Act$valor[i]+Indice_Agro_Act$apoyo[i]
suma
}
Indice_Agro_Act<-data.frame(Indice_Agro_Act,suma)
Indice_Agro_Pas<-merge(Indice_Agro_Pas,Indice_Agro_Act, by="folioviv",all=F)
Indice_Agro_Pas$Numero_Int_Prom<-matrix(rep(3.8),nrow(Indice_Agro_Pas),ncol=1)
Ingreso_Prom<-matrix(rep(0),nrow(Indice_Agro_Pas),ncol=1)
for (i in 1:n){
Ingreso_Prom[i]=Indice_Agro_Pas$suma.y[i]/3.8
Ingreso_Prom
}
Indice_Agro_Pas$Ingreso_Prom<-Ingreso_Prom
Esta medida de pobreza calcula que aproximadamente el 63.43% de los hogares viven por debajo de la linea de pobreza por ingreso que es el porcentaje de las familias que únicamente alcanzan a cubrir el 100% de su consumo con sus ingresos.
Indice_Agro_Pas$Coef<-Indice_Agro_Pas$suma.y/Indice_Agro_Pas$suma.x
plot(x=1:nrow(Indice_Agro_Pas),y=sort(Indice_Agro_Pas$Coef),pch=20,cex=0.3,
main="Coeficiente de pobreza para actividades agrÃcolas, forestales y de tala",
ylab = "Coeficiente de pobreza",xlab="Clave por hogar")
segments(x0=0,y0=1.1,x1=nrow(Indice_Agro_Pas),y1=1.1, col="red", cex=10)

sum(mean(Indice_Agro_Pas$Coef<=1.1))
[1] 0.5797309
sum(Indice_Agro_Pas$Coef<=1.1)/nrow(Indice_Agro_Pas)
[1] 0.5797309
Linea de pobreza de CONEVAL \(\$2,837.57\):
Linea_Inf<-matrix(rep(2837.57,nrow(Indice_Agro_Pas)),ncol=1)
Indice_Agro_Pas$Linea_Inf<-Linea_Inf
FGT’s
Estas medidas de pobreza toman en cuenta el valor de la cosecha para los integrantes de las familias rurales (autoconsumo):
n<-nrow(Indice_Agro_Pas)
FGT_i<-matrix(rep(0,nrow(Indice_Agro_Pas)),ncol=1)
for (i in 1:n){
FGT_i[i]=(2837.57-Indice_Agro_Pas$Ingreso_Prom[i])/2837.57
FGT_i
}
Indice_Agro_Pas$FGT_i<-FGT_i
FGT0<-sum(Indice_Agro_Pas$Ingreso_Prom<2837.57)/n
FGT0
[1] 0.295426
suma <- c()
for (i in 1:n){
if (Indice_Agro_Pas$FGT_i[i]>0){
suma <- c(suma, Indice_Agro_Pas$FGT_i[i])
}
}
total<-sum(suma)
FGT1<-total/n
FGT1
[1] 0.1562398
suma <- c()
for (i in 1:n){
if (Indice_Agro_Pas$FGT_i[i]>0){
suma <- c(suma, (Indice_Agro_Pas$FGT_i[i])^2)
}
}
total<-sum(suma)
FGT2<-total/n
FGT2
[1] 0.1053634
NO-AGRO
Ingresos:
library(dplyr)
Indice<-select(no_agro,folioviv)
Indice_NoAgro_Ingresos<-semi_join(ingresos,Indice,by="folioviv")
Indice_NoAgro_Ingresos_Agr<-aggregate(ing_tri ~ folioviv, data = Indice_NoAgro_Ingresos, sum)
Indice_NoAgro_Ing_JCF<-semi_join(ingresos_jcf,Indice,by="folioviv")
Indice_NoAgro_Ing_JCF_Agr<-aggregate(ing_tri ~ folioviv, data = Indice_NoAgro_Ing_JCF, sum)
Ingreso_Agregado<-merge(Indice_NoAgro_Ingresos_Agr,Indice_NoAgro_Ing_JCF_Agr, by="folioviv",all=T)
Ingreso_Agregado$ing_tri.y<-ifelse(is.na(Ingreso_Agregado$ing_tri.y),0,Ingreso_Agregado$ing_tri.y)
Ingreso_Agregado$Ing_Tri<-Ingreso_Agregado$ing_tri.x+Ingreso_Agregado$ing_tri.y
Ingreso_Agregado$Numero_Int_Prom<-matrix(rep(3.5,nrow(Ingreso_Agregado)),ncol=1)
Ingreso_Agregado$Ingreso_Tri_Prom<- Ingreso_Agregado$Ing_Tri/3.5
Gastos:
Indice_NoAgro_Gastos<-semi_join(gastos_hogar,Indice, by="folioviv")
Indice_NoAgro_Gastos_Agr<-aggregate(gasto_tri ~ folioviv, data = Indice_NoAgro_Gastos, sum)
Indice_NoAgro_Gas_Tar<-semi_join(gastos_tarj, Indice, by="folioviv")
Indice_NoAgro_Gas_Tar_Agr<-aggregate(gasto_tri ~ folioviv, data = Indice_NoAgro_Gas_Tar, sum)
Indice_NoAgro_Gas_Per<-semi_join(gastos_per,Indice, by="folioviv")
Indice_NoAgro_Gas_Per_Agr<-aggregate(gasto_tri ~ folioviv, data = Indice_NoAgro_Gas_Per, sum)
Indice_Gasto<-merge(Indice_NoAgro_Gastos_Agr,Indice_NoAgro_Gas_Tar_Agr,by="folioviv", all=T)
Indice_Gasto<-merge(Indice_Gasto, Indice_NoAgro_Gas_Per_Agr, by="folioviv", all=T)
Indice_Gasto$gasto_tri.x<-ifelse(is.na(Indice_Gasto$gasto_tri.x),0,Indice_Gasto$gasto_tri.x)
Indice_Gasto$gasto_tri.y<-ifelse(is.na(Indice_Gasto$gasto_tri.y),0,Indice_Gasto$gasto_tri.y)
Indice_Gasto$gasto_tri<-ifelse(is.na(Indice_Gasto$gasto_tri),0,Indice_Gasto$gasto_tri)
Indice_Gasto$Gasto_tri_tot<-Indice_Gasto$gasto_tri.x+Indice_Gasto$gasto_tri.y+Indice_Gasto$gasto_tri
Indices Agregados:
Indice_NoAgro_Agregado<-merge(Ingreso_Agregado,Indice_Gasto,by="folioviv")
Coeficiente de Pobreza:
Indice_NoAgro_Agregado$Coef<-Indice_NoAgro_Agregado$Ing_Tri/Indice_NoAgro_Agregado$Gasto_tri_tot
Gáfico:
plot(x=1:nrow(Indice_NoAgro_Agregado),y=sort(Indice_NoAgro_Agregado$Coef),pch=20,cex=0.3,
main="Coeficiente de pobreza para actividades industriales, comerciales y de servicios", cex.main=1,
ylab = "Coeficiente de pobreza",xlab="Clave por hogar")
segments(x0=0,y0=1.2,x1=nrow(Indice_NoAgro_Agregado),y1=1.2, col="red", cex=10)

COEF<-mean(Indice_NoAgro_Agregado$Coef<1.1)
COEF
[1] 0.3538725
Linea de Pobreza CONEVAL \(\$3,997.24\)
n<-nrow(Indice_NoAgro_Agregado)
FGT_i<-matrix(rep(0,nrow(Indice_NoAgro_Agregado)),ncol=1)
for (i in 1:n){
FGT_i[i]=(3997.24-Indice_NoAgro_Agregado$Ingreso_Tri_Prom[i])/3997.24
FGT_i
}
Indice_NoAgro_Agregado$FGT_i<-FGT_i
FGT0<-sum(Indice_NoAgro_Agregado$Ingreso_Tri_Prom<3997.24)/n
FGT0
[1] 0.1843294
suma <- c()
for (i in 1:n){
if (Indice_NoAgro_Agregado$FGT_i[i]>0){
suma <- c(suma, Indice_NoAgro_Agregado$FGT_i[i])
}
}
total<-sum(suma)
FGT1<-total/n
FGT1
[1] 0.06659371
suma <- c()
for (i in 1:n){
if (Indice_NoAgro_Agregado$FGT_i[i]>0){
suma <- c(suma, (Indice_NoAgro_Agregado$FGT_i[i])^2)
}
}
total<-sum(suma)
FGT2<-total/n
FGT2
[1] 0.03401634
FGT0_Agr<-0.295426*(1-0.7692)+FGT0*0.7692
FGT1_Agr<-0.1562398*(1-0.7692)+FGT1*0.7692
FGT2_Agr<-0.1053634*(1-0.7692)+FGT2*0.7692
library(dplyr)
poverty_fgt <- function(x, z, w = NULL, alpha = 0){
if(is.null(w)){
w = rep(1, length(x))
}
if(length(z) == 1){
z = rep(z, length(x))
}
data <- tibble(x,w,z) %>% filter(complete.cases(.))
rm(x, w, z)
data <- data %>%
mutate(g = ifelse(x < z, ((z - x)/z), 0),
fgt = ifelse(x < z, g^alpha, 0)) %>%
summarise(fgt = sum(w*fgt),
n = sum(w))
data$fgt/data$n
}
poverty_fgt(unlist(Indice_NoAgro_Agregado$Ingreso_Tri_Prom),3997.24,w=NULL,alpha=0)
[1] 0.1843294
FGT0_Agr
[1] 0.2099705
FGT1_Agr
[1] 0.08728402
FGT2_Agr
[1] 0.05048325
LS0tCnRpdGxlOiAiUE9CUkVaQSIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKLS0tCkRlc2NhcmdhbW9zIGxvcyBkYXRvcywgbGEgbWF5b3LDrWEgZXN0w6FuIGNhcmdhZGFzIGVuIEdpdEh1YjoKYGBge3J9CmxpYnJhcnkoZG93bmxvYWRlcikKbGlicmFyeShkcGx5cikKbGlicmFyeShyZWFkcikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZ2dwbG90MikKCnVybDwtImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9jYXJsb3NjYXJyaWxsb2wvRU5JR0gvbWFpbi9hZ3JvLmNzdiIKbmFtZTwtYmFzZW5hbWUodXJsKQppZighZmlsZS5leGlzdHMobmFtZSkpZG93bmxvYWQodXJsLG5hbWUpCmFncm88LXJlYWQuY3N2KG5hbWUpCgp1cmw8LSJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vY2FybG9zY2FycmlsbG9sL0VOSUdIL21haW4vYWdyb2NvbnN1bW8uY3N2IgpuYW1lPC1iYXNlbmFtZSh1cmwpCmlmKCFmaWxlLmV4aXN0cyhuYW1lKSlkb3dubG9hZCh1cmwsbmFtZSkKYWdyb19jb25zdW1vPC1yZWFkLmNzdihuYW1lKQoKdXJsPC0iaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2Nhcmxvc2NhcnJpbGxvbC9FTklHSC9tYWluL2Fncm9nYXN0by5jc3YiCm5hbWU8LWJhc2VuYW1lKHVybCkKaWYoIWZpbGUuZXhpc3RzKG5hbWUpKWRvd25sb2FkKHVybCxuYW1lKQphZ3JvX2dhc3RvPC1yZWFkLmNzdihuYW1lKQoKdXJsPC0iaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2Nhcmxvc2NhcnJpbGxvbC9FTklHSC9tYWluL2Fncm9wcm9kdWN0b3MuY3N2IgpuYW1lPC1iYXNlbmFtZSh1cmwpCmlmKCFmaWxlLmV4aXN0cyhuYW1lKSlkb3dubG9hZCh1cmwsbmFtZSkKYWdyb19wcm9kPC1yZWFkLmNzdihuYW1lKQoKdXJsPC0iaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2Nhcmxvc2NhcnJpbGxvbC9FTklHSC9tYWluL2Vyb2dhY2lvbmVzLmNzdiIKbmFtZTwtYmFzZW5hbWUodXJsKQppZighZmlsZS5leGlzdHMobmFtZSkpZG93bmxvYWQodXJsLG5hbWUpCmVyb2dhPC1yZWFkLmNzdihuYW1lKQoKdXJsPC0iaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2Nhcmxvc2NhcnJpbGxvbC9FTklHSC9tYWluL2dhc3RvdGFyamV0YXMuY3N2IgpuYW1lPC1iYXNlbmFtZSh1cmwpCmlmKCFmaWxlLmV4aXN0cyhuYW1lKSlkb3dubG9hZCh1cmwsbmFtZSkKZ2FzdG9zX3Rhcmo8LXJlYWQuY3N2KG5hbWUpCgp1cmw8LSJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vY2FybG9zY2FycmlsbG9sL0VOSUdIL21haW4vaW5ncmVzb3NfamNmLmNzdiIKbmFtZTwtYmFzZW5hbWUodXJsKQppZighZmlsZS5leGlzdHMobmFtZSkpZG93bmxvYWQodXJsLG5hbWUpCmluZ3Jlc29zX2pjZjwtcmVhZC5jc3YobmFtZSkKCnVybDwtImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9jYXJsb3NjYXJyaWxsb2wvRU5JR0gvbWFpbi9ub2Fncm8uY3N2IgpuYW1lPC1iYXNlbmFtZSh1cmwpCmlmKCFmaWxlLmV4aXN0cyhuYW1lKSlkb3dubG9hZCh1cmwsbmFtZSkKbm9fYWdybzwtcmVhZC5jc3YobmFtZSkKCnVybDwtImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9jYXJsb3NjYXJyaWxsb2wvRU5JR0gvbWFpbi9ub2Fncm9pbXBvcnRlcy5jc3YiCm5hbWU8LWJhc2VuYW1lKHVybCkKaWYoIWZpbGUuZXhpc3RzKG5hbWUpKWRvd25sb2FkKHVybCxuYW1lKQpub19hZ3JvX2ltcG9ydGVzPC1yZWFkLmNzdihuYW1lKQoKdXJsPC0iaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2Nhcmxvc2NhcnJpbGxvbC9FTklHSC9tYWluL3RyYWJham9zLmNzdiIKbmFtZTwtYmFzZW5hbWUodXJsKQppZighZmlsZS5leGlzdHMobmFtZSkpZG93bmxvYWQodXJsLG5hbWUpCnRyYWJham9zPC1yZWFkLmNzdihuYW1lKQoKdXJsPC0iaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2Nhcmxvc2NhcnJpbGxvbC9FTklHSC9tYWluL3ZpdmllbmRhcy5jc3YiCm5hbWU8LWJhc2VuYW1lKHVybCkKaWYoIWZpbGUuZXhpc3RzKG5hbWUpKWRvd25sb2FkKHVybCxuYW1lKQp2aXZpZW5kYXM8LXJlYWQuY3N2KG5hbWUpCgojTG9zIGHDsWFkw60gZGVzZGUgbWkgY29tcHV0YWRvcmEgcG9ycXVlIGVzdMOhbiBkZW1hc2lhZG8gcGVzYWRvcyBwYXJhIHN1YmlybG9zIGEgR2l0Cmdhc3Rvc19wZXI8LXJlYWQuY3N2KCJnYXN0b3NwZXJzb25hLmNzdiIpCmNvbl9ob2dhcjwtcmVhZC5jc3YoImNvbmNlbnRyYWRvaG9nYXIuY3N2IikKaG9nYXJlczwtcmVhZC5jc3YoImhvZ2FyZXMuY3N2IikKaW5ncmVzb3M8LXJlYWQuY3N2KCJpbmdyZXNvcy5jc3YiKQpwb2JsYWNpb248LXJlYWQuY3N2KCJwb2JsYWNpb24uY3N2IikKZ2FzdG9zX2hvZ2FyPC1yZWFkLmNzdigiZ2FzdG9zaG9nYXIuY3N2IikKYGBgCgpQYXJhIGVsIHByaW1lciBpbmRpY2Fkb3IgZGUgcG9icmV6YSB2YW1vcyBhIGlkZW50aWZpY2FyIGRlIG1hbmVyYSBnZW7DqXJpY2EsIHBhcmEgbGEgcG9ibGFjacOzbiBydXJhbCwgZGUgbWFuZXJhIHNpZ3VpZW50ZToKJCRcdGV4dGl0e0luZGljZSBkZSBQb2JyZXphIHBvciBpbmdyZXNvfV97aX09XGZyYWN7XHRleHRpdHtWYWxvciBkZWwgaW5ncmVzb31fe2l9K1x0ZXh0aXR7VmFsb3IgZGVsIGFwb3lvfV97aml9fXtcdGV4dGl0e1ZhbG9yIGRlbCBjb25zdW1vfV97aX0rXHRleHRpdHtWYWxvciBkZSBsb3MgZ2FzdG9zfV97aX19JCQKKipBR1JPKioKCkdhc3RvIHkgQ29uc3VtbzoKYGBge3J9CmluZGljZTwtc2VsZWN0KGFncm9fY29uc3Vtbyxmb2xpb3ZpdikKaW5kaWNlX0Fncm9fR2FzdG88LXNlbWlfam9pbihhZ3JvX2dhc3RvLGluZGljZSxieT0iZm9saW92aXYiKQpgYGAKCmBgYHtyfQpJbmRpY2VfQWdyb19HYXN0b19BZ3JlZ2FkbyA8LSBhZ2dyZWdhdGUoZ2FzdG8gfiBmb2xpb3ZpdiwgZGF0YSA9IGluZGljZV9BZ3JvX0dhc3RvLCBzdW0pCmBgYAoKYGBge3J9CmluZGljZV9BZ3JvX0NvbnN1bW88LXNlbWlfam9pbihhZ3JvX2NvbnN1bW8saW5kaWNlLGJ5PSJmb2xpb3ZpdiIpCkluZGljZV9BZ3JvX0NvbnN1bW9fQWdyZWdhZG8gPC0gYWdncmVnYXRlKHZhbGVzdGltIH4gZm9saW92aXYsIGRhdGEgPSBpbmRpY2VfQWdyb19Db25zdW1vLCBzdW0pCkluZGljZV9BZ3JvX1BhczwtbWVyZ2UoSW5kaWNlX0Fncm9fQ29uc3Vtb19BZ3JlZ2FkbyxJbmRpY2VfQWdyb19HYXN0b19BZ3JlZ2FkbywgYnk9ImZvbGlvdml2IixhbGw9VCkKSW5kaWNlX0Fncm9fUGFzJGdhc3RvPC1pZmVsc2UoaXMubmEoSW5kaWNlX0Fncm9fUGFzJGdhc3RvKSwwLEluZGljZV9BZ3JvX1BhcyRnYXN0bykKYGBgCgpgYGB7cn0KIy0tLS0tLS0tLS0tLS0tCkdhc3RvX0hvZzwtc2VtaV9qb2luKGdhc3Rvc19ob2dhciwgaW5kaWNlLCBieT0iZm9saW92aXYiKQpHYXN0b19Ib2ckZ2FzdG9fdHJpPC1pZmVsc2UoaXMubmEoR2FzdG9fSG9nJGdhc3RvX3RyaSksMCxHYXN0b19Ib2ckZ2FzdG9fdHJpKQpHYXN0b19Ib2c8LWFnZ3JlZ2F0ZShnYXN0b190cmkgfiBmb2xpb3ZpdiwgZGF0YSA9IEdhc3RvX0hvZywgc3VtKQpHYXN0b19Ib2ckZ2FzdG9fdHJpPC1HYXN0b19Ib2ckZ2FzdG9fdHJpLzMKSW5kaWNlX0Fncm9fUGFzPC1tZXJnZShHYXN0b19Ib2csIEluZGljZV9BZ3JvX1BhcywgYnk9ImZvbGlvdml2IiwgYWxsPVQpCiMtLS0tLS0tLS0tLS0tLQpuPC1ucm93KEluZGljZV9BZ3JvX1BhcykKc3VtYTwtbWF0cml4KHJlcCgwLG4pLG5jb2w9MSkKZm9yKGkgaW4gMTpuKXsKICBzdW1hW2ldPUluZGljZV9BZ3JvX1BhcyR2YWxlc3RpbVtpXStJbmRpY2VfQWdyb19QYXMkZ2FzdG9baV0rSW5kaWNlX0Fncm9fUGFzJGdhc3RvX3RyaVtpXQogIHN1bWEKfQpJbmRpY2VfQWdyb19QYXM8LWRhdGEuZnJhbWUoSW5kaWNlX0Fncm9fUGFzLHN1bWEpCmBgYAoKSW5ncmVzb3M6CgpgYGB7cn0KSW5kaWNlX0Fncm9fUHJvZDwtc2VtaV9qb2luKGFncm9fcHJvZCxpbmRpY2UsIGJ5PSJmb2xpb3ZpdiIpCkluZGljZV9BZ3JvX1Byb2RfQWdyZWdhZG88LWFnZ3JlZ2F0ZSh2YWxvciB+IGZvbGlvdml2LCBkYXRhID0gSW5kaWNlX0Fncm9fUHJvZCwgc3VtKQpJbmRpY2VfQWdybzwtc2VtaV9qb2luKGFncm8saW5kaWNlLGJ5PSJmb2xpb3ZpdiIpCkluZGljZV9BZ3JvX0Fwb3lvPC1maWx0ZXIoSW5kaWNlX0Fncm8sYXBveW89PTF8cHJvYWdybz49MXwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2dhbj49MXxudm9fYXBveW89PTEpCkluZGljZV9BZ3JvX0Fwb3lvJGFwb3lvXzE8LWlmZWxzZShpcy5uYShJbmRpY2VfQWdyb19BcG95byRhcG95b18xKSwwLEluZGljZV9BZ3JvX0Fwb3lvJGFwb3lvXzEpCkluZGljZV9BZ3JvX0Fwb3lvJGFwb3lvXzI8LWlmZWxzZShpcy5uYShJbmRpY2VfQWdyb19BcG95byRhcG95b18yKSwwLEluZGljZV9BZ3JvX0Fwb3lvJGFwb3lvXzIpCkluZGljZV9BZ3JvX0Fwb3lvJGFwb3lvXzM8LWlmZWxzZShpcy5uYShJbmRpY2VfQWdyb19BcG95byRhcG95b18zKSwwLEluZGljZV9BZ3JvX0Fwb3lvJGFwb3lvXzMpCkluZGljZV9BZ3JvX0Fwb3lvJGFwb3lvXzQ8LWlmZWxzZShpcy5uYShJbmRpY2VfQWdyb19BcG95byRhcG95b180KSwwLEluZGljZV9BZ3JvX0Fwb3lvJGFwb3lvXzQpCkluZGljZV9BZ3JvX0Fwb3lvJGFwb3lvXzU8LWlmZWxzZShpcy5uYShJbmRpY2VfQWdyb19BcG95byRhcG95b181KSwwLEluZGljZV9BZ3JvX0Fwb3lvJGFwb3lvXzUpCkluZGljZV9BZ3JvX0Fwb3lvJGFwb3lvXzY8LWlmZWxzZShpcy5uYShJbmRpY2VfQWdyb19BcG95byRhcG95b182KSwwLEluZGljZV9BZ3JvX0Fwb3lvJGFwb3lvXzYpCkluZGljZV9BZ3JvX0Fwb3lvJGFwb3lvXzc8LWlmZWxzZShpcy5uYShJbmRpY2VfQWdyb19BcG95byRhcG95b183KSwwLEluZGljZV9BZ3JvX0Fwb3lvJGFwb3lvXzcpCkluZGljZV9BZ3JvX0Fwb3lvJGFwb3lvXzg8LWlmZWxzZShpcy5uYShJbmRpY2VfQWdyb19BcG95byRhcG95b184KSwwLEluZGljZV9BZ3JvX0Fwb3lvJGFwb3lvXzgpCkluZGljZV9BZ3JvX0Fwb3lvJHByb2Fncm88LWlmZWxzZShpcy5uYShJbmRpY2VfQWdyb19BcG95byRwcm9hZ3JvKSwwLEluZGljZV9BZ3JvX0Fwb3lvJHByb2Fncm8pCkluZGljZV9BZ3JvX0Fwb3lvJG52b19jYW50MTwtaWZlbHNlKGlzLm5hKEluZGljZV9BZ3JvX0Fwb3lvJG52b19jYW50MSksMCxJbmRpY2VfQWdyb19BcG95byRudm9fY2FudDEpCkluZGljZV9BZ3JvX0Fwb3lvJG52b19jYW50MjwtaWZlbHNlKGlzLm5hKEluZGljZV9BZ3JvX0Fwb3lvJG52b19jYW50MiksMCxJbmRpY2VfQWdyb19BcG95byRudm9fY2FudDIpCkluZGljZV9BZ3JvX0Fwb3lvJG52b19jYW50MzwtaWZlbHNlKGlzLm5hKEluZGljZV9BZ3JvX0Fwb3lvJG52b19jYW50MyksMCxJbmRpY2VfQWdyb19BcG95byRudm9fY2FudDMpCkluZGljZV9BZ3JvX0Fwb3lvJHByb2dhbjwtaWZlbHNlKGlzLm5hKEluZGljZV9BZ3JvX0Fwb3lvJHByb2dhbiksMCxJbmRpY2VfQWdyb19BcG95byRwcm9nYW4pCkluZGljZV9BZ3JvX0Fwb3lvPC1zZWxlY3QoSW5kaWNlX0Fncm9fQXBveW8sZm9saW92aXYsYXBveW9fMSxhcG95b18yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYXBveW9fMyxhcG95b180LGFwb3lvXzUsYXBveW9fNixhcG95b183LGFwb3lvXzgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbnZvX2NhbnQxLG52b19jYW50Mixudm9fY2FudDMscHJvYWdybyxwcm9nYW4pCmBgYAoKYGBge3J9Cm48LW5yb3coSW5kaWNlX0Fncm9fQXBveW8pCmFwb3lvPC1tYXRyaXgocmVwKDAsbiksbmNvbD0xKQpmb3IoaSBpbiAxOm4pewogIGFwb3lvW2ldPXN1bShJbmRpY2VfQWdyb19BcG95b1tpLF0pLUluZGljZV9BZ3JvX0Fwb3lvJGZvbGlvdml2W2ldCiAgYXBveW8KfQpJbmRpY2VfQWdyb19BcG95bzwtZGF0YS5mcmFtZShJbmRpY2VfQWdyb19BcG95byxhcG95bykKCkluZGljZV9BZ3JvX0FjdDwtbWVyZ2UoSW5kaWNlX0Fncm9fUHJvZF9BZ3JlZ2FkbyxJbmRpY2VfQWdyb19BcG95bywgYnk9ImZvbGlvdml2IixhbGw9VCkKCkluZGljZV9BZ3JvX0FjdCRhcG95b18xPC1pZmVsc2UoaXMubmEoSW5kaWNlX0Fncm9fQWN0JGFwb3lvXzEpLDAsSW5kaWNlX0Fncm9fQWN0JGFwb3lvXzEpCkluZGljZV9BZ3JvX0FjdCRhcG95b18yPC1pZmVsc2UoaXMubmEoSW5kaWNlX0Fncm9fQWN0JGFwb3lvXzIpLDAsSW5kaWNlX0Fncm9fQWN0JGFwb3lvXzIpCkluZGljZV9BZ3JvX0FjdCRhcG95b18zPC1pZmVsc2UoaXMubmEoSW5kaWNlX0Fncm9fQWN0JGFwb3lvXzMpLDAsSW5kaWNlX0Fncm9fQWN0JGFwb3lvXzMpCkluZGljZV9BZ3JvX0FjdCRhcG95b180PC1pZmVsc2UoaXMubmEoSW5kaWNlX0Fncm9fQWN0JGFwb3lvXzQpLDAsSW5kaWNlX0Fncm9fQWN0JGFwb3lvXzQpCkluZGljZV9BZ3JvX0FjdCRhcG95b181PC1pZmVsc2UoaXMubmEoSW5kaWNlX0Fncm9fQWN0JGFwb3lvXzUpLDAsSW5kaWNlX0Fncm9fQWN0JGFwb3lvXzUpCkluZGljZV9BZ3JvX0FjdCRhcG95b182PC1pZmVsc2UoaXMubmEoSW5kaWNlX0Fncm9fQWN0JGFwb3lvXzYpLDAsSW5kaWNlX0Fncm9fQWN0JGFwb3lvXzYpCkluZGljZV9BZ3JvX0FjdCRhcG95b183PC1pZmVsc2UoaXMubmEoSW5kaWNlX0Fncm9fQWN0JGFwb3lvXzcpLDAsSW5kaWNlX0Fncm9fQWN0JGFwb3lvXzcpCkluZGljZV9BZ3JvX0FjdCRhcG95b184PC1pZmVsc2UoaXMubmEoSW5kaWNlX0Fncm9fQWN0JGFwb3lvXzgpLDAsSW5kaWNlX0Fncm9fQWN0JGFwb3lvXzgpCkluZGljZV9BZ3JvX0FjdCRudm9fY2FudDE8LWlmZWxzZShpcy5uYShJbmRpY2VfQWdyb19BY3QkbnZvX2NhbnQxKSwwLEluZGljZV9BZ3JvX0FjdCRudm9fY2FudDEpCkluZGljZV9BZ3JvX0FjdCRudm9fY2FudDI8LWlmZWxzZShpcy5uYShJbmRpY2VfQWdyb19BY3QkbnZvX2NhbnQyKSwwLEluZGljZV9BZ3JvX0FjdCRudm9fY2FudDIpCkluZGljZV9BZ3JvX0FjdCRudm9fY2FudDM8LWlmZWxzZShpcy5uYShJbmRpY2VfQWdyb19BY3QkbnZvX2NhbnQzKSwwLEluZGljZV9BZ3JvX0FjdCRudm9fY2FudDMpCkluZGljZV9BZ3JvX0FjdCRwcm9hZ3JvPC1pZmVsc2UoaXMubmEoSW5kaWNlX0Fncm9fQWN0JHByb2Fncm8pLDAsSW5kaWNlX0Fncm9fQWN0JHByb2Fncm8pCkluZGljZV9BZ3JvX0FjdCRwcm9nYW48LWlmZWxzZShpcy5uYShJbmRpY2VfQWdyb19BY3QkcHJvZ2FuKSwwLEluZGljZV9BZ3JvX0FjdCRwcm9nYW4pCkluZGljZV9BZ3JvX0FjdCRhcG95bzwtaWZlbHNlKGlzLm5hKEluZGljZV9BZ3JvX0FjdCRhcG95byksMCxJbmRpY2VfQWdyb19BY3QkYXBveW8pCgpJbmRpY2VfQWdyb19BY3Q8LXNlbGVjdChJbmRpY2VfQWdyb19BY3QsZm9saW92aXYsdmFsb3IsYXBveW8pCmBgYAoKYGBge3J9Cm48LW5yb3coSW5kaWNlX0Fncm9fQWN0KQpzdW1hPC1tYXRyaXgocmVwKDAsbiksbmNvbD0xKQpmb3IoaSBpbiAxOm4pewogIHN1bWFbaV09SW5kaWNlX0Fncm9fQWN0JHZhbG9yW2ldK0luZGljZV9BZ3JvX0FjdCRhcG95b1tpXQogIHN1bWEKfQpJbmRpY2VfQWdyb19BY3Q8LWRhdGEuZnJhbWUoSW5kaWNlX0Fncm9fQWN0LHN1bWEpCgpJbmRpY2VfQWdyb19QYXM8LW1lcmdlKEluZGljZV9BZ3JvX1BhcyxJbmRpY2VfQWdyb19BY3QsIGJ5PSJmb2xpb3ZpdiIsYWxsPUYpCmBgYAoKYGBge3J9CkluZGljZV9BZ3JvX1BhcyROdW1lcm9fSW50X1Byb208LW1hdHJpeChyZXAoMy44KSxucm93KEluZGljZV9BZ3JvX1BhcyksbmNvbD0xKQpJbmdyZXNvX1Byb208LW1hdHJpeChyZXAoMCksbnJvdyhJbmRpY2VfQWdyb19QYXMpLG5jb2w9MSkKZm9yIChpIGluIDE6bil7CiAgSW5ncmVzb19Qcm9tW2ldPUluZGljZV9BZ3JvX1BhcyRzdW1hLnlbaV0vMy44CiAgSW5ncmVzb19Qcm9tCn0KSW5kaWNlX0Fncm9fUGFzJEluZ3Jlc29fUHJvbTwtSW5ncmVzb19Qcm9tCmBgYApFc3RhIG1lZGlkYSBkZSBwb2JyZXphIGNhbGN1bGEgcXVlIGFwcm94aW1hZGFtZW50ZSBlbCA2My40M1wlIGRlIGxvcyBob2dhcmVzIHZpdmVuIHBvciBkZWJham8gZGUgbGEgbGluZWEgZGUgcG9icmV6YSBwb3IgaW5ncmVzbyBxdWUgZXMgZWwgcG9yY2VudGFqZSBkZSBsYXMgZmFtaWxpYXMgcXVlIMO6bmljYW1lbnRlIGFsY2FuemFuIGEgY3VicmlyIGVsIDEwMFwlIGRlIHN1IGNvbnN1bW8gY29uIHN1cyBpbmdyZXNvcy4KYGBge3J9CkluZGljZV9BZ3JvX1BhcyRDb2VmPC1JbmRpY2VfQWdyb19QYXMkc3VtYS55L0luZGljZV9BZ3JvX1BhcyRzdW1hLngKcGxvdCh4PTE6bnJvdyhJbmRpY2VfQWdyb19QYXMpLHk9c29ydChJbmRpY2VfQWdyb19QYXMkQ29lZikscGNoPTIwLGNleD0wLjMsCiAgICAgbWFpbj0iQ29lZmljaWVudGUgZGUgcG9icmV6YSBwYXJhIGFjdGl2aWRhZGVzIGFncsOtY29sYXMsIGZvcmVzdGFsZXMgeSBkZSB0YWxhIiwKICAgICB5bGFiID0gIkNvZWZpY2llbnRlIGRlIHBvYnJlemEiLHhsYWI9IkNsYXZlIHBvciBob2dhciIpCnNlZ21lbnRzKHgwPTAseTA9MS4xLHgxPW5yb3coSW5kaWNlX0Fncm9fUGFzKSx5MT0xLjEsIGNvbD0icmVkIiwgY2V4PTEwKQoKYGBgCmBgYHtyfQpzdW0obWVhbihJbmRpY2VfQWdyb19QYXMkQ29lZjw9MS4xKSkKc3VtKEluZGljZV9BZ3JvX1BhcyRDb2VmPD0xLjEpL25yb3coSW5kaWNlX0Fncm9fUGFzKQpgYGAKTGluZWEgZGUgcG9icmV6YSBkZSBDT05FVkFMICRcJDIsODM3LjU3JDoKYGBge3J9CkxpbmVhX0luZjwtbWF0cml4KHJlcCgyODM3LjU3LG5yb3coSW5kaWNlX0Fncm9fUGFzKSksbmNvbD0xKQpJbmRpY2VfQWdyb19QYXMkTGluZWFfSW5mPC1MaW5lYV9JbmYKYGBgCgpGR1QncwoKRXN0YXMgbWVkaWRhcyBkZSBwb2JyZXphIHRvbWFuIGVuIGN1ZW50YSBlbCB2YWxvciBkZSBsYSBjb3NlY2hhIHBhcmEgbG9zIGludGVncmFudGVzIGRlIGxhcyBmYW1pbGlhcyBydXJhbGVzIChhdXRvY29uc3Vtbyk6CmBgYHtyfQpuPC1ucm93KEluZGljZV9BZ3JvX1BhcykKRkdUX2k8LW1hdHJpeChyZXAoMCxucm93KEluZGljZV9BZ3JvX1BhcykpLG5jb2w9MSkKZm9yIChpIGluIDE6bil7CiAgRkdUX2lbaV09KDI4MzcuNTctSW5kaWNlX0Fncm9fUGFzJEluZ3Jlc29fUHJvbVtpXSkvMjgzNy41NwogIEZHVF9pCn0KSW5kaWNlX0Fncm9fUGFzJEZHVF9pPC1GR1RfaQpgYGAKCmBgYHtyIEZHVDB9CkZHVDA8LXN1bShJbmRpY2VfQWdyb19QYXMkSW5ncmVzb19Qcm9tPDI4MzcuNTcpL24KRkdUMApgYGAKCmBgYHtyIEZHVDF9CnN1bWEgPC0gYygpCmZvciAoaSBpbiAxOm4pewogIGlmIChJbmRpY2VfQWdyb19QYXMkRkdUX2lbaV0+MCl7CiAgICBzdW1hIDwtIGMoc3VtYSwgSW5kaWNlX0Fncm9fUGFzJEZHVF9pW2ldKQogIH0KfQp0b3RhbDwtc3VtKHN1bWEpCkZHVDE8LXRvdGFsL24KRkdUMQpgYGAKCmBgYHtyIEZHVDJ9CnN1bWEgPC0gYygpCmZvciAoaSBpbiAxOm4pewogIGlmIChJbmRpY2VfQWdyb19QYXMkRkdUX2lbaV0+MCl7CiAgICBzdW1hIDwtIGMoc3VtYSwgKEluZGljZV9BZ3JvX1BhcyRGR1RfaVtpXSleMikKICB9Cn0KdG90YWw8LXN1bShzdW1hKQpGR1QyPC10b3RhbC9uCkZHVDIKYGBgCioqTk8tQUdSTyoqCgpJbmdyZXNvczoKYGBge3J9CmxpYnJhcnkoZHBseXIpCkluZGljZTwtc2VsZWN0KG5vX2Fncm8sZm9saW92aXYpCkluZGljZV9Ob0Fncm9fSW5ncmVzb3M8LXNlbWlfam9pbihpbmdyZXNvcyxJbmRpY2UsYnk9ImZvbGlvdml2IikKSW5kaWNlX05vQWdyb19JbmdyZXNvc19BZ3I8LWFnZ3JlZ2F0ZShpbmdfdHJpIH4gZm9saW92aXYsIGRhdGEgPSBJbmRpY2VfTm9BZ3JvX0luZ3Jlc29zLCBzdW0pCgpJbmRpY2VfTm9BZ3JvX0luZ19KQ0Y8LXNlbWlfam9pbihpbmdyZXNvc19qY2YsSW5kaWNlLGJ5PSJmb2xpb3ZpdiIpCkluZGljZV9Ob0Fncm9fSW5nX0pDRl9BZ3I8LWFnZ3JlZ2F0ZShpbmdfdHJpIH4gZm9saW92aXYsIGRhdGEgPSBJbmRpY2VfTm9BZ3JvX0luZ19KQ0YsIHN1bSkKCkluZ3Jlc29fQWdyZWdhZG88LW1lcmdlKEluZGljZV9Ob0Fncm9fSW5ncmVzb3NfQWdyLEluZGljZV9Ob0Fncm9fSW5nX0pDRl9BZ3IsIGJ5PSJmb2xpb3ZpdiIsYWxsPVQpCkluZ3Jlc29fQWdyZWdhZG8kaW5nX3RyaS55PC1pZmVsc2UoaXMubmEoSW5ncmVzb19BZ3JlZ2FkbyRpbmdfdHJpLnkpLDAsSW5ncmVzb19BZ3JlZ2FkbyRpbmdfdHJpLnkpCkluZ3Jlc29fQWdyZWdhZG8kSW5nX1RyaTwtSW5ncmVzb19BZ3JlZ2FkbyRpbmdfdHJpLngrSW5ncmVzb19BZ3JlZ2FkbyRpbmdfdHJpLnkKCkluZ3Jlc29fQWdyZWdhZG8kTnVtZXJvX0ludF9Qcm9tPC1tYXRyaXgocmVwKDMuNSxucm93KEluZ3Jlc29fQWdyZWdhZG8pKSxuY29sPTEpCkluZ3Jlc29fQWdyZWdhZG8kSW5ncmVzb19UcmlfUHJvbTwtIEluZ3Jlc29fQWdyZWdhZG8kSW5nX1RyaS8zLjUKYGBgCkdhc3RvczoKYGBge3J9CkluZGljZV9Ob0Fncm9fR2FzdG9zPC1zZW1pX2pvaW4oZ2FzdG9zX2hvZ2FyLEluZGljZSwgYnk9ImZvbGlvdml2IikKSW5kaWNlX05vQWdyb19HYXN0b3NfQWdyPC1hZ2dyZWdhdGUoZ2FzdG9fdHJpIH4gZm9saW92aXYsIGRhdGEgPSBJbmRpY2VfTm9BZ3JvX0dhc3Rvcywgc3VtKQoKSW5kaWNlX05vQWdyb19HYXNfVGFyPC1zZW1pX2pvaW4oZ2FzdG9zX3RhcmosIEluZGljZSwgYnk9ImZvbGlvdml2IikKSW5kaWNlX05vQWdyb19HYXNfVGFyX0FncjwtYWdncmVnYXRlKGdhc3RvX3RyaSB+IGZvbGlvdml2LCBkYXRhID0gSW5kaWNlX05vQWdyb19HYXNfVGFyLCBzdW0pCgpJbmRpY2VfTm9BZ3JvX0dhc19QZXI8LXNlbWlfam9pbihnYXN0b3NfcGVyLEluZGljZSwgYnk9ImZvbGlvdml2IikKSW5kaWNlX05vQWdyb19HYXNfUGVyX0FncjwtYWdncmVnYXRlKGdhc3RvX3RyaSB+IGZvbGlvdml2LCBkYXRhID0gSW5kaWNlX05vQWdyb19HYXNfUGVyLCBzdW0pCgpJbmRpY2VfR2FzdG88LW1lcmdlKEluZGljZV9Ob0Fncm9fR2FzdG9zX0FncixJbmRpY2VfTm9BZ3JvX0dhc19UYXJfQWdyLGJ5PSJmb2xpb3ZpdiIsIGFsbD1UKQpJbmRpY2VfR2FzdG88LW1lcmdlKEluZGljZV9HYXN0bywgSW5kaWNlX05vQWdyb19HYXNfUGVyX0FnciwgYnk9ImZvbGlvdml2IiwgYWxsPVQpCkluZGljZV9HYXN0byRnYXN0b190cmkueDwtaWZlbHNlKGlzLm5hKEluZGljZV9HYXN0byRnYXN0b190cmkueCksMCxJbmRpY2VfR2FzdG8kZ2FzdG9fdHJpLngpCkluZGljZV9HYXN0byRnYXN0b190cmkueTwtaWZlbHNlKGlzLm5hKEluZGljZV9HYXN0byRnYXN0b190cmkueSksMCxJbmRpY2VfR2FzdG8kZ2FzdG9fdHJpLnkpCkluZGljZV9HYXN0byRnYXN0b190cmk8LWlmZWxzZShpcy5uYShJbmRpY2VfR2FzdG8kZ2FzdG9fdHJpKSwwLEluZGljZV9HYXN0byRnYXN0b190cmkpCkluZGljZV9HYXN0byRHYXN0b190cmlfdG90PC1JbmRpY2VfR2FzdG8kZ2FzdG9fdHJpLngrSW5kaWNlX0dhc3RvJGdhc3RvX3RyaS55K0luZGljZV9HYXN0byRnYXN0b190cmkKYGBgCkluZGljZXMgQWdyZWdhZG9zOgpgYGB7cn0KSW5kaWNlX05vQWdyb19BZ3JlZ2FkbzwtbWVyZ2UoSW5ncmVzb19BZ3JlZ2FkbyxJbmRpY2VfR2FzdG8sYnk9ImZvbGlvdml2IikKYGBgCkNvZWZpY2llbnRlIGRlIFBvYnJlemE6CmBgYHtyfQpJbmRpY2VfTm9BZ3JvX0FncmVnYWRvJENvZWY8LUluZGljZV9Ob0Fncm9fQWdyZWdhZG8kSW5nX1RyaS9JbmRpY2VfTm9BZ3JvX0FncmVnYWRvJEdhc3RvX3RyaV90b3QKYGBgCkfDoWZpY286CmBgYHtyfQpwbG90KHg9MTpucm93KEluZGljZV9Ob0Fncm9fQWdyZWdhZG8pLHk9c29ydChJbmRpY2VfTm9BZ3JvX0FncmVnYWRvJENvZWYpLHBjaD0yMCxjZXg9MC4zLAogICAgIG1haW49IkNvZWZpY2llbnRlIGRlIHBvYnJlemEgcGFyYSBhY3RpdmlkYWRlcyBpbmR1c3RyaWFsZXMsIGNvbWVyY2lhbGVzIHkgZGUgc2VydmljaW9zIiwgY2V4Lm1haW49MSwKICAgICB5bGFiID0gIkNvZWZpY2llbnRlIGRlIHBvYnJlemEiLHhsYWI9IkNsYXZlIHBvciBob2dhciIpCnNlZ21lbnRzKHgwPTAseTA9MS4yLHgxPW5yb3coSW5kaWNlX05vQWdyb19BZ3JlZ2FkbykseTE9MS4yLCBjb2w9InJlZCIsIGNleD0xMCkKYGBgCgpgYGB7cn0KQ09FRjwtbWVhbihJbmRpY2VfTm9BZ3JvX0FncmVnYWRvJENvZWY8MS4xKQpDT0VGCmBgYApMaW5lYSBkZSBQb2JyZXphIENPTkVWQUwgJFwkMyw5OTcuMjQkCmBgYHtyfQpuPC1ucm93KEluZGljZV9Ob0Fncm9fQWdyZWdhZG8pCkZHVF9pPC1tYXRyaXgocmVwKDAsbnJvdyhJbmRpY2VfTm9BZ3JvX0FncmVnYWRvKSksbmNvbD0xKQpmb3IgKGkgaW4gMTpuKXsKICBGR1RfaVtpXT0oMzk5Ny4yNC1JbmRpY2VfTm9BZ3JvX0FncmVnYWRvJEluZ3Jlc29fVHJpX1Byb21baV0pLzM5OTcuMjQKICBGR1RfaQp9CkluZGljZV9Ob0Fncm9fQWdyZWdhZG8kRkdUX2k8LUZHVF9pCmBgYAoKYGBge3J9CkZHVDA8LXN1bShJbmRpY2VfTm9BZ3JvX0FncmVnYWRvJEluZ3Jlc29fVHJpX1Byb208Mzk5Ny4yNCkvbgpGR1QwCmBgYApgYGB7cn0Kc3VtYSA8LSBjKCkKZm9yIChpIGluIDE6bil7CiAgaWYgKEluZGljZV9Ob0Fncm9fQWdyZWdhZG8kRkdUX2lbaV0+MCl7CiAgICBzdW1hIDwtIGMoc3VtYSwgSW5kaWNlX05vQWdyb19BZ3JlZ2FkbyRGR1RfaVtpXSkKICB9Cn0KdG90YWw8LXN1bShzdW1hKQpGR1QxPC10b3RhbC9uCkZHVDEKYGBgCmBgYHtyfQpzdW1hIDwtIGMoKQpmb3IgKGkgaW4gMTpuKXsKICBpZiAoSW5kaWNlX05vQWdyb19BZ3JlZ2FkbyRGR1RfaVtpXT4wKXsKICAgIHN1bWEgPC0gYyhzdW1hLCAoSW5kaWNlX05vQWdyb19BZ3JlZ2FkbyRGR1RfaVtpXSleMikKICB9Cn0KdG90YWw8LXN1bShzdW1hKQpGR1QyPC10b3RhbC9uCkZHVDIKYGBgCgpgYGB7cn0KRkdUMF9BZ3I8LTAuMjk1NDI2KigxLTAuNzY5MikrRkdUMCowLjc2OTIKRkdUMV9BZ3I8LTAuMTU2MjM5OCooMS0wLjc2OTIpK0ZHVDEqMC43NjkyCkZHVDJfQWdyPC0wLjEwNTM2MzQqKDEtMC43NjkyKStGR1QyKjAuNzY5MgpgYGAKYGBge3J9CmxpYnJhcnkoZHBseXIpCnBvdmVydHlfZmd0IDwtIGZ1bmN0aW9uKHgsIHosIHcgPSBOVUxMLCBhbHBoYSA9IDApewogICAgICAgIGlmKGlzLm51bGwodykpewogICAgICAgICAgICAgICAgdyA9IHJlcCgxLCBsZW5ndGgoeCkpCiAgICAgICAgfQogICAgICAgIAogICAgICAgIGlmKGxlbmd0aCh6KSA9PSAxKXsKICAgICAgICAgICAgICAgIHogPSByZXAoeiwgbGVuZ3RoKHgpKQogICAgICAgIH0KICAgICAgICAKICAgICAgICBkYXRhIDwtIHRpYmJsZSh4LHcseikgJT4lIGZpbHRlcihjb21wbGV0ZS5jYXNlcyguKSkKICAgICAgICAKICAgICAgICBybSh4LCB3LCB6KQogICAgICAgIAogICAgICAgIGRhdGEgPC0gZGF0YSAlPiUKICAgICAgICAgICAgICAgIG11dGF0ZShnICAgPSBpZmVsc2UoeCA8IHosICgoeiAtIHgpL3opLCAwKSwKICAgICAgICAgICAgICAgICAgICAgICBmZ3QgPSBpZmVsc2UoeCA8IHosIGdeYWxwaGEsIDApKSAlPiUKICAgICAgICAgICAgICAgIHN1bW1hcmlzZShmZ3QgPSBzdW0odypmZ3QpLAogICAgICAgICAgICAgICAgICAgICAgICAgIG4gICA9IHN1bSh3KSkKICAgICAgICAKICAgICAgICBkYXRhJGZndC9kYXRhJG4KfQpwb3ZlcnR5X2ZndCh1bmxpc3QoSW5kaWNlX05vQWdyb19BZ3JlZ2FkbyRJbmdyZXNvX1RyaV9Qcm9tKSwzOTk3LjI0LHc9TlVMTCxhbHBoYT0wKQpGR1QwX0FncgpGR1QxX0FncgpGR1QyX0FncgpgYGAKCgoKCgo=