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:
No sigue la dirección causal directa de \[
X→Y
\]
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
- 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)

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