1. Introducción

Este informe tiene como objetivo principal realizar un análisis exploratorio de los datos sobre un conjunto de datos sobre personas con enfermedades del corazón, con sus características de forma anónima para poder generar visualizaciones informativas sobre la relación que tienen las variables entre sí, para poder comprender los datos de una mejor manera, buscando patrones, identificando anomalías, etc.


2. Descripción del problema

Los problemas de corazón son cada vez más comunes en las sociedades modernas, esto debido a muchos factores que afectan la salud física de las personas, como la falta de actividad física, el consumo de comidas que perjudican el estado del corazón y el resto del cuerpo, el consumo de drogas, padecimientos previos como presión alta, diabetes, tiempos de sueño irregulares, altos niveles de estrés. Estas y otras razones son fuentes de problemas en el corazón en personas de todo el mundo.

Es por esto por lo que muchos especialistas en el tema recolectan datos de las personas que pueden ayudar a confirmar si se tiene o no algún padecimiento del corazón, o al menos se pueda utilizar como guía para poder identificarlos temprano, como el conjunto de datos que se utilizara en el presente análisis exploratorio de los datos.


3. Definición de fuentes de datos

El conjunto de datos que es usado para este análisis fue realizado por Oktay Ördekci llamado Heart Diseaseel cual contiene 21 indicadores de riesgo relacionados a los problemas de salud. Como la edad, genero, presión en sangre, etc. Estos datos fueron recolectados para analizar las posibilidades de riesgo en padecimientos del control y ayudar a la investigación en temas de salud. La siguiente tabla muestra todos los indicadores que contiene el conjunto de datos, una breve descripcion de cada uno y los valores que puede tomar.

Diccionario de variables

Indicador Descripción Valores
Age La edad de cada individuo Numérico entero
Gender El género del individuo Male o Famale
Blood Preassure La presión en sangre del individuo Numérico entero
Cholesterol Level El nivel de colesterol de cada individuo Numérico entero
Exercise Habits Nivel de ejercicio del individuo Low(bajo), Medium(medio), High(alto)
Smoking Si el individuo fuma o no Yes o No
Family Heart Disease Si alguien en la familia tiene padecimientos en el corazón Yes o No
Diabetes Si la persona padece de diabetes o no Yes o No
BMI Índice de masa corporal del individuo Numérico decimal
High Blood Pressure Si el individuo tiene presión de sangre alta Yes o No
Low HDL Cholesterol Si el individuo tiene bajo nivel de colesterol HDL Yes o No
High LDL Cholesterol Si el individuo tiene alto nivel de colesterol LDL Yes o No
Alcohol Consumption Cuanto alcohol consume el individuo None(nada), Low(poco), Medium(medio), High(alto)
Stress Level Nivel de estrés del individuo Low(bajo), Medium(medio), High(alto)
Sleep Hours Cantidad de horas de sueño del individuo Numérico decimal
Sugar Consumption Consumo de azúcar del individuo Low(bajo), Medium(medio), High(alto)
Triglyceride Level Nivel de triglicéridos del individuo Numérico entero
Fasting Blood Sugar Nivel de azúcar en sangre del individuo Numérico entero
CRP Level Nivel de la proteína C reactiva Numérico decimal
Homocysteine Level Nivel de homocisteína del individuo Numérico decimal
Heart Disease Status Si el individuo tiene o no problemas del corazón Yes o No

Definiciones importantes

  • Colesterol: es una sustancia cerosa y grasa que el cuerpo necesita para formar células saludables, hormonas y vitamina D, es producido por el hígado y viaja por la sangre.

  • Diabetes: es una enfermedad crónica que se caracteriza por altos niveles de glucosa en sangre, aparece cuando el páncreas no produce suficiente insulina o el cuerpo no es capaz de usarla.

  • Índice de Masa Corporal (BMI): es una medida que usa el peso y la estatura para estimar la grasa corporal y evaluar el riesgo de la salud en adultos, es decir si tiene sobrepeso u obesidad, se calcula mediante la siguiente formula: \[BMI = \frac{Peso (kg)}{Altura (m^2)}\]

  • HDL Colesterol: lipoproteína de alta densidad es conocido como el colesterol “bueno”, porque transporta el colesterol del cuerpo al hígado para ser destruido, reduciendo el riesgo de enfermedades cardiacas.

  • LDL Colesterol: lipoproteína de baja densidad es conocido como el colesterol “malo”, porque transporta colesterol a las células, pero cuando sus niveles son altos estos se acumulan en las paredes de las arterias, estrechándolas y provocando su endurecimiento, lo que aumenta el riesgo de ataques cardiacos.

  • Triglicéridos: es el tipo más común de grasa (lípido) en el cuerpo, el cual es esencial para proporcionar energía, cuando hay niveles altos en sangre, por encima de 200mg/dl aumentan los riesgos de enfermedades cardiacas.

  • CRP level: mide la inflamación en el cuerpo, es producida por el hígado y sus niveles aumentan cuando hay infecciones, lesiones o enfermedades crónicas, mientras mayor nivel indica que hay alta inflación del cuerpo.

  • Homocisteína: es un aminoácido presente en la sangre que se produce al descomponer proteínas. En niveles altos daña las arterias y aumentan el riesgo de enfermedades cardiovasculares.


4. Descripción detallada y explicación de las gráficas

Gráficas unidimencionales

  • Gráfica 1 Distribución de individuos por edad.

La gráfica de burbujas anterior demuestra mediante una serie de burbujas la distribución de la edad de los individuos del conjunto de datos, donde las burbujas más pequeñas representan que tienen menos individuos en esa edad, mientras las más grandes representan que hay mayor cantidad de individuos, la posición de izquierda a derecha indica la edad, siendo la izquierda la menor y la derecha la mayor. Observar esta visualización nos permite ver que hay una distribución bastante pareja de los datos, ya que la mayoria de las burbujas rondan un tamaño similar, lo que representa que en promedio por cada edad hay de 150 a 160 individuos, así mismo, podemos identificar ciertos extremos muy facilmente como es el caso de la edad 48, que es la que posee menor cantidad de individuos relacionados.

  • Gráfica 2 Distribución de individuos por género.

La gráfica de pastel anterior permite ver la distribucion de individos “Male”, “Female” o “Nulos”, donde los nulos son los datos que estan vacios, con 0 o en blanco. Se puede ver que hay una distribucion casi 50-50 entre los géneros masculino y femenino, sin embargo, hay un 0.02% mas de individuos masulinos que femeninos. El conjunto de datos posee datos de 5003 individuos masculinos y 4978 individuos femeninos y 19 individuos que no estan registrados. Esto nos permite comprender que el conjunto de datos esta balanceado entre masculinos y femeninos.

  • Gráfica 3 Distribución de individuos con antecedentes familiares de enfermedades del corazón.

La gráfica de barras anterior muestra la distribución de las respuestas de los individuos sobre si possen antecedentes de problemas en el corazón, lo que nos deja la siguiente información relevante, 5004 individuos no tienen atecedentes familiares hay 21 individuos que respondieron en blanco, mientras que, 4975 individuos si lo posee, lo que indica que podria haber un poco de probabilidad de que esos individuos. Lo que, al igual que las graficas anteriores demuestra que los datos están practicamente balanceados

Gráficas bidimencionales

  • Gráfica 1: Consumo de Azúcar vs Niveles de Glucosa en Ayunas

Esta gráfica permite evaluar como un hábito de consumo afecta un indicador clínico. Al hacer uso de los notch en las cajas, permite identificar de forma interactiva si las medias e glucosa varían significativamente según el nuvel de azúcar ingerido. Si se quisiera indagar más, esto ayudaría a validar si la dieta es un factor determinante en los niveles de azúcar en sangre de los pacientes.

  • Gráfica 2: Concentración de Colesterol según Nivel de Estrés

Se hace uso de un gráfico de violín interactivo para observar la densidad de los niveles de colesterol según el estrés del paciente. Al analizar la forma de la distribución, el EDA revela un patrón interesante: los datos se distribuyen de manera casi uniforme en todos los niveles. Esto nos indica estadísticamente que, en este conjunto de datos específico, el nivel de estrés no altera significativamente la concentración de colesterol

Gráficas multidimencionales

  • Gráfica 1 Distribución de individuos por habitos individuales, ejercicio, nivel de estres, horas de sueño, consumo de azucar y problemas del corazón.

La matriz de dispersión en escalera permite ver una comparatica de 5 dimensiones, horas de sueño redondeadas, consumo de azucar, nivel de estrés, si es fumador y la cantidad de ejercicio que se realiza comparando cada una con las demás, donde cada gráfica representa la comparación de dos variables, mediante mapas de calor interactivos, la intensidad del color azul funciona como un indicador de densidad demográfica, lo que permite ver a simple vista la cantidad de personas que cumplen con dichas caracteristicas. Para poder ver los datos, solo se pasa por encima el mouse para ver los datos.

Gráfica de facetas

  • Gráfica 1: Relación de Edad y BMI dividida por Tabaquismo

Para esta visualización se hace uso de la técnica de facetas que permite integrar 4 variables simultáneamente: Edad en el eje X, BMI en el eje Y, Estado Cardíaco representado con el Color y Tabaquismo en los Paneles separados. Al dividir la población entre fumadores y no fumadores, se puede explorar de manera interactiva si los puntos rojos, es decir, pacientes con enfermedad, tienden a concentrarse en zonas de mayor edad o mayor peso dependiendo de su hábito de fumar.


Gráfica compuesta


  • Gráfica 1: Dashboard Integrado de Factores Clínicos

Esta imagen compuesta integra las dos gráficas bidimensionales generadas anteriormente en un solo dashboard. La ventaja es que permite comparar múltiples factores de riesgo biológico y de comportamiento en una sola pantalla, e igual se mantinenen las capacidades de interacción.

5. Conclusiones

Tras realizar el EDA sobre este conjunto del total de registros, el proceso de storytelling visual nos ha permitido transformar datos crudos en hallazgos clave sobre los factores de riesgo en enfermedades cardíacas:

Para finalizar, el desarrollo de este EDA demuestra la importancia del storytelling con los datos. Al transformar registros complejos en gráficas interactivas y narrativas claras, se facilita por mucho la comprensión de la información. Gracias a la limpieza, estructuración y ausencia de sesgos demográficos comprobados, este conjunto de datos resulta ser un candidato ideal para el diseño de dashboards médicos. Estas herramientas visuales permitirían a los profesionales de la salud explorar tendencias, aislar variables interactivamente y comunicar riesgos a los pacientes de forma transparente y efectiva, cumpliendo así con el objetivo fundamental de la visualización de la información.

LS0tDQp0aXRsZTogIkFuw6FsaXNpcyBFeHBsb3JhdG9yaW8gZGUgRGF0b3M6IEVuZmVybWVkYWRlcyBkZWwgQ29yYXrDs24iDQphdXRob3I6ICJSYWZhZWwgQXJheWEgeSBPdHRvIFNlZ3VyYSINCmRhdGU6ICIxMiBkZSBhYnJpbCwgMjAyNiINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCiMjIDEuIEludHJvZHVjY2nDs24NCkVzdGUgaW5mb3JtZSB0aWVuZSBjb21vIG9iamV0aXZvIHByaW5jaXBhbCByZWFsaXphciB1biBhbsOhbGlzaXMgZXhwbG9yYXRvcmlvIGRlIGxvcyBkYXRvcyBzb2JyZSB1biBjb25qdW50byBkZSBkYXRvcyBzb2JyZSBwZXJzb25hcyBjb24gZW5mZXJtZWRhZGVzIGRlbCBjb3JhesOzbiwgY29uIHN1cyBjYXJhY3RlcsOtc3RpY2FzIGRlIGZvcm1hIGFuw7NuaW1hIHBhcmEgcG9kZXIgZ2VuZXJhciB2aXN1YWxpemFjaW9uZXMgaW5mb3JtYXRpdmFzIHNvYnJlIGxhIHJlbGFjacOzbiBxdWUgdGllbmVuIGxhcyB2YXJpYWJsZXMgZW50cmUgc8OtLCBwYXJhIHBvZGVyIGNvbXByZW5kZXIgbG9zIGRhdG9zIGRlIHVuYSBtZWpvciBtYW5lcmEsIGJ1c2NhbmRvIHBhdHJvbmVzLCBpZGVudGlmaWNhbmRvIGFub21hbMOtYXMsIGV0Yy4gDQoNCi0tLQ0KDQojIyAyLiBEZXNjcmlwY2nDs24gZGVsIHByb2JsZW1hDQpMb3MgcHJvYmxlbWFzIGRlIGNvcmF6w7NuIHNvbiBjYWRhIHZleiBtw6FzIGNvbXVuZXMgZW4gbGFzIHNvY2llZGFkZXMgbW9kZXJuYXMsIGVzdG8gZGViaWRvIGEgbXVjaG9zIGZhY3RvcmVzIHF1ZSBhZmVjdGFuIGxhIHNhbHVkIGbDrXNpY2EgZGUgbGFzIHBlcnNvbmFzLCBjb21vIGxhIGZhbHRhIGRlIGFjdGl2aWRhZCBmw61zaWNhLCBlbCBjb25zdW1vIGRlIGNvbWlkYXMgcXVlIHBlcmp1ZGljYW4gZWwgZXN0YWRvIGRlbCBjb3JhesOzbiB5IGVsIHJlc3RvIGRlbCBjdWVycG8sIGVsIGNvbnN1bW8gZGUgZHJvZ2FzLCBwYWRlY2ltaWVudG9zIHByZXZpb3MgY29tbyBwcmVzacOzbiBhbHRhLCBkaWFiZXRlcywgdGllbXBvcyBkZSBzdWXDsW8gaXJyZWd1bGFyZXMsIGFsdG9zIG5pdmVsZXMgZGUgZXN0csOpcy4gRXN0YXMgeSBvdHJhcyByYXpvbmVzIHNvbiBmdWVudGVzIGRlIHByb2JsZW1hcyBlbiBlbCBjb3JhesOzbiBlbiBwZXJzb25hcyBkZSB0b2RvIGVsIG11bmRvLg0KDQpFcyBwb3IgZXN0byBwb3IgbG8gcXVlIG11Y2hvcyBlc3BlY2lhbGlzdGFzIGVuIGVsIHRlbWEgcmVjb2xlY3RhbiBkYXRvcyBkZSBsYXMgcGVyc29uYXMgcXVlIHB1ZWRlbiBheXVkYXIgYSBjb25maXJtYXIgc2kgc2UgdGllbmUgbyBubyBhbGfDum4gcGFkZWNpbWllbnRvIGRlbCBjb3JhesOzbiwgbyBhbCBtZW5vcyBzZSBwdWVkYSB1dGlsaXphciBjb21vIGd1w61hIHBhcmEgcG9kZXIgaWRlbnRpZmljYXJsb3MgdGVtcHJhbm8sIGNvbW8gZWwgY29uanVudG8gZGUgZGF0b3MgcXVlIHNlIHV0aWxpemFyYSBlbiBlbCBwcmVzZW50ZSBhbsOhbGlzaXMgZXhwbG9yYXRvcmlvIGRlIGxvcyBkYXRvcy4NCg0KDQotLS0NCg0KIyMgMy4gRGVmaW5pY2nDs24gZGUgZnVlbnRlcyBkZSBkYXRvcw0KRWwgY29uanVudG8gZGUgZGF0b3MgcXVlIGVzIHVzYWRvIHBhcmEgZXN0ZSBhbsOhbGlzaXMgZnVlIHJlYWxpemFkbyBwb3IgT2t0YXkgw5ZyZGVrY2kgbGxhbWFkbyBbSGVhcnQgRGlzZWFzZV0oIGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGF0YXNldHMvb2t0YXlyZGVraS9oZWFydC1kaXNlYXNlICllbCBjdWFsIGNvbnRpZW5lIDIxIGluZGljYWRvcmVzIGRlIHJpZXNnbyByZWxhY2lvbmFkb3MgYSBsb3MgcHJvYmxlbWFzIGRlIHNhbHVkLiBDb21vIGxhIGVkYWQsIGdlbmVybywgcHJlc2nDs24gZW4gc2FuZ3JlLCBldGMuIEVzdG9zIGRhdG9zIGZ1ZXJvbiByZWNvbGVjdGFkb3MgcGFyYSBhbmFsaXphciBsYXMgcG9zaWJpbGlkYWRlcyBkZSByaWVzZ28gZW4gcGFkZWNpbWllbnRvcyBkZWwgY29udHJvbCB5IGF5dWRhciBhIGxhIGludmVzdGlnYWNpw7NuIGVuIHRlbWFzIGRlIHNhbHVkLiBMYSBzaWd1aWVudGUgdGFibGEgbXVlc3RyYSB0b2RvcyBsb3MgaW5kaWNhZG9yZXMgcXVlIGNvbnRpZW5lIGVsIGNvbmp1bnRvIGRlIGRhdG9zLCB1bmEgYnJldmUgZGVzY3JpcGNpb24gZGUgY2FkYSB1bm8geSBsb3MgdmFsb3JlcyBxdWUgcHVlZGUgdG9tYXIuIA0KDQojIyMgRGljY2lvbmFyaW8gZGUgdmFyaWFibGVzDQp8IEluZGljYWRvciB8IERlc2NyaXBjacOzbiB8IFZhbG9yZXMgfA0KfCA6LS0tIHwgOi0tLSB8IDotLS0gfA0KfCAqKkFnZSoqIHwgTGEgZWRhZCBkZSBjYWRhIGluZGl2aWR1byB8IE51bcOpcmljbyBlbnRlcm8gfA0KfCAqKkdlbmRlcioqIHwgRWwgZ8OpbmVybyBkZWwgaW5kaXZpZHVvIHwgTWFsZSBvIEZhbWFsZSB8DQp8ICoqQmxvb2QgUHJlYXNzdXJlKiogfCBMYSBwcmVzacOzbiBlbiBzYW5ncmUgZGVsIGluZGl2aWR1byB8IE51bcOpcmljbyBlbnRlcm8gfA0KfCAqKkNob2xlc3Rlcm9sIExldmVsKiogfCBFbCBuaXZlbCBkZSBjb2xlc3Rlcm9sIGRlIGNhZGEgaW5kaXZpZHVvIHwgTnVtw6lyaWNvIGVudGVybyB8DQp8ICoqRXhlcmNpc2UgSGFiaXRzKiogfCBOaXZlbCBkZSBlamVyY2ljaW8gZGVsIGluZGl2aWR1byB8IExvdyhiYWpvKSwgTWVkaXVtKG1lZGlvKSwgSGlnaChhbHRvKSB8DQp8ICoqU21va2luZyoqIHwgU2kgZWwgaW5kaXZpZHVvIGZ1bWEgbyBubyB8IFllcyBvIE5vIHwNCnwgKipGYW1pbHkgSGVhcnQgRGlzZWFzZSoqIHwgU2kgYWxndWllbiBlbiBsYSBmYW1pbGlhIHRpZW5lIHBhZGVjaW1pZW50b3MgZW4gZWwgY29yYXrDs24gfCBZZXMgbyBObyB8DQp8ICoqRGlhYmV0ZXMqKiB8IFNpIGxhIHBlcnNvbmEgcGFkZWNlIGRlIGRpYWJldGVzIG8gbm8gfCBZZXMgbyBObyB8DQp8ICoqQk1JKiogfCDDjW5kaWNlIGRlIG1hc2EgY29ycG9yYWwgZGVsIGluZGl2aWR1byB8IE51bcOpcmljbyBkZWNpbWFsIHwNCnwgKipIaWdoIEJsb29kIFByZXNzdXJlKiogfCBTaSBlbCBpbmRpdmlkdW8gdGllbmUgcHJlc2nDs24gZGUgc2FuZ3JlIGFsdGEgfCBZZXMgbyBObyB8DQp8ICoqTG93IEhETCBDaG9sZXN0ZXJvbCoqIHwgU2kgZWwgaW5kaXZpZHVvIHRpZW5lIGJham8gbml2ZWwgZGUgY29sZXN0ZXJvbCBIREwgfCBZZXMgbyBObyB8DQp8ICoqSGlnaCBMREwgQ2hvbGVzdGVyb2wqKiB8IFNpIGVsIGluZGl2aWR1byB0aWVuZSBhbHRvIG5pdmVsIGRlIGNvbGVzdGVyb2wgTERMIHwgWWVzIG8gTm8gfA0KfCAqKkFsY29ob2wgQ29uc3VtcHRpb24qKiB8IEN1YW50byBhbGNvaG9sIGNvbnN1bWUgZWwgaW5kaXZpZHVvIHwgTm9uZShuYWRhKSwgTG93KHBvY28pLCBNZWRpdW0obWVkaW8pLCBIaWdoKGFsdG8pIHwNCnwgKipTdHJlc3MgTGV2ZWwqKiB8IE5pdmVsIGRlIGVzdHLDqXMgZGVsIGluZGl2aWR1byB8IExvdyhiYWpvKSwgTWVkaXVtKG1lZGlvKSwgSGlnaChhbHRvKSB8DQp8ICoqU2xlZXAgSG91cnMqKiB8IENhbnRpZGFkIGRlIGhvcmFzIGRlIHN1ZcOxbyBkZWwgaW5kaXZpZHVvIHwgTnVtw6lyaWNvIGRlY2ltYWwgfA0KfCAqKlN1Z2FyIENvbnN1bXB0aW9uKiogfCBDb25zdW1vIGRlIGF6w7pjYXIgZGVsIGluZGl2aWR1byB8IExvdyhiYWpvKSwgTWVkaXVtKG1lZGlvKSwgSGlnaChhbHRvKSB8DQp8ICoqVHJpZ2x5Y2VyaWRlIExldmVsKiogfCBOaXZlbCBkZSB0cmlnbGljw6lyaWRvcyBkZWwgaW5kaXZpZHVvIHwgTnVtw6lyaWNvIGVudGVybyB8DQp8ICoqRmFzdGluZyBCbG9vZCBTdWdhcioqIHwgTml2ZWwgZGUgYXrDumNhciBlbiBzYW5ncmUgZGVsIGluZGl2aWR1byB8IE51bcOpcmljbyBlbnRlcm8gfA0KfCAqKkNSUCBMZXZlbCoqIHwgTml2ZWwgZGUgbGEgcHJvdGXDrW5hIEMgcmVhY3RpdmEgfCBOdW3DqXJpY28gZGVjaW1hbCB8DQp8ICoqSG9tb2N5c3RlaW5lIExldmVsKiogfCBOaXZlbCBkZSBob21vY2lzdGXDrW5hIGRlbCBpbmRpdmlkdW8gfCBOdW3DqXJpY28gZGVjaW1hbCB8DQp8ICoqSGVhcnQgRGlzZWFzZSBTdGF0dXMqKiB8IFNpIGVsIGluZGl2aWR1byB0aWVuZSBvIG5vIHByb2JsZW1hcyBkZWwgY29yYXrDs24gfCBZZXMgbyBObyB8DQoNCiMjIyBEZWZpbmljaW9uZXMgaW1wb3J0YW50ZXMNCiogKipDb2xlc3Rlcm9sKio6IGVzIHVuYSBzdXN0YW5jaWEgY2Vyb3NhIHkgZ3Jhc2EgcXVlIGVsIGN1ZXJwbyBuZWNlc2l0YSBwYXJhIGZvcm1hciBjw6lsdWxhcyBzYWx1ZGFibGVzLCBob3Jtb25hcyB5IHZpdGFtaW5hIEQsIGVzIHByb2R1Y2lkbyBwb3IgZWwgaMOtZ2FkbyB5IHZpYWphIHBvciBsYSBzYW5ncmUuIA0KKiAqKkRpYWJldGVzKio6IGVzIHVuYSBlbmZlcm1lZGFkIGNyw7NuaWNhIHF1ZSBzZSBjYXJhY3Rlcml6YSBwb3IgYWx0b3Mgbml2ZWxlcyBkZSBnbHVjb3NhIGVuIHNhbmdyZSwgYXBhcmVjZSBjdWFuZG8gZWwgcMOhbmNyZWFzIG5vIHByb2R1Y2Ugc3VmaWNpZW50ZSBpbnN1bGluYSBvIGVsIGN1ZXJwbyBubyBlcyBjYXBheiBkZSB1c2FybGEuIA0KDQoqICoqw41uZGljZSBkZSBNYXNhIENvcnBvcmFsIChCTUkpOioqIGVzIHVuYSBtZWRpZGEgcXVlIHVzYSBlbCBwZXNvIHkgbGEgZXN0YXR1cmEgcGFyYSBlc3RpbWFyIGxhIGdyYXNhIGNvcnBvcmFsIHkgZXZhbHVhciBlbCByaWVzZ28gZGUgbGEgc2FsdWQgZW4gYWR1bHRvcywgZXMgZGVjaXIgc2kgdGllbmUgc29icmVwZXNvIHUgb2Jlc2lkYWQsIHNlIGNhbGN1bGEgbWVkaWFudGUgbGEgc2lndWllbnRlIGZvcm11bGE6DQokJEJNSSA9IFxmcmFje1Blc28gKGtnKX17QWx0dXJhIChtXjIpfSQkDQoqICoqSERMIENvbGVzdGVyb2wqKjogbGlwb3Byb3Rlw61uYSBkZSBhbHRhIGRlbnNpZGFkIGVzIGNvbm9jaWRvIGNvbW8gZWwgY29sZXN0ZXJvbCDigJxidWVub+KAnSwgcG9ycXVlIHRyYW5zcG9ydGEgZWwgY29sZXN0ZXJvbCBkZWwgY3VlcnBvIGFsIGjDrWdhZG8gcGFyYSBzZXIgZGVzdHJ1aWRvLCByZWR1Y2llbmRvIGVsIHJpZXNnbyBkZSBlbmZlcm1lZGFkZXMgY2FyZGlhY2FzLiANCiogKipMREwgQ29sZXN0ZXJvbCoqOiBsaXBvcHJvdGXDrW5hIGRlIGJhamEgZGVuc2lkYWQgZXMgY29ub2NpZG8gY29tbyBlbCBjb2xlc3Rlcm9sIOKAnG1hbG/igJ0sIHBvcnF1ZSB0cmFuc3BvcnRhIGNvbGVzdGVyb2wgYSBsYXMgY8OpbHVsYXMsIHBlcm8gY3VhbmRvIHN1cyBuaXZlbGVzIHNvbiBhbHRvcyBlc3RvcyBzZSBhY3VtdWxhbiBlbiBsYXMgcGFyZWRlcyBkZSBsYXMgYXJ0ZXJpYXMsIGVzdHJlY2jDoW5kb2xhcyB5IHByb3ZvY2FuZG8gc3UgZW5kdXJlY2ltaWVudG8sIGxvIHF1ZSBhdW1lbnRhIGVsIHJpZXNnbyBkZSBhdGFxdWVzIGNhcmRpYWNvcy4gDQoqICoqVHJpZ2xpY8Opcmlkb3MqKjogZXMgZWwgdGlwbyBtw6FzIGNvbcO6biBkZSBncmFzYSAobMOtcGlkbykgZW4gZWwgY3VlcnBvLCBlbCBjdWFsIGVzIGVzZW5jaWFsIHBhcmEgcHJvcG9yY2lvbmFyIGVuZXJnw61hLCBjdWFuZG8gaGF5IG5pdmVsZXMgYWx0b3MgZW4gc2FuZ3JlLCBwb3IgZW5jaW1hIGRlIDIwMG1nL2RsIGF1bWVudGFuIGxvcyByaWVzZ29zIGRlIGVuZmVybWVkYWRlcyBjYXJkaWFjYXMuIA0KKiAqKkNSUCBsZXZlbCoqOiBtaWRlIGxhIGluZmxhbWFjacOzbiBlbiBlbCBjdWVycG8sIGVzIHByb2R1Y2lkYSBwb3IgZWwgaMOtZ2FkbyB5IHN1cyBuaXZlbGVzIGF1bWVudGFuIGN1YW5kbyBoYXkgaW5mZWNjaW9uZXMsIGxlc2lvbmVzIG8gZW5mZXJtZWRhZGVzIGNyw7NuaWNhcywgbWllbnRyYXMgbWF5b3Igbml2ZWwgaW5kaWNhIHF1ZSBoYXkgYWx0YSBpbmZsYWNpw7NuIGRlbCBjdWVycG8uIA0KKiAqKkhvbW9jaXN0ZcOtbmEqKjogZXMgdW4gYW1pbm/DoWNpZG8gcHJlc2VudGUgZW4gbGEgc2FuZ3JlIHF1ZSBzZSBwcm9kdWNlIGFsIGRlc2NvbXBvbmVyIHByb3Rlw61uYXMuIEVuIG5pdmVsZXMgYWx0b3MgZGHDsWEgbGFzIGFydGVyaWFzIHkgYXVtZW50YW4gZWwgcmllc2dvIGRlIGVuZmVybWVkYWRlcyBjYXJkaW92YXNjdWxhcmVzLiANCg0KDQotLS0NCg0KIyMgNC4gRGVzY3JpcGNpw7NuIGRldGFsbGFkYSB5IGV4cGxpY2FjacOzbiBkZSBsYXMgZ3LDoWZpY2FzDQoNCmBgYHtyLCBlY2hvID0gRkFMU0V9DQojaW5zdGFsbC5wYWNrYWdlcygicGxvdGx5IikNCiNpbnN0YWxsLnBhY2thZ2VzKCJkcGx5ciIpDQojaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpDQojaW5zdGFsbC5wYWNrYWdlcygiR0dhbGx5IikNCmRhdGEgPC0gcmVhZC5jc3YoImRhdGEvaGVhcnRfZGlzZWFzZS5jc3YiKQ0KYGBgDQoNCiMjIyAqKkdyw6FmaWNhcyB1bmlkaW1lbmNpb25hbGVzKioNCg0KKiAqKkdyw6FmaWNhIDEgRGlzdHJpYnVjacOzbiBkZSBpbmRpdmlkdW9zIHBvciBlZGFkLioqDQoNCmBgYHtyLCBlY2hvID0gRkFMU0V9DQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkoZHBseXIpDQoNCmRhdGEgPC0gcmVhZC5jc3YoImRhdGEvaGVhcnRfZGlzZWFzZS5jc3YiKQ0KDQpkYXRhX2J1cmJ1amFzIDwtIGRhdGEgJT4lDQogIGdyb3VwX2J5KEFnZSkgJT4lDQogIHN1bW1hcmlzZShDYW50aWRhZCA9IG4oKSkNCg0KZmlnIDwtIHBsb3RfbHkoZGF0YV9idXJidWphcywgeCA9IH5BZ2UsIHkgPSB+Q2FudGlkYWQsIHR5cGUgPSAnc2NhdHRlcicsIG1vZGUgPSAnbWFya2Vycycsc2l6ZSA9IH5DYW50aWRhZCwgY29sb3IgPSB+YXMuZmFjdG9yKEFnZSksbWFya2VyID0gbGlzdChzaXplbW9kZSA9ICdkaWFtZXRlcicsIG9wYWNpdHkgPSAwLjcsIGxpbmUgPSBsaXN0KHdpZHRoID0gMSwgY29sb3IgPSAnI0ZGRkZGRicpKSkNCg0KZmlnIDwtIGZpZyAlPiUgbGF5b3V0KA0KICAgIHRpdGxlID0gJ0Rpc3RyaWJ1Y2nDs24gZGUgaW5kaXZpZHVvcyBwb3IgZWRhZCcsDQogICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gJ0VkYWQnLCBzaG93Z3JpZCA9IEZBTFNFKSwNCiAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAnQ2FudGlkYWQgZGUgaW5kaXZpZHVvcycsIHNob3dncmlkID0gRkFMU0UpLA0KICAgIHNob3dsZWdlbmQgPSBGQUxTRQ0KICApDQoNCmZpZw0KDQpgYGANCg0KTGEgZ3LDoWZpY2EgZGUgYnVyYnVqYXMgYW50ZXJpb3IgZGVtdWVzdHJhIG1lZGlhbnRlIHVuYSBzZXJpZSBkZSBidXJidWphcyBsYSBkaXN0cmlidWNpw7NuIGRlIGxhIGVkYWQgZGUgbG9zIGluZGl2aWR1b3MgZGVsIGNvbmp1bnRvIGRlIGRhdG9zLCBkb25kZSBsYXMgYnVyYnVqYXMgbcOhcyBwZXF1ZcOxYXMgcmVwcmVzZW50YW4gcXVlIHRpZW5lbiBtZW5vcyBpbmRpdmlkdW9zIGVuIGVzYSBlZGFkLCBtaWVudHJhcyBsYXMgbcOhcyBncmFuZGVzIHJlcHJlc2VudGFuIHF1ZSBoYXkgbWF5b3IgY2FudGlkYWQgZGUgaW5kaXZpZHVvcywgbGEgcG9zaWNpw7NuIGRlIGl6cXVpZXJkYSBhIGRlcmVjaGEgaW5kaWNhIGxhIGVkYWQsIHNpZW5kbyBsYSBpenF1aWVyZGEgbGEgbWVub3IgeSBsYSBkZXJlY2hhIGxhIG1heW9yLiBPYnNlcnZhciBlc3RhIHZpc3VhbGl6YWNpw7NuIG5vcyBwZXJtaXRlIHZlciBxdWUgaGF5IHVuYSBkaXN0cmlidWNpw7NuIGJhc3RhbnRlIHBhcmVqYSBkZSBsb3MgZGF0b3MsIHlhIHF1ZSBsYSBtYXlvcmlhIGRlIGxhcyBidXJidWphcyByb25kYW4gdW4gdGFtYcOxbyBzaW1pbGFyLCBsbyBxdWUgcmVwcmVzZW50YSBxdWUgZW4gcHJvbWVkaW8gcG9yIGNhZGEgZWRhZCBoYXkgZGUgMTUwIGEgMTYwIGluZGl2aWR1b3MsIGFzw60gbWlzbW8sIHBvZGVtb3MgaWRlbnRpZmljYXIgY2llcnRvcyBleHRyZW1vcyBtdXkgZmFjaWxtZW50ZSBjb21vIGVzIGVsIGNhc28gZGUgbGEgZWRhZCA0OCwgcXVlIGVzIGxhIHF1ZSBwb3NlZSBtZW5vciBjYW50aWRhZCBkZSBpbmRpdmlkdW9zIHJlbGFjaW9uYWRvcy4gDQoNCiogKipHcsOhZmljYSAyIERpc3RyaWJ1Y2nDs24gZGUgaW5kaXZpZHVvcyBwb3IgZ8OpbmVyby4qKg0KDQoNCmBgYHtyLCBlY2hvID0gRkFMU0V9DQpsaWJyYXJ5KGRwbHlyKQ0KDQpkYXRhIDwtIHJlYWQuY3N2KCJkYXRhL2hlYXJ0X2Rpc2Vhc2UuY3N2IikNCg0KZGF0YV9nZW4gPC0gZGF0YSAlPiUNCiAgbXV0YXRlKEdlbmRlciA9IGNhc2Vfd2hlbihHZW5kZXIgPT0gIk1hbGUiIH4gIk1hc2N1bGlubyIsR2VuZGVyID09ICJGZW1hbGUiIH4gIkZlbWVuaW5vIixUUlVFIH4gIk51bG9zIg0KICApKSAlPiUNCiAgZ3JvdXBfYnkoR2VuZGVyKSAlPiUNCiAgc3VtbWFyaXNlKENhbnRpZGFkID0gbigpKQ0KDQoNCmZpZyA8LSBwbG90X2x5KGRhdGFfZ2VuLCBsYWJlbHMgPSB+R2VuZGVyLCB2YWx1ZXMgPSB+Q2FudGlkYWQsIHR5cGUgPSAncGllJywgbWFya2VyID0gbGlzdChjb2xvcnMgPSBjKCcjRjA2MjkyJywgJyMxRTg4RTUnLCAnI0JEQzNDNycpKSkgDQoNCmZpZyA8LSBmaWcgJT4lIGxheW91dCh0aXRsZSA9ICdEaXN0cmlidWNpw7NuIGRlIGluZGl2aWR1b3MgcG9yIGfDqW5lcm8nLCB4YXhpcyA9IGxpc3Qoc2hvd2dyaWQgPSBGQUxTRSwgemVyb2xpbmUgPSBGQUxTRSwgc2hvd3RpY2tsYWJlbHMgPSBGQUxTRSksIHlheGlzID0gbGlzdChzaG93Z3JpZCA9IEZBTFNFLCB6ZXJvbGluZSA9IEZBTFNFLCBzaG93dGlja2xhYmVscyA9IEZBTFNFKSkNCmZpZw0KYGBgDQpMYSBncsOhZmljYSBkZSBwYXN0ZWwgYW50ZXJpb3IgcGVybWl0ZSB2ZXIgbGEgZGlzdHJpYnVjaW9uIGRlIGluZGl2aWRvcyAiTWFsZSIsICJGZW1hbGUiIG8gIk51bG9zIiwgZG9uZGUgbG9zIG51bG9zIHNvbiBsb3MgZGF0b3MgcXVlIGVzdGFuIHZhY2lvcywgY29uIDAgbyBlbiBibGFuY28uIFNlIHB1ZWRlIHZlciBxdWUgaGF5IHVuYSBkaXN0cmlidWNpb24gY2FzaSA1MC01MCBlbnRyZSBsb3MgZ8OpbmVyb3MgbWFzY3VsaW5vIHkgZmVtZW5pbm8sIHNpbiBlbWJhcmdvLCBoYXkgdW4gMC4wMiUgbWFzIGRlIGluZGl2aWR1b3MgbWFzdWxpbm9zIHF1ZSBmZW1lbmlub3MuIEVsIGNvbmp1bnRvIGRlIGRhdG9zIHBvc2VlIGRhdG9zIGRlICoqNTAwMyoqIGluZGl2aWR1b3MgbWFzY3VsaW5vcyB5ICoqNDk3OCoqIGluZGl2aWR1b3MgZmVtZW5pbm9zIHkgKioxOSoqIGluZGl2aWR1b3MgcXVlIG5vIGVzdGFuIHJlZ2lzdHJhZG9zLiBFc3RvIG5vcyBwZXJtaXRlIGNvbXByZW5kZXIgcXVlIGVsIGNvbmp1bnRvIGRlIGRhdG9zIGVzdGEgYmFsYW5jZWFkbyBlbnRyZSBtYXNjdWxpbm9zIHkgZmVtZW5pbm9zLiANCg0KKiAqKkdyw6FmaWNhIDMgRGlzdHJpYnVjacOzbiBkZSBpbmRpdmlkdW9zIGNvbiBhbnRlY2VkZW50ZXMgZmFtaWxpYXJlcyBkZSBlbmZlcm1lZGFkZXMgZGVsIGNvcmF6w7NuLioqDQoNCmBgYHtyLCBlY2hvID0gRkFMU0V9DQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkoZHBseXIpDQoNCmRhdGEgPC0gcmVhZC5jc3YoImRhdGEvaGVhcnRfZGlzZWFzZS5jc3YiKQ0KDQpkYXRhX2ZhbSA8LSBkYXRhICU+JQ0KICBtdXRhdGUoRmFtaWx5LkhlYXJ0LkRpc2Vhc2UgPSBjYXNlX3doZW4oIGlzLm5hKEZhbWlseS5IZWFydC5EaXNlYXNlKSB8IEZhbWlseS5IZWFydC5EaXNlYXNlID09ICIiIH4gIkVuIGJsYW5jbyIsIEZhbWlseS5IZWFydC5EaXNlYXNlID09ICJZZXMiIH4gIlPDrSIsIEZhbWlseS5IZWFydC5EaXNlYXNlID09ICJObyIgfiAiTm8iLCBUUlVFIH4gYXMuY2hhcmFjdGVyKEZhbWlseS5IZWFydC5EaXNlYXNlKSApKSAlPiUgZ3JvdXBfYnkoRmFtaWx5LkhlYXJ0LkRpc2Vhc2UpICU+JSBzdW1tYXJpc2UoQ2FudGlkYWQgPSBuKCkpDQoNCmZpZyA8LSBwbG90X2x5KGRhdGFfZmFtLCB4ID0gfkZhbWlseS5IZWFydC5EaXNlYXNlLCB5ID0gfkNhbnRpZGFkLCB0eXBlID0gImJhciIsIG1hcmtlciA9IGxpc3QoY29sb3IgPSBjKCAnI0JEQzNDNycsICcjMzQ5OERCJywgICcjRTc0QzNDJykpKSANCg0KZmlnIDwtIGZpZyAlPiUgbGF5b3V0KHRpdGxlID0gJ0FudGVjZWRlbnRlcyBmYW1pbGlhcmVzIGRlIGVuZmVybWVkYWRlcyBkZWwgY29yYXrDs24nLA0KICAgICAgICAgICAgICAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICLCv1Bvc2VlIGFudGVjZWRlbnRlcz8iKSwNCiAgICAgICAgICAgICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiQ2FudGlkYWQgZGUgUGVyc29uYXMiKSkNCg0KZmlnDQoNCmBgYA0KTGEgZ3LDoWZpY2EgZGUgYmFycmFzIGFudGVyaW9yIG11ZXN0cmEgbGEgZGlzdHJpYnVjacOzbiBkZSBsYXMgcmVzcHVlc3RhcyBkZSBsb3MgaW5kaXZpZHVvcyBzb2JyZSBzaSBwb3NzZW4gYW50ZWNlZGVudGVzIGRlIHByb2JsZW1hcyBlbiBlbCBjb3JhesOzbiwgbG8gcXVlIG5vcyBkZWphIGxhIHNpZ3VpZW50ZSBpbmZvcm1hY2nDs24gcmVsZXZhbnRlLCAqKjUwMDQqKiBpbmRpdmlkdW9zIG5vIHRpZW5lbiBhdGVjZWRlbnRlcyBmYW1pbGlhcmVzIGhheSAqKjIxKiogaW5kaXZpZHVvcyBxdWUgcmVzcG9uZGllcm9uIGVuIGJsYW5jbywgbWllbnRyYXMgcXVlLCAqKjQ5NzUqKiBpbmRpdmlkdW9zIHNpIGxvIHBvc2VlLCAgbG8gcXVlIGluZGljYSBxdWUgcG9kcmlhIGhhYmVyIHVuIHBvY28gZGUgcHJvYmFiaWxpZGFkIGRlIHF1ZSBlc29zIGluZGl2aWR1b3MuIExvIHF1ZSwgYWwgaWd1YWwgcXVlIGxhcyBncmFmaWNhcyBhbnRlcmlvcmVzIGRlbXVlc3RyYSBxdWUgbG9zIGRhdG9zIGVzdMOhbiBwcmFjdGljYW1lbnRlICBiYWxhbmNlYWRvcw0KDQoNCg0KIyMjICoqR3LDoWZpY2FzIGJpZGltZW5jaW9uYWxlcyoqDQoNCiogKipHcsOhZmljYSAxOiBDb25zdW1vIGRlIEF6w7pjYXIgdnMgTml2ZWxlcyBkZSBHbHVjb3NhIGVuIEF5dW5hcyoqDQoNCmBgYHtyLCBlY2hvID0gRkFMU0V9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkoZHBseXIpDQoNCmRhdGFfYmkxIDwtIGRhdGEgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKFN1Z2FyLkNvbnN1bXB0aW9uKSwgIWlzLm5hKEZhc3RpbmcuQmxvb2QuU3VnYXIpLCBTdWdhci5Db25zdW1wdGlvbiAhPSAiIikNCg0KcDEgPC0gZ2dwbG90KGRhdGFfYmkxLCBhZXMoeCA9IFN1Z2FyLkNvbnN1bXB0aW9uLCB5ID0gRmFzdGluZy5CbG9vZC5TdWdhciwgZmlsbCA9IFN1Z2FyLkNvbnN1bXB0aW9uKSkgKw0KICBnZW9tX2JveHBsb3Qobm90Y2ggPSBUUlVFLCBhbHBoYSA9IDAuNykgKyANCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgbGFicyh0aXRsZSA9ICJSZWxhY2nDs24gZW50cmUgRGlldGEgeSBHbHVjb3NhIiwgDQogICAgICAgeCA9ICJOaXZlbCBkZSBDb25zdW1vIGRlIEF6w7pjYXIiLCANCiAgICAgICB5ID0gIkdsdWNvc2EgZW4gQXl1bmFzIChtZy9kTCkiKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIkxvdyIgPSAibGlnaHRncmVlbiIsICJNZWRpdW0iID0gImdyZWVuIiwgIkhpZ2giID0gImRhcmtncmVlbiIpKQ0KDQpncmFmaWNhXzJkXzEgPC0gZ2dwbG90bHkocDEpDQpncmFmaWNhXzJkXzENCmBgYA0KRXN0YSBncsOhZmljYSBwZXJtaXRlIGV2YWx1YXIgY29tbyB1biBow6FiaXRvIGRlIGNvbnN1bW8gYWZlY3RhIHVuIGluZGljYWRvciBjbMOtbmljby4gQWwgaGFjZXIgdXNvIGRlIGxvcyBub3RjaCBlbiBsYXMgY2FqYXMsIHBlcm1pdGUgaWRlbnRpZmljYXIgZGUgZm9ybWEgaW50ZXJhY3RpdmEgc2kgbGFzIG1lZGlhcyBlIGdsdWNvc2EgdmFyw61hbiBzaWduaWZpY2F0aXZhbWVudGUgc2Vnw7puIGVsIG51dmVsIGRlIGF6w7pjYXIgaW5nZXJpZG8uIFNpIHNlIHF1aXNpZXJhIGluZGFnYXIgbcOhcywgZXN0byBheXVkYXLDrWEgYSB2YWxpZGFyIHNpIGxhIGRpZXRhIGVzIHVuIGZhY3RvciBkZXRlcm1pbmFudGUgZW4gbG9zIG5pdmVsZXMgZGUgYXrDumNhciBlbiBzYW5ncmUgZGUgbG9zIHBhY2llbnRlcy4gDQoNCiogKipHcsOhZmljYSAyOiBDb25jZW50cmFjacOzbiBkZSBDb2xlc3Rlcm9sIHNlZ8O6biBOaXZlbCBkZSBFc3Ryw6lzICoqDQoNCmBgYHtyLCBlY2hvID0gRkFMU0V9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkoZHBseXIpDQoNCmRhdGFfYmkyIDwtIGRhdGEgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKFN0cmVzcy5MZXZlbCksICFpcy5uYShDaG9sZXN0ZXJvbC5MZXZlbCksIFN0cmVzcy5MZXZlbCAhPSAiIikNCg0KcDIgPC0gZ2dwbG90KGRhdGFfYmkyLCBhZXMoeCA9IFN0cmVzcy5MZXZlbCwgeSA9IENob2xlc3Rlcm9sLkxldmVsLCBmaWxsID0gU3RyZXNzLkxldmVsKSkgKw0KICBnZW9tX3Zpb2xpbih0cmltID0gRkFMU0UsIGFscGhhID0gMC43KSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIGxhYnModGl0bGUgPSAiRGlzdHJpYnVjacOzbiBkZSBDb2xlc3Rlcm9sIHBvciBOaXZlbCBkZSBFc3Ryw6lzIiwgDQogICAgICAgeCA9ICJOaXZlbCBkZSBFc3Ryw6lzIiwgDQogICAgICAgeSA9ICJOaXZlbCBkZSBDb2xlc3Rlcm9sIikgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJMb3ciID0gImdyZWVuIiwgIk1lZGl1bSIgPSAieWVsbG93IiwgIkhpZ2giID0gInJlZCIpKQ0KDQpncmFmaWNhXzJkXzIgPC0gZ2dwbG90bHkocDIpDQpncmFmaWNhXzJkXzINCmBgYA0KU2UgaGFjZSB1c28gZGUgdW4gZ3LDoWZpY28gZGUgdmlvbMOtbiBpbnRlcmFjdGl2byBwYXJhIG9ic2VydmFyIGxhIGRlbnNpZGFkIGRlIGxvcyBuaXZlbGVzIGRlIGNvbGVzdGVyb2wgc2Vnw7puIGVsIGVzdHLDqXMgZGVsIHBhY2llbnRlLiBBbCBhbmFsaXphciBsYSBmb3JtYSBkZSBsYSBkaXN0cmlidWNpw7NuLCBlbCBFREEgcmV2ZWxhIHVuIHBhdHLDs24gaW50ZXJlc2FudGU6IGxvcyBkYXRvcyBzZSBkaXN0cmlidXllbiBkZSBtYW5lcmEgY2FzaSB1bmlmb3JtZSBlbiB0b2RvcyBsb3Mgbml2ZWxlcy4gRXN0byBub3MgaW5kaWNhIGVzdGFkw61zdGljYW1lbnRlIHF1ZSwgZW4gZXN0ZSBjb25qdW50byBkZSBkYXRvcyBlc3BlY8OtZmljbywgZWwgbml2ZWwgZGUgZXN0csOpcyBubyBhbHRlcmEgc2lnbmlmaWNhdGl2YW1lbnRlIGxhIGNvbmNlbnRyYWNpw7NuIGRlIGNvbGVzdGVyb2wNCg0KIyMjICoqR3LDoWZpY2FzIG11bHRpZGltZW5jaW9uYWxlcyoqDQoNCiogKipHcsOhZmljYSAxIERpc3RyaWJ1Y2nDs24gZGUgaW5kaXZpZHVvcyBwb3IgaGFiaXRvcyBpbmRpdmlkdWFsZXMsIGVqZXJjaWNpbywgbml2ZWwgZGUgZXN0cmVzLCBob3JhcyBkZSBzdWXDsW8sIGNvbnN1bW8gZGUgYXp1Y2FyIHkgcHJvYmxlbWFzIGRlbCBjb3JhesOzbi4qKg0KDQpgYGB7ciwgZWNobyA9IEZBTFNFfQ0KbGlicmFyeShwbG90bHkpDQpsaWJyYXJ5KGRwbHlyKQ0KDQoNCmRhdGFfbGltcGlhIDwtIGRhdGEgJT4lDQogIG11dGF0ZShhY3Jvc3MoYyhFeGVyY2lzZS5IYWJpdHMsIFNsZWVwLkhvdXJzLCBTdWdhci5Db25zdW1wdGlvbiwgU21va2luZywgU3RyZXNzLkxldmVsKSwgDQogICAgICAgICAgICAgICAgfmFzLmNoYXJhY3RlcihpZihpcy5udW1lcmljKC4pKSByb3VuZCguKSBlbHNlIC4pKSkgJT4lIA0KICBzZWxlY3QoRWplcmNpY2lvID0gRXhlcmNpc2UuSGFiaXRzLCBTdWXDsW8gPSBTbGVlcC5Ib3VycywgDQogICAgICAgICBBesO6Y2FyID0gU3VnYXIuQ29uc3VtcHRpb24sIEZ1bWFkb3IgPSBTbW9raW5nLCBFc3Ryw6lzID0gU3RyZXNzLkxldmVsKQ0KDQp2YXJzIDwtIG5hbWVzKGRhdGFfbGltcGlhKQ0Kbl92YXJzIDwtIGxlbmd0aCh2YXJzKQ0KDQoNCmNyZWFyX2NlbGRhX2VzY2FsZXJhIDwtIGZ1bmN0aW9uKGNvbF9pZHgsIHJvd19pZHgpIHsNCiAgdjEgPC0gdmFyc1tjb2xfaWR4XSANCiAgdjIgPC0gdmFyc1tyb3dfaWR4XQ0KICANCiAgaWYgKGNvbF9pZHggPCByb3dfaWR4KSB7IA0KICAgIGRmX2NvdW50IDwtIGRhdGFfbGltcGlhICU+JSBjb3VudCguZGF0YVtbdjFdXSwgLmRhdGFbW3YyXV0pDQogICAgDQogICAgcGxvdF9seShkYXRhID0gZGZfY291bnQsIHggPSB+LmRhdGFbW3YxXV0sIHkgPSB+LmRhdGFbW3YyXV0sIHogPSB+biwgDQogICAgICAgICAgICB0eXBlID0gImhlYXRtYXAiLCBjb2xvcnNjYWxlID0gIkJsdWVzIiwgc2hvd3NjYWxlID0gRkFMU0UsIA0KICAgICAgICAgICAgaG92ZXJpbmZvID0gInRleHQiLCANCiAgICAgICAgICAgIHRleHQgPSB+cGFzdGUwKCI8Yj4iLCB2MSwgIjwvYj4gdnMgPGI+IiwgdjIsICI8L2I+PGJyPiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRhdGFbW3YxXV0sICIgLyAiLCAuZGF0YVtbdjJdXSwgIjxicj4iLCAiVG90YWw6ICIsIG4sICIgcGVyc29uYXMiKSkgJT4lDQogICAgICBsYXlvdXQoDQogICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9IGlmKHJvd19pZHggPT0gbl92YXJzKSB2MSBlbHNlICIiLCB0aWNrYW5nbGUgPSA0NSksDQogICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9IGlmKGNvbF9pZHggPT0gMSkgdjIgZWxzZSAiIikNCiAgICAgICkNCiAgfSBlbHNlIHsNCiAgICANCiAgICBwbG90X2x5KHR5cGUgPSAic2NhdHRlciIsIG1vZGUgPSAibWFya2VycyIpICU+JSANCiAgICAgIGxheW91dCh4YXhpcyA9IGxpc3QodmlzaWJsZSA9IEZBTFNFKSwgeWF4aXMgPSBsaXN0KHZpc2libGUgPSBGQUxTRSkpDQogIH0NCn0NCg0KDQpsaXN0YV9wbG90cyA8LSBsaXN0KCkNCmZvciAoaSBpbiAxOm5fdmFycykgeyAgIA0KICBmb3IgKGogaW4gMTpuX3ZhcnMpIHsgIA0KICAgIGxpc3RhX3Bsb3RzW1tsZW5ndGgobGlzdGFfcGxvdHMpICsgMV1dIDwtIGNyZWFyX2NlbGRhX2VzY2FsZXJhKGosIGkpDQogIH0NCn0NCg0KZmlnIDwtIHN1YnBsb3QobGlzdGFfcGxvdHMsIG5yb3dzID0gbl92YXJzLCBtYXJnaW4gPSAwLjAyLCANCiAgICAgICAgICAgICAgIHRpdGxlWCA9IFRSVUUsIHRpdGxlWSA9IFRSVUUsIHNoYXJlWCA9IEZBTFNFLCBzaGFyZVkgPSBGQUxTRSkgJT4lDQogIGxheW91dCgNCiAgICB0aXRsZSA9ICJDb21wYXJhdGl2YSBkZSBow6FiaXRvcyIsDQogICAgbWFyZ2luID0gbGlzdChsID0gMTAwLCBiID0gMTAwLCB0ID0gODAsIHIgPSAyMCkNCiAgKQ0KDQpmaWckd2lkdGggPC0gODUwDQpmaWckaGVpZ2h0IDwtIDg1MA0KDQpmaWcNCmBgYA0KDQoNCg0KTGEgbWF0cml6IGRlIGRpc3BlcnNpw7NuIGVuIGVzY2FsZXJhIHBlcm1pdGUgdmVyIHVuYSBjb21wYXJhdGljYSBkZSA1IGRpbWVuc2lvbmVzLCBob3JhcyBkZSBzdWXDsW8gcmVkb25kZWFkYXMsIGNvbnN1bW8gZGUgYXp1Y2FyLCBuaXZlbCBkZSBlc3Ryw6lzLCBzaSBlcyBmdW1hZG9yIHkgbGEgY2FudGlkYWQgZGUgZWplcmNpY2lvIHF1ZSBzZSByZWFsaXphIGNvbXBhcmFuZG8gY2FkYSB1bmEgY29uIGxhcyBkZW3DoXMsIGRvbmRlIGNhZGEgZ3LDoWZpY2EgcmVwcmVzZW50YSBsYSBjb21wYXJhY2nDs24gZGUgZG9zIHZhcmlhYmxlcywgbWVkaWFudGUgbWFwYXMgZGUgY2Fsb3IgaW50ZXJhY3Rpdm9zLCBsYSBpbnRlbnNpZGFkIGRlbCBjb2xvciBhenVsIGZ1bmNpb25hIGNvbW8gdW4gaW5kaWNhZG9yIGRlIGRlbnNpZGFkIGRlbW9ncsOhZmljYSwgbG8gcXVlIHBlcm1pdGUgdmVyIGEgc2ltcGxlIHZpc3RhIGxhIGNhbnRpZGFkIGRlIHBlcnNvbmFzIHF1ZSBjdW1wbGVuIGNvbiBkaWNoYXMgY2FyYWN0ZXJpc3RpY2FzLiBQYXJhIHBvZGVyIHZlciBsb3MgZGF0b3MsIHNvbG8gc2UgcGFzYSBwb3IgZW5jaW1hIGVsIG1vdXNlIHBhcmEgdmVyIGxvcyBkYXRvcy4NCg0KDQoqKkdyw6FmaWNhIGRlIGZhY2V0YXMqKg0KDQoqICoqR3LDoWZpY2EgMTogUmVsYWNpw7NuIGRlIEVkYWQgeSBCTUkgZGl2aWRpZGEgcG9yIFRhYmFxdWlzbW8qKg0KDQoNCmBgYHtyLCBlY2hvID0gRkFMU0V9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkoZHBseXIpDQoNCmRhdGFfZmFjZXRhcyA8LSBkYXRhICU+JSANCiAgZmlsdGVyKCFpcy5uYShBZ2UpLCAhaXMubmEoQk1JKSwgU21va2luZyAlaW4lIGMoIlllcyIsICJObyIpLCAhaXMubmEoSGVhcnQuRGlzZWFzZS5TdGF0dXMpKQ0KDQpwMyA8LSBnZ3Bsb3QoZGF0YV9mYWNldGFzLCBhZXMoeCA9IEFnZSwgeSA9IEJNSSwgY29sb3IgPSBIZWFydC5EaXNlYXNlLlN0YXR1cykpICsNCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNSkgKw0KICBmYWNldF93cmFwKH4gU21va2luZykgKyAjIEFxdcOtIGNyZWFtb3MgbG9zIHBhbmVsZXMgc2VwYXJhZG9zDQogIHRoZW1lX21pbmltYWwoKSArDQogIGxhYnModGl0bGUgPSAiRWRhZCB2cyBCTUkgKFBhbmVsZXMgcG9yIFRhYmFxdWlzbW8pIiwgDQogICAgICAgeCA9ICJFZGFkIChhw7FvcykiLCANCiAgICAgICB5ID0gIsONbmRpY2UgZGUgTWFzYSBDb3Jwb3JhbCAoQk1JKSIpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIk5vIiA9ICJsaWdodGJsdWUiLCAiWWVzIiA9ICJyZWQiKSkNCg0KZ3JhZmljYV9mYWNldGFzIDwtIGdncGxvdGx5KHAzKQ0KZ3JhZmljYV9mYWNldGFzDQoNCmBgYA0KDQpQYXJhIGVzdGEgdmlzdWFsaXphY2nDs24gc2UgaGFjZSB1c28gZGUgbGEgdMOpY25pY2EgZGUgZmFjZXRhcyBxdWUgcGVybWl0ZSBpbnRlZ3JhciA0IHZhcmlhYmxlcyBzaW11bHTDoW5lYW1lbnRlOiBFZGFkIGVuIGVsIGVqZSBYLCBCTUkgZW4gZWwgZWplIFksIEVzdGFkbyBDYXJkw61hY28gcmVwcmVzZW50YWRvIGNvbiBlbCBDb2xvciB5IFRhYmFxdWlzbW8gZW4gbG9zIFBhbmVsZXMgc2VwYXJhZG9zLiBBbCBkaXZpZGlyIGxhIHBvYmxhY2nDs24gZW50cmUgZnVtYWRvcmVzIHkgbm8gZnVtYWRvcmVzLCBzZSBwdWVkZSBleHBsb3JhciBkZSBtYW5lcmEgaW50ZXJhY3RpdmEgc2kgbG9zIHB1bnRvcyByb2pvcywgZXMgZGVjaXIsIHBhY2llbnRlcyBjb24gZW5mZXJtZWRhZCwgdGllbmRlbiBhIGNvbmNlbnRyYXJzZSBlbiB6b25hcyBkZSBtYXlvciBlZGFkIG8gbWF5b3IgcGVzbyBkZXBlbmRpZW5kbyBkZSBzdSBow6FiaXRvIGRlIGZ1bWFyLg0KDQotLS0NCg0KIyMjICoqR3LDoWZpY2EgY29tcHVlc3RhKioNCg0KLS0tDQoNCiogKipHcsOhZmljYSAxOiBEYXNoYm9hcmQgSW50ZWdyYWRvIGRlIEZhY3RvcmVzIENsw61uaWNvcyoqDQoNCmBgYHtyLCBlY2hvID0gRkFMU0V9DQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkoZHBseXIpDQoNCmdyYWZpY2FfY29tcHVlc3RhIDwtIHN1YnBsb3QgKGdyYWZpY2FfMmRfMSwgZ3JhZmljYV8yZF8yLCBucm93cyA9IDEsIG1hcmdpbiA9IDAuMDUsIHRpdGxlWCA9IFRSVUUsIHRpdGxlWSA9IFRSVUUpICU+JQ0KICBsYXlvdXQodGl0bGUgPSAiRGFzaGJvYXJkOiBBbsOhbGlzaXMgZGUgRXN0csOpcyB5IERpZXRhIiwgc2hvd2xlZ2VuZCA9IEZBTFNFKQ0KDQpncmFmaWNhX2NvbXB1ZXN0YQ0KYGBgDQpFc3RhIGltYWdlbiBjb21wdWVzdGEgaW50ZWdyYSBsYXMgZG9zIGdyw6FmaWNhcyBiaWRpbWVuc2lvbmFsZXMgZ2VuZXJhZGFzIGFudGVyaW9ybWVudGUgZW4gdW4gc29sbyBkYXNoYm9hcmQuIExhIHZlbnRhamEgZXMgcXVlIHBlcm1pdGUgY29tcGFyYXIgbcO6bHRpcGxlcyBmYWN0b3JlcyBkZSByaWVzZ28gYmlvbMOzZ2ljbyB5IGRlIGNvbXBvcnRhbWllbnRvIGVuIHVuYSBzb2xhIHBhbnRhbGxhLCBlIGlndWFsIHNlIG1hbnRpbmVuZW4gbGFzIGNhcGFjaWRhZGVzIGRlIGludGVyYWNjacOzbi4gDQoNCiMjIDUuIENvbmNsdXNpb25lcw0KDQpUcmFzIHJlYWxpemFyIGVsIEVEQSBzb2JyZSBlc3RlIGNvbmp1bnRvIGRlbCB0b3RhbCBkZSByZWdpc3Ryb3MsIGVsIHByb2Nlc28gZGUgc3Rvcnl0ZWxsaW5nIHZpc3VhbCBub3MgaGEgcGVybWl0aWRvIHRyYW5zZm9ybWFyIGRhdG9zIGNydWRvcyBlbiBoYWxsYXpnb3MgY2xhdmUgc29icmUgbG9zIGZhY3RvcmVzIGRlIHJpZXNnbyBlbiBlbmZlcm1lZGFkZXMgY2FyZMOtYWNhczoNCg0KKiAqKkJhbGFuY2UgeSBjYWxpZGFkIGRlIGxhIG11ZXN0cmE6KiogRWwgYW7DoWxpc2lzIHVuaWRpbWVuc2lvbmFsIHJldmVsw7MgcXVlIGVsIGNvbmp1bnRvIGRlIGRhdG9zIGVzdMOhIGV4Y2VwY2lvbmFsbWVudGUgYmFsYW5jZWFkbyBlbiB0w6lybWlub3MgZGVtb2dyw6FmaWNvcy4gTGEgZGlzdHJpYnVjacOzbiBjYXNpIHNpbcOpdHJpY2EgZW50cmUgbG9zIGfDqW5lcm9zICg1MDAzIG1hc2N1bGlub3MgeSA0OTc4IGZlbWVuaW5vcykgeSBsYSBwcm9wb3JjacOzbiBlcXVpdGF0aXZhIGRlIGFudGVjZWRlbnRlcyBmYW1pbGlhcmVzLCBnYXJhbnRpemFuIHF1ZSBsb3MgcGF0cm9uZXMgZGVzY3ViaWVydG9zIG5vIGVzdMOpbiBzZXNnYWRvcyBoYWNpYSB1biBncnVwbyBwb2JsYWNpb25hbCBlc3BlY8OtZmljby4NCg0KKiAqKkRlc21pdGlmaWNhY2nDs24gZGUgdmFyaWFibGVzIGFpc2xhZGFzOioqIFVuYSBkZSBsYXMgcmV2ZWxhY2lvbmVzIG3DoXMgdmFsaW9zYXMgc3VyZ2nDsyBlbiBlbCBhbsOhbGlzaXMgYmlkaW1lbnNpb25hbC4gQ29udHJhcmlvIGEgbGEgY3JlZW5jaWEgcG9wdWxhciBkZSBxdWUgZWwgZXN0csOpcyBkaXNwYXJhIGF1dG9tw6F0aWNhbWVudGUgZWwgY29sZXN0ZXJvbCwgbGFzIGdyw6FmaWNhcyBkZSB2aW9sw61uIGRlbW9zdHJhcm9uIHVuYSBkaXN0cmlidWNpw7NuIHVuaWZvcm1lOyBlcyBkZWNpciwgZW4gZXN0YSBwb2JsYWNpw7NuIHBhcnRpY3VsYXIsIGVsIG5pdmVsIGRlIGVzdHLDqXMgcG9yIHPDrSBzb2xvIG5vIGFsdGVyYSBkZSBmb3JtYSBlc3RhZMOtc3RpY2FtZW50ZSBzaWduaWZpY2F0aXZhIGxhIGNvbmNlbnRyYWNpw7NuIGRlIGNvbGVzdGVyb2wuIEVzdG8gaW5kaWNhIHF1ZSBubyBzZSBkZWJlIGRpYWdub3N0aWNhciBlbCByaWVzZ28gYmFzw6FuZG9zZSBlbiB1biBzb2xvIGZhY3RvciBhaXNsYWRvLg0KDQoqICoqRWwgcG9kZXIgZGUgbG9zIGZhY3RvcmVzIGNvbWJpbmFkb3M6KiogRWwgdmVyZGFkZXJvIHZhbG9yIHByZWRpY3Rpdm8gc2Ugb2JzZXJ2w7MgYWwgY3J1emFyIG3Dumx0aXBsZXMgZGltZW5zaW9uZXMuIEdyYWNpYXMgYSBsYXMgZ3LDoWZpY2FzIGRlIGZhY2V0YXMgeSBsYSBtYXRyaXogZGUgY2Fsb3IgbXVsdGlkaW1lbnNpb25hbCwgcXVlZMOzIGVuIGV2aWRlbmNpYSBxdWUgbGFzIGVuZmVybWVkYWRlcyBkZWwgY29yYXrDs24gbm8gZGVwZW5kZW4gZGUgdW4gc29sbyBtYWwgaMOhYml0bywgc2lubyBkZSBsYSBhY3VtdWxhY2nDs24gZGUgZXN0b3MuIExhIGludGVyYWNjacOzbiBzaW11bHTDoW5lYSBlbnRyZSB1bmEgbWF5b3IgZWRhZCwgdW4gQk1JIGVsZXZhZG8geSBlbCBTbW9raW5nIGFncnVwYSB2aXN1YWxtZW50ZSBhIGxvcyBwYWNpZW50ZXMgY29uIGVzdGFkbyBjYXJkw61hY28gcG9zaXRpdm8gZW5jSGVhcnQgRGlzZWFzZSBTdGF0dXMuDQoNCiogKipBY2Npb25hYmlsaWRhZDoqKg0KQSBuaXZlbCBtw6lkaWNvIHkgcHJldmVudGl2bywgZXN0ZSBhbsOhbGlzaXMgc3VnaWVyZSBxdWUgbGFzIGNhbXBhw7FhcyBkZSBzYWx1ZCBubyBkZWJlbiBlbmZvY2Fyc2Ugw7puaWNhbWVudGUgZW4gcmVkdWNpciBlbCBlc3Ryw6lzIG8gZWwgY29uc3VtbyBkZSBhesO6Y2FyIGRlIGZvcm1hIGFpc2xhZGEuIERlYmVuIGRpc2XDsWFyc2UgaW50ZXJ2ZW5jaW9uZXMgaW50ZWdyYWxlcyBkaXJpZ2lkYXMgYSBsb3MgInBlcmZpbGVzIGNvbWJpbmFkb3MiIGRlIGFsdG8gcmllc2dvIChwb3IgZWplbXBsbzogcGFjaWVudGVzIGRlIGVkYWQgYXZhbnphZGEsIGNvbiBhbHRvIEJNSSB5IGZ1bWFkb3JlcyBhY3Rpdm9zKS4gDQoNClBhcmEgZmluYWxpemFyLCBlbCBkZXNhcnJvbGxvIGRlIGVzdGUgRURBIGRlbXVlc3RyYSBsYSBpbXBvcnRhbmNpYSBkZWwgc3Rvcnl0ZWxsaW5nIGNvbiBsb3MgZGF0b3MuIEFsIHRyYW5zZm9ybWFyIHJlZ2lzdHJvcyBjb21wbGVqb3MgZW4gZ3LDoWZpY2FzIGludGVyYWN0aXZhcyB5IG5hcnJhdGl2YXMgY2xhcmFzLCBzZSBmYWNpbGl0YSBwb3IgbXVjaG8gbGEgY29tcHJlbnNpw7NuIGRlIGxhIGluZm9ybWFjacOzbi4gR3JhY2lhcyBhIGxhIGxpbXBpZXphLCBlc3RydWN0dXJhY2nDs24geSBhdXNlbmNpYSBkZSBzZXNnb3MgZGVtb2dyw6FmaWNvcyBjb21wcm9iYWRvcywgZXN0ZSBjb25qdW50byBkZSBkYXRvcyByZXN1bHRhIHNlciB1biBjYW5kaWRhdG8gaWRlYWwgcGFyYSBlbCBkaXNlw7FvIGRlIGRhc2hib2FyZHMgbcOpZGljb3MuIEVzdGFzIGhlcnJhbWllbnRhcyB2aXN1YWxlcyBwZXJtaXRpcsOtYW4gYSBsb3MgcHJvZmVzaW9uYWxlcyBkZSBsYSBzYWx1ZCBleHBsb3JhciB0ZW5kZW5jaWFzLCBhaXNsYXIgdmFyaWFibGVzIGludGVyYWN0aXZhbWVudGUgeSBjb211bmljYXIgcmllc2dvcyBhIGxvcyBwYWNpZW50ZXMgZGUgZm9ybWEgdHJhbnNwYXJlbnRlIHkgZWZlY3RpdmEsIGN1bXBsaWVuZG8gYXPDrSBjb24gZWwgb2JqZXRpdm8gZnVuZGFtZW50YWwgZGUgbGEgdmlzdWFsaXphY2nDs24gZGUgbGEgaW5mb3JtYWNpw7NuLg0K