library(tidyverse)
library(openintro)
library(stringr)
library(lubridate)
library(nycflights13)

Exercise 14.2.5.1

paste() and paste0() differ in how they handle separators:

  • paste() adds a space by default (sep = ” “)
  • paste0() adds no separator (sep = ““)
paste("red", "apple")   # "red apple"
## [1] "red apple"
paste0("red", "apple")  # "redapple"
## [1] "redapple"

Both are equivalent to str_c() from stringr:

  • paste() ≈ str_c(…, sep = ” “)
  • paste0() ≈ str_c(…, sep = ““)

They also differ in handling missing values:

  • paste() and paste0() convert NA to “NA”
  • str_c() returns NA if any input is missing
paste("apple", NA)      # "apple NA"
## [1] "apple NA"
paste0("apple", NA)     # "appleNA"
## [1] "appleNA"
str_c("apple", NA)      # NA
## [1] NA

Exercise 14.2.5.4

str_wrap() breaks long text into multiple lines based on a specified width, improving readability.

text <- "This is a very long sentence that would be difficult to read if it stayed on one line."
str_wrap(text, width = 20)
## [1] "This is a very long\nsentence that would\nbe difficult to read\nif it stayed on one\nline."

It is useful for:

  • Formatting text in reports or R Markdown
  • Improving plot labels
  • Displaying text in fixed-width spaces

Exercise 14.2.5.5

str_trim() removes whitespace from the beginning and end of a string.

text <- "   apples and oranges   "
str_trim(text)
## [1] "apples and oranges"
# "apples and oranges"

The opposite is str_pad(), which adds padding to a string.

str_pad("apples", width = 10, side = "right")
## [1] "apples    "

Exercises 14.3.1.1

Question 1

Backslash () is a special escape character in both R and regex, so it must be escaped twice.

“\\” correctly matches a single backslash (R: \\ → regex: \ → literal )

Some strings like “" are invalid because the backslash escapes the quote.

Question 2

To match the sequence “ (double quote + backslash):

"\"\\\\"
## [1] "\"\\\\"
  • " = literal quote
  • \\ = literal backslash

Question 3

Regex:

......

This matches three literal periods (…) because each . represents a dot. R string representation:

"\\.\\.\\."
## [1] "\\.\\.\\."

Exercises 14.3.2.1

Question 1

“\$\\$”

\^ matches a literal ^

\$ matches a literal $

Question 2

words <- stringr::words

# Starts with "y"
str_view(words, "^y")
## [975] │ <y>ear
## [976] │ <y>es
## [977] │ <y>esterday
## [978] │ <y>et
## [979] │ <y>ou
## [980] │ <y>oung
# Ends with "x"
str_view(words, "x$")
## [108] │ bo<x>
## [747] │ se<x>
## [772] │ si<x>
## [841] │ ta<x>
# Exactly 3 letters
str_view(words, "^...$")
##   [9] │ <act>
##  [12] │ <add>
##  [22] │ <age>
##  [24] │ <ago>
##  [26] │ <air>
##  [27] │ <all>
##  [38] │ <and>
##  [41] │ <any>
##  [51] │ <arm>
##  [54] │ <art>
##  [56] │ <ask>
##  [68] │ <bad>
##  [69] │ <bag>
##  [73] │ <bar>
##  [82] │ <bed>
##  [89] │ <bet>
##  [91] │ <big>
##  [94] │ <bit>
## [108] │ <box>
## [109] │ <boy>
## ... and 90 more
# 7 or more letters
str_view(words, "^.{7,}$")
##  [4] │ <absolute>
##  [6] │ <account>
##  [7] │ <achieve>
## [13] │ <address>
## [15] │ <advertise>
## [19] │ <afternoon>
## [21] │ <against>
## [31] │ <already>
## [32] │ <alright>
## [34] │ <although>
## [36] │ <america>
## [39] │ <another>
## [43] │ <apparent>
## [46] │ <appoint>
## [47] │ <approach>
## [48] │ <appropriate>
## [53] │ <arrange>
## [57] │ <associate>
## [61] │ <authority>
## [62] │ <available>
## ... and 199 more

Exercises 14.4.1.1

Question 1

x <- "a/b/c"
str_replace_all(x, "/", "\\\\")
## [1] "a\\b\\c"

To replace all forward slashes with backslashes, use str_replace_all(x, “/”, “\\”). The replacement string requires four backslashes because backslash is a special escape character in R strings.

Exercises 14.4.2.1

Question 1

x <- c("red", "blue", "flickered", "dark red", "red wine")
str_view(x, "\\bred\\b")
## [1] │ <red>
## [4] │ dark <red>
## [5] │ <red> wine

The original regex matched "flickered" because it contained the letters "red" inside the word. To fix this, use word boundaries so that "red" is matched only as a complete word.

Exercise 15.3.1.1

gss_cat %>%
  count(rincome) %>%
  ggplot(aes(x = fct_reorder(rincome, n), y = n)) +
  geom_col() +
  coord_flip() +
  labs(
    x = "Reported income",
    y = "Count",
    title = "Distribution of Reported Income"
  )

The default bar chart of rincome is difficult to interpret because it contains many categories with long labels, including nonresponse categories such as “No answer,” “Don’t know,” and “Refused.” These make the x-axis crowded and hard to read, and it becomes difficult to compare frequencies across income groups.

The plot can be improved by reordering the categories by frequency and flipping the coordinates so the labels are easier to read. In the improved version, the income categories are displayed vertically, which makes the labels more legible and allows for easier comparison of counts.

Exercises 15.4.1

Question 1

The histogram shows outliers, and the mean is higher than the median, indicating skew. Therefore, the mean is not a good summary.

# View distribution
gss_cat %>%
  ggplot(aes(x = tvhours)) +
  geom_histogram(binwidth = 1)
## Warning: Removed 10146 rows containing non-finite outside the scale range
## (`stat_bin()`).

# Summary stats
gss_cat %>%
  summarize(
    mean = mean(tvhours, na.rm = TRUE),
    median = median(tvhours, na.rm = TRUE),
    max = max(tvhours, na.rm = TRUE)
  )
## # A tibble: 1 × 3
##    mean median   max
##   <dbl>  <int> <int>
## 1  2.98      2    24

Question 2

levels(gss_cat$relig)
##  [1] "No answer"               "Don't know"             
##  [3] "Inter-nondenominational" "Native american"        
##  [5] "Christian"               "Orthodox-christian"     
##  [7] "Moslem/islam"            "Other eastern"          
##  [9] "Hinduism"                "Buddhism"               
## [11] "Other"                   "None"                   
## [13] "Jewish"                  "Catholic"               
## [15] "Protestant"              "Not applicable"
levels(gss_cat$denom)
##  [1] "No answer"            "Don't know"           "No denomination"     
##  [4] "Other"                "Episcopal"            "Presbyterian-dk wh"  
##  [7] "Presbyterian, merged" "Other presbyterian"   "United pres ch in us"
## [10] "Presbyterian c in us" "Lutheran-dk which"    "Evangelical luth"    
## [13] "Other lutheran"       "Wi evan luth synod"   "Lutheran-mo synod"   
## [16] "Luth ch in america"   "Am lutheran"          "Methodist-dk which"  
## [19] "Other methodist"      "United methodist"     "Afr meth ep zion"    
## [22] "Afr meth episcopal"   "Baptist-dk which"     "Other baptists"      
## [25] "Southern baptist"     "Nat bapt conv usa"    "Nat bapt conv of am" 
## [28] "Am bapt ch in usa"    "Am baptist asso"      "Not applicable"
levels(gss_cat$race)
## [1] "Other"          "Black"          "White"          "Not applicable"
levels(gss_cat$partyid)
##  [1] "No answer"          "Don't know"         "Other party"       
##  [4] "Strong republican"  "Not str republican" "Ind,near rep"      
##  [7] "Independent"        "Ind,near dem"       "Not str democrat"  
## [10] "Strong democrat"
levels(gss_cat$rincome)
##  [1] "No answer"      "Don't know"     "Refused"        "$25000 or more"
##  [5] "$20000 - 24999" "$15000 - 19999" "$10000 - 14999" "$8000 to 9999" 
##  [9] "$7000 to 7999"  "$6000 to 6999"  "$5000 to 5999"  "$4000 to 4999" 
## [13] "$3000 to 3999"  "$1000 to 2999"  "Lt $1000"       "Not applicable"
  • relig: Arbitrary; Religious categories do not have a natural ranking order
  • denom: Arbitrary; Denominations are nominal groupings and do not follow a meaningful order
  • race: Arbitrary; Race categories are categorical labels without any inherent ordering.
  • partyid: Principled; The categories follow a meaningful political spectrum from strong Democrat to strong Republican.
  • rincome: Principled; Income categories have a natural increasing order based on income level.

Question 3

When “Not applicable” was moved to the front of the factor levels, it appeared at the bottom of the plot because ggplot2 displays factor levels in order, and coord_flip() reverses the axes.

As a result:

-The first level of the factor is plotted at the bottom -The last level is plotted at the top

Therefore, moving “Not applicable” to the front of the levels caused it to appear at the bottom of the flipped bar chart.

Exercises 15.5.1

Question 1

The proportion of individuals identifying as Independent has increased over time, while Democrat and Republican proportions remain relatively stable with some fluctuations.

gss_cat %>%
  filter(!is.na(year)) %>%
  mutate(party_simple = fct_collapse(
    partyid,
    "Democrat" = c("Strong democrat", "Not str democrat"),
    "Independent" = c("Ind,near dem", "Independent", "Ind,near rep"),
    "Republican" = c("Not str republican", "Strong republican")
  )) %>%
  count(year, party_simple) %>%
  group_by(year) %>%
  mutate(prop = n / sum(n)) %>%
  ggplot(aes(x = year, y = prop, color = party_simple)) +
  geom_line() +
  labs(
    title = "Party Identification Over Time",
    y = "Proportion",
    x = "Year"
  )

Question 2

The variable rincome can be collapsed into broader categories such as low, middle, and high income using fct_collapse(). Nonresponse categories can also be grouped separately to simplify the analysis.

gss_cat %>%
  mutate(rincome_group = fct_collapse(
    rincome,
    "Low" = c("Lt $1000", "$1000 to 2999", "$3000 to 3999"),
    "Middle" = c("$4000 to 4999", "$5000 to 5999", "$6000 to 6999",
                 "$7000 to 7999", "$8000 to 9999", "$10000 - 14999"),
    "High" = c("$15000 - 19999", "$20000 - 24999", "$25000 or more"),
    "No response" = c("No answer", "Don't know", "Refused", "Not applicable")
  )) %>%
  count(rincome_group)
## # A tibble: 4 × 2
##   rincome_group     n
##   <fct>         <int>
## 1 No response    8468
## 2 High           9694
## 3 Middle         2364
## 4 Low             957

Exercise 16.2.4.3

d1 <- "January 1, 2010"
mdy(d1)
## [1] "2010-01-01"
d2 <- "2015-Mar-07"
ymd(d2)
## [1] "2015-03-07"
d3 <- "06-Jun-2017"
dmy(d3)
## [1] "2017-06-06"
d4 <- c("August 19 (2015)", "July 1 (2015)")
mdy(d4)
## [1] "2015-08-19" "2015-07-01"
d5 <- "12/30/14"
mdy(d5)
## [1] "2014-12-30"

-d1 uses mdy() because it is in month-day-year format with a full month name -d2 uses ymd() because it is in year-month-day format -d3 uses dmy() because it is in day-month-year format -d4 uses mdy() because lubridate can handle the parentheses and still recognizes month-day-year -d5 uses mdy() because it is in numeric month/day/year format

Exercise 16.3.4.1

The distribution of departure delays varies across both the day and the year. In all months, flights in the early morning have relatively small and consistent delays, with most values clustered near zero. As the day progresses, delays become more variable and extreme, with the largest delays occurring in the afternoon and evening, indicating that delays accumulate throughout the day. Additionally, summer months show greater variability and more extreme delays compared to other times of the year, likely due to increased traffic and weather-related disruptions.

flights %>%
  filter(!is.na(dep_delay)) %>%
  mutate(
    month = month(time_hour, label = TRUE)
  ) %>%
  ggplot(aes(x = hour, y = dep_delay)) +
  geom_point(alpha = 0.3) +
  facet_wrap(~month) +
  labs(
    title = "Distribution of Departure Delays by Hour and Month",
    x = "Hour of Day",
    y = "Departure Delay"
  ) +
coord_cartesian(ylim = c(-50, 200))

Exercise 16.3.4.4

The average departure delay increases throughout most of the day. Flights scheduled in the early morning have the lowest average delays, and delays increase throughout the day, peaking in the evening at approximately 25 minutes before declining later at night. This pattern suggests that delays accumulate over the course of the day, likely because earlier delays affect later departures.

flights %>%
  filter(!is.na(dep_delay), !is.na(sched_dep_time)) %>%
  mutate(
    sched_hour = sched_dep_time %/% 100
  ) %>%
  group_by(sched_hour) %>%
  summarize(avg_delay = mean(dep_delay, na.rm = TRUE)) %>%
  ggplot(aes(x = sched_hour, y = avg_delay)) +
  geom_line() +
  geom_point() +
  labs(
    title = "Average Departure Delay by Scheduled Hour of Day",
    x = "Scheduled Departure Hour",
    y = "Average Departure Delay (minutes)"
  )

LS0tCnRpdGxlOiBIb21ld29yayA2CmF1dGhvcjogQ2FpdGxpbiBLZW5uZWR5CmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OiBvcGVuaW50cm86OmxhYl9yZXBvcnQKLS0tCgpgYGB7ciBsb2FkLXBhY2thZ2VzLCBtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShvcGVuaW50cm8pCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkobnljZmxpZ2h0czEzKQpgYGAKCiMjIyBFeGVyY2lzZSAxNC4yLjUuMQoKcGFzdGUoKSBhbmQgcGFzdGUwKCkgZGlmZmVyIGluIGhvdyB0aGV5IGhhbmRsZSBzZXBhcmF0b3JzOgoKLSBwYXN0ZSgpIGFkZHMgYSBzcGFjZSBieSBkZWZhdWx0IChzZXAgPSAiICIpCi0gcGFzdGUwKCkgYWRkcyBubyBzZXBhcmF0b3IgKHNlcCA9ICIiKQoKYGBge3J9CnBhc3RlKCJyZWQiLCAiYXBwbGUiKSAgICMgInJlZCBhcHBsZSIKcGFzdGUwKCJyZWQiLCAiYXBwbGUiKSAgIyAicmVkYXBwbGUiCmBgYAoKQm90aCBhcmUgZXF1aXZhbGVudCB0byBzdHJfYygpIGZyb20gc3RyaW5ncjoKCi0gcGFzdGUoKSDiiYggc3RyX2MoLi4uLCBzZXAgPSAiICIpCi0gcGFzdGUwKCkg4omIIHN0cl9jKC4uLiwgc2VwID0gIiIpCgpUaGV5IGFsc28gZGlmZmVyIGluIGhhbmRsaW5nIG1pc3NpbmcgdmFsdWVzOgoKLSBwYXN0ZSgpIGFuZCBwYXN0ZTAoKSBjb252ZXJ0IE5BIHRvICJOQSIKLSBzdHJfYygpIHJldHVybnMgTkEgaWYgYW55IGlucHV0IGlzIG1pc3NpbmcKCmBgYHtyfQpwYXN0ZSgiYXBwbGUiLCBOQSkgICAgICAjICJhcHBsZSBOQSIKcGFzdGUwKCJhcHBsZSIsIE5BKSAgICAgIyAiYXBwbGVOQSIKc3RyX2MoImFwcGxlIiwgTkEpICAgICAgIyBOQQpgYGAKCiMjIyBFeGVyY2lzZSAxNC4yLjUuNAoKc3RyX3dyYXAoKSBicmVha3MgbG9uZyB0ZXh0IGludG8gbXVsdGlwbGUgbGluZXMgYmFzZWQgb24gYSBzcGVjaWZpZWQgd2lkdGgsIGltcHJvdmluZyByZWFkYWJpbGl0eS4KCmBgYHtyfQp0ZXh0IDwtICJUaGlzIGlzIGEgdmVyeSBsb25nIHNlbnRlbmNlIHRoYXQgd291bGQgYmUgZGlmZmljdWx0IHRvIHJlYWQgaWYgaXQgc3RheWVkIG9uIG9uZSBsaW5lLiIKc3RyX3dyYXAodGV4dCwgd2lkdGggPSAyMCkKYGBgCgpJdCBpcyB1c2VmdWwgZm9yOgoKLSBGb3JtYXR0aW5nIHRleHQgaW4gcmVwb3J0cyBvciBSIE1hcmtkb3duCi0gSW1wcm92aW5nIHBsb3QgbGFiZWxzCi0gRGlzcGxheWluZyB0ZXh0IGluIGZpeGVkLXdpZHRoIHNwYWNlcwoKIyMjIEV4ZXJjaXNlIDE0LjIuNS41CgpzdHJfdHJpbSgpIHJlbW92ZXMgd2hpdGVzcGFjZSBmcm9tIHRoZSBiZWdpbm5pbmcgYW5kIGVuZCBvZiBhIHN0cmluZy4KCmBgYHtyfQp0ZXh0IDwtICIgICBhcHBsZXMgYW5kIG9yYW5nZXMgICAiCnN0cl90cmltKHRleHQpCiMgImFwcGxlcyBhbmQgb3JhbmdlcyIKYGBgCgpUaGUgb3Bwb3NpdGUgaXMgc3RyX3BhZCgpLCB3aGljaCBhZGRzIHBhZGRpbmcgdG8gYSBzdHJpbmcuCgpgYGB7cn0Kc3RyX3BhZCgiYXBwbGVzIiwgd2lkdGggPSAxMCwgc2lkZSA9ICJyaWdodCIpCmBgYAoKCiMjIyBFeGVyY2lzZXMgMTQuMy4xLjEKCiMjIyMgUXVlc3Rpb24gMQoKQmFja3NsYXNoIChcKSBpcyBhIHNwZWNpYWwgZXNjYXBlIGNoYXJhY3RlciBpbiBib3RoIFIgYW5kIHJlZ2V4LCBzbyBpdCBtdXN0IGJlIGVzY2FwZWQgdHdpY2UuCgoiXFxcXCIgY29ycmVjdGx5IG1hdGNoZXMgYSBzaW5nbGUgYmFja3NsYXNoCihSOiBcXFxcIOKGkiByZWdleDogXFwg4oaSIGxpdGVyYWwgXCkKClNvbWUgc3RyaW5ncyBsaWtlICJcIiBhcmUgaW52YWxpZCBiZWNhdXNlIHRoZSBiYWNrc2xhc2ggZXNjYXBlcyB0aGUgcXVvdGUuCgojIyMjIFF1ZXN0aW9uIDIKClRvIG1hdGNoIHRoZSBzZXF1ZW5jZSAiXCAoZG91YmxlIHF1b3RlICsgYmFja3NsYXNoKToKCmBgYHtyfQoiXCJcXFxcIgpgYGAKCi0gXCIgPSBsaXRlcmFsIHF1b3RlCi0gXFxcXCA9IGxpdGVyYWwgYmFja3NsYXNoCgojIyMjIFF1ZXN0aW9uIDMKClJlZ2V4OgoKXC4uXC4uXC4uCgpUaGlzIG1hdGNoZXMgdGhyZWUgbGl0ZXJhbCBwZXJpb2RzICguLi4pIGJlY2F1c2UgZWFjaCBcLiByZXByZXNlbnRzIGEgZG90LgpSIHN0cmluZyByZXByZXNlbnRhdGlvbjoKCmBgYHtyfQoiXFwuXFwuXFwuIgpgYGAKCgojIyMgRXhlcmNpc2VzIDE0LjMuMi4xIAoKIyMjIyBRdWVzdGlvbiAxCgoiXFxeXFwkXFxeXFwkIgoKXFxeIG1hdGNoZXMgYSBsaXRlcmFsIF4KClxcJCBtYXRjaGVzIGEgbGl0ZXJhbCAkCgojIyMjIFF1ZXN0aW9uIDIKCmBgYHtyfQp3b3JkcyA8LSBzdHJpbmdyOjp3b3JkcwoKIyBTdGFydHMgd2l0aCAieSIKc3RyX3ZpZXcod29yZHMsICJeeSIpCgojIEVuZHMgd2l0aCAieCIKc3RyX3ZpZXcod29yZHMsICJ4JCIpCgojIEV4YWN0bHkgMyBsZXR0ZXJzCnN0cl92aWV3KHdvcmRzLCAiXi4uLiQiKQoKIyA3IG9yIG1vcmUgbGV0dGVycwpzdHJfdmlldyh3b3JkcywgIl4uezcsfSQiKQpgYGAKCiMjIyBFeGVyY2lzZXMgMTQuNC4xLjEKCiMjIyMgUXVlc3Rpb24gMQoKYGBge3J9CnggPC0gImEvYi9jIgpzdHJfcmVwbGFjZV9hbGwoeCwgIi8iLCAiXFxcXCIpCmBgYAoKVG8gcmVwbGFjZSBhbGwgZm9yd2FyZCBzbGFzaGVzIHdpdGggYmFja3NsYXNoZXMsIHVzZSBzdHJfcmVwbGFjZV9hbGwoeCwgIi8iLCAiXFxcXCIpLiBUaGUgcmVwbGFjZW1lbnQgc3RyaW5nIHJlcXVpcmVzIGZvdXIgYmFja3NsYXNoZXMgYmVjYXVzZSBiYWNrc2xhc2ggaXMgYSBzcGVjaWFsIGVzY2FwZSBjaGFyYWN0ZXIgaW4gUiBzdHJpbmdzLgoKIyMjIEV4ZXJjaXNlcyAxNC40LjIuMQoKIyMjIyBRdWVzdGlvbiAxCgpgYGB7cn0KeCA8LSBjKCJyZWQiLCAiYmx1ZSIsICJmbGlja2VyZWQiLCAiZGFyayByZWQiLCAicmVkIHdpbmUiKQpzdHJfdmlldyh4LCAiXFxicmVkXFxiIikKYGBgCgpUaGUgb3JpZ2luYWwgcmVnZXggbWF0Y2hlZCBgImZsaWNrZXJlZCJgIGJlY2F1c2UgaXQgY29udGFpbmVkIHRoZSBsZXR0ZXJzIGAicmVkImAgaW5zaWRlIHRoZSB3b3JkLiBUbyBmaXggdGhpcywgdXNlIHdvcmQgYm91bmRhcmllcyBzbyB0aGF0IGAicmVkImAgaXMgbWF0Y2hlZCBvbmx5IGFzIGEgY29tcGxldGUgd29yZC4KCiMjIyBFeGVyY2lzZSAxNS4zLjEuMQoKYGBge3J9Cmdzc19jYXQgJT4lCiAgY291bnQocmluY29tZSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gZmN0X3Jlb3JkZXIocmluY29tZSwgbiksIHkgPSBuKSkgKwogIGdlb21fY29sKCkgKwogIGNvb3JkX2ZsaXAoKSArCiAgbGFicygKICAgIHggPSAiUmVwb3J0ZWQgaW5jb21lIiwKICAgIHkgPSAiQ291bnQiLAogICAgdGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIFJlcG9ydGVkIEluY29tZSIKICApCmBgYAoKVGhlIGRlZmF1bHQgYmFyIGNoYXJ0IG9mIHJpbmNvbWUgaXMgZGlmZmljdWx0IHRvIGludGVycHJldCBiZWNhdXNlIGl0IGNvbnRhaW5zIG1hbnkgY2F0ZWdvcmllcyB3aXRoIGxvbmcgbGFiZWxzLCBpbmNsdWRpbmcgbm9ucmVzcG9uc2UgY2F0ZWdvcmllcyBzdWNoIGFzIOKAnE5vIGFuc3dlcizigJ0g4oCcRG9u4oCZdCBrbm93LOKAnSBhbmQg4oCcUmVmdXNlZC7igJ0gVGhlc2UgbWFrZSB0aGUgeC1heGlzIGNyb3dkZWQgYW5kIGhhcmQgdG8gcmVhZCwgYW5kIGl0IGJlY29tZXMgZGlmZmljdWx0IHRvIGNvbXBhcmUgZnJlcXVlbmNpZXMgYWNyb3NzIGluY29tZSBncm91cHMuCgpUaGUgcGxvdCBjYW4gYmUgaW1wcm92ZWQgYnkgcmVvcmRlcmluZyB0aGUgY2F0ZWdvcmllcyBieSBmcmVxdWVuY3kgYW5kIGZsaXBwaW5nIHRoZSBjb29yZGluYXRlcyBzbyB0aGUgbGFiZWxzIGFyZSBlYXNpZXIgdG8gcmVhZC4gSW4gdGhlIGltcHJvdmVkIHZlcnNpb24sIHRoZSBpbmNvbWUgY2F0ZWdvcmllcyBhcmUgZGlzcGxheWVkIHZlcnRpY2FsbHksIHdoaWNoIG1ha2VzIHRoZSBsYWJlbHMgbW9yZSBsZWdpYmxlIGFuZCBhbGxvd3MgZm9yIGVhc2llciBjb21wYXJpc29uIG9mIGNvdW50cy4KCiMjIyBFeGVyY2lzZXMgMTUuNC4xCgojIyMjIFF1ZXN0aW9uIDEKClRoZSBoaXN0b2dyYW0gc2hvd3Mgb3V0bGllcnMsIGFuZCB0aGUgbWVhbiBpcyBoaWdoZXIgdGhhbiB0aGUgbWVkaWFuLCBpbmRpY2F0aW5nIHNrZXcuICBUaGVyZWZvcmUsIHRoZSBtZWFuIGlzIG5vdCBhIGdvb2Qgc3VtbWFyeS4KCmBgYHtyfQojIFZpZXcgZGlzdHJpYnV0aW9uCmdzc19jYXQgJT4lCiAgZ2dwbG90KGFlcyh4ID0gdHZob3VycykpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEpCgojIFN1bW1hcnkgc3RhdHMKZ3NzX2NhdCAlPiUKICBzdW1tYXJpemUoCiAgICBtZWFuID0gbWVhbih0dmhvdXJzLCBuYS5ybSA9IFRSVUUpLAogICAgbWVkaWFuID0gbWVkaWFuKHR2aG91cnMsIG5hLnJtID0gVFJVRSksCiAgICBtYXggPSBtYXgodHZob3VycywgbmEucm0gPSBUUlVFKQogICkKYGBgCgojIyMjIFF1ZXN0aW9uIDIKCmBgYHtyfQpsZXZlbHMoZ3NzX2NhdCRyZWxpZykKbGV2ZWxzKGdzc19jYXQkZGVub20pCmxldmVscyhnc3NfY2F0JHJhY2UpCmxldmVscyhnc3NfY2F0JHBhcnR5aWQpCmxldmVscyhnc3NfY2F0JHJpbmNvbWUpCmBgYAoKLSByZWxpZzogQXJiaXRyYXJ5OyBSZWxpZ2lvdXMgY2F0ZWdvcmllcyBkbyBub3QgaGF2ZSBhIG5hdHVyYWwgcmFua2luZyBvcmRlcgotIGRlbm9tOiBBcmJpdHJhcnk7IERlbm9taW5hdGlvbnMgYXJlIG5vbWluYWwgZ3JvdXBpbmdzIGFuZCBkbyBub3QgZm9sbG93IGEgbWVhbmluZ2Z1bCBvcmRlcgotIHJhY2U6IEFyYml0cmFyeTsgUmFjZSBjYXRlZ29yaWVzIGFyZSBjYXRlZ29yaWNhbCBsYWJlbHMgd2l0aG91dCBhbnkgaW5oZXJlbnQgb3JkZXJpbmcuCi0gcGFydHlpZDogUHJpbmNpcGxlZDsgVGhlIGNhdGVnb3JpZXMgZm9sbG93IGEgbWVhbmluZ2Z1bCBwb2xpdGljYWwgc3BlY3RydW0gZnJvbSBzdHJvbmcgRGVtb2NyYXQgdG8gc3Ryb25nIFJlcHVibGljYW4uCi0gcmluY29tZTogUHJpbmNpcGxlZDsgSW5jb21lIGNhdGVnb3JpZXMgaGF2ZSBhIG5hdHVyYWwgaW5jcmVhc2luZyBvcmRlciBiYXNlZCBvbiBpbmNvbWUgbGV2ZWwuIAoKIyMjIyBRdWVzdGlvbiAzCgpXaGVuIOKAnE5vdCBhcHBsaWNhYmxl4oCdIHdhcyBtb3ZlZCB0byB0aGUgZnJvbnQgb2YgdGhlIGZhY3RvciBsZXZlbHMsIGl0IGFwcGVhcmVkIGF0IHRoZSBib3R0b20gb2YgdGhlIHBsb3QgYmVjYXVzZSBnZ3Bsb3QyIGRpc3BsYXlzIGZhY3RvciBsZXZlbHMgaW4gb3JkZXIsIGFuZCBjb29yZF9mbGlwKCkgcmV2ZXJzZXMgdGhlIGF4ZXMuCgpBcyBhIHJlc3VsdDoKCi1UaGUgZmlyc3QgbGV2ZWwgb2YgdGhlIGZhY3RvciBpcyBwbG90dGVkIGF0IHRoZSBib3R0b20KLVRoZSBsYXN0IGxldmVsIGlzIHBsb3R0ZWQgYXQgdGhlIHRvcAoKVGhlcmVmb3JlLCBtb3Zpbmcg4oCcTm90IGFwcGxpY2FibGXigJ0gdG8gdGhlIGZyb250IG9mIHRoZSBsZXZlbHMgY2F1c2VkIGl0IHRvIGFwcGVhciBhdCB0aGUgYm90dG9tIG9mIHRoZSBmbGlwcGVkIGJhciBjaGFydC4KCiMjIyBFeGVyY2lzZXMgMTUuNS4xCgojIyMjIFF1ZXN0aW9uIDEKClRoZSBwcm9wb3J0aW9uIG9mIGluZGl2aWR1YWxzIGlkZW50aWZ5aW5nIGFzIEluZGVwZW5kZW50IGhhcyBpbmNyZWFzZWQgb3ZlciB0aW1lLCB3aGlsZSBEZW1vY3JhdCBhbmQgUmVwdWJsaWNhbiBwcm9wb3J0aW9ucyByZW1haW4gcmVsYXRpdmVseSBzdGFibGUgd2l0aCBzb21lIGZsdWN0dWF0aW9ucy4KCmBgYHtyfQpnc3NfY2F0ICU+JQogIGZpbHRlcighaXMubmEoeWVhcikpICU+JQogIG11dGF0ZShwYXJ0eV9zaW1wbGUgPSBmY3RfY29sbGFwc2UoCiAgICBwYXJ0eWlkLAogICAgIkRlbW9jcmF0IiA9IGMoIlN0cm9uZyBkZW1vY3JhdCIsICJOb3Qgc3RyIGRlbW9jcmF0IiksCiAgICAiSW5kZXBlbmRlbnQiID0gYygiSW5kLG5lYXIgZGVtIiwgIkluZGVwZW5kZW50IiwgIkluZCxuZWFyIHJlcCIpLAogICAgIlJlcHVibGljYW4iID0gYygiTm90IHN0ciByZXB1YmxpY2FuIiwgIlN0cm9uZyByZXB1YmxpY2FuIikKICApKSAlPiUKICBjb3VudCh5ZWFyLCBwYXJ0eV9zaW1wbGUpICU+JQogIGdyb3VwX2J5KHllYXIpICU+JQogIG11dGF0ZShwcm9wID0gbiAvIHN1bShuKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IHByb3AsIGNvbG9yID0gcGFydHlfc2ltcGxlKSkgKwogIGdlb21fbGluZSgpICsKICBsYWJzKAogICAgdGl0bGUgPSAiUGFydHkgSWRlbnRpZmljYXRpb24gT3ZlciBUaW1lIiwKICAgIHkgPSAiUHJvcG9ydGlvbiIsCiAgICB4ID0gIlllYXIiCiAgKQpgYGAKCgojIyMjIFF1ZXN0aW9uIDIKClRoZSB2YXJpYWJsZSBgcmluY29tZWAgY2FuIGJlIGNvbGxhcHNlZCBpbnRvIGJyb2FkZXIgY2F0ZWdvcmllcyBzdWNoIGFzIGxvdywgbWlkZGxlLCBhbmQgaGlnaCBpbmNvbWUgdXNpbmcgYGZjdF9jb2xsYXBzZSgpYC4gTm9ucmVzcG9uc2UgY2F0ZWdvcmllcyBjYW4gYWxzbyBiZSBncm91cGVkIHNlcGFyYXRlbHkgdG8gc2ltcGxpZnkgdGhlIGFuYWx5c2lzLgoKYGBge3J9Cmdzc19jYXQgJT4lCiAgbXV0YXRlKHJpbmNvbWVfZ3JvdXAgPSBmY3RfY29sbGFwc2UoCiAgICByaW5jb21lLAogICAgIkxvdyIgPSBjKCJMdCAkMTAwMCIsICIkMTAwMCB0byAyOTk5IiwgIiQzMDAwIHRvIDM5OTkiKSwKICAgICJNaWRkbGUiID0gYygiJDQwMDAgdG8gNDk5OSIsICIkNTAwMCB0byA1OTk5IiwgIiQ2MDAwIHRvIDY5OTkiLAogICAgICAgICAgICAgICAgICIkNzAwMCB0byA3OTk5IiwgIiQ4MDAwIHRvIDk5OTkiLCAiJDEwMDAwIC0gMTQ5OTkiKSwKICAgICJIaWdoIiA9IGMoIiQxNTAwMCAtIDE5OTk5IiwgIiQyMDAwMCAtIDI0OTk5IiwgIiQyNTAwMCBvciBtb3JlIiksCiAgICAiTm8gcmVzcG9uc2UiID0gYygiTm8gYW5zd2VyIiwgIkRvbid0IGtub3ciLCAiUmVmdXNlZCIsICJOb3QgYXBwbGljYWJsZSIpCiAgKSkgJT4lCiAgY291bnQocmluY29tZV9ncm91cCkKYGBgCgojIyMgRXhlcmNpc2UgMTYuMi40LjMKCmBgYHtyfQpkMSA8LSAiSmFudWFyeSAxLCAyMDEwIgptZHkoZDEpCgpkMiA8LSAiMjAxNS1NYXItMDciCnltZChkMikKCmQzIDwtICIwNi1KdW4tMjAxNyIKZG15KGQzKQoKZDQgPC0gYygiQXVndXN0IDE5ICgyMDE1KSIsICJKdWx5IDEgKDIwMTUpIikKbWR5KGQ0KQoKZDUgPC0gIjEyLzMwLzE0IgptZHkoZDUpCmBgYAoKLWQxIHVzZXMgbWR5KCkgYmVjYXVzZSBpdCBpcyBpbiBtb250aC1kYXkteWVhciBmb3JtYXQgd2l0aCBhIGZ1bGwgbW9udGggbmFtZQotZDIgdXNlcyB5bWQoKSBiZWNhdXNlIGl0IGlzIGluIHllYXItbW9udGgtZGF5IGZvcm1hdAotZDMgdXNlcyBkbXkoKSBiZWNhdXNlIGl0IGlzIGluIGRheS1tb250aC15ZWFyIGZvcm1hdAotZDQgdXNlcyBtZHkoKSBiZWNhdXNlIGx1YnJpZGF0ZSBjYW4gaGFuZGxlIHRoZSBwYXJlbnRoZXNlcyBhbmQgc3RpbGwgcmVjb2duaXplcyBtb250aC1kYXkteWVhcgotZDUgdXNlcyBtZHkoKSBiZWNhdXNlIGl0IGlzIGluIG51bWVyaWMgbW9udGgvZGF5L3llYXIgZm9ybWF0CgojIyMgRXhlcmNpc2UgMTYuMy40LjEKClRoZSBkaXN0cmlidXRpb24gb2YgZGVwYXJ0dXJlIGRlbGF5cyB2YXJpZXMgYWNyb3NzIGJvdGggdGhlIGRheSBhbmQgdGhlIHllYXIuIEluIGFsbCBtb250aHMsIGZsaWdodHMgaW4gdGhlIGVhcmx5IG1vcm5pbmcgaGF2ZSByZWxhdGl2ZWx5IHNtYWxsIGFuZCBjb25zaXN0ZW50IGRlbGF5cywgd2l0aCBtb3N0IHZhbHVlcyBjbHVzdGVyZWQgbmVhciB6ZXJvLiBBcyB0aGUgZGF5IHByb2dyZXNzZXMsIGRlbGF5cyBiZWNvbWUgbW9yZSB2YXJpYWJsZSBhbmQgZXh0cmVtZSwgd2l0aCB0aGUgbGFyZ2VzdCBkZWxheXMgb2NjdXJyaW5nIGluIHRoZSBhZnRlcm5vb24gYW5kIGV2ZW5pbmcsIGluZGljYXRpbmcgdGhhdCBkZWxheXMgYWNjdW11bGF0ZSB0aHJvdWdob3V0IHRoZSBkYXkuIEFkZGl0aW9uYWxseSwgc3VtbWVyIG1vbnRocyBzaG93IGdyZWF0ZXIgdmFyaWFiaWxpdHkgYW5kIG1vcmUgZXh0cmVtZSBkZWxheXMgY29tcGFyZWQgdG8gb3RoZXIgdGltZXMgb2YgdGhlIHllYXIsIGxpa2VseSBkdWUgdG8gaW5jcmVhc2VkIHRyYWZmaWMgYW5kIHdlYXRoZXItcmVsYXRlZCBkaXNydXB0aW9ucy4KCmBgYHtyfQpmbGlnaHRzICU+JQogIGZpbHRlcighaXMubmEoZGVwX2RlbGF5KSkgJT4lCiAgbXV0YXRlKAogICAgbW9udGggPSBtb250aCh0aW1lX2hvdXIsIGxhYmVsID0gVFJVRSkKICApICU+JQogIGdncGxvdChhZXMoeCA9IGhvdXIsIHkgPSBkZXBfZGVsYXkpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMykgKwogIGZhY2V0X3dyYXAofm1vbnRoKSArCiAgbGFicygKICAgIHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBEZXBhcnR1cmUgRGVsYXlzIGJ5IEhvdXIgYW5kIE1vbnRoIiwKICAgIHggPSAiSG91ciBvZiBEYXkiLAogICAgeSA9ICJEZXBhcnR1cmUgRGVsYXkiCiAgKSArCmNvb3JkX2NhcnRlc2lhbih5bGltID0gYygtNTAsIDIwMCkpCmBgYAoKIyMjIEV4ZXJjaXNlIDE2LjMuNC40CgpUaGUgYXZlcmFnZSBkZXBhcnR1cmUgZGVsYXkgaW5jcmVhc2VzIHRocm91Z2hvdXQgbW9zdCBvZiB0aGUgZGF5LiBGbGlnaHRzIHNjaGVkdWxlZCBpbiB0aGUgZWFybHkgbW9ybmluZyBoYXZlIHRoZSBsb3dlc3QgYXZlcmFnZSBkZWxheXMsIGFuZCBkZWxheXMgaW5jcmVhc2UgdGhyb3VnaG91dCB0aGUgZGF5LCBwZWFraW5nIGluIHRoZSBldmVuaW5nIGF0IGFwcHJveGltYXRlbHkgMjUgbWludXRlcyBiZWZvcmUgZGVjbGluaW5nIGxhdGVyIGF0IG5pZ2h0LiBUaGlzIHBhdHRlcm4gc3VnZ2VzdHMgdGhhdCBkZWxheXMgYWNjdW11bGF0ZSBvdmVyIHRoZSBjb3Vyc2Ugb2YgdGhlIGRheSwgbGlrZWx5IGJlY2F1c2UgZWFybGllciBkZWxheXMgYWZmZWN0IGxhdGVyIGRlcGFydHVyZXMuCgpgYGB7cn0KZmxpZ2h0cyAlPiUKICBmaWx0ZXIoIWlzLm5hKGRlcF9kZWxheSksICFpcy5uYShzY2hlZF9kZXBfdGltZSkpICU+JQogIG11dGF0ZSgKICAgIHNjaGVkX2hvdXIgPSBzY2hlZF9kZXBfdGltZSAlLyUgMTAwCiAgKSAlPiUKICBncm91cF9ieShzY2hlZF9ob3VyKSAlPiUKICBzdW1tYXJpemUoYXZnX2RlbGF5ID0gbWVhbihkZXBfZGVsYXksIG5hLnJtID0gVFJVRSkpICU+JQogIGdncGxvdChhZXMoeCA9IHNjaGVkX2hvdXIsIHkgPSBhdmdfZGVsYXkpKSArCiAgZ2VvbV9saW5lKCkgKwogIGdlb21fcG9pbnQoKSArCiAgbGFicygKICAgIHRpdGxlID0gIkF2ZXJhZ2UgRGVwYXJ0dXJlIERlbGF5IGJ5IFNjaGVkdWxlZCBIb3VyIG9mIERheSIsCiAgICB4ID0gIlNjaGVkdWxlZCBEZXBhcnR1cmUgSG91ciIsCiAgICB5ID0gIkF2ZXJhZ2UgRGVwYXJ0dXJlIERlbGF5IChtaW51dGVzKSIKICApCmBgYAoKLi4uCgo=