Mean in R

1.Introduction

Finding the center of a dataset is one of the most common ways to summarize statistical findings. Often, people communicate the center of data using words like, on average, usually, or often.

In this lesson, you will learn how to calculate the mean of a dataset, a common measure of a dataset’s center. We will use the mean to help us answer the question,

When are adults their most creative and productive?

You could define “creative” and “productive” in a lot of ways, making this question impossible to fully answer by the end of this lesson. However, you will form an informed opinion on the question using data of the one hundred greatest novels of all time.

We collected the dataset from a survey administered by the French literary magazine, Le Monde. From the dataset, you will calculate the average age of the authors when their books were published.

Instructions

The histogram to the right displays the ages of 100 authors from the Le Monde survey. Where do you think the data is centered?

# load libraries
library(readr)
library(dplyr)
library(ggplot2)

# load data frame
greatest_books <- read_csv('top-hundred-books.csv')



#plot data
hist <- qplot(greatest_books$Ages,
      geom='histogram',
      binwidth = 3,  
      main = 'Age of Top 100 Novel Authors at Publication', 
      xlab = 'Publication Age',
      ylab = 'Count',
      fill=I("blue"), 
      col=I("red"), 
      alpha=I(.2)) 

hist

2.Calculating Mean

The mean, often referred to as the average, is a way to measure the center of a dataset.

The average of a set is calculated using a two-step process:

1.Add all of the observations in your dataset.

2.Divide the total sum from step one by the number of points in your dataset.

knitr::include_graphics("C:/Users/kuoan/Desktop/R Code/Mean1.png")

Example

Imagine that we wanted to calculate average of a dataset with the following four observations:

data <- c(4, 6, 2, 8)

Step One: Calculate the total

4+6+2+8=20

Step Two: Divide by the number of observations

The total is equal to 20, and the number of observations is equal to 4.

20 / 4 = 5

The average of this dataset is equal to 5.

Instructions

1.In this exercise, you will use R to find the average age of the first four authors in Le Monde’s top 100 books.

29,49,42,43

Add the values together, and set total equal to the answer. Print total.

total <- sum(29, 49, 42, 43)
print(total)
[1] 163

2.Divide total by the number of values in the dataset, and set mean_value to the answer.

Print mean_value. Keep that number in your head as you progress through the lesson.

mean_value <- total / 4
print(mean_value)
[1] 40.75

3.Mean in R

While you’ve shown that you can calculate the average yourself, it becomes time-consuming as the size of your dataset increases — imagine adding all of the numbers in a dataset with 10,000 observations.

The R mean() function can do the work of adding and dividing for you. In the example below, we use mean() to calculate the average of a dataset with ten values:

example_data <- c(24, 16, 30, 10, 12, 28, 38, 2, 4, 36)

example_average <- mean(example_data)

print(example_average)
[1] 20

The code above calculates the average of example_data and saves the value to example_average. The resulting average of this array is 20.

Instructions

1.Use R to calculate the average value of the author_ages array. Save the result to average_age and print it.

Does the average age of the authors surprise you? If so, how? Is it older, or younger than you expected?

# Set author ages to a vector
author_ages <- greatest_books$Ages

# Use R to calculate mean
average_age <- mean(author_ages)
average_age
[1] 41.83

4.Review and Discussion

In this lesson, you learned how to calculate the average of a dataset using the formula:

knitr::include_graphics("C:/Users/kuoan/Desktop/R Code/Mean1.png")

and the R function:

mean(my_data)

Circling back to the original question, do you feel like the average of our dataset, 42.12, provides us enough information to claim when someone is their most creative and productive?

Take a look at the histogram and mean (in red) to the right as you consider this question.

We would say, No. Though we could argue against its use for a few reasons, below, we’ve highlighted two:

1.The date of publication is not necessarily an author’s most creative year. When did they start authoring the book? What factors impacted their writing during those years?

2.The average age of the publishing dates for 100 authors may not accurately measure peak creativity in other professions. The average age of painters or sculptors may be very different.

So, what kind of information does the average provide us, and why would we use the average to describe something when we could display a histogram?

The most important outcome is that we’re able to use a single number as a measure of centrality. Although histograms provide more information, they are not a concise or precise measure of centrality — the reader must interpret it for themselves.

Instructions

Take a look at the histogram. Are you older or younger than the average age at publication?

This doesn’t tell you much about when someone will have their most creative year. However, this type of data could be used as an example in a broader study on aging.

#plot data
hist <- qplot(greatest_books$Ages,
      geom='histogram',
      binwidth = 3,  
      main = 'Age of Top 100 Novel Authors at Publication', 
      xlab = 'Publication Age',
      ylab = 'Count',
      fill=I("blue"), 
      col=I("black"), 
      alpha=I(.2)) +
  geom_vline(aes(xintercept=mean(greatest_books$Ages),
                 color="mean"), linetype="solid",
             size=1) +
  scale_color_manual(name = "statistics", values = c(mean = "red"))

hist

Median in R

1.Introduction

In this lesson, you will learn how to find the median of a dataset — a common measure of a dataset’s center. Each of the next three exercises will cover the following topics:

1.Manually finding the median of a dataset

2.Using R’s median function to find the median of a dataset

3.Interpreting what it means for a dataset to have similar and different median and mean values

In the lesson, we will use a dataset of the 100 greatest novels, determined by a French literary magazine, Le Monde. From the dataset, you will use the median to answer the question:

When are great authors most likely to publish their best work?

If you are not familiar with mean, also known as average, we recommend that you learn about it in our lesson on average.

Instructions

The histogram to the right displays the age of authors, at publication, for the top 100 novels. The red line represents the average value of this dataset.

You can think of the median as being the observation in your dataset that falls right in the middle.

Using this informal definition of the median and the graph to the right, see if you can determine whether the median of this dataset falls to the right or the left of the mean. We will show you the correct answer in the last exercise.

#plot data
hist <- qplot(greatest_books$Ages,
      geom='histogram',
      binwidth = 3,  
      main = 'Age of Top 100 Novel Authors at Publication', 
      xlab = 'Publication Age',
      ylab = 'Count',
      fill=I("blue"), 
      col=I("black"), 
      alpha=I(.2)) +
  geom_vline( aes(xintercept=mean(greatest_books$Ages),color="mean"), linetype="solid",size=1) +
  scale_color_manual(name = "statistics", values = c(mean = "red"))

hist

2.Median

The formal definition for the median of a dataset is:

The value that, assuming the dataset is ordered from smallest to largest, falls in the middle. If there are an even number of values in a dataset, you either report both of the middle two values or their average.

There are always two steps to finding the median of a dataset:

1.Order the values in the dataset from smallest to largest

2.Identify the number(s) that fall(s) in the middle

Example One: Even Number of Values

Say we have a dataset with the following ten numbers:

24, 16, 30, 10, 12, 28, 38, 2, 4, 36

The first step is to order these numbers from smallest to largest:

2, 4, 10, 12, [16, 24], 28, 30, 36, 38

Because this dataset has an even number of values, there are two medians: 16 and 24 — 16 has four datapoints to the left, and 24 has four datapoints to the right.

Although you can report both values as the median, people often average them. If you averaged 16 and 24, you could report the median as 20.

Example Two: Odd Number of Values

If we added another value (say, 24) to the dataset and sorted it, we would have:

2, 4, 10, 12, 16, [24], 24, 28, 30, 36, 38

The new median is equal to 24, because there are 5 values to the left of it, and 5 values to the right of it.

Instructions

1.In the next two steps, you will manually sort an array, and then determine which value in the array is the median.

In notebook.Rmd, we have a vector with the ages of the first five authors from Le Monde’s survey:

29,49,42,43,32

Under five_author_ages there is a variable called sorted_author_ages. Change the 0s in sorted_author_ages to the values in ascending order from five_author_ages.

# Array of the first five author ages
five_author_ages <- c(29, 49, 42, 43, 32)

# Fill in the empty array with the values sorted
sorted_author_ages <- sort(five_author_ages)

sorted_author_ages
[1] 29 32 42 43 49

2.Set median_value equal to the median of the array.

# Save the median value to median_value
median_value <- 42

# Print the sorted array and median value
cat("The sorted array is:", sorted_author_ages, '\n')
The sorted array is: 29 32 42 43 49 
cat(paste("The median of the array is: ", median_value))
The median of the array is:  42

*關於 cat():

cat() 是 “concatenate and print” 的意思,用來將字串和變數輸出成一行文字;

它不像 print() 會自動換行,所以建議你手動加入 ;

如果你用 cat(paste(…)),那麼 paste() 會先組合成一整句,再輸出;

cat() 不會回傳值,也無法直接複製回 RStudio 物件,僅用於輸出文字。

*在 R 中,paste() 是一個用來將多個字串合併成一個字串的函數。它常用於產生動態文字、報告輸出等情境。

name <- "Annabel"
age <- 18

paste("My name is", name, "and I am", age, "years old.")
[1] "My name is Annabel and I am 18 years old."
# 輸出: "My name is Annabel and I am 18 years old."

3.Median in R

Finding the median of a dataset becomes increasingly time-consuming as the size of your dataset increases — imagine finding the median of an unsorted dataset with 10,000 observations.

The R median() function can do the work of sorting, then finding the median for you. In the example below, we use median() to calculate the median of a dataset with ten values:

example_data = c(24, 16, 30, 10, 12, 28, 38, 2, 4, 36, 42)

example_median = median(example_data)

print(example_median)
[1] 24

The code above prints the median of the dataset, 24. The mean of this dataset is 22. It’s worth noting these two values are close to one another, but not equal.

Instructions

1.Use R to find the median of the author_ages array. Save the result to median_age.

Does the median age of the authors surprise you? If so, how? Is it older, or younger than you expected?

# Save author ages to author_ages
author_ages <- greatest_books$Ages

# Use R to calculate the median age of the top 100 authors
median_age <- median(author_ages)

print(paste("The median age of the 100 greatest authors, according to a survey by Le Monde is: " , median_age))
[1] "The median age of the 100 greatest authors, according to a survey by Le Monde is:  41"

4.Review and Discussion

In this lesson, you learned how to find the median of a dataset in two steps:

1.Sort the dataset

2.Identify the one or two numbers that fall in the middle of the sorted dataset

You also learned how to calculate the median using R:

median(my_data)

Discussion

Take a look at the histogram. It displays the author age distribution with vertical lines for the mean (red) and median (blue).

Do you feel like the median of our dataset, 40.5, provides us enough information to claim when authors publish their greatest work?

We argue it does not.

Although the median is a good measure of the dataset’s center, we cannot make a definitive claim about when authors publish their greatest work — the youngest author published at 18 and the oldest at 76. It would be irresponsible to say anything but, “it seems to be possible at almost any age.”

Notice that the mean and the median are nearly equal. This is not a surprising result, as both statistics are a measure of the dataset’s center. However, it’s worth noting that these results will not always be so close.

In the instructions below, we’ve written a brief explanation that puts median in the context of our problem.

#plot data
hist <- qplot(greatest_books$Ages,
      geom='histogram',
      binwidth = 3,  
      main = 'Age of Top 100 Novel Authors at Publication', 
      xlab = 'Publication Age',
      ylab = 'Count',
      fill=I("blue"), 
      col=I("black"), 
      alpha=I(.2)) +
  geom_vline(aes(xintercept=median(greatest_books$Ages),
                 color="median"), linetype="dashed",
             size=1) +
  geom_vline(aes(xintercept=mean(greatest_books$Ages),
                 color="mean"), linetype="solid",
             size=1) +
  scale_color_manual(name = "statistics", values = c(median = "blue", mean = "green"))

hist

Instructions

The median age of authors, when they publish their best work, from Le Monde’s 100 greatest books is 41.

While this does not tell us much about which year is an author’s greatest year, it does indicate that half of the authors from the survey find their greatest success before the age of 41 and half find their greatest success after the age of 41.

Mode in R (眾數)

1.Introduction

In this lesson, you will learn how to find the mode of a dataset. Each of the next three exercises will cover the following:

1.Manually finding the mode of a dataset

2.Using R’s functions to find the mode

3.Comparing mode to mean and median values

In the lesson, we will use a dataset of the 100 greatest novels, determined by a French literary magazine, Le Monde. From the dataset, you will use the mode to answer the question:

What is the most common age for a great author to publish their best work?

If you are not familiar with mean, also known as average, or median, we recommend that you learn about it in our lessons on average and median.

Instructions

The histogram to the right displays the age of authors, at publication, for the top 100 novels from Le Monde’s survey. The red line is the mean age, and the blue line is the median age.

Use the definition of mode below and the histogram to the right to guess where the mode falls. You will calculate the correct answer in the last exercise.

The mode is the most common observation in a dataset.

You will not be able to find the exact mode, because the histogram displays bins with a range of values. However, you can guess a range of values where you are most likely to see the mode.

#plot data
hist <- qplot(greatest_books$Ages,
      geom='histogram',
      binwidth = 3,  
      main = 'Age of Top 100 Novel Authors at Publication', 
      xlab = 'Publication Age',
      ylab = 'Count',
      fill=I("blue"), 
      col=I("black"), 
      alpha=I(.2)) +
  geom_vline(aes(xintercept=median(greatest_books$Ages),
                 color="median"), linetype="dashed",
             size=1) +
  geom_vline(aes(xintercept=mean(greatest_books$Ages),
                 color="mean"), linetype="solid",
             size=1) +
  scale_color_manual(name = "statistics", values = c(median = "blue", mean = "red"))

hist

2.Mode

The formal definition for the mode of a dataset is:

The most frequently occurring observation in the dataset. A dataset can have multiple modes if there is more than one value with the same maximum frequency.

While you may be able to find the mode of a small dataset by simply looking through it, if you have trouble, we recommend you follow these two steps:

1.Find the frequency of every unique number in the dataset

2.Determine which number has the highest frequency

Example

Say we have a dataset with the following ten numbers:

24, 16, 12, 10, 12, 28, 38, 12, 28, 24

Let’s find the frequency of each number:

24 16 12 10 28 38

2 1 3 1 2 1

From the table, we can see that our mode is 12, the most frequent number in our dataset.

Instructions

1.Determine the mode of the ages for the first ten authors in the Le Monde survey:

29,49,42,43,32,38,37,41,27,27

Save the value to mode_age.

mode_age <- 27
mode_age
[1] 27

2.Determine the number of authors who were the age of the mode. Save the number to mode_count.

mode_count <- 2
mode_count
[1] 2

3.Mode with DescTools

Finding the mode of a dataset becomes increasingly time-consuming as the size of your dataset increases — imagine finding the mode of a dataset with 10,000 observations.

The R package DescTools includes a handy Mode() function which can do the work of finding the mode for us. In the example below, we use Mode() to calculate the mode of a dataset with ten values:

Example: One Mode

library(DescTools)

example_data <- c(24, 16, 12, 10, 12, 28, 38, 12, 28, 24)

example_mode <- Mode(example_data)

The code above calculates the mode of the values in example_data and saves it to example_mode.

The result of Mode() is a vector with the mode value:

example_mode
[1] 12
attr(,"freq")
[1] 3

Example: Two Modes

If there are multiple modes, the Mode() function will return them as a vector.

Let’s look at a vector with two modes, 12 and 24:

example_data = c(24, 16, 12, 10, 12, 24, 38, 12, 28, 24)

example_mode = Mode(example_data)

The result is:

example_mode
[1] 12 24
attr(,"freq")
[1] 3

Instructions

1.We have already imported the DescTools library for you.

Delete the current value set to mode_age.

Find the mode of the observations in the author_ages array. Save the result to mode_age.

# Set author ages to 
author_ages <- greatest_books$Ages

mode_age <- Mode(author_ages)

print(paste("The mode age of authors from Le Monde's 100 greatest books is: ", mode_age[1]))
[1] "The mode age of authors from Le Monde's 100 greatest books is:  38"

4.Review and Discussion

In this lesson, you learned how to find the mode of a dataset in two steps:

1.Find the frequency of every unique number in the dataset

2.Determine which number has the highest frequency

You also learned how to calculate the mode using DescTools:

Mode(my_array)

Discussion

In this lesson, you found that 38 was the most common age, at publication, for an author from the Le Monde survey. How does this number compare to your guess from the beginning of the lesson?

The mode is close to the median and mean of the dataset, but it is not in the tallest bucket. This should not be surprising, as the histogram indicates the data is centered between the ages of 30 and 50 — there is a higher chance of a mode in that range than outside of it.

The mode is not always this close to the median and mean, and often will not be in the tallest bucket.

Look at the 25-30 year-old bin. There are nine observations in it. If all the values in that bin happened to be 27, then the dataset’s mode would be 27. Although unlikely, it is possible. Below, we show what this would look like:

knitr::include_graphics("C:/Users/kuoan/Desktop/R Code/Mean2.png")

Based on this graph, it is fair to say the mode may not always be a great measure of where the data is centered. Simply put, mode is a measure of the most frequent observation in the dataset, and is not an indication of the tallest bin in a histogram.

In the instructions below, we’ve written a brief explanation that puts mode in the context of our problem.

Instructions

#plot data
hist <- qplot(greatest_books$Ages,
      geom='histogram',
      binwidth = 3,  
      main = 'Age of Top 100 Novel Authors at Publication', 
      xlab = 'Publication Age',
      ylab = 'Count',
      fill=I("blue"), 
      col=I("black"), 
      alpha=I(.2)) +
  geom_vline(aes(xintercept=median(greatest_books$Ages),
                 color="median"), linetype="dashed",
             size=1) +
  geom_vline(aes(xintercept=mean(greatest_books$Ages),
                 color="mean"), linetype="solid",
             size=1) +
  geom_vline(aes(xintercept=38,
                 color="mode"), linetype="solid",
             size=1) +
  scale_color_manual(name = "statistics", values = c(median = "blue", mean = "red", mode="green"))

hist

LS0tDQp0aXRsZTogIkxlYXJuIFI6IE1lYW4sIE1lZGlhbiwgYW5kIE1vZGUiDQphdXRob3I6ICJBbm5hYmVsIEt1byINCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVZLSVtLSVkICVIOiVNJylgIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KIyBNZWFuIGluIFINCiMgMS5JbnRyb2R1Y3Rpb24NCg0KRmluZGluZyB0aGUgY2VudGVyIG9mIGEgZGF0YXNldCBpcyBvbmUgb2YgdGhlIG1vc3QgY29tbW9uIHdheXMgdG8gc3VtbWFyaXplIHN0YXRpc3RpY2FsIGZpbmRpbmdzLiBPZnRlbiwgcGVvcGxlIGNvbW11bmljYXRlIHRoZSBjZW50ZXIgb2YgZGF0YSB1c2luZyB3b3JkcyBsaWtlLCBvbiBhdmVyYWdlLCB1c3VhbGx5LCBvciBvZnRlbi4NCg0KSW4gdGhpcyBsZXNzb24sIHlvdSB3aWxsIGxlYXJuIGhvdyB0byBjYWxjdWxhdGUgdGhlIG1lYW4gb2YgYSBkYXRhc2V0LCBhIGNvbW1vbiBtZWFzdXJlIG9mIGEgZGF0YXNldOKAmXMgY2VudGVyLiBXZSB3aWxsIHVzZSB0aGUgbWVhbiB0byBoZWxwIHVzIGFuc3dlciB0aGUgcXVlc3Rpb24sDQoNCldoZW4gYXJlIGFkdWx0cyB0aGVpciBtb3N0IGNyZWF0aXZlIGFuZCBwcm9kdWN0aXZlPw0KDQpZb3UgY291bGQgZGVmaW5lIOKAnGNyZWF0aXZl4oCdIGFuZCDigJxwcm9kdWN0aXZl4oCdIGluIGEgbG90IG9mIHdheXMsIG1ha2luZyB0aGlzIHF1ZXN0aW9uIGltcG9zc2libGUgdG8gZnVsbHkgYW5zd2VyIGJ5IHRoZSBlbmQgb2YgdGhpcyBsZXNzb24uIEhvd2V2ZXIsIHlvdSB3aWxsIGZvcm0gYW4gaW5mb3JtZWQgb3BpbmlvbiBvbiB0aGUgcXVlc3Rpb24gdXNpbmcgZGF0YSBvZiB0aGUgb25lIGh1bmRyZWQgZ3JlYXRlc3Qgbm92ZWxzIG9mIGFsbCB0aW1lLg0KDQpXZSBjb2xsZWN0ZWQgdGhlIGRhdGFzZXQgZnJvbSBhIHN1cnZleSBhZG1pbmlzdGVyZWQgYnkgdGhlIEZyZW5jaCBsaXRlcmFyeSBtYWdhemluZSwgTGUgTW9uZGUuIEZyb20gdGhlIGRhdGFzZXQsIHlvdSB3aWxsIGNhbGN1bGF0ZSB0aGUgYXZlcmFnZSBhZ2Ugb2YgdGhlIGF1dGhvcnMgd2hlbiB0aGVpciBib29rcyB3ZXJlIHB1Ymxpc2hlZC4NCg0KIyMgSW5zdHJ1Y3Rpb25zDQoNClRoZSBoaXN0b2dyYW0gdG8gdGhlIHJpZ2h0IGRpc3BsYXlzIHRoZSBhZ2VzIG9mIDEwMCBhdXRob3JzIGZyb20gdGhlIExlIE1vbmRlIHN1cnZleS4gV2hlcmUgZG8geW91IHRoaW5rIHRoZSBkYXRhIGlzIGNlbnRlcmVkPw0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBsb2FkIGxpYnJhcmllcw0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQoNCiMgbG9hZCBkYXRhIGZyYW1lDQpncmVhdGVzdF9ib29rcyA8LSByZWFkX2NzdigndG9wLWh1bmRyZWQtYm9va3MuY3N2JykNCg0KDQoNCiNwbG90IGRhdGENCmhpc3QgPC0gcXBsb3QoZ3JlYXRlc3RfYm9va3MkQWdlcywNCiAgICAgIGdlb209J2hpc3RvZ3JhbScsDQogICAgICBiaW53aWR0aCA9IDMsICANCiAgICAgIG1haW4gPSAnQWdlIG9mIFRvcCAxMDAgTm92ZWwgQXV0aG9ycyBhdCBQdWJsaWNhdGlvbicsIA0KICAgICAgeGxhYiA9ICdQdWJsaWNhdGlvbiBBZ2UnLA0KICAgICAgeWxhYiA9ICdDb3VudCcsDQogICAgICBmaWxsPUkoImJsdWUiKSwgDQogICAgICBjb2w9SSgicmVkIiksIA0KICAgICAgYWxwaGE9SSguMikpIA0KDQpoaXN0DQpgYGANCg0KIyAyLkNhbGN1bGF0aW5nIE1lYW4NCg0KVGhlIG1lYW4sIG9mdGVuIHJlZmVycmVkIHRvIGFzIHRoZSBhdmVyYWdlLCBpcyBhIHdheSB0byBtZWFzdXJlIHRoZSBjZW50ZXIgb2YgYSBkYXRhc2V0Lg0KDQpUaGUgYXZlcmFnZSBvZiBhIHNldCBpcyBjYWxjdWxhdGVkIHVzaW5nIGEgdHdvLXN0ZXAgcHJvY2VzczoNCg0KMS5BZGQgYWxsIG9mIHRoZSBvYnNlcnZhdGlvbnMgaW4geW91ciBkYXRhc2V0Lg0KDQoyLkRpdmlkZSB0aGUgdG90YWwgc3VtIGZyb20gc3RlcCBvbmUgYnkgdGhlIG51bWJlciBvZiBwb2ludHMgaW4geW91ciBkYXRhc2V0Lg0KDQpgYGB7ciBNZWFuMSwgb3V0LndpZHRoPSI2MCUifQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIkM6L1VzZXJzL2t1b2FuL0Rlc2t0b3AvUiBDb2RlL01lYW4xLnBuZyIpDQpgYGANCiMjIEV4YW1wbGUNCg0KSW1hZ2luZSB0aGF0IHdlIHdhbnRlZCB0byBjYWxjdWxhdGUgYXZlcmFnZSBvZiBhIGRhdGFzZXQgd2l0aCB0aGUgZm9sbG93aW5nIGZvdXIgb2JzZXJ2YXRpb25zOg0KYGBge3J9DQpkYXRhIDwtIGMoNCwgNiwgMiwgOCkNCmBgYA0KDQojIyMgU3RlcCBPbmU6IENhbGN1bGF0ZSB0aGUgdG90YWwNCg0KNCs2KzIrOD0yMA0KDQojIyMgU3RlcCBUd286IERpdmlkZSBieSB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucw0KDQpUaGUgdG90YWwgaXMgZXF1YWwgdG8gMjAsIGFuZCB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBpcyBlcXVhbCB0byA0Lg0KDQoyMCAvIDQgPSA1DQoNClRoZSBhdmVyYWdlIG9mIHRoaXMgZGF0YXNldCBpcyBlcXVhbCB0byA1Lg0KDQojIyBJbnN0cnVjdGlvbnMNCg0KMS5JbiB0aGlzIGV4ZXJjaXNlLCB5b3Ugd2lsbCB1c2UgUiB0byBmaW5kIHRoZSBhdmVyYWdlIGFnZSBvZiB0aGUgZmlyc3QgZm91ciBhdXRob3JzIGluIExlIE1vbmRl4oCZcyB0b3AgMTAwIGJvb2tzLg0KDQoyOSw0OSw0Miw0Mw0KDQpBZGQgdGhlIHZhbHVlcyB0b2dldGhlciwgYW5kIHNldCB0b3RhbCBlcXVhbCB0byB0aGUgYW5zd2VyLiBQcmludCB0b3RhbC4NCg0KYGBge3J9DQp0b3RhbCA8LSBzdW0oMjksIDQ5LCA0MiwgNDMpDQpwcmludCh0b3RhbCkNCmBgYA0KDQoyLkRpdmlkZSB0b3RhbCBieSB0aGUgbnVtYmVyIG9mIHZhbHVlcyBpbiB0aGUgZGF0YXNldCwgYW5kIHNldCBtZWFuX3ZhbHVlIHRvIHRoZSBhbnN3ZXIuDQoNClByaW50IG1lYW5fdmFsdWUuIEtlZXAgdGhhdCBudW1iZXIgaW4geW91ciBoZWFkIGFzIHlvdSBwcm9ncmVzcyB0aHJvdWdoIHRoZSBsZXNzb24uDQoNCmBgYHtyfQ0KbWVhbl92YWx1ZSA8LSB0b3RhbCAvIDQNCnByaW50KG1lYW5fdmFsdWUpDQpgYGANCg0KIyAzLk1lYW4gaW4gUg0KDQpXaGlsZSB5b3XigJl2ZSBzaG93biB0aGF0IHlvdSBjYW4gY2FsY3VsYXRlIHRoZSBhdmVyYWdlIHlvdXJzZWxmLCBpdCBiZWNvbWVzIHRpbWUtY29uc3VtaW5nIGFzIHRoZSBzaXplIG9mIHlvdXIgZGF0YXNldCBpbmNyZWFzZXMg4oCUIGltYWdpbmUgYWRkaW5nIGFsbCBvZiB0aGUgbnVtYmVycyBpbiBhIGRhdGFzZXQgd2l0aCAxMCwwMDAgb2JzZXJ2YXRpb25zLg0KDQpUaGUgUiBtZWFuKCkgZnVuY3Rpb24gY2FuIGRvIHRoZSB3b3JrIG9mIGFkZGluZyBhbmQgZGl2aWRpbmcgZm9yIHlvdS4gSW4gdGhlIGV4YW1wbGUgYmVsb3csIHdlIHVzZSBtZWFuKCkgdG8gY2FsY3VsYXRlIHRoZSBhdmVyYWdlIG9mIGEgZGF0YXNldCB3aXRoIHRlbiB2YWx1ZXM6DQoNCmBgYHtyfQ0KZXhhbXBsZV9kYXRhIDwtIGMoMjQsIDE2LCAzMCwgMTAsIDEyLCAyOCwgMzgsIDIsIDQsIDM2KQ0KDQpleGFtcGxlX2F2ZXJhZ2UgPC0gbWVhbihleGFtcGxlX2RhdGEpDQoNCnByaW50KGV4YW1wbGVfYXZlcmFnZSkNCg0KYGBgDQoNClRoZSBjb2RlIGFib3ZlIGNhbGN1bGF0ZXMgdGhlIGF2ZXJhZ2Ugb2YgZXhhbXBsZV9kYXRhIGFuZCBzYXZlcyB0aGUgdmFsdWUgdG8gZXhhbXBsZV9hdmVyYWdlLiBUaGUgcmVzdWx0aW5nIGF2ZXJhZ2Ugb2YgdGhpcyBhcnJheSBpcyAyMC4NCg0KIyMgSW5zdHJ1Y3Rpb25zDQoNCg0KMS5Vc2UgUiB0byBjYWxjdWxhdGUgdGhlIGF2ZXJhZ2UgdmFsdWUgb2YgdGhlIGF1dGhvcl9hZ2VzIGFycmF5LiBTYXZlIHRoZSByZXN1bHQgdG8gYXZlcmFnZV9hZ2UgYW5kIHByaW50IGl0Lg0KDQpEb2VzIHRoZSBhdmVyYWdlIGFnZSBvZiB0aGUgYXV0aG9ycyBzdXJwcmlzZSB5b3U/IElmIHNvLCBob3c/IElzIGl0IG9sZGVyLCBvciB5b3VuZ2VyIHRoYW4geW91IGV4cGVjdGVkPw0KDQpgYGB7cn0NCiMgU2V0IGF1dGhvciBhZ2VzIHRvIGEgdmVjdG9yDQphdXRob3JfYWdlcyA8LSBncmVhdGVzdF9ib29rcyRBZ2VzDQoNCiMgVXNlIFIgdG8gY2FsY3VsYXRlIG1lYW4NCmF2ZXJhZ2VfYWdlIDwtIG1lYW4oYXV0aG9yX2FnZXMpDQphdmVyYWdlX2FnZQ0KYGBgDQoNCiMgNC5SZXZpZXcgYW5kIERpc2N1c3Npb24NCg0KSW4gdGhpcyBsZXNzb24sIHlvdSBsZWFybmVkIGhvdyB0byBjYWxjdWxhdGUgdGhlIGF2ZXJhZ2Ugb2YgYSBkYXRhc2V0IHVzaW5nIHRoZSBmb3JtdWxhOg0KDQpgYGB7ciAsIG91dC53aWR0aD0iNjAlIn0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJDOi9Vc2Vycy9rdW9hbi9EZXNrdG9wL1IgQ29kZS9NZWFuMS5wbmciKQ0KYGBgDQoNCmFuZCB0aGUgUiBmdW5jdGlvbjoNCg0KbWVhbihteV9kYXRhKQ0KDQpDaXJjbGluZyBiYWNrIHRvIHRoZSBvcmlnaW5hbCBxdWVzdGlvbiwgZG8geW91IGZlZWwgbGlrZSB0aGUgYXZlcmFnZSBvZiBvdXIgZGF0YXNldCwgNDIuMTIsIHByb3ZpZGVzIHVzIGVub3VnaCBpbmZvcm1hdGlvbiB0byBjbGFpbSB3aGVuIHNvbWVvbmUgaXMgdGhlaXIgbW9zdCBjcmVhdGl2ZSBhbmQgcHJvZHVjdGl2ZT8NCg0KVGFrZSBhIGxvb2sgYXQgdGhlIGhpc3RvZ3JhbSBhbmQgbWVhbiAoaW4gcmVkKSB0byB0aGUgcmlnaHQgYXMgeW91IGNvbnNpZGVyIHRoaXMgcXVlc3Rpb24uDQoNCldlIHdvdWxkIHNheSwgTm8uIFRob3VnaCB3ZSBjb3VsZCBhcmd1ZSBhZ2FpbnN0IGl0cyB1c2UgZm9yIGEgZmV3IHJlYXNvbnMsIGJlbG93LCB3ZeKAmXZlIGhpZ2hsaWdodGVkIHR3bzoNCg0KMS5UaGUgZGF0ZSBvZiBwdWJsaWNhdGlvbiBpcyBub3QgbmVjZXNzYXJpbHkgYW4gYXV0aG9y4oCZcyBtb3N0IGNyZWF0aXZlIHllYXIuIFdoZW4gZGlkIHRoZXkgc3RhcnQgYXV0aG9yaW5nIHRoZSBib29rPyBXaGF0IGZhY3RvcnMgaW1wYWN0ZWQgdGhlaXIgd3JpdGluZyBkdXJpbmcgdGhvc2UgeWVhcnM/DQoNCjIuVGhlIGF2ZXJhZ2UgYWdlIG9mIHRoZSBwdWJsaXNoaW5nIGRhdGVzIGZvciAxMDAgYXV0aG9ycyBtYXkgbm90IGFjY3VyYXRlbHkgbWVhc3VyZSBwZWFrIGNyZWF0aXZpdHkgaW4gb3RoZXIgcHJvZmVzc2lvbnMuIFRoZSBhdmVyYWdlIGFnZSBvZiBwYWludGVycyBvciBzY3VscHRvcnMgbWF5IGJlIHZlcnkgZGlmZmVyZW50Lg0KDQpTbywgd2hhdCBraW5kIG9mIGluZm9ybWF0aW9uIGRvZXMgdGhlIGF2ZXJhZ2UgcHJvdmlkZSB1cywgYW5kIHdoeSB3b3VsZCB3ZSB1c2UgdGhlIGF2ZXJhZ2UgdG8gZGVzY3JpYmUgc29tZXRoaW5nIHdoZW4gd2UgY291bGQgZGlzcGxheSBhIGhpc3RvZ3JhbT8NCg0KVGhlIG1vc3QgaW1wb3J0YW50IG91dGNvbWUgaXMgdGhhdCB3ZeKAmXJlIGFibGUgdG8gdXNlIGEgc2luZ2xlIG51bWJlciBhcyBhIG1lYXN1cmUgb2YgY2VudHJhbGl0eS4gQWx0aG91Z2ggaGlzdG9ncmFtcyBwcm92aWRlIG1vcmUgaW5mb3JtYXRpb24sIHRoZXkgYXJlIG5vdCBhIGNvbmNpc2Ugb3IgcHJlY2lzZSBtZWFzdXJlIG9mIGNlbnRyYWxpdHkg4oCUIHRoZSByZWFkZXIgbXVzdCBpbnRlcnByZXQgaXQgZm9yIHRoZW1zZWx2ZXMuDQoNCiMjIEluc3RydWN0aW9ucw0KDQpUYWtlIGEgbG9vayBhdCB0aGUgaGlzdG9ncmFtLiBBcmUgeW91IG9sZGVyIG9yIHlvdW5nZXIgdGhhbiB0aGUgYXZlcmFnZSBhZ2UgYXQgcHVibGljYXRpb24/DQoNClRoaXMgZG9lc27igJl0IHRlbGwgeW91IG11Y2ggYWJvdXQgd2hlbiBzb21lb25lIHdpbGwgaGF2ZSB0aGVpciBtb3N0IGNyZWF0aXZlIHllYXIuIEhvd2V2ZXIsIHRoaXMgdHlwZSBvZiBkYXRhIGNvdWxkIGJlIHVzZWQgYXMgYW4gZXhhbXBsZSBpbiBhIGJyb2FkZXIgc3R1ZHkgb24gYWdpbmcuDQoNCmBgYHtyfQ0KI3Bsb3QgZGF0YQ0KaGlzdCA8LSBxcGxvdChncmVhdGVzdF9ib29rcyRBZ2VzLA0KICAgICAgZ2VvbT0naGlzdG9ncmFtJywNCiAgICAgIGJpbndpZHRoID0gMywgIA0KICAgICAgbWFpbiA9ICdBZ2Ugb2YgVG9wIDEwMCBOb3ZlbCBBdXRob3JzIGF0IFB1YmxpY2F0aW9uJywgDQogICAgICB4bGFiID0gJ1B1YmxpY2F0aW9uIEFnZScsDQogICAgICB5bGFiID0gJ0NvdW50JywNCiAgICAgIGZpbGw9SSgiYmx1ZSIpLCANCiAgICAgIGNvbD1JKCJibGFjayIpLCANCiAgICAgIGFscGhhPUkoLjIpKSArDQogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9bWVhbihncmVhdGVzdF9ib29rcyRBZ2VzKSwNCiAgICAgICAgICAgICAgICAgY29sb3I9Im1lYW4iKSwgbGluZXR5cGU9InNvbGlkIiwNCiAgICAgICAgICAgICBzaXplPTEpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAic3RhdGlzdGljcyIsIHZhbHVlcyA9IGMobWVhbiA9ICJyZWQiKSkNCg0KaGlzdA0KYGBgDQoNCiMgTWVkaWFuIGluIFINCiMgMS5JbnRyb2R1Y3Rpb24NCg0KSW4gdGhpcyBsZXNzb24sIHlvdSB3aWxsIGxlYXJuIGhvdyB0byBmaW5kIHRoZSBtZWRpYW4gb2YgYSBkYXRhc2V0IOKAlCBhIGNvbW1vbiBtZWFzdXJlIG9mIGEgZGF0YXNldOKAmXMgY2VudGVyLiBFYWNoIG9mIHRoZSBuZXh0IHRocmVlIGV4ZXJjaXNlcyB3aWxsIGNvdmVyIHRoZSBmb2xsb3dpbmcgdG9waWNzOg0KDQoxLk1hbnVhbGx5IGZpbmRpbmcgdGhlIG1lZGlhbiBvZiBhIGRhdGFzZXQNCg0KMi5Vc2luZyBS4oCZcyBtZWRpYW4gZnVuY3Rpb24gdG8gZmluZCB0aGUgbWVkaWFuIG9mIGEgZGF0YXNldA0KDQozLkludGVycHJldGluZyB3aGF0IGl0IG1lYW5zIGZvciBhIGRhdGFzZXQgdG8gaGF2ZSBzaW1pbGFyIGFuZCBkaWZmZXJlbnQgbWVkaWFuIGFuZCBtZWFuIHZhbHVlcw0KDQpJbiB0aGUgbGVzc29uLCB3ZSB3aWxsIHVzZSBhIGRhdGFzZXQgb2YgdGhlIDEwMCBncmVhdGVzdCBub3ZlbHMsIGRldGVybWluZWQgYnkgYSBGcmVuY2ggbGl0ZXJhcnkgbWFnYXppbmUsIExlIE1vbmRlLiBGcm9tIHRoZSBkYXRhc2V0LCB5b3Ugd2lsbCB1c2UgdGhlIG1lZGlhbiB0byBhbnN3ZXIgdGhlIHF1ZXN0aW9uOg0KDQpXaGVuIGFyZSBncmVhdCBhdXRob3JzIG1vc3QgbGlrZWx5IHRvIHB1Ymxpc2ggdGhlaXIgYmVzdCB3b3JrPw0KDQpJZiB5b3UgYXJlIG5vdCBmYW1pbGlhciB3aXRoIG1lYW4sIGFsc28ga25vd24gYXMgYXZlcmFnZSwgd2UgcmVjb21tZW5kIHRoYXQgeW91IGxlYXJuIGFib3V0IGl0IGluIG91ciBsZXNzb24gb24gYXZlcmFnZS4NCg0KIyMgSW5zdHJ1Y3Rpb25zDQoNClRoZSBoaXN0b2dyYW0gdG8gdGhlIHJpZ2h0IGRpc3BsYXlzIHRoZSBhZ2Ugb2YgYXV0aG9ycywgYXQgcHVibGljYXRpb24sIGZvciB0aGUgdG9wIDEwMCBub3ZlbHMuIFRoZSByZWQgbGluZSByZXByZXNlbnRzIHRoZSBhdmVyYWdlIHZhbHVlIG9mIHRoaXMgZGF0YXNldC4NCg0KWW91IGNhbiB0aGluayBvZiB0aGUgbWVkaWFuIGFzIGJlaW5nIHRoZSBvYnNlcnZhdGlvbiBpbiB5b3VyIGRhdGFzZXQgdGhhdCBmYWxscyByaWdodCBpbiB0aGUgbWlkZGxlLg0KDQpVc2luZyB0aGlzIGluZm9ybWFsIGRlZmluaXRpb24gb2YgdGhlIG1lZGlhbiBhbmQgdGhlIGdyYXBoIHRvIHRoZSByaWdodCwgc2VlIGlmIHlvdSBjYW4gZGV0ZXJtaW5lIHdoZXRoZXIgdGhlIG1lZGlhbiBvZiB0aGlzIGRhdGFzZXQgZmFsbHMgdG8gdGhlIHJpZ2h0IG9yIHRoZSBsZWZ0IG9mIHRoZSBtZWFuLiBXZSB3aWxsIHNob3cgeW91IHRoZSBjb3JyZWN0IGFuc3dlciBpbiB0aGUgbGFzdCBleGVyY2lzZS4NCg0KYGBge3J9DQojcGxvdCBkYXRhDQpoaXN0IDwtIHFwbG90KGdyZWF0ZXN0X2Jvb2tzJEFnZXMsDQogICAgICBnZW9tPSdoaXN0b2dyYW0nLA0KICAgICAgYmlud2lkdGggPSAzLCAgDQogICAgICBtYWluID0gJ0FnZSBvZiBUb3AgMTAwIE5vdmVsIEF1dGhvcnMgYXQgUHVibGljYXRpb24nLCANCiAgICAgIHhsYWIgPSAnUHVibGljYXRpb24gQWdlJywNCiAgICAgIHlsYWIgPSAnQ291bnQnLA0KICAgICAgZmlsbD1JKCJibHVlIiksIA0KICAgICAgY29sPUkoImJsYWNrIiksIA0KICAgICAgYWxwaGE9SSguMikpICsNCiAgZ2VvbV92bGluZSggYWVzKHhpbnRlcmNlcHQ9bWVhbihncmVhdGVzdF9ib29rcyRBZ2VzKSxjb2xvcj0ibWVhbiIpLCBsaW5ldHlwZT0ic29saWQiLHNpemU9MSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJzdGF0aXN0aWNzIiwgdmFsdWVzID0gYyhtZWFuID0gInJlZCIpKQ0KDQpoaXN0DQpgYGANCg0KIyAyLk1lZGlhbg0KDQpUaGUgZm9ybWFsIGRlZmluaXRpb24gZm9yIHRoZSBtZWRpYW4gb2YgYSBkYXRhc2V0IGlzOg0KDQpUaGUgdmFsdWUgdGhhdCwgYXNzdW1pbmcgdGhlIGRhdGFzZXQgaXMgb3JkZXJlZCBmcm9tIHNtYWxsZXN0IHRvIGxhcmdlc3QsIGZhbGxzIGluIHRoZSBtaWRkbGUuIElmIHRoZXJlIGFyZSBhbiBldmVuIG51bWJlciBvZiB2YWx1ZXMgaW4gYSBkYXRhc2V0LCB5b3UgZWl0aGVyIHJlcG9ydCBib3RoIG9mIHRoZSBtaWRkbGUgdHdvIHZhbHVlcyBvciB0aGVpciBhdmVyYWdlLg0KDQpUaGVyZSBhcmUgYWx3YXlzIHR3byBzdGVwcyB0byBmaW5kaW5nIHRoZSBtZWRpYW4gb2YgYSBkYXRhc2V0Og0KDQoxLk9yZGVyIHRoZSB2YWx1ZXMgaW4gdGhlIGRhdGFzZXQgZnJvbSBzbWFsbGVzdCB0byBsYXJnZXN0DQoNCjIuSWRlbnRpZnkgdGhlIG51bWJlcihzKSB0aGF0IGZhbGwocykgaW4gdGhlIG1pZGRsZQ0KDQojIyMgRXhhbXBsZSBPbmU6IEV2ZW4gTnVtYmVyIG9mIFZhbHVlcw0KDQpTYXkgd2UgaGF2ZSBhIGRhdGFzZXQgd2l0aCB0aGUgZm9sbG93aW5nIHRlbiBudW1iZXJzOg0KDQoyNCwgMTYsIDMwLCAxMCwgMTIsIDI4LCAzOCwgMiwgNCwgMzYNCg0KVGhlIGZpcnN0IHN0ZXAgaXMgdG8gb3JkZXIgdGhlc2UgbnVtYmVycyBmcm9tIHNtYWxsZXN0IHRvIGxhcmdlc3Q6DQoNCjIsIDQsIDEwLCAxMiwgWzE2LCAyNF0sIDI4LCAzMCwgMzYsIDM4DQoNCkJlY2F1c2UgdGhpcyBkYXRhc2V0IGhhcyBhbiBldmVuIG51bWJlciBvZiB2YWx1ZXMsIHRoZXJlIGFyZSB0d28gbWVkaWFuczogMTYgYW5kIDI0IOKAlCAxNiBoYXMgZm91ciBkYXRhcG9pbnRzIHRvIHRoZSBsZWZ0LCBhbmQgMjQgaGFzIGZvdXIgZGF0YXBvaW50cyB0byB0aGUgcmlnaHQuDQoNCkFsdGhvdWdoIHlvdSBjYW4gcmVwb3J0IGJvdGggdmFsdWVzIGFzIHRoZSBtZWRpYW4sIHBlb3BsZSBvZnRlbiBhdmVyYWdlIHRoZW0uIElmIHlvdSBhdmVyYWdlZCAxNiBhbmQgMjQsIHlvdSBjb3VsZCByZXBvcnQgdGhlIG1lZGlhbiBhcyAyMC4NCg0KIyMjIEV4YW1wbGUgVHdvOiBPZGQgTnVtYmVyIG9mIFZhbHVlcw0KDQpJZiB3ZSBhZGRlZCBhbm90aGVyIHZhbHVlIChzYXksIDI0KSB0byB0aGUgZGF0YXNldCBhbmQgc29ydGVkIGl0LCB3ZSB3b3VsZCBoYXZlOg0KDQoyLCA0LCAxMCwgMTIsIDE2LCBbMjRdLCAyNCwgMjgsIDMwLCAzNiwgMzgNCg0KVGhlIG5ldyBtZWRpYW4gaXMgZXF1YWwgdG8gMjQsIGJlY2F1c2UgdGhlcmUgYXJlIDUgdmFsdWVzIHRvIHRoZSBsZWZ0IG9mIGl0LCBhbmQgNSB2YWx1ZXMgdG8gdGhlIHJpZ2h0IG9mIGl0Lg0KDQojIyBJbnN0cnVjdGlvbnMNCg0KMS5JbiB0aGUgbmV4dCB0d28gc3RlcHMsIHlvdSB3aWxsIG1hbnVhbGx5IHNvcnQgYW4gYXJyYXksIGFuZCB0aGVuIGRldGVybWluZSB3aGljaCB2YWx1ZSBpbiB0aGUgYXJyYXkgaXMgdGhlIG1lZGlhbi4NCg0KSW4gbm90ZWJvb2suUm1kLCB3ZSBoYXZlIGEgdmVjdG9yIHdpdGggdGhlIGFnZXMgb2YgdGhlIGZpcnN0IGZpdmUgYXV0aG9ycyBmcm9tIExlIE1vbmRl4oCZcyBzdXJ2ZXk6DQoNCjI5LDQ5LDQyLDQzLDMyDQoNClVuZGVyIGZpdmVfYXV0aG9yX2FnZXMgdGhlcmUgaXMgYSB2YXJpYWJsZSBjYWxsZWQgc29ydGVkX2F1dGhvcl9hZ2VzLiBDaGFuZ2UgdGhlIDBzIGluIHNvcnRlZF9hdXRob3JfYWdlcyB0byB0aGUgdmFsdWVzIGluIGFzY2VuZGluZyBvcmRlciBmcm9tIGZpdmVfYXV0aG9yX2FnZXMuDQoNCmBgYHtyfQ0KIyBBcnJheSBvZiB0aGUgZmlyc3QgZml2ZSBhdXRob3IgYWdlcw0KZml2ZV9hdXRob3JfYWdlcyA8LSBjKDI5LCA0OSwgNDIsIDQzLCAzMikNCg0KIyBGaWxsIGluIHRoZSBlbXB0eSBhcnJheSB3aXRoIHRoZSB2YWx1ZXMgc29ydGVkDQpzb3J0ZWRfYXV0aG9yX2FnZXMgPC0gc29ydChmaXZlX2F1dGhvcl9hZ2VzKQ0KDQpzb3J0ZWRfYXV0aG9yX2FnZXMNCmBgYA0KDQoyLlNldCBtZWRpYW5fdmFsdWUgZXF1YWwgdG8gdGhlIG1lZGlhbiBvZiB0aGUgYXJyYXkuDQoNCmBgYHtyfQ0KIyBTYXZlIHRoZSBtZWRpYW4gdmFsdWUgdG8gbWVkaWFuX3ZhbHVlDQptZWRpYW5fdmFsdWUgPC0gNDINCg0KIyBQcmludCB0aGUgc29ydGVkIGFycmF5IGFuZCBtZWRpYW4gdmFsdWUNCmNhdCgiVGhlIHNvcnRlZCBhcnJheSBpczoiLCBzb3J0ZWRfYXV0aG9yX2FnZXMsICdcbicpDQoNCmNhdChwYXN0ZSgiVGhlIG1lZGlhbiBvZiB0aGUgYXJyYXkgaXM6ICIsIG1lZGlhbl92YWx1ZSkpDQpgYGANCirpl5zmlrwgY2F0KCnvvJoNCg0KY2F0KCkg5pivICJjb25jYXRlbmF0ZSBhbmQgcHJpbnQiIOeahOaEj+aAne+8jOeUqOS+huWwh+Wtl+S4suWSjOiuiuaVuOi8uOWHuuaIkOS4gOihjOaWh+Wtl++8mw0KDQrlroPkuI3lg48gcHJpbnQoKSDmnIPoh6rli5Xmj5vooYzvvIzmiYDku6Xlu7rorbDkvaDmiYvli5XliqDlhaUgXG7vvJsNCg0K5aaC5p6c5L2g55SoIGNhdChwYXN0ZSguLi4pKe+8jOmCo+m6vCBwYXN0ZSgpIOacg+WFiOe1hOWQiOaIkOS4gOaVtOWPpe+8jOWGjei8uOWHuu+8mw0KDQpjYXQoKSDkuI3mnIPlm57lgrPlgLzvvIzkuZ/nhKHms5Xnm7TmjqXopIfoo73lm54gUlN0dWRpbyDnianku7bvvIzlg4XnlKjmlrzovLjlh7rmloflrZfjgIINCg0KKuWcqCBSIOS4re+8jHBhc3RlKCkg5piv5LiA5YCL55So5L6G5bCH5aSa5YCL5a2X5Liy5ZCI5L215oiQ5LiA5YCL5a2X5Liy55qE5Ye95pW444CC5a6D5bi455So5pa855Si55Sf5YuV5oWL5paH5a2X44CB5aCx5ZGK6Ly45Ye6562J5oOF5aKD44CCDQpgYGB7cn0NCm5hbWUgPC0gIkFubmFiZWwiDQphZ2UgPC0gMTgNCg0KcGFzdGUoIk15IG5hbWUgaXMiLCBuYW1lLCAiYW5kIEkgYW0iLCBhZ2UsICJ5ZWFycyBvbGQuIikNCiMg6Ly45Ye6OiAiTXkgbmFtZSBpcyBBbm5hYmVsIGFuZCBJIGFtIDE4IHllYXJzIG9sZC4iDQpgYGANCg0KIyAzLk1lZGlhbiBpbiBSDQoNCkZpbmRpbmcgdGhlIG1lZGlhbiBvZiBhIGRhdGFzZXQgYmVjb21lcyBpbmNyZWFzaW5nbHkgdGltZS1jb25zdW1pbmcgYXMgdGhlIHNpemUgb2YgeW91ciBkYXRhc2V0IGluY3JlYXNlcyDigJQgaW1hZ2luZSBmaW5kaW5nIHRoZSBtZWRpYW4gb2YgYW4gdW5zb3J0ZWQgZGF0YXNldCB3aXRoIDEwLDAwMCBvYnNlcnZhdGlvbnMuDQoNClRoZSBSIG1lZGlhbigpIGZ1bmN0aW9uIGNhbiBkbyB0aGUgd29yayBvZiBzb3J0aW5nLCB0aGVuIGZpbmRpbmcgdGhlIG1lZGlhbiBmb3IgeW91LiBJbiB0aGUgZXhhbXBsZSBiZWxvdywgd2UgdXNlIG1lZGlhbigpIHRvIGNhbGN1bGF0ZSB0aGUgbWVkaWFuIG9mIGEgZGF0YXNldCB3aXRoIHRlbiB2YWx1ZXM6DQpgYGB7cn0NCmV4YW1wbGVfZGF0YSA9IGMoMjQsIDE2LCAzMCwgMTAsIDEyLCAyOCwgMzgsIDIsIDQsIDM2LCA0MikNCg0KZXhhbXBsZV9tZWRpYW4gPSBtZWRpYW4oZXhhbXBsZV9kYXRhKQ0KDQpwcmludChleGFtcGxlX21lZGlhbikNCg0KYGBgDQoNClRoZSBjb2RlIGFib3ZlIHByaW50cyB0aGUgbWVkaWFuIG9mIHRoZSBkYXRhc2V0LCAyNC4gVGhlIG1lYW4gb2YgdGhpcyBkYXRhc2V0IGlzIDIyLiBJdOKAmXMgd29ydGggbm90aW5nIHRoZXNlIHR3byB2YWx1ZXMgYXJlIGNsb3NlIHRvIG9uZSBhbm90aGVyLCBidXQgbm90IGVxdWFsLg0KDQojIyBJbnN0cnVjdGlvbnMNCg0KMS5Vc2UgUiB0byBmaW5kIHRoZSBtZWRpYW4gb2YgdGhlIGF1dGhvcl9hZ2VzIGFycmF5LiBTYXZlIHRoZSByZXN1bHQgdG8gbWVkaWFuX2FnZS4NCg0KRG9lcyB0aGUgbWVkaWFuIGFnZSBvZiB0aGUgYXV0aG9ycyBzdXJwcmlzZSB5b3U/IElmIHNvLCBob3c/IElzIGl0IG9sZGVyLCBvciB5b3VuZ2VyIHRoYW4geW91IGV4cGVjdGVkPw0KDQpgYGB7cn0NCiMgU2F2ZSBhdXRob3IgYWdlcyB0byBhdXRob3JfYWdlcw0KYXV0aG9yX2FnZXMgPC0gZ3JlYXRlc3RfYm9va3MkQWdlcw0KDQojIFVzZSBSIHRvIGNhbGN1bGF0ZSB0aGUgbWVkaWFuIGFnZSBvZiB0aGUgdG9wIDEwMCBhdXRob3JzDQptZWRpYW5fYWdlIDwtIG1lZGlhbihhdXRob3JfYWdlcykNCg0KcHJpbnQocGFzdGUoIlRoZSBtZWRpYW4gYWdlIG9mIHRoZSAxMDAgZ3JlYXRlc3QgYXV0aG9ycywgYWNjb3JkaW5nIHRvIGEgc3VydmV5IGJ5IExlIE1vbmRlIGlzOiAiICwgbWVkaWFuX2FnZSkpDQpgYGANCg0KIyA0LlJldmlldyBhbmQgRGlzY3Vzc2lvbg0KDQpJbiB0aGlzIGxlc3NvbiwgeW91IGxlYXJuZWQgaG93IHRvIGZpbmQgdGhlIG1lZGlhbiBvZiBhIGRhdGFzZXQgaW4gdHdvIHN0ZXBzOg0KDQoxLlNvcnQgdGhlIGRhdGFzZXQNCg0KMi5JZGVudGlmeSB0aGUgb25lIG9yIHR3byBudW1iZXJzIHRoYXQgZmFsbCBpbiB0aGUgbWlkZGxlIG9mIHRoZSBzb3J0ZWQgZGF0YXNldA0KDQpZb3UgYWxzbyBsZWFybmVkIGhvdyB0byBjYWxjdWxhdGUgdGhlIG1lZGlhbiB1c2luZyBSOg0KDQptZWRpYW4obXlfZGF0YSkNCg0KIyMgRGlzY3Vzc2lvbg0KDQpUYWtlIGEgbG9vayBhdCB0aGUgaGlzdG9ncmFtLiBJdCBkaXNwbGF5cyB0aGUgYXV0aG9yIGFnZSBkaXN0cmlidXRpb24gd2l0aCB2ZXJ0aWNhbCBsaW5lcyBmb3IgdGhlIG1lYW4gKHJlZCkgYW5kIG1lZGlhbiAoYmx1ZSkuDQoNCkRvIHlvdSBmZWVsIGxpa2UgdGhlIG1lZGlhbiBvZiBvdXIgZGF0YXNldCwgNDAuNSwgcHJvdmlkZXMgdXMgZW5vdWdoIGluZm9ybWF0aW9uIHRvIGNsYWltIHdoZW4gYXV0aG9ycyBwdWJsaXNoIHRoZWlyIGdyZWF0ZXN0IHdvcms/DQoNCldlIGFyZ3VlIGl0IGRvZXMgbm90Lg0KDQpBbHRob3VnaCB0aGUgbWVkaWFuIGlzIGEgZ29vZCBtZWFzdXJlIG9mIHRoZSBkYXRhc2V04oCZcyBjZW50ZXIsIHdlIGNhbm5vdCBtYWtlIGEgZGVmaW5pdGl2ZSBjbGFpbSBhYm91dCB3aGVuIGF1dGhvcnMgcHVibGlzaCB0aGVpciBncmVhdGVzdCB3b3JrIOKAlCB0aGUgeW91bmdlc3QgYXV0aG9yIHB1Ymxpc2hlZCBhdCAxOCBhbmQgdGhlIG9sZGVzdCBhdCA3Ni4gSXQgd291bGQgYmUgaXJyZXNwb25zaWJsZSB0byBzYXkgYW55dGhpbmcgYnV0LCDigJxpdCBzZWVtcyB0byBiZSBwb3NzaWJsZSBhdCBhbG1vc3QgYW55IGFnZS7igJ0NCg0KTm90aWNlIHRoYXQgdGhlIG1lYW4gYW5kIHRoZSBtZWRpYW4gYXJlIG5lYXJseSBlcXVhbC4gVGhpcyBpcyBub3QgYSBzdXJwcmlzaW5nIHJlc3VsdCwgYXMgYm90aCBzdGF0aXN0aWNzIGFyZSBhIG1lYXN1cmUgb2YgdGhlIGRhdGFzZXTigJlzIGNlbnRlci4gSG93ZXZlciwgaXTigJlzIHdvcnRoIG5vdGluZyB0aGF0IHRoZXNlIHJlc3VsdHMgd2lsbCBub3QgYWx3YXlzIGJlIHNvIGNsb3NlLg0KDQpJbiB0aGUgaW5zdHJ1Y3Rpb25zIGJlbG93LCB3ZeKAmXZlIHdyaXR0ZW4gYSBicmllZiBleHBsYW5hdGlvbiB0aGF0IHB1dHMgbWVkaWFuIGluIHRoZSBjb250ZXh0IG9mIG91ciBwcm9ibGVtLg0KDQpgYGB7cn0NCiNwbG90IGRhdGENCmhpc3QgPC0gcXBsb3QoZ3JlYXRlc3RfYm9va3MkQWdlcywNCiAgICAgIGdlb209J2hpc3RvZ3JhbScsDQogICAgICBiaW53aWR0aCA9IDMsICANCiAgICAgIG1haW4gPSAnQWdlIG9mIFRvcCAxMDAgTm92ZWwgQXV0aG9ycyBhdCBQdWJsaWNhdGlvbicsIA0KICAgICAgeGxhYiA9ICdQdWJsaWNhdGlvbiBBZ2UnLA0KICAgICAgeWxhYiA9ICdDb3VudCcsDQogICAgICBmaWxsPUkoImJsdWUiKSwgDQogICAgICBjb2w9SSgiYmxhY2siKSwgDQogICAgICBhbHBoYT1JKC4yKSkgKw0KICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PW1lZGlhbihncmVhdGVzdF9ib29rcyRBZ2VzKSwNCiAgICAgICAgICAgICAgICAgY29sb3I9Im1lZGlhbiIpLCBsaW5ldHlwZT0iZGFzaGVkIiwNCiAgICAgICAgICAgICBzaXplPTEpICsNCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1tZWFuKGdyZWF0ZXN0X2Jvb2tzJEFnZXMpLA0KICAgICAgICAgICAgICAgICBjb2xvcj0ibWVhbiIpLCBsaW5ldHlwZT0ic29saWQiLA0KICAgICAgICAgICAgIHNpemU9MSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJzdGF0aXN0aWNzIiwgdmFsdWVzID0gYyhtZWRpYW4gPSAiYmx1ZSIsIG1lYW4gPSAiZ3JlZW4iKSkNCg0KaGlzdA0KYGBgDQoNCiMjIEluc3RydWN0aW9ucw0KDQpUaGUgbWVkaWFuIGFnZSBvZiBhdXRob3JzLCB3aGVuIHRoZXkgcHVibGlzaCB0aGVpciBiZXN0IHdvcmssIGZyb20gTGUgTW9uZGXigJlzIDEwMCBncmVhdGVzdCBib29rcyBpcyA0MS4NCg0KV2hpbGUgdGhpcyBkb2VzIG5vdCB0ZWxsIHVzIG11Y2ggYWJvdXQgd2hpY2ggeWVhciBpcyBhbiBhdXRob3LigJlzIGdyZWF0ZXN0IHllYXIsIGl0IGRvZXMgaW5kaWNhdGUgdGhhdCBoYWxmIG9mIHRoZSBhdXRob3JzIGZyb20gdGhlIHN1cnZleSBmaW5kIHRoZWlyIGdyZWF0ZXN0IHN1Y2Nlc3MgYmVmb3JlIHRoZSBhZ2Ugb2YgNDEgYW5kIGhhbGYgZmluZCB0aGVpciBncmVhdGVzdCBzdWNjZXNzIGFmdGVyIHRoZSBhZ2Ugb2YgNDEuDQoNCg0KIyBNb2RlIGluIFIgKOecvuaVuCkNCiMgMS5JbnRyb2R1Y3Rpb24NCg0KSW4gdGhpcyBsZXNzb24sIHlvdSB3aWxsIGxlYXJuIGhvdyB0byBmaW5kIHRoZSBtb2RlIG9mIGEgZGF0YXNldC4gRWFjaCBvZiB0aGUgbmV4dCB0aHJlZSBleGVyY2lzZXMgd2lsbCBjb3ZlciB0aGUgZm9sbG93aW5nOg0KDQoxLk1hbnVhbGx5IGZpbmRpbmcgdGhlIG1vZGUgb2YgYSBkYXRhc2V0DQoNCjIuVXNpbmcgUuKAmXMgZnVuY3Rpb25zIHRvIGZpbmQgdGhlIG1vZGUNCg0KMy5Db21wYXJpbmcgbW9kZSB0byBtZWFuIGFuZCBtZWRpYW4gdmFsdWVzDQoNCkluIHRoZSBsZXNzb24sIHdlIHdpbGwgdXNlIGEgZGF0YXNldCBvZiB0aGUgMTAwIGdyZWF0ZXN0IG5vdmVscywgZGV0ZXJtaW5lZCBieSBhIEZyZW5jaCBsaXRlcmFyeSBtYWdhemluZSwgTGUgTW9uZGUuIEZyb20gdGhlIGRhdGFzZXQsIHlvdSB3aWxsIHVzZSB0aGUgbW9kZSB0byBhbnN3ZXIgdGhlIHF1ZXN0aW9uOg0KDQpXaGF0IGlzIHRoZSBtb3N0IGNvbW1vbiBhZ2UgZm9yIGEgZ3JlYXQgYXV0aG9yIHRvIHB1Ymxpc2ggdGhlaXIgYmVzdCB3b3JrPw0KDQpJZiB5b3UgYXJlIG5vdCBmYW1pbGlhciB3aXRoIG1lYW4sIGFsc28ga25vd24gYXMgYXZlcmFnZSwgb3IgbWVkaWFuLCB3ZSByZWNvbW1lbmQgdGhhdCB5b3UgbGVhcm4gYWJvdXQgaXQgaW4gb3VyIGxlc3NvbnMgb24gYXZlcmFnZSBhbmQgbWVkaWFuLg0KDQojIyBJbnN0cnVjdGlvbnMNCg0KVGhlIGhpc3RvZ3JhbSB0byB0aGUgcmlnaHQgZGlzcGxheXMgdGhlIGFnZSBvZiBhdXRob3JzLCBhdCBwdWJsaWNhdGlvbiwgZm9yIHRoZSB0b3AgMTAwIG5vdmVscyBmcm9tIExlIE1vbmRl4oCZcyBzdXJ2ZXkuIFRoZSByZWQgbGluZSBpcyB0aGUgbWVhbiBhZ2UsIGFuZCB0aGUgYmx1ZSBsaW5lIGlzIHRoZSBtZWRpYW4gYWdlLg0KDQpVc2UgdGhlIGRlZmluaXRpb24gb2YgbW9kZSBiZWxvdyBhbmQgdGhlIGhpc3RvZ3JhbSB0byB0aGUgcmlnaHQgdG8gZ3Vlc3Mgd2hlcmUgdGhlIG1vZGUgZmFsbHMuIFlvdSB3aWxsIGNhbGN1bGF0ZSB0aGUgY29ycmVjdCBhbnN3ZXIgaW4gdGhlIGxhc3QgZXhlcmNpc2UuDQoNClRoZSBtb2RlIGlzIHRoZSBtb3N0IGNvbW1vbiBvYnNlcnZhdGlvbiBpbiBhIGRhdGFzZXQuDQoNCllvdSB3aWxsIG5vdCBiZSBhYmxlIHRvIGZpbmQgdGhlIGV4YWN0IG1vZGUsIGJlY2F1c2UgdGhlIGhpc3RvZ3JhbSBkaXNwbGF5cyBiaW5zIHdpdGggYSByYW5nZSBvZiB2YWx1ZXMuIEhvd2V2ZXIsIHlvdSBjYW4gZ3Vlc3MgYSByYW5nZSBvZiB2YWx1ZXMgd2hlcmUgeW91IGFyZSBtb3N0IGxpa2VseSB0byBzZWUgdGhlIG1vZGUuDQoNCmBgYHtyfQ0KI3Bsb3QgZGF0YQ0KaGlzdCA8LSBxcGxvdChncmVhdGVzdF9ib29rcyRBZ2VzLA0KICAgICAgZ2VvbT0naGlzdG9ncmFtJywNCiAgICAgIGJpbndpZHRoID0gMywgIA0KICAgICAgbWFpbiA9ICdBZ2Ugb2YgVG9wIDEwMCBOb3ZlbCBBdXRob3JzIGF0IFB1YmxpY2F0aW9uJywgDQogICAgICB4bGFiID0gJ1B1YmxpY2F0aW9uIEFnZScsDQogICAgICB5bGFiID0gJ0NvdW50JywNCiAgICAgIGZpbGw9SSgiYmx1ZSIpLCANCiAgICAgIGNvbD1JKCJibGFjayIpLCANCiAgICAgIGFscGhhPUkoLjIpKSArDQogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9bWVkaWFuKGdyZWF0ZXN0X2Jvb2tzJEFnZXMpLA0KICAgICAgICAgICAgICAgICBjb2xvcj0ibWVkaWFuIiksIGxpbmV0eXBlPSJkYXNoZWQiLA0KICAgICAgICAgICAgIHNpemU9MSkgKw0KICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PW1lYW4oZ3JlYXRlc3RfYm9va3MkQWdlcyksDQogICAgICAgICAgICAgICAgIGNvbG9yPSJtZWFuIiksIGxpbmV0eXBlPSJzb2xpZCIsDQogICAgICAgICAgICAgc2l6ZT0xKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gInN0YXRpc3RpY3MiLCB2YWx1ZXMgPSBjKG1lZGlhbiA9ICJibHVlIiwgbWVhbiA9ICJyZWQiKSkNCg0KaGlzdA0KYGBgDQoNCiMgMi5Nb2RlDQoNClRoZSBmb3JtYWwgZGVmaW5pdGlvbiBmb3IgdGhlIG1vZGUgb2YgYSBkYXRhc2V0IGlzOg0KDQpUaGUgbW9zdCBmcmVxdWVudGx5IG9jY3VycmluZyBvYnNlcnZhdGlvbiBpbiB0aGUgZGF0YXNldC4gQSBkYXRhc2V0IGNhbiBoYXZlIG11bHRpcGxlIG1vZGVzIGlmIHRoZXJlIGlzIG1vcmUgdGhhbiBvbmUgdmFsdWUgd2l0aCB0aGUgc2FtZSBtYXhpbXVtIGZyZXF1ZW5jeS4NCg0KV2hpbGUgeW91IG1heSBiZSBhYmxlIHRvIGZpbmQgdGhlIG1vZGUgb2YgYSBzbWFsbCBkYXRhc2V0IGJ5IHNpbXBseSBsb29raW5nIHRocm91Z2ggaXQsIGlmIHlvdSBoYXZlIHRyb3VibGUsIHdlIHJlY29tbWVuZCB5b3UgZm9sbG93IHRoZXNlIHR3byBzdGVwczoNCg0KMS5GaW5kIHRoZSBmcmVxdWVuY3kgb2YgZXZlcnkgdW5pcXVlIG51bWJlciBpbiB0aGUgZGF0YXNldA0KDQoyLkRldGVybWluZSB3aGljaCBudW1iZXIgaGFzIHRoZSBoaWdoZXN0IGZyZXF1ZW5jeQ0KDQpFeGFtcGxlDQoNClNheSB3ZSBoYXZlIGEgZGF0YXNldCB3aXRoIHRoZSBmb2xsb3dpbmcgdGVuIG51bWJlcnM6DQoNCjI0LCAxNiwgMTIsIDEwLCAxMiwgMjgsIDM4LCAxMiwgMjgsIDI0DQoNCkxldOKAmXMgZmluZCB0aGUgZnJlcXVlbmN5IG9mIGVhY2ggbnVtYmVyOg0KDQoyNAkxNgkxMgkxMAkyOAkzOA0KDQoyCSAgMQkgIDMJICAxCSAgMgkgIDENCg0KRnJvbSB0aGUgdGFibGUsIHdlIGNhbiBzZWUgdGhhdCBvdXIgbW9kZSBpcyAxMiwgdGhlIG1vc3QgZnJlcXVlbnQgbnVtYmVyIGluIG91ciBkYXRhc2V0Lg0KDQojIyBJbnN0cnVjdGlvbnMNCg0KMS5EZXRlcm1pbmUgdGhlIG1vZGUgb2YgdGhlIGFnZXMgZm9yIHRoZSBmaXJzdCB0ZW4gYXV0aG9ycyBpbiB0aGUgTGUgTW9uZGUgc3VydmV5Og0KDQoyOSw0OSw0Miw0MywzMiwzOCwzNyw0MSwyNywyNw0KDQpTYXZlIHRoZSB2YWx1ZSB0byBtb2RlX2FnZS4NCmBgYHtyfQ0KbW9kZV9hZ2UgPC0gMjcNCm1vZGVfYWdlDQpgYGANCg0KMi5EZXRlcm1pbmUgdGhlIG51bWJlciBvZiBhdXRob3JzIHdobyB3ZXJlIHRoZSBhZ2Ugb2YgdGhlIG1vZGUuIFNhdmUgdGhlIG51bWJlciB0byBtb2RlX2NvdW50Lg0KDQpgYGB7cn0NCm1vZGVfY291bnQgPC0gMg0KbW9kZV9jb3VudA0KYGBgDQoNCiMgMy5Nb2RlIHdpdGggRGVzY1Rvb2xzDQoNCkZpbmRpbmcgdGhlIG1vZGUgb2YgYSBkYXRhc2V0IGJlY29tZXMgaW5jcmVhc2luZ2x5IHRpbWUtY29uc3VtaW5nIGFzIHRoZSBzaXplIG9mIHlvdXIgZGF0YXNldCBpbmNyZWFzZXMg4oCUIGltYWdpbmUgZmluZGluZyB0aGUgbW9kZSBvZiBhIGRhdGFzZXQgd2l0aCAxMCwwMDAgb2JzZXJ2YXRpb25zLg0KDQpUaGUgUiBwYWNrYWdlIERlc2NUb29scyBpbmNsdWRlcyBhIGhhbmR5IE1vZGUoKSBmdW5jdGlvbiB3aGljaCBjYW4gZG8gdGhlIHdvcmsgb2YgZmluZGluZyB0aGUgbW9kZSBmb3IgdXMuIEluIHRoZSBleGFtcGxlIGJlbG93LCB3ZSB1c2UgTW9kZSgpIHRvIGNhbGN1bGF0ZSB0aGUgbW9kZSBvZiBhIGRhdGFzZXQgd2l0aCB0ZW4gdmFsdWVzOg0KDQpFeGFtcGxlOiBPbmUgTW9kZQ0KDQpgYGB7cn0NCmxpYnJhcnkoRGVzY1Rvb2xzKQ0KDQpleGFtcGxlX2RhdGEgPC0gYygyNCwgMTYsIDEyLCAxMCwgMTIsIDI4LCAzOCwgMTIsIDI4LCAyNCkNCg0KZXhhbXBsZV9tb2RlIDwtIE1vZGUoZXhhbXBsZV9kYXRhKQ0KDQpgYGANCg0KVGhlIGNvZGUgYWJvdmUgY2FsY3VsYXRlcyB0aGUgbW9kZSBvZiB0aGUgdmFsdWVzIGluIGV4YW1wbGVfZGF0YSBhbmQgc2F2ZXMgaXQgdG8gZXhhbXBsZV9tb2RlLg0KDQpUaGUgcmVzdWx0IG9mIE1vZGUoKSBpcyBhIHZlY3RvciB3aXRoIHRoZSBtb2RlIHZhbHVlOg0KDQpgYGB7cn0NCmV4YW1wbGVfbW9kZQ0KYGBgDQoNCkV4YW1wbGU6IFR3byBNb2Rlcw0KDQpJZiB0aGVyZSBhcmUgbXVsdGlwbGUgbW9kZXMsIHRoZSBNb2RlKCkgZnVuY3Rpb24gd2lsbCByZXR1cm4gdGhlbSBhcyBhIHZlY3Rvci4NCg0KTGV04oCZcyBsb29rIGF0IGEgdmVjdG9yIHdpdGggdHdvIG1vZGVzLCAxMiBhbmQgMjQ6DQpgYGB7cn0NCmV4YW1wbGVfZGF0YSA9IGMoMjQsIDE2LCAxMiwgMTAsIDEyLCAyNCwgMzgsIDEyLCAyOCwgMjQpDQoNCmV4YW1wbGVfbW9kZSA9IE1vZGUoZXhhbXBsZV9kYXRhKQ0KYGBgDQoNClRoZSByZXN1bHQgaXM6DQpgYGB7cn0NCmV4YW1wbGVfbW9kZQ0KYGBgDQoNCiMjIEluc3RydWN0aW9ucw0KDQoxLldlIGhhdmUgYWxyZWFkeSBpbXBvcnRlZCB0aGUgRGVzY1Rvb2xzIGxpYnJhcnkgZm9yIHlvdS4NCg0KRGVsZXRlIHRoZSBjdXJyZW50IHZhbHVlIHNldCB0byBtb2RlX2FnZS4NCg0KRmluZCB0aGUgbW9kZSBvZiB0aGUgb2JzZXJ2YXRpb25zIGluIHRoZSBhdXRob3JfYWdlcyBhcnJheS4gU2F2ZSB0aGUgcmVzdWx0IHRvIG1vZGVfYWdlLg0KDQpgYGB7cn0NCiMgU2V0IGF1dGhvciBhZ2VzIHRvIA0KYXV0aG9yX2FnZXMgPC0gZ3JlYXRlc3RfYm9va3MkQWdlcw0KDQptb2RlX2FnZSA8LSBNb2RlKGF1dGhvcl9hZ2VzKQ0KDQpwcmludChwYXN0ZSgiVGhlIG1vZGUgYWdlIG9mIGF1dGhvcnMgZnJvbSBMZSBNb25kZSdzIDEwMCBncmVhdGVzdCBib29rcyBpczogIiwgbW9kZV9hZ2VbMV0pKQ0KYGBgDQoNCiMgNC5SZXZpZXcgYW5kIERpc2N1c3Npb24NCg0KSW4gdGhpcyBsZXNzb24sIHlvdSBsZWFybmVkIGhvdyB0byBmaW5kIHRoZSBtb2RlIG9mIGEgZGF0YXNldCBpbiB0d28gc3RlcHM6DQoNCjEuRmluZCB0aGUgZnJlcXVlbmN5IG9mIGV2ZXJ5IHVuaXF1ZSBudW1iZXIgaW4gdGhlIGRhdGFzZXQNCg0KMi5EZXRlcm1pbmUgd2hpY2ggbnVtYmVyIGhhcyB0aGUgaGlnaGVzdCBmcmVxdWVuY3kNCg0KWW91IGFsc28gbGVhcm5lZCBob3cgdG8gY2FsY3VsYXRlIHRoZSBtb2RlIHVzaW5nIERlc2NUb29sczoNCg0KTW9kZShteV9hcnJheSkNCg0KIyMjIERpc2N1c3Npb24NCg0KSW4gdGhpcyBsZXNzb24sIHlvdSBmb3VuZCB0aGF0IDM4IHdhcyB0aGUgbW9zdCBjb21tb24gYWdlLCBhdCBwdWJsaWNhdGlvbiwgZm9yIGFuIGF1dGhvciBmcm9tIHRoZSBMZSBNb25kZSBzdXJ2ZXkuIEhvdyBkb2VzIHRoaXMgbnVtYmVyIGNvbXBhcmUgdG8geW91ciBndWVzcyBmcm9tIHRoZSBiZWdpbm5pbmcgb2YgdGhlIGxlc3Nvbj8NCg0KVGhlIG1vZGUgaXMgY2xvc2UgdG8gdGhlIG1lZGlhbiBhbmQgbWVhbiBvZiB0aGUgZGF0YXNldCwgYnV0IGl0IGlzIG5vdCBpbiB0aGUgdGFsbGVzdCBidWNrZXQuIFRoaXMgc2hvdWxkIG5vdCBiZSBzdXJwcmlzaW5nLCBhcyB0aGUgaGlzdG9ncmFtIGluZGljYXRlcyB0aGUgZGF0YSBpcyBjZW50ZXJlZCBiZXR3ZWVuIHRoZSBhZ2VzIG9mIDMwIGFuZCA1MCDigJQgdGhlcmUgaXMgYSBoaWdoZXIgY2hhbmNlIG9mIGEgbW9kZSBpbiB0aGF0IHJhbmdlIHRoYW4gb3V0c2lkZSBvZiBpdC4NCg0KVGhlIG1vZGUgaXMgbm90IGFsd2F5cyB0aGlzIGNsb3NlIHRvIHRoZSBtZWRpYW4gYW5kIG1lYW4sIGFuZCBvZnRlbiB3aWxsIG5vdCBiZSBpbiB0aGUgdGFsbGVzdCBidWNrZXQuDQoNCkxvb2sgYXQgdGhlIDI1LTMwIHllYXItb2xkIGJpbi4gVGhlcmUgYXJlIG5pbmUgb2JzZXJ2YXRpb25zIGluIGl0LiBJZiBhbGwgdGhlIHZhbHVlcyBpbiB0aGF0IGJpbiBoYXBwZW5lZCB0byBiZSAyNywgdGhlbiB0aGUgZGF0YXNldOKAmXMgbW9kZSB3b3VsZCBiZSAyNy4gQWx0aG91Z2ggdW5saWtlbHksIGl0IGlzIHBvc3NpYmxlLiBCZWxvdywgd2Ugc2hvdyB3aGF0IHRoaXMgd291bGQgbG9vayBsaWtlOg0KDQpgYGB7ciBNZWFuMiwgb3V0LndpZHRoPSI2MCUifQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIkM6L1VzZXJzL2t1b2FuL0Rlc2t0b3AvUiBDb2RlL01lYW4yLnBuZyIpDQpgYGANCg0KQmFzZWQgb24gdGhpcyBncmFwaCwgaXQgaXMgZmFpciB0byBzYXkgdGhlIG1vZGUgbWF5IG5vdCBhbHdheXMgYmUgYSBncmVhdCBtZWFzdXJlIG9mIHdoZXJlIHRoZSBkYXRhIGlzIGNlbnRlcmVkLiBTaW1wbHkgcHV0LCBtb2RlIGlzIGEgbWVhc3VyZSBvZiB0aGUgbW9zdCBmcmVxdWVudCBvYnNlcnZhdGlvbiBpbiB0aGUgZGF0YXNldCwgYW5kIGlzIG5vdCBhbiBpbmRpY2F0aW9uIG9mIHRoZSB0YWxsZXN0IGJpbiBpbiBhIGhpc3RvZ3JhbS4NCg0KSW4gdGhlIGluc3RydWN0aW9ucyBiZWxvdywgd2XigJl2ZSB3cml0dGVuIGEgYnJpZWYgZXhwbGFuYXRpb24gdGhhdCBwdXRzIG1vZGUgaW4gdGhlIGNvbnRleHQgb2Ygb3VyIHByb2JsZW0uDQoNCiMjIEluc3RydWN0aW9ucw0KDQpgYGB7cn0NCiNwbG90IGRhdGENCmhpc3QgPC0gcXBsb3QoZ3JlYXRlc3RfYm9va3MkQWdlcywNCiAgICAgIGdlb209J2hpc3RvZ3JhbScsDQogICAgICBiaW53aWR0aCA9IDMsICANCiAgICAgIG1haW4gPSAnQWdlIG9mIFRvcCAxMDAgTm92ZWwgQXV0aG9ycyBhdCBQdWJsaWNhdGlvbicsIA0KICAgICAgeGxhYiA9ICdQdWJsaWNhdGlvbiBBZ2UnLA0KICAgICAgeWxhYiA9ICdDb3VudCcsDQogICAgICBmaWxsPUkoImJsdWUiKSwgDQogICAgICBjb2w9SSgiYmxhY2siKSwgDQogICAgICBhbHBoYT1JKC4yKSkgKw0KICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PW1lZGlhbihncmVhdGVzdF9ib29rcyRBZ2VzKSwNCiAgICAgICAgICAgICAgICAgY29sb3I9Im1lZGlhbiIpLCBsaW5ldHlwZT0iZGFzaGVkIiwNCiAgICAgICAgICAgICBzaXplPTEpICsNCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1tZWFuKGdyZWF0ZXN0X2Jvb2tzJEFnZXMpLA0KICAgICAgICAgICAgICAgICBjb2xvcj0ibWVhbiIpLCBsaW5ldHlwZT0ic29saWQiLA0KICAgICAgICAgICAgIHNpemU9MSkgKw0KICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PTM4LA0KICAgICAgICAgICAgICAgICBjb2xvcj0ibW9kZSIpLCBsaW5ldHlwZT0ic29saWQiLA0KICAgICAgICAgICAgIHNpemU9MSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJzdGF0aXN0aWNzIiwgdmFsdWVzID0gYyhtZWRpYW4gPSAiYmx1ZSIsIG1lYW4gPSAicmVkIiwgbW9kZT0iZ3JlZW4iKSkNCg0KaGlzdA0KYGBgDQoNCg==