Hello! Welcome to this, the final of your hard-core R workshops in LIFE4138.

Last time, we looked at:

So, today we are going to go back to the for loops, and talk about a slightly different way of approaching the same problem. for loops are a fundemental part of coding in any language, although R was designed for them to be avoided, with the creation of a special family of functions unique to R, the apply() family. The three functions from this family that we’ll focus on here are:

What is apply?

The apply family of functions allow you to create a piece of code analagous to a for loop, allowing you to iterate over the items in a data structure, and apply a function or set of functions to either rows or columns of the data structure in turn. You might have a series of dataframes and you want to count the columns within them - you could do this with a for loop, or, you could use the R exclusive apply family to achieve the same thing in a much speedier and more efficient way. The apply functions were developed to avoid the use of looping in R, and are usually much faster (not always!) - there are some cases where running an apply function will be slower or considerably more tricky to do, but they’re a useful thing to learn, which will allow you to further advance your R coding prowess.

That being said, the apply functions can be quite tricky to understand and get your head around. Generally, the help files for the apply functions are a bit rubbish, and it’s tricky to find places where they are well explained. It took me a while to fully understand exactly what outcome I’d get when using apply(), and sometimes it still takes me a couple of goes to get it exactly right. Our aim here isn’t to develop some super complex functions, but to demystify them and get you famililar with how they work and where they might be useful. They’re certainly worth taking the time to understand.

There are functions beyond apply(), lapply() and sapply(), but these are the three that we will focus on today:

These functions are incredibly useful to expand your R toolkit, and once you’ve got to grips with using them, you’ll find other complex R functions much easier to understand too!

apply()

Right - we’ll start with apply(). We’ll have a quick go at using apply, then dissect it a little. First up, we need our iris data - remember to make sure the in-built R datasets are loaded first, and then have a look at iris with with head() function:

data()
head(iris)

We can see that iris has 5 columns - for now, we’re going to get rid of the species column as it’s actually going to make our life a little more difficult than we’d like, so we’ll create a new object with the iris dataframe, minus the 5th column:

Run the head() function on the new df to check that your code has removed the correct column - you should be left with 4 (petal and sepal width and length measurements). Above we can see that we have correctly removed the species column, so we can carry on! The reason we removed the species vector was to allow us to have a nice clean dataset with only numeric values inside of it, so we can more easily demonstrate apply().

Now we have a dataset where each column is a set of values pertaining to 150 observations of something. What if we want to find the means of each of these columns? There are several ways we can do this without using apply(), such as:

mean(my_iris[,1])
[1] 5.843333
mean(my_iris[,2])
[1] 3.057333
mean(my_iris[,3])
[1] 3.758
mean(my_iris[,4])
[1] 1.199333

This is theoretically achievable with only 4 columns, but is clunky and repetitive. We want to write a single command that will iterate over the entire dataset for us. We could also achieve it with a for loop:

for (x in 1:ncol(my_iris)){
  print(mean(my_iris[,x]))
}
[1] 5.843333
[1] 3.057333
[1] 3.758
[1] 1.199333

This loop has taken every value between 1 and the number of columns in the iris dataset, gives x that value, and works out the mean according to the column index. This isn’t the most efficient way of doing things, and can be a little complex to construct. It would also take ages if we were using a big dataset.

Arguably, a much quicker and more efficient way of achieving this is by using apply(). This function is structured with 3 arguments, you tell it what data you would like it to work with, and then what dimension of the data (either row or column in this case), and then we feed apply a function for it to perform on each of the dimensions of the dataset in turn. Let’s construct our first example, and then we can dissect it a little more - we will use the apply() function to achieve what we just did the hard way:

apply(my_iris, 2, mean)
Sepal.Length  Sepal.Width Petal.Length  Petal.Width 
    5.843333     3.057333     3.758000     1.199333 

You can see that apply also gives us a nicer output! But, back to the anatomy of apply. There are three arguments:

apply(my_iris, 1, mean)
  [1] 2.550 2.375 2.350 2.350 2.550 2.850 2.425 2.525 2.225 2.400 2.700 2.500 2.325 2.125 2.800 3.000 2.750 2.575
 [19] 2.875 2.675 2.675 2.675 2.350 2.650 2.575 2.450 2.600 2.600 2.550 2.425 2.425 2.675 2.725 2.825 2.425 2.400
 [37] 2.625 2.500 2.225 2.550 2.525 2.100 2.275 2.675 2.800 2.375 2.675 2.350 2.675 2.475 4.075 3.900 4.100 3.275
 [55] 3.850 3.575 3.975 2.900 3.850 3.300 2.875 3.650 3.300 3.775 3.350 3.900 3.650 3.400 3.600 3.275 3.925 3.550
 [73] 3.800 3.700 3.725 3.850 3.950 4.100 3.725 3.200 3.200 3.150 3.400 3.850 3.600 3.875 4.000 3.575 3.500 3.325
 [91] 3.425 3.775 3.400 2.900 3.450 3.525 3.525 3.675 2.925 3.475 4.525 3.875 4.525 4.150 4.375 4.825 3.400 4.575
[109] 4.200 4.850 4.200 4.075 4.350 3.800 4.025 4.300 4.200 5.100 4.875 3.675 4.525 3.825 4.800 3.925 4.450 4.550
[127] 3.900 3.950 4.225 4.400 4.550 5.025 4.250 3.925 3.925 4.775 4.425 4.200 3.900 4.375 4.450 4.350 3.875 4.550
[145] 4.550 4.300 3.925 4.175 4.325 3.950

This is somewhat meaningless biologically, but illustrates the point. Anyway, our third argument…

So, using a single line of code, we have managed to achieve what took us much more effort to perform manually or with a loop. That being said, there is a baseR function which will work out the column means of a dataset without having to use apply - colMeans().

colMeans(my_iris)
Sepal.Length  Sepal.Width Petal.Length  Petal.Width 
    5.843333     3.057333     3.758000     1.199333 

The point of telling you this isn’t to invalidate the use of apply or any of the other methods, but to get you to think about your use of code. Often, particularly with vectorisation, there is a much simpler and more straightforward way of performing quite complex commands in R - don’t forget it was literally designed to be simple! Note that some of the best coders are lazy, we’re always looking for quicker and easier ways of doing things to make our own lives easy. It is however important to strike a balance between finding a quicker way, and the time that you can spend finding that quicker way!! Don’t forget your R philosophies, and my favourite thing to say when teaching R - If it works, it works!

Going further with `apply

We’ve constructed an apply function in its most basic form, but we can go much further with them. What if, for example, there was a rogue NA in our dataset? We’ve seen in the past that lots of functions can’t handle this very well! Let’s pop one into our my_iris data and run the apply function again:

my_iris[5,2] <- NA
apply(my_iris, 2, mean)
Sepal.Length  Sepal.Width Petal.Length  Petal.Width 
    5.843333           NA     3.758000     1.199333 

Just as suspected, we’ve got an NA result for our column with the NA value. We can add function arguments into an apply function simply by popping them on the end sequentially, separated by commas. Let’s try and add the na.rm = TRUE argument to our function to fix the issue

apply(my_iris, 2, mean, na.rm = TRUE)
Sepal.Length  Sepal.Width Petal.Length  Petal.Width 
    5.843333     3.053691     3.758000     1.199333 

Piece of cake. Apply is super flexible, let’s construct another function just to really hammer home the point - we’ll try with sum() this time:

apply(my_iris, 2, sum, na.rm = TRUE)
Sepal.Length  Sepal.Width Petal.Length  Petal.Width 
       876.5        455.0        563.7        179.9 

apply() is super quick, and very useful. Whilst at first it takes some getting used to, once you’ve constructed a couple, they will become second nature.

We can also write our own functions, and use them with apply(). Let’s create a function to square a series of values

As a very quick reminder, this bit of code tells R that we want to create a function called square with a single argument x. R will assign whatever value we give the square function to x, and perform the code in the body of the function (the stuff enclosed in the {}). Let’s test square to make sure it does what we’re expecting before we use it with apply()

square(10)
[1] 100

Wonderful, our function is performing as we would expect. Now, we can pop it into apply and square each of the values in the dataset.

apply(my_iris, 2, square)
       Sepal.Length Sepal.Width Petal.Length Petal.Width
  [1,]        26.01       12.25         1.96        0.04
  [2,]        24.01        9.00         1.96        0.04
  [3,]        22.09       10.24         1.69        0.04
  [4,]        21.16        9.61         2.25        0.04
  [5,]        25.00          NA         1.96        0.04
  [6,]        29.16       15.21         2.89        0.16
  [7,]        21.16       11.56         1.96        0.09
  [8,]        25.00       11.56         2.25        0.04
  [9,]        19.36        8.41         1.96        0.04
 [10,]        24.01        9.61         2.25        0.01
 [11,]        29.16       13.69         2.25        0.04
 [12,]        23.04       11.56         2.56        0.04
 [13,]        23.04        9.00         1.96        0.01
 [14,]        18.49        9.00         1.21        0.01
 [15,]        33.64       16.00         1.44        0.04
 [16,]        32.49       19.36         2.25        0.16
 [17,]        29.16       15.21         1.69        0.16
 [18,]        26.01       12.25         1.96        0.09
 [19,]        32.49       14.44         2.89        0.09
 [20,]        26.01       14.44         2.25        0.09
 [21,]        29.16       11.56         2.89        0.04
 [22,]        26.01       13.69         2.25        0.16
 [23,]        21.16       12.96         1.00        0.04
 [24,]        26.01       10.89         2.89        0.25
 [25,]        23.04       11.56         3.61        0.04
 [26,]        25.00        9.00         2.56        0.04
 [27,]        25.00       11.56         2.56        0.16
 [28,]        27.04       12.25         2.25        0.04
 [29,]        27.04       11.56         1.96        0.04
 [30,]        22.09       10.24         2.56        0.04
 [31,]        23.04        9.61         2.56        0.04
 [32,]        29.16       11.56         2.25        0.16
 [33,]        27.04       16.81         2.25        0.01
 [34,]        30.25       17.64         1.96        0.04
 [35,]        24.01        9.61         2.25        0.04
 [36,]        25.00       10.24         1.44        0.04
 [37,]        30.25       12.25         1.69        0.04
 [38,]        24.01       12.96         1.96        0.01
 [39,]        19.36        9.00         1.69        0.04
 [40,]        26.01       11.56         2.25        0.04
 [41,]        25.00       12.25         1.69        0.09
 [42,]        20.25        5.29         1.69        0.09
 [43,]        19.36       10.24         1.69        0.04
 [44,]        25.00       12.25         2.56        0.36
 [45,]        26.01       14.44         3.61        0.16
 [46,]        23.04        9.00         1.96        0.09
 [47,]        26.01       14.44         2.56        0.04
 [48,]        21.16       10.24         1.96        0.04
 [49,]        28.09       13.69         2.25        0.04
 [50,]        25.00       10.89         1.96        0.04
 [51,]        49.00       10.24        22.09        1.96
 [52,]        40.96       10.24        20.25        2.25
 [53,]        47.61        9.61        24.01        2.25
 [54,]        30.25        5.29        16.00        1.69
 [55,]        42.25        7.84        21.16        2.25
 [56,]        32.49        7.84        20.25        1.69
 [57,]        39.69       10.89        22.09        2.56
 [58,]        24.01        5.76        10.89        1.00
 [59,]        43.56        8.41        21.16        1.69
 [60,]        27.04        7.29        15.21        1.96
 [61,]        25.00        4.00        12.25        1.00
 [62,]        34.81        9.00        17.64        2.25
 [63,]        36.00        4.84        16.00        1.00
 [64,]        37.21        8.41        22.09        1.96
 [65,]        31.36        8.41        12.96        1.69
 [66,]        44.89        9.61        19.36        1.96
 [67,]        31.36        9.00        20.25        2.25
 [68,]        33.64        7.29        16.81        1.00
 [69,]        38.44        4.84        20.25        2.25
 [70,]        31.36        6.25        15.21        1.21
 [71,]        34.81       10.24        23.04        3.24
 [72,]        37.21        7.84        16.00        1.69
 [73,]        39.69        6.25        24.01        2.25
 [74,]        37.21        7.84        22.09        1.44
 [75,]        40.96        8.41        18.49        1.69
 [76,]        43.56        9.00        19.36        1.96
 [77,]        46.24        7.84        23.04        1.96
 [78,]        44.89        9.00        25.00        2.89
 [79,]        36.00        8.41        20.25        2.25
 [80,]        32.49        6.76        12.25        1.00
 [81,]        30.25        5.76        14.44        1.21
 [82,]        30.25        5.76        13.69        1.00
 [83,]        33.64        7.29        15.21        1.44
 [84,]        36.00        7.29        26.01        2.56
 [85,]        29.16        9.00        20.25        2.25
 [86,]        36.00       11.56        20.25        2.56
 [87,]        44.89        9.61        22.09        2.25
 [88,]        39.69        5.29        19.36        1.69
 [89,]        31.36        9.00        16.81        1.69
 [90,]        30.25        6.25        16.00        1.69
 [91,]        30.25        6.76        19.36        1.44
 [92,]        37.21        9.00        21.16        1.96
 [93,]        33.64        6.76        16.00        1.44
 [94,]        25.00        5.29        10.89        1.00
 [95,]        31.36        7.29        17.64        1.69
 [96,]        32.49        9.00        17.64        1.44
 [97,]        32.49        8.41        17.64        1.69
 [98,]        38.44        8.41        18.49        1.69
 [99,]        26.01        6.25         9.00        1.21
[100,]        32.49        7.84        16.81        1.69
[101,]        39.69       10.89        36.00        6.25
[102,]        33.64        7.29        26.01        3.61
[103,]        50.41        9.00        34.81        4.41
[104,]        39.69        8.41        31.36        3.24
[105,]        42.25        9.00        33.64        4.84
[106,]        57.76        9.00        43.56        4.41
[107,]        24.01        6.25        20.25        2.89
[108,]        53.29        8.41        39.69        3.24
[109,]        44.89        6.25        33.64        3.24
[110,]        51.84       12.96        37.21        6.25
[111,]        42.25       10.24        26.01        4.00
[112,]        40.96        7.29        28.09        3.61
[113,]        46.24        9.00        30.25        4.41
[114,]        32.49        6.25        25.00        4.00
[115,]        33.64        7.84        26.01        5.76
[116,]        40.96       10.24        28.09        5.29
[117,]        42.25        9.00        30.25        3.24
[118,]        59.29       14.44        44.89        4.84
[119,]        59.29        6.76        47.61        5.29
[120,]        36.00        4.84        25.00        2.25
[121,]        47.61       10.24        32.49        5.29
[122,]        31.36        7.84        24.01        4.00
[123,]        59.29        7.84        44.89        4.00
[124,]        39.69        7.29        24.01        3.24
[125,]        44.89       10.89        32.49        4.41
[126,]        51.84       10.24        36.00        3.24
[127,]        38.44        7.84        23.04        3.24
[128,]        37.21        9.00        24.01        3.24
[129,]        40.96        7.84        31.36        4.41
[130,]        51.84        9.00        33.64        2.56
[131,]        54.76        7.84        37.21        3.61
[132,]        62.41       14.44        40.96        4.00
[133,]        40.96        7.84        31.36        4.84
[134,]        39.69        7.84        26.01        2.25
[135,]        37.21        6.76        31.36        1.96
[136,]        59.29        9.00        37.21        5.29
[137,]        39.69       11.56        31.36        5.76
[138,]        40.96        9.61        30.25        3.24
[139,]        36.00        9.00        23.04        3.24
[140,]        47.61        9.61        29.16        4.41
[141,]        44.89        9.61        31.36        5.76
[142,]        47.61        9.61        26.01        5.29
[143,]        33.64        7.29        26.01        3.61
[144,]        46.24       10.24        34.81        5.29
[145,]        44.89       10.89        32.49        6.25
[146,]        44.89        9.00        27.04        5.29
[147,]        39.69        6.25        25.00        3.61
[148,]        42.25        9.00        27.04        4.00
[149,]        38.44       11.56        29.16        5.29
[150,]        34.81        9.00        26.01        3.24

R has returned the whole dataset to us (because we gave it a function to perform on every value, rather than a series of values like sum or mean). Each value within the dataset is squared!

This is a simple e.g., but it is always worth knowing that there are alternatives. There are loads of ways to do everything in R, and being aware of them all will help you to solve errors and think about the way that your functions are performing in order to get the best possible results. For example, here, we could also run

my_iris^2

The lesson here is that you should be lazy! Look for the quickest and easiest solution to any given task! Having the knowledge of both all of the code alternatives and an understanding of the way that R processes and behaves with various data structures will give you a great starting point - you will be able to write really simple and efficient code, and have a variety of tricks up your sleeve for when you can’t quite get the first attempt to work. Of course, here, there are simple alternatives because of the nature of the examples I’m giving you, but you might have to think more carefully about this when it comes to writing your own code to perform much more complicated tasks for you!

Now - we’ve covered the basics of how the apply function works, and talked about what sorts of functions you can use it for. The final thing to say about apply() specifically (although this applies to all of the apply family) is with regards to anonymous functions. There may be a case where you want to use a custom function, but without explicitly defining it within your text. The apply family allow you to specifiy a custom function to use within an apply() function, without having to explicitly define it in your code. We can slightly alter the way that apply() is written in order to get it to perform something within a code block (remember the {}).

Let’s try and square the values of my_iris again, this time, without explicitly declaring a function to do so:

apply(my_iris, 2, function(x){
  x^2
})
       Sepal.Length Sepal.Width Petal.Length Petal.Width
  [1,]        26.01       12.25         1.96        0.04
  [2,]        24.01        9.00         1.96        0.04
  [3,]        22.09       10.24         1.69        0.04
  [4,]        21.16        9.61         2.25        0.04
  [5,]        25.00          NA         1.96        0.04
  [6,]        29.16       15.21         2.89        0.16
  [7,]        21.16       11.56         1.96        0.09
  [8,]        25.00       11.56         2.25        0.04
  [9,]        19.36        8.41         1.96        0.04
 [10,]        24.01        9.61         2.25        0.01
 [11,]        29.16       13.69         2.25        0.04
 [12,]        23.04       11.56         2.56        0.04
 [13,]        23.04        9.00         1.96        0.01
 [14,]        18.49        9.00         1.21        0.01
 [15,]        33.64       16.00         1.44        0.04
 [16,]        32.49       19.36         2.25        0.16
 [17,]        29.16       15.21         1.69        0.16
 [18,]        26.01       12.25         1.96        0.09
 [19,]        32.49       14.44         2.89        0.09
 [20,]        26.01       14.44         2.25        0.09
 [21,]        29.16       11.56         2.89        0.04
 [22,]        26.01       13.69         2.25        0.16
 [23,]        21.16       12.96         1.00        0.04
 [24,]        26.01       10.89         2.89        0.25
 [25,]        23.04       11.56         3.61        0.04
 [26,]        25.00        9.00         2.56        0.04
 [27,]        25.00       11.56         2.56        0.16
 [28,]        27.04       12.25         2.25        0.04
 [29,]        27.04       11.56         1.96        0.04
 [30,]        22.09       10.24         2.56        0.04
 [31,]        23.04        9.61         2.56        0.04
 [32,]        29.16       11.56         2.25        0.16
 [33,]        27.04       16.81         2.25        0.01
 [34,]        30.25       17.64         1.96        0.04
 [35,]        24.01        9.61         2.25        0.04
 [36,]        25.00       10.24         1.44        0.04
 [37,]        30.25       12.25         1.69        0.04
 [38,]        24.01       12.96         1.96        0.01
 [39,]        19.36        9.00         1.69        0.04
 [40,]        26.01       11.56         2.25        0.04
 [41,]        25.00       12.25         1.69        0.09
 [42,]        20.25        5.29         1.69        0.09
 [43,]        19.36       10.24         1.69        0.04
 [44,]        25.00       12.25         2.56        0.36
 [45,]        26.01       14.44         3.61        0.16
 [46,]        23.04        9.00         1.96        0.09
 [47,]        26.01       14.44         2.56        0.04
 [48,]        21.16       10.24         1.96        0.04
 [49,]        28.09       13.69         2.25        0.04
 [50,]        25.00       10.89         1.96        0.04
 [51,]        49.00       10.24        22.09        1.96
 [52,]        40.96       10.24        20.25        2.25
 [53,]        47.61        9.61        24.01        2.25
 [54,]        30.25        5.29        16.00        1.69
 [55,]        42.25        7.84        21.16        2.25
 [56,]        32.49        7.84        20.25        1.69
 [57,]        39.69       10.89        22.09        2.56
 [58,]        24.01        5.76        10.89        1.00
 [59,]        43.56        8.41        21.16        1.69
 [60,]        27.04        7.29        15.21        1.96
 [61,]        25.00        4.00        12.25        1.00
 [62,]        34.81        9.00        17.64        2.25
 [63,]        36.00        4.84        16.00        1.00
 [64,]        37.21        8.41        22.09        1.96
 [65,]        31.36        8.41        12.96        1.69
 [66,]        44.89        9.61        19.36        1.96
 [67,]        31.36        9.00        20.25        2.25
 [68,]        33.64        7.29        16.81        1.00
 [69,]        38.44        4.84        20.25        2.25
 [70,]        31.36        6.25        15.21        1.21
 [71,]        34.81       10.24        23.04        3.24
 [72,]        37.21        7.84        16.00        1.69
 [73,]        39.69        6.25        24.01        2.25
 [74,]        37.21        7.84        22.09        1.44
 [75,]        40.96        8.41        18.49        1.69
 [76,]        43.56        9.00        19.36        1.96
 [77,]        46.24        7.84        23.04        1.96
 [78,]        44.89        9.00        25.00        2.89
 [79,]        36.00        8.41        20.25        2.25
 [80,]        32.49        6.76        12.25        1.00
 [81,]        30.25        5.76        14.44        1.21
 [82,]        30.25        5.76        13.69        1.00
 [83,]        33.64        7.29        15.21        1.44
 [84,]        36.00        7.29        26.01        2.56
 [85,]        29.16        9.00        20.25        2.25
 [86,]        36.00       11.56        20.25        2.56
 [87,]        44.89        9.61        22.09        2.25
 [88,]        39.69        5.29        19.36        1.69
 [89,]        31.36        9.00        16.81        1.69
 [90,]        30.25        6.25        16.00        1.69
 [91,]        30.25        6.76        19.36        1.44
 [92,]        37.21        9.00        21.16        1.96
 [93,]        33.64        6.76        16.00        1.44
 [94,]        25.00        5.29        10.89        1.00
 [95,]        31.36        7.29        17.64        1.69
 [96,]        32.49        9.00        17.64        1.44
 [97,]        32.49        8.41        17.64        1.69
 [98,]        38.44        8.41        18.49        1.69
 [99,]        26.01        6.25         9.00        1.21
[100,]        32.49        7.84        16.81        1.69
[101,]        39.69       10.89        36.00        6.25
[102,]        33.64        7.29        26.01        3.61
[103,]        50.41        9.00        34.81        4.41
[104,]        39.69        8.41        31.36        3.24
[105,]        42.25        9.00        33.64        4.84
[106,]        57.76        9.00        43.56        4.41
[107,]        24.01        6.25        20.25        2.89
[108,]        53.29        8.41        39.69        3.24
[109,]        44.89        6.25        33.64        3.24
[110,]        51.84       12.96        37.21        6.25
[111,]        42.25       10.24        26.01        4.00
[112,]        40.96        7.29        28.09        3.61
[113,]        46.24        9.00        30.25        4.41
[114,]        32.49        6.25        25.00        4.00
[115,]        33.64        7.84        26.01        5.76
[116,]        40.96       10.24        28.09        5.29
[117,]        42.25        9.00        30.25        3.24
[118,]        59.29       14.44        44.89        4.84
[119,]        59.29        6.76        47.61        5.29
[120,]        36.00        4.84        25.00        2.25
[121,]        47.61       10.24        32.49        5.29
[122,]        31.36        7.84        24.01        4.00
[123,]        59.29        7.84        44.89        4.00
[124,]        39.69        7.29        24.01        3.24
[125,]        44.89       10.89        32.49        4.41
[126,]        51.84       10.24        36.00        3.24
[127,]        38.44        7.84        23.04        3.24
[128,]        37.21        9.00        24.01        3.24
[129,]        40.96        7.84        31.36        4.41
[130,]        51.84        9.00        33.64        2.56
[131,]        54.76        7.84        37.21        3.61
[132,]        62.41       14.44        40.96        4.00
[133,]        40.96        7.84        31.36        4.84
[134,]        39.69        7.84        26.01        2.25
[135,]        37.21        6.76        31.36        1.96
[136,]        59.29        9.00        37.21        5.29
[137,]        39.69       11.56        31.36        5.76
[138,]        40.96        9.61        30.25        3.24
[139,]        36.00        9.00        23.04        3.24
[140,]        47.61        9.61        29.16        4.41
[141,]        44.89        9.61        31.36        5.76
[142,]        47.61        9.61        26.01        5.29
[143,]        33.64        7.29        26.01        3.61
[144,]        46.24       10.24        34.81        5.29
[145,]        44.89       10.89        32.49        6.25
[146,]        44.89        9.00        27.04        5.29
[147,]        39.69        6.25        25.00        3.61
[148,]        42.25        9.00        27.04        4.00
[149,]        38.44       11.56        29.16        5.29
[150,]        34.81        9.00        26.01        3.24

Wonderful! Let’s have a look at the syntax:

  • apply(my_iris, 2, ...) - the basic function is constructed in the same way as normal
  • apply(my_iris, 2, function(x){ body of function }) - we use the function(x) argument in a similar way to usual, but we don’t close the apply() parentheses until after we’ve constructed the body of the function

This can be quite tricky to grasp fully the first few times you do it, but essentially, you’re telling R to look at the my_iris data, take each column, call it x, then perform a bit of code on it.

We already know that this example is perhaps slightly redundant because we can just raise the entire dataframe to the power 2, but anonymous functions might be useful elsewhere. Let’s write a more complex apply with an anonymous function to count the number of NAs that we have in each column of our data. We’ll start, by getting R to identify where the NAs are by writing an anonymous function with is.na() inside apply:

apply(my_iris, 2, function(x){
  is.na(x)
})
       Sepal.Length Sepal.Width Petal.Length Petal.Width
  [1,]        FALSE       FALSE        FALSE       FALSE
  [2,]        FALSE       FALSE        FALSE       FALSE
  [3,]        FALSE       FALSE        FALSE       FALSE
  [4,]        FALSE       FALSE        FALSE       FALSE
  [5,]        FALSE        TRUE        FALSE       FALSE
  [6,]        FALSE       FALSE        FALSE       FALSE
  [7,]        FALSE       FALSE        FALSE       FALSE
  [8,]        FALSE       FALSE        FALSE       FALSE
  [9,]        FALSE       FALSE        FALSE       FALSE
 [10,]        FALSE       FALSE        FALSE       FALSE
 [11,]        FALSE       FALSE        FALSE       FALSE
 [12,]        FALSE       FALSE        FALSE       FALSE
 [13,]        FALSE       FALSE        FALSE       FALSE
 [14,]        FALSE       FALSE        FALSE       FALSE
 [15,]        FALSE       FALSE        FALSE       FALSE
 [16,]        FALSE       FALSE        FALSE       FALSE
 [17,]        FALSE       FALSE        FALSE       FALSE
 [18,]        FALSE       FALSE        FALSE       FALSE
 [19,]        FALSE       FALSE        FALSE       FALSE
 [20,]        FALSE       FALSE        FALSE       FALSE
 [21,]        FALSE       FALSE        FALSE       FALSE
 [22,]        FALSE       FALSE        FALSE       FALSE
 [23,]        FALSE       FALSE        FALSE       FALSE
 [24,]        FALSE       FALSE        FALSE       FALSE
 [25,]        FALSE       FALSE        FALSE       FALSE
 [26,]        FALSE       FALSE        FALSE       FALSE
 [27,]        FALSE       FALSE        FALSE       FALSE
 [28,]        FALSE       FALSE        FALSE       FALSE
 [29,]        FALSE       FALSE        FALSE       FALSE
 [30,]        FALSE       FALSE        FALSE       FALSE
 [31,]        FALSE       FALSE        FALSE       FALSE
 [32,]        FALSE       FALSE        FALSE       FALSE
 [33,]        FALSE       FALSE        FALSE       FALSE
 [34,]        FALSE       FALSE        FALSE       FALSE
 [35,]        FALSE       FALSE        FALSE       FALSE
 [36,]        FALSE       FALSE        FALSE       FALSE
 [37,]        FALSE       FALSE        FALSE       FALSE
 [38,]        FALSE       FALSE        FALSE       FALSE
 [39,]        FALSE       FALSE        FALSE       FALSE
 [40,]        FALSE       FALSE        FALSE       FALSE
 [41,]        FALSE       FALSE        FALSE       FALSE
 [42,]        FALSE       FALSE        FALSE       FALSE
 [43,]        FALSE       FALSE        FALSE       FALSE
 [44,]        FALSE       FALSE        FALSE       FALSE
 [45,]        FALSE       FALSE        FALSE       FALSE
 [46,]        FALSE       FALSE        FALSE       FALSE
 [47,]        FALSE       FALSE        FALSE       FALSE
 [48,]        FALSE       FALSE        FALSE       FALSE
 [49,]        FALSE       FALSE        FALSE       FALSE
 [50,]        FALSE       FALSE        FALSE       FALSE
 [51,]        FALSE       FALSE        FALSE       FALSE
 [52,]        FALSE       FALSE        FALSE       FALSE
 [53,]        FALSE       FALSE        FALSE       FALSE
 [54,]        FALSE       FALSE        FALSE       FALSE
 [55,]        FALSE       FALSE        FALSE       FALSE
 [56,]        FALSE       FALSE        FALSE       FALSE
 [57,]        FALSE       FALSE        FALSE       FALSE
 [58,]        FALSE       FALSE        FALSE       FALSE
 [59,]        FALSE       FALSE        FALSE       FALSE
 [60,]        FALSE       FALSE        FALSE       FALSE
 [61,]        FALSE       FALSE        FALSE       FALSE
 [62,]        FALSE       FALSE        FALSE       FALSE
 [63,]        FALSE       FALSE        FALSE       FALSE
 [64,]        FALSE       FALSE        FALSE       FALSE
 [65,]        FALSE       FALSE        FALSE       FALSE
 [66,]        FALSE       FALSE        FALSE       FALSE
 [67,]        FALSE       FALSE        FALSE       FALSE
 [68,]        FALSE       FALSE        FALSE       FALSE
 [69,]        FALSE       FALSE        FALSE       FALSE
 [70,]        FALSE       FALSE        FALSE       FALSE
 [71,]        FALSE       FALSE        FALSE       FALSE
 [72,]        FALSE       FALSE        FALSE       FALSE
 [73,]        FALSE       FALSE        FALSE       FALSE
 [74,]        FALSE       FALSE        FALSE       FALSE
 [75,]        FALSE       FALSE        FALSE       FALSE
 [76,]        FALSE       FALSE        FALSE       FALSE
 [77,]        FALSE       FALSE        FALSE       FALSE
 [78,]        FALSE       FALSE        FALSE       FALSE
 [79,]        FALSE       FALSE        FALSE       FALSE
 [80,]        FALSE       FALSE        FALSE       FALSE
 [81,]        FALSE       FALSE        FALSE       FALSE
 [82,]        FALSE       FALSE        FALSE       FALSE
 [83,]        FALSE       FALSE        FALSE       FALSE
 [84,]        FALSE       FALSE        FALSE       FALSE
 [85,]        FALSE       FALSE        FALSE       FALSE
 [86,]        FALSE       FALSE        FALSE       FALSE
 [87,]        FALSE       FALSE        FALSE       FALSE
 [88,]        FALSE       FALSE        FALSE       FALSE
 [89,]        FALSE       FALSE        FALSE       FALSE
 [90,]        FALSE       FALSE        FALSE       FALSE
 [91,]        FALSE       FALSE        FALSE       FALSE
 [92,]        FALSE       FALSE        FALSE       FALSE
 [93,]        FALSE       FALSE        FALSE       FALSE
 [94,]        FALSE       FALSE        FALSE       FALSE
 [95,]        FALSE       FALSE        FALSE       FALSE
 [96,]        FALSE       FALSE        FALSE       FALSE
 [97,]        FALSE       FALSE        FALSE       FALSE
 [98,]        FALSE       FALSE        FALSE       FALSE
 [99,]        FALSE       FALSE        FALSE       FALSE
[100,]        FALSE       FALSE        FALSE       FALSE
[101,]        FALSE       FALSE        FALSE       FALSE
[102,]        FALSE       FALSE        FALSE       FALSE
[103,]        FALSE       FALSE        FALSE       FALSE
[104,]        FALSE       FALSE        FALSE       FALSE
[105,]        FALSE       FALSE        FALSE       FALSE
[106,]        FALSE       FALSE        FALSE       FALSE
[107,]        FALSE       FALSE        FALSE       FALSE
[108,]        FALSE       FALSE        FALSE       FALSE
[109,]        FALSE       FALSE        FALSE       FALSE
[110,]        FALSE       FALSE        FALSE       FALSE
[111,]        FALSE       FALSE        FALSE       FALSE
[112,]        FALSE       FALSE        FALSE       FALSE
[113,]        FALSE       FALSE        FALSE       FALSE
[114,]        FALSE       FALSE        FALSE       FALSE
[115,]        FALSE       FALSE        FALSE       FALSE
[116,]        FALSE       FALSE        FALSE       FALSE
[117,]        FALSE       FALSE        FALSE       FALSE
[118,]        FALSE       FALSE        FALSE       FALSE
[119,]        FALSE       FALSE        FALSE       FALSE
[120,]        FALSE       FALSE        FALSE       FALSE
[121,]        FALSE       FALSE        FALSE       FALSE
[122,]        FALSE       FALSE        FALSE       FALSE
[123,]        FALSE       FALSE        FALSE       FALSE
[124,]        FALSE       FALSE        FALSE       FALSE
[125,]        FALSE       FALSE        FALSE       FALSE
[126,]        FALSE       FALSE        FALSE       FALSE
[127,]        FALSE       FALSE        FALSE       FALSE
[128,]        FALSE       FALSE        FALSE       FALSE
[129,]        FALSE       FALSE        FALSE       FALSE
[130,]        FALSE       FALSE        FALSE       FALSE
[131,]        FALSE       FALSE        FALSE       FALSE
[132,]        FALSE       FALSE        FALSE       FALSE
[133,]        FALSE       FALSE        FALSE       FALSE
[134,]        FALSE       FALSE        FALSE       FALSE
[135,]        FALSE       FALSE        FALSE       FALSE
[136,]        FALSE       FALSE        FALSE       FALSE
[137,]        FALSE       FALSE        FALSE       FALSE
[138,]        FALSE       FALSE        FALSE       FALSE
[139,]        FALSE       FALSE        FALSE       FALSE
[140,]        FALSE       FALSE        FALSE       FALSE
[141,]        FALSE       FALSE        FALSE       FALSE
[142,]        FALSE       FALSE        FALSE       FALSE
[143,]        FALSE       FALSE        FALSE       FALSE
[144,]        FALSE       FALSE        FALSE       FALSE
[145,]        FALSE       FALSE        FALSE       FALSE
[146,]        FALSE       FALSE        FALSE       FALSE
[147,]        FALSE       FALSE        FALSE       FALSE
[148,]        FALSE       FALSE        FALSE       FALSE
[149,]        FALSE       FALSE        FALSE       FALSE
[150,]        FALSE       FALSE        FALSE       FALSE

This prints out a long series of logical values, telling us whether any given value is missing or not. We can count these, by wrapping is.na() in the sum function, which will count the incidences of TRUE in each column:

apply(my_iris, 2, function(x){
  sum(is.na(x))
})
Sepal.Length  Sepal.Width Petal.Length  Petal.Width 
           0            1            0            0 

We already know that only one of our columns should contain a single NA value (because we put it there earlier!), so we can quite easily verify that our complicated function is doing exactly what we wanted it to! This is a really quick way of getting through things that would take much longer to both construct and run with a for loop. You might never have to use the apply functions in your own code, but they are incredibly useful tools. You might, for example, borrow some code from someone else on github that includes them, or someone might share code with you that has apply functions included, so they’re a useful thing to be aware of.

lapply()

lapply() is essentially apply() for lists. It works in essentially the same way, but for different data structures. You can either feed lapply a dataframe or a list, and it will treat it as such. In order to understand the output of lapply(), we must be aware of how lists work in R.

A quick recap on lists

A list is a way of storing datastructures of different types and lengths in a single object in R, in a way that isn’t possible in a dataframe. Let’s quickly construct one and have a look

my_list
[[1]]
 [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
[38] 38 39 40 41 42 43 44 45 46 47 48 49 50

[[2]]
[1] "red"    "yellow" "green" 

[[3]]
[1] "FALSE"

Here we can see that each of the 3 vectors stored within the list is of a different length (50, 3, and 1). Recall that we access the elements of a list in a slightly different way to vectors or dataframes. In order to access each element of the list, but have it retain it’s list class, we use single square brackets []. If we want to revert back to the contents of the list in its original vector form, we use double square brackets [[]]. For e.g.:

my_list[2]
[[1]]
[1] "red"    "yellow" "green" 
class(my_list[2])
[1] "list"
my_list[[2]]
[1] "red"    "yellow" "green" 
class(my_list[[2]])
[1] "character"

If we want to pull out a single element of a vector, we use a combination of single and double square brackets - we first ask R to return the entire vector element with [[]], and then index it as usual with []. If we wanted to pull out the word “green” which is the 3rd item in the 2nd element of the list, we would use

my_list[[2]][3]
[1] "green"

Lists are complicated, but really common in R (sorry), particularly so when using functions on your data. Lots of the time, a function will output a series of values or information stored within a list, and it’s really useful to be able to extract that information in a way that means you’re always getting what you think you’re getting!

Back to `lapply()

Now that we have our list, we can use lapply() to perform functions on each of the vectors. Let’s start by working out the lengths of each of the elements of the list (note that you don’t have to provide dimension with lapply)

lapply(my_list, length)
[[1]]
[1] 50

[[2]]
[1] 3

[[3]]
[1] 1

This gives us our output as a list. So now, we have a list of lengths of elements of our original list. Phew. It’s important to remember lapply() always returns values in a list. There is a way around this, but we’ll talk about that in a moment.

We don’t have to exclusively use lapply() on lists, we can also use it on dataframes (which lapply() will coerce into lists before it does anything with them). Let’s have a look at what our my_iris data looks like as a list:

as.list(my_iris)
$Sepal.Length
  [1] 5.1 4.9 4.7 4.6 5.0 5.4 4.6 5.0 4.4 4.9 5.4 4.8 4.8 4.3 5.8 5.7 5.4 5.1 5.7 5.1 5.4 5.1 4.6 5.1 4.8 5.0 5.0
 [28] 5.2 5.2 4.7 4.8 5.4 5.2 5.5 4.9 5.0 5.5 4.9 4.4 5.1 5.0 4.5 4.4 5.0 5.1 4.8 5.1 4.6 5.3 5.0 7.0 6.4 6.9 5.5
 [55] 6.5 5.7 6.3 4.9 6.6 5.2 5.0 5.9 6.0 6.1 5.6 6.7 5.6 5.8 6.2 5.6 5.9 6.1 6.3 6.1 6.4 6.6 6.8 6.7 6.0 5.7 5.5
 [82] 5.5 5.8 6.0 5.4 6.0 6.7 6.3 5.6 5.5 5.5 6.1 5.8 5.0 5.6 5.7 5.7 6.2 5.1 5.7 6.3 5.8 7.1 6.3 6.5 7.6 4.9 7.3
[109] 6.7 7.2 6.5 6.4 6.8 5.7 5.8 6.4 6.5 7.7 7.7 6.0 6.9 5.6 7.7 6.3 6.7 7.2 6.2 6.1 6.4 7.2 7.4 7.9 6.4 6.3 6.1
[136] 7.7 6.3 6.4 6.0 6.9 6.7 6.9 5.8 6.8 6.7 6.7 6.3 6.5 6.2 5.9

$Sepal.Width
  [1] 3.5 3.0 3.2 3.1  NA 3.9 3.4 3.4 2.9 3.1 3.7 3.4 3.0 3.0 4.0 4.4 3.9 3.5 3.8 3.8 3.4 3.7 3.6 3.3 3.4 3.0 3.4
 [28] 3.5 3.4 3.2 3.1 3.4 4.1 4.2 3.1 3.2 3.5 3.6 3.0 3.4 3.5 2.3 3.2 3.5 3.8 3.0 3.8 3.2 3.7 3.3 3.2 3.2 3.1 2.3
 [55] 2.8 2.8 3.3 2.4 2.9 2.7 2.0 3.0 2.2 2.9 2.9 3.1 3.0 2.7 2.2 2.5 3.2 2.8 2.5 2.8 2.9 3.0 2.8 3.0 2.9 2.6 2.4
 [82] 2.4 2.7 2.7 3.0 3.4 3.1 2.3 3.0 2.5 2.6 3.0 2.6 2.3 2.7 3.0 2.9 2.9 2.5 2.8 3.3 2.7 3.0 2.9 3.0 3.0 2.5 2.9
[109] 2.5 3.6 3.2 2.7 3.0 2.5 2.8 3.2 3.0 3.8 2.6 2.2 3.2 2.8 2.8 2.7 3.3 3.2 2.8 3.0 2.8 3.0 2.8 3.8 2.8 2.8 2.6
[136] 3.0 3.4 3.1 3.0 3.1 3.1 3.1 2.7 3.2 3.3 3.0 2.5 3.0 3.4 3.0

$Petal.Length
  [1] 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 1.5 1.6 1.4 1.1 1.2 1.5 1.3 1.4 1.7 1.5 1.7 1.5 1.0 1.7 1.9 1.6 1.6
 [28] 1.5 1.4 1.6 1.6 1.5 1.5 1.4 1.5 1.2 1.3 1.4 1.3 1.5 1.3 1.3 1.3 1.6 1.9 1.4 1.6 1.4 1.5 1.4 4.7 4.5 4.9 4.0
 [55] 4.6 4.5 4.7 3.3 4.6 3.9 3.5 4.2 4.0 4.7 3.6 4.4 4.5 4.1 4.5 3.9 4.8 4.0 4.9 4.7 4.3 4.4 4.8 5.0 4.5 3.5 3.8
 [82] 3.7 3.9 5.1 4.5 4.5 4.7 4.4 4.1 4.0 4.4 4.6 4.0 3.3 4.2 4.2 4.2 4.3 3.0 4.1 6.0 5.1 5.9 5.6 5.8 6.6 4.5 6.3
[109] 5.8 6.1 5.1 5.3 5.5 5.0 5.1 5.3 5.5 6.7 6.9 5.0 5.7 4.9 6.7 4.9 5.7 6.0 4.8 4.9 5.6 5.8 6.1 6.4 5.6 5.1 5.6
[136] 6.1 5.6 5.5 4.8 5.4 5.6 5.1 5.1 5.9 5.7 5.2 5.0 5.2 5.4 5.1

$Petal.Width
  [1] 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 0.2 0.2 0.1 0.1 0.2 0.4 0.4 0.3 0.3 0.3 0.2 0.4 0.2 0.5 0.2 0.2 0.4
 [28] 0.2 0.2 0.2 0.2 0.4 0.1 0.2 0.2 0.2 0.2 0.1 0.2 0.2 0.3 0.3 0.2 0.6 0.4 0.3 0.2 0.2 0.2 0.2 1.4 1.5 1.5 1.3
 [55] 1.5 1.3 1.6 1.0 1.3 1.4 1.0 1.5 1.0 1.4 1.3 1.4 1.5 1.0 1.5 1.1 1.8 1.3 1.5 1.2 1.3 1.4 1.4 1.7 1.5 1.0 1.1
 [82] 1.0 1.2 1.6 1.5 1.6 1.5 1.3 1.3 1.3 1.2 1.4 1.2 1.0 1.3 1.2 1.3 1.3 1.1 1.3 2.5 1.9 2.1 1.8 2.2 2.1 1.7 1.8
[109] 1.8 2.5 2.0 1.9 2.1 2.0 2.4 2.3 1.8 2.2 2.3 1.5 2.3 2.0 2.0 1.8 2.1 1.8 1.8 1.8 2.1 1.6 1.9 2.0 2.2 1.5 1.4
[136] 2.3 2.4 1.8 1.8 2.1 2.4 2.3 1.9 2.3 2.5 2.3 1.9 2.0 2.3 1.8

This has separated each of our four columns into their own list element (helpfully with the column names retained!). There are 4 elements of the list, each with 150 observations in. lapply will automatically apply to the columns, which as you can see, are what split off into list elements. Note that we haven’t overwritten my_iris as a list - it’s still a dataframe at the minute

class(my_iris)
[1] "data.frame"

This was just to get an idea of how lapply() might coerce our data into list format, and what that might mean for the function. Let’s try and use lapply to find the means of each column

lapply(my_iris, mean)
$Sepal.Length
[1] 5.843333

$Sepal.Width
[1] NA

$Petal.Length
[1] 3.758

$Petal.Width
[1] 1.199333

Oops - we forgot about our NA problem - we can add arguments in the same way that we did in apply()

lapply(my_iris, mean, na.rm = TRUE)
$Sepal.Length
[1] 5.843333

$Sepal.Width
[1] 3.053691

$Petal.Length
[1] 3.758

$Petal.Width
[1] 1.199333

sapply()

The last of the three apply() functions we’re going to look at today is sapply(). This works almost identically to lapply(), but with the option to simplify the output from a list to a vector. This is arguably the most versatile, as it takes any input, and can return it to you in a variety of formats. Let’s start with feeding sapply() a dataset, and continue with our theme of finding the column means of my_iris:

sapply(my_iris, mean)
Sepal.Length  Sepal.Width Petal.Length  Petal.Width 
    5.843333           NA     3.758000     1.199333 

The function is constructed in an identical way to lapply(), but the output is a vector which might be more useful for downstream analysis. We remove the NA in exactly the same way as before

sapply(my_iris, mean, na.rm = TRUE)
Sepal.Length  Sepal.Width Petal.Length  Petal.Width 
    5.843333     3.053691     3.758000     1.199333 

We can also feed sapply() lists to work on. Let’s give it the list we created earlier and ask it to work out the lengths of the elements

sapply(my_list, length)
[1] 50  3  1

We can also make sapply() return a list to us, and almost revert it back to lapply(), by adding the simplify = FALSE argument. By default, this is set to TRUE in sapply():

sapply(my_list, length, simplify = FALSE)
[[1]]
[1] 50

[[2]]
[1] 3

[[3]]
[1] 1

sapply() in particular, but the apply family in general are a really useful tool in R to allow you to avoid for loops - we can use sapply() to do some really substantial stuff for us in R, way beyond what we’ve covered here. We can also use anonymous functions with sapply() in the same way as we did in apply(). Let’s write one that will take the reciprocal value of each number in a vector from 1:10

sapply(1:10, function(x){
  1/x
})
 [1] 1.0000000 0.5000000 0.3333333 0.2500000 0.2000000 0.1666667 0.1428571 0.1250000 0.1111111 0.1000000

And if we want the output in a list:

sapply(1:10, simplify = FALSE, function(x){
  1/x
})
[[1]]
[1] 1

[[2]]
[1] 0.5

[[3]]
[1] 0.3333333

[[4]]
[1] 0.25

[[5]]
[1] 0.2

[[6]]
[1] 0.1666667

[[7]]
[1] 0.1428571

[[8]]
[1] 0.125

[[9]]
[1] 0.1111111

[[10]]
[1] 0.1

We are iterating across a numeric vector, and applying an anonymous function to it. We’re taking each value from 1:10, calling it x, and then taking the reciprocal of it. We can achieve something similar with character vectors - imagine we wanted to create a series of variables for 24 chromosomes in a genome:

sapply(1:24, function(x){
  paste0("chr",x)
})
 [1] "chr1"  "chr2"  "chr3"  "chr4"  "chr5"  "chr6"  "chr7"  "chr8"  "chr9"  "chr10" "chr11" "chr12" "chr13"
[14] "chr14" "chr15" "chr16" "chr17" "chr18" "chr19" "chr20" "chr21" "chr22" "chr23" "chr24"

paste0 performs the same as paste - but doesn’t include spaces! This will output a series of chromosome names for you, without you having to faff. There is, however, as always, a quicker way of performing this function in each case.

z <- 1:10
1/z
 [1] 1.0000000 0.5000000 0.3333333 0.2500000 0.2000000 0.1666667 0.1428571 0.1250000 0.1111111 0.1000000
1/1:10
 [1] 1.0000000 0.5000000 0.3333333 0.2500000 0.2000000 0.1666667 0.1428571 0.1250000 0.1111111 0.1000000
paste0("chr", 1:24)
 [1] "chr1"  "chr2"  "chr3"  "chr4"  "chr5"  "chr6"  "chr7"  "chr8"  "chr9"  "chr10" "chr11" "chr12" "chr13"
[14] "chr14" "chr15" "chr16" "chr17" "chr18" "chr19" "chr20" "chr21" "chr22" "chr23" "chr24"

It might seem counterintuitive to bother learning apply(), but I promise there will not always be an easier way - I just think it’s a really useful skill to spot when you might be making your own life much harder than you need to!

LS0tCnRpdGxlOiAiTElGRTQxMzggQWR2YW5jZWQgUiB3b3Jrc2hvcCAyIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpIZWxsbyEgV2VsY29tZSB0byB0aGlzLCB0aGUgZmluYWwgb2YgeW91ciBoYXJkLWNvcmUgUiB3b3Jrc2hvcHMgaW4gTElGRTQxMzguCgpMYXN0IHRpbWUsIHdlIGxvb2tlZCBhdDoKCiogY29udHJvbCBmbG93IHdpdGggYGZvcmAgbG9vcHMKKiBgaWYvZWxzZWAgc3RhdGVtZW50cwoqIGNyZWF0aW5nIG91ciBvd24gZnVuY3Rpb25zCiogbGlzdHMKClNvLCB0b2RheSB3ZSBhcmUgZ29pbmcgdG8gZ28gYmFjayB0byB0aGUgYGZvcmAgbG9vcHMsIGFuZCB0YWxrIGFib3V0IGEgc2xpZ2h0bHkgZGlmZmVyZW50IHdheSBvZiBhcHByb2FjaGluZyB0aGUgc2FtZSBwcm9ibGVtLiBgZm9yYCBsb29wcyBhcmUgYSBmdW5kZW1lbnRhbCBwYXJ0IG9mIGNvZGluZyBpbiBhbnkgbGFuZ3VhZ2UsIGFsdGhvdWdoIFIgd2FzIGRlc2lnbmVkIGZvciB0aGVtIHRvIGJlIGF2b2lkZWQsIHdpdGggdGhlIGNyZWF0aW9uIG9mIGEgc3BlY2lhbCBmYW1pbHkgb2YgZnVuY3Rpb25zIHVuaXF1ZSB0byBSLCB0aGUgYGFwcGx5KClgIGZhbWlseS4gVGhlIHRocmVlIGZ1bmN0aW9ucyBmcm9tIHRoaXMgZmFtaWx5IHRoYXQgd2UnbGwgZm9jdXMgb24gaGVyZSBhcmU6CgoqIGBhcHBseSgpYAoqIGBsYXBwbHkoKWAsIGFuZAoqIGBzYXBwbHkoKWAKCiMgV2hhdCBpcyBhcHBseT8KClRoZSBhcHBseSBmYW1pbHkgb2YgZnVuY3Rpb25zIGFsbG93IHlvdSB0byBjcmVhdGUgYSBwaWVjZSBvZiBjb2RlIGFuYWxhZ291cyB0byBhIGBmb3JgIGxvb3AsIGFsbG93aW5nIHlvdSB0byBpdGVyYXRlIG92ZXIgdGhlIGl0ZW1zIGluIGEgZGF0YSBzdHJ1Y3R1cmUsIGFuZCAqYXBwbHkqIGEgZnVuY3Rpb24gb3Igc2V0IG9mIGZ1bmN0aW9ucyB0byBlaXRoZXIgcm93cyBvciBjb2x1bW5zIG9mIHRoZSBkYXRhIHN0cnVjdHVyZSBpbiB0dXJuLiBZb3UgbWlnaHQgaGF2ZSBhIHNlcmllcyBvZiBkYXRhZnJhbWVzIGFuZCB5b3Ugd2FudCB0byBjb3VudCB0aGUgY29sdW1ucyB3aXRoaW4gdGhlbSAtIHlvdSBjb3VsZCBkbyB0aGlzIHdpdGggYSBgZm9yYCBsb29wLCBvciwgeW91IGNvdWxkIHVzZSB0aGUgUiBleGNsdXNpdmUgYGFwcGx5YCBmYW1pbHkgdG8gYWNoaWV2ZSB0aGUgc2FtZSB0aGluZyBpbiBhIG11Y2ggc3BlZWRpZXIgYW5kIG1vcmUgZWZmaWNpZW50IHdheS4gVGhlIGFwcGx5IGZ1bmN0aW9ucyB3ZXJlIGRldmVsb3BlZCB0byBhdm9pZCB0aGUgdXNlIG9mIGxvb3BpbmcgaW4gUiwgYW5kIGFyZSB1c3VhbGx5IG11Y2ggZmFzdGVyIChub3QgYWx3YXlzISkgLSB0aGVyZSBhcmUgc29tZSBjYXNlcyB3aGVyZSBydW5uaW5nIGFuIGFwcGx5IGZ1bmN0aW9uIHdpbGwgYmUgc2xvd2VyIG9yIGNvbnNpZGVyYWJseSBtb3JlIHRyaWNreSB0byBkbywgYnV0IHRoZXkncmUgYSB1c2VmdWwgdGhpbmcgdG8gbGVhcm4sIHdoaWNoIHdpbGwgYWxsb3cgeW91IHRvIGZ1cnRoZXIgYWR2YW5jZSB5b3VyIFIgY29kaW5nIHByb3dlc3MuCgpUaGF0IGJlaW5nIHNhaWQsIHRoZSBhcHBseSBmdW5jdGlvbnMgY2FuIGJlIHF1aXRlIHRyaWNreSB0byB1bmRlcnN0YW5kIGFuZCBnZXQgeW91ciBoZWFkIGFyb3VuZC4gR2VuZXJhbGx5LCB0aGUgaGVscCBmaWxlcyBmb3IgdGhlIGFwcGx5IGZ1bmN0aW9ucyBhcmUgYSBiaXQgcnViYmlzaCwgYW5kIGl0J3MgdHJpY2t5IHRvIGZpbmQgcGxhY2VzIHdoZXJlIHRoZXkgYXJlIHdlbGwgZXhwbGFpbmVkLiBJdCB0b29rIG1lIGEgd2hpbGUgdG8gZnVsbHkgdW5kZXJzdGFuZCBleGFjdGx5IHdoYXQgb3V0Y29tZSBJJ2QgZ2V0IHdoZW4gdXNpbmcgYGFwcGx5KClgLCBhbmQgc29tZXRpbWVzIGl0IHN0aWxsIHRha2VzIG1lIGEgY291cGxlIG9mIGdvZXMgdG8gZ2V0IGl0IGV4YWN0bHkgcmlnaHQuIE91ciBhaW0gaGVyZSBpc24ndCB0byBkZXZlbG9wIHNvbWUgc3VwZXIgY29tcGxleCBmdW5jdGlvbnMsIGJ1dCB0byBkZW15c3RpZnkgdGhlbSBhbmQgZ2V0IHlvdSBmYW1pbGlsYXIgd2l0aCBob3cgdGhleSB3b3JrIGFuZCB3aGVyZSB0aGV5IG1pZ2h0IGJlIHVzZWZ1bC4gVGhleSdyZSBjZXJ0YWlubHkgd29ydGggdGFraW5nIHRoZSB0aW1lIHRvIHVuZGVyc3RhbmQuCgpUaGVyZSBhcmUgZnVuY3Rpb25zIGJleW9uZCBgYXBwbHkoKWAsIGBsYXBwbHkoKWAgYW5kIGBzYXBwbHkoKWAsIGJ1dCB0aGVzZSBhcmUgdGhlIHRocmVlIHRoYXQgd2Ugd2lsbCBmb2N1cyBvbiB0b2RheToKCiogYGFwcGx5KClgIGlzIHVzZWQgb24gbWF0cmljaWVzIGFuZCBkYXRhZnJhbWVzCiogYGxhcHBseSgpYCBpcyB1c2VkIG9uIGxpc3RzIChhbmQgZ2l2ZXMgYSBsaXN0IG91dHB1dCkKKiBgc2FwcGx5KClgIGlzIHNpbWlsYXIgdG8gYGxhcHBseSgpYCBidXQgd2l0aCB0aGUgb3B0aW9uIHRvIHNpbXBsaWZ5IHRoZSBvdXRwdXQgLSBhcmd1YWJseSB0aGUgbW9zdCB2ZXJzYXRpbGU/CgpUaGVzZSBmdW5jdGlvbnMgYXJlIGluY3JlZGlibHkgdXNlZnVsIHRvIGV4cGFuZCB5b3VyIFIgdG9vbGtpdCwgYW5kIG9uY2UgeW91J3ZlIGdvdCB0byBncmlwcyB3aXRoIHVzaW5nIHRoZW0sIHlvdSdsbCBmaW5kIG90aGVyIGNvbXBsZXggUiBmdW5jdGlvbnMgbXVjaCBlYXNpZXIgdG8gdW5kZXJzdGFuZCB0b28hCgojIGFwcGx5KCkKClJpZ2h0IC0gd2UnbGwgc3RhcnQgd2l0aCBgYXBwbHkoKWAuIFdlJ2xsIGhhdmUgYSBxdWljayBnbyBhdCB1c2luZyBhcHBseSwgdGhlbiBkaXNzZWN0IGl0IGEgbGl0dGxlLiBGaXJzdCB1cCwgd2UgbmVlZCBvdXIgaXJpcyBkYXRhIC0gcmVtZW1iZXIgdG8gbWFrZSBzdXJlIHRoZSBpbi1idWlsdCBSIGRhdGFzZXRzIGFyZSBsb2FkZWQgZmlyc3QsIGFuZCB0aGVuIGhhdmUgYSBsb29rIGF0IGlyaXMgd2l0aCB3aXRoIGBoZWFkKClgIGZ1bmN0aW9uOgoKYGBge3J9CmRhdGEoKQpoZWFkKGlyaXMpCmBgYAoKV2UgY2FuIHNlZSB0aGF0IGlyaXMgaGFzIDUgY29sdW1ucyAtIGZvciBub3csIHdlJ3JlIGdvaW5nIHRvIGdldCByaWQgb2YgdGhlIHNwZWNpZXMgY29sdW1uIGFzIGl0J3MgYWN0dWFsbHkgZ29pbmcgdG8gbWFrZSBvdXIgbGlmZSBhIGxpdHRsZSBtb3JlIGRpZmZpY3VsdCB0aGFuIHdlJ2QgbGlrZSwgc28gd2UnbGwgY3JlYXRlIGEgbmV3IG9iamVjdCB3aXRoIHRoZSBpcmlzIGRhdGFmcmFtZSwgbWludXMgdGhlIDV0aCBjb2x1bW46CgpgYGB7cn0KbXlfaXJpcyA8LSBpcmlzWywtNV0KaGVhZChteV9pcmlzKQpgYGAKClJ1biB0aGUgYGhlYWQoKWAgZnVuY3Rpb24gb24gdGhlIG5ldyBkZiB0byBjaGVjayB0aGF0IHlvdXIgY29kZSBoYXMgcmVtb3ZlZCB0aGUgY29ycmVjdCBjb2x1bW4gLSB5b3Ugc2hvdWxkIGJlIGxlZnQgd2l0aCA0IChwZXRhbCBhbmQgc2VwYWwgd2lkdGggYW5kIGxlbmd0aCBtZWFzdXJlbWVudHMpLiBBYm92ZSB3ZSBjYW4gc2VlIHRoYXQgd2UgaGF2ZSBjb3JyZWN0bHkgcmVtb3ZlZCB0aGUgc3BlY2llcyBjb2x1bW4sIHNvIHdlIGNhbiBjYXJyeSBvbiEgVGhlIHJlYXNvbiB3ZSByZW1vdmVkIHRoZSBzcGVjaWVzIHZlY3RvciB3YXMgdG8gYWxsb3cgdXMgdG8gaGF2ZSBhIG5pY2UgY2xlYW4gZGF0YXNldCB3aXRoIG9ubHkgbnVtZXJpYyB2YWx1ZXMgaW5zaWRlIG9mIGl0LCBzbyB3ZSBjYW4gbW9yZSBlYXNpbHkgZGVtb25zdHJhdGUgYGFwcGx5KClgLgoKTm93IHdlIGhhdmUgYSBkYXRhc2V0IHdoZXJlIGVhY2ggY29sdW1uIGlzIGEgc2V0IG9mIHZhbHVlcyBwZXJ0YWluaW5nIHRvIDE1MCBvYnNlcnZhdGlvbnMgb2Ygc29tZXRoaW5nLiBXaGF0IGlmIHdlIHdhbnQgdG8gZmluZCB0aGUgbWVhbnMgb2YgZWFjaCBvZiB0aGVzZSBjb2x1bW5zPyBUaGVyZSBhcmUgc2V2ZXJhbCB3YXlzIHdlIGNhbiBkbyB0aGlzIHdpdGhvdXQgdXNpbmcgYGFwcGx5KClgLCBzdWNoIGFzOgoKYGBge3J9Cm1lYW4obXlfaXJpc1ssMV0pCm1lYW4obXlfaXJpc1ssMl0pCm1lYW4obXlfaXJpc1ssM10pCm1lYW4obXlfaXJpc1ssNF0pCmBgYApUaGlzIGlzIHRoZW9yZXRpY2FsbHkgYWNoaWV2YWJsZSB3aXRoIG9ubHkgNCBjb2x1bW5zLCBidXQgaXMgY2x1bmt5IGFuZCByZXBldGl0aXZlLiBXZSB3YW50IHRvIHdyaXRlIGEgc2luZ2xlIGNvbW1hbmQgdGhhdCB3aWxsIGl0ZXJhdGUgb3ZlciB0aGUgZW50aXJlIGRhdGFzZXQgZm9yIHVzLiBXZSBjb3VsZCBhbHNvIGFjaGlldmUgaXQgd2l0aCBhIGBmb3JgIGxvb3A6CgpgYGB7cn0KZm9yICh4IGluIDE6bmNvbChteV9pcmlzKSl7CiAgcHJpbnQobWVhbihteV9pcmlzWyx4XSkpCn0KYGBgClRoaXMgbG9vcCBoYXMgdGFrZW4gZXZlcnkgdmFsdWUgYmV0d2VlbiAxIGFuZCB0aGUgbnVtYmVyIG9mIGNvbHVtbnMgaW4gdGhlIGlyaXMgZGF0YXNldCwgZ2l2ZXMgeCB0aGF0IHZhbHVlLCBhbmQgd29ya3Mgb3V0IHRoZSBtZWFuIGFjY29yZGluZyB0byB0aGUgY29sdW1uIGluZGV4LiBUaGlzIGlzbid0IHRoZSBtb3N0IGVmZmljaWVudCB3YXkgb2YgZG9pbmcgdGhpbmdzLCBhbmQgY2FuIGJlIGEgbGl0dGxlIGNvbXBsZXggdG8gY29uc3RydWN0LiBJdCB3b3VsZCBhbHNvIHRha2UgYWdlcyBpZiB3ZSB3ZXJlIHVzaW5nIGEgYmlnIGRhdGFzZXQuCgpBcmd1YWJseSwgYSBtdWNoIHF1aWNrZXIgYW5kIG1vcmUgZWZmaWNpZW50IHdheSBvZiBhY2hpZXZpbmcgdGhpcyBpcyBieSB1c2luZyBgYXBwbHkoKWAuIFRoaXMgZnVuY3Rpb24gaXMgc3RydWN0dXJlZCB3aXRoIDMgYXJndW1lbnRzLCB5b3UgdGVsbCBpdCB3aGF0IGRhdGEgeW91IHdvdWxkIGxpa2UgaXQgdG8gd29yayB3aXRoLCBhbmQgdGhlbiB3aGF0IGRpbWVuc2lvbiBvZiB0aGUgZGF0YSAoZWl0aGVyIHJvdyBvciBjb2x1bW4gaW4gdGhpcyBjYXNlKSwgYW5kIHRoZW4gd2UgZmVlZCBhcHBseSBhIGZ1bmN0aW9uIGZvciBpdCB0byBwZXJmb3JtIG9uIGVhY2ggb2YgdGhlIGRpbWVuc2lvbnMgb2YgdGhlIGRhdGFzZXQgaW4gdHVybi4gTGV0J3MgY29uc3RydWN0IG91ciBmaXJzdCBleGFtcGxlLCBhbmQgdGhlbiB3ZSBjYW4gZGlzc2VjdCBpdCBhIGxpdHRsZSBtb3JlIC0gd2Ugd2lsbCB1c2UgdGhlIGBhcHBseSgpYCBmdW5jdGlvbiB0byBhY2hpZXZlIHdoYXQgd2UganVzdCBkaWQgdGhlIGhhcmQgd2F5OgoKYGBge3J9CmFwcGx5KG15X2lyaXMsIDIsIG1lYW4pCmBgYAoKWW91IGNhbiBzZWUgdGhhdCBhcHBseSBhbHNvIGdpdmVzIHVzIGEgbmljZXIgb3V0cHV0ISBCdXQsIGJhY2sgdG8gdGhlIGFuYXRvbXkgb2YgYXBwbHkuIFRoZXJlIGFyZSB0aHJlZSBhcmd1bWVudHM6CgoqIFRoZSBkYXRhZnJhbWUgb3IgbWF0cml4IHRoYXQgeW91IHdhbnQgdG8gcGVyZm9ybSBhIGZ1bmN0aW9uIG9uLiBOb3RlIHRoYXQgYXBwbHkgd2lsbCBjby1lcmNlIHlvdXIgZGF0YSBpbnRvIGEgbWF0cml4ICh3aGljaCB3ZSBrbm93IGNhbiBvbmx5IHN0b3JlIG9uZSBkYXRhIGNsYXNzLCBoZW5jZSByZW1vdmluZyB0aGUgc3BlY2llcyB2ZWN0b3IhKS4KKiBUaGUgZGltZW5zaW9uIHRvIHdoaWNoIHlvdSB3YW50IHRvIGFwcGx5IHRoZSBmdW5jdGlvbi4gUmVtZW1iZXIgdGhhdCBpbiBSLCB3ZSBhbHdheXMgcmVmZXIgdG8gcm93cyBhbmQgdGhlbiBjb2x1bW5zLCBhcyBzdWNoLCByb3cgaGFzIGEgZGltZW5zaW9uIHJlZmVyZW5jZSBvZiAxLCBhbmQgY29sdW1uIG9mIDIuIElmIHdlIHdhbnRlZCB0byBwcm9kdWNlIHRoZSBtZWFuIG9mIHRoZSByb3dzIGluIHR1cm4sIHdlIGNvdWxkIHN3YXAgdGhlIDIgdG8gYSAxIGFuZCBydW46CgpgYGB7cn0KYXBwbHkobXlfaXJpcywgMSwgbWVhbikKYGBgClRoaXMgaXMgc29tZXdoYXQgbWVhbmluZ2xlc3MgYmlvbG9naWNhbGx5LCBidXQgaWxsdXN0cmF0ZXMgdGhlIHBvaW50LiBBbnl3YXksIG91ciB0aGlyZCBhcmd1bWVudC4uLgoKKiBUaGUgZnVuY3Rpb24geW91IHdpc2ggdG8gYXBwbHkuIEhlcmUsIHdlJ3ZlIHVzZWQgYG1lYW4oKWAuIFdoZW4geW91IHBhc3MgYSBmdW5jdGlvbiB0byBhcHBseSwgUiB3aWxsIHNlYXJjaCBpdCdzIGVudmlyb25tZW50IGZvciB0aGUgZnVuY3Rpb24geW91J3JlIGFmdGVyIC0geW91IGNhbiB1c2UgY3VzdG9tIGZ1bmN0aW9ucyBoZXJlIHRvbyEKClNvLCB1c2luZyBhIHNpbmdsZSBsaW5lIG9mIGNvZGUsIHdlIGhhdmUgbWFuYWdlZCB0byBhY2hpZXZlIHdoYXQgdG9vayB1cyBtdWNoIG1vcmUgZWZmb3J0IHRvIHBlcmZvcm0gbWFudWFsbHkgb3Igd2l0aCBhIGxvb3AuIFRoYXQgYmVpbmcgc2FpZCwgdGhlcmUgaXMgYSBiYXNlUiBmdW5jdGlvbiB3aGljaCB3aWxsIHdvcmsgb3V0IHRoZSBjb2x1bW4gbWVhbnMgb2YgYSBkYXRhc2V0IHdpdGhvdXQgaGF2aW5nIHRvIHVzZSBhcHBseSAtIGBjb2xNZWFucygpYC4gCgpgYGB7cn0KY29sTWVhbnMobXlfaXJpcykKYGBgCgpUaGUgcG9pbnQgb2YgdGVsbGluZyB5b3UgdGhpcyBpc24ndCB0byBpbnZhbGlkYXRlIHRoZSB1c2Ugb2YgYXBwbHkgb3IgYW55IG9mIHRoZSBvdGhlciBtZXRob2RzLCBidXQgdG8gZ2V0IHlvdSB0byB0aGluayBhYm91dCB5b3VyIHVzZSBvZiBjb2RlLiBPZnRlbiwgcGFydGljdWxhcmx5IHdpdGggdmVjdG9yaXNhdGlvbiwgdGhlcmUgaXMgYSBtdWNoIHNpbXBsZXIgYW5kIG1vcmUgc3RyYWlnaHRmb3J3YXJkIHdheSBvZiBwZXJmb3JtaW5nIHF1aXRlIGNvbXBsZXggY29tbWFuZHMgaW4gUiAtIGRvbid0IGZvcmdldCBpdCB3YXMgbGl0ZXJhbGx5IGRlc2lnbmVkIHRvIGJlIHNpbXBsZSEgTm90ZSB0aGF0IHNvbWUgb2YgdGhlIGJlc3QgY29kZXJzIGFyZSBsYXp5LCB3ZSdyZSBhbHdheXMgbG9va2luZyBmb3IgcXVpY2tlciBhbmQgZWFzaWVyIHdheXMgb2YgZG9pbmcgdGhpbmdzIHRvIG1ha2Ugb3VyIG93biBsaXZlcyBlYXN5LiBJdCBpcyBob3dldmVyIGltcG9ydGFudCB0byBzdHJpa2UgYSBiYWxhbmNlIGJldHdlZW4gZmluZGluZyBhIHF1aWNrZXIgd2F5LCBhbmQgdGhlIHRpbWUgdGhhdCB5b3UgY2FuIHNwZW5kIGZpbmRpbmcgdGhhdCBxdWlja2VyIHdheSEhIERvbid0IGZvcmdldCB5b3VyIFIgcGhpbG9zb3BoaWVzLCBhbmQgbXkgZmF2b3VyaXRlIHRoaW5nIHRvIHNheSB3aGVuIHRlYWNoaW5nIFIgLSAqKklmIGl0IHdvcmtzLCBpdCB3b3JrcyEqKgoKIyMgR29pbmcgZnVydGhlciB3aXRoIGBhcHBseQoKV2UndmUgY29uc3RydWN0ZWQgYW4gYXBwbHkgZnVuY3Rpb24gaW4gaXRzIG1vc3QgYmFzaWMgZm9ybSwgYnV0IHdlIGNhbiBnbyBtdWNoIGZ1cnRoZXIgd2l0aCB0aGVtLiBXaGF0IGlmLCBmb3IgZXhhbXBsZSwgdGhlcmUgd2FzIGEgcm9ndWUgYE5BYCBpbiBvdXIgZGF0YXNldD8gV2UndmUgc2VlbiBpbiB0aGUgcGFzdCB0aGF0IGxvdHMgb2YgZnVuY3Rpb25zIGNhbid0IGhhbmRsZSB0aGlzIHZlcnkgd2VsbCEgTGV0J3MgcG9wIG9uZSBpbnRvIG91ciBgbXlfaXJpc2AgZGF0YSBhbmQgcnVuIHRoZSBhcHBseSBmdW5jdGlvbiBhZ2FpbjoKCmBgYHtyfQpteV9pcmlzWzUsMl0gPC0gTkEKYXBwbHkobXlfaXJpcywgMiwgbWVhbikKYGBgCgpKdXN0IGFzIHN1c3BlY3RlZCwgd2UndmUgZ290IGFuIE5BIHJlc3VsdCBmb3Igb3VyIGNvbHVtbiB3aXRoIHRoZSBOQSB2YWx1ZS4gV2UgY2FuIGFkZCBmdW5jdGlvbiBhcmd1bWVudHMgaW50byBhbiBhcHBseSBmdW5jdGlvbiBzaW1wbHkgYnkgcG9wcGluZyB0aGVtIG9uIHRoZSBlbmQgc2VxdWVudGlhbGx5LCBzZXBhcmF0ZWQgYnkgY29tbWFzLiBMZXQncyB0cnkgYW5kIGFkZCB0aGUgYG5hLnJtID0gVFJVRWAgYXJndW1lbnQgdG8gb3VyIGZ1bmN0aW9uIHRvIGZpeCB0aGUgaXNzdWUKCmBgYHtyfQphcHBseShteV9pcmlzLCAyLCBtZWFuLCBuYS5ybSA9IFRSVUUpCgpgYGAKClBpZWNlIG9mIGNha2UuIEFwcGx5IGlzIHN1cGVyIGZsZXhpYmxlLCBsZXQncyBjb25zdHJ1Y3QgYW5vdGhlciBmdW5jdGlvbiBqdXN0IHRvIHJlYWxseSBoYW1tZXIgaG9tZSB0aGUgcG9pbnQgLSB3ZSdsbCB0cnkgd2l0aCBgc3VtKClgIHRoaXMgdGltZToKCmBgYHtyfQphcHBseShteV9pcmlzLCAyLCBzdW0sIG5hLnJtID0gVFJVRSkKYGBgCgpgYXBwbHkoKWAgaXMgc3VwZXIgcXVpY2ssIGFuZCB2ZXJ5IHVzZWZ1bC4gV2hpbHN0IGF0IGZpcnN0IGl0IHRha2VzIHNvbWUgZ2V0dGluZyB1c2VkIHRvLCBvbmNlIHlvdSd2ZSBjb25zdHJ1Y3RlZCBhIGNvdXBsZSwgdGhleSB3aWxsIGJlY29tZSBzZWNvbmQgbmF0dXJlLgoKV2UgY2FuIGFsc28gd3JpdGUgb3VyIG93biBmdW5jdGlvbnMsIGFuZCB1c2UgdGhlbSB3aXRoIGBhcHBseSgpYC4gTGV0J3MgY3JlYXRlIGEgZnVuY3Rpb24gdG8gc3F1YXJlIGEgc2VyaWVzIG9mIHZhbHVlcwoKYGBge3J9CnNxdWFyZSA8LSBmdW5jdGlvbih4KXsKICB5IDwtIHheMgogIHJldHVybih5KQp9CmBgYAoKQXMgYSB2ZXJ5IHF1aWNrIHJlbWluZGVyLCB0aGlzIGJpdCBvZiBjb2RlIHRlbGxzIFIgdGhhdCB3ZSB3YW50IHRvIGNyZWF0ZSBhIGZ1bmN0aW9uIGNhbGxlZCBgc3F1YXJlYCB3aXRoIGEgc2luZ2xlIGFyZ3VtZW50IGB4YC4gUiB3aWxsIGFzc2lnbiB3aGF0ZXZlciB2YWx1ZSB3ZSBnaXZlIHRoZSBgc3F1YXJlYCBmdW5jdGlvbiB0byBgeGAsIGFuZCBwZXJmb3JtIHRoZSBjb2RlIGluIHRoZSBib2R5IG9mIHRoZSBmdW5jdGlvbiAodGhlIHN0dWZmIGVuY2xvc2VkIGluIHRoZSBge31gKS4gTGV0J3MgdGVzdCBgc3F1YXJlYCB0byBtYWtlIHN1cmUgaXQgZG9lcyB3aGF0IHdlJ3JlIGV4cGVjdGluZyBiZWZvcmUgd2UgdXNlIGl0IHdpdGggYGFwcGx5KClgCgpgYGB7cn0Kc3F1YXJlKDEwKQpgYGAKCldvbmRlcmZ1bCwgb3VyIGZ1bmN0aW9uIGlzIHBlcmZvcm1pbmcgYXMgd2Ugd291bGQgZXhwZWN0LiBOb3csIHdlIGNhbiBwb3AgaXQgaW50byBhcHBseSBhbmQgc3F1YXJlIGVhY2ggb2YgdGhlIHZhbHVlcyBpbiB0aGUgZGF0YXNldC4KCmBgYHtyfQphcHBseShteV9pcmlzLCAyLCBzcXVhcmUpCmBgYApSIGhhcyByZXR1cm5lZCB0aGUgd2hvbGUgZGF0YXNldCB0byB1cyAoYmVjYXVzZSB3ZSBnYXZlIGl0IGEgZnVuY3Rpb24gdG8gcGVyZm9ybSBvbiBldmVyeSB2YWx1ZSwgcmF0aGVyIHRoYW4gYSBzZXJpZXMgb2YgdmFsdWVzIGxpa2UgYHN1bWAgb3IgYG1lYW5gKS4gRWFjaCB2YWx1ZSB3aXRoaW4gdGhlIGRhdGFzZXQgaXMgc3F1YXJlZCEKClRoaXMgaXMgYSBzaW1wbGUgZS5nLiwgYnV0IGl0IGlzIGFsd2F5cyB3b3J0aCBrbm93aW5nIHRoYXQgdGhlcmUgYXJlIGFsdGVybmF0aXZlcy4gVGhlcmUgYXJlIGxvYWRzIG9mIHdheXMgdG8gZG8gZXZlcnl0aGluZyBpbiBSLCBhbmQgYmVpbmcgYXdhcmUgb2YgdGhlbSBhbGwgd2lsbCBoZWxwIHlvdSB0byBzb2x2ZSBlcnJvcnMgYW5kIHRoaW5rIGFib3V0IHRoZSB3YXkgdGhhdCB5b3VyIGZ1bmN0aW9ucyBhcmUgcGVyZm9ybWluZyBpbiBvcmRlciB0byBnZXQgdGhlIGJlc3QgcG9zc2libGUgcmVzdWx0cy4gRm9yIGV4YW1wbGUsIGhlcmUsIHdlIGNvdWxkIGFsc28gcnVuCgpgYGB7cn0KbXlfaXJpc14yCmBgYApUaGUgbGVzc29uIGhlcmUgaXMgdGhhdCB5b3Ugc2hvdWxkIGJlIGxhenkhIExvb2sgZm9yIHRoZSBxdWlja2VzdCBhbmQgZWFzaWVzdCBzb2x1dGlvbiB0byBhbnkgZ2l2ZW4gdGFzayEgSGF2aW5nIHRoZSBrbm93bGVkZ2Ugb2YgYm90aCBhbGwgb2YgdGhlIGNvZGUgYWx0ZXJuYXRpdmVzIGFuZCBhbiB1bmRlcnN0YW5kaW5nIG9mIHRoZSB3YXkgdGhhdCBSIHByb2Nlc3NlcyBhbmQgYmVoYXZlcyB3aXRoIHZhcmlvdXMgZGF0YSBzdHJ1Y3R1cmVzIHdpbGwgZ2l2ZSB5b3UgYSBncmVhdCBzdGFydGluZyBwb2ludCAtIHlvdSB3aWxsIGJlIGFibGUgdG8gd3JpdGUgcmVhbGx5IHNpbXBsZSBhbmQgZWZmaWNpZW50IGNvZGUsIGFuZCBoYXZlIGEgdmFyaWV0eSBvZiB0cmlja3MgdXAgeW91ciBzbGVldmUgZm9yIHdoZW4geW91IGNhbid0IHF1aXRlIGdldCB0aGUgZmlyc3QgYXR0ZW1wdCB0byB3b3JrLiBPZiBjb3Vyc2UsIGhlcmUsIHRoZXJlIGFyZSBzaW1wbGUgYWx0ZXJuYXRpdmVzIGJlY2F1c2Ugb2YgdGhlIG5hdHVyZSBvZiB0aGUgZXhhbXBsZXMgSSdtIGdpdmluZyB5b3UsIGJ1dCB5b3UgbWlnaHQgaGF2ZSB0byB0aGluayBtb3JlIGNhcmVmdWxseSBhYm91dCB0aGlzIHdoZW4gaXQgY29tZXMgdG8gd3JpdGluZyB5b3VyIG93biBjb2RlIHRvIHBlcmZvcm0gbXVjaCBtb3JlIGNvbXBsaWNhdGVkIHRhc2tzIGZvciB5b3UhCgpOb3cgLSB3ZSd2ZSBjb3ZlcmVkIHRoZSBiYXNpY3Mgb2YgaG93IHRoZSBhcHBseSBmdW5jdGlvbiB3b3JrcywgYW5kIHRhbGtlZCBhYm91dCB3aGF0IHNvcnRzIG9mIGZ1bmN0aW9ucyB5b3UgY2FuIHVzZSBpdCBmb3IuIFRoZSBmaW5hbCB0aGluZyB0byBzYXkgYWJvdXQgYGFwcGx5KClgIHNwZWNpZmljYWxseSAoYWx0aG91Z2ggdGhpcyBhcHBsaWVzIHRvIGFsbCBvZiB0aGUgYXBwbHkgZmFtaWx5KSBpcyB3aXRoIHJlZ2FyZHMgdG8gYW5vbnltb3VzIGZ1bmN0aW9ucy4gVGhlcmUgbWF5IGJlIGEgY2FzZSB3aGVyZSB5b3Ugd2FudCB0byB1c2UgYSBjdXN0b20gZnVuY3Rpb24sIGJ1dCB3aXRob3V0IGV4cGxpY2l0bHkgZGVmaW5pbmcgaXQgd2l0aGluIHlvdXIgdGV4dC4gVGhlIGFwcGx5IGZhbWlseSBhbGxvdyB5b3UgdG8gc3BlY2lmaXkgYSBjdXN0b20gZnVuY3Rpb24gdG8gdXNlIHdpdGhpbiBhbiBgYXBwbHkoKWAgZnVuY3Rpb24sIHdpdGhvdXQgaGF2aW5nIHRvIGV4cGxpY2l0bHkgZGVmaW5lIGl0IGluIHlvdXIgY29kZS4gV2UgY2FuIHNsaWdodGx5IGFsdGVyIHRoZSB3YXkgdGhhdCBgYXBwbHkoKWAgaXMgd3JpdHRlbiBpbiBvcmRlciB0byBnZXQgaXQgdG8gcGVyZm9ybSBzb21ldGhpbmcgd2l0aGluIGEgY29kZSBibG9jayAocmVtZW1iZXIgdGhlIGB7fWApLiAKCkxldCdzIHRyeSBhbmQgc3F1YXJlIHRoZSB2YWx1ZXMgb2YgYG15X2lyaXNgIGFnYWluLCB0aGlzIHRpbWUsIHdpdGhvdXQgZXhwbGljaXRseSBkZWNsYXJpbmcgYSBmdW5jdGlvbiB0byBkbyBzbzoKCmBgYHtyfQphcHBseShteV9pcmlzLCAyLCBmdW5jdGlvbih4KXsKICB4XjIKfSkKYGBgCgpXb25kZXJmdWwhIExldCdzIGhhdmUgYSBsb29rIGF0IHRoZSBzeW50YXg6CgoqIGBhcHBseShteV9pcmlzLCAyLCAuLi4pYCAtIHRoZSBiYXNpYyBmdW5jdGlvbiBpcyBjb25zdHJ1Y3RlZCBpbiB0aGUgc2FtZSB3YXkgYXMgbm9ybWFsCiogYGFwcGx5KG15X2lyaXMsIDIsIGZ1bmN0aW9uKHgpeyBib2R5IG9mIGZ1bmN0aW9uIH0pYCAtIHdlIHVzZSB0aGUgYGZ1bmN0aW9uKHgpYCBhcmd1bWVudCBpbiBhIHNpbWlsYXIgd2F5IHRvIHVzdWFsLCBidXQgd2UgZG9uJ3QgY2xvc2UgdGhlIGBhcHBseSgpYCBwYXJlbnRoZXNlcyB1bnRpbCBhZnRlciB3ZSd2ZSBjb25zdHJ1Y3RlZCB0aGUgYm9keSBvZiB0aGUgZnVuY3Rpb24KClRoaXMgY2FuIGJlIHF1aXRlIHRyaWNreSB0byBncmFzcCBmdWxseSB0aGUgZmlyc3QgZmV3IHRpbWVzIHlvdSBkbyBpdCwgYnV0IGVzc2VudGlhbGx5LCB5b3UncmUgdGVsbGluZyBSIHRvIGxvb2sgYXQgdGhlIG15X2lyaXMgZGF0YSwgdGFrZSBlYWNoIGNvbHVtbiwgY2FsbCBpdCB4LCB0aGVuIHBlcmZvcm0gYSBiaXQgb2YgY29kZSBvbiBpdC4KCldlIGFscmVhZHkga25vdyB0aGF0IHRoaXMgZXhhbXBsZSBpcyBwZXJoYXBzIHNsaWdodGx5IHJlZHVuZGFudCBiZWNhdXNlIHdlIGNhbiBqdXN0IHJhaXNlIHRoZSBlbnRpcmUgZGF0YWZyYW1lIHRvIHRoZSBwb3dlciAyLCBidXQgYW5vbnltb3VzIGZ1bmN0aW9ucyBtaWdodCBiZSB1c2VmdWwgZWxzZXdoZXJlLiBMZXQncyB3cml0ZSBhIG1vcmUgY29tcGxleCBhcHBseSB3aXRoIGFuIGFub255bW91cyBmdW5jdGlvbiB0byBjb3VudCB0aGUgbnVtYmVyIG9mIGBOQWBzIHRoYXQgd2UgaGF2ZSBpbiBlYWNoIGNvbHVtbiBvZiBvdXIgZGF0YS4gV2UnbGwgc3RhcnQsIGJ5IGdldHRpbmcgUiB0byBpZGVudGlmeSB3aGVyZSB0aGUgYE5BYHMgYXJlIGJ5IHdyaXRpbmcgYW4gYW5vbnltb3VzIGZ1bmN0aW9uIHdpdGggYGlzLm5hKClgIGluc2lkZSBhcHBseToKCmBgYHtyfQphcHBseShteV9pcmlzLCAyLCBmdW5jdGlvbih4KXsKICBpcy5uYSh4KQp9KQpgYGAKClRoaXMgcHJpbnRzIG91dCBhIGxvbmcgc2VyaWVzIG9mIGxvZ2ljYWwgdmFsdWVzLCB0ZWxsaW5nIHVzIHdoZXRoZXIgYW55IGdpdmVuIHZhbHVlIGlzIG1pc3Npbmcgb3Igbm90LiBXZSBjYW4gY291bnQgdGhlc2UsIGJ5IHdyYXBwaW5nIGBpcy5uYSgpYCBpbiB0aGUgYHN1bWAgZnVuY3Rpb24sIHdoaWNoIHdpbGwgY291bnQgdGhlIGluY2lkZW5jZXMgb2YgYFRSVUVgIGluIGVhY2ggY29sdW1uOgoKYGBge3J9CmFwcGx5KG15X2lyaXMsIDIsIGZ1bmN0aW9uKHgpewogIHN1bShpcy5uYSh4KSkKfSkKYGBgCgpXZSBhbHJlYWR5IGtub3cgdGhhdCBvbmx5IG9uZSBvZiBvdXIgY29sdW1ucyBzaG91bGQgY29udGFpbiBhIHNpbmdsZSBgTkFgIHZhbHVlIChiZWNhdXNlIHdlIHB1dCBpdCB0aGVyZSBlYXJsaWVyISksIHNvIHdlIGNhbiBxdWl0ZSBlYXNpbHkgdmVyaWZ5IHRoYXQgb3VyIGNvbXBsaWNhdGVkIGZ1bmN0aW9uIGlzIGRvaW5nIGV4YWN0bHkgd2hhdCB3ZSB3YW50ZWQgaXQgdG8hIFRoaXMgaXMgYSByZWFsbHkgcXVpY2sgd2F5IG9mIGdldHRpbmcgdGhyb3VnaCB0aGluZ3MgdGhhdCB3b3VsZCB0YWtlIG11Y2ggbG9uZ2VyIHRvIGJvdGggY29uc3RydWN0IGFuZCBydW4gd2l0aCBhIGBmb3JgIGxvb3AuIFlvdSBtaWdodCBuZXZlciBoYXZlIHRvIHVzZSB0aGUgYXBwbHkgZnVuY3Rpb25zIGluIHlvdXIgb3duIGNvZGUsIGJ1dCB0aGV5IGFyZSBpbmNyZWRpYmx5IHVzZWZ1bCB0b29scy4gWW91IG1pZ2h0LCBmb3IgZXhhbXBsZSwgYm9ycm93IHNvbWUgY29kZSBmcm9tIHNvbWVvbmUgZWxzZSBvbiBnaXRodWIgdGhhdCBpbmNsdWRlcyB0aGVtLCBvciBzb21lb25lIG1pZ2h0IHNoYXJlIGNvZGUgd2l0aCB5b3UgdGhhdCBoYXMgYXBwbHkgZnVuY3Rpb25zIGluY2x1ZGVkLCBzbyB0aGV5J3JlIGEgdXNlZnVsIHRoaW5nIHRvIGJlIGF3YXJlIG9mLiAKCiMgYGxhcHBseSgpYAoKYGxhcHBseSgpYCBpcyBlc3NlbnRpYWxseSBgYXBwbHkoKWAgZm9yIGxpc3RzLiBJdCB3b3JrcyBpbiBlc3NlbnRpYWxseSB0aGUgc2FtZSB3YXksIGJ1dCBmb3IgZGlmZmVyZW50IGRhdGEgc3RydWN0dXJlcy4gIFlvdSBjYW4gZWl0aGVyIGZlZWQgbGFwcGx5IGEgZGF0YWZyYW1lIG9yIGEgbGlzdCwgYW5kIGl0IHdpbGwgdHJlYXQgaXQgYXMgc3VjaC4gSW4gb3JkZXIgdG8gdW5kZXJzdGFuZCB0aGUgb3V0cHV0IG9mIGBsYXBwbHkoKWAsIHdlIG11c3QgYmUgYXdhcmUgb2YgaG93IGxpc3RzIHdvcmsgaW4gUi4KCiMjIyBBIHF1aWNrIHJlY2FwIG9uIGxpc3RzCgpBIGxpc3QgaXMgYSB3YXkgb2Ygc3RvcmluZyBkYXRhc3RydWN0dXJlcyBvZiBkaWZmZXJlbnQgdHlwZXMgYW5kIGxlbmd0aHMgaW4gYSBzaW5nbGUgb2JqZWN0IGluIFIsIGluIGEgd2F5IHRoYXQgaXNuJ3QgcG9zc2libGUgaW4gYSBkYXRhZnJhbWUuIExldCdzIHF1aWNrbHkgY29uc3RydWN0IG9uZSBhbmQgaGF2ZSBhIGxvb2sKCmBgYHtyfQphIDwtIDE6NTAKYiA8LSBjKCJyZWQiLCAieWVsbG93IiwgImdyZWVuIikKYyA8LSAiRkFMU0UiCgpteV9saXN0IDwtIGxpc3QoYSwgYiwgYykKbXlfbGlzdApgYGAKSGVyZSB3ZSBjYW4gc2VlIHRoYXQgZWFjaCBvZiB0aGUgMyB2ZWN0b3JzIHN0b3JlZCB3aXRoaW4gdGhlIGxpc3QgaXMgb2YgYSBkaWZmZXJlbnQgbGVuZ3RoICg1MCwgMywgYW5kIDEpLgpSZWNhbGwgdGhhdCB3ZSBhY2Nlc3MgdGhlIGVsZW1lbnRzIG9mIGEgbGlzdCBpbiBhIHNsaWdodGx5IGRpZmZlcmVudCB3YXkgdG8gdmVjdG9ycyBvciBkYXRhZnJhbWVzLiBJbiBvcmRlciB0byBhY2Nlc3MgZWFjaCBlbGVtZW50IG9mIHRoZSBsaXN0LCBidXQgaGF2ZSBpdCByZXRhaW4gaXQncyBsaXN0IGNsYXNzLCB3ZSB1c2Ugc2luZ2xlIHNxdWFyZSBicmFja2V0cyBgW11gLiBJZiB3ZSB3YW50IHRvIHJldmVydCBiYWNrIHRvIHRoZSBjb250ZW50cyBvZiB0aGUgbGlzdCBpbiBpdHMgb3JpZ2luYWwgdmVjdG9yIGZvcm0sIHdlIHVzZSBkb3VibGUgc3F1YXJlIGJyYWNrZXRzIGBbW11dYC4gRm9yIGUuZy46CgpgYGB7cn0KbXlfbGlzdFsyXQpjbGFzcyhteV9saXN0WzJdKQoKbXlfbGlzdFtbMl1dCmNsYXNzKG15X2xpc3RbWzJdXSkKYGBgCklmIHdlIHdhbnQgdG8gcHVsbCBvdXQgYSBzaW5nbGUgZWxlbWVudCBvZiBhIHZlY3Rvciwgd2UgdXNlIGEgY29tYmluYXRpb24gb2Ygc2luZ2xlIGFuZCBkb3VibGUgc3F1YXJlIGJyYWNrZXRzIC0gd2UgZmlyc3QgYXNrIFIgdG8gcmV0dXJuIHRoZSBlbnRpcmUgdmVjdG9yIGVsZW1lbnQgd2l0aCBgW1tdXWAsIGFuZCB0aGVuIGluZGV4IGl0IGFzIHVzdWFsIHdpdGggYFtdYC4gSWYgd2Ugd2FudGVkIHRvIHB1bGwgb3V0IHRoZSB3b3JkICJncmVlbiIgd2hpY2ggaXMgdGhlIDNyZCBpdGVtIGluIHRoZSAybmQgZWxlbWVudCBvZiB0aGUgbGlzdCwgd2Ugd291bGQgdXNlCgpgYGB7cn0KbXlfbGlzdFtbMl1dWzNdCmBgYAoKTGlzdHMgYXJlIGNvbXBsaWNhdGVkLCBidXQgcmVhbGx5IGNvbW1vbiBpbiBSIChzb3JyeSksIHBhcnRpY3VsYXJseSBzbyB3aGVuIHVzaW5nIGZ1bmN0aW9ucyBvbiB5b3VyIGRhdGEuIExvdHMgb2YgdGhlIHRpbWUsIGEgZnVuY3Rpb24gd2lsbCBvdXRwdXQgYSBzZXJpZXMgb2YgdmFsdWVzIG9yIGluZm9ybWF0aW9uIHN0b3JlZCB3aXRoaW4gYSBsaXN0LCBhbmQgaXQncyByZWFsbHkgdXNlZnVsIHRvIGJlIGFibGUgdG8gZXh0cmFjdCB0aGF0IGluZm9ybWF0aW9uIGluIGEgd2F5IHRoYXQgbWVhbnMgeW91J3JlIGFsd2F5cyBnZXR0aW5nIHdoYXQgeW91IHRoaW5rIHlvdSdyZSBnZXR0aW5nISAKCiMjIEJhY2sgdG8gYGBsYXBwbHkoKWAKCk5vdyB0aGF0IHdlIGhhdmUgb3VyIGxpc3QsIHdlIGNhbiB1c2UgYGxhcHBseSgpYCB0byBwZXJmb3JtIGZ1bmN0aW9ucyBvbiBlYWNoIG9mIHRoZSB2ZWN0b3JzLiBMZXQncyBzdGFydCBieSB3b3JraW5nIG91dCB0aGUgbGVuZ3RocyBvZiBlYWNoIG9mIHRoZSBlbGVtZW50cyBvZiB0aGUgbGlzdCAobm90ZSB0aGF0IHlvdSBkb24ndCBoYXZlIHRvIHByb3ZpZGUgZGltZW5zaW9uIHdpdGggYGxhcHBseWApCgpgYGB7cn0KbGFwcGx5KG15X2xpc3QsIGxlbmd0aCkKYGBgClRoaXMgZ2l2ZXMgdXMgb3VyIG91dHB1dCBhcyBhIGxpc3QuIFNvIG5vdywgd2UgaGF2ZSBhIGxpc3Qgb2YgbGVuZ3RocyBvZiBlbGVtZW50cyBvZiBvdXIgb3JpZ2luYWwgbGlzdC4gUGhldy4gSXQncyBpbXBvcnRhbnQgdG8gcmVtZW1iZXIgKipsYXBwbHkoKSBhbHdheXMgcmV0dXJucyB2YWx1ZXMgaW4gYSBsaXN0KiouIFRoZXJlIGlzIGEgd2F5IGFyb3VuZCB0aGlzLCBidXQgd2UnbGwgdGFsayBhYm91dCB0aGF0IGluIGEgbW9tZW50LiAKCldlIGRvbid0IGhhdmUgdG8gZXhjbHVzaXZlbHkgdXNlIGBsYXBwbHkoKWAgb24gbGlzdHMsIHdlIGNhbiBhbHNvIHVzZSBpdCBvbiBkYXRhZnJhbWVzICh3aGljaCBgbGFwcGx5KClgIHdpbGwgY29lcmNlIGludG8gbGlzdHMgYmVmb3JlIGl0IGRvZXMgYW55dGhpbmcgd2l0aCB0aGVtKS4gTGV0J3MgaGF2ZSBhIGxvb2sgYXQgd2hhdCBvdXIgbXlfaXJpcyBkYXRhIGxvb2tzIGxpa2UgYXMgYSBsaXN0OgoKYGBge3J9CmFzLmxpc3QobXlfaXJpcykKYGBgCgpUaGlzIGhhcyBzZXBhcmF0ZWQgZWFjaCBvZiBvdXIgZm91ciBjb2x1bW5zIGludG8gdGhlaXIgb3duIGxpc3QgZWxlbWVudCAoaGVscGZ1bGx5IHdpdGggdGhlIGNvbHVtbiBuYW1lcyByZXRhaW5lZCEpLiBUaGVyZSBhcmUgNCBlbGVtZW50cyBvZiB0aGUgbGlzdCwgZWFjaCB3aXRoIDE1MCBvYnNlcnZhdGlvbnMgaW4uIGxhcHBseSB3aWxsIGF1dG9tYXRpY2FsbHkgYXBwbHkgdG8gdGhlIGNvbHVtbnMsIHdoaWNoIGFzIHlvdSBjYW4gc2VlLCBhcmUgd2hhdCBzcGxpdCBvZmYgaW50byBsaXN0IGVsZW1lbnRzLiBOb3RlIHRoYXQgd2UgaGF2ZW4ndCBvdmVyd3JpdHRlbiBteV9pcmlzIGFzIGEgbGlzdCAtIGl0J3Mgc3RpbGwgYSBkYXRhZnJhbWUgYXQgdGhlIG1pbnV0ZQoKYGBge3J9CmNsYXNzKG15X2lyaXMpCmBgYAoKVGhpcyB3YXMganVzdCB0byBnZXQgYW4gaWRlYSBvZiBob3cgYGxhcHBseSgpYCBtaWdodCBjb2VyY2Ugb3VyIGRhdGEgaW50byBsaXN0IGZvcm1hdCwgYW5kIHdoYXQgdGhhdCBtaWdodCBtZWFuIGZvciB0aGUgZnVuY3Rpb24uIExldCdzIHRyeSBhbmQgdXNlIGBsYXBwbHlgIHRvIGZpbmQgdGhlIG1lYW5zIG9mIGVhY2ggY29sdW1uCgpgYGB7cn0KbGFwcGx5KG15X2lyaXMsIG1lYW4pCmBgYApPb3BzIC0gd2UgZm9yZ290IGFib3V0IG91ciBgTkFgIHByb2JsZW0gLSB3ZSBjYW4gYWRkIGFyZ3VtZW50cyBpbiB0aGUgc2FtZSB3YXkgdGhhdCB3ZSBkaWQgaW4gYGFwcGx5KClgCgpgYGB7cn0KbGFwcGx5KG15X2lyaXMsIG1lYW4sIG5hLnJtID0gVFJVRSkKYGBgCiMgYHNhcHBseSgpYAoKVGhlIGxhc3Qgb2YgdGhlIHRocmVlIGBhcHBseSgpYCBmdW5jdGlvbnMgd2UncmUgZ29pbmcgdG8gbG9vayBhdCB0b2RheSBpcyBgc2FwcGx5KClgLiBUaGlzIHdvcmtzIGFsbW9zdCBpZGVudGljYWxseSB0byBgbGFwcGx5KClgLCBidXQgd2l0aCB0aGUgb3B0aW9uIHRvIHNpbXBsaWZ5IHRoZSBvdXRwdXQgZnJvbSBhIGxpc3QgdG8gYSB2ZWN0b3IuIFRoaXMgaXMgYXJndWFibHkgdGhlIG1vc3QgdmVyc2F0aWxlLCBhcyBpdCB0YWtlcyBhbnkgaW5wdXQsIGFuZCBjYW4gcmV0dXJuIGl0IHRvIHlvdSBpbiBhIHZhcmlldHkgb2YgZm9ybWF0cy4gTGV0J3Mgc3RhcnQgd2l0aCBmZWVkaW5nIGBzYXBwbHkoKWAgYSBkYXRhc2V0LCBhbmQgY29udGludWUgd2l0aCBvdXIgdGhlbWUgb2YgZmluZGluZyB0aGUgY29sdW1uIG1lYW5zIG9mIGBteV9pcmlzYDoKCmBgYHtyfQpzYXBwbHkobXlfaXJpcywgbWVhbikKYGBgCgpUaGUgZnVuY3Rpb24gaXMgY29uc3RydWN0ZWQgaW4gYW4gaWRlbnRpY2FsIHdheSB0byBgbGFwcGx5KClgLCBidXQgdGhlIG91dHB1dCBpcyBhIHZlY3RvciB3aGljaCBtaWdodCBiZSBtb3JlIHVzZWZ1bCBmb3IgZG93bnN0cmVhbSBhbmFseXNpcy4gV2UgcmVtb3ZlIHRoZSBgTkFgIGluIGV4YWN0bHkgdGhlIHNhbWUgd2F5IGFzIGJlZm9yZQoKYGBge3J9CnNhcHBseShteV9pcmlzLCBtZWFuLCBuYS5ybSA9IFRSVUUpCmBgYAoKV2UgY2FuIGFsc28gZmVlZCBgc2FwcGx5KClgIGxpc3RzIHRvIHdvcmsgb24uIExldCdzIGdpdmUgaXQgdGhlIGxpc3Qgd2UgY3JlYXRlZCBlYXJsaWVyIGFuZCBhc2sgaXQgdG8gd29yayBvdXQgdGhlIGxlbmd0aHMgb2YgdGhlIGVsZW1lbnRzCgpgYGB7cn0Kc2FwcGx5KG15X2xpc3QsIGxlbmd0aCkKYGBgCgpXZSBjYW4gYWxzbyBtYWtlIGBzYXBwbHkoKWAgcmV0dXJuIGEgbGlzdCB0byB1cywgYW5kIGFsbW9zdCByZXZlcnQgaXQgYmFjayB0byBgbGFwcGx5KClgLCBieSBhZGRpbmcgdGhlIGBzaW1wbGlmeSA9IEZBTFNFYCBhcmd1bWVudC4gQnkgZGVmYXVsdCwgdGhpcyBpcyBzZXQgdG8gYFRSVUVgIGluIGBzYXBwbHkoKWA6CgpgYGB7cn0Kc2FwcGx5KG15X2xpc3QsIGxlbmd0aCwgc2ltcGxpZnkgPSBGQUxTRSkKYGBgCmBzYXBwbHkoKWAgaW4gcGFydGljdWxhciwgYnV0IHRoZSBhcHBseSBmYW1pbHkgaW4gZ2VuZXJhbCBhcmUgYSByZWFsbHkgdXNlZnVsIHRvb2wgaW4gUiB0byBhbGxvdyB5b3UgdG8gYXZvaWQgZm9yIGxvb3BzIC0gd2UgY2FuIHVzZSBgc2FwcGx5KClgIHRvIGRvIHNvbWUgcmVhbGx5IHN1YnN0YW50aWFsIHN0dWZmIGZvciB1cyBpbiBSLCB3YXkgYmV5b25kIHdoYXQgd2UndmUgY292ZXJlZCBoZXJlLiBXZSBjYW4gYWxzbyB1c2UgYW5vbnltb3VzIGZ1bmN0aW9ucyB3aXRoIGBzYXBwbHkoKWAgaW4gdGhlIHNhbWUgd2F5IGFzIHdlIGRpZCBpbiBgYXBwbHkoKWAuIExldCdzIHdyaXRlIG9uZSB0aGF0IHdpbGwgdGFrZSB0aGUgcmVjaXByb2NhbCB2YWx1ZSBvZiBlYWNoIG51bWJlciBpbiBhIHZlY3RvciBmcm9tIDE6MTAKCmBgYHtyfQpzYXBwbHkoMToxMCwgZnVuY3Rpb24oeCl7CiAgMS94Cn0pCmBgYAoKQW5kIGlmIHdlIHdhbnQgdGhlIG91dHB1dCBpbiBhIGxpc3Q6CgpgYGB7cn0Kc2FwcGx5KDE6MTAsIHNpbXBsaWZ5ID0gRkFMU0UsIGZ1bmN0aW9uKHgpewogIDEveAp9KQpgYGAKCldlIGFyZSBpdGVyYXRpbmcgYWNyb3NzIGEgbnVtZXJpYyB2ZWN0b3IsIGFuZCBhcHBseWluZyBhbiBhbm9ueW1vdXMgZnVuY3Rpb24gdG8gaXQuIFdlJ3JlIHRha2luZyBlYWNoIHZhbHVlIGZyb20gMToxMCwgY2FsbGluZyBpdCB4LCBhbmQgdGhlbiB0YWtpbmcgdGhlIHJlY2lwcm9jYWwgb2YgaXQuIFdlIGNhbiBhY2hpZXZlIHNvbWV0aGluZyBzaW1pbGFyIHdpdGggY2hhcmFjdGVyIHZlY3RvcnMgLSBpbWFnaW5lIHdlIHdhbnRlZCB0byBjcmVhdGUgYSBzZXJpZXMgb2YgdmFyaWFibGVzIGZvciAyNCBjaHJvbW9zb21lcyBpbiBhIGdlbm9tZToKCmBgYHtyfQpzYXBwbHkoMToyNCwgZnVuY3Rpb24oeCl7CiAgcGFzdGUwKCJjaHIiLHgpCn0pCmBgYAogCiBwYXN0ZTAgcGVyZm9ybXMgdGhlIHNhbWUgYXMgcGFzdGUgLSBidXQgZG9lc24ndCBpbmNsdWRlIHNwYWNlcyEgVGhpcyB3aWxsIG91dHB1dCBhIHNlcmllcyBvZiBjaHJvbW9zb21lIG5hbWVzIGZvciB5b3UsIHdpdGhvdXQgeW91IGhhdmluZyB0byBmYWZmLiBUaGVyZSBpcywgaG93ZXZlciwgYXMgYWx3YXlzLCBhIHF1aWNrZXIgd2F5IG9mIHBlcmZvcm1pbmcgdGhpcyBmdW5jdGlvbiBpbiBlYWNoIGNhc2UuCiAKYGBge3J9CnogPC0gMToxMAoxL3oKCgoxLzE6MTAKCgpwYXN0ZTAoImNociIsIDE6MjQpCgpgYGAKSXQgbWlnaHQgc2VlbSBjb3VudGVyaW50dWl0aXZlIHRvIGJvdGhlciBsZWFybmluZyBgYXBwbHkoKWAsIGJ1dCBJIHByb21pc2UgdGhlcmUgd2lsbCBub3QgYWx3YXlzIGJlIGFuIGVhc2llciB3YXkgLSBJIGp1c3QgdGhpbmsgaXQncyBhIHJlYWxseSB1c2VmdWwgc2tpbGwgdG8gc3BvdCB3aGVuIHlvdSBtaWdodCBiZSBtYWtpbmcgeW91ciBvd24gbGlmZSBtdWNoIGhhcmRlciB0aGFuIHlvdSBuZWVkIHRvIQog