By in large, you will load your data into these structures and pass them to functions for plotting, simulation, plotting, etc. It is a good idea to get used to these.
Creating data.frame
Objects
To make a data.frame
we need to either:
- Make it from scratch using vectors (the more complicated).
- Load it from a file (perhaps the easiest way).
We shall start with the most complicated case.
Creating data.frame
Objects de novo
site <- c( "Const","ESan", "Aqu")
longitude <- c( -111.675, -110.3686, -110.1043)
latitude <- c(25.0247, 24.45879, 23.2855)
sites <- data.frame( Site = site,
Longitude = longitude,
Latitude = latitude )
sites
The thing about data.frame
objects is that the know how to organize and summarize their component variables.
summary(sites)
Site Longitude Latitude
Length:3 Min. :-111.7 Min. :23.29
Class :character 1st Qu.:-111.0 1st Qu.:23.87
Mode :character Median :-110.4 Median :24.46
Mean :-110.7 Mean :24.26
3rd Qu.:-110.2 3rd Qu.:24.74
Max. :-110.1 Max. :25.02
Notice that each variable is summarized a way that gives as much information about the contnets of that variable. The summary()
function is critical and one we will use over and over again.
Loading from File and/or URL
You can also load a data.frame
in using a local file or a URL to a file somewhere on the internet. The easiest way to do this is to have your file as a CSV (Comma-Separated-Value) format. This is usually a \(File \to Save\;As\) kind of routine. It is important for reproducibility and collaboration to 1) Have only one version of your data set, and 2) Keep it in a format that is accessible such as plain text.
Here is the full version of those data loaded above. It is located on a Github website and is accessible to anyone with an internet connection.
url <- "https://raw.githubusercontent.com/dyerlab/ENVS-Lectures/master/data/arapat.csv"
Once we have the url or file as a character
object, we can use the built-in read.csv()
function to load the data into a local variable. Here is what that looks like.
Samples <- read.csv(url)
summary( Samples )
Stratum Longitude Latitude
Length:39 Min. :-114.3 Min. :23.08
Class :character 1st Qu.:-112.9 1st Qu.:24.52
Mode :character Median :-111.5 Median :26.21
Mean :-111.7 Mean :26.14
3rd Qu.:-110.4 3rd Qu.:27.47
Max. :-109.1 Max. :29.33
Working with data.frame
Objects
A variable representing a data.frame
has properties and constituents just like a vector. The size of the data.frame
is defined as the dim
ensions of it and represents the number of rows and columns it contains.
nrow( Samples )
[1] 39
ncol( Samples )
[1] 3
or use the dim()
function which returns both of them.
dim( Samples )
[1] 39 3
Each variable within the data.frame
is represented by the name we gave it when we added it to the data.frame
.
names( Samples )
[1] "Stratum" "Longitude" "Latitude"
Stratum
Longitude
Latitude
The individual elements are available using the square bracket notation, just like for vectors with the exception that we have two coordinates instead of just one. The first coordinate is for row and the second is for column. So to grab the 10\(^{th}\) Stratum
name (row), which is the 1\(^{st}\) variable (column) in the data.frame
, we use:
Samples[10,1]
[1] "SFr"
SFr
While this is OK, it assumes we remember that the Stratum
variable is the first variable in the data.frame
. If you have data sets with thousands of columns of data in them, it becomes less-than-optimal to use variable numbers to index, which is why we can use the variable name itself in the following format.
Samples$Stratum[10]
[1] "SFr"
SFr
Here, we use the name of the data.frame
connected to the name of the variable using the dollar sign ($) to hook them up.
For readability, it is advised that you use the dollar-sign notation to get and set values within a data.frame
. It will always be more clear to you and anyone who reads your code if you are as verbose as you can be in your code. Trust me, your future self will like you much better if you adopt this habit as soon as possible.
Similar to for vectors, we can grab the head and tail of the whole data frame.
head( Samples )
tail(Samples, n=4)
We can use the same approach for setting values within a data.frame
. Here I’ll expand the SFr notion to represent the full location name.
Samples$Stratum[10] <- "San Francisquito"
head( Samples, n=10)
ALERT: If you received an error message with some like
Warning message:
In `[<-.factor`(`*tmp*`, 10, value = c(30L, 32L, 29L, 19L, 20L, :
invalid factor level, NA generated
It is because the read.csv()
function has a default value that converts any column with a character
variable type into a factor
data type… This is a stupid default option and you should change the default value in your R
options file - To fix this issue, see r environment for or remember that every time you load in data, you must add the optional argument stringsAsFactors=FALSE
to the read.csv()
function call.
Samples <- read.csv(url, stringAsFactors=FALSE)
Run that and try to replace the Stratum name as above.
Slices
Just like for vectors, we can also take slices of components from data.frame
objects. However, what we get in return depends on specifically what we ask for.
For example, taking from a single column in the data.frame
returns a slice of that particular variable type.
x <- Samples[1:3, 1]
x
[1] "88" "9" "84"
88
9
84
class(x)
[1] "character"
character
This is because all the returned values are from a single data column, which by definition must be the same kind of data.
You can ask R
to return it as a data.frame
rather than just a vector (in case you need to have a data.frame to work with) by passing an optional argument to the square brackets. You will notice it retains the row numbers.
x1 <- Samples[ 1:3, 1, drop=FALSE]
x1
class(x1)
[1] "data.frame"
data.frame
However, if we take the same number of object but from a row instead of a column, we can only get a data.frame
object in return.
y <- Samples[1, 1:3]
y
class(y)
[1] "data.frame"
data.frame
because this time, we are asking for the three variables representing the first record. Because these values are being drawn from across different columns of data, R
does not concatenate these into a single vector and coearce them to the least common data type. Rather it makes a new data.frame
object for you and returns that.
Modifying Existing Data Frames
Once we have a data.frame
in memory, we can also add to it. If we are adding columns, we can append a single varible onto it and R
will put it on the far right side of the data.frame
.
Samples$ID <- 1:nrow(Samples)
summary( Samples )
Stratum Longitude Latitude ID
Length:39 Min. :-114.3 Min. :23.08 Min. : 1.0
Class :character 1st Qu.:-112.9 1st Qu.:24.52 1st Qu.:10.5
Mode :character Median :-111.5 Median :26.21 Median :20.0
Mean :-111.7 Mean :26.14 Mean :20.0
3rd Qu.:-110.4 3rd Qu.:27.47 3rd Qu.:29.5
Max. :-109.1 Max. :29.33 Max. :39.0
If we want to add rows to the data.frame
, it is a bit more involved because we are going to have to either a list object whose variables are of the same order as the original data.frame
or anoher entire data.frame
(whose names are identical to the original)
names(Samples)
[1] "Stratum" "Longitude" "Latitude" "ID"
Stratum
Longitude
Latitude
ID
To add a single row, we use rbind()
and pass it the data.frame
and a new list object.
Samples <- rbind( Samples, list("Los Cabos",-109.7124, 23.0799, 40))
tail(Samples)
You can also use another data.frame
, which in this case must have the same named varaibles as the original.
moresites <- data.frame( ID = 41:42,
Stratum = c("Los Barriles","Comondu"),
Longitude = c(-109.7026, -111.8442),
Latitude = c(23.6811, 26.0708)
)
names(moresites)
[1] "ID" "Stratum" "Longitude" "Latitude"
ID
Stratum
Longitude
Latitude
However, notice that the order in which these varaibles in moresites
is different than those in Samples
. The rbind()
function rearranges the order when it concatenates onto the rows.
Samples <- rbind( Samples, moresites)
tail( Samples )
To delete a column of data, assign it the value of NULL
.
Samples$ID <- NULL
summary(Samples)
Stratum Longitude Latitude
Length:42 Min. :-114.3 Min. :23.08
Class :character 1st Qu.:-112.8 1st Qu.:24.28
Mode :character Median :-111.5 Median :26.04
Mean :-111.6 Mean :26.01
3rd Qu.:-110.3 3rd Qu.:27.39
Max. :-109.1 Max. :29.33
or use negative indices to delete rows.
Samples <- Samples[ -42:-40, ]
summary(Samples)
Stratum Longitude Latitude
Length:39 Min. :-114.3 Min. :23.08
Class :character 1st Qu.:-112.9 1st Qu.:24.52
Mode :character Median :-111.5 Median :26.21
Mean :-111.7 Mean :26.14
3rd Qu.:-110.4 3rd Qu.:27.47
Max. :-109.1 Max. :29.33
The data.frame
object is a fundamental component of your R
work flow and being able to manipulate data within it and extract data from it are a huge part of becoming data literate.
LS0tCnRpdGxlOiAiRGF0YSBGcmFtZXMiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIGNzczogImVudnM1NDMtc3R5bGVzLmNzcyIKLS0tCgo+IERhdGEgZnJhbWVzIGFyZSBhIHN0cnVjdHVyZSB0aGF0IGNhbiBob2xkIG1hbnkgZGlmZmVyZW50IGRhdGEgdHlwZXMgaW4gb25lIHNpbXBsZSBzdHJ1Y3R1cmUuCgpEYXRhIGZyYW1lcyBhcmUgdGhlICpsaW5ndWEgZnJhbmNhKiBmb3IgYFJgLCBlc3BlY2lhbGx5IG9uY2Ugd2Ugc3RhcnQgZ2V0dGluZyBpbnRvIG1vcmUgY29tcGxpY2F0ZWQgYW5hbHlzaXMgYW5kIG1hbmlwdWxhdGlvbi4gIEZvciBzaW1wbGljaXR5LCBvbmUgY2FuIGNvbnNpZGVyIGEgYGRhdGEuZnJhbWVgIG9iamVjdCBtdWNoIGxpa2UgYSBzcHJlYWRzaGVldC4gIEVhY2ggcm93IHJlcHJlc2VudHMgYSByZWNvcmQgb24gc29tZSBvYmplY3QgYW5kIGVhY2ggY29sdW1u4oCUY29uc2lzdGluZyBvZiBkaWZmZXJlbnQga2luZHMgb2YgZGF0YeKAlGFyZSBtZWFzdXJlbWVudHMgb24gdGhhdCBvYmplY3QuICAKCkJ5IGluIGxhcmdlLCB5b3Ugd2lsbCBsb2FkIHlvdXIgZGF0YSBpbnRvIHRoZXNlIHN0cnVjdHVyZXMgYW5kIHBhc3MgdGhlbSB0byBmdW5jdGlvbnMgZm9yIHBsb3R0aW5nLCBzaW11bGF0aW9uLCBwbG90dGluZywgZXRjLiAgSXQgaXMgYSBnb29kIGlkZWEgdG8gZ2V0IHVzZWQgdG8gdGhlc2UuCgoKIyMgQ3JlYXRpbmcgYGRhdGEuZnJhbWVgIE9iamVjdHMKClRvIG1ha2UgYSBgZGF0YS5mcmFtZWAgd2UgbmVlZCB0byBlaXRoZXI6CgogIDEuIE1ha2UgaXQgZnJvbSBzY3JhdGNoIHVzaW5nIHZlY3RvcnMgKHRoZSBtb3JlIGNvbXBsaWNhdGVkKS4KICAyLiBMb2FkIGl0IGZyb20gYSBmaWxlIChwZXJoYXBzIHRoZSBlYXNpZXN0IHdheSkuCgpXZSBzaGFsbCBzdGFydCB3aXRoIHRoZSBtb3N0IGNvbXBsaWNhdGVkIGNhc2UuICAKCiMjIyBDcmVhdGluZyBgZGF0YS5mcmFtZWAgT2JqZWN0cyAqZGUgbm92byoKCmBgYHtyfQpzaXRlIDwtIGMoICJDb25zdCIsIkVTYW4iLCAiQXF1IikKbG9uZ2l0dWRlIDwtIGMoIC0xMTEuNjc1LCAtMTEwLjM2ODYsIC0xMTAuMTA0MykKbGF0aXR1ZGUgPC0gYygyNS4wMjQ3LCAyNC40NTg3OSwgMjMuMjg1NSkKCnNpdGVzIDwtIGRhdGEuZnJhbWUoIFNpdGUgPSBzaXRlLAogICAgICAgICAgICAgICAgICAgICBMb25naXR1ZGUgPSBsb25naXR1ZGUsCiAgICAgICAgICAgICAgICAgICAgIExhdGl0dWRlID0gbGF0aXR1ZGUgKQpzaXRlcwpgYGAKClRoZSB0aGluZyBhYm91dCBgZGF0YS5mcmFtZWAgb2JqZWN0cyBpcyB0aGF0IHRoZSBrbm93IGhvdyB0byBvcmdhbml6ZSBhbmQgc3VtbWFyaXplIHRoZWlyIGNvbXBvbmVudCB2YXJpYWJsZXMuCgpgYGB7cn0Kc3VtbWFyeShzaXRlcykKYGBgCgpOb3RpY2UgdGhhdCBlYWNoIHZhcmlhYmxlIGlzIHN1bW1hcml6ZWQgYSB3YXkgdGhhdCBnaXZlcyBhcyBtdWNoIGluZm9ybWF0aW9uIGFib3V0IHRoZSBjb250bmV0cyBvZiB0aGF0IHZhcmlhYmxlLiBUaGUgYHN1bW1hcnkoKWAgZnVuY3Rpb24gaXMgY3JpdGljYWwgYW5kIG9uZSB3ZSB3aWxsIHVzZSBvdmVyIGFuZCBvdmVyIGFnYWluLgoKIyMjIExvYWRpbmcgZnJvbSBGaWxlIGFuZC9vciBVUkwKCllvdSBjYW4gYWxzbyBsb2FkIGEgYGRhdGEuZnJhbWVgIGluIHVzaW5nIGEgbG9jYWwgZmlsZSBvciBhIFVSTCB0byBhIGZpbGUgc29tZXdoZXJlIG9uIHRoZSBpbnRlcm5ldC4gIFRoZSBlYXNpZXN0IHdheSB0byBkbyB0aGlzIGlzIHRvIGhhdmUgeW91ciBmaWxlIGFzIGEgQ1NWIChDb21tYS1TZXBhcmF0ZWQtVmFsdWUpIGZvcm1hdC4gIFRoaXMgaXMgdXN1YWxseSBhICRGaWxlIFx0byBTYXZlXDtBcyQga2luZCBvZiByb3V0aW5lLiAgSXQgaXMgaW1wb3J0YW50IGZvciByZXByb2R1Y2liaWxpdHkgYW5kIGNvbGxhYm9yYXRpb24gdG8gMSkgSGF2ZSBvbmx5IG9uZSB2ZXJzaW9uIG9mIHlvdXIgZGF0YSBzZXQsIGFuZCAyKSBLZWVwIGl0IGluIGEgZm9ybWF0IHRoYXQgaXMgYWNjZXNzaWJsZSBzdWNoIGFzIHBsYWluIHRleHQuCgpIZXJlIGlzIHRoZSBmdWxsIHZlcnNpb24gb2YgdGhvc2UgZGF0YSBsb2FkZWQgYWJvdmUuICBJdCBpcyBsb2NhdGVkIG9uIGEgW0dpdGh1Yl0oaHR0cHM6Ly9naXRodWIuY29tL2R5ZXJsYWIvRU5WUy1MZWN0dXJlcykgd2Vic2l0ZSBhbmQgaXMgYWNjZXNzaWJsZSB0byBhbnlvbmUgd2l0aCBhbiBpbnRlcm5ldCBjb25uZWN0aW9uLgoKYGBge3J9CnVybCA8LSAiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2R5ZXJsYWIvRU5WUy1MZWN0dXJlcy9tYXN0ZXIvZGF0YS9hcmFwYXQuY3N2IgpgYGAKCk9uY2Ugd2UgaGF2ZSB0aGUgdXJsIG9yIGZpbGUgYXMgYSBgY2hhcmFjdGVyYCBvYmplY3QsIHdlIGNhbiB1c2UgdGhlIGJ1aWx0LWluIGByZWFkLmNzdigpYCBmdW5jdGlvbiB0byBsb2FkIHRoZSBkYXRhIGludG8gYSBsb2NhbCB2YXJpYWJsZS4gIEhlcmUgaXMgd2hhdCB0aGF0IGxvb2tzIGxpa2UuCgpgYGB7cn0KU2FtcGxlcyA8LSByZWFkLmNzdih1cmwpCnN1bW1hcnkoIFNhbXBsZXMgKQpgYGAKCgoKIyMgV29ya2luZyB3aXRoIGBkYXRhLmZyYW1lYCBPYmplY3RzCgpBIHZhcmlhYmxlIHJlcHJlc2VudGluZyBhIGBkYXRhLmZyYW1lYCBoYXMgcHJvcGVydGllcyBhbmQgY29uc3RpdHVlbnRzIGp1c3QgbGlrZSBhIHZlY3Rvci4gIFRoZSBzaXplIG9mIHRoZSBgZGF0YS5mcmFtZWAgaXMgZGVmaW5lZCBhcyB0aGUgYGRpbWBlbnNpb25zIG9mIGl0IGFuZCByZXByZXNlbnRzIHRoZSBudW1iZXIgb2YgKnJvd3MqIGFuZCAqY29sdW1ucyogaXQgY29udGFpbnMuCgpgYGB7cn0KbnJvdyggU2FtcGxlcyApCm5jb2woIFNhbXBsZXMgKQpgYGAKCm9yIHVzZSB0aGUgYGRpbSgpYCBmdW5jdGlvbiB3aGljaCByZXR1cm5zIGJvdGggb2YgdGhlbS4KCmBgYHtyfQpkaW0oIFNhbXBsZXMgKQpgYGAKCgpFYWNoIHZhcmlhYmxlIHdpdGhpbiB0aGUgYGRhdGEuZnJhbWVgIGlzIHJlcHJlc2VudGVkIGJ5IHRoZSBuYW1lIHdlIGdhdmUgaXQgd2hlbiB3ZSBhZGRlZCBpdCB0byB0aGUgYGRhdGEuZnJhbWVgLgoKYGBge3J9Cm5hbWVzKCBTYW1wbGVzICkKYGBgCgpUaGUgaW5kaXZpZHVhbCBlbGVtZW50cyBhcmUgYXZhaWxhYmxlIHVzaW5nIHRoZSBzcXVhcmUgYnJhY2tldCBub3RhdGlvbiwganVzdCBsaWtlIGZvciBbdmVjdG9yc10oLi4vdmVjdG9ycy9uYXJyaWF0aXZlLm5iLmh0bWwpICp3aXRoIHRoZSBleGNlcHRpb24gdGhhdCogd2UgaGF2ZSB0d28gY29vcmRpbmF0ZXMgaW5zdGVhZCBvZiBqdXN0IG9uZS4gIFRoZSBmaXJzdCBjb29yZGluYXRlIGlzIGZvciAqcm93KiBhbmQgdGhlIHNlY29uZCBpcyBmb3IgKmNvbHVtbiouICBTbyB0byBncmFiIHRoZSAxMCRee3RofSQgYFN0cmF0dW1gIG5hbWUgKHJvdyksIHdoaWNoIGlzIHRoZSAxJF57c3R9JCB2YXJpYWJsZSAoY29sdW1uKSBpbiB0aGUgYGRhdGEuZnJhbWVgLCB3ZSB1c2U6CgpgYGB7cn0KU2FtcGxlc1sxMCwxXQpgYGAKCldoaWxlIHRoaXMgaXMgT0ssIGl0IGFzc3VtZXMgd2UgcmVtZW1iZXIgdGhhdCB0aGUgYFN0cmF0dW1gIHZhcmlhYmxlIGlzIHRoZSBmaXJzdCB2YXJpYWJsZSBpbiB0aGUgYGRhdGEuZnJhbWVgLiAgSWYgeW91IGhhdmUgZGF0YSBzZXRzIHdpdGggdGhvdXNhbmRzIG9mIGNvbHVtbnMgb2YgZGF0YSBpbiB0aGVtLCBpdCBiZWNvbWVzIGxlc3MtdGhhbi1vcHRpbWFsIHRvIHVzZSB2YXJpYWJsZSBudW1iZXJzIHRvIGluZGV4LCB3aGljaCBpcyB3aHkgd2UgY2FuIHVzZSB0aGUgdmFyaWFibGUgbmFtZSBpdHNlbGYgaW4gdGhlIGZvbGxvd2luZyBmb3JtYXQuCgpgYGB7cn0KU2FtcGxlcyRTdHJhdHVtWzEwXQpgYGAKCkhlcmUsIHdlIHVzZSB0aGUgbmFtZSBvZiB0aGUgYGRhdGEuZnJhbWVgIGNvbm5lY3RlZCB0byB0aGUgbmFtZSBvZiB0aGUgdmFyaWFibGUgdXNpbmcgdGhlIGRvbGxhciBzaWduIChcJCkgdG8gaG9vayB0aGVtIHVwLiAgCgo8ZGl2IGNsYXNzPSJib3gteWVsbG93Ij5Gb3IgcmVhZGFiaWxpdHksIGl0IGlzIGFkdmlzZWQgdGhhdCB5b3UgdXNlIHRoZSBkb2xsYXItc2lnbiBub3RhdGlvbiB0byBnZXQgYW5kIHNldCB2YWx1ZXMgd2l0aGluIGEgYGRhdGEuZnJhbWVgLiAgSXQgd2lsbCBhbHdheXMgYmUgbW9yZSBjbGVhciB0byB5b3UgYW5kIGFueW9uZSB3aG8gcmVhZHMgeW91ciBjb2RlIGlmIHlvdSBhcmUgYXMgdmVyYm9zZSBhcyB5b3UgY2FuIGJlIGluIHlvdXIgY29kZS4gIFRydXN0IG1lLCB5b3VyICpmdXR1cmUgc2VsZiogd2lsbCBsaWtlIHlvdSBtdWNoIGJldHRlciBpZiB5b3UgYWRvcHQgdGhpcyBoYWJpdCBhcyBzb29uIGFzIHBvc3NpYmxlLjwvZGl2PgoKClNpbWlsYXIgdG8gZm9yIFt2ZWN0b3JzXSguLi92ZWN0b3JzL25hcnJpYXRpdmUubmIuaHRtbCksIHdlIGNhbiBncmFiIHRoZSBoZWFkIGFuZCB0YWlsIG9mIHRoZSB3aG9sZSBkYXRhIGZyYW1lLgoKYGBge3J9CmhlYWQoIFNhbXBsZXMgKQpgYGAKCmBgYHtyfQp0YWlsKFNhbXBsZXMsIG49NCkKYGBgCgoKV2UgY2FuIHVzZSB0aGUgc2FtZSBhcHByb2FjaCBmb3Igc2V0dGluZyB2YWx1ZXMgd2l0aGluIGEgYGRhdGEuZnJhbWVgLiAgSGVyZSBJJ2xsIGV4cGFuZCB0aGUgKlNGciogbm90aW9uIHRvIHJlcHJlc2VudCB0aGUgZnVsbCBsb2NhdGlvbiBuYW1lLgoKYGBge3J9ClNhbXBsZXMkU3RyYXR1bVsxMF0gPC0gIlNhbiBGcmFuY2lzcXVpdG8iCmhlYWQoIFNhbXBsZXMsIG49MTApCmBgYAoKPGRpdiBjbGFzcz0iYm94LXJlZCI+CioqQUxFUlQ6KiogIElmIHlvdSByZWNlaXZlZCBhbiBlcnJvciBtZXNzYWdlIHdpdGggc29tZSBsaWtlIApgYGAKV2FybmluZyBtZXNzYWdlOgpJbiBgWzwtLmZhY3RvcmAoYCp0bXAqYCwgMTAsIHZhbHVlID0gYygzMEwsIDMyTCwgMjlMLCAxOUwsIDIwTCwgIDoKICBpbnZhbGlkIGZhY3RvciBsZXZlbCwgTkEgZ2VuZXJhdGVkCmBgYApJdCBpcyBiZWNhdXNlIHRoZSBgcmVhZC5jc3YoKWAgZnVuY3Rpb24gaGFzIGEgZGVmYXVsdCB2YWx1ZSB0aGF0IGNvbnZlcnRzIGFueSBjb2x1bW4gd2l0aCBhIGBjaGFyYWN0ZXJgIHZhcmlhYmxlIHR5cGUgaW50byBhIGBmYWN0b3JgIGRhdGEgdHlwZS4uLiAgVGhpcyBpcyBhICoqc3R1cGlkKiogZGVmYXVsdCBvcHRpb24gYW5kIHlvdSBzaG91bGQgY2hhbmdlIHRoZSBkZWZhdWx0IHZhbHVlIGluIHlvdXIgYFJgIG9wdGlvbnMgZmlsZSAtIFRvIGZpeCB0aGlzIGlzc3VlLCBzZWUgW3IgZW52aXJvbm1lbnRdKC4uL2Vudmlyb25tZW50L25hcnJpYXRpdmUubmIuaHRtbCkgZm9yIG9yIHJlbWVtYmVyIHRoYXQgKmV2ZXJ5IHRpbWUgeW91IGxvYWQgaW4gZGF0YSosIHlvdSBtdXN0IGFkZCB0aGUgb3B0aW9uYWwgYXJndW1lbnQgYHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0VgIHRvIHRoZSBgcmVhZC5jc3YoKWAgZnVuY3Rpb24gY2FsbC4KCmBgYHtyIGV2YWw9RkFMU0V9ClNhbXBsZXMgPC0gcmVhZC5jc3YodXJsLCBzdHJpbmdBc0ZhY3RvcnM9RkFMU0UpCmBgYAoKUnVuIHRoYXQgYW5kIHRyeSB0byByZXBsYWNlIHRoZSBTdHJhdHVtIG5hbWUgYXMgYWJvdmUuCjwvZGl2PgoKCgojIyMgU2xpY2VzCgpKdXN0IGxpa2UgZm9yIFt2ZWN0b3JzXSguLi92ZWN0b3JzL25hcnJpYXRpdmUubmIuaHRtbCksIHdlIGNhbiBhbHNvIHRha2Ugc2xpY2VzIG9mIGNvbXBvbmVudHMgZnJvbSBgZGF0YS5mcmFtZWAgb2JqZWN0cy4gIEhvd2V2ZXIsIHdoYXQgd2UgZ2V0IGluIHJldHVybiBkZXBlbmRzIG9uIHNwZWNpZmljYWxseSB3aGF0IHdlIGFzayBmb3IuICAKCkZvciBleGFtcGxlLCB0YWtpbmcgZnJvbSBhIHNpbmdsZSBjb2x1bW4gaW4gdGhlIGBkYXRhLmZyYW1lYCByZXR1cm5zIGEgc2xpY2Ugb2YgdGhhdCBwYXJ0aWN1bGFyIHZhcmlhYmxlIHR5cGUuCgpgYGB7cn0KeCA8LSBTYW1wbGVzWzE6MywgMV0KeApjbGFzcyh4KQpgYGAKClRoaXMgaXMgYmVjYXVzZSBhbGwgdGhlIHJldHVybmVkIHZhbHVlcyBhcmUgZnJvbSBhIHNpbmdsZSBkYXRhIGNvbHVtbiwgd2hpY2ggYnkgZGVmaW5pdGlvbiAqbXVzdCogYmUgdGhlIHNhbWUga2luZCBvZiBkYXRhLiAgCgpZb3UgY2FuIGFzayBgUmAgdG8gcmV0dXJuIGl0IGFzIGEgYGRhdGEuZnJhbWVgIHJhdGhlciB0aGFuIGp1c3QgYSB2ZWN0b3IgKGluIGNhc2UgeW91IG5lZWQgdG8gaGF2ZSBhIGRhdGEuZnJhbWUgdG8gd29yayB3aXRoKSBieSBwYXNzaW5nIGFuIG9wdGlvbmFsIGFyZ3VtZW50IHRvIHRoZSBzcXVhcmUgYnJhY2tldHMuICBZb3Ugd2lsbCBub3RpY2UgaXQgcmV0YWlucyB0aGUgcm93IG51bWJlcnMuCgpgYGB7cn0KeDEgPC0gU2FtcGxlc1sgMTozLCAxLCBkcm9wPUZBTFNFXQp4MQpjbGFzcyh4MSkKYGBgCgoKSG93ZXZlciwgaWYgd2UgdGFrZSB0aGUgc2FtZSBudW1iZXIgb2Ygb2JqZWN0IGJ1dCBmcm9tIGEgcm93IGluc3RlYWQgb2YgYSBjb2x1bW4sIHdlIGNhbiAqb25seSogZ2V0IGEgYGRhdGEuZnJhbWVgIG9iamVjdCBpbiByZXR1cm4uCgpgYGB7cn0KeSA8LSBTYW1wbGVzWzEsIDE6M10KeQpjbGFzcyh5KQpgYGAKCmJlY2F1c2UgdGhpcyB0aW1lLCB3ZSBhcmUgYXNraW5nIGZvciB0aGUgdGhyZWUgdmFyaWFibGVzIHJlcHJlc2VudGluZyB0aGUgZmlyc3QgcmVjb3JkLiAgQmVjYXVzZSB0aGVzZSB2YWx1ZXMgYXJlIGJlaW5nIGRyYXduIGZyb20gYWNyb3NzIGRpZmZlcmVudCBjb2x1bW5zIG9mIGRhdGEsIGBSYCBkb2VzIG5vdCBjb25jYXRlbmF0ZSB0aGVzZSBpbnRvIGEgc2luZ2xlIHZlY3RvciBhbmQgY29lYXJjZSB0aGVtIHRvIHRoZSBsZWFzdCBjb21tb24gZGF0YSB0eXBlLiBSYXRoZXIgaXQgbWFrZXMgYSBuZXcgYGRhdGEuZnJhbWVgIG9iamVjdCBmb3IgeW91IGFuZCByZXR1cm5zIHRoYXQuCgoKIyMjIE1vZGlmeWluZyBFeGlzdGluZyBEYXRhIEZyYW1lcwoKT25jZSB3ZSBoYXZlIGEgYGRhdGEuZnJhbWVgIGluIG1lbW9yeSwgd2UgY2FuIGFsc28gYWRkIHRvIGl0LiAgSWYgd2UgYXJlIGFkZGluZyBjb2x1bW5zLCB3ZSBjYW4gYXBwZW5kIGEgc2luZ2xlIHZhcmlibGUgb250byBpdCBhbmQgYFJgIHdpbGwgcHV0IGl0IG9uIHRoZSBmYXIgcmlnaHQgc2lkZSBvZiB0aGUgYGRhdGEuZnJhbWVgLgoKYGBge3J9ClNhbXBsZXMkSUQgPC0gMTpucm93KFNhbXBsZXMpCnN1bW1hcnkoIFNhbXBsZXMgKQpgYGAKCgpJZiB3ZSB3YW50IHRvIGFkZCByb3dzIHRvIHRoZSBgZGF0YS5mcmFtZWAsIGl0IGlzIGEgYml0IG1vcmUgaW52b2x2ZWQgYmVjYXVzZSB3ZSBhcmUgZ29pbmcgdG8gaGF2ZSB0byBlaXRoZXIgYSBsaXN0IG9iamVjdCB3aG9zZSB2YXJpYWJsZXMgYXJlIG9mIHRoZSBzYW1lIG9yZGVyIGFzIHRoZSBvcmlnaW5hbCBgZGF0YS5mcmFtZWAgb3IgYW5vaGVyIGVudGlyZSBgZGF0YS5mcmFtZWAgKHdob3NlIG5hbWVzIGFyZSBpZGVudGljYWwgdG8gdGhlIG9yaWdpbmFsKQoKYGBge3J9Cm5hbWVzKFNhbXBsZXMpCmBgYAoKVG8gYWRkIGEgc2luZ2xlIHJvdywgd2UgdXNlIGByYmluZCgpYCBhbmQgcGFzcyBpdCB0aGUgYGRhdGEuZnJhbWVgIGFuZCBhIG5ldyBbbGlzdF0oLi4vbGlzdHMvbmFycmlhdGl2ZS5uYi5odG1sKSBvYmplY3QuCgpgYGB7cn0KU2FtcGxlcyA8LSByYmluZCggU2FtcGxlcywgbGlzdCgiTG9zIENhYm9zIiwtMTA5LjcxMjQsIDIzLjA3OTksIDQwKSkKdGFpbChTYW1wbGVzKQpgYGAKCllvdSBjYW4gYWxzbyB1c2UgYW5vdGhlciBgZGF0YS5mcmFtZWAsIHdoaWNoIGluIHRoaXMgY2FzZSBtdXN0IGhhdmUgdGhlIHNhbWUgbmFtZWQgdmFyYWlibGVzIGFzIHRoZSBvcmlnaW5hbC4gIAoKYGBge3J9Cm1vcmVzaXRlcyA8LSBkYXRhLmZyYW1lKCBJRCA9IDQxOjQyLAogICAgICAgICAgICAgICAgICAgICAgICAgU3RyYXR1bSA9IGMoIkxvcyBCYXJyaWxlcyIsIkNvbW9uZHUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgIExvbmdpdHVkZSA9IGMoLTEwOS43MDI2LCAtMTExLjg0NDIpLAogICAgICAgICAgICAgICAgICAgICAgICAgTGF0aXR1ZGUgPSBjKDIzLjY4MTEsIDI2LjA3MDgpIAogICAgICAgICAgICAgICAgICAgICAgICAgKQpuYW1lcyhtb3Jlc2l0ZXMpCmBgYAoKSG93ZXZlciwgbm90aWNlIHRoYXQgdGhlIG9yZGVyIGluIHdoaWNoIHRoZXNlIHZhcmFpYmxlcyBpbiBgbW9yZXNpdGVzYCBpcyBkaWZmZXJlbnQgdGhhbiB0aG9zZSBpbiBgU2FtcGxlc2AuICBUaGUgYHJiaW5kKClgIGZ1bmN0aW9uIHJlYXJyYW5nZXMgdGhlIG9yZGVyIHdoZW4gaXQgY29uY2F0ZW5hdGVzIG9udG8gdGhlIHJvd3MuCgpgYGB7cn0KU2FtcGxlcyA8LSByYmluZCggU2FtcGxlcywgbW9yZXNpdGVzKQp0YWlsKCBTYW1wbGVzICkKYGBgCgpUbyBkZWxldGUgYSBjb2x1bW4gb2YgZGF0YSwgYXNzaWduIGl0IHRoZSB2YWx1ZSBvZiBgTlVMTGAuCgpgYGB7cn0KU2FtcGxlcyRJRCA8LSBOVUxMCnN1bW1hcnkoU2FtcGxlcykKYGBgCgpvciB1c2UgbmVnYXRpdmUgaW5kaWNlcyB0byBkZWxldGUgcm93cy4KCmBgYHtyfQpTYW1wbGVzIDwtIFNhbXBsZXNbIC00MjotNDAsIF0Kc3VtbWFyeShTYW1wbGVzKQpgYGAKCi0tLQoKVGhlIGBkYXRhLmZyYW1lYCBvYmplY3QgaXMgYSBmdW5kYW1lbnRhbCBjb21wb25lbnQgb2YgeW91ciBgUmAgd29yayBmbG93IGFuZCBiZWluZyBhYmxlIHRvIG1hbmlwdWxhdGUgZGF0YSB3aXRoaW4gaXQgYW5kIGV4dHJhY3QgZGF0YSBmcm9tIGl0IGFyZSBhIGh1Z2UgcGFydCBvZiBiZWNvbWluZyBkYXRhIGxpdGVyYXRlLgoKCgoKCgoKCgoKCgoKCgoKCgoK