This guide will explain how to visualize key themes from a Google
Scholar profile using a WordCloud. This tutorial is designed to be
accessible to users with only a basic understanding of R programming
language.
(The entire code for this tutorial is consolidated into a single
function and presented at the end of this document. If you’re only
interested in generating the wordcloud, and don’t care about the
procedure, feel free to skip to the end of this document.”)
Load abstracts from Google Scholar
First, we need to specify a Google Scholar profile using a
researcher’s name. To do this, assign an author’s first and last name to
the objects “FirstName” and “LastName” (respectfully). For the purposes
of this tutorial, I’ll use my own name.
FirstName<-"Zak"
LastName<-"Witkower"
Next, retrieve all items indexed by Google Scholar (e.g.,
publications) for the specified researcher, using the scholar
library.
library(scholar)
library(tibble) #for data cleaning
# Retrieve unique Google Scholar identifier using first and last name objects created above.
IDnumber<-get_scholar_id(first_name = FirstName,
last_name = LastName)
# Generate list of articles indexed in Google Scholar
Mypublications<-tibble(get_publications(IDnumber))
The resulting dataframe is in wide form, with each row
representing a unique item indexed by Google Scholar for the specified
researcher, and each column representing a different variable or
attribute (e.g., title, journal name, number of citations, etc).
## # A tibble: 10 × 8
## title author journal number cites year cid pubid
## <chr> <chr> <chr> <chr> <dbl> <dbl> <chr> <chr>
## 1 Two signals of social rank: Pr… Z Wit… Journa… 118 (… 148 2020 1283… qjMa…
## 2 Bodily communication of emotio… Z Wit… Emotio… 11 (2… 125 2019 1582… UeHW…
## 3 Predicting cyberbullying perpe… C Bar… Aggres… 43 (2… 102 2017 5427… 2osO…
## 4 The evolution of pride and soc… JL Tr… Advanc… 62, 5… 85 2020 7726… hqOj…
## 5 A facial-action imposter: How … Z Wit… Psycho… 30 (6… 47 2019 3325… W7OE…
## 6 The psychological structure, s… E Mer… Curren… 39, 1… 39 2021 8498… ULOm…
## 7 How affect shapes status: Dist… Z Wit… Curren… 33, 1… 37 2020 1574… YsMS…
## 8 Breaking the link between prov… C Bar… Aggres… 42 (6… 19 2016 5389… 9yKS…
## 9 Evidence for distinct facial s… JD Ma… Affect… 2, 14… 18 2021 1827… KlAt…
## 10 Beyond face value: Evidence fo… Z Wit… Affect… 2 (3)… 17 2021 1677… _kc_…
Next we will to retrieve the abstracts for each publication using a
loop, and append each abstract to our dataframe.
# initialize new column to be filled with abstracts
Mypublications$abstract<-rep("initialize", nrow(Mypublications))
#"for" loop to add abstract for each publication
for (i in 1:nrow(Mypublications)) {
Abstracts <- get_publication_abstract(id = IDnumber,
pub_id = Mypublications$pubid[i])
#This is included to mitigate "replacement has length zero" error, in case there is an issue finding a file
ifelse(length(Abstracts) == 0, NA, Mypublications$abstract[i] <- Abstracts)
}
Create wordcloud
Finally, lets create a wordcloud.
(Note: You can adjust the aesthetics of the wordcloud using the
code below.)
library(wordcloud2)
library(randomcoloR)
#create wordcloud
wordcloud2(tidy.TDM,
color = randomColor(nrow(tidy.TDM), #create color palette with randomcoloR
hue = "random",
luminosity = "dark"),
fontWeight = "bold", #bold all items
rotate = 0, #max rotation of words within wordcloud
size=.75, #size of wordcloud
fontFamily = "Times") #font of wordcloud
Limitations
If the specified author includes their middle initial in their Google
Scholar profile, or has three names, you may encounter problems
generating their wordcloud. There are a few possible solutions:
* Input their first and last name exclusively (e.g., input “Jessica L.
Tracy” as “Jessica Tracy”, or “Gerben van Kleef” as “Gerben
Kleef”)
* Input their first and middle initials as their first name (e.g., input
“Friedrich M. Götz” as “FM Götz”)
* If all else fails, you can retrieve a researcher’s Google Scholar ID
manually from the hyperlink of their Google Scholar page, instead of
retrieving it based on their first and last name (i.e., the method used
here). Look for text “user=” embedded within the hyperlink, and extract
the 12 letters that follow. You can assign their ID as a character
string to the object “IDnumber”, and skip the first step of retrieving
Google Scholar IDs with the “get_scholar_id” function
This method relies heavily on querying Google Scholar, which may
introduce some complications. For example:
* An internet connection is required
* The specified researcher must have an active Google Scholar
profile
* The method will extract all files indexed by Google Scholar for the
specified profile, which may include non-peer-reviewed files or
supplemental materials
* Rate limits imposed by Google Scholar may restrict the total number
and speed of your requests. * If you try to generate a wordcloud for a
particularly productive researcher – which requires you to request all
of the publications and abstracts of a specified author – you may exceed
Google’s rate limit (i.e., too many requests in a short period of time),
resulting in an error.
You may wish to alternatively create a wordcloud that visualizes your
research by uploading PDF files of your research saved on your local
drive. This approach, which is described in more detail on my website.
If you have any questions, comments, or concerns, please get in touch
with me. I’m happy to help! Email: Zakwitkower@gmail.com
Website: www.ZakWitkower.com
LinkedIn: Zak
Witkower
Twitter: @Zakwitkower
Wrapping everything in a function
For simplicity, I’ve consolidated all the steps into a single
function that automates the creation of a wordcloud using just your
first and last name. Enter the first and last name of the researcher
whose research you want to visualize at the top of the code chunk
(assigned to objects “FirstName” and “LastName”), and then run the rest
of the code. The function will handle all additional steps, and output a
wordcloud.
#####################################################################
####### Please input the first and last name of a researcher ########
#####################################################################
FirstName<-"Zak"
LastName<-"Witkower"
########################################################################################
#### After assigning a name above, run the rest of the code to create the function: ####
########################################################################################
#load libraries
require(scholar)
require(tibble)
require(tm)
require(tidytext)
require(tidyverse)
require(wordcloud2)
require(randomcoloR)
#Create function
GoogleScholarWordCloud<-function(first,last){
#Get ID number from name
IDnumber<-get_scholar_id(first_name = first,
last_name = last)
#Get publications
Mypublications<-tibble(get_publications(IDnumber))
#Add abstracts
Mypublications$abstract<-rep("initialize", nrow(Mypublications))
for (i in 1:nrow(Mypublications)) {
Abstracts <- get_publication_abstract(id = IDnumber,
pub_id = Mypublications$pubid[i])
ifelse(length(Abstracts) == 0, NA, Mypublications$abstract[i] <- Abstracts)
}
#Create Corpus
MyAbstracts.corpus<-VCorpus(VectorSource(Mypublications$abstract))
#Create TDM from corpus
MyAbstracts.TDM<-TermDocumentMatrix(MyAbstracts.corpus,
control =
list(removePunctuation = TRUE,
stopwords = TRUE,
tolower = TRUE,
stemming = F,
removeNumbers = TRUE))
#Tidy TDM
MyAbstracts.TDM<-tidy(MyAbstracts.TDM) %>%
group_by(term) %>%
summarise(count,count = sum(count)) %>%
unique()%>%
ungroup() %>%
arrange(desc(count))
#retain top 100 most frequently used words
MyAbstracts.TDM<-head(MyAbstracts.TDM, 100)
#create wordcloud
wordcloud<-wordcloud2(MyAbstracts.TDM,
fontWeight = "bold", #bold all items
rotate = 0, #max rotation of words
size=.75, #size of wordcloud
fontFamily = "Times", #font of wordcloud
color = randomColor(nrow(MyAbstracts.TDM), #create color palette
hue = "random",
luminosity = "dark"))
return(wordcloud)
}
##################################################################
### Run the function we just created, using the assigned name ###
##################################################################
GoogleScholarWordCloud(FirstName, LastName)
############################ End. ###################################
LS0tCnRpdGxlOiAiVmlzdWFsaXplIHlvdXIgR29vZ2xlIFNjaG9sYXIgcHJvZmlsZSB1c2luZyBhIHdvcmRjbG91ZCIKYXV0aG9yOiAnW1phayBXaXRrb3dlcl0oaHR0cHM6Ly93d3cuemFrd2l0a293ZXIuY29tLyknCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVCICVkICVZJylgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRoZW1lOiBsdW1lbgogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgICBoaWdobGlnaHQ6IHplbmJ1cm4KICAgIGNvZGVfZG93bmxvYWQ6IHllcwogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKLS0tCjxkaXYgY2xhc3M9InRvY2lmeS1leHRlbmQtcGFnZSIgZGF0YS11bmlxdWU9InRvY2lmeS1leHRlbmQtcGFnZSIgc3R5bGU9ImhlaWdodDogMDsiPjwvZGl2PiAKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKYGBgCgpUaGlzIGd1aWRlIHdpbGwgZXhwbGFpbiBob3cgdG8gdmlzdWFsaXplIGtleSB0aGVtZXMgZnJvbSBhIEdvb2dsZSBTY2hvbGFyIHByb2ZpbGUgdXNpbmcgYSBXb3JkQ2xvdWQuIFRoaXMgdHV0b3JpYWwgaXMgZGVzaWduZWQgdG8gYmUgYWNjZXNzaWJsZSB0byB1c2VycyB3aXRoIG9ubHkgYSBiYXNpYyB1bmRlcnN0YW5kaW5nIG9mIFIgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2UuCgooKlRoZSBlbnRpcmUgY29kZSBmb3IgdGhpcyB0dXRvcmlhbCBpcyBjb25zb2xpZGF0ZWQgaW50byBhIHNpbmdsZSBmdW5jdGlvbiBhbmQgcHJlc2VudGVkIGF0IHRoZSBlbmQgb2YgdGhpcyBkb2N1bWVudC4gSWYgeW91J3JlIG9ubHkgaW50ZXJlc3RlZCBpbiBnZW5lcmF0aW5nIHRoZSB3b3JkY2xvdWQsIGFuZCBkb24ndCBjYXJlIGFib3V0IHRoZSBwcm9jZWR1cmUsIGZlZWwgZnJlZSB0byBza2lwIHRvIHRoZSBlbmQgb2YgdGhpcyBkb2N1bWVudC4iKikKCiMgTG9hZCBhYnN0cmFjdHMgZnJvbSBHb29nbGUgU2Nob2xhcgoKRmlyc3QsIHdlIG5lZWQgdG8gc3BlY2lmeSBhIEdvb2dsZSBTY2hvbGFyIHByb2ZpbGUgdXNpbmcgYSByZXNlYXJjaGVyJ3MgbmFtZS4gVG8gZG8gdGhpcywgYXNzaWduIGFuIGF1dGhvcidzIGZpcnN0IGFuZCBsYXN0IG5hbWUgdG8gdGhlIG9iamVjdHMgIkZpcnN0TmFtZSIgYW5kICJMYXN0TmFtZSIgKHJlc3BlY3RmdWxseSkuIEZvciB0aGUgcHVycG9zZXMgb2YgdGhpcyB0dXRvcmlhbCwgSSdsbCB1c2UgbXkgb3duIG5hbWUuCgpgYGB7ciwgaW5jbHVkZT1UUlVFLHdhcm5pbmc9RiwgbWVzc2FnZT1GfQpGaXJzdE5hbWU8LSJaYWsiICAKTGFzdE5hbWU8LSJXaXRrb3dlciIKYGBgCgpOZXh0LCByZXRyaWV2ZSBhbGwgaXRlbXMgaW5kZXhlZCBieSBHb29nbGUgU2Nob2xhciAoZS5nLiwgcHVibGljYXRpb25zKSBmb3IgdGhlIHNwZWNpZmllZCByZXNlYXJjaGVyLCB1c2luZyB0aGUgWypzY2hvbGFyKl0oaHR0cHM6Ly9naXRodWIuY29tL2prZWlyc3RlYWQvc2Nob2xhcikgbGlicmFyeS4gCgpgYGB7ciwgaW5jbHVkZT1UUlVFLCByZXN1bHRzID0gInNob3ciLCB3YXJuaW5nPUYsIG1lc3NhZ2U9RiwgcGFnZWQucHJpbnQ9RkFMU0V9CmxpYnJhcnkoc2Nob2xhcikKbGlicmFyeSh0aWJibGUpICNmb3IgZGF0YSBjbGVhbmluZwoKIyBSZXRyaWV2ZSB1bmlxdWUgR29vZ2xlIFNjaG9sYXIgaWRlbnRpZmllciB1c2luZyBmaXJzdCBhbmQgbGFzdCBuYW1lIG9iamVjdHMgY3JlYXRlZCBhYm92ZS4gCklEbnVtYmVyPC1nZXRfc2Nob2xhcl9pZChmaXJzdF9uYW1lID0gRmlyc3ROYW1lLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGxhc3RfbmFtZSA9IExhc3ROYW1lKQoKIyBHZW5lcmF0ZSBsaXN0IG9mIGFydGljbGVzIGluZGV4ZWQgaW4gR29vZ2xlIFNjaG9sYXIKTXlwdWJsaWNhdGlvbnM8LXRpYmJsZShnZXRfcHVibGljYXRpb25zKElEbnVtYmVyKSkKYGBgCgpUaGUgcmVzdWx0aW5nIGRhdGFmcmFtZSBpcyBpbiAqd2lkZSogZm9ybSwgd2l0aCBlYWNoIHJvdyByZXByZXNlbnRpbmcgYSB1bmlxdWUgaXRlbSBpbmRleGVkIGJ5IEdvb2dsZSBTY2hvbGFyIGZvciB0aGUgc3BlY2lmaWVkIHJlc2VhcmNoZXIsIGFuZCBlYWNoIGNvbHVtbiByZXByZXNlbnRpbmcgYSBkaWZmZXJlbnQgdmFyaWFibGUgb3IgYXR0cmlidXRlIChlLmcuLCB0aXRsZSwgam91cm5hbCBuYW1lLCBudW1iZXIgb2YgY2l0YXRpb25zLCBldGMpLiAKCmBgYHtyLCBpbmNsdWRlPVRSVUUsIHJlc3VsdHMgPSAic2hvdyIsIHdhcm5pbmc9RiwgbWVzc2FnZT1GLCBwYWdlZC5wcmludD1GQUxTRX0KaGVhZChNeXB1YmxpY2F0aW9ucywgMTApCmBgYAoKTmV4dCB3ZSB3aWxsIHRvIHJldHJpZXZlIHRoZSBhYnN0cmFjdHMgZm9yIGVhY2ggcHVibGljYXRpb24gdXNpbmcgYSBsb29wLCBhbmQgYXBwZW5kIGVhY2ggYWJzdHJhY3QgdG8gb3VyIGRhdGFmcmFtZS4KCmBgYHtyLCBpbmNsdWRlPVRSVUUsIHJlc3VsdHMgPSAiaGlkZSIsIHdhcm5pbmc9RiwgbWVzc2FnZT1GfQoKIyBpbml0aWFsaXplIG5ldyBjb2x1bW4gdG8gYmUgZmlsbGVkIHdpdGggYWJzdHJhY3RzCk15cHVibGljYXRpb25zJGFic3RyYWN0PC1yZXAoImluaXRpYWxpemUiLCBucm93KE15cHVibGljYXRpb25zKSkKCiMiZm9yIiBsb29wIHRvIGFkZCBhYnN0cmFjdCBmb3IgZWFjaCBwdWJsaWNhdGlvbgpmb3IgKGkgaW4gMTpucm93KE15cHVibGljYXRpb25zKSkgewogIEFic3RyYWN0cyA8LSBnZXRfcHVibGljYXRpb25fYWJzdHJhY3QoaWQgPSBJRG51bWJlciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwdWJfaWQgPSBNeXB1YmxpY2F0aW9ucyRwdWJpZFtpXSkKICAKI1RoaXMgaXMgaW5jbHVkZWQgdG8gbWl0aWdhdGUgICJyZXBsYWNlbWVudCBoYXMgbGVuZ3RoIHplcm8iIGVycm9yLCBpbiBjYXNlIHRoZXJlIGlzIGFuIGlzc3VlIGZpbmRpbmcgYSBmaWxlIAogIGlmZWxzZShsZW5ndGgoQWJzdHJhY3RzKSA9PSAwLCBOQSwgTXlwdWJsaWNhdGlvbnMkYWJzdHJhY3RbaV0gPC0gQWJzdHJhY3RzKSAKfQpgYGAKCiMgVHJhbnNmb3JtIGFuZCBjbGVhbiBkYXRhCk5vdyB3ZSBhcmUgcmVhZHkgdG8gdHVybiBvdXIgZGF0YWZyYW1lIGludG8gYSBjb3JwdXMsIHdoaWNoIHdlIHdpbGwgbGF0ZXIgdXNlIHRvIGNyZWF0ZSBhIFRlcm0gRG9jdW1lbnQgTWF0cml4IChURE0pLiBBIFRETSBpcyBhIG51bWVyaWNhbCByZXByZXNlbnRhdGlvbiBvZiB0aGUgdGV4dCBkYXRhIHRoYXQgd2lsbCBhbGxvdyB1cyB0byBwZXJmb3JtIHF1YW50aXRhdGl2ZSBhbmFseXNpcyBhbmQgY3JlYXRlIGEgd29yZGNsb3VkLgoKYGBge3IsIGluY2x1ZGU9VFJVRSwgcmVzdWx0cyA9ICJoaWRlIiwgd2FybmluZz1GLCBtZXNzYWdlPUZ9CmxpYnJhcnkodG0pCmxpYnJhcnkodGlkeXRleHQpCmxpYnJhcnkodGlkeXZlcnNlKQoKI2NyZWF0ZSBjb3JwdXMgZnJvbSBhYnN0cmFjdHMKTXlBYnN0cmFjdHMuY29ycHVzPC1WQ29ycHVzKFZlY3RvclNvdXJjZShNeXB1YmxpY2F0aW9ucyRhYnN0cmFjdCkpCgojY3JlYXRlIFRlcm0gRG9jdW1lbnQgTWF0cml4IChURE0pIGZyb20gY29ycHVzCk15QWJzdHJhY3RzLlRETTwtVGVybURvY3VtZW50TWF0cml4KE15QWJzdHJhY3RzLmNvcnB1cywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyb2wgPSAgI0RhdGEgZWRpdGluZzoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaXN0KHJlbW92ZVB1bmN0dWF0aW9uID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdG9wd29yZHMgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvbG93ZXIgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RlbW1pbmcgPSBGLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbW92ZU51bWJlcnMgPSBUUlVFKSkKCmBgYAoKTGV0cyBpZGVudGlmeSB0aGUgMTAwIG1vc3QgZnJlcXVlbnRseSB1c2VkIHRlcm1zLiBJIGRvIHRoaXMgYnkgc3VtbWluZyB0aGUgZnJlcXVlbmN5IG9mIGVhY2ggdW5pcXVlIHRlcm0gYWNyb3NzIGFsbCBkb2N1bWVudHMuCgpgYGB7ciwgaW5jbHVkZT1UUlVFLCByZXN1bHRzID0gImhpZGUiLCB3YXJuaW5nPUYsIG1lc3NhZ2U9Rn0KdGlkeS5URE08LXRpZHkoTXlBYnN0cmFjdHMuVERNKSAlPiUgCiAgZ3JvdXBfYnkodGVybSkgJT4lIAogIHN1bW1hcmlzZShjb3VudCxjb3VudCA9IHN1bShjb3VudCkpICU+JSAjc3VtIGZyZXF1ZW5jeQogIHVuaXF1ZSgpJT4lIAogIHVuZ3JvdXAoKSAlPiUKICBhcnJhbmdlKGRlc2MoY291bnQpKSAjcmVhcnJhbmdlIGJhc2VkIG9uIGZyZXF1ZW5jeSBvZiB0ZXJtCgojb25seSByZXRhaW4gdGhlIHRvcCAxMDAgbW9zdCBmcmVxdWVudGx5IHVzZWQgdGVybXMKdGlkeS5URE08LWhlYWQodGlkeS5URE0sIDEwMCkgCgpoZWFkKHRpZHkuVERNKQpgYGAKCiMgQ3JlYXRlIHdvcmRjbG91ZApGaW5hbGx5LCBsZXRzIGNyZWF0ZSBhIHdvcmRjbG91ZC4KCigqTm90ZTogWW91IGNhbiBhZGp1c3QgdGhlIGFlc3RoZXRpY3Mgb2YgdGhlIHdvcmRjbG91ZCB1c2luZyB0aGUgY29kZSBiZWxvdy4qKQoKYGBge3IsIGluY2x1ZGU9VFJVRSwgd2FybmluZz1GLCBtZXNzYWdlPUZ9CmxpYnJhcnkod29yZGNsb3VkMikKbGlicmFyeShyYW5kb21jb2xvUikgCgojY3JlYXRlIHdvcmRjbG91ZAp3b3JkY2xvdWQyKHRpZHkuVERNLCAKICAgICAgICAgICBjb2xvciA9IHJhbmRvbUNvbG9yKG5yb3codGlkeS5URE0pLCAjY3JlYXRlIGNvbG9yIHBhbGV0dGUgd2l0aCByYW5kb21jb2xvUgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaHVlID0gInJhbmRvbSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbHVtaW5vc2l0eSA9ICJkYXJrIiksCiAgICAgICAgICAgZm9udFdlaWdodCA9ICJib2xkIiwgICNib2xkIGFsbCBpdGVtcwogICAgICAgICAgIHJvdGF0ZSA9IDAsICAgICAgICAgICAjbWF4IHJvdGF0aW9uIG9mIHdvcmRzIHdpdGhpbiB3b3JkY2xvdWQKICAgICAgICAgICBzaXplPS43NSwgICAgICAgICAgICAgI3NpemUgb2Ygd29yZGNsb3VkCiAgICAgICAgICAgZm9udEZhbWlseSA9ICJUaW1lcyIpICNmb250IG9mIHdvcmRjbG91ZCAgIApgYGAKCiMgTGltaXRhdGlvbnMKSWYgdGhlIHNwZWNpZmllZCBhdXRob3IgaW5jbHVkZXMgdGhlaXIgbWlkZGxlIGluaXRpYWwgaW4gdGhlaXIgR29vZ2xlIFNjaG9sYXIgcHJvZmlsZSwgb3IgaGFzIHRocmVlIG5hbWVzLCB5b3UgbWF5IGVuY291bnRlciBwcm9ibGVtcyBnZW5lcmF0aW5nIHRoZWlyIHdvcmRjbG91ZC4gVGhlcmUgYXJlIGEgZmV3IHBvc3NpYmxlIHNvbHV0aW9uczogIAoqIElucHV0IHRoZWlyIGZpcnN0IGFuZCBsYXN0IG5hbWUgZXhjbHVzaXZlbHkgKGUuZy4sIGlucHV0ICJKZXNzaWNhIEwuIFRyYWN5IiBhcyAiSmVzc2ljYSBUcmFjeSIsIG9yICAiR2VyYmVuIHZhbiBLbGVlZiIgYXMgIkdlcmJlbiBLbGVlZiIpICAKKiBJbnB1dCB0aGVpciBmaXJzdCBhbmQgbWlkZGxlIGluaXRpYWxzIGFzIHRoZWlyIGZpcnN0IG5hbWUgKGUuZy4sIGlucHV0ICJGcmllZHJpY2ggTS4gR8O2dHoiIGFzICJGTSBHw7Z0eiIpICAKKiBJZiBhbGwgZWxzZSBmYWlscywgeW91IGNhbiByZXRyaWV2ZSBhIHJlc2VhcmNoZXIncyBHb29nbGUgU2Nob2xhciBJRCBtYW51YWxseSBmcm9tIHRoZSBoeXBlcmxpbmsgb2YgdGhlaXIgR29vZ2xlIFNjaG9sYXIgcGFnZSwgaW5zdGVhZCBvZiByZXRyaWV2aW5nIGl0IGJhc2VkIG9uIHRoZWlyIGZpcnN0IGFuZCBsYXN0IG5hbWUgKGkuZS4sIHRoZSBtZXRob2QgdXNlZCBoZXJlKS4gTG9vayBmb3IgdGV4dCAidXNlcj0iIGVtYmVkZGVkIHdpdGhpbiB0aGUgaHlwZXJsaW5rLCBhbmQgZXh0cmFjdCB0aGUgMTIgbGV0dGVycyB0aGF0IGZvbGxvdy4gWW91IGNhbiBhc3NpZ24gdGhlaXIgSUQgYXMgYSBjaGFyYWN0ZXIgc3RyaW5nIHRvIHRoZSBvYmplY3QgIklEbnVtYmVyIiwgYW5kIHNraXAgdGhlIGZpcnN0IHN0ZXAgb2YgcmV0cmlldmluZyBHb29nbGUgU2Nob2xhciBJRHMgd2l0aCB0aGUgImdldF9zY2hvbGFyX2lkIiBmdW5jdGlvbiAgCgpUaGlzIG1ldGhvZCByZWxpZXMgaGVhdmlseSBvbiBxdWVyeWluZyBHb29nbGUgU2Nob2xhciwgd2hpY2ggbWF5IGludHJvZHVjZSBzb21lIGNvbXBsaWNhdGlvbnMuIEZvciBleGFtcGxlOiAgCiogQW4gaW50ZXJuZXQgY29ubmVjdGlvbiBpcyByZXF1aXJlZCAgCiogVGhlIHNwZWNpZmllZCByZXNlYXJjaGVyIG11c3QgaGF2ZSBhbiBhY3RpdmUgR29vZ2xlIFNjaG9sYXIgcHJvZmlsZSAgIAoqIFRoZSBtZXRob2Qgd2lsbCBleHRyYWN0IGFsbCBmaWxlcyBpbmRleGVkIGJ5IEdvb2dsZSBTY2hvbGFyIGZvciB0aGUgc3BlY2lmaWVkIHByb2ZpbGUsIHdoaWNoIG1heSBpbmNsdWRlIG5vbi1wZWVyLXJldmlld2VkIGZpbGVzIG9yIHN1cHBsZW1lbnRhbCBtYXRlcmlhbHMgICAKKiBSYXRlIGxpbWl0cyBpbXBvc2VkIGJ5IEdvb2dsZSBTY2hvbGFyIG1heSByZXN0cmljdCB0aGUgdG90YWwgbnVtYmVyIGFuZCBzcGVlZCBvZiB5b3VyIHJlcXVlc3RzLgoqIElmIHlvdSB0cnkgdG8gZ2VuZXJhdGUgYSB3b3JkY2xvdWQgZm9yIGEgcGFydGljdWxhcmx5IHByb2R1Y3RpdmUgcmVzZWFyY2hlciAtLSB3aGljaCByZXF1aXJlcyB5b3UgdG8gcmVxdWVzdCBhbGwgb2YgdGhlIHB1YmxpY2F0aW9ucyBhbmQgYWJzdHJhY3RzIG9mIGEgc3BlY2lmaWVkIGF1dGhvciAtLSB5b3UgbWF5IGV4Y2VlZCBHb29nbGUncyByYXRlIGxpbWl0IChpLmUuLCB0b28gbWFueSByZXF1ZXN0cyBpbiBhIHNob3J0IHBlcmlvZCBvZiB0aW1lKSwgcmVzdWx0aW5nIGluIGFuIGVycm9yLiAKCllvdSBtYXkgd2lzaCB0byBhbHRlcm5hdGl2ZWx5IGNyZWF0ZSBhIHdvcmRjbG91ZCB0aGF0IHZpc3VhbGl6ZXMgeW91ciByZXNlYXJjaCBieSB1cGxvYWRpbmcgUERGIGZpbGVzIG9mIHlvdXIgcmVzZWFyY2ggc2F2ZWQgb24geW91ciBsb2NhbCBkcml2ZS4gVGhpcyBhcHByb2FjaCwgd2hpY2ggaXMgZGVzY3JpYmVkIGluIG1vcmUgZGV0YWlsIFsqb24gbXkgd2Vic2l0ZSpdKGh0dHBzOi8vd3d3Lnpha3dpdGtvd2VyLmNvbS8pLgoKSWYgeW91IGhhdmUgYW55IHF1ZXN0aW9ucywgY29tbWVudHMsIG9yIGNvbmNlcm5zLCBwbGVhc2UgZ2V0IGluIHRvdWNoIHdpdGggbWUuIEknbSBoYXBweSB0byBoZWxwIQpFbWFpbDogW1pha3dpdGtvd2VyQGdtYWlsLmNvbV0obWFpbHRvOlpha3dpdGtvd2VyQGdtYWlsLmNvbSkgIApXZWJzaXRlOiBbd3d3Llpha1dpdGtvd2VyLmNvbV0od3d3Llpha1dpdGtvd2VyLmNvbSkgIApMaW5rZWRJbjogW1phayBXaXRrb3dlcl0oaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2luL3pha3dpdGtvd2VyLykgIApUd2l0dGVyOiBbQFpha3dpdGtvd2VyXShodHRwczovL3R3aXR0ZXIuY29tL3pha3dpdGtvd2VyKSAgCgojIFdyYXBwaW5nIGV2ZXJ5dGhpbmcgaW4gYSBmdW5jdGlvbgpGb3Igc2ltcGxpY2l0eSwgSSd2ZSBjb25zb2xpZGF0ZWQgYWxsIHRoZSBzdGVwcyBpbnRvIGEgc2luZ2xlIGZ1bmN0aW9uIHRoYXQgYXV0b21hdGVzIHRoZSBjcmVhdGlvbiBvZiBhIHdvcmRjbG91ZCB1c2luZyBqdXN0IHlvdXIgZmlyc3QgYW5kIGxhc3QgbmFtZS4gRW50ZXIgdGhlIGZpcnN0IGFuZCBsYXN0IG5hbWUgb2YgdGhlIHJlc2VhcmNoZXIgd2hvc2UgcmVzZWFyY2ggeW91IHdhbnQgdG8gdmlzdWFsaXplIGF0IHRoZSB0b3Agb2YgdGhlIGNvZGUgY2h1bmsgKGFzc2lnbmVkIHRvIG9iamVjdHMgIkZpcnN0TmFtZSIgYW5kICJMYXN0TmFtZSIpLCBhbmQgdGhlbiBydW4gdGhlIHJlc3Qgb2YgdGhlIGNvZGUuIFRoZSBmdW5jdGlvbiB3aWxsIGhhbmRsZSBhbGwgYWRkaXRpb25hbCBzdGVwcywgYW5kIG91dHB1dCBhIHdvcmRjbG91ZC4KCmBgYHtyLCBpbmNsdWRlPVQsIHJlc3VsdHMgPSAiaGlkZSIsIHdhcm5pbmc9RiwgbWVzc2FnZT1GfQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyMjIyMjIyBQbGVhc2UgaW5wdXQgdGhlIGZpcnN0IGFuZCBsYXN0IG5hbWUgb2YgYSByZXNlYXJjaGVyICMjIyMjIyMjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKRmlyc3ROYW1lPC0iWmFrIiAgCkxhc3ROYW1lPC0iV2l0a293ZXIiCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMgQWZ0ZXIgYXNzaWduaW5nIGEgbmFtZSBhYm92ZSwgcnVuIHRoZSByZXN0IG9mIHRoZSBjb2RlIHRvIGNyZWF0ZSB0aGUgZnVuY3Rpb246ICMjIyMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKI2xvYWQgbGlicmFyaWVzCnJlcXVpcmUoc2Nob2xhcikKcmVxdWlyZSh0aWJibGUpIApyZXF1aXJlKHRtKQpyZXF1aXJlKHRpZHl0ZXh0KQpyZXF1aXJlKHRpZHl2ZXJzZSkKcmVxdWlyZSh3b3JkY2xvdWQyKQpyZXF1aXJlKHJhbmRvbWNvbG9SKSAKCiNDcmVhdGUgZnVuY3Rpb24KR29vZ2xlU2Nob2xhcldvcmRDbG91ZDwtZnVuY3Rpb24oZmlyc3QsbGFzdCl7CiAgCiAgI0dldCBJRCBudW1iZXIgZnJvbSBuYW1lCiAgSURudW1iZXI8LWdldF9zY2hvbGFyX2lkKGZpcnN0X25hbWUgPSBmaXJzdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhc3RfbmFtZSA9IGxhc3QpCiAgCiAgI0dldCBwdWJsaWNhdGlvbnMKICBNeXB1YmxpY2F0aW9uczwtdGliYmxlKGdldF9wdWJsaWNhdGlvbnMoSURudW1iZXIpKQogIAogICNBZGQgYWJzdHJhY3RzCiAgTXlwdWJsaWNhdGlvbnMkYWJzdHJhY3Q8LXJlcCgiaW5pdGlhbGl6ZSIsIG5yb3coTXlwdWJsaWNhdGlvbnMpKQogIGZvciAoaSBpbiAxOm5yb3coTXlwdWJsaWNhdGlvbnMpKSB7CiAgICBBYnN0cmFjdHMgPC0gZ2V0X3B1YmxpY2F0aW9uX2Fic3RyYWN0KGlkID0gSURudW1iZXIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwdWJfaWQgPSBNeXB1YmxpY2F0aW9ucyRwdWJpZFtpXSkKICAgIGlmZWxzZShsZW5ndGgoQWJzdHJhY3RzKSA9PSAwLCBOQSwgTXlwdWJsaWNhdGlvbnMkYWJzdHJhY3RbaV0gPC0gQWJzdHJhY3RzKSAKICB9CiAgCiAgI0NyZWF0ZSBDb3JwdXMKICBNeUFic3RyYWN0cy5jb3JwdXM8LVZDb3JwdXMoVmVjdG9yU291cmNlKE15cHVibGljYXRpb25zJGFic3RyYWN0KSkKICAKICAjQ3JlYXRlIFRETSBmcm9tIGNvcnB1cwogIE15QWJzdHJhY3RzLlRETTwtVGVybURvY3VtZW50TWF0cml4KE15QWJzdHJhY3RzLmNvcnB1cywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cm9sID0gCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaXN0KHJlbW92ZVB1bmN0dWF0aW9uID0gVFJVRSwgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdG9wd29yZHMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b2xvd2VyID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RlbW1pbmcgPSBGLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZW1vdmVOdW1iZXJzID0gVFJVRSkpCiAgI1RpZHkgVERNCiAgTXlBYnN0cmFjdHMuVERNPC10aWR5KE15QWJzdHJhY3RzLlRETSkgJT4lIAogICAgZ3JvdXBfYnkodGVybSkgJT4lIAogICAgc3VtbWFyaXNlKGNvdW50LGNvdW50ID0gc3VtKGNvdW50KSkgJT4lIAogICAgdW5pcXVlKCklPiUgIAogICAgdW5ncm91cCgpICU+JQogICAgYXJyYW5nZShkZXNjKGNvdW50KSkgICAgCiAgCiAgI3JldGFpbiB0b3AgMTAwIG1vc3QgZnJlcXVlbnRseSB1c2VkIHdvcmRzCiAgTXlBYnN0cmFjdHMuVERNPC1oZWFkKE15QWJzdHJhY3RzLlRETSwgMTAwKSAKICAKICAjY3JlYXRlIHdvcmRjbG91ZAogIHdvcmRjbG91ZDwtd29yZGNsb3VkMihNeUFic3RyYWN0cy5URE0sCiAgICAgICAgICAgICBmb250V2VpZ2h0ID0gImJvbGQiLCAgI2JvbGQgYWxsIGl0ZW1zCiAgICAgICAgICAgICByb3RhdGUgPSAwLCAgICAgICAgICAgI21heCByb3RhdGlvbiBvZiB3b3JkcyAKICAgICAgICAgICAgIHNpemU9Ljc1LCAgICAgICAgICAgICAjc2l6ZSBvZiB3b3JkY2xvdWQKICAgICAgICAgICAgIGZvbnRGYW1pbHkgPSAiVGltZXMiLCAjZm9udCBvZiB3b3JkY2xvdWQgICAKICAgICAgICAgICAgIGNvbG9yID0gcmFuZG9tQ29sb3IobnJvdyhNeUFic3RyYWN0cy5URE0pLCAjY3JlYXRlIGNvbG9yIHBhbGV0dGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaHVlID0gInJhbmRvbSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsdW1pbm9zaXR5ID0gImRhcmsiKSkgCiAgCiAgcmV0dXJuKHdvcmRjbG91ZCkKICB9CgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyMjIFJ1biB0aGUgZnVuY3Rpb24gd2UganVzdCBjcmVhdGVkLCB1c2luZyB0aGUgYXNzaWduZWQgbmFtZSAjIyMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpHb29nbGVTY2hvbGFyV29yZENsb3VkKEZpcnN0TmFtZSwgTGFzdE5hbWUpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIEVuZC4gIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCmBgYA==