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.frames 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:

Resources

Portions of this notebook were gratefully adapted from:

LS0tDQp0aXRsZTogIlM0IE9iamVjdHMiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCmF1dGhvcjogVGVkIExhZGVyYXMNCi0tLQ0KDQojIEJlZm9yZSB5b3Ugc3RhcnQNCg0KTWFrZSBzdXJlIHRoYXQgeW91J3ZlIGNsaWNrZWQgb24gdGhlIGBvb3BfdGFsay5ycHJvamAgZmlsZSB0byBvcGVuIHRoaXMgZm9sZGVyIGFzIGEgcHJvamVjdC4NCg0KIyBXaGF0IGFyZSBTNCBPYmplY3RzPw0KDQpTNCBvYmplY3RzIGFyZSBsaWtlIFMzIG9iamVjdHMsIGJ1dCBhcmUgc3RyaWN0ZXIuIFdoZXJlYXMgYW4gUzMgb2JqZWN0IGlzIGEgbGlzdCwgYW5kIHlvdSBjYW4gcHV0IGFueXRoaW5nIGluIHRoZSBsaXN0LCBTNCBvYmplY3RzIGhhdmUgKnNsb3RzKjogdGhlc2UgYXJlIHNwZWNpZmljIGRhdGEgdHlwZXMsIHN1Y2ggYXMgYHZlY3RvcnNgLCBgZGF0YS5mcmFtZXNgLiBZb3UgY2FuIGFsc28gcHV0IGFkZGl0aW9uYWwgcmVzdHJpY3Rpb25zIG9uIHRoZXNlIGRhdGEgZnJhbWVzLg0KDQpJbiBTMywgeW91IGNhbiBsaXRlcmFsbHkgY2hhbmdlIHRoZSBjbGFzcyBvZiBhbnkgb2JqZWN0IGJ5IHVzaW5nIHRoZSBgY2xhc3MoKWAgZnVuY3Rpb246DQoNCmBgYHtyfQ0KbXlfbGlzdCA8LSBsaXN0KGE9ImJsYWgiLCBiPWMoMSwyLDMpKQ0KY2xhc3MobXlfbGlzdCkgPC0gIm5ld2NsYXNzIg0KY2xhc3MobXlfbGlzdCkNCmBgYA0KDQpUaGlzIGZsZXhpYmlsaXR5IGNhbiBiZSBhIHZlcnkgYmFkIHRoaW5nIHdoZW4gdHJ5aW5nIHRvIGdldCBhIGRhdGEgc3RydWN0dXJlIHRvIHdvcmsgY29uc2lzdGVudGx5IGFjcm9zcyBhIGJ1bmNoIG9mIHBhY2thZ2VzLiBUaGluZ3MgbWlnaHQgbm90IHdvcmsgbGlrZSB5b3UgZXhwZWN0IHRoZW0gdG8sIG9yIHdvcnNlLCB0aGUgbG9vc2UgZGVmaW5pdGlvbiBvZiB0aGUgb2JqZWN0IGNhbiBjYXVzZSBjb21wYXRpYmlsaXR5IGlzc3VlcyBkb3duIHRoZSBsaW5lLiBTbyB0aGF0J3Mgd2h5IHlvdSB3b3VsZCB3YW50IHRvIGJlIHN0cmljdC4NCg0KUzQgYWxzbyBoYXMgKm1ldGhvZHMqIGxpa2UgKlMzKiwgYW5kIHlvdSBhbHNvIGhhdmUgdG8gYmUgc3RyaWN0IGFib3V0IHdoYXQgYXJndW1lbnRzIGdvIGludG8gZWFjaCBtZXRob2QuIFM0IGRvZXMgdGhpcyBieSBmaXJzdCBkZWZpbmluZyBhIGdlbmVyaWMgZnVuY3Rpb24sIGFuZCB0aGVuIHNwZWNpZnlpbmcgYSBtZXRob2Qgd2l0aCBzdHJpY3QgdHlwaW5nLg0KDQojIFByb3BlcnRpZXMgb2YgUzQgT2JqZWN0cw0KDQojIyBMb2FkaW5nIGFuIE9iamVjdA0KDQpXZSdyZSBnb2luZyB0byBsb2FkIGFuIG9iamVjdCBjYWxsZWQgYG15X3Jlc3VsdF9vYmplY3RgLCB3aGljaCBoYXMgdGhlIGNsYXNzIGBTdGF0c1BhY2thZ2VSZXN1bHRgLiANCg0KYGBge3J9DQpzb3VyY2UoIlIvY2xhc3Nlcy1TNC5SIikNCiN3ZSB1c2UgaGVyZQ0KbGlicmFyeShoZXJlKQ0KbXlfcmVzdWx0X29iamVjdCA8LSByZWFkUkRTKGhlcmUoImRhdGEvczRfc3RhdF9yZXN1bHQucmRzIikpDQpgYGANCg0KIyMgV2hhdCBjbGFzcyBpcyBteSBvYmplY3Q/DQoNCmBgYHtyfQ0KY2xhc3MobXlfcmVzdWx0X29iamVjdCkNCmBgYA0KDQpPa2F5IHdlIGhhdmUgYW4gb2JqZWN0LCBidXQgaG93IGRvIHdlIGtub3cgaXQncyBhbiBTNCBvYmplY3Q/DQoNCmBgYHtyfQ0KaXNTNChteV9yZXN1bHRfb2JqZWN0KQ0KYGBgDQoNCiMjIFNsb3RzDQoNCkhlcmUgd2UgY2FuIHNlZSB0aGUgYHNsb3RzYCBvZiBgbXlfcmVzdWx0X29iamVjdGAuIFNsb3RzIGhvbGQgZGlmZmVyZW50IHBhcnRzIG9mIHRoZSBkYXRhIG9iamVjdC4gV2UgaGF2ZSB0byBiZSBleHBsaWNpdCBpbiB3aGF0IGRhdGEgdHlwZXMgZ28gaW4gdGhlbS4NCg0KYGBge3J9DQpzbG90TmFtZXMobXlfcmVzdWx0X29iamVjdCkNCmBgYA0KDQpXZSBjYW4gYWxzbyBhc2sgYWJvdXQgdGhlIFM0IGNsYXNzIC0gdGhpcyBnaXZlcyB1cyBtb3JlIGluZm9ybWF0aW9uIGFib3V0IHdoYXQgaXMgaW4gdGhlIGluZGl2aWR1YWwgc2xvdHM6DQoNCmBgYHtyfQ0KDQpnZXRTbG90cygiU3RhdFBhY2thZ2VSZXN1bHQiKQ0KYGBgDQoNCiMjIFdlIG5lZWQgbW9yZSBpbmZvDQoNCldlIGNhbiB1c2UgdGhlIGBnZXRDbGFzc2AgZnVuY3Rpb24gdG8gZ2V0IG1vcmUgaW5mbyBhYm91dCB0aGUgYFN0YXRzUGFja2FnZVJlc3VsdGAgY2xhc3MuDQoNCmBgYHtyfQ0KZ2V0Q2xhc3MoIlN0YXRQYWNrYWdlUmVzdWx0IikNCmBgYA0KDQojIyBMb29raW5nIGF0IHRoZSBvYmplY3QncyBzdHJ1Y3R1cmUNCg0KV2UgY2FuIHVzZSB0aGUgYHN0cigpYCBmdW5jdGlvbiB0byBsb29rIGF0IHRoZSBvdmVyYWxsIHN0cnVjdHVyZSBvZiBvdXIgb2JqZWN0LiBXZSBjYW4gc2VlIGluZm9ybWF0aW9uIGFib3V0IHRoZSBhY3R1YWwgYGRhdGEuZnJhbWVgcyBpbiB0aGUgYGRhdGFgIHNsb3QgYW5kIHRoZSBgc3RhdGlzdGljc2Agc2xvdC4NCg0KYGBge3J9DQpzdHIobXlfcmVzdWx0X29iamVjdCkNCg0KYGBgDQoNCiMjIEFjY2Vzc2luZyBhIHNsb3QgZGlyZWN0bHkNCg0KUzQgdXNlcyB0aGUgYEBgIHNpZ24gaW5zdGVhZCBvZiB0aGUgYCRgIHNpZ24gdG8gYWNjZXNzIHRoZSBkYXRhIGluIGEgc2xvdC4NCg0KYGBge3J9DQpnbGltcHNlKG15X3Jlc3VsdF9vYmplY3RAZGF0YSkNCmBgYA0KDQojIE1ldGhvZHMNCg0KV2UndmUgZGVmaW5lZCB0d28gbWV0aG9kcyB0aGF0IHdvcmsgb24gb3VyIGNsYXNzOiBgZ2V0X3N0YXRpc3RpY3MoKWAgYW5kIGBnZXRfc2lnbmlmaWNhbnRfcmVzdWx0cygpYC4gDQoNCkxldCdzIHRyeSBvdXQgYW5kIHNlZSB3aGF0IGBnZXRfc3RhdGlzdGljcygpYCBkb2VzOg0KDQpgYGB7cn0NCmdldF9zdGF0aXN0aWNzKG15X3Jlc3VsdF9vYmplY3QpDQpgYGANCg0KYGBge3J9DQpnZXRfc3RhdGlzdGljcw0Kc2hvd01ldGhvZHMoImdldF9zdGF0aXN0aWNzIikNCmdldE1ldGhvZChmPSJnZXRfc3RhdGlzdGljcyIsIHNpZ25hdHVyZSA9IHNpZ25hdHVyZSgiU3RhdFBhY2thZ2VSZXN1bHQiKSkNCmBgYA0KDQpIb3cgZG8gd2Uga25vdyBhYm91dCB0aGUgbWV0aG9kcyB0aGF0IGJlbG9uZyB0byBhIGNsYXNzPyBIb3BlZnVsbHksIHRoaXMgaXMgZG9jdW1lbnRlZCBpbiB0aGUgZG9jdW1lbnRhdGlvbiBhYm91dCB0aGUgY2xhc3MuDQoNCkhvd2V2ZXIsIG9uZSBiaWcgaXNzdWUgaXMgdGhhdCB0aGVyZSBpcyBubyBlYXN5IHdheSB0byBmaW5kIGFsbCB0aGUgbWV0aG9kcyB0aGF0IGFjdCB1cG9uIHRoZSBjbGFzcyB0aGF0IGFyZSBpbiBvdGhlciBwYWNrYWdlcy4NCg0KIyBQUk9CTEVNDQoNClRoZXJlIGlzIGFub3RoZXIgbWV0aG9kIGZvciBvdXIgYFN0YXRzUGFja2FnZVJlc3VsdGAgY2xhc3M6IGBnZXRfc2lnbmlmaWNhbnRfcmVzdWx0cygpYC4gVHJ5IGl0IG91dCBiZWxvdzoNCg0KYGBge3J9DQpnZXRfc2lnbmlmaWNhbnRfcmVzdWx0cyhteV9yZXN1bHRfb2JqZWN0LCBjdXRvZmYgPSAwLjEpDQpgYGANCg0KU2hvdyB0aGUgbWV0aG9kIGNvZGUgZm9yIGBnZXRfc2lnbmlmaWNhbnRfcmVzdWx0cygpYC4gSGludDogeW91J2xsIGhhdmUgdG8gZmluZCB0aGUgc2lnbmF0dXJlIGZvciB0aGUgbWV0aG9kIGJlZm9yZSB5b3UgY2FuIHVzZSBgZ2V0TWV0aG9kKClgIA0KDQpgYGB7cn0NCiMjU3BhY2UgZm9yIHlvdXIgYW5zd2VyIGhlcmUNCg0KDQpgYGANCg0KIyBNYWtpbmcgYSBuZXcgYFN0YXRzUGFja2FnZVJlc3VsdGAgb2JqZWN0L1R5cGUgQ2hlY2tpbmcNCg0KTm93IHRoYXQgeW91IHNlZSB0aGUgYmFzaWNzIGJlaGluZCB0aGUgYFN0YXRzUGFja2FnZVJlc3VsdGAgY2xhc3MsIHlvdSBjYW4gbm93IG1ha2UgYSBgU3RhdHNQYWNrYWdlUmVzdWx0YCBvYmplY3QuIFlvdSB3aWxsIHByb2JhYmx5IGRvIHRoaXMgaW4geW91ciBwYWNrYWdlIGNvZGUgd2hlbiB5b3UncmUgcmV0dXJuaW5nIGEgcmVzdWx0LiANCg0KVGhlIGBTdGF0c1BhY2thZ2VSZXN1bHQoKWAgZnVuY3Rpb24gaXMgY2FsbGVkIGFuICpjb25zdHJ1Y3RvciouIFdlIG5lZWQgdG8gZ2l2ZSBpdCB2YWx1ZXMgZm9yIGVhY2ggb2YgdGhlIHNsb3RzIHRvIG1ha2UgYSB2YWxpZCBvYmplY3QuIChUaGVyZSBpcyBhbHNvIGEgd2F5IHRvIG1ha2UgYSBuZXcgb2JqZWN0IHdpdGggdGhlIGBuZXcoKWAgZnVuY3Rpb24sIGJ1dCBpdCdzIGN1cnJlbnRseSBub3QgcmVjb21tZW5kZWQuKQ0KDQpgYGB7cn0NCiNmaXJzdCBkZWZpbmUgdGhlIHN0YXRpc3RpY3Mgc2xvdA0Kc3RhdF9mcmFtZSA8LSBkYXRhLmZyYW1lKGdyb3VwPWMoInNldG9zYSIsICJ2aXJnaW5pY2EiLCAidmVyc2ljb2xvciIpLCBwdmFsdWU9YygwLjUsIDAuMiwgMC4wMDEpKQ0KDQpteV9zNF9vYmplY3RfbmV3IDwtIFN0YXRQYWNrYWdlUmVzdWx0KGRhdGEgPSBpcmlzLCBzdGF0aXN0aWNzID0gc3RhdF9mcmFtZSkNCmBgYA0KDQpXZSBrbm93IHRoYXQgdGhlIHJlcXVpcmVkIHNsb3RzIGFyZSBmb3IgYGRhdGFgLCB3aGljaCBuZWVkcyB0byBiZSBhIGBkYXRhLmZyYW1lYCwgYW5kIGBzdGF0aXN0aWNzYCwgd2hpY2ggYWxzbyBuZWVkcyB0byBiZSBhIGBkYXRhLmZyYW1lYC4gV2hhdCBpZiB3ZSBtYWtlIGEgbmV3IG9iamVjdCB3aGVyZSBgc3RhdGlzdGljc2AgaXMgYSBgdmVjdG9yYD8NCg0KYGBge3J9DQpjdyA8LSBhcy5kYXRhLmZyYW1lKENoaWNrV2VpZ2h0KQ0KbmV3X29iaiA8LSBTdGF0UGFja2FnZVJlc3VsdChkYXRhPWN3LCBzdGF0aXN0aWNzPWMoMSwxLDEpKQ0KYGBgDQoNCldoYXQgaGFwcGVucyB3aGVuIHlvdSBvbmx5IHByb3ZpZGUgYSBgZGF0YWAgYXJndW1lbnQ/IFdoYXQgaGFwcGVucz8NCg0KYGBge3J9DQpjdyA8LSBkYXRhLmZyYW1lKENoaWNrV2VpZ2h0KQ0KbmV3X29iajIgPC0gU3RhdFBhY2thZ2VSZXN1bHQoZGF0YT1jdykNCmBgYA0KDQpXZSBhbHNvIGhhdmUgYSByZXF1aXJlbWVudCB0aGF0IHRoZSBgc3RhdGlzdGljc2Agc2xvdCBoYXMgYSBgZGF0YS5mcmFtZWAgd2l0aCB0aGUgbmFtZSBgcHZhbHVlYC4gV2UnbGwgc2VlIGhvdyB3ZSBkaWQgdGhpcyBpbiB0aGUgYFZhbGlkaXR5YCBzZWN0aW9uIGJlbG93Lg0KDQpgYGB7cn0NCm5ld19vYmozIDwtIFN0YXRQYWNrYWdlUmVzdWx0KGRhdGE9Y3csIHN0YXRpc3RpY3M9Y3cpDQpgYGANCg0KIyBIb3cgZGlkIHdlIGRlZmluZSB0aGUgYFN0YXRzUGFja2FnZVJlc3VsdGAgQ2xhc3M/DQoNClRha2UgYSBsb29rIGF0IGBSL2NsYXNzZXMtUzQuUmAuIFRoZSBmaXJzdCB0aGluZyB3ZSBkaWQgd2FzIGRlZmluZSB0aGUgY2xhc3Mgd2l0aCBgc2V0Q2xhc3NgLCB3aGVyZSB3ZSBjYW4gc3BlY2lmeSB0aGUgZGF0YSB0eXBlcyBvZiBlYWNoIG9mIHRoZSBzbG90cy4gTm90ZSB0aGF0IHRoaXMgYWxzbyBkZWZpbmVzIHdoYXQncyBjYWxsZWQgdGhlICpjb25zdHJ1Y3RvciosIG9yIHRoZSBmdW5jdGlvbiB0aGF0IGxldHMgdXMgbWFrZSBuZXcgb2JqZWN0cy4NCg0KYGBgDQpTdGF0UGFja2FnZVJlc3VsdCA8LSBzZXRDbGFzcygiU3RhdFBhY2thZ2VSZXN1bHQiLA0KICAgICAgICAgICAgICAgICAgICAgICBzbG90cyA9IGMoZGF0YSA9ICJkYXRhLmZyYW1lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRpc3RpY3MgPSAiZGF0YS5mcmFtZSIpLA0KICAgICAgICAgICAgICAgICAgICAgICBwcm90b3R5cGUgPSBjKGRhdGE9TkEsIHN0YXRpc3RpY3M9TkEpDQogICAgICAgICAgICAgICAgICAgICAgICkNCmBgYA0KDQojIERlZmluaW5nIG1ldGhvZHMgZm9yIGBTdGF0c1BhY2thZ2VSZXN1bHRgDQoNClM0IG1ldGhvZHMgYXJlIGRlc2lnbmVkIHRvIGJlIGZsZXhpYmxlLiBUaGUgZG93bnNpZGUgdG8gdGhlIGZsZXhpYmlsaXR5IGlzIHRoYXQgdGhleSBhcmUgYSBsaXR0bGUgaGFyZGVyIHRvIHByb2dyYW0gd2l0aCBhbmQgc2V0IHVwLiBXaGVyZWFzIGluIFMzLCB3ZSBjb3VsZCBkZWZpbmUgYSBtZXRob2QgZm9yIG91ciBTMyBjbGFzcyBieSBqdXN0IG5hbWluZyBhIGZ1bmN0aW9uIHdpdGggYSBkb3QgKHN1Y2ggYXMgYHByaW50LnN0YXRzX3Jlc3VsdGApLCBTNCByZXF1aXJlcyB1cyB0byBmaXJzdCBlc3RhYmxpc2ggYSBgZ2VuZXJpY2AgZnVuY3Rpb24uIA0KDQpUaGUgYGdlbmVyaWNgIGZ1bmN0aW9uIGlzIGRlc2lnbmVkIHRvIHVzZSBkaWZmZXJlbnQgY29kZSBiYXNlZCBvbiB0aGUgY2xhc3Mgb2YgdGhlIG9iamVjdCwgbXVjaCBsaWtlIFM0IGdlbmVyaWNzLiBUYWtlIGEgbG9vayBhdCB0aGUgZ2VuZXJpYyBtZXRob2QgYHNob3dgLiBZb3UgY2FuIHNlZSBhbGwgb2YgdGhlIGRpZmZlcmVudCBjbGFzc2VzIGl0IHdvcmtzIG9uLiBUaGlzIGBvYmplY3Q9Ik1vZHVsZSJgIGlzIGNhbGxlZCBhICpzaWduYXR1cmUqLCBhbmQgaXQgZGVmaW5lcyBob3cgdGhlIGdlbmVyaWMgZnVuY3Rpb24gZGVjaWRlcyB3aGljaCBtZXRob2QgY29kZSB0byBkaXNwYXRjaC4NCg0KSGVyZSBhcmUgYWxsIHRoZSBTNCBtZXRob2RzIGZvciB0aGUgYHNob3dgIGdlbmVyaWMgZnVuY3Rpb24gYmFzZWQgb24gdGhlaXIgc2lnbmF0dXJlOg0KDQpgYGB7cn0NCnNob3dNZXRob2RzKCJzaG93IikNCmBgYA0KDQpCZWNhdXNlIG1ldGhvZHMgY2FuIGJlIGRpc3BhdGNoZWQgb24gbXVsdGlwbGUgc2lnbmF0dXJlcywgeW91IGZpcnN0IGhhdmUgdG8gZGVmaW5lIHRoZSBtZXRob2QgdXNpbmcgYHNldEdlbmVyaWMoKWA6DQoNCmBgYA0KI2Fsd2F5cyBuZWVkIHRvIGRlZmluZSB0aGUgZ2VuZXJpYyBtZXRob2QgZmlyc3QNCnNldEdlbmVyaWMobmFtZT0gInN0YXRpc3RpY3MiLCANCiAgICAgICAgICAgZGVmPSBmdW5jdGlvbihvYmplY3QpIHsNCiAgICAgICAgICAgICBzdGFuZGFyZEdlbmVyaWMoInN0YXRpc3RpY3MiKQ0KICAgICAgICAgICAgIH0NCiAgICAgICAgICAgKQ0KYGBgDQpUaGlzIGNyZWF0ZXMgYSAqZ2VuZXJpYyogZnVuY3Rpb24gY2FsbGVkIGBzdGF0aXN0aWNzYCwgd2hpY2ggaGFzIGEgc2luZ2xlIGFyZ3VtZW50OiBgb2JqZWN0YC4gTm90ZSB0aGF0IGBvYmplY3RgIGlzbid0IGxpbWl0ZWQgdG8gb3VyIGBTdGF0c1BhY2thZ2VSZXN1bHRgIGNsYXNzLiBXZSBjb3VsZCBhbHNvIGRlZmluZSBhIGBzdGF0aXN0aWNzYCBtZXRob2QgZm9yIG90aGVyIFM0IG9iamVjdHMuDQoNCk9uY2UgdGhlIGdlbmVyaWMgaXMgY3JlYXRlZCwgeW91IGNhbiBub3cgZGVmaW5lIGEgbWV0aG9kIGZvciB5b3VyIGNsYXNzLiANCg0KYGBgDQojZGVmaW5lIHRoZSBmdW5jdGlvbg0Kc2V0TWV0aG9kKGY9InN0YXRpc3RpY3MiLA0KICAgICAgICAgICNzaWduYXR1cmUgaXMgaG93IHRoZSBmdW5jdGlvbiBpcyBjYWxsZWQNCiAgICAgICAgICBzaWduYXR1cmUgPSBzaWduYXR1cmUoIlN0YXRQYWNrYWdlUmVzdWx0IiksIA0KICAgICAgICAgIGRlZmluaXRpb24gPSBmdW5jdGlvbihvYmplY3Qpew0KICAgICAgICAgICAgcmV0dXJuKG9iamVjdEBzdGF0aXN0aWNzKQ0KICAgICAgICAgIH0pDQpgYGANCg0KIyBWYWxpZGl0eQ0KDQpTYXkgeW91IG5lZWQgdG8gaGF2ZSBhbm90aGVyIHJlcXVpcmVtZW50IGZvciB0aGUgYGRhdGEuZnJhbWVgIGluIHRoZSBgc3RhdGlzdGljc2Agc2xvdCwgc3VjaCBhcyByZXF1aXJpbmcgYSBjb2x1bW4gY2FsbGVkIGBwdmFsdWVgLiBXZSBjYW4gZG8gdGhpcyBieSBhZGRpbmcgYSB2YWxpZGl0eSBmdW5jdGlvbiB1c2luZyBgc2V0VmFsaWRpdHlgOg0KDQpgYGANCmNoZWNrX3N0YXRzX29iamVjdCA8LSBmdW5jdGlvbihvYmplY3Qpew0KICAjY2hlY2sgd2hldGhlciBzdGF0aXN0aWNzIGRhdGEuZnJhbWUgY29udGFpbnMgInB2YWx1ZSINCiAgI2FzIGNvbHVtbiBuYW1lDQogIGlmKCJwdmFsdWUiICVpbiUgY29sbmFtZXMoZ2V0X3N0YXRpc3RpY3Mob2JqZWN0KSkpIHtUUlVFfQ0KICBlbHNleyAic3RhdGlzdGljcyBzbG90IG5lZWRzIGEgcHZhbHVlIGNvbHVtbiJ9DQp9DQoNCnNldFZhbGlkaXR5KCJTdGF0c1Jlc3VsdE9iamVjdCIsIGNoZWNrX3N0YXRzX29iamVjdCkNCg0KYGBgDQoNCiMgSW5oZXJpdGFuY2UNCg0KVGhlIGJlc3QgdGhpbmcgYWJvdXQgT2JqZWN0IE9yaWVudGVkIFByb2dyYW1taW5nIGlzIHRoYXQgeW91IGRvbid0IGhhdmUgdG8gcmVpbnZlbnQgdGhlIHdoZWVsLiBZb3UgY2FuICpleHRlbmQqIGEgY3VycmVudCBjbGFzcyBkZWZpbml0aW9uIHRvIG1ha2UgYSBuZXcgY2xhc3MuIEhlcmUgd2UncmUgbWFraW5nIGEgbmV3IGNsYXNzIGBBbm92YVJlc3VsdGAgdGhhdCBpcyBiYXNlZCBvbiBvdXIgYFN0YXRQYWNrYWdlUmVzdWx0YC4gWW91IGNhbiBzZWUgd2UgdXNlIHRoZSBgY29udGFpbnNgIGFyZ3VtZW50IHRvIHNheSB3ZSdyZSBleHRlbmRpbmcgYFN0YXRQYWNrYWdlUmVzdWx0YC4gDQoNCkFsc28sIG5vdGUgd2UncmUgYWRkaW5nIGEgYGdyb3Vwc2Agc2xvdC4gVGhlIG90aGVyIHNsb3RzIGZyb20gYFN0YXRQYWNrYWdlUmVzdWx0YCwgYGRhdGFgIGFuZCBgc3RhdGlzdGljc2AgYXJlICppbmhlcml0ZWQqIGZyb20gYFN0YXRQYWNrYWdlUmVzdWx0YC4NCg0KYGBgDQojSW5oZXJpdGFuY2U6IG1ha2luZyBhIG5ldyBjbGFzcyBmcm9tIG91ciBvbGQgY2xhc3MNCkFub3ZhUmVzdWx0IDwtIHNldENsYXNzKCJBbm92YVJlc3VsdCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgY29udGFpbnM9ICJTdGF0UGFja2FnZVJlc3VsdCIsDQogICAgICAgICAgICAgICAgICAgICAgICBzbG90cz1jKGdyb3Vwcz0iY2hhcmFjdGVyIikpDQpgYGANCg0KYGBge3J9DQpzdGF0X2ZyYW1lIDwtIGRhdGEuZnJhbWUoZ3JvdXA9Yygic2V0b3NhIiwgInZpcmdpbmljYSIsICJ2ZXJzaWNvbG9yIiksIHB2YWx1ZT1jKDAuNSwgMC4yLCAwLjAwMSkpDQpncm91cHMgPC0gYygic2V0b3NhIiwgInZpcmdpbmljYSIsICJ2ZXJzaWNvbG9yIikNCg0KYW5vdmFfcmVzdWx0X3M0IDwtIEFub3ZhUmVzdWx0KGRhdGEgPSBpcmlzLCBzdGF0aXN0aWNzID0gc3RhdF9mcmFtZSwgZ3JvdXBzPWdyb3VwcykNCg0KI2dldCB0aGUgY2xhc3MgZGVmaW5pdGlvbg0KZ2V0Q2xhc3MoIkFub3ZhUmVzdWx0IikNCmBgYA0KDQpTaG93IHRoZSBuZXcgc3RydWN0dXJlIG9mIG91ciBpbmhlcml0ZWQgb2JqZWN0Lg0KDQpgYGB7cn0NCnN0cihhbm92YV9yZXN1bHRfczQpDQpgYGANCg0KIyBFeHRlbmRpbmcgbWV0aG9kcyBmcm9tIGEgc3VwZXJsY2Fzcw0KDQpNZXRob2RzIGFyZSBjbGFzcyBzcGVjaWZpYywgYnV0IHRoZXkgYWxzbyBpbmhlcml0IGZyb20gdGhlICpzdXBlciogY2xhc3MgdGhhdCBvdXIgbmV3IGNsYXNzIGlzIGRlcml2ZWQgZnJvbS4gVGhpcyBtZWFucyB5b3UgY2FuIGFkZCBleHRyYSBjb2RlIHRvIGEgbWV0aG9kIGJ5ICpvdmVycmlkaW5nKiB0aGUgbWV0aG9kIGZvciB0aGUgbmV3IGNsYXNzIGFuZCB1c2luZyBgY2FsbE5leHRNZXRob2QoKWAgdG8gZXhlY3V0ZSB0aGUgY29kZSBiZWxvbmdpbmcgdG8gdGhlIHN1cGVyY2xhc3MgKHdoaWNoIGlzIGBTdGF0UGFja2FnZVJlc3VsdGApLg0KDQpgYGANCiNPdmVycmlkaW5nIHRoZSBnZXRfc3RhdGlzdGljcyBtZXRob2QgZm9yIFN0YXRQYWNrYWdlUmVzdWx0DQpzZXRNZXRob2QoImdldF9zdGF0aXN0aWNzIiwNCiAgICAgICAgICBzaWduYXR1cmUgPSBzaWduYXR1cmUob2JqZWN0ID0gIkFub3ZhUmVzdWx0IiksDQoNCiAgICAgICAgICAgIGRlZmluaXRpb24gPSBmdW5jdGlvbihvYmplY3Qpew0KICAgICAgICAgICAgICAgIHByaW50KG9iamVjdEBncm91cHMpDQogICAgICAgICAgICAgICAgI25vdyBydW4gdGhlIGNvZGUgdGhhdCBiZWxvbmdzIHRvIHRoZSBtZXRob2QNCiAgICAgICAgICAgICAgICAjZm9yIHRoZSBzdXBlcmNsYXNzICgiU3RhdFBhY2thZ2VSZXN1bHQiKQ0KICAgICAgICAgICAgICAgIGNhbGxOZXh0TWV0aG9kKG9iamVjdCkNCiAgICAgICAgICAgICAgfQ0KICAgICAgICAgICkNCmBgYA0KVHJ5IHJ1bm5pbmcgYGdldF9zdGF0aXN0aWNzKClgIG9uIGBhbm92YV9yZXN1bHRfczRgLiBJdCB3aWxsIGZpcnN0IHByaW50IG91dCBgZ3JvdXBgIGFuZCB0aGVuIHJldHVybiB0aGUgYHN0YXRpc3RpY3NgIHNsb3QuDQoNCmBgYHtyfQ0KZ2V0X3N0YXRpc3RpY3MoYW5vdmFfcmVzdWx0X3M0KQ0KYGBgDQoNCiMgV2hhdCB3ZSBkaWRuJ3QgY292ZXIgdG9kYXk6DQoNCi0gVXBkYXRpbmcgb2xkIG9iamVjdHMNCi0gR2V0dGluZyBTMyBhbmQgUzQgdG8gd29yayB0b2dldGhlcg0KLSBNdWx0aXBsZSBJbmhlcml0YW5jZSBhbmQgRGlzcGF0Y2gNCiAgLSBUaGUgYWJpbGl0eSBvZiBhIGNsYXNzIHRvIGluaGVyaXQgZnJvbSBtdWx0aXBsZSBjbGFzc2VzDQogIC0gSGFkbGV5IGNvdmVycyB0aGlzIG11Y2ggYmV0dGVyIHRoYW4gSSBjb3VsZDogaHR0cHM6Ly9hZHYtci5oYWRsZXkubnovczQuaHRtbCNzNC1kaXNwYXRjaA0KDQojIFJlc291cmNlcw0KDQpQb3J0aW9ucyBvZiB0aGlzIG5vdGVib29rIHdlcmUgZ3JhdGVmdWxseSBhZGFwdGVkIGZyb206DQoNCi0gUzQgQ2xhc3NlcyBhbmQgTWV0aG9kczogaHR0cHM6Ly9rYXNwZXJkYW5pZWxoYW5zZW4uZ2l0aHViLmlvL2dlbmJpb2NvbmR1Y3Rvci9odG1sL1JfUzQuaHRtbA0KLSBBIHByYWN0aWNhbCBUdXRvcmlhbCBvbiBTNCBQcm9ncmFtbWluZzogaHR0cHM6Ly93d3cuYmlvY29uZHVjdG9yLm9yZy9oZWxwL2NvdXJzZS1tYXRlcmlhbHMvMjAxMy9DU0FNQTIwMTMvZnJpZGF5L2FmdGVybm9vbi9TNC10dXRvcmlhbC5wZGYNCi0gaHR0cHM6Ly93d3cuY3ljbGlzbW8ub3JnL3R1dG9yaWFsL1IvczRDbGFzc2VzLmh0bWwNCi0gQWR2YW5jZWQgUjogaHR0cHM6Ly9hZHYtci5oYWRsZXkubnov