library(MASS)
library(latex2exp)
library(ggplot2)
library(tibble)
library(dplyr)
library(ggpubr)
library(QuantPsyc)

En el modelo habitual de regresión partimos del supuesto que hay una relación lineal entre la variable \(y\) y los regresores. Sin embargo en algunos casos esta suposición es inadecuada, puesto que por ejemplo si observamos los gráficos de dispersión esta suposición puede no estarse cumpliendo de manera evidente. Para poder solucionar este problema de no linealidad, en algunos casos a estos modelos podemos hacerlos lineales, usando una transformación adecuada.

Quizás nos preguntemos que comportamiento deberíamos observar para poder encontrar una transformación que pueda linealizar el modelo. Antes de mostrar algunos casos comunes en los que podemos transformar, veamos un ejemplo de que va transformar un modelo que a primera vista no es lineal, pero si podemos hacerlo lineal.

Consideremos la función \[y=\beta_0 e^{\beta_1 x}\varepsilon\] Esta función como podemos ver no es linear, pero la podemos transformar en una lineal si aplicamos un logaritmo, con lo que obtenemos \[\ln{y}=\ln{\beta_0 e^{\beta_1 x}\varepsilon}=\ln{\beta_0}+\beta_1 x+\ln{\varepsilon}\] Haciendo \(y'=\ln{y}\), \(\ln{\beta_0}=\beta_0'\), \(\ln{\beta_1}=\beta_1'\) y \(\ln{\varepsilon}=\varepsilon'\), tenemos el modelo \[y'=\beta_0'+\beta_1' x+\varepsilon'.\] Como podemos observar en esta transformación estamos tomando el logaritmo del error, de modo que si queremos que haya normalidad en los errores de la transformación es decir \(\ln{\varepsilon}\) sea normal distribuido con media \(0\) y varianza \(\sigma^2\), lo que implica que el error multiplicativo en el modelo original \(\varepsilon\), debe tener distribución log normal.

Comentario: De igual forma que en el modelo de regresión simple, cuando linealizamos un modelo es necesario realizar la validación de supuestos.

Funciones Linealizables

Otro ejemplo de modelos que podemos linealizar, son el caso de transformaciones reciprocas, es decir algo de la forma

\[\dfrac{1}{y}=\beta_0+\beta_1 x+\varepsilon\] y \[y=\dfrac{x}{\beta_0 x-\beta_1}+\epsilon\] Comentario: Cuando las transformaciones como las anteriores son empleadas el estimador de mínimos cuadrados tiene propiedades de mínimos cuadrados con respecto a los datos transformados, no a los originales.

Ejemplo (Molino de Viento)

tabla1 <- data.frame(stringsAsFactors=FALSE,
Velocidad_Viento = c(5.00, 6.00, 3.40, 2.70,
      10.00, 9.70, 9.55, 3.05, 8.15, 6.20, 2.90, 6.35, 4.60, 5.80, 7.40, 3.60,
      7.85, 8.80, 7.00, 5.45, 9.10, 10.20, 4.10, 3.95, 2.45),
Salida_DC = c(1.582, 1.822, 1.057, 0.500, 2.236, 2.386, 2.294, 0.558, 2.166, 1.866,
     0.653, 1.930, 1.562, 1.737, 2.088, 1.137, 2.179, 2.112, 1.800, 1.501, 2.303,
     2.310, 1.194, 1.144, 0.123)
)
names(tabla1)<-c("Velocidad del Viento (Mph)","Salida DC")
tabla1

Un ingeniero, está investigando el uso de un molino de viento para generar electricidad. Ha recopilado datos sobre la salida de DC de su molino de viento y la velocidad del viento correspondiente. La inspección del diagrama de dispersión indica que la relación entre la salida de DC \((y)\) y la velocidad del viento \((x)\) puede ser no lineal como veremos a continuación del gráfico de dispersión.

plot(tabla1$`Velocidad del Viento (Mph)`,tabla1$`Salida DC`,xlab=TeX(r'(Velocidad del Viento $x$ )'),ylab=TeX(r'(Salida DC $y$)'),pch=20,cex=2)

mult.norm(tabla1)$test
NULL

Como se puede observar del gráfico de dispersión, pareciera que la relación entre la salida del voltaje en función de la velocidad del viento es no lineal. Lo cual podemos contrastar con el trafico de residuales.

Para ellos,a justando un modelo lineal obtenemos

modelo1<-lm(tabla1$`Salida DC`~tabla1$`Velocidad del Viento (Mph)`)
summary(modelo1)

Call:
lm(formula = tabla1$`Salida DC` ~ tabla1$`Velocidad del Viento (Mph)`)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.59869 -0.14099  0.06059  0.17262  0.32184 

Coefficients:
                                    Estimate Std. Error
(Intercept)                          0.13088    0.12599
tabla1$`Velocidad del Viento (Mph)`  0.24115    0.01905
                                    t value Pr(>|t|)    
(Intercept)                           1.039     0.31    
tabla1$`Velocidad del Viento (Mph)`  12.659 7.55e-12 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.2361 on 23 degrees of freedom
Multiple R-squared:  0.8745,    Adjusted R-squared:  0.869 
F-statistic: 160.3 on 1 and 23 DF,  p-value: 7.546e-12
shapiro.test(modelo1$residuals)

    Shapiro-Wilk normality test

data:  modelo1$residuals
W = 0.93587, p-value = 0.1188
plot(modelo1$fitted.values,modelo1$residuals,pch=19,xlab="Ajustado",ylab="Residuales")


qqnorm(y=modelo1$residuals)
qqline(modelo1$residuals)

Este comportamiento observado, hace pensar que en efecto el modelo lineal no es el adecuado y quizás un modelo cuadrático del tipo \[y=\beta_0+\beta_1 x+\beta_2 x^2+\varepsilon\] resulte mejor para explicar la curvatura aparente. Sin embargo podemos observar del diagrama de dispersión que a medida que la velocidad del viento aumenta, la salida de voltaje se acerca un punto extremo de 2.5 , lo cual es consistente con el funcionamiento de un molino de viento. Dado que el modelo cuadrático eventualmente se doblará, esto indicaría que a velocidades mas altas de este punto máximo observado la salida de voltaje disminuiría lo cual, con lo cual nuevamente el modelo cuadrático tampoco seria adecuado para los datos.

Como mencionamos a medida que la velocidad aumenta, la salida de voltaje pareciera alcanzar un punto extremo, de manera que tiende como a estabilizarse, lo que sugiere que una transformación de tipo reciproca sea lo mas adecuada, pues en ellas incorporamos asíntotas, y en este caso buscamos que haya una asíntota superior que se acerque a este valor extremo. Transformando el modelo como \[y=\beta_0+\beta_1 \left(\dfrac{1}{x}\right)+\varepsilon.\] Usando esta transformación veamos su relación mediante el gráfico de dispersión

plot(1/tabla1$`Velocidad del Viento (Mph)`,tabla1$`Salida DC`,xlab=TeX(r'(Velocidad del Viento $x$ )'),ylab=TeX(r'(Salida DC $y$)'),pch=20,cex=2)


ynuevos<-(tabla1$`Salida DC`)^2
#plot(tabla1$`Velocidad del Viento (Mph)`,ynuevos)
#modelo22<-lm(ynuevos~tabla1$`Velocidad del Viento (Mph)`)
#plot(modelo22)

xnuevos<-log(tabla1$`Velocidad del Viento (Mph)`)
modelo222<-lm(tabla1$`Salida DC`~xnuevos)
plot(modelo222)

Ajustando el modelo, tenemos como resultado

tabla2 <- data.frame(stringsAsFactors=FALSE,
Velocidad_Viento = 1/c(5.00, 6.00, 3.40, 2.70,
      10.00, 9.70, 9.55, 3.05, 8.15, 6.20, 2.90, 6.35, 4.60, 5.80, 7.40, 3.60,
      7.85, 8.80, 7.00, 5.45, 9.10, 10.20, 4.10, 3.95, 2.45),
Salida_DC = c(1.582, 1.822, 1.057, 0.500, 2.236, 2.386, 2.294, 0.558, 2.166, 1.866,
     0.653, 1.930, 1.562, 1.737, 2.088, 1.137, 2.179, 2.112, 1.800, 1.501, 2.303,
     2.310, 1.194, 1.144, 0.123)
)
names(tabla2)<-c("Velocidad del Viento (Mph)","Salida DC")
tabla2
modelo2<-lm(tabla2$`Salida DC`~tabla2$`Velocidad del Viento (Mph)`)
summary(modelo2)

Call:
lm(formula = tabla2$`Salida DC` ~ tabla2$`Velocidad del Viento (Mph)`)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.20547 -0.04940  0.01100  0.08352  0.12204 

Coefficients:
                                    Estimate Std. Error
(Intercept)                           2.9789     0.0449
tabla2$`Velocidad del Viento (Mph)`  -6.9345     0.2064
                                    t value Pr(>|t|)    
(Intercept)                           66.34   <2e-16 ***
tabla2$`Velocidad del Viento (Mph)`  -33.59   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.09417 on 23 degrees of freedom
Multiple R-squared:   0.98, Adjusted R-squared:  0.9792 
F-statistic:  1128 on 1 and 23 DF,  p-value: < 2.2e-16
plot(modelo2$fitted.values,rstudent(modelo2),pch=19,xlab="Ajustado",ylab="Residuales")
abline(h=0,lty=2,col="red")

plot(modelo2)

ggqqplot(modelo2$residuals)

#mult.norm(tabla1)$mult.test
Ejemplo Datos MariaJuana

Veamos ahora si podemos aplicar alguna transformación al conjunto de datos de Mariajuana. Recordemos que en este conjunto de datos teníamos en esencia tres subconjuntos a causa de los tres cantidades que se tenían para la dosis. De esta manera es conveniente trabajar con estos tres subconjuntos. Recordemos que las transformaciones que vimos previamente por ahora están limitadas a la regresión lineal simple, con lo cual consideraremos la altura como función de precipitación o como función de la temperatura.

## Carga del conjunto de datos
maria<-read.table("/Users/danimathud/Documents/GitHub/R_projects/ModelosEstadisticos1/Datas/Mariajuana.txt")
maria
NA
## Filtrado
maria_dosis0<-maria %>% filter(Dosis.en.kg==0)
maria_dosis0

maria_dosis1<-maria %>% filter(Dosis.en.kg==1)
maria_dosis1

maria_dosis15<-maria %>% filter(Dosis.en.kg==1.5)
maria_dosis15
par(mfrow=c(1,3))
plot(maria_dosis0[,1:3],lower.panel=NULL,main="Dosis 0")
par(mfrow=c(1,3))

plot(maria_dosis1[,1:3],lower.panel=NULL,main="Dosis 1")
par(mfrow=c(1,3))

plot(maria_dosis15[,1:3],lower.panel=NULL,main="Dosis 1.5")

#plot(maria[,1:3],lower.panel=NULL)
#plot3d(maria[,1:3])

Para este ejemplo consideremos el subconjunto para dosis de 1.5, y veamos para cual resulta mas conveniente una transformación, si para altura en función de temperatura o altura en función de precipitación.

Altura en función de la temperatura

modelo3<-lm(maria_dosis15$Altura.en.cm~maria_dosis15$Temperatura.en.C)
plot(modelo3,pch=19)

shapiro.test(modelo3$residuals)

    Shapiro-Wilk normality test

data:  modelo3$residuals
W = 0.96296, p-value = 0.7156
plot(maria_dosis15$Temperatura.en.C,maria_dosis15$Altura.en.cm,xlab="Temperatura",ylab="Altura",pch=19)
abline(modelo3,col="red")

Como podemos considerando altura en función de temperatura, aunque del gráfico de residuales y QQ pareciera que se cumplen todos los supuestos de regresión lineal y normalidad en los errores, sin embargo podemos ver también, que la recta no se ajusta lo suficientemente bien. Por lo cual podríamos intentar transformar los datos esperando conseguir un mejor resultado en el ajuste del modelo.

Notemos de los datos que la recta que ajustemos tiene parámetro \(\beta_1<0\) y la temperatura que consideramos es positiva, con lo cual podemos observar que nuestros datos, tienen mas parecido con los gráficos b) y d) de la figura mostrada en un inició, así podríamos intentar considerar como transformaciones

\[\log{y}=\log{\beta_0 x^{\beta_1}}=\log{\beta_0}+\beta_1\log{x}\] o \[\log{y}=\log{\beta_0 e^{\beta_1 x}}=\log{\beta_0}+\beta_1 x.\] Veamos cual de estas nos da buenos resultados

y1_tran<-log(maria_dosis15$Altura.en.cm)
x1_tran<-log(maria_dosis15$Temperatura.en.C)
plot(x1_tran,y1_tran,pch=19,main=TeX(r'("Transformando con $y'=\log{(y)}$ y $x'=\log{(x)}$)'),xlab="log(Temperatura)",ylab="log(Altura)")
modelo3_tran1<-lm(y1_tran~x1_tran)
abline(modelo3_tran1,col="blue")

plot(modelo3_tran1,pch=19)

shapiro.test(modelo3_tran1$residuals)

    Shapiro-Wilk normality test

data:  modelo3_tran1$residuals
W = 0.96199, p-value = 0.6981

plot(maria_dosis15$Temperatura.en.C,y1_tran,pch=19,main=TeX(r'("Transformando con $y'=\log{(y)}$)'),ylab="log(Altura)",xlab="Temperatura")
modelo3_tran2<-lm(y1_tran~maria_dosis15$Temperatura.en.C)
abline(modelo3_tran2,col="red")

plot(modelo3_tran2,pch=19)

shapiro.test(modelo3_tran2$residuals)

    Shapiro-Wilk normality test

data:  modelo3_tran2$residuals
W = 0.95863, p-value = 0.637
LS0tCnRpdGxlOiAiU2VjY2lvbiA1LjMgVHJhbnNmb3JtYWNpb25lcyBQYXJhIExpbmVhbGl6YXIgTW9kZWxvcyIKYXV0aG9yOiAiRGFuaWVsIE1hcnRpbmV6IgpvdXRwdXQ6CiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAplZGl0b3Jfb3B0aW9uczoKICBtYXJrZG93bjoKICAgIHdyYXA6IDcyCi0tLQoKYGBge3J9CmxpYnJhcnkoTUFTUykKbGlicmFyeShsYXRleDJleHApCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeSh0aWJibGUpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwdWJyKQpsaWJyYXJ5KFF1YW50UHN5YykKYGBgCgoKCkVuIGVsIG1vZGVsbyBoYWJpdHVhbCBkZSByZWdyZXNpw7NuIHBhcnRpbW9zIGRlbCBzdXB1ZXN0byBxdWUgaGF5IHVuYSByZWxhY2nDs24gbGluZWFsIGVudHJlIGxhIHZhcmlhYmxlICR5JCB5IGxvcyByZWdyZXNvcmVzLiBTaW4gZW1iYXJnbyBlbiBhbGd1bm9zIGNhc29zIGVzdGEgc3Vwb3NpY2nDs24gZXMgaW5hZGVjdWFkYSwgcHVlc3RvIHF1ZSBwb3IgZWplbXBsbyBzaSBvYnNlcnZhbW9zIGxvcyBncsOhZmljb3MgZGUgZGlzcGVyc2nDs24gZXN0YSBzdXBvc2ljacOzbiBwdWVkZSBubyBlc3RhcnNlIGN1bXBsaWVuZG8gZGUgbWFuZXJhIGV2aWRlbnRlLiBQYXJhIHBvZGVyIHNvbHVjaW9uYXIgZXN0ZSBwcm9ibGVtYSBkZSBubyBsaW5lYWxpZGFkLCBlbiBhbGd1bm9zIGNhc29zIGEgZXN0b3MgbW9kZWxvcyBwb2RlbW9zIGhhY2VybG9zIGxpbmVhbGVzLCB1c2FuZG8gdW5hIHRyYW5zZm9ybWFjacOzbiBhZGVjdWFkYS4KClF1aXrDoXMgbm9zIHByZWd1bnRlbW9zIHF1ZSBjb21wb3J0YW1pZW50byBkZWJlcsOtYW1vcyBvYnNlcnZhciBwYXJhIHBvZGVyCmVuY29udHJhciB1bmEgdHJhbnNmb3JtYWNpw7NuIHF1ZSBwdWVkYSBsaW5lYWxpemFyIGVsIG1vZGVsby4gQW50ZXMgZGUKbW9zdHJhciBhbGd1bm9zIGNhc29zIGNvbXVuZXMgZW4gbG9zIHF1ZSBwb2RlbW9zIHRyYW5zZm9ybWFyLCB2ZWFtb3MgdW4KZWplbXBsbyBkZSBxdWUgdmEgdHJhbnNmb3JtYXIgdW4gbW9kZWxvIHF1ZSBhIHByaW1lcmEgdmlzdGEgbm8gZXMKbGluZWFsLCBwZXJvIHNpIHBvZGVtb3MgaGFjZXJsbyBsaW5lYWwuCgpDb25zaWRlcmVtb3MgbGEgZnVuY2nDs24gJCR5PVxiZXRhXzAgZV57XGJldGFfMSB4fVx2YXJlcHNpbG9uJCQgRXN0YQpmdW5jacOzbiBjb21vIHBvZGVtb3MgdmVyIG5vIGVzIGxpbmVhciwgcGVybyBsYSBwb2RlbW9zIHRyYW5zZm9ybWFyIGVuCnVuYSBsaW5lYWwgc2kgYXBsaWNhbW9zIHVuIGxvZ2FyaXRtbywgY29uIGxvIHF1ZSBvYnRlbmVtb3MKJCRcbG57eX09XGxue1xiZXRhXzAgZV57XGJldGFfMSB4fVx2YXJlcHNpbG9ufT1cbG57XGJldGFfMH0rXGJldGFfMSB4K1xsbntcdmFyZXBzaWxvbn0kJApIYWNpZW5kbyAkeSc9XGxue3l9JCwgJFxsbntcYmV0YV8wfT1cYmV0YV8wJyQsICRcbG57XGJldGFfMX09XGJldGFfMSckIHkKJFxsbntcdmFyZXBzaWxvbn09XHZhcmVwc2lsb24nJCwgdGVuZW1vcyBlbCBtb2RlbG8KJCR5Jz1cYmV0YV8wJytcYmV0YV8xJyB4K1x2YXJlcHNpbG9uJy4kJCBDb21vIHBvZGVtb3Mgb2JzZXJ2YXIgZW4gZXN0YQp0cmFuc2Zvcm1hY2nDs24gZXN0YW1vcyB0b21hbmRvIGVsIGxvZ2FyaXRtbyBkZWwgZXJyb3IsIGRlIG1vZG8gcXVlIHNpCnF1ZXJlbW9zIHF1ZSBoYXlhIG5vcm1hbGlkYWQgZW4gbG9zIGVycm9yZXMgZGUgbGEgdHJhbnNmb3JtYWNpw7NuIGVzCmRlY2lyICRcbG57XHZhcmVwc2lsb259JCBzZWEgbm9ybWFsIGRpc3RyaWJ1aWRvIGNvbiBtZWRpYSAkMCQgeSB2YXJpYW56YQokXHNpZ21hXjIkLCBsbyBxdWUgaW1wbGljYSBxdWUgZWwgZXJyb3IgbXVsdGlwbGljYXRpdm8gZW4gZWwgbW9kZWxvCm9yaWdpbmFsICRcdmFyZXBzaWxvbiQsIGRlYmUgdGVuZXIgZGlzdHJpYnVjacOzbiBsb2cgbm9ybWFsLgoKKioqQ29tZW50YXJpbzoqKiogRGUgaWd1YWwgZm9ybWEgcXVlIGVuIGVsIG1vZGVsbyBkZSByZWdyZXNpw7NuIHNpbXBsZSwKY3VhbmRvIGxpbmVhbGl6YW1vcyB1biBtb2RlbG8gZXMgbmVjZXNhcmlvIHJlYWxpemFyIGxhIHZhbGlkYWNpw7NuIGRlCnN1cHVlc3Rvcy4KCiFbRnVuY2lvbmVzIExpbmVhbGl6YWJsZXNdKGltYWdlcy9MaW5lYWxpemFibGVzLTAxLnBuZykKCk90cm8gZWplbXBsbyBkZSBtb2RlbG9zIHF1ZSBwb2RlbW9zIGxpbmVhbGl6YXIsIHNvbiBlbCBjYXNvIGRlCnRyYW5zZm9ybWFjaW9uZXMgcmVjaXByb2NhcywgZXMgZGVjaXIgYWxnbyBkZSBsYSBmb3JtYQoKJCRcZGZyYWN7MX17eX09XGJldGFfMCtcYmV0YV8xIHgrXHZhcmVwc2lsb24kJCB5CiQkeT1cZGZyYWN7eH17XGJldGFfMCB4LVxiZXRhXzF9K1xlcHNpbG9uJCQgKioqQ29tZW50YXJpbzoqKiogQ3VhbmRvIGxhcwp0cmFuc2Zvcm1hY2lvbmVzIGNvbW8gbGFzIGFudGVyaW9yZXMgc29uIGVtcGxlYWRhcyBlbCBlc3RpbWFkb3IgZGUKbcOtbmltb3MgY3VhZHJhZG9zIHRpZW5lIHByb3BpZWRhZGVzIGRlIG3DrW5pbW9zIGN1YWRyYWRvcyBjb24gcmVzcGVjdG8gYSBsb3MgZGF0b3MgdHJhbnNmb3JtYWRvcywgKioqbm8gYSBsb3Mgb3JpZ2luYWxlcyoqKi4KCioqRWplbXBsbyAoTW9saW5vIGRlIFZpZW50bykqKgoKYGBge3J9CnRhYmxhMSA8LSBkYXRhLmZyYW1lKHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UsClZlbG9jaWRhZF9WaWVudG8gPSBjKDUuMDAsIDYuMDAsIDMuNDAsIDIuNzAsCiAgICAgIDEwLjAwLCA5LjcwLCA5LjU1LCAzLjA1LCA4LjE1LCA2LjIwLCAyLjkwLCA2LjM1LCA0LjYwLCA1LjgwLCA3LjQwLCAzLjYwLAogICAgICA3Ljg1LCA4LjgwLCA3LjAwLCA1LjQ1LCA5LjEwLCAxMC4yMCwgNC4xMCwgMy45NSwgMi40NSksClNhbGlkYV9EQyA9IGMoMS41ODIsIDEuODIyLCAxLjA1NywgMC41MDAsIDIuMjM2LCAyLjM4NiwgMi4yOTQsIDAuNTU4LCAyLjE2NiwgMS44NjYsCiAgICAgMC42NTMsIDEuOTMwLCAxLjU2MiwgMS43MzcsIDIuMDg4LCAxLjEzNywgMi4xNzksIDIuMTEyLCAxLjgwMCwgMS41MDEsIDIuMzAzLAogICAgIDIuMzEwLCAxLjE5NCwgMS4xNDQsIDAuMTIzKQopCm5hbWVzKHRhYmxhMSk8LWMoIlZlbG9jaWRhZCBkZWwgVmllbnRvIChNcGgpIiwiU2FsaWRhIERDIikKdGFibGExCmBgYAoKVW4gaW5nZW5pZXJvLCBlc3TDoSBpbnZlc3RpZ2FuZG8gZWwgdXNvIGRlIHVuIG1vbGlubyBkZSB2aWVudG8gcGFyYQpnZW5lcmFyIGVsZWN0cmljaWRhZC4gSGEgcmVjb3BpbGFkbyBkYXRvcyBzb2JyZSBsYSBzYWxpZGEgZGUgREMgZGUgc3UKbW9saW5vIGRlIHZpZW50byB5IGxhIHZlbG9jaWRhZCBkZWwgdmllbnRvIGNvcnJlc3BvbmRpZW50ZS4gTGEKaW5zcGVjY2nDs24gZGVsIGRpYWdyYW1hIGRlIGRpc3BlcnNpw7NuIGluZGljYSBxdWUgbGEgcmVsYWNpw7NuIGVudHJlIGxhCnNhbGlkYSBkZSBEQyAkKHkpJCB5IGxhIHZlbG9jaWRhZCBkZWwgdmllbnRvICQoeCkkIHB1ZWRlIHNlciBubyBsaW5lYWwKY29tbyB2ZXJlbW9zIGEgY29udGludWFjacOzbiBkZWwgZ3LDoWZpY28gZGUgZGlzcGVyc2nDs24uCgpgYGB7cn0KcGxvdCh0YWJsYTEkYFZlbG9jaWRhZCBkZWwgVmllbnRvIChNcGgpYCx0YWJsYTEkYFNhbGlkYSBEQ2AseGxhYj1UZVgocicoVmVsb2NpZGFkIGRlbCBWaWVudG8gJHgkICknKSx5bGFiPVRlWChyJyhTYWxpZGEgREMgJHkkKScpLHBjaD0yMCxjZXg9MikKbXVsdC5ub3JtKHRhYmxhMSkkdGVzdApgYGAKCkNvbW8gc2UgcHVlZGUgb2JzZXJ2YXIgZGVsIGdyw6FmaWNvIGRlIGRpc3BlcnNpw7NuLCBwYXJlY2llcmEgcXVlIGxhCnJlbGFjacOzbiBlbnRyZSBsYSBzYWxpZGEgZGVsIHZvbHRhamUgZW4gZnVuY2nDs24gZGUgbGEgdmVsb2NpZGFkIGRlbAp2aWVudG8gZXMgbm8gbGluZWFsLiBMbyBjdWFsIHBvZGVtb3MgY29udHJhc3RhciBjb24gZWwgdHJhZmljbyBkZQpyZXNpZHVhbGVzLgoKUGFyYSBlbGxvcyxhIGp1c3RhbmRvIHVuIG1vZGVsbyBsaW5lYWwgb2J0ZW5lbW9zCgpgYGB7cn0KbW9kZWxvMTwtbG0odGFibGExJGBTYWxpZGEgRENgfnRhYmxhMSRgVmVsb2NpZGFkIGRlbCBWaWVudG8gKE1waClgKQpzdW1tYXJ5KG1vZGVsbzEpCnNoYXBpcm8udGVzdChtb2RlbG8xJHJlc2lkdWFscykKYGBgCgpgYGB7cn0KcGxvdChtb2RlbG8xJGZpdHRlZC52YWx1ZXMsbW9kZWxvMSRyZXNpZHVhbHMscGNoPTE5LHhsYWI9IkFqdXN0YWRvIix5bGFiPSJSZXNpZHVhbGVzIikKCnFxbm9ybSh5PW1vZGVsbzEkcmVzaWR1YWxzKQpxcWxpbmUobW9kZWxvMSRyZXNpZHVhbHMpCmBgYAoKRXN0ZSBjb21wb3J0YW1pZW50byBvYnNlcnZhZG8sIGhhY2UgcGVuc2FyIHF1ZSBlbiBlZmVjdG8gZWwgbW9kZWxvIGxpbmVhbCBubyBlcyBlbCBhZGVjdWFkbyB5IHF1aXrDoXMgdW4gbW9kZWxvIGN1YWRyw6F0aWNvIGRlbCB0aXBvICQkeT1cYmV0YV8wK1xiZXRhXzEgeCtcYmV0YV8yIHheMitcdmFyZXBzaWxvbiQkCnJlc3VsdGUgbWVqb3IgcGFyYSBleHBsaWNhciBsYSBjdXJ2YXR1cmEgYXBhcmVudGUuIFNpbiBlbWJhcmdvIHBvZGVtb3Mgb2JzZXJ2YXIgZGVsIGRpYWdyYW1hIGRlIGRpc3BlcnNpw7NuIHF1ZSBhIG1lZGlkYSBxdWUgbGEgdmVsb2NpZGFkIGRlbCB2aWVudG8gYXVtZW50YSwgbGEgc2FsaWRhIGRlIHZvbHRhamUgc2UgYWNlcmNhIHVuIHB1bnRvIGV4dHJlbW8gZGUgMi41ICwgbG8gY3VhbCBlcyBjb25zaXN0ZW50ZSBjb24gZWwgZnVuY2lvbmFtaWVudG8gZGUgdW4gbW9saW5vIGRlIHZpZW50by4gRGFkbyBxdWUgZWwgbW9kZWxvIGN1YWRyw6F0aWNvIGV2ZW50dWFsbWVudGUgc2UgZG9ibGFyw6EsIGVzdG8gaW5kaWNhcsOtYSBxdWUgYSB2ZWxvY2lkYWRlcyBtYXMgYWx0YXMgZGUgZXN0ZSBwdW50byBtw6F4aW1vIG9ic2VydmFkbyBsYSBzYWxpZGEgZGUgdm9sdGFqZSBkaXNtaW51aXLDrWEgbG8gY3VhbCwgY29uIGxvIGN1YWwgbnVldmFtZW50ZSBlbCBtb2RlbG8gY3VhZHLDoXRpY28gdGFtcG9jbyBzZXJpYSBhZGVjdWFkbyBwYXJhIGxvcyBkYXRvcy4KCkNvbW8gbWVuY2lvbmFtb3MgYSBtZWRpZGEgcXVlIGxhIHZlbG9jaWRhZCBhdW1lbnRhLCBsYSBzYWxpZGEgZGUgdm9sdGFqZSBwYXJlY2llcmEgYWxjYW56YXIgdW4gcHVudG8gZXh0cmVtbywgZGUgbWFuZXJhIHF1ZSB0aWVuZGUgY29tbyBhIGVzdGFiaWxpemFyc2UsIGxvIHF1ZSBzdWdpZXJlIHF1ZSB1bmEgdHJhbnNmb3JtYWNpw7NuIGRlIHRpcG8gcmVjaXByb2NhIHNlYSBsbyBtYXMgYWRlY3VhZGEsIHB1ZXMgZW4gZWxsYXMgaW5jb3Jwb3JhbW9zIGFzw61udG90YXMsIHkgZW4gZXN0ZSBjYXNvIGJ1c2NhbW9zIHF1ZSBoYXlhIHVuYSBhc8OtbnRvdGEgc3VwZXJpb3IgcXVlIHNlIGFjZXJxdWUgYSBlc3RlIHZhbG9yIGV4dHJlbW8uIFRyYW5zZm9ybWFuZG8gZWwgbW9kZWxvIGNvbW8KJCR5PVxiZXRhXzArXGJldGFfMSBcbGVmdChcZGZyYWN7MX17eH1ccmlnaHQpK1x2YXJlcHNpbG9uLiQkClVzYW5kbyBlc3RhIHRyYW5zZm9ybWFjacOzbiB2ZWFtb3Mgc3UgcmVsYWNpw7NuIG1lZGlhbnRlIGVsIGdyw6FmaWNvIGRlIGRpc3BlcnNpw7NuCgpgYGB7cn0KcGxvdCgxL3RhYmxhMSRgVmVsb2NpZGFkIGRlbCBWaWVudG8gKE1waClgLHRhYmxhMSRgU2FsaWRhIERDYCx4bGFiPVRlWChyJyhWZWxvY2lkYWQgZGVsIFZpZW50byAkeCQgKScpLHlsYWI9VGVYKHInKFNhbGlkYSBEQyAkeSQpJykscGNoPTIwLGNleD0yKQoKeW51ZXZvczwtKHRhYmxhMSRgU2FsaWRhIERDYCleMgojcGxvdCh0YWJsYTEkYFZlbG9jaWRhZCBkZWwgVmllbnRvIChNcGgpYCx5bnVldm9zKQojbW9kZWxvMjI8LWxtKHludWV2b3N+dGFibGExJGBWZWxvY2lkYWQgZGVsIFZpZW50byAoTXBoKWApCiNwbG90KG1vZGVsbzIyKQoKeG51ZXZvczwtbG9nKHRhYmxhMSRgVmVsb2NpZGFkIGRlbCBWaWVudG8gKE1waClgKQptb2RlbG8yMjI8LWxtKHRhYmxhMSRgU2FsaWRhIERDYH54bnVldm9zKQpwbG90KG1vZGVsbzIyMikKYGBgCkFqdXN0YW5kbyBlbCBtb2RlbG8sIHRlbmVtb3MgY29tbyByZXN1bHRhZG8KYGBge3J9CnRhYmxhMiA8LSBkYXRhLmZyYW1lKHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UsClZlbG9jaWRhZF9WaWVudG8gPSAxL2MoNS4wMCwgNi4wMCwgMy40MCwgMi43MCwKICAgICAgMTAuMDAsIDkuNzAsIDkuNTUsIDMuMDUsIDguMTUsIDYuMjAsIDIuOTAsIDYuMzUsIDQuNjAsIDUuODAsIDcuNDAsIDMuNjAsCiAgICAgIDcuODUsIDguODAsIDcuMDAsIDUuNDUsIDkuMTAsIDEwLjIwLCA0LjEwLCAzLjk1LCAyLjQ1KSwKU2FsaWRhX0RDID0gYygxLjU4MiwgMS44MjIsIDEuMDU3LCAwLjUwMCwgMi4yMzYsIDIuMzg2LCAyLjI5NCwgMC41NTgsIDIuMTY2LCAxLjg2NiwKICAgICAwLjY1MywgMS45MzAsIDEuNTYyLCAxLjczNywgMi4wODgsIDEuMTM3LCAyLjE3OSwgMi4xMTIsIDEuODAwLCAxLjUwMSwgMi4zMDMsCiAgICAgMi4zMTAsIDEuMTk0LCAxLjE0NCwgMC4xMjMpCikKbmFtZXModGFibGEyKTwtYygiVmVsb2NpZGFkIGRlbCBWaWVudG8gKE1waCkiLCJTYWxpZGEgREMiKQp0YWJsYTIKYGBgCgoKYGBge3J9Cm1vZGVsbzI8LWxtKHRhYmxhMiRgU2FsaWRhIERDYH50YWJsYTIkYFZlbG9jaWRhZCBkZWwgVmllbnRvIChNcGgpYCkKc3VtbWFyeShtb2RlbG8yKQpgYGAKYGBge3J9CnBsb3QobW9kZWxvMiRmaXR0ZWQudmFsdWVzLHJzdHVkZW50KG1vZGVsbzIpLHBjaD0xOSx4bGFiPSJBanVzdGFkbyIseWxhYj0iUmVzaWR1YWxlcyIpCmFibGluZShoPTAsbHR5PTIsY29sPSJyZWQiKQpwbG90KG1vZGVsbzIpCmdncXFwbG90KG1vZGVsbzIkcmVzaWR1YWxzKQojbXVsdC5ub3JtKHRhYmxhMSkkbXVsdC50ZXN0CmBgYAojIyMjIyAqKkVqZW1wbG8gRGF0b3MgTWFyaWFKdWFuYSoqCgpWZWFtb3MgYWhvcmEgc2kgcG9kZW1vcyBhcGxpY2FyIGFsZ3VuYSB0cmFuc2Zvcm1hY2nDs24gYWwgY29uanVudG8gZGUgZGF0b3MgZGUgTWFyaWFqdWFuYS4gUmVjb3JkZW1vcyBxdWUgZW4gZXN0ZSBjb25qdW50byBkZSBkYXRvcyB0ZW7DrWFtb3MgZW4gZXNlbmNpYSB0cmVzIHN1YmNvbmp1bnRvcyBhIGNhdXNhIGRlIGxvcyB0cmVzIGNhbnRpZGFkZXMgcXVlIHNlIHRlbsOtYW4gcGFyYSBsYSBkb3Npcy4gRGUgZXN0YSBtYW5lcmEgZXMgY29udmVuaWVudGUgdHJhYmFqYXIgY29uIGVzdG9zIHRyZXMgc3ViY29uanVudG9zLiAKUmVjb3JkZW1vcyBxdWUgbGFzIHRyYW5zZm9ybWFjaW9uZXMgcXVlIHZpbW9zIHByZXZpYW1lbnRlIHBvciBhaG9yYSBlc3TDoW4gbGltaXRhZGFzIGEgbGEgcmVncmVzacOzbiBsaW5lYWwgc2ltcGxlLCBjb24gbG8gY3VhbCBjb25zaWRlcmFyZW1vcyBsYSBhbHR1cmEgY29tbyBmdW5jacOzbiBkZSBwcmVjaXBpdGFjacOzbiBvIGNvbW8gZnVuY2nDs24gZGUgbGEgdGVtcGVyYXR1cmEuCgoKYGBge3J9CiMjIENhcmdhIGRlbCBjb25qdW50byBkZSBkYXRvcwptYXJpYTwtcmVhZC50YWJsZSgiL1VzZXJzL2RhbmltYXRodWQvRG9jdW1lbnRzL0dpdEh1Yi9SX3Byb2plY3RzL01vZGVsb3NFc3RhZGlzdGljb3MxL0RhdGFzL01hcmlhanVhbmEudHh0IikKbWFyaWEKCmBgYAoKYGBge3J9CiMjIEZpbHRyYWRvCm1hcmlhX2Rvc2lzMDwtbWFyaWEgJT4lIGZpbHRlcihEb3Npcy5lbi5rZz09MCkKbWFyaWFfZG9zaXMwCgptYXJpYV9kb3NpczE8LW1hcmlhICU+JSBmaWx0ZXIoRG9zaXMuZW4ua2c9PTEpCm1hcmlhX2Rvc2lzMQoKbWFyaWFfZG9zaXMxNTwtbWFyaWEgJT4lIGZpbHRlcihEb3Npcy5lbi5rZz09MS41KQptYXJpYV9kb3NpczE1CmBgYAoKCmBgYHtyfQpwYXIobWZyb3c9YygxLDMpKQpwbG90KG1hcmlhX2Rvc2lzMFssMTozXSxsb3dlci5wYW5lbD1OVUxMLG1haW49IkRvc2lzIDAiKQpwYXIobWZyb3c9YygxLDMpKQpwbG90KG1hcmlhX2Rvc2lzMVssMTozXSxsb3dlci5wYW5lbD1OVUxMLG1haW49IkRvc2lzIDEiKQpwYXIobWZyb3c9YygxLDMpKQpwbG90KG1hcmlhX2Rvc2lzMTVbLDE6M10sbG93ZXIucGFuZWw9TlVMTCxtYWluPSJEb3NpcyAxLjUiKQojcGxvdChtYXJpYVssMTozXSxsb3dlci5wYW5lbD1OVUxMKQojcGxvdDNkKG1hcmlhWywxOjNdKQpgYGAKClBhcmEgZXN0ZSBlamVtcGxvIGNvbnNpZGVyZW1vcyBlbCBzdWJjb25qdW50byBwYXJhIGRvc2lzIGRlIDEuNSwgeSB2ZWFtb3MgcGFyYSBjdWFsIHJlc3VsdGEgbWFzIGNvbnZlbmllbnRlIHVuYSB0cmFuc2Zvcm1hY2nDs24sIHNpIHBhcmEgYWx0dXJhIGVuIGZ1bmNpw7NuIGRlIHRlbXBlcmF0dXJhIG8gYWx0dXJhIGVuIGZ1bmNpw7NuIGRlIHByZWNpcGl0YWNpw7NuLgoKCioqQWx0dXJhIGVuIGZ1bmNpw7NuIGRlIGxhIHRlbXBlcmF0dXJhKioKYGBge3J9Cm1vZGVsbzM8LWxtKG1hcmlhX2Rvc2lzMTUkQWx0dXJhLmVuLmNtfm1hcmlhX2Rvc2lzMTUkVGVtcGVyYXR1cmEuZW4uQykKcGxvdChtb2RlbG8zLHBjaD0xOSkKc2hhcGlyby50ZXN0KG1vZGVsbzMkcmVzaWR1YWxzKQpwbG90KG1hcmlhX2Rvc2lzMTUkVGVtcGVyYXR1cmEuZW4uQyxtYXJpYV9kb3NpczE1JEFsdHVyYS5lbi5jbSx4bGFiPSJUZW1wZXJhdHVyYSIseWxhYj0iQWx0dXJhIixwY2g9MTkpCmFibGluZShtb2RlbG8zLGNvbD0icmVkIikKYGBgCiAKQ29tbyBwb2RlbW9zIGNvbnNpZGVyYW5kbyBhbHR1cmEgZW4gZnVuY2nDs24gZGUgdGVtcGVyYXR1cmEsIGF1bnF1ZSBkZWwgZ3LDoWZpY28gZGUgcmVzaWR1YWxlcyB5IFFRIHBhcmVjaWVyYSBxdWUgc2UgY3VtcGxlbiB0b2RvcyBsb3Mgc3VwdWVzdG9zIGRlIHJlZ3Jlc2nDs24gbGluZWFsIHkgbm9ybWFsaWRhZCBlbiBsb3MgZXJyb3Jlcywgc2luIGVtYmFyZ28gcG9kZW1vcyB2ZXIgdGFtYmnDqW4sIHF1ZSBsYSByZWN0YSBubyBzZSBhanVzdGEgbG8gc3VmaWNpZW50ZW1lbnRlIGJpZW4uIFBvciBsbyBjdWFsIHBvZHLDrWFtb3MgaW50ZW50YXIgdHJhbnNmb3JtYXIgbG9zIGRhdG9zIGVzcGVyYW5kbyBjb25zZWd1aXIgdW4gbWVqb3IgcmVzdWx0YWRvIGVuIGVsIGFqdXN0ZSBkZWwgbW9kZWxvLgoKTm90ZW1vcyBkZSBsb3MgZGF0b3MgcXVlIGxhIHJlY3RhIHF1ZSBhanVzdGVtb3MgdGllbmUgcGFyw6FtZXRybyAkXGJldGFfMTwwJCB5IGxhIHRlbXBlcmF0dXJhIHF1ZSBjb25zaWRlcmFtb3MgZXMgcG9zaXRpdmEsIGNvbiBsbyBjdWFsIHBvZGVtb3Mgb2JzZXJ2YXIgcXVlIG51ZXN0cm9zIGRhdG9zLCB0aWVuZW4gbWFzIHBhcmVjaWRvIGNvbiBsb3MgZ3LDoWZpY29zIGIpIHkgZCkgZGUgbGEgZmlndXJhIG1vc3RyYWRhIGVuIHVuIGluaWNpw7MsIGFzw60gcG9kcsOtYW1vcyBpbnRlbnRhciBjb25zaWRlcmFyIGNvbW8gdHJhbnNmb3JtYWNpb25lcyAKCiQkXGxvZ3t5fT1cbG9ne1xiZXRhXzAgeF57XGJldGFfMX19PVxsb2d7XGJldGFfMH0rXGJldGFfMVxsb2d7eH0kJApvIAogJCRcbG9ne3l9PVxsb2d7XGJldGFfMCBlXntcYmV0YV8xIHh9fT1cbG9ne1xiZXRhXzB9K1xiZXRhXzEgeC4kJApWZWFtb3MgIGN1YWwgZGUgZXN0YXMgbm9zIGRhIGJ1ZW5vcyByZXN1bHRhZG9zIAoKYGBge3J9CnkxX3RyYW48LWxvZyhtYXJpYV9kb3NpczE1JEFsdHVyYS5lbi5jbSkKeDFfdHJhbjwtbG9nKG1hcmlhX2Rvc2lzMTUkVGVtcGVyYXR1cmEuZW4uQykKcGxvdCh4MV90cmFuLHkxX3RyYW4scGNoPTE5LG1haW49VGVYKHInKCJUcmFuc2Zvcm1hbmRvIGNvbiAkeSc9XGxvZ3soeSl9JCB5ICR4Jz1cbG9neyh4KX0kKScpLHhsYWI9ImxvZyhUZW1wZXJhdHVyYSkiLHlsYWI9ImxvZyhBbHR1cmEpIikKbW9kZWxvM190cmFuMTwtbG0oeTFfdHJhbn54MV90cmFuKQphYmxpbmUobW9kZWxvM190cmFuMSxjb2w9ImJsdWUiKQpwbG90KG1vZGVsbzNfdHJhbjEscGNoPTE5KQpzaGFwaXJvLnRlc3QobW9kZWxvM190cmFuMSRyZXNpZHVhbHMpCmBgYApgYGB7cn0KCnBsb3QobWFyaWFfZG9zaXMxNSRUZW1wZXJhdHVyYS5lbi5DLHkxX3RyYW4scGNoPTE5LG1haW49VGVYKHInKCJUcmFuc2Zvcm1hbmRvIGNvbiAkeSc9XGxvZ3soeSl9JCknKSx5bGFiPSJsb2coQWx0dXJhKSIseGxhYj0iVGVtcGVyYXR1cmEiKQptb2RlbG8zX3RyYW4yPC1sbSh5MV90cmFufm1hcmlhX2Rvc2lzMTUkVGVtcGVyYXR1cmEuZW4uQykKYWJsaW5lKG1vZGVsbzNfdHJhbjIsY29sPSJyZWQiKQpwbG90KG1vZGVsbzNfdHJhbjIscGNoPTE5KQpzaGFwaXJvLnRlc3QobW9kZWxvM190cmFuMiRyZXNpZHVhbHMpCmBgYAogCgo=