1. Datos abiertos para la toma de decisiones

Los datos abiertos son aquellos “datos que pueden ser utilizados, reutilizados y redistribuidos libremente por cualquier persona”1. Para el tema de las políticas públicas, los datos abiertos permiten la participación de actores diferentes a los de la administración gubernamental. Esto se hace aún más importante en situaciones críticas donde se necesita desarrollar soluciones colectivas sobre problemas complejos, como en la actual crisis por el coronavirus.

Una de los problemas centrales que nos toca afrontar en la presente crisis consiste en compatibilizar las medidas de distanciamiento para evitar el contagío con la necesidad de realizar nuestras actividad laborales, educativas y sociales. Aquí el Internet juega un factor clave. Pero para ello es necesario saber de antemano en qué situación nos encontramos al respecto para tomar decisiones acertadas.

Sobre el tema de Internet y TIC, en nuestro país, el 2017 el gobierno lanzó una importante encuesta sobre Tecnologías de Información y Comunicación en Bolivia, la primera de su tipo. Un reporte inicial de los resultados se puede encotrar en el portal de la AGETIC y los datos fueron públicados en repositorio de datos abiertos del Estado.

Sin embargo, a la hora de procesarlos hemos encontrado algunos problemas en el formato del dataset.

2. El formato del dataset

Encontramos tres problemas:

  • Dificultad de cargar los datos con software libre
  • Formato de CSV invalido
  • Falta de semántica en sus variables y valores

2.1. Cargando el dataset

Descargamos el dataset en formato CSV del repositorio mencionado y realizamos los siguientes intentos de carga.

Primer intento con la función read.csv() en R

Nuestro primer intento con la ya anticuada pero todavía confiable función de read.csv() en R nos arroja lo siguiente :

base_r <- read.csv("base-5536-bdfinalcorregido.csv")
Error in read.table(file = file, header = header, sep = sep, quote = quote,  : 
  more columns than column names

Los datos no cargan y nos produce un error que afirma que existen más columnas que nombres de columnas…

Segundo intento con read_csv() de la librería readr en R

Ahora usamos el mucho más joven read_csv() que es más rápida y coerciona menos los tipos de datos:

library(readr)
base_r <- read_csv("base-5536-bdfinalcorregido.csv")

5536 parsing failures.

Más alla de los tipos de datos de las columnas que luego pueden especificarse, esta vez los datos cargan. Parece funcionar, aunque con algunas fallas. Vemoas la cabeza de nuestro dataset:

head(base_r, 2)

¡Pesadilla!. Cargó, pero la situación es mucho peor.

Intentemos con Python.

Tercer intento con read_csv() de la libreria pandas de Python

A pesar de que hay cierta hostilidad entre las comunidades de R y Python, aquí en el Lab nos llevamos bien con ambos.

import pandas as pd
base_p = pd.read_csv("base-5536-bdfinalcorregido.csv")
print(base_p.head(5))
ParserError: Error tokenizing data. C error: Expected 3 fields in line 17, saw 4

No logró cargar y otra vez error…

Solución

Inspeccionando el dataset más de cerca, vemos que el problema es que lleva como delimitador un ; en vez de ,. Este pequeño detalle nos ha ocasionado los problemas hasta ahora vistos. Usando la función read_delim en R o el parametro sepen pandas logramos cargar los datos.

library(readr)
base_r <- read_delim("base-5536-bdfinalcorregido.csv", delim = ";")
head(base_r, 5)

Ahora con Python:

base_p = pd.read_csv("base-5536-bdfinalcorregido.csv", sep=";")
print(base_p.head(5))
   NUMBOL  Tipo  P1  P2  ... CodP160    Ponderador5536    Ponderador5033 Nse
0       1     1  18   1  ...      33  1,66029585357411  2,55437533673007   3
1       2     1  21   1  ...      33  1,66029585357411  2,55437533673007   4
2       3     1  54   1  ...      33  1,66029585357411  2,55437533673007   2
3       4     1  30   1  ...      33  1,66029585357411  2,55437533673007   2
4       5     1  16   1  ...      33  1,66029585357411  2,55437533673007   2

[5 rows x 451 columns]

Si bien es cierto que este problema puede ser trivial para algunos, la idea de los datos abiertos es que tengan la mayor accesibilidad posible y puedan ser inmediatamente utilizados sin mayor problema de acceso. Y para eso deben ser validos, segun estandares y especificaciones.

2.2. CSV no valido

Más allá de su solución via parametros adicionales en el código, el problema central tiene que ver con que se ha publicado un CSV no valido. Subiendo este dataset a la herramienta de validación CSVlint del Open Data Institute, confirmamos esta situación:

2.3. Valores sin semántica

Ya lo tenemos cargado. Ahora vamos a analizarlo, ¿qué podría salir mal ahora? Exploremos.

Veamos la estructura del dataset:

str(base_r)
Classes ‘spec_tbl_df’, ‘tbl_df’, ‘tbl’ and 'data.frame':    5536 obs. of  451 variables:
 $ NUMBOL        : num  1 2 3 4 5 6 7 8 9 10 ...
 $ Tipo          : num  1 1 1 1 1 1 1 1 1 1 ...
 $ P1            : num  18 21 54 30 16 50 40 20 32 18 ...
 $ P2            : num  1 1 1 1 1 1 1 1 1 1 ...
 $ P3            : num  1 1 1 1 1 1 1 1 1 1 ...
 

Aquí tenemos un problema de semántica. Las variables no poseen nombres entendibles y tampoco los valores. No podemos hacer preguntas directas a la base de datos, ni siquiera sobre cosas tan básicas como la edad o el sexo. Intentemos con un diagrama de barras de la P3:

library(ggplot2)
  ggplot(base_r, aes(P3)) +
  geom_bar()

La visualización no muestra ni el nombre de la pregunta (solo P3), como tampoco los valores interpretables, (solo 1, 2, 3, 4). Si bien en el repositorio gubernamental existe un diccionario de datos en PDF, este no es directamente utilizable en el procesamiento de los datos y tampoco posee un formato abierto. Es necesario contar con las etiquetas de las variables y los valores para poder hacer una mejor interpretación y visualización de los datos.

3. Una versión propia, valida y semántica

Hemos dado una solución a los problemas de (1) validación de formato, que llevan a problemas en el cargado de los datos, y (2) a la semántica de variables y valores para una mejor interpretabilidad.

Las versiones que subimos a nuestro repositorio son CSV validos:

En nuestro repositorio pueden encontrar la misma versión no semántica del CSV publicado por el gobierno, pero con formato CSV Valido (datos_valores.csv), acompañada de dos tablas CSV para las etiquetas de las variables (etiquetas_variables.csv) y de los valores (etiquetas_valores.csv).

Sobre la semántica damos dos soluciones. La primera es una versión totalmente etiquetada tanto en variables y valores (datos_etiquetas_todo.csv). Esta es la versión que se puede usar para hacer análisis exploratorio con paquetes como Calc, Excel o Google Sheets. Tiene esta apariencia:

base_etiquetada <- read_csv("csv/eti/datos_etiquetas_todo.csv")
head(base_etiquetada, 5)

La segunda es mediante un dataset (base.csv) asociado a un diccionario (dic.csv), donde las etiquetas del diccionario pueden asociarse con los atributos de los datos mediante R o Python.

En los siguientes días sacaremos reportes de varias dimensiones de Internet y sociedad a partir de estos datos. Pero con los datos abiertos, tú también puedes hacerlo.

El repositorio se encuentra aquí.

LS0tCnRpdGxlOiAiRGF0b3MgZGUgbGEgZW5jdWVzdGEgVElDIGVuIGZvcm1hdG8gYWJpZXJ0byIKYXV0aG9yOiAiTGFiIFRlY25vU29jaWFsIgpkYXRlOiAiOCBkZSBtYXlvIGRlIDIwMjAiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICAgICAgY29sbGFwc2VkOiBmYWxzZQogICAgdGhlbWU6IGZsYXRseQogICAgaGlnaGxpZ2h0OiB6ZW5idXJuCi0tLQoKIyMgMS4gRGF0b3MgYWJpZXJ0b3MgcGFyYSBsYSB0b21hIGRlIGRlY2lzaW9uZXMKCkxvcyBkYXRvcyBhYmllcnRvcyBzb24gYXF1ZWxsb3MgImRhdG9zIHF1ZSBwdWVkZW4gc2VyIHV0aWxpemFkb3MsIHJldXRpbGl6YWRvcyB5IHJlZGlzdHJpYnVpZG9zIGxpYnJlbWVudGUgcG9yIGN1YWxxdWllciBwZXJzb25hIl5baHR0cHM6Ly9vcGVuZGF0YWhhbmRib29rLm9yZy9ndWlkZS9lcy93aGF0LWlzLW9wZW4tZGF0YS9dLiBQYXJhIGVsIHRlbWEgZGUgbGFzIHBvbMOtdGljYXMgcMO6YmxpY2FzLCBsb3MgZGF0b3MgYWJpZXJ0b3MgcGVybWl0ZW4gbGEgcGFydGljaXBhY2nDs24gZGUgYWN0b3JlcyBkaWZlcmVudGVzIGEgbG9zIGRlIGxhIGFkbWluaXN0cmFjacOzbiBndWJlcm5hbWVudGFsLiBFc3RvIHNlIGhhY2UgYcO6biBtw6FzIGltcG9ydGFudGUgZW4gc2l0dWFjaW9uZXMgY3LDrXRpY2FzIGRvbmRlIHNlIG5lY2VzaXRhIGRlc2Fycm9sbGFyIHNvbHVjaW9uZXMgY29sZWN0aXZhcyBzb2JyZSBwcm9ibGVtYXMgY29tcGxlam9zLCBjb21vIGVuIGxhIGFjdHVhbCBjcmlzaXMgcG9yIGVsIGNvcm9uYXZpcnVzLiAKClVuYSBkZSBsb3MgcHJvYmxlbWFzIGNlbnRyYWxlcyBxdWUgbm9zIHRvY2EgYWZyb250YXIgZW4gbGEgcHJlc2VudGUgY3Jpc2lzIGNvbnNpc3RlIGVuIGNvbXBhdGliaWxpemFyIGxhcyBtZWRpZGFzIGRlIGRpc3RhbmNpYW1pZW50byBwYXJhIGV2aXRhciBlbCBjb250YWfDrW8gY29uIGxhIG5lY2VzaWRhZCBkZSByZWFsaXphciBudWVzdHJhcyBhY3RpdmlkYWQgbGFib3JhbGVzLCBlZHVjYXRpdmFzIHkgc29jaWFsZXMuIEFxdcOtIGVsIEludGVybmV0IGp1ZWdhIHVuIGZhY3RvciBjbGF2ZS4gUGVybyBwYXJhIGVsbG8gZXMgbmVjZXNhcmlvIHNhYmVyIGRlIGFudGVtYW5vIGVuIHF1w6kgc2l0dWFjacOzbiBub3MgZW5jb250cmFtb3MgYWwgcmVzcGVjdG8gcGFyYSB0b21hciBkZWNpc2lvbmVzIGFjZXJ0YWRhcy4gCgpTb2JyZSBlbCB0ZW1hIGRlIEludGVybmV0IHkgVElDLCBlbiBudWVzdHJvIHBhw61zLCBlbCAyMDE3IGVsIGdvYmllcm5vIGxhbnrDsyB1bmEgaW1wb3J0YW50ZSBlbmN1ZXN0YSBzb2JyZSBUZWNub2xvZ8OtYXMgZGUgSW5mb3JtYWNpw7NuIHkgQ29tdW5pY2FjacOzbiBlbiBCb2xpdmlhLCBsYSBwcmltZXJhIGRlIHN1IHRpcG8uIFVuIHJlcG9ydGUgaW5pY2lhbCBkZSBsb3MgcmVzdWx0YWRvcyBzZSBwdWVkZSBlbmNvdHJhciBlbiBlbCBwb3J0YWwgZGUgbGEgIFtBR0VUSUNdKGh0dHBzOi8vd3d3LmFnZXRpYy5nb2IuYm8vcGRmL1Jlc3VsdGFkb3NGaW5hbGVzRW5jdWVzdGFUSUMucGRmKSB5IGxvcyBkYXRvcyBmdWVyb24gcMO6YmxpY2Fkb3MgZW4gW3JlcG9zaXRvcmlvIGRlIGRhdG9zIGFiaWVydG9zIGRlbCBFc3RhZG9dKGh0dHBzOi8vZGF0b3MuZ29iLmJvL2RhdGFzZXQvZW5jdWVzdGEtbmFjaW9uYWwtZGUtb3Bpbmlvbi1zb2JyZS10aWMpLgoKU2luIGVtYmFyZ28sIGEgbGEgaG9yYSBkZSBwcm9jZXNhcmxvcyBoZW1vcyBlbmNvbnRyYWRvIGFsZ3Vub3MgcHJvYmxlbWFzIGVuIGVsIGZvcm1hdG8gZGVsIGRhdGFzZXQuIAoKIyMgMi4gRWwgZm9ybWF0byBkZWwgZGF0YXNldAoKRW5jb250cmFtb3MgdHJlcyBwcm9ibGVtYXM6CgogLSBEaWZpY3VsdGFkIGRlIGNhcmdhciBsb3MgZGF0b3MgY29uIHNvZnR3YXJlIGxpYnJlCiAtIEZvcm1hdG8gZGUgQ1NWIGludmFsaWRvCiAtIEZhbHRhIGRlIHNlbcOhbnRpY2EgZW4gc3VzIHZhcmlhYmxlcyB5IHZhbG9yZXMgCiAKIyMjIDIuMS4gQ2FyZ2FuZG8gZWwgZGF0YXNldAoKRGVzY2FyZ2Ftb3MgZWwgZGF0YXNldCBlbiBmb3JtYXRvIENTViBkZWwgW3JlcG9zaXRvcmlvXShodHRwczovL2RhdG9zLmdvYi5iby9kYXRhc2V0L2VuY3Vlc3RhLW5hY2lvbmFsLWRlLW9waW5pb24tc29icmUtdGljKSBtZW5jaW9uYWRvIHkgcmVhbGl6YW1vcyBsb3Mgc2lndWllbnRlcyBpbnRlbnRvcyBkZSBjYXJnYS4KCiMjIyMgUHJpbWVyIGludGVudG8gY29uIGxhIGZ1bmNpw7NuIGByZWFkLmNzdigpYCBlbiBgUmAKCk51ZXN0cm8gcHJpbWVyIGludGVudG8gY29uIGxhIHlhICBhbnRpY3VhZGEgcGVybyB0b2RhdsOtYSBjb25maWFibGUgZnVuY2nDs24gZGUgYHJlYWQuY3N2KClgIGVuIFIgbm9zIGFycm9qYSBsbyBzaWd1aWVudGUgOgoKYGBge3J9CmJhc2VfciA8LSByZWFkLmNzdigiYmFzZS01NTM2LWJkZmluYWxjb3JyZWdpZG8uY3N2IikKYGBgCgpMb3MgZGF0b3Mgbm8gY2FyZ2FuIHkgbm9zIHByb2R1Y2UgdW4gZXJyb3IgcXVlIGFmaXJtYSBxdWUgZXhpc3RlbiBtw6FzIGNvbHVtbmFzIHF1ZSBub21icmVzIGRlIGNvbHVtbmFzLi4uCgojIyMjIFNlZ3VuZG8gaW50ZW50byBjb24gYHJlYWRfY3N2KClgIGRlIGxhIGxpYnJlcsOtYSBgcmVhZHJgIGVuIGBSYAoKQWhvcmEgdXNhbW9zIGVsIG11Y2hvIG3DoXMgam92ZW4gYHJlYWRfY3N2KClgIHF1ZSBlcyBtw6FzIHLDoXBpZGEgeSBjb2VyY2lvbmEgbWVub3MgbG9zIHRpcG9zIGRlIGRhdG9zOgoKYGBge3J9CmxpYnJhcnkocmVhZHIpCmJhc2VfciA8LSByZWFkX2NzdigiYmFzZS01NTM2LWJkZmluYWxjb3JyZWdpZG8uY3N2IikKYGBgCgpNw6FzIGFsbGEgZGUgbG9zIHRpcG9zIGRlIGRhdG9zIGRlIGxhcyBjb2x1bW5hcyBxdWUgbHVlZ28gcHVlZGVuIGVzcGVjaWZpY2Fyc2UsIGVzdGEgdmV6IGxvcyBkYXRvcyBjYXJnYW4uIFBhcmVjZSBmdW5jaW9uYXIsIGF1bnF1ZSBjb24gYWxndW5hcyBmYWxsYXMuIFZlbW9hcyBsYSBjYWJlemEgZGUgbnVlc3RybyBkYXRhc2V0OgoKYGBge3J9CmhlYWQoYmFzZV9yLCAyKQpgYGAKCsKhUGVzYWRpbGxhIS4gQ2FyZ8OzLCBwZXJvIGxhIHNpdHVhY2nDs24gZXMgbXVjaG8gcGVvci4KCkludGVudGVtb3MgY29uIFB5dGhvbi4KCiMjIyMgVGVyY2VyIGludGVudG8gY29uIGByZWFkX2NzdigpYCBkZSBsYSBsaWJyZXJpYSBgcGFuZGFzYCBkZSBgUHl0aG9uYAoKQSBwZXNhciBkZSBxdWUgaGF5IGNpZXJ0YSBob3N0aWxpZGFkIGVudHJlIGxhcyBjb211bmlkYWRlcyBkZSBSIHkgUHl0aG9uLCBhcXXDrSBlbiBlbCBMYWIgbm9zIGxsZXZhbW9zIGJpZW4gY29uIGFtYm9zLiAKCmBgYAppbXBvcnQgcGFuZGFzIGFzIHBkCmJhc2VfcCA9IHBkLnJlYWRfY3N2KCJiYXNlLTU1MzYtYmRmaW5hbGNvcnJlZ2lkby5jc3YiKQpwcmludChiYXNlX3AuaGVhZCg1KSkKYGBgCmBgYHtweXRob24gZWNobz1UUlVFfQppbXBvcnQgcGFuZGFzIGFzIHBkCmJhc2VfcCA9IHBkLnJlYWRfY3N2KCJiYXNlLTU1MzYtYmRmaW5hbGNvcnJlZ2lkby5jc3YiKQpwcmludChiYXNlX3AuaGVhZCg1KSkKYGBgCgpObyBsb2dyw7MgY2FyZ2FyIHkgb3RyYSB2ZXogZXJyb3IuLi4KCiMjIyMgU29sdWNpw7NuCgpJbnNwZWNjaW9uYW5kbyBlbCBkYXRhc2V0IG3DoXMgZGUgY2VyY2EsIHZlbW9zIHF1ZSBlbCBwcm9ibGVtYSBlcyBxdWUgbGxldmEgY29tbyBkZWxpbWl0YWRvciB1biBgO2AgZW4gdmV6IGRlIGAsYC4gRXN0ZSBwZXF1ZcOxbyBkZXRhbGxlIG5vcyBoYSBvY2FzaW9uYWRvIGxvcyBwcm9ibGVtYXMgaGFzdGEgYWhvcmEgdmlzdG9zLiBVc2FuZG8gbGEgZnVuY2nDs24gYHJlYWRfZGVsaW1gIGVuIGBSYCBvIGVsIHBhcmFtZXRybyBgc2VwYGVuIGBwYW5kYXNgIGxvZ3JhbW9zIGNhcmdhciBsb3MgZGF0b3MuCgpgYGB7cn0KbGlicmFyeShyZWFkcikKYmFzZV9yIDwtIHJlYWRfZGVsaW0oImJhc2UtNTUzNi1iZGZpbmFsY29ycmVnaWRvLmNzdiIsIGRlbGltID0gIjsiKQpoZWFkKGJhc2VfciwgNSkKYGBgCgpBaG9yYSBjb24gUHl0aG9uOiAKCmBgYApiYXNlX3AgPSBwZC5yZWFkX2NzdigiYmFzZS01NTM2LWJkZmluYWxjb3JyZWdpZG8uY3N2Iiwgc2VwPSI7IikKcHJpbnQoYmFzZV9wLmhlYWQoNSkpCmBgYApgYGB7cHl0aG9uIGVjaG89VFJVRX0KYmFzZV9wID0gcGQucmVhZF9jc3YoImJhc2UtNTUzNi1iZGZpbmFsY29ycmVnaWRvLmNzdiIsIHNlcD0iOyIpCnByaW50KGJhc2VfcC5oZWFkKDUpKQpgYGAKClNpIGJpZW4gZXMgY2llcnRvIHF1ZSBlc3RlIHByb2JsZW1hIHB1ZWRlIHNlciB0cml2aWFsIHBhcmEgYWxndW5vcywgbGEgaWRlYSBkZSBsb3MgZGF0b3MgYWJpZXJ0b3MgZXMgcXVlIHRlbmdhbiBsYSBtYXlvciBhY2Nlc2liaWxpZGFkIHBvc2libGUgeSBwdWVkYW4gc2VyIGlubWVkaWF0YW1lbnRlIHV0aWxpemFkb3Mgc2luIG1heW9yIHByb2JsZW1hIGRlIGFjY2Vzby4gWSBwYXJhIGVzbyBkZWJlbiBzZXIgdmFsaWRvcywgc2VndW4gZXN0YW5kYXJlcyB5IGVzcGVjaWZpY2FjaW9uZXMuCgojIyMgMi4yLiBDU1Ygbm8gdmFsaWRvCgpNw6FzIGFsbMOhIGRlIHN1IHNvbHVjacOzbiB2aWEgcGFyYW1ldHJvcyBhZGljaW9uYWxlcyBlbiBlbCBjw7NkaWdvLCBlbCBwcm9ibGVtYSBjZW50cmFsIHRpZW5lIHF1ZSB2ZXIgY29uIHF1ZSBzZSBoYSBwdWJsaWNhZG8gdW4gQ1NWIG5vIHZhbGlkby4gU3ViaWVuZG8gZXN0ZSBkYXRhc2V0IGEgbGEgaGVycmFtaWVudGEgZGUgdmFsaWRhY2nDs24gW0NTVmxpbnRdKGh0dHBzOi8vY3N2bGludC5pby8pIGRlbCBPcGVuIERhdGEgSW5zdGl0dXRlLCBjb25maXJtYW1vcyBlc3RhIHNpdHVhY2nDs246CgohW10oaW1nL2ludmFsaWQtY3N2LnBuZykKCiMjIyAyLjMuIFZhbG9yZXMgc2luIHNlbcOhbnRpY2EgCgpZYSBsbyB0ZW5lbW9zIGNhcmdhZG8uIEFob3JhIHZhbW9zIGEgYW5hbGl6YXJsbywgwr9xdcOpIHBvZHLDrWEgc2FsaXIgbWFsIGFob3JhPyBFeHBsb3JlbW9zLiAKClZlYW1vcyBsYSBlc3RydWN0dXJhIGRlbCBkYXRhc2V0OgoKYGBge3J9CnN0cihiYXNlX3IpCmBgYAoKQXF1w60gdGVuZW1vcyB1biBwcm9ibGVtYSBkZSBzZW3DoW50aWNhLiBMYXMgdmFyaWFibGVzIG5vIHBvc2VlbiBub21icmVzIGVudGVuZGlibGVzIHkgdGFtcG9jbyBsb3MgdmFsb3Jlcy4gTm8gcG9kZW1vcyBoYWNlciBwcmVndW50YXMgZGlyZWN0YXMgYSBsYSBiYXNlIGRlIGRhdG9zLCBuaSBzaXF1aWVyYSBzb2JyZSBjb3NhcyB0YW4gYsOhc2ljYXMgY29tbyBsYSBlZGFkIG8gZWwgc2V4by4gSW50ZW50ZW1vcyBjb24gdW4gZGlhZ3JhbWEgZGUgYmFycmFzIGRlIGxhIFAzOgoKYGBge3J9CmxpYnJhcnkoZ2dwbG90MikKICBnZ3Bsb3QoYmFzZV9yLCBhZXMoUDMpKSArCiAgZ2VvbV9iYXIoKQpgYGAKCkxhIHZpc3VhbGl6YWNpw7NuIG5vIG11ZXN0cmEgbmkgZWwgbm9tYnJlIGRlIGxhIHByZWd1bnRhIChzb2xvIFAzKSwgY29tbyB0YW1wb2NvIGxvcyB2YWxvcmVzIGludGVycHJldGFibGVzLCAoc29sbyAxLCAyLCAzLCA0KS4gU2kgYmllbiBlbiBlbCByZXBvc2l0b3JpbyBndWJlcm5hbWVudGFsIGV4aXN0ZSB1biBkaWNjaW9uYXJpbyBkZSBkYXRvcyBlbiBQREYsIGVzdGUgbm8gZXMgZGlyZWN0YW1lbnRlIHV0aWxpemFibGUgZW4gZWwgcHJvY2VzYW1pZW50byBkZSBsb3MgZGF0b3MgeSB0YW1wb2NvIHBvc2VlIHVuIGZvcm1hdG8gYWJpZXJ0by4gRXMgbmVjZXNhcmlvIGNvbnRhciBjb24gbGFzIGV0aXF1ZXRhcyBkZSBsYXMgdmFyaWFibGVzIHkgbG9zIHZhbG9yZXMgcGFyYSBwb2RlciBoYWNlciB1bmEgbWVqb3IgaW50ZXJwcmV0YWNpw7NuIHkgdmlzdWFsaXphY2nDs24gZGUgbG9zIGRhdG9zLiAKCiMjIDMuIFVuYSB2ZXJzacOzbiBwcm9waWEsIHZhbGlkYSB5IHNlbcOhbnRpY2EKCkhlbW9zIGRhZG8gdW5hIHNvbHVjacOzbiBhIGxvcyBwcm9ibGVtYXMgZGUgKDEpIHZhbGlkYWNpw7NuIGRlIGZvcm1hdG8sIHF1ZSBsbGV2YW4gYSBwcm9ibGVtYXMgZW4gZWwgY2FyZ2FkbyBkZSBsb3MgZGF0b3MsIHkgKDIpIGEgbGEgc2Vtw6FudGljYSBkZSB2YXJpYWJsZXMgeSB2YWxvcmVzIHBhcmEgdW5hIG1lam9yIGludGVycHJldGFiaWxpZGFkLgoKTGFzIHZlcnNpb25lcyBxdWUgc3ViaW1vcyBhIG51ZXN0cm8gcmVwb3NpdG9yaW8gc29uIENTViB2YWxpZG9zOiAKCiFbXShpbWcvdmFsaWQxLnBuZykKCkVuIG51ZXN0cm8gcmVwb3NpdG9yaW8gcHVlZGVuIGVuY29udHJhciBsYSBtaXNtYSB2ZXJzacOzbiBubyBzZW3DoW50aWNhIGRlbCBDU1YgcHVibGljYWRvIHBvciBlbCBnb2JpZXJubywgcGVybyBjb24gZm9ybWF0byBDU1YgVmFsaWRvIChgZGF0b3NfdmFsb3Jlcy5jc3ZgKSwgYWNvbXBhw7FhZGEgZGUgZG9zIHRhYmxhcyBDU1YgcGFyYSBsYXMgZXRpcXVldGFzIGRlIGxhcyB2YXJpYWJsZXMgKGBldGlxdWV0YXNfdmFyaWFibGVzLmNzdmApIHkgZGUgbG9zIHZhbG9yZXMgKGBldGlxdWV0YXNfdmFsb3Jlcy5jc3ZgKS4KClNvYnJlIGxhIHNlbcOhbnRpY2EgZGFtb3MgZG9zIHNvbHVjaW9uZXMuIExhIHByaW1lcmEgZXMgdW5hIHZlcnNpw7NuIHRvdGFsbWVudGUgZXRpcXVldGFkYSB0YW50byBlbiB2YXJpYWJsZXMgeSB2YWxvcmVzIChgZGF0b3NfZXRpcXVldGFzX3RvZG8uY3N2YCkuIEVzdGEgZXMgbGEgdmVyc2nDs24gcXVlIHNlIHB1ZWRlIHVzYXIgcGFyYSBoYWNlciBhbsOhbGlzaXMgZXhwbG9yYXRvcmlvIGNvbiBwYXF1ZXRlcyBjb21vIENhbGMsIEV4Y2VsIG8gR29vZ2xlIFNoZWV0cy4gVGllbmUgZXN0YSBhcGFyaWVuY2lhOgoKYGBge3J9CmJhc2VfZXRpcXVldGFkYSA8LSByZWFkX2NzdigiY3N2L2V0aS9kYXRvc19ldGlxdWV0YXNfdG9kby5jc3YiKQpoZWFkKGJhc2VfZXRpcXVldGFkYSwgNSkKCmBgYAoKCkxhIHNlZ3VuZGEgZXMgbWVkaWFudGUgdW4gZGF0YXNldCAoYGJhc2UuY3N2YCkgYXNvY2lhZG8gYSB1biBkaWNjaW9uYXJpbyAoYGRpYy5jc3ZgKSwgZG9uZGUgbGFzIGV0aXF1ZXRhcyBkZWwgZGljY2lvbmFyaW8gcHVlZGVuIGFzb2NpYXJzZSBjb24gbG9zIGF0cmlidXRvcyBkZSBsb3MgZGF0b3MgbWVkaWFudGUgUiBvIFB5dGhvbi4KCkVuIGxvcyBzaWd1aWVudGVzIGTDrWFzIHNhY2FyZW1vcyByZXBvcnRlcyBkZSB2YXJpYXMgZGltZW5zaW9uZXMgZGUgSW50ZXJuZXQgeSBzb2NpZWRhZCBhIHBhcnRpciAgZGUgZXN0b3MgZGF0b3MuIFBlcm8gY29uIGxvcyBkYXRvcyBhYmllcnRvcywgdMO6IHRhbWJpw6luIHB1ZWRlcyBoYWNlcmxvLgoKRWwgcmVwb3NpdG9yaW8gc2UgZW5jdWVudHJhIFthcXXDrV0oaHR0cHM6Ly9naXRodWIuY29tL2xhYi10ZWNub3NvY2lhbC9FbmN1ZXN0YVRJQ19CTykuCgo=