Seminar Learning Goals
Analyse covid-19 data trends
To run and extend some simple R code to compute book income
Exercise answers
##0. Worksheet Introduction
Pre-requisites
You should:
- have completed the Week 1 Joining Seminar
- have (re-)acquainted yourself with Week 1 Seminar worksheet
- be familiar (listened to/read) the Week 2 Lecture “The Richness of Data”
- be able to write, edit, save and re-open your own RMarkdown files
If this is proving a challenge see “Prerequisites for Week 2 Seminars and Labs (CS5701/02)” for advice.
This seminar worksheet is organised as an RMarkdown file. You can read it. You can run the embedded R and you can add your own R. I suggest you save it as another file so, if necessary, you can revert to the original.
Whenever you click Preview in the RStudio menu it will render into nicely formatted html which you can look at it in the Viewing Window in RStudio or any web browser. You may find this easier to read, however, you must edit the .rmd file, i.e., the RMarkdown in the Edit Pane if you want to make any changes.
Remember, you are encouraged to explore and experiment. Change something and see what happens!
As per last week we will cover a lot of new ground but don’t be discouraged. We will revisit these concepts over the following weeks to help you consolidate your understanding.
1. Visualising covid-19 data trends
This example shows how we can fetch and visualise covid-19 data from John Hopkins University via GitHub.
Initialisation
We need some packages over and above base R. Since we may not be sure whether they are already installed we test for their presence. Most packages come from CRAN and are easy to install using install.packages()
but the package {tidycovid19}
is on GitHub (joachim-gassen) so we also need {devtools}
in order to install packages that aren’t on CRAN.
This R code may appear daunting but don’t worry. We will revisit it in detail in Week 3. For the time being see it as a way to install and load necessary extra functionality beyond base ER.
# If a package is installed, it will be loaded and missing package(s) will be installed
# from CRAN and then loaded.
# The packages we need are:
packages = c("tidyverse", "devtools")
# Load the package or install and load it
package.check <- lapply(
packages,
FUN = function(x) {
if (!require(x, character.only = TRUE)) {
install.packages(x, dependencies = TRUE)
library(x, character.only = TRUE)
}
}
)
install_github("joachim-gassen/tidycovid19")
Skipping install of 'tidycovid19' from a github remote, the SHA1 (78254dca) has not changed since last install.
Use `force = TRUE` to force installation
library(tidycovid19)
Download the data (cached on GitHub rather than directly from John Hopkins University). This is live data updated within the last 24 hours.
#Download the data into a data frame called cv.df using the
#download_jhu_csse_covid19_data() function from the {tidycovid19} package.
#
cv.df <- download_jhu_csse_covid19_data(cached = TRUE)
Start downloading JHU CSSE Covid-19 data
Downloading cached version of JHU CSSE Covid 19 data...done. Timestamp is 2020-10-06 03:00:10
Data Info:
The COVID-19 Data Repository by the Johns Hopkins University Center for Systems
Science and Engineering (JHU CSSE) relies upon publicly available data from
multiple sources that do not always agree. It is updated daily. The data comes
in three data frames that you can select by the 'type' parameter. The 'country'
data frame contains the global country-level data reported by JHU CSSE by
aggregating over the regional data for countries that have regional data
available. The 'country_region' data frame provides regional data for the
countries that have regional data available (mosty Australia, Canada and China).
The 'us_county' data frame reports the data for the U.S. at the county level.
The column 'timestamp' reports the time the data was downloaded from its
authoritative source.
For further information refer to: https://github.com/CSSEGISandData/COVID-19.
Exercise 2.1: The dataframe which comprises all international covid-19 data recorded by John Hopkins since January 22, 2020 has 47545*7 observations (see the Environment Pane). Is this large? How much larger can R handle?
Explore the data
Let’s focus on the UK and then “eyeball” the data again.
# select only the UK data
cv.uk.df <- subset(cv.df, iso3c=="GBR")
head(cv.uk.df)
tail(cv.uk.df)
Show trends
Mortality rate
# Compute new deaths as the data shows cumulative deaths
cv.uk.df$new.d[2:nrow(cv.uk.df)] <- tail(cv.uk.df$deaths, -1) - head(cv.uk.df$deaths, -1)
Unknown or uninitialised column: `new.d`.
cv.uk.df$new.d[1] <- 0 # Add zero for first row
# Compute new infections
cv.uk.df$new.i[2:nrow(cv.uk.df)] <- tail(cv.uk.df$confirmed, -1) - head(cv.uk.df$confirmed, -1)
Unknown or uninitialised column: `new.i`.
cv.uk.df$new.i[1] <- 0 # Add zero for first row
We can produce a plot of daily additional deaths using the {ggplot} package which is an extremely powerful and flexible set of functions for producing extremely high quality graphics e.g. NYT, Guardian and the BBC. We also save the plots using the ggsave()
function which is also part of the {ggplot} package.
# NB a small span value (<1) makes the loess smoother more wiggly!
ggplot(data = cv.uk.df, aes(x = date, y = new.d)) +
geom_line(color = "skyblue", size = 0.6) +
ylim(0,1200) +
stat_smooth(color = "darkorange", fill = "darkorange", method = "loess", span = 0.2) +
ggtitle("Daily additional deaths in the UK due to covid-19") +
xlab("Date") + ylab("Daily new deaths")
ggsave("cv19_UK_deathrate.png")
Saving 7.02 x 4.34 in image
Infection rate
Note that we use a log scale for the y-axis ie daily new infection rate.
Exercise 2.2: Why did I choose to use a log scale for daily new infection rate?
ggplot(data = cv.uk.df, aes(x = date, y = new.i)) +
geom_line(color = "skyblue", size = 0.6) +
scale_y_continuous(trans = "log10") +
stat_smooth(color = "darkorange", fill = "darkorange", method = "loess") +
ggtitle("Daily new infections in the UK from covid-19") +
xlab("Date") + ylab("Daily new infections")
ggsave("cv19_UK_infectionrate.png")
Saving 7.02 x 4.34 in image
To better visualise the trends (i.e., over time) we use the loess (locally estimated scatterplot smoothing) smoother. It is designed to detect trends in the presence of noisy data when the shape of the trend is unknown thus it is a robust (non-parametric) method.
Exercise 2.3: If you look carefully at the data there is a clear cycle within the overall trend. What is it and why? How should we deal with it?
Exercise 2.4: What does the light orange shaded region around the smoothed trend line mean? Why does it vary in breadth?
Exercise 2.5: What was the greatest number of new infections in one day in the UK? HINT there is a built in function max()
and the you will need to examine the vector new.i
which is part of the cv.uk.df
dataframe so you will need the $
operator.
Extension Exercise 2.6: Edit the R code to produce a similar trend analysis for another country of your choice. Note that the data set uses 3 character country codes e.g., SWE, USA see wikipedia for a complete list. HINT: you will need to change the subset command and perhaps save to a new dataframe and then make sure you turn the cummulative counts into new counts.
Exercise 2.7: Is new.i
in the cv.uk.df dataframe an integer?
Exercise 2.8: How many people recovered in the UK on the 236th day of data collection. Write an R statement to answer.
Exercise 2.9: Update the number of new deaths on the 236th day to zero.
2. Exercise answers
2.1: Although ~47.5K observations might seem large in reality this only occopies 2.6Mb which is <0.1% of the capacity of R on a fairly standard laptop or PC.
2.2: Given the wide range of values for daily infections a log10 scale makes the plot easier to view, particularly for the smaller values.
2.3: There is a clear weekly cycle (or we can say the periodicity is 7-days). This is true of many countries. Why do you think this might be?
2.4: This shows the 95% confidence limit since there is an element of uncertainty as to exactly where the trend line should be. The broader the confidence limit band (shaded pale orange) the less confident we are about the exact location of the trend. Where the confidence limit potentially goes negative (which would be meaningless) we do not plot it. This principally occurs for the daily new death rate trend since many values are (mercifully) close to zero.
2.5: max(cv.uk.df$new.i)
2.6: Good luck!
2.7: new.i
is not an integer? One way to find out is to use the built in function is.integer()
.
is.integer(cv.uk.df$new.i)
[1] FALSE
If you wanted new.i
to be an integer you could need to code something like
cv.uk.df$new.i <- as.integer(cv.uk.df$new.i)
or make an assignment like cv.uk.df$new.i <- 10L
where L is short for Long which is a long story!
2.8: cv.uk.df$recovered[236]
Remember you need to use the $ operator to reference a particular vector (variable) in the dataframe cv.uk.df.
Exercise 2.9:
cv.uk.df$recovered[236] <- 0
LS0tCiMgVGhpcyBpcyB0aGUgWUFNTCBoZWFkZXIKdGl0bGU6ICJDUzU3MDIgVzIgU2VtaW5hciBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCmF1dGhvcjogTWFydGluIFNoZXBwZXJkCmRhdGU6IDA2LzEwLzIwMjAKIyBUaGlzIGlzIHRoZSBlbmQgb2YgdGhlIFlBTUwgaGVhZGVyIAojICh1c2UgaXQgYXMgYSB0ZW1wbGF0ZSBmb3IgeW91ciBybWFya2Rvd24gZmlsZXMpCi0tLQoKIyMgU2VtaW5hciBMZWFybmluZyBHb2FscwoKMS4gW0FuYWx5c2UgY292aWQtMTkgZGF0YSB0cmVuZHNdKCNXMlMxKSAgCjIuIFtUbyBydW4gYW5kIGV4dGVuZCBzb21lIHNpbXBsZSBSIGNvZGUgdG8gY29tcHV0ZSBib29rIGluY29tZV0oI1cyUzIpICAKCjMuIFtFeGVyY2lzZSBhbnN3ZXJzXSgjVzJBKSAKCgojIzAuIFdvcmtzaGVldCBJbnRyb2R1Y3Rpb24KCjxzcGFuIHN0eWxlPSJjb2xvcjogZGFya29yYW5nZTsiPioqUHJlLXJlcXVpc2l0ZXMqKjwvc3Bhbj4KCllvdSBzaG91bGQ6ICAKCjEuIGhhdmUgY29tcGxldGVkIHRoZSBXZWVrIDEgSm9pbmluZyBTZW1pbmFyICAKMi4gaGF2ZSAocmUtKWFjcXVhaW50ZWQgeW91cnNlbGYgd2l0aCBXZWVrIDEgU2VtaW5hciB3b3Jrc2hlZXQgIAozLiBiZSBmYW1pbGlhciAobGlzdGVuZWQgdG8vcmVhZCkgdGhlIFdlZWsgMiBMZWN0dXJlICJUaGUgUmljaG5lc3Mgb2YgRGF0YSIgIAo0LiBiZSBhYmxlIHRvIHdyaXRlLCBlZGl0LCBzYXZlIGFuZCByZS1vcGVuIHlvdXIgb3duIFJNYXJrZG93biBmaWxlcwoKSWYgdGhpcyBpcyBwcm92aW5nIGEgPHNwYW4gc3R5bGU9ImNvbG9yOiBkYXJrb3JhbmdlOyI+KipjaGFsbGVuZ2UqKjwvc3Bhbj4gc2VlIFsiUHJlcmVxdWlzaXRlcyBmb3IgV2VlayAyIFNlbWluYXJzIGFuZCBMYWJzIChDUzU3MDEvMDIpIl0oaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL21qc2hlcHBlcmQvQ1M1NzAyLURhdGEvbWFzdGVyL0NTNTcwMl9XMl9TZW1fUHJlUmVxcy5wZGYpIGZvciBhZHZpY2UuCgpUaGlzIHNlbWluYXIgd29ya3NoZWV0IGlzIG9yZ2FuaXNlZCBhcyBhbiBSTWFya2Rvd24gZmlsZS4gIFlvdSBjYW4gKipyZWFkKiogaXQuICBZb3UgY2FuICoqcnVuKiogdGhlIGVtYmVkZGVkIFIgYW5kIHlvdSBjYW4gKiphZGQqKiB5b3VyIG93biBSLiAgSSBzdWdnZXN0IHlvdSBzYXZlIGl0IGFzIGFub3RoZXIgZmlsZSBzbywgaWYgbmVjZXNzYXJ5LCB5b3UgY2FuIHJldmVydCB0byB0aGUgb3JpZ2luYWwuICAKCldoZW5ldmVyIHlvdSBjbGljayAqKlByZXZpZXcqKiBpbiB0aGUgUlN0dWRpbyBtZW51IGl0IHdpbGwgcmVuZGVyIGludG8gbmljZWx5IGZvcm1hdHRlZCBodG1sIHdoaWNoIHlvdSBjYW4gbG9vayBhdCBpdCBpbiB0aGUgVmlld2luZyBXaW5kb3cgaW4gUlN0dWRpbyBvciBhbnkgd2ViIGJyb3dzZXIuICBZb3UgbWF5IGZpbmQgdGhpcyBlYXNpZXIgdG8gcmVhZCwgaG93ZXZlciwgeW91IG11c3QgZWRpdCB0aGUgLnJtZCBmaWxlLCBpLmUuLCB0aGUgUk1hcmtkb3duIGluIHRoZSBFZGl0IFBhbmUgaWYgeW91IHdhbnQgdG8gbWFrZSBhbnkgY2hhbmdlcy4gCgpSZW1lbWJlciwgeW91IGFyZSBlbmNvdXJhZ2VkIHRvIGV4cGxvcmUgYW5kIGV4cGVyaW1lbnQuICBDaGFuZ2Ugc29tZXRoaW5nIGFuZCBzZWUgd2hhdCBoYXBwZW5zIQoKQXMgcGVyIGxhc3Qgd2VlayB3ZSB3aWxsIGNvdmVyIGEgbG90IG9mIG5ldyBncm91bmQgYnV0IGRvbid0IGJlIGRpc2NvdXJhZ2VkLiAgV2Ugd2lsbCByZXZpc2l0IHRoZXNlIGNvbmNlcHRzIG92ZXIgdGhlIGZvbGxvd2luZyB3ZWVrcyB0byBoZWxwIHlvdSBjb25zb2xpZGF0ZSB5b3VyIHVuZGVyc3RhbmRpbmcuIAoKCiMjIDEuIFZpc3VhbGlzaW5nIGNvdmlkLTE5IGRhdGEgdHJlbmRzIHsjVzJTMX0KClRoaXMgZXhhbXBsZSBzaG93cyBob3cgd2UgY2FuIGZldGNoIGFuZCB2aXN1YWxpc2UgY292aWQtMTkgZGF0YSBmcm9tIEpvaG4gSG9wa2lucyBVbml2ZXJzaXR5IHZpYSBHaXRIdWIuCgojIyMgSW5pdGlhbGlzYXRpb24KCldlIG5lZWQgc29tZSBwYWNrYWdlcyBvdmVyIGFuZCBhYm92ZSBiYXNlIFIuICBTaW5jZSB3ZSBtYXkgbm90IGJlIHN1cmUgd2hldGhlciB0aGV5IGFyZSBhbHJlYWR5IGluc3RhbGxlZCB3ZSB0ZXN0IGZvciB0aGVpciBwcmVzZW5jZS4gIE1vc3QgcGFja2FnZXMgY29tZSBmcm9tIENSQU4gYW5kIGFyZSBlYXN5IHRvIGluc3RhbGwgdXNpbmcgYGluc3RhbGwucGFja2FnZXMoKWAgYnV0IHRoZSBwYWNrYWdlIGB7dGlkeWNvdmlkMTl9YCBpcyBvbiBHaXRIdWIgKGpvYWNoaW0tZ2Fzc2VuKSBzbyB3ZSBhbHNvIG5lZWQgYHtkZXZ0b29sc31gIGluIG9yZGVyIHRvIGluc3RhbGwgcGFja2FnZXMgdGhhdCBhcmVuJ3Qgb24gQ1JBTi4KClRoaXMgUiBjb2RlIG1heSBhcHBlYXIgZGF1bnRpbmcgYnV0IGRvbid0IHdvcnJ5LiAgV2Ugd2lsbCByZXZpc2l0IGl0IGluIGRldGFpbCBpbiBXZWVrIDMuICBGb3IgdGhlIHRpbWUgYmVpbmcgc2VlIGl0IGFzIGEgd2F5IHRvIGluc3RhbGwgYW5kIGxvYWQgbmVjZXNzYXJ5IGV4dHJhIGZ1bmN0aW9uYWxpdHkgYmV5b25kIGJhc2UgRVIuCgpgYGB7ciBtZXNzYWdlcz1GfQojIElmIGEgcGFja2FnZSBpcyBpbnN0YWxsZWQsIGl0IHdpbGwgYmUgbG9hZGVkIGFuZCBtaXNzaW5nIHBhY2thZ2Uocykgd2lsbCBiZSBpbnN0YWxsZWQgCiMgZnJvbSBDUkFOIGFuZCB0aGVuIGxvYWRlZC4KCiMgVGhlIHBhY2thZ2VzIHdlIG5lZWQgYXJlOgogCnBhY2thZ2VzID0gYygidGlkeXZlcnNlIiwgImRldnRvb2xzIikKCiMgTG9hZCB0aGUgcGFja2FnZSBvciBpbnN0YWxsIGFuZCBsb2FkIGl0CnBhY2thZ2UuY2hlY2sgPC0gbGFwcGx5KAogIHBhY2thZ2VzLAogIEZVTiA9IGZ1bmN0aW9uKHgpIHsKICAgIGlmICghcmVxdWlyZSh4LCBjaGFyYWN0ZXIub25seSA9IFRSVUUpKSB7CiAgICAgIGluc3RhbGwucGFja2FnZXMoeCwgZGVwZW5kZW5jaWVzID0gVFJVRSkKICAgICAgbGlicmFyeSh4LCBjaGFyYWN0ZXIub25seSA9IFRSVUUpCiAgICB9CiAgfQopCgppbnN0YWxsX2dpdGh1Yigiam9hY2hpbS1nYXNzZW4vdGlkeWNvdmlkMTkiKQpsaWJyYXJ5KHRpZHljb3ZpZDE5KQpgYGAKCkRvd25sb2FkIHRoZSBkYXRhIChjYWNoZWQgb24gR2l0SHViIHJhdGhlciB0aGFuIGRpcmVjdGx5IGZyb20gSm9obiBIb3BraW5zIFVuaXZlcnNpdHkpLiAgVGhpcyBpcyBsaXZlIGRhdGEgdXBkYXRlZCB3aXRoaW4gdGhlIGxhc3QgMjQgaG91cnMuICAKCmBgYHtyfQojRG93bmxvYWQgdGhlIGRhdGEgaW50byBhIGRhdGEgZnJhbWUgY2FsbGVkIGN2LmRmIHVzaW5nIHRoZSAKI2Rvd25sb2FkX2podV9jc3NlX2NvdmlkMTlfZGF0YSgpIGZ1bmN0aW9uIGZyb20gdGhlIHt0aWR5Y292aWQxOX0gcGFja2FnZS4KIwpjdi5kZiA8LSBkb3dubG9hZF9qaHVfY3NzZV9jb3ZpZDE5X2RhdGEoY2FjaGVkID0gVFJVRSkKYGBgCgoqKkV4ZXJjaXNlIDIuMToqKiBUaGUgZGF0YWZyYW1lIHdoaWNoIGNvbXByaXNlcyBhbGwgaW50ZXJuYXRpb25hbCBjb3ZpZC0xOSBkYXRhIHJlY29yZGVkIGJ5IEpvaG4gSG9wa2lucyBzaW5jZSBKYW51YXJ5IDIyLCAyMDIwIGhhcyA0NzU0NSo3IG9ic2VydmF0aW9ucyAoc2VlIHRoZSBFbnZpcm9ubWVudCBQYW5lKS4gIElzIHRoaXMgbGFyZ2U/ICBIb3cgbXVjaCBsYXJnZXIgY2FuIFIgaGFuZGxlPwoKIyMjIEV4cGxvcmUgdGhlIGRhdGEKCkxldCdzIGZvY3VzIG9uIHRoZSBVSyAgYW5kIHRoZW4gImV5ZWJhbGwiIHRoZSBkYXRhIGFnYWluLgoKYGBge3J9CiMgc2VsZWN0IG9ubHkgdGhlIFVLIGRhdGEKY3YudWsuZGYgPC0gc3Vic2V0KGN2LmRmLCBpc28zYz09IkdCUiIpCgpoZWFkKGN2LnVrLmRmKQp0YWlsKGN2LnVrLmRmKQpgYGAKCiMjIFNob3cgdHJlbmRzCgojIyMgTW9ydGFsaXR5IHJhdGUKCmBgYHtyfQojIENvbXB1dGUgbmV3IGRlYXRocyBhcyB0aGUgZGF0YSBzaG93cyBjdW11bGF0aXZlIGRlYXRocwpjdi51ay5kZiRuZXcuZFsyOm5yb3coY3YudWsuZGYpXSA8LSB0YWlsKGN2LnVrLmRmJGRlYXRocywgLTEpIC0gaGVhZChjdi51ay5kZiRkZWF0aHMsIC0xKQpjdi51ay5kZiRuZXcuZFsxXSA8LSAwICAgICAjIEFkZCB6ZXJvIGZvciBmaXJzdCByb3cgCgojIENvbXB1dGUgbmV3IGluZmVjdGlvbnMKY3YudWsuZGYkbmV3LmlbMjpucm93KGN2LnVrLmRmKV0gPC0gdGFpbChjdi51ay5kZiRjb25maXJtZWQsIC0xKSAtIGhlYWQoY3YudWsuZGYkY29uZmlybWVkLCAtMSkKY3YudWsuZGYkbmV3LmlbMV0gPC0gMCAgICAgIyBBZGQgemVybyBmb3IgZmlyc3Qgcm93IApgYGAKCldlIGNhbiBwcm9kdWNlIGEgcGxvdCBvZiBkYWlseSBhZGRpdGlvbmFsIGRlYXRocyB1c2luZyB0aGUge2dncGxvdH0gcGFja2FnZSB3aGljaCBpcyBhbiBleHRyZW1lbHkgcG93ZXJmdWwgYW5kIGZsZXhpYmxlIHNldCBvZiBmdW5jdGlvbnMgZm9yIHByb2R1Y2luZyBleHRyZW1lbHkgaGlnaCBxdWFsaXR5IGdyYXBoaWNzIGUuZy4gTllULCBHdWFyZGlhbiBhbmQgdGhlIEJCQy4gIFdlIGFsc28gc2F2ZSB0aGUgcGxvdHMgdXNpbmcgdGhlIGBnZ3NhdmUoKWAgZnVuY3Rpb24gd2hpY2ggaXMgYWxzbyBwYXJ0IG9mIHRoZSB7Z2dwbG90fSBwYWNrYWdlLgoKYGBge3J9CiMgTkIgYSBzbWFsbCBzcGFuIHZhbHVlICg8MSkgbWFrZXMgdGhlIGxvZXNzIHNtb290aGVyIG1vcmUgd2lnZ2x5IQpnZ3Bsb3QoZGF0YSA9IGN2LnVrLmRmLCBhZXMoeCA9IGRhdGUsIHkgPSBuZXcuZCkpICsKICBnZW9tX2xpbmUoY29sb3IgPSAic2t5Ymx1ZSIsIHNpemUgPSAwLjYpICsKICB5bGltKDAsMTIwMCkgKwogIHN0YXRfc21vb3RoKGNvbG9yID0gImRhcmtvcmFuZ2UiLCBmaWxsID0gImRhcmtvcmFuZ2UiLCBtZXRob2QgPSAibG9lc3MiLCBzcGFuID0gMC4yKSArCiAgZ2d0aXRsZSgiRGFpbHkgYWRkaXRpb25hbCBkZWF0aHMgaW4gdGhlIFVLIGR1ZSB0byBjb3ZpZC0xOSIpICsKICB4bGFiKCJEYXRlIikgKyB5bGFiKCJEYWlseSBuZXcgZGVhdGhzIikKZ2dzYXZlKCJjdjE5X1VLX2RlYXRocmF0ZS5wbmciKQpgYGAKCiMjIyBJbmZlY3Rpb24gcmF0ZQoKTm90ZSB0aGF0IHdlIHVzZSBhIGxvZyBzY2FsZSBmb3IgdGhlIHktYXhpcyBpZSBkYWlseSBuZXcgaW5mZWN0aW9uIHJhdGUuCgoqKkV4ZXJjaXNlIDIuMjoqKiBXaHkgZGlkIEkgY2hvb3NlIHRvIHVzZSBhIGxvZyBzY2FsZSBmb3IgZGFpbHkgbmV3IGluZmVjdGlvbiByYXRlPwoKYGBge3J9CmdncGxvdChkYXRhID0gY3YudWsuZGYsIGFlcyh4ID0gZGF0ZSwgeSA9IG5ldy5pKSkgKwogIGdlb21fbGluZShjb2xvciA9ICJza3libHVlIiwgc2l6ZSA9IDAuNikgKwogIHNjYWxlX3lfY29udGludW91cyh0cmFucyA9ICJsb2cxMCIpICsKICBzdGF0X3Ntb290aChjb2xvciA9ICJkYXJrb3JhbmdlIiwgZmlsbCA9ICJkYXJrb3JhbmdlIiwgbWV0aG9kID0gImxvZXNzIikgKwogIGdndGl0bGUoIkRhaWx5IG5ldyBpbmZlY3Rpb25zIGluIHRoZSBVSyBmcm9tIGNvdmlkLTE5IikgKwogIHhsYWIoIkRhdGUiKSArIHlsYWIoIkRhaWx5IG5ldyBpbmZlY3Rpb25zIikgCmdnc2F2ZSgiY3YxOV9VS19pbmZlY3Rpb25yYXRlLnBuZyIpCmBgYAoKVG8gYmV0dGVyIHZpc3VhbGlzZSB0aGUgdHJlbmRzIChpLmUuLCBvdmVyIHRpbWUpIHdlIHVzZSB0aGUgKipsb2VzcyoqIChsb2NhbGx5IGVzdGltYXRlZCBzY2F0dGVycGxvdCBzbW9vdGhpbmcpIHNtb290aGVyLiAgSXQgaXMgZGVzaWduZWQgdG8gZGV0ZWN0IHRyZW5kcyBpbiB0aGUgcHJlc2VuY2Ugb2Ygbm9pc3kgZGF0YSB3aGVuIHRoZSBzaGFwZSBvZiB0aGUgdHJlbmQgaXMgdW5rbm93biB0aHVzIGl0IGlzIGEgcm9idXN0IChub24tcGFyYW1ldHJpYykgbWV0aG9kLiAgCgoqKkV4ZXJjaXNlIDIuMzoqKiBJZiB5b3UgbG9vayBjYXJlZnVsbHkgYXQgdGhlIGRhdGEgdGhlcmUgaXMgYSBjbGVhciBjeWNsZSB3aXRoaW4gdGhlIG92ZXJhbGwgdHJlbmQuICBXaGF0IGlzIGl0IGFuZCB3aHk/ICBIb3cgc2hvdWxkIHdlIGRlYWwgd2l0aCBpdD8KCioqRXhlcmNpc2UgMi40OioqIFdoYXQgZG9lcyB0aGUgbGlnaHQgb3JhbmdlIHNoYWRlZCByZWdpb24gYXJvdW5kIHRoZSBzbW9vdGhlZCB0cmVuZCBsaW5lIG1lYW4/ICBXaHkgZG9lcyBpdCB2YXJ5IGluIGJyZWFkdGg/CgoqKkV4ZXJjaXNlIDIuNToqKiBXaGF0IHdhcyB0aGUgZ3JlYXRlc3QgbnVtYmVyIG9mIG5ldyBpbmZlY3Rpb25zIGluIG9uZSBkYXkgaW4gdGhlIFVLPyAgSElOVCB0aGVyZSBpcyBhIGJ1aWx0IGluIGZ1bmN0aW9uIGBtYXgoKWAgYW5kIHRoZSB5b3Ugd2lsbCBuZWVkIHRvIGV4YW1pbmUgdGhlIHZlY3RvciBgbmV3LmlgIHdoaWNoIGlzIHBhcnQgb2YgdGhlIGBjdi51ay5kZmAgZGF0YWZyYW1lIHNvIHlvdSB3aWxsIG5lZWQgdGhlIGAkYCBvcGVyYXRvci4gIAoKKipFeHRlbnNpb24gRXhlcmNpc2UgMi42OioqIEVkaXQgdGhlIFIgY29kZSB0byBwcm9kdWNlIGEgc2ltaWxhciB0cmVuZCBhbmFseXNpcyBmb3IgYW5vdGhlciBjb3VudHJ5IG9mIHlvdXIgY2hvaWNlLiAgTm90ZSB0aGF0IHRoZSBkYXRhIHNldCB1c2VzIDMgY2hhcmFjdGVyIGNvdW50cnkgY29kZXMgZS5nLiwgU1dFLCBVU0Egc2VlIFt3aWtpcGVkaWFdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0lTT18zMTY2LTFfYWxwaGEtMykgZm9yIGEgY29tcGxldGUgbGlzdC4gIEhJTlQ6IHlvdSB3aWxsIG5lZWQgdG8gY2hhbmdlIHRoZSBzdWJzZXQgY29tbWFuZCBhbmQgcGVyaGFwcyBzYXZlIHRvIGEgbmV3IGRhdGFmcmFtZSBhbmQgdGhlbiBtYWtlIHN1cmUgeW91IHR1cm4gdGhlIGN1bW11bGF0aXZlIGNvdW50cyBpbnRvIG5ldyBjb3VudHMuCgoqKkV4ZXJjaXNlIDIuNzoqKiBJcyBgbmV3LmlgIGluIHRoZSBjdi51ay5kZiBkYXRhZnJhbWUgYW4gaW50ZWdlcj8gIAoKKipFeGVyY2lzZSAyLjg6KiogSG93IG1hbnkgcGVvcGxlIHJlY292ZXJlZCBpbiB0aGUgVUsgb24gdGhlIDIzNnRoIGRheSBvZiBkYXRhIGNvbGxlY3Rpb24uICBXcml0ZSBhbiBSIHN0YXRlbWVudCB0byBhbnN3ZXIuICAKCioqRXhlcmNpc2UgMi45OioqIFVwZGF0ZSB0aGUgbnVtYmVyIG9mIG5ldyBkZWF0aHMgb24gdGhlIDIzNnRoIGRheSB0byB6ZXJvLiAgCgohW0Fuc3dlcnM/XShodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vbWpzaGVwcGVyZC9DUzU3MDItRGF0YS9tYXN0ZXIvQW5zd2Vycy5wbmcpCgojIyAyLiBFeGVyY2lzZSBhbnN3ZXJzeyNXMkF9CgoyLjE6IEFsdGhvdWdoIH40Ny41SyBvYnNlcnZhdGlvbnMgbWlnaHQgc2VlbSBsYXJnZSBpbiByZWFsaXR5IHRoaXMgb25seSBvY2NvcGllcyAyLjZNYiB3aGljaCBpcyA8MC4xJSBvZiB0aGUgY2FwYWNpdHkgb2YgUiBvbiBhIGZhaXJseSBzdGFuZGFyZCBsYXB0b3Agb3IgUEMuCgoyLjI6IEdpdmVuIHRoZSB3aWRlIHJhbmdlIG9mIHZhbHVlcyBmb3IgZGFpbHkgaW5mZWN0aW9ucyBhIGxvZzEwIHNjYWxlIG1ha2VzIHRoZSBwbG90IGVhc2llciB0byB2aWV3LCBwYXJ0aWN1bGFybHkgZm9yIHRoZSBzbWFsbGVyIHZhbHVlcy4gCgoyLjM6IFRoZXJlIGlzIGEgY2xlYXIgd2Vla2x5IGN5Y2xlIChvciB3ZSBjYW4gc2F5IHRoZSBwZXJpb2RpY2l0eSBpcyA3LWRheXMpLiAgVGhpcyBpcyB0cnVlIG9mIG1hbnkgY291bnRyaWVzLiAgV2h5IGRvIHlvdSB0aGluayB0aGlzIG1pZ2h0IGJlPyAgCgoyLjQ6IFRoaXMgc2hvd3MgdGhlIDk1JSBjb25maWRlbmNlIGxpbWl0IHNpbmNlIHRoZXJlIGlzIGFuIGVsZW1lbnQgb2YgdW5jZXJ0YWludHkgYXMgdG8gZXhhY3RseSB3aGVyZSB0aGUgdHJlbmQgbGluZSBzaG91bGQgYmUuICBUaGUgYnJvYWRlciB0aGUgY29uZmlkZW5jZSBsaW1pdCBiYW5kIChzaGFkZWQgcGFsZSBvcmFuZ2UpIHRoZSBsZXNzIGNvbmZpZGVudCB3ZSBhcmUgYWJvdXQgdGhlIGV4YWN0IGxvY2F0aW9uIG9mIHRoZSB0cmVuZC4gIFdoZXJlIHRoZSBjb25maWRlbmNlIGxpbWl0IHBvdGVudGlhbGx5IGdvZXMgbmVnYXRpdmUgKHdoaWNoIHdvdWxkIGJlIG1lYW5pbmdsZXNzKSB3ZSBkbyBub3QgcGxvdCBpdC4gIFRoaXMgcHJpbmNpcGFsbHkgb2NjdXJzIGZvciB0aGUgZGFpbHkgbmV3IGRlYXRoIHJhdGUgdHJlbmQgc2luY2UgbWFueSB2YWx1ZXMgYXJlIChtZXJjaWZ1bGx5KSBjbG9zZSB0byB6ZXJvLiAgCgoyLjU6IGBtYXgoY3YudWsuZGYkbmV3LmkpYCAgCgoyLjY6IEdvb2QgbHVjayEgIAoKMi43OiBgbmV3LmlgIGlzIG5vdCBhbiBpbnRlZ2VyPyAgT25lIHdheSB0byBmaW5kIG91dCBpcyB0byB1c2UgdGhlIGJ1aWx0IGluIGZ1bmN0aW9uIGBpcy5pbnRlZ2VyKClgLgpgYGB7cn0KaXMuaW50ZWdlcihjdi51ay5kZiRuZXcuaSkKYGBgCgpJZiB5b3Ugd2FudGVkIGBuZXcuaWAgdG8gYmUgYW4gaW50ZWdlciB5b3UgY291bGQgbmVlZCB0byBjb2RlIHNvbWV0aGluZyBsaWtlCmBgYHtyfQpjdi51ay5kZiRuZXcuaSA8LSBhcy5pbnRlZ2VyKGN2LnVrLmRmJG5ldy5pKQpgYGAKb3IgbWFrZSBhbiBhc3NpZ25tZW50IGxpa2UgYGN2LnVrLmRmJG5ldy5pIDwtIDEwTGAgd2hlcmUgTCBpcyBzaG9ydCBmb3IgTG9uZyB3aGljaCBpcyBhIGxvbmcgc3RvcnkhICAKCjIuODogYGN2LnVrLmRmJHJlY292ZXJlZFsyMzZdYCAgUmVtZW1iZXIgeW91IG5lZWQgdG8gdXNlIHRoZSAkIG9wZXJhdG9yIHRvIHJlZmVyZW5jZSBhIHBhcnRpY3VsYXIgdmVjdG9yICh2YXJpYWJsZSkgaW4gdGhlIGRhdGFmcmFtZSBjdi51ay5kZi4KCkV4ZXJjaXNlIDIuOTogCgpgYGB7cn0KY3YudWsuZGYkcmVjb3ZlcmVkWzIzNl0gPC0gMApgYGAKCg==