Trabajo base de datos BlackFriday

Omar Santiago Cáceres García

Julio/2022

La base de datos a utilizar es.

Blackfriday <- read_excel("Blackfriday.xlsx")

Actividad 1

a) Tamaño de la muestra

Dado que la población es finita, estime cuál debe ser el tamaño de muestra si se desea un margen de error \(E = \$650\), un nivel de confianza del \(95\%\) y se conoce por estudios anteriores que la desviación estándar poblacional es aproximadamente \(\$5100\)

\(Solución:\) Para conocer cual debe ser el tamaño de la muestra usaremos la siguiente libreria. {library(samplingbook)}

library(samplingbook)

sigma <- 5100 # Desviación estandar
error <- 650  # Margen de error

sample.size.mean(error, sigma,N=47734 ,level = 0.95)
## 
## sample.size.mean object: Sample size for mean estimate
## With finite population correction: N=47734, precision e=650 and standard deviation S=5100
## 
## Sample size needed: 236

Nuestra muestra debe tener un mínimo de \(236\) datos para ser representativa

b) Exportar muestra a archivo en formato .xlsx

Use R para extraer una muestra aleatoria del tamaño determinado en el ítem a. Deben explicar el paso a paso, fórmulas de script en R y adjuntar la muestra en formado .xlsx

\(Solución:\) Para el muestreo aleatorio de la base de datos vamos a usar la siguiente librería {library(dplyr)} y función {slice_sample}

library(dplyr)

set.seed(10) #Utilizamos set.seed para siempre obtener la misma muestra

muestra_aleatoria<-slice_sample(Blackfriday,
                                n=236,replace = FALSE) # Muestreo sin reemplazo
muestra_aleatoria
## # A tibble: 236 x 13
##    User_ID Product_ID Gender Age   Occupation City_Category Stay_In_Current_Cit~
##      <dbl> <chr>      <chr>  <chr>      <dbl> <chr>         <chr>               
##  1 1001472 P00192042  M      26-35          7 C             1.0                 
##  2 1005862 P00313342  F      26-35          9 C             0.0                 
##  3 1002038 P00288442  F      46-50          1 B             3.0                 
##  4 1003108 P00354742  M      51-55          6 B             1.0                 
##  5 1002222 P00259942  F      46-50          1 B             2.0                 
##  6 1002067 P00343442  M      51-55         16 B             2.0                 
##  7 1003378 P00257842  M      18-25          4 A             1.0                 
##  8 1001335 P00350042  M      36-45          0 C             1.0                 
##  9 1000838 P00364142  M      51-55         17 C             0.0                 
## 10 1005812 P00274942  F      26-35          7 A             1.0                 
## # ... with 226 more rows, and 6 more variables: Marital_Status <dbl>,
## #   Product_Category_1 <dbl>, Product_Category_2 <dbl>,
## #   Product_Category_3 <dbl>, Purchase <dbl>, Income <dbl>

Usaremos la función {write.xlsx} de la librería {library(openxlsx)} para exportar la muestra aleatoria del anterior punto.

library(openxlsx)

write.xlsx(
  muestra_aleatoria,"Muestra_BlackFriday.xlsx") #Exporta el archivo a formato xlsx

c) Parámetros y estadisticos de las bases de datos

De la variable PURCHASE, determine el valor de la media y la desviación estándar poblacionales y muestrales (tienen la población y una muestra). Explique brevemente quién es el estimador de quién allí. Además, calcule la probabilidad de que la variable media muestral sea mayor o igual que el valor de la poblacional.

\(Solución:\)

Para hallar el valor de la media y la desviación estandar requerido. A continuación se muestra el código que se utilizó para hallar y crear la tabla.

mu <- mean(Blackfriday$Purchase) # Media poblacional
sigma <- sd(Blackfriday$Purchase) # Desviación estándar poblacional

xbarra <- mean(muestra_aleatoria$Purchase) # Media muestral
s <- sd(muestra_aleatoria$Purchase) # Desviación estándar muestral

library(kableExtra)

Tabla1 <- data.frame(
  .=c("Población","Muestra"),
  MEDIA=round(c(mu, xbarra)),
  DESVIACIÓN=round(c(sigma,s)) # Data.frame de los resultados
)

#Formato de la tabla
Tabla1 %>%
  kbl(format.args = list(decimal.mark = ",", big.mark = ".")) %>%
  kable_classic()
. MEDIA DESVIACIÓN
Población 9.345 4.987
Muestra 9.174 5.085

Nuestros estimadores serán la media muestral \((\bar{X})\) y la desviación estandar de la muestra \((s)\) que son los que nos roporcionan información sobre los valores de los parámetros, es decir, la media poblacional \((\mu)\) y la desviación estándar poblacional \((\sigma)\)

La probabilidad de que la variable media muestral sea mayor o igual que el valor de la poblacional, lo cálcularemos como \((P\geq \mu)\) con la función {pnorm}

mu <- 9345 # Media poblacional
sigma <- 4987 # Desviación estándar poblacional

xbarra <- 9174   # Media muestral
s <- 5085 # Desviación estándar muestral

pnorm(mu,xbarra,s,lower.tail = FALSE)
## [1] 0.4865868

Siendo así que la probabilidad de que que la variable media muestral sea mayor o igual que el valor de la poblacional apróximadamente del \(48\%\)

d) Histograma

Haga el histograma de la variable PURCHASE, calcule el sesgo, la curtosis e indique con ellos brevemente si la variable parece distribuirse de forma normal o no.

\(Solución:\)

Hist_pur <- ggplot(Blackfriday, aes(x=Blackfriday$Purchase))+
  geom_histogram(color="darkgray",fill="#98F5FF")+ 
  labs(title = "Histograma de PURCHASE",
       x="Valor de las compras promedio (en dólares)",
       y="Cantidad") + 
  scale_y_continuous(breaks = seq(0,6000,1000))+
  theme(axis.text=element_text(size=14),
        axis.title=element_text(size=16,face="bold"))+
  geom_vline(xintercept = mean(Blackfriday$Purchase), color="red")

ggplotly(Hist_pur)

Para cálcular el sesgo y la curtosis usaremos la librería {library(moments)}

library(moments)

skewness(Blackfriday$Purchase) # Asimetría
## [1] 0.630725
kurtosis(Blackfriday$Purchase) # Curtosis
## [1] 2.67324

Cómo se puede observar en el gráfico y confirmado con la función {skewness} la cuál nos da la asimetría y es positiva \(0.6307\), entonces nuestra distribución tiene un sesgo hacía la derecha.

La curtosis, cálculada con la función {kurtosis}, la que nos dio \(2.673\) nos dice que nuestra distribución es menos escarpada que la una distribución normal, la cual tiene una curtosis de \(3\)

Con lo que podemos concluir que como la distribución normal tiene una asimetría de \(0\) y curtosis de \(3\), con nuestra distribución con asimetría de \(0.6307\) y curtosis de \(2.673\) parece distribuirse de forma normal.

Actividad 2

a) Intervalo de confianza para un promedio

Construya un intervalo de confianza al noventa por ciento para el promedio de la variable PURCHASE. Escriba la interpretación en el contexto del caso. Compruebe si la media poblacional cae en dicho intervalo.

\(Solución:\) Para la construcción de los intervalos de confianza se usará la librería {stats} Para el primer apartado usaremos la función {t.test}

library(stats)

t.test(x=Blackfriday$Purchase, alternative = "two.sided", conf.level = 0.9)$conf.int
## [1] 9307.023 9382.109
## attr(,"conf.level")
## [1] 0.9

A partir del resultado obtenido se puede concluir, con un nivel de confianza del \(90\%\), que el valor de las compras promedio en uno de los de los Black Fridays se encuentra entre \(\$9.307\) y \(\$9.382\).

Observese además, que la media poblacional \(\mu=9.345\) se encuentra en dicho intervalo, esto se debe por la forma en la que se construyó la muestra, la cuál al tener un \(95\%\) de nivel de confianza, \(95\) de cada \(100\) muestras tendrán la media poblacional \(\mu\) y la desviación poblaciónal \(\sigma\) en ellas.

b) Intervalo de confianza para una proporción.

Construya un intervalo de confianza al noventa y cinco por ciento para la proporción de ventas superiores a \(\$5.000\). Escriba la interpretación en el contexto del caso. Compruebe si la proporción poblacional está en este intervalo.

\(Solución:\) Para saber la proporción de personas que hicieron compras mayores a \(\$5.000\) usarémos la función {sum} y {with}

# Cantidad de compras superiores a $5.000  
sum(with(muestra_aleatoria,Purchase>=5000))
## [1] 191

La muestra aleatoria de \(236\) usuarios revela que \(191\) realizaron en un Black Friday compras superiores a \(\$5.000\), por lo tanto, la proporción de personas que hicieron compras mayores a \(\$5.000\) y con un intervalo de confianza del \(95\%\) la encontraremos con la función {prop.test}

prop.test(191,236, conf.level = 0.95)$conf.int
## [1] 0.7521151 0.8562069
## attr(,"conf.level")
## [1] 0.95

A partir del resultado obtenido se puede concluir, con un nivel de confianza del
\(90\%\), que la proporción de personas que realizaron compras mayores a \(\$5.000\) se encuentra entre \(0.7521\) y \(0.8562\)

La proporción de la población la cálcularemos de forma similar.

sum(with(Blackfriday,Purchase>=5000))
## [1] 39856

Entonces nuestra proporción de la población de \(47.734\) será

39856/47734
## [1] 0.8349604

Concluyendo que la proporción de la población \(0.835\) se encuentra en el intervalo de confianza de \(0.7521\) y \(0.8562\), econtrado anteriormente.

c) Intervalo de confianza para diferencias de medias.

Construya un intervalo de confianza al noventa por ciento para la diferencia de medias de las compras hechas por hombres y por mujeres.

\(Solución:\) Para construir el intervalo de confianza, vamos a crear dos subconjuntos de datos donde se alojaran las variables de hombres y mujeres como sigue a continuación:

hombres <- muestra_aleatoria[muestra_aleatoria$Gender=="M",]
mujeres <- muestra_aleatoria[muestra_aleatoria$Gender=="F",]

Como se cumple el supuesto de normalidad se puede usar la función {t.test} para construir el intervalo de confianza requerido. A continuación se muestra el código

t.test(x=hombres$Purchase, y=mujeres$Purchase,
       paired = FALSE, var.equal=FALSE,
       conf.level=0.9)$conf.int
## [1] -1394.497  1232.181
## attr(,"conf.level")
## [1] 0.9

A partir del intervalo de confianza anterior se puede concluir, que como el intervalo contiene al \(0\) entonces las compras promedio entre hombres y mujeres pueden llegar a ser iguales.

Actividad 3

a) Prueba de hipótesis

Construya una prueba de hipótesis con un nivel de significancia de 0,05 para las ventas promedio, usando como hipótesis alternativa: “µ es mayor a el valor real encontrado en la población

\(Solución:\)

En este problema interesa: \[H_0=\mu\leq 9.345\\H_1=\mu\gt 9.345\] a continuación las instrucciones para calcular el estadístico y su valor \(P\). Usamos los estadisticos encontrados en la \(Actividad \quad 1\)

xbarra <- 9174  # Media de la muestra
s <- 5085       # Desviacón de la muestra
n <- 236        # Tamaño de la muestra
mu <- 9345      # Media de referencia

est <- (xbarra - mu) / (s / sqrt(n))
est  # Para obtener el valor del estadistico
## [1] -0.516608
pnorm(est) # Para obtener el valor de P 
## [1] 0.3027149

Como el valor de \(P\) es mayor que al \(10\%\) se acepta que la media poblacional \(H_0=\mu\leq 9.345\)

b) Prueba de hipótesis para la diferencia de medias

Construya una prueba de hipótesis con un nivel de significancia de 0,05 para concluir si hay diferencia entre las compras promedio de hombres y mujeres. Justifique cada parte del proceso, al final dé su conclusión en el contexto del problema.

\(Solución:\)

En este problema interesa estudiar el siguiente conjunto de hipótesis.

\[H_0: \mu_1-\mu_2=0 \\ H_1: \mu_1-\mu_2\neq0\] El código para realizar la prueba es el siguiente:

t.test(x=hombres$Purchase, y=mujeres$Purchase, alternative="two.sided", mu=0, 
       paired=FALSE, var.equal=FALSE, conf.level=0.95)
## 
##  Welch Two Sample t-test
## 
## data:  hombres$Purchase and mujeres$Purchase
## t = -0.10268, df = 91.449, p-value = 0.9184
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -1651.017  1488.700
## sample estimates:
## mean of x mean of y 
##  9154.631  9235.789

De la prueba se obtiene un valor-P grande, por lo tanto, podemos concluir que no hay diferencias significativas entre el valor promedio de las compras de hombres y mujeres, esto ya se sospechaba en el punto \(2.c\) cuando en el intervalo se incluye al \(0\).

c) Regresión lineal y correlación.

Elabore e interprete un modelo de regresión simple. Evalúe la correlación.

\(Solución:\)

y <- muestra_aleatoria$Purchase     # Variable dependiente.  (Valor Compra en US)
x1 <- muestra_aleatoria$Gender      # Variable independiente (género)
x2 <- muestra_aleatoria$Occupation  # Variable independiente (Ocupación)
x3 <- muestra_aleatoria$Income      # Variable independiente.(Ingreso mensual)
fit <- lm(y~x1+x2+x3, data=muestra_aleatoria)
summary(fit)
## 
## Call:
## lm(formula = y ~ x1 + x2 + x3, data = muestra_aleatoria)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
##  -8828  -3308  -1145   2741  14484 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 9523.48052 1891.01116   5.036 9.54e-07 ***
## x1M          -95.98057  784.41577  -0.122    0.903    
## x2             4.23134   51.19327   0.083    0.934    
## x3            -0.02433    0.13357  -0.182    0.856    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 5118 on 232 degrees of freedom
## Multiple R-squared:  0.0002163,  Adjusted R-squared:  -0.01271 
## F-statistic: 0.01673 on 3 and 232 DF,  p-value: 0.997

Cómo se puede observan en nuestra anova, nuestro P-value entre las variables es demasiado grande lo que significa es que las variables de género, ocuoación e ingresos no son significativas para el valor de compra de los usuarios.

cor(x=muestra_aleatoria$Income,y=y) # Correlación entre compras e ingreso
## [1] -0.01144803

Del resultado anterior vemos que existe una correlación de -0.01144803 entre las dos variables, eso significa que no existe una relación entre el valor de compras y los ingresos de los usuarios. Este resultado se ilustra en la siguiente gráfica, donde mustra la aleatoridad de ambas variables y no se encuentra una relación.

cor_Purchase <- ggplot(muestra_aleatoria, aes(x=Purchase, y=Income))+
  geom_point(aes(shape=Gender),color="blue", size=0.5)+
  geom_smooth(method = "lm", se = FALSE, color="red", size=0.5)

 ggplotly(cor_Purchase)
cor(x=muestra_aleatoria$Occupation,y=y) # Correlación entre Ocupación y compras
## [1] 0.004345023

Del resultado anterior vemos que existe una correlación de 0.004345023 entre las dos variables, eso significa que no existe una relación entre la ocupación y el valor de compra de los usuarios. Este resultado se ilustra en la siguiente gráfica, donde mustra la aleatoridad de ambas variables y no se encuentra una relación.

cor_gen <- ggplot(muestra_aleatoria, aes(x=Purchase, y=Occupation))+
  geom_point(color="blue", size=0.5)+
  geom_smooth(method = "lm", se = FALSE, color="red", size=0.5)

ggplotly(cor_gen)
LS0tDQp0aXRsZTogIlRyYWJham8gYmFzZSBkZSBkYXRvcyBCbGFja0ZyaWRheSINCmRhdGU6ICJKdWxpby8yMDIyIg0KYXV0aG9yOiAiT21hciBTYW50aWFnbyBDw6FjZXJlcyBHYXJjw61hIg0KbGFuZzogZXMtRVMNCm91dHB1dDoNCiAgcm1kZm9ybWF0czo6ZG93bmN1dGU6DQogICAgaGlnaGxpZ2h0OiBrYXRlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogZmFsc2UNCiAgICAgIHNtb290aF9zY3JvbGw6IGZhbHNlDQogICAgICBjc3M6IHN0eWxlcy5jc3MNCi0tLQ0KDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlID0gRkFMU0V9DQojIyBHbG9iYWwgb3B0aW9ucw0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KCW1lc3NhZ2UgPSBGQUxTRSwNCgl3YXJuaW5nID0gRkFMU0UsDQoJY2FjaGUgPSBGQUxTRSwNCglmaWcuaGVpZ2h0PTksIA0KCWZpZy53aWR0aD0xMg0KKQ0KDQpgYGANCg0KDQpgYGB7ciBsaWJyZXJpYXMsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQpsaWJyYXJ5KHJlYWR4bCkNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShwbG90bHkpDQpsaWJyYXJ5KG1vZGVlc3QpDQpsaWJyYXJ5KGphbml0b3IpDQpsaWJyYXJ5KGthYmxlRXh0cmEpDQpsaWJyYXJ5KFJDb2xvckJyZXdlcikNCg0KYGBgDQoNCkxhIGJhc2UgZGUgZGF0b3MgYSB1dGlsaXphciBlcy4NCg0KYGBge3J9DQpCbGFja2ZyaWRheSA8LSByZWFkX2V4Y2VsKCJCbGFja2ZyaWRheS54bHN4IikNCmBgYA0KDQojIEFjdGl2aWRhZCAxDQoNCiMjIGEpIFRhbWHDsW8gZGUgbGEgbXVlc3RyYQ0KDQpEYWRvIHF1ZSBsYSBwb2JsYWNpw7NuIGVzIGZpbml0YSwgZXN0aW1lIGN1w6FsIGRlYmUgc2VyIGVsIHRhbWHDsW8gZGUgbXVlc3RyYSBzaSBzZSBkZXNlYSB1biBtYXJnZW4gZGUgZXJyb3IgJEUgPSBcJDY1MCQsIHVuIG5pdmVsIGRlIGNvbmZpYW56YSBkZWwgJDk1XCUkIHkgc2UgY29ub2NlIHBvciBlc3R1ZGlvcyBhbnRlcmlvcmVzIHF1ZSBsYSBkZXN2aWFjacOzbiBlc3TDoW5kYXIgcG9ibGFjaW9uYWwgZXMgYXByb3hpbWFkYW1lbnRlICRcJDUxMDAkDQoNCiRTb2x1Y2nDs246JA0KUGFyYSBjb25vY2VyIGN1YWwgZGViZSBzZXIgZWwgdGFtYcOxbyBkZSBsYSBtdWVzdHJhIHVzYXJlbW9zIGxhIHNpZ3VpZW50ZSBsaWJyZXJpYS4gYHtsaWJyYXJ5KHNhbXBsaW5nYm9vayl9YA0KYGBge3J9DQpsaWJyYXJ5KHNhbXBsaW5nYm9vaykNCg0Kc2lnbWEgPC0gNTEwMCAjIERlc3ZpYWNpw7NuIGVzdGFuZGFyDQplcnJvciA8LSA2NTAgICMgTWFyZ2VuIGRlIGVycm9yDQoNCnNhbXBsZS5zaXplLm1lYW4oZXJyb3IsIHNpZ21hLE49NDc3MzQgLGxldmVsID0gMC45NSkNCmBgYA0KTnVlc3RyYSBtdWVzdHJhIGRlYmUgdGVuZXIgdW4gbcOtbmltbyBkZSAkMjM2JCBkYXRvcyBwYXJhIHNlciByZXByZXNlbnRhdGl2YQ0KDQojIyBiKSBFeHBvcnRhciBtdWVzdHJhIGEgYXJjaGl2byBlbiBmb3JtYXRvIC54bHN4DQoNClVzZSBSIHBhcmEgZXh0cmFlciB1bmEgbXVlc3RyYSBhbGVhdG9yaWEgZGVsIHRhbWHDsW8gZGV0ZXJtaW5hZG8gZW4gZWwgw610ZW0gYS4gRGViZW4gZXhwbGljYXIgZWwgcGFzbyBhIHBhc28sIGbDs3JtdWxhcyBkZSBzY3JpcHQgZW4gUiB5IGFkanVudGFyIGxhIG11ZXN0cmEgZW4gZm9ybWFkbyAueGxzeCANCg0KJFNvbHVjacOzbjokDQpQYXJhIGVsIG11ZXN0cmVvIGFsZWF0b3JpbyBkZSBsYSBiYXNlIGRlIGRhdG9zIHZhbW9zIGEgdXNhciBsYSBzaWd1aWVudGUgbGlicmVyw61hIGB7bGlicmFyeShkcGx5cil9YCB5IGZ1bmNpw7NuIGB7c2xpY2Vfc2FtcGxlfWAgDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQoNCnNldC5zZWVkKDEwKSAjVXRpbGl6YW1vcyBzZXQuc2VlZCBwYXJhIHNpZW1wcmUgb2J0ZW5lciBsYSBtaXNtYSBtdWVzdHJhDQoNCm11ZXN0cmFfYWxlYXRvcmlhPC1zbGljZV9zYW1wbGUoQmxhY2tmcmlkYXksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG49MjM2LHJlcGxhY2UgPSBGQUxTRSkgIyBNdWVzdHJlbyBzaW4gcmVlbXBsYXpvDQptdWVzdHJhX2FsZWF0b3JpYQ0KDQpgYGANClVzYXJlbW9zIGxhIGZ1bmNpw7NuIGB7d3JpdGUueGxzeH1gIGRlIGxhIGxpYnJlcsOtYSBge2xpYnJhcnkob3Blbnhsc3gpfWAgcGFyYSBleHBvcnRhciBsYQ0KbXVlc3RyYSBhbGVhdG9yaWEgZGVsIGFudGVyaW9yIHB1bnRvLg0KYGBge3J9DQpsaWJyYXJ5KG9wZW54bHN4KQ0KDQp3cml0ZS54bHN4KA0KICBtdWVzdHJhX2FsZWF0b3JpYSwiTXVlc3RyYV9CbGFja0ZyaWRheS54bHN4IikgI0V4cG9ydGEgZWwgYXJjaGl2byBhIGZvcm1hdG8geGxzeA0KYGBgDQoNCiMjIGMpIFBhcsOhbWV0cm9zIHkgZXN0YWRpc3RpY29zIGRlIGxhcyBiYXNlcyBkZSBkYXRvcw0KDQpEZSBsYSB2YXJpYWJsZSBQVVJDSEFTRSwgZGV0ZXJtaW5lIGVsIHZhbG9yIGRlIGxhIG1lZGlhIHkgbGEgZGVzdmlhY2nDs24gZXN0w6FuZGFyIHBvYmxhY2lvbmFsZXMgeSBtdWVzdHJhbGVzICh0aWVuZW4gbGEgcG9ibGFjacOzbiB5IHVuYSBtdWVzdHJhKS4gRXhwbGlxdWUgYnJldmVtZW50ZSBxdWnDqW4gZXMgZWwgZXN0aW1hZG9yIGRlIHF1acOpbiBhbGzDrS4gQWRlbcOhcywgY2FsY3VsZSBsYSBwcm9iYWJpbGlkYWQgZGUgcXVlIGxhIHZhcmlhYmxlIG1lZGlhIG11ZXN0cmFsIHNlYSBtYXlvciBvIGlndWFsIHF1ZSBlbCB2YWxvciBkZSBsYSBwb2JsYWNpb25hbC4NCg0KJFNvbHVjacOzbjokDQoNClBhcmEgaGFsbGFyIGVsIHZhbG9yIGRlIGxhIG1lZGlhIHkgbGEgZGVzdmlhY2nDs24gZXN0YW5kYXIgcmVxdWVyaWRvLiBBIGNvbnRpbnVhY2nDs24gc2UgbXVlc3RyYSBlbCBjw7NkaWdvDQpxdWUgc2UgdXRpbGl6w7MgcGFyYSBoYWxsYXIgeSBjcmVhciBsYSB0YWJsYS4NCmBgYHtyfQ0KbXUgPC0gbWVhbihCbGFja2ZyaWRheSRQdXJjaGFzZSkgIyBNZWRpYSBwb2JsYWNpb25hbA0Kc2lnbWEgPC0gc2QoQmxhY2tmcmlkYXkkUHVyY2hhc2UpICMgRGVzdmlhY2nDs24gZXN0w6FuZGFyIHBvYmxhY2lvbmFsDQoNCnhiYXJyYSA8LSBtZWFuKG11ZXN0cmFfYWxlYXRvcmlhJFB1cmNoYXNlKSAjIE1lZGlhIG11ZXN0cmFsDQpzIDwtIHNkKG11ZXN0cmFfYWxlYXRvcmlhJFB1cmNoYXNlKSAjIERlc3ZpYWNpw7NuIGVzdMOhbmRhciBtdWVzdHJhbA0KDQpsaWJyYXJ5KGthYmxlRXh0cmEpDQoNClRhYmxhMSA8LSBkYXRhLmZyYW1lKA0KICAuPWMoIlBvYmxhY2nDs24iLCJNdWVzdHJhIiksDQogIE1FRElBPXJvdW5kKGMobXUsIHhiYXJyYSkpLA0KICBERVNWSUFDScOTTj1yb3VuZChjKHNpZ21hLHMpKSAjIERhdGEuZnJhbWUgZGUgbG9zIHJlc3VsdGFkb3MNCikNCg0KI0Zvcm1hdG8gZGUgbGEgdGFibGENClRhYmxhMSAlPiUNCiAga2JsKGZvcm1hdC5hcmdzID0gbGlzdChkZWNpbWFsLm1hcmsgPSAiLCIsIGJpZy5tYXJrID0gIi4iKSkgJT4lDQogIGthYmxlX2NsYXNzaWMoKQ0KDQpgYGANCk51ZXN0cm9zIGVzdGltYWRvcmVzIHNlcsOhbiBsYSBtZWRpYSBtdWVzdHJhbCAkKFxiYXJ7WH0pJCB5IGxhIGRlc3ZpYWNpw7NuIA0KZXN0YW5kYXIgZGUgbGEgbXVlc3RyYSAkKHMpJCBxdWUgc29uIGxvcyBxdWUgbm9zIHJvcG9yY2lvbmFuIGluZm9ybWFjacOzbiBzb2JyZSANCmxvcyB2YWxvcmVzIGRlIGxvcyBwYXLDoW1ldHJvcywgZXMgZGVjaXIsIGxhIG1lZGlhIHBvYmxhY2lvbmFsICQoXG11KSQgeSBsYSANCmRlc3ZpYWNpw7NuIGVzdMOhbmRhciBwb2JsYWNpb25hbCAkKFxzaWdtYSkkDQoNCkxhIHByb2JhYmlsaWRhZCBkZSBxdWUgbGEgdmFyaWFibGUgbWVkaWEgbXVlc3RyYWwgc2VhIG1heW9yIG8gaWd1YWwgcXVlIGVsIHZhbG9yDQpkZSBsYSBwb2JsYWNpb25hbCwgbG8gY8OhbGN1bGFyZW1vcyBjb21vICQoUFxnZXEgXG11KSQgY29uIGxhIGZ1bmNpw7NuIGB7cG5vcm19YA0KDQpgYGB7cn0NCm11IDwtIDkzNDUgIyBNZWRpYSBwb2JsYWNpb25hbA0Kc2lnbWEgPC0gNDk4NyAjIERlc3ZpYWNpw7NuIGVzdMOhbmRhciBwb2JsYWNpb25hbA0KDQp4YmFycmEgPC0gOTE3NAkgIyBNZWRpYSBtdWVzdHJhbA0KcyA8LSA1MDg1ICMgRGVzdmlhY2nDs24gZXN0w6FuZGFyIG11ZXN0cmFsDQoNCnBub3JtKG11LHhiYXJyYSxzLGxvd2VyLnRhaWwgPSBGQUxTRSkNCmBgYA0KU2llbmRvIGFzw60gcXVlIGxhIHByb2JhYmlsaWRhZCBkZSBxdWUgcXVlIGxhIHZhcmlhYmxlIG1lZGlhIG11ZXN0cmFsIHNlYSBtYXlvciANCm8gaWd1YWwgcXVlIGVsIHZhbG9yIGRlIGxhIHBvYmxhY2lvbmFsIGFwcsOzeGltYWRhbWVudGUgZGVsICQ0OFwlJA0KDQojIyBkKSBIaXN0b2dyYW1hDQoNCkhhZ2EgZWwgaGlzdG9ncmFtYSBkZSBsYSB2YXJpYWJsZSBQVVJDSEFTRSwgY2FsY3VsZSBlbCBzZXNnbywgbGEgY3VydG9zaXMgZSBpbmRpcXVlIGNvbiBlbGxvcyBicmV2ZW1lbnRlIHNpIGxhIHZhcmlhYmxlIHBhcmVjZSBkaXN0cmlidWlyc2UgZGUgZm9ybWEgbm9ybWFsIG8gbm8uDQoNCiRTb2x1Y2nDs246JA0KYGBge3J9DQpIaXN0X3B1ciA8LSBnZ3Bsb3QoQmxhY2tmcmlkYXksIGFlcyh4PUJsYWNrZnJpZGF5JFB1cmNoYXNlKSkrDQogIGdlb21faGlzdG9ncmFtKGNvbG9yPSJkYXJrZ3JheSIsZmlsbD0iIzk4RjVGRiIpKyANCiAgbGFicyh0aXRsZSA9ICJIaXN0b2dyYW1hIGRlIFBVUkNIQVNFIiwNCiAgICAgICB4PSJWYWxvciBkZSBsYXMgY29tcHJhcyBwcm9tZWRpbyAoZW4gZMOzbGFyZXMpIiwNCiAgICAgICB5PSJDYW50aWRhZCIpICsgDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCw2MDAwLDEwMDApKSsNCiAgdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTE0KSwNCiAgICAgICAgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xNixmYWNlPSJib2xkIikpKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBtZWFuKEJsYWNrZnJpZGF5JFB1cmNoYXNlKSwgY29sb3I9InJlZCIpDQoNCmdncGxvdGx5KEhpc3RfcHVyKQ0KDQpgYGANClBhcmEgY8OhbGN1bGFyIGVsIHNlc2dvIHkgbGEgY3VydG9zaXMgdXNhcmVtb3MgbGEgbGlicmVyw61hIGB7bGlicmFyeShtb21lbnRzKX1gDQpgYGB7cn0NCmxpYnJhcnkobW9tZW50cykNCg0Kc2tld25lc3MoQmxhY2tmcmlkYXkkUHVyY2hhc2UpICMgQXNpbWV0csOtYQ0Ka3VydG9zaXMoQmxhY2tmcmlkYXkkUHVyY2hhc2UpICMgQ3VydG9zaXMNCg0KYGBgDQpDw7NtbyBzZSBwdWVkZSBvYnNlcnZhciBlbiBlbCBncsOhZmljbyB5IGNvbmZpcm1hZG8gY29uIGxhIGZ1bmNpw7NuIGB7c2tld25lc3N9YCBsYQ0KY3XDoWwgbm9zIGRhIGxhIGFzaW1ldHLDrWEgeSBlcyBwb3NpdGl2YSAkMC42MzA3JCwgZW50b25jZXMgbnVlc3RyYSBkaXN0cmlidWNpw7NuDQp0aWVuZSB1biBzZXNnbyBoYWPDrWEgbGEgZGVyZWNoYS4NCg0KTGEgY3VydG9zaXMsIGPDoWxjdWxhZGEgY29uIGxhIGZ1bmNpw7NuIGB7a3VydG9zaXN9YCwgbGEgcXVlIG5vcyBkaW8gJDIuNjczJCBub3MgDQpkaWNlIHF1ZSBudWVzdHJhIGRpc3RyaWJ1Y2nDs24gZXMgbWVub3MgZXNjYXJwYWRhIHF1ZSBsYSB1bmEgZGlzdHJpYnVjacOzbiBub3JtYWwsDQpsYSBjdWFsIHRpZW5lIHVuYSBjdXJ0b3NpcyBkZSAkMyQNCg0KQ29uIGxvIHF1ZSBwb2RlbW9zIGNvbmNsdWlyIHF1ZSBjb21vIGxhIGRpc3RyaWJ1Y2nDs24gbm9ybWFsIHRpZW5lIHVuYSBhc2ltZXRyw61hIA0KZGUgJDAkIHkgY3VydG9zaXMgZGUgJDMkLCBjb24gbnVlc3RyYSBkaXN0cmlidWNpw7NuIGNvbiBhc2ltZXRyw61hIGRlICQwLjYzMDckIHkgDQpjdXJ0b3NpcyBkZSAkMi42NzMkIHBhcmVjZSBkaXN0cmlidWlyc2UgZGUgZm9ybWEgbm9ybWFsLg0KDQojIEFjdGl2aWRhZCAyDQoNCiMjIGEpIEludGVydmFsbyBkZSBjb25maWFuemEgcGFyYSB1biBwcm9tZWRpbw0KDQpDb25zdHJ1eWEgdW4gaW50ZXJ2YWxvIGRlIGNvbmZpYW56YSBhbCBub3ZlbnRhIHBvciBjaWVudG8gcGFyYSBlbCBwcm9tZWRpbyBkZSBsYSB2YXJpYWJsZSBQVVJDSEFTRS4gRXNjcmliYSBsYSBpbnRlcnByZXRhY2nDs24gZW4gZWwgY29udGV4dG8gZGVsIGNhc28uIENvbXBydWViZSBzaSBsYSBtZWRpYSBwb2JsYWNpb25hbCBjYWUgZW4gZGljaG8gaW50ZXJ2YWxvLg0KDQokU29sdWNpw7NuOiQNClBhcmEgbGEgY29uc3RydWNjacOzbiBkZSBsb3MgaW50ZXJ2YWxvcyBkZSBjb25maWFuemEgc2UgdXNhcsOhIGxhIGxpYnJlcsOtYSBge3N0YXRzfWANClBhcmEgZWwgcHJpbWVyIGFwYXJ0YWRvIHVzYXJlbW9zIGxhIGZ1bmNpw7NuIGB7dC50ZXN0fWANCg0KYGBge3J9DQpsaWJyYXJ5KHN0YXRzKQ0KDQp0LnRlc3QoeD1CbGFja2ZyaWRheSRQdXJjaGFzZSwgYWx0ZXJuYXRpdmUgPSAidHdvLnNpZGVkIiwgY29uZi5sZXZlbCA9IDAuOSkkY29uZi5pbnQNCmBgYA0KQSBwYXJ0aXIgZGVsIHJlc3VsdGFkbyBvYnRlbmlkbyBzZSBwdWVkZSBjb25jbHVpciwgY29uIHVuIG5pdmVsIGRlIGNvbmZpYW56YSBkZWwNCiQ5MFwlJCwgcXVlIGVsIHZhbG9yIGRlIGxhcyBjb21wcmFzIHByb21lZGlvIGVuIHVubyBkZSBsb3MgZGUgbG9zIEJsYWNrIEZyaWRheXMNCnNlIGVuY3VlbnRyYSBlbnRyZSAkXCQ5LjMwNyQgeSAkXCQ5LjM4MiQuDQoNCk9ic2VydmVzZSBhZGVtw6FzLCBxdWUgbGEgbWVkaWEgcG9ibGFjaW9uYWwgJFxtdT05LjM0NSQgc2UgZW5jdWVudHJhIGVuIGRpY2hvIGludGVydmFsbywNCmVzdG8gc2UgZGViZSBwb3IgbGEgZm9ybWEgZW4gbGEgcXVlIHNlIGNvbnN0cnV5w7MgbGEgbXVlc3RyYSwgbGEgY3XDoWwgYWwgdGVuZXIgdW4NCiQ5NVwlJCBkZSBuaXZlbCBkZSBjb25maWFuemEsICQ5NSQgZGUgY2FkYSAkMTAwJCBtdWVzdHJhcyB0ZW5kcsOhbiBsYSBtZWRpYSBwb2JsYWNpb25hbA0KJFxtdSQgeSBsYSBkZXN2aWFjacOzbiBwb2JsYWNpw7NuYWwgJFxzaWdtYSQgZW4gZWxsYXMuDQoNCiMjIGIpIEludGVydmFsbyBkZSBjb25maWFuemEgcGFyYSB1bmEgcHJvcG9yY2nDs24uDQoNCkNvbnN0cnV5YSB1biBpbnRlcnZhbG8gZGUgY29uZmlhbnphIGFsIG5vdmVudGEgeSBjaW5jbyBwb3IgY2llbnRvIHBhcmEgbGEgcHJvcG9yY2nDs24gZGUgdmVudGFzIHN1cGVyaW9yZXMgYSAkXCQ1LjAwMCQuIEVzY3JpYmEgbGEgaW50ZXJwcmV0YWNpw7NuIGVuIGVsIGNvbnRleHRvIGRlbCBjYXNvLiBDb21wcnVlYmUgc2kgbGEgcHJvcG9yY2nDs24gcG9ibGFjaW9uYWwgZXN0w6EgZW4gZXN0ZSBpbnRlcnZhbG8uIA0KDQokU29sdWNpw7NuOiQNClBhcmEgc2FiZXIgbGEgcHJvcG9yY2nDs24gZGUgcGVyc29uYXMgcXVlIGhpY2llcm9uIGNvbXByYXMgbWF5b3JlcyBhICRcJDUuMDAwJA0KdXNhcsOpbW9zIGxhIGZ1bmNpw7NuIGB7c3VtfWAgeSBge3dpdGh9YA0KDQpgYGB7cn0NCiMgQ2FudGlkYWQgZGUgY29tcHJhcyBzdXBlcmlvcmVzIGEgJDUuMDAwICANCnN1bSh3aXRoKG11ZXN0cmFfYWxlYXRvcmlhLFB1cmNoYXNlPj01MDAwKSkNCmBgYA0KTGEgbXVlc3RyYSBhbGVhdG9yaWEgZGUgJDIzNiQgdXN1YXJpb3MgcmV2ZWxhIHF1ZSAkMTkxJCByZWFsaXphcm9uIGVuIHVuIEJsYWNrIEZyaWRheQ0KY29tcHJhcyBzdXBlcmlvcmVzIGEgJFwkNS4wMDAkLCBwb3IgbG8gdGFudG8sIGxhIHByb3BvcmNpw7NuIGRlIHBlcnNvbmFzIHF1ZQ0KaGljaWVyb24gY29tcHJhcyBtYXlvcmVzIGEgJFwkNS4wMDAkIHkgY29uIHVuIGludGVydmFsbyBkZSBjb25maWFuemEgZGVsICQ5NVwlJCBsYQ0KZW5jb250cmFyZW1vcyBjb24gbGEgZnVuY2nDs24gYHtwcm9wLnRlc3R9YA0KDQpgYGB7cn0NCnByb3AudGVzdCgxOTEsMjM2LCBjb25mLmxldmVsID0gMC45NSkkY29uZi5pbnQNCmBgYA0KQSBwYXJ0aXIgZGVsIHJlc3VsdGFkbyBvYnRlbmlkbyBzZSBwdWVkZSBjb25jbHVpciwgY29uIHVuIG5pdmVsIGRlIGNvbmZpYW56YSBkZWwgIA0KJDkwXCUkLCBxdWUgbGEgcHJvcG9yY2nDs24gZGUgcGVyc29uYXMgcXVlIHJlYWxpemFyb24gY29tcHJhcyBtYXlvcmVzIGEgJFwkNS4wMDAkDQpzZSBlbmN1ZW50cmEgZW50cmUgJDAuNzUyMSQgeSAkMC44NTYyJA0KDQpMYSBwcm9wb3JjacOzbiBkZSBsYSBwb2JsYWNpw7NuIGxhIGPDoWxjdWxhcmVtb3MgZGUgZm9ybWEgc2ltaWxhci4NCmBgYHtyfQ0Kc3VtKHdpdGgoQmxhY2tmcmlkYXksUHVyY2hhc2U+PTUwMDApKQ0KYGBgDQpFbnRvbmNlcyBudWVzdHJhIHByb3BvcmNpw7NuIGRlIGxhIHBvYmxhY2nDs24gZGUgJDQ3LjczNCQgc2Vyw6ENCmBgYHtyfQ0KMzk4NTYvNDc3MzQNCmBgYA0KQ29uY2x1eWVuZG8gcXVlIGxhIHByb3BvcmNpw7NuIGRlIGxhIHBvYmxhY2nDs24gJDAuODM1JCBzZSBlbmN1ZW50cmEgZW4gZWwgDQppbnRlcnZhbG8gZGUgY29uZmlhbnphIGRlICQwLjc1MjEkIHkgJDAuODU2MiQsIGVjb250cmFkbyBhbnRlcmlvcm1lbnRlLg0KDQojIyBjKSBJbnRlcnZhbG8gZGUgY29uZmlhbnphIHBhcmEgZGlmZXJlbmNpYXMgZGUgbWVkaWFzLg0KDQpDb25zdHJ1eWEgdW4gaW50ZXJ2YWxvIGRlIGNvbmZpYW56YSBhbCBub3ZlbnRhIHBvciBjaWVudG8gcGFyYSBsYSBkaWZlcmVuY2lhIGRlIG1lZGlhcyBkZSBsYXMgY29tcHJhcyBoZWNoYXMgcG9yIGhvbWJyZXMgeSBwb3IgbXVqZXJlcy4gDQoNCiRTb2x1Y2nDs246JA0KUGFyYSBjb25zdHJ1aXIgZWwgaW50ZXJ2YWxvIGRlIGNvbmZpYW56YSwgdmFtb3MgYSBjcmVhciBkb3Mgc3ViY29uanVudG9zIGRlIGRhdG9zDQpkb25kZSBzZSBhbG9qYXJhbiBsYXMgdmFyaWFibGVzIGRlIGhvbWJyZXMgeSBtdWplcmVzIGNvbW8gc2lndWUgYSBjb250aW51YWNpw7NuOg0KDQpgYGB7cn0NCmhvbWJyZXMgPC0gbXVlc3RyYV9hbGVhdG9yaWFbbXVlc3RyYV9hbGVhdG9yaWEkR2VuZGVyPT0iTSIsXQ0KbXVqZXJlcyA8LSBtdWVzdHJhX2FsZWF0b3JpYVttdWVzdHJhX2FsZWF0b3JpYSRHZW5kZXI9PSJGIixdDQpgYGANCkNvbW8gc2UgY3VtcGxlIGVsIHN1cHVlc3RvIGRlIG5vcm1hbGlkYWQgc2UgcHVlZGUgdXNhciBsYSBmdW5jacOzbiBge3QudGVzdH1gIA0KcGFyYSBjb25zdHJ1aXIgZWwgaW50ZXJ2YWxvIGRlIGNvbmZpYW56YSByZXF1ZXJpZG8uIEEgY29udGludWFjacOzbiBzZSBtdWVzdHJhIGVsIGPDs2RpZ28NCg0KYGBge3J9DQp0LnRlc3QoeD1ob21icmVzJFB1cmNoYXNlLCB5PW11amVyZXMkUHVyY2hhc2UsDQogICAgICAgcGFpcmVkID0gRkFMU0UsIHZhci5lcXVhbD1GQUxTRSwNCiAgICAgICBjb25mLmxldmVsPTAuOSkkY29uZi5pbnQNCmBgYA0KQSBwYXJ0aXIgZGVsIGludGVydmFsbyBkZSBjb25maWFuemEgYW50ZXJpb3Igc2UgcHVlZGUgY29uY2x1aXIsIHF1ZSBjb21vIGVsIGludGVydmFsbw0KY29udGllbmUgYWwgJDAkIGVudG9uY2VzIGxhcyBjb21wcmFzIHByb21lZGlvIGVudHJlIGhvbWJyZXMgeSBtdWplcmVzIHB1ZWRlbiBsbGVnYXINCmEgc2VyIGlndWFsZXMuIA0KDQojIEFjdGl2aWRhZCAzDQoNCiMjIGEpIFBydWViYSBkZSBoaXDDs3Rlc2lzDQoNCkNvbnN0cnV5YSB1bmEgcHJ1ZWJhIGRlIGhpcMOzdGVzaXMgY29uIHVuIG5pdmVsIGRlIHNpZ25pZmljYW5jaWEgZGUgMCwwNSBwYXJhIGxhcyB2ZW50YXMgcHJvbWVkaW8sIHVzYW5kbyBjb21vIGhpcMOzdGVzaXMgYWx0ZXJuYXRpdmE6IOKAnMK1IGVzIG1heW9yIGEgZWwgdmFsb3IgcmVhbCBlbmNvbnRyYWRvIGVuIGxhIHBvYmxhY2nDs24gDQoNCiRTb2x1Y2nDs246JA0KDQpFbiBlc3RlIHByb2JsZW1hIGludGVyZXNhOiAkJEhfMD1cbXVcbGVxIDkuMzQ1XFxIXzE9XG11XGd0IDkuMzQ1JCQgYSBjb250aW51YWNpw7NuIGxhcyBpbnN0cnVjY2lvbmVzIHBhcmEgY2FsY3VsYXIgZWwgZXN0YWTDrXN0aWNvIHkgc3UgdmFsb3IgJFAkLiBVc2Ftb3MgbG9zIGVzdGFkaXN0aWNvcyBlbmNvbnRyYWRvcyBlbiBsYSAkQWN0aXZpZGFkIFxxdWFkIDEkDQpgYGB7cn0NCnhiYXJyYSA8LSA5MTc0ICAjIE1lZGlhIGRlIGxhIG11ZXN0cmENCnMgPC0gNTA4NSAgICAgICAjIERlc3ZpYWPDs24gZGUgbGEgbXVlc3RyYQ0KbiA8LSAyMzYgICAgICAgICMgVGFtYcOxbyBkZSBsYSBtdWVzdHJhDQptdSA8LSA5MzQ1ICAgICAgIyBNZWRpYSBkZSByZWZlcmVuY2lhDQoNCmVzdCA8LSAoeGJhcnJhIC0gbXUpIC8gKHMgLyBzcXJ0KG4pKQ0KZXN0ICAjIFBhcmEgb2J0ZW5lciBlbCB2YWxvciBkZWwgZXN0YWRpc3RpY28NCg0KcG5vcm0oZXN0KSAjIFBhcmEgb2J0ZW5lciBlbCB2YWxvciBkZSBQIA0KYGBgDQpDb21vIGVsIHZhbG9yIGRlICRQJCBlcyBtYXlvciBxdWUgYWwgJDEwXCUkIHNlIGFjZXB0YSBxdWUgbGEgbWVkaWEgcG9ibGFjaW9uYWwNCiRIXzA9XG11XGxlcSA5LjM0NSQNCg0KIyMgYikgUHJ1ZWJhIGRlIGhpcMOzdGVzaXMgcGFyYSBsYSBkaWZlcmVuY2lhIGRlIG1lZGlhcw0KDQpDb25zdHJ1eWEgdW5hIHBydWViYSBkZSBoaXDDs3Rlc2lzIGNvbiB1biBuaXZlbCBkZSBzaWduaWZpY2FuY2lhIGRlIDAsMDUgcGFyYSBjb25jbHVpciBzaSBoYXkgZGlmZXJlbmNpYSBlbnRyZSBsYXMgY29tcHJhcyBwcm9tZWRpbyBkZSBob21icmVzIHkgbXVqZXJlcy4gSnVzdGlmaXF1ZSBjYWRhIHBhcnRlIGRlbCBwcm9jZXNvLCBhbCBmaW5hbCBkw6kgc3UgY29uY2x1c2nDs24gZW4gZWwgY29udGV4dG8gZGVsIHByb2JsZW1hLg0KDQokU29sdWNpw7NuOiQNCg0KRW4gZXN0ZSBwcm9ibGVtYSBpbnRlcmVzYSBlc3R1ZGlhciBlbCBzaWd1aWVudGUgY29uanVudG8gZGUgaGlww7N0ZXNpcy4NCg0KJCRIXzA6IFxtdV8xLVxtdV8yPTAgXFwgSF8xOiBcbXVfMS1cbXVfMlxuZXEwJCQNCkVsIGPDs2RpZ28gcGFyYSByZWFsaXphciBsYSBwcnVlYmEgZXMgZWwgc2lndWllbnRlOg0KDQpgYGB7cn0NCnQudGVzdCh4PWhvbWJyZXMkUHVyY2hhc2UsIHk9bXVqZXJlcyRQdXJjaGFzZSwgYWx0ZXJuYXRpdmU9InR3by5zaWRlZCIsIG11PTAsIA0KICAgICAgIHBhaXJlZD1GQUxTRSwgdmFyLmVxdWFsPUZBTFNFLCBjb25mLmxldmVsPTAuOTUpDQpgYGANCkRlIGxhIHBydWViYSBzZSBvYnRpZW5lIHVuIHZhbG9yLVAgZ3JhbmRlLCBwb3IgbG8gdGFudG8sIHBvZGVtb3MgY29uY2x1aXIgcXVlIG5vIGhheSBkaWZlcmVuY2lhcyBzaWduaWZpY2F0aXZhcyBlbnRyZSBlbCB2YWxvciBwcm9tZWRpbyBkZSBsYXMgY29tcHJhcyBkZSBob21icmVzIHkgbXVqZXJlcywgZXN0byB5YSBzZSBzb3NwZWNoYWJhIA0KZW4gZWwgcHVudG8gJDIuYyQgY3VhbmRvIGVuIGVsIGludGVydmFsbyBzZSBpbmNsdXllIGFsICQwJC4NCg0KIyMgYykgUmVncmVzacOzbiBsaW5lYWwgeSBjb3JyZWxhY2nDs24uDQoNCkVsYWJvcmUgZSBpbnRlcnByZXRlIHVuIG1vZGVsbyBkZSByZWdyZXNpw7NuIHNpbXBsZS4gRXZhbMO6ZSBsYSBjb3JyZWxhY2nDs24uDQoNCiRTb2x1Y2nDs246JA0KDQoNCmBgYHtyfQ0KeSA8LSBtdWVzdHJhX2FsZWF0b3JpYSRQdXJjaGFzZSAgICAgIyBWYXJpYWJsZSBkZXBlbmRpZW50ZS4gIChWYWxvciBDb21wcmEgZW4gVVMpDQp4MSA8LSBtdWVzdHJhX2FsZWF0b3JpYSRHZW5kZXIgICAgICAjIFZhcmlhYmxlIGluZGVwZW5kaWVudGUgKGfDqW5lcm8pDQp4MiA8LSBtdWVzdHJhX2FsZWF0b3JpYSRPY2N1cGF0aW9uICAjIFZhcmlhYmxlIGluZGVwZW5kaWVudGUgKE9jdXBhY2nDs24pDQp4MyA8LSBtdWVzdHJhX2FsZWF0b3JpYSRJbmNvbWUgICAgICAjIFZhcmlhYmxlIGluZGVwZW5kaWVudGUuKEluZ3Jlc28gbWVuc3VhbCkNCmZpdCA8LSBsbSh5fngxK3gyK3gzLCBkYXRhPW11ZXN0cmFfYWxlYXRvcmlhKQ0Kc3VtbWFyeShmaXQpDQoNCmBgYA0KQ8OzbW8gc2UgcHVlZGUgb2JzZXJ2YW4gZW4gbnVlc3RyYSBhbm92YSwgbnVlc3RybyBQLXZhbHVlIGVudHJlIGxhcyB2YXJpYWJsZXMgZXMgZGVtYXNpYWRvIGdyYW5kZQ0KbG8gcXVlIHNpZ25pZmljYSBlcyBxdWUgbGFzIHZhcmlhYmxlcyBkZSBnw6luZXJvLCBvY3VvYWNpw7NuIGUgaW5ncmVzb3Mgbm8gc29uIHNpZ25pZmljYXRpdmFzIHBhcmENCmVsIHZhbG9yIGRlIGNvbXByYSBkZSBsb3MgdXN1YXJpb3MuDQoNCmBgYHtyfQ0KY29yKHg9bXVlc3RyYV9hbGVhdG9yaWEkSW5jb21lLHk9eSkgIyBDb3JyZWxhY2nDs24gZW50cmUgY29tcHJhcyBlIGluZ3Jlc28NCmBgYA0KRGVsIHJlc3VsdGFkbyBhbnRlcmlvciB2ZW1vcyBxdWUgZXhpc3RlIHVuYSBjb3JyZWxhY2nDs24gZGUgLTAuMDExNDQ4MDMgZW50cmUgbGFzIGRvcyB2YXJpYWJsZXMsDQplc28gc2lnbmlmaWNhIHF1ZSBubyBleGlzdGUgdW5hIHJlbGFjacOzbiBlbnRyZSBlbCB2YWxvciBkZSBjb21wcmFzIHkgbG9zIGluZ3Jlc29zIGRlIGxvcyB1c3Vhcmlvcy4NCkVzdGUgcmVzdWx0YWRvIHNlIGlsdXN0cmEgZW4gbGEgc2lndWllbnRlIGdyw6FmaWNhLCBkb25kZSBtdXN0cmEgbGEgYWxlYXRvcmlkYWQgZGUgYW1iYXMgdmFyaWFibGVzIA0KeSBubyBzZSBlbmN1ZW50cmEgdW5hIHJlbGFjacOzbi4NCg0KYGBge3J9DQpjb3JfUHVyY2hhc2UgPC0gZ2dwbG90KG11ZXN0cmFfYWxlYXRvcmlhLCBhZXMoeD1QdXJjaGFzZSwgeT1JbmNvbWUpKSsNCiAgZ2VvbV9wb2ludChhZXMoc2hhcGU9R2VuZGVyKSxjb2xvcj0iYmx1ZSIsIHNpemU9MC41KSsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3I9InJlZCIsIHNpemU9MC41KQ0KDQogZ2dwbG90bHkoY29yX1B1cmNoYXNlKQ0KDQpgYGANCg0KDQpgYGB7cn0NCmNvcih4PW11ZXN0cmFfYWxlYXRvcmlhJE9jY3VwYXRpb24seT15KSAjIENvcnJlbGFjacOzbiBlbnRyZSBPY3VwYWNpw7NuIHkgY29tcHJhcw0KYGBgDQpEZWwgcmVzdWx0YWRvIGFudGVyaW9yIHZlbW9zIHF1ZSBleGlzdGUgdW5hIGNvcnJlbGFjacOzbiBkZSAwLjAwNDM0NTAyMyBlbnRyZSBsYXMgZG9zIHZhcmlhYmxlcywNCmVzbyBzaWduaWZpY2EgcXVlIG5vIGV4aXN0ZSB1bmEgcmVsYWNpw7NuIGVudHJlIGxhIG9jdXBhY2nDs24geSBlbCB2YWxvciBkZSBjb21wcmEgZGUgbG9zIHVzdWFyaW9zLg0KRXN0ZSByZXN1bHRhZG8gc2UgaWx1c3RyYSBlbiBsYSBzaWd1aWVudGUgZ3LDoWZpY2EsIGRvbmRlIG11c3RyYSBsYSBhbGVhdG9yaWRhZCBkZSBhbWJhcyB2YXJpYWJsZXMgDQp5IG5vIHNlIGVuY3VlbnRyYSB1bmEgcmVsYWNpw7NuLg0KDQpgYGB7cn0NCmNvcl9nZW4gPC0gZ2dwbG90KG11ZXN0cmFfYWxlYXRvcmlhLCBhZXMoeD1QdXJjaGFzZSwgeT1PY2N1cGF0aW9uKSkrDQogIGdlb21fcG9pbnQoY29sb3I9ImJsdWUiLCBzaXplPTAuNSkrDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG9yPSJyZWQiLCBzaXplPTAuNSkNCg0KZ2dwbG90bHkoY29yX2dlbikNCg0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg==