Reading and Writing Files
This covers loading and saving data in an active workspace by reading and writing files.
8.1 R-Ready Data Sets
Enter data() at the R prompt to bring up a window listing these ready-to-use data sets along with a one-line description
data()
Use ???data(package = .packages(all.available = TRUE))??? to list the data sets in all available packages.
8.1.1 Built-in Data sets
To see a summary of the data sets contained in the package, you can use the library function library(help=“datasets”)
library(help="datasets")
?ChickWeight
ChickWeight[1:15,]
Grouped Data: weight ~ Time | Chick
weight Time Chick Diet
1 42 0 1 1
2 51 2 1 1
3 59 4 1 1
4 64 6 1 1
5 76 8 1 1
6 93 10 1 1
7 106 12 1 1
8 125 14 1 1
9 149 16 1 1
10 171 18 1 1
11 199 20 1 1
12 205 21 1 1
13 40 0 2 1
14 49 2 2 1
15 58 4 2 1
8.1.2 Contributed Data Sets
Additional data sets are also available as contributed packages. To access them, first install and load the relevant package. Consider the data set ice.river which is in the contriubted package tseries by Trapletti and Hornik(2013)
First install the package by running the line install.packages(“tseries”) at the prompt. Then, to access the components of the pakcage, load it using library
install.packages("tseries"
)
library("tseries")
library(help="tseries")
You can enter ?ice.river to find more detals about th data set you want to work . The help file describes it as a “time series object” comprrised of river flow, precipitation, and temperature measurements. Data initially reported in Tong (1990)
?ice.river
Warning message:
In native_encode(res, to = encoding) :
some characters may not work under the current locale
Icelandic River Data
Description
Contains the Icelandic river data as presented in Tong (1990), pages 432???440.
Usage
data(ice.river) Format
4 univariate time series flow.vat, flow.jok, prec, and temp, each with 1095 observations and the joint series ice.river.
Details
The series are daily observations from Jan. 1, 1972 to Dec. 31, 1974 on 4 variables: flow.vat, mean daily flow of Vatnsdalsa river (cms), flow.jok, mean daily flow of Jokulsa Eystri river (cms), prec, daily precipitation in Hveravellir (mm), and mean daily temperature in Hveravellir (deg C).
These datasets were introduced into the literature in a paper by Tong, Thanoon, and Gudmundsson (1985).
data(ice.river)
ice.river[1:5,]
flow.vat flow.jok prec temp
[1,] 16.1 30.2 8.1 0.9
[2,] 19.2 29.0 4.4 1.6
[3,] 14.5 28.4 7.0 0.1
[4,] 11.0 27.8 0.0 0.6
[5,] 13.6 27.8 0.0 2.0
8.2 Reading in External Data Files
You often have to work with data from external sources. This shows how to do that.
8.2.1 The Table format
Table format files have 3 key features: Header (provides names for each column of data) Delimiter (character used to separate the entries in each line) Missing Value (character string used to exclusively denote a missing value)
Typically these files have a .txt extension or .csv Download the sample files from: https://www.nostarch.com/bookofr
mydatafile<- read.table(file="d:/bookofr/8.2.1_mydatafile.txt",
header = TRUE,
sep=" ",
na.strings="*",
stringsAsFactors = FALSE)
mydatafile
Tip: if you are working with multiple files and don’t want to specify the working directory, you can set it with the setwd() command
# get working directory
getwd()
[1] "D:/Dropbox/BigData/R Programming/Work"
# change it back to original setting
setwd("D:/Dropbox/BigData/R Programming/Work")
getwd()
[1] "D:/Dropbox/BigData/R Programming/Work"
list.files("D:/Dropbox/BigData/R Programming/Work/bookofr")
[1] "8.2.1_mydatafile.txt" "8.2.2_spreadsheetfile.csv" "Davies_Part1_Solutions.R"
[4] "Davies_Part1_Source_Code.R" "Davies_Part2_Solutions.R" "Davies_Part2_Source_Code.R"
[7] "Davies_Part3_Solutions.R" "Davies_Part3_Source_Code.R" "Davies_Part4_Solutions.R"
[10] "Davies_Part4_Source_Code.R" "Davies_Part5_Solutions.R" "Davies_Part5_Source_Code.R"
You can also find files interactively using the file.choose command
file.choose()
[1] "D:\\Dropbox\\BigData\\R Programming\\Work\\bookofr\\8.2.1_mydatafile.txt"
So you can combine the output of the above command to load the file.
mydatafile<- read.table(file=file.choose(),
header = TRUE,
sep=" ",
na.strings="*",
stringsAsFactors = FALSE)
mydatafile
Normally, read.table will convert non-numeric values into factors by default. To prevent this, we use the “stringsAsFactors=FALSE” To overide one of them as that data type:
# look at the current mydatafile before data type overide
mydatafile
# now we overide them
mydatafile$sex <- as.factor(mydatafile$sex)
mydatafile$funny <- factor(x=mydatafile$funny,levels=c("Low","Med","High"))
mydatafile
8.2.2 Spreadsheet Workbooks
Generally you will need to use file save as and save the xls or xlsx into .csv format. You can also use some contributed packages like gdata by Warnes et al. or XLConnect by Mirai Solutions
8.2.3 Web Based Files
You use the same read.table command, but this time in the file=“” area, use the URL
dia.url<-"http://www.amstat.org/publications/jse/v9n2/4cdata.txt"
diamonds <-read.table(dia.url)
diamonds
# now add the header using the names function
names(diamonds)<-c("Carat","Color","Clarity","Cert","Price")
# now list the table
diamonds[1:5,]
8.2.4 Other File Formats
Other format like .dat can be imported using read.table. Use the skip argument to remove the unwanted extra lines
8.3 Writing out data files and plots
8.3.1 Data Sets
Use the write.table function
write.table(x=mydatafile, file="D:\\Dropbox\\BigData\\R Programming\\Work\\bookofr\\somenewfile.txt",
sep="@",
na="??",
quote=FALSE,
row.names=FALSE)
The output file will have contents like this:
person@age@sex@funny@age.mon Peter@??@M@High@504 Lois@40@F@??@480 Meg@17@F@Low@204 Chris@14@M@Med@168 Stewie@1@M@High@?? Brian@??@M@Med@??
See also read.csv and write.csv which are shortcut versions of read.table and write.table.
8.3.2 Plot and Graphics Files
YOu can save plots using either: jpeg pdf eps ggsave
jpeg(filename="D:\\Dropbox\\BigData\\R Programming\\Work\\bookofr\\someplot.jpeg",
width=600,height=600
)
plot(1:5,10:6,ylab="Y axis", xlab=" x axis",
main="A save jpeg plot")
points(1:5,10:6,cex=2,pch=4, col=2)
dev.off()
null device
1
pdf(file="D:\\Dropbox\\BigData\\R Programming\\Work\\bookofr\\someplot.pdf",
width=5,height=5
)
plot(1:5,10:6,ylab="Y axis", xlab=" x axis",
main="A save jpeg plot")
points(1:5,10:6,cex=2,pch=4, col=2)
dev.off()
null device
1
library("ggplot2")
foo
[1] 1.1 2.0 3.5 3.9 4.2
bar
[1] 2.0 2.2 -1.3 0.0 0.2
qplot(foo,bar,geom="blank")+
geom_point(size=3,shape=8,color="darkgreen")+
geom_line(color="orange",linetype=4)
# now save the plot using ggsave
ggsave(filename="D:\\Dropbox\\BigData\\R Programming\\Work\\bookofr\\myqplot.png")
Saving 7.29 x 4.5 in image
# you can save into different formats by simply changing the extension
ggsave(filename="D:\\Dropbox\\BigData\\R Programming\\Work\\bookofr\\myqplot.pdf")
Saving 7.29 x 4.5 in image

To find our more details: ?pdf ?postscript ?jpeg ?ggsave
8.4 Ad Hoc Object Read/Write Operations
Use dput and dget
somelist<-list(foo=c(5,2,45),
bar=matrix(data=c(T,T,F,F,F,F,T,F,T), nrow=3,ncol=3),
baz=factor(c(1,2,2,3,1,1,3),levels=1:3,ordered=T))
somelist
$foo
[1] 5 2 45
$bar
[,1] [,2] [,3]
[1,] TRUE FALSE TRUE
[2,] TRUE FALSE FALSE
[3,] FALSE FALSE TRUE
$baz
[1] 1 2 2 3 1 1 3
Levels: 1 < 2 < 3
# put object somelist into file
dput(x=somelist, file="D:\\Dropbox\\BigData\\R Programming\\Work\\bookofr\\myRobject.txt")
Now to read back the object
newobect<-dget(file="D:\\Dropbox\\BigData\\R Programming\\Work\\bookofr\\myRobject.txt")
newobect
$foo
[1] 5 2 45
$bar
[,1] [,2] [,3]
[1,] TRUE FALSE TRUE
[2,] TRUE FALSE FALSE
[3,] FALSE FALSE TRUE
$baz
[1] 1 2 2 3 1 1 3
Levels: 1 < 2 < 3
LS0tDQp0aXRsZTogIkNoYXB0ZXIgOCBSZWFkaW5nIGFuZCBXcml0aW5nIEZpbGVzIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KPEgxPlJlYWRpbmcgYW5kIFdyaXRpbmcgRmlsZXMgPC9IMT4NClRoaXMgY292ZXJzIGxvYWRpbmcgYW5kIHNhdmluZyBkYXRhIGluIGFuIGFjdGl2ZSB3b3Jrc3BhY2UgYnkgcmVhZGluZyBhbmQgd3JpdGluZyBmaWxlcy4NCg0KPGgyPiA4LjEgUi1SZWFkeSBEYXRhIFNldHM8L2gyPg0KRW50ZXIgZGF0YSgpIGF0IHRoZSBSIHByb21wdCB0byBicmluZyB1cCBhIHdpbmRvdyBsaXN0aW5nIHRoZXNlIHJlYWR5LXRvLXVzZSBkYXRhIHNldHMgYWxvbmcgd2l0aCBhIG9uZS1saW5lIGRlc2NyaXB0aW9uDQoNCmBgYHtyfQ0KZGF0YSgpDQpgYGANCg0KVXNlID8/P2RhdGEocGFja2FnZSA9IC5wYWNrYWdlcyhhbGwuYXZhaWxhYmxlID0gVFJVRSkpPz8/DQp0byBsaXN0IHRoZSBkYXRhIHNldHMgaW4gYWxsICphdmFpbGFibGUqIHBhY2thZ2VzLg0KDQoNCjxoMz4gOC4xLjEgQnVpbHQtaW4gRGF0YSBzZXRzPC9oMz4NClRvIHNlZSBhIHN1bW1hcnkgb2YgdGhlIGRhdGEgc2V0cyBjb250YWluZWQgaW4gdGhlIHBhY2thZ2UsIHlvdSBjYW4gdXNlIHRoZSBsaWJyYXJ5IGZ1bmN0aW9uIGxpYnJhcnkoaGVscD0iZGF0YXNldHMiKQ0KDQpgYGB7cn0NCmxpYnJhcnkoaGVscD0iZGF0YXNldHMiKQ0KYGBgDQoNCg0KYGBge3J9DQo/Q2hpY2tXZWlnaHQNCmBgYA0KDQoNCiAgICAgICANCmBgYHtyfQ0KQ2hpY2tXZWlnaHRbMToxNSxdDQoNCmBgYA0KDQogICAgICAgICAgICAgICAgICAgICAgICANCjxoMz4gOC4xLjIgQ29udHJpYnV0ZWQgRGF0YSBTZXRzPC9oMz4NCkFkZGl0aW9uYWwgZGF0YSBzZXRzIGFyZSBhbHNvIGF2YWlsYWJsZSBhcyBjb250cmlidXRlZCBwYWNrYWdlcy4NClRvIGFjY2VzcyB0aGVtLCBmaXJzdCBpbnN0YWxsIGFuZCBsb2FkIHRoZSByZWxldmFudCBwYWNrYWdlLg0KQ29uc2lkZXIgdGhlIGRhdGEgc2V0IGljZS5yaXZlciB3aGljaCBpcyBpbiB0aGUgY29udHJpdWJ0ZWQgcGFja2FnZSB0c2VyaWVzIGJ5IFRyYXBsZXR0aSBhbmQgSG9ybmlrKDIwMTMpDQoNCkZpcnN0IGluc3RhbGwgdGhlIHBhY2thZ2UgYnkgcnVubmluZyB0aGUgbGluZSAgaW5zdGFsbC5wYWNrYWdlcygidHNlcmllcyIpIGF0IHRoZSBwcm9tcHQuDQpUaGVuLCB0byBhY2Nlc3MgdGhlIGNvbXBvbmVudHMgb2YgdGhlIHBha2NhZ2UsIGxvYWQgaXQgdXNpbmcgbGlicmFyeQ0KYGBge3J9DQppbnN0YWxsLnBhY2thZ2VzKCJ0c2VyaWVzIg0KICAgICAgICAgICAgICAgICApDQoNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoInRzZXJpZXMiKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShoZWxwPSJ0c2VyaWVzIikNCmBgYA0KDQpZb3UgY2FuIGVudGVyID9pY2Uucml2ZXIgdG8gZmluZCBtb3JlIGRldGFscyBhYm91dCB0aCBkYXRhIHNldCB5b3Ugd2FudCB0byB3b3JrIC4NClRoZSBoZWxwIGZpbGUgZGVzY3JpYmVzIGl0IGFzIGEgInRpbWUgc2VyaWVzIG9iamVjdCIgY29tcHJyaXNlZCBvZiByaXZlciBmbG93LCBwcmVjaXBpdGF0aW9uLCBhbmQgdGVtcGVyYXR1cmUgbWVhc3VyZW1lbnRzLiBEYXRhIGluaXRpYWxseSByZXBvcnRlZCBpbiBUb25nICgxOTkwKQ0KDQpgYGB7cn0NCj9pY2Uucml2ZXINCg0KYGBgDQpJY2VsYW5kaWMgUml2ZXIgRGF0YQ0KDQpEZXNjcmlwdGlvbg0KDQpDb250YWlucyB0aGUgSWNlbGFuZGljIHJpdmVyIGRhdGEgYXMgcHJlc2VudGVkIGluIFRvbmcgKDE5OTApLCBwYWdlcyA0MzI/Pz80NDAuDQoNClVzYWdlDQoNCmRhdGEoaWNlLnJpdmVyKQ0KRm9ybWF0DQoNCjQgdW5pdmFyaWF0ZSB0aW1lIHNlcmllcyBmbG93LnZhdCwgZmxvdy5qb2ssIHByZWMsIGFuZCB0ZW1wLCBlYWNoIHdpdGggMTA5NSBvYnNlcnZhdGlvbnMgYW5kIHRoZSBqb2ludCBzZXJpZXMgaWNlLnJpdmVyLg0KDQpEZXRhaWxzDQoNClRoZSBzZXJpZXMgYXJlIGRhaWx5IG9ic2VydmF0aW9ucyBmcm9tIEphbi4gMSwgMTk3MiB0byBEZWMuIDMxLCAxOTc0IG9uIDQgdmFyaWFibGVzOiBmbG93LnZhdCwgbWVhbiBkYWlseSBmbG93IG9mIFZhdG5zZGFsc2Egcml2ZXIgKGNtcyksIGZsb3cuam9rLCBtZWFuIGRhaWx5IGZsb3cgb2YgSm9rdWxzYSBFeXN0cmkgcml2ZXIgKGNtcyksIHByZWMsIGRhaWx5IHByZWNpcGl0YXRpb24gaW4gSHZlcmF2ZWxsaXIgKG1tKSwgYW5kIG1lYW4gZGFpbHkgdGVtcGVyYXR1cmUgaW4gSHZlcmF2ZWxsaXIgKGRlZyBDKS4NCg0KVGhlc2UgZGF0YXNldHMgd2VyZSBpbnRyb2R1Y2VkIGludG8gdGhlIGxpdGVyYXR1cmUgaW4gYSBwYXBlciBieSBUb25nLCBUaGFub29uLCBhbmQgR3VkbXVuZHNzb24gKDE5ODUpLg0KDQoNCmBgYHtyfQ0KZGF0YShpY2Uucml2ZXIpDQppY2Uucml2ZXJbMTo1LF0NCmBgYA0KDQo8aDI+IDguMiBSZWFkaW5nIGluIEV4dGVybmFsIERhdGEgRmlsZXM8L2gyPg0KWW91IG9mdGVuIGhhdmUgdG8gd29yayB3aXRoIGRhdGEgZnJvbSBleHRlcm5hbCBzb3VyY2VzLiANClRoaXMgc2hvd3MgaG93IHRvIGRvIHRoYXQuDQoNCjxoMz4gOC4yLjEgVGhlIFRhYmxlIGZvcm1hdDwvaDM+DQpUYWJsZSBmb3JtYXQgZmlsZXMgaGF2ZSAzIGtleSBmZWF0dXJlczoNCkhlYWRlciAocHJvdmlkZXMgbmFtZXMgZm9yIGVhY2ggY29sdW1uIG9mIGRhdGEpDQpEZWxpbWl0ZXIgKGNoYXJhY3RlciB1c2VkIHRvIHNlcGFyYXRlIHRoZSBlbnRyaWVzIGluIGVhY2ggbGluZSkNCk1pc3NpbmcgVmFsdWUgKGNoYXJhY3RlciBzdHJpbmcgdXNlZCB0byBleGNsdXNpdmVseSBkZW5vdGUgYSBtaXNzaW5nIHZhbHVlKQ0KDQpUeXBpY2FsbHkgdGhlc2UgZmlsZXMgaGF2ZSBhIC50eHQgZXh0ZW5zaW9uIG9yIC5jc3YNCkRvd25sb2FkIHRoZSBzYW1wbGUgZmlsZXMgZnJvbToNCmh0dHBzOi8vd3d3Lm5vc3RhcmNoLmNvbS9ib29rb2ZyDQoNCg0KDQpgYGB7cn0NCm15ZGF0YWZpbGU8LSByZWFkLnRhYmxlKGZpbGU9ImQ6L2Jvb2tvZnIvOC4yLjFfbXlkYXRhZmlsZS50eHQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVFJVRSwgDQogICAgICAgICAgICAgICAgICAgICAgICBzZXA9IiAiLA0KICAgICAgICAgICAgICAgICAgICAgICAgbmEuc3RyaW5ncz0iKiIsDQogICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpteWRhdGFmaWxlDQpgYGANClRpcDogaWYgeW91IGFyZSB3b3JraW5nIHdpdGggbXVsdGlwbGUgZmlsZXMgYW5kIGRvbid0IHdhbnQgdG8gc3BlY2lmeSB0aGUgd29ya2luZyBkaXJlY3RvcnksDQp5b3UgY2FuIHNldCBpdCB3aXRoIHRoZSBzZXR3ZCgpIGNvbW1hbmQNCmBgYHtyfQ0KIyBnZXQgd29ya2luZyBkaXJlY3RvcnkNCmdldHdkKCkNCiMgY2hhbmdlIGl0IGJhY2sgdG8gb3JpZ2luYWwgc2V0dGluZw0Kc2V0d2QoIkQ6L0Ryb3Bib3gvQmlnRGF0YS9SIFByb2dyYW1taW5nL1dvcmsiKQ0KZ2V0d2QoKQ0KDQpgYGANCmBgYHtyfQ0KbGlzdC5maWxlcygiRDovRHJvcGJveC9CaWdEYXRhL1IgUHJvZ3JhbW1pbmcvV29yay9ib29rb2ZyIikNCmBgYA0KDQpZb3UgY2FuIGFsc28gZmluZCBmaWxlcyBpbnRlcmFjdGl2ZWx5IHVzaW5nIHRoZSANCmZpbGUuY2hvb3NlIGNvbW1hbmQNCg0KYGBge3J9DQpmaWxlLmNob29zZSgpDQoNCmBgYA0KDQpTbyB5b3UgY2FuIGNvbWJpbmUgdGhlIG91dHB1dCBvZiB0aGUgYWJvdmUgY29tbWFuZCB0byBsb2FkIHRoZSBmaWxlLg0KDQpgYGB7cn0NCm15ZGF0YWZpbGU8LSByZWFkLnRhYmxlKGZpbGU9ZmlsZS5jaG9vc2UoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFRSVUUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgc2VwPSIgIiwNCiAgICAgICAgICAgICAgICAgICAgICAgIG5hLnN0cmluZ3M9IioiLA0KICAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0KbXlkYXRhZmlsZQ0KYGBgDQpOb3JtYWxseSwgDQpyZWFkLnRhYmxlIHdpbGwgY29udmVydCBub24tbnVtZXJpYyB2YWx1ZXMgaW50byBmYWN0b3JzIGJ5IGRlZmF1bHQuIA0KVG8gcHJldmVudCB0aGlzLCB3ZSB1c2UgdGhlICJzdHJpbmdzQXNGYWN0b3JzPUZBTFNFIg0KVG8gb3ZlcmlkZSBvbmUgb2YgdGhlbSBhcyB0aGF0IGRhdGEgdHlwZToNCg0KYGBge3J9DQojIGxvb2sgYXQgdGhlIGN1cnJlbnQgbXlkYXRhZmlsZSBiZWZvcmUgZGF0YSB0eXBlIG92ZXJpZGUNCm15ZGF0YWZpbGUNCiMgbm93IHdlIG92ZXJpZGUgdGhlbQ0KbXlkYXRhZmlsZSRzZXggPC0gYXMuZmFjdG9yKG15ZGF0YWZpbGUkc2V4KQ0KbXlkYXRhZmlsZSRmdW5ueSA8LSBmYWN0b3IoeD1teWRhdGFmaWxlJGZ1bm55LGxldmVscz1jKCJMb3ciLCJNZWQiLCJIaWdoIikpDQpteWRhdGFmaWxlDQoNCmBgYA0KDQo8aDM+IDguMi4yIFNwcmVhZHNoZWV0IFdvcmtib29rczwvaDM+DQoNCkdlbmVyYWxseSB5b3Ugd2lsbCBuZWVkIHRvIHVzZSBmaWxlIHNhdmUgYXMgYW5kIHNhdmUgdGhlIHhscyBvciB4bHN4IGludG8gLmNzdiBmb3JtYXQuDQpZb3UgY2FuIGFsc28gdXNlIHNvbWUgY29udHJpYnV0ZWQgcGFja2FnZXMgbGlrZSBnZGF0YSBieSBXYXJuZXMgZXQgYWwuIG9yIFhMQ29ubmVjdCBieSBNaXJhaSBTb2x1dGlvbnMNCg0KPGgzPiA4LjIuMyBXZWIgQmFzZWQgRmlsZXM8L2gzPg0KWW91IHVzZSB0aGUgc2FtZSByZWFkLnRhYmxlIGNvbW1hbmQsIGJ1dCB0aGlzIHRpbWUgaW4gdGhlIGZpbGU9IiIgYXJlYSwgdXNlIHRoZSBVUkwgDQoNCmBgYHtyfQ0KZGlhLnVybDwtImh0dHA6Ly93d3cuYW1zdGF0Lm9yZy9wdWJsaWNhdGlvbnMvanNlL3Y5bjIvNGNkYXRhLnR4dCINCmRpYW1vbmRzIDwtcmVhZC50YWJsZShkaWEudXJsKQ0KZGlhbW9uZHMNCiMgbm93IGFkZCB0aGUgaGVhZGVyIHVzaW5nIHRoZSBuYW1lcyBmdW5jdGlvbg0KDQpuYW1lcyhkaWFtb25kcyk8LWMoIkNhcmF0IiwiQ29sb3IiLCJDbGFyaXR5IiwiQ2VydCIsIlByaWNlIikNCiMgbm93IGxpc3QgdGhlIHRhYmxlDQpkaWFtb25kc1sxOjUsXQ0KYGBgDQoNCjxoMz4gOC4yLjQgT3RoZXIgRmlsZSBGb3JtYXRzPC9oMz4NCk90aGVyIGZvcm1hdCBsaWtlIC5kYXQgY2FuIGJlIGltcG9ydGVkIHVzaW5nIHJlYWQudGFibGUuIA0KVXNlIHRoZSBza2lwIGFyZ3VtZW50IHRvIHJlbW92ZSB0aGUgdW53YW50ZWQgZXh0cmEgbGluZXMNCg0KPGgyPiA4LjMgV3JpdGluZyBvdXQgZGF0YSBmaWxlcyBhbmQgcGxvdHM8L2gyPg0KDQo8aDM+IDguMy4xIERhdGEgU2V0czwvaDM+DQpVc2UgdGhlIHdyaXRlLnRhYmxlIGZ1bmN0aW9uDQpgYGB7cn0NCndyaXRlLnRhYmxlKHg9bXlkYXRhZmlsZSwgZmlsZT0iRDpcXERyb3Bib3hcXEJpZ0RhdGFcXFIgUHJvZ3JhbW1pbmdcXFdvcmtcXGJvb2tvZnJcXHNvbWVuZXdmaWxlLnR4dCIsDQogICAgICAgICAgICBzZXA9IkAiLA0KICAgICAgICAgICAgbmE9Ij8/IiwNCiAgICAgICAgICAgIHF1b3RlPUZBTFNFLA0KICAgICAgICAgICAgcm93Lm5hbWVzPUZBTFNFKQ0KYGBgDQpUaGUgb3V0cHV0IGZpbGUgd2lsbCBoYXZlIGNvbnRlbnRzIGxpa2UgdGhpczoNCg0KcGVyc29uQGFnZUBzZXhAZnVubnlAYWdlLm1vbg0KUGV0ZXJAPz9ATUBIaWdoQDUwNA0KTG9pc0A0MEBGQD8/QDQ4MA0KTWVnQDE3QEZATG93QDIwNA0KQ2hyaXNAMTRATUBNZWRAMTY4DQpTdGV3aWVAMUBNQEhpZ2hAPz8NCkJyaWFuQD8/QE1ATWVkQD8/DQoNClNlZSBhbHNvIHJlYWQuY3N2IGFuZCB3cml0ZS5jc3Ygd2hpY2ggYXJlIHNob3J0Y3V0IHZlcnNpb25zIG9mIHJlYWQudGFibGUgYW5kIHdyaXRlLnRhYmxlLg0KDQoNCjxoMz4gOC4zLjIgUGxvdCBhbmQgR3JhcGhpY3MgRmlsZXM8L2gzPg0KWU91IGNhbiBzYXZlIHBsb3RzIHVzaW5nIGVpdGhlcjoNCmpwZWcNCnBkZg0KZXBzDQpnZ3NhdmUNCg0KYGBge3J9DQpqcGVnKGZpbGVuYW1lPSJEOlxcRHJvcGJveFxcQmlnRGF0YVxcUiBQcm9ncmFtbWluZ1xcV29ya1xcYm9va29mclxcc29tZXBsb3QuanBlZyIsDQogICAgIHdpZHRoPTYwMCxoZWlnaHQ9NjAwDQogICAgICkNCnBsb3QoMTo1LDEwOjYseWxhYj0iWSBheGlzIiwgeGxhYj0iIHggYXhpcyIsDQogICAgIG1haW49IkEgc2F2ZSBqcGVnIHBsb3QiKQ0KcG9pbnRzKDE6NSwxMDo2LGNleD0yLHBjaD00LCBjb2w9MikNCmRldi5vZmYoKQ0KDQoNCmBgYA0KDQpgYGB7cn0NCiMgcGRmIHVzZXMgZmlsZSBpbnN0ZWFkIG9mIGZpbGVuYW1lDQojIHBkZiB1c2VzIGluY2hlcyBpbnN0ZWFkIG9mIHBpeGVscw0KcGRmKGZpbGU9IkQ6XFxEcm9wYm94XFxCaWdEYXRhXFxSIFByb2dyYW1taW5nXFxXb3JrXFxib29rb2ZyXFxzb21lcGxvdC5wZGYiLA0KICAgICB3aWR0aD01LGhlaWdodD01DQogICAgICkNCnBsb3QoMTo1LDEwOjYseWxhYj0iWSBheGlzIiwgeGxhYj0iIHggYXhpcyIsDQogICAgIG1haW49IkEgc2F2ZSBqcGVnIHBsb3QiKQ0KcG9pbnRzKDE6NSwxMDo2LGNleD0yLHBjaD00LCBjb2w9MikNCmRldi5vZmYoKQ0KDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KCJnZ3Bsb3QyIikNCmZvbw0KYmFyDQpxcGxvdChmb28sYmFyLGdlb209ImJsYW5rIikrDQogIGdlb21fcG9pbnQoc2l6ZT0zLHNoYXBlPTgsY29sb3I9ImRhcmtncmVlbiIpKw0KICBnZW9tX2xpbmUoY29sb3I9Im9yYW5nZSIsbGluZXR5cGU9NCkNCiMgbm93IHNhdmUgdGhlIHBsb3QgdXNpbmcgZ2dzYXZlDQpnZ3NhdmUoZmlsZW5hbWU9IkQ6XFxEcm9wYm94XFxCaWdEYXRhXFxSIFByb2dyYW1taW5nXFxXb3JrXFxib29rb2ZyXFxteXFwbG90LnBuZyIpDQojIHlvdSBjYW4gc2F2ZSBpbnRvIGRpZmZlcmVudCBmb3JtYXRzIGJ5IHNpbXBseSBjaGFuZ2luZyB0aGUgZXh0ZW5zaW9uDQpnZ3NhdmUoZmlsZW5hbWU9IkQ6XFxEcm9wYm94XFxCaWdEYXRhXFxSIFByb2dyYW1taW5nXFxXb3JrXFxib29rb2ZyXFxteXFwbG90LnBkZiIpDQpgYGANClRvIGZpbmQgb3VyIG1vcmUgZGV0YWlsczoNCj9wZGYNCj9wb3N0c2NyaXB0DQo/anBlZw0KP2dnc2F2ZQ0KDQoNCjxoMj4gOC40IEFkIEhvYyBPYmplY3QgUmVhZC9Xcml0ZSBPcGVyYXRpb25zPC9oMj4NClVzZSBkcHV0IGFuZCBkZ2V0DQpgYGB7cn0NCnNvbWVsaXN0PC1saXN0KGZvbz1jKDUsMiw0NSksDQogICAgICAgICAgICAgICBiYXI9bWF0cml4KGRhdGE9YyhULFQsRixGLEYsRixULEYsVCksIG5yb3c9MyxuY29sPTMpLA0KICAgICAgICAgICAgICAgYmF6PWZhY3RvcihjKDEsMiwyLDMsMSwxLDMpLGxldmVscz0xOjMsb3JkZXJlZD1UKSkNCnNvbWVsaXN0DQoNCg0KDQpgYGANCmBgYHtyfQ0KIyBwdXQgb2JqZWN0IHNvbWVsaXN0IGludG8gZmlsZQ0KZHB1dCh4PXNvbWVsaXN0LCBmaWxlPSJEOlxcRHJvcGJveFxcQmlnRGF0YVxcUiBQcm9ncmFtbWluZ1xcV29ya1xcYm9va29mclxcbXlSb2JqZWN0LnR4dCIpDQpgYGANCg0KTm93IHRvIHJlYWQgYmFjayB0aGUgb2JqZWN0IA0KYGBge3J9DQpuZXdvYmVjdDwtZGdldChmaWxlPSJEOlxcRHJvcGJveFxcQmlnRGF0YVxcUiBQcm9ncmFtbWluZ1xcV29ya1xcYm9va29mclxcbXlSb2JqZWN0LnR4dCIpDQpuZXdvYmVjdA0KDQpgYGANCg0K