Associated Material

Zoom notes: Zoom Notes 03 - Selecting and Filtering Data

Reading:


Introduction

When working with a complex data set, researchers rarely summarise or analyse all the values as a single unit. More commonly, we select out specific subsets of interest, and analyse those. We saw this pattern in the Visualisation Module, where we wanted to isolate the data for a single country (Denmark) from a data frame that had records for 142 different countries.

R has a rich and powerful syntax for selecting subsets from a large data frame, based on specific conditions (for example, select only those records where the value in column country is “Denmark”). Because this kind of operation is so essential, researchers have also developed additional R packages that supplement and extend the base R facilities. Our favourite among these is a library called dplyr. Library dplyr is widely used, and you will see many examples of it in R code you find in the wild.

The functions in dplyr (and in all the other R libraries you install) are technically wrappers around base R code. That is, they are themselves written using base R commands. Thus it is possible to perform all the same transformations by using dplyr, or by using only base R. Many programmers and researchers (including some of your lecturers) prefer to use base R for these operations. Therefore, in this module, we will look at both approaches.

People make the choice between dplyr and base R for several reasons. Many people find dplyr syntax easier to use, because it is more uniform. That is, all the dplyr transformation functions use approximately the same syntax. In base R, there is more variation. Scientists who work with very large data sets are often concerned about how fast their code can be executed. In some cases, dplyr executes more slowly than base R (because of the extra code required for the wrapping), leading these researchers to prefer the base R approach. Because dplyr is a relatively new addition to R, some people prefer base R because they learned it first, and are happy to continue using it.

Unless you are required to use a particular approach (check with your lecturer if you are unsure), you can choose whichever set of commands you like using. You can even mix and match them – they give the same results, and R doesn’t care. However, it is very important that you can understand both styles. One of the great benefits of the R ecosystem is the wide sharing of code, and you can’t fully participate in this unless you are comfortable with all the major dialects.


Subsetting

The most direct way to select out a subset of a vector or data frame is using the extraction operator [], which is part of base R. With this operator we specify which elements we want in one of three ways:

  • By position (e.g. the 8th and 9th elements in a vector)
  • By name (e.g. all of column Country)
  • By some condition (e.g. all values less than 1)

The square bracket syntax works on both one and two dimensional data (i.e. vectors or data frames) and we will look at both cases, starting with vectors.

Subsetting by position

Each item in a vector has a position, starting from 1.1 Colloquially, this is called its index. We pass the index as an argument to [] to select the specific item.

# A numeric vector
some_numbers <- c(2, 45, -9, 6)

# Pull out the second item
some_numbers[2]
#> [1] 45

To select multiple items, pass a vector of indices into []. The result is itself a vector of the items at the specified positions.

# A vector of strings
some_words <- c("Ant", "Bear", "Cat", "Dino")

# Pull out items 1 and 3
some_words[c(1,3)]
#> [1] "Ant" "Cat"

Items do not have to be selected in the same order in which they appear in the original vector.

# Return items in different order
some_words[c(4, 2, 1)]
#> [1] "Dino" "Bear" "Ant"

Items can be duplicated in the result by using an index multiple times inside [].

# Duplicate items
some_words[c(3,1,4, 4, 4,2)]
#> [1] "Cat"  "Ant"  "Dino" "Dino" "Dino" "Bear"

Although vector indices start from 1, [] will accept negative values. A negative values excludes the item at that position.

# Remove the first item
some_words[-1]
#> [1] "Bear" "Cat"  "Dino"

Exercise:

The expression shown above does not remove element Ant from vector some_words.

  1. Confirm this by executing an appropriate R command.
  2. Modify the expression so that Ant is deleted from vector some_words
  3. Consider the possible downside of the command you just wrote.

Subsetting by condition

Commonly, we wish to select elements from a vector (or as we will see later, rows from a data frame) based on some condition. For example, we might want to select all items greater than some minimum value, or all items not equal to some value we wish to exclude. The [] operator offers a syntactic option that we use in these cases. Rather than passing in specific item indices, we can pass in a vector of booleans (i.e. TRUE or FALSE) having the same length as the vector from which we are selecting. The operation returns all elements for which the corresponding value of the boolean vector is TRUE.

Here is a toy example to illustrate the pattern:

# A vector of string
some_words <- c("Antelope", "Bear", "Cat", "Dino", "Eagle", "Ferret")

# Passing a boolean vector to []
some_words[c(TRUE, FALSE, FALSE, FALSE, TRUE, TRUE)]
#> [1] "Antelope" "Eagle"    "Ferret"

In practice, we don’t really type out all the TRUE and FALSE values. We let R generate the boolean vector for us, by defining a condition. For example, imagine that I am interested specifically in words having more than 4 characters. I can test this condition on my vector of string as follows:

# Generating a booolean vector
nchar(some_words) > 4
#> [1]  TRUE FALSE FALSE FALSE  TRUE  TRUE

We have seen before that R is a vectorised language, so applying any operation or expression to a vector returns the result of applying the operation to each element in turn. The syntax in the preceding command is consistent with our earlier examples of vectorised operations – it computes the result of evaluating “nchar > 4” for each element of some_words, bundles them all up into a vector, and returns it.

Note that the boolean vector produced is exactly the same one passed to [] in the “Passing a boolean vector” code example earlier. Therefore, we can simply replace the manually typed out boolean vector with the conditional expression to achieve the same result:

# Using a conditional expression inside []
some_words[nchar(some_words) > 4]
#> [1] "Antelope" "Eagle"    "Ferret"

This syntactic structure, where you apply the [] operator to some_words and also use some_words in the argument you pass to [] is very idiomatic R. Many programming languages do not allow such things; if you have programmed a lot in more traditional languages, it will take you a while to get used to this. Just remember that R always evaluates the input argument first (in this case, generating a boolean vector) and then passes the result of that evaluation to []. Many people find it helps to think through those two steps separately, when trying to figure out what a command like this produces.

Exercise:

  1. Write an R command that selects from some_words all the four-character words, but no others.
  2. Check to see if executing this command has changed the value of some_words. Explain why or why not.
  3. Modify the command so that it does change some_words, with that vector now holding only words with exactly four characters.
  4. Explain what the command you just wrote illustrates about the order in which assignment statements are evaluated.


Conditional Operators in R

Operation R Symbol
Less than <
Less than or equal to <=
Greater than >
Greater than or equal to >=
Not equal to !=

Conditional Selection with %in%

We have used == to test if one value is exactly equal to another value. Often, we wish to test if a value is equal to one of a set of values (i.e. is value A equal to either value B or value C or value D). In R, this specific complex conditional logic can be performed with the %in% operator:

# %in% with a scalar

# Given a vector...
clean_vehicles <- c("bicycle", "scooter", "skateboard")

# Test if a scalar is contained in the vector
"scooter" %in% clean_vehicles
#> [1] TRUE

"jet ski" %in% clean_vehicles
#> [1] FALSE

If we use %in with a vector as the left operand, R performs in a vectorised way, as expected, testing each element in turn:

# Using %in% with a vector
my_vehicles <- c("skateboard", "tractor", "car", "scooter")

my_vehicles %in% clean_vehicles
#> [1]  TRUE FALSE FALSE  TRUE

And the resulting boolean vector can, of course, be passed to []:

# Select out my clean vehicles
my_vehicles[my_vehicles %in% clean_vehicles]
#> [1] "skateboard" "scooter"


Missing data

One extremely common subsetting task is dealing with missing data. Missing data arises frequently during real research. For example, an ecologist studying penguin populations may be measuring the weight of each penguin in a local colony. If a particular penguin runs away before it can be weighed, that penguin’s weight is missing. It would be a mistake to code the penguin’s weight as 0 – this would corrupt any numerical analysis of weight. Therefore R provides a special data entity for ‘missing’ or ‘undefined’. Missing data in R is represented by NA.

The conditional operators we used above cannot be applied to NA. Any operation for which one or more operands is NA will return NA (even NA == NA will return NA). To test for NA, therefore, R provides function is.na which returns TRUE its input is NA and FALSE in all other instances.

# Penguin #3 got away....
penguin_weights_g <- c(3475, 2975, NA, 3420)

# Use is.na to generate a boolean vector
is.na(penguin_weights_g)
#> [1] FALSE FALSE  TRUE FALSE

# Use the boolean vector to select everyone 
# who is not NA. Note the use of !
penguin_weights_g[!is.na(penguin_weights_g)]
#> [1] 3475 2975 3420


Subsetting in two dimensions

The [] operator is also used for selecting subsets from data frames. In this usage, one supplies two arguments to [], separated by commas. The first argument specifies which row(s) to select and the second specifies which column(s). The general syntax is: name_of_data_frame[row_information, column_information]. There are, however, many complex options for the format of the row and column information. We will cover the most useful here.

# Create a data frame to practice two-dimensional selection
countries <- c("Austria", "Brazil", "Canada", "Denmark")
capitals <- c("Vienna", "Brasilia", "Ottawa", "Copenhagen")
population_in_millions <- c(9, 211, 38, 6)

geography_df <- data.frame(Country = countries,
                           Capital = capitals,
                           PopulationMillions = population_in_millions)

geography_df
#>   Country    Capital PopulationMillions
#> 1 Austria     Vienna                  9
#> 2  Brazil   Brasilia                211
#> 3  Canada     Ottawa                 38
#> 4 Denmark Copenhagen                  6

In the simplest case, we wish to select a single value from a data frame, so we provide the row index and column index of the cell of interest. For example, imagine we want the population of Vienna. We know that Vienna is in row 1 and the population is in column 3. To select that cell we provide 1 for the row information and 3 for the column information in the square brackets:

geography_df[1,3]
#> [1] 9

Don’t worry about how you would know the specific row and column of the cell you are interested in. This particular selection operation is typically used in situations where your code is computing those values based on complex criteria. This example is merely illustrative.

There are two very useful extensions to this pattern:

  1. Either the row or column index (or both) may specify a range using the : operator. For example, 1:3 or 6:12 (these are “1 to 3” and “6 to 12” respectively).
# For rows 2 to 4 (Brazil, Canada, Denmark), select the population (column 3)
geography_df[2:4, 3]
#> [1] 211  38   6

# For Canada (row 3), select both the capital name and population (cols 2 and 3)
geography_df[3, 2:3]
#>   Capital PopulationMillions
#> 3  Ottawa                 38
  1. Either the row or column index may be omitted. That is, we can say geography_df[3 , ] or geography_df[ , 2]. The missing element is interpreted as all. Omit the row number and you want all rows in the supplied column(s). Omit the column number and you want all columns in the supplied row(s).
# For Denmark (row 4), select all the columns
geography_df[4, ]
#>   Country    Capital PopulationMillions
#> 4 Denmark Copenhagen                  6

# For all rows, select the capital city name (column 2)
geography_df[ , 2]
#> [1] "Vienna"     "Brasilia"   "Ottawa"     "Copenhagen"

You may have been surprised by the output generated by that last example. Although you have selected a single column, the output is printed horizontally, as though it were a row. This is a peculiarity of R. Any collection that has a single dimension (i.e. doesn’t have both columns and rows) is treated as a plain vector. And vectors are always printed horizontally. By extension, since a selected column of a data frame is a vector, you can apply everything you have learned about vectors to selected data frame columns, which is exactly what we want to be able to do.

You can combine ranges and the missing index = all technique:

# For the first three rows, select all the columns
geography_df[1:3 , ]
#>   Country  Capital PopulationMillions
#> 1 Austria   Vienna                  9
#> 2  Brazil Brasilia                211
#> 3  Canada   Ottawa                 38

Exercise

  1. What do you think geography_df[ , ] (i.e. where both row and column information are omitted) will do?
  2. Try it. Were you right?


Instead of using column numbers, you can provide column names as the column information (and row names as the row information if your data frame has named rows). Use the combine function c() to provide multiple column names, and be sure to surround each column name with quotes, because R considers them to be strings in this situation.

geography_df[2:4, "Capital"]
#> [1] "Brasilia"   "Ottawa"     "Copenhagen"

geography_df[3:4, c("Country", "Capital")]
#>   Country    Capital
#> 3  Canada     Ottawa
#> 4 Denmark Copenhagen


Function subset

An alternative for selecting rows and columns is function subset, with structure:

subset(x = dataframe, subset = conditional_statement_to_apply_to_rows, select = columns_to_keep)

countries_over_30million <- subset(geography_df, 
                                   subset = PopulationMillions > 30, 
                                   select = c("Country", "PopulationMillions") )
countries_over_30million
#>   Country PopulationMillions
#> 2  Brazil                211
#> 3  Canada                 38

Omitting values for the subset argument or select argument will extract all rows or columns, respectively.


Selecting columns

Data frames are commonly organised with a column for each data variable and a row for each instance. To analyse a particular data variable, we wish to select all rows in a column. This particular subsetting operation is so common that there are additional, efficient ways to perform it in R.

To select a single column from a data frame, use the $ operator, followed by the column name (double quotes are not used in this context).

geography_df$Country
#> [1] "Austria" "Brazil"  "Canada"  "Denmark"

This operation is commonly used when performing summary operations on entire columns:

# Mean of a the PopulationMillions column
mean(geography_df$PopulationMillions)
#> [1] 66

The $ operator can also be used to create new columns. Simply give a name to the new column on the left hand of an assignment statement, and the contents of the new column on the right hand side. (NB: This type of operation is not allowed in more traditional languages, but is very common in R.)

# Create a new column en passant
geography_df$PopulationThousands <- geography_df$PopulationMillions * 1000

# Check that the column has been created
str(geography_df)
#> 'data.frame':    4 obs. of  4 variables:
#>  $ Country            : chr  "Austria" "Brazil" "Canada" "Denmark"
#>  $ Capital            : chr  "Vienna" "Brasilia" "Ottawa" "Copenhagen"
#>  $ PopulationMillions : num  9 211 38 6
#>  $ PopulationThousands: num  9000 211000 38000 6000

# Print the contents of the new column
geography_df$PopulationThousands
#> [1]   9000 211000  38000   6000


Subsetting with dplyr

We will now switch to a larger data set, and see how the types of selection operations described above are performed with the dplyr library. There are five main functions in dplyr: filter, select, mutate (not covered in this session), group_by, and summarise. We will see how they can be used to perform fundamental processing of selected portions of data sets.

To use dplyr, you must first install it on your machine with install.packages. Alternatively, if you have installed package tidyverse, dplyr will have been installed as part of that operation. To load dplyr for use during an RStudio session, use the library command, as we have done previously.

For this section, we will use data about forest fires in Portugal in 2022. Portugal has a high incidence of forest fire, and these data can reveal patterns about occurrence and severity.

You can download the data file forest_fires_portugal.csv from this link:

https://drive.google.com/drive/folders/1UBp-P4wFAaQL3egIQ7dGa2RQe6RQKqgy or using:

download.file(url = "https://raw.githubusercontent.com/rtis-training/2023-s2-r4ssp/main/data/forest_fires_portugal.csv", 
             destfile = "data/forest_fires_portugal.csv")

Remember that R is case sensitive so if you don’t have a directory exactly called data/ modify the command to match your directory.

The file contains one row for each recorded forest fire in Portugal in 2022. Each record has a number of measures (columns) including region (x and y values on a grid), month, day, ground condition measures, meteorological measures, and the extent of the fire in heactares. Note that any fire that consumed less than one hectare has a value of 0 in this last column.

In the code that follows, we will assume that you are working in a project, that the project folder has a sub-folder called data and that the .csv file has been placed in that folder.

# Load dplyr
library(dplyr)


# Import the csv file into a data frame
fires_df <- fires_df <- read.csv("data/forest_fires_portugal.csv")

# Inspect the data
str(fires_df)
#> 'data.frame':    517 obs. of  13 variables:
#>  $ XRegion            : int  7 7 7 8 8 8 8 8 8 7 ...
#>  $ YRegion            : int  5 4 4 6 6 6 6 6 6 5 ...
#>  $ Month              : chr  "mar" "oct" "oct" "mar" ...
#>  $ Day                : chr  "fri" "tue" "sat" "fri" ...
#>  $ ForestLitterFuel   : num  86.2 90.6 90.6 91.7 89.3 92.3 92.3 91.5 91 92.5 ...
#>  $ OrganicMaterialFuel: num  26.2 35.4 43.7 33.3 51.3 ...
#>  $ DroughtLevel       : num  94.3 669.1 686.9 77.5 102.2 ...
#>  $ SpreadPotential    : num  5.1 6.7 6.7 9 9.6 14.7 8.5 10.7 7 7.1 ...
#>  $ Temperature        : num  8.2 18 14.6 8.3 11.4 22.2 24.1 8 13.1 22.8 ...
#>  $ Humidity           : int  51 33 33 97 99 29 27 86 63 40 ...
#>  $ WindSpeed          : num  6.7 0.9 1.3 4 1.8 5.4 3.1 2.2 5.4 4 ...
#>  $ Rainfall           : num  0 0 0 0.2 0 0 0 0 0 0 ...
#>  $ FireAreaHa         : num  0 0 0 0 0 0 0 0 0 0 ...

Selecting columns

To extract individual columns, use function select, passing in the dataframe, and the names of the columns you want. There is no need to format the column names into a vector, or to use double quotes.

# Select the FireAreaHa column, which shows area damaged by the fire in hectares
select(fires_df, FireAreaHa)
# Select the month and fire area columns, and store them in a new vector
month_area_df <- select(fires_df, Month, FireAreaHa)

# Inspect
month_area_df[350:355,] # You can combine base R [] with dplyr
#>     Month FireAreaHa
#> 350   sep       1.64
#> 351   sep       3.71
#> 352   sep       7.31
#> 353   sep       2.03
#> 354   sep       1.72
#> 355   sep       5.97

# For efficiency, you can define a vector of column names to use whenever
# needed. Use double quotes as per usual
selected_cols <- c("Humidity", "FireAreaHa")
humidity_area_df <- select(fires_df, all_of(selected_cols))

# Example analysis using two columns
cor(humidity_area_df)
#>               Humidity  FireAreaHa
#> Humidity    1.00000000 -0.07551856
#> FireAreaHa -0.07551856  1.00000000


Selecting rows

In computing, the process of selecting rows from a data table based on particular criteria is called filtering. With dplyr we use function filter, passing the name of the data frame and the filter condition. The result is a new data frame that contains all rows from the original for which the filter condition evaluated to TRUE.

# Extract all fires that occurred in October (i.e. where the Month column contains
# 'oct')
october_fires <- filter(fires_df, Month == 'oct')

# Compute the mean drought level for all fires in october, using base R
# column selection with $
mean(october_fires$DroughtLevel)
#> [1] 681.6733

Exercise

  1. How would you generate data frame october_fires using [] in base R?
  2. Referring to the Visualisation Module, how would you select the Denmark data using dplyr?

Filtering with complex conditionals

Often we wish to filter on criteria that involve multiple comparisons. For example, if we wish to extract all the rows for fires during the winter season (December through February in Portugal) we want rows for which Month is ‘dec’ or ‘jan’ or ‘feb’. Earlier we saw how to do this with%in%. More generally, we can combine conditional statements using the logical AND and OR operators, & and | respectively.

# Select the winter fires
winter_df <- filter(fires_df, Month == "dec" | Month == "jan" | Month == "feb")

Exercise:

The XRegion and YRegion fields are coordinates in a pre-defined 9 by 9 grid that covers all of Portugal. You want to find all fires that occurred on the east and west borders of the country – that is, in XRegions 1, 2, 8, or 9. Filter for these records. Make your expression as succinct as you can. (You only need one |.)

x_edge_fires <- filter(fires_df, XRegion <= 2 | XRegion >= 8)

Exercise:

Frequently, we want extract a subset of rows and a subset of columns from a large data set – that is, we will want to perform both a select and a filter operation. Using an intermediate variable, write code to extract month, temperature, and fire area for only the summer months (June, July, and August). Note that later in today’s session we will see an alternative “dplyr syntax” for this combined operation, but it good to master both approaches.

# Exercise Solution (there are many possible solutions)

# Filter to get the rows we want
summer_fires_df <- filter(fires_df, Month %in% c('jun', 'jul','aug'))

# Pass the result of the filtering operation to select
summer_temperature_area_df <- select(summer_fires_df, Month, Temperature, FireAreaHa)


Sorting

Sorting is an extremely common operation on large data sets, as it makes it easier to inspect our data efficiently. To sort with dplyr, use function arrange. Pass in the name of the data frame, and the columns on which you wish to sort, from slowest to fastest moving.

# Sort all records in order of area consumed (column FireAreaHa)
sort_by_area_df <- arrange(fires_df, FireAreaHa)


# To sort in descending order, apply function desc to the column
sort_by_area_df <- arrange(fires_df, desc(FireAreaHa))


# Sorting on multiple columns
sort_by_month_area_df <- arrange(fires_df, Month, desc(FireAreaHa))

You will note that this last result is sorted by month alphabetically. This makes sense to R, but we probably would prefer to have it sorted logically. To ensure this, we can cast column Month from type “chr” (just strings) to type “Ordered Factor”, an ordered categorical variable. The code for this operation is shown below. We will discuss the management of categorical vs. numerical variables in more depth in the Summarising Module, later in the semester.

# Define the logical order of our month codes
months_in_order = c("jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep",
                    "oct", "nov", "dec")

# Modify the Month column so it uses that ordering 
fires_df$Month <- ordered(fires_df$Month, levels = months_in_order)

# Repeat the sort operation to confirm
sort_by_month_area_df <- arrange(fires_df, Month, desc(FireAreaHa))

# Check
head(sort_by_month_area_df)
#>   XRegion YRegion Month Day ForestLitterFuel OrganicMaterialFuel DroughtLevel
#> 1       2       4   jan sat             82.1                 3.7          9.3
#> 2       4       5   jan sun             18.7                 1.1        171.4
#> 3       4       5   feb sun             85.0                 9.0         56.9
#> 4       5       4   feb fri             85.2                 4.9         15.8
#> 5       7       4   feb sun             83.9                 8.7         32.1
#> 6       7       4   feb mon             84.7                 9.5         58.3
#>   SpreadPotential Temperature Humidity WindSpeed Rainfall FireAreaHa
#> 1             2.9         5.3       78       3.1        0       0.00
#> 2             0.0         5.2      100       0.9        0       0.00
#> 3             3.5        10.1       62       1.8        0      51.78
#> 4             6.3         7.5       46       8.0        0      24.24
#> 5             2.1         8.8       68       2.2        0      13.05
#> 6             4.1         7.5       71       6.3        0       9.96

Summarising by group

We typically extract subsets from a data frame to serve as input to methods that summarise, perform statistical analyses, or produce graphs of those data. Library dplyr provides a pair of methods – group_by and summarise – which, when used together, make this workflow especially succinct for simple post-selection processing.

Assume that you would like to know the mean fire area consumed for each month. You will first apply group_by to fires_df to define your grouping variable as column Month. This has no major visible impact on fires_df. However, any subsequent summaries you perform on that data frame with function summarise are applied by group. For example, if you use summarise to compute the mean of FireAreaHa (syntax shown below), it computes that mean for each month separately. If you use summarise to compute the standard deviation of Temperature, it computes that standard deviation for each month separately. And so on.

# To compare area consumed by month

# Apply group_by. In View the data frame looks unchanged
fires_gp_month_df <- group_by(fires_df, Month)

# When printed to console, the data frame also looks the same except for Groups
# header
fires_gp_month_df
#> # A tibble: 517 × 13
#> # Groups:   Month [12]
#>    XRegion YRegion Month Day   ForestLitterFuel OrganicMaterialFuel DroughtLevel
#>      <int>   <int> <ord> <chr>            <dbl>               <dbl>        <dbl>
#>  1       7       5 mar   fri               86.2                26.2         94.3
#>  2       7       4 oct   tue               90.6                35.4        669. 
#>  3       7       4 oct   sat               90.6                43.7        687. 
#>  4       8       6 mar   fri               91.7                33.3         77.5
#>  5       8       6 mar   sun               89.3                51.3        102. 
#>  6       8       6 aug   sun               92.3                85.3        488  
#>  7       8       6 aug   mon               92.3                88.9        496. 
#>  8       8       6 aug   mon               91.5               145.         608. 
#>  9       8       6 sep   tue               91                 130.         693. 
#> 10       7       5 sep   sat               92.5                88          699. 
#> # ℹ 507 more rows
#> # ℹ 6 more variables: SpreadPotential <dbl>, Temperature <dbl>, Humidity <int>,
#> #   WindSpeed <dbl>, Rainfall <dbl>, FireAreaHa <dbl>

The magic happens when we take a grouped data frame and pass it to summarise. Function summarise returns a new data frame with a row for each level of the grouping variable, and a column for each summary function we specify.

# T second arg to summarise is "col header = expression". Expression is applied by group

summarise(fires_gp_month_df, MeanAreaLn = mean(FireAreaHa, na.rm = TRUE))
#> # A tibble: 12 × 2
#>    Month MeanAreaLn
#>    <ord>      <dbl>
#>  1 jan         0   
#>  2 feb         6.28
#>  3 mar         4.36
#>  4 apr         8.89
#>  5 may        19.2 
#>  6 jun         5.84
#>  7 jul        14.4 
#>  8 aug        12.5 
#>  9 sep        17.9 
#> 10 oct         6.64
#> 11 nov         0   
#> 12 dec        13.3

Note that you can provide multiple expressions to summarise. It produces a column for each.

You can also provide multiple column names to group_by. Function summarise is then applied to the groups defined by each combination of values on the grouping variables.

# Grouping on two variables
fires_month_day <- group_by(fires_df, Month, Day)
summarise(fires_month_day, MeanAreaForMonthAndDayOfWeek = mean(FireAreaHa, na.rm = TRUE))
#> `summarise()` has grouped output by 'Month'. You can override using the
#> `.groups` argument.
#> # A tibble: 64 × 3
#> # Groups:   Month [12]
#>    Month Day   MeanAreaForMonthAndDayOfWeek
#>    <ord> <chr>                        <dbl>
#>  1 jan   sat                          0    
#>  2 jan   sun                          0    
#>  3 feb   fri                          5.77 
#>  4 feb   mon                          3.32 
#>  5 feb   sat                          1.71 
#>  6 feb   sun                         17.8  
#>  7 feb   thu                          0    
#>  8 feb   tue                          3.76 
#>  9 feb   wed                          1.1  
#> 10 mar   fri                          0.985
#> # ℹ 54 more rows

Exercise

  1. Use ‘group_by’ and ‘summarise’ to find the largest fire (i.e. maximum area burnt) in each month.
  2. A useful worker function in library dplyr is n(). This function, when used in summarise, counts the number of records in each group (it takes no column header; it just counts the number of rows in the group). Generate a table that shows the number of fires that occurred on each day of the week. How would you explain the pattern in these results?
# Exercise Solution
fires_gp_day_df <- group_by(fires_df, Day)
summarise(fires_gp_day_df, NFires = n()) 
#> # A tibble: 7 × 2
#>   Day   NFires
#>   <chr>  <int>
#> 1 fri       85
#> 2 mon       74
#> 3 sat       84
#> 4 sun       95
#> 5 thu       61
#> 6 tue       64
#> 7 wed       54
  1. Modify fires_df so that summarise outputs the days in their correct logical order (e.g. Wednesday before Thursday).


Pipes

When you install dplyr (either alone or as part of meta-package tidyverse), you also get library magrittr, which contains a special operator called the pipe. (NB: The character |, used for OR, is also called the pipe. Just one of those things.)

With the pipe, we can perform a series of operations, for example filter and select, without intermediate variables. We think of starting with our complete data frame and pushing it through a series, or pipeline of operations. At each step, the output from one operation is passed along as the input of the next.

When using the pipe, we no longer have to provide the name of data frame as the first argument to all the dplyr functions – they always take the output of the previous step in the pipe.

Previously, we combined filter and select by using an intermediate variable, like this:

# Filter to get the rows we want
summer_fires_df <- filter(fires_df, Month %in% c('jun', 'jul','aug'))

# Pass the result of the filtering operation to select
summer_temperature_area_df <- select(summer_fires_df, Month, Temperature, FireAreaHa)

Using pipe syntax, the same result would be obtained with:

summer_temperature_area_df <- fires_df %>% filter(Month %in% c("jun", "jul", "aug")) %>% select(Month, Temperature, FireAreaHa)

head(summer_temperature_area_df)
#>   Month Temperature FireAreaHa
#> 1   aug        22.2          0
#> 2   aug        24.1          0
#> 3   aug         8.0          0
#> 4   aug        17.0          0
#> 5   jun        21.0          0
#> 6   aug        19.5          0

Like the + symbol in ggplot, %>% signals to RStudio that more code is coming, allowing you to make the code readable by placing each operation in the pipeline on a new line:

summer_temperature_area_df <- fires_df %>% 
  filter(Month %in% c("jun", "jul", "aug")) %>% 
  select(Month, Temperature, FireAreaHa)

head(summer_temperature_area_df)
#>   Month Temperature FireAreaHa
#> 1   aug        22.2          0
#> 2   aug        24.1          0
#> 3   aug         8.0          0
#> 4   aug        17.0          0
#> 5   jun        21.0          0
#> 6   aug        19.5          0

Exercise

  1. Using group_by, summarise, and pipe notation, compute the mean temperature for each month
# Exercise solution
fires_df %>% group_by(Month) %>% summarise(MeanTemperature = mean(Temperature, na.rm = TRUE))
#> # A tibble: 12 × 2
#>    Month MeanTemperature
#>    <ord>           <dbl>
#>  1 jan              5.25
#>  2 feb              9.64
#>  3 mar             13.1 
#>  4 apr             12.0 
#>  5 may             14.6 
#>  6 jun             20.5 
#>  7 jul             22.1 
#>  8 aug             21.6 
#>  9 sep             19.6 
#> 10 oct             17.1 
#> 11 nov             11.8 
#> 12 dec              4.52


  1. You can use ggplot at the end of a pipeline. Write a single command to make a boxplot that illustrates the distribution of drought level during each of the summer months in Portugal. Plan: First filter out the months you want, then make a boxplot with x = Month and y = DroughtLevel
library(ggplot2)

fires_df %>% filter(Month %in% c("jun", "jul", "aug")) %>%
  ggplot(mapping = aes(x = Month, y = DroughtLevel)) + 
  geom_boxplot()


  1. Write a single command that produces a bar graph of the mean temperature for each month. (Plan: The pipeline starts with group_by and summarise to compute the means, then pours that output into ggplot. Make the graph using geom_bar. Set the x axis to Month and the y axis to the column name you assign for the mean temperature in summarise. Pass into geom_bar the argument stat = "identity" so it plots the data values as provided. Note the double quotes around the identity; they are required.)
# Exercise solution

library(ggplot2)

fires_df %>% 
  group_by(Month) %>% 
  summarise(MeanTemperature = mean(Temperature, na.rm = TRUE)) %>%
  ggplot(mapping = aes(x = Month, y = MeanTemperature)) + geom_bar(stat = "identity")

A Word of Caution

Dplyr pipeline syntax is popular because it eliminates the need for intermediate variables and, therefore, requires a lot less typing. It is common, when first encountering this option, to get slightly carried away, and chain together dozens of operations, reveling in how many keystrokes you are saving. This is risky, for several reasons:

  1. If a long pipeline fails, you will not know in which operation the error occurred. This can make it extremely difficult to debug.
  2. Because you are not saving any of the intermediate outputs, you do not have them available for different processing in other contexts – you will have to repeat the whole portion of the pipeline which generated them.
  3. A long pipeline will be difficult for other people to “read” (i.e. to figure out what it’s doing). When you have multiple options for performing a computation, the goal is to strike a balance between parsimony (not too much typing) and readability (your code is easy for other people to understand). When working on group projects, or in a professional software development context, readability is considered the more critical of the two features. My personal style is never to build pipelines of more than three or four operations. The outputs of these short sequences can be saved into intermediate variables which can be checked and reused, which are then passed along into the next pipeline.

Another Word of Caution

R users are constantly adding new libraries to base R, meaning that you will probably have several options for doing any job in R. The various options sometimes have subtle technical differences that will generate a lot of argument between professional programmers, but are unlikely to matter much to research scientists. In general, you should explore the R ecosystem freely and use whatever you like. However on assignments, it is wise to check with the lecturer before using something that is really different from what is presented in class. Your lecturer may, for educational reasons, want you to use specific R tools.

What’s Next

You may recall that way back in the first module of R4SSP we said we were going to analyse data. We haven’t really done much of that yet. So far we have been getting ready to analyse data. In the next module, we will start really digging into our data with exploratory analysis and descriptive statistics. Because this is not a statistics course per se we will only be using common general analyses in the handouts and readings. If, for a project or assignment, you need to do something more esoteric, just let us know – someone has probably written an R library for it.


  1. NB: Most programming languages start from 0. If you are an experienced Java, C, etc., programmer, be alert for this.↩︎

LS0tCnRpdGxlOiAiU3Vic2V0dGluZyIKZGF0ZTogIlNlbWVzdGVyIDIsIDIwMjMiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRvY19kZXB0aDogMwogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93Ci0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkoa25pdHIpCgprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgY29tbWVudCA9ICIjPiIsCiAgZmlnLnBhdGggPSAiZmlndXJlcy8wMy8iLCAjIHVzZSBvbmx5IGZvciBzaW5nbGUgUm1kIGZpbGVzCiAgY29sbGFwc2UgPSBUUlVFLAogIGVjaG8gPSBUUlVFCikKYGBgCgoKCj4gIyMjIyBBc3NvY2lhdGVkIE1hdGVyaWFsCj4KPiBab29tIG5vdGVzOiBbWm9vbSBOb3RlcyAwMyAtIFNlbGVjdGluZyBhbmQgRmlsdGVyaW5nIERhdGFdKHpvb21fbm90ZXNfMDNfdmlzdWFsaXNlLmh0bWwpCj4KPiBSZWFkaW5nOgo+Cj4gLSBbUiBmb3IgRGF0YSBTY2llbmNlIC0gQ2hhcHRlciA1XShodHRwczovL3I0ZHMuaGFkLmNvLm56L3RyYW5zZm9ybS5odG1sKQoKXAoKIyMgSW50cm9kdWN0aW9uCgpXaGVuIHdvcmtpbmcgd2l0aCBhIGNvbXBsZXggZGF0YSBzZXQsIHJlc2VhcmNoZXJzIHJhcmVseSBzdW1tYXJpc2Ugb3IgYW5hbHlzZSBhbGwgdGhlIHZhbHVlcyBhcyBhIHNpbmdsZSB1bml0LiBNb3JlIGNvbW1vbmx5LCB3ZSBzZWxlY3Qgb3V0IHNwZWNpZmljIHN1YnNldHMgb2YgaW50ZXJlc3QsIGFuZCBhbmFseXNlIHRob3NlLiBXZSBzYXcgdGhpcyBwYXR0ZXJuIGluIHRoZSBWaXN1YWxpc2F0aW9uIE1vZHVsZSwgd2hlcmUgd2Ugd2FudGVkIHRvIGlzb2xhdGUgdGhlIGRhdGEgZm9yIGEgc2luZ2xlIGNvdW50cnkgKERlbm1hcmspIGZyb20gYSBkYXRhIGZyYW1lIHRoYXQgaGFkIHJlY29yZHMgZm9yIDE0MiBkaWZmZXJlbnQgY291bnRyaWVzLgoKUiBoYXMgYSByaWNoIGFuZCBwb3dlcmZ1bCBzeW50YXggZm9yIHNlbGVjdGluZyBzdWJzZXRzIGZyb20gYSBsYXJnZSBkYXRhIGZyYW1lLCBiYXNlZCBvbiBzcGVjaWZpYyBjb25kaXRpb25zIChmb3IgZXhhbXBsZSwgc2VsZWN0IG9ubHkgdGhvc2UgcmVjb3JkcyB3aGVyZSB0aGUgdmFsdWUgaW4gY29sdW1uIGBjb3VudHJ5YCBpcyAiRGVubWFyayIpLiBCZWNhdXNlIHRoaXMga2luZCBvZiBvcGVyYXRpb24gaXMgc28gZXNzZW50aWFsLCByZXNlYXJjaGVycyBoYXZlIGFsc28gZGV2ZWxvcGVkIGFkZGl0aW9uYWwgUiBwYWNrYWdlcyB0aGF0IHN1cHBsZW1lbnQgYW5kIGV4dGVuZCB0aGUgYmFzZSBSIGZhY2lsaXRpZXMuIE91ciBmYXZvdXJpdGUgYW1vbmcgdGhlc2UgaXMgYSBsaWJyYXJ5IGNhbGxlZCAqKmRwbHlyKiouICBMaWJyYXJ5IGBkcGx5cmAgaXMgd2lkZWx5IHVzZWQsIGFuZCB5b3Ugd2lsbCBzZWUgbWFueSBleGFtcGxlcyBvZiBpdCBpbiBSIGNvZGUgeW91IGZpbmQgaW4gdGhlIHdpbGQuCgpUaGUgZnVuY3Rpb25zIGluIGBkcGx5cmAgKGFuZCBpbiBhbGwgdGhlIG90aGVyIFIgbGlicmFyaWVzIHlvdSBpbnN0YWxsKSBhcmUgdGVjaG5pY2FsbHkgKip3cmFwcGVycyoqIGFyb3VuZCBiYXNlIFIgY29kZS4gVGhhdCBpcywgdGhleSBhcmUgdGhlbXNlbHZlcyB3cml0dGVuIHVzaW5nIGJhc2UgUiBjb21tYW5kcy4gVGh1cyBpdCBpcyBwb3NzaWJsZSB0byBwZXJmb3JtIGFsbCB0aGUgc2FtZSB0cmFuc2Zvcm1hdGlvbnMgYnkgdXNpbmcgYGRwbHlyYCwgb3IgYnkgdXNpbmcgb25seSBiYXNlIFIuIE1hbnkgcHJvZ3JhbW1lcnMgYW5kIHJlc2VhcmNoZXJzIChpbmNsdWRpbmcgc29tZSBvZiB5b3VyIGxlY3R1cmVycykgcHJlZmVyIHRvIHVzZSBiYXNlIFIgZm9yIHRoZXNlIG9wZXJhdGlvbnMuIFRoZXJlZm9yZSwgaW4gdGhpcyBtb2R1bGUsIHdlIHdpbGwgbG9vayBhdCBib3RoIGFwcHJvYWNoZXMuCgpQZW9wbGUgbWFrZSB0aGUgY2hvaWNlIGJldHdlZW4gYGRwbHlyYCBhbmQgYmFzZSBSIGZvciBzZXZlcmFsIHJlYXNvbnMuIE1hbnkgcGVvcGxlIGZpbmQgYGRwbHlyYCBzeW50YXggZWFzaWVyIHRvIHVzZSwgYmVjYXVzZSBpdCBpcyBtb3JlICoqdW5pZm9ybSoqLiBUaGF0IGlzLCBhbGwgdGhlIGBkcGx5cmAgdHJhbnNmb3JtYXRpb24gZnVuY3Rpb25zIHVzZSBhcHByb3hpbWF0ZWx5IHRoZSBzYW1lIHN5bnRheC4gSW4gYmFzZSBSLCB0aGVyZSBpcyBtb3JlIHZhcmlhdGlvbi4gU2NpZW50aXN0cyB3aG8gd29yayB3aXRoIHZlcnkgbGFyZ2UgZGF0YSBzZXRzIGFyZSBvZnRlbiBjb25jZXJuZWQgYWJvdXQgaG93IGZhc3QgdGhlaXIgY29kZSBjYW4gYmUgZXhlY3V0ZWQuIEluIHNvbWUgY2FzZXMsIGBkcGx5cmAgZXhlY3V0ZXMgbW9yZSBzbG93bHkgdGhhbiBiYXNlIFIgKGJlY2F1c2Ugb2YgdGhlIGV4dHJhIGNvZGUgcmVxdWlyZWQgZm9yIHRoZSB3cmFwcGluZyksIGxlYWRpbmcgdGhlc2UgcmVzZWFyY2hlcnMgdG8gcHJlZmVyIHRoZSBiYXNlIFIgYXBwcm9hY2guIEJlY2F1c2UgYGRwbHlyYCBpcyBhIHJlbGF0aXZlbHkgbmV3IGFkZGl0aW9uIHRvIFIsIHNvbWUgcGVvcGxlIHByZWZlciBiYXNlIFIgYmVjYXVzZSB0aGV5IGxlYXJuZWQgaXQgZmlyc3QsIGFuZCBhcmUgaGFwcHkgdG8gY29udGludWUgdXNpbmcgaXQuCgpVbmxlc3MgeW91IGFyZSByZXF1aXJlZCB0byB1c2UgYSBwYXJ0aWN1bGFyIGFwcHJvYWNoIChjaGVjayB3aXRoIHlvdXIgbGVjdHVyZXIgaWYgeW91IGFyZSB1bnN1cmUpLCB5b3UgY2FuIGNob29zZSB3aGljaGV2ZXIgc2V0IG9mIGNvbW1hbmRzIHlvdSBsaWtlIHVzaW5nLiBZb3UgY2FuIGV2ZW4gbWl4IGFuZCBtYXRjaCB0aGVtIC0tIHRoZXkgZ2l2ZSB0aGUgc2FtZSByZXN1bHRzLCBhbmQgUiBkb2Vzbid0IGNhcmUuIEhvd2V2ZXIsIGl0IGlzIHZlcnkgaW1wb3J0YW50IHRoYXQgeW91IGNhbiAqdW5kZXJzdGFuZCogYm90aCBzdHlsZXMuIE9uZSBvZiB0aGUgZ3JlYXQgYmVuZWZpdHMgb2YgdGhlIFIgZWNvc3lzdGVtIGlzIHRoZSB3aWRlIHNoYXJpbmcgb2YgY29kZSwgYW5kIHlvdSBjYW4ndCBmdWxseSBwYXJ0aWNpcGF0ZSBpbiB0aGlzIHVubGVzcyB5b3UgYXJlIGNvbWZvcnRhYmxlIHdpdGggYWxsIHRoZSBtYWpvciBkaWFsZWN0cy4KClwKCiMjIFN1YnNldHRpbmcKClRoZSBtb3N0IGRpcmVjdCB3YXkgdG8gc2VsZWN0IG91dCBhIHN1YnNldCBvZiBhIHZlY3RvciBvciBkYXRhIGZyYW1lIGlzIHVzaW5nIHRoZSAqKmV4dHJhY3Rpb24gb3BlcmF0b3IqKiBbXSwgd2hpY2ggaXMgcGFydCBvZiBiYXNlIFIuIFdpdGggdGhpcyBvcGVyYXRvciB3ZSBzcGVjaWZ5IHdoaWNoIGVsZW1lbnRzIHdlIHdhbnQgaW4gb25lIG9mIHRocmVlIHdheXM6CgotIEJ5IHBvc2l0aW9uIChlLmcuIHRoZSA4dGggYW5kIDl0aCBlbGVtZW50cyBpbiBhIHZlY3RvcikKLSBCeSBuYW1lIChlLmcuIGFsbCBvZiBjb2x1bW4gQ291bnRyeSkKLSBCeSBzb21lIGNvbmRpdGlvbiAoZS5nLiBhbGwgdmFsdWVzIGxlc3MgdGhhbiAxKQoKVGhlIHNxdWFyZSBicmFja2V0IHN5bnRheCB3b3JrcyBvbiBib3RoIG9uZSBhbmQgdHdvIGRpbWVuc2lvbmFsIGRhdGEgKGkuZS4gdmVjdG9ycyBvciBkYXRhIGZyYW1lcykgYW5kIHdlIHdpbGwgbG9vayBhdCBib3RoIGNhc2VzLCBzdGFydGluZyB3aXRoIHZlY3RvcnMuCgojIyMgU3Vic2V0dGluZyBieSBwb3NpdGlvbgoKRWFjaCBpdGVtIGluIGEgdmVjdG9yIGhhcyBhIHBvc2l0aW9uLCBzdGFydGluZyBmcm9tIDEuXltOQjogTW9zdCBwcm9ncmFtbWluZyBsYW5ndWFnZXMgc3RhcnQgZnJvbSAwLiBJZiB5b3UgYXJlIGFuIGV4cGVyaWVuY2VkIEphdmEsIEMsIGV0Yy4sIHByb2dyYW1tZXIsIGJlIGFsZXJ0IGZvciB0aGlzLl0gQ29sbG9xdWlhbGx5LCB0aGlzIGlzIGNhbGxlZCBpdHMgKippbmRleCoqLiBXZSBwYXNzIHRoZSBpbmRleCBhcyBhbiBhcmd1bWVudCB0byBgW11gIHRvIHNlbGVjdCB0aGUgc3BlY2lmaWMgaXRlbS4gCmBgYHtyfQojIEEgbnVtZXJpYyB2ZWN0b3IKc29tZV9udW1iZXJzIDwtIGMoMiwgNDUsIC05LCA2KQoKIyBQdWxsIG91dCB0aGUgc2Vjb25kIGl0ZW0Kc29tZV9udW1iZXJzWzJdCmBgYAoKVG8gc2VsZWN0IG11bHRpcGxlIGl0ZW1zLCBwYXNzIGEgdmVjdG9yIG9mIGluZGljZXMgaW50byBbXS4gVGhlIHJlc3VsdCBpcyBpdHNlbGYgYSB2ZWN0b3Igb2YgdGhlIGl0ZW1zIGF0IHRoZSBzcGVjaWZpZWQgcG9zaXRpb25zLiAKCgpgYGB7cn0KIyBBIHZlY3RvciBvZiBzdHJpbmdzCnNvbWVfd29yZHMgPC0gYygiQW50IiwgIkJlYXIiLCAiQ2F0IiwgIkRpbm8iKQoKIyBQdWxsIG91dCBpdGVtcyAxIGFuZCAzCnNvbWVfd29yZHNbYygxLDMpXQpgYGAKSXRlbXMgZG8gbm90IGhhdmUgdG8gYmUgc2VsZWN0ZWQgaW4gdGhlIHNhbWUgb3JkZXIgaW4gd2hpY2ggdGhleSBhcHBlYXIgaW4gdGhlIG9yaWdpbmFsIHZlY3Rvci4KCmBgYHtyfQojIFJldHVybiBpdGVtcyBpbiBkaWZmZXJlbnQgb3JkZXIKc29tZV93b3Jkc1tjKDQsIDIsIDEpXQpgYGAKSXRlbXMgY2FuIGJlIGR1cGxpY2F0ZWQgaW4gdGhlIHJlc3VsdCBieSB1c2luZyBhbiBpbmRleCBtdWx0aXBsZSB0aW1lcyBpbnNpZGUgW10uCgoKYGBge3J9CiMgRHVwbGljYXRlIGl0ZW1zCnNvbWVfd29yZHNbYygzLDEsNCwgNCwgNCwyKV0KYGBgCgpBbHRob3VnaCB2ZWN0b3IgaW5kaWNlcyBzdGFydCBmcm9tIDEsIFtdIHdpbGwgYWNjZXB0IG5lZ2F0aXZlIHZhbHVlcy4gQSBuZWdhdGl2ZSB2YWx1ZXMgKipleGNsdWRlcyoqIHRoZSBpdGVtIGF0IHRoYXQgcG9zaXRpb24uCgpgYGAge3J9CiMgUmVtb3ZlIHRoZSBmaXJzdCBpdGVtCnNvbWVfd29yZHNbLTFdCmBgYAoKIyMjIEV4ZXJjaXNlOgoKVGhlIGV4cHJlc3Npb24gc2hvd24gYWJvdmUgZG9lcyBub3QgcmVtb3ZlIGVsZW1lbnQgQW50IGZyb20gdmVjdG9yIGBzb21lX3dvcmRzYC4gCgoxLiBDb25maXJtIHRoaXMgYnkgZXhlY3V0aW5nIGFuIGFwcHJvcHJpYXRlIFIgY29tbWFuZC4KMi4gTW9kaWZ5IHRoZSBleHByZXNzaW9uIHNvIHRoYXQgQW50IGlzIGRlbGV0ZWQgZnJvbSB2ZWN0b3IgYHNvbWVfd29yZHNgCjMuIENvbnNpZGVyIHRoZSBwb3NzaWJsZSBkb3duc2lkZSBvZiB0aGUgY29tbWFuZCB5b3UganVzdCB3cm90ZS4KCiMjIyBTdWJzZXR0aW5nIGJ5IGNvbmRpdGlvbgoKQ29tbW9ubHksIHdlIHdpc2ggdG8gc2VsZWN0IGVsZW1lbnRzIGZyb20gYSB2ZWN0b3IgKG9yIGFzIHdlIHdpbGwgc2VlIGxhdGVyLCByb3dzIGZyb20gYSBkYXRhIGZyYW1lKSBiYXNlZCBvbiBzb21lIGNvbmRpdGlvbi4gRm9yIGV4YW1wbGUsIHdlIG1pZ2h0IHdhbnQgdG8gc2VsZWN0IGFsbCBpdGVtcyBncmVhdGVyIHRoYW4gc29tZSBtaW5pbXVtIHZhbHVlLCBvciBhbGwgaXRlbXMgbm90IGVxdWFsIHRvIHNvbWUgdmFsdWUgd2Ugd2lzaCB0byBleGNsdWRlLiBUaGUgW10gb3BlcmF0b3Igb2ZmZXJzIGEgc3ludGFjdGljIG9wdGlvbiB0aGF0IHdlIHVzZSBpbiB0aGVzZSBjYXNlcy4gUmF0aGVyIHRoYW4gcGFzc2luZyBpbiBzcGVjaWZpYyBpdGVtIGluZGljZXMsIHdlIGNhbiBwYXNzIGluIGEgdmVjdG9yIG9mIGJvb2xlYW5zIChpLmUuIFRSVUUgb3IgRkFMU0UpIGhhdmluZyB0aGUgc2FtZSBsZW5ndGggYXMgdGhlIHZlY3RvciBmcm9tIHdoaWNoIHdlIGFyZSBzZWxlY3RpbmcuIFRoZSBvcGVyYXRpb24gcmV0dXJucyBhbGwgZWxlbWVudHMgZm9yIHdoaWNoIHRoZSBjb3JyZXNwb25kaW5nIHZhbHVlIG9mIHRoZSBib29sZWFuIHZlY3RvciBpcyBUUlVFLiAKCkhlcmUgaXMgYSB0b3kgZXhhbXBsZSB0byBpbGx1c3RyYXRlIHRoZSBwYXR0ZXJuOgoKYGBge3J9CiMgQSB2ZWN0b3Igb2Ygc3RyaW5nCnNvbWVfd29yZHMgPC0gYygiQW50ZWxvcGUiLCAiQmVhciIsICJDYXQiLCAiRGlubyIsICJFYWdsZSIsICJGZXJyZXQiKQoKIyBQYXNzaW5nIGEgYm9vbGVhbiB2ZWN0b3IgdG8gW10Kc29tZV93b3Jkc1tjKFRSVUUsIEZBTFNFLCBGQUxTRSwgRkFMU0UsIFRSVUUsIFRSVUUpXQpgYGAKSW4gcHJhY3RpY2UsIHdlIGRvbid0IHJlYWxseSB0eXBlIG91dCBhbGwgdGhlIFRSVUUgYW5kIEZBTFNFIHZhbHVlcy4gV2UgbGV0IFIgZ2VuZXJhdGUgdGhlIGJvb2xlYW4gdmVjdG9yIGZvciB1cywgYnkgZGVmaW5pbmcgYSBjb25kaXRpb24uIEZvciBleGFtcGxlLCBpbWFnaW5lIHRoYXQgSSBhbSBpbnRlcmVzdGVkIHNwZWNpZmljYWxseSBpbiB3b3JkcyBoYXZpbmcgbW9yZSB0aGFuIDQgY2hhcmFjdGVycy4gSSBjYW4gdGVzdCB0aGlzIGNvbmRpdGlvbiBvbiBteSB2ZWN0b3Igb2Ygc3RyaW5nIGFzIGZvbGxvd3M6CgpgYGAge3J9CiMgR2VuZXJhdGluZyBhIGJvb29sZWFuIHZlY3RvcgpuY2hhcihzb21lX3dvcmRzKSA+IDQKYGBgCgpXZSBoYXZlIHNlZW4gYmVmb3JlIHRoYXQgUiBpcyBhICoqdmVjdG9yaXNlZCoqIGxhbmd1YWdlLCBzbyBhcHBseWluZyBhbnkgb3BlcmF0aW9uIG9yIGV4cHJlc3Npb24gdG8gYSB2ZWN0b3IgcmV0dXJucyB0aGUgcmVzdWx0IG9mIGFwcGx5aW5nIHRoZSBvcGVyYXRpb24gdG8gZWFjaCBlbGVtZW50IGluIHR1cm4uIFRoZSBzeW50YXggaW4gdGhlIHByZWNlZGluZyBjb21tYW5kIGlzIGNvbnNpc3RlbnQgd2l0aCBvdXIgZWFybGllciBleGFtcGxlcyBvZiB2ZWN0b3Jpc2VkIG9wZXJhdGlvbnMgLS0gaXQgY29tcHV0ZXMgdGhlIHJlc3VsdCBvZiBldmFsdWF0aW5nICJuY2hhciA+IDQiIGZvciBlYWNoIGVsZW1lbnQgb2YgYHNvbWVfd29yZHNgLCBidW5kbGVzIHRoZW0gYWxsIHVwIGludG8gYSB2ZWN0b3IsIGFuZCByZXR1cm5zIGl0LgoKTm90ZSB0aGF0IHRoZSBib29sZWFuIHZlY3RvciBwcm9kdWNlZCBpcyBleGFjdGx5IHRoZSBzYW1lIG9uZSBwYXNzZWQgdG8gW10gaW4gdGhlICJQYXNzaW5nIGEgYm9vbGVhbiB2ZWN0b3IiIGNvZGUgZXhhbXBsZSBlYXJsaWVyLiBUaGVyZWZvcmUsIHdlIGNhbiBzaW1wbHkgcmVwbGFjZSB0aGUgbWFudWFsbHkgdHlwZWQgb3V0IGJvb2xlYW4gdmVjdG9yIHdpdGggdGhlIGNvbmRpdGlvbmFsIGV4cHJlc3Npb24gdG8gYWNoaWV2ZSB0aGUgc2FtZSByZXN1bHQ6CgpgYGAge3J9CiMgVXNpbmcgYSBjb25kaXRpb25hbCBleHByZXNzaW9uIGluc2lkZSBbXQpzb21lX3dvcmRzW25jaGFyKHNvbWVfd29yZHMpID4gNF0KCmBgYApUaGlzIHN5bnRhY3RpYyBzdHJ1Y3R1cmUsIHdoZXJlIHlvdSBhcHBseSB0aGUgW10gb3BlcmF0b3IgdG8gYHNvbWVfd29yZHNgIGFuZCBhbHNvIHVzZSBgc29tZV93b3Jkc2AgaW4gdGhlIGFyZ3VtZW50IHlvdSBwYXNzIHRvIFtdIGlzIHZlcnkgaWRpb21hdGljIFIuIE1hbnkgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2VzIGRvIG5vdCBhbGxvdyBzdWNoIHRoaW5nczsgaWYgeW91IGhhdmUgcHJvZ3JhbW1lZCBhIGxvdCBpbiBtb3JlIHRyYWRpdGlvbmFsIGxhbmd1YWdlcywgaXQgd2lsbCB0YWtlIHlvdSBhIHdoaWxlIHRvIGdldCB1c2VkIHRvIHRoaXMuIEp1c3QgcmVtZW1iZXIgdGhhdCBSIGFsd2F5cyBldmFsdWF0ZXMgdGhlIGlucHV0IGFyZ3VtZW50IGZpcnN0IChpbiB0aGlzIGNhc2UsIGdlbmVyYXRpbmcgYSBib29sZWFuIHZlY3RvcikgYW5kIHRoZW4gcGFzc2VzIHRoZSByZXN1bHQgb2YgdGhhdCBldmFsdWF0aW9uIHRvIFtdLiBNYW55IHBlb3BsZSBmaW5kIGl0IGhlbHBzIHRvIHRoaW5rIHRocm91Z2ggdGhvc2UgdHdvIHN0ZXBzIHNlcGFyYXRlbHksIHdoZW4gdHJ5aW5nIHRvIGZpZ3VyZSBvdXQgd2hhdCBhIGNvbW1hbmQgbGlrZSB0aGlzIHByb2R1Y2VzLgoKCiMjIyBFeGVyY2lzZToKCjEuIFdyaXRlIGFuIFIgY29tbWFuZCB0aGF0IHNlbGVjdHMgZnJvbSBgc29tZV93b3Jkc2AgYWxsIHRoZSBmb3VyLWNoYXJhY3RlciB3b3JkcywgYnV0IG5vIG90aGVycy4KMi4gQ2hlY2sgdG8gc2VlIGlmIGV4ZWN1dGluZyB0aGlzIGNvbW1hbmQgaGFzIGNoYW5nZWQgdGhlIHZhbHVlIG9mIGBzb21lX3dvcmRzYC4gRXhwbGFpbiB3aHkgb3Igd2h5IG5vdC4KMy4gTW9kaWZ5IHRoZSBjb21tYW5kIHNvIHRoYXQgaXQgKipkb2VzKiogY2hhbmdlIGBzb21lX3dvcmRzYCwgd2l0aCB0aGF0IHZlY3RvciBub3cgaG9sZGluZyBvbmx5IHdvcmRzIHdpdGggZXhhY3RseSBmb3VyIGNoYXJhY3RlcnMuCjQuIEV4cGxhaW4gd2hhdCB0aGUgY29tbWFuZCB5b3UganVzdCB3cm90ZSBpbGx1c3RyYXRlcyBhYm91dCB0aGUgb3JkZXIgaW4gd2hpY2ggYXNzaWdubWVudCBzdGF0ZW1lbnRzIGFyZSBldmFsdWF0ZWQuCgoKXAoKIyMjIENvbmRpdGlvbmFsIE9wZXJhdG9ycyBpbiBSCgoKfCBPcGVyYXRpb24gICAgICAgICAgICAgICAgfCBSIFN5bWJvbCB8Cnw6LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18Oi0tLS0tLS0tLS06fAp8IExlc3MgdGhhbiAgICAgICAgICAgICAgICB8IFw8ICAgICAgIHwKfCBMZXNzIHRoYW4gb3IgZXF1YWwgdG8gICAgfCBcPD0gICAgICB8CnwgR3JlYXRlciB0aGFuICAgICAgICAgICAgIHwgXD4gICAgICAgfAp8IEdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byB8IFw+PSAgICAgIHwKfCBOb3QgZXF1YWwgdG8gICAgICAgICAgICAgfCAhPSAgICAgICB8CgoKIyMjIENvbmRpdGlvbmFsIFNlbGVjdGlvbiB3aXRoIGAlaW4lYAoKV2UgaGF2ZSB1c2VkIGA9PWAgdG8gdGVzdCBpZiBvbmUgdmFsdWUgaXMgZXhhY3RseSBlcXVhbCB0byBhbm90aGVyIHZhbHVlLiBPZnRlbiwgd2Ugd2lzaCB0byB0ZXN0IGlmIGEgdmFsdWUgaXMgZXF1YWwgdG8gb25lIG9mIGEgc2V0IG9mIHZhbHVlcyAoaS5lLiBpcyB2YWx1ZSBBIGVxdWFsIHRvIGVpdGhlciB2YWx1ZSBCIG9yIHZhbHVlIEMgb3IgdmFsdWUgRCkuIEluIFIsIHRoaXMgc3BlY2lmaWMgY29tcGxleCBjb25kaXRpb25hbCBsb2dpYyBjYW4gYmUgcGVyZm9ybWVkIHdpdGggdGhlIGAlaW4lYCBvcGVyYXRvcjoKCmBgYHtyfQojICVpbiUgd2l0aCBhIHNjYWxhcgoKIyBHaXZlbiBhIHZlY3Rvci4uLgpjbGVhbl92ZWhpY2xlcyA8LSBjKCJiaWN5Y2xlIiwgInNjb290ZXIiLCAic2thdGVib2FyZCIpCgojIFRlc3QgaWYgYSBzY2FsYXIgaXMgY29udGFpbmVkIGluIHRoZSB2ZWN0b3IKInNjb290ZXIiICVpbiUgY2xlYW5fdmVoaWNsZXMKCiJqZXQgc2tpIiAlaW4lIGNsZWFuX3ZlaGljbGVzCmBgYApJZiB3ZSB1c2UgYCVpbmAgd2l0aCBhIHZlY3RvciBhcyB0aGUgbGVmdCBvcGVyYW5kLCBSIHBlcmZvcm1zIGluIGEgdmVjdG9yaXNlZCB3YXksIGFzIGV4cGVjdGVkLCB0ZXN0aW5nIGVhY2ggZWxlbWVudCBpbiB0dXJuOgoKYGBge3J9CiMgVXNpbmcgJWluJSB3aXRoIGEgdmVjdG9yCm15X3ZlaGljbGVzIDwtIGMoInNrYXRlYm9hcmQiLCAidHJhY3RvciIsICJjYXIiLCAic2Nvb3RlciIpCgpteV92ZWhpY2xlcyAlaW4lIGNsZWFuX3ZlaGljbGVzCgpgYGAKCkFuZCB0aGUgcmVzdWx0aW5nIGJvb2xlYW4gdmVjdG9yIGNhbiwgb2YgY291cnNlLCBiZSBwYXNzZWQgdG8gW106CgpgYGAge3J9CiMgU2VsZWN0IG91dCBteSBjbGVhbiB2ZWhpY2xlcwpteV92ZWhpY2xlc1tteV92ZWhpY2xlcyAlaW4lIGNsZWFuX3ZlaGljbGVzXQoKYGBgClwKCiMjIE1pc3NpbmcgZGF0YQoKT25lIGV4dHJlbWVseSBjb21tb24gc3Vic2V0dGluZyB0YXNrIGlzIGRlYWxpbmcgd2l0aCBtaXNzaW5nIGRhdGEuIE1pc3NpbmcgZGF0YSBhcmlzZXMgZnJlcXVlbnRseSBkdXJpbmcgcmVhbCByZXNlYXJjaC4gRm9yIGV4YW1wbGUsIGFuIGVjb2xvZ2lzdCBzdHVkeWluZyBwZW5ndWluIHBvcHVsYXRpb25zIG1heSBiZSBtZWFzdXJpbmcgdGhlIHdlaWdodCBvZiBlYWNoIHBlbmd1aW4gaW4gYSBsb2NhbCBjb2xvbnkuIElmIGEgcGFydGljdWxhciBwZW5ndWluIHJ1bnMgYXdheSBiZWZvcmUgaXQgY2FuIGJlIHdlaWdoZWQsIHRoYXQgcGVuZ3VpbidzIHdlaWdodCBpcyBtaXNzaW5nLiBJdCB3b3VsZCBiZSBhIG1pc3Rha2UgdG8gY29kZSB0aGUgcGVuZ3VpbidzIHdlaWdodCBhcyAwIC0tIHRoaXMgd291bGQgY29ycnVwdCBhbnkgbnVtZXJpY2FsIGFuYWx5c2lzIG9mIHdlaWdodC4gVGhlcmVmb3JlIFIgcHJvdmlkZXMgYSBzcGVjaWFsIGRhdGEgZW50aXR5IGZvciAnbWlzc2luZycgb3IgJ3VuZGVmaW5lZCcuIE1pc3NpbmcgZGF0YSBpbiBSIGlzIHJlcHJlc2VudGVkIGJ5IGBOQWAuIAoKVGhlIGNvbmRpdGlvbmFsIG9wZXJhdG9ycyB3ZSB1c2VkIGFib3ZlIGNhbm5vdCBiZSBhcHBsaWVkIHRvIE5BLiBBbnkgb3BlcmF0aW9uIGZvciB3aGljaCBvbmUgb3IgbW9yZSBvcGVyYW5kcyBpcyBOQSB3aWxsIHJldHVybiBOQSAoZXZlbiBgTkEgPT0gTkFgIHdpbGwgcmV0dXJuIGBOQWApLiBUbyB0ZXN0IGZvciBOQSwgdGhlcmVmb3JlLCBSIHByb3ZpZGVzIGZ1bmN0aW9uIGBpcy5uYWAgd2hpY2ggcmV0dXJucyBgVFJVRWAgaXRzIGlucHV0IGlzIGBOQWAgYW5kIGBGQUxTRWAgaW4gYWxsIG90aGVyIGluc3RhbmNlcy4KCmBgYHtyfQojIFBlbmd1aW4gIzMgZ290IGF3YXkuLi4uCnBlbmd1aW5fd2VpZ2h0c19nIDwtIGMoMzQ3NSwgMjk3NSwgTkEsIDM0MjApCgojIFVzZSBpcy5uYSB0byBnZW5lcmF0ZSBhIGJvb2xlYW4gdmVjdG9yCmlzLm5hKHBlbmd1aW5fd2VpZ2h0c19nKQoKIyBVc2UgdGhlIGJvb2xlYW4gdmVjdG9yIHRvIHNlbGVjdCBldmVyeW9uZSAKIyB3aG8gaXMgbm90IE5BLiBOb3RlIHRoZSB1c2Ugb2YgIQpwZW5ndWluX3dlaWdodHNfZ1shaXMubmEocGVuZ3Vpbl93ZWlnaHRzX2cpXQoKYGBgCgpcCgojIyBTdWJzZXR0aW5nIGluIHR3byBkaW1lbnNpb25zCgpUaGUgW10gb3BlcmF0b3IgaXMgYWxzbyB1c2VkIGZvciBzZWxlY3Rpbmcgc3Vic2V0cyBmcm9tIGRhdGEgZnJhbWVzLiBJbiB0aGlzIHVzYWdlLCBvbmUgc3VwcGxpZXMgdHdvIGFyZ3VtZW50cyB0byBbXSwgc2VwYXJhdGVkIGJ5IGNvbW1hcy4gVGhlIGZpcnN0IGFyZ3VtZW50IHNwZWNpZmllcyB3aGljaCByb3cocykgdG8gc2VsZWN0IGFuZCB0aGUgc2Vjb25kIHNwZWNpZmllcyB3aGljaCBjb2x1bW4ocykuIFRoZSBnZW5lcmFsIHN5bnRheCBpczogKm5hbWVfb2ZfZGF0YV9mcmFtZVtyb3dfaW5mb3JtYXRpb24sIGNvbHVtbl9pbmZvcm1hdGlvbl0qLiBUaGVyZSBhcmUsIGhvd2V2ZXIsIG1hbnkgY29tcGxleCBvcHRpb25zIGZvciB0aGUgZm9ybWF0IG9mIHRoZSByb3cgYW5kIGNvbHVtbiBpbmZvcm1hdGlvbi4gV2Ugd2lsbCBjb3ZlciB0aGUgbW9zdCB1c2VmdWwgaGVyZS4KCmBgYHtyfQojIENyZWF0ZSBhIGRhdGEgZnJhbWUgdG8gcHJhY3RpY2UgdHdvLWRpbWVuc2lvbmFsIHNlbGVjdGlvbgpjb3VudHJpZXMgPC0gYygiQXVzdHJpYSIsICJCcmF6aWwiLCAiQ2FuYWRhIiwgIkRlbm1hcmsiKQpjYXBpdGFscyA8LSBjKCJWaWVubmEiLCAiQnJhc2lsaWEiLCAiT3R0YXdhIiwgIkNvcGVuaGFnZW4iKQpwb3B1bGF0aW9uX2luX21pbGxpb25zIDwtIGMoOSwgMjExLCAzOCwgNikKCmdlb2dyYXBoeV9kZiA8LSBkYXRhLmZyYW1lKENvdW50cnkgPSBjb3VudHJpZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIENhcGl0YWwgPSBjYXBpdGFscywKICAgICAgICAgICAgICAgICAgICAgICAgICAgUG9wdWxhdGlvbk1pbGxpb25zID0gcG9wdWxhdGlvbl9pbl9taWxsaW9ucykKCmdlb2dyYXBoeV9kZgoKYGBgCgoKSW4gdGhlIHNpbXBsZXN0IGNhc2UsIHdlIHdpc2ggdG8gc2VsZWN0IGEgc2luZ2xlIHZhbHVlIGZyb20gYSBkYXRhIGZyYW1lLCBzbyB3ZSBwcm92aWRlIHRoZSByb3cgaW5kZXggYW5kIGNvbHVtbiBpbmRleCBvZiB0aGUgY2VsbCBvZiBpbnRlcmVzdC4gRm9yIGV4YW1wbGUsIGltYWdpbmUgd2Ugd2FudCB0aGUgcG9wdWxhdGlvbiBvZiBWaWVubmEuIFdlIGtub3cgdGhhdCBWaWVubmEgaXMgaW4gcm93IDEgYW5kIHRoZSBwb3B1bGF0aW9uIGlzIGluIGNvbHVtbiAzLiBUbyBzZWxlY3QgdGhhdCBjZWxsIHdlIHByb3ZpZGUgMSBmb3IgdGhlIHJvdyBpbmZvcm1hdGlvbiBhbmQgMyBmb3IgdGhlIGNvbHVtbiBpbmZvcm1hdGlvbiBpbiB0aGUgc3F1YXJlIGJyYWNrZXRzOgoKYGBge3Igc2luZ2xlIHNlbGVjdGlvbn0KZ2VvZ3JhcGh5X2RmWzEsM10KYGBgCgpEb24ndCB3b3JyeSBhYm91dCBob3cgeW91IHdvdWxkIGtub3cgdGhlIHNwZWNpZmljIHJvdyBhbmQgY29sdW1uIG9mIHRoZSBjZWxsIHlvdSBhcmUgaW50ZXJlc3RlZCBpbi4gVGhpcyBwYXJ0aWN1bGFyIHNlbGVjdGlvbiBvcGVyYXRpb24gaXMgdHlwaWNhbGx5IHVzZWQgaW4gc2l0dWF0aW9ucyB3aGVyZSB5b3VyIGNvZGUgaXMgY29tcHV0aW5nIHRob3NlIHZhbHVlcyBiYXNlZCBvbiBjb21wbGV4IGNyaXRlcmlhLiBUaGlzIGV4YW1wbGUgaXMgbWVyZWx5IGlsbHVzdHJhdGl2ZS4KClRoZXJlIGFyZSB0d28gdmVyeSB1c2VmdWwgZXh0ZW5zaW9ucyB0byB0aGlzIHBhdHRlcm46CgoxLiAgRWl0aGVyIHRoZSByb3cgb3IgY29sdW1uIGluZGV4IChvciBib3RoKSBtYXkgc3BlY2lmeSBhICoqcmFuZ2UqKiB1c2luZyB0aGUgYDpgIG9wZXJhdG9yLiBGb3IgZXhhbXBsZSwgYDE6M2Agb3IgYDY6MTJgICh0aGVzZSBhcmUgIjEgdG8gMyIgYW5kICI2IHRvIDEyIiByZXNwZWN0aXZlbHkpLgoKYGBge3IgcmFuZ2V9CiMgRm9yIHJvd3MgMiB0byA0IChCcmF6aWwsIENhbmFkYSwgRGVubWFyayksIHNlbGVjdCB0aGUgcG9wdWxhdGlvbiAoY29sdW1uIDMpCmdlb2dyYXBoeV9kZlsyOjQsIDNdCgojIEZvciBDYW5hZGEgKHJvdyAzKSwgc2VsZWN0IGJvdGggdGhlIGNhcGl0YWwgbmFtZSBhbmQgcG9wdWxhdGlvbiAoY29scyAyIGFuZCAzKQpnZW9ncmFwaHlfZGZbMywgMjozXQoKYGBgCgoyLiAgRWl0aGVyIHRoZSByb3cgb3IgY29sdW1uIGluZGV4ICoqbWF5IGJlIG9taXR0ZWQqKi4gVGhhdCBpcywgd2UgY2FuIHNheSBgZ2VvZ3JhcGh5X2RmWzMgLCBdYCBvciBgZ2VvZ3JhcGh5X2RmWyAsIDJdYC4gVGhlIG1pc3NpbmcgZWxlbWVudCBpcyBpbnRlcnByZXRlZCBhcyAqKmFsbCoqLiBPbWl0IHRoZSByb3cgbnVtYmVyIGFuZCB5b3Ugd2FudCAqKmFsbCByb3dzKiogaW4gdGhlIHN1cHBsaWVkIGNvbHVtbihzKS4gT21pdCB0aGUgY29sdW1uIG51bWJlciBhbmQgeW91IHdhbnQgKiphbGwgY29sdW1ucyoqIGluIHRoZSBzdXBwbGllZCByb3cocykuCgpgYGB7ciBvbWl0dGVkIGluZGV4fQojIEZvciBEZW5tYXJrIChyb3cgNCksIHNlbGVjdCBhbGwgdGhlIGNvbHVtbnMKZ2VvZ3JhcGh5X2RmWzQsIF0KCiMgRm9yIGFsbCByb3dzLCBzZWxlY3QgdGhlIGNhcGl0YWwgY2l0eSBuYW1lIChjb2x1bW4gMikKZ2VvZ3JhcGh5X2RmWyAsIDJdCgpgYGAKCllvdSBtYXkgaGF2ZSBiZWVuIHN1cnByaXNlZCBieSB0aGUgb3V0cHV0IGdlbmVyYXRlZCBieSB0aGF0IGxhc3QgZXhhbXBsZS4gQWx0aG91Z2ggeW91IGhhdmUgc2VsZWN0ZWQgYSBzaW5nbGUgY29sdW1uLCB0aGUgb3V0cHV0IGlzIHByaW50ZWQgaG9yaXpvbnRhbGx5LCBhcyB0aG91Z2ggaXQgd2VyZSBhIHJvdy4gVGhpcyBpcyBhIHBlY3VsaWFyaXR5IG9mIFIuIEFueSBjb2xsZWN0aW9uIHRoYXQgaGFzIGEgc2luZ2xlIGRpbWVuc2lvbiAoaS5lLiBkb2Vzbid0IGhhdmUgYm90aCBjb2x1bW5zIGFuZCByb3dzKSBpcyB0cmVhdGVkIGFzIGEgcGxhaW4gdmVjdG9yLiBBbmQgdmVjdG9ycyBhcmUgYWx3YXlzIHByaW50ZWQgaG9yaXpvbnRhbGx5LiBCeSBleHRlbnNpb24sIHNpbmNlIGEgc2VsZWN0ZWQgY29sdW1uIG9mIGEgZGF0YSBmcmFtZSBpcyBhIHZlY3RvciwgeW91IGNhbiBhcHBseSBldmVyeXRoaW5nIHlvdSBoYXZlIGxlYXJuZWQgYWJvdXQgdmVjdG9ycyB0byBzZWxlY3RlZCBkYXRhIGZyYW1lIGNvbHVtbnMsIHdoaWNoIGlzIGV4YWN0bHkgd2hhdCB3ZSB3YW50IHRvIGJlIGFibGUgdG8gZG8uCgpZb3UgY2FuIGNvbWJpbmUgcmFuZ2VzIGFuZCB0aGUgKm1pc3NpbmcgaW5kZXggPSBhbGwqIHRlY2huaXF1ZToKCmBgYHtyIHRvZ2V0aGVyfQojIEZvciB0aGUgZmlyc3QgdGhyZWUgcm93cywgc2VsZWN0IGFsbCB0aGUgY29sdW1ucwpnZW9ncmFwaHlfZGZbMTozICwgXQoKYGBgCgojIyMgRXhlcmNpc2UKCjEuIFdoYXQgZG8geW91IHRoaW5rIGBnZW9ncmFwaHlfZGZbICwgXWAgKGkuZS4gd2hlcmUgYm90aCByb3cgYW5kIGNvbHVtbiBpbmZvcm1hdGlvbiBhcmUgb21pdHRlZCkgd2lsbCBkbz8gCjIuIFRyeSBpdC4gV2VyZSB5b3UgcmlnaHQ/CgpcCgpJbnN0ZWFkIG9mIHVzaW5nIGNvbHVtbiBudW1iZXJzLCB5b3UgY2FuIHByb3ZpZGUgY29sdW1uIG5hbWVzIGFzIHRoZSBjb2x1bW4gaW5mb3JtYXRpb24gKGFuZCByb3cgbmFtZXMgYXMgdGhlIHJvdyBpbmZvcm1hdGlvbiBpZiB5b3VyIGRhdGEgZnJhbWUgaGFzIG5hbWVkIHJvd3MpLiBVc2UgdGhlIGNvbWJpbmUgZnVuY3Rpb24gYGMoKWAgdG8gcHJvdmlkZSBtdWx0aXBsZSBjb2x1bW4gbmFtZXMsIGFuZCBiZSBzdXJlIHRvIHN1cnJvdW5kIGVhY2ggY29sdW1uIG5hbWUgd2l0aCBxdW90ZXMsIGJlY2F1c2UgUiBjb25zaWRlcnMgdGhlbSB0byBiZSBzdHJpbmdzIGluIHRoaXMgc2l0dWF0aW9uLgoKYGBge3IgbmFtZWQgY29sdW1uc30KZ2VvZ3JhcGh5X2RmWzI6NCwgIkNhcGl0YWwiXQoKZ2VvZ3JhcGh5X2RmWzM6NCwgYygiQ291bnRyeSIsICJDYXBpdGFsIildCmBgYAoKXAoKIyMgRnVuY3Rpb24gYHN1YnNldGAKCkFuIGFsdGVybmF0aXZlIGZvciBzZWxlY3Rpbmcgcm93cyBhbmQgY29sdW1ucyBpcyBmdW5jdGlvbiBgc3Vic2V0YCwgd2l0aCBzdHJ1Y3R1cmU6Cgpgc3Vic2V0KHggPSBkYXRhZnJhbWUsIHN1YnNldCA9IGNvbmRpdGlvbmFsX3N0YXRlbWVudF90b19hcHBseV90b19yb3dzLCBzZWxlY3QgPSBjb2x1bW5zX3RvX2tlZXApYAoKCmBgYHtyfQpjb3VudHJpZXNfb3Zlcl8zMG1pbGxpb24gPC0gc3Vic2V0KGdlb2dyYXBoeV9kZiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3Vic2V0ID0gUG9wdWxhdGlvbk1pbGxpb25zID4gMzAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCA9IGMoIkNvdW50cnkiLCAiUG9wdWxhdGlvbk1pbGxpb25zIikgKQpjb3VudHJpZXNfb3Zlcl8zMG1pbGxpb24KYGBgCgpPbWl0dGluZyB2YWx1ZXMgZm9yIHRoZSBgc3Vic2V0YCBhcmd1bWVudCBvciBgc2VsZWN0YCBhcmd1bWVudCB3aWxsIGV4dHJhY3QgYWxsIHJvd3Mgb3IgY29sdW1ucywgcmVzcGVjdGl2ZWx5LgoKXAoKIyMgU2VsZWN0aW5nIGNvbHVtbnMKCkRhdGEgZnJhbWVzIGFyZSBjb21tb25seSBvcmdhbmlzZWQgd2l0aCBhIGNvbHVtbiBmb3IgZWFjaCBkYXRhIHZhcmlhYmxlIGFuZCBhIHJvdyBmb3IgZWFjaCBpbnN0YW5jZS4gVG8gYW5hbHlzZSBhIHBhcnRpY3VsYXIgZGF0YSB2YXJpYWJsZSwgd2Ugd2lzaCB0byBzZWxlY3QgYWxsIHJvd3MgaW4gYSBjb2x1bW4uIFRoaXMgcGFydGljdWxhciBzdWJzZXR0aW5nIG9wZXJhdGlvbiBpcyBzbyBjb21tb24gdGhhdCB0aGVyZSBhcmUgYWRkaXRpb25hbCwgZWZmaWNpZW50IHdheXMgdG8gcGVyZm9ybSBpdCBpbiBSLgoKVG8gc2VsZWN0IGEgc2luZ2xlIGNvbHVtbiBmcm9tIGEgZGF0YSBmcmFtZSwgdXNlIHRoZSBgJGAgb3BlcmF0b3IsIGZvbGxvd2VkIGJ5IHRoZSBjb2x1bW4gbmFtZSAoZG91YmxlIHF1b3RlcyBhcmUgbm90IHVzZWQgaW4gdGhpcyBjb250ZXh0KS4KCmBgYHtyfQpnZW9ncmFwaHlfZGYkQ291bnRyeQpgYGAKClRoaXMgb3BlcmF0aW9uIGlzIGNvbW1vbmx5IHVzZWQgd2hlbiBwZXJmb3JtaW5nIHN1bW1hcnkgb3BlcmF0aW9ucyBvbiBlbnRpcmUgY29sdW1uczoKCmBgYHtyfQojIE1lYW4gb2YgYSB0aGUgUG9wdWxhdGlvbk1pbGxpb25zIGNvbHVtbgptZWFuKGdlb2dyYXBoeV9kZiRQb3B1bGF0aW9uTWlsbGlvbnMpCmBgYAoKClRoZSBgJGAgb3BlcmF0b3IgY2FuIGFsc28gYmUgdXNlZCAqdG8gY3JlYXRlIG5ldyBjb2x1bW5zKi4gU2ltcGx5IGdpdmUgYSBuYW1lIHRvIHRoZSBuZXcgY29sdW1uIG9uIHRoZSBsZWZ0IGhhbmQgb2YgYW4gYXNzaWdubWVudCBzdGF0ZW1lbnQsIGFuZCB0aGUgY29udGVudHMgb2YgdGhlIG5ldyBjb2x1bW4gb24gdGhlIHJpZ2h0IGhhbmQgc2lkZS4gKE5COiBUaGlzIHR5cGUgb2Ygb3BlcmF0aW9uIGlzIG5vdCBhbGxvd2VkIGluIG1vcmUgdHJhZGl0aW9uYWwgbGFuZ3VhZ2VzLCBidXQgaXMgdmVyeSBjb21tb24gaW4gUi4pCgpgYGB7cn0KIyBDcmVhdGUgYSBuZXcgY29sdW1uIGVuIHBhc3NhbnQKZ2VvZ3JhcGh5X2RmJFBvcHVsYXRpb25UaG91c2FuZHMgPC0gZ2VvZ3JhcGh5X2RmJFBvcHVsYXRpb25NaWxsaW9ucyAqIDEwMDAKCiMgQ2hlY2sgdGhhdCB0aGUgY29sdW1uIGhhcyBiZWVuIGNyZWF0ZWQKc3RyKGdlb2dyYXBoeV9kZikKCiMgUHJpbnQgdGhlIGNvbnRlbnRzIG9mIHRoZSBuZXcgY29sdW1uCmdlb2dyYXBoeV9kZiRQb3B1bGF0aW9uVGhvdXNhbmRzCmBgYAoKXAoKIyMgU3Vic2V0dGluZyB3aXRoIGBkcGx5cmAKCldlIHdpbGwgbm93IHN3aXRjaCB0byBhIGxhcmdlciBkYXRhIHNldCwgYW5kIHNlZSBob3cgdGhlIHR5cGVzIG9mIHNlbGVjdGlvbiBvcGVyYXRpb25zIGRlc2NyaWJlZCBhYm92ZSBhcmUgcGVyZm9ybWVkIHdpdGggdGhlIGBkcGx5cmAgbGlicmFyeS4gVGhlcmUgYXJlIGZpdmUgbWFpbiBmdW5jdGlvbnMgaW4gYGRwbHlyYDogZmlsdGVyLCBzZWxlY3QsIG11dGF0ZSAobm90IGNvdmVyZWQgaW4gdGhpcyBzZXNzaW9uKSwgZ3JvdXBfYnksIGFuZCBzdW1tYXJpc2UuIFdlIHdpbGwgc2VlIGhvdyB0aGV5IGNhbiBiZSB1c2VkIHRvIHBlcmZvcm0gZnVuZGFtZW50YWwgcHJvY2Vzc2luZyBvZiBzZWxlY3RlZCBwb3J0aW9ucyBvZiBkYXRhIHNldHMuCgpUbyB1c2UgYGRwbHlyYCwgeW91IG11c3QgZmlyc3QgaW5zdGFsbCBpdCBvbiB5b3VyIG1hY2hpbmUgd2l0aCBgaW5zdGFsbC5wYWNrYWdlc2AuIEFsdGVybmF0aXZlbHksIGlmIHlvdSBoYXZlIGluc3RhbGxlZCBwYWNrYWdlIGB0aWR5dmVyc2VgLCBgZHBseXJgIHdpbGwgaGF2ZSBiZWVuIGluc3RhbGxlZCBhcyBwYXJ0IG9mIHRoYXQgb3BlcmF0aW9uLiBUbyBsb2FkIGBkcGx5cmAgZm9yIHVzZSBkdXJpbmcgYW4gUlN0dWRpbyBzZXNzaW9uLCB1c2UgdGhlIGBsaWJyYXJ5YCBjb21tYW5kLCBhcyB3ZSBoYXZlIGRvbmUgcHJldmlvdXNseS4KCkZvciB0aGlzIHNlY3Rpb24sIHdlIHdpbGwgdXNlIGRhdGEgYWJvdXQgZm9yZXN0IGZpcmVzIGluIFBvcnR1Z2FsIGluIDIwMjIuIFBvcnR1Z2FsIGhhcyBhIGhpZ2ggaW5jaWRlbmNlIG9mIGZvcmVzdCBmaXJlLCBhbmQgdGhlc2UgZGF0YSBjYW4gcmV2ZWFsIHBhdHRlcm5zIGFib3V0IG9jY3VycmVuY2UgYW5kIHNldmVyaXR5LgoKWW91IGNhbiBkb3dubG9hZCB0aGUgZGF0YSBmaWxlICpmb3Jlc3RfZmlyZXNfcG9ydHVnYWwuY3N2KiBmcm9tIHRoaXMgbGluazoKCmh0dHBzOi8vZHJpdmUuZ29vZ2xlLmNvbS9kcml2ZS9mb2xkZXJzLzFVQnAtUDR3RkFhUUwzZWdJUTdkR2EyUlFlNlJRS3FneSBvciB1c2luZzoKCj4KPmBgYHtyLCBldmFsPUZBTFNFfQo+IGRvd25sb2FkLmZpbGUodXJsID0gImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9ydGlzLXRyYWluaW5nLzIwMjMtczItcjRzc3AvbWFpbi9kYXRhL2ZvcmVzdF9maXJlc19wb3J0dWdhbC5jc3YiLCAKPiAgICAgICAgICAgICAgZGVzdGZpbGUgPSAiZGF0YS9mb3Jlc3RfZmlyZXNfcG9ydHVnYWwuY3N2IikKPmBgYAo+IF9SZW1lbWJlciB0aGF0IFIgaXMgY2FzZSBzZW5zaXRpdmUgc28gaWYgeW91IGRvbid0IGhhdmUgYSBkaXJlY3RvcnkgZXhhY3RseSBjYWxsZWQgYGRhdGEvYCBtb2RpZnkgdGhlIGNvbW1hbmQgdG8gbWF0Y2ggeW91ciBkaXJlY3RvcnkuXwoKVGhlIGZpbGUgY29udGFpbnMgb25lIHJvdyBmb3IgZWFjaCByZWNvcmRlZCBmb3Jlc3QgZmlyZSBpbiBQb3J0dWdhbCBpbiAyMDIyLiBFYWNoIHJlY29yZCBoYXMgYSBudW1iZXIgb2YgbWVhc3VyZXMgKGNvbHVtbnMpIGluY2x1ZGluZyByZWdpb24gKHggYW5kIHkgdmFsdWVzIG9uIGEgZ3JpZCksIG1vbnRoLCBkYXksIGdyb3VuZCBjb25kaXRpb24gbWVhc3VyZXMsIG1ldGVvcm9sb2dpY2FsIG1lYXN1cmVzLCBhbmQgdGhlIGV4dGVudCBvZiB0aGUgZmlyZSBpbiBoZWFjdGFyZXMuIE5vdGUgdGhhdCBhbnkgZmlyZSB0aGF0IGNvbnN1bWVkIGxlc3MgdGhhbiBvbmUgaGVjdGFyZSBoYXMgYSB2YWx1ZSBvZiAwIGluIHRoaXMgbGFzdCBjb2x1bW4uCgpJbiB0aGUgY29kZSB0aGF0IGZvbGxvd3MsIHdlIHdpbGwgYXNzdW1lIHRoYXQgeW91IGFyZSB3b3JraW5nIGluIGEgcHJvamVjdCwgdGhhdCB0aGUgcHJvamVjdCBmb2xkZXIgaGFzIGEgc3ViLWZvbGRlciBjYWxsZWQgKipkYXRhKiogYW5kIHRoYXQgdGhlIC5jc3YgZmlsZSBoYXMgYmVlbiBwbGFjZWQgaW4gdGhhdCBmb2xkZXIuCgpgYGB7ciBsb2FkIGRhdGEsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2UgPSBGQUxTRX0KIyBMb2FkIGRwbHlyCmxpYnJhcnkoZHBseXIpCgoKIyBJbXBvcnQgdGhlIGNzdiBmaWxlIGludG8gYSBkYXRhIGZyYW1lCmZpcmVzX2RmIDwtIGZpcmVzX2RmIDwtIHJlYWQuY3N2KCJkYXRhL2ZvcmVzdF9maXJlc19wb3J0dWdhbC5jc3YiKQoKIyBJbnNwZWN0IHRoZSBkYXRhCnN0cihmaXJlc19kZikKCmBgYAoKIyMjIFNlbGVjdGluZyBjb2x1bW5zCgpUbyBleHRyYWN0IGluZGl2aWR1YWwgY29sdW1ucywgdXNlIGZ1bmN0aW9uIGBzZWxlY3RgLCBwYXNzaW5nIGluIHRoZSBkYXRhZnJhbWUsIGFuZCB0aGUgbmFtZXMgb2YgdGhlIGNvbHVtbnMgeW91IHdhbnQuIFRoZXJlIGlzIG5vIG5lZWQgdG8gZm9ybWF0IHRoZSBjb2x1bW4gbmFtZXMgaW50byBhIHZlY3Rvciwgb3IgdG8gdXNlIGRvdWJsZSBxdW90ZXMuCgpgYGB7ciwgcmVzdWx0cz0naGlkZSd9CiMgU2VsZWN0IHRoZSBGaXJlQXJlYUhhIGNvbHVtbiwgd2hpY2ggc2hvd3MgYXJlYSBkYW1hZ2VkIGJ5IHRoZSBmaXJlIGluIGhlY3RhcmVzCnNlbGVjdChmaXJlc19kZiwgRmlyZUFyZWFIYSkKYGBgCgpgYGB7cn0KIyBTZWxlY3QgdGhlIG1vbnRoIGFuZCBmaXJlIGFyZWEgY29sdW1ucywgYW5kIHN0b3JlIHRoZW0gaW4gYSBuZXcgdmVjdG9yCm1vbnRoX2FyZWFfZGYgPC0gc2VsZWN0KGZpcmVzX2RmLCBNb250aCwgRmlyZUFyZWFIYSkKCiMgSW5zcGVjdAptb250aF9hcmVhX2RmWzM1MDozNTUsXSAjIFlvdSBjYW4gY29tYmluZSBiYXNlIFIgW10gd2l0aCBkcGx5cgoKIyBGb3IgZWZmaWNpZW5jeSwgeW91IGNhbiBkZWZpbmUgYSB2ZWN0b3Igb2YgY29sdW1uIG5hbWVzIHRvIHVzZSB3aGVuZXZlcgojIG5lZWRlZC4gVXNlIGRvdWJsZSBxdW90ZXMgYXMgcGVyIHVzdWFsCnNlbGVjdGVkX2NvbHMgPC0gYygiSHVtaWRpdHkiLCAiRmlyZUFyZWFIYSIpCmh1bWlkaXR5X2FyZWFfZGYgPC0gc2VsZWN0KGZpcmVzX2RmLCBhbGxfb2Yoc2VsZWN0ZWRfY29scykpCgojIEV4YW1wbGUgYW5hbHlzaXMgdXNpbmcgdHdvIGNvbHVtbnMKY29yKGh1bWlkaXR5X2FyZWFfZGYpCgpgYGAKCjwhLS0KLSB1c2luZyBoZWxwZXIgZnVuY3Rpb25zCiAgLSBzdGFydHNfd2l0aAogIC0gZW5kc193aXRoCiAgLSBjb250YWlucwogIC0gYW55b2YKLS0+CgoKXAoKIyMjIFNlbGVjdGluZyByb3dzCgpJbiBjb21wdXRpbmcsIHRoZSBwcm9jZXNzIG9mIHNlbGVjdGluZyByb3dzIGZyb20gYSBkYXRhIHRhYmxlIGJhc2VkIG9uIHBhcnRpY3VsYXIgY3JpdGVyaWEgaXMgY2FsbGVkICoqZmlsdGVyaW5nKiouIFdpdGggYGRwbHlyYCB3ZSB1c2UgZnVuY3Rpb24gYGZpbHRlcmAsIHBhc3NpbmcgdGhlIG5hbWUgb2YgdGhlIGRhdGEgZnJhbWUgYW5kIHRoZSBmaWx0ZXIgY29uZGl0aW9uLiBUaGUgcmVzdWx0IGlzIGEgbmV3IGRhdGEgZnJhbWUgdGhhdCBjb250YWlucyBhbGwgcm93cyBmcm9tIHRoZSBvcmlnaW5hbCBmb3Igd2hpY2ggdGhlIGZpbHRlciBjb25kaXRpb24gZXZhbHVhdGVkIHRvIFRSVUUuCgpgYGB7cn0KIyBFeHRyYWN0IGFsbCBmaXJlcyB0aGF0IG9jY3VycmVkIGluIE9jdG9iZXIgKGkuZS4gd2hlcmUgdGhlIE1vbnRoIGNvbHVtbiBjb250YWlucwojICdvY3QnKQpvY3RvYmVyX2ZpcmVzIDwtIGZpbHRlcihmaXJlc19kZiwgTW9udGggPT0gJ29jdCcpCgojIENvbXB1dGUgdGhlIG1lYW4gZHJvdWdodCBsZXZlbCBmb3IgYWxsIGZpcmVzIGluIG9jdG9iZXIsIHVzaW5nIGJhc2UgUgojIGNvbHVtbiBzZWxlY3Rpb24gd2l0aCAkCm1lYW4ob2N0b2Jlcl9maXJlcyREcm91Z2h0TGV2ZWwpCgpgYGAKCiMjIyBFeGVyY2lzZQoKMS4gSG93IHdvdWxkIHlvdSBnZW5lcmF0ZSBkYXRhIGZyYW1lIG9jdG9iZXJfZmlyZXMgdXNpbmcgW10gaW4gYmFzZSBSPwoyLiBSZWZlcnJpbmcgdG8gdGhlIFZpc3VhbGlzYXRpb24gTW9kdWxlLCBob3cgd291bGQgeW91IHNlbGVjdCB0aGUgRGVubWFyayBkYXRhIHVzaW5nIGRwbHlyPwoKCiMjIyBGaWx0ZXJpbmcgd2l0aCBjb21wbGV4IGNvbmRpdGlvbmFscwoKT2Z0ZW4gd2Ugd2lzaCB0byBmaWx0ZXIgb24gY3JpdGVyaWEgdGhhdCBpbnZvbHZlIG11bHRpcGxlIGNvbXBhcmlzb25zLiBGb3IgZXhhbXBsZSwgaWYgd2Ugd2lzaCB0byBleHRyYWN0IGFsbCB0aGUgcm93cyBmb3IgZmlyZXMgZHVyaW5nIHRoZSB3aW50ZXIgc2Vhc29uIChEZWNlbWJlciB0aHJvdWdoIEZlYnJ1YXJ5IGluIFBvcnR1Z2FsKSB3ZSB3YW50IHJvd3MgZm9yIHdoaWNoIE1vbnRoIGlzICdkZWMnIG9yICdqYW4nIG9yICdmZWInLiBFYXJsaWVyIHdlIHNhdyBob3cgdG8gZG8gdGhpcyB3aXRoYCVpbiVgLiBNb3JlIGdlbmVyYWxseSwgd2UgY2FuIGNvbWJpbmUgY29uZGl0aW9uYWwgc3RhdGVtZW50cyB1c2luZyB0aGUgbG9naWNhbCBBTkQgYW5kIE9SIG9wZXJhdG9ycywgYCZgIGFuZCBgfGAgcmVzcGVjdGl2ZWx5LgoKYGBge3J9CiMgU2VsZWN0IHRoZSB3aW50ZXIgZmlyZXMKd2ludGVyX2RmIDwtIGZpbHRlcihmaXJlc19kZiwgTW9udGggPT0gImRlYyIgfCBNb250aCA9PSAiamFuIiB8IE1vbnRoID09ICJmZWIiKQpgYGAKCgojIyMgRXhlcmNpc2U6CgpUaGUgWFJlZ2lvbiBhbmQgWVJlZ2lvbiBmaWVsZHMgYXJlIGNvb3JkaW5hdGVzIGluIGEgcHJlLWRlZmluZWQgOSBieSA5IGdyaWQgdGhhdCBjb3ZlcnMgYWxsIG9mIFBvcnR1Z2FsLiBZb3Ugd2FudCB0byBmaW5kIGFsbCBmaXJlcyB0aGF0IG9jY3VycmVkIG9uIHRoZSBlYXN0IGFuZCB3ZXN0IGJvcmRlcnMgb2YgdGhlIGNvdW50cnkgLS0gdGhhdCBpcywgaW4gWFJlZ2lvbnMgMSwgMiwgOCwgb3IgOS4gRmlsdGVyIGZvciB0aGVzZSByZWNvcmRzLiBNYWtlIHlvdXIgZXhwcmVzc2lvbiBhcyBzdWNjaW5jdCBhcyB5b3UgY2FuLiAoWW91IG9ubHkgbmVlZCBvbmUgYHxgLikKCmBgYHtyfQp4X2VkZ2VfZmlyZXMgPC0gZmlsdGVyKGZpcmVzX2RmLCBYUmVnaW9uIDw9IDIgfCBYUmVnaW9uID49IDgpCmBgYAoKCgojIyMgRXhlcmNpc2U6CgpGcmVxdWVudGx5LCB3ZSB3YW50IGV4dHJhY3QgYSBzdWJzZXQgb2Ygcm93cyAqYW5kKiBhIHN1YnNldCBvZiBjb2x1bW5zIGZyb20gYSBsYXJnZSBkYXRhIHNldCAtLSB0aGF0IGlzLCB3ZSB3aWxsIHdhbnQgdG8gcGVyZm9ybSBib3RoIGEgc2VsZWN0IGFuZCBhIGZpbHRlciBvcGVyYXRpb24uIFVzaW5nIGFuIGludGVybWVkaWF0ZSB2YXJpYWJsZSwgd3JpdGUgY29kZSB0byBleHRyYWN0IG1vbnRoLCB0ZW1wZXJhdHVyZSwgYW5kIGZpcmUgYXJlYSBmb3Igb25seSB0aGUgc3VtbWVyIG1vbnRocyAoSnVuZSwgSnVseSwgYW5kIEF1Z3VzdCkuIE5vdGUgdGhhdCBsYXRlciBpbiB0b2RheSdzIHNlc3Npb24gd2Ugd2lsbCBzZWUgYW4gYWx0ZXJuYXRpdmUgImRwbHlyIHN5bnRheCIgZm9yIHRoaXMgY29tYmluZWQgb3BlcmF0aW9uLCBidXQgaXQgZ29vZCB0byBtYXN0ZXIgYm90aCBhcHByb2FjaGVzLgoKYGBge3J9CiMgRXhlcmNpc2UgU29sdXRpb24gKHRoZXJlIGFyZSBtYW55IHBvc3NpYmxlIHNvbHV0aW9ucykKCiMgRmlsdGVyIHRvIGdldCB0aGUgcm93cyB3ZSB3YW50CnN1bW1lcl9maXJlc19kZiA8LSBmaWx0ZXIoZmlyZXNfZGYsIE1vbnRoICVpbiUgYygnanVuJywgJ2p1bCcsJ2F1ZycpKQoKIyBQYXNzIHRoZSByZXN1bHQgb2YgdGhlIGZpbHRlcmluZyBvcGVyYXRpb24gdG8gc2VsZWN0CnN1bW1lcl90ZW1wZXJhdHVyZV9hcmVhX2RmIDwtIHNlbGVjdChzdW1tZXJfZmlyZXNfZGYsIE1vbnRoLCBUZW1wZXJhdHVyZSwgRmlyZUFyZWFIYSkKYGBgCgoKCgpcCgojIyBTb3J0aW5nCgpTb3J0aW5nIGlzIGFuIGV4dHJlbWVseSBjb21tb24gb3BlcmF0aW9uIG9uIGxhcmdlIGRhdGEgc2V0cywgYXMgaXQgbWFrZXMgaXQgZWFzaWVyIHRvIGluc3BlY3Qgb3VyIGRhdGEgZWZmaWNpZW50bHkuIFRvIHNvcnQgd2l0aCBgZHBseXJgLCB1c2UgZnVuY3Rpb24gYGFycmFuZ2VgLiBQYXNzIGluIHRoZSBuYW1lIG9mIHRoZSBkYXRhIGZyYW1lLCBhbmQgdGhlIGNvbHVtbnMgb24gd2hpY2ggeW91IHdpc2ggdG8gc29ydCwgZnJvbSBzbG93ZXN0IHRvIGZhc3Rlc3QgbW92aW5nLgoKYGBge3J9CiMgU29ydCBhbGwgcmVjb3JkcyBpbiBvcmRlciBvZiBhcmVhIGNvbnN1bWVkIChjb2x1bW4gRmlyZUFyZWFIYSkKc29ydF9ieV9hcmVhX2RmIDwtIGFycmFuZ2UoZmlyZXNfZGYsIEZpcmVBcmVhSGEpCgoKIyBUbyBzb3J0IGluIGRlc2NlbmRpbmcgb3JkZXIsIGFwcGx5IGZ1bmN0aW9uIGRlc2MgdG8gdGhlIGNvbHVtbgpzb3J0X2J5X2FyZWFfZGYgPC0gYXJyYW5nZShmaXJlc19kZiwgZGVzYyhGaXJlQXJlYUhhKSkKCgojIFNvcnRpbmcgb24gbXVsdGlwbGUgY29sdW1ucwpzb3J0X2J5X21vbnRoX2FyZWFfZGYgPC0gYXJyYW5nZShmaXJlc19kZiwgTW9udGgsIGRlc2MoRmlyZUFyZWFIYSkpCmBgYAoKWW91IHdpbGwgbm90ZSB0aGF0IHRoaXMgbGFzdCByZXN1bHQgaXMgc29ydGVkIGJ5IG1vbnRoICphbHBoYWJldGljYWxseSouIFRoaXMgbWFrZXMgc2Vuc2UgdG8gUiwgYnV0IHdlIHByb2JhYmx5IHdvdWxkIHByZWZlciB0byBoYXZlIGl0IHNvcnRlZCAqbG9naWNhbGx5Ki4gVG8gZW5zdXJlIHRoaXMsIHdlIGNhbiBjYXN0IGNvbHVtbiBNb250aCBmcm9tIHR5cGUgImNociIgKGp1c3Qgc3RyaW5ncykgdG8gdHlwZSAiT3JkZXJlZCBGYWN0b3IiLCBhbiBvcmRlcmVkIGNhdGVnb3JpY2FsIHZhcmlhYmxlLiBUaGUgY29kZSBmb3IgdGhpcyBvcGVyYXRpb24gaXMgc2hvd24gYmVsb3cuIFdlIHdpbGwgZGlzY3VzcyB0aGUgbWFuYWdlbWVudCBvZiBjYXRlZ29yaWNhbCB2cy4gbnVtZXJpY2FsIHZhcmlhYmxlcyBpbiBtb3JlIGRlcHRoIGluIHRoZSBTdW1tYXJpc2luZyBNb2R1bGUsIGxhdGVyIGluIHRoZSBzZW1lc3Rlci4KCmBgYCB7cn0KIyBEZWZpbmUgdGhlIGxvZ2ljYWwgb3JkZXIgb2Ygb3VyIG1vbnRoIGNvZGVzCm1vbnRoc19pbl9vcmRlciA9IGMoImphbiIsICJmZWIiLCAibWFyIiwgImFwciIsICJtYXkiLCAianVuIiwgImp1bCIsICJhdWciLCAic2VwIiwKICAgICAgICAgICAgICAgICAgICAib2N0IiwgIm5vdiIsICJkZWMiKQoKIyBNb2RpZnkgdGhlIE1vbnRoIGNvbHVtbiBzbyBpdCB1c2VzIHRoYXQgb3JkZXJpbmcgCmZpcmVzX2RmJE1vbnRoIDwtIG9yZGVyZWQoZmlyZXNfZGYkTW9udGgsIGxldmVscyA9IG1vbnRoc19pbl9vcmRlcikKCiMgUmVwZWF0IHRoZSBzb3J0IG9wZXJhdGlvbiB0byBjb25maXJtCnNvcnRfYnlfbW9udGhfYXJlYV9kZiA8LSBhcnJhbmdlKGZpcmVzX2RmLCBNb250aCwgZGVzYyhGaXJlQXJlYUhhKSkKCiMgQ2hlY2sKaGVhZChzb3J0X2J5X21vbnRoX2FyZWFfZGYpCmBgYAoKCiMjIFN1bW1hcmlzaW5nIGJ5IGdyb3VwCgpXZSB0eXBpY2FsbHkgZXh0cmFjdCBzdWJzZXRzIGZyb20gYSBkYXRhIGZyYW1lIHRvIHNlcnZlIGFzIGlucHV0IHRvIG1ldGhvZHMgdGhhdCBzdW1tYXJpc2UsIHBlcmZvcm0gc3RhdGlzdGljYWwgYW5hbHlzZXMsIG9yIHByb2R1Y2UgZ3JhcGhzIG9mIHRob3NlIGRhdGEuIExpYnJhcnkgYGRwbHlyYCBwcm92aWRlcyBhIHBhaXIgb2YgbWV0aG9kcyAtLSBgZ3JvdXBfYnlgIGFuZCBgc3VtbWFyaXNlYCAtLSB3aGljaCwgd2hlbiB1c2VkIHRvZ2V0aGVyLCBtYWtlIHRoaXMgd29ya2Zsb3cgZXNwZWNpYWxseSBzdWNjaW5jdCBmb3Igc2ltcGxlIHBvc3Qtc2VsZWN0aW9uIHByb2Nlc3NpbmcuCgpBc3N1bWUgdGhhdCB5b3Ugd291bGQgbGlrZSB0byBrbm93IHRoZSBtZWFuIGZpcmUgYXJlYSBjb25zdW1lZCBmb3IgZWFjaCBtb250aC4gWW91IHdpbGwgZmlyc3QgYXBwbHkgYGdyb3VwX2J5YCB0byBgZmlyZXNfZGZgIHRvIGRlZmluZSB5b3VyIGdyb3VwaW5nIHZhcmlhYmxlIGFzIGNvbHVtbiBgTW9udGhgLiBUaGlzIGhhcyBubyBtYWpvciB2aXNpYmxlIGltcGFjdCBvbiBgZmlyZXNfZGZgLiBIb3dldmVyLCBhbnkgc3Vic2VxdWVudCBzdW1tYXJpZXMgeW91IHBlcmZvcm0gb24gdGhhdCBkYXRhIGZyYW1lIHdpdGggZnVuY3Rpb24gYHN1bW1hcmlzZWAgKiphcmUgYXBwbGllZCBieSBncm91cCoqLiBGb3IgZXhhbXBsZSwgaWYgeW91IHVzZSBgc3VtbWFyaXNlYCB0byBjb21wdXRlIHRoZSBtZWFuIG9mIEZpcmVBcmVhSGEgKHN5bnRheCBzaG93biBiZWxvdyksIGl0IGNvbXB1dGVzIHRoYXQgbWVhbiBmb3IgZWFjaCBtb250aCBzZXBhcmF0ZWx5LiBJZiB5b3UgdXNlIGBzdW1tYXJpc2VgIHRvIGNvbXB1dGUgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiBUZW1wZXJhdHVyZSwgaXQgY29tcHV0ZXMgdGhhdCBzdGFuZGFyZCBkZXZpYXRpb24gZm9yIGVhY2ggbW9udGggc2VwYXJhdGVseS4gQW5kIHNvIG9uLgoKYGBge3J9CiMgVG8gY29tcGFyZSBhcmVhIGNvbnN1bWVkIGJ5IG1vbnRoCgojIEFwcGx5IGdyb3VwX2J5LiBJbiBWaWV3IHRoZSBkYXRhIGZyYW1lIGxvb2tzIHVuY2hhbmdlZApmaXJlc19ncF9tb250aF9kZiA8LSBncm91cF9ieShmaXJlc19kZiwgTW9udGgpCgojIFdoZW4gcHJpbnRlZCB0byBjb25zb2xlLCB0aGUgZGF0YSBmcmFtZSBhbHNvIGxvb2tzIHRoZSBzYW1lIGV4Y2VwdCBmb3IgR3JvdXBzCiMgaGVhZGVyCmZpcmVzX2dwX21vbnRoX2RmCmBgYAoKClRoZSBtYWdpYyBoYXBwZW5zIHdoZW4gd2UgdGFrZSBhIGdyb3VwZWQgZGF0YSBmcmFtZSBhbmQgcGFzcyBpdCB0byBgc3VtbWFyaXNlYC4gRnVuY3Rpb24gYHN1bW1hcmlzZWAgcmV0dXJucyBhIG5ldyBkYXRhIGZyYW1lIHdpdGggYSByb3cgZm9yIGVhY2ggbGV2ZWwgb2YgdGhlIGdyb3VwaW5nIHZhcmlhYmxlLCBhbmQgYSBjb2x1bW4gZm9yIGVhY2ggc3VtbWFyeSBmdW5jdGlvbiB3ZSBzcGVjaWZ5LgoKYGBge3J9CiMgVCBzZWNvbmQgYXJnIHRvIHN1bW1hcmlzZSBpcyAiY29sIGhlYWRlciA9IGV4cHJlc3Npb24iLiBFeHByZXNzaW9uIGlzIGFwcGxpZWQgYnkgZ3JvdXAKCnN1bW1hcmlzZShmaXJlc19ncF9tb250aF9kZiwgTWVhbkFyZWFMbiA9IG1lYW4oRmlyZUFyZWFIYSwgbmEucm0gPSBUUlVFKSkKYGBgCgpOb3RlIHRoYXQgeW91IGNhbiBwcm92aWRlIG11bHRpcGxlIGV4cHJlc3Npb25zIHRvIGBzdW1tYXJpc2VgLiBJdCBwcm9kdWNlcyBhIGNvbHVtbiBmb3IgZWFjaC4gCgpZb3UgY2FuIGFsc28gcHJvdmlkZSBtdWx0aXBsZSBjb2x1bW4gbmFtZXMgdG8gYGdyb3VwX2J5YC4gRnVuY3Rpb24gYHN1bW1hcmlzZWAgaXMgdGhlbiBhcHBsaWVkIHRvIHRoZSBncm91cHMgZGVmaW5lZCBieSBlYWNoIGNvbWJpbmF0aW9uIG9mIHZhbHVlcyBvbiB0aGUgZ3JvdXBpbmcgdmFyaWFibGVzLiAKCmBgYHtyfQojIEdyb3VwaW5nIG9uIHR3byB2YXJpYWJsZXMKZmlyZXNfbW9udGhfZGF5IDwtIGdyb3VwX2J5KGZpcmVzX2RmLCBNb250aCwgRGF5KQpzdW1tYXJpc2UoZmlyZXNfbW9udGhfZGF5LCBNZWFuQXJlYUZvck1vbnRoQW5kRGF5T2ZXZWVrID0gbWVhbihGaXJlQXJlYUhhLCBuYS5ybSA9IFRSVUUpKQoKYGBgCgoKIyMjIEV4ZXJjaXNlCgoxLiBVc2UgJ2dyb3VwX2J5JyBhbmQgJ3N1bW1hcmlzZScgdG8gZmluZCB0aGUgbGFyZ2VzdCBmaXJlIChpLmUuIG1heGltdW0gYXJlYSBidXJudCkgaW4gZWFjaCBtb250aC4KMi4gQSB1c2VmdWwgd29ya2VyIGZ1bmN0aW9uIGluIGxpYnJhcnkgYGRwbHlyYCBpcyBgbigpYC4gVGhpcyBmdW5jdGlvbiwgd2hlbiB1c2VkIGluIGBzdW1tYXJpc2VgLCBjb3VudHMgdGhlIG51bWJlciBvZiByZWNvcmRzIGluIGVhY2ggZ3JvdXAgKGl0IHRha2VzIG5vIGNvbHVtbiBoZWFkZXI7IGl0IGp1c3QgY291bnRzIHRoZSBudW1iZXIgb2Ygcm93cyBpbiB0aGUgZ3JvdXApLiBHZW5lcmF0ZSBhIHRhYmxlIHRoYXQgc2hvd3MgdGhlIG51bWJlciBvZiBmaXJlcyB0aGF0IG9jY3VycmVkIG9uIGVhY2ggZGF5IG9mIHRoZSB3ZWVrLiBIb3cgd291bGQgeW91IGV4cGxhaW4gdGhlIHBhdHRlcm4gaW4gdGhlc2UgcmVzdWx0cz8KCgpgYGB7cn0KIyBFeGVyY2lzZSBTb2x1dGlvbgpmaXJlc19ncF9kYXlfZGYgPC0gZ3JvdXBfYnkoZmlyZXNfZGYsIERheSkKc3VtbWFyaXNlKGZpcmVzX2dwX2RheV9kZiwgTkZpcmVzID0gbigpKSAKYGBgCgozLiBNb2RpZnkgYGZpcmVzX2RmYCBzbyB0aGF0IGBzdW1tYXJpc2VgIG91dHB1dHMgdGhlIGRheXMgaW4gdGhlaXIgY29ycmVjdCBsb2dpY2FsIG9yZGVyIChlLmcuIFdlZG5lc2RheSBiZWZvcmUgVGh1cnNkYXkpLgoKXAoKIyMgUGlwZXMKCldoZW4geW91IGluc3RhbGwgZHBseXIgKGVpdGhlciBhbG9uZSBvciBhcyBwYXJ0IG9mIG1ldGEtcGFja2FnZSB0aWR5dmVyc2UpLCB5b3UgYWxzbyBnZXQgbGlicmFyeSBgbWFncml0dHJgLCB3aGljaCBjb250YWlucyBhIHNwZWNpYWwgb3BlcmF0b3IgY2FsbGVkICp0aGUgcGlwZSouIChOQjogVGhlIGNoYXJhY3RlciB8LCB1c2VkIGZvciBPUiwgaXMgYWxzbyBjYWxsZWQgdGhlIHBpcGUuIEp1c3Qgb25lIG9mIHRob3NlIHRoaW5ncy4pCgpXaXRoIHRoZSBwaXBlLCB3ZSBjYW4gcGVyZm9ybSBhIHNlcmllcyBvZiBvcGVyYXRpb25zLCBmb3IgZXhhbXBsZSBmaWx0ZXIgYW5kIHNlbGVjdCwgd2l0aG91dCBpbnRlcm1lZGlhdGUgdmFyaWFibGVzLiBXZSB0aGluayBvZiBzdGFydGluZyB3aXRoIG91ciBjb21wbGV0ZSBkYXRhIGZyYW1lIGFuZCBwdXNoaW5nIGl0IHRocm91Z2ggYSBzZXJpZXMsIG9yICoqcGlwZWxpbmUqKiBvZiBvcGVyYXRpb25zLiBBdCBlYWNoIHN0ZXAsIHRoZSBvdXRwdXQgZnJvbSBvbmUgb3BlcmF0aW9uIGlzIHBhc3NlZCBhbG9uZyBhcyB0aGUgaW5wdXQgb2YgdGhlIG5leHQuCgpXaGVuIHVzaW5nIHRoZSBwaXBlLCB3ZSBubyBsb25nZXIgaGF2ZSB0byBwcm92aWRlIHRoZSBuYW1lIG9mIGRhdGEgZnJhbWUgYXMgdGhlIGZpcnN0IGFyZ3VtZW50IHRvIGFsbCB0aGUgZHBseXIgZnVuY3Rpb25zIC0tIHRoZXkgYWx3YXlzIHRha2UgdGhlIG91dHB1dCBvZiB0aGUgcHJldmlvdXMgc3RlcCBpbiB0aGUgcGlwZS4KClByZXZpb3VzbHksIHdlIGNvbWJpbmVkIGZpbHRlciBhbmQgc2VsZWN0IGJ5IHVzaW5nIGFuIGludGVybWVkaWF0ZSB2YXJpYWJsZSwgbGlrZSB0aGlzOgoKYGBge3J9CiMgRmlsdGVyIHRvIGdldCB0aGUgcm93cyB3ZSB3YW50CnN1bW1lcl9maXJlc19kZiA8LSBmaWx0ZXIoZmlyZXNfZGYsIE1vbnRoICVpbiUgYygnanVuJywgJ2p1bCcsJ2F1ZycpKQoKIyBQYXNzIHRoZSByZXN1bHQgb2YgdGhlIGZpbHRlcmluZyBvcGVyYXRpb24gdG8gc2VsZWN0CnN1bW1lcl90ZW1wZXJhdHVyZV9hcmVhX2RmIDwtIHNlbGVjdChzdW1tZXJfZmlyZXNfZGYsIE1vbnRoLCBUZW1wZXJhdHVyZSwgRmlyZUFyZWFIYSkKYGBgCgpVc2luZyBwaXBlIHN5bnRheCwgdGhlIHNhbWUgcmVzdWx0IHdvdWxkIGJlIG9idGFpbmVkIHdpdGg6CgpgYGB7cn0Kc3VtbWVyX3RlbXBlcmF0dXJlX2FyZWFfZGYgPC0gZmlyZXNfZGYgJT4lIGZpbHRlcihNb250aCAlaW4lIGMoImp1biIsICJqdWwiLCAiYXVnIikpICU+JSBzZWxlY3QoTW9udGgsIFRlbXBlcmF0dXJlLCBGaXJlQXJlYUhhKQoKaGVhZChzdW1tZXJfdGVtcGVyYXR1cmVfYXJlYV9kZikKYGBgCgpMaWtlIHRoZSArIHN5bWJvbCBpbiBnZ3Bsb3QsIGAlPiVgIHNpZ25hbHMgdG8gUlN0dWRpbyB0aGF0IG1vcmUgY29kZSBpcyBjb21pbmcsIGFsbG93aW5nIHlvdSB0byBtYWtlIHRoZSBjb2RlIHJlYWRhYmxlIGJ5IHBsYWNpbmcgZWFjaCBvcGVyYXRpb24gaW4gdGhlIHBpcGVsaW5lIG9uIGEgbmV3IGxpbmU6CgpgYGB7cn0Kc3VtbWVyX3RlbXBlcmF0dXJlX2FyZWFfZGYgPC0gZmlyZXNfZGYgJT4lIAogIGZpbHRlcihNb250aCAlaW4lIGMoImp1biIsICJqdWwiLCAiYXVnIikpICU+JSAKICBzZWxlY3QoTW9udGgsIFRlbXBlcmF0dXJlLCBGaXJlQXJlYUhhKQoKaGVhZChzdW1tZXJfdGVtcGVyYXR1cmVfYXJlYV9kZikKYGBgCgojIyMgRXhlcmNpc2UKCjEuIFVzaW5nIGdyb3VwX2J5LCBzdW1tYXJpc2UsIGFuZCBwaXBlIG5vdGF0aW9uLCBjb21wdXRlIHRoZSBtZWFuIHRlbXBlcmF0dXJlIGZvciBlYWNoIG1vbnRoCgpgYGB7cn0KIyBFeGVyY2lzZSBzb2x1dGlvbgpmaXJlc19kZiAlPiUgZ3JvdXBfYnkoTW9udGgpICU+JSBzdW1tYXJpc2UoTWVhblRlbXBlcmF0dXJlID0gbWVhbihUZW1wZXJhdHVyZSwgbmEucm0gPSBUUlVFKSkKYGBgCgpcCgoyLiBZb3UgY2FuIHVzZSBnZ3Bsb3QgYXQgdGhlIGVuZCBvZiBhIHBpcGVsaW5lLiBXcml0ZSBhIHNpbmdsZSBjb21tYW5kIHRvIG1ha2UgYSBib3hwbG90IHRoYXQgaWxsdXN0cmF0ZXMgdGhlIGRpc3RyaWJ1dGlvbiBvZiBkcm91Z2h0IGxldmVsIGR1cmluZyBlYWNoIG9mIHRoZSBzdW1tZXIgbW9udGhzIGluIFBvcnR1Z2FsLiBQbGFuOiBGaXJzdCBmaWx0ZXIgb3V0IHRoZSBtb250aHMgeW91IHdhbnQsIHRoZW4gbWFrZSBhIGJveHBsb3Qgd2l0aCB4ID0gTW9udGggYW5kIHkgPSBEcm91Z2h0TGV2ZWwKCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCgpmaXJlc19kZiAlPiUgZmlsdGVyKE1vbnRoICVpbiUgYygianVuIiwgImp1bCIsICJhdWciKSkgJT4lCiAgZ2dwbG90KG1hcHBpbmcgPSBhZXMoeCA9IE1vbnRoLCB5ID0gRHJvdWdodExldmVsKSkgKyAKICBnZW9tX2JveHBsb3QoKQpgYGAKClwKCjMuIFdyaXRlIGEgc2luZ2xlIGNvbW1hbmQgdGhhdCBwcm9kdWNlcyBhIGJhciBncmFwaCBvZiB0aGUgbWVhbiB0ZW1wZXJhdHVyZSBmb3IgZWFjaCBtb250aC4gKFBsYW46IFRoZSBwaXBlbGluZSBzdGFydHMgd2l0aCBgZ3JvdXBfYnlgIGFuZCBgc3VtbWFyaXNlYCB0byBjb21wdXRlIHRoZSBtZWFucywgdGhlbiBwb3VycyB0aGF0IG91dHB1dCBpbnRvIGdncGxvdC4gTWFrZSB0aGUgZ3JhcGggdXNpbmcgYGdlb21fYmFyYC4gU2V0IHRoZSB4IGF4aXMgdG8gTW9udGggYW5kIHRoZSB5IGF4aXMgdG8gdGhlIGNvbHVtbiBuYW1lIHlvdSBhc3NpZ24gZm9yIHRoZSBtZWFuIHRlbXBlcmF0dXJlIGluIGBzdW1tYXJpc2VgLiBQYXNzIGludG8gZ2VvbV9iYXIgdGhlIGFyZ3VtZW50IGBzdGF0ID0gImlkZW50aXR5ImAgc28gaXQgcGxvdHMgdGhlIGRhdGEgdmFsdWVzIGFzIHByb3ZpZGVkLiBOb3RlIHRoZSBkb3VibGUgcXVvdGVzIGFyb3VuZCB0aGUgKmlkZW50aXR5KjsgdGhleSBhcmUgcmVxdWlyZWQuKQoKYGBge3J9CiMgRXhlcmNpc2Ugc29sdXRpb24KCmxpYnJhcnkoZ2dwbG90MikKCmZpcmVzX2RmICU+JSAKICBncm91cF9ieShNb250aCkgJT4lIAogIHN1bW1hcmlzZShNZWFuVGVtcGVyYXR1cmUgPSBtZWFuKFRlbXBlcmF0dXJlLCBuYS5ybSA9IFRSVUUpKSAlPiUKICBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4ID0gTW9udGgsIHkgPSBNZWFuVGVtcGVyYXR1cmUpKSArIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKQpgYGAKCgoKIyMgQSBXb3JkIG9mIENhdXRpb24KCkRwbHlyIHBpcGVsaW5lIHN5bnRheCBpcyBwb3B1bGFyIGJlY2F1c2UgaXQgZWxpbWluYXRlcyB0aGUgbmVlZCBmb3IgaW50ZXJtZWRpYXRlIHZhcmlhYmxlcyBhbmQsIHRoZXJlZm9yZSwgcmVxdWlyZXMgYSBsb3QgbGVzcyB0eXBpbmcuIEl0IGlzIGNvbW1vbiwgd2hlbiBmaXJzdCBlbmNvdW50ZXJpbmcgdGhpcyBvcHRpb24sIHRvIGdldCBzbGlnaHRseSBjYXJyaWVkIGF3YXksIGFuZCBjaGFpbiB0b2dldGhlciBkb3plbnMgb2Ygb3BlcmF0aW9ucywgcmV2ZWxpbmcgaW4gaG93IG1hbnkga2V5c3Ryb2tlcyB5b3UgYXJlIHNhdmluZy4gVGhpcyBpcyByaXNreSwgZm9yIHNldmVyYWwgcmVhc29uczoKCjEuIElmIGEgbG9uZyBwaXBlbGluZSBmYWlscywgeW91IHdpbGwgbm90IGtub3cgKmluIHdoaWNoIG9wZXJhdGlvbiB0aGUgZXJyb3Igb2NjdXJyZWQqLiBUaGlzIGNhbiBtYWtlIGl0IGV4dHJlbWVseSBkaWZmaWN1bHQgdG8gZGVidWcuIAoyLiBCZWNhdXNlIHlvdSBhcmUgbm90IHNhdmluZyBhbnkgb2YgdGhlIGludGVybWVkaWF0ZSBvdXRwdXRzLCB5b3UgZG8gbm90IGhhdmUgdGhlbSBhdmFpbGFibGUgZm9yIGRpZmZlcmVudCBwcm9jZXNzaW5nIGluIG90aGVyIGNvbnRleHRzIC0tIHlvdSB3aWxsIGhhdmUgdG8gcmVwZWF0IHRoZSB3aG9sZSBwb3J0aW9uIG9mIHRoZSBwaXBlbGluZSB3aGljaCBnZW5lcmF0ZWQgdGhlbS4gCjMuIEEgbG9uZyBwaXBlbGluZSB3aWxsIGJlIGRpZmZpY3VsdCBmb3Igb3RoZXIgcGVvcGxlIHRvICJyZWFkIiAoaS5lLiB0byBmaWd1cmUgb3V0IHdoYXQgaXQncyBkb2luZykuIFdoZW4geW91IGhhdmUgbXVsdGlwbGUgb3B0aW9ucyBmb3IgcGVyZm9ybWluZyBhIGNvbXB1dGF0aW9uLCB0aGUgIGdvYWwgaXMgdG8gc3RyaWtlIGEgYmFsYW5jZSBiZXR3ZWVuICoqcGFyc2ltb255KiogKG5vdCB0b28gbXVjaCB0eXBpbmcpIGFuZCAqKnJlYWRhYmlsaXR5KiogKHlvdXIgY29kZSBpcyBlYXN5ICpmb3Igb3RoZXIgcGVvcGxlKiB0byB1bmRlcnN0YW5kKS4gV2hlbiB3b3JraW5nIG9uIGdyb3VwIHByb2plY3RzLCBvciBpbiBhIHByb2Zlc3Npb25hbCBzb2Z0d2FyZSBkZXZlbG9wbWVudCBjb250ZXh0LCByZWFkYWJpbGl0eSBpcyBjb25zaWRlcmVkIHRoZSBtb3JlIGNyaXRpY2FsIG9mIHRoZSB0d28gZmVhdHVyZXMuIE15IHBlcnNvbmFsIHN0eWxlIGlzIG5ldmVyIHRvIGJ1aWxkIHBpcGVsaW5lcyBvZiBtb3JlIHRoYW4gdGhyZWUgb3IgZm91ciBvcGVyYXRpb25zLiBUaGUgb3V0cHV0cyBvZiB0aGVzZSBzaG9ydCBzZXF1ZW5jZXMgY2FuIGJlIHNhdmVkIGludG8gaW50ZXJtZWRpYXRlIHZhcmlhYmxlcyB3aGljaCBjYW4gYmUgY2hlY2tlZCBhbmQgcmV1c2VkLCB3aGljaCBhcmUgdGhlbiBwYXNzZWQgYWxvbmcgaW50byB0aGUgbmV4dCBwaXBlbGluZS4KXAoKIyMgQW5vdGhlciBXb3JkIG9mIENhdXRpb24KClIgdXNlcnMgYXJlIGNvbnN0YW50bHkgYWRkaW5nIG5ldyBsaWJyYXJpZXMgdG8gYmFzZSBSLCBtZWFuaW5nIHRoYXQgeW91IHdpbGwgcHJvYmFibHkgaGF2ZSBzZXZlcmFsIG9wdGlvbnMgZm9yIGRvaW5nIGFueSBqb2IgaW4gUi4gVGhlIHZhcmlvdXMgb3B0aW9ucyBzb21ldGltZXMgaGF2ZSBzdWJ0bGUgdGVjaG5pY2FsIGRpZmZlcmVuY2VzIHRoYXQgd2lsbCBnZW5lcmF0ZSBhIGxvdCBvZiBhcmd1bWVudCBiZXR3ZWVuIHByb2Zlc3Npb25hbCBwcm9ncmFtbWVycywgYnV0IGFyZSB1bmxpa2VseSB0byBtYXR0ZXIgbXVjaCB0byByZXNlYXJjaCBzY2llbnRpc3RzLiBJbiBnZW5lcmFsLCB5b3Ugc2hvdWxkIGV4cGxvcmUgdGhlIFIgZWNvc3lzdGVtIGZyZWVseSBhbmQgdXNlIHdoYXRldmVyIHlvdSBsaWtlLiAqKkhvd2V2ZXIqKiBvbiBhc3NpZ25tZW50cywgaXQgaXMgd2lzZSB0byBjaGVjayB3aXRoIHRoZSBsZWN0dXJlciBiZWZvcmUgdXNpbmcgc29tZXRoaW5nIHRoYXQgaXMgcmVhbGx5IGRpZmZlcmVudCBmcm9tIHdoYXQgaXMgcHJlc2VudGVkIGluIGNsYXNzLiBZb3VyIGxlY3R1cmVyIG1heSwgZm9yIGVkdWNhdGlvbmFsIHJlYXNvbnMsIHdhbnQgeW91IHRvIHVzZSBzcGVjaWZpYyBSIHRvb2xzLgoKIyMgV2hhdCdzIE5leHQKCllvdSBtYXkgcmVjYWxsIHRoYXQgd2F5IGJhY2sgaW4gdGhlIGZpcnN0IG1vZHVsZSBvZiBSNFNTUCB3ZSBzYWlkIHdlIHdlcmUgZ29pbmcgdG8gYW5hbHlzZSBkYXRhLiBXZSBoYXZlbid0IHJlYWxseSBkb25lIG11Y2ggb2YgdGhhdCB5ZXQuIFNvIGZhciB3ZSBoYXZlIGJlZW4gKmdldHRpbmcgcmVhZHkqIHRvIGFuYWx5c2UgZGF0YS4gSW4gdGhlIG5leHQgbW9kdWxlLCB3ZSB3aWxsIHN0YXJ0IHJlYWxseSBkaWdnaW5nIGludG8gb3VyIGRhdGEgd2l0aCBleHBsb3JhdG9yeSBhbmFseXNpcyBhbmQgZGVzY3JpcHRpdmUgc3RhdGlzdGljcy4gQmVjYXVzZSB0aGlzIGlzIG5vdCBhIHN0YXRpc3RpY3MgY291cnNlICpwZXIgc2UqIHdlIHdpbGwgb25seSBiZSB1c2luZyBjb21tb24gZ2VuZXJhbCBhbmFseXNlcyBpbiB0aGUgaGFuZG91dHMgYW5kIHJlYWRpbmdzLiBJZiwgZm9yIGEgcHJvamVjdCBvciBhc3NpZ25tZW50LCB5b3UgbmVlZCB0byBkbyBzb21ldGhpbmcgbW9yZSBlc290ZXJpYywganVzdCBsZXQgdXMga25vdyAtLSBzb21lb25lIGhhcyBwcm9iYWJseSB3cml0dGVuIGFuIFIgbGlicmFyeSBmb3IgaXQuCg==