Before you start
Make sure that you’ve clicked on the oop_talk.rproj
file to open this folder as a project.
What are S4 Objects?
S4 objects are like S3 objects, but are stricter. Whereas an S3 object is a list, and you can put anything in the list, S4 objects have slots: these are specific data types, such as vectors
, data.frames
. You can also put additional restrictions on these data frames.
In S3, you can literally change the class of any object by using the class()
function:
my_list <- list(a="blah", b=c(1,2,3))
class(my_list) <- "newclass"
class(my_list)
This flexibility can be a very bad thing when trying to get a data structure to work consistently across a bunch of packages. Things might not work like you expect them to, or worse, the loose definition of the object can cause compatibility issues down the line. So that’s why you would want to be strict.
S4 also has methods like S3, and you also have to be strict about what arguments go into each method. S4 does this by first defining a generic function, and then specifying a method with strict typing.
Properties of S4 Objects
Loading an Object
We’re going to load an object called my_result_object
, which has the class StatsPackageResult
.
source("R/classes-S4.R")
#we use here
library(here)
my_result_object <- readRDS(here("data/s4_stat_result.rds"))
What class is my object?
class(my_result_object)
Okay we have an object, but how do we know it’s an S4 object?
isS4(my_result_object)
Slots
Here we can see the slots
of my_result_object
. Slots hold different parts of the data object. We have to be explicit in what data types go in them.
slotNames(my_result_object)
We can also ask about the S4 class - this gives us more information about what is in the individual slots:
getSlots("StatPackageResult")
We need more info
We can use the getClass
function to get more info about the StatsPackageResult
class.
getClass("StatPackageResult")
Looking at the object’s structure
We can use the str()
function to look at the overall structure of our object. We can see information about the actual data.frame
s in the data
slot and the statistics
slot.
str(my_result_object)
Accessing a slot directly
S4 uses the @
sign instead of the $
sign to access the data in a slot.
glimpse(my_result_object@data)
Methods
We’ve defined two methods that work on our class: get_statistics()
and get_significant_results()
.
Let’s try out and see what get_statistics()
does:
get_statistics(my_result_object)
get_statistics
showMethods("get_statistics")
getMethod(f="get_statistics", signature = signature("StatPackageResult"))
How do we know about the methods that belong to a class? Hopefully, this is documented in the documentation about the class.
However, one big issue is that there is no easy way to find all the methods that act upon the class that are in other packages.
PROBLEM
There is another method for our StatsPackageResult
class: get_significant_results()
. Try it out below:
get_significant_results(my_result_object, cutoff = 0.1)
Show the method code for get_significant_results()
. Hint: you’ll have to find the signature for the method before you can use getMethod()
##Space for your answer here
Making a new StatsPackageResult
object/Type Checking
Now that you see the basics behind the StatsPackageResult
class, you can now make a StatsPackageResult
object. You will probably do this in your package code when you’re returning a result.
The StatsPackageResult()
function is called an constructor. We need to give it values for each of the slots to make a valid object. (There is also a way to make a new object with the new()
function, but it’s currently not recommended.)
#first define the statistics slot
stat_frame <- data.frame(group=c("setosa", "virginica", "versicolor"), pvalue=c(0.5, 0.2, 0.001))
my_s4_object_new <- StatPackageResult(data = iris, statistics = stat_frame)
We know that the required slots are for data
, which needs to be a data.frame
, and statistics
, which also needs to be a data.frame
. What if we make a new object where statistics
is a vector
?
cw <- as.data.frame(ChickWeight)
new_obj <- StatPackageResult(data=cw, statistics=c(1,1,1))
What happens when you only provide a data
argument? What happens?
cw <- data.frame(ChickWeight)
new_obj2 <- StatPackageResult(data=cw)
We also have a requirement that the statistics
slot has a data.frame
with the name pvalue
. We’ll see how we did this in the Validity
section below.
new_obj3 <- StatPackageResult(data=cw, statistics=cw)
How did we define the StatsPackageResult
Class?
Take a look at R/classes-S4.R
. The first thing we did was define the class with setClass
, where we can specify the data types of each of the slots. Note that this also defines what’s called the constructor, or the function that lets us make new objects.
StatPackageResult <- setClass("StatPackageResult",
slots = c(data = "data.frame",
statistics = "data.frame"),
prototype = c(data=NA, statistics=NA)
)
Defining methods for StatsPackageResult
S4 methods are designed to be flexible. The downside to the flexibility is that they are a little harder to program with and set up. Whereas in S3, we could define a method for our S3 class by just naming a function with a dot (such as print.stats_result
), S4 requires us to first establish a generic
function.
The generic
function is designed to use different code based on the class of the object, much like S4 generics. Take a look at the generic method show
. You can see all of the different classes it works on. This object="Module"
is called a signature, and it defines how the generic function decides which method code to dispatch.
Here are all the S4 methods for the show
generic function based on their signature:
showMethods("show")
Because methods can be dispatched on multiple signatures, you first have to define the method using setGeneric()
:
#always need to define the generic method first
setGeneric(name= "statistics",
def= function(object) {
standardGeneric("statistics")
}
)
This creates a generic function called statistics
, which has a single argument: object
. Note that object
isn’t limited to our StatsPackageResult
class. We could also define a statistics
method for other S4 objects.
Once the generic is created, you can now define a method for your class.
#define the function
setMethod(f="statistics",
#signature is how the function is called
signature = signature("StatPackageResult"),
definition = function(object){
return(object@statistics)
})
Validity
Say you need to have another requirement for the data.frame
in the statistics
slot, such as requiring a column called pvalue
. We can do this by adding a validity function using setValidity
:
check_stats_object <- function(object){
#check whether statistics data.frame contains "pvalue"
#as column name
if("pvalue" %in% colnames(get_statistics(object))) {TRUE}
else{ "statistics slot needs a pvalue column"}
}
setValidity("StatsResultObject", check_stats_object)
Inheritance
The best thing about Object Oriented Programming is that you don’t have to reinvent the wheel. You can extend a current class definition to make a new class. Here we’re making a new class AnovaResult
that is based on our StatPackageResult
. You can see we use the contains
argument to say we’re extending StatPackageResult
.
Also, note we’re adding a groups
slot. The other slots from StatPackageResult
, data
and statistics
are inherited from StatPackageResult
.
#Inheritance: making a new class from our old class
AnovaResult <- setClass("AnovaResult",
contains= "StatPackageResult",
slots=c(groups="character"))
stat_frame <- data.frame(group=c("setosa", "virginica", "versicolor"), pvalue=c(0.5, 0.2, 0.001))
groups <- c("setosa", "virginica", "versicolor")
anova_result_s4 <- AnovaResult(data = iris, statistics = stat_frame, groups=groups)
#get the class definition
getClass("AnovaResult")
Show the new structure of our inherited object.
str(anova_result_s4)
Extending methods from a superlcass
Methods are class specific, but they also inherit from the super class that our new class is derived from. This means you can add extra code to a method by overriding the method for the new class and using callNextMethod()
to execute the code belonging to the superclass (which is StatPackageResult
).
#Overriding the get_statistics method for StatPackageResult
setMethod("get_statistics",
signature = signature(object = "AnovaResult"),
definition = function(object){
print(object@groups)
#now run the code that belongs to the method
#for the superclass ("StatPackageResult")
callNextMethod(object)
}
)
Try running get_statistics()
on anova_result_s4
. It will first print out group
and then return the statistics
slot.
get_statistics(anova_result_s4)
What we didn’t cover today:
- Updating old objects
- Getting S3 and S4 to work together
- Multiple Inheritance and Dispatch
Resources
Portions of this notebook were gratefully adapted from:
LS0tDQp0aXRsZTogIlM0IE9iamVjdHMiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCmF1dGhvcjogVGVkIExhZGVyYXMNCi0tLQ0KDQojIEJlZm9yZSB5b3Ugc3RhcnQNCg0KTWFrZSBzdXJlIHRoYXQgeW91J3ZlIGNsaWNrZWQgb24gdGhlIGBvb3BfdGFsay5ycHJvamAgZmlsZSB0byBvcGVuIHRoaXMgZm9sZGVyIGFzIGEgcHJvamVjdC4NCg0KIyBXaGF0IGFyZSBTNCBPYmplY3RzPw0KDQpTNCBvYmplY3RzIGFyZSBsaWtlIFMzIG9iamVjdHMsIGJ1dCBhcmUgc3RyaWN0ZXIuIFdoZXJlYXMgYW4gUzMgb2JqZWN0IGlzIGEgbGlzdCwgYW5kIHlvdSBjYW4gcHV0IGFueXRoaW5nIGluIHRoZSBsaXN0LCBTNCBvYmplY3RzIGhhdmUgKnNsb3RzKjogdGhlc2UgYXJlIHNwZWNpZmljIGRhdGEgdHlwZXMsIHN1Y2ggYXMgYHZlY3RvcnNgLCBgZGF0YS5mcmFtZXNgLiBZb3UgY2FuIGFsc28gcHV0IGFkZGl0aW9uYWwgcmVzdHJpY3Rpb25zIG9uIHRoZXNlIGRhdGEgZnJhbWVzLg0KDQpJbiBTMywgeW91IGNhbiBsaXRlcmFsbHkgY2hhbmdlIHRoZSBjbGFzcyBvZiBhbnkgb2JqZWN0IGJ5IHVzaW5nIHRoZSBgY2xhc3MoKWAgZnVuY3Rpb246DQoNCmBgYHtyfQ0KbXlfbGlzdCA8LSBsaXN0KGE9ImJsYWgiLCBiPWMoMSwyLDMpKQ0KY2xhc3MobXlfbGlzdCkgPC0gIm5ld2NsYXNzIg0KY2xhc3MobXlfbGlzdCkNCmBgYA0KDQpUaGlzIGZsZXhpYmlsaXR5IGNhbiBiZSBhIHZlcnkgYmFkIHRoaW5nIHdoZW4gdHJ5aW5nIHRvIGdldCBhIGRhdGEgc3RydWN0dXJlIHRvIHdvcmsgY29uc2lzdGVudGx5IGFjcm9zcyBhIGJ1bmNoIG9mIHBhY2thZ2VzLiBUaGluZ3MgbWlnaHQgbm90IHdvcmsgbGlrZSB5b3UgZXhwZWN0IHRoZW0gdG8sIG9yIHdvcnNlLCB0aGUgbG9vc2UgZGVmaW5pdGlvbiBvZiB0aGUgb2JqZWN0IGNhbiBjYXVzZSBjb21wYXRpYmlsaXR5IGlzc3VlcyBkb3duIHRoZSBsaW5lLiBTbyB0aGF0J3Mgd2h5IHlvdSB3b3VsZCB3YW50IHRvIGJlIHN0cmljdC4NCg0KUzQgYWxzbyBoYXMgKm1ldGhvZHMqIGxpa2UgKlMzKiwgYW5kIHlvdSBhbHNvIGhhdmUgdG8gYmUgc3RyaWN0IGFib3V0IHdoYXQgYXJndW1lbnRzIGdvIGludG8gZWFjaCBtZXRob2QuIFM0IGRvZXMgdGhpcyBieSBmaXJzdCBkZWZpbmluZyBhIGdlbmVyaWMgZnVuY3Rpb24sIGFuZCB0aGVuIHNwZWNpZnlpbmcgYSBtZXRob2Qgd2l0aCBzdHJpY3QgdHlwaW5nLg0KDQojIFByb3BlcnRpZXMgb2YgUzQgT2JqZWN0cw0KDQojIyBMb2FkaW5nIGFuIE9iamVjdA0KDQpXZSdyZSBnb2luZyB0byBsb2FkIGFuIG9iamVjdCBjYWxsZWQgYG15X3Jlc3VsdF9vYmplY3RgLCB3aGljaCBoYXMgdGhlIGNsYXNzIGBTdGF0c1BhY2thZ2VSZXN1bHRgLiANCg0KYGBge3J9DQpzb3VyY2UoIlIvY2xhc3Nlcy1TNC5SIikNCiN3ZSB1c2UgaGVyZQ0KbGlicmFyeShoZXJlKQ0KbXlfcmVzdWx0X29iamVjdCA8LSByZWFkUkRTKGhlcmUoImRhdGEvczRfc3RhdF9yZXN1bHQucmRzIikpDQpgYGANCg0KIyMgV2hhdCBjbGFzcyBpcyBteSBvYmplY3Q/DQoNCmBgYHtyfQ0KY2xhc3MobXlfcmVzdWx0X29iamVjdCkNCmBgYA0KDQpPa2F5IHdlIGhhdmUgYW4gb2JqZWN0LCBidXQgaG93IGRvIHdlIGtub3cgaXQncyBhbiBTNCBvYmplY3Q/DQoNCmBgYHtyfQ0KaXNTNChteV9yZXN1bHRfb2JqZWN0KQ0KYGBgDQoNCiMjIFNsb3RzDQoNCkhlcmUgd2UgY2FuIHNlZSB0aGUgYHNsb3RzYCBvZiBgbXlfcmVzdWx0X29iamVjdGAuIFNsb3RzIGhvbGQgZGlmZmVyZW50IHBhcnRzIG9mIHRoZSBkYXRhIG9iamVjdC4gV2UgaGF2ZSB0byBiZSBleHBsaWNpdCBpbiB3aGF0IGRhdGEgdHlwZXMgZ28gaW4gdGhlbS4NCg0KYGBge3J9DQpzbG90TmFtZXMobXlfcmVzdWx0X29iamVjdCkNCmBgYA0KDQpXZSBjYW4gYWxzbyBhc2sgYWJvdXQgdGhlIFM0IGNsYXNzIC0gdGhpcyBnaXZlcyB1cyBtb3JlIGluZm9ybWF0aW9uIGFib3V0IHdoYXQgaXMgaW4gdGhlIGluZGl2aWR1YWwgc2xvdHM6DQoNCmBgYHtyfQ0KDQpnZXRTbG90cygiU3RhdFBhY2thZ2VSZXN1bHQiKQ0KYGBgDQoNCiMjIFdlIG5lZWQgbW9yZSBpbmZvDQoNCldlIGNhbiB1c2UgdGhlIGBnZXRDbGFzc2AgZnVuY3Rpb24gdG8gZ2V0IG1vcmUgaW5mbyBhYm91dCB0aGUgYFN0YXRzUGFja2FnZVJlc3VsdGAgY2xhc3MuDQoNCmBgYHtyfQ0KZ2V0Q2xhc3MoIlN0YXRQYWNrYWdlUmVzdWx0IikNCmBgYA0KDQojIyBMb29raW5nIGF0IHRoZSBvYmplY3QncyBzdHJ1Y3R1cmUNCg0KV2UgY2FuIHVzZSB0aGUgYHN0cigpYCBmdW5jdGlvbiB0byBsb29rIGF0IHRoZSBvdmVyYWxsIHN0cnVjdHVyZSBvZiBvdXIgb2JqZWN0LiBXZSBjYW4gc2VlIGluZm9ybWF0aW9uIGFib3V0IHRoZSBhY3R1YWwgYGRhdGEuZnJhbWVgcyBpbiB0aGUgYGRhdGFgIHNsb3QgYW5kIHRoZSBgc3RhdGlzdGljc2Agc2xvdC4NCg0KYGBge3J9DQpzdHIobXlfcmVzdWx0X29iamVjdCkNCg0KYGBgDQoNCiMjIEFjY2Vzc2luZyBhIHNsb3QgZGlyZWN0bHkNCg0KUzQgdXNlcyB0aGUgYEBgIHNpZ24gaW5zdGVhZCBvZiB0aGUgYCRgIHNpZ24gdG8gYWNjZXNzIHRoZSBkYXRhIGluIGEgc2xvdC4NCg0KYGBge3J9DQpnbGltcHNlKG15X3Jlc3VsdF9vYmplY3RAZGF0YSkNCmBgYA0KDQojIE1ldGhvZHMNCg0KV2UndmUgZGVmaW5lZCB0d28gbWV0aG9kcyB0aGF0IHdvcmsgb24gb3VyIGNsYXNzOiBgZ2V0X3N0YXRpc3RpY3MoKWAgYW5kIGBnZXRfc2lnbmlmaWNhbnRfcmVzdWx0cygpYC4gDQoNCkxldCdzIHRyeSBvdXQgYW5kIHNlZSB3aGF0IGBnZXRfc3RhdGlzdGljcygpYCBkb2VzOg0KDQpgYGB7cn0NCmdldF9zdGF0aXN0aWNzKG15X3Jlc3VsdF9vYmplY3QpDQpgYGANCg0KYGBge3J9DQpnZXRfc3RhdGlzdGljcw0Kc2hvd01ldGhvZHMoImdldF9zdGF0aXN0aWNzIikNCmdldE1ldGhvZChmPSJnZXRfc3RhdGlzdGljcyIsIHNpZ25hdHVyZSA9IHNpZ25hdHVyZSgiU3RhdFBhY2thZ2VSZXN1bHQiKSkNCmBgYA0KDQpIb3cgZG8gd2Uga25vdyBhYm91dCB0aGUgbWV0aG9kcyB0aGF0IGJlbG9uZyB0byBhIGNsYXNzPyBIb3BlZnVsbHksIHRoaXMgaXMgZG9jdW1lbnRlZCBpbiB0aGUgZG9jdW1lbnRhdGlvbiBhYm91dCB0aGUgY2xhc3MuDQoNCkhvd2V2ZXIsIG9uZSBiaWcgaXNzdWUgaXMgdGhhdCB0aGVyZSBpcyBubyBlYXN5IHdheSB0byBmaW5kIGFsbCB0aGUgbWV0aG9kcyB0aGF0IGFjdCB1cG9uIHRoZSBjbGFzcyB0aGF0IGFyZSBpbiBvdGhlciBwYWNrYWdlcy4NCg0KIyBQUk9CTEVNDQoNClRoZXJlIGlzIGFub3RoZXIgbWV0aG9kIGZvciBvdXIgYFN0YXRzUGFja2FnZVJlc3VsdGAgY2xhc3M6IGBnZXRfc2lnbmlmaWNhbnRfcmVzdWx0cygpYC4gVHJ5IGl0IG91dCBiZWxvdzoNCg0KYGBge3J9DQpnZXRfc2lnbmlmaWNhbnRfcmVzdWx0cyhteV9yZXN1bHRfb2JqZWN0LCBjdXRvZmYgPSAwLjEpDQpgYGANCg0KU2hvdyB0aGUgbWV0aG9kIGNvZGUgZm9yIGBnZXRfc2lnbmlmaWNhbnRfcmVzdWx0cygpYC4gSGludDogeW91J2xsIGhhdmUgdG8gZmluZCB0aGUgc2lnbmF0dXJlIGZvciB0aGUgbWV0aG9kIGJlZm9yZSB5b3UgY2FuIHVzZSBgZ2V0TWV0aG9kKClgIA0KDQpgYGB7cn0NCiMjU3BhY2UgZm9yIHlvdXIgYW5zd2VyIGhlcmUNCg0KDQpgYGANCg0KIyBNYWtpbmcgYSBuZXcgYFN0YXRzUGFja2FnZVJlc3VsdGAgb2JqZWN0L1R5cGUgQ2hlY2tpbmcNCg0KTm93IHRoYXQgeW91IHNlZSB0aGUgYmFzaWNzIGJlaGluZCB0aGUgYFN0YXRzUGFja2FnZVJlc3VsdGAgY2xhc3MsIHlvdSBjYW4gbm93IG1ha2UgYSBgU3RhdHNQYWNrYWdlUmVzdWx0YCBvYmplY3QuIFlvdSB3aWxsIHByb2JhYmx5IGRvIHRoaXMgaW4geW91ciBwYWNrYWdlIGNvZGUgd2hlbiB5b3UncmUgcmV0dXJuaW5nIGEgcmVzdWx0LiANCg0KVGhlIGBTdGF0c1BhY2thZ2VSZXN1bHQoKWAgZnVuY3Rpb24gaXMgY2FsbGVkIGFuICpjb25zdHJ1Y3RvciouIFdlIG5lZWQgdG8gZ2l2ZSBpdCB2YWx1ZXMgZm9yIGVhY2ggb2YgdGhlIHNsb3RzIHRvIG1ha2UgYSB2YWxpZCBvYmplY3QuIChUaGVyZSBpcyBhbHNvIGEgd2F5IHRvIG1ha2UgYSBuZXcgb2JqZWN0IHdpdGggdGhlIGBuZXcoKWAgZnVuY3Rpb24sIGJ1dCBpdCdzIGN1cnJlbnRseSBub3QgcmVjb21tZW5kZWQuKQ0KDQpgYGB7cn0NCiNmaXJzdCBkZWZpbmUgdGhlIHN0YXRpc3RpY3Mgc2xvdA0Kc3RhdF9mcmFtZSA8LSBkYXRhLmZyYW1lKGdyb3VwPWMoInNldG9zYSIsICJ2aXJnaW5pY2EiLCAidmVyc2ljb2xvciIpLCBwdmFsdWU9YygwLjUsIDAuMiwgMC4wMDEpKQ0KDQpteV9zNF9vYmplY3RfbmV3IDwtIFN0YXRQYWNrYWdlUmVzdWx0KGRhdGEgPSBpcmlzLCBzdGF0aXN0aWNzID0gc3RhdF9mcmFtZSkNCmBgYA0KDQpXZSBrbm93IHRoYXQgdGhlIHJlcXVpcmVkIHNsb3RzIGFyZSBmb3IgYGRhdGFgLCB3aGljaCBuZWVkcyB0byBiZSBhIGBkYXRhLmZyYW1lYCwgYW5kIGBzdGF0aXN0aWNzYCwgd2hpY2ggYWxzbyBuZWVkcyB0byBiZSBhIGBkYXRhLmZyYW1lYC4gV2hhdCBpZiB3ZSBtYWtlIGEgbmV3IG9iamVjdCB3aGVyZSBgc3RhdGlzdGljc2AgaXMgYSBgdmVjdG9yYD8NCg0KYGBge3J9DQpjdyA8LSBhcy5kYXRhLmZyYW1lKENoaWNrV2VpZ2h0KQ0KbmV3X29iaiA8LSBTdGF0UGFja2FnZVJlc3VsdChkYXRhPWN3LCBzdGF0aXN0aWNzPWMoMSwxLDEpKQ0KYGBgDQoNCldoYXQgaGFwcGVucyB3aGVuIHlvdSBvbmx5IHByb3ZpZGUgYSBgZGF0YWAgYXJndW1lbnQ/IFdoYXQgaGFwcGVucz8NCg0KYGBge3J9DQpjdyA8LSBkYXRhLmZyYW1lKENoaWNrV2VpZ2h0KQ0KbmV3X29iajIgPC0gU3RhdFBhY2thZ2VSZXN1bHQoZGF0YT1jdykNCmBgYA0KDQpXZSBhbHNvIGhhdmUgYSByZXF1aXJlbWVudCB0aGF0IHRoZSBgc3RhdGlzdGljc2Agc2xvdCBoYXMgYSBgZGF0YS5mcmFtZWAgd2l0aCB0aGUgbmFtZSBgcHZhbHVlYC4gV2UnbGwgc2VlIGhvdyB3ZSBkaWQgdGhpcyBpbiB0aGUgYFZhbGlkaXR5YCBzZWN0aW9uIGJlbG93Lg0KDQpgYGB7cn0NCm5ld19vYmozIDwtIFN0YXRQYWNrYWdlUmVzdWx0KGRhdGE9Y3csIHN0YXRpc3RpY3M9Y3cpDQpgYGANCg0KIyBIb3cgZGlkIHdlIGRlZmluZSB0aGUgYFN0YXRzUGFja2FnZVJlc3VsdGAgQ2xhc3M/DQoNClRha2UgYSBsb29rIGF0IGBSL2NsYXNzZXMtUzQuUmAuIFRoZSBmaXJzdCB0aGluZyB3ZSBkaWQgd2FzIGRlZmluZSB0aGUgY2xhc3Mgd2l0aCBgc2V0Q2xhc3NgLCB3aGVyZSB3ZSBjYW4gc3BlY2lmeSB0aGUgZGF0YSB0eXBlcyBvZiBlYWNoIG9mIHRoZSBzbG90cy4gTm90ZSB0aGF0IHRoaXMgYWxzbyBkZWZpbmVzIHdoYXQncyBjYWxsZWQgdGhlICpjb25zdHJ1Y3RvciosIG9yIHRoZSBmdW5jdGlvbiB0aGF0IGxldHMgdXMgbWFrZSBuZXcgb2JqZWN0cy4NCg0KYGBgDQpTdGF0UGFja2FnZVJlc3VsdCA8LSBzZXRDbGFzcygiU3RhdFBhY2thZ2VSZXN1bHQiLA0KICAgICAgICAgICAgICAgICAgICAgICBzbG90cyA9IGMoZGF0YSA9ICJkYXRhLmZyYW1lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRpc3RpY3MgPSAiZGF0YS5mcmFtZSIpLA0KICAgICAgICAgICAgICAgICAgICAgICBwcm90b3R5cGUgPSBjKGRhdGE9TkEsIHN0YXRpc3RpY3M9TkEpDQogICAgICAgICAgICAgICAgICAgICAgICkNCmBgYA0KDQojIERlZmluaW5nIG1ldGhvZHMgZm9yIGBTdGF0c1BhY2thZ2VSZXN1bHRgDQoNClM0IG1ldGhvZHMgYXJlIGRlc2lnbmVkIHRvIGJlIGZsZXhpYmxlLiBUaGUgZG93bnNpZGUgdG8gdGhlIGZsZXhpYmlsaXR5IGlzIHRoYXQgdGhleSBhcmUgYSBsaXR0bGUgaGFyZGVyIHRvIHByb2dyYW0gd2l0aCBhbmQgc2V0IHVwLiBXaGVyZWFzIGluIFMzLCB3ZSBjb3VsZCBkZWZpbmUgYSBtZXRob2QgZm9yIG91ciBTMyBjbGFzcyBieSBqdXN0IG5hbWluZyBhIGZ1bmN0aW9uIHdpdGggYSBkb3QgKHN1Y2ggYXMgYHByaW50LnN0YXRzX3Jlc3VsdGApLCBTNCByZXF1aXJlcyB1cyB0byBmaXJzdCBlc3RhYmxpc2ggYSBgZ2VuZXJpY2AgZnVuY3Rpb24uIA0KDQpUaGUgYGdlbmVyaWNgIGZ1bmN0aW9uIGlzIGRlc2lnbmVkIHRvIHVzZSBkaWZmZXJlbnQgY29kZSBiYXNlZCBvbiB0aGUgY2xhc3Mgb2YgdGhlIG9iamVjdCwgbXVjaCBsaWtlIFM0IGdlbmVyaWNzLiBUYWtlIGEgbG9vayBhdCB0aGUgZ2VuZXJpYyBtZXRob2QgYHNob3dgLiBZb3UgY2FuIHNlZSBhbGwgb2YgdGhlIGRpZmZlcmVudCBjbGFzc2VzIGl0IHdvcmtzIG9uLiBUaGlzIGBvYmplY3Q9Ik1vZHVsZSJgIGlzIGNhbGxlZCBhICpzaWduYXR1cmUqLCBhbmQgaXQgZGVmaW5lcyBob3cgdGhlIGdlbmVyaWMgZnVuY3Rpb24gZGVjaWRlcyB3aGljaCBtZXRob2QgY29kZSB0byBkaXNwYXRjaC4NCg0KSGVyZSBhcmUgYWxsIHRoZSBTNCBtZXRob2RzIGZvciB0aGUgYHNob3dgIGdlbmVyaWMgZnVuY3Rpb24gYmFzZWQgb24gdGhlaXIgc2lnbmF0dXJlOg0KDQpgYGB7cn0NCnNob3dNZXRob2RzKCJzaG93IikNCmBgYA0KDQpCZWNhdXNlIG1ldGhvZHMgY2FuIGJlIGRpc3BhdGNoZWQgb24gbXVsdGlwbGUgc2lnbmF0dXJlcywgeW91IGZpcnN0IGhhdmUgdG8gZGVmaW5lIHRoZSBtZXRob2QgdXNpbmcgYHNldEdlbmVyaWMoKWA6DQoNCmBgYA0KI2Fsd2F5cyBuZWVkIHRvIGRlZmluZSB0aGUgZ2VuZXJpYyBtZXRob2QgZmlyc3QNCnNldEdlbmVyaWMobmFtZT0gInN0YXRpc3RpY3MiLCANCiAgICAgICAgICAgZGVmPSBmdW5jdGlvbihvYmplY3QpIHsNCiAgICAgICAgICAgICBzdGFuZGFyZEdlbmVyaWMoInN0YXRpc3RpY3MiKQ0KICAgICAgICAgICAgIH0NCiAgICAgICAgICAgKQ0KYGBgDQpUaGlzIGNyZWF0ZXMgYSAqZ2VuZXJpYyogZnVuY3Rpb24gY2FsbGVkIGBzdGF0aXN0aWNzYCwgd2hpY2ggaGFzIGEgc2luZ2xlIGFyZ3VtZW50OiBgb2JqZWN0YC4gTm90ZSB0aGF0IGBvYmplY3RgIGlzbid0IGxpbWl0ZWQgdG8gb3VyIGBTdGF0c1BhY2thZ2VSZXN1bHRgIGNsYXNzLiBXZSBjb3VsZCBhbHNvIGRlZmluZSBhIGBzdGF0aXN0aWNzYCBtZXRob2QgZm9yIG90aGVyIFM0IG9iamVjdHMuDQoNCk9uY2UgdGhlIGdlbmVyaWMgaXMgY3JlYXRlZCwgeW91IGNhbiBub3cgZGVmaW5lIGEgbWV0aG9kIGZvciB5b3VyIGNsYXNzLiANCg0KYGBgDQojZGVmaW5lIHRoZSBmdW5jdGlvbg0Kc2V0TWV0aG9kKGY9InN0YXRpc3RpY3MiLA0KICAgICAgICAgICNzaWduYXR1cmUgaXMgaG93IHRoZSBmdW5jdGlvbiBpcyBjYWxsZWQNCiAgICAgICAgICBzaWduYXR1cmUgPSBzaWduYXR1cmUoIlN0YXRQYWNrYWdlUmVzdWx0IiksIA0KICAgICAgICAgIGRlZmluaXRpb24gPSBmdW5jdGlvbihvYmplY3Qpew0KICAgICAgICAgICAgcmV0dXJuKG9iamVjdEBzdGF0aXN0aWNzKQ0KICAgICAgICAgIH0pDQpgYGANCg0KIyBWYWxpZGl0eQ0KDQpTYXkgeW91IG5lZWQgdG8gaGF2ZSBhbm90aGVyIHJlcXVpcmVtZW50IGZvciB0aGUgYGRhdGEuZnJhbWVgIGluIHRoZSBgc3RhdGlzdGljc2Agc2xvdCwgc3VjaCBhcyByZXF1aXJpbmcgYSBjb2x1bW4gY2FsbGVkIGBwdmFsdWVgLiBXZSBjYW4gZG8gdGhpcyBieSBhZGRpbmcgYSB2YWxpZGl0eSBmdW5jdGlvbiB1c2luZyBgc2V0VmFsaWRpdHlgOg0KDQpgYGANCmNoZWNrX3N0YXRzX29iamVjdCA8LSBmdW5jdGlvbihvYmplY3Qpew0KICAjY2hlY2sgd2hldGhlciBzdGF0aXN0aWNzIGRhdGEuZnJhbWUgY29udGFpbnMgInB2YWx1ZSINCiAgI2FzIGNvbHVtbiBuYW1lDQogIGlmKCJwdmFsdWUiICVpbiUgY29sbmFtZXMoZ2V0X3N0YXRpc3RpY3Mob2JqZWN0KSkpIHtUUlVFfQ0KICBlbHNleyAic3RhdGlzdGljcyBzbG90IG5lZWRzIGEgcHZhbHVlIGNvbHVtbiJ9DQp9DQoNCnNldFZhbGlkaXR5KCJTdGF0c1Jlc3VsdE9iamVjdCIsIGNoZWNrX3N0YXRzX29iamVjdCkNCg0KYGBgDQoNCiMgSW5oZXJpdGFuY2UNCg0KVGhlIGJlc3QgdGhpbmcgYWJvdXQgT2JqZWN0IE9yaWVudGVkIFByb2dyYW1taW5nIGlzIHRoYXQgeW91IGRvbid0IGhhdmUgdG8gcmVpbnZlbnQgdGhlIHdoZWVsLiBZb3UgY2FuICpleHRlbmQqIGEgY3VycmVudCBjbGFzcyBkZWZpbml0aW9uIHRvIG1ha2UgYSBuZXcgY2xhc3MuIEhlcmUgd2UncmUgbWFraW5nIGEgbmV3IGNsYXNzIGBBbm92YVJlc3VsdGAgdGhhdCBpcyBiYXNlZCBvbiBvdXIgYFN0YXRQYWNrYWdlUmVzdWx0YC4gWW91IGNhbiBzZWUgd2UgdXNlIHRoZSBgY29udGFpbnNgIGFyZ3VtZW50IHRvIHNheSB3ZSdyZSBleHRlbmRpbmcgYFN0YXRQYWNrYWdlUmVzdWx0YC4gDQoNCkFsc28sIG5vdGUgd2UncmUgYWRkaW5nIGEgYGdyb3Vwc2Agc2xvdC4gVGhlIG90aGVyIHNsb3RzIGZyb20gYFN0YXRQYWNrYWdlUmVzdWx0YCwgYGRhdGFgIGFuZCBgc3RhdGlzdGljc2AgYXJlICppbmhlcml0ZWQqIGZyb20gYFN0YXRQYWNrYWdlUmVzdWx0YC4NCg0KYGBgDQojSW5oZXJpdGFuY2U6IG1ha2luZyBhIG5ldyBjbGFzcyBmcm9tIG91ciBvbGQgY2xhc3MNCkFub3ZhUmVzdWx0IDwtIHNldENsYXNzKCJBbm92YVJlc3VsdCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgY29udGFpbnM9ICJTdGF0UGFja2FnZVJlc3VsdCIsDQogICAgICAgICAgICAgICAgICAgICAgICBzbG90cz1jKGdyb3Vwcz0iY2hhcmFjdGVyIikpDQpgYGANCg0KYGBge3J9DQpzdGF0X2ZyYW1lIDwtIGRhdGEuZnJhbWUoZ3JvdXA9Yygic2V0b3NhIiwgInZpcmdpbmljYSIsICJ2ZXJzaWNvbG9yIiksIHB2YWx1ZT1jKDAuNSwgMC4yLCAwLjAwMSkpDQpncm91cHMgPC0gYygic2V0b3NhIiwgInZpcmdpbmljYSIsICJ2ZXJzaWNvbG9yIikNCg0KYW5vdmFfcmVzdWx0X3M0IDwtIEFub3ZhUmVzdWx0KGRhdGEgPSBpcmlzLCBzdGF0aXN0aWNzID0gc3RhdF9mcmFtZSwgZ3JvdXBzPWdyb3VwcykNCg0KI2dldCB0aGUgY2xhc3MgZGVmaW5pdGlvbg0KZ2V0Q2xhc3MoIkFub3ZhUmVzdWx0IikNCmBgYA0KDQpTaG93IHRoZSBuZXcgc3RydWN0dXJlIG9mIG91ciBpbmhlcml0ZWQgb2JqZWN0Lg0KDQpgYGB7cn0NCnN0cihhbm92YV9yZXN1bHRfczQpDQpgYGANCg0KIyBFeHRlbmRpbmcgbWV0aG9kcyBmcm9tIGEgc3VwZXJsY2Fzcw0KDQpNZXRob2RzIGFyZSBjbGFzcyBzcGVjaWZpYywgYnV0IHRoZXkgYWxzbyBpbmhlcml0IGZyb20gdGhlICpzdXBlciogY2xhc3MgdGhhdCBvdXIgbmV3IGNsYXNzIGlzIGRlcml2ZWQgZnJvbS4gVGhpcyBtZWFucyB5b3UgY2FuIGFkZCBleHRyYSBjb2RlIHRvIGEgbWV0aG9kIGJ5ICpvdmVycmlkaW5nKiB0aGUgbWV0aG9kIGZvciB0aGUgbmV3IGNsYXNzIGFuZCB1c2luZyBgY2FsbE5leHRNZXRob2QoKWAgdG8gZXhlY3V0ZSB0aGUgY29kZSBiZWxvbmdpbmcgdG8gdGhlIHN1cGVyY2xhc3MgKHdoaWNoIGlzIGBTdGF0UGFja2FnZVJlc3VsdGApLg0KDQpgYGANCiNPdmVycmlkaW5nIHRoZSBnZXRfc3RhdGlzdGljcyBtZXRob2QgZm9yIFN0YXRQYWNrYWdlUmVzdWx0DQpzZXRNZXRob2QoImdldF9zdGF0aXN0aWNzIiwNCiAgICAgICAgICBzaWduYXR1cmUgPSBzaWduYXR1cmUob2JqZWN0ID0gIkFub3ZhUmVzdWx0IiksDQoNCiAgICAgICAgICAgIGRlZmluaXRpb24gPSBmdW5jdGlvbihvYmplY3Qpew0KICAgICAgICAgICAgICAgIHByaW50KG9iamVjdEBncm91cHMpDQogICAgICAgICAgICAgICAgI25vdyBydW4gdGhlIGNvZGUgdGhhdCBiZWxvbmdzIHRvIHRoZSBtZXRob2QNCiAgICAgICAgICAgICAgICAjZm9yIHRoZSBzdXBlcmNsYXNzICgiU3RhdFBhY2thZ2VSZXN1bHQiKQ0KICAgICAgICAgICAgICAgIGNhbGxOZXh0TWV0aG9kKG9iamVjdCkNCiAgICAgICAgICAgICAgfQ0KICAgICAgICAgICkNCmBgYA0KVHJ5IHJ1bm5pbmcgYGdldF9zdGF0aXN0aWNzKClgIG9uIGBhbm92YV9yZXN1bHRfczRgLiBJdCB3aWxsIGZpcnN0IHByaW50IG91dCBgZ3JvdXBgIGFuZCB0aGVuIHJldHVybiB0aGUgYHN0YXRpc3RpY3NgIHNsb3QuDQoNCmBgYHtyfQ0KZ2V0X3N0YXRpc3RpY3MoYW5vdmFfcmVzdWx0X3M0KQ0KYGBgDQoNCiMgV2hhdCB3ZSBkaWRuJ3QgY292ZXIgdG9kYXk6DQoNCi0gVXBkYXRpbmcgb2xkIG9iamVjdHMNCi0gR2V0dGluZyBTMyBhbmQgUzQgdG8gd29yayB0b2dldGhlcg0KLSBNdWx0aXBsZSBJbmhlcml0YW5jZSBhbmQgRGlzcGF0Y2gNCiAgLSBUaGUgYWJpbGl0eSBvZiBhIGNsYXNzIHRvIGluaGVyaXQgZnJvbSBtdWx0aXBsZSBjbGFzc2VzDQogIC0gSGFkbGV5IGNvdmVycyB0aGlzIG11Y2ggYmV0dGVyIHRoYW4gSSBjb3VsZDogaHR0cHM6Ly9hZHYtci5oYWRsZXkubnovczQuaHRtbCNzNC1kaXNwYXRjaA0KDQojIFJlc291cmNlcw0KDQpQb3J0aW9ucyBvZiB0aGlzIG5vdGVib29rIHdlcmUgZ3JhdGVmdWxseSBhZGFwdGVkIGZyb206DQoNCi0gUzQgQ2xhc3NlcyBhbmQgTWV0aG9kczogaHR0cHM6Ly9rYXNwZXJkYW5pZWxoYW5zZW4uZ2l0aHViLmlvL2dlbmJpb2NvbmR1Y3Rvci9odG1sL1JfUzQuaHRtbA0KLSBBIHByYWN0aWNhbCBUdXRvcmlhbCBvbiBTNCBQcm9ncmFtbWluZzogaHR0cHM6Ly93d3cuYmlvY29uZHVjdG9yLm9yZy9oZWxwL2NvdXJzZS1tYXRlcmlhbHMvMjAxMy9DU0FNQTIwMTMvZnJpZGF5L2FmdGVybm9vbi9TNC10dXRvcmlhbC5wZGYNCi0gaHR0cHM6Ly93d3cuY3ljbGlzbW8ub3JnL3R1dG9yaWFsL1IvczRDbGFzc2VzLmh0bWwNCi0gQWR2YW5jZWQgUjogaHR0cHM6Ly9hZHYtci5oYWRsZXkubnov