Overview: https://dplyr.tidyverse.org)
dplyr
is a grammar of data manipulation, providing a
consistent set of verbs that help you solve the most common data
manipulation challenges
Functions
select()
picks variables based on their
names.
filter()
picks cases based on their values.
mutate()
adds new variables that are functions of
existing variable
summarise()
reduces multiple values down to a single
summary.
arrange()
changes the ordering of the rows.
group_by()
takes an existing tbl and converts it
into a grouped tbl.
Subset columns using their names and types. Example uses
babynames
package as in Posit Primers: Work with Data.
- |
Columns except |
select(babynames, -prop) |
: |
Columns between (inclusive) |
select(babynames, year:n) |
contains() |
Columns that contains a string |
select(babynames, contains(“n”)) |
ends_with() |
Columns that ends with a string |
select(babynames, ends_with(“n”)) |
matches() |
Columns that matches a regex |
select(babynames, matches(“n”)) |
num_range() |
Columns with a numerical suffix in the range |
Not applicable with babynames |
one_of() |
Columns whose name appear in the given set |
select(babynames, one_of(c(“sex”, “gender”))) |
starts_with() |
Columns that starts with a string |
select(babynames, starts_with(“n”)) |
Columns except
select(iris, -Species)
Columns between
(inclusive)
select(iris, 3:5)
Columns that contains
a string
select(iris, contains("Sepal"))
Columns that ends
with a string
select(iris, ends_with("Width"))
Columns that matches
a regex
select(iris, matches("pe"))
Columns with a
numerical suffix in the range
Not applicable to iris
data
Columns whose name
appear in the given set
select(iris, one_of("Sepal.Length", "Petal.Width"))
Columns that starts
with a string
select(iris, starts_with("s"))
Columns by changing
names
select(iris, sl = Sepal.Length, sw = Sepal.Width, sp = Species)
Subset rows using column values
> |
Is x greater than y? |
x > y |
>= |
Is x greater than or equal to y? |
x >= y |
< |
Is x less than y? |
x < y |
<= |
Is x less than or equal to y? |
x <= y |
== |
Is x equal to y? |
x == y |
!= |
Is x not equal to y? |
x != y |
is.na() |
Is x an NA? |
is.na(x) |
!is.na() |
Is x not an NA? |
!is.na(x) |
Is x greater than
y?
filter(iris, Sepal.Length > 6.0)
Is x greater than or
equal to y?
And: &
filter(iris, Sepal.Length >= 5.0 & Sepal.Width >= 4.0)
Is x less than
y?
filter(iris, Sepal.Length < 5.0)
Is x less than or
equal to y?
OR: |
filter(iris, Sepal.Length >= 5.0 & Sepal.Width >= 4.0)
Is x equal to y?
filter(iris, Species=="virginica")
Is x an NA?
filter(iris, is.na(Sepal.Width))
Is x not an NA?
filter(iris, !is.na(Sepal.Width))
arrange()
orders the rows of a data frame by the values
of selected columns.
Unlike other dplyr
verbs, arrange()
largely
ignores grouping; you need to explicitly mention grouping variables (`or
use .by_group = TRUE) in order to group by them, and functions of
variables are evaluated once per data frame, not once per group.
arrange(iris, Sepal.Length, desc(Sepal.Width))
slice, slice_head, slice_tail, slice_min, slice_max, slice_sample
slice_min(iris, Sepal.Length, n = 6)
mutate(iris, rank = min_rank(Sepal.Length)) %>%
arrange(rank)
iris %>% mutate(Sepal.Ratio = Sepal.Length/Sepal.Width) %>%
arrange(Sepal.Ratio)
Most data operations are done on groups defined by
variables. group_by()
takes an existing tbl and converts it
into a grouped tbl where operations are performed “by
group”. ungroup()
removes grouping.
Summary functions
You can use any function in summarise()
so long as it
meets one criteria: the function must take a vector of values as input
and return a single value as output. Functions that do this are known as
summary functions and they are common in the field of descriptive
statistics. Some of the most useful summary functions include:
- Measures of location - mean(x), median(x), quantile(x, 0.25),
min(x), and max(x)
- Measures of spread - sd(x), var(x), IQR(x), and mad(x)
- Measures of position - first(x), nth(x, 2), and last(x)
- Counts - n_distinct(x) and n(), which takes no arguments, and
returns the size of the current group or data frame.
- Counts and proportions of logical values - sum(!is.na(x)), which
counts the number of TRUEs returned by a logical test; mean(y == 0),
which returns the proportion of TRUEs returned by a logical test.
- if_else(), recode(), case_when()
iris %>%
group_by(Species) %>%
summarize(sl_mean = mean(Sepal.Length), sw_mean = mean(Sepal.Width),
pl_mean = mean(Petal.Length), pw_mean = mean(Petal.Width))
iris %>%
group_by(Species) %>%
mutate(rank = min_rank(Sepal.Length)) %>%
arrange(rank)
Posit Primers
Please practice with Posit Primers - Work with Data
Work with Data
Learn the most important data handling skills in R: how to extract
values from a table, subset tables, calculate summary statistics, and
derive new variables.
Working with
Tibbles
Learn to use tibbles, the most user-friendly tabular data structure
in R, as well as how to manage tidyverse packages with... the tidyverse
package.
Isolating Data with
dplyr
Master three simple functions for finding, and extracting, the data
in your data set. Here you will learn to select variables, filter
observations, and arrange values. Here, you will also meet R’s pipe
operator, %>%.
Deriving Information
with dplyr
Data sets contain more information than they display, and this
tutorial will show you how to access that information. You’ll learn to
derive new variables and to compute groupwise summary statistics.
LS0tCnRpdGxlOiAiZHBseXIgd2l0aCBleGFtcGxlcyBvZiBpcmlzIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6IAogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKLS0tCgo+T3ZlcnZpZXc6IFtodHRwczovL2RwbHlyLnRpZHl2ZXJzZS5vcmddKGh0dHBzOi8vZHBseXIudGlkeXZlcnNlLm9yZykpCj4KPmBkcGx5cmAgaXMgYSBncmFtbWFyIG9mIGRhdGEgbWFuaXB1bGF0aW9uLCBwcm92aWRpbmcgYSBjb25zaXN0ZW50IHNldCBvZiB2ZXJicyB0aGF0IGhlbHAgeW91IHNvbHZlIHRoZSBtb3N0IGNvbW1vbiBkYXRhIG1hbmlwdWxhdGlvbiBjaGFsbGVuZ2VzCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmBgYAoKIyBGdW5jdGlvbnMKCi0gICBgc2VsZWN0KClgIHBpY2tzIHZhcmlhYmxlcyBiYXNlZCBvbiB0aGVpciBuYW1lcy4KCi0gICBgZmlsdGVyKClgIHBpY2tzIGNhc2VzIGJhc2VkIG9uIHRoZWlyIHZhbHVlcy4KCi0gICBgbXV0YXRlKClgIGFkZHMgbmV3IHZhcmlhYmxlcyB0aGF0IGFyZSBmdW5jdGlvbnMgb2YgZXhpc3RpbmcgdmFyaWFibGUKCi0gICBgc3VtbWFyaXNlKClgIHJlZHVjZXMgbXVsdGlwbGUgdmFsdWVzIGRvd24gdG8gYSBzaW5nbGUgc3VtbWFyeS4KCi0gICBgYXJyYW5nZSgpYCBjaGFuZ2VzIHRoZSBvcmRlcmluZyBvZiB0aGUgcm93cy4KCi0gICBgZ3JvdXBfYnkoKWAgdGFrZXMgYW4gZXhpc3RpbmcgdGJsIGFuZCBjb252ZXJ0cyBpdCBpbnRvIGEgZ3JvdXBlZCB0YmwuCgojIGBpcmlzYCBkYXRhCgpgYGB7cn0KaXJpcwpgYGAKCiMgW2BzZWxlY3RgXShodHRwczovL2RwbHlyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL3NlbGVjdC5odG1sKQoKU3Vic2V0IGNvbHVtbnMgdXNpbmcgdGhlaXIgbmFtZXMgYW5kIHR5cGVzLiBFeGFtcGxlIHVzZXMgYGJhYnluYW1lc2AgcGFja2FnZSBhcyBpbiBQb3NpdCBQcmltZXJzOiBXb3JrIHdpdGggRGF0YS4KCnwgSGVscGVyIEZ1bmN0aW9uIHwgVXNlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBFeGFtcGxlICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8LS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18CnwgXC0gICAgICAgICAgICAgIHwgQ29sdW1ucyBleGNlcHQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBzZWxlY3QoYmFieW5hbWVzLCAtcHJvcCkgICAgICAgICAgICAgICAgICAgICAgfAp8IDogICAgICAgICAgICAgICB8IENvbHVtbnMgYmV0d2VlbiAoaW5jbHVzaXZlKSAgICAgICAgICAgICAgICAgIHwgc2VsZWN0KGJhYnluYW1lcywgeWVhcjpuKSAgICAgICAgICAgICAgICAgICAgIHwKfCBjb250YWlucygpICAgICAgfCBDb2x1bW5zIHRoYXQgY29udGFpbnMgYSBzdHJpbmcgICAgICAgICAgICAgICB8IHNlbGVjdChiYWJ5bmFtZXMsIGNvbnRhaW5zKCJuIikpICAgICAgICAgICAgICB8CnwgZW5kc193aXRoKCkgICAgIHwgQ29sdW1ucyB0aGF0IGVuZHMgd2l0aCBhIHN0cmluZyAgICAgICAgICAgICAgfCBzZWxlY3QoYmFieW5hbWVzLCBlbmRzX3dpdGgoIm4iKSkgICAgICAgICAgICAgfAp8IG1hdGNoZXMoKSAgICAgICB8IENvbHVtbnMgdGhhdCBtYXRjaGVzIGEgcmVnZXggICAgICAgICAgICAgICAgIHwgc2VsZWN0KGJhYnluYW1lcywgbWF0Y2hlcygibiIpKSAgICAgICAgICAgICAgIHwKfCBudW1fcmFuZ2UoKSAgICAgfCBDb2x1bW5zIHdpdGggYSBudW1lcmljYWwgc3VmZml4IGluIHRoZSByYW5nZSB8IE5vdCBhcHBsaWNhYmxlIHdpdGggYmFieW5hbWVzICAgICAgICAgICAgICAgICB8Cnwgb25lX29mKCkgICAgICAgIHwgQ29sdW1ucyB3aG9zZSBuYW1lIGFwcGVhciBpbiB0aGUgZ2l2ZW4gc2V0ICAgfCBzZWxlY3QoYmFieW5hbWVzLCBvbmVfb2YoYygic2V4IiwgImdlbmRlciIpKSkgfAp8IHN0YXJ0c193aXRoKCkgICB8IENvbHVtbnMgdGhhdCBzdGFydHMgd2l0aCBhIHN0cmluZyAgICAgICAgICAgIHwgc2VsZWN0KGJhYnluYW1lcywgc3RhcnRzX3dpdGgoIm4iKSkgICAgICAgICAgIHwKCiMjIENvbHVtbnMgZXhjZXB0CgpgYGB7cn0Kc2VsZWN0KGlyaXMsIC1TcGVjaWVzKQpgYGAKCiMjIENvbHVtbnMgYmV0d2VlbiAoaW5jbHVzaXZlKQoKYGBge3J9CnNlbGVjdChpcmlzLCAzOjUpCmBgYAoKIyMgQ29sdW1ucyB0aGF0IGNvbnRhaW5zIGEgc3RyaW5nCgpgYGB7cn0Kc2VsZWN0KGlyaXMsIGNvbnRhaW5zKCJTZXBhbCIpKQpgYGAKCiMjIENvbHVtbnMgdGhhdCBlbmRzIHdpdGggYSBzdHJpbmcKCmBgYHtyfQpzZWxlY3QoaXJpcywgZW5kc193aXRoKCJXaWR0aCIpKQpgYGAKCiMjIENvbHVtbnMgdGhhdCBtYXRjaGVzIGEgcmVnZXgKCmBgYHtyfQpzZWxlY3QoaXJpcywgbWF0Y2hlcygicGUiKSkKYGBgCgojIyBDb2x1bW5zIHdpdGggYSBudW1lcmljYWwgc3VmZml4IGluIHRoZSByYW5nZQoKTm90IGFwcGxpY2FibGUgdG8gYGlyaXNgIGRhdGEKCiMjIENvbHVtbnMgd2hvc2UgbmFtZSBhcHBlYXIgaW4gdGhlIGdpdmVuIHNldAoKYGBge3J9CnNlbGVjdChpcmlzLCBvbmVfb2YoIlNlcGFsLkxlbmd0aCIsICJQZXRhbC5XaWR0aCIpKQpgYGAKCiMjIENvbHVtbnMgdGhhdCBzdGFydHMgd2l0aCBhIHN0cmluZwoKYGBge3J9CnNlbGVjdChpcmlzLCBzdGFydHNfd2l0aCgicyIpKQpgYGAKCiMjIENvbHVtbnMgYnkgY2hhbmdpbmcgbmFtZXMKCmBgYHtyfQpzZWxlY3QoaXJpcywgc2wgPSBTZXBhbC5MZW5ndGgsIHN3ID0gU2VwYWwuV2lkdGgsIHNwID0gU3BlY2llcykKYGBgCgojIFtgZmlsdGVyYF0oaHR0cHM6Ly9kcGx5ci50aWR5dmVyc2Uub3JnL3JlZmVyZW5jZS9maWx0ZXIuaHRtbCkKClN1YnNldCByb3dzIHVzaW5nIGNvbHVtbiB2YWx1ZXMKCnwgTG9naWNhbCBvcGVyYXRvciB8IHRlc3RzICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgRXhhbXBsZSAgIHwKfC0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tfAp8IFw+ICAgICAgICAgICAgICAgfCBJcyB4IGdyZWF0ZXIgdGhhbiB5PyAgICAgICAgICAgICB8IHggXD4geSAgICB8CnwgXD49ICAgICAgICAgICAgICB8IElzIHggZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvIHk/IHwgeCBcPj0geSAgIHwKfCBcPCAgICAgICAgICAgICAgIHwgSXMgeCBsZXNzIHRoYW4geT8gICAgICAgICAgICAgICAgfCB4IFw8IHkgICAgfAp8IFw8PSAgICAgICAgICAgICAgfCBJcyB4IGxlc3MgdGhhbiBvciBlcXVhbCB0byB5PyAgICB8IHggXDw9IHkgICB8CnwgPT0gICAgICAgICAgICAgICB8IElzIHggZXF1YWwgdG8geT8gICAgICAgICAgICAgICAgIHwgeCA9PSB5ICAgIHwKfCAhPSAgICAgICAgICAgICAgIHwgSXMgeCBub3QgZXF1YWwgdG8geT8gICAgICAgICAgICAgfCB4ICE9IHkgICAgfAp8IGlzLm5hKCkgICAgICAgICAgfCBJcyB4IGFuIE5BPyAgICAgICAgICAgICAgICAgICAgICB8IGlzLm5hKHgpICB8CnwgIWlzLm5hKCkgICAgICAgICB8IElzIHggbm90IGFuIE5BPyAgICAgICAgICAgICAgICAgIHwgIWlzLm5hKHgpIHwKCiMjIElzIHggZ3JlYXRlciB0aGFuIHk/CgpgYGB7cn0KZmlsdGVyKGlyaXMsIFNlcGFsLkxlbmd0aCA+IDYuMCkKYGBgCgojIyBJcyB4IGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byB5PwoKQW5kOiAmCgpgYGB7cn0KZmlsdGVyKGlyaXMsIFNlcGFsLkxlbmd0aCA+PSA1LjAgJiBTZXBhbC5XaWR0aCA+PSA0LjApCmBgYAoKIyMgSXMgeCBsZXNzIHRoYW4geT8KCmBgYHtyfQpmaWx0ZXIoaXJpcywgU2VwYWwuTGVuZ3RoIDwgNS4wKQpgYGAKCiMjIElzIHggbGVzcyB0aGFuIG9yIGVxdWFsIHRvIHk/CgpPUjogXHwKCmBgYHtyfQpmaWx0ZXIoaXJpcywgU2VwYWwuTGVuZ3RoID4gNy4wIHwgU2VwYWwuV2lkdGggPj0gNC4wKQpgYGAKCiMjIElzIHggZXF1YWwgdG8geT8KCmBgYHtyfQpmaWx0ZXIoaXJpcywgU3BlY2llcz09InZpcmdpbmljYSIpCmBgYAoKIyMgSXMgeCBhbiBOQT8KCmBgYHtyfQpmaWx0ZXIoaXJpcywgaXMubmEoU2VwYWwuV2lkdGgpKQpgYGAKCiMjIElzIHggbm90IGFuIE5BPwoKYGBge3J9CmZpbHRlcihpcmlzLCAhaXMubmEoU2VwYWwuV2lkdGgpKQpgYGAKCiMjIEV4dHJhCgpgYGB7cn0KZmlsdGVyKGlyaXMsIFNlcGFsLldpZHRoID4gUGV0YWwuTGVuZ3RoKQpgYGAKCiMgW2BhcnJhbmdlYF0oaHR0cHM6Ly9kcGx5ci50aWR5dmVyc2Uub3JnL3JlZmVyZW5jZS9hcnJhbmdlLmh0bWwpCgotICAgYGFycmFuZ2UoKWAgb3JkZXJzIHRoZSByb3dzIG9mIGEgZGF0YSBmcmFtZSBieSB0aGUgdmFsdWVzIG9mIHNlbGVjdGVkIGNvbHVtbnMuCgpVbmxpa2Ugb3RoZXIgYGRwbHlyYCB2ZXJicywgYGFycmFuZ2UoKWAgbGFyZ2VseSBpZ25vcmVzIGdyb3VwaW5nOyB5b3UgbmVlZCB0byBleHBsaWNpdGx5IG1lbnRpb24gZ3JvdXBpbmcgdmFyaWFibGVzIChcYG9yIHVzZSAuYnlfZ3JvdXAgPSBUUlVFKSBpbiBvcmRlciB0byBncm91cCBieSB0aGVtLCBhbmQgZnVuY3Rpb25zIG9mIHZhcmlhYmxlcyBhcmUgZXZhbHVhdGVkIG9uY2UgcGVyIGRhdGEgZnJhbWUsIG5vdCBvbmNlIHBlciBncm91cC4KCmBgYHtyfQphcnJhbmdlKGlyaXMsIFNlcGFsLkxlbmd0aCwgZGVzYyhTZXBhbC5XaWR0aCkpCmBgYAoKIyMgYHNsaWNlLCBzbGljZV9oZWFkLCBzbGljZV90YWlsLCBzbGljZV9taW4sIHNsaWNlX21heCwgc2xpY2Vfc2FtcGxlYAoKYGBge3J9CnNsaWNlX21pbihpcmlzLCBTZXBhbC5MZW5ndGgsIG4gPSA2KQpgYGAKCiMgW2BwaXBlc2BdKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovcGlwZXMuaHRtbClgKFI0RFMpYAoKIyBbYG11dGF0ZWBdKGh0dHBzOi8vZHBseXIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvbXV0YXRlLmh0bWwpCgotICAgQ3JlYXRlLCBtb2RpZnksIGFuZCBkZWxldGUgY29sdW1ucwoKLSAgIFVzZWZ1bCBtdXRhdGUgZnVuY3Rpb25zCgogICAgLSAgICssIC0sIGxvZygpLCBldGMuLCBmb3IgdGhlaXIgdXN1YWwgbWF0aGVtYXRpY2FsIG1lYW5pbmdzCgogICAgLSAgIGxlYWQoKSwgbGFnKCkKCiAgICAtICAgZGVuc2VfcmFuaygpLCBtaW5fcmFuaygpLCBwZXJjZW50X3JhbmsoKSwgcm93X251bWJlcigpLCBjdW1lX2Rpc3QoKSwgbnRpbGUoKQoKICAgIC0gICBjdW1zdW0oKSwgY3VtbWVhbigpLCBjdW1taW4oKSwgY3VtbWF4KCksIGN1bWFueSgpLCBjdW1hbGwoKQoKICAgIC0gICBuYV9pZigpLCBjb2FsZXNjZSgpCgpgYGB7cn0KbXV0YXRlKGlyaXMsIHJhbmsgPSBtaW5fcmFuayhTZXBhbC5MZW5ndGgpKSAlPiUKICBhcnJhbmdlKHJhbmspCmBgYAoKYGBge3J9CmlyaXMgJT4lIG11dGF0ZShTZXBhbC5SYXRpbyA9IFNlcGFsLkxlbmd0aC9TZXBhbC5XaWR0aCkgJT4lCiAgYXJyYW5nZShTZXBhbC5SYXRpbykKYGBgCgojIFtgZ3JvdXBfYnlgXShodHRwczovL2RwbHlyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL2dyb3VwX2J5Lmh0bWwpCgpNb3N0IGRhdGEgb3BlcmF0aW9ucyBhcmUgZG9uZSBvbiBncm91cHMgZGVmaW5lZCBieSB2YXJpYWJsZXMuwqBgZ3JvdXBfYnkoKWDCoHRha2VzIGFuIGV4aXN0aW5nIHRibCBhbmQgY29udmVydHMgaXQgaW50byBhIGdyb3VwZWQgdGJsIHdoZXJlIG9wZXJhdGlvbnMgYXJlIHBlcmZvcm1lZCAiYnkgZ3JvdXAiLsKgYHVuZ3JvdXAoKWByZW1vdmVzIGdyb3VwaW5nLgoKIyBbYHN1bW1hcmlzZWAgb3IgYHN1bW1hcml6ZWBdKGh0dHBzOi8vZHBseXIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2Uvc3VtbWFyaXNlLmh0bWwpCgojIyBTdW1tYXJ5IGZ1bmN0aW9ucyB7LnVubnVtYmVyZWR9CgpZb3UgY2FuIHVzZSBhbnkgZnVuY3Rpb24gaW4gYHN1bW1hcmlzZSgpYCBzbyBsb25nIGFzIGl0IG1lZXRzIG9uZSBjcml0ZXJpYTogdGhlIGZ1bmN0aW9uIG11c3QgdGFrZSBhIHZlY3RvciBvZiB2YWx1ZXMgYXMgaW5wdXQgYW5kIHJldHVybiBhIHNpbmdsZSB2YWx1ZSBhcyBvdXRwdXQuIEZ1bmN0aW9ucyB0aGF0IGRvIHRoaXMgYXJlIGtub3duIGFzIHN1bW1hcnkgZnVuY3Rpb25zIGFuZCB0aGV5IGFyZSBjb21tb24gaW4gdGhlIGZpZWxkIG9mIGRlc2NyaXB0aXZlIHN0YXRpc3RpY3MuIFNvbWUgb2YgdGhlIG1vc3QgdXNlZnVsIHN1bW1hcnkgZnVuY3Rpb25zIGluY2x1ZGU6CgoxLiAgTWVhc3VyZXMgb2YgbG9jYXRpb24gLSBtZWFuKHgpLCBtZWRpYW4oeCksIHF1YW50aWxlKHgsIDAuMjUpLCBtaW4oeCksIGFuZCBtYXgoeCkKMi4gIE1lYXN1cmVzIG9mIHNwcmVhZCAtIHNkKHgpLCB2YXIoeCksIElRUih4KSwgYW5kIG1hZCh4KQozLiAgTWVhc3VyZXMgb2YgcG9zaXRpb24gLSBmaXJzdCh4KSwgbnRoKHgsIDIpLCBhbmQgbGFzdCh4KQo0LiAgQ291bnRzIC0gbl9kaXN0aW5jdCh4KSBhbmQgbigpLCB3aGljaCB0YWtlcyBubyBhcmd1bWVudHMsIGFuZCByZXR1cm5zIHRoZSBzaXplIG9mIHRoZSBjdXJyZW50IGdyb3VwIG9yIGRhdGEgZnJhbWUuCjUuICBDb3VudHMgYW5kIHByb3BvcnRpb25zIG9mIGxvZ2ljYWwgdmFsdWVzIC0gc3VtKCFpcy5uYSh4KSksIHdoaWNoIGNvdW50cyB0aGUgbnVtYmVyIG9mIFRSVUVzIHJldHVybmVkIGJ5IGEgbG9naWNhbCB0ZXN0OyBtZWFuKHkgPT0gMCksIHdoaWNoIHJldHVybnMgdGhlIHByb3BvcnRpb24gb2YgVFJVRXMgcmV0dXJuZWQgYnkgYSBsb2dpY2FsIHRlc3QuCjYuICBpZl9lbHNlKCksIHJlY29kZSgpLCBjYXNlX3doZW4oKQoKYGBge3J9CmlyaXMgJT4lIAogIGdyb3VwX2J5KFNwZWNpZXMpICU+JSAKICBzdW1tYXJpemUoc2xfbWVhbiA9IG1lYW4oU2VwYWwuTGVuZ3RoKSwgc3dfbWVhbiA9IG1lYW4oU2VwYWwuV2lkdGgpLCAKICBwbF9tZWFuID0gbWVhbihQZXRhbC5MZW5ndGgpLCBwd19tZWFuID0gbWVhbihQZXRhbC5XaWR0aCkpCmBgYAoKYGBge3J9CmlyaXMgJT4lIAogIGdyb3VwX2J5KFNwZWNpZXMpICU+JQogIG11dGF0ZShyYW5rID0gbWluX3JhbmsoU2VwYWwuTGVuZ3RoKSkgJT4lCiAgYXJyYW5nZShyYW5rKQpgYGAKCiMgUG9zaXQgUHJpbWVycwoKUGxlYXNlIHByYWN0aWNlIHdpdGggUG9zaXQgUHJpbWVycyAtIFdvcmsgd2l0aCBEYXRhCgpbV29yayB3aXRoIERhdGFdKGh0dHBzOi8vcG9zaXQuY2xvdWQvbGVhcm4vcHJpbWVycy8yKQoKPiBMZWFybiB0aGUgbW9zdCBpbXBvcnRhbnQgZGF0YSBoYW5kbGluZyBza2lsbHMgaW4gUjogaG93IHRvIGV4dHJhY3QgdmFsdWVzIGZyb20gYSB0YWJsZSwgc3Vic2V0IHRhYmxlcywgY2FsY3VsYXRlIHN1bW1hcnkgc3RhdGlzdGljcywgYW5kIGRlcml2ZSBuZXcgdmFyaWFibGVzLgoKW1dvcmtpbmcgd2l0aCBUaWJibGVzXShodHRwczovL3Bvc2l0LmNsb3VkL2xlYXJuL3ByaW1lcnMvMi4xKQoKTGVhcm4gdG8gdXNlIHRpYmJsZXMsIHRoZSBtb3N0IHVzZXItZnJpZW5kbHkgdGFidWxhciBkYXRhIHN0cnVjdHVyZSBpbiBSLCBhcyB3ZWxsIGFzIGhvdyB0byBtYW5hZ2UgdGlkeXZlcnNlIHBhY2thZ2VzIHdpdGhcLi4uIHRoZSB0aWR5dmVyc2UgcGFja2FnZS4KCltJc29sYXRpbmcgRGF0YSB3aXRoIGRwbHlyXShodHRwczovL3Bvc2l0LmNsb3VkL2xlYXJuL3ByaW1lcnMvMi4yKQoKTWFzdGVyIHRocmVlIHNpbXBsZSBmdW5jdGlvbnMgZm9yIGZpbmRpbmcsIGFuZCBleHRyYWN0aW5nLCB0aGUgZGF0YSBpbiB5b3VyIGRhdGEgc2V0LiBIZXJlIHlvdSB3aWxsIGxlYXJuIHRvIHNlbGVjdCB2YXJpYWJsZXMsIGZpbHRlciBvYnNlcnZhdGlvbnMsIGFuZCBhcnJhbmdlIHZhbHVlcy4gSGVyZSwgeW91IHdpbGwgYWxzbyBtZWV0IFIncyBwaXBlIG9wZXJhdG9yLCAlXD4lLgoKW0Rlcml2aW5nIEluZm9ybWF0aW9uIHdpdGggZHBseXJdKGh0dHBzOi8vcG9zaXQuY2xvdWQvbGVhcm4vcHJpbWVycy8yLjMpCgpEYXRhIHNldHMgY29udGFpbiBtb3JlIGluZm9ybWF0aW9uIHRoYW4gdGhleSBkaXNwbGF5LCBhbmQgdGhpcyB0dXRvcmlhbCB3aWxsIHNob3cgeW91IGhvdyB0byBhY2Nlc3MgdGhhdCBpbmZvcm1hdGlvbi4gWW91J2xsIGxlYXJuIHRvIGRlcml2ZSBuZXcgdmFyaWFibGVzIGFuZCB0byBjb21wdXRlIGdyb3Vwd2lzZSBzdW1tYXJ5IHN0YXRpc3RpY3MuCg==