Tecnológico de Costa Rica

Curso: Introducción a la Programación con R

Trabajo de Investigación 1

Profesor: Luis Fernando Castro

Estudiantes:


Introducción

Actualmente, es difícil imaginar a un investigador, científico o analista de datos realizando un análisis estadístico sin la ayuda de un software especializado. Como menciona Fernández (2020), en general, un software de análisis estadístico alude a los programas informáticos con módulos orientados a la tabulación, gestión, modificación, análisis y representación gráfica de datos. En efecto, estos programas tienen ventajas respecto al cálculo manual, ya que reducen el tiempo dedicado al análisis, aumentan su precisión, editan información, representaciones gráficas y salidas para elaborar informes, entre otras funciones.

No hay más reiterar que para lograr un uso adecuado —y por ende efectivo— de este tipo de software, se requiere del despliegue de conocimientos estadísticos que permitan hacer los análisis e interpretaciones que potencialmente deban realizarse. Por otro lado, a menudo se hace la distinción entre los software de pago y los software gratuitos.

De entre los variados softwares gratuitos actualmente disponibles destaca uno que, por su cada vez mayor aceptación y promoción en los ámbitos académico e investigativo, se ha convertido en un potente referente en lo que respecta a la computación estadística de alto nivel como apoyo a las más diversas disciplinas científicas; nos referimos a R. Como tal R es un lenguaje de programación empleado primordialmente para efectuar análisis estadístico de datos y construcción de gráficos. Tiene características que lo sitúan muy por encima de prácticamente todos sus “competidores”: es gratuito y libre, es muy versátil, permite realizar una cantidad insospechable de procedimientos estadísticos y gráficos, permite construir gráficos de calidad inmejorable, etc.

Es justo dentro del mundo del lenguaje de programación R que encontramos a Shiny, que es un paquete (un conjunto de funciones) para R. El propósito de Shiny es facilitar el desarrollo de aplicaciones web que permiten a los usuarios interactuar con el código de R en un navegador y mediante elementos de la interfaz de usuario (UI) como controles deslizantes, menús desplegables, etc. En el presente trabajo de investigación ahondaremos en aspectos básicos sobre Shiny, que ofrecen una visión general de las capacidades de esta herramienta, un poco de su historia, funciones y componentes, y ejemplos de uso. También prepararemos un archivo adicional de una aplicación Shiny, que muestre el contenido del dataset Iris.

Desarrollo

¿Qué es Shiny ?

Como menciona Wickham (2021), Shiny es un paquete de R que permite crear fácilmente aplicaciones web ricas e interactivas. Permite tomar el trabajo en R y exponerlo a través de un navegador web para que cualquiera pueda utilizarlo.

En el pasado, crear aplicaciones web era difícil para la mayoría de los usuarios de R porque se necesitaba un conocimiento profundo de tecnologías web como HTML, CSS y JavaScript y crear aplicaciones interactivas complejas requería un análisis cuidadoso de los flujos de interacción para asegurarse de que cuando se cambiaba una entrada, solo las salidas relacionadas se actualizaban.

Shiny facilita significativamente a los programadores de R la creación de aplicaciones web al proporcionar un conjunto cuidadosamente seleccionado de funciones de interfaz de usuario (abreviado como UI) que generan el HTML, CSS y JavaScript necesarios para tareas comunes e introducir un nuevo estilo de programación llamado programación reactiva, que rastrea automáticamente las dependencias de las partes del código. Esto significa que cada vez que cambia una entrada, Shiny puede determinar automáticamente cómo hacer la menor cantidad de trabajo para actualizar todas las salidas relacionadas.

Historia de Shiny

Shiny fue creado por Joe Cheng, un ingeniero de software en RStudio, en 2012. La motivación principal detrás de su desarrollo fue la necesidad de una herramienta que permitiera a los usuarios de R, principalmente estadísticos y científicos de datos, crear aplicaciones web sin tener que aprender tecnologías de desarrollo web como HTML, CSS o JavaScript.

Lanzamiento Inicial:

Shiny fue lanzado por primera vez en 2012. El paquete permitió a los usuarios crear aplicaciones interactivas con solo unos pocos comandos en R. Esto democratizó el acceso al desarrollo de aplicaciones web dentro de la comunidad de usuarios de R, ya que hizo que la creación de interfaces gráficas interactivas fuera mucho más accesible.

Crecimiento y Popularidad:

Tras su lanzamiento, Shiny ganó rápidamente popularidad debido a su facilidad de uso y la potencia de las aplicaciones que se podían construir con él. RStudio continuó mejorando Shiny, agregando características y optimizaciones para manejar aplicaciones más grandes y complejas. La comunidad alrededor de Shiny también creció, con numerosos paquetes y extensiones desarrollados para complementar y expandir sus capacidades.

Evolución y Actualizaciones:

A lo largo de los años, Shiny ha recibido numerosas actualizaciones que han mejorado su funcionalidad y rendimiento. Algunas de las adiciones más importantes incluyen la integración con bibliotecas de visualización como ggplot2, el soporte para aplicaciones escalables, y mejoras en la gestión de sesiones y en la implementación de aplicaciones Shiny en servidores.

Uso en la Actualidad:

Hoy en día, Shiny es ampliamente utilizado en la academia, la industria y el gobierno para crear dashboards, visualizaciones interactivas, y aplicaciones de análisis de datos. Su capacidad para integrar análisis complejos en tiempo real y su flexibilidad lo han convertido en una herramienta esencial para muchos analistas de datos.

Funciones principales de Shiny

Shiny permite realizar las siguientes actividades:

  • Crear dashboards que rastrean indicadores clave de rendimiento a alto nivel, mientras facilitan el análisis detallado de métricas que necesitan más investigación.

  • Reemplazar cientos de páginas de PDFs con aplicaciones interactivas que permiten al usuario ir directamente a la sección exacta de los resultados que les interesan.

  • Comunicar modelos complejos a una audiencia no técnica con visualizaciones informativas y análisis de sensibilidad interactivos.

  • Proporcionar análisis de datos de autoservicio para flujos de trabajo comunes, reemplazando solicitudes por correo electrónico con una aplicación Shiny que permite a las personas cargar sus propios datos y realizar análisis estándar.

  • Crear demostraciones interactivas para enseñar conceptos de estadística y ciencia de datos que permiten a los estudiantes modificar entradas y observar los efectos en el análisis.

En resumen, Shiny da la capacidad de transmitir algunos de “superpoderes en R” a cualquier persona que pueda usar la web.

Por otro lado, Shiny proporciona varias funciones principales que permiten a los usuarios crear aplicaciones web interactivas utilizando R:

  • shinyApp()

Esta es la función principal que se utiliza para lanzar una aplicación Shiny. Toma dos argumentos, ui (la interfaz de usuario) y server (la lógica del servidor), y los combina en una aplicación completa.

  • fluidPage()

Se utiliza para definir la estructura de la interfaz de usuario. Dentro de fluidPage(), se pueden incluir varios elementos de diseño, como filas (fluidRow()), columnas (column()), y otros componentes de la interfaz.

  • titlePanel()

Se utiliza para definir el título principal de la aplicación.

  • sidebarLayout()

Permite dividir la interfaz en una barra lateral (sidebarPanel()) y un panel principal (mainPanel()).

  • sidebarPanel()

Define el contenido de la barra lateral de la interfaz. Normalmente incluye controles de entrada como sliderInput(), selectInput(), etc.

  • mainPanel()

Contiene el contenido principal de la interfaz, como gráficos, tablas y otros elementos de salida.

  • input$ y output$

En el lado del servidor, los objetos input$ y output$ se utilizan para acceder a los valores de entrada y para definir salidas reactivas, respectivamente.

  • renderPlot(), renderTable(), renderText()

Estas funciones se utilizan en la parte del servidor para generar salidas reactivas que pueden ser gráficos, tablas, texto, entre otros. Estas salidas se enlazan con elementos en output$.

  • observe() y observeEvent()

Estas funciones se utilizan para ejecutar código en respuesta a cambios en entradas reactivas, sin generar un valor de salida. Son útiles para modificar la aplicación de manera reactiva sin producir una salida directa.

  • reactive()

Se utiliza para crear expresiones reactivas que pueden ser compartidas entre varias salidas. Una expresión reactiva recalcula su valor automáticamente cuando sus entradas cambian.

  • uiOutput() y renderUI()

Permiten generar dinámicamente partes de la interfaz de usuario con base en el código del servidor.

  • isolate()

Se utiliza para evitar que una expresión reactiva se vuelva a ejecutar automáticamente cuando cambian sus entradas. Es útil para optimizar la ejecución de código.

Componentes de una aplicación Shiny

Describiremos en esta sección los componentes de Shiny. La información recabada sobre los componentes se obtuvo de la publicación de Cuevas (2021).

Primero, para instalar Shiny, podemos utilizar los siguientes códigos:

install.packages("shiny") 
if (!require("devtools")) 
  install.packages("devtools") 
devtools::install_github("shiny", "rstudio") 

Tomemos en cuenta que toda aplicación web de Shiny tendrá la misma estructura, dos bloques de códigos de R:

  • UI: genera una interfaz de usuario

  • Server: contiene las instrucciones que la computadora necesita para crear la app.

La estructura de código de una app Shiny se vería del siguiente modo:

library(shiny) 
ui <- fluidPage( 
xxxxInput(), 
xxxxOutput() 
) 
server <- function(input, output) 
{ 
 Codigo de R 
} 
shinyApp(ui = ui, server = server) 

1. La Interfaz de Usuario (UI)

La interfaz de usuario define la estructura y el diseño de la aplicación Shiny.

Shiny por default usa bootstrap (lo cual no tiene nada que ver con el método estadístico bootstrap). Esto es un marco de trabajo de HTML, CSS y Javascript más popular para desarrollar sitios web receptivos.

Para usar todos los tags en Shiny, podemos consultar estos tags con la siguiente función:

shiny::tags 
names(shiny::tags) 

Shiny fomenta la separación del código que genera su interfaz de usuario (el front-end) del código que impulsa el comportamiento de su aplicación (el back-end):

Existe una comunidad rica y vibrante de paquetes de extensión, como shinyWidgets, colorpicker y sorttable.

2. El servidor (server)

El servidor define la lógica de la aplicación, incluyendo cómo se procesan las entradas y cómo se generan las salidas.

Hay 3 reglas para escribir código en el Server:

  • Especifica con output$ + ID output cada objeto dentro de server.

  • Cada objeto se mostrará con un render(), ejemplo renderPlot({})

  • Accesa a los valores de los inputs con input$ + ID input

3. Reactividad

Shiny está basado en un modelo reactivo que actualiza automáticamente las salidas cuando cambian las entradas. Los componentes clave para manejar la reactividad incluyen:

  • Expresiones reactivas: Se crean usando reactive() y se pueden compartir entre múltiples salidas.

  • Observadores: Usan observe() para monitorear cambios en las entradas y ejecutar código en consecuencia.

  • Aislamiento de reactivos: La función isolate() evita que una expresión reactiva se recalcula cuando cambian sus dependencias.

4. Componentes de Extensión

  • shinyModules: Permiten la modularización del código Shiny, dividiendo la aplicación en componentes reutilizables.

  • shinyWidgets: Un paquete adicional que proporciona widgets adicionales para mejorar la interactividad y la estética de las aplicaciones.

  • shinyjs: Permite integrar funcionalidades de JavaScript en una aplicación Shiny, ofreciendo un control más detallado de la interacción del usuario.

Los anteriores son los componentes principales de Shiny que permiten construir aplicaciones web interactivas. Cada uno juega un papel crucial en la estructura y funcionalidad de una aplicación Shiny, haciendo posible la creación de interfaces dinámicas y reactivas con un esfuerzo relativamente bajo.

Ejemplos de uso

Shiny es una biblioteca en R que facilita la creación de aplicaciones web interactivas. Entre lo que permite hacer tenemos:

  1. Crear Interfaces Interactivas: construir aplicaciones web con interfaces gráficas interactivas para visualizar datos, realizar análisis y crear dashboards.

  2. Visualizar Datos: crear gráficos dinámicos y tablas que se actualizan en tiempo real en función de las entradas del usuario.

  3. Desarrollar Aplicaciones de Datos: construir aplicaciones para realizar análisis estadísticos, modelado predictivo o cualquier tipo de procesamiento de datos en línea.

  4. Construir Dashboards: construir paneles de control completos para supervisar métricas y datos en tiempo real.

  5. Crear Formularios y Aplicaciones de Entrada de Datos: diseñar formularios para la entrada de datos y procesar los resultados directamente en la aplicación.

  6. Integrar con Otras Herramientas: Shiny puede integrarse con otras herramientas y paquetes de R, como ggplot2 para gráficos y dplyr para manipulación de datos.

  7. Implementar Modelos de Machine Learning: construir aplicaciones que muestren predicciones y resultados de modelos de aprendizaje automático en una interfaz de usuario interactiva.

  8. Desplegar Aplicaciones: Puedes desplegar tus aplicaciones Shiny en servidores locales o en la nube, como ShinyApps.io o en servidores propios usando Shiny Server.


A continuación, se estudian dos ejemplos de uso concretos de Shiny para la creación de aplicaciones:

Cálculo de la distancia punto a línea

En el 2018, un autor de blog utilizó la librería para poder visualizar la distancia de un punto especifico de Mexico a la línea fronteriza con Estados Unidos.

  1. Para poder filtrar la información necesaria en cuanto a la localización de estados y demás, se descargó la información sobre la línea de la frontera para poder utilizarla en R. Una vez cargada la información, fue posible realizar su lectura utilizando la función sf::st_read().
 f <- st_read("Mexico_and_US_Border.shp")
  1. Seguidamente, se dibujaron los datos con el fin de confirmar que se tenían los datos necesarios.
  plot(f, max.plot = 1)
  1. Se definió el punto que se tomaría de referencia para sacar la distancia con respecto a la frontera. Se eligió tomar como referencia el Colegio de México. Para la utilización de las coordenadas de dicho lugar, se usó Google Maps. Con esta referencia se creó la tabla latitud/longitud.
pto <- data.frame(x = -99.20775, y = 19.303741) %>% 
  st_as_sf(coords = c("x", "y")) 

# Homologando el Sistema de Coordenadas de Referencia con la base de la línea de la Frontera Norte
st_crs(pto) <- st_crs(f)
  1. Se calculó la distancia utilizando la función st_distance() para calcular la distancia geodésica que hay entre dos elementos geográficos del mapa.
  2. Con la información anterior se determinó el punto más cercano de la frontera al Colegio de México, pero surgió la pregunta de en dónde está, por lo que se descompuso la línea de la frontera norte en vértices y componentes con el fin de determinar la línea con la menor longitud
  3. Después de una serie de pasos, se logró visualizar el punto con el uso del código:
linea <- st_linestring(matrix(c(pto[,"geometry"] %>% 
                              st_coordinates(), 
                              punto_frontera[,"geometry"] %>% st_coordinates()), ncol = 2, byrow = TRUE))
  1. Se plasmó en un mapa de leaflet
 leaflet() %>% 
      addTiles() %>% 
      addCircleMarkers(data = pto) %>% 
      addCircleMarkers(data = punto_frontera) %>% 
      addPolylines(data = linea) %>% 
      addPolylines(data = f, color = "red")
  1. Finalmente, se obtuvieron los siguientes resultados, que le permitió determinar que el punto más cercano a la frontera norte se encuentra unos kilómetros al Este de la Ciudad de Matamoros, en el Estado de Tamaulipas.

Con la información anterior, el autor creó un Shiny app, con el fin de que cualquier usuario pueda calcular la distancia de cualquier punto a la frontera sur de Estados Unidos. En este caso, el superpoder que se pasó fue el de poder calcular la distancia y poder construir la línea de mínima distancia tan solo con presionar un punto en el mapa.

Ecobici(Datatón)

Esta aplicación fué una entrada para el Datatón de Visualización de datos de ecobici del CIMAT. Su realización fué un trabajo conjunto entre analistas que usaron Python y R para el análisis de datos, comunicando los resultados a la aplicación a través de una API.

Ecobici es un sistema de bicicletas compartidas lanzado en febrero de 2010 por el gobierno de la Ciudad de México para la realización de viajes de corta distancia y duración a precios reducidos o de forma gratuita. El sistema cuenta con 480 cicloestaciones y más de 6 mil 800 bicicletas, de las cuales 28 estaciones y 340 bicicletas forman parte del nuevo sistema de bicicletas eléctricas de pedaleo asistido.

Conclusiones

Shiny ha transformado el panorama del análisis de datos y la visualización al permitir a los usuarios de R crear aplicaciones web interactivas sin necesidad de conocimientos avanzados en desarrollo web. Su flexibilidad, combinada con el poder de R, lo convierte en una herramienta invaluable para científicos de datos, analistas y desarrolladores en una variedad de campos.

A medida que la tecnología avanza, es probable que Shiny continúe evolucionando, incorporando nuevas funciones y capacidades que faciliten aún más la creación de aplicaciones web sofisticadas y atractivas.

Bibliografía

LS0tDQp0aXRsZTogIkxpYnJlcsOtYSBTaGlueSBkZSBSIg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOiBkZWZhdWx0DQogIHBkZl9kb2N1bWVudDogZGVmYXVsdA0KICBodG1sX2RvY3VtZW50Og0KICAgIGRmX3ByaW50OiBwYWdlZA0KICB3b3JkX2RvY3VtZW50OiBkZWZhdWx0DQotLS0NCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNClRlY25vbMOzZ2ljbyBkZSBDb3N0YSBSaWNhDQoNCkN1cnNvOiBJbnRyb2R1Y2Npw7NuIGEgbGEgUHJvZ3JhbWFjacOzbiBjb24gUg0KDQpUcmFiYWpvIGRlIEludmVzdGlnYWNpw7NuIDENCg0KUHJvZmVzb3I6IEx1aXMgRmVybmFuZG8gQ2FzdHJvDQoNCkVzdHVkaWFudGVzOg0KDQotICAgTWFyaWNydXogVmFyZ2FzIFJhbcOtcmV6DQotICAgTGF1cmEgUm9kcsOtZ3VleiBWYXJnYXMNCi0gICBNYXLDrWEgR2FicmllbGEgU2V2ZXJpbm8gQ2FsZGVyw7NuDQotICAgU2ViYXN0acOhbiBDYWJlemFzIEppbcOpbmV6DQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIyBJbnRyb2R1Y2Npw7NuDQoNCkFjdHVhbG1lbnRlLCBlcyBkaWbDrWNpbCBpbWFnaW5hciBhIHVuIGludmVzdGlnYWRvciwgY2llbnTDrWZpY28gbyBhbmFsaXN0YSBkZSBkYXRvcyByZWFsaXphbmRvIHVuIGFuw6FsaXNpcyBlc3RhZMOtc3RpY28gc2luIGxhIGF5dWRhIGRlIHVuIHNvZnR3YXJlIGVzcGVjaWFsaXphZG8uIENvbW8gbWVuY2lvbmEgRmVybsOhbmRleiAoMjAyMCksIGVuIGdlbmVyYWwsIHVuIHNvZnR3YXJlIGRlIGFuw6FsaXNpcyBlc3RhZMOtc3RpY28gYWx1ZGUgYSBsb3MgcHJvZ3JhbWFzIGluZm9ybcOhdGljb3MgY29uIG3Ds2R1bG9zIG9yaWVudGFkb3MgYSBsYSB0YWJ1bGFjacOzbiwgZ2VzdGnDs24sIG1vZGlmaWNhY2nDs24sIGFuw6FsaXNpcyB5IHJlcHJlc2VudGFjacOzbiBncsOhZmljYSBkZSBkYXRvcy4gRW4gZWZlY3RvLCBlc3RvcyBwcm9ncmFtYXMgdGllbmVuIHZlbnRhamFzIHJlc3BlY3RvIGFsIGPDoWxjdWxvIG1hbnVhbCwgeWEgcXVlIHJlZHVjZW4gZWwgdGllbXBvIGRlZGljYWRvIGFsIGFuw6FsaXNpcywgYXVtZW50YW4gc3UgcHJlY2lzacOzbiwgZWRpdGFuIGluZm9ybWFjacOzbiwgcmVwcmVzZW50YWNpb25lcyBncsOhZmljYXMgeSBzYWxpZGFzIHBhcmEgZWxhYm9yYXIgaW5mb3JtZXMsIGVudHJlIG90cmFzIGZ1bmNpb25lcy4NCg0KTm8gaGF5IG3DoXMgcmVpdGVyYXIgcXVlIHBhcmEgbG9ncmFyIHVuIHVzbyBhZGVjdWFkbyDigJR5IHBvciBlbmRlIGVmZWN0aXZv4oCUIGRlIGVzdGUgdGlwbyBkZSBzb2Z0d2FyZSwgc2UgcmVxdWllcmUgZGVsIGRlc3BsaWVndWUgZGUgY29ub2NpbWllbnRvcyBlc3RhZMOtc3RpY29zIHF1ZSBwZXJtaXRhbiBoYWNlciBsb3MgYW7DoWxpc2lzIGUgaW50ZXJwcmV0YWNpb25lcyBxdWUgcG90ZW5jaWFsbWVudGUgZGViYW4gcmVhbGl6YXJzZS4gUG9yIG90cm8gbGFkbywgYSBtZW51ZG8gc2UgaGFjZSBsYSBkaXN0aW5jacOzbiBlbnRyZSBsb3Mgc29mdHdhcmUgZGUgcGFnbyB5IGxvcyBzb2Z0d2FyZSBncmF0dWl0b3MuDQoNCkRlIGVudHJlIGxvcyB2YXJpYWRvcyBzb2Z0d2FyZXMgZ3JhdHVpdG9zIGFjdHVhbG1lbnRlIGRpc3BvbmlibGVzIGRlc3RhY2EgdW5vIHF1ZSwgcG9yIHN1IGNhZGEgdmV6IG1heW9yIGFjZXB0YWNpw7NuIHkgcHJvbW9jacOzbiBlbiBsb3Mgw6FtYml0b3MgYWNhZMOpbWljbyBlIGludmVzdGlnYXRpdm8sIHNlIGhhIGNvbnZlcnRpZG8gZW4gdW4gcG90ZW50ZSByZWZlcmVudGUgZW4gbG8gcXVlIHJlc3BlY3RhIGEgbGEgY29tcHV0YWNpw7NuIGVzdGFkw61zdGljYSBkZSBhbHRvIG5pdmVsIGNvbW8gYXBveW8gYSBsYXMgbcOhcyBkaXZlcnNhcyBkaXNjaXBsaW5hcyBjaWVudMOtZmljYXM7IG5vcyByZWZlcmltb3MgYSBSLiBDb21vIHRhbCBSIGVzIHVuIGxlbmd1YWplIGRlIHByb2dyYW1hY2nDs24gZW1wbGVhZG8gcHJpbW9yZGlhbG1lbnRlIHBhcmEgZWZlY3R1YXIgYW7DoWxpc2lzIGVzdGFkw61zdGljbyBkZSBkYXRvcyB5IGNvbnN0cnVjY2nDs24gZGUgZ3LDoWZpY29zLiBUaWVuZSBjYXJhY3RlcsOtc3RpY2FzIHF1ZSBsbyBzaXTDumFuIG11eSBwb3IgZW5jaW1hIGRlIHByw6FjdGljYW1lbnRlIHRvZG9zIHN1cyDigJxjb21wZXRpZG9yZXPigJ06IGVzIGdyYXR1aXRvIHkgbGlicmUsIGVzIG11eSB2ZXJzw6F0aWwsIHBlcm1pdGUgcmVhbGl6YXIgdW5hIGNhbnRpZGFkIGluc29zcGVjaGFibGUgZGUgcHJvY2VkaW1pZW50b3MgZXN0YWTDrXN0aWNvcyB5IGdyw6FmaWNvcywgcGVybWl0ZSBjb25zdHJ1aXIgZ3LDoWZpY29zIGRlIGNhbGlkYWQgaW5tZWpvcmFibGUsIGV0Yy4NCg0KRXMganVzdG8gZGVudHJvIGRlbCBtdW5kbyBkZWwgbGVuZ3VhamUgZGUgcHJvZ3JhbWFjacOzbiBSIHF1ZSBlbmNvbnRyYW1vcyBhIFNoaW55LCBxdWUgZXMgdW4gcGFxdWV0ZSAodW4gY29uanVudG8gZGUgZnVuY2lvbmVzKSBwYXJhIFIuIEVsIHByb3DDs3NpdG8gZGUgU2hpbnkgZXMgZmFjaWxpdGFyIGVsIGRlc2Fycm9sbG8gZGUgYXBsaWNhY2lvbmVzIHdlYiBxdWUgcGVybWl0ZW4gYSBsb3MgdXN1YXJpb3MgaW50ZXJhY3R1YXIgY29uIGVsIGPDs2RpZ28gZGUgUiBlbiB1biBuYXZlZ2Fkb3IgeSBtZWRpYW50ZSBlbGVtZW50b3MgZGUgbGEgaW50ZXJmYXogZGUgdXN1YXJpbyAoVUkpIGNvbW8gY29udHJvbGVzIGRlc2xpemFudGVzLCBtZW7DunMgZGVzcGxlZ2FibGVzLCBldGMuIEVuIGVsIHByZXNlbnRlIHRyYWJham8gZGUgaW52ZXN0aWdhY2nDs24gYWhvbmRhcmVtb3MgZW4gYXNwZWN0b3MgYsOhc2ljb3Mgc29icmUgU2hpbnksIHF1ZSBvZnJlY2VuIHVuYSB2aXNpw7NuIGdlbmVyYWwgZGUgbGFzIGNhcGFjaWRhZGVzIGRlIGVzdGEgaGVycmFtaWVudGEsIHVuIHBvY28gZGUgc3UgaGlzdG9yaWEsIGZ1bmNpb25lcyB5IGNvbXBvbmVudGVzLCB5IGVqZW1wbG9zIGRlIHVzby4gVGFtYmnDqW4gcHJlcGFyYXJlbW9zIHVuIGFyY2hpdm8gYWRpY2lvbmFsIGRlIHVuYSBhcGxpY2FjacOzbiBTaGlueSwgcXVlIG11ZXN0cmUgZWwgY29udGVuaWRvIGRlbCBkYXRhc2V0IElyaXMuDQoNCiMjIERlc2Fycm9sbG8NCg0KIyMjIMK/UXXDqSBlcyBbU2hpbnldKGh0dHBzOi8vc2hpbnkucG9zaXQuY28vci9nZXRzdGFydGVkL3NoaW55LWJhc2ljcy9sZXNzb24xL2luZGV4Lmh0bWwpID8NCg0KQ29tbyBtZW5jaW9uYSBXaWNraGFtICgyMDIxKSwgU2hpbnkgZXMgdW4gcGFxdWV0ZSBkZSBSIHF1ZSBwZXJtaXRlIGNyZWFyIGbDoWNpbG1lbnRlIGFwbGljYWNpb25lcyB3ZWIgcmljYXMgZSBpbnRlcmFjdGl2YXMuIFBlcm1pdGUgdG9tYXIgZWwgdHJhYmFqbyBlbiBSIHkgZXhwb25lcmxvIGEgdHJhdsOpcyBkZSB1biBuYXZlZ2Fkb3Igd2ViIHBhcmEgcXVlIGN1YWxxdWllcmEgcHVlZGEgdXRpbGl6YXJsby4NCg0KRW4gZWwgcGFzYWRvLCBjcmVhciBhcGxpY2FjaW9uZXMgd2ViIGVyYSBkaWbDrWNpbCBwYXJhIGxhIG1heW9yw61hIGRlIGxvcyB1c3VhcmlvcyBkZSBSIHBvcnF1ZSBzZSBuZWNlc2l0YWJhIHVuIGNvbm9jaW1pZW50byBwcm9mdW5kbyBkZSB0ZWNub2xvZ8OtYXMgd2ViIGNvbW8gSFRNTCwgQ1NTIHkgSmF2YVNjcmlwdCB5IGNyZWFyIGFwbGljYWNpb25lcyBpbnRlcmFjdGl2YXMgY29tcGxlamFzIHJlcXVlcsOtYSB1biBhbsOhbGlzaXMgY3VpZGFkb3NvIGRlIGxvcyBmbHVqb3MgZGUgaW50ZXJhY2Npw7NuIHBhcmEgYXNlZ3VyYXJzZSBkZSBxdWUgY3VhbmRvIHNlIGNhbWJpYWJhIHVuYSBlbnRyYWRhLCBzb2xvIGxhcyBzYWxpZGFzIHJlbGFjaW9uYWRhcyBzZSBhY3R1YWxpemFiYW4uDQoNClNoaW55IGZhY2lsaXRhIHNpZ25pZmljYXRpdmFtZW50ZSBhIGxvcyBwcm9ncmFtYWRvcmVzIGRlIFIgbGEgY3JlYWNpw7NuIGRlIGFwbGljYWNpb25lcyB3ZWIgYWwgcHJvcG9yY2lvbmFyIHVuIGNvbmp1bnRvIGN1aWRhZG9zYW1lbnRlIHNlbGVjY2lvbmFkbyBkZSBmdW5jaW9uZXMgZGUgaW50ZXJmYXogZGUgdXN1YXJpbyAoYWJyZXZpYWRvIGNvbW8gVUkpIHF1ZSBnZW5lcmFuIGVsIEhUTUwsIENTUyB5IEphdmFTY3JpcHQgbmVjZXNhcmlvcyBwYXJhIHRhcmVhcyBjb211bmVzIGUgaW50cm9kdWNpciB1biBudWV2byBlc3RpbG8gZGUgcHJvZ3JhbWFjacOzbiBsbGFtYWRvIHByb2dyYW1hY2nDs24gcmVhY3RpdmEsIHF1ZSByYXN0cmVhIGF1dG9tw6F0aWNhbWVudGUgbGFzIGRlcGVuZGVuY2lhcyBkZSBsYXMgcGFydGVzIGRlbCBjw7NkaWdvLiBFc3RvIHNpZ25pZmljYSBxdWUgY2FkYSB2ZXogcXVlIGNhbWJpYSB1bmEgZW50cmFkYSwgU2hpbnkgcHVlZGUgZGV0ZXJtaW5hciBhdXRvbcOhdGljYW1lbnRlIGPDs21vIGhhY2VyIGxhIG1lbm9yIGNhbnRpZGFkIGRlIHRyYWJham8gcGFyYSBhY3R1YWxpemFyIHRvZGFzIGxhcyBzYWxpZGFzIHJlbGFjaW9uYWRhcy4NCg0KIyMjIEhpc3RvcmlhIGRlIFNoaW55DQoNClNoaW55IGZ1ZSBjcmVhZG8gcG9yIEpvZSBDaGVuZywgdW4gaW5nZW5pZXJvIGRlIHNvZnR3YXJlIGVuIFJTdHVkaW8sIGVuIDIwMTIuIExhIG1vdGl2YWNpw7NuIHByaW5jaXBhbCBkZXRyw6FzIGRlIHN1IGRlc2Fycm9sbG8gZnVlIGxhIG5lY2VzaWRhZCBkZSB1bmEgaGVycmFtaWVudGEgcXVlIHBlcm1pdGllcmEgYSBsb3MgdXN1YXJpb3MgZGUgUiwgcHJpbmNpcGFsbWVudGUgZXN0YWTDrXN0aWNvcyB5IGNpZW50w61maWNvcyBkZSBkYXRvcywgY3JlYXIgYXBsaWNhY2lvbmVzIHdlYiBzaW4gdGVuZXIgcXVlIGFwcmVuZGVyIHRlY25vbG9nw61hcyBkZSBkZXNhcnJvbGxvIHdlYiBjb21vIEhUTUwsIENTUyBvIEphdmFTY3JpcHQuDQoNCioqTGFuemFtaWVudG8gSW5pY2lhbDoqKg0KDQpTaGlueSBmdWUgbGFuemFkbyBwb3IgcHJpbWVyYSB2ZXogZW4gMjAxMi4gRWwgcGFxdWV0ZSBwZXJtaXRpw7MgYSBsb3MgdXN1YXJpb3MgY3JlYXIgYXBsaWNhY2lvbmVzIGludGVyYWN0aXZhcyBjb24gc29sbyB1bm9zIHBvY29zIGNvbWFuZG9zIGVuIFIuIEVzdG8gZGVtb2NyYXRpesOzIGVsIGFjY2VzbyBhbCBkZXNhcnJvbGxvIGRlIGFwbGljYWNpb25lcyB3ZWIgZGVudHJvIGRlIGxhIGNvbXVuaWRhZCBkZSB1c3VhcmlvcyBkZSBSLCB5YSBxdWUgaGl6byBxdWUgbGEgY3JlYWNpw7NuIGRlIGludGVyZmFjZXMgZ3LDoWZpY2FzIGludGVyYWN0aXZhcyBmdWVyYSBtdWNobyBtw6FzIGFjY2VzaWJsZS4NCg0KKipDcmVjaW1pZW50byB5IFBvcHVsYXJpZGFkOioqDQoNClRyYXMgc3UgbGFuemFtaWVudG8sIFNoaW55IGdhbsOzIHLDoXBpZGFtZW50ZSBwb3B1bGFyaWRhZCBkZWJpZG8gYSBzdSBmYWNpbGlkYWQgZGUgdXNvIHkgbGEgcG90ZW5jaWEgZGUgbGFzIGFwbGljYWNpb25lcyBxdWUgc2UgcG9kw61hbiBjb25zdHJ1aXIgY29uIMOpbC4gUlN0dWRpbyBjb250aW51w7MgbWVqb3JhbmRvIFNoaW55LCBhZ3JlZ2FuZG8gY2FyYWN0ZXLDrXN0aWNhcyB5IG9wdGltaXphY2lvbmVzIHBhcmEgbWFuZWphciBhcGxpY2FjaW9uZXMgbcOhcyBncmFuZGVzIHkgY29tcGxlamFzLiBMYSBjb211bmlkYWQgYWxyZWRlZG9yIGRlIFNoaW55IHRhbWJpw6luIGNyZWNpw7MsIGNvbiBudW1lcm9zb3MgcGFxdWV0ZXMgeSBleHRlbnNpb25lcyBkZXNhcnJvbGxhZG9zIHBhcmEgY29tcGxlbWVudGFyIHkgZXhwYW5kaXIgc3VzIGNhcGFjaWRhZGVzLg0KDQoqKkV2b2x1Y2nDs24geSBBY3R1YWxpemFjaW9uZXM6KioNCg0KQSBsbyBsYXJnbyBkZSBsb3MgYcOxb3MsIFNoaW55IGhhIHJlY2liaWRvIG51bWVyb3NhcyBhY3R1YWxpemFjaW9uZXMgcXVlIGhhbiBtZWpvcmFkbyBzdSBmdW5jaW9uYWxpZGFkIHkgcmVuZGltaWVudG8uIEFsZ3VuYXMgZGUgbGFzIGFkaWNpb25lcyBtw6FzIGltcG9ydGFudGVzIGluY2x1eWVuIGxhIGludGVncmFjacOzbiBjb24gYmlibGlvdGVjYXMgZGUgdmlzdWFsaXphY2nDs24gY29tbyBnZ3Bsb3QyLCBlbCBzb3BvcnRlIHBhcmEgYXBsaWNhY2lvbmVzIGVzY2FsYWJsZXMsIHkgbWVqb3JhcyBlbiBsYSBnZXN0acOzbiBkZSBzZXNpb25lcyB5IGVuIGxhIGltcGxlbWVudGFjacOzbiBkZSBhcGxpY2FjaW9uZXMgU2hpbnkgZW4gc2Vydmlkb3Jlcy4NCg0KKipVc28gZW4gbGEgQWN0dWFsaWRhZDoqKg0KDQpIb3kgZW4gZMOtYSwgU2hpbnkgZXMgYW1wbGlhbWVudGUgdXRpbGl6YWRvIGVuIGxhIGFjYWRlbWlhLCBsYSBpbmR1c3RyaWEgeSBlbCBnb2JpZXJubyBwYXJhIGNyZWFyIGRhc2hib2FyZHMsIHZpc3VhbGl6YWNpb25lcyBpbnRlcmFjdGl2YXMsIHkgYXBsaWNhY2lvbmVzIGRlIGFuw6FsaXNpcyBkZSBkYXRvcy4gU3UgY2FwYWNpZGFkIHBhcmEgaW50ZWdyYXIgYW7DoWxpc2lzIGNvbXBsZWpvcyBlbiB0aWVtcG8gcmVhbCB5IHN1IGZsZXhpYmlsaWRhZCBsbyBoYW4gY29udmVydGlkbyBlbiB1bmEgaGVycmFtaWVudGEgZXNlbmNpYWwgcGFyYSBtdWNob3MgYW5hbGlzdGFzIGRlIGRhdG9zLg0KDQojIyMgRnVuY2lvbmVzIHByaW5jaXBhbGVzIGRlIFNoaW55DQoNClNoaW55IHBlcm1pdGUgcmVhbGl6YXIgbGFzIHNpZ3VpZW50ZXMgKiphY3RpdmlkYWRlczoqKg0KDQotICAgQ3JlYXIgZGFzaGJvYXJkcyBxdWUgcmFzdHJlYW4gaW5kaWNhZG9yZXMgY2xhdmUgZGUgcmVuZGltaWVudG8gYSBhbHRvIG5pdmVsLCBtaWVudHJhcyBmYWNpbGl0YW4gZWwgYW7DoWxpc2lzIGRldGFsbGFkbyBkZSBtw6l0cmljYXMgcXVlIG5lY2VzaXRhbiBtw6FzIGludmVzdGlnYWNpw7NuLg0KDQotICAgUmVlbXBsYXphciBjaWVudG9zIGRlIHDDoWdpbmFzIGRlIFBERnMgY29uIGFwbGljYWNpb25lcyBpbnRlcmFjdGl2YXMgcXVlIHBlcm1pdGVuIGFsIHVzdWFyaW8gaXIgZGlyZWN0YW1lbnRlIGEgbGEgc2VjY2nDs24gZXhhY3RhIGRlIGxvcyByZXN1bHRhZG9zIHF1ZSBsZXMgaW50ZXJlc2FuLg0KDQotICAgQ29tdW5pY2FyIG1vZGVsb3MgY29tcGxlam9zIGEgdW5hIGF1ZGllbmNpYSBubyB0w6ljbmljYSBjb24gdmlzdWFsaXphY2lvbmVzIGluZm9ybWF0aXZhcyB5IGFuw6FsaXNpcyBkZSBzZW5zaWJpbGlkYWQgaW50ZXJhY3Rpdm9zLg0KDQotICAgUHJvcG9yY2lvbmFyIGFuw6FsaXNpcyBkZSBkYXRvcyBkZSBhdXRvc2VydmljaW8gcGFyYSBmbHVqb3MgZGUgdHJhYmFqbyBjb211bmVzLCByZWVtcGxhemFuZG8gc29saWNpdHVkZXMgcG9yIGNvcnJlbyBlbGVjdHLDs25pY28gY29uIHVuYSBhcGxpY2FjacOzbiBTaGlueSBxdWUgcGVybWl0ZSBhIGxhcyBwZXJzb25hcyBjYXJnYXIgc3VzIHByb3Bpb3MgZGF0b3MgeSByZWFsaXphciBhbsOhbGlzaXMgZXN0w6FuZGFyLg0KDQotICAgQ3JlYXIgZGVtb3N0cmFjaW9uZXMgaW50ZXJhY3RpdmFzIHBhcmEgZW5zZcOxYXIgY29uY2VwdG9zIGRlIGVzdGFkw61zdGljYSB5IGNpZW5jaWEgZGUgZGF0b3MgcXVlIHBlcm1pdGVuIGEgbG9zIGVzdHVkaWFudGVzIG1vZGlmaWNhciBlbnRyYWRhcyB5IG9ic2VydmFyIGxvcyBlZmVjdG9zIGVuIGVsIGFuw6FsaXNpcy4NCg0KRW4gcmVzdW1lbiwgU2hpbnkgZGEgbGEgY2FwYWNpZGFkIGRlIHRyYW5zbWl0aXIgYWxndW5vcyBkZSAic3VwZXJwb2RlcmVzIGVuIFIiIGEgY3VhbHF1aWVyIHBlcnNvbmEgcXVlIHB1ZWRhIHVzYXIgbGEgd2ViLg0KDQpQb3Igb3RybyBsYWRvLCBTaGlueSBwcm9wb3JjaW9uYSB2YXJpYXMgKipmdW5jaW9uZXMgcHJpbmNpcGFsZXMqKiBxdWUgcGVybWl0ZW4gYSBsb3MgdXN1YXJpb3MgY3JlYXIgYXBsaWNhY2lvbmVzIHdlYiBpbnRlcmFjdGl2YXMgdXRpbGl6YW5kbyBSOg0KDQotICAgKnNoaW55QXBwKCkqDQoNCkVzdGEgZXMgbGEgZnVuY2nDs24gcHJpbmNpcGFsIHF1ZSBzZSB1dGlsaXphIHBhcmEgbGFuemFyIHVuYSBhcGxpY2FjacOzbiBTaGlueS4gVG9tYSBkb3MgYXJndW1lbnRvcywgdWkgKGxhIGludGVyZmF6IGRlIHVzdWFyaW8pIHkgc2VydmVyIChsYSBsw7NnaWNhIGRlbCBzZXJ2aWRvciksIHkgbG9zIGNvbWJpbmEgZW4gdW5hIGFwbGljYWNpw7NuIGNvbXBsZXRhLg0KDQotICAgKmZsdWlkUGFnZSgpKg0KDQpTZSB1dGlsaXphIHBhcmEgZGVmaW5pciBsYSBlc3RydWN0dXJhIGRlIGxhIGludGVyZmF6IGRlIHVzdWFyaW8uIERlbnRybyBkZSBmbHVpZFBhZ2UoKSwgc2UgcHVlZGVuIGluY2x1aXIgdmFyaW9zIGVsZW1lbnRvcyBkZSBkaXNlw7FvLCBjb21vIGZpbGFzIChmbHVpZFJvdygpKSwgY29sdW1uYXMgKGNvbHVtbigpKSwgeSBvdHJvcyBjb21wb25lbnRlcyBkZSBsYSBpbnRlcmZhei4NCg0KLSAgICp0aXRsZVBhbmVsKCkqDQoNClNlIHV0aWxpemEgcGFyYSBkZWZpbmlyIGVsIHTDrXR1bG8gcHJpbmNpcGFsIGRlIGxhIGFwbGljYWNpw7NuLg0KDQotICAgKnNpZGViYXJMYXlvdXQoKSoNCg0KUGVybWl0ZSBkaXZpZGlyIGxhIGludGVyZmF6IGVuIHVuYSBiYXJyYSBsYXRlcmFsIChzaWRlYmFyUGFuZWwoKSkgeSB1biBwYW5lbCBwcmluY2lwYWwgKG1haW5QYW5lbCgpKS4NCg0KLSAgICpzaWRlYmFyUGFuZWwoKSoNCg0KRGVmaW5lIGVsIGNvbnRlbmlkbyBkZSBsYSBiYXJyYSBsYXRlcmFsIGRlIGxhIGludGVyZmF6LiBOb3JtYWxtZW50ZSBpbmNsdXllIGNvbnRyb2xlcyBkZSBlbnRyYWRhIGNvbW8gc2xpZGVySW5wdXQoKSwgc2VsZWN0SW5wdXQoKSwgZXRjLg0KDQotICAgKm1haW5QYW5lbCgpKg0KDQpDb250aWVuZSBlbCBjb250ZW5pZG8gcHJpbmNpcGFsIGRlIGxhIGludGVyZmF6LCBjb21vIGdyw6FmaWNvcywgdGFibGFzIHkgb3Ryb3MgZWxlbWVudG9zIGRlIHNhbGlkYS4NCg0KLSAgICppbnB1dFwkIHkgb3V0cHV0XCQqDQoNCkVuIGVsIGxhZG8gZGVsIHNlcnZpZG9yLCBsb3Mgb2JqZXRvcyBpbnB1dFwkIHkgb3V0cHV0XCQgc2UgdXRpbGl6YW4gcGFyYSBhY2NlZGVyIGEgbG9zIHZhbG9yZXMgZGUgZW50cmFkYSB5IHBhcmEgZGVmaW5pciBzYWxpZGFzIHJlYWN0aXZhcywgcmVzcGVjdGl2YW1lbnRlLg0KDQotICAgKnJlbmRlclBsb3QoKSwgcmVuZGVyVGFibGUoKSwgcmVuZGVyVGV4dCgpKg0KDQpFc3RhcyBmdW5jaW9uZXMgc2UgdXRpbGl6YW4gZW4gbGEgcGFydGUgZGVsIHNlcnZpZG9yIHBhcmEgZ2VuZXJhciBzYWxpZGFzIHJlYWN0aXZhcyBxdWUgcHVlZGVuIHNlciBncsOhZmljb3MsIHRhYmxhcywgdGV4dG8sIGVudHJlIG90cm9zLiBFc3RhcyBzYWxpZGFzIHNlIGVubGF6YW4gY29uIGVsZW1lbnRvcyBlbiBvdXRwdXRcJC4NCg0KLSAgICpvYnNlcnZlKCkgeSBvYnNlcnZlRXZlbnQoKSoNCg0KRXN0YXMgZnVuY2lvbmVzIHNlIHV0aWxpemFuIHBhcmEgZWplY3V0YXIgY8OzZGlnbyBlbiByZXNwdWVzdGEgYSBjYW1iaW9zIGVuIGVudHJhZGFzIHJlYWN0aXZhcywgc2luIGdlbmVyYXIgdW4gdmFsb3IgZGUgc2FsaWRhLiBTb24gw7p0aWxlcyBwYXJhIG1vZGlmaWNhciBsYSBhcGxpY2FjacOzbiBkZSBtYW5lcmEgcmVhY3RpdmEgc2luIHByb2R1Y2lyIHVuYSBzYWxpZGEgZGlyZWN0YS4NCg0KLSAgICpyZWFjdGl2ZSgpKg0KDQpTZSB1dGlsaXphIHBhcmEgY3JlYXIgZXhwcmVzaW9uZXMgcmVhY3RpdmFzIHF1ZSBwdWVkZW4gc2VyIGNvbXBhcnRpZGFzIGVudHJlIHZhcmlhcyBzYWxpZGFzLiBVbmEgZXhwcmVzacOzbiByZWFjdGl2YSByZWNhbGN1bGEgc3UgdmFsb3IgYXV0b23DoXRpY2FtZW50ZSBjdWFuZG8gc3VzIGVudHJhZGFzIGNhbWJpYW4uDQoNCi0gICAqdWlPdXRwdXQoKSB5IHJlbmRlclVJKCkqDQoNClBlcm1pdGVuIGdlbmVyYXIgZGluw6FtaWNhbWVudGUgcGFydGVzIGRlIGxhIGludGVyZmF6IGRlIHVzdWFyaW8gY29uIGJhc2UgZW4gZWwgY8OzZGlnbyBkZWwgc2Vydmlkb3IuDQoNCi0gICAqaXNvbGF0ZSgpKg0KDQpTZSB1dGlsaXphIHBhcmEgZXZpdGFyIHF1ZSB1bmEgZXhwcmVzacOzbiByZWFjdGl2YSBzZSB2dWVsdmEgYSBlamVjdXRhciBhdXRvbcOhdGljYW1lbnRlIGN1YW5kbyBjYW1iaWFuIHN1cyBlbnRyYWRhcy4gRXMgw7p0aWwgcGFyYSBvcHRpbWl6YXIgbGEgZWplY3VjacOzbiBkZSBjw7NkaWdvLg0KDQojIyMgQ29tcG9uZW50ZXMgZGUgdW5hIGFwbGljYWNpw7NuIFNoaW55DQoNCkRlc2NyaWJpcmVtb3MgZW4gZXN0YSBzZWNjacOzbiBsb3MgY29tcG9uZW50ZXMgZGUgU2hpbnkuIExhIGluZm9ybWFjacOzbiByZWNhYmFkYSBzb2JyZSBsb3MgY29tcG9uZW50ZXMgc2Ugb2J0dXZvIGRlIGxhIHB1YmxpY2FjacOzbiBkZSBDdWV2YXMgKDIwMjEpLg0KDQpQcmltZXJvLCBwYXJhICoqaW5zdGFsYXIgU2hpbnkqKiwgcG9kZW1vcyB1dGlsaXphciBsb3Mgc2lndWllbnRlcyBjw7NkaWdvczoNCg0KYGBge3J9DQppbnN0YWxsLnBhY2thZ2VzKCJzaGlueSIpIA0KaWYgKCFyZXF1aXJlKCJkZXZ0b29scyIpKSANCiAgaW5zdGFsbC5wYWNrYWdlcygiZGV2dG9vbHMiKSANCmRldnRvb2xzOjppbnN0YWxsX2dpdGh1Yigic2hpbnkiLCAicnN0dWRpbyIpIA0KYGBgDQoNClRvbWVtb3MgZW4gY3VlbnRhIHF1ZSB0b2RhIGFwbGljYWNpw7NuIHdlYiBkZSBTaGlueSB0ZW5kcsOhIGxhIG1pc21hIGVzdHJ1Y3R1cmEsIGRvcyBibG9xdWVzIGRlIGPDs2RpZ29zIGRlIFI6DQoNCi0gICBVSTogZ2VuZXJhIHVuYSBpbnRlcmZheiBkZSB1c3VhcmlvDQoNCi0gICBTZXJ2ZXI6IGNvbnRpZW5lIGxhcyBpbnN0cnVjY2lvbmVzIHF1ZSBsYSBjb21wdXRhZG9yYSBuZWNlc2l0YSBwYXJhIGNyZWFyIGxhIGFwcC4NCg0KIVtdKGltYWdlcy8zLWJsYW5rLnBuZykNCg0KTGEgZXN0cnVjdHVyYSBkZSBjw7NkaWdvIGRlIHVuYSBhcHAgU2hpbnkgc2UgdmVyw61hIGRlbCBzaWd1aWVudGUgbW9kbzoNCg0KYGBge3J9DQpsaWJyYXJ5KHNoaW55KSANCnVpIDwtIGZsdWlkUGFnZSggDQp4eHh4SW5wdXQoKSwgDQp4eHh4T3V0cHV0KCkgDQopIA0Kc2VydmVyIDwtIGZ1bmN0aW9uKGlucHV0LCBvdXRwdXQpIA0KeyANCiBDb2RpZ28gZGUgUiANCn0gDQpzaGlueUFwcCh1aSA9IHVpLCBzZXJ2ZXIgPSBzZXJ2ZXIpIA0KYGBgDQoNCioqMS4gTGEgSW50ZXJmYXogZGUgVXN1YXJpbyAoVUkpKioNCg0KTGEgaW50ZXJmYXogZGUgdXN1YXJpbyBkZWZpbmUgbGEgZXN0cnVjdHVyYSB5IGVsIGRpc2XDsW8gZGUgbGEgYXBsaWNhY2nDs24gU2hpbnkuDQoNClNoaW55IHBvciBkZWZhdWx0IHVzYSBib290c3RyYXAgKGxvIGN1YWwgbm8gdGllbmUgbmFkYSBxdWUgdmVyIGNvbiBlbCBtw6l0b2RvIGVzdGFkw61zdGljbyBib290c3RyYXApLiBFc3RvIGVzIHVuIG1hcmNvIGRlIHRyYWJham8gZGUgSFRNTCwgQ1NTIHkgSmF2YXNjcmlwdCBtw6FzIHBvcHVsYXIgcGFyYSBkZXNhcnJvbGxhciBzaXRpb3Mgd2ViIHJlY2VwdGl2b3MuDQoNClBhcmEgdXNhciB0b2RvcyBsb3MgdGFncyBlbiBTaGlueSwgcG9kZW1vcyBjb25zdWx0YXIgZXN0b3MgdGFncyBjb24gbGEgc2lndWllbnRlIGZ1bmNpw7NuOg0KDQpgYGB7cn0NCnNoaW55Ojp0YWdzIA0KbmFtZXMoc2hpbnk6OnRhZ3MpIA0KYGBgDQoNClNoaW55IGZvbWVudGEgbGEgc2VwYXJhY2nDs24gZGVsIGPDs2RpZ28gcXVlIGdlbmVyYSBzdSBpbnRlcmZheiBkZSB1c3VhcmlvIChlbCBmcm9udC1lbmQpIGRlbCBjw7NkaWdvIHF1ZSBpbXB1bHNhIGVsIGNvbXBvcnRhbWllbnRvIGRlIHN1IGFwbGljYWNpw7NuIChlbCBiYWNrLWVuZCk6DQoNCiFbXShpbWFnZXMvdW5uYW1lZC5wbmcpDQoNCkV4aXN0ZSB1bmEgY29tdW5pZGFkIHJpY2EgeSB2aWJyYW50ZSBkZSBwYXF1ZXRlcyBkZSBleHRlbnNpw7NuLCBjb21vIHNoaW55V2lkZ2V0cywgY29sb3JwaWNrZXIgeSBzb3J0dGFibGUuDQoNCioqMi4gRWwgc2Vydmlkb3IgKHNlcnZlcikqKg0KDQpFbCBzZXJ2aWRvciBkZWZpbmUgbGEgbMOzZ2ljYSBkZSBsYSBhcGxpY2FjacOzbiwgaW5jbHV5ZW5kbyBjw7NtbyBzZSBwcm9jZXNhbiBsYXMgZW50cmFkYXMgeSBjw7NtbyBzZSBnZW5lcmFuIGxhcyBzYWxpZGFzLg0KDQpIYXkgMyByZWdsYXMgcGFyYSBlc2NyaWJpciBjw7NkaWdvIGVuIGVsIFNlcnZlcjoNCg0KLSAgIEVzcGVjaWZpY2EgY29uIGBvdXRwdXQkYCArIGBJRCBvdXRwdXRgIGNhZGEgb2JqZXRvIGRlbnRybyBkZSBgc2VydmVyYC4NCg0KLSAgIENhZGEgb2JqZXRvIHNlIG1vc3RyYXLDoSBjb24gdW4gYHJlbmRlcigpYCwgZWplbXBsbyBgcmVuZGVyUGxvdCh7fSlgDQoNCi0gICBBY2Nlc2EgYSBsb3MgdmFsb3JlcyBkZSBsb3MgaW5wdXRzIGNvbiBgaW5wdXQkYCArIGBJRCBpbnB1dGANCg0KIVtdKGltYWdlcy9zaGlueV84LnBuZykNCg0KKiozLiBSZWFjdGl2aWRhZCoqDQoNClNoaW55IGVzdMOhIGJhc2FkbyBlbiB1biBtb2RlbG8gcmVhY3Rpdm8gcXVlIGFjdHVhbGl6YSBhdXRvbcOhdGljYW1lbnRlIGxhcyBzYWxpZGFzIGN1YW5kbyBjYW1iaWFuIGxhcyBlbnRyYWRhcy4gTG9zIGNvbXBvbmVudGVzIGNsYXZlIHBhcmEgbWFuZWphciBsYSByZWFjdGl2aWRhZCBpbmNsdXllbjoNCg0KLSAgICoqRXhwcmVzaW9uZXMgcmVhY3RpdmFzKio6IFNlIGNyZWFuIHVzYW5kbyBgcmVhY3RpdmUoKWAgeSBzZSBwdWVkZW4gY29tcGFydGlyIGVudHJlIG3Dumx0aXBsZXMgc2FsaWRhcy4NCg0KLSAgICoqT2JzZXJ2YWRvcmVzKio6IFVzYW4gYG9ic2VydmUoKWAgcGFyYSBtb25pdG9yZWFyIGNhbWJpb3MgZW4gbGFzIGVudHJhZGFzIHkgZWplY3V0YXIgY8OzZGlnbyBlbiBjb25zZWN1ZW5jaWEuDQoNCi0gICAqKkFpc2xhbWllbnRvIGRlIHJlYWN0aXZvcyoqOiBMYSBmdW5jacOzbiBgaXNvbGF0ZSgpYCBldml0YSBxdWUgdW5hIGV4cHJlc2nDs24gcmVhY3RpdmEgc2UgcmVjYWxjdWxhIGN1YW5kbyBjYW1iaWFuIHN1cyBkZXBlbmRlbmNpYXMuDQoNCioqNC4gQ29tcG9uZW50ZXMgZGUgRXh0ZW5zacOzbioqDQoNCi0gICAqKmBzaGlueU1vZHVsZXNgKio6IFBlcm1pdGVuIGxhIG1vZHVsYXJpemFjacOzbiBkZWwgY8OzZGlnbyBTaGlueSwgZGl2aWRpZW5kbyBsYSBhcGxpY2FjacOzbiBlbiBjb21wb25lbnRlcyByZXV0aWxpemFibGVzLg0KDQotICAgKipgc2hpbnlXaWRnZXRzYCoqOiBVbiBwYXF1ZXRlIGFkaWNpb25hbCBxdWUgcHJvcG9yY2lvbmEgd2lkZ2V0cyBhZGljaW9uYWxlcyBwYXJhIG1lam9yYXIgbGEgaW50ZXJhY3RpdmlkYWQgeSBsYSBlc3TDqXRpY2EgZGUgbGFzIGFwbGljYWNpb25lcy4NCg0KLSAgICoqYHNoaW55anNgKio6IFBlcm1pdGUgaW50ZWdyYXIgZnVuY2lvbmFsaWRhZGVzIGRlIEphdmFTY3JpcHQgZW4gdW5hIGFwbGljYWNpw7NuIFNoaW55LCBvZnJlY2llbmRvIHVuIGNvbnRyb2wgbcOhcyBkZXRhbGxhZG8gZGUgbGEgaW50ZXJhY2Npw7NuIGRlbCB1c3VhcmlvLg0KDQpMb3MgYW50ZXJpb3JlcyBzb24gbG9zIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzIGRlIFNoaW55IHF1ZSBwZXJtaXRlbiBjb25zdHJ1aXIgYXBsaWNhY2lvbmVzIHdlYiBpbnRlcmFjdGl2YXMuIENhZGEgdW5vIGp1ZWdhIHVuIHBhcGVsIGNydWNpYWwgZW4gbGEgZXN0cnVjdHVyYSB5IGZ1bmNpb25hbGlkYWQgZGUgdW5hIGFwbGljYWNpw7NuIFNoaW55LCBoYWNpZW5kbyBwb3NpYmxlIGxhIGNyZWFjacOzbiBkZSBpbnRlcmZhY2VzIGRpbsOhbWljYXMgeSByZWFjdGl2YXMgY29uIHVuIGVzZnVlcnpvIHJlbGF0aXZhbWVudGUgYmFqby4NCg0KIyMjIEVqZW1wbG9zIGRlIHVzbw0KDQpTaGlueSBlcyB1bmEgYmlibGlvdGVjYSBlbiBSIHF1ZSBmYWNpbGl0YSBsYSBjcmVhY2nDs24gZGUgYXBsaWNhY2lvbmVzIHdlYiBpbnRlcmFjdGl2YXMuIEVudHJlIGxvIHF1ZSBwZXJtaXRlIGhhY2VyIHRlbmVtb3M6DQoNCjEuICAqKkNyZWFyIEludGVyZmFjZXMgSW50ZXJhY3RpdmFzKio6IGNvbnN0cnVpciBhcGxpY2FjaW9uZXMgd2ViIGNvbiBpbnRlcmZhY2VzIGdyw6FmaWNhcyBpbnRlcmFjdGl2YXMgcGFyYSB2aXN1YWxpemFyIGRhdG9zLCByZWFsaXphciBhbsOhbGlzaXMgeSBjcmVhciBkYXNoYm9hcmRzLg0KDQoyLiAgKipWaXN1YWxpemFyIERhdG9zKio6IGNyZWFyIGdyw6FmaWNvcyBkaW7DoW1pY29zIHkgdGFibGFzIHF1ZSBzZSBhY3R1YWxpemFuIGVuIHRpZW1wbyByZWFsIGVuIGZ1bmNpw7NuIGRlIGxhcyBlbnRyYWRhcyBkZWwgdXN1YXJpby4NCg0KMy4gICoqRGVzYXJyb2xsYXIgQXBsaWNhY2lvbmVzIGRlIERhdG9zKio6IGNvbnN0cnVpciBhcGxpY2FjaW9uZXMgcGFyYSByZWFsaXphciBhbsOhbGlzaXMgZXN0YWTDrXN0aWNvcywgbW9kZWxhZG8gcHJlZGljdGl2byBvIGN1YWxxdWllciB0aXBvIGRlIHByb2Nlc2FtaWVudG8gZGUgZGF0b3MgZW4gbMOtbmVhLg0KDQo0LiAgKipDb25zdHJ1aXIgRGFzaGJvYXJkcyoqOiBjb25zdHJ1aXIgcGFuZWxlcyBkZSBjb250cm9sIGNvbXBsZXRvcyBwYXJhIHN1cGVydmlzYXIgbcOpdHJpY2FzIHkgZGF0b3MgZW4gdGllbXBvIHJlYWwuDQoNCjUuICAqKkNyZWFyIEZvcm11bGFyaW9zIHkgQXBsaWNhY2lvbmVzIGRlIEVudHJhZGEgZGUgRGF0b3MqKjogZGlzZcOxYXIgZm9ybXVsYXJpb3MgcGFyYSBsYSBlbnRyYWRhIGRlIGRhdG9zIHkgcHJvY2VzYXIgbG9zIHJlc3VsdGFkb3MgZGlyZWN0YW1lbnRlIGVuIGxhIGFwbGljYWNpw7NuLg0KDQo2LiAgKipJbnRlZ3JhciBjb24gT3RyYXMgSGVycmFtaWVudGFzKio6IFNoaW55IHB1ZWRlIGludGVncmFyc2UgY29uIG90cmFzIGhlcnJhbWllbnRhcyB5IHBhcXVldGVzIGRlIFIsIGNvbW8gZ2dwbG90MiBwYXJhIGdyw6FmaWNvcyB5IGRwbHlyIHBhcmEgbWFuaXB1bGFjacOzbiBkZSBkYXRvcy4NCg0KNy4gICoqSW1wbGVtZW50YXIgTW9kZWxvcyBkZSBNYWNoaW5lIExlYXJuaW5nKio6IGNvbnN0cnVpciBhcGxpY2FjaW9uZXMgcXVlIG11ZXN0cmVuIHByZWRpY2Npb25lcyB5IHJlc3VsdGFkb3MgZGUgbW9kZWxvcyBkZSBhcHJlbmRpemFqZSBhdXRvbcOhdGljbyBlbiB1bmEgaW50ZXJmYXogZGUgdXN1YXJpbyBpbnRlcmFjdGl2YS4NCg0KOC4gICoqRGVzcGxlZ2FyIEFwbGljYWNpb25lcyoqOiBQdWVkZXMgZGVzcGxlZ2FyIHR1cyBhcGxpY2FjaW9uZXMgU2hpbnkgZW4gc2Vydmlkb3JlcyBsb2NhbGVzIG8gZW4gbGEgbnViZSwgY29tbyBTaGlueUFwcHMuaW8gbyBlbiBzZXJ2aWRvcmVzIHByb3Bpb3MgdXNhbmRvIFNoaW55IFNlcnZlci4NCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCkEgY29udGludWFjacOzbiwgc2UgZXN0dWRpYW4gZG9zIGVqZW1wbG9zIGRlIHVzbyBjb25jcmV0b3MgZGUgU2hpbnkgcGFyYSBsYSBjcmVhY2nDs24gZGUgYXBsaWNhY2lvbmVzOg0KDQoqKkPDoWxjdWxvIGRlIGxhIGRpc3RhbmNpYSBwdW50byBhIGzDrW5lYSoqDQoNCkVuIGVsIDIwMTgsIHVuIGF1dG9yIGRlIGJsb2cgdXRpbGl6w7MgbGEgbGlicmVyw61hIHBhcmEgcG9kZXIgdmlzdWFsaXphciBsYSBkaXN0YW5jaWEgZGUgdW4gcHVudG8gZXNwZWNpZmljbyBkZSBNZXhpY28gYSBsYSBsw61uZWEgZnJvbnRlcml6YSBjb24gRXN0YWRvcyBVbmlkb3MuDQoNCjEuICBQYXJhIHBvZGVyIGZpbHRyYXIgbGEgaW5mb3JtYWNpw7NuIG5lY2VzYXJpYSBlbiBjdWFudG8gYSBsYSBsb2NhbGl6YWNpw7NuIGRlIGVzdGFkb3MgeSBkZW3DoXMsIHNlIGRlc2NhcmfDsyBsYSBpbmZvcm1hY2nDs24gc29icmUgbGEgbMOtbmVhIGRlIGxhIGZyb250ZXJhIHBhcmEgcG9kZXIgdXRpbGl6YXJsYSBlbiBSLiBVbmEgdmV6IGNhcmdhZGEgbGEgaW5mb3JtYWNpw7NuLCBmdWUgcG9zaWJsZSByZWFsaXphciBzdSBsZWN0dXJhIHV0aWxpemFuZG8gbGEgZnVuY2nDs24gYHNmOjpzdF9yZWFkKClgLg0KDQpgYGB7cn0NCiBmIDwtIHN0X3JlYWQoIk1leGljb19hbmRfVVNfQm9yZGVyLnNocCIpDQpgYGANCg0KMi4gIFNlZ3VpZGFtZW50ZSwgc2UgZGlidWphcm9uIGxvcyBkYXRvcyBjb24gZWwgZmluIGRlIGNvbmZpcm1hciBxdWUgc2UgdGVuw61hbiBsb3MgZGF0b3MgbmVjZXNhcmlvcy4NCg0KYGBge3J9DQogIHBsb3QoZiwgbWF4LnBsb3QgPSAxKQ0KYGBgDQoNCjMuICBTZSBkZWZpbmnDsyBlbCBwdW50byBxdWUgc2UgdG9tYXLDrWEgZGUgcmVmZXJlbmNpYSBwYXJhIHNhY2FyIGxhIGRpc3RhbmNpYSBjb24gcmVzcGVjdG8gYSBsYSBmcm9udGVyYS4gU2UgZWxpZ2nDsyB0b21hciBjb21vIHJlZmVyZW5jaWEgZWwgQ29sZWdpbyBkZSBNw6l4aWNvLiBQYXJhIGxhIHV0aWxpemFjacOzbiBkZSBsYXMgY29vcmRlbmFkYXMgZGUgZGljaG8gbHVnYXIsIHNlIHVzw7MgR29vZ2xlIE1hcHMuIENvbiBlc3RhIHJlZmVyZW5jaWEgc2UgY3Jlw7MgbGEgdGFibGEgbGF0aXR1ZC9sb25naXR1ZC4NCg0KYGBge3J9DQpwdG8gPC0gZGF0YS5mcmFtZSh4ID0gLTk5LjIwNzc1LCB5ID0gMTkuMzAzNzQxKSAlPiUgDQogIHN0X2FzX3NmKGNvb3JkcyA9IGMoIngiLCAieSIpKSANCg0KIyBIb21vbG9nYW5kbyBlbCBTaXN0ZW1hIGRlIENvb3JkZW5hZGFzIGRlIFJlZmVyZW5jaWEgY29uIGxhIGJhc2UgZGUgbGEgbMOtbmVhIGRlIGxhIEZyb250ZXJhIE5vcnRlDQpzdF9jcnMocHRvKSA8LSBzdF9jcnMoZikNCmBgYA0KDQo0LiAgU2UgY2FsY3Vsw7MgbGEgZGlzdGFuY2lhIHV0aWxpemFuZG8gbGEgZnVuY2nDs24gYHN0X2Rpc3RhbmNlKClgIHBhcmEgY2FsY3VsYXIgbGEgZGlzdGFuY2lhIGdlb2TDqXNpY2EgcXVlIGhheSBlbnRyZSBkb3MgZWxlbWVudG9zIGdlb2dyw6FmaWNvcyBkZWwgbWFwYS4NCjUuICBDb24gbGEgaW5mb3JtYWNpw7NuIGFudGVyaW9yIHNlIGRldGVybWluw7MgZWwgcHVudG8gbcOhcyBjZXJjYW5vIGRlIGxhIGZyb250ZXJhIGFsIENvbGVnaW8gZGUgTcOpeGljbywgcGVybyBzdXJnacOzIGxhIHByZWd1bnRhIGRlIGVuIGTDs25kZSBlc3TDoSwgcG9yIGxvIHF1ZSBzZSBkZXNjb21wdXNvIGxhIGzDrW5lYSBkZSBsYSBmcm9udGVyYSBub3J0ZSBlbiB2w6lydGljZXMgeSBjb21wb25lbnRlcyBjb24gZWwgZmluIGRlIGRldGVybWluYXIgbGEgbMOtbmVhIGNvbiBsYSBtZW5vciBsb25naXR1ZA0KNi4gIERlc3B1w6lzIGRlIHVuYSBzZXJpZSBkZSBwYXNvcywgc2UgbG9ncsOzIHZpc3VhbGl6YXIgZWwgcHVudG8gY29uIGVsIHVzbyBkZWwgY8OzZGlnbzoNCg0KYGBge3J9DQpsaW5lYSA8LSBzdF9saW5lc3RyaW5nKG1hdHJpeChjKHB0b1ssImdlb21ldHJ5Il0gJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RfY29vcmRpbmF0ZXMoKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwdW50b19mcm9udGVyYVssImdlb21ldHJ5Il0gJT4lIHN0X2Nvb3JkaW5hdGVzKCkpLCBuY29sID0gMiwgYnlyb3cgPSBUUlVFKSkNCmBgYA0KDQo3LiAgU2UgcGxhc23DsyBlbiB1biBtYXBhIGRlIGBsZWFmbGV0YA0KDQpgYGB7cn0NCiBsZWFmbGV0KCkgJT4lIA0KICAgICAgYWRkVGlsZXMoKSAlPiUgDQogICAgICBhZGRDaXJjbGVNYXJrZXJzKGRhdGEgPSBwdG8pICU+JSANCiAgICAgIGFkZENpcmNsZU1hcmtlcnMoZGF0YSA9IHB1bnRvX2Zyb250ZXJhKSAlPiUgDQogICAgICBhZGRQb2x5bGluZXMoZGF0YSA9IGxpbmVhKSAlPiUgDQogICAgICBhZGRQb2x5bGluZXMoZGF0YSA9IGYsIGNvbG9yID0gInJlZCIpDQpgYGANCg0KOC4gIEZpbmFsbWVudGUsIHNlIG9idHV2aWVyb24gbG9zIHNpZ3VpZW50ZXMgcmVzdWx0YWRvcywgcXVlIGxlIHBlcm1pdGnDsyBkZXRlcm1pbmFyIHF1ZSBlbCBwdW50byBtw6FzIGNlcmNhbm8gYSBsYSBmcm9udGVyYSBub3J0ZSBzZSBlbmN1ZW50cmEgdW5vcyBraWzDs21ldHJvcyBhbCBFc3RlIGRlIGxhIENpdWRhZCBkZSBNYXRhbW9yb3MsIGVuIGVsIEVzdGFkbyBkZSBUYW1hdWxpcGFzLg0KDQogICAgIVtdKENhcHR1cmEgZGUgcGFudGFsbGEgMjAyNC0wOC0yNSAxOTMxMDMucG5nKQ0KDQpDb24gbGEgaW5mb3JtYWNpw7NuIGFudGVyaW9yLCBlbCBhdXRvciBjcmXDsyB1biBTaGlueSBhcHAsIGNvbiBlbCBmaW4gZGUgcXVlIGN1YWxxdWllciB1c3VhcmlvIHB1ZWRhIGNhbGN1bGFyIGxhIGRpc3RhbmNpYSBkZSBjdWFscXVpZXIgcHVudG8gYSBsYSBmcm9udGVyYSBzdXIgZGUgRXN0YWRvcyBVbmlkb3MuIEVuIGVzdGUgY2FzbywgZWwgKipzdXBlcnBvZGVyKiogcXVlIHNlIHBhc8OzIGZ1ZSBlbCBkZSBwb2RlciBjYWxjdWxhciBsYSBkaXN0YW5jaWEgeSBwb2RlciBjb25zdHJ1aXIgbGEgbMOtbmVhIGRlIG3DrW5pbWEgZGlzdGFuY2lhIHRhbiBzb2xvIGNvbiBwcmVzaW9uYXIgdW4gcHVudG8gZW4gZWwgbWFwYS4NCg0KIVtdKENhcHR1cmEgZGUgcGFudGFsbGEgMjAyNC0wOC0yNSAxOTMzNTkucG5nKQ0KDQpbKipFY29iaWNpKipdKGh0dHBzOi8vbG5wcG1pY3Jvc2l0aW8uc2hpbnlhcHBzLmlvL2Vjb2JpY2lEYXRhdG9uLykqKihEYXRhdMOzbikqKg0KDQpFc3RhIGFwbGljYWNpw7NuIGZ1w6kgdW5hIGVudHJhZGEgcGFyYSBlbCBEYXRhdMOzbiBkZSBWaXN1YWxpemFjacOzbiBkZSBkYXRvcyBkZSBlY29iaWNpIGRlbCBDSU1BVC4gU3UgcmVhbGl6YWNpw7NuIGZ1w6kgdW4gdHJhYmFqbyBjb25qdW50byBlbnRyZSBhbmFsaXN0YXMgcXVlIHVzYXJvbiBQeXRob24geSBSIHBhcmEgZWwgYW7DoWxpc2lzIGRlIGRhdG9zLCBjb211bmljYW5kbyBsb3MgcmVzdWx0YWRvcyBhIGxhIGFwbGljYWNpw7NuIGEgdHJhdsOpcyBkZSB1bmEgQVBJLg0KDQpFY29iaWNpIGVzIHVuIHNpc3RlbWEgZGUgYmljaWNsZXRhcyBjb21wYXJ0aWRhcyBsYW56YWRvIGVuIGZlYnJlcm8gZGUgMjAxMCBwb3IgZWwgZ29iaWVybm8gZGUgbGEgQ2l1ZGFkIGRlIE3DqXhpY28gcGFyYSBsYSByZWFsaXphY2nDs24gZGUgdmlhamVzIGRlIGNvcnRhIGRpc3RhbmNpYSB5IGR1cmFjacOzbiBhIHByZWNpb3MgcmVkdWNpZG9zIG8gZGUgZm9ybWEgZ3JhdHVpdGEuIEVsIHNpc3RlbWEgY3VlbnRhIGNvbiA0ODAgY2ljbG9lc3RhY2lvbmVzIHkgbcOhcyBkZSA2IG1pbCA4MDAgYmljaWNsZXRhcywgZGUgbGFzIGN1YWxlcyAyOCBlc3RhY2lvbmVzIHkgMzQwIGJpY2ljbGV0YXMgZm9ybWFuIHBhcnRlIGRlbCBudWV2byBzaXN0ZW1hIGRlIGJpY2ljbGV0YXMgZWzDqWN0cmljYXMgZGUgcGVkYWxlbyBhc2lzdGlkby4NCg0KIVtdKENhcHR1cmEgZGUgcGFudGFsbGEgMjAyNC0wOC0yNSAxOTQzMzIucG5nKQ0KDQojIyBDb25jbHVzaW9uZXMNCg0KU2hpbnkgaGEgdHJhbnNmb3JtYWRvIGVsIHBhbm9yYW1hIGRlbCBhbsOhbGlzaXMgZGUgZGF0b3MgeSBsYSB2aXN1YWxpemFjacOzbiBhbCBwZXJtaXRpciBhIGxvcyB1c3VhcmlvcyBkZSBSIGNyZWFyIGFwbGljYWNpb25lcyB3ZWIgaW50ZXJhY3RpdmFzIHNpbiBuZWNlc2lkYWQgZGUgY29ub2NpbWllbnRvcyBhdmFuemFkb3MgZW4gZGVzYXJyb2xsbyB3ZWIuIFN1IGZsZXhpYmlsaWRhZCwgY29tYmluYWRhIGNvbiBlbCBwb2RlciBkZSBSLCBsbyBjb252aWVydGUgZW4gdW5hIGhlcnJhbWllbnRhIGludmFsdWFibGUgcGFyYSBjaWVudMOtZmljb3MgZGUgZGF0b3MsIGFuYWxpc3RhcyB5IGRlc2Fycm9sbGFkb3JlcyBlbiB1bmEgdmFyaWVkYWQgZGUgY2FtcG9zLg0KDQpBIG1lZGlkYSBxdWUgbGEgdGVjbm9sb2fDrWEgYXZhbnphLCBlcyBwcm9iYWJsZSBxdWUgU2hpbnkgY29udGluw7plIGV2b2x1Y2lvbmFuZG8sIGluY29ycG9yYW5kbyBudWV2YXMgZnVuY2lvbmVzIHkgY2FwYWNpZGFkZXMgcXVlIGZhY2lsaXRlbiBhw7puIG3DoXMgbGEgY3JlYWNpw7NuIGRlIGFwbGljYWNpb25lcyB3ZWIgc29maXN0aWNhZGFzIHkgYXRyYWN0aXZhcy4NCg0KIyMgQmlibGlvZ3JhZsOtYQ0KDQotICAgQmVlbGV5LCBDLiwgJiBDaGVuZywgSi4gKDIwMTgpLiBXZWIgQXBwbGljYXRpb24gRGV2ZWxvcG1lbnQgd2l0aCBSIFVzaW5nIFNoaW55OiBCdWlsZCBTdHVubmluZyBHcmFwaGljcyBhbmQgSW50ZXJhY3RpdmUgRGF0YSBWaXN1YWxpemF0aW9ucy4gUGFja3QgUHVibGlzaGluZy4NCg0KLSAgIENoYW5nLCBXLiwgQ2hlbmcsIEouLCBBbGxhaXJlLCBKLiwgWGllLCBZLiwgJiBNY1BoZXJzb24sIEouICgyMDE4KS4gU2hpbnk6IFdlYiBBcHBsaWNhdGlvbiBGcmFtZXdvcmsgZm9yIFIuIFIgcGFja2FnZSB2ZXJzaW9uIDEuMi4wLg0KDQotICAgQ3VldmFzLUZlcm5hbmRleiwgRS4gKDIwMjEpLiBJbnRyb2R1Y2Npw7NuIGEgU2hpbnkuIFdvcmtzaG9wIENEU0IgMjAyMTogRmx1am9zIGRlIHRyYWJham8gY29uIFJTdHVkaW8geSBjcmVhY2nDs24gZGUgU2hpbnkgYXBwcy4gaHR0cHM6Ly9jb211bmlkYWRiaW9pbmZvLmdpdGh1Yi5pby9jZHNiMjAyMV93b3JrZmxvd3MvaW50cm9kdWNjaSVDMyVCM24tYS1zaGlueS5odG1sI3F1JUMzJUE5LWVzLXktcGFyYS1xdSVDMyVBOS1tZS1zaXJ2ZS1zaGlueQ0KDQotICAgRmVybsOhbmRleiwgTS5JLiAoMjAyMCkgVmVudGFqYXMgZGUgUiBjb21vIGhlcnJhbWllbnRhIHBhcmEgZWwgQW7DoWxpc2lzIHkgVmlzdWFsaXphY2nDs24gZGUgZGF0b3MgZW4gQ2llbmNpYXMgU29jaWFsZXMuIFJldi4gY2llbnRlLiBVQ1NBIHZvbC43IG5vLjIgQXN1bmNpw7NuIEF1Zy4gMjAyMC4gUmVjdXBlcmFkbyBkZSBodHRwOi8vc2NpZWxvLmlpY3MudW5hLnB5L3NjaWVsby5waHA/c2NyaXB0PXNjaV9hcnR0ZXh0JnBpZD1TMjQwOS04NzUyMjAyMDAwMDIwMDA5Nw0KDQotICAgR3JvbGVtdW5kLCBHLiwgJiBXaWNraGFtLCBILiAoMjAxNikuIFIgZm9yIERhdGEgU2NpZW5jZTogSW1wb3J0LCBUaWR5LCBUcmFuc2Zvcm0sIFZpc3VhbGl6ZSwgYW5kIE1vZGVsIERhdGEuIE8nUmVpbGx5IE1lZGlhLg0KDQotICAgSnV2ZSBCbG9nLiAoMjAyMCkuIERpc3RhbmNpYSBwdW50byBhIGxpbmVhIGh0dHBzOi8vanV2ZW5hbGNhbXBvcy5jb20vMjAyMC8wMi8xOC9kaXN0YW5jaWEtcHVudG8tYS1saW5lYS8NCg0KLSAgIEp1dmUgQmxvZy4oMjAyMCkuRWplbXBsb3MgZGUgbG8gcXVlIHNlIHB1ZWRlIGhhY2VyIGVuIHNoaW55IC0gaHR0cHM6Ly9qdXZlbmFsY2FtcG9zLmNvbS8yMDIwLzAzLzAzL2VqZW1wbG9zLWRlLWxvLXF1ZS1zZS1wdWVkZS1oYWNlci1lbi1zaGlueS8NCg0KLSAgIFJTdHVkaW8uICgyMDIwKS4gU2hpbnk6IEVhc3kgd2ViIGFwcGxpY2F0aW9ucyBpbiBSLiBSU3R1ZGlvLCBJbmMuDQoNCi0gICBSeWFuLCBZLiAoMjAyMywgRGVjZW1iZXIgMTMpLiBDcmVhY2nDs24gZGUgYXBsaWNhY2lvbmVzIHdlYiBpbnRlcmFjdGl2YXMgY29uIFIgeSBTaGlueS4gUHJvZ3JhbW1pbmcgSGlzdG9yaWFuLiBodHRwczovL3Byb2dyYW1taW5naGlzdG9yaWFuLm9yZy9lcy9sZWNjaW9uZXMvY3JlYWNpb24tZGUtYXBsaWNhY2lvbi1zaGlueQ0KDQotICAgU2hpbnkgaHR0cHM6Ly9zaGlueS5wb3NpdC5jbw0KDQotICAgU2lldmVydCwgQy4gKDIwMjApLiBJbnRlcmFjdGl2ZSBXZWItQmFzZWQgRGF0YSBWaXN1YWxpemF0aW9uIHdpdGggUiwgcGxvdGx5LCBhbmQgc2hpbnkuIENoYXBtYW4gYW5kIEhhbGwvQ1JDLg0KDQotICAgV2lja2hhbSwgSC4gKDIwMjEpLiBNYXN0ZXJpbmcgU2hpbnk6IEJ1aWxkIGludGVyYWN0aXZlIGFwcHMsIHJlcG9ydHMsIGFuZCBkYXNoYm9hcmRzIHBvd2VyZWQgYnkgUi4gTydSZWlsbHkgTWVkaWEuIFJlY3VwZXJhZG8gZGUgaHR0cHM6Ly9tYXN0ZXJpbmctc2hpbnkub3JnL2luZGV4Lmh0bWwNCg==