Data Organization in R
Data in R can be stored as a variety of data types and organized in a
variety of data structures. We can also recode data in R depending on
our research needs.
This section covers how data is organized in R and how to clean a
dataset. Understanding how your data is organized and being able to
adjust that organization to match your research needs is an important
part of research data management. For example, you might need your data
to be in a certain structure to run certain statistical analyses or you
may need to transform variables into versions that are more easily
understood.
[Source]
This section covers five main topics:
- What data types exist in R
- What data structures exist in R
- Introduction to the
dplyr
package
- Recoding existing data into another type of data
- Dealing with missing values
Let’s get started!
Data Types in R
Data can come in many different formats or units. Sometimes we have
numbers with decimals, sometimes we have counts of how many times
something happened, and sometimes we have categories with names. It is
important to know what type of data you have, how to figure that out in
R, and how to modify the data type if needed. Various functions in R
require using certain data types, so these are important foundational
skill for managing data in R.
Numeric Data
Numeric data is data made up of numbers. This is what we most
commonly think of as data, and this data type can have decimals. For
example, how many hours people slept on a given day (6, 8.25, 7.5), the
percent accuracy that students got on an exam (87.45, 75.92, 98.40), or
number of people who attended a data management workshop each day (32,
38, 28).
Integer Data
This data type deals with whole numbers (i.e., no decimals) and
operates similarly to numeric data types. Some data can be stored as
“numeric” and “integer” at the same time.
Character/String Data
Character variables are variables with words or letters. Such as
names of people (Erin, Maria, Huy) or places (ON, BC, QC). Character
variables usually need to be put in quotation marks in R code, so they
are not confused with words that actually denote functions in R.
Factors
Factors are how R handles categorical data. Factors can store string
or integer data, because sometimes numbers do represent categories
(rather than a continuous range of numbers).Factors have leveled data.
For example, the variable of education may have the levels of “high
school,” “bachelors degree,” and “masters degree.” Factors can be
ordered or unordered. Factor structure is particularly useful for
statistical modeling.
We will create some factor variables later in this section.
Dates and Times
Data can also be stored in date and/or time format in R. Our data
doesn’t contain dates or times, but we want to let you know this is
possible. Date data would typically look like “22-05-2025” or
“2025-05-22.” Times could look like “11:12:34.”
Logical Data
Logical data includes TRUE
and FALSE
data.
We can also ask R to provide us TRUE
or FALSE
response if we ask if a condition is met.
Data Structures in R
Data structures are how the data is organized in R. Here are the
major data structures in R. There are some additional structures (e.g.,
matrices and arrays) that are mostly used only when doing statistical
modeling. We will skip over these for now and focus on the data
structures you will likely encounter in a research data management
context.
Vectors
Vectors are the simplest data structure. They are essentially a list
of elements of the same data type. For example, you could have a numeric
vector containing the elements (10, 15, 20, 25) or a character vector
containing the elements (“blue”, “red”, “green”). They are one
dimensional, since they are just one long list. A single variable (e.g.,
a list of ages of all the participants) can be considered a vector.
Data Frames
Data frames are the most common and popular type of data structure
used in R. Data frames work essentially like spreadsheets in that they
are two dimensional (i.e., have columns and rows) and can store
different data types in the same data frame (i.e., numeric and
character). Data frames are made up of vectors of the same length.
However, data frames do have some constraints. First, the columns and
rows must be named. Second, the lists of vectors in the data frame must
have equal lengths (i.e., each column needs an identical number of
elements/rows). Third, all elements in a single column must be of the
same data type (i.e., you can’t switch between numbers and names in a
single column).
You may see mention of tibbles, which are an updated version of data
frames and part of the tidyverse package, and have the same constraints
as data frames. They are a bit more user-friendly version of tabular
data.
For this course, our data is in data frame format.
Lists
Lists are an ordered collection of elements. They can contain
different data types and they are one dimensional. You can also have
lists that contain a series of vectors or data frames. We don’t often
have data in list form, but because lists can contain elements of
different lengths (unlike data frames) some functions in R will output
results into list format, so it is good to be aware of them. Here is an
example of a list:
list_example <- list("red", 400, "skyblue", "forestgreen", .333)
list_example
## [[1]]
## [1] "red"
##
## [[2]]
## [1] 400
##
## [[3]]
## [1] "skyblue"
##
## [[4]]
## [1] "forestgreen"
##
## [[5]]
## [1] 0.333
Because lists are ordered (i.e., each element in the list has a
specific spot in the list), you can call for an element based on the
order it has been assigned. For example, “skyblue” is third in this
example list.
list_example [3]
## [[1]]
## [1] "skyblue"
Introduction to dplyr
In order to check and modify data types we suggest using the
dplyr
package, which is part of the tidyverse.
dplyr
is a powerful R package designed to simplify data
manipulation tasks. It provides a set of intuitive functions that help
with filtering, selecting, and transforming data frames. It is the go to
package for data organization. We will use just a few of the functions
of this package in this course, but there are many more applications of
dplyr
you can explore. You can find more information about
dplyr
on the
tidyverse
website.
Here are some of the most common functions of dplyr
. We
will practice using some of these today with our dataset.
mutate()
: Useful when you want to create new columns
based on values in existing columns in your dataset. For example, you
may want to recode numeric data into new categories with character
names.
recode()
: Useful for changing data format of
variables or re-categorizing certain values in a variable as some other
value. For example, maybe you want to label everyone who sleeps less
than seven hours a night as “sleep deprived.”
group_by()
: Allows you to view your data based on
groups that you define or already exist in your data. For example, you
may want to group your data based on whether people live in a city or
rural area, or by gender.
summarize()
or summarise()
: Useful for
seeing basic descriptive info about your data. This is particularly
helpful when use with the group_by()
function. For example,
you can see if people in cities compared to rural areas feel more rushed
on average (i.e., compare means between these two groups).
|>
(pipe operator): Allows you to tell R to apply
one function several times. You can read it more or less as “and then”
when thinking about what your R code is doing.
filter()
: This function allows you to extract rows
that meet specific conditions you include.
select()
: This function lets you choose particular
columns based on your specifications.
It is important when using dplyr
to assign your output
to an object if you want to retain the info you’ve found or created.
Remember the <-
symbol can be used to assign output to a
named object. We will practice this today too.
Together, these functions in dplyr
enable you to easily
explore your data by various subgroups, create new variables, or create
a focused subset of your data for further analysis.
Let’s explore the data types in our data using the dplyr
functions!
Checking Data Types
First we load the dplyr
package (remember to install it
first if you haven’t yet). Y If you have installed the
tidyverse
package, then dplyr
was also
included. However, it is best practice to just load in the libraries you
need (i.e., just dplyr
and not all of the tidyverse
packages) to save space.
We will also load in our data. Yesterday we used the
read_csv
function to read in the csv file, but now we are
working with an Rdata file we saved yesterday, so we can use the
load
function.
library(dplyr)
load("data/timeuse_day2.Rdata")
Just to reacquaint ourselves with our data, use the head
function to peak at the first 6 rows of our data.
head(js_data)
id
|
ageGrp
|
sex
|
maritalStat
|
province
|
popCenter
|
eduLevel
|
feelRushed
|
extraTime
|
durSleep
|
durMealPrep
|
durEating
|
durAlone
|
durDriving
|
durWork
|
durShoolSite
|
durSchoolOnline
|
durStudy
|
mainStudy
|
mainJobHunting
|
mainWork
|
worked12m
|
workedWeek
|
enrollStat
|
dailyTexts
|
timeSlowDown
|
timeWorkaholic
|
timeNotFamFriends
|
timeWantAlone
|
10000
|
5
|
1
|
5
|
46
|
1
|
3
|
1
|
1
|
510
|
60
|
120
|
770
|
90
|
0
|
0
|
0
|
0
|
NA
|
1
|
1
|
1
|
2
|
NA
|
8
|
2
|
2
|
2
|
2
|
10001
|
5
|
1
|
1
|
59
|
1
|
4
|
3
|
4
|
420
|
150
|
0
|
0
|
0
|
0
|
0
|
0
|
0
|
NA
|
2
|
1
|
1
|
2
|
NA
|
1
|
2
|
2
|
2
|
2
|
10002
|
4
|
2
|
1
|
47
|
1
|
5
|
1
|
6
|
570
|
0
|
0
|
630
|
30
|
480
|
0
|
0
|
0
|
NA
|
NA
|
NA
|
1
|
1
|
NA
|
7
|
2
|
1
|
1
|
1
|
10003
|
6
|
2
|
5
|
35
|
1
|
4
|
2
|
4
|
510
|
10
|
45
|
875
|
80
|
20
|
0
|
0
|
0
|
NA
|
NA
|
NA
|
1
|
1
|
NA
|
1
|
2
|
2
|
2
|
2
|
10004
|
2
|
1
|
6
|
35
|
1
|
NA
|
1
|
3
|
525
|
90
|
40
|
815
|
0
|
0
|
0
|
0
|
0
|
NA
|
NA
|
NA
|
2
|
2
|
NA
|
1
|
2
|
2
|
2
|
2
|
10005
|
1
|
1
|
6
|
35
|
1
|
1
|
1
|
6
|
435
|
0
|
0
|
430
|
40
|
530
|
0
|
0
|
0
|
NA
|
NA
|
NA
|
1
|
1
|
NA
|
2
|
2
|
1
|
1
|
2
|
We can check the data type of variables using the
class()
function and calling for a specific variable from
our dataset js_data
using the $
operator,
followed by the name of our variable.
class(js_data$durWork)
## [1] "numeric"
Try exploring the data type of a few other variables on your own.
Recoding Data Types
For some variables, we might want to change the data type based on
our codebook. For instance, we can see that our “province” variable is
in numeric format.
class(js_data$province)
## [1] "numeric"
However, maybe we would prefer to have province acronyms (i.e.,
factor format) rather than the numeric representation of them. We can
re-code variables using the dplyr functions |>
and
mutate()
. The possible values for the province variable,
and what province they represent can be found in the dataset
codebook.
js_data <- js_data |> mutate(province_fact = recode_factor(js_data$province,
"10" = "NL",
"11" = "PEI",
"12" = "NS",
"13" = "NB",
"24" = "QC",
"35" = "ON",
"46" = "MB",
"47" = "SK",
"48" = "AB",
"59" = "BC"))
This code is telling R to use the function
recode_factor()
to recode the variable “province” from the
dataset “js_data” into a new variable called “province_fact” (you could
call it anything, but make sure it is a meaningful name).
The list outlines how each value of the current “province”
variable should be recoded for the new “province_fact”
variable.
The mutate()
portion tells R to create a new column
called “province_fact”.
Before the mutate()
function this code tells R to
take the “js_data” object (i.e., the dataset) “and then” (i.e., the pipe
function) apply the following functions.
The pipe function (|>
) tells R to recode all of
these values all at once, rather than having to write out
mutate()
and recode()
for each one.
Lastly, all of this work needs to be assigned back to our dataset
“js_data” using teh <-
symbol in order to keep our work
in our environment.
We did not assign this work to replace/overwrite the existing
“province” variable. In order to have transparent data management and to
prevent overwriting the original data in the instance that you make a
mistake in your recoding, it is always best practice to keep the
original variables in their original format and create new variables
based on them as needed. In this way, if you ever need to reference the
original data (and you definitely will need to), you still have it
available to you.
Now lets check the data type of this new variable we just
created.
class(js_data$province_fact)
## [1] "factor"
An alternative way to check your data types is using the
is.numeric
, is.factor
, or other variations of
this function. With this function you will get a logical operator as the
output. These are base R functions, and not from the tidyverse.
is.numeric(js_data$province_fact)
## [1] FALSE
is.factor(js_data$province_fact)
## [1] TRUE
Sometimes you may want to change the data type without recoding all
of the data. In this case a useful function is
as.numeric()
. Because this data is already stored in
numeric format, this function will not change the data type in this
instance, but this can be helpful for other datasets you may work with
in the future. Here is an example of how you would use this function.
This is a base R function, and not from the tidyverse.
as.numeric(js_data$durSleep)
Missing Data
You may have noticed that there are some cells in the data with
NA
This represents missing data in our dataset. Most
datasets having missing data. There are many reasons for missing data
and many different ways to handle missing data. These choices will
depend on the context of specific research, but generally you should
plan for how to approach missing data in advance.
In the original dataset, missing data had been notated with various
numerical codes (you can see these in the original codebook), but we
have recoded the data so that all missing data as been denoted
NA
If your data contains NA values, sometimes functions will give error
messages due to incomplete data. For example, if you try to get the mean
of education level (eduLevel), R will not provide one because it can’t
calculate a mean when there are missing values.
Note: getting a mean for education level, which is a categorical
variable, is not a meaningful number. However, it is used here to
illustrate this point, given that the continuous numeric variables in
this dataset do not contain missing values.
mean(js_data$eduLevel)
## [1] NA
If we look up the mean
function (i.e., run
help(mean) in your console)
, we can see that the default
for mean
is to have na.rm = FALSE
.
Instead, we tell R to ignore those missing values. Including
na.rm = TRUE
to the function will typically tell R that it
should complete the function, ignoring missing values.
mean(js_data$eduLevel, na.rm = TRUE)
## [1] 3.723747
If you want to check if a variable or data frame has missing data,
you can use the function is.na
.
is.na(js_data$eduLevel)
If you want to know the number of cells with missing data for a given
variable you can use the same function, wrapped in the sum
function. We can layer functions like this, with R reading the functions
starting from inside the parentheses and then moving outwards. We will
continue to work with syntax like this throughout the week.
sum(is.na(js_data$eduLevel))
## [1] 630
If you want to find instances where there is no missing data you can
use complete.cases()
.
complete.cases(js_data)
If you want to know the total number of rows (i.e., participants)
with no missing data you can take the complete.cases()
function and wrap it in the sum()
function.
sum(complete.cases(js_data))
## [1] 699
Your Turn!
Recoding Data Types
What type of data is the variable for marital status?
class(js_data$maritalStat)
Can you re-code marital status into a factor variable?
js_data<-js_data |> mutate(maritalStat_fact = recode_factor(js_data$maritalStat,
"1" = "Married",
"2" = "Living common-law",
"3" = "Widowed",
"4" = "Separated",
"5" = "Divorced",
"6" = "Single, never married"))
class(js_data$maritalStat_fact)
Can you recode level of education into a factor variable?
js_data <- js_data |> mutate(eduLevel_fact = recode_factor(js_data$eduLevel,
"1" = "Less than high school dimploma or its equivalent",
"2" = "High school diploma or equivalency",
"3" = "Trade certificate or diploma",
"4" = "College, CEGEP, or other non-university certificate or dimploma",
"5" = "University certificate or dimploma below the bachelor's level",
"6" = "Bachelor's degree",
"7" = "University certificate, diploma, degree above the BA level"))
class(js_data$eduLevel_fact)
Check Your Knowledge
What data structure would you use to store the following data?
The names of 10 most popular movies this year (10 data
points)
The names of the leading actor from each of the 10 most popular
movies this year (10 data points total)
A collection of all of the actors in each of the 10 most popular
movies this year (100 data points total)
A combination of a and b
A combination of a, b, and c
The data we have been working with in this workshop
Is our data in a data frame format? Hint: use the function
“is.data.frame()”
LS0tCnRpdGxlOiAiRGF0YSBUeXBlcyBhbmQgU3RydWN0dXJlcyBpbiBSIgpwYWdldGl0bGU6ICJEYXRhIFR5cGVzIGFuZCBTdHJ1Y3R1cmVzIGluIFIiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgY29kZV9mb2xkaW5nOiBzaG93ICMgYWxsb3dzIHRvZ2dsaW5nIG9mIHNob3dpbmcgYW5kIGhpZGluZyBjb2RlLiBSZW1vdmUgaWYgbm90IHVzaW5nIGNvZGUuCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlICMgYWxsb3dzIHRoZSB1c2VyIHRvIGRvd25sb2FkIHRoZSBzb3VyY2UgLlJtZCBmaWxlLiBSZW1vdmUgaWYgbm90IHVzaW5nIGNvZGUuCiAgICBpbmNsdWRlczoKICAgICAgYWZ0ZXJfYm9keTogZm9vdGVyLmh0bWwgIyBpbmNsdWRlIGEgY3VzdG9tIGZvb3Rlci4KICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAzCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogZmFsc2UKICAgICAgc21vb3RoX3Njcm9sbDogZmFsc2UKLS0tCgpgYGB7ciwgbGlicmFyaWVzLCBpbmNsdWRlID0gRkFMU0V9CmxpYnJhcnkoa2FibGVFeHRyYSkKYGBgCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmdzID0gRkFMU0UpCmBgYAoKCiMjIERhdGEgT3JnYW5pemF0aW9uIGluIFIKCgo6OjppbnRybwpEYXRhIGluIFIgY2FuIGJlIHN0b3JlZCBhcyBhIHZhcmlldHkgb2YgZGF0YSB0eXBlcyBhbmQgb3JnYW5pemVkIGluIGEgdmFyaWV0eSBvZiBkYXRhIHN0cnVjdHVyZXMuIFdlIGNhbiBhbHNvIHJlY29kZSBkYXRhIGluIFIgZGVwZW5kaW5nIG9uIG91ciByZXNlYXJjaCBuZWVkcy4KOjo6CgpUaGlzIHNlY3Rpb24gY292ZXJzIGhvdyBkYXRhIGlzIG9yZ2FuaXplZCBpbiBSIGFuZCBob3cgdG8gY2xlYW4gYSBkYXRhc2V0LiBVbmRlcnN0YW5kaW5nIGhvdyB5b3VyIGRhdGEgaXMgb3JnYW5pemVkIGFuZCBiZWluZyBhYmxlIHRvIGFkanVzdCB0aGF0IG9yZ2FuaXphdGlvbiB0byBtYXRjaCB5b3VyIHJlc2VhcmNoIG5lZWRzIGlzIGFuIGltcG9ydGFudCBwYXJ0IG9mIHJlc2VhcmNoIGRhdGEgbWFuYWdlbWVudC4gRm9yIGV4YW1wbGUsIHlvdSBtaWdodCBuZWVkIHlvdXIgZGF0YSB0byBiZSBpbiBhIGNlcnRhaW4gc3RydWN0dXJlIHRvIHJ1biBjZXJ0YWluIHN0YXRpc3RpY2FsIGFuYWx5c2VzIG9yIHlvdSBtYXkgbmVlZCB0byB0cmFuc2Zvcm0gdmFyaWFibGVzIGludG8gdmVyc2lvbnMgdGhhdCBhcmUgbW9yZSBlYXNpbHkgdW5kZXJzdG9vZC4gCgohW10oaW1hZ2VzL3RpZHl2ZXJzZS13b3JrZmxvdy5wbmcpCjxhIGhyZWY9Imh0dHBzOi8vdGVsYXBwcy5sb25kb24uZWR1L2FuYWx5dGljc193aXRoX1IvdGlkeXZlcnNlLmh0bWwiPltTb3VyY2VdPC9hPgoKOjo6bm90ZQpUaGlzIHNlY3Rpb24gY292ZXJzIGZpdmUgbWFpbiB0b3BpY3M6CgoxLiBXaGF0IGRhdGEgdHlwZXMgZXhpc3QgaW4gUgoyLiBXaGF0IGRhdGEgc3RydWN0dXJlcyBleGlzdCBpbiBSCjMuIEludHJvZHVjdGlvbiB0byB0aGUgYGRwbHlyYCBwYWNrYWdlCjQuIFJlY29kaW5nIGV4aXN0aW5nIGRhdGEgaW50byBhbm90aGVyIHR5cGUgb2YgZGF0YQo1LiBEZWFsaW5nIHdpdGggbWlzc2luZyB2YWx1ZXMKOjo6CgpMZXQncyBnZXQgc3RhcnRlZCEgCgojIyBEYXRhIFR5cGVzIGluIFIKRGF0YSBjYW4gY29tZSBpbiBtYW55IGRpZmZlcmVudCBmb3JtYXRzIG9yIHVuaXRzLiBTb21ldGltZXMgd2UgaGF2ZSBudW1iZXJzIHdpdGggZGVjaW1hbHMsIHNvbWV0aW1lcyB3ZSBoYXZlIGNvdW50cyBvZiBob3cgbWFueSB0aW1lcyBzb21ldGhpbmcgaGFwcGVuZWQsIGFuZCBzb21ldGltZXMgd2UgaGF2ZSBjYXRlZ29yaWVzIHdpdGggbmFtZXMuIEl0IGlzIGltcG9ydGFudCB0byBrbm93IHdoYXQgdHlwZSBvZiBkYXRhIHlvdSBoYXZlLCBob3cgdG8gZmlndXJlIHRoYXQgb3V0IGluIFIsIGFuZCBob3cgdG8gbW9kaWZ5IHRoZSBkYXRhIHR5cGUgaWYgbmVlZGVkLiBWYXJpb3VzIGZ1bmN0aW9ucyBpbiBSIHJlcXVpcmUgdXNpbmcgY2VydGFpbiBkYXRhIHR5cGVzLCBzbyB0aGVzZSBhcmUgaW1wb3J0YW50IGZvdW5kYXRpb25hbCBza2lsbCBmb3IgbWFuYWdpbmcgZGF0YSBpbiBSLiAKCiMjIyMgKipOdW1lcmljIERhdGEqKgpOdW1lcmljIGRhdGEgaXMgZGF0YSBtYWRlIHVwIG9mIG51bWJlcnMuIFRoaXMgaXMgd2hhdCB3ZSBtb3N0IGNvbW1vbmx5IHRoaW5rIG9mIGFzIGRhdGEsIGFuZCB0aGlzIGRhdGEgdHlwZSBjYW4gaGF2ZSBkZWNpbWFscy4gRm9yIGV4YW1wbGUsIGhvdyBtYW55IGhvdXJzIHBlb3BsZSBzbGVwdCBvbiBhIGdpdmVuIGRheSAoNiwgOC4yNSwgNy41KSwgdGhlIHBlcmNlbnQgYWNjdXJhY3kgdGhhdCBzdHVkZW50cyBnb3Qgb24gYW4gZXhhbSAoODcuNDUsIDc1LjkyLCA5OC40MCksIG9yIG51bWJlciBvZiBwZW9wbGUgd2hvIGF0dGVuZGVkIGEgZGF0YSBtYW5hZ2VtZW50IHdvcmtzaG9wIGVhY2ggZGF5ICgzMiwgMzgsIDI4KS4gCgojIyMjICoqSW50ZWdlciBEYXRhKioKVGhpcyBkYXRhIHR5cGUgZGVhbHMgd2l0aCB3aG9sZSBudW1iZXJzIChpLmUuLCBubyBkZWNpbWFscykgYW5kIG9wZXJhdGVzIHNpbWlsYXJseSB0byBudW1lcmljIGRhdGEgdHlwZXMuIFNvbWUgZGF0YSBjYW4gYmUgc3RvcmVkIGFzICJudW1lcmljIiBhbmQgImludGVnZXIiIGF0IHRoZSBzYW1lIHRpbWUuCgojIyMjICoqQ2hhcmFjdGVyL1N0cmluZyBEYXRhKioKQ2hhcmFjdGVyIHZhcmlhYmxlcyBhcmUgdmFyaWFibGVzIHdpdGggd29yZHMgb3IgbGV0dGVycy4gU3VjaCBhcyBuYW1lcyBvZiBwZW9wbGUgKEVyaW4sIE1hcmlhLCBIdXkpIG9yIHBsYWNlcyAoT04sIEJDLCBRQykuIENoYXJhY3RlciB2YXJpYWJsZXMgdXN1YWxseSBuZWVkIHRvIGJlIHB1dCBpbiBxdW90YXRpb24gbWFya3MgaW4gUiBjb2RlLCBzbyB0aGV5IGFyZSBub3QgY29uZnVzZWQgd2l0aCB3b3JkcyB0aGF0IGFjdHVhbGx5IGRlbm90ZSBmdW5jdGlvbnMgaW4gUi4gCgojIyMjICoqRmFjdG9ycyoqCkZhY3RvcnMgYXJlIGhvdyBSIGhhbmRsZXMgY2F0ZWdvcmljYWwgZGF0YS4gRmFjdG9ycyBjYW4gc3RvcmUgc3RyaW5nIG9yIGludGVnZXIgZGF0YSwgYmVjYXVzZSBzb21ldGltZXMgbnVtYmVycyBkbyByZXByZXNlbnQgY2F0ZWdvcmllcyAocmF0aGVyIHRoYW4gYSBjb250aW51b3VzIHJhbmdlIG9mIG51bWJlcnMpLkZhY3RvcnMgaGF2ZSBsZXZlbGVkIGRhdGEuIEZvciBleGFtcGxlLCB0aGUgdmFyaWFibGUgb2YgZWR1Y2F0aW9uIG1heSBoYXZlIHRoZSBsZXZlbHMgb2YgImhpZ2ggc2Nob29sLCIgImJhY2hlbG9ycyBkZWdyZWUsIiBhbmQgIm1hc3RlcnMgZGVncmVlLiIgRmFjdG9ycyBjYW4gYmUgb3JkZXJlZCBvciB1bm9yZGVyZWQuIEZhY3RvciBzdHJ1Y3R1cmUgaXMgcGFydGljdWxhcmx5IHVzZWZ1bCBmb3Igc3RhdGlzdGljYWwgbW9kZWxpbmcuCgpXZSB3aWxsIGNyZWF0ZSBzb21lIGZhY3RvciB2YXJpYWJsZXMgbGF0ZXIgaW4gdGhpcyBzZWN0aW9uLiAKCiMjIyMgKipEYXRlcyBhbmQgVGltZXMqKgpEYXRhIGNhbiBhbHNvIGJlIHN0b3JlZCBpbiBkYXRlIGFuZC9vciB0aW1lIGZvcm1hdCBpbiBSLiBPdXIgZGF0YSBkb2Vzbid0IGNvbnRhaW4gZGF0ZXMgb3IgdGltZXMsIGJ1dCB3ZSB3YW50IHRvIGxldCB5b3Uga25vdyB0aGlzIGlzIHBvc3NpYmxlLiBEYXRlIGRhdGEgd291bGQgdHlwaWNhbGx5IGxvb2sgbGlrZSAiMjItMDUtMjAyNSIgb3IgIjIwMjUtMDUtMjIuIiBUaW1lcyBjb3VsZCBsb29rIGxpa2UgIjExOjEyOjM0LiIKCiMjIyMgKipMb2dpY2FsIERhdGEqKgpMb2dpY2FsIGRhdGEgaW5jbHVkZXMgYFRSVUVgIGFuZCBgRkFMU0VgIGRhdGEuIFdlIGNhbiBhbHNvIGFzayBSIHRvIHByb3ZpZGUgdXMgYFRSVUVgIG9yIGBGQUxTRWAgcmVzcG9uc2UgaWYgd2UgYXNrIGlmIGEgY29uZGl0aW9uIGlzIG1ldC4gCgojIyBEYXRhIFN0cnVjdHVyZXMgaW4gUgpEYXRhIHN0cnVjdHVyZXMgYXJlIGhvdyB0aGUgZGF0YSBpcyBvcmdhbml6ZWQgaW4gUi4gSGVyZSBhcmUgdGhlIG1ham9yIGRhdGEgc3RydWN0dXJlcyBpbiBSLiBUaGVyZSBhcmUgc29tZSBhZGRpdGlvbmFsIHN0cnVjdHVyZXMgKGUuZy4sIG1hdHJpY2VzIGFuZCBhcnJheXMpIHRoYXQgYXJlIG1vc3RseSB1c2VkIG9ubHkgd2hlbiBkb2luZyBzdGF0aXN0aWNhbCBtb2RlbGluZy4gV2Ugd2lsbCBza2lwIG92ZXIgdGhlc2UgZm9yIG5vdyBhbmQgZm9jdXMgb24gdGhlIGRhdGEgc3RydWN0dXJlcyB5b3Ugd2lsbCBsaWtlbHkgZW5jb3VudGVyIGluIGEgcmVzZWFyY2ggZGF0YSBtYW5hZ2VtZW50IGNvbnRleHQuIAoKIyMjIyAqKlZlY3RvcnMqKgpWZWN0b3JzIGFyZSB0aGUgc2ltcGxlc3QgZGF0YSBzdHJ1Y3R1cmUuIFRoZXkgYXJlIGVzc2VudGlhbGx5IGEgbGlzdCBvZiBlbGVtZW50cyBvZiB0aGUgc2FtZSBkYXRhIHR5cGUuIEZvciBleGFtcGxlLCB5b3UgY291bGQgaGF2ZSBhIG51bWVyaWMgdmVjdG9yIGNvbnRhaW5pbmcgdGhlIGVsZW1lbnRzICgxMCwgMTUsIDIwLCAyNSkgb3IgYSBjaGFyYWN0ZXIgdmVjdG9yIGNvbnRhaW5pbmcgdGhlIGVsZW1lbnRzICgiYmx1ZSIsICJyZWQiLCAiZ3JlZW4iKS4gVGhleSBhcmUgb25lIGRpbWVuc2lvbmFsLCBzaW5jZSB0aGV5IGFyZSBqdXN0IG9uZSBsb25nIGxpc3QuIEEgc2luZ2xlIHZhcmlhYmxlIChlLmcuLCBhIGxpc3Qgb2YgYWdlcyBvZiBhbGwgdGhlIHBhcnRpY2lwYW50cykgY2FuIGJlIGNvbnNpZGVyZWQgYSB2ZWN0b3IuIAoKIyMjIyAqKkRhdGEgRnJhbWVzKioKRGF0YSBmcmFtZXMgYXJlIHRoZSBtb3N0IGNvbW1vbiBhbmQgcG9wdWxhciB0eXBlIG9mIGRhdGEgc3RydWN0dXJlIHVzZWQgaW4gUi4gRGF0YSBmcmFtZXMgd29yayBlc3NlbnRpYWxseSBsaWtlIHNwcmVhZHNoZWV0cyBpbiB0aGF0IHRoZXkgYXJlIHR3byBkaW1lbnNpb25hbCAoaS5lLiwgaGF2ZSBjb2x1bW5zIGFuZCByb3dzKSBhbmQgY2FuIHN0b3JlIGRpZmZlcmVudCBkYXRhIHR5cGVzIGluIHRoZSBzYW1lIGRhdGEgZnJhbWUgKGkuZS4sIG51bWVyaWMgYW5kIGNoYXJhY3RlcikuIERhdGEgZnJhbWVzIGFyZSBtYWRlIHVwIG9mIHZlY3RvcnMgb2YgdGhlIHNhbWUgbGVuZ3RoLiAKCkhvd2V2ZXIsIGRhdGEgZnJhbWVzIGRvIGhhdmUgc29tZSBjb25zdHJhaW50cy4gRmlyc3QsIHRoZSBjb2x1bW5zIGFuZCByb3dzIG11c3QgYmUgbmFtZWQuIFNlY29uZCwgdGhlIGxpc3RzIG9mIHZlY3RvcnMgaW4gdGhlIGRhdGEgZnJhbWUgbXVzdCBoYXZlIGVxdWFsIGxlbmd0aHMgKGkuZS4sIGVhY2ggY29sdW1uIG5lZWRzIGFuIGlkZW50aWNhbCBudW1iZXIgb2YgZWxlbWVudHMvcm93cykuIFRoaXJkLCBhbGwgZWxlbWVudHMgaW4gYSBzaW5nbGUgY29sdW1uIG11c3QgYmUgb2YgdGhlIHNhbWUgZGF0YSB0eXBlIChpLmUuLCB5b3UgY2FuJ3Qgc3dpdGNoIGJldHdlZW4gbnVtYmVycyBhbmQgbmFtZXMgaW4gYSBzaW5nbGUgY29sdW1uKS4KCllvdSBtYXkgc2VlIG1lbnRpb24gb2YgdGliYmxlcywgd2hpY2ggYXJlIGFuIHVwZGF0ZWQgdmVyc2lvbiBvZiBkYXRhIGZyYW1lcyBhbmQgcGFydCBvZiB0aGUgdGlkeXZlcnNlIHBhY2thZ2UsIGFuZCBoYXZlIHRoZSBzYW1lIGNvbnN0cmFpbnRzIGFzIGRhdGEgZnJhbWVzLiBUaGV5IGFyZSBhIGJpdCBtb3JlIHVzZXItZnJpZW5kbHkgdmVyc2lvbiBvZiB0YWJ1bGFyIGRhdGEuIAoKRm9yIHRoaXMgY291cnNlLCBvdXIgZGF0YSBpcyBpbiBkYXRhIGZyYW1lIGZvcm1hdC4gCgojIyMjICoqTGlzdHMqKgpMaXN0cyBhcmUgYW4gb3JkZXJlZCBjb2xsZWN0aW9uIG9mIGVsZW1lbnRzLiBUaGV5IGNhbiBjb250YWluIGRpZmZlcmVudCBkYXRhIHR5cGVzIGFuZCB0aGV5IGFyZSBvbmUgZGltZW5zaW9uYWwuIFlvdSBjYW4gYWxzbyBoYXZlIGxpc3RzIHRoYXQgY29udGFpbiBhIHNlcmllcyBvZiB2ZWN0b3JzIG9yIGRhdGEgZnJhbWVzLiBXZSBkb24ndCBvZnRlbiBoYXZlIGRhdGEgaW4gbGlzdCBmb3JtLCBidXQgYmVjYXVzZSBsaXN0cyBjYW4gY29udGFpbiBlbGVtZW50cyBvZiBkaWZmZXJlbnQgbGVuZ3RocyAodW5saWtlIGRhdGEgZnJhbWVzKSBzb21lIGZ1bmN0aW9ucyBpbiBSIHdpbGwgb3V0cHV0IHJlc3VsdHMgaW50byBsaXN0IGZvcm1hdCwgc28gaXQgaXMgZ29vZCB0byBiZSBhd2FyZSBvZiB0aGVtLiBIZXJlIGlzIGFuIGV4YW1wbGUgb2YgYSBsaXN0OgoKYGBge3J9Cmxpc3RfZXhhbXBsZSA8LSBsaXN0KCJyZWQiLCA0MDAsICJza3libHVlIiwgImZvcmVzdGdyZWVuIiwgLjMzMykKbGlzdF9leGFtcGxlCmBgYAoKQmVjYXVzZSBsaXN0cyBhcmUgb3JkZXJlZCAoaS5lLiwgZWFjaCBlbGVtZW50IGluIHRoZSBsaXN0IGhhcyBhIHNwZWNpZmljIHNwb3QgaW4gdGhlIGxpc3QpLCB5b3UgY2FuIGNhbGwgZm9yIGFuIGVsZW1lbnQgYmFzZWQgb24gdGhlIG9yZGVyIGl0IGhhcyBiZWVuIGFzc2lnbmVkLiBGb3IgZXhhbXBsZSwgInNreWJsdWUiIGlzIHRoaXJkIGluIHRoaXMgZXhhbXBsZSBsaXN0LiAKCmBgYHtyfQpsaXN0X2V4YW1wbGUgWzNdCmBgYAoKIyMgSW50cm9kdWN0aW9uIHRvIGRwbHlyCkluIG9yZGVyIHRvIGNoZWNrIGFuZCBtb2RpZnkgZGF0YSB0eXBlcyB3ZSBzdWdnZXN0IHVzaW5nIHRoZSBgZHBseXJgIHBhY2thZ2UsIHdoaWNoIGlzIHBhcnQgb2YgdGhlIHRpZHl2ZXJzZS4gYGRwbHlyYCBpcyBhIHBvd2VyZnVsIFIgcGFja2FnZSBkZXNpZ25lZCB0byBzaW1wbGlmeSBkYXRhIG1hbmlwdWxhdGlvbiB0YXNrcy4gSXQgcHJvdmlkZXMgYSBzZXQgb2YgaW50dWl0aXZlIGZ1bmN0aW9ucyB0aGF0IGhlbHAgd2l0aCBmaWx0ZXJpbmcsIHNlbGVjdGluZywgYW5kIHRyYW5zZm9ybWluZyBkYXRhIGZyYW1lcy4gSXQgaXMgdGhlIGdvIHRvIHBhY2thZ2UgZm9yIGRhdGEgb3JnYW5pemF0aW9uLiBXZSB3aWxsIHVzZSBqdXN0IGEgZmV3IG9mIHRoZSBmdW5jdGlvbnMgb2YgdGhpcyBwYWNrYWdlIGluIHRoaXMgY291cnNlLCBidXQgdGhlcmUgYXJlIG1hbnkgbW9yZSBhcHBsaWNhdGlvbnMgb2YgYGRwbHlyYCB5b3UgY2FuIGV4cGxvcmUuIFlvdSBjYW4gZmluZCBtb3JlIGluZm9ybWF0aW9uIGFib3V0IGBkcGx5cmAgb24gdGhlIDxhIGhyZWY9Imh0dHBzOi8vZHBseXIudGlkeXZlcnNlLm9yZy9pbmRleC5odG1sIj50aWR5dmVyc2Ugd2Vic2l0ZTwvYT4uCgpIZXJlIGFyZSBzb21lIG9mIHRoZSBtb3N0IGNvbW1vbiBmdW5jdGlvbnMgb2YgYGRwbHlyYC4gV2Ugd2lsbCBwcmFjdGljZSB1c2luZyBzb21lIG9mIHRoZXNlIHRvZGF5IHdpdGggb3VyIGRhdGFzZXQuIAoKICAtIGBtdXRhdGUoKWA6IFVzZWZ1bCB3aGVuIHlvdSB3YW50IHRvIGNyZWF0ZSBuZXcgY29sdW1ucyBiYXNlZCBvbiB2YWx1ZXMgaW4gZXhpc3RpbmcgY29sdW1ucyBpbiB5b3VyIGRhdGFzZXQuIEZvciBleGFtcGxlLCB5b3UgbWF5IHdhbnQgdG8gcmVjb2RlIG51bWVyaWMgZGF0YSBpbnRvIG5ldyBjYXRlZ29yaWVzIHdpdGggY2hhcmFjdGVyIG5hbWVzLiAKICAKICAtIGByZWNvZGUoKWA6IFVzZWZ1bCBmb3IgY2hhbmdpbmcgZGF0YSBmb3JtYXQgb2YgdmFyaWFibGVzIG9yIHJlLWNhdGVnb3JpemluZyBjZXJ0YWluIHZhbHVlcyBpbiBhIHZhcmlhYmxlIGFzIHNvbWUgb3RoZXIgdmFsdWUuIEZvciBleGFtcGxlLCBtYXliZSB5b3Ugd2FudCB0byBsYWJlbCBldmVyeW9uZSB3aG8gc2xlZXBzIGxlc3MgdGhhbiBzZXZlbiBob3VycyBhIG5pZ2h0IGFzICJzbGVlcCBkZXByaXZlZC4iIAoKICAtIGBncm91cF9ieSgpYDogQWxsb3dzIHlvdSB0byB2aWV3IHlvdXIgZGF0YSBiYXNlZCBvbiBncm91cHMgdGhhdCB5b3UgZGVmaW5lIG9yIGFscmVhZHkgZXhpc3QgaW4geW91ciBkYXRhLiBGb3IgZXhhbXBsZSwgeW91IG1heSB3YW50IHRvIGdyb3VwIHlvdXIgZGF0YSBiYXNlZCBvbiB3aGV0aGVyIHBlb3BsZSBsaXZlIGluIGEgY2l0eSBvciBydXJhbCBhcmVhLCBvciBieSBnZW5kZXIuIAogIAogIC0gYHN1bW1hcml6ZSgpYCBvciBgc3VtbWFyaXNlKClgOiBVc2VmdWwgZm9yIHNlZWluZyBiYXNpYyBkZXNjcmlwdGl2ZSBpbmZvIGFib3V0IHlvdXIgZGF0YS4gVGhpcyBpcyBwYXJ0aWN1bGFybHkgaGVscGZ1bCB3aGVuIHVzZSB3aXRoIHRoZSBgZ3JvdXBfYnkoKWAgZnVuY3Rpb24uIEZvciBleGFtcGxlLCB5b3UgY2FuIHNlZSBpZiBwZW9wbGUgaW4gY2l0aWVzIGNvbXBhcmVkIHRvIHJ1cmFsIGFyZWFzIGZlZWwgbW9yZSBydXNoZWQgb24gYXZlcmFnZSAoaS5lLiwgY29tcGFyZSBtZWFucyBiZXR3ZWVuIHRoZXNlIHR3byBncm91cHMpLiAKICAKICAtIGB8PmAgKHBpcGUgb3BlcmF0b3IpOiBBbGxvd3MgeW91IHRvIHRlbGwgUiB0byBhcHBseSBvbmUgZnVuY3Rpb24gc2V2ZXJhbCB0aW1lcy4gWW91IGNhbiByZWFkIGl0IG1vcmUgb3IgbGVzcyBhcyAiYW5kIHRoZW4iIHdoZW4gdGhpbmtpbmcgYWJvdXQgd2hhdCB5b3VyIFIgY29kZSBpcyBkb2luZy4gCiAgCiAgLSBgZmlsdGVyKClgOiBUaGlzIGZ1bmN0aW9uIGFsbG93cyB5b3UgdG8gZXh0cmFjdCByb3dzIHRoYXQgbWVldCBzcGVjaWZpYyBjb25kaXRpb25zIHlvdSBpbmNsdWRlLiAKICAKICAtIGBzZWxlY3QoKWA6IFRoaXMgZnVuY3Rpb24gbGV0cyB5b3UgY2hvb3NlIHBhcnRpY3VsYXIgY29sdW1ucyBiYXNlZCBvbiB5b3VyIHNwZWNpZmljYXRpb25zLiAKICAKSXQgaXMgaW1wb3J0YW50IHdoZW4gdXNpbmcgYGRwbHlyYCB0byBhc3NpZ24geW91ciBvdXRwdXQgdG8gYW4gb2JqZWN0IGlmIHlvdSB3YW50IHRvIHJldGFpbiB0aGUgaW5mbyB5b3UndmUgZm91bmQgb3IgY3JlYXRlZC4gUmVtZW1iZXIgdGhlIGA8LWAgc3ltYm9sIGNhbiBiZSB1c2VkIHRvIGFzc2lnbiBvdXRwdXQgdG8gYSBuYW1lZCBvYmplY3QuIFdlIHdpbGwgcHJhY3RpY2UgdGhpcyB0b2RheSB0b28uIAoKVG9nZXRoZXIsIHRoZXNlIGZ1bmN0aW9ucyBpbiBgZHBseXJgIGVuYWJsZSB5b3UgdG8gZWFzaWx5IGV4cGxvcmUgeW91ciBkYXRhIGJ5IHZhcmlvdXMgc3ViZ3JvdXBzLCBjcmVhdGUgbmV3IHZhcmlhYmxlcywgb3IgY3JlYXRlIGEgZm9jdXNlZCBzdWJzZXQgb2YgeW91ciBkYXRhIGZvciBmdXJ0aGVyIGFuYWx5c2lzLgoKTGV0J3MgZXhwbG9yZSB0aGUgZGF0YSB0eXBlcyBpbiBvdXIgZGF0YSB1c2luZyB0aGUgYGRwbHlyYCBmdW5jdGlvbnMhCgojIyBDaGVja2luZyBEYXRhIFR5cGVzCgpGaXJzdCB3ZSBsb2FkICB0aGUgYGRwbHlyYCBwYWNrYWdlIChyZW1lbWJlciB0byBpbnN0YWxsIGl0IGZpcnN0IGlmIHlvdSBoYXZlbid0IHlldCkuIFkgSWYgeW91IGhhdmUgaW5zdGFsbGVkIHRoZSBgdGlkeXZlcnNlYCBwYWNrYWdlLCB0aGVuIGBkcGx5cmAgd2FzIGFsc28gaW5jbHVkZWQuIEhvd2V2ZXIsIGl0IGlzIGJlc3QgcHJhY3RpY2UgdG8ganVzdCBsb2FkIGluIHRoZSBsaWJyYXJpZXMgeW91IG5lZWQgKGkuZS4sIGp1c3QgYGRwbHlyYCBhbmQgbm90IGFsbCBvZiB0aGUgdGlkeXZlcnNlIHBhY2thZ2VzKSB0byBzYXZlIHNwYWNlLgoKV2Ugd2lsbCBhbHNvIGxvYWQgaW4gb3VyIGRhdGEuIFllc3RlcmRheSB3ZSB1c2VkIHRoZSBgcmVhZF9jc3ZgIGZ1bmN0aW9uIHRvIHJlYWQgaW4gdGhlIGNzdiBmaWxlLCBidXQgbm93IHdlIGFyZSB3b3JraW5nIHdpdGggYW4gUmRhdGEgZmlsZSB3ZSBzYXZlZCB5ZXN0ZXJkYXksIHNvIHdlIGNhbiB1c2UgdGhlIGBsb2FkYCBmdW5jdGlvbi4gCgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFfQpsaWJyYXJ5KGRwbHlyKQpsb2FkKCJkYXRhL3RpbWV1c2VfZGF5Mi5SZGF0YSIpCmBgYAoKSnVzdCB0byByZWFjcXVhaW50IG91cnNlbHZlcyB3aXRoIG91ciBkYXRhLCB1c2UgdGhlIGBoZWFkYCBmdW5jdGlvbiB0byBwZWFrIGF0IHRoZSBmaXJzdCA2IHJvd3Mgb2Ygb3VyIGRhdGEuIAoKYGBge3IsIGRhdGEtaXNvbGF0aW9uLCByZXN1bHRzID0gRkFMU0V9CmhlYWQoanNfZGF0YSkKYGBgCgpgYGB7ciwgZWNobyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoa2FibGVFeHRyYSkKaGVhZChqc19kYXRhKXw+CiAga2JsKCkgfD4KICAja2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9ICJzdHJpcGVkIikKa2FibGVfcGFwZXIoKSAlPiUKICBzY3JvbGxfYm94KHdpZHRoID0gIjUwMHB4IiwgaGVpZ2h0ID0gIjIwMHB4IikKCmBgYAoKCldlIGNhbiBjaGVjayB0aGUgZGF0YSB0eXBlIG9mIHZhcmlhYmxlcyB1c2luZyB0aGUgYGNsYXNzKClgIGZ1bmN0aW9uIGFuZCBjYWxsaW5nIGZvciBhIHNwZWNpZmljIHZhcmlhYmxlIGZyb20gb3VyIGRhdGFzZXQgYGpzX2RhdGFgIHVzaW5nIHRoZSBgJGAgb3BlcmF0b3IsIGZvbGxvd2VkIGJ5IHRoZSBuYW1lIG9mIG91ciB2YXJpYWJsZS4gCgpgYGB7cn0KY2xhc3MoanNfZGF0YSRkdXJXb3JrKQpgYGAKCjo6OnF1ZXN0aW9uClRyeSBleHBsb3JpbmcgdGhlIGRhdGEgdHlwZSBvZiBhIGZldyBvdGhlciB2YXJpYWJsZXMgb24geW91ciBvd24uIAo6OjoKCiMjIFJlY29kaW5nIERhdGEgVHlwZXMKRm9yIHNvbWUgdmFyaWFibGVzLCB3ZSBtaWdodCB3YW50IHRvIGNoYW5nZSB0aGUgZGF0YSB0eXBlIGJhc2VkIG9uIG91ciBjb2RlYm9vay4gRm9yIGluc3RhbmNlLCB3ZSBjYW4gc2VlIHRoYXQgb3VyICJwcm92aW5jZSIgdmFyaWFibGUgaXMgaW4gbnVtZXJpYyBmb3JtYXQuIApgYGB7cn0KY2xhc3MoanNfZGF0YSRwcm92aW5jZSkKYGBgCgpIb3dldmVyLCBtYXliZSB3ZSB3b3VsZCBwcmVmZXIgdG8gaGF2ZSBwcm92aW5jZSBhY3JvbnltcyAoaS5lLiwgZmFjdG9yIGZvcm1hdCkgcmF0aGVyIHRoYW4gdGhlIG51bWVyaWMgcmVwcmVzZW50YXRpb24gb2YgdGhlbS4gV2UgY2FuIHJlLWNvZGUgdmFyaWFibGVzIHVzaW5nIHRoZSBkcGx5ciBmdW5jdGlvbnMgYHw+YCBhbmQgYG11dGF0ZSgpYC4gVGhlIHBvc3NpYmxlIHZhbHVlcyBmb3IgdGhlIHByb3ZpbmNlIHZhcmlhYmxlLCBhbmQgd2hhdCBwcm92aW5jZSB0aGV5IHJlcHJlc2VudCBjYW4gYmUgZm91bmQgaW4gdGhlIGRhdGFzZXQgY29kZWJvb2suIAoKYGBge3J9CmpzX2RhdGEgPC0ganNfZGF0YSB8PiBtdXRhdGUocHJvdmluY2VfZmFjdCA9IHJlY29kZV9mYWN0b3IoanNfZGF0YSRwcm92aW5jZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMTAiID0gIk5MIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMTEiID0gIlBFSSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIjEyIiA9ICJOUyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMTMiID0gIk5CIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMjQiID0gIlFDIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMzUiID0gIk9OIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiNDYiID0gIk1CIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiNDciID0gIlNLIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiNDgiID0gIkFCIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiNTkiID0gIkJDIikpCmBgYAoKOjo6d2Fsa3Rocm91Z2gKICAtIFRoaXMgY29kZSBpcyB0ZWxsaW5nIFIgdG8gdXNlIHRoZSBmdW5jdGlvbiBgcmVjb2RlX2ZhY3RvcigpYCB0byByZWNvZGUgdGhlIHZhcmlhYmxlICJwcm92aW5jZSIgZnJvbSB0aGUgZGF0YXNldCAianNfZGF0YSIgaW50byBhIG5ldyB2YXJpYWJsZSBjYWxsZWQgInByb3ZpbmNlX2ZhY3QiICh5b3UgY291bGQgY2FsbCBpdCBhbnl0aGluZywgYnV0IG1ha2Ugc3VyZSBpdCBpcyBhIG1lYW5pbmdmdWwgbmFtZSkuIAoKICAtIFRoZSBsaXN0IG91dGxpbmVzIGhvdyBlYWNoIHZhbHVlIG9mIHRoZSBjdXJyZW50ICJwcm92aW5jZSIgdmFyaWFibGUgc2hvdWxkIGJlIHJlY29kZWQgZm9yIHRoZSBuZXcgInByb3ZpbmNlX2ZhY3QiIHZhcmlhYmxlLiAKICAKICAtIFRoZSBgbXV0YXRlKClgIHBvcnRpb24gdGVsbHMgUiB0byBjcmVhdGUgYSBuZXcgY29sdW1uIGNhbGxlZCAicHJvdmluY2VfZmFjdCIuIAogIAogIC0gQmVmb3JlIHRoZSBgbXV0YXRlKClgIGZ1bmN0aW9uIHRoaXMgY29kZSB0ZWxscyBSIHRvIHRha2UgdGhlICJqc19kYXRhIiBvYmplY3QgKGkuZS4sIHRoZSBkYXRhc2V0KSAiYW5kIHRoZW4iIChpLmUuLCB0aGUgcGlwZSBmdW5jdGlvbikgYXBwbHkgdGhlIGZvbGxvd2luZyBmdW5jdGlvbnMuIAogIAogIC0gVGhlIHBpcGUgZnVuY3Rpb24gKGB8PmApIHRlbGxzIFIgdG8gcmVjb2RlIGFsbCBvZiB0aGVzZSB2YWx1ZXMgYWxsIGF0IG9uY2UsIHJhdGhlciB0aGFuIGhhdmluZyB0byB3cml0ZSBvdXQgYG11dGF0ZSgpYCBhbmQgYHJlY29kZSgpYCBmb3IgZWFjaCBvbmUuIAogIAogIC0gTGFzdGx5LCBhbGwgb2YgdGhpcyB3b3JrIG5lZWRzIHRvIGJlIGFzc2lnbmVkIGJhY2sgdG8gb3VyIGRhdGFzZXQgImpzX2RhdGEiIHVzaW5nIHRlaCBgPC1gIHN5bWJvbCBpbiBvcmRlciB0byBrZWVwIG91ciB3b3JrIGluIG91ciBlbnZpcm9ubWVudC4KOjo6Cgo6Ojpub3RlCldlIGRpZCBub3QgYXNzaWduIHRoaXMgd29yayB0byByZXBsYWNlL292ZXJ3cml0ZSB0aGUgZXhpc3RpbmcgInByb3ZpbmNlIiB2YXJpYWJsZS4gSW4gb3JkZXIgdG8gaGF2ZSB0cmFuc3BhcmVudCBkYXRhIG1hbmFnZW1lbnQgYW5kIHRvIHByZXZlbnQgb3ZlcndyaXRpbmcgdGhlIG9yaWdpbmFsIGRhdGEgaW4gdGhlIGluc3RhbmNlIHRoYXQgeW91IG1ha2UgYSBtaXN0YWtlIGluIHlvdXIgcmVjb2RpbmcsIGl0IGlzIGFsd2F5cyBiZXN0IHByYWN0aWNlIHRvIGtlZXAgdGhlIG9yaWdpbmFsIHZhcmlhYmxlcyBpbiB0aGVpciBvcmlnaW5hbCBmb3JtYXQgYW5kIGNyZWF0ZSBuZXcgdmFyaWFibGVzIGJhc2VkIG9uIHRoZW0gYXMgbmVlZGVkLiBJbiB0aGlzIHdheSwgaWYgeW91IGV2ZXIgbmVlZCB0byByZWZlcmVuY2UgdGhlIG9yaWdpbmFsIGRhdGEgKGFuZCB5b3UgZGVmaW5pdGVseSB3aWxsIG5lZWQgdG8pLCB5b3Ugc3RpbGwgaGF2ZSBpdCBhdmFpbGFibGUgdG8geW91LiAKCjo6OgoKTm93IGxldHMgY2hlY2sgdGhlIGRhdGEgdHlwZSBvZiB0aGlzIG5ldyB2YXJpYWJsZSB3ZSBqdXN0IGNyZWF0ZWQuIApgYGB7cn0KY2xhc3MoanNfZGF0YSRwcm92aW5jZV9mYWN0KQpgYGAKCkFuIGFsdGVybmF0aXZlIHdheSB0byBjaGVjayB5b3VyIGRhdGEgdHlwZXMgaXMgdXNpbmcgdGhlIGBpcy5udW1lcmljYCwgYGlzLmZhY3RvcmAsIG9yIG90aGVyIHZhcmlhdGlvbnMgb2YgdGhpcyBmdW5jdGlvbi4gV2l0aCB0aGlzIGZ1bmN0aW9uIHlvdSB3aWxsIGdldCBhIGxvZ2ljYWwgb3BlcmF0b3IgYXMgdGhlIG91dHB1dC4gVGhlc2UgYXJlIGJhc2UgUiBmdW5jdGlvbnMsIGFuZCBub3QgZnJvbSB0aGUgdGlkeXZlcnNlLiAKYGBge3J9CmlzLm51bWVyaWMoanNfZGF0YSRwcm92aW5jZV9mYWN0KQppcy5mYWN0b3IoanNfZGF0YSRwcm92aW5jZV9mYWN0KQoKYGBgCgpTb21ldGltZXMgeW91IG1heSB3YW50IHRvIGNoYW5nZSB0aGUgZGF0YSB0eXBlIHdpdGhvdXQgcmVjb2RpbmcgYWxsIG9mIHRoZSBkYXRhLiBJbiB0aGlzIGNhc2UgYSB1c2VmdWwgZnVuY3Rpb24gaXMgYGFzLm51bWVyaWMoKWAuIEJlY2F1c2UgdGhpcyBkYXRhIGlzIGFscmVhZHkgc3RvcmVkIGluIG51bWVyaWMgZm9ybWF0LCB0aGlzIGZ1bmN0aW9uIHdpbGwgbm90IGNoYW5nZSB0aGUgZGF0YSB0eXBlIGluIHRoaXMgaW5zdGFuY2UsIGJ1dCB0aGlzIGNhbiBiZSBoZWxwZnVsIGZvciBvdGhlciBkYXRhc2V0cyB5b3UgbWF5IHdvcmsgd2l0aCBpbiB0aGUgZnV0dXJlLiBIZXJlIGlzIGFuIGV4YW1wbGUgb2YgaG93IHlvdSB3b3VsZCB1c2UgdGhpcyBmdW5jdGlvbi4gVGhpcyBpcyBhIGJhc2UgUiBmdW5jdGlvbiwgYW5kIG5vdCBmcm9tIHRoZSB0aWR5dmVyc2UuIApgYGB7ciwgcmVzdWx0cyA9ICdoaWRlJ30KYXMubnVtZXJpYyhqc19kYXRhJGR1clNsZWVwKQpgYGAKCiMjIE1pc3NpbmcgRGF0YQpZb3UgbWF5IGhhdmUgbm90aWNlZCB0aGF0IHRoZXJlIGFyZSBzb21lIGNlbGxzIGluIHRoZSBkYXRhIHdpdGggYE5BYCBUaGlzIHJlcHJlc2VudHMgbWlzc2luZyBkYXRhIGluIG91ciBkYXRhc2V0LiBNb3N0IGRhdGFzZXRzIGhhdmluZyBtaXNzaW5nIGRhdGEuIFRoZXJlIGFyZSBtYW55IHJlYXNvbnMgZm9yIG1pc3NpbmcgZGF0YSBhbmQgbWFueSBkaWZmZXJlbnQgd2F5cyB0byBoYW5kbGUgbWlzc2luZyBkYXRhLiBUaGVzZSBjaG9pY2VzIHdpbGwgZGVwZW5kIG9uIHRoZSBjb250ZXh0IG9mIHNwZWNpZmljIHJlc2VhcmNoLCBidXQgZ2VuZXJhbGx5IHlvdSBzaG91bGQgcGxhbiBmb3IgaG93IHRvIGFwcHJvYWNoIG1pc3NpbmcgZGF0YSBpbiBhZHZhbmNlLiAKCkluIHRoZSBvcmlnaW5hbCBkYXRhc2V0LCBtaXNzaW5nIGRhdGEgaGFkIGJlZW4gbm90YXRlZCB3aXRoIHZhcmlvdXMgbnVtZXJpY2FsIGNvZGVzICh5b3UgY2FuIHNlZSB0aGVzZSBpbiB0aGUgb3JpZ2luYWwgY29kZWJvb2spLCBidXQgd2UgaGF2ZSByZWNvZGVkIHRoZSBkYXRhIHNvIHRoYXQgYWxsIG1pc3NpbmcgZGF0YSBhcyBiZWVuIGRlbm90ZWQgYE5BYCAKCklmIHlvdXIgZGF0YSBjb250YWlucyBOQSB2YWx1ZXMsIHNvbWV0aW1lcyBmdW5jdGlvbnMgd2lsbCBnaXZlIGVycm9yIG1lc3NhZ2VzIGR1ZSB0byBpbmNvbXBsZXRlIGRhdGEuIEZvciBleGFtcGxlLCBpZiB5b3UgdHJ5IHRvIGdldCB0aGUgbWVhbiBvZiBlZHVjYXRpb24gbGV2ZWwgKGVkdUxldmVsKSwgUiB3aWxsIG5vdCBwcm92aWRlIG9uZSBiZWNhdXNlIGl0IGNhbid0IGNhbGN1bGF0ZSBhIG1lYW4gd2hlbiB0aGVyZSBhcmUgbWlzc2luZyB2YWx1ZXMuIAoKTm90ZTogZ2V0dGluZyBhIG1lYW4gZm9yIGVkdWNhdGlvbiBsZXZlbCwgd2hpY2ggaXMgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSwgaXMgbm90IGEgbWVhbmluZ2Z1bCBudW1iZXIuIEhvd2V2ZXIsIGl0IGlzIHVzZWQgaGVyZSB0byBpbGx1c3RyYXRlIHRoaXMgcG9pbnQsIGdpdmVuIHRoYXQgdGhlIGNvbnRpbnVvdXMgbnVtZXJpYyB2YXJpYWJsZXMgaW4gdGhpcyBkYXRhc2V0IGRvIG5vdCBjb250YWluIG1pc3NpbmcgdmFsdWVzLiAKYGBge3J9Cm1lYW4oanNfZGF0YSRlZHVMZXZlbCkKYGBgCgpJZiB3ZSBsb29rIHVwIHRoZSBgbWVhbmAgZnVuY3Rpb24gKGkuZS4sIHJ1biBgaGVscChtZWFuKSBpbiB5b3VyIGNvbnNvbGUpYCwgd2UgY2FuIHNlZSB0aGF0IHRoZSBkZWZhdWx0IGZvciBgbWVhbmAgaXMgdG8gaGF2ZSBgbmEucm0gPSBGQUxTRWAuCgpJbnN0ZWFkLCB3ZSB0ZWxsIFIgdG8gaWdub3JlIHRob3NlIG1pc3NpbmcgdmFsdWVzLiBJbmNsdWRpbmcgYG5hLnJtID0gVFJVRWAgdG8gdGhlIGZ1bmN0aW9uIHdpbGwgdHlwaWNhbGx5IHRlbGwgUiB0aGF0IGl0IHNob3VsZCBjb21wbGV0ZSB0aGUgZnVuY3Rpb24sIGlnbm9yaW5nIG1pc3NpbmcgdmFsdWVzLiAKYGBge3J9Cm1lYW4oanNfZGF0YSRlZHVMZXZlbCwgbmEucm0gPSBUUlVFKQpgYGAKSWYgeW91IHdhbnQgdG8gY2hlY2sgaWYgYSB2YXJpYWJsZSBvciBkYXRhIGZyYW1lIGhhcyBtaXNzaW5nIGRhdGEsIHlvdSBjYW4gdXNlIHRoZSBmdW5jdGlvbiBgaXMubmFgLiAKYGBge3IsIHJlc3VsdHMgPSAnaGlkZSd9CmlzLm5hKGpzX2RhdGEkZWR1TGV2ZWwpCmBgYApJZiB5b3Ugd2FudCB0byBrbm93IHRoZSBudW1iZXIgb2YgY2VsbHMgd2l0aCBtaXNzaW5nIGRhdGEgZm9yIGEgZ2l2ZW4gdmFyaWFibGUgeW91IGNhbiB1c2UgdGhlIHNhbWUgZnVuY3Rpb24sIHdyYXBwZWQgaW4gdGhlIGBzdW1gIGZ1bmN0aW9uLiBXZSBjYW4gbGF5ZXIgZnVuY3Rpb25zIGxpa2UgdGhpcywgd2l0aCBSIHJlYWRpbmcgdGhlIGZ1bmN0aW9ucyBzdGFydGluZyBmcm9tIGluc2lkZSB0aGUgcGFyZW50aGVzZXMgYW5kIHRoZW4gbW92aW5nIG91dHdhcmRzLiBXZSB3aWxsIGNvbnRpbnVlIHRvIHdvcmsgd2l0aCBzeW50YXggbGlrZSB0aGlzIHRocm91Z2hvdXQgdGhlIHdlZWsuIApgYGB7cn0Kc3VtKGlzLm5hKGpzX2RhdGEkZWR1TGV2ZWwpKQpgYGAKSWYgeW91IHdhbnQgdG8gZmluZCBpbnN0YW5jZXMgd2hlcmUgdGhlcmUgaXMgbm8gbWlzc2luZyBkYXRhIHlvdSBjYW4gdXNlIGBjb21wbGV0ZS5jYXNlcygpYC4gCmBgYHtyLCByZXN1bHRzID0gJ2hpZGUnfQpjb21wbGV0ZS5jYXNlcyhqc19kYXRhKQpgYGAKSWYgeW91IHdhbnQgdG8ga25vdyB0aGUgdG90YWwgbnVtYmVyIG9mIHJvd3MgKGkuZS4sIHBhcnRpY2lwYW50cykgd2l0aCBubyBtaXNzaW5nIGRhdGEgeW91IGNhbiB0YWtlIHRoZSBgY29tcGxldGUuY2FzZXMoKWAgZnVuY3Rpb24gYW5kIHdyYXAgaXQgaW4gdGhlIGBzdW0oKWAgZnVuY3Rpb24uCmBgYHtyfQpzdW0oY29tcGxldGUuY2FzZXMoanNfZGF0YSkpCmBgYAoKIyMgWW91ciBUdXJuIQojIyMgUmVjb2RpbmcgRGF0YSBUeXBlcwo6OjogcXVlc3Rpb24KV2hhdCB0eXBlIG9mIGRhdGEgaXMgdGhlIHZhcmlhYmxlIGZvciBtYXJpdGFsIHN0YXR1cz8KOjo6CgpgYGB7ciBjbGFzcy5zb3VyY2UgPSAnZm9sZC1oaWRlJywgcmVzdWx0cyA9ICdoaWRlJ30KY2xhc3MoanNfZGF0YSRtYXJpdGFsU3RhdCkKYGBgCgo6OjpxdWVzdGlvbgpDYW4geW91IHJlLWNvZGUgbWFyaXRhbCBzdGF0dXMgaW50byBhIGZhY3RvciB2YXJpYWJsZT8KOjo6CgpgYGB7ciBjbGFzcy5zb3VyY2UgPSAnZm9sZC1oaWRlJywgcmVzdWx0cyA9ICdoaWRlJ30KanNfZGF0YTwtanNfZGF0YSB8PiBtdXRhdGUobWFyaXRhbFN0YXRfZmFjdCA9IHJlY29kZV9mYWN0b3IoanNfZGF0YSRtYXJpdGFsU3RhdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMSIgPSAiTWFycmllZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIiID0gIkxpdmluZyBjb21tb24tbGF3IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMyIgPSAiV2lkb3dlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiNCIgPSAiU2VwYXJhdGVkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiNSIgPSAiRGl2b3JjZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICI2IiA9ICJTaW5nbGUsIG5ldmVyIG1hcnJpZWQiKSkKCmNsYXNzKGpzX2RhdGEkbWFyaXRhbFN0YXRfZmFjdCkKYGBgCgo6OjogcXVlc3Rpb24KQ2FuIHlvdSByZWNvZGUgbGV2ZWwgb2YgZWR1Y2F0aW9uIGludG8gYSBmYWN0b3IgdmFyaWFibGU/Cjo6OgoKYGBge3IgY2xhc3Muc291cmNlID0gJ2ZvbGQtaGlkZScsIHJlc3VsdHMgPSAnaGlkZSd9CmpzX2RhdGEgPC0ganNfZGF0YSB8PiBtdXRhdGUoZWR1TGV2ZWxfZmFjdCA9IHJlY29kZV9mYWN0b3IoanNfZGF0YSRlZHVMZXZlbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICIxIiA9ICJMZXNzIHRoYW4gaGlnaCBzY2hvb2wgZGltcGxvbWEgb3IgaXRzIGVxdWl2YWxlbnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIiID0gIkhpZ2ggc2Nob29sIGRpcGxvbWEgb3IgZXF1aXZhbGVuY3kiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIjMiID0gIlRyYWRlIGNlcnRpZmljYXRlIG9yIGRpcGxvbWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIjQiID0gIkNvbGxlZ2UsIENFR0VQLCBvciBvdGhlciBub24tdW5pdmVyc2l0eSBjZXJ0aWZpY2F0ZSBvciBkaW1wbG9tYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiNSIgPSAiVW5pdmVyc2l0eSBjZXJ0aWZpY2F0ZSBvciBkaW1wbG9tYSBiZWxvdyB0aGUgYmFjaGVsb3IncyBsZXZlbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiNiIgPSAiQmFjaGVsb3IncyBkZWdyZWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIjciID0gIlVuaXZlcnNpdHkgY2VydGlmaWNhdGUsIGRpcGxvbWEsIGRlZ3JlZSBhYm92ZSB0aGUgQkEgbGV2ZWwiKSkKCmNsYXNzKGpzX2RhdGEkZWR1TGV2ZWxfZmFjdCkKYGBgCiMjIyBDaGVjayBZb3VyIEtub3dsZWRnZQoKOjo6cXVlc3Rpb24KV2hhdCBkYXRhIHN0cnVjdHVyZSB3b3VsZCB5b3UgdXNlIHRvIHN0b3JlIHRoZSBmb2xsb3dpbmcgZGF0YT8KCmEpIFRoZSBuYW1lcyBvZiAxMCBtb3N0IHBvcHVsYXIgbW92aWVzIHRoaXMgeWVhciAoMTAgZGF0YSBwb2ludHMpCgpiKSBUaGUgbmFtZXMgb2YgdGhlIGxlYWRpbmcgYWN0b3IgZnJvbSBlYWNoIG9mIHRoZSAxMCBtb3N0IHBvcHVsYXIgbW92aWVzIHRoaXMgeWVhciAoMTAgZGF0YSBwb2ludHMgdG90YWwpCgpjKSBBIGNvbGxlY3Rpb24gb2YgYWxsIG9mIHRoZSBhY3RvcnMgaW4gZWFjaCBvZiB0aGUgMTAgbW9zdCBwb3B1bGFyIG1vdmllcyB0aGlzIHllYXIgKDEwMCBkYXRhIHBvaW50cyB0b3RhbCkKCmQpIEEgY29tYmluYXRpb24gb2YgYSBhbmQgYgoKZSkgQSBjb21iaW5hdGlvbiBvZiBhLCBiLCBhbmQgYwoKZikgVGhlIGRhdGEgd2UgaGF2ZSBiZWVuIHdvcmtpbmcgd2l0aCBpbiB0aGlzIHdvcmtzaG9wCjo6OgoKOjo6cXVlc3Rpb24KSXMgb3VyIGRhdGEgaW4gYSBkYXRhIGZyYW1lIGZvcm1hdD8gSGludDogdXNlIHRoZSBmdW5jdGlvbiAiaXMuZGF0YS5mcmFtZSgpIgo6OjoKCg==