RETO No. 2

suppressMessages(library(dplyr))
suppressMessages(library(tidyverse))
suppressMessages(library(XML))
suppressMessages(library(xml2))
suppressMessages(library(tm))
suppressMessages(library(wordcloud))
g <- gc(reset = T); rm(list = ls())
root <- "/Users/cesara.saavedravanegas/Desktop/Prueba_Tecnica_iDATA"
pth <- paste0(root,"/Reto_2/2020")

Como parte del reto #2 se cuenta con datos con informacion de resumenes de articulos, estos archivos se encuentran en formato “.xml” con los cuales se busca desarrollar un modelo de clasificacion no supervisado que permita agruparlos por tematicas similares.

Para llevar a cabo este proceamiento y clasificacion se hace necesario utilizar tecnicas de lenguaje natural y aprendizaje automatico. Para reliazar este analisis haremos uso de las librerias “tm” para el procesamiento de texto, “caret” para entrenar el modelo de clasificacion y uso de la libreria “XML” y “xml2 para la lectura de los articulos

1. Lectura de datos

Haciendo uso de la funcion “get_pminds” que lee y permite extraer el dato de interes del archivo .xml en este caso extraer los “AbstractNarration”.

# Listado de archivos
mylist <- list.files(path = pth, pattern = ".xml$", full.names = TRUE)
mylist <- mylist
# mylist <- mylist[1:100]
get_pmids <- function(x){
  xml_data <- xmlParse(x)
  pmid <- xpathSApply(xml_data, '//AbstractNarration', xmlValue)
  pmid
}
# Aplicar la funcion al listado de archivos
data_list <- lapply(mylist, get_pmids)

2. Procesamiento de la informacion

Tras listar los archivos .xml se procede a realizar la preparacion de la informacion, esto hacinedo uso de la libreria “corpus” con el fin de transformar el texto, esto es realizar limpieza de las “stopwords”, eliminacion de signos de putuacion, numeros y el ajuste de todo el texto a minusculas.

#
corpus <- tm::Corpus(VectorSource(data_list))
#
corpus <- tm_map(corpus, content_transformer(tolower))
Warning: transformation drops documents
corpus <- tm_map(corpus, removePunctuation)
Warning: transformation drops documents
corpus <- tm_map(corpus, removeNumbers)
Warning: transformation drops documents
corpus <- tm_map(corpus, removeWords, stopwords("en"))
Warning: transformation drops documents
corpus <- tm_map(corpus, stripWhitespace)
Warning: transformation drops documents

3. Creacion de la matriz de terminos

Tras realizar el procesamiento de los textos y estandarizacion de los textos, se procede a realizar la creacion de una matrix de texto con los terminos encontrados dentro de los abstract. Sin embargo se hace necesario ajustar el numero de terminos con baja frecuencia de aparicion en el conjunto de documentos y para llevar a cabo este procedimiento se hara uso de la matriz de terminos.

# Creacion de la matriz de terminos
dtm <- DocumentTermMatrix(corpus)
#
dtm <- removeSparseTerms(dtm, .9)
tfidf <- weightTfIdf(dtm)
Warning: empty document(s): 283 381 383 384 385 396 465 571 623 702 838 855 875 899 1058 1236 1650 1866 1965 2501 2619 2787 3235 3264 3307 3308 3370 3389 3401 3424 3763 3842 3965 3983 4018 4108 4159 4783 4788 4843 4870 4920 5012 5226 5434 5596 5622 5840 5894 6416 6485 6870 6901 6945 7559 7795 7799 7931 7936 7937 8091 8347 8559 8570 8574 8620 8637 8745 8747 9149 9165 9280 9346 9354 9358 9376 9379 9393 9395 9485 9562 9618 9629 9637 9683 9705 9710 9756 9759 9779 9809 9882 10020 10041 10063 10071 10075 10087 10129 10239 10488 10640 10785 10810 11577 11583 11836 11837 11877 11899 11908 11909 11932 11953 11962 11965 11971 11999 12001 12007 12008 12009 12050 12079 12090 12270 12292 12378 12466 12472 12588 12648 12649 12653 12707 12709 12758 12775 12783 12815 12845

4. Clasificacio por medio de Cluster

Para realizar la clasificacion de los abstract se pueden utilizar distintos metodos clustering, en este ejercicio en particular utilizaremos la agrupacion mediante K-means. Este metodo hace uso de un parametro k que es el encargado de dividir los datos en k grupos, por lo cual se hace importante encontrar el k optimo para agrupar los articulos.

Para conocer este numero optimo de cluster, se va utilizar el metodo Elbow el cual observa como cambia la varianza dentro de cada cluster. Siendo el minimo valor de varianza el que nos indica el k optimo.

# Metodo Elbow
wss <- numeric(100)
for (i in 1:100) {
  kmeans_model <- kmeans(tfidf, centers = i)
  wss[i] <- kmeans_model$tot.withinss
}
Warning: Quick-TRANSfer stage steps exceeded maximum (= 665000)Warning: did not converge in 10 iterationsWarning: did not converge in 10 iterationsWarning: did not converge in 10 iterationsWarning: did not converge in 10 iterationsWarning: did not converge in 10 iterationsWarning: did not converge in 10 iterationsWarning: did not converge in 10 iterationsWarning: Quick-TRANSfer stage steps exceeded maximum (= 665000)Warning: did not converge in 10 iterationsWarning: did not converge in 10 iterationsWarning: did not converge in 10 iterationsWarning: did not converge in 10 iterationsWarning: did not converge in 10 iterationsWarning: did not converge in 10 iterationsWarning: did not converge in 10 iterationsWarning: did not converge in 10 iterationsWarning: did not converge in 10 iterationsWarning: did not converge in 10 iterationsWarning: did not converge in 10 iterationsWarning: did not converge in 10 iterationsWarning: did not converge in 10 iterationsWarning: did not converge in 10 iterationsWarning: did not converge in 10 iterationsWarning: did not converge in 10 iterationsWarning: did not converge in 10 iterations
plot(1:100, wss, type = "b", pch = 19, frame = FALSE, 
     xlab = "Numero de Clusters (k)", ylab = "WSS")

En la figura anterior se observa como a medida que aumenta el numero de clusters, la distancia entre los elementos disminuye, esto nos indica que a medida que aumenta el k los cluster seran mas pequeños. Dado el tamano de la base de datos (contamos con 13300 abstract) el tamaño k de cluster optimos lo voy a definir en K=100.

Posterior a esto utilizare la matriz de terminos para iniciar la clasificacion y correspondiente asignacion de los articulos a los kluster.

# Cluster k-means
optimal_k <- 100
kmeans_model <- kmeans(tfidf, centers = optimal_k)
cluster_assignments <- kmeans_model$cluster

Haciendo uso de las palabras mas comunes y con mayor relevancia se realiza la clasificacion y asignacion de los cluster a cada uno de los textos.

# Example analysis
cluster_results <- data.frame(abstract = data_list, cluster = cluster_assignments)

Aqui se muestra la frecuencia de observaciones con la que cuenta cada uno de loa 100 cluster que se definieron, en promedio cada cluster tiene al rededor de 50 abstract, esto nos podria indicar que pueda reducirse el numero de cluster.

# Example bar plot of cluster sizes
barplot(table(cluster_assignments), main = "Cluster Sizes", xlab = "Cluster", ylab = "Number of Documents", col = "skyblue")

Como parte del ejercicio de clasficacion, se presentan aquellos terminos con mayor frecuencia de aparicion en los k-cluster definidos previamente

# Terminos mas comunes
for (i in 1:optimal_k) {
  cat("Cluster", i, ":\n")
  terms <- colnames(tfidf)[order(kmeans_model$centers[i, ], decreasing = TRUE)[1:5]]
  cat("Top terminos:", paste(terms, collapse = ", "), "\n\n")
}
Cluster 1 :
Top terminos: surface, water, chemical, properties, materials 

Cluster 2 :
Top terminos: properties, materials, structure, fundamental, chemical 

Cluster 3 :
Top terminos: chemical, materials, university, processes, energy 

Cluster 4 :
Top terminos: environments, environment, different, environmental, conditions 

Cluster 5 :
Top terminos: surface, processes, structure, conditions, study 

Cluster 6 :
Top terminos: energy, materials, high, generation, performance 

Cluster 7 :
Top terminos: social, health, data, networks, behavior 

Cluster 8 :
Top terminos: data, team, will, public, work 

Cluster 9 :
Top terminos: interactions, experimental, biological, studies, understanding 

Cluster 10 :
Top terminos: changes, response, conditions, change, may 

Cluster 11 :
Top terminos: mechanisms, processes, understanding, role, identify 

Cluster 12 :
Top terminos: environmental, conditions, environment, change, changes 

Cluster 13 :
Top terminos: states, state, data, across, test 

Cluster 14 :
Top terminos: dynamics, systems, models, field, model 

Cluster 15 :
Top terminos: institutions, stem, undergraduate, students, underrepresented 

Cluster 16 :
Top terminos: energy, building, system, technology, systems 

Cluster 17 :
Top terminos: small, proposed, technology, potential, system 

Cluster 18 :
Top terminos: engineering, students, education, student, learning 

Cluster 19 :
Top terminos: surface, materials, proposed, used, energy 

Cluster 20 :
Top terminos: problems, theory, algorithms, methods, analysis 

Cluster 21 :
Top terminos: control, systems, system, energy, behavior 

Cluster 22 :
Top terminos: critical, water, processes, network, surface 

Cluster 23 :
Top terminos: workforce, industry, education, advanced, program 

Cluster 24 :
Top terminos: methods, data, computational, analysis, develop 

Cluster 25 :
Top terminos: natural, researchers, environmental, water, field 

Cluster 26 :
Top terminos: data, available, public, life, time 

Cluster 27 :
Top terminos: computational, tools, modeling, algorithms, methods 

Cluster 28 :
Top terminos: theory, number, problems, areas, fields 

Cluster 29 :
Top terminos: technology, proposed, may, potential, based 

Cluster 30 :
Top terminos: theory, physics, study, structures, groups 

Cluster 31 :
Top terminos: school, high, students, student, education 

Cluster 32 :
Top terminos: models, model, data, computational, modeling 

Cluster 33 :
Top terminos: researchers, system, participation, nsf, advanced 

Cluster 34 :
Top terminos: techniques, data, analysis, efficient, tools 

Cluster 35 :
Top terminos: practices, stem, education, institutions, learning 

Cluster 36 :
Top terminos: time, years, one, test, processes 

Cluster 37 :
Top terminos: materials, properties, energy, advanced, applications 

Cluster 38 :
Top terminos: biological, biology, systems, chemical, data 

Cluster 39 :
Top terminos: change, changes, environmental, global, future 

Cluster 40 :
Top terminos: process, energy, technology, processes, materials 

Cluster 41 :
Top terminos: systems, system, design, data, applications 

Cluster 42 :
Top terminos: scientists, scientific, science, early, community 

Cluster 43 :
Top terminos: behavior, social, study, information, may 

Cluster 44 :
Top terminos: effects, social, study, may, different 

Cluster 45 :
Top terminos: water, technology, control, use, different 

Cluster 46 :
Top terminos: stem, graduate, education, nsf, supports 

Cluster 47 :
Top terminos: technologies, technology, systems, work, industry 

Cluster 48 :
Top terminos: network, networks, data, access, resources 

Cluster 49 :
Top terminos: experiments, experimental, conditions, processes, test 

Cluster 50 :
Top terminos: framework, data, learning, systems, modeling 

Cluster 51 :
Top terminos: communities, community, states, social, local 

Cluster 52 :
Top terminos: access, data, algorithms, information, multiple 

Cluster 53 :
Top terminos: theory, problems, study, questions, physics 

Cluster 54 :
Top terminos: machine, learning, data, algorithms, systems 

Cluster 55 :
Top terminos: group, groups, theory, study, social 

Cluster 56 :
Top terminos: program, students, training, projects, university 

Cluster 57 :
Top terminos: algorithms, problems, learning, data, efficient 

Cluster 58 :
Top terminos: structures, materials, structure, properties, design 

Cluster 59 :
Top terminos: industry, technologies, future, workforce, technology 

Cluster 60 :
Top terminos: biology, biological, participation, underrepresented, training 

Cluster 61 :
Top terminos: networks, network, data, learning, applications 

Cluster 62 :
Top terminos: water, processes, changes, surface, environmental 

Cluster 63 :
Top terminos: programs, program, stem, development, university 

Cluster 64 :
Top terminos: water, surface, lead, technology, system 

Cluster 65 :
Top terminos: stem, education, participation, institutions, program 

Cluster 66 :
Top terminos: information, data, systems, knowledge, can 

Cluster 67 :
Top terminos: career, early, scientists, stem, researchers 

Cluster 68 :
Top terminos: machine, learning, algorithms, data, models 

Cluster 69 :
Top terminos: system, systems, proposed, data, small 

Cluster 70 :
Top terminos: chemical, university, structure, used, program 

Cluster 71 :
Top terminos: effective, specific, used, health, system 

Cluster 72 :
Top terminos: global, change, changes, environmental, researchers 

Cluster 73 :
Top terminos: form, one, processes, study, order 

Cluster 74 :
Top terminos: model, models, data, modeling, used 

Cluster 75 :
Top terminos: diversity, biological, diverse, communities, across 

Cluster 76 :
Top terminos: strategies, social, health, different, public 

Cluster 77 :
Top terminos: communities, community, local, social, knowledge 

Cluster 78 :
Top terminos: human, health, data, systems, physical 

Cluster 79 :
Top terminos: materials, properties, energy, new, state 

Cluster 80 :
Top terminos: data, science, community, analysis, access 

Cluster 81 :
Top terminos: models, modeling, data, model, processes 

Cluster 82 :
Top terminos: learning, student, knowledge, machine, education 

Cluster 83 :
Top terminos: networks, network, social, algorithms, theory 

Cluster 84 :
Top terminos: education, resources, community, stem, nsf 

Cluster 85 :
Top terminos: nsf, provides, projects, scientists, university 

Cluster 86 :
Top terminos: analysis, data, university, techniques, methods 

Cluster 87 :
Top terminos: performance, applications, data, system, can 

Cluster 88 :
Top terminos: physics, theory, energy, theoretical, model 

Cluster 89 :
Top terminos: stem, increase, students, need, student 

Cluster 90 :
Top terminos: stem, learning, environments, experiences, practices 

Cluster 91 :
Top terminos: control, systems, algorithms, system, theory 

Cluster 92 :
Top terminos: computer, science, learning, education, students 

Cluster 93 :
Top terminos: student, learning, stem, students, education 

Cluster 94 :
Top terminos: scale, large, time, global, energy 

Cluster 95 :
Top terminos: applications, performance, data, systems, efficient 

Cluster 96 :
Top terminos: design, integrated, performance, enable, engineering 

Cluster 97 :
Top terminos: level, change, global, future, response 

Cluster 98 :
Top terminos: life, early, across, change, environment 

Cluster 99 :
Top terminos: health, public, social, data, information 

Cluster 100 :
Top terminos: stem, school, university, effective, program 

Nuevamente y como se menciono anteriormente, es posible que si se realiza una reduccion de los k-clusters se puedan agrupar de una mejor forma. Esto dado que en algunos cluster se evidencia la repeticion de algunos terminos.

Finalmente como parte del ejercicio de clasificacion de textos, se presentan algunas nubes de palabras o wordcloud, esto con el fin de visibilizar aquellos terminos mas comunes en algunos de los cluster. Para llevar a cabo estos graficos se crea una funcion que itera en el numero de k-optimo, esto es 1 a 100. Por terminos de practicidad se presenta un ejemplo de nube de palabras para un cluster que reune abstract que tienen en comun los terminos que alli se muestran.


wordcloud(words = tfidf[["dimnames"]][["Terms"]],
            freq = as.vector(tfidf[cluster_assignments == 2, ]),
            min.freq = 1,
            scale = c(3, 0.5),
            colors = brewer.pal(8, "Dark2"),
            main = paste("Cluster", i))

5. Conclusiones

Como parte del ejercicio de clasificacion de textos mediante un algoritmo no supervisado, es importante mencionar la practicidad que tiene este y el como el tener un corpus de gran tamaño permite tener mejores resultados. Tambien es importante mencionar que puede hacerse uso de otros algoritmos de clasificacion mas precisos.

Es relvante mencionar que para tener una clasificacion mas precisa, no solo requiere un algoritmo de clasificacion sino que seria de gran utilidad tener una clasificacion previa “topics”, esto con el fin de tener una fuente de entrada que nos permita definir con mayor claridad el numero de cluster y los terminos comunes que se van a asociar a cada grupo esto ayudaria a tener una clasificacion mas precisa.

LS0tCnRpdGxlOiAiTm90ZWJvb2sgLSBQcnVlYmEgaURhdGEiCmF1dGhvcjogIkNlc2FyIEEuIFNhYXZlZHJhIFZhbmVnYXMsIGNlc2FyLnNhYXZlZHJhQGNvcnJlb3VuaXZhbGxlLmVkdS5jbyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBSRVRPIE5vLiAyCgpgYGB7cn0Kc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KGRwbHlyKSkKc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KHRpZHl2ZXJzZSkpCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeShYTUwpKQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoeG1sMikpCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeSh0bSkpCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeSh3b3JkY2xvdWQpKQpgYGAKCgpgYGB7cn0KZyA8LSBnYyhyZXNldCA9IFQpOyBybShsaXN0ID0gbHMoKSkKcm9vdCA8LSAiL1VzZXJzL2Nlc2FyYS5zYWF2ZWRyYXZhbmVnYXMvRGVza3RvcC9QcnVlYmFfVGVjbmljYV9pREFUQSIKcHRoIDwtIHBhc3RlMChyb290LCIvUmV0b18yLzIwMjAiKQpgYGAKCkNvbW8gcGFydGUgZGVsIHJldG8gIzIgc2UgY3VlbnRhIGNvbiBkYXRvcyBjb24gaW5mb3JtYWNpb24gZGUgcmVzdW1lbmVzIGRlIGFydGljdWxvcywgZXN0b3MgYXJjaGl2b3Mgc2UgZW5jdWVudHJhbiBlbiBmb3JtYXRvICIueG1sIiBjb24gbG9zIGN1YWxlcyBzZSBidXNjYSBkZXNhcnJvbGxhciB1biBtb2RlbG8gZGUgY2xhc2lmaWNhY2lvbiBubyBzdXBlcnZpc2FkbyBxdWUgcGVybWl0YSBhZ3J1cGFybG9zIHBvciB0ZW1hdGljYXMgc2ltaWxhcmVzLiAKClBhcmEgbGxldmFyIGEgY2FibyBlc3RlIHByb2NlYW1pZW50byB5IGNsYXNpZmljYWNpb24gc2UgaGFjZSBuZWNlc2FyaW8gdXRpbGl6YXIgdGVjbmljYXMgZGUgbGVuZ3VhamUgbmF0dXJhbCB5IGFwcmVuZGl6YWplIGF1dG9tYXRpY28uIFBhcmEgcmVsaWF6YXIgZXN0ZSBhbmFsaXNpcyBoYXJlbW9zIHVzbyBkZSBsYXMgbGlicmVyaWFzICJ0bSIgcGFyYSBlbCBwcm9jZXNhbWllbnRvIGRlIHRleHRvLCAiY2FyZXQiIHBhcmEgZW50cmVuYXIgZWwgbW9kZWxvIGRlIGNsYXNpZmljYWNpb24geSB1c28gZGUgbGEgbGlicmVyaWEgIlhNTCIgeSAieG1sMiBwYXJhIGxhIGxlY3R1cmEgZGUgbG9zIGFydGljdWxvcyAKCiMgMS4gTGVjdHVyYSBkZSBkYXRvcwoKSGFjaWVuZG8gdXNvIGRlIGxhIGZ1bmNpb24gImdldF9wbWluZHMiIHF1ZSBsZWUgeSBwZXJtaXRlIGV4dHJhZXIgZWwgZGF0byBkZSBpbnRlcmVzIGRlbCBhcmNoaXZvIC54bWwgZW4gZXN0ZSBjYXNvIGV4dHJhZXIgbG9zICJBYnN0cmFjdE5hcnJhdGlvbiIuCgpgYGB7cn0KIyBMaXN0YWRvIGRlIGFyY2hpdm9zCm15bGlzdCA8LSBsaXN0LmZpbGVzKHBhdGggPSBwdGgsIHBhdHRlcm4gPSAiLnhtbCQiLCBmdWxsLm5hbWVzID0gVFJVRSkKbXlsaXN0IDwtIG15bGlzdAojIG15bGlzdCA8LSBteWxpc3RbMToxMDBdCmdldF9wbWlkcyA8LSBmdW5jdGlvbih4KXsKICB4bWxfZGF0YSA8LSB4bWxQYXJzZSh4KQogIHBtaWQgPC0geHBhdGhTQXBwbHkoeG1sX2RhdGEsICcvL0Fic3RyYWN0TmFycmF0aW9uJywgeG1sVmFsdWUpCiAgcG1pZAp9CiMgQXBsaWNhciBsYSBmdW5jaW9uIGFsIGxpc3RhZG8gZGUgYXJjaGl2b3MKZGF0YV9saXN0IDwtIGxhcHBseShteWxpc3QsIGdldF9wbWlkcykKYGBgCgojIDIuIFByb2Nlc2FtaWVudG8gZGUgbGEgaW5mb3JtYWNpb24KClRyYXMgbGlzdGFyIGxvcyBhcmNoaXZvcyAueG1sIHNlIHByb2NlZGUgYSByZWFsaXphciBsYSBwcmVwYXJhY2lvbiBkZSBsYSBpbmZvcm1hY2lvbiwgZXN0byBoYWNpbmVkbyB1c28gZGUgbGEgbGlicmVyaWEgImNvcnB1cyIgY29uIGVsIGZpbiBkZSB0cmFuc2Zvcm1hciBlbCB0ZXh0bywgZXN0byBlcyByZWFsaXphciBsaW1waWV6YSBkZSBsYXMgInN0b3B3b3JkcyIsIGVsaW1pbmFjaW9uIGRlIHNpZ25vcyBkZSBwdXR1YWNpb24sIG51bWVyb3MgeSBlbCBhanVzdGUgZGUgdG9kbyBlbCB0ZXh0byBhIG1pbnVzY3VsYXMuCgpgYGB7cn0KIwpjb3JwdXMgPC0gdG06OkNvcnB1cyhWZWN0b3JTb3VyY2UoZGF0YV9saXN0KSkKIwpjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgY29udGVudF90cmFuc2Zvcm1lcih0b2xvd2VyKSkKY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHJlbW92ZVB1bmN0dWF0aW9uKQpjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgcmVtb3ZlTnVtYmVycykKY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHJlbW92ZVdvcmRzLCBzdG9wd29yZHMoImVuIikpCmNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCBzdHJpcFdoaXRlc3BhY2UpCmBgYAoKIyAzLiBDcmVhY2lvbiBkZSBsYSBtYXRyaXogZGUgdGVybWlub3MKClRyYXMgcmVhbGl6YXIgZWwgcHJvY2VzYW1pZW50byBkZSBsb3MgdGV4dG9zIHkgZXN0YW5kYXJpemFjaW9uIGRlIGxvcyB0ZXh0b3MsIHNlIHByb2NlZGUgYSByZWFsaXphciBsYSBjcmVhY2lvbiBkZSB1bmEgbWF0cml4IGRlIHRleHRvIGNvbiBsb3MgdGVybWlub3MgZW5jb250cmFkb3MgZGVudHJvIGRlIGxvcyBhYnN0cmFjdC4gU2luIGVtYmFyZ28gc2UgaGFjZSBuZWNlc2FyaW8gYWp1c3RhciBlbCBudW1lcm8gZGUgdGVybWlub3MgY29uIGJhamEgZnJlY3VlbmNpYSBkZSBhcGFyaWNpb24gZW4gZWwgY29uanVudG8gZGUgZG9jdW1lbnRvcyB5IHBhcmEgbGxldmFyIGEgY2FibyBlc3RlIHByb2NlZGltaWVudG8gc2UgaGFyYSB1c28gZGUgbGEgbWF0cml6IGRlIHRlcm1pbm9zLiAKCmBgYHtyfQojIENyZWFjaW9uIGRlIGxhIG1hdHJpeiBkZSB0ZXJtaW5vcwpkdG0gPC0gRG9jdW1lbnRUZXJtTWF0cml4KGNvcnB1cykKIwpkdG0gPC0gcmVtb3ZlU3BhcnNlVGVybXMoZHRtLCAuOSkKdGZpZGYgPC0gd2VpZ2h0VGZJZGYoZHRtKQpgYGAKCiMgNC4gQ2xhc2lmaWNhY2lvIHBvciBtZWRpbyBkZSBDbHVzdGVyIAoKUGFyYSByZWFsaXphciBsYSBjbGFzaWZpY2FjaW9uIGRlIGxvcyBhYnN0cmFjdCBzZSBwdWVkZW4gdXRpbGl6YXIgZGlzdGludG9zIG1ldG9kb3MgY2x1c3RlcmluZywgZW4gZXN0ZSBlamVyY2ljaW8gZW4gcGFydGljdWxhciB1dGlsaXphcmVtb3MgbGEgYWdydXBhY2lvbiBtZWRpYW50ZSBLLW1lYW5zLiBFc3RlIG1ldG9kbyBoYWNlIHVzbyBkZSB1biBwYXJhbWV0cm8gayBxdWUgZXMgZWwgZW5jYXJnYWRvIGRlIGRpdmlkaXIgbG9zIGRhdG9zIGVuIGsgZ3J1cG9zLCBwb3IgbG8gY3VhbCBzZSBoYWNlIGltcG9ydGFudGUgZW5jb250cmFyIGVsIGsgb3B0aW1vIHBhcmEgYWdydXBhciBsb3MgYXJ0aWN1bG9zLiAKClBhcmEgY29ub2NlciBlc3RlIG51bWVybyBvcHRpbW8gZGUgY2x1c3Rlciwgc2UgdmEgdXRpbGl6YXIgZWwgbWV0b2RvIEVsYm93IGVsIGN1YWwgb2JzZXJ2YSBjb21vIGNhbWJpYSBsYSB2YXJpYW56YSBkZW50cm8gZGUgY2FkYSBjbHVzdGVyLiBTaWVuZG8gZWwgbWluaW1vIHZhbG9yIGRlIHZhcmlhbnphIGVsIHF1ZSBub3MgaW5kaWNhIGVsIGsgb3B0aW1vLiAKCmBgYHtyfQojIE1ldG9kbyBFbGJvdwp3c3MgPC0gbnVtZXJpYygxMDApCmZvciAoaSBpbiAxOjEwMCkgewogIGttZWFuc19tb2RlbCA8LSBrbWVhbnModGZpZGYsIGNlbnRlcnMgPSBpKQogIHdzc1tpXSA8LSBrbWVhbnNfbW9kZWwkdG90LndpdGhpbnNzCn0KYGBgCgpgYGB7cn0KcGxvdCgxOjEwMCwgd3NzLCB0eXBlID0gImIiLCBwY2ggPSAxOSwgZnJhbWUgPSBGQUxTRSwgCiAgICAgeGxhYiA9ICJOdW1lcm8gZGUgQ2x1c3RlcnMgKGspIiwgeWxhYiA9ICJXU1MiKQpgYGAKRW4gbGEgZmlndXJhIGFudGVyaW9yIHNlIG9ic2VydmEgY29tbyBhIG1lZGlkYSBxdWUgYXVtZW50YSBlbCBudW1lcm8gZGUgY2x1c3RlcnMsIGxhIGRpc3RhbmNpYSBlbnRyZSBsb3MgZWxlbWVudG9zIGRpc21pbnV5ZSwgZXN0byBub3MgaW5kaWNhIHF1ZSBhIG1lZGlkYSBxdWUgYXVtZW50YSBlbCBrIGxvcyBjbHVzdGVyIHNlcmFuIG1hcyBwZXF1ZcOxb3MuIERhZG8gZWwgdGFtYW5vIGRlIGxhIGJhc2UgZGUgZGF0b3MgKGNvbnRhbW9zIGNvbiAxMzMwMCBhYnN0cmFjdCkgZWwgdGFtYcOxbyBrIGRlIGNsdXN0ZXIgb3B0aW1vcyBsbyB2b3kgYSBkZWZpbmlyIGVuIEs9MTAwLgoKUG9zdGVyaW9yIGEgZXN0byB1dGlsaXphcmUgbGEgbWF0cml6IGRlIHRlcm1pbm9zIHBhcmEgaW5pY2lhciBsYSBjbGFzaWZpY2FjaW9uIHkgY29ycmVzcG9uZGllbnRlIGFzaWduYWNpb24gZGUgbG9zIGFydGljdWxvcyBhIGxvcyBrbHVzdGVyLiAKCgpgYGB7cn0KIyBDbHVzdGVyIGstbWVhbnMKb3B0aW1hbF9rIDwtIDEwMAprbWVhbnNfbW9kZWwgPC0ga21lYW5zKHRmaWRmLCBjZW50ZXJzID0gb3B0aW1hbF9rKQpjbHVzdGVyX2Fzc2lnbm1lbnRzIDwtIGttZWFuc19tb2RlbCRjbHVzdGVyCmBgYAoKSGFjaWVuZG8gdXNvIGRlIGxhcyBwYWxhYnJhcyBtYXMgY29tdW5lcyB5IGNvbiBtYXlvciByZWxldmFuY2lhIHNlIHJlYWxpemEgbGEgY2xhc2lmaWNhY2lvbiB5IGFzaWduYWNpb24gZGUgbG9zIGNsdXN0ZXIgYSBjYWRhIHVubyBkZSBsb3MgdGV4dG9zLgoKYGBge3J9CiMgRXhhbXBsZSBhbmFseXNpcwpjbHVzdGVyX3Jlc3VsdHMgPC0gZGF0YS5mcmFtZShhYnN0cmFjdCA9IGRhdGFfbGlzdCwgY2x1c3RlciA9IGNsdXN0ZXJfYXNzaWdubWVudHMpCgpgYGAKCkFxdWkgc2UgbXVlc3RyYSBsYSBmcmVjdWVuY2lhIGRlIG9ic2VydmFjaW9uZXMgY29uIGxhIHF1ZSBjdWVudGEgY2FkYSB1bm8gZGUgbG9hIDEwMCBjbHVzdGVyIHF1ZSBzZSBkZWZpbmllcm9uLCBlbiBwcm9tZWRpbyBjYWRhIGNsdXN0ZXIgdGllbmUgYWwgcmVkZWRvciBkZSA1MCBhYnN0cmFjdCwgZXN0byBub3MgcG9kcmlhIGluZGljYXIgcXVlIHB1ZWRhIHJlZHVjaXJzZSBlbCBudW1lcm8gZGUgY2x1c3Rlci4gCgpgYGB7cn0KIyBFeGFtcGxlIGJhciBwbG90IG9mIGNsdXN0ZXIgc2l6ZXMKYmFycGxvdCh0YWJsZShjbHVzdGVyX2Fzc2lnbm1lbnRzKSwgbWFpbiA9ICJDbHVzdGVyIFNpemVzIiwgeGxhYiA9ICJDbHVzdGVyIiwgeWxhYiA9ICJOdW1iZXIgb2YgRG9jdW1lbnRzIiwgY29sID0gInNreWJsdWUiKQpgYGAKQ29tbyBwYXJ0ZSBkZWwgZWplcmNpY2lvIGRlIGNsYXNmaWNhY2lvbiwgc2UgcHJlc2VudGFuIGFxdWVsbG9zIHRlcm1pbm9zIGNvbiBtYXlvciBmcmVjdWVuY2lhIGRlIGFwYXJpY2lvbiBlbiBsb3Mgay1jbHVzdGVyIGRlZmluaWRvcyBwcmV2aWFtZW50ZSAKCmBgYHtyfQojIFRlcm1pbm9zIG1hcyBjb211bmVzCmZvciAoaSBpbiAxOm9wdGltYWxfaykgewogIGNhdCgiQ2x1c3RlciIsIGksICI6XG4iKQogIHRlcm1zIDwtIGNvbG5hbWVzKHRmaWRmKVtvcmRlcihrbWVhbnNfbW9kZWwkY2VudGVyc1tpLCBdLCBkZWNyZWFzaW5nID0gVFJVRSlbMTo1XV0KICBjYXQoIlRvcCB0ZXJtaW5vczoiLCBwYXN0ZSh0ZXJtcywgY29sbGFwc2UgPSAiLCAiKSwgIlxuXG4iKQp9CmBgYAoKCk51ZXZhbWVudGUgeSBjb21vIHNlIG1lbmNpb25vIGFudGVyaW9ybWVudGUsIGVzIHBvc2libGUgcXVlIHNpIHNlIHJlYWxpemEgdW5hIHJlZHVjY2lvbiBkZSBsb3Mgay1jbHVzdGVycyBzZSBwdWVkYW4gYWdydXBhciBkZSB1bmEgbWVqb3IgZm9ybWEuIEVzdG8gZGFkbyBxdWUgZW4gYWxndW5vcyBjbHVzdGVyIHNlIGV2aWRlbmNpYSBsYSByZXBldGljaW9uIGRlIGFsZ3Vub3MgdGVybWlub3MuICAKCmBgYHtyIGluY2x1ZGU9RkFMU0V9CiMgR3JhZmljbyBkZSBiYXJyYXMgcGFyYSB0ZXJtaW5vcyBtYXMgY29tdW5lcyBwb3IgY2x1c3Rlcgpmb3IgKGkgaW4gMTpvcHRpbWFsX2spIHsKICB0ZXJtcyA8LSBjb2xuYW1lcyh0ZmlkZilbb3JkZXIoa21lYW5zX21vZGVsJGNlbnRlcnNbaSwgXSwgZGVjcmVhc2luZyA9IFRSVUUpWzE6NV1dCiAgYmFycGxvdChrbWVhbnNfbW9kZWwkY2VudGVyc1tpLCBdLCAKICAgICAgICAgIG1haW4gPSBwYXN0ZSgiVG9wIFRlcm1zIGZvciBDbHVzdGVyIiwgaSksIAogICAgICAgICAgY29sID0gInNreWJsdWUiLCBsYXMgPSAyKQp9CmBgYAoKCkZpbmFsbWVudGUgY29tbyBwYXJ0ZSBkZWwgZWplcmNpY2lvIGRlIGNsYXNpZmljYWNpb24gZGUgdGV4dG9zLCBzZSBwcmVzZW50YW4gYWxndW5hcyBudWJlcyBkZSBwYWxhYnJhcyBvIHdvcmRjbG91ZCwgZXN0byBjb24gZWwgZmluIGRlIHZpc2liaWxpemFyIGFxdWVsbG9zIHRlcm1pbm9zIG1hcyBjb211bmVzIGVuIGFsZ3Vub3MgZGUgbG9zIGNsdXN0ZXIuIFBhcmEgbGxldmFyIGEgY2FibyBlc3RvcyBncmFmaWNvcyBzZSBjcmVhIHVuYSBmdW5jaW9uIHF1ZSBpdGVyYSBlbiBlbCBudW1lcm8gZGUgay1vcHRpbW8sIGVzdG8gZXMgMSBhIDEwMC4gUG9yIHRlcm1pbm9zIGRlIHByYWN0aWNpZGFkIHNlIHByZXNlbnRhIHVuIGVqZW1wbG8gZGUgbnViZSBkZSBwYWxhYnJhcyBwYXJhIHVuIGNsdXN0ZXIgcXVlIHJldW5lIGFic3RyYWN0IHF1ZSB0aWVuZW4gZW4gY29tdW4gbG9zIHRlcm1pbm9zIHF1ZSBhbGxpIHNlIG11ZXN0cmFuLiAKCmBgYHtyfQoKd29yZGNsb3VkKHdvcmRzID0gdGZpZGZbWyJkaW1uYW1lcyJdXVtbIlRlcm1zIl1dLAogICAgICAgICAgICBmcmVxID0gYXMudmVjdG9yKHRmaWRmW2NsdXN0ZXJfYXNzaWdubWVudHMgPT0gMiwgXSksCiAgICAgICAgICAgIG1pbi5mcmVxID0gMSwKICAgICAgICAgICAgc2NhbGUgPSBjKDMsIDAuNSksCiAgICAgICAgICAgIGNvbG9ycyA9IGJyZXdlci5wYWwoOCwgIkRhcmsyIiksCiAgICAgICAgICAgIG1haW4gPSBwYXN0ZSgiQ2x1c3RlciIsIGkpKQpgYGAKCiMgNS4gQ29uY2x1c2lvbmVzCgpDb21vIHBhcnRlIGRlbCBlamVyY2ljaW8gZGUgY2xhc2lmaWNhY2lvbiBkZSB0ZXh0b3MgbWVkaWFudGUgdW4gYWxnb3JpdG1vIG5vIHN1cGVydmlzYWRvLCBlcyBpbXBvcnRhbnRlIG1lbmNpb25hciBsYSBwcmFjdGljaWRhZCBxdWUgdGllbmUgZXN0ZSB5IGVsIGNvbW8gZWwgdGVuZXIgdW4gY29ycHVzIGRlIGdyYW4gdGFtYcOxbyBwZXJtaXRlIHRlbmVyIG1lam9yZXMgcmVzdWx0YWRvcy4gVGFtYmllbiBlcyBpbXBvcnRhbnRlIG1lbmNpb25hciBxdWUgcHVlZGUgaGFjZXJzZSB1c28gZGUgb3Ryb3MgYWxnb3JpdG1vcyBkZSBjbGFzaWZpY2FjaW9uIG1hcyBwcmVjaXNvcy4gCgpFcyByZWx2YW50ZSBtZW5jaW9uYXIgcXVlIHBhcmEgdGVuZXIgdW5hIGNsYXNpZmljYWNpb24gbWFzIHByZWNpc2EsIG5vIHNvbG8gcmVxdWllcmUgdW4gYWxnb3JpdG1vIGRlIGNsYXNpZmljYWNpb24gc2lubyBxdWUgc2VyaWEgZGUgZ3JhbiB1dGlsaWRhZCB0ZW5lciB1bmEgY2xhc2lmaWNhY2lvbiBwcmV2aWEgInRvcGljcyIsIGVzdG8gY29uIGVsIGZpbiBkZSB0ZW5lciB1bmEgZnVlbnRlIGRlIGVudHJhZGEgcXVlIG5vcyBwZXJtaXRhIGRlZmluaXIgY29uIG1heW9yIGNsYXJpZGFkIGVsIG51bWVybyBkZSBjbHVzdGVyIHkgbG9zIHRlcm1pbm9zIGNvbXVuZXMgcXVlIHNlIHZhbiBhIGFzb2NpYXIgYSBjYWRhIGdydXBvIGVzdG8gYXl1ZGFyaWEgYSB0ZW5lciB1bmEgY2xhc2lmaWNhY2lvbiBtYXMgcHJlY2lzYS4gCgog