3. Ejercicios de Regresión Lineal Simple (segunda parte)
Ejercicio 3.1 Medidas del cuerpo, Parte IV. Base de datos bdims del paquete openintro.
- Compare los ajustes realizados en los ejercicios 2.1 y 2.2.
- modelo 2.1:
- formula = wgt ~ hip.gi
- \(R^2\) 0.5821
- modelo 2.2:
- formula = wgt ~ hgt
- \(R^2\) 0.5145
El modelo wgt ~ hip.gi es mejor, porque tiene un mejor \(R^2\)
b)Para el ajuste del peso usando la circunferencia de cadera como única covariable, halle un intervalo de confianza de nivel 0.95 cuando el contorno de cadera mide 100 cm. Compárelo con el intervalo de predicción para ese mismo contorno de cadera.
lm_fitted <- lm(wgt~hip.gi,data =bdims )
new <- data.frame(hip.gi = 100)
#intervalo de confianza
predict.lm(lm_fitted,newdata = new,interval="confidence",level = 0.95)
fit lwr upr
1 74.20646 73.36492 75.048
#intervalo de predicción
predict.lm(lm_fitted,newdata = new,interval="prediction",level = 0.95)
fit lwr upr
1 74.20646 57.21927 91.19365
- Para el ajuste del peso usando la altura como única covariable, halle un intervalo de confianza de nivel 0.95 cuando la altura es de 176 cm. Compárelo con el intervalo de predicción para esa misma altura. ¿Cuál de los dos modelos da un intervalo de predicción más útil?
lm_fitted <- lm(wgt~hgt,data =bdims )
new <- data.frame(hgt = 176)
#intervalo de confianza
predict.lm(lm_fitted,newdata = new,interval="confidence",level = 0.95)
fit lwr upr
1 74.0893 73.17511 75.00349
#intervalo de predicción
predict.lm(lm_fitted,newdata = new,interval="prediction",level = 0.95)
fit lwr upr
1 74.0893 55.77921 92.39939
Es más útil el primer modelo, de la circunferencia de la cadera, porque el intervalo de predicción, a un mismo nivel de significatividad, es más acotado.
- Construya un intervalo de confianza para el peso esperado cuando el contorno de cintura es de 80cm.,95cm., 125cm. de nivel 0.95. Estos tres intervalos, ¿tienen nivel simultáneo 0.95? Es decir, la siguiente afirmación ¿es verdadera o falsa? Justifique. En aproximadamente 95 de cada 100 veces que yo construya los IC basados en una (misma) muestra, cada uno de los 3 IC contendrán al verdadero valor esperado del peso.
lm_fitted <- lm(wgt~hip.gi,data =bdims )
new <- data.frame(hip.gi = c(80,95,125))
#intervalo de confianza
predict.lm(lm_fitted,newdata = new,interval="confidence",level = 0.95)
fit lwr upr
1 43.72306 41.69463 45.75148
2 66.58561 65.80858 67.36264
3 112.31071 109.02587 115.59554
Es falso, no tienen un nivel de confianza simultaneo del 95%, porque no son independientes los test, al tratarse de una misma muestra.
Ejercicio 3.2: heights.txt
- Realice un scatterplot de los datos, con la altura de las madres en el eje horizontal.
library(alr3)
Loading required package: car
Attaching package: ‘car’
The following object is masked from ‘package:openintro’:
densityPlot
The following object is masked from ‘package:dplyr’:
recode
The following object is masked from ‘package:purrr’:
some
height.plot <- ggplot(heights, aes(Mheight,Dheight)) +
geom_point()+
geom_abline(colour="firebrick", size =1)+
theme_minimal()+
lims(x = c(55,75), y = c(55,75))
height.plot
¿Describe esta figura un buen resumen de la relación entre ambas variables? Si, aunque pareciera que existe una tendencia a que las hijas sean más altas que las madres.
En base al scatterplot, ¿parecería ser cierto que las madres más altas suelen tener hijas más altas y viceversa con las más bajas? Si b) Ajuste el modelo lineal a los datos. Indique el valor de la recta ajustada. Superpóngala al scatter plot.
lm.ajustado <- lm(Dheight~Mheight,data = heights)
lm.ajustado
Call:
lm(formula = Dheight ~ Mheight, data = heights)
Coefficients:
(Intercept) Mheight
29.9174 0.5417
#intervalo de confianza para la pendiente
height.plot+ geom_smooth(method = "lm", se = FALSE)
¿Presenta visualmente un mejor ajuste que la recta identidad postulada en el ítem anterior? si
#coeficientes, errores estandar, coeficientes de determinación
summary(lm.ajustado)
Call:
lm(formula = Dheight ~ Mheight, data = heights)
Residuals:
Min 1Q Median 3Q Max
-7.397 -1.529 0.036 1.492 9.053
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 29.91744 1.62247 18.44 <2e-16 ***
Mheight 0.54175 0.02596 20.87 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 2.266 on 1373 degrees of freedom
Multiple R-squared: 0.2408, Adjusted R-squared: 0.2402
F-statistic: 435.5 on 1 and 1373 DF, p-value: < 2.2e-16
# varianza de los errores
anova(lm.ajustado)
Analysis of Variance Table
Response: Dheight
Df Sum Sq Mean Sq F value Pr(>F)
Mheight 1 2236.7 2236.66 435.47 < 2.2e-16 ***
Residuals 1373 7052.0 5.14
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
confint(lm.ajustado,level = 0.95,parm = 2)
2.5 % 97.5 %
Mheight 0.4908201 0.5926739
El p-valor del test t para \(\beta_0\) es <2e-16, por lo que rechazamos la hipótesis nula de que \(E(Dheight |Mheight) = \beta_0\), esto implica que el incremento de la altura de la madre es significativa para la altura esperada de la hija
- Prediga y obtenga un intervalo de predicción para la altura de una hija cuya madre mide 64 pulgadas.
new <- data.frame(Mheight = 64, Dheight = NA)
predict.lm(lm.ajustado,newdata = new,interval="confidence",level = 0.95)
fit lwr upr
1 64.58925 64.44578 64.73271
- Una pulgada equivale a 2.54cm. Convierta ambas variables a centímetros (Dheightcm y Mheightcm) y ajuste un modelo lineal a estas nuevas variables.
heights <- heights %>%
mutate(Mheightcm = Mheight/2.54,
Dheightcm = Dheight/2.54)
lm.ajustado.cm <- lm(Dheightcm~Mheightcm,data = heights)
# Ajuste en cm
summary(lm.ajustado.cm)
Call:
lm(formula = Dheightcm ~ Mheightcm, data = heights)
Residuals:
Min 1Q Median 3Q Max
-2.9124 -0.6018 0.0142 0.5874 3.5640
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 11.77852 0.63877 18.44 <2e-16 ***
Mheightcm 0.54175 0.02596 20.87 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.8922 on 1373 degrees of freedom
Multiple R-squared: 0.2408, Adjusted R-squared: 0.2402
F-statistic: 435.5 on 1 and 1373 DF, p-value: < 2.2e-16
# Ajuste en pulgadas
summary(lm.ajustado)
Call:
lm(formula = Dheight ~ Mheight, data = heights)
Residuals:
Min 1Q Median 3Q Max
-7.397 -1.529 0.036 1.492 9.053
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 29.91744 1.62247 18.44 <2e-16 ***
Mheight 0.54175 0.02596 20.87 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 2.266 on 1373 degrees of freedom
Multiple R-squared: 0.2408, Adjusted R-squared: 0.2402
F-statistic: 435.5 on 1 and 1373 DF, p-value: < 2.2e-16
preguntas
- ¿Deberían cambiar los estimadores de \(\beta_0\) y \(\beta_1\)?
- Si la ordenada al origen, \(\beta_0\), no \(\beta_1\) porque es independiente de las unidades de medida
- ¿De qué manera?
- \(\beta_0\) tiene que ser en cm 2,54 veces menor que en pulgadas
- ¿Y los errores estándares?
- ¿Y los p-valores?
- ¿Y el coeficiente de determinación?
- ¿Y la estimación del desvío estándar de los errores?
- tiene que ser en cm 2,54 veces menor que en pulgadas
Ejercicio 3.3. Simulación 1.
- Generar n = 22 datos que sigan el modelo lineal simple \[ Y = 10 + 5X + \epsilon \]
\(\epsilon \sim \mathcal{N}(0,\,\sigma^{2}).\) con \(\sigma^2=49\)
set.seed(54321)
epsilon <- rnorm(n = 22,sd = 7)
densityPlot(epsilon, col="lightcoral")
X <- round(runif(n = 22, min = 0, max = 10),2)
Y <- 10 + 5*X + epsilon
XY <- data.frame(X=X, Y=Y)
ggplot(XY, aes(X,Y)) + geom_point()
- Ajuste el modelo lineal
ajuste <- lm(Y~X, data = XY)
summary(ajuste)
Call:
lm(formula = Y ~ X, data = XY)
Residuals:
Min 1Q Median 3Q Max
-18.645 -7.530 1.272 7.506 16.880
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 13.2363 3.9821 3.324 0.00338 **
X 4.6735 0.7081 6.600 1.99e-06 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 9.299 on 20 degrees of freedom
Multiple R-squared: 0.6853, Adjusted R-squared: 0.6696
F-statistic: 43.56 on 1 and 20 DF, p-value: 1.986e-06
confint(ajuste)
2.5 % 97.5 %
(Intercept) 4.929862 21.542819
X 3.196389 6.150661
preguntas:
- ¿Los verdaderos \(\beta_0\) y \(\beta_1\) pertenecen a dichos intervalos?
- ¿Cuánto dio la pendiente estimada, \(\hat{\beta_1}\)?
- ¿En qué parte de la salida del ajuste lineal podemos encontrar el estimador de \(\sigma\)? * en el Residual standard error se indica \(\sigma\)
- ¿Cuánto debería valer?
- Pídamosle al R que chequee si el 5 pertenece al IC de nivel 0.95 calculado en base a la muestra.
beta1est <- 5 > confint(ajuste, parm = 2)[1] & 5 < confint(ajuste, parm = 2)[2]
beta1est
[1] TRUE
- Superpóngale al scatterplot de los datos la recta verdadera (en azul) y la estimada en base a ellos (en rojo).
ggplot(XY, aes(X,Y)) +
geom_point()+
geom_smooth(method = "lm",color="firebrick",se = FALSE)+
geom_abline(slope =5,intercept = 10, color = "steelblue", size = 1)
Ejercicio 3.4 Simulación 2.
1000 repeticiones del ejercicio anterior
- ¿Puede usted anticipar, desde la teoría las respuestas de las preguntas que siguen?
- Las pendientes estimadas en las B = 1000 replicaciones, ¿serán siempre iguales o cambiarán de replicación en replicación?
- ¿Alrededor de qué número variarán las pendientes estimadas en las 1000 replicaciones?
- Si hacemos un histograma de estas B = 1000 replicaciones, ¿a qué distribución debería parecerse?
- \(\beta_1 \sim \mathcal{N}(5,\,\sigma_b^{2}).\)
- Aproximadamente, ¿qué porcentaje de los 1000 intervalos de confianza para la pendiente estimados a partir de las 1000 muestras cubrirá al verdadero valor de la pendiente?
beta1est <- rep(NA,1000)
icbet <- rep(NA,1000)
set.seed(54321)
X <- round(runif(n = 22, min = 0, max = 10),2)
for(i in 1:1000){
epsilon <- rnorm(n = 22,sd = 7)
Y <- 10 + 5*X + epsilon
XY <- data.frame(X=X, Y=Y)
ajuste <- lm(Y~X, data = XY)
beta1est[i] <- ajuste$coefficients[2]
icbet[i] <- 5 > confint(ajuste, parm = 2)[1] & 5 < confint(ajuste, parm = 2)[2]
}
- Haga un histograma de las pendientes estimadas. ¿Qué distribución parecen tener los datos?
ggplot(as.data.frame(beta1est), aes(beta1est))+
geom_histogram(fill='aquamarine3',color="gray40", alpha=0.75)+
geom_vline(xintercept = mean(beta1est), linetype ="dashed")+
theme_light()
Tienen una distribución aproximadamente normal, con media 5.0062792
- ¿Qué proporción de los intervalos de conanza construidos contiene al verdadero valor de la pendiente?
sum(icbet)/length(icbet)
[1] 0.942
Ejercicio 3.5 Mamíferos, Parte IV.conjunto de datos mammals del paquete openintro.
- Si dos animales difieren en el BodyWt por un factor de diez, dé un intervalo del 95% de confianza para la diferencia en el log10(BrainWt) para estos dos animales.
lm_fitted <- lm(logBrainWt ~ logBodyWt, data = mammals)
confint(lm_fitted)[2,]
2.5 % 97.5 %
0.6947503 0.8086215
- Para un mamífero que no está en la base de datos, cuyo peso corporal es de 100 kg., obtenga la predicción y un intervalo de nivel 95% de predicción del log10 (BrainWt) :
nuevo <- data.frame(logBodyWt = log10(100), logBrainWt = NA)
predict.lm(lm_fitted,newdata = nuevo,interval="prediction",level = 0.95)
fit lwr upr
1 3.638161 2.237701 5.03862
intervalo de predicción del peso del cerebro del mamífero cuyo peso corporal es 100kg. Mirando los valores numéricos obtenidos, ¿parece muy útil el resultado obtenido?
10^predict.lm(lm_fitted,newdata = nuevo,interval="prediction",level = 0.95)[2:3]
[1] 172.8626 109299.9493
No es útil el resultado obtenido.
Ejercicio 3.6. wblake
- Hacer un scatter plot de la longitud (Length) en función de la edad (Age).
ggplot(wblake, aes(Age, Length))+geom_point()
La variable años es discreta
- Calcule las medias y los desvíos estándares muestrales para cada uno de las ocho subpoblaciones
wblake %>%
group_by(Age) %>%
summarise(media = mean(Length),
desvio_estandar = sd(Length))
ggplot(wblake, aes(Age, Length, fill = as.factor(Age), group = Age))+
geom_boxplot()+
theme_minimal()+
theme(legend.position = "none")
La longitud, ¿parece aumentar con la edad? si
La dispersión de la longitud, ¿parece mantenerse más o menos constante con la edad? ? ¿O crece? ¿O decrece? se mantiene constante
- Ajuste un modelo lineal para explicar la longitud (Length) en función de la edad (Age).
ajuste <- lm(Length ~ Age, data = wblake)
summary(ajuste)
Call:
lm(formula = Length ~ Age, data = wblake)
Residuals:
Min 1Q Median 3Q Max
-85.794 -19.499 -4.499 16.177 94.853
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 65.5272 3.1974 20.49 <2e-16 ***
Age 30.3239 0.6877 44.09 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 28.65 on 437 degrees of freedom
Multiple R-squared: 0.8165, Adjusted R-squared: 0.8161
F-statistic: 1944 on 1 and 437 DF, p-value: < 2.2e-16
¿Resulta significativa la pendiente?
si
Resuma la bondad del ajuste con el R2:
el modelo explica un 82% de la variabilidad del largo
Superponga la recta estimada al gráfico de dispersión, y también las medias muestrales por grupos.
ggplot(wblake, aes(Age, Length))+
geom_point()+
geom_smooth(method = "lm", se = FALSE)+
geom_boxplot(aes( color = as.factor(Age), fill=NULL, group = Age), alpha=0.5)+
theme_minimal()+
theme(legend.position = "none")
Halle el estimador de \(\sigma\) que proporciona el modelo lineal.
sigma(ajuste)
[1] 28.64585
¿A qué valor debiera parecerse?
se debe parecer al Residual standard error
¿Se parece?
si
sd(wblake$Length)
[1] 66.79134
¿Le parece que el ajuste obtenido por el modelo lineal es satisfactorio?
si
- Obtenga intervalos de confianza de nivel 95% para la longitud media a edades 2, 4 y 6 años
new <- data.frame(Age = c(2,4,6))
#intervalo de confianza
predict.lm(ajuste,newdata = new,interval="confidence",level = 0.95)
fit lwr upr
1 126.1749 122.1643 130.1856
2 186.8227 184.1217 189.5237
3 247.4705 243.8481 251.0929
¿Sería correcto obtener IC para la longitud media a los 9 años con este conjunto de datos?
implicaría realizar una extrapolación de los resultados.
LS0tCnRpdGxlOiAiRWplcmNpY2lvcyBtb2RlbG8gbGluZWFsLiBJSUkiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCi0tLQoKCiMgMy4gRWplcmNpY2lvcyBkZSBSZWdyZXNpw7NuIExpbmVhbCBTaW1wbGUgKHNlZ3VuZGEgcGFydGUpCiAgCiMjIyBFamVyY2ljaW8gMy4xIE1lZGlkYXMgZGVsIGN1ZXJwbywgUGFydGUgSVYuIEJhc2UgZGUgZGF0b3MgYmRpbXMgZGVsIHBhcXVldGUgb3BlbmludHJvLiAKIGEpIENvbXBhcmUgbG9zIGFqdXN0ZXMgcmVhbGl6YWRvcyBlbiBsb3MgZWplcmNpY2lvcyAyLjEgeSAyLjIuCgoqIF9fbW9kZWxvIDIuMV9fOgogICAgICArIGZvcm11bGEgPSB3Z3QgfiBoaXAuZ2kKICAgICAgKyAkUl4yJCAgMC41ODIxCiogX19tb2RlbG8gMi4yX186CiAgICAgICsgZm9ybXVsYSA9IHdndCB+IGhndAogICAgICArICRSXjIkICAwLjUxNDUKIAogRWwgbW9kZWxvIHdndCB+IGhpcC5naSBlcyBtZWpvciwgcG9ycXVlIHRpZW5lIHVuIG1lam9yICRSXjIkCiAKIGIpUGFyYSBlbCBhanVzdGUgZGVsIHBlc28gdXNhbmRvIGxhIGNpcmN1bmZlcmVuY2lhIGRlIGNhZGVyYSBjb21vIMO6bmljYSBjb3ZhcmlhYmxlLCBoYWxsZSB1biBpbnRlcnZhbG8gZGUgY29uZmlhbnphIGRlIG5pdmVsIDAuOTUgY3VhbmRvIGVsIGNvbnRvcm5vIGRlIGNhZGVyYSBtaWRlIDEwMCBjbS4gQ29tcMOhcmVsbyBjb24gZWwgaW50ZXJ2YWxvIGRlIHByZWRpY2Npw7NuIHBhcmEgZXNlIG1pc21vIGNvbnRvcm5vIGRlIGNhZGVyYS4KYGBge3J9CmxtX2ZpdHRlZCA8LSBsbSh3Z3R+aGlwLmdpLGRhdGEgPWJkaW1zICkKbmV3IDwtIGRhdGEuZnJhbWUoaGlwLmdpID0gMTAwKQojaW50ZXJ2YWxvIGRlIGNvbmZpYW56YQpwcmVkaWN0LmxtKGxtX2ZpdHRlZCxuZXdkYXRhID0gbmV3LGludGVydmFsPSJjb25maWRlbmNlIixsZXZlbCA9IDAuOTUpCiNpbnRlcnZhbG8gZGUgcHJlZGljY2nDs24KcHJlZGljdC5sbShsbV9maXR0ZWQsbmV3ZGF0YSA9IG5ldyxpbnRlcnZhbD0icHJlZGljdGlvbiIsbGV2ZWwgPSAwLjk1KQoKYGBgCgogYykgUGFyYSBlbCBhanVzdGUgZGVsIHBlc28gdXNhbmRvIGxhIGFsdHVyYSBjb21vIMO6bmljYSBjb3ZhcmlhYmxlLCBoYWxsZSB1biBpbnRlcnZhbG8gZGUgY29uZmlhbnphIGRlIG5pdmVsIDAuOTUgY3VhbmRvIGxhIGFsdHVyYSBlcyBkZSAxNzYgY20uIENvbXDDoXJlbG8gY29uIGVsIGludGVydmFsbyBkZSBwcmVkaWNjacOzbiBwYXJhIGVzYSBtaXNtYSBhbHR1cmEuIMK/Q3XDoWwgZGUgbG9zIGRvcyBtb2RlbG9zIGRhIHVuIGludGVydmFsbyBkZSBwcmVkaWNjacOzbiBtw6FzIMO6dGlsPwogIApgYGB7cn0KbG1fZml0dGVkIDwtIGxtKHdndH5oZ3QsZGF0YSA9YmRpbXMgKQpuZXcgPC0gZGF0YS5mcmFtZShoZ3QgPSAxNzYpCiNpbnRlcnZhbG8gZGUgY29uZmlhbnphCnByZWRpY3QubG0obG1fZml0dGVkLG5ld2RhdGEgPSBuZXcsaW50ZXJ2YWw9ImNvbmZpZGVuY2UiLGxldmVsID0gMC45NSkKI2ludGVydmFsbyBkZSBwcmVkaWNjacOzbgpwcmVkaWN0LmxtKGxtX2ZpdHRlZCxuZXdkYXRhID0gbmV3LGludGVydmFsPSJwcmVkaWN0aW9uIixsZXZlbCA9IDAuOTUpCgpgYGAKCkVzIG3DoXMgw7p0aWwgZWwgcHJpbWVyIG1vZGVsbywgZGUgbGEgY2lyY3VuZmVyZW5jaWEgZGUgbGEgY2FkZXJhLCBwb3JxdWUgZWwgaW50ZXJ2YWxvIGRlIHByZWRpY2Npw7NuLCBhIHVuIG1pc21vIG5pdmVsIGRlIHNpZ25pZmljYXRpdmlkYWQsIGVzIG3DoXMgYWNvdGFkby4KCiBkKSBDb25zdHJ1eWEgdW4gaW50ZXJ2YWxvIGRlIGNvbmZpYW56YSBwYXJhIGVsIHBlc28gZXNwZXJhZG8gY3VhbmRvIGVsIGNvbnRvcm5vIGRlIGNpbnR1cmEgZXMgZGUgODBjbS4sOTVjbS4sIDEyNWNtLiBkZSBuaXZlbCAwLjk1LiBFc3RvcyB0cmVzIGludGVydmFsb3MsIMK/dGllbmVuIG5pdmVsIHNpbXVsdMOhbmVvIDAuOTU/IEVzIGRlY2lyLCBsYSBzaWd1aWVudGUgYWZpcm1hY2nDs24gwr9lcyB2ZXJkYWRlcmEgbyBmYWxzYT8gSnVzdGlmaXF1ZS4gRW4gYXByb3hpbWFkYW1lbnRlIDk1IGRlIGNhZGEgMTAwIHZlY2VzIHF1ZSB5byBjb25zdHJ1eWEgbG9zIElDIGJhc2Fkb3MgZW4gdW5hIChtaXNtYSkgbXVlc3RyYSwgY2FkYSB1bm8gZGUgbG9zIDMgSUMgY29udGVuZHLDoW4gYWwgdmVyZGFkZXJvIHZhbG9yIGVzcGVyYWRvIGRlbCBwZXNvLgogIAogIApgYGB7cn0KbG1fZml0dGVkIDwtIGxtKHdndH5oaXAuZ2ksZGF0YSA9YmRpbXMgKQpuZXcgPC0gZGF0YS5mcmFtZShoaXAuZ2kgPSBjKDgwLDk1LDEyNSkpCiNpbnRlcnZhbG8gZGUgY29uZmlhbnphCnByZWRpY3QubG0obG1fZml0dGVkLG5ld2RhdGEgPSBuZXcsaW50ZXJ2YWw9ImNvbmZpZGVuY2UiLGxldmVsID0gMC45NSkKYGBgCkVzIGZhbHNvLCBubyB0aWVuZW4gdW4gbml2ZWwgZGUgY29uZmlhbnphIHNpbXVsdGFuZW8gZGVsIDk1JSwgcG9ycXVlIG5vIHNvbiBpbmRlcGVuZGllbnRlcyBsb3MgdGVzdCwgYWwgdHJhdGFyc2UgZGUgdW5hIG1pc21hIG11ZXN0cmEuCgojIyMgRWplcmNpY2lvIDMuMjogaGVpZ2h0cy50eHQKCmEpIFJlYWxpY2UgdW4gc2NhdHRlcnBsb3QgZGUgbG9zIGRhdG9zLCBjb24gbGEgYWx0dXJhIGRlIGxhcyBtYWRyZXMgZW4gZWwgZWplIGhvcml6b250YWwuCgpgYGB7cn0KbGlicmFyeShhbHIzKQoKaGVpZ2h0LnBsb3QgPC0gIGdncGxvdChoZWlnaHRzLCBhZXMoTWhlaWdodCxEaGVpZ2h0KSkgKwogIGdlb21fcG9pbnQoKSsKICBnZW9tX2FibGluZShjb2xvdXI9ImZpcmVicmljayIsIHNpemUgPTEpKwogIHRoZW1lX21pbmltYWwoKSsKICBsaW1zKHggPSBjKDU1LDc1KSwgeSA9IGMoNTUsNzUpKQpoZWlnaHQucGxvdApgYGAKCsK/RGVzY3JpYmUgZXN0YSBmaWd1cmEgdW4gYnVlbiByZXN1bWVuIGRlIGxhIHJlbGFjacOzbiBlbnRyZSBhbWJhcyB2YXJpYWJsZXM/Cl9fU2lfXywgYXVucXVlIHBhcmVjaWVyYSBxdWUgZXhpc3RlIHVuYSB0ZW5kZW5jaWEgYSBxdWUgbGFzIGhpamFzIHNlYW4gbcOhcyBhbHRhcyBxdWUgbGFzIG1hZHJlcy4KCkVuIGJhc2UgYWwgc2NhdHRlcnBsb3QsIMK/cGFyZWNlcsOtYSBzZXIgY2llcnRvIHF1ZSBsYXMgbWFkcmVzIG3DoXMgYWx0YXMgc3VlbGVuIHRlbmVyIGhpamFzIG3DoXMgYWx0YXMgeSB2aWNldmVyc2EgY29uIGxhcyBtw6FzIGJhamFzPyAKX19TaV9fCmIpIEFqdXN0ZSBlbCBtb2RlbG8gbGluZWFsIGEgbG9zIGRhdG9zLiBJbmRpcXVlIGVsIHZhbG9yIGRlIGxhIHJlY3RhIGFqdXN0YWRhLiBTdXBlcnDDs25nYWxhIGFsIHNjYXR0ZXIgcGxvdC4KCmBgYHtyfQpsbS5hanVzdGFkbyA8LSBsbShEaGVpZ2h0fk1oZWlnaHQsZGF0YSA9IGhlaWdodHMpCmxtLmFqdXN0YWRvCgojaW50ZXJ2YWxvIGRlIGNvbmZpYW56YSBwYXJhIGxhIHBlbmRpZW50ZQpoZWlnaHQucGxvdCsgIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UpCmBgYAoKwr9QcmVzZW50YSB2aXN1YWxtZW50ZSB1biBtZWpvciBhanVzdGUgcXVlIGxhIHJlY3RhIGlkZW50aWRhZCBwb3N0dWxhZGEgZW4gZWwgw610ZW0gYW50ZXJpb3I/Cl9fc2lfXwpgYGB7cn0KI2NvZWZpY2llbnRlcywgZXJyb3JlcyBlc3RhbmRhciwgY29lZmljaWVudGVzIGRlIGRldGVybWluYWNpw7NuCnN1bW1hcnkobG0uYWp1c3RhZG8pCiMgdmFyaWFuemEgZGUgbG9zIGVycm9yZXMKYW5vdmEobG0uYWp1c3RhZG8pCgpjb25maW50KGxtLmFqdXN0YWRvLGxldmVsID0gMC45NSxwYXJtID0gMikKYGBgCgpFbCBwLXZhbG9yIGRlbCB0ZXN0IHQgcGFyYSAkXGJldGFfMCQgZXMgPDJlLTE2LCBwb3IgbG8gcXVlIHJlY2hhemFtb3MgbGEgaGlww7N0ZXNpcyBudWxhIGRlIHF1ZSAkRShEaGVpZ2h0IHxNaGVpZ2h0KSA9ICBcYmV0YV8wJCwgZXN0byBpbXBsaWNhIHF1ZSBlbCBpbmNyZW1lbnRvIGRlIGxhIGFsdHVyYSBkZSBsYSBtYWRyZSBlcyBzaWduaWZpY2F0aXZhIHBhcmEgbGEgYWx0dXJhIGVzcGVyYWRhIGRlIGxhIGhpamEKCmMpIFByZWRpZ2EgeSBvYnRlbmdhIHVuIGludGVydmFsbyBkZSBwcmVkaWNjacOzbiBwYXJhIGxhIGFsdHVyYSBkZSB1bmEgaGlqYSBjdXlhIG1hZHJlIG1pZGUgNjQgcHVsZ2FkYXMuCmBgYHtyfQpuZXcgPC0gZGF0YS5mcmFtZShNaGVpZ2h0ID0gNjQsIERoZWlnaHQgPSBOQSkKcHJlZGljdC5sbShsbS5hanVzdGFkbyxuZXdkYXRhID0gbmV3LGludGVydmFsPSJjb25maWRlbmNlIixsZXZlbCA9IDAuOTUpCmBgYAoKZCkgVW5hIHB1bGdhZGEgZXF1aXZhbGUgYSAyLjU0Y20uIENvbnZpZXJ0YSBhbWJhcyB2YXJpYWJsZXMgYSBjZW50w61tZXRyb3MgKERoZWlnaHRjbSB5IE1oZWlnaHRjbSkgeSBhanVzdGUgdW4gbW9kZWxvIGxpbmVhbCBhIGVzdGFzIG51ZXZhcyB2YXJpYWJsZXMuCgpgYGB7cn0KaGVpZ2h0cyA8LSBoZWlnaHRzICU+JSAKICBtdXRhdGUoTWhlaWdodGNtID0gTWhlaWdodC8yLjU0LAogICAgICAgICBEaGVpZ2h0Y20gPSBEaGVpZ2h0LzIuNTQpCgpsbS5hanVzdGFkby5jbSA8LSBsbShEaGVpZ2h0Y21+TWhlaWdodGNtLGRhdGEgPSBoZWlnaHRzKQoKIyBBanVzdGUgZW4gY20Kc3VtbWFyeShsbS5hanVzdGFkby5jbSkKIyBBanVzdGUgZW4gcHVsZ2FkYXMKc3VtbWFyeShsbS5hanVzdGFkbykKCmBgYAoKX3ByZWd1bnRhc18KCiogwr9EZWJlcsOtYW4gY2FtYmlhciBsb3MgZXN0aW1hZG9yZXMgZGUgJFxiZXRhXzAkIHkgJFxiZXRhXzEkPyAKICAgICAgKiBTaSBsYSBvcmRlbmFkYSBhbCBvcmlnZW4sICRcYmV0YV8wJCwgbm8gJFxiZXRhXzEkIHBvcnF1ZSBlcyBpbmRlcGVuZGllbnRlIGRlIGxhcyB1bmlkYWRlcyBkZSBtZWRpZGEKKiDCv0RlIHF1w6kgbWFuZXJhPyAKICAgICAgKiAkXGJldGFfMCQgdGllbmUgcXVlIHNlciBlbiBjbSAyLDU0IHZlY2VzIG1lbm9yIHF1ZSBlbiBwdWxnYWRhcwoqIMK/WSBsb3MgZXJyb3JlcyBlc3TDoW5kYXJlcz8gCiAgICAgICogZGUgaWd1YWwgbWFuZXJhCiogwr9ZIGxvcyBwLXZhbG9yZXM/CiAgICAgICogbm8gY2FtYmlhbgoqIMK/WSBlbCBjb2VmaWNpZW50ZSBkZSBkZXRlcm1pbmFjacOzbj8gCiAgICAgICogbm8gY2FtYmlhCiogwr9ZIGxhIGVzdGltYWNpw7NuIGRlbCBkZXN2w61vIGVzdMOhbmRhciBkZSBsb3MgZXJyb3Jlcz8KICAgICAgKiB0aWVuZSBxdWUgc2VyIGVuIGNtIDIsNTQgdmVjZXMgbWVub3IgcXVlIGVuIHB1bGdhZGFzCgojIyMgRWplcmNpY2lvIDMuMy4gU2ltdWxhY2nDs24gMS4KCmEpIEdlbmVyYXIgbiA9IDIyIGRhdG9zIHF1ZSBzaWdhbiBlbCBtb2RlbG8gbGluZWFsIHNpbXBsZQogJCQgWSA9IDEwICsgNVggKyBcZXBzaWxvbiAkJAogCiRcZXBzaWxvbiAgXHNpbSBcbWF0aGNhbHtOfSgwLFwsXHNpZ21hXnsyfSkuJCBjb24gJFxzaWdtYV4yPTQ5JAoKYGBge3J9CnNldC5zZWVkKDU0MzIxKQplcHNpbG9uIDwtIHJub3JtKG4gPSAyMixzZCA9IDcpCmRlbnNpdHlQbG90KGVwc2lsb24sIGNvbD0ibGlnaHRjb3JhbCIpCgpYIDwtIHJvdW5kKHJ1bmlmKG4gPSAyMiwgbWluID0gMCwgbWF4ID0gMTApLDIpClkgPC0gMTAgKyA1KlggKyBlcHNpbG9uClhZIDwtIGRhdGEuZnJhbWUoWD1YLCBZPVkpCmdncGxvdChYWSwgYWVzKFgsWSkpICsgZ2VvbV9wb2ludCgpCmBgYApjKSBBanVzdGUgZWwgbW9kZWxvIGxpbmVhbAoKYGBge3J9CmFqdXN0ZSA8LSBsbShZflgsIGRhdGEgPSBYWSkKCnN1bW1hcnkoYWp1c3RlKQpjb25maW50KGFqdXN0ZSkKCmBgYAoKX19wcmVndW50YXNfXzoKCiogwr9Mb3MgdmVyZGFkZXJvcyAkXGJldGFfMCQgeSAkXGJldGFfMSQgcGVydGVuZWNlbiBhIGRpY2hvcyBpbnRlcnZhbG9zPyAKICAgICogU2kKKiDCv0N1w6FudG8gZGlvIGxhIHBlbmRpZW50ZSBlc3RpbWFkYSwgJFxoYXR7XGJldGFfMX0kPwogICAgKiA4LjQyNwoqIMK/RW4gcXXDqSBwYXJ0ZSBkZSBsYSBzYWxpZGEgZGVsIGFqdXN0ZSBsaW5lYWwgcG9kZW1vcyBlbmNvbnRyYXIgZWwgZXN0aW1hZG9yIGRlICRcc2lnbWEkPyAgICAgKiBlbiBlbCBfUmVzaWR1YWwgc3RhbmRhcmQgZXJyb3JfIHNlIGluZGljYSAkXHNpZ21hJAoqIMK/Q3XDoW50byBkZWJlcsOtYSB2YWxlcj8KICAgICogNwogICAgCmQpIFDDrWRhbW9zbGUgYWwgUiBxdWUgY2hlcXVlZSBzaSBlbCA1IHBlcnRlbmVjZSBhbCBJQyBkZSBuaXZlbCAwLjk1IGNhbGN1bGFkbyBlbiBiYXNlIGEgbGEgbXVlc3RyYS4KCgpgYGB7cn0KYmV0YTFlc3QgPC0gNSA+IGNvbmZpbnQoYWp1c3RlLCBwYXJtID0gMilbMV0gJiA1IDwgY29uZmludChhanVzdGUsIHBhcm0gPSAyKVsyXQpiZXRhMWVzdApgYGAKCmUpIFN1cGVycMOzbmdhbGUgYWwgc2NhdHRlcnBsb3QgZGUgbG9zIGRhdG9zIGxhIHJlY3RhIHZlcmRhZGVyYSAoZW4gYXp1bCkgeSBsYSBlc3RpbWFkYSBlbiBiYXNlIGEgZWxsb3MgKGVuIHJvam8pLgoKYGBge3J9CmdncGxvdChYWSwgYWVzKFgsWSkpICsgCiAgZ2VvbV9wb2ludCgpKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsY29sb3I9ImZpcmVicmljayIsc2UgPSBGQUxTRSkrCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPTUsaW50ZXJjZXB0ID0gMTAsIGNvbG9yID0gInN0ZWVsYmx1ZSIsIHNpemUgPSAxKQoKYGBgCgojIyMgRWplcmNpY2lvIDMuNCBTaW11bGFjacOzbiAyLiAKCjEwMDAgcmVwZXRpY2lvbmVzIGRlbCBlamVyY2ljaW8gYW50ZXJpb3IKCmEpIMK/UHVlZGUgdXN0ZWQgYW50aWNpcGFyLCBkZXNkZSBsYSB0ZW9yw61hIGxhcyByZXNwdWVzdGFzIGRlIGxhcyBwcmVndW50YXMgcXVlIHNpZ3Vlbj8KCgppLiBMYXMgcGVuZGllbnRlcyBlc3RpbWFkYXMgZW4gbGFzIEIgPSAxMDAwIHJlcGxpY2FjaW9uZXMsIMK/c2Vyw6FuIHNpZW1wcmUgaWd1YWxlcyBvIGNhbWJpYXLDoW4gZGUgcmVwbGljYWNpw7NuIGVuIHJlcGxpY2FjacOzbj8KICAgKyBDYW1iaWFuCmlpLiDCv0FscmVkZWRvciBkZSBxdcOpIG7Dum1lcm8gdmFyaWFyw6FuIGxhcyBwZW5kaWVudGVzIGVzdGltYWRhcyBlbiBsYXMgMTAwMCByZXBsaWNhY2lvbmVzPwogICArIDUKaWlpLiBTaSBoYWNlbW9zIHVuIGhpc3RvZ3JhbWEgZGUgZXN0YXMgQiA9IDEwMDAgcmVwbGljYWNpb25lcywgwr9hIHF1w6kgZGlzdHJpYnVjacOzbiBkZWJlcsOtYSBwYXJlY2Vyc2U/CiAgICsgICRcYmV0YV8xICBcc2ltIFxtYXRoY2Fse059KDUsXCxcc2lnbWFfYl57Mn0pLiQKaXYuIEFwcm94aW1hZGFtZW50ZSwgwr9xdcOpIHBvcmNlbnRhamUgZGUgbG9zIDEwMDAgaW50ZXJ2YWxvcyBkZSBjb25maWFuemEgcGFyYSBsYSBwZW5kaWVudGUgZXN0aW1hZG9zIGEgcGFydGlyIGRlIGxhcyAxMDAwIG11ZXN0cmFzIGN1YnJpcsOhIGFsIHZlcmRhZGVybyB2YWxvciBkZSBsYSBwZW5kaWVudGU/CiAgICsgOTUwCgpiKQoKYGBge3J9CmJldGExZXN0IDwtIHJlcChOQSwxMDAwKQppY2JldCA8LSByZXAoTkEsMTAwMCkKCnNldC5zZWVkKDU0MzIxKQpYIDwtIHJvdW5kKHJ1bmlmKG4gPSAyMiwgbWluID0gMCwgbWF4ID0gMTApLDIpCmZvcihpIGluIDE6MTAwMCl7CmVwc2lsb24gPC0gcm5vcm0obiA9IDIyLHNkID0gNykKWSA8LSAxMCArIDUqWCArIGVwc2lsb24KWFkgPC0gZGF0YS5mcmFtZShYPVgsIFk9WSkKCmFqdXN0ZSA8LSBsbShZflgsIGRhdGEgPSBYWSkKCmJldGExZXN0W2ldIDwtIGFqdXN0ZSRjb2VmZmljaWVudHNbMl0KaWNiZXRbaV0gPC0gNSA+IGNvbmZpbnQoYWp1c3RlLCBwYXJtID0gMilbMV0gJiA1IDwgY29uZmludChhanVzdGUsIHBhcm0gPSAyKVsyXQp9CgpgYGAKCmQpIEhhZ2EgdW4gaGlzdG9ncmFtYSBkZSBsYXMgcGVuZGllbnRlcyBlc3RpbWFkYXMuIMK/UXXDqSBkaXN0cmlidWNpw7NuIHBhcmVjZW4gdGVuZXIgbG9zIGRhdG9zPwoKYGBge3J9CmdncGxvdChhcy5kYXRhLmZyYW1lKGJldGExZXN0KSwgYWVzKGJldGExZXN0KSkrCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbD0nYXF1YW1hcmluZTMnLGNvbG9yPSJncmF5NDAiLCBhbHBoYT0wLjc1KSsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBtZWFuKGJldGExZXN0KSwgbGluZXR5cGUgPSJkYXNoZWQiKSsKICB0aGVtZV9saWdodCgpCmBgYAoKClRpZW5lbiB1bmEgZGlzdHJpYnVjacOzbiBhcHJveGltYWRhbWVudGUgbm9ybWFsLCBjb24gbWVkaWEgYGBgciBtZWFuKGJldGExZXN0KWBgYCAKCmUpIMK/UXXDqSBwcm9wb3JjacOzbiBkZSBsb3MgaW50ZXJ2YWxvcyBkZSBjb24cYW56YSBjb25zdHJ1aWRvcyBjb250aWVuZSBhbCB2ZXJkYWRlcm8gdmFsb3IgZGUgbGEgcGVuZGllbnRlPwoKYGBge3J9CnN1bShpY2JldCkvbGVuZ3RoKGljYmV0KQpgYGAKCiMjIyBFamVyY2ljaW8gMy41IE1hbcOtZmVyb3MsIFBhcnRlIElWLmNvbmp1bnRvIGRlIGRhdG9zIG1hbW1hbHMgZGVsIHBhcXVldGUgb3BlbmludHJvLgoKYSkgU2kgZG9zIGFuaW1hbGVzIGRpZmllcmVuIGVuIGVsIEJvZHlXdCBwb3IgdW4gZmFjdG9yIGRlIGRpZXosIGTDqSB1biBpbnRlcnZhbG8KZGVsIDk1JSBkZSBjb25maWFuemEgcGFyYSBsYSBkaWZlcmVuY2lhIGVuIGVsIGxvZzEwKEJyYWluV3QpIHBhcmEgZXN0b3MgZG9zIGFuaW1hbGVzLgoKYGBge3J9CgpsbV9maXR0ZWQgPC0gbG0obG9nQnJhaW5XdCB+IGxvZ0JvZHlXdCwgZGF0YSA9IG1hbW1hbHMpCmNvbmZpbnQobG1fZml0dGVkKVsyLF0KCmBgYAoKCmIpIFBhcmEgdW4gbWFtw61mZXJvIHF1ZSBubyBlc3TDoSBlbiBsYSBiYXNlIGRlIGRhdG9zLCBjdXlvIHBlc28gY29ycG9yYWwgZXMgZGUgMTAwIGtnLiwgb2J0ZW5nYSBsYSBwcmVkaWNjacOzbiB5IHVuIGludGVydmFsbyBkZSBuaXZlbCA5NSUgZGUgcHJlZGljY2nDs24gZGVsIGxvZzEwIChCcmFpbld0KSA6CgoKYGBge3J9Cm51ZXZvIDwtIGRhdGEuZnJhbWUobG9nQm9keVd0ID0gbG9nMTAoMTAwKSwgbG9nQnJhaW5XdCA9IE5BKQoKcHJlZGljdC5sbShsbV9maXR0ZWQsbmV3ZGF0YSA9IG51ZXZvLGludGVydmFsPSJwcmVkaWN0aW9uIixsZXZlbCA9IDAuOTUpCgpgYGAKCmludGVydmFsbyBkZSBwcmVkaWNjacOzbiBkZWwgcGVzbyBkZWwgY2VyZWJybyBkZWwgbWFtw61mZXJvIGN1eW8gcGVzbwpjb3Jwb3JhbCBlcyAxMDBrZy4gTWlyYW5kbyBsb3MgdmFsb3JlcyBudW3DqXJpY29zIG9idGVuaWRvcywgwr9wYXJlY2UgbXV5IMO6dGlsIGVsIHJlc3VsdGFkbyBvYnRlbmlkbz8KCmBgYHtyfQoxMF5wcmVkaWN0LmxtKGxtX2ZpdHRlZCxuZXdkYXRhID0gbnVldm8saW50ZXJ2YWw9InByZWRpY3Rpb24iLGxldmVsID0gMC45NSlbMjozXQpgYGAKCk5vIGVzIMO6dGlsIGVsIHJlc3VsdGFkbyBvYnRlbmlkby4KCiMjIyBFamVyY2ljaW8gMy42LiB3Ymxha2UKCmEpIEhhY2VyIHVuIHNjYXR0ZXIgcGxvdCBkZSBsYSBsb25naXR1ZCAoTGVuZ3RoKSBlbiBmdW5jacOzbiBkZSBsYSBlZGFkIChBZ2UpLgpgYGB7cn0KZ2dwbG90KHdibGFrZSwgYWVzKEFnZSwgTGVuZ3RoKSkrZ2VvbV9wb2ludCgpCmBgYAoKCkxhIHZhcmlhYmxlIGHDsW9zIGVzIGRpc2NyZXRhCgpiKSBDYWxjdWxlIGxhcyBtZWRpYXMgeSBsb3MgZGVzdsOtb3MgZXN0w6FuZGFyZXMgbXVlc3RyYWxlcyBwYXJhIGNhZGEgdW5vIGRlIGxhcyBvY2hvIHN1YnBvYmxhY2lvbmVzCgpgYGB7cn0Kd2JsYWtlICU+JSAKICBncm91cF9ieShBZ2UpICU+JSAKICBzdW1tYXJpc2UobWVkaWEgICA9IG1lYW4oTGVuZ3RoKSwKICAgICAgICAgICAgZGVzdmlvX2VzdGFuZGFyID0gc2QoTGVuZ3RoKSkKCmdncGxvdCh3Ymxha2UsIGFlcyhBZ2UsIExlbmd0aCwgZmlsbCA9IGFzLmZhY3RvcihBZ2UpLCBncm91cCA9IEFnZSkpKwogIGdlb21fYm94cGxvdCgpKwogIHRoZW1lX21pbmltYWwoKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpgYGAKCkxhIGxvbmdpdHVkLCDCv3BhcmVjZSBhdW1lbnRhciBjb24gbGEgZWRhZD8gX19zaV9fICAgIApMYSBkaXNwZXJzacOzbiBkZSBsYSBsb25naXR1ZCwgwr9wYXJlY2UgbWFudGVuZXJzZSBtw6FzIG8gbWVub3MgY29uc3RhbnRlIGNvbiBsYSBlZGFkPyA/IMK/TyBjcmVjZT8gwr9PIGRlY3JlY2U/IF9fc2UgbWFudGllbmUgY29uc3RhbnRlX18KCgpjKSBBanVzdGUgdW4gbW9kZWxvIGxpbmVhbCBwYXJhIGV4cGxpY2FyIGxhIGxvbmdpdHVkIChMZW5ndGgpIGVuIGZ1bmNpw7NuIGRlIGxhIGVkYWQgKEFnZSkuIAoKYGBge3J9CmFqdXN0ZSA8LSBsbShMZW5ndGggfiBBZ2UsIGRhdGEgPSB3Ymxha2UpCnN1bW1hcnkoYWp1c3RlKQpgYGAKCsK/UmVzdWx0YSBzaWduaWZpY2F0aXZhIGxhIHBlbmRpZW50ZT8gICAgICAgCl9fc2lfXyAgIApSZXN1bWEgbGEgYm9uZGFkIGRlbCBhanVzdGUgY29uIGVsIFIyOiAgICAKX19lbCBtb2RlbG8gZXhwbGljYSB1biA4MiUgZGUgbGEgdmFyaWFiaWxpZGFkIGRlbCBsYXJnb19fCgpTdXBlcnBvbmdhIGxhIHJlY3RhIGVzdGltYWRhIGFsIGdyw6FmaWNvIGRlIGRpc3BlcnNpw7NuLCB5IHRhbWJpw6luIGxhcyBtZWRpYXMgbXVlc3RyYWxlcyBwb3IgZ3J1cG9zLgoKYGBge3J9CmdncGxvdCh3Ymxha2UsIGFlcyhBZ2UsIExlbmd0aCkpKwogIGdlb21fcG9pbnQoKSsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFKSsKICBnZW9tX2JveHBsb3QoYWVzKCBjb2xvciA9IGFzLmZhY3RvcihBZ2UpLCBmaWxsPU5VTEwsIGdyb3VwID0gQWdlKSwgYWxwaGE9MC41KSsKICB0aGVtZV9taW5pbWFsKCkrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKCgpgYGAKCkhhbGxlIGVsIGVzdGltYWRvciBkZSAkXHNpZ21hJCBxdWUgcHJvcG9yY2lvbmEgZWwgbW9kZWxvIGxpbmVhbC4KCmBgYHtyfQpzaWdtYShhanVzdGUpCmBgYAoKwr9BIHF1w6kgdmFsb3IgZGViaWVyYSBwYXJlY2Vyc2U/ICAgICAgICAKc2UgZGViZSBwYXJlY2VyIGFsIFJlc2lkdWFsIHN0YW5kYXJkIGVycm9yICAgICAgIArCv1NlIHBhcmVjZT8gICAgICAgCiBfX3NpX18KCmBgYHtyfQpzZCh3Ymxha2UkTGVuZ3RoKQpgYGAKCsK/TGUgcGFyZWNlIHF1ZSBlbCBhanVzdGUgb2J0ZW5pZG8gcG9yIGVsIG1vZGVsbyBsaW5lYWwgZXMgc2F0aXNmYWN0b3Jpbz8gICAgCl9fc2lfXwoKZCkgT2J0ZW5nYSBpbnRlcnZhbG9zIGRlIGNvbmZpYW56YSBkZSBuaXZlbCA5NSUgcGFyYSBsYSBsb25naXR1ZCBtZWRpYSBhIGVkYWRlcyAyLCA0IHkgNiBhw7FvcwoKYGBge3J9Cm5ldyA8LSBkYXRhLmZyYW1lKEFnZSA9IGMoMiw0LDYpKQojaW50ZXJ2YWxvIGRlIGNvbmZpYW56YQpwcmVkaWN0LmxtKGFqdXN0ZSxuZXdkYXRhID0gbmV3LGludGVydmFsPSJjb25maWRlbmNlIixsZXZlbCA9IDAuOTUpCgpgYGAKCsK/U2Vyw61hIGNvcnJlY3RvIG9idGVuZXIgSUMgcGFyYSBsYSBsb25naXR1ZCBtZWRpYSBhIGxvcyA5IGHDsW9zIGNvbiBlc3RlIGNvbmp1bnRvIGRlIGRhdG9zPyAgCl9faW1wbGljYXLDrWEgcmVhbGl6YXIgdW5hIGV4dHJhcG9sYWNpw7NuIGRlIGxvcyByZXN1bHRhZG9zLl9fCgo=