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:

  1. What data types exist in R
  2. What data structures exist in R
  3. Introduction to the dplyr package
  4. Recoding existing data into another type of data
  5. 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?

  1. The names of 10 most popular movies this year (10 data points)

  2. The names of the leading actor from each of the 10 most popular movies this year (10 data points total)

  3. A collection of all of the actors in each of the 10 most popular movies this year (100 data points total)

  4. A combination of a and b

  5. A combination of a, b, and c

  6. 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==