1 Introduccion

La inferencia causal es una metodología estadística y analítica que busca identificar relaciones de causa y efecto entre variables, más allá de simples correlaciones. Su objetivo es responder preguntas del tipo “¿qué pasaría si…?”, permitiendo estimar el impacto de una intervención o cambio en una variable sobre otra. Esta técnica es ampliamente utilizada en campos como la economía, la medicina, las ciencias sociales, el marketing y el aprendizaje automático, donde es crucial entender cómo ciertas acciones o políticas influyen en los resultados observados. Por ejemplo, puede emplearse para evaluar el efecto de una política pública, el impacto de un tratamiento médico o el rendimiento de una estrategia comercial.

En este caso, asumiremos que a unos investigadores les interesa saber si el uso de mosquiteros disminuye el riesgo de que una persona contraiga malaria. Para ello han recopilado datos de 1.752 hogares en un país sin nombre y tienen variables relacionadas con los factores ambientales, salud individual y las características de los hogares. Además, este país tiene un programa especial que proporciona mosquiteros gratuitos a los hogares que cumplen con requisitos específicos: para calificar para el programa, debe haber más de 4 miembros del hogar, y el ingreso mensual del hogar debe ser inferior a 700 dólares al mes. Los hogares no se inscriben automáticamente en el programa, y muchos no lo usan. Los datos no son experimentales - los investigadores no tienen control sobre quién usa los mosquiteros, y los hogares individuales toman sus propias decisiones sobre si solicitan mosquiteros gratuitos o compran sus propios mosquiteros, así como si usan los mosquiteros si los tienen.

2 Importamos librerias

library(dagitty)   # Para crear, analizar y evaluar diagramas causales (DAGs)
library(ggdag)     # Extensión de ggplot2 para visualizar y personalizar DAGs
library(tidyverse) # Conjunto de herramientas para manipulación, transformación y análisis de datos
library(ggplot2)   # Para crear gráficos elegantes y personalizables en R
library(MatchIt)   # Para realizar emparejamiento de muestras (matching) en análisis causal
library(XReg) # Salida de modelos de regresion
library(texreg) # Resumen y comparaciones de modelos

3 Modelamos DAG (Diagram Aclyclic Graph)

mosquito_dag <- dagify(
  riesgo_malaria ~ red + ingreso + salud + temperatura + resistencia,
  red  ~ ingreso + salud + temperatura + elegible + hogar,
  elegible ~ ingreso + hogar,
  salud ~ ingreso,
  exposure = "red",
  outcome = "riesgo_malaria",
  coords = list(x = c(riesgo_malaria = 7, red  = 3, ingreso = 4, salud = 5,
                      temperatura = 6, resistencia = 8.5, elegible = 2, hogar = 1),
                y = c(riesgo_malaria = 2, red  = 2, ingreso = 3, salud = 1,
                      temperatura = 3, resistencia = 2, elegible = 3, hogar = 2)),
  labels = c(riesgo_malaria = "Riesgo de malaria", red  = "Mosquitero", ingreso = "Ingreso",
             salud = "Salud", temperatura = "temperaturas nocturnas", 
             resistencia = "Resistencia a insecticidas",
             elegible = "Eligible para el programa", hogar = "Miembros en el hogar")
)

ggdag_status(mosquito_dag, use_labels = "label", text = FALSE) + 
  theme_dag()

Este código en R construye y visualiza un grafo acíclico dirigido (DAG, por sus siglas en inglés) que representa relaciones causales hipotéticas entre variables relacionadas con el riesgo de malaria. Utiliza la función dagify() para definir cómo se cree que las variables están causalmente conectadas: por ejemplo, el uso de mosquiteros (red) depende de factores como ingreso, salud, temperatura, elegibilidad y tamaño del hogar, y a su vez influye en el riesgo de malaria (riesgo_malaria). Se especifican las variables de exposición (red) y resultado (riesgo_malaria), así como las coordenadas para su visualización y etiquetas descriptivas. Finalmente, ggdag_status() genera un gráfico que muestra el estado de las variables en el DAG, útil para analizar supuestos de identificación causal y planear estrategias de estimación.

Cada nodo en el DAG es una columna en la base de datos recogida por los investigadores, e incluye lo siguiente:

Riesgo de malaria (malaria_risk): La probabilidad de que alguien en el hogar se infecte con malaria. Se mide en una escala de 0-100, con valores más altos que indican un mayor riesgo.

Mosquitero ((net and net_num): Una variable binaria que indica si el hogar utiliza mosquiteros.

Elegible para el programa (eligible): Una variable binaria que indica si el hogar es elegible para el programa de mosquiteros gratuitos.

Ingresos (income): Los ingresos mensuales del hogar, en dólares americanos.

Temperaturas nocturnas (temperature): La temperatura media nocturna, en grados centígrados.

Salud (health): La salud de la familia se declarada por sus propios miembros. Medido en una escala de 0-100, con valores más altos que indican mejor salud.

Número en el hogar (household): Número de personas que viven en el hogar.

Resistencia a los insecticidas (resistance): Algunas cepas de mosquitos son más resistentes a los insecticidas y, por lo tanto, suponen un mayor riesgo de infectar a las personas con malaria. Esto se mide en una escala de 0-100, con valores más altos que indican una mayor resistencia.

Según el DAG, el riesgo de contraer malaria es causado por los ingresos, las temperaturas, la salud, la resistencia a los insecticidas y el uso de mosquiteros. Las personas que viven en regiones más cálidas, tienen ingresos más bajos, tienen peor salud, están rodeadas de mosquitos con alta resistencia a los insecticidas y los que no utilizan mosquiteros corren un riesgo mayor de contraer malaria que los que los utilizan. El uso de los mosquiteros se explica por los ingresos, las temperaturas nocturnas, la salud, el número de personas que viven en la vivienda y la elegibilidad para el programa de mosquiteros gratuitos. Las personas que viven en zonas más frescas por la noche, tienen ingresos más altos, mejor salud, tienen más personas en el hogar, y son elegibles para los mosquiteros gratuitos del gobierno, tienen más probabilidades de usar regularmente los mosquiteros. El DAG también muestra que la elegibilidad para el programa de mosquiteros gratuitos se explica por los ingresos y el tamaño de los núcleos familiares, ya que los hogares deben cumplir con umbrales específicos para calificar.

4 Cargamos la base de datos

load("~/Library/Mobile Documents/com~apple~CloudDocs/Cursos/Causal Inference/Causal Inference in R/R for political data science/data/mosquito_nets.rda")

glimpse(mosquito_nets)
Rows: 1,752
Columns: 10
$ id           <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,…
$ net          <lgl> TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, TR…
$ net_num      <dbl> 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, …
$ malaria_risk <dbl> 33, 42, 80, 34, 44, 25, 19, 35, 32, 40, 30, 14, 31, 34, 22, 54, 23, 41, 37, 65, 59, 59, 41, 21, 25, 27…
$ income       <dbl> 781, 974, 502, 671, 728, 1050, 1146, 1093, 1037, 828, 889, 1133, 807, 950, 1195, 594, 936, 816, 962, 4…
$ health       <dbl> 56, 57, 15, 20, 17, 48, 65, 75, 60, 36, 75, 62, 42, 53, 90, 29, 47, 30, 55, 6, 36, 30, 45, 64, 62, 75,…
$ household    <dbl> 2, 4, 3, 5, 5, 1, 3, 5, 3, 3, 6, 3, 4, 3, 1, 5, 2, 1, 2, 6, 5, 4, 3, 7, 3, 4, 3, 3, 2, 2, 6, 5, 4, 4, …
$ eligible     <lgl> FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE…
$ temperature  <dbl> 21.1, 26.5, 25.6, 21.3, 19.2, 25.3, 27.4, 29.8, 27.6, 21.3, 17.4, 18.9, 27.6, 24.0, 24.5, 25.5, 26.1, …
$ resistance   <dbl> 59, 73, 65, 46, 54, 34, 45, 65, 55, 54, 33, 39, 37, 53, 34, 55, 32, 73, 54, 38, 51, 43, 53, 51, 33, 37…

5 Analisamos las independencias condicionales

El comando impliedConditionalIndependencies() se utiliza en el paquete dagitty en R para analizar un DAG (Gráfico Acíclico Dirigido).Este comando identifica las independencias condicionales que deberían existir en el modelo, basándose en su estructura. Teniendo en cuenta que el signo se interpreta como independencia .

Cuando dos variables son independientes incondicionalmente, significa que no tienen relación directa o indirecta, y conocer el valor de una no proporciona información sobre la otra. Por ejemplo, si A y B son incondicionalmente independientes, el conocimiento de A no afecta nuestra predicción sobre B. Por otro lado, dos variables son independientes condicionalmente si dejan de estar relacionadas al conocer el valor de una tercera variable C. En este caso, A y B pueden estar correlacionadas inicialmente, pero esa correlación desaparece al controlar por C.

Primero, verificar independecias condicionales

impliedConditionalIndependencies(mosquito_dag)
elgb _||_ rsst
elgb _||_ rsg_ | ingr, red, sald, tmpr
elgb _||_ sald | ingr
elgb _||_ tmpr
hogr _||_ ingr
hogr _||_ rsst
hogr _||_ rsg_ | ingr, red, sald, tmpr
hogr _||_ sald
hogr _||_ tmpr
ingr _||_ rsst
ingr _||_ tmpr
red _||_ rsst
rsst _||_ sald
rsst _||_ tmpr
sald _||_ tmpr

las independencias incondicionales (como elgb || rsst) significan que, basándonos en la estructura del DAG, las variables “Eligible para el programa” (elegible) y “Resistencia a insecticidas” (resistencia) no tienen una relación directa o indirecta; conocer el estado de una no cambia nada sobre la otra. Por otro lado, las independencias condicionales (como elgb || sald | ingr) indican que, aunque podría haber una relación entre “Elegible” y “Salud”, esta relación desaparece si conocemos “Ingreso”, que actúa como variable de ajuste.

Segundo, validamos correlación entre las variables


# Elegible ⊥ resistencia
cor(mosquito_nets$eligible,mosquito_nets$resistance)
[1] 0.01234798
# Elegible ⊥ temperatura
cor(mosquito_nets$eligible,mosquito_nets$temperature)
[1] -0.02092867
# Miembros Hogar ⊥ Ingreso
cor(mosquito_nets$household,mosquito_nets$income)
[1] 0.008606828
# Miembros Hogar ⊥ Resistencia
cor(mosquito_nets$household,mosquito_nets$resistance)
[1] 0.02036479
# Miembros Hogar ⊥ Salud
cor(mosquito_nets$household,mosquito_nets$health)
[1] 0.00009785337
# Miembros Hogar ⊥ temperatura
cor(mosquito_nets$household,mosquito_nets$temperature)
[1] -0.02355615
#  Ingreso ⊥ resistencias
cor(mosquito_nets$income,mosquito_nets$resistance)
[1] 0.01371297
#  Ingreso ⊥ temperatura
cor(mosquito_nets$income,mosquito_nets$temperature)
[1] 0.1145676
# Red ⊥ resistencia
cor(mosquito_nets$net_num,mosquito_nets$resistance)
[1] 0.01677202
# resistencia ⊥ salud
cor(mosquito_nets$resistance,mosquito_nets$health)
[1] 0.007841029
# resistencia ⊥ temperatura
cor(mosquito_nets$resistance,mosquito_nets$temperature)
[1] -0.02198524
# salud ⊥ temperatura
cor(mosquito_nets$health,mosquito_nets$temperature)
[1] 0.1199855

Podemos que observar que la correlación entre las variables independientes incondicionadas es significativamente bajas. Sugiriendo la ausencia de dependencias entre ellas

6 Evaluamos la independencia condicional

El riesgo de malaria debe ser independiente del número de miembros de la familia, dado que los niveles de salud, ingresos, uso de mosquiteros y temperaturas nocturnas son similares.

No podemos utilizar cor() para probar esta implicación, ya que hay muchas variables en juego, pero podemos utilizar un modelo de regresión para comprobar si el número de miembros del hogar está significativamente relacionado con el riesgo de malaria

# Riesgo de malaria ⊥ Miembros en el hogar| Salud, Ingreso, Uso de la red, Temperatura:
lm(malaria_risk ~ household + health + income + net_num  + temperature, 
   data = mosquito_nets) %>% 
  summary()

Call:
lm(formula = malaria_risk ~ household + health + income + net_num + 
    temperature, data = mosquito_nets)

Residuals:
     Min       1Q   Median       3Q      Max 
-13.1458  -3.9117  -0.5715   3.3512  16.4438 

Coefficients:
              Estimate Std. Error t value            Pr(>|t|)    
(Intercept)  76.206730   0.965788  78.906 <0.0000000000000002 ***
household    -0.015453   0.089311  -0.173               0.863    
health        0.148337   0.010672  13.900 <0.0000000000000002 ***
income       -0.075144   0.001036 -72.563 <0.0000000000000002 ***
net_num     -10.437014   0.266500 -39.163 <0.0000000000000002 ***
temperature   1.005790   0.030964  32.483 <0.0000000000000002 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 5.245 on 1746 degrees of freedom
Multiple R-squared:  0.8852,    Adjusted R-squared:  0.8848 
F-statistic:  2692 on 5 and 1746 DF,  p-value: < 0.00000000000000022

No es significativo (t= −0.17, p = 0.863), lo que significa que los dos son independientes, como se esperaba. Por lo tanto, la variable riesgos de malaria es independiente a la variable miembros del hogar.

Si hay correlaciones sustanciales y significativas entre los nodos que deberían ser independientes, es probable que haya un problema con la especificación del DAG.

Para este ejemplo en concreto hemos validado que no hay dependencia significativas y que nuestro DAG calcula la realizad del modelo.

7 Econtramos el set de ajuste

Existe una vía directa entre el uso de mosquiteros y el riesgo de contraer malaria, pero el efecto no se identifica causalmente debido a otras varias vías abiertas. Podemos dejar que R encuentre los sets de ajuste apropiados automáticamente:

# Comando para evualuar los caminos del DAG
paths(mosquito_dag)
$paths
 [1] "red -> riesgo_malaria"                                         
 [2] "red <- elegible <- ingreso -> riesgo_malaria"                  
 [3] "red <- elegible <- ingreso -> salud -> riesgo_malaria"         
 [4] "red <- hogar -> elegible <- ingreso -> riesgo_malaria"         
 [5] "red <- hogar -> elegible <- ingreso -> salud -> riesgo_malaria"
 [6] "red <- ingreso -> riesgo_malaria"                              
 [7] "red <- ingreso -> salud -> riesgo_malaria"                     
 [8] "red <- salud -> riesgo_malaria"                                
 [9] "red <- salud <- ingreso -> riesgo_malaria"                     
[10] "red <- temperatura -> riesgo_malaria"                          

$open
 [1]  TRUE  TRUE  TRUE FALSE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE

$paths

Muestra todas las rutas (causales, indirectas, espurias) entre variables en el DAG. Esto es útil para visualizar cómo las variables están conectadas directa e indirectamente.

$open

La lista $open indica si las rutas están abiertas o cerradas. Las rutas [4], [5] están cerradas (FALSE), lo que sugiere que están bloqueadas por el control de ciertas variables. Para entender, la ruta 4 está cerrada por la variable elegibles, ya que no permite el flujo de ingreso (variable confusa) a la variable tratamiento a pesar de que si tiene influencia en el outcome.

Una ruta se determina abierta o cerrada dependiendo si permite el flujo causal. Es decir, una ruta es abierta (TRUE) si hay relación entre la exposición (tratamiento) y el resultado (outcome), ya sea por medio de una variable confusor o de forma directa como la ruta 1.

El siguente comando identifica las variables que deben ajustarse para obtener una estimación no sesgada del efecto causal. Las variables de ajuste son aquellas que “cierran” las rutas de confusión, permitiendo analizar el efecto directo entre las variables de interés.

El efecto de confusión ocurre cuando la relación observada entre dos variables está influenciada por una tercera variable (llamada confusor) que afecta tanto a la variable independiente (exposición) como a la variable dependiente (resultado). Este efecto puede distorsionar o sesgar la estimación del efecto causal, llevando a conclusiones incorrectas.

# Variables necesarias para controlar efecto de confusion
adjustmentSets(mosquito_dag)
{ ingreso, salud, temperatura }

Basándose en las relaciones entre todos los nodos del DAG, el ajuste por salud, ingresos y temperatura es suficiente para cerrar todas las puertas traseras e identificar la relación entre el uso de la red y el riesgo de malaria. Es importante destacar que no tenemos que preocuparnos por ninguno de los nodos relacionados con el programa gubernamental de redes gratuitas, ya que esos nodos no están d conectados con el riesgo de malaria. Sólo tenemos que preocuparnos por las relaciones de confusión.

Esto significa que, para estimar correctamente el efecto causal de la exposición (por ejemplo, red) sobre el resultado (por ejemplo, riesgo_malaria), es necesario controlar (o ajustar) por las variables ingreso, salud, y temperatura, ya que estas variables influyen tanto en el tratamiento (red) como en el resultado (malaria), bajo el termino en ingles confounder.

Podemos confirmar esto gráficamente con ggdag_adjustment_set():

ggdag_adjustment_set(mosquito_dag, shadow = TRUE,
                     use_labels = "label", text = FALSE)

8 Estimación ingenua no ajustada

Primero, podemos ver cuál es la relación entre el uso de mosquiteros y el riesgo de malaria en ausencia de cualquier ajuste. Si creamos un cuadro de la distribución del riesgo de malaria entre las personas que usan y no usan mosquiteros, vemos que el riesgo medio es sustancialmente menor entre los que usan mosquiteros

ggplot(mosquito_nets, aes(x = net, y = malaria_risk)) +
  geom_boxplot()

Podemos ejecutar un simple modelo de regresión para medir la diferencia promedio exacta:

model_naive <- lm(malaria_risk ~ net, data = mosquito_nets) 
tbl_regression(model_naive)
G1;H1;Errorh in tbl_regression(model_naive) : 
  could not find function "tbl_regression"
Error during wrapup: not that many frames on the stack
Error: no more error handlers available (recursive errors?); invoking 'abort' restart
g
summary(model_naive)

Call:
lm(formula = malaria_risk ~ net, data = mosquito_nets)

Residuals:
    Min      1Q  Median      3Q     Max 
-26.937  -9.605  -1.937   7.063  55.395 

Coefficients:
            Estimate Std. Error t value            Pr(>|t|)    
(Intercept)  41.9365     0.4049  103.57 <0.0000000000000002 ***
netTRUE     -16.3315     0.6495  -25.15 <0.0000000000000002 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 13.25 on 1750 degrees of freedom
Multiple R-squared:  0.2654,    Adjusted R-squared:  0.265 
F-statistic: 632.3 on 1 and 1750 DF,  p-value: < 0.00000000000000022

Según este modelo, parece que el uso de un mosquitero está asociado con una disminución de 16 puntos en el riesgo de malaria. Sin embargo, este no es el efecto causal. Este es un caso en el que la correlación no es igual a la causalidad. Otros factores como los ingresos, la salud y las temperaturas confunden la relación entre el uso de los mosquiteros y el riesgo

9 Regresiones

Una forma rápida y fácil de tratar de ajustar las variables de confusión es incluirlas como covariables en una regresión lineal. A primera vista, esto tiene sentido intuitivo: el objetivo del ajuste es comparar los nodos de tratamiento y de resultado con los mismos valores de los diversos confusores, y el propósito de la regresión múltiple es explicar la variación del resultado manteniendo constantes las diferentes variables explicativas. Sin embargo, hacer ajustes de confusión con la regresión lineal dará como resultado relaciones causales correctamente identificadas sólo en circunstancias muy específicas. Para que el ajuste basado en la regresión funcione, las relaciones entre todos los nodos de tratamiento, resultado y confusión deben ser lineales, lo cual es difícil de probar y verificar con datos de observación reales. Casi siempre es mejor utilizar una de las otras técnicas de ajuste que se describen a continuación (matching o ponderación de probabilidad inversa), ya que esos métodos no se basan en el supuesto de la linealidad.

model_regression <- lm(malaria_risk ~ net + income + temperature + health,
data = mosquito_nets)
summary(model_regression)

Call:
lm(formula = malaria_risk ~ net + income + temperature + health, 
    data = mosquito_nets)

Residuals:
    Min      1Q  Median      3Q     Max 
-13.143  -3.915  -0.561   3.333  16.461 

Coefficients:
              Estimate Std. Error t value            Pr(>|t|)    
(Intercept)  76.159901   0.926835   82.17 <0.0000000000000002 ***
netTRUE     -10.441932   0.264906  -39.42 <0.0000000000000002 ***
income       -0.075144   0.001035  -72.58 <0.0000000000000002 ***
temperature   1.005855   0.030953   32.50 <0.0000000000000002 ***
health        0.148362   0.010668   13.91 <0.0000000000000002 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 5.244 on 1747 degrees of freedom
Multiple R-squared:  0.8852,    Adjusted R-squared:  0.8849 
F-statistic:  3366 on 4 and 1747 DF,  p-value: < 0.00000000000000022

Según estos resultados, el uso de un mosquitero causa una disminución de 10.44 puntos en el riesgo de paludismo, en promedio. Nótese que debido a que hemos ajustado los confusores, ahora podemos usar justificadamente el lenguaje causal en lugar de hablar simplemente de asociaciones.

Podemos hablar de causalidad después de una regresión lineal cuando se han ajustado los confusores porque estos se incorporan explícitamente como variables adicionales en el modelo. Al incluirlos, se controla estadísticamente su influencia tanto sobre la variable independiente como sobre la dependiente, lo que permite “bloquear” los caminos espurios que podrían generar asociaciones engañosas. Este ajuste se realiza al estimar el efecto de la variable de interés mientras se mantienen constantes los confusores, lo que simula un escenario de intervención. Así, el coeficiente estimado refleja el efecto directo de la variable explicativa sobre la respuesta, justificando el uso de lenguaje causal.

10 Emparejamiento (Matching)

El principal problema de utilizar datos de observación en lugar de datos experimentales es que las personas que utilizaron un mosquitero lo hicieron sin ser asignadas a un grupo de tratamiento. Las características individuales llevaron a las personas a auto-seleccionarse para el tratamiento, lo que hace que las personas que usaron mosquiteros sean esencialmente diferentes de las que no lo hicieron. Gracias al DAG, conocemos muchos de los factores que causaron que la gente eligiera usar los mosquiteros: ingresos, salud y temperatura.

El objetivo del código es emparejar las observaciones del dataset mosquito_nets entre los grupos tratados (personas que recibieron una red antimosquitos, representado por net) y no tratados, basándose en las covariables income, temperature, y health. Este emparejamiento busca reducir el sesgo al balancear las covariables entre los dos grupos para estimar correctamente el efecto del tratamiento (net).

Nota: recordemos que una covariable es una característica o variable que puede influir tanto en el tratamiento como en el resultado que se quiere estudiar.

El emparejamiento en el código que emplea MatchIt se basa en la idea de crear grupos tratados y no tratados que sean comparables entre sí. Esto se logra al seleccionar observaciones de ambos grupos que sean similares en términos de las covariables que podrían confundir la relación entre el tratamiento (net) y el resultado. Este proceso emula un experimento controlado aleatorizado en un estudio observacional

Ejemplo de MatchIt: un ejemplo sencillo para ilustrar el emparejamiento con covariables:

Imagina que estás evaluando si entregar una red antimosquitos (tratamiento) mejora la salud de las personas (resultado). Sin embargo, las personas con mayor ingreso (income) o que viven en zonas con más mosquitos (temperature) podrían tener más probabilidades de recibir la red y también de tener mejor o peor salud, independientemente del tratamiento. Entonces, si comparas directamente a tratados y no tratados, podrías confundir el efecto real de la red con el efecto de esas otras variables.

Para evitar eso, el emparejamiento busca, por ejemplo, una persona tratada con ingreso de $500, temperatura de 28°C y salud regular, y la empareja con una persona no tratada con características muy similares. Así, al comparar sus resultados de salud, puedes atribuir con mayor confianza cualquier diferencia al efecto de la red, porque las otras condiciones están equilibradas. Esto es lo que se busca al emular un experimento aleatorizado en un estudio observacional.

Continuado con el analisis

La similitud se mide utilizando la distancia de Mahalanobis, que calcula la distancia multidimensional entre observaciones considerando las correlaciones y escalas de las covariables. Observaciones más cercanas en esta métrica son consideradas más similares.

# Indicamos semilla de reproducibilidad
set.seed(123)

# Indicamos modelo de emparejamiento
matched <- matchit(net ~ income + temperature + health, # Definir covariables
                   data = mosquito_nets, # Definir conjunto de datos
                   method = "nearest",  # Emperejamiento por vecinos mas cercanos
                   distance = "mahalanobis",  # Tipo de distancia multidimensional
                   replace = TRUE # permitir reutilizacion para emparejamiento
                   )

summary(matched)                  

Call:
matchit(formula = net ~ income + temperature + health, data = mosquito_nets, 
    method = "nearest", distance = "mahalanobis", replace = TRUE)

Summary of Balance for All Data:

Summary of Balance for Matched Data:

Sample Sizes:

Este código realiza un emparejamiento entre personas que recibieron una red antimosquitos y las que no, utilizando el paquete MatchIt en R. Lo hace comparando las covariables income, temperature y health, que podrían influir tanto en la asignación del tratamiento como en el resultado. Usa el método de vecinos más cercanos (method = “nearest”) con la distancia de Mahalanobis, que considera la correlación entre variables, para encontrar pares lo más similares posible. Además, permite que una misma persona no tratada sea reutilizada en varios emparejamientos (replace = TRUE), lo que mejora la calidad del emparejamiento cuando hay pocos controles disponibles. El objetivo es crear grupos comparables y reducir el sesgo para estimar el efecto causal del tratamiento.

En el resultado de Sample Sizestenemos que:

  • Había 1071 controles y 681 tratados antes del emparejamiento.

  • Se utilizaron 436 observaciones del grupo control para emparejar a las 681 del grupo tratado.

  • Dado que replace = TRUE, algunas observaciones del grupo control se reutilizaron para emparejar a varios tratados.

  • 635 observaciones del grupo control no pudieron ser emparejadas. Discarded:

  • No se descartaron observaciones en este análisis.

El valor Matched (ESS), o Tamaño Efectivo de la Muestra (por sus siglas en ingles), representa una estimación ajustada del número de unidades de control emparejadas, teniendo en cuenta que algunas de ellas pueden haber sido reutilizadas varias veces durante el emparejamiento (porque se usó replace = TRUE). Aunque el número real de controles emparejados fue 436, el ESS fue de 320.94, lo que indica que la reutilización de controles reduce la diversidad efectiva del grupo de comparación, y por tanto, el poder estadístico del análisis. Es una forma más precisa de reflejar cuánta “información independiente” se tiene realmente en el grupo de control emparejado

El emparejamiento fue exitoso, logrando balancear las covariables entre los dos grupos, lo que permitirá estimar el efecto del tratamiento (net) con menor sesgo.

Ahora,podemos crear una nueva base de datos basada en este matching con la función match.data(). Observa cómo ahora hay sólo 1117 filas en lugar de 1752, ya que hemos descartado las observaciones no emparejadas. También ahora hay una nueva columna llamada weights. La función matchit() asigna a los pares de observaciones emparejadas diferentes pesos dependiendo de lo cerca o lejos que estén los emparejamientos en un intento de controlar la variación de la distancia. Podemos utilizar estos pesos en nuestro modelo de regresión para mejorar nuestra estimación del efecto causal

mosquito_nets_matched <- match.data(matched) 
glimpse(mosquito_nets_matched) 
Rows: 1,117
Columns: 11
$ id           <dbl> 1, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14, 16, 17, 20, 22, 23, 24, 25, 27, 28, 31, 33, 35, 36, 40, 43, 44, 4…
$ net          <lgl> TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE…
$ net_num      <dbl> 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, …
$ malaria_risk <dbl> 33, 80, 34, 44, 25, 19, 35, 30, 14, 31, 34, 54, 23, 65, 59, 41, 21, 25, 23, 26, 50, 29, 66, 27, 21, 21…
$ income       <dbl> 781, 502, 671, 728, 1050, 1146, 1093, 889, 1133, 807, 950, 594, 936, 431, 655, 896, 1033, 1115, 967, 8…
$ health       <dbl> 56, 15, 20, 17, 48, 65, 75, 75, 62, 42, 53, 29, 47, 6, 30, 45, 64, 62, 71, 37, 37, 53, 22, 67, 40, 53,…
$ household    <dbl> 2, 3, 5, 5, 1, 3, 5, 6, 3, 4, 3, 5, 2, 6, 4, 3, 7, 3, 3, 3, 6, 4, 1, 3, 2, 3, 2, 2, 2, 2, 5, 1, 1, 2, …
$ eligible     <lgl> FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, …
$ temperature  <dbl> 21.1, 25.6, 21.3, 19.2, 25.3, 27.4, 29.8, 17.4, 18.9, 27.6, 24.0, 25.5, 26.1, 26.8, 23.6, 25.9, 23.4, …
$ resistance   <dbl> 59, 65, 46, 54, 34, 45, 65, 33, 39, 37, 53, 55, 32, 38, 43, 53, 51, 33, 52, 71, 59, 52, 84, 31, 63, 53…
$ weights      <dbl> 1.0000000, 0.6402349, 1.0000000, 0.6402349, 1.2804699, 1.0000000, 1.9207048, 0.6402349, 1.0000000, 1.0…

Por ultimo,podemos hacer una regresión usando los datos emparejados:


# Indicamos modelo lineal
model_matched <- lm(malaria_risk ~ net, data = mosquito_nets_matched,
weights = weights)

# Vemos resumen estadistico
summary(model_matched)

Call:
lm(formula = malaria_risk ~ net, data = mosquito_nets_matched, 
    weights = weights)

Weighted Residuals:
    Min      1Q  Median      3Q     Max 
-38.295  -7.605  -2.365   5.395  55.395 

Coefficients:
            Estimate Std. Error t value            Pr(>|t|)    
(Intercept)  36.0896     0.5971   60.45 <0.0000000000000002 ***
netTRUE     -10.4846     0.7647  -13.71 <0.0000000000000002 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 12.47 on 1115 degrees of freedom
Multiple R-squared:  0.1443,    Adjusted R-squared:  0.1435 
F-statistic:   188 on 1 and 1115 DF,  p-value: < 0.00000000000000022

Según estos resultados, el uso de un mosquitero causa una disminución de 10.48 puntos en el riesgo de malaria, en promedio. Una vez más, podemos utilizar el lenguaje causal ahora porque hemos ajustado los confusores al hacer la comparación, identificando así el camino causal entre el uso de mosquiteros y el riesgo de malaria.

11 Ponderación de probabilidad inversa

Una desventaja del uso de matching es que desechamos mucha información: las observaciones no coincidentes se descartan, y el tamaño de nuestra muestra puede reducirse significativamente. El emparejamiento también tiende a ser muy riguroso, ya que cada observación tratada debe ser emparejada con una (o más) observaciones no tratadas. Aunque que algunas observaciones no tratadas están en realidad muy cerca de las observaciones tratadas, aún así se descartan porque fueron superadas por observaciones que tienen una distancia ligeramente menor.

En lugar de desechar datos potencialmente útiles, podemos utilizar otros métodos para crear coincidencias que sean menos rigurosas pero más informativas. Un método común en epidemiología y bioestadística es la ponderación de probabilidad inversa (IPW, en inglés). En la IPW, a cada observación se le asigna un peso basado en lo bien que su asignación real al tratamiento coincide con la probabilidad prevista del tratamiento, y esos pesos se utilizan luego en un modelo de regresión para estimar el efecto causal del tratamiento en el resultado.

Primero, podemos ajustar los factores de confusión de nuestro mosquitero y el ejemplo de riesgo de malaria usando una ponderación de probabilidad inversa.

Para ello, usamos una regresión logística para predecir la propensión a usar un mosquitero usando los ingresos, la temperatura y la salud. Luego usamos los puntajes de propensión para calcular los pesos de probabilidad inversa usando esta fórmula:

\[ \frac{\text{Mosquitero}}{\text{Propensión}} + \frac{1 - \text{Mosquitero}}{1 - \text{Propensión}} \]

# Creamos regresion logistica
model_mosquito_net <- glm(net ~ income + temperature + health,
                          data = mosquito_nets, family = binomial(link = "logit"))



# Agregamos ipw
mosquito_nets_ipw <- mosquito_nets %>% # Indicamos el df
  mutate(propensity = predict(model_mosquito_net, type = "response"), #Aplicamos el modelo logistico, con las probabilidades
         ipw = (net_num / propensity) + (1 - net_num) / (1 - propensity)) # creamos columna ipw


# Vemos resultados
print(mosquito_nets_ipw)

Este código ajusta un modelo de regresión logística para estimar la probabilidad de que una persona reciba un mosquitero (net) en función de sus ingresos, temperatura y salud, y luego utiliza esas probabilidades (propensiones) para calcular pesos de ponderación por la inversa de la probabilidad de tratamiento (IPW). Estos pesos permiten corregir posibles sesgos de selección al comparar grupos tratados y no tratados, asignando mayor peso a las observaciones que recibieron un tratamiento inesperado según sus características. Así, se busca simular un escenario más parecido a un experimento aleatorio y estimar de forma más justa el efecto del tratamiento.

Segundo, ahora que tenemos pesos de probabilidad inversa, podemos usarlos en una regresión:

# Indicamos modelo lineal
model_ipw <- lm(malaria_risk ~ net, data = mosquito_nets_ipw,
weights = ipw)

# Vemos resultados
summary(model_ipw)

Call:
lm(formula = malaria_risk ~ net, data = mosquito_nets_ipw, weights = ipw)

Weighted Residuals:
    Min      1Q  Median      3Q     Max 
-45.705 -14.622  -4.924  10.791 162.642 

Coefficients:
            Estimate Std. Error t value            Pr(>|t|)    
(Intercept)  39.6788     0.4684   84.71 <0.0000000000000002 ***
netTRUE     -10.1312     0.6583  -15.39 <0.0000000000000002 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 19.54 on 1750 degrees of freedom
Multiple R-squared:  0.1192,    Adjusted R-squared:  0.1187 
F-statistic: 236.8 on 1 and 1750 DF,  p-value: < 0.00000000000000022

Según este modelo de IPW, el uso de un mosquitero causa una disminución de 10.13 puntos en el riesgo de malaria, en promedio. Una vez más, podemos utilizar con seguridad el lenguaje causal porque hemos identificado el camino causal entre el uso de mosquiteros y el riesgo de malaria teniendo en cuenta los factores de confusión en los pesos de probabilidad inversos.

12 Comparando todos los métodos

Ahora que hemos ejecutado varios modelos de regresión que se ajustan a los factores de confusión de diferentes maneras, podemos comparar los resultados todos juntos. La ingenua estimación de -16 parece ser definitivamente una sobreestimación: después de ajustar con la regresión, el matching y la ponderación de probabilidad inversa, el efecto causal del uso de un mosquitero en el riesgo de malaria es consistentemente de alrededor de -10. Asumiendo que nuestro DAG está correcto, encontramos con éxito un efecto causal a partir de datos no experimentales y observacionales.

texreg::screenreg(list(model_naive, model_regression,
                       model_matched, model_ipw),
                  custom.model.names = c("Naive", "Regression",
                                         "Matching", "IPW"))

===============================================================
             Naive        Regression   Matching     IPW        
---------------------------------------------------------------
(Intercept)    41.94 ***    76.16 ***    36.09 ***    39.68 ***
               (0.40)       (0.93)       (0.60)       (0.47)   
netTRUE       -16.33 ***   -10.44 ***   -10.48 ***   -10.13 ***
               (0.65)       (0.26)       (0.76)       (0.66)   
income                      -0.08 ***                          
                            (0.00)                             
temperature                  1.01 ***                          
                            (0.03)                             
health                       0.15 ***                          
                            (0.01)                             
---------------------------------------------------------------
R^2             0.27         0.89         0.14         0.12    
Adj. R^2        0.27         0.88         0.14         0.12    
Num. obs.    1752         1752         1117         1752       
===============================================================
*** p < 0.001; ** p < 0.01; * p < 0.05
LS0tCnRpdGxlOiAiSW5mZXJlbmNpYSBjYXVzYWwgYXBsaWNhZGEiCmF1dGhvcjogIkp1YW4gSm9zw6kgRWNoZXZlcnJ5IgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUgICAgICAgICAgIyBBY3RpdmEgdGFibGEgZGUgY29udGVuaWRvCiAgICB0b2NfZGVwdGg6IDMgICAgICAgIyBQcm9mdW5kaWRhZCBkZSBsYSBUT0MgKHBvciBkZWZlY3RvIGVzIDMpCiAgICB0b2NfZmxvYXQ6IHRydWUgICAgIyBUYWJsYSBkZSBjb250ZW5pZG8gZmxvdGFudGUKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZSAgIyBOdW1lcmEgc2VjY2lvbmVzCiAgICBmaWdfd2lkdGg6IDcgICAgICAgIyBBbmNobyBwcmVkZXRlcm1pbmFkbyBkZSBmaWd1cmFzIChlbiBwdWxnYWRhcykKICAgIGZpZ19oZWlnaHQ6IDUgICAgICAjIEFsdG8gcHJlZGV0ZXJtaW5hZG8gZGUgZmlndXJhcyAoZW4gcHVsZ2FkYXMpCiAgICAjdGhlbWU6IHVuaXRlZCAgICAgICMgVGVtYSB2aXN1YWwgZGUgQm9vdHN0cmFwIChvcGNpb25hbCkKICAgIGhpZ2hsaWdodDogdGFuZ28gICAgIyBUZW1hIGRlIHJlc2FsdGFkbyBkZSBjw7NkaWdvCi0tLQoKYGBge3Igbm8gdmlzaWJsZSwgaW5jbHVkZT1GQUxTRX0Kb3B0aW9ucyhzY2lwZW4gPSA5OTkpCgpgYGAKCiMgSW50cm9kdWNjaW9uCgpMYSBpbmZlcmVuY2lhIGNhdXNhbCBlcyB1bmEgbWV0b2RvbG9nw61hIGVzdGFkw61zdGljYSB5IGFuYWzDrXRpY2EgcXVlIGJ1c2NhIGlkZW50aWZpY2FyIHJlbGFjaW9uZXMgZGUgY2F1c2EgeSBlZmVjdG8gZW50cmUgdmFyaWFibGVzLCBtw6FzIGFsbMOhIGRlIHNpbXBsZXMgY29ycmVsYWNpb25lcy4gU3Ugb2JqZXRpdm8gZXMgcmVzcG9uZGVyIHByZWd1bnRhcyBkZWwgdGlwbyDigJzCv3F1w6kgcGFzYXLDrWEgc2nigKY/4oCdLCBwZXJtaXRpZW5kbyBlc3RpbWFyIGVsIGltcGFjdG8gZGUgdW5hIGludGVydmVuY2nDs24gbyBjYW1iaW8gZW4gdW5hIHZhcmlhYmxlIHNvYnJlIG90cmEuIEVzdGEgdMOpY25pY2EgZXMgYW1wbGlhbWVudGUgdXRpbGl6YWRhIGVuIGNhbXBvcyBjb21vIGxhIGVjb25vbcOtYSwgbGEgbWVkaWNpbmEsIGxhcyBjaWVuY2lhcyBzb2NpYWxlcywgZWwgbWFya2V0aW5nIHkgZWwgYXByZW5kaXphamUgYXV0b23DoXRpY28sIGRvbmRlIGVzIGNydWNpYWwgZW50ZW5kZXIgY8OzbW8gY2llcnRhcyBhY2Npb25lcyBvIHBvbMOtdGljYXMgaW5mbHV5ZW4gZW4gbG9zIHJlc3VsdGFkb3Mgb2JzZXJ2YWRvcy4gUG9yIGVqZW1wbG8sIHB1ZWRlIGVtcGxlYXJzZSBwYXJhIGV2YWx1YXIgZWwgZWZlY3RvIGRlIHVuYSBwb2zDrXRpY2EgcMO6YmxpY2EsIGVsIGltcGFjdG8gZGUgdW4gdHJhdGFtaWVudG8gbcOpZGljbyBvIGVsIHJlbmRpbWllbnRvIGRlIHVuYSBlc3RyYXRlZ2lhIGNvbWVyY2lhbC4KCkVuIGVzdGUgY2FzbywgYXN1bWlyZW1vcyBxdWUgYSB1bm9zIGludmVzdGlnYWRvcmVzIGxlcyBpbnRlcmVzYSBzYWJlciBzaSBlbCB1c28gZGUgbW9zcXVpdGVyb3MgZGlzbWludXllIGVsIHJpZXNnbyBkZSBxdWUgdW5hIHBlcnNvbmEgY29udHJhaWdhIG1hbGFyaWEuIFBhcmEgZWxsbyBoYW4gcmVjb3BpbGFkbyBkYXRvcyBkZSAxLjc1MiBob2dhcmVzIGVuIHVuIHBhw61zIHNpbiBub21icmUgeSB0aWVuZW4gdmFyaWFibGVzIHJlbGFjaW9uYWRhcyBjb24gbG9zIGZhY3RvcmVzIGFtYmllbnRhbGVzLCBzYWx1ZCBpbmRpdmlkdWFsIHkgbGFzIGNhcmFjdGVyw61zdGljYXMgZGUgbG9zIGhvZ2FyZXMuIEFkZW3DoXMsIGVzdGUgcGHDrXMgdGllbmUgdW4gcHJvZ3JhbWEgZXNwZWNpYWwgcXVlIHByb3BvcmNpb25hIG1vc3F1aXRlcm9zIGdyYXR1aXRvcyBhIGxvcyBob2dhcmVzIHF1ZSBjdW1wbGVuIGNvbiByZXF1aXNpdG9zIGVzcGVjw61maWNvczogcGFyYSBjYWxpZmljYXIgcGFyYSBlbCBwcm9ncmFtYSwgZGViZSBoYWJlciBtw6FzIGRlIDQgbWllbWJyb3MgZGVsIGhvZ2FyLCB5IGVsIGluZ3Jlc28gbWVuc3VhbCBkZWwgaG9nYXIgZGViZSBzZXIgaW5mZXJpb3IgYSA3MDAgZMOzbGFyZXMgYWwgbWVzLiBMb3MgaG9nYXJlcyBubyBzZSBpbnNjcmliZW4gYXV0b23DoXRpY2FtZW50ZSBlbiBlbCBwcm9ncmFtYSwgeSBtdWNob3Mgbm8gbG8gdXNhbi4gTG9zIGRhdG9zIG5vIHNvbiBleHBlcmltZW50YWxlcyAtIGxvcyBpbnZlc3RpZ2Fkb3JlcyBubyB0aWVuZW4gY29udHJvbCBzb2JyZSBxdWnDqW4gdXNhIGxvcyBtb3NxdWl0ZXJvcywgeSBsb3MgaG9nYXJlcyBpbmRpdmlkdWFsZXMgdG9tYW4gc3VzIHByb3BpYXMgZGVjaXNpb25lcyBzb2JyZSBzaSBzb2xpY2l0YW4gbW9zcXVpdGVyb3MgZ3JhdHVpdG9zIG8gY29tcHJhbiBzdXMgcHJvcGlvcyBtb3NxdWl0ZXJvcywgYXPDrSBjb21vIHNpIHVzYW4gbG9zIG1vc3F1aXRlcm9zIHNpIGxvcyB0aWVuZW4uCgojIEltcG9ydGFtb3MgbGlicmVyaWFzCgpgYGB7ciBMaWJyZXJpYXMgbmVjZXNhcmlhcywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShkYWdpdHR5KSAgICMgUGFyYSBjcmVhciwgYW5hbGl6YXIgeSBldmFsdWFyIGRpYWdyYW1hcyBjYXVzYWxlcyAoREFHcykKbGlicmFyeShnZ2RhZykgICAgICMgRXh0ZW5zacOzbiBkZSBnZ3Bsb3QyIHBhcmEgdmlzdWFsaXphciB5IHBlcnNvbmFsaXphciBEQUdzCmxpYnJhcnkodGlkeXZlcnNlKSAjIENvbmp1bnRvIGRlIGhlcnJhbWllbnRhcyBwYXJhIG1hbmlwdWxhY2nDs24sIHRyYW5zZm9ybWFjacOzbiB5IGFuw6FsaXNpcyBkZSBkYXRvcwpsaWJyYXJ5KGdncGxvdDIpICAgIyBQYXJhIGNyZWFyIGdyw6FmaWNvcyBlbGVnYW50ZXMgeSBwZXJzb25hbGl6YWJsZXMgZW4gUgpsaWJyYXJ5KE1hdGNoSXQpICAgIyBQYXJhIHJlYWxpemFyIGVtcGFyZWphbWllbnRvIGRlIG11ZXN0cmFzIChtYXRjaGluZykgZW4gYW7DoWxpc2lzIGNhdXNhbApsaWJyYXJ5KFhSZWcpICMgU2FsaWRhIGRlIG1vZGVsb3MgZGUgcmVncmVzaW9uCmxpYnJhcnkodGV4cmVnKSAjIFJlc3VtZW4geSBjb21wYXJhY2lvbmVzIGRlIG1vZGVsb3MKCgpgYGAKCiMgTW9kZWxhbW9zIERBRyAoRGlhZ3JhbSBBY2x5Y2xpYyBHcmFwaCkKCmBgYHtyIGZpZy5oZWlnaHQ9MTUsIGZpZy53aWR0aD0xNX0KbW9zcXVpdG9fZGFnIDwtIGRhZ2lmeSgKICByaWVzZ29fbWFsYXJpYSB+IHJlZCArIGluZ3Jlc28gKyBzYWx1ZCArIHRlbXBlcmF0dXJhICsgcmVzaXN0ZW5jaWEsCiAgcmVkICB+IGluZ3Jlc28gKyBzYWx1ZCArIHRlbXBlcmF0dXJhICsgZWxlZ2libGUgKyBob2dhciwKICBlbGVnaWJsZSB+IGluZ3Jlc28gKyBob2dhciwKICBzYWx1ZCB+IGluZ3Jlc28sCiAgZXhwb3N1cmUgPSAicmVkIiwKICBvdXRjb21lID0gInJpZXNnb19tYWxhcmlhIiwKICBjb29yZHMgPSBsaXN0KHggPSBjKHJpZXNnb19tYWxhcmlhID0gNywgcmVkICA9IDMsIGluZ3Jlc28gPSA0LCBzYWx1ZCA9IDUsCiAgICAgICAgICAgICAgICAgICAgICB0ZW1wZXJhdHVyYSA9IDYsIHJlc2lzdGVuY2lhID0gOC41LCBlbGVnaWJsZSA9IDIsIGhvZ2FyID0gMSksCiAgICAgICAgICAgICAgICB5ID0gYyhyaWVzZ29fbWFsYXJpYSA9IDIsIHJlZCAgPSAyLCBpbmdyZXNvID0gMywgc2FsdWQgPSAxLAogICAgICAgICAgICAgICAgICAgICAgdGVtcGVyYXR1cmEgPSAzLCByZXNpc3RlbmNpYSA9IDIsIGVsZWdpYmxlID0gMywgaG9nYXIgPSAyKSksCiAgbGFiZWxzID0gYyhyaWVzZ29fbWFsYXJpYSA9ICJSaWVzZ28gZGUgbWFsYXJpYSIsIHJlZCAgPSAiTW9zcXVpdGVybyIsIGluZ3Jlc28gPSAiSW5ncmVzbyIsCiAgICAgICAgICAgICBzYWx1ZCA9ICJTYWx1ZCIsIHRlbXBlcmF0dXJhID0gInRlbXBlcmF0dXJhcyBub2N0dXJuYXMiLCAKICAgICAgICAgICAgIHJlc2lzdGVuY2lhID0gIlJlc2lzdGVuY2lhIGEgaW5zZWN0aWNpZGFzIiwKICAgICAgICAgICAgIGVsZWdpYmxlID0gIkVsaWdpYmxlIHBhcmEgZWwgcHJvZ3JhbWEiLCBob2dhciA9ICJNaWVtYnJvcyBlbiBlbCBob2dhciIpCikKCmdnZGFnX3N0YXR1cyhtb3NxdWl0b19kYWcsIHVzZV9sYWJlbHMgPSAibGFiZWwiLCB0ZXh0ID0gRkFMU0UpICsgCiAgdGhlbWVfZGFnKCkKYGBgCgpFc3RlIGPDs2RpZ28gZW4gUiBjb25zdHJ1eWUgeSB2aXN1YWxpemEgdW4gZ3JhZm8gYWPDrWNsaWNvIGRpcmlnaWRvIChEQUcsIHBvciBzdXMgc2lnbGFzIGVuIGluZ2zDqXMpIHF1ZSByZXByZXNlbnRhIHJlbGFjaW9uZXMgY2F1c2FsZXMgaGlwb3TDqXRpY2FzIGVudHJlIHZhcmlhYmxlcyByZWxhY2lvbmFkYXMgY29uIGVsIHJpZXNnbyBkZSBtYWxhcmlhLiBVdGlsaXphIGxhIGZ1bmNpw7NuIGRhZ2lmeSgpIHBhcmEgZGVmaW5pciBjw7NtbyBzZSBjcmVlIHF1ZSBsYXMgdmFyaWFibGVzIGVzdMOhbiBjYXVzYWxtZW50ZSBjb25lY3RhZGFzOiBwb3IgZWplbXBsbywgZWwgdXNvIGRlIG1vc3F1aXRlcm9zIChyZWQpIGRlcGVuZGUgZGUgZmFjdG9yZXMgY29tbyBpbmdyZXNvLCBzYWx1ZCwgdGVtcGVyYXR1cmEsIGVsZWdpYmlsaWRhZCB5IHRhbWHDsW8gZGVsIGhvZ2FyLCB5IGEgc3UgdmV6IGluZmx1eWUgZW4gZWwgcmllc2dvIGRlIG1hbGFyaWEgKHJpZXNnb19tYWxhcmlhKS4gU2UgZXNwZWNpZmljYW4gbGFzIHZhcmlhYmxlcyBkZSBleHBvc2ljacOzbiAocmVkKSB5IHJlc3VsdGFkbyAocmllc2dvX21hbGFyaWEpLCBhc8OtIGNvbW8gbGFzIGNvb3JkZW5hZGFzIHBhcmEgc3UgdmlzdWFsaXphY2nDs24geSBldGlxdWV0YXMgZGVzY3JpcHRpdmFzLiBGaW5hbG1lbnRlLCBnZ2RhZ19zdGF0dXMoKSBnZW5lcmEgdW4gZ3LDoWZpY28gcXVlIG11ZXN0cmEgZWwgZXN0YWRvIGRlIGxhcyB2YXJpYWJsZXMgZW4gZWwgREFHLCDDunRpbCBwYXJhIGFuYWxpemFyIHN1cHVlc3RvcyBkZSBpZGVudGlmaWNhY2nDs24gY2F1c2FsIHkgcGxhbmVhciBlc3RyYXRlZ2lhcyBkZSBlc3RpbWFjacOzbi4KCkNhZGEgbm9kbyBlbiBlbCBEQUcgZXMgdW5hIGNvbHVtbmEgZW4gbGEgYmFzZSBkZSBkYXRvcyByZWNvZ2lkYSBwb3IgbG9zIGludmVzdGlnYWRvcmVzLCBlIGluY2x1eWUgbG8gc2lndWllbnRlOgoKKipSaWVzZ28gZGUgbWFsYXJpYSAobWFsYXJpYV9yaXNrKSoqOiBMYSBwcm9iYWJpbGlkYWQgZGUgcXVlIGFsZ3VpZW4gZW4gZWwgaG9nYXIgc2UgaW5mZWN0ZSBjb24gbWFsYXJpYS4gU2UgbWlkZSBlbiB1bmEgZXNjYWxhIGRlIDAtMTAwLCBjb24gdmFsb3JlcyBtw6FzIGFsdG9zIHF1ZSBpbmRpY2FuIHVuIG1heW9yIHJpZXNnby4KCioqTW9zcXVpdGVybyAoKG5ldCBhbmQgbmV0X251bSkqKjogVW5hIHZhcmlhYmxlIGJpbmFyaWEgcXVlIGluZGljYSBzaSBlbCBob2dhciB1dGlsaXphIG1vc3F1aXRlcm9zLgoKKipFbGVnaWJsZSBwYXJhIGVsIHByb2dyYW1hIChlbGlnaWJsZSkqKjogVW5hIHZhcmlhYmxlIGJpbmFyaWEgcXVlIGluZGljYSBzaSBlbCBob2dhciBlcyBlbGVnaWJsZSBwYXJhIGVsIHByb2dyYW1hIGRlIG1vc3F1aXRlcm9zIGdyYXR1aXRvcy4KCioqSW5ncmVzb3MgKGluY29tZSkqKjogTG9zIGluZ3Jlc29zIG1lbnN1YWxlcyBkZWwgaG9nYXIsIGVuIGTDs2xhcmVzIGFtZXJpY2Fub3MuCgoqKlRlbXBlcmF0dXJhcyBub2N0dXJuYXMgKHRlbXBlcmF0dXJlKSoqOiBMYSB0ZW1wZXJhdHVyYSBtZWRpYSBub2N0dXJuYSwgZW4gZ3JhZG9zIGNlbnTDrWdyYWRvcy4KCioqU2FsdWQgKGhlYWx0aCkqKjogTGEgc2FsdWQgZGUgbGEgZmFtaWxpYSBzZSBkZWNsYXJhZGEgcG9yIHN1cyBwcm9waW9zIG1pZW1icm9zLiBNZWRpZG8gZW4gdW5hIGVzY2FsYSBkZSAwLTEwMCwgY29uIHZhbG9yZXMgbcOhcyBhbHRvcyBxdWUgaW5kaWNhbiBtZWpvciBzYWx1ZC4KCioqTsO6bWVybyBlbiBlbCBob2dhciAoaG91c2Vob2xkKSoqOiBOw7ptZXJvIGRlIHBlcnNvbmFzIHF1ZSB2aXZlbiBlbiBlbCBob2dhci4KCioqUmVzaXN0ZW5jaWEgYSBsb3MgaW5zZWN0aWNpZGFzIChyZXNpc3RhbmNlKSoqOiBBbGd1bmFzIGNlcGFzIGRlIG1vc3F1aXRvcyBzb24gbcOhcyByZXNpc3RlbnRlcyBhIGxvcyBpbnNlY3RpY2lkYXMgeSwgcG9yIGxvIHRhbnRvLCBzdXBvbmVuIHVuIG1heW9yIHJpZXNnbyBkZSBpbmZlY3RhciBhIGxhcyBwZXJzb25hcyBjb24gbWFsYXJpYS4gRXN0byBzZSBtaWRlIGVuIHVuYSBlc2NhbGEgZGUgMC0xMDAsIGNvbiB2YWxvcmVzIG3DoXMgYWx0b3MgcXVlIGluZGljYW4gdW5hIG1heW9yIHJlc2lzdGVuY2lhLgoKU2Vnw7puIGVsIERBRywgZWwgcmllc2dvIGRlIGNvbnRyYWVyIG1hbGFyaWEgZXMgY2F1c2FkbyBwb3IgbG9zIGluZ3Jlc29zLCBsYXMgdGVtcGVyYXR1cmFzLCBsYSBzYWx1ZCwgbGEgcmVzaXN0ZW5jaWEgYSBsb3MgaW5zZWN0aWNpZGFzIHkgZWwgdXNvIGRlIG1vc3F1aXRlcm9zLiBMYXMgcGVyc29uYXMgcXVlIHZpdmVuIGVuIHJlZ2lvbmVzIG3DoXMgY8OhbGlkYXMsIHRpZW5lbiBpbmdyZXNvcyBtw6FzIGJham9zLCB0aWVuZW4gcGVvciBzYWx1ZCwgZXN0w6FuIHJvZGVhZGFzIGRlIG1vc3F1aXRvcyBjb24gYWx0YSByZXNpc3RlbmNpYSBhIGxvcyBpbnNlY3RpY2lkYXMgeSBsb3MgcXVlIG5vIHV0aWxpemFuIG1vc3F1aXRlcm9zIGNvcnJlbiB1biByaWVzZ28gbWF5b3IgZGUgY29udHJhZXIgbWFsYXJpYSBxdWUgbG9zIHF1ZSBsb3MgdXRpbGl6YW4uIEVsIHVzbyBkZSBsb3MgbW9zcXVpdGVyb3Mgc2UgZXhwbGljYSBwb3IgbG9zIGluZ3Jlc29zLCBsYXMgdGVtcGVyYXR1cmFzIG5vY3R1cm5hcywgbGEgc2FsdWQsIGVsIG7Dum1lcm8gZGUgcGVyc29uYXMgcXVlIHZpdmVuIGVuIGxhIHZpdmllbmRhIHkgbGEgZWxlZ2liaWxpZGFkIHBhcmEgZWwgcHJvZ3JhbWEgZGUgbW9zcXVpdGVyb3MgZ3JhdHVpdG9zLiBMYXMgcGVyc29uYXMgcXVlIHZpdmVuIGVuIHpvbmFzIG3DoXMgZnJlc2NhcyBwb3IgbGEgbm9jaGUsIHRpZW5lbiBpbmdyZXNvcyBtw6FzIGFsdG9zLCBtZWpvciBzYWx1ZCwgdGllbmVuIG3DoXMgcGVyc29uYXMgZW4gZWwgaG9nYXIsIHkgc29uIGVsZWdpYmxlcyBwYXJhIGxvcyBtb3NxdWl0ZXJvcyBncmF0dWl0b3MgZGVsIGdvYmllcm5vLCB0aWVuZW4gbcOhcyBwcm9iYWJpbGlkYWRlcyBkZSB1c2FyIHJlZ3VsYXJtZW50ZSBsb3MgbW9zcXVpdGVyb3MuIEVsIERBRyB0YW1iacOpbiBtdWVzdHJhIHF1ZSBsYSBlbGVnaWJpbGlkYWQgcGFyYSBlbCBwcm9ncmFtYSBkZSBtb3NxdWl0ZXJvcyBncmF0dWl0b3Mgc2UgZXhwbGljYSBwb3IgbG9zIGluZ3Jlc29zIHkgZWwgdGFtYcOxbyBkZSBsb3MgbsO6Y2xlb3MgZmFtaWxpYXJlcywgeWEgcXVlIGxvcyBob2dhcmVzIGRlYmVuIGN1bXBsaXIgY29uIHVtYnJhbGVzIGVzcGVjw61maWNvcyBwYXJhIGNhbGlmaWNhci4KCiMgQ2FyZ2Ftb3MgbGEgYmFzZSBkZSBkYXRvcwoKYGBge3J9CmxvYWQoIn4vTGlicmFyeS9Nb2JpbGUgRG9jdW1lbnRzL2NvbX5hcHBsZX5DbG91ZERvY3MvQ3Vyc29zL0NhdXNhbCBJbmZlcmVuY2UvQ2F1c2FsIEluZmVyZW5jZSBpbiBSL1IgZm9yIHBvbGl0aWNhbCBkYXRhIHNjaWVuY2UvZGF0YS9tb3NxdWl0b19uZXRzLnJkYSIpCgpnbGltcHNlKG1vc3F1aXRvX25ldHMpCmBgYAoKIyBBbmFsaXNhbW9zIGxhcyBpbmRlcGVuZGVuY2lhcyBjb25kaWNpb25hbGVzCgpFbCBjb21hbmRvIGBpbXBsaWVkQ29uZGl0aW9uYWxJbmRlcGVuZGVuY2llcygpYCBzZSB1dGlsaXphIGVuIGVsIHBhcXVldGUgZGFnaXR0eSBlbiBSIHBhcmEgYW5hbGl6YXIgdW4gREFHIChHcsOhZmljbyBBY8OtY2xpY28gRGlyaWdpZG8pLkVzdGUgY29tYW5kbyBpZGVudGlmaWNhIGxhcyBpbmRlcGVuZGVuY2lhcyBjb25kaWNpb25hbGVzIHF1ZSBkZWJlcsOtYW4gZXhpc3RpciBlbiBlbCBtb2RlbG8sIGJhc8OhbmRvc2UgZW4gc3UgZXN0cnVjdHVyYS4gVGVuaWVuZG8gZW4gY3VlbnRhIHF1ZSBlbCBzaWdubyBzZSBpbnRlcnByZXRhIGNvbW8gaW5kZXBlbmRlbmNpYSBg4oqlYC4KCkN1YW5kbyBkb3MgdmFyaWFibGVzIHNvbiBpbmRlcGVuZGllbnRlcyBpbmNvbmRpY2lvbmFsbWVudGUsIHNpZ25pZmljYSBxdWUgbm8gdGllbmVuIHJlbGFjacOzbiBkaXJlY3RhIG8gaW5kaXJlY3RhLCB5IGNvbm9jZXIgZWwgdmFsb3IgZGUgdW5hIG5vIHByb3BvcmNpb25hIGluZm9ybWFjacOzbiBzb2JyZSBsYSBvdHJhLiBQb3IgZWplbXBsbywgc2kgQSB5IEIgc29uIGluY29uZGljaW9uYWxtZW50ZSBpbmRlcGVuZGllbnRlcywgZWwgY29ub2NpbWllbnRvIGRlIEEgbm8gYWZlY3RhIG51ZXN0cmEgcHJlZGljY2nDs24gc29icmUgQi4gUG9yIG90cm8gbGFkbywgZG9zIHZhcmlhYmxlcyBzb24gaW5kZXBlbmRpZW50ZXMgY29uZGljaW9uYWxtZW50ZSBzaSBkZWphbiBkZSBlc3RhciByZWxhY2lvbmFkYXMgYWwgY29ub2NlciBlbCB2YWxvciBkZSB1bmEgdGVyY2VyYSB2YXJpYWJsZSBDLiBFbiBlc3RlIGNhc28sIEEgeSBCIHB1ZWRlbiBlc3RhciBjb3JyZWxhY2lvbmFkYXMgaW5pY2lhbG1lbnRlLCBwZXJvIGVzYSBjb3JyZWxhY2nDs24gZGVzYXBhcmVjZSBhbCBjb250cm9sYXIgcG9yIEMuCgoqKlByaW1lcm8qKiwgdmVyaWZpY2FyIGluZGVwZW5kZWNpYXMgY29uZGljaW9uYWxlcwoKYGBge3J9CmltcGxpZWRDb25kaXRpb25hbEluZGVwZW5kZW5jaWVzKG1vc3F1aXRvX2RhZykKYGBgCgpsYXMgaW5kZXBlbmRlbmNpYXMgaW5jb25kaWNpb25hbGVzIChjb21vIGVsZ2IgKlx8XHwqIHJzc3QpIHNpZ25pZmljYW4gcXVlLCBiYXPDoW5kb25vcyBlbiBsYSBlc3RydWN0dXJhIGRlbCBEQUcsIGxhcyB2YXJpYWJsZXMgIkVsaWdpYmxlIHBhcmEgZWwgcHJvZ3JhbWEiIChlbGVnaWJsZSkgeSAiUmVzaXN0ZW5jaWEgYSBpbnNlY3RpY2lkYXMiIChyZXNpc3RlbmNpYSkgbm8gdGllbmVuIHVuYSByZWxhY2nDs24gZGlyZWN0YSBvIGluZGlyZWN0YTsgY29ub2NlciBlbCBlc3RhZG8gZGUgdW5hIG5vIGNhbWJpYSBuYWRhIHNvYnJlIGxhIG90cmEuIFBvciBvdHJvIGxhZG8sIGxhcyBpbmRlcGVuZGVuY2lhcyBjb25kaWNpb25hbGVzIChjb21vIGVsZ2IgKlx8XHwqIHNhbGQgXHwgaW5ncikgaW5kaWNhbiBxdWUsIGF1bnF1ZSBwb2Ryw61hIGhhYmVyIHVuYSByZWxhY2nDs24gZW50cmUgIkVsZWdpYmxlIiB5ICJTYWx1ZCIsIGVzdGEgcmVsYWNpw7NuIGRlc2FwYXJlY2Ugc2kgY29ub2NlbW9zICJJbmdyZXNvIiwgcXVlIGFjdMO6YSBjb21vIHZhcmlhYmxlIGRlIGFqdXN0ZS4KCioqU2VndW5kbyoqLCB2YWxpZGFtb3MgY29ycmVsYWNpw7NuIGVudHJlIGxhcyB2YXJpYWJsZXMKCmBgYHtyfQoKIyBFbGVnaWJsZSDiiqUgcmVzaXN0ZW5jaWEKY29yKG1vc3F1aXRvX25ldHMkZWxpZ2libGUsbW9zcXVpdG9fbmV0cyRyZXNpc3RhbmNlKQoKIyBFbGVnaWJsZSDiiqUgdGVtcGVyYXR1cmEKY29yKG1vc3F1aXRvX25ldHMkZWxpZ2libGUsbW9zcXVpdG9fbmV0cyR0ZW1wZXJhdHVyZSkKCiMgTWllbWJyb3MgSG9nYXIg4oqlIEluZ3Jlc28KY29yKG1vc3F1aXRvX25ldHMkaG91c2Vob2xkLG1vc3F1aXRvX25ldHMkaW5jb21lKQoKIyBNaWVtYnJvcyBIb2dhciDiiqUgUmVzaXN0ZW5jaWEKY29yKG1vc3F1aXRvX25ldHMkaG91c2Vob2xkLG1vc3F1aXRvX25ldHMkcmVzaXN0YW5jZSkKCiMgTWllbWJyb3MgSG9nYXIg4oqlIFNhbHVkCmNvcihtb3NxdWl0b19uZXRzJGhvdXNlaG9sZCxtb3NxdWl0b19uZXRzJGhlYWx0aCkKCiMgTWllbWJyb3MgSG9nYXIg4oqlIHRlbXBlcmF0dXJhCmNvcihtb3NxdWl0b19uZXRzJGhvdXNlaG9sZCxtb3NxdWl0b19uZXRzJHRlbXBlcmF0dXJlKQoKIyAgSW5ncmVzbyDiiqUgcmVzaXN0ZW5jaWFzCmNvcihtb3NxdWl0b19uZXRzJGluY29tZSxtb3NxdWl0b19uZXRzJHJlc2lzdGFuY2UpCgojICBJbmdyZXNvIOKKpSB0ZW1wZXJhdHVyYQpjb3IobW9zcXVpdG9fbmV0cyRpbmNvbWUsbW9zcXVpdG9fbmV0cyR0ZW1wZXJhdHVyZSkKCiMgUmVkIOKKpSByZXNpc3RlbmNpYQpjb3IobW9zcXVpdG9fbmV0cyRuZXRfbnVtLG1vc3F1aXRvX25ldHMkcmVzaXN0YW5jZSkKCiMgcmVzaXN0ZW5jaWEg4oqlIHNhbHVkCmNvcihtb3NxdWl0b19uZXRzJHJlc2lzdGFuY2UsbW9zcXVpdG9fbmV0cyRoZWFsdGgpCgojIHJlc2lzdGVuY2lhIOKKpSB0ZW1wZXJhdHVyYQpjb3IobW9zcXVpdG9fbmV0cyRyZXNpc3RhbmNlLG1vc3F1aXRvX25ldHMkdGVtcGVyYXR1cmUpCgojIHNhbHVkIOKKpSB0ZW1wZXJhdHVyYQpjb3IobW9zcXVpdG9fbmV0cyRoZWFsdGgsbW9zcXVpdG9fbmV0cyR0ZW1wZXJhdHVyZSkKCmBgYAoKUG9kZW1vcyBxdWUgb2JzZXJ2YXIgcXVlIGxhIGNvcnJlbGFjacOzbiBlbnRyZSBsYXMgdmFyaWFibGVzIGluZGVwZW5kaWVudGVzIGluY29uZGljaW9uYWRhcyBlcyBzaWduaWZpY2F0aXZhbWVudGUgYmFqYXMuIFN1Z2lyaWVuZG8gbGEgYXVzZW5jaWEgZGUgZGVwZW5kZW5jaWFzIGVudHJlIGVsbGFzCgojIEV2YWx1YW1vcyBsYSBpbmRlcGVuZGVuY2lhIGNvbmRpY2lvbmFsCgpFbCByaWVzZ28gZGUgbWFsYXJpYSBkZWJlIHNlciBpbmRlcGVuZGllbnRlIGRlbCBuw7ptZXJvIGRlIG1pZW1icm9zIGRlIGxhIGZhbWlsaWEsIGRhZG8gcXVlIGxvcyBuaXZlbGVzIGRlIHNhbHVkLCBpbmdyZXNvcywgdXNvIGRlIG1vc3F1aXRlcm9zIHkgdGVtcGVyYXR1cmFzIG5vY3R1cm5hcyBzb24gc2ltaWxhcmVzLgoKTm8gcG9kZW1vcyB1dGlsaXphciBjb3IoKSBwYXJhIHByb2JhciBlc3RhIGltcGxpY2FjacOzbiwgeWEgcXVlIGhheSBtdWNoYXMgdmFyaWFibGVzIGVuIGp1ZWdvLCBwZXJvIHBvZGVtb3MgdXRpbGl6YXIgdW4gbW9kZWxvIGRlIHJlZ3Jlc2nDs24gcGFyYSBjb21wcm9iYXIgc2kgZWwgbsO6bWVybyBkZSBtaWVtYnJvcyBkZWwgaG9nYXIgZXN0w6Egc2lnbmlmaWNhdGl2YW1lbnRlIHJlbGFjaW9uYWRvIGNvbiBlbCByaWVzZ28gZGUgbWFsYXJpYQoKYGBge3J9CiMgUmllc2dvIGRlIG1hbGFyaWEg4oqlIE1pZW1icm9zIGVuIGVsIGhvZ2FyfCBTYWx1ZCwgSW5ncmVzbywgVXNvIGRlIGxhIHJlZCwgVGVtcGVyYXR1cmE6CmxtKG1hbGFyaWFfcmlzayB+IGhvdXNlaG9sZCArIGhlYWx0aCArIGluY29tZSArIG5ldF9udW0gICsgdGVtcGVyYXR1cmUsIAogICBkYXRhID0gbW9zcXVpdG9fbmV0cykgJT4lIAogIHN1bW1hcnkoKQpgYGAKCk5vIGVzIHNpZ25pZmljYXRpdm8gKHQ9IOKIkjAuMTcsIHAgPSAwLjg2MyksIGxvIHF1ZSBzaWduaWZpY2EgcXVlIGxvcyBkb3Mgc29uIGluZGVwZW5kaWVudGVzLCBjb21vIHNlIGVzcGVyYWJhLiBQb3IgbG8gdGFudG8sIGxhIHZhcmlhYmxlIHJpZXNnb3MgZGUgbWFsYXJpYSBlcyBpbmRlcGVuZGllbnRlIGEgbGEgdmFyaWFibGUgbWllbWJyb3MgZGVsIGhvZ2FyLgoKU2kgaGF5IGNvcnJlbGFjaW9uZXMgc3VzdGFuY2lhbGVzIHkgc2lnbmlmaWNhdGl2YXMgZW50cmUgbG9zIG5vZG9zIHF1ZSBkZWJlcsOtYW4gc2VyIGluZGVwZW5kaWVudGVzLCBlcyBwcm9iYWJsZSBxdWUgaGF5YSB1biBwcm9ibGVtYSBjb24gbGEgZXNwZWNpZmljYWNpw7NuIGRlbCBEQUcuCgpQYXJhIGVzdGUgZWplbXBsbyBlbiBjb25jcmV0byBoZW1vcyB2YWxpZGFkbyBxdWUgbm8gaGF5IGRlcGVuZGVuY2lhIHNpZ25pZmljYXRpdmFzIHkgcXVlIG51ZXN0cm8gREFHIGNhbGN1bGEgbGEgcmVhbGl6YWQgZGVsIG1vZGVsby4KCiMgRWNvbnRyYW1vcyBlbCBzZXQgZGUgYWp1c3RlCgpFeGlzdGUgdW5hIHbDrWEgZGlyZWN0YSBlbnRyZSBlbCB1c28gZGUgbW9zcXVpdGVyb3MgeSBlbCByaWVzZ28gZGUgY29udHJhZXIgbWFsYXJpYSwgcGVybyBlbCBlZmVjdG8gbm8gc2UgaWRlbnRpZmljYSBjYXVzYWxtZW50ZSBkZWJpZG8gYSBvdHJhcyB2YXJpYXMgdsOtYXMgYWJpZXJ0YXMuIFBvZGVtb3MgZGVqYXIgcXVlIFIgZW5jdWVudHJlIGxvcyBzZXRzIGRlIGFqdXN0ZSBhcHJvcGlhZG9zIGF1dG9tw6F0aWNhbWVudGU6CgpgYGB7cn0KIyBDb21hbmRvIHBhcmEgZXZ1YWx1YXIgbG9zIGNhbWlub3MgZGVsIERBRwpwYXRocyhtb3NxdWl0b19kYWcpCgpgYGAKCioqXCRwYXRocyoqCgpNdWVzdHJhIHRvZGFzIGxhcyBydXRhcyAoY2F1c2FsZXMsIGluZGlyZWN0YXMsIGVzcHVyaWFzKSBlbnRyZSB2YXJpYWJsZXMgZW4gZWwgREFHLiBFc3RvIGVzIMO6dGlsIHBhcmEgdmlzdWFsaXphciBjw7NtbyBsYXMgdmFyaWFibGVzIGVzdMOhbiBjb25lY3RhZGFzIGRpcmVjdGEgZSBpbmRpcmVjdGFtZW50ZS4KCioqXCRvcGVuKioKCkxhIGxpc3RhIFwkb3BlbiBpbmRpY2Egc2kgbGFzIHJ1dGFzIGVzdMOhbiBhYmllcnRhcyBvIGNlcnJhZGFzLiBMYXMgcnV0YXMgWzRdLCBbNV0gZXN0w6FuIGNlcnJhZGFzIChGQUxTRSksIGxvIHF1ZSBzdWdpZXJlIHF1ZSBlc3TDoW4gYmxvcXVlYWRhcyBwb3IgZWwgY29udHJvbCBkZSBjaWVydGFzIHZhcmlhYmxlcy4gUGFyYSBlbnRlbmRlciwgbGEgcnV0YSA0IGVzdMOhIGNlcnJhZGEgcG9yIGxhIHZhcmlhYmxlIGVsZWdpYmxlcywgeWEgcXVlIG5vIHBlcm1pdGUgZWwgZmx1am8gZGUgaW5ncmVzbyAodmFyaWFibGUgY29uZnVzYSkgYSBsYSB2YXJpYWJsZSB0cmF0YW1pZW50byBhIHBlc2FyIGRlIHF1ZSBzaSB0aWVuZSBpbmZsdWVuY2lhIGVuIGVsIG91dGNvbWUuCgpVbmEgcnV0YSBzZSBkZXRlcm1pbmEgYWJpZXJ0YSBvIGNlcnJhZGEgZGVwZW5kaWVuZG8gc2kgcGVybWl0ZSBlbCBmbHVqbyBjYXVzYWwuIEVzIGRlY2lyLCB1bmEgcnV0YSBlcyBhYmllcnRhIChUUlVFKSBzaSBoYXkgcmVsYWNpw7NuIGVudHJlIGxhIGV4cG9zaWNpw7NuICh0cmF0YW1pZW50bykgeSBlbCByZXN1bHRhZG8gKG91dGNvbWUpLCB5YSBzZWEgcG9yIG1lZGlvIGRlIHVuYSB2YXJpYWJsZSBjb25mdXNvciBvIGRlIGZvcm1hIGRpcmVjdGEgY29tbyBsYSBydXRhIDEuCgpFbCBzaWd1ZW50ZSBjb21hbmRvIGlkZW50aWZpY2EgbGFzIHZhcmlhYmxlcyBxdWUgZGViZW4gYWp1c3RhcnNlIHBhcmEgb2J0ZW5lciB1bmEgZXN0aW1hY2nDs24gbm8gc2VzZ2FkYSBkZWwgZWZlY3RvIGNhdXNhbC4gTGFzIHZhcmlhYmxlcyBkZSBhanVzdGUgc29uIGFxdWVsbGFzIHF1ZSAiY2llcnJhbiIgbGFzIHJ1dGFzIGRlIGNvbmZ1c2nDs24sIHBlcm1pdGllbmRvIGFuYWxpemFyIGVsIGVmZWN0byBkaXJlY3RvIGVudHJlIGxhcyB2YXJpYWJsZXMgZGUgaW50ZXLDqXMuCgpFbCBlZmVjdG8gZGUgY29uZnVzacOzbiBvY3VycmUgY3VhbmRvIGxhIHJlbGFjacOzbiBvYnNlcnZhZGEgZW50cmUgZG9zIHZhcmlhYmxlcyBlc3TDoSBpbmZsdWVuY2lhZGEgcG9yIHVuYSB0ZXJjZXJhIHZhcmlhYmxlIChsbGFtYWRhIGNvbmZ1c29yKSBxdWUgYWZlY3RhIHRhbnRvIGEgbGEgdmFyaWFibGUgaW5kZXBlbmRpZW50ZSAoZXhwb3NpY2nDs24pIGNvbW8gYSBsYSB2YXJpYWJsZSBkZXBlbmRpZW50ZSAocmVzdWx0YWRvKS4gRXN0ZSBlZmVjdG8gcHVlZGUgZGlzdG9yc2lvbmFyIG8gc2VzZ2FyIGxhIGVzdGltYWNpw7NuIGRlbCBlZmVjdG8gY2F1c2FsLCBsbGV2YW5kbyBhIGNvbmNsdXNpb25lcyBpbmNvcnJlY3Rhcy4KCmBgYHtyfQojIFZhcmlhYmxlcyBuZWNlc2FyaWFzIHBhcmEgY29udHJvbGFyIGVmZWN0byBkZSBjb25mdXNpb24KYWRqdXN0bWVudFNldHMobW9zcXVpdG9fZGFnKQpgYGAKCkJhc8OhbmRvc2UgZW4gbGFzIHJlbGFjaW9uZXMgZW50cmUgdG9kb3MgbG9zIG5vZG9zIGRlbCBEQUcsIGVsIGFqdXN0ZSBwb3Igc2FsdWQsIGluZ3Jlc29zIHkgdGVtcGVyYXR1cmEgZXMgc3VmaWNpZW50ZSBwYXJhIGNlcnJhciB0b2RhcyBsYXMgcHVlcnRhcyB0cmFzZXJhcyBlIGlkZW50aWZpY2FyIGxhIHJlbGFjacOzbiBlbnRyZSBlbCB1c28gZGUgbGEgcmVkIHkgZWwgcmllc2dvIGRlIG1hbGFyaWEuIEVzIGltcG9ydGFudGUgZGVzdGFjYXIgcXVlIG5vIHRlbmVtb3MgcXVlIHByZW9jdXBhcm5vcyBwb3IgbmluZ3VubyBkZSBsb3Mgbm9kb3MgcmVsYWNpb25hZG9zIGNvbiBlbCBwcm9ncmFtYSBndWJlcm5hbWVudGFsIGRlIHJlZGVzIGdyYXR1aXRhcywgeWEgcXVlIGVzb3Mgbm9kb3Mgbm8gZXN0w6FuIGQgY29uZWN0YWRvcyBjb24gZWwgcmllc2dvIGRlIG1hbGFyaWEuIFPDs2xvIHRlbmVtb3MgcXVlIHByZW9jdXBhcm5vcyBwb3IgbGFzIHJlbGFjaW9uZXMgZGUgY29uZnVzacOzbi4KCkVzdG8gc2lnbmlmaWNhIHF1ZSwgcGFyYSBlc3RpbWFyIGNvcnJlY3RhbWVudGUgZWwgZWZlY3RvIGNhdXNhbCBkZSBsYSBleHBvc2ljacOzbiAocG9yIGVqZW1wbG8sIHJlZCkgc29icmUgZWwgcmVzdWx0YWRvIChwb3IgZWplbXBsbywgcmllc2dvX21hbGFyaWEpLCBlcyBuZWNlc2FyaW8gY29udHJvbGFyIChvIGFqdXN0YXIpIHBvciBsYXMgdmFyaWFibGVzIGluZ3Jlc28sIHNhbHVkLCB5IHRlbXBlcmF0dXJhLCB5YSBxdWUgZXN0YXMgdmFyaWFibGVzIGluZmx1eWVuIHRhbnRvIGVuIGVsIHRyYXRhbWllbnRvIChyZWQpIGNvbW8gZW4gZWwgcmVzdWx0YWRvIChtYWxhcmlhKSwgYmFqbyBlbCB0ZXJtaW5vIGVuIGluZ2xlcyBgY29uZm91bmRlcmAuCgpQb2RlbW9zIGNvbmZpcm1hciBlc3RvIGdyw6FmaWNhbWVudGUgY29uIGdnZGFnX2FkanVzdG1lbnRfc2V0KCk6CgpgYGB7ciBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTB9CmdnZGFnX2FkanVzdG1lbnRfc2V0KG1vc3F1aXRvX2RhZywgc2hhZG93ID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgdXNlX2xhYmVscyA9ICJsYWJlbCIsIHRleHQgPSBGQUxTRSkKYGBgCgojIEVzdGltYWNpw7NuIGluZ2VudWEgbm8gYWp1c3RhZGEKCioqUHJpbWVybyoqLCBwb2RlbW9zIHZlciBjdcOhbCBlcyBsYSByZWxhY2nDs24gZW50cmUgZWwgdXNvIGRlIG1vc3F1aXRlcm9zIHkgZWwgcmllc2dvIGRlIG1hbGFyaWEgZW4gYXVzZW5jaWEgZGUgY3VhbHF1aWVyIGFqdXN0ZS4gU2kgY3JlYW1vcyB1biBjdWFkcm8gZGUgbGEgZGlzdHJpYnVjacOzbiBkZWwgcmllc2dvIGRlIG1hbGFyaWEgZW50cmUgbGFzIHBlcnNvbmFzIHF1ZSB1c2FuIHkgbm8gdXNhbiBtb3NxdWl0ZXJvcywgdmVtb3MgcXVlIGVsIHJpZXNnbyBtZWRpbyBlcyBzdXN0YW5jaWFsbWVudGUgbWVub3IgZW50cmUgbG9zIHF1ZSB1c2FuIG1vc3F1aXRlcm9zCgpgYGB7cn0KZ2dwbG90KG1vc3F1aXRvX25ldHMsIGFlcyh4ID0gbmV0LCB5ID0gbWFsYXJpYV9yaXNrKSkgKwogIGdlb21fYm94cGxvdCgpCgpgYGAKClBvZGVtb3MgZWplY3V0YXIgdW4gc2ltcGxlIG1vZGVsbyBkZSByZWdyZXNpw7NuIHBhcmEgbWVkaXIgbGEgZGlmZXJlbmNpYSBwcm9tZWRpbyBleGFjdGE6CgpgYGB7cn0KbW9kZWxfbmFpdmUgPC0gbG0obWFsYXJpYV9yaXNrIH4gbmV0LCBkYXRhID0gbW9zcXVpdG9fbmV0cykgCnRibF9yZWdyZXNzaW9uKG1vZGVsX25haXZlKQpzdW1tYXJ5KG1vZGVsX25haXZlKQpgYGAKClNlZ8O6biBlc3RlIG1vZGVsbywgcGFyZWNlIHF1ZSBlbCB1c28gZGUgdW4gbW9zcXVpdGVybyBlc3TDoSBhc29jaWFkbyBjb24gdW5hIGRpc21pbnVjacOzbiBkZSAxNiBwdW50b3MgZW4gZWwgcmllc2dvIGRlIG1hbGFyaWEuIFNpbiBlbWJhcmdvLCBlc3RlIG5vIGVzIGVsIGVmZWN0byBjYXVzYWwuIEVzdGUgZXMgdW4gY2FzbyBlbiBlbCBxdWUgbGEgY29ycmVsYWNpw7NuIG5vIGVzIGlndWFsIGEgbGEgY2F1c2FsaWRhZC4gT3Ryb3MgZmFjdG9yZXMgY29tbyBsb3MgaW5ncmVzb3MsIGxhIHNhbHVkIHkgbGFzIHRlbXBlcmF0dXJhcyBjb25mdW5kZW4gbGEgcmVsYWNpw7NuIGVudHJlIGVsIHVzbyBkZSBsb3MgbW9zcXVpdGVyb3MgeSBlbCByaWVzZ28KCiMgUmVncmVzaW9uZXMKClVuYSBmb3JtYSByw6FwaWRhIHkgZsOhY2lsIGRlIHRyYXRhciBkZSBhanVzdGFyIGxhcyB2YXJpYWJsZXMgZGUgY29uZnVzacOzbiBlcyBpbmNsdWlybGFzIGNvbW8gY292YXJpYWJsZXMgZW4gdW5hIHJlZ3Jlc2nDs24gbGluZWFsLiBBIHByaW1lcmEgdmlzdGEsIGVzdG8gdGllbmUgc2VudGlkbyBpbnR1aXRpdm86IGVsIG9iamV0aXZvIGRlbCBhanVzdGUgZXMgY29tcGFyYXIgbG9zIG5vZG9zIGRlIHRyYXRhbWllbnRvIHkgZGUgcmVzdWx0YWRvIGNvbiBsb3MgbWlzbW9zIHZhbG9yZXMgZGUgbG9zIGRpdmVyc29zIGNvbmZ1c29yZXMsIHkgZWwgcHJvcMOzc2l0byBkZSBsYSByZWdyZXNpw7NuIG3Dumx0aXBsZSBlcyBleHBsaWNhciBsYSB2YXJpYWNpw7NuIGRlbCByZXN1bHRhZG8gbWFudGVuaWVuZG8gY29uc3RhbnRlcyBsYXMgZGlmZXJlbnRlcyB2YXJpYWJsZXMgZXhwbGljYXRpdmFzLiBTaW4gZW1iYXJnbywgaGFjZXIgYWp1c3RlcyBkZSBjb25mdXNpw7NuIGNvbiBsYSByZWdyZXNpw7NuIGxpbmVhbCBkYXLDoSBjb21vIHJlc3VsdGFkbyByZWxhY2lvbmVzIGNhdXNhbGVzIGNvcnJlY3RhbWVudGUgaWRlbnRpZmljYWRhcyBzw7NsbyBlbiBjaXJjdW5zdGFuY2lhcyBtdXkgZXNwZWPDrWZpY2FzLiBQYXJhIHF1ZSBlbCBhanVzdGUgYmFzYWRvIGVuIGxhIHJlZ3Jlc2nDs24gZnVuY2lvbmUsIGxhcyByZWxhY2lvbmVzIGVudHJlIHRvZG9zIGxvcyBub2RvcyBkZSB0cmF0YW1pZW50bywgcmVzdWx0YWRvIHkgY29uZnVzacOzbiBkZWJlbiBzZXIgbGluZWFsZXMsIGxvIGN1YWwgZXMgZGlmw61jaWwgZGUgcHJvYmFyIHkgdmVyaWZpY2FyIGNvbiBkYXRvcyBkZSBvYnNlcnZhY2nDs24gcmVhbGVzLiBDYXNpIHNpZW1wcmUgZXMgbWVqb3IgdXRpbGl6YXIgdW5hIGRlIGxhcyBvdHJhcyB0w6ljbmljYXMgZGUgYWp1c3RlIHF1ZSBzZSBkZXNjcmliZW4gYSBjb250aW51YWNpw7NuIChtYXRjaGluZyBvIHBvbmRlcmFjacOzbiBkZSBwcm9iYWJpbGlkYWQgaW52ZXJzYSksIHlhIHF1ZSBlc29zIG3DqXRvZG9zIG5vIHNlIGJhc2FuIGVuIGVsIHN1cHVlc3RvIGRlIGxhIGxpbmVhbGlkYWQuCgpgYGB7cn0KbW9kZWxfcmVncmVzc2lvbiA8LSBsbShtYWxhcmlhX3Jpc2sgfiBuZXQgKyBpbmNvbWUgKyB0ZW1wZXJhdHVyZSArIGhlYWx0aCwKZGF0YSA9IG1vc3F1aXRvX25ldHMpCnN1bW1hcnkobW9kZWxfcmVncmVzc2lvbikKYGBgCgpTZWfDum4gZXN0b3MgcmVzdWx0YWRvcywgZWwgdXNvIGRlIHVuIG1vc3F1aXRlcm8gY2F1c2EgdW5hIGRpc21pbnVjacOzbiBkZSAxMC40NCBwdW50b3MgZW4gZWwgcmllc2dvIGRlIHBhbHVkaXNtbywgZW4gcHJvbWVkaW8uIE7Ds3Rlc2UgcXVlIGRlYmlkbyBhIHF1ZSBoZW1vcyBhanVzdGFkbyBsb3MgY29uZnVzb3JlcywgYWhvcmEgcG9kZW1vcyB1c2FyIGp1c3RpZmljYWRhbWVudGUgZWwgbGVuZ3VhamUgY2F1c2FsIGVuIGx1Z2FyIGRlIGhhYmxhciBzaW1wbGVtZW50ZSBkZSBhc29jaWFjaW9uZXMuCgpQb2RlbW9zIGhhYmxhciBkZSBjYXVzYWxpZGFkIGRlc3B1w6lzIGRlIHVuYSByZWdyZXNpw7NuIGxpbmVhbCBjdWFuZG8gc2UgaGFuIGFqdXN0YWRvIGxvcyBjb25mdXNvcmVzIHBvcnF1ZSBlc3RvcyBzZSBpbmNvcnBvcmFuIGV4cGzDrWNpdGFtZW50ZSBjb21vIHZhcmlhYmxlcyBhZGljaW9uYWxlcyBlbiBlbCBtb2RlbG8uIEFsIGluY2x1aXJsb3MsIHNlIGNvbnRyb2xhIGVzdGFkw61zdGljYW1lbnRlIHN1IGluZmx1ZW5jaWEgdGFudG8gc29icmUgbGEgdmFyaWFibGUgaW5kZXBlbmRpZW50ZSBjb21vIHNvYnJlIGxhIGRlcGVuZGllbnRlLCBsbyBxdWUgcGVybWl0ZSDigJxibG9xdWVhcuKAnSBsb3MgY2FtaW5vcyBlc3B1cmlvcyBxdWUgcG9kcsOtYW4gZ2VuZXJhciBhc29jaWFjaW9uZXMgZW5nYcOxb3Nhcy4gRXN0ZSBhanVzdGUgc2UgcmVhbGl6YSBhbCBlc3RpbWFyIGVsIGVmZWN0byBkZSBsYSB2YXJpYWJsZSBkZSBpbnRlcsOpcyBtaWVudHJhcyBzZSBtYW50aWVuZW4gY29uc3RhbnRlcyBsb3MgY29uZnVzb3JlcywgbG8gcXVlIHNpbXVsYSB1biBlc2NlbmFyaW8gZGUgaW50ZXJ2ZW5jacOzbi4gQXPDrSwgZWwgY29lZmljaWVudGUgZXN0aW1hZG8gcmVmbGVqYSBlbCBlZmVjdG8gZGlyZWN0byBkZSBsYSB2YXJpYWJsZSBleHBsaWNhdGl2YSBzb2JyZSBsYSByZXNwdWVzdGEsIGp1c3RpZmljYW5kbyBlbCB1c28gZGUgbGVuZ3VhamUgY2F1c2FsLgoKIyBFbXBhcmVqYW1pZW50byAoTWF0Y2hpbmcpCgpFbCBwcmluY2lwYWwgcHJvYmxlbWEgZGUgdXRpbGl6YXIgZGF0b3MgZGUgb2JzZXJ2YWNpw7NuIGVuIGx1Z2FyIGRlIGRhdG9zIGV4cGVyaW1lbnRhbGVzIGVzIHF1ZSBsYXMgcGVyc29uYXMgcXVlIHV0aWxpemFyb24gdW4gbW9zcXVpdGVybyBsbyBoaWNpZXJvbiBzaW4gc2VyIGFzaWduYWRhcyBhIHVuIGdydXBvIGRlIHRyYXRhbWllbnRvLiBMYXMgY2FyYWN0ZXLDrXN0aWNhcyBpbmRpdmlkdWFsZXMgbGxldmFyb24gYSBsYXMgcGVyc29uYXMgYSBhdXRvLXNlbGVjY2lvbmFyc2UgcGFyYSBlbCB0cmF0YW1pZW50bywgbG8gcXVlIGhhY2UgcXVlIGxhcyBwZXJzb25hcyBxdWUgdXNhcm9uIG1vc3F1aXRlcm9zIHNlYW4gZXNlbmNpYWxtZW50ZSBkaWZlcmVudGVzIGRlIGxhcyBxdWUgbm8gbG8gaGljaWVyb24uIEdyYWNpYXMgYWwgREFHLCBjb25vY2Vtb3MgbXVjaG9zIGRlIGxvcyBmYWN0b3JlcyBxdWUgY2F1c2Fyb24gcXVlIGxhIGdlbnRlIGVsaWdpZXJhIHVzYXIgbG9zIG1vc3F1aXRlcm9zOiBpbmdyZXNvcywgc2FsdWQgeSB0ZW1wZXJhdHVyYS4KCkVsIG9iamV0aXZvIGRlbCBjw7NkaWdvIGVzIGVtcGFyZWphciBsYXMgb2JzZXJ2YWNpb25lcyBkZWwgZGF0YXNldCBtb3NxdWl0b19uZXRzIGVudHJlIGxvcyBncnVwb3MgdHJhdGFkb3MgKHBlcnNvbmFzIHF1ZSByZWNpYmllcm9uIHVuYSByZWQgYW50aW1vc3F1aXRvcywgcmVwcmVzZW50YWRvIHBvciBuZXQpIHkgbm8gdHJhdGFkb3MsIGJhc8OhbmRvc2UgZW4gbGFzIGNvdmFyaWFibGVzIGluY29tZSwgdGVtcGVyYXR1cmUsIHkgaGVhbHRoLiBFc3RlIGVtcGFyZWphbWllbnRvIGJ1c2NhIHJlZHVjaXIgZWwgc2VzZ28gYWwgYmFsYW5jZWFyIGxhcyBjb3ZhcmlhYmxlcyBlbnRyZSBsb3MgZG9zIGdydXBvcyBwYXJhIGVzdGltYXIgY29ycmVjdGFtZW50ZSBlbCBlZmVjdG8gZGVsIHRyYXRhbWllbnRvIChuZXQpLgoKKipOb3RhKio6IHJlY29yZGVtb3MgcXVlIHVuYSBjb3ZhcmlhYmxlIGVzIHVuYSBjYXJhY3RlcsOtc3RpY2EgbyB2YXJpYWJsZSBxdWUgcHVlZGUgaW5mbHVpciB0YW50byBlbiBlbCB0cmF0YW1pZW50byBjb21vIGVuIGVsIHJlc3VsdGFkbyBxdWUgc2UgcXVpZXJlIGVzdHVkaWFyLgoKRWwgZW1wYXJlamFtaWVudG8gZW4gZWwgY8OzZGlnbyBxdWUgZW1wbGVhIE1hdGNoSXQgc2UgYmFzYSBlbiBsYSBpZGVhIGRlIGNyZWFyIGdydXBvcyB0cmF0YWRvcyB5IG5vIHRyYXRhZG9zIHF1ZSBzZWFuIGNvbXBhcmFibGVzIGVudHJlIHPDrS4gRXN0byBzZSBsb2dyYSBhbCBzZWxlY2Npb25hciBvYnNlcnZhY2lvbmVzIGRlIGFtYm9zIGdydXBvcyBxdWUgc2VhbiBzaW1pbGFyZXMgZW4gdMOpcm1pbm9zIGRlIGxhcyBjb3ZhcmlhYmxlcyBxdWUgcG9kcsOtYW4gY29uZnVuZGlyIGxhIHJlbGFjacOzbiBlbnRyZSBlbCB0cmF0YW1pZW50byAobmV0KSB5IGVsIHJlc3VsdGFkby4gRXN0ZSBwcm9jZXNvIGVtdWxhIHVuIGV4cGVyaW1lbnRvIGNvbnRyb2xhZG8gYWxlYXRvcml6YWRvIGVuIHVuIGVzdHVkaW8gb2JzZXJ2YWNpb25hbAoKKipFamVtcGxvIGRlIE1hdGNoSXQqKjogdW4gZWplbXBsbyBzZW5jaWxsbyBwYXJhIGlsdXN0cmFyIGVsIGVtcGFyZWphbWllbnRvIGNvbiBjb3ZhcmlhYmxlczoKCkltYWdpbmEgcXVlIGVzdMOhcyBldmFsdWFuZG8gc2kgZW50cmVnYXIgdW5hIHJlZCBhbnRpbW9zcXVpdG9zICh0cmF0YW1pZW50bykgbWVqb3JhIGxhIHNhbHVkIGRlIGxhcyBwZXJzb25hcyAocmVzdWx0YWRvKS4gU2luIGVtYmFyZ28sIGxhcyBwZXJzb25hcyBjb24gbWF5b3IgaW5ncmVzbyAoaW5jb21lKSBvIHF1ZSB2aXZlbiBlbiB6b25hcyBjb24gbcOhcyBtb3NxdWl0b3MgKHRlbXBlcmF0dXJlKSBwb2Ryw61hbiB0ZW5lciBtw6FzIHByb2JhYmlsaWRhZGVzIGRlIHJlY2liaXIgbGEgcmVkIHkgdGFtYmnDqW4gZGUgdGVuZXIgbWVqb3IgbyBwZW9yIHNhbHVkLCBpbmRlcGVuZGllbnRlbWVudGUgZGVsIHRyYXRhbWllbnRvLiBFbnRvbmNlcywgc2kgY29tcGFyYXMgZGlyZWN0YW1lbnRlIGEgdHJhdGFkb3MgeSBubyB0cmF0YWRvcywgcG9kcsOtYXMgY29uZnVuZGlyIGVsIGVmZWN0byByZWFsIGRlIGxhIHJlZCBjb24gZWwgZWZlY3RvIGRlIGVzYXMgb3RyYXMgdmFyaWFibGVzLgoKUGFyYSBldml0YXIgZXNvLCBlbCBlbXBhcmVqYW1pZW50byBidXNjYSwgcG9yIGVqZW1wbG8sIHVuYSBwZXJzb25hIHRyYXRhZGEgY29uIGluZ3Jlc28gZGUgXCQ1MDAsIHRlbXBlcmF0dXJhIGRlIDI4wrBDIHkgc2FsdWQgcmVndWxhciwgeSBsYSBlbXBhcmVqYSBjb24gdW5hIHBlcnNvbmEgbm8gdHJhdGFkYSBjb24gY2FyYWN0ZXLDrXN0aWNhcyBtdXkgc2ltaWxhcmVzLiBBc8OtLCBhbCBjb21wYXJhciBzdXMgcmVzdWx0YWRvcyBkZSBzYWx1ZCwgcHVlZGVzIGF0cmlidWlyIGNvbiBtYXlvciBjb25maWFuemEgY3VhbHF1aWVyIGRpZmVyZW5jaWEgYWwgZWZlY3RvIGRlIGxhIHJlZCwgcG9ycXVlIGxhcyBvdHJhcyBjb25kaWNpb25lcyBlc3TDoW4gZXF1aWxpYnJhZGFzLiBFc3RvIGVzIGxvIHF1ZSBzZSBidXNjYSBhbCBlbXVsYXIgdW4gZXhwZXJpbWVudG8gYWxlYXRvcml6YWRvIGVuIHVuIGVzdHVkaW8gb2JzZXJ2YWNpb25hbC4KCioqQ29udGludWFkbyBjb24gZWwgYW5hbGlzaXMqKgoKTGEgc2ltaWxpdHVkIHNlIG1pZGUgdXRpbGl6YW5kbyBsYSBkaXN0YW5jaWEgZGUgTWFoYWxhbm9iaXMsIHF1ZSBjYWxjdWxhIGxhIGRpc3RhbmNpYSBtdWx0aWRpbWVuc2lvbmFsIGVudHJlIG9ic2VydmFjaW9uZXMgY29uc2lkZXJhbmRvIGxhcyBjb3JyZWxhY2lvbmVzIHkgZXNjYWxhcyBkZSBsYXMgY292YXJpYWJsZXMuIE9ic2VydmFjaW9uZXMgbcOhcyBjZXJjYW5hcyBlbiBlc3RhIG3DqXRyaWNhIHNvbiBjb25zaWRlcmFkYXMgbcOhcyBzaW1pbGFyZXMuCgpgYGB7cn0KIyBJbmRpY2Ftb3Mgc2VtaWxsYSBkZSByZXByb2R1Y2liaWxpZGFkCnNldC5zZWVkKDEyMykKCiMgSW5kaWNhbW9zIG1vZGVsbyBkZSBlbXBhcmVqYW1pZW50bwptYXRjaGVkIDwtIG1hdGNoaXQobmV0IH4gaW5jb21lICsgdGVtcGVyYXR1cmUgKyBoZWFsdGgsICMgRGVmaW5pciBjb3ZhcmlhYmxlcwogICAgICAgICAgICAgICAgICAgZGF0YSA9IG1vc3F1aXRvX25ldHMsICMgRGVmaW5pciBjb25qdW50byBkZSBkYXRvcwogICAgICAgICAgICAgICAgICAgbWV0aG9kID0gIm5lYXJlc3QiLCAgIyBFbXBlcmVqYW1pZW50byBwb3IgdmVjaW5vcyBtYXMgY2VyY2Fub3MKICAgICAgICAgICAgICAgICAgIGRpc3RhbmNlID0gIm1haGFsYW5vYmlzIiwgICMgVGlwbyBkZSBkaXN0YW5jaWEgbXVsdGlkaW1lbnNpb25hbAogICAgICAgICAgICAgICAgICAgcmVwbGFjZSA9IFRSVUUgIyBwZXJtaXRpciByZXV0aWxpemFjaW9uIHBhcmEgZW1wYXJlamFtaWVudG8KICAgICAgICAgICAgICAgICAgICkKCnN1bW1hcnkobWF0Y2hlZCkgICAgICAgICAgICAgICAgICAKCmBgYAoKRXN0ZSBjw7NkaWdvIHJlYWxpemEgdW4gZW1wYXJlamFtaWVudG8gZW50cmUgcGVyc29uYXMgcXVlIHJlY2liaWVyb24gdW5hIHJlZCBhbnRpbW9zcXVpdG9zIHkgbGFzIHF1ZSBubywgdXRpbGl6YW5kbyBlbCBwYXF1ZXRlIE1hdGNoSXQgZW4gUi4gTG8gaGFjZSBjb21wYXJhbmRvIGxhcyBjb3ZhcmlhYmxlcyBpbmNvbWUsIHRlbXBlcmF0dXJlIHkgaGVhbHRoLCBxdWUgcG9kcsOtYW4gaW5mbHVpciB0YW50byBlbiBsYSBhc2lnbmFjacOzbiBkZWwgdHJhdGFtaWVudG8gY29tbyBlbiBlbCByZXN1bHRhZG8uIFVzYSBlbCBtw6l0b2RvIGRlIHZlY2lub3MgbcOhcyBjZXJjYW5vcyAobWV0aG9kID0gIm5lYXJlc3QiKSBjb24gbGEgZGlzdGFuY2lhIGRlIE1haGFsYW5vYmlzLCBxdWUgY29uc2lkZXJhIGxhIGNvcnJlbGFjacOzbiBlbnRyZSB2YXJpYWJsZXMsIHBhcmEgZW5jb250cmFyIHBhcmVzIGxvIG3DoXMgc2ltaWxhcmVzIHBvc2libGUuIEFkZW3DoXMsIHBlcm1pdGUgcXVlIHVuYSBtaXNtYSBwZXJzb25hIG5vIHRyYXRhZGEgc2VhIHJldXRpbGl6YWRhIGVuIHZhcmlvcyBlbXBhcmVqYW1pZW50b3MgKHJlcGxhY2UgPSBUUlVFKSwgbG8gcXVlIG1lam9yYSBsYSBjYWxpZGFkIGRlbCBlbXBhcmVqYW1pZW50byBjdWFuZG8gaGF5IHBvY29zIGNvbnRyb2xlcyBkaXNwb25pYmxlcy4gRWwgb2JqZXRpdm8gZXMgY3JlYXIgZ3J1cG9zIGNvbXBhcmFibGVzIHkgcmVkdWNpciBlbCBzZXNnbyBwYXJhIGVzdGltYXIgZWwgZWZlY3RvIGNhdXNhbCBkZWwgdHJhdGFtaWVudG8uCgpFbiBlbCByZXN1bHRhZG8gZGUgYFNhbXBsZSBTaXplc2B0ZW5lbW9zIHF1ZToKCi0gICBIYWLDrWEgMTA3MSBjb250cm9sZXMgeSA2ODEgdHJhdGFkb3MgYW50ZXMgZGVsIGVtcGFyZWphbWllbnRvLgoKLSAgIFNlIHV0aWxpemFyb24gNDM2IG9ic2VydmFjaW9uZXMgZGVsIGdydXBvIGNvbnRyb2wgcGFyYSBlbXBhcmVqYXIgYSBsYXMgNjgxIGRlbCBncnVwbyB0cmF0YWRvLgoKLSAgIERhZG8gcXVlIHJlcGxhY2UgPSBUUlVFLCBhbGd1bmFzIG9ic2VydmFjaW9uZXMgZGVsIGdydXBvIGNvbnRyb2wgc2UgcmV1dGlsaXphcm9uIHBhcmEgZW1wYXJlamFyIGEgdmFyaW9zIHRyYXRhZG9zLgoKLSAgIDYzNSBvYnNlcnZhY2lvbmVzIGRlbCBncnVwbyBjb250cm9sIG5vIHB1ZGllcm9uIHNlciBlbXBhcmVqYWRhcy4gRGlzY2FyZGVkOgoKLSAgIE5vIHNlIGRlc2NhcnRhcm9uIG9ic2VydmFjaW9uZXMgZW4gZXN0ZSBhbsOhbGlzaXMuCgpFbCB2YWxvciBNYXRjaGVkIChFU1MpLCBvIFRhbWHDsW8gRWZlY3Rpdm8gZGUgbGEgTXVlc3RyYSAocG9yIHN1cyBzaWdsYXMgZW4gaW5nbGVzKSwgcmVwcmVzZW50YSB1bmEgZXN0aW1hY2nDs24gYWp1c3RhZGEgZGVsIG7Dum1lcm8gZGUgdW5pZGFkZXMgZGUgY29udHJvbCBlbXBhcmVqYWRhcywgdGVuaWVuZG8gZW4gY3VlbnRhIHF1ZSBhbGd1bmFzIGRlIGVsbGFzIHB1ZWRlbiBoYWJlciBzaWRvIHJldXRpbGl6YWRhcyB2YXJpYXMgdmVjZXMgZHVyYW50ZSBlbCBlbXBhcmVqYW1pZW50byAocG9ycXVlIHNlIHVzw7MgcmVwbGFjZSA9IFRSVUUpLiBBdW5xdWUgZWwgbsO6bWVybyByZWFsIGRlIGNvbnRyb2xlcyBlbXBhcmVqYWRvcyBmdWUgNDM2LCBlbCBFU1MgZnVlIGRlIDMyMC45NCwgbG8gcXVlIGluZGljYSBxdWUgbGEgcmV1dGlsaXphY2nDs24gZGUgY29udHJvbGVzIHJlZHVjZSBsYSBkaXZlcnNpZGFkIGVmZWN0aXZhIGRlbCBncnVwbyBkZSBjb21wYXJhY2nDs24sIHkgcG9yIHRhbnRvLCBlbCBwb2RlciBlc3RhZMOtc3RpY28gZGVsIGFuw6FsaXNpcy4gRXMgdW5hIGZvcm1hIG3DoXMgcHJlY2lzYSBkZSByZWZsZWphciBjdcOhbnRhICJpbmZvcm1hY2nDs24gaW5kZXBlbmRpZW50ZSIgc2UgdGllbmUgcmVhbG1lbnRlIGVuIGVsIGdydXBvIGRlIGNvbnRyb2wgZW1wYXJlamFkbwoKRWwgZW1wYXJlamFtaWVudG8gZnVlIGV4aXRvc28sIGxvZ3JhbmRvIGJhbGFuY2VhciBsYXMgY292YXJpYWJsZXMgZW50cmUgbG9zIGRvcyBncnVwb3MsIGxvIHF1ZSBwZXJtaXRpcsOhIGVzdGltYXIgZWwgZWZlY3RvIGRlbCB0cmF0YW1pZW50byAobmV0KSBjb24gbWVub3Igc2VzZ28uCgpBaG9yYSxwb2RlbW9zIGNyZWFyIHVuYSBudWV2YSBiYXNlIGRlIGRhdG9zIGJhc2FkYSBlbiBlc3RlIG1hdGNoaW5nIGNvbiBsYSBmdW5jacOzbiBgbWF0Y2guZGF0YSgpYC4gT2JzZXJ2YSBjw7NtbyBhaG9yYSBoYXkgc8OzbG8gMTExNyBmaWxhcyBlbiBsdWdhciBkZSAxNzUyLCB5YSBxdWUgaGVtb3MgZGVzY2FydGFkbyBsYXMgb2JzZXJ2YWNpb25lcyBubyBlbXBhcmVqYWRhcy4gVGFtYmnDqW4gYWhvcmEgaGF5IHVuYSBudWV2YSBjb2x1bW5hIGxsYW1hZGEgd2VpZ2h0cy4gTGEgZnVuY2nDs24gYG1hdGNoaXQoKWAgYXNpZ25hIGEgbG9zIHBhcmVzIGRlIG9ic2VydmFjaW9uZXMgZW1wYXJlamFkYXMgZGlmZXJlbnRlcyBwZXNvcyBkZXBlbmRpZW5kbyBkZSBsbyBjZXJjYSBvIGxlam9zIHF1ZSBlc3TDqW4gbG9zIGVtcGFyZWphbWllbnRvcyBlbiB1biBpbnRlbnRvIGRlIGNvbnRyb2xhciBsYSB2YXJpYWNpw7NuIGRlIGxhIGRpc3RhbmNpYS4gUG9kZW1vcyB1dGlsaXphciBlc3RvcyBwZXNvcyBlbiBudWVzdHJvIG1vZGVsbyBkZSByZWdyZXNpw7NuIHBhcmEgbWVqb3JhciBudWVzdHJhIGVzdGltYWNpw7NuIGRlbCBlZmVjdG8gY2F1c2FsCgpgYGB7cn0KbW9zcXVpdG9fbmV0c19tYXRjaGVkIDwtIG1hdGNoLmRhdGEobWF0Y2hlZCkgCmdsaW1wc2UobW9zcXVpdG9fbmV0c19tYXRjaGVkKSAKYGBgCgoqKlBvciB1bHRpbW8qKixwb2RlbW9zIGhhY2VyIHVuYSByZWdyZXNpw7NuIHVzYW5kbyBsb3MgZGF0b3MgZW1wYXJlamFkb3M6CgpgYGB7cn0KCiMgSW5kaWNhbW9zIG1vZGVsbyBsaW5lYWwKbW9kZWxfbWF0Y2hlZCA8LSBsbShtYWxhcmlhX3Jpc2sgfiBuZXQsIGRhdGEgPSBtb3NxdWl0b19uZXRzX21hdGNoZWQsCndlaWdodHMgPSB3ZWlnaHRzKQoKIyBWZW1vcyByZXN1bWVuIGVzdGFkaXN0aWNvCnN1bW1hcnkobW9kZWxfbWF0Y2hlZCkKCmBgYAoKU2Vnw7puIGVzdG9zIHJlc3VsdGFkb3MsIGVsIHVzbyBkZSB1biBtb3NxdWl0ZXJvIGNhdXNhIHVuYSBkaXNtaW51Y2nDs24gZGUgMTAuNDggcHVudG9zIGVuIGVsIHJpZXNnbyBkZSBtYWxhcmlhLCBlbiBwcm9tZWRpby4gVW5hIHZleiBtw6FzLCBwb2RlbW9zIHV0aWxpemFyIGVsIGxlbmd1YWplIGNhdXNhbCBhaG9yYSBwb3JxdWUgaGVtb3MgYWp1c3RhZG8gbG9zIGNvbmZ1c29yZXMgYWwgaGFjZXIgbGEgY29tcGFyYWNpw7NuLCBpZGVudGlmaWNhbmRvIGFzw60gZWwgY2FtaW5vIGNhdXNhbCBlbnRyZSBlbCB1c28gZGUgbW9zcXVpdGVyb3MgeSBlbCByaWVzZ28gZGUgbWFsYXJpYS4KCiMgUG9uZGVyYWNpw7NuIGRlIHByb2JhYmlsaWRhZCBpbnZlcnNhCgpVbmEgZGVzdmVudGFqYSBkZWwgdXNvIGRlIG1hdGNoaW5nIGVzIHF1ZSBkZXNlY2hhbW9zIG11Y2hhIGluZm9ybWFjacOzbjogbGFzIG9ic2VydmFjaW9uZXMgbm8gY29pbmNpZGVudGVzIHNlIGRlc2NhcnRhbiwgeSBlbCB0YW1hw7FvIGRlIG51ZXN0cmEgbXVlc3RyYSBwdWVkZSByZWR1Y2lyc2Ugc2lnbmlmaWNhdGl2YW1lbnRlLiBFbCBlbXBhcmVqYW1pZW50byB0YW1iacOpbiB0aWVuZGUgYSBzZXIgbXV5IHJpZ3Vyb3NvLCB5YSBxdWUgY2FkYSBvYnNlcnZhY2nDs24gdHJhdGFkYSBkZWJlIHNlciBlbXBhcmVqYWRhIGNvbiB1bmEgKG8gbcOhcykgb2JzZXJ2YWNpb25lcyBubyB0cmF0YWRhcy4gQXVucXVlIHF1ZSBhbGd1bmFzIG9ic2VydmFjaW9uZXMgbm8gdHJhdGFkYXMgZXN0w6FuIGVuIHJlYWxpZGFkIG11eSBjZXJjYSBkZSBsYXMgb2JzZXJ2YWNpb25lcyB0cmF0YWRhcywgYcO6biBhc8OtIHNlIGRlc2NhcnRhbiBwb3JxdWUgZnVlcm9uIHN1cGVyYWRhcyBwb3Igb2JzZXJ2YWNpb25lcyBxdWUgdGllbmVuIHVuYSBkaXN0YW5jaWEgbGlnZXJhbWVudGUgbWVub3IuCgpFbiBsdWdhciBkZSBkZXNlY2hhciBkYXRvcyBwb3RlbmNpYWxtZW50ZSDDunRpbGVzLCBwb2RlbW9zIHV0aWxpemFyIG90cm9zIG3DqXRvZG9zIHBhcmEgY3JlYXIgY29pbmNpZGVuY2lhcyBxdWUgc2VhbiBtZW5vcyByaWd1cm9zYXMgcGVybyBtw6FzIGluZm9ybWF0aXZhcy4gVW4gbcOpdG9kbyBjb23Dum4gZW4gZXBpZGVtaW9sb2fDrWEgeSBiaW9lc3RhZMOtc3RpY2EgZXMgbGEgcG9uZGVyYWNpw7NuIGRlIHByb2JhYmlsaWRhZCBpbnZlcnNhIChJUFcsIGVuIGluZ2zDqXMpLiBFbiBsYSBJUFcsIGEgY2FkYSBvYnNlcnZhY2nDs24gc2UgbGUgYXNpZ25hIHVuIHBlc28gYmFzYWRvIGVuIGxvIGJpZW4gcXVlIHN1IGFzaWduYWNpw7NuIHJlYWwgYWwgdHJhdGFtaWVudG8gY29pbmNpZGUgY29uIGxhIHByb2JhYmlsaWRhZCBwcmV2aXN0YSBkZWwgdHJhdGFtaWVudG8sIHkgZXNvcyBwZXNvcyBzZSB1dGlsaXphbiBsdWVnbyBlbiB1biBtb2RlbG8gZGUgcmVncmVzacOzbiBwYXJhIGVzdGltYXIgZWwgZWZlY3RvIGNhdXNhbCBkZWwgdHJhdGFtaWVudG8gZW4gZWwgcmVzdWx0YWRvLgoKKipQcmltZXJvKiosIHBvZGVtb3MgYWp1c3RhciBsb3MgZmFjdG9yZXMgZGUgY29uZnVzacOzbiBkZSBudWVzdHJvIG1vc3F1aXRlcm8geSBlbCBlamVtcGxvIGRlIHJpZXNnbyBkZSBtYWxhcmlhIHVzYW5kbyB1bmEgcG9uZGVyYWNpw7NuIGRlIHByb2JhYmlsaWRhZCBpbnZlcnNhLgoKUGFyYSBlbGxvLCB1c2Ftb3MgdW5hIHJlZ3Jlc2nDs24gbG9nw61zdGljYSBwYXJhIHByZWRlY2lyIGxhIHByb3BlbnNpw7NuIGEgdXNhciB1biBtb3NxdWl0ZXJvIHVzYW5kbyBsb3MgaW5ncmVzb3MsIGxhIHRlbXBlcmF0dXJhIHkgbGEgc2FsdWQuIEx1ZWdvIHVzYW1vcyBsb3MgcHVudGFqZXMgZGUgcHJvcGVuc2nDs24gcGFyYSBjYWxjdWxhciBsb3MgcGVzb3MgZGUgcHJvYmFiaWxpZGFkIGludmVyc2EgdXNhbmRvIGVzdGEgZsOzcm11bGE6CgokJApcZnJhY3tcdGV4dHtNb3NxdWl0ZXJvfX17XHRleHR7UHJvcGVuc2nDs259fSArIFxmcmFjezEgLSBcdGV4dHtNb3NxdWl0ZXJvfX17MSAtIFx0ZXh0e1Byb3BlbnNpw7NufX0KJCQKCmBgYHtyfQojIENyZWFtb3MgcmVncmVzaW9uIGxvZ2lzdGljYQptb2RlbF9tb3NxdWl0b19uZXQgPC0gZ2xtKG5ldCB+IGluY29tZSArIHRlbXBlcmF0dXJlICsgaGVhbHRoLAogICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBtb3NxdWl0b19uZXRzLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IikpCgoKCiMgQWdyZWdhbW9zIGlwdwptb3NxdWl0b19uZXRzX2lwdyA8LSBtb3NxdWl0b19uZXRzICU+JSAjIEluZGljYW1vcyBlbCBkZgogIG11dGF0ZShwcm9wZW5zaXR5ID0gcHJlZGljdChtb2RlbF9tb3NxdWl0b19uZXQsIHR5cGUgPSAicmVzcG9uc2UiKSwgI0FwbGljYW1vcyBlbCBtb2RlbG8gbG9naXN0aWNvLCBjb24gbGFzIHByb2JhYmlsaWRhZGVzCiAgICAgICAgIGlwdyA9IChuZXRfbnVtIC8gcHJvcGVuc2l0eSkgKyAoMSAtIG5ldF9udW0pIC8gKDEgLSBwcm9wZW5zaXR5KSkgIyBjcmVhbW9zIGNvbHVtbmEgaXB3CgoKIyBWZW1vcyByZXN1bHRhZG9zCnByaW50KG1vc3F1aXRvX25ldHNfaXB3KQpgYGAKCkVzdGUgY8OzZGlnbyBhanVzdGEgdW4gbW9kZWxvIGRlIHJlZ3Jlc2nDs24gbG9nw61zdGljYSBwYXJhIGVzdGltYXIgbGEgcHJvYmFiaWxpZGFkIGRlIHF1ZSB1bmEgcGVyc29uYSByZWNpYmEgdW4gbW9zcXVpdGVybyAoYG5ldGApIGVuIGZ1bmNpw7NuIGRlIHN1cyBpbmdyZXNvcywgdGVtcGVyYXR1cmEgeSBzYWx1ZCwgeSBsdWVnbyB1dGlsaXphIGVzYXMgcHJvYmFiaWxpZGFkZXMgKHByb3BlbnNpb25lcykgcGFyYSBjYWxjdWxhciBwZXNvcyBkZSBwb25kZXJhY2nDs24gcG9yIGxhIGludmVyc2EgZGUgbGEgcHJvYmFiaWxpZGFkIGRlIHRyYXRhbWllbnRvIChJUFcpLiBFc3RvcyBwZXNvcyBwZXJtaXRlbiBjb3JyZWdpciBwb3NpYmxlcyBzZXNnb3MgZGUgc2VsZWNjacOzbiBhbCBjb21wYXJhciBncnVwb3MgdHJhdGFkb3MgeSBubyB0cmF0YWRvcywgYXNpZ25hbmRvIG1heW9yIHBlc28gYSBsYXMgb2JzZXJ2YWNpb25lcyBxdWUgcmVjaWJpZXJvbiB1biB0cmF0YW1pZW50byBpbmVzcGVyYWRvIHNlZ8O6biBzdXMgY2FyYWN0ZXLDrXN0aWNhcy4gQXPDrSwgc2UgYnVzY2Egc2ltdWxhciB1biBlc2NlbmFyaW8gbcOhcyBwYXJlY2lkbyBhIHVuIGV4cGVyaW1lbnRvIGFsZWF0b3JpbyB5IGVzdGltYXIgZGUgZm9ybWEgbcOhcyBqdXN0YSBlbCBlZmVjdG8gZGVsIHRyYXRhbWllbnRvLgoKKipTZWd1bmRvKiosIGFob3JhIHF1ZSB0ZW5lbW9zIHBlc29zIGRlIHByb2JhYmlsaWRhZCBpbnZlcnNhLCBwb2RlbW9zIHVzYXJsb3MgZW4gdW5hIHJlZ3Jlc2nDs246CgpgYGB7cn0KIyBJbmRpY2Ftb3MgbW9kZWxvIGxpbmVhbAptb2RlbF9pcHcgPC0gbG0obWFsYXJpYV9yaXNrIH4gbmV0LCBkYXRhID0gbW9zcXVpdG9fbmV0c19pcHcsCndlaWdodHMgPSBpcHcpCgojIFZlbW9zIHJlc3VsdGFkb3MKc3VtbWFyeShtb2RlbF9pcHcpCgpgYGAKClNlZ8O6biBlc3RlIG1vZGVsbyBkZSBJUFcsIGVsIHVzbyBkZSB1biBtb3NxdWl0ZXJvICpjYXVzYSogdW5hIGRpc21pbnVjacOzbiBkZSAxMC4xMyBwdW50b3MgZW4gZWwgcmllc2dvIGRlIG1hbGFyaWEsIGVuIHByb21lZGlvLiBVbmEgdmV6IG3DoXMsIHBvZGVtb3MgdXRpbGl6YXIgY29uIHNlZ3VyaWRhZCBlbCBsZW5ndWFqZSBjYXVzYWwgcG9ycXVlIGhlbW9zIGlkZW50aWZpY2FkbyBlbCBjYW1pbm8gY2F1c2FsIGVudHJlIGVsIHVzbyBkZSBtb3NxdWl0ZXJvcyB5IGVsIHJpZXNnbyBkZSBtYWxhcmlhIHRlbmllbmRvIGVuIGN1ZW50YSBsb3MgZmFjdG9yZXMgZGUgY29uZnVzacOzbiBlbiBsb3MgcGVzb3MgZGUgcHJvYmFiaWxpZGFkIGludmVyc29zLgoKIyBDb21wYXJhbmRvIHRvZG9zIGxvcyBtw6l0b2RvcwoKQWhvcmEgcXVlIGhlbW9zIGVqZWN1dGFkbyB2YXJpb3MgbW9kZWxvcyBkZSByZWdyZXNpw7NuIHF1ZSBzZSBhanVzdGFuIGEgbG9zIGZhY3RvcmVzIGRlIGNvbmZ1c2nDs24gZGUgZGlmZXJlbnRlcyBtYW5lcmFzLCBwb2RlbW9zIGNvbXBhcmFyIGxvcyByZXN1bHRhZG9zIHRvZG9zIGp1bnRvcy4gTGEgaW5nZW51YSBlc3RpbWFjacOzbiBkZSAtMTYgcGFyZWNlIHNlciBkZWZpbml0aXZhbWVudGUgdW5hIHNvYnJlZXN0aW1hY2nDs246IGRlc3B1w6lzIGRlIGFqdXN0YXIgY29uIGxhIHJlZ3Jlc2nDs24sIGVsIG1hdGNoaW5nIHkgbGEgcG9uZGVyYWNpw7NuIGRlIHByb2JhYmlsaWRhZCBpbnZlcnNhLCBlbCBlZmVjdG8gY2F1c2FsIGRlbCB1c28gZGUgdW4gbW9zcXVpdGVybyBlbiBlbCByaWVzZ28gZGUgbWFsYXJpYSBlcyBjb25zaXN0ZW50ZW1lbnRlIGRlIGFscmVkZWRvciBkZSAtMTAuIEFzdW1pZW5kbyBxdWUgbnVlc3RybyBEQUcgZXN0w6EgY29ycmVjdG8sIGVuY29udHJhbW9zIGNvbiDDqXhpdG8gdW4gZWZlY3RvIGNhdXNhbCBhIHBhcnRpciBkZSBkYXRvcyBubyBleHBlcmltZW50YWxlcyB5IG9ic2VydmFjaW9uYWxlcy4KCmBgYHtyfQp0ZXhyZWc6OnNjcmVlbnJlZyhsaXN0KG1vZGVsX25haXZlLCBtb2RlbF9yZWdyZXNzaW9uLAogICAgICAgICAgICAgICAgICAgICAgIG1vZGVsX21hdGNoZWQsIG1vZGVsX2lwdyksCiAgICAgICAgICAgICAgICAgIGN1c3RvbS5tb2RlbC5uYW1lcyA9IGMoIk5haXZlIiwgIlJlZ3Jlc3Npb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNYXRjaGluZyIsICJJUFciKSkKCmBgYAo=