Objetivos:

Existen tres estadísticos (o conjunto de prueba de hipótesissobre muestras y poblaciones) que son absolutamente necesarios en la industria y en el desarrollo de investigación. En Rigos existen muchas más pero son cinco los que más frecuentemente aparecen en los casos de estudio y (como observación personal) sugiero que al menos los tres primeros se tengan muy presentes para el curso que desarrollamos

Estos estadísticos son:

  • Prueba T de Student

  • ANOVA (Análisis de Varianza)

  • Prueba \(\chi²\) (chi-cuadrado)

  • Prueba F de Fisher

  • Pruebas no paramétricas (Mann-Whitney, Kruskal-Wallis, etc.)

Sitios consultados:

Este ultimo dataset se puede citar como:

APA Autor: Comunidad de R (o R Core Team si no hay información más específica).  Año: \(2024\) (o el año del paquete datasets más reciente).  Título: Dataset mtcars [DataSet].  Fuente: Paquete datasets de R.  URL: URL de la documentación oficial, por ejemplo: https://stat.ethz.ch/R-manual/R-devel/library/datasets/html/mtcars.html

bibtex @book{Wickham2015, title = {R for Data Science}, author = {Hadley Wickham and Garrett Grolemund}, year = {2015}, publisher = {O’Reilly Media}, url = {https://r4ds.had.co.nz/data-visualisation.html} }

Repaso de definiciones

Nivel de significancia (p-valor)

Un p-valor es una medida de la probabilidad de obtener resultados tan extremos como los observados en un estudio, asumiendo que la hipótesis nula (que no hay efecto o diferencia) es verdadera. Un p-valor bajo indica que los resultados son poco probables bajo la hipótesis nula, lo que sugiere que hay evidencia suficiente para rechazarla. Se utiliza en el contraste de hipótesis para determinar la significación estadística de un resultado.

Recordar

\(\alpha\) (alfa): nivel de significancia o área bajo la curva que define la región crítica (rechazo de H₀).

p-valor: probabilidad de obtener un estadístico igual o más extremo que el observado, dado que \(H_0\) es cierta.

Si p < α → se rechaza \(H_0\).

# Instalar si hace falta
# install.packages("ggplot2")

library(ggplot2)

# Datos base
x <- seq(-4, 4, length = 1000)
dens <- dnorm(x)

# Valores de prueba
alpha <- 0.05
z_crit_one <- qnorm(1 - alpha)
z_crit_two <- qnorm(1 - alpha/2)

# --- Gráfico 1: Una cola ---
df1 <- data.frame(x, dens)
pval_one <- 0.02  # ejemplo

ggplot(df1, aes(x, dens)) +
  geom_line(size=1) +
  geom_area(data=subset(df1, x > z_crit_one), aes(y=dens), fill="yellow", alpha=0.6) +
  geom_area(data=subset(df1, x > qnorm(1 - pval_one)), aes(y=dens), fill="red", alpha=0.4) +
  geom_vline(xintercept = z_crit_one, linetype="dashed") +
  geom_vline(xintercept = qnorm(1 - pval_one), color="red", linetype="dotted") +
  annotate("text", x=1.5, y=0.35, label="α = 0.05", color="black", size=5) +
  annotate("text", x=2.0, y=0.15, label="p = 0.02", color="red", size=5) +
  labs(title="Prueba de una cola (derecha)", x="Estadístico Z", y="Densidad") +
  theme_minimal()
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

# --- Gráfico 2: Dos colas ---
ggplot(df1, aes(x, dens)) +
  geom_line(size=1) +
  geom_area(data=subset(df1, x < -z_crit_two | x > z_crit_two), aes(y=dens), fill="yellow", alpha=0.6) +
  geom_vline(xintercept = c(-z_crit_two, z_crit_two), linetype="dashed") +
  annotate("text", x=-3, y=0.05, label="α/2", color="black", size=5) +
  annotate("text", x=3, y=0.05, label="α/2", color="black", size=5) +
  labs(title="Prueba de dos colas", x="Estadístico Z", y="Densidad") +
  theme_minimal()

Qué muestran los gráficos 🔹 Una cola (arriba):

El área amarilla representa la región crítica (α = 0.05).

El área roja representa el p-valor observado (p = 0.02).

Como \(p \le α\), se rechaza H₀.

🔹 Dos colas: (abajo)

Las dos áreas amarillas (a izquierda y derecha) suman α = 0.05 (cada una α/2 = 0.025).

Se usa cuando la hipótesis alternativa es bidireccional (\(H_1\): \(\mu \ne \mu_0\)).

Características

  • Probabilidad bajo la hipótesis nula: El p-valor se calcula asumiendo que la hipótesis nula es cierta y representa la probabilidad de obtener los datos observados, o datos aún más extremos.

  • Indicador de significación estadística: Un p-valor pequeño (comúnmente menor que \(0.05\)) se considera estadísticamente significativo. Esto significa que es improbable que los resultados se deban únicamente al azar, y se puede rechazar la hipótesis nula.

  • Medida de evidencia en contra de la hipótesis nula: Un p-valor más bajo proporciona una evidencia más fuerte en contra de la hipótesis nula.

Lo que NO es el p-valor:

  • No es la probabilidad de que la hipótesis nula sea falsa.

  • No es la probabilidad de que el resultado sea real.

  • No es una medida de la importancia práctica del resultado, solo de su significación estadística. 

    Adopto un nivel de significancia = 0.05 o valor crítico del p-valor

¿Cómo se usa? 

Se compara el p-valor obtenido del análisis con un nivel de significación preestablecido (como \(0.05\)).

  • Si el p-valor es menor que el nivel de significación (\(p<0.05\)): Se rechaza la hipótesis nula.
  • Si el p-valor es mayor que el nivel de significación (\(p>0.05\)): No hay suficiente evidencia para rechazar la hipótesis nula. 

Comprender el p-valor ayuda a evaluar la solidez de la evidencia estadística en un estudio, pero es importante considerarlo junto con otros factores como el tamaño del efecto y los intervalos de confianza para una interpretación completa. 

T-Test

Este tipo de prueba es muy utilizada en ciencias médicas, por lo que no nos debe extrañar que la mayoría de los ejemplos no provengan de casos industriales.

Es aplicable cuando tengo Una Variable continua y dos discretas

¿Qué pregunta quiero responder?

  • Hipótesis nula \(H_0\) El pseo del niño y fumar en el embarazo NO están asociados

Verdadero si y sólo si \(T \iff p-valor \ge 0.05\)

  • Hipótesis Alternativa \(N_1\) El peso del niño y fumar durante el embarazo SI están asociados

Verdadero si y sólo si \(T \iff p-valor \le 0.05\)

Si se cumple la segunda hipótesis tengo que verificar si el peso de los bebés de madres fumadoras es mayor o menor que el de la madres no fumadoras.

Ej. Tabla de pesos de niños y dos grupos (madres que fuman y madres que no fuman)

Peso Si Fuma / No Fuma
6.88 Si
7.69 No
8.88 No
9:00 No
7.94 No
8.25 Si

Caso industrial:

consumo de combustible de autos con caja manual o automática.

library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ lubridate 1.9.3     ✔ tibble    3.2.1
## ✔ purrr     1.0.2     ✔ tidyr     1.3.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
data("mtcars")
#data(births)
str(mtcars)
## 'data.frame':    32 obs. of  11 variables:
##  $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
##  $ cyl : num  6 6 4 6 8 6 8 4 4 6 ...
##  $ disp: num  160 160 108 258 360 ...
##  $ hp  : num  110 110 93 110 175 105 245 62 95 123 ...
##  $ drat: num  3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
##  $ wt  : num  2.62 2.88 2.32 3.21 3.44 ...
##  $ qsec: num  16.5 17 18.6 19.4 17 ...
##  $ vs  : num  0 0 1 1 0 1 0 1 1 1 ...
##  $ am  : num  1 1 1 0 0 0 0 0 0 0 ...
##  $ gear: num  4 4 4 3 3 3 3 4 4 4 ...
##  $ carb: num  4 4 1 1 2 1 4 2 2 4 ...
automoviles <- mtcars

cambiaremos la variable \(am\) que tiene valores 1 y 0 a una variable categorica “automático am =1” y “manual am=0”.

automoviles$vs <- factor (automoviles$vs , levels = 0:1, labels = c("manual", "automatico"))

str(automoviles)
## 'data.frame':    32 obs. of  11 variables:
##  $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
##  $ cyl : num  6 6 4 6 8 6 8 4 4 6 ...
##  $ disp: num  160 160 108 258 360 ...
##  $ hp  : num  110 110 93 110 175 105 245 62 95 123 ...
##  $ drat: num  3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
##  $ wt  : num  2.62 2.88 2.32 3.21 3.44 ...
##  $ qsec: num  16.5 17 18.6 19.4 17 ...
##  $ vs  : Factor w/ 2 levels "manual","automatico": 1 1 2 2 1 2 1 2 2 2 ...
##  $ am  : num  1 1 1 0 0 0 0 0 0 0 ...
##  $ gear: num  4 4 4 3 3 3 3 4 4 4 ...
##  $ carb: num  4 4 1 1 2 1 4 2 2 4 ...
plot(automoviles$vs)

boxplot(automoviles$mpg ~ automoviles$vs, ylab="Consumo en millas por galón")

Pregunta de investigación

¿Existe evidencia de menor consumo debido al uso de tipo de transmisión?

Lo primero que haremos será separar los consumos en millas por galón para cada tipo de caja de cambios.

library(tidyverse)
library(lubridate)

automatico <- automoviles %>% filter(vs == "automatico") %>% pull(mpg)
automatico
##  [1] 22.8 21.4 18.1 24.4 22.8 19.2 17.8 32.4 30.4 33.9 21.5 27.3 30.4 21.4
library(tidyverse)
library(lubridate)

manual <- automoviles %>% filter(vs == "manual") %>% pull(mpg)
manual
##  [1] 21.0 21.0 18.7 14.3 16.4 17.3 15.2 10.4 10.4 14.7 15.5 15.2 13.3 19.2 26.0
## [16] 15.8 19.7 15.0

Prueba de normalidad

Es necesario que pruebe si mis datos demuestran normalidad , tanto para cajas automáticas como cajas manuales.

Para hacer eso recurrimos al test de Shapiro

plot(density(automatico))

shapiro.test(automatico)
## 
##  Shapiro-Wilk normality test
## 
## data:  automatico
## W = 0.91166, p-value = 0.1666
plot(density(manual))

shapiro.test(manual)
## 
##  Shapiro-Wilk normality test
## 
## data:  manual
## W = 0.95151, p-value = 0.4491

En ambos casos el p-valor NO es menor que 0.05, por eso podemos asumir que ambas muestras siguen una distribución normal. A pesar de ello el factor de peso W cercano a 1 me indicaría que tengo que aumentar el número de muestras que utilizo.

Igualdad de varianzas

Si no podemos tomas más muestras, al menos debemos estar seguros que las varianzas de las muestras no están muy alejadas. Esto es las campanas de ambas variables deben tener espacio muestral común.

Para ello utilizamos la prueva estadística de Homoestadicidad de LEVENE

library(car)
## Loading required package: carData
## 
## Attaching package: 'car'
## The following object is masked from 'package:dplyr':
## 
##     recode
## The following object is masked from 'package:purrr':
## 
##     some
leveneTest(automoviles$mpg ~ automoviles$vs ,  center="median")
## Levene's Test for Homogeneity of Variance (center = "median")
##       Df F value Pr(>F)
## group  1  1.5922 0.2167
##       30

Como vemos el Pr (p-valor) es 0.2167 lo que nos dice que la hipótesis de igualdad de varianza es verdadera . Esto es equivalente a decir que la Hipótesis nula \(H_0\) es vardadera.

Por lo tanto estamos en condiciones de hacer la prueba T de Student.

Prueba T-test aplicada

Aquí tenemos una hipótesis nula que es la que propone la igualdad de las muestras o dicho de otra manera los valores de consumo en millas por galón provienen de una sola población y es únicamente un fenómeno aleatorio el que ha hehco que estas pequeñas muestras exhiban diferencias.

t.test (automatico , manual)
## 
##  Welch Two Sample t-test
## 
## data:  automatico and manual
## t = 4.6671, df = 22.716, p-value = 0.0001098
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##   4.418445 11.462508
## sample estimates:
## mean of x mean of y 
##  24.55714  16.61667

El p-valor que hemos obtenido es mucho menor que 0.05, lo que indica que la \(H_0\) debe ser rechazada. Las muestras no son equivalentes.

Procederemos a verificar la \(H_1\) o hipótesis alternativa que propone que una de las muestras es mayor que otra.

También recurrimos al t-test

t.test( manual, automatico , alternative = "greater")
## 
##  Welch Two Sample t-test
## 
## data:  manual and automatico
## t = -4.6671, df = 22.716, p-value = 0.9999
## alternative hypothesis: true difference in means is greater than 0
## 95 percent confidence interval:
##  -10.85797       Inf
## sample estimates:
## mean of x mean of y 
##  16.61667  24.55714

El p-valor que nos ha dado es del orden de $10^{-5} que es muy pequeño respecto a 0.05. Por eso tenemos una alta confiabilidad sobre la pregunta de investigación que dice que los autos automáticos tienen mayor consumo que los manuales.

ANOVA

Se utiliza para Una Variable continua y dos o más categóricas, grupos o discretas

Ej. Tabla con ventas de autos de 5 concesionarios y 4 colores

Concesionarios 1 2 3 4 5 6
Amarillo 16 11 20 21 14 7
Blanco 37 32 15 25 39 41
Verde 21 12 14 17 13 17
Azul 45 59 48 46 38 47

Carga de datos manual en R.

autos <- c(16,11,20,21,14,7,37,32,15,25,39,41,21,12,14,17,13,17,45,59,48,46,38,47)
colores <- as.factor(c  (rep( c("amarillo","azul","blanco","negro"), each=6)))

armado del dataframe

autos_electricos <- data.frame (autos,colores)

boxplot(autos_electricos$autos ~ autos_electricos$colores, ylab="Unidades Vendidas", xlab= "Colores", col=c("yellow","lightblue","white","grey"))

Pregunta de investigación

¿Podemos asegurar que no todos los autos eléctricos se venden igualmente?

Creareos un modelo lineal para poder hacer el análisis ANOVA

modelo_lineal <- lm(autos ~ colores, data = autos_electricos)

modelo_lineal
## 
## Call:
## lm(formula = autos ~ colores, data = autos_electricos)
## 
## Coefficients:
##   (Intercept)    coloresazul  coloresblanco   coloresnegro  
##       14.8333        16.6667         0.8333        32.3333
summary(modelo_lineal)
## 
## Call:
## lm(formula = autos ~ colores, data = autos_electricos)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -16.5000  -2.9167   0.1667   5.2083  11.8333 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)    14.8333     2.7696   5.356 3.05e-05 ***
## coloresazul    16.6667     3.9168   4.255 0.000387 ***
## coloresblanco   0.8333     3.9168   0.213 0.833671    
## coloresnegro   32.3333     3.9168   8.255 7.16e-08 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 6.784 on 20 degrees of freedom
## Multiple R-squared:  0.8209, Adjusted R-squared:  0.794 
## F-statistic: 30.55 on 3 and 20 DF,  p-value: 1.151e-07

Estadistico matemático ANOVA

annova_autos <- aov(modelo_lineal)
summary(annova_autos)
##             Df Sum Sq Mean Sq F value   Pr(>F)    
## colores      3   4218    1406   30.55 1.15e-07 ***
## Residuals   20    920      46                     
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Como podemos ver el p-valor (Pr del modelo anova) es muy cercano a cero, es decir que es mucho menos que 0.05. Esto implica que los grupos son diferentes.

Al igual que en el t-test nuestras consignas de partida eran primero por la igualdad o \(H_0\) verdadera si Pr es mayor a 0.05 (todos los grupos iguales) o \(H_1\) verdadera si pr < 0.05 . Vale decir no todos los autos eléctricos se venden por igual.

Pero vemos que los autos azules y blancos son muy parecidos en sus ventas, para analizar esto tendremos que utilizar el test de Tukey

TukeyHSD(annova_autos)
##   Tukey multiple comparisons of means
##     95% family-wise confidence level
## 
## Fit: aov(formula = modelo_lineal)
## 
## $colores
##                        diff       lwr       upr     p adj
## azul-amarillo    16.6666667   5.70367 27.629663 0.0020222
## blanco-amarillo   0.8333333 -10.12966 11.796330 0.9964823
## negro-amarillo   32.3333333  21.37034 43.296330 0.0000004
## blanco-azul     -15.8333333 -26.79633 -4.870337 0.0032835
## negro-azul       15.6666667   4.70367 26.629663 0.0036170
## negro-blanco     31.5000000  20.53700 42.462996 0.0000006

Vemos que el p-valor entre blanco-amarillo es de 0.996 lo que implica que es mayor que 0.05, por eso podemos decir que estos dos grupos tienen comportamietno semejante.

Chi Cuadrado

2 Variables discretas

Cantidad de Casos de Peso del recién Nacido

Gestante Peso Alto Peso Bajo Total
Fumadora 43 207 250
No Fumadora 105 1645 1750
Total 148 1852 2000

Cargaremos los valores de la pabla en R

Ten cuidado , estamos cargando los valores por columnas

Peso_alto <-c(43,105)
Peso_bajo <- c(207,1645)
tabla_chi <- data.frame (Peso_alto, Peso_bajo)
rownames(tabla_chi) <- c("Fumadores","No Fumadores")
tabla_chi
##              Peso_alto Peso_bajo
## Fumadores           43       207
## No Fumadores       105      1645

Chi cuadrado test aplicado

chisq.test(tabla_chi)
## 
##  Pearson's Chi-squared test with Yates' continuity correction
## 
## data:  tabla_chi
## X-squared = 38.427, df = 1, p-value = 5.685e-10

el p-valor es mucho menor que cero, entonces la \(H_0\) (hipótesis nula) es verdadera. Podemos decir que con los datos suministrados no hay evidencia de diferencas entre las muestras. Ambos grupos (peso alto y peso bajo) provienen de una misma población, por la tanto el hecho de la influencia de fumar no puede atribuirse como causal de las diferencias observadas en la tabla y por ello se estima que solo un proceso aleatorio en la selección de las muestras es la cauda de las diferencias. Pero a pesar de ello el valor de 38.42 es alto por lo que tendríamos que considerar aumentar la cantidad de muestras que tomamos (2000) para tener evidencia plena.

LS0tCnRpdGxlOiAiRXN0YWRpc3RpY29zIFQtVGVzdCwgQU5PVkEgeSBDaGktY3VhZHJhZG8gIgphdXRob3I6ICJSLlBhbG1hIDxyaWNhcmRvLnJwYWxtYUBnbWFpbC5jb20+IgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDUKICAgIHRvY19mbG9hdDogeWVzCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGNvZGVfZG93bmxvYWQ6IFRSVUUKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCiMjIE9iamV0aXZvczoKCkV4aXN0ZW4gdHJlcyBlc3RhZMOtc3RpY29zIChvIGNvbmp1bnRvIGRlIHBydWViYSBkZSBoaXDDs3Rlc2lzc29icmUgbXVlc3RyYXMgeSBwb2JsYWNpb25lcykgcXVlIHNvbiBhYnNvbHV0YW1lbnRlIG5lY2VzYXJpb3MgZW4gbGEgaW5kdXN0cmlhIHkgZW4gZWwgZGVzYXJyb2xsbyBkZSBpbnZlc3RpZ2FjacOzbi4gRW4gUmlnb3MgZXhpc3RlbiBtdWNoYXMgbcOhcyBwZXJvIHNvbiBjaW5jbyBsb3MgcXVlIG3DoXMgZnJlY3VlbnRlbWVudGUgYXBhcmVjZW4gZW4gbG9zIGNhc29zIGRlIGVzdHVkaW8geSAoY29tbyBvYnNlcnZhY2nDs24gcGVyc29uYWwpIHN1Z2llcm8gcXVlIGFsIG1lbm9zIGxvcyB0cmVzIHByaW1lcm9zIHNlIHRlbmdhbiBtdXkgcHJlc2VudGVzIHBhcmEgZWwgY3Vyc28gcXVlIGRlc2Fycm9sbGFtb3MKCkVzdG9zIGVzdGFkw61zdGljb3Mgc29uOgoKKiA8c3BhbiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjogeWVsbG93Ij5QcnVlYmEgVCBkZSBTdHVkZW50PC9zcGFuPgoKKiA8c3BhbiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjogeWVsbG93Ij5BTk9WQSAoQW7DoWxpc2lzIGRlIFZhcmlhbnphKTwvc3Bhbj4KCiogPHNwYW4gc3R5bGU9ImJhY2tncm91bmQtY29sb3I6IHllbGxvdyI+UHJ1ZWJhICRcY2hpwrIkIChjaGktY3VhZHJhZG8pPC9zcGFuPgoKKiBQcnVlYmEgRiBkZSBGaXNoZXIKCiogUHJ1ZWJhcyBubyBwYXJhbcOpdHJpY2FzIChNYW5uLVdoaXRuZXksIEtydXNrYWwtV2FsbGlzLCBldGMuKQoKCgojIyMgU2l0aW9zIGNvbnN1bHRhZG9zOgoKKiBNb3RvcmVzIGh0dHBzOi8va2lybG9za2FyZWxlY3RyaWMuY29tLwoqIERhdGFzZXRzIHN1Z2VyaWRvcyBwYXJhIGF1dG9lamVyY2l0YXJzZSA8aHR0cHM6Ly96ZW5vZG8ub3JnL3JlY29yZHMvMTcwNDgwMjg+CiogRGVzY2FyZ2EgZGUgZXN0ZSBjdWFkcmVubyBodHRwczovL3JwdWJzLmNvbS9yaWNhcmRvcnBhbG1hLzEzNjE0MzcKKiBEYXRhc2V0ICptdGNhcnMqCgpFc3RlIHVsdGltbyBkYXRhc2V0IHNlIHB1ZWRlIGNpdGFyIGNvbW86CgoqKkFQQSoqCkF1dG9yOiBDb211bmlkYWQgZGUgUiAobyBSIENvcmUgVGVhbSBzaSBubyBoYXkgaW5mb3JtYWNpw7NuIG3DoXMgZXNwZWPDrWZpY2EpLsKgIEHDsW86ICBcKDIwMjRcKSAobyBlbCBhw7FvIGRlbCBwYXF1ZXRlIGRhdGFzZXRzIG3DoXMgcmVjaWVudGUpLsKgIFTDrXR1bG86IERhdGFzZXQgbXRjYXJzIFtEYXRhU2V0XS7CoCBGdWVudGU6IFBhcXVldGUgZGF0YXNldHMgZGUgUi7CoCBVUkw6IFVSTCBkZSBsYSBkb2N1bWVudGFjacOzbiBvZmljaWFsLCBwb3IgZWplbXBsbzogaHR0cHM6Ly9zdGF0LmV0aHouY2gvUi1tYW51YWwvUi1kZXZlbC9saWJyYXJ5L2RhdGFzZXRzL2h0bWwvbXRjYXJzLmh0bWwuwqAKCioqYmlidGV4KioKQGJvb2t7V2lja2hhbTIwMTUsCiAgdGl0bGUgPSB7UiBmb3IgRGF0YSBTY2llbmNlfSwKICBhdXRob3IgPSB7SGFkbGV5IFdpY2toYW0gYW5kIEdhcnJldHQgR3JvbGVtdW5kfSwKICB5ZWFyID0gezIwMTV9LAogIHB1Ymxpc2hlciA9IHtPJ1JlaWxseSBNZWRpYX0sCiAgdXJsID0ge2h0dHBzOi8vcjRkcy5oYWQuY28ubnovZGF0YS12aXN1YWxpc2F0aW9uLmh0bWx9Cn0KCgojIyBSZXBhc28gZGUgZGVmaW5pY2lvbmVzCgojIyMgTml2ZWwgZGUgc2lnbmlmaWNhbmNpYSAocC12YWxvcikKClVuIHAtdmFsb3IgZXMgdW5hIG1lZGlkYSBkZSBsYSBwcm9iYWJpbGlkYWQgZGUgb2J0ZW5lciByZXN1bHRhZG9zIHRhbiBleHRyZW1vcyBjb21vIGxvcyBvYnNlcnZhZG9zIGVuIHVuIGVzdHVkaW8sIGFzdW1pZW5kbyBxdWUgbGEgaGlww7N0ZXNpcyBudWxhIChxdWUgbm8gaGF5IGVmZWN0byBvIGRpZmVyZW5jaWEpIGVzIHZlcmRhZGVyYS4gVW4gcC12YWxvciBiYWpvIGluZGljYSBxdWUgbG9zIHJlc3VsdGFkb3Mgc29uIHBvY28gcHJvYmFibGVzIGJham8gbGEgaGlww7N0ZXNpcyBudWxhLCBsbyBxdWUgc3VnaWVyZSBxdWUgaGF5IGV2aWRlbmNpYSBzdWZpY2llbnRlIHBhcmEgcmVjaGF6YXJsYS4gU2UgdXRpbGl6YSBlbiBlbCBjb250cmFzdGUgZGUgaGlww7N0ZXNpcyBwYXJhIGRldGVybWluYXIgbGEgc2lnbmlmaWNhY2nDs24gZXN0YWTDrXN0aWNhIGRlIHVuIHJlc3VsdGFkby4gCgojIyMgUmVjb3JkYXIgCgokXGFscGhhJCAoYWxmYSk6IG5pdmVsIGRlIHNpZ25pZmljYW5jaWEgbyDDoXJlYSBiYWpvIGxhIGN1cnZhIHF1ZSBkZWZpbmUgbGEgcmVnacOzbiBjcsOtdGljYSAocmVjaGF6byBkZSBI4oKAKS4KCioqcC12YWxvcjoqKiBwcm9iYWJpbGlkYWQgZGUgb2J0ZW5lciB1biBlc3RhZMOtc3RpY28gaWd1YWwgbyBtw6FzIGV4dHJlbW8gcXVlIGVsIG9ic2VydmFkbywgZGFkbyBxdWUgJEhfMCQgZXMgY2llcnRhLgoKU2kgcCA8IM6xIOKGkiBzZSByZWNoYXphICRIXzAkLgoKYGBge3J9CiMgSW5zdGFsYXIgc2kgaGFjZSBmYWx0YQojIGluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQoKbGlicmFyeShnZ3Bsb3QyKQoKIyBEYXRvcyBiYXNlCnggPC0gc2VxKC00LCA0LCBsZW5ndGggPSAxMDAwKQpkZW5zIDwtIGRub3JtKHgpCgojIFZhbG9yZXMgZGUgcHJ1ZWJhCmFscGhhIDwtIDAuMDUKel9jcml0X29uZSA8LSBxbm9ybSgxIC0gYWxwaGEpCnpfY3JpdF90d28gPC0gcW5vcm0oMSAtIGFscGhhLzIpCgojIC0tLSBHcsOhZmljbyAxOiBVbmEgY29sYSAtLS0KZGYxIDwtIGRhdGEuZnJhbWUoeCwgZGVucykKcHZhbF9vbmUgPC0gMC4wMiAgIyBlamVtcGxvCgpnZ3Bsb3QoZGYxLCBhZXMoeCwgZGVucykpICsKICBnZW9tX2xpbmUoc2l6ZT0xKSArCiAgZ2VvbV9hcmVhKGRhdGE9c3Vic2V0KGRmMSwgeCA+IHpfY3JpdF9vbmUpLCBhZXMoeT1kZW5zKSwgZmlsbD0ieWVsbG93IiwgYWxwaGE9MC42KSArCiAgZ2VvbV9hcmVhKGRhdGE9c3Vic2V0KGRmMSwgeCA+IHFub3JtKDEgLSBwdmFsX29uZSkpLCBhZXMoeT1kZW5zKSwgZmlsbD0icmVkIiwgYWxwaGE9MC40KSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gel9jcml0X29uZSwgbGluZXR5cGU9ImRhc2hlZCIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBxbm9ybSgxIC0gcHZhbF9vbmUpLCBjb2xvcj0icmVkIiwgbGluZXR5cGU9ImRvdHRlZCIpICsKICBhbm5vdGF0ZSgidGV4dCIsIHg9MS41LCB5PTAuMzUsIGxhYmVsPSLOsSA9IDAuMDUiLCBjb2xvcj0iYmxhY2siLCBzaXplPTUpICsKICBhbm5vdGF0ZSgidGV4dCIsIHg9Mi4wLCB5PTAuMTUsIGxhYmVsPSJwID0gMC4wMiIsIGNvbG9yPSJyZWQiLCBzaXplPTUpICsKICBsYWJzKHRpdGxlPSJQcnVlYmEgZGUgdW5hIGNvbGEgKGRlcmVjaGEpIiwgeD0iRXN0YWTDrXN0aWNvIFoiLCB5PSJEZW5zaWRhZCIpICsKICB0aGVtZV9taW5pbWFsKCkKCiMgLS0tIEdyw6FmaWNvIDI6IERvcyBjb2xhcyAtLS0KZ2dwbG90KGRmMSwgYWVzKHgsIGRlbnMpKSArCiAgZ2VvbV9saW5lKHNpemU9MSkgKwogIGdlb21fYXJlYShkYXRhPXN1YnNldChkZjEsIHggPCAtel9jcml0X3R3byB8IHggPiB6X2NyaXRfdHdvKSwgYWVzKHk9ZGVucyksIGZpbGw9InllbGxvdyIsIGFscGhhPTAuNikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoLXpfY3JpdF90d28sIHpfY3JpdF90d28pLCBsaW5ldHlwZT0iZGFzaGVkIikgKwogIGFubm90YXRlKCJ0ZXh0IiwgeD0tMywgeT0wLjA1LCBsYWJlbD0izrEvMiIsIGNvbG9yPSJibGFjayIsIHNpemU9NSkgKwogIGFubm90YXRlKCJ0ZXh0IiwgeD0zLCB5PTAuMDUsIGxhYmVsPSLOsS8yIiwgY29sb3I9ImJsYWNrIiwgc2l6ZT01KSArCiAgbGFicyh0aXRsZT0iUHJ1ZWJhIGRlIGRvcyBjb2xhcyIsIHg9IkVzdGFkw61zdGljbyBaIiwgeT0iRGVuc2lkYWQiKSArCiAgdGhlbWVfbWluaW1hbCgpCgpgYGAKClF1w6kgbXVlc3RyYW4gbG9zIGdyw6FmaWNvcwrwn5S5ICoqVW5hIGNvbGEgKGFycmliYSk6KioKCkVsIMOhcmVhIGFtYXJpbGxhIHJlcHJlc2VudGEgbGEgcmVnacOzbiBjcsOtdGljYSAozrEgPSAwLjA1KS4KCkVsIMOhcmVhIHJvamEgcmVwcmVzZW50YSBlbCBwLXZhbG9yIG9ic2VydmFkbyAocCA9IDAuMDIpLgoKQ29tbyAkcCBcbGUgzrEkLCBzZSByZWNoYXphIEjigoAuCgrwn5S5ICoqRG9zIGNvbGFzOiAoYWJham8pKioKCkxhcyBkb3Mgw6FyZWFzIGFtYXJpbGxhcyAoYSBpenF1aWVyZGEgeSBkZXJlY2hhKSBzdW1hbiDOsSA9IDAuMDUgKGNhZGEgdW5hIM6xLzIgPSAwLjAyNSkuCgpTZSB1c2EgY3VhbmRvIGxhIGhpcMOzdGVzaXMgYWx0ZXJuYXRpdmEgZXMgYmlkaXJlY2Npb25hbCAoJEhfMSQ6ICRcbXUgXG5lIFxtdV8wJCkuCgoKIyMjIENhcmFjdGVyw61zdGljYXMKCiogUHJvYmFiaWxpZGFkIGJham8gbGEgaGlww7N0ZXNpcyBudWxhOiBFbCBwLXZhbG9yIHNlIGNhbGN1bGEgYXN1bWllbmRvIHF1ZSBsYSBoaXDDs3Rlc2lzIG51bGEgZXMgY2llcnRhIHkgcmVwcmVzZW50YSBsYSBwcm9iYWJpbGlkYWQgZGUgb2J0ZW5lciBsb3MgZGF0b3Mgb2JzZXJ2YWRvcywgbyBkYXRvcyBhw7puIG3DoXMgZXh0cmVtb3MuCgoqIEluZGljYWRvciBkZSBzaWduaWZpY2FjacOzbiBlc3RhZMOtc3RpY2E6IFVuIHAtdmFsb3IgcGVxdWXDsW8gKGNvbcO6bm1lbnRlIG1lbm9yIHF1ZSBcKDAuMDVcKSkgc2UgY29uc2lkZXJhIGVzdGFkw61zdGljYW1lbnRlIHNpZ25pZmljYXRpdm8uIEVzdG8gc2lnbmlmaWNhIHF1ZSBlcyBpbXByb2JhYmxlIHF1ZSBsb3MgcmVzdWx0YWRvcyBzZSBkZWJhbiDDum5pY2FtZW50ZSBhbCBhemFyLCB5IHNlIHB1ZWRlIHJlY2hhemFyIGxhIGhpcMOzdGVzaXMgbnVsYS4KCiogTWVkaWRhIGRlIGV2aWRlbmNpYSBlbiBjb250cmEgZGUgbGEgaGlww7N0ZXNpcyBudWxhOiBVbiBwLXZhbG9yIG3DoXMgYmFqbyBwcm9wb3JjaW9uYSB1bmEgZXZpZGVuY2lhIG3DoXMgZnVlcnRlIGVuIGNvbnRyYSBkZSBsYSBoaXDDs3Rlc2lzIG51bGEuCgojIyMgTG8gcXVlIE5PIGVzIGVsIHAtdmFsb3I6CgoqIE5vIGVzIGxhIHByb2JhYmlsaWRhZCBkZSBxdWUgbGEgaGlww7N0ZXNpcyBudWxhIHNlYSBmYWxzYS4KKiBObyBlcyBsYSBwcm9iYWJpbGlkYWQgZGUgcXVlIGVsIHJlc3VsdGFkbyBzZWEgcmVhbC4KKiBObyBlcyB1bmEgbWVkaWRhIGRlIGxhIGltcG9ydGFuY2lhIHByw6FjdGljYSBkZWwgcmVzdWx0YWRvLCBzb2xvIGRlIHN1IHNpZ25pZmljYWNpw7NuIGVzdGFkw61zdGljYS7CoAoKCiAgICBBZG9wdG8gdW4gbml2ZWwgZGUgc2lnbmlmaWNhbmNpYSA9IDAuMDUgbyB2YWxvciBjcsOtdGljbyBkZWwgcC12YWxvcgoKCiMjIMK/Q8OzbW8gc2UgdXNhP8KgCgpTZSBjb21wYXJhIGVsIHAtdmFsb3Igb2J0ZW5pZG8gZGVsIGFuw6FsaXNpcyBjb24gdW4gbml2ZWwgZGUgc2lnbmlmaWNhY2nDs24gcHJlZXN0YWJsZWNpZG8gKGNvbW8gXCgwLjA1XCkpLgoKKiBTaSBlbCBwLXZhbG9yIGVzIG1lbm9yIHF1ZSBlbCBuaXZlbCBkZSBzaWduaWZpY2FjacOzbiAoXChwPDAuMDVcKSk6IFNlIHJlY2hhemEgbGEgaGlww7N0ZXNpcyBudWxhLgoqIFNpIGVsIHAtdmFsb3IgZXMgbWF5b3IgcXVlIGVsIG5pdmVsIGRlIHNpZ25pZmljYWNpw7NuIChcKHA+MC4wNVwpKTogTm8gaGF5IHN1ZmljaWVudGUgZXZpZGVuY2lhIHBhcmEgcmVjaGF6YXIgbGEgaGlww7N0ZXNpcyBudWxhLsKgCgpDb21wcmVuZGVyIGVsIHAtdmFsb3IgYXl1ZGEgYSBldmFsdWFyIGxhIHNvbGlkZXogZGUgbGEgZXZpZGVuY2lhIGVzdGFkw61zdGljYSBlbiB1biBlc3R1ZGlvLCBwZXJvIGVzIGltcG9ydGFudGUgY29uc2lkZXJhcmxvIGp1bnRvIGNvbiBvdHJvcyBmYWN0b3JlcyBjb21vIGVsIHRhbWHDsW8gZGVsIGVmZWN0byB5IGxvcyBpbnRlcnZhbG9zIGRlIGNvbmZpYW56YSBwYXJhIHVuYSBpbnRlcnByZXRhY2nDs24gY29tcGxldGEuwqAKCgoKCiMjIFQtVGVzdAoKRXN0ZSB0aXBvIGRlIHBydWViYSBlcyBtdXkgdXRpbGl6YWRhIGVuIGNpZW5jaWFzIG3DqWRpY2FzLCBwb3IgbG8gcXVlIG5vIG5vcyBkZWJlIGV4dHJhw7FhciBxdWUgbGEgbWF5b3LDrWEgZGUgbG9zIGVqZW1wbG9zIG5vIHByb3ZlbmdhbiBkZSBjYXNvcyBpbmR1c3RyaWFsZXMuCgoKRXMgYXBsaWNhYmxlIGN1YW5kbyB0ZW5nbyAqKlVuYSBWYXJpYWJsZSBjb250aW51YSB5IGRvcyBkaXNjcmV0YXMqKgoKIyMjIMK/UXXDqSBwcmVndW50YSBxdWllcm8gcmVzcG9uZGVyPyAKCiogSGlww7N0ZXNpcyBudWxhICRIXzAkIEVsIHBzZW8gZGVsIG5pw7FvIHkgZnVtYXIgZW4gZWwgZW1iYXJhem8gKipOTyoqIGVzdMOhbiBhc29jaWFkb3MKIAogVmVyZGFkZXJvIHNpIHkgc8OzbG8gc2kgJFQgXGlmZiBwLXZhbG9yIFxnZSAwLjA1JAogCiogIEhpcMOzdGVzaXMgQWx0ZXJuYXRpdmEgJE5fMSQgIEVsIHBlc28gZGVsIG5pw7FvIHkgZnVtYXIgZHVyYW50ZSBlbCBlbWJhcmF6byAqKlNJKiogZXN0w6FuIGFzb2NpYWRvcwogCiAgVmVyZGFkZXJvIHNpIHkgc8OzbG8gc2kgJFQgXGlmZiBwLXZhbG9yIFxsZSAwLjA1JAogCiAKIFNpIHNlIGN1bXBsZSBsYSBzZWd1bmRhIGhpcMOzdGVzaXMgdGVuZ28gcXVlIHZlcmlmaWNhciBzaSBlbCBwZXNvIGRlIGxvcyBiZWLDqXMgZGUgbWFkcmVzIGZ1bWFkb3JhcyBlcyBtYXlvciBvIG1lbm9yIHF1ZSBlbCBkZSBsYSBtYWRyZXMgbm8gZnVtYWRvcmFzLgogCiAKCgpFai4gVGFibGEgZGUgcGVzb3MgZGUgbmnDsW9zIHkgZG9zIGdydXBvcyAobWFkcmVzIHF1ZSBmdW1hbiB5IG1hZHJlcyBxdWUgbm8gZnVtYW4pCgoKfFBlc28gICAgfCBTaSBGdW1hIC8gTm8gRnVtYSB8CnwtLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tfAp8IDYuODggfCBTaXwKfCA3LjY5IHwgTm98CnwgOC44OCB8IE5vfAp8IDk6MDAgfCBOb3wKfCA3Ljk0IHwgTm98CnwgOC4yNSB8IFNpfAoKCiMjIENhc28gaW5kdXN0cmlhbDogCgpjb25zdW1vIGRlIGNvbWJ1c3RpYmxlIGRlIGF1dG9zIGNvbiBjYWphIG1hbnVhbCBvIGF1dG9tw6F0aWNhLiAKCgoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpkYXRhKCJtdGNhcnMiKQojZGF0YShiaXJ0aHMpCnN0cihtdGNhcnMpCmF1dG9tb3ZpbGVzIDwtIG10Y2FycwoKCgpgYGAKCmNhbWJpYXJlbW9zIGxhIHZhcmlhYmxlICRhbSQgcXVlIHRpZW5lIHZhbG9yZXMgMSB5IDAgYSB1bmEgdmFyaWFibGUgY2F0ZWdvcmljYSAiYXV0b23DoXRpY28gYW0gPTEiICB5ICJtYW51YWwgYW09MCIuCgpgYGB7cn0KYXV0b21vdmlsZXMkdnMgPC0gZmFjdG9yIChhdXRvbW92aWxlcyR2cyAsIGxldmVscyA9IDA6MSwgbGFiZWxzID0gYygibWFudWFsIiwgImF1dG9tYXRpY28iKSkKCnN0cihhdXRvbW92aWxlcykKCmBgYAoKYGBge3J9CnBsb3QoYXV0b21vdmlsZXMkdnMpCmBgYAoKCmBgYHtyfQpib3hwbG90KGF1dG9tb3ZpbGVzJG1wZyB+IGF1dG9tb3ZpbGVzJHZzLCB5bGFiPSJDb25zdW1vIGVuIG1pbGxhcyBwb3IgZ2Fsw7NuIikKYGBgCgojIyBQcmVndW50YSBkZSBpbnZlc3RpZ2FjacOzbgoKwr9FeGlzdGUgZXZpZGVuY2lhIGRlIG1lbm9yIGNvbnN1bW8gZGViaWRvIGFsIHVzbyBkZSB0aXBvIGRlIHRyYW5zbWlzacOzbj8KCgpMbyBwcmltZXJvIHF1ZSBoYXJlbW9zIHNlcsOhIHNlcGFyYXIgbG9zIGNvbnN1bW9zIGVuIG1pbGxhcyBwb3IgZ2Fsw7NuIHBhcmEgY2FkYSB0aXBvIGRlIGNhamEgZGUgY2FtYmlvcy4KCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShsdWJyaWRhdGUpCgphdXRvbWF0aWNvIDwtIGF1dG9tb3ZpbGVzICU+JSBmaWx0ZXIodnMgPT0gImF1dG9tYXRpY28iKSAlPiUgcHVsbChtcGcpCmF1dG9tYXRpY28KCgpgYGAKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShsdWJyaWRhdGUpCgptYW51YWwgPC0gYXV0b21vdmlsZXMgJT4lIGZpbHRlcih2cyA9PSAibWFudWFsIikgJT4lIHB1bGwobXBnKQptYW51YWwKCgpgYGAKCiMjIFBydWViYSBkZSBub3JtYWxpZGFkCgpFcyBuZWNlc2FyaW8gcXVlIHBydWViZSBzaSBtaXMgZGF0b3MgZGVtdWVzdHJhbiBub3JtYWxpZGFkICwgdGFudG8gcGFyYSBjYWphcyBhdXRvbcOhdGljYXMgY29tbyBjYWphcyBtYW51YWxlcy4KClBhcmEgaGFjZXIgZXNvIHJlY3Vycmltb3MgYWwgdGVzdCBkZSBTaGFwaXJvCgpgYGB7cn0KcGxvdChkZW5zaXR5KGF1dG9tYXRpY28pKQpzaGFwaXJvLnRlc3QoYXV0b21hdGljbykKCmBgYAoKYGBge3J9CnBsb3QoZGVuc2l0eShtYW51YWwpKQpzaGFwaXJvLnRlc3QobWFudWFsKQoKYGBgCgpFbiBhbWJvcyBjYXNvcyBlbCBwLXZhbG9yIE5PIGVzIG1lbm9yIHF1ZSAwLjA1LCBwb3IgZXNvIHBvZGVtb3MgYXN1bWlyIHF1ZSBhbWJhcyBtdWVzdHJhcyBzaWd1ZW4gdW5hIGRpc3RyaWJ1Y2nDs24gbm9ybWFsLiBBIHBlc2FyIGRlIGVsbG8gZWwgZmFjdG9yIGRlIHBlc28gVyBjZXJjYW5vIGEgMSBtZSBpbmRpY2Fyw61hIHF1ZSB0ZW5nbyBxdWUgYXVtZW50YXIgZWwgbsO6bWVybyBkZSBtdWVzdHJhcyBxdWUgdXRpbGl6by4KCgojIyBJZ3VhbGRhZCBkZSB2YXJpYW56YXMKClNpIG5vIHBvZGVtb3MgdG9tYXMgbcOhcyBtdWVzdHJhcywgYWwgbWVub3MgZGViZW1vcyBlc3RhciBzZWd1cm9zIHF1ZSBsYXMgdmFyaWFuemFzIGRlIGxhcyBtdWVzdHJhcyBubyBlc3TDoW4gbXV5IGFsZWphZGFzLiBFc3RvIGVzIGxhcyBjYW1wYW5hcyBkZSBhbWJhcyB2YXJpYWJsZXMgZGViZW4gdGVuZXIgZXNwYWNpbyBtdWVzdHJhbCBjb23Dum4uCgpQYXJhIGVsbG8gdXRpbGl6YW1vcyBsYSBwcnVldmEgZXN0YWTDrXN0aWNhIGRlICoqSG9tb2VzdGFkaWNpZGFkKiogZGUgTEVWRU5FCgpgYGB7cn0KbGlicmFyeShjYXIpCmxldmVuZVRlc3QoYXV0b21vdmlsZXMkbXBnIH4gYXV0b21vdmlsZXMkdnMgLCAgY2VudGVyPSJtZWRpYW4iKQpgYGAKQ29tbyB2ZW1vcyBlbCBQciAocC12YWxvcikgZXMgMC4yMTY3IGxvIHF1ZSBub3MgZGljZSBxdWUgbGEgaGlww7N0ZXNpcyBkZSBpZ3VhbGRhZCBkZSB2YXJpYW56YSBlcyB2ZXJkYWRlcmEgLiBFc3RvIGVzIGVxdWl2YWxlbnRlIGEgZGVjaXIgcXVlIGxhIEhpcMOzdGVzaXMgbnVsYSAkSF8wJCBlcyB2YXJkYWRlcmEuCgpQb3IgbG8gdGFudG8gZXN0YW1vcyBlbiBjb25kaWNpb25lcyBkZSBoYWNlciBsYSBwcnVlYmEgVCBkZSBTdHVkZW50LgoKIyMgUHJ1ZWJhIFQtdGVzdCBhcGxpY2FkYQoKQXF1w60gdGVuZW1vcyB1bmEgaGlww7N0ZXNpcyBudWxhIHF1ZSBlcyBsYSBxdWUgcHJvcG9uZSBsYSBpZ3VhbGRhZCBkZSBsYXMgbXVlc3RyYXMgbyBkaWNobyBkZSBvdHJhIG1hbmVyYSBsb3MgdmFsb3JlcyBkZSBjb25zdW1vIGVuIG1pbGxhcyBwb3IgZ2Fsw7NuIHByb3ZpZW5lbiBkZSB1bmEgc29sYSBwb2JsYWNpw7NuIHkgZXMgw7puaWNhbWVudGUgdW4gZmVuw7NtZW5vIGFsZWF0b3JpbyBlbCBxdWUgaGEgaGVoY28gcXVlIGVzdGFzIHBlcXVlw7FhcyBtdWVzdHJhcyBleGhpYmFuIGRpZmVyZW5jaWFzLgoKYGBge3J9CnQudGVzdCAoYXV0b21hdGljbyAsIG1hbnVhbCkKYGBgCkVsIHAtdmFsb3IgcXVlIGhlbW9zIG9idGVuaWRvIGVzIG11Y2hvIG1lbm9yIHF1ZSAwLjA1LCBsbyBxdWUgaW5kaWNhIHF1ZSBsYSAkSF8wJCBkZWJlIHNlciByZWNoYXphZGEuIExhcyBtdWVzdHJhcyBubyBzb24gZXF1aXZhbGVudGVzLgoKUHJvY2VkZXJlbW9zIGEgdmVyaWZpY2FyIGxhICRIXzEkIG8gaGlww7N0ZXNpcyBhbHRlcm5hdGl2YSBxdWUgcHJvcG9uZSBxdWUgdW5hIGRlIGxhcyBtdWVzdHJhcyBlcyBtYXlvciBxdWUgb3RyYS4KClRhbWJpw6luIHJlY3Vycmltb3MgYWwgdC10ZXN0CgpgYGB7cn0KdC50ZXN0KCBtYW51YWwsIGF1dG9tYXRpY28gLCBhbHRlcm5hdGl2ZSA9ICJncmVhdGVyIikKYGBgCkVsIHAtdmFsb3IgcXVlIG5vcyBoYSBkYWRvIGVzIGRlbCBvcmRlbiBkZSAkMTBeey01fSBxdWUgZXMgbXV5IHBlcXVlw7FvIHJlc3BlY3RvIGEgMC4wNS4gUG9yIGVzbyB0ZW5lbW9zIHVuYSBhbHRhIGNvbmZpYWJpbGlkYWQgc29icmUgbGEgcHJlZ3VudGEgZGUgaW52ZXN0aWdhY2nDs24gcXVlIGRpY2UgcXVlIGxvcyBhdXRvcyBhdXRvbcOhdGljb3MgdGllbmVuIG1heW9yIGNvbnN1bW8gcXVlIGxvcyBtYW51YWxlcy4KCgoKCgojIyBBTk9WQQoKU2UgdXRpbGl6YSBwYXJhICoqVW5hIFZhcmlhYmxlIGNvbnRpbnVhIHkgZG9zIG8gbcOhcyBjYXRlZ8OzcmljYXMsIGdydXBvcyBvIGRpc2NyZXRhcyoqIAoKCkVqLiBUYWJsYSBjb24gdmVudGFzIGRlIGF1dG9zIGRlIDUgY29uY2VzaW9uYXJpb3MgeSA0IGNvbG9yZXMKCgp8Q29uY2VzaW9uYXJpb3MgfDEgfCAyIHwgMyB8IDQgfCA1IHwgNiB8CnwtLS0tLS0tLS0tLS0tLS18LS18LS0tfC0tLXwtLS18LS0tfC0tLXwKfCBBbWFyaWxsbyAgfCAxNiB8IDExIHwgMjAgfCAyMSB8IDE0IHwgNyAgfAp8IEJsYW5jbyAgICB8IDM3IHwgMzIgfCAxNSB8IDI1IHwgMzkgfCA0MSB8CnwgVmVyZGUgICAgIHwgMjEgfCAxMiB8IDE0IHwgMTcgfCAxMyB8IDE3IHwKfCBBenVsICAgICAgfCA0NSB8IDU5IHwgNDggfCA0NiB8IDM4IHwgNDcgfAoKQ2FyZ2EgZGUgZGF0b3MgbWFudWFsIGVuIFIuCgpgYGB7cn0KYXV0b3MgPC0gYygxNiwxMSwyMCwyMSwxNCw3LDM3LDMyLDE1LDI1LDM5LDQxLDIxLDEyLDE0LDE3LDEzLDE3LDQ1LDU5LDQ4LDQ2LDM4LDQ3KQpjb2xvcmVzIDwtIGFzLmZhY3RvcihjICAocmVwKCBjKCJhbWFyaWxsbyIsImF6dWwiLCJibGFuY28iLCJuZWdybyIpLCBlYWNoPTYpKSkKYGBgCgphcm1hZG8gZGVsIGRhdGFmcmFtZQoKYGBge3J9CmF1dG9zX2VsZWN0cmljb3MgPC0gZGF0YS5mcmFtZSAoYXV0b3MsY29sb3JlcykKCmJveHBsb3QoYXV0b3NfZWxlY3RyaWNvcyRhdXRvcyB+IGF1dG9zX2VsZWN0cmljb3MkY29sb3JlcywgeWxhYj0iVW5pZGFkZXMgVmVuZGlkYXMiLCB4bGFiPSAiQ29sb3JlcyIsIGNvbD1jKCJ5ZWxsb3ciLCJsaWdodGJsdWUiLCJ3aGl0ZSIsImdyZXkiKSkKYGBgCgojIyBQcmVndW50YSBkZSBpbnZlc3RpZ2FjacOzbgoKwr9Qb2RlbW9zIGFzZWd1cmFyIHF1ZSBubyB0b2RvcyBsb3MgYXV0b3MgZWzDqWN0cmljb3Mgc2UgdmVuZGVuIGlndWFsbWVudGU/CgpDcmVhcmVvcyB1biBtb2RlbG8gbGluZWFsIHBhcmEgcG9kZXIgaGFjZXIgZWwgYW7DoWxpc2lzIEFOT1ZBCgpgYGB7cn0KbW9kZWxvX2xpbmVhbCA8LSBsbShhdXRvcyB+IGNvbG9yZXMsIGRhdGEgPSBhdXRvc19lbGVjdHJpY29zKQoKbW9kZWxvX2xpbmVhbAoKc3VtbWFyeShtb2RlbG9fbGluZWFsKQpgYGAKCkVzdGFkaXN0aWNvIG1hdGVtw6F0aWNvIEFOT1ZBCgpgYGB7cn0KYW5ub3ZhX2F1dG9zIDwtIGFvdihtb2RlbG9fbGluZWFsKQpzdW1tYXJ5KGFubm92YV9hdXRvcykKYGBgCkNvbW8gcG9kZW1vcyB2ZXIgZWwgcC12YWxvciAoUHIgZGVsIG1vZGVsbyBhbm92YSkgZXMgbXV5IGNlcmNhbm8gYSBjZXJvLCBlcyBkZWNpciBxdWUgZXMgbXVjaG8gbWVub3MgcXVlIDAuMDUuIEVzdG8gaW1wbGljYSBxdWUgbG9zIGdydXBvcyBzb24gZGlmZXJlbnRlcy4KCkFsIGlndWFsIHF1ZSBlbiBlbCB0LXRlc3QgbnVlc3RyYXMgY29uc2lnbmFzIGRlIHBhcnRpZGEgZXJhbiBwcmltZXJvIHBvciBsYSBpZ3VhbGRhZCBvICRIXzAkIHZlcmRhZGVyYSBzaSBQciBlcyBtYXlvciBhIDAuMDUgKHRvZG9zIGxvcyBncnVwb3MgaWd1YWxlcykgbyAkSF8xJCB2ZXJkYWRlcmEgc2kgcHIgPCAwLjA1IC4gVmFsZSBkZWNpciBubyB0b2RvcyBsb3MgYXV0b3MgZWzDqWN0cmljb3Mgc2UgdmVuZGVuIHBvciBpZ3VhbC4KClBlcm8gdmVtb3MgcXVlIGxvcyBhdXRvcyBhenVsZXMgeSBibGFuY29zIHNvbiBtdXkgcGFyZWNpZG9zIGVuIHN1cyB2ZW50YXMsIHBhcmEgYW5hbGl6YXIgZXN0byB0ZW5kcmVtb3MgcXVlIHV0aWxpemFyIGVsIHRlc3QgZGUgVHVrZXkKCmBgYHtyfQpUdWtleUhTRChhbm5vdmFfYXV0b3MpCmBgYAoKVmVtb3MgcXVlIGVsIHAtdmFsb3IgZW50cmUgYmxhbmNvLWFtYXJpbGxvIGVzIGRlIDAuOTk2IGxvIHF1ZSBpbXBsaWNhIHF1ZSBlcyBtYXlvciBxdWUgMC4wNSwgcG9yIGVzbyBwb2RlbW9zIGRlY2lyIHF1ZSBlc3RvcyBkb3MgZ3J1cG9zIHRpZW5lbiBjb21wb3J0YW1pZXRubyBzZW1lamFudGUuCgojIyBDaGkgQ3VhZHJhZG8KCjIgVmFyaWFibGVzIGRpc2NyZXRhcwoKKipDYW50aWRhZCBkZSBDYXNvcyBkZSBQZXNvIGRlbCByZWNpw6luIE5hY2lkbyoqCgp8IEdlc3RhbnRlICB8IFBlc28gQWx0byAgfCBQZXNvIEJham8gIHwgIFRvdGFsIHwKfC0tLS0tLS0tLS0tfDotLS0tLS0tLS0tLS0tLTp8Oi0tLS0tLS0tLS0tLS0tOnwtLS0tLS0tOnwKfCBGdW1hZG9yYSAgfCA0MyB8IDIwNyB8IDI1MCB8CnwgTm8gRnVtYWRvcmF8IDEwNSB8IDE2NDUgfCAxNzUwIHwKfCAgICAgVG90YWwgICAgfCAxNDggICB8IDE4NTIgfCAyMDAwIHwKCgpDYXJnYXJlbW9zIGxvcyB2YWxvcmVzIGRlIGxhIHBhYmxhIGVuIFIKClRlbiBjdWlkYWRvICwgZXN0YW1vcyBjYXJnYW5kbyBsb3MgdmFsb3JlcyBwb3IgY29sdW1uYXMKCmBgYHtyfQpQZXNvX2FsdG8gPC1jKDQzLDEwNSkKUGVzb19iYWpvIDwtIGMoMjA3LDE2NDUpCnRhYmxhX2NoaSA8LSBkYXRhLmZyYW1lIChQZXNvX2FsdG8sIFBlc29fYmFqbykKcm93bmFtZXModGFibGFfY2hpKSA8LSBjKCJGdW1hZG9yZXMiLCJObyBGdW1hZG9yZXMiKQp0YWJsYV9jaGkKYGBgCgojIyBDaGkgY3VhZHJhZG8gdGVzdCBhcGxpY2FkbwoKYGBge3J9CmNoaXNxLnRlc3QodGFibGFfY2hpKQpgYGAKZWwgcC12YWxvciBlcyBtdWNobyBtZW5vciBxdWUgY2VybywgZW50b25jZXMgbGEgJEhfMCQgKGhpcMOzdGVzaXMgbnVsYSkgZXMgdmVyZGFkZXJhLiBQb2RlbW9zIGRlY2lyIHF1ZSBjb24gbG9zIGRhdG9zIHN1bWluaXN0cmFkb3Mgbm8gaGF5IGV2aWRlbmNpYSBkZSBkaWZlcmVuY2FzIGVudHJlIGxhcyBtdWVzdHJhcy4gQW1ib3MgZ3J1cG9zIChwZXNvIGFsdG8geSBwZXNvIGJham8pIHByb3ZpZW5lbiBkZSB1bmEgbWlzbWEgcG9ibGFjacOzbiwgcG9yIGxhIHRhbnRvIGVsIGhlY2hvIGRlIGxhIGluZmx1ZW5jaWEgZGUgZnVtYXIgbm8gcHVlZGUgYXRyaWJ1aXJzZSBjb21vIGNhdXNhbCBkZSBsYXMgZGlmZXJlbmNpYXMgb2JzZXJ2YWRhcyBlbiBsYSB0YWJsYSB5IHBvciBlbGxvIHNlIGVzdGltYSBxdWUgc29sbyB1biBwcm9jZXNvIGFsZWF0b3JpbyBlbiBsYSBzZWxlY2Npw7NuIGRlIGxhcyBtdWVzdHJhcyBlcyBsYSBjYXVkYSBkZSBsYXMgZGlmZXJlbmNpYXMuClBlcm8gYSBwZXNhciBkZSBlbGxvIGVsIHZhbG9yIGRlIDM4LjQyIGVzIGFsdG8gcG9yIGxvIHF1ZSB0ZW5kcsOtYW1vcyBxdWUgY29uc2lkZXJhciBhdW1lbnRhciBsYSBjYW50aWRhZCBkZSBtdWVzdHJhcyBxdWUgdG9tYW1vcyAoMjAwMCkgcGFyYSB0ZW5lciBldmlkZW5jaWEgcGxlbmEuCgo=