Melting and Casting
Why Reshape Your Data
Reshape2 is a package that allows us to easily transform our data into whatever structure we may need. Many of us are used to seeing our data structured so that corresponds to a single participant and each column corresponds to a variable. This type of data structure is known as wide format. However, many of the packages in R require that we stretch our data so that a single participant may occupy multiple rows. This type of data structure is known as long format. For example, ggplot2
and some data analysis functions require long format. Any of you who have tried to restructure their data using Excel or SPSS will immediately recognize the immense power of this package. Therefore, without further ado, let’s get to it.
As a quick note, this tutorial will be heavily based around learning from examples. Therefore, I strongly encourage you to follow along with the example data and code provided below. Before we can begin our demonstration, it will be helpful to clear our environment, set our working directory, load the necessary packages, and take a quick glance at the description of melting and casting as described by the wonderous RStudio helper window.
So please, join me on this magical journey by running the code below.
#First, remove all your stuff
rm(list=ls())
#Make sure to set your working directory
#setwd("PATH")
#Next, you need to download and install the reshape pachage
#install.packages("reshape2")
library(reshape2)
R Help
Running the following code will give you the description of the reshape2 package
?melt
#or
?cast
Data Frame
Great job! Now, we need a dataframe to play with. The code below will create one for you with two within-subjects factors and one between subjects factor.
#Creating a toy data set to melt
## Run everything below TOGETHER
ID<-c(1:6) #Creating an ID variable for 6 participants
set.seed(66) #Setting a seed so we can all have the same values
WTN1<-runif(6, min = 1, max = 7) #Creating a within-Subjects variable
set.seed(16) #Setting a seed so we can all have the same values
WTN2<-runif(6, min = 1, max = 7) #Creating a within-Subjects variable
BTW<- replicate(3,1:2, simplify = T) #Creating a between subjects variable
BTW<-as.vector(BTW) #Turning between-Subjects variable into a vector
mind<-cbind.data.frame(ID, WTN1, WTN2, BTW) #Combining variables into a dataframe
#mind$BTW<-as.factor(mind$BTW) #Turning between-subjects variable into a factor
#mind$ID<-as.factor(mind$I) #Turning ID into a factor
mind #Let's view this data set
## ID WTN1 WTN2 BTW
## 1 1 6.939619 5.098660 1
## 2 2 5.978156 2.464705 2
## 3 3 4.515321 3.700668 1
## 4 4 3.502277 2.376611 2
## 5 5 4.972581 6.181047 1
## 6 6 3.275813 2.867202 2
str(mind)
## 'data.frame': 6 obs. of 4 variables:
## $ ID : int 1 2 3 4 5 6
## $ WTN1: num 6.94 5.98 4.52 3.5 4.97 ...
## $ WTN2: num 5.1 2.46 3.7 2.38 6.18 ...
## $ BTW : int 1 2 1 2 1 2
Melting
Below is the generic code for melt
ing.
#This is commented out so that the generic code does not run
#melt(data, ..., na.rm = FALSE, value.name = "value")
Ok, now that we have a dataframe, let’s melt
the sucker!
#Melt your mind!
melt.mind<-melt(mind)
head(melt.mind) #Look at this!
## variable value
## 1 ID 1
## 2 ID 2
## 3 ID 3
## 4 ID 4
## 5 ID 5
## 6 ID 6
tail(melt.mind) #Look at that!
## variable value
## 19 BTW 1
## 20 BTW 2
## 21 BTW 1
## 22 BTW 2
## 23 BTW 1
## 24 BTW 2
Explanation
So what just happened?
The melt function took our dataframe that had a column for each variable, and created a dataframe with only TWO columns: One column named variable
and one column named value
.
As psychologists, we are often used to seeing things in wide format because SPSS defaults to wide format.
Wide format has a column for each variable, and every row is an instance of the variable participant, that is, each row represents one participant.
However, it is often useful, even occasionally necessary, to stretch out the dataframe so that each row is an instance of a different variable. But what does that mean?
When we melt
ed the dataframe mind
, we told R that we wanted each row to be a single instance of a value. In order to do that, we needed to collapse across all other variables into the new variables: variable
and value
. We stretched out our dataset so that it was longer, or into long format.
In long format, each row no longer represents a single participant. In our example, each participant was stretched into four rows, one row for each variable: one between-subjects variable, one ID
variable, and two within-subjects variables.
But what if we wanted to maintain some other columns? For example, what if we wanted ID
and our between-subjects variable BTW
to be, well, between-subjects?
melt.mind2<-melt(mind, id=c("ID","BTW"))
melt.mind2 #Look at this!
## ID BTW variable value
## 1 1 1 WTN1 6.939619
## 2 2 2 WTN1 5.978156
## 3 3 1 WTN1 4.515321
## 4 4 2 WTN1 3.502277
## 5 5 1 WTN1 4.972581
## 6 6 2 WTN1 3.275813
## 7 1 1 WTN2 5.098660
## 8 2 2 WTN2 2.464705
## 9 3 1 WTN2 3.700668
## 10 4 2 WTN2 2.376611
## 11 5 1 WTN2 6.181047
## 12 6 2 WTN2 2.867202
In the melt
function, you can specify your ID
, or between-subjects variables, as in the previous line of code. R is smart and will assume all other variables are to be collapsed into each other.
By specifying that ID
and BTW
were between-subjects variables, we told R that we wanted our dataset structured so that each row is an instance of one of the within-subjects variables. This means that we now have two rows per subject because each subject experienced both of the levels of the within-subjects variable. Neat, right?
Now, what if we wanted to name our within-subjects variable to something other than variable
? Try this…
melt.mind3<-melt(mind,id=c("ID","BTW"),
variable.name = "WTN")
melt.mind3 #Look at that!
## ID BTW WTN value
## 1 1 1 WTN1 6.939619
## 2 2 2 WTN1 5.978156
## 3 3 1 WTN1 4.515321
## 4 4 2 WTN1 3.502277
## 5 5 1 WTN1 4.972581
## 6 6 2 WTN1 3.275813
## 7 1 1 WTN2 5.098660
## 8 2 2 WTN2 2.464705
## 9 3 1 WTN2 3.700668
## 10 4 2 WTN2 2.376611
## 11 5 1 WTN2 6.181047
## 12 6 2 WTN2 2.867202
As you can see, all we needed to do was specify that we would name our variable with the command variable.name
. Easy-peasy!
And if we also wanted to name our values
?
melted.mind<-melt(mind,id=c("ID","BTW"),
variable.name = "WTN",
value.name = "Results")
head(melted.mind) #Look at this!
## ID BTW WTN Results
## 1 1 1 WTN1 6.939619
## 2 2 2 WTN1 5.978156
## 3 3 1 WTN1 4.515321
## 4 4 2 WTN1 3.502277
## 5 5 1 WTN1 4.972581
## 6 6 2 WTN1 3.275813
tail(melted.mind) #Look at that!
## ID BTW WTN Results
## 7 1 1 WTN2 5.098660
## 8 2 2 WTN2 2.464705
## 9 3 1 WTN2 3.700668
## 10 4 2 WTN2 2.376611
## 11 5 1 WTN2 6.181047
## 12 6 2 WTN2 2.867202
Cool cool cool. We’ve sucessfully melt
ed our mind
in a way that we’d like. Our data is structured so that each row represents an instance of the within-subjects variable, WTN
, and we’ve maintained the variables ID
and BTW
. Now, let’s continue this magical journey onto the wondrous land of cast
ing.
Casting
Cast
ing will transform long format back into wide format. This will, essentially, make your data look as it did in the beginning (or in any other way you’d prefer).
There are multiple cast
functions depending on the structures of your data. If you want to cast
your data into a dataframe, use dcast
, and if you want to cast
your data into vector/matrix/arry, then use acast
.
Because we will be working with a dataframe, we will use dcast
. The generic code for both types is below.
#These have been commented out so that they do not run.
#dcast(data, formula, fun.aggregate = NULL, ..., margins = NULL,
# subset = NULL, fill = NULL, drop = TRUE,
# value.var = guess_value(data))
#acast(data, formula, fun.aggregate = NULL, ..., margins = NULL,
# subset = NULL, fill = NULL, drop = TRUE,
# value.var = guess_value(data))
Before we begin, it’s important to note that cast
ing is much more challenging than melt
ing. This may often take some trial and error, and you should not feel bad about that. Just remember: You’re awesome. Feeling good about yourself? Good. Good.
Now, let’s cast
our data
cast.mind<-dcast(melted.mind, ID+BTW~WTN)
cast.mind #Look at this!
## ID BTW WTN1 WTN2
## 1 1 1 6.939619 5.098660
## 2 2 2 5.978156 2.464705
## 3 3 1 4.515321 3.700668
## 4 4 2 3.502277 2.376611
## 5 5 1 4.972581 6.181047
## 6 6 2 3.275813 2.867202
Explanation
Al-righty then. First, we needed to specify the dataframe we would be using. Here, we used the melted.mind
dataframe.
Next, we put in our cast
ing formula. Now, R is pretty smart, and it assumes that the order in which you put the variables is meaningful. The description will tell you that whichever variable you put in first will be the “slowest varying” variable. In our case, the slowest varying is actually the between-subjects variable BTW
because there are only 2 levels. In other words, our BTW
variable will vary only once. However, if we put that in first, then the ID
numbers would be out of order. Like this…
cast.mind2<-dcast(melted.mind, BTW+ID~WTN)
cast.mind2 #Look at that!
## BTW ID WTN1 WTN2
## 1 1 1 6.939619 5.098660
## 2 1 3 4.515321 3.700668
## 3 1 5 4.972581 6.181047
## 4 2 2 5.978156 2.464705
## 5 2 4 3.502277 2.376611
## 6 2 6 3.275813 2.867202
We can also choose to specify only one side of the cast
ing formula, like this…
cast.mind3<-dcast(melted.mind, ID+BTW~...)
cast.mind3 #Look at this!
## ID BTW WTN1 WTN2
## 1 1 1 6.939619 5.098660
## 2 2 2 5.978156 2.464705
## 3 3 1 4.515321 3.700668
## 4 4 2 3.502277 2.376611
## 5 5 1 4.972581 6.181047
## 6 6 2 3.275813 2.867202
…or this…
cast.mind4<-dcast(melted.mind, ...~WTN)
cast.mind4 #Look at that!
## ID BTW WTN1 WTN2
## 1 1 1 6.939619 5.098660
## 2 2 2 5.978156 2.464705
## 3 3 1 4.515321 3.700668
## 4 4 2 3.502277 2.376611
## 5 5 1 4.972581 6.181047
## 6 6 2 3.275813 2.867202
Now, we could have started from the original dataset melt.mind
, but we will need to do something extra to recover something close to the original wide data. How about you run the code below, and I’ll walk you through what you see? Sound good? Ok, go for it. I’ll wait.
cast.mind5<-dcast(melt.mind, ID+BTW+WTN1+WTN2~"Row")
cast.mind5 #Look at this!
## ID BTW WTN1 WTN2 Row
## 1 1 1 6.939619 5.098660 1
## 2 2 2 5.978156 2.464705 2
## 3 3 1 4.515321 3.700668 3
## 4 4 2 3.502277 2.376611 4
## 5 5 1 4.972581 6.181047 5
## 6 6 2 3.275813 2.867202 6
As you can see, we have a new column named “Row
”. Why did I do that? In our original dataset mind
, I did not specify that ID
and BTW
were factors. If you’ll scroll back up to the section where I called the structure of the mind
data, the variable types for ID
and BTW
are int
. This is why the two variables get folded into each other in the melt.mind
data. If you’ll go back even farther to the code where we were creating our dataframe, I commented out two lines that would have converted ID
and BTW
into factors. If you run that code prior to creating the melt.mind
data, then it will look exactly like the melt.mind2
data. Don’t believe me? You can try it, if you’d like. If you do try it, however, you should probably rename the datasets you create something else so you can keep everything straight.
Now, what happens if you forget to include a variable in your casting formula? Well, that all depends on which variable you forget. If you forget to include your between-subjects, BTW
variable, then it may disappear from your casted data. Like this…
error.mind<-dcast(melted.mind, ID~WTN)
error.mind #Look at that!
## ID WTN1 WTN2
## 1 1 6.939619 5.098660
## 2 2 5.978156 2.464705
## 3 3 4.515321 3.700668
## 4 4 3.502277 2.376611
## 5 5 4.972581 6.181047
## 6 6 3.275813 2.867202
Notice how the BTW
variable just disappeared? That is something you should be aware of and keep an eye out for. Personally, I always double-check my work after melt
ing and cast
ing.
What happens if you forget the subject ID
variable? Well, this will result in a very different result. Check it out…
error.mind2<-dcast(melted.mind, BTW~WTN)
error.mind2 #Look at this!
## BTW WTN1 WTN2
## 1 1 3 3
## 2 2 3 3
Notice the error message Aggregation function missing: defaulting to length
? Notice that there are now only 2 rows, one for each level of your BTW
variable, and the values in under each WTN
level is 3
? That’s because defaulting to length
appears to have meant that R
will collapse all values that you used to have into just the number of columns in your dataset. Now, maybe you want to collapse accross all participants. Hey, it’s possible. But what if instead of a worthless number, like the number of columns in you data, you wanted the average for each within-subjects variable at each between-subjects variable? Now that sounds like some info that could be useful!! To do this, we will need to use the fun.aggregate
function in the cast
ing formula. Like this…
mind.summary<-dcast(melted.mind, BTW~WTN, fun.aggregate = mean)
mind.summary #Look at that!
## BTW WTN1 WTN2
## 1 1 5.475841 4.993459
## 2 2 4.252082 2.569506
You could have actually included any function after the fun.aggregate
function, including a local function. I chose to demonstrat the mean
function simply because it was easy and may be useful to you in the future.
Well, that’s it. Read on for more useful links and information.
Final Words
This is it for my introduction to the reshape2
package, but there are a ton of things you can do with cast
that I did not get around to describing. I recommend that you play around with this package and figure out what works best for you. And, if you need any other help, or if my explanations were too ridiculous for your serious mind
, then you can go to the sources below for additional help…
LS0tDQp0aXRsZTogIkNoYXB0ZXIgODogTWVsdGluZyAmIENhc3RpbmciDQphdXRob3I6ICJQTzMgVGltb3RoeSBDYXJzZWwiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdGhlbWU6IGNlcnVsZWFuDQogICAgaGlnaGxpZ2h0OiB0ZXh0bWF0ZQ0KICAgIGZvbnRzaXplOiA4cHQNCiAgICB0b2M6IHRydWUNCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiBmYWxzZQ0KLS0tDQoNCiMgTWVsdGluZyBhbmQgQ2FzdGluZw0KDQojIyBXaHkgUmVzaGFwZSBZb3VyIERhdGENCg0KUmVzaGFwZTIgaXMgYSBwYWNrYWdlIHRoYXQgYWxsb3dzIHVzIHRvIGVhc2lseSB0cmFuc2Zvcm0gb3VyIGRhdGEgaW50byB3aGF0ZXZlciBzdHJ1Y3R1cmUgd2UgbWF5IG5lZWQuIE1hbnkgb2YgdXMgYXJlIHVzZWQgdG8gc2VlaW5nIG91ciBkYXRhIHN0cnVjdHVyZWQgc28gdGhhdCBjb3JyZXNwb25kcyB0byBhIHNpbmdsZSBwYXJ0aWNpcGFudCBhbmQgZWFjaCBjb2x1bW4gY29ycmVzcG9uZHMgdG8gYSB2YXJpYWJsZS4gVGhpcyB0eXBlIG9mIGRhdGEgc3RydWN0dXJlIGlzIGtub3duIGFzICoqd2lkZSBmb3JtYXQqKi4gSG93ZXZlciwgbWFueSBvZiB0aGUgcGFja2FnZXMgaW4gUiByZXF1aXJlIHRoYXQgd2Ugc3RyZXRjaCBvdXIgZGF0YSBzbyB0aGF0IGEgc2luZ2xlIHBhcnRpY2lwYW50IG1heSBvY2N1cHkgbXVsdGlwbGUgcm93cy4gVGhpcyB0eXBlIG9mIGRhdGEgc3RydWN0dXJlIGlzIGtub3duIGFzICoqbG9uZyBmb3JtYXQqKi4gRm9yIGV4YW1wbGUsIGBgYGdncGxvdDJgYGAgYW5kIHNvbWUgZGF0YSBhbmFseXNpcyBmdW5jdGlvbnMgcmVxdWlyZSAqKmxvbmcgZm9ybWF0KiouIEFueSBvZiB5b3Ugd2hvIGhhdmUgdHJpZWQgdG8gcmVzdHJ1Y3R1cmUgdGhlaXIgZGF0YSB1c2luZyBFeGNlbCBvciBTUFNTIHdpbGwgaW1tZWRpYXRlbHkgcmVjb2duaXplIHRoZSBpbW1lbnNlIHBvd2VyIG9mIHRoaXMgcGFja2FnZS4gVGhlcmVmb3JlLCB3aXRob3V0IGZ1cnRoZXIgYWRvLCBsZXQncyBnZXQgdG8gaXQuDQoNCkFzIGEgcXVpY2sgbm90ZSwgdGhpcyB0dXRvcmlhbCB3aWxsIGJlIGhlYXZpbHkgYmFzZWQgYXJvdW5kIGxlYXJuaW5nIGZyb20gZXhhbXBsZXMuIFRoZXJlZm9yZSwgSSBzdHJvbmdseSBlbmNvdXJhZ2UgeW91IHRvIGZvbGxvdyBhbG9uZyB3aXRoIHRoZSBleGFtcGxlIGRhdGEgYW5kIGNvZGUgcHJvdmlkZWQgYmVsb3cuIEJlZm9yZSB3ZSBjYW4gYmVnaW4gb3VyIGRlbW9uc3RyYXRpb24sIGl0IHdpbGwgYmUgaGVscGZ1bCB0byBjbGVhciBvdXIgZW52aXJvbm1lbnQsIHNldCBvdXIgd29ya2luZyBkaXJlY3RvcnksIGxvYWQgdGhlIG5lY2Vzc2FyeSBwYWNrYWdlcywgYW5kIHRha2UgYSBxdWljayBnbGFuY2UgYXQgdGhlIGRlc2NyaXB0aW9uIG9mIG1lbHRpbmcgYW5kIGNhc3RpbmcgYXMgZGVzY3JpYmVkIGJ5IHRoZSB3b25kZXJvdXMgUlN0dWRpbyBoZWxwZXIgd2luZG93LiANCg0KU28gcGxlYXNlLCBqb2luIG1lIG9uIHRoaXMgbWFnaWNhbCBqb3VybmV5IGJ5IHJ1bm5pbmcgdGhlIGNvZGUgYmVsb3cuDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQ0KI0ZpcnN0LCByZW1vdmUgYWxsIHlvdXIgc3R1ZmYNCnJtKGxpc3Q9bHMoKSkNCg0KI01ha2Ugc3VyZSB0byBzZXQgeW91ciB3b3JraW5nIGRpcmVjdG9yeQ0KI3NldHdkKCJQQVRIIikNCg0KI05leHQsIHlvdSBuZWVkIHRvIGRvd25sb2FkIGFuZCBpbnN0YWxsIHRoZSByZXNoYXBlIHBhY2hhZ2UNCiNpbnN0YWxsLnBhY2thZ2VzKCJyZXNoYXBlMiIpDQpsaWJyYXJ5KHJlc2hhcGUyKQ0KYGBgDQoNCg0KIyMgUiBIZWxwDQoNClJ1bm5pbmcgdGhlIGZvbGxvd2luZyBjb2RlIHdpbGwgZ2l2ZSB5b3UgdGhlIGRlc2NyaXB0aW9uIG9mIHRoZSByZXNoYXBlMiBwYWNrYWdlDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KP21lbHQNCiNvcg0KP2Nhc3QNCmBgYA0KDQoNCiMjIERhdGEgRnJhbWUNCg0KR3JlYXQgam9iISBOb3csIHdlIG5lZWQgYSBkYXRhZnJhbWUgdG8gcGxheSB3aXRoLg0KVGhlIGNvZGUgYmVsb3cgd2lsbCBjcmVhdGUgb25lIGZvciB5b3Ugd2l0aCB0d28gd2l0aGluLXN1YmplY3RzIGZhY3RvcnMgYW5kIG9uZSBiZXR3ZWVuIHN1YmplY3RzIGZhY3Rvci4gDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQ0KI0NyZWF0aW5nIGEgdG95IGRhdGEgc2V0IHRvIG1lbHQNCiMjIFJ1biBldmVyeXRoaW5nIGJlbG93IFRPR0VUSEVSDQpJRDwtYygxOjYpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNDcmVhdGluZyBhbiBJRCB2YXJpYWJsZSBmb3IgNiBwYXJ0aWNpcGFudHMNCnNldC5zZWVkKDY2KSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI1NldHRpbmcgYSBzZWVkIHNvIHdlIGNhbiBhbGwgaGF2ZSB0aGUgc2FtZSB2YWx1ZXMNCldUTjE8LXJ1bmlmKDYsIG1pbiA9IDEsIG1heCA9IDcpICAgICAgICAgICAgI0NyZWF0aW5nIGEgd2l0aGluLVN1YmplY3RzIHZhcmlhYmxlDQpzZXQuc2VlZCgxNikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNTZXR0aW5nIGEgc2VlZCBzbyB3ZSBjYW4gYWxsIGhhdmUgdGhlIHNhbWUgdmFsdWVzDQpXVE4yPC1ydW5pZig2LCBtaW4gPSAxLCBtYXggPSA3KSAgICAgICAgICAgICNDcmVhdGluZyBhIHdpdGhpbi1TdWJqZWN0cyB2YXJpYWJsZQ0KQlRXPC0gcmVwbGljYXRlKDMsMToyLCBzaW1wbGlmeSA9IFQpICAgICAgICAjQ3JlYXRpbmcgYSBiZXR3ZWVuIHN1YmplY3RzIHZhcmlhYmxlDQpCVFc8LWFzLnZlY3RvcihCVFcpICAgICAgICAgICAgICAgICAgICAgICAgICNUdXJuaW5nIGJldHdlZW4tU3ViamVjdHMgdmFyaWFibGUgaW50byBhIHZlY3Rvcg0KbWluZDwtY2JpbmQuZGF0YS5mcmFtZShJRCwgV1ROMSwgV1ROMiwgQlRXKSAjQ29tYmluaW5nIHZhcmlhYmxlcyBpbnRvIGEgZGF0YWZyYW1lDQojbWluZCRCVFc8LWFzLmZhY3RvcihtaW5kJEJUVykgICAgICAgICAgICAgICNUdXJuaW5nIGJldHdlZW4tc3ViamVjdHMgdmFyaWFibGUgaW50byBhIGZhY3Rvcg0KI21pbmQkSUQ8LWFzLmZhY3RvcihtaW5kJEkpICAgICAgICAgICAgICAgICAjVHVybmluZyBJRCBpbnRvIGEgZmFjdG9yDQoNCm1pbmQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI0xldCdzIHZpZXcgdGhpcyBkYXRhIHNldA0Kc3RyKG1pbmQpDQpgYGANCg0KDQojIyBNZWx0aW5nDQoNCkJlbG93IGlzIHRoZSBnZW5lcmljIGNvZGUgZm9yIGBgYG1lbHRgYGBpbmcuDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQ0KI1RoaXMgaXMgY29tbWVudGVkIG91dCBzbyB0aGF0IHRoZSBnZW5lcmljIGNvZGUgZG9lcyBub3QgcnVuDQojbWVsdChkYXRhLCAuLi4sIG5hLnJtID0gRkFMU0UsIHZhbHVlLm5hbWUgPSAidmFsdWUiKQ0KYGBgDQoNCg0KT2ssIG5vdyB0aGF0IHdlIGhhdmUgYSBkYXRhZnJhbWUsIGxldCdzIGBgYG1lbHRgYGAgdGhlIHN1Y2tlciENCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0V9DQojTWVsdCB5b3VyIG1pbmQhDQptZWx0Lm1pbmQ8LW1lbHQobWluZCkgICAgICAgICAgICAgICAgICANCg0KaGVhZChtZWx0Lm1pbmQpICAgICAgICAgICAgICAgICAgICAgICAgICAgICNMb29rIGF0IHRoaXMhIA0KdGFpbChtZWx0Lm1pbmQpICAgICAgICAgICAgICAgICAgICAgICAgICAgICNMb29rIGF0IHRoYXQhDQpgYGANCg0KDQojIyBFeHBsYW5hdGlvbiANCg0KU28gd2hhdCBqdXN0IGhhcHBlbmVkPw0KDQpUaGUgbWVsdCBmdW5jdGlvbiB0b29rIG91ciBkYXRhZnJhbWUgdGhhdCBoYWQgYSBjb2x1bW4gZm9yIGVhY2ggdmFyaWFibGUsIGFuZCBjcmVhdGVkIGEgZGF0YWZyYW1lIHdpdGggb25seSAqKlRXTyoqIGNvbHVtbnM6IE9uZSBjb2x1bW4gbmFtZWQgYGBgdmFyaWFibGVgYGAgYW5kIG9uZSBjb2x1bW4gbmFtZWQgYGBgdmFsdWVgYGAuDQoNCkFzIHBzeWNob2xvZ2lzdHMsIHdlIGFyZSBvZnRlbiB1c2VkIHRvIHNlZWluZyB0aGluZ3MgaW4gKip3aWRlIGZvcm1hdCoqIGJlY2F1c2UgU1BTUyBkZWZhdWx0cyB0byAqKndpZGUgZm9ybWF0KiouDQoNCioqV2lkZSBmb3JtYXQqKiBoYXMgYSBjb2x1bW4gZm9yIGVhY2ggdmFyaWFibGUsIGFuZCBldmVyeSByb3cgaXMgYW4gaW5zdGFuY2Ugb2YgdGhlIHZhcmlhYmxlICoqcGFydGljaXBhbnQqKiwgdGhhdCBpcywgZWFjaCByb3cgcmVwcmVzZW50cyBvbmUgKipwYXJ0aWNpcGFudCoqLg0KDQpIb3dldmVyLCBpdCBpcyBvZnRlbiB1c2VmdWwsIGV2ZW4gb2NjYXNpb25hbGx5IG5lY2Vzc2FyeSwgdG8gc3RyZXRjaCBvdXQgdGhlIGRhdGFmcmFtZSBzbyB0aGF0IGVhY2ggcm93IGlzIGFuIGluc3RhbmNlIG9mIGEgZGlmZmVyZW50IHZhcmlhYmxlLiBCdXQgd2hhdCBkb2VzIHRoYXQgbWVhbj8NCg0KV2hlbiB3ZSBgYGBtZWx0YGBgZWQgdGhlIGRhdGFmcmFtZSBgYGBtaW5kYGBgLCB3ZSB0b2xkIFIgdGhhdCB3ZSB3YW50ZWQgZWFjaCByb3cgdG8gYmUgYSBzaW5nbGUgaW5zdGFuY2Ugb2YgYSB2YWx1ZS4gSW4gb3JkZXIgdG8gZG8gdGhhdCwgd2UgbmVlZGVkIHRvIGNvbGxhcHNlIGFjcm9zcyBhbGwgb3RoZXIgdmFyaWFibGVzIGludG8gdGhlIG5ldyB2YXJpYWJsZXM6IGBgYHZhcmlhYmxlYGBgIGFuZCBgYGB2YWx1ZWBgYC4gV2Ugc3RyZXRjaGVkIG91dCBvdXIgZGF0YXNldCBzbyB0aGF0IGl0IHdhcyAqKmxvbmdlcioqLCBvciBpbnRvICoqbG9uZyBmb3JtYXQqKi4NCg0KSW4gKipsb25nIGZvcm1hdCoqLCBlYWNoIHJvdyBubyBsb25nZXIgcmVwcmVzZW50cyBhIHNpbmdsZSBwYXJ0aWNpcGFudC4gSW4gb3VyIGV4YW1wbGUsIGVhY2ggcGFydGljaXBhbnQgd2FzIHN0cmV0Y2hlZCBpbnRvIGZvdXIgcm93cywgb25lIHJvdyBmb3IgZWFjaCB2YXJpYWJsZTogb25lICoqYmV0d2Vlbi1zdWJqZWN0cyoqIHZhcmlhYmxlLCBvbmUgYGBgSURgYGAgdmFyaWFibGUsIGFuZCB0d28gKip3aXRoaW4tc3ViamVjdHMqKiB2YXJpYWJsZXMuDQoNCkJ1dCB3aGF0IGlmIHdlIHdhbnRlZCB0byBtYWludGFpbiBzb21lIG90aGVyIGNvbHVtbnM/IEZvciBleGFtcGxlLCB3aGF0IGlmIHdlIHdhbnRlZCBgYGBJRGBgYCBhbmQgb3VyICoqYmV0d2Vlbi1zdWJqZWN0cyoqIHZhcmlhYmxlIGBgYEJUV2BgYCB0byBiZSwgd2VsbCwgKipiZXR3ZWVuLXN1YmplY3RzKio/DQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQ0KbWVsdC5taW5kMjwtbWVsdChtaW5kLCBpZD1jKCJJRCIsIkJUVyIpKQ0KDQptZWx0Lm1pbmQyICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI0xvb2sgYXQgdGhpcyEgDQpgYGANCg0KDQpJbiB0aGUgYGBgbWVsdGBgYCBmdW5jdGlvbiwgeW91IGNhbiBzcGVjaWZ5IHlvdXIgYGBgSURgYGAsIG9yICoqYmV0d2Vlbi1zdWJqZWN0cyoqIHZhcmlhYmxlcywgYXMgaW4gdGhlIHByZXZpb3VzIGxpbmUgb2YgY29kZS4gUiBpcyBzbWFydCBhbmQgd2lsbCBhc3N1bWUgYWxsIG90aGVyIHZhcmlhYmxlcyBhcmUgdG8gYmUgY29sbGFwc2VkIGludG8gZWFjaCBvdGhlci4NCg0KQnkgc3BlY2lmeWluZyB0aGF0IGBgYElEYGBgIGFuZCBgYGBCVFdgYGAgd2VyZSAqKmJldHdlZW4tc3ViamVjdHMqKiB2YXJpYWJsZXMsIHdlIHRvbGQgUiB0aGF0IHdlIHdhbnRlZCBvdXIgZGF0YXNldCBzdHJ1Y3R1cmVkIHNvIHRoYXQgZWFjaCByb3cgaXMgYW4gaW5zdGFuY2Ugb2Ygb25lIG9mIHRoZSAqKndpdGhpbi1zdWJqZWN0cyoqIHZhcmlhYmxlcy4gVGhpcyBtZWFucyB0aGF0IHdlIG5vdyBoYXZlIHR3byByb3dzIHBlciBzdWJqZWN0IGJlY2F1c2UgZWFjaCBzdWJqZWN0IGV4cGVyaWVuY2VkIGJvdGggb2YgdGhlIGxldmVscyBvZiB0aGUgKip3aXRoaW4tc3ViamVjdHMqKiB2YXJpYWJsZS4gTmVhdCwgcmlnaHQ/DQoNCk5vdywgd2hhdCBpZiB3ZSB3YW50ZWQgdG8gbmFtZSBvdXIgKip3aXRoaW4tc3ViamVjdHMqKiB2YXJpYWJsZSB0byBzb21ldGhpbmcgb3RoZXIgdGhhbiBgYGB2YXJpYWJsZWBgYD8gVHJ5IHRoaXMuLi4NCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0V9DQptZWx0Lm1pbmQzPC1tZWx0KG1pbmQsaWQ9YygiSUQiLCJCVFciKSwgDQogICAgICAgICAgICAgICAgIHZhcmlhYmxlLm5hbWUgPSAiV1ROIikNCg0KbWVsdC5taW5kMyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNMb29rIGF0IHRoYXQhIA0KYGBgDQoNCg0KQXMgeW91IGNhbiBzZWUsIGFsbCB3ZSBuZWVkZWQgdG8gZG8gd2FzIHNwZWNpZnkgdGhhdCB3ZSB3b3VsZCBuYW1lIG91ciB2YXJpYWJsZSB3aXRoIHRoZSBjb21tYW5kIGBgYHZhcmlhYmxlLm5hbWVgYGAuIEVhc3ktcGVhc3khDQoNCkFuZCBpZiB3ZSBhbHNvIHdhbnRlZCB0byBuYW1lIG91ciBgYGB2YWx1ZXNgYGA/DQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQ0KbWVsdGVkLm1pbmQ8LW1lbHQobWluZCxpZD1jKCJJRCIsIkJUVyIpLCANCiAgICAgICAgICAgICAgICAgIHZhcmlhYmxlLm5hbWUgPSAiV1ROIiwgDQogICAgICAgICAgICAgICAgICB2YWx1ZS5uYW1lID0gIlJlc3VsdHMiKQ0KDQpoZWFkKG1lbHRlZC5taW5kKSAgICAgICAgICAgICAgICAgICAgICAgICAgI0xvb2sgYXQgdGhpcyEgDQp0YWlsKG1lbHRlZC5taW5kKSAgICAgICAgICAgICAgICAgICAgICAgICAgI0xvb2sgYXQgdGhhdCEgDQpgYGANCg0KDQpDb29sIGNvb2wgY29vbC4gV2UndmUgc3VjZXNzZnVsbHkgYGBgbWVsdGBgYGVkIG91ciBgYGBtaW5kYGBgIGluIGEgd2F5IHRoYXQgd2UnZCBsaWtlLiBPdXIgZGF0YSBpcyBzdHJ1Y3R1cmVkIHNvIHRoYXQgZWFjaCByb3cgcmVwcmVzZW50cyBhbiBpbnN0YW5jZSBvZiB0aGUgKip3aXRoaW4tc3ViamVjdHMqKiB2YXJpYWJsZSwgYGBgV1ROYGBgLCBhbmQgd2UndmUgbWFpbnRhaW5lZCB0aGUgdmFyaWFibGVzIGBgYElEYGBgIGFuZCBgYGBCVFdgYGAuIE5vdywgbGV0J3MgY29udGludWUgdGhpcyBtYWdpY2FsIGpvdXJuZXkgb250byB0aGUgd29uZHJvdXMgbGFuZCBvZiBgYGBjYXN0YGBgaW5nLg0KDQojIyBDYXN0aW5nDQoNCmBgYENhc3RgYGBpbmcgd2lsbCB0cmFuc2Zvcm0gKipsb25nIGZvcm1hdCoqIGJhY2sgaW50byAqKndpZGUgZm9ybWF0KiouIFRoaXMgd2lsbCwgZXNzZW50aWFsbHksIG1ha2UgeW91ciBkYXRhIGxvb2sgYXMgaXQgZGlkIGluIHRoZSBiZWdpbm5pbmcgKG9yIGluIGFueSBvdGhlciB3YXkgeW91J2QgcHJlZmVyKS4gDQoNClRoZXJlIGFyZSBtdWx0aXBsZSBgYGBjYXN0YGBgIGZ1bmN0aW9ucyBkZXBlbmRpbmcgb24gdGhlIHN0cnVjdHVyZXMgb2YgeW91ciBkYXRhLiBJZiB5b3Ugd2FudCB0byBgYGBjYXN0YGBgIHlvdXIgZGF0YSBpbnRvIGEgZGF0YWZyYW1lLCB1c2UgYGBgZGNhc3RgYGAsIGFuZCBpZiB5b3Ugd2FudCB0byBgYGBjYXN0YGBgIHlvdXIgZGF0YSBpbnRvIHZlY3Rvci9tYXRyaXgvYXJyeSwgdGhlbiB1c2UgYGBgYWNhc3RgYGAuDQoNCkJlY2F1c2Ugd2Ugd2lsbCBiZSB3b3JraW5nIHdpdGggYSBkYXRhZnJhbWUsIHdlIHdpbGwgdXNlIGBgYGRjYXN0YGBgLiBUaGUgZ2VuZXJpYyBjb2RlIGZvciBib3RoIHR5cGVzIGlzIGJlbG93Lg0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRX0NCiNUaGVzZSBoYXZlIGJlZW4gY29tbWVudGVkIG91dCBzbyB0aGF0IHRoZXkgZG8gbm90IHJ1bi4NCg0KI2RjYXN0KGRhdGEsIGZvcm11bGEsIGZ1bi5hZ2dyZWdhdGUgPSBOVUxMLCAuLi4sIG1hcmdpbnMgPSBOVUxMLA0KIyAgc3Vic2V0ID0gTlVMTCwgZmlsbCA9IE5VTEwsIGRyb3AgPSBUUlVFLA0KIyAgdmFsdWUudmFyID0gZ3Vlc3NfdmFsdWUoZGF0YSkpDQoNCiNhY2FzdChkYXRhLCBmb3JtdWxhLCBmdW4uYWdncmVnYXRlID0gTlVMTCwgLi4uLCBtYXJnaW5zID0gTlVMTCwNCiMgIHN1YnNldCA9IE5VTEwsIGZpbGwgPSBOVUxMLCBkcm9wID0gVFJVRSwNCiMgIHZhbHVlLnZhciA9IGd1ZXNzX3ZhbHVlKGRhdGEpKQ0KYGBgDQoNCg0KQmVmb3JlIHdlIGJlZ2luLCBpdCdzIGltcG9ydGFudCB0byBub3RlIHRoYXQgYGBgY2FzdGBgYGluZyBpcyBtdWNoIG1vcmUgY2hhbGxlbmdpbmcgdGhhbiBgYGBtZWx0YGBgaW5nLiBUaGlzIG1heSBvZnRlbiB0YWtlIHNvbWUgdHJpYWwgYW5kIGVycm9yLCBhbmQgeW91IHNob3VsZCBub3QgZmVlbCBiYWQgYWJvdXQgdGhhdC4gSnVzdCByZW1lbWJlcjogKipZb3UncmUgYXdlc29tZSoqLiBGZWVsaW5nIGdvb2QgYWJvdXQgeW91cnNlbGY/IEdvb2QuICpHb29kKi4NCg0KTm93LCBsZXQncyBgYGBjYXN0YGBgIG91ciBkYXRhDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQ0KY2FzdC5taW5kPC1kY2FzdChtZWx0ZWQubWluZCwgSUQrQlRXfldUTikNCg0KY2FzdC5taW5kICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI0xvb2sgYXQgdGhpcyEgDQoNCmBgYA0KDQojIyBFeHBsYW5hdGlvbiANCg0KQWwtcmlnaHR5IHRoZW4uIEZpcnN0LCB3ZSBuZWVkZWQgdG8gc3BlY2lmeSB0aGUgZGF0YWZyYW1lIHdlIHdvdWxkIGJlIHVzaW5nLiBIZXJlLCB3ZSB1c2VkIHRoZSBgYGBtZWx0ZWQubWluZGBgYCBkYXRhZnJhbWUuIA0KDQpOZXh0LCB3ZSBwdXQgaW4gb3VyIGBgYGNhc3RgYGBpbmcgZm9ybXVsYS4gTm93LCBSIGlzIHByZXR0eSBzbWFydCwgYW5kIGl0IGFzc3VtZXMgdGhhdCB0aGUgb3JkZXIgaW4gd2hpY2ggeW91IHB1dCB0aGUgdmFyaWFibGVzIGlzIG1lYW5pbmdmdWwuIFRoZSBkZXNjcmlwdGlvbiB3aWxsIHRlbGwgeW91IHRoYXQgd2hpY2hldmVyIHZhcmlhYmxlIHlvdSBwdXQgaW4gZmlyc3Qgd2lsbCBiZSB0aGUgKiJzbG93ZXN0IHZhcnlpbmciKiB2YXJpYWJsZS4gSW4gb3VyIGNhc2UsIHRoZSBzbG93ZXN0IHZhcnlpbmcgaXMgYWN0dWFsbHkgdGhlICoqYmV0d2Vlbi1zdWJqZWN0cyoqIHZhcmlhYmxlIGBgYEJUV2BgYCBiZWNhdXNlIHRoZXJlIGFyZSBvbmx5IDIgbGV2ZWxzLiBJbiBvdGhlciB3b3Jkcywgb3VyIGBgYEJUV2BgYCB2YXJpYWJsZSB3aWxsIHZhcnkgb25seSBvbmNlLiBIb3dldmVyLCBpZiB3ZSBwdXQgdGhhdCBpbiBmaXJzdCwgdGhlbiB0aGUgYGBgSURgYGAgbnVtYmVycyB3b3VsZCBiZSBvdXQgb2Ygb3JkZXIuIExpa2UgdGhpcy4uLg0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRX0NCmNhc3QubWluZDI8LWRjYXN0KG1lbHRlZC5taW5kLCBCVFcrSUR+V1ROKQ0KDQpjYXN0Lm1pbmQyICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI0xvb2sgYXQgdGhhdCEgDQpgYGANCg0KDQoNCldlIGNhbiBhbHNvIGNob29zZSB0byBzcGVjaWZ5IG9ubHkgb25lIHNpZGUgb2YgdGhlIGBgYGNhc3RgYGBpbmcgZm9ybXVsYSwgbGlrZSB0aGlzLi4uDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQ0KY2FzdC5taW5kMzwtZGNhc3QobWVsdGVkLm1pbmQsIElEK0JUV34uLi4pDQoNCmNhc3QubWluZDMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjTG9vayBhdCB0aGlzISANCmBgYA0KDQoNCi4uLm9yIHRoaXMuLi4NCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0V9DQpjYXN0Lm1pbmQ0PC1kY2FzdChtZWx0ZWQubWluZCwgLi4ufldUTikNCg0KY2FzdC5taW5kNCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNMb29rIGF0IHRoYXQhIA0KYGBgDQoNCg0KTm93LCB3ZSBjb3VsZCBoYXZlIHN0YXJ0ZWQgZnJvbSB0aGUgb3JpZ2luYWwgZGF0YXNldCBgYGBtZWx0Lm1pbmRgYGAsIGJ1dCB3ZSB3aWxsIG5lZWQgdG8gZG8gc29tZXRoaW5nIGV4dHJhIHRvIHJlY292ZXIgc29tZXRoaW5nIGNsb3NlIHRvIHRoZSBvcmlnaW5hbCAqKndpZGUqKiBkYXRhLiBIb3cgYWJvdXQgeW91IHJ1biB0aGUgY29kZSBiZWxvdywgYW5kIEknbGwgd2FsayB5b3UgdGhyb3VnaCB3aGF0IHlvdSBzZWU/IFNvdW5kIGdvb2Q/IE9rLCBnbyBmb3IgaXQuIEknbGwgd2FpdC4NCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0V9DQpjYXN0Lm1pbmQ1PC1kY2FzdChtZWx0Lm1pbmQsIElEK0JUVytXVE4xK1dUTjJ+IlJvdyIpDQoNCmNhc3QubWluZDUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjTG9vayBhdCB0aGlzISANCmBgYA0KDQoNCkFzIHlvdSBjYW4gc2VlLCB3ZSBoYXZlIGEgbmV3IGNvbHVtbiBuYW1lZCAiYGBgUm93YGBgIi4gV2h5IGRpZCBJIGRvIHRoYXQ/IEluIG91ciBvcmlnaW5hbCBkYXRhc2V0IGBgYG1pbmRgYGAsIEkgZGlkIG5vdCBzcGVjaWZ5IHRoYXQgYGBgSURgYGAgYW5kIGBgYEJUV2BgYCB3ZXJlIGZhY3RvcnMuIElmIHlvdSdsbCBzY3JvbGwgYmFjayB1cCB0byB0aGUgc2VjdGlvbiB3aGVyZSBJIGNhbGxlZCB0aGUgc3RydWN0dXJlIG9mIHRoZSBgYGBtaW5kYGBgIGRhdGEsIHRoZSB2YXJpYWJsZSB0eXBlcyBmb3IgYGBgSURgYGAgYW5kIGBgYEJUV2BgYCBhcmUgYGBgaW50YGBgLiBUaGlzIGlzIHdoeSB0aGUgdHdvIHZhcmlhYmxlcyBnZXQgZm9sZGVkIGludG8gZWFjaCBvdGhlciBpbiB0aGUgYGBgbWVsdC5taW5kYGBgIGRhdGEuIElmIHlvdSdsbCBnbyBiYWNrICpldmVuIGZhcnRoZXIqIHRvIHRoZSBjb2RlIHdoZXJlIHdlIHdlcmUgY3JlYXRpbmcgb3VyIGRhdGFmcmFtZSwgSSBjb21tZW50ZWQgb3V0IHR3byBsaW5lcyB0aGF0IHdvdWxkIGhhdmUgY29udmVydGVkIGBgYElEYGBgIGFuZCBgYGBCVFdgYGAgaW50byBmYWN0b3JzLiBJZiB5b3UgcnVuIHRoYXQgY29kZSBwcmlvciB0byBjcmVhdGluZyB0aGUgYGBgbWVsdC5taW5kYGBgIGRhdGEsIHRoZW4gaXQgd2lsbCBsb29rIGV4YWN0bHkgbGlrZSB0aGUgYGBgbWVsdC5taW5kMmBgYCBkYXRhLiBEb24ndCBiZWxpZXZlIG1lPyBZb3UgY2FuIHRyeSBpdCwgaWYgeW91J2QgbGlrZS4gSWYgeW91IGRvIHRyeSBpdCwgaG93ZXZlciwgeW91IHNob3VsZCBwcm9iYWJseSByZW5hbWUgdGhlIGRhdGFzZXRzIHlvdSBjcmVhdGUgc29tZXRoaW5nIGVsc2Ugc28geW91IGNhbiBrZWVwIGV2ZXJ5dGhpbmcgc3RyYWlnaHQuDQoNCk5vdywgd2hhdCBoYXBwZW5zIGlmIHlvdSBmb3JnZXQgdG8gaW5jbHVkZSBhIHZhcmlhYmxlIGluIHlvdXIgY2FzdGluZyBmb3JtdWxhPyBXZWxsLCB0aGF0IGFsbCBkZXBlbmRzIG9uIHdoaWNoIHZhcmlhYmxlIHlvdSBmb3JnZXQuIElmIHlvdSBmb3JnZXQgdG8gaW5jbHVkZSB5b3VyIGJldHdlZW4tc3ViamVjdHMsIGBgYEJUV2BgYCB2YXJpYWJsZSwgdGhlbiBpdCBtYXkgZGlzYXBwZWFyIGZyb20geW91ciBjYXN0ZWQgZGF0YS4gTGlrZSB0aGlzLi4uDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQ0KZXJyb3IubWluZDwtZGNhc3QobWVsdGVkLm1pbmQsIElEfldUTikNCg0KZXJyb3IubWluZCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNMb29rIGF0IHRoYXQhIA0KYGBgDQoNCg0KTm90aWNlIGhvdyB0aGUgYGBgQlRXYGBgIHZhcmlhYmxlIGp1c3QgZGlzYXBwZWFyZWQ/IFRoYXQgaXMgc29tZXRoaW5nIHlvdSBzaG91bGQgYmUgYXdhcmUgb2YgYW5kIGtlZXAgYW4gZXllIG91dCBmb3IuIFBlcnNvbmFsbHksIEkgYWx3YXlzIGRvdWJsZS1jaGVjayBteSB3b3JrIGFmdGVyIGBgYG1lbHRgYGBpbmcgYW5kIGBgYGNhc3RgYGBpbmcuIA0KDQpXaGF0IGhhcHBlbnMgaWYgeW91IGZvcmdldCB0aGUgc3ViamVjdCBgYGBJRGBgYCB2YXJpYWJsZT8gV2VsbCwgdGhpcyB3aWxsIHJlc3VsdCBpbiBhIHZlcnkgZGlmZmVyZW50IHJlc3VsdC4gQ2hlY2sgaXQgb3V0Li4uDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQ0KZXJyb3IubWluZDI8LWRjYXN0KG1lbHRlZC5taW5kLCBCVFd+V1ROKQ0KDQplcnJvci5taW5kMiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNMb29rIGF0IHRoaXMhIA0KYGBgDQoNCg0KTm90aWNlIHRoZSBlcnJvciBtZXNzYWdlIGBgYEFnZ3JlZ2F0aW9uIGZ1bmN0aW9uIG1pc3Npbmc6IGRlZmF1bHRpbmcgdG8gbGVuZ3RoYGBgPyBOb3RpY2UgdGhhdCB0aGVyZSBhcmUgbm93IG9ubHkgMiByb3dzLCBvbmUgZm9yIGVhY2ggbGV2ZWwgb2YgeW91ciBgYGBCVFdgYGAgdmFyaWFibGUsIGFuZCB0aGUgdmFsdWVzIGluIHVuZGVyIGVhY2ggYGBgV1ROYGBgIGxldmVsIGlzIGBgYDNgYGA/IFRoYXQncyBiZWNhdXNlIGBgYGRlZmF1bHRpbmcgdG8gbGVuZ3RoYGBgIGFwcGVhcnMgdG8gaGF2ZSBtZWFudCB0aGF0IGBgYFJgYGAgd2lsbCBjb2xsYXBzZSBhbGwgdmFsdWVzIHRoYXQgeW91IHVzZWQgdG8gaGF2ZSBpbnRvICBqdXN0IHRoZSBudW1iZXIgb2YgY29sdW1ucyBpbiB5b3VyIGRhdGFzZXQuIE5vdywgbWF5YmUgeW91IHdhbnQgdG8gY29sbGFwc2UgYWNjcm9zcyBhbGwgcGFydGljaXBhbnRzLiBIZXksIGl0J3MgcG9zc2libGUuIEJ1dCB3aGF0IGlmIGluc3RlYWQgb2YgYSB3b3J0aGxlc3MgbnVtYmVyLCBsaWtlIHRoZSBudW1iZXIgb2YgY29sdW1ucyBpbiB5b3UgZGF0YSwgeW91IHdhbnRlZCB0aGUgYXZlcmFnZSBmb3IgZWFjaCB3aXRoaW4tc3ViamVjdHMgdmFyaWFibGUgYXQgZWFjaCBiZXR3ZWVuLXN1YmplY3RzIHZhcmlhYmxlPyBOb3cgdGhhdCBzb3VuZHMgbGlrZSBzb21lIGluZm8gdGhhdCBjb3VsZCBiZSB1c2VmdWwhISBUbyBkbyB0aGlzLCB3ZSB3aWxsIG5lZWQgdG8gdXNlIHRoZSBgYGBmdW4uYWdncmVnYXRlYGBgIGZ1bmN0aW9uIGluIHRoZSBgYGBjYXN0YGBgaW5nIGZvcm11bGEuIExpa2UgdGhpcy4uLg0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRX0NCm1pbmQuc3VtbWFyeTwtZGNhc3QobWVsdGVkLm1pbmQsIEJUV35XVE4sIGZ1bi5hZ2dyZWdhdGUgPSBtZWFuKQ0KDQptaW5kLnN1bW1hcnkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNMb29rIGF0IHRoYXQhIA0KYGBgDQoNCg0KWW91IGNvdWxkIGhhdmUgYWN0dWFsbHkgaW5jbHVkZWQgYW55IGZ1bmN0aW9uIGFmdGVyIHRoZSBgYGBmdW4uYWdncmVnYXRlYGBgIGZ1bmN0aW9uLCBpbmNsdWRpbmcgYSBsb2NhbCBmdW5jdGlvbi4gSSBjaG9zZSB0byBkZW1vbnN0cmF0IHRoZSBgYGBtZWFuYGBgIGZ1bmN0aW9uIHNpbXBseSBiZWNhdXNlIGl0IHdhcyBlYXN5IGFuZCBtYXkgYmUgdXNlZnVsIHRvIHlvdSBpbiB0aGUgZnV0dXJlLiANCg0KV2VsbCwgdGhhdCdzIGl0LiBSZWFkIG9uIGZvciBtb3JlIHVzZWZ1bCBsaW5rcyBhbmQgaW5mb3JtYXRpb24uDQoNCiMjIEZpbmFsIFdvcmRzDQoNClRoaXMgaXMgaXQgZm9yIG15IGludHJvZHVjdGlvbiB0byB0aGUgYGBgcmVzaGFwZTJgYGAgcGFja2FnZSwgYnV0IHRoZXJlIGFyZSBhICp0b24qIG9mIHRoaW5ncyB5b3UgY2FuIGRvIHdpdGggYGBgY2FzdGBgYCB0aGF0IEkgZGlkIG5vdCBnZXQgYXJvdW5kIHRvIGRlc2NyaWJpbmcuIEkgcmVjb21tZW5kIHRoYXQgeW91IHBsYXkgYXJvdW5kIHdpdGggdGhpcyBwYWNrYWdlIGFuZCBmaWd1cmUgb3V0IHdoYXQgd29ya3MgYmVzdCBmb3IgeW91LiBBbmQsIGlmIHlvdSBuZWVkIGFueSBvdGhlciBoZWxwLCBvciBpZiBteSBleHBsYW5hdGlvbnMgd2VyZSB0b28gcmlkaWN1bG91cyBmb3IgeW91ciBzZXJpb3VzIGBgYG1pbmRgYGAsIHRoZW4geW91IGNhbiBnbyB0byB0aGUgc291cmNlcyBiZWxvdyBmb3IgYWRkaXRpb25hbCBoZWxwLi4uDQoNCiMjIFNvdXJjZXMgdGhhdCB3ZXJlIGltbWVuc2VseSBoZWxwZnVsIGluIHRoZSBjcmVhdGlvbiBvZiBteSB0dXRvcmlhbA0KDQpodHRwOi8vc2VhbmFuZGVyc29uLmNhLzIwMTMvMTAvMTkvcmVzaGFwZS5odG1sICAgICAgICAgICAgICAgICAgDQpUaGlzIHR1dG9yaWFsIGlzIGFtYXppbmcNCg0KaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3Jlc2hhcGUyL3Jlc2hhcGUyLnBkZiAgIA0KVGhpcyBvbmUgaXMgcHJldHR5IGdvb2QgdG9vDQoNCmh0dHA6Ly9oYWQuY28ubnovcmVzaGFwZS8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANClRoaXMgaXMgdGhlIGBgYHJlc2hhcGUyYGBgIHdlYnNpdGUNCg0KDQo8c2NyaXB0Pg0KICAoZnVuY3Rpb24oaSxzLG8sZyxyLGEsbSl7aVsnR29vZ2xlQW5hbHl0aWNzT2JqZWN0J109cjtpW3JdPWlbcl18fGZ1bmN0aW9uKCl7DQogIChpW3JdLnE9aVtyXS5xfHxbXSkucHVzaChhcmd1bWVudHMpfSxpW3JdLmw9MSpuZXcgRGF0ZSgpO2E9cy5jcmVhdGVFbGVtZW50KG8pLA0KICBtPXMuZ2V0RWxlbWVudHNCeVRhZ05hbWUobylbMF07YS5hc3luYz0xO2Euc3JjPWc7bS5wYXJlbnROb2RlLmluc2VydEJlZm9yZShhLG0pDQogIH0pKHdpbmRvdyxkb2N1bWVudCwnc2NyaXB0JywnaHR0cHM6Ly93d3cuZ29vZ2xlLWFuYWx5dGljcy5jb20vYW5hbHl0aWNzLmpzJywnZ2EnKTsNCg0KICBnYSgnY3JlYXRlJywgJ1VBLTk4ODc4NzkzLTEnLCAnYXV0bycpOw0KICBnYSgnc2VuZCcsICdwYWdldmlldycpOw0KDQo8L3NjcmlwdD4=