Teoría

La minería de texto (TM) es el proceso de extraer información útil, patrones o conocimientos de textos no estructurados.

Consta de 3 etapas:
1. Obtener datos: El reconocimiento óptico de caracteres (OCR) es una tecnología que permite convertir imágenes de texto en texto editable. También es conocido como extracción de texto de imágenes.
2. Explorar datos: Representacion gráfica o visual de los datos para su interpretación. Los métodos más comunes son el Análisis de Sentimientos, la Nube de Palabras y el Topic Modeling.
3. Análisis predictivo: son las técnicas y modelos estadísticos para predecir resultados futuros. Los modelos más usados son el Random Forest, Redes Neuronales y Regresiones.

Instalar paquetes y llamar librerías

#install.packages("tidyverse") #Data wrangling
library(tidyverse)
#install.packages("tesseract") # OCR
library(tesseract)
#install.packages("magick") # PNG
library(magick)
#install.packages("officer") # office(word)
library(officer)
#install.packages("pdftools") # PDF
library(pdftools)
#install.packages("purrr") # Para la función map para aplicar una función a cada elemento de un vector
library(purrr)
#install.packages("tm") # Text Mining
library(tm)
#install.packages("RColorBrewer") # Colores
library(RColorBrewer)
#install.packages("wordcloud") # Nube de palabras
library(wordcloud)
#install.packages("topicmodels") # Modelos de Temas
library(topicmodels)
#install.packages("ggplot2") # Gráficas con más diseño
library(ggplot2)

Obtener Datos mediante OCR

De imagen PNG a texto en WORD

imagen1 <- image_read("/Users/karla/Desktop/Módulo 2/imagen1.PNG")
texto1 <- ocr(imagen1)
texto1
## [1] "Linear regression with one variable x is also known as univariate linear regression\nor simple linear regression. Simple linear regression is used to predict a single\noutput from a single input. This is an example of supervised learning, which means\nthat the data is labeled, i.e., the output values are known in the training data. Let us\nfit a line through the data using simple linear regression as shown in Fig. 4.1.\n"
doc1 <- read_docx() #Crea un documento de word en blanco
doc1 <- doc1 %>% body_add_par(texto1, style = "Normal") #Pega el texto en el word
# print(doc1, target = "texto1.docx") #Guarda el word en la computadora

Imagen en español PNG a texto en WORD

Consultar idiomas disponibles

imagen2 <- image_read("/Users/karla/Desktop/Módulo 2/imagen2.PNG")
tesseract_download("spa")
## [1] "/Users/karla/Library/Application Support/tesseract5/tessdata/spa.traineddata"
texto2 <- ocr(imagen2, engine = tesseract("spa"))
texto2
## [1] "Un importante, y quizá controversial, asunto político es el que se refiere al efecto del salario mínimo sobre\nlas tasas de desempleo en diversos grupos de trabajadores. Aunque este problema puede ser estudiado con\ndiversos tipos de datos (corte transversal, series de tiempo o datos de panel), suelen usarse las series de\ntiempo para observar los efectos agregados. En la tabla 1.3 se presenta un ejemplo de una base de datos\nde series de tiempo sobre tasas de desempleo y salarios mínimos.\n"
doc2 <- read_docx() #Crea un documento de word en blanco
doc2 <- doc2 %>% body_add_par(texto2, style = "Normal") #Pega el texto en el word
# print(doc2, target = "texto2.docx") #Guarda el word en la computadora

De PDF a texto en WORD

pdf1 <- pdf_convert("/Users/karla/Desktop/Módulo 2/pdf1.pdf", dpi=600) %>% map(ocr)
## Converting page 1 to pdf1_1.png... done!
## Converting page 2 to pdf1_2.png... done!
## Converting page 3 to pdf1_3.png... done!
## Converting page 4 to pdf1_4.png... done!
## Converting page 5 to pdf1_5.png... done!
## Converting page 6 to pdf1_6.png... done!
## Converting page 7 to pdf1_7.png... done!
## Converting page 8 to pdf1_8.png... done!
# Repetir pasos previos para convertir imágenes a texto en WORD

Actividad 1. Novela “IT”

eso3 <- pdf_convert("/Users/karla/Desktop/Módulo 2/eso3.pdf", dpi=600) %>% map(ocr)
## Converting page 1 to eso3_1.png... done!
## Converting page 2 to eso3_2.png... done!
## Converting page 3 to eso3_3.png... done!
e1 <- image_read("/Users/karla/Desktop/Módulo 2/eso3_1.png")
tesseract_download("spa")
## [1] "/Users/karla/Library/Application Support/tesseract5/tessdata/spa.traineddata"
textoe1 <- ocr(e1, engine = tesseract("spa"))
e2 <- image_read("/Users/karla/Desktop/Módulo 2/eso3_2.png")
tesseract_download("spa")
## [1] "/Users/karla/Library/Application Support/tesseract5/tessdata/spa.traineddata"
textoe2 <- ocr(e2, engine = tesseract("spa"))
e3 <- image_read("/Users/karla/Desktop/Módulo 2/eso3_3.png")
tesseract_download("spa")
## [1] "/Users/karla/Library/Application Support/tesseract5/tessdata/spa.traineddata"
textoe3 <- ocr(e3, engine = tesseract("spa"))

Actividad 2. Exploración de Datos

Análisis de Frecuencias

text_IT <- readLines("/Users/karla/Desktop/Módulo 2/ESO_3.txt") #traer texto de internet
#stopwords("spanish")

#texto_sin_acentos<- iconv(text_IT, to= "ASCII//TRANSLIT") #Texto sin acentos
#text2<- iconv(text_IT, to= "ASCII//TRANSLIT") #Texto sin acentos

text <- iconv(text_IT, to = "UTF-8", sub = "byte") # Convertir texto codificado a caracteres legibles

corpus <- Corpus(VectorSource(text)) # Pone cada renglón en una celda de vector
# inspect(corpus)
corpus <- tm_map(corpus, content_transformer(tolower)) # Pone todo en minúsculas
## Warning in tm_map.SimpleCorpus(corpus, content_transformer(tolower)):
## transformation drops documents
 #inspect(corpus)
corpus <- tm_map(corpus, removePunctuation) # Elimina puntuación
## Warning in tm_map.SimpleCorpus(corpus, removePunctuation): transformation drops
## documents
#inspect(corpus)
corpus <- tm_map(corpus, removeNumbers) # Elimina números
## Warning in tm_map.SimpleCorpus(corpus, removeNumbers): transformation drops
## documents
corpus <- tm_map(corpus, removeWords, stopwords("spanish")) # Elimina palabras que no hablan del tema
## Warning in tm_map.SimpleCorpus(corpus, removeWords, stopwords("spanish")):
## transformation drops documents
# corpus <- tm_map(corpus, removeWords, c("dream","")) # Elimina palabras puntuales
inspect(corpus)
## <<SimpleCorpus>>
## Metadata:  corpus specific: 1, document level (indexed): 0
## Content:  documents: 3
## 
## [1]  alli  persiguiendo  barco  papel   lado izquierdo  witcham street corra deprisa   agua  ganaba   barquito  sacando ventaja oy  rugido profundo  vio cmo cincuenta metros ms adelante colina abajo  agua   cuneta  precipitaba dentro   boca  tormenta  acn continuaba abierta   largo semicirculo oscuro abierto   bordillo   acera  mientras george miraba  rama desgarrada   corteza oscura  reluciente  hundi  aquellas fauces all pendi   momento  luego  desliz hacia  interior hacia all  encaminaba  bote  d cmierda dchill horrorizado  forz  paso    momento pareci  iba  alcanzar  barquito     ples resbal  george cayo despatarrado despellejndose  rodilla   grito  dolor   nueva perspectiva   altura  pavimento vio   barco giraba  redondo dos veces momentneamente atrapado   remolino   desaparecer  dcmierda  ms mierda dvolvi  chillar estrellando  puo   pavimento   tambien doli   ech  sollozar cque manera tan estupida  perder  barco   levant  caminar hacia  boca  tormenta  all  dej caer  rodillas  mirar hacia  interior  agua haca  ruido hueco  hcmedo  caer   oscuridad  sonido  daba escalofrios haca pensar   dceh   exclamacin   arrancada    cordel retrocedio  all adentro haba  ojos amarillos  tipo  ojos   siempre imaginaba  verlos nunca   oscuridad  stano   animal dpenso incoherented     animal   mejor  gato  qued atrapado    modos   echar  correr habria corrido   dos segundos   tablero mental   hecho cargo  espanto   produjeron  dos ojos amarillos  brillantes sinti  spera superficie  pavimento bajo  dedos   fina lmina  agua fra  corra alrededor  vio  s mismo levantndose  retrocediendo   entonces   voz  voz perfectamente razonable  bastante simptica  habl  dentro   boca  tormenta  dhola george ddijo  george parpadeo  volvi  mirar apenas poda dar credito    vela    sacado   cuento    pelcula   sabe   animales hablan  bailan si   diez aos ms  habria creido     viendo   tenia dieciseis aos sino seis    boca  tormenta habia  payaso  luz distaba  ser buena  bast   george denbrough  seguro    vela   payaso    circo    tele parecia  mezcla  bozo  clarabell   hablaba haciendo sonar  bocina  howdy doody  sbados   maana bcfalo bob   cnico  entenda  clarabell   siempre hacia reir  george  cara  payaso metido   boca  tormenta  blanca tenia cmicos mechones  pelo rojo  cada lado   calva   gran sonrisa  payaso pintada 
## [2] alrededor   boca si george  vivido aos despues habria pensado  ronald mcdonald    bozo   clarabell   payaso tena   mano  manojo  globos    colores  tentadora fruta madura      barquito  papel  george  dcquieres  barquito georgie  payaso sonrela  george tambien sonri  poda evitarlo aquella sonrisa   tipo   devuelve  querer  dpor supuesto   payaso  ech  reir  dcpor supuestoc cas  gusta cas  gusta cy  globo cque  parece cquieres  globod dbueno s  supuesto dalarg  mano   inmediato  retir   voluntadd  debo coger    ofrezca  desconocido  dice  pap  dy  papa  mucha razn dreplic  payaso   boca  tormenta sonriendo george  pregunt cmo podia haber creido   ojos  amarillos si    color azul brillante bailarin   ojos   mam   bill d muchsima razn   creo    voy  presentarme george   seor bob gray tambien conocido  pennywise  payaso ballarin pennywise  presento  george denbrough george  presento  pennywise  ahora   conocemos     desconocido   tampoco ccorrecto  george solt  risita  dcorrecto dvolvi  estirar  mano   retirarlad ccmo  metiste alli adentro  dla tormenta  trajo volaaaando ddijo pennywise  payaso bailarind  llev   circo cno sientes olor  circo george  george  inclin hacia adelante cde pronto ola  cacahuetes ccacahuetes tostados cy vinagre blanco    pone   patatas fritas   agujero   tapa  ola  algodn  azucar  buuelos  tambien leve  poderosamente  estiercol  animales salvajes olia  aroma regocijante  aserrin   embargo   embargo bajo   ola  inundacin  hojas deshechas   oscuras sombras  bocas  tormenta   olor hcmedo  putrido  olor  stano     olores  ms fuertes  dclaro   huelo ddlijo  dcquieres  barquito george dpregunt pennywised   pregunto  vez   pareces desearlo                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
## [3]   mostr  alto sonriendo llevaba  traje  seda abolsado  grandes botones color naranja  corbata brillante  color azul electrico   derramaba   pechera   manos llevaba grandes guantes blancos  mickey  donald  dsi claro ddijo george mirando dentro   boca  tormenta  dcy  globo   rojos verdes amarillos azules  dcflotan  dcque si flotan dla sonrisa  payaso  acentud oh s claro  s cflotan tambien  algodn  azucar  george estir  mano   payaso  sujeto  brazo   entonces george vio cmo  cara  payaso cambiaba    vio entonces  tan terrible   peor  haba imaginado   cosa  stano pareca  dulce sueo   vio destruy  cordura   zarpazo  dflotan dcro  cosa   alcantarilla   voz  rea   cogulos  sujetaba  brazo  george   puo grueso  agusanado tir   hacia  horrible oscuridad    agua corra  ruga  aullaba llevando hacia  mar  desechos   tormenta george estir  cuello  apartarse   negrura definitiva  empez  gritar hacia  lluvia  gritar   loco hacia  gris cielo otoal   curvaba  derry aquel da  otoo    gritos  agudos  penetrantes    largo  toda  calle  gente  asom   ventanas   lanz   porches  dflotan dgru  cosad flotan georgie   estes aqui abajo conmigo tc tambien flotars   hombro  george  clav   cemento  bordillo dave gardener   da  habia ido  trabajar  shoeboat debido   inundacin vio slo   nio  impermeable amarillo  nio  gritaba   retorcia   arroyo mientras  agua lodosa  corra   cara haciendo   alaridos sonaran burbujeantes  daqui abajo  flota dsusurr  voz podrida riendo   pronto   desgarro    destello  agona  george denbrough   supo ms  dave gardener   primero  llegar aunque lleg slo cuarenta  cinco segundos despues  primer grito george denbrough  habia muerto gardener  agarr   impermeable tir    sacarlo   calle   girar   manos  cuerpo  george tambien  empez  gritar  lado izquierdo  impermeable  nio    rojo intenso  sangre flua hacia  alcantarilla   agujero  haba   brazo izquierdo  trozo  hueso horriblemente brillante asomaba   tela rota   ojos  nio miraban fijamente  cielo gris  mientras dave retroceda  tropezones hacia     corrian   calle empezaron  llenarse  lluvia
tdm<- TermDocumentMatrix(corpus)
m<- as.matrix(tdm) #Cuenta las veces que aparece cada palabra por renglón.
frecuencia<- sort(rowSums(m), decreasing = TRUE) #Cuenta la frecuencia de cada palabra en el texto
frecuencia_df<- data.frame(word=names(frecuencia), freq=frecuencia) #Convierte la frecuencia a data
ggplot(head(frecuencia_df,10), aes(x=reorder(word, -freq), y=freq)) +
      geom_bar(stat = "identity", fill = "red") +
      geom_text(aes(label = freq), vjust = -0.5) +
      labs(title = "TOP 10 palabras más frecuentes", subtitle = "IT (Eso) - Stephen King", x = "Palabra", y="Frecuencia") +
      ylim(0,20)
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`geom_bar()`).
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`geom_text()`).

Nube de Palabras

# El procesamiento de datos antes de la nube de palabras es igual que en el Análisis de Frecuencias, desde importar el texto hasta frecuencia_df
set.seed(123)
wordcloud(words = frecuencia_df$word,freq=frecuencia_df$freq, min.freq=1,
          random.order = FALSE, colors = brewer.pal(8, "Reds"))

LS0tCnRpdGxlOiAiVGV4dCBNaW5pbmciCmF1dGhvcjogIkthcmxhIFPDoW5jaGV6IC0gQTAxMTk4MTg0IgpkYXRlOiAiMjAyNC0wMi0yNiIKb3V0cHV0OiAKIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdGhlbWU6IGNvc21vCi0tLQoKIVtdKC9Vc2Vycy9rYXJsYS9EZXNrdG9wL01vzIFkdWxvIDIvSVQuZ2lmKQoKCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogcmVkOyI+VGVvcsOtYTwvc3Bhbj4KTGEgKiptaW5lcsOtYSBkZSB0ZXh0byAoVE0pKiogZXMgZWwgcHJvY2VzbyBkZSBleHRyYWVyCmluZm9ybWFjacOzbiDDunRpbCwgcGF0cm9uZXMgbyBjb25vY2ltaWVudG9zIGRlIHRleHRvcyBubyBlc3RydWN0dXJhZG9zLiAgCgpDb25zdGEgZGUgMyBldGFwYXM6ICAKMS4gT2J0ZW5lciBkYXRvczogRWwgKipyZWNvbm9jaW1pZW50byDDs3B0aWNvIGRlIGNhcmFjdGVyZXMgKE9DUikqKiBlcyB1bmEgdGVjbm9sb2fDrWEgcXVlIHBlcm1pdGUKY29udmVydGlyIGltw6FnZW5lcyBkZSB0ZXh0byBlbiB0ZXh0byBlZGl0YWJsZS4gVGFtYmnDqW4gZXMgY29ub2NpZG8gY29tbyAqKmV4dHJhY2Npw7NuIGRlIHRleHRvIGRlIGltw6FnZW5lcyoqLiAgCjIuIEV4cGxvcmFyIGRhdG9zOiBSZXByZXNlbnRhY2lvbiBncsOhZmljYSBvIHZpc3VhbCBkZSBsb3MgZGF0b3MgcGFyYSBzdSBpbnRlcnByZXRhY2nDs24uIExvcyBtw6l0b2RvcyBtw6FzIGNvbXVuZXMgc29uIGVsIEFuw6FsaXNpcyBkZSBTZW50aW1pZW50b3MsIGxhIE51YmUgZGUgUGFsYWJyYXMgeSBlbCBUb3BpYyBNb2RlbGluZy4gIAozLiBBbsOhbGlzaXMgcHJlZGljdGl2bzogc29uIGxhcyB0w6ljbmljYXMgeSBtb2RlbG9zIGVzdGFkw61zdGljb3MgcGFyYSBwcmVkZWNpciByZXN1bHRhZG9zIGZ1dHVyb3MuIExvcyBtb2RlbG9zIG3DoXMgdXNhZG9zIHNvbiBlbCBSYW5kb20gRm9yZXN0LCBSZWRlcyBOZXVyb25hbGVzIHkgUmVncmVzaW9uZXMuICAKCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogcmVkOyI+SW5zdGFsYXIgcGFxdWV0ZXMgeSBsbGFtYXIgbGlicmVyw61hczwvc3Bhbj4KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI2luc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpICNEYXRhIHdyYW5nbGluZwpsaWJyYXJ5KHRpZHl2ZXJzZSkKI2luc3RhbGwucGFja2FnZXMoInRlc3NlcmFjdCIpICMgT0NSCmxpYnJhcnkodGVzc2VyYWN0KQojaW5zdGFsbC5wYWNrYWdlcygibWFnaWNrIikgIyBQTkcKbGlicmFyeShtYWdpY2spCiNpbnN0YWxsLnBhY2thZ2VzKCJvZmZpY2VyIikgIyBvZmZpY2Uod29yZCkKbGlicmFyeShvZmZpY2VyKQojaW5zdGFsbC5wYWNrYWdlcygicGRmdG9vbHMiKSAjIFBERgpsaWJyYXJ5KHBkZnRvb2xzKQojaW5zdGFsbC5wYWNrYWdlcygicHVycnIiKSAjIFBhcmEgbGEgZnVuY2nDs24gbWFwIHBhcmEgYXBsaWNhciB1bmEgZnVuY2nDs24gYSBjYWRhIGVsZW1lbnRvIGRlIHVuIHZlY3RvcgpsaWJyYXJ5KHB1cnJyKQojaW5zdGFsbC5wYWNrYWdlcygidG0iKSAjIFRleHQgTWluaW5nCmxpYnJhcnkodG0pCiNpbnN0YWxsLnBhY2thZ2VzKCJSQ29sb3JCcmV3ZXIiKSAjIENvbG9yZXMKbGlicmFyeShSQ29sb3JCcmV3ZXIpCiNpbnN0YWxsLnBhY2thZ2VzKCJ3b3JkY2xvdWQiKSAjIE51YmUgZGUgcGFsYWJyYXMKbGlicmFyeSh3b3JkY2xvdWQpCiNpbnN0YWxsLnBhY2thZ2VzKCJ0b3BpY21vZGVscyIpICMgTW9kZWxvcyBkZSBUZW1hcwpsaWJyYXJ5KHRvcGljbW9kZWxzKQojaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpICMgR3LDoWZpY2FzIGNvbiBtw6FzIGRpc2XDsW8KbGlicmFyeShnZ3Bsb3QyKQpgYGAKCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiByZWQ7Ij5PYnRlbmVyIERhdG9zIG1lZGlhbnRlIE9DUjwvc3Bhbj4KCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogcmVkOyI+RGUgaW1hZ2VuIFBORyBhIHRleHRvIGVuIFdPUkQ8L3NwYW4+CmBgYHtyfQppbWFnZW4xIDwtIGltYWdlX3JlYWQoIi9Vc2Vycy9rYXJsYS9EZXNrdG9wL01vzIFkdWxvIDIvaW1hZ2VuMS5QTkciKQp0ZXh0bzEgPC0gb2NyKGltYWdlbjEpCnRleHRvMQpkb2MxIDwtIHJlYWRfZG9jeCgpICNDcmVhIHVuIGRvY3VtZW50byBkZSB3b3JkIGVuIGJsYW5jbwpkb2MxIDwtIGRvYzEgJT4lIGJvZHlfYWRkX3Bhcih0ZXh0bzEsIHN0eWxlID0gIk5vcm1hbCIpICNQZWdhIGVsIHRleHRvIGVuIGVsIHdvcmQKIyBwcmludChkb2MxLCB0YXJnZXQgPSAidGV4dG8xLmRvY3giKSAjR3VhcmRhIGVsIHdvcmQgZW4gbGEgY29tcHV0YWRvcmEKYGBgCgojIyA8c3BhbiBzdHlsZT0iY29sb3I6IHJlZDsiPkltYWdlbiBlbiBlc3Bhw7FvbCBQTkcgYSB0ZXh0byBlbiBXT1JEPC9zcGFuPgoKW0NvbnN1bHRhciBpZGlvbWFzIGRpc3BvbmlibGVzXShodHRwczovL3Rlc3NlcmFjdC1vY3IuZ2l0aHViLmlvL3Rlc3Nkb2MvRGF0YS1GaWxlcy1pbi1kaWZmZXJlbnQtdmVyc2lvbnMuaHRtbCkKYGBge3J9CmltYWdlbjIgPC0gaW1hZ2VfcmVhZCgiL1VzZXJzL2thcmxhL0Rlc2t0b3AvTW/MgWR1bG8gMi9pbWFnZW4yLlBORyIpCnRlc3NlcmFjdF9kb3dubG9hZCgic3BhIikKdGV4dG8yIDwtIG9jcihpbWFnZW4yLCBlbmdpbmUgPSB0ZXNzZXJhY3QoInNwYSIpKQp0ZXh0bzIKZG9jMiA8LSByZWFkX2RvY3goKSAjQ3JlYSB1biBkb2N1bWVudG8gZGUgd29yZCBlbiBibGFuY28KZG9jMiA8LSBkb2MyICU+JSBib2R5X2FkZF9wYXIodGV4dG8yLCBzdHlsZSA9ICJOb3JtYWwiKSAjUGVnYSBlbCB0ZXh0byBlbiBlbCB3b3JkCiMgcHJpbnQoZG9jMiwgdGFyZ2V0ID0gInRleHRvMi5kb2N4IikgI0d1YXJkYSBlbCB3b3JkIGVuIGxhIGNvbXB1dGFkb3JhCmBgYAoKIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiByZWQ7Ij5EZSBQREYgYSB0ZXh0byBlbiBXT1JEPC9zcGFuPgpgYGB7cn0KcGRmMSA8LSBwZGZfY29udmVydCgiL1VzZXJzL2thcmxhL0Rlc2t0b3AvTW/MgWR1bG8gMi9wZGYxLnBkZiIsIGRwaT02MDApICU+JSBtYXAob2NyKQojIFJlcGV0aXIgcGFzb3MgcHJldmlvcyBwYXJhIGNvbnZlcnRpciBpbcOhZ2VuZXMgYSB0ZXh0byBlbiBXT1JECmBgYAoKIyA8c3BhbiBzdHlsZT0iY29sb3I6IHJlZDsiPkFjdGl2aWRhZCAxLiBOb3ZlbGEgIklUIjwvc3Bhbj4KYGBge3J9CmVzbzMgPC0gcGRmX2NvbnZlcnQoIi9Vc2Vycy9rYXJsYS9EZXNrdG9wL01vzIFkdWxvIDIvZXNvMy5wZGYiLCBkcGk9NjAwKSAlPiUgbWFwKG9jcikKYGBgCgpgYGB7cn0KZTEgPC0gaW1hZ2VfcmVhZCgiL1VzZXJzL2thcmxhL0Rlc2t0b3AvTW/MgWR1bG8gMi9lc28zXzEucG5nIikKdGVzc2VyYWN0X2Rvd25sb2FkKCJzcGEiKQp0ZXh0b2UxIDwtIG9jcihlMSwgZW5naW5lID0gdGVzc2VyYWN0KCJzcGEiKSkKYGBgCgpgYGB7cn0KZTIgPC0gaW1hZ2VfcmVhZCgiL1VzZXJzL2thcmxhL0Rlc2t0b3AvTW/MgWR1bG8gMi9lc28zXzIucG5nIikKdGVzc2VyYWN0X2Rvd25sb2FkKCJzcGEiKQp0ZXh0b2UyIDwtIG9jcihlMiwgZW5naW5lID0gdGVzc2VyYWN0KCJzcGEiKSkKYGBgCgpgYGB7cn0KZTMgPC0gaW1hZ2VfcmVhZCgiL1VzZXJzL2thcmxhL0Rlc2t0b3AvTW/MgWR1bG8gMi9lc28zXzMucG5nIikKdGVzc2VyYWN0X2Rvd25sb2FkKCJzcGEiKQp0ZXh0b2UzIDwtIG9jcihlMywgZW5naW5lID0gdGVzc2VyYWN0KCJzcGEiKSkKYGBgCgojIDxzcGFuIHN0eWxlPSJjb2xvcjogcmVkOyI+QWN0aXZpZGFkIDIuIEV4cGxvcmFjacOzbiBkZSBEYXRvczwvc3Bhbj4KCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogcmVkOyI+QW7DoWxpc2lzIGRlIEZyZWN1ZW5jaWFzPC9zcGFuPgpgYGB7cn0KdGV4dF9JVCA8LSByZWFkTGluZXMoIi9Vc2Vycy9rYXJsYS9EZXNrdG9wL01vzIFkdWxvIDIvRVNPXzMudHh0IikgI3RyYWVyIHRleHRvIGRlIGludGVybmV0CiNzdG9wd29yZHMoInNwYW5pc2giKQoKI3RleHRvX3Npbl9hY2VudG9zPC0gaWNvbnYodGV4dF9JVCwgdG89ICJBU0NJSS8vVFJBTlNMSVQiKSAjVGV4dG8gc2luIGFjZW50b3MKI3RleHQyPC0gaWNvbnYodGV4dF9JVCwgdG89ICJBU0NJSS8vVFJBTlNMSVQiKSAjVGV4dG8gc2luIGFjZW50b3MKCnRleHQgPC0gaWNvbnYodGV4dF9JVCwgdG8gPSAiVVRGLTgiLCBzdWIgPSAiYnl0ZSIpICMgQ29udmVydGlyIHRleHRvIGNvZGlmaWNhZG8gYSBjYXJhY3RlcmVzIGxlZ2libGVzCgpjb3JwdXMgPC0gQ29ycHVzKFZlY3RvclNvdXJjZSh0ZXh0KSkgIyBQb25lIGNhZGEgcmVuZ2zDs24gZW4gdW5hIGNlbGRhIGRlIHZlY3RvcgojIGluc3BlY3QoY29ycHVzKQpjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgY29udGVudF90cmFuc2Zvcm1lcih0b2xvd2VyKSkgIyBQb25lIHRvZG8gZW4gbWluw7pzY3VsYXMKICNpbnNwZWN0KGNvcnB1cykKY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHJlbW92ZVB1bmN0dWF0aW9uKSAjIEVsaW1pbmEgcHVudHVhY2nDs24KI2luc3BlY3QoY29ycHVzKQpjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgcmVtb3ZlTnVtYmVycykgIyBFbGltaW5hIG7Dum1lcm9zCmNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCByZW1vdmVXb3Jkcywgc3RvcHdvcmRzKCJzcGFuaXNoIikpICMgRWxpbWluYSBwYWxhYnJhcyBxdWUgbm8gaGFibGFuIGRlbCB0ZW1hCgojIGNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCByZW1vdmVXb3JkcywgYygiZHJlYW0iLCIiKSkgIyBFbGltaW5hIHBhbGFicmFzIHB1bnR1YWxlcwppbnNwZWN0KGNvcnB1cykKCgp0ZG08LSBUZXJtRG9jdW1lbnRNYXRyaXgoY29ycHVzKQptPC0gYXMubWF0cml4KHRkbSkgI0N1ZW50YSBsYXMgdmVjZXMgcXVlIGFwYXJlY2UgY2FkYSBwYWxhYnJhIHBvciByZW5nbMOzbi4KZnJlY3VlbmNpYTwtIHNvcnQocm93U3VtcyhtKSwgZGVjcmVhc2luZyA9IFRSVUUpICNDdWVudGEgbGEgZnJlY3VlbmNpYSBkZSBjYWRhIHBhbGFicmEgZW4gZWwgdGV4dG8KZnJlY3VlbmNpYV9kZjwtIGRhdGEuZnJhbWUod29yZD1uYW1lcyhmcmVjdWVuY2lhKSwgZnJlcT1mcmVjdWVuY2lhKSAjQ29udmllcnRlIGxhIGZyZWN1ZW5jaWEgYSBkYXRhCmBgYAoKYGBge3J9CmdncGxvdChoZWFkKGZyZWN1ZW5jaWFfZGYsMTApLCBhZXMoeD1yZW9yZGVyKHdvcmQsIC1mcmVxKSwgeT1mcmVxKSkgKwogICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJyZWQiKSArCiAgICAgIGdlb21fdGV4dChhZXMobGFiZWwgPSBmcmVxKSwgdmp1c3QgPSAtMC41KSArCiAgICAgIGxhYnModGl0bGUgPSAiVE9QIDEwIHBhbGFicmFzIG3DoXMgZnJlY3VlbnRlcyIsIHN1YnRpdGxlID0gIklUIChFc28pIC0gU3RlcGhlbiBLaW5nIiwgeCA9ICJQYWxhYnJhIiwgeT0iRnJlY3VlbmNpYSIpICsKICAgICAgeWxpbSgwLDIwKQpgYGAKCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogcmVkOyI+TnViZSBkZSBQYWxhYnJhczwvc3Bhbj4KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBFbCBwcm9jZXNhbWllbnRvIGRlIGRhdG9zIGFudGVzIGRlIGxhIG51YmUgZGUgcGFsYWJyYXMgZXMgaWd1YWwgcXVlIGVuIGVsIEFuw6FsaXNpcyBkZSBGcmVjdWVuY2lhcywgZGVzZGUgaW1wb3J0YXIgZWwgdGV4dG8gaGFzdGEgZnJlY3VlbmNpYV9kZgpzZXQuc2VlZCgxMjMpCndvcmRjbG91ZCh3b3JkcyA9IGZyZWN1ZW5jaWFfZGYkd29yZCxmcmVxPWZyZWN1ZW5jaWFfZGYkZnJlcSwgbWluLmZyZXE9MSwKICAgICAgICAgIHJhbmRvbS5vcmRlciA9IEZBTFNFLCBjb2xvcnMgPSBicmV3ZXIucGFsKDgsICJSZWRzIikpCmBgYAoKCg==