Associated Material

Zoom notes: Zoom Notes 03 - Selecting and Filtering Data

Reading:


Introduction

If you are working through the suggested materials in order, you have just completed Chapter 5 - Data Transformation (https://r4ds.had.co.nz/transform.html) from the online text R for Data Science. This material demonstrated how to use the library dplyr, one of the libraries in the tidyverse family. You will have learned how to use the five core transformation functions – filter, arrange, select, mutate and summarise (with its helper function group_by). These functions allow you to modify and perform summaries on data frames, and to pull out specific portions of data frames for detailed analysis. 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 libraries in the tidyverse) are technically wrappers around base R code. That is, they themselves are written using base R commands. Thus it is possible to perform all the same transformations without dplyr, by using only base R. Many programmers and researchers (including some of your lecturers) prefer to use base R for these operations, and you will also see it often in R code in the wild. Therefore, in this supplementary handout, we will illustrate the equivalent base R syntax for the dplyr functions you just learned.

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 big five 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

Often when we’re dealing with data we want to be able to pull out and operate on subsets of it. There are many different methods that can be used to subset data, and we’ll cover a couple of different methods. One of the most common methods is to use the “extract” function [].

There are two main ways approaches to sub-setting: based on an identifier such as position or name, or based on a condition. And for rectangular two-dimensional objects like data frames we also think about if we’re operating on rows or columns.

Subsetting by position (index)

Vectors are made up of items, and each item has a positional index (starting from 1 - other languages differ). We can use this index as an argument to [] to pull out and return a new vector of the specified item. A negative of the index will return a copy of the original but with the item at the given position removed.

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

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

# remove the first item
some_numbers[-1]
#> [1] 45 -9  6

If we want multiple items we supply a vector of numbers for the indexes we want. The order of the supplied indexes is the order in which the resultant vector will be created - it can also be used to duplicate items.

some_letters <- c("l", "o", "h", "e")

# pull out items 1 and 3
some_letters[c(1,3)]
#> [1] "l" "h"

# reorder and duplicate
some_letters[c(3,4,1,1,2)]
#> [1] "h" "e" "l" "l" "o"

Indices are positional, but we could also supply a boolean vector with the TRUE in the positions for items we would like to keep and FALSE for items we would like to drop. The boolean vector can either match in length or be a factor of the vector length (in which case it gets ‘recycled’ until it matches the length)

some_numbers
#> [1]  2 45 -9  6

# matching length 
some_numbers[c(TRUE, TRUE, FALSE, FALSE)]
#> [1]  2 45

# take every second item
some_numbers[c(FALSE, TRUE)]
#> [1] 45  6


Subsetting by condition

Often though, we don’t want to have to identify and keep track of the indices for items in our data, but instead we want to subset our data to items that match certain conditions.

Similar to how we can operate on an entire vector through the arithmetic operators, there are also operators for performing comparisons.

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

When we apply comparisons to a vector we get in return a vector with boolean values (TRUE/FALSE) corresponding an item-wise comparison.

some_numbers < 15
#> [1]  TRUE FALSE  TRUE  TRUE

And these boolean vectors are used for sub-setting. So we can in fact supply our conditional statement as the argument to [] so keep all the items that meet our condition

# keep numbers less than 15
some_numbers[some_numbers < 15]
#> [1]  2 -9  6

One final comparison function is %in%, which lets us compare two vectors for matching items. %in% will return a boolean vector corresponding to the items on the left hand side that were also found “in” the right hand side. This operator is extremely helpful to use instead of combining multiple ‘or’ (|) conditions.

my_pets <- c("dog", "cat", "turtle")

# using 'or'
my_pets[ my_pets == "frog" | my_pets == "dog" | my_pets == "rabbit" | my_pets == "horse"]
#> [1] "dog"


# use of %in%
my_pets %in% c("frog", "dog", "rabbit", "horse")
#> [1]  TRUE FALSE FALSE

my_pets[my_pets %in% c("frog", "dog", "rabbit")]
#> [1] "dog"


Missing data

One extremely common subsetting operation is dealing with missing data. Missing data in R is represented by NA. NA in R is a special data type and the set of comparator operations that we have covered will always return NA (even NA == NA will return NA) so instead there is a special function that is used to tell us when we have missing data so we can handle it appropriately and that function is is.na which will return TRUE is something is NA and FALSE in all other instances.

NA < 6
#> [1] NA

NA == "a"
#> [1] NA

NA != TRUE
#> [1] NA

NA == NA
#> [1] NA

is.na(NA)
#> [1] TRUE

Some functions can deal with missing data as part of the function by setting the parameter na.rm = TRUE, but not all functions have this.

missing_example <- c(NA, 1, 4, 6, NA, 8)

mean(missing_example)
#> [1] NA

mean(missing_example, na.rm = TRUE)
#> [1] 4.75

To remove missing data so it can be used with functions with an na.rm parameter we can use is.na to identify the NA values and then conditionally subset:

missing_example
#> [1] NA  1  4  6 NA  8

is.na(missing_example)
#> [1]  TRUE FALSE FALSE FALSE  TRUE FALSE

missing_example[!is.na(missing_example)]
#> [1] 1 4 6 8

Remember is.na will be TRUE when there is NA, so we can use the ! (not) operator to invert the logic.



Subsetting in 2-dimensions

We can take the same principles we covered using [] on vectors and apply them on rectangular 2-dimensional structures like the data.frame. Adding a second dimension means we now need to supply 2 arguments to [], the first argument is for rows, and the second is for columns.

The general syntax is:

name_of_data_frame[row_information, column_information]

There are a variety of ways to express row and column information. To see how they work, let’s first make a very simple data frame by hand, and then perform some sub-setting operations on it. Enter the following code into RStudio to create geography_df.

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 form of subsetting, we want just one single value from a data frame, so we provide the row number and column number 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. 1

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

As an 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

Another method available in base R is the subset function. It takes the format

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

Again, not supplying the subset argument or select argument will keep all rows (subset) or columns (select).

Sub-setting isn’t usually done performed in isolation. Usually there is a workflow that we’re working through as part of our data analysis. We’re now going to take look at some functions from the Tidyverse - specifically dplyr that are part of that data analysis workflow, and we’ll also provide the equivalent base R approach.


Selecting columns

So far we’ve covered methods that will let us subset both rows and columns at the same time.

If we’re after a single column in a data frame this can be pulled out using the $ using the format dataframe$columnname, which will return the column as a vector. For instance if we wanted to know all the countries in the geography_df data we can use

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

This $ syntax can be useful if you want to perform an operation on only one column such as calculating a summary statistic like the mean or standard deviation. It can also be used to modify or create a new column on a data frame.

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

# new column PopulationThousands
geography_df$PopulationThousands <- geography_df$PopulationMillions * 1000
geography_df$PopulationThousands
#> [1]   9000 211000  38000   6000

To see how selection with the select function from dplyr compares to selection with the extract operator [ ] in base R, lets load the flights data frame and repeat some of the exercises from R for Data Science.


# Load the library that contains the flights data frame
library(nycflights13)

# Load dplyr
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union



# Select the year, month, and day columns from the flights data frame

# With dplyr
year_month_day_cols_dplyr <- select(flights, year, month, day)
year_month_day_cols_dplyr
#> # A tibble: 336,776 × 3
#>     year month   day
#>    <int> <int> <int>
#>  1  2013     1     1
#>  2  2013     1     1
#>  3  2013     1     1
#>  4  2013     1     1
#>  5  2013     1     1
#>  6  2013     1     1
#>  7  2013     1     1
#>  8  2013     1     1
#>  9  2013     1     1
#> 10  2013     1     1
#> # … with 336,766 more rows

# With base R
year_month_day_cols_base <- flights[ , c("year", "month", "day")]
year_month_day_cols_base
#> # A tibble: 336,776 × 3
#>     year month   day
#>    <int> <int> <int>
#>  1  2013     1     1
#>  2  2013     1     1
#>  3  2013     1     1
#>  4  2013     1     1
#>  5  2013     1     1
#>  6  2013     1     1
#>  7  2013     1     1
#>  8  2013     1     1
#>  9  2013     1     1
#> 10  2013     1     1
#> # … with 336,766 more rows


Filtering rows

The dplyr function filter is analogous to the base R function subset. The two functions have identical syntax. We can see how some of the dplyr filter operations from the previous section would be written using base R. If you wish, run this code in RStudio, and inspect the results of each statement.


# In all cases, these pairs of commands produce the same output
# In each pair, the first version is dplyr and the second
# is base R

# All flights with arrival delay >= 120 minutes
late_dplyr <- filter(flights, arr_delay > 120)
late_base <- subset(flights, arr_delay > 120)

# Flew to IAH or HOU
houston_dplyr <- filter(flights, dest == "IAH" | dest == "HOU")
houston_base <- subset(flights, dest == "IAH" | dest == "HOU")

# Alternatively, using %in%, which requires less typing
houston_dplyr <- filter(flights, dest %in% c("IAH", "HOU"))
houston_base <- subset(flights, dest %in% c("IAH", "HOU"))

# Select rows with missing values using is.na() 
missing_dep_time_dplyr <- filter(flights, is.na(dep_time))
missing_dep_time_base <- subset(flights, is.na(dep_time))

Base R does not have the helper function between, but the same result can be achieved in a number of ways:

# Between

# These four commands all produce the same result

# dplyr
summer_dplyr <- filter(flights, between(month, 7, 9))

# base R
summer_base_01 <- subset(flights, month %in% c(7,8,9))
summer_base_02 <- subset(flights, month %in% 7:9)
summer_base_03 <- subset(flights, month >=7 & month <= 9)

When you have multiple options for performing a computation, the general 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.


Arranging (sorting)

The dplyr function arrange is analogous to base R selection using [ ] combined with function order. We use order as the row information to [ ]. The arguments to order are a comma separated sequence of the columns on which we wish to sort. We identify the columns using the $ operator, in the usual way.

For example, the dplyr statement and the base R statement below both sort the entire flight data frame on the year, month, and day columns:


# Sort using arrange or order

# dplyr
year_month_day_dplyr <- arrange(flights, year, month, day)

# base R – we omit the column index to get all columns in the result
year_month_day_base <- flights[order(flights$year, flights$month, flights$day), ] 

# Compare the results
year_month_day_dplyr
#> # A tibble: 336,776 × 19
#>     year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
#>    <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
#>  1  2013     1     1      517            515         2      830            819
#>  2  2013     1     1      533            529         4      850            830
#>  3  2013     1     1      542            540         2      923            850
#>  4  2013     1     1      544            545        -1     1004           1022
#>  5  2013     1     1      554            600        -6      812            837
#>  6  2013     1     1      554            558        -4      740            728
#>  7  2013     1     1      555            600        -5      913            854
#>  8  2013     1     1      557            600        -3      709            723
#>  9  2013     1     1      557            600        -3      838            846
#> 10  2013     1     1      558            600        -2      753            745
#> # … with 336,766 more rows, and 11 more variables: arr_delay <dbl>,
#> #   carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
#> #   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>
year_month_day_base
#> # A tibble: 336,776 × 19
#>     year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
#>    <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
#>  1  2013     1     1      517            515         2      830            819
#>  2  2013     1     1      533            529         4      850            830
#>  3  2013     1     1      542            540         2      923            850
#>  4  2013     1     1      544            545        -1     1004           1022
#>  5  2013     1     1      554            600        -6      812            837
#>  6  2013     1     1      554            558        -4      740            728
#>  7  2013     1     1      555            600        -5      913            854
#>  8  2013     1     1      557            600        -3      709            723
#>  9  2013     1     1      557            600        -3      838            846
#> 10  2013     1     1      558            600        -2      753            745
#> # … with 336,766 more rows, and 11 more variables: arr_delay <dbl>,
#> #   carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
#> #   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>

By default, order sorts in ascending order (i.e. from smallest to largest). To sort in descending order, place - (the negative sign; the hyphen) in front of an argument to order. We can again compare this operation in dplyr and base R:

# Descending sort

# dplyr
desc_dep_delay_dplyr <- arrange(flights, desc(dep_delay))

# base R
desc_dep_delay_base <- flights[order(-flights$dep_delay),]

# Check dplyr – the data frame is sorted in descending order of dep_delay
desc_dep_delay_dplyr
#> # A tibble: 336,776 × 19
#>     year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
#>    <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
#>  1  2013     1     9      641            900      1301     1242           1530
#>  2  2013     6    15     1432           1935      1137     1607           2120
#>  3  2013     1    10     1121           1635      1126     1239           1810
#>  4  2013     9    20     1139           1845      1014     1457           2210
#>  5  2013     7    22      845           1600      1005     1044           1815
#>  6  2013     4    10     1100           1900       960     1342           2211
#>  7  2013     3    17     2321            810       911      135           1020
#>  8  2013     6    27      959           1900       899     1236           2226
#>  9  2013     7    22     2257            759       898      121           1026
#> 10  2013    12     5      756           1700       896     1058           2020
#> # … with 336,766 more rows, and 11 more variables: arr_delay <dbl>,
#> #   carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
#> #   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>

# Check base – the data frame is sorted in descending order of dep_delay
desc_dep_delay_base
#> # A tibble: 336,776 × 19
#>     year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
#>    <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
#>  1  2013     1     9      641            900      1301     1242           1530
#>  2  2013     6    15     1432           1935      1137     1607           2120
#>  3  2013     1    10     1121           1635      1126     1239           1810
#>  4  2013     9    20     1139           1845      1014     1457           2210
#>  5  2013     7    22      845           1600      1005     1044           1815
#>  6  2013     4    10     1100           1900       960     1342           2211
#>  7  2013     3    17     2321            810       911      135           1020
#>  8  2013     6    27      959           1900       899     1236           2226
#>  9  2013     7    22     2257            759       898      121           1026
#> 10  2013    12     5      756           1700       896     1058           2020
#> # … with 336,766 more rows, and 11 more variables: arr_delay <dbl>,
#> #   carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
#> #   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>


Creating new columns

In dplyr we use function mutate to create new columns. In base R, we simply assign the new column directly to the data frame, using $. Each new column must be created in a separate statement. In the code below, we will compare the two techniques. In both approaches we will begin by making a copy of data frame flights, before we start to modify it. This is common practice so that you always have a clean copy of your original data.


# dplyr

# Make a copy
flights_dplyr <- flights

# Add new columns with mutate
flights_dplyr <- mutate(flights_dplyr, gain=dep_delay - arr_delay, speed = distance / air_time * 60)


# base R

# Make a copy
flights_base <- flights

# Add the new columns
attach(flights_base)
flights_base$gain <- dep_delay - arr_delay
flights_base$speed <- distance / air_time * 60

# Compare using base R selection
# Ask for columns gain and speed for rows 1 to 15
# They are the same
flights_dplyr[1:5, c("gain", "speed")]
#> # A tibble: 5 × 2
#>    gain speed
#>   <dbl> <dbl>
#> 1    -9  370.
#> 2   -16  374.
#> 3   -31  408.
#> 4    17  517.
#> 5    19  394.
flights_base[1:5, c("gain", "speed")]
#> # A tibble: 5 × 2
#>    gain speed
#>   <dbl> <dbl>
#> 1    -9  370.
#> 2   -16  374.
#> 3   -31  408.
#> 4    17  517.
#> 5    19  394.


Grouping and Summarising

With dplyr we take group summaries (e.g. getting the average arrival for all flights in each month) by using group_by to group the data frame (gather the rows together by month) and summarise to apply the summary function (take the average for each month). In base R both of these steps are handled by the single function aggregate. This function takes four arguments:

Arg name Meaning
x The name of the data frame
by A list of columns to group by
FUN The name of the summary function to apply
na.rm Set to TRUE is you want to ignore missing values

The only new part is the syntax used to declare a list for argument by. We will first look at an example of how to take group means in both dplyr and base R, and then discuss the list in more detail.

# Compute the average arrival delay, collapsed across months

# Using dplyr

# Group by month
by_month <- group_by(flights, month)

# Take the means
mean_delay_by_month_dplyr <- summarise(by_month, MeanDelay = mean(arr_delay, na.rm = TRUE))

# Check the output
mean_delay_by_month_dplyr
#> # A tibble: 12 × 2
#>    month MeanDelay
#>    <int>     <dbl>
#>  1     1     6.13 
#>  2     2     5.61 
#>  3     3     5.81 
#>  4     4    11.2  
#>  5     5     3.52 
#>  6     6    16.5  
#>  7     7    16.7  
#>  8     8     6.04 
#>  9     9    -4.02 
#> 10    10    -0.167
#> 11    11     0.461
#> 12    12    14.9



# Using base R function aggregate
mean_delay_by_month_base <- aggregate(x = flights$arr_delay, 
                                      by = list(Month = flights$month),
                                      FUN = mean,
                                      na.rm = TRUE)


# Check the output
mean_delay_by_month_base
#>    Month          x
#> 1      1  6.1299720
#> 2      2  5.6130194
#> 3      3  5.8075765
#> 4      4 11.1760630
#> 5      5  3.5215088
#> 6      6 16.4813296
#> 7      7 16.7113067
#> 8      8  6.0406524
#> 9      9 -4.0183636
#> 10    10 -0.1670627
#> 11    11  0.4613474
#> 12    12 14.8703553

Use function list to create the value for argument by . This function is like the combine function for vectors, except it creates a collection of named elements. We often see the function in situations like this:

# A list is a collection of named elements
pet_data <- list(PetName = "Snoopy", PetOwner = "Charlie Brown", PetBreed = "Beagle")
pet_data
#> $PetName
#> [1] "Snoopy"
#> 
#> $PetOwner
#> [1] "Charlie Brown"
#> 
#> $PetBreed
#> [1] "Beagle"

When using aggregate you create a list of columns that you want to group by. The names of the columns will be the column headers for the output table of summarised results. To group by multiple columns, add more elements to the list. For example, if we wanted the average delay by month for each origin airport separately we would say:

# Compute the average arrival delay, collapsed across months, separately for
# each origin airport. There are 3 airports and 12 months, so we expect to 
# get 36 means.

# Using dplyr

# Group by month and origin
by_month_origin <- group_by(flights, month, origin)

# Take the means
mean_month_origin_dplyr <- summarise(by_month_origin, MeanDelay = mean(arr_delay, na.rm = TRUE))
#> `summarise()` has grouped output by 'month'. You can override using the
#> `.groups` argument.

# Check the output
mean_month_origin_dplyr
#> # A tibble: 36 × 3
#> # Groups:   month [12]
#>    month origin MeanDelay
#>    <int> <chr>      <dbl>
#>  1     1 EWR        12.8 
#>  2     1 JFK         1.37
#>  3     1 LGA         3.38
#>  4     2 EWR         8.78
#>  5     2 JFK         4.39
#>  6     2 LGA         3.15
#>  7     3 EWR        10.6 
#>  8     3 JFK         2.58
#>  9     3 LGA         3.74
#> 10     4 EWR        14.1 
#> # … with 26 more rows



# Using base R function aggregate
mean_month_origin_base <- aggregate(x = flights$arr_delay, 
                                      by = list(Month = flights$month, Origin = flights$origin),
                                      FUN = mean,
                                      na.rm = TRUE)


# Check the output. Note that dplyr and base R sort the output in different orders
mean_month_origin_base
#>    Month Origin          x
#> 1      1    EWR 12.8165557
#> 2      2    EWR  8.7751603
#> 3      3    EWR 10.6007988
#> 4      4    EWR 14.1433877
#> 5      5    EWR  5.3819276
#> 6      6    EWR 16.8635990
#> 7      7    EWR 15.4602015
#> 8      8    EWR  6.7123423
#> 9      9    EWR -4.7299722
#> 10    10    EWR  2.6047372
#> 11    11    EWR  0.6724982
#> 12    12    EWR 19.6397450
#> 13     1    JFK  1.3683977
#> 14     2    JFK  4.3910328
#> 15     3    JFK  2.5808150
#> 16     4    JFK  7.0115389
#> 17     5    JFK  2.1229773
#> 18     6    JFK 17.5969288
#> 19     7    JFK 20.1902224
#> 20     8    JFK  5.9108409
#> 21     9    JFK -4.4630178
#> 22    10    JFK -3.5859719
#> 23    11    JFK -0.8728745
#> 24    12    JFK 12.6775748
#> 25     1    LGA  3.3824023
#> 26     2    LGA  3.1473894
#> 27     3    LGA  3.7384982
#> 28     4    LGA 12.0385817
#> 29     5    LGA  2.7963764
#> 30     6    LGA 14.7692779
#> 31     7    LGA 14.1815696
#> 32     8    LGA  5.4078014
#> 33     9    LGA -2.8253950
#> 34    10    LGA  0.1864229
#> 35    11    LGA  1.5511865
#> 36    12    LGA 11.9563716


Workflows and data pipelines

Traditionally data analysis workflows in R have consisted of either many nested operations, or the use of assigning intermediate steps to variables. One of the key differences in approach between the Tidyverse and base R (until very recently with R v4.1+) is the idea of ‘pipes’ which allow us to ‘chain’ operations together, with the key benefit being readability of code. When reading code, it can be useful to read the pipe as the word “then”.


Pipes

The pipe function from magrittr which is part of the Tidyverse, enables the creation of ‘pipelines’ or chaining together of functions as opposed to nesting. The pipe function (%>% shortcut Ctrl + Shift + M - on a Mac use Cmd instead of Ctrl) takes the output of the function and uses it as the first argument for the next function. When you read %>% in code you can think of it as the word “then”.

For instance, if we call the name of our data set by itself, it will put the results onto the screen, however if we ‘pipe’ it to another function it gets used as the input for that function instead.

flights
#> # A tibble: 336,776 × 19
#>     year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
#>    <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
#>  1  2013     1     1      517            515         2      830            819
#>  2  2013     1     1      533            529         4      850            830
#>  3  2013     1     1      542            540         2      923            850
#>  4  2013     1     1      544            545        -1     1004           1022
#>  5  2013     1     1      554            600        -6      812            837
#>  6  2013     1     1      554            558        -4      740            728
#>  7  2013     1     1      555            600        -5      913            854
#>  8  2013     1     1      557            600        -3      709            723
#>  9  2013     1     1      557            600        -3      838            846
#> 10  2013     1     1      558            600        -2      753            745
#> # … with 336,766 more rows, and 11 more variables: arr_delay <dbl>,
#> #   carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
#> #   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>


flights %>% head()
#> # A tibble: 6 × 19
#>    year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
#>   <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
#> 1  2013     1     1      517            515         2      830            819
#> 2  2013     1     1      533            529         4      850            830
#> 3  2013     1     1      542            540         2      923            850
#> 4  2013     1     1      544            545        -1     1004           1022
#> 5  2013     1     1      554            600        -6      812            837
#> 6  2013     1     1      554            558        -4      740            728
#> # … with 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
#> #   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
#> #   hour <dbl>, minute <dbl>, time_hour <dttm>

This works for functions that expect the first argument to be the data. We can also be explicit about which argument we would like the input from the pipe to occupy. We can use . to represent this

flights %>% head(n = 10, x = .)
#> # A tibble: 10 × 19
#>     year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
#>    <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
#>  1  2013     1     1      517            515         2      830            819
#>  2  2013     1     1      533            529         4      850            830
#>  3  2013     1     1      542            540         2      923            850
#>  4  2013     1     1      544            545        -1     1004           1022
#>  5  2013     1     1      554            600        -6      812            837
#>  6  2013     1     1      554            558        -4      740            728
#>  7  2013     1     1      555            600        -5      913            854
#>  8  2013     1     1      557            600        -3      709            723
#>  9  2013     1     1      557            600        -3      838            846
#> 10  2013     1     1      558            600        -2      753            745
#> # … with 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
#> #   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
#> #   hour <dbl>, minute <dbl>, time_hour <dttm>


We can use the %>% to chain multiple functions together. Here we’ll look at the workflow of calculating the mean airtime of flights leaving JFK or LGA for each month with the resulting mean airtime sorted from longest to shortest flight time.

# base R with intermediates

# Subset the data
flights_jfk_lga <- subset(flights, origin == "JFK" | origin == "LGA", select = c("month", "origin","air_time"))

# calculate the mean air time for each month/origin grouping
flight_results <- aggregate(x = flights_jfk_lga$air_time, 
          by = list(month = flights_jfk_lga$month, origin = flights_jfk_lga$origin),
          FUN = mean,
          na.rm = TRUE)

# rename the result column
names(flight_results)[which(names(flight_results) == "x")] <- "mean_air_time"

# sort the results
flight_results_base <- flight_results[order(flight_results$mean_air_time, decreasing = TRUE),]

# show top 6 results
head(flight_results_base)
#>    month origin mean_air_time
#> 12    12    JFK      191.4167
#> 11    11    JFK      185.1466
#> 4      4    JFK      182.2326
#> 1      1    JFK      181.1520
#> 10    10    JFK      179.0988
#> 3      3    JFK      178.4356
# dplyr using pipes

flight_results_dplyr <- flights %>% 
  # subset the data
  select(month, origin, air_time) %>% 
  filter(origin == "JFK" | origin == "LGA") %>%
  # calculate the mean air time for each month/origin grouping
  group_by(month, origin) %>% 
  summarise(mean_air_time = mean(air_time, na.rm = TRUE)) %>% 
  # sort the results
  arrange(desc(mean_air_time))
#> `summarise()` has grouped output by 'month'. You can override using the
#> `.groups` argument.

# show top 6 results
head(flight_results_dplyr)
#> # A tibble: 6 × 3
#> # Groups:   month [6]
#>   month origin mean_air_time
#>   <int> <chr>          <dbl>
#> 1    12 JFK             191.
#> 2    11 JFK             185.
#> 3     4 JFK             182.
#> 4     1 JFK             181.
#> 5    10 JFK             179.
#> 6     3 JFK             178.

One of the nice features of dealing with pipes, is that you can do your subsetting workflow and pipe directly into ggplot, although it’s usually a good idea to assign your subsetted data and then use that to start your plotting pipeline. If you pipe your data into ggplot RStudio will also let you auto-complete your columns with Tab.

library(ggplot2)

flights %>% 
  # subset the data
  select(month, origin, air_time) %>% 
  filter(origin == "JFK" | origin == "LGA") %>%
  # plot the data
  ggplot(aes(x = origin, y = air_time)) + geom_boxplot()
#> Warning: Removed 5722 rows containing non-finite values (stat_boxplot).



Conclusion

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

Fill in the module feedback form https://tinyurl.com/r4ssp-module-fb.

You may recall that way back in the first module of this mini-course 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. If you have programmed before in Java or one of the C-family of languages, you may expect the first row to be row 0, not row 1, and the first column to be column 0, not column 1. Just let go of that. In R, row and column numbering starts at 1. Different languages, different rules.↩︎

LS0tCnRpdGxlOiAiU3Vic2V0dGluZyIKZGF0ZTogIlNlbWVzdGVyIDIsIDIwMjIiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRvY19kZXB0aDogMwogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93Ci0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkoa25pdHIpCgprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgY29tbWVudCA9ICIjPiIsCiAgZmlnLnBhdGggPSAiZmlndXJlcy8wMy8iLCAjIHVzZSBvbmx5IGZvciBzaW5nbGUgUm1kIGZpbGVzCiAgY29sbGFwc2UgPSBUUlVFLAogIGVjaG8gPSBUUlVFCikKYGBgCgoKCj4gIyMjIyBBc3NvY2lhdGVkIE1hdGVyaWFsCj4KPiBab29tIG5vdGVzOiBbWm9vbSBOb3RlcyAwMyAtIFNlbGVjdGluZyBhbmQgRmlsdGVyaW5nIERhdGFdKHpvb21fbm90ZXNfMDMuaHRtbCkKPgo+IFJlYWRpbmc6Cj4KPiAtIFtSIGZvciBEYXRhIFNjaWVuY2UgLSBDaGFwdGVyIDVdKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovdHJhbnNmb3JtLmh0bWwpCgpcCgojIyBJbnRyb2R1Y3Rpb24KCklmIHlvdSBhcmUgd29ya2luZyB0aHJvdWdoIHRoZSBzdWdnZXN0ZWQgbWF0ZXJpYWxzIGluIG9yZGVyLCB5b3UgaGF2ZSBqdXN0IGNvbXBsZXRlZCBbKipDaGFwdGVyIDUgLSBEYXRhIFRyYW5zZm9ybWF0aW9uIChodHRwczovL3I0ZHMuaGFkLmNvLm56L3RyYW5zZm9ybS5odG1sKSoqXShodHRwczovL3I0ZHMuaGFkLmNvLm56L3RyYW5zZm9ybS5odG1sKSBmcm9tIHRoZSBvbmxpbmUgdGV4dCAqUiBmb3IgRGF0YSBTY2llbmNlKi4gVGhpcyBtYXRlcmlhbCBkZW1vbnN0cmF0ZWQgaG93IHRvIHVzZSB0aGUgbGlicmFyeSAqKmRwbHlyKiosIG9uZSBvZiB0aGUgbGlicmFyaWVzIGluIHRoZSAqKnRpZHl2ZXJzZSoqIGZhbWlseS4gWW91IHdpbGwgaGF2ZSBsZWFybmVkIGhvdyB0byB1c2UgdGhlIGZpdmUgY29yZSB0cmFuc2Zvcm1hdGlvbiBmdW5jdGlvbnMgLS0gYGZpbHRlcmAsIGBhcnJhbmdlYCwgYHNlbGVjdGAsIGBtdXRhdGVgIGFuZCBgc3VtbWFyaXNlYCAod2l0aCBpdHMgaGVscGVyIGZ1bmN0aW9uIGBncm91cF9ieWApLiBUaGVzZSBmdW5jdGlvbnMgYWxsb3cgeW91IHRvIG1vZGlmeSBhbmQgcGVyZm9ybSBzdW1tYXJpZXMgb24gZGF0YSBmcmFtZXMsIGFuZCB0byBwdWxsIG91dCBzcGVjaWZpYyBwb3J0aW9ucyBvZiBkYXRhIGZyYW1lcyBmb3IgZGV0YWlsZWQgYW5hbHlzaXMuIExpYnJhcnkgYGRwbHlyYCBpcyB3aWRlbHkgdXNlZCwgYW5kIHlvdSB3aWxsIHNlZSBtYW55IGV4YW1wbGVzIG9mIGl0IGluIFIgY29kZSB5b3UgZmluZCBpbiB0aGUgd2lsZC4KClRoZSBmdW5jdGlvbnMgaW4gYGRwbHlyYCAoYW5kIGluIGFsbCB0aGUgb3RoZXIgbGlicmFyaWVzIGluIHRoZSB0aWR5dmVyc2UpIGFyZSB0ZWNobmljYWxseSAqKndyYXBwZXJzKiogYXJvdW5kIGJhc2UgUiBjb2RlLiBUaGF0IGlzLCB0aGV5IHRoZW1zZWx2ZXMgYXJlIHdyaXR0ZW4gdXNpbmcgYmFzZSBSIGNvbW1hbmRzLiBUaHVzIGl0IGlzIHBvc3NpYmxlIHRvIHBlcmZvcm0gYWxsIHRoZSBzYW1lIHRyYW5zZm9ybWF0aW9ucyAqd2l0aG91dCogYGRwbHlyYCwgYnkgdXNpbmcgb25seSBiYXNlIFIuIE1hbnkgcHJvZ3JhbW1lcnMgYW5kIHJlc2VhcmNoZXJzIChpbmNsdWRpbmcgc29tZSBvZiB5b3VyIGxlY3R1cmVycykgcHJlZmVyIHRvIHVzZSBiYXNlIFIgZm9yIHRoZXNlIG9wZXJhdGlvbnMsIGFuZCB5b3Ugd2lsbCBhbHNvIHNlZSBpdCBvZnRlbiBpbiBSIGNvZGUgaW4gdGhlIHdpbGQuIFRoZXJlZm9yZSwgaW4gdGhpcyBzdXBwbGVtZW50YXJ5IGhhbmRvdXQsIHdlIHdpbGwgaWxsdXN0cmF0ZSB0aGUgZXF1aXZhbGVudCBiYXNlIFIgc3ludGF4IGZvciB0aGUgYGRwbHlyYCBmdW5jdGlvbnMgeW91IGp1c3QgbGVhcm5lZC4KClBlb3BsZSBtYWtlIHRoZSBjaG9pY2UgYmV0d2VlbiBgZHBseXJgIGFuZCBiYXNlIFIgZm9yIHNldmVyYWwgcmVhc29ucy4gTWFueSBwZW9wbGUgZmluZCBgZHBseXJgIHN5bnRheCBlYXNpZXIgdG8gdXNlLCBiZWNhdXNlIGl0IGlzIG1vcmUgKip1bmlmb3JtKiouIFRoYXQgaXMsIGFsbCB0aGUgYmlnIGZpdmUgYGRwbHlyYCB0cmFuc2Zvcm1hdGlvbiBmdW5jdGlvbnMgdXNlIGFwcHJveGltYXRlbHkgdGhlIHNhbWUgc3ludGF4LiBJbiBiYXNlIFIsIHRoZXJlIGlzIG1vcmUgdmFyaWF0aW9uLiBTY2llbnRpc3RzIHdobyB3b3JrIHdpdGggdmVyeSBsYXJnZSBkYXRhIHNldHMgYXJlIG9mdGVuIGNvbmNlcm5lZCBhYm91dCBob3cgZmFzdCB0aGVpciBjb2RlIGNhbiBiZSBleGVjdXRlZC4gSW4gc29tZSBjYXNlcywgYGRwbHlyYCBleGVjdXRlcyBtb3JlIHNsb3dseSB0aGFuIGJhc2UgUiAoYmVjYXVzZSBvZiB0aGUgZXh0cmEgY29kZSByZXF1aXJlZCBmb3IgdGhlIHdyYXBwaW5nKSwgbGVhZGluZyB0aGVzZSByZXNlYXJjaGVycyB0byBwcmVmZXIgdGhlIGJhc2UgUiBhcHByb2FjaC4gQmVjYXVzZSBgZHBseXJgIGlzIGEgcmVsYXRpdmVseSBuZXcgYWRkaXRpb24gdG8gUiwgc29tZSBwZW9wbGUgcHJlZmVyIGJhc2UgUiBiZWNhdXNlIHRoZXkgbGVhcm5lZCBpdCBmaXJzdCwgYW5kIGFyZSBoYXBweSB0byBjb250aW51ZSB1c2luZyBpdC4KClVubGVzcyB5b3UgYXJlIHJlcXVpcmVkIHRvIHVzZSBhIHBhcnRpY3VsYXIgYXBwcm9hY2ggKGNoZWNrIHdpdGggeW91ciBsZWN0dXJlciBpZiB5b3UgYXJlIHVuc3VyZSksIHlvdSBjYW4gY2hvb3NlIHdoaWNoZXZlciBzZXQgb2YgY29tbWFuZHMgeW91IGxpa2UgdXNpbmcuIFlvdSBjYW4gZXZlbiBtaXggYW5kIG1hdGNoIHRoZW0gLS0gdGhleSBnaXZlIHRoZSBzYW1lIHJlc3VsdHMsIGFuZCBSIGRvZXNuJ3QgY2FyZS4gSG93ZXZlciwgaXQgaXMgdmVyeSBpbXBvcnRhbnQgdGhhdCB5b3UgY2FuICp1bmRlcnN0YW5kKiBib3RoIHN0eWxlcy4gT25lIG9mIHRoZSBncmVhdCBiZW5lZml0cyBvZiB0aGUgUiBlY29zeXN0ZW0gaXMgdGhlIHdpZGUgc2hhcmluZyBvZiBjb2RlLCBhbmQgeW91IGNhbid0IGZ1bGx5IHBhcnRpY2lwYXRlIGluIHRoaXMgdW5sZXNzIHlvdSBhcmUgY29tZm9ydGFibGUgd2l0aCBhbGwgdGhlIG1ham9yIGRpYWxlY3RzLgoKXAoKIyMgU3Vic2V0dGluZwoKT2Z0ZW4gd2hlbiB3ZSdyZSBkZWFsaW5nIHdpdGggZGF0YSB3ZSB3YW50IHRvIGJlIGFibGUgdG8gcHVsbCBvdXQgYW5kIG9wZXJhdGUgb24gc3Vic2V0cyBvZiBpdC4gVGhlcmUgYXJlIG1hbnkgZGlmZmVyZW50IG1ldGhvZHMgdGhhdCBjYW4gYmUgdXNlZCB0byBzdWJzZXQgZGF0YSwgYW5kIHdlJ2xsIGNvdmVyIGEgY291cGxlIG9mIGRpZmZlcmVudCBtZXRob2RzLiBPbmUgb2YgdGhlIG1vc3QgY29tbW9uIG1ldGhvZHMgaXMgdG8gdXNlIHRoZSAiZXh0cmFjdCIgZnVuY3Rpb24gYFtdYC4gCgpUaGVyZSBhcmUgdHdvIG1haW4gd2F5cyBhcHByb2FjaGVzIHRvIHN1Yi1zZXR0aW5nOiBiYXNlZCBvbiBhbiBpZGVudGlmaWVyIHN1Y2ggYXMgcG9zaXRpb24gb3IgbmFtZSwgb3IgYmFzZWQgb24gYSBjb25kaXRpb24uIEFuZCBmb3IgcmVjdGFuZ3VsYXIgdHdvLWRpbWVuc2lvbmFsIG9iamVjdHMgbGlrZSBkYXRhIGZyYW1lcyB3ZSBhbHNvIHRoaW5rIGFib3V0IGlmIHdlJ3JlIG9wZXJhdGluZyBvbiByb3dzIG9yIGNvbHVtbnMuCgojIyMgU3Vic2V0dGluZyBieSBwb3NpdGlvbiAoaW5kZXgpCgpWZWN0b3JzIGFyZSBtYWRlIHVwIG9mIGl0ZW1zLCBhbmQgZWFjaCBpdGVtIGhhcyBhIHBvc2l0aW9uYWwgaW5kZXggKHN0YXJ0aW5nIGZyb20gMSAtIG90aGVyIGxhbmd1YWdlcyBkaWZmZXIpLiBXZSBjYW4gdXNlIHRoaXMgaW5kZXggYXMgYW4gYXJndW1lbnQgdG8gYFtdYCB0byBwdWxsIG91dCBhbmQgcmV0dXJuIGEgbmV3IHZlY3RvciBvZiB0aGUgc3BlY2lmaWVkIGl0ZW0uIEEgbmVnYXRpdmUgb2YgdGhlIGluZGV4IHdpbGwgcmV0dXJuIGEgY29weSBvZiB0aGUgb3JpZ2luYWwgYnV0IHdpdGggdGhlIGl0ZW0gYXQgdGhlIGdpdmVuIHBvc2l0aW9uIHJlbW92ZWQuCgpgYGB7cn0KIyBhIG51bWVyaWMgdmVjdG9yCnNvbWVfbnVtYmVycyA8LSBjKDIsIDQ1LCAtOSwgNikKCiMgcHVsbCBvdXQgdGhlIHNlY29uZCBpdGVtCnNvbWVfbnVtYmVyc1syXQoKIyByZW1vdmUgdGhlIGZpcnN0IGl0ZW0Kc29tZV9udW1iZXJzWy0xXQpgYGAKCklmIHdlIHdhbnQgbXVsdGlwbGUgaXRlbXMgd2Ugc3VwcGx5IGEgdmVjdG9yIG9mIG51bWJlcnMgZm9yIHRoZSBpbmRleGVzIHdlIHdhbnQuIFRoZSBvcmRlciBvZiB0aGUgc3VwcGxpZWQgaW5kZXhlcyBpcyB0aGUgb3JkZXIgaW4gd2hpY2ggdGhlIHJlc3VsdGFudCB2ZWN0b3Igd2lsbCBiZSBjcmVhdGVkIC0gaXQgY2FuIGFsc28gYmUgdXNlZCB0byBkdXBsaWNhdGUgaXRlbXMuCgoKYGBge3J9CnNvbWVfbGV0dGVycyA8LSBjKCJsIiwgIm8iLCAiaCIsICJlIikKCiMgcHVsbCBvdXQgaXRlbXMgMSBhbmQgMwpzb21lX2xldHRlcnNbYygxLDMpXQoKIyByZW9yZGVyIGFuZCBkdXBsaWNhdGUKc29tZV9sZXR0ZXJzW2MoMyw0LDEsMSwyKV0KYGBgCgpJbmRpY2VzIGFyZSBwb3NpdGlvbmFsLCBidXQgd2UgY291bGQgYWxzbyBzdXBwbHkgYSBib29sZWFuIHZlY3RvciB3aXRoIHRoZSBgVFJVRWAgaW4gdGhlIHBvc2l0aW9ucyBmb3IgaXRlbXMgd2Ugd291bGQgbGlrZSB0byBrZWVwIGFuZCBgRkFMU0VgIGZvciBpdGVtcyB3ZSB3b3VsZCBsaWtlIHRvIGRyb3AuIFRoZSBib29sZWFuIHZlY3RvciBjYW4gZWl0aGVyIG1hdGNoIGluIGxlbmd0aCBvciBiZSBhIGZhY3RvciBvZiB0aGUgdmVjdG9yIGxlbmd0aCAoaW4gd2hpY2ggY2FzZSBpdCBnZXRzICdyZWN5Y2xlZCcgdW50aWwgaXQgbWF0Y2hlcyB0aGUgbGVuZ3RoKQoKYGBge3J9CnNvbWVfbnVtYmVycwoKIyBtYXRjaGluZyBsZW5ndGggCnNvbWVfbnVtYmVyc1tjKFRSVUUsIFRSVUUsIEZBTFNFLCBGQUxTRSldCgojIHRha2UgZXZlcnkgc2Vjb25kIGl0ZW0Kc29tZV9udW1iZXJzW2MoRkFMU0UsIFRSVUUpXQpgYGAKClwKCiMjIyBTdWJzZXR0aW5nIGJ5IGNvbmRpdGlvbgoKT2Z0ZW4gdGhvdWdoLCB3ZSBkb24ndCB3YW50IHRvIGhhdmUgdG8gaWRlbnRpZnkgYW5kIGtlZXAgdHJhY2sgb2YgdGhlIGluZGljZXMgZm9yIGl0ZW1zIGluIG91ciBkYXRhLCBidXQgaW5zdGVhZCB3ZSB3YW50IHRvIHN1YnNldCBvdXIgZGF0YSB0byBpdGVtcyB0aGF0IG1hdGNoIGNlcnRhaW4gY29uZGl0aW9ucy4KClNpbWlsYXIgdG8gaG93IHdlIGNhbiBvcGVyYXRlIG9uIGFuIGVudGlyZSB2ZWN0b3IgdGhyb3VnaCB0aGUgYXJpdGhtZXRpYyBvcGVyYXRvcnMsIHRoZXJlIGFyZSBhbHNvIG9wZXJhdG9ycyBmb3IgcGVyZm9ybWluZyBjb21wYXJpc29ucy4KCnwgT3BlcmF0aW9uICAgICAgICAgICAgICAgIHwgUiBTeW1ib2wgfAp8Oi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfDotLS0tLS0tLS0tOnwKfCBMZXNzIHRoYW4gICAgICAgICAgICAgICAgfCBcPCAgICAgICB8CnwgTGVzcyB0aGFuIG9yIGVxdWFsIHRvICAgIHwgXDw9ICAgICAgfAp8IEdyZWF0ZXIgdGhhbiAgICAgICAgICAgICB8IFw+ICAgICAgIHwKfCBHcmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gfCBcPj0gICAgICB8CnwgTm90IGVxdWFsIHRvICAgICAgICAgICAgIHwgIT0gICAgICAgfAoKV2hlbiB3ZSBhcHBseSBjb21wYXJpc29ucyB0byBhIHZlY3RvciB3ZSBnZXQgaW4gcmV0dXJuIGEgdmVjdG9yIHdpdGggYm9vbGVhbiB2YWx1ZXMgKGBUUlVFYC9gRkFMU0VgKSBjb3JyZXNwb25kaW5nIGFuIGl0ZW0td2lzZSBjb21wYXJpc29uLgoKYGBge3J9CnNvbWVfbnVtYmVycyA8IDE1CmBgYAoKQW5kIHRoZXNlIGJvb2xlYW4gdmVjdG9ycyBhcmUgdXNlZCBmb3Igc3ViLXNldHRpbmcuIFNvIHdlIGNhbiBpbiBmYWN0IHN1cHBseSBvdXIgY29uZGl0aW9uYWwgc3RhdGVtZW50IGFzIHRoZSBhcmd1bWVudCB0byBgW11gIHNvIGtlZXAgYWxsIHRoZSBpdGVtcyB0aGF0IG1lZXQgb3VyIGNvbmRpdGlvbgoKYGBge3J9CiMga2VlcCBudW1iZXJzIGxlc3MgdGhhbiAxNQpzb21lX251bWJlcnNbc29tZV9udW1iZXJzIDwgMTVdCmBgYAoKT25lIGZpbmFsIGNvbXBhcmlzb24gZnVuY3Rpb24gaXMgYCVpbiVgLCB3aGljaCBsZXRzIHVzIGNvbXBhcmUgdHdvIHZlY3RvcnMgZm9yIG1hdGNoaW5nIGl0ZW1zLiBgJWluJWAgd2lsbCByZXR1cm4gYSBib29sZWFuIHZlY3RvciBjb3JyZXNwb25kaW5nIHRvIHRoZSBpdGVtcyBvbiB0aGUgbGVmdCBoYW5kIHNpZGUgdGhhdCB3ZXJlIGFsc28gZm91bmQgImluIiB0aGUgcmlnaHQgaGFuZCBzaWRlLiBUaGlzIG9wZXJhdG9yIGlzIGV4dHJlbWVseSBoZWxwZnVsIHRvIHVzZSBpbnN0ZWFkIG9mIGNvbWJpbmluZyBtdWx0aXBsZSAnb3InIChgfGApIGNvbmRpdGlvbnMuCgpgYGB7cn0KbXlfcGV0cyA8LSBjKCJkb2ciLCAiY2F0IiwgInR1cnRsZSIpCgojIHVzaW5nICdvcicKbXlfcGV0c1sgbXlfcGV0cyA9PSAiZnJvZyIgfCBteV9wZXRzID09ICJkb2ciIHwgbXlfcGV0cyA9PSAicmFiYml0IiB8IG15X3BldHMgPT0gImhvcnNlIl0KCgojIHVzZSBvZiAlaW4lCm15X3BldHMgJWluJSBjKCJmcm9nIiwgImRvZyIsICJyYWJiaXQiLCAiaG9yc2UiKQoKbXlfcGV0c1tteV9wZXRzICVpbiUgYygiZnJvZyIsICJkb2ciLCAicmFiYml0IildCmBgYAoKXAoKIyMjIyBNaXNzaW5nIGRhdGEKCk9uZSBleHRyZW1lbHkgY29tbW9uIHN1YnNldHRpbmcgb3BlcmF0aW9uIGlzIGRlYWxpbmcgd2l0aCBtaXNzaW5nIGRhdGEuIE1pc3NpbmcgZGF0YSBpbiBSIGlzIHJlcHJlc2VudGVkIGJ5IGBOQWAuIGBOQWAgaW4gUiBpcyBhIHNwZWNpYWwgZGF0YSB0eXBlIGFuZCB0aGUgc2V0IG9mIGNvbXBhcmF0b3Igb3BlcmF0aW9ucyB0aGF0IHdlIGhhdmUgY292ZXJlZCB3aWxsIGFsd2F5cyByZXR1cm4gYE5BYCAoZXZlbiBgTkEgPT0gTkFgIHdpbGwgcmV0dXJuIGBOQWApIHNvIGluc3RlYWQgdGhlcmUgaXMgYSBzcGVjaWFsIGZ1bmN0aW9uIHRoYXQgaXMgdXNlZCB0byB0ZWxsIHVzIHdoZW4gd2UgaGF2ZSBtaXNzaW5nIGRhdGEgc28gd2UgY2FuIGhhbmRsZSBpdCBhcHByb3ByaWF0ZWx5IGFuZCB0aGF0IGZ1bmN0aW9uIGlzIGBpcy5uYWAgd2hpY2ggd2lsbCByZXR1cm4gYFRSVUVgIGlzIHNvbWV0aGluZyBpcyBgTkFgIGFuZCBgRkFMU0VgIGluIGFsbCBvdGhlciBpbnN0YW5jZXMuCgpgYGB7cn0KTkEgPCA2CgpOQSA9PSAiYSIKCk5BICE9IFRSVUUKCk5BID09IE5BCgppcy5uYShOQSkKYGBgCgoKU29tZSBmdW5jdGlvbnMgY2FuIGRlYWwgd2l0aCBtaXNzaW5nIGRhdGEgYXMgcGFydCBvZiB0aGUgZnVuY3Rpb24gYnkgc2V0dGluZyB0aGUgcGFyYW1ldGVyIGBuYS5ybSA9IFRSVUVgLCBidXQgbm90IGFsbCBmdW5jdGlvbnMgaGF2ZSB0aGlzLgoKYGBge3J9Cm1pc3NpbmdfZXhhbXBsZSA8LSBjKE5BLCAxLCA0LCA2LCBOQSwgOCkKCm1lYW4obWlzc2luZ19leGFtcGxlKQoKbWVhbihtaXNzaW5nX2V4YW1wbGUsIG5hLnJtID0gVFJVRSkKYGBgCgpUbyByZW1vdmUgbWlzc2luZyBkYXRhIHNvIGl0IGNhbiBiZSB1c2VkIHdpdGggZnVuY3Rpb25zIHdpdGggYW4gYG5hLnJtYCBwYXJhbWV0ZXIgd2UgY2FuIHVzZSBgaXMubmFgIHRvIGlkZW50aWZ5IHRoZSBgTkFgIHZhbHVlcyBhbmQgdGhlbiBjb25kaXRpb25hbGx5IHN1YnNldDoKCmBgYHtyfQptaXNzaW5nX2V4YW1wbGUKCmlzLm5hKG1pc3NpbmdfZXhhbXBsZSkKCm1pc3NpbmdfZXhhbXBsZVshaXMubmEobWlzc2luZ19leGFtcGxlKV0KYGBgCgpSZW1lbWJlciBgaXMubmFgIHdpbGwgYmUgYFRSVUVgIHdoZW4gdGhlcmUgaXMgYE5BYCwgc28gd2UgY2FuIHVzZSB0aGUgYCFgIChub3QpIG9wZXJhdG9yIHRvIGludmVydCB0aGUgbG9naWMuCgpcCgpcCgojIyBTdWJzZXR0aW5nIGluIDItZGltZW5zaW9ucwoKV2UgY2FuIHRha2UgdGhlIHNhbWUgcHJpbmNpcGxlcyB3ZSBjb3ZlcmVkIHVzaW5nIGBbXWAgb24gdmVjdG9ycyBhbmQgYXBwbHkgdGhlbSBvbiByZWN0YW5ndWxhciAyLWRpbWVuc2lvbmFsIHN0cnVjdHVyZXMgbGlrZSB0aGUgZGF0YS5mcmFtZS4gQWRkaW5nIGEgc2Vjb25kIGRpbWVuc2lvbiBtZWFucyB3ZSBub3cgbmVlZCB0byBzdXBwbHkgMiBhcmd1bWVudHMgdG8gYFtdYCwgdGhlIGZpcnN0IGFyZ3VtZW50IGlzIGZvciByb3dzLCBhbmQgdGhlIHNlY29uZCBpcyBmb3IgY29sdW1ucy4KClRoZSBnZW5lcmFsIHN5bnRheCBpczoKCipuYW1lX29mX2RhdGFfZnJhbWVbcm93X2luZm9ybWF0aW9uLCBjb2x1bW5faW5mb3JtYXRpb25dKgoKVGhlcmUgYXJlIGEgdmFyaWV0eSBvZiB3YXlzIHRvIGV4cHJlc3Mgcm93IGFuZCBjb2x1bW4gaW5mb3JtYXRpb24uIFRvIHNlZSBob3cgdGhleSB3b3JrLCBsZXQncyBmaXJzdCBtYWtlIGEgdmVyeSBzaW1wbGUgZGF0YSBmcmFtZSBieSBoYW5kLCBhbmQgdGhlbiBwZXJmb3JtIHNvbWUgc3ViLXNldHRpbmcgb3BlcmF0aW9ucyBvbiBpdC4gRW50ZXIgdGhlIGZvbGxvd2luZyBjb2RlIGludG8gUlN0dWRpbyB0byBjcmVhdGUgKipnZW9ncmFwaHlfZGYqKi4KCmBgYHtyIG1hbnVhbCBkYXRhIDF9CmNvdW50cmllcyA8LSBjKCJBdXN0cmlhIiwgIkJyYXppbCIsICJDYW5hZGEiLCAiRGVubWFyayIpCmNhcGl0YWxzIDwtIGMoIlZpZW5uYSIsICJCcmFzaWxpYSIsICJPdHRhd2EiLCAiQ29wZW5oYWdlbiIpCnBvcHVsYXRpb25faW5fbWlsbGlvbnMgPC0gYyg5LCAyMTEsIDM4LCA2KQoKZ2VvZ3JhcGh5X2RmIDwtIGRhdGEuZnJhbWUoQ291bnRyeSA9IGNvdW50cmllcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgQ2FwaXRhbCA9IGNhcGl0YWxzLAogICAgICAgICAgICAgICAgICAgICAgICAgICBQb3B1bGF0aW9uTWlsbGlvbnMgPSBwb3B1bGF0aW9uX2luX21pbGxpb25zKQoKZ2VvZ3JhcGh5X2RmCmBgYAoKSW4gdGhlIHNpbXBsZXN0IGZvcm0gb2Ygc3Vic2V0dGluZywgd2Ugd2FudCBqdXN0IG9uZSBzaW5nbGUgdmFsdWUgZnJvbSBhIGRhdGEgZnJhbWUsIHNvIHdlIHByb3ZpZGUgdGhlIHJvdyBudW1iZXIgYW5kIGNvbHVtbiBudW1iZXIgb2YgdGhlIGNlbGwgb2YgaW50ZXJlc3QuIEZvciBleGFtcGxlLCBpbWFnaW5lIHdlIHdhbnQgdGhlIHBvcHVsYXRpb24gb2YgVmllbm5hLiBXZSBrbm93IHRoYXQgVmllbm5hIGlzIGluIHJvdyAxIGFuZCB0aGUgcG9wdWxhdGlvbiBpcyBpbiBjb2x1bW4gMy4gVG8gc2VsZWN0IHRoYXQgY2VsbCB3ZSBwcm92aWRlIDEgZm9yIHRoZSByb3cgaW5mb3JtYXRpb24gYW5kIDMgZm9yIHRoZSBjb2x1bW4gaW5mb3JtYXRpb24gaW4gdGhlIHNxdWFyZSBicmFja2V0czoKCmBgYHtyIHNpbmdsZSBzZWxlY3Rpb259Cmdlb2dyYXBoeV9kZlsxLDNdCmBgYAoKRG9uJ3Qgd29ycnkgYWJvdXQgaG93IHlvdSB3b3VsZCBrbm93IHRoZSBzcGVjaWZpYyByb3cgYW5kIGNvbHVtbiBvZiB0aGUgY2VsbCB5b3UgYXJlIGludGVyZXN0ZWQgaW4uIFRoaXMgcGFydGljdWxhciBzZWxlY3Rpb24gb3BlcmF0aW9uIGlzIHR5cGljYWxseSB1c2VkIGluIHNpdHVhdGlvbnMgd2hlcmUgeW91ciBjb2RlIGlzIGNvbXB1dGluZyB0aG9zZSB2YWx1ZXMgYmFzZWQgb24gY29tcGxleCBjcml0ZXJpYS4gVGhpcyBleGFtcGxlIGlzIG1lcmVseSBpbGx1c3RyYXRpdmUuIFteMV0KClteMV06IElmIHlvdSBoYXZlIHByb2dyYW1tZWQgYmVmb3JlIGluIEphdmEgb3Igb25lIG9mIHRoZSBDLWZhbWlseSBvZiBsYW5ndWFnZXMsIHlvdSBtYXkgZXhwZWN0IHRoZSBmaXJzdCByb3cgdG8gYmUgKipyb3cgMCoqLCBub3QgKipyb3cgMSoqLCBhbmQgdGhlIGZpcnN0IGNvbHVtbiB0byBiZSAqKmNvbHVtbiAwKiosIG5vdCAqKmNvbHVtbiAxKiouIEp1c3QgbGV0IGdvIG9mIHRoYXQuIEluIFIsIHJvdyBhbmQgY29sdW1uIG51bWJlcmluZyBzdGFydHMgYXQgMS4gRGlmZmVyZW50IGxhbmd1YWdlcywgZGlmZmVyZW50IHJ1bGVzLgoKVGhlcmUgYXJlIHR3byB2ZXJ5IHVzZWZ1bCBleHRlbnNpb25zIHRvIHRoaXMgcGF0dGVybjoKCjEuICBFaXRoZXIgdGhlIHJvdyBvciBjb2x1bW4gaW5kZXggKG9yIGJvdGgpIG1heSBzcGVjaWZ5IGEgKipyYW5nZSoqIHVzaW5nIHRoZSA6IG9wZXJhdG9yLiBGb3IgZXhhbXBsZSwgMTozIG9yIDY6MTIgKHRoZXNlIGFyZSAiMSB0byAzIiBhbmQgIjYgdG8gMTIiIHJlc3BlY3RpdmVseSkuCgpgYGB7ciByYW5nZX0KIyBGb3Igcm93cyAyIHRvIDQgKEJyYXppbCwgQ2FuYWRhLCBEZW5tYXJrKSwgc2VsZWN0IHRoZSBwb3B1bGF0aW9uIChjb2x1bW4gMykKZ2VvZ3JhcGh5X2RmWzI6NCwgM10KCiMgRm9yIENhbmFkYSAocm93IDMpLCBzZWxlY3QgYm90aCB0aGUgY2FwaXRhbCBuYW1lIGFuZCBwb3B1bGF0aW9uIChjb2xzIDIgYW5kIDMpCmdlb2dyYXBoeV9kZlszLCAyOjNdCgpgYGAKCjIuICBFaXRoZXIgdGhlIHJvdyBvciBjb2x1bW4gaW5kZXggKiptYXkgYmUgb21pdHRlZCoqLiBUaGF0IGlzLCB3ZSBjYW4gc2F5IGBnZW9ncmFwaHlfZGZbMyAsIF1gIG9yIGBnZW9ncmFwaHlfZGZbICwgMl1gLiBUaGUgbWlzc2luZyBlbGVtZW50IGlzIGludGVycHJldGVkIGFzICoqYWxsKiouIE9taXQgdGhlIHJvdyBudW1iZXIgYW5kIHlvdSB3YW50ICoqYWxsIHJvd3MqKiBpbiB0aGUgc3VwcGxpZWQgY29sdW1uKHMpLiBPbWl0IHRoZSBjb2x1bW4gbnVtYmVyIGFuZCB5b3Ugd2FudCAqKmFsbCBjb2x1bW5zKiogaW4gdGhlIHN1cHBsaWVkIHJvdyhzKS4KCmBgYHtyIG9taXR0ZWQgaW5kZXh9CgojIEZvciBEZW5tYXJrIChyb3cgNCksIHNlbGVjdCBhbGwgdGhlIGNvbHVtbnMKZ2VvZ3JhcGh5X2RmWzQsIF0KCiMgRm9yIGFsbCByb3dzLCBzZWxlY3QgdGhlIGNhcGl0YWwgY2l0eSBuYW1lIChjb2x1bW4gMikKZ2VvZ3JhcGh5X2RmWyAsIDJdCgpgYGAKCllvdSBtYXkgaGF2ZSBiZWVuIHN1cnByaXNlZCBieSB0aGUgb3V0cHV0IGdlbmVyYXRlZCBieSB0aGF0IGxhc3QgZXhhbXBsZS4gQWx0aG91Z2ggeW91IGhhdmUgc2VsZWN0ZWQgYSBzaW5nbGUgY29sdW1uLCB0aGUgb3V0cHV0IGlzIHByaW50ZWQgaG9yaXpvbnRhbGx5LCBhcyB0aG91Z2ggaXQgd2VyZSBhIHJvdy4gVGhpcyBpcyBhIHBlY3VsaWFyaXR5IG9mIFIuIEFueSBjb2xsZWN0aW9uIHRoYXQgaGFzIGEgc2luZ2xlIGRpbWVuc2lvbiAoaS5lLiBkb2Vzbid0IGhhdmUgYm90aCBjb2x1bW5zIGFuZCByb3dzKSBpcyB0cmVhdGVkIGFzIGEgcGxhaW4gdmVjdG9yLiBBbmQgdmVjdG9ycyBhcmUgYWx3YXlzIHByaW50ZWQgaG9yaXpvbnRhbGx5LiBCeSBleHRlbnNpb24sIHNpbmNlIGEgc2VsZWN0ZWQgY29sdW1uIG9mIGEgZGF0YSBmcmFtZSBpcyBhIHZlY3RvciwgeW91IGNhbiBhcHBseSBldmVyeXRoaW5nIHlvdSBoYXZlIGxlYXJuZWQgYWJvdXQgdmVjdG9ycyB0byBzZWxlY3RlZCBkYXRhIGZyYW1lIGNvbHVtbnMsIHdoaWNoIGlzIGV4YWN0bHkgd2hhdCB3ZSB3YW50IHRvIGJlIGFibGUgdG8gZG8uCgpZb3UgY2FuIGNvbWJpbmUgcmFuZ2VzIGFuZCB0aGUgKm1pc3NpbmcgaW5kZXggPSBhbGwqIHRlY2huaXF1ZToKCmBgYHtyIHRvZ2V0aGVyfQojIEZvciB0aGUgZmlyc3QgdGhyZWUgcm93cywgc2VsZWN0IGFsbCB0aGUgY29sdW1ucwpnZW9ncmFwaHlfZGZbMTozICwgXQoKYGBgCgpBcyBhbiBleGVyY2lzZSwgd2hhdCBkbyB5b3UgdGhpbmsgYGdlb2dyYXBoeV9kZlsgLCBdYCAoaS5lLiB3aGVyZSBib3RoIHJvdyBhbmQgY29sdW1uIGluZm9ybWF0aW9uIGFyZSBvbWl0dGVkKSB3aWxsIGRvPyBUcnkgaXQuIFdlcmUgeW91IHJpZ2h0PwoKSW5zdGVhZCBvZiB1c2luZyBjb2x1bW4gbnVtYmVycywgeW91IGNhbiBwcm92aWRlIGNvbHVtbiBuYW1lcyBhcyB0aGUgY29sdW1uIGluZm9ybWF0aW9uIChhbmQgcm93IG5hbWVzIGFzIHRoZSByb3cgaW5mb3JtYXRpb24gaWYgeW91ciBkYXRhIGZyYW1lIGhhcyBuYW1lZCByb3dzKS4gVXNlIHRoZSBjb21iaW5lIGZ1bmN0aW9uIGBjKClgIHRvIHByb3ZpZGUgbXVsdGlwbGUgY29sdW1uIG5hbWVzLCBhbmQgYmUgc3VyZSB0byBzdXJyb3VuZCBlYWNoIGNvbHVtbiBuYW1lIHdpdGggcXVvdGVzLCBiZWNhdXNlIFIgY29uc2lkZXJzIHRoZW0gdG8gYmUgc3RyaW5ncyBpbiB0aGlzIHNpdHVhdGlvbi4KCmBgYHtyIG5hbWVkIGNvbHVtbnN9Cmdlb2dyYXBoeV9kZlsyOjQsICJDYXBpdGFsIl0KCmdlb2dyYXBoeV9kZlszOjQsIGMoIkNvdW50cnkiLCAiQ2FwaXRhbCIpXQpgYGAKCgoKQW5vdGhlciBtZXRob2QgYXZhaWxhYmxlIGluIGJhc2UgUiBpcyB0aGUgYHN1YnNldGAgZnVuY3Rpb24uIEl0IHRha2VzIHRoZSBmb3JtYXQKCnN1YnNldCh4ID0gZGF0YWZyYW1lLCBzdWJzZXQgPSBjb25kaXRpb25hbF9zdGF0ZW1lbnRfdG9fYXBwbHlfdG9fcm93cywgc2VsZWN0ID0gY29sdW1uc190b19rZWVwKQoKCmBgYHtyfQpjb3VudHJpZXNfb3Zlcl8zMG1pbGxpb24gPC0gc3Vic2V0KGdlb2dyYXBoeV9kZiwgc3Vic2V0ID0gUG9wdWxhdGlvbk1pbGxpb25zID4gMzAsIHNlbGVjdCA9IGMoIkNvdW50cnkiLCAiUG9wdWxhdGlvbk1pbGxpb25zIikgKQpjb3VudHJpZXNfb3Zlcl8zMG1pbGxpb24KYGBgCkFnYWluLCBub3Qgc3VwcGx5aW5nIHRoZSBgc3Vic2V0YCBhcmd1bWVudCBvciBgc2VsZWN0YCBhcmd1bWVudCB3aWxsIGtlZXAgYWxsIHJvd3MgKHN1YnNldCkgb3IgY29sdW1ucyAoc2VsZWN0KS4KCgpTdWItc2V0dGluZyBpc24ndCB1c3VhbGx5IGRvbmUgcGVyZm9ybWVkIGluIGlzb2xhdGlvbi4gVXN1YWxseSB0aGVyZSBpcyBhIHdvcmtmbG93IHRoYXQgd2UncmUgd29ya2luZyB0aHJvdWdoIGFzIHBhcnQgb2Ygb3VyIGRhdGEgYW5hbHlzaXMuIFdlJ3JlIG5vdyBnb2luZyB0byB0YWtlIGxvb2sgYXQgc29tZSBmdW5jdGlvbnMgZnJvbSB0aGUgVGlkeXZlcnNlIC0gc3BlY2lmaWNhbGx5IGBkcGx5cmAgdGhhdCBhcmUgcGFydCBvZiB0aGF0IGRhdGEgYW5hbHlzaXMgd29ya2Zsb3csIGFuZCB3ZSdsbCBhbHNvIHByb3ZpZGUgdGhlIGVxdWl2YWxlbnQgYmFzZSBSIGFwcHJvYWNoLgoKXAoKIyMjIFNlbGVjdGluZyBjb2x1bW5zCgpTbyBmYXIgd2UndmUgY292ZXJlZCBtZXRob2RzIHRoYXQgd2lsbCBsZXQgdXMgc3Vic2V0IGJvdGggcm93cyBhbmQgY29sdW1ucyBhdCB0aGUgc2FtZSB0aW1lLiAKCklmIHdlJ3JlIGFmdGVyIGEgc2luZ2xlIGNvbHVtbiBpbiBhIGRhdGEgZnJhbWUgdGhpcyBjYW4gYmUgcHVsbGVkIG91dCB1c2luZyB0aGUgYCRgIHVzaW5nIHRoZSBmb3JtYXQgYGRhdGFmcmFtZSRjb2x1bW5uYW1lYCwgd2hpY2ggd2lsbCByZXR1cm4gdGhlIGNvbHVtbiBhcyBhIHZlY3Rvci4gRm9yIGluc3RhbmNlIGlmIHdlIHdhbnRlZCB0byBrbm93IGFsbCB0aGUgY291bnRyaWVzIGluIHRoZSBgZ2VvZ3JhcGh5X2RmYCBkYXRhIHdlIGNhbiB1c2UKCmBgYHtyfQpnZW9ncmFwaHlfZGYkQ291bnRyeQpgYGAKClRoaXMgYCRgIHN5bnRheCBjYW4gYmUgdXNlZnVsIGlmIHlvdSB3YW50IHRvIHBlcmZvcm0gYW4gb3BlcmF0aW9uIG9uIG9ubHkgb25lIGNvbHVtbiBzdWNoIGFzIGNhbGN1bGF0aW5nIGEgc3VtbWFyeSBzdGF0aXN0aWMgbGlrZSB0aGUgbWVhbiBvciBzdGFuZGFyZCBkZXZpYXRpb24uIEl0IGNhbiBhbHNvIGJlIHVzZWQgdG8gbW9kaWZ5IG9yIGNyZWF0ZSBhIG5ldyBjb2x1bW4gb24gYSBkYXRhIGZyYW1lLgoKYGBge3J9CiMgbWVhbiBvZiBhIHRoZSBQb3B1bGF0aW9uTWlsbGlvbnMgY29sdW1uCm1lYW4oZ2VvZ3JhcGh5X2RmJFBvcHVsYXRpb25NaWxsaW9ucykKCiMgbmV3IGNvbHVtbiBQb3B1bGF0aW9uVGhvdXNhbmRzCmdlb2dyYXBoeV9kZiRQb3B1bGF0aW9uVGhvdXNhbmRzIDwtIGdlb2dyYXBoeV9kZiRQb3B1bGF0aW9uTWlsbGlvbnMgKiAxMDAwCmdlb2dyYXBoeV9kZiRQb3B1bGF0aW9uVGhvdXNhbmRzCmBgYAoKClRvIHNlZSBob3cgc2VsZWN0aW9uIHdpdGggdGhlIGBzZWxlY3RgIGZ1bmN0aW9uIGZyb20gYGRwbHlyYCBjb21wYXJlcyB0byBzZWxlY3Rpb24gd2l0aCB0aGUgZXh0cmFjdCBvcGVyYXRvciBgWyBdYCBpbiBiYXNlIFIsIGxldHMgbG9hZCB0aGUgKipmbGlnaHRzKiogZGF0YSBmcmFtZSBhbmQgcmVwZWF0IHNvbWUgb2YgdGhlIGV4ZXJjaXNlcyBmcm9tICpSIGZvciBEYXRhIFNjaWVuY2UqLgoKYGBge3IgbG9hZCBmbGlnaHRzLCB3YXJuaW5nPUZBTFNFfQoKIyBMb2FkIHRoZSBsaWJyYXJ5IHRoYXQgY29udGFpbnMgdGhlIGZsaWdodHMgZGF0YSBmcmFtZQpsaWJyYXJ5KG55Y2ZsaWdodHMxMykKCiMgTG9hZCBkcGx5cgpsaWJyYXJ5KGRwbHlyKQoKCgojIFNlbGVjdCB0aGUgeWVhciwgbW9udGgsIGFuZCBkYXkgY29sdW1ucyBmcm9tIHRoZSBmbGlnaHRzIGRhdGEgZnJhbWUKCiMgV2l0aCBkcGx5cgp5ZWFyX21vbnRoX2RheV9jb2xzX2RwbHlyIDwtIHNlbGVjdChmbGlnaHRzLCB5ZWFyLCBtb250aCwgZGF5KQp5ZWFyX21vbnRoX2RheV9jb2xzX2RwbHlyCgojIFdpdGggYmFzZSBSCnllYXJfbW9udGhfZGF5X2NvbHNfYmFzZSA8LSBmbGlnaHRzWyAsIGMoInllYXIiLCAibW9udGgiLCAiZGF5IildCnllYXJfbW9udGhfZGF5X2NvbHNfYmFzZQpgYGAKCgo8IS0tCi0gdXNpbmcgaGVscGVyIGZ1bmN0aW9ucwogIC0gc3RhcnRzX3dpdGgKICAtIGVuZHNfd2l0aAogIC0gY29udGFpbnMKICAtIGFueW9mCi0tPgoKClwKCiMjIyBGaWx0ZXJpbmcgcm93cwoKVGhlIGBkcGx5cmAgZnVuY3Rpb24gYGZpbHRlcmAgaXMgYW5hbG9nb3VzIHRvIHRoZSBiYXNlIFIgZnVuY3Rpb24gYHN1YnNldGAuIFRoZSB0d28gZnVuY3Rpb25zIGhhdmUgaWRlbnRpY2FsIHN5bnRheC4gV2UgY2FuIHNlZSBob3cgc29tZSBvZiB0aGUgYGRwbHlyYCBmaWx0ZXIgb3BlcmF0aW9ucyBmcm9tIHRoZSBwcmV2aW91cyBzZWN0aW9uIHdvdWxkIGJlIHdyaXR0ZW4gdXNpbmcgYmFzZSBSLiBJZiB5b3Ugd2lzaCwgcnVuIHRoaXMgY29kZSBpbiBSU3R1ZGlvLCBhbmQgaW5zcGVjdCB0aGUgcmVzdWx0cyBvZiBlYWNoIHN0YXRlbWVudC4KCmBgYHtyIGZpbHRlciBhbmQgc3Vic2V0fQoKIyBJbiBhbGwgY2FzZXMsIHRoZXNlIHBhaXJzIG9mIGNvbW1hbmRzIHByb2R1Y2UgdGhlIHNhbWUgb3V0cHV0CiMgSW4gZWFjaCBwYWlyLCB0aGUgZmlyc3QgdmVyc2lvbiBpcyBkcGx5ciBhbmQgdGhlIHNlY29uZAojIGlzIGJhc2UgUgoKIyBBbGwgZmxpZ2h0cyB3aXRoIGFycml2YWwgZGVsYXkgPj0gMTIwIG1pbnV0ZXMKbGF0ZV9kcGx5ciA8LSBmaWx0ZXIoZmxpZ2h0cywgYXJyX2RlbGF5ID4gMTIwKQpsYXRlX2Jhc2UgPC0gc3Vic2V0KGZsaWdodHMsIGFycl9kZWxheSA+IDEyMCkKCiMgRmxldyB0byBJQUggb3IgSE9VCmhvdXN0b25fZHBseXIgPC0gZmlsdGVyKGZsaWdodHMsIGRlc3QgPT0gIklBSCIgfCBkZXN0ID09ICJIT1UiKQpob3VzdG9uX2Jhc2UgPC0gc3Vic2V0KGZsaWdodHMsIGRlc3QgPT0gIklBSCIgfCBkZXN0ID09ICJIT1UiKQoKIyBBbHRlcm5hdGl2ZWx5LCB1c2luZyAlaW4lLCB3aGljaCByZXF1aXJlcyBsZXNzIHR5cGluZwpob3VzdG9uX2RwbHlyIDwtIGZpbHRlcihmbGlnaHRzLCBkZXN0ICVpbiUgYygiSUFIIiwgIkhPVSIpKQpob3VzdG9uX2Jhc2UgPC0gc3Vic2V0KGZsaWdodHMsIGRlc3QgJWluJSBjKCJJQUgiLCAiSE9VIikpCgojIFNlbGVjdCByb3dzIHdpdGggbWlzc2luZyB2YWx1ZXMgdXNpbmcgaXMubmEoKSAKbWlzc2luZ19kZXBfdGltZV9kcGx5ciA8LSBmaWx0ZXIoZmxpZ2h0cywgaXMubmEoZGVwX3RpbWUpKQptaXNzaW5nX2RlcF90aW1lX2Jhc2UgPC0gc3Vic2V0KGZsaWdodHMsIGlzLm5hKGRlcF90aW1lKSkKYGBgCgpCYXNlIFIgZG9lcyBub3QgaGF2ZSB0aGUgaGVscGVyIGZ1bmN0aW9uIGBiZXR3ZWVuYCwgYnV0IHRoZSBzYW1lIHJlc3VsdCBjYW4gYmUgYWNoaWV2ZWQgaW4gYSBudW1iZXIgb2Ygd2F5czoKCmBgYHtyIGJldHdlZW59CiMgQmV0d2VlbgoKIyBUaGVzZSBmb3VyIGNvbW1hbmRzIGFsbCBwcm9kdWNlIHRoZSBzYW1lIHJlc3VsdAoKIyBkcGx5cgpzdW1tZXJfZHBseXIgPC0gZmlsdGVyKGZsaWdodHMsIGJldHdlZW4obW9udGgsIDcsIDkpKQoKIyBiYXNlIFIKc3VtbWVyX2Jhc2VfMDEgPC0gc3Vic2V0KGZsaWdodHMsIG1vbnRoICVpbiUgYyg3LDgsOSkpCnN1bW1lcl9iYXNlXzAyIDwtIHN1YnNldChmbGlnaHRzLCBtb250aCAlaW4lIDc6OSkKc3VtbWVyX2Jhc2VfMDMgPC0gc3Vic2V0KGZsaWdodHMsIG1vbnRoID49NyAmIG1vbnRoIDw9IDkpCmBgYAoKV2hlbiB5b3UgaGF2ZSBtdWx0aXBsZSBvcHRpb25zIGZvciBwZXJmb3JtaW5nIGEgY29tcHV0YXRpb24sIHRoZSBnZW5lcmFsIGdvYWwgaXMgdG8gc3RyaWtlIGEgYmFsYW5jZSBiZXR3ZWVuICoqcGFyc2ltb255KiogKG5vdCB0b28gbXVjaCB0eXBpbmcpIGFuZCAqKnJlYWRhYmlsaXR5KiogKHlvdXIgY29kZSBpcyBlYXN5ICpmb3Igb3RoZXIgcGVvcGxlKiB0byB1bmRlcnN0YW5kKS4gV2hlbiB3b3JraW5nIG9uIGdyb3VwIHByb2plY3RzLCBvciBpbiBhIHByb2Zlc3Npb25hbCBzb2Z0d2FyZSBkZXZlbG9wbWVudCBjb250ZXh0LCByZWFkYWJpbGl0eSBpcyBjb25zaWRlcmVkIHRoZSBtb3JlIGNyaXRpY2FsIG9mIHRoZSB0d28gZmVhdHVyZXMuXAoKXAoKIyMgQXJyYW5naW5nIChzb3J0aW5nKQoKVGhlIGBkcGx5cmAgZnVuY3Rpb24gYGFycmFuZ2VgIGlzIGFuYWxvZ291cyB0byBiYXNlIFIgc2VsZWN0aW9uIHVzaW5nIFsgXSBjb21iaW5lZCB3aXRoIGZ1bmN0aW9uIGBvcmRlcmAuIFdlIHVzZSBgb3JkZXJgIGFzIHRoZSByb3cgaW5mb3JtYXRpb24gdG8gWyBdLiBUaGUgYXJndW1lbnRzIHRvIGBvcmRlcmAgYXJlIGEgY29tbWEgc2VwYXJhdGVkIHNlcXVlbmNlIG9mIHRoZSBjb2x1bW5zIG9uIHdoaWNoIHdlIHdpc2ggdG8gc29ydC4gV2UgaWRlbnRpZnkgdGhlIGNvbHVtbnMgdXNpbmcgdGhlIFwkIG9wZXJhdG9yLCBpbiB0aGUgdXN1YWwgd2F5LgoKRm9yIGV4YW1wbGUsIHRoZSBgZHBseXJgIHN0YXRlbWVudCBhbmQgdGhlIGJhc2UgUiBzdGF0ZW1lbnQgYmVsb3cgYm90aCBzb3J0IHRoZSBlbnRpcmUgZmxpZ2h0IGRhdGEgZnJhbWUgb24gdGhlIHllYXIsIG1vbnRoLCBhbmQgZGF5IGNvbHVtbnM6CgpgYGB7ciBvcmRlcn0KCiMgU29ydCB1c2luZyBhcnJhbmdlIG9yIG9yZGVyCgojIGRwbHlyCnllYXJfbW9udGhfZGF5X2RwbHlyIDwtIGFycmFuZ2UoZmxpZ2h0cywgeWVhciwgbW9udGgsIGRheSkKCiMgYmFzZSBSIOKAkyB3ZSBvbWl0IHRoZSBjb2x1bW4gaW5kZXggdG8gZ2V0IGFsbCBjb2x1bW5zIGluIHRoZSByZXN1bHQKeWVhcl9tb250aF9kYXlfYmFzZSA8LSBmbGlnaHRzW29yZGVyKGZsaWdodHMkeWVhciwgZmxpZ2h0cyRtb250aCwgZmxpZ2h0cyRkYXkpLCBdIAoKIyBDb21wYXJlIHRoZSByZXN1bHRzCnllYXJfbW9udGhfZGF5X2RwbHlyCnllYXJfbW9udGhfZGF5X2Jhc2UKCmBgYAoKCkJ5IGRlZmF1bHQsIGBvcmRlcmAgc29ydHMgaW4gYXNjZW5kaW5nIG9yZGVyIChpLmUuIGZyb20gc21hbGxlc3QgdG8gbGFyZ2VzdCkuIFRvIHNvcnQgaW4gZGVzY2VuZGluZyBvcmRlciwgcGxhY2UgLSAodGhlIG5lZ2F0aXZlIHNpZ247IHRoZSBoeXBoZW4pIGluIGZyb250IG9mIGFuIGFyZ3VtZW50IHRvIGBvcmRlcmAuIFdlIGNhbiBhZ2FpbiBjb21wYXJlIHRoaXMgb3BlcmF0aW9uIGluIGBkcGx5cmAgYW5kIGJhc2UgUjoKCmBgYHtyIGRlc2NlbmRpbmd9CiMgRGVzY2VuZGluZyBzb3J0CgojIGRwbHlyCmRlc2NfZGVwX2RlbGF5X2RwbHlyIDwtIGFycmFuZ2UoZmxpZ2h0cywgZGVzYyhkZXBfZGVsYXkpKQoKIyBiYXNlIFIKZGVzY19kZXBfZGVsYXlfYmFzZSA8LSBmbGlnaHRzW29yZGVyKC1mbGlnaHRzJGRlcF9kZWxheSksXQoKIyBDaGVjayBkcGx5ciDigJMgdGhlIGRhdGEgZnJhbWUgaXMgc29ydGVkIGluIGRlc2NlbmRpbmcgb3JkZXIgb2YgZGVwX2RlbGF5CmRlc2NfZGVwX2RlbGF5X2RwbHlyCgojIENoZWNrIGJhc2Ug4oCTIHRoZSBkYXRhIGZyYW1lIGlzIHNvcnRlZCBpbiBkZXNjZW5kaW5nIG9yZGVyIG9mIGRlcF9kZWxheQpkZXNjX2RlcF9kZWxheV9iYXNlCgpgYGAKClwKCiMjIENyZWF0aW5nIG5ldyBjb2x1bW5zCgpJbiBgZHBseXJgIHdlIHVzZSBmdW5jdGlvbiBgbXV0YXRlYCB0byBjcmVhdGUgbmV3IGNvbHVtbnMuIEluIGJhc2UgUiwgd2Ugc2ltcGx5IGFzc2lnbiB0aGUgbmV3IGNvbHVtbiBkaXJlY3RseSB0byB0aGUgZGF0YSBmcmFtZSwgdXNpbmcgXCQuIEVhY2ggbmV3IGNvbHVtbiBtdXN0IGJlIGNyZWF0ZWQgaW4gYSBzZXBhcmF0ZSBzdGF0ZW1lbnQuIEluIHRoZSBjb2RlIGJlbG93LCB3ZSB3aWxsIGNvbXBhcmUgdGhlIHR3byB0ZWNobmlxdWVzLiBJbiBib3RoIGFwcHJvYWNoZXMgd2Ugd2lsbCBiZWdpbiBieSBtYWtpbmcgYSBjb3B5IG9mIGRhdGEgZnJhbWUgZmxpZ2h0cywgYmVmb3JlIHdlIHN0YXJ0IHRvIG1vZGlmeSBpdC4gVGhpcyBpcyBjb21tb24gcHJhY3RpY2Ugc28gdGhhdCB5b3UgYWx3YXlzIGhhdmUgYSBjbGVhbiBjb3B5IG9mIHlvdXIgb3JpZ2luYWwgZGF0YS4KCmBgYHtyIG11dGF0ZSwgd2FybmluZz1GQUxTRX0KCiMgZHBseXIKCiMgTWFrZSBhIGNvcHkKZmxpZ2h0c19kcGx5ciA8LSBmbGlnaHRzCgojIEFkZCBuZXcgY29sdW1ucyB3aXRoIG11dGF0ZQpmbGlnaHRzX2RwbHlyIDwtIG11dGF0ZShmbGlnaHRzX2RwbHlyLCBnYWluPWRlcF9kZWxheSAtIGFycl9kZWxheSwgc3BlZWQgPSBkaXN0YW5jZSAvIGFpcl90aW1lICogNjApCgoKIyBiYXNlIFIKCiMgTWFrZSBhIGNvcHkKZmxpZ2h0c19iYXNlIDwtIGZsaWdodHMKCiMgQWRkIHRoZSBuZXcgY29sdW1ucwphdHRhY2goZmxpZ2h0c19iYXNlKQpmbGlnaHRzX2Jhc2UkZ2FpbiA8LSBkZXBfZGVsYXkgLSBhcnJfZGVsYXkKZmxpZ2h0c19iYXNlJHNwZWVkIDwtIGRpc3RhbmNlIC8gYWlyX3RpbWUgKiA2MAoKIyBDb21wYXJlIHVzaW5nIGJhc2UgUiBzZWxlY3Rpb24KIyBBc2sgZm9yIGNvbHVtbnMgZ2FpbiBhbmQgc3BlZWQgZm9yIHJvd3MgMSB0byAxNQojIFRoZXkgYXJlIHRoZSBzYW1lCmZsaWdodHNfZHBseXJbMTo1LCBjKCJnYWluIiwgInNwZWVkIildCmZsaWdodHNfYmFzZVsxOjUsIGMoImdhaW4iLCAic3BlZWQiKV0KYGBgCgpcCgojIyBHcm91cGluZyBhbmQgU3VtbWFyaXNpbmcKCldpdGggYGRwbHlyYCB3ZSB0YWtlIGdyb3VwIHN1bW1hcmllcyAoZS5nLiBnZXR0aW5nIHRoZSBhdmVyYWdlIGFycml2YWwgZm9yIGFsbCBmbGlnaHRzIGluIGVhY2ggbW9udGgpIGJ5IHVzaW5nIGBncm91cF9ieWAgdG8gZ3JvdXAgdGhlIGRhdGEgZnJhbWUgKGdhdGhlciB0aGUgcm93cyB0b2dldGhlciBieSBtb250aCkgYW5kIGBzdW1tYXJpc2VgIHRvIGFwcGx5IHRoZSBzdW1tYXJ5IGZ1bmN0aW9uICh0YWtlIHRoZSBhdmVyYWdlIGZvciBlYWNoIG1vbnRoKS4gSW4gYmFzZSBSIGJvdGggb2YgdGhlc2Ugc3RlcHMgYXJlIGhhbmRsZWQgYnkgdGhlIHNpbmdsZSBmdW5jdGlvbiBgYWdncmVnYXRlYC4gVGhpcyBmdW5jdGlvbiB0YWtlcyBmb3VyIGFyZ3VtZW50czoKCnwgQXJnIG5hbWUgfCBNZWFuaW5nICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8LS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwKfCB4ICAgICAgICB8IFRoZSBuYW1lIG9mIHRoZSBkYXRhIGZyYW1lICAgICAgICAgICAgICAgICAgICAgICB8CnwgYnkgICAgICAgfCBBIGxpc3Qgb2YgY29sdW1ucyB0byBncm91cCBieSAgICAgICAgICAgICAgICAgICAgfAp8IEZVTiAgICAgIHwgVGhlIG5hbWUgb2YgdGhlIHN1bW1hcnkgZnVuY3Rpb24gdG8gYXBwbHkgICAgICAgIHwKfCBuYS5ybSAgICB8IFNldCB0byBUUlVFIGlzIHlvdSB3YW50IHRvIGlnbm9yZSBtaXNzaW5nIHZhbHVlcyB8CgpUaGUgb25seSBuZXcgcGFydCBpcyB0aGUgc3ludGF4IHVzZWQgdG8gZGVjbGFyZSBhIGxpc3QgZm9yIGFyZ3VtZW50ICoqYnkqKi4gV2Ugd2lsbCBmaXJzdCBsb29rIGF0IGFuIGV4YW1wbGUgb2YgaG93IHRvIHRha2UgZ3JvdXAgbWVhbnMgaW4gYm90aCBgZHBseXJgIGFuZCBiYXNlIFIsIGFuZCB0aGVuIGRpc2N1c3MgdGhlIGxpc3QgaW4gbW9yZSBkZXRhaWwuCgpgYGB7ciBncm91cCBtZWFucyAwMSwgd2FybmluZz1GQUxTRX0KIyBDb21wdXRlIHRoZSBhdmVyYWdlIGFycml2YWwgZGVsYXksIGNvbGxhcHNlZCBhY3Jvc3MgbW9udGhzCgojIFVzaW5nIGRwbHlyCgojIEdyb3VwIGJ5IG1vbnRoCmJ5X21vbnRoIDwtIGdyb3VwX2J5KGZsaWdodHMsIG1vbnRoKQoKIyBUYWtlIHRoZSBtZWFucwptZWFuX2RlbGF5X2J5X21vbnRoX2RwbHlyIDwtIHN1bW1hcmlzZShieV9tb250aCwgTWVhbkRlbGF5ID0gbWVhbihhcnJfZGVsYXksIG5hLnJtID0gVFJVRSkpCgojIENoZWNrIHRoZSBvdXRwdXQKbWVhbl9kZWxheV9ieV9tb250aF9kcGx5cgoKCgojIFVzaW5nIGJhc2UgUiBmdW5jdGlvbiBhZ2dyZWdhdGUKbWVhbl9kZWxheV9ieV9tb250aF9iYXNlIDwtIGFnZ3JlZ2F0ZSh4ID0gZmxpZ2h0cyRhcnJfZGVsYXksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gbGlzdChNb250aCA9IGZsaWdodHMkbW9udGgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZVTiA9IG1lYW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKQoKCiMgQ2hlY2sgdGhlIG91dHB1dAptZWFuX2RlbGF5X2J5X21vbnRoX2Jhc2UKYGBgCgpVc2UgZnVuY3Rpb24gYGxpc3RgIHRvIGNyZWF0ZSB0aGUgdmFsdWUgZm9yIGFyZ3VtZW50IGBieWAgLiBUaGlzIGZ1bmN0aW9uIGlzIGxpa2UgdGhlIGNvbWJpbmUgZnVuY3Rpb24gZm9yIHZlY3RvcnMsIGV4Y2VwdCBpdCBjcmVhdGVzIGEgY29sbGVjdGlvbiBvZiAqbmFtZWQgZWxlbWVudHMqLiBXZSBvZnRlbiBzZWUgdGhlIGZ1bmN0aW9uIGluIHNpdHVhdGlvbnMgbGlrZSB0aGlzOgoKYGBge3IgbGlzdH0KIyBBIGxpc3QgaXMgYSBjb2xsZWN0aW9uIG9mIG5hbWVkIGVsZW1lbnRzCnBldF9kYXRhIDwtIGxpc3QoUGV0TmFtZSA9ICJTbm9vcHkiLCBQZXRPd25lciA9ICJDaGFybGllIEJyb3duIiwgUGV0QnJlZWQgPSAiQmVhZ2xlIikKcGV0X2RhdGEKYGBgCgpXaGVuIHVzaW5nIGBhZ2dyZWdhdGVgIHlvdSBjcmVhdGUgYSBsaXN0IG9mIGNvbHVtbnMgdGhhdCB5b3Ugd2FudCB0byBncm91cCBieS4gVGhlIG5hbWVzIG9mIHRoZSBjb2x1bW5zIHdpbGwgYmUgdGhlIGNvbHVtbiBoZWFkZXJzIGZvciB0aGUgb3V0cHV0IHRhYmxlIG9mIHN1bW1hcmlzZWQgcmVzdWx0cy4gVG8gZ3JvdXAgYnkgbXVsdGlwbGUgY29sdW1ucywgYWRkIG1vcmUgZWxlbWVudHMgdG8gdGhlIGxpc3QuIEZvciBleGFtcGxlLCBpZiB3ZSB3YW50ZWQgdGhlIGF2ZXJhZ2UgZGVsYXkgYnkgbW9udGggKmZvciBlYWNoIG9yaWdpbiBhaXJwb3J0IHNlcGFyYXRlbHkqIHdlIHdvdWxkIHNheToKCmBgYHtyIGdyb3VwIG1lYW5zIDAyLCB3YXJuaW5nPUZBTFNFfQojIENvbXB1dGUgdGhlIGF2ZXJhZ2UgYXJyaXZhbCBkZWxheSwgY29sbGFwc2VkIGFjcm9zcyBtb250aHMsIHNlcGFyYXRlbHkgZm9yCiMgZWFjaCBvcmlnaW4gYWlycG9ydC4gVGhlcmUgYXJlIDMgYWlycG9ydHMgYW5kIDEyIG1vbnRocywgc28gd2UgZXhwZWN0IHRvIAojIGdldCAzNiBtZWFucy4KCiMgVXNpbmcgZHBseXIKCiMgR3JvdXAgYnkgbW9udGggYW5kIG9yaWdpbgpieV9tb250aF9vcmlnaW4gPC0gZ3JvdXBfYnkoZmxpZ2h0cywgbW9udGgsIG9yaWdpbikKCiMgVGFrZSB0aGUgbWVhbnMKbWVhbl9tb250aF9vcmlnaW5fZHBseXIgPC0gc3VtbWFyaXNlKGJ5X21vbnRoX29yaWdpbiwgTWVhbkRlbGF5ID0gbWVhbihhcnJfZGVsYXksIG5hLnJtID0gVFJVRSkpCgojIENoZWNrIHRoZSBvdXRwdXQKbWVhbl9tb250aF9vcmlnaW5fZHBseXIKCgoKIyBVc2luZyBiYXNlIFIgZnVuY3Rpb24gYWdncmVnYXRlCm1lYW5fbW9udGhfb3JpZ2luX2Jhc2UgPC0gYWdncmVnYXRlKHggPSBmbGlnaHRzJGFycl9kZWxheSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSBsaXN0KE1vbnRoID0gZmxpZ2h0cyRtb250aCwgT3JpZ2luID0gZmxpZ2h0cyRvcmlnaW4pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZVTiA9IG1lYW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKQoKCiMgQ2hlY2sgdGhlIG91dHB1dC4gTm90ZSB0aGF0IGRwbHlyIGFuZCBiYXNlIFIgc29ydCB0aGUgb3V0cHV0IGluIGRpZmZlcmVudCBvcmRlcnMKbWVhbl9tb250aF9vcmlnaW5fYmFzZQpgYGAKClwKCiMjIFdvcmtmbG93cyBhbmQgZGF0YSBwaXBlbGluZXMKClRyYWRpdGlvbmFsbHkgZGF0YSBhbmFseXNpcyB3b3JrZmxvd3MgaW4gUiBoYXZlIGNvbnNpc3RlZCBvZiBlaXRoZXIgbWFueSBuZXN0ZWQgb3BlcmF0aW9ucywgb3IgdGhlIHVzZSBvZiBhc3NpZ25pbmcgaW50ZXJtZWRpYXRlIHN0ZXBzIHRvIHZhcmlhYmxlcy4gT25lIG9mIHRoZSBrZXkgZGlmZmVyZW5jZXMgaW4gYXBwcm9hY2ggYmV0d2VlbiB0aGUgVGlkeXZlcnNlIGFuZCBiYXNlIFIgKHVudGlsIHZlcnkgcmVjZW50bHkgd2l0aCBSIHY0LjErKSBpcyB0aGUgaWRlYSBvZiAncGlwZXMnIHdoaWNoIGFsbG93IHVzIHRvICdjaGFpbicgb3BlcmF0aW9ucyB0b2dldGhlciwgd2l0aCB0aGUga2V5IGJlbmVmaXQgYmVpbmcgcmVhZGFiaWxpdHkgb2YgY29kZS4gV2hlbiByZWFkaW5nIGNvZGUsIGl0IGNhbiBiZSB1c2VmdWwgdG8gcmVhZCB0aGUgcGlwZSBhcyB0aGUgd29yZCAidGhlbiIuCgpcCgojIyMgUGlwZXMKCgpUaGUgcGlwZSBmdW5jdGlvbiBmcm9tIGBtYWdyaXR0cmAgd2hpY2ggaXMgcGFydCBvZiB0aGUgVGlkeXZlcnNlLCBlbmFibGVzIHRoZSBjcmVhdGlvbiBvZiAncGlwZWxpbmVzJyBvciBjaGFpbmluZyB0b2dldGhlciBvZiBmdW5jdGlvbnMgYXMgb3Bwb3NlZCB0byBuZXN0aW5nLiBUaGUgcGlwZSBmdW5jdGlvbiAoYCU+JWAgc2hvcnRjdXQgPGtiZD5DdHJsPC9rYmQ+ICsgPGtiZD5TaGlmdDwva2JkPiArIDxrYmQ+TTwva2JkPiAtIG9uIGEgTWFjIHVzZSA8a2JkPkNtZDwva2JkPiBpbnN0ZWFkIG9mIDxrYmQ+Q3RybDwva2JkPikgdGFrZXMgdGhlIG91dHB1dCBvZiB0aGUgZnVuY3Rpb24gYW5kIHVzZXMgaXQgYXMgdGhlIGZpcnN0IGFyZ3VtZW50IGZvciB0aGUgbmV4dCBmdW5jdGlvbi4gV2hlbiB5b3UgcmVhZCBgJT4lYCBpbiBjb2RlIHlvdSBjYW4gdGhpbmsgb2YgaXQgYXMgdGhlIHdvcmQgInRoZW4iLgoKRm9yIGluc3RhbmNlLCBpZiB3ZSBjYWxsIHRoZSBuYW1lIG9mIG91ciBkYXRhIHNldCBieSBpdHNlbGYsIGl0IHdpbGwgcHV0IHRoZSByZXN1bHRzIG9udG8gdGhlIHNjcmVlbiwgaG93ZXZlciBpZiB3ZSAncGlwZScgaXQgdG8gYW5vdGhlciBmdW5jdGlvbiBpdCBnZXRzIHVzZWQgYXMgdGhlIGlucHV0IGZvciB0aGF0IGZ1bmN0aW9uIGluc3RlYWQuIApgYGB7cn0KZmxpZ2h0cwoKCmZsaWdodHMgJT4lIGhlYWQoKQpgYGAKClRoaXMgd29ya3MgZm9yIGZ1bmN0aW9ucyB0aGF0IGV4cGVjdCB0aGUgZmlyc3QgYXJndW1lbnQgdG8gYmUgdGhlIGRhdGEuIFdlIGNhbiBhbHNvIGJlIGV4cGxpY2l0IGFib3V0IHdoaWNoIGFyZ3VtZW50IHdlIHdvdWxkIGxpa2UgdGhlIGlucHV0IGZyb20gdGhlIHBpcGUgdG8gb2NjdXB5LiBXZSBjYW4gdXNlIGAuYCB0byByZXByZXNlbnQgdGhpcwoKYGBge3J9CmZsaWdodHMgJT4lIGhlYWQobiA9IDEwLCB4ID0gLikKYGBgCgpcCgpXZSBjYW4gdXNlIHRoZSBgJT4lYCB0byBjaGFpbiBtdWx0aXBsZSBmdW5jdGlvbnMgdG9nZXRoZXIuIEhlcmUgd2UnbGwgbG9vayBhdCB0aGUgd29ya2Zsb3cgb2YgY2FsY3VsYXRpbmcgdGhlIG1lYW4gYWlydGltZSBvZiBmbGlnaHRzIGxlYXZpbmcgSkZLIG9yIExHQSBmb3IgZWFjaCBtb250aCB3aXRoIHRoZSByZXN1bHRpbmcgbWVhbiBhaXJ0aW1lIHNvcnRlZCBmcm9tIGxvbmdlc3QgdG8gc2hvcnRlc3QgZmxpZ2h0IHRpbWUuIAoKYGBge3J9CiMgYmFzZSBSIHdpdGggaW50ZXJtZWRpYXRlcwoKIyBTdWJzZXQgdGhlIGRhdGEKZmxpZ2h0c19qZmtfbGdhIDwtIHN1YnNldChmbGlnaHRzLCBvcmlnaW4gPT0gIkpGSyIgfCBvcmlnaW4gPT0gIkxHQSIsIHNlbGVjdCA9IGMoIm1vbnRoIiwgIm9yaWdpbiIsImFpcl90aW1lIikpCgojIGNhbGN1bGF0ZSB0aGUgbWVhbiBhaXIgdGltZSBmb3IgZWFjaCBtb250aC9vcmlnaW4gZ3JvdXBpbmcKZmxpZ2h0X3Jlc3VsdHMgPC0gYWdncmVnYXRlKHggPSBmbGlnaHRzX2pma19sZ2EkYWlyX3RpbWUsIAogICAgICAgICAgYnkgPSBsaXN0KG1vbnRoID0gZmxpZ2h0c19qZmtfbGdhJG1vbnRoLCBvcmlnaW4gPSBmbGlnaHRzX2pma19sZ2Ekb3JpZ2luKSwKICAgICAgICAgIEZVTiA9IG1lYW4sCiAgICAgICAgICBuYS5ybSA9IFRSVUUpCgojIHJlbmFtZSB0aGUgcmVzdWx0IGNvbHVtbgpuYW1lcyhmbGlnaHRfcmVzdWx0cylbd2hpY2gobmFtZXMoZmxpZ2h0X3Jlc3VsdHMpID09ICJ4IildIDwtICJtZWFuX2Fpcl90aW1lIgoKIyBzb3J0IHRoZSByZXN1bHRzCmZsaWdodF9yZXN1bHRzX2Jhc2UgPC0gZmxpZ2h0X3Jlc3VsdHNbb3JkZXIoZmxpZ2h0X3Jlc3VsdHMkbWVhbl9haXJfdGltZSwgZGVjcmVhc2luZyA9IFRSVUUpLF0KCiMgc2hvdyB0b3AgNiByZXN1bHRzCmhlYWQoZmxpZ2h0X3Jlc3VsdHNfYmFzZSkKYGBgCgoKYGBge3J9CiMgZHBseXIgdXNpbmcgcGlwZXMKCmZsaWdodF9yZXN1bHRzX2RwbHlyIDwtIGZsaWdodHMgJT4lIAogICMgc3Vic2V0IHRoZSBkYXRhCiAgc2VsZWN0KG1vbnRoLCBvcmlnaW4sIGFpcl90aW1lKSAlPiUgCiAgZmlsdGVyKG9yaWdpbiA9PSAiSkZLIiB8IG9yaWdpbiA9PSAiTEdBIikgJT4lCiAgIyBjYWxjdWxhdGUgdGhlIG1lYW4gYWlyIHRpbWUgZm9yIGVhY2ggbW9udGgvb3JpZ2luIGdyb3VwaW5nCiAgZ3JvdXBfYnkobW9udGgsIG9yaWdpbikgJT4lIAogIHN1bW1hcmlzZShtZWFuX2Fpcl90aW1lID0gbWVhbihhaXJfdGltZSwgbmEucm0gPSBUUlVFKSkgJT4lIAogICMgc29ydCB0aGUgcmVzdWx0cwogIGFycmFuZ2UoZGVzYyhtZWFuX2Fpcl90aW1lKSkKCiMgc2hvdyB0b3AgNiByZXN1bHRzCmhlYWQoZmxpZ2h0X3Jlc3VsdHNfZHBseXIpCmBgYAoKT25lIG9mIHRoZSBuaWNlIGZlYXR1cmVzIG9mIGRlYWxpbmcgd2l0aCBwaXBlcywgaXMgdGhhdCB5b3UgY2FuIGRvIHlvdXIgc3Vic2V0dGluZyB3b3JrZmxvdyBhbmQgcGlwZSBkaXJlY3RseSBpbnRvIGBnZ3Bsb3RgLCBhbHRob3VnaCBpdCdzIHVzdWFsbHkgYSBnb29kIGlkZWEgdG8gYXNzaWduIHlvdXIgc3Vic2V0dGVkIGRhdGEgYW5kIHRoZW4gdXNlIHRoYXQgdG8gc3RhcnQgeW91ciBwbG90dGluZyBwaXBlbGluZS4gSWYgeW91IHBpcGUgeW91ciBkYXRhIGludG8gZ2dwbG90IFJTdHVkaW8gd2lsbCBhbHNvIGxldCB5b3UgYXV0by1jb21wbGV0ZSB5b3VyIGNvbHVtbnMgd2l0aCA8a2JkPlRhYjwva2JkPi4KCmBgYHtyIHBpcGVfcGxvdH0KbGlicmFyeShnZ3Bsb3QyKQoKZmxpZ2h0cyAlPiUgCiAgIyBzdWJzZXQgdGhlIGRhdGEKICBzZWxlY3QobW9udGgsIG9yaWdpbiwgYWlyX3RpbWUpICU+JSAKICBmaWx0ZXIob3JpZ2luID09ICJKRksiIHwgb3JpZ2luID09ICJMR0EiKSAlPiUKICAjIHBsb3QgdGhlIGRhdGEKICBnZ3Bsb3QoYWVzKHggPSBvcmlnaW4sIHkgPSBhaXJfdGltZSkpICsgZ2VvbV9ib3hwbG90KCkKYGBgCgpcCgpcCgojIyBDb25jbHVzaW9uCgpSIHVzZXJzIGFyZSBjb25zdGFudGx5IGFkZGluZyBuZXcgbGlicmFyaWVzIHRvIGJhc2UgUiwgbWVhbmluZyB0aGF0IHlvdSB3aWxsIHByb2JhYmx5IGhhdmUgc2V2ZXJhbCBvcHRpb25zIGZvciBkb2luZyBhbnkgam9iIGluIFIuIFRoZSB2YXJpb3VzIG9wdGlvbnMgc29tZXRpbWVzIGhhdmUgc3VidGxlIHRlY2huaWNhbCBkaWZmZXJlbmNlcyB0aGF0IHdpbGwgZ2VuZXJhdGUgYSBsb3Qgb2YgYXJndW1lbnQgYmV0d2VlbiBwcm9mZXNzaW9uYWwgcHJvZ3JhbW1lcnMsIGJ1dCBhcmUgdW5saWtlbHkgdG8gbWF0dGVyIG11Y2ggdG8gcmVzZWFyY2ggc2NpZW50aXN0cy4gSW4gZ2VuZXJhbCwgeW91IHNob3VsZCBleHBsb3JlIHRoZSBSIGVjb3N5c3RlbSBmcmVlbHkgYW5kIHVzZSB3aGF0ZXZlciB5b3UgbGlrZS4gKipIb3dldmVyKiogb24gYXNzaWdubWVudHMsIGl0IGlzIHdpc2UgdG8gY2hlY2sgd2l0aCB0aGUgbGVjdHVyZXIgYmVmb3JlIHVzaW5nIHNvbWV0aGluZyB0aGF0IGlzIHJlYWxseSBkaWZmZXJlbnQgZnJvbSB3aGF0IGlzIHByZXNlbnRlZCBpbiBjbGFzcy4gWW91ciBsZWN0dXJlciBtYXksIGZvciBlZHVjYXRpb25hbCByZWFzb25zLCB3YW50IHlvdSB0byB1c2Ugc3BlY2lmaWMgUiB0b29scy4KCiMjIFdoYXQncyBOZXh0CgpGaWxsIGluIHRoZSBtb2R1bGUgZmVlZGJhY2sgZm9ybSA8aHR0cHM6Ly90aW55dXJsLmNvbS9yNHNzcC1tb2R1bGUtZmI+LgoKWW91IG1heSByZWNhbGwgdGhhdCB3YXkgYmFjayBpbiB0aGUgZmlyc3QgbW9kdWxlIG9mIHRoaXMgbWluaS1jb3Vyc2Ugd2Ugc2FpZCB3ZSB3ZXJlIGdvaW5nIHRvIGFuYWx5c2UgZGF0YS4gV2UgaGF2ZW4ndCByZWFsbHkgZG9uZSBtdWNoIG9mIHRoYXQgeWV0LiBTbyBmYXIgd2UgaGF2ZSBiZWVuICpnZXR0aW5nIHJlYWR5KiB0byBhbmFseXNlIGRhdGEuIEluIHRoZSBuZXh0IG1vZHVsZSwgd2Ugd2lsbCBzdGFydCByZWFsbHkgZGlnZ2luZyBpbnRvIG91ciBkYXRhIHdpdGggZXhwbG9yYXRvcnkgYW5hbHlzaXMgYW5kIGRlc2NyaXB0aXZlIHN0YXRpc3RpY3MuIEJlY2F1c2UgdGhpcyBpcyBub3QgYSBzdGF0aXN0aWNzIGNvdXJzZSAqcGVyIHNlKiB3ZSB3aWxsIG9ubHkgYmUgdXNpbmcgY29tbW9uIGdlbmVyYWwgYW5hbHlzZXMgaW4gdGhlIGhhbmRvdXRzIGFuZCByZWFkaW5ncy4gSWYsIGZvciBhIHByb2plY3Qgb3IgYXNzaWdubWVudCwgeW91IG5lZWQgdG8gZG8gc29tZXRoaW5nIG1vcmUgZXNvdGVyaWMsIGp1c3QgbGV0IHVzIGtub3cgLS0gc29tZW9uZSBoYXMgcHJvYmFibHkgd3JpdHRlbiBhbiBSIGxpYnJhcnkgZm9yIGl0LgoKCgoK