Now let’s talk about R6 classes. They aren’t built into the base R distribution, but live in their own package, called R6
.
The two major features of R6 that are super useful are:
mutability, which means that you can modify an object in place, which is useful for maintaining state, and
private versus public fields, which is especially useful if you want your object to act like an API.
library(here)
library(R6)
source(here("R/classes-R6.R"))
Making an new R6 object
We’re going to make a new object of class StatPackageResultR6
first. We do this by calling $new()
on the StatsPackageResultR6
class:
stat_frame <- data.frame(group=c("setosa", "virginica", "versicolor"), pvalue=c(0.5, 0.2, 0.001))
my_stats_r6 <- StatPackageResultR6$new(data = iris, statistics = stat_frame)
class(my_stats_r6)
[1] "StatPackageResultR6" "R6"
What’s in the Object?
If we just use str()
on our object, we’ll get information about the structure of the object. The first thing to note is that there are two main groupings: public
and private
.
str(my_stats_r6)
Classes 'StatPackageResultR6', 'R6' <StatPackageResultR6>
Public:
clone: function (deep = FALSE)
data: data.frame
get_significant_results: function ()
get_statistics: function ()
get_threshold: function ()
initialize: function (data, statistics)
print: function ()
set_threshold: function (threshold)
statistics: data.frame
validate: function ()
Private:
threshold: NULL
Methods are attached to the object
If you look under public
, you’ll notice that there’s a number of functions. These are the methods that are attached to the my_stats_r6
object. You access these methods using the $
operator.
my_stats_r6$get_statistics()
What about get_significant_results()
method? Trying it, we get an error.
my_stats_r6$get_significant_results()
Error in my_stats_r6$get_significant_results() : Threshold is not set
Huh, we need to set a threshold. How do we do this?
Private versus Public
R6 has an additional feature that is very useful; private fields verus public fields. Private fields are provided as an argument to the private
argument, which is a list.
Part of the reason for having private fields is that you don’t want the user to directly access these values. There is no way to get the threshold
value without using an accessor
method. If we try that:
my_stats_r6$get_threshold()
NULL
The threshold is not set for this object. We can set a value using set_threshold()
:
my_stats_r6$set_threshold(threshold = 0.02)
Whoa - there was no assignment operator! This is one of the features of R6 - they are processed in place.
my_stats_r6$get_threshold()
[1] 0.02
Now if we try get_significant_results
it will work:
my_stats_r6$get_significant_results()
How do we define methods in R6?
Let’s take a look at the StatPackageResultR6
class. The first thing we notice is that there are two main arguments: public
and private
, which are both lists.
StatPackageResultR6 <- R6::R6Class(classname = "StatPackageResultR6",
public = list(
#functions and public fields go here
}),
private=list(
#private fields go here
)
)
We define public methods as functions that are arguments in the list in public
:
StatPackageResultR6 <- R6::R6Class(classname = "StatPackageResultR6",
public = list(
#methods and fields defined here:
get_significant_results = function(){
if(is.null(private$threshold)){
stop("Threshold is not set")
}
filtered_results <- self$statistics %>%
filter(pvalue < private$threshold)
filtered_results
},
# more methods defined below
}),
private=list(
#private fields go here
)
)
And our private field, threshold
, is an argument to the private
list:
StatPackageResultR6 <- R6::R6Class(classname = "StatPackageResultR6",
public = list(
#functions and public fields go here
}),
private=list(
threshold = NULL
)
)
Let’s take a look at the get_significant_results()
method:
get_significant_results = function(){
if(is.null(private$threshold)){
stop("Threshold is not set")
}
filtered_results <- self$statistics %>%
filter(pvalue < private$threshold)
filtered_results
}
The first thing to note is the line:
if(is.null(private$threshold)){
We’re accessing the threshold
value using private
, because it’s a private field.
The next thing to note is the line:
filtered_results <- self$statistics %>%
We access the statistics
field using self
. Why is it self
and not public
? This naming convention comes from other object programming languages.
Setting values: invisible(self)
When you set values, you have to end the method with invisible(self)
. We’re basically returning our modified object after we’ve set it.
set_threshold = function(threshold){
private$threshold <- threshold
invisible(self)
}
Important method: $initialize()
One method you should always specify is $initialize
, which defines the constructor for the method. This is the method that is used whenever we create a new object with $new()
:
#this is what we use to initialize our object
initialize = function(data, statistics){
self$data <- data
self$statistics <- statistics
invisible(self)
},
Rather annoying: specifiying methods outside of the class
The other thing to note is that you have to specify these functions as list arguments to the public
list. Because they use self
and private
in the function, they can’t be defined as separate functions outside of the list.
For tidy-ness, and overall code legibility, you can use the $set()
method to add individual methods to the class. For example, this is how we’ll add a $print()
method to our class:
StatPackageResultR6$set(which = "public", name = "print",
value = function() {
print(head(self$data))
print(head(self$statistics))
}
)
Important Method: $validate()
The $validate()
method lets you define a method to validate the contents of your R6 object, much like setValidity()
let you do this for S4 objects.
StatPackageResultR6$set(which = "public", name = "validate",
value = function() {
if(!is.data.frame(self$statistics)){
warning("statistics field is not a data.frame")
return(FALSE)
}
if(!"pvalue" %in% colnames(self$statistics)){
warning("statistics field doesn't contain
a pvalue column")
return(FALSE)
}
#return TRUE otherwise
return(TRUE)
}
)
Having a $validate()
method is especially useful when getting and setting complex data types in fields.
my_stats_r6$validate()
[1] TRUE
Chaining Methods
What do you think the following does?
my_stats_r6$set_threshold(0.21)$get_significant_results()
Chaining multiple methods together is a style that is common in JavaScript and Python and can be done by chaining $methods
Maintaining State is Important: R6/Shiny
The main use case I’ve found for R6 in my work is for building data objects in Shiny. The data is encapsulated in an R6 object which can provide different formats of the data given a Shiny visualization.
I use R6 in my Shiny apps, for modularity reasons. The same data object is used for different visualizations, so I can design the visualizations to expect a certain format (long or wide). This gives me the flexibility of changing the internal format of the data fields in the object if necessary.
Here are my R6 Classes: https://github.com/laderast/flowDashboard/blob/master/R/classes.R
I don’t necessarily think this is the best implementation, but you can see what I did.
Inheritance
R6 objects can inherit from each other. Here we’re making a new class called AnovaResultR6
, using the inherit=
argument. Our AnovaResultR6
class has an additional field we’re calling groups
.
We’re overriding our $initialize
method for the StatPackageResultR6
. It sets the groups
field, and then uses super$initialize()
to set the other fields in the object. super
is the equivalent of NextMethod()
in S3.
AnovaResultR6 <- R6::R6Class(classname = "AnovaResultR6",
inherit="StatPackageResultR6",
public =
list(groups = NULL,
initialize=function(data, statistics, groups){
self$groups <- groups
super$initialize(data, statistics)
invisible(self)
},
print = function(){
print(self$groups)
super$print()
})
)
Let’s make an AnovaResultR6
object:
stat_frame <- data.frame(group=c("setosa", "virginica", "versicolor"), pvalue=c(0.5, 0.2, 0.001))
anova_object <- AnovaResultR6$new(data=iris,
statistics=stat_frame, groups=c("setosa",
"virginica",
"versicolor"))
We can see that our AnovaResultR6
object inherits from StatPackageResultR6
and that it has an additional groups
field in public.
str(anova_object)
And it can use the $get_statistics()
method it inherited:
anova_object$get_statistics()
R6 Quirks: Copy By Reference
R6 objects are built on environments. This means that if you assign my_stats_r6
to a new object new_my_stats_r6
, it’s just a pointer to the original object.
new_my_stats_r6 <- my_stats_r6
new_my_stats_r6$set_threshold(0.1)
my_stats_r6$get_threshold()
If you need to make a brand new object that is a separate copy of that object, you need to use the $clone()
method:
new_my_stats_r6 <- my_stats_r6$clone()
new_my_stats_r6$set_threshold(0.4)
new_my_stats_r6$get_threshold()
my_stats_r6$get_threshold()
If your R6 object contains other R6 objects as fields and you want to clone these as well, you’ll have to additionally apply the deep=TRUE
argument.
Note: R6 is Weird to most R users
You probably don’t want have your final results object as an R6 class. Mostly because most users aren’t familiar with R6 and using methods attached to an object. I learned this the hard way.
The one exception is when your package is going to be used by developers - they will probably be more familiar with the R6 object structure and getting things out of it.
Things we didn’t cover
- R6 Classes also have an
active
slot, which has its uses.
- Multiple inheritance
LS0tDQp0aXRsZTogIlI2IENsYXNzZXMiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpOb3cgbGV0J3MgdGFsayBhYm91dCBSNiBjbGFzc2VzLiBUaGV5IGFyZW4ndCBidWlsdCBpbnRvIHRoZSBiYXNlIFIgZGlzdHJpYnV0aW9uLCBidXQgbGl2ZSBpbiB0aGVpciBvd24gcGFja2FnZSwgY2FsbGVkIGBSNmAuDQoNClRoZSB0d28gbWFqb3IgZmVhdHVyZXMgb2YgUjYgdGhhdCBhcmUgc3VwZXIgdXNlZnVsIGFyZToNCg0KMS4gKm11dGFiaWxpdHkqLCB3aGljaCBtZWFucyB0aGF0IHlvdSBjYW4gbW9kaWZ5IGFuIG9iamVjdCBpbiBwbGFjZSwgd2hpY2ggaXMgdXNlZnVsIGZvciBtYWludGFpbmluZyBzdGF0ZSwgYW5kDQoNCjIuICpwcml2YXRlKiB2ZXJzdXMgKnB1YmxpYyogZmllbGRzLCB3aGljaCBpcyBlc3BlY2lhbGx5IHVzZWZ1bCBpZiB5b3Ugd2FudCB5b3VyIG9iamVjdCB0byBhY3QgbGlrZSBhbiBBUEkuIA0KDQpgYGB7cn0NCmxpYnJhcnkoaGVyZSkNCmxpYnJhcnkoUjYpDQpzb3VyY2UoaGVyZSgiUi9jbGFzc2VzLVI2LlIiKSkNCmBgYA0KDQojIyBNYWtpbmcgYW4gbmV3IFI2IG9iamVjdA0KDQpXZSdyZSBnb2luZyB0byBtYWtlIGEgbmV3IG9iamVjdCBvZiBjbGFzcyBgU3RhdFBhY2thZ2VSZXN1bHRSNmAgZmlyc3QuIFdlIGRvIHRoaXMgYnkgY2FsbGluZyBgJG5ldygpYCBvbiB0aGUgYFN0YXRzUGFja2FnZVJlc3VsdFI2YCBjbGFzczoNCg0KYGBge3J9DQpzdGF0X2ZyYW1lIDwtIGRhdGEuZnJhbWUoZ3JvdXA9Yygic2V0b3NhIiwgInZpcmdpbmljYSIsICJ2ZXJzaWNvbG9yIiksIHB2YWx1ZT1jKDAuNSwgMC4yLCAwLjAwMSkpDQoNCm15X3N0YXRzX3I2IDwtIFN0YXRQYWNrYWdlUmVzdWx0UjYkbmV3KGRhdGEgPSBpcmlzLCBzdGF0aXN0aWNzID0gc3RhdF9mcmFtZSkNCmNsYXNzKG15X3N0YXRzX3I2KQ0KYGBgDQoNCiMjIFdoYXQncyBpbiB0aGUgT2JqZWN0Pw0KDQpJZiB3ZSBqdXN0IHVzZSBgc3RyKClgIG9uIG91ciBvYmplY3QsIHdlJ2xsIGdldCBpbmZvcm1hdGlvbiBhYm91dCB0aGUgc3RydWN0dXJlIG9mIHRoZSBvYmplY3QuIFRoZSBmaXJzdCB0aGluZyB0byBub3RlIGlzIHRoYXQgdGhlcmUgYXJlIHR3byBtYWluIGdyb3VwaW5nczogYHB1YmxpY2AgYW5kIGBwcml2YXRlYC4gDQoNCmBgYHtyfQ0Kc3RyKG15X3N0YXRzX3I2KQ0KYGBgDQoNCiMjIE1ldGhvZHMgYXJlIGF0dGFjaGVkIHRvIHRoZSBvYmplY3QNCg0KSWYgeW91IGxvb2sgdW5kZXIgYHB1YmxpY2AsIHlvdSdsbCBub3RpY2UgdGhhdCB0aGVyZSdzIGEgbnVtYmVyIG9mIGZ1bmN0aW9ucy4gVGhlc2UgYXJlIHRoZSAqbWV0aG9kcyogdGhhdCBhcmUgYXR0YWNoZWQgdG8gdGhlIGBteV9zdGF0c19yNmAgb2JqZWN0LiBZb3UgYWNjZXNzIHRoZXNlIG1ldGhvZHMgdXNpbmcgdGhlIGAkYCBvcGVyYXRvci4gDQoNCmBgYHtyfQ0KbXlfc3RhdHNfcjYkZ2V0X3N0YXRpc3RpY3MoKQ0KYGBgDQoNCldoYXQgYWJvdXQgYGdldF9zaWduaWZpY2FudF9yZXN1bHRzKClgIG1ldGhvZD8gVHJ5aW5nIGl0LCB3ZSBnZXQgYW4gZXJyb3IuDQoNCmBgYHtyfQ0KbXlfc3RhdHNfcjYkZ2V0X3NpZ25pZmljYW50X3Jlc3VsdHMoKQ0KYGBgDQoNCkh1aCwgd2UgbmVlZCB0byBzZXQgYSB0aHJlc2hvbGQuIEhvdyBkbyB3ZSBkbyB0aGlzPw0KDQojIyBQcml2YXRlIHZlcnN1cyBQdWJsaWMNCg0KUjYgaGFzIGFuIGFkZGl0aW9uYWwgZmVhdHVyZSB0aGF0IGlzIHZlcnkgdXNlZnVsOyAqcHJpdmF0ZSogZmllbGRzIHZlcnVzICpwdWJsaWMqIGZpZWxkcy4gUHJpdmF0ZSBmaWVsZHMgYXJlIHByb3ZpZGVkIGFzIGFuIGFyZ3VtZW50IHRvIHRoZSBgcHJpdmF0ZWAgYXJndW1lbnQsIHdoaWNoIGlzIGEgbGlzdC4NCg0KUGFydCBvZiB0aGUgcmVhc29uIGZvciBoYXZpbmcgKnByaXZhdGUqIGZpZWxkcyBpcyB0aGF0IHlvdSBkb24ndCB3YW50IHRoZSB1c2VyIHRvIGRpcmVjdGx5IGFjY2VzcyB0aGVzZSB2YWx1ZXMuIFRoZXJlIGlzIG5vIHdheSB0byBnZXQgdGhlIGB0aHJlc2hvbGRgIHZhbHVlIHdpdGhvdXQgdXNpbmcgYW4gYGFjY2Vzc29yYCBtZXRob2QuIElmIHdlIHRyeSB0aGF0Og0KDQpgYGB7cn0NCm15X3N0YXRzX3I2JGdldF90aHJlc2hvbGQoKQ0KDQpgYGANCg0KVGhlIHRocmVzaG9sZCBpcyBub3Qgc2V0IGZvciB0aGlzIG9iamVjdC4gV2UgY2FuIHNldCBhIHZhbHVlIHVzaW5nIGBzZXRfdGhyZXNob2xkKClgOg0KDQpgYGB7cn0NCm15X3N0YXRzX3I2JHNldF90aHJlc2hvbGQodGhyZXNob2xkID0gMC4wMikNCmBgYA0KDQpXaG9hIC0gdGhlcmUgd2FzIG5vIGFzc2lnbm1lbnQgb3BlcmF0b3IhIFRoaXMgaXMgb25lIG9mIHRoZSBmZWF0dXJlcyBvZiBSNiAtIHRoZXkgYXJlIHByb2Nlc3NlZCBpbiBwbGFjZS4NCg0KYGBge3J9DQpteV9zdGF0c19yNiRnZXRfdGhyZXNob2xkKCkNCmBgYA0KDQpOb3cgaWYgd2UgdHJ5IGBnZXRfc2lnbmlmaWNhbnRfcmVzdWx0c2AgaXQgd2lsbCB3b3JrOg0KDQpgYGB7cn0NCm15X3N0YXRzX3I2JGdldF9zaWduaWZpY2FudF9yZXN1bHRzKCkNCmBgYA0KDQojIEhvdyBkbyB3ZSBkZWZpbmUgbWV0aG9kcyBpbiBSNj8NCg0KTGV0J3MgdGFrZSBhIGxvb2sgYXQgdGhlIGBTdGF0UGFja2FnZVJlc3VsdFI2YCBjbGFzcy4gVGhlIGZpcnN0IHRoaW5nIHdlIG5vdGljZSBpcyB0aGF0IHRoZXJlIGFyZSB0d28gbWFpbiBhcmd1bWVudHM6IGBwdWJsaWNgIGFuZCBgcHJpdmF0ZWAsIHdoaWNoIGFyZSBib3RoIGxpc3RzLg0KDQpgYGANClN0YXRQYWNrYWdlUmVzdWx0UjYgPC0gUjY6OlI2Q2xhc3MoY2xhc3NuYW1lID0gIlN0YXRQYWNrYWdlUmVzdWx0UjYiLA0KICAgICAgICAgICAgcHVibGljID0gbGlzdCgNCiAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICNmdW5jdGlvbnMgYW5kIHB1YmxpYyBmaWVsZHMgZ28gaGVyZQ0KICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgIH0pLA0KICAgICAgICAgICAgDQogICAgICAgICAgICBwcml2YXRlPWxpc3QoDQogICAgICAgICAgICAgICNwcml2YXRlIGZpZWxkcyBnbyBoZXJlDQogICAgICAgICAgICANCiAgICAgICAgICAgICAgKQ0KICAgICAgICAgICAgKQ0KDQpgYGANCg0KV2UgZGVmaW5lIHB1YmxpYyBtZXRob2RzIGFzIGZ1bmN0aW9ucyB0aGF0IGFyZSBhcmd1bWVudHMgaW4gdGhlIGxpc3QgaW4gYHB1YmxpY2A6DQoNCg0KYGBgDQpTdGF0UGFja2FnZVJlc3VsdFI2IDwtIFI2OjpSNkNsYXNzKGNsYXNzbmFtZSA9ICJTdGF0UGFja2FnZVJlc3VsdFI2IiwNCiAgICAgICAgICAgIHB1YmxpYyA9IGxpc3QoDQogICAgICAgICAgICAgICNtZXRob2RzIGFuZCBmaWVsZHMgZGVmaW5lZCBoZXJlOg0KICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgZ2V0X3NpZ25pZmljYW50X3Jlc3VsdHMgPSBmdW5jdGlvbigpew0KICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgaWYoaXMubnVsbChwcml2YXRlJHRocmVzaG9sZCkpew0KICAgICAgICAgICAgICAgICAgICBzdG9wKCJUaHJlc2hvbGQgaXMgbm90IHNldCIpDQogICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICBmaWx0ZXJlZF9yZXN1bHRzIDwtIHNlbGYkc3RhdGlzdGljcyAlPiUNCiAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHB2YWx1ZSA8IHByaXZhdGUkdGhyZXNob2xkKQ0KICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICBmaWx0ZXJlZF9yZXN1bHRzDQogICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgfSwNCiAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICMgbW9yZSBtZXRob2RzIGRlZmluZWQgYmVsb3cNCiAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICB9KSwNCiAgICAgICAgICAgIA0KICAgICAgICAgICAgcHJpdmF0ZT1saXN0KA0KICAgICAgICAgICAgICAjcHJpdmF0ZSBmaWVsZHMgZ28gaGVyZQ0KICAgICAgICAgICAgDQogICAgICAgICAgICAgICkNCiAgICAgICAgICAgICkNCmBgYA0KDQpBbmQgb3VyIHByaXZhdGUgZmllbGQsIGB0aHJlc2hvbGRgLCBpcyBhbiBhcmd1bWVudCB0byB0aGUgYHByaXZhdGVgIGxpc3Q6DQoNCmBgYA0KU3RhdFBhY2thZ2VSZXN1bHRSNiA8LSBSNjo6UjZDbGFzcyhjbGFzc25hbWUgPSAiU3RhdFBhY2thZ2VSZXN1bHRSNiIsDQogICAgICAgICAgICBwdWJsaWMgPSBsaXN0KA0KICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgI2Z1bmN0aW9ucyBhbmQgcHVibGljIGZpZWxkcyBnbyBoZXJlDQogICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgfSksDQogICAgICAgICAgICANCiAgICAgICAgICAgIHByaXZhdGU9bGlzdCgNCiAgICAgICAgICAgICAgdGhyZXNob2xkID0gTlVMTA0KICAgICAgICAgICAgDQogICAgICAgICAgICAgICkNCiAgICAgICAgICAgICkNCg0KYGBgDQoNCkxldCdzIHRha2UgYSBsb29rIGF0IHRoZSBgZ2V0X3NpZ25pZmljYW50X3Jlc3VsdHMoKWAgbWV0aG9kOg0KDQpgYGANCmdldF9zaWduaWZpY2FudF9yZXN1bHRzID0gZnVuY3Rpb24oKXsNCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgIGlmKGlzLm51bGwocHJpdmF0ZSR0aHJlc2hvbGQpKXsNCiAgICAgICAgICAgICAgICAgICAgc3RvcCgiVGhyZXNob2xkIGlzIG5vdCBzZXQiKQ0KICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgZmlsdGVyZWRfcmVzdWx0cyA8LSBzZWxmJHN0YXRpc3RpY3MgJT4lDQogICAgICAgICAgICAgICAgICAgIGZpbHRlcihwdmFsdWUgPCBwcml2YXRlJHRocmVzaG9sZCkNCiAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgZmlsdGVyZWRfcmVzdWx0cw0KICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgIH0NCmBgYA0KDQpUaGUgZmlyc3QgdGhpbmcgdG8gbm90ZSBpcyB0aGUgbGluZTogDQoNCmBpZihpcy5udWxsKHByaXZhdGUkdGhyZXNob2xkKSl7YA0KDQpXZSdyZSBhY2Nlc3NpbmcgdGhlIGB0aHJlc2hvbGRgIHZhbHVlIHVzaW5nIGBwcml2YXRlYCwgYmVjYXVzZSBpdCdzIGEgcHJpdmF0ZSBmaWVsZC4NCg0KVGhlIG5leHQgdGhpbmcgdG8gbm90ZSBpcyB0aGUgbGluZToNCg0KYGZpbHRlcmVkX3Jlc3VsdHMgPC0gc2VsZiRzdGF0aXN0aWNzICU+JWANCg0KV2UgYWNjZXNzIHRoZSBgc3RhdGlzdGljc2AgZmllbGQgdXNpbmcgYHNlbGZgLiBXaHkgaXMgaXQgYHNlbGZgIGFuZCBub3QgYHB1YmxpY2A/IFRoaXMgbmFtaW5nIGNvbnZlbnRpb24gY29tZXMgZnJvbSBvdGhlciBvYmplY3QgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2VzLg0KDQojIFNldHRpbmcgdmFsdWVzOiBgaW52aXNpYmxlKHNlbGYpYA0KDQpXaGVuIHlvdSBzZXQgdmFsdWVzLCB5b3UgaGF2ZSB0byBlbmQgdGhlIG1ldGhvZCB3aXRoIGBpbnZpc2libGUoc2VsZilgLiBXZSdyZSBiYXNpY2FsbHkgcmV0dXJuaW5nIG91ciBtb2RpZmllZCBvYmplY3QgYWZ0ZXIgd2UndmUgc2V0IGl0LiANCg0KYGBgDQpzZXRfdGhyZXNob2xkID0gZnVuY3Rpb24odGhyZXNob2xkKXsNCiAgICAgICAgICAgICAgICBwcml2YXRlJHRocmVzaG9sZCA8LSB0aHJlc2hvbGQNCiAgICAgICAgICAgICAgICBpbnZpc2libGUoc2VsZikNCiAgICAgICAgICAgICAgfQ0KYGBgDQoNCiMgSW1wb3J0YW50IG1ldGhvZDogYCRpbml0aWFsaXplKClgDQoNCk9uZSBtZXRob2QgeW91IHNob3VsZCBhbHdheXMgc3BlY2lmeSBpcyBgJGluaXRpYWxpemVgLCB3aGljaCBkZWZpbmVzIHRoZSAqY29uc3RydWN0b3IqIGZvciB0aGUgbWV0aG9kLiBUaGlzIGlzIHRoZSBtZXRob2QgdGhhdCBpcyB1c2VkIHdoZW5ldmVyIHdlIGNyZWF0ZSBhIG5ldyBvYmplY3Qgd2l0aCBgJG5ldygpYDoNCg0KYGBgDQogICAgICAgICAgICAgICN0aGlzIGlzIHdoYXQgd2UgdXNlIHRvIGluaXRpYWxpemUgb3VyIG9iamVjdA0KICAgICAgICAgICAgICBpbml0aWFsaXplID0gZnVuY3Rpb24oZGF0YSwgc3RhdGlzdGljcyl7DQogICAgICAgICAgICAgICAgc2VsZiRkYXRhIDwtIGRhdGENCiAgICAgICAgICAgICAgICBzZWxmJHN0YXRpc3RpY3MgPC0gc3RhdGlzdGljcw0KICAgICAgICAgICAgICAgIGludmlzaWJsZShzZWxmKQ0KICAgICAgICAgICAgICB9LA0KYGBgDQoNCg0KIyBSYXRoZXIgYW5ub3lpbmc6IHNwZWNpZml5aW5nIG1ldGhvZHMgb3V0c2lkZSBvZiB0aGUgY2xhc3MNCg0KVGhlIG90aGVyIHRoaW5nIHRvIG5vdGUgaXMgdGhhdCB5b3UgaGF2ZSB0byBzcGVjaWZ5IHRoZXNlIGZ1bmN0aW9ucyBhcyBsaXN0IGFyZ3VtZW50cyB0byB0aGUgYHB1YmxpY2AgbGlzdC4gQmVjYXVzZSB0aGV5IHVzZSBgc2VsZmAgYW5kIGBwcml2YXRlYCBpbiB0aGUgZnVuY3Rpb24sIHRoZXkgY2FuJ3QgYmUgZGVmaW5lZCBhcyBzZXBhcmF0ZSBmdW5jdGlvbnMgb3V0c2lkZSBvZiB0aGUgbGlzdC4NCg0KRm9yIHRpZHktbmVzcywgYW5kIG92ZXJhbGwgY29kZSBsZWdpYmlsaXR5LCB5b3UgY2FuIHVzZSB0aGUgYCRzZXQoKWAgbWV0aG9kIHRvIGFkZCBpbmRpdmlkdWFsIG1ldGhvZHMgdG8gdGhlIGNsYXNzLiBGb3IgZXhhbXBsZSwgdGhpcyBpcyBob3cgd2UnbGwgYWRkIGEgYCRwcmludCgpYCBtZXRob2QgdG8gb3VyIGNsYXNzOg0KDQpgYGANClN0YXRQYWNrYWdlUmVzdWx0UjYkc2V0KHdoaWNoID0gInB1YmxpYyIsIG5hbWUgPSAicHJpbnQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gZnVuY3Rpb24oKSB7DQogICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBwcmludChoZWFkKHNlbGYkZGF0YSkpDQogICAgICAgICAgICAgICAgICAgICAgICAgIHByaW50KGhlYWQoc2VsZiRzdGF0aXN0aWNzKSkNCiAgICAgICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICAgICAgICApDQpgYGANCg0KIyBJbXBvcnRhbnQgTWV0aG9kOiBgJHZhbGlkYXRlKClgDQoNClRoZSBgJHZhbGlkYXRlKClgIG1ldGhvZCBsZXRzIHlvdSBkZWZpbmUgYSBtZXRob2QgdG8gdmFsaWRhdGUgdGhlIGNvbnRlbnRzIG9mIHlvdXIgUjYgb2JqZWN0LCBtdWNoIGxpa2UgYHNldFZhbGlkaXR5KClgIGxldCB5b3UgZG8gdGhpcyBmb3IgUzQgb2JqZWN0cy4NCg0KYGBgDQpTdGF0UGFja2FnZVJlc3VsdFI2JHNldCh3aGljaCA9ICJwdWJsaWMiLCBuYW1lID0gInZhbGlkYXRlIiwgDQogICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IGZ1bmN0aW9uKCkgew0KICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgIGlmKCFpcy5kYXRhLmZyYW1lKHNlbGYkc3RhdGlzdGljcykpew0KICAgICAgICAgICAgd2FybmluZygic3RhdGlzdGljcyBmaWVsZCBpcyBub3QgYSBkYXRhLmZyYW1lIikNCiAgICAgICAgICAgIHJldHVybihGQUxTRSkNCiAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgaWYoISJwdmFsdWUiICVpbiUgY29sbmFtZXMoc2VsZiRzdGF0aXN0aWNzKSl7DQogICAgICAgICAgICB3YXJuaW5nKCJzdGF0aXN0aWNzIGZpZWxkIGRvZXNuJ3QgY29udGFpbiANCiAgICAgICAgICAgICAgICBhIHB2YWx1ZSBjb2x1bW4iKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybihGQUxTRSkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAjcmV0dXJuIFRSVUUgb3RoZXJ3aXNlDQogICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybihUUlVFKQ0KICAgICAgICAgICAgICAgICAgICAgICAgfQ0KKQ0KYGBgDQoNCkhhdmluZyBhIGAkdmFsaWRhdGUoKWAgbWV0aG9kIGlzIGVzcGVjaWFsbHkgdXNlZnVsIHdoZW4gZ2V0dGluZyBhbmQgc2V0dGluZyBjb21wbGV4IGRhdGEgdHlwZXMgaW4gZmllbGRzLg0KDQpgYGB7cn0NCm15X3N0YXRzX3I2JHZhbGlkYXRlKCkNCmBgYA0KDQojIyBDaGFpbmluZyBNZXRob2RzDQoNCldoYXQgZG8geW91IHRoaW5rIHRoZSBmb2xsb3dpbmcgZG9lcz8NCg0KYGBge3J9DQpteV9zdGF0c19yNiRzZXRfdGhyZXNob2xkKDAuMjEpJGdldF9zaWduaWZpY2FudF9yZXN1bHRzKCkNCmBgYA0KDQpDaGFpbmluZyBtdWx0aXBsZSBtZXRob2RzIHRvZ2V0aGVyIGlzIGEgc3R5bGUgdGhhdCBpcyBjb21tb24gaW4gSmF2YVNjcmlwdCBhbmQgUHl0aG9uIGFuZCBjYW4gYmUgZG9uZSBieSBjaGFpbmluZyBgJG1ldGhvZHNgDQoNCiMjIE1haW50YWluaW5nIFN0YXRlIGlzIEltcG9ydGFudDogUjYvU2hpbnkNCg0KVGhlIG1haW4gdXNlIGNhc2UgSSd2ZSBmb3VuZCBmb3IgUjYgaW4gbXkgd29yayBpcyBmb3IgYnVpbGRpbmcgZGF0YSBvYmplY3RzIGluIFNoaW55LiBUaGUgZGF0YSBpcyBlbmNhcHN1bGF0ZWQgaW4gYW4gUjYgb2JqZWN0IHdoaWNoIGNhbiBwcm92aWRlIGRpZmZlcmVudCBmb3JtYXRzIG9mIHRoZSBkYXRhIGdpdmVuIGEgU2hpbnkgdmlzdWFsaXphdGlvbi4NCg0KSSB1c2UgUjYgaW4gbXkgU2hpbnkgYXBwcywgZm9yIG1vZHVsYXJpdHkgcmVhc29ucy4gVGhlIHNhbWUgZGF0YSBvYmplY3QgaXMgdXNlZCBmb3IgZGlmZmVyZW50IHZpc3VhbGl6YXRpb25zLCBzbyBJIGNhbiBkZXNpZ24gdGhlIHZpc3VhbGl6YXRpb25zIHRvIGV4cGVjdCBhIGNlcnRhaW4gZm9ybWF0IChsb25nIG9yIHdpZGUpLiBUaGlzIGdpdmVzIG1lIHRoZSBmbGV4aWJpbGl0eSBvZiBjaGFuZ2luZyB0aGUgaW50ZXJuYWwgZm9ybWF0IG9mIHRoZSBkYXRhIGZpZWxkcyBpbiB0aGUgb2JqZWN0IGlmIG5lY2Vzc2FyeS4gIA0KDQpIZXJlIGFyZSBteSBSNiBDbGFzc2VzOiBodHRwczovL2dpdGh1Yi5jb20vbGFkZXJhc3QvZmxvd0Rhc2hib2FyZC9ibG9iL21hc3Rlci9SL2NsYXNzZXMuUg0KDQpJIGRvbid0IG5lY2Vzc2FyaWx5IHRoaW5rIHRoaXMgaXMgdGhlIGJlc3QgaW1wbGVtZW50YXRpb24sIGJ1dCB5b3UgY2FuIHNlZSB3aGF0IEkgZGlkLg0KDQojIyBJbmhlcml0YW5jZQ0KDQpSNiBvYmplY3RzIGNhbiBpbmhlcml0IGZyb20gZWFjaCBvdGhlci4gSGVyZSB3ZSdyZSBtYWtpbmcgYSBuZXcgY2xhc3MgY2FsbGVkIGBBbm92YVJlc3VsdFI2YCwgdXNpbmcgdGhlIGBpbmhlcml0PWAgYXJndW1lbnQuIE91ciBgQW5vdmFSZXN1bHRSNmAgY2xhc3MgaGFzIGFuIGFkZGl0aW9uYWwgZmllbGQgd2UncmUgY2FsbGluZyBgZ3JvdXBzYC4gIA0KDQpXZSdyZSBvdmVycmlkaW5nIG91ciBgJGluaXRpYWxpemVgIG1ldGhvZCBmb3IgdGhlIGBTdGF0UGFja2FnZVJlc3VsdFI2YC4gSXQgc2V0cyB0aGUgYGdyb3Vwc2AgZmllbGQsIGFuZCB0aGVuIHVzZXMgYHN1cGVyJGluaXRpYWxpemUoKWAgdG8gc2V0IHRoZSBvdGhlciBmaWVsZHMgaW4gdGhlIG9iamVjdC4gYHN1cGVyYCBpcyB0aGUgZXF1aXZhbGVudCBvZiBgTmV4dE1ldGhvZCgpYCBpbiBTMy4NCg0KYGBgDQpBbm92YVJlc3VsdFI2IDwtIFI2OjpSNkNsYXNzKGNsYXNzbmFtZSA9ICJBbm92YVJlc3VsdFI2IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5oZXJpdD0iU3RhdFBhY2thZ2VSZXN1bHRSNiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHB1YmxpYyA9IA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3QoZ3JvdXBzID0gTlVMTCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5pdGlhbGl6ZT1mdW5jdGlvbihkYXRhLCBzdGF0aXN0aWNzLCBncm91cHMpew0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmJGdyb3VwcyA8LSBncm91cHMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VwZXIkaW5pdGlhbGl6ZShkYXRhLCBzdGF0aXN0aWNzKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnZpc2libGUoc2VsZikNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByaW50ID0gZnVuY3Rpb24oKXsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpbnQoc2VsZiRncm91cHMpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1cGVyJHByaW50KCkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICkNCmBgYA0KDQoNCkxldCdzIG1ha2UgYW4gYEFub3ZhUmVzdWx0UjZgIG9iamVjdDoNCg0KYGBge3J9DQpzdGF0X2ZyYW1lIDwtIGRhdGEuZnJhbWUoZ3JvdXA9Yygic2V0b3NhIiwgInZpcmdpbmljYSIsICJ2ZXJzaWNvbG9yIiksIHB2YWx1ZT1jKDAuNSwgMC4yLCAwLjAwMSkpDQoNCmFub3ZhX29iamVjdCA8LSBBbm92YVJlc3VsdFI2JG5ldyhkYXRhPWlyaXMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRpc3RpY3M9c3RhdF9mcmFtZSwgZ3JvdXBzPWMoInNldG9zYSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInZpcmdpbmljYSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInZlcnNpY29sb3IiKSkNCmBgYA0KDQpXZSBjYW4gc2VlIHRoYXQgb3VyIGBBbm92YVJlc3VsdFI2YCBvYmplY3QgaW5oZXJpdHMgZnJvbSBgU3RhdFBhY2thZ2VSZXN1bHRSNmAgYW5kIHRoYXQgaXQgaGFzIGFuIGFkZGl0aW9uYWwgYGdyb3Vwc2AgZmllbGQgaW4gcHVibGljLg0KDQpgYGB7cn0NCnN0cihhbm92YV9vYmplY3QpDQpgYGANCg0KQW5kIGl0IGNhbiB1c2UgdGhlIGAkZ2V0X3N0YXRpc3RpY3MoKWAgbWV0aG9kIGl0IGluaGVyaXRlZDoNCg0KYGBge3J9DQphbm92YV9vYmplY3QkZ2V0X3N0YXRpc3RpY3MoKQ0KYGBgDQoNCiMjIFI2IFF1aXJrczogQ29weSBCeSBSZWZlcmVuY2UNCg0KUjYgb2JqZWN0cyBhcmUgYnVpbHQgb24gZW52aXJvbm1lbnRzLiBUaGlzIG1lYW5zIHRoYXQgaWYgeW91IGFzc2lnbiBgbXlfc3RhdHNfcjZgIHRvIGEgbmV3IG9iamVjdCBgbmV3X215X3N0YXRzX3I2YCwgaXQncyBqdXN0IGEgcG9pbnRlciB0byB0aGUgb3JpZ2luYWwgb2JqZWN0Lg0KDQpgYGB7cn0NCm5ld19teV9zdGF0c19yNiA8LSBteV9zdGF0c19yNg0KDQpuZXdfbXlfc3RhdHNfcjYkc2V0X3RocmVzaG9sZCgwLjEpDQoNCm15X3N0YXRzX3I2JGdldF90aHJlc2hvbGQoKQ0KYGBgDQoNCklmIHlvdSBuZWVkIHRvIG1ha2UgYSBicmFuZCBuZXcgb2JqZWN0IHRoYXQgaXMgYSBzZXBhcmF0ZSBjb3B5IG9mIHRoYXQgb2JqZWN0LCB5b3UgbmVlZCB0byB1c2UgdGhlIGAkY2xvbmUoKWAgbWV0aG9kOg0KDQpgYGB7cn0NCm5ld19teV9zdGF0c19yNiA8LSBteV9zdGF0c19yNiRjbG9uZSgpDQoNCm5ld19teV9zdGF0c19yNiRzZXRfdGhyZXNob2xkKDAuNCkNCg0KbmV3X215X3N0YXRzX3I2JGdldF90aHJlc2hvbGQoKQ0KDQpteV9zdGF0c19yNiRnZXRfdGhyZXNob2xkKCkNCg0KYGBgDQoNCklmIHlvdXIgUjYgb2JqZWN0IGNvbnRhaW5zIG90aGVyIFI2IG9iamVjdHMgYXMgZmllbGRzIGFuZCB5b3Ugd2FudCB0byBjbG9uZSB0aGVzZSBhcyB3ZWxsLCB5b3UnbGwgaGF2ZSB0byBhZGRpdGlvbmFsbHkgYXBwbHkgdGhlIGBkZWVwPVRSVUVgIGFyZ3VtZW50Lg0KDQojIyBOb3RlOiBSNiBpcyBXZWlyZCB0byBtb3N0IFIgdXNlcnMNCg0KWW91IHByb2JhYmx5IGRvbid0IHdhbnQgaGF2ZSB5b3VyIGZpbmFsIHJlc3VsdHMgb2JqZWN0IGFzIGFuIFI2IGNsYXNzLiBNb3N0bHkgYmVjYXVzZSBtb3N0IHVzZXJzIGFyZW4ndCBmYW1pbGlhciB3aXRoIFI2IGFuZCB1c2luZyBtZXRob2RzIGF0dGFjaGVkIHRvIGFuIG9iamVjdC4gSSBsZWFybmVkIHRoaXMgdGhlIGhhcmQgd2F5Lg0KDQpUaGUgb25lIGV4Y2VwdGlvbiBpcyB3aGVuIHlvdXIgcGFja2FnZSBpcyBnb2luZyB0byBiZSB1c2VkIGJ5IGRldmVsb3BlcnMgLSB0aGV5IHdpbGwgcHJvYmFibHkgYmUgbW9yZSBmYW1pbGlhciB3aXRoIHRoZSBSNiBvYmplY3Qgc3RydWN0dXJlIGFuZCBnZXR0aW5nIHRoaW5ncyBvdXQgb2YgaXQuDQoNCiMjIFRoaW5ncyB3ZSBkaWRuJ3QgY292ZXINCg0KLSBSNiBDbGFzc2VzIGFsc28gaGF2ZSBhbiBgYWN0aXZlYCBzbG90LCB3aGljaCBoYXMgaXRzIHVzZXMuIA0KLSBNdWx0aXBsZSBpbmhlcml0YW5jZQ0KDQojIyBSZXNvdXJjZXMNCg0KaHR0cHM6Ly9hZHYtci5oYWRsZXkubnovcjYuaHRtbA0KDQo=