This lab journal shows the extraction and cleaning of first and last names of doctoral recipients on a mock data set.


Starting with an empty environment.

rm(list = ls())

1 Custom functions

  • fpackage.check: Check if packages are installed (and install if not) in R (source).
fpackage.check <- function(packages) {
  lapply(packages, FUN = function(x) {
    if (!require(x, character.only = TRUE)) {
      install.packages(x, dependencies = TRUE)
      library(x, character.only = TRUE)
    }
  })
}

2 Packages

  • tidyverse: general package for data manipulation

  • stringr: to execute various string manipulations

  • stringi: to remove diacritics

  • kableExtra: to make tables in Rmarkdown

packages = c("tidyverse", "stringr", "stringi", "kableExtra")

fpackage.check(packages)

3 Input

We use one mock dataset:

  • phd_metadf.rda: this dataset mimicks the structure of our raw data, but contains 8 example rows to maintain anonymity.
    • name of dataset: phd_metadf
load(file = "./data/phd_metadf.rda")

This lab journal is used to demonstrate how we extract first and last names from PhDs.

For this, we use an example dataframe containing 8 observations (4 ethnic majority names, 2 ethnic minority names, 2 other names - all split equally between male- and female-typed first names). This mock dataframe mirrors the set-up of our web-scraped data, which consists of name information which are web scraped from different sources.

  • 1 auteur: the ‘author’ column on NARCIS dissertation pages
  • 2 narcisname: full name that is mentioned at the top of personal NARCIS pages
  • 3 pdfname and pdfnamep1: full names mentioned in the running text of dissertation PDF, and on cover pages of the dissertation provided by a subset of universities, respectively.

Below you can see the example data,

auteur narcisname pdfname pdfnamep1 diss_birthplace uni phd_year id
Verschuuren, J-W.M. J.W.M. Verschuuren jan-willem marinus verschuuren verschuuren, jan-willem marinus geboren te ’s-gravenhage UvA 2013 a
Janssen-de Jong, Corine Prof. Dr. C.W.P. Janssen-de Jong de jong, c. w. p.  RUG 1998 b
Vries, J. de; Lammers, H.G.W. de Vries, J. jan de vries geboren te oldenzaal in EUR 2004 c
van Vliet, M.A.  Dr. M.A. (Monique) van Vliet vliet, monique van TUE 2006 d
Aydin, S. Aydin, S selim aydin aydin, selim geboren te giresun, turkije RU 2017 e
Karimi, Nahid Fouad N.F. Karimi (MSc) LU 2012 f
Bernard, J.O Bernard, Jacques Olivier jacques bernard bernard, jacques quimper, frankrijk UU 2019 g
L.C. Schneider (Lena) Schneider, LC schneider, lena carolina WUR 2000 h

4 Gathering first names from ‘auteur’(Author) on NARCIS dissertation pages

Some dissertations appear to have multiple authors. We only want the first author, so remove everything after “;”

phd_metadf$auteur <- gsub(";.*", "", phd_metadf$auteur)

4.1 First names in brackets

phd_metadf$firstname <- str_extract(phd_metadf$auteur, "(?<=\\().*(?=\\))")

phd_metadf$firstname <- ifelse(phd_metadf$firstname == "", NA, phd_metadf$firstname)

4.2 First names after a comma

phd_metadf$com <- str_detect(phd_metadf$auteur, ",") # detect comma

# Keep everything after a comma if there is one
phd_metadf <- phd_metadf %>%
  mutate(firstname = ifelse((is.na(firstname) & com==TRUE), str_remove(auteur, ".*,"), firstname)) %>% select(-com)
phd_metadf$firstname <- trimws(phd_metadf$firstname, which = c("both"), whitespace = "[ \t\r\n]")

4.3 Cleaning the first names

Many last names include so-called ‘nobiliary particles’. These are additions to the last name (e.g. “van de” in Dutch, “de la” in French or “zu” in German). In order to extract the first names we detect and remove these. Nobiliary particles have crept into first name when gathering everything after a comma, for example when names are in the format of “Vries, Jan de”. The nobiliary particles are also important to separate from the rest of the last name to create matchable last names later.

# Removing all nobiliary particles that consist of multiple words
vande0 <- c("(V|v)an (D|d)er", "(V|v)an (D|d)en", "(V|v)an (D|d)e", "(V|v)ande(n)?", "(V|v)an '(T|t)", "(V|v)an'(T|t)", "(V|v)an (T|t)", "(V|v)an (H|h)et", "(V|v)on (D|d)er", "(O|o)p den", "(O|o)p 't", "(O|o)f ten", "(A|a)an de(n)?", "(D|d)e (L|l)a", "(I|i)n (H|h)et", "(I|i)n '(T|t)", "(I|i)n'(T|t)","(I|i)n (T|t)", "(I|i)n (D|d)er", "(B|b)ij (D|d)e") 


# Some of the nobiliary particles can actually be part of the first name, e.g. "Al" in the name "Alice". These require some more care to remove: only remove these when surrounded by whitespaces or when they take up the entire name.  

# Whitespaces around van/de
vande1 <- c("\\s(L|l)a\\s", "\\s(O|o)p\\s" ,"\\s(V|v)an\\s", "\\s(V|v)on\\s", "\\s(D|d)en\\s", "\\s(D|d)er\\s", "\\s(D|d)el\\s", "\\s(D|d)(e|a|u|i)\\s", "\\s(D|d)os?\\s", "\\s(T|t)er\\s", "\\s(T|t)en\\s", "\\s(T|t)e\\s", "\\s'(T|t)\\s", "\\s(L|l)e\\s", "\\s(E|A)l-", "\\s[(A|a)(E|e)](L|l)'?\\s", "\\s(D|d)'", "\\szu\\s", "\\s(Z|z)ur\\s", "\\s(Y|y)\\s", "\\s(E|e)\\s") 


# Entire string consists of van/de
vande2 <- c("^(L|l)a$", "^(O|o)p$" , "^(V|v)an$", "^(V|v)on$", "^(D|d)en$", "^(D|d)er$", "^(D|d)el$", "^(D|d)(e|a|u|i)$", "^(D|d)os?$", "^Vande[$//s]", "^(T|t)er$",  "^(T|t)en$", "^(T|t)e$", "^'(T|t)$", "^(L|l)e$", "^[(A|a)(E|e)](L|l)'?$", "^(D|d)'$", "^zu$", "^(Z|z)ur$")


# String starts with van/de followed by a whitespace
vande3 <- c("^(L|l)a\\s", "^(O|o)p\\s" ,"^(V|v)an\\s", "^(V|v)on\\s", "^(D|d)en\\s", "^(D|d)er\\s", "^(D|d)el\\s", "^(D|d)(e|a|u|i)\\s", "^(D|d)os?\\s", "^(T|t)er\\s" , "^(T|t)en\\s", "^(T|t)e\\s", "^'(T|t)\\s", "^(L|l)e\\s", "^El-", "^[(A|a)(E|e)](L|l)'?\\s", "^(D|d)'", "^zu\\s", "^(Z|z)ur\\s", "^e\\s")


# String ends with van/de
vande4 <- c("\\s(L|l)a$", "\\s(O|o)p$" ,"\\s(V|v)an$", "\\s(V|v)on$", "\\s(D|d)en$", "\\s(D|d)er$", "\\s(D|d)el$", "\\s(D|d)(e|a|u|i)$", "\\s(D|d)os?$", "\\s(T|t)er$", "\\s(T|t)en$", "\\s(T|t)e$", "\\s'(T|t)$", "\\s(L|l)e$", "\\s[(A|a)(E|e)](L|l)'?$", "\\s(D|d)'$", "\\szu$", "\\s(Z|z)ur$")



# remove the nobiliary particles in different forms
phd_metadf$firstname <- str_remove(phd_metadf$firstname, paste0(vande0, collapse="|"))
phd_metadf$firstname <- str_replace_all(phd_metadf$firstname, paste(vande1, collapse = "|"), "")
phd_metadf$firstname <- str_remove_all(phd_metadf$firstname, paste(vande2, collapse = "|"))
phd_metadf$firstname <- str_replace_all(phd_metadf$firstname, paste(vande3, collapse = "|"), "")
phd_metadf$firstname <- str_remove(phd_metadf$firstname, paste(vande4, collapse = "|"))

4.3.1 Removing initials after the comma in auteur

Since we extracted everything after the comma, some of the first names contain initials, e.g.: “Smith, A.B.C.”. We remove these.

phd_metadf$firstname <- trimws(phd_metadf$firstname, which = "both")


# There are multiple patterns, and we want to extract all possible forms of initials into our object

initialpattern <- paste(c("^\\s?([:upper:]\\.)+[:upper:]\\s?$",   # A.A.A (last initial does not contain a period at the end)
                          "([:upper:]\\.?\\-\\.?)+",                  # A- or A-. or A.-
                          "([:upper:]\\.+)+", "([:lower:]\\.){2,}",   # A.  or a.
                          "(T|t|C|c|P|p)h\\.\\s?",                    # Th. Ph. Ch. 
                          "^\\s?([:alpha:]\\s)+",                     # A or a surrounded by whitespace
                          "^\\s?[:alpha:]\\.?\\s?$",                  # entire string consists of a single letter
                          "^\\s?[:upper:]{2,4}\\s?$"),                # entire string consists of 2-4 capital letters
                        collapse = "|")


phd_metadf$initials2 <- as.character((str_extract_all(phd_metadf$firstname, initialpattern)))


# If there were multiple different patterns present in the initials, they were combined in a c() object. Remove the unnecessary text here. 
phd_metadf$initials2 <- gsub("c\\(\"", "", phd_metadf$initials2)
phd_metadf$initials2 <- gsub("\", \"", "", phd_metadf$initials2)
phd_metadf$initials2 <- gsub("\"\\)", "", phd_metadf$initials2)

In order to extract first names, we remove the initials gathered in the chunk above.

phd_metadf$firstname <- str_remove(phd_metadf$firstname, phd_metadf$initials2)

phd_metadf$firstname <- trimws(phd_metadf$firstname, which = "both")

phd_metadf <- subset(phd_metadf, select=-initials2)

Final cleaning steps

phd_metadf$firstname <- gsub("/.*", "", phd_metadf$firstname) # Some names in the form "Floor/Floris". Remove everything after "/"

# make the names lowercase
phd_metadf$firstname <- tolower(phd_metadf$firstname)

# remove diacritics
phd_metadf$firstname <- stri_trans_general(phd_metadf$firstname, id = "latin-ascii")

# remove non-letter characters, taking the first mentioned name
phd_metadf$firstname <- str_extract(phd_metadf$firstname, "[a-z]+\\-*[a-z]*")

# removing white spaces at the beginning and at the end of the name first name string
phd_metadf$firstname <- trimws(phd_metadf$firstname, which = "both")

# removing nobiliary particles which slipped through
phd_metadf$firstname <- str_remove_all(phd_metadf$firstname, paste(vande2, collapse = "|"))

phd_metadf <- phd_metadf %>%
  mutate(firstname = ifelse((firstname == "^\\s$" | firstname == "") ,NA, firstname)) # empty string to NA

phd_metadf$firstname <- ifelse(nchar(phd_metadf$firstname)==1, NA, phd_metadf$firstname) # single-character string (i.e. initial) to NA

5 Last names from ‘auteur’ on NARCIS dissertation page

First, we extract last names in the format “lastname comma firstname”

# remove everything after a comma
phd_metadf$lastname <- gsub(",.*$", "", phd_metadf$auteur) 

# remove diacritics
phd_metadf$lastname <- stri_trans_general(phd_metadf$lastname, id = "latin-ascii")

# we assume that V/D, v/d and v.d. indicate the popular Dutch nobiliary particle "van de"
phd_metadf$lastname <- str_replace(phd_metadf$lastname, "(v\\.d\\.)|((V|v)/(D|d))", "van de")


# remove initials
phd_metadf$lastname <- str_remove_all(phd_metadf$lastname, initialpattern) # object initialpattern defined in section 1
phd_metadf$lastname <- trimws(phd_metadf$lastname, which = "both") # removing whitespace


# remove titles
phd_metadf$lastname <- trimws(phd_metadf$lastname, which = "both")
phd_metadf$lastname <- str_remove_all(phd_metadf$lastname, "(^(M|m)r\\.?\\s)|(^(D|d)rs?\\.?\\s)|(^St\\.\\s)|(^(M|M)r?s\\.?\\s)|(^ext\\.\\s)|(^(M|m)d\\.?\\s)")


# remove first names between brackets from the last name
phd_metadf$lastname <- str_remove_all(phd_metadf$lastname, "\\s\\(.*\\)$")


# Next, we extract the nobiliary particles and save these in a separate object. These can be used when matching names to other databases later. 

phd_metadf$lastname <- trimws(phd_metadf$lastname, which = "both") # first, we trim whitespaces

# extract nobiliary particles at the beginning of the last name string (vande3)
phd_metadf$np <- str_extract(phd_metadf$lastname, paste(vande3, collapse = "|")) # extract into new variable np
phd_metadf$lastname <- str_remove(phd_metadf$lastname, paste(vande3, collapse = "|")) # remove from lastname variable

# extract nobiliary particles at the end of the auteur string (vande4)
# first detect, or else it overwrites the np with NA if not applicable
phd_metadf$end <- as.numeric(str_detect(phd_metadf$auteur, paste(vande4, collapse = "|")))
phd_metadf$np <- ifelse(phd_metadf$end==1, str_extract(phd_metadf$auteur, paste(vande4, collapse = "|")), phd_metadf$np) #only extract if np is detected at the end
phd_metadf <- subset(phd_metadf, select = -end)

# also extract nobiliary particles at the end of the lastname string (vande4)
phd_metadf$end <- as.numeric(str_detect(phd_metadf$lastname, paste(vande4, collapse = "|")))
phd_metadf$np <- ifelse(phd_metadf$end==1, str_extract(phd_metadf$lastname, paste(vande4, collapse = "|")), phd_metadf$np)
phd_metadf$lastname <- str_remove(phd_metadf$lastname, paste(vande4, collapse = "|"))
phd_metadf <- subset(phd_metadf, select = -end) #remove intermediate object

# trim white spaces in the noviliary particle
phd_metadf$np <- trimws(phd_metadf$np, which = "both")

# removing multiple spaces
phd_metadf$lastname <- sub("\\s{2,}", "\\s", phd_metadf$lastname)
phd_metadf$lastname <- trimws(phd_metadf$lastname, which = "both")

# removing "-" from nobiliary particle El- or Al- and "'" for 't 
phd_metadf$np <- str_remove(phd_metadf$np, "-")
phd_metadf$np <- str_remove(phd_metadf$np, "\'")

# remove Jr.
phd_metadf$lastname <- str_remove(phd_metadf$lastname, "\\sJr\\.$")
phd_metadf$lastname <- str_remove(phd_metadf$lastname, "\\sJunior$")

# remove interpunction
phd_metadf$lastname <- str_remove_all(phd_metadf$lastname, "(\\?)|(\\`)|(\\^)|(^\\')|(\\´)|(\\·)")

# names and nobiliary particles to lowercase
phd_metadf$lastname <- tolower(phd_metadf$lastname)
phd_metadf$np <- tolower(phd_metadf$np)

# we only want the first last name if there are multiple
phd_metadf$lastname <- str_extract(phd_metadf$lastname, "[:lower:]+")


# combining nobiliary particle and last name into a separate objecr
phd_metadf %>%
  mutate(lastname_full = ifelse(!is.na(np), paste(np, lastname), lastname)) -> phd_metadf

6 Extracting first names from personal NARCIS profiles

In the following part of the script, first names from personal NARCIS profiles will be cleaned. The method here is roughly the same as the method used to clean the first names from the ‘Author’ section of dissertation NARCIS pages.

The cleaned first names are stored in an intermediate object, “int”, to ensure that the original scraped name is preserved in “narcisname”.

6.1 Extract first names in brackets

E.g. “A.B.C. (Andrea) Smith”

phd_metadf$int <- str_extract(phd_metadf$narcisname, "(?<=\\().*(?=\\))")

phd_metadf$int <- ifelse(phd_metadf$int == "", NA, phd_metadf$int)

6.2 Extract everything after a comma

E.g. “Smith, Andrea”

phd_metadf$comma <- str_detect(phd_metadf$narcisname, ",") # only when narcisname contains a comma

phd_metadf <- phd_metadf %>% 
  mutate(int = ifelse((is.na(int) & comma==TRUE), str_remove(narcisname, ".*,"), int))

phd_metadf$int <- trimws(phd_metadf$int, which = c("both"))

phd_metadf <- subset(phd_metadf, select = -comma)

6.3 Cleaning Narcis names

Similar approach to extraction of first names from ‘Auteur’, meaning we remove non-name strings from the name object (nobiliary particles, initials, titles, punctuation)

# nobiliary particles at different places in the string
phd_metadf$int <- str_remove(phd_metadf$int, paste0(vande0, collapse="|"))
phd_metadf$int <- str_remove(phd_metadf$int, paste(vande1, collapse = "|"))
phd_metadf$int <- str_remove(phd_metadf$int, paste(vande2, collapse = "|"))
phd_metadf$int <- str_remove(phd_metadf$int, paste(vande3, collapse = "|"))
phd_metadf$int <- str_remove(phd_metadf$int, paste(vande4, collapse = "|"))

# removing initials 
phd_metadf$int <- str_remove_all(phd_metadf$int, initialpattern) # object initialpattern defined in section 1

# next, we remove a number of different titles that can be found in the name object
phd_metadf$int <- str_remove_all(phd_metadf$int, "(MSc)|(MA)|(MPhil)|(PhD)|(Mr\\.)|(^Mr)|((D|d)rs?\\.)|(Md\\.)|(Mr?s\\.)")


phd_metadf$int <- gsub("/.*", "", phd_metadf$int) # some names in the form "Floor/Floris". Remove everything after "/"


# finally, we do some general cleaning of the names
phd_metadf$int <- trimws(phd_metadf$int, which = "both")

phd_metadf$int <- tolower(phd_metadf$int) # set names to lowercase

# remove diacritics from the name
phd_metadf$int <- stri_trans_general(phd_metadf$int, id = "latin-ascii")

# keep only the first-mentioned name
phd_metadf$int <- str_extract(phd_metadf$int, "[a-z]+\\-*[a-z]*")


phd_metadf <- phd_metadf %>%
  mutate(int = ifelse((int == "^//s$" | int == "") ,NA, int)) # empty to NA

phd_metadf$int <- trimws(phd_metadf$int, which = "both")
phd_metadf$int <- ifelse(nchar(phd_metadf$int)==1, NA, phd_metadf$int) # remove erroneous one-character names

7 Combining first name information from dissertation & personal NARCIS pages

We give priority to names from the dissertation pages, because these appear to be the formal first names, while personal NARCIS page names correspond to the given first name. Given that we match individuals based on the name which is formally registered, it seems appropriate to take the ‘auteur’ name as the basis and replace with ‘narcisname’ when the name based on ‘auteur’ is unknown.

phd_metadf <- phd_metadf %>%
  mutate(firstname = ifelse(is.na(firstname), int, firstname))

# set empty to NA
phd_metadf <- phd_metadf %>%
  mutate(firstname = ifelse(firstname=="", NA, firstname))

phd_metadf$narcis_fn <- phd_metadf$int # longer but more informative name

phd_metadf <- subset(phd_metadf, select = -int)

8 First names from dissertation PDFs

There are two name objects gathered from the pdfs: pdfname (consisting of names that were extracted from running text in the dissertation, often from dissertation front pages) and pdfnamep1 (names on standardized dissertation frontpages that are provided by a subset of universities, which contain a specific header for the PhD name)

8.1 Cleaning the pdfname object

In comparison to the names from the 2 NARCIS page sources, the name object from the dissertation PDF can sometimes be a bit messy. Especially the ‘pdfname’ object, due to the fact that these names are extracted from natural text, meaning sometimes non-name information enters the name object. Furthermore, some of the older PDFs are scanned versions of a printed dissertation, meaning there may be errors when these images are converted to text.

In the provided dataframe, we only included more straightforward name examples. So, the code below is not directly applicable to our example case, but still shows how we cleaned some of the messier names.

# remove diacritics
phd_metadf$pdfname <- stri_trans_general(phd_metadf$pdfname, 'latin-ascii')

# remove punctuation
phd_metadf$pdfname <- str_remove_all(phd_metadf$pdfname, "[~!@#\\$%\\^\\&\\*\\(\\)\\{\\}\\_\\+:<>\\?\\/;\\'\\[\\]\\=\\,\\•\\.]")

# remove digits
phd_metadf$pdfname <- str_remove_all(phd_metadf$pdfname,  "[:digit:]")

# remove copyright indications
phd_metadf$pdfname <- str_remove_all(phd_metadf$pdfname,  "copyright")
phd_metadf$pdfname <- str_remove_all(phd_metadf$pdfname,  "(C)")
phd_metadf$pdfname <- gsub("\\sall rights.*", "", phd_metadf$pdfname)

phd_metadf$pdfname <- trimws(phd_metadf$pdfname, which = "both")

# removing titles from the name
phd_metadf$pdfname <- gsub("master.*", "", phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\smsc.*", "", phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\smd.*", "", phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\smagister.*", "", phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\smagistri.*", "", phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\sbachelor.*", "",phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\slaurea.*", "", phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\smestre.*", "", phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\sdottore.*", "", phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\supm.*", "", phd_metadf$pdfname) # specific UM press thing
phd_metadf$pdfname <- gsub("\\sp\\su\\sm.*", "", phd_metadf$pdfname) # specific UM press thing
phd_metadf$pdfname <- gsub("\\sdipl.*", "", phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\sdiplom.*", "", phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\sdiploma.*", "", phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\slicen.*", "", phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\shbo.*", "", phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\shts.*", "", phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\sdoctorandus.*", "", phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\scandidat.*", "", phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\ssarjana.*", "", phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\sspecialist.*", "", phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\suniver.*", "", phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\sengineer.*", "", phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\singeniero.*", "", phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\singiner.*", "", phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\singeniera.*", "", phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\singenieria.*", "", phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\singegnere.*", "", phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\singegneria.*", "", phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\singenieur.*", "", phd_metadf$pdfname)
phd_metadf$pdfname <- gsub("\\s[[:alpha:]\\-]*ingenieur.*", "", phd_metadf$pdfname) # ingenieur and everything that is attached before

# specific types of engineering titles
engineeringtitles <- c("ele(c|k)trotechnisch.*", "civiel.*", "(land)?(werktuig)?(scheeps)?(mijn)?bouwkundig.*", "(wis)?(natuur)?(schei)?(werktuig)?(materiaal)?(bestuurs)?kundig.*", "informatica.*", "geodetisch.*", "lucht- en ruimtevaart technisch.*", "chemisch.*", "maritiem.*", "bioinformatica.*", "raadgevend.*", "architect.*", "geologisch.*", "geofysisch.*", "meet- en regeltechnisch")

phd_metadf$pdfname <- str_remove(phd_metadf$pdfname, paste0(engineeringtitles, collapse = "|"))

phd_metadf$pdfname <- trimws(phd_metadf$pdfname, which = "both")

Some dissertations have multiple authors. We only want the first author, so remove everything after “;”

phd_metadf$pdfnamep1 <- gsub(";.*", "", phd_metadf$pdfnamep1)

8.2 First names from pdfnamep1

The object pdfnamep1 contains all names in a standardized format. The format is: “last name, first name(s)”. To extract first names, we look at everything that follows the comma.

phd_metadf$com <- str_detect(phd_metadf$pdfnamep1, ",") # detect comma

# Keep everything after a comma if there is one
phd_metadf <- phd_metadf %>%
  mutate(firstnamepdf = ifelse((com==TRUE), str_remove(pdfnamep1, ".*,"), pdfnamep1)) %>%
  select(-com)

8.3 Cleaning the first names

Removing nobiliary particles, initials amd punctuation.

# removing all nobiliary particles
phd_metadf$firstnamepdf <- str_remove(phd_metadf$firstnamepdf, paste0(vande0, collapse="|"))
phd_metadf$firstnamepdf <- str_replace_all(phd_metadf$firstnamepdf, paste(vande1, collapse = "|"), "")
phd_metadf$firstnamepdf <- str_remove_all(phd_metadf$firstnamepdf, paste(vande2, collapse = "|"))
phd_metadf$firstnamepdf <- str_replace_all(phd_metadf$firstnamepdf, paste(vande3, collapse = "|"), "")
phd_metadf$firstnamepdf <- str_remove(phd_metadf$firstnamepdf, paste(vande4, collapse = "|"))

phd_metadf$firstnamepdf <- trimws(phd_metadf$firstnamepdf, which = "both") # trimming whitespace

phd_metadf$firstnamepdf <- str_remove_all(phd_metadf$firstnamepdf, initialpattern) # object initialpattern defined in section 1

# extracting only the first-mentioned first name and removing punctuation marks
phd_metadf$firstnamepdf <- str_extract(phd_metadf$firstnamepdf, "[a-z]+\\-*[a-z]*")


phd_metadf <- phd_metadf %>%
  mutate(firstnamepdf = ifelse((firstnamepdf == "^\\s$" | firstnamepdf == "") ,NA, firstnamepdf)) # empty to NA

phd_metadf$firstnamepdf <- ifelse(nchar(phd_metadf$firstnamepdf)==1, NA, phd_metadf$firstnamepdf) # remove erroneous one-character names

8.4 Adding first names from pdfname

Because names from the pdfname object are not as neat as names from pdfnamep1, we give priority to the latter.

The format of the pdfname object is “first name(s) last name”. So, we extract the first word from this object to gather the first name. Some names contain a large number of whitespaces (e.g. “m a t t h e w j o h n s o n” or “m atthew j ohnson”). The former case, we currently do not extract.

# A few names have a couple of added spaces, often following the first letter of a name. Remove this space after the first letter

phd_metadf$spaces <- as.numeric(str_detect(phd_metadf$pdfname, "^\\s?[:alpha:]\\s[:alpha:]{2,}")) # detect a single letter, followed by a space, followed by more than 1 letter

phd_metadf$spaces <- ifelse(is.na(phd_metadf$spaces), 0, phd_metadf$spaces) # replace NA with 0

phd_metadf$pdfname <- ifelse(phd_metadf$spaces==1, str_remove(phd_metadf$pdfname, "\\s"), phd_metadf$pdfname) # remove the first space if a name follows the pattern described above

phd_metadf$firstnamepdf2 <- str_extract(phd_metadf$pdfname, "[a-z]+\\-*[a-z]*")



# Now, we fill the firstname object with the first word in 'pdfname', but only if firstname based on 'pdfnamep1' is missing
phd_metadf$firstnamepdf <- ifelse(is.na(phd_metadf$firstnamepdf), phd_metadf$firstnamepdf2, phd_metadf$firstnamepdf)


# Again, we remove spaces and one-character names
phd_metadf$firstnamepdf <- str_remove_all(phd_metadf$firstnamepdf, "\\s") # remove spaces
phd_metadf$firstnamepdf <- ifelse(nchar(phd_metadf$firstnamepdf)==1, NA, phd_metadf$firstnamepdf) # remove erroneous one-character names


# Remove unknown characters
phd_metadf$firstnamepdf <- str_extract(phd_metadf$firstnamepdf, "[a-z]+\\-*[a-z]*")


phd_metadf <- subset(phd_metadf, select = -firstnamepdf2) # remove intermediate object

9 Gathering last names from the dissertation PDFs

There is a very small number of individuals for whom the last name is unknown. To fill this, we use the name object from the dissertation data. Given the formatting of names in this object as “first name(s) last name(s)”, we just take the last word of the string, and then add potential nobiliary particles that are mentioned in the middle of the string.

phd_metadf$lastnamepdf <- word(phd_metadf$pdfname, -1)

# extracting nobiliary particles
phd_metadf$np2 <- str_extract(phd_metadf$pdfname, paste0(vande0, collapse="|")) # nobiliary particles that cannot be part of the name
phd_metadf$np2 <- ifelse(is.na(phd_metadf$np2), str_extract(phd_metadf$pdfname, paste0(vande1, collapse="|")), phd_metadf$np2) # nobiliary particles surrounded with whitespaces

# Combining nobiliary particle and last name
phd_metadf %>%
  mutate(lastname_full_pdf = ifelse(!is.na(np2), paste(np2, lastnamepdf), lastnamepdf)) -> phd_metadf

phd_metadf$lastnamepdf <- ifelse(nchar(phd_metadf$lastnamepdf)==1, NA, phd_metadf$lastnamepdf) # remove erroneous one-character names

10 Harmonizing names from NARCIS pages and dissertation text

Next, we harmonize the names we now have based on NARCIS pages (personal and dissertation page), with names gathered from dissertation PDF text. We give priority to names from NARCIS pages, because they contain less noise than names from the dissertation text.

phd_metadf$firstname <- ifelse(is.na(phd_metadf$firstname), phd_metadf$firstnamepdf, phd_metadf$firstname)


phd_metadf$lastname <- ifelse(is.na(phd_metadf$lastname), phd_metadf$lastnamepdf, phd_metadf$lastname)

11 View of the dataframe with cleaned last names

After all of this cleaning, we now have a dataframe that contains a cleaned first name and last name (with nobiliary particles if present). This dataframe is used as input for our gender and ethnicity variables.

id auteur narcisname pdfname pdfnamep1 firstname np lastname lastname_full diss_birthplace uni phd_year
a Verschuuren, J-W.M. J.W.M. Verschuuren jan-willem marinus verschuuren verschuuren, jan-willem marinus jan-willem NA verschuuren verschuuren geboren te ’s-gravenhage UvA 2013
b Janssen-de Jong, Corine Prof. Dr. C.W.P. Janssen-de Jong de jong, c. w. p.  corine NA janssen janssen RUG 1998
c Vries, J. de de Vries, J. jan de vries jan de vries de vries geboren te oldenzaal in EUR 2004
d van Vliet, M.A.  Dr. M.A. (Monique) van Vliet vliet, monique van monique van vliet van vliet TUE 2006
e Aydin, S. Aydin, S selim aydin aydin, selim selim NA aydin aydin geboren te giresun, turkije RU 2017
f Karimi, Nahid Fouad N.F. Karimi (MSc) nahid NA karimi karimi LU 2012
g Bernard, J.O Bernard, Jacques Olivier jacques bernard bernard, jacques jacques NA bernard bernard quimper, frankrijk UU 2019
h L.C. Schneider (Lena) Schneider, LC schneider, lena carolina lena NA schneider schneider WUR 2000

12 Output

We save the dataset phd_metadf including the cleaned first and last names, with the duplicate observations removed.

phd_metadf %>%
  select(id, firstname, np, lastname, lastname_full, diss_birthplace, uni, phd_year) -> phdnames

save(phdnames, file = "data/processed/phdnames.rda")

13 References

LS0tDQp0aXRsZTogIkFjYWRlbWljIHB1Ymxpc2hpbmcgY2FyZWVycyBpbiBOTDogZ2F0aGVyaW5nIG5hbWVzIg0KZGF0ZTogIkxhc3QgY29tcGlsZWQgb24gYHIgZm9ybWF0KFN5cy50aW1lKCksICclQiwgJVknKWAiDQpvdXRwdXQ6IA0KICBodG1sX2RvY3VtZW50Og0KICAgIGNzczogdHdlYWtzLmNzcw0KICAgIHRvYzogIHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUNCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICANCi0tLQ0KDQpgYGB7ciwgZ2xvYmFsc2V0dGluZ3MsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9ImhpZGUifQ0KDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShmb3JtYXRSKQ0Kb3B0c19jaHVuayRzZXQodGlkeS5vcHRzPWxpc3Qod2lkdGguY3V0b2ZmPTEwMCksdGlkeT1GQUxTRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsY29tbWVudCA9ICIjPiIsIGNhY2hlPVRSVUUsIGNsYXNzLnNvdXJjZT1jKCJ0ZXN0IiksIGNsYXNzLm91dHB1dD1jKCJ0ZXN0MiIpLCBjYWNoZS5sYXp5ID0gRkFMU0UpDQpvcHRpb25zKHdpZHRoID0gMTAwKQ0KcmdsOjpzZXR1cEtuaXRyKCkNCg0KY29sb3JpemUgPC0gZnVuY3Rpb24oeCwgY29sb3IpIHtzcHJpbnRmKCI8c3BhbiBzdHlsZT0nY29sb3I6ICVzOyc+JXM8L3NwYW4+IiwgY29sb3IsIHgpIH0NCg0KYGBgDQoNCmBgYHtyIGtsaXBweSwgZWNobz1GQUxTRSwgaW5jbHVkZT1UUlVFfQ0KDQprbGlwcHk6OmtsaXBweShwb3NpdGlvbiA9IGMoJ3RvcCcsICdyaWdodCcpKQ0KDQpgYGANCg0KDQoNCg0KLS0tLQ0KDQoNClRoaXMgbGFiIGpvdXJuYWwgc2hvd3MgdGhlIGV4dHJhY3Rpb24gYW5kIGNsZWFuaW5nIG9mIGZpcnN0IGFuZCBsYXN0IG5hbWVzIG9mIGRvY3RvcmFsIHJlY2lwaWVudHMgb24gYSBtb2NrIGRhdGEgc2V0LiANCg0KDQotLS0tDQoNClN0YXJ0aW5nIHdpdGggYW4gZW1wdHkgZW52aXJvbm1lbnQuDQoNCmBgYHtyfQ0KDQpybShsaXN0ID0gbHMoKSkNCg0KYGBgDQoNCg0KDQoNCiMgQ3VzdG9tIGZ1bmN0aW9ucw0KDQotIGBmcGFja2FnZS5jaGVja2A6IENoZWNrIGlmIHBhY2thZ2VzIGFyZSBpbnN0YWxsZWQgKGFuZCBpbnN0YWxsIGlmIG5vdCkgaW4gUiAoW3NvdXJjZV0oaHR0cHM6Ly92YmFsaWdhLmdpdGh1Yi5pby92ZXJpZnktdGhhdC1yLXBhY2thZ2VzLWFyZS1pbnN0YWxsZWQtYW5kLWxvYWRlZC8pKS4gIA0KDQoNCmBgYHtyLCByZXN1bHRzPSdoaWRlJ30NCmZwYWNrYWdlLmNoZWNrIDwtIGZ1bmN0aW9uKHBhY2thZ2VzKSB7DQogIGxhcHBseShwYWNrYWdlcywgRlVOID0gZnVuY3Rpb24oeCkgew0KICAgIGlmICghcmVxdWlyZSh4LCBjaGFyYWN0ZXIub25seSA9IFRSVUUpKSB7DQogICAgICBpbnN0YWxsLnBhY2thZ2VzKHgsIGRlcGVuZGVuY2llcyA9IFRSVUUpDQogICAgICBsaWJyYXJ5KHgsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkNCiAgICB9DQogIH0pDQp9DQpgYGANCg0KLS0tICANCg0KIyBQYWNrYWdlcw0KDQotIGB0aWR5dmVyc2VgOiBnZW5lcmFsIHBhY2thZ2UgZm9yIGRhdGEgbWFuaXB1bGF0aW9uDQoNCi0gYHN0cmluZ3JgOiB0byBleGVjdXRlIHZhcmlvdXMgc3RyaW5nIG1hbmlwdWxhdGlvbnMNCg0KLSBgc3RyaW5naWA6IHRvIHJlbW92ZSBkaWFjcml0aWNzDQoNCi0gYGthYmxlRXh0cmFgOiB0byBtYWtlIHRhYmxlcyBpbiBSbWFya2Rvd24NCg0KDQpgYGB7ciwgcmVzdWx0cz0naGlkZSd9DQpwYWNrYWdlcyA9IGMoInRpZHl2ZXJzZSIsICJzdHJpbmdyIiwgInN0cmluZ2kiLCAia2FibGVFeHRyYSIpDQoNCmZwYWNrYWdlLmNoZWNrKHBhY2thZ2VzKQ0KDQpgYGANCg0KLS0tIA0KDQoNCiMgSW5wdXQNCg0KV2UgdXNlIG9uZSBtb2NrIGRhdGFzZXQ6DQoNCiogW3BoZF9tZXRhZGYucmRhXShodHRwczovL2dpdGh1Yi5jb20vYW1tdWxkZXJzL2FtYXR0ZXJvZnRpbWUvZGF0YS9waGRfbWV0YWRmLnJkYSk6IHRoaXMgZGF0YXNldCBtaW1pY2tzIHRoZSBzdHJ1Y3R1cmUgb2Ygb3VyIHJhdyBkYXRhLCBidXQgY29udGFpbnMgOCBleGFtcGxlIHJvd3MgdG8gbWFpbnRhaW4gYW5vbnltaXR5Lg0KICAgIC0gbmFtZSBvZiBkYXRhc2V0OiBgcGhkX21ldGFkZmAgDQoNCmBgYHtyIGRhdGFzZXRzLCBjYWNoZT1GQUxTRX0NCg0KbG9hZChmaWxlID0gIi4vZGF0YS9waGRfbWV0YWRmLnJkYSIpDQoNCmBgYA0KDQoNClRoaXMgbGFiIGpvdXJuYWwgaXMgdXNlZCB0byBkZW1vbnN0cmF0ZSBob3cgd2UgZXh0cmFjdCBmaXJzdCBhbmQgbGFzdCBuYW1lcyBmcm9tIFBoRHMuIA0KDQpGb3IgdGhpcywgd2UgdXNlIGFuIGV4YW1wbGUgZGF0YWZyYW1lIGNvbnRhaW5pbmcgOCBvYnNlcnZhdGlvbnMgKDQgZXRobmljIG1ham9yaXR5IG5hbWVzLCAyIGV0aG5pYyBtaW5vcml0eSBuYW1lcywgMiBvdGhlciBuYW1lcyAtIGFsbCBzcGxpdCBlcXVhbGx5IGJldHdlZW4gbWFsZS0gYW5kIGZlbWFsZS10eXBlZCBmaXJzdCBuYW1lcykuIFRoaXMgbW9jayBkYXRhZnJhbWUgbWlycm9ycyB0aGUgc2V0LXVwIG9mIG91ciB3ZWItc2NyYXBlZCBkYXRhLCB3aGljaCBjb25zaXN0cyBvZiBuYW1lIGluZm9ybWF0aW9uIHdoaWNoIGFyZSB3ZWIgc2NyYXBlZCBmcm9tIGRpZmZlcmVudCBzb3VyY2VzLiANCg0KKiAxIGF1dGV1cjogdGhlICdhdXRob3InIGNvbHVtbiBvbiBOQVJDSVMgZGlzc2VydGF0aW9uIHBhZ2VzDQoqIDIgbmFyY2lzbmFtZTogZnVsbCBuYW1lIHRoYXQgaXMgbWVudGlvbmVkIGF0IHRoZSB0b3Agb2YgcGVyc29uYWwgTkFSQ0lTIHBhZ2VzDQoqIDMgcGRmbmFtZSBhbmQgcGRmbmFtZXAxOiBmdWxsIG5hbWVzIG1lbnRpb25lZCBpbiB0aGUgcnVubmluZyB0ZXh0IG9mIGRpc3NlcnRhdGlvbiBQREYsIGFuZCBvbiBjb3ZlciBwYWdlcyBvZiB0aGUgZGlzc2VydGF0aW9uIHByb3ZpZGVkIGJ5IGEgc3Vic2V0IG9mIHVuaXZlcnNpdGllcywgcmVzcGVjdGl2ZWx5Lg0KDQoNCkJlbG93IHlvdSBjYW4gc2VlIHRoZSBleGFtcGxlIGRhdGEsIA0KDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KDQpwaGRfbWV0YWRmICU+JQ0KICBrYWJsZSgpICU+JQ0KICBrYWJsZV9zdHlsaW5nKCkgJT4lDQogIHNjcm9sbF9ib3god2lkdGg9IjEwMCUiKQ0KDQpgYGANCg0KDQoNCi0tLSAgDQoNCg0KDQojIEdhdGhlcmluZyBmaXJzdCBuYW1lcyBmcm9tICdhdXRldXInKEF1dGhvcikgb24gTkFSQ0lTIGRpc3NlcnRhdGlvbiBwYWdlcw0KDQoNClNvbWUgZGlzc2VydGF0aW9ucyBhcHBlYXIgdG8gaGF2ZSBtdWx0aXBsZSBhdXRob3JzLiBXZSBvbmx5IHdhbnQgdGhlIGZpcnN0IGF1dGhvciwgc28gcmVtb3ZlIGV2ZXJ5dGhpbmcgYWZ0ZXIgIjsiDQpgYGB7ciBtdWx0aXBsZS1hdXRob3JzfQ0KDQpwaGRfbWV0YWRmJGF1dGV1ciA8LSBnc3ViKCI7LioiLCAiIiwgcGhkX21ldGFkZiRhdXRldXIpDQoNCmBgYA0KDQoNCiMjIEZpcnN0IG5hbWVzIGluIGJyYWNrZXRzDQpgYGB7ciBicmFja2V0bmFtZXN9DQpwaGRfbWV0YWRmJGZpcnN0bmFtZSA8LSBzdHJfZXh0cmFjdChwaGRfbWV0YWRmJGF1dGV1ciwgIig/PD1cXCgpLiooPz1cXCkpIikNCg0KcGhkX21ldGFkZiRmaXJzdG5hbWUgPC0gaWZlbHNlKHBoZF9tZXRhZGYkZmlyc3RuYW1lID09ICIiLCBOQSwgcGhkX21ldGFkZiRmaXJzdG5hbWUpDQoNCmBgYA0KDQoNCiMjIEZpcnN0IG5hbWVzIGFmdGVyIGEgY29tbWENCg0KYGBge3IgY29tbWFuYW1lc30NCg0KcGhkX21ldGFkZiRjb20gPC0gc3RyX2RldGVjdChwaGRfbWV0YWRmJGF1dGV1ciwgIiwiKSAjIGRldGVjdCBjb21tYQ0KDQojIEtlZXAgZXZlcnl0aGluZyBhZnRlciBhIGNvbW1hIGlmIHRoZXJlIGlzIG9uZQ0KcGhkX21ldGFkZiA8LSBwaGRfbWV0YWRmICU+JQ0KICBtdXRhdGUoZmlyc3RuYW1lID0gaWZlbHNlKChpcy5uYShmaXJzdG5hbWUpICYgY29tPT1UUlVFKSwgc3RyX3JlbW92ZShhdXRldXIsICIuKiwiKSwgZmlyc3RuYW1lKSkgJT4lIHNlbGVjdCgtY29tKQ0KDQpgYGANCg0KYGBge3IgdHJpbXdzfQ0KcGhkX21ldGFkZiRmaXJzdG5hbWUgPC0gdHJpbXdzKHBoZF9tZXRhZGYkZmlyc3RuYW1lLCB3aGljaCA9IGMoImJvdGgiKSwgd2hpdGVzcGFjZSA9ICJbIFx0XHJcbl0iKQ0KYGBgDQoNCg0KIyMgQ2xlYW5pbmcgdGhlIGZpcnN0IG5hbWVzDQoNCk1hbnkgbGFzdCBuYW1lcyBpbmNsdWRlIHNvLWNhbGxlZCAnbm9iaWxpYXJ5IHBhcnRpY2xlcycuIFRoZXNlIGFyZSBhZGRpdGlvbnMgdG8gdGhlIGxhc3QgbmFtZSAoZS5nLiAidmFuIGRlIiBpbiBEdXRjaCwgImRlIGxhIiBpbiBGcmVuY2ggb3IgInp1IiBpbiBHZXJtYW4pLiBJbiBvcmRlciB0byBleHRyYWN0IHRoZSBmaXJzdCBuYW1lcyB3ZSBkZXRlY3QgYW5kIHJlbW92ZSB0aGVzZS4gTm9iaWxpYXJ5IHBhcnRpY2xlcyBoYXZlIGNyZXB0IGludG8gZmlyc3QgbmFtZSB3aGVuIGdhdGhlcmluZyBldmVyeXRoaW5nIGFmdGVyIGEgY29tbWEsIGZvciBleGFtcGxlIHdoZW4gbmFtZXMgYXJlIGluIHRoZSBmb3JtYXQgb2YgIlZyaWVzLCBKYW4gZGUiLiBUaGUgbm9iaWxpYXJ5IHBhcnRpY2xlcyBhcmUgYWxzbyBpbXBvcnRhbnQgdG8gc2VwYXJhdGUgZnJvbSB0aGUgcmVzdCBvZiB0aGUgbGFzdCBuYW1lIHRvIGNyZWF0ZSBtYXRjaGFibGUgbGFzdCBuYW1lcyBsYXRlci4gDQoNCg0KDQpgYGB7ciBjbGVhbmluZy12YW5kZX0NCg0KIyBSZW1vdmluZyBhbGwgbm9iaWxpYXJ5IHBhcnRpY2xlcyB0aGF0IGNvbnNpc3Qgb2YgbXVsdGlwbGUgd29yZHMNCnZhbmRlMCA8LSBjKCIoVnx2KWFuIChEfGQpZXIiLCAiKFZ8dilhbiAoRHxkKWVuIiwgIihWfHYpYW4gKER8ZCllIiwgIihWfHYpYW5kZShuKT8iLCAiKFZ8dilhbiAnKFR8dCkiLCAiKFZ8dilhbicoVHx0KSIsICIoVnx2KWFuIChUfHQpIiwgIihWfHYpYW4gKEh8aClldCIsICIoVnx2KW9uIChEfGQpZXIiLCAiKE98bylwIGRlbiIsICIoT3xvKXAgJ3QiLCAiKE98bylmIHRlbiIsICIoQXxhKWFuIGRlKG4pPyIsICIoRHxkKWUgKEx8bClhIiwgIihJfGkpbiAoSHxoKWV0IiwgIihJfGkpbiAnKFR8dCkiLCAiKEl8aSluJyhUfHQpIiwiKEl8aSluIChUfHQpIiwgIihJfGkpbiAoRHxkKWVyIiwgIihCfGIpaWogKER8ZCllIikgDQoNCg0KIyBTb21lIG9mIHRoZSBub2JpbGlhcnkgcGFydGljbGVzIGNhbiBhY3R1YWxseSBiZSBwYXJ0IG9mIHRoZSBmaXJzdCBuYW1lLCBlLmcuICJBbCIgaW4gdGhlIG5hbWUgIkFsaWNlIi4gVGhlc2UgcmVxdWlyZSBzb21lIG1vcmUgY2FyZSB0byByZW1vdmU6IG9ubHkgcmVtb3ZlIHRoZXNlIHdoZW4gc3Vycm91bmRlZCBieSB3aGl0ZXNwYWNlcyBvciB3aGVuIHRoZXkgdGFrZSB1cCB0aGUgZW50aXJlIG5hbWUuICANCg0KIyBXaGl0ZXNwYWNlcyBhcm91bmQgdmFuL2RlDQp2YW5kZTEgPC0gYygiXFxzKEx8bClhXFxzIiwgIlxccyhPfG8pcFxccyIgLCJcXHMoVnx2KWFuXFxzIiwgIlxccyhWfHYpb25cXHMiLCAiXFxzKER8ZCllblxccyIsICJcXHMoRHxkKWVyXFxzIiwgIlxccyhEfGQpZWxcXHMiLCAiXFxzKER8ZCkoZXxhfHV8aSlcXHMiLCAiXFxzKER8ZClvcz9cXHMiLCAiXFxzKFR8dCllclxccyIsICJcXHMoVHx0KWVuXFxzIiwgIlxccyhUfHQpZVxccyIsICJcXHMnKFR8dClcXHMiLCAiXFxzKEx8bCllXFxzIiwgIlxccyhFfEEpbC0iLCAiXFxzWyhBfGEpKEV8ZSldKEx8bCknP1xccyIsICJcXHMoRHxkKSciLCAiXFxzenVcXHMiLCAiXFxzKFp8eil1clxccyIsICJcXHMoWXx5KVxccyIsICJcXHMoRXxlKVxccyIpIA0KDQoNCiMgRW50aXJlIHN0cmluZyBjb25zaXN0cyBvZiB2YW4vZGUNCnZhbmRlMiA8LSBjKCJeKEx8bClhJCIsICJeKE98bylwJCIgLCAiXihWfHYpYW4kIiwgIl4oVnx2KW9uJCIsICJeKER8ZCllbiQiLCAiXihEfGQpZXIkIiwgIl4oRHxkKWVsJCIsICJeKER8ZCkoZXxhfHV8aSkkIiwgIl4oRHxkKW9zPyQiLCAiXlZhbmRlWyQvL3NdIiwgIl4oVHx0KWVyJCIsICAiXihUfHQpZW4kIiwgIl4oVHx0KWUkIiwgIl4nKFR8dCkkIiwgIl4oTHxsKWUkIiwgIl5bKEF8YSkoRXxlKV0oTHxsKSc/JCIsICJeKER8ZCknJCIsICJeenUkIiwgIl4oWnx6KXVyJCIpDQoNCg0KIyBTdHJpbmcgc3RhcnRzIHdpdGggdmFuL2RlIGZvbGxvd2VkIGJ5IGEgd2hpdGVzcGFjZQ0KdmFuZGUzIDwtIGMoIl4oTHxsKWFcXHMiLCAiXihPfG8pcFxccyIgLCJeKFZ8dilhblxccyIsICJeKFZ8dilvblxccyIsICJeKER8ZCllblxccyIsICJeKER8ZCllclxccyIsICJeKER8ZCllbFxccyIsICJeKER8ZCkoZXxhfHV8aSlcXHMiLCAiXihEfGQpb3M/XFxzIiwgIl4oVHx0KWVyXFxzIiAsICJeKFR8dCllblxccyIsICJeKFR8dCllXFxzIiwgIl4nKFR8dClcXHMiLCAiXihMfGwpZVxccyIsICJeRWwtIiwgIl5bKEF8YSkoRXxlKV0oTHxsKSc/XFxzIiwgIl4oRHxkKSciLCAiXnp1XFxzIiwgIl4oWnx6KXVyXFxzIiwgIl5lXFxzIikNCg0KDQojIFN0cmluZyBlbmRzIHdpdGggdmFuL2RlDQp2YW5kZTQgPC0gYygiXFxzKEx8bClhJCIsICJcXHMoT3xvKXAkIiAsIlxccyhWfHYpYW4kIiwgIlxccyhWfHYpb24kIiwgIlxccyhEfGQpZW4kIiwgIlxccyhEfGQpZXIkIiwgIlxccyhEfGQpZWwkIiwgIlxccyhEfGQpKGV8YXx1fGkpJCIsICJcXHMoRHxkKW9zPyQiLCAiXFxzKFR8dCllciQiLCAiXFxzKFR8dCllbiQiLCAiXFxzKFR8dCllJCIsICJcXHMnKFR8dCkkIiwgIlxccyhMfGwpZSQiLCAiXFxzWyhBfGEpKEV8ZSldKEx8bCknPyQiLCAiXFxzKER8ZCknJCIsICJcXHN6dSQiLCAiXFxzKFp8eil1ciQiKQ0KDQoNCg0KIyByZW1vdmUgdGhlIG5vYmlsaWFyeSBwYXJ0aWNsZXMgaW4gZGlmZmVyZW50IGZvcm1zDQpwaGRfbWV0YWRmJGZpcnN0bmFtZSA8LSBzdHJfcmVtb3ZlKHBoZF9tZXRhZGYkZmlyc3RuYW1lLCBwYXN0ZTAodmFuZGUwLCBjb2xsYXBzZT0ifCIpKQ0KcGhkX21ldGFkZiRmaXJzdG5hbWUgPC0gc3RyX3JlcGxhY2VfYWxsKHBoZF9tZXRhZGYkZmlyc3RuYW1lLCBwYXN0ZSh2YW5kZTEsIGNvbGxhcHNlID0gInwiKSwgIiIpDQpwaGRfbWV0YWRmJGZpcnN0bmFtZSA8LSBzdHJfcmVtb3ZlX2FsbChwaGRfbWV0YWRmJGZpcnN0bmFtZSwgcGFzdGUodmFuZGUyLCBjb2xsYXBzZSA9ICJ8IikpDQpwaGRfbWV0YWRmJGZpcnN0bmFtZSA8LSBzdHJfcmVwbGFjZV9hbGwocGhkX21ldGFkZiRmaXJzdG5hbWUsIHBhc3RlKHZhbmRlMywgY29sbGFwc2UgPSAifCIpLCAiIikNCnBoZF9tZXRhZGYkZmlyc3RuYW1lIDwtIHN0cl9yZW1vdmUocGhkX21ldGFkZiRmaXJzdG5hbWUsIHBhc3RlKHZhbmRlNCwgY29sbGFwc2UgPSAifCIpKQ0KDQoNCmBgYA0KDQoNCg0KIyMjIFJlbW92aW5nIGluaXRpYWxzIGFmdGVyIHRoZSBjb21tYSBpbiBhdXRldXIgIA0KDQpTaW5jZSB3ZSBleHRyYWN0ZWQgZXZlcnl0aGluZyBhZnRlciB0aGUgY29tbWEsIHNvbWUgb2YgdGhlIGZpcnN0IG5hbWVzIGNvbnRhaW4gaW5pdGlhbHMsIGUuZy46ICJTbWl0aCwgQS5CLkMuIi4gV2UgcmVtb3ZlIHRoZXNlLiANCg0KDQpgYGB7ciBleHRyYWN0LWluaXRpYWxzLWFmdGVyLWNvbW1hfQ0KDQpwaGRfbWV0YWRmJGZpcnN0bmFtZSA8LSB0cmltd3MocGhkX21ldGFkZiRmaXJzdG5hbWUsIHdoaWNoID0gImJvdGgiKQ0KDQoNCiMgVGhlcmUgYXJlIG11bHRpcGxlIHBhdHRlcm5zLCBhbmQgd2Ugd2FudCB0byBleHRyYWN0IGFsbCBwb3NzaWJsZSBmb3JtcyBvZiBpbml0aWFscyBpbnRvIG91ciBvYmplY3QNCg0KaW5pdGlhbHBhdHRlcm4gPC0gcGFzdGUoYygiXlxccz8oWzp1cHBlcjpdXFwuKStbOnVwcGVyOl1cXHM/JCIsICAgIyBBLkEuQSAobGFzdCBpbml0aWFsIGRvZXMgbm90IGNvbnRhaW4gYSBwZXJpb2QgYXQgdGhlIGVuZCkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIihbOnVwcGVyOl1cXC4/XFwtXFwuPykrIiwgICAgICAgICAgICAgICAgICAjIEEtIG9yIEEtLiBvciBBLi0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgIihbOnVwcGVyOl1cXC4rKSsiLCAiKFs6bG93ZXI6XVxcLil7Mix9IiwgICAjIEEuICBvciBhLg0KICAgICAgICAgICAgICAgICAgICAgICAgICAiKFR8dHxDfGN8UHxwKWhcXC5cXHM/IiwgICAgICAgICAgICAgICAgICAgICMgVGguIFBoLiBDaC4gDQogICAgICAgICAgICAgICAgICAgICAgICAgICJeXFxzPyhbOmFscGhhOl1cXHMpKyIsICAgICAgICAgICAgICAgICAgICAgIyBBIG9yIGEgc3Vycm91bmRlZCBieSB3aGl0ZXNwYWNlDQogICAgICAgICAgICAgICAgICAgICAgICAgICJeXFxzP1s6YWxwaGE6XVxcLj9cXHM/JCIsICAgICAgICAgICAgICAgICAgIyBlbnRpcmUgc3RyaW5nIGNvbnNpc3RzIG9mIGEgc2luZ2xlIGxldHRlcg0KICAgICAgICAgICAgICAgICAgICAgICAgICAiXlxccz9bOnVwcGVyOl17Miw0fVxccz8kIiksICAgICAgICAgICAgICAgICMgZW50aXJlIHN0cmluZyBjb25zaXN0cyBvZiAyLTQgY2FwaXRhbCBsZXR0ZXJzDQogICAgICAgICAgICAgICAgICAgICAgICBjb2xsYXBzZSA9ICJ8IikNCg0KDQpwaGRfbWV0YWRmJGluaXRpYWxzMiA8LSBhcy5jaGFyYWN0ZXIoKHN0cl9leHRyYWN0X2FsbChwaGRfbWV0YWRmJGZpcnN0bmFtZSwgaW5pdGlhbHBhdHRlcm4pKSkNCg0KDQojIElmIHRoZXJlIHdlcmUgbXVsdGlwbGUgZGlmZmVyZW50IHBhdHRlcm5zIHByZXNlbnQgaW4gdGhlIGluaXRpYWxzLCB0aGV5IHdlcmUgY29tYmluZWQgaW4gYSBjKCkgb2JqZWN0LiBSZW1vdmUgdGhlIHVubmVjZXNzYXJ5IHRleHQgaGVyZS4gDQpwaGRfbWV0YWRmJGluaXRpYWxzMiA8LSBnc3ViKCJjXFwoXCIiLCAiIiwgcGhkX21ldGFkZiRpbml0aWFsczIpDQpwaGRfbWV0YWRmJGluaXRpYWxzMiA8LSBnc3ViKCJcIiwgXCIiLCAiIiwgcGhkX21ldGFkZiRpbml0aWFsczIpDQpwaGRfbWV0YWRmJGluaXRpYWxzMiA8LSBnc3ViKCJcIlxcKSIsICIiLCBwaGRfbWV0YWRmJGluaXRpYWxzMikNCg0KDQpgYGANCg0KDQpJbiBvcmRlciB0byBleHRyYWN0IGZpcnN0IG5hbWVzLCB3ZSByZW1vdmUgdGhlIGluaXRpYWxzIGdhdGhlcmVkIGluIHRoZSBjaHVuayBhYm92ZS4NCg0KDQpgYGB7ciBleHRyYWN0LWZpcnN0LW5hbWVzfQ0KDQpwaGRfbWV0YWRmJGZpcnN0bmFtZSA8LSBzdHJfcmVtb3ZlKHBoZF9tZXRhZGYkZmlyc3RuYW1lLCBwaGRfbWV0YWRmJGluaXRpYWxzMikNCg0KcGhkX21ldGFkZiRmaXJzdG5hbWUgPC0gdHJpbXdzKHBoZF9tZXRhZGYkZmlyc3RuYW1lLCB3aGljaCA9ICJib3RoIikNCg0KcGhkX21ldGFkZiA8LSBzdWJzZXQocGhkX21ldGFkZiwgc2VsZWN0PS1pbml0aWFsczIpDQoNCmBgYA0KDQpGaW5hbCBjbGVhbmluZyBzdGVwcw0KDQpgYGB7cn0NCg0KcGhkX21ldGFkZiRmaXJzdG5hbWUgPC0gZ3N1YigiLy4qIiwgIiIsIHBoZF9tZXRhZGYkZmlyc3RuYW1lKSAjIFNvbWUgbmFtZXMgaW4gdGhlIGZvcm0gIkZsb29yL0Zsb3JpcyIuIFJlbW92ZSBldmVyeXRoaW5nIGFmdGVyICIvIg0KDQojIG1ha2UgdGhlIG5hbWVzIGxvd2VyY2FzZQ0KcGhkX21ldGFkZiRmaXJzdG5hbWUgPC0gdG9sb3dlcihwaGRfbWV0YWRmJGZpcnN0bmFtZSkNCg0KIyByZW1vdmUgZGlhY3JpdGljcw0KcGhkX21ldGFkZiRmaXJzdG5hbWUgPC0gc3RyaV90cmFuc19nZW5lcmFsKHBoZF9tZXRhZGYkZmlyc3RuYW1lLCBpZCA9ICJsYXRpbi1hc2NpaSIpDQoNCiMgcmVtb3ZlIG5vbi1sZXR0ZXIgY2hhcmFjdGVycywgdGFraW5nIHRoZSBmaXJzdCBtZW50aW9uZWQgbmFtZQ0KcGhkX21ldGFkZiRmaXJzdG5hbWUgPC0gc3RyX2V4dHJhY3QocGhkX21ldGFkZiRmaXJzdG5hbWUsICJbYS16XStcXC0qW2Etel0qIikNCg0KIyByZW1vdmluZyB3aGl0ZSBzcGFjZXMgYXQgdGhlIGJlZ2lubmluZyBhbmQgYXQgdGhlIGVuZCBvZiB0aGUgbmFtZSBmaXJzdCBuYW1lIHN0cmluZw0KcGhkX21ldGFkZiRmaXJzdG5hbWUgPC0gdHJpbXdzKHBoZF9tZXRhZGYkZmlyc3RuYW1lLCB3aGljaCA9ICJib3RoIikNCg0KIyByZW1vdmluZyBub2JpbGlhcnkgcGFydGljbGVzIHdoaWNoIHNsaXBwZWQgdGhyb3VnaA0KcGhkX21ldGFkZiRmaXJzdG5hbWUgPC0gc3RyX3JlbW92ZV9hbGwocGhkX21ldGFkZiRmaXJzdG5hbWUsIHBhc3RlKHZhbmRlMiwgY29sbGFwc2UgPSAifCIpKQ0KDQpwaGRfbWV0YWRmIDwtIHBoZF9tZXRhZGYgJT4lDQogIG11dGF0ZShmaXJzdG5hbWUgPSBpZmVsc2UoKGZpcnN0bmFtZSA9PSAiXlxccyQiIHwgZmlyc3RuYW1lID09ICIiKSAsTkEsIGZpcnN0bmFtZSkpICMgZW1wdHkgc3RyaW5nIHRvIE5BDQoNCnBoZF9tZXRhZGYkZmlyc3RuYW1lIDwtIGlmZWxzZShuY2hhcihwaGRfbWV0YWRmJGZpcnN0bmFtZSk9PTEsIE5BLCBwaGRfbWV0YWRmJGZpcnN0bmFtZSkgIyBzaW5nbGUtY2hhcmFjdGVyIHN0cmluZyAoaS5lLiBpbml0aWFsKSB0byBOQQ0KDQoNCmBgYA0KDQoNCiMgTGFzdCBuYW1lcyBmcm9tICdhdXRldXInIG9uIE5BUkNJUyBkaXNzZXJ0YXRpb24gcGFnZQ0KDQoNCkZpcnN0LCB3ZSBleHRyYWN0IGxhc3QgbmFtZXMgaW4gdGhlIGZvcm1hdCAibGFzdG5hbWUgY29tbWEgZmlyc3RuYW1lIg0KDQpgYGB7ciBsYXN0LW5hbWVzMX0NCg0KIyByZW1vdmUgZXZlcnl0aGluZyBhZnRlciBhIGNvbW1hDQpwaGRfbWV0YWRmJGxhc3RuYW1lIDwtIGdzdWIoIiwuKiQiLCAiIiwgcGhkX21ldGFkZiRhdXRldXIpIA0KDQojIHJlbW92ZSBkaWFjcml0aWNzDQpwaGRfbWV0YWRmJGxhc3RuYW1lIDwtIHN0cmlfdHJhbnNfZ2VuZXJhbChwaGRfbWV0YWRmJGxhc3RuYW1lLCBpZCA9ICJsYXRpbi1hc2NpaSIpDQoNCiMgd2UgYXNzdW1lIHRoYXQgVi9ELCB2L2QgYW5kIHYuZC4gaW5kaWNhdGUgdGhlIHBvcHVsYXIgRHV0Y2ggbm9iaWxpYXJ5IHBhcnRpY2xlICJ2YW4gZGUiDQpwaGRfbWV0YWRmJGxhc3RuYW1lIDwtIHN0cl9yZXBsYWNlKHBoZF9tZXRhZGYkbGFzdG5hbWUsICIodlxcLmRcXC4pfCgoVnx2KS8oRHxkKSkiLCAidmFuIGRlIikNCg0KDQojIHJlbW92ZSBpbml0aWFscw0KcGhkX21ldGFkZiRsYXN0bmFtZSA8LSBzdHJfcmVtb3ZlX2FsbChwaGRfbWV0YWRmJGxhc3RuYW1lLCBpbml0aWFscGF0dGVybikgIyBvYmplY3QgaW5pdGlhbHBhdHRlcm4gZGVmaW5lZCBpbiBzZWN0aW9uIDENCnBoZF9tZXRhZGYkbGFzdG5hbWUgPC0gdHJpbXdzKHBoZF9tZXRhZGYkbGFzdG5hbWUsIHdoaWNoID0gImJvdGgiKSAjIHJlbW92aW5nIHdoaXRlc3BhY2UNCg0KDQojIHJlbW92ZSB0aXRsZXMNCnBoZF9tZXRhZGYkbGFzdG5hbWUgPC0gdHJpbXdzKHBoZF9tZXRhZGYkbGFzdG5hbWUsIHdoaWNoID0gImJvdGgiKQ0KcGhkX21ldGFkZiRsYXN0bmFtZSA8LSBzdHJfcmVtb3ZlX2FsbChwaGRfbWV0YWRmJGxhc3RuYW1lLCAiKF4oTXxtKXJcXC4/XFxzKXwoXihEfGQpcnM/XFwuP1xccyl8KF5TdFxcLlxccyl8KF4oTXxNKXI/c1xcLj9cXHMpfCheZXh0XFwuXFxzKXwoXihNfG0pZFxcLj9cXHMpIikNCg0KDQojIHJlbW92ZSBmaXJzdCBuYW1lcyBiZXR3ZWVuIGJyYWNrZXRzIGZyb20gdGhlIGxhc3QgbmFtZQ0KcGhkX21ldGFkZiRsYXN0bmFtZSA8LSBzdHJfcmVtb3ZlX2FsbChwaGRfbWV0YWRmJGxhc3RuYW1lLCAiXFxzXFwoLipcXCkkIikNCg0KDQojIE5leHQsIHdlIGV4dHJhY3QgdGhlIG5vYmlsaWFyeSBwYXJ0aWNsZXMgYW5kIHNhdmUgdGhlc2UgaW4gYSBzZXBhcmF0ZSBvYmplY3QuIFRoZXNlIGNhbiBiZSB1c2VkIHdoZW4gbWF0Y2hpbmcgbmFtZXMgdG8gb3RoZXIgZGF0YWJhc2VzIGxhdGVyLiANCg0KcGhkX21ldGFkZiRsYXN0bmFtZSA8LSB0cmltd3MocGhkX21ldGFkZiRsYXN0bmFtZSwgd2hpY2ggPSAiYm90aCIpICMgZmlyc3QsIHdlIHRyaW0gd2hpdGVzcGFjZXMNCg0KIyBleHRyYWN0IG5vYmlsaWFyeSBwYXJ0aWNsZXMgYXQgdGhlIGJlZ2lubmluZyBvZiB0aGUgbGFzdCBuYW1lIHN0cmluZyAodmFuZGUzKQ0KcGhkX21ldGFkZiRucCA8LSBzdHJfZXh0cmFjdChwaGRfbWV0YWRmJGxhc3RuYW1lLCBwYXN0ZSh2YW5kZTMsIGNvbGxhcHNlID0gInwiKSkgIyBleHRyYWN0IGludG8gbmV3IHZhcmlhYmxlIG5wDQpwaGRfbWV0YWRmJGxhc3RuYW1lIDwtIHN0cl9yZW1vdmUocGhkX21ldGFkZiRsYXN0bmFtZSwgcGFzdGUodmFuZGUzLCBjb2xsYXBzZSA9ICJ8IikpICMgcmVtb3ZlIGZyb20gbGFzdG5hbWUgdmFyaWFibGUNCg0KIyBleHRyYWN0IG5vYmlsaWFyeSBwYXJ0aWNsZXMgYXQgdGhlIGVuZCBvZiB0aGUgYXV0ZXVyIHN0cmluZyAodmFuZGU0KQ0KIyBmaXJzdCBkZXRlY3QsIG9yIGVsc2UgaXQgb3ZlcndyaXRlcyB0aGUgbnAgd2l0aCBOQSBpZiBub3QgYXBwbGljYWJsZQ0KcGhkX21ldGFkZiRlbmQgPC0gYXMubnVtZXJpYyhzdHJfZGV0ZWN0KHBoZF9tZXRhZGYkYXV0ZXVyLCBwYXN0ZSh2YW5kZTQsIGNvbGxhcHNlID0gInwiKSkpDQpwaGRfbWV0YWRmJG5wIDwtIGlmZWxzZShwaGRfbWV0YWRmJGVuZD09MSwgc3RyX2V4dHJhY3QocGhkX21ldGFkZiRhdXRldXIsIHBhc3RlKHZhbmRlNCwgY29sbGFwc2UgPSAifCIpKSwgcGhkX21ldGFkZiRucCkgI29ubHkgZXh0cmFjdCBpZiBucCBpcyBkZXRlY3RlZCBhdCB0aGUgZW5kDQpwaGRfbWV0YWRmIDwtIHN1YnNldChwaGRfbWV0YWRmLCBzZWxlY3QgPSAtZW5kKQ0KDQojIGFsc28gZXh0cmFjdCBub2JpbGlhcnkgcGFydGljbGVzIGF0IHRoZSBlbmQgb2YgdGhlIGxhc3RuYW1lIHN0cmluZyAodmFuZGU0KQ0KcGhkX21ldGFkZiRlbmQgPC0gYXMubnVtZXJpYyhzdHJfZGV0ZWN0KHBoZF9tZXRhZGYkbGFzdG5hbWUsIHBhc3RlKHZhbmRlNCwgY29sbGFwc2UgPSAifCIpKSkNCnBoZF9tZXRhZGYkbnAgPC0gaWZlbHNlKHBoZF9tZXRhZGYkZW5kPT0xLCBzdHJfZXh0cmFjdChwaGRfbWV0YWRmJGxhc3RuYW1lLCBwYXN0ZSh2YW5kZTQsIGNvbGxhcHNlID0gInwiKSksIHBoZF9tZXRhZGYkbnApDQpwaGRfbWV0YWRmJGxhc3RuYW1lIDwtIHN0cl9yZW1vdmUocGhkX21ldGFkZiRsYXN0bmFtZSwgcGFzdGUodmFuZGU0LCBjb2xsYXBzZSA9ICJ8IikpDQpwaGRfbWV0YWRmIDwtIHN1YnNldChwaGRfbWV0YWRmLCBzZWxlY3QgPSAtZW5kKSAjcmVtb3ZlIGludGVybWVkaWF0ZSBvYmplY3QNCg0KIyB0cmltIHdoaXRlIHNwYWNlcyBpbiB0aGUgbm92aWxpYXJ5IHBhcnRpY2xlDQpwaGRfbWV0YWRmJG5wIDwtIHRyaW13cyhwaGRfbWV0YWRmJG5wLCB3aGljaCA9ICJib3RoIikNCg0KIyByZW1vdmluZyBtdWx0aXBsZSBzcGFjZXMNCnBoZF9tZXRhZGYkbGFzdG5hbWUgPC0gc3ViKCJcXHN7Mix9IiwgIlxccyIsIHBoZF9tZXRhZGYkbGFzdG5hbWUpDQpwaGRfbWV0YWRmJGxhc3RuYW1lIDwtIHRyaW13cyhwaGRfbWV0YWRmJGxhc3RuYW1lLCB3aGljaCA9ICJib3RoIikNCg0KIyByZW1vdmluZyAiLSIgZnJvbSBub2JpbGlhcnkgcGFydGljbGUgRWwtIG9yIEFsLSBhbmQgIiciIGZvciAndCANCnBoZF9tZXRhZGYkbnAgPC0gc3RyX3JlbW92ZShwaGRfbWV0YWRmJG5wLCAiLSIpDQpwaGRfbWV0YWRmJG5wIDwtIHN0cl9yZW1vdmUocGhkX21ldGFkZiRucCwgIlwnIikNCg0KIyByZW1vdmUgSnIuDQpwaGRfbWV0YWRmJGxhc3RuYW1lIDwtIHN0cl9yZW1vdmUocGhkX21ldGFkZiRsYXN0bmFtZSwgIlxcc0pyXFwuJCIpDQpwaGRfbWV0YWRmJGxhc3RuYW1lIDwtIHN0cl9yZW1vdmUocGhkX21ldGFkZiRsYXN0bmFtZSwgIlxcc0p1bmlvciQiKQ0KDQojIHJlbW92ZSBpbnRlcnB1bmN0aW9uDQpwaGRfbWV0YWRmJGxhc3RuYW1lIDwtIHN0cl9yZW1vdmVfYWxsKHBoZF9tZXRhZGYkbGFzdG5hbWUsICIoXFw/KXwoXFxgKXwoXFxeKXwoXlxcJyl8KFxcwrQpfChcXMK3KSIpDQoNCiMgbmFtZXMgYW5kIG5vYmlsaWFyeSBwYXJ0aWNsZXMgdG8gbG93ZXJjYXNlDQpwaGRfbWV0YWRmJGxhc3RuYW1lIDwtIHRvbG93ZXIocGhkX21ldGFkZiRsYXN0bmFtZSkNCnBoZF9tZXRhZGYkbnAgPC0gdG9sb3dlcihwaGRfbWV0YWRmJG5wKQ0KDQojIHdlIG9ubHkgd2FudCB0aGUgZmlyc3QgbGFzdCBuYW1lIGlmIHRoZXJlIGFyZSBtdWx0aXBsZQ0KcGhkX21ldGFkZiRsYXN0bmFtZSA8LSBzdHJfZXh0cmFjdChwaGRfbWV0YWRmJGxhc3RuYW1lLCAiWzpsb3dlcjpdKyIpDQoNCg0KIyBjb21iaW5pbmcgbm9iaWxpYXJ5IHBhcnRpY2xlIGFuZCBsYXN0IG5hbWUgaW50byBhIHNlcGFyYXRlIG9iamVjcg0KcGhkX21ldGFkZiAlPiUNCiAgbXV0YXRlKGxhc3RuYW1lX2Z1bGwgPSBpZmVsc2UoIWlzLm5hKG5wKSwgcGFzdGUobnAsIGxhc3RuYW1lKSwgbGFzdG5hbWUpKSAtPiBwaGRfbWV0YWRmDQoNCg0KYGBgDQoNCg0KDQojIEV4dHJhY3RpbmcgZmlyc3QgbmFtZXMgZnJvbSBwZXJzb25hbCBOQVJDSVMgcHJvZmlsZXMNCg0KSW4gdGhlIGZvbGxvd2luZyBwYXJ0IG9mIHRoZSBzY3JpcHQsIGZpcnN0IG5hbWVzIGZyb20gcGVyc29uYWwgTkFSQ0lTIHByb2ZpbGVzIHdpbGwgYmUgY2xlYW5lZC4gVGhlIG1ldGhvZCBoZXJlIGlzIHJvdWdobHkgdGhlIHNhbWUgYXMgdGhlIG1ldGhvZCB1c2VkIHRvIGNsZWFuIHRoZSBmaXJzdCBuYW1lcyBmcm9tIHRoZSAnQXV0aG9yJyBzZWN0aW9uIG9mIGRpc3NlcnRhdGlvbiBOQVJDSVMgcGFnZXMuIA0KDQpUaGUgY2xlYW5lZCBmaXJzdCBuYW1lcyBhcmUgc3RvcmVkIGluIGFuIGludGVybWVkaWF0ZSBvYmplY3QsICJpbnQiLCB0byBlbnN1cmUgdGhhdCB0aGUgb3JpZ2luYWwgc2NyYXBlZCBuYW1lIGlzIHByZXNlcnZlZCBpbiAibmFyY2lzbmFtZSIuIA0KDQoNCiMjIEV4dHJhY3QgZmlyc3QgbmFtZXMgaW4gYnJhY2tldHMNCg0KRS5nLiAiQS5CLkMuIChBbmRyZWEpIFNtaXRoIg0KDQpgYGB7ciBuYXJjaXNuYW1lLWJyYWNrZXRzfQ0KDQpwaGRfbWV0YWRmJGludCA8LSBzdHJfZXh0cmFjdChwaGRfbWV0YWRmJG5hcmNpc25hbWUsICIoPzw9XFwoKS4qKD89XFwpKSIpDQoNCnBoZF9tZXRhZGYkaW50IDwtIGlmZWxzZShwaGRfbWV0YWRmJGludCA9PSAiIiwgTkEsIHBoZF9tZXRhZGYkaW50KQ0KDQpgYGANCg0KDQojIyBFeHRyYWN0IGV2ZXJ5dGhpbmcgYWZ0ZXIgYSBjb21tYQ0KDQoNCkUuZy4gIlNtaXRoLCBBbmRyZWEiDQoNCmBgYHtyIG5hcmNpc25hbWUtY29tbWF9DQoNCnBoZF9tZXRhZGYkY29tbWEgPC0gc3RyX2RldGVjdChwaGRfbWV0YWRmJG5hcmNpc25hbWUsICIsIikgIyBvbmx5IHdoZW4gbmFyY2lzbmFtZSBjb250YWlucyBhIGNvbW1hDQoNCnBoZF9tZXRhZGYgPC0gcGhkX21ldGFkZiAlPiUgDQogIG11dGF0ZShpbnQgPSBpZmVsc2UoKGlzLm5hKGludCkgJiBjb21tYT09VFJVRSksIHN0cl9yZW1vdmUobmFyY2lzbmFtZSwgIi4qLCIpLCBpbnQpKQ0KDQpwaGRfbWV0YWRmJGludCA8LSB0cmltd3MocGhkX21ldGFkZiRpbnQsIHdoaWNoID0gYygiYm90aCIpKQ0KDQpwaGRfbWV0YWRmIDwtIHN1YnNldChwaGRfbWV0YWRmLCBzZWxlY3QgPSAtY29tbWEpDQoNCmBgYA0KDQoNCiMjIENsZWFuaW5nIE5hcmNpcyBuYW1lcw0KDQpTaW1pbGFyIGFwcHJvYWNoIHRvIGV4dHJhY3Rpb24gb2YgZmlyc3QgbmFtZXMgZnJvbSAnQXV0ZXVyJywgbWVhbmluZyB3ZSByZW1vdmUgbm9uLW5hbWUgc3RyaW5ncyBmcm9tIHRoZSBuYW1lIG9iamVjdCAobm9iaWxpYXJ5IHBhcnRpY2xlcywgaW5pdGlhbHMsIHRpdGxlcywgcHVuY3R1YXRpb24pIA0KDQpgYGB7ciBuYXJjaXMtY2xlYW5pbmd9DQoNCiMgbm9iaWxpYXJ5IHBhcnRpY2xlcyBhdCBkaWZmZXJlbnQgcGxhY2VzIGluIHRoZSBzdHJpbmcNCnBoZF9tZXRhZGYkaW50IDwtIHN0cl9yZW1vdmUocGhkX21ldGFkZiRpbnQsIHBhc3RlMCh2YW5kZTAsIGNvbGxhcHNlPSJ8IikpDQpwaGRfbWV0YWRmJGludCA8LSBzdHJfcmVtb3ZlKHBoZF9tZXRhZGYkaW50LCBwYXN0ZSh2YW5kZTEsIGNvbGxhcHNlID0gInwiKSkNCnBoZF9tZXRhZGYkaW50IDwtIHN0cl9yZW1vdmUocGhkX21ldGFkZiRpbnQsIHBhc3RlKHZhbmRlMiwgY29sbGFwc2UgPSAifCIpKQ0KcGhkX21ldGFkZiRpbnQgPC0gc3RyX3JlbW92ZShwaGRfbWV0YWRmJGludCwgcGFzdGUodmFuZGUzLCBjb2xsYXBzZSA9ICJ8IikpDQpwaGRfbWV0YWRmJGludCA8LSBzdHJfcmVtb3ZlKHBoZF9tZXRhZGYkaW50LCBwYXN0ZSh2YW5kZTQsIGNvbGxhcHNlID0gInwiKSkNCg0KIyByZW1vdmluZyBpbml0aWFscyANCnBoZF9tZXRhZGYkaW50IDwtIHN0cl9yZW1vdmVfYWxsKHBoZF9tZXRhZGYkaW50LCBpbml0aWFscGF0dGVybikgIyBvYmplY3QgaW5pdGlhbHBhdHRlcm4gZGVmaW5lZCBpbiBzZWN0aW9uIDENCg0KIyBuZXh0LCB3ZSByZW1vdmUgYSBudW1iZXIgb2YgZGlmZmVyZW50IHRpdGxlcyB0aGF0IGNhbiBiZSBmb3VuZCBpbiB0aGUgbmFtZSBvYmplY3QNCnBoZF9tZXRhZGYkaW50IDwtIHN0cl9yZW1vdmVfYWxsKHBoZF9tZXRhZGYkaW50LCAiKE1TYyl8KE1BKXwoTVBoaWwpfChQaEQpfChNclxcLil8KF5Ncil8KChEfGQpcnM/XFwuKXwoTWRcXC4pfChNcj9zXFwuKSIpDQoNCg0KcGhkX21ldGFkZiRpbnQgPC0gZ3N1YigiLy4qIiwgIiIsIHBoZF9tZXRhZGYkaW50KSAjIHNvbWUgbmFtZXMgaW4gdGhlIGZvcm0gIkZsb29yL0Zsb3JpcyIuIFJlbW92ZSBldmVyeXRoaW5nIGFmdGVyICIvIg0KDQoNCiMgZmluYWxseSwgd2UgZG8gc29tZSBnZW5lcmFsIGNsZWFuaW5nIG9mIHRoZSBuYW1lcw0KcGhkX21ldGFkZiRpbnQgPC0gdHJpbXdzKHBoZF9tZXRhZGYkaW50LCB3aGljaCA9ICJib3RoIikNCg0KcGhkX21ldGFkZiRpbnQgPC0gdG9sb3dlcihwaGRfbWV0YWRmJGludCkgIyBzZXQgbmFtZXMgdG8gbG93ZXJjYXNlDQoNCiMgcmVtb3ZlIGRpYWNyaXRpY3MgZnJvbSB0aGUgbmFtZQ0KcGhkX21ldGFkZiRpbnQgPC0gc3RyaV90cmFuc19nZW5lcmFsKHBoZF9tZXRhZGYkaW50LCBpZCA9ICJsYXRpbi1hc2NpaSIpDQoNCiMga2VlcCBvbmx5IHRoZSBmaXJzdC1tZW50aW9uZWQgbmFtZQ0KcGhkX21ldGFkZiRpbnQgPC0gc3RyX2V4dHJhY3QocGhkX21ldGFkZiRpbnQsICJbYS16XStcXC0qW2Etel0qIikNCg0KDQpwaGRfbWV0YWRmIDwtIHBoZF9tZXRhZGYgJT4lDQogIG11dGF0ZShpbnQgPSBpZmVsc2UoKGludCA9PSAiXi8vcyQiIHwgaW50ID09ICIiKSAsTkEsIGludCkpICMgZW1wdHkgdG8gTkENCg0KcGhkX21ldGFkZiRpbnQgPC0gdHJpbXdzKHBoZF9tZXRhZGYkaW50LCB3aGljaCA9ICJib3RoIikNCnBoZF9tZXRhZGYkaW50IDwtIGlmZWxzZShuY2hhcihwaGRfbWV0YWRmJGludCk9PTEsIE5BLCBwaGRfbWV0YWRmJGludCkgIyByZW1vdmUgZXJyb25lb3VzIG9uZS1jaGFyYWN0ZXIgbmFtZXMNCg0KDQoNCmBgYA0KDQoNCg0KIyBDb21iaW5pbmcgZmlyc3QgbmFtZSBpbmZvcm1hdGlvbiBmcm9tIGRpc3NlcnRhdGlvbiAmIHBlcnNvbmFsIE5BUkNJUyBwYWdlcw0KDQpXZSBnaXZlIHByaW9yaXR5IHRvIG5hbWVzIGZyb20gdGhlIGRpc3NlcnRhdGlvbiBwYWdlcywgYmVjYXVzZSB0aGVzZSBhcHBlYXIgdG8gYmUgdGhlIGZvcm1hbCBmaXJzdCBuYW1lcywgd2hpbGUgcGVyc29uYWwgTkFSQ0lTIHBhZ2UgbmFtZXMgY29ycmVzcG9uZCB0byB0aGUgZ2l2ZW4gZmlyc3QgbmFtZS4gDQpHaXZlbiB0aGF0IHdlIG1hdGNoIGluZGl2aWR1YWxzIGJhc2VkIG9uIHRoZSBuYW1lIHdoaWNoIGlzIGZvcm1hbGx5IHJlZ2lzdGVyZWQsIGl0IHNlZW1zIGFwcHJvcHJpYXRlIHRvIHRha2UgdGhlICdhdXRldXInIG5hbWUgYXMgdGhlIGJhc2lzIGFuZCByZXBsYWNlIHdpdGggJ25hcmNpc25hbWUnIHdoZW4gdGhlIG5hbWUgYmFzZWQgb24gJ2F1dGV1cicgaXMgdW5rbm93bi4gDQoNCg0KYGBge3IgaGFybW9uaXppbmctTkFSQ0lTfQ0KDQpwaGRfbWV0YWRmIDwtIHBoZF9tZXRhZGYgJT4lDQogIG11dGF0ZShmaXJzdG5hbWUgPSBpZmVsc2UoaXMubmEoZmlyc3RuYW1lKSwgaW50LCBmaXJzdG5hbWUpKQ0KDQojIHNldCBlbXB0eSB0byBOQQ0KcGhkX21ldGFkZiA8LSBwaGRfbWV0YWRmICU+JQ0KICBtdXRhdGUoZmlyc3RuYW1lID0gaWZlbHNlKGZpcnN0bmFtZT09IiIsIE5BLCBmaXJzdG5hbWUpKQ0KDQpwaGRfbWV0YWRmJG5hcmNpc19mbiA8LSBwaGRfbWV0YWRmJGludCAjIGxvbmdlciBidXQgbW9yZSBpbmZvcm1hdGl2ZSBuYW1lDQoNCnBoZF9tZXRhZGYgPC0gc3Vic2V0KHBoZF9tZXRhZGYsIHNlbGVjdCA9IC1pbnQpDQoNCg0KYGBgDQoNCg0KDQojIEZpcnN0IG5hbWVzIGZyb20gZGlzc2VydGF0aW9uIFBERnMNCg0KVGhlcmUgYXJlIHR3byBuYW1lIG9iamVjdHMgZ2F0aGVyZWQgZnJvbSB0aGUgcGRmczogcGRmbmFtZSAoY29uc2lzdGluZyBvZiBuYW1lcyB0aGF0IHdlcmUgZXh0cmFjdGVkIGZyb20gcnVubmluZyB0ZXh0IGluIHRoZSBkaXNzZXJ0YXRpb24sIG9mdGVuIGZyb20gZGlzc2VydGF0aW9uIGZyb250IHBhZ2VzKSBhbmQgcGRmbmFtZXAxIChuYW1lcyBvbiBzdGFuZGFyZGl6ZWQgZGlzc2VydGF0aW9uIGZyb250cGFnZXMgdGhhdCBhcmUgcHJvdmlkZWQgYnkgYSBzdWJzZXQgb2YgdW5pdmVyc2l0aWVzLCB3aGljaCBjb250YWluIGEgc3BlY2lmaWMgaGVhZGVyIGZvciB0aGUgUGhEIG5hbWUpDQoNCg0KDQojIyBDbGVhbmluZyB0aGUgcGRmbmFtZSBvYmplY3QNCg0KSW4gY29tcGFyaXNvbiB0byB0aGUgbmFtZXMgZnJvbSB0aGUgMiBOQVJDSVMgcGFnZSBzb3VyY2VzLCB0aGUgbmFtZSBvYmplY3QgZnJvbSB0aGUgZGlzc2VydGF0aW9uIFBERiBjYW4gc29tZXRpbWVzIGJlIGEgYml0IG1lc3N5LiBFc3BlY2lhbGx5IHRoZSAncGRmbmFtZScgb2JqZWN0LCBkdWUgdG8gdGhlIGZhY3QgdGhhdCB0aGVzZSBuYW1lcyBhcmUgZXh0cmFjdGVkIGZyb20gbmF0dXJhbCB0ZXh0LCBtZWFuaW5nIHNvbWV0aW1lcyBub24tbmFtZSBpbmZvcm1hdGlvbiBlbnRlcnMgdGhlIG5hbWUgb2JqZWN0LiBGdXJ0aGVybW9yZSwgc29tZSBvZiB0aGUgb2xkZXIgUERGcyBhcmUgc2Nhbm5lZCB2ZXJzaW9ucyBvZiBhIHByaW50ZWQgZGlzc2VydGF0aW9uLCBtZWFuaW5nIHRoZXJlIG1heSBiZSBlcnJvcnMgd2hlbiB0aGVzZSBpbWFnZXMgYXJlIGNvbnZlcnRlZCB0byB0ZXh0LiANCg0KSW4gdGhlIHByb3ZpZGVkIGRhdGFmcmFtZSwgd2Ugb25seSBpbmNsdWRlZCBtb3JlIHN0cmFpZ2h0Zm9yd2FyZCBuYW1lIGV4YW1wbGVzLiBTbywgdGhlIGNvZGUgYmVsb3cgaXMgbm90IGRpcmVjdGx5IGFwcGxpY2FibGUgdG8gb3VyIGV4YW1wbGUgY2FzZSwgYnV0IHN0aWxsIHNob3dzIGhvdyB3ZSBjbGVhbmVkIHNvbWUgb2YgdGhlIG1lc3NpZXIgbmFtZXMuDQoNCmBgYHtyIGNsZWFuaW5nLXBkZm5hbWV9DQoNCiMgcmVtb3ZlIGRpYWNyaXRpY3MNCnBoZF9tZXRhZGYkcGRmbmFtZSA8LSBzdHJpX3RyYW5zX2dlbmVyYWwocGhkX21ldGFkZiRwZGZuYW1lLCAnbGF0aW4tYXNjaWknKQ0KDQojIHJlbW92ZSBwdW5jdHVhdGlvbg0KcGhkX21ldGFkZiRwZGZuYW1lIDwtIHN0cl9yZW1vdmVfYWxsKHBoZF9tZXRhZGYkcGRmbmFtZSwgIlt+IUAjXFwkJVxcXlxcJlxcKlxcKFxcKVxce1xcfVxcX1xcKzo8PlxcP1xcLztcXCdcXFtcXF1cXD1cXCxcXOKAolxcLl0iKQ0KDQojIHJlbW92ZSBkaWdpdHMNCnBoZF9tZXRhZGYkcGRmbmFtZSA8LSBzdHJfcmVtb3ZlX2FsbChwaGRfbWV0YWRmJHBkZm5hbWUsICAiWzpkaWdpdDpdIikNCg0KIyByZW1vdmUgY29weXJpZ2h0IGluZGljYXRpb25zDQpwaGRfbWV0YWRmJHBkZm5hbWUgPC0gc3RyX3JlbW92ZV9hbGwocGhkX21ldGFkZiRwZGZuYW1lLCAgImNvcHlyaWdodCIpDQpwaGRfbWV0YWRmJHBkZm5hbWUgPC0gc3RyX3JlbW92ZV9hbGwocGhkX21ldGFkZiRwZGZuYW1lLCAgIihDKSIpDQpwaGRfbWV0YWRmJHBkZm5hbWUgPC0gZ3N1YigiXFxzYWxsIHJpZ2h0cy4qIiwgIiIsIHBoZF9tZXRhZGYkcGRmbmFtZSkNCg0KcGhkX21ldGFkZiRwZGZuYW1lIDwtIHRyaW13cyhwaGRfbWV0YWRmJHBkZm5hbWUsIHdoaWNoID0gImJvdGgiKQ0KDQojIHJlbW92aW5nIHRpdGxlcyBmcm9tIHRoZSBuYW1lDQpwaGRfbWV0YWRmJHBkZm5hbWUgPC0gZ3N1YigibWFzdGVyLioiLCAiIiwgcGhkX21ldGFkZiRwZGZuYW1lKQ0KcGhkX21ldGFkZiRwZGZuYW1lIDwtIGdzdWIoIlxcc21zYy4qIiwgIiIsIHBoZF9tZXRhZGYkcGRmbmFtZSkNCnBoZF9tZXRhZGYkcGRmbmFtZSA8LSBnc3ViKCJcXHNtZC4qIiwgIiIsIHBoZF9tZXRhZGYkcGRmbmFtZSkNCnBoZF9tZXRhZGYkcGRmbmFtZSA8LSBnc3ViKCJcXHNtYWdpc3Rlci4qIiwgIiIsIHBoZF9tZXRhZGYkcGRmbmFtZSkNCnBoZF9tZXRhZGYkcGRmbmFtZSA8LSBnc3ViKCJcXHNtYWdpc3RyaS4qIiwgIiIsIHBoZF9tZXRhZGYkcGRmbmFtZSkNCnBoZF9tZXRhZGYkcGRmbmFtZSA8LSBnc3ViKCJcXHNiYWNoZWxvci4qIiwgIiIscGhkX21ldGFkZiRwZGZuYW1lKQ0KcGhkX21ldGFkZiRwZGZuYW1lIDwtIGdzdWIoIlxcc2xhdXJlYS4qIiwgIiIsIHBoZF9tZXRhZGYkcGRmbmFtZSkNCnBoZF9tZXRhZGYkcGRmbmFtZSA8LSBnc3ViKCJcXHNtZXN0cmUuKiIsICIiLCBwaGRfbWV0YWRmJHBkZm5hbWUpDQpwaGRfbWV0YWRmJHBkZm5hbWUgPC0gZ3N1YigiXFxzZG90dG9yZS4qIiwgIiIsIHBoZF9tZXRhZGYkcGRmbmFtZSkNCnBoZF9tZXRhZGYkcGRmbmFtZSA8LSBnc3ViKCJcXHN1cG0uKiIsICIiLCBwaGRfbWV0YWRmJHBkZm5hbWUpICMgc3BlY2lmaWMgVU0gcHJlc3MgdGhpbmcNCnBoZF9tZXRhZGYkcGRmbmFtZSA8LSBnc3ViKCJcXHNwXFxzdVxcc20uKiIsICIiLCBwaGRfbWV0YWRmJHBkZm5hbWUpICMgc3BlY2lmaWMgVU0gcHJlc3MgdGhpbmcNCnBoZF9tZXRhZGYkcGRmbmFtZSA8LSBnc3ViKCJcXHNkaXBsLioiLCAiIiwgcGhkX21ldGFkZiRwZGZuYW1lKQ0KcGhkX21ldGFkZiRwZGZuYW1lIDwtIGdzdWIoIlxcc2RpcGxvbS4qIiwgIiIsIHBoZF9tZXRhZGYkcGRmbmFtZSkNCnBoZF9tZXRhZGYkcGRmbmFtZSA8LSBnc3ViKCJcXHNkaXBsb21hLioiLCAiIiwgcGhkX21ldGFkZiRwZGZuYW1lKQ0KcGhkX21ldGFkZiRwZGZuYW1lIDwtIGdzdWIoIlxcc2xpY2VuLioiLCAiIiwgcGhkX21ldGFkZiRwZGZuYW1lKQ0KcGhkX21ldGFkZiRwZGZuYW1lIDwtIGdzdWIoIlxcc2hiby4qIiwgIiIsIHBoZF9tZXRhZGYkcGRmbmFtZSkNCnBoZF9tZXRhZGYkcGRmbmFtZSA8LSBnc3ViKCJcXHNodHMuKiIsICIiLCBwaGRfbWV0YWRmJHBkZm5hbWUpDQpwaGRfbWV0YWRmJHBkZm5hbWUgPC0gZ3N1YigiXFxzZG9jdG9yYW5kdXMuKiIsICIiLCBwaGRfbWV0YWRmJHBkZm5hbWUpDQpwaGRfbWV0YWRmJHBkZm5hbWUgPC0gZ3N1YigiXFxzY2FuZGlkYXQuKiIsICIiLCBwaGRfbWV0YWRmJHBkZm5hbWUpDQpwaGRfbWV0YWRmJHBkZm5hbWUgPC0gZ3N1YigiXFxzc2FyamFuYS4qIiwgIiIsIHBoZF9tZXRhZGYkcGRmbmFtZSkNCnBoZF9tZXRhZGYkcGRmbmFtZSA8LSBnc3ViKCJcXHNzcGVjaWFsaXN0LioiLCAiIiwgcGhkX21ldGFkZiRwZGZuYW1lKQ0KcGhkX21ldGFkZiRwZGZuYW1lIDwtIGdzdWIoIlxcc3VuaXZlci4qIiwgIiIsIHBoZF9tZXRhZGYkcGRmbmFtZSkNCnBoZF9tZXRhZGYkcGRmbmFtZSA8LSBnc3ViKCJcXHNlbmdpbmVlci4qIiwgIiIsIHBoZF9tZXRhZGYkcGRmbmFtZSkNCnBoZF9tZXRhZGYkcGRmbmFtZSA8LSBnc3ViKCJcXHNpbmdlbmllcm8uKiIsICIiLCBwaGRfbWV0YWRmJHBkZm5hbWUpDQpwaGRfbWV0YWRmJHBkZm5hbWUgPC0gZ3N1YigiXFxzaW5naW5lci4qIiwgIiIsIHBoZF9tZXRhZGYkcGRmbmFtZSkNCnBoZF9tZXRhZGYkcGRmbmFtZSA8LSBnc3ViKCJcXHNpbmdlbmllcmEuKiIsICIiLCBwaGRfbWV0YWRmJHBkZm5hbWUpDQpwaGRfbWV0YWRmJHBkZm5hbWUgPC0gZ3N1YigiXFxzaW5nZW5pZXJpYS4qIiwgIiIsIHBoZF9tZXRhZGYkcGRmbmFtZSkNCnBoZF9tZXRhZGYkcGRmbmFtZSA8LSBnc3ViKCJcXHNpbmdlZ25lcmUuKiIsICIiLCBwaGRfbWV0YWRmJHBkZm5hbWUpDQpwaGRfbWV0YWRmJHBkZm5hbWUgPC0gZ3N1YigiXFxzaW5nZWduZXJpYS4qIiwgIiIsIHBoZF9tZXRhZGYkcGRmbmFtZSkNCnBoZF9tZXRhZGYkcGRmbmFtZSA8LSBnc3ViKCJcXHNpbmdlbmlldXIuKiIsICIiLCBwaGRfbWV0YWRmJHBkZm5hbWUpDQpwaGRfbWV0YWRmJHBkZm5hbWUgPC0gZ3N1YigiXFxzW1s6YWxwaGE6XVxcLV0qaW5nZW5pZXVyLioiLCAiIiwgcGhkX21ldGFkZiRwZGZuYW1lKSAjIGluZ2VuaWV1ciBhbmQgZXZlcnl0aGluZyB0aGF0IGlzIGF0dGFjaGVkIGJlZm9yZQ0KDQojIHNwZWNpZmljIHR5cGVzIG9mIGVuZ2luZWVyaW5nIHRpdGxlcw0KZW5naW5lZXJpbmd0aXRsZXMgPC0gYygiZWxlKGN8ayl0cm90ZWNobmlzY2guKiIsICJjaXZpZWwuKiIsICIobGFuZCk/KHdlcmt0dWlnKT8oc2NoZWVwcyk/KG1pam4pP2JvdXdrdW5kaWcuKiIsICIod2lzKT8obmF0dXVyKT8oc2NoZWkpPyh3ZXJrdHVpZyk/KG1hdGVyaWFhbCk/KGJlc3R1dXJzKT9rdW5kaWcuKiIsICJpbmZvcm1hdGljYS4qIiwgImdlb2RldGlzY2guKiIsICJsdWNodC0gZW4gcnVpbXRldmFhcnQgdGVjaG5pc2NoLioiLCAiY2hlbWlzY2guKiIsICJtYXJpdGllbS4qIiwgImJpb2luZm9ybWF0aWNhLioiLCAicmFhZGdldmVuZC4qIiwgImFyY2hpdGVjdC4qIiwgImdlb2xvZ2lzY2guKiIsICJnZW9meXNpc2NoLioiLCAibWVldC0gZW4gcmVnZWx0ZWNobmlzY2giKQ0KDQpwaGRfbWV0YWRmJHBkZm5hbWUgPC0gc3RyX3JlbW92ZShwaGRfbWV0YWRmJHBkZm5hbWUsIHBhc3RlMChlbmdpbmVlcmluZ3RpdGxlcywgY29sbGFwc2UgPSAifCIpKQ0KDQpwaGRfbWV0YWRmJHBkZm5hbWUgPC0gdHJpbXdzKHBoZF9tZXRhZGYkcGRmbmFtZSwgd2hpY2ggPSAiYm90aCIpDQoNCmBgYA0KDQoNClNvbWUgZGlzc2VydGF0aW9ucyBoYXZlIG11bHRpcGxlIGF1dGhvcnMuIFdlIG9ubHkgd2FudCB0aGUgZmlyc3QgYXV0aG9yLCBzbyByZW1vdmUgZXZlcnl0aGluZyBhZnRlciAiOyINCmBgYHtyIG11bHRpcGxlLWF1dGhvcnMyfQ0KDQpwaGRfbWV0YWRmJHBkZm5hbWVwMSA8LSBnc3ViKCI7LioiLCAiIiwgcGhkX21ldGFkZiRwZGZuYW1lcDEpDQoNCmBgYA0KDQoNCg0KIyMgRmlyc3QgbmFtZXMgZnJvbSBgcGRmbmFtZXAxYA0KDQpUaGUgb2JqZWN0IGBwZGZuYW1lcDFgIGNvbnRhaW5zIGFsbCBuYW1lcyBpbiBhIHN0YW5kYXJkaXplZCBmb3JtYXQuIFRoZSBmb3JtYXQgaXM6ICJsYXN0IG5hbWUsIGZpcnN0IG5hbWUocykiLiBUbyBleHRyYWN0IGZpcnN0IG5hbWVzLCB3ZSBsb29rIGF0IGV2ZXJ5dGhpbmcgdGhhdCBmb2xsb3dzIHRoZSBjb21tYS4gDQoNCmBgYHtyIGNvbW1hbmFtZXMyfQ0KDQpwaGRfbWV0YWRmJGNvbSA8LSBzdHJfZGV0ZWN0KHBoZF9tZXRhZGYkcGRmbmFtZXAxLCAiLCIpICMgZGV0ZWN0IGNvbW1hDQoNCiMgS2VlcCBldmVyeXRoaW5nIGFmdGVyIGEgY29tbWEgaWYgdGhlcmUgaXMgb25lDQpwaGRfbWV0YWRmIDwtIHBoZF9tZXRhZGYgJT4lDQogIG11dGF0ZShmaXJzdG5hbWVwZGYgPSBpZmVsc2UoKGNvbT09VFJVRSksIHN0cl9yZW1vdmUocGRmbmFtZXAxLCAiLiosIiksIHBkZm5hbWVwMSkpICU+JQ0KICBzZWxlY3QoLWNvbSkNCg0KYGBgDQoNCg0KIyMgQ2xlYW5pbmcgdGhlIGZpcnN0IG5hbWVzDQoNClJlbW92aW5nIG5vYmlsaWFyeSBwYXJ0aWNsZXMsIGluaXRpYWxzIGFtZCBwdW5jdHVhdGlvbi4gDQoNCg0KYGBge3IgY2xlYW5pbmctcGRmbmFtZXAxfQ0KDQojIHJlbW92aW5nIGFsbCBub2JpbGlhcnkgcGFydGljbGVzDQpwaGRfbWV0YWRmJGZpcnN0bmFtZXBkZiA8LSBzdHJfcmVtb3ZlKHBoZF9tZXRhZGYkZmlyc3RuYW1lcGRmLCBwYXN0ZTAodmFuZGUwLCBjb2xsYXBzZT0ifCIpKQ0KcGhkX21ldGFkZiRmaXJzdG5hbWVwZGYgPC0gc3RyX3JlcGxhY2VfYWxsKHBoZF9tZXRhZGYkZmlyc3RuYW1lcGRmLCBwYXN0ZSh2YW5kZTEsIGNvbGxhcHNlID0gInwiKSwgIiIpDQpwaGRfbWV0YWRmJGZpcnN0bmFtZXBkZiA8LSBzdHJfcmVtb3ZlX2FsbChwaGRfbWV0YWRmJGZpcnN0bmFtZXBkZiwgcGFzdGUodmFuZGUyLCBjb2xsYXBzZSA9ICJ8IikpDQpwaGRfbWV0YWRmJGZpcnN0bmFtZXBkZiA8LSBzdHJfcmVwbGFjZV9hbGwocGhkX21ldGFkZiRmaXJzdG5hbWVwZGYsIHBhc3RlKHZhbmRlMywgY29sbGFwc2UgPSAifCIpLCAiIikNCnBoZF9tZXRhZGYkZmlyc3RuYW1lcGRmIDwtIHN0cl9yZW1vdmUocGhkX21ldGFkZiRmaXJzdG5hbWVwZGYsIHBhc3RlKHZhbmRlNCwgY29sbGFwc2UgPSAifCIpKQ0KDQpwaGRfbWV0YWRmJGZpcnN0bmFtZXBkZiA8LSB0cmltd3MocGhkX21ldGFkZiRmaXJzdG5hbWVwZGYsIHdoaWNoID0gImJvdGgiKSAjIHRyaW1taW5nIHdoaXRlc3BhY2UNCg0KcGhkX21ldGFkZiRmaXJzdG5hbWVwZGYgPC0gc3RyX3JlbW92ZV9hbGwocGhkX21ldGFkZiRmaXJzdG5hbWVwZGYsIGluaXRpYWxwYXR0ZXJuKSAjIG9iamVjdCBpbml0aWFscGF0dGVybiBkZWZpbmVkIGluIHNlY3Rpb24gMQ0KDQojIGV4dHJhY3Rpbmcgb25seSB0aGUgZmlyc3QtbWVudGlvbmVkIGZpcnN0IG5hbWUgYW5kIHJlbW92aW5nIHB1bmN0dWF0aW9uIG1hcmtzDQpwaGRfbWV0YWRmJGZpcnN0bmFtZXBkZiA8LSBzdHJfZXh0cmFjdChwaGRfbWV0YWRmJGZpcnN0bmFtZXBkZiwgIlthLXpdK1xcLSpbYS16XSoiKQ0KDQoNCnBoZF9tZXRhZGYgPC0gcGhkX21ldGFkZiAlPiUNCiAgbXV0YXRlKGZpcnN0bmFtZXBkZiA9IGlmZWxzZSgoZmlyc3RuYW1lcGRmID09ICJeXFxzJCIgfCBmaXJzdG5hbWVwZGYgPT0gIiIpICxOQSwgZmlyc3RuYW1lcGRmKSkgIyBlbXB0eSB0byBOQQ0KDQpwaGRfbWV0YWRmJGZpcnN0bmFtZXBkZiA8LSBpZmVsc2UobmNoYXIocGhkX21ldGFkZiRmaXJzdG5hbWVwZGYpPT0xLCBOQSwgcGhkX21ldGFkZiRmaXJzdG5hbWVwZGYpICMgcmVtb3ZlIGVycm9uZW91cyBvbmUtY2hhcmFjdGVyIG5hbWVzDQoNCmBgYA0KDQoNCiMjIEFkZGluZyBmaXJzdCBuYW1lcyBmcm9tIGBwZGZuYW1lYA0KDQpCZWNhdXNlIG5hbWVzIGZyb20gdGhlIGBwZGZuYW1lYCBvYmplY3QgYXJlIG5vdCBhcyBuZWF0IGFzIG5hbWVzIGZyb20gYHBkZm5hbWVwMWAsIHdlIGdpdmUgcHJpb3JpdHkgdG8gdGhlIGxhdHRlci4gDQoNCg0KVGhlIGZvcm1hdCBvZiB0aGUgYHBkZm5hbWVgIG9iamVjdCBpcyAiZmlyc3QgbmFtZShzKSBsYXN0IG5hbWUiLiBTbywgd2UgZXh0cmFjdCB0aGUgZmlyc3Qgd29yZCBmcm9tIHRoaXMgb2JqZWN0IHRvIGdhdGhlciB0aGUgZmlyc3QgbmFtZS4gDQpTb21lIG5hbWVzIGNvbnRhaW4gYSBsYXJnZSBudW1iZXIgb2Ygd2hpdGVzcGFjZXMgKGUuZy4gIm0gYSB0IHQgaCBlIHcgaiBvIGggbiBzIG8gbiIgb3IgIm0gYXR0aGV3IGogb2huc29uIikuIFRoZSBmb3JtZXIgY2FzZSwgd2UgY3VycmVudGx5IGRvIG5vdCBleHRyYWN0LiANCg0KDQpgYGB7ciBmaXJzdG5hbWVzLXBkZn0NCg0KIyBBIGZldyBuYW1lcyBoYXZlIGEgY291cGxlIG9mIGFkZGVkIHNwYWNlcywgb2Z0ZW4gZm9sbG93aW5nIHRoZSBmaXJzdCBsZXR0ZXIgb2YgYSBuYW1lLiBSZW1vdmUgdGhpcyBzcGFjZSBhZnRlciB0aGUgZmlyc3QgbGV0dGVyDQoNCnBoZF9tZXRhZGYkc3BhY2VzIDwtIGFzLm51bWVyaWMoc3RyX2RldGVjdChwaGRfbWV0YWRmJHBkZm5hbWUsICJeXFxzP1s6YWxwaGE6XVxcc1s6YWxwaGE6XXsyLH0iKSkgIyBkZXRlY3QgYSBzaW5nbGUgbGV0dGVyLCBmb2xsb3dlZCBieSBhIHNwYWNlLCBmb2xsb3dlZCBieSBtb3JlIHRoYW4gMSBsZXR0ZXINCg0KcGhkX21ldGFkZiRzcGFjZXMgPC0gaWZlbHNlKGlzLm5hKHBoZF9tZXRhZGYkc3BhY2VzKSwgMCwgcGhkX21ldGFkZiRzcGFjZXMpICMgcmVwbGFjZSBOQSB3aXRoIDANCg0KcGhkX21ldGFkZiRwZGZuYW1lIDwtIGlmZWxzZShwaGRfbWV0YWRmJHNwYWNlcz09MSwgc3RyX3JlbW92ZShwaGRfbWV0YWRmJHBkZm5hbWUsICJcXHMiKSwgcGhkX21ldGFkZiRwZGZuYW1lKSAjIHJlbW92ZSB0aGUgZmlyc3Qgc3BhY2UgaWYgYSBuYW1lIGZvbGxvd3MgdGhlIHBhdHRlcm4gZGVzY3JpYmVkIGFib3ZlDQoNCnBoZF9tZXRhZGYkZmlyc3RuYW1lcGRmMiA8LSBzdHJfZXh0cmFjdChwaGRfbWV0YWRmJHBkZm5hbWUsICJbYS16XStcXC0qW2Etel0qIikNCg0KDQoNCiMgTm93LCB3ZSBmaWxsIHRoZSBmaXJzdG5hbWUgb2JqZWN0IHdpdGggdGhlIGZpcnN0IHdvcmQgaW4gJ3BkZm5hbWUnLCBidXQgb25seSBpZiBmaXJzdG5hbWUgYmFzZWQgb24gJ3BkZm5hbWVwMScgaXMgbWlzc2luZw0KcGhkX21ldGFkZiRmaXJzdG5hbWVwZGYgPC0gaWZlbHNlKGlzLm5hKHBoZF9tZXRhZGYkZmlyc3RuYW1lcGRmKSwgcGhkX21ldGFkZiRmaXJzdG5hbWVwZGYyLCBwaGRfbWV0YWRmJGZpcnN0bmFtZXBkZikNCg0KDQojIEFnYWluLCB3ZSByZW1vdmUgc3BhY2VzIGFuZCBvbmUtY2hhcmFjdGVyIG5hbWVzDQpwaGRfbWV0YWRmJGZpcnN0bmFtZXBkZiA8LSBzdHJfcmVtb3ZlX2FsbChwaGRfbWV0YWRmJGZpcnN0bmFtZXBkZiwgIlxccyIpICMgcmVtb3ZlIHNwYWNlcw0KcGhkX21ldGFkZiRmaXJzdG5hbWVwZGYgPC0gaWZlbHNlKG5jaGFyKHBoZF9tZXRhZGYkZmlyc3RuYW1lcGRmKT09MSwgTkEsIHBoZF9tZXRhZGYkZmlyc3RuYW1lcGRmKSAjIHJlbW92ZSBlcnJvbmVvdXMgb25lLWNoYXJhY3RlciBuYW1lcw0KDQoNCiMgUmVtb3ZlIHVua25vd24gY2hhcmFjdGVycw0KcGhkX21ldGFkZiRmaXJzdG5hbWVwZGYgPC0gc3RyX2V4dHJhY3QocGhkX21ldGFkZiRmaXJzdG5hbWVwZGYsICJbYS16XStcXC0qW2Etel0qIikNCg0KDQpwaGRfbWV0YWRmIDwtIHN1YnNldChwaGRfbWV0YWRmLCBzZWxlY3QgPSAtZmlyc3RuYW1lcGRmMikgIyByZW1vdmUgaW50ZXJtZWRpYXRlIG9iamVjdA0KDQoNCmBgYA0KDQoNCg0KIyBHYXRoZXJpbmcgbGFzdCBuYW1lcyBmcm9tIHRoZSBkaXNzZXJ0YXRpb24gUERGcw0KDQpUaGVyZSBpcyBhICp2ZXJ5KiBzbWFsbCBudW1iZXIgb2YgaW5kaXZpZHVhbHMgZm9yIHdob20gdGhlIGxhc3QgbmFtZSBpcyB1bmtub3duLiBUbyBmaWxsIHRoaXMsIHdlIHVzZSB0aGUgbmFtZSBvYmplY3QgZnJvbSB0aGUgZGlzc2VydGF0aW9uIGRhdGEuIEdpdmVuIHRoZSBmb3JtYXR0aW5nIG9mIG5hbWVzIGluIHRoaXMgb2JqZWN0IGFzICJmaXJzdCBuYW1lKHMpIGxhc3QgbmFtZShzKSIsIHdlIGp1c3QgdGFrZSB0aGUgbGFzdCB3b3JkIG9mIHRoZSBzdHJpbmcsIGFuZCB0aGVuIGFkZCBwb3RlbnRpYWwgbm9iaWxpYXJ5IHBhcnRpY2xlcyB0aGF0IGFyZSBtZW50aW9uZWQgaW4gdGhlIG1pZGRsZSBvZiB0aGUgc3RyaW5nLiANCg0KYGBge3IgbGFzdG5hbWVzLXBkZn0NCg0KcGhkX21ldGFkZiRsYXN0bmFtZXBkZiA8LSB3b3JkKHBoZF9tZXRhZGYkcGRmbmFtZSwgLTEpDQoNCiMgZXh0cmFjdGluZyBub2JpbGlhcnkgcGFydGljbGVzDQpwaGRfbWV0YWRmJG5wMiA8LSBzdHJfZXh0cmFjdChwaGRfbWV0YWRmJHBkZm5hbWUsIHBhc3RlMCh2YW5kZTAsIGNvbGxhcHNlPSJ8IikpICMgbm9iaWxpYXJ5IHBhcnRpY2xlcyB0aGF0IGNhbm5vdCBiZSBwYXJ0IG9mIHRoZSBuYW1lDQpwaGRfbWV0YWRmJG5wMiA8LSBpZmVsc2UoaXMubmEocGhkX21ldGFkZiRucDIpLCBzdHJfZXh0cmFjdChwaGRfbWV0YWRmJHBkZm5hbWUsIHBhc3RlMCh2YW5kZTEsIGNvbGxhcHNlPSJ8IikpLCBwaGRfbWV0YWRmJG5wMikgIyBub2JpbGlhcnkgcGFydGljbGVzIHN1cnJvdW5kZWQgd2l0aCB3aGl0ZXNwYWNlcw0KDQojIENvbWJpbmluZyBub2JpbGlhcnkgcGFydGljbGUgYW5kIGxhc3QgbmFtZQ0KcGhkX21ldGFkZiAlPiUNCiAgbXV0YXRlKGxhc3RuYW1lX2Z1bGxfcGRmID0gaWZlbHNlKCFpcy5uYShucDIpLCBwYXN0ZShucDIsIGxhc3RuYW1lcGRmKSwgbGFzdG5hbWVwZGYpKSAtPiBwaGRfbWV0YWRmDQoNCnBoZF9tZXRhZGYkbGFzdG5hbWVwZGYgPC0gaWZlbHNlKG5jaGFyKHBoZF9tZXRhZGYkbGFzdG5hbWVwZGYpPT0xLCBOQSwgcGhkX21ldGFkZiRsYXN0bmFtZXBkZikgIyByZW1vdmUgZXJyb25lb3VzIG9uZS1jaGFyYWN0ZXIgbmFtZXMNCg0KDQpgYGANCg0KDQoNCiMgSGFybW9uaXppbmcgbmFtZXMgZnJvbSBOQVJDSVMgcGFnZXMgYW5kIGRpc3NlcnRhdGlvbiB0ZXh0DQoNCk5leHQsIHdlIGhhcm1vbml6ZSB0aGUgbmFtZXMgd2Ugbm93IGhhdmUgYmFzZWQgb24gTkFSQ0lTIHBhZ2VzIChwZXJzb25hbCBhbmQgZGlzc2VydGF0aW9uIHBhZ2UpLCB3aXRoIG5hbWVzIGdhdGhlcmVkIGZyb20gZGlzc2VydGF0aW9uIFBERiB0ZXh0LiBXZSBnaXZlIHByaW9yaXR5IHRvIG5hbWVzIGZyb20gTkFSQ0lTIHBhZ2VzLCBiZWNhdXNlIHRoZXkgY29udGFpbiBsZXNzIG5vaXNlIHRoYW4gbmFtZXMgZnJvbSB0aGUgZGlzc2VydGF0aW9uIHRleHQuIA0KDQpgYGB7ciBOQVJDSVMtcGRmLWNvbWJpbmVkfQ0KDQpwaGRfbWV0YWRmJGZpcnN0bmFtZSA8LSBpZmVsc2UoaXMubmEocGhkX21ldGFkZiRmaXJzdG5hbWUpLCBwaGRfbWV0YWRmJGZpcnN0bmFtZXBkZiwgcGhkX21ldGFkZiRmaXJzdG5hbWUpDQoNCg0KcGhkX21ldGFkZiRsYXN0bmFtZSA8LSBpZmVsc2UoaXMubmEocGhkX21ldGFkZiRsYXN0bmFtZSksIHBoZF9tZXRhZGYkbGFzdG5hbWVwZGYsIHBoZF9tZXRhZGYkbGFzdG5hbWUpDQoNCg0KYGBgDQoNCg0KIyBWaWV3IG9mIHRoZSBkYXRhZnJhbWUgd2l0aCBjbGVhbmVkIGxhc3QgbmFtZXMNCg0KQWZ0ZXIgYWxsIG9mIHRoaXMgY2xlYW5pbmcsIHdlIG5vdyBoYXZlIGEgZGF0YWZyYW1lIHRoYXQgY29udGFpbnMgYSBjbGVhbmVkIGZpcnN0IG5hbWUgYW5kIGxhc3QgbmFtZSAod2l0aCBub2JpbGlhcnkgcGFydGljbGVzIGlmIHByZXNlbnQpLiBUaGlzIGRhdGFmcmFtZSBpcyB1c2VkIGFzIGlucHV0IGZvciBvdXIgZ2VuZGVyIGFuZCBldGhuaWNpdHkgdmFyaWFibGVzLiANCg0KYGBge3IgZGF0YXByZXZpZXcsIGVjaG89RkFMU0V9DQoNCm91dHB1dHZpZXcgPC0gcGhkX21ldGFkZlssYyg4LDEsMiwzLDQsOSwxMSwxMCwxMiw1LDYsNyldDQoNCg0Kb3V0cHV0dmlldyAlPiUNCiAga2FibGUoKSAlPiUNCiAga2FibGVfc3R5bGluZygpICU+JQ0KICBzY3JvbGxfYm94KHdpZHRoPSIxMDAlIikNCg0KDQpgYGANCg0KDQoNCg0KDQotLS0gDQoNCiMgT3V0cHV0DQoNCldlIHNhdmUgdGhlIGRhdGFzZXQgcGhkX21ldGFkZiBpbmNsdWRpbmcgdGhlIGNsZWFuZWQgZmlyc3QgYW5kIGxhc3QgbmFtZXMsIHdpdGggdGhlIGR1cGxpY2F0ZSBvYnNlcnZhdGlvbnMgcmVtb3ZlZC4gDQoNCmBgYHtyIHNhdmUsIGV2YWw9RkFMU0V9DQoNCnBoZF9tZXRhZGYgJT4lDQogIHNlbGVjdChpZCwgZmlyc3RuYW1lLCBucCwgbGFzdG5hbWUsIGxhc3RuYW1lX2Z1bGwsIGRpc3NfYmlydGhwbGFjZSwgdW5pLCBwaGRfeWVhcikgLT4gcGhkbmFtZXMNCg0Kc2F2ZShwaGRuYW1lcywgZmlsZSA9ICJkYXRhL3Byb2Nlc3NlZC9waGRuYW1lcy5yZGEiKQ0KDQoNCmBgYA0KDQoNCi0tLSAgDQoNCiMgUmVmZXJlbmNlcw0KDQo=


Copyright © 2023