Teoría

La minería de texto (TM) es el proceso de extraer infrmación útil, patrones o conocimiento 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: Representación gráfica o visual de los datos para su interpretación. Los métodos más comune son: el Análisis de sentimientos, 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 Random Forest, Redes Neuronales y Regresiones.

Instalar paquetes y llamar librerías

#install.packages("tidyverse")    #Para manipulación de tablas
library(tidyverse)
#install.packages("tesseract")    #Para generar los OCR 
library(tesseract)
#install.packages("magick")       #Para trabajar con PNG
library(magick)
#install.packages("officer")      #Para exportar en formatos office (principalmente word)
library(officer)
#install.packages("pdftools")     #Para poder usar PDF's
library(pdftools)
#install.packages("purrr")        #Para la función map (aplicar funciones a vectores)
library(purrr)
#install.packages("tm")           #Para realizar Text Mining
library(tm)
#install.packages("RColorBrewer") #Para manejar colores
library(RColorBrewer)
#install.packages("wordcloud")    #Para realizar nubes de palabras (resaltar las más usadas)
library(wordcloud)
#install.packages("topicmodels")  #Mapa hacer modelos de temas (saber de qué habla el texto)
library(topicmodels)
#install.packages("ggplot2")
library(ggplot2)

1. Obtener datos mediante OCR

De imagen a texto

imagen1<- image_read("C:\\Users\\LuisD\\Documents\\Concentración\\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 que creamos
#print(doc1, target = "Texto1.docx") #Guarda el word en la computadora

De imagen a texto EN ESPAÑOL

Consultar idiomas disponibles de tesseract

#file.choose()
imagen2<- image_read("C:\\Users\\LuisD\\Documents\\Concentración\\imagen2.PNG")
tesseract_download("spa") #Se ponen entre comillas las letras correspondientes al idioma
## [1] "C:\\Users\\LuisD\\AppData\\Local\\tesseract5\\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() 
doc2<- doc2%>% body_add_par(texto2, style = "Normal") 
#print(doc2, target = "Texto2.docx")

De PDF a PNG

#file.choose()
#pdf1<- pdf_convert("C:\\Users\\LuisD\\Documents\\Concentración\\pdf1.pdf", dpi=600) %>% Map(ocr)

Repetir los pasos para pasar de PNG a texto

# EJEMPLO:

imagen_pdf1<- image_read("C:\\Users\\LuisD\\Documents\\Concentración\\pdf1_1.png")
#imagen_pdf2<- image_read("C:\\Users\\LuisD\\Documents\\Concentración\\pdf1_2.png")
#imagen_pdf3<- image_read("C:\\Users\\LuisD\\Documents\\Concentración\\pdf1_3.png")
#imagen_pdf4<- image_read("C:\\Users\\LuisD\\Documents\\Concentración\\pdf1_4.png")
#imagen_pdf5<- image_read("C:\\Users\\LuisD\\Documents\\Concentración\\pdf1_5.png")
#imagen_pdf6<- image_read("C:\\Users\\LuisD\\Documents\\Concentración\\pdf1_6.png")
#imagen_pdf7<- image_read("C:\\Users\\LuisD\\Documents\\Concentración\\pdf1_7.png")
#imagen_pdf8<- image_read("C:\\Users\\LuisD\\Documents\\Concentración\\pdf1_8.png")

tesseract_download("spa") #Se ponen entre comillas las letras correspondientes al idioma
## [1] "C:\\Users\\LuisD\\AppData\\Local\\tesseract5\\tesseract5\\tessdata/spa.traineddata"
texto3<- ocr(imagen_pdf1, engine=tesseract("spa"))
texto3
## [1] "SET RSE\nG S (ESA\né NX Missouri Department of Health and Senior Services CES)\n1D) RDA PO. Box 570, Jefferson City, MO 65102-0570 Phone: 573-751-6400 FAX: 573-751-6010 al\nN /. RELAY MISSOURI for Hearing and Speech Impaired 1-800-735-2966 VOICE 1-800-735-2466 leia\ne Peter Lyskowski Jeremiah W. (Jay) Ni\nQs Acting ble | e ar qe\nMissouri Public Water Systems\nNovember 10, 2015\nDear Public Water System Owners/Operators:\nThe Missouri State Public Health Laboratory (MSPHL) is in the process of implementing a new\nLaboratory Information Management System (LIMS) in its drinking water bacteriology testing\nlaboratory. The OpenELIS (OE) LIMS will provide the laboratory with improved sample management\ncapability, improved data integrity and reduced potential for human data entry error. In addition, the\nsystem will provide improved reporting capabilities, including direct electronic data exchange with the\nMissouri Department of Natural Resources” (MDNR) Safe Drinking Water Information System\n(SDWIS). SDWIS is the computer system MDNR uses to store regulatory water testing data and report\ntesting results to you and the U.S. Environmental Protection Agency. In addition, the new OE LIMS will\nprovide a web portal that MSPHL clients can use to access their own test results in real time.\nAs the MSPHL implements this new computer system, several changes will be made in the way you\ncollect and submit water samples for testing. This letter and information packet will provide you with\ninformation to help educate you on these changes.\nNEW SAMPLE BOTTLES:\nBeginning in August 2015, the MSPHL began using a larger sample bottle for water bacterial testing.\nThis bottle has a shrink wrap seal and two lines to indicate the proper sample volume. Please read the\nattached “SAMPLE COLLECTION INSTRUCTIONS” for details on how to use these new bottles.\nSample volume MUST be within the two lines on the bottle (100 — 120 mL) to be acceptable for\ntesting. You may continue to use your old bottles until the MSPHL can ship you new ones. Once you\nhave received the new bottles, please discard or recycle the old bottles.\nNEW SAMPLE INFORMATION FORMS:\nThe traditional sample information “card” that has been used for more than twenty years is being\nreplaced by the Environmental Sample Collection Form. An example form is attached. Please read the\nattached instructions for information on properly completing the new form.\nChanges to the form include the following;\n|. Form size is expanded to a single 8 Y” x 11” sheet of paper. The form is no longer in a triplicate\ncarbon copy format. You may choose to photocopy for your records if you prefer. Note: MDNR\ndoes not require a public water system to retain copies of sample collection forms: however, you\nmight utilize them for system inspections.\n2. The form is printed by the OE LIMS and will be pre-populated with your Public Water Supply\nID number, PWS name, address and county. Forms should not be shared with other supplies.\nwww.health.mo.qov\nHealthy Missourians for life.\nThe Missouri Department of Health and Senior Services will be the leader in promoting, protecting and partnering for health.\nAN EQUAL OPPORTUNITY / AFFIRMATIVE ACTION EMPLOYER: Services provided on a nondiscriminatory basis.\n"

2. Actividad 1 IT

Convertir de PDF a PNG

#file.choose()
pdf_it<- pdf_convert("C:\\Users\\LuisD\\Documents\\Concentración\\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!

Convertir de PNG a texto

imagen_eso1<- image_read("C:\\Users\\LuisD\\Documents\\Concentración\\eso3_1.png")
imagen_eso2<- image_read("C:\\Users\\LuisD\\Documents\\Concentración\\eso3_2.png")
imagen_eso3<- image_read("C:\\Users\\LuisD\\Documents\\Concentración\\eso3_3.png")

Agregar textosal WORD

tesseract_download("spa") #Se ponen entre comillas las letras correspondientes al idioma
## [1] "C:\\Users\\LuisD\\AppData\\Local\\tesseract5\\tesseract5\\tessdata/spa.traineddata"
texto_eso1<- ocr(imagen_eso1, engine=tesseract("spa"))
texto_eso1
## [1] "Y alli estaba, persiguiendo su barco de papel por el lado izquierdo de Witcham Street. Corría\ndeprisa, pero el agua le ganaba y el barquito estaba sacando ventaja. Oyó un rugido profundo y\nvio cómo cincuenta metros más adelante, colina abajo, el agua de la cuneta se precipitaba\ndentro de una boca de tormenta que aún continuaba abierta. Era un largo semicirculo oscuro\nabierto en el bordillo de la acera y mientras George miraba, una rama desgarrada, con la corteza\noscura y reluciente se hundió en aquellas fauces. Allí pendió por un momento y luego se deslizó\nhacia el interior. Hacia allí se encaminaba su bote.\n\n— ¡Mierda! —chilló horrorizado.\n\nForzó el paso y, por un momento, pareció que iba a alcanzar al barquito. Pero uno de sus ples\nresbaló y George cayo despatarrado despellejándose la rodilla con un grito de dolor. Desde su\nnueva perspectiva, a la altura del pavimento, vio que su barco giraba en redondo dos veces,\nmomentáneamente atrapado en otro remolino, antes de desaparecer.\n\n—|¡Mierda y más mierda! —volvió a chillar, estrellando el puño contra el pavimento.\n\nEso también dolió, y se echó a sollozar. ¡Qué manera tan estupida de perder el barco!\n\nSe levantó para caminar hacia la boca de tormenta y allí se dejó caer de rodillas, para mirar hacia\nel interior. El agua hacia un ruido hueco y humedo al caer en la oscuridad, Ese sonido le daba\nescalofrios. Hacía pensar en..\n\n—¡Eh!\n\nLa exclamación le fue arrancada como con un cordel. Retrocedioó.\n\nAllí adentro había unos ojos amarillos. Ese tipo de ojos que el siempre imaginaba, sin verlos\nnunca, en la oscuridad del sótano. Es un animal —penso, incoherente—,; eso es todo: un animal; a lo\nmejor un gato que quedó atrapado...\n\nDe todos modos, estaba por echar a correr; habria corrido uno o dos segundos, cuando su\ntablero mental se hubiera hecho cargo del espanto que le produjeron esos dos ojos amarillos y\nbrillantes. Sintió la áspera superficie del pavimento bajo los dedos y la fina lámina de agua fría\nque corría alrededor. Se vio a sí mismo levantándose y retrocediendo. Y fue entonces cuando\nuna voz, una voz perfectamente razonable y bastante simpática, le habló desde dentro de la\nboca de tormenta:\n\n—Hola, George —dijo.\n\nGeorge parpadeo y volvió a mirar. Apenas podía dar crédito a lo que vela; era como algo sacado\nde un cuento o de una película donde uno sabe que los animales hablan y bailan. Si hubiera\ntenido diez años más, no habria creido en lo que estaba viendo; pero no tenia dieciséis años, sino\nseis.\n\nEn la boca de tormenta habia un payaso. La luz distaba de ser buena, pero bastó para que\nGeorge Denbrough estuviese seguro de lo que veía. Era un payaso, como en el circo o en la tele.\nParecía una mezcla de Bozo y Clarabell, el que hablaba haciendo sonar su bocina en Howdy\nDoody, los sábados por la mañana. Búfalo Bob era el único que entendía a Clarabell, y eso\nsiempre hacia reir a George. La cara del payaso metido en la boca de tormenta era blanca; tenia\ncómicos mechones de pelo rojo a cada lado de la calva y una gran sonrisa de payaso pintada\n"
texto_eso2<- ocr(imagen_eso2, engine=tesseract("spa"))
texto_eso2
## [1] "alrededor de la boca. Si George hubiese vivido años después, habria pensado en Ronald\nMcDonald antes que en Bozo o en Clarabell.\n\nEl payaso tenía en una mano un manojo de globos de todos los colores, como tentadora fruta\nmadura.\n\nEn la otra, el barquito de papel de George.\n\n—¿Quieres tu barquito, Georgie? —El payaso sonrela.\n\nGeorge también sonrió. No podía evitarlo; aquella sonrisa era del tipo que uno devuelve sin\nquerer.\n\n—Por supuesto.\n\nEl payaso se echó a reir.\n\n—«Por supuesto». ¡Así me gusta! ¡Así me gusta! ¿Y un globo? ¿Que te parece? ¿Quieres un globo”\n—Bueno.. sí, por supuesto. —Alargó la mano, pero de inmediato la retiró contra su voluntad—. No\ndebo coger nada que me ofrezca un desconocido. Lo dice mi papá.\n\n—Y tu papa tiene mucha razón —replicó el payaso de la boca de tormenta sonriendo. George se\npreguntó cómo podia haber creido que sus ojos eran amarillos, si eran de un color azul brillante,\nbailarin, como los ojos de su mamá y de Bill —. Muchísima razón, ya lo creo. Por lo tanto, voy a\npresentarme. George, soy el señor Bob Gray, también conocido como Pennywise, el payaso\nBallarin. Pennywise, te presento a George Denbrough. George, te presento a Pennywise. Y ahora\nya nos conocemos. Yo no soy un desconocido y tu tampoco. ¿Correcto?\n\nGeorge soltó una risita.\n\n—Correcto. —Volvió a estirar la mano.. y a retirarla—. ¿Cómo te metiste alli adentro?\n\n—La tormenta me trajo volaaaando —dijo Pennywise, el payaso Bailarin—. Se llevó todo el circo.\n¿No sientes olor a circo, George?\n\nGeorge se inclinó hacia adelante. ¡De pronto olía a cacahuetes! ¡Cacahuetes tostados! ¡Y vinagre\nblanco, del que se pone en las patatas fritas por un agujero de la tapa! Y olía a algodón de\nazucar, a buñuelos, y también, leve, pero poderosamente, a estiercol de animales salvajes. Olia el\naroma regocijante del aserrin. Y sin embargo..\n\nSin embargo, bajo todo eso olía a inundación, a hojas deshechas y a oscuras sombras en bocas\nde tormenta. Era un olor húmedo y putrido. El olor del sótano.\n\nPero los otros olores eran más fuertes.\n\n—Claro que lo huelo —dijo.\n\n—¿Quieres tu barquito, George? —preguntó Pennywise—. Te lo pregunto otra vez porque no\npareces desearlo mucho.\n"
texto_eso3<- ocr(imagen_eso3, engine=tesseract("spa"))
texto_eso3
## [1] "Y lo mostró en alto, sonriendo. Llevaba un traje de seda abolsado con grandes botones color\nnaranja. Una corbata brillante, de color azul eléctrico, se le derramaba por la pechera. En las\nmanos llevaba grandes guantes blancos, como Mickey y Donald.\n\n—Si, claro —dijo George, mirando dentro de la boca de tormenta.\n\n—¿Y un globo? Los tengo rojos, verdes, amarillos, aZules..\n\n—¿Flotan?\n\n—¿Que si flotan? —La sonrisa del payaso se acentuó—. Oh, sí, claro que sí. ¡Flotan! También tengo\nalgodón de azucar.\n\nGeorge estiró la mano.\n\nEl payaso le sujeto el brazo.\n\nY entonces George vio cómo la cara del payaso cambiaba.\n\nLo que vio entonces fue tan terrible que lo peor que había imaginado sobre la cosa del sótano\nparecía un dulce sueño. Lo que vio destruyó su cordura de un zarpazo.\n\n—Flotan —croó la cosa de la alcantarilla con una voz que reía como entre coágulos.\n\nSujetaba el brazo de George con su puño grueso y agusanado. Tiró de él hacia esa horrible\noscuridad por donde el agua corría y rugía y aullaba llevando hacia el mar los desechos de la\ntormenta. George estiró el cuello para apartarse de esa negrura definitiva y empezó a gritar hacia\nla lluvia, a gritar como un loco hacia el gris cielo otoñal que se curvaba sobre Derry aquel día de\notoño de 1957. Sus gritos eran agudos y penetrantes y a lo largo de toda la calle, la gente se\nasomó a las ventanas o se lanzó a los porches.\n\n—Flotan —gruñó la cosa—, flotan, Georgie. Y cuando estés aqui abajo, conmigo, tú también\nflotarás.\n\nEl hombro de George se clavó contra el cemento del bordillo. Dave Gardener, que ese día no\nhabia ido a trabajar al Shoeboat debido a la inundación, vio sólo a un niño de impermeable\namarillo, un niño que gritaba y se retorcia en el arroyo mientras el agua lodosa le corría sobre la\ncara haciendo que sus alaridos sonaran burbujeantes.\n\n—Aqui abajo todo flota —susurró esa voz podrida, riendo, y de pronto sonó un desgarro y hubo\nun destello de agonía y George Denbrough ya no supo más.\n\nDave Gardener fue el primero en llegar. Aunque llegó sólo cuarenta y cinco segundos después\ndel primer grito, George Denbrough ya habia muerto. Gardener lo agarró por el impermeable, tiró\nde él hasta sacarlo a la calle.. y al girar en sus manos el cuerpo de George, también el empezó a\ngritar. El lado izquierdo del impermeable del niño estaba de un rojo intenso. La sangre fluía hacia\nla alcantarilla desde el agujero donde había estado el brazo izquierdo. Un trozo de hueso,\nhorriblemente brillante, asomaba por la tela rota.\n\nLos ojos del niño miraban fijamente el cielo gris y mientras Dave retrocedía a tropezones hacia\nlos otros que ya corrian por la calle, empezaron a llenarse de lluvia.\n"
doc_eso<- read_docx() 
doc_eso <- doc_eso %>% body_add_par(texto_eso1, style = "Normal") %>% body_add_par(texto_eso2, style = "Normal") %>% body_add_par(texto_eso3, style = "Normal") 
#print(doc_eso, target= "Actividad_eso.docx")

3. Exploración de datos “I have a dream”

Análisis de frecuencias

text<- readLines("http://www.sthda.com/sthda/RDoc/example-files/martin-luther-king-i-have-a-dream-speech.txt")
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
corpus<- tm_map(corpus, removePunctuation)  #Elimina la puntuación
## Warning in tm_map.SimpleCorpus(corpus, removePunctuation): transformation drops
## documents
corpus<- tm_map(corpus, removeNumbers)  #Elimina los números
## Warning in tm_map.SimpleCorpus(corpus, removeNumbers): transformation drops
## documents
corpus<- tm_map(corpus, removeWords, stopwords("en")) #Elimina las palabras conectoras (que no hablan del tema)
## Warning in tm_map.SimpleCorpus(corpus, removeWords, stopwords("en")):
## transformation drops documents
# corpus<- tm_map(corpus, removeWords, c("","")) Elimina palabras puntuales indeseadas 

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 completo

frecuenca_df<- data.frame(word=names(frecuencia), freq=frecuencia) #Convierte en un dataframe

ggplot(head(frecuenca_df,10),aes(x=reorder(word, -freq), y=freq))+
         geom_bar(stat = "identity", fill="lightblue")+
  geom_text(aes(label=freq), vjust= -0.5)+
          labs(title= "Top 10 palabras",subtitle = "Discurso 'I have a dream' de M. L. King",  x="Palabra", y="Frecuencia")+
  ylim(0,20)

Nube de palabras

#El procesamiento de datos antes de realizar la nube de palabras es igual que en el Análisis de frecuencias, desde la importación del texto hasta importar dicho texto a un dataframe
set.seed(123)
wordcloud(words=frecuenca_df$word, freq=frecuenca_df$freq, min.freq=1, random.order = FALSE, colors = brewer.pal(8,"RdYlBu"))

LS0tDQp0aXRsZTogIlRleHQgTWluaW5nIg0KYXV0aG9yOiAiTHVpcyBEYXZpZCBTw6FuY2hleiBDYXN0aWxsbyBBMDEyNzU2NTUiDQpkYXRlOiAiMi8yNi8yMDI0Ig0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICB0aGVtZTogeWV0aQ0KICBwZGZfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCi0tLQ0KDQogICFbXShDOlxcVXNlcnNcXEx1aXNEXFxEb2N1bWVudHNcXENvbmNlbnRyYWNpw7NuXFx0bS5wbmcpDQoNCg0KIyA8c3BhbiBzdHlsZT0gImNvbG9yOiByZWQ7Ij5UZW9yw61hPC9zcGFuPiANCkxhICoqbWluZXLDrWEgZGUgdGV4dG8qKiAoVE0pIGVzIGVsIHByb2Nlc28gZGUgZXh0cmFlciBpbmZybWFjacOzbiDDunRpbCwgcGF0cm9uZXMgbyBjb25vY2ltaWVudG8gZGUgdGV4dG9zIG5vIGVzdHJ1Y3R1cmFkb3MuICANCkNvbnN0YSBkZSAzIGV0YXBhczogIA0KMS4gT2J0ZW5lciBkYXRvczogRWwgKipyZWNvbm9jaW1pZW50byDDs3B0aWNvIGRlIGNhcmFjdGVyZXMgKE9DUikqKiBlcyB1bmEgdGVjbm9sb2fDrWEgcXVlIHBlcm1pdGUgY29udmVydGlyIGltw6FnZW5lcyBkZSB0ZXh0byBlbiB0ZXh0byBlZGl0YWJsZS4gVGFtYmnDqW4gZXMgY29ub2NpZG8gY29tbyAqKmV4dHJhY2Npw7NuIGRlIHRleHRvIGRlIGltw6FnZW5lcyoqICANCjIuIEV4cGxvcmFyIGRhdG9zOiBSZXByZXNlbnRhY2nDs24gZ3LDoWZpY2EgbyB2aXN1YWwgZGUgbG9zIGRhdG9zIHBhcmEgc3UgaW50ZXJwcmV0YWNpw7NuLiBMb3MgbcOpdG9kb3MgbcOhcyBjb211bmUgc29uOiBlbCBBbsOhbGlzaXMgZGUgc2VudGltaWVudG9zLCBOdWJlIGRlIHBhbGFicmFzIHkgZWwgVG9waWMgbW9kZWxpbmcuICANCjMuIEFuw6FsaXNpcyBwcmVkaWN0aXZvOiBzb24gbGFzIHTDqWNuaWNhcyB5IG1vZGVsb3MgZXN0YWTDrXN0aWNvcyBwYXJhIHByZWRlY2lyIHJlc3VsdGFkb3MgZnV0dXJvcy4gTG9zIG1vZGVsb3MgbcOhcyB1c2Fkb3Mgc29uIFJhbmRvbSBGb3Jlc3QsIFJlZGVzIE5ldXJvbmFsZXMgeSBSZWdyZXNpb25lcy4NCg0KIyA8c3BhbiBzdHlsZT0gImNvbG9yOiByZWQ7Ij5JbnN0YWxhciBwYXF1ZXRlcyB5IGxsYW1hciBsaWJyZXLDrWFzPC9zcGFuPiANCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikgICAgI1BhcmEgbWFuaXB1bGFjacOzbiBkZSB0YWJsYXMNCmxpYnJhcnkodGlkeXZlcnNlKQ0KI2luc3RhbGwucGFja2FnZXMoInRlc3NlcmFjdCIpICAgICNQYXJhIGdlbmVyYXIgbG9zIE9DUiANCmxpYnJhcnkodGVzc2VyYWN0KQ0KI2luc3RhbGwucGFja2FnZXMoIm1hZ2ljayIpICAgICAgICNQYXJhIHRyYWJhamFyIGNvbiBQTkcNCmxpYnJhcnkobWFnaWNrKQ0KI2luc3RhbGwucGFja2FnZXMoIm9mZmljZXIiKSAgICAgICNQYXJhIGV4cG9ydGFyIGVuIGZvcm1hdG9zIG9mZmljZSAocHJpbmNpcGFsbWVudGUgd29yZCkNCmxpYnJhcnkob2ZmaWNlcikNCiNpbnN0YWxsLnBhY2thZ2VzKCJwZGZ0b29scyIpICAgICAjUGFyYSBwb2RlciB1c2FyIFBERidzDQpsaWJyYXJ5KHBkZnRvb2xzKQ0KI2luc3RhbGwucGFja2FnZXMoInB1cnJyIikgICAgICAgICNQYXJhIGxhIGZ1bmNpw7NuIG1hcCAoYXBsaWNhciBmdW5jaW9uZXMgYSB2ZWN0b3JlcykNCmxpYnJhcnkocHVycnIpDQojaW5zdGFsbC5wYWNrYWdlcygidG0iKSAgICAgICAgICAgI1BhcmEgcmVhbGl6YXIgVGV4dCBNaW5pbmcNCmxpYnJhcnkodG0pDQojaW5zdGFsbC5wYWNrYWdlcygiUkNvbG9yQnJld2VyIikgI1BhcmEgbWFuZWphciBjb2xvcmVzDQpsaWJyYXJ5KFJDb2xvckJyZXdlcikNCiNpbnN0YWxsLnBhY2thZ2VzKCJ3b3JkY2xvdWQiKSAgICAjUGFyYSByZWFsaXphciBudWJlcyBkZSBwYWxhYnJhcyAocmVzYWx0YXIgbGFzIG3DoXMgdXNhZGFzKQ0KbGlicmFyeSh3b3JkY2xvdWQpDQojaW5zdGFsbC5wYWNrYWdlcygidG9waWNtb2RlbHMiKSAgI01hcGEgaGFjZXIgbW9kZWxvcyBkZSB0ZW1hcyAoc2FiZXIgZGUgcXXDqSBoYWJsYSBlbCB0ZXh0bykNCmxpYnJhcnkodG9waWNtb2RlbHMpDQojaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpDQpsaWJyYXJ5KGdncGxvdDIpDQpgYGANCg0KIyA8c3BhbiBzdHlsZT0gImNvbG9yOiByZWQ7Ij4xLiBPYnRlbmVyIGRhdG9zIG1lZGlhbnRlIE9DUjwvc3Bhbj4gDQoNCiMjIDxzcGFuIHN0eWxlPSAiY29sb3I6IHJlZDsiPkRlIGltYWdlbiBhIHRleHRvPC9zcGFuPiANCmBgYHtyfQ0KDQppbWFnZW4xPC0gaW1hZ2VfcmVhZCgiQzpcXFVzZXJzXFxMdWlzRFxcRG9jdW1lbnRzXFxDb25jZW50cmFjacOzblxcaW1hZ2VuMS5QTkciKQ0KdGV4dG8xPC0gb2NyKGltYWdlbjEpDQp0ZXh0bzENCmRvYzE8LSByZWFkX2RvY3goKSAjQ3JlYSB1biBkb2N1bWVudG8gZGUgd29yZCBlbiBibGFuY28NCmRvYzE8LSBkb2MxJT4lIGJvZHlfYWRkX3Bhcih0ZXh0bzEsIHN0eWxlID0gIk5vcm1hbCIpICNQZWdhIGVsIHRleHRvIGVuIGVsIHdvcmQgcXVlIGNyZWFtb3MNCiNwcmludChkb2MxLCB0YXJnZXQgPSAiVGV4dG8xLmRvY3giKSAjR3VhcmRhIGVsIHdvcmQgZW4gbGEgY29tcHV0YWRvcmENCmBgYA0KDQojIyA8c3BhbiBzdHlsZT0gImNvbG9yOiByZWQ7Ij5EZSBpbWFnZW4gYSB0ZXh0byAqRU4gRVNQQcORT0wqIDwvc3Bhbj4NCltDb25zdWx0YXIgaWRpb21hcyBkaXNwb25pYmxlcyBkZSB0ZXNzZXJhY3RdKGh0dHBzOi8vdGVzc2VyYWN0LW9jci5naXRodWIuaW8vdGVzc2RvYy9EYXRhLUZpbGVzLWluLWRpZmZlcmVudC12ZXJzaW9ucy5odG1sKQ0KYGBge3J9DQojZmlsZS5jaG9vc2UoKQ0KaW1hZ2VuMjwtIGltYWdlX3JlYWQoIkM6XFxVc2Vyc1xcTHVpc0RcXERvY3VtZW50c1xcQ29uY2VudHJhY2nDs25cXGltYWdlbjIuUE5HIikNCnRlc3NlcmFjdF9kb3dubG9hZCgic3BhIikgI1NlIHBvbmVuIGVudHJlIGNvbWlsbGFzIGxhcyBsZXRyYXMgY29ycmVzcG9uZGllbnRlcyBhbCBpZGlvbWENCnRleHRvMjwtIG9jcihpbWFnZW4yLCBlbmdpbmU9dGVzc2VyYWN0KCJzcGEiKSkNCnRleHRvMg0KZG9jMjwtIHJlYWRfZG9jeCgpIA0KZG9jMjwtIGRvYzIlPiUgYm9keV9hZGRfcGFyKHRleHRvMiwgc3R5bGUgPSAiTm9ybWFsIikgDQojcHJpbnQoZG9jMiwgdGFyZ2V0ID0gIlRleHRvMi5kb2N4IikNCmBgYA0KDQojIyA8c3BhbiBzdHlsZT0gImNvbG9yOiByZWQ7Ij5EZSBQREYgYSBQTkcgIDwvc3Bhbj4NCmBgYHtyIGVjaG89VFJVRX0NCiNmaWxlLmNob29zZSgpDQojcGRmMTwtIHBkZl9jb252ZXJ0KCJDOlxcVXNlcnNcXEx1aXNEXFxEb2N1bWVudHNcXENvbmNlbnRyYWNpw7NuXFxwZGYxLnBkZiIsIGRwaT02MDApICU+JSBNYXAob2NyKQ0KYGBgDQoNCiMjIDxzcGFuIHN0eWxlPSAiY29sb3I6IHJlZDsiPlJlcGV0aXIgbG9zIHBhc29zIHBhcmEgcGFzYXIgZGUgUE5HIGEgdGV4dG8gIDwvc3Bhbj4NCmBgYHtyfQ0KIyBFSkVNUExPOg0KDQppbWFnZW5fcGRmMTwtIGltYWdlX3JlYWQoIkM6XFxVc2Vyc1xcTHVpc0RcXERvY3VtZW50c1xcQ29uY2VudHJhY2nDs25cXHBkZjFfMS5wbmciKQ0KI2ltYWdlbl9wZGYyPC0gaW1hZ2VfcmVhZCgiQzpcXFVzZXJzXFxMdWlzRFxcRG9jdW1lbnRzXFxDb25jZW50cmFjacOzblxccGRmMV8yLnBuZyIpDQojaW1hZ2VuX3BkZjM8LSBpbWFnZV9yZWFkKCJDOlxcVXNlcnNcXEx1aXNEXFxEb2N1bWVudHNcXENvbmNlbnRyYWNpw7NuXFxwZGYxXzMucG5nIikNCiNpbWFnZW5fcGRmNDwtIGltYWdlX3JlYWQoIkM6XFxVc2Vyc1xcTHVpc0RcXERvY3VtZW50c1xcQ29uY2VudHJhY2nDs25cXHBkZjFfNC5wbmciKQ0KI2ltYWdlbl9wZGY1PC0gaW1hZ2VfcmVhZCgiQzpcXFVzZXJzXFxMdWlzRFxcRG9jdW1lbnRzXFxDb25jZW50cmFjacOzblxccGRmMV81LnBuZyIpDQojaW1hZ2VuX3BkZjY8LSBpbWFnZV9yZWFkKCJDOlxcVXNlcnNcXEx1aXNEXFxEb2N1bWVudHNcXENvbmNlbnRyYWNpw7NuXFxwZGYxXzYucG5nIikNCiNpbWFnZW5fcGRmNzwtIGltYWdlX3JlYWQoIkM6XFxVc2Vyc1xcTHVpc0RcXERvY3VtZW50c1xcQ29uY2VudHJhY2nDs25cXHBkZjFfNy5wbmciKQ0KI2ltYWdlbl9wZGY4PC0gaW1hZ2VfcmVhZCgiQzpcXFVzZXJzXFxMdWlzRFxcRG9jdW1lbnRzXFxDb25jZW50cmFjacOzblxccGRmMV84LnBuZyIpDQoNCnRlc3NlcmFjdF9kb3dubG9hZCgic3BhIikgI1NlIHBvbmVuIGVudHJlIGNvbWlsbGFzIGxhcyBsZXRyYXMgY29ycmVzcG9uZGllbnRlcyBhbCBpZGlvbWENCnRleHRvMzwtIG9jcihpbWFnZW5fcGRmMSwgZW5naW5lPXRlc3NlcmFjdCgic3BhIikpDQp0ZXh0bzMNCmBgYA0KDQoNCiMgPHNwYW4gc3R5bGU9ICJjb2xvcjogcmVkOyI+Mi4gQWN0aXZpZGFkIDEgSVQgPC9zcGFuPg0KDQojIyA8c3BhbiBzdHlsZT0gImNvbG9yOiByZWQ7Ij4gQ29udmVydGlyIGRlIFBERiBhIFBORyA8L3NwYW4+DQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KI2ZpbGUuY2hvb3NlKCkNCnBkZl9pdDwtIHBkZl9jb252ZXJ0KCJDOlxcVXNlcnNcXEx1aXNEXFxEb2N1bWVudHNcXENvbmNlbnRyYWNpw7NuXFxlc28zLnBkZiIsIGRwaT02MDApICU+JSBtYXAob2NyKQ0KYGBgDQoNCiMjIDxzcGFuIHN0eWxlPSAiY29sb3I6IHJlZDsiPkNvbnZlcnRpciBkZSBQTkcgYSB0ZXh0byA8L3NwYW4+DQpgYGB7cn0NCmltYWdlbl9lc28xPC0gaW1hZ2VfcmVhZCgiQzpcXFVzZXJzXFxMdWlzRFxcRG9jdW1lbnRzXFxDb25jZW50cmFjacOzblxcZXNvM18xLnBuZyIpDQppbWFnZW5fZXNvMjwtIGltYWdlX3JlYWQoIkM6XFxVc2Vyc1xcTHVpc0RcXERvY3VtZW50c1xcQ29uY2VudHJhY2nDs25cXGVzbzNfMi5wbmciKQ0KaW1hZ2VuX2VzbzM8LSBpbWFnZV9yZWFkKCJDOlxcVXNlcnNcXEx1aXNEXFxEb2N1bWVudHNcXENvbmNlbnRyYWNpw7NuXFxlc28zXzMucG5nIikNCmBgYA0KDQojIyA8c3BhbiBzdHlsZT0gImNvbG9yOiByZWQ7Ij5BZ3JlZ2FyIHRleHRvc2FsIFdPUkQgPC9zcGFuPg0KYGBge3J9DQp0ZXNzZXJhY3RfZG93bmxvYWQoInNwYSIpICNTZSBwb25lbiBlbnRyZSBjb21pbGxhcyBsYXMgbGV0cmFzIGNvcnJlc3BvbmRpZW50ZXMgYWwgaWRpb21hDQp0ZXh0b19lc28xPC0gb2NyKGltYWdlbl9lc28xLCBlbmdpbmU9dGVzc2VyYWN0KCJzcGEiKSkNCnRleHRvX2VzbzENCmBgYA0KYGBge3J9DQp0ZXh0b19lc28yPC0gb2NyKGltYWdlbl9lc28yLCBlbmdpbmU9dGVzc2VyYWN0KCJzcGEiKSkNCnRleHRvX2VzbzINCmBgYA0KDQpgYGB7cn0NCnRleHRvX2VzbzM8LSBvY3IoaW1hZ2VuX2VzbzMsIGVuZ2luZT10ZXNzZXJhY3QoInNwYSIpKQ0KdGV4dG9fZXNvMw0KYGBgDQoNCg0KYGBge3J9DQpkb2NfZXNvPC0gcmVhZF9kb2N4KCkgDQpkb2NfZXNvIDwtIGRvY19lc28gJT4lIGJvZHlfYWRkX3Bhcih0ZXh0b19lc28xLCBzdHlsZSA9ICJOb3JtYWwiKSAlPiUgYm9keV9hZGRfcGFyKHRleHRvX2VzbzIsIHN0eWxlID0gIk5vcm1hbCIpICU+JSBib2R5X2FkZF9wYXIodGV4dG9fZXNvMywgc3R5bGUgPSAiTm9ybWFsIikgDQojcHJpbnQoZG9jX2VzbywgdGFyZ2V0PSAiQWN0aXZpZGFkX2Vzby5kb2N4IikNCmBgYA0KDQoNCiMgPHNwYW4gc3R5bGU9ICJjb2xvcjogcmVkOyI+My4gRXhwbG9yYWNpw7NuIGRlIGRhdG9zICJJIGhhdmUgYSBkcmVhbSIgPC9zcGFuPg0KDQojIyA8c3BhbiBzdHlsZT0gImNvbG9yOiByZWQ7Ij5BbsOhbGlzaXMgZGUgZnJlY3VlbmNpYXMgPC9zcGFuPg0KYGBge3J9DQp0ZXh0PC0gcmVhZExpbmVzKCJodHRwOi8vd3d3LnN0aGRhLmNvbS9zdGhkYS9SRG9jL2V4YW1wbGUtZmlsZXMvbWFydGluLWx1dGhlci1raW5nLWktaGF2ZS1hLWRyZWFtLXNwZWVjaC50eHQiKQ0KY29ycHVzPC0gQ29ycHVzKFZlY3RvclNvdXJjZSh0ZXh0KSkgICNQb25lIGNhZGEgcmVuZ2zDs24gZW4gdW5hIGNlbGRhIGRlIHZlY3Rvcg0KI2luc3BlY3QoY29ycHVzKQ0KY29ycHVzPC0gdG1fbWFwKGNvcnB1cywgY29udGVudF90cmFuc2Zvcm1lcih0b2xvd2VyKSkgICNQb25lIHRvZG8gZW4gbWluw7pzY3VsYXMNCmNvcnB1czwtIHRtX21hcChjb3JwdXMsIHJlbW92ZVB1bmN0dWF0aW9uKSAgI0VsaW1pbmEgbGEgcHVudHVhY2nDs24NCmNvcnB1czwtIHRtX21hcChjb3JwdXMsIHJlbW92ZU51bWJlcnMpICAjRWxpbWluYSBsb3MgbsO6bWVyb3MNCmNvcnB1czwtIHRtX21hcChjb3JwdXMsIHJlbW92ZVdvcmRzLCBzdG9wd29yZHMoImVuIikpICNFbGltaW5hIGxhcyBwYWxhYnJhcyBjb25lY3RvcmFzIChxdWUgbm8gaGFibGFuIGRlbCB0ZW1hKQ0KIyBjb3JwdXM8LSB0bV9tYXAoY29ycHVzLCByZW1vdmVXb3JkcywgYygiIiwiIikpIEVsaW1pbmEgcGFsYWJyYXMgcHVudHVhbGVzIGluZGVzZWFkYXMgDQoNCnRkbTwtIFRlcm1Eb2N1bWVudE1hdHJpeChjb3JwdXMpDQptPC0gYXMubWF0cml4KHRkbSkgI0N1ZW50YSBsYXMgdmVjZXMgcXVlIGFwYXJlY2UgY2FkYSBwYWxhYnJhIHBvciByZW5nbMOzbg0KDQpmcmVjdWVuY2lhPC1zb3J0KHJvd1N1bXMobSksIGRlY3JlYXNpbmcgPSBUUlVFKSAjQ3VlbnRhIGxhIGZyZWN1ZW5jaWEgZGUgY2FkYSBwYWxhYnJhIGVuIGVsIHRleHRvIGNvbXBsZXRvDQoNCmZyZWN1ZW5jYV9kZjwtIGRhdGEuZnJhbWUod29yZD1uYW1lcyhmcmVjdWVuY2lhKSwgZnJlcT1mcmVjdWVuY2lhKSAjQ29udmllcnRlIGVuIHVuIGRhdGFmcmFtZQ0KDQpnZ3Bsb3QoaGVhZChmcmVjdWVuY2FfZGYsMTApLGFlcyh4PXJlb3JkZXIod29yZCwgLWZyZXEpLCB5PWZyZXEpKSsNCiAgICAgICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsPSJsaWdodGJsdWUiKSsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1mcmVxKSwgdmp1c3Q9IC0wLjUpKw0KICAgICAgICAgIGxhYnModGl0bGU9ICJUb3AgMTAgcGFsYWJyYXMiLHN1YnRpdGxlID0gIkRpc2N1cnNvICdJIGhhdmUgYSBkcmVhbScgZGUgTS4gTC4gS2luZyIsICB4PSJQYWxhYnJhIiwgeT0iRnJlY3VlbmNpYSIpKw0KICB5bGltKDAsMjApDQpgYGANCg0KIyMgPHNwYW4gc3R5bGU9ICJjb2xvcjogcmVkOyI+TnViZSBkZSBwYWxhYnJhcyA8L3NwYW4+DQpgYGB7cn0NCiNFbCBwcm9jZXNhbWllbnRvIGRlIGRhdG9zIGFudGVzIGRlIHJlYWxpemFyIGxhIG51YmUgZGUgcGFsYWJyYXMgZXMgaWd1YWwgcXVlIGVuIGVsIEFuw6FsaXNpcyBkZSBmcmVjdWVuY2lhcywgZGVzZGUgbGEgaW1wb3J0YWNpw7NuIGRlbCB0ZXh0byBoYXN0YSBpbXBvcnRhciBkaWNobyB0ZXh0byBhIHVuIGRhdGFmcmFtZQ0Kc2V0LnNlZWQoMTIzKQ0Kd29yZGNsb3VkKHdvcmRzPWZyZWN1ZW5jYV9kZiR3b3JkLCBmcmVxPWZyZWN1ZW5jYV9kZiRmcmVxLCBtaW4uZnJlcT0xLCByYW5kb20ub3JkZXIgPSBGQUxTRSwgY29sb3JzID0gYnJld2VyLnBhbCg4LCJSZFlsQnUiKSkNCmBgYA0KDQogICAgICAgICAg