Gráfico Acíclico Dirigido

Introducción

Un Gráfico Acíclico Dirigido (DAG, por sus siglas en inglés: Directed Acyclic Graph) es una estructura gráfica que se utiliza para representar relaciones causales entre variables. Los DAGs son herramientas poderosas en diversas áreas, incluyendo la epidemiología, las ciencias sociales, la economía y la inteligencia artificial, entre otras. En el caso de la evaluación de políticas publicas, los DAGs nos permiten entender mejor las relaciones causales con que se desarrollan los proyectos y programas de desarrollo. Con ellos podemos entender mejor cómo ciertas intervenciones conducen a determinados resultados e impactos.

Para identificar efectos causales en intervenciones de política social necesitamos bloquear todos los caminos (paths) no causales mientras que mantenemos los que si son causales, para lo cual se necesita listar todos los caminos que conecten la variable de tratamiento (usualmente denominada X o D) con la variable de resultados (usualmente denominada Y).

Componentes de un DAG

Nodos: Representan las variables en estudio. Cada nodo en el gráfico corresponde a una variable específica.

Flechas (aristas dirigidas): Indican la dirección de la relación causal entre las variables. Una flecha de un nodo A a un nodo B (A → B) sugiere que A tiene un efecto causal sobre B.

Características de los DAGs

A-cíclicos: No contienen ciclos, lo que significa que no es posible volver al mismo nodo siguiendo las flechas dirigidas. Es decir, no hay un camino cerrado en el que una variable se cause a sí misma directa o indirectamente.

Dirigidos: Las aristas tienen una dirección, lo que denota la relación causal y la direccionalidad del efecto entre las variables.

Propósitos y Usos de los DAGs

Representación Causal: Los DAGs se utilizan para representar y visualizar las relaciones causales entre variables, facilitando el entendimiento de cómo una variable puede influir en otra.

Identificación de Sesgos: Permiten identificar posibles fuentes de sesgo, como caminos de “backdoor” o variables confusoras, que pueden afectar la estimación del efecto causal.

Diseño de Estudios: Ayudan en el diseño de estudios observacionales y experimentales, indicando qué variables deben ser controladas para obtener una estimación causal no sesgada.

Inferencia Causal: Se utilizan en análisis estadísticos para realizar inferencias causales, identificando las condiciones bajo las cuales los efectos causales pueden ser correctamente estimados.

Tipos de DAG

Los tipos de DAGs (Gráficos Acíclicos Dirigidos) más importantes en el análisis causal son aquellos que permiten identificar claramente las relaciones causales y las posibles fuentes de sesgo en los estudios.

1. DAG Directo (Direct Causal Pathway) Representa una relación causal directa entre dos variables sin la intervención de variables intermedias. Útil para modelar relaciones causales simples.

Ejemplo:

Relación entre fumar (F) y riesgo de cáncer de pulmón (C).

Representación: \[ \ F → C \]

## 
## Attaching package: 'ggdag'
## The following object is masked from 'package:stats':
## 
##     filter

2. DAG de Cadena (Chain) Representa una secuencia causal en la que una variable afecta a otra, que a su vez afecta a una tercera variable. Importante para identificar efectos mediadores.

Ejemplo:

Relación entre la dieta (D), el índice de masa corporal (B), y la salud cardiovascular (H).

Representación: \[ \ D → B → H \]

3. DAG de Colisionador (Collider) Representa una situación en la que dos variables independientes afectan conjuntamente a una tercera variable. En esta situación, el collider permite que las puertas traseras estén cerradas “naturalmente”: \[ X → Collider ←Y \] Es decir, la existencia de un collider en un camino hace que automaticamente cierra los caminos o puertas traseras.

Son cruciales para reconocer asociaciones espurias inducidas por ajustar el colisionador, pues ajustar el colisionador abre una puerta trasera. Al controlar o condicionar por un collider el camino que estaba cerrado se vuelve a abrir. Por esto es crítico, para cualquier estrategia de identificación, el diferenciar entre variables colliders y variables de confusión, y controlar por estas últimas pero NO por las primeros.

Ejemplo:

Nivel de ejercicio (E) y dieta (D) afectando al peso corporal (W).

Representación: \[ E → W ← D \] 4. DAG de Confusor (Confounder) Incluye una variable confusora que afecta tanto a la variable de exposición como a la variable de resultado.

Ayuda a identificar y ajustar variables confusoras para evitar sesgos. Las variables confusoras abren caminos o puertas traseras no deseadas en el ejercicio de encontrar la relacion causal entre tratamiento y resultado.

Ejemplo:

Relación entre fumar (F), exposición a toxinas (T), y riesgo de cáncer de pulmón (C).

Representación: \[ T → F \] \[ T → C \]

\[ F → C \]

5. DAG de Interacción (Moderator) Representa una situación en la que el efecto de una variable sobre otra depende de una tercera variable. Útil para modelar efectos que dependen de otra variable.

Ejemplo:

Relación entre ejercicio físico (E), la presencia de una condición genética (G), y la salud cardiovascular (H).

Representación: \[ E → H \]

\[ G → H \]

\[ E ↔ G \]

6. DAG de Mediador (Mediator) Incluye una variable mediadora que transmite el efecto de una variable sobre otra. Ayuda a entender cómo se transmite un efecto causal a través de una variable intermediaria.

Ejemplo:

Relación entre la motivación parental (P), el rendimiento académico (R), y el éxito profesional (S).

Representación: \[ P → R → S \]

Existencia de Backdoor en una relacion causal

En el contexto de los Gráficos Acíclicos Dirigidos (DAGs), un “backdoor” se refiere a un camino indirecto que conecta la variable de exposición (o tratamiento) con la variable de resultado (o desenlace) a través de una o más variables intermediarias. Este camino indirecto puede introducir sesgos en la estimación del efecto causal si no se ajusta adecuadamente.

Concepto de Backdoor Path Un backdoor path es cualquier camino entre la variable de exposición X y la variable de resultado Y que:

  1. No sigue la dirección causal directa de \[ X→Y \]

  2. Conecta X y Y a través de una o más variables intermediarias, que pueden ser confusores.

Ejemplo

Relaciones Causales en Educación Variables:

I: Nivel de inteligencia de un estudiante. S: Horas de estudio. G: Calificaciones obtenidas.

Relaciones:

El nivel de inteligencia (I) afecta las horas de estudio (S). Las horas de estudio (S) afectan las calificaciones (G).

\[ I→S→G \]

Un “backdoor” es un camino alternativo entre las variables que podría introducir sesgo si no se controla adecuadamente.

Vamos a añadir una nueva variable P (motivación parental), que afecta tanto el nivel de inteligencia I como las horas de estudio S.

Relaciones:

La motivación parental (P) afecta tanto el nivel de inteligencia (I) como las horas de estudio (S). El nivel de inteligencia (I) afecta las horas de estudio (S). Las horas de estudio (S) afectan las calificaciones (G).

En este nuevo DAG, la motivación parental (P) introduce un “backdoor” entre I y S. Esto significa que si no controlamos por P, cualquier análisis que busque entender la relación entre I y S podría estar sesgado debido a la influencia de P.

Para obtener una estimación no sesgada del efecto causal de I sobre S y de S sobre G, necesitaríamos ajustar por P.

Ajuste para Eliminar el Backdoor Path Para eliminar el sesgo introducido por el backdoor path, se debe ajustar por la variable confusora P. Esto se puede hacer mediante:

Estratificación: Dividir los datos en estratos según los valores de P y analizar cada estrato por separado.

Regresión: Incluir P como covariable en un modelo de regresión.

Emparejamiento: Emparejar individuos con valores similares de P para comparar los efectos de I sobre G.

Independencia condicional

La independencia condicional es un concepto fundamental en el análisis causal y se representa de manera natural en los Gráficos Acíclicos Dirigidos (DAGs). En un DAG, la independencia condicional se utiliza para identificar cuales variables son independientes unas de otras dado un conjunto de variables condicionantes.

Definición:

Dos variables X y Y son condicionalmente independientes dadas una tercera variable Z. En notación, esto se escribe como:

\[ X⊥Y∣ Z \]

En un DAG:

La independencia condicional se puede leer directamente del DAG utilizando el criterio de d-separación (d-separation). Si un conjunto de variables Z bloquea todos los caminos entre X y Y, entonces X y Y son condicionalmente independientes dado Z.

Tipos de DAGs que Representan Independencia Condicional

DAG Directo (Direct Causal Pathway): En un DAG directo sin variables intermediarias ni confusores, la relación directa entre dos variables implica que no hay independencia condicional sin intervención.

DAG de Cadena (Chain): En un DAG de cadena, dos variables X y Y pueden ser independientes si condicionamos en la variable intermedia Z.

\[ X → Z → Y \] Aquí, X y Y son condicionalmente independientes dado Z.

DAG de Colisionador (Collider): En un DAG de colisionador, dos variables X y Y son independientes a menos que se condicione en la variable colisionadora Z o en sus descendientes.

\[ X → Z ← Y \] Aquí, X y Y son independientes a menos que condicionemos en Z.

DAG con Confusor (Confounder):

En un DAG con un confusor, las variables pueden volverse condicionalmente independientes cuando se ajusta por el confusor.

\[ Z → X \] \[ Z → Y \]

\[ X → Y \] Aquí, X y Y pueden ser independientes si ajustamos por Z.

Condicionar (controlar) en un DAG

En un DAG, entender cuándo y cómo condicionar en una variable es crucial para el análisis de relaciones causales.

Para Controlar por Confusión (Confounding): Condicionar en variables que pueden actuar como confusores ayuda a obtener una estimación no sesgada del efecto causal.

Para Bloquear Rutas No Deseadas: A veces, necesitamos bloquear rutas indirectas que no forman parte del efecto causal de interés.

Recordar los siguientes conceptos Clave:

Confounders: Variables que afectan tanto a la variable de exposición como a la de resultado. Condicionar en confounders ayuda a obtener una relación causal más precisa.

Colliders: Nodos en los que dos aristas convergen. Condicionar en colliders puede inducir una asociación no causal entre las variables de entrada.

Non-Colliders: Nodos que no son colliders, generalmente se recomienda no condicionar en ellos a menos que se necesite para bloquear una ruta no deseada.

Ejemplos

  1. Condicionar para Controlar por Confusión

DAG Ejemplo: \[ T <- S -> I -> P \]

S es un confounder, ya que afecta tanto a T (intervention) como a P (outcome) a través de I. Para obtener una relación no sesgada entre T y P, debemos condicionar en S.

Condicionemos ahora S:

# Definir un DAG simple
dag_simple <- dagify(
  P ~ T + S,  # Desempeño influenciado por el Tipo de Programa y Nivel Socioeconómico
  T ~ S,      # Tipo de Programa influenciado por el Nivel Socioeconómico
  outcome="P",
  exposure = "T",
  labels = c("T" = "Tipo de Programa",
             "P" = "Desempeño Académico",
             "S" = "Nivel Socioeconómico")
)
# Convertir el DAG a un objeto dagitty
dagitty_dag <- as.dagitty(dag_simple)
# Visualizar el DAG
ggdag(dagitty_dag) + theme_dag()

Ahora, realizamos el análisis de paths para ver cómo las rutas están afectadas por condicionar en S.

# Realizar el análisis de paths desde T hasta P
paths(dagitty_dag, from = "T", to = "P")
## $paths
## [1] "T -> P"      "T <- S -> P"
## 
## $open
## [1] TRUE TRUE

Sin Condicionar en S

Ruta directa: T -> P Ruta indirecta: T <- S -> P

Ambas rutas están abiertas. La ruta directa T -> P y la ruta indirecta T <- S -> P están abiertas, lo que significa que S puede estar confundiéndonos sobre la verdadera relación entre T y P.

Condicionando en S

Al condicionar en S, bloqueamos la ruta T <- S -> P, lo que nos permite estimar el efecto directo de T en P.

Para esto utulizamos la funci[on adjustmentSets que nos ayuda a encontar el set minimo suficiente (Minimally Sufficient Sett)

# Identificar los conjuntos de ajuste para controlar confusión
adjustmentSets(dagitty_dag, exposure = "T", outcome = "P")
## { S }
ggdag_adjustment_set(dagitty_dag, text = FALSE, use_labels = "label", 
                     shadow = TRUE, stylized = TRUE, node_size = 10,   text_size = 2.8)

  1. Condicionar para Bloquear Rutas No Deseadas

DAG Ejemplo: \[ T -> I -> P \] \[ S -> I \]

I es un nodo en una ruta indirecta de T a P.

Si queremos bloquear esta ruta, podríamos condicionar en I para obtener la relación directa entre T y P.

En resumen, condicionar en una variable significa ajustar por ella en el análisis para controlar su influencia y obtener relaciones causales más precisas. Es una práctica fundamental en la modelización causal y debe ser utilizada estratégicamente para asegurar la validez de los resultados. A modo de conclusión:

Condicionar en Confounders: Esto ayuda a eliminar la confusión y obtener una estimación causal precisa. Condicionar en Colliders: Generalmente no se debe hacer, ya que puede inducir asociaciones no causales. Condicionar en Non-Colliders: Útil para bloquear rutas no deseadas o para controlar confusión.

D-Separated y D-Connected Paths

En el contexto de los DAGs (Graphos Acíclicos Dirigidos), los conceptos de d-separated y d-connected son cruciales para entender cómo las variables están relacionadas y cómo la información se transmite a través del modelo.

1. D-Separated Paths Dos variables están d-separated si, dado el conocimiento de ciertas otras variables, no hay ninguna ruta activa (es decir, ninguna ruta a través de la cual la información pueda fluir) entre ellas. En otras palabras, las variables están independientemente condicionadas por otras variables en el DAG.

Cómo Determinar la D-Separation:

Variable de Ajuste: Para que dos variables estén d-separadas, se debe ajustar por ciertas variables que “bloquean” todas las rutas entre ellas.

Colisionadores y Confusores: Una ruta está bloqueada si pasa por un colisionador y no se ajusta por el colisionador ni por sus descendientes.

Una ruta también puede estar bloqueada si pasa por un confusor y se ajusta por el confusor.

Ejemplo: En un DAG donde X -> Z <- Y, X y Y están d-separados dado Z. La información no fluye entre X y Y si Z es conocido.

2. D-Connected Paths

Dos variables están d-conectadas si existe una ruta activa entre ellas, es decir, si no hay ninguna ruta bloqueada por las variables condicionadas. En otras palabras, la información puede fluir entre las dos variables a través de una o más rutas en el DAG.

Cómo Determinar la D-Connection:

Colisionadores y Confusores: Una ruta es activa si pasa por un confusor y se ajusta por él. Una ruta es activa si pasa por un colisionador y el colisionador (o sus descendientes) no se ajusta por él.

Ejemplo: En un DAG donde X -> Z -> Y y se ajusta por Z, X y Y están d-conectados a través de Z. La información puede fluir de X a Y a través de Z.

 # Definir un DAG simple
dag_example <- dagify(
  Y ~ X + Z,
  Z ~ X,
  outcome= "Y",
  exposure= "X",
  labels = c("X" = "Variable X",
             "Y" = "Variable Y",
             "Z" = "Variable Z")
)

# Convertir el DAG a un objeto dagitty
dagitty_dag <- as.dagitty(dag_example)

# Visualizar el DAG
ggdag(dagitty_dag) + theme_dag()

# Analizar la d-separation entre X y Y dado Z usando ggdag_drelationship
ggdag_drelationship(dagitty_dag, controlling_for  = "Z", text = FALSE, use_labels = "label",                     stylized = TRUE, node_size = 10,   text_size = 2.8, edge_type="link_arc")

```

LS0tCnRpdGxlOiAiREFHcyIKYXV0aG9yOiAiRmVybmFuZG8gQnVjaGVsaSIKZGF0ZTogIjIwMjUtMDEtMjYiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgY29kZV9kb3dubG9hZDogdHJ1ZQoKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCiMgR3LDoWZpY28gQWPDrWNsaWNvIERpcmlnaWRvCgojIyBJbnRyb2R1Y2Npw7NuIApVbiBHcsOhZmljbyBBY8OtY2xpY28gRGlyaWdpZG8gKERBRywgcG9yIHN1cyBzaWdsYXMgZW4gaW5nbMOpczogRGlyZWN0ZWQgQWN5Y2xpYyBHcmFwaCkgZXMgdW5hIGVzdHJ1Y3R1cmEgZ3LDoWZpY2EgcXVlIHNlIHV0aWxpemEgcGFyYSByZXByZXNlbnRhciByZWxhY2lvbmVzIGNhdXNhbGVzIGVudHJlIHZhcmlhYmxlcy4gTG9zIERBR3Mgc29uIGhlcnJhbWllbnRhcyBwb2Rlcm9zYXMgZW4gZGl2ZXJzYXMgw6FyZWFzLCBpbmNsdXllbmRvIGxhIGVwaWRlbWlvbG9nw61hLCBsYXMgY2llbmNpYXMgc29jaWFsZXMsIGxhIGVjb25vbcOtYSB5IGxhIGludGVsaWdlbmNpYSBhcnRpZmljaWFsLCBlbnRyZSBvdHJhcy4gRW4gZWwgY2FzbyBkZSBsYSBldmFsdWFjacOzbiBkZSBwb2zDrXRpY2FzIHB1YmxpY2FzLCBsb3MgREFHcyBub3MgcGVybWl0ZW4gZW50ZW5kZXIgbWVqb3IgbGFzIHJlbGFjaW9uZXMgY2F1c2FsZXMgY29uIHF1ZSBzZSBkZXNhcnJvbGxhbiBsb3MgcHJveWVjdG9zIHkgcHJvZ3JhbWFzIGRlIGRlc2Fycm9sbG8uIENvbiBlbGxvcyBwb2RlbW9zIGVudGVuZGVyIG1lam9yIGPDs21vIGNpZXJ0YXMgaW50ZXJ2ZW5jaW9uZXMgY29uZHVjZW4gYSBkZXRlcm1pbmFkb3MgcmVzdWx0YWRvcyBlIGltcGFjdG9zLiAKClBhcmEgaWRlbnRpZmljYXIgZWZlY3RvcyBjYXVzYWxlcyBlbiBpbnRlcnZlbmNpb25lcyBkZSBwb2zDrXRpY2Egc29jaWFsIG5lY2VzaXRhbW9zIGJsb3F1ZWFyIHRvZG9zIGxvcyBjYW1pbm9zIChwYXRocykgbm8gY2F1c2FsZXMgbWllbnRyYXMgcXVlIG1hbnRlbmVtb3MgbG9zIHF1ZSBzaSBzb24gY2F1c2FsZXMsIHBhcmEgbG8gY3VhbCBzZSBuZWNlc2l0YSBsaXN0YXIgdG9kb3MgbG9zIGNhbWlub3MgcXVlIGNvbmVjdGVuIGxhIHZhcmlhYmxlIGRlIHRyYXRhbWllbnRvICh1c3VhbG1lbnRlIGRlbm9taW5hZGEgWCBvIEQpIGNvbiBsYSB2YXJpYWJsZSBkZSByZXN1bHRhZG9zICh1c3VhbG1lbnRlIGRlbm9taW5hZGEgWSkuCgoKIyMgQ29tcG9uZW50ZXMgZGUgdW4gREFHCgoqKk5vZG9zOioqClJlcHJlc2VudGFuIGxhcyB2YXJpYWJsZXMgZW4gZXN0dWRpby4gQ2FkYSBub2RvIGVuIGVsIGdyw6FmaWNvIGNvcnJlc3BvbmRlIGEgdW5hIHZhcmlhYmxlIGVzcGVjw61maWNhLgoKKipGbGVjaGFzIChhcmlzdGFzIGRpcmlnaWRhcyk6KioKSW5kaWNhbiBsYSBkaXJlY2Npw7NuIGRlIGxhIHJlbGFjacOzbiBjYXVzYWwgZW50cmUgbGFzIHZhcmlhYmxlcy4gVW5hIGZsZWNoYSBkZSB1biBub2RvIEEgYSB1biBub2RvIEIgKEEg4oaSIEIpIHN1Z2llcmUgcXVlIEEgdGllbmUgdW4gZWZlY3RvIGNhdXNhbCBzb2JyZSBCLgoKIyMgQ2FyYWN0ZXLDrXN0aWNhcyBkZSBsb3MgREFHcwoKKipBLWPDrWNsaWNvczoqKgpObyBjb250aWVuZW4gY2ljbG9zLCBsbyBxdWUgc2lnbmlmaWNhIHF1ZSBubyBlcyBwb3NpYmxlIHZvbHZlciBhbCBtaXNtbyBub2RvIHNpZ3VpZW5kbyBsYXMgZmxlY2hhcyBkaXJpZ2lkYXMuIEVzIGRlY2lyLCBubyBoYXkgdW4gY2FtaW5vIGNlcnJhZG8gZW4gZWwgcXVlIHVuYSB2YXJpYWJsZSBzZSBjYXVzZSBhIHPDrSBtaXNtYSBkaXJlY3RhIG8gaW5kaXJlY3RhbWVudGUuCgoqKkRpcmlnaWRvczoqKgpMYXMgYXJpc3RhcyB0aWVuZW4gdW5hIGRpcmVjY2nDs24sIGxvIHF1ZSBkZW5vdGEgbGEgcmVsYWNpw7NuIGNhdXNhbCB5IGxhIGRpcmVjY2lvbmFsaWRhZCBkZWwgZWZlY3RvIGVudHJlIGxhcyB2YXJpYWJsZXMuCgojIyBQcm9ww7NzaXRvcyB5IFVzb3MgZGUgbG9zIERBR3MKCioqUmVwcmVzZW50YWNpw7NuIENhdXNhbDoqKgpMb3MgREFHcyBzZSB1dGlsaXphbiBwYXJhIHJlcHJlc2VudGFyIHkgdmlzdWFsaXphciBsYXMgcmVsYWNpb25lcyBjYXVzYWxlcyBlbnRyZSB2YXJpYWJsZXMsIGZhY2lsaXRhbmRvIGVsIGVudGVuZGltaWVudG8gZGUgY8OzbW8gdW5hIHZhcmlhYmxlIHB1ZWRlIGluZmx1aXIgZW4gb3RyYS4KCioqSWRlbnRpZmljYWNpw7NuIGRlIFNlc2dvczoqKgpQZXJtaXRlbiBpZGVudGlmaWNhciBwb3NpYmxlcyBmdWVudGVzIGRlIHNlc2dvLCBjb21vIGNhbWlub3MgZGUgImJhY2tkb29yIiBvIHZhcmlhYmxlcyBjb25mdXNvcmFzLCBxdWUgcHVlZGVuIGFmZWN0YXIgbGEgZXN0aW1hY2nDs24gZGVsIGVmZWN0byBjYXVzYWwuCgoqKkRpc2XDsW8gZGUgRXN0dWRpb3M6KioKQXl1ZGFuIGVuIGVsIGRpc2XDsW8gZGUgZXN0dWRpb3Mgb2JzZXJ2YWNpb25hbGVzIHkgZXhwZXJpbWVudGFsZXMsIGluZGljYW5kbyBxdcOpIHZhcmlhYmxlcyBkZWJlbiBzZXIgY29udHJvbGFkYXMgcGFyYSBvYnRlbmVyIHVuYSBlc3RpbWFjacOzbiBjYXVzYWwgbm8gc2VzZ2FkYS4KCioqSW5mZXJlbmNpYSBDYXVzYWw6KioKU2UgdXRpbGl6YW4gZW4gYW7DoWxpc2lzIGVzdGFkw61zdGljb3MgcGFyYSByZWFsaXphciBpbmZlcmVuY2lhcyBjYXVzYWxlcywgaWRlbnRpZmljYW5kbyBsYXMgY29uZGljaW9uZXMgYmFqbyBsYXMgY3VhbGVzIGxvcyBlZmVjdG9zIGNhdXNhbGVzIHB1ZWRlbiBzZXIgY29ycmVjdGFtZW50ZSBlc3RpbWFkb3MuCgojIyBUaXBvcyBkZSBEQUcKCkxvcyB0aXBvcyBkZSBEQUdzIChHcsOhZmljb3MgQWPDrWNsaWNvcyBEaXJpZ2lkb3MpIG3DoXMgaW1wb3J0YW50ZXMgZW4gZWwgYW7DoWxpc2lzIGNhdXNhbCBzb24gYXF1ZWxsb3MgcXVlIHBlcm1pdGVuIGlkZW50aWZpY2FyIGNsYXJhbWVudGUgbGFzIHJlbGFjaW9uZXMgY2F1c2FsZXMgeSBsYXMgcG9zaWJsZXMgZnVlbnRlcyBkZSBzZXNnbyBlbiBsb3MgZXN0dWRpb3MuIAoKKioxLiBEQUcgRGlyZWN0byAoRGlyZWN0IENhdXNhbCBQYXRod2F5KSoqClJlcHJlc2VudGEgdW5hIHJlbGFjacOzbiBjYXVzYWwgZGlyZWN0YSBlbnRyZSBkb3MgdmFyaWFibGVzIHNpbiBsYSBpbnRlcnZlbmNpw7NuIGRlIHZhcmlhYmxlcyBpbnRlcm1lZGlhcy4Kw5p0aWwgcGFyYSBtb2RlbGFyIHJlbGFjaW9uZXMgY2F1c2FsZXMgc2ltcGxlcy4KCkVqZW1wbG86CgpSZWxhY2nDs24gZW50cmUgZnVtYXIgKEYpIHkgcmllc2dvIGRlIGPDoW5jZXIgZGUgcHVsbcOzbiAoQykuCgpSZXByZXNlbnRhY2nDs246CiQkClwgRiDihpIgQwokJApgYGB7ciBEQUcgZGlyZWN0bywgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBDYXJnYXIgbG9zIHBhcXVldGVzIG5lY2VzYXJpb3MKbGlicmFyeShkYWdpdHR5KQpsaWJyYXJ5KGdnZGFnKQoKIyBEQUcgRGlyZWN0bwpkYWdfZGlyZWN0byA8LSBkYWdpdHR5KCdkYWcgewogIEYgW3Bvcz0iMCwwIl0KICBDIFtwb3M9IjEsMCJdCiAgRiAtPiBDCn0nKQoKZ2dkYWcoZGFnX2RpcmVjdG8pICsgdGhlbWVfZGFnKCkKYGBgCgoKKioyLiBEQUcgZGUgQ2FkZW5hIChDaGFpbikqKgpSZXByZXNlbnRhIHVuYSBzZWN1ZW5jaWEgY2F1c2FsIGVuIGxhIHF1ZSB1bmEgdmFyaWFibGUgYWZlY3RhIGEgb3RyYSwgcXVlIGEgc3UgdmV6IGFmZWN0YSBhIHVuYSB0ZXJjZXJhIHZhcmlhYmxlLgpJbXBvcnRhbnRlIHBhcmEgaWRlbnRpZmljYXIgZWZlY3RvcyBtZWRpYWRvcmVzLgoKRWplbXBsbzoKClJlbGFjacOzbiBlbnRyZSBsYSBkaWV0YSAoRCksIGVsIMOtbmRpY2UgZGUgbWFzYSBjb3Jwb3JhbCAoQiksIHkgbGEgc2FsdWQgY2FyZGlvdmFzY3VsYXIgKEgpLgoKUmVwcmVzZW50YWNpw7NuOgokJApcIEQg4oaSIEIg4oaSIEggCiQkCmBgYHtyIERBRyBjYWRlbmEsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgREFHIGRlIENhZGVuYQpkYWdfY2hhaW4gPC0gZGFnaXR0eSgnZGFnIHsKICBEIFtwb3M9IjAsMCJdCiAgQiBbcG9zPSIxLDAiXQogIEggW3Bvcz0iMiwwIl0KICBEIC0+IEIKICBCIC0+IEgKfScpCgpnZ2RhZyhkYWdfY2hhaW4pICsgdGhlbWVfZGFnKCkKYGBgCgoKCioqMy4gREFHIGRlIENvbGlzaW9uYWRvciAoQ29sbGlkZXIpKioKUmVwcmVzZW50YSB1bmEgc2l0dWFjacOzbiBlbiBsYSBxdWUgZG9zIHZhcmlhYmxlcyBpbmRlcGVuZGllbnRlcyBhZmVjdGFuIGNvbmp1bnRhbWVudGUgYSB1bmEgdGVyY2VyYSB2YXJpYWJsZS4gRW4gZXN0YSBzaXR1YWNpw7NuLCBlbCBjb2xsaWRlciBwZXJtaXRlIHF1ZSBsYXMgcHVlcnRhcyB0cmFzZXJhcyBlc3TDqW4gY2VycmFkYXMgIm5hdHVyYWxtZW50ZSI6CiQkClgg4oaSIENvbGxpZGVyIOKGkFkKJCQKRXMgZGVjaXIsIGxhIGV4aXN0ZW5jaWEgZGUgdW4gY29sbGlkZXIgZW4gdW4gY2FtaW5vIGhhY2UgcXVlIGF1dG9tYXRpY2FtZW50ZSBjaWVycmEgbG9zIGNhbWlub3MgbyBwdWVydGFzIHRyYXNlcmFzLiAKClNvbiBjcnVjaWFsZXMgcGFyYSByZWNvbm9jZXIgYXNvY2lhY2lvbmVzIGVzcHVyaWFzIGluZHVjaWRhcyBwb3IgYWp1c3RhciBlbCBjb2xpc2lvbmFkb3IsIHB1ZXMgYWp1c3RhciBlbCBjb2xpc2lvbmFkb3IgYWJyZSB1bmEgcHVlcnRhIHRyYXNlcmEuIEFsIGNvbnRyb2xhciBvIGNvbmRpY2lvbmFyIHBvciB1biBjb2xsaWRlciBlbCBjYW1pbm8gcXVlIGVzdGFiYSBjZXJyYWRvIHNlIHZ1ZWx2ZSBhIGFicmlyLiBQb3IgZXN0byBlcyBjcsOtdGljbywgcGFyYSBjdWFscXVpZXIgZXN0cmF0ZWdpYSBkZSBpZGVudGlmaWNhY2nDs24sIGVsIGRpZmVyZW5jaWFyIGVudHJlIHZhcmlhYmxlcyBjb2xsaWRlcnMgeSB2YXJpYWJsZXMgZGUgY29uZnVzacOzbiwgeSBjb250cm9sYXIgcG9yIGVzdGFzIMO6bHRpbWFzIHBlcm8gTk8gcG9yIGxhcyBwcmltZXJvcy4KCkVqZW1wbG86CgpOaXZlbCBkZSBlamVyY2ljaW8gKEUpIHkgZGlldGEgKEQpIGFmZWN0YW5kbyBhbCBwZXNvIGNvcnBvcmFsIChXKS4KClJlcHJlc2VudGFjacOzbjoKJCQKRSDihpIgVyDihpAgRAokJApgYGB7ciBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIERBRyBkZSBDb2xpc2lvbmFkb3IKZGFnX2NvbGxpZGVyIDwtIGRhZ2l0dHkoJ2RhZyB7CiAgRSBbcG9zPSIwLDEiXQogIEQgW3Bvcz0iMSwxIl0KICBXIFtwb3M9IjAuNSwwIl0KICBFIC0+IFcKICBEIC0+IFcKfScpCgpnZ2RhZyhkYWdfY29sbGlkZXIpKyB0aGVtZV9kYWcoKQpgYGAKKio0LiBEQUcgZGUgQ29uZnVzb3IgKENvbmZvdW5kZXIpKioKSW5jbHV5ZSB1bmEgdmFyaWFibGUgY29uZnVzb3JhIHF1ZSBhZmVjdGEgdGFudG8gYSBsYSB2YXJpYWJsZSBkZSBleHBvc2ljacOzbiBjb21vIGEgbGEgdmFyaWFibGUgZGUgcmVzdWx0YWRvLgoKQXl1ZGEgYSBpZGVudGlmaWNhciB5IGFqdXN0YXIgdmFyaWFibGVzIGNvbmZ1c29yYXMgcGFyYSBldml0YXIgc2VzZ29zLiBMYXMgdmFyaWFibGVzIGNvbmZ1c29yYXMgYWJyZW4gY2FtaW5vcyBvIHB1ZXJ0YXMgdHJhc2VyYXMgbm8gZGVzZWFkYXMgZW4gZWwgZWplcmNpY2lvIGRlIGVuY29udHJhciBsYSByZWxhY2lvbiBjYXVzYWwgZW50cmUgdHJhdGFtaWVudG8geSByZXN1bHRhZG8uIAoKCkVqZW1wbG86CgpSZWxhY2nDs24gZW50cmUgZnVtYXIgKEYpLCBleHBvc2ljacOzbiBhIHRveGluYXMgKFQpLCB5IHJpZXNnbyBkZSBjw6FuY2VyIGRlIHB1bG3Ds24gKEMpLgoKUmVwcmVzZW50YWNpw7NuOgokJApUIOKGkiBGCiQkCiQkClQg4oaSIEMKJCQKCiQkCkYg4oaSIEMKJCQKCmBgYHtyIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgREFHIGRlIENvbmZ1c29yCmRhZ19jb25mb3VuZGVyIDwtIGRhZ2l0dHkoJ2RhZyB7CiAgVCBbcG9zPSIwLjUsMSJdCiAgRiBbcG9zPSIwLDAiXQogIEMgW3Bvcz0iMSwwIl0KICBUIC0+IEYKICBUIC0+IEMKICBGIC0+IEMKfScpCgpnZ2RhZyhkYWdfY29uZm91bmRlcikrIHRoZW1lX2RhZygpCmBgYAoKCioqNS4gREFHIGRlIEludGVyYWNjacOzbiAoTW9kZXJhdG9yKSoqClJlcHJlc2VudGEgdW5hIHNpdHVhY2nDs24gZW4gbGEgcXVlIGVsIGVmZWN0byBkZSB1bmEgdmFyaWFibGUgc29icmUgb3RyYSBkZXBlbmRlIGRlIHVuYSB0ZXJjZXJhIHZhcmlhYmxlLgrDmnRpbCBwYXJhIG1vZGVsYXIgZWZlY3RvcyBxdWUgZGVwZW5kZW4gZGUgb3RyYSB2YXJpYWJsZS4KCkVqZW1wbG86CgpSZWxhY2nDs24gZW50cmUgZWplcmNpY2lvIGbDrXNpY28gKEUpLCBsYSBwcmVzZW5jaWEgZGUgdW5hIGNvbmRpY2nDs24gZ2Vuw6l0aWNhIChHKSwgeSBsYSBzYWx1ZCBjYXJkaW92YXNjdWxhciAoSCkuCgpSZXByZXNlbnRhY2nDs246CiQkCkUg4oaSIEgKJCQKCiQkCkcg4oaSIEgKJCQKCiQkCkUg4oaUIEcKJCQKCmBgYHtyLCBlY2hvPUZBTFNFfQojIERBRyBkZSBJbnRlcmFjY2nDs24KZGFnX2ludGVyYWN0aW9uIDwtIGRhZ2l0dHkoJ2RhZyB7CiAgRSBbcG9zPSIwLDAiXQogIEcgW3Bvcz0iMSwwIl0KICBIIFtwb3M9IjAuNSwtMSJdCiAgRSAtPiBICiAgRyAtPiBICiAgRSA8LT4gRwp9JykKCmdnZGFnKGRhZ19pbnRlcmFjdGlvbikrIHRoZW1lX2RhZygpCmBgYAoKKio2LiBEQUcgZGUgTWVkaWFkb3IgKE1lZGlhdG9yKSoqCkluY2x1eWUgdW5hIHZhcmlhYmxlIG1lZGlhZG9yYSBxdWUgdHJhbnNtaXRlIGVsIGVmZWN0byBkZSB1bmEgdmFyaWFibGUgc29icmUgb3RyYS4KQXl1ZGEgYSBlbnRlbmRlciBjw7NtbyBzZSB0cmFuc21pdGUgdW4gZWZlY3RvIGNhdXNhbCBhIHRyYXbDqXMgZGUgdW5hIHZhcmlhYmxlIGludGVybWVkaWFyaWEuCgpFamVtcGxvOgoKUmVsYWNpw7NuIGVudHJlIGxhIG1vdGl2YWNpw7NuIHBhcmVudGFsIChQKSwgZWwgcmVuZGltaWVudG8gYWNhZMOpbWljbyAoUiksIHkgZWwgw6l4aXRvIHByb2Zlc2lvbmFsIChTKS4KClJlcHJlc2VudGFjacOzbjoKJCQKUCDihpIgUiDihpIgUwokJApgYGB7ciwgZWNobz1GQUxTRX0KIyBEQUcgZGUgTWVkaWFkb3IKZGFnX21lZGlhdG9yIDwtIGRhZ2l0dHkoJ2RhZyB7CiAgUCBbcG9zPSIwLDAiXQogIFIgW3Bvcz0iMSwwIl0KICBTIFtwb3M9IjIsMCJdCiAgUCAtPiBSCiAgUiAtPiBTCn0nKQoKZ2dkYWcoZGFnX21lZGlhdG9yKSsgdGhlbWVfZGFnKCkKYGBgCgojIyBFeGlzdGVuY2lhIGRlIEJhY2tkb29yIGVuIHVuYSByZWxhY2lvbiBjYXVzYWwKRW4gZWwgY29udGV4dG8gZGUgbG9zIEdyw6FmaWNvcyBBY8OtY2xpY29zIERpcmlnaWRvcyAoREFHcyksIHVuICJiYWNrZG9vciIgc2UgcmVmaWVyZSBhIHVuIGNhbWlubyBpbmRpcmVjdG8gcXVlIGNvbmVjdGEgbGEgdmFyaWFibGUgZGUgZXhwb3NpY2nDs24gKG8gdHJhdGFtaWVudG8pIGNvbiBsYSB2YXJpYWJsZSBkZSByZXN1bHRhZG8gKG8gZGVzZW5sYWNlKSBhIHRyYXbDqXMgZGUgdW5hIG8gbcOhcyB2YXJpYWJsZXMgaW50ZXJtZWRpYXJpYXMuIEVzdGUgY2FtaW5vIGluZGlyZWN0byBwdWVkZSBpbnRyb2R1Y2lyIHNlc2dvcyBlbiBsYSBlc3RpbWFjacOzbiBkZWwgZWZlY3RvIGNhdXNhbCBzaSBubyBzZSBhanVzdGEgYWRlY3VhZGFtZW50ZS4KCioqQ29uY2VwdG8gZGUgQmFja2Rvb3IgUGF0aCoqClVuIGJhY2tkb29yIHBhdGggZXMgY3VhbHF1aWVyIGNhbWlubyBlbnRyZSBsYSB2YXJpYWJsZSBkZSBleHBvc2ljacOzbiBYIHkgbGEgdmFyaWFibGUgZGUgcmVzdWx0YWRvIFkKcXVlOgoKMS4gTm8gc2lndWUgbGEgZGlyZWNjacOzbiBjYXVzYWwgZGlyZWN0YSBkZSAKJCQKWOKGklkKJCQKCjIuIENvbmVjdGEgWCB5IFkgYSB0cmF2w6lzIGRlIHVuYSBvIG3DoXMgdmFyaWFibGVzIGludGVybWVkaWFyaWFzLCBxdWUgcHVlZGVuIHNlciBjb25mdXNvcmVzLgoKKipFamVtcGxvKioKClJlbGFjaW9uZXMgQ2F1c2FsZXMgZW4gRWR1Y2FjacOzbgpWYXJpYWJsZXM6CgpJOiBOaXZlbCBkZSBpbnRlbGlnZW5jaWEgZGUgdW4gZXN0dWRpYW50ZS4KUzogSG9yYXMgZGUgZXN0dWRpby4KRzogQ2FsaWZpY2FjaW9uZXMgb2J0ZW5pZGFzLgoKUmVsYWNpb25lczoKCkVsIG5pdmVsIGRlIGludGVsaWdlbmNpYSAoSSkgYWZlY3RhIGxhcyBob3JhcyBkZSBlc3R1ZGlvIChTKS4KTGFzIGhvcmFzIGRlIGVzdHVkaW8gKFMpIGFmZWN0YW4gbGFzIGNhbGlmaWNhY2lvbmVzIChHKS4KCiQkCknihpJT4oaSRwokJAoKYGBge3IsIGVjaG89RkFMU0V9CiMgRGVmaW5pciBlbCBEQUcKZGFnIDwtIGRhZ2l0dHkoJ2RhZyB7CiAgSSBbcG9zPSIwLDAiXQogIFMgW3Bvcz0iMSwwIl0KICBHIFtwb3M9IjIsMCJdCiAgSSAtPiBTCiAgUyAtPiBHCn0nKQoKIyBHcmFmaWNhciBlbCBEQUcKZ2dkYWcoZGFnKSArCiAgdGhlbWVfZGFnKCkKYGBgCgpVbiAiYmFja2Rvb3IiIGVzIHVuIGNhbWlubyBhbHRlcm5hdGl2byBlbnRyZSBsYXMgdmFyaWFibGVzIHF1ZSBwb2Ryw61hIGludHJvZHVjaXIgc2VzZ28gc2kgbm8gc2UgY29udHJvbGEgYWRlY3VhZGFtZW50ZS4KClZhbW9zIGEgYcOxYWRpciB1bmEgbnVldmEgdmFyaWFibGUgUCAobW90aXZhY2nDs24gcGFyZW50YWwpLCBxdWUgYWZlY3RhIHRhbnRvIGVsIG5pdmVsIGRlIGludGVsaWdlbmNpYSBJIGNvbW8gbGFzIGhvcmFzIGRlIGVzdHVkaW8gUy4KClJlbGFjaW9uZXM6CgpMYSBtb3RpdmFjacOzbiBwYXJlbnRhbCAoUCkgYWZlY3RhIHRhbnRvIGVsIG5pdmVsIGRlIGludGVsaWdlbmNpYSAoSSkgY29tbyBsYXMgaG9yYXMgZGUgZXN0dWRpbyAoUykuCkVsIG5pdmVsIGRlIGludGVsaWdlbmNpYSAoSSkgYWZlY3RhIGxhcyBob3JhcyBkZSBlc3R1ZGlvIChTKS4KTGFzIGhvcmFzIGRlIGVzdHVkaW8gKFMpIGFmZWN0YW4gbGFzIGNhbGlmaWNhY2lvbmVzIChHKS4KCmBgYHtyLCBlY2hvPUZBTFNFfQojIERlZmluaXIgZWwgREFHIGNvbiBlbCBiYWNrZG9vcgpkYWcgPC0gZGFnaXR0eSgnZGFnIHsKICBQIFtwb3M9IjAuNSwxIl0KICBJIFtwb3M9IjAsMCJdCiAgUyBbcG9zPSIxLDAiXQogIEcgW3Bvcz0iMiwwIl0KICBQIC0+IEkKICBQIC0+IFMKICBJIC0+IFMKICBTIC0+IEcKfScpCgojIEdyYWZpY2FyIGVsIERBRwpnZ2RhZyhkYWcpICsKICB0aGVtZV9kYWcoKQpgYGAKCkVuIGVzdGUgbnVldm8gREFHLCBsYSBtb3RpdmFjacOzbiBwYXJlbnRhbCAoUCkgaW50cm9kdWNlIHVuICJiYWNrZG9vciIgZW50cmUgSSB5IFMuIEVzdG8gc2lnbmlmaWNhIHF1ZSBzaSBubyBjb250cm9sYW1vcyBwb3IgUCwgY3VhbHF1aWVyIGFuw6FsaXNpcyBxdWUgYnVzcXVlIGVudGVuZGVyIGxhIHJlbGFjacOzbiBlbnRyZSBJIHkgUyBwb2Ryw61hIGVzdGFyIHNlc2dhZG8gZGViaWRvIGEgbGEgaW5mbHVlbmNpYSBkZSBQLgoKUGFyYSBvYnRlbmVyIHVuYSBlc3RpbWFjacOzbiBubyBzZXNnYWRhIGRlbCBlZmVjdG8gY2F1c2FsIGRlIEkgc29icmUgUyB5IGRlIFMgc29icmUgRywgbmVjZXNpdGFyw61hbW9zIGFqdXN0YXIgcG9yIFAuCgoqKkFqdXN0ZSBwYXJhIEVsaW1pbmFyIGVsIEJhY2tkb29yIFBhdGgqKgpQYXJhIGVsaW1pbmFyIGVsIHNlc2dvIGludHJvZHVjaWRvIHBvciBlbCBiYWNrZG9vciBwYXRoLCBzZSBkZWJlIGFqdXN0YXIgcG9yIGxhIHZhcmlhYmxlIGNvbmZ1c29yYSBQLiBFc3RvIHNlIHB1ZWRlIGhhY2VyIG1lZGlhbnRlOgoKRXN0cmF0aWZpY2FjacOzbjogRGl2aWRpciBsb3MgZGF0b3MgZW4gZXN0cmF0b3Mgc2Vnw7puIGxvcyB2YWxvcmVzIGRlIFAgeSBhbmFsaXphciBjYWRhIGVzdHJhdG8gcG9yIHNlcGFyYWRvLgoKUmVncmVzacOzbjogSW5jbHVpciBQIGNvbW8gY292YXJpYWJsZSBlbiB1biBtb2RlbG8gZGUgcmVncmVzacOzbi4KCkVtcGFyZWphbWllbnRvOiBFbXBhcmVqYXIgaW5kaXZpZHVvcyBjb24gdmFsb3JlcyBzaW1pbGFyZXMgZGUgUCBwYXJhIGNvbXBhcmFyIGxvcyBlZmVjdG9zIGRlIApJIHNvYnJlIEcuCgojIyBJbmRlcGVuZGVuY2lhIGNvbmRpY2lvbmFsCgpMYSBpbmRlcGVuZGVuY2lhIGNvbmRpY2lvbmFsIGVzIHVuIGNvbmNlcHRvIGZ1bmRhbWVudGFsIGVuIGVsIGFuw6FsaXNpcyBjYXVzYWwgeSBzZSByZXByZXNlbnRhIGRlIG1hbmVyYSBuYXR1cmFsIGVuIGxvcyBHcsOhZmljb3MgQWPDrWNsaWNvcyBEaXJpZ2lkb3MgKERBR3MpLiBFbiB1biBEQUcsIGxhIGluZGVwZW5kZW5jaWEgY29uZGljaW9uYWwgc2UgdXRpbGl6YSBwYXJhIGlkZW50aWZpY2FyIGN1YWxlcyB2YXJpYWJsZXMgc29uIGluZGVwZW5kaWVudGVzIHVuYXMgZGUgb3RyYXMgZGFkbyB1biBjb25qdW50byBkZSB2YXJpYWJsZXMgY29uZGljaW9uYW50ZXMuCgoqKkRlZmluaWNpw7NuOioqCgpEb3MgdmFyaWFibGVzIFggeSBZIHNvbiBjb25kaWNpb25hbG1lbnRlIGluZGVwZW5kaWVudGVzIGRhZGFzIHVuYSB0ZXJjZXJhIHZhcmlhYmxlIFouIEVuIG5vdGFjacOzbiwgZXN0byBzZSBlc2NyaWJlIGNvbW86IAoKJCQKWOKKpVniiKMgWiAKJCQKCkVuIHVuIERBRzoKCkxhIGluZGVwZW5kZW5jaWEgY29uZGljaW9uYWwgc2UgcHVlZGUgbGVlciBkaXJlY3RhbWVudGUgZGVsIERBRyB1dGlsaXphbmRvIGVsIGNyaXRlcmlvIGRlIGQtc2VwYXJhY2nDs24gKGQtc2VwYXJhdGlvbikuIFNpIHVuIGNvbmp1bnRvIGRlIHZhcmlhYmxlcyBaIGJsb3F1ZWEgdG9kb3MgbG9zIGNhbWlub3MgZW50cmUgWCB5IFksIGVudG9uY2VzIFggeSBZIHNvbiBjb25kaWNpb25hbG1lbnRlIGluZGVwZW5kaWVudGVzIGRhZG8gWi4KCiMjIyBUaXBvcyBkZSBEQUdzIHF1ZSBSZXByZXNlbnRhbiBJbmRlcGVuZGVuY2lhIENvbmRpY2lvbmFsCgoqKkRBRyBEaXJlY3RvIChEaXJlY3QgQ2F1c2FsIFBhdGh3YXkpOioqCkVuIHVuIERBRyBkaXJlY3RvIHNpbiB2YXJpYWJsZXMgaW50ZXJtZWRpYXJpYXMgbmkgY29uZnVzb3JlcywgbGEgcmVsYWNpw7NuIGRpcmVjdGEgZW50cmUgZG9zIHZhcmlhYmxlcyBpbXBsaWNhIHF1ZSBubyBoYXkgaW5kZXBlbmRlbmNpYSBjb25kaWNpb25hbCBzaW4gaW50ZXJ2ZW5jacOzbi4KCioqREFHIGRlIENhZGVuYSAoQ2hhaW4pOioqCkVuIHVuIERBRyBkZSBjYWRlbmEsIGRvcyB2YXJpYWJsZXMgWCB5IFkgcHVlZGVuIHNlciBpbmRlcGVuZGllbnRlcyBzaSBjb25kaWNpb25hbW9zIGVuIGxhIHZhcmlhYmxlIGludGVybWVkaWEgWi4KCiQkClgg4oaSIFog4oaSIFkKJCQKQXF1w60sIFggeSBZIHNvbiBjb25kaWNpb25hbG1lbnRlIGluZGVwZW5kaWVudGVzIGRhZG8gWi4KCioqREFHIGRlIENvbGlzaW9uYWRvciAoQ29sbGlkZXIpOioqCkVuIHVuIERBRyBkZSBjb2xpc2lvbmFkb3IsIGRvcyB2YXJpYWJsZXMgWCB5IFkgc29uIGluZGVwZW5kaWVudGVzIGEgbWVub3MgcXVlIHNlIGNvbmRpY2lvbmUgZW4gbGEgdmFyaWFibGUgY29saXNpb25hZG9yYSBaIG8gZW4gc3VzIGRlc2NlbmRpZW50ZXMuCgokJApYIOKGkiBaIOKGkCBZCiQkCkFxdcOtLCBYIHkgWSBzb24gaW5kZXBlbmRpZW50ZXMgYSBtZW5vcyBxdWUgY29uZGljaW9uZW1vcyBlbiBaLgoKKipEQUcgY29uIENvbmZ1c29yIChDb25mb3VuZGVyKToqKgoKRW4gdW4gREFHIGNvbiB1biBjb25mdXNvciwgbGFzIHZhcmlhYmxlcyBwdWVkZW4gdm9sdmVyc2UgY29uZGljaW9uYWxtZW50ZSBpbmRlcGVuZGllbnRlcyBjdWFuZG8gc2UgYWp1c3RhIHBvciBlbCBjb25mdXNvci4KCiQkClog4oaSIFgKJCQKJCQKWiDihpIgWQokJAoKJCQKWCDihpIgWQokJApBcXXDrSwgWCB5IFkgcHVlZGVuIHNlciBpbmRlcGVuZGllbnRlcyBzaSBhanVzdGFtb3MgcG9yIFouCgojIyBDb25kaWNpb25hciAoY29udHJvbGFyKSBlbiB1biBEQUcKCkVuIHVuIERBRywgZW50ZW5kZXIgY3XDoW5kbyB5IGPDs21vIGNvbmRpY2lvbmFyIGVuIHVuYSB2YXJpYWJsZSBlcyBjcnVjaWFsIHBhcmEgZWwgYW7DoWxpc2lzIGRlIHJlbGFjaW9uZXMgY2F1c2FsZXMuIAoKKipQYXJhIENvbnRyb2xhciBwb3IgQ29uZnVzacOzbiAoQ29uZm91bmRpbmcpOioqIENvbmRpY2lvbmFyIGVuIHZhcmlhYmxlcyBxdWUgcHVlZGVuIGFjdHVhciBjb21vIGNvbmZ1c29yZXMgYXl1ZGEgYSBvYnRlbmVyIHVuYSBlc3RpbWFjacOzbiBubyBzZXNnYWRhIGRlbCBlZmVjdG8gY2F1c2FsLgoKKipQYXJhIEJsb3F1ZWFyIFJ1dGFzIE5vIERlc2VhZGFzOioqIEEgdmVjZXMsIG5lY2VzaXRhbW9zIGJsb3F1ZWFyIHJ1dGFzIGluZGlyZWN0YXMgcXVlIG5vIGZvcm1hbiBwYXJ0ZSBkZWwgZWZlY3RvIGNhdXNhbCBkZSBpbnRlcsOpcy4KClJlY29yZGFyIGxvcyBzaWd1aWVudGVzIGNvbmNlcHRvcyBDbGF2ZToKCkNvbmZvdW5kZXJzOiBWYXJpYWJsZXMgcXVlIGFmZWN0YW4gdGFudG8gYSBsYSB2YXJpYWJsZSBkZSBleHBvc2ljacOzbiBjb21vIGEgbGEgZGUgcmVzdWx0YWRvLiBDb25kaWNpb25hciBlbiBjb25mb3VuZGVycyBheXVkYSBhIG9idGVuZXIgdW5hIHJlbGFjacOzbiBjYXVzYWwgbcOhcyBwcmVjaXNhLgoKQ29sbGlkZXJzOiBOb2RvcyBlbiBsb3MgcXVlIGRvcyBhcmlzdGFzIGNvbnZlcmdlbi4gQ29uZGljaW9uYXIgZW4gY29sbGlkZXJzIHB1ZWRlIGluZHVjaXIgdW5hIGFzb2NpYWNpw7NuIG5vIGNhdXNhbCBlbnRyZSBsYXMgdmFyaWFibGVzIGRlIGVudHJhZGEuCgpOb24tQ29sbGlkZXJzOiBOb2RvcyBxdWUgbm8gc29uIGNvbGxpZGVycywgZ2VuZXJhbG1lbnRlIHNlIHJlY29taWVuZGEgbm8gY29uZGljaW9uYXIgZW4gZWxsb3MgYSBtZW5vcyBxdWUgc2UgbmVjZXNpdGUgcGFyYSBibG9xdWVhciB1bmEgcnV0YSBubyBkZXNlYWRhLgoKIyMjIEVqZW1wbG9zCgoxLiBDb25kaWNpb25hciBwYXJhIENvbnRyb2xhciBwb3IgQ29uZnVzacOzbgoKREFHIEVqZW1wbG86CiQkClQgPC0gUyAtPiBJIC0+IFAKJCQKCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CmNvbmZ1c2lvbiA8LSBkYWdpdHR5KCdkYWcgewogICAgVCA8LSBTIC0+IEkgLT4gUAogICAgCiB9JykKcGxvdChjb25mdXNpb24pCgpgYGAKUyBlcyB1biBjb25mb3VuZGVyLCB5YSBxdWUgYWZlY3RhIHRhbnRvIGEgVCAoaW50ZXJ2ZW50aW9uKSBjb21vIGEgUCAob3V0Y29tZSkgYSB0cmF2w6lzIGRlIEkuClBhcmEgb2J0ZW5lciB1bmEgcmVsYWNpw7NuIG5vIHNlc2dhZGEgZW50cmUgVCB5IFAsIGRlYmVtb3MgY29uZGljaW9uYXIgZW4gUy4KCkNvbmRpY2lvbmVtb3MgYWhvcmEgUzoKCmBgYHtyfQojIERlZmluaXIgdW4gREFHIHNpbXBsZQpkYWdfc2ltcGxlIDwtIGRhZ2lmeSgKICBQIH4gVCArIFMsICAjIERlc2VtcGXDsW8gaW5mbHVlbmNpYWRvIHBvciBlbCBUaXBvIGRlIFByb2dyYW1hIHkgTml2ZWwgU29jaW9lY29uw7NtaWNvCiAgVCB+IFMsICAgICAgIyBUaXBvIGRlIFByb2dyYW1hIGluZmx1ZW5jaWFkbyBwb3IgZWwgTml2ZWwgU29jaW9lY29uw7NtaWNvCiAgb3V0Y29tZT0iUCIsCiAgZXhwb3N1cmUgPSAiVCIsCiAgbGFiZWxzID0gYygiVCIgPSAiVGlwbyBkZSBQcm9ncmFtYSIsCiAgICAgICAgICAgICAiUCIgPSAiRGVzZW1wZcOxbyBBY2Fkw6ltaWNvIiwKICAgICAgICAgICAgICJTIiA9ICJOaXZlbCBTb2Npb2Vjb27Ds21pY28iKQopCgpgYGAKCmBgYHtyfQojIENvbnZlcnRpciBlbCBEQUcgYSB1biBvYmpldG8gZGFnaXR0eQpkYWdpdHR5X2RhZyA8LSBhcy5kYWdpdHR5KGRhZ19zaW1wbGUpCmBgYAoKYGBge3J9CiMgVmlzdWFsaXphciBlbCBEQUcKZ2dkYWcoZGFnaXR0eV9kYWcpICsgdGhlbWVfZGFnKCkKYGBgCgpBaG9yYSwgcmVhbGl6YW1vcyBlbCBhbsOhbGlzaXMgZGUgcGF0aHMgcGFyYSB2ZXIgY8OzbW8gbGFzIHJ1dGFzIGVzdMOhbiBhZmVjdGFkYXMgcG9yIGNvbmRpY2lvbmFyIGVuIFMuCgpgYGB7cn0KIyBSZWFsaXphciBlbCBhbsOhbGlzaXMgZGUgcGF0aHMgZGVzZGUgVCBoYXN0YSBQCnBhdGhzKGRhZ2l0dHlfZGFnLCBmcm9tID0gIlQiLCB0byA9ICJQIikKCmBgYApTaW4gQ29uZGljaW9uYXIgZW4gUwoKUnV0YSBkaXJlY3RhOiBUIC0+IFAKUnV0YSBpbmRpcmVjdGE6IFQgPC0gUyAtPiBQCgpBbWJhcyBydXRhcyBlc3TDoW4gYWJpZXJ0YXMuIExhIHJ1dGEgZGlyZWN0YSBUIC0+IFAgeSBsYSBydXRhIGluZGlyZWN0YSBUIDwtIFMgLT4gUCBlc3TDoW4gYWJpZXJ0YXMsIGxvIHF1ZSBzaWduaWZpY2EgcXVlIFMgcHVlZGUgZXN0YXIgY29uZnVuZGnDqW5kb25vcyBzb2JyZSBsYSB2ZXJkYWRlcmEgcmVsYWNpw7NuIGVudHJlIFQgeSBQLgoKQ29uZGljaW9uYW5kbyBlbiBTCgpBbCBjb25kaWNpb25hciBlbiBTLCBibG9xdWVhbW9zIGxhIHJ1dGEgVCA8LSBTIC0+IFAsIGxvIHF1ZSBub3MgcGVybWl0ZSBlc3RpbWFyIGVsIGVmZWN0byBkaXJlY3RvIGRlIFQgZW4gUC4KClBhcmEgZXN0byB1dHVsaXphbW9zIGxhIGZ1bmNpW29uIGFkanVzdG1lbnRTZXRzIHF1ZSBub3MgYXl1ZGEgYSBlbmNvbnRhciBlbCBzZXQgbWluaW1vIHN1ZmljaWVudGUgKiooTWluaW1hbGx5IFN1ZmZpY2llbnQgU2V0dCkqKgoKYGBge3J9CiMgSWRlbnRpZmljYXIgbG9zIGNvbmp1bnRvcyBkZSBhanVzdGUgcGFyYSBjb250cm9sYXIgY29uZnVzacOzbgphZGp1c3RtZW50U2V0cyhkYWdpdHR5X2RhZywgZXhwb3N1cmUgPSAiVCIsIG91dGNvbWUgPSAiUCIpCgpnZ2RhZ19hZGp1c3RtZW50X3NldChkYWdpdHR5X2RhZywgdGV4dCA9IEZBTFNFLCB1c2VfbGFiZWxzID0gImxhYmVsIiwgCiAgICAgICAgICAgICAgICAgICAgIHNoYWRvdyA9IFRSVUUsIHN0eWxpemVkID0gVFJVRSwgbm9kZV9zaXplID0gMTAsICAgdGV4dF9zaXplID0gMi44KQpgYGAKCgoyLiBDb25kaWNpb25hciBwYXJhIEJsb3F1ZWFyIFJ1dGFzIE5vIERlc2VhZGFzCgpEQUcgRWplbXBsbzoKJCQKVCAtPiBJIC0+IFAKJCQKJCQKUyAtPiBJCiQkCgpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKYmxvcXVlYXJfcnV0YXMgPC0gZGFnaXR0eSgnZGFnIHsKICAgIFQgLT4gSSAtPiBQCiAgICBTIC0+IEkKICAgICB9JykKcGxvdChibG9xdWVhcl9ydXRhcykKCmBgYAoKSSBlcyB1biBub2RvIGVuIHVuYSBydXRhIGluZGlyZWN0YSBkZSBUIGEgUC4KClNpIHF1ZXJlbW9zIGJsb3F1ZWFyIGVzdGEgcnV0YSwgcG9kcsOtYW1vcyBjb25kaWNpb25hciBlbiBJIHBhcmEgb2J0ZW5lciBsYSByZWxhY2nDs24gZGlyZWN0YSBlbnRyZSBUIHkgUC4KCkVuIHJlc3VtZW4sIGNvbmRpY2lvbmFyIGVuIHVuYSB2YXJpYWJsZSBzaWduaWZpY2EgYWp1c3RhciBwb3IgZWxsYSBlbiBlbCBhbsOhbGlzaXMgcGFyYSBjb250cm9sYXIgc3UgaW5mbHVlbmNpYSB5IG9idGVuZXIgcmVsYWNpb25lcyBjYXVzYWxlcyBtw6FzIHByZWNpc2FzLiBFcyB1bmEgcHLDoWN0aWNhIGZ1bmRhbWVudGFsIGVuIGxhIG1vZGVsaXphY2nDs24gY2F1c2FsIHkgZGViZSBzZXIgdXRpbGl6YWRhIGVzdHJhdMOpZ2ljYW1lbnRlIHBhcmEgYXNlZ3VyYXIgbGEgdmFsaWRleiBkZSBsb3MgcmVzdWx0YWRvcy4gQSBtb2RvIGRlIGNvbmNsdXNpw7NuOgoKKipDb25kaWNpb25hciBlbiBDb25mb3VuZGVyczoqKiBFc3RvIGF5dWRhIGEgZWxpbWluYXIgbGEgY29uZnVzacOzbiB5IG9idGVuZXIgdW5hIGVzdGltYWNpw7NuIGNhdXNhbCBwcmVjaXNhLgoqKkNvbmRpY2lvbmFyIGVuIENvbGxpZGVyczoqKiBHZW5lcmFsbWVudGUgbm8gc2UgZGViZSBoYWNlciwgeWEgcXVlIHB1ZWRlIGluZHVjaXIgYXNvY2lhY2lvbmVzIG5vIGNhdXNhbGVzLgoqKkNvbmRpY2lvbmFyIGVuIE5vbi1Db2xsaWRlcnM6Kiogw5p0aWwgcGFyYSBibG9xdWVhciBydXRhcyBubyBkZXNlYWRhcyBvIHBhcmEgY29udHJvbGFyIGNvbmZ1c2nDs24uCgojIyBELVNlcGFyYXRlZCB5IEQtQ29ubmVjdGVkIFBhdGhzCgpFbiBlbCBjb250ZXh0byBkZSBsb3MgREFHcyAoR3JhcGhvcyBBY8OtY2xpY29zIERpcmlnaWRvcyksIGxvcyBjb25jZXB0b3MgZGUgZC1zZXBhcmF0ZWQgeSBkLWNvbm5lY3RlZCBzb24gY3J1Y2lhbGVzIHBhcmEgZW50ZW5kZXIgY8OzbW8gbGFzIHZhcmlhYmxlcyBlc3TDoW4gcmVsYWNpb25hZGFzIHkgY8OzbW8gbGEgaW5mb3JtYWNpw7NuIHNlIHRyYW5zbWl0ZSBhIHRyYXbDqXMgZGVsIG1vZGVsby4KCioqMS4gRC1TZXBhcmF0ZWQgUGF0aHMqKgpEb3MgdmFyaWFibGVzIGVzdMOhbiBkLXNlcGFyYXRlZCBzaSwgZGFkbyBlbCBjb25vY2ltaWVudG8gZGUgY2llcnRhcyBvdHJhcyB2YXJpYWJsZXMsIG5vIGhheSBuaW5ndW5hIHJ1dGEgYWN0aXZhIChlcyBkZWNpciwgbmluZ3VuYSBydXRhIGEgdHJhdsOpcyBkZSBsYSBjdWFsIGxhIGluZm9ybWFjacOzbiBwdWVkYSBmbHVpcikgZW50cmUgZWxsYXMuIEVuIG90cmFzIHBhbGFicmFzLCBsYXMgdmFyaWFibGVzIGVzdMOhbiBpbmRlcGVuZGllbnRlbWVudGUgY29uZGljaW9uYWRhcyBwb3Igb3RyYXMgdmFyaWFibGVzIGVuIGVsIERBRy4KCioqQ8OzbW8gRGV0ZXJtaW5hciBsYSBELVNlcGFyYXRpb246KioKCioqVmFyaWFibGUgZGUgQWp1c3RlOioqIFBhcmEgcXVlIGRvcyB2YXJpYWJsZXMgZXN0w6luIGQtc2VwYXJhZGFzLCBzZSBkZWJlIGFqdXN0YXIgcG9yIGNpZXJ0YXMgdmFyaWFibGVzIHF1ZSAiYmxvcXVlYW4iIHRvZGFzIGxhcyBydXRhcyBlbnRyZSBlbGxhcy4KCioqQ29saXNpb25hZG9yZXMgeSBDb25mdXNvcmVzOioqClVuYSBydXRhIGVzdMOhIGJsb3F1ZWFkYSBzaSBwYXNhIHBvciB1biBjb2xpc2lvbmFkb3IgeSBubyBzZSBhanVzdGEgcG9yIGVsIGNvbGlzaW9uYWRvciBuaSBwb3Igc3VzIGRlc2NlbmRpZW50ZXMuCgpVbmEgcnV0YSB0YW1iacOpbiBwdWVkZSBlc3RhciBibG9xdWVhZGEgc2kgcGFzYSBwb3IgdW4gY29uZnVzb3IgeSBzZSBhanVzdGEgcG9yIGVsIGNvbmZ1c29yLgoKRWplbXBsbzogRW4gdW4gREFHIGRvbmRlIFggLT4gWiA8LSBZLCBYIHkgWSBlc3TDoW4gZC1zZXBhcmFkb3MgZGFkbyBaLiBMYSBpbmZvcm1hY2nDs24gbm8gZmx1eWUgZW50cmUgWCB5IFkgc2kgWiBlcyBjb25vY2lkby4KCioqMi4gRC1Db25uZWN0ZWQgUGF0aHMqKgoKRG9zIHZhcmlhYmxlcyBlc3TDoW4gZC1jb25lY3RhZGFzIHNpIGV4aXN0ZSB1bmEgcnV0YSBhY3RpdmEgZW50cmUgZWxsYXMsIGVzIGRlY2lyLCBzaSBubyBoYXkgbmluZ3VuYSBydXRhIGJsb3F1ZWFkYSBwb3IgbGFzIHZhcmlhYmxlcyBjb25kaWNpb25hZGFzLiBFbiBvdHJhcyBwYWxhYnJhcywgbGEgaW5mb3JtYWNpw7NuIHB1ZWRlIGZsdWlyIGVudHJlIGxhcyBkb3MgdmFyaWFibGVzIGEgdHJhdsOpcyBkZSB1bmEgbyBtw6FzIHJ1dGFzIGVuIGVsIERBRy4KCioqQ8OzbW8gRGV0ZXJtaW5hciBsYSBELUNvbm5lY3Rpb246KioKCioqQ29saXNpb25hZG9yZXMgeSBDb25mdXNvcmVzOioqClVuYSBydXRhIGVzIGFjdGl2YSBzaSBwYXNhIHBvciB1biBjb25mdXNvciB5IHNlIGFqdXN0YSBwb3Igw6lsLgpVbmEgcnV0YSBlcyBhY3RpdmEgc2kgcGFzYSBwb3IgdW4gY29saXNpb25hZG9yIHkgZWwgY29saXNpb25hZG9yIChvIHN1cyBkZXNjZW5kaWVudGVzKSBubyBzZSBhanVzdGEgcG9yIMOpbC4KCkVqZW1wbG86IEVuIHVuIERBRyBkb25kZSBYIC0+IFogLT4gWSB5IHNlIGFqdXN0YSBwb3IgWiwgWCB5IFkgZXN0w6FuIGQtY29uZWN0YWRvcyBhIHRyYXbDqXMgZGUgWi4gTGEgaW5mb3JtYWNpw7NuIHB1ZWRlIGZsdWlyIGRlIFggYSBZIGEgdHJhdsOpcyBkZSBaLgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KICMgRGVmaW5pciB1biBEQUcgc2ltcGxlCmRhZ19leGFtcGxlIDwtIGRhZ2lmeSgKICBZIH4gWCArIFosCiAgWiB+IFgsCiAgb3V0Y29tZT0gIlkiLAogIGV4cG9zdXJlPSAiWCIsCiAgbGFiZWxzID0gYygiWCIgPSAiVmFyaWFibGUgWCIsCiAgICAgICAgICAgICAiWSIgPSAiVmFyaWFibGUgWSIsCiAgICAgICAgICAgICAiWiIgPSAiVmFyaWFibGUgWiIpCikKCiMgQ29udmVydGlyIGVsIERBRyBhIHVuIG9iamV0byBkYWdpdHR5CmRhZ2l0dHlfZGFnIDwtIGFzLmRhZ2l0dHkoZGFnX2V4YW1wbGUpCgojIFZpc3VhbGl6YXIgZWwgREFHCmdnZGFnKGRhZ2l0dHlfZGFnKSArIHRoZW1lX2RhZygpCmBgYAoKCmBgYHtyfQoKCiMgQW5hbGl6YXIgbGEgZC1zZXBhcmF0aW9uIGVudHJlIFggeSBZIGRhZG8gWiB1c2FuZG8gZ2dkYWdfZHJlbGF0aW9uc2hpcApnZ2RhZ19kcmVsYXRpb25zaGlwKGRhZ2l0dHlfZGFnLCBjb250cm9sbGluZ19mb3IgID0gIloiLCB0ZXh0ID0gRkFMU0UsIHVzZV9sYWJlbHMgPSAibGFiZWwiLCAgICAgICAgICAgICAgICAgICAgIHN0eWxpemVkID0gVFJVRSwgbm9kZV9zaXplID0gMTAsICAgdGV4dF9zaXplID0gMi44LCBlZGdlX3R5cGU9ImxpbmtfYXJjIikKCmBgYAoKCmBgYAoKCg==