Marco

El taller abierto es un espacio de encuentro para conocer y utilizar entre todos y todas herramientas de valor profesional para la ciencias sociales, son llevados adelante por el Núcleo de Innovación Social, con el aval del Colegio de Sociólogos y Sociólogas de la Provincia de Buenos Aires (Ley 10.307), el Consejo de Profesionales en Sociología (Ley 23.553) y la Asociación de Sociólogos de la República Argentina.

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

skim_variable n_missing complete_rate min max empty n_unique whitespace
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

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
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:

  1. 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.

  2. 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