Introduction
In previous sections you’ve seen methods for describing individual categorical variables. Now we’ll switch over to describing numerical variables.
The most basic, and probably most commonly used way to describe the typical person in a population with respect to some characteristic that is recorded as a numerical variable, like height or weight, is with a measure of central tendency. In this lecture we’ll discuss three measures of central tendency:
The mean
The median
And the mode
Now, this is not a statistics course, but here we briefly discuss these measures and some of their characteristics to make sure that we’re all on the same page when we discuss interpretation of our results.
The mean
When we talk about the typical, or “average”, value of some variable measured on a continuous scale, we are usually talking about the mean value of that variable, and to be even more specific we are usually talking about the arithmetic mean value. And this value has some favorable characteristics that make it a good description of central tendency.
For starters it’s simple. Most people are familiar with the mean, and at the very least, have some intuitive sense of what it means (no pun intended).
In addition, for any set of values, there can be only one mean value.
However, there are a couple of potentially problematic characteristics of the mean as well:
It’s susceptible to extreme values in your data. In other words, a couple of people with very atypical values for the characteristic you are interested in, can drastically alter the value of the mean, and your estimate for the typical person in your population of interest along with it.
Additionally, it’s very possible to calculate a mean value that is not actually observed anywhere in your data. For instance, the mean weight for our class could be 133 pounds even if nobody in the class actually weighs 133 pounds.
Note: The sample mean is often referred to as \(\bar{x}\), which pronounced “x bar.”
The mode
And finally, we have the mode, or the value that is most often observed in the data. It doesn’t get much simpler than that. But, unlike the mean and the median, there can be more than one mode for a given set of values. In fact, there can even be no mode if all the values are observed the exact same number of times.
However, if there is a mode, by definition it’s observed in the data.
Now that we are all on the same page with respect to the fundamentals of central tendency, let’s take a look at how to calculate these measures using R.
Calculate the mean
Calculating the mean is really straightforward. We can just use base R’s built-in mean()
function.
# Load the Tidyverse package
library(tidyverse)
# Simulate some data
height_and_weight_20 <- tribble(
~id, ~sex, ~ht_in, ~wt_lbs,
"001", "Male", 71, 190,
"002", "Male", 69, 177,
"003", "Female", 64, 130,
"004", "Female", 65, 153,
"005", NA, 73, 173,
"006", "Male", 69, 182,
"007", "Female", 68, 186,
"008", NA, 73, 185,
"009", "Female", 71, 157,
"010", "Male", 66, 155,
"011", "Male", 71, 213,
"012", "Female", 69, 151,
"013", "Female", 66, 147,
"014", "Female", 68, 196,
"015", "Male", 75, 212,
"016", "Female", 69, 19000,
"017", "Female", 66, 194,
"018", "Female", 65, 176,
"019", "Female", 65, 176,
"020", "Female", 65, 102
)
mean(height_and_weight_20$ht_in)
[1] 68.4
Here’s what we did above:
We started by simulating some data. Heights and weights for 20 hypothetical students.
Next, we used base R’s mean()
function to calculate the mean of the column “ht_in” from the data frame “height_and_weight_20”.
Note: if you just type mean(ht_in)
you will get an error. That’s because R will look for an object called “ht_in” in the global environment.
However, we didn’t create an object called “ht_in”. We created an object (in this case a data frame) called “height_and_weight_20”. That object has a column in it called “ht_in”.
So, we must specifically tell R to look for the “ht_in” column in the data frame “height_and_weight_20”. Using base R, we can do that in one of two ways: height_and_weight_20$ht_in
or height_and_weight_20[["ht_in"]]
.
Calculate the mode
Base R does not have a built-in mode()
function. Well, it actually does have a mode()
function, but for some reason that function does not return the mode value(s) of a set of numbers. Instead, the mode()
function gets or sets the type or storage mode of an object. For example:
mode(height_and_weight_20$ht_in)
[1] "numeric"
This is clearly not what we are looking for. So, how do we find the mode value(s)? Well, we are going to have to build our own mode function. I’ll start at the final result – our mode function. Then, I’ll walk you through how I built it one step at a time. Keep in mind, as is almost always the case with R, my way of writing this function is only one of multiple possible ways.
mode_val <- function(x) {
# Count the number of occurrences for each value of x
value_counts <- table(x)
# Get the maximum number of times any value is observed
max_count <- max(value_counts)
# Create and index vector that identifies the positions that correspond to
# count values that are the same as the maximum count value: TRUE if so
# and false otherwise
index <- value_counts == max_count
# Use the index vector to get all values that are observed the same number
# of times as the maximum number of times that any value is observed
unique_values <- names(value_counts)
result <- unique_values[index]
# If result is the same length as value counts that means that every value
# occured the same number of times. If every value occurred the same number
# of times, then there is no mode
no_mode <- length(value_counts) == length(result)
# If there is no mode then change the value of result to NA
if (no_mode) {
result <- NA
}
# Return result
result
}
mode_val(height_and_weight_20$ht_in)
[1] "65" "69"
Here’s what we did above:
We created our own function, mode_val()
, that takes a vector (or data frame column) as an argument to its “x” parameter, and returns the mode value(s) of that vector.
We can also see that the function works as expected when there is more than one mode value. In this case, “65” and “69” each occur 4 times in the column “ht_in”.
Now that we created our mode function, let’s test to make sure it also works when there is only one mode value and when there is no mode value.
# Test data for one mode value
one_mode <- c(1, 1, 2, 3, 4)
# Should return 1
mode_val(one_mode)
[1] "1"
# Test data for no mode value
no_mode <- c(1, 2, 3, 4, 5)
# Should return NA
mode_val(no_mode)
[1] NA
Here’s what we did above:
We tested our function, mode_val()
, on a vector with one mode value and a vector with no mode value. We got the results we expected.
Now you may want to save this function somewhere so that you can use it again in the future if you need to.
Dissecting our mode function
You may have already figured out how our mode_val()
function works by just looking through the comments I put inside the function. If so, great! If not, I walk through how it works step-by-step in this section.
First, we used the table()
function to return a contingency table. A numeric vector that includes each unique value of “ht_in” along with the number of times each value occurs.
# Count the number of occurrences for each value of x
value_counts <- table(height_and_weight_20$ht_in)
value_counts
64 65 66 68 69 71 73 75
1 4 3 2 4 3 2 1
Just looking at the contingency table above, you can see that the largest number of occurrences is 4. In other words, 4 students had a height of 65" and 4 students had a height of 69". If this were our real data, we would probably just stop here. We have our answer. However, it would be tedious and error-prone to manually check for the mode value this way if our real data included many more possible values.
Second, we figured out what the maximum number of times any value occurred.
# Get the maximum number of times any value is observed
max_count <- max(value_counts)
max_count
[1] 4
Third, we created an index vector that is the same length as “value_counts” (i.e. 8). The index vector has a value of TRUE in each position were “value_counts” is equal to “max_count” (i.e. 4).
# Create and index vector that identifies the positions that correspond to
# count values that are the same as the maximum count value: TRUE if so
# and false otherwise
index <- value_counts == max_count
index
64 65 66 68 69 71 73 75
FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE
Fourth, we use that index vector to keep only the values of “ht_in” that were observed 4 times – where “index” is TRUE.
unique_values <- names(value_counts)
unique_values
[1] "64" "65" "66" "68" "69" "71" "73" "75"
result <- unique_values[index]
result
[1] "65" "69"
We could stop here if we didn’t have to worry about vectors that don’t have a mode value. However, if we want our function to be as complete as possible, we should make sure it intelligently handles vectors that don’t have a mode value.
We will do that below using a conditional statement. If you need a refresher on conditional statements, you may want to work through Intermediate R, Chapter 1: Conditionals and Control Flow again.
So, the fifth step is to test the equality of the lengths of “value_counts” and “result”. At this point in our function “value_counts” is a vector that includes each unique value of “ht_in” along with the number of times each value occurs. Result is a vector that includes only the values of “ht_in” that were observed the same number of times as the maximum number of times any value was observed – in this case, 4. So, the lengths of “value_counts” and “result” are:
length(value_counts)
[1] 8
length(result)
[1] 2
And therefore…
length(value_counts) == length(result)
[1] FALSE
And therefore…
# If result is the same length as value counts that means that every value
# occured the same number of times. If every value occurred the same number
# of times, then there is no mode
no_mode <- length(value_counts) == length(result)
no_mode
[1] FALSE
But, what would happen in a case where each value appeared exactly one time?
ht_in_same <- c(68, 69, 70,71,72)
value_counts_same <- table(ht_in_same)
max_count_same <- max(value_counts_same)
index_same <- value_counts_same == max_count_same
unique_values_same <- names(value_counts_same)
result_same <- unique_values_same[index_same]
value_counts_same
ht_in_same
68 69 70 71 72
1 1 1 1 1
result_same
[1] "68" "69" "70" "71" "72"
length(value_counts_same) == length(result_same)
[1] TRUE
As you can see, whenever each value appears the same number of times (in this case one time each) the length of “value_counts” and “result” will be equal. In that case (i.e. “no_mode” is TRUE), we want to overwrite the value of result to be NA (missing). In other words, when all values appear the same name of times, there is no mode value – it is missing.
Here’s what we did above:
We broke down our mode_val()
function into its component parts. We viewed what each part does and how it ultimately contributes to a working function.
This version of the mode_val()
function was especially long an verbose. I did this intentionally to help make it easier to understand how it works. And in this case, that really isn’t a problem. However, you can try rewriting this function in a more succinct way if you want to challenge yourself.
LS0tCnRpdGxlOiAiRGVzY3JpYmluZyBDZW50cmFsIFRlbmRlbmN5IgphdXRob3I6ICJCcmFkIENhbm5lbGwiCmRhdGU6ICJDcmVhdGVkOiAyMDE5LTA0LTIyIDxicj4gVXBkYXRlZDogYHIgU3lzLkRhdGUoKWAiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazogCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY3NzOiAiLi4vLi4vY3NzL2xtLW1hcmtkb3duLXN0eWxlcy5jc3MiCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKYGBgCgojIEludHJvZHVjdGlvbgoKSW4gcHJldmlvdXMgc2VjdGlvbnMgeW91J3ZlIHNlZW4gbWV0aG9kcyBmb3IgZGVzY3JpYmluZyBpbmRpdmlkdWFsIGNhdGVnb3JpY2FsIHZhcmlhYmxlcy4gTm93IHdl4oCZbGwgc3dpdGNoIG92ZXIgdG8gZGVzY3JpYmluZyBudW1lcmljYWwgdmFyaWFibGVzLgoKIVtdKGltZ19kZXNjcmlwdGl2ZV9hbmFseXNpcy9kZXNjcmlwdGl2ZV9hbmFseXNpc19mbG93Y2hhcnRfMDJfbnVtX29ubHkucG5nKQoKVGhlIG1vc3QgYmFzaWMsIGFuZCBwcm9iYWJseSBtb3N0IGNvbW1vbmx5IHVzZWQgd2F5IHRvIGRlc2NyaWJlIHRoZSB0eXBpY2FsIHBlcnNvbiBpbiBhIHBvcHVsYXRpb24gd2l0aCByZXNwZWN0IHRvIHNvbWUgY2hhcmFjdGVyaXN0aWMgdGhhdCBpcyByZWNvcmRlZCBhcyBhIG51bWVyaWNhbCB2YXJpYWJsZSwgbGlrZSBoZWlnaHQgb3Igd2VpZ2h0LCBpcyB3aXRoIGEgbWVhc3VyZSBvZiBjZW50cmFsIHRlbmRlbmN5LgpJbiB0aGlzIGxlY3R1cmUgd2XigJlsbCBkaXNjdXNzIHRocmVlIG1lYXN1cmVzIG9mIGNlbnRyYWwgdGVuZGVuY3k6CgoqIFRoZSBtZWFuCgoqIFRoZSBtZWRpYW4KCiogQW5kIHRoZSBtb2RlCgohW10oaW1nX2Rlc2NyaXB0aXZlX2FuYWx5c2lzL2NlbnRyYWxfdGVuZGVuY3lfMDEucG5nKQoKTm93LCB0aGlzIGlzIG5vdCBhIHN0YXRpc3RpY3MgY291cnNlLCBidXQgaGVyZSB3ZSBicmllZmx5IGRpc2N1c3MgdGhlc2UgbWVhc3VyZXMgYW5kIHNvbWUgb2YgdGhlaXIgY2hhcmFjdGVyaXN0aWNzIHRvIG1ha2Ugc3VyZSB0aGF0IHdl4oCZcmUgYWxsIG9uIHRoZSBzYW1lIHBhZ2Ugd2hlbiB3ZSBkaXNjdXNzIGludGVycHJldGF0aW9uIG9mIG91ciByZXN1bHRzLgoKIyMgVGhlIG1lYW4KCiFbXShpbWdfZGVzY3JpcHRpdmVfYW5hbHlzaXMvY2VudHJhbF90ZW5kZW5jeV8wMi5wbmcpCgpXaGVuIHdlIHRhbGsgYWJvdXQgdGhlIHR5cGljYWwsIG9yIOKAnGF2ZXJhZ2XigJ0sIHZhbHVlIG9mIHNvbWUgdmFyaWFibGUgbWVhc3VyZWQgb24gYSBjb250aW51b3VzIHNjYWxlLCB3ZSBhcmUgdXN1YWxseSB0YWxraW5nIGFib3V0IHRoZSBtZWFuIHZhbHVlIG9mIHRoYXQgdmFyaWFibGUsIGFuZCB0byBiZSBldmVuIG1vcmUgc3BlY2lmaWMgd2UgYXJlIHVzdWFsbHkgdGFsa2luZyBhYm91dCB0aGUgYXJpdGhtZXRpYyBtZWFuIHZhbHVlLiBBbmQgdGhpcyB2YWx1ZSBoYXMgc29tZSBmYXZvcmFibGUgY2hhcmFjdGVyaXN0aWNzIHRoYXQgbWFrZSBpdCBhIGdvb2QgZGVzY3JpcHRpb24gb2YgY2VudHJhbCB0ZW5kZW5jeS4KCjEuIEZvciBzdGFydGVycyBpdOKAmXMgc2ltcGxlLiBNb3N0IHBlb3BsZSBhcmUgZmFtaWxpYXIgd2l0aCB0aGUgbWVhbiwgYW5kIGF0IHRoZSB2ZXJ5IGxlYXN0LCBoYXZlIHNvbWUgaW50dWl0aXZlIHNlbnNlIG9mIHdoYXQgaXQgbWVhbnMgKG5vIHB1biBpbnRlbmRlZCkuIAoKMi4gSW4gYWRkaXRpb24sIGZvciBhbnkgc2V0IG9mIHZhbHVlcywgdGhlcmUgY2FuIGJlIG9ubHkgb25lIG1lYW4gdmFsdWUuIAoKSG93ZXZlciwgdGhlcmUgYXJlIGEgY291cGxlIG9mIHBvdGVudGlhbGx5IHByb2JsZW1hdGljIGNoYXJhY3RlcmlzdGljcyBvZiB0aGUgbWVhbiBhcyB3ZWxsOiAKCjEuIEl04oCZcyBzdXNjZXB0aWJsZSB0byBleHRyZW1lIHZhbHVlcyBpbiB5b3VyIGRhdGEuIEluIG90aGVyIHdvcmRzLCBhIGNvdXBsZSBvZiBwZW9wbGUgd2l0aCB2ZXJ5IGF0eXBpY2FsIHZhbHVlcyBmb3IgdGhlIGNoYXJhY3RlcmlzdGljIHlvdSBhcmUgaW50ZXJlc3RlZCBpbiwgY2FuIGRyYXN0aWNhbGx5IGFsdGVyIHRoZSB2YWx1ZSBvZiB0aGUgbWVhbiwgYW5kIHlvdXIgZXN0aW1hdGUgZm9yIHRoZSB0eXBpY2FsIHBlcnNvbiBpbiB5b3VyIHBvcHVsYXRpb24gb2YgaW50ZXJlc3QgYWxvbmcgd2l0aCBpdC4gPCEtLSBDb2RlIGFuIGV4YW1wbGUgLS0+CgoyLiBBZGRpdGlvbmFsbHksIGl04oCZcyB2ZXJ5IHBvc3NpYmxlIHRvIGNhbGN1bGF0ZSBhIG1lYW4gdmFsdWUgdGhhdCBpcyBub3QgYWN0dWFsbHkgb2JzZXJ2ZWQgYW55d2hlcmUgaW4geW91ciBkYXRhLiBGb3IgaW5zdGFuY2UsIHRoZSBtZWFuIHdlaWdodCBmb3Igb3VyIGNsYXNzIGNvdWxkIGJlIDEzMyBwb3VuZHMgZXZlbiBpZiBub2JvZHkgaW4gdGhlIGNsYXNzIGFjdHVhbGx5IHdlaWdocyAxMzMgcG91bmRzLiA8IS0tIENvZGUgYW4gZXhhbXBsZSAtLT4KCjxkaXYgY2xhc3M9Im1vcmUtaW5mbyI+Ck5vdGU6IFRoZSBzYW1wbGUgbWVhbiBpcyBvZnRlbiByZWZlcnJlZCB0byBhcyAkXGJhcnt4fSQsIHdoaWNoIHByb25vdW5jZWQgInggYmFyLiIKPC9kaXY+CgojIyBUaGUgbWVkaWFuCgohW10oaW1nX2Rlc2NyaXB0aXZlX2FuYWx5c2lzL2NlbnRyYWxfdGVuZGVuY3lfMDMucG5nKQoKVGhlIG1lZGlhbiBpcyBwcm9iYWJseSB0aGUgc2Vjb25kIG1vc3QgY29tbW9ubHkgdXNlZCBtZWFzdXJlIG9mIGNlbnRyYWwgdGVuZGVuY3kgYW5kIGxpa2UgdGhlIG1lYW4gaXTigJlzIGNvbXB1dGF0aW9uYWxseSBzaW1wbGUgYW5kIHJlbGF0aXZlbHkgc3RyYWlnaHRmb3J3YXJkIHRvIHVuZGVyc3RhbmQuIFRoZXJlIGNhbiBiZSBvbmUsIGFuZCBvbmx5IG9uZSwgbWVkaWFuLiBBbmQsIGl0cyB2YWx1ZSBtYXkgYWxzbyBiZSB1bm9ic2VydmVkIGluIHRoZSBkYXRhLgoKSG93ZXZlciwgdW5saWtlIHRoZSBtZWFuLCBpdOKAmXMgcmVsYXRpdmVseSByZXNpc3RhbnQgdG8gZXh0cmVtZSB2YWx1ZXM8IS0tIENvZGUgYW4gZXhhbXBsZSAtLT4uIEluIGZhY3QsIHdoZW4gdGhlIG1lZGlhbiBpcyB1c2VkIGFzIHRoZSBtZWFzdXJlIG9mIGNlbnRyYWwgdGVuZGVuY3ksIGl04oCZcyBvZnRlbiBiZWNhdXNlIHRoZSBwZXJzb24gY29uZHVjdGluZyB0aGUgYW5hbHlzaXMgc3VzcGVjdHMgdGhhdCBleHRyZW1lIHZhbHVlcyBpbiB0aGUgZGF0YSBhcmUgbGlrZWx5IHRvIGRpc3RvcnQgdGhlIG1lYW4uCgojIyBUaGUgbW9kZQoKIVtdKGltZ19kZXNjcmlwdGl2ZV9hbmFseXNpcy9jZW50cmFsX3RlbmRlbmN5XzA0LnBuZykKCkFuZCBmaW5hbGx5LCB3ZSBoYXZlIHRoZSBtb2RlLCBvciB0aGUgdmFsdWUgdGhhdCBpcyBtb3N0IG9mdGVuIG9ic2VydmVkIGluIHRoZSBkYXRhLiBJdCBkb2VzbuKAmXQgZ2V0IG11Y2ggc2ltcGxlciB0aGFuIHRoYXQuIEJ1dCwgdW5saWtlIHRoZSBtZWFuIGFuZCB0aGUgbWVkaWFuLCB0aGVyZSBjYW4gYmUgbW9yZSB0aGFuIG9uZSBtb2RlIGZvciBhIGdpdmVuIHNldCBvZiB2YWx1ZXMuIEluIGZhY3QsIHRoZXJlIGNhbiBldmVuIGJlIG5vIG1vZGUgaWYgYWxsIHRoZSB2YWx1ZXMgYXJlIG9ic2VydmVkIHRoZSBleGFjdCBzYW1lIG51bWJlciBvZiB0aW1lcy4KCkhvd2V2ZXIsIGlmIHRoZXJlIGlzIGEgbW9kZSwgYnkgZGVmaW5pdGlvbiBpdOKAmXMgb2JzZXJ2ZWQgaW4gdGhlIGRhdGEuCgpOb3cgdGhhdCB3ZSBhcmUgYWxsIG9uIHRoZSBzYW1lIHBhZ2Ugd2l0aCByZXNwZWN0IHRvIHRoZSBmdW5kYW1lbnRhbHMgb2YgY2VudHJhbCB0ZW5kZW5jeSwgbGV04oCZcyB0YWtlIGEgbG9vayBhdCBob3cgdG8gY2FsY3VsYXRlIHRoZXNlIG1lYXN1cmVzIHVzaW5nIFIuCgojIENhbGN1bGF0ZSB0aGUgbWVhbgoKQ2FsY3VsYXRpbmcgdGhlIG1lYW4gaXMgcmVhbGx5IHN0cmFpZ2h0Zm9yd2FyZC4gV2UgY2FuIGp1c3QgdXNlIGJhc2UgUidzIGJ1aWx0LWluIGBtZWFuKClgIGZ1bmN0aW9uLgoKYGBge3IgbWVzc2FnZT1GQUxTRX0KIyBMb2FkIHRoZSBUaWR5dmVyc2UgcGFja2FnZQpsaWJyYXJ5KHRpZHl2ZXJzZSkKYGBgCgpgYGB7cn0KIyBTaW11bGF0ZSBzb21lIGRhdGEKaGVpZ2h0X2FuZF93ZWlnaHRfMjAgPC0gdHJpYmJsZSgKICB+aWQsICAgfnNleCwgICAgIH5odF9pbiwgfnd0X2xicywKICAiMDAxIiwgIk1hbGUiLCAgIDcxLCAgICAgMTkwLAogICIwMDIiLCAiTWFsZSIsICAgNjksICAgICAxNzcsCiAgIjAwMyIsICJGZW1hbGUiLCA2NCwgICAgIDEzMCwKICAiMDA0IiwgIkZlbWFsZSIsIDY1LCAgICAgMTUzLAogICIwMDUiLCBOQSwgICAgICAgNzMsICAgICAxNzMsCiAgIjAwNiIsICJNYWxlIiwgICA2OSwgICAgIDE4MiwKICAiMDA3IiwgIkZlbWFsZSIsIDY4LCAgICAgMTg2LAogICIwMDgiLCBOQSwgICAgICAgNzMsICAgICAxODUsCiAgIjAwOSIsICJGZW1hbGUiLCA3MSwgICAgIDE1NywKICAiMDEwIiwgIk1hbGUiLCAgIDY2LCAgICAgMTU1LAogICIwMTEiLCAiTWFsZSIsICAgNzEsICAgICAyMTMsCiAgIjAxMiIsICJGZW1hbGUiLCA2OSwgICAgIDE1MSwKICAiMDEzIiwgIkZlbWFsZSIsIDY2LCAgICAgMTQ3LAogICIwMTQiLCAiRmVtYWxlIiwgNjgsICAgICAxOTYsCiAgIjAxNSIsICJNYWxlIiwgICA3NSwgICAgIDIxMiwKICAiMDE2IiwgIkZlbWFsZSIsIDY5LCAgICAgMTkwMDAsCiAgIjAxNyIsICJGZW1hbGUiLCA2NiwgICAgIDE5NCwKICAiMDE4IiwgIkZlbWFsZSIsIDY1LCAgICAgMTc2LAogICIwMTkiLCAiRmVtYWxlIiwgNjUsICAgICAxNzYsCiAgIjAyMCIsICJGZW1hbGUiLCA2NSwgICAgIDEwMgopCmBgYAoKYGBge3J9Cm1lYW4oaGVpZ2h0X2FuZF93ZWlnaHRfMjAkaHRfaW4pCmBgYAoKKipIZXJlJ3Mgd2hhdCB3ZSBkaWQgYWJvdmU6KioKCiogV2Ugc3RhcnRlZCBieSBzaW11bGF0aW5nIHNvbWUgZGF0YS4gSGVpZ2h0cyBhbmQgd2VpZ2h0cyBmb3IgMjAgaHlwb3RoZXRpY2FsIHN0dWRlbnRzLgoKKiBOZXh0LCB3ZSB1c2VkIGJhc2UgUidzIGBtZWFuKClgIGZ1bmN0aW9uIHRvIGNhbGN1bGF0ZSB0aGUgbWVhbiBvZiB0aGUgY29sdW1uICJodF9pbiIgZnJvbSB0aGUgZGF0YSBmcmFtZSAiaGVpZ2h0X2FuZF93ZWlnaHRfMjAiLgoKICAtIE5vdGU6IGlmIHlvdSBqdXN0IHR5cGUgYG1lYW4oaHRfaW4pYCB5b3Ugd2lsbCBnZXQgYW4gZXJyb3IuIFRoYXQncyBiZWNhdXNlIFIgd2lsbCBsb29rIGZvciBhbiBvYmplY3QgY2FsbGVkICJodF9pbiIgaW4gdGhlIGdsb2JhbCBlbnZpcm9ubWVudC4gCiAgCiAgLSBIb3dldmVyLCB3ZSBkaWRuJ3QgY3JlYXRlIGFuIG9iamVjdCBjYWxsZWQgImh0X2luIi4gV2UgY3JlYXRlZCBhbiBvYmplY3QgKGluIHRoaXMgY2FzZSBhIGRhdGEgZnJhbWUpIGNhbGxlZCAiaGVpZ2h0X2FuZF93ZWlnaHRfMjAiLiBUaGF0IG9iamVjdCBoYXMgYSBjb2x1bW4gaW4gaXQgY2FsbGVkICJodF9pbiIuCgogIC0gU28sIHdlIG11c3Qgc3BlY2lmaWNhbGx5IHRlbGwgUiB0byBsb29rIGZvciB0aGUgImh0X2luIiBjb2x1bW4gaW4gdGhlIGRhdGEgZnJhbWUgImhlaWdodF9hbmRfd2VpZ2h0XzIwIi4gVXNpbmcgYmFzZSBSLCB3ZSBjYW4gZG8gdGhhdCBpbiBvbmUgb2YgdHdvIHdheXM6IGBoZWlnaHRfYW5kX3dlaWdodF8yMCRodF9pbmAgb3IgYGhlaWdodF9hbmRfd2VpZ2h0XzIwW1siaHRfaW4iXV1gLgogIAojIENhbGN1bGF0ZSB0aGUgbWVkaWFuCgpTaW1pbGFyIHRvIGFib3ZlLCB3ZSBjYW4gdXNlIGJhc2UgUidzIGBtZWRpYW4oKWAgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIHRoZSBtZWRpYW4uCgpgYGB7cn0KbWVkaWFuKGhlaWdodF9hbmRfd2VpZ2h0XzIwJGh0X2luKQpgYGAKCioqSGVyZSdzIHdoYXQgd2UgZGlkIGFib3ZlOioqCgoqIFdlIHVzZWQgYmFzZSBSJ3MgYG1lZGlhbigpYCBmdW5jdGlvbiB0byBjYWxjdWxhdGUgdGhlIG1vZGlhbiBvZiB0aGUgY29sdW1uICJodF9pbiIgZnJvbSB0aGUgZGF0YSBmcmFtZSAiaGVpZ2h0X2FuZF93ZWlnaHRfMjAiLgoKIyBDYWxjdWxhdGUgdGhlIG1vZGUKCkJhc2UgUiBkb2VzIG5vdCBoYXZlIGEgYnVpbHQtaW4gYG1vZGUoKWAgZnVuY3Rpb24uIFdlbGwsIGl0IGFjdHVhbGx5IGRvZXMgaGF2ZSBhIGBtb2RlKClgIGZ1bmN0aW9uLCBidXQgZm9yIHNvbWUgcmVhc29uIHRoYXQgZnVuY3Rpb24gZG9lcyBub3QgcmV0dXJuIHRoZSBtb2RlIHZhbHVlKHMpIG9mIGEgc2V0IG9mIG51bWJlcnMuIEluc3RlYWQsIHRoZSBgbW9kZSgpYCBmdW5jdGlvbiBnZXRzIG9yIHNldHMgdGhlIHR5cGUgb3Igc3RvcmFnZSBtb2RlIG9mIGFuIG9iamVjdC4gRm9yIGV4YW1wbGU6CgpgYGB7cn0KbW9kZShoZWlnaHRfYW5kX3dlaWdodF8yMCRodF9pbikKYGBgCgpUaGlzIGlzIGNsZWFybHkgbm90IHdoYXQgd2UgYXJlIGxvb2tpbmcgZm9yLiBTbywgaG93IGRvIHdlIGZpbmQgdGhlIG1vZGUgdmFsdWUocyk/IFdlbGwsIHdlIGFyZSBnb2luZyB0byBoYXZlIHRvIGJ1aWxkIG91ciBvd24gbW9kZSBmdW5jdGlvbi4gSSdsbCBzdGFydCBhdCB0aGUgZmluYWwgcmVzdWx0IC0tIG91ciBtb2RlIGZ1bmN0aW9uLiBUaGVuLCBJJ2xsIHdhbGsgeW91IHRocm91Z2ggaG93IEkgYnVpbHQgaXQgb25lIHN0ZXAgYXQgYSB0aW1lLiBLZWVwIGluIG1pbmQsIGFzIGlzIGFsbW9zdCBhbHdheXMgdGhlIGNhc2Ugd2l0aCBSLCBteSB3YXkgb2Ygd3JpdGluZyB0aGlzIGZ1bmN0aW9uIGlzIG9ubHkgb25lIG9mIG11bHRpcGxlIHBvc3NpYmxlIHdheXMuCgpgYGB7cn0KbW9kZV92YWwgPC0gZnVuY3Rpb24oeCkgewogIAogICMgQ291bnQgdGhlIG51bWJlciBvZiBvY2N1cnJlbmNlcyBmb3IgZWFjaCB2YWx1ZSBvZiB4CiAgdmFsdWVfY291bnRzIDwtIHRhYmxlKHgpCiAgCiAgIyBHZXQgdGhlIG1heGltdW0gbnVtYmVyIG9mIHRpbWVzIGFueSB2YWx1ZSBpcyBvYnNlcnZlZAogIG1heF9jb3VudCA8LSBtYXgodmFsdWVfY291bnRzKQogIAogICMgQ3JlYXRlIGFuZCBpbmRleCB2ZWN0b3IgdGhhdCBpZGVudGlmaWVzIHRoZSBwb3NpdGlvbnMgdGhhdCBjb3JyZXNwb25kIHRvCiAgIyBjb3VudCB2YWx1ZXMgdGhhdCBhcmUgdGhlIHNhbWUgYXMgdGhlIG1heGltdW0gY291bnQgdmFsdWU6IFRSVUUgaWYgc28KICAjIGFuZCBmYWxzZSBvdGhlcndpc2UKICBpbmRleCA8LSB2YWx1ZV9jb3VudHMgPT0gbWF4X2NvdW50CiAgCiAgIyBVc2UgdGhlIGluZGV4IHZlY3RvciB0byBnZXQgYWxsIHZhbHVlcyB0aGF0IGFyZSBvYnNlcnZlZCB0aGUgc2FtZSBudW1iZXIgCiAgIyBvZiB0aW1lcyBhcyB0aGUgbWF4aW11bSBudW1iZXIgb2YgdGltZXMgdGhhdCBhbnkgdmFsdWUgaXMgb2JzZXJ2ZWQKICB1bmlxdWVfdmFsdWVzIDwtIG5hbWVzKHZhbHVlX2NvdW50cykKICByZXN1bHQgPC0gdW5pcXVlX3ZhbHVlc1tpbmRleF0KICAKICAjIElmIHJlc3VsdCBpcyB0aGUgc2FtZSBsZW5ndGggYXMgdmFsdWUgY291bnRzIHRoYXQgbWVhbnMgdGhhdCBldmVyeSB2YWx1ZQogICMgb2NjdXJlZCB0aGUgc2FtZSBudW1iZXIgb2YgdGltZXMuIElmIGV2ZXJ5IHZhbHVlIG9jY3VycmVkIHRoZSBzYW1lIG51bWJlcgogICMgb2YgdGltZXMsIHRoZW4gdGhlcmUgaXMgbm8gbW9kZQogIG5vX21vZGUgPC0gbGVuZ3RoKHZhbHVlX2NvdW50cykgPT0gbGVuZ3RoKHJlc3VsdCkKICAKICAjIElmIHRoZXJlIGlzIG5vIG1vZGUgdGhlbiBjaGFuZ2UgdGhlIHZhbHVlIG9mIHJlc3VsdCB0byBOQQogIGlmIChub19tb2RlKSB7CiAgICByZXN1bHQgPC0gTkEKICB9CiAgCiAgIyBSZXR1cm4gcmVzdWx0CiAgcmVzdWx0Cn0KYGBgCgpgYGB7cn0KbW9kZV92YWwoaGVpZ2h0X2FuZF93ZWlnaHRfMjAkaHRfaW4pCmBgYAoKKipIZXJlJ3Mgd2hhdCB3ZSBkaWQgYWJvdmU6KioKCiogV2UgY3JlYXRlZCBvdXIgb3duIGZ1bmN0aW9uLCBgbW9kZV92YWwoKWAsIHRoYXQgdGFrZXMgYSB2ZWN0b3IgKG9yIGRhdGEgZnJhbWUgY29sdW1uKSBhcyBhbiBhcmd1bWVudCB0byBpdHMgIngiIHBhcmFtZXRlciwgYW5kIHJldHVybnMgdGhlIG1vZGUgdmFsdWUocykgb2YgdGhhdCB2ZWN0b3IuCgoqIFdlIGNhbiBhbHNvIHNlZSB0aGF0IHRoZSBmdW5jdGlvbiB3b3JrcyBhcyBleHBlY3RlZCB3aGVuIHRoZXJlIGlzIG1vcmUgdGhhbiBvbmUgbW9kZSB2YWx1ZS4gSW4gdGhpcyBjYXNlLCAiNjUiIGFuZCAiNjkiIGVhY2ggb2NjdXIgNCB0aW1lcyBpbiB0aGUgY29sdW1uICJodF9pbiIuIAoKTm93IHRoYXQgd2UgY3JlYXRlZCBvdXIgbW9kZSBmdW5jdGlvbiwgbGV0J3MgdGVzdCB0byBtYWtlIHN1cmUgaXQgYWxzbyB3b3JrcyB3aGVuIHRoZXJlIGlzIG9ubHkgb25lIG1vZGUgdmFsdWUgYW5kIHdoZW4gdGhlcmUgaXMgbm8gbW9kZSB2YWx1ZS4KCmBgYHtyfQojIFRlc3QgZGF0YSBmb3Igb25lIG1vZGUgdmFsdWUKb25lX21vZGUgPC0gYygxLCAxLCAyLCAzLCA0KQpgYGAKCmBgYHtyfQojIFNob3VsZCByZXR1cm4gMQptb2RlX3ZhbChvbmVfbW9kZSkKYGBgCgpgYGB7cn0KIyBUZXN0IGRhdGEgZm9yIG5vIG1vZGUgdmFsdWUKbm9fbW9kZSA8LSBjKDEsIDIsIDMsIDQsIDUpCmBgYAoKYGBge3J9CiMgU2hvdWxkIHJldHVybiBOQQptb2RlX3ZhbChub19tb2RlKQpgYGAKCioqSGVyZSdzIHdoYXQgd2UgZGlkIGFib3ZlOioqCgoqIFdlIHRlc3RlZCBvdXIgZnVuY3Rpb24sIGBtb2RlX3ZhbCgpYCwgb24gYSB2ZWN0b3Igd2l0aCBvbmUgbW9kZSB2YWx1ZSBhbmQgYSB2ZWN0b3Igd2l0aCBubyBtb2RlIHZhbHVlLiBXZSBnb3QgdGhlIHJlc3VsdHMgd2UgZXhwZWN0ZWQuCgoqIE5vdyB5b3UgbWF5IHdhbnQgdG8gc2F2ZSB0aGlzIGZ1bmN0aW9uIHNvbWV3aGVyZSBzbyB0aGF0IHlvdSBjYW4gdXNlIGl0IGFnYWluIGluIHRoZSBmdXR1cmUgaWYgeW91IG5lZWQgdG8uCgojIyBEaXNzZWN0aW5nIG91ciBtb2RlIGZ1bmN0aW9uCgpZb3UgbWF5IGhhdmUgYWxyZWFkeSBmaWd1cmVkIG91dCBob3cgb3VyIGBtb2RlX3ZhbCgpYCBmdW5jdGlvbiB3b3JrcyBieSBqdXN0IGxvb2tpbmcgdGhyb3VnaCB0aGUgY29tbWVudHMgSSBwdXQgaW5zaWRlIHRoZSBmdW5jdGlvbi4gSWYgc28sIGdyZWF0ISBJZiBub3QsIEkgd2FsayB0aHJvdWdoIGhvdyBpdCB3b3JrcyBzdGVwLWJ5LXN0ZXAgaW4gdGhpcyBzZWN0aW9uLgoKRmlyc3QsIHdlIHVzZWQgdGhlIGB0YWJsZSgpYCBmdW5jdGlvbiB0byByZXR1cm4gYSBjb250aW5nZW5jeSB0YWJsZS4gQSBudW1lcmljIHZlY3RvciB0aGF0IGluY2x1ZGVzIGVhY2ggdW5pcXVlIHZhbHVlIG9mICJodF9pbiIgYWxvbmcgd2l0aCB0aGUgbnVtYmVyIG9mIHRpbWVzIGVhY2ggdmFsdWUgb2NjdXJzLgoKYGBge3J9CiMgQ291bnQgdGhlIG51bWJlciBvZiBvY2N1cnJlbmNlcyBmb3IgZWFjaCB2YWx1ZSBvZiB4CnZhbHVlX2NvdW50cyA8LSB0YWJsZShoZWlnaHRfYW5kX3dlaWdodF8yMCRodF9pbikKdmFsdWVfY291bnRzCmBgYAoKSnVzdCBsb29raW5nIGF0IHRoZSBjb250aW5nZW5jeSB0YWJsZSBhYm92ZSwgeW91IGNhbiBzZWUgdGhhdCB0aGUgbGFyZ2VzdCBudW1iZXIgb2Ygb2NjdXJyZW5jZXMgaXMgNC4gSW4gb3RoZXIgd29yZHMsIDQgc3R1ZGVudHMgaGFkIGEgaGVpZ2h0IG9mIDY1IiBhbmQgNCBzdHVkZW50cyBoYWQgYSBoZWlnaHQgb2YgNjkiLiBJZiB0aGlzIHdlcmUgb3VyIHJlYWwgZGF0YSwgd2Ugd291bGQgcHJvYmFibHkganVzdCBzdG9wIGhlcmUuIFdlIGhhdmUgb3VyIGFuc3dlci4gSG93ZXZlciwgaXQgd291bGQgYmUgdGVkaW91cyBhbmQgZXJyb3ItcHJvbmUgdG8gbWFudWFsbHkgY2hlY2sgZm9yIHRoZSBtb2RlIHZhbHVlIHRoaXMgd2F5IGlmIG91ciByZWFsIGRhdGEgaW5jbHVkZWQgbWFueSBtb3JlIHBvc3NpYmxlIHZhbHVlcy4KClNlY29uZCwgd2UgZmlndXJlZCBvdXQgd2hhdCB0aGUgbWF4aW11bSBudW1iZXIgb2YgdGltZXMgYW55IHZhbHVlIG9jY3VycmVkLiAKCmBgYHtyfQojIEdldCB0aGUgbWF4aW11bSBudW1iZXIgb2YgdGltZXMgYW55IHZhbHVlIGlzIG9ic2VydmVkCm1heF9jb3VudCA8LSBtYXgodmFsdWVfY291bnRzKQptYXhfY291bnQKYGBgCgpUaGlyZCwgd2UgY3JlYXRlZCBhbiBpbmRleCB2ZWN0b3IgdGhhdCBpcyB0aGUgc2FtZSBsZW5ndGggYXMgInZhbHVlX2NvdW50cyIgKGkuZS4gOCkuIFRoZSBpbmRleCB2ZWN0b3IgaGFzIGEgdmFsdWUgb2YgVFJVRSBpbiBlYWNoIHBvc2l0aW9uIHdlcmUgInZhbHVlX2NvdW50cyIgaXMgZXF1YWwgdG8gIm1heF9jb3VudCIgKGkuZS4gNCkuCgpgYGB7cn0KIyBDcmVhdGUgYW5kIGluZGV4IHZlY3RvciB0aGF0IGlkZW50aWZpZXMgdGhlIHBvc2l0aW9ucyB0aGF0IGNvcnJlc3BvbmQgdG8KIyBjb3VudCB2YWx1ZXMgdGhhdCBhcmUgdGhlIHNhbWUgYXMgdGhlIG1heGltdW0gY291bnQgdmFsdWU6IFRSVUUgaWYgc28KIyBhbmQgZmFsc2Ugb3RoZXJ3aXNlCmluZGV4IDwtIHZhbHVlX2NvdW50cyA9PSBtYXhfY291bnQKaW5kZXgKYGBgCgpGb3VydGgsIHdlIHVzZSB0aGF0IGluZGV4IHZlY3RvciB0byBrZWVwIG9ubHkgdGhlIHZhbHVlcyBvZiAiaHRfaW4iIHRoYXQgd2VyZSBvYnNlcnZlZCA0IHRpbWVzIC0tIHdoZXJlICJpbmRleCIgaXMgVFJVRS4KCmBgYHtyfQp1bmlxdWVfdmFsdWVzIDwtIG5hbWVzKHZhbHVlX2NvdW50cykKdW5pcXVlX3ZhbHVlcwpgYGAKCmBgYHtyfQpyZXN1bHQgPC0gdW5pcXVlX3ZhbHVlc1tpbmRleF0KcmVzdWx0CmBgYAoKV2UgY291bGQgc3RvcCBoZXJlIGlmIHdlIGRpZG4ndCBoYXZlIHRvIHdvcnJ5IGFib3V0IHZlY3RvcnMgdGhhdCBkb24ndCBoYXZlIGEgbW9kZSB2YWx1ZS4gSG93ZXZlciwgaWYgd2Ugd2FudCBvdXIgZnVuY3Rpb24gdG8gYmUgYXMgY29tcGxldGUgYXMgcG9zc2libGUsIHdlIHNob3VsZCBtYWtlIHN1cmUgaXQgaW50ZWxsaWdlbnRseSBoYW5kbGVzIHZlY3RvcnMgdGhhdCBkb24ndCBoYXZlIGEgbW9kZSB2YWx1ZS4KCldlIHdpbGwgZG8gdGhhdCBiZWxvdyB1c2luZyBhIGNvbmRpdGlvbmFsIHN0YXRlbWVudC4gSWYgeW91IG5lZWQgYSByZWZyZXNoZXIgb24gY29uZGl0aW9uYWwgc3RhdGVtZW50cywgeW91IG1heSB3YW50IHRvIHdvcmsgdGhyb3VnaCBbSW50ZXJtZWRpYXRlIFIsIENoYXB0ZXIgMTogQ29uZGl0aW9uYWxzIGFuZCBDb250cm9sIEZsb3ddKGh0dHBzOi8vd3d3LmRhdGFjYW1wLmNvbS9jb3Vyc2VzL2ludGVybWVkaWF0ZS1yKSBhZ2Fpbi4KClNvLCB0aGUgZmlmdGggc3RlcCBpcyB0byB0ZXN0IHRoZSBlcXVhbGl0eSBvZiB0aGUgbGVuZ3RocyBvZiAidmFsdWVfY291bnRzIiBhbmQgInJlc3VsdCIuIEF0IHRoaXMgcG9pbnQgaW4gb3VyIGZ1bmN0aW9uICJ2YWx1ZV9jb3VudHMiIGlzIGEgdmVjdG9yIHRoYXQgaW5jbHVkZXMgZWFjaCB1bmlxdWUgdmFsdWUgb2YgImh0X2luIiBhbG9uZyB3aXRoIHRoZSBudW1iZXIgb2YgdGltZXMgZWFjaCB2YWx1ZSBvY2N1cnMuIFJlc3VsdCBpcyBhIHZlY3RvciB0aGF0IGluY2x1ZGVzIG9ubHkgdGhlIHZhbHVlcyBvZiAiaHRfaW4iIHRoYXQgd2VyZSBvYnNlcnZlZCB0aGUgc2FtZSBudW1iZXIgb2YgdGltZXMgYXMgdGhlIG1heGltdW0gbnVtYmVyIG9mIHRpbWVzIGFueSB2YWx1ZSB3YXMgb2JzZXJ2ZWQgLS0gaW4gdGhpcyBjYXNlLCA0LiBTbywgdGhlIGxlbmd0aHMgb2YgInZhbHVlX2NvdW50cyIgYW5kICJyZXN1bHQiIGFyZToKCmBgYHtyfQpsZW5ndGgodmFsdWVfY291bnRzKQpgYGAKCmBgYHtyfQpsZW5ndGgocmVzdWx0KQpgYGAKCkFuZCB0aGVyZWZvcmUuLi4KCmBgYHtyfQpsZW5ndGgodmFsdWVfY291bnRzKSA9PSBsZW5ndGgocmVzdWx0KQpgYGAKCkFuZCB0aGVyZWZvcmUuLi4KCmBgYHtyfQojIElmIHJlc3VsdCBpcyB0aGUgc2FtZSBsZW5ndGggYXMgdmFsdWUgY291bnRzIHRoYXQgbWVhbnMgdGhhdCBldmVyeSB2YWx1ZQojIG9jY3VyZWQgdGhlIHNhbWUgbnVtYmVyIG9mIHRpbWVzLiBJZiBldmVyeSB2YWx1ZSBvY2N1cnJlZCB0aGUgc2FtZSBudW1iZXIKIyBvZiB0aW1lcywgdGhlbiB0aGVyZSBpcyBubyBtb2RlCm5vX21vZGUgPC0gbGVuZ3RoKHZhbHVlX2NvdW50cykgPT0gbGVuZ3RoKHJlc3VsdCkKbm9fbW9kZQpgYGAKCkJ1dCwgd2hhdCB3b3VsZCBoYXBwZW4gaW4gYSBjYXNlIHdoZXJlIGVhY2ggdmFsdWUgYXBwZWFyZWQgZXhhY3RseSBvbmUgdGltZT8KCmBgYHtyfQpodF9pbl9zYW1lIDwtIGMoNjgsIDY5LCA3MCw3MSw3MikKdmFsdWVfY291bnRzX3NhbWUgPC0gdGFibGUoaHRfaW5fc2FtZSkKbWF4X2NvdW50X3NhbWUgPC0gbWF4KHZhbHVlX2NvdW50c19zYW1lKQppbmRleF9zYW1lIDwtIHZhbHVlX2NvdW50c19zYW1lID09IG1heF9jb3VudF9zYW1lCnVuaXF1ZV92YWx1ZXNfc2FtZSA8LSBuYW1lcyh2YWx1ZV9jb3VudHNfc2FtZSkKcmVzdWx0X3NhbWUgPC0gdW5pcXVlX3ZhbHVlc19zYW1lW2luZGV4X3NhbWVdCmBgYAoKYGBge3J9CnZhbHVlX2NvdW50c19zYW1lCmBgYAoKYGBge3J9CnJlc3VsdF9zYW1lCmBgYAoKYGBge3J9Cmxlbmd0aCh2YWx1ZV9jb3VudHNfc2FtZSkgPT0gbGVuZ3RoKHJlc3VsdF9zYW1lKQpgYGAKCkFzIHlvdSBjYW4gc2VlLCB3aGVuZXZlciBlYWNoIHZhbHVlIGFwcGVhcnMgdGhlIHNhbWUgbnVtYmVyIG9mIHRpbWVzIChpbiB0aGlzIGNhc2Ugb25lIHRpbWUgZWFjaCkgdGhlIGxlbmd0aCBvZiAidmFsdWVfY291bnRzIiBhbmQgInJlc3VsdCIgd2lsbCBiZSBlcXVhbC4gSW4gdGhhdCBjYXNlIChpLmUuICJub19tb2RlIiBpcyBUUlVFKSwgd2Ugd2FudCB0byBvdmVyd3JpdGUgdGhlIHZhbHVlIG9mIHJlc3VsdCB0byBiZSBOQSAobWlzc2luZykuIEluIG90aGVyIHdvcmRzLCB3aGVuIGFsbCB2YWx1ZXMgYXBwZWFyIHRoZSBzYW1lIG5hbWUgb2YgdGltZXMsIHRoZXJlIGlzIG5vIG1vZGUgdmFsdWUgLS0gaXQgaXMgbWlzc2luZy4KCioqSGVyZSdzIHdoYXQgd2UgZGlkIGFib3ZlOioqCgoqIFdlIGJyb2tlIGRvd24gb3VyIGBtb2RlX3ZhbCgpYCBmdW5jdGlvbiBpbnRvIGl0cyBjb21wb25lbnQgcGFydHMuIFdlIHZpZXdlZCB3aGF0IGVhY2ggcGFydCBkb2VzIGFuZCBob3cgaXQgdWx0aW1hdGVseSBjb250cmlidXRlcyB0byBhIHdvcmtpbmcgZnVuY3Rpb24uIAoKKiBUaGlzIHZlcnNpb24gb2YgdGhlIGBtb2RlX3ZhbCgpYCBmdW5jdGlvbiB3YXMgZXNwZWNpYWxseSBsb25nIGFuIHZlcmJvc2UuIEkgZGlkIHRoaXMgaW50ZW50aW9uYWxseSB0byBoZWxwIG1ha2UgaXQgZWFzaWVyIHRvIHVuZGVyc3RhbmQgaG93IGl0IHdvcmtzLiBBbmQgaW4gdGhpcyBjYXNlLCB0aGF0IHJlYWxseSBpc24ndCBhIHByb2JsZW0uIEhvd2V2ZXIsIHlvdSBjYW4gdHJ5IHJld3JpdGluZyB0aGlzIGZ1bmN0aW9uIGluIGEgbW9yZSBzdWNjaW5jdCB3YXkgaWYgeW91IHdhbnQgdG8gY2hhbGxlbmdlIHlvdXJzZWxmLgoKIyBDb21wYXJlIG1lYW4sIG1lZGlhbiwgYW5kIG1vZGUKCjwhLS0gVGhpcyBpc24ndCBIT1cgdG8gZ2V0IHRoZSBtZWFuLiBUaGlzIGEgY29tcGFyaXNvbiBvZiB0aGUgbWVhbiBhbmQgdGhlIG1lZGlhbiAtIHRoZSBXSFkgLS0+CgpOb3cgdGhhdCB5b3Uga25vdyBob3cgdG8gY2FsY3VsYXRlIHRoZSBtZWFuLCBtZWRpYW4sIGFuZCBtb2RlLCBsZXQncyBjb21wYXJlIHRoZXNlIHRocmVlIG1lYXN1cmVzIG9mIGNlbnRyYWwgdGVuZGVuY3kuIFRoaXMgaXMgYSBnb29kIG9wcG9ydHVuaXR5IHRvIGRlbW9uc3RyYXRlIHNvbWUgb2YgdGhlIGRpZmZlcmVudCBjaGFyYWN0ZXJpc3RpY3Mgb2YgZWFjaCB0aGF0IHdlIHNwb2tlIGFib3V0IGVhcmxpZXIuCgpgYGB7cn0KaGVpZ2h0X2FuZF93ZWlnaHRfMjAgJT4lIAogIHN1bW1hcmlzZSgKICAgIG1pbl93ZWlnaHQgICAgPSBtaW4od3RfbGJzKSwKICAgIG1lYW5fd2VpZ2h0ICAgPSBtZWFuKHd0X2xicyksCiAgICBtZWRpYW5fd2VpZ2h0ID0gbWVkaWFuKHd0X2xicyksCiAgICBtb2RlX3dlaWdodCAgID0gbW9kZV92YWwod3RfbGJzKSAlPiUgYXMuZG91YmxlKCksCiAgICBtYXhfd2VpZ2h0ICAgID0gbWF4KHd0X2xicykKICApCmBgYAoKKipIZXJlJ3Mgd2hhdCB3ZSBkaWQgYWJvdmU6KioKCiogV2UgdXNlZCB0aGUgYG1lYW4oKWAgZnVuY3Rpb24sIGBtZWRpYW4oKWAgZnVuY3Rpb24sIGFuZCBvdXIgYG1vZGVfdmFsKClgIGZ1bmN0aW9uIGluc2lkZSBvZiBkcHlscidzIGBzdW1tYXJpc2UoKWAgZnVuY3Rpb24gdG8gZmluZCB0aGUgbWVhbiwgbWVkaWFuLCBhbmQgbW9kZSB2YWx1ZXMgb2YgdGhlIGNvbHVtbiAid3RfbGJzIiBpbiB0aGUgImhlaWdodF9hbmRfd2VpZ2h0XzIwIiBkYXRhIGZyYW1lLgoKKiBXZSBhbHNvIHVzZWQgdGhlIGBhcy5kb3VibGUoKWAgZnVuY3Rpb24gdG8gY29udmVydCB0aGUgdmFsdWUgcmV0dXJuZWQgYnkgYG1vZGVfdmFsKClgIC0tICIxNzYiIC0tIGZyb20gYSBjaGFyYWN0ZXIgc3RyaW5nIHRvIGEgbnVtZXJpYyBkb3VibGUuIFRoaXMgaXNuJ3Qgc3RyaWN0bHkgbmVjZXNzYXJ5LCBidXQgSSB0aGluayBpdCBsb29rcyBiZXR0ZXIuCgoqIEZpbmFsbHksIHdlIHVzZWQgYmFzZSBSJ3MgYG1pbigpYCBhbmQgYG1heCgpYCBmdW5jdGlvbnMgdG8gdmlldyB0aGUgbG93ZXN0IGFuZCBoaWdoZXN0IHdlaWdodHMgaW4gb3VyIHNhbXBsZS4gCgojIyBEYXRhIGNoZWNraW5nCgpEbyB5b3Ugc2VlIGFueSByZWQgZmxhZ3Mg8J+aqWFzIHlvdSBzY2FuIHRoZSByZXN1bHRzPyBEbyB5b3UgcmVhbGx5IHRoaW5rIGEgbWVhbiB3ZWlnaHQgb2YgMSwxMTMgcG91bmRzIHNvdW5kcyByZWFzb25hYmxlPyBUaGlzIHNob3VsZCBkZWZpbml0ZWx5IGJlIGEgcmVkIGZsYWcgZm9yIHlvdS4gTm93IG1vdmUgeW91ciBnYXplIHRocmVlIGNvbHVtbnMgdG8gdGhlIHJpZ2h0IGFuZCBub3RpY2UgdGhhdCB0aGUgbWF4aW11bSB2YWx1ZSBvZiB3ZWlnaHQgaXMgMTksMDAwIGxicyDigJMgYW4gaW1wb3NzaWJsZSB2YWx1ZSBmb3IgYSBzdHVkeSBpbiBodW1hbiBwb3B1bGF0aW9ucy4gSW4gdGhpcyBjYXNlIHRoZSByZWFsIHdlaWdodCB3YXMgc3VwcG9zZWQgdG8gYmUgMTkwIHBvdW5kcywgYnV0IHRoZSBwZXJzb24gZW50ZXJpbmcgdGhlIGRhdGEgYWNjaWRlbnRseSBnb3QgYSBsaXR0bGUgdHJpZ2dlci1oYXBweSB3aXRoIHRoZSB6ZXJvIGtleS4gVGhpcyBpcyBhbiBleGFtcGxlIG9mIHdoYXQgSSBtZWFudCB3aGVuIEkgc2FpZCAiV2UgY2FuIHVzZSBkZXNjcmlwdGl2ZSBhbmFseXNpcyB0byB1bmNvdmVyIGVycm9ycyBpbiBvdXIgZGF0YSIgaW4gdGhlIFtJbnRyb2R1Y3Rpb24gdG8gRGVzY3JpcHRpdmUgQW5hbHlzaXMgbGVzc29uXSgwMF9pbnRyb2R1Y3Rpb24ubmIuaHRtbCkuIE9mdGVuIHRpbWVzLCBmb3IgdmFyaW91cyByZWFzb25zLCBzb21lIG9ic2VydmF0aW9ucyBmb3IgYSBnaXZlbiB2YXJpYWJsZSB0YWtlIG9uIHZhbHVlcyB0aGF0IGRvbuKAmXQgbWFrZSBzZW5zZS4gU3RhcnRpbmcgYnkgY2FsY3VsYXRpbmcgc29tZSBiYXNpYyBkZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIGZvciBlYWNoIHZhcmlhYmxlIGlzIG9uZSBhcHByb2FjaCB5b3UgY2FuIHVzZSB0byB0cnkgdG8gZmlndXJlIG91dCBpZiB5b3UgaGF2ZSB2YWx1ZXMgaW4geW91ciBkYXRhIHRoYXQgZG9u4oCZdCBtYWtlIHNlbnNlLgoKSW4gdGhpcyBjYXNlIHdlIGNhbiBqdXN0IGdvIGJhY2sgYW5kIGZpeCBvdXIgZGF0YSwgYnV0IHdoYXQgaWYgd2UgZGlkbuKAmXQga25vdyB0aGlzIHZhbHVlIHdhcyBhbiBlcnJvcj8gV2hhdCBpZiBpdCB3ZXJlIGEgdmFsdWUgdGhhdCB3YXMgdGVjaG5pY2FsbHkgcG9zc2libGUsIGJ1dCB2ZXJ5IHVubGlrZWx5PyBXZWxsLCB3ZSBjYW7igJl0IGp1c3QgZ28gY2hhbmdpbmcgdmFsdWVzIGluIG91ciBkYXRhLiBJdOKAmXMgdW5ldGhpY2FsLCBhbmQgaW4gc29tZSBjYXNlcyBpbGxlZ2FsLiBCZWxvdywgd2UgZGlzY3VzcyB0aGUgaG93IHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBtZWRpYW4gYW5kIG1vZGUgY2FuIGNvbWUgaW4gaGFuZHkgaW4gc2l0dWF0aW9ucyBzdWNoIGFzIHRoaXMuCgojIyBQcm9wZXJ0aWVzIG9mIG1lYW4sIG1lZGlhbiwgYW5kIG1vZGUgCgpEZXNwaXRlIHRoZSBmYWN0IHRoYXQgdGhpcyBpbXBvc3NpYmx5IGV4dHJlbWUgdmFsdWUgaXMgaW4gb3VyIGRhdGEsIHRoZSBtZWRpYW4gYW5kIG1vZGUgZXN0aW1hdGVzIGFyZSByZWFzb25hYmxlIGVzdGltYXRlcyBvZiB0aGUgYXZlcmFnZSBwZXJzb27igJlzIHdlaWdodCBpbiB0aGlzIHNhbXBsZS4gVGhpcyBpcyB3aGF0IEkgbWVhbnQgd2hlbiBJIHNhaWQgdGhhdCB0aGUgbWVkaWFuIGFuZCBtb2RlIHdlcmUgbW9yZSDigJxyZXNpc3RhbnQgdG8gZXh0cmVtZSB2YWx1ZXPigJ0gdGhhbiB0aGUgbWVhbi4gCgpZb3UgbWF5IGFsc28gbm90aWNlIHRoYXQgbm8gcGVyc29uIGluIG91ciBzYW1wbGUgaGFkIGFuIGFjdHVhbCB3ZWlnaHQgb2YgMSwxMTIuNzUgKHRoZSBtZWFuKSBvciBldmVuIDE3Ni41ICh0aGUgbWVkaWFuKS4gVGhpcyBpcyB3aGF0IEkgbWVhbnQgYWJvdmUgd2hlbiBJIHNhaWQgdGhhdCB0aGUgbWVhbiBhbmQgbWVkaWFuIHZhbHVlcyBhcmUg4oCcbm90IG5lY2Vzc2FyaWx5IG9ic2VydmVkIGluIHRoZSBkYXRhLuKAnQoKSW4gdGhpcyBjYXNlLCB0aGUgbW9kZSB2YWx1ZSAoMTc2KSBpcyBhbHNvIGEgbW9yZSByZWFzb25hYmxlIGVzdGltYXRlIG9mIHRoZSBhdmVyYWdlIHBlcnNvbidzIHdlaWdodCB0aGFuIHRoZSBtZWFuLiBBbmQgdW5saWtlIHRoZSBtZWFuIGFuZCB0aGUgbWVkaWFuLCBwYXJ0aWNpcGFudHMgMTggYW5kIDE5IGFjdHVhbGx5IHdlaWdoIDE3NiBwb3VuZHMuIEknbSBfX25vdF9fIHNheWluZyB0aGF0IHRoZSBtb2RlIGlzIGFsd2F5cyB0aGUgYmVzdCBtZWFzdXJlIG9mIGNlbnRyYWwgdGVuZGVuY3kgdG8gdXNlLiBJIF9fYW1fXyBzYXlpbmcgdGhhdCB5b3UgY2FuIG9mdGVuIGxlYXJuIHVzZWZ1bCBpbmZvcm1hdGlvbiBmcm9tIHlvdXIgZGF0YSBieSBjYWxjdWxhdGluZyBhbmQgY29tcGFyaW5nIHRoZXNlIHJlbGF0aXZlbHkgc2ltcGxlIGRlc2NyaXB0aXZlIHN0YXRpc3RpY3Mgb24gZWFjaCBvZiB5b3VyIG51bWVyaWMgdmFyaWFibGVzLgo=