Import the stringr library -

> library(stringr)

All the stringr’s functions starts with str_.

Length of strings

Function: str_length()

> str_length("Do the work")
[1] 11
> str_length(c("This","GOOgle","AeioU"))
[1] 4 6 5

Spaces are counted as a character.

Or the base R function: nchar()

> nchar("Do the work")
[1] 11
> nchar(c("This","GOOgle","AeioU"))
[1] 4 6 5

Coverting case

All upper case

Function: str_to_upper()

> str_to_upper("don't go there")
[1] "DON'T GO THERE"
> str_to_upper(c("This","GOOgle","AeioU"))
[1] "THIS"   "GOOGLE" "AEIOU" 

All lower case

> str_to_lower("don't go there")
[1] "don't go there"
> str_to_lower(c("This","GOOgle","AeioU"))
[1] "this"   "google" "aeiou" 

Title like formating

> str_to_title("the fINAL destiNATION")
[1] "The Final Destination"

Sentence like formating

> str_to_sentence("this Is Nothing BUT a sentence")
[1] "This is nothing but a sentence"

Trim

Trim both sides

> str_trim("   This is good!   ")
[1] "This is good!"

Trim right side

> str_trim("   This is good!   ", side="right")
[1] "   This is good!"

Trim left side

> str_trim("   This is good!   ", side="left")
[1] "This is good!   "

Padding

> rbind(
+   str_pad(c("do"), width="10", side="both",pad="$"),
+   str_pad(c("do"), width="10", side="both",pad=" "),
+   str_pad(c("this"), width="10", side="right",pad="-"),
+   str_pad(c("no way"), width="10",side="left",pad="-")
+ )
     [,1]        
[1,] "$$$$do$$$$"
[2,] "    do    "
[3,] "this------"
[4,] "----no way"

Truncate

> string1 <- "An introduction to the science of life."
> rbind(
+   str_trunc(string1, width=30, "right"),
+   str_trunc(string1, width=30, "left"),
+   str_trunc(string1, width=30, "center")
+ )
     [,1]                            
[1,] "An introduction to the scie..."
[2,] "...ion to the science of life."
[3,] "An introductio...ence of life."

Split sentence

Split by something

> sen1 <- "This is OK, but how! Alas! And, there was nothing!"
> str_split(sen1, pattern=" ")
[[1]]
 [1] "This"     "is"       "OK,"      "but"      "how!"     "Alas!"   
 [7] "And,"     "there"    "was"      "nothing!"
> str_split(sen1, ", ")
[[1]]
[1] "This is OK"         "but how! Alas! And" "there was nothing!"
> str_split(sen1, "! ")
[[1]]
[1] "This is OK, but how"     "Alas"                   
[3] "And, there was nothing!"

The simplify argument determined what to return. If FALSE, it returns a list of character vectors. If TRUE returns a character matrix -

> str_split(sen1, " ", simplify = F)
[[1]]
 [1] "This"     "is"       "OK,"      "but"      "how!"     "Alas!"   
 [7] "And,"     "there"    "was"      "nothing!"
> str_split(sen1, " ", simplify = T)
     [,1]   [,2] [,3]  [,4]  [,5]   [,6]    [,7]   [,8]    [,9]  [,10]     
[1,] "This" "is" "OK," "but" "how!" "Alas!" "And," "there" "was" "nothing!"

Split in limited numbers

> sen1 <- "This is OK, but how! Alas! And, there was nothing!"
> str_split(sen1, pattern=" ", n=8)
[[1]]
[1] "This"               "is"                 "OK,"               
[4] "but"                "how!"               "Alas!"             
[7] "And,"               "there was nothing!"

Here the sentence is split into 8 parts.

Join strings

Using str_c() -

> str_c("Join", "this!", sep="_")
[1] "Join_this!"
> str_c( c("No","Yes"),
+        c("way", "yesss"), 
+        sep = " ")
[1] "No way"    "Yes yesss"

It is equivalent to the function paste() from base R -

> paste("Join", "this!", sep="_")
[1] "Join_this!"
> paste( c("No","Yes"),
+        c("way", "yesss"), 
+        sep = " ")
[1] "No way"    "Yes yesss"

collapse

Collapse a vector of strings into a single string -

> str_c(string = c("this","is","just","an","example"),  sep="_")
[1] "this"    "is"      "just"    "an"      "example"

NOTICE: This is not a vector of words, but previous one was -

> str_c("this","is","just","an","example",  sep="_")
[1] "this_is_just_an_example"

Removing strings

Lets look at the vector of strings that should be of numeric type -

> cost <- c("1,579","1,975","3,000","2,500")
> as.numeric(cost)
[1] NA NA NA NA

So, we have to remove the commas from the values before converting into numeric -

> cost <- str_remove(string = cost, pattern = ",")
> cost  # see the vector
[1] "1579" "1975" "3000" "2500"
> as.numeric(cost)
[1] 1579 1975 3000 2500

Replacing NA

By default NA turns into a string “NA” -

> string3 <- c("one word", NA, "another", "word")
> string3
[1] "one word" NA         "another"  "word"    
> str_replace_na(string3)
[1] "one word" "NA"       "another"  "word"    

But using the replacement argument NA can be replaced to anything -

> str_replace_na(string3, replacement = 99)
[1] "one word" "99"       "another"  "word"    

Sorting

str_sort() sorts in alphabetical order -

> string4 <- c("b","a","b","B","q","Y")
> str_sort(string4)
[1] "a" "b" "b" "B" "q" "Y"

str_oder() returns the order of the strings -

> str_order(string4)
[1] 2 1 3 4 5 6
> string4[str_order(string4)] # equivalent to str_sort()
[1] "a" "b" "b" "B" "q" "Y"

Here base R’s sort() can also be used -

> 'b' < 'B'
[1] TRUE
> sort(string4)
[1] "a" "b" "b" "B" "q" "Y"

Insert variable values into strings

Using the function str_glue() -

> fname <- c("Ahsanul","Ataur","Mehedi")
> lname <- c("Islam","Rahman","Hasan")
> str_glue("He is my friend, {fname} {lname}.")
He is my friend, Ahsanul Islam.
He is my friend, Ataur Rahman.
He is my friend, Mehedi Hasan.

Mathematical operations can be done inside the {} -

> f <- 10
> ages <- c(21, 22, 19)
> str_glue("{fname} {lname} is {ages} years old now. \nAfter {f} years he will be {ages+f} years old.\n\n")
Ahsanul Islam is 21 years old now. 
After 10 years he will be 31 years old.

Ataur Rahman is 22 years old now. 
After 10 years he will be 32 years old.

Mehedi Hasan is 19 years old now. 
After 10 years he will be 29 years old.

Another one -

> nums <- c(10, 100, 5, 9)
> str_glue("The square of {nums} is {nums**2}")
The square of 10 is 100
The square of 100 is 10000
The square of 5 is 25
The square of 9 is 81

Extract all words from a sentence string

Using str_extract_all() and using the argument boundary(“word”) -

> str_extract_all("This is an example word. How is it?", pattern = boundary("word"))
[[1]]
[1] "This"    "is"      "an"      "example" "word"    "How"     "is"     
[8] "it"     

It returns a list of vectors-

> sen2 <- c("This is an example","Second, Example","wow! Nice.")
> str_extract_all(sen2, boundary("word"))
[[1]]
[1] "This"    "is"      "an"      "example"

[[2]]
[1] "Second"  "Example"

[[3]]
[1] "wow"  "Nice"
> str_extract_all(sen2, boundary("word"), simplify = T)  # Returns a matrix
     [,1]     [,2]      [,3] [,4]     
[1,] "This"   "is"      "an" "example"
[2,] "Second" "Example" ""   ""       
[3,] "wow"    "Nice"    ""   ""       

Note: Boundary takes the values - “character”, “line_break”, “sentence”, “word”.

Matching string

Extracting matching words

> str_extract_all("THIS is nothing but a sentence. He is right", pattern=fixed("is", ignore_case = T))
[[1]]
[1] "IS" "is" "is"
> str_extract_all("THIS is nothing but a sentence. He is right",
+                 pattern="is|but") # the 'IS' from 'THIS' will be matched
[[1]]
[1] "is"  "but" "is" 

Looks for either is or but.

Gettings strings that matches the pattern

Using str_subset() -

> fruit <- c("apple", "banana", "Pear", "pinapple")
> str_subset(fruit, "b")  # Looks for b in any position
[1] "banana"
> str_subset(fruit, "^a")  # Looks for a in first position
[1] "apple"
> str_subset(fruit, "a$")  # Looks for a in last position
[1] "banana"
> str_subset(fruit, "[aeiou]")  # Looks for any of the patterns in any position
[1] "apple"    "banana"   "Pear"     "pinapple"
> str_subset(fruit, "[A-Z]")  # Looks for any of the latters A to B 
[1] "Pear"

The argument negate determines what strings to return, matched or not matched -

> str_subset(fruit, "b")
[1] "banana"
> str_subset(fruit, "b", negate = T)
[1] "apple"    "Pear"     "pinapple"

Finding matched string using str_match()

Suppose we have two different words which is similar in meaning but has slightly different spelling. In these case we can get a matrix in return with words and their matched part using str_match() -

> str_match(c("color","colour","eye"), "colo(|u)r") # "col(o|ou)r" can be used also
     [,1]     [,2]
[1,] "color"  ""  
[2,] "colour" "u" 
[3,] NA       NA  

The 3rd row is NA because the pattern didn’t match here.

We can get only the matched words also -

> str_match(c("color","colour","eye"), "col(?:o|ou)r")
     [,1]    
[1,] "color" 
[2,] "colour"
[3,] NA      

Getting logical output of matched strings

Using str_detect() -

> str_detect(fruit, "a")
[1] TRUE TRUE TRUE TRUE
> str_detect(fruit, "^a")
[1]  TRUE FALSE FALSE FALSE
> str_detect(fruit, "a$")
[1] FALSE  TRUE FALSE FALSE
> str_detect(fruit, "[aeiou]")
[1] TRUE TRUE TRUE TRUE

Finding matched string’s position

str_which() shows the index of the matching string-

> string5 <- "I can can the can. This is nothing but fun. But how?"
> str_split(string5," ")[[1]]
 [1] "I"       "can"     "can"     "the"     "can."    "This"    "is"     
 [8] "nothing" "but"     "fun."    "But"     "how?"   
> str_which(str_split(string5," ")[[1]], pattern = "can")
[1] 2 3 5

The above example takes a vector of strings as input.

Finding starting and ending index of matched string

> string5
[1] "I can can the can. This is nothing but fun. But how?"

Returns a list of matrix -

> str_locate_all(string5, "can")
[[1]]
     start end
[1,]     3   5
[2,]     7   9
[3,]    15  17
> str_locate_all(string5, c("can","fun"))
[[1]]
     start end
[1,]     3   5
[2,]     7   9
[3,]    15  17

[[2]]
     start end
[1,]    40  42

Finding words by no. of position

> word("A small example of string.", start=1, end=4)
[1] "A small example of"
> word("A small example of string.", start=3, end=-1)
[1] "example of string."

Negative values in end count backwards from the last character.

Counting the no. of matches in a string

Look at the example string5 -

> string5
[1] "I can can the can. This is nothing but fun. But how?"

Usingstr_count() -

> str_count(string5, "can")
[1] 3

Finding strings by index

> str_sub("A small example of string.", start=3)
[1] "small example of string."
> str_sub("A small example of string.", end=3)
[1] "A s"
> str_sub("A small example of string.", start=3, end=10)
[1] "small ex"

Replacing strings

To replace all matches -

> string6 <- "Everyone loves cat. Cat is sweet, and cat is smol."
> str_replace_all(string6, 
+                 pattern = fixed("cat", ignore_case = T),
+                 replacement = "dog")
[1] "Everyone loves dog. dog is sweet, and dog is smol."

Applying function as replacement -

> str_replace_all(string6, pattern = fixed("cat", ignore_case = T),
+             replacement = toupper)
[1] "Everyone loves CAT. CAT is sweet, and CAT is smol."

More examples -

> fruits <- c("one apple", "two pears", "three bananas")
> str_replace(fruits, "[aeiou]", "-")    # replaces only the first match
[1] "-ne apple"     "tw- pears"     "thr-e bananas"
> str_replace_all(fruits, "[aeiou]", "-")  # replaces all
[1] "-n- -ppl-"     "tw- p--rs"     "thr-- b-n-n-s"
> str_replace_all(fruits, "two", NA_character_)  # turns the matched string into NA
[1] "one apple"     NA              "three bananas"
> str_replace(fruits, "([aeiou])", "")   # deletes the matched string
[1] "ne apple"     "tw pears"     "thre bananas"

To know details on regex and stringr click here.

Answers to R homework questions by experts at https://www.homeworkhelponline.net/programming/r-programming.

LS0tDQp0aXRsZTogU3RyaW5nciBQYWNrYWdlIEJhc2ljIE9wZXJhdGlvbnMNCmF1dGhvcjogTUQgQUhTQU5VTCBJU0xBTQ0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0aGVtZTogcmVhZGFibGUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQotLS0NCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoDQogIGNvbW1lbnQgPSAiIiwgcHJvbXB0ID0gVFJVRSwgbWVzc2FnZT1GLCB3YXJuaW5nID1GDQopDQpgYGANCg0KSW1wb3J0IHRoZSBgc3RyaW5ncmAgbGlicmFyeSAtDQpgYGB7cn0NCmxpYnJhcnkoc3RyaW5ncikNCmBgYA0KDQpBbGwgdGhlIHN0cmluZ3IncyBmdW5jdGlvbnMgc3RhcnRzIHdpdGggYHN0cl9gLg0KDQoNCiMjIExlbmd0aCBvZiBzdHJpbmdzDQoNCkZ1bmN0aW9uOiBzdHJfbGVuZ3RoKCkgICAgDQpgYGB7cn0NCnN0cl9sZW5ndGgoIkRvIHRoZSB3b3JrIikNCnN0cl9sZW5ndGgoYygiVGhpcyIsIkdPT2dsZSIsIkFlaW9VIikpDQpgYGANClNwYWNlcyBhcmUgY291bnRlZCBhcyBhIGNoYXJhY3Rlci4NCg0KT3IgdGhlIGJhc2UgUiBmdW5jdGlvbjogbmNoYXIoKSANCmBgYHtyfQ0KbmNoYXIoIkRvIHRoZSB3b3JrIikNCm5jaGFyKGMoIlRoaXMiLCJHT09nbGUiLCJBZWlvVSIpKQ0KYGBgDQoNCiMjIENvdmVydGluZyBjYXNlIA0KDQojIyMgQWxsIHVwcGVyIGNhc2UNCg0KRnVuY3Rpb246IHN0cl90b191cHBlcigpDQpgYGB7cn0NCnN0cl90b191cHBlcigiZG9uJ3QgZ28gdGhlcmUiKQ0Kc3RyX3RvX3VwcGVyKGMoIlRoaXMiLCJHT09nbGUiLCJBZWlvVSIpKQ0KYGBgDQoNCiMjIyBBbGwgbG93ZXIgY2FzZQ0KDQpgYGB7cn0NCnN0cl90b19sb3dlcigiZG9uJ3QgZ28gdGhlcmUiKQ0Kc3RyX3RvX2xvd2VyKGMoIlRoaXMiLCJHT09nbGUiLCJBZWlvVSIpKQ0KYGBgDQoNCiMjIyBUaXRsZSBsaWtlIGZvcm1hdGluZw0KDQpgYGB7cn0NCnN0cl90b190aXRsZSgidGhlIGZJTkFMIGRlc3RpTkFUSU9OIikNCmBgYA0KDQojIyMgU2VudGVuY2UgbGlrZSBmb3JtYXRpbmcNCg0KYGBge3J9DQpzdHJfdG9fc2VudGVuY2UoInRoaXMgSXMgTm90aGluZyBCVVQgYSBzZW50ZW5jZSIpDQpgYGANCg0KIyMgVHJpbQ0KDQojIyMgVHJpbSBib3RoIHNpZGVzDQpgYGB7cn0NCnN0cl90cmltKCIgICBUaGlzIGlzIGdvb2QhICAgIikNCmBgYA0KDQojIyMgVHJpbSByaWdodCBzaWRlDQpgYGB7cn0NCnN0cl90cmltKCIgICBUaGlzIGlzIGdvb2QhICAgIiwgc2lkZT0icmlnaHQiKQ0KYGBgDQoNCiMjIyBUcmltIGxlZnQgc2lkZQ0KYGBge3J9DQpzdHJfdHJpbSgiICAgVGhpcyBpcyBnb29kISAgICIsIHNpZGU9ImxlZnQiKQ0KYGBgDQoNCiMjIFBhZGRpbmcNCg0KYGBge3J9DQpyYmluZCgNCiAgc3RyX3BhZChjKCJkbyIpLCB3aWR0aD0iMTAiLCBzaWRlPSJib3RoIixwYWQ9IiQiKSwNCiAgc3RyX3BhZChjKCJkbyIpLCB3aWR0aD0iMTAiLCBzaWRlPSJib3RoIixwYWQ9IiAiKSwNCiAgc3RyX3BhZChjKCJ0aGlzIiksIHdpZHRoPSIxMCIsIHNpZGU9InJpZ2h0IixwYWQ9Ii0iKSwNCiAgc3RyX3BhZChjKCJubyB3YXkiKSwgd2lkdGg9IjEwIixzaWRlPSJsZWZ0IixwYWQ9Ii0iKQ0KKQ0KYGBgDQoNCiMjIFRydW5jYXRlIA0KDQpgYGB7cn0NCnN0cmluZzEgPC0gIkFuIGludHJvZHVjdGlvbiB0byB0aGUgc2NpZW5jZSBvZiBsaWZlLiINCnJiaW5kKA0KICBzdHJfdHJ1bmMoc3RyaW5nMSwgd2lkdGg9MzAsICJyaWdodCIpLA0KICBzdHJfdHJ1bmMoc3RyaW5nMSwgd2lkdGg9MzAsICJsZWZ0IiksDQogIHN0cl90cnVuYyhzdHJpbmcxLCB3aWR0aD0zMCwgImNlbnRlciIpDQopDQpgYGANCg0KIyMgU3BsaXQgc2VudGVuY2UNCg0KIyMjIFNwbGl0IGJ5IHNvbWV0aGluZw0KDQpgYGB7cn0NCnNlbjEgPC0gIlRoaXMgaXMgT0ssIGJ1dCBob3chIEFsYXMhIEFuZCwgdGhlcmUgd2FzIG5vdGhpbmchIg0Kc3RyX3NwbGl0KHNlbjEsIHBhdHRlcm49IiAiKQ0Kc3RyX3NwbGl0KHNlbjEsICIsICIpDQpzdHJfc3BsaXQoc2VuMSwgIiEgIikNCmBgYA0KDQpUaGUgc2ltcGxpZnkgYXJndW1lbnQgZGV0ZXJtaW5lZCB3aGF0IHRvIHJldHVybi4gSWYgRkFMU0UsIGl0IHJldHVybnMgYSBsaXN0IG9mIGNoYXJhY3RlciB2ZWN0b3JzLiBJZiBUUlVFIHJldHVybnMgYSBjaGFyYWN0ZXIgbWF0cml4IC0gDQpgYGB7cn0NCnN0cl9zcGxpdChzZW4xLCAiICIsIHNpbXBsaWZ5ID0gRikNCnN0cl9zcGxpdChzZW4xLCAiICIsIHNpbXBsaWZ5ID0gVCkNCmBgYA0KDQojIyMgU3BsaXQgaW4gbGltaXRlZCBudW1iZXJzDQoNCmBgYHtyfQ0Kc2VuMSA8LSAiVGhpcyBpcyBPSywgYnV0IGhvdyEgQWxhcyEgQW5kLCB0aGVyZSB3YXMgbm90aGluZyEiDQpzdHJfc3BsaXQoc2VuMSwgcGF0dGVybj0iICIsIG49OCkNCmBgYA0KSGVyZSB0aGUgc2VudGVuY2UgaXMgc3BsaXQgaW50byA4IHBhcnRzLg0KDQojIyBKb2luIHN0cmluZ3MNCg0KVXNpbmcgc3RyX2MoKSAtDQpgYGB7cn0NCnN0cl9jKCJKb2luIiwgInRoaXMhIiwgc2VwPSJfIikNCnN0cl9jKCBjKCJObyIsIlllcyIpLA0KICAgICAgIGMoIndheSIsICJ5ZXNzcyIpLCANCiAgICAgICBzZXAgPSAiICIpDQpgYGANCg0KSXQgaXMgZXF1aXZhbGVudCB0byB0aGUgZnVuY3Rpb24gYHBhc3RlKClgIGZyb20gYmFzZSBSIC0NCmBgYHtyfQ0KcGFzdGUoIkpvaW4iLCAidGhpcyEiLCBzZXA9Il8iKQ0KcGFzdGUoIGMoIk5vIiwiWWVzIiksDQogICAgICAgYygid2F5IiwgInllc3NzIiksIA0KICAgICAgIHNlcCA9ICIgIikNCmBgYA0KDQojIyMgY29sbGFwc2UNCg0KQ29sbGFwc2UgYSB2ZWN0b3Igb2Ygc3RyaW5ncyBpbnRvIGEgc2luZ2xlIHN0cmluZyAtIA0KYGBge3J9DQpzdHJfYyhzdHJpbmcgPSBjKCJ0aGlzIiwiaXMiLCJqdXN0IiwiYW4iLCJleGFtcGxlIiksICBzZXA9Il8iKQ0KYGBgDQoNCk5PVElDRTogVGhpcyBpcyBub3QgYSB2ZWN0b3Igb2Ygd29yZHMsIGJ1dCBwcmV2aW91cyBvbmUgd2FzIC0gDQpgYGB7cn0NCnN0cl9jKCJ0aGlzIiwiaXMiLCJqdXN0IiwiYW4iLCJleGFtcGxlIiwgIHNlcD0iXyIpDQpgYGANCg0KIyMgUmVtb3Zpbmcgc3RyaW5ncw0KDQpMZXRzIGxvb2sgYXQgdGhlIHZlY3RvciBvZiBzdHJpbmdzIHRoYXQgc2hvdWxkIGJlIG9mIG51bWVyaWMgdHlwZSAtDQpgYGB7cn0NCmNvc3QgPC0gYygiMSw1NzkiLCIxLDk3NSIsIjMsMDAwIiwiMiw1MDAiKQ0KYXMubnVtZXJpYyhjb3N0KQ0KYGBgDQpTbywgd2UgaGF2ZSB0byByZW1vdmUgdGhlIGNvbW1hcyBmcm9tIHRoZSB2YWx1ZXMgYmVmb3JlIGNvbnZlcnRpbmcgaW50byBudW1lcmljIC0gDQpgYGB7cn0NCmNvc3QgPC0gc3RyX3JlbW92ZShzdHJpbmcgPSBjb3N0LCBwYXR0ZXJuID0gIiwiKQ0KY29zdCAgIyBzZWUgdGhlIHZlY3Rvcg0KYXMubnVtZXJpYyhjb3N0KQ0KYGBgDQoNCg0KIyMgUmVwbGFjaW5nIE5BIA0KDQpCeSBkZWZhdWx0IE5BIHR1cm5zIGludG8gYSBzdHJpbmcgIk5BIiAtDQpgYGB7cn0NCnN0cmluZzMgPC0gYygib25lIHdvcmQiLCBOQSwgImFub3RoZXIiLCAid29yZCIpDQpzdHJpbmczDQpzdHJfcmVwbGFjZV9uYShzdHJpbmczKQ0KYGBgDQoNCkJ1dCB1c2luZyB0aGUgcmVwbGFjZW1lbnQgYXJndW1lbnQgTkEgY2FuIGJlIHJlcGxhY2VkIHRvIGFueXRoaW5nIC0NCmBgYHtyfQ0Kc3RyX3JlcGxhY2VfbmEoc3RyaW5nMywgcmVwbGFjZW1lbnQgPSA5OSkNCmBgYA0KDQojIyBTb3J0aW5nDQoNCnN0cl9zb3J0KCkgc29ydHMgaW4gYWxwaGFiZXRpY2FsIG9yZGVyIC0NCmBgYHtyfQ0Kc3RyaW5nNCA8LSBjKCJiIiwiYSIsImIiLCJCIiwicSIsIlkiKQ0Kc3RyX3NvcnQoc3RyaW5nNCkNCmBgYA0KDQpzdHJfb2RlcigpIHJldHVybnMgdGhlIG9yZGVyIG9mIHRoZSBzdHJpbmdzIC0gDQpgYGB7cn0NCnN0cl9vcmRlcihzdHJpbmc0KQ0Kc3RyaW5nNFtzdHJfb3JkZXIoc3RyaW5nNCldICMgZXF1aXZhbGVudCB0byBzdHJfc29ydCgpDQpgYGANCg0KSGVyZSBiYXNlIFIncyBzb3J0KCkgY2FuIGFsc28gYmUgdXNlZCAtIA0KYGBge3J9DQonYicgPCAnQicNCnNvcnQoc3RyaW5nNCkNCmBgYA0KDQojIyBJbnNlcnQgdmFyaWFibGUgdmFsdWVzIGludG8gc3RyaW5ncw0KDQpVc2luZyB0aGUgZnVuY3Rpb24gYHN0cl9nbHVlKClgIC0gDQpgYGB7cn0NCmZuYW1lIDwtIGMoIkFoc2FudWwiLCJBdGF1ciIsIk1laGVkaSIpDQpsbmFtZSA8LSBjKCJJc2xhbSIsIlJhaG1hbiIsIkhhc2FuIikNCnN0cl9nbHVlKCJIZSBpcyBteSBmcmllbmQsIHtmbmFtZX0ge2xuYW1lfS4iKQ0KYGBgDQoNCk1hdGhlbWF0aWNhbCBvcGVyYXRpb25zIGNhbiBiZSBkb25lIGluc2lkZSB0aGUge30gLQ0KYGBge3J9DQpmIDwtIDEwDQphZ2VzIDwtIGMoMjEsIDIyLCAxOSkNCnN0cl9nbHVlKCJ7Zm5hbWV9IHtsbmFtZX0gaXMge2FnZXN9IHllYXJzIG9sZCBub3cuIFxuQWZ0ZXIge2Z9IHllYXJzIGhlIHdpbGwgYmUge2FnZXMrZn0geWVhcnMgb2xkLlxuXG4iKQ0KYGBgDQoNCkFub3RoZXIgb25lIC0gDQpgYGB7cn0NCm51bXMgPC0gYygxMCwgMTAwLCA1LCA5KQ0Kc3RyX2dsdWUoIlRoZSBzcXVhcmUgb2Yge251bXN9IGlzIHtudW1zKioyfSIpDQpgYGANCg0KIyMgRXh0cmFjdCBhbGwgd29yZHMgZnJvbSBhIHNlbnRlbmNlIHN0cmluZw0KDQpVc2luZyBgc3RyX2V4dHJhY3RfYWxsKClgIGFuZCB1c2luZyB0aGUgYXJndW1lbnQgYm91bmRhcnkoIndvcmQiKSAtDQpgYGB7cn0NCnN0cl9leHRyYWN0X2FsbCgiVGhpcyBpcyBhbiBleGFtcGxlIHdvcmQuIEhvdyBpcyBpdD8iLCBwYXR0ZXJuID0gYm91bmRhcnkoIndvcmQiKSkNCmBgYA0KDQpJdCByZXR1cm5zIGEgbGlzdCBvZiB2ZWN0b3JzLQ0KYGBge3J9DQpzZW4yIDwtIGMoIlRoaXMgaXMgYW4gZXhhbXBsZSIsIlNlY29uZCwgRXhhbXBsZSIsIndvdyEgTmljZS4iKQ0Kc3RyX2V4dHJhY3RfYWxsKHNlbjIsIGJvdW5kYXJ5KCJ3b3JkIikpDQpzdHJfZXh0cmFjdF9hbGwoc2VuMiwgYm91bmRhcnkoIndvcmQiKSwgc2ltcGxpZnkgPSBUKSAgIyBSZXR1cm5zIGEgbWF0cml4DQpgYGANCg0KKipOb3RlOioqIEJvdW5kYXJ5IHRha2VzIHRoZSB2YWx1ZXMgLSAiY2hhcmFjdGVyIiwgImxpbmVfYnJlYWsiLCAic2VudGVuY2UiLCAid29yZCIuDQoNCiMjIE1hdGNoaW5nIHN0cmluZw0KDQojIyMgRXh0cmFjdGluZyBtYXRjaGluZyB3b3JkcyANCg0KDQpgYGB7cn0NCnN0cl9leHRyYWN0X2FsbCgiVEhJUyBpcyBub3RoaW5nIGJ1dCBhIHNlbnRlbmNlLiBIZSBpcyByaWdodCIsIHBhdHRlcm49Zml4ZWQoImlzIiwgaWdub3JlX2Nhc2UgPSBUKSkNCmBgYA0KDQpgYGB7cn0NCnN0cl9leHRyYWN0X2FsbCgiVEhJUyBpcyBub3RoaW5nIGJ1dCBhIHNlbnRlbmNlLiBIZSBpcyByaWdodCIsDQogICAgICAgICAgICAgICAgcGF0dGVybj0iaXN8YnV0IikgIyB0aGUgJ0lTJyBmcm9tICdUSElTJyB3aWxsIGJlIG1hdGNoZWQNCmBgYA0KTG9va3MgZm9yIGVpdGhlciBpcyBvciBidXQuDQoNCiMjIyBHZXR0aW5ncyBzdHJpbmdzIHRoYXQgbWF0Y2hlcyB0aGUgcGF0dGVybg0KDQpVc2luZyBgc3RyX3N1YnNldCgpYCAtIA0KYGBge3J9DQoNCmZydWl0IDwtIGMoImFwcGxlIiwgImJhbmFuYSIsICJQZWFyIiwgInBpbmFwcGxlIikNCnN0cl9zdWJzZXQoZnJ1aXQsICJiIikgICMgTG9va3MgZm9yIGIgaW4gYW55IHBvc2l0aW9uDQpzdHJfc3Vic2V0KGZydWl0LCAiXmEiKSAgIyBMb29rcyBmb3IgYSBpbiBmaXJzdCBwb3NpdGlvbg0Kc3RyX3N1YnNldChmcnVpdCwgImEkIikgICMgTG9va3MgZm9yIGEgaW4gbGFzdCBwb3NpdGlvbg0Kc3RyX3N1YnNldChmcnVpdCwgIlthZWlvdV0iKSAgIyBMb29rcyBmb3IgYW55IG9mIHRoZSBwYXR0ZXJucyBpbiBhbnkgcG9zaXRpb24NCnN0cl9zdWJzZXQoZnJ1aXQsICJbQS1aXSIpICAjIExvb2tzIGZvciBhbnkgb2YgdGhlIGxhdHRlcnMgQSB0byBCIA0KYGBgDQoNClRoZSBhcmd1bWVudCBuZWdhdGUgZGV0ZXJtaW5lcyB3aGF0IHN0cmluZ3MgdG8gcmV0dXJuLCBtYXRjaGVkIG9yIG5vdCBtYXRjaGVkIC0NCmBgYHtyfQ0Kc3RyX3N1YnNldChmcnVpdCwgImIiKQ0Kc3RyX3N1YnNldChmcnVpdCwgImIiLCBuZWdhdGUgPSBUKQ0KYGBgDQoNCiMjIyBGaW5kaW5nIG1hdGNoZWQgc3RyaW5nIHVzaW5nIHN0cl9tYXRjaCgpDQoNClN1cHBvc2Ugd2UgaGF2ZSB0d28gZGlmZmVyZW50IHdvcmRzIHdoaWNoIGlzIHNpbWlsYXIgaW4gbWVhbmluZyBidXQgaGFzIHNsaWdodGx5IGRpZmZlcmVudCBzcGVsbGluZy4gSW4gdGhlc2UgY2FzZSB3ZSBjYW4gZ2V0IGEgbWF0cml4IGluIHJldHVybiB3aXRoIHdvcmRzIGFuZCB0aGVpciBtYXRjaGVkIHBhcnQgdXNpbmcgc3RyX21hdGNoKCkgLSANCmBgYHtyfQ0Kc3RyX21hdGNoKGMoImNvbG9yIiwiY29sb3VyIiwiZXllIiksICJjb2xvKHx1KXIiKSAjICJjb2wob3xvdSlyIiBjYW4gYmUgdXNlZCBhbHNvDQpgYGANClRoZSAzcmQgcm93IGlzIE5BIGJlY2F1c2UgdGhlIHBhdHRlcm4gZGlkbid0IG1hdGNoIGhlcmUuDQoNCldlIGNhbiBnZXQgb25seSB0aGUgbWF0Y2hlZCB3b3JkcyBhbHNvIC0gDQpgYGB7cn0NCnN0cl9tYXRjaChjKCJjb2xvciIsImNvbG91ciIsImV5ZSIpLCAiY29sKD86b3xvdSlyIikNCg0KYGBgDQoNCg0KIyMjIEdldHRpbmcgbG9naWNhbCBvdXRwdXQgb2YgbWF0Y2hlZCBzdHJpbmdzDQoNClVzaW5nIGBzdHJfZGV0ZWN0KClgIC0gDQpgYGB7cn0NCnN0cl9kZXRlY3QoZnJ1aXQsICJhIikNCnN0cl9kZXRlY3QoZnJ1aXQsICJeYSIpDQpzdHJfZGV0ZWN0KGZydWl0LCAiYSQiKQ0Kc3RyX2RldGVjdChmcnVpdCwgIlthZWlvdV0iKQ0KYGBgDQoNCiMjIyBGaW5kaW5nIG1hdGNoZWQgc3RyaW5nJ3MgcG9zaXRpb24NCg0KYHN0cl93aGljaCgpYCBzaG93cyB0aGUgaW5kZXggb2YgdGhlIG1hdGNoaW5nIHN0cmluZy0NCmBgYHtyfQ0Kc3RyaW5nNSA8LSAiSSBjYW4gY2FuIHRoZSBjYW4uIFRoaXMgaXMgbm90aGluZyBidXQgZnVuLiBCdXQgaG93PyINCnN0cl9zcGxpdChzdHJpbmc1LCIgIilbWzFdXQ0Kc3RyX3doaWNoKHN0cl9zcGxpdChzdHJpbmc1LCIgIilbWzFdXSwgcGF0dGVybiA9ICJjYW4iKQ0KYGBgDQpUaGUgYWJvdmUgZXhhbXBsZSB0YWtlcyBhIHZlY3RvciBvZiBzdHJpbmdzIGFzIGlucHV0Lg0KDQojIyMgRmluZGluZyBzdGFydGluZyBhbmQgZW5kaW5nIGluZGV4IG9mIG1hdGNoZWQgc3RyaW5nDQoNCmBgYHtyfQ0Kc3RyaW5nNQ0KYGBgDQoNClJldHVybnMgYSBsaXN0IG9mIG1hdHJpeCAtIA0KYGBge3J9DQpzdHJfbG9jYXRlX2FsbChzdHJpbmc1LCAiY2FuIikNCnN0cl9sb2NhdGVfYWxsKHN0cmluZzUsIGMoImNhbiIsImZ1biIpKQ0KYGBgDQoNCiMjIyBGaW5kaW5nIHdvcmRzIGJ5IG5vLiBvZiBwb3NpdGlvbg0KDQpgYGB7cn0NCndvcmQoIkEgc21hbGwgZXhhbXBsZSBvZiBzdHJpbmcuIiwgc3RhcnQ9MSwgZW5kPTQpDQp3b3JkKCJBIHNtYWxsIGV4YW1wbGUgb2Ygc3RyaW5nLiIsIHN0YXJ0PTMsIGVuZD0tMSkNCmBgYA0KTmVnYXRpdmUgdmFsdWVzIGluIGVuZCBjb3VudCBiYWNrd2FyZHMgZnJvbSB0aGUgbGFzdCBjaGFyYWN0ZXIuDQoNCiMjIyBDb3VudGluZyB0aGUgbm8uIG9mIG1hdGNoZXMgaW4gYSBzdHJpbmcNCg0KTG9vayBhdCB0aGUgZXhhbXBsZSBzdHJpbmc1IC0gDQpgYGB7cn0NCnN0cmluZzUNCmBgYA0KDQpVc2luZ2Agc3RyX2NvdW50KClgIC0NCmBgYHtyfQ0Kc3RyX2NvdW50KHN0cmluZzUsICJjYW4iKQ0KYGBgDQoNCiMjIyBGaW5kaW5nIHN0cmluZ3MgYnkgaW5kZXgNCg0KYGBge3J9DQpzdHJfc3ViKCJBIHNtYWxsIGV4YW1wbGUgb2Ygc3RyaW5nLiIsIHN0YXJ0PTMpDQpzdHJfc3ViKCJBIHNtYWxsIGV4YW1wbGUgb2Ygc3RyaW5nLiIsIGVuZD0zKQ0Kc3RyX3N1YigiQSBzbWFsbCBleGFtcGxlIG9mIHN0cmluZy4iLCBzdGFydD0zLCBlbmQ9MTApDQpgYGANCg0KIyMgUmVwbGFjaW5nIHN0cmluZ3MNCg0KVG8gcmVwbGFjZSBhbGwgbWF0Y2hlcyAtIA0KYGBge3J9DQpzdHJpbmc2IDwtICJFdmVyeW9uZSBsb3ZlcyBjYXQuIENhdCBpcyBzd2VldCwgYW5kIGNhdCBpcyBzbW9sLiINCnN0cl9yZXBsYWNlX2FsbChzdHJpbmc2LCANCiAgICAgICAgICAgICAgICBwYXR0ZXJuID0gZml4ZWQoImNhdCIsIGlnbm9yZV9jYXNlID0gVCksDQogICAgICAgICAgICAgICAgcmVwbGFjZW1lbnQgPSAiZG9nIikNCmBgYA0KDQpBcHBseWluZyBmdW5jdGlvbiBhcyByZXBsYWNlbWVudCAtIA0KYGBge3J9DQpzdHJfcmVwbGFjZV9hbGwoc3RyaW5nNiwgcGF0dGVybiA9IGZpeGVkKCJjYXQiLCBpZ25vcmVfY2FzZSA9IFQpLA0KICAgICAgICAgICAgcmVwbGFjZW1lbnQgPSB0b3VwcGVyKQ0KYGBgDQoNCk1vcmUgZXhhbXBsZXMgLSANCmBgYHtyfQ0KZnJ1aXRzIDwtIGMoIm9uZSBhcHBsZSIsICJ0d28gcGVhcnMiLCAidGhyZWUgYmFuYW5hcyIpDQpzdHJfcmVwbGFjZShmcnVpdHMsICJbYWVpb3VdIiwgIi0iKSAgICAjIHJlcGxhY2VzIG9ubHkgdGhlIGZpcnN0IG1hdGNoDQpzdHJfcmVwbGFjZV9hbGwoZnJ1aXRzLCAiW2FlaW91XSIsICItIikgICMgcmVwbGFjZXMgYWxsDQpzdHJfcmVwbGFjZV9hbGwoZnJ1aXRzLCAidHdvIiwgTkFfY2hhcmFjdGVyXykgICMgdHVybnMgdGhlIG1hdGNoZWQgc3RyaW5nIGludG8gTkENCnN0cl9yZXBsYWNlKGZydWl0cywgIihbYWVpb3VdKSIsICIiKSAgICMgZGVsZXRlcyB0aGUgbWF0Y2hlZCBzdHJpbmcNCmBgYA0KDQpUbyBrbm93IGRldGFpbHMgb24gcmVnZXggYW5kIHN0cmluZ3IgW2NsaWNrIGhlcmUuXShodHRwczovL3N0cmluZ3IudGlkeXZlcnNlLm9yZy9hcnRpY2xlcy9yZWd1bGFyLWV4cHJlc3Npb25zLmh0bWwpDQoNCkFuc3dlcnMgdG8gUiBob21ld29yayBxdWVzdGlvbnMgYnkgZXhwZXJ0cyBhdCBbaHR0cHM6Ly93d3cuaG9tZXdvcmtoZWxwb25saW5lLm5ldC9wcm9ncmFtbWluZy9yLXByb2dyYW1taW5nXShodHRwczovL3d3dy5ob21ld29ya2hlbHBvbmxpbmUubmV0L3Byb2dyYW1taW5nL3ItcHJvZ3JhbW1pbmcgIlIgU3R1ZGlvIGV4cGVydHMiKS4NCg0K