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)
| 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
| 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
| 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=