library
library(ggplot2)
library(dplyr)

Entendiendo el Tidy Data

Por Fernanda Arros y Tomás Chanampa.

A la hora de enfrentarnos a un conjunto de datos que desamos procesar mediante porgramas como R es preciso que ordenemos esta información de la manera más estructurada posible, para que así nuestro trabajo con los datos pueda ser comprendido con facilidad.

En ese sentido, una herramienta fundamental para ordenar nuestros datos es el Data Tidying, un concepto que fue abordado por Hadley Wickham en 2014 y que en el siguiente texto comenzaremos a revisar.

De acuerdo a Wickham, el Data Tidy es un proceso que consiste en “estructurar conjuntos de datos para facilitar su análisis”. Es decir, ordenar la información de un conjunto de datos.

En la práctica, al trabajar en programas como R, el Data Tidying se traduce en algo denominado Tidy Data, una estructura que según Wickham “proporciona una forma estandarizada de vincular la estructura de un conjunto de datos (su diseño físico) con su semántica (su significado)”.

Pero ¿Qué es todo esto en la práctica?

En las siguientes tablas podemos ver dos ejemplos donde se compila la edades de los alumnos de un curso.

Curso <- tibble(
   Edad_Alumnos= c(rep("10 Años", 8), 
                 rep("11 Años", 21),      
                 rep("12 Años", 3))
)
Curso

En la primera tabla nos encontramos con los datos de las edades en “bruto” compilados en una lista. Con datos en esta manera, el trabajo de datos es lento, porque hay que ir agrupando los datos uno por uno si es que se quiere hayar algo

Curso_Data <- tribble(                                   
 ~Edad_Alumnos, ~Cantidad,      
    "10 años",            8,        
  "11 años",             21,                  
    "12 años",            3
)
Curso_Data

En cambio, en la segunda tabla, los datos se agruparon automaticamente.

Siguiendo con el ejemplo de las tablas 1 y 2 podemos comprender lo que Wickham plantea respecto al Tidy Data.

De acuerdo al autor,“un conjunto de datos es Tidy o desordenado dependiendo de cómo las filas, columnas y tablas se combinan con las observaciones,variables y tipos”.

Es decir, mis datos serán más o menos compresibles de acuerdo a la estructura lógica que yo eliga para presentarlos

En ese sentido, el autor plantea que para que un set de datos sea Tidy es indispensable que:

- Cada variable forme una columna

- Cada osbervacion forme un fila

- Cada tipo de unidad de observación forme una tabla

Podemos ver aplicadas estas reglas en la suiguente tabla

Peliculas_Taquilleras_Chile_2018 <-  tribble (
  
    ~Pelicula,                           ~Productora,   ~MillDolRec,  ~MesEstreno,   
    "Avengers_Infinity_War",                    "Disney",          14.7,      "Abril",   
  "Incredibles_2",                          "Disney",           8.9,        "Junio",    
    "Jurassic_World_Fallen_Kingdom",             "UPI",           7.7,      "Junio",    
  "Hotel_Transylvania_3_Summer_Vacation",       "Sony",           6.5,      "Julio",    
    "Deadpool_2",                                "Fox",           6.2,       "Mayo",    
    "Black_Panther",                          "Disney",           4.9,    "Febrero",    
    "Ferdinand",                                 "Fox",           3.4,      "Enero",    
    "Venom",                                    "Sony",           2.8,    "Octubre",    
    "Ant-Man_and_the_Wasp",                   "Disney",           2.4,      "Julio",
  "Fifty_Shades_Freed",                         "AF",             2.3,    "Febrero"
)
Peliculas_Taquilleras_Chile_2018

La importancia de trabajar con Datos Tidy en programas como R radica en que no solo el orden de nuestros datos nos permite comprender mejor lo que estamos haciendo, sino en que ahorramos tiempo y podemos sacar un mejor provecho de las herramientas de esta forma.

Por ejemplo, ante la tarea de ordener las películas más exitosas en Chile en los últimos tres años, al ordenar los datos mediante la misma lógica Tidy, vista anteriormente, R nos permite visualizar en primera instancia el predominio del estudio Disney en el mercado nacional.


Peliculas_Taquilleras_Chile_2016_A_2018 <-  tribble (
  
    ~Pelicula,                           ~Productora,    ~MillDolRec,  ~MesEstreno,    ~Año,
    "Avengers_Infinity_War",                    "Disney",           14.7,      "Abril",    2018,
  "Incredibles_2",                          "Disney",            8.9,        "Junio",    2018,
    "Jurassic_World_Fallen_Kingdom",             "UPI",            7.7,      "Junio",    2018,
  "Hotel_Transylvania_3_Summer_Vacation",       "Sony",            6.5,      "Julio",    2018,
    "Deadpool_2",                                "Fox",            6.2,       "Mayo",    2018,
    "Black_Panther",                          "Disney",            4.9,    "Febrero",    2018,
    "Ferdinand",                                 "Fox",            3.4,      "Enero",    2018,
    "Venom",                                    "Sony",            2.8,    "Octubre",    2018,
    "Ant-Man_and_the_Wasp",                   "Disney",            2.4,      "Julio",    2018,
  "Fifty_Shades_Freed",                         "AF",              2.3,    "Febrero",    2018,
  "Coco",                                   "Disney",           10.0,  "Noviembre",    2017,
  "Despicable_Me_3",                           "UPI",            7.3,      "Junio",    2017,
  "The_Fate_of_the_Furious",                     "UPI",            6.9,      "Abril",    2017,
  "Moana",                                  "Disney",            5.3,      "Enero",    2017,
  "Star_Wars_The_Last_Jedi",                "Disney",              4.9,  "Diciembre",    2017,
  "Beauty_and_the_Beast",                     "Disney",            4.8,      "Marzo",    2017, 
  "The_Boss_Baby",                             "Fox",              4.6,      "Marzo",    2017,  
  "Jumanji_Welcome_to_the_Jungle",              "Sony",            4.6,  "Diciembre",    2017,
  "Spider-Man_Homecoming",                    "Sony",            4.3,        "Julio",    2017,
  "Pirates_of_the_Caribbean_D.M.T.N.T",     "Disney",            4.1,       "Mayo",    2017,
    "Ice_Age_Collision_Course",                  "Fox",            7.5,      "Julio",    2016,
    "Finding_Dory",                           "Disney",            7.0,      "Junio",    2016,
    "Captain_America:Civil_War",              "Disney",            6.7,      "Abril",    2016,
    "The_Secret_life_of_Pets",                   "UPI",            6.0,      "Julio",    2016,
    "Batman_VS_Superman:Dawn_of_Justice",         "WB",            5.1,      "Marzo",    2016,  
    "The_Jungle_Book",                        "Disney",            4.7,      "Abril",    2016,
    "Sin_Filtro",                                "n/a",            4.4,      "Enero",    2016,
    "Zootopia",                               "Disney",            4.2,    "Febrero",    2016,
    "Deadpool",                                  "Fox",            4.2,    "Febrero",    2016,
    "Sing",                                      "UPI",              3.5,  "Diciembre",    2016
    
    
    )
Peliculas_Taquilleras_Chile_2016_A_2018

Al manejar grandes sets de datos en programas como R el uso del Tidy Data se vuelve fundamental para conseguir nuestro objetivo de presentar la mejor información de la manera más sencilla posible y obtener nuevos datos gracias al uso de las distintas funciones de R. Una de las herramientas que podemos usar para ello son los verbos de manipulación que vienen incluidos en el paquete de detos de dplyr

Por ejemplo, retomando la tabla anterior de las películas más taquilleras de Chile entre 2016 y 2018, podemos usar la función filter para tomar ciertos datos que son de nuestro interés.

PeliculasDisney2016_A_2018 <- filter(Peliculas_Taquilleras_Chile_2016_A_2018, Productora == "Disney")
PeliculasDisney2016_A_2018

En este caso, como con filter podemos ver datos especificos que cumplan ciertas condiciones, acá tomamos los datos del estudio Disney en el año 2017.

Esto, entre otras, cosas nos pemtirá ver cómo le fue las producciones del estudio dentro de las películas más poulares en Chile en el año 2017.

filter(Peliculas_Taquilleras_Chile_2016_A_2018, Productora == "Disney", Año == 2017)

Otra función que podemos utilizar para sacar el máximo provecho a los datos ordenados según los criterios de Tidy es names, que nos permite conocer las variantes que existen en nuestra tabla.

names(Peliculas_Taquilleras_Chile_2016_A_2018)

En una línea similar podemos seguir explorando nuestra Tidy Data con la función select, la cual nos permite ver variantes específicas.

Por ejemplo, en este caso, una variable específica sería el monto recaudado por cada película, ya que es un valor presente con distintas cifras en cada producción.

select(Peliculas_Taquilleras_Chile_2016_A_2018, Pelicula, MillDolRec)

Dentro de esta misma función podemos organizar más aún nuestra información si ponemos “-” luego una variante, lo que permitirá que en nuestra tabla aprezcan todas las varientes menos esa.

Para efectos de este ejemplo decidimos prescindir del año de estreno de las películas.

select(Peliculas_Taquilleras_Chile_2016_A_2018, -Año)

Siguiendo con select y sus múltiples opciones que nos permiten organizar nuestros datos, también podemos ordenar las variables de nuestra tidy data si escribimos todas las variables y luego las cambiamos de lugar.

Algo que en la siguiente tabla exploramos moviendo el año de estreno desde el costado derecho al izquierdo.

select(Peliculas_Taquilleras_Chile_2016_A_2018, Año, Pelicula, Productora, MillDolRec, MesEstreno)

Otra función muy útil para sacarle provecho a nuestros Datos Tidy es mutate, la que nos permite crear nuevas categorías a partir de las ya existentes.

Sin embargo, por la naturaleza de los datos que hemos explorado hasta ahora respecto a las películas más vistas en Chile, este verbo de manipulación no es compatible con nuestra tabla debido a que las varientes existentes no pueden interactuar entre si para crear otras nuevas.

Esto claramente nos demuestra la importancia de la Tidy Data ya que, si no tuvieramos nuestros datos ordenados, perderíamos nuestro tiempo creando una tabla que no tiene sentido y será difícil de entender.

Pero si bien no todas las funciones sirven para todos los casos, alternativas como summarise son ideales para comenzar a procesar nuestra información ya que esta característica nos permite ver por ejemplo, el promedio de variantes y sus valores maximos y minimos, entre otros datos.

Por ejemplo, nosotros escogimos ver la recaudación promedio y la recaudación máxima de las películas más vistas en Chile entre 2016 y 2018.

summarise(Peliculas_Taquilleras_Chile_2016_A_2018, RecaudaciónPromedio = mean(MillDolRec))
summarise(Peliculas_Taquilleras_Chile_2016_A_2018, RecaudaciónMaxima = max(MillDolRec))

Aunque también podemos usar la función para ver datos como el monto más bajo de recaudacion de nuestras muestras o la suma de todas las ganancias de los films que hay en nuestra tabla.

summarise(Peliculas_Taquilleras_Chile_2016_A_2018, RecaudaciónMinima = min(MillDolRec))
summarise(Peliculas_Taquilleras_Chile_2016_A_2018, RecaudaciónTotal = sum(MillDolRec))

Otro verbo de manipulación que se puede aplicar a los datos como lo hace summarise es group_by, que básicamente permite que los otros verbos de manipulación señalados anteriormente no solo trabajen sobre variables, sino que se ejecuten a través de datos concretos.

Así, por ejemplo, si anteriormente usamos summarise para sacar el promedio de las ganancias cosechadas por las película, lo que nos arrojó fue el promedio de todos los datos de esa variante. En cambio ahora, gracias a group_by, el promedio de ganancias fue separado por año.

Por_Años <- group_by(Peliculas_Taquilleras_Chile_2016_A_2018, Año)
Por_Años
summarise(Por_Años, RecaudaciónPromedio = mean(MillDolRec))

Una última función que nos permite sacar el máximo provecho a nuestra Tidy Data es arrange, un verbo de manipulación que ordena las tablas según las variantes que uno quiera.

En este caso decidimos separar primero por películas y posteriormente por productora y película. Lo que muestra la versatilidad de esta función.

arrange(Peliculas_Taquilleras_Chile_2016_A_2018, Pelicula)
arrange(Peliculas_Taquilleras_Chile_2016_A_2018, Productora, Pelicula)

Visualización de datos

Todo el orden del Tidy Data plasmado mediante los distintos verbos de manipulación además nos permite identificar distintas variables que son de nuestro interés y graficarlos mediantes funciones como ggplot2 con geom_bar.

geom_bar nos ofrece un gráfico de barras, que en este caso muestra la frecuencia de estrenos de las películas más taquilleras en Chile entre 2016 y 2018.

ggplot(data = Por_Meses ) +
  geom_bar(mapping = aes(MesEstreno)) +
   labs(
title = " Catidad de estrenos las peliculas más taquilleras en Chile según cada mes",
subtitle="                                                            Entre 2016 a 2018",
caption = "Datos de www.boxofficemojo.com ",
x = "Meses",
y = " Cantidad"

)

Pero geom_bar no es la única alternativa que ggplot2 nos ofrece para presentar nuestros datos, ya que la función también cuenta con geom_point, que grafica los datos mediante puntos como queda claro en el siguiente gráfico sobre las ganancias de las productoras por las películas más populares en Chile entre 2016 y 2018.

ggplot(data = Peliculas_Taquilleras_Chile_2016_A_2018) +
  geom_point(mapping = aes(x = Productora , y = MillDolRec
                           , colour = as.factor(Año))) +
   labs(
title = " Ganancias de productoras por sus peliculas más taquilleras en Chile",
subtitle="                                                    Entre 2016 a 2018",
caption = "Datos de www.boxofficemojo.com ",
x = "Productoras de Peliculas",
y = " Recaudaciones de Millones de Dolares",
colour = "Año"
)

Siguiendo ese mismo ejemplo, también podemos ver cómo funciona geom_histogram, otra herramienta de ggplot2 que permite graficar los mismo datos que la tabla anterior, pero en el formato de un histograma. Además, gracias a la función facet_Wrap() se forman gráficos comparativos, en esta caso, diviendo la información por cada año.

ggplot(data = Peliculas_Taquilleras_Chile_2016_A_2018) +
  geom_histogram(mapping = aes(x = MillDolRec, fill = Productora),
                 colour = "black") +
  scale_fill_viridis_d() +
  facet_wrap(~Año) +
   labs(
title = "Comparación de la cantidad generada de ganancias por las productoras
                   por cada una de sus peliculas más taquilleras en Chile",
subtitle="                                                    Entre 2016 a 2018",
caption = "Datos de www.boxofficemojo.com ",
x = "Millones de Dolares",
y = "Cantidad",
colour = "Productora"
)

A la luz de todas estas posiblidades para presentar en distintas formas y estructuras un conjunto de datos una vez que es ordenado bajo los principios Tidy, es posible comprender la importancia del orden para el trabajo con datos.

No solo porque, como plantea Wickham, el orden permite estructurar mejor nuestro trabajo, sino porque también nos permite sacarle el máximo provecho a nuestra información y utilizar todas las funciones de R para, por ejemplo, contar una historia a partir de un trabajo a base de datos.

LS0tDQp0aXRsZTogIlRyYWJham8gZGUgVGlkeSBEYXRhIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCmBgYHtyfQ0KbGlicmFyeQ0KYGBgDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmBgYA0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KYGBgDQoNCiNFbnRlbmRpZW5kbyBlbCBUaWR5IERhdGENCiMjIyNQb3IgRmVybmFuZGEgQXJyb3MgeSBUb23hcyBDaGFuYW1wYS4NCg0KIyMjQSBsYSBob3JhIGRlIGVuZnJlbnRhcm5vcyBhIHVuIGNvbmp1bnRvIGRlIGRhdG9zIHF1ZSBkZXNhbW9zIHByb2Nlc2FyIG1lZGlhbnRlIHBvcmdyYW1hcyBjb21vIFIgZXMgcHJlY2lzbyBxdWUgb3JkZW5lbW9zIGVzdGEgaW5mb3JtYWNp824gZGUgbGEgbWFuZXJhIG3hcyBlc3RydWN0dXJhZGEgcG9zaWJsZSwgcGFyYSBxdWUgYXPtIG51ZXN0cm8gdHJhYmFqbyBjb24gbG9zIGRhdG9zIHB1ZWRhIHNlciBjb21wcmVuZGlkbyBjb24gZmFjaWxpZGFkLg0KDQojIyMgRW4gZXNlIHNlbnRpZG8sIHVuYSBoZXJyYW1pZW50YSBmdW5kYW1lbnRhbCBwYXJhIG9yZGVuYXIgbnVlc3Ryb3MgZGF0b3MgZXMgZWwgKipEYXRhIFRpZHlpbmcqKiwgdW4gY29uY2VwdG8gcXVlIGZ1ZSBhYm9yZGFkbyBwb3IgSGFkbGV5IFdpY2toYW0gZW4gMjAxNCB5IHF1ZSBlbiBlbCBzaWd1aWVudGUgdGV4dG8gY29tZW56YXJlbW9zIGEgcmV2aXNhci4gDQoNCiMjI0RlIGFjdWVyZG8gYSBXaWNraGFtLCBlbCBEYXRhIFRpZHkgZXMgdW4gcHJvY2VzbyBxdWUgY29uc2lzdGUgZW4gKioiZXN0cnVjdHVyYXIgY29uanVudG9zIGRlIGRhdG9zIHBhcmEgZmFjaWxpdGFyIHN1IGFu4Wxpc2lzIioqLiBFcyBkZWNpciwgb3JkZW5hciBsYSBpbmZvcm1hY2nzbiBkZSB1biBjb25qdW50byBkZSBkYXRvcy4NCg0KIyMjRW4gbGEgcHLhY3RpY2EsIGFsIHRyYWJhamFyIGVuIHByb2dyYW1hcyBjb21vIFIsIGVsIERhdGEgVGlkeWluZyBzZSB0cmFkdWNlIGVuIGFsZ28gZGVub21pbmFkbyAqKlRpZHkgRGF0YSoqLCB1bmEgZXN0cnVjdHVyYSBxdWUgc2Vn+m4gV2lja2hhbSAicHJvcG9yY2lvbmEgdW5hIGZvcm1hIGVzdGFuZGFyaXphZGEgZGUgdmluY3VsYXIgbGEgZXN0cnVjdHVyYSBkZSB1biBjb25qdW50byBkZSBkYXRvcyAoc3UgZGlzZfFvIGbtc2ljbykgY29uIHN1IHNlbeFudGljYSAoc3Ugc2lnbmlmaWNhZG8pIi4NCg0KIyMqKlBlcm8gv1F16SBlcyB0b2RvIGVzdG8gZW4gbGEgcHLhY3RpY2E/KioNCg0KIyMjRW4gbGFzIHNpZ3VpZW50ZXMgdGFibGFzIHBvZGVtb3MgdmVyIGRvcyBlamVtcGxvcyBkb25kZSBzZSBjb21waWxhIGxhIGVkYWRlcyBkZSBsb3MgYWx1bW5vcyBkZSB1biBjdXJzby4NCg0KDQoNCg0KYGBge3J9DQpDdXJzbyA8LSB0aWJibGUoDQogICBFZGFkX0FsdW1ub3M9IGMocmVwKCIxMCBB8W9zIiwgOCksIA0KICAgICAgICAgICAgICAgICByZXAoIjExIEHxb3MiLCAyMSksICAgICAgDQogICAgICAgICAgICAgICAgIHJlcCgiMTIgQfFvcyIsIDMpKQ0KKQ0KYGBgDQoNCmBgYHtyfQ0KQ3Vyc28NCmBgYA0KIyMjIEVuIGxhIHByaW1lcmEgdGFibGEgbm9zIGVuY29udHJhbW9zIGNvbiBsb3MgZGF0b3MgZGUgbGFzIGVkYWRlcyBlbiAiYnJ1dG8iIGNvbXBpbGFkb3MgZW4gdW5hIGxpc3RhLiBDb24gZGF0b3MgZW4gZXN0YSBtYW5lcmEsIGVsIHRyYWJham8gZGUgZGF0b3MgZXMgbGVudG8sIHBvcnF1ZSBoYXkgcXVlIGlyIGFncnVwYW5kbyBsb3MgZGF0b3MgdW5vIHBvciB1bm8gc2kgZXMgcXVlIHNlIHF1aWVyZSBoYXlhciBhbGdvDQoNCmBgYHtyfQ0KQ3Vyc29fRGF0YSA8LSB0cmliYmxlKCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCSAgICAgDQoNCiB+RWRhZF9BbHVtbm9zLCB+Q2FudGlkYWQsICAgICAgDQoJIjEwIGHxb3MiLCAgICAgICAgICAgIDgsICAgICAgCQ0KICAiMTEgYfFvcyIsCSAgICAgICAgIDIxLCAgICAgICAgICAgICAgICAgIA0KCSIxMiBh8W9zIiwgICAgICAgICAgICAzDQopDQpgYGANCg0KYGBge3J9DQpDdXJzb19EYXRhDQpgYGANCiMjIyBFbiBjYW1iaW8sIGVuIGxhIHNlZ3VuZGEgdGFibGEsIGxvcyBkYXRvcyBzZSBhZ3J1cGFyb24gYXV0b21hdGljYW1lbnRlLg0KDQojIyNTaWd1aWVuZG8gY29uIGVsIGVqZW1wbG8gZGUgbGFzIHRhYmxhcyAxIHkgMiBwb2RlbW9zIGNvbXByZW5kZXIgbG8gcXVlIFdpY2toYW0gcGxhbnRlYSByZXNwZWN0byBhbCBUaWR5IERhdGEuIA0KDQojIyNEZSBhY3VlcmRvIGFsIGF1dG9yLCoqInVuIGNvbmp1bnRvIGRlIGRhdG9zIGVzIFRpZHkgbyBkZXNvcmRlbmFkbyBkZXBlbmRpZW5kbyBkZSBj821vIGxhcyBmaWxhcywgY29sdW1uYXMgeSB0YWJsYXMgc2UgY29tYmluYW4gY29uIGxhcyBvYnNlcnZhY2lvbmVzLHZhcmlhYmxlcyB5IHRpcG9zIioqLiANCg0KIyMjRXMgZGVjaXIsIG1pcyBkYXRvcyBzZXLhbiBt4XMgbyBtZW5vcyBjb21wcmVzaWJsZXMgZGUgYWN1ZXJkbyBhIGxhIGVzdHJ1Y3R1cmEgbPNnaWNhIHF1ZSB5byBlbGlnYSBwYXJhIHByZXNlbnRhcmxvcw0KDQojIyNFbiBlc2Ugc2VudGlkbywgZWwgYXV0b3IgcGxhbnRlYSBxdWUgcGFyYSBxdWUgdW4gc2V0IGRlIGRhdG9zIHNlYSBUaWR5IGVzIGluZGlzcGVuc2FibGUgcXVlOiANCiMjIy0gQ2FkYSB2YXJpYWJsZSBmb3JtZSB1bmEgY29sdW1uYSANCiMjIy0gQ2FkYSBvc2JlcnZhY2lvbiBmb3JtZSB1biBmaWxhIA0KIyMjLSBDYWRhIHRpcG8gZGUgdW5pZGFkIGRlIG9ic2VydmFjafNuIGZvcm1lIHVuYSB0YWJsYSANCg0KIyMjIFBvZGVtb3MgdmVyIGFwbGljYWRhcyBlc3RhcyByZWdsYXMgZW4gbGEgc3VpZ3VlbnRlIHRhYmxhIA0KYGBge3J9DQpQZWxpY3VsYXNfVGFxdWlsbGVyYXNfQ2hpbGVfMjAxOCA8LSAgdHJpYmJsZSAoDQogIA0KICAgIH5QZWxpY3VsYSwgICAgICAgICAgICAgICAgICAgICAgICAgICB+UHJvZHVjdG9yYSwgICB+TWlsbERvbFJlYywgIH5NZXNFc3RyZW5vLCAgIA0KCSJBdmVuZ2Vyc19JbmZpbml0eV9XYXIiLCAgICAgICAgICAgICAgICAgCSJEaXNuZXkiLCAgICAgICAgICAxNC43LCAgICAgICJBYnJpbCIsICAgDQogICJJbmNyZWRpYmxlc18yIiwJICAgICAgICAgICAgICAgICAgICAgICAgIkRpc25leSIsICAgICAgICAgICA4LjksCSAgICAiSnVuaW8iLCAgICANCgkiSnVyYXNzaWNfV29ybGRfRmFsbGVuX0tpbmdkb20iLCAgICAgICAgICAgICAiVVBJIiwgICAgICAgICAgIDcuNywJICAgICJKdW5pbyIsICAgIA0KICAiSG90ZWxfVHJhbnN5bHZhbmlhXzNfU3VtbWVyX1ZhY2F0aW9uIiwJICAgICJTb255IiwJICAgICAgICAgIDYuNSwJICAgICJKdWxpbyIsICAgIA0KCSJEZWFkcG9vbF8yIiwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJGb3giLCAgICAgICAgICAgNi4yLAkgICAgICJNYXlvIiwgICAgDQoJIkJsYWNrX1BhbnRoZXIiLCAgICAgICAgICAgICAgICAgICAgICAgICAgIkRpc25leSIsCSAgICAgICAgICA0LjksCSAgIkZlYnJlcm8iLCAgICANCgkiRmVyZGluYW5kIiwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRm94IiwJICAgICAgICAgIDMuNCwJICAgICJFbmVybyIsICAgIA0KCSJWZW5vbSIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNvbnkiLCAgICAgICAgICAgMi44LAkgICJPY3R1YnJlIiwgICAgDQoJIkFudC1NYW5fYW5kX3RoZV9XYXNwIiwgICAgICAgICAgICAgICAgICAgIkRpc25leSIsICAgICAgICAgICAyLjQsCSAgICAiSnVsaW8iLA0KICAiRmlmdHlfU2hhZGVzX0ZyZWVkIiwJICAgICAgICAgICAgICAgICAgICAgICAgIkFGIiwJICAgICAgICAgIDIuMywJICAiRmVicmVybyINCikNCmBgYA0KDQpgYGB7cn0NClBlbGljdWxhc19UYXF1aWxsZXJhc19DaGlsZV8yMDE4DQpgYGANCg0KIyMjTGEgaW1wb3J0YW5jaWEgZGUgdHJhYmFqYXIgY29uIERhdG9zIFRpZHkgZW4gcHJvZ3JhbWFzIGNvbW8gUiByYWRpY2EgZW4gcXVlIG5vIHNvbG8gZWwgb3JkZW4gZGUgbnVlc3Ryb3MgZGF0b3Mgbm9zIHBlcm1pdGUgY29tcHJlbmRlciBtZWpvciBsbyBxdWUgZXN0YW1vcyBoYWNpZW5kbywgc2lubyBlbiBxdWUgYWhvcnJhbW9zIHRpZW1wbyB5IHBvZGVtb3Mgc2FjYXIgdW4gbWVqb3IgcHJvdmVjaG8gZGUgbGFzIGhlcnJhbWllbnRhcyBkZSBlc3RhIGZvcm1hLiANCg0KIyMjUG9yIGVqZW1wbG8sIGFudGUgbGEgdGFyZWEgZGUgb3JkZW5lciBsYXMgcGVs7WN1bGFzIG3hcyBleGl0b3NhcyBlbiBDaGlsZSBlbiBsb3Mg+mx0aW1vcyB0cmVzIGHxb3MsIGFsIG9yZGVuYXIgbG9zIGRhdG9zIG1lZGlhbnRlIGxhIG1pc21hIGzzZ2ljYSBUaWR5LCB2aXN0YSBhbnRlcmlvcm1lbnRlLCBSIG5vcyBwZXJtaXRlIHZpc3VhbGl6YXIgZW4gcHJpbWVyYSBpbnN0YW5jaWEgZWwgcHJlZG9taW5pbyBkZWwgZXN0dWRpbyBEaXNuZXkgZW4gZWwgbWVyY2FkbyBuYWNpb25hbC4NCg0KYGBge3J9DQoNClBlbGljdWxhc19UYXF1aWxsZXJhc19DaGlsZV8yMDE2X0FfMjAxOCA8LSAgdHJpYmJsZSAoDQogIA0KICAgIH5QZWxpY3VsYSwgICAgICAgICAgICAgICAgICAgICAgICAgICB+UHJvZHVjdG9yYSwgICAgfk1pbGxEb2xSZWMsICB+TWVzRXN0cmVubywgICAgfkHxbywNCgkiQXZlbmdlcnNfSW5maW5pdHlfV2FyIiwgICAgICAgICAgICAgICAgIAkiRGlzbmV5IiwgICAgICAgICAgIDE0LjcsICAgICAgIkFicmlsIiwgICAgMjAxOCwNCiAgIkluY3JlZGlibGVzXzIiLAkgICAgICAgICAgICAgICAgICAgICAgICAiRGlzbmV5IiwgICAgICAgICAgICA4LjksCSAgICAgIkp1bmlvIiwgICAgMjAxOCwNCgkiSnVyYXNzaWNfV29ybGRfRmFsbGVuX0tpbmdkb20iLCAgICAgICAgICAgICAiVVBJIiwgICAgICAgICAgICA3LjcsCSAgICAgIkp1bmlvIiwgICAgMjAxOCwNCiAgIkhvdGVsX1RyYW5zeWx2YW5pYV8zX1N1bW1lcl9WYWNhdGlvbiIsCSAgICAiU29ueSIsCSAgICAgICAgICAgNi41LAkgICAgICJKdWxpbyIsICAgIDIwMTgsDQoJIkRlYWRwb29sXzIiLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkZveCIsICAgICAgICAgICAgNi4yLAkgICAgICAiTWF5byIsICAgIDIwMTgsDQoJIkJsYWNrX1BhbnRoZXIiLCAgICAgICAgICAgICAgICAgICAgICAgICAgIkRpc25leSIsCSAgICAgICAgICAgNC45LAkgICAiRmVicmVybyIsICAgIDIwMTgsDQoJIkZlcmRpbmFuZCIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkZveCIsCSAgICAgICAgICAgMy40LAkgICAgICJFbmVybyIsICAgIDIwMTgsDQoJIlZlbm9tIiwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU29ueSIsICAgICAgICAgICAgMi44LCAgICAiT2N0dWJyZSIsICAgIDIwMTgsDQoJIkFudC1NYW5fYW5kX3RoZV9XYXNwIiwgICAgICAgICAgICAgICAgICAgIkRpc25leSIsICAgICAgICAgICAgMi40LAkgICAgICJKdWxpbyIsICAgIDIwMTgsDQogICJGaWZ0eV9TaGFkZXNfRnJlZWQiLAkgICAgICAgICAgICAgICAgICAgICAgICAiQUYiLAkgICAgICAgICAgIDIuMywJICAgIkZlYnJlcm8iLCAgICAyMDE4LA0KICAiQ29jbyIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRGlzbmV5IiwgICAgICAgICAgIDEwLjAsICAiTm92aWVtYnJlIiwgICAgMjAxNywNCiAgIkRlc3BpY2FibGVfTWVfMyIsICAgICAgICAgICAgICAgICAgICAgICAgICAgIlVQSSIsICAgICAgICAgICAgNy4zLCAgICAgICJKdW5pbyIsICAgIDIwMTcsDQogICJUaGVfRmF0ZV9vZl90aGVfRnVyaW91cyIsCSAgICAgICAgICAgICAgICAgIlVQSSIsICAgICAgICAgICAgNi45LCAgICAgICJBYnJpbCIsICAgIDIwMTcsDQogICJNb2FuYSIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJEaXNuZXkiLCAgICAgICAgICAgIDUuMywgICAgICAiRW5lcm8iLCAgICAyMDE3LA0KICAiU3Rhcl9XYXJzX1RoZV9MYXN0X0plZGkiLCAgICAgICAgICAgICAgICAiRGlzbmV5IiwJICAgICAgICAgICA0LjksICAiRGljaWVtYnJlIiwgICAgMjAxNywNCiAgIkJlYXV0eV9hbmRfdGhlX0JlYXN0IiwJICAgICAgICAgICAgICAgICAgIkRpc25leSIsICAgICAgICAgICAgNC44LCAgICAgICJNYXJ6byIsICAgIDIwMTcsIA0KICAiVGhlX0Jvc3NfQmFieSIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRm94IiwJICAgICAgICAgICA0LjYsICAgICAgIk1hcnpvIiwgICAgMjAxNywJDQogICJKdW1hbmppX1dlbGNvbWVfdG9fdGhlX0p1bmdsZSIsICAgICAgICAgICAJIlNvbnkiLCAgICAgICAgICAgIDQuNiwgICJEaWNpZW1icmUiLCAgICAyMDE3LA0KICAiU3BpZGVyLU1hbl9Ib21lY29taW5nIiwgICAgICAgICAgICAgICAgICAgICJTb255IiwgICAgICAgICAgICA0LjMsCSAgICAgIkp1bGlvIiwgICAgMjAxNywNCiAgIlBpcmF0ZXNfb2ZfdGhlX0NhcmliYmVhbl9ELk0uVC5OLlQiLCAgICAgIkRpc25leSIsICAgICAgICAgICAgNC4xLCAgICAgICAiTWF5byIsICAgIDIwMTcsDQoJIkljZV9BZ2VfQ29sbGlzaW9uX0NvdXJzZSIsICAgICAgICAgICAgICAgICAgIkZveCIsICAgICAgICAgICAgNy41LCAgICAgICJKdWxpbyIsICAgIDIwMTYsDQoJIkZpbmRpbmdfRG9yeSIsCSAgICAgICAgICAgICAgICAgICAgICAgICAgIkRpc25leSIsICAgICAgICAgICAgNy4wLCAgICAgICJKdW5pbyIsICAgIDIwMTYsDQoJIkNhcHRhaW5fQW1lcmljYTpDaXZpbF9XYXIiLCAgICAgICAgICAgICAgIkRpc25leSIsICAgICAgICAgICAgNi43LCAgICAgICJBYnJpbCIsICAgIDIwMTYsDQoJIlRoZV9TZWNyZXRfbGlmZV9vZl9QZXRzIiwJICAgICAgICAgICAgICAgICAiVVBJIiwJICAgICAgICAgICA2LjAsICAgICAgIkp1bGlvIiwgICAgMjAxNiwNCgkiQmF0bWFuX1ZTX1N1cGVybWFuOkRhd25fb2ZfSnVzdGljZSIsICAgICAgICAgIldCIiwJICAgICAgICAgICA1LjEsICAgICAgIk1hcnpvIiwgICAgMjAxNiwJDQoJIlRoZV9KdW5nbGVfQm9vayIsCSAgICAgICAgICAgICAgICAgICAgICAiRGlzbmV5IiwJICAgICAgICAgICA0LjcsICAgICAgIkFicmlsIiwgICAgMjAxNiwNCgkiU2luX0ZpbHRybyIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibi9hIiwgICAgICAgICAgICA0LjQsICAgICAgIkVuZXJvIiwgICAgMjAxNiwNCgkiWm9vdG9waWEiLAkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRGlzbmV5IiwgICAgICAgICAgICA0LjIsICAgICJGZWJyZXJvIiwgICAgMjAxNiwNCgkiRGVhZHBvb2wiLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRm94IiwgICAgICAgICAgICA0LjIsICAgICJGZWJyZXJvIiwgICAgMjAxNiwNCgkiU2luZyIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVVBJIiwgCSAgICAgICAgIDMuNSwgICJEaWNpZW1icmUiLCAgICAyMDE2DQoJDQoJDQoJKQ0KYGBgDQoNCmBgYHtyfQ0KUGVsaWN1bGFzX1RhcXVpbGxlcmFzX0NoaWxlXzIwMTZfQV8yMDE4DQpgYGANCg0KIyMjQWwgbWFuZWphciBncmFuZGVzIHNldHMgZGUgZGF0b3MgZW4gcHJvZ3JhbWFzIGNvbW8gUiBlbCB1c28gZGVsIFRpZHkgRGF0YSBzZSB2dWVsdmUgZnVuZGFtZW50YWwgcGFyYSBjb25zZWd1aXIgbnVlc3RybyBvYmpldGl2byBkZSBwcmVzZW50YXIgbGEgbWVqb3IgaW5mb3JtYWNp824gZGUgbGEgbWFuZXJhIG3hcyBzZW5jaWxsYSBwb3NpYmxlIHkgb2J0ZW5lciBudWV2b3MgZGF0b3MgZ3JhY2lhcyBhbCB1c28gZGUgbGFzIGRpc3RpbnRhcyBmdW5jaW9uZXMgZGUgUi4gVW5hIGRlIGxhcyBoZXJyYW1pZW50YXMgcXVlIHBvZGVtb3MgdXNhciBwYXJhIGVsbG8gc29uIGxvcyB2ZXJib3MgZGUgbWFuaXB1bGFjafNuIHF1ZSB2aWVuZW4gaW5jbHVpZG9zIGVuIGVsIHBhcXVldGUgZGUgZGV0b3MgZGUgKipkcGx5cioqDQoNCiMjI1BvciBlamVtcGxvLCByZXRvbWFuZG8gbGEgdGFibGEgYW50ZXJpb3IgZGUgbGFzIHBlbO1jdWxhcyBt4XMgdGFxdWlsbGVyYXMgZGUgQ2hpbGUgZW50cmUgMjAxNiB5IDIwMTgsIHBvZGVtb3MgdXNhciBsYSBmdW5jafNuICoqZmlsdGVyKiogcGFyYSB0b21hciBjaWVydG9zIGRhdG9zIHF1ZSBzb24gZGUgbnVlc3RybyBpbnRlculzLg0KDQpgYGB7cn0NClBlbGljdWxhc0Rpc25leTIwMTZfQV8yMDE4IDwtIGZpbHRlcihQZWxpY3VsYXNfVGFxdWlsbGVyYXNfQ2hpbGVfMjAxNl9BXzIwMTgsIFByb2R1Y3RvcmEgPT0gIkRpc25leSIpDQpgYGANCg0KYGBge3J9DQpQZWxpY3VsYXNEaXNuZXkyMDE2X0FfMjAxOA0KYGBgDQoNCiMjI0VuIGVzdGUgY2FzbywgY29tbyBjb24gZmlsdGVyIHBvZGVtb3MgdmVyIGRhdG9zIGVzcGVjaWZpY29zIHF1ZSBjdW1wbGFuIGNpZXJ0YXMgY29uZGljaW9uZXMsIGFj4SB0b21hbW9zIGxvcyBkYXRvcyBkZWwgZXN0dWRpbyBEaXNuZXkgZW4gZWwgYfFvIDIwMTcuDQoNCiMjI0VzdG8sIGVudHJlIG90cmFzLCBjb3NhcyBub3MgcGVtdGly4SB2ZXIgY/NtbyBsZSBmdWUgbGFzIHByb2R1Y2Npb25lcyBkZWwgZXN0dWRpbyBkZW50cm8gZGUgbGFzIHBlbO1jdWxhcyBt4XMgcG91bGFyZXMgZW4gQ2hpbGUgZW4gZWwgYfFvIDIwMTcuDQoNCmBgYHtyfQ0KZmlsdGVyKFBlbGljdWxhc19UYXF1aWxsZXJhc19DaGlsZV8yMDE2X0FfMjAxOCwgUHJvZHVjdG9yYSA9PSAiRGlzbmV5IiwgQfFvID09IDIwMTcpDQpgYGANCg0KIyMjT3RyYSBmdW5jafNuIHF1ZSBwb2RlbW9zIHV0aWxpemFyIHBhcmEgc2FjYXIgZWwgbeF4aW1vIHByb3ZlY2hvIGEgbG9zIGRhdG9zIG9yZGVuYWRvcyBzZWf6biBsb3MgY3JpdGVyaW9zIGRlIFRpZHkgZXMgKipuYW1lcyoqLCBxdWUgbm9zIHBlcm1pdGUgY29ub2NlciBsYXMgdmFyaWFudGVzIHF1ZSBleGlzdGVuIGVuIG51ZXN0cmEgdGFibGEuDQoNCmBgYHtyfQ0KbmFtZXMoUGVsaWN1bGFzX1RhcXVpbGxlcmFzX0NoaWxlXzIwMTZfQV8yMDE4KQ0KYGBgDQoNCiMjI0VuIHVuYSBs7W5lYSBzaW1pbGFyIHBvZGVtb3Mgc2VndWlyIGV4cGxvcmFuZG8gbnVlc3RyYSBUaWR5IERhdGEgY29uIGxhIGZ1bmNp824gKipzZWxlY3QqKiwgbGEgY3VhbCBub3MgcGVybWl0ZSB2ZXIgdmFyaWFudGVzIGVzcGVj7WZpY2FzLiANCg0KIyMjUG9yIGVqZW1wbG8sIGVuIGVzdGUgY2FzbywgdW5hIHZhcmlhYmxlIGVzcGVj7WZpY2Egc2Vy7WEgZWwgbW9udG8gcmVjYXVkYWRvIHBvciBjYWRhIHBlbO1jdWxhLCB5YSBxdWUgZXMgdW4gdmFsb3IgcHJlc2VudGUgY29uIGRpc3RpbnRhcyBjaWZyYXMgZW4gY2FkYSBwcm9kdWNjafNuLg0KDQpgYGB7cn0NCnNlbGVjdChQZWxpY3VsYXNfVGFxdWlsbGVyYXNfQ2hpbGVfMjAxNl9BXzIwMTgsIFBlbGljdWxhLCBNaWxsRG9sUmVjKQ0KYGBgDQoNCiMjI0RlbnRybyBkZSBlc3RhIG1pc21hIGZ1bmNp824gcG9kZW1vcyBvcmdhbml6YXIgbeFzIGH6biBudWVzdHJhIGluZm9ybWFjafNuIHNpIHBvbmVtb3MgIi0iICBsdWVnbyB1bmEgdmFyaWFudGUsIGxvIHF1ZSBwZXJtaXRpcuEgcXVlIGVuIG51ZXN0cmEgdGFibGEgYXByZXpjYW4gdG9kYXMgbGFzIHZhcmllbnRlcyBtZW5vcyBlc2EuDQoNCiMjI1BhcmEgZWZlY3RvcyBkZSBlc3RlIGVqZW1wbG8gZGVjaWRpbW9zIHByZXNjaW5kaXIgZGVsIGHxbyBkZSBlc3RyZW5vIGRlIGxhcyBwZWztY3VsYXMuDQpgYGB7cn0NCnNlbGVjdChQZWxpY3VsYXNfVGFxdWlsbGVyYXNfQ2hpbGVfMjAxNl9BXzIwMTgsIC1B8W8pDQpgYGANCg0KIyMjU2lndWllbmRvIGNvbiBzZWxlY3QgeSBzdXMgbfpsdGlwbGVzIG9wY2lvbmVzIHF1ZSBub3MgcGVybWl0ZW4gb3JnYW5pemFyIG51ZXN0cm9zIGRhdG9zLCB0YW1iaeluIHBvZGVtb3Mgb3JkZW5hciBsYXMgdmFyaWFibGVzIGRlIG51ZXN0cmEgdGlkeSBkYXRhIHNpIGVzY3JpYmltb3MgdG9kYXMgbGFzIHZhcmlhYmxlcyB5IGx1ZWdvIGxhcyBjYW1iaWFtb3MgZGUgbHVnYXIuDQoNCiMjI0FsZ28gcXVlIGVuIGxhIHNpZ3VpZW50ZSB0YWJsYSBleHBsb3JhbW9zIG1vdmllbmRvIGVsIGHxbyBkZSBlc3RyZW5vIGRlc2RlIGVsIGNvc3RhZG8gZGVyZWNobyBhbCBpenF1aWVyZG8uDQoNCmBgYHtyfQ0Kc2VsZWN0KFBlbGljdWxhc19UYXF1aWxsZXJhc19DaGlsZV8yMDE2X0FfMjAxOCwgQfFvLCBQZWxpY3VsYSwgUHJvZHVjdG9yYSwgTWlsbERvbFJlYywgTWVzRXN0cmVubykNCmBgYA0KDQojIyNPdHJhIGZ1bmNp824gbXV5IPp0aWwgcGFyYSBzYWNhcmxlIHByb3ZlY2hvIGEgbnVlc3Ryb3MgRGF0b3MgVGlkeSBlcyAqKm11dGF0ZSoqLCBsYSBxdWUgbm9zIHBlcm1pdGUgY3JlYXIgbnVldmFzIGNhdGVnb3LtYXMgYSBwYXJ0aXIgZGUgbGFzIHlhIGV4aXN0ZW50ZXMuIA0KDQojIyNTaW4gZW1iYXJnbywgcG9yIGxhIG5hdHVyYWxlemEgZGUgbG9zIGRhdG9zIHF1ZSBoZW1vcyBleHBsb3JhZG8gaGFzdGEgYWhvcmEgcmVzcGVjdG8gYSBsYXMgcGVs7WN1bGFzIG3hcyB2aXN0YXMgZW4gQ2hpbGUsIGVzdGUgdmVyYm8gZGUgbWFuaXB1bGFjafNuIG5vIGVzIGNvbXBhdGlibGUgY29uIG51ZXN0cmEgdGFibGEgZGViaWRvIGEgcXVlIGxhcyB2YXJpZW50ZXMgZXhpc3RlbnRlcyBubyBwdWVkZW4gaW50ZXJhY3R1YXIgZW50cmUgc2kgcGFyYSBjcmVhciBvdHJhcyBudWV2YXMuDQoNCiMjI0VzdG8gY2xhcmFtZW50ZSBub3MgZGVtdWVzdHJhIGxhIGltcG9ydGFuY2lhIGRlIGxhICpUaWR5IERhdGEqIHlhIHF1ZSwgc2kgbm8gdHV2aWVyYW1vcyBudWVzdHJvcyBkYXRvcyBvcmRlbmFkb3MsIHBlcmRlcu1hbW9zIG51ZXN0cm8gdGllbXBvIGNyZWFuZG8gdW5hIHRhYmxhIHF1ZSBubyB0aWVuZSBzZW50aWRvIHkgc2Vy4SBkaWbtY2lsIGRlIGVudGVuZGVyLg0KDQojIyNQZXJvIHNpIGJpZW4gbm8gdG9kYXMgbGFzIGZ1bmNpb25lcyBzaXJ2ZW4gcGFyYSB0b2RvcyBsb3MgY2Fzb3MsIGFsdGVybmF0aXZhcyBjb21vICoqc3VtbWFyaXNlKiogc29uIGlkZWFsZXMgcGFyYSBjb21lbnphciBhIHByb2Nlc2FyIG51ZXN0cmEgaW5mb3JtYWNp824geWEgcXVlIGVzdGEgY2FyYWN0ZXLtc3RpY2Egbm9zIHBlcm1pdGUgdmVyIHBvciBlamVtcGxvLCBlbCBwcm9tZWRpbyBkZSB2YXJpYW50ZXMgeSBzdXMgdmFsb3JlcyBtYXhpbW9zIHkgbWluaW1vcywgZW50cmUgb3Ryb3MgZGF0b3MuIA0KDQojIyNQb3IgZWplbXBsbywgbm9zb3Ryb3MgZXNjb2dpbW9zIHZlciBsYSByZWNhdWRhY2nzbiBwcm9tZWRpbyB5IGxhIHJlY2F1ZGFjafNuIG3heGltYSBkZSBsYXMgcGVs7WN1bGFzIG3hcyB2aXN0YXMgZW4gQ2hpbGUgZW50cmUgMjAxNiB5IDIwMTguDQpgYGB7cn0NCnN1bW1hcmlzZShQZWxpY3VsYXNfVGFxdWlsbGVyYXNfQ2hpbGVfMjAxNl9BXzIwMTgsIFJlY2F1ZGFjafNuUHJvbWVkaW8gPSBtZWFuKE1pbGxEb2xSZWMpKQ0KYGBgDQpgYGB7cn0NCnN1bW1hcmlzZShQZWxpY3VsYXNfVGFxdWlsbGVyYXNfQ2hpbGVfMjAxNl9BXzIwMTgsIFJlY2F1ZGFjafNuTWF4aW1hID0gbWF4KE1pbGxEb2xSZWMpKQ0KYGBgDQoNCiMjI0F1bnF1ZSB0YW1iaeluIHBvZGVtb3MgdXNhciBsYSBmdW5jafNuIHBhcmEgdmVyIGRhdG9zIGNvbW8gZWwgbW9udG8gbeFzIGJham8gZGUgcmVjYXVkYWNpb24gZGUgbnVlc3RyYXMgbXVlc3RyYXMgbyBsYSBzdW1hIGRlIHRvZGFzIGxhcyBnYW5hbmNpYXMgZGUgbG9zIGZpbG1zIHF1ZSBoYXkgZW4gbnVlc3RyYSB0YWJsYS4NCg0KYGBge3J9DQpzdW1tYXJpc2UoUGVsaWN1bGFzX1RhcXVpbGxlcmFzX0NoaWxlXzIwMTZfQV8yMDE4LCBSZWNhdWRhY2nzbk1pbmltYSA9IG1pbihNaWxsRG9sUmVjKSkNCmBgYA0KDQpgYGB7cn0NCnN1bW1hcmlzZShQZWxpY3VsYXNfVGFxdWlsbGVyYXNfQ2hpbGVfMjAxNl9BXzIwMTgsIFJlY2F1ZGFjafNuVG90YWwgPSBzdW0oTWlsbERvbFJlYykpDQpgYGANCg0KIyMjT3RybyB2ZXJibyBkZSBtYW5pcHVsYWNp824gcXVlIHNlIHB1ZWRlIGFwbGljYXIgYSBsb3MgZGF0b3MgY29tbyBsbyBoYWNlICoqc3VtbWFyaXNlKiogZXMgKipncm91cF9ieSoqLCBxdWUgYuFzaWNhbWVudGUgcGVybWl0ZSBxdWUgbG9zIG90cm9zIHZlcmJvcyBkZSBtYW5pcHVsYWNp824gc2XxYWxhZG9zIGFudGVyaW9ybWVudGUgbm8gc29sbyB0cmFiYWplbiBzb2JyZSB2YXJpYWJsZXMsIHNpbm8gcXVlIHNlIGVqZWN1dGVuIGEgdHJhdulzIGRlIGRhdG9zIGNvbmNyZXRvcy4NCg0KIyMjQXPtLCBwb3IgZWplbXBsbywgc2kgYW50ZXJpb3JtZW50ZSB1c2Ftb3Mgc3VtbWFyaXNlIHBhcmEgc2FjYXIgZWwgcHJvbWVkaW8gZGUgbGFzIGdhbmFuY2lhcyBjb3NlY2hhZGFzIHBvciBsYXMgcGVs7WN1bGEsIGxvIHF1ZSBub3MgYXJyb2rzIGZ1ZSBlbCBwcm9tZWRpbyBkZSB0b2RvcyBsb3MgZGF0b3MgZGUgZXNhIHZhcmlhbnRlLiBFbiBjYW1iaW8gYWhvcmEsIGdyYWNpYXMgYSBncm91cF9ieSwgZWwgcHJvbWVkaW8gZGUgZ2FuYW5jaWFzIGZ1ZSBzZXBhcmFkbyBwb3IgYfFvLg0KDQpgYGB7cn0NClBvcl9B8W9zIDwtIGdyb3VwX2J5KFBlbGljdWxhc19UYXF1aWxsZXJhc19DaGlsZV8yMDE2X0FfMjAxOCwgQfFvKQ0KYGBgDQpgYGB7cn0NClBvcl9B8W9zDQpgYGANCg0KYGBge3J9DQpzdW1tYXJpc2UoUG9yX0Hxb3MsIFJlY2F1ZGFjafNuUHJvbWVkaW8gPSBtZWFuKE1pbGxEb2xSZWMpKQ0KYGBgDQoNCiMjIyBVbmEg+mx0aW1hIGZ1bmNp824gcXVlIG5vcyBwZXJtaXRlIHNhY2FyIGVsIG3heGltbyBwcm92ZWNobyBhIG51ZXN0cmEgVGlkeSBEYXRhIGVzICoqYXJyYW5nZSoqLCB1biB2ZXJibyBkZSBtYW5pcHVsYWNp824gcXVlIG9yZGVuYSBsYXMgdGFibGFzIHNlZ/puIGxhcyB2YXJpYW50ZXMgcXVlIHVubyBxdWllcmEuDQoNCiMjI0VuIGVzdGUgY2FzbyBkZWNpZGltb3Mgc2VwYXJhciBwcmltZXJvIHBvciBwZWztY3VsYXMgeSBwb3N0ZXJpb3JtZW50ZSBwb3IgcHJvZHVjdG9yYSB5IHBlbO1jdWxhLiBMbyBxdWUgbXVlc3RyYSBsYSB2ZXJzYXRpbGlkYWQgZGUgZXN0YSBmdW5jafNuLg0KYGBge3J9DQphcnJhbmdlKFBlbGljdWxhc19UYXF1aWxsZXJhc19DaGlsZV8yMDE2X0FfMjAxOCwgUGVsaWN1bGEpDQpgYGANCmBgYHtyfQ0KYXJyYW5nZShQZWxpY3VsYXNfVGFxdWlsbGVyYXNfQ2hpbGVfMjAxNl9BXzIwMTgsIFByb2R1Y3RvcmEsIFBlbGljdWxhKQ0KYGBgDQoNCiMjVmlzdWFsaXphY2nzbiBkZSBkYXRvcw0KDQojIyNUb2RvIGVsIG9yZGVuIGRlbCBUaWR5IERhdGEgcGxhc21hZG8gbWVkaWFudGUgbG9zIGRpc3RpbnRvcyB2ZXJib3MgZGUgbWFuaXB1bGFjafNuIGFkZW3hcyBub3MgcGVybWl0ZSBpZGVudGlmaWNhciBkaXN0aW50YXMgdmFyaWFibGVzIHF1ZSBzb24gZGUgbnVlc3RybyBpbnRlculzIHkgZ3JhZmljYXJsb3MgbWVkaWFudGVzIGZ1bmNpb25lcyBjb21vICoqZ2dwbG90MioqIGNvbiAqKmdlb21fYmFyKiouDQoNCiMjI2dlb21fYmFyIG5vcyBvZnJlY2UgdW4gZ3LhZmljbyBkZSBiYXJyYXMsIHF1ZSBlbiBlc3RlIGNhc28gbXVlc3RyYSBsYSBmcmVjdWVuY2lhIGRlIGVzdHJlbm9zIGRlIGxhcyBwZWztY3VsYXMgbeFzIHRhcXVpbGxlcmFzIGVuIENoaWxlIGVudHJlIDIwMTYgeSAyMDE4LiANCg0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gUG9yX01lc2VzICkgKw0KICBnZW9tX2JhcihtYXBwaW5nID0gYWVzKE1lc0VzdHJlbm8pKSArDQogICBsYWJzKA0KdGl0bGUgPSAiIENhdGlkYWQgZGUgZXN0cmVub3MgbGFzIHBlbGljdWxhcyBt4XMgdGFxdWlsbGVyYXMgZW4gQ2hpbGUgc2Vn+m4gY2FkYSBtZXMiLA0Kc3VidGl0bGU9IiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudHJlIDIwMTYgYSAyMDE4IiwNCmNhcHRpb24gPSAiRGF0b3MgZGUgd3d3LmJveG9mZmljZW1vam8uY29tICIsDQp4ID0gIk1lc2VzIiwNCnkgPSAiIENhbnRpZGFkIg0KDQopDQpgYGANCg0KIyMjUGVybyBnZW9tX2JhciBubyBlcyBsYSD6bmljYSBhbHRlcm5hdGl2YSBxdWUgZ2dwbG90MiBub3Mgb2ZyZWNlIHBhcmEgcHJlc2VudGFyIG51ZXN0cm9zIGRhdG9zLCB5YSBxdWUgbGEgZnVuY2nzbiB0YW1iaeluIGN1ZW50YSBjb24gKipnZW9tX3BvaW50KiosIHF1ZSBncmFmaWNhIGxvcyBkYXRvcyBtZWRpYW50ZSBwdW50b3MgY29tbyBxdWVkYSBjbGFybyBlbiBlbCBzaWd1aWVudGUgZ3LhZmljbyBzb2JyZSBsYXMgZ2FuYW5jaWFzIGRlIGxhcyBwcm9kdWN0b3JhcyBwb3IgbGFzIHBlbO1jdWxhcyBt4XMgcG9wdWxhcmVzIGVuIENoaWxlIGVudHJlIDIwMTYgeSAyMDE4Lg0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gUGVsaWN1bGFzX1RhcXVpbGxlcmFzX0NoaWxlXzIwMTZfQV8yMDE4KSArDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gUHJvZHVjdG9yYSAsIHkgPSBNaWxsRG9sUmVjDQogICAgICAgICAgICAgICAgICAgICAgICAgICAsIGNvbG91ciA9IGFzLmZhY3RvcihB8W8pKSkgKw0KICAgbGFicygNCnRpdGxlID0gIiBHYW5hbmNpYXMgZGUgcHJvZHVjdG9yYXMgcG9yIHN1cyBwZWxpY3VsYXMgbeFzIHRhcXVpbGxlcmFzIGVuIENoaWxlIiwNCnN1YnRpdGxlPSIgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRW50cmUgMjAxNiBhIDIwMTgiLA0KY2FwdGlvbiA9ICJEYXRvcyBkZSB3d3cuYm94b2ZmaWNlbW9qby5jb20gIiwNCnggPSAiUHJvZHVjdG9yYXMgZGUgUGVsaWN1bGFzIiwNCnkgPSAiIFJlY2F1ZGFjaW9uZXMgZGUgTWlsbG9uZXMgZGUgRG9sYXJlcyIsDQpjb2xvdXIgPSAiQfFvIg0KKQ0KYGBgDQoNCiMjI1NpZ3VpZW5kbyBlc2UgbWlzbW8gZWplbXBsbywgdGFtYmnpbiBwb2RlbW9zIHZlciBj821vIGZ1bmNpb25hICoqZ2VvbV9oaXN0b2dyYW0qKiwgb3RyYSBoZXJyYW1pZW50YSBkZSBnZ3Bsb3QyIHF1ZSBwZXJtaXRlIGdyYWZpY2FyIGxvcyBtaXNtbyBkYXRvcyBxdWUgbGEgdGFibGEgYW50ZXJpb3IsIHBlcm8gZW4gZWwgZm9ybWF0byBkZSB1biBoaXN0b2dyYW1hLiBBZGVt4XMsIGdyYWNpYXMgYSBsYSBmdW5jafNuIGZhY2V0X1dyYXAoKSBzZSBmb3JtYW4gZ3LhZmljb3MgY29tcGFyYXRpdm9zLCBlbiBlc3RhIGNhc28sIGRpdmllbmRvIGxhIGluZm9ybWFjafNuIHBvciBjYWRhIGHxby4gDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBQZWxpY3VsYXNfVGFxdWlsbGVyYXNfQ2hpbGVfMjAxNl9BXzIwMTgpICsNCiAgZ2VvbV9oaXN0b2dyYW0obWFwcGluZyA9IGFlcyh4ID0gTWlsbERvbFJlYywgZmlsbCA9IFByb2R1Y3RvcmEpLA0KICAgICAgICAgICAgICAgICBjb2xvdXIgPSAiYmxhY2siKSArDQogIHNjYWxlX2ZpbGxfdmlyaWRpc19kKCkgKw0KICBmYWNldF93cmFwKH5B8W8pICsNCiAgIGxhYnMoDQp0aXRsZSA9ICJDb21wYXJhY2nzbiBkZSBsYSBjYW50aWRhZCBnZW5lcmFkYSBkZSBnYW5hbmNpYXMgcG9yIGxhcyBwcm9kdWN0b3Jhcw0KICAgICAgICAgICAgICAgICAgIHBvciBjYWRhIHVuYSBkZSBzdXMgcGVsaWN1bGFzIG3hcyB0YXF1aWxsZXJhcyBlbiBDaGlsZSIsDQpzdWJ0aXRsZT0iICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEVudHJlIDIwMTYgYSAyMDE4IiwNCmNhcHRpb24gPSAiRGF0b3MgZGUgd3d3LmJveG9mZmljZW1vam8uY29tICIsDQp4ID0gIk1pbGxvbmVzIGRlIERvbGFyZXMiLA0KeSA9ICJDYW50aWRhZCIsDQpjb2xvdXIgPSAiUHJvZHVjdG9yYSINCikNCmBgYA0KDQojIyNBIGxhIGx1eiBkZSB0b2RhcyBlc3RhcyBwb3NpYmxpZGFkZXMgcGFyYSBwcmVzZW50YXIgZW4gZGlzdGludGFzIGZvcm1hcyB5IGVzdHJ1Y3R1cmFzIHVuIGNvbmp1bnRvIGRlIGRhdG9zIHVuYSB2ZXogcXVlIGVzIG9yZGVuYWRvIGJham8gbG9zIHByaW5jaXBpb3MgVGlkeSwgZXMgcG9zaWJsZSBjb21wcmVuZGVyIGxhIGltcG9ydGFuY2lhIGRlbCBvcmRlbiBwYXJhIGVsIHRyYWJham8gY29uIGRhdG9zLg0KDQojIyMgTm8gc29sbyBwb3JxdWUsIGNvbW8gcGxhbnRlYSBXaWNraGFtLCBlbCBvcmRlbiBwZXJtaXRlIGVzdHJ1Y3R1cmFyIG1lam9yIG51ZXN0cm8gdHJhYmFqbywgc2lubyBwb3JxdWUgdGFtYmnpbiBub3MgcGVybWl0ZSBzYWNhcmxlIGVsIG3heGltbyBwcm92ZWNobyBhIG51ZXN0cmEgaW5mb3JtYWNp824geSB1dGlsaXphciB0b2RhcyBsYXMgZnVuY2lvbmVzIGRlIFIgcGFyYSwgcG9yIGVqZW1wbG8sIGNvbnRhciB1bmEgaGlzdG9yaWEgYSBwYXJ0aXIgZGUgdW4gdHJhYmFqbyBhIGJhc2UgZGUgZGF0b3MuIA0K