Instructions and Overview

In this lab, we will practice calculating and interpreting measures of central tendency and measures of dispersion, as well as investigating the consequences of relying on such numbers out of context to represent complex problems. To begin you will need to import and clean your dataset, and then you will follow the prompts while responding to short answer questions. Examples have been provided to support you throughout the process. At the end of the assignment, we will integrate some of your calculations into the Shiny application you started last week.

Getting Started

Load the relevant libraries

library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
── Attaching packages ────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.0 ──
✓ ggplot2 3.3.1     ✓ purrr   0.3.4
✓ tibble  3.0.1     ✓ dplyr   1.0.0
✓ tidyr   1.1.0     ✓ stringr 1.4.0
✓ readr   1.3.1     ✓ forcats 0.5.0
── Conflicts ───────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
library(lubridate)

Attaching package: ‘lubridate’

The following objects are masked from ‘package:base’:

    date, intersect, setdiff, union

Import and clean example datasets

hospitals <- read.csv("https://opendata.arcgis.com/datasets/6ac5e325468c4cb9b905f1728d6fbf0f_0.csv", stringsAsFactors = FALSE)

world_health_econ <- read.csv("https://raw.githubusercontent.com/lindsaypoirier/STS-115/master/datasets/world_health_econ.csv", stringsAsFactors = FALSE)

cases <- read.csv("https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv", stringsAsFactors = FALSE)

#Do not worry about this line of code for now. Since the cases data gets appended every day with a new column representing that day's case counts, if we want the total cases per country, we need to add up all of the previous day's counts into a new column. The column below does this for us. 
cases <- 
  cases %>% 
  mutate(Total.Cases = 
           cases %>% 
           select(starts_with("X")) %>% 
           rowSums()
         ) %>%
  select(Province.State, Country.Region, Total.Cases)

hospitals$ZIP <- as.character(hospitals$ZIP)

hospitals$ZIP <- str_pad(hospitals$ZIP, 5, pad = "0") 

is.na(hospitals) <- hospitals == "NOT AVAILABLE"
is.na(hospitals) <- hospitals == -999
is.na(cases) <- cases == ""

hospitals$SOURCEDATE <- ymd_hms(hospitals$SOURCEDATE)
hospitals$VAL_DATE <- ymd_hms(hospitals$VAL_DATE)

Import and clean your dataset

#Copy and paste relevant code from Lab 4 to import your data here. 

#Copy and paste relevant code from Lab 4 to clean your data here. This includes any row binding, character removals, converions in variable type, date formatting, or NA conversions. 

Zooming out - aka grouping common values and summarizing

At times, we are seeking to get a broader picture of what’s going on in our dataset than provided - grouping observations that share a common value and then performing a calculation to summarize something within each of those groups. In other words, sometimes we want to see our data in aggregate. For instance, I may want to know the total number of hospital beds per state. To calculate this, I would need to group all of the hospital observations by state and then sum the total number of beds in each group. In such cases, we can call group_by() to aggregate the observations with common variable values into groups. Then we will call summarize() to perform a calculation within each of those groups. summarize() takes a set of values and a calculation method and returns a single value. For instance, if we call summarize() with a numeric column in our dataset and “mean” as a calculation method, it will return the average of all the numeric values in that column. When called in conjunction with group_by(), summarize() takes a set of values for each group and a calculation method and returns a single value for each group.

For the hospitals dataset, we will group the observations by STATE and then use summarize to calculate the sum of BEDS per state. Notice below how we are choosing to ignore NA values above by calling na.rm = TRUE. When we do so, we need to keep in mind that we are not summarizing across all observations in the dataset, but only those for which there is a value listed in the variable we are operating on. Because of this, I also calculate the number of observations in each group, the number of observations where the BEDS variable is missing, and the percentage of observations in the group where the variable is missing. This provides important context for how readily we can rely on these numbers. For instance, when you run the code below, note how in Alaska, the number of beds are missing for 28% of the observations.

#Run this code chunk.

#df %>% group_by(CATEGORICAL_VARIABLE) %>% summarize(NEW_VARIABLE_NAME = sum(NUMBERIC_VARIABLE, na.rm = TRUE)) %>% ungroup()

hospitals %>% 
  group_by(STATE) %>% #Group observations by state
  summarize(
    STATES_BEDS = sum(BEDS, na.rm = TRUE), #Calculate the sum of BEDS within each STATE group
    OBSERVATIONS = n(), #Calculate how many observations are in each STATE group
    MISSING_BEDS = sum(is.na(BEDS)), #Calculate how many NAs are in the BEDS variable in each STATE group
    PERCENT_MISSING = sum(is.na(BEDS))/n()*100) %>% #Divide the two values you just calculated to determine the percent of missing data
  ungroup()
`summarise()` ungrouping output (override with `.groups` argument)

Notice that I close each of these calls with ungroup(). When we group_by() a variable, any subsequent function calls will continue to be performed on the grouped data, unless we ungroup() it. This can be important if we want to filter to specific values after we summarize() the data. Assuming that we don’t want to perform a filter operation within each group but on the entire new dataframe created after summarizing, we need to ungroup() the data before performing the filter() operation.

From this function, we see the number of beds across all hospitals per state. Depending on the question we are asking, this may or may not be relevant. For instance, if I’m wondering how much hospital infrastructure is available to support Covid-19 patients, one (of a number of factors) I need to consider before presenting this data is which types of hospitals are accepting Covid-19 patients. Are rehabilitation hospitals accepting patients? Psychiatric hospitals? Military hospitals? If they aren’t now, will they at some point? Further, some states are talking about cordoning off hotels for Covid-19 patients. How do we account for this change in the number of hospital beds (something definitely not represented in our data based on the way hospital has been defined). We need to do external research to answer these questions. Then we may wish to filter our data to relevant hospital types. For instance, at this moment, we may filter our data to only include beds at General Acute Care Hospitals. We also know that some hospitals in the dataset are closed. We need to also filter these out before presenting the data. Notice how below, I can do this by simply copying and pasting the code from above and adding one filter statement before grouping the data.

#Run this code chunk.

hospitals %>% 
  filter(TYPE == "GENERAL ACUTE CARE" & STATUS == "OPEN") %>%
  group_by(STATE) %>% #Group observations by state
  summarize(
    STATES_BEDS = sum(BEDS, na.rm = TRUE), #Calculate the sum of BEDS within each STATE group
    OBSERVATIONS = n(), #Calculate how many observations are in each STATE group
    MISSING_BEDS = sum(is.na(BEDS)), #Calculate how many NAs are in the BEDS variable in each STATE group
    PERCENT_MISSING = sum(is.na(BEDS))/n()*100) %>% #Divide the two values you just calculated to determine the percent of missing data
  ungroup()
`summarise()` ungrouping output (override with `.groups` argument)

In other words, often times to answer questions within a dataset, we need to both zoom in and out on data - honing in on certain observations and then generalizing across them. We cannot answer questions well if we don’t have a good understanding of what’s included in our data and how issues are defined. Had we not known that hospitals that are closed and hospitals that are classed as rehabs or psychiatric facilities were included in the data, we may have made some poor assumptions about the number of beds available. Also note how, in every step of data analysis, we have to make decisions about what to include and what to exclude in the analysis. Data analysts play a very active role in shaping the knowledge that gets produced from data. The numbers can never speak for themselves.

Select a categorical variable that you would like to group your data by, so that you can summarize some statistics across each grouping. You may group your data by a particular year, by a particular location (such as a state or a region), or by a particular category. Then select a numeric variable in your dataset to summarize by. For instance, you may want to sum the total number of reports in a given year, or find the average number of cases reported in a certain state. Also calculate the percent of observations where data is missing in each group. If you have qualified units of observation, you may want to group the data by one of the variables in your unique key. For instance, if your unique key is a county and year, then perhaps you want to group the data by county and summarize something across each year. If you have qualified units of observation and choose to group by a variable that is not in your unique key, then be sure to filter the data as you have been above.

#Uncomment the appropriate lines below, and fill in your data frame, variables, and summarize variable name, and math function. Then run the code.
#_____ %>% group_by(_____) %>% summarize(_____ = _____(_____, na.rm = TRUE), OBSERVATIONS = n(), MISSING = sum(is.na(_____)), PERCENT_MISSING = sum(is.na(BEDS))/n()*100)

#If you have qualified units of observation (and not grouping by the qualifier).
#_____ %>% filter(_____ == _____) %>% group_by(_____) %>% summarize(_____ = _____(_____, na.rm = TRUE), OBSERVATIONS = n(), MISSING = sum(is.na(_____)), PERCENT_MISSING = sum(is.na(BEDS))/n()*100)

What question might this analysis help to address?

Fill your response here. 

Are there any other variables in your dataset that you need to take into consideration before directing this analysis towards answering that question? In other words, do you need to zoom into any specific areas of the dataset (by filtering) in order to appropriately address this question? If so, which? Be sure to adjust your plot above to reflect this.

Fill your response here. 

What else would we need to know to fully address this question? Here you may consider what you know about how this dataset was produced and its limitations.

Fill your response here. 

What insight can you draw from grouping and summarizing?

Fill your response here. 

Measures of Central Tendency

A measure of central tendency is a single numeric quantity describing data by identifying a central position within it. It summarizes values within a set into a single value. We often refer to such a value as an average.

At times, finding this measure can be quite useful __. However, we also need to be careful when relying on measures of central tendency to communicate information about our data. This is because measures of central tendency can be reductionist - reducing a complex story told across data to a single value. They can hide meaningful outliers and erase the nuance of a complicated narrative. For instance, measures of central tendency related to wealth in the US are likely to hide the experiences of the most impoverished communities. Such a measure can be a weapon for stakeholders combatting government policies to direct public resources towards communities in need.

Further, there are many pitfalls we need to steer clear of when assessing a measure of central tendency. Such a measure should only be taken to summarize the values across similar observations. If you have qualified units of observation, this will likely mean filtering your data to a set of similar values - to one year in the world_health_econ dataset for instance if you were looking to average populations across countries.

Let’s say that we were looking to calculate the average number of beds in hospitals across the US. To do so, would it be appropriate to identify a central position within the BEDS variable in the dataset? Probably not. There are many different types of hospitals in the hospitals dataset, and we would expect these different hospitals to have different numbers of beds. For instance, we know from our research that Critical Access Hospitals are supposed to have 25 beds or fewer. In averaging across all of them, we would be measuring the center value of dissimilar observations. Before taking an average of BEDS, we would want to filter our data to a set of similar observations. We will do this below - filtering to open general acute care hospitals.

Mean

A commomn measure of central tendency is a mean - the sum of a series of values divided by the number of values summed. This measure considers every value in a set of data and thus is a model of the entire set of data. Remember from lab five that we calculate mean with summarize() Let’s calculate the mean number of beds at open general acute care hospitals.

#df %>% summarize(mean_value = mean(NUMERIC_VARIABLE, na.rm = TRUE))

hospitals %>% 
  filter(STATUS == "OPEN" & TYPE == "GENERAL ACUTE CARE") %>%
  summarize(mean_value = mean(BEDS, na.rm = TRUE))

Similarly, if we wanted to know the mean number of Covid-19 cases per country, as we learned last week, we would need to group_by() the country and summarize() the total number of cases. Remember that this is because some cases are reported at the province level and some are reported at the country level. To ensure that we are taking a measure of central tendency across similar data, we need to ensure that all of the values we are summarizing are reported at one geographic scale - in this case, the country level.

#df %>% summarize(mean_value = mean(NUMERIC_VARIABLE, na.rm = TRUE))

cases %>% 
  group_by(Country.Region) %>%
  summarize(Total.Cases = sum(Total.Cases, na.rm = TRUE)) %>%
  ungroup() %>%
  summarize(mean_value = mean(Total.Cases, na.rm = TRUE))
`summarise()` ungrouping output (override with `.groups` argument)

Median

Another measure of central tendency considers the middle value in a dataset; this is referred to as the median. Now let’s calculate the median number of beds at open general acute care hospitals.

#df %>% summarize(median_value = median(NUMERIC_VARIABLE, na.rm = TRUE))

hospitals %>% 
  filter(STATUS == "OPEN" & TYPE == "GENERAL ACUTE CARE") %>%
  summarize(median_value = median(BEDS, na.rm = TRUE))

Let’s also calculate the median number of Covid-19 cases per country.

#df %>% summarize(mean_value = mean(NUMERIC_VARIABLE, na.rm = TRUE))

cases %>% 
  group_by(Country.Region) %>%
  summarize(Total.Cases = sum(Total.Cases, na.rm = TRUE)) %>%
  ungroup() %>%
  summarize(median_value = median(Total.Cases, na.rm = TRUE))
`summarise()` ungrouping output (override with `.groups` argument)

Notice how there’s a considerable difference between the mean and the median value across both of these sets of calculations. So which should we rely on to summarize the central location in our dataset?

We want to keep in mind that because the mean is a model of the entire dataset, it is easily influenced by outliers in the dataset, as well as a skewed distribution. When the distribution of values in a set is normal, the mean and median of the dataset will be the same because the values on either side of the middle value will be symmetrical. In other words, the distribution will be balanced on either side of the median. Frequency plots give us a good indication of the distribution of values the dataset.

hospitals %>% 
  filter(STATUS == "OPEN" & TYPE == "GENERAL ACUTE CARE") %>%
  ggplot(aes(x = BEDS)) +
  geom_freqpoly(binwidth = 10) + 
  labs(title = "Distribution of Beds across General Acute Care Hospitals in the US that are Open", x = "Beds", y = "Count of Hospitals") +
  theme_bw()

cases %>% 
  group_by(Country.Region) %>%
  summarize(Total.Cases = sum(Total.Cases, na.rm = TRUE)) %>%
  ungroup() %>%
  ggplot(aes(x = Total.Cases)) + 
  geom_freqpoly(binwidth = 10000) +
  labs(title = "Distribution of Cases across Countries", x = "Total Cases", y = "Count of Countries") + # To add titles and labels
  theme_bw() +
  theme(axis.text.x = element_text(angle = 90, hjust=1)) + #Turn labels 90 degrees
  scale_x_continuous(labels = scales::comma) #Change labels from scientific to comma notation
`summarise()` ungrouping output (override with `.groups` argument)

You’ll notice in the hospitals and the cases dataset, the values of are significantly right-skewed. We can tell because the values represented on the plot are far from symmetrical. Instead, there is a long tail running to the right of the data. In such cases, the mean is going to be significantly influenced by the larger values in the data even though there are far fewer.

When the values in a frequency plot are skewed to the left or the right, we often want to rely on the median rather than the mean as a measure of central tendency, as it more clearly distinguishes the central location in the data. In the hospitals and the cases dataset, median is a better indicator of central tendency than the mean. However, both still significanltly gloss over the dispersion of values in the data.

We also need to be careful when taking measures of central tendency that we do not attempt to take an average of an average. Let me provide an exmaple of why this is inappropriate. Let’s say I were to find the average number of beds at open general acute hospitals per state using group_by() and summarize().

avg_by_state <- 
  hospitals %>% 
  filter(STATUS == "OPEN" & TYPE == "GENERAL ACUTE CARE") %>%
  group_by(STATE) %>%
  summarize(mean_value = mean(BEDS, na.rm = TRUE)) %>%
  ungroup() 
`summarise()` ungrouping output (override with `.groups` argument)
avg_by_state

In taking the mean of the mean_value column we just created (i.e. an average of the state averages), you will notice that we get a different value than the mean we calculated above:

#Mean of BEDS across all observations
avg_across_all_obs <-
  hospitals %>% 
  filter(STATUS == "OPEN" & TYPE == "GENERAL ACUTE CARE") %>%
  summarize(mean_value = mean(BEDS, na.rm = TRUE))

#Mean of BEDS across all state averages
avg_across_state_avgs <-
  avg_by_state %>%
  summarize(mean_value = mean(mean_value, na.rm = TRUE))

#Check if they are equal
paste("When we check if", avg_across_all_obs, "(the mean of BEDS across all observations) is equal to", avg_across_state_avgs, "(the mean of BEDS across state averages) the result is", avg_across_all_obs == avg_across_state_avgs)
[1] "When we check if 197.901932712956 (the mean of BEDS across all observations) is equal to 190.405566557084 (the mean of BEDS across state averages) the result is FALSE"

This is because when we take an average of averages, we are ignoring a key confounding variable - the size of the denominator in each of the state averages. We know that there are different numbers of hospitals in each state. When we take the mean across all state averages, we basically ignore this variable - producing a different mean than if we were to calculate mean across all observations in the set. This can have dramatic consequences on the values reported in our data.

Please watch this short video on Simpon’s Paradox to learn more about the importance of avoiding this pitfall:

This is an issue we would need to keep in mind when calculating measures of central tendency in our world_health_econ dataset. The majority of the variables reported in the world_health_econ dataset are already averages - either averages across the population of the country or averages across the country’s total spending on health. Because of this, it would be inappropriate to calculate measures of central tendency across these variables without knowing their denominators.

You might be thinking, “Well don’t we have population as another variable in the dataset. Doesn’t that tell us the denominator of some of the averages?” That is corret. However, looking at our data dictionary you will notice that the population variable in the dataset is derived from a different source than the health economics indicators. While we can expect these numbers to be in proximity, different organizations count the number of people in a country differently. This value might not accurately reflect the denominator of many of our health economics indicators.

Measures of Central Tendency in your Own Dataset

Calculate the mean and median of a numeric variable in your dataset.

Be sure to filter your dataset to ensure that you are summarizing across similar observations. Also be sure to avoid averaging an average.

#Fill your code here. 

What question might these measures of central tendency help to address?

Fill your response here. 

Create a frequency plot of the numeric variable you produced calculations of above. (You may have created this last week, and you may copy and paste it from the previous lab.)

#Create a frequency plot here. 

Characterize the distribution of values in the frequency plot you created. Is it symmetrical or skewed?

Fill your response here. 

Which value is more appropriate as a measure of central tendency in your data?

Fill your response here. 

Characterize the extent to which the value you selected as a measure of central tendency above (mean or median) is representative of your data. What story is told when we rely on this number as a summary of the data?

Fill your response here. 

If we were to use this single value to summarize this variable, what narratives would be left out? How does the complexity of the narratives in your data get reduced in calculating this value.

Fill your response here. 

Select another numeric variable in your dataset and calculate both the mean and the median.

Be sure to filter your dataset to ensure that you are summarizing across similar observations. Also be sure to avoid averaging an average.

#Fill your code here. 

What question might these measures of central tendency help to address?

Fill your response here. 

Create a frequency plot of the numeric variable you produced calculations of above. (You may have created this last week, and you may copy and paste it from the previous lab.)

#Create a frequency plot here. 

Characterize the distribution of values in the frequency plot you created. Is it symmetrical or skewed?

Fill your response here. 

Which value is more appropriate as a measure of central tendency in your data?

Fill your response here. 

What story do these calculations tell? Would you select the median or the mean as a measure of central tendency? Why?

Fill your response here. 

Characterize the extent to which the value you selected as a measure of central tendency above is representative of your data.

Fill your response here. 

If we were to use this single value to summarize this variable, what narratives would be left out? How does the complexity of the narratives in your data get reduced in calculating this value.

Fill your response here. 

As we’ve been discussing in class, any measure that we calculate is mediated by the way the phenomena we are measuring gets defined. How were the numeric variables that you selected defined? What was included in these definitions, and what potentially relevant values were excluded?

Fill your response here. 

Measures of Dispersion

Measures of dispersion help us to understand how spread out the values in our dataset are - their variations from each other and from the data’s center. Like measures of central tendency, measures of dispersion should be taken across a set of data with similar values. This often means filtering our data to those that represent a similar set of observations.

Ranges

The range of data refers to the difference between the maximum value in a set and the minimum value in a set. We can also use summarize() to find the max value, min value, and range of values in a numeric variable.

#df %>% summarize(max_value = max(NUMERIC_VARIABLE, na.rm = TRUE))
hospitals %>% 
  filter(STATUS == "OPEN" & TYPE == "GENERAL ACUTE CARE") %>%
  summarize(max_value = max(BEDS, na.rm = TRUE))

#df %>% summarize(min_value = min(NUMERIC_VARIABLE, na.rm = TRUE))
hospitals %>% 
  filter(STATUS == "OPEN" & TYPE == "GENERAL ACUTE CARE") %>%
  summarize(min_value = min(BEDS, na.rm = TRUE))

#df %>% summarize(range = max(NUMERIC_VARIABLE, na.rm = TRUE) - min(NUMERIC_VARIABLE, na.rm = TRUE))
hospitals %>% 
  filter(STATUS == "OPEN" & TYPE == "GENERAL ACUTE CARE") %>%
  summarize(range = max(BEDS, na.rm = TRUE) - min(BEDS, na.rm = TRUE))

Quartile Deviation

Even though we are introducing the boxplot in relation to quartile deviation, it can be a tool for summarizing a number of quantitative insights in relation to a numerical variable in our dataset. Boxplots provide a visual representation of both measures of central tendency and measures of dispersion. The center line in a boxplot indicates the median of the dataset. The bottom of the box represents the 1st quartile - the value in the middle of the minimum and the median (or the the value at the 1st quarter position). The top of the box represents the 3rd quartile - the value in the middle of the median and the maximum (or the value at the 3rd quarter position). The whiskers include almost all of the data - indicating its range from minimum to maximum excluding outliers. The dots represent outliers. ggplot has a calculation for outliers that we need not go into in this course.

The further the 1st and 3rd quartile are from the median (or, in other words, the wider the box), the greater the quartile deviation. In general, a narrower box and whiskers indicates less dispersion in the data, while a wider box and whiskers indicates greater dispersion.

Let’s use a boxplot to check out the quartile deviation of beds in open general acute care hospitals in the US.

#df %>% ggplot(aes(y = NUMERIC_VARIABLE)) + geom_boxplot() + theme_bw()

hospitals %>%
  filter(STATUS == "OPEN" & TYPE == "GENERAL ACUTE CARE") %>%
  ggplot(aes(y = BEDS)) +
  geom_boxplot() +
  labs(title = "Distribution of Beds across General Acute Care Hospitals in the US that are Open", y = "Beds") +
  theme_bw()

Note how we can title a boxplot very similarly to how we title a frequency plot. Both show distributions of values.

We can see from this plot that the quartile deviation is much smaller than the range in our dataset. This suggests that centered values are more concentrated than the extremes.

Standard Deviation

Standard deviation calculates the extent of concentration of values around the mean. A higher standard deviation indicates that values are more dispersed from the mean, and a lower standard deviation indicates that values are more concentrated around the mean.

#df %>% summarize(sd_value = sd(NUMERIC_VALUE, na.rm = TRUE))

hospitals %>% 
  filter(STATUS == "OPEN" & TYPE == "GENERAL ACUTE CARE") %>%
  summarize(sd_value = sd(BEDS, na.rm = TRUE))

Measures of Dispersion in Your Own Dataset

Select one of the numeric variables on which you calculated a measure of central tendency above, and calculate the maximum value, the minimum value, and the range of values within that variable.

Be sure to filter your dataset to ensure that you are summarizing across similar observations.

#Fill your code to calculate max here. 

#Fill your code to calculate min here. 

#Fill your code to calculate range here. 

What question might this measure of dispersion help to address?

Fill your response here. 

Do the numbers surprise you? What insight can you draw from this calculation?

Fill your response here. 

Create a boxplot for one of the numeric variables on which you calculated a measure of central tendency above.

Be sure to filter your dataset to ensure that you are plotting across similar observations.

#Fill your plot here. Be sure to add a title and labels to your plot. 

What question might this measure of dispersion help to address?

Fill your response here. 

What insight can you draw from the plot you created?

Fill your response here. 

Calculate the standard deviation for one of the numeric variables on which you calculated a measure of central tendency above.

Be sure to filter your dataset to ensure that you are summarizing across similar observations.

#Fill your code here.

What question might this measure of dispersion help to address?

Fill your response here. 

What insight can you draw from this calculation?

Fill your response here. 

Now that you have a sense of the dispersion of some of the values in your data, why do you believe the values are as concentrated or dispersed as they are? What do the measures of dispersion you calculated say about social, political, or economic life in the area the data is representing? You may need to do some research to answer this question. For instance, noting the dispersion of beds in the hospitals data, I may do a Web search for “Why do some hospitals in the US have more beds than others?” and find this article. Be sure to assess the reputability of your source and cite it in your response below.

Fill your response here. 

Grouped Quantitative Insights

Like we learned in regards to co-variation, some of the most interesting information we can gain from our data is how values change depending on where in the data we are looking.

Boxplots

ggplot’s geom_boxplot feature is particularly good at comparing measures of dispersion across grouped values in a categorical variable. It is set up to visualize several boxplots side-by-side. When we do have dissimilar observations in our dataset, this is a way to compare the dispersion of values across them. Let’s take a look at how we could compare dispersions in the number of hospital beds available by hospital ownership.

#df %>% ggplot(aes(x = CATEGORICAL_VARIABLE, y = NUMERIC_VARIABLE)) + geom_boxplot()

hospitals %>%
  filter(STATUS == "OPEN") %>%
  ggplot(aes(x = TYPE, y = BEDS)) +
  geom_boxplot() +
  labs(title = "Distribution of Beds across Hospitals in the US that are Open by Type", x = "Type", Y = "Beds") +
  theme_bw() +
  theme(axis.text.x = element_text(angle = 90, hjust=1)) + #Changes x-axis tick labels 90 degrees
  coord_flip() #Flips the x and y axis to make the data easier to read and compare

We can also filter our data to similar values and the compare dispersions across another category.

#df %>% ggplot(aes(x = CATEGORICAL_VARIABLE, y = NUMERIC_VARIABLE)) + geom_boxplot()

hospitals %>%
  filter(STATUS == "OPEN" & TYPE == "GENERAL ACUTE CARE") %>%
  ggplot(aes(x = OWNER, y = BEDS)) +
  geom_boxplot() +
  labs(title = "Distribution of Beds across Hospitals in the US that are Open by Type", x = "OWNER", Y = "Beds") +
  theme_bw() +
  theme(axis.text.x = element_text(angle = 90, hjust=1)) + #Changes x-axis tick labels 90 degrees
  coord_flip() #Flips the x and y axis to make the data easier to read and compare

We see above that there is a greater dispersion in the number of beds available at state hospitals and non-profit hospitals. We also see that, in local hospitals, the median is closer to the first quartile than in other plots, and there are a number of outliers, indicating that the data is going to be more right skewed than in other plots right-skewed. Compare this to federal hospitals, where the median is more centered in the box (and there are few outliers). We are likely to see a less skewed distribution in this plot. Let’s confirm this.

hospitals %>%
  filter(STATUS == "OPEN" & TYPE == "GENERAL ACUTE CARE" & OWNER == "GOVERNMENT - LOCAL") %>%
  ggplot(aes(x = BEDS)) +
  geom_freqpoly(binwidth = 25) +
  labs(title = "Distribution of Beds across Open General Acute Care Local Hospitals in the US", x = "Beds", y = "Count of Hospitals") + # To add titles and labels
  theme_bw()


hospitals %>%
  filter(STATUS == "OPEN" & TYPE == "GENERAL ACUTE CARE" & OWNER == "GOVERNMENT - FEDERAL") %>%
  ggplot(aes(x = BEDS)) +
  geom_freqpoly(binwidth = 25) +
  labs(title = "Distribution of Beds across Open General Acute Care Federal Hospitals in the US", x = "Beds", y = "Count of Hospitals") + # To add titles and labels
  theme_bw()

We can see above how the distribution in the second plot is a bit more normal than the distribution in the first, confirming what we concluded above.

Create a grouped boxplot for your dataset below.

Be sure to filter your dataset to ensure that you are summarizing across similar observations or ensure that each group is made up of similar observations.

#Fill your code here. Add a title and labels to your plot. 

Summarize what you learn from the plot.

Fill your response here. 

How does the story that this grouped boxplot tells differ from the story told by the single boxplot you created above? Interpret why the story differs.

Fill your response here. 
LS0tCnRpdGxlOiAiTGFiIDYgLSBRdWFudGl0YXRpdmUgSW5zaWdodHMiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogMwogICAgdG9jX2Zsb2F0OiB5ZXMKICBodG1sX2RvY3VtZW50OgogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAnMycKZWRpdG9yX29wdGlvbnM6CiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCiMjIEluc3RydWN0aW9ucyBhbmQgT3ZlcnZpZXcKCkluIHRoaXMgbGFiLCB3ZSB3aWxsIHByYWN0aWNlIGNhbGN1bGF0aW5nIGFuZCBpbnRlcnByZXRpbmcgbWVhc3VyZXMgb2YgY2VudHJhbCB0ZW5kZW5jeSBhbmQgbWVhc3VyZXMgb2YgZGlzcGVyc2lvbiwgYXMgd2VsbCBhcyBpbnZlc3RpZ2F0aW5nIHRoZSBjb25zZXF1ZW5jZXMgb2YgcmVseWluZyBvbiBzdWNoIG51bWJlcnMgb3V0IG9mIGNvbnRleHQgdG8gcmVwcmVzZW50IGNvbXBsZXggcHJvYmxlbXMuIFRvIGJlZ2luIHlvdSB3aWxsIG5lZWQgdG8gaW1wb3J0IGFuZCBjbGVhbiB5b3VyIGRhdGFzZXQsIGFuZCB0aGVuIHlvdSB3aWxsIGZvbGxvdyB0aGUgcHJvbXB0cyB3aGlsZSByZXNwb25kaW5nIHRvIHNob3J0IGFuc3dlciBxdWVzdGlvbnMuIEV4YW1wbGVzIGhhdmUgYmVlbiBwcm92aWRlZCB0byBzdXBwb3J0IHlvdSB0aHJvdWdob3V0IHRoZSBwcm9jZXNzLiBBdCB0aGUgZW5kIG9mIHRoZSBhc3NpZ25tZW50LCB3ZSB3aWxsIGludGVncmF0ZSBzb21lIG9mIHlvdXIgY2FsY3VsYXRpb25zIGludG8gdGhlIFNoaW55IGFwcGxpY2F0aW9uIHlvdSBzdGFydGVkIGxhc3Qgd2Vlay4gCgojIyBHZXR0aW5nIFN0YXJ0ZWQKCiMjIyBMb2FkIHRoZSByZWxldmFudCBsaWJyYXJpZXMKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShsdWJyaWRhdGUpCmBgYAoKCiMjIyBJbXBvcnQgYW5kIGNsZWFuIGV4YW1wbGUgZGF0YXNldHMgCgpgYGB7cn0KaG9zcGl0YWxzIDwtIHJlYWQuY3N2KCJodHRwczovL29wZW5kYXRhLmFyY2dpcy5jb20vZGF0YXNldHMvNmFjNWUzMjU0NjhjNGNiOWI5MDVmMTcyOGQ2ZmJmMGZfMC5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCgp3b3JsZF9oZWFsdGhfZWNvbiA8LSByZWFkLmNzdigiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2xpbmRzYXlwb2lyaWVyL1NUUy0xMTUvbWFzdGVyL2RhdGFzZXRzL3dvcmxkX2hlYWx0aF9lY29uLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKCmNhc2VzIDwtIHJlYWQuY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vQ1NTRUdJU2FuZERhdGEvQ09WSUQtMTkvbWFzdGVyL2Nzc2VfY292aWRfMTlfZGF0YS9jc3NlX2NvdmlkXzE5X3RpbWVfc2VyaWVzL3RpbWVfc2VyaWVzX2NvdmlkMTlfY29uZmlybWVkX2dsb2JhbC5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCgojRG8gbm90IHdvcnJ5IGFib3V0IHRoaXMgbGluZSBvZiBjb2RlIGZvciBub3cuIFNpbmNlIHRoZSBjYXNlcyBkYXRhIGdldHMgYXBwZW5kZWQgZXZlcnkgZGF5IHdpdGggYSBuZXcgY29sdW1uIHJlcHJlc2VudGluZyB0aGF0IGRheSdzIGNhc2UgY291bnRzLCBpZiB3ZSB3YW50IHRoZSB0b3RhbCBjYXNlcyBwZXIgY291bnRyeSwgd2UgbmVlZCB0byBhZGQgdXAgYWxsIG9mIHRoZSBwcmV2aW91cyBkYXkncyBjb3VudHMgaW50byBhIG5ldyBjb2x1bW4uIFRoZSBjb2x1bW4gYmVsb3cgZG9lcyB0aGlzIGZvciB1cy4gCmNhc2VzIDwtIAogIGNhc2VzICU+JSAKICBtdXRhdGUoVG90YWwuQ2FzZXMgPSAKICAgICAgICAgICBjYXNlcyAlPiUgCiAgICAgICAgICAgc2VsZWN0KHN0YXJ0c193aXRoKCJYIikpICU+JSAKICAgICAgICAgICByb3dTdW1zKCkKICAgICAgICAgKSAlPiUKICBzZWxlY3QoUHJvdmluY2UuU3RhdGUsIENvdW50cnkuUmVnaW9uLCBUb3RhbC5DYXNlcykKCmhvc3BpdGFscyRaSVAgPC0gYXMuY2hhcmFjdGVyKGhvc3BpdGFscyRaSVApCgpob3NwaXRhbHMkWklQIDwtIHN0cl9wYWQoaG9zcGl0YWxzJFpJUCwgNSwgcGFkID0gIjAiKSAKCmlzLm5hKGhvc3BpdGFscykgPC0gaG9zcGl0YWxzID09ICJOT1QgQVZBSUxBQkxFIgppcy5uYShob3NwaXRhbHMpIDwtIGhvc3BpdGFscyA9PSAtOTk5CmlzLm5hKGNhc2VzKSA8LSBjYXNlcyA9PSAiIgoKaG9zcGl0YWxzJFNPVVJDRURBVEUgPC0geW1kX2htcyhob3NwaXRhbHMkU09VUkNFREFURSkKaG9zcGl0YWxzJFZBTF9EQVRFIDwtIHltZF9obXMoaG9zcGl0YWxzJFZBTF9EQVRFKQpgYGAKCiMjIyBJbXBvcnQgYW5kIGNsZWFuIHlvdXIgZGF0YXNldAoKYGBge3J9CiNDb3B5IGFuZCBwYXN0ZSByZWxldmFudCBjb2RlIGZyb20gTGFiIDQgdG8gaW1wb3J0IHlvdXIgZGF0YSBoZXJlLiAKCiNDb3B5IGFuZCBwYXN0ZSByZWxldmFudCBjb2RlIGZyb20gTGFiIDQgdG8gY2xlYW4geW91ciBkYXRhIGhlcmUuIFRoaXMgaW5jbHVkZXMgYW55IHJvdyBiaW5kaW5nLCBjaGFyYWN0ZXIgcmVtb3ZhbHMsIGNvbnZlcmlvbnMgaW4gdmFyaWFibGUgdHlwZSwgZGF0ZSBmb3JtYXR0aW5nLCBvciBOQSBjb252ZXJzaW9ucy4gCmBgYAoKCgojIyMgWm9vbWluZyBvdXQgLSBha2EgZ3JvdXBpbmcgY29tbW9uIHZhbHVlcyBhbmQgc3VtbWFyaXppbmcKCkF0IHRpbWVzLCB3ZSBhcmUgc2Vla2luZyB0byBnZXQgYSBicm9hZGVyIHBpY3R1cmUgb2Ygd2hhdCdzIGdvaW5nIG9uIGluIG91ciBkYXRhc2V0IHRoYW4gcHJvdmlkZWQgLSBncm91cGluZyBvYnNlcnZhdGlvbnMgdGhhdCBzaGFyZSBhIGNvbW1vbiB2YWx1ZSBhbmQgdGhlbiBwZXJmb3JtaW5nIGEgY2FsY3VsYXRpb24gdG8gc3VtbWFyaXplIHNvbWV0aGluZyB3aXRoaW4gZWFjaCBvZiB0aG9zZSBncm91cHMuIEluIG90aGVyIHdvcmRzLCBzb21ldGltZXMgd2Ugd2FudCB0byBzZWUgb3VyIGRhdGEgaW4gYWdncmVnYXRlLiBGb3IgaW5zdGFuY2UsIEkgbWF5IHdhbnQgdG8ga25vdyB0aGUgdG90YWwgbnVtYmVyIG9mIGhvc3BpdGFsIGJlZHMgcGVyIHN0YXRlLiBUbyBjYWxjdWxhdGUgdGhpcywgSSB3b3VsZCBuZWVkIHRvIGdyb3VwIGFsbCBvZiB0aGUgaG9zcGl0YWwgb2JzZXJ2YXRpb25zIGJ5IHN0YXRlIGFuZCB0aGVuIHN1bSB0aGUgdG90YWwgbnVtYmVyIG9mIGJlZHMgaW4gZWFjaCBncm91cC4gCkluIHN1Y2ggY2FzZXMsIHdlIGNhbiBjYWxsICoqZ3JvdXBfYnkoKSoqIHRvIGFnZ3JlZ2F0ZSB0aGUgb2JzZXJ2YXRpb25zIHdpdGggY29tbW9uIHZhcmlhYmxlIHZhbHVlcyBpbnRvIGdyb3Vwcy4gVGhlbiB3ZSB3aWxsIGNhbGwgKipzdW1tYXJpemUoKSoqIHRvIHBlcmZvcm0gYSBjYWxjdWxhdGlvbiB3aXRoaW4gZWFjaCBvZiB0aG9zZSBncm91cHMuICoqc3VtbWFyaXplKCkqKiB0YWtlcyBhIHNldCBvZiB2YWx1ZXMgYW5kIGEgY2FsY3VsYXRpb24gbWV0aG9kIGFuZCByZXR1cm5zIGEgc2luZ2xlIHZhbHVlLiBGb3IgaW5zdGFuY2UsIGlmIHdlIGNhbGwgc3VtbWFyaXplKCkgd2l0aCBhIG51bWVyaWMgY29sdW1uIGluIG91ciBkYXRhc2V0IGFuZCAibWVhbiIgYXMgYSBjYWxjdWxhdGlvbiBtZXRob2QsIGl0IHdpbGwgcmV0dXJuIHRoZSBhdmVyYWdlIG9mIGFsbCB0aGUgbnVtZXJpYyB2YWx1ZXMgaW4gdGhhdCBjb2x1bW4uIFdoZW4gY2FsbGVkIGluIGNvbmp1bmN0aW9uIHdpdGggZ3JvdXBfYnkoKSwgKipzdW1tYXJpemUoKSoqIHRha2VzIGEgc2V0IG9mIHZhbHVlcyBmb3IgZWFjaCBncm91cCBhbmQgYSBjYWxjdWxhdGlvbiBtZXRob2QgYW5kIHJldHVybnMgYSBzaW5nbGUgdmFsdWUgZm9yIGVhY2ggZ3JvdXAuIAoKRm9yIHRoZSBob3NwaXRhbHMgZGF0YXNldCwgd2Ugd2lsbCBncm91cCB0aGUgb2JzZXJ2YXRpb25zIGJ5IFNUQVRFIGFuZCB0aGVuIHVzZSBzdW1tYXJpemUgdG8gY2FsY3VsYXRlIHRoZSBzdW0gb2YgQkVEUyBwZXIgc3RhdGUuIE5vdGljZSBiZWxvdyBob3cgd2UgYXJlIGNob29zaW5nIHRvIGlnbm9yZSBOQSB2YWx1ZXMgYWJvdmUgYnkgY2FsbGluZyBuYS5ybSA9IFRSVUUuIFdoZW4gd2UgZG8gc28sIHdlIG5lZWQgdG8ga2VlcCBpbiBtaW5kIHRoYXQgd2UgYXJlIG5vdCBzdW1tYXJpemluZyBhY3Jvc3MgYWxsIG9ic2VydmF0aW9ucyBpbiB0aGUgZGF0YXNldCwgYnV0IG9ubHkgdGhvc2UgZm9yIHdoaWNoIHRoZXJlIGlzIGEgdmFsdWUgbGlzdGVkIGluIHRoZSB2YXJpYWJsZSB3ZSBhcmUgb3BlcmF0aW5nIG9uLiBCZWNhdXNlIG9mIHRoaXMsIEkgYWxzbyBjYWxjdWxhdGUgdGhlIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgaW4gZWFjaCBncm91cCwgdGhlIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgd2hlcmUgdGhlIEJFRFMgdmFyaWFibGUgaXMgbWlzc2luZywgYW5kIHRoZSBwZXJjZW50YWdlIG9mIG9ic2VydmF0aW9ucyBpbiB0aGUgZ3JvdXAgd2hlcmUgdGhlIHZhcmlhYmxlIGlzIG1pc3NpbmcuIFRoaXMgcHJvdmlkZXMgaW1wb3J0YW50IGNvbnRleHQgZm9yIGhvdyByZWFkaWx5IHdlIGNhbiByZWx5IG9uIHRoZXNlIG51bWJlcnMuIEZvciBpbnN0YW5jZSwgd2hlbiB5b3UgcnVuIHRoZSBjb2RlIGJlbG93LCBub3RlIGhvdyBpbiBBbGFza2EsIHRoZSBudW1iZXIgb2YgYmVkcyBhcmUgbWlzc2luZyBmb3IgMjglIG9mIHRoZSBvYnNlcnZhdGlvbnMuIAoKYGBge3J9CiNSdW4gdGhpcyBjb2RlIGNodW5rLgoKI2RmICU+JSBncm91cF9ieShDQVRFR09SSUNBTF9WQVJJQUJMRSkgJT4lIHN1bW1hcml6ZShORVdfVkFSSUFCTEVfTkFNRSA9IHN1bShOVU1CRVJJQ19WQVJJQUJMRSwgbmEucm0gPSBUUlVFKSkgJT4lIHVuZ3JvdXAoKQoKaG9zcGl0YWxzICU+JSAKICBncm91cF9ieShTVEFURSkgJT4lICNHcm91cCBvYnNlcnZhdGlvbnMgYnkgc3RhdGUKICBzdW1tYXJpemUoCiAgICBTVEFURVNfQkVEUyA9IHN1bShCRURTLCBuYS5ybSA9IFRSVUUpLCAjQ2FsY3VsYXRlIHRoZSBzdW0gb2YgQkVEUyB3aXRoaW4gZWFjaCBTVEFURSBncm91cAogICAgT0JTRVJWQVRJT05TID0gbigpLCAjQ2FsY3VsYXRlIGhvdyBtYW55IG9ic2VydmF0aW9ucyBhcmUgaW4gZWFjaCBTVEFURSBncm91cAogICAgTUlTU0lOR19CRURTID0gc3VtKGlzLm5hKEJFRFMpKSwgI0NhbGN1bGF0ZSBob3cgbWFueSBOQXMgYXJlIGluIHRoZSBCRURTIHZhcmlhYmxlIGluIGVhY2ggU1RBVEUgZ3JvdXAKICAgIFBFUkNFTlRfTUlTU0lORyA9IHN1bShpcy5uYShCRURTKSkvbigpKjEwMCkgJT4lICNEaXZpZGUgdGhlIHR3byB2YWx1ZXMgeW91IGp1c3QgY2FsY3VsYXRlZCB0byBkZXRlcm1pbmUgdGhlIHBlcmNlbnQgb2YgbWlzc2luZyBkYXRhCiAgdW5ncm91cCgpCmBgYAoKPiBOb3RpY2UgdGhhdCBJIGNsb3NlIGVhY2ggb2YgdGhlc2UgY2FsbHMgd2l0aCAqKnVuZ3JvdXAoKSoqLiBXaGVuIHdlIGdyb3VwX2J5KCkgYSB2YXJpYWJsZSwgYW55IHN1YnNlcXVlbnQgZnVuY3Rpb24gY2FsbHMgd2lsbCBjb250aW51ZSB0byBiZSBwZXJmb3JtZWQgb24gdGhlIGdyb3VwZWQgZGF0YSwgdW5sZXNzIHdlIHVuZ3JvdXAoKSBpdC4gVGhpcyBjYW4gYmUgaW1wb3J0YW50IGlmIHdlIHdhbnQgdG8gZmlsdGVyIHRvIHNwZWNpZmljIHZhbHVlcyBhZnRlciB3ZSBzdW1tYXJpemUoKSB0aGUgZGF0YS4gQXNzdW1pbmcgdGhhdCB3ZSBkb24ndCB3YW50IHRvIHBlcmZvcm0gYSBmaWx0ZXIgb3BlcmF0aW9uIHdpdGhpbiBlYWNoIGdyb3VwIGJ1dCBvbiB0aGUgZW50aXJlIG5ldyBkYXRhZnJhbWUgY3JlYXRlZCBhZnRlciBzdW1tYXJpemluZywgd2UgbmVlZCB0byB1bmdyb3VwKCkgdGhlIGRhdGEgYmVmb3JlIHBlcmZvcm1pbmcgdGhlIGZpbHRlcigpIG9wZXJhdGlvbi4gCgpGcm9tIHRoaXMgZnVuY3Rpb24sIHdlIHNlZSB0aGUgbnVtYmVyIG9mIGJlZHMgYWNyb3NzIGFsbCBob3NwaXRhbHMgcGVyIHN0YXRlLiBEZXBlbmRpbmcgb24gdGhlIHF1ZXN0aW9uIHdlIGFyZSBhc2tpbmcsIHRoaXMgbWF5IG9yIG1heSBub3QgYmUgcmVsZXZhbnQuIEZvciBpbnN0YW5jZSwgaWYgSSdtIHdvbmRlcmluZyBob3cgbXVjaCBob3NwaXRhbCBpbmZyYXN0cnVjdHVyZSBpcyBhdmFpbGFibGUgdG8gc3VwcG9ydCBDb3ZpZC0xOSBwYXRpZW50cywgb25lIChvZiBhIG51bWJlciBvZiBmYWN0b3JzKSBJIG5lZWQgdG8gY29uc2lkZXIgYmVmb3JlIHByZXNlbnRpbmcgdGhpcyBkYXRhIGlzIHdoaWNoIHR5cGVzIG9mIGhvc3BpdGFscyBhcmUgYWNjZXB0aW5nIENvdmlkLTE5IHBhdGllbnRzLiBBcmUgcmVoYWJpbGl0YXRpb24gaG9zcGl0YWxzIGFjY2VwdGluZyBwYXRpZW50cz8gUHN5Y2hpYXRyaWMgaG9zcGl0YWxzPyBNaWxpdGFyeSBob3NwaXRhbHM/IElmIHRoZXkgYXJlbid0IG5vdywgd2lsbCB0aGV5IGF0IHNvbWUgcG9pbnQ/IEZ1cnRoZXIsIHNvbWUgc3RhdGVzIGFyZSB0YWxraW5nIGFib3V0IGNvcmRvbmluZyBvZmYgaG90ZWxzIGZvciBDb3ZpZC0xOSBwYXRpZW50cy4gSG93IGRvIHdlIGFjY291bnQgZm9yIHRoaXMgY2hhbmdlIGluIHRoZSBudW1iZXIgb2YgaG9zcGl0YWwgYmVkcyAoc29tZXRoaW5nIGRlZmluaXRlbHkgbm90IHJlcHJlc2VudGVkIGluIG91ciBkYXRhIGJhc2VkIG9uIHRoZSB3YXkgaG9zcGl0YWwgaGFzIGJlZW4gZGVmaW5lZCkuIFdlIG5lZWQgdG8gZG8gZXh0ZXJuYWwgcmVzZWFyY2ggdG8gYW5zd2VyIHRoZXNlIHF1ZXN0aW9ucy4gVGhlbiB3ZSBtYXkgd2lzaCB0byBmaWx0ZXIgb3VyIGRhdGEgdG8gcmVsZXZhbnQgaG9zcGl0YWwgdHlwZXMuIEZvciBpbnN0YW5jZSwgYXQgdGhpcyBtb21lbnQsIHdlIG1heSBmaWx0ZXIgb3VyIGRhdGEgdG8gb25seSBpbmNsdWRlIGJlZHMgYXQgR2VuZXJhbCBBY3V0ZSBDYXJlIEhvc3BpdGFscy4gV2UgYWxzbyBrbm93IHRoYXQgc29tZSBob3NwaXRhbHMgaW4gdGhlIGRhdGFzZXQgYXJlIGNsb3NlZC4gV2UgbmVlZCB0byBhbHNvIGZpbHRlciB0aGVzZSBvdXQgYmVmb3JlIHByZXNlbnRpbmcgdGhlIGRhdGEuIE5vdGljZSBob3cgYmVsb3csIEkgY2FuIGRvIHRoaXMgYnkgc2ltcGx5IGNvcHlpbmcgYW5kIHBhc3RpbmcgdGhlIGNvZGUgZnJvbSBhYm92ZSBhbmQgYWRkaW5nIG9uZSBmaWx0ZXIgc3RhdGVtZW50IGJlZm9yZSBncm91cGluZyB0aGUgZGF0YS4gCgpgYGB7cn0KI1J1biB0aGlzIGNvZGUgY2h1bmsuCgpob3NwaXRhbHMgJT4lIAogIGZpbHRlcihUWVBFID09ICJHRU5FUkFMIEFDVVRFIENBUkUiICYgU1RBVFVTID09ICJPUEVOIikgJT4lCiAgZ3JvdXBfYnkoU1RBVEUpICU+JSAjR3JvdXAgb2JzZXJ2YXRpb25zIGJ5IHN0YXRlCiAgc3VtbWFyaXplKAogICAgU1RBVEVTX0JFRFMgPSBzdW0oQkVEUywgbmEucm0gPSBUUlVFKSwgI0NhbGN1bGF0ZSB0aGUgc3VtIG9mIEJFRFMgd2l0aGluIGVhY2ggU1RBVEUgZ3JvdXAKICAgIE9CU0VSVkFUSU9OUyA9IG4oKSwgI0NhbGN1bGF0ZSBob3cgbWFueSBvYnNlcnZhdGlvbnMgYXJlIGluIGVhY2ggU1RBVEUgZ3JvdXAKICAgIE1JU1NJTkdfQkVEUyA9IHN1bShpcy5uYShCRURTKSksICNDYWxjdWxhdGUgaG93IG1hbnkgTkFzIGFyZSBpbiB0aGUgQkVEUyB2YXJpYWJsZSBpbiBlYWNoIFNUQVRFIGdyb3VwCiAgICBQRVJDRU5UX01JU1NJTkcgPSBzdW0oaXMubmEoQkVEUykpL24oKSoxMDApICU+JSAjRGl2aWRlIHRoZSB0d28gdmFsdWVzIHlvdSBqdXN0IGNhbGN1bGF0ZWQgdG8gZGV0ZXJtaW5lIHRoZSBwZXJjZW50IG9mIG1pc3NpbmcgZGF0YQogIHVuZ3JvdXAoKQpgYGAKCkluIG90aGVyIHdvcmRzLCBvZnRlbiB0aW1lcyB0byBhbnN3ZXIgcXVlc3Rpb25zIHdpdGhpbiBhIGRhdGFzZXQsIHdlIG5lZWQgdG8gYm90aCB6b29tIGluIGFuZCBvdXQgb24gZGF0YSAtIGhvbmluZyBpbiBvbiBjZXJ0YWluIG9ic2VydmF0aW9ucyBhbmQgdGhlbiBnZW5lcmFsaXppbmcgYWNyb3NzIHRoZW0uIFdlIGNhbm5vdCBhbnN3ZXIgcXVlc3Rpb25zIHdlbGwgaWYgd2UgZG9uJ3QgaGF2ZSBhIGdvb2QgdW5kZXJzdGFuZGluZyBvZiB3aGF0J3MgaW5jbHVkZWQgaW4gb3VyIGRhdGEgYW5kIGhvdyBpc3N1ZXMgYXJlIGRlZmluZWQuIEhhZCB3ZSBub3Qga25vd24gdGhhdCBob3NwaXRhbHMgdGhhdCBhcmUgY2xvc2VkIGFuZCBob3NwaXRhbHMgdGhhdCBhcmUgY2xhc3NlZCBhcyByZWhhYnMgb3IgcHN5Y2hpYXRyaWMgZmFjaWxpdGllcyB3ZXJlIGluY2x1ZGVkIGluIHRoZSBkYXRhLCB3ZSBtYXkgaGF2ZSBtYWRlIHNvbWUgcG9vciBhc3N1bXB0aW9ucyBhYm91dCB0aGUgbnVtYmVyIG9mIGJlZHMgYXZhaWxhYmxlLiBBbHNvIG5vdGUgaG93LCBpbiBldmVyeSBzdGVwIG9mIGRhdGEgYW5hbHlzaXMsIHdlIGhhdmUgdG8gbWFrZSBkZWNpc2lvbnMgYWJvdXQgd2hhdCB0byBpbmNsdWRlIGFuZCB3aGF0IHRvIGV4Y2x1ZGUgaW4gdGhlIGFuYWx5c2lzLiBEYXRhIGFuYWx5c3RzIHBsYXkgYSB2ZXJ5IGFjdGl2ZSByb2xlIGluIHNoYXBpbmcgdGhlIGtub3dsZWRnZSB0aGF0IGdldHMgcHJvZHVjZWQgZnJvbSBkYXRhLiBUaGUgbnVtYmVycyBjYW4gbmV2ZXIgc3BlYWsgZm9yIHRoZW1zZWx2ZXMuIAoKU2VsZWN0IGEgY2F0ZWdvcmljYWwgdmFyaWFibGUgdGhhdCB5b3Ugd291bGQgbGlrZSB0byBncm91cCB5b3VyIGRhdGEgYnksIHNvIHRoYXQgeW91IGNhbiBzdW1tYXJpemUgc29tZSBzdGF0aXN0aWNzIGFjcm9zcyBlYWNoIGdyb3VwaW5nLiBZb3UgbWF5IGdyb3VwIHlvdXIgZGF0YSBieSBhIHBhcnRpY3VsYXIgeWVhciwgYnkgYSBwYXJ0aWN1bGFyIGxvY2F0aW9uIChzdWNoIGFzIGEgc3RhdGUgb3IgYSByZWdpb24pLCBvciBieSBhIHBhcnRpY3VsYXIgY2F0ZWdvcnkuIFRoZW4gc2VsZWN0IGEgbnVtZXJpYyB2YXJpYWJsZSBpbiB5b3VyIGRhdGFzZXQgdG8gc3VtbWFyaXplIGJ5LiBGb3IgaW5zdGFuY2UsIHlvdSBtYXkgd2FudCB0byBzdW0gdGhlIHRvdGFsIG51bWJlciBvZiByZXBvcnRzIGluIGEgZ2l2ZW4geWVhciwgb3IgZmluZCB0aGUgYXZlcmFnZSBudW1iZXIgb2YgY2FzZXMgcmVwb3J0ZWQgaW4gYSBjZXJ0YWluIHN0YXRlLiBBbHNvIGNhbGN1bGF0ZSB0aGUgcGVyY2VudCBvZiBvYnNlcnZhdGlvbnMgd2hlcmUgZGF0YSBpcyBtaXNzaW5nIGluIGVhY2ggZ3JvdXAuIElmIHlvdSBoYXZlIHF1YWxpZmllZCB1bml0cyBvZiBvYnNlcnZhdGlvbiwgeW91IG1heSB3YW50IHRvIGdyb3VwIHRoZSBkYXRhIGJ5IG9uZSBvZiB0aGUgdmFyaWFibGVzIGluIHlvdXIgdW5pcXVlIGtleS4gRm9yIGluc3RhbmNlLCBpZiB5b3VyIHVuaXF1ZSBrZXkgaXMgYSBjb3VudHkgYW5kIHllYXIsIHRoZW4gcGVyaGFwcyB5b3Ugd2FudCB0byBncm91cCB0aGUgZGF0YSBieSBjb3VudHkgYW5kIHN1bW1hcml6ZSBzb21ldGhpbmcgYWNyb3NzIGVhY2ggeWVhci4gSWYgeW91IGhhdmUgcXVhbGlmaWVkIHVuaXRzIG9mIG9ic2VydmF0aW9uIGFuZCBjaG9vc2UgdG8gZ3JvdXAgYnkgYSB2YXJpYWJsZSB0aGF0IGlzIG5vdCBpbiB5b3VyIHVuaXF1ZSBrZXksIHRoZW4gYmUgc3VyZSB0byBmaWx0ZXIgdGhlIGRhdGEgYXMgeW91IGhhdmUgYmVlbiBhYm92ZS4gCgpgYGB7cn0KI1VuY29tbWVudCB0aGUgYXBwcm9wcmlhdGUgbGluZXMgYmVsb3csIGFuZCBmaWxsIGluIHlvdXIgZGF0YSBmcmFtZSwgdmFyaWFibGVzLCBhbmQgc3VtbWFyaXplIHZhcmlhYmxlIG5hbWUsIGFuZCBtYXRoIGZ1bmN0aW9uLiBUaGVuIHJ1biB0aGUgY29kZS4KI19fX19fICU+JSBncm91cF9ieShfX19fXykgJT4lIHN1bW1hcml6ZShfX19fXyA9IF9fX19fKF9fX19fLCBuYS5ybSA9IFRSVUUpLCBPQlNFUlZBVElPTlMgPSBuKCksIE1JU1NJTkcgPSBzdW0oaXMubmEoX19fX18pKSwgUEVSQ0VOVF9NSVNTSU5HID0gc3VtKGlzLm5hKEJFRFMpKS9uKCkqMTAwKQoKI0lmIHlvdSBoYXZlIHF1YWxpZmllZCB1bml0cyBvZiBvYnNlcnZhdGlvbiAoYW5kIG5vdCBncm91cGluZyBieSB0aGUgcXVhbGlmaWVyKS4KI19fX19fICU+JSBmaWx0ZXIoX19fX18gPT0gX19fX18pICU+JSBncm91cF9ieShfX19fXykgJT4lIHN1bW1hcml6ZShfX19fXyA9IF9fX19fKF9fX19fLCBuYS5ybSA9IFRSVUUpLCBPQlNFUlZBVElPTlMgPSBuKCksIE1JU1NJTkcgPSBzdW0oaXMubmEoX19fX18pKSwgUEVSQ0VOVF9NSVNTSU5HID0gc3VtKGlzLm5hKEJFRFMpKS9uKCkqMTAwKQpgYGAKCldoYXQgcXVlc3Rpb24gbWlnaHQgdGhpcyBhbmFseXNpcyBoZWxwIHRvIGFkZHJlc3M/CgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4gCmBgYAoKQXJlIHRoZXJlIGFueSBvdGhlciB2YXJpYWJsZXMgaW4geW91ciBkYXRhc2V0IHRoYXQgeW91IG5lZWQgdG8gdGFrZSBpbnRvIGNvbnNpZGVyYXRpb24gYmVmb3JlIGRpcmVjdGluZyB0aGlzIGFuYWx5c2lzIHRvd2FyZHMgYW5zd2VyaW5nIHRoYXQgcXVlc3Rpb24/IEluIG90aGVyIHdvcmRzLCBkbyB5b3UgbmVlZCB0byB6b29tIGludG8gYW55IHNwZWNpZmljIGFyZWFzIG9mIHRoZSBkYXRhc2V0IChieSBmaWx0ZXJpbmcpIGluIG9yZGVyIHRvIGFwcHJvcHJpYXRlbHkgYWRkcmVzcyB0aGlzIHF1ZXN0aW9uPyBJZiBzbywgd2hpY2g/IEJlIHN1cmUgdG8gYWRqdXN0IHlvdXIgcGxvdCBhYm92ZSB0byByZWZsZWN0IHRoaXMuCgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4gCmBgYAoKV2hhdCBlbHNlIHdvdWxkIHdlIG5lZWQgdG8ga25vdyB0byBmdWxseSBhZGRyZXNzIHRoaXMgcXVlc3Rpb24/IEhlcmUgeW91IG1heSBjb25zaWRlciB3aGF0IHlvdSBrbm93IGFib3V0IGhvdyB0aGlzIGRhdGFzZXQgd2FzIHByb2R1Y2VkIGFuZCBpdHMgbGltaXRhdGlvbnMuCgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4gCmBgYAoKV2hhdCBpbnNpZ2h0IGNhbiB5b3UgZHJhdyBmcm9tIGdyb3VwaW5nIGFuZCBzdW1tYXJpemluZz8KCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgeW91ciByZXNwb25zZSBoZXJlLiAKYGBgCgojIyBNZWFzdXJlcyBvZiBDZW50cmFsIFRlbmRlbmN5CgpBIG1lYXN1cmUgb2YgY2VudHJhbCB0ZW5kZW5jeSBpcyBhIHNpbmdsZSBudW1lcmljIHF1YW50aXR5IGRlc2NyaWJpbmcgZGF0YSBieSBpZGVudGlmeWluZyBhIGNlbnRyYWwgcG9zaXRpb24gd2l0aGluIGl0LiBJdCBzdW1tYXJpemVzIHZhbHVlcyB3aXRoaW4gYSBzZXQgaW50byBhIHNpbmdsZSB2YWx1ZS4gV2Ugb2Z0ZW4gcmVmZXIgdG8gc3VjaCBhIHZhbHVlIGFzIGFuIGF2ZXJhZ2UuIAoKQXQgdGltZXMsIGZpbmRpbmcgdGhpcyBtZWFzdXJlIGNhbiBiZSBxdWl0ZSB1c2VmdWwgX18uIEhvd2V2ZXIsIHdlIGFsc28gbmVlZCB0byBiZSBjYXJlZnVsIHdoZW4gcmVseWluZyBvbiBtZWFzdXJlcyBvZiBjZW50cmFsIHRlbmRlbmN5IHRvIGNvbW11bmljYXRlIGluZm9ybWF0aW9uIGFib3V0IG91ciBkYXRhLiBUaGlzIGlzIGJlY2F1c2UgbWVhc3VyZXMgb2YgY2VudHJhbCB0ZW5kZW5jeSBjYW4gYmUgKnJlZHVjdGlvbmlzdCogLSByZWR1Y2luZyBhIGNvbXBsZXggc3RvcnkgdG9sZCBhY3Jvc3MgZGF0YSB0byBhIHNpbmdsZSB2YWx1ZS4gVGhleSBjYW4gaGlkZSBtZWFuaW5nZnVsIG91dGxpZXJzIGFuZCBlcmFzZSB0aGUgbnVhbmNlIG9mIGEgY29tcGxpY2F0ZWQgbmFycmF0aXZlLiBGb3IgaW5zdGFuY2UsIG1lYXN1cmVzIG9mIGNlbnRyYWwgdGVuZGVuY3kgcmVsYXRlZCB0byB3ZWFsdGggaW4gdGhlIFVTIGFyZSBsaWtlbHkgdG8gaGlkZSB0aGUgZXhwZXJpZW5jZXMgb2YgdGhlIG1vc3QgaW1wb3ZlcmlzaGVkIGNvbW11bml0aWVzLiBTdWNoIGEgbWVhc3VyZSBjYW4gYmUgYSB3ZWFwb24gZm9yIHN0YWtlaG9sZGVycyBjb21iYXR0aW5nIGdvdmVybm1lbnQgcG9saWNpZXMgdG8gZGlyZWN0IHB1YmxpYyByZXNvdXJjZXMgdG93YXJkcyBjb21tdW5pdGllcyBpbiBuZWVkLiAKCkZ1cnRoZXIsIHRoZXJlIGFyZSBtYW55IHBpdGZhbGxzIHdlIG5lZWQgdG8gc3RlZXIgY2xlYXIgb2Ygd2hlbiBhc3Nlc3NpbmcgYSBtZWFzdXJlIG9mIGNlbnRyYWwgdGVuZGVuY3kuIFN1Y2ggYSBtZWFzdXJlIHNob3VsZCBvbmx5IGJlIHRha2VuIHRvIHN1bW1hcml6ZSB0aGUgdmFsdWVzIGFjcm9zcyAqc2ltaWxhciBvYnNlcnZhdGlvbnMuKiBJZiB5b3UgaGF2ZSBxdWFsaWZpZWQgdW5pdHMgb2Ygb2JzZXJ2YXRpb24sIHRoaXMgd2lsbCBsaWtlbHkgbWVhbiBmaWx0ZXJpbmcgeW91ciBkYXRhIHRvIGEgc2V0IG9mIHNpbWlsYXIgdmFsdWVzIC0gdG8gb25lIHllYXIgaW4gdGhlIHdvcmxkX2hlYWx0aF9lY29uIGRhdGFzZXQgZm9yIGluc3RhbmNlIGlmIHlvdSB3ZXJlIGxvb2tpbmcgdG8gYXZlcmFnZSBwb3B1bGF0aW9ucyBhY3Jvc3MgY291bnRyaWVzLiAKCkxldCdzIHNheSB0aGF0IHdlIHdlcmUgbG9va2luZyB0byBjYWxjdWxhdGUgdGhlIGF2ZXJhZ2UgbnVtYmVyIG9mIGJlZHMgaW4gaG9zcGl0YWxzIGFjcm9zcyB0aGUgVVMuIFRvIGRvIHNvLCB3b3VsZCBpdCBiZSBhcHByb3ByaWF0ZSB0byBpZGVudGlmeSBhIGNlbnRyYWwgcG9zaXRpb24gd2l0aGluIHRoZSBCRURTIHZhcmlhYmxlIGluIHRoZSBkYXRhc2V0PyBQcm9iYWJseSBub3QuIFRoZXJlIGFyZSBtYW55IGRpZmZlcmVudCB0eXBlcyBvZiBob3NwaXRhbHMgaW4gdGhlIGhvc3BpdGFscyBkYXRhc2V0LCBhbmQgd2Ugd291bGQgZXhwZWN0IHRoZXNlIGRpZmZlcmVudCBob3NwaXRhbHMgdG8gaGF2ZSBkaWZmZXJlbnQgbnVtYmVycyBvZiBiZWRzLiBGb3IgaW5zdGFuY2UsIHdlICprbm93KiBmcm9tIG91ciByZXNlYXJjaCB0aGF0IENyaXRpY2FsIEFjY2VzcyBIb3NwaXRhbHMgYXJlIHN1cHBvc2VkIHRvIGhhdmUgMjUgYmVkcyBvciBmZXdlci4gSW4gYXZlcmFnaW5nIGFjcm9zcyBhbGwgb2YgdGhlbSwgd2Ugd291bGQgYmUgbWVhc3VyaW5nIHRoZSBjZW50ZXIgdmFsdWUgb2YgZGlzc2ltaWxhciBvYnNlcnZhdGlvbnMuIEJlZm9yZSB0YWtpbmcgYW4gYXZlcmFnZSBvZiBCRURTLCB3ZSB3b3VsZCB3YW50IHRvIGZpbHRlciBvdXIgZGF0YSB0byBhIHNldCBvZiBzaW1pbGFyIG9ic2VydmF0aW9ucy4gV2Ugd2lsbCBkbyB0aGlzIGJlbG93IC0gZmlsdGVyaW5nIHRvIG9wZW4gZ2VuZXJhbCBhY3V0ZSBjYXJlIGhvc3BpdGFscy4KCiMjIyBNZWFuCgpBIGNvbW1vbW4gbWVhc3VyZSBvZiBjZW50cmFsIHRlbmRlbmN5IGlzIGEgKm1lYW4qIC0gdGhlIHN1bSBvZiBhIHNlcmllcyBvZiB2YWx1ZXMgZGl2aWRlZCBieSB0aGUgbnVtYmVyIG9mIHZhbHVlcyBzdW1tZWQuIFRoaXMgbWVhc3VyZSBjb25zaWRlcnMgZXZlcnkgdmFsdWUgaW4gYSBzZXQgb2YgZGF0YSBhbmQgdGh1cyBpcyBhIG1vZGVsIG9mIHRoZSBlbnRpcmUgc2V0IG9mIGRhdGEuIFJlbWVtYmVyIGZyb20gbGFiIGZpdmUgdGhhdCB3ZSBjYWxjdWxhdGUgbWVhbiB3aXRoICoqc3VtbWFyaXplKCkqKiAgTGV0J3MgY2FsY3VsYXRlIHRoZSBtZWFuIG51bWJlciBvZiBiZWRzIGF0IG9wZW4gZ2VuZXJhbCBhY3V0ZSBjYXJlIGhvc3BpdGFscy4KCmBgYHtyfQojZGYgJT4lIHN1bW1hcml6ZShtZWFuX3ZhbHVlID0gbWVhbihOVU1FUklDX1ZBUklBQkxFLCBuYS5ybSA9IFRSVUUpKQoKaG9zcGl0YWxzICU+JSAKICBmaWx0ZXIoU1RBVFVTID09ICJPUEVOIiAmIFRZUEUgPT0gIkdFTkVSQUwgQUNVVEUgQ0FSRSIpICU+JQogIHN1bW1hcml6ZShtZWFuX3ZhbHVlID0gbWVhbihCRURTLCBuYS5ybSA9IFRSVUUpKQpgYGAKClNpbWlsYXJseSwgaWYgd2Ugd2FudGVkIHRvIGtub3cgdGhlIG1lYW4gbnVtYmVyIG9mIENvdmlkLTE5IGNhc2VzIHBlciBjb3VudHJ5LCBhcyB3ZSBsZWFybmVkIGxhc3Qgd2Vlaywgd2Ugd291bGQgbmVlZCB0byBncm91cF9ieSgpIHRoZSBjb3VudHJ5IGFuZCBzdW1tYXJpemUoKSB0aGUgdG90YWwgbnVtYmVyIG9mIGNhc2VzLiBSZW1lbWJlciB0aGF0IHRoaXMgaXMgYmVjYXVzZSBzb21lIGNhc2VzIGFyZSByZXBvcnRlZCBhdCB0aGUgcHJvdmluY2UgbGV2ZWwgYW5kIHNvbWUgYXJlIHJlcG9ydGVkIGF0IHRoZSBjb3VudHJ5IGxldmVsLiBUbyBlbnN1cmUgdGhhdCB3ZSBhcmUgdGFraW5nIGEgbWVhc3VyZSBvZiBjZW50cmFsIHRlbmRlbmN5IGFjcm9zcyBzaW1pbGFyIGRhdGEsIHdlIG5lZWQgdG8gZW5zdXJlIHRoYXQgYWxsIG9mIHRoZSB2YWx1ZXMgd2UgYXJlIHN1bW1hcml6aW5nIGFyZSByZXBvcnRlZCBhdCBvbmUgZ2VvZ3JhcGhpYyBzY2FsZSAtIGluIHRoaXMgY2FzZSwgdGhlIGNvdW50cnkgbGV2ZWwuIAoKYGBge3J9CiNkZiAlPiUgc3VtbWFyaXplKG1lYW5fdmFsdWUgPSBtZWFuKE5VTUVSSUNfVkFSSUFCTEUsIG5hLnJtID0gVFJVRSkpCgpjYXNlcyAlPiUgCiAgZ3JvdXBfYnkoQ291bnRyeS5SZWdpb24pICU+JQogIHN1bW1hcml6ZShUb3RhbC5DYXNlcyA9IHN1bShUb3RhbC5DYXNlcywgbmEucm0gPSBUUlVFKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIHN1bW1hcml6ZShtZWFuX3ZhbHVlID0gbWVhbihUb3RhbC5DYXNlcywgbmEucm0gPSBUUlVFKSkKYGBgCgojIyMgTWVkaWFuCgpBbm90aGVyIG1lYXN1cmUgb2YgY2VudHJhbCB0ZW5kZW5jeSBjb25zaWRlcnMgdGhlIG1pZGRsZSB2YWx1ZSBpbiBhIGRhdGFzZXQ7IHRoaXMgaXMgcmVmZXJyZWQgdG8gYXMgdGhlICptZWRpYW4qLiBOb3cgbGV0J3MgY2FsY3VsYXRlIHRoZSBtZWRpYW4gbnVtYmVyIG9mIGJlZHMgYXQgb3BlbiBnZW5lcmFsIGFjdXRlIGNhcmUgaG9zcGl0YWxzLgoKYGBge3J9CiNkZiAlPiUgc3VtbWFyaXplKG1lZGlhbl92YWx1ZSA9IG1lZGlhbihOVU1FUklDX1ZBUklBQkxFLCBuYS5ybSA9IFRSVUUpKQoKaG9zcGl0YWxzICU+JSAKICBmaWx0ZXIoU1RBVFVTID09ICJPUEVOIiAmIFRZUEUgPT0gIkdFTkVSQUwgQUNVVEUgQ0FSRSIpICU+JQogIHN1bW1hcml6ZShtZWRpYW5fdmFsdWUgPSBtZWRpYW4oQkVEUywgbmEucm0gPSBUUlVFKSkKYGBgCgpMZXQncyBhbHNvIGNhbGN1bGF0ZSB0aGUgbWVkaWFuIG51bWJlciBvZiBDb3ZpZC0xOSBjYXNlcyBwZXIgY291bnRyeS4KYGBge3J9CiNkZiAlPiUgc3VtbWFyaXplKG1lYW5fdmFsdWUgPSBtZWFuKE5VTUVSSUNfVkFSSUFCTEUsIG5hLnJtID0gVFJVRSkpCgpjYXNlcyAlPiUgCiAgZ3JvdXBfYnkoQ291bnRyeS5SZWdpb24pICU+JQogIHN1bW1hcml6ZShUb3RhbC5DYXNlcyA9IHN1bShUb3RhbC5DYXNlcywgbmEucm0gPSBUUlVFKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIHN1bW1hcml6ZShtZWRpYW5fdmFsdWUgPSBtZWRpYW4oVG90YWwuQ2FzZXMsIG5hLnJtID0gVFJVRSkpCmBgYAoKTm90aWNlIGhvdyB0aGVyZSdzIGEgY29uc2lkZXJhYmxlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgbWVhbiBhbmQgdGhlIG1lZGlhbiB2YWx1ZSBhY3Jvc3MgYm90aCBvZiB0aGVzZSBzZXRzIG9mIGNhbGN1bGF0aW9ucy4gU28gd2hpY2ggc2hvdWxkIHdlIHJlbHkgb24gdG8gc3VtbWFyaXplIHRoZSBjZW50cmFsIGxvY2F0aW9uIGluIG91ciBkYXRhc2V0PyAKCldlIHdhbnQgdG8ga2VlcCBpbiBtaW5kIHRoYXQgYmVjYXVzZSB0aGUgbWVhbiBpcyBhIG1vZGVsIG9mIHRoZSBlbnRpcmUgZGF0YXNldCwgaXQgaXMgZWFzaWx5IGluZmx1ZW5jZWQgYnkgb3V0bGllcnMgaW4gdGhlIGRhdGFzZXQsIGFzIHdlbGwgYXMgYSBza2V3ZWQgZGlzdHJpYnV0aW9uLiBXaGVuIHRoZSBkaXN0cmlidXRpb24gb2YgdmFsdWVzIGluIGEgc2V0IGlzIG5vcm1hbCwgdGhlIG1lYW4gYW5kIG1lZGlhbiBvZiB0aGUgZGF0YXNldCB3aWxsIGJlIHRoZSBzYW1lIGJlY2F1c2UgdGhlIHZhbHVlcyBvbiBlaXRoZXIgc2lkZSBvZiB0aGUgbWlkZGxlIHZhbHVlIHdpbGwgYmUgc3ltbWV0cmljYWwuIEluIG90aGVyIHdvcmRzLCB0aGUgZGlzdHJpYnV0aW9uIHdpbGwgYmUgYmFsYW5jZWQgb24gZWl0aGVyIHNpZGUgb2YgdGhlIG1lZGlhbi4gRnJlcXVlbmN5IHBsb3RzIGdpdmUgdXMgYSBnb29kIGluZGljYXRpb24gb2YgdGhlIGRpc3RyaWJ1dGlvbiBvZiB2YWx1ZXMgdGhlIGRhdGFzZXQuIAoKYGBge3IgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9MTB9Cmhvc3BpdGFscyAlPiUgCiAgZmlsdGVyKFNUQVRVUyA9PSAiT1BFTiIgJiBUWVBFID09ICJHRU5FUkFMIEFDVVRFIENBUkUiKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBCRURTKSkgKwogIGdlb21fZnJlcXBvbHkoYmlud2lkdGggPSAxMCkgKyAKICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBCZWRzIGFjcm9zcyBHZW5lcmFsIEFjdXRlIENhcmUgSG9zcGl0YWxzIGluIHRoZSBVUyB0aGF0IGFyZSBPcGVuIiwgeCA9ICJCZWRzIiwgeSA9ICJDb3VudCBvZiBIb3NwaXRhbHMiKSArCiAgdGhlbWVfYncoKQpgYGAKCgpgYGB7ciBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD0xMH0KY2FzZXMgJT4lIAogIGdyb3VwX2J5KENvdW50cnkuUmVnaW9uKSAlPiUKICBzdW1tYXJpemUoVG90YWwuQ2FzZXMgPSBzdW0oVG90YWwuQ2FzZXMsIG5hLnJtID0gVFJVRSkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBUb3RhbC5DYXNlcykpICsgCiAgZ2VvbV9mcmVxcG9seShiaW53aWR0aCA9IDEwMDAwKSArCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgQ2FzZXMgYWNyb3NzIENvdW50cmllcyIsIHggPSAiVG90YWwgQ2FzZXMiLCB5ID0gIkNvdW50IG9mIENvdW50cmllcyIpICsgIyBUbyBhZGQgdGl0bGVzIGFuZCBsYWJlbHMKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdD0xKSkgKyAjVHVybiBsYWJlbHMgOTAgZGVncmVlcwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmNvbW1hKSAjQ2hhbmdlIGxhYmVscyBmcm9tIHNjaWVudGlmaWMgdG8gY29tbWEgbm90YXRpb24KYGBgCgpZb3UnbGwgbm90aWNlIGluIHRoZSBob3NwaXRhbHMgYW5kIHRoZSBjYXNlcyBkYXRhc2V0LCB0aGUgdmFsdWVzIG9mIGFyZSBzaWduaWZpY2FudGx5IHJpZ2h0LXNrZXdlZC4gV2UgY2FuIHRlbGwgYmVjYXVzZSB0aGUgdmFsdWVzIHJlcHJlc2VudGVkIG9uIHRoZSBwbG90IGFyZSBmYXIgZnJvbSBzeW1tZXRyaWNhbC4gSW5zdGVhZCwgdGhlcmUgaXMgYSBsb25nIHRhaWwgcnVubmluZyB0byB0aGUgcmlnaHQgb2YgdGhlIGRhdGEuIEluIHN1Y2ggY2FzZXMsIHRoZSBtZWFuIGlzIGdvaW5nIHRvIGJlIHNpZ25pZmljYW50bHkgaW5mbHVlbmNlZCBieSB0aGUgbGFyZ2VyIHZhbHVlcyBpbiB0aGUgZGF0YSBldmVuIHRob3VnaCB0aGVyZSBhcmUgZmFyIGZld2VyLiAKCldoZW4gdGhlIHZhbHVlcyBpbiBhIGZyZXF1ZW5jeSBwbG90IGFyZSBza2V3ZWQgdG8gdGhlIGxlZnQgb3IgdGhlIHJpZ2h0LCB3ZSBvZnRlbiB3YW50IHRvIHJlbHkgb24gdGhlIG1lZGlhbiByYXRoZXIgdGhhbiB0aGUgbWVhbiBhcyBhIG1lYXN1cmUgb2YgY2VudHJhbCB0ZW5kZW5jeSwgYXMgaXQgbW9yZSBjbGVhcmx5IGRpc3Rpbmd1aXNoZXMgdGhlIGNlbnRyYWwgbG9jYXRpb24gaW4gdGhlIGRhdGEuIEluIHRoZSBob3NwaXRhbHMgYW5kIHRoZSBjYXNlcyBkYXRhc2V0LCBtZWRpYW4gaXMgYSBiZXR0ZXIgaW5kaWNhdG9yIG9mIGNlbnRyYWwgdGVuZGVuY3kgdGhhbiB0aGUgbWVhbi4gSG93ZXZlciwgYm90aCBzdGlsbCBzaWduaWZpY2FubHRseSBnbG9zcyBvdmVyIHRoZSBkaXNwZXJzaW9uIG9mIHZhbHVlcyBpbiB0aGUgZGF0YS4gCgpXZSBhbHNvIG5lZWQgdG8gYmUgY2FyZWZ1bCB3aGVuIHRha2luZyBtZWFzdXJlcyBvZiBjZW50cmFsIHRlbmRlbmN5IHRoYXQgd2UgZG8gbm90IGF0dGVtcHQgdG8gdGFrZSBhbiBhdmVyYWdlIG9mIGFuIGF2ZXJhZ2UuIExldCBtZSBwcm92aWRlIGFuIGV4bWFwbGUgb2Ygd2h5IHRoaXMgaXMgaW5hcHByb3ByaWF0ZS4gTGV0J3Mgc2F5IEkgd2VyZSB0byBmaW5kIHRoZSBhdmVyYWdlIG51bWJlciBvZiBiZWRzIGF0IG9wZW4gZ2VuZXJhbCBhY3V0ZSBob3NwaXRhbHMgcGVyIHN0YXRlIHVzaW5nIGdyb3VwX2J5KCkgYW5kIHN1bW1hcml6ZSgpLgoKYGBge3J9CmF2Z19ieV9zdGF0ZSA8LSAKICBob3NwaXRhbHMgJT4lIAogIGZpbHRlcihTVEFUVVMgPT0gIk9QRU4iICYgVFlQRSA9PSAiR0VORVJBTCBBQ1VURSBDQVJFIikgJT4lCiAgZ3JvdXBfYnkoU1RBVEUpICU+JQogIHN1bW1hcml6ZShtZWFuX3ZhbHVlID0gbWVhbihCRURTLCBuYS5ybSA9IFRSVUUpKSAlPiUKICB1bmdyb3VwKCkgCgphdmdfYnlfc3RhdGUKYGBgCgpJbiB0YWtpbmcgdGhlIG1lYW4gb2YgdGhlIG1lYW5fdmFsdWUgY29sdW1uIHdlIGp1c3QgY3JlYXRlZCAoaS5lLiBhbiBhdmVyYWdlIG9mIHRoZSBzdGF0ZSBhdmVyYWdlcyksIHlvdSB3aWxsIG5vdGljZSB0aGF0IHdlIGdldCBhIGRpZmZlcmVudCB2YWx1ZSB0aGFuIHRoZSBtZWFuIHdlIGNhbGN1bGF0ZWQgYWJvdmU6CgpgYGB7cn0KI01lYW4gb2YgQkVEUyBhY3Jvc3MgYWxsIG9ic2VydmF0aW9ucwphdmdfYWNyb3NzX2FsbF9vYnMgPC0KICBob3NwaXRhbHMgJT4lIAogIGZpbHRlcihTVEFUVVMgPT0gIk9QRU4iICYgVFlQRSA9PSAiR0VORVJBTCBBQ1VURSBDQVJFIikgJT4lCiAgc3VtbWFyaXplKG1lYW5fdmFsdWUgPSBtZWFuKEJFRFMsIG5hLnJtID0gVFJVRSkpCgojTWVhbiBvZiBCRURTIGFjcm9zcyBhbGwgc3RhdGUgYXZlcmFnZXMKYXZnX2Fjcm9zc19zdGF0ZV9hdmdzIDwtCiAgYXZnX2J5X3N0YXRlICU+JQogIHN1bW1hcml6ZShtZWFuX3ZhbHVlID0gbWVhbihtZWFuX3ZhbHVlLCBuYS5ybSA9IFRSVUUpKQoKI0NoZWNrIGlmIHRoZXkgYXJlIGVxdWFsCnBhc3RlKCJXaGVuIHdlIGNoZWNrIGlmIiwgYXZnX2Fjcm9zc19hbGxfb2JzLCAiKHRoZSBtZWFuIG9mIEJFRFMgYWNyb3NzIGFsbCBvYnNlcnZhdGlvbnMpIGlzIGVxdWFsIHRvIiwgYXZnX2Fjcm9zc19zdGF0ZV9hdmdzLCAiKHRoZSBtZWFuIG9mIEJFRFMgYWNyb3NzIHN0YXRlIGF2ZXJhZ2VzKSB0aGUgcmVzdWx0IGlzIiwgYXZnX2Fjcm9zc19hbGxfb2JzID09IGF2Z19hY3Jvc3Nfc3RhdGVfYXZncykKYGBgCgpUaGlzIGlzIGJlY2F1c2Ugd2hlbiB3ZSB0YWtlIGFuIGF2ZXJhZ2Ugb2YgYXZlcmFnZXMsIHdlIGFyZSBpZ25vcmluZyBhIGtleSBjb25mb3VuZGluZyB2YXJpYWJsZSAtIHRoZSBzaXplIG9mIHRoZSBkZW5vbWluYXRvciBpbiBlYWNoIG9mIHRoZSBzdGF0ZSBhdmVyYWdlcy4gV2Uga25vdyB0aGF0IHRoZXJlIGFyZSBkaWZmZXJlbnQgbnVtYmVycyBvZiBob3NwaXRhbHMgaW4gZWFjaCBzdGF0ZS4gV2hlbiB3ZSB0YWtlIHRoZSBtZWFuIGFjcm9zcyBhbGwgc3RhdGUgYXZlcmFnZXMsIHdlIGJhc2ljYWxseSBpZ25vcmUgdGhpcyB2YXJpYWJsZSAtIHByb2R1Y2luZyBhIGRpZmZlcmVudCBtZWFuIHRoYW4gaWYgd2Ugd2VyZSB0byBjYWxjdWxhdGUgbWVhbiBhY3Jvc3MgYWxsIG9ic2VydmF0aW9ucyBpbiB0aGUgc2V0LiBUaGlzIGNhbiBoYXZlIGRyYW1hdGljIGNvbnNlcXVlbmNlcyBvbiB0aGUgdmFsdWVzIHJlcG9ydGVkIGluIG91ciBkYXRhLiAKClBsZWFzZSB3YXRjaCB0aGlzIHNob3J0IHZpZGVvIG9uIFNpbXBvbidzIFBhcmFkb3ggdG8gbGVhcm4gbW9yZSBhYm91dCB0aGUgaW1wb3J0YW5jZSBvZiBhdm9pZGluZyB0aGlzIHBpdGZhbGw6Cgo8aWZyYW1lIHdpZHRoPSI1NjAiIGhlaWdodD0iMzE1IiBzcmM9Imh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL2VtYmVkL2ViRWtuLUJpVzVrIiBmcmFtZWJvcmRlcj0iMCIgYWxsb3c9ImFjY2VsZXJvbWV0ZXI7IGF1dG9wbGF5OyBlbmNyeXB0ZWQtbWVkaWE7IGd5cm9zY29wZTsgcGljdHVyZS1pbi1waWN0dXJlIiBhbGxvd2Z1bGxzY3JlZW4+PC9pZnJhbWU+CgpUaGlzIGlzIGFuIGlzc3VlIHdlIHdvdWxkIG5lZWQgdG8ga2VlcCBpbiBtaW5kIHdoZW4gY2FsY3VsYXRpbmcgbWVhc3VyZXMgb2YgY2VudHJhbCB0ZW5kZW5jeSBpbiBvdXIgd29ybGRfaGVhbHRoX2Vjb24gZGF0YXNldC4gVGhlIG1ham9yaXR5IG9mIHRoZSB2YXJpYWJsZXMgcmVwb3J0ZWQgaW4gdGhlIHdvcmxkX2hlYWx0aF9lY29uIGRhdGFzZXQgYXJlIGFscmVhZHkgYXZlcmFnZXMgLSBlaXRoZXIgYXZlcmFnZXMgYWNyb3NzIHRoZSBwb3B1bGF0aW9uIG9mIHRoZSBjb3VudHJ5IG9yIGF2ZXJhZ2VzIGFjcm9zcyB0aGUgY291bnRyeSdzIHRvdGFsIHNwZW5kaW5nIG9uIGhlYWx0aC4gQmVjYXVzZSBvZiB0aGlzLCBpdCB3b3VsZCBiZSBpbmFwcHJvcHJpYXRlIHRvIGNhbGN1bGF0ZSBtZWFzdXJlcyBvZiBjZW50cmFsIHRlbmRlbmN5IGFjcm9zcyB0aGVzZSB2YXJpYWJsZXMgd2l0aG91dCBrbm93aW5nIHRoZWlyIGRlbm9taW5hdG9ycy4gCgo+IFlvdSBtaWdodCBiZSB0aGlua2luZywgIldlbGwgZG9uJ3Qgd2UgaGF2ZSBwb3B1bGF0aW9uIGFzIGFub3RoZXIgdmFyaWFibGUgaW4gdGhlIGRhdGFzZXQuIERvZXNuJ3QgdGhhdCB0ZWxsIHVzIHRoZSBkZW5vbWluYXRvciBvZiBzb21lIG9mIHRoZSBhdmVyYWdlcz8iIFRoYXQgaXMgY29ycmV0LiBIb3dldmVyLCBsb29raW5nIGF0IG91ciBkYXRhIGRpY3Rpb25hcnkgeW91IHdpbGwgbm90aWNlIHRoYXQgdGhlIHBvcHVsYXRpb24gdmFyaWFibGUgaW4gdGhlIGRhdGFzZXQgaXMgZGVyaXZlZCBmcm9tIGEgZGlmZmVyZW50IHNvdXJjZSB0aGFuIHRoZSBoZWFsdGggZWNvbm9taWNzIGluZGljYXRvcnMuIFdoaWxlIHdlIGNhbiBleHBlY3QgdGhlc2UgbnVtYmVycyB0byBiZSBpbiBwcm94aW1pdHksIGRpZmZlcmVudCBvcmdhbml6YXRpb25zIGNvdW50IHRoZSBudW1iZXIgb2YgcGVvcGxlIGluIGEgY291bnRyeSBkaWZmZXJlbnRseS4gVGhpcyB2YWx1ZSBtaWdodCBub3QgYWNjdXJhdGVseSByZWZsZWN0IHRoZSBkZW5vbWluYXRvciBvZiBtYW55IG9mIG91ciBoZWFsdGggZWNvbm9taWNzIGluZGljYXRvcnMuIAoKIyMjIE1lYXN1cmVzIG9mIENlbnRyYWwgVGVuZGVuY3kgaW4geW91ciBPd24gRGF0YXNldAoKIyMjIyBDYWxjdWxhdGUgdGhlIG1lYW4gYW5kIG1lZGlhbiBvZiBhIG51bWVyaWMgdmFyaWFibGUgaW4geW91ciBkYXRhc2V0LiAKCkJlIHN1cmUgdG8gZmlsdGVyIHlvdXIgZGF0YXNldCB0byBlbnN1cmUgdGhhdCB5b3UgYXJlIHN1bW1hcml6aW5nIGFjcm9zcyBzaW1pbGFyIG9ic2VydmF0aW9ucy4gQWxzbyBiZSBzdXJlIHRvIGF2b2lkIGF2ZXJhZ2luZyBhbiBhdmVyYWdlLiAgCgpgYGB7cn0KI0ZpbGwgeW91ciBjb2RlIGhlcmUuIApgYGAKCldoYXQgcXVlc3Rpb24gbWlnaHQgdGhlc2UgbWVhc3VyZXMgb2YgY2VudHJhbCB0ZW5kZW5jeSBoZWxwIHRvIGFkZHJlc3M/CgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4gCmBgYAoKQ3JlYXRlIGEgZnJlcXVlbmN5IHBsb3Qgb2YgdGhlIG51bWVyaWMgdmFyaWFibGUgeW91IHByb2R1Y2VkIGNhbGN1bGF0aW9ucyBvZiBhYm92ZS4gKFlvdSBtYXkgaGF2ZSBjcmVhdGVkIHRoaXMgbGFzdCB3ZWVrLCBhbmQgeW91IG1heSBjb3B5IGFuZCBwYXN0ZSBpdCBmcm9tIHRoZSBwcmV2aW91cyBsYWIuKQoKYGBge3IgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9MTB9CiNDcmVhdGUgYSBmcmVxdWVuY3kgcGxvdCBoZXJlLiAKYGBgCgpDaGFyYWN0ZXJpemUgdGhlIGRpc3RyaWJ1dGlvbiBvZiB2YWx1ZXMgaW4gdGhlIGZyZXF1ZW5jeSBwbG90IHlvdSBjcmVhdGVkLiBJcyBpdCBzeW1tZXRyaWNhbCBvciBza2V3ZWQ/IAoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCB5b3VyIHJlc3BvbnNlIGhlcmUuIApgYGAKCldoaWNoIHZhbHVlIGlzIG1vcmUgYXBwcm9wcmlhdGUgYXMgYSBtZWFzdXJlIG9mIGNlbnRyYWwgdGVuZGVuY3kgaW4geW91ciBkYXRhPyAKCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgeW91ciByZXNwb25zZSBoZXJlLiAKYGBgCgpDaGFyYWN0ZXJpemUgdGhlIGV4dGVudCB0byB3aGljaCB0aGUgdmFsdWUgeW91IHNlbGVjdGVkIGFzIGEgbWVhc3VyZSBvZiBjZW50cmFsIHRlbmRlbmN5IGFib3ZlIChtZWFuIG9yIG1lZGlhbikgaXMgcmVwcmVzZW50YXRpdmUgb2YgeW91ciBkYXRhLiBXaGF0IHN0b3J5IGlzIHRvbGQgd2hlbiB3ZSByZWx5IG9uIHRoaXMgbnVtYmVyIGFzIGEgc3VtbWFyeSBvZiB0aGUgZGF0YT8gCgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4gCmBgYAoKSWYgd2Ugd2VyZSB0byB1c2UgdGhpcyBzaW5nbGUgdmFsdWUgdG8gc3VtbWFyaXplIHRoaXMgdmFyaWFibGUsIHdoYXQgbmFycmF0aXZlcyB3b3VsZCBiZSBsZWZ0IG91dD8gSG93IGRvZXMgdGhlIGNvbXBsZXhpdHkgb2YgdGhlIG5hcnJhdGl2ZXMgaW4geW91ciBkYXRhIGdldCByZWR1Y2VkIGluIGNhbGN1bGF0aW5nIHRoaXMgdmFsdWUuIAoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCB5b3VyIHJlc3BvbnNlIGhlcmUuIApgYGAKCiMjIyMgU2VsZWN0IGFub3RoZXIgbnVtZXJpYyB2YXJpYWJsZSBpbiB5b3VyIGRhdGFzZXQgYW5kIGNhbGN1bGF0ZSBib3RoIHRoZSBtZWFuIGFuZCB0aGUgbWVkaWFuLiAKCkJlIHN1cmUgdG8gZmlsdGVyIHlvdXIgZGF0YXNldCB0byBlbnN1cmUgdGhhdCB5b3UgYXJlIHN1bW1hcml6aW5nIGFjcm9zcyBzaW1pbGFyIG9ic2VydmF0aW9ucy4gQWxzbyBiZSBzdXJlIHRvIGF2b2lkIGF2ZXJhZ2luZyBhbiBhdmVyYWdlLiAKCmBgYHtyfQojRmlsbCB5b3VyIGNvZGUgaGVyZS4gCmBgYAoKV2hhdCBxdWVzdGlvbiBtaWdodCB0aGVzZSBtZWFzdXJlcyBvZiBjZW50cmFsIHRlbmRlbmN5IGhlbHAgdG8gYWRkcmVzcz8KCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgeW91ciByZXNwb25zZSBoZXJlLiAKYGBgCgpDcmVhdGUgYSBmcmVxdWVuY3kgcGxvdCBvZiB0aGUgbnVtZXJpYyB2YXJpYWJsZSB5b3UgcHJvZHVjZWQgY2FsY3VsYXRpb25zIG9mIGFib3ZlLiAoWW91IG1heSBoYXZlIGNyZWF0ZWQgdGhpcyBsYXN0IHdlZWssIGFuZCB5b3UgbWF5IGNvcHkgYW5kIHBhc3RlIGl0IGZyb20gdGhlIHByZXZpb3VzIGxhYi4pCgpgYGB7ciBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD0xMH0KI0NyZWF0ZSBhIGZyZXF1ZW5jeSBwbG90IGhlcmUuIApgYGAKCkNoYXJhY3Rlcml6ZSB0aGUgZGlzdHJpYnV0aW9uIG9mIHZhbHVlcyBpbiB0aGUgZnJlcXVlbmN5IHBsb3QgeW91IGNyZWF0ZWQuIElzIGl0IHN5bW1ldHJpY2FsIG9yIHNrZXdlZD8gCgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4gCmBgYAoKV2hpY2ggdmFsdWUgaXMgbW9yZSBhcHByb3ByaWF0ZSBhcyBhIG1lYXN1cmUgb2YgY2VudHJhbCB0ZW5kZW5jeSBpbiB5b3VyIGRhdGE/IAoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCB5b3VyIHJlc3BvbnNlIGhlcmUuIApgYGAKCldoYXQgc3RvcnkgZG8gdGhlc2UgY2FsY3VsYXRpb25zIHRlbGw/IFdvdWxkIHlvdSBzZWxlY3QgdGhlIG1lZGlhbiBvciB0aGUgbWVhbiBhcyBhIG1lYXN1cmUgb2YgY2VudHJhbCB0ZW5kZW5jeT8gV2h5PwoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCB5b3VyIHJlc3BvbnNlIGhlcmUuIApgYGAKCkNoYXJhY3Rlcml6ZSB0aGUgZXh0ZW50IHRvIHdoaWNoIHRoZSB2YWx1ZSB5b3Ugc2VsZWN0ZWQgYXMgYSBtZWFzdXJlIG9mIGNlbnRyYWwgdGVuZGVuY3kgYWJvdmUgaXMgcmVwcmVzZW50YXRpdmUgb2YgeW91ciBkYXRhLiAKCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgeW91ciByZXNwb25zZSBoZXJlLiAKYGBgCgpJZiB3ZSB3ZXJlIHRvIHVzZSB0aGlzIHNpbmdsZSB2YWx1ZSB0byBzdW1tYXJpemUgdGhpcyB2YXJpYWJsZSwgd2hhdCBuYXJyYXRpdmVzIHdvdWxkIGJlIGxlZnQgb3V0PyBIb3cgZG9lcyB0aGUgY29tcGxleGl0eSBvZiB0aGUgbmFycmF0aXZlcyBpbiB5b3VyIGRhdGEgZ2V0IHJlZHVjZWQgaW4gY2FsY3VsYXRpbmcgdGhpcyB2YWx1ZS4gCgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4gCmBgYAoKQXMgd2UndmUgYmVlbiBkaXNjdXNzaW5nIGluIGNsYXNzLCBhbnkgbWVhc3VyZSB0aGF0IHdlIGNhbGN1bGF0ZSBpcyBtZWRpYXRlZCBieSB0aGUgd2F5IHRoZSBwaGVub21lbmEgd2UgYXJlIG1lYXN1cmluZyBnZXRzIGRlZmluZWQuIEhvdyB3ZXJlIHRoZSBudW1lcmljIHZhcmlhYmxlcyB0aGF0IHlvdSBzZWxlY3RlZCBkZWZpbmVkPyBXaGF0IHdhcyBpbmNsdWRlZCBpbiB0aGVzZSBkZWZpbml0aW9ucywgYW5kIHdoYXQgcG90ZW50aWFsbHkgcmVsZXZhbnQgdmFsdWVzIHdlcmUgZXhjbHVkZWQ/CgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4gCmBgYAoKIyMgTWVhc3VyZXMgb2YgRGlzcGVyc2lvbgoKTWVhc3VyZXMgb2YgZGlzcGVyc2lvbiBoZWxwIHVzIHRvIHVuZGVyc3RhbmQgaG93IHNwcmVhZCBvdXQgdGhlIHZhbHVlcyBpbiBvdXIgZGF0YXNldCBhcmUgLSB0aGVpciB2YXJpYXRpb25zIGZyb20gZWFjaCBvdGhlciBhbmQgZnJvbSB0aGUgZGF0YSdzIGNlbnRlci4gTGlrZSBtZWFzdXJlcyBvZiBjZW50cmFsIHRlbmRlbmN5LCBtZWFzdXJlcyBvZiBkaXNwZXJzaW9uIHNob3VsZCBiZSB0YWtlbiBhY3Jvc3MgYSBzZXQgb2YgZGF0YSB3aXRoIHNpbWlsYXIgdmFsdWVzLiBUaGlzIG9mdGVuIG1lYW5zIGZpbHRlcmluZyBvdXIgZGF0YSB0byB0aG9zZSB0aGF0IHJlcHJlc2VudCBhIHNpbWlsYXIgc2V0IG9mIG9ic2VydmF0aW9ucy4KCiMjIyBSYW5nZXMKClRoZSByYW5nZSBvZiBkYXRhIHJlZmVycyB0byB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBtYXhpbXVtIHZhbHVlIGluIGEgc2V0IGFuZCB0aGUgbWluaW11bSB2YWx1ZSBpbiBhIHNldC4gV2UgY2FuIGFsc28gdXNlIHN1bW1hcml6ZSgpIHRvIGZpbmQgdGhlIG1heCB2YWx1ZSwgbWluIHZhbHVlLCBhbmQgcmFuZ2Ugb2YgdmFsdWVzIGluIGEgbnVtZXJpYyB2YXJpYWJsZS4gCgpgYGB7cn0KI2RmICU+JSBzdW1tYXJpemUobWF4X3ZhbHVlID0gbWF4KE5VTUVSSUNfVkFSSUFCTEUsIG5hLnJtID0gVFJVRSkpCmhvc3BpdGFscyAlPiUgCiAgZmlsdGVyKFNUQVRVUyA9PSAiT1BFTiIgJiBUWVBFID09ICJHRU5FUkFMIEFDVVRFIENBUkUiKSAlPiUKICBzdW1tYXJpemUobWF4X3ZhbHVlID0gbWF4KEJFRFMsIG5hLnJtID0gVFJVRSkpCgojZGYgJT4lIHN1bW1hcml6ZShtaW5fdmFsdWUgPSBtaW4oTlVNRVJJQ19WQVJJQUJMRSwgbmEucm0gPSBUUlVFKSkKaG9zcGl0YWxzICU+JSAKICBmaWx0ZXIoU1RBVFVTID09ICJPUEVOIiAmIFRZUEUgPT0gIkdFTkVSQUwgQUNVVEUgQ0FSRSIpICU+JQogIHN1bW1hcml6ZShtaW5fdmFsdWUgPSBtaW4oQkVEUywgbmEucm0gPSBUUlVFKSkKCiNkZiAlPiUgc3VtbWFyaXplKHJhbmdlID0gbWF4KE5VTUVSSUNfVkFSSUFCTEUsIG5hLnJtID0gVFJVRSkgLSBtaW4oTlVNRVJJQ19WQVJJQUJMRSwgbmEucm0gPSBUUlVFKSkKaG9zcGl0YWxzICU+JSAKICBmaWx0ZXIoU1RBVFVTID09ICJPUEVOIiAmIFRZUEUgPT0gIkdFTkVSQUwgQUNVVEUgQ0FSRSIpICU+JQogIHN1bW1hcml6ZShyYW5nZSA9IG1heChCRURTLCBuYS5ybSA9IFRSVUUpIC0gbWluKEJFRFMsIG5hLnJtID0gVFJVRSkpCmBgYAoKIyMjIFF1YXJ0aWxlIERldmlhdGlvbgoKRXZlbiB0aG91Z2ggd2UgYXJlIGludHJvZHVjaW5nIHRoZSBib3hwbG90IGluIHJlbGF0aW9uIHRvIHF1YXJ0aWxlIGRldmlhdGlvbiwgaXQgY2FuIGJlIGEgdG9vbCBmb3Igc3VtbWFyaXppbmcgYSBudW1iZXIgb2YgcXVhbnRpdGF0aXZlIGluc2lnaHRzIGluIHJlbGF0aW9uIHRvIGEgbnVtZXJpY2FsIHZhcmlhYmxlIGluIG91ciBkYXRhc2V0LiBCb3hwbG90cyBwcm92aWRlIGEgdmlzdWFsIHJlcHJlc2VudGF0aW9uIG9mIGJvdGggbWVhc3VyZXMgb2YgY2VudHJhbCB0ZW5kZW5jeSBhbmQgbWVhc3VyZXMgb2YgZGlzcGVyc2lvbi4gVGhlIGNlbnRlciBsaW5lIGluIGEgYm94cGxvdCBpbmRpY2F0ZXMgdGhlIG1lZGlhbiBvZiB0aGUgZGF0YXNldC4gVGhlIGJvdHRvbSBvZiB0aGUgYm94IHJlcHJlc2VudHMgdGhlIDFzdCBxdWFydGlsZSAtIHRoZSB2YWx1ZSBpbiB0aGUgbWlkZGxlIG9mIHRoZSBtaW5pbXVtIGFuZCB0aGUgbWVkaWFuIChvciB0aGUgdGhlIHZhbHVlIGF0IHRoZSAxc3QgcXVhcnRlciBwb3NpdGlvbikuIFRoZSB0b3Agb2YgdGhlIGJveCByZXByZXNlbnRzIHRoZSAzcmQgcXVhcnRpbGUgLSB0aGUgdmFsdWUgaW4gdGhlIG1pZGRsZSBvZiB0aGUgbWVkaWFuIGFuZCB0aGUgbWF4aW11bSAob3IgdGhlIHZhbHVlIGF0IHRoZSAzcmQgcXVhcnRlciBwb3NpdGlvbikuIFRoZSB3aGlza2VycyBpbmNsdWRlIGFsbW9zdCBhbGwgb2YgdGhlIGRhdGEgLSBpbmRpY2F0aW5nIGl0cyByYW5nZSBmcm9tIG1pbmltdW0gdG8gbWF4aW11bSBleGNsdWRpbmcgb3V0bGllcnMuIFRoZSBkb3RzIHJlcHJlc2VudCBvdXRsaWVycy4gZ2dwbG90IGhhcyBhIGNhbGN1bGF0aW9uIGZvciBvdXRsaWVycyB0aGF0IHdlIG5lZWQgbm90IGdvIGludG8gaW4gdGhpcyBjb3Vyc2UuCgpUaGUgZnVydGhlciB0aGUgMXN0IGFuZCAzcmQgcXVhcnRpbGUgYXJlIGZyb20gdGhlIG1lZGlhbiAob3IsIGluIG90aGVyIHdvcmRzLCB0aGUgd2lkZXIgdGhlIGJveCksIHRoZSBncmVhdGVyIHRoZSAqcXVhcnRpbGUgZGV2aWF0aW9uLiogSW4gZ2VuZXJhbCwgYSBuYXJyb3dlciBib3ggYW5kIHdoaXNrZXJzIGluZGljYXRlcyBsZXNzIGRpc3BlcnNpb24gaW4gdGhlIGRhdGEsIHdoaWxlIGEgd2lkZXIgYm94IGFuZCB3aGlza2VycyBpbmRpY2F0ZXMgZ3JlYXRlciBkaXNwZXJzaW9uLiAgCgpMZXQncyB1c2UgYSBib3hwbG90IHRvIGNoZWNrIG91dCB0aGUgcXVhcnRpbGUgZGV2aWF0aW9uIG9mIGJlZHMgaW4gb3BlbiBnZW5lcmFsIGFjdXRlIGNhcmUgaG9zcGl0YWxzIGluIHRoZSBVUy4KCmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTV9CiNkZiAlPiUgZ2dwbG90KGFlcyh5ID0gTlVNRVJJQ19WQVJJQUJMRSkpICsgZ2VvbV9ib3hwbG90KCkgKyB0aGVtZV9idygpCgpob3NwaXRhbHMgJT4lCiAgZmlsdGVyKFNUQVRVUyA9PSAiT1BFTiIgJiBUWVBFID09ICJHRU5FUkFMIEFDVVRFIENBUkUiKSAlPiUKICBnZ3Bsb3QoYWVzKHkgPSBCRURTKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBCZWRzIGFjcm9zcyBHZW5lcmFsIEFjdXRlIENhcmUgSG9zcGl0YWxzIGluIHRoZSBVUyB0aGF0IGFyZSBPcGVuIiwgeSA9ICJCZWRzIikgKwogIHRoZW1lX2J3KCkKYGBgCj4gTm90ZSBob3cgd2UgY2FuIHRpdGxlIGEgYm94cGxvdCB2ZXJ5IHNpbWlsYXJseSB0byBob3cgd2UgdGl0bGUgYSBmcmVxdWVuY3kgcGxvdC4gQm90aCBzaG93IGRpc3RyaWJ1dGlvbnMgb2YgdmFsdWVzLiAKCldlIGNhbiBzZWUgZnJvbSB0aGlzIHBsb3QgdGhhdCB0aGUgcXVhcnRpbGUgZGV2aWF0aW9uIGlzIG11Y2ggc21hbGxlciB0aGFuIHRoZSByYW5nZSBpbiBvdXIgZGF0YXNldC4gVGhpcyBzdWdnZXN0cyB0aGF0IGNlbnRlcmVkIHZhbHVlcyBhcmUgbW9yZSBjb25jZW50cmF0ZWQgdGhhbiB0aGUgZXh0cmVtZXMuIAoKIyMjIFN0YW5kYXJkIERldmlhdGlvbgoKKlN0YW5kYXJkIGRldmlhdGlvbiogY2FsY3VsYXRlcyB0aGUgZXh0ZW50IG9mIGNvbmNlbnRyYXRpb24gb2YgdmFsdWVzIGFyb3VuZCB0aGUgbWVhbi4gQSBoaWdoZXIgc3RhbmRhcmQgZGV2aWF0aW9uIGluZGljYXRlcyB0aGF0IHZhbHVlcyBhcmUgbW9yZSBkaXNwZXJzZWQgZnJvbSB0aGUgbWVhbiwgYW5kIGEgbG93ZXIgc3RhbmRhcmQgZGV2aWF0aW9uIGluZGljYXRlcyB0aGF0IHZhbHVlcyBhcmUgbW9yZSBjb25jZW50cmF0ZWQgYXJvdW5kIHRoZSBtZWFuLiAgCgpgYGB7cn0KI2RmICU+JSBzdW1tYXJpemUoc2RfdmFsdWUgPSBzZChOVU1FUklDX1ZBTFVFLCBuYS5ybSA9IFRSVUUpKQoKaG9zcGl0YWxzICU+JSAKICBmaWx0ZXIoU1RBVFVTID09ICJPUEVOIiAmIFRZUEUgPT0gIkdFTkVSQUwgQUNVVEUgQ0FSRSIpICU+JQogIHN1bW1hcml6ZShzZF92YWx1ZSA9IHNkKEJFRFMsIG5hLnJtID0gVFJVRSkpCmBgYAoKIyMjIE1lYXN1cmVzIG9mIERpc3BlcnNpb24gaW4gWW91ciBPd24gRGF0YXNldAoKIyMjIyBTZWxlY3Qgb25lIG9mIHRoZSBudW1lcmljIHZhcmlhYmxlcyBvbiB3aGljaCB5b3UgY2FsY3VsYXRlZCBhIG1lYXN1cmUgb2YgY2VudHJhbCB0ZW5kZW5jeSBhYm92ZSwgYW5kIGNhbGN1bGF0ZSB0aGUgbWF4aW11bSB2YWx1ZSwgdGhlIG1pbmltdW0gdmFsdWUsIGFuZCB0aGUgcmFuZ2Ugb2YgdmFsdWVzIHdpdGhpbiB0aGF0IHZhcmlhYmxlLgoKQmUgc3VyZSB0byBmaWx0ZXIgeW91ciBkYXRhc2V0IHRvIGVuc3VyZSB0aGF0IHlvdSBhcmUgc3VtbWFyaXppbmcgYWNyb3NzIHNpbWlsYXIgb2JzZXJ2YXRpb25zLgoKYGBge3J9CiNGaWxsIHlvdXIgY29kZSB0byBjYWxjdWxhdGUgbWF4IGhlcmUuIAoKI0ZpbGwgeW91ciBjb2RlIHRvIGNhbGN1bGF0ZSBtaW4gaGVyZS4gCgojRmlsbCB5b3VyIGNvZGUgdG8gY2FsY3VsYXRlIHJhbmdlIGhlcmUuIApgYGAKCldoYXQgcXVlc3Rpb24gbWlnaHQgdGhpcyBtZWFzdXJlIG9mIGRpc3BlcnNpb24gaGVscCB0byBhZGRyZXNzPwoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCB5b3VyIHJlc3BvbnNlIGhlcmUuIApgYGAKCkRvIHRoZSBudW1iZXJzIHN1cnByaXNlIHlvdT8gV2hhdCBpbnNpZ2h0IGNhbiB5b3UgZHJhdyBmcm9tIHRoaXMgY2FsY3VsYXRpb24/CgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4gCmBgYAoKIyMjIyBDcmVhdGUgYSBib3hwbG90IGZvciBvbmUgb2YgdGhlIG51bWVyaWMgdmFyaWFibGVzIG9uIHdoaWNoIHlvdSBjYWxjdWxhdGVkIGEgbWVhc3VyZSBvZiBjZW50cmFsIHRlbmRlbmN5IGFib3ZlLgoKQmUgc3VyZSB0byBmaWx0ZXIgeW91ciBkYXRhc2V0IHRvIGVuc3VyZSB0aGF0IHlvdSBhcmUgcGxvdHRpbmcgYWNyb3NzIHNpbWlsYXIgb2JzZXJ2YXRpb25zLiAKCmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTV9CiNGaWxsIHlvdXIgcGxvdCBoZXJlLiBCZSBzdXJlIHRvIGFkZCBhIHRpdGxlIGFuZCBsYWJlbHMgdG8geW91ciBwbG90LiAKYGBgCgpXaGF0IHF1ZXN0aW9uIG1pZ2h0IHRoaXMgbWVhc3VyZSBvZiBkaXNwZXJzaW9uIGhlbHAgdG8gYWRkcmVzcz8KCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgeW91ciByZXNwb25zZSBoZXJlLiAKYGBgCgpXaGF0IGluc2lnaHQgY2FuIHlvdSBkcmF3IGZyb20gdGhlIHBsb3QgeW91IGNyZWF0ZWQ/CgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4gCmBgYAoKCiMjIyBDYWxjdWxhdGUgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBmb3Igb25lIG9mIHRoZSBudW1lcmljIHZhcmlhYmxlcyBvbiB3aGljaCB5b3UgY2FsY3VsYXRlZCBhIG1lYXN1cmUgb2YgY2VudHJhbCB0ZW5kZW5jeSBhYm92ZS4KCkJlIHN1cmUgdG8gZmlsdGVyIHlvdXIgZGF0YXNldCB0byBlbnN1cmUgdGhhdCB5b3UgYXJlIHN1bW1hcml6aW5nIGFjcm9zcyBzaW1pbGFyIG9ic2VydmF0aW9ucy4gCgpgYGB7cn0KI0ZpbGwgeW91ciBjb2RlIGhlcmUuCmBgYAoKV2hhdCBxdWVzdGlvbiBtaWdodCB0aGlzIG1lYXN1cmUgb2YgZGlzcGVyc2lvbiBoZWxwIHRvIGFkZHJlc3M/CgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4gCmBgYAoKV2hhdCBpbnNpZ2h0IGNhbiB5b3UgZHJhdyBmcm9tIHRoaXMgY2FsY3VsYXRpb24/CgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4gCmBgYAoKTm93IHRoYXQgeW91IGhhdmUgYSBzZW5zZSBvZiB0aGUgZGlzcGVyc2lvbiBvZiBzb21lIG9mIHRoZSB2YWx1ZXMgaW4geW91ciBkYXRhLCB3aHkgZG8geW91IGJlbGlldmUgdGhlIHZhbHVlcyBhcmUgYXMgY29uY2VudHJhdGVkIG9yIGRpc3BlcnNlZCBhcyB0aGV5IGFyZT8gV2hhdCBkbyB0aGUgbWVhc3VyZXMgb2YgZGlzcGVyc2lvbiB5b3UgY2FsY3VsYXRlZCBzYXkgYWJvdXQgc29jaWFsLCBwb2xpdGljYWwsIG9yIGVjb25vbWljIGxpZmUgaW4gdGhlIGFyZWEgdGhlIGRhdGEgaXMgcmVwcmVzZW50aW5nPyBZb3UgbWF5IG5lZWQgdG8gZG8gc29tZSByZXNlYXJjaCB0byBhbnN3ZXIgdGhpcyBxdWVzdGlvbi4gRm9yIGluc3RhbmNlLCBub3RpbmcgdGhlIGRpc3BlcnNpb24gb2YgYmVkcyBpbiB0aGUgaG9zcGl0YWxzIGRhdGEsIEkgbWF5IGRvIGEgV2ViIHNlYXJjaCBmb3IgIldoeSBkbyBzb21lIGhvc3BpdGFscyBpbiB0aGUgVVMgaGF2ZSBtb3JlIGJlZHMgdGhhbiBvdGhlcnM/IiBhbmQgZmluZCBbdGhpc10oaHR0cHM6Ly93d3cubnl0aW1lcy5jb20vaW50ZXJhY3RpdmUvMjAyMC8wMy8xNy91cHNob3QvaG9zcGl0YWwtYmVkLXNob3J0YWdlcy1jb3JvbmF2aXJ1cy5odG1sKSBhcnRpY2xlLiBCZSBzdXJlIHRvIGFzc2VzcyB0aGUgcmVwdXRhYmlsaXR5IG9mIHlvdXIgc291cmNlIGFuZCBjaXRlIGl0IGluIHlvdXIgcmVzcG9uc2UgYmVsb3cuIAoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCB5b3VyIHJlc3BvbnNlIGhlcmUuIApgYGAKCiMjIEdyb3VwZWQgUXVhbnRpdGF0aXZlIEluc2lnaHRzIAoKTGlrZSB3ZSBsZWFybmVkIGluIHJlZ2FyZHMgdG8gY28tdmFyaWF0aW9uLCBzb21lIG9mIHRoZSBtb3N0IGludGVyZXN0aW5nIGluZm9ybWF0aW9uIHdlIGNhbiBnYWluIGZyb20gb3VyIGRhdGEgaXMgaG93IHZhbHVlcyBjaGFuZ2UgZGVwZW5kaW5nIG9uIHdoZXJlIGluIHRoZSBkYXRhIHdlIGFyZSBsb29raW5nLiAKCiMjIyBCb3hwbG90cwoKZ2dwbG90J3MgZ2VvbV9ib3hwbG90IGZlYXR1cmUgaXMgcGFydGljdWxhcmx5IGdvb2QgYXQgY29tcGFyaW5nIG1lYXN1cmVzIG9mIGRpc3BlcnNpb24gYWNyb3NzIGdyb3VwZWQgdmFsdWVzIGluIGEgY2F0ZWdvcmljYWwgdmFyaWFibGUuIEl0IGlzIHNldCB1cCB0byB2aXN1YWxpemUgc2V2ZXJhbCBib3hwbG90cyBzaWRlLWJ5LXNpZGUuIFdoZW4gd2UgZG8gaGF2ZSBkaXNzaW1pbGFyIG9ic2VydmF0aW9ucyBpbiBvdXIgZGF0YXNldCwgdGhpcyBpcyBhIHdheSB0byBjb21wYXJlIHRoZSBkaXNwZXJzaW9uIG9mIHZhbHVlcyBhY3Jvc3MgdGhlbS4gTGV0J3MgdGFrZSBhIGxvb2sgYXQgaG93IHdlIGNvdWxkIGNvbXBhcmUgZGlzcGVyc2lvbnMgaW4gdGhlIG51bWJlciBvZiBob3NwaXRhbCBiZWRzIGF2YWlsYWJsZSBieSBob3NwaXRhbCBvd25lcnNoaXAuIAoKYGBge3IgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9MTB9CiNkZiAlPiUgZ2dwbG90KGFlcyh4ID0gQ0FURUdPUklDQUxfVkFSSUFCTEUsIHkgPSBOVU1FUklDX1ZBUklBQkxFKSkgKyBnZW9tX2JveHBsb3QoKQoKaG9zcGl0YWxzICU+JQogIGZpbHRlcihTVEFUVVMgPT0gIk9QRU4iKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBUWVBFLCB5ID0gQkVEUykpICsKICBnZW9tX2JveHBsb3QoKSArCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgQmVkcyBhY3Jvc3MgSG9zcGl0YWxzIGluIHRoZSBVUyB0aGF0IGFyZSBPcGVuIGJ5IFR5cGUiLCB4ID0gIlR5cGUiLCBZID0gIkJlZHMiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3Q9MSkpICsgI0NoYW5nZXMgeC1heGlzIHRpY2sgbGFiZWxzIDkwIGRlZ3JlZXMKICBjb29yZF9mbGlwKCkgI0ZsaXBzIHRoZSB4IGFuZCB5IGF4aXMgdG8gbWFrZSB0aGUgZGF0YSBlYXNpZXIgdG8gcmVhZCBhbmQgY29tcGFyZQoKYGBgCgpXZSBjYW4gYWxzbyBmaWx0ZXIgb3VyIGRhdGEgdG8gc2ltaWxhciB2YWx1ZXMgYW5kIHRoZSBjb21wYXJlIGRpc3BlcnNpb25zIGFjcm9zcyBhbm90aGVyIGNhdGVnb3J5LiAKCmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTEwfQojZGYgJT4lIGdncGxvdChhZXMoeCA9IENBVEVHT1JJQ0FMX1ZBUklBQkxFLCB5ID0gTlVNRVJJQ19WQVJJQUJMRSkpICsgZ2VvbV9ib3hwbG90KCkKCmhvc3BpdGFscyAlPiUKICBmaWx0ZXIoU1RBVFVTID09ICJPUEVOIiAmIFRZUEUgPT0gIkdFTkVSQUwgQUNVVEUgQ0FSRSIpICU+JQogIGdncGxvdChhZXMoeCA9IE9XTkVSLCB5ID0gQkVEUykpICsKICBnZW9tX2JveHBsb3QoKSArCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgQmVkcyBhY3Jvc3MgSG9zcGl0YWxzIGluIHRoZSBVUyB0aGF0IGFyZSBPcGVuIGJ5IFR5cGUiLCB4ID0gIk9XTkVSIiwgWSA9ICJCZWRzIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0PTEpKSArICNDaGFuZ2VzIHgtYXhpcyB0aWNrIGxhYmVscyA5MCBkZWdyZWVzCiAgY29vcmRfZmxpcCgpICNGbGlwcyB0aGUgeCBhbmQgeSBheGlzIHRvIG1ha2UgdGhlIGRhdGEgZWFzaWVyIHRvIHJlYWQgYW5kIGNvbXBhcmUKCmBgYAoKV2Ugc2VlIGFib3ZlIHRoYXQgdGhlcmUgaXMgYSBncmVhdGVyIGRpc3BlcnNpb24gaW4gdGhlIG51bWJlciBvZiBiZWRzIGF2YWlsYWJsZSBhdCBzdGF0ZSBob3NwaXRhbHMgYW5kIG5vbi1wcm9maXQgaG9zcGl0YWxzLiBXZSBhbHNvIHNlZSB0aGF0LCBpbiBsb2NhbCBob3NwaXRhbHMsIHRoZSBtZWRpYW4gaXMgY2xvc2VyIHRvIHRoZSBmaXJzdCBxdWFydGlsZSB0aGFuIGluIG90aGVyIHBsb3RzLCBhbmQgdGhlcmUgYXJlIGEgbnVtYmVyIG9mIG91dGxpZXJzLCBpbmRpY2F0aW5nIHRoYXQgdGhlIGRhdGEgaXMgZ29pbmcgdG8gYmUgbW9yZSByaWdodCBza2V3ZWQgdGhhbiBpbiBvdGhlciBwbG90cyByaWdodC1za2V3ZWQuIENvbXBhcmUgdGhpcyB0byBmZWRlcmFsIGhvc3BpdGFscywgd2hlcmUgdGhlIG1lZGlhbiBpcyBtb3JlIGNlbnRlcmVkIGluIHRoZSBib3ggKGFuZCB0aGVyZSBhcmUgZmV3IG91dGxpZXJzKS4gV2UgYXJlIGxpa2VseSB0byBzZWUgYSBsZXNzIHNrZXdlZCBkaXN0cmlidXRpb24gaW4gdGhpcyBwbG90LiBMZXQncyBjb25maXJtIHRoaXMuCgpgYGB7ciBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD01fQpob3NwaXRhbHMgJT4lCiAgZmlsdGVyKFNUQVRVUyA9PSAiT1BFTiIgJiBUWVBFID09ICJHRU5FUkFMIEFDVVRFIENBUkUiICYgT1dORVIgPT0gIkdPVkVSTk1FTlQgLSBMT0NBTCIpICU+JQogIGdncGxvdChhZXMoeCA9IEJFRFMpKSArCiAgZ2VvbV9mcmVxcG9seShiaW53aWR0aCA9IDI1KSArCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgQmVkcyBhY3Jvc3MgT3BlbiBHZW5lcmFsIEFjdXRlIENhcmUgTG9jYWwgSG9zcGl0YWxzIGluIHRoZSBVUyIsIHggPSAiQmVkcyIsIHkgPSAiQ291bnQgb2YgSG9zcGl0YWxzIikgKyAjIFRvIGFkZCB0aXRsZXMgYW5kIGxhYmVscwogIHRoZW1lX2J3KCkKCmhvc3BpdGFscyAlPiUKICBmaWx0ZXIoU1RBVFVTID09ICJPUEVOIiAmIFRZUEUgPT0gIkdFTkVSQUwgQUNVVEUgQ0FSRSIgJiBPV05FUiA9PSAiR09WRVJOTUVOVCAtIEZFREVSQUwiKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBCRURTKSkgKwogIGdlb21fZnJlcXBvbHkoYmlud2lkdGggPSAyNSkgKwogIGxhYnModGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIEJlZHMgYWNyb3NzIE9wZW4gR2VuZXJhbCBBY3V0ZSBDYXJlIEZlZGVyYWwgSG9zcGl0YWxzIGluIHRoZSBVUyIsIHggPSAiQmVkcyIsIHkgPSAiQ291bnQgb2YgSG9zcGl0YWxzIikgKyAjIFRvIGFkZCB0aXRsZXMgYW5kIGxhYmVscwogIHRoZW1lX2J3KCkKYGBgCldlIGNhbiBzZWUgYWJvdmUgaG93IHRoZSBkaXN0cmlidXRpb24gaW4gdGhlIHNlY29uZCBwbG90IGlzIGEgYml0IG1vcmUgbm9ybWFsIHRoYW4gdGhlIGRpc3RyaWJ1dGlvbiBpbiB0aGUgZmlyc3QsIGNvbmZpcm1pbmcgd2hhdCB3ZSBjb25jbHVkZWQgYWJvdmUuIAoKIyMjIENyZWF0ZSBhIGdyb3VwZWQgYm94cGxvdCBmb3IgeW91ciBkYXRhc2V0IGJlbG93LgoKQmUgc3VyZSB0byBmaWx0ZXIgeW91ciBkYXRhc2V0IHRvIGVuc3VyZSB0aGF0IHlvdSBhcmUgc3VtbWFyaXppbmcgYWNyb3NzIHNpbWlsYXIgb2JzZXJ2YXRpb25zICoqb3IqKiBlbnN1cmUgdGhhdCBlYWNoIGdyb3VwIGlzIG1hZGUgdXAgb2Ygc2ltaWxhciBvYnNlcnZhdGlvbnMuIAoKYGBge3IgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9MTB9CiNGaWxsIHlvdXIgY29kZSBoZXJlLiBBZGQgYSB0aXRsZSBhbmQgbGFiZWxzIHRvIHlvdXIgcGxvdC4gCmBgYAoKU3VtbWFyaXplIHdoYXQgeW91IGxlYXJuIGZyb20gdGhlIHBsb3QuIAoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCB5b3VyIHJlc3BvbnNlIGhlcmUuIApgYGAKCkhvdyBkb2VzIHRoZSBzdG9yeSB0aGF0IHRoaXMgZ3JvdXBlZCBib3hwbG90IHRlbGxzIGRpZmZlciBmcm9tIHRoZSBzdG9yeSB0b2xkIGJ5IHRoZSBzaW5nbGUgYm94cGxvdCB5b3UgY3JlYXRlZCBhYm92ZT8gSW50ZXJwcmV0IHdoeSB0aGUgc3RvcnkgZGlmZmVycy4KCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgeW91ciByZXNwb25zZSBoZXJlLiAKYGBgCgoK