Writing Functions, Combining Files, Summarizing
Data
QUESTION 1
Introduction
For this first programming assignment you will write three functions
that are meant to interact with dataset that accompanies this
assignment. The dataset is contained in a zip file specdata.zip that you
can download from the Coursera web site.
Although this is a programming assignment, you will be assessed using
a separate quiz. Data
The zip file containing the data can be downloaded here: Coursera
The zip file contains 332 comma-separated-value (CSV) files
containing pollution monitoring data for fine particulate matter (PM)
air pollution at 332 locations in the United States. Each file contains
data from a single monitor and the ID number for each monitor is
contained in the file name. For example, data for monitor 200 is
contained in the file “200.csv”. Each file contains variables:
Date: the date of the observation in MM-DD-YYYY format (month-day-year)
sulfate: the level of sulfate PM in the air on that date (measured in micrograms per cubic meter)
nitrate: the level of nitrate PM in the air on that date (measured in micrograms per cubic meter)

For this programming assignment you will need to unzip this file and
create the directory ‘specdata’. Once you have unzipped the zip file, do
not make any modifications to the files in the ‘specdata’ directory. In
each file you’ll notice that there are many days where either sulfate or
nitrate (or both) are missing (coded as NA). This is common with air
pollution monitoring data in the United States. Part 1
Write a function named ‘pollutantmean’ that calculates the mean of a
pollutant (sulfate or nitrate) across a specified list of monitors. The
function ‘pollutantmean’ takes three arguments: ‘directory’,
‘pollutant’, and ‘id’. Given a vector monitor ID numbers,
‘pollutantmean’ reads that monitors’ particulate matter data from the
directory specified in the ‘directory’ argument and returns the mean of
the pollutant across all of the monitors, ignoring any missing values
coded as NA. A prototype of the function is as follows:

You can see some example output from this function below. The
function that you write should be able to match this output.
Helper function for pollutant_mean()
-Combine files with given id numbers in specdata folder
# 'ID' is the fourth column in each file
combine_csv <- function(directory = 'specdata', id = 1:332){
df <- list.files(path = directory, full.names = TRUE) %>%
lapply(read.csv) %>%
bind_rows()
if(is.null(id)){
df
}else{
df %>%
filter(ID %in% id)
}
}
pollutant_mean <- function(directory = 'specdata', pollutant = 'sulfate', id = 1:332){
df <- combine_csv(directory = directory, id = id) #combine files in directory
pollutantVec <- df[, pollutant]; #mean takes a vector
mean(pollutantVec, na.rm = TRUE) # Find average
}
pollutant_mean("specdata", "sulfate")
[1] 3.189369
pollutant_mean(id = 1:10)
[1] 4.064128
pollutant_mean("specdata", "nitrate", 70:72)
[1] 1.706047
pollutant_mean('specdata', 'nitrate', 23)
[1] 1.280833
QUESTION 2
Part 2
Write a function that reads a directory full of files and reports the
number of completely observed cases in each data file. The function
should return a data frame where the first column is the name of the
file and the second column is the number of complete cases. A prototype
of this function follows:

You can see some example output from this function below. The
function that you write should be able to match this output.
complete <- function(directory = 'specdata', id = NULL){
df <- combine_csv(directory, id)
df %>%
drop_na() %>%
group_by(id = ID) %>%
summarize(nobs = n())
# summarize(num_complete_cases = n())
}
complete(id = 1)
complete(id = c(2, 4, 6, 8, 10, 12))
complete(id = 30:25)
complete(id = 3)
cc <- complete("specdata", c(6, 10, 20, 34, 100, 200, 310))
print(cc$nobs)
[1] 228 148 124 165 104 460 232
cc <- complete("specdata", 54)
print(cc$nobs)
[1] 219
QUESTION 3
Write a function that takes a directory of data files and a threshold
for complete cases and calculates the correlation between sulfate and
nitrate for monitor locations where the number of completely observed
cases (on all variables) is greater than the threshold. The function
should return a vector of correlations for the monitors that meet the
threshold requirement. If no monitors meet the threshold requirement,
then the function should return a numeric vector of length 0. A
prototype of this function follows:
knitr::include_graphics("corr_prototype.jpg")

For this function you will need to use the ‘cor’ function in R which
calculates the correlation between two vectors. Please read the help
page for this function via ‘?cor’ and make sure that you know how to use
it.
You can see some example output from this function below. The
function that you write should be able to approximately match this
output. Note that because of how R rounds and presents floating point
numbers, the output you generate may differ slightly from the example
output. Please save your code to a file named corr.R. To run the submit
script for this part, make sure your working directory has the file
corr.R in it.
corr <- function(directory = 'specdata', threshold = 0){
df <- combine_csv(directory = directory, id = NULL)
df2 <- df %>%
drop_na() %>%
group_by(id = ID)%>%
summarize(n = n(), correl = cor(sulfate, nitrate)) %>%
subset(subset = n > threshold, select = correl)
df2[[1]]
}
corr() %>%
head()
[1] -0.22255256 -0.01895754 -0.14051254 -0.04389737 -0.06815956 -0.12350667
cr <- corr('specdata', 150)
head(cr)
[1] -0.01895754 -0.14051254 -0.04389737 -0.06815956 -0.12350667 -0.07588814
summary(cr)
Min. 1st Qu. Median Mean 3rd Qu. Max.
-0.21057 -0.04999 0.09463 0.12525 0.26844 0.76313
cr <- corr('specdata', 5000)
cr
numeric(0)
length(cr)
[1] 0
t <- corr("specdata")
length(t)
[1] 323
summary(t)
Min. 1st Qu. Median Mean 3rd Qu. Max.
-1.00000 -0.05282 0.10718 0.13684 0.27831 1.00000
LS0tDQp0aXRsZTogIldlZWsgMjogUHJvZ3JhbW1pbmcgQXNzaWdubWVudCINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCiMjIyAqKldyaXRpbmcgRnVuY3Rpb25zLCBDb21iaW5pbmcgRmlsZXMsIFN1bW1hcml6aW5nIERhdGEqKg0KDQoNCiMjIyMjICoqUVVFU1RJT04gMSoqDQoNCg0KSW50cm9kdWN0aW9uDQoNCkZvciB0aGlzIGZpcnN0IHByb2dyYW1taW5nIGFzc2lnbm1lbnQgeW91IHdpbGwgd3JpdGUgdGhyZWUgZnVuY3Rpb25zIHRoYXQgYXJlIG1lYW50IHRvIGludGVyYWN0IHdpdGggZGF0YXNldCB0aGF0IGFjY29tcGFuaWVzIHRoaXMgYXNzaWdubWVudC4gVGhlIGRhdGFzZXQgaXMgY29udGFpbmVkIGluIGEgemlwIGZpbGUgc3BlY2RhdGEuemlwIHRoYXQgeW91IGNhbiBkb3dubG9hZCBmcm9tIHRoZSBDb3Vyc2VyYSB3ZWIgc2l0ZS4gDQoNCkFsdGhvdWdoIHRoaXMgaXMgYSBwcm9ncmFtbWluZyBhc3NpZ25tZW50LCB5b3Ugd2lsbCBiZSBhc3Nlc3NlZCB1c2luZyBhIHNlcGFyYXRlIHF1aXouDQpEYXRhDQoNClRoZSB6aXAgZmlsZSBjb250YWluaW5nIHRoZSBkYXRhIGNhbiBiZSBkb3dubG9hZGVkIGhlcmU6IENvdXJzZXJhDQoNClRoZSB6aXAgZmlsZSBjb250YWlucyAzMzIgY29tbWEtc2VwYXJhdGVkLXZhbHVlIChDU1YpIGZpbGVzIGNvbnRhaW5pbmcgcG9sbHV0aW9uIG1vbml0b3JpbmcgZGF0YSBmb3IgZmluZSBwYXJ0aWN1bGF0ZSBtYXR0ZXIgKFBNKSBhaXIgcG9sbHV0aW9uIGF0IDMzMiBsb2NhdGlvbnMgaW4gdGhlIFVuaXRlZCBTdGF0ZXMuIEVhY2ggZmlsZSBjb250YWlucyBkYXRhIGZyb20gYSBzaW5nbGUgbW9uaXRvciBhbmQgdGhlIElEIG51bWJlciBmb3IgZWFjaCBtb25pdG9yIGlzIGNvbnRhaW5lZCBpbiB0aGUgZmlsZSBuYW1lLiBGb3IgZXhhbXBsZSwgZGF0YSBmb3IgbW9uaXRvciAyMDAgaXMgY29udGFpbmVkIGluIHRoZSBmaWxlICIyMDAuY3N2Ii4gRWFjaCBmaWxlIGNvbnRhaW5zIHZhcmlhYmxlczoNCg0KICAgIERhdGU6IHRoZSBkYXRlIG9mIHRoZSBvYnNlcnZhdGlvbiBpbiBNTS1ERC1ZWVlZIGZvcm1hdCAobW9udGgtZGF5LXllYXIpDQoNCiAgICBzdWxmYXRlOiB0aGUgbGV2ZWwgb2Ygc3VsZmF0ZSBQTSBpbiB0aGUgYWlyIG9uIHRoYXQgZGF0ZSAobWVhc3VyZWQgaW4gbWljcm9ncmFtcyBwZXIgY3ViaWMgbWV0ZXIpDQoNCiAgICBuaXRyYXRlOiB0aGUgbGV2ZWwgb2Ygbml0cmF0ZSBQTSBpbiB0aGUgYWlyIG9uIHRoYXQgZGF0ZSAobWVhc3VyZWQgaW4gbWljcm9ncmFtcyBwZXIgY3ViaWMgbWV0ZXIpDQogICAgDQpgYGB7ciBmaWxlLCBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImZpbGVfcHJvdG90eXBlLmpwZyIpDQpgYGANCg0KDQoNCkZvciB0aGlzIHByb2dyYW1taW5nIGFzc2lnbm1lbnQgeW91IHdpbGwgbmVlZCB0byB1bnppcCB0aGlzIGZpbGUgYW5kIGNyZWF0ZSB0aGUgZGlyZWN0b3J5ICdzcGVjZGF0YScuIE9uY2UgeW91IGhhdmUgdW56aXBwZWQgdGhlIHppcCBmaWxlLCBkbyBub3QgbWFrZSBhbnkgbW9kaWZpY2F0aW9ucyB0byB0aGUgZmlsZXMgaW4gdGhlICdzcGVjZGF0YScgZGlyZWN0b3J5LiBJbiBlYWNoIGZpbGUgeW91J2xsIG5vdGljZSB0aGF0IHRoZXJlIGFyZSBtYW55IGRheXMgd2hlcmUgZWl0aGVyIHN1bGZhdGUgb3Igbml0cmF0ZSAob3IgYm90aCkgYXJlIG1pc3NpbmcgKGNvZGVkIGFzIE5BKS4gVGhpcyBpcyBjb21tb24gd2l0aCBhaXIgcG9sbHV0aW9uIG1vbml0b3JpbmcgZGF0YSBpbiB0aGUgVW5pdGVkIFN0YXRlcy4NClBhcnQgMQ0KDQpXcml0ZSBhIGZ1bmN0aW9uIG5hbWVkICdwb2xsdXRhbnRtZWFuJyB0aGF0IGNhbGN1bGF0ZXMgdGhlIG1lYW4gb2YgYSBwb2xsdXRhbnQgKHN1bGZhdGUgb3Igbml0cmF0ZSkgYWNyb3NzIGEgc3BlY2lmaWVkIGxpc3Qgb2YgbW9uaXRvcnMuIFRoZSBmdW5jdGlvbiAncG9sbHV0YW50bWVhbicgdGFrZXMgdGhyZWUgYXJndW1lbnRzOiAnZGlyZWN0b3J5JywgJ3BvbGx1dGFudCcsIGFuZCAnaWQnLiBHaXZlbiBhIHZlY3RvciBtb25pdG9yIElEIG51bWJlcnMsICdwb2xsdXRhbnRtZWFuJyByZWFkcyB0aGF0IG1vbml0b3JzJyBwYXJ0aWN1bGF0ZSBtYXR0ZXIgZGF0YSBmcm9tIHRoZSBkaXJlY3Rvcnkgc3BlY2lmaWVkIGluIHRoZSAnZGlyZWN0b3J5JyBhcmd1bWVudCBhbmQgcmV0dXJucyB0aGUgbWVhbiBvZiB0aGUgcG9sbHV0YW50IGFjcm9zcyBhbGwgb2YgdGhlIG1vbml0b3JzLCBpZ25vcmluZyBhbnkgbWlzc2luZyB2YWx1ZXMgY29kZWQgYXMgTkEuIEEgcHJvdG90eXBlIG9mIHRoZSBmdW5jdGlvbiBpcyBhcyBmb2xsb3dzOg0KIA0KYGBge3IgcG9sbHV0YW50X21lYW4sIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygicG9sbHV0YW50X21lYW5fcHJvdG90eXBlLmpwZyIpDQoNCmBgYA0KDQoNCllvdSBjYW4gc2VlIHNvbWUgZXhhbXBsZSBvdXRwdXQgZnJvbSB0aGlzIGZ1bmN0aW9uIGJlbG93LiBUaGUgZnVuY3Rpb24gdGhhdCB5b3Ugd3JpdGUgc2hvdWxkIGJlIGFibGUgdG8gbWF0Y2ggdGhpcyBvdXRwdXQuIA0KDQoNCiMjIyMjICoqSGVscGVyIGZ1bmN0aW9uIGZvciBwb2xsdXRhbnRfbWVhbigpKioNCi1Db21iaW5lIGZpbGVzIHdpdGggZ2l2ZW4gaWQgbnVtYmVycyBpbiBzcGVjZGF0YSBmb2xkZXINCmBgYHtyfQ0KIyAnSUQnIGlzIHRoZSBmb3VydGggY29sdW1uIGluIGVhY2ggZmlsZQ0KY29tYmluZV9jc3YgPC0gZnVuY3Rpb24oZGlyZWN0b3J5ID0gJ3NwZWNkYXRhJywgaWQgPSAxOjMzMil7DQogIA0KICBkZiA8LSBsaXN0LmZpbGVzKHBhdGggPSBkaXJlY3RvcnksIGZ1bGwubmFtZXMgPSBUUlVFKSAlPiUNCiAgICBsYXBwbHkocmVhZC5jc3YpICU+JQ0KICAgIGJpbmRfcm93cygpDQogIA0KICBpZihpcy5udWxsKGlkKSl7DQogICAgZGYNCiAgfWVsc2V7DQogICAgZGYgJT4lDQogICAgZmlsdGVyKElEICVpbiUgaWQpDQogIH0NCiAgDQp9DQoNCmBgYA0KDQoNCmBgYHtyfQ0KcG9sbHV0YW50X21lYW4gPC0gZnVuY3Rpb24oZGlyZWN0b3J5ID0gJ3NwZWNkYXRhJywgcG9sbHV0YW50ID0gJ3N1bGZhdGUnLCBpZCA9IDE6MzMyKXsNCg0KICBkZiA8LSBjb21iaW5lX2NzdihkaXJlY3RvcnkgPSBkaXJlY3RvcnksIGlkID0gaWQpICNjb21iaW5lIGZpbGVzIGluIGRpcmVjdG9yeQ0KDQogIHBvbGx1dGFudFZlYyA8LSBkZlssIHBvbGx1dGFudF07ICNtZWFuIHRha2VzIGEgdmVjdG9yDQogIG1lYW4ocG9sbHV0YW50VmVjLCBuYS5ybSA9IFRSVUUpICMgRmluZCBhdmVyYWdlDQogIH0NCg0KYGBgDQoNCmBgYHtyfQ0KcG9sbHV0YW50X21lYW4oInNwZWNkYXRhIiwgInN1bGZhdGUiKQ0KYGBgDQoNCmBgYHtyfQ0KcG9sbHV0YW50X21lYW4oaWQgPSAxOjEwKQ0KYGBgDQoNCmBgYHtyfQ0KcG9sbHV0YW50X21lYW4oInNwZWNkYXRhIiwgIm5pdHJhdGUiLCA3MDo3MikNCmBgYA0KDQpgYGB7cn0NCnBvbGx1dGFudF9tZWFuKCdzcGVjZGF0YScsICduaXRyYXRlJywgMjMpDQpgYGANCg0KDQoNCiMjIyMjICoqUVVFU1RJT04gMioqDQoNClBhcnQgMg0KDQpXcml0ZSBhIGZ1bmN0aW9uIHRoYXQgcmVhZHMgYSBkaXJlY3RvcnkgZnVsbCBvZiBmaWxlcyBhbmQgcmVwb3J0cyB0aGUgbnVtYmVyIG9mIGNvbXBsZXRlbHkgb2JzZXJ2ZWQgY2FzZXMgaW4gZWFjaCBkYXRhIGZpbGUuIFRoZSBmdW5jdGlvbiBzaG91bGQgcmV0dXJuIGEgZGF0YSBmcmFtZSB3aGVyZSB0aGUgZmlyc3QgY29sdW1uIGlzIHRoZSBuYW1lIG9mIHRoZSBmaWxlIGFuZCB0aGUgc2Vjb25kIGNvbHVtbiBpcyB0aGUgbnVtYmVyIG9mIGNvbXBsZXRlIGNhc2VzLiANCiBBIHByb3RvdHlwZSBvZiB0aGlzIGZ1bmN0aW9uIGZvbGxvd3M6DQogDQpgYGB7ciBjb21wbGV0ZSwgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJjb21wbGV0ZV9wcm90b3R5cGUuanBnIikNCmBgYA0KIA0KDQpZb3UgY2FuIHNlZSBzb21lIGV4YW1wbGUgb3V0cHV0IGZyb20gdGhpcyBmdW5jdGlvbiBiZWxvdy4gVGhlIGZ1bmN0aW9uIHRoYXQgeW91IHdyaXRlIHNob3VsZCBiZSBhYmxlIHRvIG1hdGNoIHRoaXMgb3V0cHV0Lg0KDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KDQoNCmBgYHtyfQ0KY29tcGxldGUgPC0gZnVuY3Rpb24oZGlyZWN0b3J5ID0gJ3NwZWNkYXRhJywgaWQgPSBOVUxMKXsNCiAgDQogIGRmIDwtIGNvbWJpbmVfY3N2KGRpcmVjdG9yeSwgaWQpDQogIA0KICBkZiAlPiUNCiAgICBkcm9wX25hKCkgJT4lDQogICAgZ3JvdXBfYnkoaWQgPSBJRCkgJT4lDQogICAgc3VtbWFyaXplKG5vYnMgPSBuKCkpDQogICAgIyBzdW1tYXJpemUobnVtX2NvbXBsZXRlX2Nhc2VzID0gbigpKQ0KfQ0KDQpgYGANCg0KYGBge3J9DQpjb21wbGV0ZShpZCA9IDEpDQpgYGANCg0KYGBge3J9DQpjb21wbGV0ZShpZCA9IGMoMiwgNCwgNiwgOCwgMTAsIDEyKSkNCmBgYA0KDQpgYGB7cn0NCmNvbXBsZXRlKGlkID0gMzA6MjUpDQpgYGANCg0KYGBge3J9DQpjb21wbGV0ZShpZCA9IDMpDQpgYGANCg0KYGBge3J9DQpjYyA8LSBjb21wbGV0ZSgic3BlY2RhdGEiLCBjKDYsIDEwLCAyMCwgMzQsIDEwMCwgMjAwLCAzMTApKQ0KcHJpbnQoY2Mkbm9icykNCg0KYGBgDQoNCmBgYHtyfQ0KY2MgPC0gY29tcGxldGUoInNwZWNkYXRhIiwgNTQpDQpwcmludChjYyRub2JzKQ0KDQpgYGANCiANCiMjIyMjICoqUVVFU1RJT04gMyoqDQoNCldyaXRlIGEgZnVuY3Rpb24gdGhhdCB0YWtlcyBhIGRpcmVjdG9yeSBvZiBkYXRhIGZpbGVzIGFuZCBhIHRocmVzaG9sZCBmb3IgY29tcGxldGUgY2FzZXMgYW5kIGNhbGN1bGF0ZXMgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gc3VsZmF0ZSBhbmQgbml0cmF0ZSBmb3IgbW9uaXRvciBsb2NhdGlvbnMgd2hlcmUgdGhlIG51bWJlciBvZiBjb21wbGV0ZWx5IG9ic2VydmVkIGNhc2VzIChvbiBhbGwgdmFyaWFibGVzKSBpcyBncmVhdGVyIHRoYW4gdGhlIHRocmVzaG9sZC4gVGhlIGZ1bmN0aW9uIHNob3VsZCByZXR1cm4gYSB2ZWN0b3Igb2YgY29ycmVsYXRpb25zIGZvciB0aGUgbW9uaXRvcnMgdGhhdCBtZWV0IHRoZSB0aHJlc2hvbGQgcmVxdWlyZW1lbnQuIElmIG5vIG1vbml0b3JzIG1lZXQgdGhlIHRocmVzaG9sZCByZXF1aXJlbWVudCwgdGhlbiB0aGUgZnVuY3Rpb24gc2hvdWxkIHJldHVybiBhIG51bWVyaWMgdmVjdG9yIG9mIGxlbmd0aCAwLiBBIHByb3RvdHlwZSBvZiB0aGlzIGZ1bmN0aW9uIGZvbGxvd3M6DQoNCmBgYHtyIGNvcnIsIGVjaG89VFJVRSwgd2FybmluZz1GQUxTRX0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJjb3JyX3Byb3RvdHlwZS5qcGciKQ0KYGBgDQoNCg0KRm9yIHRoaXMgZnVuY3Rpb24geW91IHdpbGwgbmVlZCB0byB1c2UgdGhlICdjb3InIGZ1bmN0aW9uIGluIFIgd2hpY2ggY2FsY3VsYXRlcyB0aGUgY29ycmVsYXRpb24gYmV0d2VlbiB0d28gdmVjdG9ycy4gUGxlYXNlIHJlYWQgdGhlIGhlbHAgcGFnZSBmb3IgdGhpcyBmdW5jdGlvbiB2aWEgJz9jb3InIGFuZCBtYWtlIHN1cmUgdGhhdCB5b3Uga25vdyBob3cgdG8gdXNlIGl0Lg0KDQpZb3UgY2FuIHNlZSBzb21lIGV4YW1wbGUgb3V0cHV0IGZyb20gdGhpcyBmdW5jdGlvbiBiZWxvdy4gVGhlIGZ1bmN0aW9uIHRoYXQgeW91IHdyaXRlIHNob3VsZCBiZSBhYmxlIHRvIGFwcHJveGltYXRlbHkgbWF0Y2ggdGhpcyBvdXRwdXQuIE5vdGUgdGhhdCBiZWNhdXNlIG9mIGhvdyBSIHJvdW5kcyBhbmQgcHJlc2VudHMgZmxvYXRpbmcgcG9pbnQgbnVtYmVycywgdGhlIG91dHB1dCB5b3UgZ2VuZXJhdGUgbWF5IGRpZmZlciBzbGlnaHRseSBmcm9tIHRoZSBleGFtcGxlIG91dHB1dC4gUGxlYXNlIHNhdmUgeW91ciBjb2RlIHRvIGEgZmlsZSBuYW1lZCBjb3JyLlIuIFRvIHJ1biB0aGUgc3VibWl0IHNjcmlwdCBmb3IgdGhpcyBwYXJ0LCBtYWtlIHN1cmUgeW91ciB3b3JraW5nIGRpcmVjdG9yeSBoYXMgdGhlIGZpbGUgY29yci5SIGluIGl0Lg0KDQoNCmBgYHtyfQ0KY29yciA8LSBmdW5jdGlvbihkaXJlY3RvcnkgPSAnc3BlY2RhdGEnLCB0aHJlc2hvbGQgPSAwKXsNCiAgDQogIGRmIDwtIGNvbWJpbmVfY3N2KGRpcmVjdG9yeSA9IGRpcmVjdG9yeSwgaWQgPSBOVUxMKQ0KICANCiAgZGYyIDwtIGRmICU+JQ0KICAgIGRyb3BfbmEoKSAlPiUNCiAgICBncm91cF9ieShpZCA9IElEKSU+JQ0KICAgIHN1bW1hcml6ZShuID0gbigpLCBjb3JyZWwgPSBjb3Ioc3VsZmF0ZSwgbml0cmF0ZSkpICU+JQ0KICAgIHN1YnNldChzdWJzZXQgPSBuID4gdGhyZXNob2xkLCBzZWxlY3QgPSBjb3JyZWwpIA0KICANCiAgZGYyW1sxXV0NCg0KICANCn0NCg0KYGBgDQoNCmBgYHtyfQ0KY29ycigpICU+JSANCiAgaGVhZCgpDQpgYGANCg0KYGBge3J9DQpjciA8LSBjb3JyKCdzcGVjZGF0YScsIDE1MCkNCmhlYWQoY3IpDQpgYGANCmBgYHtyfQ0Kc3VtbWFyeShjcikNCmBgYA0KDQpgYGB7cn0NCmNyIDwtIGNvcnIoJ3NwZWNkYXRhJywgNTAwMCkNCmNyDQpgYGANCmBgYHtyfQ0KbGVuZ3RoKGNyKQ0KYGBgDQoNCg0KYGBge3J9DQp0IDwtIGNvcnIoInNwZWNkYXRhIikNCmxlbmd0aCh0KQ0KDQpgYGANCmBgYHtyfQ0Kc3VtbWFyeSh0KQ0KYGBgDQoNCg==