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. 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.
- Confirm this by executing an appropriate R command.
- Modify the expression so that Ant is deleted from vector
some_words
- 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:
- Write an R command that selects from some_wordsall the
four-character words, but no others.
- Check to see if executing this command has changed the value of
some_words. Explain why or why not.
- Modify the command so that it does change
some_words, with that vector now holding only words with
exactly four characters.
- Explain what the command you just wrote illustrates about the order
in which assignment statements are evaluated.
 
Conditional Operators in R
| 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:
- Either the row or column index (or both) may specify a
range using the :operator. For example,1:3or6: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
- Either the row or column index may be omitted. That
is, we can say geography_df[3 , ]orgeography_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
- What do you think geography_df[ , ](i.e. where both
row and column information are omitted) will do?
- 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
- How would you generate data frame october_fires using [] in base
R?
- 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
- Use ‘group_by’ and ‘summarise’ to find the largest fire
(i.e. maximum area burnt) in each month.
- A useful worker function in library dplyrisn(). This function, when used insummarise,
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
- Modify fires_dfso thatsummariseoutputs
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
- 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
- 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()

- Write a single command that produces a bar graph of the mean
temperature for each month. (Plan: The pipeline starts with
group_byandsummariseto compute the means,
then pours that output into ggplot. Make the graph usinggeom_bar. Set the x axis to Month and the y axis to the
column name you assign for the mean temperature insummarise. Pass into geom_bar the argumentstat = "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:
- If a long pipeline fails, you will not know in which operation
the error occurred. This can make it extremely difficult to
debug.
- 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.
- 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.
 
LS0tCnRpdGxlOiAiU3Vic2V0dGluZyIKZGF0ZTogIlNlbWVzdGVyIDIsIDIwMjMiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRvY19kZXB0aDogMwogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93Ci0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkoa25pdHIpCgprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgY29tbWVudCA9ICIjPiIsCiAgZmlnLnBhdGggPSAiZmlndXJlcy8wMy8iLCAjIHVzZSBvbmx5IGZvciBzaW5nbGUgUm1kIGZpbGVzCiAgY29sbGFwc2UgPSBUUlVFLAogIGVjaG8gPSBUUlVFCikKYGBgCgoKCj4gIyMjIyBBc3NvY2lhdGVkIE1hdGVyaWFsCj4KPiBab29tIG5vdGVzOiBbWm9vbSBOb3RlcyAwMyAtIFNlbGVjdGluZyBhbmQgRmlsdGVyaW5nIERhdGFdKHpvb21fbm90ZXNfMDNfdmlzdWFsaXNlLmh0bWwpCj4KPiBSZWFkaW5nOgo+Cj4gLSBbUiBmb3IgRGF0YSBTY2llbmNlIC0gQ2hhcHRlciA1XShodHRwczovL3I0ZHMuaGFkLmNvLm56L3RyYW5zZm9ybS5odG1sKQoKXAoKIyMgSW50cm9kdWN0aW9uCgpXaGVuIHdvcmtpbmcgd2l0aCBhIGNvbXBsZXggZGF0YSBzZXQsIHJlc2VhcmNoZXJzIHJhcmVseSBzdW1tYXJpc2Ugb3IgYW5hbHlzZSBhbGwgdGhlIHZhbHVlcyBhcyBhIHNpbmdsZSB1bml0LiBNb3JlIGNvbW1vbmx5LCB3ZSBzZWxlY3Qgb3V0IHNwZWNpZmljIHN1YnNldHMgb2YgaW50ZXJlc3QsIGFuZCBhbmFseXNlIHRob3NlLiBXZSBzYXcgdGhpcyBwYXR0ZXJuIGluIHRoZSBWaXN1YWxpc2F0aW9uIE1vZHVsZSwgd2hlcmUgd2Ugd2FudGVkIHRvIGlzb2xhdGUgdGhlIGRhdGEgZm9yIGEgc2luZ2xlIGNvdW50cnkgKERlbm1hcmspIGZyb20gYSBkYXRhIGZyYW1lIHRoYXQgaGFkIHJlY29yZHMgZm9yIDE0MiBkaWZmZXJlbnQgY291bnRyaWVzLgoKUiBoYXMgYSByaWNoIGFuZCBwb3dlcmZ1bCBzeW50YXggZm9yIHNlbGVjdGluZyBzdWJzZXRzIGZyb20gYSBsYXJnZSBkYXRhIGZyYW1lLCBiYXNlZCBvbiBzcGVjaWZpYyBjb25kaXRpb25zIChmb3IgZXhhbXBsZSwgc2VsZWN0IG9ubHkgdGhvc2UgcmVjb3JkcyB3aGVyZSB0aGUgdmFsdWUgaW4gY29sdW1uIGBjb3VudHJ5YCBpcyAiRGVubWFyayIpLiBCZWNhdXNlIHRoaXMga2luZCBvZiBvcGVyYXRpb24gaXMgc28gZXNzZW50aWFsLCByZXNlYXJjaGVycyBoYXZlIGFsc28gZGV2ZWxvcGVkIGFkZGl0aW9uYWwgUiBwYWNrYWdlcyB0aGF0IHN1cHBsZW1lbnQgYW5kIGV4dGVuZCB0aGUgYmFzZSBSIGZhY2lsaXRpZXMuIE91ciBmYXZvdXJpdGUgYW1vbmcgdGhlc2UgaXMgYSBsaWJyYXJ5IGNhbGxlZCAqKmRwbHlyKiouICBMaWJyYXJ5IGBkcGx5cmAgaXMgd2lkZWx5IHVzZWQsIGFuZCB5b3Ugd2lsbCBzZWUgbWFueSBleGFtcGxlcyBvZiBpdCBpbiBSIGNvZGUgeW91IGZpbmQgaW4gdGhlIHdpbGQuCgpUaGUgZnVuY3Rpb25zIGluIGBkcGx5cmAgKGFuZCBpbiBhbGwgdGhlIG90aGVyIFIgbGlicmFyaWVzIHlvdSBpbnN0YWxsKSBhcmUgdGVjaG5pY2FsbHkgKip3cmFwcGVycyoqIGFyb3VuZCBiYXNlIFIgY29kZS4gVGhhdCBpcywgdGhleSBhcmUgdGhlbXNlbHZlcyB3cml0dGVuIHVzaW5nIGJhc2UgUiBjb21tYW5kcy4gVGh1cyBpdCBpcyBwb3NzaWJsZSB0byBwZXJmb3JtIGFsbCB0aGUgc2FtZSB0cmFuc2Zvcm1hdGlvbnMgYnkgdXNpbmcgYGRwbHlyYCwgb3IgYnkgdXNpbmcgb25seSBiYXNlIFIuIE1hbnkgcHJvZ3JhbW1lcnMgYW5kIHJlc2VhcmNoZXJzIChpbmNsdWRpbmcgc29tZSBvZiB5b3VyIGxlY3R1cmVycykgcHJlZmVyIHRvIHVzZSBiYXNlIFIgZm9yIHRoZXNlIG9wZXJhdGlvbnMuIFRoZXJlZm9yZSwgaW4gdGhpcyBtb2R1bGUsIHdlIHdpbGwgbG9vayBhdCBib3RoIGFwcHJvYWNoZXMuCgpQZW9wbGUgbWFrZSB0aGUgY2hvaWNlIGJldHdlZW4gYGRwbHlyYCBhbmQgYmFzZSBSIGZvciBzZXZlcmFsIHJlYXNvbnMuIE1hbnkgcGVvcGxlIGZpbmQgYGRwbHlyYCBzeW50YXggZWFzaWVyIHRvIHVzZSwgYmVjYXVzZSBpdCBpcyBtb3JlICoqdW5pZm9ybSoqLiBUaGF0IGlzLCBhbGwgdGhlIGBkcGx5cmAgdHJhbnNmb3JtYXRpb24gZnVuY3Rpb25zIHVzZSBhcHByb3hpbWF0ZWx5IHRoZSBzYW1lIHN5bnRheC4gSW4gYmFzZSBSLCB0aGVyZSBpcyBtb3JlIHZhcmlhdGlvbi4gU2NpZW50aXN0cyB3aG8gd29yayB3aXRoIHZlcnkgbGFyZ2UgZGF0YSBzZXRzIGFyZSBvZnRlbiBjb25jZXJuZWQgYWJvdXQgaG93IGZhc3QgdGhlaXIgY29kZSBjYW4gYmUgZXhlY3V0ZWQuIEluIHNvbWUgY2FzZXMsIGBkcGx5cmAgZXhlY3V0ZXMgbW9yZSBzbG93bHkgdGhhbiBiYXNlIFIgKGJlY2F1c2Ugb2YgdGhlIGV4dHJhIGNvZGUgcmVxdWlyZWQgZm9yIHRoZSB3cmFwcGluZyksIGxlYWRpbmcgdGhlc2UgcmVzZWFyY2hlcnMgdG8gcHJlZmVyIHRoZSBiYXNlIFIgYXBwcm9hY2guIEJlY2F1c2UgYGRwbHlyYCBpcyBhIHJlbGF0aXZlbHkgbmV3IGFkZGl0aW9uIHRvIFIsIHNvbWUgcGVvcGxlIHByZWZlciBiYXNlIFIgYmVjYXVzZSB0aGV5IGxlYXJuZWQgaXQgZmlyc3QsIGFuZCBhcmUgaGFwcHkgdG8gY29udGludWUgdXNpbmcgaXQuCgpVbmxlc3MgeW91IGFyZSByZXF1aXJlZCB0byB1c2UgYSBwYXJ0aWN1bGFyIGFwcHJvYWNoIChjaGVjayB3aXRoIHlvdXIgbGVjdHVyZXIgaWYgeW91IGFyZSB1bnN1cmUpLCB5b3UgY2FuIGNob29zZSB3aGljaGV2ZXIgc2V0IG9mIGNvbW1hbmRzIHlvdSBsaWtlIHVzaW5nLiBZb3UgY2FuIGV2ZW4gbWl4IGFuZCBtYXRjaCB0aGVtIC0tIHRoZXkgZ2l2ZSB0aGUgc2FtZSByZXN1bHRzLCBhbmQgUiBkb2Vzbid0IGNhcmUuIEhvd2V2ZXIsIGl0IGlzIHZlcnkgaW1wb3J0YW50IHRoYXQgeW91IGNhbiAqdW5kZXJzdGFuZCogYm90aCBzdHlsZXMuIE9uZSBvZiB0aGUgZ3JlYXQgYmVuZWZpdHMgb2YgdGhlIFIgZWNvc3lzdGVtIGlzIHRoZSB3aWRlIHNoYXJpbmcgb2YgY29kZSwgYW5kIHlvdSBjYW4ndCBmdWxseSBwYXJ0aWNpcGF0ZSBpbiB0aGlzIHVubGVzcyB5b3UgYXJlIGNvbWZvcnRhYmxlIHdpdGggYWxsIHRoZSBtYWpvciBkaWFsZWN0cy4KClwKCiMjIFN1YnNldHRpbmcKClRoZSBtb3N0IGRpcmVjdCB3YXkgdG8gc2VsZWN0IG91dCBhIHN1YnNldCBvZiBhIHZlY3RvciBvciBkYXRhIGZyYW1lIGlzIHVzaW5nIHRoZSAqKmV4dHJhY3Rpb24gb3BlcmF0b3IqKiBbXSwgd2hpY2ggaXMgcGFydCBvZiBiYXNlIFIuIFdpdGggdGhpcyBvcGVyYXRvciB3ZSBzcGVjaWZ5IHdoaWNoIGVsZW1lbnRzIHdlIHdhbnQgaW4gb25lIG9mIHRocmVlIHdheXM6CgotIEJ5IHBvc2l0aW9uIChlLmcuIHRoZSA4dGggYW5kIDl0aCBlbGVtZW50cyBpbiBhIHZlY3RvcikKLSBCeSBuYW1lIChlLmcuIGFsbCBvZiBjb2x1bW4gQ291bnRyeSkKLSBCeSBzb21lIGNvbmRpdGlvbiAoZS5nLiBhbGwgdmFsdWVzIGxlc3MgdGhhbiAxKQoKVGhlIHNxdWFyZSBicmFja2V0IHN5bnRheCB3b3JrcyBvbiBib3RoIG9uZSBhbmQgdHdvIGRpbWVuc2lvbmFsIGRhdGEgKGkuZS4gdmVjdG9ycyBvciBkYXRhIGZyYW1lcykgYW5kIHdlIHdpbGwgbG9vayBhdCBib3RoIGNhc2VzLCBzdGFydGluZyB3aXRoIHZlY3RvcnMuCgojIyMgU3Vic2V0dGluZyBieSBwb3NpdGlvbgoKRWFjaCBpdGVtIGluIGEgdmVjdG9yIGhhcyBhIHBvc2l0aW9uLCBzdGFydGluZyBmcm9tIDEuXltOQjogTW9zdCBwcm9ncmFtbWluZyBsYW5ndWFnZXMgc3RhcnQgZnJvbSAwLiBJZiB5b3UgYXJlIGFuIGV4cGVyaWVuY2VkIEphdmEsIEMsIGV0Yy4sIHByb2dyYW1tZXIsIGJlIGFsZXJ0IGZvciB0aGlzLl0gQ29sbG9xdWlhbGx5LCB0aGlzIGlzIGNhbGxlZCBpdHMgKippbmRleCoqLiBXZSBwYXNzIHRoZSBpbmRleCBhcyBhbiBhcmd1bWVudCB0byBgW11gIHRvIHNlbGVjdCB0aGUgc3BlY2lmaWMgaXRlbS4gCmBgYHtyfQojIEEgbnVtZXJpYyB2ZWN0b3IKc29tZV9udW1iZXJzIDwtIGMoMiwgNDUsIC05LCA2KQoKIyBQdWxsIG91dCB0aGUgc2Vjb25kIGl0ZW0Kc29tZV9udW1iZXJzWzJdCmBgYAoKVG8gc2VsZWN0IG11bHRpcGxlIGl0ZW1zLCBwYXNzIGEgdmVjdG9yIG9mIGluZGljZXMgaW50byBbXS4gVGhlIHJlc3VsdCBpcyBpdHNlbGYgYSB2ZWN0b3Igb2YgdGhlIGl0ZW1zIGF0IHRoZSBzcGVjaWZpZWQgcG9zaXRpb25zLiAKCgpgYGB7cn0KIyBBIHZlY3RvciBvZiBzdHJpbmdzCnNvbWVfd29yZHMgPC0gYygiQW50IiwgIkJlYXIiLCAiQ2F0IiwgIkRpbm8iKQoKIyBQdWxsIG91dCBpdGVtcyAxIGFuZCAzCnNvbWVfd29yZHNbYygxLDMpXQpgYGAKSXRlbXMgZG8gbm90IGhhdmUgdG8gYmUgc2VsZWN0ZWQgaW4gdGhlIHNhbWUgb3JkZXIgaW4gd2hpY2ggdGhleSBhcHBlYXIgaW4gdGhlIG9yaWdpbmFsIHZlY3Rvci4KCmBgYHtyfQojIFJldHVybiBpdGVtcyBpbiBkaWZmZXJlbnQgb3JkZXIKc29tZV93b3Jkc1tjKDQsIDIsIDEpXQpgYGAKSXRlbXMgY2FuIGJlIGR1cGxpY2F0ZWQgaW4gdGhlIHJlc3VsdCBieSB1c2luZyBhbiBpbmRleCBtdWx0aXBsZSB0aW1lcyBpbnNpZGUgW10uCgoKYGBge3J9CiMgRHVwbGljYXRlIGl0ZW1zCnNvbWVfd29yZHNbYygzLDEsNCwgNCwgNCwyKV0KYGBgCgpBbHRob3VnaCB2ZWN0b3IgaW5kaWNlcyBzdGFydCBmcm9tIDEsIFtdIHdpbGwgYWNjZXB0IG5lZ2F0aXZlIHZhbHVlcy4gQSBuZWdhdGl2ZSB2YWx1ZXMgKipleGNsdWRlcyoqIHRoZSBpdGVtIGF0IHRoYXQgcG9zaXRpb24uCgpgYGAge3J9CiMgUmVtb3ZlIHRoZSBmaXJzdCBpdGVtCnNvbWVfd29yZHNbLTFdCmBgYAoKIyMjIEV4ZXJjaXNlOgoKVGhlIGV4cHJlc3Npb24gc2hvd24gYWJvdmUgZG9lcyBub3QgcmVtb3ZlIGVsZW1lbnQgQW50IGZyb20gdmVjdG9yIGBzb21lX3dvcmRzYC4gCgoxLiBDb25maXJtIHRoaXMgYnkgZXhlY3V0aW5nIGFuIGFwcHJvcHJpYXRlIFIgY29tbWFuZC4KMi4gTW9kaWZ5IHRoZSBleHByZXNzaW9uIHNvIHRoYXQgQW50IGlzIGRlbGV0ZWQgZnJvbSB2ZWN0b3IgYHNvbWVfd29yZHNgCjMuIENvbnNpZGVyIHRoZSBwb3NzaWJsZSBkb3duc2lkZSBvZiB0aGUgY29tbWFuZCB5b3UganVzdCB3cm90ZS4KCiMjIyBTdWJzZXR0aW5nIGJ5IGNvbmRpdGlvbgoKQ29tbW9ubHksIHdlIHdpc2ggdG8gc2VsZWN0IGVsZW1lbnRzIGZyb20gYSB2ZWN0b3IgKG9yIGFzIHdlIHdpbGwgc2VlIGxhdGVyLCByb3dzIGZyb20gYSBkYXRhIGZyYW1lKSBiYXNlZCBvbiBzb21lIGNvbmRpdGlvbi4gRm9yIGV4YW1wbGUsIHdlIG1pZ2h0IHdhbnQgdG8gc2VsZWN0IGFsbCBpdGVtcyBncmVhdGVyIHRoYW4gc29tZSBtaW5pbXVtIHZhbHVlLCBvciBhbGwgaXRlbXMgbm90IGVxdWFsIHRvIHNvbWUgdmFsdWUgd2Ugd2lzaCB0byBleGNsdWRlLiBUaGUgW10gb3BlcmF0b3Igb2ZmZXJzIGEgc3ludGFjdGljIG9wdGlvbiB0aGF0IHdlIHVzZSBpbiB0aGVzZSBjYXNlcy4gUmF0aGVyIHRoYW4gcGFzc2luZyBpbiBzcGVjaWZpYyBpdGVtIGluZGljZXMsIHdlIGNhbiBwYXNzIGluIGEgdmVjdG9yIG9mIGJvb2xlYW5zIChpLmUuIFRSVUUgb3IgRkFMU0UpIGhhdmluZyB0aGUgc2FtZSBsZW5ndGggYXMgdGhlIHZlY3RvciBmcm9tIHdoaWNoIHdlIGFyZSBzZWxlY3RpbmcuIFRoZSBvcGVyYXRpb24gcmV0dXJucyBhbGwgZWxlbWVudHMgZm9yIHdoaWNoIHRoZSBjb3JyZXNwb25kaW5nIHZhbHVlIG9mIHRoZSBib29sZWFuIHZlY3RvciBpcyBUUlVFLiAKCkhlcmUgaXMgYSB0b3kgZXhhbXBsZSB0byBpbGx1c3RyYXRlIHRoZSBwYXR0ZXJuOgoKYGBge3J9CiMgQSB2ZWN0b3Igb2Ygc3RyaW5nCnNvbWVfd29yZHMgPC0gYygiQW50ZWxvcGUiLCAiQmVhciIsICJDYXQiLCAiRGlubyIsICJFYWdsZSIsICJGZXJyZXQiKQoKIyBQYXNzaW5nIGEgYm9vbGVhbiB2ZWN0b3IgdG8gW10Kc29tZV93b3Jkc1tjKFRSVUUsIEZBTFNFLCBGQUxTRSwgRkFMU0UsIFRSVUUsIFRSVUUpXQpgYGAKSW4gcHJhY3RpY2UsIHdlIGRvbid0IHJlYWxseSB0eXBlIG91dCBhbGwgdGhlIFRSVUUgYW5kIEZBTFNFIHZhbHVlcy4gV2UgbGV0IFIgZ2VuZXJhdGUgdGhlIGJvb2xlYW4gdmVjdG9yIGZvciB1cywgYnkgZGVmaW5pbmcgYSBjb25kaXRpb24uIEZvciBleGFtcGxlLCBpbWFnaW5lIHRoYXQgSSBhbSBpbnRlcmVzdGVkIHNwZWNpZmljYWxseSBpbiB3b3JkcyBoYXZpbmcgbW9yZSB0aGFuIDQgY2hhcmFjdGVycy4gSSBjYW4gdGVzdCB0aGlzIGNvbmRpdGlvbiBvbiBteSB2ZWN0b3Igb2Ygc3RyaW5nIGFzIGZvbGxvd3M6CgpgYGAge3J9CiMgR2VuZXJhdGluZyBhIGJvb29sZWFuIHZlY3RvcgpuY2hhcihzb21lX3dvcmRzKSA+IDQKYGBgCgpXZSBoYXZlIHNlZW4gYmVmb3JlIHRoYXQgUiBpcyBhICoqdmVjdG9yaXNlZCoqIGxhbmd1YWdlLCBzbyBhcHBseWluZyBhbnkgb3BlcmF0aW9uIG9yIGV4cHJlc3Npb24gdG8gYSB2ZWN0b3IgcmV0dXJucyB0aGUgcmVzdWx0IG9mIGFwcGx5aW5nIHRoZSBvcGVyYXRpb24gdG8gZWFjaCBlbGVtZW50IGluIHR1cm4uIFRoZSBzeW50YXggaW4gdGhlIHByZWNlZGluZyBjb21tYW5kIGlzIGNvbnNpc3RlbnQgd2l0aCBvdXIgZWFybGllciBleGFtcGxlcyBvZiB2ZWN0b3Jpc2VkIG9wZXJhdGlvbnMgLS0gaXQgY29tcHV0ZXMgdGhlIHJlc3VsdCBvZiBldmFsdWF0aW5nICJuY2hhciA+IDQiIGZvciBlYWNoIGVsZW1lbnQgb2YgYHNvbWVfd29yZHNgLCBidW5kbGVzIHRoZW0gYWxsIHVwIGludG8gYSB2ZWN0b3IsIGFuZCByZXR1cm5zIGl0LgoKTm90ZSB0aGF0IHRoZSBib29sZWFuIHZlY3RvciBwcm9kdWNlZCBpcyBleGFjdGx5IHRoZSBzYW1lIG9uZSBwYXNzZWQgdG8gW10gaW4gdGhlICJQYXNzaW5nIGEgYm9vbGVhbiB2ZWN0b3IiIGNvZGUgZXhhbXBsZSBlYXJsaWVyLiBUaGVyZWZvcmUsIHdlIGNhbiBzaW1wbHkgcmVwbGFjZSB0aGUgbWFudWFsbHkgdHlwZWQgb3V0IGJvb2xlYW4gdmVjdG9yIHdpdGggdGhlIGNvbmRpdGlvbmFsIGV4cHJlc3Npb24gdG8gYWNoaWV2ZSB0aGUgc2FtZSByZXN1bHQ6CgpgYGAge3J9CiMgVXNpbmcgYSBjb25kaXRpb25hbCBleHByZXNzaW9uIGluc2lkZSBbXQpzb21lX3dvcmRzW25jaGFyKHNvbWVfd29yZHMpID4gNF0KCmBgYApUaGlzIHN5bnRhY3RpYyBzdHJ1Y3R1cmUsIHdoZXJlIHlvdSBhcHBseSB0aGUgW10gb3BlcmF0b3IgdG8gYHNvbWVfd29yZHNgIGFuZCBhbHNvIHVzZSBgc29tZV93b3Jkc2AgaW4gdGhlIGFyZ3VtZW50IHlvdSBwYXNzIHRvIFtdIGlzIHZlcnkgaWRpb21hdGljIFIuIE1hbnkgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2VzIGRvIG5vdCBhbGxvdyBzdWNoIHRoaW5nczsgaWYgeW91IGhhdmUgcHJvZ3JhbW1lZCBhIGxvdCBpbiBtb3JlIHRyYWRpdGlvbmFsIGxhbmd1YWdlcywgaXQgd2lsbCB0YWtlIHlvdSBhIHdoaWxlIHRvIGdldCB1c2VkIHRvIHRoaXMuIEp1c3QgcmVtZW1iZXIgdGhhdCBSIGFsd2F5cyBldmFsdWF0ZXMgdGhlIGlucHV0IGFyZ3VtZW50IGZpcnN0IChpbiB0aGlzIGNhc2UsIGdlbmVyYXRpbmcgYSBib29sZWFuIHZlY3RvcikgYW5kIHRoZW4gcGFzc2VzIHRoZSByZXN1bHQgb2YgdGhhdCBldmFsdWF0aW9uIHRvIFtdLiBNYW55IHBlb3BsZSBmaW5kIGl0IGhlbHBzIHRvIHRoaW5rIHRocm91Z2ggdGhvc2UgdHdvIHN0ZXBzIHNlcGFyYXRlbHksIHdoZW4gdHJ5aW5nIHRvIGZpZ3VyZSBvdXQgd2hhdCBhIGNvbW1hbmQgbGlrZSB0aGlzIHByb2R1Y2VzLgoKCiMjIyBFeGVyY2lzZToKCjEuIFdyaXRlIGFuIFIgY29tbWFuZCB0aGF0IHNlbGVjdHMgZnJvbSBgc29tZV93b3Jkc2AgYWxsIHRoZSBmb3VyLWNoYXJhY3RlciB3b3JkcywgYnV0IG5vIG90aGVycy4KMi4gQ2hlY2sgdG8gc2VlIGlmIGV4ZWN1dGluZyB0aGlzIGNvbW1hbmQgaGFzIGNoYW5nZWQgdGhlIHZhbHVlIG9mIGBzb21lX3dvcmRzYC4gRXhwbGFpbiB3aHkgb3Igd2h5IG5vdC4KMy4gTW9kaWZ5IHRoZSBjb21tYW5kIHNvIHRoYXQgaXQgKipkb2VzKiogY2hhbmdlIGBzb21lX3dvcmRzYCwgd2l0aCB0aGF0IHZlY3RvciBub3cgaG9sZGluZyBvbmx5IHdvcmRzIHdpdGggZXhhY3RseSBmb3VyIGNoYXJhY3RlcnMuCjQuIEV4cGxhaW4gd2hhdCB0aGUgY29tbWFuZCB5b3UganVzdCB3cm90ZSBpbGx1c3RyYXRlcyBhYm91dCB0aGUgb3JkZXIgaW4gd2hpY2ggYXNzaWdubWVudCBzdGF0ZW1lbnRzIGFyZSBldmFsdWF0ZWQuCgoKXAoKIyMjIENvbmRpdGlvbmFsIE9wZXJhdG9ycyBpbiBSCgoKfCBPcGVyYXRpb24gICAgICAgICAgICAgICAgfCBSIFN5bWJvbCB8Cnw6LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18Oi0tLS0tLS0tLS06fAp8IExlc3MgdGhhbiAgICAgICAgICAgICAgICB8IFw8ICAgICAgIHwKfCBMZXNzIHRoYW4gb3IgZXF1YWwgdG8gICAgfCBcPD0gICAgICB8CnwgR3JlYXRlciB0aGFuICAgICAgICAgICAgIHwgXD4gICAgICAgfAp8IEdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byB8IFw+PSAgICAgIHwKfCBOb3QgZXF1YWwgdG8gICAgICAgICAgICAgfCAhPSAgICAgICB8CgoKIyMjIENvbmRpdGlvbmFsIFNlbGVjdGlvbiB3aXRoIGAlaW4lYAoKV2UgaGF2ZSB1c2VkIGA9PWAgdG8gdGVzdCBpZiBvbmUgdmFsdWUgaXMgZXhhY3RseSBlcXVhbCB0byBhbm90aGVyIHZhbHVlLiBPZnRlbiwgd2Ugd2lzaCB0byB0ZXN0IGlmIGEgdmFsdWUgaXMgZXF1YWwgdG8gb25lIG9mIGEgc2V0IG9mIHZhbHVlcyAoaS5lLiBpcyB2YWx1ZSBBIGVxdWFsIHRvIGVpdGhlciB2YWx1ZSBCIG9yIHZhbHVlIEMgb3IgdmFsdWUgRCkuIEluIFIsIHRoaXMgc3BlY2lmaWMgY29tcGxleCBjb25kaXRpb25hbCBsb2dpYyBjYW4gYmUgcGVyZm9ybWVkIHdpdGggdGhlIGAlaW4lYCBvcGVyYXRvcjoKCmBgYHtyfQojICVpbiUgd2l0aCBhIHNjYWxhcgoKIyBHaXZlbiBhIHZlY3Rvci4uLgpjbGVhbl92ZWhpY2xlcyA8LSBjKCJiaWN5Y2xlIiwgInNjb290ZXIiLCAic2thdGVib2FyZCIpCgojIFRlc3QgaWYgYSBzY2FsYXIgaXMgY29udGFpbmVkIGluIHRoZSB2ZWN0b3IKInNjb290ZXIiICVpbiUgY2xlYW5fdmVoaWNsZXMKCiJqZXQgc2tpIiAlaW4lIGNsZWFuX3ZlaGljbGVzCmBgYApJZiB3ZSB1c2UgYCVpbmAgd2l0aCBhIHZlY3RvciBhcyB0aGUgbGVmdCBvcGVyYW5kLCBSIHBlcmZvcm1zIGluIGEgdmVjdG9yaXNlZCB3YXksIGFzIGV4cGVjdGVkLCB0ZXN0aW5nIGVhY2ggZWxlbWVudCBpbiB0dXJuOgoKYGBge3J9CiMgVXNpbmcgJWluJSB3aXRoIGEgdmVjdG9yCm15X3ZlaGljbGVzIDwtIGMoInNrYXRlYm9hcmQiLCAidHJhY3RvciIsICJjYXIiLCAic2Nvb3RlciIpCgpteV92ZWhpY2xlcyAlaW4lIGNsZWFuX3ZlaGljbGVzCgpgYGAKCkFuZCB0aGUgcmVzdWx0aW5nIGJvb2xlYW4gdmVjdG9yIGNhbiwgb2YgY291cnNlLCBiZSBwYXNzZWQgdG8gW106CgpgYGAge3J9CiMgU2VsZWN0IG91dCBteSBjbGVhbiB2ZWhpY2xlcwpteV92ZWhpY2xlc1tteV92ZWhpY2xlcyAlaW4lIGNsZWFuX3ZlaGljbGVzXQoKYGBgClwKCiMjIE1pc3NpbmcgZGF0YQoKT25lIGV4dHJlbWVseSBjb21tb24gc3Vic2V0dGluZyB0YXNrIGlzIGRlYWxpbmcgd2l0aCBtaXNzaW5nIGRhdGEuIE1pc3NpbmcgZGF0YSBhcmlzZXMgZnJlcXVlbnRseSBkdXJpbmcgcmVhbCByZXNlYXJjaC4gRm9yIGV4YW1wbGUsIGFuIGVjb2xvZ2lzdCBzdHVkeWluZyBwZW5ndWluIHBvcHVsYXRpb25zIG1heSBiZSBtZWFzdXJpbmcgdGhlIHdlaWdodCBvZiBlYWNoIHBlbmd1aW4gaW4gYSBsb2NhbCBjb2xvbnkuIElmIGEgcGFydGljdWxhciBwZW5ndWluIHJ1bnMgYXdheSBiZWZvcmUgaXQgY2FuIGJlIHdlaWdoZWQsIHRoYXQgcGVuZ3VpbidzIHdlaWdodCBpcyBtaXNzaW5nLiBJdCB3b3VsZCBiZSBhIG1pc3Rha2UgdG8gY29kZSB0aGUgcGVuZ3VpbidzIHdlaWdodCBhcyAwIC0tIHRoaXMgd291bGQgY29ycnVwdCBhbnkgbnVtZXJpY2FsIGFuYWx5c2lzIG9mIHdlaWdodC4gVGhlcmVmb3JlIFIgcHJvdmlkZXMgYSBzcGVjaWFsIGRhdGEgZW50aXR5IGZvciAnbWlzc2luZycgb3IgJ3VuZGVmaW5lZCcuIE1pc3NpbmcgZGF0YSBpbiBSIGlzIHJlcHJlc2VudGVkIGJ5IGBOQWAuIAoKVGhlIGNvbmRpdGlvbmFsIG9wZXJhdG9ycyB3ZSB1c2VkIGFib3ZlIGNhbm5vdCBiZSBhcHBsaWVkIHRvIE5BLiBBbnkgb3BlcmF0aW9uIGZvciB3aGljaCBvbmUgb3IgbW9yZSBvcGVyYW5kcyBpcyBOQSB3aWxsIHJldHVybiBOQSAoZXZlbiBgTkEgPT0gTkFgIHdpbGwgcmV0dXJuIGBOQWApLiBUbyB0ZXN0IGZvciBOQSwgdGhlcmVmb3JlLCBSIHByb3ZpZGVzIGZ1bmN0aW9uIGBpcy5uYWAgd2hpY2ggcmV0dXJucyBgVFJVRWAgaXRzIGlucHV0IGlzIGBOQWAgYW5kIGBGQUxTRWAgaW4gYWxsIG90aGVyIGluc3RhbmNlcy4KCmBgYHtyfQojIFBlbmd1aW4gIzMgZ290IGF3YXkuLi4uCnBlbmd1aW5fd2VpZ2h0c19nIDwtIGMoMzQ3NSwgMjk3NSwgTkEsIDM0MjApCgojIFVzZSBpcy5uYSB0byBnZW5lcmF0ZSBhIGJvb2xlYW4gdmVjdG9yCmlzLm5hKHBlbmd1aW5fd2VpZ2h0c19nKQoKIyBVc2UgdGhlIGJvb2xlYW4gdmVjdG9yIHRvIHNlbGVjdCBldmVyeW9uZSAKIyB3aG8gaXMgbm90IE5BLiBOb3RlIHRoZSB1c2Ugb2YgIQpwZW5ndWluX3dlaWdodHNfZ1shaXMubmEocGVuZ3Vpbl93ZWlnaHRzX2cpXQoKYGBgCgpcCgojIyBTdWJzZXR0aW5nIGluIHR3byBkaW1lbnNpb25zCgpUaGUgW10gb3BlcmF0b3IgaXMgYWxzbyB1c2VkIGZvciBzZWxlY3Rpbmcgc3Vic2V0cyBmcm9tIGRhdGEgZnJhbWVzLiBJbiB0aGlzIHVzYWdlLCBvbmUgc3VwcGxpZXMgdHdvIGFyZ3VtZW50cyB0byBbXSwgc2VwYXJhdGVkIGJ5IGNvbW1hcy4gVGhlIGZpcnN0IGFyZ3VtZW50IHNwZWNpZmllcyB3aGljaCByb3cocykgdG8gc2VsZWN0IGFuZCB0aGUgc2Vjb25kIHNwZWNpZmllcyB3aGljaCBjb2x1bW4ocykuIFRoZSBnZW5lcmFsIHN5bnRheCBpczogKm5hbWVfb2ZfZGF0YV9mcmFtZVtyb3dfaW5mb3JtYXRpb24sIGNvbHVtbl9pbmZvcm1hdGlvbl0qLiBUaGVyZSBhcmUsIGhvd2V2ZXIsIG1hbnkgY29tcGxleCBvcHRpb25zIGZvciB0aGUgZm9ybWF0IG9mIHRoZSByb3cgYW5kIGNvbHVtbiBpbmZvcm1hdGlvbi4gV2Ugd2lsbCBjb3ZlciB0aGUgbW9zdCB1c2VmdWwgaGVyZS4KCmBgYHtyfQojIENyZWF0ZSBhIGRhdGEgZnJhbWUgdG8gcHJhY3RpY2UgdHdvLWRpbWVuc2lvbmFsIHNlbGVjdGlvbgpjb3VudHJpZXMgPC0gYygiQXVzdHJpYSIsICJCcmF6aWwiLCAiQ2FuYWRhIiwgIkRlbm1hcmsiKQpjYXBpdGFscyA8LSBjKCJWaWVubmEiLCAiQnJhc2lsaWEiLCAiT3R0YXdhIiwgIkNvcGVuaGFnZW4iKQpwb3B1bGF0aW9uX2luX21pbGxpb25zIDwtIGMoOSwgMjExLCAzOCwgNikKCmdlb2dyYXBoeV9kZiA8LSBkYXRhLmZyYW1lKENvdW50cnkgPSBjb3VudHJpZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIENhcGl0YWwgPSBjYXBpdGFscywKICAgICAgICAgICAgICAgICAgICAgICAgICAgUG9wdWxhdGlvbk1pbGxpb25zID0gcG9wdWxhdGlvbl9pbl9taWxsaW9ucykKCmdlb2dyYXBoeV9kZgoKYGBgCgoKSW4gdGhlIHNpbXBsZXN0IGNhc2UsIHdlIHdpc2ggdG8gc2VsZWN0IGEgc2luZ2xlIHZhbHVlIGZyb20gYSBkYXRhIGZyYW1lLCBzbyB3ZSBwcm92aWRlIHRoZSByb3cgaW5kZXggYW5kIGNvbHVtbiBpbmRleCBvZiB0aGUgY2VsbCBvZiBpbnRlcmVzdC4gRm9yIGV4YW1wbGUsIGltYWdpbmUgd2Ugd2FudCB0aGUgcG9wdWxhdGlvbiBvZiBWaWVubmEuIFdlIGtub3cgdGhhdCBWaWVubmEgaXMgaW4gcm93IDEgYW5kIHRoZSBwb3B1bGF0aW9uIGlzIGluIGNvbHVtbiAzLiBUbyBzZWxlY3QgdGhhdCBjZWxsIHdlIHByb3ZpZGUgMSBmb3IgdGhlIHJvdyBpbmZvcm1hdGlvbiBhbmQgMyBmb3IgdGhlIGNvbHVtbiBpbmZvcm1hdGlvbiBpbiB0aGUgc3F1YXJlIGJyYWNrZXRzOgoKYGBge3Igc2luZ2xlIHNlbGVjdGlvbn0KZ2VvZ3JhcGh5X2RmWzEsM10KYGBgCgpEb24ndCB3b3JyeSBhYm91dCBob3cgeW91IHdvdWxkIGtub3cgdGhlIHNwZWNpZmljIHJvdyBhbmQgY29sdW1uIG9mIHRoZSBjZWxsIHlvdSBhcmUgaW50ZXJlc3RlZCBpbi4gVGhpcyBwYXJ0aWN1bGFyIHNlbGVjdGlvbiBvcGVyYXRpb24gaXMgdHlwaWNhbGx5IHVzZWQgaW4gc2l0dWF0aW9ucyB3aGVyZSB5b3VyIGNvZGUgaXMgY29tcHV0aW5nIHRob3NlIHZhbHVlcyBiYXNlZCBvbiBjb21wbGV4IGNyaXRlcmlhLiBUaGlzIGV4YW1wbGUgaXMgbWVyZWx5IGlsbHVzdHJhdGl2ZS4KClRoZXJlIGFyZSB0d28gdmVyeSB1c2VmdWwgZXh0ZW5zaW9ucyB0byB0aGlzIHBhdHRlcm46CgoxLiAgRWl0aGVyIHRoZSByb3cgb3IgY29sdW1uIGluZGV4IChvciBib3RoKSBtYXkgc3BlY2lmeSBhICoqcmFuZ2UqKiB1c2luZyB0aGUgYDpgIG9wZXJhdG9yLiBGb3IgZXhhbXBsZSwgYDE6M2Agb3IgYDY6MTJgICh0aGVzZSBhcmUgIjEgdG8gMyIgYW5kICI2IHRvIDEyIiByZXNwZWN0aXZlbHkpLgoKYGBge3IgcmFuZ2V9CiMgRm9yIHJvd3MgMiB0byA0IChCcmF6aWwsIENhbmFkYSwgRGVubWFyayksIHNlbGVjdCB0aGUgcG9wdWxhdGlvbiAoY29sdW1uIDMpCmdlb2dyYXBoeV9kZlsyOjQsIDNdCgojIEZvciBDYW5hZGEgKHJvdyAzKSwgc2VsZWN0IGJvdGggdGhlIGNhcGl0YWwgbmFtZSBhbmQgcG9wdWxhdGlvbiAoY29scyAyIGFuZCAzKQpnZW9ncmFwaHlfZGZbMywgMjozXQoKYGBgCgoyLiAgRWl0aGVyIHRoZSByb3cgb3IgY29sdW1uIGluZGV4ICoqbWF5IGJlIG9taXR0ZWQqKi4gVGhhdCBpcywgd2UgY2FuIHNheSBgZ2VvZ3JhcGh5X2RmWzMgLCBdYCBvciBgZ2VvZ3JhcGh5X2RmWyAsIDJdYC4gVGhlIG1pc3NpbmcgZWxlbWVudCBpcyBpbnRlcnByZXRlZCBhcyAqKmFsbCoqLiBPbWl0IHRoZSByb3cgbnVtYmVyIGFuZCB5b3Ugd2FudCAqKmFsbCByb3dzKiogaW4gdGhlIHN1cHBsaWVkIGNvbHVtbihzKS4gT21pdCB0aGUgY29sdW1uIG51bWJlciBhbmQgeW91IHdhbnQgKiphbGwgY29sdW1ucyoqIGluIHRoZSBzdXBwbGllZCByb3cocykuCgpgYGB7ciBvbWl0dGVkIGluZGV4fQojIEZvciBEZW5tYXJrIChyb3cgNCksIHNlbGVjdCBhbGwgdGhlIGNvbHVtbnMKZ2VvZ3JhcGh5X2RmWzQsIF0KCiMgRm9yIGFsbCByb3dzLCBzZWxlY3QgdGhlIGNhcGl0YWwgY2l0eSBuYW1lIChjb2x1bW4gMikKZ2VvZ3JhcGh5X2RmWyAsIDJdCgpgYGAKCllvdSBtYXkgaGF2ZSBiZWVuIHN1cnByaXNlZCBieSB0aGUgb3V0cHV0IGdlbmVyYXRlZCBieSB0aGF0IGxhc3QgZXhhbXBsZS4gQWx0aG91Z2ggeW91IGhhdmUgc2VsZWN0ZWQgYSBzaW5nbGUgY29sdW1uLCB0aGUgb3V0cHV0IGlzIHByaW50ZWQgaG9yaXpvbnRhbGx5LCBhcyB0aG91Z2ggaXQgd2VyZSBhIHJvdy4gVGhpcyBpcyBhIHBlY3VsaWFyaXR5IG9mIFIuIEFueSBjb2xsZWN0aW9uIHRoYXQgaGFzIGEgc2luZ2xlIGRpbWVuc2lvbiAoaS5lLiBkb2Vzbid0IGhhdmUgYm90aCBjb2x1bW5zIGFuZCByb3dzKSBpcyB0cmVhdGVkIGFzIGEgcGxhaW4gdmVjdG9yLiBBbmQgdmVjdG9ycyBhcmUgYWx3YXlzIHByaW50ZWQgaG9yaXpvbnRhbGx5LiBCeSBleHRlbnNpb24sIHNpbmNlIGEgc2VsZWN0ZWQgY29sdW1uIG9mIGEgZGF0YSBmcmFtZSBpcyBhIHZlY3RvciwgeW91IGNhbiBhcHBseSBldmVyeXRoaW5nIHlvdSBoYXZlIGxlYXJuZWQgYWJvdXQgdmVjdG9ycyB0byBzZWxlY3RlZCBkYXRhIGZyYW1lIGNvbHVtbnMsIHdoaWNoIGlzIGV4YWN0bHkgd2hhdCB3ZSB3YW50IHRvIGJlIGFibGUgdG8gZG8uCgpZb3UgY2FuIGNvbWJpbmUgcmFuZ2VzIGFuZCB0aGUgKm1pc3NpbmcgaW5kZXggPSBhbGwqIHRlY2huaXF1ZToKCmBgYHtyIHRvZ2V0aGVyfQojIEZvciB0aGUgZmlyc3QgdGhyZWUgcm93cywgc2VsZWN0IGFsbCB0aGUgY29sdW1ucwpnZW9ncmFwaHlfZGZbMTozICwgXQoKYGBgCgojIyMgRXhlcmNpc2UKCjEuIFdoYXQgZG8geW91IHRoaW5rIGBnZW9ncmFwaHlfZGZbICwgXWAgKGkuZS4gd2hlcmUgYm90aCByb3cgYW5kIGNvbHVtbiBpbmZvcm1hdGlvbiBhcmUgb21pdHRlZCkgd2lsbCBkbz8gCjIuIFRyeSBpdC4gV2VyZSB5b3UgcmlnaHQ/CgpcCgpJbnN0ZWFkIG9mIHVzaW5nIGNvbHVtbiBudW1iZXJzLCB5b3UgY2FuIHByb3ZpZGUgY29sdW1uIG5hbWVzIGFzIHRoZSBjb2x1bW4gaW5mb3JtYXRpb24gKGFuZCByb3cgbmFtZXMgYXMgdGhlIHJvdyBpbmZvcm1hdGlvbiBpZiB5b3VyIGRhdGEgZnJhbWUgaGFzIG5hbWVkIHJvd3MpLiBVc2UgdGhlIGNvbWJpbmUgZnVuY3Rpb24gYGMoKWAgdG8gcHJvdmlkZSBtdWx0aXBsZSBjb2x1bW4gbmFtZXMsIGFuZCBiZSBzdXJlIHRvIHN1cnJvdW5kIGVhY2ggY29sdW1uIG5hbWUgd2l0aCBxdW90ZXMsIGJlY2F1c2UgUiBjb25zaWRlcnMgdGhlbSB0byBiZSBzdHJpbmdzIGluIHRoaXMgc2l0dWF0aW9uLgoKYGBge3IgbmFtZWQgY29sdW1uc30KZ2VvZ3JhcGh5X2RmWzI6NCwgIkNhcGl0YWwiXQoKZ2VvZ3JhcGh5X2RmWzM6NCwgYygiQ291bnRyeSIsICJDYXBpdGFsIildCmBgYAoKXAoKIyMgRnVuY3Rpb24gYHN1YnNldGAKCkFuIGFsdGVybmF0aXZlIGZvciBzZWxlY3Rpbmcgcm93cyBhbmQgY29sdW1ucyBpcyBmdW5jdGlvbiBgc3Vic2V0YCwgd2l0aCBzdHJ1Y3R1cmU6Cgpgc3Vic2V0KHggPSBkYXRhZnJhbWUsIHN1YnNldCA9IGNvbmRpdGlvbmFsX3N0YXRlbWVudF90b19hcHBseV90b19yb3dzLCBzZWxlY3QgPSBjb2x1bW5zX3RvX2tlZXApYAoKCmBgYHtyfQpjb3VudHJpZXNfb3Zlcl8zMG1pbGxpb24gPC0gc3Vic2V0KGdlb2dyYXBoeV9kZiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3Vic2V0ID0gUG9wdWxhdGlvbk1pbGxpb25zID4gMzAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCA9IGMoIkNvdW50cnkiLCAiUG9wdWxhdGlvbk1pbGxpb25zIikgKQpjb3VudHJpZXNfb3Zlcl8zMG1pbGxpb24KYGBgCgpPbWl0dGluZyB2YWx1ZXMgZm9yIHRoZSBgc3Vic2V0YCBhcmd1bWVudCBvciBgc2VsZWN0YCBhcmd1bWVudCB3aWxsIGV4dHJhY3QgYWxsIHJvd3Mgb3IgY29sdW1ucywgcmVzcGVjdGl2ZWx5LgoKXAoKIyMgU2VsZWN0aW5nIGNvbHVtbnMKCkRhdGEgZnJhbWVzIGFyZSBjb21tb25seSBvcmdhbmlzZWQgd2l0aCBhIGNvbHVtbiBmb3IgZWFjaCBkYXRhIHZhcmlhYmxlIGFuZCBhIHJvdyBmb3IgZWFjaCBpbnN0YW5jZS4gVG8gYW5hbHlzZSBhIHBhcnRpY3VsYXIgZGF0YSB2YXJpYWJsZSwgd2Ugd2lzaCB0byBzZWxlY3QgYWxsIHJvd3MgaW4gYSBjb2x1bW4uIFRoaXMgcGFydGljdWxhciBzdWJzZXR0aW5nIG9wZXJhdGlvbiBpcyBzbyBjb21tb24gdGhhdCB0aGVyZSBhcmUgYWRkaXRpb25hbCwgZWZmaWNpZW50IHdheXMgdG8gcGVyZm9ybSBpdCBpbiBSLgoKVG8gc2VsZWN0IGEgc2luZ2xlIGNvbHVtbiBmcm9tIGEgZGF0YSBmcmFtZSwgdXNlIHRoZSBgJGAgb3BlcmF0b3IsIGZvbGxvd2VkIGJ5IHRoZSBjb2x1bW4gbmFtZSAoZG91YmxlIHF1b3RlcyBhcmUgbm90IHVzZWQgaW4gdGhpcyBjb250ZXh0KS4KCmBgYHtyfQpnZW9ncmFwaHlfZGYkQ291bnRyeQpgYGAKClRoaXMgb3BlcmF0aW9uIGlzIGNvbW1vbmx5IHVzZWQgd2hlbiBwZXJmb3JtaW5nIHN1bW1hcnkgb3BlcmF0aW9ucyBvbiBlbnRpcmUgY29sdW1uczoKCmBgYHtyfQojIE1lYW4gb2YgYSB0aGUgUG9wdWxhdGlvbk1pbGxpb25zIGNvbHVtbgptZWFuKGdlb2dyYXBoeV9kZiRQb3B1bGF0aW9uTWlsbGlvbnMpCmBgYAoKClRoZSBgJGAgb3BlcmF0b3IgY2FuIGFsc28gYmUgdXNlZCAqdG8gY3JlYXRlIG5ldyBjb2x1bW5zKi4gU2ltcGx5IGdpdmUgYSBuYW1lIHRvIHRoZSBuZXcgY29sdW1uIG9uIHRoZSBsZWZ0IGhhbmQgb2YgYW4gYXNzaWdubWVudCBzdGF0ZW1lbnQsIGFuZCB0aGUgY29udGVudHMgb2YgdGhlIG5ldyBjb2x1bW4gb24gdGhlIHJpZ2h0IGhhbmQgc2lkZS4gKE5COiBUaGlzIHR5cGUgb2Ygb3BlcmF0aW9uIGlzIG5vdCBhbGxvd2VkIGluIG1vcmUgdHJhZGl0aW9uYWwgbGFuZ3VhZ2VzLCBidXQgaXMgdmVyeSBjb21tb24gaW4gUi4pCgpgYGB7cn0KIyBDcmVhdGUgYSBuZXcgY29sdW1uIGVuIHBhc3NhbnQKZ2VvZ3JhcGh5X2RmJFBvcHVsYXRpb25UaG91c2FuZHMgPC0gZ2VvZ3JhcGh5X2RmJFBvcHVsYXRpb25NaWxsaW9ucyAqIDEwMDAKCiMgQ2hlY2sgdGhhdCB0aGUgY29sdW1uIGhhcyBiZWVuIGNyZWF0ZWQKc3RyKGdlb2dyYXBoeV9kZikKCiMgUHJpbnQgdGhlIGNvbnRlbnRzIG9mIHRoZSBuZXcgY29sdW1uCmdlb2dyYXBoeV9kZiRQb3B1bGF0aW9uVGhvdXNhbmRzCmBgYAoKXAoKIyMgU3Vic2V0dGluZyB3aXRoIGBkcGx5cmAKCldlIHdpbGwgbm93IHN3aXRjaCB0byBhIGxhcmdlciBkYXRhIHNldCwgYW5kIHNlZSBob3cgdGhlIHR5cGVzIG9mIHNlbGVjdGlvbiBvcGVyYXRpb25zIGRlc2NyaWJlZCBhYm92ZSBhcmUgcGVyZm9ybWVkIHdpdGggdGhlIGBkcGx5cmAgbGlicmFyeS4gVGhlcmUgYXJlIGZpdmUgbWFpbiBmdW5jdGlvbnMgaW4gYGRwbHlyYDogZmlsdGVyLCBzZWxlY3QsIG11dGF0ZSAobm90IGNvdmVyZWQgaW4gdGhpcyBzZXNzaW9uKSwgZ3JvdXBfYnksIGFuZCBzdW1tYXJpc2UuIFdlIHdpbGwgc2VlIGhvdyB0aGV5IGNhbiBiZSB1c2VkIHRvIHBlcmZvcm0gZnVuZGFtZW50YWwgcHJvY2Vzc2luZyBvZiBzZWxlY3RlZCBwb3J0aW9ucyBvZiBkYXRhIHNldHMuCgpUbyB1c2UgYGRwbHlyYCwgeW91IG11c3QgZmlyc3QgaW5zdGFsbCBpdCBvbiB5b3VyIG1hY2hpbmUgd2l0aCBgaW5zdGFsbC5wYWNrYWdlc2AuIEFsdGVybmF0aXZlbHksIGlmIHlvdSBoYXZlIGluc3RhbGxlZCBwYWNrYWdlIGB0aWR5dmVyc2VgLCBgZHBseXJgIHdpbGwgaGF2ZSBiZWVuIGluc3RhbGxlZCBhcyBwYXJ0IG9mIHRoYXQgb3BlcmF0aW9uLiBUbyBsb2FkIGBkcGx5cmAgZm9yIHVzZSBkdXJpbmcgYW4gUlN0dWRpbyBzZXNzaW9uLCB1c2UgdGhlIGBsaWJyYXJ5YCBjb21tYW5kLCBhcyB3ZSBoYXZlIGRvbmUgcHJldmlvdXNseS4KCkZvciB0aGlzIHNlY3Rpb24sIHdlIHdpbGwgdXNlIGRhdGEgYWJvdXQgZm9yZXN0IGZpcmVzIGluIFBvcnR1Z2FsIGluIDIwMjIuIFBvcnR1Z2FsIGhhcyBhIGhpZ2ggaW5jaWRlbmNlIG9mIGZvcmVzdCBmaXJlLCBhbmQgdGhlc2UgZGF0YSBjYW4gcmV2ZWFsIHBhdHRlcm5zIGFib3V0IG9jY3VycmVuY2UgYW5kIHNldmVyaXR5LgoKWW91IGNhbiBkb3dubG9hZCB0aGUgZGF0YSBmaWxlICpmb3Jlc3RfZmlyZXNfcG9ydHVnYWwuY3N2KiBmcm9tIHRoaXMgbGluazoKCmh0dHBzOi8vZHJpdmUuZ29vZ2xlLmNvbS9kcml2ZS9mb2xkZXJzLzFVQnAtUDR3RkFhUUwzZWdJUTdkR2EyUlFlNlJRS3FneSBvciB1c2luZzoKCj4KPmBgYHtyLCBldmFsPUZBTFNFfQo+IGRvd25sb2FkLmZpbGUodXJsID0gImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9ydGlzLXRyYWluaW5nLzIwMjMtczItcjRzc3AvbWFpbi9kYXRhL2ZvcmVzdF9maXJlc19wb3J0dWdhbC5jc3YiLCAKPiAgICAgICAgICAgICAgZGVzdGZpbGUgPSAiZGF0YS9mb3Jlc3RfZmlyZXNfcG9ydHVnYWwuY3N2IikKPmBgYAo+IF9SZW1lbWJlciB0aGF0IFIgaXMgY2FzZSBzZW5zaXRpdmUgc28gaWYgeW91IGRvbid0IGhhdmUgYSBkaXJlY3RvcnkgZXhhY3RseSBjYWxsZWQgYGRhdGEvYCBtb2RpZnkgdGhlIGNvbW1hbmQgdG8gbWF0Y2ggeW91ciBkaXJlY3RvcnkuXwoKVGhlIGZpbGUgY29udGFpbnMgb25lIHJvdyBmb3IgZWFjaCByZWNvcmRlZCBmb3Jlc3QgZmlyZSBpbiBQb3J0dWdhbCBpbiAyMDIyLiBFYWNoIHJlY29yZCBoYXMgYSBudW1iZXIgb2YgbWVhc3VyZXMgKGNvbHVtbnMpIGluY2x1ZGluZyByZWdpb24gKHggYW5kIHkgdmFsdWVzIG9uIGEgZ3JpZCksIG1vbnRoLCBkYXksIGdyb3VuZCBjb25kaXRpb24gbWVhc3VyZXMsIG1ldGVvcm9sb2dpY2FsIG1lYXN1cmVzLCBhbmQgdGhlIGV4dGVudCBvZiB0aGUgZmlyZSBpbiBoZWFjdGFyZXMuIE5vdGUgdGhhdCBhbnkgZmlyZSB0aGF0IGNvbnN1bWVkIGxlc3MgdGhhbiBvbmUgaGVjdGFyZSBoYXMgYSB2YWx1ZSBvZiAwIGluIHRoaXMgbGFzdCBjb2x1bW4uCgpJbiB0aGUgY29kZSB0aGF0IGZvbGxvd3MsIHdlIHdpbGwgYXNzdW1lIHRoYXQgeW91IGFyZSB3b3JraW5nIGluIGEgcHJvamVjdCwgdGhhdCB0aGUgcHJvamVjdCBmb2xkZXIgaGFzIGEgc3ViLWZvbGRlciBjYWxsZWQgKipkYXRhKiogYW5kIHRoYXQgdGhlIC5jc3YgZmlsZSBoYXMgYmVlbiBwbGFjZWQgaW4gdGhhdCBmb2xkZXIuCgpgYGB7ciBsb2FkIGRhdGEsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2UgPSBGQUxTRX0KIyBMb2FkIGRwbHlyCmxpYnJhcnkoZHBseXIpCgoKIyBJbXBvcnQgdGhlIGNzdiBmaWxlIGludG8gYSBkYXRhIGZyYW1lCmZpcmVzX2RmIDwtIGZpcmVzX2RmIDwtIHJlYWQuY3N2KCJkYXRhL2ZvcmVzdF9maXJlc19wb3J0dWdhbC5jc3YiKQoKIyBJbnNwZWN0IHRoZSBkYXRhCnN0cihmaXJlc19kZikKCmBgYAoKIyMjIFNlbGVjdGluZyBjb2x1bW5zCgpUbyBleHRyYWN0IGluZGl2aWR1YWwgY29sdW1ucywgdXNlIGZ1bmN0aW9uIGBzZWxlY3RgLCBwYXNzaW5nIGluIHRoZSBkYXRhZnJhbWUsIGFuZCB0aGUgbmFtZXMgb2YgdGhlIGNvbHVtbnMgeW91IHdhbnQuIFRoZXJlIGlzIG5vIG5lZWQgdG8gZm9ybWF0IHRoZSBjb2x1bW4gbmFtZXMgaW50byBhIHZlY3Rvciwgb3IgdG8gdXNlIGRvdWJsZSBxdW90ZXMuCgpgYGB7ciwgcmVzdWx0cz0naGlkZSd9CiMgU2VsZWN0IHRoZSBGaXJlQXJlYUhhIGNvbHVtbiwgd2hpY2ggc2hvd3MgYXJlYSBkYW1hZ2VkIGJ5IHRoZSBmaXJlIGluIGhlY3RhcmVzCnNlbGVjdChmaXJlc19kZiwgRmlyZUFyZWFIYSkKYGBgCgpgYGB7cn0KIyBTZWxlY3QgdGhlIG1vbnRoIGFuZCBmaXJlIGFyZWEgY29sdW1ucywgYW5kIHN0b3JlIHRoZW0gaW4gYSBuZXcgdmVjdG9yCm1vbnRoX2FyZWFfZGYgPC0gc2VsZWN0KGZpcmVzX2RmLCBNb250aCwgRmlyZUFyZWFIYSkKCiMgSW5zcGVjdAptb250aF9hcmVhX2RmWzM1MDozNTUsXSAjIFlvdSBjYW4gY29tYmluZSBiYXNlIFIgW10gd2l0aCBkcGx5cgoKIyBGb3IgZWZmaWNpZW5jeSwgeW91IGNhbiBkZWZpbmUgYSB2ZWN0b3Igb2YgY29sdW1uIG5hbWVzIHRvIHVzZSB3aGVuZXZlcgojIG5lZWRlZC4gVXNlIGRvdWJsZSBxdW90ZXMgYXMgcGVyIHVzdWFsCnNlbGVjdGVkX2NvbHMgPC0gYygiSHVtaWRpdHkiLCAiRmlyZUFyZWFIYSIpCmh1bWlkaXR5X2FyZWFfZGYgPC0gc2VsZWN0KGZpcmVzX2RmLCBhbGxfb2Yoc2VsZWN0ZWRfY29scykpCgojIEV4YW1wbGUgYW5hbHlzaXMgdXNpbmcgdHdvIGNvbHVtbnMKY29yKGh1bWlkaXR5X2FyZWFfZGYpCgpgYGAKCjwhLS0KLSB1c2luZyBoZWxwZXIgZnVuY3Rpb25zCiAgLSBzdGFydHNfd2l0aAogIC0gZW5kc193aXRoCiAgLSBjb250YWlucwogIC0gYW55b2YKLS0+CgoKXAoKIyMjIFNlbGVjdGluZyByb3dzCgpJbiBjb21wdXRpbmcsIHRoZSBwcm9jZXNzIG9mIHNlbGVjdGluZyByb3dzIGZyb20gYSBkYXRhIHRhYmxlIGJhc2VkIG9uIHBhcnRpY3VsYXIgY3JpdGVyaWEgaXMgY2FsbGVkICoqZmlsdGVyaW5nKiouIFdpdGggYGRwbHlyYCB3ZSB1c2UgZnVuY3Rpb24gYGZpbHRlcmAsIHBhc3NpbmcgdGhlIG5hbWUgb2YgdGhlIGRhdGEgZnJhbWUgYW5kIHRoZSBmaWx0ZXIgY29uZGl0aW9uLiBUaGUgcmVzdWx0IGlzIGEgbmV3IGRhdGEgZnJhbWUgdGhhdCBjb250YWlucyBhbGwgcm93cyBmcm9tIHRoZSBvcmlnaW5hbCBmb3Igd2hpY2ggdGhlIGZpbHRlciBjb25kaXRpb24gZXZhbHVhdGVkIHRvIFRSVUUuCgpgYGB7cn0KIyBFeHRyYWN0IGFsbCBmaXJlcyB0aGF0IG9jY3VycmVkIGluIE9jdG9iZXIgKGkuZS4gd2hlcmUgdGhlIE1vbnRoIGNvbHVtbiBjb250YWlucwojICdvY3QnKQpvY3RvYmVyX2ZpcmVzIDwtIGZpbHRlcihmaXJlc19kZiwgTW9udGggPT0gJ29jdCcpCgojIENvbXB1dGUgdGhlIG1lYW4gZHJvdWdodCBsZXZlbCBmb3IgYWxsIGZpcmVzIGluIG9jdG9iZXIsIHVzaW5nIGJhc2UgUgojIGNvbHVtbiBzZWxlY3Rpb24gd2l0aCAkCm1lYW4ob2N0b2Jlcl9maXJlcyREcm91Z2h0TGV2ZWwpCgpgYGAKCiMjIyBFeGVyY2lzZQoKMS4gSG93IHdvdWxkIHlvdSBnZW5lcmF0ZSBkYXRhIGZyYW1lIG9jdG9iZXJfZmlyZXMgdXNpbmcgW10gaW4gYmFzZSBSPwoyLiBSZWZlcnJpbmcgdG8gdGhlIFZpc3VhbGlzYXRpb24gTW9kdWxlLCBob3cgd291bGQgeW91IHNlbGVjdCB0aGUgRGVubWFyayBkYXRhIHVzaW5nIGRwbHlyPwoKCiMjIyBGaWx0ZXJpbmcgd2l0aCBjb21wbGV4IGNvbmRpdGlvbmFscwoKT2Z0ZW4gd2Ugd2lzaCB0byBmaWx0ZXIgb24gY3JpdGVyaWEgdGhhdCBpbnZvbHZlIG11bHRpcGxlIGNvbXBhcmlzb25zLiBGb3IgZXhhbXBsZSwgaWYgd2Ugd2lzaCB0byBleHRyYWN0IGFsbCB0aGUgcm93cyBmb3IgZmlyZXMgZHVyaW5nIHRoZSB3aW50ZXIgc2Vhc29uIChEZWNlbWJlciB0aHJvdWdoIEZlYnJ1YXJ5IGluIFBvcnR1Z2FsKSB3ZSB3YW50IHJvd3MgZm9yIHdoaWNoIE1vbnRoIGlzICdkZWMnIG9yICdqYW4nIG9yICdmZWInLiBFYXJsaWVyIHdlIHNhdyBob3cgdG8gZG8gdGhpcyB3aXRoYCVpbiVgLiBNb3JlIGdlbmVyYWxseSwgd2UgY2FuIGNvbWJpbmUgY29uZGl0aW9uYWwgc3RhdGVtZW50cyB1c2luZyB0aGUgbG9naWNhbCBBTkQgYW5kIE9SIG9wZXJhdG9ycywgYCZgIGFuZCBgfGAgcmVzcGVjdGl2ZWx5LgoKYGBge3J9CiMgU2VsZWN0IHRoZSB3aW50ZXIgZmlyZXMKd2ludGVyX2RmIDwtIGZpbHRlcihmaXJlc19kZiwgTW9udGggPT0gImRlYyIgfCBNb250aCA9PSAiamFuIiB8IE1vbnRoID09ICJmZWIiKQpgYGAKCgojIyMgRXhlcmNpc2U6CgpUaGUgWFJlZ2lvbiBhbmQgWVJlZ2lvbiBmaWVsZHMgYXJlIGNvb3JkaW5hdGVzIGluIGEgcHJlLWRlZmluZWQgOSBieSA5IGdyaWQgdGhhdCBjb3ZlcnMgYWxsIG9mIFBvcnR1Z2FsLiBZb3Ugd2FudCB0byBmaW5kIGFsbCBmaXJlcyB0aGF0IG9jY3VycmVkIG9uIHRoZSBlYXN0IGFuZCB3ZXN0IGJvcmRlcnMgb2YgdGhlIGNvdW50cnkgLS0gdGhhdCBpcywgaW4gWFJlZ2lvbnMgMSwgMiwgOCwgb3IgOS4gRmlsdGVyIGZvciB0aGVzZSByZWNvcmRzLiBNYWtlIHlvdXIgZXhwcmVzc2lvbiBhcyBzdWNjaW5jdCBhcyB5b3UgY2FuLiAoWW91IG9ubHkgbmVlZCBvbmUgYHxgLikKCmBgYHtyfQp4X2VkZ2VfZmlyZXMgPC0gZmlsdGVyKGZpcmVzX2RmLCBYUmVnaW9uIDw9IDIgfCBYUmVnaW9uID49IDgpCmBgYAoKCgojIyMgRXhlcmNpc2U6CgpGcmVxdWVudGx5LCB3ZSB3YW50IGV4dHJhY3QgYSBzdWJzZXQgb2Ygcm93cyAqYW5kKiBhIHN1YnNldCBvZiBjb2x1bW5zIGZyb20gYSBsYXJnZSBkYXRhIHNldCAtLSB0aGF0IGlzLCB3ZSB3aWxsIHdhbnQgdG8gcGVyZm9ybSBib3RoIGEgc2VsZWN0IGFuZCBhIGZpbHRlciBvcGVyYXRpb24uIFVzaW5nIGFuIGludGVybWVkaWF0ZSB2YXJpYWJsZSwgd3JpdGUgY29kZSB0byBleHRyYWN0IG1vbnRoLCB0ZW1wZXJhdHVyZSwgYW5kIGZpcmUgYXJlYSBmb3Igb25seSB0aGUgc3VtbWVyIG1vbnRocyAoSnVuZSwgSnVseSwgYW5kIEF1Z3VzdCkuIE5vdGUgdGhhdCBsYXRlciBpbiB0b2RheSdzIHNlc3Npb24gd2Ugd2lsbCBzZWUgYW4gYWx0ZXJuYXRpdmUgImRwbHlyIHN5bnRheCIgZm9yIHRoaXMgY29tYmluZWQgb3BlcmF0aW9uLCBidXQgaXQgZ29vZCB0byBtYXN0ZXIgYm90aCBhcHByb2FjaGVzLgoKYGBge3J9CiMgRXhlcmNpc2UgU29sdXRpb24gKHRoZXJlIGFyZSBtYW55IHBvc3NpYmxlIHNvbHV0aW9ucykKCiMgRmlsdGVyIHRvIGdldCB0aGUgcm93cyB3ZSB3YW50CnN1bW1lcl9maXJlc19kZiA8LSBmaWx0ZXIoZmlyZXNfZGYsIE1vbnRoICVpbiUgYygnanVuJywgJ2p1bCcsJ2F1ZycpKQoKIyBQYXNzIHRoZSByZXN1bHQgb2YgdGhlIGZpbHRlcmluZyBvcGVyYXRpb24gdG8gc2VsZWN0CnN1bW1lcl90ZW1wZXJhdHVyZV9hcmVhX2RmIDwtIHNlbGVjdChzdW1tZXJfZmlyZXNfZGYsIE1vbnRoLCBUZW1wZXJhdHVyZSwgRmlyZUFyZWFIYSkKYGBgCgoKCgpcCgojIyBTb3J0aW5nCgpTb3J0aW5nIGlzIGFuIGV4dHJlbWVseSBjb21tb24gb3BlcmF0aW9uIG9uIGxhcmdlIGRhdGEgc2V0cywgYXMgaXQgbWFrZXMgaXQgZWFzaWVyIHRvIGluc3BlY3Qgb3VyIGRhdGEgZWZmaWNpZW50bHkuIFRvIHNvcnQgd2l0aCBgZHBseXJgLCB1c2UgZnVuY3Rpb24gYGFycmFuZ2VgLiBQYXNzIGluIHRoZSBuYW1lIG9mIHRoZSBkYXRhIGZyYW1lLCBhbmQgdGhlIGNvbHVtbnMgb24gd2hpY2ggeW91IHdpc2ggdG8gc29ydCwgZnJvbSBzbG93ZXN0IHRvIGZhc3Rlc3QgbW92aW5nLgoKYGBge3J9CiMgU29ydCBhbGwgcmVjb3JkcyBpbiBvcmRlciBvZiBhcmVhIGNvbnN1bWVkIChjb2x1bW4gRmlyZUFyZWFIYSkKc29ydF9ieV9hcmVhX2RmIDwtIGFycmFuZ2UoZmlyZXNfZGYsIEZpcmVBcmVhSGEpCgoKIyBUbyBzb3J0IGluIGRlc2NlbmRpbmcgb3JkZXIsIGFwcGx5IGZ1bmN0aW9uIGRlc2MgdG8gdGhlIGNvbHVtbgpzb3J0X2J5X2FyZWFfZGYgPC0gYXJyYW5nZShmaXJlc19kZiwgZGVzYyhGaXJlQXJlYUhhKSkKCgojIFNvcnRpbmcgb24gbXVsdGlwbGUgY29sdW1ucwpzb3J0X2J5X21vbnRoX2FyZWFfZGYgPC0gYXJyYW5nZShmaXJlc19kZiwgTW9udGgsIGRlc2MoRmlyZUFyZWFIYSkpCmBgYAoKWW91IHdpbGwgbm90ZSB0aGF0IHRoaXMgbGFzdCByZXN1bHQgaXMgc29ydGVkIGJ5IG1vbnRoICphbHBoYWJldGljYWxseSouIFRoaXMgbWFrZXMgc2Vuc2UgdG8gUiwgYnV0IHdlIHByb2JhYmx5IHdvdWxkIHByZWZlciB0byBoYXZlIGl0IHNvcnRlZCAqbG9naWNhbGx5Ki4gVG8gZW5zdXJlIHRoaXMsIHdlIGNhbiBjYXN0IGNvbHVtbiBNb250aCBmcm9tIHR5cGUgImNociIgKGp1c3Qgc3RyaW5ncykgdG8gdHlwZSAiT3JkZXJlZCBGYWN0b3IiLCBhbiBvcmRlcmVkIGNhdGVnb3JpY2FsIHZhcmlhYmxlLiBUaGUgY29kZSBmb3IgdGhpcyBvcGVyYXRpb24gaXMgc2hvd24gYmVsb3cuIFdlIHdpbGwgZGlzY3VzcyB0aGUgbWFuYWdlbWVudCBvZiBjYXRlZ29yaWNhbCB2cy4gbnVtZXJpY2FsIHZhcmlhYmxlcyBpbiBtb3JlIGRlcHRoIGluIHRoZSBTdW1tYXJpc2luZyBNb2R1bGUsIGxhdGVyIGluIHRoZSBzZW1lc3Rlci4KCmBgYCB7cn0KIyBEZWZpbmUgdGhlIGxvZ2ljYWwgb3JkZXIgb2Ygb3VyIG1vbnRoIGNvZGVzCm1vbnRoc19pbl9vcmRlciA9IGMoImphbiIsICJmZWIiLCAibWFyIiwgImFwciIsICJtYXkiLCAianVuIiwgImp1bCIsICJhdWciLCAic2VwIiwKICAgICAgICAgICAgICAgICAgICAib2N0IiwgIm5vdiIsICJkZWMiKQoKIyBNb2RpZnkgdGhlIE1vbnRoIGNvbHVtbiBzbyBpdCB1c2VzIHRoYXQgb3JkZXJpbmcgCmZpcmVzX2RmJE1vbnRoIDwtIG9yZGVyZWQoZmlyZXNfZGYkTW9udGgsIGxldmVscyA9IG1vbnRoc19pbl9vcmRlcikKCiMgUmVwZWF0IHRoZSBzb3J0IG9wZXJhdGlvbiB0byBjb25maXJtCnNvcnRfYnlfbW9udGhfYXJlYV9kZiA8LSBhcnJhbmdlKGZpcmVzX2RmLCBNb250aCwgZGVzYyhGaXJlQXJlYUhhKSkKCiMgQ2hlY2sKaGVhZChzb3J0X2J5X21vbnRoX2FyZWFfZGYpCmBgYAoKCiMjIFN1bW1hcmlzaW5nIGJ5IGdyb3VwCgpXZSB0eXBpY2FsbHkgZXh0cmFjdCBzdWJzZXRzIGZyb20gYSBkYXRhIGZyYW1lIHRvIHNlcnZlIGFzIGlucHV0IHRvIG1ldGhvZHMgdGhhdCBzdW1tYXJpc2UsIHBlcmZvcm0gc3RhdGlzdGljYWwgYW5hbHlzZXMsIG9yIHByb2R1Y2UgZ3JhcGhzIG9mIHRob3NlIGRhdGEuIExpYnJhcnkgYGRwbHlyYCBwcm92aWRlcyBhIHBhaXIgb2YgbWV0aG9kcyAtLSBgZ3JvdXBfYnlgIGFuZCBgc3VtbWFyaXNlYCAtLSB3aGljaCwgd2hlbiB1c2VkIHRvZ2V0aGVyLCBtYWtlIHRoaXMgd29ya2Zsb3cgZXNwZWNpYWxseSBzdWNjaW5jdCBmb3Igc2ltcGxlIHBvc3Qtc2VsZWN0aW9uIHByb2Nlc3NpbmcuCgpBc3N1bWUgdGhhdCB5b3Ugd291bGQgbGlrZSB0byBrbm93IHRoZSBtZWFuIGZpcmUgYXJlYSBjb25zdW1lZCBmb3IgZWFjaCBtb250aC4gWW91IHdpbGwgZmlyc3QgYXBwbHkgYGdyb3VwX2J5YCB0byBgZmlyZXNfZGZgIHRvIGRlZmluZSB5b3VyIGdyb3VwaW5nIHZhcmlhYmxlIGFzIGNvbHVtbiBgTW9udGhgLiBUaGlzIGhhcyBubyBtYWpvciB2aXNpYmxlIGltcGFjdCBvbiBgZmlyZXNfZGZgLiBIb3dldmVyLCBhbnkgc3Vic2VxdWVudCBzdW1tYXJpZXMgeW91IHBlcmZvcm0gb24gdGhhdCBkYXRhIGZyYW1lIHdpdGggZnVuY3Rpb24gYHN1bW1hcmlzZWAgKiphcmUgYXBwbGllZCBieSBncm91cCoqLiBGb3IgZXhhbXBsZSwgaWYgeW91IHVzZSBgc3VtbWFyaXNlYCB0byBjb21wdXRlIHRoZSBtZWFuIG9mIEZpcmVBcmVhSGEgKHN5bnRheCBzaG93biBiZWxvdyksIGl0IGNvbXB1dGVzIHRoYXQgbWVhbiBmb3IgZWFjaCBtb250aCBzZXBhcmF0ZWx5LiBJZiB5b3UgdXNlIGBzdW1tYXJpc2VgIHRvIGNvbXB1dGUgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiBUZW1wZXJhdHVyZSwgaXQgY29tcHV0ZXMgdGhhdCBzdGFuZGFyZCBkZXZpYXRpb24gZm9yIGVhY2ggbW9udGggc2VwYXJhdGVseS4gQW5kIHNvIG9uLgoKYGBge3J9CiMgVG8gY29tcGFyZSBhcmVhIGNvbnN1bWVkIGJ5IG1vbnRoCgojIEFwcGx5IGdyb3VwX2J5LiBJbiBWaWV3IHRoZSBkYXRhIGZyYW1lIGxvb2tzIHVuY2hhbmdlZApmaXJlc19ncF9tb250aF9kZiA8LSBncm91cF9ieShmaXJlc19kZiwgTW9udGgpCgojIFdoZW4gcHJpbnRlZCB0byBjb25zb2xlLCB0aGUgZGF0YSBmcmFtZSBhbHNvIGxvb2tzIHRoZSBzYW1lIGV4Y2VwdCBmb3IgR3JvdXBzCiMgaGVhZGVyCmZpcmVzX2dwX21vbnRoX2RmCmBgYAoKClRoZSBtYWdpYyBoYXBwZW5zIHdoZW4gd2UgdGFrZSBhIGdyb3VwZWQgZGF0YSBmcmFtZSBhbmQgcGFzcyBpdCB0byBgc3VtbWFyaXNlYC4gRnVuY3Rpb24gYHN1bW1hcmlzZWAgcmV0dXJucyBhIG5ldyBkYXRhIGZyYW1lIHdpdGggYSByb3cgZm9yIGVhY2ggbGV2ZWwgb2YgdGhlIGdyb3VwaW5nIHZhcmlhYmxlLCBhbmQgYSBjb2x1bW4gZm9yIGVhY2ggc3VtbWFyeSBmdW5jdGlvbiB3ZSBzcGVjaWZ5LgoKYGBge3J9CiMgVCBzZWNvbmQgYXJnIHRvIHN1bW1hcmlzZSBpcyAiY29sIGhlYWRlciA9IGV4cHJlc3Npb24iLiBFeHByZXNzaW9uIGlzIGFwcGxpZWQgYnkgZ3JvdXAKCnN1bW1hcmlzZShmaXJlc19ncF9tb250aF9kZiwgTWVhbkFyZWFMbiA9IG1lYW4oRmlyZUFyZWFIYSwgbmEucm0gPSBUUlVFKSkKYGBgCgpOb3RlIHRoYXQgeW91IGNhbiBwcm92aWRlIG11bHRpcGxlIGV4cHJlc3Npb25zIHRvIGBzdW1tYXJpc2VgLiBJdCBwcm9kdWNlcyBhIGNvbHVtbiBmb3IgZWFjaC4gCgpZb3UgY2FuIGFsc28gcHJvdmlkZSBtdWx0aXBsZSBjb2x1bW4gbmFtZXMgdG8gYGdyb3VwX2J5YC4gRnVuY3Rpb24gYHN1bW1hcmlzZWAgaXMgdGhlbiBhcHBsaWVkIHRvIHRoZSBncm91cHMgZGVmaW5lZCBieSBlYWNoIGNvbWJpbmF0aW9uIG9mIHZhbHVlcyBvbiB0aGUgZ3JvdXBpbmcgdmFyaWFibGVzLiAKCmBgYHtyfQojIEdyb3VwaW5nIG9uIHR3byB2YXJpYWJsZXMKZmlyZXNfbW9udGhfZGF5IDwtIGdyb3VwX2J5KGZpcmVzX2RmLCBNb250aCwgRGF5KQpzdW1tYXJpc2UoZmlyZXNfbW9udGhfZGF5LCBNZWFuQXJlYUZvck1vbnRoQW5kRGF5T2ZXZWVrID0gbWVhbihGaXJlQXJlYUhhLCBuYS5ybSA9IFRSVUUpKQoKYGBgCgoKIyMjIEV4ZXJjaXNlCgoxLiBVc2UgJ2dyb3VwX2J5JyBhbmQgJ3N1bW1hcmlzZScgdG8gZmluZCB0aGUgbGFyZ2VzdCBmaXJlIChpLmUuIG1heGltdW0gYXJlYSBidXJudCkgaW4gZWFjaCBtb250aC4KMi4gQSB1c2VmdWwgd29ya2VyIGZ1bmN0aW9uIGluIGxpYnJhcnkgYGRwbHlyYCBpcyBgbigpYC4gVGhpcyBmdW5jdGlvbiwgd2hlbiB1c2VkIGluIGBzdW1tYXJpc2VgLCBjb3VudHMgdGhlIG51bWJlciBvZiByZWNvcmRzIGluIGVhY2ggZ3JvdXAgKGl0IHRha2VzIG5vIGNvbHVtbiBoZWFkZXI7IGl0IGp1c3QgY291bnRzIHRoZSBudW1iZXIgb2Ygcm93cyBpbiB0aGUgZ3JvdXApLiBHZW5lcmF0ZSBhIHRhYmxlIHRoYXQgc2hvd3MgdGhlIG51bWJlciBvZiBmaXJlcyB0aGF0IG9jY3VycmVkIG9uIGVhY2ggZGF5IG9mIHRoZSB3ZWVrLiBIb3cgd291bGQgeW91IGV4cGxhaW4gdGhlIHBhdHRlcm4gaW4gdGhlc2UgcmVzdWx0cz8KCgpgYGB7cn0KIyBFeGVyY2lzZSBTb2x1dGlvbgpmaXJlc19ncF9kYXlfZGYgPC0gZ3JvdXBfYnkoZmlyZXNfZGYsIERheSkKc3VtbWFyaXNlKGZpcmVzX2dwX2RheV9kZiwgTkZpcmVzID0gbigpKSAKYGBgCgozLiBNb2RpZnkgYGZpcmVzX2RmYCBzbyB0aGF0IGBzdW1tYXJpc2VgIG91dHB1dHMgdGhlIGRheXMgaW4gdGhlaXIgY29ycmVjdCBsb2dpY2FsIG9yZGVyIChlLmcuIFdlZG5lc2RheSBiZWZvcmUgVGh1cnNkYXkpLgoKXAoKIyMgUGlwZXMKCldoZW4geW91IGluc3RhbGwgZHBseXIgKGVpdGhlciBhbG9uZSBvciBhcyBwYXJ0IG9mIG1ldGEtcGFja2FnZSB0aWR5dmVyc2UpLCB5b3UgYWxzbyBnZXQgbGlicmFyeSBgbWFncml0dHJgLCB3aGljaCBjb250YWlucyBhIHNwZWNpYWwgb3BlcmF0b3IgY2FsbGVkICp0aGUgcGlwZSouIChOQjogVGhlIGNoYXJhY3RlciB8LCB1c2VkIGZvciBPUiwgaXMgYWxzbyBjYWxsZWQgdGhlIHBpcGUuIEp1c3Qgb25lIG9mIHRob3NlIHRoaW5ncy4pCgpXaXRoIHRoZSBwaXBlLCB3ZSBjYW4gcGVyZm9ybSBhIHNlcmllcyBvZiBvcGVyYXRpb25zLCBmb3IgZXhhbXBsZSBmaWx0ZXIgYW5kIHNlbGVjdCwgd2l0aG91dCBpbnRlcm1lZGlhdGUgdmFyaWFibGVzLiBXZSB0aGluayBvZiBzdGFydGluZyB3aXRoIG91ciBjb21wbGV0ZSBkYXRhIGZyYW1lIGFuZCBwdXNoaW5nIGl0IHRocm91Z2ggYSBzZXJpZXMsIG9yICoqcGlwZWxpbmUqKiBvZiBvcGVyYXRpb25zLiBBdCBlYWNoIHN0ZXAsIHRoZSBvdXRwdXQgZnJvbSBvbmUgb3BlcmF0aW9uIGlzIHBhc3NlZCBhbG9uZyBhcyB0aGUgaW5wdXQgb2YgdGhlIG5leHQuCgpXaGVuIHVzaW5nIHRoZSBwaXBlLCB3ZSBubyBsb25nZXIgaGF2ZSB0byBwcm92aWRlIHRoZSBuYW1lIG9mIGRhdGEgZnJhbWUgYXMgdGhlIGZpcnN0IGFyZ3VtZW50IHRvIGFsbCB0aGUgZHBseXIgZnVuY3Rpb25zIC0tIHRoZXkgYWx3YXlzIHRha2UgdGhlIG91dHB1dCBvZiB0aGUgcHJldmlvdXMgc3RlcCBpbiB0aGUgcGlwZS4KClByZXZpb3VzbHksIHdlIGNvbWJpbmVkIGZpbHRlciBhbmQgc2VsZWN0IGJ5IHVzaW5nIGFuIGludGVybWVkaWF0ZSB2YXJpYWJsZSwgbGlrZSB0aGlzOgoKYGBge3J9CiMgRmlsdGVyIHRvIGdldCB0aGUgcm93cyB3ZSB3YW50CnN1bW1lcl9maXJlc19kZiA8LSBmaWx0ZXIoZmlyZXNfZGYsIE1vbnRoICVpbiUgYygnanVuJywgJ2p1bCcsJ2F1ZycpKQoKIyBQYXNzIHRoZSByZXN1bHQgb2YgdGhlIGZpbHRlcmluZyBvcGVyYXRpb24gdG8gc2VsZWN0CnN1bW1lcl90ZW1wZXJhdHVyZV9hcmVhX2RmIDwtIHNlbGVjdChzdW1tZXJfZmlyZXNfZGYsIE1vbnRoLCBUZW1wZXJhdHVyZSwgRmlyZUFyZWFIYSkKYGBgCgpVc2luZyBwaXBlIHN5bnRheCwgdGhlIHNhbWUgcmVzdWx0IHdvdWxkIGJlIG9idGFpbmVkIHdpdGg6CgpgYGB7cn0Kc3VtbWVyX3RlbXBlcmF0dXJlX2FyZWFfZGYgPC0gZmlyZXNfZGYgJT4lIGZpbHRlcihNb250aCAlaW4lIGMoImp1biIsICJqdWwiLCAiYXVnIikpICU+JSBzZWxlY3QoTW9udGgsIFRlbXBlcmF0dXJlLCBGaXJlQXJlYUhhKQoKaGVhZChzdW1tZXJfdGVtcGVyYXR1cmVfYXJlYV9kZikKYGBgCgpMaWtlIHRoZSArIHN5bWJvbCBpbiBnZ3Bsb3QsIGAlPiVgIHNpZ25hbHMgdG8gUlN0dWRpbyB0aGF0IG1vcmUgY29kZSBpcyBjb21pbmcsIGFsbG93aW5nIHlvdSB0byBtYWtlIHRoZSBjb2RlIHJlYWRhYmxlIGJ5IHBsYWNpbmcgZWFjaCBvcGVyYXRpb24gaW4gdGhlIHBpcGVsaW5lIG9uIGEgbmV3IGxpbmU6CgpgYGB7cn0Kc3VtbWVyX3RlbXBlcmF0dXJlX2FyZWFfZGYgPC0gZmlyZXNfZGYgJT4lIAogIGZpbHRlcihNb250aCAlaW4lIGMoImp1biIsICJqdWwiLCAiYXVnIikpICU+JSAKICBzZWxlY3QoTW9udGgsIFRlbXBlcmF0dXJlLCBGaXJlQXJlYUhhKQoKaGVhZChzdW1tZXJfdGVtcGVyYXR1cmVfYXJlYV9kZikKYGBgCgojIyMgRXhlcmNpc2UKCjEuIFVzaW5nIGdyb3VwX2J5LCBzdW1tYXJpc2UsIGFuZCBwaXBlIG5vdGF0aW9uLCBjb21wdXRlIHRoZSBtZWFuIHRlbXBlcmF0dXJlIGZvciBlYWNoIG1vbnRoCgpgYGB7cn0KIyBFeGVyY2lzZSBzb2x1dGlvbgpmaXJlc19kZiAlPiUgZ3JvdXBfYnkoTW9udGgpICU+JSBzdW1tYXJpc2UoTWVhblRlbXBlcmF0dXJlID0gbWVhbihUZW1wZXJhdHVyZSwgbmEucm0gPSBUUlVFKSkKYGBgCgpcCgoyLiBZb3UgY2FuIHVzZSBnZ3Bsb3QgYXQgdGhlIGVuZCBvZiBhIHBpcGVsaW5lLiBXcml0ZSBhIHNpbmdsZSBjb21tYW5kIHRvIG1ha2UgYSBib3hwbG90IHRoYXQgaWxsdXN0cmF0ZXMgdGhlIGRpc3RyaWJ1dGlvbiBvZiBkcm91Z2h0IGxldmVsIGR1cmluZyBlYWNoIG9mIHRoZSBzdW1tZXIgbW9udGhzIGluIFBvcnR1Z2FsLiBQbGFuOiBGaXJzdCBmaWx0ZXIgb3V0IHRoZSBtb250aHMgeW91IHdhbnQsIHRoZW4gbWFrZSBhIGJveHBsb3Qgd2l0aCB4ID0gTW9udGggYW5kIHkgPSBEcm91Z2h0TGV2ZWwKCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCgpmaXJlc19kZiAlPiUgZmlsdGVyKE1vbnRoICVpbiUgYygianVuIiwgImp1bCIsICJhdWciKSkgJT4lCiAgZ2dwbG90KG1hcHBpbmcgPSBhZXMoeCA9IE1vbnRoLCB5ID0gRHJvdWdodExldmVsKSkgKyAKICBnZW9tX2JveHBsb3QoKQpgYGAKClwKCjMuIFdyaXRlIGEgc2luZ2xlIGNvbW1hbmQgdGhhdCBwcm9kdWNlcyBhIGJhciBncmFwaCBvZiB0aGUgbWVhbiB0ZW1wZXJhdHVyZSBmb3IgZWFjaCBtb250aC4gKFBsYW46IFRoZSBwaXBlbGluZSBzdGFydHMgd2l0aCBgZ3JvdXBfYnlgIGFuZCBgc3VtbWFyaXNlYCB0byBjb21wdXRlIHRoZSBtZWFucywgdGhlbiBwb3VycyB0aGF0IG91dHB1dCBpbnRvIGdncGxvdC4gTWFrZSB0aGUgZ3JhcGggdXNpbmcgYGdlb21fYmFyYC4gU2V0IHRoZSB4IGF4aXMgdG8gTW9udGggYW5kIHRoZSB5IGF4aXMgdG8gdGhlIGNvbHVtbiBuYW1lIHlvdSBhc3NpZ24gZm9yIHRoZSBtZWFuIHRlbXBlcmF0dXJlIGluIGBzdW1tYXJpc2VgLiBQYXNzIGludG8gZ2VvbV9iYXIgdGhlIGFyZ3VtZW50IGBzdGF0ID0gImlkZW50aXR5ImAgc28gaXQgcGxvdHMgdGhlIGRhdGEgdmFsdWVzIGFzIHByb3ZpZGVkLiBOb3RlIHRoZSBkb3VibGUgcXVvdGVzIGFyb3VuZCB0aGUgKmlkZW50aXR5KjsgdGhleSBhcmUgcmVxdWlyZWQuKQoKYGBge3J9CiMgRXhlcmNpc2Ugc29sdXRpb24KCmxpYnJhcnkoZ2dwbG90MikKCmZpcmVzX2RmICU+JSAKICBncm91cF9ieShNb250aCkgJT4lIAogIHN1bW1hcmlzZShNZWFuVGVtcGVyYXR1cmUgPSBtZWFuKFRlbXBlcmF0dXJlLCBuYS5ybSA9IFRSVUUpKSAlPiUKICBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4ID0gTW9udGgsIHkgPSBNZWFuVGVtcGVyYXR1cmUpKSArIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKQpgYGAKCgoKIyMgQSBXb3JkIG9mIENhdXRpb24KCkRwbHlyIHBpcGVsaW5lIHN5bnRheCBpcyBwb3B1bGFyIGJlY2F1c2UgaXQgZWxpbWluYXRlcyB0aGUgbmVlZCBmb3IgaW50ZXJtZWRpYXRlIHZhcmlhYmxlcyBhbmQsIHRoZXJlZm9yZSwgcmVxdWlyZXMgYSBsb3QgbGVzcyB0eXBpbmcuIEl0IGlzIGNvbW1vbiwgd2hlbiBmaXJzdCBlbmNvdW50ZXJpbmcgdGhpcyBvcHRpb24sIHRvIGdldCBzbGlnaHRseSBjYXJyaWVkIGF3YXksIGFuZCBjaGFpbiB0b2dldGhlciBkb3plbnMgb2Ygb3BlcmF0aW9ucywgcmV2ZWxpbmcgaW4gaG93IG1hbnkga2V5c3Ryb2tlcyB5b3UgYXJlIHNhdmluZy4gVGhpcyBpcyByaXNreSwgZm9yIHNldmVyYWwgcmVhc29uczoKCjEuIElmIGEgbG9uZyBwaXBlbGluZSBmYWlscywgeW91IHdpbGwgbm90IGtub3cgKmluIHdoaWNoIG9wZXJhdGlvbiB0aGUgZXJyb3Igb2NjdXJyZWQqLiBUaGlzIGNhbiBtYWtlIGl0IGV4dHJlbWVseSBkaWZmaWN1bHQgdG8gZGVidWcuIAoyLiBCZWNhdXNlIHlvdSBhcmUgbm90IHNhdmluZyBhbnkgb2YgdGhlIGludGVybWVkaWF0ZSBvdXRwdXRzLCB5b3UgZG8gbm90IGhhdmUgdGhlbSBhdmFpbGFibGUgZm9yIGRpZmZlcmVudCBwcm9jZXNzaW5nIGluIG90aGVyIGNvbnRleHRzIC0tIHlvdSB3aWxsIGhhdmUgdG8gcmVwZWF0IHRoZSB3aG9sZSBwb3J0aW9uIG9mIHRoZSBwaXBlbGluZSB3aGljaCBnZW5lcmF0ZWQgdGhlbS4gCjMuIEEgbG9uZyBwaXBlbGluZSB3aWxsIGJlIGRpZmZpY3VsdCBmb3Igb3RoZXIgcGVvcGxlIHRvICJyZWFkIiAoaS5lLiB0byBmaWd1cmUgb3V0IHdoYXQgaXQncyBkb2luZykuIFdoZW4geW91IGhhdmUgbXVsdGlwbGUgb3B0aW9ucyBmb3IgcGVyZm9ybWluZyBhIGNvbXB1dGF0aW9uLCB0aGUgIGdvYWwgaXMgdG8gc3RyaWtlIGEgYmFsYW5jZSBiZXR3ZWVuICoqcGFyc2ltb255KiogKG5vdCB0b28gbXVjaCB0eXBpbmcpIGFuZCAqKnJlYWRhYmlsaXR5KiogKHlvdXIgY29kZSBpcyBlYXN5ICpmb3Igb3RoZXIgcGVvcGxlKiB0byB1bmRlcnN0YW5kKS4gV2hlbiB3b3JraW5nIG9uIGdyb3VwIHByb2plY3RzLCBvciBpbiBhIHByb2Zlc3Npb25hbCBzb2Z0d2FyZSBkZXZlbG9wbWVudCBjb250ZXh0LCByZWFkYWJpbGl0eSBpcyBjb25zaWRlcmVkIHRoZSBtb3JlIGNyaXRpY2FsIG9mIHRoZSB0d28gZmVhdHVyZXMuIE15IHBlcnNvbmFsIHN0eWxlIGlzIG5ldmVyIHRvIGJ1aWxkIHBpcGVsaW5lcyBvZiBtb3JlIHRoYW4gdGhyZWUgb3IgZm91ciBvcGVyYXRpb25zLiBUaGUgb3V0cHV0cyBvZiB0aGVzZSBzaG9ydCBzZXF1ZW5jZXMgY2FuIGJlIHNhdmVkIGludG8gaW50ZXJtZWRpYXRlIHZhcmlhYmxlcyB3aGljaCBjYW4gYmUgY2hlY2tlZCBhbmQgcmV1c2VkLCB3aGljaCBhcmUgdGhlbiBwYXNzZWQgYWxvbmcgaW50byB0aGUgbmV4dCBwaXBlbGluZS4KXAoKIyMgQW5vdGhlciBXb3JkIG9mIENhdXRpb24KClIgdXNlcnMgYXJlIGNvbnN0YW50bHkgYWRkaW5nIG5ldyBsaWJyYXJpZXMgdG8gYmFzZSBSLCBtZWFuaW5nIHRoYXQgeW91IHdpbGwgcHJvYmFibHkgaGF2ZSBzZXZlcmFsIG9wdGlvbnMgZm9yIGRvaW5nIGFueSBqb2IgaW4gUi4gVGhlIHZhcmlvdXMgb3B0aW9ucyBzb21ldGltZXMgaGF2ZSBzdWJ0bGUgdGVjaG5pY2FsIGRpZmZlcmVuY2VzIHRoYXQgd2lsbCBnZW5lcmF0ZSBhIGxvdCBvZiBhcmd1bWVudCBiZXR3ZWVuIHByb2Zlc3Npb25hbCBwcm9ncmFtbWVycywgYnV0IGFyZSB1bmxpa2VseSB0byBtYXR0ZXIgbXVjaCB0byByZXNlYXJjaCBzY2llbnRpc3RzLiBJbiBnZW5lcmFsLCB5b3Ugc2hvdWxkIGV4cGxvcmUgdGhlIFIgZWNvc3lzdGVtIGZyZWVseSBhbmQgdXNlIHdoYXRldmVyIHlvdSBsaWtlLiAqKkhvd2V2ZXIqKiBvbiBhc3NpZ25tZW50cywgaXQgaXMgd2lzZSB0byBjaGVjayB3aXRoIHRoZSBsZWN0dXJlciBiZWZvcmUgdXNpbmcgc29tZXRoaW5nIHRoYXQgaXMgcmVhbGx5IGRpZmZlcmVudCBmcm9tIHdoYXQgaXMgcHJlc2VudGVkIGluIGNsYXNzLiBZb3VyIGxlY3R1cmVyIG1heSwgZm9yIGVkdWNhdGlvbmFsIHJlYXNvbnMsIHdhbnQgeW91IHRvIHVzZSBzcGVjaWZpYyBSIHRvb2xzLgoKIyMgV2hhdCdzIE5leHQKCllvdSBtYXkgcmVjYWxsIHRoYXQgd2F5IGJhY2sgaW4gdGhlIGZpcnN0IG1vZHVsZSBvZiBSNFNTUCB3ZSBzYWlkIHdlIHdlcmUgZ29pbmcgdG8gYW5hbHlzZSBkYXRhLiBXZSBoYXZlbid0IHJlYWxseSBkb25lIG11Y2ggb2YgdGhhdCB5ZXQuIFNvIGZhciB3ZSBoYXZlIGJlZW4gKmdldHRpbmcgcmVhZHkqIHRvIGFuYWx5c2UgZGF0YS4gSW4gdGhlIG5leHQgbW9kdWxlLCB3ZSB3aWxsIHN0YXJ0IHJlYWxseSBkaWdnaW5nIGludG8gb3VyIGRhdGEgd2l0aCBleHBsb3JhdG9yeSBhbmFseXNpcyBhbmQgZGVzY3JpcHRpdmUgc3RhdGlzdGljcy4gQmVjYXVzZSB0aGlzIGlzIG5vdCBhIHN0YXRpc3RpY3MgY291cnNlICpwZXIgc2UqIHdlIHdpbGwgb25seSBiZSB1c2luZyBjb21tb24gZ2VuZXJhbCBhbmFseXNlcyBpbiB0aGUgaGFuZG91dHMgYW5kIHJlYWRpbmdzLiBJZiwgZm9yIGEgcHJvamVjdCBvciBhc3NpZ25tZW50LCB5b3UgbmVlZCB0byBkbyBzb21ldGhpbmcgbW9yZSBlc290ZXJpYywganVzdCBsZXQgdXMga25vdyAtLSBzb21lb25lIGhhcyBwcm9iYWJseSB3cml0dGVuIGFuIFIgbGlicmFyeSBmb3IgaXQuCg==