Carga de librerías

library(tidyverse)
library(GGally)
library(cowplot)

Motivación y objetivo

Nuestro objetivo va a ser crear un modelo estadístico sencillo que nos permita modelar una relación lineal entre dos variables: una será nuestra variable a explicar y la otra será nuestra variable explicativa. Para eso vamos a ver:

  1. El concepto de covarianza y correlación, su estimación y los tests asociados
  2. Las diferencias entre la correlación y causalidad
  3. Modelo de Regresión Lineal Simple: breve introducción teórica, interpretación y evaluación.

Dataset

Vamos a trabajar con el dataset state.x77 que se encuentra en R. Como es una matriz, lo transformamos a un dataframe con as.data.frame()

estados <- state.x77 %>%
  as.data.frame() %>% # Transformo la matriz a dataframe
  rename(life_exp = `Life Exp`, hs_grad=`HS Grad`) # Renombro las variables para no tener problema con los espacios

Para conocer el dataset utilicemos ?state.x77 para abrir la ayuda de R y la funcion glimpse() para ver la estructura de nuestros datos.

?state.x77
glimpse(estados)
Observations: 50
Variables: 8
$ Population <dbl> 3615, 365, 2212, 2110, 21198, 2541, 3100, 579, 8277, 4931, 868, 813, 11197, 5313, 2861, 2280, 3387, 3806, 1058, 41...
$ Income     <dbl> 3624, 6315, 4530, 3378, 5114, 4884, 5348, 4809, 4815, 4091, 4963, 4119, 5107, 4458, 4628, 4669, 3712, 3545, 3694, ...
$ Illiteracy <dbl> 2.1, 1.5, 1.8, 1.9, 1.1, 0.7, 1.1, 0.9, 1.3, 2.0, 1.9, 0.6, 0.9, 0.7, 0.5, 0.6, 1.6, 2.8, 0.7, 0.9, 1.1, 0.9, 0.6,...
$ life_exp   <dbl> 69.05, 69.31, 70.55, 70.66, 71.71, 72.06, 72.48, 70.06, 70.66, 68.54, 73.60, 71.87, 70.14, 70.88, 72.56, 72.58, 70...
$ Murder     <dbl> 15.1, 11.3, 7.8, 10.1, 10.3, 6.8, 3.1, 6.2, 10.7, 13.9, 6.2, 5.3, 10.3, 7.1, 2.3, 4.5, 10.6, 13.2, 2.7, 8.5, 3.3, ...
$ hs_grad    <dbl> 41.3, 66.7, 58.1, 39.9, 62.6, 63.9, 56.0, 54.6, 52.6, 40.6, 61.9, 59.5, 52.6, 52.9, 59.0, 59.9, 38.5, 42.2, 54.7, ...
$ Frost      <dbl> 20, 152, 15, 65, 20, 166, 139, 103, 11, 60, 0, 126, 127, 122, 140, 114, 95, 12, 161, 101, 103, 125, 160, 50, 108, ...
$ Area       <dbl> 50708, 566432, 113417, 51945, 156361, 103766, 4862, 1982, 54090, 58073, 6425, 82677, 55748, 36097, 55941, 81787, 3...

Tenemos 50 observaciones (los 50 estados de Estados Unidos) y 8 variables númericas:

  • population: población
  • income: ingreso per capita
  • illiteracy: porcentaje de la población que es analfabeta
  • Life Exp: esperanza de vida en años
  • Murder: cantidad de homicidios cada 100.000 habitantes
  • HS Grad: porcentaje de la población que terminó la secundaria
  • Frost: promedio de días con temperatura mínima por debajo de los 0 grados
  • Area: area en millas cuadradas

Veamos algunas estadisticas de resumen para conocer un poco más nuestras variables, usando la funcion summary:

summary(estados)
   Population        Income       Illiteracy       life_exp         Murder          hs_grad          Frost             Area       
 Min.   :  365   Min.   :3098   Min.   :0.500   Min.   :67.96   Min.   : 1.400   Min.   :37.80   Min.   :  0.00   Min.   :  1049  
 1st Qu.: 1080   1st Qu.:3993   1st Qu.:0.625   1st Qu.:70.12   1st Qu.: 4.350   1st Qu.:48.05   1st Qu.: 66.25   1st Qu.: 36985  
 Median : 2838   Median :4519   Median :0.950   Median :70.67   Median : 6.850   Median :53.25   Median :114.50   Median : 54277  
 Mean   : 4246   Mean   :4436   Mean   :1.170   Mean   :70.88   Mean   : 7.378   Mean   :53.11   Mean   :104.46   Mean   : 70736  
 3rd Qu.: 4968   3rd Qu.:4814   3rd Qu.:1.575   3rd Qu.:71.89   3rd Qu.:10.675   3rd Qu.:59.15   3rd Qu.:139.75   3rd Qu.: 81162  
 Max.   :21198   Max.   :6315   Max.   :2.800   Max.   :73.60   Max.   :15.100   Max.   :67.30   Max.   :188.00   Max.   :566432  

Podemos ver el valor mínimo, primer cuartil, mediana, promedio, tercer cuartil y valor máximo de nuestras variables numéricas

Covarianza y correlación

Covarianza

Definición

Es un estadístico que permite medir la variabilidad conjunta de 2 variables.

Puntualmente, nos permite medir la asociacion lineal entre dos variables.

La fórmula de cálculo de esta medida es:

\(q= \frac{1}{N-1} \sum\limits_{i=1}^N (x_i-\bar{x})(y_i-\bar{y})\)

  • Cuando valores altos de x corresponden a valores altos de y, y valores bajos de x corresponden a valores bajos de y la COVARIANZA es positiva

  • Cuando valores altos de x corresponden a valores bajos de y, y valores bajos de x corresponden a valores altos de y la COVARIANZA es negativa

  • Cuando no ocurre ninguna de las dos cosas anteriores, la covarianza será muy cercana a cero

Interpretacion grafica

A continuación presentamos algunos gráficos de dispersión entre variables del dataset de estados.

ASOCIACION LINEAL POSITIVA

  • En el eje horizontal se encuentra la variable Asesinatos (Murder) y en el eje vertical se encuentra la variable Analfabetismo (Illiteracy)

  • Un punto representa las mediciones de esas dos variables para un estado

  • La línea vertical punteada marca el promedio de Asesinatos (Murder)

  • La línea horizontal punteada marca el promedio de Analfabetismo (Illiteracy)

ggplot(estados, aes(x=Murder,y=Illiteracy)) + geom_point(size=2) +
  geom_hline(yintercept = mean(estados$Illiteracy),color='steelblue', linetype='dashed', size=1) +
  geom_vline(xintercept = mean(estados$Murder), color='steelblue', linetype='dashed', size=1) +
  annotate(geom='text', x=c(6.5,8.3,15,15), y=c(2.9,2.9,1.5,0.8), label='+', colour='forestgreen', size=19) +
  annotate(geom='text', x=c(6.5,8.3,0,0), y=c(0.3,0.3,1.5,0.8), label='-', colour='firebrick', size=27) +
  annotate(geom='text', x=15, y=2.9, label='1', colour='steelblue', size=10) +
  annotate(geom='text', x=15, y=0.3, label='4', colour='steelblue', size=10) +
  annotate(geom='text', x=0, y=0.3, label='3', colour='steelblue', size=10) +
  annotate(geom='text', x=0, y=2.9, label='2', colour='steelblue', size=10) +
  labs(title='Asociacion lineal positiva', x='Asesinatos (Murder)', y='Analfabetismo (Illiteracy)')+
  theme_bw() + scale_y_continuous(limits = c(0,3)) + scale_x_continuous(limits = c(0,16))

Vemos que los puntos se concentran en:

  • En el cuadrante 1) donde el valor de cada variable es mayor a su promedio. Entonces, la fórmula de la covarianza es positiva

  • En el cuadrante 3) donde el valor de cada variable es menor a su promedio. Entonces, la fórmula de la covarianza tambien es positiva

Por lo tanto, la covarianza es positiva:

La funcion cov permite calcular la covarianza entre dos variables.

cov(x=estados$Murder, y=estados$Illiteracy)
[1] 1.581776

ASOCIACION LINEAL NEGATIVA

  • En el eje horizontal se encuentra la variable Asesinatos (Murder) y en el eje vertical se encuentra la variable Life Exp (Experanza de Vida)

  • Un punto representa las mediciones de esas dos variables para un estado

  • La línea vertical punteada marca el promedio de Asesinatos (Murder)

  • La línea horizontal punteada marca el promedio de Life Exp (Experanza de Vida)

ggplot(estados, aes(x=Murder,y=life_exp)) + geom_point(size=2) +
  geom_hline(yintercept = mean(estados$life_exp), color='steelblue', linetype='dashed', size=1, alpha=0.7) +
  geom_vline(xintercept = mean(estados$Murder), color='steelblue', linetype='dashed', size=1, alpha=0.7) +
  annotate(geom='text', x=c(6.5,8.3,15,15), y=c(74.2,74.2,71.7,70.1), label='+', colour='forestgreen', size=19) +
  annotate(geom='text', x=c(6.5,8.3,0,0), y=c(67.9,67.9,71.7,70.1), label='-', colour='firebrick', size=27) +
  annotate(geom='text', x=15, y=74.2, label='1', colour='steelblue', size=10) +
  annotate(geom='text', x=15, y=67.9, label='4', colour='steelblue', size=10) +
  annotate(geom='text', x=0, y=67.9, label='3', colour='steelblue', size=10) +
  annotate(geom='text', x=0, y=74.2, label='2', colour='steelblue', size=10) +
  labs(title='Asociacion lineal negativa', x='Asesinatos (Murder)', y='Life Exp (Experanza Vida)')+
  theme_bw() +
  scale_x_continuous(limits = c(0,16)) + scale_y_continuous(limits = c(67.5,74.5))

Vemos que los puntos se concentran en:

  • En el cuadrante 2) donde el valor de Asesinatos es menor a su promedio y el valor de Esperanza de Vida es mayor a su promedio. Entonces, la fórmula de la covarianza tambien es positiva

  • En el cuadrante 4) donde el valor de Asesinatos es mayor a su promedio y el valor de Esperanza de Vida es menor a su promedio. Entonces, la fórmula de la covarianza es negativa

Por lo tanto, la covarianza es negativa:

cov(x=estados$Murder, y=estados$life_exp)
[1] -3.86948

SIN ASOCIACION LINEAL

  • En el eje horizontal se encuentra la variable Area y en el eje vertical se encuentra la variable Analfabetismo (Illiteracy)

  • Un punto representa las mediciones de esas dos variables para un estado

  • La línea vertical punteada marca el promedio de Area

  • La línea horizontal punteada marca el promedio de Analfabetismo (Illiteracy)

ggplot(estados, aes(x=Area,y=Illiteracy)) + geom_point(size=2) +
  geom_hline(yintercept = mean(estados$Illiteracy),color='steelblue', linetype='dashed', size=1) +
  geom_vline(xintercept = mean(estados$Area), color='steelblue', linetype='dashed', size=1) +
  annotate(geom='text', x=c(-10000,150000,500000,500000), y=c(2.9,2.9,1.5,0.8), label='+', colour='forestgreen', size=19) +
  annotate(geom='text', x=c(0,150000,-400000,-400000), y=c(-0.6,-0.6,1.5,0.8), label='-', colour='firebrick', size=27) +
  annotate(geom='text', x=500000, y=2.9, label='1', colour='steelblue', size=10) +
  annotate(geom='text', x=500000, y=-0.6, label='4', colour='steelblue', size=10) +
  annotate(geom='text', x=-400000, y=-0.6, label='3', colour='steelblue', size=10) +
  annotate(geom='text', x=-400000, y=2.9, label='2', colour='steelblue', size=10) +
  labs(title='Sin asociacion lineal',y='Analfabetismo (Illiteracy)')+
  theme_bw() + scale_y_continuous(limits = c(-1,3)) + scale_x_continuous(limits = c(-400000,600000))

Vemos que los puntos se distribuyen entre el cuadrante 2) y 3) sin una estructura muy clara. Entonces decimos que no hay asociación lineal entre las variables:

cov(x = estados$Area, y=estados$Illiteracy)
[1] 4018.337

¿Qué pasó? Habíamos dicho que la covarianza entre Asesinatos y Analfabetismo era positiva y la covarianza entre Area y Analfabetismo era inexsistente. Sin embargo, la segunda es mucho más grande que la primera.

La covarianza tiene una CARACTERÍSTICA que puede ser un PROBLEMA importante: se ve afectada por la unidad de medida de las variables.

Por ejemplo:

# Covarianza entre area (medida en millas cuadradas) y analfabetismo
cov_1 = cov(x = estados$Area, y=estados$Illiteracy)
cov_1
[1] 4018.337
# 1 milla cuadrada = 2.59 kilometros cuadrados
area_kilometros = estados$Area*2.59
# Covarianza entre area (medida en kilometros cuadradas) y analfabetismo
cov_2=cov(x = area_kilometros, y=estados$Illiteracy)
cov_2
[1] 10407.49

La covarianza entre el área y analfabetismo es distinta dependiendo de como midamos el área. Si la medimos en millas cuadras la covarianza es 4018.3 y si la medimos en kilómetros cuadrados es igual a 10407.5.

Como la covarianza se ve afectada por la unidad de medida de las variables puede ser muy difícil (o imposible) realizar una comparación entre las covarianzas de distintas variables. Para eso podemos utilizar otra medida

Correlación

Definición

Al igual que la covarianza, la correlación nos permite medir la asociación lineal entre dos variables.

La fórmula de calculo para el coeficiente de correlación es:

\(r= \frac{1}{N-1} \sum\limits_{i=1}^N \frac{(x_i-\bar{x})(y_i-\bar{y})}{S_x \cdot S_y}\)

\(S_x\) es el desvío estándar estimado de X y \(S_y\) es el desvío estándar estimado de Y.

Al agregar los desvíos, la correlación sólo puede tomar valores entre -1 y 1 y así se resuelve el problema que tiene la covarianza de verse afectada por la unidad de medida de las variables

Características

  1. Puede tomar valores entre -1 y 1

  2. No se ve afectada por las unidades de medida de las variables

  3. El valor absoluto (módulo) del coeficiente mide la fuerza de la relacion lineal entre X e y. Cuanto mayor sea el valor absoluto, más fuerte es la relación LINEAL entre X e Y

    1. \(r=1\) indica una relación lineal perfecta positiva (los puntos se encuentra una recta diagonal de pendiente positiva)
    2. \(r=0\) indica que no existe relación lineal entre X e Y
    3. \(r=-1\) indica una relación lineal perfecta negativa (los puntos se encuentra una recta diagonal de pendiente negativa)

Veamos la caracteristica 2) con nuestro ejemplo de la relacion entre analfabetismo y area

La funcion cor permite calcular la correlacion entre dos variables.

# Correlacion entre area (medida en millas cuadradas) y analfabetismo
corr_1 = cor(x = estados$Area, y=estados$Illiteracy)
corr_1
[1] 0.07726113
# 1 milla cuadrada = 2.59 kilometros cuadrados
area_kilometros = estados$Area*2.59
# Correlacion entre area (medida en kilometros cuadradas) y analfabetismo
corr_2=cor(x = area_kilometros, y=estados$Illiteracy)
corr_2
[1] 0.07726113

Vemos que ambos coeficientes de correlación son iguales.

Ejemplos

Veamos el coeficiente de correlación para las relaciones que graficamos antes:

# Correlacion entre homicidios y analfabetismo
corr_positiva = cor(x = estados$Murder, y=estados$Illiteracy)
corr_positiva
[1] 0.7029752

Existe una correlación positiva fuerte entre la cantidad de homicidios y el porcentaje de analfabetas

# Correlacion entre homicidios y esperanza de vida
corr_negativa = cor(x = estados$Murder, y=estados$life_exp)
corr_negativa
[1] -0.7808458

Existe una correlación negativa fuerte entre la cantidad de homicidios y la esperanza de vida

# Covarianza entre area (medida en kilometros cuadradas) y analfabetismo
corr_nula = cor(x = estados$Area, y=estados$Illiteracy)
corr_nula
[1] 0.07726113

Existe una correlación positiva muy débil entre área y analfabetismo

GGAlly

La libreria GGally es muy útil porque nos permite resumir información sobre las relaciones de las variables de manera gráfica.

Con el comando ggpairs vamos a poder ver:

  1. En la diagonal: los gráficos de distribucion de la variable

  2. Por debajo de la diagonal: los gráficos de dispersion para cada par de variables

  3. Por encima de la diagonal: los coeficientes de correlacion para cada par de variables

ggpairs(estados) + theme_bw() + theme(axis.text.x = element_text(angle = 90, hjust = 1))

Por ejemplo:

  • En la fila 2, columna 2 vemos la distribución de la variable ingreso

  • En la fila 2, columna 1 vemos el diagrama de dispersión entre población e ingreso

  • En la fila 2, columna 3 vemos el coeficiente de correlación entre el ingreso y el porcentaje de analfabetas

Test de Hipótesis

Motivación

El coeficiente de correlación es el resultado de una estimación sobre nuestro conjunto de datos. Por lo tanto, el número que se obtiene va a depender de que individuos fueron seleccionados en la muestra.

Veamos esto con un ejemplo

# Sacamos el promedio de días con temperatura mínima por debajo de los 0 grados para los 50 estados
mean(estados$Frost)
[1] 104.46
# Sacamos la correlacion entre dias debajo de los 0 grados (Frost) y el analfabetismo 
cor(estados$Frost, estados$Illiteracy)
[1] -0.671947
#Seleccionamos los 10 estados mas frios 
frios= estados %>% arrange(desc(Frost)) %>% slice(1:10)
# Sacamos el promedio de días con temperatura mínima por debajo de los 0 grados para esos 10 estados
mean(frios$Frost)
[1] 170.3
# Sacamos la correlacion entre dias debajo de los 0 grados (Frost) y el analfabetismo para esos 10 estados
cor(frios$Frost, frios$Illiteracy)
[1] 0.02294539
# Ahora seleccionamos los 10 estados mas calidos 
calidos= estados %>% arrange(desc(Frost)) %>% slice(41:50)
# Sacamos el promedio de días con temperatura mínima por debajo de los 0 grados para esos 10 estados
mean(calidos$Frost)
[1] 23.9
cor(calidos$Frost, calidos$Illiteracy)
[1] -0.1864304

Considerando los 50 estados vemos que en promedio tienen 104 días por debajo de 0 grados y la correlación entre días fríos y analfabetismo es negativa y bastante fuerte (igual a -0.67)

Los 10 estados más fríos tienen en promedio 170 días por debajo de los 0 grados (casi la mitad del año) mientras los 10 estados más cálidos tienen en promedio 24 días por debajo de los 0 grados (menos de un mes).

Por su parte, vemos que la correlación entre días fríos y analfabetismo es muy cercana a 0 (es igual a 0.02) para los estados más fríos, mientras que para los estados más cálidos la correlación es negativa y baja (es igual a -0.19).

Vemos que el coeficiente de correlación puede cambiar mucho dependiendo de que individuos hayamos incluido en nuestro dataset (muestra). Esto va suceder con cualquier medida estadística que calculemos sobre nuestro conjunto de datos.

En conclusión, el coeficiente de correlación (y otras medidas estadísticas como el promedio) va a tener cierta VARIABILIDAD O INCERTIDUMBRE en su estimación.

Test de Hipótesis

Puntualmente, nos interesa saber:

  1. ¿Puede ser que el coeficiente de correlación sea igual a cero?

  2. ¿Qué tan probable es que sea igual a cero?

Porque, si es probable que el coeficiente de correlacion sea igual a cero, entonces no va a existir una relacion lineal importante entre esas dos variables

En la siguiente imagen vemos:

  • La curva ROJA es la distribución del coeficiente de correlación entre Area y Analfabetismo.
  • La curva VERDE es es la distribución del coeficiente de correlación entre Asesinatos y Analfabetismo

  • La linea punteada nos indica el punto en el cual el coeficiente de correlación es cero.

¿Cuál de estas dos curvas está más cerca del cero? ¿Cuál creen que es el coeficiente de correlación que es más probable que sea igual a cero?

ggplot(data = data.frame(x = c(-1, 1)), aes(x)) +
  stat_function(fun = dnorm, n = 100, args = list(mean = 0.07, sd = .1), color="firebrick", size=1.5) +
  stat_function(fun = dnorm, n = 100, args = list(mean = 0.71, sd = .1), color="forestgreen",size=1.5) +
  geom_vline(xintercept = 0, linetype='dashed', size=1) +
  theme_bw() +
  labs(title="Distribucion coeficientes de correlacion", x="Coeficiente de Correlacion", y="")+
  scale_y_continuous(breaks = NULL)

A simple vista, parece ser que el coeficiente de correlacion entre Area y Analfabetismo tiene una probabilidad más alta de ser igual a cero ya que la curva roja está centrada más cerca del cero. Mientras que la curva verde se encuentra bastante alejada del cero, por lo tanto la probabilidad que el coeficiente sea igual a cero es muy baja.

Podemos usar un test estadístico para responder correctamente a las dos preguntas que hicimos arriba. Vamos a TESTEAR la HIPÓTESIS: El coeficiente de correlacion es igual a cero

La función que vamos a utilizar se llama cor.test

# Veamos la documentacion
?cor.test
# Al igual que para calcular el coeficiente de correlacion pasamos nuestras dos variables: X e Y
cor.test(x=estados$Murder, y=estados$Illiteracy)

    Pearson's product-moment correlation

data:  estados$Murder and estados$Illiteracy
t = 6.8479, df = 48, p-value = 1.258e-08
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.5279280 0.8207295
sample estimates:
      cor 
0.7029752 

Observamos:

  1. Debajo de la parte que dice 95 percent confidence interval: el intervalo de confianza para el coeficiente de correlación.
  • El primer valor es el valor más chico que esperamos ver del coeficiente de correlación
  • El segundo valor es el valor más grande que esperamos ver del coeficiente de correlación

IMPORTANTE: nos interesa ver si dentro del intervalo de confianza se encuentra el cero:

  • Si esta DENTRO del INTERVALO, entonces es PROBABLE que el COEFICIENTE DE CORRELACION sea igual a cero y NO EXISTA UNA RELACION LINEAL IMPORTANTE ENTRE LAS VARIABLES
  • Si esta FUERA del INTERVALO, entonces es MUY POCO PROBABLE que el COEFICIENTE DE CORRELACION sea igual a cero y EXISTA UNA RELACION LINEAL IMPORTANTE ENTRE LAS VARIABLES
  1. p-value: es número que va entre 0 y 1:
  • Cuanto más cerca de 0 este, es MUY POCO PROBABLE que el COEFICIENTE DE CORRELACION sea igual a cero
  • Cuanto más cerca de 1 este, es MUY PROBABLE que el COEFICIENTE DE CORRELACION sea igual a cero

IMPORTANTE: Cuando el p-valor sea menor a 0.05 podemos estar bastante seguros que el COEFICIENTE DE CORRELACIÓN es distinto de cero y EXISTE UNA RELACIÓN LINEAL IMPORTANTE ENTRE LAS VARIABLES

Para el caso de la correlación entre Asesinatos y Analfabetismo vemos que:

  1. El intervalo de confianza NO contiene al cero

  2. El p-valor es mas chico que 0.05

CONCLUSIÓN: rechazamos que el COEFICIENTE DE CORRELACIÓN es distinto de cero

Veamos el test de la correlacion entre Area y Analfabetismo:

cor.test(x=estados$Area, y=estados$Illiteracy)

    Pearson's product-moment correlation

data:  estados$Area and estados$Illiteracy
t = 0.53689, df = 48, p-value = 0.5938
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.2055061  0.3481223
sample estimates:
       cor 
0.07726113 

Vemos que:

  1. El intervalo de confianza SI contiene al cero

  2. El p-valor es mucho mas grande que 0.05

CONCLUSIÓN: NO rechazamos que el COEFICIENTE DE CORRELACIÓN es distinto de cero

Correlación vs causalidad

La correlación mide el grado de asociación lineal entre dos variables.

La CAUSALIDAD indica que una o más variables (variables predictoras/exogenas/explicativas) sirven para explicar el comportamiento de otra variable (variable a predecir/endogena/ a explicar)

Puede haber variables con una baja (o nula) correlación, y sin embargo, que exista otro tipo de relación entre ellas. Como tambien pueden existir variables con una alta correlación pero que no podamos explicar el vinculo entre ellas.

Para este segundo caso, podemos clasificarlo en dos situaciones:

  1. Correlación espuria: dos variables tienen una correlación elevada por motivos puramente azarosos

  2. Variables ocultas: dos variables tienen una correlación elevada porque hay información “escondida” en alguna de ellas (o en ambas)

Veamos algunos ejemplos para aclarar la situacion

Ejemplo de estados con Frost vs Illiteracy

ggplot(estados, aes(x=Frost,y=Illiteracy)) + geom_point(size=2) +
  geom_hline(yintercept = mean(estados$Illiteracy),color='steelblue', linetype='dashed', size=1) +
  geom_vline(xintercept = mean(estados$Frost), color='steelblue', linetype='dashed', size=1) +
  labs(title='¿Correlacion espuria?')+
  theme_bw() + scale_y_continuous(limits = c(-1,3)) + scale_x_continuous(limits = c(-10,200))

cor(x=estados$Frost, y=estados$Illiteracy)
[1] -0.671947

Existe una correlación negativa fuerte entre Analfabetismo y Cantidad de Dias debajo de los 0 grados.

No tiene sentido decir: Para que haga menos frío, tenemos que reducir el analfabetismo en la población. Sin embargo, pueden existir factores que expliquen que los estados que más días fríos tienen, también tienen las menores tasas de analfabetismo. Por ejemplo, puede ser que en los estados donde hace más frío hay más escuelas porque la gente no viaja tanto por la nieve y eso lleva a que haya una menor tasa de analfabetismo.

Poder encontrar estas variables ocultas es una parte muy importante del modelado estadístico.

Modelo

Realizar un modelo implica contar con una variable que deseamos explicar (variable a predecir) y una o más variables que sirven para explicarla (variable/s predictora/s). A su vez, necesitamos SUPONER cual es el tipo de relación entre las variables.

Modelo lineal simple

Definicion

El modelo que vamos a usar es:

\(Y= \beta_0 + \beta_1 \cdot X + \varepsilon\)

  1. Y es la variable a predecir

  2. X es la variable predictora

  3. La relación que suponemos entre ambas variables es una recta, por lo tanto la relación es LINEAL

  4. \(\varepsilon\) es un termino de error. La relación entre las variables nunca va a ser exactamente igual a una recta, el termino de error da cuenta de cuán lejos esta nuestro modelo (nuestra recta) de los datos que vemos.

Tarea de ejemplo

Supongamos que nos interesa modelar la relación entre asesinatos y la esperanza de vida en los estados de Estados Unidos.

ggplot(estados, aes(x=Murder,y=life_exp)) +
  geom_point(size=2) +
  labs(title='Asesinatos y Esperanza de Vida', x='Asesinatos (Murder)', y='Life Exp (Experanza Vida)')+
  theme_bw()

Entonces podemos usar el modelo lineal simple para esta tarea:

  1. Y sera Esperanza de Vida

  2. X sera Asesinatos

Nuestro modelo nos queda igual a:

\(EsperanzaVida= \beta_0 + \beta_1 \cdot Asesinatos + \varepsilon\)

Nosotros ya contamos con los datos de la esperanza de vida y los asesinatos. Entonces la tarea que tenemos por delante es encontrar los valores de \(\beta_0\) y \(\beta_1\).

Rectas

El valor de \(\beta_0\) es la ordenada al origen de mi recta mientras que \(\beta_1\) es la pendiente

Consideremos la recta \(Y= 6 - 2X\)

# Creo la funcion
funcion <- function(x) {6 - 2*x}
# Grafico
ggplot(data.frame(x = c(-1, 3)), aes(x)) +
  stat_function(fun=funcion, colour='forestgreen', size=2)+
  geom_vline(xintercept = 0) +
  geom_hline(yintercept = 0) +
  theme_bw()

Vemos que:

Cuando \(x=0\) la variable Y es igual a la ordenada al origen. La ordenada al origen indica cual es el valor de la variable Y cuando la variable X es igual a cero

Cuando \(x=1\), \(y= 6-2.1=4\) . Cuando X aumento en 1 unidad Y se redujo en 2 unidades. La pendiente nos indica justamente eso: cuanto cambia la variable Y, cuando la variable X cambia en una unidad.

Parámetros del modelo

Volviendo a nuestro modelo de Asesinatos y Esperanza de Vida, surge la pregunta:

¿Hay valores de la ordenada al origen y la pendiente que sean mejores para explicar la relación entre ellas?

Probemos algunas rectas y veamos cual se ajusta mejor a nuestros datos

recta1 <- ggplot(estados, aes(x=Murder,y=life_exp)) +
  geom_point(size=2) +
  geom_abline(intercept = 73, slope = -0.3, colour='forestgreen', size=1.5) +
  labs(title='Recta 1', x='Asesinatos (Murder)', y='Life Exp (Experanza Vida)')+
  theme_bw()
recta2 <- ggplot(estados, aes(x=Murder,y=life_exp)) +
  geom_point(size=2) +
  geom_abline(intercept = 69, slope = 0.2, colour='firebrick', size=1.5) +
  labs(title='Recta 2', x='Asesinatos (Murder)', y='Life Exp (Experanza Vida)')+
  theme_bw()
recta3 <- ggplot(estados, aes(x=Murder,y=life_exp)) +
  geom_point(size=2) +
  geom_abline(intercept = 71, slope = -0.3, colour='steelblue', size=1.5) +
  labs(title='Recta 3', x='Asesinatos (Murder)', y='Life Exp (Experanza Vida)')+
  theme_bw()
plot_grid(recta1,recta2,recta3)

  • La recta 2 atraviesa los puntos por la mitad. No se ajusta para nada a los datos

  • La recta 3 deja todos los puntos por encima de ella. Sería un mal modelo

  • La recta 1 parece ser que se ajusta mucho mejor a la estructura de los datos

Entonces, ya sabemos que puede haber valores de \(\beta_0\) (ordenada al origen) y \(\beta_1\) (pendiente) que son mejores que otros.

Cuando creemos un modelo lineal, la regresión va a obtener los MEJORES valores \(\beta_0\) y \(\beta_1\). Son los MEJORES porque son los que producen la RECTA que MEJOR se AJUSTA a los DATOS.

Modelo en R

La función para crear un modelo lineal en R es lm(). En ella le tenemos que pasar:

  • formula: es la formula de nuestro modelo y se escribe Y~X

  • data: es la tabla/dataset que estamos usando

#Creo el modelo con life_exp (variable a predecir) ~ Murder (variable predictora)
modelo_asesinatos<-lm(formula = life_exp~Murder, data = estados)
modelo_asesinatos

Call:
lm(formula = life_exp ~ Murder, data = estados)

Coefficients:
(Intercept)       Murder  
    72.9736      -0.2839  

Cuando creamos un modelo vamos a poder acceder a mucha informacion contenida en él. Podemos ver que cosas tiene dentro con modelo_asesinatos$

Interpretación

Recordemos que nuestro modelo era:

\(EsperanzaVida= \beta_0 + \beta_1 \cdot Asesinatos + \varepsilon\)

Y queríamos encontrar los valores de \(\beta_0\) y \(\beta_1\).

Si realizamos modelo_asesinatos$coefficients vamos a poder acceder a los valores de \(\beta_0\) y \(\beta_1\) estimados por la regresión simple:

modelo_asesinatos$coefficients
(Intercept)      Murder 
 72.9735623  -0.2839472 
beta_0 <- modelo_asesinatos$coefficients[[1]] # Guardamos el valor del intercepto
beta_1 <- modelo_asesinatos$coefficients[[2]] # Guardamos el valor de la pendiente

¿Cómo interpretamos los coeficientes?

  • El intercepto nos indica que si no hay asesinatos, la esperanza de vida en promedio para los estados es de 73 años

  • La pendiente nos indica que cada asesinato adicional reduce la esperanza de vida en promedio en 0.3 años. Es decir, que más o menos, cada 3 homicidios la esperanza de vida promedio se reduce en 1 año.

Veamos como luce nuestro modelo lineal gráficamente:

ggplot(estados, aes(x=Murder,y=life_exp)) +
  geom_point(size=2) +
  geom_abline(intercept = beta_0, slope = beta_1, colour='forestgreen', size=1.5, alpha=0.6) +
  geom_vline(xintercept = 0) +
  labs(title='Modelo lineal', x='Asesinatos (Murder)', y='Life Exp (Experanza Vida)')+
  theme_bw()

Evaluación del modelo

Hasta ahora no sabemos que tan bueno es nuestro modelo para explicar la esperanza de vida.

Para evaluar que tan bueno es nuestro modelo vamos a ver dos cosas:

  1. El p-valor de la ordenada al origen y la pendiente

  2. El valor del R cuadrado

p-valor

Al igual que con el coeficiente de correlación, las estimaciones de \(\beta_0\) y \(\beta_1\) van a tener un p-valor asociado.

En este caso:

  • Si el p-valor es inferior a 0.05, estamos bastante seguros que la variable es buena para explicar a nuestra variable Y

  • Si el p-valor es superior a 0.05, estamos bastante seguros que la variable no sirve para explicar a nuestra variable Y

R cuadrado

Es un valor que va entre 0 y 1, e indica que tan bueno es mi modelo en su totalidad para explicar mi variable Y.

IMPORTANTE: podemos usar el R cuadrado para comparar modelos distintos entre sí

  • Si se encuentra muy cerca de 0, el modelo es malo para explicar a la variable Y

  • Si se encuentra muy cerca de 1, el modelo es bueno para explicar a la variable Y

Con la función summary accedemos a un resumen del modelo que va a tener todas las cosas mencionadas anteriormente

# Resumen del modelo
summary(modelo_asesinatos)

Call:
lm(formula = life_exp ~ Murder, data = estados)

Residuals:
     Min       1Q   Median       3Q      Max 
-1.81690 -0.48139  0.09591  0.39769  2.38691 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 72.97356    0.26997  270.30  < 2e-16 ***
Murder      -0.28395    0.03279   -8.66 2.26e-11 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.8473 on 48 degrees of freedom
Multiple R-squared:  0.6097,    Adjusted R-squared:  0.6016 
F-statistic: 74.99 on 1 and 48 DF,  p-value: 2.26e-11

Notemos que:

  • Ambos p-valores son mas chicos que 0.05. Entonces la variable Asesinatos es buena para explicar la Esperanza de Vida

  • El R cuadrado (Multiple R-squared) es igual a 0.61. Por lo que podemos decir que es un buen modelo

Ahora creemos otro modelo, para ver si su R-cuadrado es mayor o menor.

Nuestro nuevo modelo va a tratar de explicar la Esperanza de Vida a partir del Ingreso per capita

#Creo el modelo con life_exp (variable a predecir) ~ Income (variable predictora)
modelo_ingreso<-lm(formula = life_exp~Income, data = estados)
# Resumen del modelo
summary(modelo_ingreso)

Call:
lm(formula = life_exp ~ Income, data = estados)

Residuals:
     Min       1Q   Median       3Q      Max 
-2.96547 -0.76381 -0.03428  0.92876  2.32951 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 6.758e+01  1.328e+00  50.906   <2e-16 ***
Income      7.433e-04  2.965e-04   2.507   0.0156 *  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.275 on 48 degrees of freedom
Multiple R-squared:  0.1158,    Adjusted R-squared:  0.09735 
F-statistic: 6.285 on 1 and 48 DF,  p-value: 0.01562

Notemos que:

  • Ambos p-valores son mas chicos que 0.05. Entonces la variable Ingreso es buena para explicar la Esperanza de Vida

  • El R cuadrado (Multiple R-squared) es igual a 0.12

En conclusión, nuestro primer modelo tiene un R cuadrado mucho más alto que el segundo modelo. Por lo tanto, el primer modelo es mucho mejor para predecir la esperanza de vida de los estados de Estados Unidos que el segundo.

Ejercicios de tarea

  1. Realizar el gráfico de dispersión entre Income y Illiteracy, y entre Income y hs_grad

  2. Calcular la covarianza y correlación entre Income y Illiteracy, y entre Income y hs_grad

    1. Realizar un modelo lineal que explique Income en función de Illiteracy

    2. Realizar un modelo lineal que explique Income en función de hs_grad

  3. Obtener los coefientes de los 2 modelos previos. Interpretarlos brevemente

  4. Obtener el R-cuadrado de los 2 modelos anteriores. Elegir el que mejor explique la variable Income

Bonus

  1. Graficar la recta de cada modelo sobre el diagrama de dispersión correspondiente
LS0tCnRpdGxlOiAiQ2xhc2UgNCIKYXV0aG9yOiAiQmFycmlvbGEsIEtvemxvd3NraSB5IFdlc2tsZXIiCmRhdGU6ICIxNC8xMi8yMDE4IgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazogCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQotLS0KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KZGl2Lm1haW4tY29udGFpbmVyIHsKICBtYXgtd2lkdGg6IDE2MDBweDsKICBtYXJnaW4tbGVmdDogYXV0bzsKICBtYXJnaW4tcmlnaHQ6IGF1dG87Cn0KPC9zdHlsZT4KCiMjIyMgQ2FyZ2EgZGUgbGlicmVyw61hcwpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoR0dhbGx5KQpsaWJyYXJ5KGNvd3Bsb3QpCmBgYAoKIyBNb3RpdmFjacOzbiB5IG9iamV0aXZvCgpOdWVzdHJvIG9iamV0aXZvIHZhIGEgc2VyIGNyZWFyIHVuIG1vZGVsbyBlc3RhZMOtc3RpY28gc2VuY2lsbG8gcXVlIG5vcyBwZXJtaXRhIG1vZGVsYXIgdW5hIHJlbGFjacOzbiBsaW5lYWwgZW50cmUgZG9zIHZhcmlhYmxlczogdW5hIHNlcsOhIG51ZXN0cmEgdmFyaWFibGUgYSBleHBsaWNhciB5IGxhIG90cmEgc2Vyw6EgbnVlc3RyYSB2YXJpYWJsZSBleHBsaWNhdGl2YS4gUGFyYSBlc28gdmFtb3MgYSB2ZXI6CgoxKSBFbCBjb25jZXB0byBkZSBjb3ZhcmlhbnphIHkgY29ycmVsYWNpw7NuLCBzdSBlc3RpbWFjacOzbiB5IGxvcyB0ZXN0cyBhc29jaWFkb3MKMikgTGFzIGRpZmVyZW5jaWFzIGVudHJlIGxhIGNvcnJlbGFjacOzbiB5IGNhdXNhbGlkYWQKMykgTW9kZWxvIGRlIFJlZ3Jlc2nDs24gTGluZWFsIFNpbXBsZTogYnJldmUgaW50cm9kdWNjacOzbiB0ZcOzcmljYSwgaW50ZXJwcmV0YWNpw7NuIHkgZXZhbHVhY2nDs24uCgojIERhdGFzZXQKClZhbW9zIGEgdHJhYmFqYXIgY29uIGVsIGRhdGFzZXQgKipzdGF0ZS54NzcqKiBxdWUgc2UgZW5jdWVudHJhIGVuIFIuIENvbW8gZXMgdW5hIG1hdHJpeiwgbG8gdHJhbnNmb3JtYW1vcyBhIHVuIGRhdGFmcmFtZSBjb24gYGFzLmRhdGEuZnJhbWUoKWAKCmBgYHtyfQplc3RhZG9zIDwtIHN0YXRlLng3NyAlPiUKICBhcy5kYXRhLmZyYW1lKCkgJT4lICMgVHJhbnNmb3JtbyBsYSBtYXRyaXogYSBkYXRhZnJhbWUKICByZW5hbWUobGlmZV9leHAgPSBgTGlmZSBFeHBgLCBoc19ncmFkPWBIUyBHcmFkYCkgIyBSZW5vbWJybyBsYXMgdmFyaWFibGVzIHBhcmEgbm8gdGVuZXIgcHJvYmxlbWEgY29uIGxvcyBlc3BhY2lvcwpgYGAKClBhcmEgY29ub2NlciBlbCBkYXRhc2V0IHV0aWxpY2Vtb3MgYD9zdGF0ZS54NzdgIHBhcmEgYWJyaXIgbGEgYXl1ZGEgZGUgUiB5IGxhIGZ1bmNpb24gYGdsaW1wc2UoKWAgcGFyYSB2ZXIgbGEgZXN0cnVjdHVyYSBkZSBudWVzdHJvcyBkYXRvcy4KCmBgYHtyfQo/c3RhdGUueDc3CmdsaW1wc2UoZXN0YWRvcykKYGBgCgpUZW5lbW9zIDUwIG9ic2VydmFjaW9uZXMgKGxvcyA1MCBlc3RhZG9zIGRlIEVzdGFkb3MgVW5pZG9zKSB5IDggdmFyaWFibGVzIG7Dum1lcmljYXM6CgoqIHBvcHVsYXRpb246IHBvYmxhY2nDs24KKiBpbmNvbWU6IGluZ3Jlc28gcGVyIGNhcGl0YQoqIGlsbGl0ZXJhY3k6IHBvcmNlbnRhamUgZGUgbGEgcG9ibGFjacOzbiBxdWUgZXMgYW5hbGZhYmV0YQoqIExpZmUgRXhwOiBlc3BlcmFuemEgZGUgdmlkYSBlbiBhw7FvcyAKKiBNdXJkZXI6IGNhbnRpZGFkIGRlIGhvbWljaWRpb3MgY2FkYSAxMDAuMDAwIGhhYml0YW50ZXMKKiBIUyBHcmFkOiBwb3JjZW50YWplIGRlIGxhIHBvYmxhY2nDs24gcXVlIHRlcm1pbsOzIGxhIHNlY3VuZGFyaWEKKiBGcm9zdDogcHJvbWVkaW8gZGUgZMOtYXMgY29uIHRlbXBlcmF0dXJhIG3DrW5pbWEgcG9yIGRlYmFqbyBkZSBsb3MgMCBncmFkb3MKKiBBcmVhOiBhcmVhIGVuIG1pbGxhcyBjdWFkcmFkYXMKClZlYW1vcyBhbGd1bmFzIGVzdGFkaXN0aWNhcyBkZSByZXN1bWVuIHBhcmEgY29ub2NlciB1biBwb2NvIG3DoXMgbnVlc3RyYXMgdmFyaWFibGVzLCB1c2FuZG8gbGEgZnVuY2lvbiBgc3VtbWFyeWA6CgpgYGB7ciBjYXJzfQpzdW1tYXJ5KGVzdGFkb3MpCmBgYAoKUG9kZW1vcyB2ZXIgZWwgdmFsb3IgbcOtbmltbywgcHJpbWVyIGN1YXJ0aWwsIG1lZGlhbmEsIHByb21lZGlvLCB0ZXJjZXIgY3VhcnRpbCB5IHZhbG9yIG3DoXhpbW8gZGUgbnVlc3RyYXMgdmFyaWFibGVzIG51bcOpcmljYXMKCiMgQ292YXJpYW56YSB5IGNvcnJlbGFjacOzbgoKIyMgQ292YXJpYW56YQoKIyMjIERlZmluaWNpw7NuCgpFcyB1biBlc3RhZMOtc3RpY28gcXVlIHBlcm1pdGUgbWVkaXIgbGEgdmFyaWFiaWxpZGFkIGNvbmp1bnRhIGRlIDIgdmFyaWFibGVzLgoKUHVudHVhbG1lbnRlLCBub3MgcGVybWl0ZSBtZWRpciBsYSBhc29jaWFjaW9uIGxpbmVhbCBlbnRyZSBkb3MgdmFyaWFibGVzLgoKTGEgZsOzcm11bGEgZGUgY8OhbGN1bG8gZGUgZXN0YSBtZWRpZGEgZXM6CgokcT0gXGZyYWN7MX17Ti0xfSBcc3VtXGxpbWl0c197aT0xfV5OICh4X2ktXGJhcnt4fSkoeV9pLVxiYXJ7eX0pJAoKKiBDdWFuZG8gdmFsb3JlcyBhbHRvcyBkZSAqKngqKiBjb3JyZXNwb25kZW4gYSB2YWxvcmVzIGFsdG9zIGRlICoqeSoqLCB5IHZhbG9yZXMgYmFqb3MgZGUgKip4KiogY29ycmVzcG9uZGVuIGEgdmFsb3JlcyBiYWpvcyBkZSAqKnkqKiBsYSBDT1ZBUklBTlpBIGVzIHBvc2l0aXZhCgoqIEN1YW5kbyB2YWxvcmVzIGFsdG9zIGRlICoqeCoqIGNvcnJlc3BvbmRlbiBhIHZhbG9yZXMgYmFqb3MgZGUgKip5KiosIHkgdmFsb3JlcyBiYWpvcyBkZSAqKngqKiBjb3JyZXNwb25kZW4gYSB2YWxvcmVzIGFsdG9zIGRlICoqeSoqIGxhIENPVkFSSUFOWkEgZXMgbmVnYXRpdmEKCiogQ3VhbmRvIG5vIG9jdXJyZSBuaW5ndW5hIGRlIGxhcyBkb3MgY29zYXMgYW50ZXJpb3JlcywgbGEgY292YXJpYW56YSBzZXLDoSBtdXkgY2VyY2FuYSBhIGNlcm8KCiMjIyBJbnRlcnByZXRhY2lvbiBncmFmaWNhCgpBIGNvbnRpbnVhY2nDs24gcHJlc2VudGFtb3MgYWxndW5vcyBncsOhZmljb3MgZGUgZGlzcGVyc2nDs24gZW50cmUgdmFyaWFibGVzIGRlbCBkYXRhc2V0IGRlIGVzdGFkb3MuCgoqKkFTT0NJQUNJT04gTElORUFMIFBPU0lUSVZBKioKCiogRW4gZWwgZWplIGhvcml6b250YWwgc2UgZW5jdWVudHJhIGxhIHZhcmlhYmxlIEFzZXNpbmF0b3MgKE11cmRlcikgeSBlbiBlbCBlamUgdmVydGljYWwgc2UgZW5jdWVudHJhIGxhIHZhcmlhYmxlIEFuYWxmYWJldGlzbW8gKElsbGl0ZXJhY3kpCgoqIFVuIHB1bnRvIHJlcHJlc2VudGEgbGFzIG1lZGljaW9uZXMgZGUgZXNhcyBkb3MgdmFyaWFibGVzIHBhcmEgdW4gZXN0YWRvCgoqIExhIGzDrW5lYSB2ZXJ0aWNhbCBwdW50ZWFkYSBtYXJjYSBlbCBwcm9tZWRpbyBkZSBBc2VzaW5hdG9zIChNdXJkZXIpCgoqIExhIGzDrW5lYSBob3Jpem9udGFsIHB1bnRlYWRhIG1hcmNhIGVsIHByb21lZGlvIGRlIEFuYWxmYWJldGlzbW8gKElsbGl0ZXJhY3kpCgpgYGB7cn0KZ2dwbG90KGVzdGFkb3MsIGFlcyh4PU11cmRlcix5PUlsbGl0ZXJhY3kpKSArIGdlb21fcG9pbnQoc2l6ZT0yKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gbWVhbihlc3RhZG9zJElsbGl0ZXJhY3kpLGNvbG9yPSdzdGVlbGJsdWUnLCBsaW5ldHlwZT0nZGFzaGVkJywgc2l6ZT0xKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbWVhbihlc3RhZG9zJE11cmRlciksIGNvbG9yPSdzdGVlbGJsdWUnLCBsaW5ldHlwZT0nZGFzaGVkJywgc2l6ZT0xKSArCiAgYW5ub3RhdGUoZ2VvbT0ndGV4dCcsIHg9Yyg2LjUsOC4zLDE1LDE1KSwgeT1jKDIuOSwyLjksMS41LDAuOCksIGxhYmVsPScrJywgY29sb3VyPSdmb3Jlc3RncmVlbicsIHNpemU9MTkpICsKICBhbm5vdGF0ZShnZW9tPSd0ZXh0JywgeD1jKDYuNSw4LjMsMCwwKSwgeT1jKDAuMywwLjMsMS41LDAuOCksIGxhYmVsPSctJywgY29sb3VyPSdmaXJlYnJpY2snLCBzaXplPTI3KSArCiAgYW5ub3RhdGUoZ2VvbT0ndGV4dCcsIHg9MTUsIHk9Mi45LCBsYWJlbD0nMScsIGNvbG91cj0nc3RlZWxibHVlJywgc2l6ZT0xMCkgKwogIGFubm90YXRlKGdlb209J3RleHQnLCB4PTE1LCB5PTAuMywgbGFiZWw9JzQnLCBjb2xvdXI9J3N0ZWVsYmx1ZScsIHNpemU9MTApICsKICBhbm5vdGF0ZShnZW9tPSd0ZXh0JywgeD0wLCB5PTAuMywgbGFiZWw9JzMnLCBjb2xvdXI9J3N0ZWVsYmx1ZScsIHNpemU9MTApICsKICBhbm5vdGF0ZShnZW9tPSd0ZXh0JywgeD0wLCB5PTIuOSwgbGFiZWw9JzInLCBjb2xvdXI9J3N0ZWVsYmx1ZScsIHNpemU9MTApICsKICBsYWJzKHRpdGxlPSdBc29jaWFjaW9uIGxpbmVhbCBwb3NpdGl2YScsIHg9J0FzZXNpbmF0b3MgKE11cmRlciknLCB5PSdBbmFsZmFiZXRpc21vIChJbGxpdGVyYWN5KScpKwogIHRoZW1lX2J3KCkgKyBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLDMpKSArIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsMTYpKQpgYGAKClZlbW9zIHF1ZSBsb3MgcHVudG9zIHNlIGNvbmNlbnRyYW4gZW46CgoqIEVuIGVsIGN1YWRyYW50ZSAxKSBkb25kZSBlbCB2YWxvciBkZSBjYWRhIHZhcmlhYmxlIGVzIG1heW9yIGEgc3UgcHJvbWVkaW8uIEVudG9uY2VzLCBsYSBmw7NybXVsYSBkZSBsYSBjb3ZhcmlhbnphIGVzIHBvc2l0aXZhCgoqIEVuIGVsIGN1YWRyYW50ZSAzKSBkb25kZSBlbCB2YWxvciBkZSBjYWRhIHZhcmlhYmxlIGVzIG1lbm9yIGEgc3UgcHJvbWVkaW8uIEVudG9uY2VzLCBsYSBmw7NybXVsYSBkZSBsYSBjb3ZhcmlhbnphIHRhbWJpZW4gZXMgcG9zaXRpdmEKClBvciBsbyB0YW50bywgbGEgY292YXJpYW56YSBlcyBwb3NpdGl2YToKCkxhIGZ1bmNpb24gYGNvdmAgcGVybWl0ZSBjYWxjdWxhciBsYSBjb3ZhcmlhbnphIGVudHJlIGRvcyB2YXJpYWJsZXMuCgpgYGB7cn0KY292KHg9ZXN0YWRvcyRNdXJkZXIsIHk9ZXN0YWRvcyRJbGxpdGVyYWN5KQpgYGAKCgoqKkFTT0NJQUNJT04gTElORUFMIE5FR0FUSVZBKioKCiogRW4gZWwgZWplIGhvcml6b250YWwgc2UgZW5jdWVudHJhIGxhIHZhcmlhYmxlIEFzZXNpbmF0b3MgKE11cmRlcikgeSBlbiBlbCBlamUgdmVydGljYWwgc2UgZW5jdWVudHJhIGxhIHZhcmlhYmxlIExpZmUgRXhwIChFeHBlcmFuemEgZGUgVmlkYSkKCiogVW4gcHVudG8gcmVwcmVzZW50YSBsYXMgbWVkaWNpb25lcyBkZSBlc2FzIGRvcyB2YXJpYWJsZXMgcGFyYSB1biBlc3RhZG8KCiogTGEgbMOtbmVhIHZlcnRpY2FsIHB1bnRlYWRhIG1hcmNhIGVsIHByb21lZGlvIGRlIEFzZXNpbmF0b3MgKE11cmRlcikKCiogTGEgbMOtbmVhIGhvcml6b250YWwgcHVudGVhZGEgbWFyY2EgZWwgcHJvbWVkaW8gZGUgTGlmZSBFeHAgKEV4cGVyYW56YSBkZSBWaWRhKQoKCmBgYHtyfQpnZ3Bsb3QoZXN0YWRvcywgYWVzKHg9TXVyZGVyLHk9bGlmZV9leHApKSArIGdlb21fcG9pbnQoc2l6ZT0yKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gbWVhbihlc3RhZG9zJGxpZmVfZXhwKSwgY29sb3I9J3N0ZWVsYmx1ZScsIGxpbmV0eXBlPSdkYXNoZWQnLCBzaXplPTEsIGFscGhhPTAuNykgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IG1lYW4oZXN0YWRvcyRNdXJkZXIpLCBjb2xvcj0nc3RlZWxibHVlJywgbGluZXR5cGU9J2Rhc2hlZCcsIHNpemU9MSwgYWxwaGE9MC43KSArCiAgYW5ub3RhdGUoZ2VvbT0ndGV4dCcsIHg9Yyg2LjUsOC4zLDE1LDE1KSwgeT1jKDc0LjIsNzQuMiw3MS43LDcwLjEpLCBsYWJlbD0nKycsIGNvbG91cj0nZm9yZXN0Z3JlZW4nLCBzaXplPTE5KSArCiAgYW5ub3RhdGUoZ2VvbT0ndGV4dCcsIHg9Yyg2LjUsOC4zLDAsMCksIHk9Yyg2Ny45LDY3LjksNzEuNyw3MC4xKSwgbGFiZWw9Jy0nLCBjb2xvdXI9J2ZpcmVicmljaycsIHNpemU9MjcpICsKICBhbm5vdGF0ZShnZW9tPSd0ZXh0JywgeD0xNSwgeT03NC4yLCBsYWJlbD0nMScsIGNvbG91cj0nc3RlZWxibHVlJywgc2l6ZT0xMCkgKwogIGFubm90YXRlKGdlb209J3RleHQnLCB4PTE1LCB5PTY3LjksIGxhYmVsPSc0JywgY29sb3VyPSdzdGVlbGJsdWUnLCBzaXplPTEwKSArCiAgYW5ub3RhdGUoZ2VvbT0ndGV4dCcsIHg9MCwgeT02Ny45LCBsYWJlbD0nMycsIGNvbG91cj0nc3RlZWxibHVlJywgc2l6ZT0xMCkgKwogIGFubm90YXRlKGdlb209J3RleHQnLCB4PTAsIHk9NzQuMiwgbGFiZWw9JzInLCBjb2xvdXI9J3N0ZWVsYmx1ZScsIHNpemU9MTApICsKICBsYWJzKHRpdGxlPSdBc29jaWFjaW9uIGxpbmVhbCBuZWdhdGl2YScsIHg9J0FzZXNpbmF0b3MgKE11cmRlciknLCB5PSdMaWZlIEV4cCAoRXhwZXJhbnphIFZpZGEpJykrCiAgdGhlbWVfYncoKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwxNikpICsgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoNjcuNSw3NC41KSkKYGBgCgpWZW1vcyBxdWUgbG9zIHB1bnRvcyBzZSBjb25jZW50cmFuIGVuOgoKKiBFbiBlbCBjdWFkcmFudGUgMikgZG9uZGUgZWwgdmFsb3IgZGUgQXNlc2luYXRvcyBlcyBtZW5vciBhIHN1IHByb21lZGlvIHkgZWwgdmFsb3IgZGUgRXNwZXJhbnphIGRlIFZpZGEgZXMgbWF5b3IgYSBzdSBwcm9tZWRpby4gRW50b25jZXMsIGxhIGbDs3JtdWxhIGRlIGxhIGNvdmFyaWFuemEgdGFtYmllbiBlcyBwb3NpdGl2YQoKKiBFbiBlbCBjdWFkcmFudGUgNCkgZG9uZGUgZWwgdmFsb3IgZGUgQXNlc2luYXRvcyBlcyBtYXlvciBhIHN1IHByb21lZGlvIHkgZWwgdmFsb3IgZGUgRXNwZXJhbnphIGRlIFZpZGEgZXMgbWVub3IgYSBzdSBwcm9tZWRpby4gRW50b25jZXMsIGxhIGbDs3JtdWxhIGRlIGxhIGNvdmFyaWFuemEgZXMgbmVnYXRpdmEKClBvciBsbyB0YW50bywgbGEgY292YXJpYW56YSBlcyBuZWdhdGl2YToKCmBgYHtyfQpjb3YoeD1lc3RhZG9zJE11cmRlciwgeT1lc3RhZG9zJGxpZmVfZXhwKQpgYGAKCgoqKlNJTiBBU09DSUFDSU9OIExJTkVBTCoqCgoqIEVuIGVsIGVqZSBob3Jpem9udGFsIHNlIGVuY3VlbnRyYSBsYSB2YXJpYWJsZSBBcmVhIHkgZW4gZWwgZWplIHZlcnRpY2FsIHNlIGVuY3VlbnRyYSBsYSB2YXJpYWJsZSBBbmFsZmFiZXRpc21vIChJbGxpdGVyYWN5KQoKKiBVbiBwdW50byByZXByZXNlbnRhIGxhcyBtZWRpY2lvbmVzIGRlIGVzYXMgZG9zIHZhcmlhYmxlcyBwYXJhIHVuIGVzdGFkbwoKKiBMYSBsw61uZWEgdmVydGljYWwgcHVudGVhZGEgbWFyY2EgZWwgcHJvbWVkaW8gZGUgQXJlYQoKKiBMYSBsw61uZWEgaG9yaXpvbnRhbCBwdW50ZWFkYSBtYXJjYSBlbCBwcm9tZWRpbyBkZSBBbmFsZmFiZXRpc21vIChJbGxpdGVyYWN5KQoKYGBge3J9CmdncGxvdChlc3RhZG9zLCBhZXMoeD1BcmVhLHk9SWxsaXRlcmFjeSkpICsgZ2VvbV9wb2ludChzaXplPTIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBtZWFuKGVzdGFkb3MkSWxsaXRlcmFjeSksY29sb3I9J3N0ZWVsYmx1ZScsIGxpbmV0eXBlPSdkYXNoZWQnLCBzaXplPTEpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBtZWFuKGVzdGFkb3MkQXJlYSksIGNvbG9yPSdzdGVlbGJsdWUnLCBsaW5ldHlwZT0nZGFzaGVkJywgc2l6ZT0xKSArCiAgYW5ub3RhdGUoZ2VvbT0ndGV4dCcsIHg9YygtMTAwMDAsMTUwMDAwLDUwMDAwMCw1MDAwMDApLCB5PWMoMi45LDIuOSwxLjUsMC44KSwgbGFiZWw9JysnLCBjb2xvdXI9J2ZvcmVzdGdyZWVuJywgc2l6ZT0xOSkgKwogIGFubm90YXRlKGdlb209J3RleHQnLCB4PWMoMCwxNTAwMDAsLTQwMDAwMCwtNDAwMDAwKSwgeT1jKC0wLjYsLTAuNiwxLjUsMC44KSwgbGFiZWw9Jy0nLCBjb2xvdXI9J2ZpcmVicmljaycsIHNpemU9MjcpICsKICBhbm5vdGF0ZShnZW9tPSd0ZXh0JywgeD01MDAwMDAsIHk9Mi45LCBsYWJlbD0nMScsIGNvbG91cj0nc3RlZWxibHVlJywgc2l6ZT0xMCkgKwogIGFubm90YXRlKGdlb209J3RleHQnLCB4PTUwMDAwMCwgeT0tMC42LCBsYWJlbD0nNCcsIGNvbG91cj0nc3RlZWxibHVlJywgc2l6ZT0xMCkgKwogIGFubm90YXRlKGdlb209J3RleHQnLCB4PS00MDAwMDAsIHk9LTAuNiwgbGFiZWw9JzMnLCBjb2xvdXI9J3N0ZWVsYmx1ZScsIHNpemU9MTApICsKICBhbm5vdGF0ZShnZW9tPSd0ZXh0JywgeD0tNDAwMDAwLCB5PTIuOSwgbGFiZWw9JzInLCBjb2xvdXI9J3N0ZWVsYmx1ZScsIHNpemU9MTApICsKICBsYWJzKHRpdGxlPSdTaW4gYXNvY2lhY2lvbiBsaW5lYWwnLHk9J0FuYWxmYWJldGlzbW8gKElsbGl0ZXJhY3kpJykrCiAgdGhlbWVfYncoKSArIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKC0xLDMpKSArIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKC00MDAwMDAsNjAwMDAwKSkKYGBgCgpWZW1vcyBxdWUgbG9zIHB1bnRvcyBzZSBkaXN0cmlidXllbiBlbnRyZSBlbCBjdWFkcmFudGUgMikgeSAzKSBzaW4gdW5hIGVzdHJ1Y3R1cmEgbXV5IGNsYXJhLiBFbnRvbmNlcyBkZWNpbW9zIHF1ZSBubyBoYXkgYXNvY2lhY2nDs24gbGluZWFsIGVudHJlIGxhcyB2YXJpYWJsZXM6CgpgYGB7cn0KY292KHggPSBlc3RhZG9zJEFyZWEsIHk9ZXN0YWRvcyRJbGxpdGVyYWN5KQpgYGAKCsK/UXXDqSBwYXPDsz8gSGFiw61hbW9zIGRpY2hvIHF1ZSBsYSBjb3ZhcmlhbnphIGVudHJlIEFzZXNpbmF0b3MgeSBBbmFsZmFiZXRpc21vIGVyYSBwb3NpdGl2YSB5IGxhIGNvdmFyaWFuemEgZW50cmUgQXJlYSB5IEFuYWxmYWJldGlzbW8gZXJhIGluZXhzaXN0ZW50ZS4gU2luIGVtYmFyZ28sIGxhIHNlZ3VuZGEgZXMgbXVjaG8gbcOhcyBncmFuZGUgcXVlIGxhIHByaW1lcmEuCgpMYSBjb3ZhcmlhbnphIHRpZW5lIHVuYSAqKkNBUkFDVEVSw41TVElDQSoqIHF1ZSBwdWVkZSBzZXIgdW4gKipQUk9CTEVNQSoqIGltcG9ydGFudGU6IHNlIHZlIGFmZWN0YWRhIHBvciBsYSB1bmlkYWQgZGUgbWVkaWRhIGRlIGxhcyB2YXJpYWJsZXMuCgpQb3IgZWplbXBsbzoKCmBgYHtyfQojIENvdmFyaWFuemEgZW50cmUgYXJlYSAobWVkaWRhIGVuIG1pbGxhcyBjdWFkcmFkYXMpIHkgYW5hbGZhYmV0aXNtbwpjb3ZfMSA9IGNvdih4ID0gZXN0YWRvcyRBcmVhLCB5PWVzdGFkb3MkSWxsaXRlcmFjeSkKY292XzEKIyAxIG1pbGxhIGN1YWRyYWRhID0gMi41OSBraWxvbWV0cm9zIGN1YWRyYWRvcwphcmVhX2tpbG9tZXRyb3MgPSBlc3RhZG9zJEFyZWEqMi41OQojIENvdmFyaWFuemEgZW50cmUgYXJlYSAobWVkaWRhIGVuIGtpbG9tZXRyb3MgY3VhZHJhZGFzKSB5IGFuYWxmYWJldGlzbW8KY292XzI9Y292KHggPSBhcmVhX2tpbG9tZXRyb3MsIHk9ZXN0YWRvcyRJbGxpdGVyYWN5KQpjb3ZfMgpgYGAKCkxhIGNvdmFyaWFuemEgZW50cmUgZWwgw6FyZWEgeSBhbmFsZmFiZXRpc21vIGVzIGRpc3RpbnRhIGRlcGVuZGllbmRvIGRlIGNvbW8gbWlkYW1vcyBlbCDDoXJlYS4gU2kgbGEgbWVkaW1vcyBlbiBtaWxsYXMgY3VhZHJhcyBsYSBjb3ZhcmlhbnphIGVzIDQwMTguMyB5IHNpIGxhIG1lZGltb3MgZW4ga2lsw7NtZXRyb3MgY3VhZHJhZG9zIGVzIGlndWFsIGEgMTA0MDcuNS4gCgpDb21vIGxhIGNvdmFyaWFuemEgc2UgdmUgYWZlY3RhZGEgcG9yIGxhIHVuaWRhZCBkZSBtZWRpZGEgZGUgbGFzIHZhcmlhYmxlcyBwdWVkZSBzZXIgbXV5IGRpZsOtY2lsIChvIGltcG9zaWJsZSkgcmVhbGl6YXIgdW5hIGNvbXBhcmFjacOzbiBlbnRyZSBsYXMgY292YXJpYW56YXMgZGUgZGlzdGludGFzIHZhcmlhYmxlcy4gUGFyYSBlc28gcG9kZW1vcyB1dGlsaXphciBvdHJhIG1lZGlkYQoKIyMgQ29ycmVsYWNpw7NuCgojIyMgRGVmaW5pY2nDs24KCkFsIGlndWFsIHF1ZSBsYSBjb3ZhcmlhbnphLCBsYSBjb3JyZWxhY2nDs24gbm9zIHBlcm1pdGUgbWVkaXIgbGEgYXNvY2lhY2nDs24gbGluZWFsIGVudHJlIGRvcyB2YXJpYWJsZXMuCgpMYSBmw7NybXVsYSBkZSBjYWxjdWxvIHBhcmEgZWwgY29lZmljaWVudGUgZGUgY29ycmVsYWNpw7NuIGVzOgoKJHI9IFxmcmFjezF9e04tMX0gXHN1bVxsaW1pdHNfe2k9MX1eTiBcZnJhY3soeF9pLVxiYXJ7eH0pKHlfaS1cYmFye3l9KX17U194IFxjZG90IFNfeX0kCgokU194JCBlcyBlbCBkZXN2w61vIGVzdMOhbmRhciBlc3RpbWFkbyBkZSBYIHkgJFNfeSQgZXMgZWwgZGVzdsOtbyBlc3TDoW5kYXIgZXN0aW1hZG8gZGUgWS4KCkFsIGFncmVnYXIgbG9zIGRlc3bDrW9zLCBsYSBjb3JyZWxhY2nDs24gc8OzbG8gcHVlZGUgdG9tYXIgdmFsb3JlcyBlbnRyZSAtMSB5IDEgeSBhc8OtIHNlIHJlc3VlbHZlIGVsIHByb2JsZW1hIHF1ZSB0aWVuZSBsYSBjb3ZhcmlhbnphIGRlIHZlcnNlIGFmZWN0YWRhIHBvciBsYSB1bmlkYWQgZGUgbWVkaWRhIGRlIGxhcyB2YXJpYWJsZXMKCiMjIyBDYXJhY3RlcsOtc3RpY2FzCgogIDEpIFB1ZWRlIHRvbWFyIHZhbG9yZXMgZW50cmUgLTEgeSAxCgogIDIpIE5vIHNlIHZlIGFmZWN0YWRhIHBvciBsYXMgdW5pZGFkZXMgZGUgbWVkaWRhIGRlIGxhcyB2YXJpYWJsZXMKCiAgMykgRWwgdmFsb3IgYWJzb2x1dG8gKG3Ds2R1bG8pIGRlbCBjb2VmaWNpZW50ZSBtaWRlIGxhIGZ1ZXJ6YSBkZSBsYSByZWxhY2lvbiBsaW5lYWwgZW50cmUgWCBlIHkuIEN1YW50byBtYXlvciBzZWEgZWwgdmFsb3IgYWJzb2x1dG8sIG3DoXMgZnVlcnRlIGVzIGxhIHJlbGFjacOzbiBMSU5FQUwgZW50cmUgWCBlIFkKCiAgNCkgYSkgJHI9MSQgaW5kaWNhIHVuYSByZWxhY2nDs24gbGluZWFsIHBlcmZlY3RhIHBvc2l0aXZhIChsb3MgcHVudG9zIHNlIGVuY3VlbnRyYSB1bmEgcmVjdGEgZGlhZ29uYWwgZGUgcGVuZGllbnRlIHBvc2l0aXZhKQogICAgIGIpICRyPTAkIGluZGljYSBxdWUgbm8gZXhpc3RlIHJlbGFjacOzbiBsaW5lYWwgZW50cmUgWCBlIFkgCiAgICAgYykgJHI9LTEkIGluZGljYSB1bmEgcmVsYWNpw7NuIGxpbmVhbCBwZXJmZWN0YSBuZWdhdGl2YSAobG9zIHB1bnRvcyBzZSBlbmN1ZW50cmEgdW5hIHJlY3RhIGRpYWdvbmFsIGRlIHBlbmRpZW50ZSBuZWdhdGl2YSkKICAgICAKVmVhbW9zIGxhIGNhcmFjdGVyaXN0aWNhIDIpIGNvbiBudWVzdHJvIGVqZW1wbG8gZGUgbGEgcmVsYWNpb24gZW50cmUgYW5hbGZhYmV0aXNtbyB5IGFyZWEKCkxhIGZ1bmNpb24gYGNvcmAgcGVybWl0ZSBjYWxjdWxhciBsYSBjb3JyZWxhY2lvbiBlbnRyZSBkb3MgdmFyaWFibGVzLgoKYGBge3J9CiMgQ29ycmVsYWNpb24gZW50cmUgYXJlYSAobWVkaWRhIGVuIG1pbGxhcyBjdWFkcmFkYXMpIHkgYW5hbGZhYmV0aXNtbwpjb3JyXzEgPSBjb3IoeCA9IGVzdGFkb3MkQXJlYSwgeT1lc3RhZG9zJElsbGl0ZXJhY3kpCmNvcnJfMQojIDEgbWlsbGEgY3VhZHJhZGEgPSAyLjU5IGtpbG9tZXRyb3MgY3VhZHJhZG9zCmFyZWFfa2lsb21ldHJvcyA9IGVzdGFkb3MkQXJlYSoyLjU5CiMgQ29ycmVsYWNpb24gZW50cmUgYXJlYSAobWVkaWRhIGVuIGtpbG9tZXRyb3MgY3VhZHJhZGFzKSB5IGFuYWxmYWJldGlzbW8KY29ycl8yPWNvcih4ID0gYXJlYV9raWxvbWV0cm9zLCB5PWVzdGFkb3MkSWxsaXRlcmFjeSkKY29ycl8yCmBgYAoKVmVtb3MgcXVlIGFtYm9zIGNvZWZpY2llbnRlcyBkZSBjb3JyZWxhY2nDs24gc29uIGlndWFsZXMuCgojIyMgRWplbXBsb3MKClZlYW1vcyBlbCBjb2VmaWNpZW50ZSBkZSBjb3JyZWxhY2nDs24gcGFyYSBsYXMgcmVsYWNpb25lcyBxdWUgZ3JhZmljYW1vcyBhbnRlczoKCmBgYHtyfQojIENvcnJlbGFjaW9uIGVudHJlIGhvbWljaWRpb3MgeSBhbmFsZmFiZXRpc21vCmNvcnJfcG9zaXRpdmEgPSBjb3IoeCA9IGVzdGFkb3MkTXVyZGVyLCB5PWVzdGFkb3MkSWxsaXRlcmFjeSkKY29ycl9wb3NpdGl2YQpgYGAKRXhpc3RlIHVuYSBjb3JyZWxhY2nDs24gcG9zaXRpdmEgZnVlcnRlIGVudHJlIGxhIGNhbnRpZGFkIGRlIGhvbWljaWRpb3MgeSBlbCBwb3JjZW50YWplIGRlIGFuYWxmYWJldGFzCgoKYGBge3J9CiMgQ29ycmVsYWNpb24gZW50cmUgaG9taWNpZGlvcyB5IGVzcGVyYW56YSBkZSB2aWRhCmNvcnJfbmVnYXRpdmEgPSBjb3IoeCA9IGVzdGFkb3MkTXVyZGVyLCB5PWVzdGFkb3MkbGlmZV9leHApCmNvcnJfbmVnYXRpdmEKYGBgCgpFeGlzdGUgdW5hIGNvcnJlbGFjacOzbiBuZWdhdGl2YSBmdWVydGUgZW50cmUgbGEgY2FudGlkYWQgZGUgaG9taWNpZGlvcyB5IGxhIGVzcGVyYW56YSBkZSB2aWRhCgpgYGB7cn0KIyBDb3ZhcmlhbnphIGVudHJlIGFyZWEgKG1lZGlkYSBlbiBraWxvbWV0cm9zIGN1YWRyYWRhcykgeSBhbmFsZmFiZXRpc21vCmNvcnJfbnVsYSA9IGNvcih4ID0gZXN0YWRvcyRBcmVhLCB5PWVzdGFkb3MkSWxsaXRlcmFjeSkKY29ycl9udWxhCmBgYApFeGlzdGUgdW5hIGNvcnJlbGFjacOzbiBwb3NpdGl2YSBtdXkgZMOpYmlsIGVudHJlIMOhcmVhIHkgYW5hbGZhYmV0aXNtbwoKIyMjIEdHQWxseQoKTGEgbGlicmVyaWEgKipHR2FsbHkqKiBlcyBtdXkgw7p0aWwgcG9ycXVlIG5vcyBwZXJtaXRlIHJlc3VtaXIgaW5mb3JtYWNpw7NuIHNvYnJlIGxhcyByZWxhY2lvbmVzIGRlIGxhcyB2YXJpYWJsZXMgZGUgbWFuZXJhIGdyw6FmaWNhLgoKQ29uIGVsIGNvbWFuZG8gYGdncGFpcnNgIHZhbW9zIGEgcG9kZXIgdmVyOgoKMSkgKipFbiBsYSBkaWFnb25hbCoqOiBsb3MgZ3LDoWZpY29zIGRlIGRpc3RyaWJ1Y2lvbiBkZSBsYSB2YXJpYWJsZQoKMikgKipQb3IgZGViYWpvIGRlIGxhIGRpYWdvbmFsKio6IGxvcyBncsOhZmljb3MgZGUgZGlzcGVyc2lvbiBwYXJhIGNhZGEgcGFyIGRlIHZhcmlhYmxlcwoKMykgKipQb3IgZW5jaW1hIGRlIGxhIGRpYWdvbmFsKio6IGxvcyBjb2VmaWNpZW50ZXMgZGUgY29ycmVsYWNpb24gcGFyYSBjYWRhIHBhciBkZSB2YXJpYWJsZXMgCgoKYGBge3IsIG1lc3NhZ2U9RkFMU0V9CgpnZ3BhaXJzKGVzdGFkb3MpICsgdGhlbWVfYncoKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpCmBgYAoKUG9yIGVqZW1wbG86CgoqIEVuIGxhIGZpbGEgMiwgY29sdW1uYSAyIHZlbW9zIGxhIGRpc3RyaWJ1Y2nDs24gZGUgbGEgdmFyaWFibGUgaW5ncmVzbwoKKiBFbiBsYSBmaWxhIDIsIGNvbHVtbmEgMSB2ZW1vcyBlbCBkaWFncmFtYSBkZSBkaXNwZXJzacOzbiBlbnRyZSBwb2JsYWNpw7NuIGUgaW5ncmVzbwoKKiBFbiBsYSBmaWxhIDIsIGNvbHVtbmEgMyB2ZW1vcyBlbCBjb2VmaWNpZW50ZSBkZSBjb3JyZWxhY2nDs24gZW50cmUgZWwgaW5ncmVzbyB5IGVsIHBvcmNlbnRhamUgZGUgYW5hbGZhYmV0YXMKCiMjIyBUZXN0IGRlIEhpcMOzdGVzaXMKCiMjIyMgTW90aXZhY2nDs24KCkVsIGNvZWZpY2llbnRlIGRlIGNvcnJlbGFjacOzbiBlcyBlbCByZXN1bHRhZG8gZGUgdW5hIGVzdGltYWNpw7NuIHNvYnJlIG51ZXN0cm8gY29uanVudG8gZGUgZGF0b3MuIFBvciBsbyB0YW50bywgZWwgbsO6bWVybyBxdWUgc2Ugb2J0aWVuZSB2YSBhIGRlcGVuZGVyIGRlIHF1ZSBpbmRpdmlkdW9zIGZ1ZXJvbiBzZWxlY2Npb25hZG9zIGVuIGxhIG11ZXN0cmEuCgpWZWFtb3MgZXN0byBjb24gdW4gZWplbXBsbwoKYGBge3J9CiMgU2FjYW1vcyBlbCBwcm9tZWRpbyBkZSBkw61hcyBjb24gdGVtcGVyYXR1cmEgbcOtbmltYSBwb3IgZGViYWpvIGRlIGxvcyAwIGdyYWRvcyBwYXJhIGxvcyA1MCBlc3RhZG9zCm1lYW4oZXN0YWRvcyRGcm9zdCkKIyBTYWNhbW9zIGxhIGNvcnJlbGFjaW9uIGVudHJlIGRpYXMgZGViYWpvIGRlIGxvcyAwIGdyYWRvcyAoRnJvc3QpIHkgZWwgYW5hbGZhYmV0aXNtbyAKY29yKGVzdGFkb3MkRnJvc3QsIGVzdGFkb3MkSWxsaXRlcmFjeSkKCiNTZWxlY2Npb25hbW9zIGxvcyAxMCBlc3RhZG9zIG1hcyBmcmlvcyAKZnJpb3M9IGVzdGFkb3MgJT4lIGFycmFuZ2UoZGVzYyhGcm9zdCkpICU+JSBzbGljZSgxOjEwKQojIFNhY2Ftb3MgZWwgcHJvbWVkaW8gZGUgZMOtYXMgY29uIHRlbXBlcmF0dXJhIG3DrW5pbWEgcG9yIGRlYmFqbyBkZSBsb3MgMCBncmFkb3MgcGFyYSBlc29zIDEwIGVzdGFkb3MKbWVhbihmcmlvcyRGcm9zdCkKIyBTYWNhbW9zIGxhIGNvcnJlbGFjaW9uIGVudHJlIGRpYXMgZGViYWpvIGRlIGxvcyAwIGdyYWRvcyAoRnJvc3QpIHkgZWwgYW5hbGZhYmV0aXNtbyBwYXJhIGVzb3MgMTAgZXN0YWRvcwpjb3IoZnJpb3MkRnJvc3QsIGZyaW9zJElsbGl0ZXJhY3kpCgojIEFob3JhIHNlbGVjY2lvbmFtb3MgbG9zIDEwIGVzdGFkb3MgbWFzIGNhbGlkb3MgCmNhbGlkb3M9IGVzdGFkb3MgJT4lIGFycmFuZ2UoZGVzYyhGcm9zdCkpICU+JSBzbGljZSg0MTo1MCkKIyBTYWNhbW9zIGVsIHByb21lZGlvIGRlIGTDrWFzIGNvbiB0ZW1wZXJhdHVyYSBtw61uaW1hIHBvciBkZWJham8gZGUgbG9zIDAgZ3JhZG9zIHBhcmEgZXNvcyAxMCBlc3RhZG9zCm1lYW4oY2FsaWRvcyRGcm9zdCkKY29yKGNhbGlkb3MkRnJvc3QsIGNhbGlkb3MkSWxsaXRlcmFjeSkKYGBgCgpDb25zaWRlcmFuZG8gbG9zIDUwIGVzdGFkb3MgdmVtb3MgcXVlIGVuIHByb21lZGlvIHRpZW5lbiAxMDQgZMOtYXMgcG9yIGRlYmFqbyBkZSAwIGdyYWRvcyB5IGxhIGNvcnJlbGFjacOzbiBlbnRyZSBkw61hcyBmcsOtb3MgeSBhbmFsZmFiZXRpc21vIGVzIG5lZ2F0aXZhIHkgYmFzdGFudGUgZnVlcnRlIChpZ3VhbCBhIC0wLjY3KQoKTG9zIDEwIGVzdGFkb3MgbcOhcyBmcsOtb3MgdGllbmVuIGVuIHByb21lZGlvIDE3MCBkw61hcyBwb3IgZGViYWpvIGRlIGxvcyAwIGdyYWRvcyAoY2FzaSBsYSBtaXRhZCBkZWwgYcOxbykgbWllbnRyYXMgbG9zIDEwIGVzdGFkb3MgbcOhcyBjw6FsaWRvcyB0aWVuZW4gZW4gcHJvbWVkaW8gMjQgZMOtYXMgcG9yIGRlYmFqbyBkZSBsb3MgMCBncmFkb3MgKG1lbm9zIGRlIHVuIG1lcykuCgpQb3Igc3UgcGFydGUsIHZlbW9zIHF1ZSBsYSBjb3JyZWxhY2nDs24gZW50cmUgZMOtYXMgZnLDrW9zIHkgYW5hbGZhYmV0aXNtbyBlcyBtdXkgY2VyY2FuYSBhIDAgKGVzIGlndWFsIGEgMC4wMikgcGFyYSBsb3MgZXN0YWRvcyBtw6FzIGZyw61vcywgbWllbnRyYXMgcXVlIHBhcmEgbG9zIGVzdGFkb3MgbcOhcyBjw6FsaWRvcyBsYSBjb3JyZWxhY2nDs24gZXMgbmVnYXRpdmEgeSBiYWphIChlcyBpZ3VhbCBhIC0wLjE5KS4KClZlbW9zIHF1ZSBlbCBjb2VmaWNpZW50ZSBkZSBjb3JyZWxhY2nDs24gcHVlZGUgY2FtYmlhciBtdWNobyBkZXBlbmRpZW5kbyBkZSBxdWUgaW5kaXZpZHVvcyBoYXlhbW9zIGluY2x1aWRvIGVuIG51ZXN0cm8gZGF0YXNldCAobXVlc3RyYSkuIEVzdG8gdmEgc3VjZWRlciBjb24gY3VhbHF1aWVyIG1lZGlkYSBlc3RhZMOtc3RpY2EgcXVlIGNhbGN1bGVtb3Mgc29icmUgbnVlc3RybyBjb25qdW50byBkZSBkYXRvcy4KCkVuIGNvbmNsdXNpw7NuLCBlbCBjb2VmaWNpZW50ZSBkZSBjb3JyZWxhY2nDs24gKHkgb3RyYXMgbWVkaWRhcyBlc3RhZMOtc3RpY2FzIGNvbW8gZWwgcHJvbWVkaW8pIHZhIGEgdGVuZXIgY2llcnRhICoqVkFSSUFCSUxJREFEIE8gSU5DRVJUSURVTUJSRSoqIGVuIHN1IGVzdGltYWNpw7NuLiAKCiMjIyMgVGVzdCBkZSBIaXDDs3Rlc2lzCgpQdW50dWFsbWVudGUsIG5vcyBpbnRlcmVzYSBzYWJlcjoKCjEpIMK/UHVlZGUgc2VyIHF1ZSBlbCBjb2VmaWNpZW50ZSBkZSBjb3JyZWxhY2nDs24gc2VhIGlndWFsIGEgY2Vybz8KCjIpIMK/UXXDqSB0YW4gcHJvYmFibGUgZXMgcXVlIHNlYSBpZ3VhbCBhIGNlcm8/CgpQb3JxdWUsIHNpIGVzIHByb2JhYmxlIHF1ZSBlbCBjb2VmaWNpZW50ZSBkZSBjb3JyZWxhY2lvbiBzZWEgaWd1YWwgYSBjZXJvLCBlbnRvbmNlcyBubyB2YSBhIGV4aXN0aXIgdW5hIHJlbGFjaW9uIGxpbmVhbCBpbXBvcnRhbnRlIGVudHJlIGVzYXMgZG9zIHZhcmlhYmxlcwoKRW4gbGEgc2lndWllbnRlIGltYWdlbiB2ZW1vczoKCiogTGEgY3VydmEgUk9KQSBlcyBsYSBkaXN0cmlidWNpw7NuIGRlbCBjb2VmaWNpZW50ZSBkZSBjb3JyZWxhY2nDs24gZW50cmUgQXJlYSB5IEFuYWxmYWJldGlzbW8uCiogTGEgY3VydmEgVkVSREUgZXMgZXMgbGEgZGlzdHJpYnVjacOzbiBkZWwgY29lZmljaWVudGUgZGUgY29ycmVsYWNpw7NuIGVudHJlIEFzZXNpbmF0b3MgeSBBbmFsZmFiZXRpc21vCgoqIExhIGxpbmVhIHB1bnRlYWRhIG5vcyBpbmRpY2EgZWwgcHVudG8gZW4gZWwgY3VhbCBlbCBjb2VmaWNpZW50ZSBkZSBjb3JyZWxhY2nDs24gZXMgY2Vyby4KCsK/Q3XDoWwgZGUgZXN0YXMgZG9zIGN1cnZhcyBlc3TDoSBtw6FzIGNlcmNhIGRlbCBjZXJvPyDCv0N1w6FsIGNyZWVuIHF1ZSBlcyBlbCBjb2VmaWNpZW50ZSBkZSBjb3JyZWxhY2nDs24gcXVlIGVzIG3DoXMgcHJvYmFibGUgcXVlIHNlYSBpZ3VhbCBhIGNlcm8/CgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBkYXRhLmZyYW1lKHggPSBjKC0xLCAxKSksIGFlcyh4KSkgKwogIHN0YXRfZnVuY3Rpb24oZnVuID0gZG5vcm0sIG4gPSAxMDAsIGFyZ3MgPSBsaXN0KG1lYW4gPSAwLjA3LCBzZCA9IC4xKSwgY29sb3I9ImZpcmVicmljayIsIHNpemU9MS41KSArCiAgc3RhdF9mdW5jdGlvbihmdW4gPSBkbm9ybSwgbiA9IDEwMCwgYXJncyA9IGxpc3QobWVhbiA9IDAuNzEsIHNkID0gLjEpLCBjb2xvcj0iZm9yZXN0Z3JlZW4iLHNpemU9MS41KSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGU9J2Rhc2hlZCcsIHNpemU9MSkgKwogIHRoZW1lX2J3KCkgKwogIGxhYnModGl0bGU9IkRpc3RyaWJ1Y2lvbiBjb2VmaWNpZW50ZXMgZGUgY29ycmVsYWNpb24iLCB4PSJDb2VmaWNpZW50ZSBkZSBDb3JyZWxhY2lvbiIsIHk9IiIpKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBOVUxMKQpgYGAKCkEgc2ltcGxlIHZpc3RhLCBwYXJlY2Ugc2VyIHF1ZSBlbCBjb2VmaWNpZW50ZSBkZSBjb3JyZWxhY2lvbiBlbnRyZSBBcmVhIHkgQW5hbGZhYmV0aXNtbyB0aWVuZSB1bmEgcHJvYmFiaWxpZGFkIG3DoXMgYWx0YSBkZSBzZXIgaWd1YWwgYSBjZXJvIHlhIHF1ZSBsYSBjdXJ2YSByb2phIGVzdMOhIGNlbnRyYWRhIG3DoXMgY2VyY2EgZGVsIGNlcm8uIE1pZW50cmFzIHF1ZSBsYSBjdXJ2YSB2ZXJkZSBzZSBlbmN1ZW50cmEgYmFzdGFudGUgYWxlamFkYSBkZWwgY2VybywgcG9yIGxvIHRhbnRvIGxhIHByb2JhYmlsaWRhZCBxdWUgZWwgY29lZmljaWVudGUgc2VhIGlndWFsIGEgY2VybyBlcyBtdXkgYmFqYS4KClBvZGVtb3MgdXNhciB1biB0ZXN0IGVzdGFkw61zdGljbyBwYXJhIHJlc3BvbmRlciBjb3JyZWN0YW1lbnRlIGEgbGFzIGRvcyBwcmVndW50YXMgcXVlIGhpY2ltb3MgYXJyaWJhLiBWYW1vcyBhIFRFU1RFQVIgbGEgSElQw5NURVNJUzogRWwgY29lZmljaWVudGUgZGUgY29ycmVsYWNpb24gZXMgaWd1YWwgYSBjZXJvCgpMYSBmdW5jacOzbiBxdWUgdmFtb3MgYSB1dGlsaXphciBzZSBsbGFtYSBgY29yLnRlc3RgCgpgYGB7cn0KIyBWZWFtb3MgbGEgZG9jdW1lbnRhY2lvbgo/Y29yLnRlc3QKIyBBbCBpZ3VhbCBxdWUgcGFyYSBjYWxjdWxhciBlbCBjb2VmaWNpZW50ZSBkZSBjb3JyZWxhY2lvbiBwYXNhbW9zIG51ZXN0cmFzIGRvcyB2YXJpYWJsZXM6IFggZSBZCmNvci50ZXN0KHg9ZXN0YWRvcyRNdXJkZXIsIHk9ZXN0YWRvcyRJbGxpdGVyYWN5KQpgYGAKCk9ic2VydmFtb3M6CgoxKSBEZWJham8gZGUgbGEgcGFydGUgcXVlIGRpY2UgKio5NSBwZXJjZW50IGNvbmZpZGVuY2UgaW50ZXJ2YWwqKjogZWwgKippbnRlcnZhbG8gZGUgY29uZmlhbnphKiogcGFyYSBlbCBjb2VmaWNpZW50ZSBkZSBjb3JyZWxhY2nDs24uCgogICogRWwgcHJpbWVyIHZhbG9yIGVzIGVsIHZhbG9yIG3DoXMgY2hpY28gcXVlIGVzcGVyYW1vcyB2ZXIgZGVsIGNvZWZpY2llbnRlIGRlIGNvcnJlbGFjacOzbiAKICAqIEVsIHNlZ3VuZG8gdmFsb3IgZXMgZWwgdmFsb3IgbcOhcyBncmFuZGUgcXVlIGVzcGVyYW1vcyB2ZXIgZGVsIGNvZWZpY2llbnRlIGRlIGNvcnJlbGFjacOzbiAKCklNUE9SVEFOVEU6IG5vcyBpbnRlcmVzYSB2ZXIgc2kgZGVudHJvIGRlbCBpbnRlcnZhbG8gZGUgY29uZmlhbnphIHNlIGVuY3VlbnRyYSBlbCBjZXJvOgoKICAqIFNpIGVzdGEgREVOVFJPIGRlbCBJTlRFUlZBTE8sIGVudG9uY2VzIGVzIFBST0JBQkxFIHF1ZSBlbCBDT0VGSUNJRU5URSBERSBDT1JSRUxBQ0lPTiBzZWEgaWd1YWwgYSBjZXJvIHkgTk8gRVhJU1RBIFVOQSBSRUxBQ0lPTiBMSU5FQUwgSU1QT1JUQU5URSBFTlRSRSBMQVMgVkFSSUFCTEVTCiAgKiBTaSBlc3RhIEZVRVJBIGRlbCBJTlRFUlZBTE8sIGVudG9uY2VzIGVzIE1VWSBQT0NPIFBST0JBQkxFIHF1ZSBlbCBDT0VGSUNJRU5URSBERSBDT1JSRUxBQ0lPTiBzZWEgaWd1YWwgYSBjZXJvIHkgRVhJU1RBIFVOQSBSRUxBQ0lPTiBMSU5FQUwgSU1QT1JUQU5URSBFTlRSRSBMQVMgVkFSSUFCTEVTCgoyKSAqKnAtdmFsdWUqKjogZXMgbsO6bWVybyBxdWUgdmEgZW50cmUgMCB5IDE6CiAgCiAgKiBDdWFudG8gbcOhcyBjZXJjYSBkZSAwIGVzdGUsIGVzIE1VWSBQT0NPIFBST0JBQkxFIHF1ZSBlbCBDT0VGSUNJRU5URSBERSBDT1JSRUxBQ0lPTiBzZWEgaWd1YWwgYSBjZXJvCiAgKiBDdWFudG8gbcOhcyBjZXJjYSBkZSAxIGVzdGUsIGVzIE1VWSBQUk9CQUJMRSBxdWUgZWwgQ09FRklDSUVOVEUgREUgQ09SUkVMQUNJT04gc2VhIGlndWFsIGEgY2VybwogIAoqKklNUE9SVEFOVEUqKjogQ3VhbmRvIGVsIHAtdmFsb3Igc2VhIG1lbm9yIGEgMC4wNSBwb2RlbW9zIGVzdGFyIGJhc3RhbnRlIHNlZ3Vyb3MgcXVlIGVsIENPRUZJQ0lFTlRFIERFIENPUlJFTEFDScOTTiBlcyBkaXN0aW50byBkZSBjZXJvIHkgRVhJU1RFIFVOQSBSRUxBQ0nDk04gTElORUFMIElNUE9SVEFOVEUgRU5UUkUgTEFTIFZBUklBQkxFUwoKUGFyYSBlbCBjYXNvIGRlIGxhIGNvcnJlbGFjacOzbiBlbnRyZSAqKkFzZXNpbmF0b3MgeSBBbmFsZmFiZXRpc21vKiogdmVtb3MgcXVlOgoKMSkgRWwgaW50ZXJ2YWxvIGRlIGNvbmZpYW56YSBOTyBjb250aWVuZSBhbCBjZXJvCgoyKSBFbCBwLXZhbG9yIGVzIG1hcyBjaGljbyBxdWUgMC4wNQoKKipDT05DTFVTScOTTioqOiByZWNoYXphbW9zIHF1ZSBlbCBDT0VGSUNJRU5URSBERSBDT1JSRUxBQ0nDk04gZXMgZGlzdGludG8gZGUgY2VybwoKVmVhbW9zIGVsIHRlc3QgZGUgbGEgY29ycmVsYWNpb24gZW50cmUgKipBcmVhIHkgQW5hbGZhYmV0aXNtbyoqOgoKYGBge3J9CmNvci50ZXN0KHg9ZXN0YWRvcyRBcmVhLCB5PWVzdGFkb3MkSWxsaXRlcmFjeSkKYGBgCgpWZW1vcyBxdWU6CgoxKSBFbCBpbnRlcnZhbG8gZGUgY29uZmlhbnphIFNJIGNvbnRpZW5lIGFsIGNlcm8KCjIpIEVsIHAtdmFsb3IgZXMgbXVjaG8gbWFzIGdyYW5kZSBxdWUgMC4wNQoKKipDT05DTFVTScOTTioqOiBOTyByZWNoYXphbW9zIHF1ZSBlbCBDT0VGSUNJRU5URSBERSBDT1JSRUxBQ0nDk04gZXMgZGlzdGludG8gZGUgY2VybwoKIyBDb3JyZWxhY2nDs24gdnMgY2F1c2FsaWRhZAoKTGEgY29ycmVsYWNpw7NuIG1pZGUgZWwgZ3JhZG8gZGUgYXNvY2lhY2nDs24gbGluZWFsIGVudHJlIGRvcyB2YXJpYWJsZXMuCgpMYSBDQVVTQUxJREFEIGluZGljYSBxdWUgdW5hIG8gbcOhcyB2YXJpYWJsZXMgKHZhcmlhYmxlcyBwcmVkaWN0b3Jhcy9leG9nZW5hcy9leHBsaWNhdGl2YXMpIHNpcnZlbiBwYXJhIGV4cGxpY2FyIGVsIGNvbXBvcnRhbWllbnRvIGRlIG90cmEgdmFyaWFibGUgKHZhcmlhYmxlIGEgcHJlZGVjaXIvZW5kb2dlbmEvIGEgZXhwbGljYXIpCgpQdWVkZSBoYWJlciB2YXJpYWJsZXMgY29uIHVuYSBiYWphIChvIG51bGEpIGNvcnJlbGFjacOzbiwgeSBzaW4gZW1iYXJnbywgcXVlIGV4aXN0YSBvdHJvIHRpcG8gZGUgcmVsYWNpw7NuIGVudHJlIGVsbGFzLiBDb21vIHRhbWJpZW4gcHVlZGVuIGV4aXN0aXIgdmFyaWFibGVzIGNvbiB1bmEgYWx0YSBjb3JyZWxhY2nDs24gcGVybyBxdWUgbm8gcG9kYW1vcyBleHBsaWNhciBlbCB2aW5jdWxvIGVudHJlIGVsbGFzLgoKUGFyYSBlc3RlIHNlZ3VuZG8gY2FzbywgcG9kZW1vcyBjbGFzaWZpY2FybG8gZW4gZG9zIHNpdHVhY2lvbmVzOgoKMSkgKipDb3JyZWxhY2nDs24gZXNwdXJpYSoqOiBkb3MgdmFyaWFibGVzIHRpZW5lbiB1bmEgY29ycmVsYWNpw7NuIGVsZXZhZGEgcG9yIG1vdGl2b3MgcHVyYW1lbnRlIGF6YXJvc29zCgoyKSAqKlZhcmlhYmxlcyBvY3VsdGFzKio6IGRvcyB2YXJpYWJsZXMgdGllbmVuIHVuYSBjb3JyZWxhY2nDs24gZWxldmFkYSBwb3JxdWUgaGF5IGluZm9ybWFjacOzbiAiZXNjb25kaWRhIiBlbiBhbGd1bmEgZGUgZWxsYXMgKG8gZW4gYW1iYXMpCgpWZWFtb3MgYWxndW5vcyBlamVtcGxvcyBwYXJhIGFjbGFyYXIgbGEgc2l0dWFjaW9uCgohW0Z1ZW50ZTogaHR0cDovL3d3dy50eWxlcnZpZ2VuLmNvbS9zcHVyaW91cy1jb3JyZWxhdGlvbnNdKGVzcHVyaWFfMS5wbmcpICAgICAKCiFbRnVlbnRlOiBodHRwOi8vd3d3LnR5bGVydmlnZW4uY29tL3NwdXJpb3VzLWNvcnJlbGF0aW9uc10oZXNwdXJpYV8yLnBuZykgICAKCkVqZW1wbG8gZGUgYGVzdGFkb3NgIGNvbiBGcm9zdCB2cyBJbGxpdGVyYWN5CgpgYGB7cn0KZ2dwbG90KGVzdGFkb3MsIGFlcyh4PUZyb3N0LHk9SWxsaXRlcmFjeSkpICsgZ2VvbV9wb2ludChzaXplPTIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBtZWFuKGVzdGFkb3MkSWxsaXRlcmFjeSksY29sb3I9J3N0ZWVsYmx1ZScsIGxpbmV0eXBlPSdkYXNoZWQnLCBzaXplPTEpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBtZWFuKGVzdGFkb3MkRnJvc3QpLCBjb2xvcj0nc3RlZWxibHVlJywgbGluZXR5cGU9J2Rhc2hlZCcsIHNpemU9MSkgKwogIGxhYnModGl0bGU9J8K/Q29ycmVsYWNpb24gZXNwdXJpYT8nKSsKICB0aGVtZV9idygpICsgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoLTEsMykpICsgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoLTEwLDIwMCkpCmBgYAoKYGBge3J9CmNvcih4PWVzdGFkb3MkRnJvc3QsIHk9ZXN0YWRvcyRJbGxpdGVyYWN5KQpgYGAKCkV4aXN0ZSB1bmEgY29ycmVsYWNpw7NuIG5lZ2F0aXZhIGZ1ZXJ0ZSBlbnRyZSBBbmFsZmFiZXRpc21vIHkgQ2FudGlkYWQgZGUgRGlhcyBkZWJham8gZGUgbG9zIDAgZ3JhZG9zLgoKTm8gdGllbmUgc2VudGlkbyBkZWNpcjogUGFyYSBxdWUgaGFnYSBtZW5vcyBmcsOtbywgdGVuZW1vcyBxdWUgcmVkdWNpciBlbCBhbmFsZmFiZXRpc21vIGVuIGxhIHBvYmxhY2nDs24uIFNpbiBlbWJhcmdvLCBwdWVkZW4gZXhpc3RpciBmYWN0b3JlcyBxdWUgZXhwbGlxdWVuIHF1ZSBsb3MgZXN0YWRvcyBxdWUgbcOhcyBkw61hcyBmcsOtb3MgdGllbmVuLCB0YW1iacOpbiB0aWVuZW4gbGFzIG1lbm9yZXMgdGFzYXMgZGUgYW5hbGZhYmV0aXNtby4gUG9yIGVqZW1wbG8sIHB1ZWRlIHNlciBxdWUgZW4gbG9zIGVzdGFkb3MgZG9uZGUgaGFjZSBtw6FzIGZyw61vIGhheSBtw6FzIGVzY3VlbGFzIHBvcnF1ZSBsYSBnZW50ZSBubyB2aWFqYSB0YW50byBwb3IgbGEgbmlldmUgeSBlc28gbGxldmEgYSBxdWUgaGF5YSB1bmEgbWVub3IgdGFzYSBkZSBhbmFsZmFiZXRpc21vLgoKUG9kZXIgZW5jb250cmFyIGVzdGFzIHZhcmlhYmxlcyBvY3VsdGFzIGVzIHVuYSBwYXJ0ZSBtdXkgaW1wb3J0YW50ZSBkZWwgbW9kZWxhZG8gZXN0YWTDrXN0aWNvLgoKIyBNb2RlbG8KClJlYWxpemFyIHVuIG1vZGVsbyBpbXBsaWNhIGNvbnRhciBjb24gdW5hIHZhcmlhYmxlIHF1ZSBkZXNlYW1vcyBleHBsaWNhciAoKip2YXJpYWJsZSBhIHByZWRlY2lyKiopIHkgdW5hIG8gbcOhcyB2YXJpYWJsZXMgcXVlIHNpcnZlbiBwYXJhIGV4cGxpY2FybGEgKCoqdmFyaWFibGUvcyBwcmVkaWN0b3JhL3MqKikuIEEgc3UgdmV6LCBuZWNlc2l0YW1vcyBTVVBPTkVSIGN1YWwgZXMgZWwgdGlwbyBkZSByZWxhY2nDs24gZW50cmUgbGFzIHZhcmlhYmxlcy4KCiMjIE1vZGVsbyBsaW5lYWwgc2ltcGxlCgojIyMgRGVmaW5pY2lvbgoKRWwgbW9kZWxvIHF1ZSB2YW1vcyBhIHVzYXIgZXM6CgokWT0gXGJldGFfMCArIFxiZXRhXzEgXGNkb3QgWCArIFx2YXJlcHNpbG9uJAoKMSkgWSBlcyBsYSAqKnZhcmlhYmxlIGEgcHJlZGVjaXIqKgoKMikgWCBlcyBsYSAqKnZhcmlhYmxlIHByZWRpY3RvcmEqKgoKMykgTGEgcmVsYWNpw7NuIHF1ZSBzdXBvbmVtb3MgZW50cmUgYW1iYXMgdmFyaWFibGVzIGVzIHVuYSByZWN0YSwgcG9yIGxvIHRhbnRvIGxhIHJlbGFjacOzbiBlcyAqKkxJTkVBTCoqCgo0KSAkXHZhcmVwc2lsb24kIGVzIHVuIHRlcm1pbm8gZGUgZXJyb3IuIExhIHJlbGFjacOzbiBlbnRyZSBsYXMgdmFyaWFibGVzIG51bmNhIHZhIGEgc2VyIGV4YWN0YW1lbnRlIGlndWFsIGEgdW5hIHJlY3RhLCBlbCB0ZXJtaW5vIGRlIGVycm9yIGRhIGN1ZW50YSBkZSBjdcOhbiBsZWpvcyBlc3RhIG51ZXN0cm8gbW9kZWxvIChudWVzdHJhIHJlY3RhKSBkZSBsb3MgZGF0b3MgcXVlIHZlbW9zLgoKKipUYXJlYSBkZSBlamVtcGxvKioKClN1cG9uZ2Ftb3MgcXVlIG5vcyBpbnRlcmVzYSBtb2RlbGFyIGxhIHJlbGFjacOzbiBlbnRyZSBhc2VzaW5hdG9zIHkgbGEgZXNwZXJhbnphIGRlIHZpZGEgZW4gbG9zIGVzdGFkb3MgZGUgRXN0YWRvcyBVbmlkb3MuCgpgYGB7cn0KZ2dwbG90KGVzdGFkb3MsIGFlcyh4PU11cmRlcix5PWxpZmVfZXhwKSkgKwogIGdlb21fcG9pbnQoc2l6ZT0yKSArCiAgbGFicyh0aXRsZT0nQXNlc2luYXRvcyB5IEVzcGVyYW56YSBkZSBWaWRhJywgeD0nQXNlc2luYXRvcyAoTXVyZGVyKScsIHk9J0xpZmUgRXhwIChFeHBlcmFuemEgVmlkYSknKSsKICB0aGVtZV9idygpCmBgYAoKCkVudG9uY2VzIHBvZGVtb3MgdXNhciBlbCBtb2RlbG8gbGluZWFsIHNpbXBsZSBwYXJhIGVzdGEgdGFyZWE6CgoxKSBZIHNlcmEgKipFc3BlcmFuemEgZGUgVmlkYSoqCgoyKSBYIHNlcmEgKipBc2VzaW5hdG9zKioKCk51ZXN0cm8gbW9kZWxvIG5vcyBxdWVkYSBpZ3VhbCBhOgoKJEVzcGVyYW56YVZpZGE9IFxiZXRhXzAgKyBcYmV0YV8xIFxjZG90IEFzZXNpbmF0b3MgKyBcdmFyZXBzaWxvbiQKCk5vc290cm9zIHlhIGNvbnRhbW9zIGNvbiBsb3MgZGF0b3MgZGUgbGEgZXNwZXJhbnphIGRlIHZpZGEgeSBsb3MgYXNlc2luYXRvcy4gRW50b25jZXMgbGEgdGFyZWEgcXVlIHRlbmVtb3MgcG9yIGRlbGFudGUgZXMgZW5jb250cmFyIGxvcyB2YWxvcmVzIGRlICRcYmV0YV8wJCB5ICRcYmV0YV8xJC4KCiMjIyBSZWN0YXMKCkVsIHZhbG9yIGRlICRcYmV0YV8wJCBlcyBsYSAqKm9yZGVuYWRhIGFsIG9yaWdlbioqIGRlIG1pIHJlY3RhIG1pZW50cmFzIHF1ZSAkXGJldGFfMSQgZXMgbGEgKipwZW5kaWVudGUqKgoKQ29uc2lkZXJlbW9zIGxhIHJlY3RhICRZPSA2IC0gMlgkCgpgYGB7cn0KIyBDcmVvIGxhIGZ1bmNpb24KZnVuY2lvbiA8LSBmdW5jdGlvbih4KSB7NiAtIDIqeH0KIyBHcmFmaWNvCmdncGxvdChkYXRhLmZyYW1lKHggPSBjKC0xLCAzKSksIGFlcyh4KSkgKwogIHN0YXRfZnVuY3Rpb24oZnVuPWZ1bmNpb24sIGNvbG91cj0nZm9yZXN0Z3JlZW4nLCBzaXplPTIpKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgdGhlbWVfYncoKQpgYGAKClZlbW9zIHF1ZToKCkN1YW5kbyAkeD0wJCBsYSB2YXJpYWJsZSBZIGVzIGlndWFsIGEgbGEgb3JkZW5hZGEgYWwgb3JpZ2VuLiBMYSBvcmRlbmFkYSBhbCBvcmlnZW4gaW5kaWNhIGN1YWwgZXMgZWwgdmFsb3IgZGUgbGEgdmFyaWFibGUgWSBjdWFuZG8gbGEgdmFyaWFibGUgWCBlcyBpZ3VhbCBhIGNlcm8KCkN1YW5kbyAkeD0xJCwgJHk9IDYtMi4xPTQkIC4gQ3VhbmRvIFggYXVtZW50byBlbiAxIHVuaWRhZCBZIHNlIHJlZHVqbyBlbiAyIHVuaWRhZGVzLiBMYSBwZW5kaWVudGUgbm9zIGluZGljYSBqdXN0YW1lbnRlIGVzbzogY3VhbnRvIGNhbWJpYSBsYSB2YXJpYWJsZSBZLCBjdWFuZG8gbGEgdmFyaWFibGUgWCBjYW1iaWEgZW4gdW5hIHVuaWRhZC4KCiMjIyBQYXLDoW1ldHJvcyBkZWwgbW9kZWxvCgpWb2x2aWVuZG8gYSBudWVzdHJvIG1vZGVsbyBkZSBBc2VzaW5hdG9zIHkgRXNwZXJhbnphIGRlIFZpZGEsIHN1cmdlIGxhIHByZWd1bnRhOgoKwr9IYXkgdmFsb3JlcyBkZSBsYSBvcmRlbmFkYSBhbCBvcmlnZW4geSBsYSBwZW5kaWVudGUgcXVlIHNlYW4gbWVqb3JlcyBwYXJhIGV4cGxpY2FyIGxhIHJlbGFjacOzbiBlbnRyZSBlbGxhcz8KClByb2JlbW9zIGFsZ3VuYXMgcmVjdGFzIHkgdmVhbW9zIGN1YWwgc2UgYWp1c3RhIG1lam9yIGEgbnVlc3Ryb3MgZGF0b3MKCmBgYHtyfQpyZWN0YTEgPC0gZ2dwbG90KGVzdGFkb3MsIGFlcyh4PU11cmRlcix5PWxpZmVfZXhwKSkgKwogIGdlb21fcG9pbnQoc2l6ZT0yKSArCiAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gNzMsIHNsb3BlID0gLTAuMywgY29sb3VyPSdmb3Jlc3RncmVlbicsIHNpemU9MS41KSArCiAgbGFicyh0aXRsZT0nUmVjdGEgMScsIHg9J0FzZXNpbmF0b3MgKE11cmRlciknLCB5PSdMaWZlIEV4cCAoRXhwZXJhbnphIFZpZGEpJykrCiAgdGhlbWVfYncoKQoKcmVjdGEyIDwtIGdncGxvdChlc3RhZG9zLCBhZXMoeD1NdXJkZXIseT1saWZlX2V4cCkpICsKICBnZW9tX3BvaW50KHNpemU9MikgKwogIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDY5LCBzbG9wZSA9IDAuMiwgY29sb3VyPSdmaXJlYnJpY2snLCBzaXplPTEuNSkgKwogIGxhYnModGl0bGU9J1JlY3RhIDInLCB4PSdBc2VzaW5hdG9zIChNdXJkZXIpJywgeT0nTGlmZSBFeHAgKEV4cGVyYW56YSBWaWRhKScpKwogIHRoZW1lX2J3KCkKCnJlY3RhMyA8LSBnZ3Bsb3QoZXN0YWRvcywgYWVzKHg9TXVyZGVyLHk9bGlmZV9leHApKSArCiAgZ2VvbV9wb2ludChzaXplPTIpICsKICBnZW9tX2FibGluZShpbnRlcmNlcHQgPSA3MSwgc2xvcGUgPSAtMC4zLCBjb2xvdXI9J3N0ZWVsYmx1ZScsIHNpemU9MS41KSArCiAgbGFicyh0aXRsZT0nUmVjdGEgMycsIHg9J0FzZXNpbmF0b3MgKE11cmRlciknLCB5PSdMaWZlIEV4cCAoRXhwZXJhbnphIFZpZGEpJykrCiAgdGhlbWVfYncoKQoKcGxvdF9ncmlkKHJlY3RhMSxyZWN0YTIscmVjdGEzKQoKYGBgCgoqIExhIHJlY3RhIDIgYXRyYXZpZXNhIGxvcyBwdW50b3MgcG9yIGxhIG1pdGFkLiBObyBzZSBhanVzdGEgcGFyYSBuYWRhIGEgbG9zIGRhdG9zCgoqIExhIHJlY3RhIDMgZGVqYSB0b2RvcyBsb3MgcHVudG9zIHBvciBlbmNpbWEgZGUgZWxsYS4gU2Vyw61hIHVuIG1hbCBtb2RlbG8KCiogTGEgcmVjdGEgMSBwYXJlY2Ugc2VyIHF1ZSBzZSBhanVzdGEgbXVjaG8gbWVqb3IgYSBsYSBlc3RydWN0dXJhIGRlIGxvcyBkYXRvcwoKRW50b25jZXMsIHlhIHNhYmVtb3MgcXVlIHB1ZWRlIGhhYmVyIHZhbG9yZXMgZGUgJFxiZXRhXzAkIChvcmRlbmFkYSBhbCBvcmlnZW4pIHkgJFxiZXRhXzEkIChwZW5kaWVudGUpIHF1ZSBzb24gbWVqb3JlcyBxdWUgb3Ryb3MuCgpDdWFuZG8gY3JlZW1vcyB1biBtb2RlbG8gbGluZWFsLCBsYSByZWdyZXNpw7NuIHZhIGEgb2J0ZW5lciBsb3MgKipNRUpPUkVTKiogdmFsb3JlcyAkXGJldGFfMCQgeSAkXGJldGFfMSQuIFNvbiBsb3MgTUVKT1JFUyBwb3JxdWUgc29uIGxvcyBxdWUgcHJvZHVjZW4gbGEgUkVDVEEgcXVlIE1FSk9SIHNlIEFKVVNUQSBhIGxvcyBEQVRPUy4gCgojIyBNb2RlbG8gZW4gUgoKTGEgZnVuY2nDs24gcGFyYSBjcmVhciB1biBtb2RlbG8gbGluZWFsIGVuIFIgZXMgYGxtKClgLiBFbiBlbGxhIGxlIHRlbmVtb3MgcXVlIHBhc2FyOgoKKiBmb3JtdWxhOiBlcyBsYSBmb3JtdWxhIGRlIG51ZXN0cm8gbW9kZWxvIHkgc2UgZXNjcmliZSBZflgKCiogZGF0YTogZXMgbGEgdGFibGEvZGF0YXNldCBxdWUgZXN0YW1vcyB1c2FuZG8KCmBgYHtyfQojQ3JlbyBlbCBtb2RlbG8gY29uIGxpZmVfZXhwICh2YXJpYWJsZSBhIHByZWRlY2lyKSB+IE11cmRlciAodmFyaWFibGUgcHJlZGljdG9yYSkKbW9kZWxvX2FzZXNpbmF0b3M8LWxtKGZvcm11bGEgPSBsaWZlX2V4cH5NdXJkZXIsIGRhdGEgPSBlc3RhZG9zKQoKbW9kZWxvX2FzZXNpbmF0b3MKYGBgCgpDdWFuZG8gY3JlYW1vcyB1biBtb2RlbG8gdmFtb3MgYSBwb2RlciBhY2NlZGVyIGEgbXVjaGEgaW5mb3JtYWNpb24gY29udGVuaWRhIGVuIMOpbC4gUG9kZW1vcyB2ZXIgcXVlIGNvc2FzIHRpZW5lIGRlbnRybyBjb24gYG1vZGVsb19hc2VzaW5hdG9zJGAKCiMjIyBJbnRlcnByZXRhY2nDs24KClJlY29yZGVtb3MgcXVlIG51ZXN0cm8gbW9kZWxvIGVyYToKCiRFc3BlcmFuemFWaWRhPSBcYmV0YV8wICsgXGJldGFfMSBcY2RvdCBBc2VzaW5hdG9zICsgXHZhcmVwc2lsb24kCgpZIHF1ZXLDrWFtb3MgZW5jb250cmFyIGxvcyB2YWxvcmVzIGRlICRcYmV0YV8wJCB5ICRcYmV0YV8xJC4KClNpIHJlYWxpemFtb3MgYG1vZGVsb19hc2VzaW5hdG9zJGNvZWZmaWNpZW50c2AgdmFtb3MgYSBwb2RlciBhY2NlZGVyIGEgbG9zIHZhbG9yZXMgZGUgJFxiZXRhXzAkIHkgJFxiZXRhXzEkIGVzdGltYWRvcyBwb3IgbGEgcmVncmVzacOzbiBzaW1wbGU6CgpgYGB7cn0KbW9kZWxvX2FzZXNpbmF0b3MkY29lZmZpY2llbnRzCgpiZXRhXzAgPC0gbW9kZWxvX2FzZXNpbmF0b3MkY29lZmZpY2llbnRzW1sxXV0gIyBHdWFyZGFtb3MgZWwgdmFsb3IgZGVsIGludGVyY2VwdG8KYmV0YV8xIDwtIG1vZGVsb19hc2VzaW5hdG9zJGNvZWZmaWNpZW50c1tbMl1dICMgR3VhcmRhbW9zIGVsIHZhbG9yIGRlIGxhIHBlbmRpZW50ZQpgYGAKCsK/Q8OzbW8gaW50ZXJwcmV0YW1vcyBsb3MgY29lZmljaWVudGVzPwoKKiBFbCBpbnRlcmNlcHRvIG5vcyBpbmRpY2EgcXVlIHNpIG5vIGhheSBhc2VzaW5hdG9zLCBsYSBlc3BlcmFuemEgZGUgdmlkYSBlbiBwcm9tZWRpbyBwYXJhIGxvcyBlc3RhZG9zIGVzIGRlIDczIGHDsW9zCgoqIExhIHBlbmRpZW50ZSBub3MgaW5kaWNhIHF1ZSBjYWRhIGFzZXNpbmF0byBhZGljaW9uYWwgcmVkdWNlIGxhIGVzcGVyYW56YSBkZSB2aWRhIGVuIHByb21lZGlvIGVuIDAuMyBhw7Fvcy4gRXMgZGVjaXIsIHF1ZSBtw6FzIG8gbWVub3MsIGNhZGEgMyBob21pY2lkaW9zIGxhIGVzcGVyYW56YSBkZSB2aWRhIHByb21lZGlvIHNlIHJlZHVjZSBlbiAxIGHDsW8uCgpWZWFtb3MgY29tbyBsdWNlIG51ZXN0cm8gbW9kZWxvIGxpbmVhbCBncsOhZmljYW1lbnRlOgoKYGBge3J9CmdncGxvdChlc3RhZG9zLCBhZXMoeD1NdXJkZXIseT1saWZlX2V4cCkpICsKICBnZW9tX3BvaW50KHNpemU9MikgKwogIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IGJldGFfMCwgc2xvcGUgPSBiZXRhXzEsIGNvbG91cj0nZm9yZXN0Z3JlZW4nLCBzaXplPTEuNSwgYWxwaGE9MC42KSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCkgKwogIGxhYnModGl0bGU9J01vZGVsbyBsaW5lYWwnLCB4PSdBc2VzaW5hdG9zIChNdXJkZXIpJywgeT0nTGlmZSBFeHAgKEV4cGVyYW56YSBWaWRhKScpKwogIHRoZW1lX2J3KCkKYGBgCgojIyMgRXZhbHVhY2nDs24gZGVsIG1vZGVsbwoKSGFzdGEgYWhvcmEgbm8gc2FiZW1vcyBxdWUgdGFuIGJ1ZW5vIGVzIG51ZXN0cm8gbW9kZWxvIHBhcmEgZXhwbGljYXIgbGEgZXNwZXJhbnphIGRlIHZpZGEuCgpQYXJhIGV2YWx1YXIgcXVlIHRhbiBidWVubyBlcyBudWVzdHJvIG1vZGVsbyB2YW1vcyBhIHZlciBkb3MgY29zYXM6CgoxKSBFbCBwLXZhbG9yIGRlIGxhIG9yZGVuYWRhIGFsIG9yaWdlbiB5IGxhIHBlbmRpZW50ZQoKMikgRWwgdmFsb3IgZGVsIFIgY3VhZHJhZG8KCioqcC12YWxvcioqCgpBbCBpZ3VhbCBxdWUgY29uIGVsIGNvZWZpY2llbnRlIGRlIGNvcnJlbGFjacOzbiwgbGFzIGVzdGltYWNpb25lcyBkZSAkXGJldGFfMCQgeSAkXGJldGFfMSQgdmFuIGEgdGVuZXIgdW4gcC12YWxvciBhc29jaWFkby4gCgpFbiBlc3RlIGNhc286CgoqIFNpIGVsIHAtdmFsb3IgZXMgaW5mZXJpb3IgYSAwLjA1LCBlc3RhbW9zIGJhc3RhbnRlIHNlZ3Vyb3MgcXVlIGxhIHZhcmlhYmxlIGVzIGJ1ZW5hIHBhcmEgZXhwbGljYXIgYSBudWVzdHJhIHZhcmlhYmxlIFkKCiogU2kgZWwgcC12YWxvciBlcyBzdXBlcmlvciBhIDAuMDUsIGVzdGFtb3MgYmFzdGFudGUgc2VndXJvcyBxdWUgbGEgdmFyaWFibGUgbm8gc2lydmUgcGFyYSBleHBsaWNhciBhIG51ZXN0cmEgdmFyaWFibGUgWQoKKipSIGN1YWRyYWRvKioKCkVzIHVuIHZhbG9yIHF1ZSB2YSBlbnRyZSAwIHkgMSwgZSBpbmRpY2EgcXVlIHRhbiBidWVubyBlcyBtaSBtb2RlbG8gZW4gc3UgdG90YWxpZGFkIHBhcmEgZXhwbGljYXIgbWkgdmFyaWFibGUgWS4gCgpJTVBPUlRBTlRFOiBwb2RlbW9zIHVzYXIgZWwgKipSIGN1YWRyYWRvKiogcGFyYSBjb21wYXJhciBtb2RlbG9zIGRpc3RpbnRvcyBlbnRyZSBzw60KCiogU2kgc2UgZW5jdWVudHJhIG11eSBjZXJjYSBkZSAwLCBlbCBtb2RlbG8gZXMgbWFsbyBwYXJhIGV4cGxpY2FyIGEgbGEgdmFyaWFibGUgWQoKKiBTaSBzZSBlbmN1ZW50cmEgbXV5IGNlcmNhIGRlIDEsIGVsIG1vZGVsbyBlcyBidWVubyBwYXJhIGV4cGxpY2FyIGEgbGEgdmFyaWFibGUgWQoKQ29uIGxhIGZ1bmNpw7NuIGBzdW1tYXJ5YCBhY2NlZGVtb3MgYSB1biByZXN1bWVuIGRlbCBtb2RlbG8gcXVlIHZhIGEgdGVuZXIgdG9kYXMgbGFzIGNvc2FzIG1lbmNpb25hZGFzIGFudGVyaW9ybWVudGUKCmBgYHtyfQojIFJlc3VtZW4gZGVsIG1vZGVsbwpzdW1tYXJ5KG1vZGVsb19hc2VzaW5hdG9zKQpgYGAKCk5vdGVtb3MgcXVlOgoKKiBBbWJvcyBwLXZhbG9yZXMgc29uIG1hcyBjaGljb3MgcXVlIDAuMDUuIEVudG9uY2VzIGxhIHZhcmlhYmxlIEFzZXNpbmF0b3MgZXMgYnVlbmEgcGFyYSBleHBsaWNhciBsYSBFc3BlcmFuemEgZGUgVmlkYQoKKiBFbCBSIGN1YWRyYWRvIChNdWx0aXBsZSBSLXNxdWFyZWQpIGVzIGlndWFsIGEgMC42MS4gUG9yIGxvIHF1ZSBwb2RlbW9zIGRlY2lyIHF1ZSBlcyB1biBidWVuIG1vZGVsbwoKQWhvcmEgY3JlZW1vcyBvdHJvIG1vZGVsbywgcGFyYSB2ZXIgc2kgc3UgUi1jdWFkcmFkbyBlcyBtYXlvciBvIG1lbm9yLgoKTnVlc3RybyBudWV2byBtb2RlbG8gdmEgYSB0cmF0YXIgZGUgZXhwbGljYXIgbGEgRXNwZXJhbnphIGRlIFZpZGEgYSBwYXJ0aXIgZGVsIEluZ3Jlc28gcGVyIGNhcGl0YQoKYGBge3J9CiNDcmVvIGVsIG1vZGVsbyBjb24gbGlmZV9leHAgKHZhcmlhYmxlIGEgcHJlZGVjaXIpIH4gSW5jb21lICh2YXJpYWJsZSBwcmVkaWN0b3JhKQptb2RlbG9faW5ncmVzbzwtbG0oZm9ybXVsYSA9IGxpZmVfZXhwfkluY29tZSwgZGF0YSA9IGVzdGFkb3MpCiMgUmVzdW1lbiBkZWwgbW9kZWxvCnN1bW1hcnkobW9kZWxvX2luZ3Jlc28pCmBgYAoKTm90ZW1vcyBxdWU6CgoqIEFtYm9zIHAtdmFsb3JlcyBzb24gbWFzIGNoaWNvcyBxdWUgMC4wNS4gRW50b25jZXMgbGEgdmFyaWFibGUgSW5ncmVzbyBlcyBidWVuYSBwYXJhIGV4cGxpY2FyIGxhIEVzcGVyYW56YSBkZSBWaWRhCgoqIEVsIFIgY3VhZHJhZG8gKE11bHRpcGxlIFItc3F1YXJlZCkgZXMgaWd1YWwgYSAwLjEyCgpFbiBjb25jbHVzacOzbiwgbnVlc3RybyBwcmltZXIgbW9kZWxvIHRpZW5lIHVuIFIgY3VhZHJhZG8gbXVjaG8gbcOhcyBhbHRvIHF1ZSBlbCBzZWd1bmRvIG1vZGVsby4gUG9yIGxvIHRhbnRvLCBlbCBwcmltZXIgbW9kZWxvIGVzIG11Y2hvIG1lam9yIHBhcmEgcHJlZGVjaXIgbGEgZXNwZXJhbnphIGRlIHZpZGEgZGUgbG9zIGVzdGFkb3MgZGUgRXN0YWRvcyBVbmlkb3MgcXVlIGVsIHNlZ3VuZG8uCgojIEVqZXJjaWNpb3MgZGUgdGFyZWEKCiAgMSkgUmVhbGl6YXIgZWwgZ3LDoWZpY28gZGUgZGlzcGVyc2nDs24gZW50cmUgKipJbmNvbWUqKiB5ICoqSWxsaXRlcmFjeSoqLCB5IGVudHJlICoqSW5jb21lKiogeSAqKmhzX2dyYWQqKgoKICAyKSBDYWxjdWxhciBsYSBjb3ZhcmlhbnphIHkgY29ycmVsYWNpw7NuIGVudHJlICoqSW5jb21lKiogeSAqKklsbGl0ZXJhY3kqKiwgeSBlbnRyZSAqKkluY29tZSoqIHkgKipoc19ncmFkKioKCiAgMykgCiAgICBhKSBSZWFsaXphciB1biBtb2RlbG8gbGluZWFsIHF1ZSBleHBsaXF1ZSAgKipJbmNvbWUqKiBlbiBmdW5jacOzbiBkZSAqKklsbGl0ZXJhY3kqKgogIAogICAgYikgUmVhbGl6YXIgdW4gbW9kZWxvIGxpbmVhbCBxdWUgZXhwbGlxdWUgICoqSW5jb21lKiogZW4gZnVuY2nDs24gZGUgKipoc19ncmFkKioKCiAgNCkgT2J0ZW5lciBsb3MgY29lZmllbnRlcyBkZSBsb3MgMiBtb2RlbG9zIHByZXZpb3MuIEludGVycHJldGFybG9zIGJyZXZlbWVudGUKICAKICA1KSBPYnRlbmVyIGVsIFItY3VhZHJhZG8gZGUgbG9zIDIgbW9kZWxvcyBhbnRlcmlvcmVzLiBFbGVnaXIgZWwgcXVlIG1lam9yIGV4cGxpcXVlIGxhIHZhcmlhYmxlICoqSW5jb21lKioKCioqQm9udXMqKgoKICA2KSBHcmFmaWNhciBsYSByZWN0YSBkZSBjYWRhIG1vZGVsbyBzb2JyZSBlbCBkaWFncmFtYSBkZSBkaXNwZXJzacOzbiBjb3JyZXNwb25kaWVudGUK