Objectives

This notebook will demonstrate how to:

  • Navigate the RStudio environment
  • Use R for simple calculations, both mathematical and logical
  • Define and use variables in base R
  • Understand and apply base R functions
  • Understand, define, and use R data types, including vector manipulation and indexing
  • Understand the anatomy of a data frame

What is R?

R is a statistical computing language that is open source, meaning the underlying code for the language is freely available to anyone. You do not need a special license or set of permissions to use and develop code in R.

R itself is an interpreted computer language and comes with functionality that comes bundled with the language itself, known as “base R”. But there is also rich additional functionality provided by external packages, or libraries of code that assist in accomplishing certain tasks and can be freely downloaded and loaded for use.

In the next notebook and subsequent modules, we will be using a suite of packages collectively known as The Tidyverse. The tidyverse is geared towards intuitive data science applications that follow a shared data philosophy. But there are still many core features of base R which are important to be aware of, and we will be using concepts from both base R and the tidyverse in our analyses, as well as task specific packages for analyses such as gene expression.

What is RStudio?

RStudio is a graphical environment (“integrated development environment” or IDE) for writing and developing R code. RStudio is NOT a separate programming language - it is an interface we use to facilitate R programming. In other words, you can program in R without RStudio, but you can’t use the RStudio environment without R.

For more information about RStudio than you ever wanted to know, see this RStudio IDE Cheatsheet (pdf).

The RStudio Environment

The RStudio environment has four main panes, each of which may have a number of tabs that display different information or functionality. (their specific location can be changed under Tools -> Global Options -> Pane Layout). RStudio Appearance

  1. The Editor pane is where you can write R scripts and other documents. Each tab here is its own document. This is your text editor, which will allow you to save your R code for future use. Note that change code here will not run automatically until you run it.

  2. The Console pane is where you can interactively run R code.

  • There is also a Terminal tab here which can be used for running programs outside R on your computer
  1. The Environment pane primarily displays the variables, sometimes known as objects that are defined during a given R session, and what data or values they might hold.

  2. The final pane, Files, Plots, Help, …, has several pretty important tabs:

    • The Files tab shows the structure and contents of files and folders (also known as directories) on your computer.
    • The Plots tab will reveal plots when you make them
    • The Packages tab shows which installed packages have been loaded into your R session
    • The Help tab will show the help page when you look up a function
    • The Viewer tab will reveal compiled R Markdown documents

Basic Calculations

Mathematical operators

The most basic use of R is as a regular calculator:

Operation Symbol
Add +
Subtract -
Multiply *
Divide /
Exponentiate ^ or **

For example, we can do some simple multiplication like this. When you execute code within the notebook, the results appear beneath the code. Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Cmd+Shift+Enter on a Mac, or Ctrl+Shift+Enter on a PC.

5 * 6
[1] 30

Use the console to calculate other expressions. Standard order of operations applies (mostly), and you can use parentheses () as you might expect (but not brackets [] or braces{}, which have special meanings). Note however, that you must always specify multiplication with *; implicit multiplication such as 10(3 + 4) or 10x will not work and will generate an error, or worse.

10 * (3 + 4)^2
[1] 490

Defining and using variables

To define a variable, we use the assignment operator which looks like an arrow: <-, for example x <- 7 takes the value on the right-hand side of the operator and assigns it to the variable name on the left-hand side.

# Define a variable x to equal 7, and print out the value of x
x <- 7

# We can have R repeat back to us what `x` is by just using `x`
x
[1] 7

Some features of variables, considering the example x <- 7: Every variable has a name, a value, and a type. This variable’s name is x, its value is 7, and its type is numeric (7 is a number!). Re-defining a variable will overwrite the value.

x <- 5.5

x
[1] 5.5

We can modify an existing variable by reassigning it to its same name. Here we’ll add 2 to x and reassign the result back to x.

x <- x + 2

x
[1] 7.5

Variable naming note:

As best you can, it is a good idea to make your variable names informative (e.g. x doesn’t mean anything, but sandwich_price is meaningful… if we’re talking about the cost of sandwiches, that is..).

Comments

Arguably the most important aspect of your coding is comments: Small pieces of explanatory text you leave in your code to explain what the code is doing and/or leave notes to yourself or others. Comments are invaluable for communicating your code to others, but they are most important for Future You. Future You comes into existence about one second after you write code, and has no idea what on earth Past You was thinking.

Comments in R code are indicated with pound signs (aka hashtags, octothorps). R will ignore any text in a line after the pound sign, so you can put whatever text you like there.

22/7 # not quite pi
[1] 3.142857
# If we need a better approximation of pi, we can use Euler's formula
# This uses atan(), which calculates arctangent.
20 * atan(1/7) + 8 * atan(3/79) 
[1] 3.141593

Help out Future You by adding lots of comments! Future You next week thinks Today You is an idiot, and the only way you can convince Future You that Today You is reasonably competent is by adding comments in your code explaining why Today You is actually not so bad.

Functions

We can use pre-built computation methods called “functions” for other operations. Functions have the following format, where the argument is the information we are providing to the function for it to run. An example of this was the atan() function used above.

function_name(argument)

To learn about functions, we’ll examine one called log() first.

To know what a function does and how to use it, use the question mark which will reveal documentation in the help pane: ?log rhelp

The documentation tells us that log() is derived from {base}, meaning it is a function that is part of base R. It provides a brief description of what the function does and shows several examples of to how use it.

In particular, the documentation tells us about what argument(s) to provide:

  • The first required argument is the value we’d like to take the log of, by default its natural log
  • The second optional argument can specify a different base rather than the default e.

Functions also return values for us to use. In the case of log(), the returned value is the log’d value the function computed.

log(73)
[1] 4.290459

Here we can specify an argument of base to calculate log base 3.

log(81, base = 3)
[1] 4

If we don’t specify the argument names, it assumes they are in the order that log defines them. See ?log to see more about its arguments.

log(8, 2)
[1] 3

We can switch the order if we specify the argument names.

log(base = 10, x = 4342)
[1] 3.63769

We can also provide variables as arguments in the same way as the raw values.

meaning <- 42
log(meaning)
[1] 3.73767

Working with variables

Variable Types

Variable types in R can sometimes be coerced (converted) from one type to another.

# Define a variable with a number
x <- 15

The function class() will tell us the variable’s type.

class(x)
[1] "numeric"
numeric

Let’s coerce it to a character.

x <- as.character(x)
class(x)
[1] "character"
character

See it now has quotes around it? It’s now a character and will behave as such.

x
[1] "15"
15

Use this chunk to try to perform calculations with x, now that it is a character, what happens?

# Try to perform calculations on `x`

But we can’t coerce everything:

# Let's create a character variable
x <- "look at my character variable"

Let’s try making this a numeric variable:

x <- as.numeric(x)
Warning: NAs introduced by coercion

Print out x.

x
[1] NA

R is telling us it doesn’t know how to convert this to a numeric variable, so it has returned NA instead.

For reference, here’s a summary of some of the most important variable types.

Variable Type Definition Examples Coercion
numeric Any number value 5
7.5
-1
as.numeric()
integer Any whole number value (no decimals) 5
-100
as.integer()
character Any collection of characters defined within quotation marks. Also known as a “string”. "a" (a single letter)
"stringofletters" (a whole bunch of characters put together as one)
"string of letters and spaces"
"5"
'single quotes are also good'
as.character()
logical A value of TRUE, FALSE, or NA TRUE
FALSE
NA (not defined)
as.logical()
factor A special type of variable that denotes specific categories of a categorical variable (stay tuned..) as.factor()

Vectors

You will have noticed that all your computations tend to pop up with a [1] preceding them in R’s output. This is because, in fact, all (ok mostly all) variables are by default vectors, and our answers are the first (in these cases only) value in the vector. As vectors get longer, new index indicators will appear at the start of new lines.

# This is actually an vector that has one item in it.
x <- 7
# The length() functions tells us how long an vector is:
length(x)
[1] 1

We can define vectors with the function c(), which stands for “combine”. This function takes a comma-separated set of values to place in the vector, and returns the vector itself:

my_numeric_vector <- c(1, 1, 2, 3, 5, 8, 13, 21)
my_numeric_vector
[1]  1  1  2  3  5  8 13 21

We can build on vectors in place by redefining them:

# add the next two Fibonacci numbers to the series.
my_numeric_vector <- c(my_numeric_vector, 34, 55)
my_numeric_vector
 [1]  1  1  2  3  5  8 13 21 34 55

We can pull out specific items from an vector using a process called indexing, which uses brackets [] to specify the position of an item.

# Grab the fourth value from my_numeric_vector
# This gives us an vector of length 1 
my_numeric_vector[4]
[1] 3

Colons are also a nice way to quickly make ordered numeric vectors Use a colon to specify an inclusive range of indices This will return an vector with 2, 3, 4, and 5.

my_numeric_vector[2:5]
[1] 1 2 3 5

One major benefit of vectors is the concept of vectorization, where R by default performs operations on the entire vector at once. For example, we can get the log of all numbers 1-20 with a single, simple call, and more!

values_1_to_20 <- 1:20
# calculate the log of values_1_to_20
log(values_1_to_20)
 [1] 0.0000000 0.6931472 1.0986123 1.3862944 1.6094379 1.7917595 1.9459101
 [8] 2.0794415 2.1972246 2.3025851 2.3978953 2.4849066 2.5649494 2.6390573
[15] 2.7080502 2.7725887 2.8332133 2.8903718 2.9444390 2.9957323

Finally, we can apply logical expressions to vectors, just as we can do for single values. The output here is a logical vector telling us whether each value in example_vector is TRUE or FALSE

# Which values are <= 3?
values_1_to_20 <= 3
 [1]  TRUE  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[13] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE

There are several key functions which can be used on vectors containing numeric values, some of which are below.

  • mean(): The average value in the vector
  • min(): The minimum value in the vector
  • max(): The maximum value in the vector
  • sum(): The sum of all values in the vector

We can try out these functions on the vector values_1_to_20 we’ve created.

mean(values_1_to_20)
[1] 10.5
# Try out some of the other functions we've listed above 

A note on variable naming

We have learned functions such as c, length, sum, and etc. Imagine defining a variable called c: This will work, but it will lead to a lot of unintended bugs, so it’s best to avoid this.

The %in% logical operator

%in% is useful for determining whether a given item(s) are in an vector.

# is `7` in our vector? 
7 %in% values_1_to_20
[1] TRUE
# is `50` in our vector? 
50 %in% values_1_to_20
[1] FALSE

We can test a vector of values being within another vector of values.

question_values <- c(1:3, 7, 50)
# Are these values in our vector?
question_values %in% values_1_to_20
[1]  TRUE  TRUE  TRUE  TRUE FALSE

Data frames

Data frames are one of the most useful tools for data analysis in R. They are tables which consist of rows and columns, much like a spreadsheet. Each column is a variable which behaves as a vector, and each row is an observation. We will begin our exploration with dataset of measurements from three penguin species measured, which we can find in the palmerpenguins package. We’ll talk more about packages soon! To use this dataset, we will load it from the palmerpenguins package using a :: (more on this later) and assign it to a variable named penguins in our current environment.

penguins <- palmerpenguins::penguins

drawings of penguin species Artwork by @allison_horst

Exploring data frames

The first step to using any data is to look at it!!! RStudio contains a special function View() which allows you to literally view a variable. You can also click on the object in the environment pane to see its overall properties, or click the table icon on the object’s row to automatically view the variable.

Some useful functions for exploring our data frame include:

  • head() to see the first 6 rows of a data frame. Additional arguments supplied can change the number of rows.
  • tail() to see the last 6 rows of a data frame. Additional arguments supplied can change the number of rows.
  • names() to see the column names of the data frame.
  • nrow() to see how many rows are in the data frame
  • ncol() to see how many columns are in the data frame.

We can additionally explore overall properties of the data frame with two different functions: summary() and str().

This provides summary statistics for each column:

summary(penguins)
      species          island    bill_length_mm  bill_depth_mm  
 Adelie   :152   Biscoe   :168   Min.   :32.10   Min.   :13.10  
 Chinstrap: 68   Dream    :124   1st Qu.:39.23   1st Qu.:15.60  
 Gentoo   :124   Torgersen: 52   Median :44.45   Median :17.30  
                                 Mean   :43.92   Mean   :17.15  
                                 3rd Qu.:48.50   3rd Qu.:18.70  
                                 Max.   :59.60   Max.   :21.50  
                                 NA's   :2       NA's   :2      
 flipper_length_mm  body_mass_g       sex           year     
 Min.   :172.0     Min.   :2700   female:165   Min.   :2007  
 1st Qu.:190.0     1st Qu.:3550   male  :168   1st Qu.:2007  
 Median :197.0     Median :4050   NA's  : 11   Median :2008  
 Mean   :200.9     Mean   :4202                Mean   :2008  
 3rd Qu.:213.0     3rd Qu.:4750                3rd Qu.:2009  
 Max.   :231.0     Max.   :6300                Max.   :2009  
 NA's   :2         NA's   :2                                 

This provides a short view of the structure and contents of the data frame.

str(penguins)
tibble [344 × 8] (S3: tbl_df/tbl/data.frame)
 $ species          : Factor w/ 3 levels "Adelie","Chinstrap",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ island           : Factor w/ 3 levels "Biscoe","Dream",..: 3 3 3 3 3 3 3 3 3 3 ...
 $ bill_length_mm   : num [1:344] 39.1 39.5 40.3 NA 36.7 39.3 38.9 39.2 34.1 42 ...
 $ bill_depth_mm    : num [1:344] 18.7 17.4 18 NA 19.3 20.6 17.8 19.6 18.1 20.2 ...
 $ flipper_length_mm: int [1:344] 181 186 195 NA 193 190 181 195 193 190 ...
 $ body_mass_g      : int [1:344] 3750 3800 3250 NA 3450 3650 3625 4675 3475 4250 ...
 $ sex              : Factor w/ 2 levels "female","male": 2 1 1 NA 1 2 1 2 NA NA ...
 $ year             : int [1:344] 2007 2007 2007 2007 2007 2007 2007 2007 2007 2007 ...

You’ll notice that the column species is a factor: This is a special type of character variable that represents distinct categories known as “levels”. We have learned here that there are three levels in the species column: Adelie, Chinstrap, and Gentoo. We might want to explore individual columns of the data frame more in-depth. We can examine individual columns using the dollar sign $ to select one by name:

# Extract bill_length_mm as a vector
penguins$bill_length_mm
  [1] 39.1 39.5 40.3   NA 36.7 39.3 38.9 39.2 34.1 42.0 37.8 37.8 41.1 38.6 34.6
 [16] 36.6 38.7 42.5 34.4 46.0 37.8 37.7 35.9 38.2 38.8 35.3 40.6 40.5 37.9 40.5
 [31] 39.5 37.2 39.5 40.9 36.4 39.2 38.8 42.2 37.6 39.8 36.5 40.8 36.0 44.1 37.0
 [46] 39.6 41.1 37.5 36.0 42.3 39.6 40.1 35.0 42.0 34.5 41.4 39.0 40.6 36.5 37.6
 [61] 35.7 41.3 37.6 41.1 36.4 41.6 35.5 41.1 35.9 41.8 33.5 39.7 39.6 45.8 35.5
 [76] 42.8 40.9 37.2 36.2 42.1 34.6 42.9 36.7 35.1 37.3 41.3 36.3 36.9 38.3 38.9
 [91] 35.7 41.1 34.0 39.6 36.2 40.8 38.1 40.3 33.1 43.2
 [ reached getOption("max.print") -- omitted 244 entries ]
# indexing operators can be used on these vectors too
penguins$bill_length_mm[1:10]
 [1] 39.1 39.5 40.3   NA 36.7 39.3 38.9 39.2 34.1 42.0

We can perform our regular vector operations on columns directly.

# calculate the mean of the bill_length_mm column
mean(penguins$bill_length_mm,
     na.rm = TRUE) # remove missing values before calculating the mean
[1] 43.92193

We can also calculate the full summary statistics for a single column directly.

# show a summary of the bill_length_mm column
summary(penguins$bill_length_mm)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
  32.10   39.23   44.45   43.92   48.50   59.60       2 

Extract species as a vector and subset it to see a preview.

# get the first 10 values of the species column
penguins$species[1:10]
 [1] Adelie Adelie Adelie Adelie Adelie Adelie Adelie Adelie Adelie Adelie
Levels: Adelie Chinstrap Gentoo

And view its levels with the levels() function.

levels(penguins$species)
[1] "Adelie"    "Chinstrap" "Gentoo"   
Adelie

Chinstrap

Gentoo

Files and directories

In many situations, we will be reading in tabular data from a file and using it as a data frame. To practice, we will read in a file we will be using in the next notebook as well, gene_results_GSE44971.tsv, in the data folder. File paths are relative to the location where this notebook file (.Rmd) is saved.

Here we will use a function, read_tsv() from the readr package. Before we are able to use the function, we have to load the package using library().

library(readr)

file.path() creates a properly formatted file path by adding a path separator (/ on Mac and Linux operating systems, the latter of which is the operating system that our RStudio Server runs on) between separate folders or directories. Because file path separators can differ between your computer and the computer of someone who wants to use your code, we use file.path() instead of typing out "data/gene_results_GSE44971.tsv". Each argument to file.path() is a directory or file name. You’ll notice each argument is in quotes, we specify data first because the file, gene_results_GSE44971.tsv is in the data folder.

file.path("data", "gene_results_GSE44971.tsv")
[1] "data/gene_results_GSE44971.tsv"
data/gene_results_GSE44971.tsv

As you can see above, the result of running file.path() is that it creates a string with an accurately-formatted path for your file system. This string can be used moving forward when you need to refer to the path to your file. Let’s go ahead and store this file path as a variable in our environment.

gene_file_path <- file.path("data", "gene_results_GSE44971.tsv")

Now we are ready to use read_tsv() to read the file into R. The resulting data frame will be stored in a variable named stats_df. Note the <- (assignment operator!) is responsible for saving this to our global environment.

# read in the file `gene_results_GSE44971.tsv` from the data directory
stats_df <- read_tsv(gene_file_path)
Rows: 6804 Columns: 8
── Column specification ────────────────────────────────────────────────────────
Delimiter: "\t"
chr (3): ensembl_id, gene_symbol, contrast
dbl (5): log_fold_change, avg_expression, t_statistic, p_value, adj_p_value

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Take a look at your environment panel to see what stats_df looks like. We can also print out a preview of the stats_df data frame here.

# display stats_df
stats_df

Session Info

At the end of every notebook, you will see us print out sessionInfo. This aids in the reproducibility of your code by showing exactly what packages and versions were being used the last time the notebook was run.

sessionInfo()
R version 4.2.3 (2023-03-15)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 22.04.2 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.20.so

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
 [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] readr_2.1.4    optparse_1.7.3

loaded via a namespace (and not attached):
 [1] knitr_1.42           magrittr_2.0.3       hms_1.1.3           
 [4] tidyselect_1.2.0     bit_4.0.5            getopt_1.20.3       
 [7] R6_2.5.1             rlang_1.1.0          fastmap_1.1.1       
[10] fansi_1.0.4          stringr_1.5.0        tools_4.2.3         
[13] palmerpenguins_0.1.1 parallel_4.2.3       vroom_1.6.1         
[16] xfun_0.39            utf8_1.2.3           cli_3.6.1           
[19] jquerylib_0.1.4      htmltools_0.5.5      bit64_4.0.5         
[22] yaml_2.3.7           digest_0.6.31        tibble_3.2.1        
[25] lifecycle_1.0.3      crayon_1.5.2         tzdb_0.3.0          
[28] sass_0.4.5           vctrs_0.6.2          glue_1.6.2          
[31] cachem_1.0.7         evaluate_0.20        rmarkdown_2.21      
[34] stringi_1.7.12       pillar_1.9.0         compiler_4.2.3      
[37] bslib_0.4.2          jsonlite_1.8.4       pkgconfig_2.0.3     
LS0tCnRpdGxlOiAiSW50cm9kdWN0aW9uIHRvIFIgYW5kIFJTdHVkaW8iCmF1dGhvcjogT3JpZ2luYWxseSBhdXRob3JlZCBieSBTdGVwaGFuaWUgSi4gU3BpZWxtYW4sPGJyPmFkYXB0ZWQgYnkgQ0NETCBmb3IgQUxTRgpkYXRlOiAyMDIxCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKLS0tCgojIyBPYmplY3RpdmVzCgpUaGlzIG5vdGVib29rIHdpbGwgZGVtb25zdHJhdGUgaG93IHRvOiAgCgotIE5hdmlnYXRlIHRoZSBSU3R1ZGlvIGVudmlyb25tZW50ICAKLSBVc2UgUiBmb3Igc2ltcGxlIGNhbGN1bGF0aW9ucywgYm90aCBtYXRoZW1hdGljYWwgYW5kIGxvZ2ljYWwgIAotIERlZmluZSBhbmQgdXNlIHZhcmlhYmxlcyBpbiBiYXNlIFIgIAotIFVuZGVyc3RhbmQgYW5kIGFwcGx5IGJhc2UgUiBmdW5jdGlvbnMgICAKLSBVbmRlcnN0YW5kLCBkZWZpbmUsIGFuZCB1c2UgUiBkYXRhIHR5cGVzLCBpbmNsdWRpbmcgdmVjdG9yIG1hbmlwdWxhdGlvbiBhbmQgaW5kZXhpbmcgIAotIFVuZGVyc3RhbmQgdGhlIGFuYXRvbXkgb2YgYSBkYXRhIGZyYW1lICAKCi0tLQoKIyMjIyAqTW9yZSByZXNvdXJjZXMgZm9yIGxlYXJuaW5nIFIqIAoKLSBbU3dpcmwsIGFuIGludGVyYWN0aXZlIHR1dG9yaWFsXShodHRwczovL3N3aXJsc3RhdHMuY29tLykgIAotIFtfUiBmb3IgRGF0YSBTY2llbmNlXyBib29rXShodHRwczovL3I0ZHMuaGFkLmNvLm56LykgIAotIFtUdXRvcmlhbCBvbiBSLCBSU3R1ZGlvIGFuZCBSIE1hcmtkb3duXShodHRwczovL2lzbWF5Yy5naXRodWIuaW8vcmJhc2ljcy1ib29rLykgIAotIFtIYW5keSBSIGNoZWF0c2hlZXRzXShodHRwczovL3d3dy5wb3NpdC5jby9yZXNvdXJjZXMvY2hlYXRzaGVldHMvKSAgCi0gW1IgTWFya2Rvd24gd2Vic2l0ZV0oaHR0cHM6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20pICAKLSBbX1IgTWFya2Rvd246IFRoZSBEZWZpbml0aXZlIEd1aWRlX10oaHR0cHM6Ly9ib29rZG93bi5vcmcveWlodWkvcm1hcmtkb3duLykgIAoKIyMgV2hhdCBpcyBSPwoKKipSKiogaXMgYSBzdGF0aXN0aWNhbCBjb21wdXRpbmcgbGFuZ3VhZ2UgdGhhdCBpcyBfb3BlbiBzb3VyY2VfLCBtZWFuaW5nIHRoZSB1bmRlcmx5aW5nIGNvZGUgZm9yIHRoZSBsYW5ndWFnZSBpcyBmcmVlbHkgYXZhaWxhYmxlIHRvIGFueW9uZS4gCllvdSBkbyBub3QgbmVlZCBhIHNwZWNpYWwgbGljZW5zZSBvciBzZXQgb2YgcGVybWlzc2lvbnMgdG8gdXNlIGFuZCBkZXZlbG9wIGNvZGUgaW4gUi4gCgpSIGl0c2VsZiBpcyBhbiBfaW50ZXJwcmV0ZWQgY29tcHV0ZXIgbGFuZ3VhZ2VfIGFuZCBjb21lcyB3aXRoIGZ1bmN0aW9uYWxpdHkgdGhhdCBjb21lcyBidW5kbGVkIHdpdGggdGhlIGxhbmd1YWdlIGl0c2VsZiwga25vd24gYXMgKioiYmFzZSBSIioqLgpCdXQgdGhlcmUgaXMgYWxzbyByaWNoIGFkZGl0aW9uYWwgZnVuY3Rpb25hbGl0eSBwcm92aWRlZCBieSAqKmV4dGVybmFsIHBhY2thZ2VzKiosIG9yIGxpYnJhcmllcyBvZiBjb2RlIHRoYXQgYXNzaXN0IGluIGFjY29tcGxpc2hpbmcgY2VydGFpbiB0YXNrcyBhbmQgY2FuIGJlIGZyZWVseSBkb3dubG9hZGVkIGFuZCBsb2FkZWQgZm9yIHVzZS4gCgpJbiB0aGUgbmV4dCBub3RlYm9vayBhbmQgc3Vic2VxdWVudCBtb2R1bGVzLCB3ZSB3aWxsIGJlIHVzaW5nIGEgc3VpdGUgb2YgcGFja2FnZXMgY29sbGVjdGl2ZWx5IGtub3duIGFzIFsqKlRoZSBUaWR5dmVyc2UqKl0oaHR0cHM6Ly90aWR5dmVyc2Uub3JnKS4gClRoZSBgdGlkeXZlcnNlYCBpcyBnZWFyZWQgdG93YXJkcyBpbnR1aXRpdmUgZGF0YSBzY2llbmNlIGFwcGxpY2F0aW9ucyB0aGF0IGZvbGxvdyBhIHNoYXJlZCBkYXRhIHBoaWxvc29waHkuCkJ1dCB0aGVyZSBhcmUgc3RpbGwgbWFueSBjb3JlIGZlYXR1cmVzIG9mIGJhc2UgUiB3aGljaCBhcmUgaW1wb3J0YW50IHRvIGJlIGF3YXJlIG9mLCBhbmQgd2Ugd2lsbCBiZSB1c2luZyBjb25jZXB0cyBmcm9tIGJvdGggYmFzZSBSIGFuZCB0aGUgdGlkeXZlcnNlIGluIG91ciBhbmFseXNlcywgYXMgd2VsbCBhcyB0YXNrIHNwZWNpZmljIHBhY2thZ2VzIGZvciBhbmFseXNlcyBzdWNoIGFzIGdlbmUgZXhwcmVzc2lvbi4gCgojIyMgV2hhdCBpcyBSU3R1ZGlvPwoKUlN0dWRpbyBpcyBhIF9ncmFwaGljYWwgZW52aXJvbm1lbnRfICgiaW50ZWdyYXRlZCBkZXZlbG9wbWVudCBlbnZpcm9ubWVudCIgb3IgSURFKSBmb3Igd3JpdGluZyBhbmQgZGV2ZWxvcGluZyBSIGNvZGUuIFJTdHVkaW8gaXMgTk9UIGEgc2VwYXJhdGUgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2UgLSBpdCBpcyBhbiBpbnRlcmZhY2Ugd2UgdXNlIHRvIGZhY2lsaXRhdGUgUiBwcm9ncmFtbWluZy4gCkluIG90aGVyIHdvcmRzLCB5b3UgY2FuIHByb2dyYW0gaW4gUiB3aXRob3V0IFJTdHVkaW8sIGJ1dCB5b3UgY2FuJ3QgdXNlIHRoZSBSU3R1ZGlvIGVudmlyb25tZW50IHdpdGhvdXQgUi4KCkZvciBtb3JlIGluZm9ybWF0aW9uIGFib3V0IFJTdHVkaW8gdGhhbiB5b3UgZXZlciB3YW50ZWQgdG8ga25vdywgc2VlIHRoaXMgW1JTdHVkaW8gSURFIENoZWF0c2hlZXQgKHBkZildKGh0dHBzOi8vZ2l0aHViLmNvbS9yc3R1ZGlvL2NoZWF0c2hlZXRzL3Jhdy9tYWluL3JzdHVkaW8taWRlLnBkZikuCgojIyBUaGUgUlN0dWRpbyBFbnZpcm9ubWVudAoKVGhlIFJTdHVkaW8gZW52aXJvbm1lbnQgaGFzIGZvdXIgbWFpbiAqKnBhbmVzKiosIGVhY2ggb2Ygd2hpY2ggbWF5IGhhdmUgYSBudW1iZXIgb2YgdGFicyB0aGF0IGRpc3BsYXkgZGlmZmVyZW50IGluZm9ybWF0aW9uIG9yIGZ1bmN0aW9uYWxpdHkuICh0aGVpciBzcGVjaWZpYyBsb2NhdGlvbiBjYW4gYmUgY2hhbmdlZCB1bmRlciBUb29scyAtPiBHbG9iYWwgT3B0aW9ucyAtPiBQYW5lIExheW91dCkuCiFbUlN0dWRpbyBBcHBlYXJhbmNlXShzY3JlZW5zaG90cy9yc3R1ZGlvLXBhbmVzLnBuZykgCgoxLiBUaGUgKipFZGl0b3IqKiBwYW5lIGlzIHdoZXJlIHlvdSBjYW4gd3JpdGUgUiBzY3JpcHRzIGFuZCBvdGhlciBkb2N1bWVudHMuIEVhY2ggdGFiIGhlcmUgaXMgaXRzIG93biBkb2N1bWVudC4KVGhpcyBpcyB5b3VyIF90ZXh0IGVkaXRvcl8sIHdoaWNoIHdpbGwgYWxsb3cgeW91IHRvIHNhdmUgeW91ciBSIGNvZGUgZm9yIGZ1dHVyZSB1c2UuIApOb3RlIHRoYXQgY2hhbmdlIGNvZGUgaGVyZSB3aWxsIG5vdCBydW4gYXV0b21hdGljYWxseSB1bnRpbCB5b3UgcnVuIGl0LiAKCjIuIFRoZSAqKkNvbnNvbGUqKiBwYW5lIGlzIHdoZXJlIHlvdSBjYW4gX2ludGVyYWN0aXZlbHlfIHJ1biBSIGNvZGUuIAogICsgVGhlcmUgaXMgYWxzbyBhICoqVGVybWluYWwqKiB0YWIgaGVyZSB3aGljaCBjYW4gYmUgdXNlZCBmb3IgcnVubmluZyBwcm9ncmFtcyBvdXRzaWRlIFIgb24geW91ciBjb21wdXRlcgogIAozLiBUaGUgKipFbnZpcm9ubWVudCoqIHBhbmUgcHJpbWFyaWx5IGRpc3BsYXlzIHRoZSB2YXJpYWJsZXMsIHNvbWV0aW1lcyBrbm93biBhcyBfb2JqZWN0c18gdGhhdCBhcmUgZGVmaW5lZCBkdXJpbmcgYSBnaXZlbiBSIHNlc3Npb24sIGFuZCB3aGF0IGRhdGEgb3IgdmFsdWVzIHRoZXkgbWlnaHQgaG9sZC4KCjQuIFRoZSBmaW5hbCBwYW5lLCAqKkZpbGVzLCBQbG90cywgSGVscCwgLi4uKiosIGhhcyBzZXZlcmFsIHByZXR0eSBpbXBvcnRhbnQgdGFiczoKICAgICsgVGhlICoqRmlsZXMqKiB0YWIgc2hvd3MgdGhlIHN0cnVjdHVyZSBhbmQgY29udGVudHMgb2YgZmlsZXMgYW5kIGZvbGRlcnMgKGFsc28ga25vd24gYXMgZGlyZWN0b3JpZXMpIG9uIHlvdXIgY29tcHV0ZXIuCiAgICArIFRoZSAqKlBsb3RzKiogdGFiIHdpbGwgcmV2ZWFsIHBsb3RzIHdoZW4geW91IG1ha2UgdGhlbQogICAgKyBUaGUgKipQYWNrYWdlcyoqIHRhYiBzaG93cyB3aGljaCBpbnN0YWxsZWQgcGFja2FnZXMgaGF2ZSBiZWVuIGxvYWRlZCBpbnRvIHlvdXIgUiBzZXNzaW9uCiAgICArIFRoZSAqKkhlbHAqKiB0YWIgd2lsbCBzaG93IHRoZSBoZWxwIHBhZ2Ugd2hlbiB5b3UgbG9vayB1cCBhIGZ1bmN0aW9uCiAgICArIFRoZSAqKlZpZXdlcioqIHRhYiB3aWxsIHJldmVhbCBjb21waWxlZCBSIE1hcmtkb3duIGRvY3VtZW50cwoKIyMgQmFzaWMgQ2FsY3VsYXRpb25zCgojIyMgTWF0aGVtYXRpY2FsIG9wZXJhdG9ycwoKVGhlIG1vc3QgYmFzaWMgdXNlIG9mIFIgaXMgYXMgYSByZWd1bGFyIGNhbGN1bGF0b3I6Cgp8IE9wZXJhdGlvbiB8IFN5bWJvbCB8CnwtLS0tLS0tLS0tLXwtLS0tLS0tLXwKfCBBZGQgIHwgYCtgIHwgCnwgU3VidHJhY3QgIHwgYC1gIHwgCnwgTXVsdGlwbHkgIHwgYCpgIHwgCnwgRGl2aWRlICB8IGAvYCB8IAp8IEV4cG9uZW50aWF0ZSB8IGBeYCBvciBgKipgIHwgCgpGb3IgZXhhbXBsZSwgd2UgY2FuIGRvIHNvbWUgc2ltcGxlIG11bHRpcGxpY2F0aW9uIGxpa2UgdGhpcy4gCldoZW4geW91IGV4ZWN1dGUgY29kZSB3aXRoaW4gdGhlIG5vdGVib29rLCB0aGUgcmVzdWx0cyBhcHBlYXIgYmVuZWF0aCB0aGUgY29kZS4gClRyeSBleGVjdXRpbmcgdGhpcyBjaHVuayBieSBjbGlja2luZyB0aGUgKlJ1biogYnV0dG9uIHdpdGhpbiB0aGUgY2h1bmsgb3IgYnkgCnBsYWNpbmcgeW91ciBjdXJzb3IgaW5zaWRlIGl0IGFuZCBwcmVzc2luZyAqQ21kK1NoaWZ0K0VudGVyKiBvbiBhIE1hYywgb3IgKkN0cmwrU2hpZnQrRW50ZXIqIG9uIGEgUEMuCgpgYGB7ciBjYWxjdWxhdG9yfQo1ICogNgpgYGAKClVzZSB0aGUgY29uc29sZSB0byBjYWxjdWxhdGUgb3RoZXIgZXhwcmVzc2lvbnMuIFN0YW5kYXJkIG9yZGVyIG9mIG9wZXJhdGlvbnMgYXBwbGllcyAobW9zdGx5KSwgYW5kICB5b3UgY2FuIHVzZSBwYXJlbnRoZXNlcyBgKClgIGFzIHlvdSBtaWdodCBleHBlY3QgKGJ1dCBub3QgYnJhY2tldHMgYFtdYCBvciBicmFjZXNge31gLCB3aGljaCBoYXZlIHNwZWNpYWwgbWVhbmluZ3MpLiBOb3RlIGhvd2V2ZXIsIHRoYXQgeW91IG11c3QgKiphbHdheXMqKiBzcGVjaWZ5IG11bHRpcGxpY2F0aW9uIHdpdGggYCpgOyBpbXBsaWNpdCBtdWx0aXBsaWNhdGlvbiBzdWNoIGFzIGAxMCgzICsgNClgIG9yIGAxMHhgIHdpbGwgbm90IHdvcmsgYW5kIHdpbGwgZ2VuZXJhdGUgYW4gZXJyb3IsIG9yIHdvcnNlLgoKYGBge3IgZXhwcmVzc2lvbnMsIGxpdmUgPSBUUlVFfQoxMCAqICgzICsgNCleMgpgYGAKCgojIyMgRGVmaW5pbmcgYW5kIHVzaW5nIHZhcmlhYmxlcyAKClRvIGRlZmluZSBhIHZhcmlhYmxlLCB3ZSB1c2UgdGhlIF9hc3NpZ25tZW50IG9wZXJhdG9yXyB3aGljaCBsb29rcyBsaWtlIGFuIGFycm93OiBgPC1gLCBmb3IgZXhhbXBsZSBgeCA8LSA3YCB0YWtlcyB0aGUgdmFsdWUgb24gdGhlIHJpZ2h0LWhhbmQgc2lkZSBvZiB0aGUgb3BlcmF0b3IgYW5kIGFzc2lnbnMgaXQgdG8gdGhlIHZhcmlhYmxlIG5hbWUgb24gdGhlIGxlZnQtaGFuZCBzaWRlLiAKCmBgYHtyIHZhci1kZWZpbmUsIGxpdmUgPSBUUlVFfQojIERlZmluZSBhIHZhcmlhYmxlIHggdG8gZXF1YWwgNywgYW5kIHByaW50IG91dCB0aGUgdmFsdWUgb2YgeAp4IDwtIDcKCiMgV2UgY2FuIGhhdmUgUiByZXBlYXQgYmFjayB0byB1cyB3aGF0IGB4YCBpcyBieSBqdXN0IHVzaW5nIGB4YAp4CmBgYAoKU29tZSBmZWF0dXJlcyBvZiB2YXJpYWJsZXMsIGNvbnNpZGVyaW5nIHRoZSBleGFtcGxlIGB4IDwtIDdgOgpFdmVyeSB2YXJpYWJsZSBoYXMgYSAqKm5hbWUqKiwgYSAqKnZhbHVlKiosIGFuZCBhICoqdHlwZSoqLiAKVGhpcyB2YXJpYWJsZSdzIG5hbWUgaXMgYHhgLCBpdHMgdmFsdWUgaXMgYDdgLCBhbmQgaXRzIHR5cGUgaXMgYG51bWVyaWNgICg3IGlzIGEgbnVtYmVyISkuClJlLWRlZmluaW5nIGEgdmFyaWFibGUgd2lsbCBvdmVyd3JpdGUgdGhlIHZhbHVlLgoKYGBge3IgdmFyLXJlZGVmaW5lfQp4IDwtIDUuNQoKeApgYGAKCldlIGNhbiBtb2RpZnkgYW4gZXhpc3RpbmcgdmFyaWFibGUgYnkgcmVhc3NpZ25pbmcgaXQgdG8gaXRzIHNhbWUgbmFtZS4gCkhlcmUgd2UnbGwgYWRkIGAyYCB0byBgeGAgYW5kIHJlYXNzaWduIHRoZSByZXN1bHQgYmFjayB0byBgeGAuIAoKYGBge3IgdmFyLW1vZGlmeSwgbGl2ZSA9IFRSVUV9CnggPC0geCArIDIKCngKYGBgCgojIyMgVmFyaWFibGUgbmFtaW5nIG5vdGU6CkFzIGJlc3QgeW91IGNhbiwgaXQgaXMgYSBnb29kIGlkZWEgdG8gbWFrZSB5b3VyIHZhcmlhYmxlIG5hbWVzIGluZm9ybWF0aXZlIChlLmcuIGB4YCBkb2Vzbid0IG1lYW4gYW55dGhpbmcsIGJ1dCBgc2FuZHdpY2hfcHJpY2VgIGlzIG1lYW5pbmdmdWwuLi4gaWYgd2UncmUgdGFsa2luZyBhYm91dCB0aGUgY29zdCBvZiBzYW5kd2ljaGVzLCB0aGF0IGlzLi4pLiAKCiMjIyBDb21tZW50cwoKQXJndWFibHkgdGhlIF9fbW9zdCBpbXBvcnRhbnRfXyBhc3BlY3Qgb2YgeW91ciBjb2RpbmcgaXMgY29tbWVudHM6IFNtYWxsIHBpZWNlcyBvZiBleHBsYW5hdG9yeSB0ZXh0IHlvdSBsZWF2ZSBpbiB5b3VyIGNvZGUgdG8gZXhwbGFpbiB3aGF0IHRoZSBjb2RlIGlzIGRvaW5nIGFuZC9vciBsZWF2ZSBub3RlcyB0byB5b3Vyc2VsZiBvciBvdGhlcnMuIApDb21tZW50cyBhcmUgaW52YWx1YWJsZSBmb3IgY29tbXVuaWNhdGluZyB5b3VyIGNvZGUgdG8gb3RoZXJzLCBidXQgdGhleSBhcmUgbW9zdCBpbXBvcnRhbnQgZm9yICoqRnV0dXJlIFlvdSoqLiAKRnV0dXJlIFlvdSBjb21lcyBpbnRvIGV4aXN0ZW5jZSBhYm91dCBvbmUgc2Vjb25kIGFmdGVyIHlvdSB3cml0ZSBjb2RlLCBhbmQgaGFzIG5vIGlkZWEgd2hhdCBvbiBlYXJ0aCBQYXN0IFlvdSB3YXMgdGhpbmtpbmcuIAoKQ29tbWVudHMgaW4gUiBjb2RlIGFyZSBpbmRpY2F0ZWQgd2l0aCBwb3VuZCBzaWducyAoKmFrYSogaGFzaHRhZ3MsIG9jdG90aG9ycHMpLiBSIHdpbGwgX2lnbm9yZV8gYW55IHRleHQgaW4gYSBsaW5lIGFmdGVyIHRoZSBwb3VuZCBzaWduLCBzbyB5b3UgY2FuIHB1dCB3aGF0ZXZlciB0ZXh0IHlvdSBsaWtlIHRoZXJlLgoKYGBge3IgY29tbWVudHN9CjIyLzcgIyBub3QgcXVpdGUgcGkKCiMgSWYgd2UgbmVlZCBhIGJldHRlciBhcHByb3hpbWF0aW9uIG9mIHBpLCB3ZSBjYW4gdXNlIEV1bGVyJ3MgZm9ybXVsYQojIFRoaXMgdXNlcyBhdGFuKCksIHdoaWNoIGNhbGN1bGF0ZXMgYXJjdGFuZ2VudC4KMjAgKiBhdGFuKDEvNykgKyA4ICogYXRhbigzLzc5KSAKYGBgCgpIZWxwIG91dCBGdXR1cmUgWW91IGJ5IGFkZGluZyBsb3RzIG9mIGNvbW1lbnRzISAKRnV0dXJlIFlvdSBuZXh0IHdlZWsgdGhpbmtzIFRvZGF5IFlvdSBpcyBhbiBpZGlvdCwgYW5kIHRoZSBvbmx5IHdheSB5b3UgY2FuIGNvbnZpbmNlIEZ1dHVyZSBZb3UgdGhhdCBUb2RheSBZb3UgaXMgcmVhc29uYWJseSBjb21wZXRlbnQgaXMgYnkgYWRkaW5nIGNvbW1lbnRzIGluIHlvdXIgY29kZSBleHBsYWluaW5nIHdoeSBUb2RheSBZb3UgaXMgYWN0dWFsbHkgbm90IHNvIGJhZC4KCiMjIEZ1bmN0aW9ucwpXZSBjYW4gdXNlIHByZS1idWlsdCBjb21wdXRhdGlvbiBtZXRob2RzIGNhbGxlZCAiZnVuY3Rpb25zIiBmb3Igb3RoZXIgb3BlcmF0aW9ucy4gCkZ1bmN0aW9ucyBoYXZlIHRoZSBmb2xsb3dpbmcgZm9ybWF0LCB3aGVyZSB0aGUgX2FyZ3VtZW50XyBpcyB0aGUgaW5mb3JtYXRpb24gd2UgYXJlIHByb3ZpZGluZyB0byB0aGUgZnVuY3Rpb24gZm9yIGl0IHRvIHJ1bi4gCkFuIGV4YW1wbGUgb2YgdGhpcyB3YXMgdGhlIGBhdGFuKClgIGZ1bmN0aW9uIHVzZWQgYWJvdmUuCgpgYGByCmZ1bmN0aW9uX25hbWUoYXJndW1lbnQpCmBgYAoKVG8gbGVhcm4gYWJvdXQgZnVuY3Rpb25zLCB3ZSdsbCBleGFtaW5lIG9uZSBjYWxsZWQgYGxvZygpYCBmaXJzdC4gCgpUbyBrbm93IHdoYXQgYSBmdW5jdGlvbiBkb2VzIGFuZCBob3cgdG8gdXNlIGl0LCB1c2UgdGhlIHF1ZXN0aW9uIG1hcmsgd2hpY2ggd2lsbCByZXZlYWwgZG9jdW1lbnRhdGlvbiBpbiB0aGUgKipoZWxwIHBhbmUqKjogYD9sb2dgCiFbcmhlbHBdKHNjcmVlbnNob3RzL3JoZWxwLWxvZy5wbmcpIAoKVGhlIGRvY3VtZW50YXRpb24gdGVsbHMgdXMgdGhhdCBgbG9nKClgIGlzIGRlcml2ZWQgZnJvbSBge2Jhc2V9YCwgbWVhbmluZyBpdCBpcyBhIGZ1bmN0aW9uIHRoYXQgaXMgcGFydCBvZiBiYXNlIFIuIApJdCBwcm92aWRlcyBhIGJyaWVmIGRlc2NyaXB0aW9uIG9mIHdoYXQgdGhlIGZ1bmN0aW9uIGRvZXMgYW5kIHNob3dzIHNldmVyYWwgZXhhbXBsZXMgb2YgdG8gaG93IHVzZSBpdC4KCkluIHBhcnRpY3VsYXIsIHRoZSBkb2N1bWVudGF0aW9uIHRlbGxzIHVzIGFib3V0IHdoYXQgYXJndW1lbnQocykgdG8gcHJvdmlkZToKCisgVGhlIGZpcnN0IF9yZXF1aXJlZF8gYXJndW1lbnQgaXMgdGhlIHZhbHVlIHdlJ2QgbGlrZSB0byB0YWtlIHRoZSBsb2cgb2YsIGJ5IGRlZmF1bHQgaXRzIF9uYXR1cmFsIGxvZ18KKyBUaGUgc2Vjb25kIF9vcHRpb25hbF8gYXJndW1lbnQgY2FuIHNwZWNpZnkgYSBkaWZmZXJlbnQgYmFzZSByYXRoZXIgdGhhbiB0aGUgZGVmYXVsdCBgZWAuCgpGdW5jdGlvbnMgYWxzbyBfcmV0dXJuXyB2YWx1ZXMgZm9yIHVzIHRvIHVzZS4gCkluIHRoZSBjYXNlIG9mIGBsb2coKWAsIHRoZSByZXR1cm5lZCB2YWx1ZSBpcyB0aGUgbG9nJ2QgdmFsdWUgdGhlIGZ1bmN0aW9uIGNvbXB1dGVkLgoKYGBge3IgbG9nfQpsb2coNzMpCmBgYAoKSGVyZSB3ZSBjYW4gc3BlY2lmeSBhbiBfYXJndW1lbnRfIG9mIGBiYXNlYCB0byBjYWxjdWxhdGUgbG9nIGJhc2UgMy4gCgpgYGB7ciBsb2czfQpsb2coODEsIGJhc2UgPSAzKQpgYGAKCklmIHdlIGRvbid0IHNwZWNpZnkgdGhlIF9hcmd1bWVudF8gbmFtZXMsIGl0IGFzc3VtZXMgdGhleSBhcmUgaW4gdGhlIG9yZGVyIHRoYXQgYGxvZ2AgZGVmaW5lcyB0aGVtLiAKU2VlIGA/bG9nYCB0byBzZWUgbW9yZSBhYm91dCBpdHMgYXJndW1lbnRzLiAKCmBgYHtyIGxvZzIsIGxpdmUgPSBUUlVFfQpsb2coOCwgMikKYGBgCgpXZSBjYW4gc3dpdGNoIHRoZSBvcmRlciBpZiB3ZSBzcGVjaWZ5IHRoZSBhcmd1bWVudCBuYW1lcy4gCgpgYGB7ciBsb2ctb3JkZXJ9CmxvZyhiYXNlID0gMTAsIHggPSA0MzQyKQpgYGAKCldlIGNhbiBhbHNvIHByb3ZpZGUgdmFyaWFibGVzIGFzIGFyZ3VtZW50cyBpbiB0aGUgc2FtZSB3YXkgYXMgdGhlIHJhdyB2YWx1ZXMuIAoKYGBge3IgbG9nLXZhcmlhYmxlfQptZWFuaW5nIDwtIDQyCmxvZyhtZWFuaW5nKQpgYGAKCiMjIFdvcmtpbmcgd2l0aCB2YXJpYWJsZXMKCiMjIyBWYXJpYWJsZSBUeXBlcwoKVmFyaWFibGUgdHlwZXMgaW4gUiBjYW4gc29tZXRpbWVzIGJlIF9jb2VyY2VkXyAoY29udmVydGVkKSBmcm9tIG9uZSB0eXBlIHRvIGFub3RoZXIuCgpgYGB7cn0KIyBEZWZpbmUgYSB2YXJpYWJsZSB3aXRoIGEgbnVtYmVyCnggPC0gMTUKYGBgCgpUaGUgZnVuY3Rpb24gYGNsYXNzKClgIHdpbGwgdGVsbCB1cyB0aGUgdmFyaWFibGUncyB0eXBlLgoKYGBge3J9CmNsYXNzKHgpCmBgYAoKTGV0J3MgY29lcmNlIGl0IHRvIGEgY2hhcmFjdGVyLiAKCmBgYHtyfQp4IDwtIGFzLmNoYXJhY3Rlcih4KQpjbGFzcyh4KQpgYGAKClNlZSBpdCBub3cgaGFzIHF1b3RlcyBhcm91bmQgaXQ/IEl0J3Mgbm93IGEgY2hhcmFjdGVyIGFuZCB3aWxsIGJlaGF2ZSBhcyBzdWNoLgoKYGBge3J9CngKYGBgCgpVc2UgdGhpcyBjaHVuayB0byB0cnkgdG8gcGVyZm9ybSBjYWxjdWxhdGlvbnMgd2l0aCBgeGAsIG5vdyB0aGF0IGl0IGlzIGEgY2hhcmFjdGVyLCB3aGF0IGhhcHBlbnM/IAoKYGBge3IgbGl2ZSA9IFRSVUV9CiMgVHJ5IHRvIHBlcmZvcm0gY2FsY3VsYXRpb25zIG9uIGB4YApgYGAKCkJ1dCB3ZSBjYW4ndCBjb2VyY2UgZXZlcnl0aGluZzoKCmBgYHtyfQojIExldCdzIGNyZWF0ZSBhIGNoYXJhY3RlciB2YXJpYWJsZQp4IDwtICJsb29rIGF0IG15IGNoYXJhY3RlciB2YXJpYWJsZSIKYGBgCgpMZXQncyB0cnkgbWFraW5nIHRoaXMgYSBudW1lcmljIHZhcmlhYmxlOgoKYGBge3IgY29lcmNlLWNoYXIsIGVycm9yPVRSVUV9CnggPC0gYXMubnVtZXJpYyh4KQpgYGAKClByaW50IG91dCBgeGAuCgpgYGB7cn0KeApgYGAKClIgaXMgdGVsbGluZyB1cyBpdCBkb2Vzbid0IGtub3cgaG93IHRvIGNvbnZlcnQgdGhpcyB0byBhIG51bWVyaWMgdmFyaWFibGUsIHNvIGl0IGhhcyByZXR1cm5lZCBgTkFgIGluc3RlYWQuCgpGb3IgcmVmZXJlbmNlLCBoZXJlJ3MgYSBzdW1tYXJ5IG9mIHNvbWUgb2YgdGhlIG1vc3QgaW1wb3J0YW50IHZhcmlhYmxlIHR5cGVzLiAKCnwgVmFyaWFibGUgVHlwZSB8IERlZmluaXRpb24gfCBFeGFtcGxlcyB8IENvZXJjaW9uIHwKfC0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS18LS0tLS0tLS0tLXwgLS0tLS0tLS18CnwgYG51bWVyaWNgICAgICAgIHwgQW55IG51bWJlciB2YWx1ZSB8IGA1YDxicj5gNy41YCA8YnI+YC0xYHwgYGFzLm51bWVyaWMoKWAKfCBgaW50ZWdlcmAgICAgICAgfCBBbnkgX3dob2xlXyBudW1iZXIgdmFsdWUgKG5vIGRlY2ltYWxzKSB8IGA1YCA8YnI+IGAtMTAwYCB8IGBhcy5pbnRlZ2VyKClgCnxgY2hhcmFjdGVyYCAgICAgIHwgQW55IGNvbGxlY3Rpb24gb2YgY2hhcmFjdGVycyBkZWZpbmVkIHdpdGhpbiBfcXVvdGF0aW9uIG1hcmtzXy4gQWxzbyBrbm93biBhcyBhICJzdHJpbmciLiB8IGAiYSJgIChhIHNpbmdsZSBsZXR0ZXIpIDxicj5gInN0cmluZ29mbGV0dGVycyJgIChhIHdob2xlIGJ1bmNoIG9mIGNoYXJhY3RlcnMgcHV0IHRvZ2V0aGVyIGFzIG9uZSkgPGJyPiBgInN0cmluZyBvZiBsZXR0ZXJzIGFuZCBzcGFjZXMiYCA8YnI+IGAiNSJgIDxicj4gYCdzaW5nbGUgcXVvdGVzIGFyZSBhbHNvIGdvb2QnYCB8IGBhcy5jaGFyYWN0ZXIoKWAKfGBsb2dpY2FsYCAgICAgIHwgQSB2YWx1ZSBvZiBgVFJVRWAsIGBGQUxTRWAsIG9yIGBOQWAgfCBgVFJVRWAgPGJyPiBgRkFMU0VgIDxicj4gYE5BYCAobm90IGRlZmluZWQpIHwgYGFzLmxvZ2ljYWwoKWAgCnxgZmFjdG9yYCAgICAgICB8IEEgc3BlY2lhbCB0eXBlIG9mIHZhcmlhYmxlIHRoYXQgZGVub3RlcyBzcGVjaWZpYyBjYXRlZ29yaWVzIG9mIGEgY2F0ZWdvcmljYWwgdmFyaWFibGUgfCAoc3RheSB0dW5lZC4uKSB8IGBhcy5mYWN0b3IoKWAKCiMjIyBWZWN0b3JzCgpZb3Ugd2lsbCBoYXZlIG5vdGljZWQgdGhhdCBhbGwgeW91ciBjb21wdXRhdGlvbnMgdGVuZCB0byBwb3AgdXAgd2l0aCBhIGBbMV1gIHByZWNlZGluZyB0aGVtIGluIFIncyBvdXRwdXQuIApUaGlzIGlzIGJlY2F1c2UsIGluIGZhY3QsIGFsbCAob2sgbW9zdGx5IGFsbCkgdmFyaWFibGVzIGFyZSBfYnkgZGVmYXVsdF8gIHZlY3RvcnMsIGFuZCBvdXIgYW5zd2VycyBhcmUgdGhlIGZpcnN0IChpbiB0aGVzZSBjYXNlcyBvbmx5KSB2YWx1ZSBpbiB0aGUgdmVjdG9yLiAKQXMgdmVjdG9ycyBnZXQgbG9uZ2VyLCBuZXcgaW5kZXggaW5kaWNhdG9ycyB3aWxsIGFwcGVhciBhdCB0aGUgc3RhcnQgb2YgbmV3IGxpbmVzLiAKCmBgYHtyfQojIFRoaXMgaXMgYWN0dWFsbHkgYW4gdmVjdG9yIHRoYXQgaGFzIG9uZSBpdGVtIGluIGl0Lgp4IDwtIDcKYGBgCgpgYGB7ciB2ZWN0b3ItbGVuZ3RofQojIFRoZSBsZW5ndGgoKSBmdW5jdGlvbnMgdGVsbHMgdXMgaG93IGxvbmcgYW4gdmVjdG9yIGlzOgpsZW5ndGgoeCkKYGBgCgpXZSBjYW4gZGVmaW5lIHZlY3RvcnMgd2l0aCB0aGUgZnVuY3Rpb24gYGMoKWAsIHdoaWNoIHN0YW5kcyBmb3IgImNvbWJpbmUiLiAKVGhpcyBmdW5jdGlvbiB0YWtlcyBhIGNvbW1hLXNlcGFyYXRlZCBzZXQgb2YgdmFsdWVzIHRvIHBsYWNlIGluIHRoZSB2ZWN0b3IsIGFuZCByZXR1cm5zIHRoZSB2ZWN0b3IgaXRzZWxmOgoKYGBge3IgbWFrZS12ZWN0b3J9Cm15X251bWVyaWNfdmVjdG9yIDwtIGMoMSwgMSwgMiwgMywgNSwgOCwgMTMsIDIxKQpteV9udW1lcmljX3ZlY3RvcgpgYGAKCldlIGNhbiBidWlsZCBvbiB2ZWN0b3JzIGluIHBsYWNlIGJ5IHJlZGVmaW5pbmcgdGhlbToKCmBgYHtyIGZpYmJvbmFjY2ksIGxpdmUgPSBUUlVFfQojIGFkZCB0aGUgbmV4dCB0d28gRmlib25hY2NpIG51bWJlcnMgdG8gdGhlIHNlcmllcy4KbXlfbnVtZXJpY192ZWN0b3IgPC0gYyhteV9udW1lcmljX3ZlY3RvciwgMzQsIDU1KQpteV9udW1lcmljX3ZlY3RvcgpgYGAKCldlIGNhbiBwdWxsIG91dCBzcGVjaWZpYyBpdGVtcyBmcm9tIGFuIHZlY3RvciB1c2luZyBhIHByb2Nlc3MgY2FsbGVkIF9pbmRleGluZ18sIHdoaWNoIHVzZXMgYnJhY2tldHMgYFtdYCB0byBzcGVjaWZ5IHRoZSBwb3NpdGlvbiBvZiBhbiBpdGVtLiAKCmBgYHtyIHN1YnNldDF9CiMgR3JhYiB0aGUgZm91cnRoIHZhbHVlIGZyb20gbXlfbnVtZXJpY192ZWN0b3IKIyBUaGlzIGdpdmVzIHVzIGFuIHZlY3RvciBvZiBsZW5ndGggMSAKbXlfbnVtZXJpY192ZWN0b3JbNF0KYGBgCgpDb2xvbnMgYXJlIGFsc28gYSBuaWNlIHdheSB0byBxdWlja2x5IG1ha2Ugb3JkZXJlZCBudW1lcmljIHZlY3RvcnMKVXNlIGEgY29sb24gdG8gc3BlY2lmeSBhbiBpbmNsdXNpdmUgcmFuZ2Ugb2YgaW5kaWNlcwpUaGlzIHdpbGwgcmV0dXJuIGFuIHZlY3RvciB3aXRoIDIsIDMsIDQsIGFuZCA1LgoKYGBge3Igc3Vic2V0LW1hbnl9Cm15X251bWVyaWNfdmVjdG9yWzI6NV0KYGBgCgpPbmUgbWFqb3IgYmVuZWZpdCBvZiB2ZWN0b3JzIGlzIHRoZSBjb25jZXB0IG9mICoqdmVjdG9yaXphdGlvbioqLCB3aGVyZSBSIGJ5IGRlZmF1bHQgcGVyZm9ybXMgb3BlcmF0aW9ucyBvbiB0aGUgX2VudGlyZSB2ZWN0b3IgYXQgb25jZV8uIApGb3IgZXhhbXBsZSwgd2UgY2FuIGdldCB0aGUgbG9nIG9mIGFsbCBudW1iZXJzIDEtMjAgd2l0aCBhIHNpbmdsZSwgc2ltcGxlIGNhbGwsIGFuZCBtb3JlIQoKYGBge3IgdmVjdG9yaXplfQp2YWx1ZXNfMV90b18yMCA8LSAxOjIwCmBgYAoKCmBgYHtyIHZlY3Rvcml6ZS1sb2csIGxpdmUgPSBUUlVFfQojIGNhbGN1bGF0ZSB0aGUgbG9nIG9mIHZhbHVlc18xX3RvXzIwCmxvZyh2YWx1ZXNfMV90b18yMCkKYGBgCgpGaW5hbGx5LCB3ZSBjYW4gYXBwbHkgbG9naWNhbCBleHByZXNzaW9ucyB0byB2ZWN0b3JzLCBqdXN0IGFzIHdlIGNhbiBkbyBmb3Igc2luZ2xlIHZhbHVlcy4KVGhlIG91dHB1dCBoZXJlIGlzIGEgbG9naWNhbCB2ZWN0b3IgdGVsbGluZyB1cyB3aGV0aGVyIGVhY2ggdmFsdWUgaW4gZXhhbXBsZV92ZWN0b3IgaXMgVFJVRSBvciBGQUxTRQoKYGBge3IgdmVjdG9yLWNvbXBhcmV9CiMgV2hpY2ggdmFsdWVzIGFyZSA8PSAzPwp2YWx1ZXNfMV90b18yMCA8PSAzCmBgYAoKVGhlcmUgYXJlIHNldmVyYWwga2V5IGZ1bmN0aW9ucyB3aGljaCBjYW4gYmUgdXNlZCBvbiB2ZWN0b3JzIGNvbnRhaW5pbmcgbnVtZXJpYyB2YWx1ZXMsIHNvbWUgb2Ygd2hpY2ggYXJlIGJlbG93LgoKKyBgbWVhbigpYDogVGhlIGF2ZXJhZ2UgdmFsdWUgaW4gdGhlIHZlY3RvcgorIGBtaW4oKWA6IFRoZSBtaW5pbXVtIHZhbHVlIGluIHRoZSB2ZWN0b3IKKyBgbWF4KClgOiBUaGUgbWF4aW11bSB2YWx1ZSBpbiB0aGUgdmVjdG9yCisgYHN1bSgpYDogVGhlIHN1bSBvZiBhbGwgdmFsdWVzIGluIHRoZSB2ZWN0b3IKCldlIGNhbiB0cnkgb3V0IHRoZXNlIGZ1bmN0aW9ucyBvbiB0aGUgdmVjdG9yIGB2YWx1ZXNfMV90b18yMGAgd2UndmUgY3JlYXRlZC4gCgpgYGB7ciB2ZWN0b3ItZnVuY3N9Cm1lYW4odmFsdWVzXzFfdG9fMjApCgojIFRyeSBvdXQgc29tZSBvZiB0aGUgb3RoZXIgZnVuY3Rpb25zIHdlJ3ZlIGxpc3RlZCBhYm92ZSAKCmBgYAoKIyMjIEEgbm90ZSBvbiB2YXJpYWJsZSBuYW1pbmcKCldlIGhhdmUgbGVhcm5lZCBmdW5jdGlvbnMgc3VjaCBhcyBgY2AsIGBsZW5ndGhgLCBgc3VtYCwgYW5kIGV0Yy4gCkltYWdpbmUgZGVmaW5pbmcgYSB2YXJpYWJsZSBjYWxsZWQgYGNgOiBUaGlzIHdpbGwgd29yaywgYnV0IGl0IHdpbGwgbGVhZCB0byBhIApsb3Qgb2YgdW5pbnRlbmRlZCBidWdzLCBzbyBpdCdzIGJlc3QgdG8gYXZvaWQgdGhpcy4gCgojIyMgVGhlIGAlaW4lYCBsb2dpY2FsIG9wZXJhdG9yIAoKYCVpbiVgIGlzIHVzZWZ1bCBmb3IgZGV0ZXJtaW5pbmcgd2hldGhlciBhIGdpdmVuIGl0ZW0ocykgYXJlIGluIGFuIHZlY3Rvci4KCmBgYHtyIGluLW9wZXJhdG9yfQojIGlzIGA3YCBpbiBvdXIgdmVjdG9yPyAKNyAlaW4lIHZhbHVlc18xX3RvXzIwCmBgYAoKYGBge3IgaW4yLCBsaXZlID0gVFJVRX0KIyBpcyBgNTBgIGluIG91ciB2ZWN0b3I/IAo1MCAlaW4lIHZhbHVlc18xX3RvXzIwCmBgYAoKV2UgY2FuIHRlc3QgYSB2ZWN0b3Igb2YgdmFsdWVzIGJlaW5nIHdpdGhpbiBhbm90aGVyIHZlY3RvciBvZiB2YWx1ZXMuIAoKYGBge3IgdmVjdG9yLWluLCBsaXZlID0gVFJVRX0KcXVlc3Rpb25fdmFsdWVzIDwtIGMoMTozLCA3LCA1MCkKIyBBcmUgdGhlc2UgdmFsdWVzIGluIG91ciB2ZWN0b3I/CnF1ZXN0aW9uX3ZhbHVlcyAlaW4lIHZhbHVlc18xX3RvXzIwCmBgYAoKIyMgRGF0YSBmcmFtZXMKCl9EYXRhIGZyYW1lcyBhcmUgb25lIG9mIHRoZSBtb3N0IHVzZWZ1bCB0b29scyBmb3IgZGF0YSBhbmFseXNpcyBpbiBSLl8gClRoZXkgYXJlIHRhYmxlcyB3aGljaCBjb25zaXN0IG9mIHJvd3MgYW5kIGNvbHVtbnMsIG11Y2ggbGlrZSBhIF9zcHJlYWRzaGVldF8uIApFYWNoIGNvbHVtbiBpcyBhIHZhcmlhYmxlIHdoaWNoIGJlaGF2ZXMgYXMgYSBfdmVjdG9yXywgYW5kIGVhY2ggcm93IGlzIGFuIG9ic2VydmF0aW9uLiAKV2Ugd2lsbCBiZWdpbiBvdXIgZXhwbG9yYXRpb24gd2l0aCBkYXRhc2V0IG9mIG1lYXN1cmVtZW50cyBmcm9tIHRocmVlIHBlbmd1aW4gc3BlY2llcyBtZWFzdXJlZCwgd2hpY2ggd2UgY2FuIGZpbmQgaW4gdGhlIFtgcGFsbWVycGVuZ3VpbnNgIHBhY2thZ2VdKGh0dHBzOi8vYWxsaXNvbmhvcnN0LmdpdGh1Yi5pby9wYWxtZXJwZW5ndWlucy8pLiAKV2UnbGwgdGFsayBtb3JlIGFib3V0IHBhY2thZ2VzIHNvb24hClRvIHVzZSB0aGlzIGRhdGFzZXQsIHdlIHdpbGwgbG9hZCBpdCBmcm9tIHRoZSBgcGFsbWVycGVuZ3VpbnNgIHBhY2thZ2UgdXNpbmcgYSBgOjpgIChtb3JlIG9uIHRoaXMgbGF0ZXIpIGFuZCBhc3NpZ24gaXQgdG8gYSB2YXJpYWJsZSBuYW1lZCBgcGVuZ3VpbnNgIGluIG91ciBjdXJyZW50IGVudmlyb25tZW50LgoKYGBge3IgcGVuZ3Vpbi1saWJyYXJ5fQpwZW5ndWlucyA8LSBwYWxtZXJwZW5ndWluczo6cGVuZ3VpbnMKYGBgCgohW2RyYXdpbmdzIG9mIHBlbmd1aW4gc3BlY2llc10oZGlhZ3JhbXMvbHRlcl9wZW5ndWlucy5wbmcpIEFydHdvcmsgYnkgW0BhbGxpc29uX2hvcnN0XShodHRwczovL3R3aXR0ZXIuY29tL2FsbGlzb25faG9yc3QpCgojIyMgRXhwbG9yaW5nIGRhdGEgZnJhbWVzCgpUaGUgZmlyc3Qgc3RlcCB0byB1c2luZyBhbnkgZGF0YSBpcyB0byBsb29rIGF0IGl0ISEhIApSU3R1ZGlvIGNvbnRhaW5zIGEgc3BlY2lhbCBmdW5jdGlvbiBgVmlldygpYCB3aGljaCBhbGxvd3MgeW91IHRvIGxpdGVyYWxseSB2aWV3IGEgdmFyaWFibGUuCllvdSBjYW4gYWxzbyBjbGljayBvbiB0aGUgb2JqZWN0IGluIHRoZSBlbnZpcm9ubWVudCBwYW5lIHRvIHNlZSBpdHMgb3ZlcmFsbCBwcm9wZXJ0aWVzLCBvciBjbGljayB0aGUgdGFibGUgaWNvbiBvbiB0aGUgb2JqZWN0J3Mgcm93IHRvIGF1dG9tYXRpY2FsbHkgdmlldyB0aGUgdmFyaWFibGUuIAoKU29tZSB1c2VmdWwgZnVuY3Rpb25zIGZvciBleHBsb3Jpbmcgb3VyIGRhdGEgZnJhbWUgaW5jbHVkZToKCisgYGhlYWQoKWAgdG8gc2VlIHRoZSBmaXJzdCA2IHJvd3Mgb2YgYSBkYXRhIGZyYW1lLiBBZGRpdGlvbmFsIGFyZ3VtZW50cyBzdXBwbGllZCBjYW4gY2hhbmdlIHRoZSBudW1iZXIgb2Ygcm93cy4KKyBgdGFpbCgpYCB0byBzZWUgdGhlIGxhc3QgNiByb3dzIG9mIGEgZGF0YSBmcmFtZS4gQWRkaXRpb25hbCBhcmd1bWVudHMgc3VwcGxpZWQgY2FuIGNoYW5nZSB0aGUgbnVtYmVyIG9mIHJvd3MuCisgYG5hbWVzKClgIHRvIHNlZSB0aGUgY29sdW1uIG5hbWVzIG9mIHRoZSBkYXRhIGZyYW1lLgorIGBucm93KClgIHRvIHNlZSBob3cgbWFueSByb3dzIGFyZSBpbiB0aGUgZGF0YSBmcmFtZQorIGBuY29sKClgIHRvIHNlZSBob3cgbWFueSBjb2x1bW5zIGFyZSBpbiB0aGUgZGF0YSBmcmFtZS4KCldlIGNhbiBhZGRpdGlvbmFsbHkgZXhwbG9yZSBfb3ZlcmFsbCBwcm9wZXJ0aWVzXyBvZiB0aGUgZGF0YSBmcmFtZSB3aXRoIHR3byBkaWZmZXJlbnQgZnVuY3Rpb25zOiBgc3VtbWFyeSgpYCBhbmQgYHN0cigpYC4KClRoaXMgcHJvdmlkZXMgc3VtbWFyeSBzdGF0aXN0aWNzIGZvciBlYWNoIGNvbHVtbjoKCmBgYHtyIHBlbmd1aW5zLXN1bW1hcnl9CnN1bW1hcnkocGVuZ3VpbnMpCmBgYAoKVGhpcyBwcm92aWRlcyBhIHNob3J0IHZpZXcgb2YgdGhlICoqc3RyKip1Y3R1cmUgYW5kIGNvbnRlbnRzIG9mIHRoZSBkYXRhIGZyYW1lLgoKYGBge3IgcGVuZ3VpbnMtc3RyfQpzdHIocGVuZ3VpbnMpCmBgYAoKWW91J2xsIG5vdGljZSB0aGF0IHRoZSBjb2x1bW4gYHNwZWNpZXNgIGlzIGEgX2ZhY3Rvcl86IFRoaXMgaXMgYSBzcGVjaWFsIHR5cGUgb2YgY2hhcmFjdGVyIHZhcmlhYmxlIHRoYXQgcmVwcmVzZW50cyBkaXN0aW5jdCBjYXRlZ29yaWVzIGtub3duIGFzICJsZXZlbHMiLiAKV2UgaGF2ZSBsZWFybmVkIGhlcmUgdGhhdCB0aGVyZSBhcmUgdGhyZWUgbGV2ZWxzIGluIHRoZSBgc3BlY2llc2AgY29sdW1uOiBBZGVsaWUsIENoaW5zdHJhcCwgYW5kIEdlbnRvby4KV2UgbWlnaHQgd2FudCB0byBleHBsb3JlIGluZGl2aWR1YWwgY29sdW1ucyBvZiB0aGUgZGF0YSBmcmFtZSBtb3JlIGluLWRlcHRoLiAKV2UgY2FuIGV4YW1pbmUgaW5kaXZpZHVhbCBjb2x1bW5zIHVzaW5nIHRoZSBkb2xsYXIgc2lnbiBgJGAgdG8gc2VsZWN0IG9uZSBieSBuYW1lOgoKYGBge3IgcGVuZ3VpbnMtc3Vic2V0fQojIEV4dHJhY3QgYmlsbF9sZW5ndGhfbW0gYXMgYSB2ZWN0b3IKcGVuZ3VpbnMkYmlsbF9sZW5ndGhfbW0KCiMgaW5kZXhpbmcgb3BlcmF0b3JzIGNhbiBiZSB1c2VkIG9uIHRoZXNlIHZlY3RvcnMgdG9vCnBlbmd1aW5zJGJpbGxfbGVuZ3RoX21tWzE6MTBdCmBgYAoKV2UgY2FuIHBlcmZvcm0gb3VyIHJlZ3VsYXIgdmVjdG9yIG9wZXJhdGlvbnMgb24gY29sdW1ucyBkaXJlY3RseS4KCmBgYHtyIHBlbmd1aW5zLWNvbC1tZWFuLCBsaXZlID0gVFJVRX0KIyBjYWxjdWxhdGUgdGhlIG1lYW4gb2YgdGhlIGJpbGxfbGVuZ3RoX21tIGNvbHVtbgptZWFuKHBlbmd1aW5zJGJpbGxfbGVuZ3RoX21tLAogICAgIG5hLnJtID0gVFJVRSkgIyByZW1vdmUgbWlzc2luZyB2YWx1ZXMgYmVmb3JlIGNhbGN1bGF0aW5nIHRoZSBtZWFuCmBgYAoKV2UgY2FuIGFsc28gY2FsY3VsYXRlIHRoZSBmdWxsIHN1bW1hcnkgc3RhdGlzdGljcyBmb3IgYSBzaW5nbGUgY29sdW1uIGRpcmVjdGx5LiAKCmBgYHtyIHBlbmd1aW5zLWNvbC1zdW1tYXJ5LCBsaXZlID0gVFJVRX0KIyBzaG93IGEgc3VtbWFyeSBvZiB0aGUgYmlsbF9sZW5ndGhfbW0gY29sdW1uCnN1bW1hcnkocGVuZ3VpbnMkYmlsbF9sZW5ndGhfbW0pCmBgYAoKRXh0cmFjdCBgc3BlY2llc2AgYXMgYSB2ZWN0b3IgYW5kIHN1YnNldCBpdCB0byBzZWUgYSBwcmV2aWV3LgoKYGBge3IgcGVuZ3VpbnMtY29sLXN1YnNldCwgbGl2ZSA9IFRSVUV9CiMgZ2V0IHRoZSBmaXJzdCAxMCB2YWx1ZXMgb2YgdGhlIHNwZWNpZXMgY29sdW1uCnBlbmd1aW5zJHNwZWNpZXNbMToxMF0KYGBgCgpBbmQgdmlldyBpdHMgX2xldmVsc18gd2l0aCB0aGUgYGxldmVscygpYCBmdW5jdGlvbi4KCmBgYHtyIHBlbmd1aW4tbGV2ZWxzfQpsZXZlbHMocGVuZ3VpbnMkc3BlY2llcykKYGBgCgojIyBGaWxlcyBhbmQgZGlyZWN0b3JpZXMKCkluIG1hbnkgc2l0dWF0aW9ucywgd2Ugd2lsbCBiZSByZWFkaW5nIGluIHRhYnVsYXIgZGF0YSBmcm9tIGEgZmlsZSBhbmQgdXNpbmcgaXQgYXMgYSBkYXRhIGZyYW1lLiAKVG8gcHJhY3RpY2UsIHdlIHdpbGwgcmVhZCBpbiBhIGZpbGUgd2Ugd2lsbCBiZSB1c2luZyBpbiB0aGUgbmV4dCBub3RlYm9vayBhcyB3ZWxsLCBgZ2VuZV9yZXN1bHRzX0dTRTQ0OTcxLnRzdmAsIGluIHRoZSBgZGF0YWAgZm9sZGVyLiAKRmlsZSBwYXRocyBhcmUgcmVsYXRpdmUgdG8gdGhlIGxvY2F0aW9uIHdoZXJlIHRoaXMgbm90ZWJvb2sgZmlsZSAoLlJtZCkgaXMgc2F2ZWQuCgpIZXJlIHdlIHdpbGwgdXNlIGEgZnVuY3Rpb24sIGByZWFkX3RzdigpYCBmcm9tIHRoZSBgcmVhZHJgIHBhY2thZ2UuCkJlZm9yZSB3ZSBhcmUgYWJsZSB0byB1c2UgdGhlIGZ1bmN0aW9uLCB3ZSBoYXZlIHRvIGxvYWQgdGhlIHBhY2thZ2UgdXNpbmcgYGxpYnJhcnkoKWAuIAoKYGBge3IgcmVhZHJ9CmxpYnJhcnkocmVhZHIpCmBgYAoKYGZpbGUucGF0aCgpYCBjcmVhdGVzIGEgcHJvcGVybHkgZm9ybWF0dGVkIGZpbGUgcGF0aCBieSBhZGRpbmcgYSBwYXRoIHNlcGFyYXRvciAoYC9gIG9uIE1hYyBhbmQgTGludXggb3BlcmF0aW5nIHN5c3RlbXMsIHRoZSBsYXR0ZXIgb2Ygd2hpY2ggaXMgdGhlIG9wZXJhdGluZyBzeXN0ZW0gdGhhdCBvdXIgUlN0dWRpbyBTZXJ2ZXIgcnVucyBvbikgYmV0d2VlbiBzZXBhcmF0ZSBmb2xkZXJzIG9yIGRpcmVjdG9yaWVzLgpCZWNhdXNlIGZpbGUgcGF0aCBzZXBhcmF0b3JzIGNhbiBkaWZmZXIgYmV0d2VlbiB5b3VyIGNvbXB1dGVyIGFuZCB0aGUgY29tcHV0ZXIgb2Ygc29tZW9uZSB3aG8gd2FudHMgdG8gdXNlIHlvdXIgY29kZSwgd2UgdXNlIGBmaWxlLnBhdGgoKWAgaW5zdGVhZCBvZiB0eXBpbmcgb3V0IGAiZGF0YS9nZW5lX3Jlc3VsdHNfR1NFNDQ5NzEudHN2ImAuCkVhY2ggX2FyZ3VtZW50XyB0byBgZmlsZS5wYXRoKClgIGlzIGEgZGlyZWN0b3J5IG9yIGZpbGUgbmFtZS4KWW91J2xsIG5vdGljZSBlYWNoIGFyZ3VtZW50IGlzIGluIHF1b3Rlcywgd2Ugc3BlY2lmeSBgZGF0YWAgZmlyc3QgYmVjYXVzZSB0aGUgZmlsZSwgYGdlbmVfcmVzdWx0c19HU0U0NDk3MS50c3ZgIGlzIGluIHRoZSBgZGF0YWAgZm9sZGVyLiAKCmBgYHtyIGZpbGUucGF0aH0KZmlsZS5wYXRoKCJkYXRhIiwgImdlbmVfcmVzdWx0c19HU0U0NDk3MS50c3YiKQpgYGAKCkFzIHlvdSBjYW4gc2VlIGFib3ZlLCB0aGUgcmVzdWx0IG9mIHJ1bm5pbmcgYGZpbGUucGF0aCgpYCBpcyB0aGF0IGl0IF9jcmVhdGVzIGEgc3RyaW5nXyB3aXRoIGFuIGFjY3VyYXRlbHktZm9ybWF0dGVkIHBhdGggZm9yIHlvdXIgZmlsZSBzeXN0ZW0uClRoaXMgc3RyaW5nIGNhbiBiZSB1c2VkIG1vdmluZyBmb3J3YXJkIHdoZW4geW91IG5lZWQgdG8gcmVmZXIgdG8gdGhlIHBhdGggdG8geW91ciBmaWxlLgpMZXQncyBnbyBhaGVhZCBhbmQgc3RvcmUgdGhpcyBmaWxlIHBhdGggYXMgYSB2YXJpYWJsZSBpbiBvdXIgZW52aXJvbm1lbnQuIAoKYGBge3IgZmlsZS5wYXRoLXZhcmlhYmxlfQpnZW5lX2ZpbGVfcGF0aCA8LSBmaWxlLnBhdGgoImRhdGEiLCAiZ2VuZV9yZXN1bHRzX0dTRTQ0OTcxLnRzdiIpCmBgYAoKTm93IHdlIGFyZSByZWFkeSB0byB1c2UgYHJlYWRfdHN2KClgIHRvIHJlYWQgdGhlIGZpbGUgaW50byBSLgpUaGUgcmVzdWx0aW5nIGRhdGEgZnJhbWUgd2lsbCBiZSBzdG9yZWQgaW4gYSB2YXJpYWJsZSBuYW1lZCBgc3RhdHNfZGZgLgpOb3RlIHRoZSBgPC1gIChhc3NpZ25tZW50IG9wZXJhdG9yISkgaXMgcmVzcG9uc2libGUgZm9yIHNhdmluZyB0aGlzIHRvIG91ciBnbG9iYWwgZW52aXJvbm1lbnQuIAoKYGBge3IgcmVhZC1zdGF0c30KIyByZWFkIGluIHRoZSBmaWxlIGBnZW5lX3Jlc3VsdHNfR1NFNDQ5NzEudHN2YCBmcm9tIHRoZSBkYXRhIGRpcmVjdG9yeQpzdGF0c19kZiA8LSByZWFkX3RzdihnZW5lX2ZpbGVfcGF0aCkKYGBgCgpUYWtlIGEgbG9vayBhdCB5b3VyIGVudmlyb25tZW50IHBhbmVsIHRvIHNlZSB3aGF0IGBzdGF0c19kZmAgbG9va3MgbGlrZS4gCldlIGNhbiBhbHNvIHByaW50IG91dCBhIHByZXZpZXcgb2YgdGhlIGBzdGF0c19kZmAgZGF0YSBmcmFtZSBoZXJlLiAKCmBgYHtyIHNob3ctc3RhdHMsIGxpdmUgPSBUUlVFfQojIGRpc3BsYXkgc3RhdHNfZGYKc3RhdHNfZGYKYGBgCgojIyMgU2Vzc2lvbiBJbmZvCgpBdCB0aGUgZW5kIG9mIGV2ZXJ5IG5vdGVib29rLCB5b3Ugd2lsbCBzZWUgdXMgcHJpbnQgb3V0IGBzZXNzaW9uSW5mb2AuIApUaGlzIGFpZHMgaW4gdGhlIHJlcHJvZHVjaWJpbGl0eSBvZiB5b3VyIGNvZGUgYnkgc2hvd2luZyBleGFjdGx5IHdoYXQgcGFja2FnZXMgCmFuZCB2ZXJzaW9ucyB3ZXJlIGJlaW5nIHVzZWQgdGhlIGxhc3QgdGltZSB0aGUgbm90ZWJvb2sgd2FzIHJ1bi4KCmBgYHtyfQpzZXNzaW9uSW5mbygpCmBgYAo=