Introducción

Hasta el momento se ha visto la prueba t para comparar medias de solo 2 grupos. En esta sección veremos cómo expandir la comparación para varias medias usando otra prueba de inferencia. Es decir, se busca analizar la relación entre una variable dependiente cuantitativa (o numérica) y una variable independiente categórica (o de factor).

La media de la variable dependiente es comparada para cada grupo de la variable independiente categórica, típicamente una variable nominal. Por ejemplo:

  • Ingresos entre grupos étnicos.

  • CRAEST entre alumnos de especialidades de Ciencias Sociales.

  • Posición ideológica entre simpatizantes de diferentes partidos.

Para poder hacer estas comparaciones entre varios grupos vamos a usar el test del ANOVA

Test de ANOVA

El test de ANOVA sirve para comparar la media de una variable dependiente numérica entre grupos de una variable de tipo factor (con más de 2 grupos).

Este test parte teóricamente de la distribución general de la variable numérica, la que tiene una media poblacional \(\mu\), y compara esta media poblacional general, con las medias poblacionales de la variable numérica por cada grupo de la variable de factor con n grupos, \(\mu_1...\mu_2...\mu_3...\mu_n\).

Esta prueba se basa en la distribución F y propone la siguiente hipótesis nula para la comparación de una variable numérica X entre n grupos de la variable de factor.

\[ H0: \mu_{x1} = \mu_{x2} = \mu_{x1} =...= \mu_{xn} \]

La hipótesis alternativa que propone es que al menos una media poblacional de un grupo es diferente. Es decir, si se rechaza la H0, quizá todas las medias poblacionales entre grupos sean distintas, quizá algunas o quizá solo una difiere de las otras.

Esta prueba se basa en una comparación entre la variabilidad entre (between) y la variabilidad intra (within).

Variabilidad entre

  • La variabilidad entre se refiere a la comparación de la media muestral grupal \(\overline{X}_1\) y la media general \(\overline{X}\).

  • Se entiende como un promedio ponderado de las distancias \(\overline{X_g}-\overline{X}\).

  • Para evitar que sea una distancia negativa se eleva al cuadrado \((\overline{X_g}-\overline{X})^2\).

  • Se pondera por el número de observaciones de cada grupo \(n_g*(\overline{X_g}-\overline{X})^2\).

  • Se suma estas cantidades de cada grupo: \(\sum n_g*(\overline{X_g}-\overline{X})^2\).

  • Esa suma se divide entre los grados de libertad g-1 (número de grupos -1).

Variabilidad intra

  • Es la variabilidad entre las observaciones de cada grupo con su media grupal.

  • Se entiende como el cálculo de la desviación estándar en cada grupo.

  • Se calcula \(\sum (X_i-\overline{X_g})^2\) en cada grupo. Estas sumatorias se suman.

  • Esa suma total se divide entre los grados de libertad N-g (total de observaciones - número de grupos).

Estadístico de la prueba F

  • Se calcula como F = estimado de la variabilidad entre / estimado de la variabilidad intra

El estadístico F se hace grande cuando: hay mayor variabilidad entre y/o menos variabilidad intra.

El estadístico F se hace pequeño cuando: hay menor variabilidad entre y/o mayor variabilidad intra.

A medida que el estadístico F es más grande, se ubica más en la cola de la distribución, por lo que el p-value será menor, con los que se tendría una mayor evidencia en contra de la H0 sobre la igualdad de medias poblacionales.

Por lo tanto se concluiría que al menos una de las medias grupales sería significativamente diferente de las otras medias grupales. El tema es que la prueba de ANOVA no llega hasta ahí, no nos indica qué medias son diferentes. Para saber qué media(s) es(son) diferente(s) se tiene que hacer un test posterior.

Post hoc: Test de Tukey

Este test sirve para analizar qué diferencias entre grupos son significativas. Es decir, reporta todos los emparejamientos posibles entre grupos y en cada pareja calcula una prueba t de diferencia de medias y la reporta.

Ejemplo 1 para una variable numérica entre 2+ grupos: ENDO

library(rio)
endo2020 = import("bases/ENDO_REMOTO_2020.dta")

Si queremos evaluar si existen diferencias entre el número promedio de alumnos con los que trabaja un profesor entre tipos de profesores (nombrados, contratados con concurso o contratados con otra modalidad), se puede usar ANOVA.

Primero se tiene que factorizar la variable tipo de profesor (P1_7).

library(dplyr)
library(tidyverse)
endo2020 = endo2020 %>%
  mutate(tipo = factor(P1_7, labels=c("Nombrado", "Contratado por concurso",
                                      "Contratado por otra modalidad")))
alumxtipo = endo2020 %>% 
  group_by(tipo) %>%
  summarize(media = mean(P1_6, na.rm = T), desv = sd(P1_6, na.rm = T))
alumxtipo
## # A tibble: 4 × 3
##   tipo                          media  desv
##   <fct>                         <dbl> <dbl>
## 1 Nombrado                       36.9  48.0
## 2 Contratado por concurso        43.7  53.6
## 3 Contratado por otra modalidad  50.6  66.1
## 4 <NA>                          NaN    NA
alumxtipo = alumxtipo[-4, ]

Para tener una descripción completa entre los 3 grupos, también se puede usar:

library(lsr)
ICalumxtipo = endo2020 %>%
  group_by(tipo) %>%
  summarise(media = mean(P1_6, na.rm=T),
            liminf = ciMean(P1_6, na.rm=T)[1],
            limsup = ciMean(P1_6, na.rm=T)[2]
            )
ICalumxtipo
## # A tibble: 4 × 4
##   tipo                          media liminf limsup
##   <fct>                         <dbl>  <dbl>  <dbl>
## 1 Nombrado                       36.9   36.0   37.8
## 2 Contratado por concurso        43.7   42.5   44.8
## 3 Contratado por otra modalidad  50.6   37.5   63.8
## 4 <NA>                          NaN     NA     NA
ICalumxtipo = ICalumxtipo[-4, ]

¿Qué conclusiones “informales” se pueden sacar del gráfico?

library(ggplot2)
graf1 = ggplot(ICalumxtipo, aes(x=tipo, y=media))+
  geom_bar(stat="identity")+
  geom_errorbar(aes(ymin=liminf, ymax=limsup), width=0.2)+
  geom_text(aes(label=paste(round(media, 1))), vjust=-1, size=3)+
  xlab("Tipo del contrato") + ylab("Alumnos atendidos")+
  ylim(0, 80)
graf1

Esta observación visual se tiene que confirmar con la prueba de ANOVA. Para esto se usa el comando aov para crear un objeto “anova1” que luego se describe con summary.

anova1 = aov(endo2020$P1_6~endo2020$tipo)
summary(anova1)
##                  Df   Sum Sq Mean Sq F value Pr(>F)    
## endo2020$tipo     2   223104  111552   43.48 <2e-16 ***
## Residuals     18947 48614075    2566                   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 9266 observations deleted due to missingness

Con la prueba de ANOVA y dado que el p-value es menor a 0.05, se puede rechazar la H0. Es decir, se afirma la Ha de que al menos una de las diferencias es significativa. ANOVA no nos indica cuál es la(s) diferencia(s) significativa(s).

Para evaluar las diferencias, se corre la prueba de Tukey para analizar cada emparejamiento. Esto se hace con el comando TukeyHSD en el que se inserta el objeto “anova1” y con el cual se crea un objeto “compara”.

compara = TukeyHSD(anova1)
compara
##   Tukey multiple comparisons of means
##     95% family-wise confidence level
## 
## Fit: aov(formula = endo2020$P1_6 ~ endo2020$tipo)
## 
## $`endo2020$tipo`
##                                                            diff       lwr
## Contratado por concurso-Nombrado                       6.743547  5.003923
## Contratado por otra modalidad-Nombrado                13.713640  1.724766
## Contratado por otra modalidad-Contratado por concurso  6.970093 -5.032398
##                                                             upr     p adj
## Contratado por concurso-Nombrado                       8.483171 0.0000000
## Contratado por otra modalidad-Nombrado                25.702515 0.0200876
## Contratado por otra modalidad-Contratado por concurso 18.972585 0.3615009

Se observa que los resultados comprueban las observaciones del gráfico. Cada emparejamiento tiene un valor de la diferencia de medias “diff”, un límite inferior “lwr” y límite superior “upr” del intervalo de confianza de esa diferencia y un p-value “p adj”. Este último valor es el que se evalúa para saber si el emparejamiento tiene una diferencia estadísticamente significativa. Se observa que el emparejamiento “Contratado por concurso-Nombrado” tiene un p-value muy pequeño (no es cero, solo faltan decimales), por lo que podemos rechazar la Ho y afirmar que sí existen diferencias en el número de alumnos con los que trabajan estos tipo de profesores.

El emparejamiento entre “Contratado por otra modalidad-Nombrado” tiene un p-value de 0.02, que es menor que 0.05, por lo que concluimos que también existen diferencias en el número de alumnos promedio con el que trabajan estos tipos de profesores.

El emparejamiento “Contratado por otra modalidad-Contratado por concurso” tiene un p-value = 0.36 que es mayor que 0.05, por lo que no se puede concluir que haya diferencias en el promedio de alumnos con los que trabajan estos tipos de profesores.

Este gráfico se puede reproducir con la librería ggplot. Para esto, primero, se tiene que transformar el objeto “compara” (que es una lista) en un dataframe, con el comando as.data.frame y se crea un nuevo objeto “compara.df”, que tiene los valores que requerimos para graficar, excepto que el nombre de las comparaciones esta como nombre de las filas y no como variable. Para incluir las comparaciones como una variable se usa el comando rownames y se crea una nueva columna compara.df$compara.

compara.df = as.data.frame(compara[1])
compara.df$compara = rownames(compara.df)

Con este dataframe, podemos usar la librería ggplot para graficar los intervalos de confianza de las diferencias de medias. Aquellos emparejamientos cuyas líneas no crucen la línea vertical del cero, se puede decir que hay diferencias estadísticamente significativas.

graf2 = ggplot(compara.df, aes(x=compara, y=endo2020.tipo.diff))+
  geom_errorbar(aes(ymin=endo2020.tipo.lwr, ymax=endo2020.tipo.upr), width=0.2)+
  geom_text(aes(label=paste(round(endo2020.tipo.diff, 1))), vjust=-1, size=3)+
  xlab("Comparación") + ylab("Diferencia")+
  ylim(-10, 40) +
  coord_flip() +
  geom_hline(yintercept = 0, color = "red", linetype="dotted") +
  theme_classic()
graf2

NOTA: Hay ocasiones como esta en que la prueba de ANOVA indica que existe un emparejamiento con una diferencia significativa, y luego, cuando se evalúan los emparejamientos, no se observa esa diferencia. Eso es debido a que cada emparejamiento de evalúa mediante la prueba t de manera autónoma.

LS0tCnRpdGxlOiAiQ2xhc2UgNyIKYXV0aG9yOiAiQXJ0dXJvIE1hbGRvbmFkbyIKZGF0ZTogIjIxLzEwLzIwMjQiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGNvbGxhcHNlZDogZmFsc2UKICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UKICAgIHRvY19kZXB0aDogMQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdGhlbWU6IGNvc21vCiAgICBoaWdobGlnaHQ6IHRleHRtYXRlCmVkaXRvcl9vcHRpb25zOgogIG1hcmtkb3duOgogICAgd3JhcDogc2VudGVuY2UKYmlibGlvZ3JhcGh5OiByZWZlcmVuY2VzLmJpYgotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmBgYAoKIyBJbnRyb2R1Y2Npw7NuCgpIYXN0YSBlbCBtb21lbnRvIHNlIGhhIHZpc3RvIGxhIHBydWViYSB0IHBhcmEgY29tcGFyYXIgbWVkaWFzIGRlIHNvbG8gMiBncnVwb3MuCkVuIGVzdGEgc2VjY2nDs24gdmVyZW1vcyBjw7NtbyBleHBhbmRpciBsYSBjb21wYXJhY2nDs24gcGFyYSB2YXJpYXMgbWVkaWFzIHVzYW5kbyBvdHJhIHBydWViYSBkZSBpbmZlcmVuY2lhLgpFcyBkZWNpciwgc2UgYnVzY2EgYW5hbGl6YXIgbGEgcmVsYWNpw7NuIGVudHJlIHVuYSB2YXJpYWJsZSBkZXBlbmRpZW50ZSBjdWFudGl0YXRpdmEgKG8gbnVtw6lyaWNhKSB5IHVuYSB2YXJpYWJsZSBpbmRlcGVuZGllbnRlIGNhdGVnw7NyaWNhIChvIGRlIGZhY3RvcikuCgpMYSBtZWRpYSBkZSBsYSB2YXJpYWJsZSBkZXBlbmRpZW50ZSBlcyBjb21wYXJhZGEgcGFyYSBjYWRhIGdydXBvIGRlIGxhIHZhcmlhYmxlIGluZGVwZW5kaWVudGUgY2F0ZWfDs3JpY2EsIHTDrXBpY2FtZW50ZSB1bmEgdmFyaWFibGUgbm9taW5hbC4KUG9yIGVqZW1wbG86CgotICAgSW5ncmVzb3MgZW50cmUgZ3J1cG9zIMOpdG5pY29zLgoKLSAgIENSQUVTVCBlbnRyZSBhbHVtbm9zIGRlIGVzcGVjaWFsaWRhZGVzIGRlIENpZW5jaWFzIFNvY2lhbGVzLgoKLSAgIFBvc2ljacOzbiBpZGVvbMOzZ2ljYSBlbnRyZSBzaW1wYXRpemFudGVzIGRlIGRpZmVyZW50ZXMgcGFydGlkb3MuCgpQYXJhIHBvZGVyIGhhY2VyIGVzdGFzIGNvbXBhcmFjaW9uZXMgZW50cmUgdmFyaW9zIGdydXBvcyB2YW1vcyBhIHVzYXIgZWwgdGVzdCBkZWwgQU5PVkEKCiMgVGVzdCBkZSBBTk9WQQoKRWwgdGVzdCBkZSBBTk9WQSBzaXJ2ZSBwYXJhIGNvbXBhcmFyIGxhIG1lZGlhIGRlIHVuYSB2YXJpYWJsZSBkZXBlbmRpZW50ZSBudW3DqXJpY2EgZW50cmUgZ3J1cG9zIGRlIHVuYSB2YXJpYWJsZSBkZSB0aXBvIGZhY3RvciAoY29uIG3DoXMgZGUgMiBncnVwb3MpLgoKRXN0ZSB0ZXN0IHBhcnRlIHRlw7NyaWNhbWVudGUgZGUgbGEgZGlzdHJpYnVjacOzbiBnZW5lcmFsIGRlIGxhIHZhcmlhYmxlIG51bcOpcmljYSwgbGEgcXVlIHRpZW5lIHVuYSBtZWRpYSBwb2JsYWNpb25hbCAkXG11JCwgeSBjb21wYXJhIGVzdGEgbWVkaWEgcG9ibGFjaW9uYWwgZ2VuZXJhbCwgY29uIGxhcyBtZWRpYXMgcG9ibGFjaW9uYWxlcyBkZSBsYSB2YXJpYWJsZSBudW3DqXJpY2EgcG9yIGNhZGEgZ3J1cG8gZGUgbGEgdmFyaWFibGUgZGUgZmFjdG9yIGNvbiBuIGdydXBvcywgJFxtdV8xLi4uXG11XzIuLi5cbXVfMy4uLlxtdV9uJC4KCiFbXShhbm92YTEucG5nKXt3aWR0aD0iNTM0In0KCkVzdGEgcHJ1ZWJhIHNlIGJhc2EgZW4gbGEgZGlzdHJpYnVjacOzbiBGIHkgcHJvcG9uZSBsYSBzaWd1aWVudGUgaGlww7N0ZXNpcyBudWxhIHBhcmEgbGEgY29tcGFyYWNpw7NuIGRlIHVuYSB2YXJpYWJsZSBudW3DqXJpY2EgWCBlbnRyZSBuIGdydXBvcyBkZSBsYSB2YXJpYWJsZSBkZSBmYWN0b3IuCgokJApIMDogXG11X3t4MX0gPSBcbXVfe3gyfSA9IFxtdV97eDF9ID0uLi49IFxtdV97eG59CiQkCgpMYSBoaXDDs3Rlc2lzIGFsdGVybmF0aXZhIHF1ZSBwcm9wb25lIGVzIHF1ZSBhbCBtZW5vcyB1bmEgbWVkaWEgcG9ibGFjaW9uYWwgZGUgdW4gZ3J1cG8gZXMgZGlmZXJlbnRlLgpFcyBkZWNpciwgc2kgc2UgcmVjaGF6YSBsYSBIMCwgcXVpesOhIHRvZGFzIGxhcyBtZWRpYXMgcG9ibGFjaW9uYWxlcyBlbnRyZSBncnVwb3Mgc2VhbiBkaXN0aW50YXMsIHF1aXrDoSBhbGd1bmFzIG8gcXVpesOhIHNvbG8gdW5hIGRpZmllcmUgZGUgbGFzIG90cmFzLgoKRXN0YSBwcnVlYmEgc2UgYmFzYSBlbiB1bmEgY29tcGFyYWNpw7NuIGVudHJlIGxhIHZhcmlhYmlsaWRhZCBlbnRyZSAoYmV0d2VlbikgeSBsYSB2YXJpYWJpbGlkYWQgaW50cmEgKHdpdGhpbikuCgojIyBWYXJpYWJpbGlkYWQgZW50cmUKCi0gICBMYSB2YXJpYWJpbGlkYWQgZW50cmUgc2UgcmVmaWVyZSBhIGxhIGNvbXBhcmFjacOzbiBkZSBsYSBtZWRpYSBtdWVzdHJhbCBncnVwYWwgJFxvdmVybGluZXtYfV8xJCB5IGxhIG1lZGlhIGdlbmVyYWwgJFxvdmVybGluZXtYfSQuCgotICAgU2UgZW50aWVuZGUgY29tbyB1biBwcm9tZWRpbyBwb25kZXJhZG8gZGUgbGFzIGRpc3RhbmNpYXMgJFxvdmVybGluZXtYX2d9LVxvdmVybGluZXtYfSQuCgotICAgUGFyYSBldml0YXIgcXVlIHNlYSB1bmEgZGlzdGFuY2lhIG5lZ2F0aXZhIHNlIGVsZXZhIGFsIGN1YWRyYWRvICQoXG92ZXJsaW5le1hfZ30tXG92ZXJsaW5le1h9KV4yJC4KCi0gICBTZSBwb25kZXJhIHBvciBlbCBuw7ptZXJvIGRlIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBncnVwbyAkbl9nKihcb3ZlcmxpbmV7WF9nfS1cb3ZlcmxpbmV7WH0pXjIkLgoKLSAgIFNlIHN1bWEgZXN0YXMgY2FudGlkYWRlcyBkZSBjYWRhIGdydXBvOiAkXHN1bSBuX2cqKFxvdmVybGluZXtYX2d9LVxvdmVybGluZXtYfSleMiQuCgotICAgRXNhIHN1bWEgc2UgZGl2aWRlIGVudHJlIGxvcyBncmFkb3MgZGUgbGliZXJ0YWQgZy0xIChuw7ptZXJvIGRlIGdydXBvcyAtMSkuCgojIyBWYXJpYWJpbGlkYWQgaW50cmEKCi0gICBFcyBsYSB2YXJpYWJpbGlkYWQgZW50cmUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBncnVwbyBjb24gc3UgbWVkaWEgZ3J1cGFsLgoKLSAgIFNlIGVudGllbmRlIGNvbW8gZWwgY8OhbGN1bG8gZGUgbGEgZGVzdmlhY2nDs24gZXN0w6FuZGFyIGVuIGNhZGEgZ3J1cG8uCgotICAgU2UgY2FsY3VsYSAkXHN1bSAoWF9pLVxvdmVybGluZXtYX2d9KV4yJCBlbiBjYWRhIGdydXBvLgogICAgRXN0YXMgc3VtYXRvcmlhcyBzZSBzdW1hbi4KCi0gICBFc2Egc3VtYSB0b3RhbCBzZSBkaXZpZGUgZW50cmUgbG9zIGdyYWRvcyBkZSBsaWJlcnRhZCBOLWcgKHRvdGFsIGRlIG9ic2VydmFjaW9uZXMgLSBuw7ptZXJvIGRlIGdydXBvcykuCgojIyBFc3RhZMOtc3RpY28gZGUgbGEgcHJ1ZWJhIEYKCi0gICBTZSBjYWxjdWxhIGNvbW8gRiA9IGVzdGltYWRvIGRlIGxhIHZhcmlhYmlsaWRhZCBlbnRyZSAvIGVzdGltYWRvIGRlIGxhIHZhcmlhYmlsaWRhZCBpbnRyYQoKRWwgZXN0YWTDrXN0aWNvIEYgc2UgaGFjZSBncmFuZGUgY3VhbmRvOiBoYXkgbWF5b3IgdmFyaWFiaWxpZGFkIGVudHJlIHkvbyBtZW5vcyB2YXJpYWJpbGlkYWQgaW50cmEuCgpFbCBlc3RhZMOtc3RpY28gRiBzZSBoYWNlIHBlcXVlw7FvIGN1YW5kbzogaGF5IG1lbm9yIHZhcmlhYmlsaWRhZCBlbnRyZSB5L28gbWF5b3IgdmFyaWFiaWxpZGFkIGludHJhLgoKQSBtZWRpZGEgcXVlIGVsIGVzdGFkw61zdGljbyBGIGVzIG3DoXMgZ3JhbmRlLCBzZSB1YmljYSBtw6FzIGVuIGxhIGNvbGEgZGUgbGEgZGlzdHJpYnVjacOzbiwgcG9yIGxvIHF1ZSBlbCBwLXZhbHVlIHNlcsOhIG1lbm9yLCBjb24gbG9zIHF1ZSBzZSB0ZW5kcsOtYSB1bmEgbWF5b3IgZXZpZGVuY2lhIGVuIGNvbnRyYSBkZSBsYSBIMCBzb2JyZSBsYSBpZ3VhbGRhZCBkZSBtZWRpYXMgcG9ibGFjaW9uYWxlcy4KCiFbXShhbm92YTIucG5nKXt3aWR0aD0iNTM0In0KClBvciBsbyB0YW50byBzZSBjb25jbHVpcsOtYSBxdWUgYWwgbWVub3MgdW5hIGRlIGxhcyBtZWRpYXMgZ3J1cGFsZXMgc2Vyw61hIHNpZ25pZmljYXRpdmFtZW50ZSBkaWZlcmVudGUgZGUgbGFzIG90cmFzIG1lZGlhcyBncnVwYWxlcy4KRWwgdGVtYSBlcyBxdWUgbGEgcHJ1ZWJhIGRlIEFOT1ZBIG5vIGxsZWdhIGhhc3RhIGFow60sIG5vIG5vcyBpbmRpY2EgcXXDqSBtZWRpYXMgc29uIGRpZmVyZW50ZXMuClBhcmEgc2FiZXIgcXXDqSBtZWRpYShzKSBlcyhzb24pIGRpZmVyZW50ZShzKSBzZSB0aWVuZSBxdWUgaGFjZXIgdW4gdGVzdCBwb3N0ZXJpb3IuCgojIyBQb3N0IGhvYzogVGVzdCBkZSBUdWtleQoKRXN0ZSB0ZXN0IHNpcnZlIHBhcmEgYW5hbGl6YXIgcXXDqSBkaWZlcmVuY2lhcyBlbnRyZSBncnVwb3Mgc29uIHNpZ25pZmljYXRpdmFzLgpFcyBkZWNpciwgcmVwb3J0YSB0b2RvcyBsb3MgZW1wYXJlamFtaWVudG9zIHBvc2libGVzIGVudHJlIGdydXBvcyB5IGVuIGNhZGEgcGFyZWphIGNhbGN1bGEgdW5hIHBydWViYSB0IGRlIGRpZmVyZW5jaWEgZGUgbWVkaWFzIHkgbGEgcmVwb3J0YS4KCiMgRWplbXBsbyAxIHBhcmEgdW5hIHZhcmlhYmxlIG51bcOpcmljYSBlbnRyZSAyKyBncnVwb3M6IEVORE8KCmBgYHtyIGJhc2UgZW5kbywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShyaW8pCmVuZG8yMDIwID0gaW1wb3J0KCJiYXNlcy9FTkRPX1JFTU9UT18yMDIwLmR0YSIpCmBgYAoKU2kgcXVlcmVtb3MgZXZhbHVhciBzaSBleGlzdGVuIGRpZmVyZW5jaWFzIGVudHJlIGVsIG7Dum1lcm8gcHJvbWVkaW8gZGUgYWx1bW5vcyBjb24gbG9zIHF1ZSB0cmFiYWphIHVuIHByb2Zlc29yIGVudHJlIHRpcG9zIGRlIHByb2Zlc29yZXMgKG5vbWJyYWRvcywgY29udHJhdGFkb3MgY29uIGNvbmN1cnNvIG8gY29udHJhdGFkb3MgY29uIG90cmEgbW9kYWxpZGFkKSwgc2UgcHVlZGUgdXNhciBBTk9WQS4KClByaW1lcm8gc2UgdGllbmUgcXVlIGZhY3Rvcml6YXIgbGEgdmFyaWFibGUgdGlwbyBkZSBwcm9mZXNvciAoUDFfNykuCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKZW5kbzIwMjAgPSBlbmRvMjAyMCAlPiUKICBtdXRhdGUodGlwbyA9IGZhY3RvcihQMV83LCBsYWJlbHM9YygiTm9tYnJhZG8iLCAiQ29udHJhdGFkbyBwb3IgY29uY3Vyc28iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDb250cmF0YWRvIHBvciBvdHJhIG1vZGFsaWRhZCIpKSkKYGBgCgpgYGB7cn0KYWx1bXh0aXBvID0gZW5kbzIwMjAgJT4lIAogIGdyb3VwX2J5KHRpcG8pICU+JQogIHN1bW1hcml6ZShtZWRpYSA9IG1lYW4oUDFfNiwgbmEucm0gPSBUKSwgZGVzdiA9IHNkKFAxXzYsIG5hLnJtID0gVCkpCmFsdW14dGlwbwpgYGAKCmBgYHtyfQphbHVteHRpcG8gPSBhbHVteHRpcG9bLTQsIF0KYGBgCgpQYXJhIHRlbmVyIHVuYSBkZXNjcmlwY2nDs24gY29tcGxldGEgZW50cmUgbG9zIDMgZ3J1cG9zLCB0YW1iacOpbiBzZSBwdWVkZSB1c2FyOgoKYGBge3J9CmxpYnJhcnkobHNyKQpJQ2FsdW14dGlwbyA9IGVuZG8yMDIwICU+JQogIGdyb3VwX2J5KHRpcG8pICU+JQogIHN1bW1hcmlzZShtZWRpYSA9IG1lYW4oUDFfNiwgbmEucm09VCksCiAgICAgICAgICAgIGxpbWluZiA9IGNpTWVhbihQMV82LCBuYS5ybT1UKVsxXSwKICAgICAgICAgICAgbGltc3VwID0gY2lNZWFuKFAxXzYsIG5hLnJtPVQpWzJdCiAgICAgICAgICAgICkKSUNhbHVteHRpcG8KYGBgCgpgYGB7cn0KSUNhbHVteHRpcG8gPSBJQ2FsdW14dGlwb1stNCwgXQpgYGAKCsK/UXXDqSBjb25jbHVzaW9uZXMgImluZm9ybWFsZXMiIHNlIHB1ZWRlbiBzYWNhciBkZWwgZ3LDoWZpY28/CgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQpncmFmMSA9IGdncGxvdChJQ2FsdW14dGlwbywgYWVzKHg9dGlwbywgeT1tZWRpYSkpKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikrCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1saW1pbmYsIHltYXg9bGltc3VwKSwgd2lkdGg9MC4yKSsKICBnZW9tX3RleHQoYWVzKGxhYmVsPXBhc3RlKHJvdW5kKG1lZGlhLCAxKSkpLCB2anVzdD0tMSwgc2l6ZT0zKSsKICB4bGFiKCJUaXBvIGRlbCBjb250cmF0byIpICsgeWxhYigiQWx1bW5vcyBhdGVuZGlkb3MiKSsKICB5bGltKDAsIDgwKQpncmFmMQpgYGAKCkVzdGEgb2JzZXJ2YWNpw7NuIHZpc3VhbCBzZSB0aWVuZSBxdWUgY29uZmlybWFyIGNvbiBsYSBwcnVlYmEgZGUgQU5PVkEuClBhcmEgZXN0byBzZSB1c2EgZWwgY29tYW5kbyBgYW92YCBwYXJhIGNyZWFyIHVuIG9iamV0byAiYW5vdmExIiBxdWUgbHVlZ28gc2UgZGVzY3JpYmUgY29uIGBzdW1tYXJ5YC4KCmBgYHtyIGFub3ZhIGFsdW1ub3MgeCB0aXBvfQphbm92YTEgPSBhb3YoZW5kbzIwMjAkUDFfNn5lbmRvMjAyMCR0aXBvKQpzdW1tYXJ5KGFub3ZhMSkKYGBgCgpDb24gbGEgcHJ1ZWJhIGRlIEFOT1ZBIHkgZGFkbyBxdWUgZWwgcC12YWx1ZSBlcyBtZW5vciBhIDAuMDUsIHNlIHB1ZWRlIHJlY2hhemFyIGxhIEgwLgpFcyBkZWNpciwgc2UgYWZpcm1hIGxhIEhhIGRlIHF1ZSBhbCBtZW5vcyB1bmEgZGUgbGFzIGRpZmVyZW5jaWFzIGVzIHNpZ25pZmljYXRpdmEuCkFOT1ZBIG5vIG5vcyBpbmRpY2EgY3XDoWwgZXMgbGEocykgZGlmZXJlbmNpYShzKSBzaWduaWZpY2F0aXZhKHMpLgoKUGFyYSBldmFsdWFyIGxhcyBkaWZlcmVuY2lhcywgc2UgY29ycmUgbGEgcHJ1ZWJhIGRlIFR1a2V5IHBhcmEgYW5hbGl6YXIgY2FkYSBlbXBhcmVqYW1pZW50by4KRXN0byBzZSBoYWNlIGNvbiBlbCBjb21hbmRvIGBUdWtleUhTRGAgZW4gZWwgcXVlIHNlIGluc2VydGEgZWwgb2JqZXRvICJhbm92YTEiIHkgY29uIGVsIGN1YWwgc2UgY3JlYSB1biBvYmpldG8gImNvbXBhcmEiLgoKYGBge3IgVHVrZXkgYWx1bW5vcyB4IHRpcG99CmNvbXBhcmEgPSBUdWtleUhTRChhbm92YTEpCmNvbXBhcmEKYGBgCgpTZSBvYnNlcnZhIHF1ZSBsb3MgcmVzdWx0YWRvcyBjb21wcnVlYmFuIGxhcyBvYnNlcnZhY2lvbmVzIGRlbCBncsOhZmljby4KQ2FkYSBlbXBhcmVqYW1pZW50byB0aWVuZSB1biB2YWxvciBkZSBsYSBkaWZlcmVuY2lhIGRlIG1lZGlhcyAiZGlmZiIsIHVuIGzDrW1pdGUgaW5mZXJpb3IgImx3ciIgeSBsw61taXRlIHN1cGVyaW9yICJ1cHIiIGRlbCBpbnRlcnZhbG8gZGUgY29uZmlhbnphIGRlIGVzYSBkaWZlcmVuY2lhIHkgdW4gcC12YWx1ZSAicCBhZGoiLgpFc3RlIMO6bHRpbW8gdmFsb3IgZXMgZWwgcXVlIHNlIGV2YWzDumEgcGFyYSBzYWJlciBzaSBlbCBlbXBhcmVqYW1pZW50byB0aWVuZSB1bmEgZGlmZXJlbmNpYSBlc3RhZMOtc3RpY2FtZW50ZSBzaWduaWZpY2F0aXZhLgpTZSBvYnNlcnZhIHF1ZSBlbCBlbXBhcmVqYW1pZW50byAiQ29udHJhdGFkbyBwb3IgY29uY3Vyc28tTm9tYnJhZG8iIHRpZW5lIHVuIHAtdmFsdWUgbXV5IHBlcXVlw7FvIChubyBlcyBjZXJvLCBzb2xvIGZhbHRhbiBkZWNpbWFsZXMpLCBwb3IgbG8gcXVlIHBvZGVtb3MgcmVjaGF6YXIgbGEgSG8geSBhZmlybWFyIHF1ZSBzw60gZXhpc3RlbiBkaWZlcmVuY2lhcyBlbiBlbCBuw7ptZXJvIGRlIGFsdW1ub3MgY29uIGxvcyBxdWUgdHJhYmFqYW4gZXN0b3MgdGlwbyBkZSBwcm9mZXNvcmVzLgoKRWwgZW1wYXJlamFtaWVudG8gZW50cmUgIkNvbnRyYXRhZG8gcG9yIG90cmEgbW9kYWxpZGFkLU5vbWJyYWRvIiB0aWVuZSB1biBwLXZhbHVlIGRlIDAuMDIsIHF1ZSBlcyBtZW5vciBxdWUgMC4wNSwgcG9yIGxvIHF1ZSBjb25jbHVpbW9zIHF1ZSB0YW1iacOpbiBleGlzdGVuIGRpZmVyZW5jaWFzIGVuIGVsIG7Dum1lcm8gZGUgYWx1bW5vcyBwcm9tZWRpbyBjb24gZWwgcXVlIHRyYWJhamFuIGVzdG9zIHRpcG9zIGRlIHByb2Zlc29yZXMuCgpFbCBlbXBhcmVqYW1pZW50byAiQ29udHJhdGFkbyBwb3Igb3RyYSBtb2RhbGlkYWQtQ29udHJhdGFkbyBwb3IgY29uY3Vyc28iIHRpZW5lIHVuIHAtdmFsdWUgPSAwLjM2IHF1ZSBlcyBtYXlvciBxdWUgMC4wNSwgcG9yIGxvIHF1ZSBubyBzZSBwdWVkZSBjb25jbHVpciBxdWUgaGF5YSBkaWZlcmVuY2lhcyBlbiBlbCBwcm9tZWRpbyBkZSBhbHVtbm9zIGNvbiBsb3MgcXVlIHRyYWJhamFuIGVzdG9zIHRpcG9zIGRlIHByb2Zlc29yZXMuCgpFc3RlIGdyw6FmaWNvIHNlIHB1ZWRlIHJlcHJvZHVjaXIgY29uIGxhIGxpYnJlcsOtYSBgZ2dwbG90YC4KUGFyYSBlc3RvLCBwcmltZXJvLCBzZSB0aWVuZSBxdWUgdHJhbnNmb3JtYXIgZWwgb2JqZXRvICJjb21wYXJhIiAocXVlIGVzIHVuYSBsaXN0YSkgZW4gdW4gZGF0YWZyYW1lLCBjb24gZWwgY29tYW5kbyBgYXMuZGF0YS5mcmFtZWAgeSBzZSBjcmVhIHVuIG51ZXZvIG9iamV0byAiY29tcGFyYS5kZiIsIHF1ZSB0aWVuZSBsb3MgdmFsb3JlcyBxdWUgcmVxdWVyaW1vcyBwYXJhIGdyYWZpY2FyLCBleGNlcHRvIHF1ZSBlbCBub21icmUgZGUgbGFzIGNvbXBhcmFjaW9uZXMgZXN0YSBjb21vIG5vbWJyZSBkZSBsYXMgZmlsYXMgeSBubyBjb21vIHZhcmlhYmxlLgpQYXJhIGluY2x1aXIgbGFzIGNvbXBhcmFjaW9uZXMgY29tbyB1bmEgdmFyaWFibGUgc2UgdXNhIGVsIGNvbWFuZG8gYHJvd25hbWVzYCB5IHNlIGNyZWEgdW5hIG51ZXZhIGNvbHVtbmEgYGNvbXBhcmEuZGYkY29tcGFyYWAuCgpgYGB7cn0KY29tcGFyYS5kZiA9IGFzLmRhdGEuZnJhbWUoY29tcGFyYVsxXSkKY29tcGFyYS5kZiRjb21wYXJhID0gcm93bmFtZXMoY29tcGFyYS5kZikKYGBgCgpDb24gZXN0ZSBkYXRhZnJhbWUsIHBvZGVtb3MgdXNhciBsYSBsaWJyZXLDrWEgYGdncGxvdGAgcGFyYSBncmFmaWNhciBsb3MgaW50ZXJ2YWxvcyBkZSBjb25maWFuemEgZGUgbGFzIGRpZmVyZW5jaWFzIGRlIG1lZGlhcy4KQXF1ZWxsb3MgZW1wYXJlamFtaWVudG9zIGN1eWFzIGzDrW5lYXMgbm8gY3J1Y2VuIGxhIGzDrW5lYSB2ZXJ0aWNhbCBkZWwgY2Vybywgc2UgcHVlZGUgZGVjaXIgcXVlIGhheSBkaWZlcmVuY2lhcyBlc3RhZMOtc3RpY2FtZW50ZSBzaWduaWZpY2F0aXZhcy4KCmBgYHtyfQpncmFmMiA9IGdncGxvdChjb21wYXJhLmRmLCBhZXMoeD1jb21wYXJhLCB5PWVuZG8yMDIwLnRpcG8uZGlmZikpKwogIGdlb21fZXJyb3JiYXIoYWVzKHltaW49ZW5kbzIwMjAudGlwby5sd3IsIHltYXg9ZW5kbzIwMjAudGlwby51cHIpLCB3aWR0aD0wLjIpKwogIGdlb21fdGV4dChhZXMobGFiZWw9cGFzdGUocm91bmQoZW5kbzIwMjAudGlwby5kaWZmLCAxKSkpLCB2anVzdD0tMSwgc2l6ZT0zKSsKICB4bGFiKCJDb21wYXJhY2nDs24iKSArIHlsYWIoIkRpZmVyZW5jaWEiKSsKICB5bGltKC0xMCwgNDApICsKICBjb29yZF9mbGlwKCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGNvbG9yID0gInJlZCIsIGxpbmV0eXBlPSJkb3R0ZWQiKSArCiAgdGhlbWVfY2xhc3NpYygpCmdyYWYyCmBgYAoKTk9UQTogSGF5IG9jYXNpb25lcyBjb21vIGVzdGEgZW4gcXVlIGxhIHBydWViYSBkZSBBTk9WQSBpbmRpY2EgcXVlIGV4aXN0ZSB1biBlbXBhcmVqYW1pZW50byBjb24gdW5hIGRpZmVyZW5jaWEgc2lnbmlmaWNhdGl2YSwgeSBsdWVnbywgY3VhbmRvIHNlIGV2YWzDumFuIGxvcyBlbXBhcmVqYW1pZW50b3MsIG5vIHNlIG9ic2VydmEgZXNhIGRpZmVyZW5jaWEuCkVzbyBlcyBkZWJpZG8gYSBxdWUgY2FkYSBlbXBhcmVqYW1pZW50byBkZSBldmFsw7phIG1lZGlhbnRlIGxhIHBydWViYSB0IGRlIG1hbmVyYSBhdXTDs25vbWEuCgojIAo=