2. Navegar la estructura HTML con rvest
Existen varias funciones de rvest para navegar sobre HTML. Veamos algunas de ellas sobre el ejemplo de la clase pasada.
library(rvest)
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
method from
print.tbl_lazy
print.tbl_sql
-- Attaching packages ------------------------------------------ tidyverse 1.3.1 --
v ggplot2 3.3.5 v purrr 0.3.4
v tibble 3.1.3 v dplyr 1.0.7
v tidyr 1.1.3 v stringr 1.4.0
v readr 2.0.0 v forcats 0.5.1
-- Conflicts --------------------------------------------- tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x readr::guess_encoding() masks rvest::guess_encoding()
x dplyr::lag() masks stats::lag()
url <- "https://www.york.ac.uk/teaching/cws/wws/webpage1.html"
html <- url %>% read_html()
- Un primer método es el uso de la función html_children(), la cual toma un nodo y nos devuelve sus hijos, que son de la clase xml_nodeset.
html %>% html_children()
{xml_nodeset (1)}
[1] <body><hmtl><title>webpage1</title>\n<table width="75%" align="center"><tr>\ ...
Si a este conjunto de nodos intentamos convertirlos automáticamente a texto, obtendremos el siguiente resultado.
html %>% html_children() %>% html_text()
[1] "webpage1\nSTARTING . . . \n\n\nThere are lots of ways to create web pages using already coded programmes. These lessons will teach you how to use the underlying HyperText Markup Language - HTML. \nHTML isn't computer code, but is a language that uses US English to enable texts (words, images, sounds) to be inserted and formatting such as colo(u)r and centre/ering to be written in. The process is fairly simple; the main difficulties often lie in small mistakes - if you slip up while word processing your reader may pick up your typos, but the page will still be legible. However, if your HTML is inaccurate the page may not appear - writing web pages is, at the least, very good practice for proof reading!\n\nLearning HTML will enable you to:\ncreate your own simple pages\nread and appreciate pages created by others\ndevelop an understanding of the creative and literary implications of web-texts\nhave the confidence to branch out into more complex web design \nA HTML web page is made up of tags. Tags are placed in brackets like this < tag > . A tag tells the browser how to display information. Most tags need to be opened < tag > and closed < /tag >.\n\n To make a simple web page you need to know only four tags:\n< HTML > tells the browser your page is written in HTML format\n< HEAD > this is a kind of preface of vital information that doesn't appear on the screen. \n< TITLE >Write the title of the web page here - this is the information that viewers see on the upper bar of their screen. (I've given this page the title 'webpage1').\n< BODY >This is where you put the content of your page, the words and pictures that people read on the screen. \nAll these tags need to be closed.\n\nEXERCISE\n\nWrite a simple web page.\n Copy out exactly the HTML below, using a WP program such as Notepad.\nInformation in italics indicates where you can insert your own text, other information is HTML and needs to be exact. However, make sure there are no spaces between the tag brackets and the text inside.\n(Find Notepad by going to the START menu\\ PROGRAMS\\ ACCESSORIES\\ NOTEPAD). \n\n< HTML >< HEAD >< TITLE > title of page< /TITLE >< /HEAD >< BODY> write what you like here: 'my first web page', or a piece about what you are reading, or a few thoughts on the course, or copy out a few words from a book or cornflake packet. Just type in your words using no extras such as bold, or italics, as these have special HTML tags, although you may use upper and lower case letters and single spaces. < /BODY >< /HTML >Save the file as 'first.html' (ie. call the file anything at all) It's useful if you start a folder - just as you would for word-processing - and call it something like WEBPAGES, and put your first.html file in the folder.\n\nNOW - open your browser.\nOn Netscape the process is: \nTop menu; FILE\\ OPEN PAGE\\ CHOOSE FILE \nClick on your WEBPAGES folder\\ FIRST file\nClick 'open' and your page should appear.\nOn Internet Explorer: \nTop menu; FILE\\ OPEN\\ BROWSE \nClick on your WEBPAGES folder\\ FIRST file\nClick 'open' and your page should appear.If the page doesn't open, go back over your notepad typing and make sure that all the HTML tags are correct. Check there are no spaces between tags and internal text; check that all tags are closed; check that you haven't written < HTLM > or < BDDY >. Your page will work eventually. \n\nMake another page. Call it somethingdifferent.html and place it in the same WEBPAGES folder as detailed above.\nstart formatting in lesson two\nback to wws index \n\n \n \n\n\n\n\n"
Como se puede notar, al usar html_text se obtiene el texto de todas las etiquetas en el conjunto de nodos utilizado.
- Otra forma de navegar es el uso de selectores a través de las funciones html_nodes y html_node. Mientras html_nodes devuelve todos los nodos del selector escogido, html_node devuelve solo el primero que encuentre. Así, el argumento que necesitan estas funciones para realizar su trabajo es un selector. Un selector no es más que una cadena de texto que especifica un camino que se debe recorrer en el árbol HTML para llegar al objeto que estamos buscando. Cabe notar que estos selectores siguen una sintaxis específica. Intentemos obtener solo el texto de los nodos p (párrafos).
html %>% html_nodes("p") %>% html_text()
[1] "There are lots of ways to create web pages using already coded programmes. These lessons will teach you how to use the underlying HyperText Markup Language - HTML. \n"
[2] "HTML isn't computer code, but is a language that uses US English to enable texts (words, images, sounds) to be inserted and formatting such as colo(u)r and centre/ering to be written in. The process is fairly simple; the main difficulties often lie in small mistakes - if you slip up while word processing your reader may pick up your typos, but the page will still be legible. However, if your HTML is inaccurate the page may not appear - writing web pages is, at the least, very good practice for proof reading!"
[3] "Learning HTML will enable you to:\n"
[4] "A HTML web page is made up of tags. Tags are placed in brackets like this < tag > . A tag tells the browser how to display information. Most tags need to be opened < tag > and closed < /tag >.\n\n"
[5] " To make a simple web page you need to know only four tags:\n"
[6] "All these tags need to be closed.\n\n"
[7] "Write a simple web page."
[8] " Copy out exactly the HTML below, using a WP program such as Notepad.\nInformation in italics indicates where you can insert your own text, other information is HTML and needs to be exact. However, make sure there are no spaces between the tag brackets and the text inside.\n(Find Notepad by going to the START menu\\ PROGRAMS\\ ACCESSORIES\\ NOTEPAD). \n"
[9] "\n< HTML >< HEAD >< TITLE > title of page< /TITLE >< /HEAD >< BODY> write what you like here: 'my first web page', or a piece about what you are reading, or a few thoughts on the course, or copy out a few words from a book or cornflake packet. Just type in your words using no extras such as bold, or italics, as these have special HTML tags, although you may use upper and lower case letters and single spaces. < /BODY >< /HTML >"
[10] "Save the file as 'first.html' (ie. call the file anything at all) It's useful if you start a folder - just as you would for word-processing - and call it something like WEBPAGES, and put your first.html file in the folder.\n\n"
[11] "NOW - open your browser.\nOn Netscape the process is: \nTop menu; FILE\\ OPEN PAGE\\ CHOOSE FILE \nClick on your WEBPAGES folder\\ FIRST file\nClick 'open' and your page should appear.\n"
[12] "On Internet Explorer: \nTop menu; FILE\\ OPEN\\ BROWSE \nClick on your WEBPAGES folder\\ FIRST file\nClick 'open' and your page should appear."
[13] "If the page doesn't open, go back over your notepad typing and make sure that all the HTML tags are correct. Check there are no spaces between tags and internal text; check that all tags are closed; check that you haven't written < HTLM > or < BDDY >. Your page will work eventually. \n"
[14] "\nMake another page. Call it somethingdifferent.html and place it in the same WEBPAGES folder as detailed above.\n"
[15] "start formatting in lesson two\nback to wws index "
Notemos que al usar solo p, se obtuvieron todos los elementos de este tipo en todo el documento, para navegar a un nodo específico, tendremos que detallar más el selector, lo cual lo podemos lograr a través de la opción inspeccionar que tienen casi todos los navegadores existentes, o través de extensiones como SelectorGadget en Google Chrome.
- Finalmente, una vez que naveguemos a los selectores deseados, podemos obtener atributos específicos de ellos, como hipervínculos a través de la función html_attr. Esta necesita como argumento el atributo que deseamos extraer. Si usamos la función html_attrs, esta nos devolverá todos los atributos del nodo seleccionado como un vector.
html %>% html_nodes("table p") %>% pluck(15) %>% html_node("a") %>% html_attrs()
href
"webpage2.html"
html %>% html_nodes("table p") %>% pluck(15) %>% html_node("a") %>% html_attr("href")
[1] "webpage2.html"
LS0tDQp0aXRsZTogIldlYiBTY3JhcHBpbmcgY29uIFIiDQpzdWJ0aXRsZTogJ0NhcMOtdHVsbyAzOiBOYXZlZ2FyIEhUTUwnDQphdXRob3I6IEh1Z28gUG9ycmFzDQpvdXRwdXQ6IA0KICBodG1sX25vdGVib29rOg0KICAgIGNzczogRXN0aWxvcy5jc3MNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZGVwdGg6IDINCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IHRydWUNCiAgICAgIHNtb290aF9zY3JvbGw6IGZhbHNlDQpiaWJsaW9ncmFwaHk6IEJpYmxpb2dyYWZpYS5iaWINCmNzbDogY2VwYWwueG1sDQotLS0NCg0KIyAqKjEuIFJlZ2xhcyBiw6FzaWNhcyBkZSBsYSBuYXZlZ2FjacOzbiBIVE1MKioNCg0KIVtdKGh0dHBzOi8vbGgzLmdvb2dsZXVzZXJjb250ZW50LmNvbS9wcm94eS9lWnozS1hMVTVuMXVBTkY3dGJpQV9LR1ZEV25QM3RUY1E1QWY0U3FqbzlrQm5nNTF0X3g4NVBYTDBlYUNqdEJXcUpnQmVKdGlyUkJZZFpsVFNNeVVUSF92WmljS0cyeTU2NnhCYXRQcFVKSWIzUU81T19MT0lxNFB0VVFPcExmQVdPaE13ekFOQm9zX2VSSTc1dEo4a2tzdjczdHpTQmhtUnZtWmg4T0xVTjBQdVhpWGVGMDBaM3pDS0w4bHA3Z2wwVUhCMHZTbU44MzhieXcteFlCTUtpMHFGeWJaTGcpDQoNCkVuIGVzdGUgY2Fww610dWxvIGFuYWxpemFyZW1vcyBhbGd1bmFzIHJlZ2xhcyBkZSBuYXZlZ2FjacOzbiBlbiBIVE1MIHkgY8OzbW8gc2NyYXBlYXIgdW5hIHRhYmxhLg0KDQorICoqSFRNTCBmdW5jaW9uYSBjb21vIHVuIMOhcmJvbCoqOiBEYWRhIHN1IG5hdHVyYWxlemEgamVyw6FycXVpY2EsIGxhIGZvcm1hIGVuIHF1ZSBzZSB1YmljYW4gbG9zIGRhdG9zIGRlbnRybyBkZWwgY8OzZGlnbyBIVE1MLCBlcyBlbiBsYSBkZSB1biDDoXJib2wgaW52ZXJ0aWRvLiBFbCBub2RvIHJhw616IGRlIGVzdGUgw6FyYm9sIHNpZW1wcmUgZXMgbGEgZXRpcXVldGEgSFRNTCB5IGRlIGFsbMOtIHNhbGRyYW4gcmFtYXMgcXVlIG5vcyBkaXJpZ2VuIGEgb3Ryb3Mgbm9kb3MsIGNvbm9jaWRvcyBlbiBIVE1MIGNvbW8gaGlqb3MgbyAqKmNoaWxkcmVuKiouDQoNCiFbXShodHRwczovL3d3dy5yZXNlYXJjaGdhdGUubmV0L3Byb2ZpbGUvQW50YW5hcy1DZW55cy9wdWJsaWNhdGlvbi8yNjY2MDk2MDkvZmlndXJlL2ZpZzMvQVM6NjY4OTE1NzMwNDk3NTM5QDE1MzY0OTMzNDYyMzAvSFRNTC1zb3VyY2UtY29kZS1vbi1sZWZ0LXNob3duLWFzLWEtdHJlZS1zdHJ1Y3R1cmUtb24tcmlnaHQucG5nKQ0KDQorIExhcyBldGlxdWV0YXMgcXVlIHNlIGVuY3VlbnRyYW4gYWwgbWlzbW8gbml2ZWwgeSBxdWUgc29uIGhpamFzIGRlIGxhIG1pc21hIGV0aXF1ZXRhIHNvbiBwYXJpZW50ZXMgbyAqKnNpYmxpbmdzKiouDQorIEVsIGhpam8gZGUgbGEgZXRpcXVldGEgVElUTEUgZXMgdW4gdGV4dG86IEdvb2dsZS4gRXN0YSBzZSBkZW5vbWluYSBjb21vIGhvamEsICoqbm9kbyBkZSB0ZXh0KiogbyAqKmxlYWYqKiwgZGFkbyBxdWUgbm8gZXMgZXRpcXVldGEgeSB0aWVuZSB0ZXh0by4gU1RZTEUgZXMgdMOpY25pY2FtZW50ZSBzdSBoZXJtYW5hLCBwZXJvIG5vIGVzIHVuYSBob2phLCBkYWRvIHF1ZSBkZW50cm8gZGUgc8OtIHRpZW5lIGV0aXF1ZXRhcy4NCg0KIyAqKjIuIE5hdmVnYXIgbGEgZXN0cnVjdHVyYSBIVE1MIGNvbiBydmVzdCoqDQoNCkV4aXN0ZW4gdmFyaWFzIGZ1bmNpb25lcyBkZSBydmVzdCBwYXJhIG5hdmVnYXIgc29icmUgSFRNTC4gVmVhbW9zIGFsZ3VuYXMgZGUgZWxsYXMgc29icmUgZWwgZWplbXBsbyBkZSBsYSBjbGFzZSBwYXNhZGEuDQoNCmBgYHtyfQ0KbGlicmFyeShydmVzdCkNCmxpYnJhcnkodGlkeXZlcnNlKQ0KdXJsIDwtICJodHRwczovL3d3dy55b3JrLmFjLnVrL3RlYWNoaW5nL2N3cy93d3Mvd2VicGFnZTEuaHRtbCINCmh0bWwgPC0gdXJsICU+JSByZWFkX2h0bWwoKQ0KYGBgDQoNCisgVW4gcHJpbWVyIG3DqXRvZG8gZXMgZWwgdXNvIGRlIGxhIGZ1bmNpw7NuICoqaHRtbF9jaGlsZHJlbigpKiosIGxhIGN1YWwgdG9tYSB1biBub2RvIHkgbm9zIGRldnVlbHZlIHN1cyBoaWpvcywgcXVlIHNvbiBkZSBsYSBjbGFzZSB4bWxfbm9kZXNldC4NCg0KYGBge3J9DQpodG1sICU+JSBodG1sX2NoaWxkcmVuKCkNCmBgYA0KU2kgYSBlc3RlIGNvbmp1bnRvIGRlIG5vZG9zIGludGVudGFtb3MgY29udmVydGlybG9zIGF1dG9tw6F0aWNhbWVudGUgYSB0ZXh0bywgb2J0ZW5kcmVtb3MgZWwgc2lndWllbnRlIHJlc3VsdGFkby4NCg0KYGBge3J9DQpodG1sICU+JSBodG1sX2NoaWxkcmVuKCkgJT4lIGh0bWxfdGV4dCgpDQpgYGANCg0KQ29tbyBzZSBwdWVkZSBub3RhciwgYWwgdXNhciAqKmh0bWxfdGV4dCoqIHNlIG9idGllbmUgZWwgdGV4dG8gZGUgdG9kYXMgbGFzIGV0aXF1ZXRhcyBlbiBlbCBjb25qdW50byBkZSBub2RvcyB1dGlsaXphZG8uDQoNCisgT3RyYSBmb3JtYSBkZSBuYXZlZ2FyIGVzIGVsIHVzbyBkZSAqKnNlbGVjdG9yZXMqKiBhIHRyYXbDqXMgZGUgbGFzIGZ1bmNpb25lcyAqKmh0bWxfbm9kZXMqKiB5ICoqaHRtbF9ub2RlKiouIE1pZW50cmFzICoqaHRtbF9ub2RlcyoqIGRldnVlbHZlIHRvZG9zIGxvcyBub2RvcyBkZWwgc2VsZWN0b3IgZXNjb2dpZG8sICoqaHRtbF9ub2RlKiogZGV2dWVsdmUgc29sbyBlbCBwcmltZXJvIHF1ZSBlbmN1ZW50cmUuIEFzw60sIGVsIGFyZ3VtZW50byBxdWUgbmVjZXNpdGFuIGVzdGFzIGZ1bmNpb25lcyBwYXJhIHJlYWxpemFyIHN1IHRyYWJham8gZXMgdW4gKipzZWxlY3RvcioqLiBVbiBzZWxlY3RvciBubyBlcyBtw6FzIHF1ZSB1bmEgKipjYWRlbmEgZGUgdGV4dG8qKiBxdWUgKiplc3BlY2lmaWNhIHVuIGNhbWlubyBxdWUgc2UgZGViZSByZWNvcnJlciBlbiBlbCDDoXJib2wgSFRNTCoqIHBhcmEgbGxlZ2FyIGFsIG9iamV0byBxdWUgZXN0YW1vcyBidXNjYW5kby4gQ2FiZSBub3RhciBxdWUgZXN0b3Mgc2VsZWN0b3JlcyBzaWd1ZW4gdW5hICoqc2ludGF4aXMgZXNwZWPDrWZpY2EqKi4gSW50ZW50ZW1vcyBvYnRlbmVyIHNvbG8gZWwgdGV4dG8gZGUgbG9zIG5vZG9zICoqcCoqIChww6FycmFmb3MpLg0KDQpgYGB7cn0NCmh0bWwgJT4lIGh0bWxfbm9kZXMoInAiKSAlPiUgaHRtbF90ZXh0KCkNCmBgYA0KDQpOb3RlbW9zIHF1ZSBhbCB1c2FyIHNvbG8gKipwKiosIHNlIG9idHV2aWVyb24gdG9kb3MgbG9zIGVsZW1lbnRvcyBkZSBlc3RlIHRpcG8gZW4gdG9kbyBlbCBkb2N1bWVudG8sIHBhcmEgbmF2ZWdhciBhIHVuIG5vZG8gZXNwZWPDrWZpY28sIHRlbmRyZW1vcyBxdWUgZGV0YWxsYXIgbcOhcyBlbCBzZWxlY3RvciwgbG8gY3VhbCBsbyBwb2RlbW9zIGxvZ3JhciBhIHRyYXbDqXMgZGUgbGEgb3BjacOzbiAqKmluc3BlY2Npb25hcioqIHF1ZSB0aWVuZW4gY2FzaSB0b2RvcyBsb3MgbmF2ZWdhZG9yZXMgZXhpc3RlbnRlcywgbyB0cmF2w6lzIGRlIGV4dGVuc2lvbmVzIGNvbW8gKipTZWxlY3RvckdhZGdldCoqIGVuIEdvb2dsZSBDaHJvbWUuDQoNCisgRmluYWxtZW50ZSwgdW5hIHZleiBxdWUgbmF2ZWd1ZW1vcyBhIGxvcyBzZWxlY3RvcmVzIGRlc2VhZG9zLCBwb2RlbW9zIG9idGVuZXIgYXRyaWJ1dG9zIGVzcGVjw61maWNvcyBkZSBlbGxvcywgY29tbyBoaXBlcnbDrW5jdWxvcyBhIHRyYXbDqXMgZGUgbGEgZnVuY2nDs24gKipodG1sX2F0dHIqKi4gRXN0YSBuZWNlc2l0YSBjb21vIGFyZ3VtZW50byBlbCBhdHJpYnV0byBxdWUgZGVzZWFtb3MgZXh0cmFlci4gU2kgdXNhbW9zIGxhIGZ1bmNpw7NuICoqaHRtbF9hdHRycyoqLCBlc3RhIG5vcyBkZXZvbHZlcsOhIHRvZG9zIGxvcyBhdHJpYnV0b3MgZGVsIG5vZG8gc2VsZWNjaW9uYWRvIGNvbW8gdW4gdmVjdG9yLiANCg0KYGBge3J9DQpodG1sICU+JSBodG1sX25vZGVzKCJ0YWJsZSBwIikgJT4lIHBsdWNrKDE1KSAlPiUgaHRtbF9ub2RlKCJhIikgJT4lIGh0bWxfYXR0cnMoKQ0KYGBgDQoNCmBgYHtyfQ0KaHRtbCAlPiUgaHRtbF9ub2RlcygidGFibGUgcCIpICU+JSBwbHVjaygxNSkgJT4lIGh0bWxfbm9kZSgiYSIpICU+JSBodG1sX2F0dHIoImhyZWYiKQ0KYGBgDQoNCiMgKiozLiBFeHRyYWNjacOzbiBkZSB0YWJsYXMgY29uIHJ2ZXN0KioNCg0KIVtdKGh0dHBzOi8vY2RuLnR0Yy5pby9pL2ZpdC8xMDM1LzAvc20vMC9wbGFpbi9leHBvc2luZ3RoZWludmlzaWJsZS5vcmcvY2tlZGl0b3JfYXNzZXRzL3BpY3R1cmVzLzY0Ny9jb250ZW50X2NzLXdlYi1zY3JhcGluZy1lbi12MDEtMDEwLWV4cGFuZGVkLXBhbmUucG5nKQ0KDQpIYXN0YSBhaG9yYSBzYWJlbW9zIGPDs21vIG9idGVuZXIgbGEgZ3JhbiBtYXlvcsOtYSBkZSBlbGVtZW50b3MgcXVlIHNlIGVuY3VlbnRyYW4gZW4gdW4gZG9jdW1lbnRvIEhUTUwuIEFzw60sIHZlcmVtb3MgYSBjb250aW51YWNpw7NuIHVuIGNhc28gZXNwZWNpYWw6IHRhYmxhcy4NCg0KRW4gc3UgZm9ybWEgbcOhcyBzZW5jaWxsYSwgdW5hIHRhYmxhIGNvbnNpc3RlIGRlIHRyZXMgZXRpcXVldGFzIEhUTUwgZGlzdGludGFzOiAqKnRhYmxlKiosICoqdHIqKiB5ICoqdGQqKi4gTGEgZXRpcXVldGEgKip0YWJsZSoqIGRlc2lnbmEgdW5hIHRhYmxhLCBsYSBldGlxdWV0YSAqKnRyKiogZGVzaWduYSBmaWxhcyB5IGVuY2llcnJhcyB2YXJpYXMgZXRpcXVldGFzICoqdGQqKiwgbGFzIGN1YWxlcyBkZXNpZ25hbiBjZWxkYXMuIE5vcm1hbG1lbnRlIGVsIG7Dum1lcm8gZGUgKip0ZCoqIGRlbnRybyBkZSBsYXMgKip0cioqIGRlYmUgc2VyIGVsIG1pc21vOyBzaW4gZW1iYXJnbywgcHVlZGUgdXRpbGl6YXJzZSBlbCBhdHJpYnV0byAqKmNvbHNwYW4qKiBlbiBsYXMgZXRpcXVldGFzICoqdGQqKiwgcGVybWl0aWVuZG8gcXVlIHVuYSBjZWxkYSBzZSBleHRpZW5kYSBwb3IgdmFyaWFzIGNvbHVtbmFzLg0KDQohW10oaHR0cHM6Ly9mbGF2aW9jb3Blcy5jb20vaHRtbC10YWJsZXMvbm8tc3R5bGluZy5wbmcpDQoNCkNvbW8gc2UgcHVlZGUgbm90YXIgZW4gbGEgZ3LDoWZpY2EsIGV4aXN0ZW4gdmFyaWFzIG90cmFzIGV0aXF1ZXRhcyBxdWUgc2UgcHVlZGVuIHV0aWxpemFyIHBhcmEgZXN0cnVjdHVyYXIgdW5hIHRhYmxhLCB0YWwgY29tbyBsYSBldGlxdWV0YSAqKnRoKiosIGxhIGN1YWwgbm9zIHBlcm1pdGUgY29sb2NhciB1bmEgZmlsYSBjb21vIGVuY2FiZXphZG8uIFRhYmxhcyBxdWUgdGllbmVuIGVzdGEgZmlsYSBzb24gbcOhcyBmw6FjaWxlcyBkZSBzY3JhcGVhci4NCg0KUGFyYSBzY3JhcGVhciB1bmEgdGFibGEgdXNhbmRvIHJ2ZXN0LCB1c2FyZW1vcyBsYSBmdW5jacOzbiAqKmh0bWxfdGFibGUqKiAoYXBvecOhbmRvbm9zIGVuIGxhIGhlcnJhbWllbnRhIGluc3BlY2Npb25hciksIHRvbWFuZG8gY29tbyBlamVtcGxvIGxhIHDDoWdpbmEgZGUgd2lraXBlZGlhIHF1ZSBub3MgbXVlc3RyYSBsYSBkaXNjb2dyYWbDrWEgZGUgbGEgYmFuZGEgZGUgcm9jayBhbHRlcm5hdGl2byAqKltNdXNlXShodHRwczovL2VzLndpa2lwZWRpYS5vcmcvd2lraS9NdXNlKSoqOg0KDQpgYGB7cn0NCmh0bWwgPC0gcmVhZF9odG1sKCJodHRwczovL2VzLndpa2lwZWRpYS5vcmcvd2lraS9BbmV4bzpEaXNjb2dyYWYlQzMlQURhX2RlX011c2UiKQ0KaHRtbCAlPiUgaHRtbF9ub2RlKCIjbXctY29udGVudC10ZXh0ID4gZGl2Lm13LXBhcnNlci1vdXRwdXQgPiBjZW50ZXI6bnRoLWNoaWxkKDkpID4gdGFibGUiKSAlPiUgaHRtbF90YWJsZSgpDQpgYGANCg0KQ29tbyBzZSBwdWVkZSBub3RhciwgZXN0YSBmdW5jacOzbiB0cmFuc2Zvcm1hIGEgbG9zIGRhdG9zIGVuIHVuIHRpYmJsZSAob2JqZXRvIHF1ZSBhbG1hY2VuYSB1bmEgdGFibGEgZGUgZGF0b3MsIHByb3BpYSBkZWwgdGlkeXZlcnNlKS4gUG9yIG90cm8gbGFkbywgZGljaGEgZnVuY2nDs24gdGVuZHLDoSB1biBtZWpvciByZXN1bHRhZG8gYSBtZWRpZGEgcXVlIG1lam9yIGVzdHJ1Y3R1cmFkb3MgZXN0w6luIGxvcyBkYXRvcy4gTGEgZnVuY2nDs24gKipodG1sX3RhYmxlKiogdGllbmUgbG9zIGFyZ3VtZW50b3MgKipoZWFkZXIqKiB5ICoqZmlsbCoqIHF1ZSBub3Mgc2lydmVuIHBhcmEgZXNwZWNpZmljYXIgcXVlIGxhIHByaW1lcmEgZmlsYSBlcyB1biBlbmNhYmV6YWRvIChzaSBubyBleGlzdGVuIGV0aXF1ZXRhcyAqKnRoKiopIHkgcGFyYSByZWxsZW5hciBjZWxkYXMgdmFjw61hcy4NCg0KRW4gZWwgc2lndWllbnRlIGNhcMOtdHVsbyB2ZXJlbW9zIGxvcyB0aXBvcyBkZSBzZWxlY3RvcmVzIGV4aXN0ZW50ZXMgeSBhbGd1bmFzIGRlIHN1cyB1dGlsaWRhZGVzLg0KDQo=