En esta clase nos enfocaremos en agregar a nuestra caja de herramientas funciones para manipular dataframes (data rectangular) provenientes del paquete dplyr. Utilizaremos de ejemplo principalmente los datos que vienen en el objeto gapminder pertenecientes al paquete que lleva el mismo nombre.

Lo primero que haremos será cargar los paquetes que utilizaremos en nuestro análisis.

# Cargamos nuestras aplicaciones (paquetes).
library(dplyr)   # funciones (verbos) para manipular dataframes.
library(gapminder)  # paquete que tiene la data con que trabajaremos.

Algunos puntos antes de partir

Antes de comenzar, repasemos algunos puntos para asegurarnos de que todos nos encontramos hablando en los mismos t?rminos.

  1. Estructura de datos: en el contexto de programación es como representamos la información. Hasta ahora solo hemos visto la estructura llamada data rectangular que la conocemos como dataframes o tibbles. Un ejemplo de este tipo de estructura de datos ser? el siguiente dataframe:
  1. Dataframe: es el nombre formal de la estructura de datos que representa la data rectangular en el lenguaje de programación R. Por dataframe nos referimos simplemente a columnas que representan variables y filas que representan observaciones. En el ejemplo anterior, cada observación representa la nota de uno de mis ramos. Además hablamos de tibbles como término equivalente a dataframe, pero destacaremos una sola diferencia entre ambos, un tibble es más agradable de visualizar que un dataframe tradicional en la consola. En la clase pasada vimos las siguientes formas para crear data rectangular en R:
# Para crear un tibble por columnas.
notas <- tibble(
                ramo = c("Mate", "Lenguaje", "Danza"),
                notas = c(5.2,      3.9,         5.5)
                )


# Para crear un tibble por filas, ¡OJO! acá la función es tribble() con r.
# Vamos creando la data en orientación fila y especificamos los nombres de las
# columnas anteponiendo una cola de chancho ~ (alt + 126 en teclado 
# númerico)
notas <- tribble(
                  ~ramo,   ~ notas,
                  #---------------    # <- No es necesario escribir este comentario
                  "Mate",      5.2,   #    en el código, es para mostrar la
                  "Lenguaje",  3.9,   #    separaci?n del nombre de las columnas
                  "Danza",     5.5    #    con respecto a las observaciones.
)

# Fomra tradicional de crear un dataframe en R, la mécanica es equivalente
# a tibble() pero hay que forzar a que los caracteres sean tratados como
# tal y no como variable tipo "factor", especificando de esta forma el argumento 
# 'stringsAsFactors = FALSE'. En cambio, tibble() por defecto representan a los 
# caracteres como variable tipo "chr".
notas <- data.frame(
                ramo = c("Mate", "Lenguaje", "Danza"),
                notas = c(5.2,      3.9,         5.5),
                stringsAsFactors = FALSE
)

# Ahora en los tres casos anteriores, creamos una datarectangular y le asignamos
# al objeto que representa a esta, el nombre de "notas". Si queremos llamar
# o visualizar nuestra data en la consola, tenemos que llamar al objeto por
# su nombre de la siguiente manera: 
notas
  1. Con respecto al código escrito arriba, destacar:
notas<-data.frame(ramo=c("Mate","Lenguaje","Danza"),notas=c(5.5,3.9,5.5),stringsAsFactors=FALSE)
  1. Cuando hablamos de herramientas que nos entrega un paquete, estamos hablando en el contexto de programación de funciones . La forma útil de pensar en una función es como una caja negra que le entregamos algo (input) y nos devuelve un resultado (output) en base a lo entregado. Si queremos saber que debemos entregarle a esta caja negra, podemos leer la documentación dentro de R que viene con información acerca de como usar y qué entregarle y/o especificarle a la función. Para esto debemos escribir ? inmediatamente seguido del nombre de la función en la consola como se muestra a continuación de este parrafo y se desplegará la documentación respectiva en uno de los cuadrantes. Lo importante con respecto a las funciones es que nos fuerzan a interactuar a traves de una interface para realizar una operación, evitando entrar en los detalles especificos de lo que ocurré por debajo, es por esto que la comparamos con una caja negra ya que no podemos observar lo que ocurré en su interior. Este concepto en programación se conoce como abstracción.
# Para consultar la documentación de la función tribble() dentro de R.
?data.frame

Los verbos de la manipulación

Nos referiremos por verbos de la manipulación a un conjunto de funciones pertenecientas al paquete dyplr que ejecutan una acción especifica sobre un dataframe y nos entregan un dataframe modificado como resultado.

Empezaremos explorando de forma individual cada uno de los verbos detallados a continuación y al final mostraremos como podemos componer operaciones más complejas sobre nuestros datos al juntar más de uno de estos verbos.

filter, para filtrar observaciones

Partamos con una operación a la que ya fuimos expuestos cuando realizamos el gráfico de burbujas. Estamos interesados solo en las observaciones de la data gapminder que tienen registros de paises pertenecientes al continente de America. Este tipo de tarea es ideal para la función filter(), podemos obtener subconjuntos de observaciones basados en los valores de estos.

filter(gapminder, continent == "Americas")

Reflexionemos un poco sobre la línea de código de arriba, el primer argumento de la función filter(), es decir, lo primero que especificamos dentro de la función es el nombre del objeto que representa nuestra data rectangular gapminder. Luego, encontramos la siguiente expresión continent == "Americas", que nos referiremos a este tipo de expresiones como condiciones lógicas.

Una condición lógica es una proposición que su resultado puede tener dos posibles valores: verdadero o falso.

Muchas de las condiciones lógicas se construyen con los operadores de relación, en las que se relaciona una variable con un valor. En el lenguaje de programación R los operadores de relación se especifican de la siguiente manera:

  • ==: Igualdad.
  • !=: No igualdad.
  • >: Mayor que.
  • <: Menor que.
  • >=: Mayor o igual que.
  • <=: Menor o igual que.

En el caso de nuestra condición lógica, queremos solo las observaciones de la data gapminder en que la relación continent == "Americas" sean evaluadas con valor verdadero. En otras palabras, no nos interesa el resto de las observaciones que pertencen a otros continentes para formar este subconjunto de datos.

filter(gapminder, continent = "Americas")
Error: `continent` (`continent = "Americas"`) must not be named, do you need `==`?

¡Ojo! un error común es utilizar = en vez de == para crear la relación de igualdad. Acá estaríamos tratando de asignar el valor "Americas" a la variable continent, cuando en realidad queremos generar una relación de igualdad, es decir utilizar el operador de relación ==.

Los operadores de relación >, <, >= y <= son utilizados para crear condiciones lógicas con variables númericas o con variables que no son númericas pero pueden ser representadas de alguna forma númerica.

# Ejemplo de una variable que no es n?merica pero puede
# tomar una representaci?n n?merica v?lida. TRUE = 1, FALSE = 0
c(TRUE, FALSE, TRUE, FALSE, FALSE) > 0
[1]  TRUE FALSE  TRUE FALSE FALSE

Un aspecto práctico de la sintaxis de la función filter(), y el resto de los verbos que veremos, es que las variables de nuestro dataframe en que hacemos referencia dentro de los argumentos, no deben ser rodeados de comillas. Por ejemplo, el nombre de la variable en la condición lógica continent == "Americas" no lleva comillas. Sin embargo, el valor de las observaciones que deseamos filtrar de la variable continent si va entre comillas "Americas".

Podemos agregar más de un argumento expresando una condición lógica en la función filter(). Por ejemplo, queremos obtener solo información de los países del continente americano sobre el año 2000.

filter(gapminder, continent == "Americas", year > 2000)

Lo relevante cuando ocupamos más de un argumento con condiciones lógicas dentro de filter(), es que cada expresión que va separada por una coma, se une con el operador lógico conocido como & (AND). Esto significa que nos entregará las observaciones que cumplan las siguientes dos condiciones simultaneamente:

  1. continent == "Americas"
  2. year > 2000.

Como podemos observar del resultado que nos entrega el código, no hay observaciones que sean year > 2000 pero que no pertenezcan al continente americano, o viceversa, no hay observaciones que pertenezcan continent == "Americas" pero que daten igual o menor al año 2000.

Existen tambien los operadores lógicos:

  • !: negación, se antepone en una condición lógica para invertir su valor.
  • &: “y” lógico, equivalente agregar más de un argumento en filter.
  • |: “?” lógico, sí se cumple alguna de las condiciones.

Si quisieramos obtener todas las observaciones que no sean del continente americano, podriamos negar la condición lógica continent == "Americas", invirtiendo el signo a FALSE cuando las observaciones pertenezcan al continente “Americas” y a TRUE cuando sean distintas de “Americas”, esto anteponiendo el operador lógico ! de la siguiente forma:

# Invertir el signo de la evaluación de la condición lógica con "!".
filter(gapminder, !(continent == "Americas"))

El operador & es equivalente cómo se mencionó anteriormente a enumerar más de una condición lógica en los argumentos de la función filter.

# Las dos formas de uso son equivalentes:
filter(gapminder, continent == "Americas", year > 2000)
filter(gapminder, continent == "Americas" & year > 2000)

En cambio, el operador lógico | (OR), no puede ser empleado enumerando condiciones lógicas en los argumentos de filter. Se debe hacer uso explicito de este operador, por ejemplo, si quisieramos las observaciones pertenecientes al continente americano o asiatico, es una buena oportunidad para ocupar | en uno de los argumentos de filter:

filter(gapminder, continent == "Americas" | continent == "Asia")

Observemos que la condición lógica continent == "Americas" | continent == "Asia" va en un solo argumento dentro de filter, no hay comas entremedio y además se debe especificar el nombre de la variable en cada uso del operador de igualdad ==. Los siguientes usos serían una forma incorrecta de aplicar el operador |:

# Mal uso del operador |.
filter(gapminder, continent == "Americas" | "Asia") 
# Esto equivale al operador & y no al operador |. De hecho, una observación
# no puede tener el valor "Americas" y "Asia" al mismo tiempo.
filter(gapminder, continent == "Americas", continent == "Asia")

Un último punto con respecto a la función filter y las condiciones lógicas es el uso del operador %in%. Para ilustrar las bondades de este nuevo operador, describamos el caso tedioso en que deseamos filtrar las observaciones que pertenezcan al continente americano o asiático o europeo. Según lo discutido anteriormente, esto equivaldría a emplear la condición lógica continent == "Americas" | continent == "Asia" | continent == "Europe" dentro de la función filter:

filter(gapminder, continent == "Americas" | continent == "Asia" | continent == "Europe")

El operador %in% nos permitira escribir la operación anterior de la siguiente forma:

filter(gapminder, continent %in% c("Americas", "Asia", "Europe"))

Este operador evalúa en cada observación de gapminder, se el valor de la variable continent se encuentra en alguno de los elementos del vector definido como c("Americas", "Asia", "Europe"). Por ahora, basta con entender que un vector es simplemente un conjunto de elementos del mismo tipo, en este caso, todos los elementos son un carácter.

Muchas veces es útil combinar el operador de negación ! junto a la condición lógica compuesta por el operador %in% de la siguiente forma:

# Filtrar todas las observaciones que no esten en los siguientes continentes:
filter(gapminder, !(continent %in% c("Americas", "Asia", "Europe")))

select: seleccionar variables por su nombre

El verbo select es más simple de entender. La acción que ejecuta sobre un dataframe es la de seleccionar variables por su nombre. Al igual que filter, el nombre de las variables no debe ir rodeado por comillas.

Veamos el nombre de las variables contenidas en gapminder.

names(gapminder)
[1] "country"   "continent" "year"      "lifeExp"   "pop"      
[6] "gdpPercap"

Imaginemos que de la tabla gapminder solo nos interesan las variables country, year y lifeExp.

select(gapminder, country, year, lifeExp)

Esto que es una simple selección, muchas veces es la implementación de una simple técnica que es focalizar el análisis en una dimensión más reducida de los datos. Evidentemente el costo de disminuir la complejidad de nuestros datos descartando variables es el de la pérdida de información.

Podemos utilizar select para descartar variables, esto anteponiendo un signo - en el nombre de la variable a descartar.

# Todas las variables menos lifeExp.
select(gapminder, -lifeExp)

Una forma rápida para evitar tipear el nombre de muchas variables, es crear rangos de selección en variables que se quieren seleccionar y se encuentran de forma continua en la tabla. Por ejemplo, en gapminder sí quisiera escoger las variables year a gdpPercap podr?amos escribir esta selección por rango como year:gdpPercap.

# Seleccionar las variables que se encuentran entre year y gdpPercap inclusive.
select(gapminder, year:gdpPercap)

Otros uso de la función select es para reacomodar el orden de las variables. A veces, esto puede ser tedioso sí solo quisieramos mover la variable year a la primera columna y dejar el resto de las variables con el mismo orden. Esto implicaría escribir el siguiente código:

select(gapminder, year, country, continent, lifeExp, pop, gdpPercap)

La existencia de la función auxiliar everything para usar en conjunto con select facilita este tipo de tarea al realizar la misma operación de forma más concisa:

# Debemos incluir los parentesis para llamar a la funci?n everything()!
select(gapminder, year, everything())

Existen más funciones auxiliares que son convenientes de usar en conjunto con select como:

  • starts_with("prefijo"): seleccionar variables que compartan igual prefijo.
  • ends_with("sufijo"): seleccionar variables que compartan igual sufijo.
  • contains("patron"): seleccionar variables que contengan un patrón común.

mutate: para crear nuevas variables

El verbo mutate nos permite crear una nueva variable en nuestro dataframe que se adjunta como columna al final de la tabla.

Ilustremos el uso de mutate creando la nueva variable popMillions en la tabla gapminder.

# Crear una variable con la poblaci?n en millones.
mutate(gapminder, popMillions = pop / 1e6) # 1e6 = 1000000

El ejemplo anterior es simplemente cambiar la unidad de medida de una variable ya existente. En caso de que conservar la variable original pop no nos interese, podemos sobreescribir esta directamente en la definición de mutate:

mutate(gapminder, pop = pop / 1e6)

Un ejemplo más interesante de mutate es el siguiente que involucra más de una variable de gapminder.

# Computar el PIB por cada observaci?n a partir del PIB per capita y la poblaci?n.
mutate(gapminder, gdp = pop * gdpPercap)

Otra caracteristica de mutate es que podemos crear más de una variable, incorporando cada creación en un nuevo argumento. Además, podemos utilizar variables nuevas que fueron creadas en algún argumento anterior en otro argumento dentro del mismo llamado de la función mutate.

mutate(gapminder, gdp = pop * gdpPercap,  # creo gdp primero
                  gdpMillion = round(gdp / 1e9, 2)) # ahora gdp en miles de millones

Podemos utilizar funciones en conjunto con mutate para crear las nuevas variables:

mutate(gapminder, pos_90 = ifelse(year > 1990, TRUE, FALSE))

Es importante entender que mutate esta diseñado para agregar nuevas variables a la tabla que se le entrega, por esto mismo, la variable creada debe ser del mismo tama?o que el resto de las variables. No se puede “descuadrar” la data rectangular, al tener una variable con más o menos observaciones que las variables restantes.

En línea con lo anterior, es importante tener presente lo qué pasa cuando hay una función involucrada en la creación de una nueva variable dentro de mutate, que devuelve menos valores de los que se le entregan. Es decir, le entrego una variable como gdpPercap que tiene 1704 observaciones y la función, que puede ser por ejemplo mean, me entrega un solo valor que es el promedio de estas 1704 observaciones que corresponde a 7215.327.

mutate(gapminder, avg_gdpPercap = mean(gdpPercap))

En el caso anterior, mutate recicla el valor 7215.327, repitiendo este tantas veces como número de filas tenga la tabla y así mantener la consistencia de la data rectangular.

summarise: para resumir valores

El verbo summarise funciona similar a mutate pero con el objetivo de crear variables resumenes. Estas se crean a partir de funciones que toman un grupo de valores y entregan un solo valor. Ejemplo de este tipo de funciones son:

  • count
  • sum
  • mean
  • median
  • sd
  • max
  • min

Un caso aplicado de summarise sobre gapminder puede ser el cálculo promedio de expectativa de vida.

summarise(gapminder, avgLifeExp = mean(lifeExp))

La sintaxis de summarise es símil a la de mutate, primero y como todos los verbos, damos el nombre de nuestra data rectangular. Segundo, escribimos el nombre de la nueva variable resumen (avgLifeExp) seguido de = y la operación o acción sobre variables ya existente en la data entregada (lifeExp). Tambien se pueden crear más de una variable resumen en un mismo llamado de la función summarise.

summarise(gapminder, 
          avgLifeExp = mean(lifeExp),
          numObs = n())

La función n() cuenta el número de observaciones en la tabla. En general, summarise tiene mayor utilidad en conjunto de group_by, como veremos más adelante.

group_by: para cambiar el dominio de acción de los verbos

¿Qué pasa sí queremos el promedio de lifeExp pero ahora por continente? ¿o filtrar observaciones que cumplan cierta condición lógica pero para cada uno de los distintos años (year) de nuestra data gapminder?

group_by será la pieza que actuará cambiando el dominio en que se ejecuta cada verbo. Respondamos la primera interrogante, necesitamos agrupar (group_by) por continente (continent) para ejecutar el verbo summarise y crear la variable expectativa de vida promedio (avgLifeExp).

# cambiamos el dominio de ejecución (o análisis) de los verbos
por_continente <- group_by(gapminder, continent)
# en vez de aplicar los verbos sobre gapminder, lo hacemos sobre
# por_continente
summarise(por_continente, avgLifeExp = mean(lifeExp))

Abordemos ahora una interrogante como la segunda planteada, digamos que queremos encontrar el país (country) con mayor expectativa de vida (lifeExp) por año (year).

por_periodo <- group_by(gapminder, year)
filter(por_periodo, lifeExp == max(lifeExp))

El filter aplicado sobre la data agrupada por_periodo, arrojó 12 observaciones. Podemos corroborar que nuestra operación estuvo correcta sí analizamos cuantos años diferentes hay en gapminder y para esto podemos utilizar otra función de dplyr llamada distinct.

distinct(gapminder, year)

Efectivamente, el verbo filter nos entrego para cada uno de los años contenidos (por_periodo) en la base gapminder, la observación con mayor expectativa de vida lifeExp.

arrange: para ordenar observaciones

A veces queremos ordenar nuestra data rectangular en base a una o más variables. Esto es útil para saber que observación es la menor o mayor con respecto alguna variable. Para este tipo de tareas es útil el verbo arrange.

Nos gustaría ordenar gapminder por la variable year.

arrange(gapminder, year)

Podemos incorporar otra variable para ordenar dentro de cada año. Ordenemos luego de year por lifeExp tambien en orden ascedente, es decir, de menos a mas en caso de lifeExp, de lo pasado a lo más actual en caso de year.

arrange(gapminder, year, lifeExp)

Podemos observar que en el año 1952, el país con menor expectativa de vida fue Afghanistan. Si quisieramos ordenar de tal forma que las primeras observaciones de gapminder reflejen la situación de los países más cercano a la actualidad con respecto a que país tuvo menor expectativa de vida lifeExp. Para esta tarea, podemos utilizar la función auxiliar desc en conjunto con arrange.

arrange(gapminder, desc(year), lifeExp)

En el año 2007, la situación de Afghanistan mejoró aumentando aproximadamente 15 años la expectativa de vida. Sin embargo, esta mejora sigue siendo insuficiente sí consideramos que transcurrieron 55 años desde la primera medición.

Componer con los verbos y la historia de Pin Pon

En esta sección discutiremos acerca de como componer operaciones más complejas sobre dataframes que las ejercidas por un solo verbo.

Supongamos que tenemos en mente realizar las siguientes operaciones sobre la data gapminder para concluir con un gráfico.

  1. Filtrar solo las observaciones correspondientes country igual Chile.
  2. Seleccionar las variables year, pop y gdpPercap
  3. Computar la variable gdpMillion en base a pop y gdpPercap.
  4. Gráficar la evolución del PIB con respecto a la variable year (gráfico de línea).

Una forma de pasar lo que tenemos en mente a la consola, es enfocarse en el último paso y saber que para crear el gráfico necesitamos entregarle a la función ggplot una data con las caracteristicas deseadas. Luego, añadirle una capa con una línea como representación de las variables year y gdpMillion mapeadas al eje x e y respectivamente. Por lo tanto, el esqueleto simple de nuestro programa para ejecutar los pasos deseados es:

library(ggplot2)
ggplot(data = DATA_CARACTERISTICAS_DESEADAS)
  + geom_line(mapping = aes(x = year, y = gdpMillion))

En cuanto a la DATA_CARACTERISTICAS_DESEADAS, debemos pensar que cada verbo entrega un dataframe modificado. Luego, sí le entrego este output recibido de un verbo a otro, el nuevo verbo ejecutará su acción sobre una tabla ya modificada. Por lo tanto, si continuó esta cadena en algún punto obtendré una tabla con todas las caracteristicas deseadas.

                                           # IDENTIFICAR ARGUMENTOS
                                           # ----------------------             
mutate(                                    #                   | mutate
       select(                             #         | select  | data3
              filter(                      #| filter |  data2  | data3
                    gapminder,             #| data1  |  data2  | data3  
                    country == "Chile"     #| arg1   |  data2  | data3
                    ),                     #         |  data2  | data3
              year, pop, gdpPercap         #         |  arg2   | data3
              ),                           #                   | data3
      gdpMillion = (gdpPercap * pop) / 1e6 #                   | arg3
)                                          # ----------------------
                                           # Parentesis deben estar ()!

Integrando estos dos bloques de código en uno.

library(ggplot2) 
ggplot(data =
        mutate(
               select(
                      filter(
                             gapminder, 
                             country == "Chile"),
                      year,
                      pop,
                      gdpPercap
                      ),
               gdpMillion = (gdpPercap * pop) / 1e6
              )
      ) +
  geom_line(mapping = aes(x = year, y = gdpMillion))  

¿Podemos realizar la secuencia de operaciones sobre gapminder de otra forma?

La segunda alternativa es asignar el resultado de cada verbo a una variable y luego ir transmitiendo esta en representación de la operación.

chile <- filter(gapminder, country == "Chile")
chile2 <- select(chile, year, pop, gdpPercap)
chile3 <- mutate(chile2, gdpMillion = (gdpPercap * pop) / 1e6)
ggplot(data = chile3) +
  geom_line(mapping = aes(x = year, y = gdpMillion))

La tercera alternativa, es útilizar el operador %>% (ctrl + shift + m), llamado “pipe”, que Pin Pon nos contará un poco más.

Analicemos el primer párrafo de la canción de Pin Pon:

Pin Pon es un muñeco
Muy guapo y de cartón, de cartón,
Se lava la carita
Con agua y con jabón, con jabón

Traduzcamos esto para el computador, queremos que Pin Pon, este muñeco guapo y de cartón, se lavé la carita con agua y con jabón.

Debemos crear primero al muñeco Pin Pon y las características que lo describen.

pin_pon <- muñeco(apariencia = guapo, material = carton)

Sí queremos ejecutar la acción lavar sobre el muñeco Pin Pon podemos utilizar esta como una función equivalente al verbo select, solo que en este caso el resultado modificará el estado higienico de Pin Pon y no un dataframe.

lavar(pin_pon, 
      que = carita, 
      como = con_agua_y_con_jabon)

El operador pipe %>%, toma el objeto que se encuentra a su izquierda como el primer argumento de la función que esta a la derecha. Es decir, obj_izq %>% accion_derecha() == accion_derecha(obj_izq). Por lo que aplicar la acción de lavar a Pin Pon quedaría escrito de la siguiente forma:

pin_pon %>% 
    lavar(que = carita,
          como = con_agua_y_con_jabon)

¿Qué gano con esto? El verdadero poder del operador %>% surge cuando estamos en una situación similar a la descrita al principio de esta sección. Nos encontramos con multiples acciones que ejecutar sobre un objeto como un dataframe.

Analicemos otro parrafo más de la canción de Pin Pon para encontrar una situación similar:

Pin Pon toma su sopa
Y no ensucia el delantal
Pues come con cuidado
Como un buen colegial

En este parrafo, a diferencia del anterior, Pin Pon ejecuta dos acciones principales tomar y comer. Podriamos escribir el código en la forma clásica como:

comer(
      tomar(
            pin_pon, 
            que = sopa),
      con = cuidado, 
      como = un_buen_colegial
      )

Sí utilizamos el operador %>% para escribir lo mismo:

pin_pon %>% 
        tomar(que = sopa) %>% 
        comer(con = cuidado,
              como = un_buen_colegial)

Cada operador %>% va tomando el objeto que tiene a su izquierda y lo ingresa como el primer argumento de la acción a ejecutarse por la función a la derecha del operador. Esto como resultado, tiene dos ventajas:

  1. El código es más fácil de leer y entender, simplemente partimos con nuestro objeto inicial y vamos aplicando acciones que modifican a este objeto de arriba hacía abajo.

  2. No necesitamos guardar variables intermedias con las modificaciones del objeto, simplemente guardamos cuando llegamos a la última modificación que nos interesa almacenar en una variable para ocupar después.

Ya dejando descansar a Pin Pon, ahora podemos ocupar esta forma de escribir código para crear nuestro gráfico:

gapminder %>% 
  filter(country == "Chile") %>% 
  select(year, pop, gdpPercap) %>% 
  mutate(gdpMillion = (gdpPercap * pop) / 1e6) %>% 
  ggplot() +
    geom_line(mapping = aes(x = year, y = gdpMillion))

El código anterior ilustra las ventajas del operador %>% sobre alternativas anteriores.

  1. Sobre la primera alternativa, es evidente que es más fácil leer la ejecución de acciones de manera lineal, en el ejemplo, de arriba hacía abajo se van ejecutando cada uno de los verbos. En cambio, la primera alternativa que vimos, se va haciendo más compleja de leer al tener mayor número de acciones porque debemos iniciar una lectura de “adentro hacía afuera”

  2. Sobre la segunda alternativa, la de almacenar el resultado de las acciones a variables para luego referirnos a estas por su nombre. Tiene a veces el problema de obligarnos a guardar resultados intermedios de los que por sí no tenemos mucho interes. El operador %>% nos propone la regla para crear objetos con nombres cuando estos realmente merecen tenerlos, y evitar crear objetos intermedios como chile1, chile2, chile3 que su único proposito es lograr un paso para otra acción de la cual tenemos interes en su resultado.

LS0tDQp0aXRsZTogIkNsYXNlIDQ6IExvcyB2ZXJib3MgZGUgbGEgbWFuaXB1bGFjacOzbiINCm91dHB1dDogDQogIGh0bWxfbm90ZWJvb2s6IA0KICAgIGhpZ2hsaWdodDoga2F0ZQ0KICAgIHRoZW1lOiBjZXJ1bGVhbg0KICAgIHRvYzogeWVzDQotLS0NCg0KYGBge3IsIGVjaG8gPSBGQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldCgNCiAgY29tbWVudCA9ICIjPiIsDQogIGVjaG8gPSBUUlVFDQopDQpgYGANCg0KRW4gZXN0YSBjbGFzZSBub3MgZW5mb2NhcmVtb3MgZW4gYWdyZWdhciBhIG51ZXN0cmEgY2FqYSBkZSBoZXJyYW1pZW50YXMgZnVuY2lvbmVzDQpwYXJhIG1hbmlwdWxhciAqZGF0YWZyYW1lcyogKGRhdGEgcmVjdGFuZ3VsYXIpIHByb3ZlbmllbnRlcyBkZWwgcGFxdWV0ZSAqKmRwbHlyKiouDQpVdGlsaXphcmVtb3MgZGUgZWplbXBsbyBwcmluY2lwYWxtZW50ZSBsb3MgZGF0b3MgcXVlIHZpZW5lbiBlbiBlbCBvYmpldG8gYGdhcG1pbmRlcmAgcGVydGVuZWNpZW50ZXMgYWwgcGFxdWV0ZSBxdWUgbGxldmEgZWwgbWlzbW8gbm9tYnJlLg0KDQpMbyBwcmltZXJvIHF1ZSBoYXJlbW9zIHNlcsOhIGNhcmdhciBsb3MgcGFxdWV0ZXMgcXVlIHV0aWxpemFyZW1vcyANCmVuIG51ZXN0cm8gYW7DoWxpc2lzLg0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgQ2FyZ2Ftb3MgbnVlc3RyYXMgYXBsaWNhY2lvbmVzIChwYXF1ZXRlcykuDQpsaWJyYXJ5KGRwbHlyKSAgICMgZnVuY2lvbmVzICh2ZXJib3MpIHBhcmEgbWFuaXB1bGFyIGRhdGFmcmFtZXMuDQpsaWJyYXJ5KGdhcG1pbmRlcikgICMgcGFxdWV0ZSBxdWUgdGllbmUgbGEgZGF0YSBjb24gcXVlIHRyYWJhamFyZW1vcy4NCmBgYA0KDQojIyBBbGd1bm9zIHB1bnRvcyBhbnRlcyBkZSBwYXJ0aXINCg0KQW50ZXMgZGUgY29tZW56YXIsIHJlcGFzZW1vcyBhbGd1bm9zIHB1bnRvcyBwYXJhIGFzZWd1cmFybm9zIGRlIHF1ZSB0b2RvcyBub3MgZW5jb250cmFtb3MgaGFibGFuZG8gZW4gbG9zIG1pc21vcyB0P3JtaW5vcy4NCg0KMS4gRXN0cnVjdHVyYSBkZSBkYXRvczogZW4gZWwgY29udGV4dG8gZGUgcHJvZ3JhbWFjacOzbiBlcyBjb21vIHJlcHJlc2VudGFtb3MgbGEgaW5mb3JtYWNpw7NuLiBIYXN0YSBhaG9yYSBzb2xvIGhlbW9zIHZpc3RvIGxhIGVzdHJ1Y3R1cmEgbGxhbWFkYSAqKmRhdGEgcmVjdGFuZ3VsYXIqKiBxdWUgbGEgY29ub2NlbW9zIGNvbW8gKmRhdGFmcmFtZXMqIG8gKnRpYmJsZXMqLiBVbiBlamVtcGxvIGRlIGVzdGUgdGlwbyBkZSBlc3RydWN0dXJhIGRlIGRhdG9zIHNlcj8gZWwgc2lndWllbnRlICpkYXRhZnJhbWUqOg0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCiMgRXN0byBlcyB1biB2ZWN0b3IsIHVuYSBsaXN0YSBjb24gZWxlbWVudG9zIGRlIHRpcG8gaG9tb2dlbmVvcy4NCm5vdGFzIDwtIHRpYmJsZSgNCiAgICAgICAgICAgICAgcmFtbyA9IGMoIk1hdGUiLCAiTGVuZ3VhamUiLCAiRGFuemEiKSwNCiAgICAgICAgICAgICAgbm90YXMgPSBjKDUuMiwgMy45LCA1LjUpDQopDQoNCm5vdGFzDQpgYGANCg0KDQoyLiBEYXRhZnJhbWU6IGVzIGVsIG5vbWJyZSBmb3JtYWwgZGUgbGEgZXN0cnVjdHVyYSBkZSBkYXRvcyBxdWUgcmVwcmVzZW50YSANCmxhIGRhdGEgcmVjdGFuZ3VsYXIgZW4gZWwgbGVuZ3VhamUgZGUgcHJvZ3JhbWFjacOzbiBSLiAqKlBvciBkYXRhZnJhbWUgbm9zIHJlZmVyaW1vcw0Kc2ltcGxlbWVudGUgYSBjb2x1bW5hcyBxdWUgcmVwcmVzZW50YW4gdmFyaWFibGVzIHkgZmlsYXMgcXVlIHJlcHJlc2VudGFuIG9ic2VydmFjaW9uZXMqKi4gRW4gZWwgZWplbXBsbyBhbnRlcmlvciwgY2FkYSBvYnNlcnZhY2nDs24gcmVwcmVzZW50YSBsYSBub3RhIGRlIHVubyBkZSBtaXMgcmFtb3MuIEFkZW3DoXMgaGFibGFtb3MgZGUgKnRpYmJsZXMqIGNvbW8gdMOpcm1pbm8gZXF1aXZhbGVudGUgYSAqZGF0YWZyYW1lKiwgcGVybyBkZXN0YWNhcmVtb3MgdW5hIHNvbGEgZGlmZXJlbmNpYSBlbnRyZSBhbWJvcywgdW4gKnRpYmJsZSogZXMgbcOhcyBhZ3JhZGFibGUgZGUgdmlzdWFsaXphciBxdWUgdW4gKmRhdGFmcmFtZSogdHJhZGljaW9uYWwgZW4gbGEgY29uc29sYS4gRW4gbGEgY2xhc2UgcGFzYWRhIHZpbW9zIGxhcyBzaWd1aWVudGVzIGZvcm1hcyBwYXJhIGNyZWFyIGRhdGEgcmVjdGFuZ3VsYXIgZW4gUjoNCg0KYGBge3IsIGV2YWw9RkFMU0V9DQojIFBhcmEgY3JlYXIgdW4gdGliYmxlIHBvciBjb2x1bW5hcy4NCm5vdGFzIDwtIHRpYmJsZSgNCiAgICAgICAgICAgICAgICByYW1vID0gYygiTWF0ZSIsICJMZW5ndWFqZSIsICJEYW56YSIpLA0KICAgICAgICAgICAgICAgIG5vdGFzID0gYyg1LjIsICAgICAgMy45LCAgICAgICAgIDUuNSkNCiAgICAgICAgICAgICAgICApDQoNCg0KIyBQYXJhIGNyZWFyIHVuIHRpYmJsZSBwb3IgZmlsYXMsIMKhT0pPISBhY8OhIGxhIGZ1bmNpw7NuIGVzIHRyaWJibGUoKSBjb24gci4NCiMgVmFtb3MgY3JlYW5kbyBsYSBkYXRhIGVuIG9yaWVudGFjacOzbiBmaWxhIHkgZXNwZWNpZmljYW1vcyBsb3Mgbm9tYnJlcyBkZSBsYXMNCiMgY29sdW1uYXMgYW50ZXBvbmllbmRvIHVuYSBjb2xhIGRlIGNoYW5jaG8gfiAoYWx0ICsgMTI2IGVuIHRlY2xhZG8gDQojIG7Dum1lcmljbykNCm5vdGFzIDwtIHRyaWJibGUoDQogICAgICAgICAgICAgICAgICB+cmFtbywgICB+IG5vdGFzLA0KICAgICAgICAgICAgICAgICAgIy0tLS0tLS0tLS0tLS0tLSAgICAjIDwtIE5vIGVzIG5lY2VzYXJpbyBlc2NyaWJpciBlc3RlIGNvbWVudGFyaW8NCiAgICAgICAgICAgICAgICAgICJNYXRlIiwgICAgICA1LjIsICAgIyAgICBlbiBlbCBjw7NkaWdvLCBlcyBwYXJhIG1vc3RyYXIgbGENCiAgICAgICAgICAgICAgICAgICJMZW5ndWFqZSIsICAzLjksICAgIyAgICBzZXBhcmFjaT9uIGRlbCBub21icmUgZGUgbGFzIGNvbHVtbmFzDQogICAgICAgICAgICAgICAgICAiRGFuemEiLCAgICAgNS41ICAgICMgICAgY29uIHJlc3BlY3RvIGEgbGFzIG9ic2VydmFjaW9uZXMuDQopDQoNCiMgRm9tcmEgdHJhZGljaW9uYWwgZGUgY3JlYXIgdW4gZGF0YWZyYW1lIGVuIFIsIGxhIG3DqWNhbmljYSBlcyBlcXVpdmFsZW50ZQ0KIyBhIHRpYmJsZSgpIHBlcm8gaGF5IHF1ZSBmb3J6YXIgYSBxdWUgbG9zIGNhcmFjdGVyZXMgc2VhbiB0cmF0YWRvcyBjb21vDQojIHRhbCB5IG5vIGNvbW8gdmFyaWFibGUgdGlwbyAiZmFjdG9yIiwgZXNwZWNpZmljYW5kbyBkZSBlc3RhIGZvcm1hIGVsIGFyZ3VtZW50byANCiMgJ3N0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRScuIEVuIGNhbWJpbywgdGliYmxlKCkgcG9yIGRlZmVjdG8gcmVwcmVzZW50YW4gYSBsb3MgDQojIGNhcmFjdGVyZXMgY29tbyB2YXJpYWJsZSB0aXBvICJjaHIiLg0Kbm90YXMgPC0gZGF0YS5mcmFtZSgNCiAgICAgICAgICAgICAgICByYW1vID0gYygiTWF0ZSIsICJMZW5ndWFqZSIsICJEYW56YSIpLA0KICAgICAgICAgICAgICAgIG5vdGFzID0gYyg1LjIsICAgICAgMy45LCAgICAgICAgIDUuNSksDQogICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFDQopDQoNCiMgQWhvcmEgZW4gbG9zIHRyZXMgY2Fzb3MgYW50ZXJpb3JlcywgY3JlYW1vcyB1bmEgZGF0YXJlY3Rhbmd1bGFyIHkgbGUgYXNpZ25hbW9zDQojIGFsIG9iamV0byBxdWUgcmVwcmVzZW50YSBhIGVzdGEsIGVsIG5vbWJyZSBkZSAibm90YXMiLiBTaSBxdWVyZW1vcyBsbGFtYXINCiMgbyB2aXN1YWxpemFyIG51ZXN0cmEgZGF0YSBlbiBsYSBjb25zb2xhLCB0ZW5lbW9zIHF1ZSBsbGFtYXIgYWwgb2JqZXRvIHBvcg0KIyBzdSBub21icmUgZGUgbGEgc2lndWllbnRlIG1hbmVyYTogDQpub3Rhcw0KYGBgDQoNCjMuIENvbiByZXNwZWN0byBhbCBjw7NkaWdvIGVzY3JpdG8gYXJyaWJhLCBkZXN0YWNhcjoNCi0gRWwgdXNvIGRlIGAjYCBwYXJhIGVzY3JpYmlyIGNvbWVudGFyaW9zIGluZm9ybWF0aXZvcyBlbiBsYSByZWdpw7NuIGRlbCBjw7NkaWdvLg0KLSBFbCBvcGVyYWRvciBkZSBhc2lnbmFjacOzbiwgYDwtYCAodGVjbGEgcsOhcGlkYTogYWx0ICsgLSksIHBhcmEgZGFybGUgdW4gbm9tYnJlIGEgdW4gb2JqZXRvIHF1ZSBjcmVlbW9zIHkgYXPDrSBkZXNwdcOpcyBwb2RlciB1dGlsaXphcmxvIGVuIG90cmEgb3BlcmFjacOzbi4NCi0gSW5kZW50YXIgZWwgY8OzZGlnbywgwqFBZ3JlZ2FyIGVzcGFjaW8gcGFyYSBxdWUgZWwgY8OzZGlnbyByZXNwaXJlISwgeSBwYXJhIHF1ZSB2aXN1YWxtZW50ZSBzZWEgbcOhcyBmw6FjaWwgZGUgbGVlci4gTm8gcXVlcmVtb3MgZXNjcmliaXIgYWxnbyBjb21vIGxvIHNpZ3VpZW50ZSBxdWUgZWplY3V0YSBsbyBtaXNtbyBxdWUgbGEgw7psdGltYSBmb3JtYSBkZSBjcmVhciBkYXRhZnJhbWVzIGFycmliYSBwZXJvIGVzIG11Y2hvIG3DoXMgZMOtZmljaWwgZGUgbGVlcjoNCmBgYHtyLCBldmFsPUZBTFNFfQ0Kbm90YXM8LWRhdGEuZnJhbWUocmFtbz1jKCJNYXRlIiwiTGVuZ3VhamUiLCJEYW56YSIpLG5vdGFzPWMoNS41LDMuOSw1LjUpLHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpDQpgYGANCg0KDQotIFJlc3BlY3RvIGFsIGVzdGlsbyBxdWUgYWRvcHRhciBwYXJhIGVzY3JpYmlyIGPDs2RpZ28sIGRhcmxlIG5vbWJyZSBhIGxhcyB2YXJpYWJsZXMsDQphcmNoaXZvcywgZXRjw6l0ZXJhLCBwdWVkZW4gbGVlciBtw6FzIGVuIGVzdGUgW2xpbmtdKGh0dHA6Ly9zdHlsZS50aWR5dmVyc2Uub3JnL3N5bnRheC5odG1sI29iamVjdC1uYW1lcykNCg0KDQo0LiBDdWFuZG8gaGFibGFtb3MgZGUgaGVycmFtaWVudGFzIHF1ZSBub3MgZW50cmVnYSB1biBwYXF1ZXRlLCBlc3RhbW9zIGhhYmxhbmRvIA0KZW4gZWwgY29udGV4dG8gZGUgcHJvZ3JhbWFjacOzbiBkZSAqKmZ1bmNpb25lcyoqIC4gTGEgZm9ybWEgw7p0aWwgZGUgcGVuc2FyIGVuIHVuYQ0KZnVuY2nDs24gZXMgY29tbyB1bmEgY2FqYSBuZWdyYSBxdWUgbGUgZW50cmVnYW1vcyBhbGdvICgqaW5wdXQqKSB5IG5vcyBkZXZ1ZWx2ZSB1biANCnJlc3VsdGFkbyAoKm91dHB1dCopIGVuIGJhc2UgYSBsbyBlbnRyZWdhZG8uIFNpIHF1ZXJlbW9zIHNhYmVyIHF1ZSBkZWJlbW9zIGVudHJlZ2FybGUNCmEgZXN0YSBjYWphIG5lZ3JhLCBwb2RlbW9zIGxlZXIgbGEgZG9jdW1lbnRhY2nDs24gZGVudHJvIGRlIFIgcXVlIHZpZW5lIGNvbg0KaW5mb3JtYWNpw7NuIGFjZXJjYSBkZSBjb21vIHVzYXIgeSBxdcOpIGVudHJlZ2FybGUgeS9vIGVzcGVjaWZpY2FybGUgYSBsYSBmdW5jacOzbi4gUGFyYSBlc3RvIGRlYmVtb3MNCmVzY3JpYmlyID8gaW5tZWRpYXRhbWVudGUgc2VndWlkbyBkZWwgbm9tYnJlIGRlIGxhIGZ1bmNpw7NuIGVuIGxhIGNvbnNvbGEgY29tbyBzZSBtdWVzdHJhIGENCmNvbnRpbnVhY2nDs24gZGUgZXN0ZSBwYXJyYWZvIHkgc2UgZGVzcGxlZ2Fyw6EgbGEgZG9jdW1lbnRhY2nDs24gcmVzcGVjdGl2YSAgZW4gdW5vIA0KZGUgbG9zIGN1YWRyYW50ZXMuICoqTG8gaW1wb3J0YW50ZSBjb24gcmVzcGVjdG8gYSBsYXMgZnVuY2lvbmVzIGVzIHF1ZQ0Kbm9zIGZ1ZXJ6YW4gYSBpbnRlcmFjdHVhciBhIHRyYXZlcyBkZSB1bmEgaW50ZXJmYWNlIHBhcmEgcmVhbGl6YXIgdW5hIG9wZXJhY2nDs24sIGV2aXRhbmRvDQplbnRyYXIgZW4gbG9zIGRldGFsbGVzIGVzcGVjaWZpY29zIGRlIGxvIHF1ZSBvY3VycsOpIHBvciBkZWJham8qKiwgZXMgcG9yIGVzdG8gcXVlIGxhIGNvbXBhcmFtb3MgY29uIHVuYSBjYWphIG5lZ3JhIHlhIHF1ZSBubyBwb2RlbW9zIG9ic2VydmFyIGxvIHF1ZSBvY3VycsOpIGVuIHN1IGludGVyaW9yLiBFc3RlIGNvbmNlcHRvIGVuIHByb2dyYW1hY2nDs24gc2UgY29ub2NlIGNvbW8gYWJzdHJhY2Npw7NuLg0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCiMgUGFyYSBjb25zdWx0YXIgbGEgZG9jdW1lbnRhY2nDs24gZGUgbGEgZnVuY2nDs24gdHJpYmJsZSgpIGRlbnRybyBkZSBSLg0KP2RhdGEuZnJhbWUNCmBgYA0KDQoNCiMjIExvcyB2ZXJib3MgZGUgbGEgbWFuaXB1bGFjacOzbg0KDQpOb3MgcmVmZXJpcmVtb3MgcG9yICoqdmVyYm9zKiogZGUgbGEgbWFuaXB1bGFjacOzbiBhIHVuIGNvbmp1bnRvIGRlIGZ1bmNpb25lcyANCnBlcnRlbmVjaWVudGFzIGFsIHBhcXVldGUgKipkeXBscioqIHF1ZSBlamVjdXRhbiB1bmEgYWNjacOzbiBlc3BlY2lmaWNhIHNvYnJlIHVuIA0KKmRhdGFmcmFtZSogeSBub3MgZW50cmVnYW4gdW4gKmRhdGFmcmFtZSogKiptb2RpZmljYWRvKiogY29tbyByZXN1bHRhZG8uDQoNCkVtcGV6YXJlbW9zIGV4cGxvcmFuZG8gZGUgZm9ybWEgaW5kaXZpZHVhbCBjYWRhIHVubyBkZSBsb3MgdmVyYm9zIGRldGFsbGFkb3MgYSANCmNvbnRpbnVhY2nDs24geSBhbCBmaW5hbCBtb3N0cmFyZW1vcyBjb21vIHBvZGVtb3MgY29tcG9uZXIgb3BlcmFjaW9uZXMgbcOhcyBjb21wbGVqYXMNCnNvYnJlIG51ZXN0cm9zIGRhdG9zIGFsIGp1bnRhciBtw6FzIGRlIHVubyBkZSBlc3RvcyB2ZXJib3MuDQoNCi0gYGZpbHRlcmA6IHBhcmEgKipmaWx0cmFyIG9ic2VydmFjaW9uZXMqKiBiYXNhZG9zIGVuIHVuYSBvIG3DoXMgY29uZGljaW9uZXMuDQotIGBzZWxlY3RgOiBwYXJhICoqc2VsZWNjaW9uYXIgdmFyaWFibGVzKiogcG9yIG5vbWJyZS4NCi0gYG11dGF0ZWA6IHBhcmEgKipjcmVhciBudWV2YXMgdmFyaWFibGVzKiogYmFzYWRhcyBlbiBvdHJhcy4NCi0gYHN1bW1hcmlzZWA6IHBhcmEgKipjcmVhciB2YXJpYWJsZXMqIHF1ZSByZXByZXNlbnRhbiAqKnJlc3VtZW5lcyoqIGRlIG90cmFzIGNvbW8gZWwgcHJvbWVkaW8uDQotIGBhcnJhbmdlYDogcGFyYSAqKm9yZGVuYXIgbGFzIG9ic2VydmFjaW9uZXMqKiBiYXNhZG8gZW4gdW5hIG8gbcOhcyB2YXJpYWJsZS4NCi0gYGdyb3VwX2J5YDogcGFyYSBjYW1iaWFyIGVsICoqZG9taW5pbyoqIGVuIHF1ZSBzZSBhcGxpY2FuIGxvcyB2ZXJib3MgYSBuaXZlbCBkZSBncnVwb3MgZm9ybWFkb3MgZW4gYmFzZSBhIHZhcmlhYmxlcyBkZW50cm8gZGUgdW4gKmRhdGFmcmFtZSouDQoNCiMjIyBmaWx0ZXIsIHBhcmEgZmlsdHJhciBvYnNlcnZhY2lvbmVzDQoNClBhcnRhbW9zIGNvbiB1bmEgb3BlcmFjacOzbiBhIGxhIHF1ZSB5YSBmdWltb3MgZXhwdWVzdG9zIGN1YW5kbyByZWFsaXphbW9zIGVsIGdyw6FmaWNvIGRlIGJ1cmJ1amFzLiBFc3RhbW9zIGludGVyZXNhZG9zIHNvbG8gZW4gbGFzIG9ic2VydmFjaW9uZXMgZGUgbGEgZGF0YSBgZ2FwbWluZGVyYCBxdWUgdGllbmVuIHJlZ2lzdHJvcyBkZSBwYWlzZXMgcGVydGVuZWNpZW50ZXMgYWwgY29udGluZW50ZSBkZSBBbWVyaWNhLiBFc3RlIHRpcG8gZGUgdGFyZWEgZXMgaWRlYWwgcGFyYSBsYSBmdW5jacOzbiBgZmlsdGVyKClgLCBwb2RlbW9zIG9idGVuZXIgc3ViY29uanVudG9zIGRlIG9ic2VydmFjaW9uZXMgYmFzYWRvcyBlbiBsb3MgdmFsb3JlcyBkZSBlc3Rvcy4NCg0KYGBge3J9DQpmaWx0ZXIoZ2FwbWluZGVyLCBjb250aW5lbnQgPT0gIkFtZXJpY2FzIikNCmBgYA0KDQpSZWZsZXhpb25lbW9zIHVuIHBvY28gc29icmUgbGEgbMOtbmVhIGRlIGPDs2RpZ28gZGUgYXJyaWJhLCBlbCBwcmltZXIgYXJndW1lbnRvIGRlIGxhIGZ1bmNpw7NuIGBmaWx0ZXIoKWAsIGVzIGRlY2lyLCAqKmxvIHByaW1lcm8gcXVlIGVzcGVjaWZpY2Ftb3MgZGVudHJvIGRlIGxhIGZ1bmNpw7NuIGVzIGVsIG5vbWJyZSBkZWwgb2JqZXRvIHF1ZSByZXByZXNlbnRhIG51ZXN0cmEgZGF0YSByZWN0YW5ndWxhcioqIGBnYXBtaW5kZXJgLiBMdWVnbywgZW5jb250cmFtb3MgbGEgc2lndWllbnRlIGV4cHJlc2nDs24gYGNvbnRpbmVudCA9PSAiQW1lcmljYXMiYCwgcXVlIG5vcyByZWZlcmlyZW1vcyBhIGVzdGUgdGlwbyBkZSBleHByZXNpb25lcyBjb21vICoqY29uZGljaW9uZXMgbMOzZ2ljYXMqKi4NCg0KVW5hIGNvbmRpY2nDs24gbMOzZ2ljYSBlcyB1bmEgcHJvcG9zaWNpw7NuIHF1ZSBzdSByZXN1bHRhZG8gcHVlZGUgdGVuZXIgZG9zIHBvc2libGVzIHZhbG9yZXM6IHZlcmRhZGVybyBvIGZhbHNvLg0KDQpNdWNoYXMgZGUgbGFzIGNvbmRpY2lvbmVzIGzDs2dpY2FzIHNlIGNvbnN0cnV5ZW4gY29uIGxvcyAqKm9wZXJhZG9yZXMgZGUgcmVsYWNpw7NuKiosIGVuIGxhcyBxdWUgc2UgcmVsYWNpb25hIHVuYSB2YXJpYWJsZSBjb24gdW4gdmFsb3IuIEVuIGVsIGxlbmd1YWplIGRlIHByb2dyYW1hY2nDs24gUiBsb3MgKipvcGVyYWRvcmVzIGRlIHJlbGFjacOzbioqIHNlIGVzcGVjaWZpY2FuIGRlIGxhIHNpZ3VpZW50ZSBtYW5lcmE6DQoNCi0gYD09YDogSWd1YWxkYWQuDQotIGAhPWA6IE5vIGlndWFsZGFkLg0KLSBgPmA6IE1heW9yIHF1ZS4NCi0gYDxgOiBNZW5vciBxdWUuDQotIGA+PWA6IE1heW9yIG8gaWd1YWwgcXVlLg0KLSBgPD1gOiBNZW5vciBvIGlndWFsIHF1ZS4NCg0KRW4gZWwgY2FzbyBkZSBudWVzdHJhIGNvbmRpY2nDs24gbMOzZ2ljYSwgcXVlcmVtb3Mgc29sbyBsYXMgb2JzZXJ2YWNpb25lcyBkZSBsYSBkYXRhIGBnYXBtaW5kZXJgIGVuIHF1ZSBsYSByZWxhY2nDs24gYGNvbnRpbmVudCA9PSAiQW1lcmljYXMiYCBzZWFuIGV2YWx1YWRhcyBjb24gdmFsb3IgKip2ZXJkYWRlcm8qKi4gRW4gb3RyYXMgcGFsYWJyYXMsIG5vIG5vcyBpbnRlcmVzYSBlbCByZXN0byBkZSBsYXMgb2JzZXJ2YWNpb25lcyBxdWUgcGVydGVuY2VuIGEgb3Ryb3MgY29udGluZW50ZXMgcGFyYSBmb3JtYXIgZXN0ZSBzdWJjb25qdW50byBkZSBkYXRvcy4NCg0KYGBge3J9DQpmaWx0ZXIoZ2FwbWluZGVyLCBjb250aW5lbnQgPSAiQW1lcmljYXMiKQ0KYGBgDQoNCsKhT2pvISB1biBlcnJvciBjb23Dum4gZXMgdXRpbGl6YXIgYD1gIGVuIHZleiBkZSBgPT1gIHBhcmEgY3JlYXIgbGEgcmVsYWNpw7NuIGRlIGlndWFsZGFkLiBBY8OhIGVzdGFyw61hbW9zIHRyYXRhbmRvIGRlIGFzaWduYXIgZWwgdmFsb3IgYCJBbWVyaWNhcyJgIGEgbGEgdmFyaWFibGUgYGNvbnRpbmVudGAsIGN1YW5kbyBlbiByZWFsaWRhZCBxdWVyZW1vcyBnZW5lcmFyIHVuYSByZWxhY2nDs24gZGUgaWd1YWxkYWQsIGVzIGRlY2lyIHV0aWxpemFyIGVsIG9wZXJhZG9yIGRlIHJlbGFjacOzbiBgPT1gLg0KDQpMb3Mgb3BlcmFkb3JlcyBkZSByZWxhY2nDs24gYD5gLCBgPGAsIGA+PWAgeSBgPD1gIHNvbiB1dGlsaXphZG9zIHBhcmEgY3JlYXIgY29uZGljaW9uZXMgbMOzZ2ljYXMgY29uIHZhcmlhYmxlcyBuw7ptZXJpY2FzIG8gY29uIHZhcmlhYmxlcyBxdWUgbm8gc29uIG7Dum1lcmljYXMgcGVybyBwdWVkZW4gc2VyIHJlcHJlc2VudGFkYXMgZGUgYWxndW5hIGZvcm1hIG7Dum1lcmljYS4NCg0KYGBge3IsIGVjaG8gPSBUUlVFfQ0KIyBFamVtcGxvIGRlIHVuYSB2YXJpYWJsZSBxdWUgbm8gZXMgbsO6bWVyaWNhIHBlcm8gcHVlZGUNCiMgdG9tYXIgdW5hIHJlcHJlc2VudGFjacOzbiBuw7ptZXJpY2EgdsOhbGlkYS4gVFJVRSA9IDEsIEZBTFNFID0gMA0KYyhUUlVFLCBGQUxTRSwgVFJVRSwgRkFMU0UsIEZBTFNFKSA+IDANCmBgYA0KDQpVbiBhc3BlY3RvIHByw6FjdGljbyBkZSBsYSBzaW50YXhpcyBkZSBsYSBmdW5jacOzbiBgZmlsdGVyKClgLCB5IGVsIHJlc3RvIGRlIGxvcyB2ZXJib3MgcXVlIHZlcmVtb3MsIGVzIHF1ZSAqKmxhcyB2YXJpYWJsZXMgZGUgbnVlc3RybyBkYXRhZnJhbWUgZW4gcXVlIGhhY2Vtb3MgcmVmZXJlbmNpYSBkZW50cm8gZGUgbG9zIGFyZ3VtZW50b3MsIG5vIGRlYmVuIHNlciByb2RlYWRvcyBkZSBjb21pbGxhcyoqLiBQb3IgZWplbXBsbywgZWwgbm9tYnJlIGRlIGxhIHZhcmlhYmxlIGVuIGxhIGNvbmRpY2nDs24gbMOzZ2ljYSBgY29udGluZW50ID09ICJBbWVyaWNhcyJgIG5vIGxsZXZhIGNvbWlsbGFzLiBTaW4gZW1iYXJnbywgZWwgdmFsb3IgZGUgbGFzIG9ic2VydmFjaW9uZXMgcXVlIGRlc2VhbW9zIGZpbHRyYXIgZGUgbGEgdmFyaWFibGUgYGNvbnRpbmVudGAgc2kgdmEgZW50cmUgY29taWxsYXMgYCJBbWVyaWNhcyJgLg0KDQpQb2RlbW9zIGFncmVnYXIgbcOhcyBkZSB1biBhcmd1bWVudG8gZXhwcmVzYW5kbyB1bmEgY29uZGljacOzbiBsw7NnaWNhIGVuIGxhIGZ1bmNpw7NuIGBmaWx0ZXIoKWAuIFBvciBlamVtcGxvLCBxdWVyZW1vcyBvYnRlbmVyIHNvbG8gaW5mb3JtYWNpw7NuIGRlIGxvcyBwYcOtc2VzIGRlbCBjb250aW5lbnRlIGFtZXJpY2FubyBzb2JyZSBlbCBhw7FvIDIwMDAuDQoNCmBgYHtyIGVjaG89VFJVRX0NCmZpbHRlcihnYXBtaW5kZXIsIGNvbnRpbmVudCA9PSAiQW1lcmljYXMiLCB5ZWFyID4gMjAwMCkNCmBgYA0KDQpMbyByZWxldmFudGUgY3VhbmRvIG9jdXBhbW9zIG3DoXMgZGUgdW4gYXJndW1lbnRvIGNvbiBjb25kaWNpb25lcyBsw7NnaWNhcyBkZW50cm8gZGUgYGZpbHRlcigpYCwgZXMgcXVlIGNhZGEgZXhwcmVzacOzbiBxdWUgdmEgc2VwYXJhZGEgcG9yIHVuYSBjb21hLCBzZSB1bmUgY29uIGVsIG9wZXJhZG9yIGzDs2dpY28gY29ub2NpZG8gY29tbyBgJmAgKGBBTkRgKS4gRXN0byBzaWduaWZpY2EgcXVlIG5vcyBlbnRyZWdhcsOhIGxhcyBvYnNlcnZhY2lvbmVzIHF1ZSBjdW1wbGFuIGxhcyBzaWd1aWVudGVzIGRvcyBjb25kaWNpb25lcyBzaW11bHRhbmVhbWVudGU6DQoNCjEuIGBjb250aW5lbnQgPT0gIkFtZXJpY2FzImAgDQoyLiBgeWVhciA+IDIwMDBgLg0KDQpDb21vIHBvZGVtb3Mgb2JzZXJ2YXIgZGVsIHJlc3VsdGFkbyBxdWUgbm9zIGVudHJlZ2EgZWwgY8OzZGlnbywgbm8gaGF5IG9ic2VydmFjaW9uZXMgcXVlIHNlYW4gYHllYXIgPiAyMDAwYCBwZXJvIHF1ZSBubyBwZXJ0ZW5lemNhbiBhbCBjb250aW5lbnRlIGFtZXJpY2FubywgbyB2aWNldmVyc2EsIG5vIGhheSBvYnNlcnZhY2lvbmVzIHF1ZSBwZXJ0ZW5lemNhbiBgY29udGluZW50ID09ICJBbWVyaWNhcyJgIHBlcm8gcXVlIGRhdGVuIGlndWFsIG8gbWVub3IgYWwgYcOxbyAyMDAwLg0KDQpFeGlzdGVuIHRhbWJpZW4gbG9zIG9wZXJhZG9yZXMgbMOzZ2ljb3M6DQoNCi0gYCFgOiBuZWdhY2nDs24sIHNlIGFudGVwb25lIGVuIHVuYSBjb25kaWNpw7NuIGzDs2dpY2EgcGFyYSBpbnZlcnRpciBzdSB2YWxvci4NCi0gYCZgOiAieSIgbMOzZ2ljbywgZXF1aXZhbGVudGUgYWdyZWdhciBtw6FzIGRlIHVuIGFyZ3VtZW50byBlbiBgZmlsdGVyYC4NCi0gYHxgOiAiPyIgbMOzZ2ljbywgc8OtIHNlIGN1bXBsZSBhbGd1bmEgZGUgbGFzIGNvbmRpY2lvbmVzLg0KDQpTaSBxdWlzaWVyYW1vcyBvYnRlbmVyIHRvZGFzIGxhcyBvYnNlcnZhY2lvbmVzIHF1ZSBubyBzZWFuIGRlbCBjb250aW5lbnRlIGFtZXJpY2FubywgcG9kcmlhbW9zIG5lZ2FyIGxhIGNvbmRpY2nDs24gbMOzZ2ljYSBgY29udGluZW50ID09ICJBbWVyaWNhcyJgLCBpbnZpcnRpZW5kbyBlbCBzaWdubyBhIGBGQUxTRWAgY3VhbmRvIGxhcyBvYnNlcnZhY2lvbmVzIHBlcnRlbmV6Y2FuIGFsIGNvbnRpbmVudGUgIkFtZXJpY2FzIiB5IGEgYFRSVUVgIGN1YW5kbyBzZWFuIGRpc3RpbnRhcyBkZSAiQW1lcmljYXMiLCBlc3RvIGFudGVwb25pZW5kbyBlbCBvcGVyYWRvciBsw7NnaWNvIGAhYCBkZSBsYSBzaWd1aWVudGUgZm9ybWE6DQoNCmBgYHtyIGVjaG89VFJVRX0NCiMgSW52ZXJ0aXIgZWwgc2lnbm8gZGUgbGEgZXZhbHVhY2nDs24gZGUgbGEgY29uZGljacOzbiBsw7NnaWNhIGNvbiAiISIuDQpmaWx0ZXIoZ2FwbWluZGVyLCAhKGNvbnRpbmVudCA9PSAiQW1lcmljYXMiKSkNCmBgYA0KDQpFbCBvcGVyYWRvciBgJmAgZXMgZXF1aXZhbGVudGUgY8OzbW8gc2UgbWVuY2lvbsOzIGFudGVyaW9ybWVudGUgYSBlbnVtZXJhciBtw6FzIGRlIHVuYSBjb25kaWNpw7NuIGzDs2dpY2EgZW4gbG9zIGFyZ3VtZW50b3MgZGUgbGEgZnVuY2nDs24gYGZpbHRlcmAuDQoNCmBgYHtyLCBldmFsID0gRkFMU0V9DQojIExhcyBkb3MgZm9ybWFzIGRlIHVzbyBzb24gZXF1aXZhbGVudGVzOg0KZmlsdGVyKGdhcG1pbmRlciwgY29udGluZW50ID09ICJBbWVyaWNhcyIsIHllYXIgPiAyMDAwKQ0KZmlsdGVyKGdhcG1pbmRlciwgY29udGluZW50ID09ICJBbWVyaWNhcyIgJiB5ZWFyID4gMjAwMCkNCmBgYA0KDQpFbiBjYW1iaW8sIGVsIG9wZXJhZG9yIGzDs2dpY28gYHxgIChgT1JgKSwgbm8gcHVlZGUgc2VyIGVtcGxlYWRvIGVudW1lcmFuZG8gY29uZGljaW9uZXMgbMOzZ2ljYXMgZW4gbG9zIGFyZ3VtZW50b3MgZGUgYGZpbHRlcmAuIFNlIGRlYmUgaGFjZXIgdXNvIGV4cGxpY2l0byBkZSBlc3RlIG9wZXJhZG9yLCBwb3IgZWplbXBsbywgc2kgcXVpc2llcmFtb3MgbGFzIG9ic2VydmFjaW9uZXMgcGVydGVuZWNpZW50ZXMgYWwgY29udGluZW50ZSBhbWVyaWNhbm8gbyBhc2lhdGljbywgZXMgdW5hIGJ1ZW5hIG9wb3J0dW5pZGFkIHBhcmEgb2N1cGFyIGB8YCBlbiB1bm8gZGUgbG9zIGFyZ3VtZW50b3MgZGUgYGZpbHRlcmA6DQoNCmBgYHtyIGVjaG89VFJVRX0NCmZpbHRlcihnYXBtaW5kZXIsIGNvbnRpbmVudCA9PSAiQW1lcmljYXMiIHwgY29udGluZW50ID09ICJBc2lhIikNCmBgYA0KDQpPYnNlcnZlbW9zIHF1ZSBsYSBjb25kaWNpw7NuIGzDs2dpY2EgYGNvbnRpbmVudCA9PSAiQW1lcmljYXMiIHwgY29udGluZW50ID09ICJBc2lhImAgKip2YSBlbiB1biBzb2xvIGFyZ3VtZW50byBkZW50cm8gZGUqKiBgZmlsdGVyYCwgbm8gaGF5IGNvbWFzIGVudHJlbWVkaW8geSBhZGVtw6FzIHNlIGRlYmUgZXNwZWNpZmljYXIgZWwgbm9tYnJlIGRlIGxhIHZhcmlhYmxlIGVuIGNhZGEgdXNvIGRlbCBvcGVyYWRvciBkZSBpZ3VhbGRhZCBgPT1gLiBMb3Mgc2lndWllbnRlcyB1c29zIHNlcsOtYW4gdW5hIGZvcm1hIGluY29ycmVjdGEgZGUgYXBsaWNhciBlbCBvcGVyYWRvciBgfGA6DQoNCmBgYHtyIGV2YWw9RkFMU0V9DQojIE1hbCB1c28gZGVsIG9wZXJhZG9yIHwuDQpmaWx0ZXIoZ2FwbWluZGVyLCBjb250aW5lbnQgPT0gIkFtZXJpY2FzIiB8ICJBc2lhIikgDQojIEVzdG8gZXF1aXZhbGUgYWwgb3BlcmFkb3IgJiB5IG5vIGFsIG9wZXJhZG9yIHwuIERlIGhlY2hvLCB1bmEgb2JzZXJ2YWNpw7NuDQojIG5vIHB1ZWRlIHRlbmVyIGVsIHZhbG9yICJBbWVyaWNhcyIgeSAiQXNpYSIgYWwgbWlzbW8gdGllbXBvLg0KZmlsdGVyKGdhcG1pbmRlciwgY29udGluZW50ID09ICJBbWVyaWNhcyIsIGNvbnRpbmVudCA9PSAiQXNpYSIpDQpgYGANCg0KVW4gw7psdGltbyBwdW50byBjb24gcmVzcGVjdG8gYSBsYSBmdW5jacOzbiBgZmlsdGVyYCB5IGxhcyBjb25kaWNpb25lcyBsw7NnaWNhcyBlcyBlbCB1c28gZGVsIG9wZXJhZG9yIGAlaW4lYC4gUGFyYSBpbHVzdHJhciBsYXMgYm9uZGFkZXMgZGUgZXN0ZSBudWV2byBvcGVyYWRvciwgZGVzY3JpYmFtb3MgZWwgY2FzbyB0ZWRpb3NvIGVuIHF1ZSBkZXNlYW1vcyBmaWx0cmFyIGxhcyBvYnNlcnZhY2lvbmVzIHF1ZSBwZXJ0ZW5lemNhbiBhbCBjb250aW5lbnRlIGFtZXJpY2FubyBvIGFzacOhdGljbyBvIGV1cm9wZW8uIFNlZ8O6biBsbyBkaXNjdXRpZG8gYW50ZXJpb3JtZW50ZSwgZXN0byBlcXVpdmFsZHLDrWEgYSBlbXBsZWFyIGxhIGNvbmRpY2nDs24gbMOzZ2ljYSBgY29udGluZW50ID09ICJBbWVyaWNhcyIgfCBjb250aW5lbnQgPT0gIkFzaWEiIHwgY29udGluZW50ID09ICJFdXJvcGUiYCBkZW50cm8gZGUgbGEgZnVuY2nDs24gYGZpbHRlcmA6DQoNCmBgYHtyIGVjaG89VFJVRX0NCmZpbHRlcihnYXBtaW5kZXIsIGNvbnRpbmVudCA9PSAiQW1lcmljYXMiIHwgY29udGluZW50ID09ICJBc2lhIiB8IGNvbnRpbmVudCA9PSAiRXVyb3BlIikNCmBgYA0KDQpFbCBvcGVyYWRvciBgJWluJWAgbm9zIHBlcm1pdGlyYSBlc2NyaWJpciBsYSBvcGVyYWNpw7NuIGFudGVyaW9yIGRlIGxhIHNpZ3VpZW50ZSBmb3JtYToNCg0KYGBge3IgZWNobz1UUlVFfQ0KZmlsdGVyKGdhcG1pbmRlciwgY29udGluZW50ICVpbiUgYygiQW1lcmljYXMiLCAiQXNpYSIsICJFdXJvcGUiKSkNCmBgYA0KDQpFc3RlIG9wZXJhZG9yIGV2YWzDumEgZW4gY2FkYSBvYnNlcnZhY2nDs24gZGUgYGdhcG1pbmRlcmAsIHNlIGVsIHZhbG9yIGRlIGxhIHZhcmlhYmxlIGBjb250aW5lbnRgIHNlIGVuY3VlbnRyYSBlbiBhbGd1bm8gZGUgbG9zIGVsZW1lbnRvcyBkZWwgdmVjdG9yIGRlZmluaWRvIGNvbW8gYGMoIkFtZXJpY2FzIiwgIkFzaWEiLCAiRXVyb3BlIilgLiBQb3IgYWhvcmEsIGJhc3RhIGNvbiBlbnRlbmRlciBxdWUgdW4gdmVjdG9yIGVzIHNpbXBsZW1lbnRlIHVuIGNvbmp1bnRvIGRlIGVsZW1lbnRvcyBkZWwgbWlzbW8gdGlwbywgZW4gZXN0ZSBjYXNvLCB0b2RvcyBsb3MgZWxlbWVudG9zIHNvbiB1biBjYXLDoWN0ZXIuDQoNCk11Y2hhcyB2ZWNlcyBlcyDDunRpbCBjb21iaW5hciBlbCBvcGVyYWRvciBkZSBuZWdhY2nDs24gYCFgIGp1bnRvIGEgbGEgY29uZGljacOzbiBsw7NnaWNhIGNvbXB1ZXN0YSBwb3IgZWwgb3BlcmFkb3IgYCVpbiVgIGRlIGxhIHNpZ3VpZW50ZSBmb3JtYToNCg0KYGBge3J9DQojIEZpbHRyYXIgdG9kYXMgbGFzIG9ic2VydmFjaW9uZXMgcXVlIG5vIGVzdGVuIGVuIGxvcyBzaWd1aWVudGVzIGNvbnRpbmVudGVzOg0KZmlsdGVyKGdhcG1pbmRlciwgIShjb250aW5lbnQgJWluJSBjKCJBbWVyaWNhcyIsICJBc2lhIiwgIkV1cm9wZSIpKSkNCmBgYA0KDQoNCiMjIyBzZWxlY3Q6IHNlbGVjY2lvbmFyIHZhcmlhYmxlcyBwb3Igc3Ugbm9tYnJlDQoNCkVsIHZlcmJvIGBzZWxlY3RgIGVzIG3DoXMgc2ltcGxlIGRlIGVudGVuZGVyLiBMYSBhY2Npw7NuIHF1ZSBlamVjdXRhIHNvYnJlIHVuICpkYXRhZnJhbWUqIGVzIGxhIGRlIHNlbGVjY2lvbmFyIHZhcmlhYmxlcyBwb3Igc3Ugbm9tYnJlLiBBbCBpZ3VhbCBxdWUgYGZpbHRlcmAsIGVsIG5vbWJyZSBkZSBsYXMgdmFyaWFibGVzIG5vIGRlYmUgaXIgcm9kZWFkbyBwb3IgY29taWxsYXMuDQoNClZlYW1vcyBlbCBub21icmUgZGUgbGFzIHZhcmlhYmxlcyBjb250ZW5pZGFzIGVuIGBnYXBtaW5kZXJgLg0KDQpgYGB7cn0NCm5hbWVzKGdhcG1pbmRlcikNCmBgYA0KDQpJbWFnaW5lbW9zIHF1ZSBkZSBsYSB0YWJsYSBgZ2FwbWluZGVyYCBzb2xvIG5vcyBpbnRlcmVzYW4gbGFzIHZhcmlhYmxlcyBgY291bnRyeWAsIGB5ZWFyYCB5IGBsaWZlRXhwYC4NCg0KYGBge3IgZWNobz1UUlVFfQ0Kc2VsZWN0KGdhcG1pbmRlciwgY291bnRyeSwgeWVhciwgbGlmZUV4cCkNCmBgYA0KDQpFc3RvIHF1ZSBlcyB1bmEgc2ltcGxlIHNlbGVjY2nDs24sIG11Y2hhcyB2ZWNlcyBlcyBsYSBpbXBsZW1lbnRhY2nDs24gZGUgdW5hIHNpbXBsZSB0w6ljbmljYSBxdWUgZXMgZm9jYWxpemFyIGVsIGFuw6FsaXNpcyBlbiB1bmEgZGltZW5zacOzbiBtw6FzIHJlZHVjaWRhIGRlIGxvcyBkYXRvcy4gRXZpZGVudGVtZW50ZSBlbCBjb3N0byBkZSBkaXNtaW51aXIgbGEgY29tcGxlamlkYWQgZGUgbnVlc3Ryb3MgZGF0b3MgZGVzY2FydGFuZG8gdmFyaWFibGVzIGVzIGVsIGRlIGxhIHDDqXJkaWRhIGRlIGluZm9ybWFjacOzbi4NCg0KUG9kZW1vcyB1dGlsaXphciBgc2VsZWN0YCBwYXJhIGRlc2NhcnRhciB2YXJpYWJsZXMsIGVzdG8gYW50ZXBvbmllbmRvIHVuIHNpZ25vIGAtYCBlbiBlbCBub21icmUgZGUgbGEgdmFyaWFibGUgYSBkZXNjYXJ0YXIuDQoNCmBgYHtyLCBlY2hvID0gVFJVRX0NCiMgVG9kYXMgbGFzIHZhcmlhYmxlcyBtZW5vcyBsaWZlRXhwLg0Kc2VsZWN0KGdhcG1pbmRlciwgLWxpZmVFeHApDQpgYGANCg0KVW5hIGZvcm1hIHLDoXBpZGEgcGFyYSBldml0YXIgdGlwZWFyIGVsIG5vbWJyZSBkZSBtdWNoYXMgdmFyaWFibGVzLCBlcyBjcmVhciByYW5nb3MgZGUgc2VsZWNjacOzbiBlbiB2YXJpYWJsZXMgcXVlIHNlIHF1aWVyZW4gc2VsZWNjaW9uYXIgeSBzZSBlbmN1ZW50cmFuIGRlIGZvcm1hIGNvbnRpbnVhIGVuIGxhIHRhYmxhLiBQb3IgZWplbXBsbywgZW4gYGdhcG1pbmRlcmAgc8OtIHF1aXNpZXJhIGVzY29nZXIgbGFzIHZhcmlhYmxlcyBgeWVhcmAgYSBgZ2RwUGVyY2FwYCBwb2RyP2Ftb3MgZXNjcmliaXIgZXN0YSBzZWxlY2Npw7NuIHBvciByYW5nbyBjb21vIGB5ZWFyOmdkcFBlcmNhcGAuIA0KDQpgYGB7ciBlY2hvPVRSVUV9DQojIFNlbGVjY2lvbmFyIGxhcyB2YXJpYWJsZXMgcXVlIHNlIGVuY3VlbnRyYW4gZW50cmUgeWVhciB5IGdkcFBlcmNhcCBpbmNsdXNpdmUuDQpzZWxlY3QoZ2FwbWluZGVyLCB5ZWFyOmdkcFBlcmNhcCkNCmBgYA0KDQpPdHJvcyB1c28gZGUgbGEgZnVuY2nDs24gYHNlbGVjdGAgZXMgcGFyYSByZWFjb21vZGFyIGVsIG9yZGVuIGRlIGxhcyB2YXJpYWJsZXMuIEEgdmVjZXMsIGVzdG8gcHVlZGUgc2VyIHRlZGlvc28gc8OtIHNvbG8gcXVpc2llcmFtb3MgbW92ZXIgbGEgdmFyaWFibGUgYHllYXJgIGEgbGEgcHJpbWVyYSBjb2x1bW5hIHkgZGVqYXIgZWwgcmVzdG8gZGUgbGFzIHZhcmlhYmxlcyBjb24gZWwgbWlzbW8gb3JkZW4uIEVzdG8gaW1wbGljYXLDrWEgZXNjcmliaXIgZWwgc2lndWllbnRlIGPDs2RpZ286DQoNCmBgYHtyfQ0Kc2VsZWN0KGdhcG1pbmRlciwgeWVhciwgY291bnRyeSwgY29udGluZW50LCBsaWZlRXhwLCBwb3AsIGdkcFBlcmNhcCkNCmBgYA0KDQpMYSBleGlzdGVuY2lhIGRlIGxhIGZ1bmNpw7NuIGF1eGlsaWFyIGBldmVyeXRoaW5nYCBwYXJhIHVzYXIgZW4gY29uanVudG8gY29uIGBzZWxlY3RgIGZhY2lsaXRhIGVzdGUgdGlwbyBkZSB0YXJlYSBhbCByZWFsaXphciBsYSBtaXNtYSBvcGVyYWNpw7NuIGRlIGZvcm1hIG3DoXMgY29uY2lzYToNCg0KYGBge3J9DQojIERlYmVtb3MgaW5jbHVpciBsb3MgcGFyZW50ZXNpcyBwYXJhIGxsYW1hciBhIGxhIGZ1bmNpP24gZXZlcnl0aGluZygpIQ0Kc2VsZWN0KGdhcG1pbmRlciwgeWVhciwgZXZlcnl0aGluZygpKQ0KYGBgDQoNCkV4aXN0ZW4gbcOhcyBmdW5jaW9uZXMgYXV4aWxpYXJlcyBxdWUgc29uIGNvbnZlbmllbnRlcyBkZSB1c2FyIGVuIGNvbmp1bnRvIGNvbiBgc2VsZWN0YCBjb21vOg0KDQotIGBzdGFydHNfd2l0aCgicHJlZmlqbyIpYDogc2VsZWNjaW9uYXIgdmFyaWFibGVzIHF1ZSBjb21wYXJ0YW4gaWd1YWwgcHJlZmlqby4NCi0gYGVuZHNfd2l0aCgic3VmaWpvIilgOiBzZWxlY2Npb25hciB2YXJpYWJsZXMgcXVlIGNvbXBhcnRhbiBpZ3VhbCBzdWZpam8uDQotIGBjb250YWlucygicGF0cm9uIilgOiBzZWxlY2Npb25hciB2YXJpYWJsZXMgcXVlIGNvbnRlbmdhbiB1biBwYXRyw7NuIGNvbcO6bi4NCg0KIyMjIG11dGF0ZTogcGFyYSBjcmVhciBudWV2YXMgdmFyaWFibGVzDQoNCkVsIHZlcmJvIGBtdXRhdGVgIG5vcyBwZXJtaXRlIGNyZWFyIHVuYSBudWV2YSB2YXJpYWJsZSBlbiBudWVzdHJvICpkYXRhZnJhbWUqIHF1ZSBzZSBhZGp1bnRhIGNvbW8gY29sdW1uYSBhbCBmaW5hbCBkZSBsYSB0YWJsYS4NCg0KSWx1c3RyZW1vcyBlbCB1c28gZGUgYG11dGF0ZWAgY3JlYW5kbyBsYSBudWV2YSB2YXJpYWJsZSBgcG9wTWlsbGlvbnNgIGVuIGxhIHRhYmxhIGBnYXBtaW5kZXJgLg0KDQpgYGB7cn0NCiMgQ3JlYXIgdW5hIHZhcmlhYmxlIGNvbiBsYSBwb2JsYWNpP24gZW4gbWlsbG9uZXMuDQptdXRhdGUoZ2FwbWluZGVyLCBwb3BNaWxsaW9ucyA9IHBvcCAvIDFlNikgIyAxZTYgPSAxMDAwMDAwDQpgYGANCg0KRWwgZWplbXBsbyBhbnRlcmlvciBlcyBzaW1wbGVtZW50ZSBjYW1iaWFyIGxhIHVuaWRhZCBkZSBtZWRpZGEgZGUgdW5hIHZhcmlhYmxlIHlhIGV4aXN0ZW50ZS4gRW4gY2FzbyBkZSBxdWUgY29uc2VydmFyIGxhIHZhcmlhYmxlIG9yaWdpbmFsIGBwb3BgIG5vIG5vcyBpbnRlcmVzZSwgcG9kZW1vcyBzb2JyZWVzY3JpYmlyIGVzdGEgZGlyZWN0YW1lbnRlIGVuIGxhIGRlZmluaWNpw7NuIGRlIGBtdXRhdGVgOg0KDQpgYGB7cn0NCm11dGF0ZShnYXBtaW5kZXIsIHBvcCA9IHBvcCAvIDFlNikNCmBgYA0KDQpVbiBlamVtcGxvIG3DoXMgaW50ZXJlc2FudGUgZGUgYG11dGF0ZWAgZXMgZWwgc2lndWllbnRlIHF1ZSBpbnZvbHVjcmEgbcOhcyBkZSB1bmEgdmFyaWFibGUgZGUgYGdhcG1pbmRlcmAuDQoNCmBgYHtyfQ0KIyBDb21wdXRhciBlbCBQSUIgcG9yIGNhZGEgb2JzZXJ2YWNpP24gYSBwYXJ0aXIgZGVsIFBJQiBwZXIgY2FwaXRhIHkgbGEgcG9ibGFjaT9uLg0KbXV0YXRlKGdhcG1pbmRlciwgZ2RwID0gcG9wICogZ2RwUGVyY2FwKQ0KYGBgDQoNCk90cmEgY2FyYWN0ZXJpc3RpY2EgZGUgYG11dGF0ZWAgZXMgcXVlIHBvZGVtb3MgY3JlYXIgbcOhcyBkZSB1bmEgdmFyaWFibGUsIGluY29ycG9yYW5kbyBjYWRhIGNyZWFjacOzbiBlbiB1biBudWV2byBhcmd1bWVudG8uIEFkZW3DoXMsIHBvZGVtb3MgdXRpbGl6YXIgdmFyaWFibGVzIG51ZXZhcyBxdWUgZnVlcm9uIGNyZWFkYXMgZW4gYWxnw7puIGFyZ3VtZW50byBhbnRlcmlvciBlbiBvdHJvIGFyZ3VtZW50byBkZW50cm8gZGVsIG1pc21vIGxsYW1hZG8gZGUgbGEgZnVuY2nDs24gYG11dGF0ZWAuDQoNCmBgYHtyfQ0KbXV0YXRlKGdhcG1pbmRlciwgZ2RwID0gcG9wICogZ2RwUGVyY2FwLCAgIyBjcmVvIGdkcCBwcmltZXJvDQogICAgICAgICAgICAgICAgICBnZHBNaWxsaW9uID0gcm91bmQoZ2RwIC8gMWU5LCAyKSkgIyBhaG9yYSBnZHAgZW4gbWlsZXMgZGUgbWlsbG9uZXMNCmBgYA0KDQoNClBvZGVtb3MgdXRpbGl6YXIgZnVuY2lvbmVzIGVuIGNvbmp1bnRvIGNvbiBgbXV0YXRlYCBwYXJhIGNyZWFyIGxhcyBudWV2YXMgdmFyaWFibGVzOg0KDQpgYGB7cn0NCm11dGF0ZShnYXBtaW5kZXIsIHBvc185MCA9IGlmZWxzZSh5ZWFyID4gMTk5MCwgVFJVRSwgRkFMU0UpKQ0KYGBgDQoNCioqRXMgaW1wb3J0YW50ZSBlbnRlbmRlciBxdWUqKiBgbXV0YXRlYCAqKmVzdGEgZGlzZcOxYWRvIHBhcmEgYWdyZWdhciBudWV2YXMgdmFyaWFibGVzIGEgbGEgdGFibGEgcXVlIHNlIGxlIGVudHJlZ2EsIHBvciBlc3RvIG1pc21vLCBsYSB2YXJpYWJsZSBjcmVhZGEgZGViZSBzZXIgZGVsIG1pc21vIHRhbWE/byBxdWUgZWwgcmVzdG8gZGUgbGFzIHZhcmlhYmxlcy4qKiBObyBzZSBwdWVkZSAiZGVzY3VhZHJhciIgbGEgZGF0YSByZWN0YW5ndWxhciwgYWwgdGVuZXIgdW5hIHZhcmlhYmxlIGNvbiBtw6FzIG8gbWVub3Mgb2JzZXJ2YWNpb25lcyBxdWUgbGFzIHZhcmlhYmxlcyByZXN0YW50ZXMuDQoNCkVuIGzDrW5lYSBjb24gbG8gYW50ZXJpb3IsIGVzIGltcG9ydGFudGUgdGVuZXIgcHJlc2VudGUgbG8gcXXDqSBwYXNhIGN1YW5kbyBoYXkgdW5hIGZ1bmNpw7NuIGludm9sdWNyYWRhIGVuIGxhIGNyZWFjacOzbiBkZSB1bmEgbnVldmEgdmFyaWFibGUgZGVudHJvIGRlIGBtdXRhdGVgLCBxdWUgZGV2dWVsdmUgbWVub3MgdmFsb3JlcyBkZSBsb3MgcXVlIHNlIGxlIGVudHJlZ2FuLiBFcyBkZWNpciwgbGUgZW50cmVnbyB1bmEgdmFyaWFibGUgY29tbyBgZ2RwUGVyY2FwYCBxdWUgdGllbmUgYHIgbnJvdyhnYXBtaW5kZXIpYA0Kb2JzZXJ2YWNpb25lcyB5IGxhIGZ1bmNpw7NuLCBxdWUgcHVlZGUgc2VyIHBvciBlamVtcGxvIGBtZWFuYCwgbWUgZW50cmVnYSB1biBzb2xvIHZhbG9yIHF1ZSBlcyBlbCBwcm9tZWRpbyBkZSBlc3RhcyBgciBucm93KGdhcG1pbmRlcilgIG9ic2VydmFjaW9uZXMgcXVlIGNvcnJlc3BvbmRlIGEgYHIgcm91bmQobWVhbihnYXBtaW5kZXIkZ2RwUGVyY2FwKSwgMylgLg0KDQoNCmBgYHtyfQ0KbXV0YXRlKGdhcG1pbmRlciwgYXZnX2dkcFBlcmNhcCA9IG1lYW4oZ2RwUGVyY2FwKSkNCmBgYA0KDQpFbiBlbCBjYXNvIGFudGVyaW9yLCBgbXV0YXRlYCByZWNpY2xhIGVsIHZhbG9yIGByIHJvdW5kKG1lYW4oZ2FwbWluZGVyJGdkcFBlcmNhcCksIDMpYCwgcmVwaXRpZW5kbyBlc3RlIHRhbnRhcyB2ZWNlcyBjb21vIG7Dum1lcm8gZGUgZmlsYXMgdGVuZ2EgbGEgdGFibGEgeSBhc8OtIG1hbnRlbmVyIGxhIGNvbnNpc3RlbmNpYSBkZSBsYSBkYXRhIHJlY3Rhbmd1bGFyLg0KDQojIyMgc3VtbWFyaXNlOiBwYXJhIHJlc3VtaXIgdmFsb3Jlcw0KDQpFbCB2ZXJibyBgc3VtbWFyaXNlYCBmdW5jaW9uYSBzaW1pbGFyIGEgYG11dGF0ZWAgcGVybyBjb24gZWwgb2JqZXRpdm8gZGUgY3JlYXIgKip2YXJpYWJsZXMgcmVzdW1lbmVzKiouIEVzdGFzIHNlIGNyZWFuIGEgcGFydGlyIGRlIGZ1bmNpb25lcyBxdWUgdG9tYW4gdW4gZ3J1cG8gZGUgdmFsb3JlcyB5IGVudHJlZ2FuIHVuIHNvbG8gdmFsb3IuIEVqZW1wbG8gZGUgZXN0ZSB0aXBvIGRlIGZ1bmNpb25lcyBzb246DQoNCi0gYGNvdW50YA0KLSBgc3VtYA0KLSBgbWVhbmANCi0gYG1lZGlhbmANCi0gYHNkYA0KLSBgbWF4YA0KLSBgbWluYA0KDQpVbiBjYXNvIGFwbGljYWRvIGRlIGBzdW1tYXJpc2VgIHNvYnJlIGBnYXBtaW5kZXJgIHB1ZWRlIHNlciBlbCBjw6FsY3VsbyBwcm9tZWRpbyBkZSBleHBlY3RhdGl2YSBkZSB2aWRhLg0KDQpgYGB7ciwgZWNobyA9IFRSVUV9DQpzdW1tYXJpc2UoZ2FwbWluZGVyLCBhdmdMaWZlRXhwID0gbWVhbihsaWZlRXhwKSkNCmBgYA0KDQpMYSBzaW50YXhpcyBkZSBgc3VtbWFyaXNlYCBlcyBzw61taWwgYSBsYSBkZSBgbXV0YXRlYCwgcHJpbWVybyB5IGNvbW8gdG9kb3MgbG9zIHZlcmJvcywgZGFtb3MgZWwgbm9tYnJlIGRlIG51ZXN0cmEgZGF0YSByZWN0YW5ndWxhci4gU2VndW5kbywgZXNjcmliaW1vcyBlbCBub21icmUgZGUgbGEgbnVldmEgdmFyaWFibGUgcmVzdW1lbiAoYGF2Z0xpZmVFeHBgKSBzZWd1aWRvIGRlIGA9YCB5IGxhIG9wZXJhY2nDs24gbyBhY2Npw7NuIHNvYnJlIHZhcmlhYmxlcyB5YSBleGlzdGVudGUgZW4gbGEgZGF0YSBlbnRyZWdhZGEgKGBsaWZlRXhwYCkuIFRhbWJpZW4gc2UgcHVlZGVuIGNyZWFyIG3DoXMgZGUgdW5hIHZhcmlhYmxlIHJlc3VtZW4gZW4gdW4gbWlzbW8gbGxhbWFkbyBkZSBsYSBmdW5jacOzbiBgc3VtbWFyaXNlYC4NCg0KYGBge3IsIGVjaG8gPSBUUlVFfQ0Kc3VtbWFyaXNlKGdhcG1pbmRlciwgDQogICAgICAgICAgYXZnTGlmZUV4cCA9IG1lYW4obGlmZUV4cCksDQogICAgICAgICAgbnVtT2JzID0gbigpKQ0KYGBgDQoNCkxhIGZ1bmNpw7NuIGBuKClgIGN1ZW50YSBlbCBuw7ptZXJvIGRlIG9ic2VydmFjaW9uZXMgZW4gbGEgdGFibGEuIEVuIGdlbmVyYWwsIGBzdW1tYXJpc2VgIHRpZW5lIG1heW9yIHV0aWxpZGFkIGVuIGNvbmp1bnRvIGRlIGBncm91cF9ieWAsIGNvbW8gdmVyZW1vcyBtw6FzIGFkZWxhbnRlLg0KDQojIyMgZ3JvdXBfYnk6IHBhcmEgY2FtYmlhciBlbCBkb21pbmlvIGRlIGFjY2nDs24gZGUgbG9zIHZlcmJvcw0KDQrCv1F1w6kgcGFzYSBzw60gcXVlcmVtb3MgZWwgcHJvbWVkaW8gZGUgYGxpZmVFeHBgIHBlcm8gYWhvcmEgcG9yIGNvbnRpbmVudGU/IMK/byBmaWx0cmFyIG9ic2VydmFjaW9uZXMgcXVlIGN1bXBsYW4gY2llcnRhIGNvbmRpY2nDs24gbMOzZ2ljYSBwZXJvIHBhcmEgY2FkYSB1bm8gZGUgbG9zIGRpc3RpbnRvcyBhw7FvcyAoYHllYXJgKSBkZSBudWVzdHJhIGRhdGEgYGdhcG1pbmRlcmA/DQoNCmBncm91cF9ieWAgc2Vyw6EgbGEgcGllemEgcXVlIGFjdHVhcsOhIGNhbWJpYW5kbyBlbCBkb21pbmlvIGVuIHF1ZSBzZSBlamVjdXRhIGNhZGEgdmVyYm8uIFJlc3BvbmRhbW9zIGxhIHByaW1lcmEgaW50ZXJyb2dhbnRlLCBuZWNlc2l0YW1vcyBhZ3J1cGFyIChgZ3JvdXBfYnlgKSBwb3IgY29udGluZW50ZSAoYGNvbnRpbmVudGApIHBhcmEgZWplY3V0YXIgZWwgdmVyYm8gYHN1bW1hcmlzZWAgeSBjcmVhciBsYSB2YXJpYWJsZSBleHBlY3RhdGl2YSBkZSB2aWRhIHByb21lZGlvIChgYXZnTGlmZUV4cGApLg0KDQpgYGB7cn0NCiMgY2FtYmlhbW9zIGVsIGRvbWluaW8gZGUgZWplY3VjacOzbiAobyBhbsOhbGlzaXMpIGRlIGxvcyB2ZXJib3MNCnBvcl9jb250aW5lbnRlIDwtIGdyb3VwX2J5KGdhcG1pbmRlciwgY29udGluZW50KQ0KDQojIGVuIHZleiBkZSBhcGxpY2FyIGxvcyB2ZXJib3Mgc29icmUgZ2FwbWluZGVyLCBsbyBoYWNlbW9zIHNvYnJlDQojIHBvcl9jb250aW5lbnRlDQpzdW1tYXJpc2UocG9yX2NvbnRpbmVudGUsIGF2Z0xpZmVFeHAgPSBtZWFuKGxpZmVFeHApKQ0KYGBgDQoNCkFib3JkZW1vcyBhaG9yYSB1bmEgaW50ZXJyb2dhbnRlIGNvbW8gbGEgc2VndW5kYSBwbGFudGVhZGEsIGRpZ2Ftb3MgcXVlIHF1ZXJlbW9zIGVuY29udHJhciBlbCBwYcOtcyAoYGNvdW50cnlgKSBjb24gbWF5b3IgZXhwZWN0YXRpdmEgZGUgdmlkYSAoYGxpZmVFeHBgKSBwb3IgYcOxbyAoYHllYXJgKS4NCg0KDQpgYGB7cn0NCnBvcl9wZXJpb2RvIDwtIGdyb3VwX2J5KGdhcG1pbmRlciwgeWVhcikNCmZpbHRlcihwb3JfcGVyaW9kbywgbGlmZUV4cCA9PSBtYXgobGlmZUV4cCkpDQpgYGANCg0KRWwgYGZpbHRlcmAgYXBsaWNhZG8gc29icmUgbGEgZGF0YSBhZ3J1cGFkYSBgcG9yX3BlcmlvZG9gLCBhcnJvasOzIDEyIG9ic2VydmFjaW9uZXMuIFBvZGVtb3MgY29ycm9ib3JhciBxdWUgbnVlc3RyYSBvcGVyYWNpw7NuIGVzdHV2byBjb3JyZWN0YSBzw60gYW5hbGl6YW1vcyBjdWFudG9zIGHDsW9zIGRpZmVyZW50ZXMgaGF5IGVuIGBnYXBtaW5kZXJgIHkgcGFyYSBlc3RvIHBvZGVtb3MgdXRpbGl6YXIgb3RyYSBmdW5jacOzbiBkZSBkcGx5ciBsbGFtYWRhIGBkaXN0aW5jdGAuDQoNCmBgYHtyfQ0KIyBub3MgYXJyb2plIGxvcyB2YWxvcmVzIMO6bmljb3MgZGUgbGEgdmFyaWFibGUgeWVhciBkZSBsYSB0YWJsYSBnYXBtaW5kZXINCmRpc3RpbmN0KGdhcG1pbmRlciwgeWVhcikNCmBgYA0KDQoNCkVmZWN0aXZhbWVudGUsIGVsIHZlcmJvIGBmaWx0ZXJgIG5vcyBlbnRyZWdvIHBhcmEgY2FkYSB1bm8gZGUgbG9zIGHDsW9zIGNvbnRlbmlkb3MgKGBwb3JfcGVyaW9kb2ApIGVuIGxhIGJhc2UgYGdhcG1pbmRlcmAsIGxhIG9ic2VydmFjacOzbiBjb24gbWF5b3IgZXhwZWN0YXRpdmEgZGUgdmlkYSBgbGlmZUV4cGAuDQoNCiMjIyBhcnJhbmdlOiBwYXJhIG9yZGVuYXIgb2JzZXJ2YWNpb25lcw0KDQpBIHZlY2VzIHF1ZXJlbW9zIG9yZGVuYXIgbnVlc3RyYSBkYXRhIHJlY3Rhbmd1bGFyIGVuIGJhc2UgYSB1bmEgbyBtw6FzIHZhcmlhYmxlcy4gRXN0byBlcyDDunRpbCBwYXJhIHNhYmVyIHF1ZSBvYnNlcnZhY2nDs24gZXMgbGEgbWVub3IgbyBtYXlvciBjb24gcmVzcGVjdG8gYWxndW5hIHZhcmlhYmxlLiBQYXJhIGVzdGUgdGlwbyBkZSB0YXJlYXMgZXMgw7p0aWwgZWwgdmVyYm8gYGFycmFuZ2VgLg0KDQpOb3MgZ3VzdGFyw61hIG9yZGVuYXIgYGdhcG1pbmRlcmAgcG9yIGxhIHZhcmlhYmxlIGB5ZWFyYC4NCg0KYGBge3IsIGVjaG8gPSBUUlVFfQ0KYXJyYW5nZShnYXBtaW5kZXIsIHllYXIpDQpgYGANCg0KUG9kZW1vcyBpbmNvcnBvcmFyIG90cmEgdmFyaWFibGUgcGFyYSBvcmRlbmFyIGRlbnRybyBkZSBjYWRhIGHDsW8uIE9yZGVuZW1vcyBsdWVnbyBkZSBgeWVhcmAgcG9yIGBsaWZlRXhwYCB0YW1iaWVuIGVuIG9yZGVuIGFzY2VkZW50ZSwgZXMgZGVjaXIsIGRlIG1lbm9zIGEgbWFzIGVuIGNhc28gZGUgYGxpZmVFeHBgLCBkZSBsbyBwYXNhZG8gYSBsbyBtw6FzIGFjdHVhbCBlbiBjYXNvIGRlIGB5ZWFyYC4NCg0KYGBge3IsIGVjaG8gPSBUUlVFfQ0KYXJyYW5nZShnYXBtaW5kZXIsIHllYXIsIGxpZmVFeHApDQpgYGANCg0KUG9kZW1vcyBvYnNlcnZhciBxdWUgZW4gZWwgYcOxbyAxOTUyLCBlbCBwYcOtcyBjb24gbWVub3IgZXhwZWN0YXRpdmEgZGUgdmlkYSBmdWUgQWZnaGFuaXN0YW4uIFNpIHF1aXNpZXJhbW9zIG9yZGVuYXIgZGUgdGFsIGZvcm1hIHF1ZSBsYXMgcHJpbWVyYXMgb2JzZXJ2YWNpb25lcyBkZSBgZ2FwbWluZGVyYCByZWZsZWplbiBsYSBzaXR1YWNpw7NuIGRlIGxvcyBwYcOtc2VzIG3DoXMgY2VyY2FubyBhIGxhIGFjdHVhbGlkYWQgY29uIHJlc3BlY3RvIGEgcXVlIHBhw61zIHR1dm8gbWVub3IgZXhwZWN0YXRpdmEgZGUgdmlkYSBgbGlmZUV4cGAuIFBhcmEgZXN0YSB0YXJlYSwgcG9kZW1vcyB1dGlsaXphciBsYSBmdW5jacOzbiBhdXhpbGlhciBgZGVzY2AgZW4gY29uanVudG8gY29uIGBhcnJhbmdlYC4NCg0KYGBge3IsIGVjaG8gPSBUUlVFfQ0KYXJyYW5nZShnYXBtaW5kZXIsIGRlc2MoeWVhciksIGxpZmVFeHApDQpgYGANCg0KRW4gZWwgYcOxbyAyMDA3LCBsYSBzaXR1YWNpw7NuIGRlIEFmZ2hhbmlzdGFuIG1lam9yw7MgYXVtZW50YW5kbyBhcHJveGltYWRhbWVudGUgMTUgYcOxb3MgbGEgZXhwZWN0YXRpdmEgZGUgdmlkYS4gU2luIGVtYmFyZ28sIGVzdGEgbWVqb3JhIHNpZ3VlIHNpZW5kbyBpbnN1ZmljaWVudGUgc8OtIGNvbnNpZGVyYW1vcyBxdWUgdHJhbnNjdXJyaWVyb24gYHIgMjAwNyAtIDE5NTJgIGHDsW9zIGRlc2RlIGxhIHByaW1lcmEgbWVkaWNpw7NuLg0KDQoNCiMjIENvbXBvbmVyIGNvbiBsb3MgdmVyYm9zIHkgbGEgaGlzdG9yaWEgZGUgUGluIFBvbg0KDQpFbiBlc3RhIHNlY2Npw7NuIGRpc2N1dGlyZW1vcyBhY2VyY2EgZGUgY29tbyBjb21wb25lciBvcGVyYWNpb25lcyBtw6FzIGNvbXBsZWphcyBzb2JyZSAqZGF0YWZyYW1lcyogcXVlIGxhcyBlamVyY2lkYXMgcG9yIHVuIHNvbG8gdmVyYm8uDQoNClN1cG9uZ2Ftb3MgcXVlIHRlbmVtb3MgZW4gbWVudGUgcmVhbGl6YXIgbGFzIHNpZ3VpZW50ZXMgb3BlcmFjaW9uZXMgc29icmUgbGEgZGF0YSBgZ2FwbWluZGVyYCBwYXJhIGNvbmNsdWlyIGNvbiB1biBncsOhZmljby4NCg0KMS4gRmlsdHJhciBzb2xvIGxhcyBvYnNlcnZhY2lvbmVzIGNvcnJlc3BvbmRpZW50ZXMgYGNvdW50cnlgIGlndWFsIENoaWxlLg0KMi4gU2VsZWNjaW9uYXIgbGFzIHZhcmlhYmxlcyBgeWVhcmAsIGBwb3BgIHkgYGdkcFBlcmNhcGANCjMuIENvbXB1dGFyIGxhIHZhcmlhYmxlIGBnZHBNaWxsaW9uYCBlbiBiYXNlIGEgYHBvcGAgeSBgZ2RwUGVyY2FwYC4NCjQuIEdyw6FmaWNhciBsYSBldm9sdWNpw7NuIGRlbCBQSUIgY29uIHJlc3BlY3RvIGEgbGEgdmFyaWFibGUgYHllYXJgIChncsOhZmljbyBkZSBsw61uZWEpLg0KDQpVbmEgZm9ybWEgZGUgcGFzYXIgbG8gcXVlIHRlbmVtb3MgZW4gbWVudGUgYSBsYSBjb25zb2xhLCBlcyBlbmZvY2Fyc2UgZW4gZWwgw7psdGltbyBwYXNvIHkgc2FiZXIgcXVlIHBhcmEgY3JlYXIgZWwgZ3LDoWZpY28gbmVjZXNpdGFtb3MgZW50cmVnYXJsZSBhIGxhIGZ1bmNpw7NuIGBnZ3Bsb3RgIHVuYSBkYXRhIGNvbiBsYXMgY2FyYWN0ZXJpc3RpY2FzIGRlc2VhZGFzLiBMdWVnbywgYcOxYWRpcmxlIHVuYSBjYXBhIGNvbiB1bmEgbMOtbmVhIGNvbW8gcmVwcmVzZW50YWNpw7NuIGRlIGxhcyB2YXJpYWJsZXMgYHllYXJgIHkgYGdkcE1pbGxpb25gIG1hcGVhZGFzIGFsIGVqZSB4IGUgeSByZXNwZWN0aXZhbWVudGUuIFBvciBsbyB0YW50bywgZWwgZXNxdWVsZXRvIHNpbXBsZSBkZSBudWVzdHJvIHByb2dyYW1hIHBhcmEgZWplY3V0YXIgbG9zIHBhc29zIGRlc2VhZG9zIGVzOg0KDQpgYGB7ciwgZXZhbCA9IEZBTFNFfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KZ2dwbG90KGRhdGEgPSBEQVRBX0NBUkFDVEVSSVNUSUNBU19ERVNFQURBUykNCiAgKyBnZW9tX2xpbmUobWFwcGluZyA9IGFlcyh4ID0geWVhciwgeSA9IGdkcE1pbGxpb24pKQ0KYGBgDQoNCg0KRW4gY3VhbnRvIGEgbGEgYERBVEFfQ0FSQUNURVJJU1RJQ0FTX0RFU0VBREFTYCwgZGViZW1vcyBwZW5zYXIgcXVlIGNhZGEgdmVyYm8gZW50cmVnYSB1biAqZGF0YWZyYW1lKiBtb2RpZmljYWRvLiBMdWVnbywgc8OtIGxlIGVudHJlZ28gZXN0ZSAqb3V0cHV0KiByZWNpYmlkbyBkZSB1biB2ZXJibyBhIG90cm8sIGVsIG51ZXZvIHZlcmJvIGVqZWN1dGFyw6Egc3UgYWNjacOzbiBzb2JyZSB1bmEgdGFibGEgeWEgbW9kaWZpY2FkYS4gUG9yIGxvIHRhbnRvLCBzaSBjb250aW51w7MgZXN0YSBjYWRlbmEgZW4gYWxnw7puIHB1bnRvIG9idGVuZHLDqSB1bmEgdGFibGEgY29uIHRvZGFzIGxhcyBjYXJhY3RlcmlzdGljYXMgZGVzZWFkYXMuDQoNCmBgYHtyLCBldmFsID0gRkFMU0UsIGVjaG8gPSBUUlVFfQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgSURFTlRJRklDQVIgQVJHVU1FTlRPUw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAgICAgICAgICAgICANCm11dGF0ZSggICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjICAgICAgICAgICAgICAgICAgIHwgbXV0YXRlDQogICAgICAgc2VsZWN0KCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyAgICAgICAgIHwgc2VsZWN0ICB8IGRhdGEzDQogICAgICAgICAgICAgIGZpbHRlciggICAgICAgICAgICAgICAgICAgICAgI3wgZmlsdGVyIHwgIGRhdGEyICB8IGRhdGEzDQogICAgICAgICAgICAgICAgICAgIGdhcG1pbmRlciwgICAgICAgICAgICAgI3wgZGF0YTEgIHwgIGRhdGEyICB8IGRhdGEzICANCiAgICAgICAgICAgICAgICAgICAgY291bnRyeSA9PSAiQ2hpbGUiICAgICAjfCBhcmcxICAgfCAgZGF0YTIgIHwgZGF0YTMNCiAgICAgICAgICAgICAgICAgICAgKSwgICAgICAgICAgICAgICAgICAgICAjICAgICAgICAgfCAgZGF0YTIgIHwgZGF0YTMNCiAgICAgICAgICAgICAgeWVhciwgcG9wLCBnZHBQZXJjYXAgICAgICAgICAjICAgICAgICAgfCAgYXJnMiAgIHwgZGF0YTMNCiAgICAgICAgICAgICAgKSwgICAgICAgICAgICAgICAgICAgICAgICAgICAjICAgICAgICAgICAgICAgICAgIHwgZGF0YTMNCiAgICAgIGdkcE1pbGxpb24gPSAoZ2RwUGVyY2FwICogcG9wKSAvIDFlNiAjICAgICAgICAgICAgICAgICAgIHwgYXJnMw0KKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgUGFyZW50ZXNpcyBkZWJlbiBlc3RhciAoKSENCmBgYA0KDQpJbnRlZ3JhbmRvIGVzdG9zIGRvcyBibG9xdWVzIGRlIGPDs2RpZ28gZW4gdW5vLg0KDQpgYGB7ciwgZWNobyA9IFRSVUV9DQpsaWJyYXJ5KGdncGxvdDIpIA0KZ2dwbG90KGRhdGEgPQ0KICAgICAgICBtdXRhdGUoDQogICAgICAgICAgICAgICBzZWxlY3QoDQogICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnYXBtaW5kZXIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3VudHJ5ID09ICJDaGlsZSIpLA0KICAgICAgICAgICAgICAgICAgICAgIHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgcG9wLA0KICAgICAgICAgICAgICAgICAgICAgIGdkcFBlcmNhcA0KICAgICAgICAgICAgICAgICAgICAgICksDQogICAgICAgICAgICAgICBnZHBNaWxsaW9uID0gKGdkcFBlcmNhcCAqIHBvcCkgLyAxZTYNCiAgICAgICAgICAgICAgKQ0KICAgICAgKSArDQogIGdlb21fbGluZShtYXBwaW5nID0gYWVzKHggPSB5ZWFyLCB5ID0gZ2RwTWlsbGlvbikpICANCg0KDQpgYGANCg0Kwr9Qb2RlbW9zIHJlYWxpemFyIGxhIHNlY3VlbmNpYSBkZSBvcGVyYWNpb25lcyBzb2JyZSBgZ2FwbWluZGVyYCBkZSBvdHJhIGZvcm1hPw0KDQpMYSBzZWd1bmRhIGFsdGVybmF0aXZhIGVzIGFzaWduYXIgZWwgcmVzdWx0YWRvIGRlIGNhZGEgdmVyYm8gYSB1bmEgdmFyaWFibGUgeSBsdWVnbyBpciB0cmFuc21pdGllbmRvIGVzdGEgZW4gcmVwcmVzZW50YWNpw7NuIGRlIGxhIG9wZXJhY2nDs24uDQoNCmBgYHtyLCBlY2hvID0gVFJVRX0NCmNoaWxlIDwtIGZpbHRlcihnYXBtaW5kZXIsIGNvdW50cnkgPT0gIkNoaWxlIikNCmNoaWxlMiA8LSBzZWxlY3QoY2hpbGUsIHllYXIsIHBvcCwgZ2RwUGVyY2FwKQ0KY2hpbGUzIDwtIG11dGF0ZShjaGlsZTIsIGdkcE1pbGxpb24gPSAoZ2RwUGVyY2FwICogcG9wKSAvIDFlNikNCmdncGxvdChkYXRhID0gY2hpbGUzKSArDQogIGdlb21fbGluZShtYXBwaW5nID0gYWVzKHggPSB5ZWFyLCB5ID0gZ2RwTWlsbGlvbikpDQpgYGANCg0KTGEgdGVyY2VyYSBhbHRlcm5hdGl2YSwgZXMgw7p0aWxpemFyIGVsIG9wZXJhZG9yIGAlPiVgIChjdHJsICsgc2hpZnQgKyBtKSwgbGxhbWFkbyAicGlwZSIsIHF1ZSAgUGluIFBvbiBub3MgY29udGFyw6EgdW4gcG9jbyBtw6FzLg0KDQpBbmFsaWNlbW9zIGVsIHByaW1lciBww6FycmFmbyBkZSBsYSBjYW5jacOzbiBkZSBQaW4gUG9uOg0KDQogICAgUGluIFBvbiBlcyB1biBtdcOxZWNvDQogICAgTXV5IGd1YXBvIHkgZGUgY2FydMOzbiwgZGUgY2FydMOzbiwNCiAgICBTZSBsYXZhIGxhIGNhcml0YQ0KICAgIENvbiBhZ3VhIHkgY29uIGphYsOzbiwgY29uIGphYsOzbg0KDQpUcmFkdXpjYW1vcyBlc3RvIHBhcmEgZWwgY29tcHV0YWRvciwgcXVlcmVtb3MgcXVlIFBpbiBQb24sIGVzdGUgbXXDsWVjbyBndWFwbyB5IGRlIGNhcnTDs24sIHNlIGxhdsOpIGxhIGNhcml0YSBjb24gYWd1YSB5IGNvbiBqYWLDs24uDQoNCkRlYmVtb3MgY3JlYXIgcHJpbWVybyBhbCBtdcOxZWNvIFBpbiBQb24geSBsYXMgY2FyYWN0ZXLDrXN0aWNhcyBxdWUgbG8gZGVzY3JpYmVuLg0KDQpgYGB7ciwgZXZhbCA9IEZBTFNFfQ0KcGluX3BvbiA8LSBtdcOxZWNvKGFwYXJpZW5jaWEgPSBndWFwbywgbWF0ZXJpYWwgPSBjYXJ0b24pDQpgYGANCg0KU8OtIHF1ZXJlbW9zIGVqZWN1dGFyIGxhIGFjY2nDs24gYGxhdmFyYCBzb2JyZSBlbCBtdcOxZWNvIFBpbiBQb24gcG9kZW1vcyB1dGlsaXphciBlc3RhIGNvbW8gdW5hIGZ1bmNpw7NuIGVxdWl2YWxlbnRlIGFsIHZlcmJvIGBzZWxlY3RgLCBzb2xvIHF1ZSBlbiBlc3RlIGNhc28gZWwgcmVzdWx0YWRvIG1vZGlmaWNhcsOhIGVsIGVzdGFkbyBoaWdpZW5pY28gZGUgUGluIFBvbiB5IG5vIHVuICpkYXRhZnJhbWUqLg0KDQpgYGB7ciwgZXZhbCA9IEZBTFNFfQ0KbGF2YXIocGluX3BvbiwgDQogICAgICBxdWUgPSBjYXJpdGEsIA0KICAgICAgY29tbyA9IGNvbl9hZ3VhX3lfY29uX2phYm9uKQ0KYGBgDQoNCkVsIG9wZXJhZG9yIHBpcGUgYCU+JWAsIHRvbWEgZWwgb2JqZXRvIHF1ZSBzZSBlbmN1ZW50cmEgYSBzdSBpenF1aWVyZGEgY29tbyBlbCBwcmltZXIgYXJndW1lbnRvIGRlIGxhIGZ1bmNpw7NuIHF1ZSBlc3RhIGEgbGEgZGVyZWNoYS4gRXMgZGVjaXIsIGBvYmpfaXpxICU+JSBhY2Npb25fZGVyZWNoYSgpID09IGFjY2lvbl9kZXJlY2hhKG9ial9penEpYC4gUG9yIGxvIHF1ZSBhcGxpY2FyIGxhIGFjY2nDs24gZGUgbGF2YXIgYSBQaW4gUG9uIHF1ZWRhcsOtYSBlc2NyaXRvIGRlIGxhIHNpZ3VpZW50ZSBmb3JtYToNCg0KYGBge3IsIGV2YWwgPSBGQUxTRX0NCnBpbl9wb24gJT4lIA0KICAgIGxhdmFyKHF1ZSA9IGNhcml0YSwNCiAgICAgICAgICBjb21vID0gY29uX2FndWFfeV9jb25famFib24pDQpgYGANCg0Kwr9RdcOpIGdhbm8gY29uIGVzdG8/IEVsIHZlcmRhZGVybyBwb2RlciBkZWwgb3BlcmFkb3IgYCU+JWAgc3VyZ2UgY3VhbmRvIGVzdGFtb3MgZW4gdW5hIHNpdHVhY2nDs24gc2ltaWxhciBhIGxhIGRlc2NyaXRhIGFsIHByaW5jaXBpbyBkZSBlc3RhIHNlY2Npw7NuLiBOb3MgZW5jb250cmFtb3MgY29uIG11bHRpcGxlcyBhY2Npb25lcyBxdWUgZWplY3V0YXIgc29icmUgdW4gb2JqZXRvIGNvbW8gdW4gKmRhdGFmcmFtZSouDQoNCkFuYWxpY2Vtb3Mgb3RybyBwYXJyYWZvIG3DoXMgZGUgbGEgY2FuY2nDs24gZGUgUGluIFBvbiBwYXJhIGVuY29udHJhciB1bmEgc2l0dWFjacOzbiBzaW1pbGFyOg0KDQogICAgUGluIFBvbiB0b21hIHN1IHNvcGENCiAgICBZIG5vIGVuc3VjaWEgZWwgZGVsYW50YWwNCiAgICBQdWVzIGNvbWUgY29uIGN1aWRhZG8NCiAgICBDb21vIHVuIGJ1ZW4gY29sZWdpYWwNCiAgICANCkVuIGVzdGUgcGFycmFmbywgYSBkaWZlcmVuY2lhIGRlbCBhbnRlcmlvciwgUGluIFBvbiBlamVjdXRhIGRvcyBhY2Npb25lcyBwcmluY2lwYWxlcyBgdG9tYXJgIHkgYGNvbWVyYC4gUG9kcmlhbW9zIGVzY3JpYmlyIGVsIGPDs2RpZ28gZW4gbGEgZm9ybWEgY2zDoXNpY2EgY29tbzoNCg0KYGBge3IsIGV2YWwgPSBGQUxTRX0NCmNvbWVyKA0KICAgICAgdG9tYXIoDQogICAgICAgICAgICBwaW5fcG9uLCANCiAgICAgICAgICAgIHF1ZSA9IHNvcGEpLA0KICAgICAgY29uID0gY3VpZGFkbywgDQogICAgICBjb21vID0gdW5fYnVlbl9jb2xlZ2lhbA0KICAgICAgKQ0KYGBgDQoNClPDrSB1dGlsaXphbW9zIGVsIG9wZXJhZG9yIGAlPiVgIHBhcmEgZXNjcmliaXIgbG8gbWlzbW86DQoNCmBgYHtyLCBldmFsID0gRkFMU0V9DQpwaW5fcG9uICU+JSANCiAgICAgICAgdG9tYXIocXVlID0gc29wYSkgJT4lIA0KICAgICAgICBjb21lcihjb24gPSBjdWlkYWRvLA0KICAgICAgICAgICAgICBjb21vID0gdW5fYnVlbl9jb2xlZ2lhbCkNCmBgYA0KDQpDYWRhIG9wZXJhZG9yIGAlPiVgIHZhIHRvbWFuZG8gZWwgb2JqZXRvIHF1ZSB0aWVuZSBhIHN1IGl6cXVpZXJkYSB5IGxvIGluZ3Jlc2EgY29tbyBlbCBwcmltZXIgYXJndW1lbnRvIGRlIGxhIGFjY2nDs24gYSBlamVjdXRhcnNlIHBvciBsYSBmdW5jacOzbiBhIGxhIGRlcmVjaGEgZGVsIG9wZXJhZG9yLiBFc3RvIGNvbW8gcmVzdWx0YWRvLCB0aWVuZSBkb3MgdmVudGFqYXM6DQoNCjEuIEVsIGPDs2RpZ28gZXMgbcOhcyBmw6FjaWwgZGUgbGVlciB5IGVudGVuZGVyLCBzaW1wbGVtZW50ZSBwYXJ0aW1vcyBjb24gbnVlc3RybyBvYmpldG8gaW5pY2lhbCB5IHZhbW9zIGFwbGljYW5kbyBhY2Npb25lcyBxdWUgbW9kaWZpY2FuIGEgZXN0ZSBvYmpldG8gZGUgYXJyaWJhIGhhY8OtYSBhYmFqby4NCg0KMi4gTm8gbmVjZXNpdGFtb3MgZ3VhcmRhciB2YXJpYWJsZXMgaW50ZXJtZWRpYXMgY29uIGxhcyBtb2RpZmljYWNpb25lcyBkZWwgb2JqZXRvLCBzaW1wbGVtZW50ZSBndWFyZGFtb3MgY3VhbmRvIGxsZWdhbW9zIGEgbGEgw7psdGltYSBtb2RpZmljYWNpw7NuIHF1ZSBub3MgaW50ZXJlc2EgYWxtYWNlbmFyIGVuIHVuYSB2YXJpYWJsZSBwYXJhIG9jdXBhciBkZXNwdcOpcy4NCg0KWWEgZGVqYW5kbyBkZXNjYW5zYXIgYSBQaW4gUG9uLCBhaG9yYSBwb2RlbW9zIG9jdXBhciBlc3RhIGZvcm1hIGRlIGVzY3JpYmlyIGPDs2RpZ28gcGFyYSBjcmVhciBudWVzdHJvIGdyw6FmaWNvOg0KDQpgYGB7cn0NCmdhcG1pbmRlciAlPiUgDQogIGZpbHRlcihjb3VudHJ5ID09ICJDaGlsZSIpICU+JSANCiAgc2VsZWN0KHllYXIsIHBvcCwgZ2RwUGVyY2FwKSAlPiUgDQogIG11dGF0ZShnZHBNaWxsaW9uID0gKGdkcFBlcmNhcCAqIHBvcCkgLyAxZTYpICU+JSANCiAgZ2dwbG90KCkgKw0KICAgIGdlb21fbGluZShtYXBwaW5nID0gYWVzKHggPSB5ZWFyLCB5ID0gZ2RwTWlsbGlvbikpDQpgYGANCg0KRWwgY8OzZGlnbyBhbnRlcmlvciBpbHVzdHJhIGxhcyB2ZW50YWphcyBkZWwgb3BlcmFkb3IgYCU+JWAgc29icmUgYWx0ZXJuYXRpdmFzIGFudGVyaW9yZXMuDQoNCiAgMS4gU29icmUgbGEgcHJpbWVyYSBhbHRlcm5hdGl2YSwgZXMgZXZpZGVudGUgcXVlIGVzIG3DoXMgZsOhY2lsIGxlZXIgbGEgZWplY3VjacOzbiBkZSBhY2Npb25lcyBkZSBtYW5lcmEgbGluZWFsLCBlbiBlbCBlamVtcGxvLCBkZSBhcnJpYmEgaGFjw61hIGFiYWpvIHNlIHZhbiBlamVjdXRhbmRvIGNhZGEgdW5vIGRlIGxvcyB2ZXJib3MuIEVuIGNhbWJpbywgbGEgcHJpbWVyYSBhbHRlcm5hdGl2YSBxdWUgdmltb3MsIHNlIHZhIGhhY2llbmRvIG3DoXMgY29tcGxlamEgZGUgbGVlciBhbCB0ZW5lciBtYXlvciBuw7ptZXJvIGRlIGFjY2lvbmVzIHBvcnF1ZSBkZWJlbW9zIGluaWNpYXIgdW5hIGxlY3R1cmEgZGUgImFkZW50cm8gaGFjw61hIGFmdWVyYSINCiAgDQogIDIuIFNvYnJlIGxhIHNlZ3VuZGEgYWx0ZXJuYXRpdmEsIGxhIGRlIGFsbWFjZW5hciBlbCByZXN1bHRhZG8gZGUgbGFzIGFjY2lvbmVzIGEgdmFyaWFibGVzIHBhcmEgbHVlZ28gcmVmZXJpcm5vcyBhIGVzdGFzIHBvciBzdSBub21icmUuIFRpZW5lIGEgdmVjZXMgZWwgcHJvYmxlbWEgZGUgb2JsaWdhcm5vcyBhIGd1YXJkYXIgcmVzdWx0YWRvcyBpbnRlcm1lZGlvcyBkZSBsb3MgcXVlIHBvciBzw60gbm8gdGVuZW1vcyBtdWNobyBpbnRlcmVzLiBFbCBvcGVyYWRvciBgJT4lYCBub3MgcHJvcG9uZSBsYSByZWdsYSBwYXJhIGNyZWFyIG9iamV0b3MgY29uIG5vbWJyZXMgY3VhbmRvIGVzdG9zIHJlYWxtZW50ZSBtZXJlY2VuIHRlbmVybG9zLCB5IGV2aXRhciBjcmVhciBvYmpldG9zIGludGVybWVkaW9zIGNvbW8gYGNoaWxlMSwgY2hpbGUyLCBjaGlsZTNgICBxdWUgc3Ugw7puaWNvIHByb3Bvc2l0byBlcyBsb2dyYXIgdW4gcGFzbyBwYXJhIG90cmEgYWNjacOzbiBkZSBsYSBjdWFsIHRlbmVtb3MgaW50ZXJlcyBlbiBzdSByZXN1bHRhZG8uDQo=