Visualización de Datos con ggplot2
La visualización de datos es una de las etapas fundamentales en el
análisis de datos porque se relaciona con la
comunicación de los resultados.
Una buena visualización permite:
- condensar mucha información
- evidenciar nuestro punto de vista
- contar historias con datos
ggplot2 es uno de los paquetes que está dentro de
tidyverse y es el paquete más utilizado para
hacer gráficos.
Podés consultar un cheatsheet
en castellano en este link.


El paquete ggplot2
es uno de los paquetes dentro de la
colección tidyverse
, y que está basado en la teoría de
“grammar of graphics” (la gramática de los gráficos),
porque permite construir los gráficos por capas, controlando las
características individuales de cada uno.
Esto implica que podemos controlar desde la
estructura del gráfico (títulos, ejes) hasta todo lo
que pasa dentro de la visualización.
Veamos en detalle cada una de las capas:
Data (Datos): La fuente de datos que usaremos
para graficar los datos.
Aesthetics (Estética): Son las modificaciones
estéticas que haremos asignando variables al gráfico.
Geometries (Geometría): Va a ser la forma
geométrica con la que vamos a representar los datos (barras, líneas,
puntos, etc.).
Estas tres capas son las esenciales para hacer un gráfico en
ggplot2
. Las siguientes capas nos permiten controlar otros
aspectos de la visualización.
Facets (Facetas o lados): Si tenemos un gráfico
que combina varios elementos, los facets nos permiten un
gráfico individual por cada elemento.
Statistics (Estadística): Podemos agregar una
capa que incorpore por ejemplo una regresión lineal o bien una
referencia como un valor promedio.
Coordinates (Ejes): Nos permite controlar los
ejes, desde su presentación, o incluso los límites, etc..
Theme (Estilo): Controla aspectos visuales sobre
el fondo, fuente, ejes, etc..
Haciendo gráficos con ggplot2
La sintáxis básica de ggplot2
es la siguiente:
ggplot(nombre_dataframe, aes(x, y)) +
geom_XXX
La función para hacer gráficos siempre será
ggplot()
.
Luego tenemos que poner el nombre del data frame.
Adentro del aes()
ponemos las columnas que queremos ver
reflejadas en el gráfico. Esto en la jerga de R se llama mapear
variables en el gráfico. Las variables las podemos utilizar además
de verlas reflejadas en los ejes x
, e y
,
también pueden usarse para modificar el color y el tamaño de los
elementos de un gráfico.
Por último, con geom_xxx()
le indicamos la forma
geométrica que puede adoptar la visualización (gráficos, puntos, líneas,
etc.).
Para sumar capas en un gráfico tenemos que usar el signo
+
. Un error común que cometo es confundirlo por el
pipe %>%
.
Los geoms que veremos en estas clases son:
geom_histogram()
: Para graficar histogramas. Nos
permiten ver la distribución de una variable numérica. Se puede graficar
mapeando una sola variable al menos.
geom_freqpoly()
: También nos permite ver la
distribución de una variable numérica, atenuando la curva. Se puede
graficar mapeando una sola variable al menos.
geom_boxplot()
: Hace gráficos boxplot, también
conocidos como de bigote y caja. Permite visualizar una gran cantidad de
información estadística.
geom_bar()
: Hace gráficos de barras. El largo de las
barras lo determina la cantidad de filas de lo que estemos mapeando.
Funciona incluso con un sólo eje.
geom_col()
: También hace gráficos de barra pero el
largo lo determina el valor de la/s celda/s que grafiquemos. Necesita
por lo menos mapear una variable para el eje x, y otro para el eje
y.
geom_line()
: Para hacer gráficos de línea.
geom_point()
: Para hacer gráficos de dispersión
(también conocidos como scatter plots).
Estos no son todos los tipos de gráficos que se pueden hacer con
ggplot2
. En 2020 la comunidad hispanoparlante de R lanzó
una actividad llamada 30 Días de Gráficos en honor de
Florence
Nightingale, un desafío en el cual a lo largo de 30 días quien
quisiera podría hacer un tipo de gráfico diferente.
Pueden ver una muestra de todos los gráficos en el repositorio de
GitHub de Ariadna
Angulo Brunet, una psicóloga española que realizó los 30
gráficos.
Histogramas
Los histogramas son un tipo de gráfico que nos permite ver la
distribución de una variable numérica, y entre otras cosas, analizar por
ejemplo su simetría.
Por default, geom_histogram()
divide a la variable
numérica en 30 secciones con un rango de valores. El largo de cada barra
estará determinado por la cantidad de observaciones que quedan dentro de
cada rango de valores.
Hagamos un histograma de la variable sueldo_bruto
del
data frame kiwi
.
# Hagamos un histograma de sueldo_bruto del data frame kiwi
ggplot(kiwi, aes(x = sueldo_bruto)) +
geom_histogram()

Cada barra de un histograma en R se llama bin
.
Podemos controlar la cantidad de barras que vemos usando dentro de
geom_histogram()
el parámetro bins
y asignando
el número que más nos sirva. También podemos modificar el ancho de los
bins con el parámetro bindwidth
.
# Modifiquemos la cantidad de bins a 15
ggplot(kiwi, aes(x = sueldo_bruto)) +
geom_histogram(bins = 15)

# Modifiquemos el ancho de los bins por 20000
ggplot(kiwi, aes(x = sueldo_bruto)) +
geom_histogram(binwidth = 25000)

Una alternativa a los histogramas es geom_freqpoly()
que
permite ver la forma de la distribución, generando un gráfico de líneas
al centro de cada bin.
También existe geom_density()
que permite ver una curva
atenuada de la distribución, pero como el eje y
muestra la
proporción de la distribución es un poco más compleja de
interpretar.
# Hacer un histograma de sueldo_bruto
ggplot(kiwi, aes(x = sueldo_bruto)) +
geom_histogram()

# Hacer un histograma de sueldo_bruto y combinarlo con geom_freqpoly()
ggplot(kiwi, aes(x = sueldo_bruto)) +
geom_histogram() +
geom_freqpoly()

# Hacer un gráfico de densidad
ggplot(kiwi, aes(x = sueldo_bruto)) +
geom_density()

Boxplots
Los boxplots son gráficos que contienen una gran cantidad de
información estadística.

En este gráfico podemos ver:
- Los cuartiles 1 y 3 (Q1 y Q3) en los bordes de la caja.
- La mediana que es la linea dentro de la caja.
- Los outliers, representados en puntos, que son observaciones que
superan una vez y media (1,5 veces) el rango intercuartil.
Además, la extensión de la caja nos permite tener una idea de la
distribución de los datos.
# Hacer un boxplot básico
ggplot(kiwi, aes(x = sueldo_bruto)) +
geom_boxplot()

# Compararlo con un histograma
ggplot(kiwi, aes(x = sueldo_bruto)) +
geom_histogram()

En la explicación previa, decíamos que podemos “mapear” una
variable para modificar el color de un gráfico. En los tipos de gráficos
que contienen una superficie, como los boxplots o los gráficos de
barras, el parámetro que necesitamos para modificar los colores en
función de una variable se llama fill
y lo tenemos que usar
dentro del aes()
.
# Mapear la variable género con el parámetro fill
ggplot(kiwi, aes(y = sueldo_bruto, fill = genero)) +
geom_boxplot()

Prácticas
Usando los data frames maestro
y mensuales
realizar los siguientes gráficos:
# Realizar un histograma de EDAD del data frame maestro
# Realizar un histograma y un freqpoly de los sueldos en mensuales
# Realizar un boxplot de mensuales, mapeando PUESTO en el eje x y SUELDO en y.

Gráficos de barra
geom_bar()
En R contamos con dos geoms para hacer gráficos de
barra:
geom_bar()
: El largo de la barra lo determina la
cantidad de filas de una columna. Se pueden hacer
mapeando una sola variable.
geom_col()
: El largo de la barra lo determina el
valor de la celda. Otra diferencia respecto de
geom_bar()
es que necesitamos mapear una variable al eje
x
y otra variable al eje y
.
Usemos el data frame kiwi
para probar ambos
gráficos.
# Hacer un gráfico de barras mapeando puesto al eje x
# Usar geom_bar()
ggplot(kiwi, aes(x = puesto, fill = genero)) +
geom_bar()

Si mapeamos, por ejemplo la variable genero
al color,
podemos controlar la posición de las barras con los siguientes
parámetros:
position = "dodge"
: Para poner las barras una al
lado de la otra.
position = "identity"
: Pone una barra detrás de la
otra.
position = "stack"
: Para hacer gráficos apilados. Es
la opción por default de geom_bar()
.
position = "fill"
: Para hacer un gráfico apilado al
100%
Las visualizaciones también se pueden guardar en objetos. Lo cual nos
permite ahorrar mucho tiempo escribiendo.
# Guardar la primera parte del gráfico en un objeto
barras <- ggplot(kiwi, aes(x = puesto, fill = genero))
# Reutilizamos el objeto para hacer gráficos de barras
barras +
geom_bar()

Ahora probemos modificar los parámetros con las opciones
dodge
, identity
y fill
.
# Usar el objeto vis1 y modificar el parámetro dodge dentro de geom_bar()
barras +
geom_bar(position = "dodge")

# Usar position = "identity"
barras +
geom_bar(position = "identity", alpha = 0.6)

# Usar position = "fill"
barras +
geom_bar(position = "fill")

geom_col()
A diferencia de geom_bar()
necesitamos pasar una columna
al eje x
y una columna al eje y
. Pero antes,
vamos a necesitar hacer un par de cálculos previos.
sueldo_rubro <- kiwi %>%
group_by(rubro) %>% # Agrupo por rubro
summarise(sueldo_promedio = mean(sueldo_bruto)) %>% # Calculo sueldo promedio
slice_max(n = 10, # Nos permite recortar la salida
order_by = sueldo_promedio) # Criterio para ordenar resultados
# Veamos el contenido
sueldo_rubro
## # A tibble: 10 × 2
## rubro sueldo_promedio
## <chr> <dbl>
## 1 Minería (carbón, otra minería) 105792.
## 2 Industrias químicas 104261.
## 3 Servicios financieros; seguros 103052.
## 4 Ingeniería mecánica 102000
## 5 Medios de comunicación; cultura; gráficos 101120
## 6 Oil & gas 96244.
## 7 Silvicultura; madera; celulosa; papel 96000
## 8 Transporte marítimo; puertos; 91667.
## 9 Alimentación; bebidas; tabaco 91389.
## 10 Servicios de correos, y de telecomunicaciones 84620
Como decíamos antes, ahora podemos mapear una variable (asignar) al
eje x
y asignar otra variable al eje y
.
# Hacer un gráfico de columnas
ggplot(sueldo_rubro, aes(x = rubro, y = sueldo_promedio)) +
geom_col()

No necesariamente tenemos que mapear las columnas de texto al eje
x
. Cuando las etiquetas son largas, para hacerlo más
legible al eje, podemos asignar las variables de texto al eje
y
.
# Repetir el gráfico anterior pero invirtiendo los ejes
ggplot(sueldo_rubro, aes(y = rubro, x = sueldo_promedio)) +
geom_col() +
geom_text(aes(label = round(sueldo_promedio)),
size = 3,
hjust = 1.2,
color = "white")

Cuando la variable de texto no tiene un orden implícito, como las
jerarquías de un puesto por ejemplo, una buena práctica es ordenar las
barras de mayor a menor. Esto simplifica al lector la interpretación del
gráfico (o en otras palabras, hace que nuestro trabajo sea de mayor
calidad).
Hay varias formas de lograr esto, una forma simple de hacerlo es con
la función reorder()
.
# Repetir el gráfico anterior, pero ordenando las barras de mayor a menor
ggplot(sueldo_rubro, aes(x = sueldo_promedio,
y = reorder(rubro, sueldo_promedio))) +
geom_col()

La sintaxis de reorder()
es la siguiente:
eje = reorder(variable_eje, variable_criterio)
En el ejemplo anterior hicimos
y = reorder(rubro, sueldo_promedio)
. Vamos por partes:
y
: es el eje al cual estamos asignando (mapeando) la
variable.
reorder()
: es la función:
rubro
: es la variable que estamos asignando al eje
y
en este caso.
sueldo_promedio
: El criterio por el cual vamos a
ordenar las barras. Si queremos ordenar las barras al revés sólo tenemos
que poner el signo menos (-
) delante de la variable que
estamos usando como criterio de orden (por ejemplo
-sueldo_promedio
).
Algo que no está bueno en el gráfico anterior es que se muestran los
nombres de los ejes tal cual como vienen en el data frame original. Una
función que nos permite añadir títulos y corregir los nombres de las
variables es la función labs()
.
# Repetir el gráfico anterior, y añadir títulos, subtítulos, ejes, y nota al pie
ggplot(sueldo_rubro, aes(x = sueldo_promedio,
y = reorder(rubro, sueldo_promedio))) +
geom_col() +
labs(title = "Sueldo promedio por rubro",
subtitle = "En AR$ - Puestos de RRHH",
x = "Sueldo Promedio",
y = "Rubro",
caption = "Fuente: Encuesta KIWI 2020")

Para saber más sobre estética de los gráficos pueden ver la sesión
4 de R4HR Club de R para RRHH, y también la sesión de Microaprendizajes.
Gráficos de líneas
Los gráficos de líneas son el gráfico por excelencia para visualizar
series de tiempo, es decir la evolución temporal de una variable.
Para este ejemplo vamos a utilizar el data frame de
rotacion
.
# Veamos el contenido del data frame 'rotacion'
rotacion
## Periodo Movimientos Cantidades
## 1 2010 Ingresos 9
## 2 2010 Egresos 2
## 3 2011 Ingresos 84
## 4 2011 Egresos 14
## 5 2012 Ingresos 44
## 6 2012 Egresos 17
## 7 2013 Ingresos 44
## 8 2013 Egresos 15
## 9 2014 Ingresos 60
## 10 2014 Egresos 14
## 11 2015 Ingresos 36
## 12 2015 Egresos 27
## 13 2016 Ingresos 14
## 14 2016 Egresos 14
Para ver la evolución de ambas líneas, podemos mapear:
# Hacer un gráfico de líneas con la evolución temporal de los Ingresos y Egresos
ggplot(rotacion, aes(x = Periodo, y = Cantidades, color = Movimientos)) +
geom_line()

Para marcar la sección donde corta cada año, podemos agregar una capa
de puntos al gráfico anterior. Juguemos con el parámetro
size
dentro de geom_point()
.
# Agregar una capa de puntos
ggplot(rotacion, aes(x = Periodo, y = Cantidades, color = Movimientos)) +
geom_line() +
geom_point(size = 2)

Este es un buen momento para ver la utilidad de los
facets.
# Añadir una capa de facet_wrap(~Movimientos)
ggplot(rotacion, aes(x = Periodo, y = Cantidades, color = Movimientos)) +
geom_line() +
geom_point(size = 2) +
facet_wrap(~Movimientos)

Gráficos de dispersión - Scatter plots
Los gráficos, o diagramas de dispersión, son una gran forma de
visualizar relaciones entre variables numéricas, concentraciones de
datos, entre otras cosas. Es una forma de introducirnos en el análisis
de regresiones lineales.
También permiten la concentración de datos entre variables numéricas
y categóricas. El geom que necesitaremos es
geom_point()
.
# Realizar un gráfico de dispersión entre anios_experiencia y sueldo_bruto
ggplot(kiwi, aes(x = anios_experiencia, y = sueldo_bruto)) +
geom_point()

Si quisiéramos trazar una recta de regresión, una forma de hacerlo es
la siguiente:
# Agregar una regresión lineal
ggplot(kiwi, aes(x = anios_experiencia, y = sueldo_bruto)) +
geom_point() +
geom_smooth(method = "lm")

Como decíamos, también podemos analizar la distribución de los datos
entre una variable categórica y una variable numérica
# Graficar genero vs. sueldo_bruto
ggplot(kiwi, aes(x = genero, y = sueldo_bruto)) +
geom_point()

Cuando hacemos gráficos de dispersión, dos parámetros muy útiles para
analizar donde hay más concentración de datos, son los parámetros
jitter y alpha.
Jitter le añade un poco de ruido a los datos para
evitar la superposición de puntos, pero manteniendo la distribución de
los datos. Hablando mal y pronto, lo que hace es mover un poquito los
puntos dentro del gráfico para que sean más visibles.
Otro parámetro muy útil es alpha que le añade
transparencia a los puntos, lo cual nos ayuda a ver donde hay más
concentración de datos, en donde haya más oscuridad del color.
También se puede jugar con el parámetro size o
shape para modificar el tamaño, o la forma de los
puntos.
En este gráfico ponemos estos parámetros en práctica.
# Hacemos el gráfico añadiendo el parámetro jitter y alpha
ggplot(kiwi, aes(x = genero, y = sueldo_bruto)) +
geom_point(position = "jitter",
alpha = 0.3,
size = 2) +
theme_minimal()

Gráficos de torta

Todas las personas que trabajan en visualización de datos AMAN odiar
los gráficos de torta. De hecho en ggplot2
no hay un
geom_pie
y no conozco ninguna extensión que los realice de
manera sencilla. Aunque si existe la función de R base
pie
# Preprocesamiento
satisfaccion <- kiwi %>%
select(satisfaccion) %>%
filter(!is.na(satisfaccion)) %>%
group_by(satisfaccion) %>%
tally() %>%
arrange(satisfaccion)
# Hacemos el gráfico en R base
pie(satisfaccion$n)

De todas maneras, como dice mi abuela, siempre hay un roto para
un descosido y aquí les presento una forma de realizar un
gráfico de dona.
En esencia, lo que vamos a hacer es un gráfico de barras apiladas al
100% al cual doblaremos, de la misma manera que las cucharas en
Matrix.

Primero haremos un gráfico de barras apiladas al 100%, cuyas
porciones (rectángulos) “doblaremos” posteriormente. En este ejemplo,
vamos a hacer un gráfico de dona sobre el porcentaje de gente y el tipo
de universidad. Para lo cual tenemos que hacer un pequeño
preprocesamiento de datos:
# Crear un objeto llamado educacion
educacion <- kiwi %>%
select(tipo_universidad) %>% # Selecciona la columna
group_by(tipo_universidad) %>% # Agrupa por tipo_universidad
summarise(cantidad = n()) %>% # Agrega columna con cantidad de casos
mutate(porcentaje = cantidad / sum(cantidad)) %>% # Agrega columna de porcentaje
arrange(-cantidad) # Ordena descendemtente por cantidad
# Veamos el resultado
educacion
## # A tibble: 3 × 3
## tipo_universidad cantidad porcentaje
## <chr> <int> <dbl>
## 1 Universidad Pública 246 0.502
## 2 Universidad Privada 222 0.453
## 3 No estudié en la Universidad 22 0.0449
El siguiente paso es determinar dónde empieza y dónde termina cada
rectángulo que vamos a crear. Eso lo vamos a poner en unas columnas
nuevas que llamaremos ymax
y ymin
.
# Calculamos los límites superiores de cada rectángulo
educacion$ymax <- cumsum(educacion$porcentaje)
# Calculamos el límite inferior de cada porción
educacion$ymin <- c(0, head(educacion$ymax, n=-1))
# Calculamos la posición de la etiqueta
educacion$posicion_etiqueta <- (educacion$ymax + educacion$ymin) / 2
# Creamos las etiquetas de cada porción
educacion$etiqueta <- paste0(educacion$tipo_universidad, # paste0 pega elementos
"\n Cant: ",
educacion$cantidad)
# Ver como quedó el data frame
educacion
## # A tibble: 3 × 7
## tipo_universidad cantidad porcentaje ymax ymin posicio…¹ etiqu…²
## <chr> <int> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 Universidad Pública 246 0.502 0.502 0 0.251 "Unive…
## 2 Universidad Privada 222 0.453 0.955 0.502 0.729 "Unive…
## 3 No estudié en la Universidad 22 0.0449 1 0.955 0.978 "No es…
## # … with abbreviated variable names ¹posicion_etiqueta, ²etiqueta
Los pasos anteriores crearon la posición donde comienzan y donde
termina cada barra, en donde se ubica cada etiqueta, y por último, qué
va a decir cada etiqueta.
Con la función paste0()
lo que hacemos es concatenar
varios elementos, primero, los valores de la columna
tipo_universidad
(Universidad Pública, Universidad
Privada, etc.), luego, con la barra invertida y la n
\n
en otro renglón agrega la palabra Cant:
y
finalmente pone el valor de la columna cantidad
.
Ahora, vamos a hacer el gráfico capa por capa para que vean cómo se
construye:
# Realizar el gráfico de dona
# Primera capa del gráfico
ggplot(educacion, aes(ymax=ymax,
ymin=ymin,
xmax=4,
xmin=3,
fill=tipo_universidad)) +
geom_rect()

# There is no spoon! Nuestro primer gráfico de torta
ggplot(educacion, aes(ymax=ymax,
ymin=ymin,
xmax=4,
xmin=3,
fill=tipo_universidad)) +
geom_rect() +
coord_polar(theta = "y")

# Recortamos el centro de la torta
ggplot(educacion, aes(ymax=ymax,
ymin=ymin,
xmax=4,
xmin=3,
fill=tipo_universidad)) +
geom_rect() +
coord_polar(theta = "y") +
xlim(c(2,4))

# Así quedaría el gráfico de barra sin coord_polar
ggplot(educacion, aes(ymax=ymax,
ymin=ymin,
xmax=4,
xmin=3,
fill=tipo_universidad)) +
geom_rect() +
xlim(c(2,4))

# Agregamos algunas modificaciones estéticas
ggplot(educacion, aes(ymax=ymax,
ymin=ymin,
xmax=4,
xmin=3,
fill=tipo_universidad)) +
geom_rect() +
coord_polar(theta = "y") +
xlim(c(2,4)) +
theme_void() + # Elimina fondos y referencias
scale_fill_viridis_d() + # Define una escala de colores
theme(legend.position = "right",
plot.title.position = "plot") + # Modifica posición leyendas y del título
labs(title = "Respuestas según Tipo de Universidad",
fill = "Tipo de Universidad",
caption = "Fuente: Encuesta KIWI de Sueldos de RH 2020") +
geom_label(x = 3.5,
aes(y = posicion_etiqueta,
label = etiqueta),
size = 3)

Check out
ggplot2
es un paquete que tiene una infinidad de
posibilidades, tiene muchas extensiones que posibilitan construir todo
tipo de gráficos, añadirles interactividad, información dinámica y
muchas cosas más.
Este paquete construye los gráficos por capas. Las capas
fundamentales son:
Los gráficos además se pueden combinar agregando capas, lo cual
posibilita agregar información, o limpiar los gráficos para añadir
información de contexto.
Customizar un gráfico lleva trabajo, pero todos esos elementos se
pueden guardar en objetos y reutilizarlos para ahorrar código y
esfuerzo.
Esto me permite ir trabajando progresivamente con los gráficos.
Primero me aseguro que el gráfico funcione, y luego voy incorporando
capas para definir colores, los ejes, los títulos, y finalmente la
estética general del gráfico.
Pueden explorar algunas extensiones en este link: https://exts.ggplot2.tidyverse.org/gallery/. También hay
un libro online (en inglés) que pueden revisar acá: https://ggplot2-book.org/.
LS0tDQp0aXRsZTogIlZpc3VhbGl6YWNpw7NuIGRlIERhdG9zIg0KYXV0aG9yOiAiU2VyZ2lvIEdhcmNpYSBNb3JhIHwgRGF0YSA0SFIiDQpkYXRlOiAiMTEvMTAvMjAyMiINCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdGhlbWU6IGx1bWVuDQogICAgaGlnaGxpZ2h0OiBweWdtZW50cw0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgIGNvZGVfZm9sZGluZzogc2hvdw0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIGZpZy5yZXRpbmEgPSAzLCBvdXQud2lkdGggPSAiODAlIikNCmBgYA0KDQojIFZpc3VhbGl6YWNpw7NuIGRlIERhdG9zIGNvbiBgZ2dwbG90MmANCg0KTGEgdmlzdWFsaXphY2nDs24gZGUgZGF0b3MgZXMgdW5hIGRlIGxhcyBldGFwYXMgZnVuZGFtZW50YWxlcyBlbiBlbCBhbsOhbGlzaXMgZGUgZGF0b3MgcG9ycXVlIHNlIHJlbGFjaW9uYSBjb24gKipsYSBjb211bmljYWNpw7NuKiogZGUgbG9zIHJlc3VsdGFkb3MuDQoNClVuYSBidWVuYSB2aXN1YWxpemFjacOzbiBwZXJtaXRlOg0KDQotICAgY29uZGVuc2FyIG11Y2hhIGluZm9ybWFjacOzbg0KLSAgIGV2aWRlbmNpYXIgbnVlc3RybyBwdW50byBkZSB2aXN0YQ0KLSAgIGNvbnRhciBoaXN0b3JpYXMgY29uIGRhdG9zDQoNCioqZ2dwbG90MioqIGVzIHVubyBkZSBsb3MgcGFxdWV0ZXMgcXVlIGVzdMOhIGRlbnRybyBkZSAqdGlkeXZlcnNlKiB5IGVzICoqZWwqKiBwYXF1ZXRlIG3DoXMgdXRpbGl6YWRvIHBhcmEgaGFjZXIgZ3LDoWZpY29zLg0KDQpQb2TDqXMgY29uc3VsdGFyIHVuIFtjaGVhdHNoZWV0IGVuIGNhc3RlbGxhbm8gZW4gZXN0ZSBsaW5rXShodHRwczovL2dpdGh1Yi5jb20vcnN0dWRpby9jaGVhdHNoZWV0cy9yYXcvbWFzdGVyL3RyYW5zbGF0aW9ucy9zcGFuaXNoL2RhdGEtdmlzdWFsaXphdGlvbl9lcy5wZGYpLg0KDQohW10oQXJjaGl2b3MvZGlhMTItMi5wbmcpe3dpZHRoPSI0MjAifQ0KDQohW10oQXJjaGl2b3Mvc2NhdHRlci1maW4tMS5wbmcpe3dpZHRoPSIzODMifQ0KDQpFbCBwYXF1ZXRlIGBnZ3Bsb3QyYCBlcyB1bm8gZGUgbG9zIHBhcXVldGVzIGRlbnRybyBkZSBsYSBjb2xlY2Npw7NuIGB0aWR5dmVyc2VgLCB5IHF1ZSBlc3TDoSBiYXNhZG8gZW4gbGEgdGVvcsOtYSBkZSAqKiJncmFtbWFyIG9mIGdyYXBoaWNzIioqIChsYSBncmFtw6F0aWNhIGRlIGxvcyBncsOhZmljb3MpLCBwb3JxdWUgcGVybWl0ZSBjb25zdHJ1aXIgbG9zIGdyw6FmaWNvcyBwb3IgY2FwYXMsIGNvbnRyb2xhbmRvIGxhcyBjYXJhY3RlcsOtc3RpY2FzIGluZGl2aWR1YWxlcyBkZSBjYWRhIHVuby4NCg0KIVtMYXMgY2FwYXMgZGUgbG9zIGdyw6FmaWNvc10oQXJjaGl2b3MvZ3JhbW1hcl9ncmFwaGljc19kZXRhaWxzLnBuZykNCg0KRXN0byBpbXBsaWNhIHF1ZSBwb2RlbW9zIGNvbnRyb2xhciBkZXNkZSBsYSAqKmVzdHJ1Y3R1cmEqKiBkZWwgZ3LDoWZpY28gKHTDrXR1bG9zLCBlamVzKSBoYXN0YSB0b2RvIGxvIHF1ZSBwYXNhIGRlbnRybyBkZSBsYSAqKnZpc3VhbGl6YWNpw7NuKiouDQoNClZlYW1vcyBlbiBkZXRhbGxlIGNhZGEgdW5hIGRlIGxhcyBjYXBhczoNCg0KLSAgICoqRGF0YSAoRGF0b3MpOioqIExhIGZ1ZW50ZSBkZSBkYXRvcyBxdWUgdXNhcmVtb3MgcGFyYSBncmFmaWNhciBsb3MgZGF0b3MuDQoNCi0gICAqKkFlc3RoZXRpY3MgKEVzdMOpdGljYSk6KiogU29uIGxhcyBtb2RpZmljYWNpb25lcyBlc3TDqXRpY2FzIHF1ZSBoYXJlbW9zIGFzaWduYW5kbyB2YXJpYWJsZXMgYWwgZ3LDoWZpY28uDQoNCi0gICAqKkdlb21ldHJpZXMgKEdlb21ldHLDrWEpOioqIFZhIGEgc2VyIGxhIGZvcm1hIGdlb23DqXRyaWNhIGNvbiBsYSBxdWUgdmFtb3MgYSByZXByZXNlbnRhciBsb3MgZGF0b3MgKGJhcnJhcywgbMOtbmVhcywgcHVudG9zLCBldGMuKS4NCg0KRXN0YXMgdHJlcyBjYXBhcyBzb24gbGFzIGVzZW5jaWFsZXMgcGFyYSBoYWNlciB1biBncsOhZmljbyBlbiBgZ2dwbG90MmAuIExhcyBzaWd1aWVudGVzIGNhcGFzIG5vcyBwZXJtaXRlbiBjb250cm9sYXIgb3Ryb3MgYXNwZWN0b3MgZGUgbGEgdmlzdWFsaXphY2nDs24uDQoNCi0gICAqKkZhY2V0cyAoRmFjZXRhcyBvIGxhZG9zKToqKiBTaSB0ZW5lbW9zIHVuIGdyw6FmaWNvIHF1ZSBjb21iaW5hIHZhcmlvcyBlbGVtZW50b3MsIGxvcyAqZmFjZXRzKiBub3MgcGVybWl0ZW4gdW4gZ3LDoWZpY28gaW5kaXZpZHVhbCBwb3IgY2FkYSBlbGVtZW50by4NCg0KLSAgICoqU3RhdGlzdGljcyAoRXN0YWTDrXN0aWNhKToqKiBQb2RlbW9zIGFncmVnYXIgdW5hIGNhcGEgcXVlIGluY29ycG9yZSBwb3IgZWplbXBsbyB1bmEgcmVncmVzacOzbiBsaW5lYWwgbyBiaWVuIHVuYSByZWZlcmVuY2lhIGNvbW8gdW4gdmFsb3IgcHJvbWVkaW8uDQoNCi0gICAqKkNvb3JkaW5hdGVzIChFamVzKToqKiBOb3MgcGVybWl0ZSBjb250cm9sYXIgbG9zIGVqZXMsIGRlc2RlIHN1IHByZXNlbnRhY2nDs24sIG8gaW5jbHVzbyBsb3MgbMOtbWl0ZXMsIGV0Yy4uDQoNCi0gICAqKlRoZW1lIChFc3RpbG8pKio6IENvbnRyb2xhIGFzcGVjdG9zIHZpc3VhbGVzIHNvYnJlIGVsIGZvbmRvLCBmdWVudGUsIGVqZXMsIGV0Yy4uDQoNCiMgUHJlcGFyw6FuZG9ub3MNCg0KQWwgaWd1YWwgcXVlIGNvbiBjdWFscXVpZXIgcGFxdWV0ZSwgbmVjZXNpdGFtb3MgaW5zdGFsYXIgeSBjYXJnYXIgZWwgcGFxdWV0ZSBwYXJhIHV0aWxpemFybG8uDQoNCipTaSB5YSBpbnN0YWxhbW9zIGB0aWR5dmVyc2UoKWAgbm8gaGFjZSBmYWx0YXIgdm9sdmVyIGEgaW5zdGFsYXIgYGdncGxvdDJgLioNCg0KYGBge3IgaW5zdGFsYXItcGtnLCBldmFsPUZBTFNFfQ0KaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpDQpgYGANCg0KTHVlZ28sIHRlbmVtb3MgcXVlIGNhcmdhciBlbCBwYXF1ZXRlLiBUYW1iacOpbiBjYXJnYXJlbW9zIG90cm9zIHBhcXVldGVzIHBhcmEgY2FyZ2FyIHkgbWFuaXB1bGFyIGRhdG9zLg0KDQpgYGB7ciBjYXJnYXItZ2dwbG90Mn0NCiMgQ2FyZ2FyIGxvcyBwYXF1ZXRlcyBnZ3Bsb3QyLCByZWFkeGwsIHkgZHBseXINCmxpYnJhcnkoZ2dwbG90MikgICAjIFZpc3VhbGl6YWNpw7NuIGRlIGRhdG9zDQpsaWJyYXJ5KHJlYWR4bCkgICAgIyBDYXJnYXIgYXJjaGl2b3MgZGUgRXhjZWwNCmxpYnJhcnkoZHBseXIpICAgICMgTGltcGllemEgeSBtYW5pcHVsYWNpw7NuIGRlIGRhdG9zDQpgYGANCg0KIyMgRnVlbnRlcyBkZSBkYXRvcw0KDQpMb3MgZGF0b3MgcXVlIHV0aWxpemFyZW1vcyBwYXJhIHRyYWJhamFyIHNvbiBsb3Mgc2lndWllbnRlcy4NCg0KLSAgIGBtYWVzdHJvLnhsc3hgIHkgYHNhbGFyaW9zLnhsc3hgIHF1ZSBzb24gdW4gbGlzdGFkbyBkZSBlbXBsZWFkb3MgeSB0YW1iacOpbiB1biBsaXN0YWRvIGRlIHN1ZWxkb3MgZGUgZW1wbGVhZG9zIG1lbnN1YWxpemFkb3MuDQotICAgYHJvdGFjaW9uLmNzdmAgcXVlIG11ZXN0cmEgbGEgZXZvbHVjacOzbiBkZSBpbmdyZXNvcyB5IGRlIGVncmVzb3MgYSBsbyBsYXJnbyBkZSB2YXJpb3MgYcOxb3MuDQotICAgYGtpd2lfYXIuUkRTYCwgdW4gYXJjaGl2byBkZSBkYXRvcyBwcm9waW8gZGUgUiBxdWUgY29udGllbmUgdW4gZGF0YSBmcmFtZSBtw6FzIGxpbXBpbyB5IG1hbnRlbmllbmRvIGFsZ3VuYXMgY2FyYWN0ZXLDrXN0aWNhcy4NCg0KYGBge3IgZGF0b3N9DQojIENhcmdhciBsb3MgYXJjaGl2b3MgZGUgRXhjZWwNCm1hZXN0cm8gPC0gcmVhZF94bHN4KCJtYWVzdHJvLnhsc3giKQ0Kc2FsYXJpb3MgPC0gcmVhZF94bHN4KCJzYWxhcmlvcy54bHN4IikNCg0KIyMgVW5pciBhbWJvcyBkYXRhIGZyYW1lcw0KbWVuc3VhbGVzIDwtIGxlZnRfam9pbihtYWVzdHJvLCBzYWxhcmlvcywgYnkgPSAiSUQiKSAlPiUgDQogIGZpbHRlcighaXMubmEoUFVFU1RPKSkgICMgRmlsdHJhIHRvZGFzIGxhcyBmaWxhcyBxdWUgbm8gZXN0w6FuIHZhY8OtYXMgZGUgbGEgY29sdW1uYSBQVUVTVE8NCg0KIyBDYXJnYXIgZWwgYXJjaGl2byByb3RhY2lvbi5jc3YNCnJvdGFjaW9uIDwtIHJlYWQuY3N2KCJyb3RhY2lvbi5jc3YiLCANCiAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICI7IikgICAjIEluZGljYSBlbCBzw61tYm9sbyBxdWUgc2VwYXJhIGxhcyBjb2x1bW5hcw0KDQojIENhcmdhciBlbCBhcmNoaXZvIGtpd2lfYXIuUkRTDQpraXdpIDwtIHJlYWRSRFMoImtpd2lfYXIuUkRTIikNCg0KDQpgYGANCg0KIyBIYWNpZW5kbyBncsOhZmljb3MgY29uIGdncGxvdDINCg0KTGEgc2ludMOheGlzIGLDoXNpY2EgZGUgYGdncGxvdDJgIGVzIGxhIHNpZ3VpZW50ZToNCg0KYGBge3IgZ2dwMSwgZXZhbCA9IEZBTFNFfQ0KZ2dwbG90KG5vbWJyZV9kYXRhZnJhbWUsIGFlcyh4LCB5KSkgKw0KICAgICAgICAgZ2VvbV9YWFgNCmBgYA0KDQpMYSBmdW5jacOzbiBwYXJhIGhhY2VyIGdyw6FmaWNvcyBzaWVtcHJlIHNlcsOhIGBnZ3Bsb3QoKWAuDQoNCkx1ZWdvIHRlbmVtb3MgcXVlIHBvbmVyIGVsIG5vbWJyZSBkZWwgZGF0YSBmcmFtZS4NCg0KQWRlbnRybyBkZWwgYGFlcygpYCBwb25lbW9zIGxhcyBjb2x1bW5hcyBxdWUgcXVlcmVtb3MgdmVyIHJlZmxlamFkYXMgZW4gZWwgZ3LDoWZpY28uIEVzdG8gZW4gbGEgamVyZ2EgZGUgUiBzZSBsbGFtYSAqbWFwZWFyIHZhcmlhYmxlcyBlbiBlbCBncsOhZmljbyouIExhcyB2YXJpYWJsZXMgbGFzIHBvZGVtb3MgdXRpbGl6YXIgYWRlbcOhcyBkZSB2ZXJsYXMgcmVmbGVqYWRhcyBlbiBsb3MgZWplcyBgeGAsIGUgYHlgLCB0YW1iacOpbiBwdWVkZW4gdXNhcnNlIHBhcmEgbW9kaWZpY2FyIGVsIGNvbG9yIHkgZWwgdGFtYcOxbyBkZSBsb3MgZWxlbWVudG9zIGRlIHVuIGdyw6FmaWNvLg0KDQpQb3Igw7psdGltbywgY29uIGBnZW9tX3h4eCgpYCBsZSBpbmRpY2Ftb3MgbGEgZm9ybWEgZ2VvbcOpdHJpY2EgcXVlIHB1ZWRlIGFkb3B0YXIgbGEgdmlzdWFsaXphY2nDs24gKGdyw6FmaWNvcywgcHVudG9zLCBsw61uZWFzLCBldGMuKS4NCg0KUGFyYSBzdW1hciBjYXBhcyBlbiB1biBncsOhZmljbyB0ZW5lbW9zIHF1ZSB1c2FyIGVsIHNpZ25vIGArYC4gVW4gZXJyb3IgY29tw7puIHF1ZSBjb21ldG8gZXMgY29uZnVuZGlybG8gcG9yIGVsICpwaXBlKiBgJT4lYC4NCg0KTG9zICpnZW9tcyogcXVlIHZlcmVtb3MgZW4gZXN0YXMgY2xhc2VzIHNvbjoNCg0KLSAgIGBnZW9tX2hpc3RvZ3JhbSgpYDogUGFyYSBncmFmaWNhciBoaXN0b2dyYW1hcy4gTm9zIHBlcm1pdGVuIHZlciBsYSBkaXN0cmlidWNpw7NuIGRlIHVuYSB2YXJpYWJsZSBudW3DqXJpY2EuIFNlIHB1ZWRlIGdyYWZpY2FyIG1hcGVhbmRvIHVuYSBzb2xhIHZhcmlhYmxlIGFsIG1lbm9zLg0KLSAgIGBnZW9tX2ZyZXFwb2x5KClgOiBUYW1iacOpbiBub3MgcGVybWl0ZSB2ZXIgbGEgZGlzdHJpYnVjacOzbiBkZSB1bmEgdmFyaWFibGUgbnVtw6lyaWNhLCBhdGVudWFuZG8gbGEgY3VydmEuIFNlIHB1ZWRlIGdyYWZpY2FyIG1hcGVhbmRvIHVuYSBzb2xhIHZhcmlhYmxlIGFsIG1lbm9zLg0KLSAgIGBnZW9tX2JveHBsb3QoKWA6IEhhY2UgZ3LDoWZpY29zIGJveHBsb3QsIHRhbWJpw6luIGNvbm9jaWRvcyBjb21vIGRlIGJpZ290ZSB5IGNhamEuIFBlcm1pdGUgdmlzdWFsaXphciB1bmEgZ3JhbiBjYW50aWRhZCBkZSBpbmZvcm1hY2nDs24gZXN0YWTDrXN0aWNhLg0KLSAgIGBnZW9tX2JhcigpYDogSGFjZSBncsOhZmljb3MgZGUgYmFycmFzLiBFbCBsYXJnbyBkZSBsYXMgYmFycmFzIGxvIGRldGVybWluYSBsYSBjYW50aWRhZCBkZSBmaWxhcyBkZSBsbyBxdWUgZXN0ZW1vcyBtYXBlYW5kby4gRnVuY2lvbmEgaW5jbHVzbyBjb24gdW4gc8OzbG8gZWplLg0KLSAgIGBnZW9tX2NvbCgpYDogVGFtYmnDqW4gaGFjZSBncsOhZmljb3MgZGUgYmFycmEgcGVybyBlbCBsYXJnbyBsbyBkZXRlcm1pbmEgZWwgdmFsb3IgZGUgbGEvcyBjZWxkYS9zIHF1ZSBncmFmaXF1ZW1vcy4gTmVjZXNpdGEgcG9yIGxvIG1lbm9zIG1hcGVhciB1bmEgdmFyaWFibGUgcGFyYSBlbCBlamUgeCwgeSBvdHJvIHBhcmEgZWwgZWplIHkuDQotICAgYGdlb21fbGluZSgpYDogUGFyYSBoYWNlciBncsOhZmljb3MgZGUgbMOtbmVhLg0KLSAgIGBnZW9tX3BvaW50KClgOiBQYXJhIGhhY2VyIGdyw6FmaWNvcyBkZSBkaXNwZXJzacOzbiAodGFtYmnDqW4gY29ub2NpZG9zIGNvbW8gc2NhdHRlciBwbG90cykuDQoNCkVzdG9zIG5vIHNvbiB0b2RvcyBsb3MgdGlwb3MgZGUgZ3LDoWZpY29zIHF1ZSBzZSBwdWVkZW4gaGFjZXIgY29uIGBnZ3Bsb3QyYC4gRW4gMjAyMCBsYSBjb211bmlkYWQgaGlzcGFub3BhcmxhbnRlIGRlIFIgbGFuesOzIHVuYSBhY3RpdmlkYWQgbGxhbWFkYSAqKjMwIETDrWFzIGRlIEdyw6FmaWNvcyoqIGVuIGhvbm9yIGRlIFtGbG9yZW5jZSBOaWdodGluZ2FsZV0oaHR0cHM6Ly9tdWplcmVzY29uY2llbmNpYS5jb20vMjAxNC8wNS8xMi9mbG9yZW5jZS1uaWd0aGluZ2FsZS1waW9uZXJhLWVzdGFkaXN0aWNhLyksIHVuIGRlc2Fmw61vIGVuIGVsIGN1YWwgYSBsbyBsYXJnbyBkZSAzMCBkw61hcyBxdWllbiBxdWlzaWVyYSBwb2Ryw61hIGhhY2VyIHVuIHRpcG8gZGUgZ3LDoWZpY28gZGlmZXJlbnRlLg0KDQpQdWVkZW4gdmVyIHVuYSBtdWVzdHJhIGRlIHRvZG9zIGxvcyBncsOhZmljb3MgZW4gZWwgcmVwb3NpdG9yaW8gZGUgR2l0SHViIGRlIFtBcmlhZG5hIEFuZ3VsbyBCcnVuZXRdKGh0dHBzOi8vZ2l0aHViLmNvbS9Bbmd1bG9CL2RhdG9zZGVtaWVyY29sZXMpLCB1bmEgcHNpY8OzbG9nYSBlc3Bhw7FvbGEgcXVlIHJlYWxpesOzIGxvcyAzMCBncsOhZmljb3MuDQoNCiMjIEhpc3RvZ3JhbWFzDQoNCkxvcyBoaXN0b2dyYW1hcyBzb24gdW4gdGlwbyBkZSBncsOhZmljbyBxdWUgbm9zIHBlcm1pdGUgdmVyIGxhIGRpc3RyaWJ1Y2nDs24gZGUgdW5hIHZhcmlhYmxlIG51bcOpcmljYSwgeSBlbnRyZSBvdHJhcyBjb3NhcywgYW5hbGl6YXIgcG9yIGVqZW1wbG8gc3Ugc2ltZXRyw61hLg0KDQpQb3IgZGVmYXVsdCwgYGdlb21faGlzdG9ncmFtKClgIGRpdmlkZSBhIGxhIHZhcmlhYmxlIG51bcOpcmljYSBlbiAzMCBzZWNjaW9uZXMgY29uIHVuIHJhbmdvIGRlIHZhbG9yZXMuIEVsIGxhcmdvIGRlIGNhZGEgYmFycmEgZXN0YXLDoSBkZXRlcm1pbmFkbyBwb3IgbGEgY2FudGlkYWQgZGUgb2JzZXJ2YWNpb25lcyBxdWUgcXVlZGFuIGRlbnRybyBkZSBjYWRhIHJhbmdvIGRlIHZhbG9yZXMuDQoNCkhhZ2Ftb3MgdW4gaGlzdG9ncmFtYSBkZSBsYSB2YXJpYWJsZSBgc3VlbGRvX2JydXRvYCBkZWwgZGF0YSBmcmFtZSBga2l3aWAuDQoNCmBgYHtyIGhpc3QxfQ0KIyBIYWdhbW9zIHVuIGhpc3RvZ3JhbWEgZGUgc3VlbGRvX2JydXRvIGRlbCBkYXRhIGZyYW1lIGtpd2kNCmdncGxvdChraXdpLCBhZXMoeCA9IHN1ZWxkb19icnV0bykpICsNCiAgZ2VvbV9oaXN0b2dyYW0oKQ0KDQpgYGANCg0KQ2FkYSAqYmFycmEqIGRlIHVuIGhpc3RvZ3JhbWEgZW4gUiBzZSBsbGFtYSBgYmluYC4gUG9kZW1vcyBjb250cm9sYXIgbGEgY2FudGlkYWQgZGUgYmFycmFzIHF1ZSB2ZW1vcyB1c2FuZG8gZGVudHJvIGRlIGBnZW9tX2hpc3RvZ3JhbSgpYCBlbCBwYXLDoW1ldHJvIGBiaW5zYCB5IGFzaWduYW5kbyBlbCBuw7ptZXJvIHF1ZSBtw6FzIG5vcyBzaXJ2YS4gVGFtYmnDqW4gcG9kZW1vcyBtb2RpZmljYXIgZWwgYW5jaG8gZGUgbG9zICpiaW5zKiBjb24gZWwgcGFyw6FtZXRybyBgYmluZHdpZHRoYC4NCg0KYGBge3IgaGlzdDJ9DQojIE1vZGlmaXF1ZW1vcyBsYSBjYW50aWRhZCBkZSBiaW5zIGEgMTUNCmdncGxvdChraXdpLCBhZXMoeCA9IHN1ZWxkb19icnV0bykpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDE1KQ0KDQojIE1vZGlmaXF1ZW1vcyBlbCBhbmNobyBkZSBsb3MgYmlucyBwb3IgMjAwMDANCmdncGxvdChraXdpLCBhZXMoeCA9IHN1ZWxkb19icnV0bykpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAyNTAwMCkNCmBgYA0KDQpVbmEgYWx0ZXJuYXRpdmEgYSBsb3MgaGlzdG9ncmFtYXMgZXMgYGdlb21fZnJlcXBvbHkoKWAgcXVlIHBlcm1pdGUgdmVyIGxhIGZvcm1hIGRlIGxhIGRpc3RyaWJ1Y2nDs24sIGdlbmVyYW5kbyB1biBncsOhZmljbyBkZSBsw61uZWFzIGFsIGNlbnRybyBkZSBjYWRhIGJpbi4NCg0KVGFtYmnDqW4gZXhpc3RlIGBnZW9tX2RlbnNpdHkoKWAgcXVlIHBlcm1pdGUgdmVyIHVuYSBjdXJ2YSBhdGVudWFkYSBkZSBsYSBkaXN0cmlidWNpw7NuLCBwZXJvIGNvbW8gZWwgZWplIGB5YCBtdWVzdHJhIGxhIHByb3BvcmNpw7NuIGRlIGxhIGRpc3RyaWJ1Y2nDs24gZXMgdW4gcG9jbyBtw6FzIGNvbXBsZWphIGRlIGludGVycHJldGFyLg0KDQpgYGB7ciBoaXN0M30NCiMgSGFjZXIgdW4gaGlzdG9ncmFtYSBkZSBzdWVsZG9fYnJ1dG8NCmdncGxvdChraXdpLCBhZXMoeCA9IHN1ZWxkb19icnV0bykpICsNCiAgZ2VvbV9oaXN0b2dyYW0oKQ0KDQojIEhhY2VyIHVuIGhpc3RvZ3JhbWEgZGUgc3VlbGRvX2JydXRvIHkgY29tYmluYXJsbyBjb24gZ2VvbV9mcmVxcG9seSgpDQpnZ3Bsb3Qoa2l3aSwgYWVzKHggPSBzdWVsZG9fYnJ1dG8pKSArDQogIGdlb21faGlzdG9ncmFtKCkgKw0KICBnZW9tX2ZyZXFwb2x5KCkNCg0KIyBIYWNlciB1biBncsOhZmljbyBkZSBkZW5zaWRhZA0KZ2dwbG90KGtpd2ksIGFlcyh4ID0gc3VlbGRvX2JydXRvKSkgKw0KICBnZW9tX2RlbnNpdHkoKQ0KYGBgDQoNCiMjIEJveHBsb3RzDQoNCkxvcyBib3hwbG90cyBzb24gZ3LDoWZpY29zIHF1ZSBjb250aWVuZW4gdW5hIGdyYW4gY2FudGlkYWQgZGUgaW5mb3JtYWNpw7NuIGVzdGFkw61zdGljYS4NCg0KIVtdKEFyY2hpdm9zL2JveHBsb3QucG5nKXt3aWR0aD0iNDk0In0NCg0KRW4gZXN0ZSBncsOhZmljbyBwb2RlbW9zIHZlcjoNCg0KLSAgIExvcyBjdWFydGlsZXMgMSB5IDMgKFExIHkgUTMpIGVuIGxvcyBib3JkZXMgZGUgbGEgY2FqYS4NCi0gICBMYSBtZWRpYW5hIHF1ZSBlcyBsYSBsaW5lYSBkZW50cm8gZGUgbGEgY2FqYS4NCi0gICBMb3Mgb3V0bGllcnMsIHJlcHJlc2VudGFkb3MgZW4gcHVudG9zLCBxdWUgc29uIG9ic2VydmFjaW9uZXMgcXVlIHN1cGVyYW4gdW5hIHZleiB5IG1lZGlhICgxLDUgdmVjZXMpIGVsIHJhbmdvIGludGVyY3VhcnRpbC4NCg0KQWRlbcOhcywgbGEgZXh0ZW5zacOzbiBkZSBsYSBjYWphIG5vcyBwZXJtaXRlIHRlbmVyIHVuYSBpZGVhIGRlIGxhICoqZGlzdHJpYnVjacOzbioqIGRlIGxvcyBkYXRvcy4NCg0KYGBge3IgYm94cDF9DQojIEhhY2VyIHVuIGJveHBsb3QgYsOhc2ljbw0KZ2dwbG90KGtpd2ksIGFlcyh4ID0gc3VlbGRvX2JydXRvKSkgKw0KICBnZW9tX2JveHBsb3QoKQ0KDQojIENvbXBhcmFybG8gY29uIHVuIGhpc3RvZ3JhbWENCmdncGxvdChraXdpLCBhZXMoeCA9IHN1ZWxkb19icnV0bykpICsNCiAgZ2VvbV9oaXN0b2dyYW0oKQ0KDQpgYGANCg0KRW4gbGEgZXhwbGljYWNpw7NuIHByZXZpYSwgZGVjw61hbW9zIHF1ZSBwb2RlbW9zICoibWFwZWFyIiogdW5hIHZhcmlhYmxlIHBhcmEgbW9kaWZpY2FyIGVsIGNvbG9yIGRlIHVuIGdyw6FmaWNvLiBFbiBsb3MgdGlwb3MgZGUgZ3LDoWZpY29zIHF1ZSBjb250aWVuZW4gdW5hIHN1cGVyZmljaWUsIGNvbW8gbG9zIGJveHBsb3RzIG8gbG9zIGdyw6FmaWNvcyBkZSBiYXJyYXMsIGVsIHBhcsOhbWV0cm8gcXVlIG5lY2VzaXRhbW9zIHBhcmEgbW9kaWZpY2FyIGxvcyBjb2xvcmVzIGVuIGZ1bmNpw7NuIGRlIHVuYSB2YXJpYWJsZSBzZSBsbGFtYSBgZmlsbGAgeSBsbyB0ZW5lbW9zIHF1ZSB1c2FyIGRlbnRybyBkZWwgYGFlcygpYC4NCg0KYGBge3IgYm94cDJ9DQojIE1hcGVhciBsYSB2YXJpYWJsZSBnw6luZXJvIGNvbiBlbCBwYXLDoW1ldHJvIGZpbGwNCmdncGxvdChraXdpLCBhZXMoeSA9IHN1ZWxkb19icnV0bywgZmlsbCA9IGdlbmVybykpICsNCiAgZ2VvbV9ib3hwbG90KCkNCg0KYGBgDQoNCiMjIyBQcsOhY3RpY2FzDQoNClVzYW5kbyBsb3MgZGF0YSBmcmFtZXMgYG1hZXN0cm9gIHkgYG1lbnN1YWxlc2AgcmVhbGl6YXIgbG9zIHNpZ3VpZW50ZXMgZ3LDoWZpY29zOg0KDQpgYGB7ciBwcmFjdGljYTF9DQojIFJlYWxpemFyIHVuIGhpc3RvZ3JhbWEgZGUgRURBRCBkZWwgZGF0YSBmcmFtZSBtYWVzdHJvDQoNCg0KIyBSZWFsaXphciB1biBoaXN0b2dyYW1hIHkgdW4gZnJlcXBvbHkgZGUgbG9zIHN1ZWxkb3MgZW4gbWVuc3VhbGVzDQoNCg0KIyBSZWFsaXphciB1biBib3hwbG90IGRlIG1lbnN1YWxlcywgbWFwZWFuZG8gUFVFU1RPIGVuIGVsIGVqZSB4IHkgU1VFTERPIGVuIHkuDQoNCmBgYA0KDQohW10oaHR0cHM6Ly9tZWRpYS5naXBoeS5jb20vbWVkaWEvTFRZVDVHVElpQU1CYS9naXBoeS5naWYpe3dpZHRoPSIzMTEifQ0KDQojIyBHcsOhZmljb3MgZGUgYmFycmENCg0KIyMjIGdlb21fYmFyKCkNCg0KRW4gUiBjb250YW1vcyBjb24gZG9zICpnZW9tcyogcGFyYSBoYWNlciBncsOhZmljb3MgZGUgYmFycmE6DQoNCi0gICBgZ2VvbV9iYXIoKWA6IEVsIGxhcmdvIGRlIGxhIGJhcnJhIGxvIGRldGVybWluYSBsYSAqKmNhbnRpZGFkIGRlIGZpbGFzKiogZGUgdW5hIGNvbHVtbmEuIFNlIHB1ZWRlbiBoYWNlciBtYXBlYW5kbyB1bmEgc29sYSB2YXJpYWJsZS4NCg0KLSAgIGBnZW9tX2NvbCgpYDogRWwgbGFyZ28gZGUgbGEgYmFycmEgbG8gZGV0ZXJtaW5hIGVsICoqdmFsb3IgZGUgbGEgY2VsZGEqKi4gT3RyYSBkaWZlcmVuY2lhIHJlc3BlY3RvIGRlIGBnZW9tX2JhcigpYCBlcyBxdWUgbmVjZXNpdGFtb3MgbWFwZWFyIHVuYSB2YXJpYWJsZSBhbCBlamUgYHhgIHkgb3RyYSB2YXJpYWJsZSBhbCBlamUgYHlgLg0KDQpVc2Vtb3MgZWwgZGF0YSBmcmFtZSBga2l3aWAgcGFyYSBwcm9iYXIgYW1ib3MgZ3LDoWZpY29zLg0KDQpgYGB7ciBiYXIxfQ0KIyBIYWNlciB1biBncsOhZmljbyBkZSBiYXJyYXMgbWFwZWFuZG8gcHVlc3RvIGFsIGVqZSB4DQojIFVzYXIgZ2VvbV9iYXIoKQ0KZ2dwbG90KGtpd2ksIGFlcyh4ID0gcHVlc3RvLCBmaWxsID0gZ2VuZXJvKSkgKw0KICBnZW9tX2JhcigpIA0KYGBgDQoNClNpIG1hcGVhbW9zLCBwb3IgZWplbXBsbyBsYSB2YXJpYWJsZSBgZ2VuZXJvYCBhbCBjb2xvciwgcG9kZW1vcyBjb250cm9sYXIgbGEgcG9zaWNpw7NuIGRlIGxhcyBiYXJyYXMgY29uIGxvcyBzaWd1aWVudGVzIHBhcsOhbWV0cm9zOg0KDQotICAgYHBvc2l0aW9uID0gImRvZGdlImA6IFBhcmEgcG9uZXIgbGFzIGJhcnJhcyB1bmEgYWwgbGFkbyBkZSBsYSBvdHJhLg0KDQotICAgYHBvc2l0aW9uID0gImlkZW50aXR5ImA6IFBvbmUgdW5hIGJhcnJhIGRldHLDoXMgZGUgbGEgb3RyYS4NCg0KLSAgIGBwb3NpdGlvbiA9ICJzdGFjayJgOiBQYXJhIGhhY2VyIGdyw6FmaWNvcyBhcGlsYWRvcy4gRXMgbGEgb3BjacOzbiBwb3IgZGVmYXVsdCBkZSBgZ2VvbV9iYXIoKWAuDQoNCi0gICBgcG9zaXRpb24gPSAiZmlsbCJgOiBQYXJhIGhhY2VyIHVuIGdyw6FmaWNvIGFwaWxhZG8gYWwgMTAwJQ0KDQpMYXMgdmlzdWFsaXphY2lvbmVzIHRhbWJpw6luIHNlIHB1ZWRlbiBndWFyZGFyIGVuIG9iamV0b3MuIExvIGN1YWwgbm9zIHBlcm1pdGUgYWhvcnJhciBtdWNobyB0aWVtcG8gZXNjcmliaWVuZG8uDQoNCmBgYHtyIGJhcjJ9DQojIEd1YXJkYXIgbGEgcHJpbWVyYSBwYXJ0ZSBkZWwgZ3LDoWZpY28gZW4gdW4gb2JqZXRvDQpiYXJyYXMgPC0gZ2dwbG90KGtpd2ksIGFlcyh4ID0gcHVlc3RvLCBmaWxsID0gZ2VuZXJvKSkgDQoNCiMgUmV1dGlsaXphbW9zIGVsIG9iamV0byBwYXJhIGhhY2VyIGdyw6FmaWNvcyBkZSBiYXJyYXMNCmJhcnJhcyArIA0KICBnZW9tX2JhcigpDQpgYGANCg0KQWhvcmEgcHJvYmVtb3MgbW9kaWZpY2FyIGxvcyBwYXLDoW1ldHJvcyBjb24gbGFzIG9wY2lvbmVzIGBkb2RnZWAsIGBpZGVudGl0eWAgeSBgZmlsbGAuDQoNCmBgYHtyIGJhcjN9DQojIFVzYXIgZWwgb2JqZXRvIHZpczEgeSBtb2RpZmljYXIgZWwgcGFyw6FtZXRybyBkb2RnZSBkZW50cm8gZGUgZ2VvbV9iYXIoKQ0KYmFycmFzICsNCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiKQ0KDQojIFVzYXIgcG9zaXRpb24gPSAiaWRlbnRpdHkiDQpiYXJyYXMgKw0KICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJpZGVudGl0eSIsIGFscGhhID0gMC42KQ0KDQojIFVzYXIgcG9zaXRpb24gPSAiZmlsbCINCmJhcnJhcyArIA0KICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJmaWxsIikNCg0KYGBgDQoNCiMjIyBnZW9tX2NvbCgpDQoNCkEgZGlmZXJlbmNpYSBkZSBgZ2VvbV9iYXIoKWAgbmVjZXNpdGFtb3MgcGFzYXIgdW5hIGNvbHVtbmEgYWwgZWplIGB4YCB5IHVuYSBjb2x1bW5hIGFsIGVqZSBgeWAuIFBlcm8gYW50ZXMsIHZhbW9zIGEgbmVjZXNpdGFyIGhhY2VyIHVuIHBhciBkZSBjw6FsY3Vsb3MgcHJldmlvcy4NCg0KYGBge3IgcHJvbWVkaW9zfQ0Kc3VlbGRvX3J1YnJvIDwtIGtpd2kgJT4lIA0KICBncm91cF9ieShydWJybykgJT4lICAgICAjIEFncnVwbyBwb3IgcnVicm8NCiAgc3VtbWFyaXNlKHN1ZWxkb19wcm9tZWRpbyA9IG1lYW4oc3VlbGRvX2JydXRvKSkgJT4lICMgQ2FsY3VsbyBzdWVsZG8gcHJvbWVkaW8NCiAgc2xpY2VfbWF4KG4gPSAxMCwgICAgICAgICAgICAgICAgICAgICAjIE5vcyBwZXJtaXRlIHJlY29ydGFyIGxhIHNhbGlkYQ0KICAgICAgICAgICAgb3JkZXJfYnkgPSBzdWVsZG9fcHJvbWVkaW8pICMgQ3JpdGVyaW8gcGFyYSBvcmRlbmFyIHJlc3VsdGFkb3MNCg0KIyBWZWFtb3MgZWwgY29udGVuaWRvDQpzdWVsZG9fcnVicm8NCmBgYA0KDQpDb21vIGRlY8OtYW1vcyBhbnRlcywgYWhvcmEgcG9kZW1vcyBtYXBlYXIgdW5hIHZhcmlhYmxlIChhc2lnbmFyKSBhbCBlamUgYHhgIHkgYXNpZ25hciBvdHJhIHZhcmlhYmxlIGFsIGVqZSBgeWAuDQoNCmBgYHtyIGNvbDF9DQojIEhhY2VyIHVuIGdyw6FmaWNvIGRlIGNvbHVtbmFzDQpnZ3Bsb3Qoc3VlbGRvX3J1YnJvLCBhZXMoeCA9IHJ1YnJvLCB5ID0gc3VlbGRvX3Byb21lZGlvKSkgKw0KICBnZW9tX2NvbCgpDQpgYGANCg0KTm8gbmVjZXNhcmlhbWVudGUgdGVuZW1vcyBxdWUgbWFwZWFyIGxhcyBjb2x1bW5hcyBkZSB0ZXh0byBhbCBlamUgYHhgLiBDdWFuZG8gbGFzIGV0aXF1ZXRhcyBzb24gbGFyZ2FzLCBwYXJhIGhhY2VybG8gbcOhcyBsZWdpYmxlIGFsIGVqZSwgcG9kZW1vcyBhc2lnbmFyIGxhcyB2YXJpYWJsZXMgZGUgdGV4dG8gYWwgZWplIGB5YC4NCg0KYGBge3IgY29sMn0NCiMgUmVwZXRpciBlbCBncsOhZmljbyBhbnRlcmlvciBwZXJvIGludmlydGllbmRvIGxvcyBlamVzDQpnZ3Bsb3Qoc3VlbGRvX3J1YnJvLCBhZXMoeSA9IHJ1YnJvLCB4ID0gc3VlbGRvX3Byb21lZGlvKSkgKw0KICBnZW9tX2NvbCgpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKHN1ZWxkb19wcm9tZWRpbykpLA0KICAgICAgICAgICAgc2l6ZSA9IDMsDQogICAgICAgICAgICBoanVzdCA9IDEuMiwNCiAgICAgICAgICAgIGNvbG9yID0gIndoaXRlIikNCmBgYA0KDQpDdWFuZG8gbGEgdmFyaWFibGUgZGUgdGV4dG8gbm8gdGllbmUgdW4gb3JkZW4gaW1wbMOtY2l0bywgY29tbyBsYXMgamVyYXJxdcOtYXMgZGUgdW4gcHVlc3RvIHBvciBlamVtcGxvLCB1bmEgYnVlbmEgcHLDoWN0aWNhIGVzIG9yZGVuYXIgbGFzIGJhcnJhcyBkZSBtYXlvciBhIG1lbm9yLiBFc3RvIHNpbXBsaWZpY2EgYWwgbGVjdG9yIGxhIGludGVycHJldGFjacOzbiBkZWwgZ3LDoWZpY28gKG8gZW4gb3RyYXMgcGFsYWJyYXMsIGhhY2UgcXVlIG51ZXN0cm8gdHJhYmFqbyBzZWEgZGUgbWF5b3IgY2FsaWRhZCkuDQoNCkhheSB2YXJpYXMgZm9ybWFzIGRlIGxvZ3JhciBlc3RvLCB1bmEgZm9ybWEgc2ltcGxlIGRlIGhhY2VybG8gZXMgY29uIGxhIGZ1bmNpw7NuIGByZW9yZGVyKClgLg0KDQpgYGB7ciBjb2wzfQ0KIyBSZXBldGlyIGVsIGdyw6FmaWNvIGFudGVyaW9yLCBwZXJvIG9yZGVuYW5kbyBsYXMgYmFycmFzIGRlIG1heW9yIGEgbWVub3INCmdncGxvdChzdWVsZG9fcnVicm8sIGFlcyh4ID0gc3VlbGRvX3Byb21lZGlvLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSByZW9yZGVyKHJ1YnJvLCBzdWVsZG9fcHJvbWVkaW8pKSkgKw0KICBnZW9tX2NvbCgpDQogDQpgYGANCg0KTGEgc2ludGF4aXMgZGUgYHJlb3JkZXIoKWAgZXMgbGEgc2lndWllbnRlOg0KDQpgYGB7ciByZW9yZGVyLCBldmFsPUZBTFNFfQ0KZWplID0gcmVvcmRlcih2YXJpYWJsZV9lamUsIHZhcmlhYmxlX2NyaXRlcmlvKSANCmBgYA0KDQpFbiBlbCBlamVtcGxvIGFudGVyaW9yIGhpY2ltb3MgYHkgPSByZW9yZGVyKHJ1YnJvLCBzdWVsZG9fcHJvbWVkaW8pYC4gVmFtb3MgcG9yIHBhcnRlczoNCg0KLSAgIGB5YDogZXMgZWwgZWplIGFsIGN1YWwgZXN0YW1vcyBhc2lnbmFuZG8gKG1hcGVhbmRvKSBsYSB2YXJpYWJsZS4NCg0KLSAgIGByZW9yZGVyKClgOiBlcyBsYSBmdW5jacOzbjoNCg0KLSAgIGBydWJyb2A6IGVzIGxhIHZhcmlhYmxlIHF1ZSBlc3RhbW9zIGFzaWduYW5kbyBhbCBlamUgYHlgIGVuIGVzdGUgY2Fzby4NCg0KLSAgIGBzdWVsZG9fcHJvbWVkaW9gOiBFbCBjcml0ZXJpbyBwb3IgZWwgY3VhbCB2YW1vcyBhIG9yZGVuYXIgbGFzIGJhcnJhcy4gU2kgcXVlcmVtb3Mgb3JkZW5hciBsYXMgYmFycmFzIGFsIHJldsOpcyBzw7NsbyB0ZW5lbW9zIHF1ZSBwb25lciBlbCBzaWdubyBtZW5vcyAoYC1gKSBkZWxhbnRlIGRlIGxhIHZhcmlhYmxlIHF1ZSBlc3RhbW9zIHVzYW5kbyBjb21vIGNyaXRlcmlvIGRlIG9yZGVuIChwb3IgZWplbXBsbyBgLXN1ZWxkb19wcm9tZWRpb2ApLg0KDQpBbGdvIHF1ZSBubyBlc3TDoSBidWVubyBlbiBlbCBncsOhZmljbyBhbnRlcmlvciBlcyBxdWUgc2UgbXVlc3RyYW4gbG9zIG5vbWJyZXMgZGUgbG9zIGVqZXMgdGFsIGN1YWwgY29tbyB2aWVuZW4gZW4gZWwgZGF0YSBmcmFtZSBvcmlnaW5hbC4gVW5hIGZ1bmNpw7NuIHF1ZSBub3MgcGVybWl0ZSBhw7FhZGlyIHTDrXR1bG9zIHkgY29ycmVnaXIgbG9zIG5vbWJyZXMgZGUgbGFzIHZhcmlhYmxlcyBlcyBsYSBmdW5jacOzbiBgbGFicygpYC4NCg0KYGBge3IgY29sNH0NCiMgUmVwZXRpciBlbCBncsOhZmljbyBhbnRlcmlvciwgeSBhw7FhZGlyIHTDrXR1bG9zLCBzdWJ0w610dWxvcywgZWplcywgeSBub3RhIGFsIHBpZQ0KZ2dwbG90KHN1ZWxkb19ydWJybywgYWVzKHggPSBzdWVsZG9fcHJvbWVkaW8sDQogICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHJlb3JkZXIocnVicm8sIHN1ZWxkb19wcm9tZWRpbykpKSArDQogIGdlb21fY29sKCkgKw0KICBsYWJzKHRpdGxlID0gIlN1ZWxkbyBwcm9tZWRpbyBwb3IgcnVicm8iLA0KICAgICAgIHN1YnRpdGxlID0gIkVuIEFSJCAtIFB1ZXN0b3MgZGUgUlJISCIsDQogICAgICAgeCA9ICJTdWVsZG8gUHJvbWVkaW8iLA0KICAgICAgIHkgPSAiUnVicm8iLA0KICAgICAgIGNhcHRpb24gPSAiRnVlbnRlOiBFbmN1ZXN0YSBLSVdJIDIwMjAiKQ0KDQpgYGANCg0KUGFyYSBzYWJlciBtw6FzIHNvYnJlIGVzdMOpdGljYSBkZSBsb3MgZ3LDoWZpY29zIHB1ZWRlbiB2ZXIgbGEgW3Nlc2nDs24gNCBkZSBSNEhSIENsdWIgZGUgUiBwYXJhIFJSSEhdKGh0dHBzOi8vZHJpdmUuZ29vZ2xlLmNvbS9kcml2ZS9mb2xkZXJzLzFhSGlDYllGZE1QNEduLXBBRGtxUlRwcTBNNzEyMzZxWj91c3A9c2hhcmluZyksIHkgdGFtYmnDqW4gbGEgc2VzacOzbiBkZSBbTWljcm9hcHJlbmRpemFqZXNdKGh0dHBzOi8vcnB1YnMuY29tL0RhdGE0SFIvcjRoci1taWNyb2FwcmVuZGl6YWplcykuDQoNCiMjIEdyw6FmaWNvcyBkZSBsw61uZWFzDQoNCkxvcyBncsOhZmljb3MgZGUgbMOtbmVhcyBzb24gZWwgZ3LDoWZpY28gcG9yIGV4Y2VsZW5jaWEgcGFyYSB2aXN1YWxpemFyIHNlcmllcyBkZSB0aWVtcG8sIGVzIGRlY2lyIGxhIGV2b2x1Y2nDs24gdGVtcG9yYWwgZGUgdW5hIHZhcmlhYmxlLg0KDQpQYXJhIGVzdGUgZWplbXBsbyB2YW1vcyBhIHV0aWxpemFyIGVsIGRhdGEgZnJhbWUgZGUgYHJvdGFjaW9uYC4NCg0KYGBge3IgbGluZWF9DQojIFZlYW1vcyBlbCBjb250ZW5pZG8gZGVsIGRhdGEgZnJhbWUgJ3JvdGFjaW9uJw0Kcm90YWNpb24NCmBgYA0KDQpQYXJhIHZlciBsYSBldm9sdWNpw7NuIGRlIGFtYmFzIGzDrW5lYXMsIHBvZGVtb3MgbWFwZWFyOg0KDQotICAgYFBlcmlvZG9gIGFsIGVqZSB4DQoNCi0gICBgQ2FudGlkYWRlc2AgYWwgZWplIHkNCg0KLSAgIGBNb3ZpbWllbnRvc2AgY29tbyBgY29sb3JgLg0KDQotICAgYGdlb21fbGluZSgpYCBjb21vIHZpc3VhbGl6YWNpw7NuDQoNCmBgYHtyIGxpbmVhMn0NCiMgSGFjZXIgdW4gZ3LDoWZpY28gZGUgbMOtbmVhcyBjb24gbGEgZXZvbHVjacOzbiB0ZW1wb3JhbCBkZSBsb3MgSW5ncmVzb3MgeSBFZ3Jlc29zDQpnZ3Bsb3Qocm90YWNpb24sIGFlcyh4ID0gUGVyaW9kbywgeSA9IENhbnRpZGFkZXMsIGNvbG9yID0gTW92aW1pZW50b3MpKSArDQogIGdlb21fbGluZSgpDQpgYGANCg0KUGFyYSBtYXJjYXIgbGEgc2VjY2nDs24gZG9uZGUgY29ydGEgY2FkYSBhw7FvLCBwb2RlbW9zIGFncmVnYXIgdW5hIGNhcGEgZGUgcHVudG9zIGFsIGdyw6FmaWNvIGFudGVyaW9yLiBKdWd1ZW1vcyBjb24gZWwgcGFyw6FtZXRybyBgc2l6ZWAgZGVudHJvIGRlIGBnZW9tX3BvaW50KClgLg0KDQpgYGB7ciBsaW5lYTN9DQojIEFncmVnYXIgdW5hIGNhcGEgZGUgcHVudG9zDQpnZ3Bsb3Qocm90YWNpb24sIGFlcyh4ID0gUGVyaW9kbywgeSA9IENhbnRpZGFkZXMsIGNvbG9yID0gTW92aW1pZW50b3MpKSArDQogIGdlb21fbGluZSgpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMikNCg0KYGBgDQoNCkVzdGUgZXMgdW4gYnVlbiBtb21lbnRvIHBhcmEgdmVyIGxhIHV0aWxpZGFkIGRlIGxvcyAqZmFjZXRzKi4NCg0KYGBge3IgbGluZWEtNH0NCiMgQcOxYWRpciB1bmEgY2FwYSBkZSBmYWNldF93cmFwKH5Nb3ZpbWllbnRvcykNCmdncGxvdChyb3RhY2lvbiwgYWVzKHggPSBQZXJpb2RvLCB5ID0gQ2FudGlkYWRlcywgY29sb3IgPSBNb3ZpbWllbnRvcykpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBnZW9tX3BvaW50KHNpemUgPSAyKSArDQogIGZhY2V0X3dyYXAofk1vdmltaWVudG9zKQ0KYGBgDQoNCiMjIEdyw6FmaWNvcyBkZSBkaXNwZXJzacOzbiAtIFNjYXR0ZXIgcGxvdHMNCg0KTG9zIGdyw6FmaWNvcywgbyBkaWFncmFtYXMgZGUgZGlzcGVyc2nDs24sIHNvbiB1bmEgZ3JhbiBmb3JtYSBkZSB2aXN1YWxpemFyIHJlbGFjaW9uZXMgZW50cmUgdmFyaWFibGVzIG51bcOpcmljYXMsIGNvbmNlbnRyYWNpb25lcyBkZSBkYXRvcywgZW50cmUgb3RyYXMgY29zYXMuIEVzIHVuYSBmb3JtYSBkZSBpbnRyb2R1Y2lybm9zIGVuIGVsIGFuw6FsaXNpcyBkZSByZWdyZXNpb25lcyBsaW5lYWxlcy4NCg0KVGFtYmnDqW4gcGVybWl0ZW4gbGEgY29uY2VudHJhY2nDs24gZGUgZGF0b3MgZW50cmUgdmFyaWFibGVzIG51bcOpcmljYXMgeSBjYXRlZ8OzcmljYXMuIEVsICpnZW9tKiBxdWUgbmVjZXNpdGFyZW1vcyBlcyBgZ2VvbV9wb2ludCgpYC4NCg0KYGBge3Igc2NhdGVyMX0NCiMgUmVhbGl6YXIgdW4gZ3LDoWZpY28gZGUgZGlzcGVyc2nDs24gZW50cmUgYW5pb3NfZXhwZXJpZW5jaWEgeSBzdWVsZG9fYnJ1dG8NCmdncGxvdChraXdpLCBhZXMoeCA9IGFuaW9zX2V4cGVyaWVuY2lhLCB5ID0gc3VlbGRvX2JydXRvKSkgKw0KICBnZW9tX3BvaW50KCkNCmBgYA0KDQpTaSBxdWlzacOpcmFtb3MgdHJhemFyIHVuYSByZWN0YSBkZSByZWdyZXNpw7NuLCB1bmEgZm9ybWEgZGUgaGFjZXJsbyBlcyBsYSBzaWd1aWVudGU6DQoNCmBgYHtyIHNjYXR0ZXItcmVnfQ0KIyBBZ3JlZ2FyIHVuYSByZWdyZXNpw7NuIGxpbmVhbA0KZ2dwbG90KGtpd2ksIGFlcyh4ID0gYW5pb3NfZXhwZXJpZW5jaWEsIHkgPSBzdWVsZG9fYnJ1dG8pKSArDQogIGdlb21fcG9pbnQoKSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIpDQpgYGANCg0KQ29tbyBkZWPDrWFtb3MsIHRhbWJpw6luIHBvZGVtb3MgYW5hbGl6YXIgbGEgZGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MgZW50cmUgdW5hIHZhcmlhYmxlIGNhdGVnw7NyaWNhIHkgdW5hIHZhcmlhYmxlIG51bcOpcmljYQ0KDQpgYGB7ciBzY2F0ZXIyfQ0KIyBHcmFmaWNhciBnZW5lcm8gdnMuIHN1ZWxkb19icnV0bw0KZ2dwbG90KGtpd2ksIGFlcyh4ID0gZ2VuZXJvLCB5ID0gc3VlbGRvX2JydXRvKSkgKw0KICBnZW9tX3BvaW50KCkNCmBgYA0KDQpDdWFuZG8gaGFjZW1vcyBncsOhZmljb3MgZGUgZGlzcGVyc2nDs24sIGRvcyBwYXLDoW1ldHJvcyBtdXkgw7p0aWxlcyBwYXJhIGFuYWxpemFyIGRvbmRlIGhheSBtw6FzIGNvbmNlbnRyYWNpw7NuIGRlIGRhdG9zLCBzb24gbG9zIHBhcsOhbWV0cm9zICoqaml0dGVyKiogeSAqKmFscGhhKiouDQoNCioqSml0dGVyKiogbGUgYcOxYWRlIHVuIHBvY28gZGUgcnVpZG8gYSBsb3MgZGF0b3MgcGFyYSBldml0YXIgbGEgc3VwZXJwb3NpY2nDs24gZGUgcHVudG9zLCBwZXJvIG1hbnRlbmllbmRvIGxhIGRpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zLiBIYWJsYW5kbyBtYWwgeSBwcm9udG8sIGxvIHF1ZSBoYWNlIGVzIG1vdmVyIHVuIHBvcXVpdG8gbG9zIHB1bnRvcyBkZW50cm8gZGVsIGdyw6FmaWNvIHBhcmEgcXVlIHNlYW4gbcOhcyB2aXNpYmxlcy4NCg0KT3RybyBwYXLDoW1ldHJvIG11eSDDunRpbCBlcyAqKmFscGhhKiogcXVlIGxlIGHDsWFkZSB0cmFuc3BhcmVuY2lhIGEgbG9zIHB1bnRvcywgbG8gY3VhbCBub3MgYXl1ZGEgYSB2ZXIgZG9uZGUgaGF5IG3DoXMgY29uY2VudHJhY2nDs24gZGUgZGF0b3MsIGVuIGRvbmRlIGhheWEgbcOhcyBvc2N1cmlkYWQgZGVsIGNvbG9yLg0KDQpUYW1iacOpbiBzZSBwdWVkZSBqdWdhciBjb24gZWwgcGFyw6FtZXRybyAqKnNpemUqKiBvICoqc2hhcGUqKiBwYXJhIG1vZGlmaWNhciBlbCB0YW1hw7FvLCBvIGxhIGZvcm1hIGRlIGxvcyBwdW50b3MuDQoNCkVuIGVzdGUgZ3LDoWZpY28gcG9uZW1vcyBlc3RvcyBwYXLDoW1ldHJvcyBlbiBwcsOhY3RpY2EuDQoNCmBgYHtyIHNjYXR0ZXItZmlufQ0KIyBIYWNlbW9zIGVsIGdyw6FmaWNvIGHDsWFkaWVuZG8gZWwgcGFyw6FtZXRybyBqaXR0ZXIgeSBhbHBoYQ0KZ2dwbG90KGtpd2ksIGFlcyh4ID0gZ2VuZXJvLCB5ID0gc3VlbGRvX2JydXRvKSkgKw0KICBnZW9tX3BvaW50KHBvc2l0aW9uID0gImppdHRlciIsDQogICAgICAgICAgICAgYWxwaGEgPSAwLjMsDQogICAgICAgICAgICAgc2l6ZSA9IDIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KIyMgR3LDoWZpY29zIGRlIHRvcnRhDQoNCiFbXShodHRwczovL2dpdGh1Yi5jb20vY2hlY2hvaWQvcGVwYWl0YmEvYmxvYi9tYWluL2luc3QvdHV0b3JpYWxzL3BlcGExL3BpZV9jcm9jcy5qcGc/cmF3PXRydWUpe3dpZHRoPSIzMDIifQ0KDQpUb2RhcyBsYXMgcGVyc29uYXMgcXVlIHRyYWJhamFuIGVuIHZpc3VhbGl6YWNpw7NuIGRlIGRhdG9zIEFNQU4gb2RpYXIgbG9zIGdyw6FmaWNvcyBkZSB0b3J0YS4gRGUgaGVjaG8gZW4gYGdncGxvdDJgIG5vIGhheSB1biBgZ2VvbV9waWVgIHkgbm8gY29ub3pjbyBuaW5ndW5hIGV4dGVuc2nDs24gcXVlIGxvcyByZWFsaWNlIGRlIG1hbmVyYSBzZW5jaWxsYS4gQXVucXVlIHNpIGV4aXN0ZSBsYSBmdW5jacOzbiBkZSBSIGJhc2UgYHBpZWANCg0KYGBge3IgcGllLWJhc2V9DQojIFByZXByb2Nlc2FtaWVudG8NCnNhdGlzZmFjY2lvbiA8LSBraXdpICU+JSANCiAgc2VsZWN0KHNhdGlzZmFjY2lvbikgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKHNhdGlzZmFjY2lvbikpICU+JSANCiAgZ3JvdXBfYnkoc2F0aXNmYWNjaW9uKSAlPiUgDQogIHRhbGx5KCkgJT4lIA0KICBhcnJhbmdlKHNhdGlzZmFjY2lvbikNCg0KIyBIYWNlbW9zIGVsIGdyw6FmaWNvIGVuIFIgYmFzZQ0KcGllKHNhdGlzZmFjY2lvbiRuKQ0KYGBgDQoNCkRlIHRvZGFzIG1hbmVyYXMsIGNvbW8gZGljZSBtaSBhYnVlbGEsICpzaWVtcHJlIGhheSB1biByb3RvIHBhcmEgdW4gZGVzY29zaWRvKiB5IGFxdcOtIGxlcyBwcmVzZW50byB1bmEgZm9ybWEgZGUgcmVhbGl6YXIgdW4gKipncsOhZmljbyBkZSBkb25hKiouDQoNCkVuIGVzZW5jaWEsIGxvIHF1ZSB2YW1vcyBhIGhhY2VyIGVzIHVuIGdyw6FmaWNvIGRlIGJhcnJhcyBhcGlsYWRhcyBhbCAxMDAlIGFsIGN1YWwgZG9ibGFyZW1vcywgZGUgbGEgbWlzbWEgbWFuZXJhIHF1ZSBsYXMgY3VjaGFyYXMgZW4gTWF0cml4Lg0KDQohW10oaHR0cHM6Ly9pbWcxLndzaW1nLmNvbS9pc3RlYW0vaXAvMzIwYmRlNDQtNTYxZS00MWU0LWE1YWEtNDAyOGE1YzVkODgzL3RoZXJlJTI1MjBpcyUyNTIwbm8lMjUyMHNwb29uLmpwZyl7d2lkdGg9IjM0NCJ9DQoNClByaW1lcm8gaGFyZW1vcyB1biBncsOhZmljbyBkZSBiYXJyYXMgYXBpbGFkYXMgYWwgMTAwJSwgY3V5YXMgcG9yY2lvbmVzIChyZWN0w6FuZ3Vsb3MpICJkb2JsYXJlbW9zIiBwb3N0ZXJpb3JtZW50ZS4gRW4gZXN0ZSBlamVtcGxvLCB2YW1vcyBhIGhhY2VyIHVuIGdyw6FmaWNvIGRlIGRvbmEgc29icmUgZWwgcG9yY2VudGFqZSBkZSBnZW50ZSB5IGVsIHRpcG8gZGUgdW5pdmVyc2lkYWQuIFBhcmEgbG8gY3VhbCB0ZW5lbW9zIHF1ZSBoYWNlciB1biBwZXF1ZcOxbyBwcmVwcm9jZXNhbWllbnRvIGRlIGRhdG9zOg0KDQpgYGB7ciBwaWUtcHJlfQ0KIyBDcmVhciB1biBvYmpldG8gbGxhbWFkbyBlZHVjYWNpb24NCmVkdWNhY2lvbiA8LSBraXdpICU+JSANCiAgc2VsZWN0KHRpcG9fdW5pdmVyc2lkYWQpICU+JSAgICAgICAgICAgICMgU2VsZWNjaW9uYSBsYSBjb2x1bW5hDQogIGdyb3VwX2J5KHRpcG9fdW5pdmVyc2lkYWQpICU+JSAgICAgICAgICAjIEFncnVwYSBwb3IgdGlwb191bml2ZXJzaWRhZA0KICBzdW1tYXJpc2UoY2FudGlkYWQgPSBuKCkpICU+JSAgICAgICAgICAgIyBBZ3JlZ2EgY29sdW1uYSBjb24gY2FudGlkYWQgZGUgY2Fzb3MNCiAgbXV0YXRlKHBvcmNlbnRhamUgPSBjYW50aWRhZCAvIHN1bShjYW50aWRhZCkpICU+JSAjIEFncmVnYSBjb2x1bW5hIGRlIHBvcmNlbnRhamUNCiAgYXJyYW5nZSgtY2FudGlkYWQpICAgICAgICAgICAgICAgICAgICAgICMgT3JkZW5hIGRlc2NlbmRlbXRlbnRlIHBvciBjYW50aWRhZA0KDQojIFZlYW1vcyBlbCByZXN1bHRhZG8NCmVkdWNhY2lvbg0KYGBgDQoNCkVsIHNpZ3VpZW50ZSBwYXNvIGVzIGRldGVybWluYXIgZMOzbmRlIGVtcGllemEgeSBkw7NuZGUgdGVybWluYSBjYWRhIHJlY3TDoW5ndWxvIHF1ZSB2YW1vcyBhIGNyZWFyLiBFc28gbG8gdmFtb3MgYSBwb25lciBlbiB1bmFzIGNvbHVtbmFzIG51ZXZhcyBxdWUgbGxhbWFyZW1vcyBgeW1heGAgeSBgeW1pbmAuDQoNCmBgYHtyIHBpZS1tYXhtaW59DQojIENhbGN1bGFtb3MgbG9zIGzDrW1pdGVzIHN1cGVyaW9yZXMgZGUgY2FkYSByZWN0w6FuZ3Vsbw0KZWR1Y2FjaW9uJHltYXggPC0gY3Vtc3VtKGVkdWNhY2lvbiRwb3JjZW50YWplKQ0KDQojIENhbGN1bGFtb3MgZWwgbMOtbWl0ZSBpbmZlcmlvciBkZSBjYWRhIHBvcmNpw7NuDQplZHVjYWNpb24keW1pbiA8LSBjKDAsIGhlYWQoZWR1Y2FjaW9uJHltYXgsIG49LTEpKQ0KDQojIENhbGN1bGFtb3MgbGEgcG9zaWNpw7NuIGRlIGxhIGV0aXF1ZXRhDQplZHVjYWNpb24kcG9zaWNpb25fZXRpcXVldGEgPC0gKGVkdWNhY2lvbiR5bWF4ICsgZWR1Y2FjaW9uJHltaW4pIC8gMg0KDQojIENyZWFtb3MgbGFzIGV0aXF1ZXRhcyBkZSBjYWRhIHBvcmNpw7NuDQplZHVjYWNpb24kZXRpcXVldGEgPC0gcGFzdGUwKGVkdWNhY2lvbiR0aXBvX3VuaXZlcnNpZGFkLCAjIHBhc3RlMCBwZWdhIGVsZW1lbnRvcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiXG4gQ2FudDogIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVkdWNhY2lvbiRjYW50aWRhZCkNCg0KIyBWZXIgY29tbyBxdWVkw7MgZWwgZGF0YSBmcmFtZQ0KZWR1Y2FjaW9uDQpgYGANCg0KTG9zIHBhc29zIGFudGVyaW9yZXMgY3JlYXJvbiBsYSBwb3NpY2nDs24gZG9uZGUgY29taWVuemFuIHkgZG9uZGUgdGVybWluYSBjYWRhIGJhcnJhLCBlbiBkb25kZSBzZSB1YmljYSBjYWRhIGV0aXF1ZXRhLCB5IHBvciDDumx0aW1vLCBxdcOpIHZhIGEgZGVjaXIgY2FkYSBldGlxdWV0YS4NCg0KQ29uIGxhIGZ1bmNpw7NuIGBwYXN0ZTAoKWAgbG8gcXVlIGhhY2Vtb3MgZXMgY29uY2F0ZW5hciB2YXJpb3MgZWxlbWVudG9zLCBwcmltZXJvLCBsb3MgdmFsb3JlcyBkZSBsYSBjb2x1bW5hIGB0aXBvX3VuaXZlcnNpZGFkYCAoKlVuaXZlcnNpZGFkIFDDumJsaWNhLCBVbml2ZXJzaWRhZCBQcml2YWRhLCogZXRjLiksIGx1ZWdvLCBjb24gbGEgYmFycmEgaW52ZXJ0aWRhIHkgbGEgbiBgXG5gIGVuIG90cm8gcmVuZ2zDs24gYWdyZWdhIGxhIHBhbGFicmEgYENhbnQ6YCB5IGZpbmFsbWVudGUgcG9uZSBlbCB2YWxvciBkZSBsYSBjb2x1bW5hIGBjYW50aWRhZGAuDQoNCkFob3JhLCB2YW1vcyBhIGhhY2VyIGVsIGdyw6FmaWNvIGNhcGEgcG9yIGNhcGEgcGFyYSBxdWUgdmVhbiBjw7NtbyBzZSBjb25zdHJ1eWU6DQoNCmBgYHtyIHBpZS1wbG90fQ0KIyBSZWFsaXphciBlbCBncsOhZmljbyBkZSBkb25hDQoNCiMgUHJpbWVyYSBjYXBhIGRlbCBncsOhZmljbw0KZ2dwbG90KGVkdWNhY2lvbiwgYWVzKHltYXg9eW1heCwgDQogICAgICAgICAgICAgICAgICAgICAgeW1pbj15bWluLCANCiAgICAgICAgICAgICAgICAgICAgICB4bWF4PTQsIA0KICAgICAgICAgICAgICAgICAgICAgIHhtaW49MywgDQogICAgICAgICAgICAgICAgICAgICAgZmlsbD10aXBvX3VuaXZlcnNpZGFkKSkgKw0KICBnZW9tX3JlY3QoKSANCg0KIyBUaGVyZSBpcyBubyBzcG9vbiEgTnVlc3RybyBwcmltZXIgZ3LDoWZpY28gZGUgdG9ydGENCiBnZ3Bsb3QoZWR1Y2FjaW9uLCBhZXMoeW1heD15bWF4LCANCiAgICAgICAgICAgICAgICAgICAgICB5bWluPXltaW4sIA0KICAgICAgICAgICAgICAgICAgICAgIHhtYXg9NCwgDQogICAgICAgICAgICAgICAgICAgICAgeG1pbj0zLCANCiAgICAgICAgICAgICAgICAgICAgICBmaWxsPXRpcG9fdW5pdmVyc2lkYWQpKSArDQogIGdlb21fcmVjdCgpICsNCiAgY29vcmRfcG9sYXIodGhldGEgPSAieSIpDQogDQoNCiMgUmVjb3J0YW1vcyBlbCBjZW50cm8gZGUgbGEgdG9ydGENCmdncGxvdChlZHVjYWNpb24sIGFlcyh5bWF4PXltYXgsIA0KICAgICAgICAgICAgICAgICAgICAgIHltaW49eW1pbiwgDQogICAgICAgICAgICAgICAgICAgICAgeG1heD00LCANCiAgICAgICAgICAgICAgICAgICAgICB4bWluPTMsIA0KICAgICAgICAgICAgICAgICAgICAgIGZpbGw9dGlwb191bml2ZXJzaWRhZCkpICsNCiAgZ2VvbV9yZWN0KCkgKw0KICBjb29yZF9wb2xhcih0aGV0YSA9ICJ5IikgKw0KICB4bGltKGMoMiw0KSkNCg0KIyBBc8OtIHF1ZWRhcsOtYSBlbCBncsOhZmljbyBkZSBiYXJyYSBzaW4gY29vcmRfcG9sYXINCmdncGxvdChlZHVjYWNpb24sIGFlcyh5bWF4PXltYXgsIA0KICAgICAgICAgICAgICAgICAgICAgIHltaW49eW1pbiwgDQogICAgICAgICAgICAgICAgICAgICAgeG1heD00LCANCiAgICAgICAgICAgICAgICAgICAgICB4bWluPTMsIA0KICAgICAgICAgICAgICAgICAgICAgIGZpbGw9dGlwb191bml2ZXJzaWRhZCkpICsNCiAgZ2VvbV9yZWN0KCkgKw0KICB4bGltKGMoMiw0KSkNCg0KDQojIEFncmVnYW1vcyBhbGd1bmFzIG1vZGlmaWNhY2lvbmVzIGVzdMOpdGljYXMNCmdncGxvdChlZHVjYWNpb24sIGFlcyh5bWF4PXltYXgsIA0KICAgICAgICAgICAgICAgICAgICAgIHltaW49eW1pbiwgDQogICAgICAgICAgICAgICAgICAgICAgeG1heD00LCANCiAgICAgICAgICAgICAgICAgICAgICB4bWluPTMsIA0KICAgICAgICAgICAgICAgICAgICAgIGZpbGw9dGlwb191bml2ZXJzaWRhZCkpICsNCiAgZ2VvbV9yZWN0KCkgKw0KICBjb29yZF9wb2xhcih0aGV0YSA9ICJ5IikgKw0KICB4bGltKGMoMiw0KSkgKw0KICB0aGVtZV92b2lkKCkgKyAgICAgICAgICAgICAjIEVsaW1pbmEgZm9uZG9zIHkgcmVmZXJlbmNpYXMNCiAgc2NhbGVfZmlsbF92aXJpZGlzX2QoKSArICAgIyBEZWZpbmUgdW5hIGVzY2FsYSBkZSBjb2xvcmVzDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsDQogICAgICAgIHBsb3QudGl0bGUucG9zaXRpb24gPSAicGxvdCIpICsgIyBNb2RpZmljYSBwb3NpY2nDs24gbGV5ZW5kYXMgeSBkZWwgdMOtdHVsbw0KICBsYWJzKHRpdGxlID0gIlJlc3B1ZXN0YXMgc2Vnw7puIFRpcG8gZGUgVW5pdmVyc2lkYWQiLA0KICAgICAgIGZpbGwgPSAiVGlwbyBkZSBVbml2ZXJzaWRhZCIsIA0KICAgICAgIGNhcHRpb24gPSAiRnVlbnRlOiBFbmN1ZXN0YSBLSVdJIGRlIFN1ZWxkb3MgZGUgUkggMjAyMCIpICsNCiAgZ2VvbV9sYWJlbCh4ID0gMy41LA0KICAgICAgICAgICAgIGFlcyh5ID0gcG9zaWNpb25fZXRpcXVldGEsDQogICAgICAgICAgICAgICAgIGxhYmVsID0gZXRpcXVldGEpLA0KICAgICAgICAgICAgIHNpemUgPSAzKQ0KDQoNCmBgYA0KDQojIyBDaGVjayBvdXQNCg0KYGdncGxvdDJgIGVzIHVuIHBhcXVldGUgcXVlIHRpZW5lIHVuYSBpbmZpbmlkYWQgZGUgcG9zaWJpbGlkYWRlcywgdGllbmUgbXVjaGFzIGV4dGVuc2lvbmVzIHF1ZSBwb3NpYmlsaXRhbiBjb25zdHJ1aXIgdG9kbyB0aXBvIGRlIGdyw6FmaWNvcywgYcOxYWRpcmxlcyBpbnRlcmFjdGl2aWRhZCwgaW5mb3JtYWNpw7NuIGRpbsOhbWljYSB5IG11Y2hhcyBjb3NhcyBtw6FzLg0KDQpFc3RlIHBhcXVldGUgY29uc3RydXllIGxvcyBncsOhZmljb3MgcG9yIGNhcGFzLiBMYXMgY2FwYXMgZnVuZGFtZW50YWxlcyBzb246DQoNCi0gICBEYXRvcw0KDQotICAgVmFyaWFibGVzLCBxdWUgc2UgYXNpZ25hbiBkZW50cm8gZGVsIGBhZXMoKWAuDQoNCi0gICBVbiBgZ2VvbV8iYWxnbyJgIHF1ZSBsZSB2YSBhIGRhciBsYSBmb3JtYSBhbCBncsOhZmljby4NCg0KTG9zIGdyw6FmaWNvcyBhZGVtw6FzIHNlIHB1ZWRlbiBjb21iaW5hciBhZ3JlZ2FuZG8gY2FwYXMsIGxvIGN1YWwgcG9zaWJpbGl0YSBhZ3JlZ2FyIGluZm9ybWFjacOzbiwgbyBsaW1waWFyIGxvcyBncsOhZmljb3MgcGFyYSBhw7FhZGlyIGluZm9ybWFjacOzbiBkZSBjb250ZXh0by4NCg0KQ3VzdG9taXphciB1biBncsOhZmljbyBsbGV2YSB0cmFiYWpvLCBwZXJvIHRvZG9zIGVzb3MgZWxlbWVudG9zIHNlIHB1ZWRlbiBndWFyZGFyIGVuIG9iamV0b3MgeSByZXV0aWxpemFybG9zIHBhcmEgYWhvcnJhciBjw7NkaWdvIHkgZXNmdWVyem8uDQoNCkVzdG8gbWUgcGVybWl0ZSBpciB0cmFiYWphbmRvIHByb2dyZXNpdmFtZW50ZSBjb24gbG9zIGdyw6FmaWNvcy4gUHJpbWVybyBtZSBhc2VndXJvIHF1ZSBlbCBncsOhZmljbyBmdW5jaW9uZSwgeSBsdWVnbyB2b3kgaW5jb3Jwb3JhbmRvIGNhcGFzIHBhcmEgZGVmaW5pciBjb2xvcmVzLCBsb3MgZWplcywgbG9zIHTDrXR1bG9zLCB5IGZpbmFsbWVudGUgbGEgZXN0w6l0aWNhIGdlbmVyYWwgZGVsIGdyw6FmaWNvLg0KDQpQdWVkZW4gZXhwbG9yYXIgYWxndW5hcyBleHRlbnNpb25lcyBlbiBlc3RlIGxpbms6IDxodHRwczovL2V4dHMuZ2dwbG90Mi50aWR5dmVyc2Uub3JnL2dhbGxlcnkvPi4gVGFtYmnDqW4gaGF5IHVuIGxpYnJvIG9ubGluZSAoZW4gaW5nbMOpcykgcXVlIHB1ZWRlbiByZXZpc2FyIGFjw6E6IDxodHRwczovL2dncGxvdDItYm9vay5vcmcvPi4NCg==