Presentación
El presente documento es un material de taller pensado para profesionales de las ciencias sociales y público interesado. Procuraremos aquí presentar de manera general una serie de procedimientos asociados al procesamiento de encuestas con R.
Veremos aquí:
Carga de datos de un formulario drive y transformación.
Análisis preliminar/exploratorio.
Visualización.
Recomendaciones profesionales: visual mode (ahora mismo), skimr, esquisser y janitor.
Carga de datos
Los datos de trabajo pertenecen a una sub-muestra de una encuesta realizada por los Colegios Profesionales de Buenos Aires y el NIS a comienzos de la pandemia, los mismos son 100% anónimos y fueron recabados por medio de un formulario Google.
Comenzamos cargando en R las respuestas de drive (previamente debemos compartirlo como público en la web, en formato csv) y creamos el objeto muestra1.
muestra1<-read.csv("https://docs.google.com/spreadsheets/d/e/2PACX-1vTbdWYdjYhfvt8quj9A5LpIEhH-sSKwxTsG8lKLLK_E_C5r1tkqFNdQNSAdzXvgthWCrFDn7oiN3-9P/pub?gid=346447959&single=true&output=csv",encoding = "UTF-8")
Exploramos con funciones base de R nuestros datos (todavía no estamos usando paquetes).
Indagamos acerca de la clase de nuestros datos:
class(muestra1)
## [1] "data.frame"
Consultamos la dimensión del conjunto de datos, filas y columnas:
dim(muestra1)
## [1] 627 24
Y podríamos seguir así, pero no, cargamos el (muy genial) paquete skimr el cual nos ayudará a crear un primer resumen de las características de nuestro set de datos (tengamos presente que para correr un paquete primero hay que instalarlo).
#install.packages("skimr") #lo grisado no se ejecuta
library(skimr)
## Warning: package 'skimr' was built under R version 4.1.3
skim(muestra1)
Data summary
| Name |
muestra1 |
| Number of rows |
627 |
| Number of columns |
24 |
| _______________________ |
|
| Column type frequency: |
|
| character |
19 |
| numeric |
5 |
| ________________________ |
|
| Group variables |
None |
Variable type: character
| Marca.temporal |
0 |
1 |
17 |
19 |
0 |
622 |
0 |
| X.Estás.haciendo.cuarentena. |
0 |
1 |
2 |
2 |
0 |
2 |
0 |
| Te.identificas.como. |
0 |
1 |
0 |
6 |
9 |
3 |
0 |
| X.En.qué.provincia.vivís.actualmente. |
0 |
1 |
0 |
31 |
9 |
18 |
0 |
| X.Cuál.es.el.máximo.nivel.educativo.que.completaste. |
0 |
1 |
0 |
36 |
9 |
9 |
0 |
| X.Cuál.es.tu.principal.ocupación. |
0 |
1 |
0 |
156 |
9 |
11 |
0 |
| X.Estas.trabajando.desde.tu.casa.bajo.alguna.modalidad.de.tele.trabajo..home.office.. |
0 |
1 |
0 |
29 |
119 |
4 |
0 |
| X.Tenes.hijos.en.edad.escolar. |
0 |
1 |
0 |
49 |
9 |
5 |
0 |
| X.Estás.viviendo.con.ellos.durante.esta.cuarentena. |
0 |
1 |
0 |
68 |
310 |
4 |
0 |
| De.la.siguiente.lista..Cuáles.son.tus.tres.principales.medios.para.informarte.sobre.los.asuntos.del.país.y.la.circunstancia.del.coronavirus. |
0 |
1 |
0 |
151 |
9 |
246 |
0 |
| X.Te.gustaría.nombrar.algún.otro.medio.que.estés.usando. |
0 |
1 |
0 |
125 |
224 |
119 |
0 |
| X.Cambiaste.la.forma.en.que.te.informas.desde.que.comenzó.la.cuarentena. |
0 |
1 |
0 |
2 |
9 |
3 |
0 |
| X.Cómo.cambió.la.forma.en.que.te.informaste |
0 |
1 |
0 |
626 |
426 |
201 |
0 |
| X.Recibiste.noticias..información.relacionada.al.coronavirus.y.o.la.cuarentena.que.resultaron.ser.falsas. |
0 |
1 |
0 |
5 |
9 |
4 |
0 |
| X.Recordas.a.través.de.qué.medio.recibiste.esa.información.falsa. |
0 |
1 |
0 |
152 |
159 |
103 |
0 |
| X.Crees.que.las.noticias.falsas.o.fake.news.están.influyendo.en.el.comportamiento.de.las.personas. |
0 |
1 |
0 |
5 |
9 |
4 |
0 |
| X.Cómo.crees.que.influyen.las.noticias.falsas.o.fake.news.están.influyendo.en.el.comportamiento.de.las.personas. |
0 |
1 |
0 |
909 |
212 |
400 |
0 |
| X.Cuál.es.la.ocupación.de.la.persona.que.realiza.el.principal.aporte.económico. |
0 |
1 |
0 |
167 |
9 |
11 |
0 |
| Ante.una.emergencia.médica..problema.de.salud..a.dónde.acudis.primero. |
0 |
1 |
0 |
116 |
12 |
20 |
0 |
Variable type: numeric
| X.Cuántos.años.tenés. |
9 |
0.99 |
42.48 |
13.65 |
18 |
32 |
40 |
53 |
82 |
▅▇▅▃▁ |
| X.En.qué.medida.te.sentís.informado.a.acerca.de.las.medidas.de.prevención.del.Coronavirus. |
9 |
0.99 |
4.28 |
0.79 |
1 |
4 |
4 |
5 |
5 |
▁▁▂▆▇ |
| X.Cuál.es.tu.opinión.acerca.de.lo.que.comunican.los.medios.de.comunicación.argentinos.sobre.el.Coronavirus. |
9 |
0.99 |
3.34 |
0.89 |
1 |
3 |
3 |
4 |
5 |
▁▂▇▆▂ |
| X.Cuántas.personas.viven.en.tu.hogar.incluyéndote.a.vos. |
9 |
0.99 |
3.54 |
20.97 |
0 |
2 |
2 |
4 |
522 |
▇▁▁▁▁ |
| X.y.cuántas.realizan.algún.tipo.de.aporte.económico. |
9 |
0.99 |
1.78 |
0.81 |
0 |
1 |
2 |
2 |
5 |
▆▇▂▁▁ |
Un resumen de nuestros datos con dos líneas de código, genial no? Este tipo de paquetes y funciones caracterizan a R, existen muchos desarrollos de la comunidad que pueden ayudarnos en nuestra labor diaria. Lo importante es conocerlos y contar con el criterio de saber en qué momento y cómo usarlos.
Limpieza de datos
Como hemos visto, tenemos una muestra de respondentes y la propuesta es ahora presentar algunos cálculos de estadística descriptiva y generar visualizaciones, ya que una parte importante de nuestro trabajo con encuestas tiene que ver con armar gráficos que reflejen el comportamiento de variables.
Ahora bien, antes de avanzar precisamos hacerle algunos ajustes a nuestros datos.
Para llevar adelante este proceso vamos a cargar dos paquetes muy útiles para transformar datos -tidyverse- ly normalizar las fechas -lubridate-.
#install.packages("tidyverse")
library(tidyverse)
#install.packages("lubridate")
library(lubridate)
Creamos el objeto muestra2, son nuestros datos de partida con fechas normalizadas y espacios en blanco reemplazados por NAs (mejora el procesamiento). Lo hacemos mediante las siguientes transformaciones:
muestra2<-muestra1%>% #pipe de tidyverse
mutate(Marca.temporal=sub(" .*", "", Marca.temporal))%>%
#transformamos nuestros datos
mutate(Marca.temporal=dmy(Marca.temporal))%>% #formateamos fecha
mutate_if(is.character, list(~na_if(.,"")))
Primeras preguntas
Dado el ajuste rápido de nuestros datos, queremos conocer más sobre el proceso de campo del formulario, por ejemplo: entre qué fechas tuvo lugar y cuántos respondentes tuvo por día?
Veamos qué podemos decir con nuestro objeto muestra2:
respuestas <- muestra2%>%
group_by(Marca.temporal)%>% #agrupamos por fecha
count() #contamos respuestas por fecha
respuestas
## # A tibble: 25 x 2
## # Groups: Marca.temporal [25]
## Marca.temporal n
## <date> <int>
## 1 2020-03-31 2
## 2 2020-04-06 367
## 3 2020-04-07 116
## 4 2020-04-08 50
## 5 2020-04-09 23
## 6 2020-04-10 27
## 7 2020-04-11 5
## 8 2020-04-12 2
## 9 2020-04-13 4
## 10 2020-04-14 3
## # ... with 15 more rows
Graficamos las respuestas por día con ggplot2, una librería R que sirve para hacer gráficos. Viene con el paquete tidyverse que ya tenemos activado.
Veamos como opera la lógica de estos gráficos en la práctica:
respuestas%>% #nuestro objeto
ggplot() + #declara la funcion para graficar el objeto
aes(x = Marca.temporal, y = n) + #idicamos las variables a graficar
geom_line(size = 0.5) #una geometria que la exprese, en este caso es una linea

Vemos que el momento de nuestro campo tuvo un período de actividad desde finales de marzo y durante todo abril, luego registró respuestas esporádicas (por error).
Repitamos el ejercicio poniendo nuestra atención en el lapso temporal en el que se registró la mayor cantidad de respuestas basándonos en la referencia visual que creamos.
respuestas%>%
filter(!Marca.temporal>="2020-05-01")%>% #excluimos mayo 2020 en adelante
ggplot() + #declara la funcion para graficar el objeto
aes(x = Marca.temporal, y = n) + #una geometria que la exprese, en este caso es una linea
geom_line(size = 0.9) #aumentamos la linea

Presentamos ahora una tecnología facilitadora del proceso que acabamos de realizar.
Gráficos con la librería Esquisse
Antes de contarles qué hace, veamos cómo funciona:
#install.packages("esquisse")
library(esquisse)
# grisamos nuestro codigo como un machete.
# lo a ctivamos para consulta
# respuestas%>%
# esquisser()
Esquisse ayuda a explorar y visualizar nuestros datos de forma interactiva. El paquete crea gráficos ggplot de manera ágil por medio de una interfaz basada en arrastrar, soltar y filtrar para luego exportar los resultados como .png, .jpg o recuperar el código.
Plantea dos utilidades principales:
EDA al instante: aunque ggplot es muy rápido y fácil de usar, esquisse permite explorar visualmente los datos en todos los ángulos con una variedad de tipos de gráficos, filtros, agrupaciones, etc.
Conocer ggplot : con este paquete se puede crear rápidamente un gráfico, mirar el código, hacer un cambio, ver cómo eso impactó en el código y repetir.
Como se distribuye la variable edad de nuestra muestra? lo exploramos con esquisse.
# muestra2%>%
# esquisser()
# Cod: ejemplo
ggplot(muestra2) +
aes(x = X.Cuántos.años.tenés.) +
geom_histogram(bins = 10L, fill = "#46337E") +
labs(
x = "años",
y = "n respondentes",
title = "Distribucion de la variable edad",
subtitle = "datos de muestra"
) +
theme_light()
## Warning: Removed 9 rows containing non-finite values (stat_bin).

Calculemos porcentuales
El paquete janitor es otro aliado imprescindible ya que suma una una gama extra de funcionalidades a la hora de limpiar datos, entre las más destacables: genera nombres de columnas legibles, elimina columnas y filas vacías y encuentra valores duplicados. Aquí la usaremos para un proceso muy específico que es la creación de tablas de frecuencias y porcentuales.
#install.packages("janitor")
library(janitor)
cuarentena<-muestra2%>%
tabyl(X.Estás.haciendo.cuarentena.)
print(cuarentena)
## X.Estás.haciendo.cuarentena. n percent
## No 9 0.01435407
## Sí 618 0.98564593
El recorte de nuestra muestra indica que casi el 99% estaba haciendo cuarentena al momento de responder el formulario.
Crucemos ahora estos datos con la variable de tenencia de hijos en edad escolar, para crear una tabla de doble entrada.
cruce <- muestra2 %>%
rename(hace_home=X.Estas.trabajando.desde.tu.casa.bajo.alguna.modalidad.de.tele.trabajo..home.office..)%>%
tabyl(X.Tenes.hijos.en.edad.escolar.,
hace_home,
show_na = FALSE)%>%
adorn_percentages("row")
cruce
## X.Tenes.hijos.en.edad.escolar. No Sí
## No, no tengo hijos 0.2154472 0.7276423
## Sí, tengo hijos en edad escolar 0.2352941 0.6993464
## Sí, tengo hijos pero aún no están en edad escolar 0.3000000 0.7000000
## Sí, tengo hijos pero ya no tienen edad escolar 0.2323232 0.7373737
## Siempre trabajo desde mi casa
## 0.05691057
## 0.06535948
## 0.00000000
## 0.03030303
# y si lo esquisiamos (?
# cruce%>%
# esquisser() #que pasa?
Asi como los estamos exportando no podemos graficarlos con ggplot ya que se multiplican las columnas con información. Para evitar que esto pase, un procedimiento habitual es volver a transformar nuestros datos en un par clave-valor.
cruce2 <- cruce%>%
gather('hace_home', 'pct', c(2:4))%>% #reune varias columnas para convertirlas en un par clave-valor
mutate(pct=round(pct*100, 1))# formateamos porcentaje
head(cruce2)
## X.Tenes.hijos.en.edad.escolar. hace_home pct
## 1 No, no tengo hijos No 21.5
## 2 Sí, tengo hijos en edad escolar No 23.5
## 3 Sí, tengo hijos pero aún no están en edad escolar No 30.0
## 4 Sí, tengo hijos pero ya no tienen edad escolar No 23.2
## 5 No, no tengo hijos Sí 72.8
## 6 Sí, tengo hijos en edad escolar Sí 69.9
#checkeamos
# cruce2%>%
# esquisser()
Con nuestro datos transformados podríamos generar un gráfico de base similar a este:
ggplot(cruce2) +
aes(x = X.Tenes.hijos.en.edad.escolar., y = pct, fill = hace_home) +
geom_col() +
scale_fill_hue(direction = 1) +
theme(axis.text.x = element_text(angle = 45))

Procesando variable de escala Likert
O casi. Transformamos la pregunta: en qué medida te sentís informado a acerca de las medidas de prevención del Coronavirus, con una escala de 1 a 5, donde 1 es nada informado/a y 5 es muy informado/a.
muestra3<-muestra1%>%
rename(informa=X.En.qué.medida.te.sentís.informado.a.acerca.de.las.medidas.de.prevención.del.Coronavirus.)%>%
tabyl(informa,
show_na = FALSE)
muestra3<-muestra3%>%
mutate(percent=round(percent*100,1))%>%
mutate(informa=case_when(informa==1~"1 nada informado/a",
informa==2~"2 un poco informado/a",
informa==3~"3 informado/a",
informa==4~"4 bastante informado/a",
informa==5~"5 muy informado/a"))%>%
mutate(informa=as.factor(informa))
#repetimos el esquisseo (??
# muestra3%>%
# esquisser()
Ejemplo: monitor socioeconómico
Es un tablero creado completamente en R que extrae los microdatos de la Encuesta Permanente de Hogares (INDEC), los procesa y visualiza de manera dinámica para conocer más sobre la coyuntura e historia reciente del mercado de trabajo y condiciones de vida en Argentina.
Se trata de un proyecto en progreso del NIS que da cuenta de cómo podemos usar las nuevas herramientas de análisis y programación para automatizar y comunicar nuestro trabajo.
Bonus
La lógica de visualización no es solo para datos, ubicando puntos en los ejes x e y también podremos dibujar:
seq(-2,2, by = 0.01) %>%
expand.grid(x=., y=.) %>%
ggplot(aes(x = x^3 - sin(y), y = y^3 - cos(x)))+
geom_point(alpha = 0.05,
color = "#5E17EB", shape = 20, size = 0)+ #https://www.color-hex.com/
theme_void()+
coord_polar()+
labs(subtitle = "Llegamos al final del taller abierto, gracias por participar")

Hasta la próxima!
LS0tDQp0aXRsZTogIlRhbGxlciBhYmllcnRvIg0KYXV0aG9yOiAiUGVkcm8gT3JkZW4iDQpkYXRlOiAiMTYvOS8yMDIyIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICB0aGVtZTogc2ltcGxleA0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KYGBgDQoNCiMjIE1hcmNvDQoNCkVsIFt0YWxsZXIgYWJpZXJ0b10oaHR0cHM6Ly93d3cuY2FudmEuY29tL2Rlc2lnbi9EQUZMeU4ydy1ldy9qSno3Y3M2aWd3dy1pZ08yblZvQ2VBL3ZpZXcpIGVzIHVuIGVzcGFjaW8gZGUgZW5jdWVudHJvIHBhcmEgY29ub2NlciB5IHV0aWxpemFyIGVudHJlIHRvZG9zIHkgdG9kYXMgaGVycmFtaWVudGFzIGRlIHZhbG9yIHByb2Zlc2lvbmFsIHBhcmEgbGEgY2llbmNpYXMgc29jaWFsZXMsIHNvbiBsbGV2YWRvcyBhZGVsYW50ZSBwb3IgZWwgW07DumNsZW8gZGUgSW5ub3ZhY2nDs24gU29jaWFsXShodHRwczovL3d3dy5udWNsZW9kZWlubm92YWNpb24uY29tLyksIGNvbiBlbCBhdmFsIGRlbCBbQ29sZWdpbyBkZSBTb2Npw7Nsb2dvcyB5IFNvY2nDs2xvZ2FzIGRlIGxhIFByb3ZpbmNpYSBkZSBCdWVub3MgQWlyZXMgKExleSAxMC4zMDcpXShodHRwOi8vY3NwYmEub3JnLmFyLyksIGVsIFtDb25zZWpvIGRlIFByb2Zlc2lvbmFsZXMgZW4gU29jaW9sb2fDrWEgKExleSAyMy41NTMpXShodHRwOi8vY3BzLm9yZy5hci8pIHkgbGEgW0Fzb2NpYWNpw7NuIGRlIFNvY2nDs2xvZ29zIGRlIGxhIFJlcMO6YmxpY2EgQXJnZW50aW5hXShodHRwczovL3d3dy5mYWNlYm9vay5jb20vc29jaW9sb2dvcy5hcmdlbnRpbm9zLkFTUkEpLg0KDQojIyBQcmVzZW50YWNpw7NuDQoNCkVsIHByZXNlbnRlIGRvY3VtZW50byBlcyB1biBtYXRlcmlhbCBkZSB0YWxsZXIgcGVuc2FkbyBwYXJhIHByb2Zlc2lvbmFsZXMgZGUgbGFzIGNpZW5jaWFzIHNvY2lhbGVzIHkgcMO6YmxpY28gaW50ZXJlc2Fkby4gUHJvY3VyYXJlbW9zIGFxdcOtIHByZXNlbnRhciBkZSBtYW5lcmEgZ2VuZXJhbCB1bmEgc2VyaWUgZGUgcHJvY2VkaW1pZW50b3MgYXNvY2lhZG9zIGFsIHByb2Nlc2FtaWVudG8gZGUgZW5jdWVzdGFzIGNvbiBSLg0KDQpWZXJlbW9zIGFxdcOtOg0KDQotICAgQ2FyZ2EgZGUgZGF0b3MgZGUgdW4gZm9ybXVsYXJpbyBkcml2ZSB5IHRyYW5zZm9ybWFjacOzbi4NCg0KLSAgIEFuw6FsaXNpcyBwcmVsaW1pbmFyL2V4cGxvcmF0b3Jpby4NCg0KLSAgIFZpc3VhbGl6YWNpw7NuLg0KDQotICAgUmVjb21lbmRhY2lvbmVzIHByb2Zlc2lvbmFsZXM6IFt2aXN1YWwgbW9kZV0oaHR0cHM6Ly93d3cucnN0dWRpby5jb20vYmxvZy9leHBsb3JpbmctcnN0dWRpby12aXN1YWwtbWFya2Rvd24tZWRpdG9yLykgKFthaG9yYSBtaXNtb117LnVsfSksIFtza2ltcl0oaHR0cHM6Ly9kb2NzLnJvcGVuc2NpLm9yZy9za2ltci8pLCBbZXNxdWlzc2VyXShodHRwczovL2RyZWFtcnMuZ2l0aHViLmlvL2VzcXVpc3NlLykgeSBbamFuaXRvcl0oaHR0cDovL3NmaXJrZS5naXRodWIuaW8vamFuaXRvci8pLg0KDQojIyBDYXJnYSBkZSBkYXRvcw0KDQpMb3MgZGF0b3MgZGUgdHJhYmFqbyBwZXJ0ZW5lY2VuIGEgdW5hIHN1Yi1tdWVzdHJhIGRlIHVuYSBlbmN1ZXN0YSByZWFsaXphZGEgcG9yIGxvcyBbQ29sZWdpb3MgUHJvZmVzaW9uYWxlcyBkZSBCdWVub3MgQWlyZXMgeSBlbCBOSVNdKGh0dHBzOi8vY2xpcC11cmJhbm8uY29tLzIwMjAvMDQvMDUvZWwtY29sZWdpby1kZS1zb2Npb2xvZ29zLWludml0YS1hLXBhcnRpY2lwYXItZGUtdW5hLWVuY3Vlc3RhLXNvYnJlLW1lZGlvcy1lLWluZm9ybWFjaW9uLWVuLXRpZW1wb3MtZGUtcGFuZGVtaWEvKSBhIGNvbWllbnpvcyBkZSBsYSBwYW5kZW1pYSwgbG9zIG1pc21vcyBzb24gMTAwJSBhbsOzbmltb3MgeSBmdWVyb24gcmVjYWJhZG9zIHBvciBtZWRpbyBkZSB1biBmb3JtdWxhcmlvIEdvb2dsZS4NCg0KQ29tZW56YW1vcyBjYXJnYW5kbyBlbiBSIGxhcyByZXNwdWVzdGFzIGRlICoqZHJpdmUqKiAocHJldmlhbWVudGUgZGViZW1vcyBjb21wYXJ0aXJsbyBjb21vIHDDumJsaWNvIGVuIGxhIHdlYiwgZW4gZm9ybWF0byAqY3N2KikgeSBjcmVhbW9zIGVsIG9iamV0byAqbXVlc3RyYTEqLg0KDQpgYGB7cn0NCm11ZXN0cmExPC1yZWFkLmNzdigiaHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vc3ByZWFkc2hlZXRzL2QvZS8yUEFDWC0xdlRiZFdZZGpZaGZ2dDhxdWo5QTVMcElFaEgtc1NLd3hUc0c4bEtMTEtfRV9DNXIxdGtxRk5kUU5TQWR6WHZndGhXQ3JGRG43b2lOMy05UC9wdWI/Z2lkPTM0NjQ0Nzk1OSZzaW5nbGU9dHJ1ZSZvdXRwdXQ9Y3N2IixlbmNvZGluZyA9ICJVVEYtOCIpDQpgYGANCg0KRXhwbG9yYW1vcyBjb24gKipmdW5jaW9uZXMgYmFzZSoqIGRlIFIgbnVlc3Ryb3MgZGF0b3MgKHRvZGF2w61hIG5vIGVzdGFtb3MgdXNhbmRvIHBhcXVldGVzKS4NCg0KSW5kYWdhbW9zIGFjZXJjYSBkZSBsYSBjbGFzZSBkZSBudWVzdHJvcyBkYXRvczoNCg0KYGBge3J9DQpjbGFzcyhtdWVzdHJhMSkNCmBgYA0KDQpDb25zdWx0YW1vcyBsYSBkaW1lbnNpw7NuIGRlbCBjb25qdW50byBkZSBkYXRvcywgZmlsYXMgeSBjb2x1bW5hczoNCg0KYGBge3J9DQpkaW0obXVlc3RyYTEpDQpgYGANCg0KWSBwb2Ryw61hbW9zIHNlZ3VpciBhc8OtLCBwZXJvIG5vLCBjYXJnYW1vcyBlbCAqKG11eSBnZW5pYWwpKiBwYXF1ZXRlIFtza2ltcl0oaHR0cHM6Ly9kb2NzLnJvcGVuc2NpLm9yZy9za2ltci8pIGVsIGN1YWwgbm9zIGF5dWRhcsOhIGEgY3JlYXIgdW4gcHJpbWVyICoqcmVzdW1lbioqIGRlIGxhcyBjYXJhY3RlcsOtc3RpY2FzIGRlIG51ZXN0cm8gc2V0IGRlIGRhdG9zICh0ZW5nYW1vcyBwcmVzZW50ZSBxdWUgcGFyYSBjb3JyZXIgdW4gcGFxdWV0ZSBwcmltZXJvIGhheSBxdWUgaW5zdGFsYXJsbykuDQoNCmBgYHtyfQ0KI2luc3RhbGwucGFja2FnZXMoInNraW1yIikgI2xvIGdyaXNhZG8gbm8gc2UgZWplY3V0YQ0KbGlicmFyeShza2ltcikNCnNraW0obXVlc3RyYTEpDQpgYGANCg0KVW4gcmVzdW1lbiBkZSBudWVzdHJvcyBkYXRvcyBjb24gZG9zIGzDrW5lYXMgZGUgY8OzZGlnbywgZ2VuaWFsIG5vPyBFc3RlIHRpcG8gZGUgcGFxdWV0ZXMgeSBmdW5jaW9uZXMgY2FyYWN0ZXJpemFuIGEgUiwgZXhpc3RlbiBtdWNob3MgZGVzYXJyb2xsb3MgZGUgbGEgW2NvbXVuaWRhZF0oaHR0cHM6Ly9jb21tdW5pdHkucnN0dWRpby5jb20vKSBxdWUgcHVlZGVuIGF5dWRhcm5vcyBlbiBudWVzdHJhIGxhYm9yIGRpYXJpYS4gTG8gW2ltcG9ydGFudGVdey51bH0gZXMgY29ub2NlcmxvcyB5IGNvbnRhciBjb24gZWwgY3JpdGVyaW8gZGUgc2FiZXIgZW4gcXXDqSBtb21lbnRvIHkgY8OzbW8gdXNhcmxvcy4NCg0KIyMgTGltcGllemEgZGUgZGF0b3MNCg0KQ29tbyBoZW1vcyB2aXN0bywgdGVuZW1vcyB1bmEgbXVlc3RyYSBkZSByZXNwb25kZW50ZXMgeSBsYSBwcm9wdWVzdGEgZXMgYWhvcmEgcHJlc2VudGFyIGFsZ3Vub3MgY8OhbGN1bG9zIGRlIGVzdGFkw61zdGljYSBkZXNjcmlwdGl2YSB5IGdlbmVyYXIgdmlzdWFsaXphY2lvbmVzLCB5YSBxdWUgdW5hIHBhcnRlIGltcG9ydGFudGUgZGUgbnVlc3RybyB0cmFiYWpvIGNvbiBlbmN1ZXN0YXMgdGllbmUgcXVlIHZlciBjb24gYXJtYXIgZ3LDoWZpY29zIHF1ZSByZWZsZWplbiBlbCBjb21wb3J0YW1pZW50byBkZSB2YXJpYWJsZXMuDQoNCkFob3JhIGJpZW4sIGFudGVzIGRlIGF2YW56YXIgcHJlY2lzYW1vcyBoYWNlcmxlIGFsZ3Vub3MgYWp1c3RlcyBhIG51ZXN0cm9zIGRhdG9zLg0KDQpQYXJhIGxsZXZhciBhZGVsYW50ZSBlc3RlIHByb2Nlc28gdmFtb3MgYSBjYXJnYXIgZG9zIHBhcXVldGVzIG11eSDDunRpbGVzIHBhcmEgdHJhbnNmb3JtYXIgZGF0b3MgLVt0aWR5dmVyc2VdKGh0dHBzOi8vd3d3LnRpZHl2ZXJzZS5vcmcvKS0gbHkgbm9ybWFsaXphciBsYXMgZmVjaGFzIC1bbHVicmlkYXRlXShodHRwczovL2x1YnJpZGF0ZS50aWR5dmVyc2Uub3JnLyktLg0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KI2luc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCiNpbnN0YWxsLnBhY2thZ2VzKCJsdWJyaWRhdGUiKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpgYGANCg0KQ3JlYW1vcyBlbCBvYmpldG8gbXVlc3RyYTIsIHNvbiBudWVzdHJvcyBkYXRvcyBkZSBwYXJ0aWRhIGNvbiAqZmVjaGFzKiBub3JtYWxpemFkYXMgeSAqZXNwYWNpb3MqIGVuIGJsYW5jbyByZWVtcGxhemFkb3MgcG9yIE5BcyAobWVqb3JhIGVsIHByb2Nlc2FtaWVudG8pLiBMbyBoYWNlbW9zIG1lZGlhbnRlIGxhcyBzaWd1aWVudGVzIHRyYW5zZm9ybWFjaW9uZXM6DQoNCmBgYHtyfQ0KbXVlc3RyYTI8LW11ZXN0cmExJT4lICNwaXBlIGRlIHRpZHl2ZXJzZQ0KICBtdXRhdGUoTWFyY2EudGVtcG9yYWw9c3ViKCIgLioiLCAiIiwgTWFyY2EudGVtcG9yYWwpKSU+JQ0KICAjdHJhbnNmb3JtYW1vcyBudWVzdHJvcyBkYXRvcw0KICBtdXRhdGUoTWFyY2EudGVtcG9yYWw9ZG15KE1hcmNhLnRlbXBvcmFsKSklPiUgI2Zvcm1hdGVhbW9zIGZlY2hhDQogIG11dGF0ZV9pZihpcy5jaGFyYWN0ZXIsIGxpc3Qofm5hX2lmKC4sIiIpKSkNCmBgYA0KDQojIyBQcmltZXJhcyBwcmVndW50YXMNCg0KRGFkbyBlbCBhanVzdGUgcsOhcGlkbyBkZSBudWVzdHJvcyBkYXRvcywgcXVlcmVtb3MgY29ub2NlciBtw6FzIHNvYnJlIGVsIHByb2Nlc28gZGUgY2FtcG8gZGVsIGZvcm11bGFyaW8sIHBvciBlamVtcGxvOiBlbnRyZSBxdcOpIGZlY2hhcyB0dXZvIGx1Z2FyIHkgY3XDoW50b3MgcmVzcG9uZGVudGVzIHR1dm8gcG9yIGTDrWE/DQoNClZlYW1vcyBxdcOpIHBvZGVtb3MgZGVjaXIgY29uIG51ZXN0cm8gb2JqZXRvIG11ZXN0cmEyOg0KDQpgYGB7cn0NCnJlc3B1ZXN0YXMgPC0gbXVlc3RyYTIlPiUNCiAgZ3JvdXBfYnkoTWFyY2EudGVtcG9yYWwpJT4lICNhZ3J1cGFtb3MgcG9yIGZlY2hhDQogIGNvdW50KCkgI2NvbnRhbW9zIHJlc3B1ZXN0YXMgcG9yIGZlY2hhDQoNCnJlc3B1ZXN0YXMNCmBgYA0KDQpHcmFmaWNhbW9zIGxhcyByZXNwdWVzdGFzIHBvciBkw61hIGNvbiBbZ2dwbG90Ml0oaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvKSwgdW5hIGxpYnJlcsOtYSBSIHF1ZSBzaXJ2ZSBwYXJhIGhhY2VyIGdyw6FmaWNvcy4gVmllbmUgY29uIGVsIHBhcXVldGUgdGlkeXZlcnNlIHF1ZSB5YSB0ZW5lbW9zIGFjdGl2YWRvLg0KDQpWZWFtb3MgY29tbyBvcGVyYSBsYSBsw7NnaWNhIGRlIGVzdG9zIGdyw6FmaWNvcyBlbiBsYSBwcsOhY3RpY2E6DQoNCmBgYHtyfQ0KcmVzcHVlc3RhcyU+JSAjbnVlc3RybyBvYmpldG8NCiAgZ2dwbG90KCkgKyAjZGVjbGFyYSBsYSBmdW5jaW9uIHBhcmEgZ3JhZmljYXIgZWwgb2JqZXRvDQogIGFlcyh4ID0gTWFyY2EudGVtcG9yYWwsIHkgPSBuKSArICNpZGljYW1vcyBsYXMgdmFyaWFibGVzIGEgZ3JhZmljYXINCiAgZ2VvbV9saW5lKHNpemUgPSAwLjUpICN1bmEgZ2VvbWV0cmlhIHF1ZSBsYSBleHByZXNlLCBlbiBlc3RlIGNhc28gZXMgdW5hIGxpbmVhDQpgYGANCg0KVmVtb3MgcXVlIGVsIG1vbWVudG8gZGUgbnVlc3RybyBjYW1wbyB0dXZvIHVuIHBlcsOtb2RvIGRlIGFjdGl2aWRhZCBkZXNkZSBmaW5hbGVzIGRlIG1hcnpvIHkgZHVyYW50ZSB0b2RvIGFicmlsLCBsdWVnbyByZWdpc3Ryw7MgcmVzcHVlc3RhcyBlc3BvcsOhZGljYXMgKHBvciBlcnJvcikuDQoNClJlcGl0YW1vcyBlbCBlamVyY2ljaW8gcG9uaWVuZG8gbnVlc3RyYSBhdGVuY2nDs24gZW4gZWwgbGFwc28gdGVtcG9yYWwgZW4gZWwgcXVlIHNlIHJlZ2lzdHLDsyBsYSBtYXlvciBjYW50aWRhZCBkZSByZXNwdWVzdGFzIGJhc8OhbmRvbm9zIGVuIGxhIHJlZmVyZW5jaWEgdmlzdWFsIHF1ZSBjcmVhbW9zLg0KDQpgYGB7cn0NCnJlc3B1ZXN0YXMlPiUNCiAgZmlsdGVyKCFNYXJjYS50ZW1wb3JhbD49IjIwMjAtMDUtMDEiKSU+JSAjZXhjbHVpbW9zIG1heW8gMjAyMCBlbiBhZGVsYW50ZQ0KICBnZ3Bsb3QoKSArICNkZWNsYXJhIGxhIGZ1bmNpb24gcGFyYSBncmFmaWNhciBlbCBvYmpldG8NCiAgYWVzKHggPSBNYXJjYS50ZW1wb3JhbCwgeSA9IG4pICsgI3VuYSBnZW9tZXRyaWEgcXVlIGxhIGV4cHJlc2UsIGVuIGVzdGUgY2FzbyBlcyB1bmEgbGluZWENCiAgZ2VvbV9saW5lKHNpemUgPSAwLjkpICNhdW1lbnRhbW9zIGxhIGxpbmVhDQpgYGANCg0KUHJlc2VudGFtb3MgYWhvcmEgdW5hIHRlY25vbG9nw61hICpmYWNpbGl0YWRvcmEqIGRlbCBwcm9jZXNvIHF1ZSBhY2FiYW1vcyBkZSByZWFsaXphci4NCg0KIyMgR3LDoWZpY29zIGNvbiBsYSBsaWJyZXLDrWEgRXNxdWlzc2UNCg0KQW50ZXMgZGUgY29udGFybGVzIHF1w6kgaGFjZSwgdmVhbW9zIGPDs21vIGZ1bmNpb25hOg0KDQpgYGB7cn0NCiNpbnN0YWxsLnBhY2thZ2VzKCJlc3F1aXNzZSIpDQpsaWJyYXJ5KGVzcXVpc3NlKQ0KIyBncmlzYW1vcyBudWVzdHJvIGNvZGlnbyBjb21vIHVuIG1hY2hldGUuDQojIGxvIGEgY3RpdmFtb3MgcGFyYSBjb25zdWx0YSANCiMgcmVzcHVlc3RhcyU+JQ0KIyAgIGVzcXVpc3NlcigpDQpgYGANCg0KWyoqRXNxdWlzc2UqKl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2VzcXVpc3NlL3ZpZ25ldHRlcy9nZXQtc3RhcnRlZC5odG1sKSBheXVkYSBhIGV4cGxvcmFyIHkgdmlzdWFsaXphciBudWVzdHJvcyBkYXRvcyBkZSBmb3JtYSBpbnRlcmFjdGl2YS4gRWwgcGFxdWV0ZSBjcmVhIGdyw6FmaWNvcyBnZ3Bsb3QgZGUgbWFuZXJhIMOhZ2lsIHBvciBtZWRpbyBkZSB1bmEgaW50ZXJmYXogYmFzYWRhIGVuIGFycmFzdHJhciwgc29sdGFyIHkgZmlsdHJhciBwYXJhIGx1ZWdvIGV4cG9ydGFyIGxvcyByZXN1bHRhZG9zIGNvbW8gLnBuZywgLmpwZyBvIHJlY3VwZXJhciBlbCBjw7NkaWdvLg0KDQpQbGFudGVhIGRvcyB1dGlsaWRhZGVzIHByaW5jaXBhbGVzOg0KDQoxLiAgKipFREEgYWwgaW5zdGFudGUqKjogYXVucXVlIGdncGxvdCBlcyBtdXkgcsOhcGlkbyB5IGbDoWNpbCBkZSB1c2FyLCBlc3F1aXNzZSBwZXJtaXRlIGV4cGxvcmFyIHZpc3VhbG1lbnRlIGxvcyBkYXRvcyBlbiB0b2RvcyBsb3Mgw6FuZ3Vsb3MgY29uIHVuYSB2YXJpZWRhZCBkZSB0aXBvcyBkZSBncsOhZmljb3MsIGZpbHRyb3MsIGFncnVwYWNpb25lcywgZXRjLg0KDQoyLiAgKipDb25vY2VyIGdncGxvdCoqIDogY29uIGVzdGUgcGFxdWV0ZSBzZSBwdWVkZSBjcmVhciByw6FwaWRhbWVudGUgdW4gZ3LDoWZpY28sIG1pcmFyIGVsIGPDs2RpZ28sIGhhY2VyIHVuIGNhbWJpbywgdmVyIGPDs21vIGVzbyBpbXBhY3TDsyBlbiBlbCBjw7NkaWdvIHkgcmVwZXRpci4NCg0KQ29tbyBzZSBkaXN0cmlidXllIGxhIHZhcmlhYmxlIGVkYWQgZGUgbnVlc3RyYSBtdWVzdHJhPyBsbyBleHBsb3JhbW9zIGNvbiBlc3F1aXNzZS4NCg0KYGBge3J9DQojIG11ZXN0cmEyJT4lDQojICAgZXNxdWlzc2VyKCkNCg0KIyBDb2Q6IGVqZW1wbG8NCiAgZ2dwbG90KG11ZXN0cmEyKSArDQogIGFlcyh4ID0gWC5DdcOhbnRvcy5hw7Fvcy50ZW7DqXMuKSArDQogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAxMEwsIGZpbGwgPSAiIzQ2MzM3RSIpICsNCiAgbGFicygNCiAgICB4ID0gImHDsW9zIiwNCiAgICB5ID0gIm4gcmVzcG9uZGVudGVzIiwNCiAgICB0aXRsZSA9ICJEaXN0cmlidWNpb24gZGUgbGEgdmFyaWFibGUgZWRhZCIsDQogICAgc3VidGl0bGUgPSAiZGF0b3MgZGUgbXVlc3RyYSINCiAgKSArDQogIHRoZW1lX2xpZ2h0KCkNCmBgYA0KDQojIyBDYWxjdWxlbW9zIHBvcmNlbnR1YWxlcw0KDQpFbCBwYXF1ZXRlIFtqYW5pdG9yXShodHRwOi8vc2ZpcmtlLmdpdGh1Yi5pby9qYW5pdG9yLykgZXMgb3RybyBhbGlhZG8gaW1wcmVzY2luZGlibGUgeWEgcXVlIHN1bWEgdW5hIHVuYSBnYW1hIGV4dHJhIGRlIGZ1bmNpb25hbGlkYWRlcyBhIGxhIGhvcmEgZGUgbGltcGlhciBkYXRvcywgZW50cmUgbGFzIG3DoXMgZGVzdGFjYWJsZXM6IGdlbmVyYSBub21icmVzIGRlIGNvbHVtbmFzIGxlZ2libGVzLCBlbGltaW5hIGNvbHVtbmFzIHkgZmlsYXMgdmFjw61hcyB5IGVuY3VlbnRyYSB2YWxvcmVzIGR1cGxpY2Fkb3MuIEFxdcOtIGxhIHVzYXJlbW9zIHBhcmEgdW4gcHJvY2VzbyBtdXkgZXNwZWPDrWZpY28gcXVlIGVzIGxhIGNyZWFjacOzbiBkZSB0YWJsYXMgZGUgZnJlY3VlbmNpYXMgeSBwb3JjZW50dWFsZXMuDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQojaW5zdGFsbC5wYWNrYWdlcygiamFuaXRvciIpDQpsaWJyYXJ5KGphbml0b3IpDQoNCmN1YXJlbnRlbmE8LW11ZXN0cmEyJT4lDQogICAgdGFieWwoWC5Fc3TDoXMuaGFjaWVuZG8uY3VhcmVudGVuYS4pDQoNCnByaW50KGN1YXJlbnRlbmEpDQpgYGANCg0KRWwgcmVjb3J0ZSBkZSBudWVzdHJhIG11ZXN0cmEgaW5kaWNhIHF1ZSBjYXNpIGVsIDk5JSBlc3RhYmEgaGFjaWVuZG8gY3VhcmVudGVuYSBhbCBtb21lbnRvIGRlIHJlc3BvbmRlciBlbCBmb3JtdWxhcmlvLg0KDQpDcnVjZW1vcyBhaG9yYSBlc3RvcyBkYXRvcyBjb24gbGEgdmFyaWFibGUgZGUgdGVuZW5jaWEgZGUgaGlqb3MgZW4gZWRhZCBlc2NvbGFyLCBwYXJhIGNyZWFyIHVuYSB0YWJsYSBkZSBkb2JsZSBlbnRyYWRhLg0KDQpgYGB7cn0NCmNydWNlIDwtIG11ZXN0cmEyICU+JQ0KICByZW5hbWUoaGFjZV9ob21lPVguRXN0YXMudHJhYmFqYW5kby5kZXNkZS50dS5jYXNhLmJham8uYWxndW5hLm1vZGFsaWRhZC5kZS50ZWxlLnRyYWJham8uLmhvbWUub2ZmaWNlLi4pJT4lDQogIHRhYnlsKFguVGVuZXMuaGlqb3MuZW4uZWRhZC5lc2NvbGFyLiwgDQogICAgICAgIGhhY2VfaG9tZSwNCiAgICAgICAgc2hvd19uYSA9IEZBTFNFKSU+JQ0KICBhZG9ybl9wZXJjZW50YWdlcygicm93IikNCg0KY3J1Y2UNCg0KIyB5IHNpIGxvIGVzcXVpc2lhbW9zICg/DQojIGNydWNlJT4lDQojICAgZXNxdWlzc2VyKCkgI3F1ZSBwYXNhPw0KYGBgDQoNCkFzaSBjb21vIGxvcyBlc3RhbW9zIGV4cG9ydGFuZG8gbm8gcG9kZW1vcyBncmFmaWNhcmxvcyBjb24gZ2dwbG90IHlhIHF1ZSBzZSBtdWx0aXBsaWNhbiBsYXMgY29sdW1uYXMgY29uIGluZm9ybWFjacOzbi4gUGFyYSBldml0YXIgcXVlIGVzdG8gcGFzZSwgdW4gcHJvY2VkaW1pZW50byBoYWJpdHVhbCBlcyB2b2x2ZXIgYSB0cmFuc2Zvcm1hciBudWVzdHJvcyBkYXRvcyBlbiB1biBwYXIgY2xhdmUtdmFsb3IuDQoNCmBgYHtyfQ0KY3J1Y2UyIDwtIGNydWNlJT4lDQogIGdhdGhlcignaGFjZV9ob21lJywgJ3BjdCcsIGMoMjo0KSklPiUgI3JldW5lIHZhcmlhcyBjb2x1bW5hcyBwYXJhIGNvbnZlcnRpcmxhcyBlbiB1biBwYXIgY2xhdmUtdmFsb3INCiAgbXV0YXRlKHBjdD1yb3VuZChwY3QqMTAwLCAxKSkjIGZvcm1hdGVhbW9zIHBvcmNlbnRhamUNCg0KaGVhZChjcnVjZTIpDQojY2hlY2tlYW1vcw0KIyBjcnVjZTIlPiUNCiMgICBlc3F1aXNzZXIoKQ0KYGBgDQoNCkNvbiBudWVzdHJvIGRhdG9zIHRyYW5zZm9ybWFkb3MgcG9kcsOtYW1vcyBnZW5lcmFyIHVuIGdyw6FmaWNvIGRlIGJhc2Ugc2ltaWxhciBhIGVzdGU6DQoNCmBgYHtyfQ0KZ2dwbG90KGNydWNlMikgKw0KIGFlcyh4ID0gWC5UZW5lcy5oaWpvcy5lbi5lZGFkLmVzY29sYXIuLCB5ID0gcGN0LCBmaWxsID0gaGFjZV9ob21lKSArDQogZ2VvbV9jb2woKSArDQogc2NhbGVfZmlsbF9odWUoZGlyZWN0aW9uID0gMSkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1KSkNCmBgYA0KDQojIyBQcm9jZXNhbmRvIHZhcmlhYmxlIGRlIGVzY2FsYSBMaWtlcnQNCg0KTyBjYXNpLiBUcmFuc2Zvcm1hbW9zIGxhIHByZWd1bnRhOiAqZW4gcXXDqSBtZWRpZGEgdGUgc2VudMOtcyBpbmZvcm1hZG8gYSBhY2VyY2EgZGUgbGFzIG1lZGlkYXMgZGUgcHJldmVuY2nDs24gZGVsIENvcm9uYXZpcnVzKiwgY29uIHVuYSBlc2NhbGEgZGUgMSBhIDUsIGRvbmRlIDEgZXMgKm5hZGEgaW5mb3JtYWRvL2EqIHkgNSBlcyAqbXV5IGluZm9ybWFkby9hKi4NCg0KYGBge3J9DQptdWVzdHJhMzwtbXVlc3RyYTElPiUNCiAgcmVuYW1lKGluZm9ybWE9WC5Fbi5xdcOpLm1lZGlkYS50ZS5zZW50w61zLmluZm9ybWFkby5hLmFjZXJjYS5kZS5sYXMubWVkaWRhcy5kZS5wcmV2ZW5jacOzbi5kZWwuQ29yb25hdmlydXMuKSU+JQ0KICB0YWJ5bChpbmZvcm1hLCANCiAgICAgICAgc2hvd19uYSA9IEZBTFNFKQ0KDQptdWVzdHJhMzwtbXVlc3RyYTMlPiUNCiAgbXV0YXRlKHBlcmNlbnQ9cm91bmQocGVyY2VudCoxMDAsMSkpJT4lDQogIG11dGF0ZShpbmZvcm1hPWNhc2Vfd2hlbihpbmZvcm1hPT0xfiIxIG5hZGEgaW5mb3JtYWRvL2EiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mb3JtYT09Mn4iMiB1biBwb2NvIGluZm9ybWFkby9hIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGluZm9ybWE9PTN+IjMgaW5mb3JtYWRvL2EiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5mb3JtYT09NH4iNCBiYXN0YW50ZSBpbmZvcm1hZG8vYSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBpbmZvcm1hPT01fiI1IG11eSBpbmZvcm1hZG8vYSIpKSU+JQ0KICBtdXRhdGUoaW5mb3JtYT1hcy5mYWN0b3IoaW5mb3JtYSkpDQoNCiNyZXBldGltb3MgZWwgZXNxdWlzc2VvICg/Pw0KIyBtdWVzdHJhMyU+JQ0KIyAgIGVzcXVpc3NlcigpDQpgYGANCg0KIyMgRWplbXBsbzogbW9uaXRvciBzb2Npb2Vjb27Ds21pY28NCg0KRXMgdW4gW3RhYmxlcm9dKGh0dHBzOi8vcGVkcm9vcmRlbi5zaGlueWFwcHMuaW8vc29jaW8tZWNvbm9taWNvLykgY3JlYWRvIGNvbXBsZXRhbWVudGUgZW4gUiBxdWUgZXh0cmFlIGxvcyBtaWNyb2RhdG9zIGRlIGxhIEVuY3Vlc3RhIFBlcm1hbmVudGUgZGUgSG9nYXJlcyAoSU5ERUMpLCBsb3MgcHJvY2VzYSB5IHZpc3VhbGl6YSBkZSBtYW5lcmEgZGluw6FtaWNhIHBhcmEgY29ub2NlciBtw6FzIHNvYnJlIGxhIGNveXVudHVyYSBlIGhpc3RvcmlhIHJlY2llbnRlIGRlbCBtZXJjYWRvIGRlIHRyYWJham8geSBjb25kaWNpb25lcyBkZSB2aWRhIGVuIEFyZ2VudGluYS4NCg0KU2UgdHJhdGEgZGUgdW4gcHJveWVjdG8gZW4gcHJvZ3Jlc28gZGVsICoqTklTKiogcXVlIGRhIGN1ZW50YSBkZSBjw7NtbyBwb2RlbW9zIHVzYXIgbGFzIG51ZXZhcyBoZXJyYW1pZW50YXMgZGUgYW7DoWxpc2lzIHkgcHJvZ3JhbWFjacOzbiBwYXJhIGF1dG9tYXRpemFyIHkgY29tdW5pY2FyIG51ZXN0cm8gdHJhYmFqby4NCg0KIyMgQm9udXMNCg0KTGEgbMOzZ2ljYSBkZSB2aXN1YWxpemFjacOzbiBubyBlcyBzb2xvIHBhcmEgZGF0b3MsIHViaWNhbmRvIHB1bnRvcyBlbiBsb3MgZWplcyAqKngqKiBlICoqeSoqIHRhbWJpw6luIHBvZHJlbW9zIGRpYnVqYXI6DQoNCmBgYHtyfQ0KDQpzZXEoLTIsMiwgYnkgPSAwLjAxKSAlPiUgDQogIGV4cGFuZC5ncmlkKHg9LiwgeT0uKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IHheMyAtIHNpbih5KSwgeSA9IHleMyAtIGNvcyh4KSkpKw0KICBnZW9tX3BvaW50KGFscGhhID0gMC4wNSwgDQogICAgICAgICAgICAgY29sb3IgPSAiIzVFMTdFQiIsIHNoYXBlID0gMjAsIHNpemUgPSAwKSsgI2h0dHBzOi8vd3d3LmNvbG9yLWhleC5jb20vDQogIHRoZW1lX3ZvaWQoKSsNCiAgY29vcmRfcG9sYXIoKSsNCiAgbGFicyhzdWJ0aXRsZSA9ICJMbGVnYW1vcyBhbCBmaW5hbCBkZWwgdGFsbGVyIGFiaWVydG8sIGdyYWNpYXMgcG9yIHBhcnRpY2lwYXIiKQ0KYGBgDQoNCkhhc3RhIGxhIHByw7N4aW1hIQ0K