Los datos

Los datos del fichero EdadPesoGrasas.txt corresponden a tres variables medidas en 25 individuos: edad, peso y cantidad de grasas en sangre. Para leer el fichero de datos y saber los nombres de las variables:

grasas <- read.table('http://verso.mat.uam.es/~joser.berrendero/datos/EdadPesoGrasas.txt', header = TRUE)
names(grasas)
[1] "peso"   "edad"   "grasas"

Con el fin de conocer las relaciones existentes entre cada par de variables podemos representar una matriz de diagramas de dispersión. Al parecer existe una relación lineal bastante clara entre la edad y las grasas, pero no entre los otros dos pares de variables. Por otra parte el fichero contiene un dato atípico.

Para cuantificar el grado de relación lineal, calculamos la matriz de coeficientes de correlación:

cor(grasas)
            peso      edad    grasas
peso   1.0000000 0.2400133 0.2652935
edad   0.2400133 1.0000000 0.8373534
grasas 0.2652935 0.8373534 1.0000000

Cálculo y representacion de la recta de mínimos cuadrados

El comando básico es lm (linear models). El primer argumento de este comando es una fórmula \(y\)~\(x\) en la que se especifica cuál es la variable respuesta o dependiente (\(y\)) y cuál es la variable regresora o independiente (\(x\)). El segundo argumento, llamado data especifica cuál es el fichero en el que se encuentran las variables. El resultado lo guardamos en un objeto llamado regresion. Este objeto es una lista que contiene toda la información relevante sobre el análisis. Mediante el comando summary obtenemos un resumen de los principales resultados:

regresion <- lm(grasas ~ edad, data = grasas)
summary(regresion)

Call:
lm(formula = grasas ~ edad, data = grasas)

Residuals:
    Min      1Q  Median      3Q     Max 
-63.478 -26.816  -3.854  28.315  90.881 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 102.5751    29.6376   3.461  0.00212 ** 
edad          5.3207     0.7243   7.346 1.79e-07 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 43.46 on 23 degrees of freedom
Multiple R-squared:  0.7012,    Adjusted R-squared:  0.6882 
F-statistic: 53.96 on 1 and 23 DF,  p-value: 1.794e-07

Los parámetros de la ecuación de la recta de mínimos cuadrados que relaciona la cantidad de grasas en la sangre en función del peso vienen dados por la columna Estimate de la tabla Coefficients de la salida anterior. Por lo tanto, en este ejemplo la ecuación de la recta de mínimos cuadrados es:

\(y=102.575+5.321x\)

Los siguientes comandos representan la nube de puntos (comando plot) y añaden la representación gráfica de la recta de mínimos cuadrados (comando abline aplicado al objeto generado por lm):

El coeficiente de determinación (es decir, el coeficiente de correlación al cuadrado) mide la bondad del ajuste de la recta a los datos. A partir de la salida anterior, vemos que su valor en este caso es Multiple R-squared: 0.701.

Cálculo de predicciones

Supongamos que queremos utilizar la recta de mínimos cuadrados para predecir la cantidad de grasas para individuos de edades \(31,31,32,…,50\). Basta crear un fichero de datos que contenga las nuevas variables regresoras y usar el comando predict:

nuevas.edades <- data.frame(edad = seq(30, 50))
predict(regresion, nuevas.edades)
       1        2        3        4        5        6        7        8        9 
262.1954 267.5161 272.8368 278.1575 283.4781 288.7988 294.1195 299.4402 304.7608 
      10       11       12       13       14       15       16       17       18 
310.0815 315.4022 320.7229 326.0435 331.3642 336.6849 342.0056 347.3263 352.6469 
      19       20       21 
357.9676 363.2883 368.6090 

Por ejemplo, para un individuo de 30 años, predecimos una cantidad de grasas de 262.2

Inferencia en el modelo de regresión simple

Suponemos ahora que los datos proceden de un modelo de regresión simple de la forma:

\(yi=β0+β1xi+ϵi, i=1,…,n,\)

donde los errores aleatorios \(ϵi\) son independientes con distribución normal de media 0 y varianza \(σ^2\).

Bajo este modelo,

confint(regresion)
                2.5 %     97.5 %
(Intercept) 41.265155 163.885130
edad         3.822367   6.818986
confint(regresion, level = 0.90)
                  5 %       95 %
(Intercept) 51.780153 153.370132
edad         4.079335   6.562018
nuevas.edades <- data.frame(edad = seq(20, 60))
# Grafico de dispersion y recta
plot(grasas$edad, grasas$grasas, xlab='Edad', ylab='Grasas')
abline(regresion)

# Intervalos de confianza de la respuesta media:
# ic es una matriz con tres columnas: la primera es la prediccion, las otras dos son los extremos del intervalo
ic <- predict(regresion, nuevas.edades, interval = 'confidence')
lines(nuevas.edades$edad, ic[, 2], lty = 2)
lines(nuevas.edades$edad, ic[, 3], lty = 2)

# Intervalos de prediccion
ic <- predict(regresion, nuevas.edades, interval = 'prediction')
lines(nuevas.edades$edad, ic[, 2], lty = 2, col = 'red')
lines(nuevas.edades$edad, ic[, 3], lty = 2, col = 'red')

anova(regresion)
Analysis of Variance Table

Response: grasas
          Df Sum Sq Mean Sq F value    Pr(>F)    
edad       1 101933  101933  53.964 1.794e-07 ***
Residuals 23  43444    1889                      
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Diagnóstico del modelo

Los valores ajustados \(\hat{y}_i\) y los residuos \(e_i=\hat{y}_i−y_i\) se pueden obtener con los comandos fitted y residuals respectivamente. Los residuos estandarizados se obtienen con rstandard. Por ejemplo, el siguiente código obtiene una representación de los residuos estandarizados frente a los valores ajustados, que resulta útil al llevar a cabo el diagnóstico del modelo:

No se observa ningún patrón especial, por lo que tanto la homocedasticidad como la linealidad resultan hipótesis razonables.

La hipótesis de normalidad se suele comprobar mediante un QQ plot de los residuos. El siguiente código sirve para obtenerlo:

Dado que los puntos están bastante alineados, la normalidad también parece aceptable.

# Variable regresora (dieño fijo) y parámetros
x = seq(1,10)
beta0 <- 0
beta1 <- 1
sigma <- 0.3

# Genera la variable respuesta
y <- beta0 + beta1*x + rnorm(length(x), sd=sigma)

# Ajusta el modelo
reg <- lm(y~x)

# Extrae el valor de la pendiente estimada
coefficients(reg)[2]
       x 
1.031375 
# Resume el ajuste
summary(reg)

Call:
lm(formula = y ~ x)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.54850 -0.30062 -0.00401  0.17426  0.70650 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) -0.06301    0.27941  -0.226    0.827    
x            1.03138    0.04503  22.904  1.4e-08 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.409 on 8 degrees of freedom
Multiple R-squared:  0.985, Adjusted R-squared:  0.9831 
F-statistic: 524.6 on 1 and 8 DF,  p-value: 1.4e-08
LS0tDQp0aXRsZTogIlJlZ3Jlc2nDs24gTGluZWFsIHNpbXBsZSBjb24gUiINCmF1dGhvcjogIkRhbmllbCBCZW5hdmlkZXMiDQpkYXRlOiAiMTAgZGUganVsaW8gZGUgMjAyNCINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdA0KICBEYW5pZWwgQmVuYXZpZGVzOiBkZWZhdWx0DQogIHBkZl9kb2N1bWVudDogZGVmYXVsdA0KLS0tDQoNCiMjIExvcyBkYXRvcw0KDQpMb3MgZGF0b3MgZGVsIGZpY2hlcm8gRWRhZFBlc29HcmFzYXMudHh0IGNvcnJlc3BvbmRlbiBhIHRyZXMgdmFyaWFibGVzIG1lZGlkYXMgZW4gMjUgaW5kaXZpZHVvczogZWRhZCwgcGVzbyB5IGNhbnRpZGFkIGRlIGdyYXNhcyBlbiBzYW5ncmUuIFBhcmEgbGVlciBlbCBmaWNoZXJvIGRlIGRhdG9zIHkgc2FiZXIgbG9zIG5vbWJyZXMgZGUgbGFzIHZhcmlhYmxlczoNCg0KYGBge3J9DQpncmFzYXMgPC0gcmVhZC50YWJsZSgnaHR0cDovL3ZlcnNvLm1hdC51YW0uZXMvfmpvc2VyLmJlcnJlbmRlcm8vZGF0b3MvRWRhZFBlc29HcmFzYXMudHh0JywgaGVhZGVyID0gVFJVRSkNCm5hbWVzKGdyYXNhcykNCmBgYA0KQ29uIGVsIGZpbiBkZSBjb25vY2VyIGxhcyByZWxhY2lvbmVzIGV4aXN0ZW50ZXMgZW50cmUgY2FkYSBwYXIgZGUgdmFyaWFibGVzIHBvZGVtb3MgcmVwcmVzZW50YXIgdW5hIG1hdHJpeiBkZSBkaWFncmFtYXMgZGUgZGlzcGVyc2nDs24uIEFsIHBhcmVjZXIgZXhpc3RlIHVuYSByZWxhY2nDs24gbGluZWFsIGJhc3RhbnRlIGNsYXJhIGVudHJlIGxhIGVkYWQgeSBsYXMgZ3Jhc2FzLCBwZXJvIG5vIGVudHJlIGxvcyBvdHJvcyBkb3MgcGFyZXMgZGUgdmFyaWFibGVzLiBQb3Igb3RyYSBwYXJ0ZSBlbCBmaWNoZXJvIGNvbnRpZW5lIHVuIGRhdG8gYXTDrXBpY28uDQoNCmBgYHtyfQ0KcGFpcnMoZ3Jhc2FzKQ0KYGBgDQpQYXJhIGN1YW50aWZpY2FyIGVsIGdyYWRvIGRlIHJlbGFjacOzbiBsaW5lYWwsIGNhbGN1bGFtb3MgbGEgbWF0cml6IGRlIGNvZWZpY2llbnRlcyBkZSBjb3JyZWxhY2nDs246DQoNCmBgYHtyfQ0KY29yKGdyYXNhcykNCmBgYA0KIyMgQ8OhbGN1bG8geSByZXByZXNlbnRhY2lvbiBkZSBsYSByZWN0YSBkZSBtw61uaW1vcyBjdWFkcmFkb3MNCg0KRWwgY29tYW5kbyBiw6FzaWNvIGVzIGxtIChsaW5lYXIgbW9kZWxzKS4gRWwgcHJpbWVyIGFyZ3VtZW50byBkZSBlc3RlIGNvbWFuZG8gZXMgdW5hIGbDs3JtdWxhICR5JH4keCQgZW4gbGEgcXVlIHNlIGVzcGVjaWZpY2EgY3XDoWwgZXMgbGEgdmFyaWFibGUgcmVzcHVlc3RhIG8gZGVwZW5kaWVudGUgKCR5JCkgeSBjdcOhbCBlcyBsYSB2YXJpYWJsZSByZWdyZXNvcmEgbyBpbmRlcGVuZGllbnRlICgkeCQpLiBFbCBzZWd1bmRvIGFyZ3VtZW50bywgbGxhbWFkbyBkYXRhIGVzcGVjaWZpY2EgY3XDoWwgZXMgZWwgZmljaGVybyBlbiBlbCBxdWUgc2UgZW5jdWVudHJhbiBsYXMgdmFyaWFibGVzLiBFbCByZXN1bHRhZG8gbG8gZ3VhcmRhbW9zIGVuIHVuIG9iamV0byBsbGFtYWRvIHJlZ3Jlc2lvbi4gRXN0ZSBvYmpldG8gZXMgdW5hIGxpc3RhIHF1ZSBjb250aWVuZSB0b2RhIGxhIGluZm9ybWFjacOzbiByZWxldmFudGUgc29icmUgZWwgYW7DoWxpc2lzLiBNZWRpYW50ZSBlbCBjb21hbmRvIGBzdW1tYXJ5YCBvYnRlbmVtb3MgdW4gcmVzdW1lbiBkZSBsb3MgcHJpbmNpcGFsZXMgcmVzdWx0YWRvczoNCg0KYGBge3J9DQpyZWdyZXNpb24gPC0gbG0oZ3Jhc2FzIH4gZWRhZCwgZGF0YSA9IGdyYXNhcykNCnN1bW1hcnkocmVncmVzaW9uKQ0KYGBgDQpMb3MgcGFyw6FtZXRyb3MgZGUgbGEgZWN1YWNpw7NuIGRlIGxhIHJlY3RhIGRlIG3DrW5pbW9zIGN1YWRyYWRvcyBxdWUgcmVsYWNpb25hIGxhIGNhbnRpZGFkIGRlIGdyYXNhcyBlbiBsYSBzYW5ncmUgZW4gZnVuY2nDs24gZGVsIHBlc28gdmllbmVuIGRhZG9zIHBvciBsYSBjb2x1bW5hIGBFc3RpbWF0ZWAgZGUgbGEgdGFibGEgYENvZWZmaWNpZW50c2AgZGUgbGEgc2FsaWRhIGFudGVyaW9yLiBQb3IgbG8gdGFudG8sIGVuIGVzdGUgZWplbXBsbyBsYSBlY3VhY2nDs24gZGUgbGEgcmVjdGEgZGUgbcOtbmltb3MgY3VhZHJhZG9zIGVzOg0KDQo8Y2VudGVyPiR5PTEwMi41NzUrNS4zMjF4JDwvY2VudGVyPg0KDQoNCkxvcyBzaWd1aWVudGVzIGNvbWFuZG9zIHJlcHJlc2VudGFuIGxhIG51YmUgZGUgcHVudG9zIChjb21hbmRvIHBsb3QpIHkgYcOxYWRlbiBsYSByZXByZXNlbnRhY2nDs24gZ3LDoWZpY2EgZGUgbGEgcmVjdGEgZGUgbcOtbmltb3MgY3VhZHJhZG9zIChjb21hbmRvIGFibGluZSBhcGxpY2FkbyBhbCBvYmpldG8gZ2VuZXJhZG8gcG9yIGBsbWApOg0KDQpgYGB7cn0NCnBsb3QoZ3Jhc2FzJGVkYWQsIGdyYXNhcyRncmFzYXMsIHhsYWI9J0VkYWQnLCB5bGFiPSdHcmFzYXMnKQ0KYWJsaW5lKHJlZ3Jlc2lvbikNCmBgYA0KRWwgY29lZmljaWVudGUgZGUgZGV0ZXJtaW5hY2nDs24gKGVzIGRlY2lyLCBlbCBjb2VmaWNpZW50ZSBkZSBjb3JyZWxhY2nDs24gYWwgY3VhZHJhZG8pIG1pZGUgbGEgYm9uZGFkIGRlbCBhanVzdGUgZGUgbGEgcmVjdGEgYSBsb3MgZGF0b3MuIEEgcGFydGlyIGRlIGxhIHNhbGlkYSBhbnRlcmlvciwgdmVtb3MgcXVlIHN1IHZhbG9yIGVuIGVzdGUgY2FzbyBlcyBgTXVsdGlwbGUgUi1zcXVhcmVkOiAwLjcwMWAuDQoNCiMjIEPDoWxjdWxvIGRlIHByZWRpY2Npb25lcw0KDQpTdXBvbmdhbW9zIHF1ZSBxdWVyZW1vcyB1dGlsaXphciBsYSByZWN0YSBkZSBtw61uaW1vcyBjdWFkcmFkb3MgcGFyYSBwcmVkZWNpciBsYSBjYW50aWRhZCBkZSBncmFzYXMgcGFyYSBpbmRpdmlkdW9zIGRlIGVkYWRlcyAkMzEsMzEsMzIs4oCmLDUwJC4gQmFzdGEgY3JlYXIgdW4gZmljaGVybyBkZSBkYXRvcyBxdWUgY29udGVuZ2EgbGFzIG51ZXZhcyB2YXJpYWJsZXMgcmVncmVzb3JhcyB5IHVzYXIgZWwgY29tYW5kbyBgcHJlZGljdGA6DQoNCmBgYHtyfQ0KbnVldmFzLmVkYWRlcyA8LSBkYXRhLmZyYW1lKGVkYWQgPSBzZXEoMzAsIDUwKSkNCnByZWRpY3QocmVncmVzaW9uLCBudWV2YXMuZWRhZGVzKQ0KYGBgDQpQb3IgZWplbXBsbywgcGFyYSB1biBpbmRpdmlkdW8gZGUgMzAgYcOxb3MsIHByZWRlY2ltb3MgdW5hIGNhbnRpZGFkIGRlIGdyYXNhcyBkZSAyNjIuMg0KDQojIyBJbmZlcmVuY2lhIGVuIGVsIG1vZGVsbyBkZSByZWdyZXNpw7NuIHNpbXBsZQ0KDQpTdXBvbmVtb3MgYWhvcmEgcXVlIGxvcyBkYXRvcyBwcm9jZWRlbiBkZSB1biBtb2RlbG8gZGUgcmVncmVzacOzbiBzaW1wbGUgZGUgbGEgZm9ybWE6DQoNCjxjZW50ZXI+JHlpPc6yMCvOsjF4aSvPtWksIGk9MSzigKYsbiwkPC9jZW50ZXI+ICANCg0KZG9uZGUgbG9zIGVycm9yZXMgYWxlYXRvcmlvcyAkz7VpJCBzb24gaW5kZXBlbmRpZW50ZXMgY29uIGRpc3RyaWJ1Y2nDs24gbm9ybWFsIGRlIG1lZGlhIDAgeSB2YXJpYW56YSAkz4NeMiQuDQoNCkJham8gZXN0ZSBtb2RlbG8sDQoNCi0gTG9zIF9fX2Vycm9yZXMgdMOtcGljb3NfX18gZGUgbG9zIGVzdGltYWRvcmVzIGRlIGxvcyBwYXLDoW1ldHJvcyDOsjAgeSDOsjEgc2UgZW5jdWVudHJhbiBlbiBsYSBjb2x1bW5hIFN0ZCBFcnJvciBkZSBsYSBzYWxpZGEgYW50ZXJpb3IuIEVuIGVsIGVqZW1wbG8sIHN1cyB2YWxvcmVzIHNvbiAyOS42MzggeSAwLjcyNCByZXNwZWN0aXZhbWVudGUuDQoNCi0gTGEgY29sdW1uYSBgdCB2YWx1ZWAgY29udGllbmUgZWwgX19lc3RhZMOtc3RpY28gdF9fLCBlcyBkZWNpciwgY29jaWVudGUgZW50cmUgY2FkYSBlc3RpbWFkb3IgeSBzdSBlcnJvciB0w61waWNvLiBFc3RvcyBjb2NpZW50ZXMgc29uIGxhIGJhc2UgcGFyYSBsbGV2YXIgYSBjYWJvIGxvcyBjb250cmFzdGVzICRIX3swfTrOsl97MH09MCQgeSAkSF8wOs6yXzE9MCQuDQogDQotIExvcyBjb3JyZXNwb25kaWVudGVzIHAtdmFsb3JlcyBhcGFyZWNlbiBlbiBsYSBjb2x1bW5hIGBQcig+fHR8KWAuIEVuIGVzdGUgY2FzbyBzb24gbXV5IHBlcXVlw7FvcyBwb3IgbG8gcXVlIHNlIHJlY2hhemFuIGFtYmFzIGhpcMOzdGVzaXMgcGFyYSBsb3Mgbml2ZWxlcyBkZSBzaWduaWZpY2FjacOzbiBoYWJpdHVhbGVzLg0KDQotIEVsIGVzdGltYWRvciBkZSBsYSBfX2Rlc3ZpYWNpw7NuIHTDrXBpY2EgZGUgbG9zIGVycm9yZXNfXyAkz4MkIGFwYXJlY2UgY29tbyBSZXNpZHVhbCBzdGFuZGFyZCBlcnJvciB5IHN1IHZhbG9yIGVuIGVsIGVqZW1wbG8gZXMgNDMuNQ0KDQotIExvcyBfX2ludGVydmFsb3MgZGUgY29uZmlhbnphIHBhcmEgbG9zIHBhcsOhbWV0cm9zX18gc2Ugb2J0aWVuZW4gY29uIGVsIGNvbWFuZG8gYGNvbmZpbnRgLiBFbCBwYXLDoW1ldHJvIGBsZXZlbGAgcGVybWl0ZSBlbGVnaXIgZWwgbml2ZWwgZGUgY29uZmlhbnphIChwb3IgZGVmZWN0byBlcyAwLjk1KToNCg0KYGBge3J9DQpjb25maW50KHJlZ3Jlc2lvbikNCmBgYA0KYGBge3J9DQpjb25maW50KHJlZ3Jlc2lvbiwgbGV2ZWwgPSAwLjkwKQ0KYGBgDQotIExvcyBpbnRlcnZhbG9zIGRlIGNvbmZpYW56YSBwYXJhIGxhIHJlc3B1ZXN0YSBtZWRpYSB5IGxvcyBpbnRlcnZhbG9zIGRlIHByZWRpY2Npw7NuIHBhcmEgbGEgcmVzcHVlc3RhIHNlIHB1ZWRlbiBvYnRlbmVyIHVzYW5kbyBlbCBjb21hbmRvIGBwcmVkaWN0YC4gUG9yIGVqZW1wbG8sIGVsIHNpZ3VpZW50ZSBjw7NkaWdvIGNhbGN1bGEgeSByZXByZXNlbnRhIGxvcyBkb3MgdGlwb3MgZGUgaW50ZXJ2YWxvcyBwYXJhIGVsIHJhbmdvIGRlIGVkYWRlcyBxdWUgdmEgZGUgMjAgYSA2MCBhw7FvcyAobG9zIGRlIHByZWRpY2Npw7NuIGVuIHJvam8pOg0KDQpgYGB7cn0NCm51ZXZhcy5lZGFkZXMgPC0gZGF0YS5mcmFtZShlZGFkID0gc2VxKDIwLCA2MCkpDQojIEdyYWZpY28gZGUgZGlzcGVyc2lvbiB5IHJlY3RhDQpwbG90KGdyYXNhcyRlZGFkLCBncmFzYXMkZ3Jhc2FzLCB4bGFiPSdFZGFkJywgeWxhYj0nR3Jhc2FzJykNCmFibGluZShyZWdyZXNpb24pDQoNCiMgSW50ZXJ2YWxvcyBkZSBjb25maWFuemEgZGUgbGEgcmVzcHVlc3RhIG1lZGlhOg0KIyBpYyBlcyB1bmEgbWF0cml6IGNvbiB0cmVzIGNvbHVtbmFzOiBsYSBwcmltZXJhIGVzIGxhIHByZWRpY2Npb24sIGxhcyBvdHJhcyBkb3Mgc29uIGxvcyBleHRyZW1vcyBkZWwgaW50ZXJ2YWxvDQppYyA8LSBwcmVkaWN0KHJlZ3Jlc2lvbiwgbnVldmFzLmVkYWRlcywgaW50ZXJ2YWwgPSAnY29uZmlkZW5jZScpDQpsaW5lcyhudWV2YXMuZWRhZGVzJGVkYWQsIGljWywgMl0sIGx0eSA9IDIpDQpsaW5lcyhudWV2YXMuZWRhZGVzJGVkYWQsIGljWywgM10sIGx0eSA9IDIpDQoNCiMgSW50ZXJ2YWxvcyBkZSBwcmVkaWNjaW9uDQppYyA8LSBwcmVkaWN0KHJlZ3Jlc2lvbiwgbnVldmFzLmVkYWRlcywgaW50ZXJ2YWwgPSAncHJlZGljdGlvbicpDQpsaW5lcyhudWV2YXMuZWRhZGVzJGVkYWQsIGljWywgMl0sIGx0eSA9IDIsIGNvbCA9ICdyZWQnKQ0KbGluZXMobnVldmFzLmVkYWRlcyRlZGFkLCBpY1ssIDNdLCBsdHkgPSAyLCBjb2wgPSAncmVkJykNCmBgYA0KLSBMYSBfX3RhYmxhIGRlIGFuw6FsaXNpcyBkZSBsYSB2YXJpYW56YV9fIGRlIGxvcyBlcnJvcmVzIHNlIG9idGllbmUgY29uIGVsIGNvbWFuZG8gYGFub3ZhYDoNCg0KYGBge3J9DQphbm92YShyZWdyZXNpb24pDQpgYGANCiMjIERpYWduw7NzdGljbyBkZWwgbW9kZWxvDQoNCkxvcyBfX3ZhbG9yZXMgYWp1c3RhZG9zX18gJFxoYXR7eX1faSQgeSBsb3MgX19yZXNpZHVvc19fICRlX2k9XGhhdHt5fV9p4oiSeV9pJCBzZSBwdWVkZW4gb2J0ZW5lciBjb24gbG9zIGNvbWFuZG9zICBgZml0dGVkYCB5IGByZXNpZHVhbHNgIHJlc3BlY3RpdmFtZW50ZS4gTG9zIHJlc2lkdW9zIGVzdGFuZGFyaXphZG9zIHNlIG9idGllbmVuIGNvbiBgcnN0YW5kYXJkYC4gUG9yIGVqZW1wbG8sIGVsIHNpZ3VpZW50ZSBjw7NkaWdvIG9idGllbmUgdW5hIHJlcHJlc2VudGFjacOzbiBkZSBsb3MgcmVzaWR1b3MgZXN0YW5kYXJpemFkb3MgZnJlbnRlIGEgbG9zIHZhbG9yZXMgYWp1c3RhZG9zLCBxdWUgcmVzdWx0YSDDunRpbCBhbCBsbGV2YXIgYSBjYWJvIGVsIGRpYWduw7NzdGljbyBkZWwgbW9kZWxvOg0KDQpgYGB7cn0NCnJlc2lkdW9zIDwtIHJzdGFuZGFyZChyZWdyZXNpb24pDQp2YWxvcmVzLmFqdXN0YWRvcyA8LSBmaXR0ZWQocmVncmVzaW9uKQ0KcGxvdCh2YWxvcmVzLmFqdXN0YWRvcywgcmVzaWR1b3MpDQpgYGANCk5vIHNlIG9ic2VydmEgbmluZ8O6biBwYXRyw7NuIGVzcGVjaWFsLCBwb3IgbG8gcXVlIHRhbnRvIGxhIGhvbW9jZWRhc3RpY2lkYWQgY29tbyBsYSBsaW5lYWxpZGFkIHJlc3VsdGFuIGhpcMOzdGVzaXMgcmF6b25hYmxlcy4NCg0KTGEgaGlww7N0ZXNpcyBkZSBub3JtYWxpZGFkIHNlIHN1ZWxlIGNvbXByb2JhciBtZWRpYW50ZSB1biBfX19RUV9fXyBwbG90IGRlIGxvcyByZXNpZHVvcy4gRWwgc2lndWllbnRlIGPDs2RpZ28gc2lydmUgcGFyYSBvYnRlbmVybG86DQoNCmBgYHtyfQ0KcXFub3JtKHJlc2lkdW9zKQ0KcXFsaW5lKHJlc2lkdW9zKQ0KYGBgDQpEYWRvIHF1ZSBsb3MgcHVudG9zIGVzdMOhbiBiYXN0YW50ZSBhbGluZWFkb3MsIGxhIG5vcm1hbGlkYWQgdGFtYmnDqW4gcGFyZWNlIGFjZXB0YWJsZS4NCg0KYGBge3J9DQojIFZhcmlhYmxlIHJlZ3Jlc29yYSAoZGllw7FvIGZpam8pIHkgcGFyw6FtZXRyb3MNCnggPSBzZXEoMSwxMCkNCmJldGEwIDwtIDANCmJldGExIDwtIDENCnNpZ21hIDwtIDAuMw0KDQojIEdlbmVyYSBsYSB2YXJpYWJsZSByZXNwdWVzdGENCnkgPC0gYmV0YTAgKyBiZXRhMSp4ICsgcm5vcm0obGVuZ3RoKHgpLCBzZD1zaWdtYSkNCg0KIyBBanVzdGEgZWwgbW9kZWxvDQpyZWcgPC0gbG0oeX54KQ0KDQojIEV4dHJhZSBlbCB2YWxvciBkZSBsYSBwZW5kaWVudGUgZXN0aW1hZGENCmNvZWZmaWNpZW50cyhyZWcpWzJdDQoNCiMgUmVzdW1lIGVsIGFqdXN0ZQ0Kc3VtbWFyeShyZWcpDQpgYGANCg0K