Capítulo 12 Cuadernos y Markdown

Me preguntas si llevo un cuaderno para anotar mis grandes ideas. Solo he tenido uno.
Albert Einstein

12.1 ¿Qué es un cuaderno (Notebook) ?

R es todopoderoso para la manipulación, visualización y análisis de datos. Lo que a menudo se subestima es la flexibilidad con la que se pueden exportar o informar los análisis.

Por ejemplo, se puede escribir fácilmente un artículo científico completo, un informe de la industria o una actualización mensual para acomodar un conjunto de datos subyacente variable, y todas las tablas y gráficos se actualizarán automáticamente.

Esta idea se puede extender a un flujo de trabajo en el que todos los análisis se realizan principalmente dentro de un documento que funciona como el informe final.

¡Ingrese a “Cuadernos de datos”! Los cuadernos son documentos que combinan código y elementos de texto enriquecido, como encabezados, párrafos y enlaces, en un solo documento. Combinan análisis e informes en un documento legible por humanos para proporcionar una interfaz intuitiva entre el investigador y su análisis (Figura 12.1 ). Esto a veces se denomina “programación alfabetizada”, dado que la estructura lógica resultante de la información se puede leer fácilmente de la misma manera que un humano leería un libro.

FIGURA 12.1: Programación tradicional versus alfabetizada usando Notebooks.

En nuestro propio trabajo, ahora hemos pasado a realizar la mayoría de nuestros análisis en un archivo de Notebook, en lugar de usar un archivo de “script”. Puede que no lo hayas adivinado, pero todo este libro está escrito de esta manera.

Algunas de las ventajas de la interfaz de Notebook son:

  • el código y la salida son adyacentes entre sí, por lo que no está cambiando constantemente entre “paneles”;
  • más fácil de trabajar en una pantalla más pequeña, por ejemplo, una computadora portátil;
  • la documentación y los informes se pueden realizar junto con el código, los elementos de texto se pueden formatear por completo;
  • el código en sí se puede mostrar u ocultar;
  • el código no se limita a R; puede usar Python, SQL, etc.;
  • facilitar la colaboración compartiendo fácilmente documentos de análisis legibles por humanos;
  • se puede generar en varios formatos, incluidos HTML (página web), PDF y Microsoft Word;
  • la salida se puede extender a otros formatos como presentaciones;
  • la capacitación/aprendizaje puede ser más fácil ya que los materiales del curso, los ejemplos y las notas de los estudiantes están todos en el mismo documento.

12.2 ¿Qué es Markdown?

Markdown es un lenguaje ligero que se puede utilizar para escribir documentos con formato completo. Es texto sin formato y utiliza un conjunto simple de reglas para producir resultados bastante sofisticados. ¡Nos encanta!

Es fácil formatear encabezados, texto en negrita, cursiva, etc. Dentro de RStudio hay una guía de referencia rápida (Figura 12.2 ) y se pueden encontrar enlaces a las hojas de trucos de RStudio en el menú desplegable Ayuda.

FIGURA 12.2: Guía de referencia rápida de RStudio Markdown.

Markdown existe independientemente de R y es utilizado por una variedad de técnicos y similares. Una combinación de Markdown (que es texto con caracteres especiales para indicar el formato deseado) y el código R que contiene (generalmente para producir tablas y gráficos) se denomina R Markdown. Los scripts R tienen la extensión de archivo .R,los documentos Markdown tienen una extensión de archivo .md, por lo tanto, los documentos R Markdown son.Rmd.

12.3 ¿Cuál es la diferencia entre un Notebook y un archivo R Markdown?

La mayoría de la gente usa los términos R Notebook y R Markdown indistintamente y eso está bien. Técnicamente, R Markdown es un archivo, mientras que R Notebook es una forma de trabajar con archivos R Markdown. Los cuadernos R no tienen su propio formato de archivo, todos usan .Rmd. Todos los cuadernos de R se pueden ‘tejer’ a las salidas de R Markdown, y todos los documentos de R Markdown se pueden interconectar como un cuaderno.

Una diferencia importante está en la ejecución del código. En R Markdown, cuando el archivo es Knit, también se ejecutan todos los elementos (fragmentos). Knit es para R Markdown lo que Source es para un script R (Source se presentó en el Capítulo 1, esencialmente significa ‘Ejecutar todas las líneas’).

En un Notebook, cuando el archivo se procesa con el Preview botón, no se vuelve a ejecutar ningún código, solo se incluye en la salida el que ya se ha ejecutado y está presente en el documento. Además, en el archivo detrás de escena de Notebook ( .nb), siempre se incluye todo el código. Algo a tener en cuenta si su código contiene información confidencial, como una contraseña (¡que nunca debería!).

12.4 Cuaderno vs HTML vs PDF vs Word

En RStudio, se puede crear un Notebook yendo a: Archivo -> Nuevo archivo -> R Notebook

Alternativamente, puede crear un archivo Markdown usando: Archivo -> Nuevo archivo -> R Markdown…

No te preocupes cuál eliges. Como se mencionó anteriormente, son esencialmente lo mismo pero vienen con diferentes opciones. Es fácil cambiar de un Notebook a un archivo Markdown si desea crear un documento PDF o Word, por ejemplo.

Si realiza análisis principalmente en el entorno de Notebook, elija Notebook. Si está creando principalmente un documento PDF o Word, elija el archivo R Markdown.

12.5 La anatomía de un archivo Notebook / R Markdown

Cuando crea un archivo, se proporciona una plantilla útil para que pueda comenzar. La figura 12.3 muestra los elementos esenciales de un archivo de Notebook y cómo se traducen en la HTML vista previa.

12.5.1 Encabezado YAML

Cada archivo de Notebook y Markdown requiere un “encabezado YAML”. ¿De dónde obtienen estos términos que pides? Originalmente, se decía que YAML significaba otro lenguaje de marcas, haciendo referencia a su propósito como lenguaje de marcas. Más tarde se reutilizó como YAML Ain’t Markup Language, un acrónimo recursivo, para distinguir su propósito como orientado a datos en lugar de marcado de documentos (gracias Wikipedia).

Aquí es simplemente donde se colocan muchas de las configuraciones/opciones para la creación de archivos. En RStudio, estos a menudo se actualizan automáticamente a medida que se invocan diferentes configuraciones en el menú Opciones.

FIGURA 12.3: La anatomía de un archivo Notebook/Markdown. Entrada (izquierda) y salida (derecha).

12.5.2 Fragmentos de código R

El código R dentro de un archivo Notebook o Markdown se puede incluir de dos maneras:

  • en línea: por ejemplo, el número total de naranjas fue `r sum(fruit$oranges)`;
  • como un “chunk (trozo)”.

Los fragmentos R son flexibles, vienen con muchas opciones y pronto aprenderá a usarlos.

La figura 12.3 muestra cómo encaja un trozo en el documento.

# Esta es una parte básica.
# Siempre comienza con ```{r}
# Y termina con ```
# El código va aquí
sum(fruit$oranges)

Esto puede parecer desagradable, pero sigue adelante por ahora. Puede escribir los cuatro acentos graves manualmente o usar el Insert botón y elegir R. También notará que los fragmentos no se limitan al código R. Es particularmente útil que Python también se pueda ejecutar de esta manera.

Al realizar un análisis en un cuaderno, casi siempre querrá ver el código y el resultado. Cuando esté creando un documento final, es posible que desee ocultar el código. El comportamiento de los fragmentos se puede controlar a través Chunk Cogdela parte derecha del fragmento (Figura 12.3 ).

La tabla 12.1 muestra las diversas permutaciones de código y opciones de salida que están disponibles. El código se coloca en el encabezado del fragmento, pero las opciones emergentes ahora lo hacen automáticamente, por ejemplo,

12.5.3 Configuración de opciones de fragmentos predeterminados

Podemos establecer opciones predeterminadas para todos nuestros fragmentos en la parte superior de nuestro documento agregando y editando knitr::opts_chunk$set(echo = TRUE) en la parte superior del documento.

knitr::opts_chunk$set(echo = TRUE,
                      warning = FALSE)

12.5.4 Configuración de opciones de figuras predeterminadas

Es posible establecer diferentes tamaños predeterminados para diferentes tipos de salida incluyéndolos en el encabezado YAML (o usando el engranaje del documento):

---
title: "R Notebook"
output: 
  pdf_document: 
    fig_height: 3
    fig_width: 4
  html_document: 
    fig_height: 6
    fig_width: 9
---

El encabezado YAML es muy sensible a los espacios/tabulaciones, así que asegúrese de que sean correctos.

12.5.5 Elementos de Markdown

El texto de Markdown se puede incluir como desee alrededor de sus fragmentos. La Figura 12.3 muestra un ejemplo de cómo se puede hacer esto. Esta es una excelente manera de adquirir el hábito de documentar explícitamente su análisis. Cuando regresa a un archivo dentro de 6 meses, todo su pensamiento está ahí frente a usted, en lugar de tener que averiguar qué diablos estaba haciendo a partir de una colección de código aleatorio.

12.6 Interfaz y salida

12.6.1 Ejecución de codigo ,chunks y knitting

La figura 12.4 muestra los diversos controles para ejecutar fragmentos y producir un documento de salida. El código se puede ejecutar línea por línea usando Ctrl+Enter como está acostumbrado. Hay opciones para ejecutar todos los fragmentos por encima del fragmento actual en el que está trabajando. Esto es útil ya que un fragmento en el que está trabajando a menudo se basará en objetos creados en fragmentos anteriores.

FIGURA 12.4: Opciones de fragmentos y documentos en archivos de Notebook/Markdown.

Es una buena práctica usar la Restart R and Run All Chunks opción en el Run menú cada cierto tiempo. Esto garantiza que todo el código en su documento sea autónomo y no dependa de un objeto en el entorno que haya creado en otro lugar. Si este fuera el caso, fallará al renderizar un documento Markdown.

Probablemente el motor más importante detrás de la funcionalidad RStudio Notebooks es el paquete knitr de Yihui Xie.

No tejer como lo hace tu abuela, sino convertir un documento de Markdown en un archivo de salida, como HTML, PDF o Word. Hay muchas opciones que se pueden aplicar para lograr el resultado deseado. Algunos de estos se han codificado específicamente en RStudio (Figura 12.4 ).

La creación de documentos PDF requiere LaTeX que se instale una distribución en su computadora. Dependiendo del sistema que esté utilizando, es posible que esto ya esté configurado. Una manera fácil de hacer esto es usando el paquete tinytex .

install.packages("tinytex")
# Restart R, then run
tinytex::install_tinytex()

En el próximo capítulo nos centraremos en los detalles de la producción de un documento final pulido.

12.7 Estructura de archivos y flujo de trabajo

A medida que los proyectos crecen, es importante que estén bien organizados. Esto evitará errores y facilitará la colaboración.

Lo que es absolutamente obligatorio es que su análisis debe residir dentro de un Proyecto RStudio y tener un nombre significativo (¡no MiProyecto! o Análisis1). La creación de un nuevo proyecto en RStudio creará automáticamente una nueva carpeta para sí mismo (a menos que elija “Carpeta existente”). Nunca trabaje dentro de un directorio Inicio o Documentos genérico. Además, no cambie el directorio de trabajo usando setwd(): no hay razón para hacerlo y, por lo general, hace que su análisis sea menos reproducible. Una vez que empiece a familiarizarse con R, debe iniciar todos los proyectos con un repositorio Git para el control de versiones (consulte el Capítulo 13 ).

Para proyectos más pequeños con 1-2 archivos de datos, un par de scripts y un documento R Markdown, está bien mantenerlos todos en la carpeta Proyecto (pero repetimos, cada Proyecto debe tener su propia carpeta). Una vez que la cantidad de archivos crezca más allá de eso, debe agregar carpetas separadas para diferentes tipos de archivos.

Aquí está nuestro enfoque sugerido. Según la naturaleza de sus análisis, la cantidad de carpetas puede ser menor o mayor que esto, y pueden tener un nombre diferente

proj/
- scripts/
- data_raw/
- data_processed/
- figures/
- 00_analysis.Rmd

scripts/ contiene todos los .R archivos de script utilizados para la limpieza/preparación de datos. Si solo tiene algunos scripts, está bien no tener este y simplemente mantener los .R archivos en la carpeta del proyecto (donde 00_analysis .Rmd está en el ejemplo anterior). data_raw /contiene todos los datos sin procesar, como .csv archivos, data_processed/contiene datos que ha tomado sin procesar, limpiados, modificados, unidos o cambiados de otro modo mediante scripts R. figures/puede contener gráficos (p. ej., .png, .jpg, .pdf) 00_analysis.Rmd o 00_analysis.R es el archivo de trabajo principal real, y lo mantenemos en el directorio principal del proyecto.

Sus scripts R deben numerarse con dos dígitos y deben tener nombres significativos, por ejemplo:

scripts/00_source_all.R
scripts/01_read_data.R
scripts/02_make_factors.R
scripts/03_duplicate_records.R

Por ejemplo, 01_read_data.R puede verse así.

# Proyecto de melanoma
## extracción de datos
# Obtener datos
library(readr)
melanoma <- read_csv(
  here::here("data_raw", "melanoma.csv")
)

# Other basic reccoding or renaming functions here

# Save
save(melanoma, file = 
  here::here("data_processed", "melanoma_working.rda")
)

Tenga en cuenta el uso de here::here(). Los proyectos de RStudio administran los directorios de trabajo de una mejor manera que setwd(). here::here() es útil cuando se comparten proyectos entre máquinas Linux, Mac y Windows, que tienen diferentes convenciones para las rutas de los archivos.

Por ejemplo, en una Mac lo haría de otra manera read_csv("data/melanoma.csv")y en Windows tendría que hacer read_csv("data\melanoma.csv"). Tener que incluir /(GNU/Linux, macOS) o \ (Windows) en su secuencia de comandos significa que tendrá que cambiarse a mano cuando se ejecute en un sistema diferente. Lo que here::here("data_raw", "melanoma.csv"), sin embargo, funciona en cualquier sistema, ya que utilizará uno apropiado ‘detrás de escena’ sin que tengas que cambiar nada.

02_make_factors.Res nuestro segundo archivo de ejemplo, pero podría ser cualquier cosa que desee. Podría verse algo como esto.

# Proyecto Melanoma 
## Creando factores
library(tidyverse)
load(
  here::here("data_processed", "melanoma_working.rda")
)
## Recode variables
melanoma <- melanoma %>%
  mutate(
    sex = factor(sex) %>% 
      fct_recode("Male" = "1", 
                 "Female" = "0")
  )
# Salvar
save(melanoma, file = 
  here::here("data", "melanoma_working.rda")
)

Todos estos archivos se pueden reunir en un solo archivo en formato source(). Esta función se utiliza para ejecutar código desde un archivo.

00_source_all.R podría verse así:

# Melanoma project
## Source all
source( here::here("scripts", "01_data_upload.R") )
source( here::here("scripts", "02_make_factors.R") ) 
source( here::here("scripts", "03_duplicate_records.R") ) 
# Save
save(melanoma, file = 
  here::here("data_processed", "melanoma_final.rda")
)

Ahora puede traer sus datos sólidamente preparados a su archivo de análisis, que puede ser .R o .Rmd si está trabajando en un cuaderno. Llamamos a esto 00_analysis.Rmd y siempre se encuentra en el directorio raíz del proyecto. Tiene dos opciones para traer los datos.

1.source("00_source_all.R")para volver a cargar y procesar los datos de nuevo + esto es útil si los datos están cambiando + puede llevar mucho tiempo si se trata de un gran conjunto de datos con muchas manipulaciones 2.load("melanoma_final.rda") de la data_processed/carpeta + generalmente más rápido, pero carga el conjunto de datos que se creó la última vez que ejecutó00_source_all.R

Recuerda: Para .R archivos usa source(), para .rda archivos usa load().

Las dos opciones se ven así:

---
title: "Melanoma analysis"
output: html_notebook
---

```{r get-data-option-1, echo=FALSE}
load(
  here:here("data", "melanoma_all.rda")
)
```

```{r get-data-option-2, echo=FALSE}
source(
  here:here("R", "00_source_all.R")
)

12.7.1 ¿Por qué darse todas estas molestias?

Viene de muchos años de encontrar errores debido a proyectos mal organizados. No es necesario para un pequeño proyecto rápido, pero es esencial para cualquier trabajo importante.

Al comienzo de un análisis (como en el primer día), comenzaremos a trabajar en un solo archivo. Moveremos rápidamente fragmentos de código de limpieza/preparación de datos en archivos separados a medida que avanzamos.

La compartimentación de la limpieza de datos ayuda a encontrar y tratar los errores (“depuración”). Los archivos originales se pueden ‘comentar’ (agregando un # a una línea en el 00_source_all.R archivo) si desea excluir las manipulaciones en ese archivo en particular.

Lo más importante, ayuda con la colaboración. Cuando varias personas trabajan en un proyecto, es esencial que la comunicación sea buena y que todos trabajen según el mismo plan general.

LS0tDQp0aXRsZTogIlIgcGFyYSBDaWVuY2lhIGRlIERhdG9zIGRlIFNhbHVkIg0KYXV0aG9yOiAiRXdlbiBIYXJyaXNvbiB5IFJpaW51IFBpdXMgLyB0cmFkdWNpZG8gcG9yIEEuQ2Fyb2xpbmEgTGVkZXptYS1DYXJyaXphbGV6Ig0KZGF0ZTogIjIwMjItMTItMTgiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZSA9IEZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGZpZy5hbGlnbiA9ICdjZW50ZXInKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGthYmxlRXh0cmEpDQpsaWJyYXJ5KHRpbnl0ZXgpDQpteWthYmxlID0gZnVuY3Rpb24oeCwgY2FwdGlvbiA9ICJDQVBUSU9OIiwgLi4uKXsNCiAga2FibGUoeCwgcm93Lm5hbWVzID0gRkFMU0UsIGFsaWduID0gYygibCIsICJsIiwgInIiLCAiciIsICJyIiwgInIiLCAiciIsICJyIiwgInIiKSwgDQogICAgICAgIGJvb2t0YWJzID0gVFJVRSwgY2FwdGlvbiA9IGNhcHRpb24sIA0KICAgICAgICBsaW5lc2VwID0gIiIsIC4uLikNCn0NCmBgYA0KDQojIENhcMOtdHVsbyAxMiBDdWFkZXJub3MgeSBNYXJrZG93bg0KDQo+IE1lIHByZWd1bnRhcyBzaSBsbGV2byB1biBjdWFkZXJubyBwYXJhIGFub3RhciBtaXMgZ3JhbmRlcyBpZGVhcy4gU29sbyBoZSB0ZW5pZG8gdW5vLlwNCj4gQWxiZXJ0IEVpbnN0ZWluDQoNCiMjIDEyLjEgwr9RdcOpIGVzIHVuIGN1YWRlcm5vIChOb3RlYm9vaykgPw0KDQpSIGVzIHRvZG9wb2Rlcm9zbyBwYXJhIGxhIG1hbmlwdWxhY2nDs24sIHZpc3VhbGl6YWNpw7NuIHkgYW7DoWxpc2lzIGRlIGRhdG9zLiBMbyBxdWUgYSBtZW51ZG8gc2Ugc3ViZXN0aW1hIGVzIGxhIGZsZXhpYmlsaWRhZCBjb24gbGEgcXVlIHNlIHB1ZWRlbiBleHBvcnRhciBvIGluZm9ybWFyIGxvcyBhbsOhbGlzaXMuDQoNClBvciBlamVtcGxvLCBzZSBwdWVkZSBlc2NyaWJpciBmw6FjaWxtZW50ZSB1biBhcnTDrWN1bG8gY2llbnTDrWZpY28gY29tcGxldG8sIHVuIGluZm9ybWUgZGUgbGEgaW5kdXN0cmlhIG8gdW5hIGFjdHVhbGl6YWNpw7NuIG1lbnN1YWwgcGFyYSBhY29tb2RhciB1biBjb25qdW50byBkZSBkYXRvcyBzdWJ5YWNlbnRlIHZhcmlhYmxlLCB5IHRvZGFzIGxhcyB0YWJsYXMgeSBncsOhZmljb3Mgc2UgYWN0dWFsaXphcsOhbiBhdXRvbcOhdGljYW1lbnRlLg0KDQpFc3RhIGlkZWEgc2UgcHVlZGUgZXh0ZW5kZXIgYSB1biBmbHVqbyBkZSB0cmFiYWpvIGVuIGVsIHF1ZSB0b2RvcyBsb3MgYW7DoWxpc2lzIHNlIHJlYWxpemFuIHByaW5jaXBhbG1lbnRlIGRlbnRybyBkZSB1biBkb2N1bWVudG8gcXVlIGZ1bmNpb25hIGNvbW8gZWwgaW5mb3JtZSBmaW5hbC4NCg0KwqFJbmdyZXNlIGEgIkN1YWRlcm5vcyBkZSBkYXRvcyIhIExvcyBjdWFkZXJub3Mgc29uIGRvY3VtZW50b3MgcXVlIGNvbWJpbmFuIGPDs2RpZ28geSBlbGVtZW50b3MgZGUgdGV4dG8gZW5yaXF1ZWNpZG8sIGNvbW8gZW5jYWJlemFkb3MsIHDDoXJyYWZvcyB5IGVubGFjZXMsIGVuIHVuIHNvbG8gZG9jdW1lbnRvLiBDb21iaW5hbiBhbsOhbGlzaXMgZSBpbmZvcm1lcyBlbiB1biBkb2N1bWVudG8gbGVnaWJsZSBwb3IgaHVtYW5vcyBwYXJhIHByb3BvcmNpb25hciB1bmEgaW50ZXJmYXogaW50dWl0aXZhIGVudHJlIGVsIGludmVzdGlnYWRvciB5IHN1IGFuw6FsaXNpcyAoRmlndXJhIFsxMi4xXShodHRwczovL2FyZ29zaGFyZS5pcy5lZC5hYy51ay9oZWFsdGh5cl9ib29rL3doYXQtaXMtYS1ub3RlYm9vay5odG1sI2ZpZzpjaGFwMTItZmlnLWxpdGVyYXRlKSApLiBFc3RvIGEgdmVjZXMgc2UgZGVub21pbmEgInByb2dyYW1hY2nDs24gYWxmYWJldGl6YWRhIiwgZGFkbyBxdWUgbGEgZXN0cnVjdHVyYSBsw7NnaWNhIHJlc3VsdGFudGUgZGUgbGEgaW5mb3JtYWNpw7NuIHNlIHB1ZWRlIGxlZXIgZsOhY2lsbWVudGUgZGUgbGEgbWlzbWEgbWFuZXJhIHF1ZSB1biBodW1hbm8gbGVlcsOtYSB1biBsaWJyby4NCg0KDQohW0ZJR1VSQSAxMi4xOiBQcm9ncmFtYWNpw7NuIHRyYWRpY2lvbmFsIHZlcnN1cyBhbGZhYmV0aXphZGEgdXNhbmRvIE5vdGVib29rcy5dKGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9TdXJnaWNhbEluZm9ybWF0aWNzL2hlYWx0aHlyX2Jvb2svbWFzdGVyL2ltYWdlcy9jaGFwdGVyMTIvMV9saXRlcmF0ZV9wcm9ncmFtbWluZy5wbmcpe3dpZHRoPSI3NSUifQ0KDQpFbiBudWVzdHJvIHByb3BpbyB0cmFiYWpvLCBhaG9yYSBoZW1vcyBwYXNhZG8gYSByZWFsaXphciBsYSBtYXlvcsOtYSBkZSBudWVzdHJvcyBhbsOhbGlzaXMgZW4gdW4gYXJjaGl2byBkZSBOb3RlYm9vaywgZW4gbHVnYXIgZGUgdXNhciB1biBhcmNoaXZvIGRlICJzY3JpcHQiLiBQdWVkZSBxdWUgbm8gbG8gaGF5YXMgYWRpdmluYWRvLCBwZXJvIHRvZG8gZXN0ZSBsaWJybyBlc3TDoSBlc2NyaXRvIGRlIGVzdGEgbWFuZXJhLg0KDQpBbGd1bmFzIGRlIGxhcyB2ZW50YWphcyBkZSBsYSBpbnRlcmZheiBkZSBOb3RlYm9vayBzb246DQoNCi0gICBlbCBjw7NkaWdvIHkgbGEgc2FsaWRhIHNvbiBhZHlhY2VudGVzIGVudHJlIHPDrSwgcG9yIGxvIHF1ZSBubyBlc3TDoSBjYW1iaWFuZG8gY29uc3RhbnRlbWVudGUgZW50cmUgInBhbmVsZXMiOw0KLSAgIG3DoXMgZsOhY2lsIGRlIHRyYWJhamFyIGVuIHVuYSBwYW50YWxsYSBtw6FzIHBlcXVlw7FhLCBwb3IgZWplbXBsbywgdW5hIGNvbXB1dGFkb3JhIHBvcnTDoXRpbDsNCi0gICBsYSBkb2N1bWVudGFjacOzbiB5IGxvcyBpbmZvcm1lcyBzZSBwdWVkZW4gcmVhbGl6YXIganVudG8gY29uIGVsIGPDs2RpZ28sIGxvcyBlbGVtZW50b3MgZGUgdGV4dG8gc2UgcHVlZGVuIGZvcm1hdGVhciBwb3IgY29tcGxldG87DQotICAgZWwgY8OzZGlnbyBlbiBzw60gc2UgcHVlZGUgbW9zdHJhciB1IG9jdWx0YXI7DQotICAgZWwgY8OzZGlnbyBubyBzZSBsaW1pdGEgYSBSOyBwdWVkZSB1c2FyIFB5dGhvbiwgU1FMLCBldGMuOw0KLSAgIGZhY2lsaXRhciBsYSBjb2xhYm9yYWNpw7NuIGNvbXBhcnRpZW5kbyBmw6FjaWxtZW50ZSBkb2N1bWVudG9zIGRlIGFuw6FsaXNpcyBsZWdpYmxlcyBwb3IgaHVtYW5vczsNCi0gICBzZSBwdWVkZSBnZW5lcmFyIGVuIHZhcmlvcyBmb3JtYXRvcywgaW5jbHVpZG9zIEhUTUwgKHDDoWdpbmEgd2ViKSwgUERGIHkgTWljcm9zb2Z0IFdvcmQ7DQotICAgbGEgc2FsaWRhIHNlIHB1ZWRlIGV4dGVuZGVyIGEgb3Ryb3MgZm9ybWF0b3MgY29tbyBwcmVzZW50YWNpb25lczsNCi0gICBsYSBjYXBhY2l0YWNpw7NuL2FwcmVuZGl6YWplIHB1ZWRlIHNlciBtw6FzIGbDoWNpbCB5YSBxdWUgbG9zIG1hdGVyaWFsZXMgZGVsIGN1cnNvLCBsb3MgZWplbXBsb3MgeSBsYXMgbm90YXMgZGUgbG9zIGVzdHVkaWFudGVzIGVzdMOhbiB0b2RvcyBlbiBlbCBtaXNtbyBkb2N1bWVudG8uDQoNCiMjIDEyLjIgwr9RdcOpIGVzIE1hcmtkb3duPw0KDQpNYXJrZG93biBlcyB1biBsZW5ndWFqZSBsaWdlcm8gcXVlIHNlIHB1ZWRlIHV0aWxpemFyIHBhcmEgZXNjcmliaXIgZG9jdW1lbnRvcyBjb24gZm9ybWF0byBjb21wbGV0by4gRXMgdGV4dG8gc2luIGZvcm1hdG8geSB1dGlsaXphIHVuIGNvbmp1bnRvIHNpbXBsZSBkZSByZWdsYXMgcGFyYSBwcm9kdWNpciByZXN1bHRhZG9zIGJhc3RhbnRlIHNvZmlzdGljYWRvcy4gwqFOb3MgZW5jYW50YSENCg0KRXMgZsOhY2lsIGZvcm1hdGVhciBlbmNhYmV6YWRvcywgdGV4dG8gZW4gbmVncml0YSwgY3Vyc2l2YSwgZXRjLiBEZW50cm8gZGUgUlN0dWRpbyBoYXkgdW5hIGd1w61hIGRlIHJlZmVyZW5jaWEgcsOhcGlkYSAoRmlndXJhIFsxMi4yXShodHRwczovL2FyZ29zaGFyZS5pcy5lZC5hYy51ay9oZWFsdGh5cl9ib29rL3doYXQtaXMtbWFya2Rvd24uaHRtbCNmaWc6Y2hhcDEyLWZpZy1oZWxwKSApIHkgc2UgcHVlZGVuIGVuY29udHJhciBlbmxhY2VzIGEgbGFzIGhvamFzIGRlIHRydWNvcyBkZSBbUlN0dWRpb10oaHR0cHM6Ly93d3cucnN0dWRpby5jb20vcmVzb3VyY2VzL2NoZWF0c2hlZXRzKSBlbiBlbCBtZW7DuiBkZXNwbGVnYWJsZSBBeXVkYS4NCg0KIVtGSUdVUkEgMTIuMjogR3XDrWEgZGUgcmVmZXJlbmNpYSByw6FwaWRhIGRlIFJTdHVkaW8gTWFya2Rvd24uXShodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vU3VyZ2ljYWxJbmZvcm1hdGljcy9oZWFsdGh5cl9ib29rL21hc3Rlci9pbWFnZXMvY2hhcHRlcjEyLzNfaGVscC5wbmcpe3dpZHRoPSI3NSUifQ0KDQpNYXJrZG93biBleGlzdGUgaW5kZXBlbmRpZW50ZW1lbnRlIGRlIFIgeSBlcyB1dGlsaXphZG8gcG9yIHVuYSB2YXJpZWRhZCBkZSB0w6ljbmljb3MgeSBzaW1pbGFyZXMuIFVuYSBjb21iaW5hY2nDs24gZGUgTWFya2Rvd24gKHF1ZSBlcyB0ZXh0byBjb24gY2FyYWN0ZXJlcyBlc3BlY2lhbGVzIHBhcmEgaW5kaWNhciBlbCBmb3JtYXRvIGRlc2VhZG8pIHkgZWwgY8OzZGlnbyBSIHF1ZSBjb250aWVuZSAoZ2VuZXJhbG1lbnRlIHBhcmEgcHJvZHVjaXIgdGFibGFzIHkgZ3LDoWZpY29zKSBzZSBkZW5vbWluYSBSIE1hcmtkb3duLiBMb3Mgc2NyaXB0cyBSIHRpZW5lbiBsYSBleHRlbnNpw7NuIGRlIGFyY2hpdm8gYC5SLGBsb3MgZG9jdW1lbnRvcyBNYXJrZG93biB0aWVuZW4gdW5hIGV4dGVuc2nDs24gZGUgYXJjaGl2byBgLm1kLGAgcG9yIGxvIHRhbnRvLCBsb3MgZG9jdW1lbnRvcyBSIE1hcmtkb3duIHNvbmAuUm1kYC4NCg0KIyMgMTIuMyDCv0N1w6FsIGVzIGxhIGRpZmVyZW5jaWEgZW50cmUgdW4gTm90ZWJvb2sgeSB1biBhcmNoaXZvIFIgTWFya2Rvd24/DQoNCkxhIG1heW9yw61hIGRlIGxhIGdlbnRlIHVzYSBsb3MgdMOpcm1pbm9zIFIgTm90ZWJvb2sgeSBSIE1hcmtkb3duIGluZGlzdGludGFtZW50ZSB5IGVzbyBlc3TDoSBiaWVuLiBUw6ljbmljYW1lbnRlLCBSIE1hcmtkb3duIGVzIHVuIGFyY2hpdm8sIG1pZW50cmFzIHF1ZSBSIE5vdGVib29rIGVzIHVuYSBmb3JtYSBkZSB0cmFiYWphciBjb24gYXJjaGl2b3MgUiBNYXJrZG93bi4gTG9zIGN1YWRlcm5vcyBSIG5vIHRpZW5lbiBzdSBwcm9waW8gZm9ybWF0byBkZSBhcmNoaXZvLCB0b2RvcyB1c2FuIGAuUm1kYC4gVG9kb3MgbG9zIGN1YWRlcm5vcyBkZSBSIHNlIHB1ZWRlbiAndGVqZXInIGEgbGFzIHNhbGlkYXMgZGUgUiBNYXJrZG93biwgeSB0b2RvcyBsb3MgZG9jdW1lbnRvcyBkZSBSIE1hcmtkb3duIHNlIHB1ZWRlbiBpbnRlcmNvbmVjdGFyIGNvbW8gdW4gY3VhZGVybm8uDQoNClVuYSBkaWZlcmVuY2lhIGltcG9ydGFudGUgZXN0w6EgZW4gbGEgZWplY3VjacOzbiBkZWwgY8OzZGlnby4gRW4gUiBNYXJrZG93biwgY3VhbmRvIGVsIGFyY2hpdm8gZXMgYEtuaXRgLCB0YW1iacOpbiBzZSBlamVjdXRhbiB0b2RvcyBsb3MgZWxlbWVudG9zIChmcmFnbWVudG9zKS4gS25pdCBlcyBwYXJhIFIgTWFya2Rvd24gbG8gcXVlIFNvdXJjZSBlcyBwYXJhIHVuIHNjcmlwdCBSIChTb3VyY2Ugc2UgcHJlc2VudMOzIGVuIGVsIENhcMOtdHVsbyAxLCBlc2VuY2lhbG1lbnRlIHNpZ25pZmljYSAnRWplY3V0YXIgdG9kYXMgbGFzIGzDrW5lYXMnKS4NCg0KRW4gdW4gTm90ZWJvb2ssIGN1YW5kbyBlbCBhcmNoaXZvIHNlIHByb2Nlc2EgY29uIGVsIGBQcmV2aWV3YCBib3TDs24sIG5vIHNlIHZ1ZWx2ZSBhIGVqZWN1dGFyIG5pbmfDum4gY8OzZGlnbywgc29sbyBzZSBpbmNsdXllIGVuIGxhIHNhbGlkYSBlbCBxdWUgeWEgc2UgaGEgZWplY3V0YWRvIHkgZXN0w6EgcHJlc2VudGUgZW4gZWwgZG9jdW1lbnRvLiBBZGVtw6FzLCBlbiBlbCBhcmNoaXZvIGRldHLDoXMgZGUgZXNjZW5hIGRlIE5vdGVib29rICggYC5uYmApLCBzaWVtcHJlIHNlIGluY2x1eWUgdG9kbyBlbCBjw7NkaWdvLiBBbGdvIGEgdGVuZXIgZW4gY3VlbnRhIHNpIHN1IGPDs2RpZ28gY29udGllbmUgaW5mb3JtYWNpw7NuIGNvbmZpZGVuY2lhbCwgY29tbyB1bmEgY29udHJhc2XDsWEgKMKhcXVlIG51bmNhIGRlYmVyw61hISkuDQoNCiMjIDEyLjQgQ3VhZGVybm8gdnMgSFRNTCB2cyBQREYgdnMgV29yZA0KXGluZGV4e01pY3Jvc29mdCBXb3JkfQ0KXGluZGV4e1BERn0NClxpbmRleHtIVE1MfQ0KDQpFbiBSU3R1ZGlvLCBzZSBwdWVkZSBjcmVhciB1biBOb3RlYm9vayB5ZW5kbyBhOiANCkFyY2hpdm8gLT4gTnVldm8gYXJjaGl2byAtPiBSIE5vdGVib29rDQoNCkFsdGVybmF0aXZhbWVudGUsIHB1ZWRlIGNyZWFyIHVuIGFyY2hpdm8gTWFya2Rvd24gdXNhbmRvOiANCkFyY2hpdm8gLT4gTnVldm8gYXJjaGl2byAtPiBSIE1hcmtkb3duLi4uDQoNCk5vIHRlIHByZW9jdXBlcyBjdcOhbCBlbGlnZXMuIENvbW8gc2UgbWVuY2lvbsOzIGFudGVyaW9ybWVudGUsIHNvbiBlc2VuY2lhbG1lbnRlIGxvIG1pc21vIHBlcm8gdmllbmVuIGNvbiBkaWZlcmVudGVzIG9wY2lvbmVzLiBFcyBmw6FjaWwgY2FtYmlhciBkZSB1biBOb3RlYm9vayBhIHVuIGFyY2hpdm8gTWFya2Rvd24gc2kgZGVzZWEgY3JlYXIgdW4gZG9jdW1lbnRvIFBERiBvIFdvcmQsIHBvciBlamVtcGxvLg0KDQpTaSByZWFsaXphIGFuw6FsaXNpcyBwcmluY2lwYWxtZW50ZSBlbiBlbCBlbnRvcm5vIGRlIE5vdGVib29rLCBlbGlqYSBOb3RlYm9vay4gU2kgZXN0w6EgY3JlYW5kbyBwcmluY2lwYWxtZW50ZSB1biBkb2N1bWVudG8gUERGIG8gV29yZCwgZWxpamEgZWwgYXJjaGl2byBSIE1hcmtkb3duLg0KDQojIyAxMi41IExhIGFuYXRvbcOtYSBkZSB1biBhcmNoaXZvIE5vdGVib29rIC8gUiBNYXJrZG93bg0KDQpDdWFuZG8gY3JlYSB1biBhcmNoaXZvLCBzZSBwcm9wb3JjaW9uYSB1bmEgcGxhbnRpbGxhIMO6dGlsIHBhcmEgcXVlIHB1ZWRhIGNvbWVuemFyLiBMYSBmaWd1cmEgMTIuMyBtdWVzdHJhIGxvcyBlbGVtZW50b3MgZXNlbmNpYWxlcyBkZSB1biBhcmNoaXZvIGRlIE5vdGVib29rIHkgY8OzbW8gc2UgdHJhZHVjZW4gZW4gbGEgYEhUTUxgIHZpc3RhIHByZXZpYS4NCg0KIyMjIDEyLjUuMSBFbmNhYmV6YWRvIFlBTUwNClxpbmRleHtZQU1MIGhlYWRlcn0NCg0KQ2FkYSBhcmNoaXZvIGRlIE5vdGVib29rIHkgTWFya2Rvd24gcmVxdWllcmUgdW4gImVuY2FiZXphZG8gWUFNTCIuIMK/RGUgZMOzbmRlIG9idGllbmVuIGVzdG9zIHTDqXJtaW5vcyBxdWUgcGlkZXM/IE9yaWdpbmFsbWVudGUsIHNlIGRlY8OtYSBxdWUgWUFNTCBzaWduaWZpY2FiYSBvdHJvIGxlbmd1YWplIGRlIG1hcmNhcywgaGFjaWVuZG8gcmVmZXJlbmNpYSBhIHN1IHByb3DDs3NpdG8gY29tbyBsZW5ndWFqZSBkZSBtYXJjYXMuIE3DoXMgdGFyZGUgc2UgcmV1dGlsaXrDsyBjb21vIFlBTUwgQWluJ3QgTWFya3VwIExhbmd1YWdlLCB1biBhY3LDs25pbW8gcmVjdXJzaXZvLCBwYXJhIGRpc3Rpbmd1aXIgc3UgcHJvcMOzc2l0byBjb21vIG9yaWVudGFkbyBhIGRhdG9zIGVuIGx1Z2FyIGRlIG1hcmNhZG8gZGUgZG9jdW1lbnRvcyAoZ3JhY2lhcyBXaWtpcGVkaWEpLg0KDQpBcXXDrSBlcyBzaW1wbGVtZW50ZSBkb25kZSBzZSBjb2xvY2FuIG11Y2hhcyBkZSBsYXMgY29uZmlndXJhY2lvbmVzL29wY2lvbmVzIHBhcmEgbGEgY3JlYWNpw7NuIGRlIGFyY2hpdm9zLiBFbiBSU3R1ZGlvLCBlc3RvcyBhIG1lbnVkbyBzZSBhY3R1YWxpemFuIGF1dG9tw6F0aWNhbWVudGUgYSBtZWRpZGEgcXVlIHNlIGludm9jYW4gZGlmZXJlbnRlcyBjb25maWd1cmFjaW9uZXMgZW4gZWwgbWVuw7ogT3BjaW9uZXMuDQoNCiFbRklHVVJBIDEyLjM6IExhIGFuYXRvbcOtYSBkZSB1biBhcmNoaXZvIE5vdGVib29rL01hcmtkb3duLiBFbnRyYWRhIChpenF1aWVyZGEpIHkgc2FsaWRhIChkZXJlY2hhKS5dKGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9TdXJnaWNhbEluZm9ybWF0aWNzL2hlYWx0aHlyX2Jvb2svbWFzdGVyL2ltYWdlcy9jaGFwdGVyMTIvMl9hbmF0b215X3JvdGF0ZWQucG5nKXt3aWR0aD0iNzUlIn1cDQoNCiMjIyAxMi41LjIgRnJhZ21lbnRvcyBkZSBjw7NkaWdvIFINClxpbmRleHtjaHVua3N9DQoNCkVsIGPDs2RpZ28gUiBkZW50cm8gZGUgdW4gYXJjaGl2byBOb3RlYm9vayBvIE1hcmtkb3duIHNlIHB1ZWRlIGluY2x1aXIgZGUgZG9zIG1hbmVyYXM6DQoNCi0gICBlbiBsw61uZWE6IHBvciBlamVtcGxvLCBlbCBuw7ptZXJvIHRvdGFsIGRlIG5hcmFuamFzIGZ1ZSAgYGAgYHIgYGAgYGAgc3VtKGZydWl0JG9yYW5nZXMpYCBgYDsNCi0gICBjb21vIHVuICJjaHVuayAodHJvem8pIi4NCg0KTG9zIGZyYWdtZW50b3MgUiBzb24gZmxleGlibGVzLCB2aWVuZW4gY29uIG11Y2hhcyBvcGNpb25lcyB5IHByb250byBhcHJlbmRlcsOhIGEgdXNhcmxvcy4NCg0KTGEgZmlndXJhIDEyLjMgbXVlc3RyYSBjw7NtbyBlbmNhamEgdW4gdHJvem8gZW4gZWwgZG9jdW1lbnRvLg0KDQpgYGB7cn0NCiMgRXN0YSBlcyB1bmEgcGFydGUgYsOhc2ljYS4NCiMgU2llbXByZSBjb21pZW56YSBjb24gYGBge3J9DQojIFkgdGVybWluYSBjb24gYGBgDQojIEVsIGPDs2RpZ28gdmEgYXF1w60NCnN1bShmcnVpdCRvcmFuZ2VzKQ0KYGBgDQoNCg0KDQpFc3RvIHB1ZWRlIHBhcmVjZXIgZGVzYWdyYWRhYmxlLCBwZXJvIHNpZ3VlIGFkZWxhbnRlIHBvciBhaG9yYS4gUHVlZGUgZXNjcmliaXIgbG9zIGN1YXRybyBhY2VudG9zIGdyYXZlcyBtYW51YWxtZW50ZSBvIHVzYXIgZWwgYEluc2VydGAgYm90w7NuIHkgZWxlZ2lyIGBSYC4gVGFtYmnDqW4gbm90YXLDoSBxdWUgbG9zIGZyYWdtZW50b3Mgbm8gc2UgbGltaXRhbiBhbCBjw7NkaWdvIFIuIEVzIHBhcnRpY3VsYXJtZW50ZSDDunRpbCBxdWUgUHl0aG9uIHRhbWJpw6luIHNlIHB1ZWRhIGVqZWN1dGFyIGRlIGVzdGEgbWFuZXJhLg0KDQpBbCByZWFsaXphciB1biBhbsOhbGlzaXMgZW4gdW4gY3VhZGVybm8sIGNhc2kgc2llbXByZSBxdWVycsOhIHZlciBlbCBjw7NkaWdvIHkgZWwgcmVzdWx0YWRvLiBDdWFuZG8gZXN0w6kgY3JlYW5kbyB1biBkb2N1bWVudG8gZmluYWwsIGVzIHBvc2libGUgcXVlIGRlc2VlIG9jdWx0YXIgZWwgY8OzZGlnby4gRWwgY29tcG9ydGFtaWVudG8gZGUgbG9zIGZyYWdtZW50b3Mgc2UgcHVlZGUgY29udHJvbGFyIGEgdHJhdsOpcyBgQ2h1bmsgQ29nZGVgbGEgcGFydGUgZGVyZWNoYSBkZWwgZnJhZ21lbnRvIChGaWd1cmEgMTIuMyApLg0KDQpMYSB0YWJsYSAxMi4xIG11ZXN0cmEgbGFzIGRpdmVyc2FzIHBlcm11dGFjaW9uZXMgZGUgY8OzZGlnbyB5IG9wY2lvbmVzIGRlIHNhbGlkYSBxdWUgZXN0w6FuIGRpc3BvbmlibGVzLiBFbCBjw7NkaWdvIHNlIGNvbG9jYSBlbiBlbCBlbmNhYmV6YWRvIGRlbCBmcmFnbWVudG8sIHBlcm8gbGFzIG9wY2lvbmVzIGVtZXJnZW50ZXMgYWhvcmEgbG8gaGFjZW4gYXV0b23DoXRpY2FtZW50ZSwgcG9yIGVqZW1wbG8sDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KYGBgDQoNCmBgYHtyIGNoYXAxMi10YWItY2h1bmstb3V0cHV0LCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KbGlicmFyeShkcGx5cikNCmRhdGEuZnJhbWUoDQogIE9wdGlvbiA9IGMoDQogICJNb3N0cmFyIHNvbG8gc2FsaWRhIiwNCiAgICJNb3N0cmFyIGPDs2RpZ28geSBzYWxpZGEiLA0KICAgIlNob3cgQ29kZSAobm8gZWplY3V0ZSBjw7NkaWdvKSIsDQogICAiU2hvdyBOb3RoaW5nIChFamVjdXRhciBjw7NkaWdvKSIsDQogICAiTW9zdHJhciBuYWRhIChubyBlamVjdXRlIGPDs2RpZ28pIiwNCiAgICIiLA0KICAgIk9jdWx0YXIgYWR2ZXJ0ZW5jaWFzIiwNCiAgICJPY3VsdGFyIG1lbnNhamVzIg0KKSwgIA0KICBDb2RlID0gYygNCiAgImVjaG89RkFMU0UiLA0KICAgImVjaG89VFJVRSIsDQogICAiZXZhbD1GQUxTRSIsDQogICAiaW5jbHVkZT1GQUxTRSIsDQogICAiaW5jbHVkZT1GQUxTRSwgZXZhbD1GQUxTRSIsDQogICAiIiwNCiAgICJ3YXJuaW5ncz1GQUxTRSIsDQogICAibWVzc2FnZXM9RkFMU0UiDQoJKQ0KKSAlPiUgDQogIGtuaXRyOjprYWJsZShjYXB0aW9uID0gIkNodW5rIG91dHB1dCBvcHRpb25zIHdoZW4ga25pdHRpbmcgYW4gUiBNYXJrZG93biBmaWxlLiBXaGVuIHVzaW5nIHRoZSBDaHVuayBDb2csIFJTdHVkaW8gd2lsbCBhZGQgdGhlc2Ugb3B0aW9ucyBhcHByb3ByaWF0ZWx5OyB0aGVyZSBpcyBubyBuZWVkIHRvIG1lbW9yaXNlIHRoZW0uIiwNCiAgICAgICAgICAgICAgIGJvb2t0YWJzID0gVFJVRSkNCmBgYA0KDQojIyMgMTIuNS4zIENvbmZpZ3VyYWNpw7NuIGRlIG9wY2lvbmVzIGRlIGZyYWdtZW50b3MgcHJlZGV0ZXJtaW5hZG9zDQoNClBvZGVtb3MgZXN0YWJsZWNlciBvcGNpb25lcyBwcmVkZXRlcm1pbmFkYXMgcGFyYSB0b2RvcyBudWVzdHJvcyBmcmFnbWVudG9zIGVuIGxhIHBhcnRlIHN1cGVyaW9yIGRlIG51ZXN0cm8gZG9jdW1lbnRvIGFncmVnYW5kbyB5IGVkaXRhbmRvIGBrbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpYCBlbiBsYSBwYXJ0ZSBzdXBlcmlvciBkZWwgZG9jdW1lbnRvLg0KDQpgYGB7cn0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UpDQpgYGANCg0KIyMjIDEyLjUuNCBDb25maWd1cmFjacOzbiBkZSBvcGNpb25lcyBkZSBmaWd1cmFzIHByZWRldGVybWluYWRhcw0KDQpFcyBwb3NpYmxlIGVzdGFibGVjZXIgZGlmZXJlbnRlcyB0YW1hw7FvcyBwcmVkZXRlcm1pbmFkb3MgcGFyYSBkaWZlcmVudGVzIHRpcG9zIGRlIHNhbGlkYSBpbmNsdXnDqW5kb2xvcyBlbiBlbCBlbmNhYmV6YWRvIFlBTUwgKG8gdXNhbmRvIGVsIGVuZ3JhbmFqZSBkZWwgZG9jdW1lbnRvKToNCg0KDQpgYGBgbWFya2Rvd24NCi0tLQ0KdGl0bGU6ICJSIE5vdGVib29rIg0Kb3V0cHV0OiANCiAgcGRmX2RvY3VtZW50OiANCiAgICBmaWdfaGVpZ2h0OiAzDQogICAgZmlnX3dpZHRoOiA0DQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIGZpZ19oZWlnaHQ6IDYNCiAgICBmaWdfd2lkdGg6IDkNCi0tLQ0KYGBgYA0KDQpFbCBlbmNhYmV6YWRvIFlBTUwgZXMgbXV5IHNlbnNpYmxlIGEgbG9zIGVzcGFjaW9zL3RhYnVsYWNpb25lcywgYXPDrSBxdWUgYXNlZ8O6cmVzZSBkZSBxdWUgc2VhbiBjb3JyZWN0b3MuDQoNCiMjIyAxMi41LjUgRWxlbWVudG9zIGRlIE1hcmtkb3duDQoNCkVsIHRleHRvIGRlIE1hcmtkb3duIHNlIHB1ZWRlIGluY2x1aXIgY29tbyBkZXNlZSBhbHJlZGVkb3IgZGUgc3VzIGZyYWdtZW50b3MuIExhIEZpZ3VyYSAxMi4zIG11ZXN0cmEgdW4gZWplbXBsbyBkZSBjw7NtbyBzZSBwdWVkZSBoYWNlciBlc3RvLiBFc3RhIGVzIHVuYSBleGNlbGVudGUgbWFuZXJhIGRlIGFkcXVpcmlyIGVsIGjDoWJpdG8gZGUgZG9jdW1lbnRhciBleHBsw61jaXRhbWVudGUgc3UgYW7DoWxpc2lzLiBDdWFuZG8gcmVncmVzYSBhIHVuIGFyY2hpdm8gZGVudHJvIGRlIDYgbWVzZXMsIHRvZG8gc3UgcGVuc2FtaWVudG8gZXN0w6EgYWjDrSBmcmVudGUgYSB1c3RlZCwgZW4gbHVnYXIgZGUgdGVuZXIgcXVlIGF2ZXJpZ3VhciBxdcOpIGRpYWJsb3MgZXN0YWJhIGhhY2llbmRvIGEgcGFydGlyIGRlIHVuYSBjb2xlY2Npw7NuIGRlIGPDs2RpZ28gYWxlYXRvcmlvLg0KDQojIyAxMi42IEludGVyZmF6IHkgc2FsaWRhDQoNCiMjIyAxMi42LjEgRWplY3VjacOzbiBkZSBjb2RpZ28gLGNodW5rcyB5IGtuaXR0aW5nDQoNCkxhIGZpZ3VyYSAxMi40IG11ZXN0cmEgbG9zIGRpdmVyc29zIGNvbnRyb2xlcyBwYXJhIGVqZWN1dGFyIGZyYWdtZW50b3MgeSBwcm9kdWNpciB1biBkb2N1bWVudG8gZGUgc2FsaWRhLiBFbCBjw7NkaWdvIHNlIHB1ZWRlIGVqZWN1dGFyIGzDrW5lYSBwb3IgbMOtbmVhIHVzYW5kbyBgQ3RybCtFbnRlcmAgY29tbyBlc3TDoSBhY29zdHVtYnJhZG8uIEhheSBvcGNpb25lcyBwYXJhIGVqZWN1dGFyIHRvZG9zIGxvcyBmcmFnbWVudG9zIHBvciBlbmNpbWEgZGVsIGZyYWdtZW50byBhY3R1YWwgZW4gZWwgcXVlIGVzdMOhIHRyYWJhamFuZG8uIEVzdG8gZXMgw7p0aWwgeWEgcXVlIHVuIGZyYWdtZW50byBlbiBlbCBxdWUgZXN0w6EgdHJhYmFqYW5kbyBhIG1lbnVkbyBzZSBiYXNhcsOhIGVuIG9iamV0b3MgY3JlYWRvcyBlbiBmcmFnbWVudG9zIGFudGVyaW9yZXMuDQoNCiFbRklHVVJBIDEyLjQ6IE9wY2lvbmVzIGRlIGZyYWdtZW50b3MgeSBkb2N1bWVudG9zIGVuIGFyY2hpdm9zIGRlIE5vdGVib29rL01hcmtkb3duLl0oaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL1N1cmdpY2FsSW5mb3JtYXRpY3MvaGVhbHRoeXJfYm9vay9tYXN0ZXIvaW1hZ2VzL2NoYXB0ZXIxMi80X25vdGVib29rX29wdGlvbnNfcm90YXRlZC5wbmcpDQoNCkVzIHVuYSBidWVuYSBwcsOhY3RpY2EgdXNhciBsYSBgUmVzdGFydCBSIGFuZCBSdW4gQWxsIENodW5rc2Agb3BjacOzbiBlbiBlbCBgUnVuYCBtZW7DuiBjYWRhIGNpZXJ0byB0aWVtcG8uIEVzdG8gZ2FyYW50aXphIHF1ZSB0b2RvIGVsIGPDs2RpZ28gZW4gc3UgZG9jdW1lbnRvIHNlYSBhdXTDs25vbW8geSBubyBkZXBlbmRhIGRlIHVuIG9iamV0byBlbiBlbCBlbnRvcm5vIHF1ZSBoYXlhIGNyZWFkbyBlbiBvdHJvIGx1Z2FyLiBTaSBlc3RlIGZ1ZXJhIGVsIGNhc28sIGZhbGxhcsOhIGFsIHJlbmRlcml6YXIgdW4gZG9jdW1lbnRvIE1hcmtkb3duLg0KDQpQcm9iYWJsZW1lbnRlIGVsIG1vdG9yIG3DoXMgaW1wb3J0YW50ZSBkZXRyw6FzIGRlIGxhIGZ1bmNpb25hbGlkYWQgUlN0dWRpbyBOb3RlYm9va3MgZXMgZWwgcGFxdWV0ZSBrbml0ciBkZSAqKllpaHVpKiogWGllLg0KDQpObyB0ZWplciBjb21vIGxvIGhhY2UgdHUgYWJ1ZWxhLCBzaW5vIGNvbnZlcnRpciB1biBkb2N1bWVudG8gZGUgTWFya2Rvd24gZW4gdW4gYXJjaGl2byBkZSBzYWxpZGEsIGNvbW8gSFRNTCwgUERGIG8gV29yZC4gSGF5IG11Y2hhcyBvcGNpb25lcyBxdWUgc2UgcHVlZGVuIGFwbGljYXIgcGFyYSBsb2dyYXIgZWwgcmVzdWx0YWRvIGRlc2VhZG8uIEFsZ3Vub3MgZGUgZXN0b3Mgc2UgaGFuIGNvZGlmaWNhZG8gZXNwZWPDrWZpY2FtZW50ZSBlbiBSU3R1ZGlvIChGaWd1cmEgMTIuNCApLg0KDQpMYSBjcmVhY2nDs24gZGUgZG9jdW1lbnRvcyBQREYgcmVxdWllcmUgTGFUZVggcXVlIHNlIGluc3RhbGUgdW5hIGRpc3RyaWJ1Y2nDs24gZW4gc3UgY29tcHV0YWRvcmEuIERlcGVuZGllbmRvIGRlbCBzaXN0ZW1hIHF1ZSBlc3TDqSB1dGlsaXphbmRvLCBlcyBwb3NpYmxlIHF1ZSBlc3RvIHlhIGVzdMOpIGNvbmZpZ3VyYWRvLiBVbmEgbWFuZXJhIGbDoWNpbCBkZSBoYWNlciBlc3RvIGVzIHVzYW5kbyBlbCBwYXF1ZXRlICoqdGlueXRleCoqIC4NCg0KYGBge3J9DQppbnN0YWxsLnBhY2thZ2VzKCJ0aW55dGV4IikNCiMgUmVzdGFydCBSLCB0aGVuIHJ1bg0KdGlueXRleDo6aW5zdGFsbF90aW55dGV4KCkNCmBgYA0KDQpFbiBlbCBwcsOzeGltbyBjYXDDrXR1bG8gbm9zIGNlbnRyYXJlbW9zIGVuIGxvcyBkZXRhbGxlcyBkZSBsYSBwcm9kdWNjacOzbiBkZSB1biBkb2N1bWVudG8gZmluYWwgcHVsaWRvLg0KDQojIyAxMi43IEVzdHJ1Y3R1cmEgZGUgYXJjaGl2b3MgeSBmbHVqbyBkZSB0cmFiYWpvDQpcaW5kZXh7ZmlsZSBzdHJ1Y3R1cmVAXHRleHRiZntmaWxlIHN0cnVjdHVyZX19DQpcaW5kZXh7d29ya2Zsb3dAXHRleHRiZnt3b3JrZmxvd319DQoNCg0KQSBtZWRpZGEgcXVlIGxvcyBwcm95ZWN0b3MgY3JlY2VuLCBlcyBpbXBvcnRhbnRlIHF1ZSBlc3TDqW4gYmllbiBvcmdhbml6YWRvcy4gRXN0byBldml0YXLDoSBlcnJvcmVzIHkgZmFjaWxpdGFyw6EgbGEgY29sYWJvcmFjacOzbi4NCg0KTG8gcXVlIGVzIGFic29sdXRhbWVudGUgb2JsaWdhdG9yaW8gZXMgcXVlIHN1IGFuw6FsaXNpcyBkZWJlIHJlc2lkaXIgZGVudHJvIGRlIHVuIFByb3llY3RvIFJTdHVkaW8geSB0ZW5lciB1biBub21icmUgc2lnbmlmaWNhdGl2byAowqFubyBNaVByb3llY3RvISBvIEFuw6FsaXNpczEpLiBMYSBjcmVhY2nDs24gZGUgdW4gbnVldm8gcHJveWVjdG8gZW4gUlN0dWRpbyBjcmVhcsOhIGF1dG9tw6F0aWNhbWVudGUgdW5hIG51ZXZhIGNhcnBldGEgcGFyYSBzw60gbWlzbW8gKGEgbWVub3MgcXVlIGVsaWphICJDYXJwZXRhIGV4aXN0ZW50ZSIpLiBOdW5jYSB0cmFiYWplIGRlbnRybyBkZSB1biBkaXJlY3RvcmlvIEluaWNpbyBvIERvY3VtZW50b3MgZ2Vuw6lyaWNvLiBBZGVtw6FzLCBubyBjYW1iaWUgZWwgZGlyZWN0b3JpbyBkZSB0cmFiYWpvIHVzYW5kbyBgc2V0d2QoKWA6IG5vIGhheSByYXrDs24gcGFyYSBoYWNlcmxvIHksIHBvciBsbyBnZW5lcmFsLCBoYWNlIHF1ZSBzdSBhbsOhbGlzaXMgc2VhIG1lbm9zIHJlcHJvZHVjaWJsZS4gVW5hIHZleiBxdWUgZW1waWVjZSBhIGZhbWlsaWFyaXphcnNlIGNvbiBSLCBkZWJlIGluaWNpYXIgdG9kb3MgbG9zIHByb3llY3RvcyBjb24gdW4gcmVwb3NpdG9yaW8gR2l0IHBhcmEgZWwgY29udHJvbCBkZSB2ZXJzaW9uZXMgKGNvbnN1bHRlIGVsIENhcMOtdHVsbyAxMyApLg0KDQpQYXJhIHByb3llY3RvcyBtw6FzIHBlcXVlw7FvcyBjb24gMS0yIGFyY2hpdm9zIGRlIGRhdG9zLCB1biBwYXIgZGUgc2NyaXB0cyB5IHVuIGRvY3VtZW50byBSIE1hcmtkb3duLCBlc3TDoSBiaWVuIG1hbnRlbmVybG9zIHRvZG9zIGVuIGxhIGNhcnBldGEgUHJveWVjdG8gKHBlcm8gcmVwZXRpbW9zLCBjYWRhIFByb3llY3RvIGRlYmUgdGVuZXIgc3UgcHJvcGlhIGNhcnBldGEpLiBVbmEgdmV6IHF1ZSBsYSBjYW50aWRhZCBkZSBhcmNoaXZvcyBjcmV6Y2EgbcOhcyBhbGzDoSBkZSBlc28sIGRlYmUgYWdyZWdhciBjYXJwZXRhcyBzZXBhcmFkYXMgcGFyYSBkaWZlcmVudGVzIHRpcG9zIGRlIGFyY2hpdm9zLg0KDQpBcXXDrSBlc3TDoSBudWVzdHJvIGVuZm9xdWUgc3VnZXJpZG8uIFNlZ8O6biBsYSBuYXR1cmFsZXphIGRlIHN1cyBhbsOhbGlzaXMsIGxhIGNhbnRpZGFkIGRlIGNhcnBldGFzIHB1ZWRlIHNlciBtZW5vciBvIG1heW9yIHF1ZSBlc3RvLCB5IHB1ZWRlbiB0ZW5lciB1biBub21icmUgZGlmZXJlbnRlDQoNCmBgYA0KcHJvai8NCi0gc2NyaXB0cy8NCi0gZGF0YV9yYXcvDQotIGRhdGFfcHJvY2Vzc2VkLw0KLSBmaWd1cmVzLw0KLSAwMF9hbmFseXNpcy5SbWQNCg0KYGBgDQpgc2NyaXB0cy9gIGNvbnRpZW5lIHRvZG9zIGxvcyBgLlJgIGFyY2hpdm9zIGRlIHNjcmlwdCB1dGlsaXphZG9zIHBhcmEgbGEgbGltcGllemEvcHJlcGFyYWNpw7NuIGRlIGRhdG9zLiBTaSBzb2xvIHRpZW5lIGFsZ3Vub3Mgc2NyaXB0cywgZXN0w6EgYmllbiBubyB0ZW5lciBlc3RlIHkgc2ltcGxlbWVudGUgbWFudGVuZXIgbG9zIGAuUmAgYXJjaGl2b3MgZW4gbGEgY2FycGV0YSBkZWwgcHJveWVjdG8gKGRvbmRlIGAwMF9hbmFseXNpcyAuUm1kYCBlc3TDoSBlbiBlbCBlamVtcGxvIGFudGVyaW9yKS4gYGRhdGFfcmF3YCAvY29udGllbmUgdG9kb3MgbG9zIGRhdG9zIHNpbiBwcm9jZXNhciwgY29tbyBgLmNzdmAgYXJjaGl2b3MsIGRhdGFfcHJvY2Vzc2VkL2NvbnRpZW5lIGRhdG9zIHF1ZSBoYSB0b21hZG8gc2luIHByb2Nlc2FyLCBsaW1waWFkb3MsIG1vZGlmaWNhZG9zLCB1bmlkb3MgbyBjYW1iaWFkb3MgZGUgb3RybyBtb2RvIG1lZGlhbnRlIHNjcmlwdHMgUi4gZmlndXJlcy9wdWVkZSBjb250ZW5lciBncsOhZmljb3MgKHAuIGVqLiwgYC5wbmcsYCBgLmpwZ2AsIGAucGRmYCkgYDAwX2FuYWx5c2lzLlJtZGAgbyBgMDBfYW5hbHlzaXMuUmAgZXMgZWwgYXJjaGl2byBkZSB0cmFiYWpvIHByaW5jaXBhbCByZWFsLCB5IGxvIG1hbnRlbmVtb3MgZW4gZWwgZGlyZWN0b3JpbyBwcmluY2lwYWwgZGVsIHByb3llY3RvLg0KDQpTdXMgc2NyaXB0cyBSIGRlYmVuIG51bWVyYXJzZSBjb24gZG9zIGTDrWdpdG9zIHkgZGViZW4gdGVuZXIgbm9tYnJlcyBzaWduaWZpY2F0aXZvcywgcG9yIGVqZW1wbG86DQoNCmBgYA0Kc2NyaXB0cy8wMF9zb3VyY2VfYWxsLlINCnNjcmlwdHMvMDFfcmVhZF9kYXRhLlINCnNjcmlwdHMvMDJfbWFrZV9mYWN0b3JzLlINCnNjcmlwdHMvMDNfZHVwbGljYXRlX3JlY29yZHMuUg0KDQpgYGANCg0KUG9yIGVqZW1wbG8sIGAwMV9yZWFkX2RhdGEuUmAgcHVlZGUgdmVyc2UgYXPDrS4NCg0KDQpgYGB7cn0NCiMgUHJveWVjdG8gZGUgbWVsYW5vbWENCiMjIGV4dHJhY2Npw7NuIGRlIGRhdG9zDQojIE9idGVuZXIgZGF0b3MNCmxpYnJhcnkocmVhZHIpDQptZWxhbm9tYSA8LSByZWFkX2NzdigNCiAgaGVyZTo6aGVyZSgiZGF0YV9yYXciLCAibWVsYW5vbWEuY3N2IikNCikNCg0KIyBPdGhlciBiYXNpYyByZWNjb2Rpbmcgb3IgcmVuYW1pbmcgZnVuY3Rpb25zIGhlcmUNCg0KIyBTYXZlDQpzYXZlKG1lbGFub21hLCBmaWxlID0gDQogIGhlcmU6OmhlcmUoImRhdGFfcHJvY2Vzc2VkIiwgIm1lbGFub21hX3dvcmtpbmcucmRhIikNCikNCmBgYA0KDQpUZW5nYSBlbiBjdWVudGEgZWwgdXNvIGRlIGBoZXJlOjpoZXJlKClgLiBMb3MgcHJveWVjdG9zIGRlIFJTdHVkaW8gYWRtaW5pc3RyYW4gbG9zIGRpcmVjdG9yaW9zIGRlIHRyYWJham8gZGUgdW5hIG1lam9yIG1hbmVyYSBxdWUgYHNldHdkKClgLiBgaGVyZTo6aGVyZSgpYCBlcyDDunRpbCBjdWFuZG8gc2UgY29tcGFydGVuIHByb3llY3RvcyBlbnRyZSBtw6FxdWluYXMgTGludXgsIE1hYyB5IFdpbmRvd3MsIHF1ZSB0aWVuZW4gZGlmZXJlbnRlcyBjb252ZW5jaW9uZXMgcGFyYSBsYXMgcnV0YXMgZGUgbG9zIGFyY2hpdm9zLg0KDQpQb3IgZWplbXBsbywgZW4gdW5hIE1hYyBsbyBoYXLDrWEgZGUgb3RyYSBtYW5lcmEgYHJlYWRfY3N2KCJkYXRhL21lbGFub21hLmNzdiIpYHkgZW4gV2luZG93cyB0ZW5kcsOtYSBxdWUgaGFjZXIgYHJlYWRfY3N2KCJkYXRhXG1lbGFub21hLmNzdiIpYC4gVGVuZXIgcXVlIGluY2x1aXIgYC9gKEdOVS9MaW51eCwgbWFjT1MpIG8gYFxgIChXaW5kb3dzKSBlbiBzdSBzZWN1ZW5jaWEgZGUgY29tYW5kb3Mgc2lnbmlmaWNhIHF1ZSB0ZW5kcsOhIHF1ZSBjYW1iaWFyc2UgYSBtYW5vIGN1YW5kbyBzZSBlamVjdXRlIGVuIHVuIHNpc3RlbWEgZGlmZXJlbnRlLiBMbyBxdWUgYGhlcmU6OmhlcmUoImRhdGFfcmF3IiwgIm1lbGFub21hLmNzdiIpYCwgc2luIGVtYmFyZ28sIGZ1bmNpb25hIGVuIGN1YWxxdWllciBzaXN0ZW1hLCB5YSBxdWUgdXRpbGl6YXLDoSB1bm8gYXByb3BpYWRvICdkZXRyw6FzIGRlIGVzY2VuYScgc2luIHF1ZSB0ZW5nYXMgcXVlIGNhbWJpYXIgbmFkYS4NCg0KYDAyX21ha2VfZmFjdG9yc2AuUmVzIG51ZXN0cm8gc2VndW5kbyBhcmNoaXZvIGRlIGVqZW1wbG8sIHBlcm8gcG9kcsOtYSBzZXIgY3VhbHF1aWVyIGNvc2EgcXVlIGRlc2VlLiBQb2Ryw61hIHZlcnNlIGFsZ28gY29tbyBlc3RvLg0KDQpgYGAgcg0KIyBQcm95ZWN0byBNZWxhbm9tYSANCiMjIENyZWFuZG8gZmFjdG9yZXMNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbG9hZCgNCiAgaGVyZTo6aGVyZSgiZGF0YV9wcm9jZXNzZWQiLCAibWVsYW5vbWFfd29ya2luZy5yZGEiKQ0KKQ0KIyMgUmVjb2RlIHZhcmlhYmxlcw0KbWVsYW5vbWEgPC0gbWVsYW5vbWEgJT4lDQogIG11dGF0ZSgNCiAgICBzZXggPSBmYWN0b3Ioc2V4KSAlPiUgDQogICAgICBmY3RfcmVjb2RlKCJNYWxlIiA9ICIxIiwgDQogICAgICAgICAgICAgICAgICJGZW1hbGUiID0gIjAiKQ0KICApDQojIFNhbHZhcg0Kc2F2ZShtZWxhbm9tYSwgZmlsZSA9IA0KICBoZXJlOjpoZXJlKCJkYXRhIiwgIm1lbGFub21hX3dvcmtpbmcucmRhIikNCikNCmBgYA0KDQoNClRvZG9zIGVzdG9zIGFyY2hpdm9zIHNlIHB1ZWRlbiByZXVuaXIgZW4gdW4gc29sbyBhcmNoaXZvIGVuIGZvcm1hdG8gc291cmNlKCkuIEVzdGEgZnVuY2nDs24gc2UgdXRpbGl6YSBwYXJhIGVqZWN1dGFyIGPDs2RpZ28gZGVzZGUgdW4gYXJjaGl2by4NCg0KYDAwX3NvdXJjZV9hbGwuUmAgcG9kcsOtYSB2ZXJzZSBhc8OtOg0KDQpgYGB7cn0NCiMgTWVsYW5vbWEgcHJvamVjdA0KIyMgU291cmNlIGFsbA0Kc291cmNlKCBoZXJlOjpoZXJlKCJzY3JpcHRzIiwgIjAxX2RhdGFfdXBsb2FkLlIiKSApDQpzb3VyY2UoIGhlcmU6OmhlcmUoInNjcmlwdHMiLCAiMDJfbWFrZV9mYWN0b3JzLlIiKSApIA0Kc291cmNlKCBoZXJlOjpoZXJlKCJzY3JpcHRzIiwgIjAzX2R1cGxpY2F0ZV9yZWNvcmRzLlIiKSApIA0KIyBTYXZlDQpzYXZlKG1lbGFub21hLCBmaWxlID0gDQogIGhlcmU6OmhlcmUoImRhdGFfcHJvY2Vzc2VkIiwgIm1lbGFub21hX2ZpbmFsLnJkYSIpDQopDQoNCmBgYA0KQWhvcmEgcHVlZGUgdHJhZXIgc3VzIGRhdG9zIHPDs2xpZGFtZW50ZSBwcmVwYXJhZG9zIGEgc3UgYXJjaGl2byBkZSBhbsOhbGlzaXMsIHF1ZSBwdWVkZSBzZXIgYC5SYCBvIGAuUm1kYCBzaSBlc3TDoSB0cmFiYWphbmRvIGVuIHVuIGN1YWRlcm5vLiBMbGFtYW1vcyBhIGVzdG8gYDAwX2FuYWx5c2lzLlJtZGAgeSBzaWVtcHJlIHNlIGVuY3VlbnRyYSBlbiBlbCBkaXJlY3RvcmlvIHJhw616IGRlbCBwcm95ZWN0by4gVGllbmUgZG9zIG9wY2lvbmVzIHBhcmEgdHJhZXIgbG9zIGRhdG9zLg0KDQoxLmBzb3VyY2UoIjAwX3NvdXJjZV9hbGwuUiIpYHBhcmEgdm9sdmVyIGEgY2FyZ2FyIHkgcHJvY2VzYXIgbG9zIGRhdG9zIGRlIG51ZXZvDQogICsgZXN0byBlcyDDunRpbCBzaSBsb3MgZGF0b3MgZXN0w6FuIGNhbWJpYW5kbw0KICArIHB1ZWRlIGxsZXZhciBtdWNobyB0aWVtcG8gc2kgc2UgdHJhdGEgZGUgdW4gZ3JhbiBjb25qdW50byBkZSBkYXRvcyBjb24gbXVjaGFzIG1hbmlwdWxhY2lvbmVzDQoyLmBsb2FkKCJtZWxhbm9tYV9maW5hbC5yZGEiKWAgZGUgbGEgYGRhdGFfcHJvY2Vzc2VkL2BjYXJwZXRhDQogICsgZ2VuZXJhbG1lbnRlIG3DoXMgcsOhcGlkbywgcGVybyBjYXJnYSBlbCBjb25qdW50byBkZSBkYXRvcyBxdWUgc2UgY3Jlw7MgbGEgw7psdGltYSB2ZXogcXVlIGVqZWN1dMOzYDAwX3NvdXJjZV9hbGwuUmANCiAgDQo+IFJlY3VlcmRhOiBQYXJhIGAuUmAgYXJjaGl2b3MgdXNhIGBzb3VyY2UoKWAsIHBhcmEgYC5yZGFgIGFyY2hpdm9zIHVzYSBgbG9hZCgpYC4NCg0KTGFzIGRvcyBvcGNpb25lcyBzZSB2ZW4gYXPDrToNCg0KDQpgYGBgbWFya2Rvd24NCi0tLQ0KdGl0bGU6ICJNZWxhbm9tYSBhbmFseXNpcyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCmByICcnYGBgYHtyIGdldC1kYXRhLW9wdGlvbi0xLCBlY2hvPUZBTFNFfQ0KbG9hZCgNCiAgaGVyZTpoZXJlKCJkYXRhIiwgIm1lbGFub21hX2FsbC5yZGEiKQ0KKQ0KYGBgDQoNCmByICcnYGBgYHtyIGdldC1kYXRhLW9wdGlvbi0yLCBlY2hvPUZBTFNFfQ0Kc291cmNlKA0KICBoZXJlOmhlcmUoIlIiLCAiMDBfc291cmNlX2FsbC5SIikNCikNCmBgYGANCg0KIyMjIDEyLjcuMSDCv1BvciBxdcOpIGRhcnNlIHRvZGFzIGVzdGFzIG1vbGVzdGlhcz8NCg0KVmllbmUgZGUgbXVjaG9zIGHDsW9zIGRlIGVuY29udHJhciBlcnJvcmVzIGRlYmlkbyBhIHByb3llY3RvcyBtYWwgb3JnYW5pemFkb3MuIE5vIGVzIG5lY2VzYXJpbyBwYXJhIHVuIHBlcXVlw7FvIHByb3llY3RvIHLDoXBpZG8sIHBlcm8gZXMgZXNlbmNpYWwgcGFyYSBjdWFscXVpZXIgdHJhYmFqbyBpbXBvcnRhbnRlLg0KDQpBbCBjb21pZW56byBkZSB1biBhbsOhbGlzaXMgKGNvbW8gZW4gZWwgcHJpbWVyIGTDrWEpLCBjb21lbnphcmVtb3MgYSB0cmFiYWphciBlbiB1biBzb2xvIGFyY2hpdm8uIE1vdmVyZW1vcyByw6FwaWRhbWVudGUgZnJhZ21lbnRvcyBkZSBjw7NkaWdvIGRlIGxpbXBpZXphL3ByZXBhcmFjacOzbiBkZSBkYXRvcyBlbiBhcmNoaXZvcyBzZXBhcmFkb3MgYSBtZWRpZGEgcXVlIGF2YW56YW1vcy4NCg0KTGEgY29tcGFydGltZW50YWNpw7NuIGRlIGxhIGxpbXBpZXphIGRlIGRhdG9zIGF5dWRhIGEgZW5jb250cmFyIHkgdHJhdGFyIGxvcyBlcnJvcmVzICgiZGVwdXJhY2nDs24iKS4gTG9zIGFyY2hpdm9zIG9yaWdpbmFsZXMgc2UgcHVlZGVuICdjb21lbnRhcicgKGFncmVnYW5kbyB1biAjIGEgdW5hIGzDrW5lYSBlbiBlbCBgMDBfc291cmNlX2FsbC5SYCBhcmNoaXZvKSBzaSBkZXNlYSBleGNsdWlyIGxhcyBtYW5pcHVsYWNpb25lcyBlbiBlc2UgYXJjaGl2byBlbiBwYXJ0aWN1bGFyLg0KDQpMbyBtw6FzIGltcG9ydGFudGUsIGF5dWRhIGNvbiBsYSBjb2xhYm9yYWNpw7NuLiBDdWFuZG8gdmFyaWFzIHBlcnNvbmFzIHRyYWJhamFuIGVuIHVuIHByb3llY3RvLCBlcyBlc2VuY2lhbCBxdWUgbGEgY29tdW5pY2FjacOzbiBzZWEgYnVlbmEgeSBxdWUgdG9kb3MgdHJhYmFqZW4gc2Vnw7puIGVsIG1pc21vIHBsYW4gZ2VuZXJhbC4NCg0KDQoNCg0KDQoNCg==