read.csv

The utils package, which is automatically loaded in your R session on startup, can import CSV files with the read.csv() function.

# Import test.csv.csv: pools
pools = read.csv("test.csv")

# Print the structure of pools
str(pools)
'data.frame':   205 obs. of  27 variables:
 $ X                : int  0 1 2 3 4 5 6 7 8 9 ...
 $ symboling        : int  3 3 1 2 2 2 1 1 1 0 ...
 $ normalized.losses: Factor w/ 52 levels "?","101","102",..: 1 1 1 29 29 1 27 1 27 1 ...
 $ make             : Factor w/ 22 levels "alfa-romero",..: 1 1 1 2 2 2 2 2 2 2 ...
 $ fuel.type        : Factor w/ 2 levels "diesel","gas": 2 2 2 2 2 2 2 2 2 2 ...
 $ aspiration       : Factor w/ 2 levels "std","turbo": 1 1 1 1 1 1 1 1 2 2 ...
 $ num.of.doors     : Factor w/ 3 levels "?","four","two": 3 3 3 2 2 3 2 2 2 3 ...
 $ body.style       : Factor w/ 5 levels "convertible",..: 1 1 3 4 4 4 4 5 4 3 ...
 $ drive.wheels     : Factor w/ 3 levels "4wd","fwd","rwd": 3 3 3 2 1 2 2 2 2 1 ...
 $ engine.location  : Factor w/ 2 levels "front","rear": 1 1 1 1 1 1 1 1 1 1 ...
 $ wheel.base       : num  88.6 88.6 94.5 99.8 99.4 ...
 $ length           : num  169 169 171 177 177 ...
 $ width            : num  64.1 64.1 65.5 66.2 66.4 66.3 71.4 71.4 71.4 67.9 ...
 $ height           : num  48.8 48.8 52.4 54.3 54.3 53.1 55.7 55.7 55.9 52 ...
 $ curb.weight      : int  2548 2548 2823 2337 2824 2507 2844 2954 3086 3053 ...
 $ engine.type      : Factor w/ 7 levels "dohc","dohcv",..: 1 1 6 4 4 4 4 4 4 4 ...
 $ num.of.cylinders : Factor w/ 7 levels "eight","five",..: 3 3 4 3 2 2 2 2 2 2 ...
 $ engine.size      : int  130 130 152 109 136 136 136 136 131 131 ...
 $ fuel.system      : Factor w/ 8 levels "1bbl","2bbl",..: 6 6 6 6 6 6 6 6 6 6 ...
 $ bore             : Factor w/ 39 levels "?","2.54","2.68",..: 25 25 3 15 15 15 15 15 12 12 ...
 $ stroke           : Factor w/ 37 levels "?","2.07","2.19",..: 6 6 29 26 26 26 26 26 26 26 ...
 $ compression.ratio: num  9 9 9 10 8 8.5 8.5 8.5 8.3 7 ...
 $ horsepower       : Factor w/ 60 levels "?","100","101",..: 7 7 22 4 10 6 6 6 17 25 ...
 $ peak.rpm         : Factor w/ 24 levels "?","4150","4200",..: 12 12 12 18 18 18 18 18 18 18 ...
 $ city.mpg         : int  21 21 19 24 18 19 19 19 17 16 ...
 $ highway.mpg      : int  27 27 26 30 22 25 25 25 20 22 ...
 $ price            : Factor w/ 187 levels "?","10198","10245",..: 33 52 52 38 63 43 65 73 83 1 ...

stringsAsFactors

With stringsAsFactors, you can tell R whether it should convert strings in the flat file to factors.

For all importing functions in the utils package, this argument is TRUE, which means that you import strings as factors. This only makes sense if the strings you import represent categorical variables in R. If you set stringsAsFactors to FALSE, the data frame columns corresponding to strings in your text file will be character.

# Import test.csv.csv: pools
pools = read.csv("test.csv", stringsAsFactors = FALSE)

# Print the structure of pools
str(pools)
'data.frame':   205 obs. of  27 variables:
 $ X                : int  0 1 2 3 4 5 6 7 8 9 ...
 $ symboling        : int  3 3 1 2 2 2 1 1 1 0 ...
 $ normalized.losses: chr  "?" "?" "?" "164" ...
 $ make             : chr  "alfa-romero" "alfa-romero" "alfa-romero" "audi" ...
 $ fuel.type        : chr  "gas" "gas" "gas" "gas" ...
 $ aspiration       : chr  "std" "std" "std" "std" ...
 $ num.of.doors     : chr  "two" "two" "two" "four" ...
 $ body.style       : chr  "convertible" "convertible" "hatchback" "sedan" ...
 $ drive.wheels     : chr  "rwd" "rwd" "rwd" "fwd" ...
 $ engine.location  : chr  "front" "front" "front" "front" ...
 $ wheel.base       : num  88.6 88.6 94.5 99.8 99.4 ...
 $ length           : num  169 169 171 177 177 ...
 $ width            : num  64.1 64.1 65.5 66.2 66.4 66.3 71.4 71.4 71.4 67.9 ...
 $ height           : num  48.8 48.8 52.4 54.3 54.3 53.1 55.7 55.7 55.9 52 ...
 $ curb.weight      : int  2548 2548 2823 2337 2824 2507 2844 2954 3086 3053 ...
 $ engine.type      : chr  "dohc" "dohc" "ohcv" "ohc" ...
 $ num.of.cylinders : chr  "four" "four" "six" "four" ...
 $ engine.size      : int  130 130 152 109 136 136 136 136 131 131 ...
 $ fuel.system      : chr  "mpfi" "mpfi" "mpfi" "mpfi" ...
 $ bore             : chr  "3.47" "3.47" "2.68" "3.19" ...
 $ stroke           : chr  "2.68" "2.68" "3.47" "3.40" ...
 $ compression.ratio: num  9 9 9 10 8 8.5 8.5 8.5 8.3 7 ...
 $ horsepower       : chr  "111" "111" "154" "102" ...
 $ peak.rpm         : chr  "5000" "5000" "5000" "5500" ...
 $ city.mpg         : int  21 21 19 24 18 19 19 19 17 16 ...
 $ highway.mpg      : int  27 27 26 30 22 25 25 25 20 22 ...
 $ price            : chr  "13495" "16500" "16500" "13950" ...

tab delimited

Aside from .csv files, there are also the .txt files which are basically text files. You can import these functions with read.delim(). By default, it sets the sep argument to " (fields in a record are delimited by tabs) and the header argument to TRUE (the first row contains the field names).

# Import hotdogs.txt: hotdogs
hotdogs = read.delim("hotdogs.txt", header = FALSE)

# Summarize hotdogs
summary(hotdogs)
       V1           V2              V3       
 Beef   :20   Min.   : 86.0   Min.   :144.0  
 Meat   :17   1st Qu.:132.0   1st Qu.:362.5  
 Poultry:17   Median :145.0   Median :405.0  
              Mean   :145.4   Mean   :424.8  
              3rd Qu.:172.8   3rd Qu.:503.5  
              Max.   :195.0   Max.   :645.0  

read.table

f you’re dealing with more exotic flat file formats, you’ll want to use read.table(). It’s the most basic importing function; you can specify tons of different arguments in this function. Unlike read.csv() and read.delim(), the header argument defaults to FALSE and the sep argument is "" by default.

# Path to the hotdogs.txt file: path
path <- file.path("hotdogs.txt")

# Import the hotdogs.txt file: hotdogs
hotdogs <- read.table(path, 
                      sep = "\t", 
                      col.names = c("type", "calories", "sodium"))

# Call head() on hotdogs
head(hotdogs)

Arguments

# Finish the read.delim() call
hotdogs <- read.delim("hotdogs.txt", header = FALSE, col.names = c("type", "calories", "sodium"))

# Select the hot dog with the least calories: lily
lily <- hotdogs[which.min(hotdogs$calories), ]

# Select the observation with the most sodium: tom
tom <- hotdogs[which.max(hotdogs$sodium), ]

# Print lily and tom
lily
tom

Column classes

Next to column names, you can also specify the column types or column classes of the resulting data frame. You can do this by setting the colClasses argument to a vector of strings representing classes.

This approach can be useful if you have some columns that should be factors and others that should be characters. You don’t have to bother with stringsAsFactors anymore; just state for each column what the class should be.

If a column is set to “NULL” in the colClasses vector, this column will be skipped and will not be loaded into the data frame.

# Previous call to import hotdogs.txt
hotdogs <- read.delim("hotdogs.txt", header = FALSE, col.names = c("type", "calories", "sodium"))

# Display structure of hotdogs
str(hotdogs)
'data.frame':   54 obs. of  3 variables:
 $ type    : Factor w/ 3 levels "Beef","Meat",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ calories: int  186 181 176 149 184 190 158 139 175 148 ...
 $ sodium  : int  495 477 425 322 482 587 370 322 479 375 ...
# Edit the colClasses argument to import the data correctly: hotdogs2
hotdogs2 <- read.delim("hotdogs.txt", header = FALSE, 
                       col.names = c("type", "calories", "sodium"),
                       colClasses = c("factor", "NULL", "numeric"))


# Display structure of hotdogs2
str(hotdogs2)
'data.frame':   54 obs. of  2 variables:
 $ type  : Factor w/ 3 levels "Beef","Meat",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ sodium: num  495 477 425 322 482 587 370 322 479 375 ...

readr

read_csv

CSV files can be imported with read_csv(). It’s a wrapper function around read_delim() that handles all the details for you. For example, it will assume that the first row contains the column names.

# Load the readr package
library(readr)

# Import potatoes.csv with read_csv(): potatoes
potatoes <- read_csv("potatoes.csv")
Parsed with column specification:
cols(
  area = col_double(),
  temp = col_double(),
  size = col_double(),
  storage = col_double(),
  method = col_double(),
  texture = col_double(),
  flavor = col_double(),
  moistness = col_double()
)

read_tsv

Where you use read_csv() to easily read in CSV files, you use read_tsv() to easily read in TSV files. TSV is short for tab-separated values.

# Column names
properties <- c("area", "temp", "size", "storage", "method",
                "texture", "flavor", "moistness")

# Import potatoes.txt: potatoes
potatoes <- read_tsv("potatoes.txt", col_names = properties)
Parsed with column specification:
cols(
  area = col_double(),
  temp = col_double(),
  size = col_double(),
  storage = col_double(),
  method = col_double(),
  texture = col_double(),
  flavor = col_double(),
  moistness = col_double()
)
# Call head() on potatoes
head(potatoes)

read_delim

Just as read.table() was the main utils function, read_delim() is the main readr function.

read_delim() takes two mandatory arguments:

# Column names
properties <- c("area", "temp", "size", "storage", "method",
                "texture", "flavor", "moistness")

# Import potatoes.txt using read_delim(): potatoes
potatoes <- read_delim("potatoes.txt", delim = "\t", col_names = properties)
Parsed with column specification:
cols(
  area = col_double(),
  temp = col_double(),
  size = col_double(),
  storage = col_double(),
  method = col_double(),
  texture = col_double(),
  flavor = col_double(),
  moistness = col_double()
)
# Print out potatoes
potatoes

skip and n_max

Through skip and n_max you can control which part of your flat file you’re actually importing into R.

Once you skip some lines, you also skip the first line that can contain column names!

# Column names
properties <- c("area", "temp", "size", "storage", "method",
                "texture", "flavor", "moistness")

# Import 5 observations from potatoes.txt: potatoes_fragment
potatoes_fragment <- read_tsv("potatoes.txt", skip = 6, n_max = 5, col_names = properties)
Parsed with column specification:
cols(
  area = col_double(),
  temp = col_double(),
  size = col_double(),
  storage = col_double(),
  method = col_double(),
  texture = col_double(),
  flavor = col_double(),
  moistness = col_double()
)

col_types

You can also specify which types the columns in your imported data frame should have. You can do this with col_types. If set to NULL, the default, functions from the readr package will try to find the correct types themselves. You can manually set the types with a string, where each character denotes the class of the column: character, double, integer and logical. _ skips the column as a whole.

# Column names
properties <- c("area", "temp", "size", "storage", "method",
                "texture", "flavor", "moistness")

# Import all data, but force all columns to be character: potatoes_char
potatoes_char <- read_tsv("potatoes.txt", col_types = "cccccccc", col_names = properties)

# Print out structure of potatoes_char
str(potatoes_char)
Classes ‘spec_tbl_df’, ‘tbl_df’, ‘tbl’ and 'data.frame':    160 obs. of  8 variables:
 $ area     : chr  "1" "1" "1" "1" ...
 $ temp     : chr  "1" "1" "1" "1" ...
 $ size     : chr  "1" "1" "1" "1" ...
 $ storage  : chr  "1" "1" "1" "1" ...
 $ method   : chr  "1" "2" "3" "4" ...
 $ texture  : chr  "2.9" "2.3" "2.5" "2.1" ...
 $ flavor   : chr  "3.2" "2.5" "2.8" "2.9" ...
 $ moistness: chr  "3.0" "2.6" "2.8" "2.4" ...
 - attr(*, "spec")=
  .. cols(
  ..   area = col_character(),
  ..   temp = col_character(),
  ..   size = col_character(),
  ..   storage = col_character(),
  ..   method = col_character(),
  ..   texture = col_character(),
  ..   flavor = col_character(),
  ..   moistness = col_character()
  .. )

col_types with collectors

Another way of setting the types of the imported columns is using collectors. Collector functions can be passed in a list() to the col_types argument of read_ functions to tell them how to interpret values in a column.

For a complete list of collector functions, you can take a look at the collector documentation.

For example: - col_integer(): the column should be interpreted as an integer. - col_factor(levels, ordered = FALSE): the column should be interpreted as a factor with levels.

# Import without col_types
hotdogs <- read_tsv("hotdogs.txt", col_names = c("type", "calories", "sodium"))
Parsed with column specification:
cols(
  type = col_character(),
  calories = col_double(),
  sodium = col_double()
)
# Display the summary of hotdogs
summary(hotdogs)
     type              calories         sodium     
 Length:54          Min.   : 86.0   Min.   :144.0  
 Class :character   1st Qu.:132.0   1st Qu.:362.5  
 Mode  :character   Median :145.0   Median :405.0  
                    Mean   :145.4   Mean   :424.8  
                    3rd Qu.:172.8   3rd Qu.:503.5  
                    Max.   :195.0   Max.   :645.0  
# The collectors you will need to import the data
fac <- col_factor(levels = c("Beef", "Meat", "Poultry"))
int <- col_integer()

# Edit the col_types argument to import the data correctly: hotdogs_factor
hotdogs_factor <- read_tsv("hotdogs.txt",
                           col_names = c("type", "calories", "sodium"),
                           col_types = list(fac, int, int))

# Display the summary of hotdogs_factor
summary(hotdogs_factor)
      type       calories         sodium     
 Beef   :20   Min.   : 86.0   Min.   :144.0  
 Meat   :17   1st Qu.:132.0   1st Qu.:362.5  
 Poultry:17   Median :145.0   Median :405.0  
              Mean   :145.4   Mean   :424.8  
              3rd Qu.:172.8   3rd Qu.:503.5  
              Max.   :195.0   Max.   :645.0  

data.table

library(data.table)
package 㤼㸱data.table㤼㸲 was built under R version 3.6.3Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
data.table 1.12.8 using 1 threads (see ?getDTthreads).  Latest news: r-datatable.com

fread

You still remember how to use read.table(), right? Well, fread() is a function that does the same job with very similar arguments. It is extremely easy to use and blazingly fast! Often, simply specifying the path to the file is enough to successfully import your data.

# Import potatoes.csv with fread(): potatoes
potatoes <- fread("potatoes.csv")

# Print out potatoes
potatoes

fread: drop and select

to drop or select variables of interest.

# Import columns 6 and 8 of potatoes.csv: potatoes
potatoes = (fread("potatoes.csv", select = c(6,8)))

# Plot texture (x) and moistness (y) of potatoes
plot(x <- potatoes$texture, y <- potatoes$moistness, main = "Potatoes", xlab = "Texture", ylab = "moistness")

You might have noticed that the fread() function produces data frames that look slightly different when you print them out. That’s because another class named data.table is assigned to the resulting data frames. The printout of such data.table objects is different. Does something similar happen with the data frames generated by readr?

readxl (tidyverse)

Before you can start importing from Excel, you should find out which sheets are available in the workbook. You can use the excel_sheets() function for this.

# Load the readxl package
library(readxl)
# Print the names of all worksheets
excel_sheets("urbanpop.xlsx")
[1] "1960-1966" "1967-1974" "1975-2011"

Now that you know the names of the sheets in the Excel file you want to import, it is time to import those sheets into R. You can do this with the read_excel() function.

# Read the sheets, one by one
pop_1 <- read_excel("urbanpop.xlsx", sheet = 1)
pop_2 <- read_excel("urbanpop.xlsx", sheet = 2)
pop_3 <- read_excel("urbanpop.xlsx", sheet = "1975-2011")

# Put pop_1, pop_2 and pop_3 in a list: pop_list
pop_list <- list(pop_1, pop_2, pop_3)

# Display the structure of pop_list
str(pop_list)
List of 3
 $ :Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   209 obs. of  8 variables:
  ..$ country: chr [1:209] "Afghanistan" "Albania" "Algeria" "American Samoa" ...
  ..$ 1960   : num [1:209] 769308 494443 3293999 NA NA ...
  ..$ 1961   : num [1:209] 814923 511803 3515148 13660 8724 ...
  ..$ 1962   : num [1:209] 858522 529439 3739963 14166 9700 ...
  ..$ 1963   : num [1:209] 903914 547377 3973289 14759 10748 ...
  ..$ 1964   : num [1:209] 951226 565572 4220987 15396 11866 ...
  ..$ 1965   : num [1:209] 1000582 583983 4488176 16045 13053 ...
  ..$ 1966   : num [1:209] 1058743 602512 4649105 16693 14217 ...
 $ :Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   209 obs. of  9 variables:
  ..$ country: chr [1:209] "Afghanistan" "Albania" "Algeria" "American Samoa" ...
  ..$ 1967   : num [1:209] 1119067 621180 4826104 17349 15440 ...
  ..$ 1968   : num [1:209] 1182159 639964 5017299 17996 16727 ...
  ..$ 1969   : num [1:209] 1248901 658853 5219332 18619 18088 ...
  ..$ 1970   : num [1:209] 1319849 677839 5429743 19206 19529 ...
  ..$ 1971   : num [1:209] 1409001 698932 5619042 19752 20929 ...
  ..$ 1972   : num [1:209] 1502402 720207 5815734 20263 22406 ...
  ..$ 1973   : num [1:209] 1598835 741681 6020647 20742 23937 ...
  ..$ 1974   : num [1:209] 1696445 763385 6235114 21194 25482 ...
 $ :Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   209 obs. of  38 variables:
  ..$ country: chr [1:209] "Afghanistan" "Albania" "Algeria" "American Samoa" ...
  ..$ 1975   : num [1:209] 1793266 785350 6460138 21632 27019 ...
  ..$ 1976   : num [1:209] 1905033 807990 6774099 22047 28366 ...
  ..$ 1977   : num [1:209] 2021308 830959 7102902 22452 29677 ...
  ..$ 1978   : num [1:209] 2142248 854262 7447728 22899 31037 ...
  ..$ 1979   : num [1:209] 2268015 877898 7810073 23457 32572 ...
  ..$ 1980   : num [1:209] 2398775 901884 8190772 24177 34366 ...
  ..$ 1981   : num [1:209] 2493265 927224 8637724 25173 36356 ...
  ..$ 1982   : num [1:209] 2590846 952447 9105820 26342 38618 ...
  ..$ 1983   : num [1:209] 2691612 978476 9591900 27655 40983 ...
  ..$ 1984   : num [1:209] 2795656 1006613 10091289 29062 43207 ...
  ..$ 1985   : num [1:209] 2903078 1037541 10600112 30524 45119 ...
  ..$ 1986   : num [1:209] 3006983 1072365 11101757 32014 46254 ...
  ..$ 1987   : num [1:209] 3113957 1109954 11609104 33548 47019 ...
  ..$ 1988   : num [1:209] 3224082 1146633 12122941 35095 47669 ...
  ..$ 1989   : num [1:209] 3337444 1177286 12645263 36618 48577 ...
  ..$ 1990   : num [1:209] 3454129 1198293 13177079 38088 49982 ...
  ..$ 1991   : num [1:209] 3617842 1215445 13708813 39600 51972 ...
  ..$ 1992   : num [1:209] 3788685 1222544 14248297 41049 54469 ...
  ..$ 1993   : num [1:209] 3966956 1222812 14789176 42443 57079 ...
  ..$ 1994   : num [1:209] 4152960 1221364 15322651 43798 59243 ...
  ..$ 1995   : num [1:209] 4347018 1222234 15842442 45129 60598 ...
  ..$ 1996   : num [1:209] 4531285 1228760 16395553 46343 60927 ...
  ..$ 1997   : num [1:209] 4722603 1238090 16935451 47527 60462 ...
  ..$ 1998   : num [1:209] 4921227 1250366 17469200 48705 59685 ...
  ..$ 1999   : num [1:209] 5127421 1265195 18007937 49906 59281 ...
  ..$ 2000   : num [1:209] 5341456 1282223 18560597 51151 59719 ...
  ..$ 2001   : num [1:209] 5564492 1315690 19198872 52341 61062 ...
  ..$ 2002   : num [1:209] 5795940 1352278 19854835 53583 63212 ...
  ..$ 2003   : num [1:209] 6036100 1391143 20529356 54864 65802 ...
  ..$ 2004   : num [1:209] 6285281 1430918 21222198 56166 68301 ...
  ..$ 2005   : num [1:209] 6543804 1470488 21932978 57474 70329 ...
  ..$ 2006   : num [1:209] 6812538 1512255 22625052 58679 71726 ...
  ..$ 2007   : num [1:209] 7091245 1553491 23335543 59894 72684 ...
  ..$ 2008   : num [1:209] 7380272 1594351 24061749 61118 73335 ...
  ..$ 2009   : num [1:209] 7679982 1635262 24799591 62357 73897 ...
  ..$ 2010   : num [1:209] 7990746 1676545 25545622 63616 74525 ...
  ..$ 2011   : num [1:209] 8316976 1716842 26216968 64817 75207 ...

Loading in every sheet manually and then merging them in a list can be quite tedious. Luckily, you can automate this with lapply().

# Read all Excel sheets with lapply(): pop_list
pop_list <- lapply(excel_sheets("urbanpop.xlsx"),
read_excel,
path = "urbanpop.xlsx")

# Display the structure of pop_list
str(pop_list)
List of 3
 $ :Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   209 obs. of  8 variables:
  ..$ country: chr [1:209] "Afghanistan" "Albania" "Algeria" "American Samoa" ...
  ..$ 1960   : num [1:209] 769308 494443 3293999 NA NA ...
  ..$ 1961   : num [1:209] 814923 511803 3515148 13660 8724 ...
  ..$ 1962   : num [1:209] 858522 529439 3739963 14166 9700 ...
  ..$ 1963   : num [1:209] 903914 547377 3973289 14759 10748 ...
  ..$ 1964   : num [1:209] 951226 565572 4220987 15396 11866 ...
  ..$ 1965   : num [1:209] 1000582 583983 4488176 16045 13053 ...
  ..$ 1966   : num [1:209] 1058743 602512 4649105 16693 14217 ...
 $ :Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   209 obs. of  9 variables:
  ..$ country: chr [1:209] "Afghanistan" "Albania" "Algeria" "American Samoa" ...
  ..$ 1967   : num [1:209] 1119067 621180 4826104 17349 15440 ...
  ..$ 1968   : num [1:209] 1182159 639964 5017299 17996 16727 ...
  ..$ 1969   : num [1:209] 1248901 658853 5219332 18619 18088 ...
  ..$ 1970   : num [1:209] 1319849 677839 5429743 19206 19529 ...
  ..$ 1971   : num [1:209] 1409001 698932 5619042 19752 20929 ...
  ..$ 1972   : num [1:209] 1502402 720207 5815734 20263 22406 ...
  ..$ 1973   : num [1:209] 1598835 741681 6020647 20742 23937 ...
  ..$ 1974   : num [1:209] 1696445 763385 6235114 21194 25482 ...
 $ :Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   209 obs. of  38 variables:
  ..$ country: chr [1:209] "Afghanistan" "Albania" "Algeria" "American Samoa" ...
  ..$ 1975   : num [1:209] 1793266 785350 6460138 21632 27019 ...
  ..$ 1976   : num [1:209] 1905033 807990 6774099 22047 28366 ...
  ..$ 1977   : num [1:209] 2021308 830959 7102902 22452 29677 ...
  ..$ 1978   : num [1:209] 2142248 854262 7447728 22899 31037 ...
  ..$ 1979   : num [1:209] 2268015 877898 7810073 23457 32572 ...
  ..$ 1980   : num [1:209] 2398775 901884 8190772 24177 34366 ...
  ..$ 1981   : num [1:209] 2493265 927224 8637724 25173 36356 ...
  ..$ 1982   : num [1:209] 2590846 952447 9105820 26342 38618 ...
  ..$ 1983   : num [1:209] 2691612 978476 9591900 27655 40983 ...
  ..$ 1984   : num [1:209] 2795656 1006613 10091289 29062 43207 ...
  ..$ 1985   : num [1:209] 2903078 1037541 10600112 30524 45119 ...
  ..$ 1986   : num [1:209] 3006983 1072365 11101757 32014 46254 ...
  ..$ 1987   : num [1:209] 3113957 1109954 11609104 33548 47019 ...
  ..$ 1988   : num [1:209] 3224082 1146633 12122941 35095 47669 ...
  ..$ 1989   : num [1:209] 3337444 1177286 12645263 36618 48577 ...
  ..$ 1990   : num [1:209] 3454129 1198293 13177079 38088 49982 ...
  ..$ 1991   : num [1:209] 3617842 1215445 13708813 39600 51972 ...
  ..$ 1992   : num [1:209] 3788685 1222544 14248297 41049 54469 ...
  ..$ 1993   : num [1:209] 3966956 1222812 14789176 42443 57079 ...
  ..$ 1994   : num [1:209] 4152960 1221364 15322651 43798 59243 ...
  ..$ 1995   : num [1:209] 4347018 1222234 15842442 45129 60598 ...
  ..$ 1996   : num [1:209] 4531285 1228760 16395553 46343 60927 ...
  ..$ 1997   : num [1:209] 4722603 1238090 16935451 47527 60462 ...
  ..$ 1998   : num [1:209] 4921227 1250366 17469200 48705 59685 ...
  ..$ 1999   : num [1:209] 5127421 1265195 18007937 49906 59281 ...
  ..$ 2000   : num [1:209] 5341456 1282223 18560597 51151 59719 ...
  ..$ 2001   : num [1:209] 5564492 1315690 19198872 52341 61062 ...
  ..$ 2002   : num [1:209] 5795940 1352278 19854835 53583 63212 ...
  ..$ 2003   : num [1:209] 6036100 1391143 20529356 54864 65802 ...
  ..$ 2004   : num [1:209] 6285281 1430918 21222198 56166 68301 ...
  ..$ 2005   : num [1:209] 6543804 1470488 21932978 57474 70329 ...
  ..$ 2006   : num [1:209] 6812538 1512255 22625052 58679 71726 ...
  ..$ 2007   : num [1:209] 7091245 1553491 23335543 59894 72684 ...
  ..$ 2008   : num [1:209] 7380272 1594351 24061749 61118 73335 ...
  ..$ 2009   : num [1:209] 7679982 1635262 24799591 62357 73897 ...
  ..$ 2010   : num [1:209] 7990746 1676545 25545622 63616 74525 ...
  ..$ 2011   : num [1:209] 8316976 1716842 26216968 64817 75207 ...

Apart from path and sheet, there are several other arguments you can specify in read_excel(). One of these arguments is called col_names.

By default it is TRUE, denoting whether the first row in the Excel sheets contains the column names. If this is not the case, you can set col_names to FALSE. In this case, R will choose column names for you. You can also choose to set col_names to a character vector with names for each column. It works exactly the same as in the readr package.

# Import the first Excel sheet of urbanpop_nonames.xlsx (R gives names): pop_a
pop_a <- read_excel("urbanpop_nonames.xlsx",
col_names = FALSE)
New names:
* `` -> ...1
* `` -> ...2
* `` -> ...3
* `` -> ...4
* `` -> ...5
* ... and 3 more problems
# Import the first Excel sheet of urbanpop_nonames.xlsx (specify col_names): pop_b
cols <- c("country", paste0("year_", 1960:1966))
pop_b <- read_excel("urbanpop_nonames.xlsx",
col_names = cols)

# Print the summary of pop_a
summary(pop_a)
     ...1                ...2                ...3          
 Length:209         Min.   :     3378   Min.   :     1028  
 Class :character   1st Qu.:    88978   1st Qu.:    70644  
 Mode  :character   Median :   580675   Median :   570159  
                    Mean   :  4988124   Mean   :  4991613  
                    3rd Qu.:  3077228   3rd Qu.:  2807280  
                    Max.   :126469700   Max.   :129268133  
                    NA's   :11                             
      ...4                ...5                ...6          
 Min.   :     1090   Min.   :     1154   Min.   :     1218  
 1st Qu.:    74974   1st Qu.:    81870   1st Qu.:    84953  
 Median :   593968   Median :   619331   Median :   645262  
 Mean   :  5141592   Mean   :  5303711   Mean   :  5468966  
 3rd Qu.:  2948396   3rd Qu.:  3148941   3rd Qu.:  3296444  
 Max.   :131974143   Max.   :134599886   Max.   :137205240  
                                                            
      ...7                ...8          
 Min.   :     1281   Min.   :     1349  
 1st Qu.:    88633   1st Qu.:    93638  
 Median :   679109   Median :   735139  
 Mean   :  5637394   Mean   :  5790281  
 3rd Qu.:  3317422   3rd Qu.:  3418036  
 Max.   :139663053   Max.   :141962708  
                                        
summary(pop_b)
   country            year_1960           year_1961        
 Length:209         Min.   :     3378   Min.   :     1028  
 Class :character   1st Qu.:    88978   1st Qu.:    70644  
 Mode  :character   Median :   580675   Median :   570159  
                    Mean   :  4988124   Mean   :  4991613  
                    3rd Qu.:  3077228   3rd Qu.:  2807280  
                    Max.   :126469700   Max.   :129268133  
                    NA's   :11                             
   year_1962           year_1963           year_1964        
 Min.   :     1090   Min.   :     1154   Min.   :     1218  
 1st Qu.:    74974   1st Qu.:    81870   1st Qu.:    84953  
 Median :   593968   Median :   619331   Median :   645262  
 Mean   :  5141592   Mean   :  5303711   Mean   :  5468966  
 3rd Qu.:  2948396   3rd Qu.:  3148941   3rd Qu.:  3296444  
 Max.   :131974143   Max.   :134599886   Max.   :137205240  
                                                            
   year_1965           year_1966        
 Min.   :     1281   Min.   :     1349  
 1st Qu.:    88633   1st Qu.:    93638  
 Median :   679109   Median :   735139  
 Mean   :  5637394   Mean   :  5790281  
 3rd Qu.:  3317422   3rd Qu.:  3418036  
 Max.   :139663053   Max.   :141962708  
                                        

Another argument that can be very useful when reading in Excel files that are less tidy, is skip. With skip, you can tell R to ignore a specified number of rows inside the Excel sheets you’re trying to pull data from.

# Import the second sheet of urbanpop.xlsx, skipping the first 21 rows: urbanpop_sel
urbanpop_sel <- read_excel("urbanpop.xlsx", sheet = 2, skip = 21, col_names = FALSE)
New names:
* `` -> ...1
* `` -> ...2
* `` -> ...3
* `` -> ...4
* `` -> ...5
* ... and 4 more problems
# Print out the first observation from urbanpop_sel
head(urbanpop_sel, n=1)

gdata

In this part of the chapter you’ll learn how to import .xls files using the gdata package. Similar to the readxl package, you can import single Excel sheets from Excel sheets to start your analysis in R.

library("gdata")
gdata: Unable to locate valid perl interpreter
gdata: 
gdata: read.xls() will be unable to read Excel XLS and XLSX
gdata: files unless the 'perl=' argument is used to specify
gdata: the location of a valid perl intrpreter.
gdata: 
gdata: (To avoid display of this message in the future, please
gdata: ensure perl is installed and available on the
gdata: executable search path.)
gdata: Unable to load perl libaries needed by read.xls()
gdata: to support 'XLX' (Excel 97-2004) files.

gdata: Unable to load perl libaries needed by read.xls()
gdata: to support 'XLSX' (Excel 2007+) files.

gdata: Run the function 'installXLSXsupport()'
gdata: to automatically download and install the perl
gdata: libaries needed to support Excel XLS and XLSX formats.

Attaching package: 㤼㸱gdata㤼㸲

The following objects are masked from 㤼㸱package:data.table㤼㸲:

    first, last

The following object is masked from 㤼㸱package:stats㤼㸲:

    nobs

The following object is masked from 㤼㸱package:utils㤼㸲:

    object.size

The following object is masked from 㤼㸱package:base㤼㸲:

    startsWith
# Import the second sheet of urbanpop.xls: urban_pop
urban_pop <- read.xls("urbanpop.xls", sheet = 2, perl="c:/Program Files/Git/usr/bin/perl.exe")

# Print the first 11 observations using head()
head(urban_pop, 11)

read.xls() wraps around read.table()

Remember how read.xls() actually works? It basically comes down to two steps: converting the Excel file to a .csv file using a Perl script, and then reading that .csv file with the read.csv() function that is loaded by default in R, through the utils package.

This means that all the options that you can specify in read.csv(), can also be specified in read.xls().

# Column names for urban_pop
columns <- c("country", paste0("year_", 1967:1974))

# Finish the read.xls call
urban_pop <- read.xls("urbanpop.xls", sheet = 2,
                      skip = 50, header = FALSE, stringsAsFactors = FALSE,
                      col.names = columns, perl="c:/Program Files/Git/usr/bin/perl.exe")

# Print first 10 observation of urban_pop
head(urban_pop, 10)

Now that you can read in Excel data, let’s try to clean and merge it. You already used the cbind() function some exercises ago.

# Add code to import data from all three sheets in urbanpop.xls
path <- "urbanpop.xls"
p <- "c:/Program Files/Git/usr/bin/perl.exe"
urban_sheet1 <- read.xls(path, sheet = 1, stringsAsFactors = FALSE, perl=p)
urban_sheet2 <- read.xls(path, sheet = 2, stringsAsFactors = FALSE, perl=p)
urban_sheet3 <- read.xls(path, sheet = 3, stringsAsFactors = FALSE, perl=p)

# Extend the cbind() call to include urban_sheet3: urban
urban <- cbind(urban_sheet1, urban_sheet2[-1], urban_sheet3[-1])

# Remove all rows with NAs from urban: urban_clean
urban_clean <- na.omit(urban)

# Print out a summary of urban_clean
summary(urban_clean)
   country              X1960               X1961          
 Length:197         Min.   :     3378   Min.   :     3433  
 Class :character   1st Qu.:    87735   1st Qu.:    92905  
 Mode  :character   Median :   599714   Median :   630788  
                    Mean   :  5012388   Mean   :  5282488  
                    3rd Qu.:  3130085   3rd Qu.:  3155370  
                    Max.   :126469700   Max.   :129268133  
     X1962               X1963               X1964          
 Min.   :     3481   Min.   :     3532   Min.   :     3586  
 1st Qu.:    98331   1st Qu.:   104988   1st Qu.:   112084  
 Median :   659464   Median :   704989   Median :   740609  
 Mean   :  5440972   Mean   :  5612312   Mean   :  5786961  
 3rd Qu.:  3250211   3rd Qu.:  3416490   3rd Qu.:  3585464  
 Max.   :131974143   Max.   :134599886   Max.   :137205240  
     X1965               X1966               X1967          
 Min.   :     3644   Min.   :     3706   Min.   :     3771  
 1st Qu.:   119322   1st Qu.:   128565   1st Qu.:   138024  
 Median :   774957   Median :   809768   Median :   838449  
 Mean   :  5964970   Mean   :  6126413   Mean   :  6288771  
 3rd Qu.:  3666724   3rd Qu.:  3871757   3rd Qu.:  4019906  
 Max.   :139663053   Max.   :141962708   Max.   :144201722  
     X1968               X1969               X1970          
 Min.   :     3835   Min.   :     3893   Min.   :     3941  
 1st Qu.:   147846   1st Qu.:   158252   1st Qu.:   171063  
 Median :   890270   Median :   929450   Median :   976471  
 Mean   :  6451367   Mean   :  6624909   Mean   :  6799110  
 3rd Qu.:  4158186   3rd Qu.:  4300669   3rd Qu.:  4440047  
 Max.   :146340364   Max.   :148475901   Max.   :150922373  
     X1971               X1972               X1973          
 Min.   :     4017   Min.   :     4084   Min.   :     4146  
 1st Qu.:   181483   1st Qu.:   189492   1st Qu.:   197792  
 Median :  1008630   Median :  1048738   Median :  1097293  
 Mean   :  6980895   Mean   :  7165338   Mean   :  7349454  
 3rd Qu.:  4595966   3rd Qu.:  4766545   3rd Qu.:  4838297  
 Max.   :152863831   Max.   :154530473   Max.   :156034106  
     X1974               X1975               X1976          
 Min.   :     4206   Min.   :     4267   Min.   :     4334  
 1st Qu.:   205410   1st Qu.:   211746   1st Qu.:   216991  
 Median :  1159402   Median :  1223146   Median :  1249829  
 Mean   :  7540446   Mean   :  7731973   Mean   :  7936401  
 3rd Qu.:  4906384   3rd Qu.:  5003370   3rd Qu.:  5121118  
 Max.   :157488074   Max.   :159452730   Max.   :165583752  
     X1977               X1978               X1979          
 Min.   :     4402   Min.   :     4470   Min.   :     4539  
 1st Qu.:   222209   1st Qu.:   227605   1st Qu.:   233461  
 Median :  1311276   Median :  1340811   Median :  1448185  
 Mean   :  8145945   Mean   :  8361360   Mean   :  8583138  
 3rd Qu.:  5227677   3rd Qu.:  5352746   3rd Qu.:  5558850  
 Max.   :171550310   Max.   :177605736   Max.   :183785364  
     X1980               X1981               X1982          
 Min.   :     4607   Min.   :     4645   Min.   :     4681  
 1st Qu.:   242583   1st Qu.:   248948   1st Qu.:   257944  
 Median :  1592397   Median :  1673079   Median :  1713060  
 Mean   :  8808772   Mean   :  9049163   Mean   :  9295226  
 3rd Qu.:  5815772   3rd Qu.:  6070457   3rd Qu.:  6337995  
 Max.   :189947471   Max.   :199385258   Max.   :209435968  
     X1983               X1984               X1985          
 Min.   :     4716   Min.   :     4750   Min.   :     4782  
 1st Qu.:   274139   1st Qu.:   284939   1st Qu.:   300928  
 Median :  1730626   Median :  1749033   Median :  1786125  
 Mean   :  9545035   Mean   :  9798559   Mean   : 10058661  
 3rd Qu.:  6619987   3rd Qu.:  6918261   3rd Qu.:  6931780  
 Max.   :219680098   Max.   :229872397   Max.   :240414890  
     X1986               X1987               X1988          
 Min.   :     4809   Min.   :     4835   Min.   :     4859  
 1st Qu.:   307699   1st Qu.:   321125   1st Qu.:   334616  
 Median :  1850910   Median :  1953694   Median :  1997011  
 Mean   : 10323839   Mean   : 10595817   Mean   : 10873041  
 3rd Qu.:  6935763   3rd Qu.:  6939905   3rd Qu.:  6945022  
 Max.   :251630158   Max.   :263433513   Max.   :275570541  
     X1989               X1990               X1991          
 Min.   :     4883   Min.   :     4907   Min.   :     4946  
 1st Qu.:   347348   1st Qu.:   370152   1st Qu.:   394611  
 Median :  1993544   Median :  2066505   Median :  2150230  
 Mean   : 11154458   Mean   : 11438543   Mean   : 11725076  
 3rd Qu.:  6885378   3rd Qu.:  6830026   3rd Qu.:  6816589  
 Max.   :287810747   Max.   :300165618   Max.   :314689997  
     X1992               X1993               X1994          
 Min.   :     4985   Min.   :     5024   Min.   :     5062  
 1st Qu.:   418788   1st Qu.:   427457   1st Qu.:   435959  
 Median :  2237405   Median :  2322158   Median :  2410297  
 Mean   : 12010922   Mean   : 12296949   Mean   : 12582930  
 3rd Qu.:  6820099   3rd Qu.:  7139656   3rd Qu.:  7499901  
 Max.   :329099365   Max.   :343555327   Max.   :358232230  
     X1995               X1996               X1997          
 Min.   :     5100   Min.   :     5079   Min.   :     5055  
 1st Qu.:   461993   1st Qu.:   488136   1st Qu.:   494203  
 Median :  2482393   Median :  2522460   Median :  2606125  
 Mean   : 12871480   Mean   : 13165924   Mean   : 13463675  
 3rd Qu.:  7708571   3rd Qu.:  7686092   3rd Qu.:  7664316  
 Max.   :373035157   Max.   :388936607   Max.   :405031716  
     X1998               X1999               X2000          
 Min.   :     5029   Min.   :     5001   Min.   :     4971  
 1st Qu.:   498002   1st Qu.:   505144   1st Qu.:   525629  
 Median :  2664983   Median :  2737809   Median :  2826647  
 Mean   : 13762861   Mean   : 14063387   Mean   : 14369278  
 3rd Qu.:  7784056   3rd Qu.:  8083488   3rd Qu.:  8305564  
 Max.   :421147610   Max.   :437126845   Max.   :452999147  
     X2001               X2002               X2003          
 Min.   :     5003   Min.   :     5034   Min.   :     5064  
 1st Qu.:   550638   1st Qu.:   567531   1st Qu.:   572094  
 Median :  2925851   Median :  2928252   Median :  2944934  
 Mean   : 14705743   Mean   : 15043381   Mean   : 15384513  
 3rd Qu.:  8421967   3rd Qu.:  8448628   3rd Qu.:  8622732  
 Max.   :473204511   Max.   :493402140   Max.   :513607776  
     X2004               X2005               X2006          
 Min.   :     5090   Min.   :     5111   Min.   :     5135  
 1st Qu.:   593900   1st Qu.:   620511   1st Qu.:   632659  
 Median :  2994356   Median :  3057923   Median :  3269963  
 Mean   : 15730299   Mean   : 16080262   Mean   : 16435872  
 3rd Qu.:  8999112   3rd Qu.:  9394001   3rd Qu.:  9689807  
 Max.   :533892175   Max.   :554367818   Max.   :575050081  
     X2007               X2008               X2009          
 Min.   :     5155   Min.   :     5172   Min.   :     5189  
 1st Qu.:   645172   1st Qu.:   658017   1st Qu.:   671085  
 Median :  3432024   Median :  3589395   Median :  3652338  
 Mean   : 16797484   Mean   : 17164898   Mean   : 17533997  
 3rd Qu.:  9803381   3rd Qu.: 10210317   3rd Qu.: 10518289  
 Max.   :595731464   Max.   :616552722   Max.   :637533976  
     X2010               X2011          
 Min.   :     5206   Min.   :     5233  
 1st Qu.:   684302   1st Qu.:   698009  
 Median :  3676309   Median :  3664664  
 Mean   : 17904811   Mean   : 18276297  
 3rd Qu.: 10618596   3rd Qu.: 10731193  
 Max.   :658557734   Max.   :678796403  

XLConnect

When working with XLConnect, the first step will be to load a workbook in your R session with loadWorkbook(); this function will build a “bridge” between your Excel file and your R session.

library("XLConnect")
# Build connection to urbanpop.xlsx: my_book
my_book <- loadWorkbook("urbanpop.xlsx")

# Print out the class of my_book
class(my_book)
[1] "workbook"
attr(,"package")
[1] "XLConnect"

Just as readxl and gdata, you can use XLConnect to import data from Excel file into R.

To list the sheets in an Excel file, use getSheets(). To actually import data from a sheet, you can use readWorksheet(). Both functions require an XLConnect workbook object as the first argument.

# Build connection to urbanpop.xlsx
my_book <- loadWorkbook("urbanpop.xlsx")

# List the sheets in my_book
getSheets(my_book)
[1] "1960-1966" "1967-1974" "1975-2011"
# Import the second sheet in my_book
readWorksheet(my_book, 2)
# Build connection to urbanpop.xlsx
my_book <- loadWorkbook("urbanpop.xlsx")

# Import columns 3, 4, and 5 from second sheet in my_book: urbanpop_sel
urbanpop_sel <- readWorksheet(my_book, sheet = 2, startCol = 3, endCol = 5)

# Import first column from second sheet in my_book: countries
countries <- readWorksheet(my_book, sheet = 2, startCol = 1, endCol = 1)

# cbind() urbanpop_sel and countries together: selection
selection <- cbind(countries, urbanpop_sel)

Add worksheet

Where readxl and gdata were only able to import Excel data, XLConnect’s approach of providing an actual interface to an Excel file makes it able to edit your Excel files from inside R. In this exercise, you’ll create a new sheet. In the next exercise, you’ll populate the sheet with data, and save the results in a new Excel file.

# Build connection to urbanpop.xlsx
my_book <- loadWorkbook("urbanpop.xlsx")

# Add a worksheet to my_book, named "data_summary"
createSheet(my_book, name = "data_summary")

# Use getSheets() on my_book
getSheets(my_book)
[1] "1960-1966"    "1967-1974"    "1975-2011"    "data_summary"

The first step of creating a sheet is done; let’s populate it with some data now! summ, a data frame with some summary statistics on the two Excel sheets is already coded so you can take it from there.

# Build connection to urbanpop.xlsx
my_book <- loadWorkbook("urbanpop.xlsx")

# Add a worksheet to my_book, named "data_summary"
createSheet(my_book, "data_summary")

# Create data frame: summ
sheets <- getSheets(my_book)[1:3]
dims <- sapply(sheets, function(x) dim(readWorksheet(my_book, sheet = x)), USE.NAMES = FALSE)
summ <- data.frame(sheets = sheets,
                   nrows = dims[1, ],
                   ncols = dims[2, ])

# Add data in summ to "data_summary" sheet
writeWorksheet(my_book, summ, sheet = "data_summary")

# Save workbook as summary.xlsx
saveWorkbook(my_book, file = "summary.xlsx")
# Rename "data_summary" sheet to "summary"
renameSheet(my_book, "data_summary", "summary")

# Print out sheets of my_book
getSheets(my_book)
[1] "1960-1966" "1967-1974" "1975-2011" "summary"  
# Save workbook to "renamed.xlsx"
saveWorkbook(my_book, file = "renamed.xlsx")
# Build connection to renamed.xlsx: my_book
my_book <- loadWorkbook("renamed.xlsx")

# Remove the fourth sheet
removeSheet(my_book, sheet = "summary")

# Save workbook to "clean.xlsx"
saveWorkbook(my_book, file = "clean.xlsx")
LS0tDQp0aXRsZTogSW50cm9kdWN0aW9uIHRvIEltcG9ydGluZyBEYXRhIFIiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KIyMjIHJlYWQuY3N2DQpUaGUgdXRpbHMgcGFja2FnZSwgd2hpY2ggaXMgYXV0b21hdGljYWxseSBsb2FkZWQgaW4geW91ciBSIHNlc3Npb24gb24gc3RhcnR1cCwgY2FuIGltcG9ydCBDU1YgZmlsZXMgd2l0aCB0aGUgcmVhZC5jc3YoKSBmdW5jdGlvbi4NCmBgYHtyfQ0KIyBJbXBvcnQgdGVzdC5jc3YuY3N2OiBwb29scw0KcG9vbHMgPSByZWFkLmNzdigidGVzdC5jc3YiKQ0KDQojIFByaW50IHRoZSBzdHJ1Y3R1cmUgb2YgcG9vbHMNCnN0cihwb29scykNCmBgYA0KIyMjIHN0cmluZ3NBc0ZhY3RvcnMNCg0KV2l0aCBzdHJpbmdzQXNGYWN0b3JzLCB5b3UgY2FuIHRlbGwgUiB3aGV0aGVyIGl0IHNob3VsZCBjb252ZXJ0IHN0cmluZ3MgaW4gdGhlIGZsYXQgZmlsZSB0byBmYWN0b3JzLg0KDQpGb3IgYWxsIGltcG9ydGluZyBmdW5jdGlvbnMgaW4gdGhlIHV0aWxzIHBhY2thZ2UsIHRoaXMgYXJndW1lbnQgaXMgVFJVRSwgd2hpY2ggbWVhbnMgdGhhdCB5b3UgaW1wb3J0IHN0cmluZ3MgYXMgZmFjdG9ycy4gVGhpcyBvbmx5IG1ha2VzIHNlbnNlIGlmIHRoZSBzdHJpbmdzIHlvdSBpbXBvcnQgcmVwcmVzZW50IGNhdGVnb3JpY2FsIHZhcmlhYmxlcyBpbiBSLiBJZiB5b3Ugc2V0IHN0cmluZ3NBc0ZhY3RvcnMgdG8gRkFMU0UsIHRoZSBkYXRhIGZyYW1lIGNvbHVtbnMgY29ycmVzcG9uZGluZyB0byBzdHJpbmdzIGluIHlvdXIgdGV4dCBmaWxlIHdpbGwgYmUgY2hhcmFjdGVyLg0KDQpgYGB7cn0NCiMgSW1wb3J0IHRlc3QuY3N2LmNzdjogcG9vbHMNCnBvb2xzID0gcmVhZC5jc3YoInRlc3QuY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0KDQojIFByaW50IHRoZSBzdHJ1Y3R1cmUgb2YgcG9vbHMNCnN0cihwb29scykNCmBgYA0KIyMjIyB0YWIgZGVsaW1pdGVkDQoNCkFzaWRlIGZyb20gLmNzdiBmaWxlcywgdGhlcmUgYXJlIGFsc28gdGhlIC50eHQgZmlsZXMgd2hpY2ggYXJlIGJhc2ljYWxseSB0ZXh0IGZpbGVzLiBZb3UgY2FuIGltcG9ydCB0aGVzZSBmdW5jdGlvbnMgd2l0aCByZWFkLmRlbGltKCkuIEJ5IGRlZmF1bHQsIGl0IHNldHMgdGhlIHNlcCBhcmd1bWVudCB0byAiXHQiIChmaWVsZHMgaW4gYSByZWNvcmQgYXJlIGRlbGltaXRlZCBieSB0YWJzKSBhbmQgdGhlIGhlYWRlciBhcmd1bWVudCB0byBUUlVFICh0aGUgZmlyc3Qgcm93IGNvbnRhaW5zIHRoZSBmaWVsZCBuYW1lcykuDQpgYGB7cn0NCiMgSW1wb3J0IGhvdGRvZ3MudHh0OiBob3Rkb2dzDQpob3Rkb2dzID0gcmVhZC5kZWxpbSgiaG90ZG9ncy50eHQiLCBoZWFkZXIgPSBGQUxTRSkNCg0KIyBTdW1tYXJpemUgaG90ZG9ncw0Kc3VtbWFyeShob3Rkb2dzKQ0KYGBgDQoNCiMjIyMgcmVhZC50YWJsZQ0KDQpmIHlvdSdyZSBkZWFsaW5nIHdpdGggbW9yZSBleG90aWMgZmxhdCBmaWxlIGZvcm1hdHMsIHlvdSdsbCB3YW50IHRvIHVzZSByZWFkLnRhYmxlKCkuIEl0J3MgdGhlIG1vc3QgYmFzaWMgaW1wb3J0aW5nIGZ1bmN0aW9uOyB5b3UgY2FuIHNwZWNpZnkgdG9ucyBvZiBkaWZmZXJlbnQgYXJndW1lbnRzIGluIHRoaXMgZnVuY3Rpb24uIFVubGlrZSByZWFkLmNzdigpIGFuZCByZWFkLmRlbGltKCksIHRoZSBoZWFkZXIgYXJndW1lbnQgZGVmYXVsdHMgdG8gRkFMU0UgYW5kIHRoZSBzZXAgYXJndW1lbnQgaXMgIiIgYnkgZGVmYXVsdC4NCg0KYGBge3J9DQojIFBhdGggdG8gdGhlIGhvdGRvZ3MudHh0IGZpbGU6IHBhdGgNCnBhdGggPC0gZmlsZS5wYXRoKCJob3Rkb2dzLnR4dCIpDQoNCiMgSW1wb3J0IHRoZSBob3Rkb2dzLnR4dCBmaWxlOiBob3Rkb2dzDQpob3Rkb2dzIDwtIHJlYWQudGFibGUocGF0aCwgDQogICAgICAgICAgICAgICAgICAgICAgc2VwID0gIlx0IiwgDQogICAgICAgICAgICAgICAgICAgICAgY29sLm5hbWVzID0gYygidHlwZSIsICJjYWxvcmllcyIsICJzb2RpdW0iKSkNCg0KIyBDYWxsIGhlYWQoKSBvbiBob3Rkb2dzDQpoZWFkKGhvdGRvZ3MpDQpgYGANCiMjIyMgQXJndW1lbnRzDQpgYGB7cn0NCiMgRmluaXNoIHRoZSByZWFkLmRlbGltKCkgY2FsbA0KaG90ZG9ncyA8LSByZWFkLmRlbGltKCJob3Rkb2dzLnR4dCIsIGhlYWRlciA9IEZBTFNFLCBjb2wubmFtZXMgPSBjKCJ0eXBlIiwgImNhbG9yaWVzIiwgInNvZGl1bSIpKQ0KDQojIFNlbGVjdCB0aGUgaG90IGRvZyB3aXRoIHRoZSBsZWFzdCBjYWxvcmllczogbGlseQ0KbGlseSA8LSBob3Rkb2dzW3doaWNoLm1pbihob3Rkb2dzJGNhbG9yaWVzKSwgXQ0KDQojIFNlbGVjdCB0aGUgb2JzZXJ2YXRpb24gd2l0aCB0aGUgbW9zdCBzb2RpdW06IHRvbQ0KdG9tIDwtIGhvdGRvZ3Nbd2hpY2gubWF4KGhvdGRvZ3Mkc29kaXVtKSwgXQ0KDQojIFByaW50IGxpbHkgYW5kIHRvbQ0KbGlseQ0KdG9tDQpgYGANCiMjIyMgQ29sdW1uIGNsYXNzZXMNCg0KTmV4dCB0byBjb2x1bW4gbmFtZXMsIHlvdSBjYW4gYWxzbyBzcGVjaWZ5IHRoZSBjb2x1bW4gdHlwZXMgb3IgY29sdW1uIGNsYXNzZXMgb2YgdGhlIHJlc3VsdGluZyBkYXRhIGZyYW1lLiBZb3UgY2FuIGRvIHRoaXMgYnkgc2V0dGluZyB0aGUgY29sQ2xhc3NlcyBhcmd1bWVudCB0byBhIHZlY3RvciBvZiBzdHJpbmdzIHJlcHJlc2VudGluZyBjbGFzc2VzLg0KDQpUaGlzIGFwcHJvYWNoIGNhbiBiZSB1c2VmdWwgaWYgeW91IGhhdmUgc29tZSBjb2x1bW5zIHRoYXQgc2hvdWxkIGJlIGZhY3RvcnMgYW5kIG90aGVycyB0aGF0IHNob3VsZCBiZSBjaGFyYWN0ZXJzLiBZb3UgZG9uJ3QgaGF2ZSB0byBib3RoZXIgd2l0aCBzdHJpbmdzQXNGYWN0b3JzIGFueW1vcmU7IGp1c3Qgc3RhdGUgZm9yIGVhY2ggY29sdW1uIHdoYXQgdGhlIGNsYXNzIHNob3VsZCBiZS4NCg0KSWYgYSBjb2x1bW4gaXMgc2V0IHRvICJOVUxMIiBpbiB0aGUgY29sQ2xhc3NlcyB2ZWN0b3IsIHRoaXMgY29sdW1uIHdpbGwgYmUgc2tpcHBlZCBhbmQgd2lsbCBub3QgYmUgbG9hZGVkIGludG8gdGhlIGRhdGEgZnJhbWUuDQoNCmBgYHtyfQ0KIyBQcmV2aW91cyBjYWxsIHRvIGltcG9ydCBob3Rkb2dzLnR4dA0KaG90ZG9ncyA8LSByZWFkLmRlbGltKCJob3Rkb2dzLnR4dCIsIGhlYWRlciA9IEZBTFNFLCBjb2wubmFtZXMgPSBjKCJ0eXBlIiwgImNhbG9yaWVzIiwgInNvZGl1bSIpKQ0KDQojIERpc3BsYXkgc3RydWN0dXJlIG9mIGhvdGRvZ3MNCnN0cihob3Rkb2dzKQ0KDQojIEVkaXQgdGhlIGNvbENsYXNzZXMgYXJndW1lbnQgdG8gaW1wb3J0IHRoZSBkYXRhIGNvcnJlY3RseTogaG90ZG9nczINCmhvdGRvZ3MyIDwtIHJlYWQuZGVsaW0oImhvdGRvZ3MudHh0IiwgaGVhZGVyID0gRkFMU0UsIA0KICAgICAgICAgICAgICAgICAgICAgICBjb2wubmFtZXMgPSBjKCJ0eXBlIiwgImNhbG9yaWVzIiwgInNvZGl1bSIpLA0KICAgICAgICAgICAgICAgICAgICAgICBjb2xDbGFzc2VzID0gYygiZmFjdG9yIiwgIk5VTEwiLCAibnVtZXJpYyIpKQ0KDQoNCiMgRGlzcGxheSBzdHJ1Y3R1cmUgb2YgaG90ZG9nczINCnN0cihob3Rkb2dzMikNCmBgYA0KIyMjIHJlYWRyDQoNCiMjIyMgcmVhZF9jc3YNCkNTViBmaWxlcyBjYW4gYmUgaW1wb3J0ZWQgd2l0aCByZWFkX2NzdigpLiBJdCdzIGEgd3JhcHBlciBmdW5jdGlvbiBhcm91bmQgcmVhZF9kZWxpbSgpIHRoYXQgaGFuZGxlcyBhbGwgdGhlIGRldGFpbHMgZm9yIHlvdS4gRm9yIGV4YW1wbGUsIGl0IHdpbGwgYXNzdW1lIHRoYXQgdGhlIGZpcnN0IHJvdyBjb250YWlucyB0aGUgY29sdW1uIG5hbWVzLg0KDQpgYGB7cn0NCiMgTG9hZCB0aGUgcmVhZHIgcGFja2FnZQ0KbGlicmFyeShyZWFkcikNCg0KIyBJbXBvcnQgcG90YXRvZXMuY3N2IHdpdGggcmVhZF9jc3YoKTogcG90YXRvZXMNCnBvdGF0b2VzIDwtIHJlYWRfY3N2KCJwb3RhdG9lcy5jc3YiKQ0KYGBgDQojIyMjIHJlYWRfdHN2DQpXaGVyZSB5b3UgdXNlIHJlYWRfY3N2KCkgdG8gZWFzaWx5IHJlYWQgaW4gQ1NWIGZpbGVzLCB5b3UgdXNlIHJlYWRfdHN2KCkgdG8gZWFzaWx5IHJlYWQgaW4gVFNWIGZpbGVzLiBUU1YgaXMgc2hvcnQgZm9yIHRhYi1zZXBhcmF0ZWQgdmFsdWVzLg0KDQpgYGB7cn0NCiMgQ29sdW1uIG5hbWVzDQpwcm9wZXJ0aWVzIDwtIGMoImFyZWEiLCAidGVtcCIsICJzaXplIiwgInN0b3JhZ2UiLCAibWV0aG9kIiwNCiAgICAgICAgICAgICAgICAidGV4dHVyZSIsICJmbGF2b3IiLCAibW9pc3RuZXNzIikNCg0KIyBJbXBvcnQgcG90YXRvZXMudHh0OiBwb3RhdG9lcw0KcG90YXRvZXMgPC0gcmVhZF90c3YoInBvdGF0b2VzLnR4dCIsIGNvbF9uYW1lcyA9IHByb3BlcnRpZXMpDQoNCiMgQ2FsbCBoZWFkKCkgb24gcG90YXRvZXMNCmhlYWQocG90YXRvZXMpDQpgYGANCiMjIyByZWFkX2RlbGltDQoNCkp1c3QgYXMgcmVhZC50YWJsZSgpIHdhcyB0aGUgbWFpbiB1dGlscyBmdW5jdGlvbiwgcmVhZF9kZWxpbSgpIGlzIHRoZSBtYWluIHJlYWRyIGZ1bmN0aW9uLg0KDQpyZWFkX2RlbGltKCkgdGFrZXMgdHdvIG1hbmRhdG9yeSBhcmd1bWVudHM6DQoNCiAtIGZpbGU6IHRoZSBmaWxlIHRoYXQgY29udGFpbnMgdGhlIGRhdGENCiAtIGRlbGltOiB0aGUgY2hhcmFjdGVyIHRoYXQgc2VwYXJhdGVzIHRoZSB2YWx1ZXMgaW4gdGhlIGRhdGEgZmlsZQ0KDQpgYGB7cn0NCiMgQ29sdW1uIG5hbWVzDQpwcm9wZXJ0aWVzIDwtIGMoImFyZWEiLCAidGVtcCIsICJzaXplIiwgInN0b3JhZ2UiLCAibWV0aG9kIiwNCiAgICAgICAgICAgICAgICAidGV4dHVyZSIsICJmbGF2b3IiLCAibW9pc3RuZXNzIikNCg0KIyBJbXBvcnQgcG90YXRvZXMudHh0IHVzaW5nIHJlYWRfZGVsaW0oKTogcG90YXRvZXMNCnBvdGF0b2VzIDwtIHJlYWRfZGVsaW0oInBvdGF0b2VzLnR4dCIsIGRlbGltID0gIlx0IiwgY29sX25hbWVzID0gcHJvcGVydGllcykNCg0KIyBQcmludCBvdXQgcG90YXRvZXMNCnBvdGF0b2VzDQpgYGANCiMjIyBza2lwIGFuZCBuX21heA0KDQpUaHJvdWdoIHNraXAgYW5kIG5fbWF4IHlvdSBjYW4gY29udHJvbCB3aGljaCBwYXJ0IG9mIHlvdXIgZmxhdCBmaWxlIHlvdSdyZSBhY3R1YWxseSBpbXBvcnRpbmcgaW50byBSLg0KDQogLSBza2lwIHNwZWNpZmllcyB0aGUgbnVtYmVyIG9mIGxpbmVzIHlvdSdyZSBpZ25vcmluZyBpbiB0aGUgZmxhdCBmaWxlIGJlZm9yZSBhY3R1YWxseSBzdGFydGluZyB0byBpbXBvcnQgZGF0YS4NCiAtIG5fbWF4IHNwZWNpZmllcyB0aGUgbnVtYmVyIG9mIGxpbmVzIHlvdSdyZSBhY3R1YWxseSBpbXBvcnRpbmcuDQoNCk9uY2UgeW91IHNraXAgc29tZSBsaW5lcywgeW91IGFsc28gc2tpcCB0aGUgZmlyc3QgbGluZSB0aGF0IGNhbiBjb250YWluIGNvbHVtbiBuYW1lcyENCmBgYHtyfQ0KIyBDb2x1bW4gbmFtZXMNCnByb3BlcnRpZXMgPC0gYygiYXJlYSIsICJ0ZW1wIiwgInNpemUiLCAic3RvcmFnZSIsICJtZXRob2QiLA0KICAgICAgICAgICAgICAgICJ0ZXh0dXJlIiwgImZsYXZvciIsICJtb2lzdG5lc3MiKQ0KDQojIEltcG9ydCA1IG9ic2VydmF0aW9ucyBmcm9tIHBvdGF0b2VzLnR4dDogcG90YXRvZXNfZnJhZ21lbnQNCnBvdGF0b2VzX2ZyYWdtZW50IDwtIHJlYWRfdHN2KCJwb3RhdG9lcy50eHQiLCBza2lwID0gNiwgbl9tYXggPSA1LCBjb2xfbmFtZXMgPSBwcm9wZXJ0aWVzKQ0KYGBgDQojIyMgY29sX3R5cGVzDQoNCllvdSBjYW4gYWxzbyBzcGVjaWZ5IHdoaWNoIHR5cGVzIHRoZSBjb2x1bW5zIGluIHlvdXIgaW1wb3J0ZWQgZGF0YSBmcmFtZSBzaG91bGQgaGF2ZS4gWW91IGNhbiBkbyB0aGlzIHdpdGggY29sX3R5cGVzLiBJZiBzZXQgdG8gTlVMTCwgdGhlIGRlZmF1bHQsIGZ1bmN0aW9ucyBmcm9tIHRoZSByZWFkciBwYWNrYWdlIHdpbGwgdHJ5IHRvIGZpbmQgdGhlIGNvcnJlY3QgdHlwZXMgdGhlbXNlbHZlcy4gWW91IGNhbiBtYW51YWxseSBzZXQgdGhlIHR5cGVzIHdpdGggYSBzdHJpbmcsIHdoZXJlIGVhY2ggY2hhcmFjdGVyIGRlbm90ZXMgdGhlIGNsYXNzIG9mIHRoZSBjb2x1bW46IGNoYXJhY3RlciwgZG91YmxlLCBpbnRlZ2VyIGFuZCBsb2dpY2FsLiBfIHNraXBzIHRoZSBjb2x1bW4gYXMgYSB3aG9sZS4NCg0KYGBge3J9DQojIENvbHVtbiBuYW1lcw0KcHJvcGVydGllcyA8LSBjKCJhcmVhIiwgInRlbXAiLCAic2l6ZSIsICJzdG9yYWdlIiwgIm1ldGhvZCIsDQogICAgICAgICAgICAgICAgInRleHR1cmUiLCAiZmxhdm9yIiwgIm1vaXN0bmVzcyIpDQoNCiMgSW1wb3J0IGFsbCBkYXRhLCBidXQgZm9yY2UgYWxsIGNvbHVtbnMgdG8gYmUgY2hhcmFjdGVyOiBwb3RhdG9lc19jaGFyDQpwb3RhdG9lc19jaGFyIDwtIHJlYWRfdHN2KCJwb3RhdG9lcy50eHQiLCBjb2xfdHlwZXMgPSAiY2NjY2NjY2MiLCBjb2xfbmFtZXMgPSBwcm9wZXJ0aWVzKQ0KDQojIFByaW50IG91dCBzdHJ1Y3R1cmUgb2YgcG90YXRvZXNfY2hhcg0Kc3RyKHBvdGF0b2VzX2NoYXIpDQpgYGANCiMjIyBjb2xfdHlwZXMgd2l0aCBjb2xsZWN0b3JzDQoNCkFub3RoZXIgd2F5IG9mIHNldHRpbmcgdGhlIHR5cGVzIG9mIHRoZSBpbXBvcnRlZCBjb2x1bW5zIGlzIHVzaW5nIGNvbGxlY3RvcnMuIENvbGxlY3RvciBmdW5jdGlvbnMgY2FuIGJlIHBhc3NlZCBpbiBhIGxpc3QoKSB0byB0aGUgY29sX3R5cGVzIGFyZ3VtZW50IG9mIHJlYWRfIGZ1bmN0aW9ucyB0byB0ZWxsIHRoZW0gaG93IHRvIGludGVycHJldCB2YWx1ZXMgaW4gYSBjb2x1bW4uDQoNCkZvciBhIGNvbXBsZXRlIGxpc3Qgb2YgY29sbGVjdG9yIGZ1bmN0aW9ucywgeW91IGNhbiB0YWtlIGEgbG9vayBhdCB0aGUgW2NvbGxlY3Rvcl0oaHR0cHM6Ly93d3cucmRvY3VtZW50YXRpb24ub3JnL3BhY2thZ2VzL3JlYWRyL3ZlcnNpb25zLzAuMi4yL3RvcGljcy9jb2xsZWN0b3IpIGRvY3VtZW50YXRpb24uDQoNCkZvciBleGFtcGxlOg0KIC0gY29sX2ludGVnZXIoKTogdGhlIGNvbHVtbiBzaG91bGQgYmUgaW50ZXJwcmV0ZWQgYXMgYW4gaW50ZWdlci4NCiAtIGNvbF9mYWN0b3IobGV2ZWxzLCBvcmRlcmVkID0gRkFMU0UpOiB0aGUgY29sdW1uIHNob3VsZCBiZSBpbnRlcnByZXRlZCBhcyBhIGZhY3RvciB3aXRoIGxldmVscy4NCiANCmBgYHtyfQ0KIyBJbXBvcnQgd2l0aG91dCBjb2xfdHlwZXMNCmhvdGRvZ3MgPC0gcmVhZF90c3YoImhvdGRvZ3MudHh0IiwgY29sX25hbWVzID0gYygidHlwZSIsICJjYWxvcmllcyIsICJzb2RpdW0iKSkNCg0KIyBEaXNwbGF5IHRoZSBzdW1tYXJ5IG9mIGhvdGRvZ3MNCnN1bW1hcnkoaG90ZG9ncykNCg0KIyBUaGUgY29sbGVjdG9ycyB5b3Ugd2lsbCBuZWVkIHRvIGltcG9ydCB0aGUgZGF0YQ0KZmFjIDwtIGNvbF9mYWN0b3IobGV2ZWxzID0gYygiQmVlZiIsICJNZWF0IiwgIlBvdWx0cnkiKSkNCmludCA8LSBjb2xfaW50ZWdlcigpDQoNCiMgRWRpdCB0aGUgY29sX3R5cGVzIGFyZ3VtZW50IHRvIGltcG9ydCB0aGUgZGF0YSBjb3JyZWN0bHk6IGhvdGRvZ3NfZmFjdG9yDQpob3Rkb2dzX2ZhY3RvciA8LSByZWFkX3RzdigiaG90ZG9ncy50eHQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sX25hbWVzID0gYygidHlwZSIsICJjYWxvcmllcyIsICJzb2RpdW0iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbF90eXBlcyA9IGxpc3QoZmFjLCBpbnQsIGludCkpDQoNCiMgRGlzcGxheSB0aGUgc3VtbWFyeSBvZiBob3Rkb2dzX2ZhY3Rvcg0Kc3VtbWFyeShob3Rkb2dzX2ZhY3RvcikNCmBgYA0KIyMjIGRhdGEudGFibGUNCmBgYHtyfQ0KbGlicmFyeShkYXRhLnRhYmxlKQ0KYGBgDQojIyMgZnJlYWQNCg0KWW91IHN0aWxsIHJlbWVtYmVyIGhvdyB0byB1c2UgcmVhZC50YWJsZSgpLCByaWdodD8gV2VsbCwgZnJlYWQoKSBpcyBhIGZ1bmN0aW9uIHRoYXQgZG9lcyB0aGUgc2FtZSBqb2Igd2l0aCB2ZXJ5IHNpbWlsYXIgYXJndW1lbnRzLiBJdCBpcyBleHRyZW1lbHkgZWFzeSB0byB1c2UgYW5kIGJsYXppbmdseSBmYXN0ISBPZnRlbiwgc2ltcGx5IHNwZWNpZnlpbmcgdGhlIHBhdGggdG8gdGhlIGZpbGUgaXMgZW5vdWdoIHRvIHN1Y2Nlc3NmdWxseSBpbXBvcnQgeW91ciBkYXRhLg0KDQpgYGB7cn0NCiMgSW1wb3J0IHBvdGF0b2VzLmNzdiB3aXRoIGZyZWFkKCk6IHBvdGF0b2VzDQpwb3RhdG9lcyA8LSBmcmVhZCgicG90YXRvZXMuY3N2IikNCg0KIyBQcmludCBvdXQgcG90YXRvZXMNCnBvdGF0b2VzDQpgYGANCiMjIyMgZnJlYWQ6IGRyb3AgYW5kIHNlbGVjdA0KDQp0byBkcm9wIG9yIHNlbGVjdCB2YXJpYWJsZXMgb2YgaW50ZXJlc3QuDQoNCmBgYHtyfQ0KIyBJbXBvcnQgY29sdW1ucyA2IGFuZCA4IG9mIHBvdGF0b2VzLmNzdjogcG90YXRvZXMNCnBvdGF0b2VzID0gKGZyZWFkKCJwb3RhdG9lcy5jc3YiLCBzZWxlY3QgPSBjKDYsOCkpKQ0KDQojIFBsb3QgdGV4dHVyZSAoeCkgYW5kIG1vaXN0bmVzcyAoeSkgb2YgcG90YXRvZXMNCnBsb3QoeCA8LSBwb3RhdG9lcyR0ZXh0dXJlLCB5IDwtIHBvdGF0b2VzJG1vaXN0bmVzcywgbWFpbiA9ICJQb3RhdG9lcyIsIHhsYWIgPSAiVGV4dHVyZSIsIHlsYWIgPSAibW9pc3RuZXNzIikNCmBgYA0KWW91IG1pZ2h0IGhhdmUgbm90aWNlZCB0aGF0IHRoZSBmcmVhZCgpIGZ1bmN0aW9uIHByb2R1Y2VzIGRhdGEgZnJhbWVzIHRoYXQgbG9vayBzbGlnaHRseSBkaWZmZXJlbnQgd2hlbiB5b3UgcHJpbnQgdGhlbSBvdXQuIFRoYXQncyBiZWNhdXNlIGFub3RoZXIgY2xhc3MgbmFtZWQgZGF0YS50YWJsZSBpcyBhc3NpZ25lZCB0byB0aGUgcmVzdWx0aW5nIGRhdGEgZnJhbWVzLiBUaGUgcHJpbnRvdXQgb2Ygc3VjaCBkYXRhLnRhYmxlIG9iamVjdHMgaXMgZGlmZmVyZW50LiBEb2VzIHNvbWV0aGluZyBzaW1pbGFyIGhhcHBlbiB3aXRoIHRoZSBkYXRhIGZyYW1lcyBnZW5lcmF0ZWQgYnkgcmVhZHI/DQoNCiMjIyByZWFkeGwgKHRpZHl2ZXJzZSkNCg0KQmVmb3JlIHlvdSBjYW4gc3RhcnQgaW1wb3J0aW5nIGZyb20gRXhjZWwsIHlvdSBzaG91bGQgZmluZCBvdXQgd2hpY2ggc2hlZXRzIGFyZSBhdmFpbGFibGUgaW4gdGhlIHdvcmtib29rLiBZb3UgY2FuIHVzZSB0aGUgZXhjZWxfc2hlZXRzKCkgZnVuY3Rpb24gZm9yIHRoaXMuDQoNCmBgYHtyfQ0KIyBMb2FkIHRoZSByZWFkeGwgcGFja2FnZQ0KbGlicmFyeShyZWFkeGwpDQojIFByaW50IHRoZSBuYW1lcyBvZiBhbGwgd29ya3NoZWV0cw0KZXhjZWxfc2hlZXRzKCJ1cmJhbnBvcC54bHN4IikNCmBgYA0KTm93IHRoYXQgeW91IGtub3cgdGhlIG5hbWVzIG9mIHRoZSBzaGVldHMgaW4gdGhlIEV4Y2VsIGZpbGUgeW91IHdhbnQgdG8gaW1wb3J0LCBpdCBpcyB0aW1lIHRvIGltcG9ydCB0aG9zZSBzaGVldHMgaW50byBSLiBZb3UgY2FuIGRvIHRoaXMgd2l0aCB0aGUgcmVhZF9leGNlbCgpIGZ1bmN0aW9uLg0KDQpgYGB7cn0NCiMgUmVhZCB0aGUgc2hlZXRzLCBvbmUgYnkgb25lDQpwb3BfMSA8LSByZWFkX2V4Y2VsKCJ1cmJhbnBvcC54bHN4Iiwgc2hlZXQgPSAxKQ0KcG9wXzIgPC0gcmVhZF9leGNlbCgidXJiYW5wb3AueGxzeCIsIHNoZWV0ID0gMikNCnBvcF8zIDwtIHJlYWRfZXhjZWwoInVyYmFucG9wLnhsc3giLCBzaGVldCA9ICIxOTc1LTIwMTEiKQ0KDQojIFB1dCBwb3BfMSwgcG9wXzIgYW5kIHBvcF8zIGluIGEgbGlzdDogcG9wX2xpc3QNCnBvcF9saXN0IDwtIGxpc3QocG9wXzEsIHBvcF8yLCBwb3BfMykNCg0KIyBEaXNwbGF5IHRoZSBzdHJ1Y3R1cmUgb2YgcG9wX2xpc3QNCnN0cihwb3BfbGlzdCkNCmBgYA0KTG9hZGluZyBpbiBldmVyeSBzaGVldCBtYW51YWxseSBhbmQgdGhlbiBtZXJnaW5nIHRoZW0gaW4gYSBsaXN0IGNhbiBiZSBxdWl0ZSB0ZWRpb3VzLiBMdWNraWx5LCB5b3UgY2FuIGF1dG9tYXRlIHRoaXMgd2l0aCBsYXBwbHkoKS4NCg0KYGBge3J9DQojIFJlYWQgYWxsIEV4Y2VsIHNoZWV0cyB3aXRoIGxhcHBseSgpOiBwb3BfbGlzdA0KcG9wX2xpc3QgPC0gbGFwcGx5KGV4Y2VsX3NoZWV0cygidXJiYW5wb3AueGxzeCIpLA0KcmVhZF9leGNlbCwNCnBhdGggPSAidXJiYW5wb3AueGxzeCIpDQoNCiMgRGlzcGxheSB0aGUgc3RydWN0dXJlIG9mIHBvcF9saXN0DQpzdHIocG9wX2xpc3QpDQpgYGANCkFwYXJ0IGZyb20gcGF0aCBhbmQgc2hlZXQsIHRoZXJlIGFyZSBzZXZlcmFsIG90aGVyIGFyZ3VtZW50cyB5b3UgY2FuIHNwZWNpZnkgaW4gcmVhZF9leGNlbCgpLiBPbmUgb2YgdGhlc2UgYXJndW1lbnRzIGlzIGNhbGxlZCBjb2xfbmFtZXMuDQoNCkJ5IGRlZmF1bHQgaXQgaXMgVFJVRSwgZGVub3Rpbmcgd2hldGhlciB0aGUgZmlyc3Qgcm93IGluIHRoZSBFeGNlbCBzaGVldHMgY29udGFpbnMgdGhlIGNvbHVtbiBuYW1lcy4gSWYgdGhpcyBpcyBub3QgdGhlIGNhc2UsIHlvdSBjYW4gc2V0IGNvbF9uYW1lcyB0byBGQUxTRS4gSW4gdGhpcyBjYXNlLCBSIHdpbGwgY2hvb3NlIGNvbHVtbiBuYW1lcyBmb3IgeW91LiBZb3UgY2FuIGFsc28gY2hvb3NlIHRvIHNldCBjb2xfbmFtZXMgdG8gYSBjaGFyYWN0ZXIgdmVjdG9yIHdpdGggbmFtZXMgZm9yIGVhY2ggY29sdW1uLiBJdCB3b3JrcyBleGFjdGx5IHRoZSBzYW1lIGFzIGluIHRoZSByZWFkciBwYWNrYWdlLg0KYGBge3J9DQojIEltcG9ydCB0aGUgZmlyc3QgRXhjZWwgc2hlZXQgb2YgdXJiYW5wb3Bfbm9uYW1lcy54bHN4IChSIGdpdmVzIG5hbWVzKTogcG9wX2ENCnBvcF9hIDwtIHJlYWRfZXhjZWwoInVyYmFucG9wX25vbmFtZXMueGxzeCIsDQpjb2xfbmFtZXMgPSBGQUxTRSkNCg0KIyBJbXBvcnQgdGhlIGZpcnN0IEV4Y2VsIHNoZWV0IG9mIHVyYmFucG9wX25vbmFtZXMueGxzeCAoc3BlY2lmeSBjb2xfbmFtZXMpOiBwb3BfYg0KY29scyA8LSBjKCJjb3VudHJ5IiwgcGFzdGUwKCJ5ZWFyXyIsIDE5NjA6MTk2NikpDQpwb3BfYiA8LSByZWFkX2V4Y2VsKCJ1cmJhbnBvcF9ub25hbWVzLnhsc3giLA0KY29sX25hbWVzID0gY29scykNCg0KIyBQcmludCB0aGUgc3VtbWFyeSBvZiBwb3BfYQ0Kc3VtbWFyeShwb3BfYSkNCnN1bW1hcnkocG9wX2IpDQpgYGANCkFub3RoZXIgYXJndW1lbnQgdGhhdCBjYW4gYmUgdmVyeSB1c2VmdWwgd2hlbiByZWFkaW5nIGluIEV4Y2VsIGZpbGVzIHRoYXQgYXJlIGxlc3MgdGlkeSwgaXMgc2tpcC4gV2l0aCBza2lwLCB5b3UgY2FuIHRlbGwgUiB0byBpZ25vcmUgYSBzcGVjaWZpZWQgbnVtYmVyIG9mIHJvd3MgaW5zaWRlIHRoZSBFeGNlbCBzaGVldHMgeW91J3JlIHRyeWluZyB0byBwdWxsIGRhdGEgZnJvbS4NCmBgYHtyfQ0KIyBJbXBvcnQgdGhlIHNlY29uZCBzaGVldCBvZiB1cmJhbnBvcC54bHN4LCBza2lwcGluZyB0aGUgZmlyc3QgMjEgcm93czogdXJiYW5wb3Bfc2VsDQp1cmJhbnBvcF9zZWwgPC0gcmVhZF9leGNlbCgidXJiYW5wb3AueGxzeCIsIHNoZWV0ID0gMiwgc2tpcCA9IDIxLCBjb2xfbmFtZXMgPSBGQUxTRSkNCg0KIyBQcmludCBvdXQgdGhlIGZpcnN0IG9ic2VydmF0aW9uIGZyb20gdXJiYW5wb3Bfc2VsDQpoZWFkKHVyYmFucG9wX3NlbCwgbj0xKQ0KYGBgDQojIyMgZ2RhdGENCg0KSW4gdGhpcyBwYXJ0IG9mIHRoZSBjaGFwdGVyIHlvdSdsbCBsZWFybiBob3cgdG8gaW1wb3J0IC54bHMgZmlsZXMgdXNpbmcgdGhlIGdkYXRhIHBhY2thZ2UuIFNpbWlsYXIgdG8gdGhlIHJlYWR4bCBwYWNrYWdlLCB5b3UgY2FuIGltcG9ydCBzaW5nbGUgRXhjZWwgc2hlZXRzIGZyb20gRXhjZWwgc2hlZXRzIHRvIHN0YXJ0IHlvdXIgYW5hbHlzaXMgaW4gUi4NCmBgYHtyfQ0KbGlicmFyeSgiZ2RhdGEiKQ0KYGBgDQoNCmBgYHtyfQ0KIyBJbXBvcnQgdGhlIHNlY29uZCBzaGVldCBvZiB1cmJhbnBvcC54bHM6IHVyYmFuX3BvcA0KdXJiYW5fcG9wIDwtIHJlYWQueGxzKCJ1cmJhbnBvcC54bHMiLCBzaGVldCA9IDIsIHBlcmw9ImM6L1Byb2dyYW0gRmlsZXMvR2l0L3Vzci9iaW4vcGVybC5leGUiKQ0KDQojIFByaW50IHRoZSBmaXJzdCAxMSBvYnNlcnZhdGlvbnMgdXNpbmcgaGVhZCgpDQpoZWFkKHVyYmFuX3BvcCwgMTEpDQpgYGANCiMjIyMgcmVhZC54bHMoKSB3cmFwcyBhcm91bmQgcmVhZC50YWJsZSgpDQoNClJlbWVtYmVyIGhvdyByZWFkLnhscygpIGFjdHVhbGx5IHdvcmtzPyBJdCBiYXNpY2FsbHkgY29tZXMgZG93biB0byB0d28gc3RlcHM6IGNvbnZlcnRpbmcgdGhlIEV4Y2VsIGZpbGUgdG8gYSAuY3N2IGZpbGUgdXNpbmcgYSBQZXJsIHNjcmlwdCwgYW5kIHRoZW4gcmVhZGluZyB0aGF0IC5jc3YgZmlsZSB3aXRoIHRoZSByZWFkLmNzdigpIGZ1bmN0aW9uIHRoYXQgaXMgbG9hZGVkIGJ5IGRlZmF1bHQgaW4gUiwgdGhyb3VnaCB0aGUgdXRpbHMgcGFja2FnZS4NCg0KVGhpcyBtZWFucyB0aGF0IGFsbCB0aGUgb3B0aW9ucyB0aGF0IHlvdSBjYW4gc3BlY2lmeSBpbiByZWFkLmNzdigpLCBjYW4gYWxzbyBiZSBzcGVjaWZpZWQgaW4gcmVhZC54bHMoKS4NCg0KYGBge3J9DQojIENvbHVtbiBuYW1lcyBmb3IgdXJiYW5fcG9wDQpjb2x1bW5zIDwtIGMoImNvdW50cnkiLCBwYXN0ZTAoInllYXJfIiwgMTk2NzoxOTc0KSkNCg0KIyBGaW5pc2ggdGhlIHJlYWQueGxzIGNhbGwNCnVyYmFuX3BvcCA8LSByZWFkLnhscygidXJiYW5wb3AueGxzIiwgc2hlZXQgPSAyLA0KICAgICAgICAgICAgICAgICAgICAgIHNraXAgPSA1MCwgaGVhZGVyID0gRkFMU0UsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBjb2wubmFtZXMgPSBjb2x1bW5zLCBwZXJsPSJjOi9Qcm9ncmFtIEZpbGVzL0dpdC91c3IvYmluL3BlcmwuZXhlIikNCg0KIyBQcmludCBmaXJzdCAxMCBvYnNlcnZhdGlvbiBvZiB1cmJhbl9wb3ANCmhlYWQodXJiYW5fcG9wLCAxMCkNCmBgYA0KTm93IHRoYXQgeW91IGNhbiByZWFkIGluIEV4Y2VsIGRhdGEsIGxldCdzIHRyeSB0byBjbGVhbiBhbmQgbWVyZ2UgaXQuIFlvdSBhbHJlYWR5IHVzZWQgdGhlIGNiaW5kKCkgZnVuY3Rpb24gc29tZSBleGVyY2lzZXMgYWdvLg0KYGBge3J9DQojIEFkZCBjb2RlIHRvIGltcG9ydCBkYXRhIGZyb20gYWxsIHRocmVlIHNoZWV0cyBpbiB1cmJhbnBvcC54bHMNCnBhdGggPC0gInVyYmFucG9wLnhscyINCnAgPC0gImM6L1Byb2dyYW0gRmlsZXMvR2l0L3Vzci9iaW4vcGVybC5leGUiDQp1cmJhbl9zaGVldDEgPC0gcmVhZC54bHMocGF0aCwgc2hlZXQgPSAxLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UsIHBlcmw9cCkNCnVyYmFuX3NoZWV0MiA8LSByZWFkLnhscyhwYXRoLCBzaGVldCA9IDIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSwgcGVybD1wKQ0KdXJiYW5fc2hlZXQzIDwtIHJlYWQueGxzKHBhdGgsIHNoZWV0ID0gMywgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFLCBwZXJsPXApDQoNCiMgRXh0ZW5kIHRoZSBjYmluZCgpIGNhbGwgdG8gaW5jbHVkZSB1cmJhbl9zaGVldDM6IHVyYmFuDQp1cmJhbiA8LSBjYmluZCh1cmJhbl9zaGVldDEsIHVyYmFuX3NoZWV0MlstMV0sIHVyYmFuX3NoZWV0M1stMV0pDQoNCiMgUmVtb3ZlIGFsbCByb3dzIHdpdGggTkFzIGZyb20gdXJiYW46IHVyYmFuX2NsZWFuDQp1cmJhbl9jbGVhbiA8LSBuYS5vbWl0KHVyYmFuKQ0KDQojIFByaW50IG91dCBhIHN1bW1hcnkgb2YgdXJiYW5fY2xlYW4NCnN1bW1hcnkodXJiYW5fY2xlYW4pDQpgYGANCiMjIyBYTENvbm5lY3QNCldoZW4gd29ya2luZyB3aXRoIFhMQ29ubmVjdCwgdGhlIGZpcnN0IHN0ZXAgd2lsbCBiZSB0byBsb2FkIGEgd29ya2Jvb2sgaW4geW91ciBSIHNlc3Npb24gd2l0aCBsb2FkV29ya2Jvb2soKTsgdGhpcyBmdW5jdGlvbiB3aWxsIGJ1aWxkIGEgImJyaWRnZSIgYmV0d2VlbiB5b3VyIEV4Y2VsIGZpbGUgYW5kIHlvdXIgUiBzZXNzaW9uLg0KYGBge3J9DQpsaWJyYXJ5KCJYTENvbm5lY3QiKQ0KYGBgDQpgYGB7cn0NCiMgQnVpbGQgY29ubmVjdGlvbiB0byB1cmJhbnBvcC54bHN4OiBteV9ib29rDQpteV9ib29rIDwtIGxvYWRXb3JrYm9vaygidXJiYW5wb3AueGxzeCIpDQoNCiMgUHJpbnQgb3V0IHRoZSBjbGFzcyBvZiBteV9ib29rDQpjbGFzcyhteV9ib29rKQ0KYGBgDQpKdXN0IGFzIHJlYWR4bCBhbmQgZ2RhdGEsIHlvdSBjYW4gdXNlIFhMQ29ubmVjdCB0byBpbXBvcnQgZGF0YSBmcm9tIEV4Y2VsIGZpbGUgaW50byBSLg0KDQpUbyBsaXN0IHRoZSBzaGVldHMgaW4gYW4gRXhjZWwgZmlsZSwgdXNlIGdldFNoZWV0cygpLiBUbyBhY3R1YWxseSBpbXBvcnQgZGF0YSBmcm9tIGEgc2hlZXQsIHlvdSBjYW4gdXNlIHJlYWRXb3Jrc2hlZXQoKS4gQm90aCBmdW5jdGlvbnMgcmVxdWlyZSBhbiBYTENvbm5lY3Qgd29ya2Jvb2sgb2JqZWN0IGFzIHRoZSBmaXJzdCBhcmd1bWVudC4NCg0KYGBge3J9DQojIEJ1aWxkIGNvbm5lY3Rpb24gdG8gdXJiYW5wb3AueGxzeA0KbXlfYm9vayA8LSBsb2FkV29ya2Jvb2soInVyYmFucG9wLnhsc3giKQ0KDQojIExpc3QgdGhlIHNoZWV0cyBpbiBteV9ib29rDQpnZXRTaGVldHMobXlfYm9vaykNCg0KIyBJbXBvcnQgdGhlIHNlY29uZCBzaGVldCBpbiBteV9ib29rDQpyZWFkV29ya3NoZWV0KG15X2Jvb2ssIDIpDQpgYGANCg0KYGBge3J9DQojIEJ1aWxkIGNvbm5lY3Rpb24gdG8gdXJiYW5wb3AueGxzeA0KbXlfYm9vayA8LSBsb2FkV29ya2Jvb2soInVyYmFucG9wLnhsc3giKQ0KDQojIEltcG9ydCBjb2x1bW5zIDMsIDQsIGFuZCA1IGZyb20gc2Vjb25kIHNoZWV0IGluIG15X2Jvb2s6IHVyYmFucG9wX3NlbA0KdXJiYW5wb3Bfc2VsIDwtIHJlYWRXb3Jrc2hlZXQobXlfYm9vaywgc2hlZXQgPSAyLCBzdGFydENvbCA9IDMsIGVuZENvbCA9IDUpDQoNCiMgSW1wb3J0IGZpcnN0IGNvbHVtbiBmcm9tIHNlY29uZCBzaGVldCBpbiBteV9ib29rOiBjb3VudHJpZXMNCmNvdW50cmllcyA8LSByZWFkV29ya3NoZWV0KG15X2Jvb2ssIHNoZWV0ID0gMiwgc3RhcnRDb2wgPSAxLCBlbmRDb2wgPSAxKQ0KDQojIGNiaW5kKCkgdXJiYW5wb3Bfc2VsIGFuZCBjb3VudHJpZXMgdG9nZXRoZXI6IHNlbGVjdGlvbg0Kc2VsZWN0aW9uIDwtIGNiaW5kKGNvdW50cmllcywgdXJiYW5wb3Bfc2VsKQ0KYGBgDQojIyMgQWRkIHdvcmtzaGVldA0KV2hlcmUgcmVhZHhsIGFuZCBnZGF0YSB3ZXJlIG9ubHkgYWJsZSB0byBpbXBvcnQgRXhjZWwgZGF0YSwgWExDb25uZWN0J3MgYXBwcm9hY2ggb2YgcHJvdmlkaW5nIGFuIGFjdHVhbCBpbnRlcmZhY2UgdG8gYW4gRXhjZWwgZmlsZSBtYWtlcyBpdCBhYmxlIHRvIGVkaXQgeW91ciBFeGNlbCBmaWxlcyBmcm9tIGluc2lkZSBSLiBJbiB0aGlzIGV4ZXJjaXNlLCB5b3UnbGwgY3JlYXRlIGEgbmV3IHNoZWV0LiBJbiB0aGUgbmV4dCBleGVyY2lzZSwgeW91J2xsIHBvcHVsYXRlIHRoZSBzaGVldCB3aXRoIGRhdGEsIGFuZCBzYXZlIHRoZSByZXN1bHRzIGluIGEgbmV3IEV4Y2VsIGZpbGUuDQoNCmBgYHtyfQ0KIyBCdWlsZCBjb25uZWN0aW9uIHRvIHVyYmFucG9wLnhsc3gNCm15X2Jvb2sgPC0gbG9hZFdvcmtib29rKCJ1cmJhbnBvcC54bHN4IikNCg0KIyBBZGQgYSB3b3Jrc2hlZXQgdG8gbXlfYm9vaywgbmFtZWQgImRhdGFfc3VtbWFyeSINCmNyZWF0ZVNoZWV0KG15X2Jvb2ssIG5hbWUgPSAiZGF0YV9zdW1tYXJ5IikNCg0KIyBVc2UgZ2V0U2hlZXRzKCkgb24gbXlfYm9vaw0KZ2V0U2hlZXRzKG15X2Jvb2spDQpgYGANClRoZSBmaXJzdCBzdGVwIG9mIGNyZWF0aW5nIGEgc2hlZXQgaXMgZG9uZTsgbGV0J3MgcG9wdWxhdGUgaXQgd2l0aCBzb21lIGRhdGEgbm93ISBzdW1tLCBhIGRhdGEgZnJhbWUgd2l0aCBzb21lIHN1bW1hcnkgc3RhdGlzdGljcyBvbiB0aGUgdHdvIEV4Y2VsIHNoZWV0cyBpcyBhbHJlYWR5IGNvZGVkIHNvIHlvdSBjYW4gdGFrZSBpdCBmcm9tIHRoZXJlLg0KDQpgYGB7cn0NCiMgQnVpbGQgY29ubmVjdGlvbiB0byB1cmJhbnBvcC54bHN4DQpteV9ib29rIDwtIGxvYWRXb3JrYm9vaygidXJiYW5wb3AueGxzeCIpDQoNCiMgQWRkIGEgd29ya3NoZWV0IHRvIG15X2Jvb2ssIG5hbWVkICJkYXRhX3N1bW1hcnkiDQpjcmVhdGVTaGVldChteV9ib29rLCAiZGF0YV9zdW1tYXJ5IikNCg0KIyBDcmVhdGUgZGF0YSBmcmFtZTogc3VtbQ0Kc2hlZXRzIDwtIGdldFNoZWV0cyhteV9ib29rKVsxOjNdDQpkaW1zIDwtIHNhcHBseShzaGVldHMsIGZ1bmN0aW9uKHgpIGRpbShyZWFkV29ya3NoZWV0KG15X2Jvb2ssIHNoZWV0ID0geCkpLCBVU0UuTkFNRVMgPSBGQUxTRSkNCnN1bW0gPC0gZGF0YS5mcmFtZShzaGVldHMgPSBzaGVldHMsDQogICAgICAgICAgICAgICAgICAgbnJvd3MgPSBkaW1zWzEsIF0sDQogICAgICAgICAgICAgICAgICAgbmNvbHMgPSBkaW1zWzIsIF0pDQoNCiMgQWRkIGRhdGEgaW4gc3VtbSB0byAiZGF0YV9zdW1tYXJ5IiBzaGVldA0Kd3JpdGVXb3Jrc2hlZXQobXlfYm9vaywgc3VtbSwgc2hlZXQgPSAiZGF0YV9zdW1tYXJ5IikNCg0KIyBTYXZlIHdvcmtib29rIGFzIHN1bW1hcnkueGxzeA0Kc2F2ZVdvcmtib29rKG15X2Jvb2ssIGZpbGUgPSAic3VtbWFyeS54bHN4IikNCmBgYA0KYGBge3J9DQojIFJlbmFtZSAiZGF0YV9zdW1tYXJ5IiBzaGVldCB0byAic3VtbWFyeSINCnJlbmFtZVNoZWV0KG15X2Jvb2ssICJkYXRhX3N1bW1hcnkiLCAic3VtbWFyeSIpDQoNCiMgUHJpbnQgb3V0IHNoZWV0cyBvZiBteV9ib29rDQpnZXRTaGVldHMobXlfYm9vaykNCg0KIyBTYXZlIHdvcmtib29rIHRvICJyZW5hbWVkLnhsc3giDQpzYXZlV29ya2Jvb2sobXlfYm9vaywgZmlsZSA9ICJyZW5hbWVkLnhsc3giKQ0KYGBgDQpgYGB7cn0NCiMgQnVpbGQgY29ubmVjdGlvbiB0byByZW5hbWVkLnhsc3g6IG15X2Jvb2sNCm15X2Jvb2sgPC0gbG9hZFdvcmtib29rKCJyZW5hbWVkLnhsc3giKQ0KDQojIFJlbW92ZSB0aGUgZm91cnRoIHNoZWV0DQpyZW1vdmVTaGVldChteV9ib29rLCBzaGVldCA9ICJzdW1tYXJ5IikNCg0KIyBTYXZlIHdvcmtib29rIHRvICJjbGVhbi54bHN4Ig0Kc2F2ZVdvcmtib29rKG15X2Jvb2ssIGZpbGUgPSAiY2xlYW4ueGxzeCIpDQpgYGANCg0K