Note:

-An R Notebook is an R Markdown document with chunks that can be executed independently and interactively, with output visible immediately beneath the input.

-Notebook output are available as HTML, PDF, Word, or Latex.

-This Notebook as HTML is preferably open with Google Chrome.

-R-Code can be extracted as Rmd file under the button “Code” in the notebook.

-This Notebook using iterative development. It means the process starts with a simple implementation of a small set of idea requirements and iteratively enhances the evolving versions until the complete version is implemented and perfect.

Getting started

#https://rstudio-education.github.io/hopr/

This book are:

  • Teach you how to program in R, with hands-on examples
  • A friendly introduction to the R language
  • Newfound skills to solve practical data science problems
  • Go from loading data to writing your own functions
  • Help you become a data scientist, as well as a computer scientist
  • Focus on the programming skills that are most related to data science
  • Treat R purely as a programming language


==Project 1: Weighted Dice==

Improve your ability as a data scientist:

  • Memorize (store) entire data sets
  • Recall data values on demand
  • Perform complex calculations with large amounts of data
  • Do repetitive tasks without becoming careless or bored

Your first mission is simple: assemble R code that will simulate rolling a pair of dice, like at a craps table. In this project, you will learn how to:

  • Use the R and RStudio interfaces
  • Run R commands
  • Create R objects
  • Write your own R functions and scripts
  • Load and use R packages
  • Generate random samples
  • Create quick plots
  • Get help when you need it

You’ll need to have both R and RStudio installed on your computer before you can use them. Both are free and easy to download. See Appendix A


1. The Very Basics

In it, you will build a pair of virtual dice that you can use to generate random numbers.

The R User Interface:

#https://rstudio-education.github.io/hopr/basics.html#the-r-user-interface

If you do not yet have R and RStudio intalled on your computer-or do not know what I am talking about-visit Appendix A. The appendix will give you an overview of the two free tools and tell you how to download them.

When you type a command at the prompt and hit Enter, your computer executes the command and shows you the results. Then RStudio displays a fresh prompt for your next command. For example, if you type 1 + 1 and hit Enter, RStudio will display:

1 + 1 
[1] 2

You can mostly ignore the numbers that appear in brackets:

100:130 
 [1] 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
[24] 123 124 125 126 127 128 129 130

If you type an incomplete command and press Enter, R will display a + prompt, which means R is waiting for you to type the rest of your command. Either finish the command or hit Escape to start over:

5 -
Error: Incomplete expression: 5 -

If you type a command that R doesn’t recognize, R will return an error message. If you ever see an error message, don’t panic. R is just telling you that your computer couldn’t understand or do what you asked it to do.

3 % 5
Error: unexpected input in "3 % 5"

Once you get the hang of the command line, you can easily do anything in R that you would do with a calculator. For example, you could do some basic arithmetic:

2 * 3
[1] 6
4 - 1
[1] 3
6 / (4 - 1)
[1] 2

____Exercise_The R User Interface:

  1. Choose any number and add 2 to it.
  2. Multiply the result by 3.
  3. Subtract 6 from the answer.
  4. Divide what you get by 3.

Solution:

10 + 2
[1] 12
## 12
12 * 3
[1] 36
## 36
36 - 6
[1] 30
## 30
30 / 3
[1] 10
## 10

Objects:

R lets you save data by storing it inside an R object. What’s an object? Just a name that you can use to call up stored data.

a <- 1 
a
[1] 1
  
die <- 1:6
die
[1] 1 2 3 4 5 6

#https://rstudio-education.github.io/hopr/basics.html#objects

R also understands capitalization (or is case-sensitive), so name and Name will refer to different objects:

Name <- 1 
Name
[1] 1
name <- 0
name  
[1] 0

You can see which object names you have already used with the function ls:

ls() 
[1] "a"    "die"  "name" "Name"

If you are a big fan of linear algebra (and who isn’t?), you may notice that R does not always follow the rules of matrix multiplication. Instead, R uses element-wise execution. When you manipulate a set of numbers, R will apply the same operation to each element in the set. So for example, when you run die - 1, R subtracts one from each element of die.

The result will be a new vector the same length as the first two, as shown in Figure 1-3.


#https://rstudio-education.github.io/hopr/basics.html#objects

If you give R two vectors of unequal lengths, R will repeat the shorter vector until it is as long as the longer vector, and then do the math, as shown in Figure 1-4.


#https://rstudio-education.github.io/hopr/basics.html#objects

But don’t think that R has given up on traditional matrix multiplication. You just have to ask for it when you want it. You can do inner multiplication with the %*% operator and outer multiplication with the %o% operator:

die<-1:8
die
[1] 1 2 3 4 5 6 7 8
die*die  
[1]  1  4  9 16 25 36 49 64
die%*%die
     [,1]
[1,]  204
die%o%die   
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,]    1    2    3    4    5    6    7    8
[2,]    2    4    6    8   10   12   14   16
[3,]    3    6    9   12   15   18   21   24
[4,]    4    8   12   16   20   24   28   32
[5,]    5   10   15   20   25   30   35   40
[6,]    6   12   18   24   30   36   42   48
[7,]    7   14   21   28   35   42   49   56
[8,]    8   16   24   32   40   48   56   64

Functions:

Using a function is pretty simple. Just write the name of the function and then the data you want the function to operate on in parentheses:

round(3.1415) ## 3
[1] 3
factorial(3) ## 6 
[1] 6

The data that you pass into the function is called the function’s argument. The argument can be raw data, an R object, or even the results of another R function. In this last case, R will work from the innermost function to the outermost, as in Figure 1-5:

#https://rstudio-education.github.io/hopr/basics.html#objects

If you’re not sure which names to use with a function, you can look up the function’s arguments with args. To do this, place the name of the function in the parentheses behind args. For example, you can see that the round function takes two arguments, one named x and one named digits:

round(3.444)
[1] 3
  args(round) ## function (x, digits = 0) ## NULL 
function (x, digits = 0) 
NULL

Sample with Replacement:

Sampling with replacement is an easy way to create independent random samples. Each value in your sample will be a sample of size one that is independent of the other values. This is the correct way to simulate a pair of dice:

die<-1:8
sample(die, size = 2, replace = TRUE) 
[1] 5 5
dice <- sample(die, size = 2, replace = TRUE) 
dice 
[1] 8 6
sum(dice) 
[1] 14

What would happen if you call dice multiple times? Would R generate a new pair of dice values each time? Let’s give it a try:

dice 
[1] 4 6
dice 
[1] 4 6
dice 
[1] 4 6

Nope. Each time you call dice, R will show you the result of that one time you called sample and saved the output to dice. R won’t rerun sample(die, 2, replace = TRUE) to create a new roll of the dice. This is a relief in a way. Once you save a set of results to an R object, those results do not change. Programming would be quite hard if the values of your objects changed each time you called them.

Writing Your Own Functions:

To recap, you already have working R code that simulates rolling a pair of dice:

die <- 1:6 
dice <- sample(die, size = 2, replace = TRUE) 
sum(dice) 
[1] 7

It would be easier to use your code if you wrapped it into its own function. Functions may seem mysterious or fancy, but they are just another type of R object. Instead of containing data, they contain code. This code is stored in a special format that makes it easy to reuse the code in new situations. You can write your own functions by recreating this format.

The Function Constructor:

Every function in R has three basic parts:

  1. a name
  2. a body of code, and
  3. a set of arguments

my_function <- function() {}

roll <- function() {  
      die <- 1:6  
      dice <- sample(die, size = 2, replace = TRUE)  
      sum(dice) 
      } 
    roll()
[1] 9
    roll
function() {  
      die <- 1:6  
      dice <- sample(die, size = 2, replace = TRUE)  
      sum(dice) 
      }

Arguments:

 roll2 <- function(bones = 1:6) {  
      dice <- sample(bones, size = 2, replace = TRUE) 
      sum(dice) 
      } 
    
    
    roll2()
[1] 5
    roll2
function(bones = 1:6) {  
      dice <- sample(bones, size = 2, replace = TRUE) 
      sum(dice) 
      }

Finally, you give your function a name by saving its output to an R object, as shown in Figure 2-6.

#https://rstudio-education.github.io/hopr/basics.html#objects

Scripts:

You can open an R script in RStudio by going to File > New File > R script in the menu bar. RStudio will then open a fresh script above your console pane, as shown in Figure 1-7. Figure 1-8.

#https://rstudio-education.github.io/hopr/basics.html#objects
#https://rstudio-education.github.io/hopr/basics.html#objects

Summary:

The two most important components of the R language are

  1. objects, which store data, and

  2. functions, which manipulate data. You’ll also look at two of the most useful components of the R language.

R packages, which are collections of functions writted by R’s talented community of developers, and R documentation, which is a collection of help pages built into R that explains every function and data set in the language.

2. Packages and Help Pages

Many of the most useful R tools come in R packages, so let’s take a moment to look at what R packages are and how you can use them.

Packages:

You’re not the only person writing your own functions with R. Many professors, programmers, and statisticians use R to design tools that can help people analyze data. They then make these tools free for anyone to use. Appendix 2: R Packages contains detailed instructions for downloading and updating R packages.

We’re going to use the qplot function to make some quick plots. qplot comes in the ggplot2 package, a popular package for making graphs. Before you can use qplot, or anything else in the ggplot2 package, you need to download and install it.

Install.packages:

Each R package is hosted at http://cran.r-project.org, the same website that hosts R. However, you don’t need to visit the website to download an R package; You can download packages straight from R’s command line in RStudio.

Here’s how:

  1. Open RStudio.
  2. Make sure you are connected to the Internet.
  3. Run install.packages("ggplot2") at the command line.

library:

Installing a package doesn’t place its functions at your fingertips just yet: It simply places them in your hard drive. To use an R package, you next have to load it in your R session with the command library("ggplot2").

The main thing to remember is that you only need to install a package once, but you need to load it with library each time you wish to use it in a new R session. R will unload all of its packages each time you close RStudio.

The following code will make the plot that appears in Figure 2-1.

x <- c(-1, -0.8, -0.6, -0.4, -0.2, 0, 0.2, 0.4, 0.6, 0.8, 1)
x
 [1] -1.0 -0.8 -0.6 -0.4 -0.2  0.0  0.2  0.4  0.6  0.8  1.0
## -1.0 -0.8 -0.6 -0.4 -0.2  0.0  0.2  0.4  0.6  0.8  1.0
y <- x^3
y
 [1] -1.000 -0.512 -0.216 -0.064 -0.008  0.000  0.008  0.064  0.216  0.512  1.000
## -1.000 -0.512 -0.216 -0.064 -0.008  0.000  0.008
##  0.064  0.216  0.512  1.000
qplot(x, y)

#https://rstudio-education.github.io/hopr/basics.html#objects

Give c all of the numbers that you want to appear in the vector, separated by a comma. c stands for concatenate, but you can think of it as “collect” or “combine”:

x <- c(-1, -0.8, -0.6, -0.4, -0.2, 0, 0.2, 0.4, 0.6, 0.8, 1) 
x ## -1.0 -0.8 -0.6 -0.4 -0.2  0.0  0.2  0.4  0.6  0.8  1.0
 [1] -1.0 -0.8 -0.6 -0.4 -0.2  0.0  0.2  0.4  0.6  0.8  1.0
y <- x^3 
y ## -1.000 -0.512 -0.216 -0.064 -0.008  0.000  0.008 ##  0.064  0.216  0.512  1.000
 [1] -1.000 -0.512 -0.216 -0.064 -0.008  0.000  0.008  0.064  0.216  0.512  1.000
plot(x, y)

The following code makes the left-hand plot in Figure 2-2 (we’ll worry about the right-hand plot in just second). To make sure our graphs look the same, use the extra argument binwidth = 1:

#https://rstudio-education.github.io/hopr/basics.html#objects
x <- c(1, 2, 2, 2, 3, 3) 
hist(x, binwidth = 1)

Let’s try another histogram. This code makes the right-hand plot in Figure 2-2.

x2 <- c(1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4) 
plot(x2, binwidth = 1)

Exercise_1:

Let x3 be the following vector:

x3 <- c(0, 1, 1, 2, 2, 2, 3, 3, 4)
x3
[1] 0 1 1 2 2 2 3 3 4
  • Imagine what a histogram of x3 would look like.
  • Assume that the histogram has a bin width of 1.
  • How many bars will the histogram have?
  • Where will they appear?
  • How high will each be? When you are done, plot a histogram of x3 with binwidth = 1, and see if you are right.

How can you use a histogram to check the accuracy of your dice? Well, if you roll your dice many times and keep track of the results, you would expect some numbers to occur more than others. This is because there are more ways to get some numbers by adding two dice together than to get other numbers, as shown in Figure 2-3.

#https://rstudio-education.github.io/hopr/basics.html#objects

This is where replicate comes in. Replicate provides an easy way to repeat an R command many times. To use it, first give replicate the number of times you wish to repeat an R command, and then give it the command you wish to repeat. Replicate will run the command multiple times and store the results as a vector:

roll <- function() {  
      die <- 1:6  
      dice <- sample(die, size = 2, replace = TRUE)  
      sum(dice) 
      } 
replicate(3, 1 + 1) 
[1] 2 2 2
replicate(10, roll()) 
 [1]  7 11  7 11  5  6  8  4 10  6
  

So let’s simulate 10,000 dice rolls and plot the results. Don’t worry; qplot and replicate can handle it. Figure 2-4:

#https://rstudio-education.github.io/hopr/basics.html#objects
roll <- function() {  
    die <- 1:6  
    dice <- sample(die, size = 2, replace = TRUE)  
    sum(dice) 
  } 
  rolls <- replicate(10, roll()) 
  hist(rolls, binwidth = 1) 

rolls
 [1] 8 8 4 3 6 7 8 8 7 3

See Appendix B and Appendix C

Getting Help with Help Pages:

There are over 1,000 functions at the core of R, and new R functions are created all of the time. This can be a lot of material to memorize and learn! Luckily, each R function comes with its own help page, which you can access by typing the function’s name after.

?sqrt
?log10 
?sample

Here, almost every help page includes some example code that puts the function in action. Running this code is a great way to learn by example.

Note: If a function comes in an R package, R won’t be able to find its help page unless the package is loaded.

Parts of a Help Page:

Each help page is divided into sections. Which sections appear can vary from help page to help page, but you can usually expect to find these useful topics:

  • -Description
  • -Usage
  • -Arguments
  • -Details
  • -Value

If you’d like to look up the help page for a function but have forgotten the function’s name, you can search by keyword.

To do this, type two question marks followed by a keyword in R’s command line. R will pull up a list of links to help pages related to the keyword. You can think of this as the help page for the help page:

??log

Exercise_2:

Rewrite the roll function to roll a pair of weighted dice:

roll <- function() {  
    die <- 1:6  
    dice <- sample(die, size = 2, replace = TRUE)  
    sum(dice) 
    } 

You will need to add a prob argument to the sample function inside of roll. This argument should tell sample to sample the numbers one through five with probability 1/8 and the number 6 with probability 3/8.

roll <- function() {  
       die <- 1:6  
       dice <- sample(die, size = 2, replace = TRUE,    prob = c(1/8, 1/8, 1/8, 1/8, 1/8, 3/8))  
       
       sum(dice) 
       } 
roll()
[1] 7

This will cause roll to pick 1 through 5 with probability 1/8 and 6 with probability 3/8.

rolls <- replicate(10000, roll()) 
hist(rolls, binwidth = 1)

#https://rstudio-education.github.io/hopr/basics.html#objects

Getting More Help:

  • R also comes with a super active community of users that you can turn to for help on the R-help mailing list. https://community.rstudio.com/

  • You can email the list with questions, but there’s a great chance that your question has already been answered.

  • Find out by searching the archives.

Even better than the R-help list is Stack Overflow, a website that allows programmers to answer questions and users to rank answers based on helpfulness.

Summary:

  • R’s packages and help pages can make you a more productive programmer.

  • Often the function that you want to write will already exist in an R package.

  • install.packages, and then load it into each new R session with library for using package.

  • R’s help pages will help you master the functions that appear in R and its packages.

==Project 2: Playing Cards==

How to store, retrieve, and change data values in your computer’s memory. These skills will help you save and manage data without accumulating errors.

Along the way, you will learn how to:

  • Save new types of data, like character strings and logical values
  • Save a data set as a vector, matrix, array, list, or data frame
  • Load and save your own data sets with R
  • Extract individual values from a data set
  • Change individual values within a data set
  • Write logical tests
  • Use R’s missing-value symbol, NA

We’ve divided it into four tasks. Each task will teach you a new skill for managing data with R:

Task 1: build the deck In R Objects, you will design and build a virtual deck of playing cards. This will be a complete data set, just like the ones you will use as a data scientist. You’ll need to know how to use R’s data types and data structures to make this work.

Task 2: write functions that deal and shuffle Next, in R Notation, you will write two functions to use with the deck. One function will deal cards from the deck, and the other will reshuffle the deck. To write these functions, you’ll need to know how to extract values from a data set with R.

Task 3: change the point system to suit your game In Modifying Values, you will use R’s notation system to change the point values of your cards to match the card games you may wish to play, like war, hearts, or blackjack. This will help you change values in place in existing data sets.

Task 4: manage the state of the deck Finally, in Environments, you will make sure that your deck remembers which cards it has dealt. This is an advanced task, and it will introduce R’s environment system and scoping rules. To do it successfully, you will need to learn the minute details of how R looks up and uses the data that you have stored in your computer.

3. R Objects

Atomic Vectors:

You can make an atomic vector by grouping some values of data together with c:

die <- c(1, 2, 3, 4, 5, 6) 
die
[1] 1 2 3 4 5 6
is.vector(die) 
[1] TRUE
#is.vector tests whether an object is an atomic vector. 
#It returns TRUE if the object is an atomic vector and FALSE otherwise.

You can also make an atomic vector with just one value. R saves single values as an atomic vector of length 1:

five <- 5 
five ## 5
[1] 5
is.vector(five) 
[1] TRUE
##  TRUE
length(five) 
[1] 1
## 1 
length(die) 
[1] 6
## 6
#!!!length returns the length of an atomic vector.

Each atomic vector stores its values as a one-dimensional vector, and each atomic vector can only store one type of data. You can save different types of data in R by using different types of atomic vectors. Altogether, R recognizes six basic types of atomic vectors: doubles, integers, characters, logicals, complex, and raw.

You can do this by using some simple conventions when you enter your data. For example, you can create an integer vector by including a capital L with your input. You can create a character vector by surrounding your input in quotation marks:

int <- 1L 
int
[1] 1
text <- "ace" 
text
[1] "ace"

If you’d like to make atomic vectors that have more than one element in them, you can combine an element with the c function.

int <- c(1L, 5L) 
text <- c("ace", "hearts") 
  

You may wonder why R uses multiple types of vectors. Vector types help R behave as you would expect. For example, R will do math with atomic vectors that contain numbers, but not with atomic vectors that contain character strings:

sum(int) ## 6
[1] 6
sum(text) ## Error in sum(text) : invalid 'type' (character) of argument 
Error in sum(text) : invalid 'type' (character) of argument

But we’re getting ahead of ourselves! Get ready to say hello to the six types of atomic vectors in R.

  • 1-Doubles
die <- c(1, 2, 3, 4, 5, 6) 
die ## 1 2 3 4 5 6 
[1] 1 2 3 4 5 6
typeof(die) ##  "double" 
[1] "double"
    
  • 2-Integers
int <- c(-1L, 2L, 4L) 
    int ## -1  2  4
[1] -1  2  4
    typeof(int) ## "integer" 
[1] "integer"
  • 3-Characters
text <- c("Hello",  "World") 
    text ##  "Hello"  "World"
[1] "Hello" "World"
    typeof(text) ## "character"
[1] "character"
    typeof("Hello") ## "character" 
[1] "character"
  • 4-Logicals
3 > 4 
[1] FALSE
    ## FALSE 
    
    logic <- c(TRUE, FALSE, TRUE) 
    logic ##   TRUE FALSE  TRUE
[1]  TRUE FALSE  TRUE
    typeof(logic) ## "logical"
[1] "logical"
    typeof(F) ## "logical" 
[1] "logical"
    
  • 5-Complex
x <- 1
y <- 1
 
comp<- complex(real = x, imaginary = y)
 
typeof(comp) ## "complex" 
[1] "complex"
    
  • 6-Raw

Raw vectors store raw bytes of data. Making raw vectors gets complicated, but you can make an empty raw vector of length n with raw(n). See the help page of raw for more options when working with this type of data:

#Raw vectors store raw bytes of data. Making raw vectors gets complicated, 
    #but you can make an empty raw vector of length n with raw(n). 
    #See the help page of raw for more options when working with this type of data:
    
    raw(3) 
[1] 00 00 00
      ## 00 00 00
    typeof(raw(3))
[1] "raw"
    ## "raw"
  • Exercise

Create an atomic vector that stores just the face names of the cards in a royal flush, for example, the ace of spades, king of spades, queen of spades, jack of spades, and ten of spades. The face name of the ace of spades would be “ace,” and “spades” is the suit. Which type of vector will you use to save the names?

hand <- c("ace", "king", "queen", "jack", "ten") 
    hand 
[1] "ace"   "king"  "queen" "jack"  "ten"  
    ## "ace"   "king"  "queen" "jack"  "ten"
    typeof(hand)
[1] "character"
    ## "character" 

Attributes:

You can think of an attribute as “metadata”; it is just a convenient place to put information associated with an object.

die <- c(1, 2, 3, 4, 5, 6) 
attributes(die)
NULL
  ## NULL

The most common attributes to give an atomic vector are names, dimensions (dim), and classes.

Note: R uses NULL to represent the null set, an empty object. NULL is often returned by functions whose values are undefined. You can create a NULL object by typing NULL in capital letters.

  • Names:
die <- c(1, 2, 3, 4, 5, 6) 
names(die) ## NULL 
NULL
names(die) <- c("one", "two", "three", "four", "five", "six") 
names(die) ## "one"   "two"   "three" "four"  "five"  "six"
[1] "one"   "two"   "three" "four"  "five"  "six"  
attributes(die)
$names
[1] "one"   "two"   "three" "four"  "five"  "six"  
  

R will display the names above the elements of die whenever you look at the vector:

 die
  one   two three  four  five   six 
    1     2     3     4     5     6 

To remove the names attribute, set it to NULL:

names(die) <- NULL 
  die 
[1] 1 2 3 4 5 6
  • Dim:

You can transform an atomic vector into an n-dimensional array by giving it a dimensions attribute with dim.

die <- c(1, 2, 3, 4, 5, 6)  
  dim(die) <- c(2, 3) 
die   
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6
    
dim(die) <- c(3, 2) 
die 
     [,1] [,2]
[1,]    1    4
[2,]    2    5
[3,]    3    6
  
dim(die) <- c(1, 2, 3)
die
, , 1

     [,1] [,2]
[1,]    1    2

, , 2

     [,1] [,2]
[1,]    3    4

, , 3

     [,1] [,2]
[1,]    5    6

For example, R always fills up each matrix by columns, instead of by rows. If you’d like more control over this process, you can use one of R’s helper functions, matrix or array. They do the same thing as changing the dim attribute, but they provide extra arguments to customize the process.

Matrices:

die <- c(1, 2, 3, 4, 5, 6)
m <- matrix(die, nrow = 2) 
m 
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6

Matrix will fill up the matrix column by column by default, but you can fill the matrix row by row if you include the argument byrow = TRUE:

mm <- matrix(die, nrow = 2, byrow = TRUE) 
mm
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    4    5    6

Arrays:

The array function creates an n-dimensional Matrix.

ar <- array(c(11:14, 21:24, 31:34), dim = c(2, 2, 3)) 
ar
, , 1

     [,1] [,2]
[1,]   11   13
[2,]   12   14

, , 2

     [,1] [,2]
[1,]   21   23
[2,]   22   24

, , 3

     [,1] [,2]
[1,]   31   33
[2,]   32   34

Exercise:

Create the following matrix, which stores the name and suit of every card in a royal flush.

hand1 <- c("ace", "king", "queen", "jack", "ten", "spades", "spades",  "spades", "spades", "spades")
matrix(hand1, nrow = 5) 
     [,1]    [,2]    
[1,] "ace"   "spades"
[2,] "king"  "spades"
[3,] "queen" "spades"
[4,] "jack"  "spades"
[5,] "ten"   "spades"
matrix(hand1, ncol = 2) 
     [,1]    [,2]    
[1,] "ace"   "spades"
[2,] "king"  "spades"
[3,] "queen" "spades"
[4,] "jack"  "spades"
[5,] "ten"   "spades"
dim(hand1) <- c(5, 2) 
hand1
     [,1]    [,2]    
[1,] "ace"   "spades"
[2,] "king"  "spades"
[3,] "queen" "spades"
[4,] "jack"  "spades"
[5,] "ten"   "spades"
test<-matrix(hand1,nrow=5, ncol=2)
test
     [,1]    [,2]    
[1,] "ace"   "spades"
[2,] "king"  "spades"
[3,] "queen" "spades"
[4,] "jack"  "spades"
[5,] "ten"   "spades"

Class:

class("Hello")
[1] "character"
##  "character"
class(5) ##  
[1] "numeric"
"numeric" 
[1] "numeric"
  • Dates and Times:
now <- Sys.time() 
now
[1] "2019-04-14 11:35:59 CEST"
typeof(now) ##  "double"
[1] "double"
class(now) ## "POSIXct" "POSIXt" 
[1] "POSIXct" "POSIXt" 
  • Factors:

Factors are R’s way of storing categorical information, like ethnicity or eye color. Think of a factor as something like a gender; it can only have certain values (male or female).

gender <- factor(c("male", "female", "female", "male"))
gender
[1] male   female female male  
Levels: female male
typeof(gender) 
[1] "integer"
attributes(gender) 
$levels
[1] "female" "male"  

$class
[1] "factor"

You can see exactly how R is storing your factor with unclass:

gender <- factor(c("male", "female", "female", "male"))
unclass(gender)
[1] 2 1 1 2
attr(,"levels")
[1] "female" "male"  
gender
[1] male   female female male  
Levels: female male

Factors make it easy to put categorical variables into a statistical model because the variables are already coded as numbers. However, factors can be confusing since they look like character strings but behave like integers.

gender <- factor(c("male", "female", "female", "male"))
as.character(gender) 
[1] "male"   "female" "female" "male"  

Exercise:

Many card games assign a numerical value to each card. For example, in blackjack, each face card is worth 10 points, each number card is worth between 2 and 10 points, and each ace is worth 1 or 11 points, depending on the final score. Make a virtual playing card by combining “ace,” “heart,” and 1 into a vector. What type of atomic vector will result? Check if you are right.

You can convert a factor to a character string with the as.character function. R will retain the display version of the factor, not the integers stored in memory:

card <- c("ace", "hearts", 1) 
card 

This will cause trouble if you want to do math with that point value, for example, to see who won your game of blackjack. Since matrices and arrays are special cases of atomic vectors, they suffer from the same behavior. Each can only store one type of data. This creates a couple of problems. First, many data sets contain multiple types of data. Simple programs like Excel and Numbers can save multiple types of data in the same data set, and you should hope that R can too. Don’t worry, it can.

Coercion:

Figure 3-1.

R uses the same coercion rules when you try to do math with logical values. So the following code:

sum(c(TRUE, TRUE, FALSE, FALSE)) 
[1] 2
#will become:
sum(c(1, 1, 0, 0)) 
[1] 2

You can explicitly ask R to convert data from one type to another with the as functions. R will convert the data whenever there is a sensible way to do so:

as.character(1) 
[1] "1"
  ## "1"
as.logical(1) 
[1] TRUE
  ## TRUE
as.numeric(FALSE) 
[1] 0
  ## 0 

Lists:

Lists are like atomic vectors because they group data into a one-dimensional set. However, lists do not group together individual values; lists group together R objects, such as atomic vectors and other lists.

list1 <- list(100:130, "R", list(TRUE, FALSE)) 
print(list1)
[[1]]
 [1] 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
[24] 123 124 125 126 127 128 129 130

[[2]]
[1] "R"

[[3]]
[[3]][[1]]
[1] TRUE

[[3]][[2]]
[1] FALSE

Exercise:

Use a list to store a single playing card, like the ace of hearts, which has a point value of one. The list should save the face of the card, the suit, and the point value in separate elements.

card <- list("ace", "hearts", 1) 
print(card)
[[1]]
[1] "ace"

[[2]]
[1] "hearts"

[[3]]
[1] 1

Data Frames:

You can think of a data frame as R’s equivalent to the Excel spreadsheet because it stores data in a similar format. Data frames group vectors together into a two-dimensional table. Each vector becomes a column in the table. As a result, each column of a data frame can contain a different type of data; but within a column, every cell must be the same type of data, as in Figure 3-2.

df <- data.frame(face = c("ace", "two", "six"),  suit = c("clubs", "clubs", "clubs"), value = c(1, 2, 3)) 
df

In fact, each data frame is a list with class data.frame.

typeof(df)
[1] "list"
class(df) 
[1] "data.frame"
str(df) 
'data.frame':   3 obs. of  3 variables:
 $ face : Factor w/ 3 levels "ace","six","two": 1 3 2
 $ suit : Factor w/ 1 level "clubs": 1 1 1
 $ value: num  1 2 3

Notice that R saved your character strings as factors. R likes factors! It is not a very big deal here, but you can prevent this behavior by adding the argument stringsAsFactors = FALSE to data.frame:

df <- data.frame(face = c("ace", "two", "six"),  suit = c("clubs", "clubs", "clubs"), value = c(1, 2, 3),  stringsAsFactors = FALSE) 
df

You should avoid typing large data sets in by hand whenever possible. Typing invites typos and errors, not to mention RSI. It is always better to acquire large data sets as a computer file. You can then ask R to read the file and store the contents as an object.

Loading Data:

Dataset: https://gist.github.com/garrettgman/9629323

  • Most data-science applications can open plain-text files and export data as plain-text files.
  • This makes plain-text files a sort of lingua franca for data science.
  • To load a plain-text file into R, click the Import Dataset icon in RStudio, shown in Figure 3-3.
  • Then select “From text file.”

RStudio will ask you to select the file you want to import, then it will open a wizard to help you import the data, as in Figure 3-4. You can also unclick the box “Strings as factors” in the wizard. I recommend doing this. If you do, R will load all of your character strings as character strings. If you do not, R will convert them to factors.

deck
class(deck)
[1] "data.frame"

Once everything looks right, click Import. RStudio will read in the data and save it to a data frame. RStudio will also open a data viewer, so you can see your new data in a spreadsheet format. This is a good way to check that everything came through as expected.

Saving Data:

You can save any data frame in R to a .csv file with the command write.csv. To save deck, run:

`write.csv(deck, file = “cards.csv”, row.names = FALSE)``

R will turn your data frame into a plain-text file with the comma-separated values format and save the file to your working directory. To see where your working directory is, run getwd().

getwd()
[1] "C:/Users/cevi herdian/Documents/MEGA/Data-Sciences/R Programming/tutorial/Hands On Programming with R/Github/hopr"
  

To change the location of your working directory, visit Session > Set Working Directory > Choose Directory in the RStudio menu bar.

Summary:

You can save data in R with five different objects, which let you store different types of values in different types of relationships, as in Figure 3-6. Data frames store one of the most common forms of data used in data science, tabular data. You can load tabular data into a data frame with RStudio’s Import Dataset button-so long as the data is saved as a plain-text file. No program is better at converting Excel files than Excel. Similarly, no program is better at converting SAS Xport files than SAS, and so on.

  • 6 types R atomic vectors:
  1. Integers
  2. Double
  3. Logic
  4. Characters
  5. Complexs
  6. Raw
  • 5 R objects:
  1. Vectors
  2. Matrix
  3. Arrays
  4. List
  5. Data Frame

See the Appendix D

4. R Notation

Selecting Values:

First of all, import the deck.csv. To extract a value or set of values from a data frame, write the data frame’s name followed by a pair of hard brackets:

deck
class(deck)
[1] "data.frame"
deck[ , ]

You have a choice when it comes to writing indexes. There are six different ways to write an index for R, and each does something slightly different.

  1. Positive integers
  2. Negative integers
  3. Zero
  4. Blank spaces
  5. Logical values
  6. Names

The simplest of these to use is positive integers.

  1. Positive Integers

R treats positive integers just like ij notation in linear algebra: deck[i,j] will return the value of deck that is in the ith row and the jth column, Figure 4-1.

deck[1, 1]
[1] king
Levels: ace eight five four jack king nine queen seven six ten three two

To extract more than one value, use a vector of positive integers. For example, you can return the first row of deck with deck[1, c(1, 2, 3)] or deck[1, 1:3]:

deck[1, c(1, 2, 3)] 

R will give you a new set of values which are copies of the original values. You can then save this new set to an R object with R’s assignment operator:

new <- deck[1, c(1, 2, 3)] 
new 

R’s notation system is not limited to data frames. You can use the same syntax to select values in any R object, as long as you supply one index for each dimension of the object. So, for example, you can subset a vector (which has one dimension) with a single index:

vec <- c(6, 1, 3, 6, 10, 5)
vec[1:3]
[1] 6 1 3
  1. Negative Integers

Negative integers do the exact opposite of positive integers when indexing. R will return every element except the elements in a negative index.

deck[-(2:52), 1:3] 

Negative integers are a more efficient way to subset than positive integers if you want to include the majority of a data frame’s rows or columns.

  1. Zero

R will return nothing from a dimension when you use zero as an index. This creates an empty object:

deck[0, 0] 

data frame with 0 columns and 0 rows To be honest, indexing with zero is not very helpful.

  1. Blank Spaces

You can use a blank space to tell R to extract every value in a dimension.

deck[1, ] 
  1. Logical Values

If you supply a vector of TRUEs and FALSEs as your index, R will match each TRUE and FALSE to a row in your data frame (or a column depending on where you place the index). R will then return each row that corresponds to a TRUE, Figure 4-2.

deck[1, c(TRUE, TRUE, FALSE)] 
  1. Names

Finally, you can ask for the elements you want by name-if your object has names.

deck[1, c("face", "suit", "value")]

Deal a Card:

Complete the following code to make a function that returns the first row of a data frame:

deal <- function(cards) {  
    cards[1, ] 
    } 
  
  deal(deck)

Shuffle the Deck:

deck2 <- deck[1:52, ]
  deck2
  
  head(deck2) 
  
  
  deck3 <- deck[c(2, 1, 3:52), ]
  deck3  

How could you generate such a random collection of integers? With our friendly neighborhood sample function:

random <- sample(1:52, size = 52) 
  random 
 [1] 33 38 48 47 36  5 28  6  2 10 31  4 16 19 39 18  8 52 15 34 23 12  7 42 43 30 14 13 32 40 17
[32] 25 35  3 51 44 26 29 49  9  1 20 21 22 24 37 46 45 41 11 27 50
  
  
  
  deck4 <- deck[random, ] 
  head(deck4)

Exercise:

Use the preceding ideas to write a shuffle function. Shuffle should take a data frame and return a shuffled copy of the data frame. Your shuffle function will look like the one that follows:

shuffle <- function(cards) {  
    random <- sample(1:52, size = 52)  
    cards[random, ] 
    } 
  
  
  deal(deck)
  deck2 <- shuffle(deck)
  deal(deck2)

Dollar Signs and Double Brackets:

Two types of object in R obey an optional second system of notation. You can extract values from data frames and lists with the $ syntax.

deck$value 
 [1] 13 12 11 10  9  8  7  6  5  4  3  2  1 13 12 11 10  9  8  7  6  5  4  3  2  1 13 12 11 10  9
[32]  8  7  6  5  4  3  2  1 13 12 11 10  9  8  7  6  5  4  3  2  1
mean(deck$value) 
[1] 7
median(deck$value)
[1] 7

You can use the same $ notation with the elements of a list, if they have names.

lst <- list(numbers = c(1, 2), logical = TRUE, strings = c("a", "b", "c")) 
lst 
$numbers
[1] 1 2

$logical
[1] TRUE

$strings
[1] "a" "b" "c"

And then subset it:

lst[1] 
$numbers
[1] 1 2
lst$numbers 
[1] 1 2
lst[[1]] 
[1] 1 2
lst[["numbers"]] 
[1] 1 2
  

In the R community, there is a popular, and helpful, way to think about it, Figure 4-3.

Summary:

You have learned how to access values that have been stored in R. You can retrieve a copy of values that live inside a data frame and use the copies for new computations.

5. Modifying Values

Changing Values in Place:

vec <- c(0, 0, 0, 0, 0, 0) 
vec
[1] 0 0 0 0 0 0

Here’s how you can select the first value of vec:

vec[1]
[1] 0

And here is how you can modify it:

vec[1] <- 1000
vec 
[1] 1000    0    0    0    0    0

You can replace multiple values at once as long as the number of new values equals the number of selected values:

vec[c(1, 3, 5)] <- c(1, 1, 1) 
vec
[1] 1 0 1 0 1 0
vec[4:6] <- vec[4:6] + 1
vec 
[1] 1 0 1 2 3 2

This provides a great way to add new variables to your data set: firts import the deck.csv

deck
deck2<-deck
deck2$new <- 1:52
deck2

You can also remove columns from a data frame (and elements from a list) by assigning them the symbol NULL:

deck2$new <- NULL
  head(deck2)

You can single out just the values of the aces by subsetting the columns dimension of deck2. Or, even better, you can subset the column vector deck2$value:

deck2[c(13, 26, 39, 52), 3]
[1] 1 1 1 1
deck2$value[c(13, 26, 39, 52)]
[1] 1 1 1 1

Now all you have to do is assign a new set of values to these old values.

deck2$value[c(13, 26, 39, 52)] <- c(14, 14, 14, 14)
  # or
  deck2$value[c(13, 26, 39, 52)] <- 14
  deck2  

Logical Subsetting:

vec <- c(1, 0, 1, 1, 0, 2) 
vec
[1] 1 0 1 1 0 2
vec[c(FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE)] 
[1] 0

At first glance, this system might seem impractical. Who wants to type out long vectors of TRUEs and FALSEs? No one. But you don’t have to. You can let a logical test create a vector of TRUEs and FALSEs for you.

Logical Tests:

A logical test is a comparison like “is one less than two?”, 1 < 2, or “is three greater than four?”, 3 > 4. R provides seven logical operators that you can use to make comparisons, shown in Table 7-1 and Table 7-2.

Each operator returns a TRUE or a FALSE. If you use an operator to compare vectors, R will do element-wise comparisons-just like it does with the arithmetic operators:

1 > 2 
[1] FALSE
1 > c(0, 1, 2) 
[1]  TRUE FALSE FALSE
c(1, 2, 3) == c(3, 2, 1) 
[1] FALSE  TRUE FALSE

%in% is the only operator that does not do normal element-wise execution. %in% tests whether the value(s) on the left side are in the vector on the right side.

1 %in% c(3, 4, 5) 
[1] FALSE
c(1, 2) %in% c(3, 4, 5) 
[1] FALSE FALSE
c(1, 2, 3) %in% c(3, 4, 5)
[1] FALSE FALSE  TRUE
c(1, 2, 3, 4) %in% c(3, 4, 5)
[1] FALSE FALSE  TRUE  TRUE

Notice that you test for equality with a double equals sign, ==, and not a single equals sign, =, which is another way to write <-. You can compare any two R objects with a logical operator; however, logical operators make the most sense if you compare two objects of the same data type. If you compare objects of different data types, R will use its coercion rules to coerce the objects to the same type before it makes the comparison.

Missing Information:

Missing information problems happen frequently in data science. The NA character is a special symbol in R. It stands for “not available” and can be used as a placeholder for missing information. Generally, NAs will propagate whenever you use them in an R operation or function. This can save you from making errors based on missing data.

  • na.rm:

Missing values can help you work around holes in your data sets, but they can also create some frustrating problems. Suppose, for example, that you’ve collected 1,000 observations and wish to take their average with R’s mean function. If even one of the values is NA, your result will be NA:

c(NA, 1:50) 
 [1] NA  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
[32] 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
mean(c(NA, 1:50)) 
[1] NA

Understandably, you may prefer a different behavior. Most R functions come with the optional argument, na.rm, which stands for NA remove. R will ignore NAs when it evaluates a function if you add the argument na.rm = TRUE:

mean(c(NA, 1:50), na.rm = TRUE) 
[1] 25.5
  • is.na:

On occasion, you may want to identify the NAs in your data set with a logical test, but that too creates a problem. How would you go about it? If something is a missing value, any logical test that uses it will return a missing value, even this test:

NA == NA
[1] NA

Which means that tests like this won’t help you find missing values:

c(1, 2, 3, NA) == NA 
[1] NA NA NA NA

But don’t worry too hard; R supplies a special function that can test whether a value is an NA. The function is sensibly named is.na:

is.na(NA) ## TRUE
[1] TRUE
vec <- c(1, 2, 3, NA)
is.na(vec)
[1] FALSE FALSE FALSE  TRUE

Let’s set all of your ace values to NA. This will accomplish two things. First, it will remind you that you do not know the final value of each ace. Second, it will prevent you from accidentally scoring a hand that has an ace before you determine the ace’s final value.

deck5<-deck
deck5$value[deck5$face == "ace"] <- NA
deck5

Summary:

You can modify values in place inside an R object when you combine R’s notation syntax with the assignment operator, <-. This lets you update your data and clean your data sets.

6. Environments-X

Environments:

For example, Figure 8.1 shows part of the file system on my computer. I have tons of folders. Inside one of them is a subfolder named Documents, inside of that subfolder is a sub-subfolder named ggsubplot, inside of that folder is a folder named inst, inside of that is a folder named doc, and inside of that is a file named manual.pdf.

R uses a similar system to save R objects. Each object is saved inside of an environment, a list-like object that resembles a folder on your computer. Each environment is connected to a parent environment, a higher-level environment, which creates a hierarchy of environments.

You can see R’s environment system with the parenvs function in the pryr package (note parenvs came in the pryr package when this book was first published). parenvs(all = TRUE) will return a list of the environments that your R session is using.

library(pryr)
parenvs(all = TRUE)

It takes some imagination to interpret this output, so let’s visualize the environments as a system of folders, Figure 8.2.

Working with Environments:

R comes with some helper functions that you can use to explore your environment tree.

as.environment("package:stats")
<environment: package:stats>
attr(,"name")
[1] "package:stats"
attr(,"path")
[1] "C:/Program Files/R/R-3.5.3/library/stats"

Three environments in your tree also come with their own accessor functions.

globalenv()
<environment: R_GlobalEnv>
## <environment: R_GlobalEnv>
baseenv()
<environment: base>
## <environment: base>
emptyenv()
<environment: R_EmptyEnv>
##<environment: R_EmptyEnv>

Next, you can look up an environment’s parent with parent.env:

parent.env(globalenv())
<environment: package:pryr>
attr(,"name")
[1] "package:pryr"
attr(,"path")
[1] "C:/Users/cevi herdian/Documents/R/win-library/3.5/pryr"

You can view the objects saved in an environment with ls or ls.str.

ls(globalenv())
[1] "a"     "b"     "c"     "data"  "deck"  "poker" "stuff"

You can use R’s $ syntax to access an object in a specific environment. For example, you can access deck from the global environment:

head(globalenv()$deck, 3)

And you can use the assign function to save an object into a particular environment.

assign("new", "Hello Global", envir = globalenv())
globalenv()$new
[1] "Hello Global"
  • The Active Environment

At any moment of time, R is working closely with a single environment. R will store new objects in this environment (if you create any), and R will use this environment as a starting point to look up existing objects (if you call any).

environment()
<environment: R_GlobalEnv>

The global environment plays a special role in R. It is the active environment for every command that you run at the command line. As a result, any object that you create at the command line will be saved in the global environment. You can think of the global environment as your user workspace.

When you call an object at the command line, R will look for it first in the global environment. But what if the object is not there? In that case, R will follow a series of rules to look up the object.

Scoping Rules:

R follows a special set of rules to look up objects. These rules are known as R’s scoping rules:

  1. R looks for objects in the current active environment.
  2. When you work at the command line, the active environment is the global environment. Hence, R looks up objects that you call at the command line in the global environment as in Figure 8.3.

Assignment:

When you assign a value to an object, R saves the value in the active environment under the object’s name. If an object with the same name already exists in the active environment, R will overwrite it.

new
[1] "Hello Global"
new <- "Hello Active"
new
[1] "Hello Active"

This arrangement creates a quandary for R whenever R runs a function. Many functions save temporary objects that help them do their jobs.

roll <- function() {
  die <- 1:6
  dice <- sample(die, size = 2, replace = TRUE)
  sum(dice)
}
roll()
[1] 9

Evaluation:

R creates a new environment each time it evaluates a function. R will use the new environment as the active environment while it runs the function, and then R will return to the environment that you called the function from, bringing the function’s result with it.

We want to know what the environments look like: what are their parent environments, and what objects do they contain? show_env is designed to tell us:

show_env <- function(){
  list(ran.in = environment(), 
    parent = parent.env(environment()), 
    objects = ls.str(environment()))
}

show_env is itself a function, so when we call show_env(), R will create a runtime environment to evaluate the function in.

show_env()
$ran.in
<environment: 0x000000000a0831e0>

$parent
<environment: R_GlobalEnv>

$objects

This time show_env ran in a new environment, 0x000000000a0831e0

==Project 3: Slot Machine==

7. Programs-X

The following function generates three symbols from a group of common slot machine symbols

get_symbols <- function() {
  wheel <- c("DD", "7", "BBB", "BB", "B", "C", "0")
  sample(wheel, size = 3, replace = TRUE, 
    prob = c(0.03, 0.03, 0.06, 0.1, 0.25, 0.01, 0.52))
}
get_symbols()
[1] "0"   "0"   "BBB"

get_symbols uses the probabilities observed in a group of video lottery terminals from Manitoba, Canada. The Manitoba slot machines use the complicated payout scheme shown in Table 9.1. A player will win a prize if he gets:

  1. Three of the same type of symbol (except for three zeroes)
  2. Three bars (of mixed variety)
  3. One or more cherries
  • Sequential Steps

To have R execute steps in sequence, place the steps one after another in an R script or function body. See Figure 9.1

  • Parallel Cases

Another way to divide a task is to spot groups of similar cases within the task. Some tasks require different algorithms for different groups of input. If you can identify those groups, you can work out their algorithms one at a time. See Figure 9.2 and Figure 9.3

if Statements:

An if statement tells R to do a certain task for a certain case. In English you would say something like, “If this is true, do that.” In R, you would say:

# if (this) {
#   that
# }
x <- 1
if (3 == 3) {
  x <- 2
}
x
[1] 2

else Statements:

# if (this) {
#   Plan A
# } else {
#   Plan B
# }
a <- 1
b <- 1
if (a > b) {
  print("A wins!")
} else if (a < b) {
  print("B wins!")
} else {
  print("Tie.")
}
[1] "Tie."
# if ( # Case 1: all the same <1>) {
#   prize <- # look up the prize <3>
# } else if ( # Case 2: all bars <2> ) {
#   prize <- # assign $5 <4>
# } else {
#   # count cherries <5>
#   prize <- # calculate a prize <7>
# }

If you like, you can reorganize your flow chart around these tasks, as in Figure 9.4. The chart will describe the same strategy, but in a more precise way. I’ll use a diamond shape to symbolize an if else decision. See Figure 9-4.

Lookup Tables:

Very often in R, the simplest way to do something will involve subsetting. How could you use subsetting here? Since you know the exact relationship between the symbols and their prizes, you can create a vector that captures this information.

payouts <- c("DD" = 100, "7" = 80, "BBB" = 40, "BB" = 25, 
  "B" = 10, "C" = 10, "0" = 0)
payouts
 DD   7 BBB  BB   B   C   0 
100  80  40  25  10  10   0 

Now you can extract the correct prize for any symbol by subsetting the vector with the symbol’s name:

payouts["DD"]
 DD 
100 
payouts["B"]
 B 
10 

If you want to leave behind the symbol’s name when subsetting, you can run the unname function on the output:

unname(payouts["DD"])
[1] 100

unname returns a copy of an object with the names attribute removed.

payouts is a type of lookup table, an R object that you can use to look up values. Subsetting payouts provides a simple way to find the prize for a symbol. It doesn’t take many lines of code, and it does the same amount of work whether your symbol is DD or 0.

Sadly, our method is not quite automatic; we need to tell R which symbol to look up in `payouts

symbols <- c("7", "7", "7")
symbols[1]
[1] "7"
## "7"
payouts[symbols[1]]
 7 
80 
##  7 
## 80 
symbols <- c("C", "C", "C")
payouts[symbols[1]]
 C 
10 
##  C 
## 10 

You don’t need to know the exact symbol to look up because you can tell R to look up whichever symbol happens to be in symbols.

8. S3-X

9. Loops-X

10. Speed-X

Appendix

A. Installing R and Rstudio

You’ll go from downloading R to opening your first R session. Both R and RStudio are free and easy to download (Open Source).

How to Download and Install R:

R is maintained by an international team of developers who make the language available through the web page of The Comprehensive R Archive Network. The top of the web page provides three links for downloading R. Follow the link that describes your operating system: Windows, Mac, or Linux. https://cran.r-project.org/

  • Windows/ Mac/ Linux

To install R on Windows/Mac/Linux, click the “Download R for Windows” link. Then click the “base” link. Next, click the first link at the top of the new page.

  • 32-bit Versus 64-bit

64-bit R uses 64-bit memory pointers, and 32-bit R uses 32-bit memory pointers. This means 64-bit R has a larger memory space to use (and search through). The terms 32-bit and 64-bit refer to the way a computer’s processor (also called a CPU), handles information. The 64-bit version of Windows handles large amounts of random access memory (RAM) more effectively than a 32-bit system. Source: https://support.microsoft.com/en-us/help/15056/windows-7-32-64-bit-faq

Using R:

R isn’t a program that you can open and start using, like Microsoft Word or Internet Explorer. Instead, R is a computer language, like C, C++, or UNIX. Now almost everyone uses R with an application called RStudio IDE (Integrated Development).

Windows and Mac users usually do not program from a terminal window, so the Windows and Mac downloads for R come with a simple program that opens a terminal-like window for you to run R code in. You may hear people refer to them as the Windows or Mac R GUIs (Grafics User Interfaces.

When you open RStudio, a window appears with three panes in it, as in Figure A-1.vThe largest pane is a console window. This is where you’ll run your R code and see results. The console window is exactly what you’d see if you ran R from a UNIX console or the Windows or Mac GUIs.

RStudio:

RStudio is an application like Microsoft Word-except that instead of helping you write in English, RStudio helps you write in R.

Getting started R Programming:

Now that you have both R and RStudio on your computer, you can begin using R by opening the RStudio program. Open RStudio just as you would any program, by clicking on its icon or by typing “RStudio” at the Windows Run prompt.

B. R Packages

  • Many of R’s most useful functions do not come preloaded when you start R, but reside in packages that can be installed on top of R.
  • R packages are similar to libraries in C, C ++, and Javascript, packages in Python, and gems in Ruby. An R package bundles together useful functions, help files, and data sets. You can use these functions within your own R code once you load the package they live in.

R packages will let you take advantage of R’s most useful features:

  • its large community of package writers (many of whom are active data scientists)
  • and its prewritten routines for handling many common (and exotic) data-science tasks

Base R: It is just the collection of R functions that gets loaded every time you start R. These functions provide the basics of the language, and you don’t have to load a package before you can use them.

Installing Packages:

The easiest way to install an R package is with the install.packages R function. install.packages("package name")

This will search for the specified package in the collection of packages hosted on the CRAN site. When R finds the package, it will download it into a libraries folder on your computer. R can access the package here in future R sessions without reinstalling it.

You can install multiple packages at once by linking their names with R’s concatenate function, c. For example, to install the ggplot2, reshape2, and dplyr packages, run:

install.packages(c("ggplot2", "reshape2", "dplyr"))

Loading Packages:

Installing a package doesn’t immediately place its functions at your fingertips. It just places them on your computer. To use an R package, you next have to load it in your R session with the command:

library(package name)

Library will make all of the package’s functions, data sets, and help files available to you until you close your current R session. The next time you begin an R session, you’ll have to reload the package with library if you want to use it, but you won’t have to reinstall it.

You only have to install each package once. After that, a copy of the package will live in your R library. To see which packages you currently have in your R library, run:

library()

library() also shows the path to your actual R library, which is the folder that contains your R packages. You may notice many packages that you don’t remember installing. This is because R automatically downloads a set of useful packages when you first install R.

Install packages from (almost) anywhere The devtools R package makes it easy to install packages from locations other than the CRAN website. devtools provides functions like

  • install_github
  • install_gitorious
  • install_bitbucket
  • in stall_url

These work similar to install.packages, but they search new locations for R packages. install_github is especially useful because many R developers provide development versions of their packages on GitHub. The development version of a package will contain a sneak peek of new functions and patches but may not be as stable or as bug free as the CRAN version.

Why does R make you bother with installing and loading packages?

  • If every packed load-> very large and slow program
  • It is simpler to only install and load the packages that you want to use when you want to use them.
  • It is possible to update your copy of an R package without updating your entire copy of R.

What’s the best way to learn about R packages?

C. Updating R and Its Packages

The R Core Development Team continuously hones the R language by catching bugs, improving performance, and updating R to work with new technologies. The easiest way to stay current with R is to periodically check the CRAN website: https://cran.r-project.org

RStudio also constantly improves its product. You can acquire the newest updates just by downloading them from RStudio.

  • R Packages

Package authors occasionally release new versions of their packages to add functions, fix bugs, or improve performance. update.packages(c("ggplot2", "reshape2", "dplyr"))

D. Loading and Saving Data in R

  • Data Sets in Base R

Import deck.

deck

These data sets are not very interesting, but they give you a chance to test code or make a point without having to load a data set from outside R. You can see a list of R’s data sets as well as a short description of each by running: help(package = "datasets")

help(package = "datasets")

To use a data set, just type its name. Each data set is already presaved as an R object. For example: iris (Edgar Anderson’s Iris Data)

iris
  • Working Directory

Each time you open R, it links itself to a directory on your computer, which R calls the working directory. This is where R will look for files when you attempt to load them, and it is where R will save files when you save them.

To determine which directory R is using as your working directory, run: getwd()

getwd()

You can place data files straight into the folder that is your working directory, or you can move your working directory to where your data files are. You can move your working directory to any folder on your computer with the function setwd()

You can also change your working directory by clicking on Session > Set Working Directory > Choose Directory in the RStudio menu bar.

You can see what files are in your working directory with list.files().

list.files()
  • Plain-text Files

Plain-text files are one of the most common ways to save data. They are very simple and can be read by many different computer programs-even the most basic text editors. For this reason, public data often comes as plain-text files.

All plain-text files can be saved with the extension .txt (for text), but sometimes a file will receive a special extension that advertises how it separates data-cell entries. Since entries in the data set mentioned earlier are separated with a comma, this file would be a comma-separated-values file and would usually be saved with the extension .csv.

  • read.table

To load a plain-text file, use read.table.If the royal flush data set was saved as a file named poker.csv in your working directory, you could load it with:

poker <- read.table("deck.csv", sep = ",", header = TRUE)

More about read.table, see the documentation https://www.rdocumentation.org/packages/utils/versions/3.5.3/topics/read.table sep: Use sep to tell read.table what character your file uses to separate data entries.

header: Use header to tell read.table whether the first line of the file contains variable names instead of values.

na.strings: Oftentimes data sets will use special symbols to represent missing information. If you know that your data uses a certain symbol to represent missing entries, you can tell read.table (and the preceding functions) what the symbol is with the na.strings argument.

Skip and nrow: Use skip to tell R to skip a specific number of lines before it starts reading in values from the file. Use nrow to tell R to stop reading in values after it has read in a certain number of lines.

stringsAsFactors: Setting the argument stringsAsFactors to FALSE will ensure that R saves any character strings in your data set as character strings, not factors.

If you will be loading more than one data file, you can change the default factoring behavior at the global level with: options(stringsAsFactors = FALSE)

Or

You can use Import Dataset from toolbar Environment -From Text -From Excel etc.

The read Family:

R also comes with some prepackaged short cuts for read.table, shown in Table D-1.

‘read.delim2’ and ‘read.csv2’ exist for European R users. These functions tell R that the data uses a comma instead of a period to denote decimal places. (If you’re wondering how this works with CSV files, CSV2 files usually separate cells with a semicolon, not a comma.)

  • read.fwf

One type of plain-text file defies the pattern by using its layout to separate data cells. Each row is placed in its own line (as with other plain-text files), and then each column begins at a specific number of characters from the lefthand side of the document.

You can read fixed-width files into R with the function read.fwf. The function takes the same arguments as read.table but requires an additional argument, widths, which should be a vector of numbers. Each ith entry of the widths vector should state the width (in characters) of the ith column of the data set. poker <- read.fwf("poker.fwf", widths = c(10, 7, 6), header = TRUE)

  • HTML Links

You can pass a web address into the file name argument for any of R’s data-reading functions. poker <- read.csv("http://.../poker.csv")

Note that websites that begin with https:// are secure websites, which means R may not be able to access the data provided at these links.

** Saving Plain-Text Files: **

Once your data is in R, you can save it to any file format that R supports. The three basic write functions appear in Table D-2.

Use write.csv to save your data as a .csv file and write.table to save your data as a tab delimited document or a document with more exotic separators. write.csv(poker, "data/poker.csv", row.names = FALSE)

  • Compressing Files

To compress a plain-text file, surround the file name or file path with the function bzfile, gzfile, or xzfile. For example: write.csv(poker, file = bzfile("data/poker.csv.bz2"), row.names = FALSE)

Each of these functions will compress the output with a different type of compression format, shown in Table D-3.

  • R Files

R provides two file formats of its own for storing data, .RDS and .RData. RDS files can store a single R object, and RData files can store multiple R objects.

You can open a RDS file with readRDS. For example, if the royal flush data was saved as poker.RDS, you could open it with: poker <- readRDS("poker.RDS")

Opening RData files is even easier. Simply run the function load with the file: load("file.RData")

Both readRDS and load take a file path as their first argument, just like R’s other read and write functions. If your file is in your working directory, the file path will be the file name.

  • Saving R Files

For example, if you have three R objects, a, b, and c, you could save them all in the same RData file and then reload them in another R session:

a <- 1
b <- 2
c <- 3
data<-c(a,b,c)
save(data, file = "stuff.RData")
load("stuff.RData")
stuff<-load("stuff.RData")
stuff
data

Saving your data as an R file offers some advantages over saving your data as a plaintext file. R automatically compresses the file and will also save any R-related metadata associated with your object. This can be handy if your data contains factors, dates and times, or class attributes. You won’t have to reparse this information into R the way you would if you converted everything to a text file.

On the other hand, R files cannot be read by many other programs, which makes them inefficient for sharing. They may also create a problem for long-term storage if you don’t think you’ll have a copy of R when you reopen the files.

Excel Spreadsheets:

Microsoft Excel is a popular spreadsheet program that has become almost industry standard in the business world. There is a good chance that you will need to work with an Excel spreadsheet in R at least once in your career. You can read spreadsheets into R and also save R data as a spreadsheet in a variety of ways.

  • Export from Excel

The best method for moving data from Excel to R is to export the spreadsheet from Excel as a .csv or .txt file. Not only will R be able to read the text file, so will any other data analysis software. Text files are the lingua franca of data storage.

To export data from Excel, open the Excel spreadsheet and then go to Save As in the Microsoft Office Button menu. Then choose CSV in the Save as type box that appears and save the files. You can then read the file into R with the read.csv function.

  • Copy and Paste

You can also copy portions of an Excel spreadsheet and paste them into R. To do this, open the spreadsheet and select the cells you wish to read into R. Then select Edit > Copy in the menu bar-or use a keyboard shortcut-to copy the cells to your clipboard. On most operating systems, you can read the data stored in your clipboard into R with: read.table("clipboard")

  • XLConnect

Many packages have been written to help you read Excel files directly into R. Unfortunately, many of these packages do not work on all operating systems. Others have been made out of date by the .xlsx file format. One package that does work on all file systems (and gets good reviews) is the XLConnect package. To use it, you’ll need to install and load the package: install.packages("XLConnect")

  • Reading Spreadsheets

You can use XLConnect to read in an Excel spreadsheet with either a one- or a two-step process.

wb <- loadWorkbook("file.xlsx")

sheet1 <- readWorksheet(wb, sheet = 1, startRow = 0, startCol = 0, endRow = 100, endCol = 3)

You can combine these two steps with readWorksheetFromFile. It takes the file argument from loadWorkbook and combines it with the arguments from readWorksheet. You can use it to read one or more sheets straight from an Excel file:

sheet1 <- readWorksheetFromFile("file.xlsx", sheet = 1, startRow = 0, startCol = 0, endRow = 100, endCol = 3)

  • Writing Spreadsheets

Writing to an Excel spreadsheet is a four-step process:

  1. b <- loadWorkbook("file.xlsx", create = TRUE)
  2. createSheet(wb, "Sheet 1")
  3. writeWorksheet(wb, data = poker, sheet = "Sheet 1")
  4. writeWorksheetToFile("file.xlsx", data = poker, sheet = "Sheet 1", startRow = 1, startCol = 1)

Loading Files from Other Programs:

You should follow the same advice I gave you for Excel files whenever you wish to work with file formats native to other programs: open the file in the original program and export the data as a plain-text file, usually a CSV. This will ensure the most faithful transcription of the data in the file, and it will usually give you the most options for customizing how the data is transcribed.

Sometimes, however, you may acquire a file but not the program it came from. As a result, you won’t be able to open the file in its native program and export it as a text file. In this case, you can use one of the functions in Table D-4 to open the file.

  • Connecting to Databases

Working with a database will require experience that goes beyond the skill set of a typical R user. However, if you are interested in doing this, the best place to start is by downloading these R packages and reading their documentation. Use the DBI package to connect to databases through individual drivers.

For MySQL use RMySQL, for SQLite use RSQLite, for Oracle use ROracle, for PostgreSQL use RPostgreSQL, and for databases that use drivers based on the Java Database Connectivity (JDBC) API use RJDBC. Once you have loaded the appropriate driver package, you can use the commands provided by DBI to access your database.

E. Debugging R Code-X

Change log update

  • 19.01.2019
  • 13.04.2019
  • 14.04.2019
  • 15.04.2019
  • 16.04.2019
  • 17.04.2019


License

MIT

LS0tDQp0aXRsZTogIkhhbmRzLU9uIFByb2dyYW1taW5nIHdpdGggUiINCnN1YnRpdGxlOiAiU3VtbWFyaXppbmcgc2VyaWVzIGZyb20gZXhjZWxsZW50IGF1dGhvcnMiDQphdXRob3I6ICJDZXZpIEhlcmRpYW4iDQpkYXRlOiAiU2VlIHRoZSBjaGFuZ2UgbG9nIHVwZGF0ZSINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzDQogICAgdGhlbWU6IGNvc21vDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDUNCiAgICB0b2NfZmxvYXQ6IHllcw0KICBodG1sX2RvY3VtZW50Og0KICAgIGRmX3ByaW50OiBwYWdlZA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiAnNScNCiAgcGRmX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiAnNScNCiAgd29yZF9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogJzUnDQotLS0NCg0KIVtdKGh0dHBzOi8vb2N0b2RleC5naXRodWIuY29tL2ltYWdlcy9kb2pvY2F0LmpwZykNCg0KDQoNCioqTm90ZToqKg0KDQotQW4gUiBOb3RlYm9vayBpcyBhbiBSIE1hcmtkb3duIGRvY3VtZW50IHdpdGggY2h1bmtzIHRoYXQgY2FuIGJlIGV4ZWN1dGVkIGluZGVwZW5kZW50bHkgYW5kIGludGVyYWN0aXZlbHksIHdpdGggb3V0cHV0IHZpc2libGUgaW1tZWRpYXRlbHkgYmVuZWF0aCB0aGUgaW5wdXQuDQoNCi1Ob3RlYm9vayBvdXRwdXQgYXJlIGF2YWlsYWJsZSBhcyBIVE1MLCBQREYsIFdvcmQsIG9yIExhdGV4LiANCg0KLVRoaXMgTm90ZWJvb2sgYXMgSFRNTCBpcyBwcmVmZXJhYmx5IG9wZW4gd2l0aCBHb29nbGUgQ2hyb21lLg0KDQotUi1Db2RlIGNhbiBiZSBleHRyYWN0ZWQgYXMgUm1kIGZpbGUgdW5kZXIgdGhlIGJ1dHRvbiAiQ29kZSIgaW4gdGhlIG5vdGVib29rLg0KDQotVGhpcyBOb3RlYm9vayB1c2luZyBpdGVyYXRpdmUgZGV2ZWxvcG1lbnQuIEl0IG1lYW5zIHRoZSBwcm9jZXNzIHN0YXJ0cyB3aXRoIGEgc2ltcGxlIGltcGxlbWVudGF0aW9uIG9mIGEgc21hbGwgc2V0IG9mIGlkZWEgcmVxdWlyZW1lbnRzIGFuZCBpdGVyYXRpdmVseSBlbmhhbmNlcyB0aGUgZXZvbHZpbmcgdmVyc2lvbnMgdW50aWwgdGhlIGNvbXBsZXRlIHZlcnNpb24gaXMgaW1wbGVtZW50ZWQgYW5kIHBlcmZlY3QuDQoNCg0KDQojR2V0dGluZyBzdGFydGVkDQoNCiFbXShjb3Zlci5QTkcpDQoNCmBgYHtyfQ0KDQojaHR0cHM6Ly9yc3R1ZGlvLWVkdWNhdGlvbi5naXRodWIuaW8vaG9wci8NCg0KYGBgDQoNCg0KVGhpcyBib29rIGFyZToNCg0KKiBUZWFjaCB5b3UgaG93IHRvIHByb2dyYW0gaW4gUiwgd2l0aCBoYW5kcy1vbiBleGFtcGxlcw0KKiBBIGZyaWVuZGx5IGludHJvZHVjdGlvbiB0byB0aGUgUiBsYW5ndWFnZQ0KKiBOZXdmb3VuZCBza2lsbHMgdG8gc29sdmUgcHJhY3RpY2FsIGRhdGEgc2NpZW5jZSBwcm9ibGVtcw0KKiBHbyBmcm9tIGxvYWRpbmcgZGF0YSB0byB3cml0aW5nIHlvdXIgb3duIGZ1bmN0aW9ucw0KKiBIZWxwIHlvdSBiZWNvbWUgYSBkYXRhIHNjaWVudGlzdCwgYXMgd2VsbCBhcyBhIGNvbXB1dGVyIHNjaWVudGlzdA0KKiBGb2N1cyBvbiB0aGUgcHJvZ3JhbW1pbmcgc2tpbGxzIHRoYXQgYXJlIG1vc3QgcmVsYXRlZCB0byBkYXRhIHNjaWVuY2UNCiogVHJlYXQgUiBwdXJlbHkgYXMgYSBwcm9ncmFtbWluZyBsYW5ndWFnZQ0KDQo8QnI+DQoNCiM9PVByb2plY3QgMTogV2VpZ2h0ZWQgRGljZT09DQoNCkltcHJvdmUgeW91ciBhYmlsaXR5IGFzIGEgZGF0YSBzY2llbnRpc3Q6DQoNCiogTWVtb3JpemUgKHN0b3JlKSBlbnRpcmUgZGF0YSBzZXRzDQoqIFJlY2FsbCBkYXRhIHZhbHVlcyBvbiBkZW1hbmQNCiogUGVyZm9ybSBjb21wbGV4IGNhbGN1bGF0aW9ucyB3aXRoIGxhcmdlIGFtb3VudHMgb2YgZGF0YQ0KKiBEbyByZXBldGl0aXZlIHRhc2tzIHdpdGhvdXQgYmVjb21pbmcgY2FyZWxlc3Mgb3IgYm9yZWQNCg0KWW91ciBmaXJzdCBtaXNzaW9uIGlzIHNpbXBsZTogYXNzZW1ibGUgUiBjb2RlIHRoYXQgd2lsbCBzaW11bGF0ZSByb2xsaW5nIGEgcGFpciBvZiBkaWNlLCBsaWtlIGF0IGEgY3JhcHMgdGFibGUuIEluIHRoaXMgcHJvamVjdCwgeW91IHdpbGwgbGVhcm4gaG93IHRvOg0KDQoqIFVzZSB0aGUgUiBhbmQgUlN0dWRpbyBpbnRlcmZhY2VzDQoqIFJ1biBSIGNvbW1hbmRzDQoqIENyZWF0ZSBSIG9iamVjdHMNCiogV3JpdGUgeW91ciBvd24gUiBmdW5jdGlvbnMgYW5kIHNjcmlwdHMNCiogTG9hZCBhbmQgdXNlIFIgcGFja2FnZXMNCiogR2VuZXJhdGUgcmFuZG9tIHNhbXBsZXMNCiogQ3JlYXRlIHF1aWNrIHBsb3RzDQoqIEdldCBoZWxwIHdoZW4geW91IG5lZWQgaXQNCg0KWW91J2xsIG5lZWQgdG8gaGF2ZSBib3RoIFIgYW5kIFJTdHVkaW8gaW5zdGFsbGVkIG9uIHlvdXIgY29tcHV0ZXIgYmVmb3JlIHlvdSBjYW4gdXNlIHRoZW0uIEJvdGggYXJlIGZyZWUgYW5kIGVhc3kgdG8gZG93bmxvYWQuIFNlZSAqKkFwcGVuZGl4IEEqKg0KDQo8QnI+DQoNCiMxLiBUaGUgVmVyeSBCYXNpY3MNCg0KSW4gaXQsIHlvdSB3aWxsIGJ1aWxkIGEgcGFpciBvZiB2aXJ0dWFsIGRpY2UgdGhhdCB5b3UgY2FuIHVzZSB0byBnZW5lcmF0ZSByYW5kb20gbnVtYmVycy4NCg0KKipUaGUgUiBVc2VyIEludGVyZmFjZTogKioNCg0KIVtdKDEtMS5QTkcpDQoNCmBgYHtyfQ0KDQojaHR0cHM6Ly9yc3R1ZGlvLWVkdWNhdGlvbi5naXRodWIuaW8vaG9wci9iYXNpY3MuaHRtbCN0aGUtci11c2VyLWludGVyZmFjZQ0KDQpgYGANCg0KDQo+SWYgeW91IGRvIG5vdCB5ZXQgaGF2ZSBSIGFuZCBSU3R1ZGlvIGludGFsbGVkIG9uIHlvdXIgY29tcHV0ZXItb3IgZG8gbm90IGtub3cgd2hhdCBJIGFtIHRhbGtpbmcgYWJvdXQtdmlzaXQgQXBwZW5kaXggQS4gVGhlIGFwcGVuZGl4IHdpbGwgZ2l2ZSB5b3UgYW4gb3ZlcnZpZXcgb2YgdGhlIHR3byBmcmVlIHRvb2xzIGFuZCB0ZWxsIHlvdSBob3cgdG8gZG93bmxvYWQgdGhlbS4NCg0KV2hlbiB5b3UgdHlwZSBhIGNvbW1hbmQgYXQgdGhlIHByb21wdCBhbmQgaGl0IEVudGVyLCB5b3VyIGNvbXB1dGVyIGV4ZWN1dGVzIHRoZSBjb21tYW5kIGFuZCBzaG93cyB5b3UgdGhlIHJlc3VsdHMuIFRoZW4gUlN0dWRpbyBkaXNwbGF5cyBhIGZyZXNoIHByb21wdCBmb3IgeW91ciBuZXh0IGNvbW1hbmQuIEZvciBleGFtcGxlLCBpZiB5b3UgdHlwZSAxICsgMSBhbmQgaGl0IEVudGVyLCBSU3R1ZGlvIHdpbGwgZGlzcGxheToNCg0KYGBge3J9DQoxICsgMSANCg0KYGBgDQoNCllvdSBjYW4gbW9zdGx5IGlnbm9yZSB0aGUgbnVtYmVycyB0aGF0IGFwcGVhciBpbiBicmFja2V0czoNCg0KYGBge3J9DQoNCjEwMDoxMzAgDQoNCmBgYA0KDQoNCklmIHlvdSB0eXBlIGFuIGluY29tcGxldGUgY29tbWFuZCBhbmQgcHJlc3MgRW50ZXIsIFIgd2lsbCBkaXNwbGF5IGEgKyBwcm9tcHQsIHdoaWNoIG1lYW5zIFIgaXMgd2FpdGluZyBmb3IgeW91IHRvIHR5cGUgdGhlIHJlc3Qgb2YgeW91ciBjb21tYW5kLiBFaXRoZXIgZmluaXNoIHRoZSBjb21tYW5kIG9yIGhpdCBFc2NhcGUgdG8gc3RhcnQgb3ZlcjoNCg0KYGBge3J9DQo1IC0NCg0KDQpgYGANCg0KSWYgeW91IHR5cGUgYSBjb21tYW5kIHRoYXQgUiBkb2Vzbid0IHJlY29nbml6ZSwgUiB3aWxsIHJldHVybiBhbiBlcnJvciBtZXNzYWdlLiANCklmIHlvdSBldmVyIHNlZSBhbiBlcnJvciBtZXNzYWdlLCBkb24ndCBwYW5pYy4gUiBpcyBqdXN0IHRlbGxpbmcgeW91IHRoYXQgeW91ciBjb21wdXRlciBjb3VsZG4ndCB1bmRlcnN0YW5kIG9yIGRvIHdoYXQgeW91IGFza2VkIGl0IHRvIGRvLg0KDQpgYGB7cn0NCg0KMyAlIDUNCg0KYGBgDQoNCk9uY2UgeW91IGdldCB0aGUgaGFuZyBvZiB0aGUgY29tbWFuZCBsaW5lLCB5b3UgY2FuIGVhc2lseSBkbyBhbnl0aGluZyBpbiBSIHRoYXQgeW91IHdvdWxkIGRvIHdpdGggYSBjYWxjdWxhdG9yLiBGb3IgZXhhbXBsZSwgeW91IGNvdWxkIGRvIHNvbWUgYmFzaWMgYXJpdGhtZXRpYzoNCiAgDQpgYGB7cn0NCjIgKiAzDQoNCjQgLSAxDQoNCg0KNiAvICg0IC0gMSkNCg0KYGBgDQogIA0KIA0KDQpfX19fRXhlcmNpc2VfVGhlIFIgVXNlciBJbnRlcmZhY2U6DQoNCjEuIENob29zZSBhbnkgbnVtYmVyIGFuZCBhZGQgMiB0byBpdC4NCjIuIE11bHRpcGx5IHRoZSByZXN1bHQgYnkgMy4NCjMuIFN1YnRyYWN0IDYgZnJvbSB0aGUgYW5zd2VyLg0KNC4gRGl2aWRlIHdoYXQgeW91IGdldCBieSAzLg0KICANClNvbHV0aW9uOg0KDQpgYGB7cn0NCg0KMTAgKyAyDQojIyAxMg0KDQoxMiAqIDMNCiMjIDM2DQoNCjM2IC0gNg0KIyMgMzANCg0KMzAgLyAzDQojIyAxMA0KDQpgYGANCg0KICANCioqT2JqZWN0czogKioNCg0KUiBsZXRzIHlvdSBzYXZlIGRhdGEgYnkgc3RvcmluZyBpdCBpbnNpZGUgYW4gUiBvYmplY3QuIFdoYXQncyBhbiBvYmplY3Q/IEp1c3QgYSBuYW1lIHRoYXQgeW91IGNhbiB1c2UgdG8gY2FsbCB1cCBzdG9yZWQgZGF0YS4NCg0KDQogDQpgYGB7cn0NCg0KYSA8LSAxIA0KYQ0KICANCmRpZSA8LSAxOjYNCmRpZQ0KDQpgYGANCg0KIVtdKDEtMi5QTkcpDQoNCmBgYHtyfQ0KDQojaHR0cHM6Ly9yc3R1ZGlvLWVkdWNhdGlvbi5naXRodWIuaW8vaG9wci9iYXNpY3MuaHRtbCNvYmplY3RzDQoNCmBgYA0KDQoNClIgYWxzbyB1bmRlcnN0YW5kcyBjYXBpdGFsaXphdGlvbiAob3IgaXMgY2FzZS1zZW5zaXRpdmUpLCBzbyBuYW1lIGFuZCBOYW1lIHdpbGwgcmVmZXIgdG8gZGlmZmVyZW50IG9iamVjdHM6IA0KDQpgYGB7cn0NCg0KTmFtZSA8LSAxIA0KTmFtZQ0KbmFtZSA8LSAwDQpuYW1lICANCmBgYA0KDQpZb3UgY2FuIHNlZSB3aGljaCBvYmplY3QgbmFtZXMgeW91IGhhdmUgYWxyZWFkeSB1c2VkIHdpdGggdGhlIGZ1bmN0aW9uIGBsc2A6DQoNCmBgYHtyfQ0KbHMoKSANCg0KYGBgDQoNCg0KDQpJZiB5b3UgYXJlIGEgYmlnIGZhbiBvZiBsaW5lYXIgYWxnZWJyYSAoYW5kIHdobyBpc24ndD8pLCB5b3UgbWF5IG5vdGljZSB0aGF0IFIgZG9lcyBub3QgYWx3YXlzIGZvbGxvdyB0aGUgcnVsZXMgb2YgbWF0cml4IG11bHRpcGxpY2F0aW9uLiBJbnN0ZWFkLCBSIHVzZXMgZWxlbWVudC13aXNlIGV4ZWN1dGlvbi4gV2hlbiB5b3UgbWFuaXB1bGF0ZSBhIHNldCBvZiBudW1iZXJzLCBSIHdpbGwgYXBwbHkgdGhlIHNhbWUgb3BlcmF0aW9uIHRvIGVhY2ggZWxlbWVudCBpbiB0aGUgc2V0LiBTbyBmb3IgZXhhbXBsZSwgd2hlbiB5b3UgcnVuIGRpZSAtIDEsIFIgc3VidHJhY3RzIG9uZSBmcm9tIGVhY2ggZWxlbWVudCBvZiBkaWUuIA0KDQpUaGUgcmVzdWx0IHdpbGwgYmUgYSBuZXcgdmVjdG9yIHRoZSBzYW1lIGxlbmd0aCBhcyB0aGUgZmlyc3QgdHdvLCBhcyBzaG93biBpbiBGaWd1cmUgMS0zLg0KDQohW10oMS0zLlBORykNCg0KYGBge3J9DQoNCiNodHRwczovL3JzdHVkaW8tZWR1Y2F0aW9uLmdpdGh1Yi5pby9ob3ByL2Jhc2ljcy5odG1sI29iamVjdHMNCg0KYGBgDQoNCg0KSWYgeW91IGdpdmUgUiB0d28gdmVjdG9ycyBvZiB1bmVxdWFsIGxlbmd0aHMsIFIgd2lsbCByZXBlYXQgdGhlIHNob3J0ZXIgdmVjdG9yIHVudGlsIGl0IGlzIGFzIGxvbmcgYXMgdGhlIGxvbmdlciB2ZWN0b3IsIGFuZCB0aGVuIGRvIHRoZSBtYXRoLCBhcyBzaG93biBpbiBGaWd1cmUgMS00LiANCg0KIVtdKDEtNC5QTkcpDQoNCmBgYHtyfQ0KDQojaHR0cHM6Ly9yc3R1ZGlvLWVkdWNhdGlvbi5naXRodWIuaW8vaG9wci9iYXNpY3MuaHRtbCNvYmplY3RzDQoNCmBgYA0KDQoNCkJ1dCBkb24ndCB0aGluayB0aGF0IFIgaGFzIGdpdmVuIHVwIG9uIHRyYWRpdGlvbmFsIG1hdHJpeCBtdWx0aXBsaWNhdGlvbi4gWW91IGp1c3QgaGF2ZSB0byBhc2sgZm9yIGl0IHdoZW4geW91IHdhbnQgaXQuIFlvdSBjYW4gZG8gaW5uZXIgbXVsdGlwbGljYXRpb24gd2l0aCB0aGUgYCUqJWAgb3BlcmF0b3IgYW5kIG91dGVyIG11bHRpcGxpY2F0aW9uIHdpdGggdGhlIGAlbyVgIG9wZXJhdG9yOg0KDQpgYGB7cn0NCg0KZGllPC0xOjgNCmRpZQ0KZGllKmRpZSAgDQpkaWUlKiVkaWUNCmRpZSVvJWRpZSAgIA0KDQoNCmBgYA0KDQogIA0KICANCiAgDQoqKkZ1bmN0aW9uczogKioNCg0KVXNpbmcgYSBmdW5jdGlvbiBpcyBwcmV0dHkgc2ltcGxlLiBKdXN0IHdyaXRlIHRoZSBuYW1lIG9mIHRoZSBmdW5jdGlvbiBhbmQgdGhlbiB0aGUgZGF0YSB5b3Ugd2FudCB0aGUgZnVuY3Rpb24gdG8gb3BlcmF0ZSBvbiBpbiBwYXJlbnRoZXNlczoNCg0KYGBge3J9DQoNCnJvdW5kKDMuMTQxNSkgIyMgMw0KZmFjdG9yaWFsKDMpICMjIDYgDQoNCmBgYA0KDQpUaGUgZGF0YSB0aGF0IHlvdSBwYXNzIGludG8gdGhlIGZ1bmN0aW9uIGlzIGNhbGxlZCB0aGUgZnVuY3Rpb24ncyBhcmd1bWVudC4gVGhlIGFyZ3VtZW50IGNhbiBiZSByYXcgZGF0YSwgYW4gUiBvYmplY3QsIG9yIGV2ZW4gdGhlIHJlc3VsdHMgb2YgYW5vdGhlciBSIGZ1bmN0aW9uLiBJbiB0aGlzIGxhc3QgY2FzZSwgUiB3aWxsIHdvcmsgZnJvbSB0aGUgaW5uZXJtb3N0IGZ1bmN0aW9uIHRvIHRoZSBvdXRlcm1vc3QsIGFzIGluIEZpZ3VyZSAxLTU6DQoNCiFbXSgxLTUuUE5HKQ0KDQpgYGB7cn0NCg0KI2h0dHBzOi8vcnN0dWRpby1lZHVjYXRpb24uZ2l0aHViLmlvL2hvcHIvYmFzaWNzLmh0bWwjb2JqZWN0cw0KDQpgYGANCiAgDQpJZiB5b3UncmUgbm90IHN1cmUgd2hpY2ggbmFtZXMgdG8gdXNlIHdpdGggYSBmdW5jdGlvbiwgeW91IGNhbiBsb29rIHVwIHRoZSBmdW5jdGlvbidzIGFyZ3VtZW50cyB3aXRoIGFyZ3MuIFRvIGRvIHRoaXMsIHBsYWNlIHRoZSBuYW1lIG9mIHRoZSBmdW5jdGlvbiBpbiB0aGUgcGFyZW50aGVzZXMgYmVoaW5kIGBhcmdzYC4gRm9yIGV4YW1wbGUsIHlvdSBjYW4gc2VlIHRoYXQgdGhlIHJvdW5kIGZ1bmN0aW9uIHRha2VzIHR3byBhcmd1bWVudHMsIG9uZSBuYW1lZCB4IGFuZCBvbmUgbmFtZWQgZGlnaXRzOg0KDQpgYGB7cn0NCg0Kcm91bmQoMy40NDQpDQogIGFyZ3Mocm91bmQpICMjIGZ1bmN0aW9uICh4LCBkaWdpdHMgPSAwKSAjIyBOVUxMIA0KDQpgYGANCg0KKipTYW1wbGUgd2l0aCBSZXBsYWNlbWVudDogKioNCg0KU2FtcGxpbmcgd2l0aCByZXBsYWNlbWVudCBpcyBhbiBlYXN5IHdheSB0byBjcmVhdGUgaW5kZXBlbmRlbnQgcmFuZG9tIHNhbXBsZXMuIA0KRWFjaCB2YWx1ZSBpbiB5b3VyIHNhbXBsZSB3aWxsIGJlIGEgc2FtcGxlIG9mIHNpemUgb25lIHRoYXQgaXMgaW5kZXBlbmRlbnQgb2YgdGhlIG90aGVyIHZhbHVlcy4gVGhpcyBpcyB0aGUgY29ycmVjdCB3YXkgdG8gc2ltdWxhdGUgYSBwYWlyIG9mIGRpY2U6DQoNCmBgYHtyfQ0KZGllPC0xOjgNCnNhbXBsZShkaWUsIHNpemUgPSAyLCByZXBsYWNlID0gVFJVRSkgDQpkaWNlIDwtIHNhbXBsZShkaWUsIHNpemUgPSAyLCByZXBsYWNlID0gVFJVRSkgDQpkaWNlIA0Kc3VtKGRpY2UpIA0KDQpgYGANCg0KICANCldoYXQgd291bGQgaGFwcGVuIGlmIHlvdSBjYWxsIGRpY2UgbXVsdGlwbGUgdGltZXM/IFdvdWxkIFIgZ2VuZXJhdGUgYSBuZXcgcGFpciBvZiBkaWNlIHZhbHVlcyBlYWNoIHRpbWU/IExldCdzIGdpdmUgaXQgYSB0cnk6DQogIA0KYGBge3J9DQoNCmRpY2UgDQpkaWNlIA0KZGljZSANCg0KYGBgDQogIA0KTm9wZS4gRWFjaCB0aW1lIHlvdSBjYWxsIGRpY2UsIFIgd2lsbCBzaG93IHlvdSB0aGUgcmVzdWx0IG9mIHRoYXQgb25lIHRpbWUgeW91IGNhbGxlZCBzYW1wbGUgYW5kIHNhdmVkIHRoZSBvdXRwdXQgdG8gZGljZS4gUiB3b24ndCByZXJ1biBgc2FtcGxlKGRpZSwgMiwgcmVwbGFjZSA9IFRSVUUpYCB0byBjcmVhdGUgYSBuZXcgcm9sbCBvZiB0aGUgZGljZS4gVGhpcyBpcyBhIHJlbGllZiBpbiBhIHdheS4gT25jZSB5b3Ugc2F2ZSBhIHNldCBvZiByZXN1bHRzIHRvIGFuIFIgb2JqZWN0LCB0aG9zZSByZXN1bHRzIGRvIG5vdCBjaGFuZ2UuIFByb2dyYW1taW5nIHdvdWxkIGJlIHF1aXRlIGhhcmQgaWYgdGhlIHZhbHVlcyBvZiB5b3VyIG9iamVjdHMgY2hhbmdlZCBlYWNoIHRpbWUgeW91IGNhbGxlZCB0aGVtLiANCiAgDQogIA0KKipXcml0aW5nIFlvdXIgT3duIEZ1bmN0aW9uczogKiogDQoNClRvIHJlY2FwLCB5b3UgYWxyZWFkeSBoYXZlIHdvcmtpbmcgUiBjb2RlIHRoYXQgc2ltdWxhdGVzIHJvbGxpbmcgYSBwYWlyIG9mIGRpY2U6DQoNCmBgYHtyfQ0KDQpkaWUgPC0gMTo2IA0KZGljZSA8LSBzYW1wbGUoZGllLCBzaXplID0gMiwgcmVwbGFjZSA9IFRSVUUpIA0Kc3VtKGRpY2UpIA0KDQpgYGANCg0KSXQgd291bGQgYmUgZWFzaWVyIHRvIHVzZSB5b3VyIGNvZGUgaWYgeW91IHdyYXBwZWQgaXQgaW50byBpdHMgb3duIGZ1bmN0aW9uLiBGdW5jdGlvbnMgbWF5IHNlZW0gbXlzdGVyaW91cyBvciBmYW5jeSwgYnV0IHRoZXkgYXJlIGp1c3QgYW5vdGhlciB0eXBlIG9mIFIgb2JqZWN0LiBJbnN0ZWFkIG9mIGNvbnRhaW5pbmcgZGF0YSwgdGhleSBjb250YWluIGNvZGUuIFRoaXMgY29kZSBpcyBzdG9yZWQgaW4gYSBzcGVjaWFsIGZvcm1hdCB0aGF0IG1ha2VzIGl0IGVhc3kgdG8gcmV1c2UgdGhlIGNvZGUgaW4gbmV3IHNpdHVhdGlvbnMuIFlvdSBjYW4gd3JpdGUgeW91ciBvd24gZnVuY3Rpb25zIGJ5IHJlY3JlYXRpbmcgdGhpcyBmb3JtYXQuDQogICAgDQoqKlRoZSBGdW5jdGlvbiBDb25zdHJ1Y3RvcjogKioNCg0KRXZlcnkgZnVuY3Rpb24gaW4gUiBoYXMgdGhyZWUgYmFzaWMgcGFydHM6IA0KDQoxLiBhIG5hbWUNCjIuIGEgYm9keSBvZiBjb2RlLCBhbmQgDQozLiBhIHNldCBvZiBhcmd1bWVudHMgDQoNCj4gbXlfZnVuY3Rpb24gPC0gZnVuY3Rpb24oKSB7fSANCg0KYGBge3J9DQoNCnJvbGwgPC0gZnVuY3Rpb24oKSB7ICANCiAgICAgIGRpZSA8LSAxOjYgIA0KICAgICAgZGljZSA8LSBzYW1wbGUoZGllLCBzaXplID0gMiwgcmVwbGFjZSA9IFRSVUUpICANCiAgICAgIHN1bShkaWNlKSANCiAgICAgIH0gDQoNCg0KICAgIHJvbGwoKQ0KICAgIHJvbGwNCg0KYGBgDQoNCg0KKipBcmd1bWVudHM6ICoqDQoNCmBgYHtyfQ0KDQogcm9sbDIgPC0gZnVuY3Rpb24oYm9uZXMgPSAxOjYpIHsgIA0KICAgICAgZGljZSA8LSBzYW1wbGUoYm9uZXMsIHNpemUgPSAyLCByZXBsYWNlID0gVFJVRSkgDQogICAgICBzdW0oZGljZSkgDQogICAgICB9IA0KICAgIA0KICAgIA0KICAgIHJvbGwyKCkNCiAgICByb2xsMg0KDQpgYGANCg0KRmluYWxseSwgeW91IGdpdmUgeW91ciBmdW5jdGlvbiBhIG5hbWUgYnkgc2F2aW5nIGl0cyBvdXRwdXQgdG8gYW4gUiBvYmplY3QsIGFzIHNob3duIGluIEZpZ3VyZSAyLTYuICANCg0KIVtdKDEtNi5QTkcpDQoNCmBgYHtyfQ0KDQojaHR0cHM6Ly9yc3R1ZGlvLWVkdWNhdGlvbi5naXRodWIuaW8vaG9wci9iYXNpY3MuaHRtbCNvYmplY3RzDQoNCmBgYA0KDQoNCioqU2NyaXB0czogKioNCg0KWW91IGNhbiBvcGVuIGFuIFIgc2NyaXB0IGluIFJTdHVkaW8gYnkgZ29pbmcgdG8gRmlsZSA+IE5ldyBGaWxlID4gUiBzY3JpcHQgaW4gdGhlIG1lbnUgYmFyLiBSU3R1ZGlvIHdpbGwgdGhlbiBvcGVuIGEgZnJlc2ggc2NyaXB0IGFib3ZlIHlvdXIgY29uc29sZSBwYW5lLCBhcyBzaG93biBpbiBGaWd1cmUgMS03LiBGaWd1cmUgMS04LiANCiAgICANCiFbXSgxLTcuUE5HKQ0KDQpgYGB7cn0NCg0KI2h0dHBzOi8vcnN0dWRpby1lZHVjYXRpb24uZ2l0aHViLmlvL2hvcHIvYmFzaWNzLmh0bWwjb2JqZWN0cw0KDQpgYGANCg0KIVtdKDEtOC5QTkcpDQoNCmBgYHtyfQ0KDQojaHR0cHM6Ly9yc3R1ZGlvLWVkdWNhdGlvbi5naXRodWIuaW8vaG9wci9iYXNpY3MuaHRtbCNvYmplY3RzDQoNCmBgYA0KDQoNCioqU3VtbWFyeTogKioNCg0KVGhlIHR3byBtb3N0IGltcG9ydGFudCBjb21wb25lbnRzIG9mIHRoZSBSIGxhbmd1YWdlIGFyZSANCg0KMS4gb2JqZWN0cywgd2hpY2ggc3RvcmUgZGF0YSwgYW5kIA0KDQoyLiBmdW5jdGlvbnMsIHdoaWNoIG1hbmlwdWxhdGUgZGF0YS4gWW91J2xsIGFsc28gbG9vayBhdCB0d28gb2YgdGhlIG1vc3QgdXNlZnVsIGNvbXBvbmVudHMgb2YgdGhlIFIgbGFuZ3VhZ2UuIA0KDQpSIHBhY2thZ2VzLCB3aGljaCBhcmUgY29sbGVjdGlvbnMgb2YgZnVuY3Rpb25zIHdyaXR0ZWQgYnkgUidzIHRhbGVudGVkIGNvbW11bml0eSBvZiBkZXZlbG9wZXJzLCBhbmQgUiBkb2N1bWVudGF0aW9uLCB3aGljaCBpcyBhIGNvbGxlY3Rpb24gb2YgaGVscCBwYWdlcyBidWlsdCBpbnRvIFIgdGhhdCBleHBsYWlucyBldmVyeSBmdW5jdGlvbiBhbmQgZGF0YSBzZXQgaW4gdGhlIGxhbmd1YWdlLg0KICAgIA0KDQoNCg0KDQojMi4gUGFja2FnZXMgYW5kIEhlbHAgUGFnZXMNCg0KTWFueSBvZiB0aGUgbW9zdCB1c2VmdWwgUiB0b29scyBjb21lIGluIFIgcGFja2FnZXMsIHNvIGxldCdzIHRha2UgYSBtb21lbnQgdG8gbG9vayBhdCB3aGF0IFIgcGFja2FnZXMgYXJlIGFuZCBob3cgeW91IGNhbiB1c2UgdGhlbS4gDQoNCg0KKipQYWNrYWdlczogKioNCg0KWW914oCZcmUgbm90IHRoZSBvbmx5IHBlcnNvbiB3cml0aW5nIHlvdXIgb3duIGZ1bmN0aW9ucyB3aXRoIFIuIE1hbnkgcHJvZmVzc29ycywgcHJvZ3JhbW1lcnMsIGFuZCBzdGF0aXN0aWNpYW5zIHVzZSBSIHRvIGRlc2lnbiB0b29scyB0aGF0IGNhbiBoZWxwIHBlb3BsZSBhbmFseXplIGRhdGEuIFRoZXkgdGhlbiBtYWtlIHRoZXNlIHRvb2xzIGZyZWUgZm9yIGFueW9uZSB0byB1c2UuIGBBcHBlbmRpeCAyOiBSIFBhY2thZ2VzYCBjb250YWlucyBkZXRhaWxlZCBpbnN0cnVjdGlvbnMgZm9yIGRvd25sb2FkaW5nIGFuZCB1cGRhdGluZyBSIHBhY2thZ2VzLg0KDQoNCldlJ3JlIGdvaW5nIHRvIHVzZSB0aGUgYHFwbG90YCBmdW5jdGlvbiB0byBtYWtlIHNvbWUgcXVpY2sgcGxvdHMuIHFwbG90IGNvbWVzIGluIHRoZSBgZ2dwbG90MmAgcGFja2FnZSwgYSBwb3B1bGFyIHBhY2thZ2UgZm9yIG1ha2luZyBncmFwaHMuIEJlZm9yZSB5b3UgY2FuIHVzZSBgcXBsb3RgLCBvciBhbnl0aGluZyBlbHNlIGluIHRoZSBgZ2dwbG90MmAgcGFja2FnZSwgeW91IG5lZWQgdG8gZG93bmxvYWQgYW5kIGluc3RhbGwgaXQuDQoNCioqSW5zdGFsbC5wYWNrYWdlczogKioNCg0KRWFjaCBSIHBhY2thZ2UgaXMgaG9zdGVkIGF0IGh0dHA6Ly9jcmFuLnItcHJvamVjdC5vcmcsIHRoZSBzYW1lIHdlYnNpdGUgdGhhdCBob3N0cyBSLiBIb3dldmVyLCB5b3UgZG9uJ3QgbmVlZCB0byB2aXNpdCB0aGUgd2Vic2l0ZSB0byBkb3dubG9hZCBhbiBSIHBhY2thZ2U7IFlvdSBjYW4gZG93bmxvYWQgcGFja2FnZXMgc3RyYWlnaHQgZnJvbSBSJ3MgY29tbWFuZCBsaW5lIGluIFJTdHVkaW8uDQoNCkhlcmUncyBob3c6DQoNCjEuIE9wZW4gUlN0dWRpby4gDQoyLiBNYWtlIHN1cmUgeW91IGFyZSBjb25uZWN0ZWQgdG8gdGhlIEludGVybmV0LiANCjMuIFJ1biBgaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpYCBhdCB0aGUgY29tbWFuZCBsaW5lLiANCg0KKipsaWJyYXJ5OiAqKg0KDQoNCkluc3RhbGxpbmcgYSBwYWNrYWdlIGRvZXNuJ3QgcGxhY2UgaXRzIGZ1bmN0aW9ucyBhdCB5b3VyIGZpbmdlcnRpcHMganVzdCB5ZXQ6IEl0IHNpbXBseSBwbGFjZXMgdGhlbSBpbiB5b3VyIGhhcmQgZHJpdmUuIFRvIHVzZSBhbiBSIHBhY2thZ2UsIHlvdSBuZXh0IGhhdmUgdG8gbG9hZCBpdCBpbiB5b3VyIFIgc2Vzc2lvbiB3aXRoIHRoZSBjb21tYW5kIGBsaWJyYXJ5KCJnZ3Bsb3QyIilgLiANCg0KDQpUaGUgbWFpbiB0aGluZyB0byByZW1lbWJlciBpcyB0aGF0IHlvdSBvbmx5IG5lZWQgdG8gaW5zdGFsbCBhIHBhY2thZ2Ugb25jZSwgYnV0IHlvdSBuZWVkIHRvIGxvYWQgaXQgd2l0aCBsaWJyYXJ5IGVhY2ggdGltZSB5b3Ugd2lzaCB0byB1c2UgaXQgaW4gYSBuZXcgUiBzZXNzaW9uLiBSIHdpbGwgdW5sb2FkIGFsbCBvZiBpdHMgcGFja2FnZXMgZWFjaCB0aW1lIHlvdSBjbG9zZSBSU3R1ZGlvLiANCg0KVGhlIGZvbGxvd2luZyBjb2RlIHdpbGwgbWFrZSB0aGUgcGxvdCB0aGF0IGFwcGVhcnMgaW4gRmlndXJlIDItMS4gDQoNCmBgYHtyfQ0KeCA8LSBjKC0xLCAtMC44LCAtMC42LCAtMC40LCAtMC4yLCAwLCAwLjIsIDAuNCwgMC42LCAwLjgsIDEpDQp4DQojIyAtMS4wIC0wLjggLTAuNiAtMC40IC0wLjIgIDAuMCAgMC4yICAwLjQgIDAuNiAgMC44ICAxLjANCg0KeSA8LSB4XjMNCnkNCiMjIC0xLjAwMCAtMC41MTIgLTAuMjE2IC0wLjA2NCAtMC4wMDggIDAuMDAwICAwLjAwOA0KIyMgIDAuMDY0ICAwLjIxNiAgMC41MTIgIDEuMDAwDQoNCnFwbG90KHgsIHkpDQpgYGANCg0KDQohW10oMi0xLlBORykNCg0KYGBge3J9DQoNCiNodHRwczovL3JzdHVkaW8tZWR1Y2F0aW9uLmdpdGh1Yi5pby9ob3ByL2Jhc2ljcy5odG1sI29iamVjdHMNCg0KYGBgDQoNCkdpdmUgYyBhbGwgb2YgdGhlIG51bWJlcnMgdGhhdCB5b3Ugd2FudCB0byBhcHBlYXIgaW4gdGhlIHZlY3Rvciwgc2VwYXJhdGVkIGJ5IGEgY29tbWEuIGMgc3RhbmRzIGZvciBjb25jYXRlbmF0ZSwgYnV0IHlvdSBjYW4gdGhpbmsgb2YgaXQgYXMgImNvbGxlY3QiIG9yICJjb21iaW5lIjoNCg0KYGBge3J9DQoNCnggPC0gYygtMSwgLTAuOCwgLTAuNiwgLTAuNCwgLTAuMiwgMCwgMC4yLCAwLjQsIDAuNiwgMC44LCAxKSANCnggIyMgLTEuMCAtMC44IC0wLjYgLTAuNCAtMC4yICAwLjAgIDAuMiAgMC40ICAwLjYgIDAuOCAgMS4wDQp5IDwtIHheMyANCnkgIyMgLTEuMDAwIC0wLjUxMiAtMC4yMTYgLTAuMDY0IC0wLjAwOCAgMC4wMDAgIDAuMDA4ICMjICAwLjA2NCAgMC4yMTYgIDAuNTEyICAxLjAwMA0KDQpwbG90KHgsIHkpDQoNCmBgYA0KDQoNClRoZSBmb2xsb3dpbmcgY29kZSBtYWtlcyB0aGUgbGVmdC1oYW5kIHBsb3QgaW4gRmlndXJlIDItMiAod2UnbGwgd29ycnkgYWJvdXQgdGhlIHJpZ2h0LWhhbmQgcGxvdCBpbiBqdXN0IHNlY29uZCkuIFRvIG1ha2Ugc3VyZSBvdXIgZ3JhcGhzIGxvb2sgdGhlIHNhbWUsIHVzZSB0aGUgZXh0cmEgYXJndW1lbnQgYmlud2lkdGggPSAxOg0KDQoNCiFbXSgyLTIuUE5HKQ0KDQpgYGB7cn0NCg0KI2h0dHBzOi8vcnN0dWRpby1lZHVjYXRpb24uZ2l0aHViLmlvL2hvcHIvYmFzaWNzLmh0bWwjb2JqZWN0cw0KDQpgYGANCg0KYGBge3J9DQoNCnggPC0gYygxLCAyLCAyLCAyLCAzLCAzKSANCmhpc3QoeCwgYmlud2lkdGggPSAxKQ0KDQoNCmBgYA0KDQpMZXQncyB0cnkgYW5vdGhlciBoaXN0b2dyYW0uIFRoaXMgY29kZSBtYWtlcyB0aGUgcmlnaHQtaGFuZCBwbG90IGluIEZpZ3VyZSAyLTIuDQoNCmBgYHtyfQ0KDQp4MiA8LSBjKDEsIDEsIDEsIDEsIDEsIDIsIDIsIDIsIDIsIDMsIDMsIDQpIA0KcGxvdCh4MiwgYmlud2lkdGggPSAxKQ0KDQoNCmBgYA0KDQoqKkV4ZXJjaXNlXzE6ICoqDQoNCkxldCB4MyBiZSB0aGUgZm9sbG93aW5nIHZlY3RvcjoNCg0KYGBge3J9DQp4MyA8LSBjKDAsIDEsIDEsIDIsIDIsIDIsIDMsIDMsIDQpDQp4Mw0KDQoNCmBgYA0KDQoNCiogSW1hZ2luZSB3aGF0IGEgaGlzdG9ncmFtIG9mIHgzIHdvdWxkIGxvb2sgbGlrZS4gDQoqIEFzc3VtZSB0aGF0IHRoZSBoaXN0b2dyYW0gaGFzIGEgYmluIHdpZHRoIG9mIDEuIA0KKiBIb3cgbWFueSBiYXJzIHdpbGwgdGhlIGhpc3RvZ3JhbSBoYXZlPyANCiogV2hlcmUgd2lsbCB0aGV5IGFwcGVhcj8gDQoqIEhvdyBoaWdoIHdpbGwgZWFjaCBiZT8gV2hlbiB5b3UgYXJlIGRvbmUsIHBsb3QgYSBoaXN0b2dyYW0gb2YgeDMgd2l0aCBiaW53aWR0aCA9IDEsIGFuZCBzZWUgaWYgeW91IGFyZSByaWdodC4NCg0KSG93IGNhbiB5b3UgdXNlIGEgaGlzdG9ncmFtIHRvIGNoZWNrIHRoZSBhY2N1cmFjeSBvZiB5b3VyIGRpY2U/IFdlbGwsIGlmIHlvdSByb2xsIHlvdXIgZGljZSBtYW55IHRpbWVzIGFuZCBrZWVwIHRyYWNrIG9mIHRoZSByZXN1bHRzLCB5b3Ugd291bGQgZXhwZWN0IHNvbWUgbnVtYmVycyB0byBvY2N1ciBtb3JlIHRoYW4gb3RoZXJzLiBUaGlzIGlzIGJlY2F1c2UgdGhlcmUgYXJlIG1vcmUgd2F5cyB0byBnZXQgc29tZSBudW1iZXJzIGJ5IGFkZGluZyB0d28gZGljZSB0b2dldGhlciB0aGFuIHRvIGdldCBvdGhlciBudW1iZXJzLCBhcyBzaG93biBpbiBGaWd1cmUgMi0zLiANCg0KIVtdKDItMy5QTkcpDQoNCmBgYHtyfQ0KDQojaHR0cHM6Ly9yc3R1ZGlvLWVkdWNhdGlvbi5naXRodWIuaW8vaG9wci9iYXNpY3MuaHRtbCNvYmplY3RzDQoNCmBgYA0KDQpUaGlzIGlzIHdoZXJlIHJlcGxpY2F0ZSBjb21lcyBpbi4gUmVwbGljYXRlIHByb3ZpZGVzIGFuIGVhc3kgd2F5IHRvIHJlcGVhdCBhbiBSIGNvbW1hbmQgbWFueSB0aW1lcy4gDQpUbyB1c2UgaXQsIGZpcnN0IGdpdmUgcmVwbGljYXRlIHRoZSBudW1iZXIgb2YgdGltZXMgeW91IHdpc2ggdG8gcmVwZWF0IGFuIFIgY29tbWFuZCwgYW5kIHRoZW4gZ2l2ZSBpdCB0aGUgY29tbWFuZCB5b3Ugd2lzaCB0byByZXBlYXQuIFJlcGxpY2F0ZSB3aWxsIHJ1biB0aGUgY29tbWFuZCBtdWx0aXBsZSB0aW1lcyBhbmQgc3RvcmUgdGhlIHJlc3VsdHMgYXMgYSB2ZWN0b3I6DQoNCmBgYHtyfQ0KDQpyb2xsIDwtIGZ1bmN0aW9uKCkgeyAgDQogICAgICBkaWUgPC0gMTo2ICANCiAgICAgIGRpY2UgPC0gc2FtcGxlKGRpZSwgc2l6ZSA9IDIsIHJlcGxhY2UgPSBUUlVFKSAgDQogICAgICBzdW0oZGljZSkgDQogICAgICB9IA0KDQpyZXBsaWNhdGUoMywgMSArIDEpIA0KcmVwbGljYXRlKDEwLCByb2xsKCkpIA0KICANCg0KYGBgDQoNClNvIGxldCdzIHNpbXVsYXRlIDEwLDAwMCBkaWNlIHJvbGxzIGFuZCBwbG90IHRoZSByZXN1bHRzLiBEb24ndCB3b3JyeTsgcXBsb3QgYW5kIHJlcGxpY2F0ZSBjYW4gaGFuZGxlIGl0LiBGaWd1cmUgMi00Og0KICANCiFbXSgyLTQuUE5HKQ0KDQpgYGB7cn0NCg0KI2h0dHBzOi8vcnN0dWRpby1lZHVjYXRpb24uZ2l0aHViLmlvL2hvcHIvYmFzaWNzLmh0bWwjb2JqZWN0cw0KDQpgYGANCg0KDQpgYGB7cn0NCg0Kcm9sbCA8LSBmdW5jdGlvbigpIHsgIA0KICAgIGRpZSA8LSAxOjYgIA0KICAgIGRpY2UgPC0gc2FtcGxlKGRpZSwgc2l6ZSA9IDIsIHJlcGxhY2UgPSBUUlVFKSAgDQogICAgc3VtKGRpY2UpIA0KICB9IA0KDQogIHJvbGxzIDwtIHJlcGxpY2F0ZSgxMCwgcm9sbCgpKSANCiAgaGlzdChyb2xscywgYmlud2lkdGggPSAxKSANCnJvbGxzDQoNCmBgYA0KDQoNClNlZSBgQXBwZW5kaXggQmAgYW5kIGBBcHBlbmRpeCBDYA0KDQoqKkdldHRpbmcgSGVscCB3aXRoIEhlbHAgUGFnZXM6ICoqDQoNClRoZXJlIGFyZSBvdmVyIDEsMDAwIGZ1bmN0aW9ucyBhdCB0aGUgY29yZSBvZiBSLCBhbmQgbmV3IFIgZnVuY3Rpb25zIGFyZSBjcmVhdGVkIGFsbCBvZiB0aGUgdGltZS4gVGhpcyBjYW4gYmUgYSBsb3Qgb2YgbWF0ZXJpYWwgdG8gbWVtb3JpemUgYW5kIGxlYXJuISBMdWNraWx5LCBlYWNoIFIgZnVuY3Rpb24gY29tZXMgd2l0aCBpdHMgb3duIGhlbHAgcGFnZSwgd2hpY2ggeW91IGNhbiBhY2Nlc3MgYnkgdHlwaW5nIHRoZSBmdW5jdGlvbidzIG5hbWUgYWZ0ZXIuDQoNCmBgYHtyfQ0KDQo/c3FydA0KP2xvZzEwIA0KP3NhbXBsZQ0KDQpgYGANCg0KDQpIZXJlLCBhbG1vc3QgZXZlcnkgaGVscCBwYWdlIGluY2x1ZGVzIHNvbWUgZXhhbXBsZSBjb2RlIHRoYXQgcHV0cyB0aGUgZnVuY3Rpb24gaW4gYWN0aW9uLiBSdW5uaW5nIHRoaXMgY29kZSBpcyBhIGdyZWF0IHdheSB0byBsZWFybiBieSBleGFtcGxlLg0KDQo+IE5vdGU6IElmIGEgZnVuY3Rpb24gY29tZXMgaW4gYW4gUiBwYWNrYWdlLCBSIHdvbid0IGJlIGFibGUgdG8gZmluZCBpdHMgaGVscCBwYWdlIHVubGVzcyB0aGUgcGFja2FnZSBpcyBsb2FkZWQuDQoNCg0KKipQYXJ0cyBvZiBhIEhlbHAgUGFnZTogKioNCg0KRWFjaCBoZWxwIHBhZ2UgaXMgZGl2aWRlZCBpbnRvIHNlY3Rpb25zLiBXaGljaCBzZWN0aW9ucyBhcHBlYXIgY2FuIHZhcnkgZnJvbSBoZWxwIHBhZ2UgdG8gaGVscCBwYWdlLCBidXQgeW91IGNhbiB1c3VhbGx5IGV4cGVjdCB0byBmaW5kIHRoZXNlIHVzZWZ1bCB0b3BpY3M6IA0KDQoqIC1EZXNjcmlwdGlvbg0KKiAtVXNhZ2UNCiogLUFyZ3VtZW50cw0KKiAtRGV0YWlscw0KKiAtVmFsdWUNCg0KSWYgeW91J2QgbGlrZSB0byBsb29rIHVwIHRoZSBoZWxwIHBhZ2UgZm9yIGEgZnVuY3Rpb24gYnV0IGhhdmUgZm9yZ290dGVuIHRoZSBmdW5jdGlvbidzIG5hbWUsIHlvdSBjYW4gc2VhcmNoIGJ5IGtleXdvcmQuICANCg0KVG8gZG8gdGhpcywgdHlwZSB0d28gcXVlc3Rpb24gbWFya3MgZm9sbG93ZWQgYnkgYSBrZXl3b3JkIGluIFIncyBjb21tYW5kIGxpbmUuIFIgd2lsbCBwdWxsIHVwIGEgbGlzdCBvZiBsaW5rcyB0byBoZWxwIHBhZ2VzIHJlbGF0ZWQgdG8gdGhlIGtleXdvcmQuIFlvdSBjYW4gdGhpbmsgb2YgdGhpcyBhcyB0aGUgaGVscCBwYWdlIGZvciB0aGUgaGVscCBwYWdlOg0KDQpgYGB7cn0NCg0KPz9sb2cNCg0KYGBgDQoNCg0KDQoqKkV4ZXJjaXNlXzI6ICoqDQoNClJld3JpdGUgdGhlIHJvbGwgZnVuY3Rpb24gdG8gcm9sbCBhIHBhaXIgb2Ygd2VpZ2h0ZWQgZGljZToNCg0KYGBge3J9DQoNCnJvbGwgPC0gZnVuY3Rpb24oKSB7ICANCiAgICBkaWUgPC0gMTo2ICANCiAgICBkaWNlIDwtIHNhbXBsZShkaWUsIHNpemUgPSAyLCByZXBsYWNlID0gVFJVRSkgIA0KICAgIHN1bShkaWNlKSANCiAgICB9IA0KDQpgYGANCg0KWW91IHdpbGwgbmVlZCB0byBhZGQgYSBgcHJvYmAgYXJndW1lbnQgdG8gdGhlIHNhbXBsZSBmdW5jdGlvbiBpbnNpZGUgb2Ygcm9sbC4gVGhpcyBhcmd1bWVudCBzaG91bGQgdGVsbCBzYW1wbGUgdG8gc2FtcGxlIHRoZSBudW1iZXJzIG9uZSB0aHJvdWdoIGZpdmUgd2l0aCBwcm9iYWJpbGl0eSAxLzggYW5kIHRoZSBudW1iZXIgNiB3aXRoIHByb2JhYmlsaXR5IDMvOC4NCg0KDQoNCmBgYHtyfQ0KDQpyb2xsIDwtIGZ1bmN0aW9uKCkgeyAgDQogICAgICAgZGllIDwtIDE6NiAgDQogICAgICAgZGljZSA8LSBzYW1wbGUoZGllLCBzaXplID0gMiwgcmVwbGFjZSA9IFRSVUUsICAgIHByb2IgPSBjKDEvOCwgMS84LCAxLzgsIDEvOCwgMS84LCAzLzgpKSAgDQogICAgICAgDQogICAgICAgc3VtKGRpY2UpIA0KICAgICAgIH0gDQoNCg0Kcm9sbCgpDQoNCmBgYA0KDQpUaGlzIHdpbGwgY2F1c2Ugcm9sbCB0byBwaWNrIDEgdGhyb3VnaCA1IHdpdGggcHJvYmFiaWxpdHkgMS84IGFuZCA2IHdpdGggcHJvYmFiaWxpdHkgMy84Lg0KDQpgYGB7cn0NCg0Kcm9sbHMgPC0gcmVwbGljYXRlKDEwMDAwLCByb2xsKCkpIA0KaGlzdChyb2xscywgYmlud2lkdGggPSAxKQ0KDQpgYGANCg0KDQohW10oMi01LlBORykNCg0KYGBge3J9DQoNCiNodHRwczovL3JzdHVkaW8tZWR1Y2F0aW9uLmdpdGh1Yi5pby9ob3ByL2Jhc2ljcy5odG1sI29iamVjdHMNCg0KYGBgDQoNCg0KKipHZXR0aW5nIE1vcmUgSGVscDogKioNCg0KKiBSIGFsc28gY29tZXMgd2l0aCBhIHN1cGVyIGFjdGl2ZSBjb21tdW5pdHkgb2YgdXNlcnMgdGhhdCB5b3UgY2FuIHR1cm4gdG8gZm9yIGhlbHAgb24gdGhlIFItaGVscCBtYWlsaW5nIGxpc3QuIGh0dHBzOi8vY29tbXVuaXR5LnJzdHVkaW8uY29tLw0KDQoqIFlvdSBjYW4gZW1haWwgdGhlIGxpc3Qgd2l0aCBxdWVzdGlvbnMsIGJ1dCB0aGVyZSdzIGEgZ3JlYXQgY2hhbmNlIHRoYXQgeW91ciBxdWVzdGlvbiBoYXMgYWxyZWFkeSBiZWVuIGFuc3dlcmVkLiANCg0KKiBGaW5kIG91dCBieSBzZWFyY2hpbmcgdGhlIGFyY2hpdmVzLiANCg0KRXZlbiBiZXR0ZXIgdGhhbiB0aGUgUi1oZWxwIGxpc3QgaXMgYFN0YWNrIE92ZXJmbG93YCwgYSB3ZWJzaXRlIHRoYXQgYWxsb3dzIHByb2dyYW1tZXJzIHRvIGFuc3dlciBxdWVzdGlvbnMgYW5kIHVzZXJzIHRvIHJhbmsgYW5zd2VycyBiYXNlZCBvbiBoZWxwZnVsbmVzcy4gDQoNCg0KDQoqKlN1bW1hcnk6ICoqDQoNCiogUidzIHBhY2thZ2VzIGFuZCBoZWxwIHBhZ2VzIGNhbiBtYWtlIHlvdSBhIG1vcmUgcHJvZHVjdGl2ZSBwcm9ncmFtbWVyLg0KDQoqIE9mdGVuIHRoZSBmdW5jdGlvbiB0aGF0IHlvdSB3YW50IHRvIHdyaXRlIHdpbGwgYWxyZWFkeSBleGlzdCBpbiBhbiBSIHBhY2thZ2UuIA0KDQoqIGBpbnN0YWxsLnBhY2thZ2VzYCwgYW5kIHRoZW4gbG9hZCBpdCBpbnRvIGVhY2ggbmV3IFIgc2Vzc2lvbiB3aXRoIGBsaWJyYXJ5YCBmb3IgdXNpbmcgcGFja2FnZS4NCg0KKiBSJ3MgaGVscCBwYWdlcyB3aWxsIGhlbHAgeW91IG1hc3RlciB0aGUgZnVuY3Rpb25zIHRoYXQgYXBwZWFyIGluIFIgYW5kIGl0cyBwYWNrYWdlcy4NCg0KDQojPT1Qcm9qZWN0IDI6IFBsYXlpbmcgQ2FyZHM9PQ0KDQpIb3cgdG8gc3RvcmUsIHJldHJpZXZlLCBhbmQgY2hhbmdlIGRhdGEgdmFsdWVzIGluIHlvdXIgY29tcHV0ZXIncyBtZW1vcnkuIFRoZXNlIHNraWxscyB3aWxsIGhlbHAgeW91IHNhdmUgYW5kIG1hbmFnZSBkYXRhIHdpdGhvdXQgYWNjdW11bGF0aW5nIGVycm9ycy4NCg0KQWxvbmcgdGhlIHdheSwgeW91IHdpbGwgbGVhcm4gaG93IHRvOg0KDQoqIFNhdmUgbmV3IHR5cGVzIG9mIGRhdGEsIGxpa2UgY2hhcmFjdGVyIHN0cmluZ3MgYW5kIGxvZ2ljYWwgdmFsdWVzDQoqIFNhdmUgYSBkYXRhIHNldCBhcyBhIHZlY3RvciwgbWF0cml4LCBhcnJheSwgbGlzdCwgb3IgZGF0YSBmcmFtZQ0KKiBMb2FkIGFuZCBzYXZlIHlvdXIgb3duIGRhdGEgc2V0cyB3aXRoIFINCiogRXh0cmFjdCBpbmRpdmlkdWFsIHZhbHVlcyBmcm9tIGEgZGF0YSBzZXQNCiogQ2hhbmdlIGluZGl2aWR1YWwgdmFsdWVzIHdpdGhpbiBhIGRhdGEgc2V0DQoqIFdyaXRlIGxvZ2ljYWwgdGVzdHMNCiogVXNlIFIncyBtaXNzaW5nLXZhbHVlIHN5bWJvbCwgTkENCg0KV2UndmUgZGl2aWRlZCBpdCBpbnRvIGZvdXIgdGFza3MuIEVhY2ggdGFzayB3aWxsIHRlYWNoIHlvdSBhIG5ldyBza2lsbCBmb3IgbWFuYWdpbmcgZGF0YSB3aXRoIFI6DQoNCioqVGFzayAxOiBidWlsZCB0aGUgZGVjayoqDQpJbiBSIE9iamVjdHMsIHlvdSB3aWxsIGRlc2lnbiBhbmQgYnVpbGQgYSB2aXJ0dWFsIGRlY2sgb2YgcGxheWluZyBjYXJkcy4gVGhpcyB3aWxsIGJlIGEgY29tcGxldGUgZGF0YSBzZXQsIGp1c3QgbGlrZSB0aGUgb25lcyB5b3Ugd2lsbCB1c2UgYXMgYSBkYXRhIHNjaWVudGlzdC4gWW91J2xsIG5lZWQgdG8ga25vdyBob3cgdG8gdXNlIFIncyBkYXRhIHR5cGVzIGFuZCBkYXRhIHN0cnVjdHVyZXMgdG8gbWFrZSB0aGlzIHdvcmsuDQoNCioqVGFzayAyOiB3cml0ZSBmdW5jdGlvbnMgdGhhdCBkZWFsIGFuZCBzaHVmZmxlKioNCk5leHQsIGluIFIgTm90YXRpb24sIHlvdSB3aWxsIHdyaXRlIHR3byBmdW5jdGlvbnMgdG8gdXNlIHdpdGggdGhlIGRlY2suIE9uZSBmdW5jdGlvbiB3aWxsIGRlYWwgY2FyZHMgZnJvbSB0aGUgZGVjaywgYW5kIHRoZSBvdGhlciB3aWxsIHJlc2h1ZmZsZSB0aGUgZGVjay4gVG8gd3JpdGUgdGhlc2UgZnVuY3Rpb25zLCB5b3UnbGwgbmVlZCB0byBrbm93IGhvdyB0byBleHRyYWN0IHZhbHVlcyBmcm9tIGEgZGF0YSBzZXQgd2l0aCBSLg0KDQoqKlRhc2sgMzogY2hhbmdlIHRoZSBwb2ludCBzeXN0ZW0gdG8gc3VpdCB5b3VyIGdhbWUqKg0KSW4gTW9kaWZ5aW5nIFZhbHVlcywgeW91IHdpbGwgdXNlIFIncyBub3RhdGlvbiBzeXN0ZW0gdG8gY2hhbmdlIHRoZSBwb2ludCB2YWx1ZXMgb2YgeW91ciBjYXJkcyB0byBtYXRjaCB0aGUgY2FyZCBnYW1lcyB5b3UgbWF5IHdpc2ggdG8gcGxheSwgbGlrZSB3YXIsIGhlYXJ0cywgb3IgYmxhY2tqYWNrLiBUaGlzIHdpbGwgaGVscCB5b3UgY2hhbmdlIHZhbHVlcyBpbiBwbGFjZSBpbiBleGlzdGluZyBkYXRhIHNldHMuDQoNCioqVGFzayA0OiBtYW5hZ2UgdGhlIHN0YXRlIG9mIHRoZSBkZWNrKioNCkZpbmFsbHksIGluIEVudmlyb25tZW50cywgeW91IHdpbGwgbWFrZSBzdXJlIHRoYXQgeW91ciBkZWNrIHJlbWVtYmVycyB3aGljaCBjYXJkcyBpdCBoYXMgZGVhbHQuIFRoaXMgaXMgYW4gYWR2YW5jZWQgdGFzaywgYW5kIGl0IHdpbGwgaW50cm9kdWNlIFIncyBlbnZpcm9ubWVudCBzeXN0ZW0gYW5kIHNjb3BpbmcgcnVsZXMuIFRvIGRvIGl0IHN1Y2Nlc3NmdWxseSwgeW91IHdpbGwgbmVlZCB0byBsZWFybiB0aGUgbWludXRlIGRldGFpbHMgb2YgaG93IFIgbG9va3MgdXAgYW5kIHVzZXMgdGhlIGRhdGEgdGhhdCB5b3UgaGF2ZSBzdG9yZWQgaW4geW91ciBjb21wdXRlci4NCg0KDQoNCiMzLiBSIE9iamVjdHMNCg0KKipBdG9taWMgVmVjdG9yczogKioNCg0KWW91IGNhbiBtYWtlIGFuIGF0b21pYyB2ZWN0b3IgYnkgZ3JvdXBpbmcgc29tZSB2YWx1ZXMgb2YgZGF0YSB0b2dldGhlciB3aXRoIGBjYDoNCg0KYGBge3J9DQpkaWUgPC0gYygxLCAyLCAzLCA0LCA1LCA2KSANCmRpZQ0KDQppcy52ZWN0b3IoZGllKSANCg0KI2lzLnZlY3RvciB0ZXN0cyB3aGV0aGVyIGFuIG9iamVjdCBpcyBhbiBhdG9taWMgdmVjdG9yLiANCiNJdCByZXR1cm5zIFRSVUUgaWYgdGhlIG9iamVjdCBpcyBhbiBhdG9taWMgdmVjdG9yIGFuZCBGQUxTRSBvdGhlcndpc2UuDQoNCmBgYA0KDQpZb3UgY2FuIGFsc28gbWFrZSBhbiBhdG9taWMgdmVjdG9yIHdpdGgganVzdCBvbmUgdmFsdWUuIFIgc2F2ZXMgc2luZ2xlIHZhbHVlcyBhcyBhbiBhdG9taWMgdmVjdG9yIG9mIGxlbmd0aCAxOg0KDQpgYGB7cn0NCmZpdmUgPC0gNSANCmZpdmUgIyMgNQ0KaXMudmVjdG9yKGZpdmUpIA0KIyMgIFRSVUUNCmxlbmd0aChmaXZlKSANCiMjIDEgDQpsZW5ndGgoZGllKSANCiMjIDYNCg0KIyEhIWxlbmd0aCByZXR1cm5zIHRoZSBsZW5ndGggb2YgYW4gYXRvbWljIHZlY3Rvci4NCg0KYGBgDQogIA0KRWFjaCBhdG9taWMgdmVjdG9yIHN0b3JlcyBpdHMgdmFsdWVzIGFzIGEgb25lLWRpbWVuc2lvbmFsIHZlY3RvciwgYW5kIGVhY2ggYXRvbWljIHZlY3RvciBjYW4gb25seSBzdG9yZSBvbmUgdHlwZSBvZiBkYXRhLiBZb3UgY2FuIHNhdmUgZGlmZmVyZW50IHR5cGVzIG9mIGRhdGEgaW4gUiBieSB1c2luZyBkaWZmZXJlbnQgdHlwZXMgb2YgYXRvbWljIHZlY3RvcnMuIEFsdG9nZXRoZXIsIFIgcmVjb2duaXplcyBzaXggYmFzaWMgdHlwZXMgb2YgYXRvbWljIHZlY3RvcnM6IGRvdWJsZXMsIGludGVnZXJzLCBjaGFyYWN0ZXJzLCBsb2dpY2FscywgY29tcGxleCwgYW5kIHJhdy4gDQoNCg0KWW91IGNhbiBkbyB0aGlzIGJ5IHVzaW5nIHNvbWUgc2ltcGxlIGNvbnZlbnRpb25zIHdoZW4geW91IGVudGVyIHlvdXIgZGF0YS4gRm9yIGV4YW1wbGUsIHlvdSBjYW4gY3JlYXRlIGFuIGludGVnZXIgdmVjdG9yIGJ5IGluY2x1ZGluZyBhIGNhcGl0YWwgTCB3aXRoIHlvdXIgaW5wdXQuIFlvdSBjYW4gY3JlYXRlIGEgY2hhcmFjdGVyIHZlY3RvciBieSBzdXJyb3VuZGluZyB5b3VyIGlucHV0IGluIHF1b3RhdGlvbiBtYXJrczoNCg0KYGBge3J9DQppbnQgPC0gMUwgDQppbnQNCnRleHQgPC0gImFjZSIgDQp0ZXh0DQpgYGANCg0KSWYgeW91J2QgbGlrZSB0byBtYWtlIGF0b21pYyB2ZWN0b3JzIHRoYXQgaGF2ZSBtb3JlIHRoYW4gb25lIGVsZW1lbnQgaW4gdGhlbSwgeW91IGNhbiBjb21iaW5lIGFuIGVsZW1lbnQgd2l0aCB0aGUgYGNgIGZ1bmN0aW9uLg0KDQpgYGB7cn0NCmludCA8LSBjKDFMLCA1TCkgDQp0ZXh0IDwtIGMoImFjZSIsICJoZWFydHMiKSANCiAgDQpgYGANCg0KWW91IG1heSB3b25kZXIgd2h5IFIgdXNlcyBtdWx0aXBsZSB0eXBlcyBvZiB2ZWN0b3JzLiBWZWN0b3IgdHlwZXMgaGVscCBSIGJlaGF2ZSBhcyB5b3Ugd291bGQgZXhwZWN0LiBGb3IgZXhhbXBsZSwgUiB3aWxsIGRvIG1hdGggd2l0aCBhdG9taWMgdmVjdG9ycyB0aGF0IGNvbnRhaW4gbnVtYmVycywgYnV0IG5vdCB3aXRoIGF0b21pYyB2ZWN0b3JzIHRoYXQgY29udGFpbiBjaGFyYWN0ZXIgc3RyaW5nczoNCg0KYGBge3J9DQpzdW0oaW50KSAjIyA2DQpzdW0odGV4dCkgIyMgRXJyb3IgaW4gc3VtKHRleHQpIDogaW52YWxpZCAndHlwZScgKGNoYXJhY3Rlcikgb2YgYXJndW1lbnQgDQoNCmBgYA0KDQoNCkJ1dCB3ZSdyZSBnZXR0aW5nIGFoZWFkIG9mIG91cnNlbHZlcyEgR2V0IHJlYWR5IHRvIHNheSBoZWxsbyB0byB0aGUgKipzaXggdHlwZXMgb2YgYXRvbWljIHZlY3RvcnMgaW4gUioqLiANCg0KKiAxLURvdWJsZXMNCg0KYGBge3J9DQpkaWUgPC0gYygxLCAyLCAzLCA0LCA1LCA2KSANCmRpZSAjIyAxIDIgMyA0IDUgNiANCg0KdHlwZW9mKGRpZSkgIyMgICJkb3VibGUiIA0KICAgIA0KYGBgDQoNCiogMi1JbnRlZ2Vycw0KDQpgYGB7cn0NCmludCA8LSBjKC0xTCwgMkwsIDRMKSANCiAgICBpbnQgIyMgLTEgIDIgIDQNCiAgICB0eXBlb2YoaW50KSAjIyAiaW50ZWdlciIgDQpgYGANCg0KDQoqIDMtQ2hhcmFjdGVycw0KDQpgYGB7cn0NCnRleHQgPC0gYygiSGVsbG8iLCAgIldvcmxkIikgDQogICAgdGV4dCAjIyAgIkhlbGxvIiAgIldvcmxkIg0KICAgIHR5cGVvZih0ZXh0KSAjIyAiY2hhcmFjdGVyIg0KICAgIHR5cGVvZigiSGVsbG8iKSAjIyAiY2hhcmFjdGVyIiANCg0KYGBgDQoNCiogNC1Mb2dpY2Fscw0KDQpgYGB7cn0NCjMgPiA0IA0KICAgICMjIEZBTFNFIA0KICAgIA0KICAgIGxvZ2ljIDwtIGMoVFJVRSwgRkFMU0UsIFRSVUUpIA0KICAgIGxvZ2ljICMjICAgVFJVRSBGQUxTRSAgVFJVRQ0KICAgIHR5cGVvZihsb2dpYykgIyMgImxvZ2ljYWwiDQogICAgdHlwZW9mKEYpICMjICJsb2dpY2FsIiANCiAgICANCmBgYA0KDQoqIDUtQ29tcGxleCANCg0KYGBge3J9DQp4IDwtIDENCnkgPC0gMQ0KIA0KY29tcDwtIGNvbXBsZXgocmVhbCA9IHgsIGltYWdpbmFyeSA9IHkpDQogDQp0eXBlb2YoY29tcCkgIyMgImNvbXBsZXgiIA0KICAgIA0KYGBgDQoNCg0KKiA2LVJhdw0KDQpSYXcgdmVjdG9ycyBzdG9yZSByYXcgYnl0ZXMgb2YgZGF0YS4gTWFraW5nIHJhdyB2ZWN0b3JzIGdldHMgY29tcGxpY2F0ZWQsIGJ1dCB5b3UgY2FuIG1ha2UgYW4gZW1wdHkgcmF3IHZlY3RvciBvZiBsZW5ndGggbiB3aXRoIHJhdyhuKS4gU2VlIHRoZSBoZWxwIHBhZ2Ugb2YgcmF3IGZvciBtb3JlIG9wdGlvbnMgd2hlbiB3b3JraW5nIHdpdGggdGhpcyB0eXBlIG9mIGRhdGE6DQogICAgDQoNCmBgYHtyfQ0KIw0KICAgIHJhdygzKSANCiAgICAgICMjIDAwIDAwIDAwDQogICAgdHlwZW9mKHJhdygzKSkNCiAgICAjIyAicmF3Ig0KYGBgDQoNCiogRXhlcmNpc2UNCg0KQ3JlYXRlIGFuIGF0b21pYyB2ZWN0b3IgdGhhdCBzdG9yZXMganVzdCB0aGUgZmFjZSBuYW1lcyBvZiB0aGUgY2FyZHMgaW4gYSByb3lhbCBmbHVzaCwgZm9yIGV4YW1wbGUsIHRoZSBhY2Ugb2Ygc3BhZGVzLCBraW5nIG9mIHNwYWRlcywgcXVlZW4gb2Ygc3BhZGVzLCBqYWNrIG9mIHNwYWRlcywgYW5kIHRlbiBvZiBzcGFkZXMuIFRoZSBmYWNlIG5hbWUgb2YgdGhlIGFjZSBvZiBzcGFkZXMgd291bGQgYmUgImFjZSwiIGFuZCAic3BhZGVzIiBpcyB0aGUgc3VpdC4gV2hpY2ggdHlwZSBvZiB2ZWN0b3Igd2lsbCB5b3UgdXNlIHRvIHNhdmUgdGhlIG5hbWVzPw0KDQoNCmBgYHtyfQ0KaGFuZCA8LSBjKCJhY2UiLCAia2luZyIsICJxdWVlbiIsICJqYWNrIiwgInRlbiIpIA0KICAgIGhhbmQgDQogICAgIyMgImFjZSIgICAia2luZyIgICJxdWVlbiIgImphY2siICAidGVuIg0KICAgIHR5cGVvZihoYW5kKQ0KICAgICMjICJjaGFyYWN0ZXIiIA0KYGBgDQoNCioqQXR0cmlidXRlczogKioNCg0KWW91IGNhbiB0aGluayBvZiBhbiBhdHRyaWJ1dGUgYXMgIm1ldGFkYXRhIjsgaXQgaXMganVzdCBhIGNvbnZlbmllbnQgcGxhY2UgdG8gcHV0IGluZm9ybWF0aW9uIGFzc29jaWF0ZWQgd2l0aCBhbiBvYmplY3QuICANCg0KYGBge3J9DQpkaWUgPC0gYygxLCAyLCAzLCA0LCA1LCA2KSANCg0KYXR0cmlidXRlcyhkaWUpDQogICMjIE5VTEwNCmBgYA0KDQpUaGUgbW9zdCBjb21tb24gYXR0cmlidXRlcyB0byBnaXZlIGFuIGF0b21pYyB2ZWN0b3IgYXJlIG5hbWVzLCBkaW1lbnNpb25zIChkaW0pLCBhbmQgY2xhc3Nlcy4gDQoNCg0KTm90ZTogUiB1c2VzIE5VTEwgdG8gcmVwcmVzZW50IHRoZSBudWxsIHNldCwgYW4gZW1wdHkgb2JqZWN0LiBOVUxMIGlzIG9mdGVuIHJldHVybmVkIGJ5IGZ1bmN0aW9ucyB3aG9zZSB2YWx1ZXMgYXJlIHVuZGVmaW5lZC4gWW91IGNhbiBjcmVhdGUgYSBOVUxMIG9iamVjdCBieSB0eXBpbmcgTlVMTCBpbiBjYXBpdGFsIGxldHRlcnMuDQogIA0KDQoqIE5hbWVzOg0KDQpgYGB7cn0NCmRpZSA8LSBjKDEsIDIsIDMsIDQsIDUsIDYpIA0KbmFtZXMoZGllKSAjIyBOVUxMIA0KbmFtZXMoZGllKSA8LSBjKCJvbmUiLCAidHdvIiwgInRocmVlIiwgImZvdXIiLCAiZml2ZSIsICJzaXgiKSANCm5hbWVzKGRpZSkgIyMgIm9uZSIgICAidHdvIiAgICJ0aHJlZSIgImZvdXIiICAiZml2ZSIgICJzaXgiDQphdHRyaWJ1dGVzKGRpZSkNCiAgDQpgYGANCg0KUiB3aWxsIGRpc3BsYXkgdGhlIG5hbWVzIGFib3ZlIHRoZSBlbGVtZW50cyBvZiBkaWUgd2hlbmV2ZXIgeW91IGxvb2sgYXQgdGhlIHZlY3RvcjogDQoNCmBgYHtyfQ0KIGRpZQ0KYGBgDQoNClRvIHJlbW92ZSB0aGUgbmFtZXMgYXR0cmlidXRlLCBzZXQgaXQgdG8gTlVMTDoNCg0KYGBge3J9DQpuYW1lcyhkaWUpIDwtIE5VTEwgDQogIGRpZSANCmBgYA0KDQoqIERpbToNCg0KWW91IGNhbiB0cmFuc2Zvcm0gYW4gYXRvbWljIHZlY3RvciBpbnRvIGFuIG4tZGltZW5zaW9uYWwgYXJyYXkgYnkgZ2l2aW5nIGl0IGEgZGltZW5zaW9ucyBhdHRyaWJ1dGUgd2l0aCBkaW0uDQoNCg0KYGBge3J9DQpkaWUgPC0gYygxLCAyLCAzLCA0LCA1LCA2KSAgDQogIGRpbShkaWUpIDwtIGMoMiwgMykgDQpkaWUgICANCiAgICANCmRpbShkaWUpIDwtIGMoMywgMikgDQpkaWUgDQogIA0KZGltKGRpZSkgPC0gYygxLCAyLCAzKSAjYXMgQXJyYXlzOiAzIEFycmF5cw0KZGllDQpgYGANCg0KRm9yIGV4YW1wbGUsIFIgYWx3YXlzIGZpbGxzIHVwIGVhY2ggbWF0cml4IGJ5IGNvbHVtbnMsIGluc3RlYWQgb2YgYnkgcm93cy4gSWYgeW91J2QgbGlrZSBtb3JlIGNvbnRyb2wgb3ZlciB0aGlzIHByb2Nlc3MsIHlvdSBjYW4gdXNlIG9uZSBvZiBSJ3MgaGVscGVyIGZ1bmN0aW9ucywgbWF0cml4IG9yIGFycmF5LiBUaGV5IGRvIHRoZSBzYW1lIHRoaW5nIGFzIGNoYW5naW5nIHRoZSBkaW0gYXR0cmlidXRlLCBidXQgdGhleSBwcm92aWRlIGV4dHJhIGFyZ3VtZW50cyB0byBjdXN0b21pemUgdGhlIHByb2Nlc3MuIA0KDQoNCioqTWF0cmljZXM6ICoqDQoNCmBgYHtyfQ0KZGllIDwtIGMoMSwgMiwgMywgNCwgNSwgNikNCg0KbSA8LSBtYXRyaXgoZGllLCBucm93ID0gMikgDQptIA0KYGBgDQoNCg0KTWF0cml4IHdpbGwgZmlsbCB1cCB0aGUgbWF0cml4IGNvbHVtbiBieSBjb2x1bW4gYnkgZGVmYXVsdCwgYnV0IHlvdSBjYW4gZmlsbCB0aGUgbWF0cml4IHJvdyBieSByb3cgaWYgeW91IGluY2x1ZGUgdGhlIGFyZ3VtZW50IGBieXJvdyA9IFRSVUVgOg0KDQpgYGB7cn0NCm1tIDwtIG1hdHJpeChkaWUsIG5yb3cgPSAyLCBieXJvdyA9IFRSVUUpIA0KbW0NCmBgYA0KDQoqKkFycmF5czogKioNCg0KVGhlIGFycmF5IGZ1bmN0aW9uIGNyZWF0ZXMgYW4gbi1kaW1lbnNpb25hbCBNYXRyaXguIA0KDQpgYGB7cn0NCmFyIDwtIGFycmF5KGMoMTE6MTQsIDIxOjI0LCAzMTozNCksIGRpbSA9IGMoMiwgMiwgMykpIA0KYXINCmBgYA0KDQoNCkV4ZXJjaXNlOg0KDQpDcmVhdGUgdGhlIGZvbGxvd2luZyBtYXRyaXgsIHdoaWNoIHN0b3JlcyB0aGUgbmFtZSBhbmQgc3VpdCBvZiBldmVyeSBjYXJkIGluIGEgcm95YWwgZmx1c2guDQoNCmBgYHtyfQ0KaGFuZDEgPC0gYygiYWNlIiwgImtpbmciLCAicXVlZW4iLCAiamFjayIsICJ0ZW4iLCAic3BhZGVzIiwgInNwYWRlcyIsICAic3BhZGVzIiwgInNwYWRlcyIsICJzcGFkZXMiKQ0KbWF0cml4KGhhbmQxLCBucm93ID0gNSkgDQptYXRyaXgoaGFuZDEsIG5jb2wgPSAyKSANCmRpbShoYW5kMSkgPC0gYyg1LCAyKSANCmhhbmQxDQoNCg0KdGVzdDwtbWF0cml4KGhhbmQxLG5yb3c9NSwgbmNvbD0yKQ0KdGVzdA0KDQpgYGANCg0KDQoqKkNsYXNzOiAqKg0KDQpgYGB7cn0NCmNsYXNzKCJIZWxsbyIpDQojIyAgImNoYXJhY3RlciINCg0KDQpjbGFzcyg1KSAjIyAgDQoibnVtZXJpYyIgDQoNCmBgYA0KDQoqIERhdGVzIGFuZCBUaW1lczoNCg0KYGBge3J9DQpub3cgPC0gU3lzLnRpbWUoKSANCm5vdw0KDQoNCnR5cGVvZihub3cpICMjICAiZG91YmxlIg0KY2xhc3Mobm93KSAjIyAiUE9TSVhjdCIgIlBPU0lYdCIgDQoNCg0KYGBgDQoNCiogRmFjdG9yczoNCg0KRmFjdG9ycyBhcmUgUidzIHdheSBvZiBzdG9yaW5nIGNhdGVnb3JpY2FsIGluZm9ybWF0aW9uLCBsaWtlIGV0aG5pY2l0eSBvciBleWUgY29sb3IuIFRoaW5rIG9mIGEgZmFjdG9yIGFzIHNvbWV0aGluZyBsaWtlIGEgZ2VuZGVyOyBpdCBjYW4gb25seSBoYXZlIGNlcnRhaW4gdmFsdWVzIChtYWxlIG9yIGZlbWFsZSkuIA0KDQoNCmBgYHtyfQ0KZ2VuZGVyIDwtIGZhY3RvcihjKCJtYWxlIiwgImZlbWFsZSIsICJmZW1hbGUiLCAibWFsZSIpKQ0KZ2VuZGVyDQp0eXBlb2YoZ2VuZGVyKSANCg0KYXR0cmlidXRlcyhnZW5kZXIpIA0KDQpgYGANCg0KWW91IGNhbiBzZWUgZXhhY3RseSBob3cgUiBpcyBzdG9yaW5nIHlvdXIgZmFjdG9yIHdpdGggdW5jbGFzczogDQoNCmBgYHtyfQ0KZ2VuZGVyIDwtIGZhY3RvcihjKCJtYWxlIiwgImZlbWFsZSIsICJmZW1hbGUiLCAibWFsZSIpKQ0KDQp1bmNsYXNzKGdlbmRlcikNCmdlbmRlcg0KDQpgYGANCg0KRmFjdG9ycyBtYWtlIGl0IGVhc3kgdG8gcHV0IGNhdGVnb3JpY2FsIHZhcmlhYmxlcyBpbnRvIGEgc3RhdGlzdGljYWwgbW9kZWwgYmVjYXVzZSB0aGUgdmFyaWFibGVzIGFyZSBhbHJlYWR5IGNvZGVkIGFzIG51bWJlcnMuIEhvd2V2ZXIsIGZhY3RvcnMgY2FuIGJlIGNvbmZ1c2luZyBzaW5jZSB0aGV5IGxvb2sgbGlrZSBjaGFyYWN0ZXIgc3RyaW5ncyBidXQgYmVoYXZlIGxpa2UgaW50ZWdlcnMuIA0KDQpgYGB7cn0NCmdlbmRlciA8LSBmYWN0b3IoYygibWFsZSIsICJmZW1hbGUiLCAiZmVtYWxlIiwgIm1hbGUiKSkNCmFzLmNoYXJhY3RlcihnZW5kZXIpIA0KYGBgDQoNCkV4ZXJjaXNlOg0KDQpNYW55IGNhcmQgZ2FtZXMgYXNzaWduIGEgbnVtZXJpY2FsIHZhbHVlIHRvIGVhY2ggY2FyZC4gRm9yIGV4YW1wbGUsIGluIGJsYWNramFjaywgZWFjaCBmYWNlIGNhcmQgaXMgd29ydGggMTAgcG9pbnRzLCBlYWNoIG51bWJlciBjYXJkIGlzIHdvcnRoIGJldHdlZW4gMiBhbmQgMTAgcG9pbnRzLCBhbmQgZWFjaCBhY2UgaXMgd29ydGggMSBvciAxMSBwb2ludHMsIGRlcGVuZGluZyBvbiB0aGUgZmluYWwgc2NvcmUuIE1ha2UgYSB2aXJ0dWFsIHBsYXlpbmcgY2FyZCBieSBjb21iaW5pbmcgImFjZSwiICJoZWFydCwiIGFuZCAxIGludG8gYSB2ZWN0b3IuIFdoYXQgdHlwZSBvZiBhdG9taWMgdmVjdG9yIHdpbGwgcmVzdWx0PyBDaGVjayBpZiB5b3UgYXJlIHJpZ2h0Lg0KDQoNCllvdSBjYW4gY29udmVydCBhIGZhY3RvciB0byBhIGNoYXJhY3RlciBzdHJpbmcgd2l0aCB0aGUgYGFzLmNoYXJhY3RlciBmdW5jdGlvbmAuIFIgd2lsbCByZXRhaW4gdGhlIGRpc3BsYXkgdmVyc2lvbiBvZiB0aGUgZmFjdG9yLCBub3QgdGhlIGludGVnZXJzIHN0b3JlZCBpbiBtZW1vcnk6DQoNCmBgYHtyfQ0KY2FyZCA8LSBjKCJhY2UiLCAiaGVhcnRzIiwgMSkgDQpjYXJkIA0KDQpgYGANCg0KDQpUaGlzIHdpbGwgY2F1c2UgdHJvdWJsZSBpZiB5b3Ugd2FudCB0byBkbyBtYXRoIHdpdGggdGhhdCBwb2ludCB2YWx1ZSwgZm9yIGV4YW1wbGUsIHRvIHNlZSB3aG8gd29uIHlvdXIgZ2FtZSBvZiBibGFja2phY2suIFNpbmNlIG1hdHJpY2VzIGFuZCBhcnJheXMgYXJlIHNwZWNpYWwgY2FzZXMgb2YgYXRvbWljIHZlY3RvcnMsIHRoZXkgc3VmZmVyIGZyb20gdGhlIHNhbWUgYmVoYXZpb3IuIEVhY2ggY2FuIG9ubHkgc3RvcmUgb25lIHR5cGUgb2YgZGF0YS4gVGhpcyBjcmVhdGVzIGEgY291cGxlIG9mIHByb2JsZW1zLiBGaXJzdCwgbWFueSBkYXRhIHNldHMgY29udGFpbiBtdWx0aXBsZSB0eXBlcyBvZiBkYXRhLiBTaW1wbGUgcHJvZ3JhbXMgbGlrZSBFeGNlbCBhbmQgTnVtYmVycyBjYW4gc2F2ZSBtdWx0aXBsZSB0eXBlcyBvZiBkYXRhIGluIHRoZSBzYW1lIGRhdGEgc2V0LCBhbmQgeW91IHNob3VsZCBob3BlIHRoYXQgUiBjYW4gdG9vLiBEb24ndCB3b3JyeSwgaXQgY2FuLiANCg0KDQoqKkNvZXJjaW9uOiAqKg0KDQpGaWd1cmUgMy0xLiANCg0KIVtdKDMtMS5QTkcpDQoNClIgdXNlcyB0aGUgc2FtZSBjb2VyY2lvbiBydWxlcyB3aGVuIHlvdSB0cnkgdG8gZG8gbWF0aCB3aXRoIGxvZ2ljYWwgdmFsdWVzLiBTbyB0aGUgZm9sbG93aW5nIGNvZGU6IA0KDQpgYGB7cn0NCnN1bShjKFRSVUUsIFRSVUUsIEZBTFNFLCBGQUxTRSkpIA0KI3dpbGwgYmVjb21lOg0Kc3VtKGMoMSwgMSwgMCwgMCkpIA0KYGBgDQoNCllvdSBjYW4gZXhwbGljaXRseSBhc2sgUiB0byBjb252ZXJ0IGRhdGEgZnJvbSBvbmUgdHlwZSB0byBhbm90aGVyIHdpdGggdGhlIGFzIGZ1bmN0aW9ucy4gUiB3aWxsIGNvbnZlcnQgdGhlIGRhdGEgd2hlbmV2ZXIgdGhlcmUgaXMgYSBzZW5zaWJsZSB3YXkgdG8gZG8gc286DQoNCmBgYHtyfQ0KYXMuY2hhcmFjdGVyKDEpIA0KICAjIyAiMSINCmFzLmxvZ2ljYWwoMSkgDQogICMjIFRSVUUNCmFzLm51bWVyaWMoRkFMU0UpIA0KICAjIyAwIA0KYGBgDQoNCioqTGlzdHM6ICoqDQoNCkxpc3RzIGFyZSBsaWtlIGF0b21pYyB2ZWN0b3JzIGJlY2F1c2UgdGhleSBncm91cCBkYXRhIGludG8gYSBvbmUtZGltZW5zaW9uYWwgc2V0LiBIb3dldmVyLCBsaXN0cyBkbyBub3QgZ3JvdXAgdG9nZXRoZXIgaW5kaXZpZHVhbCB2YWx1ZXM7IGxpc3RzIGdyb3VwIHRvZ2V0aGVyIFIgb2JqZWN0cywgc3VjaCBhcyBhdG9taWMgdmVjdG9ycyBhbmQgb3RoZXIgbGlzdHMuDQoNCmBgYHtyfQ0KbGlzdDEgPC0gbGlzdCgxMDA6MTMwLCAiUiIsIGxpc3QoVFJVRSwgRkFMU0UpKSANCnByaW50KGxpc3QxKQ0KYGBgDQoNCkV4ZXJjaXNlOiANCg0KVXNlIGEgbGlzdCB0byBzdG9yZSBhIHNpbmdsZSBwbGF5aW5nIGNhcmQsIGxpa2UgdGhlIGFjZSBvZiBoZWFydHMsIHdoaWNoIGhhcyBhIHBvaW50IHZhbHVlIG9mIG9uZS4gVGhlIGxpc3Qgc2hvdWxkIHNhdmUgdGhlIGZhY2Ugb2YgdGhlIGNhcmQsIHRoZSBzdWl0LCBhbmQgdGhlIHBvaW50IHZhbHVlIGluIHNlcGFyYXRlIGVsZW1lbnRzLg0KICANCmBgYHtyfQ0KY2FyZCA8LSBsaXN0KCJhY2UiLCAiaGVhcnRzIiwgMSkgDQpwcmludChjYXJkKQ0KYGBgDQoNCioqRGF0YSBGcmFtZXM6ICoqDQoNCllvdSBjYW4gdGhpbmsgb2YgYSBkYXRhIGZyYW1lIGFzIFIncyBlcXVpdmFsZW50IHRvIHRoZSBFeGNlbCBzcHJlYWRzaGVldCBiZWNhdXNlIGl0IHN0b3JlcyBkYXRhIGluIGEgc2ltaWxhciBmb3JtYXQuICBEYXRhIGZyYW1lcyBncm91cCB2ZWN0b3JzIHRvZ2V0aGVyIGludG8gYSB0d28tZGltZW5zaW9uYWwgdGFibGUuIEVhY2ggdmVjdG9yIGJlY29tZXMgYSBjb2x1bW4gaW4gdGhlIHRhYmxlLiBBcyBhIHJlc3VsdCwgZWFjaCBjb2x1bW4gb2YgYSBkYXRhIGZyYW1lIGNhbiBjb250YWluIGEgZGlmZmVyZW50IHR5cGUgb2YgZGF0YTsgYnV0IHdpdGhpbiBhIGNvbHVtbiwgZXZlcnkgY2VsbCBtdXN0IGJlIHRoZSBzYW1lIHR5cGUgb2YgZGF0YSwgYXMgaW4gRmlndXJlIDMtMi4NCiAgDQohW10oMy0yLlBORykNCg0KYGBge3J9DQpkZiA8LSBkYXRhLmZyYW1lKGZhY2UgPSBjKCJhY2UiLCAidHdvIiwgInNpeCIpLCAgc3VpdCA9IGMoImNsdWJzIiwgImNsdWJzIiwgImNsdWJzIiksIHZhbHVlID0gYygxLCAyLCAzKSkgDQpkZg0KYGBgDQoNCg0KIEluIGZhY3QsIGVhY2ggZGF0YSBmcmFtZSBpcyBhIGxpc3Qgd2l0aCBjbGFzcyBgZGF0YS5mcmFtZWAuIA0KDQpgYGB7cn0NCnR5cGVvZihkZikNCmNsYXNzKGRmKSANCnN0cihkZikgDQpgYGANCg0KTm90aWNlIHRoYXQgUiBzYXZlZCB5b3VyIGNoYXJhY3RlciBzdHJpbmdzIGFzIGZhY3RvcnMuIFIgbGlrZXMgZmFjdG9ycyEgSXQgaXMgbm90IGEgdmVyeSBiaWcgZGVhbCBoZXJlLCBidXQgeW91IGNhbiBwcmV2ZW50IHRoaXMgYmVoYXZpb3IgYnkgYWRkaW5nIHRoZSBhcmd1bWVudCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UgdG8gZGF0YS5mcmFtZToNCiAgICANCmBgYHtyfQ0KZGYgPC0gZGF0YS5mcmFtZShmYWNlID0gYygiYWNlIiwgInR3byIsICJzaXgiKSwgIHN1aXQgPSBjKCJjbHVicyIsICJjbHVicyIsICJjbHVicyIpLCB2YWx1ZSA9IGMoMSwgMiwgMyksICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpIA0KZGYNCmBgYA0KDQoNCllvdSBzaG91bGQgYXZvaWQgdHlwaW5nIGxhcmdlIGRhdGEgc2V0cyBpbiBieSBoYW5kIHdoZW5ldmVyIHBvc3NpYmxlLiBUeXBpbmcgaW52aXRlcyB0eXBvcyBhbmQgZXJyb3JzLCBub3QgdG8gbWVudGlvbiBSU0kuIEl0IGlzIGFsd2F5cyBiZXR0ZXIgdG8gYWNxdWlyZSBsYXJnZSBkYXRhIHNldHMgYXMgYSBjb21wdXRlciBmaWxlLiBZb3UgY2FuIHRoZW4gYXNrIFIgdG8gcmVhZCB0aGUgZmlsZSBhbmQgc3RvcmUgdGhlIGNvbnRlbnRzIGFzIGFuIG9iamVjdC4gICANCiAgDQogIA0KKipMb2FkaW5nIERhdGE6ICoqDQoNCkRhdGFzZXQ6IGh0dHBzOi8vZ2lzdC5naXRodWIuY29tL2dhcnJldHRnbWFuLzk2MjkzMjMNCg0KKiBNb3N0IGRhdGEtc2NpZW5jZSBhcHBsaWNhdGlvbnMgY2FuIG9wZW4gcGxhaW4tdGV4dCBmaWxlcyBhbmQgZXhwb3J0IGRhdGEgYXMgcGxhaW4tdGV4dCBmaWxlcy4gDQoqIFRoaXMgbWFrZXMgcGxhaW4tdGV4dCBmaWxlcyBhIHNvcnQgb2YgbGluZ3VhIGZyYW5jYSBmb3IgZGF0YSBzY2llbmNlLiANCiogVG8gbG9hZCBhIHBsYWluLXRleHQgZmlsZSBpbnRvIFIsIGNsaWNrIHRoZSBJbXBvcnQgRGF0YXNldCBpY29uIGluIFJTdHVkaW8sIHNob3duIGluIEZpZ3VyZSAzLTMuIA0KKiBUaGVuIHNlbGVjdCAiRnJvbSB0ZXh0IGZpbGUuIg0KDQohW10oMy0zLlBORykNCg0KUlN0dWRpbyB3aWxsIGFzayB5b3UgdG8gc2VsZWN0IHRoZSBmaWxlIHlvdSB3YW50IHRvIGltcG9ydCwgdGhlbiBpdCB3aWxsIG9wZW4gYSB3aXphcmQgdG8gaGVscCB5b3UgaW1wb3J0IHRoZSBkYXRhLCBhcyBpbiBGaWd1cmUgMy00LiBZb3UgY2FuIGFsc28gdW5jbGljayB0aGUgYm94ICJTdHJpbmdzIGFzIGZhY3RvcnMiIGluIHRoZSB3aXphcmQuIEkgcmVjb21tZW5kIGRvaW5nIHRoaXMuIElmIHlvdSBkbywgUiB3aWxsIGxvYWQgYWxsIG9mIHlvdXIgY2hhcmFjdGVyIHN0cmluZ3MgYXMgY2hhcmFjdGVyIHN0cmluZ3MuIElmIHlvdSBkbyBub3QsIFIgd2lsbCBjb252ZXJ0IHRoZW0gdG8gZmFjdG9ycy4NCiAgDQoNCmBgYHtyfQ0KZGVjaw0KY2xhc3MoZGVjaykNCmBgYA0KDQoNCk9uY2UgZXZlcnl0aGluZyBsb29rcyByaWdodCwgY2xpY2sgSW1wb3J0LiBSU3R1ZGlvIHdpbGwgcmVhZCBpbiB0aGUgZGF0YSBhbmQgc2F2ZSBpdCB0byBhIGRhdGEgZnJhbWUuIFJTdHVkaW8gd2lsbCBhbHNvIG9wZW4gYSBkYXRhIHZpZXdlciwgc28geW91IGNhbiBzZWUgeW91ciBuZXcgZGF0YSBpbiBhIHNwcmVhZHNoZWV0IGZvcm1hdC4gVGhpcyBpcyBhIGdvb2Qgd2F5IHRvIGNoZWNrIHRoYXQgZXZlcnl0aGluZyBjYW1lIHRocm91Z2ggYXMgZXhwZWN0ZWQuDQogIA0KKipTYXZpbmcgRGF0YTogKioNCg0KWW91IGNhbiBzYXZlIGFueSBkYXRhIGZyYW1lIGluIFIgdG8gYSAuY3N2IGZpbGUgd2l0aCB0aGUgY29tbWFuZCB3cml0ZS5jc3YuIFRvIHNhdmUgZGVjaywgcnVuOg0KDQpgd3JpdGUuY3N2KGRlY2ssIGZpbGUgPSAiY2FyZHMuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpYGANCg0KUiB3aWxsIHR1cm4geW91ciBkYXRhIGZyYW1lIGludG8gYSBwbGFpbi10ZXh0IGZpbGUgd2l0aCB0aGUgY29tbWEtc2VwYXJhdGVkIHZhbHVlcyBmb3JtYXQgYW5kIHNhdmUgdGhlIGZpbGUgdG8geW91ciB3b3JraW5nIGRpcmVjdG9yeS4gVG8gc2VlIHdoZXJlIHlvdXIgd29ya2luZyBkaXJlY3RvcnkgaXMsIHJ1biBgZ2V0d2QoKWAuDQoNCmBgYHtyfQ0KZ2V0d2QoKQ0KICANCmBgYA0KDQpUbyBjaGFuZ2UgdGhlIGxvY2F0aW9uIG9mIHlvdXIgd29ya2luZyBkaXJlY3RvcnksIHZpc2l0IGBTZXNzaW9uID4gU2V0IFdvcmtpbmcgRGlyZWN0b3J5ID4gQ2hvb3NlIERpcmVjdG9yeWAgaW4gdGhlIFJTdHVkaW8gbWVudSBiYXIuIA0KICANCg0KDQoNCioqU3VtbWFyeTogKioNCg0KWW91IGNhbiBzYXZlIGRhdGEgaW4gUiB3aXRoIGZpdmUgZGlmZmVyZW50IG9iamVjdHMsIHdoaWNoIGxldCB5b3Ugc3RvcmUgZGlmZmVyZW50IHR5cGVzIG9mIHZhbHVlcyBpbiBkaWZmZXJlbnQgdHlwZXMgb2YgcmVsYXRpb25zaGlwcywgYXMgaW4gRmlndXJlIDMtNi4gRGF0YSBmcmFtZXMgc3RvcmUgb25lIG9mIHRoZSBtb3N0IGNvbW1vbiBmb3JtcyBvZiBkYXRhIHVzZWQgaW4gZGF0YSBzY2llbmNlLCB0YWJ1bGFyIGRhdGEuIFlvdSBjYW4gbG9hZCB0YWJ1bGFyIGRhdGEgaW50byBhIGRhdGEgZnJhbWUgd2l0aCBSU3R1ZGlvJ3MgSW1wb3J0IERhdGFzZXQgYnV0dG9uLXNvIGxvbmcgYXMgdGhlIGRhdGEgaXMgc2F2ZWQgYXMgYSBwbGFpbi10ZXh0IGZpbGUuIE5vIHByb2dyYW0gaXMgYmV0dGVyIGF0IGNvbnZlcnRpbmcgRXhjZWwgZmlsZXMgdGhhbiBFeGNlbC4gU2ltaWxhcmx5LCBubyBwcm9ncmFtIGlzIGJldHRlciBhdCBjb252ZXJ0aW5nIFNBUyBYcG9ydCBmaWxlcyB0aGFuIFNBUywgYW5kIHNvIG9uLiANCg0KIVtdKDMtNi5QTkcpDQogIA0KIA0KKiA2IHR5cGVzIFIgYXRvbWljIHZlY3RvcnM6DQoNCjEuIEludGVnZXJzDQoyLiBEb3VibGUNCjMuIExvZ2ljDQo0LiBDaGFyYWN0ZXJzDQo1LiBDb21wbGV4cw0KNi4gUmF3DQoNCiogNSBSIG9iamVjdHM6DQoNCjEuIFZlY3RvcnMNCjIuIE1hdHJpeA0KMy4gQXJyYXlzDQo0LiBMaXN0DQo1LiBEYXRhIEZyYW1lDQoNCg0KDQpTZWUgdGhlIGBBcHBlbmRpeCBEYA0KDQojNC4gUiBOb3RhdGlvbg0KDQoqKlNlbGVjdGluZyBWYWx1ZXM6ICoqDQoNCkZpcnN0IG9mIGFsbCwgaW1wb3J0IHRoZSBkZWNrLmNzdi4gVG8gZXh0cmFjdCBhIHZhbHVlIG9yIHNldCBvZiB2YWx1ZXMgZnJvbSBhIGRhdGEgZnJhbWUsIHdyaXRlIHRoZSBkYXRhIGZyYW1lJ3MgbmFtZSBmb2xsb3dlZCBieSBhIHBhaXIgb2YgaGFyZCBicmFja2V0czoNCg0KYGBge3J9DQpkZWNrDQpjbGFzcyhkZWNrKQ0KZGVja1sgLCBdDQpgYGANCg0KDQpZb3UgaGF2ZSBhIGNob2ljZSB3aGVuIGl0IGNvbWVzIHRvIHdyaXRpbmcgaW5kZXhlcy4gVGhlcmUgYXJlIHNpeCBkaWZmZXJlbnQgd2F5cyB0byB3cml0ZSBhbiBpbmRleCBmb3IgUiwgYW5kIGVhY2ggZG9lcyBzb21ldGhpbmcgc2xpZ2h0bHkgZGlmZmVyZW50LiANCg0KMS4gUG9zaXRpdmUgaW50ZWdlcnMgDQoyLiBOZWdhdGl2ZSBpbnRlZ2VycyANCjMuIFplcm8gDQo0LiBCbGFuayBzcGFjZXMgDQo1LiBMb2dpY2FsIHZhbHVlcyANCjYuIE5hbWVzIA0KDQpUaGUgc2ltcGxlc3Qgb2YgdGhlc2UgdG8gdXNlIGlzIHBvc2l0aXZlIGludGVnZXJzLiANCg0KMS4gUG9zaXRpdmUgSW50ZWdlcnMNCg0KUiB0cmVhdHMgcG9zaXRpdmUgaW50ZWdlcnMganVzdCBsaWtlIGlqIG5vdGF0aW9uIGluIGxpbmVhciBhbGdlYnJhOiBgZGVja1tpLGpdYCB3aWxsIHJldHVybiB0aGUgdmFsdWUgb2YgZGVjayB0aGF0IGlzIGluIHRoZSBpdGggcm93IGFuZCB0aGUganRoIGNvbHVtbiwgRmlndXJlIDQtMS4NCg0KIVtdKDQtMS5QTkcpDQoNCmBgYHtyfQ0KZGVja1sxLCAxXQ0KYGBgDQoNCg0KVG8gZXh0cmFjdCBtb3JlIHRoYW4gb25lIHZhbHVlLCB1c2UgYSB2ZWN0b3Igb2YgcG9zaXRpdmUgaW50ZWdlcnMuIEZvciBleGFtcGxlLCB5b3UgY2FuIHJldHVybiB0aGUgZmlyc3Qgcm93IG9mIGRlY2sgd2l0aCBkZWNrWzEsIGMoMSwgMiwgMyldIG9yIGRlY2tbMSwgMTozXToNCiAgDQpgYGB7cn0NCmRlY2tbMSwgYygxLCAyLCAzKV0gDQpgYGANCg0KUiB3aWxsIGdpdmUgeW91IGEgbmV3IHNldCBvZiB2YWx1ZXMgd2hpY2ggYXJlIGNvcGllcyBvZiB0aGUgb3JpZ2luYWwgdmFsdWVzLiBZb3UgY2FuIHRoZW4gc2F2ZSB0aGlzIG5ldyBzZXQgdG8gYW4gUiBvYmplY3Qgd2l0aCBSJ3MgYXNzaWdubWVudCBvcGVyYXRvcjoNCiANCmBgYHtyfQ0KbmV3IDwtIGRlY2tbMSwgYygxLCAyLCAzKV0gDQpuZXcgDQpgYGANCg0KDQpSJ3Mgbm90YXRpb24gc3lzdGVtIGlzIG5vdCBsaW1pdGVkIHRvIGRhdGEgZnJhbWVzLiBZb3UgY2FuIHVzZSB0aGUgc2FtZSBzeW50YXggdG8gc2VsZWN0IHZhbHVlcyBpbiBhbnkgUiBvYmplY3QsIGFzIGxvbmcgYXMgeW91IHN1cHBseSBvbmUgaW5kZXggZm9yIGVhY2ggZGltZW5zaW9uIG9mIHRoZSBvYmplY3QuIFNvLCBmb3IgZXhhbXBsZSwgeW91IGNhbiBzdWJzZXQgYSB2ZWN0b3IgKHdoaWNoIGhhcyBvbmUgZGltZW5zaW9uKSB3aXRoIGEgc2luZ2xlIGluZGV4Og0KICANCmBgYHtyfQ0KdmVjIDwtIGMoNiwgMSwgMywgNiwgMTAsIDUpDQp2ZWNbMTozXQ0KYGBgDQoNCjIuIE5lZ2F0aXZlIEludGVnZXJzDQoNCk5lZ2F0aXZlIGludGVnZXJzIGRvIHRoZSBleGFjdCBvcHBvc2l0ZSBvZiBwb3NpdGl2ZSBpbnRlZ2VycyB3aGVuIGluZGV4aW5nLiBSIHdpbGwgcmV0dXJuIGV2ZXJ5IGVsZW1lbnQgZXhjZXB0IHRoZSBlbGVtZW50cyBpbiBhIG5lZ2F0aXZlIGluZGV4LiANCg0KDQpgYGB7cn0NCmRlY2tbLSgyOjUyKSwgMTozXSANCmBgYA0KDQpOZWdhdGl2ZSBpbnRlZ2VycyBhcmUgYSBtb3JlIGVmZmljaWVudCB3YXkgdG8gc3Vic2V0IHRoYW4gcG9zaXRpdmUgaW50ZWdlcnMgaWYgeW91IHdhbnQgdG8gaW5jbHVkZSB0aGUgbWFqb3JpdHkgb2YgYSBkYXRhIGZyYW1lJ3Mgcm93cyBvciBjb2x1bW5zLiANCg0KDQozLiBaZXJvDQoNClIgd2lsbCByZXR1cm4gbm90aGluZyBmcm9tIGEgZGltZW5zaW9uIHdoZW4geW91IHVzZSB6ZXJvIGFzIGFuIGluZGV4LiBUaGlzIGNyZWF0ZXMgYW4gZW1wdHkgb2JqZWN0Og0KICANCmBgYHtyfQ0KZGVja1swLCAwXSANCmBgYA0KDQpkYXRhIGZyYW1lIHdpdGggMCBjb2x1bW5zIGFuZCAwIHJvd3MgVG8gYmUgaG9uZXN0LCBpbmRleGluZyB3aXRoIHplcm8gaXMgbm90IHZlcnkgaGVscGZ1bC4gDQoNCjQuIEJsYW5rIFNwYWNlcw0KDQpZb3UgY2FuIHVzZSBhIGJsYW5rIHNwYWNlIHRvIHRlbGwgUiB0byBleHRyYWN0IGV2ZXJ5IHZhbHVlIGluIGEgZGltZW5zaW9uLiANCg0KYGBge3J9DQpkZWNrWzEsIF0gDQoNCmBgYA0KDQo1LiBMb2dpY2FsIFZhbHVlcw0KDQpJZiB5b3Ugc3VwcGx5IGEgdmVjdG9yIG9mIFRSVUVzIGFuZCBGQUxTRXMgYXMgeW91ciBpbmRleCwgUiB3aWxsIG1hdGNoIGVhY2ggVFJVRSBhbmQgRkFMU0UgdG8gYSByb3cgaW4geW91ciBkYXRhIGZyYW1lIChvciBhIGNvbHVtbiBkZXBlbmRpbmcgb24gd2hlcmUgeW91IHBsYWNlIHRoZSBpbmRleCkuIFIgd2lsbCB0aGVuIHJldHVybiBlYWNoIHJvdyB0aGF0IGNvcnJlc3BvbmRzIHRvIGEgVFJVRSwgRmlndXJlIDQtMi4NCiAgDQohW10oNC0yLlBORykNCg0KDQpgYGB7cn0NCmRlY2tbMSwgYyhUUlVFLCBUUlVFLCBGQUxTRSldIA0KYGBgDQoNCg0KNi4gTmFtZXMNCg0KRmluYWxseSwgeW91IGNhbiBhc2sgZm9yIHRoZSBlbGVtZW50cyB5b3Ugd2FudCBieSBuYW1lLWlmIHlvdXIgb2JqZWN0IGhhcyBuYW1lcy4gDQoNCmBgYHtyfQ0KZGVja1sxLCBjKCJmYWNlIiwgInN1aXQiLCAidmFsdWUiKV0NCmBgYA0KICANCg0KKipEZWFsIGEgQ2FyZDogKioNCg0KQ29tcGxldGUgdGhlIGZvbGxvd2luZyBjb2RlIHRvIG1ha2UgYSBmdW5jdGlvbiB0aGF0IHJldHVybnMgdGhlIGZpcnN0IHJvdyBvZiBhIGRhdGEgZnJhbWU6DQogICAgDQpgYGB7cn0NCmRlYWwgPC0gZnVuY3Rpb24oY2FyZHMpIHsgIA0KICAgIGNhcmRzWzEsIF0gDQogICAgfSANCiAgDQogIGRlYWwoZGVjaykNCmBgYA0KDQoqKlNodWZmbGUgdGhlIERlY2s6ICoqDQoNCmBgYHtyfQ0KZGVjazIgPC0gZGVja1sxOjUyLCBdDQogIGRlY2syDQogIA0KICBoZWFkKGRlY2syKSANCiAgDQogIA0KICBkZWNrMyA8LSBkZWNrW2MoMiwgMSwgMzo1MiksIF0NCiAgZGVjazMgIA0KYGBgDQoNCkhvdyBjb3VsZCB5b3UgZ2VuZXJhdGUgc3VjaCBhIHJhbmRvbSBjb2xsZWN0aW9uIG9mIGludGVnZXJzPyBXaXRoIG91ciBmcmllbmRseSBuZWlnaGJvcmhvb2Qgc2FtcGxlIGZ1bmN0aW9uOg0KICAgIA0KYGBge3J9DQpyYW5kb20gPC0gc2FtcGxlKDE6NTIsIHNpemUgPSA1MikgDQpyYW5kb20gDQogIA0KZGVjazQgPC0gZGVja1tyYW5kb20sIF0gDQpoZWFkKGRlY2s0KQ0KYGBgDQoNCkV4ZXJjaXNlOiANCg0KVXNlIHRoZSBwcmVjZWRpbmcgaWRlYXMgdG8gd3JpdGUgYSBzaHVmZmxlIGZ1bmN0aW9uLiBTaHVmZmxlIHNob3VsZCB0YWtlIGEgZGF0YSBmcmFtZSBhbmQgcmV0dXJuIGEgc2h1ZmZsZWQgY29weSBvZiB0aGUgZGF0YSBmcmFtZS4gWW91ciBzaHVmZmxlIGZ1bmN0aW9uIHdpbGwgbG9vayBsaWtlIHRoZSBvbmUgdGhhdCBmb2xsb3dzOg0KICAgIA0KYGBge3J9DQpzaHVmZmxlIDwtIGZ1bmN0aW9uKGNhcmRzKSB7ICANCiAgICByYW5kb20gPC0gc2FtcGxlKDE6NTIsIHNpemUgPSA1MikgIA0KICAgIGNhcmRzW3JhbmRvbSwgXSANCiAgICB9IA0KICANCiAgDQogIGRlYWwoZGVjaykNCiAgZGVjazIgPC0gc2h1ZmZsZShkZWNrKQ0KICBkZWFsKGRlY2syKQ0KYGBgDQogIA0KDQoqKkRvbGxhciBTaWducyBhbmQgRG91YmxlIEJyYWNrZXRzOiAqKg0KDQpUd28gdHlwZXMgb2Ygb2JqZWN0IGluIFIgb2JleSBhbiBvcHRpb25hbCBzZWNvbmQgc3lzdGVtIG9mIG5vdGF0aW9uLiBZb3UgY2FuIGV4dHJhY3QgdmFsdWVzIGZyb20gZGF0YSBmcmFtZXMgYW5kIGxpc3RzIHdpdGggdGhlICQgc3ludGF4Lg0KICANCmBgYHtyfQ0KZGVjayR2YWx1ZSANCm1lYW4oZGVjayR2YWx1ZSkgDQptZWRpYW4oZGVjayR2YWx1ZSkNCg0KYGBgDQoNCg0KWW91IGNhbiB1c2UgdGhlIHNhbWUgJCBub3RhdGlvbiB3aXRoIHRoZSBlbGVtZW50cyBvZiBhIGxpc3QsIGlmIHRoZXkgaGF2ZSBuYW1lcy4gDQogIA0KYGBge3J9DQpsc3QgPC0gbGlzdChudW1iZXJzID0gYygxLCAyKSwgbG9naWNhbCA9IFRSVUUsIHN0cmluZ3MgPSBjKCJhIiwgImIiLCAiYyIpKSANCmxzdCANCmBgYA0KDQpBbmQgdGhlbiBzdWJzZXQgaXQ6IA0KDQpgYGB7cn0NCmxzdFsxXSANCmxzdCRudW1iZXJzIA0KbHN0W1sxXV0gDQpsc3RbWyJudW1iZXJzIl1dIA0KICANCmBgYA0KDQpJbiB0aGUgUiBjb21tdW5pdHksIHRoZXJlIGlzIGEgcG9wdWxhciwgYW5kIGhlbHBmdWwsIHdheSB0byB0aGluayBhYm91dCBpdCwgRmlndXJlIDQtMy4gDQogIA0KIVtdKDQtMy5QTkcpDQoNCioqU3VtbWFyeTogKioNCg0KWW91IGhhdmUgbGVhcm5lZCBob3cgdG8gYWNjZXNzIHZhbHVlcyB0aGF0IGhhdmUgYmVlbiBzdG9yZWQgaW4gUi4gWW91IGNhbiByZXRyaWV2ZSBhIGNvcHkgb2YgdmFsdWVzIHRoYXQgbGl2ZSBpbnNpZGUgYSBkYXRhIGZyYW1lIGFuZCB1c2UgdGhlIGNvcGllcyBmb3IgbmV3IGNvbXB1dGF0aW9ucy4gDQogIA0KDQojNS4gTW9kaWZ5aW5nIFZhbHVlcw0KDQoqKkNoYW5naW5nIFZhbHVlcyBpbiBQbGFjZTogKioNCg0KYGBge3J9DQp2ZWMgPC0gYygwLCAwLCAwLCAwLCAwLCAwKSANCnZlYw0KYGBgDQoNCkhlcmUncyBob3cgeW91IGNhbiBzZWxlY3QgdGhlIGZpcnN0IHZhbHVlIG9mIHZlYzoNCg0KYGBge3J9DQp2ZWNbMV0NCmBgYA0KDQpBbmQgaGVyZSBpcyBob3cgeW91IGNhbiBtb2RpZnkgaXQ6DQoNCmBgYHtyfQ0KdmVjWzFdIDwtIDEwMDANCnZlYyANCmBgYA0KDQpZb3UgY2FuIHJlcGxhY2UgbXVsdGlwbGUgdmFsdWVzIGF0IG9uY2UgYXMgbG9uZyBhcyB0aGUgbnVtYmVyIG9mIG5ldyB2YWx1ZXMgZXF1YWxzIHRoZSBudW1iZXIgb2Ygc2VsZWN0ZWQgdmFsdWVzOg0KICANCmBgYHtyfQ0KdmVjW2MoMSwgMywgNSldIDwtIGMoMSwgMSwgMSkgDQp2ZWMNCmBgYA0KDQpgYGB7cn0NCnZlY1s0OjZdIDwtIHZlY1s0OjZdICsgMQ0KdmVjIA0KYGBgDQoNCg0KVGhpcyBwcm92aWRlcyBhIGdyZWF0IHdheSB0byBhZGQgbmV3IHZhcmlhYmxlcyB0byB5b3VyIGRhdGEgc2V0OiBmaXJ0cyBpbXBvcnQgdGhlIGRlY2suY3N2DQoNCg0KYGBge3J9DQpkZWNrDQpkZWNrMjwtZGVjaw0KZGVjazIkbmV3IDwtIDE6NTINCmRlY2syDQpgYGANCg0KWW91IGNhbiBhbHNvIHJlbW92ZSBjb2x1bW5zIGZyb20gYSBkYXRhIGZyYW1lIChhbmQgZWxlbWVudHMgZnJvbSBhIGxpc3QpIGJ5IGFzc2lnbmluZyB0aGVtIHRoZSBzeW1ib2wgTlVMTDoNCiAgICANCmBgYHtyfQ0KZGVjazIkbmV3IDwtIE5VTEwNCiAgaGVhZChkZWNrMikNCmBgYA0KDQoNCllvdSBjYW4gc2luZ2xlIG91dCBqdXN0IHRoZSB2YWx1ZXMgb2YgdGhlIGFjZXMgYnkgc3Vic2V0dGluZyB0aGUgY29sdW1ucyBkaW1lbnNpb24gb2YgZGVjazIuIE9yLCBldmVuIGJldHRlciwgeW91IGNhbiBzdWJzZXQgdGhlIGNvbHVtbiB2ZWN0b3IgZGVjazIkdmFsdWU6DQogICAgDQpgYGB7cn0NCmRlY2syW2MoMTMsIDI2LCAzOSwgNTIpLCAzXQ0KYGBgDQoNCmBgYHtyfQ0KZGVjazIkdmFsdWVbYygxMywgMjYsIDM5LCA1MildDQpgYGANCg0KTm93IGFsbCB5b3UgaGF2ZSB0byBkbyBpcyBhc3NpZ24gYSBuZXcgc2V0IG9mIHZhbHVlcyB0byB0aGVzZSBvbGQgdmFsdWVzLiANCiAgDQpgYGB7cn0NCmRlY2syJHZhbHVlW2MoMTMsIDI2LCAzOSwgNTIpXSA8LSBjKDE0LCAxNCwgMTQsIDE0KQ0KICAjIG9yDQogIGRlY2syJHZhbHVlW2MoMTMsIDI2LCAzOSwgNTIpXSA8LSAxNA0KICBkZWNrMiAgDQpgYGANCg0KKipMb2dpY2FsIFN1YnNldHRpbmc6ICoqDQoNCmBgYHtyfQ0KdmVjIDwtIGMoMSwgMCwgMSwgMSwgMCwgMSkgDQp2ZWMNCmBgYA0KDQpgYGB7cn0NCnZlY1tjKEZBTFNFLCBGQUxTRSwgRkFMU0UsIEZBTFNFLCBUUlVFLCBGQUxTRSwgRkFMU0UpXSANCmBgYA0KDQpBdCBmaXJzdCBnbGFuY2UsIHRoaXMgc3lzdGVtIG1pZ2h0IHNlZW0gaW1wcmFjdGljYWwuIFdobyB3YW50cyB0byB0eXBlIG91dCBsb25nIHZlY3RvcnMgb2YgVFJVRXMgYW5kIEZBTFNFcz8gTm8gb25lLiBCdXQgeW91IGRvbid0IGhhdmUgdG8uIFlvdSBjYW4gbGV0IGEgbG9naWNhbCB0ZXN0IGNyZWF0ZSBhIHZlY3RvciBvZiBUUlVFcyBhbmQgRkFMU0VzIGZvciB5b3UuIA0KICANCiAgDQoqKkxvZ2ljYWwgVGVzdHM6ICoqDQoNCkEgbG9naWNhbCB0ZXN0IGlzIGEgY29tcGFyaXNvbiBsaWtlICJpcyBvbmUgbGVzcyB0aGFuIHR3bz8iLCBgMSA8IDJgLCBvciAiaXMgdGhyZWUgZ3JlYXRlciB0aGFuIGZvdXI/IiwgYDMgPiA0YC4gUiBwcm92aWRlcyBzZXZlbiBsb2dpY2FsIG9wZXJhdG9ycyB0aGF0IHlvdSBjYW4gdXNlIHRvIG1ha2UgY29tcGFyaXNvbnMsIHNob3duIGluIFRhYmxlIDctMSBhbmQgVGFibGUgNy0yLg0KICANCiAgDQogIA0KIVtdKFRhYmxlNy0xLlBORykNCg0KDQohW10oVGFibGU3LTIuUE5HKQ0KDQoNCg0KRWFjaCBvcGVyYXRvciByZXR1cm5zIGEgVFJVRSBvciBhIEZBTFNFLiBJZiB5b3UgdXNlIGFuIG9wZXJhdG9yIHRvIGNvbXBhcmUgdmVjdG9ycywgUiB3aWxsIGRvIGVsZW1lbnQtd2lzZSBjb21wYXJpc29ucy1qdXN0IGxpa2UgaXQgZG9lcyB3aXRoIHRoZSBhcml0aG1ldGljIG9wZXJhdG9yczoNCg0KDQpgYGB7cn0NCjEgPiAyIA0KMSA+IGMoMCwgMSwgMikgDQpjKDEsIDIsIDMpID09IGMoMywgMiwgMSkgDQpgYGANCg0KDQpgJWluJWAgaXMgdGhlIG9ubHkgb3BlcmF0b3IgdGhhdCBkb2VzIG5vdCBkbyBub3JtYWwgZWxlbWVudC13aXNlIGV4ZWN1dGlvbi4gYCVpbiVgIHRlc3RzIHdoZXRoZXIgdGhlIHZhbHVlKHMpIG9uIHRoZSBsZWZ0IHNpZGUgYXJlIGluIHRoZSB2ZWN0b3Igb24gdGhlIHJpZ2h0IHNpZGUuIA0KICANCg0KDQpgYGB7cn0NCjEgJWluJSBjKDMsIDQsIDUpIA0KYygxLCAyKSAlaW4lIGMoMywgNCwgNSkgDQpjKDEsIDIsIDMpICVpbiUgYygzLCA0LCA1KQ0KYygxLCAyLCAzLCA0KSAlaW4lIGMoMywgNCwgNSkNCmBgYA0KDQoNCk5vdGljZSB0aGF0IHlvdSB0ZXN0IGZvciBlcXVhbGl0eSB3aXRoIGEgZG91YmxlIGVxdWFscyBzaWduLCA9PSwgYW5kIG5vdCBhIHNpbmdsZSBlcXVhbHMgc2lnbiwgPSwgd2hpY2ggaXMgYW5vdGhlciB3YXkgdG8gd3JpdGUgYDwtYC4gWW91IGNhbiBjb21wYXJlIGFueSB0d28gUiBvYmplY3RzIHdpdGggYSBsb2dpY2FsIG9wZXJhdG9yOyBob3dldmVyLCBsb2dpY2FsIG9wZXJhdG9ycyBtYWtlIHRoZSBtb3N0IHNlbnNlIGlmIHlvdSBjb21wYXJlIHR3byBvYmplY3RzIG9mIHRoZSBzYW1lIGRhdGEgdHlwZS4gSWYgeW91IGNvbXBhcmUgb2JqZWN0cyBvZiBkaWZmZXJlbnQgZGF0YSB0eXBlcywgUiB3aWxsIHVzZSBpdHMgY29lcmNpb24gcnVsZXMgdG8gY29lcmNlIHRoZSBvYmplY3RzIHRvIHRoZSBzYW1lIHR5cGUgYmVmb3JlIGl0IG1ha2VzIHRoZSBjb21wYXJpc29uLg0KDQoNCioqTWlzc2luZyBJbmZvcm1hdGlvbjogKioNCg0KTWlzc2luZyBpbmZvcm1hdGlvbiBwcm9ibGVtcyBoYXBwZW4gZnJlcXVlbnRseSBpbiBkYXRhIHNjaWVuY2UuIFRoZSBOQSBjaGFyYWN0ZXIgaXMgYSBzcGVjaWFsIHN5bWJvbCBpbiBSLiBJdCBzdGFuZHMgZm9yICJub3QgYXZhaWxhYmxlIiBhbmQgY2FuIGJlIHVzZWQgYXMgYSBwbGFjZWhvbGRlciBmb3IgbWlzc2luZyBpbmZvcm1hdGlvbi4gR2VuZXJhbGx5LCBOQXMgd2lsbCBwcm9wYWdhdGUgd2hlbmV2ZXIgeW91IHVzZSB0aGVtIGluIGFuIFIgb3BlcmF0aW9uIG9yIGZ1bmN0aW9uLiBUaGlzIGNhbiBzYXZlIHlvdSBmcm9tIG1ha2luZyBlcnJvcnMgYmFzZWQgb24gbWlzc2luZyBkYXRhLg0KDQoqIG5hLnJtOg0KDQpNaXNzaW5nIHZhbHVlcyBjYW4gaGVscCB5b3Ugd29yayBhcm91bmQgaG9sZXMgaW4geW91ciBkYXRhIHNldHMsIGJ1dCB0aGV5IGNhbiBhbHNvIGNyZWF0ZSBzb21lIGZydXN0cmF0aW5nIHByb2JsZW1zLiBTdXBwb3NlLCBmb3IgZXhhbXBsZSwgdGhhdCB5b3UndmUgY29sbGVjdGVkIDEsMDAwIG9ic2VydmF0aW9ucyBhbmQgd2lzaCB0byB0YWtlIHRoZWlyIGF2ZXJhZ2Ugd2l0aCBSJ3MgbWVhbiBmdW5jdGlvbi4gSWYgZXZlbiBvbmUgb2YgdGhlIHZhbHVlcyBpcyBOQSwgeW91ciByZXN1bHQgd2lsbCBiZSBOQToNCiAgDQogICAgDQpgYGB7cn0NCmMoTkEsIDE6NTApIA0KbWVhbihjKE5BLCAxOjUwKSkgDQpgYGANCiANCiAgDQpVbmRlcnN0YW5kYWJseSwgeW91IG1heSBwcmVmZXIgYSBkaWZmZXJlbnQgYmVoYXZpb3IuIE1vc3QgUiBmdW5jdGlvbnMgY29tZSB3aXRoIHRoZSBvcHRpb25hbCBhcmd1bWVudCwgbmEucm0sIHdoaWNoIHN0YW5kcyBmb3IgTkEgcmVtb3ZlLiBSIHdpbGwgaWdub3JlIE5BcyB3aGVuIGl0IGV2YWx1YXRlcyBhIGZ1bmN0aW9uIGlmIHlvdSBhZGQgdGhlIGFyZ3VtZW50IGBuYS5ybSA9IFRSVUVgOg0KDQpgYGB7cn0NCm1lYW4oYyhOQSwgMTo1MCksIG5hLnJtID0gVFJVRSkgDQpgYGANCg0KKiBpcy5uYToNCg0KT24gb2NjYXNpb24sIHlvdSBtYXkgd2FudCB0byBpZGVudGlmeSB0aGUgTkFzIGluIHlvdXIgZGF0YSBzZXQgd2l0aCBhIGxvZ2ljYWwgdGVzdCwgYnV0IHRoYXQgdG9vIGNyZWF0ZXMgYSBwcm9ibGVtLiBIb3cgd291bGQgeW91IGdvIGFib3V0IGl0PyBJZiBzb21ldGhpbmcgaXMgYSBtaXNzaW5nIHZhbHVlLCBhbnkgbG9naWNhbCB0ZXN0IHRoYXQgdXNlcyBpdCB3aWxsIHJldHVybiBhIG1pc3NpbmcgdmFsdWUsIGV2ZW4gdGhpcyB0ZXN0Og0KDQpgYGB7cn0NCk5BID09IE5BDQpgYGANCg0KV2hpY2ggbWVhbnMgdGhhdCB0ZXN0cyBsaWtlIHRoaXMgd29uJ3QgaGVscCB5b3UgZmluZCBtaXNzaW5nIHZhbHVlczoNCg0KYGBge3J9DQpjKDEsIDIsIDMsIE5BKSA9PSBOQSANCmBgYA0KDQpCdXQgZG9uJ3Qgd29ycnkgdG9vIGhhcmQ7IFIgc3VwcGxpZXMgYSBzcGVjaWFsIGZ1bmN0aW9uIHRoYXQgY2FuIHRlc3Qgd2hldGhlciBhIHZhbHVlIGlzIGFuIE5BLiBUaGUgZnVuY3Rpb24gaXMgc2Vuc2libHkgbmFtZWQgaXMubmE6DQoNCmBgYHtyfQ0KaXMubmEoTkEpICMjIFRSVUUNCnZlYyA8LSBjKDEsIDIsIDMsIE5BKQ0KaXMubmEodmVjKQ0KYGBgDQoNCg0KTGV0J3Mgc2V0IGFsbCBvZiB5b3VyIGFjZSB2YWx1ZXMgdG8gTkEuIFRoaXMgd2lsbCBhY2NvbXBsaXNoIHR3byB0aGluZ3MuIEZpcnN0LCBpdCB3aWxsIHJlbWluZCB5b3UgdGhhdCB5b3UgZG8gbm90IGtub3cgdGhlIGZpbmFsIHZhbHVlIG9mIGVhY2ggYWNlLiBTZWNvbmQsIGl0IHdpbGwgcHJldmVudCB5b3UgZnJvbSBhY2NpZGVudGFsbHkgc2NvcmluZyBhIGhhbmQgdGhhdCBoYXMgYW4gYWNlIGJlZm9yZSB5b3UgZGV0ZXJtaW5lIHRoZSBhY2UncyBmaW5hbCB2YWx1ZS4gDQogIA0KYGBge3J9DQpkZWNrNTwtZGVjaw0KZGVjazUkdmFsdWVbZGVjazUkZmFjZSA9PSAiYWNlIl0gPC0gTkENCmRlY2s1DQpgYGANCg0KDQoqKlN1bW1hcnk6ICoqDQoNCllvdSBjYW4gbW9kaWZ5IHZhbHVlcyBpbiBwbGFjZSBpbnNpZGUgYW4gUiBvYmplY3Qgd2hlbiB5b3UgY29tYmluZSBSJ3Mgbm90YXRpb24gc3ludGF4IHdpdGggdGhlIGFzc2lnbm1lbnQgb3BlcmF0b3IsIGA8LWAuIFRoaXMgbGV0cyB5b3UgdXBkYXRlIHlvdXIgZGF0YSBhbmQgY2xlYW4geW91ciBkYXRhIHNldHMuIA0KICANCiAgIA0KICANCg0KIzYuIEVudmlyb25tZW50cy1YDQoNCioqRW52aXJvbm1lbnRzOiAqKg0KDQpGb3IgZXhhbXBsZSwgRmlndXJlIDguMSBzaG93cyBwYXJ0IG9mIHRoZSBmaWxlIHN5c3RlbSBvbiBteSBjb21wdXRlci4gSSBoYXZlIHRvbnMgb2YgZm9sZGVycy4gSW5zaWRlIG9uZSBvZiB0aGVtIGlzIGEgc3ViZm9sZGVyIG5hbWVkIERvY3VtZW50cywgaW5zaWRlIG9mIHRoYXQgc3ViZm9sZGVyIGlzIGEgc3ViLXN1YmZvbGRlciBuYW1lZCBnZ3N1YnBsb3QsIGluc2lkZSBvZiB0aGF0IGZvbGRlciBpcyBhIGZvbGRlciBuYW1lZCBpbnN0LCBpbnNpZGUgb2YgdGhhdCBpcyBhIGZvbGRlciBuYW1lZCBkb2MsIGFuZCBpbnNpZGUgb2YgdGhhdCBpcyBhIGZpbGUgbmFtZWQgbWFudWFsLnBkZi4NCg0KIVtdKDgtMS5QTkcpDQoNClIgdXNlcyBhIHNpbWlsYXIgc3lzdGVtIHRvIHNhdmUgUiBvYmplY3RzLiBFYWNoIG9iamVjdCBpcyBzYXZlZCBpbnNpZGUgb2YgYW4gZW52aXJvbm1lbnQsIGEgbGlzdC1saWtlIG9iamVjdCB0aGF0IHJlc2VtYmxlcyBhIGZvbGRlciBvbiB5b3VyIGNvbXB1dGVyLiBFYWNoIGVudmlyb25tZW50IGlzIGNvbm5lY3RlZCB0byBhIHBhcmVudCBlbnZpcm9ubWVudCwgYSBoaWdoZXItbGV2ZWwgZW52aXJvbm1lbnQsIHdoaWNoIGNyZWF0ZXMgYSBoaWVyYXJjaHkgb2YgZW52aXJvbm1lbnRzLg0KDQpZb3UgY2FuIHNlZSBS4oCZcyBlbnZpcm9ubWVudCBzeXN0ZW0gd2l0aCB0aGUgcGFyZW52cyBmdW5jdGlvbiBpbiB0aGUgYHByeXJgIHBhY2thZ2UgKG5vdGUgcGFyZW52cyBjYW1lIGluIHRoZSBwcnlyIHBhY2thZ2Ugd2hlbiB0aGlzIGJvb2sgd2FzIGZpcnN0IHB1Ymxpc2hlZCkuIGBwYXJlbnZzKGFsbCA9IFRSVUUpYCB3aWxsIHJldHVybiBhIGxpc3Qgb2YgdGhlIGVudmlyb25tZW50cyB0aGF0IHlvdXIgUiBzZXNzaW9uIGlzIHVzaW5nLg0KDQpgYGB7cn0NCmxpYnJhcnkocHJ5cikNCnBhcmVudnMoYWxsID0gVFJVRSkNCmBgYA0KDQpJdCB0YWtlcyBzb21lIGltYWdpbmF0aW9uIHRvIGludGVycHJldCB0aGlzIG91dHB1dCwgc28gbGV04oCZcyB2aXN1YWxpemUgdGhlIGVudmlyb25tZW50cyBhcyBhIHN5c3RlbSBvZiBmb2xkZXJzLCBGaWd1cmUgOC4yLg0KDQohW10oOC0yLlBORykNCg0KDQoqKldvcmtpbmcgd2l0aCBFbnZpcm9ubWVudHM6ICoqDQoNClIgY29tZXMgd2l0aCBzb21lIGhlbHBlciBmdW5jdGlvbnMgdGhhdCB5b3UgY2FuIHVzZSB0byBleHBsb3JlIHlvdXIgZW52aXJvbm1lbnQgdHJlZS4gDQoNCmBgYHtyfQ0KYXMuZW52aXJvbm1lbnQoInBhY2thZ2U6c3RhdHMiKQ0KYGBgDQoNClRocmVlIGVudmlyb25tZW50cyBpbiB5b3VyIHRyZWUgYWxzbyBjb21lIHdpdGggdGhlaXIgb3duIGFjY2Vzc29yIGZ1bmN0aW9ucy4NCg0KYGBge3J9DQpnbG9iYWxlbnYoKQ0KIyMgPGVudmlyb25tZW50OiBSX0dsb2JhbEVudj4NCg0KYmFzZWVudigpDQojIyA8ZW52aXJvbm1lbnQ6IGJhc2U+DQoNCmVtcHR5ZW52KCkNCiMjPGVudmlyb25tZW50OiBSX0VtcHR5RW52Pg0KYGBgDQoNCg0KTmV4dCwgeW91IGNhbiBsb29rIHVwIGFuIGVudmlyb25tZW504oCZcyBwYXJlbnQgd2l0aCBwYXJlbnQuZW52Og0KDQpgYGB7cn0NCnBhcmVudC5lbnYoZ2xvYmFsZW52KCkpDQpgYGANCg0KDQpZb3UgY2FuIHZpZXcgdGhlIG9iamVjdHMgc2F2ZWQgaW4gYW4gZW52aXJvbm1lbnQgd2l0aCBgbHNgIG9yIGBscy5zdHJgLg0KDQpgYGB7cn0NCmxzKGdsb2JhbGVudigpKQ0KYGBgDQoNCllvdSBjYW4gdXNlIFLigJlzICQgc3ludGF4IHRvIGFjY2VzcyBhbiBvYmplY3QgaW4gYSBzcGVjaWZpYyBlbnZpcm9ubWVudC4gRm9yIGV4YW1wbGUsIHlvdSBjYW4gYWNjZXNzIGBkZWNrYCBmcm9tIHRoZSBnbG9iYWwgZW52aXJvbm1lbnQ6DQoNCmBgYHtyfQ0KaGVhZChnbG9iYWxlbnYoKSRkZWNrLCAzKQ0KYGBgDQoNCkFuZCB5b3UgY2FuIHVzZSB0aGUgYGFzc2lnbmAgZnVuY3Rpb24gdG8gc2F2ZSBhbiBvYmplY3QgaW50byBhIHBhcnRpY3VsYXIgZW52aXJvbm1lbnQuDQoNCmBgYHtyfQ0KYXNzaWduKCJuZXciLCAiSGVsbG8gR2xvYmFsIiwgZW52aXIgPSBnbG9iYWxlbnYoKSkNCg0KZ2xvYmFsZW52KCkkbmV3DQpgYGANCg0KKiBUaGUgQWN0aXZlIEVudmlyb25tZW50DQoNCkF0IGFueSBtb21lbnQgb2YgdGltZSwgUiBpcyB3b3JraW5nIGNsb3NlbHkgd2l0aCBhIHNpbmdsZSBlbnZpcm9ubWVudC4gUiB3aWxsIHN0b3JlIG5ldyBvYmplY3RzIGluIHRoaXMgZW52aXJvbm1lbnQgKGlmIHlvdSBjcmVhdGUgYW55KSwgYW5kIFIgd2lsbCB1c2UgdGhpcyBlbnZpcm9ubWVudCBhcyBhIHN0YXJ0aW5nIHBvaW50IHRvIGxvb2sgdXAgZXhpc3Rpbmcgb2JqZWN0cyAoaWYgeW91IGNhbGwgYW55KS4NCg0KYGBge3J9DQplbnZpcm9ubWVudCgpDQpgYGANCg0KVGhlIGdsb2JhbCBlbnZpcm9ubWVudCBwbGF5cyBhIHNwZWNpYWwgcm9sZSBpbiBSLiBJdCBpcyB0aGUgYWN0aXZlIGVudmlyb25tZW50IGZvciBldmVyeSBjb21tYW5kIHRoYXQgeW91IHJ1biBhdCB0aGUgY29tbWFuZCBsaW5lLiBBcyBhIHJlc3VsdCwgYW55IG9iamVjdCB0aGF0IHlvdSBjcmVhdGUgYXQgdGhlIGNvbW1hbmQgbGluZSB3aWxsIGJlIHNhdmVkIGluIHRoZSBnbG9iYWwgZW52aXJvbm1lbnQuIFlvdSBjYW4gdGhpbmsgb2YgdGhlIGdsb2JhbCBlbnZpcm9ubWVudCBhcyB5b3VyIHVzZXIgd29ya3NwYWNlLg0KDQpXaGVuIHlvdSBjYWxsIGFuIG9iamVjdCBhdCB0aGUgY29tbWFuZCBsaW5lLCBSIHdpbGwgbG9vayBmb3IgaXQgZmlyc3QgaW4gdGhlIGdsb2JhbCBlbnZpcm9ubWVudC4gQnV0IHdoYXQgaWYgdGhlIG9iamVjdCBpcyBub3QgdGhlcmU/IEluIHRoYXQgY2FzZSwgUiB3aWxsIGZvbGxvdyBhIHNlcmllcyBvZiBydWxlcyB0byBsb29rIHVwIHRoZSBvYmplY3QuDQoNCioqU2NvcGluZyBSdWxlczogKioNCg0KUiBmb2xsb3dzIGEgc3BlY2lhbCBzZXQgb2YgcnVsZXMgdG8gbG9vayB1cCBvYmplY3RzLiBUaGVzZSBydWxlcyBhcmUga25vd24gYXMgUuKAmXMgc2NvcGluZyBydWxlczogDQoNCjEuIFIgbG9va3MgZm9yIG9iamVjdHMgaW4gdGhlIGN1cnJlbnQgYWN0aXZlIGVudmlyb25tZW50Lg0KMi4gV2hlbiB5b3Ugd29yayBhdCB0aGUgY29tbWFuZCBsaW5lLCB0aGUgYWN0aXZlIGVudmlyb25tZW50IGlzIHRoZSBnbG9iYWwgZW52aXJvbm1lbnQuIEhlbmNlLCBSIGxvb2tzIHVwIG9iamVjdHMgdGhhdCB5b3UgY2FsbCBhdCB0aGUgY29tbWFuZCBsaW5lIGluIHRoZSBnbG9iYWwgZW52aXJvbm1lbnQgYXMgaW4gRmlndXJlIDguMy4NCg0KIVtdKDgtMy5QTkcpDQoNCioqQXNzaWdubWVudDogKioNCg0KV2hlbiB5b3UgYXNzaWduIGEgdmFsdWUgdG8gYW4gb2JqZWN0LCBSIHNhdmVzIHRoZSB2YWx1ZSBpbiB0aGUgYWN0aXZlIGVudmlyb25tZW50IHVuZGVyIHRoZSBvYmplY3TigJlzIG5hbWUuIElmIGFuIG9iamVjdCB3aXRoIHRoZSBzYW1lIG5hbWUgYWxyZWFkeSBleGlzdHMgaW4gdGhlIGFjdGl2ZSBlbnZpcm9ubWVudCwgUiB3aWxsIG92ZXJ3cml0ZSBpdC4NCg0KYGBge3J9DQpuZXcNCmBgYA0KDQpgYGB7cn0NCm5ldyA8LSAiSGVsbG8gQWN0aXZlIg0KDQpuZXcNCmBgYA0KDQpUaGlzIGFycmFuZ2VtZW50IGNyZWF0ZXMgYSBxdWFuZGFyeSBmb3IgUiB3aGVuZXZlciBSIHJ1bnMgYSBmdW5jdGlvbi4gTWFueSBmdW5jdGlvbnMgc2F2ZSB0ZW1wb3Jhcnkgb2JqZWN0cyB0aGF0IGhlbHAgdGhlbSBkbyB0aGVpciBqb2JzLg0KDQpgYGB7cn0NCnJvbGwgPC0gZnVuY3Rpb24oKSB7DQogIGRpZSA8LSAxOjYNCiAgZGljZSA8LSBzYW1wbGUoZGllLCBzaXplID0gMiwgcmVwbGFjZSA9IFRSVUUpDQogIHN1bShkaWNlKQ0KfQ0Kcm9sbCgpDQpgYGANCg0KDQoqKkV2YWx1YXRpb246ICoqDQoNClIgY3JlYXRlcyBhIG5ldyBlbnZpcm9ubWVudCBlYWNoIHRpbWUgaXQgZXZhbHVhdGVzIGEgZnVuY3Rpb24uIFIgd2lsbCB1c2UgdGhlIG5ldyBlbnZpcm9ubWVudCBhcyB0aGUgYWN0aXZlIGVudmlyb25tZW50IHdoaWxlIGl0IHJ1bnMgdGhlIGZ1bmN0aW9uLCBhbmQgdGhlbiBSIHdpbGwgcmV0dXJuIHRvIHRoZSBlbnZpcm9ubWVudCB0aGF0IHlvdSBjYWxsZWQgdGhlIGZ1bmN0aW9uIGZyb20sIGJyaW5naW5nIHRoZSBmdW5jdGlvbuKAmXMgcmVzdWx0IHdpdGggaXQuIA0KDQpXZSB3YW50IHRvIGtub3cgd2hhdCB0aGUgZW52aXJvbm1lbnRzIGxvb2sgbGlrZTogd2hhdCBhcmUgdGhlaXIgcGFyZW50IGVudmlyb25tZW50cywgYW5kIHdoYXQgb2JqZWN0cyBkbyB0aGV5IGNvbnRhaW4/IGBzaG93X2VudmAgaXMgZGVzaWduZWQgdG8gdGVsbCB1czoNCg0KYGBge3J9DQpzaG93X2VudiA8LSBmdW5jdGlvbigpew0KICBsaXN0KHJhbi5pbiA9IGVudmlyb25tZW50KCksIA0KICAgIHBhcmVudCA9IHBhcmVudC5lbnYoZW52aXJvbm1lbnQoKSksIA0KICAgIG9iamVjdHMgPSBscy5zdHIoZW52aXJvbm1lbnQoKSkpDQp9DQpgYGANCg0KYHNob3dfZW52YCBpcyBpdHNlbGYgYSBmdW5jdGlvbiwgc28gd2hlbiB3ZSBjYWxsIHNob3dfZW52KCksIFIgd2lsbCBjcmVhdGUgYSBydW50aW1lIGVudmlyb25tZW50IHRvIGV2YWx1YXRlIHRoZSBmdW5jdGlvbiBpbi4NCg0KYGBge3J9DQpzaG93X2VudigpDQpgYGANCg0KVGhpcyB0aW1lIHNob3dfZW52IHJhbiBpbiBhIG5ldyBlbnZpcm9ubWVudCwgMHgwMDAwMDAwMDBhMDgzMWUwDQoNCiM9PVByb2plY3QgMzogU2xvdCBNYWNoaW5lPT0NCg0KIzcuIFByb2dyYW1zLVgNCg0KVGhlIGZvbGxvd2luZyBmdW5jdGlvbiBnZW5lcmF0ZXMgdGhyZWUgc3ltYm9scyBmcm9tIGEgZ3JvdXAgb2YgY29tbW9uIHNsb3QgbWFjaGluZSBzeW1ib2xzDQoNCmBgYHtyfQ0KZ2V0X3N5bWJvbHMgPC0gZnVuY3Rpb24oKSB7DQogIHdoZWVsIDwtIGMoIkREIiwgIjciLCAiQkJCIiwgIkJCIiwgIkIiLCAiQyIsICIwIikNCiAgc2FtcGxlKHdoZWVsLCBzaXplID0gMywgcmVwbGFjZSA9IFRSVUUsIA0KICAgIHByb2IgPSBjKDAuMDMsIDAuMDMsIDAuMDYsIDAuMSwgMC4yNSwgMC4wMSwgMC41MikpDQp9DQpgYGANCg0KDQpgYGB7cn0NCmdldF9zeW1ib2xzKCkNCmBgYA0KDQpgZ2V0X3N5bWJvbHNgIHVzZXMgdGhlIHByb2JhYmlsaXRpZXMgb2JzZXJ2ZWQgaW4gYSBncm91cCBvZiB2aWRlbyBsb3R0ZXJ5IHRlcm1pbmFscyBmcm9tIE1hbml0b2JhLCBDYW5hZGEuIFRoZSBNYW5pdG9iYSBzbG90IG1hY2hpbmVzIHVzZSB0aGUgY29tcGxpY2F0ZWQgcGF5b3V0IHNjaGVtZSBzaG93biBpbiBgVGFibGUgOS4xLmAgQSBwbGF5ZXIgd2lsbCB3aW4gYSBwcml6ZSBpZiBoZSBnZXRzOg0KDQoxLiBUaHJlZSBvZiB0aGUgc2FtZSB0eXBlIG9mIHN5bWJvbCAoZXhjZXB0IGZvciB0aHJlZSB6ZXJvZXMpDQoyLiBUaHJlZSBiYXJzIChvZiBtaXhlZCB2YXJpZXR5KQ0KMy4gT25lIG9yIG1vcmUgY2hlcnJpZXMNCg0KIVtdKFRhYmxlOS0xLlBORykNCg0KKiBTZXF1ZW50aWFsIFN0ZXBzDQoNClRvIGhhdmUgUiBleGVjdXRlIHN0ZXBzIGluIHNlcXVlbmNlLCBwbGFjZSB0aGUgc3RlcHMgb25lIGFmdGVyIGFub3RoZXIgaW4gYW4gUiBzY3JpcHQgb3IgZnVuY3Rpb24gYm9keS4gU2VlIEZpZ3VyZSA5LjENCg0KIVtdKDktMS5QTkcpDQoNCg0KKiBQYXJhbGxlbCBDYXNlcw0KDQpBbm90aGVyIHdheSB0byBkaXZpZGUgYSB0YXNrIGlzIHRvIHNwb3QgZ3JvdXBzIG9mIHNpbWlsYXIgY2FzZXMgd2l0aGluIHRoZSB0YXNrLiBTb21lIHRhc2tzIHJlcXVpcmUgZGlmZmVyZW50IGFsZ29yaXRobXMgZm9yIGRpZmZlcmVudCBncm91cHMgb2YgaW5wdXQuIElmIHlvdSBjYW4gaWRlbnRpZnkgdGhvc2UgZ3JvdXBzLCB5b3UgY2FuIHdvcmsgb3V0IHRoZWlyIGFsZ29yaXRobXMgb25lIGF0IGEgdGltZS4gU2VlIEZpZ3VyZSA5LjIgYW5kIEZpZ3VyZSA5LjMNCg0KIVtdKDktMi5QTkcpDQoNCiFbXSg5LTMuUE5HKQ0KDQoNCg0KKippZiBTdGF0ZW1lbnRzOiAqKg0KDQpBbiBgaWZgIHN0YXRlbWVudCB0ZWxscyBSIHRvIGRvIGEgY2VydGFpbiB0YXNrIGZvciBhIGNlcnRhaW4gY2FzZS4gSW4gRW5nbGlzaCB5b3Ugd291bGQgc2F5IHNvbWV0aGluZyBsaWtlLCDigJxJZiB0aGlzIGlzIHRydWUsIGRvIHRoYXQu4oCdIEluIFIsIHlvdSB3b3VsZCBzYXk6DQoNCmBgYHtyfQ0KIyBpZiAodGhpcykgew0KIyAgIHRoYXQNCiMgfQ0KYGBgDQoNCg0KYGBge3J9DQp4IDwtIDENCmlmICgzID09IDMpIHsNCiAgeCA8LSAyDQp9DQp4DQpgYGANCg0KDQoqKmVsc2UgU3RhdGVtZW50czogKioNCg0KYGBge3J9DQojIGlmICh0aGlzKSB7DQojICAgUGxhbiBBDQojIH0gZWxzZSB7DQojICAgUGxhbiBCDQojIH0NCmBgYA0KDQpgYGB7cn0NCmEgPC0gMQ0KYiA8LSAxDQoNCmlmIChhID4gYikgew0KICBwcmludCgiQSB3aW5zISIpDQp9IGVsc2UgaWYgKGEgPCBiKSB7DQogIHByaW50KCJCIHdpbnMhIikNCn0gZWxzZSB7DQogIHByaW50KCJUaWUuIikNCn0NCmBgYA0KDQoNCmBgYHtyfQ0KIyBpZiAoICMgQ2FzZSAxOiBhbGwgdGhlIHNhbWUgPDE+KSB7DQojICAgcHJpemUgPC0gIyBsb29rIHVwIHRoZSBwcml6ZSA8Mz4NCiMgfSBlbHNlIGlmICggIyBDYXNlIDI6IGFsbCBiYXJzIDwyPiApIHsNCiMgICBwcml6ZSA8LSAjIGFzc2lnbiAkNSA8ND4NCiMgfSBlbHNlIHsNCiMgICAjIGNvdW50IGNoZXJyaWVzIDw1Pg0KIyAgIHByaXplIDwtICMgY2FsY3VsYXRlIGEgcHJpemUgPDc+DQojIH0NCmBgYA0KDQpJZiB5b3UgbGlrZSwgeW91IGNhbiByZW9yZ2FuaXplIHlvdXIgZmxvdyBjaGFydCBhcm91bmQgdGhlc2UgdGFza3MsIGFzIGluIEZpZ3VyZSA5LjQuIFRoZSBjaGFydCB3aWxsIGRlc2NyaWJlIHRoZSBzYW1lIHN0cmF0ZWd5LCBidXQgaW4gYSBtb3JlIHByZWNpc2Ugd2F5LiBJ4oCZbGwgdXNlIGEgZGlhbW9uZCBzaGFwZSB0byBzeW1ib2xpemUgYW4gaWYgZWxzZSBkZWNpc2lvbi4gU2VlIEZpZ3VyZSA5LTQuDQoNCiFbXSg5LTQuUE5HKQ0KDQoNCioqTG9va3VwIFRhYmxlczogKioNCg0KVmVyeSBvZnRlbiBpbiBSLCB0aGUgc2ltcGxlc3Qgd2F5IHRvIGRvIHNvbWV0aGluZyB3aWxsIGludm9sdmUgc3Vic2V0dGluZy4gSG93IGNvdWxkIHlvdSB1c2Ugc3Vic2V0dGluZyBoZXJlPyBTaW5jZSB5b3Uga25vdyB0aGUgZXhhY3QgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHN5bWJvbHMgYW5kIHRoZWlyIHByaXplcywgeW91IGNhbiBjcmVhdGUgYSB2ZWN0b3IgdGhhdCBjYXB0dXJlcyB0aGlzIGluZm9ybWF0aW9uLg0KDQpgYGB7cn0NCnBheW91dHMgPC0gYygiREQiID0gMTAwLCAiNyIgPSA4MCwgIkJCQiIgPSA0MCwgIkJCIiA9IDI1LCANCiAgIkIiID0gMTAsICJDIiA9IDEwLCAiMCIgPSAwKQ0KcGF5b3V0cw0KYGBgDQoNCk5vdyB5b3UgY2FuIGV4dHJhY3QgdGhlIGNvcnJlY3QgcHJpemUgZm9yIGFueSBzeW1ib2wgYnkgc3Vic2V0dGluZyB0aGUgdmVjdG9yIHdpdGggdGhlIHN5bWJvbOKAmXMgbmFtZToNCg0KYGBge3J9DQpwYXlvdXRzWyJERCJdDQpgYGANCg0KDQpgYGB7cn0NCnBheW91dHNbIkIiXQ0KYGBgDQoNCg0KSWYgeW91IHdhbnQgdG8gbGVhdmUgYmVoaW5kIHRoZSBzeW1ib2zigJlzIG5hbWUgd2hlbiBzdWJzZXR0aW5nLCB5b3UgY2FuIHJ1biB0aGUgYHVubmFtZWAgZnVuY3Rpb24gb24gdGhlIG91dHB1dDoNCg0KYGBge3J9DQp1bm5hbWUocGF5b3V0c1siREQiXSkNCmBgYA0KDQpgdW5uYW1lYCByZXR1cm5zIGEgY29weSBvZiBhbiBvYmplY3Qgd2l0aCB0aGUgbmFtZXMgYXR0cmlidXRlIHJlbW92ZWQuDQoNCmBwYXlvdXRzYCBpcyBhIHR5cGUgb2YgbG9va3VwIHRhYmxlLCBhbiBSIG9iamVjdCB0aGF0IHlvdSBjYW4gdXNlIHRvIGxvb2sgdXAgdmFsdWVzLiBTdWJzZXR0aW5nIHBheW91dHMgcHJvdmlkZXMgYSBzaW1wbGUgd2F5IHRvIGZpbmQgdGhlIHByaXplIGZvciBhIHN5bWJvbC4gSXQgZG9lc27igJl0IHRha2UgbWFueSBsaW5lcyBvZiBjb2RlLCBhbmQgaXQgZG9lcyB0aGUgc2FtZSBhbW91bnQgb2Ygd29yayB3aGV0aGVyIHlvdXIgc3ltYm9sIGlzIGBERGAgb3IgYDBgLg0KDQpTYWRseSwgb3VyIG1ldGhvZCBpcyBub3QgcXVpdGUgYXV0b21hdGljOyB3ZSBuZWVkIHRvIHRlbGwgUiB3aGljaCBzeW1ib2wgdG8gbG9vayB1cCBpbiBgYHBheW91dHNgDQoNCmBgYHtyfQ0Kc3ltYm9scyA8LSBjKCI3IiwgIjciLCAiNyIpDQpzeW1ib2xzWzFdDQojIyAiNyINCg0KcGF5b3V0c1tzeW1ib2xzWzFdXQ0KIyMgIDcgDQojIyA4MCANCg0Kc3ltYm9scyA8LSBjKCJDIiwgIkMiLCAiQyIpDQpwYXlvdXRzW3N5bWJvbHNbMV1dDQojIyAgQyANCiMjIDEwIA0KYGBgDQoNCg0KWW91IGRvbuKAmXQgbmVlZCB0byBrbm93IHRoZSBleGFjdCBzeW1ib2wgdG8gbG9vayB1cCBiZWNhdXNlIHlvdSBjYW4gdGVsbCBSIHRvIGxvb2sgdXAgd2hpY2hldmVyIHN5bWJvbCBoYXBwZW5zIHRvIGJlIGluIGBzeW1ib2xzYC4gDQoNCg0KDQoNCiM4LiBTMy1YDQoNCiM5LiBMb29wcy1YDQoNCiMxMC4gU3BlZWQtWA0KDQojQXBwZW5kaXgNCg0KIyNBLiBJbnN0YWxsaW5nIFIgYW5kIFJzdHVkaW8NCg0KWW91J2xsIGdvIGZyb20gZG93bmxvYWRpbmcgUiB0byBvcGVuaW5nIHlvdXIgZmlyc3QgUiBzZXNzaW9uLiBCb3RoIFIgYW5kIFJTdHVkaW8gYXJlIGZyZWUgYW5kIGVhc3kgdG8gZG93bmxvYWQgKE9wZW4gU291cmNlKS4NCg0KKipIb3cgdG8gRG93bmxvYWQgYW5kIEluc3RhbGwgUjogKioNCg0KUiBpcyBtYWludGFpbmVkIGJ5IGFuIGludGVybmF0aW9uYWwgdGVhbSBvZiBkZXZlbG9wZXJzIHdobyBtYWtlIHRoZSBsYW5ndWFnZSBhdmFpbGFibGUgdGhyb3VnaCB0aGUgd2ViIHBhZ2Ugb2YgVGhlIENvbXByZWhlbnNpdmUgUiBBcmNoaXZlIE5ldHdvcmsuIFRoZSB0b3Agb2YgdGhlIHdlYiBwYWdlIHByb3ZpZGVzIHRocmVlIGxpbmtzIGZvciBkb3dubG9hZGluZyBSLiBGb2xsb3cgdGhlIGxpbmsgdGhhdCBkZXNjcmliZXMgeW91ciBvcGVyYXRpbmcgc3lzdGVtOiBXaW5kb3dzLCBNYWMsIG9yIExpbnV4LiBodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy8NCg0KKiBXaW5kb3dzLyBNYWMvIExpbnV4DQoNClRvIGluc3RhbGwgUiBvbiBXaW5kb3dzL01hYy9MaW51eCwgY2xpY2sgdGhlICJEb3dubG9hZCBSIGZvciBXaW5kb3dzIiBsaW5rLiBUaGVuIGNsaWNrIHRoZSAiYmFzZSIgbGluay4gTmV4dCwgY2xpY2sgdGhlIGZpcnN0IGxpbmsgYXQgdGhlIHRvcCBvZiB0aGUgbmV3IHBhZ2UuIA0KDQoqIDMyLWJpdCBWZXJzdXMgNjQtYml0DQoNCjY0LWJpdCBSIHVzZXMgNjQtYml0IG1lbW9yeSBwb2ludGVycywgYW5kIDMyLWJpdCBSIHVzZXMgMzItYml0IG1lbW9yeSBwb2ludGVycy4gVGhpcyBtZWFucyA2NC1iaXQgUiBoYXMgYSBsYXJnZXIgbWVtb3J5IHNwYWNlIHRvIHVzZSAoYW5kIHNlYXJjaCB0aHJvdWdoKS4gVGhlIHRlcm1zIDMyLWJpdCBhbmQgNjQtYml0IHJlZmVyIHRvIHRoZSB3YXkgYSBjb21wdXRlcidzIHByb2Nlc3NvciAoYWxzbyBjYWxsZWQgYSBDUFUpLCBoYW5kbGVzIGluZm9ybWF0aW9uLiBUaGUgNjQtYml0IHZlcnNpb24gb2YgV2luZG93cyBoYW5kbGVzIGxhcmdlIGFtb3VudHMgb2YgcmFuZG9tIGFjY2VzcyBtZW1vcnkgKFJBTSkgbW9yZSBlZmZlY3RpdmVseSB0aGFuIGEgMzItYml0IHN5c3RlbS4gU291cmNlOiBodHRwczovL3N1cHBvcnQubWljcm9zb2Z0LmNvbS9lbi11cy9oZWxwLzE1MDU2L3dpbmRvd3MtNy0zMi02NC1iaXQtZmFxDQoNCg0KDQoNCg0KDQoqKlVzaW5nIFI6ICoqDQoNClIgaXNuJ3QgYSBwcm9ncmFtIHRoYXQgeW91IGNhbiBvcGVuIGFuZCBzdGFydCB1c2luZywgbGlrZSBNaWNyb3NvZnQgV29yZCBvciBJbnRlcm5ldCBFeHBsb3Jlci4gSW5zdGVhZCwgUiBpcyBhIGNvbXB1dGVyIGxhbmd1YWdlLCBsaWtlIEMsIEMrKywgb3IgVU5JWC4gTm93IGFsbW9zdCBldmVyeW9uZSB1c2VzIFIgd2l0aCBhbiBhcHBsaWNhdGlvbiBjYWxsZWQgUlN0dWRpbyBJREUgKEludGVncmF0ZWQgRGV2ZWxvcG1lbnQpLiANCg0KDQpXaW5kb3dzIGFuZCBNYWMgdXNlcnMgdXN1YWxseSBkbyBub3QgcHJvZ3JhbSBmcm9tIGEgdGVybWluYWwgd2luZG93LCBzbyB0aGUgV2luZG93cyBhbmQgTWFjIGRvd25sb2FkcyBmb3IgUiBjb21lIHdpdGggYSBzaW1wbGUgcHJvZ3JhbSB0aGF0IG9wZW5zIGEgdGVybWluYWwtbGlrZSB3aW5kb3cgZm9yIHlvdSB0byBydW4gUiBjb2RlIGluLiBZb3UgbWF5IGhlYXIgcGVvcGxlIHJlZmVyIHRvIHRoZW0gYXMgdGhlIFdpbmRvd3Mgb3IgTWFjIFIgR1VJcyAoR3JhZmljcyBVc2VyIEludGVyZmFjZXMuDQoNCldoZW4geW91IG9wZW4gUlN0dWRpbywgYSB3aW5kb3cgYXBwZWFycyB3aXRoIHRocmVlIHBhbmVzIGluIGl0LCBhcyBpbiBgRmlndXJlIEEtMWAudlRoZSBsYXJnZXN0IHBhbmUgaXMgYSBjb25zb2xlIHdpbmRvdy4gVGhpcyBpcyB3aGVyZSB5b3UnbGwgcnVuIHlvdXIgUiBjb2RlIGFuZCBzZWUgcmVzdWx0cy4gVGhlIGNvbnNvbGUgd2luZG93IGlzIGV4YWN0bHkgd2hhdCB5b3UnZCBzZWUgaWYgeW91IHJhbiBSIGZyb20gYSBVTklYIGNvbnNvbGUgb3IgdGhlIFdpbmRvd3Mgb3IgTWFjIEdVSXMuDQoNCiFbXShBLTEuUE5HKQ0KDQoNCioqUlN0dWRpbzogKioNCg0KUlN0dWRpbyBpcyBhbiBhcHBsaWNhdGlvbiBsaWtlIE1pY3Jvc29mdCBXb3JkLWV4Y2VwdCB0aGF0IGluc3RlYWQgb2YgaGVscGluZyB5b3Ugd3JpdGUgaW4gRW5nbGlzaCwgUlN0dWRpbyBoZWxwcyB5b3Ugd3JpdGUgaW4gUi4gDQoNCioqR2V0dGluZyBzdGFydGVkIFIgUHJvZ3JhbW1pbmc6ICoqDQoNCk5vdyB0aGF0IHlvdSBoYXZlIGJvdGggUiBhbmQgUlN0dWRpbyBvbiB5b3VyIGNvbXB1dGVyLCB5b3UgY2FuIGJlZ2luIHVzaW5nIFIgYnkgb3BlbmluZyB0aGUgUlN0dWRpbyBwcm9ncmFtLiBPcGVuIFJTdHVkaW8ganVzdCBhcyB5b3Ugd291bGQgYW55IHByb2dyYW0sIGJ5IGNsaWNraW5nIG9uIGl0cyBpY29uIG9yIGJ5IHR5cGluZyAiUlN0dWRpbyIgYXQgdGhlIFdpbmRvd3MgUnVuIHByb21wdC4NCg0KDQojI0IuIFIgUGFja2FnZXMNCg0KKiBNYW55IG9mIFIncyBtb3N0IHVzZWZ1bCBmdW5jdGlvbnMgZG8gbm90IGNvbWUgcHJlbG9hZGVkIHdoZW4geW91IHN0YXJ0IFIsIGJ1dCByZXNpZGUgaW4gcGFja2FnZXMgdGhhdCBjYW4gYmUgaW5zdGFsbGVkIG9uIHRvcCBvZiBSLiANCiogUiBwYWNrYWdlcyBhcmUgc2ltaWxhciB0byBsaWJyYXJpZXMgaW4gQywgQyArKywgYW5kIEphdmFzY3JpcHQsIHBhY2thZ2VzIGluIFB5dGhvbiwgYW5kIGdlbXMgaW4gUnVieS4gDQpBbiBSIHBhY2thZ2UgYnVuZGxlcyB0b2dldGhlciB1c2VmdWwgZnVuY3Rpb25zLCBoZWxwIGZpbGVzLCBhbmQgZGF0YSBzZXRzLiBZb3UgY2FuIHVzZSB0aGVzZSBmdW5jdGlvbnMgd2l0aGluIHlvdXIgb3duIFIgY29kZSBvbmNlIHlvdSBsb2FkIHRoZSBwYWNrYWdlIHRoZXkgbGl2ZSBpbi4NCg0KUiBwYWNrYWdlcyB3aWxsIGxldCB5b3UgdGFrZSBhZHZhbnRhZ2Ugb2YgUidzIG1vc3QgdXNlZnVsIGZlYXR1cmVzOiANCg0KKiBpdHMgbGFyZ2UgY29tbXVuaXR5IG9mIHBhY2thZ2Ugd3JpdGVycyAobWFueSBvZiB3aG9tIGFyZSBhY3RpdmUgZGF0YSBzY2llbnRpc3RzKSANCiogYW5kIGl0cyBwcmV3cml0dGVuIHJvdXRpbmVzIGZvciBoYW5kbGluZyBtYW55IGNvbW1vbiAoYW5kIGV4b3RpYykgZGF0YS1zY2llbmNlIHRhc2tzDQoNCj4gQmFzZSBSOiBJdCBpcyBqdXN0IHRoZSBjb2xsZWN0aW9uIG9mIFIgZnVuY3Rpb25zIHRoYXQgZ2V0cyBsb2FkZWQgZXZlcnkgdGltZSB5b3Ugc3RhcnQgUi4gVGhlc2UgZnVuY3Rpb25zIHByb3ZpZGUgdGhlIGJhc2ljcyBvZiB0aGUgbGFuZ3VhZ2UsIGFuZCB5b3UgZG9uJ3QgaGF2ZSB0byBsb2FkIGEgcGFja2FnZSBiZWZvcmUgeW91IGNhbiB1c2UgdGhlbS4gDQoNCioqSW5zdGFsbGluZyBQYWNrYWdlczogKioNCg0KVGhlIGVhc2llc3Qgd2F5IHRvIGluc3RhbGwgYW4gUiBwYWNrYWdlIGlzIHdpdGggdGhlIGBpbnN0YWxsLnBhY2thZ2VzYCBSIGZ1bmN0aW9uLiBgaW5zdGFsbC5wYWNrYWdlcygicGFja2FnZSBuYW1lIilgDQoNClRoaXMgd2lsbCBzZWFyY2ggZm9yIHRoZSBzcGVjaWZpZWQgcGFja2FnZSBpbiB0aGUgY29sbGVjdGlvbiBvZiBwYWNrYWdlcyBob3N0ZWQgb24gdGhlIENSQU4gc2l0ZS4gV2hlbiBSIGZpbmRzIHRoZSBwYWNrYWdlLCBpdCB3aWxsIGRvd25sb2FkIGl0IGludG8gYSBsaWJyYXJpZXMgZm9sZGVyIG9uIHlvdXIgY29tcHV0ZXIuIFIgY2FuIGFjY2VzcyB0aGUgcGFja2FnZSBoZXJlIGluIGZ1dHVyZSBSIHNlc3Npb25zIHdpdGhvdXQgcmVpbnN0YWxsaW5nIGl0LiANCg0KDQpZb3UgY2FuIGluc3RhbGwgbXVsdGlwbGUgcGFja2FnZXMgYXQgb25jZSBieSBsaW5raW5nIHRoZWlyIG5hbWVzIHdpdGggUidzIGNvbmNhdGVuYXRlIGZ1bmN0aW9uLCBgY2AuIA0KRm9yIGV4YW1wbGUsIHRvIGluc3RhbGwgdGhlIGBnZ3Bsb3QyYCwgYHJlc2hhcGUyYCwgYW5kIGBkcGx5cmAgcGFja2FnZXMsIHJ1bjoNCg0KDQpgaW5zdGFsbC5wYWNrYWdlcyhjKCJnZ3Bsb3QyIiwgInJlc2hhcGUyIiwgImRwbHlyIikpYA0KDQoNCioqTG9hZGluZyBQYWNrYWdlczogKioNCg0KSW5zdGFsbGluZyBhIHBhY2thZ2UgZG9lc24ndCBpbW1lZGlhdGVseSBwbGFjZSBpdHMgZnVuY3Rpb25zIGF0IHlvdXIgZmluZ2VydGlwcy4gSXQganVzdCBwbGFjZXMgdGhlbSBvbiB5b3VyIGNvbXB1dGVyLiBUbyB1c2UgYW4gUiBwYWNrYWdlLCB5b3UgbmV4dCBoYXZlIHRvIGxvYWQgaXQgaW4geW91ciBSIHNlc3Npb24gd2l0aCB0aGUgY29tbWFuZDoNCg0KYGxpYnJhcnkocGFja2FnZSBuYW1lKWANCg0KTGlicmFyeSB3aWxsIG1ha2UgYWxsIG9mIHRoZSBwYWNrYWdlJ3MgZnVuY3Rpb25zLCBkYXRhIHNldHMsIGFuZCBoZWxwIGZpbGVzIGF2YWlsYWJsZSB0byB5b3UgdW50aWwgeW91IGNsb3NlIHlvdXIgY3VycmVudCBSIHNlc3Npb24uIFRoZSBuZXh0IHRpbWUgeW91IGJlZ2luIGFuIFIgc2Vzc2lvbiwgeW91J2xsIGhhdmUgdG8gcmVsb2FkIHRoZSBwYWNrYWdlIHdpdGggbGlicmFyeSBpZiB5b3Ugd2FudCB0byB1c2UgaXQsIGJ1dCB5b3Ugd29uJ3QgaGF2ZSB0byByZWluc3RhbGwgaXQuIA0KDQpZb3Ugb25seSBoYXZlIHRvIGluc3RhbGwgZWFjaCBwYWNrYWdlIG9uY2UuIEFmdGVyIHRoYXQsIGEgY29weSBvZiB0aGUgcGFja2FnZSB3aWxsIGxpdmUgaW4geW91ciBSIGxpYnJhcnkuIFRvIHNlZSB3aGljaCBwYWNrYWdlcyB5b3UgY3VycmVudGx5IGhhdmUgaW4geW91ciBSIGxpYnJhcnksIHJ1bjoNCg0KYGxpYnJhcnkoKWANCg0KYGxpYnJhcnkoKWAgYWxzbyBzaG93cyB0aGUgcGF0aCB0byB5b3VyIGFjdHVhbCBSIGxpYnJhcnksIHdoaWNoIGlzIHRoZSBmb2xkZXIgdGhhdCBjb250YWlucyB5b3VyIFIgcGFja2FnZXMuIFlvdSBtYXkgbm90aWNlIG1hbnkgcGFja2FnZXMgdGhhdCB5b3UgZG9uJ3QgcmVtZW1iZXIgaW5zdGFsbGluZy4gVGhpcyBpcyBiZWNhdXNlIFIgYXV0b21hdGljYWxseSBkb3dubG9hZHMgYSBzZXQgb2YgdXNlZnVsIHBhY2thZ2VzIHdoZW4geW91IGZpcnN0IGluc3RhbGwgUi4NCg0KSW5zdGFsbCBwYWNrYWdlcyBmcm9tIChhbG1vc3QpIGFueXdoZXJlIFRoZSBkZXZ0b29scyBSIHBhY2thZ2UgbWFrZXMgaXQgZWFzeSB0byBpbnN0YWxsIHBhY2thZ2VzIGZyb20gbG9jYXRpb25zIG90aGVyIHRoYW4gdGhlIENSQU4gd2Vic2l0ZS4gZGV2dG9vbHMgcHJvdmlkZXMgZnVuY3Rpb25zIGxpa2UgDQoNCiogaW5zdGFsbF9naXRodWIgDQoqIGluc3RhbGxfZ2l0b3Jpb3VzDQoqIGluc3RhbGxfYml0YnVja2V0DQoqIGluIHN0YWxsX3VybA0KDQpUaGVzZSB3b3JrIHNpbWlsYXIgdG8gaW5zdGFsbC5wYWNrYWdlcywgYnV0IHRoZXkgc2VhcmNoIG5ldyBsb2NhdGlvbnMgZm9yIFIgcGFja2FnZXMuIGBpbnN0YWxsX2dpdGh1YmAgaXMgZXNwZWNpYWxseSB1c2VmdWwgYmVjYXVzZSBtYW55IFIgZGV2ZWxvcGVycyBwcm92aWRlIGRldmVsb3BtZW50IHZlcnNpb25zIG9mIHRoZWlyIHBhY2thZ2VzIG9uIEdpdEh1Yi4gVGhlIGRldmVsb3BtZW50IHZlcnNpb24gb2YgYSBwYWNrYWdlIHdpbGwgY29udGFpbiBhIHNuZWFrIHBlZWsgb2YgbmV3IGZ1bmN0aW9ucyBhbmQgcGF0Y2hlcyBidXQgbWF5IG5vdCBiZSBhcyBzdGFibGUgb3IgYXMgYnVnIGZyZWUgYXMgdGhlIENSQU4gdmVyc2lvbi4NCg0KDQpXaHkgZG9lcyBSIG1ha2UgeW91IGJvdGhlciB3aXRoIGluc3RhbGxpbmcgYW5kIGxvYWRpbmcgcGFja2FnZXM/IA0KDQoqIElmIGV2ZXJ5IHBhY2tlZCBsb2FkLT4gdmVyeSBsYXJnZSBhbmQgc2xvdyBwcm9ncmFtDQoqIEl0IGlzIHNpbXBsZXIgdG8gb25seSBpbnN0YWxsIGFuZCBsb2FkIHRoZSBwYWNrYWdlcyB0aGF0IHlvdSB3YW50IHRvIHVzZSB3aGVuIHlvdSB3YW50IHRvIHVzZSB0aGVtLiANCiogSXQgaXMgcG9zc2libGUgdG8gdXBkYXRlIHlvdXIgY29weSBvZiBhbiBSIHBhY2thZ2Ugd2l0aG91dCB1cGRhdGluZyB5b3VyIGVudGlyZSBjb3B5IG9mIFIuDQoNCg0KV2hhdCdzIHRoZSBiZXN0IHdheSB0byBsZWFybiBhYm91dCBSIHBhY2thZ2VzPyANCg0KKiBUaGUgUi1wYWNrYWdlcyBtYWlsaW5nIGxpc3QgaXMgYSBwbGFjZSB0byBzdGFydC46IGh0dHBzOi8vc3RhdC5ldGh6LmNoL21haWxtYW4vbGlzdGluZm8vci1wYWNrYWdlcw0KKiBCbG9nczogIHd3dy5yLWJsb2dnZXJzLmNvbQ0KKiBSU3R1ZGlvOiBodHRwOi8vc3VwcG9ydC5yc3R1ZGlvLmNvbS4NCiogQ1JBTiBncm91cHMgcGFja2FnZXMgYnkgc3ViamVjdCBhcmVhOiBodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvdmlld3MvDQogIA0KDQoNCiMjQy4gVXBkYXRpbmcgUiBhbmQgSXRzIFBhY2thZ2VzDQoNClRoZSBSIENvcmUgRGV2ZWxvcG1lbnQgVGVhbSBjb250aW51b3VzbHkgaG9uZXMgdGhlIFIgbGFuZ3VhZ2UgYnkgY2F0Y2hpbmcgYnVncywgaW1wcm92aW5nIHBlcmZvcm1hbmNlLCBhbmQgdXBkYXRpbmcgUiB0byB3b3JrIHdpdGggbmV3IHRlY2hub2xvZ2llcy4gVGhlIGVhc2llc3Qgd2F5IHRvIHN0YXkgY3VycmVudCB3aXRoIFIgaXMgdG8gcGVyaW9kaWNhbGx5IGNoZWNrIHRoZSBDUkFOIHdlYnNpdGU6IGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnDQoNClJTdHVkaW8gYWxzbyBjb25zdGFudGx5IGltcHJvdmVzIGl0cyBwcm9kdWN0LiBZb3UgY2FuIGFjcXVpcmUgdGhlIG5ld2VzdCB1cGRhdGVzIGp1c3QgYnkgZG93bmxvYWRpbmcgdGhlbSBmcm9tIFJTdHVkaW8uIA0KDQoqIFIgUGFja2FnZXMNCg0KUGFja2FnZSBhdXRob3JzIG9jY2FzaW9uYWxseSByZWxlYXNlIG5ldyB2ZXJzaW9ucyBvZiB0aGVpciBwYWNrYWdlcyB0byBhZGQgZnVuY3Rpb25zLCBmaXggYnVncywgb3IgaW1wcm92ZSBwZXJmb3JtYW5jZS4gYHVwZGF0ZS5wYWNrYWdlcyhjKCJnZ3Bsb3QyIiwgInJlc2hhcGUyIiwgImRwbHlyIikpYA0KDQoNCg0KDQojI0QuIExvYWRpbmcgYW5kIFNhdmluZyBEYXRhIGluIFINCg0KKiBEYXRhIFNldHMgaW4gQmFzZSBSDQoNCkltcG9ydCBgZGVja2AuDQoNCmBgYHtyfQ0KZGVjaw0KYGBgDQoNClRoZXNlIGRhdGEgc2V0cyBhcmUgbm90IHZlcnkgaW50ZXJlc3RpbmcsIGJ1dCB0aGV5IGdpdmUgeW91IGEgY2hhbmNlIHRvIHRlc3QgY29kZSBvciBtYWtlIGEgcG9pbnQgd2l0aG91dCBoYXZpbmcgdG8gbG9hZCBhIGRhdGEgc2V0IGZyb20gb3V0c2lkZSBSLiBZb3UgY2FuIHNlZSBhIGxpc3Qgb2YgUidzIGRhdGEgc2V0cyBhcyB3ZWxsIGFzIGEgc2hvcnQgZGVzY3JpcHRpb24gb2YgZWFjaCBieSBydW5uaW5nOiBgaGVscChwYWNrYWdlID0gImRhdGFzZXRzIilgDQoNCmBgYHtyfQ0KaGVscChwYWNrYWdlID0gImRhdGFzZXRzIikNCmBgYA0KDQpUbyB1c2UgYSBkYXRhIHNldCwganVzdCB0eXBlIGl0cyBuYW1lLiBFYWNoIGRhdGEgc2V0IGlzIGFscmVhZHkgcHJlc2F2ZWQgYXMgYW4gUiBvYmplY3QuIEZvciBleGFtcGxlOiBpcmlzIChFZGdhciBBbmRlcnNvbidzIElyaXMgRGF0YSkNCg0KYGBge3J9DQppcmlzDQpgYGANCg0KKiBXb3JraW5nIERpcmVjdG9yeQ0KDQpFYWNoIHRpbWUgeW91IG9wZW4gUiwgaXQgbGlua3MgaXRzZWxmIHRvIGEgZGlyZWN0b3J5IG9uIHlvdXIgY29tcHV0ZXIsIHdoaWNoIFIgY2FsbHMgdGhlIHdvcmtpbmcgZGlyZWN0b3J5LiBUaGlzIGlzIHdoZXJlIFIgd2lsbCBsb29rIGZvciBmaWxlcyB3aGVuIHlvdSBhdHRlbXB0IHRvIGxvYWQgdGhlbSwgYW5kIGl0IGlzIHdoZXJlIFIgd2lsbCBzYXZlIGZpbGVzIHdoZW4geW91IHNhdmUgdGhlbS4gDQoNCg0KVG8gZGV0ZXJtaW5lIHdoaWNoIGRpcmVjdG9yeSBSIGlzIHVzaW5nIGFzIHlvdXIgd29ya2luZyBkaXJlY3RvcnksIHJ1bjogYGdldHdkKClgDQoNCmBgYHtyfQ0KZ2V0d2QoKQ0KYGBgDQoNCg0KWW91IGNhbiBwbGFjZSBkYXRhIGZpbGVzIHN0cmFpZ2h0IGludG8gdGhlIGZvbGRlciB0aGF0IGlzIHlvdXIgd29ya2luZyBkaXJlY3RvcnksIG9yIHlvdSBjYW4gbW92ZSB5b3VyIHdvcmtpbmcgZGlyZWN0b3J5IHRvIHdoZXJlIHlvdXIgZGF0YSBmaWxlcyBhcmUuIFlvdSBjYW4gbW92ZSB5b3VyIHdvcmtpbmcgZGlyZWN0b3J5IHRvIGFueSBmb2xkZXIgb24geW91ciBjb21wdXRlciB3aXRoIHRoZSBmdW5jdGlvbiBgc2V0d2QoKWANCg0KDQpZb3UgY2FuIGFsc28gY2hhbmdlIHlvdXIgd29ya2luZyBkaXJlY3RvcnkgYnkgY2xpY2tpbmcgb24gU2Vzc2lvbiA+IFNldCBXb3JraW5nIERpcmVjdG9yeSA+IENob29zZSBEaXJlY3RvcnkgaW4gdGhlIFJTdHVkaW8gbWVudSBiYXIuIA0KDQoNCllvdSBjYW4gc2VlIHdoYXQgZmlsZXMgYXJlIGluIHlvdXIgd29ya2luZyBkaXJlY3Rvcnkgd2l0aCBsaXN0LmZpbGVzKCkuDQoNCmBgYHtyfQ0KbGlzdC5maWxlcygpDQpgYGANCg0KDQoqIFBsYWluLXRleHQgRmlsZXMNCg0KUGxhaW4tdGV4dCBmaWxlcyBhcmUgb25lIG9mIHRoZSBtb3N0IGNvbW1vbiB3YXlzIHRvIHNhdmUgZGF0YS4gVGhleSBhcmUgdmVyeSBzaW1wbGUgYW5kIGNhbiBiZSByZWFkIGJ5IG1hbnkgZGlmZmVyZW50IGNvbXB1dGVyIHByb2dyYW1zLWV2ZW4gdGhlIG1vc3QgYmFzaWMgdGV4dCBlZGl0b3JzLiBGb3IgdGhpcyByZWFzb24sIHB1YmxpYyBkYXRhIG9mdGVuIGNvbWVzIGFzIHBsYWluLXRleHQgZmlsZXMuDQoNCkFsbCBwbGFpbi10ZXh0IGZpbGVzIGNhbiBiZSBzYXZlZCB3aXRoIHRoZSBleHRlbnNpb24gLnR4dCAoZm9yIHRleHQpLCBidXQgc29tZXRpbWVzIGEgZmlsZSB3aWxsIHJlY2VpdmUgYSBzcGVjaWFsIGV4dGVuc2lvbiB0aGF0IGFkdmVydGlzZXMgaG93IGl0IHNlcGFyYXRlcyBkYXRhLWNlbGwgZW50cmllcy4gU2luY2UgZW50cmllcyBpbiB0aGUgZGF0YSBzZXQgbWVudGlvbmVkIGVhcmxpZXIgYXJlIHNlcGFyYXRlZCB3aXRoIGEgY29tbWEsIHRoaXMgZmlsZSB3b3VsZCBiZSBhIGNvbW1hLXNlcGFyYXRlZC12YWx1ZXMgZmlsZSBhbmQgd291bGQgdXN1YWxseSBiZSBzYXZlZCB3aXRoIHRoZSBleHRlbnNpb24gLmNzdi4gDQoNCg0KKiByZWFkLnRhYmxlDQoNClRvIGxvYWQgYSBwbGFpbi10ZXh0IGZpbGUsIHVzZSBgcmVhZC50YWJsZWAuSWYgdGhlIHJveWFsIGZsdXNoIGRhdGEgc2V0IHdhcyBzYXZlZCBhcyBhIGZpbGUgbmFtZWQgcG9rZXIuY3N2IGluIHlvdXIgd29ya2luZyBkaXJlY3RvcnksIHlvdSBjb3VsZCBsb2FkIGl0IHdpdGg6DQoNCmBgYHtyfQ0KcG9rZXIgPC0gcmVhZC50YWJsZSgiZGVjay5jc3YiLCBzZXAgPSAiLCIsIGhlYWRlciA9IFRSVUUpDQpgYGANCg0KDQpNb3JlIGFib3V0IHJlYWQudGFibGUsIHNlZSB0aGUgZG9jdW1lbnRhdGlvbiBodHRwczovL3d3dy5yZG9jdW1lbnRhdGlvbi5vcmcvcGFja2FnZXMvdXRpbHMvdmVyc2lvbnMvMy41LjMvdG9waWNzL3JlYWQudGFibGUNCnNlcDogVXNlIHNlcCB0byB0ZWxsIHJlYWQudGFibGUgd2hhdCBjaGFyYWN0ZXIgeW91ciBmaWxlIHVzZXMgdG8gc2VwYXJhdGUgZGF0YSBlbnRyaWVzLg0KDQpoZWFkZXI6IFVzZSBoZWFkZXIgdG8gdGVsbCByZWFkLnRhYmxlIHdoZXRoZXIgdGhlIGZpcnN0IGxpbmUgb2YgdGhlIGZpbGUgY29udGFpbnMgdmFyaWFibGUgbmFtZXMgaW5zdGVhZCBvZiB2YWx1ZXMuDQoNCm5hLnN0cmluZ3M6IE9mdGVudGltZXMgZGF0YSBzZXRzIHdpbGwgdXNlIHNwZWNpYWwgc3ltYm9scyB0byByZXByZXNlbnQgbWlzc2luZyBpbmZvcm1hdGlvbi4gSWYgeW91IGtub3cgdGhhdCB5b3VyIGRhdGEgdXNlcyBhIGNlcnRhaW4gc3ltYm9sIHRvIHJlcHJlc2VudCBtaXNzaW5nIGVudHJpZXMsIHlvdSBjYW4gdGVsbCByZWFkLnRhYmxlIChhbmQgdGhlIHByZWNlZGluZyBmdW5jdGlvbnMpIHdoYXQgdGhlIHN5bWJvbCBpcyB3aXRoIHRoZSBuYS5zdHJpbmdzIGFyZ3VtZW50LiANCg0KU2tpcCBhbmQgbnJvdzogVXNlIHNraXAgdG8gdGVsbCBSIHRvIHNraXAgYSBzcGVjaWZpYyBudW1iZXIgb2YgbGluZXMgYmVmb3JlIGl0IHN0YXJ0cyByZWFkaW5nIGluIHZhbHVlcyBmcm9tIHRoZSBmaWxlLiBVc2UgbnJvdyB0byB0ZWxsIFIgdG8gc3RvcCByZWFkaW5nIGluIHZhbHVlcyBhZnRlciBpdCBoYXMgcmVhZCBpbiBhIGNlcnRhaW4gbnVtYmVyIG9mIGxpbmVzLg0KDQpzdHJpbmdzQXNGYWN0b3JzOiBTZXR0aW5nIHRoZSBhcmd1bWVudCBzdHJpbmdzQXNGYWN0b3JzIHRvIEZBTFNFIHdpbGwgZW5zdXJlIHRoYXQgUiBzYXZlcyBhbnkgY2hhcmFjdGVyIHN0cmluZ3MgaW4geW91ciBkYXRhIHNldCBhcyBjaGFyYWN0ZXIgc3RyaW5ncywgbm90IGZhY3RvcnMuIA0KDQpJZiB5b3Ugd2lsbCBiZSBsb2FkaW5nIG1vcmUgdGhhbiBvbmUgZGF0YSBmaWxlLCB5b3UgY2FuIGNoYW5nZSB0aGUgZGVmYXVsdCBmYWN0b3JpbmcgYmVoYXZpb3IgYXQgdGhlIGdsb2JhbCBsZXZlbCB3aXRoOiBgb3B0aW9ucyhzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpYA0KDQoNCg0KT3INCg0KWW91IGNhbiB1c2UgSW1wb3J0IERhdGFzZXQgZnJvbSB0b29sYmFyIEVudmlyb25tZW50DQotRnJvbSBUZXh0DQotRnJvbSBFeGNlbCBldGMuDQoNCg0KKipUaGUgcmVhZCBGYW1pbHk6ICoqDQoNClIgYWxzbyBjb21lcyB3aXRoIHNvbWUgcHJlcGFja2FnZWQgc2hvcnQgY3V0cyBmb3IgcmVhZC50YWJsZSwgc2hvd24gaW4gVGFibGUgRC0xLiANCg0KIVtdKFRhYmxlRC0xLlBORykNCg0KJ3JlYWQuZGVsaW0yJyBhbmQgJ3JlYWQuY3N2MicgZXhpc3QgZm9yIEV1cm9wZWFuIFIgdXNlcnMuIFRoZXNlIGZ1bmN0aW9ucyB0ZWxsIFIgdGhhdCB0aGUgZGF0YSB1c2VzIGEgY29tbWEgaW5zdGVhZCBvZiBhIHBlcmlvZCB0byBkZW5vdGUgZGVjaW1hbCBwbGFjZXMuIChJZiB5b3UncmUgd29uZGVyaW5nIGhvdyB0aGlzIHdvcmtzIHdpdGggQ1NWIGZpbGVzLCBDU1YyIGZpbGVzIHVzdWFsbHkgc2VwYXJhdGUgY2VsbHMgd2l0aCBhIHNlbWljb2xvbiwgbm90IGEgY29tbWEuKQ0KDQoNCiogcmVhZC5md2YNCg0KT25lIHR5cGUgb2YgcGxhaW4tdGV4dCBmaWxlIGRlZmllcyB0aGUgcGF0dGVybiBieSB1c2luZyBpdHMgbGF5b3V0IHRvIHNlcGFyYXRlIGRhdGEgY2VsbHMuIEVhY2ggcm93IGlzIHBsYWNlZCBpbiBpdHMgb3duIGxpbmUgKGFzIHdpdGggb3RoZXIgcGxhaW4tdGV4dCBmaWxlcyksIGFuZCB0aGVuIGVhY2ggY29sdW1uIGJlZ2lucyBhdCBhIHNwZWNpZmljIG51bWJlciBvZiBjaGFyYWN0ZXJzIGZyb20gdGhlIGxlZnRoYW5kIHNpZGUgb2YgdGhlIGRvY3VtZW50LiANCg0KWW91IGNhbiByZWFkIGZpeGVkLXdpZHRoIGZpbGVzIGludG8gUiB3aXRoIHRoZSBmdW5jdGlvbiByZWFkLmZ3Zi4gVGhlIGZ1bmN0aW9uIHRha2VzIHRoZSBzYW1lIGFyZ3VtZW50cyBhcyByZWFkLnRhYmxlIGJ1dCByZXF1aXJlcyBhbiBhZGRpdGlvbmFsIGFyZ3VtZW50LCB3aWR0aHMsIHdoaWNoIHNob3VsZCBiZSBhIHZlY3RvciBvZiBudW1iZXJzLiBFYWNoIGl0aCBlbnRyeSBvZiB0aGUgd2lkdGhzIHZlY3RvciBzaG91bGQgc3RhdGUgdGhlIHdpZHRoIChpbiBjaGFyYWN0ZXJzKSBvZiB0aGUgaXRoIGNvbHVtbiBvZiB0aGUgZGF0YSBzZXQuIGBwb2tlciA8LSByZWFkLmZ3ZigicG9rZXIuZndmIiwgd2lkdGhzID0gYygxMCwgNywgNiksIGhlYWRlciA9IFRSVUUpYA0KDQoqIEhUTUwgTGlua3MNCg0KWW91IGNhbiBwYXNzIGEgd2ViIGFkZHJlc3MgaW50byB0aGUgZmlsZSBuYW1lIGFyZ3VtZW50IGZvciBhbnkgb2YgUidzIGRhdGEtcmVhZGluZyBmdW5jdGlvbnMuIGBwb2tlciA8LSByZWFkLmNzdigiaHR0cDovLy4uLi9wb2tlci5jc3YiKWANCg0KTm90ZSB0aGF0IHdlYnNpdGVzIHRoYXQgYmVnaW4gd2l0aCAqKmh0dHBzOi8vICoqIGFyZSBzZWN1cmUgd2Vic2l0ZXMsIHdoaWNoIG1lYW5zIFIgbWF5IG5vdCBiZSBhYmxlIHRvIGFjY2VzcyB0aGUgZGF0YSBwcm92aWRlZCBhdCB0aGVzZSBsaW5rcy4gDQoNCg0KDQoNCioqIFNhdmluZyBQbGFpbi1UZXh0IEZpbGVzOiAqKg0KDQpPbmNlIHlvdXIgZGF0YSBpcyBpbiBSLCB5b3UgY2FuIHNhdmUgaXQgdG8gYW55IGZpbGUgZm9ybWF0IHRoYXQgUiBzdXBwb3J0cy4gVGhlIHRocmVlIGJhc2ljIHdyaXRlIGZ1bmN0aW9ucyBhcHBlYXIgaW4gVGFibGUgRC0yLg0KDQohW10oVGFibGVELTIuUE5HKQ0KDQpVc2Ugd3JpdGUuY3N2IHRvIHNhdmUgeW91ciBkYXRhIGFzIGEgLmNzdiBmaWxlIGFuZCB3cml0ZS50YWJsZSB0byBzYXZlIHlvdXIgZGF0YSBhcyBhIHRhYiBkZWxpbWl0ZWQgZG9jdW1lbnQgb3IgYSBkb2N1bWVudCB3aXRoIG1vcmUgZXhvdGljIHNlcGFyYXRvcnMuIGB3cml0ZS5jc3YocG9rZXIsICJkYXRhL3Bva2VyLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKWANCg0KDQoqIENvbXByZXNzaW5nIEZpbGVzDQoNClRvIGNvbXByZXNzIGEgcGxhaW4tdGV4dCBmaWxlLCBzdXJyb3VuZCB0aGUgZmlsZSBuYW1lIG9yIGZpbGUgcGF0aCB3aXRoIHRoZSBmdW5jdGlvbiBiemZpbGUsIGd6ZmlsZSwgb3IgeHpmaWxlLiBGb3IgZXhhbXBsZTogYHdyaXRlLmNzdihwb2tlciwgZmlsZSA9IGJ6ZmlsZSgiZGF0YS9wb2tlci5jc3YuYnoyIiksIHJvdy5uYW1lcyA9IEZBTFNFKWANCg0KRWFjaCBvZiB0aGVzZSBmdW5jdGlvbnMgd2lsbCBjb21wcmVzcyB0aGUgb3V0cHV0IHdpdGggYSBkaWZmZXJlbnQgdHlwZSBvZiBjb21wcmVzc2lvbiBmb3JtYXQsIHNob3duIGluIFRhYmxlIEQtMy4gDQoNCiFbXShUYWJsZUQtMy5QTkcpDQoNCg0KKiBSIEZpbGVzDQoNClIgcHJvdmlkZXMgdHdvIGZpbGUgZm9ybWF0cyBvZiBpdHMgb3duIGZvciBzdG9yaW5nIGRhdGEsIGAuUkRTYCBhbmQgYC5SRGF0YWAuIFJEUyBmaWxlcyBjYW4gc3RvcmUgYSBzaW5nbGUgUiBvYmplY3QsIGFuZCBSRGF0YSBmaWxlcyBjYW4gc3RvcmUgbXVsdGlwbGUgUiBvYmplY3RzLiANCg0KWW91IGNhbiBvcGVuIGEgUkRTIGZpbGUgd2l0aCByZWFkUkRTLiBGb3IgZXhhbXBsZSwgaWYgdGhlIHJveWFsIGZsdXNoIGRhdGEgd2FzIHNhdmVkIGFzIHBva2VyLlJEUywgeW91IGNvdWxkIG9wZW4gaXQgd2l0aDogYHBva2VyIDwtIHJlYWRSRFMoInBva2VyLlJEUyIpYA0KDQpPcGVuaW5nIFJEYXRhIGZpbGVzIGlzIGV2ZW4gZWFzaWVyLiBTaW1wbHkgcnVuIHRoZSBmdW5jdGlvbiBsb2FkIHdpdGggdGhlIGZpbGU6IGBsb2FkKCJmaWxlLlJEYXRhIilgDQoNCkJvdGggcmVhZFJEUyBhbmQgbG9hZCB0YWtlIGEgZmlsZSBwYXRoIGFzIHRoZWlyIGZpcnN0IGFyZ3VtZW50LCBqdXN0IGxpa2UgUidzIG90aGVyIHJlYWQgYW5kIHdyaXRlIGZ1bmN0aW9ucy4gSWYgeW91ciBmaWxlIGlzIGluIHlvdXIgd29ya2luZyBkaXJlY3RvcnksIHRoZSBmaWxlIHBhdGggd2lsbCBiZSB0aGUgZmlsZSBuYW1lLiANCg0KKiBTYXZpbmcgUiBGaWxlcw0KDQpGb3IgZXhhbXBsZSwgaWYgeW91IGhhdmUgdGhyZWUgUiBvYmplY3RzLCBhLCBiLCBhbmQgYywgIHlvdSBjb3VsZCBzYXZlIHRoZW0gYWxsIGluIHRoZSBzYW1lIFJEYXRhIGZpbGUgYW5kIHRoZW4gcmVsb2FkIHRoZW0gaW4gYW5vdGhlciBSIHNlc3Npb246DQoNCmBgYHtyfQ0KYSA8LSAxDQpiIDwtIDINCmMgPC0gMw0KZGF0YTwtYyhhLGIsYykNCnNhdmUoZGF0YSwgZmlsZSA9ICJzdHVmZi5SRGF0YSIpDQpsb2FkKCJzdHVmZi5SRGF0YSIpDQpgYGANCg0KDQpgYGB7cn0NCnN0dWZmPC1sb2FkKCJzdHVmZi5SRGF0YSIpDQpgYGANCg0KDQpgYGB7cn0NCnN0dWZmDQpkYXRhDQpgYGANCg0KU2F2aW5nIHlvdXIgZGF0YSBhcyBhbiBSIGZpbGUgb2ZmZXJzIHNvbWUgYWR2YW50YWdlcyBvdmVyIHNhdmluZyB5b3VyIGRhdGEgYXMgYSBwbGFpbnRleHQgZmlsZS4gUiBhdXRvbWF0aWNhbGx5IGNvbXByZXNzZXMgdGhlIGZpbGUgYW5kIHdpbGwgYWxzbyBzYXZlIGFueSBSLXJlbGF0ZWQgbWV0YWRhdGEgYXNzb2NpYXRlZCB3aXRoIHlvdXIgb2JqZWN0LiBUaGlzIGNhbiBiZSBoYW5keSBpZiB5b3VyIGRhdGEgY29udGFpbnMgZmFjdG9ycywgZGF0ZXMgYW5kIHRpbWVzLCBvciBjbGFzcyBhdHRyaWJ1dGVzLiBZb3Ugd29uJ3QgaGF2ZSB0byByZXBhcnNlIHRoaXMgaW5mb3JtYXRpb24gaW50byBSIHRoZSB3YXkgeW91IHdvdWxkIGlmIHlvdSBjb252ZXJ0ZWQgZXZlcnl0aGluZyB0byBhIHRleHQgZmlsZS4gDQoNCk9uIHRoZSBvdGhlciBoYW5kLCBSIGZpbGVzIGNhbm5vdCBiZSByZWFkIGJ5IG1hbnkgb3RoZXIgcHJvZ3JhbXMsIHdoaWNoIG1ha2VzIHRoZW0gaW5lZmZpY2llbnQgZm9yIHNoYXJpbmcuIFRoZXkgbWF5IGFsc28gY3JlYXRlIGEgcHJvYmxlbSBmb3IgbG9uZy10ZXJtIHN0b3JhZ2UgaWYgeW91IGRvbid0IHRoaW5rIHlvdSdsbCBoYXZlIGEgY29weSBvZiBSIHdoZW4geW91IHJlb3BlbiB0aGUgZmlsZXMuIA0KDQoNCioqRXhjZWwgU3ByZWFkc2hlZXRzOiAqKg0KDQpNaWNyb3NvZnQgRXhjZWwgaXMgYSBwb3B1bGFyIHNwcmVhZHNoZWV0IHByb2dyYW0gdGhhdCBoYXMgYmVjb21lIGFsbW9zdCBpbmR1c3RyeSBzdGFuZGFyZCBpbiB0aGUgYnVzaW5lc3Mgd29ybGQuIFRoZXJlIGlzIGEgZ29vZCBjaGFuY2UgdGhhdCB5b3Ugd2lsbCBuZWVkIHRvIHdvcmsgd2l0aCBhbiBFeGNlbCBzcHJlYWRzaGVldCBpbiBSIGF0IGxlYXN0IG9uY2UgaW4geW91ciBjYXJlZXIuIFlvdSBjYW4gcmVhZCBzcHJlYWRzaGVldHMgaW50byBSIGFuZCBhbHNvIHNhdmUgUiBkYXRhIGFzIGEgc3ByZWFkc2hlZXQgaW4gYSB2YXJpZXR5IG9mIHdheXMuIA0KDQoqIEV4cG9ydCBmcm9tIEV4Y2VsDQoNClRoZSBiZXN0IG1ldGhvZCBmb3IgbW92aW5nIGRhdGEgZnJvbSBFeGNlbCB0byBSIGlzIHRvIGV4cG9ydCB0aGUgc3ByZWFkc2hlZXQgZnJvbSBFeGNlbCBhcyBhIC5jc3Ygb3IgLnR4dCBmaWxlLiBOb3Qgb25seSB3aWxsIFIgYmUgYWJsZSB0byByZWFkIHRoZSB0ZXh0IGZpbGUsIHNvIHdpbGwgYW55IG90aGVyIGRhdGEgYW5hbHlzaXMgc29mdHdhcmUuIFRleHQgZmlsZXMgYXJlIHRoZSBsaW5ndWEgZnJhbmNhIG9mIGRhdGEgc3RvcmFnZS4gDQoNClRvIGV4cG9ydCBkYXRhIGZyb20gRXhjZWwsIG9wZW4gdGhlIEV4Y2VsIHNwcmVhZHNoZWV0IGFuZCB0aGVuIGdvIHRvIFNhdmUgQXMgaW4gdGhlIE1pY3Jvc29mdCBPZmZpY2UgQnV0dG9uIG1lbnUuIFRoZW4gY2hvb3NlIENTViBpbiB0aGUgU2F2ZSBhcyB0eXBlIGJveCB0aGF0IGFwcGVhcnMgYW5kIHNhdmUgdGhlIGZpbGVzLiBZb3UgY2FuIHRoZW4gcmVhZCB0aGUgZmlsZSBpbnRvIFIgd2l0aCB0aGUgcmVhZC5jc3YgZnVuY3Rpb24uIA0KDQoqIENvcHkgYW5kIFBhc3RlDQoNCllvdSBjYW4gYWxzbyBjb3B5IHBvcnRpb25zIG9mIGFuIEV4Y2VsIHNwcmVhZHNoZWV0IGFuZCBwYXN0ZSB0aGVtIGludG8gUi4gDQpUbyBkbyB0aGlzLCBvcGVuIHRoZSBzcHJlYWRzaGVldCBhbmQgc2VsZWN0IHRoZSBjZWxscyB5b3Ugd2lzaCB0byByZWFkIGludG8gUi4gVGhlbiBzZWxlY3QgRWRpdCA+IENvcHkgaW4gdGhlIG1lbnUgYmFyLW9yIHVzZSBhIGtleWJvYXJkIHNob3J0Y3V0LXRvIGNvcHkgdGhlIGNlbGxzIHRvIHlvdXIgY2xpcGJvYXJkLiBPbiBtb3N0IG9wZXJhdGluZyBzeXN0ZW1zLCB5b3UgY2FuIHJlYWQgdGhlIGRhdGEgc3RvcmVkIGluIHlvdXIgY2xpcGJvYXJkIGludG8gUiB3aXRoOiBgcmVhZC50YWJsZSgiY2xpcGJvYXJkIilgDQoNCiogWExDb25uZWN0DQoNCk1hbnkgcGFja2FnZXMgaGF2ZSBiZWVuIHdyaXR0ZW4gdG8gaGVscCB5b3UgcmVhZCBFeGNlbCBmaWxlcyBkaXJlY3RseSBpbnRvIFIuIFVuZm9ydHVuYXRlbHksIG1hbnkgb2YgdGhlc2UgcGFja2FnZXMgZG8gbm90IHdvcmsgb24gYWxsIG9wZXJhdGluZyBzeXN0ZW1zLiBPdGhlcnMgaGF2ZSBiZWVuIG1hZGUgb3V0IG9mIGRhdGUgYnkgdGhlIC54bHN4IGZpbGUgZm9ybWF0LiBPbmUgcGFja2FnZSB0aGF0IGRvZXMgd29yayBvbiBhbGwgZmlsZSBzeXN0ZW1zIChhbmQgZ2V0cyBnb29kIHJldmlld3MpIGlzIHRoZSBYTENvbm5lY3QgcGFja2FnZS4gVG8gdXNlIGl0LCB5b3UnbGwgbmVlZCB0byBpbnN0YWxsIGFuZCBsb2FkIHRoZSBwYWNrYWdlOiBgaW5zdGFsbC5wYWNrYWdlcygiWExDb25uZWN0IilgIA0KDQoNCiogUmVhZGluZyBTcHJlYWRzaGVldHMNCg0KWW91IGNhbiB1c2UgWExDb25uZWN0IHRvIHJlYWQgaW4gYW4gRXhjZWwgc3ByZWFkc2hlZXQgd2l0aCBlaXRoZXIgYSBvbmUtIG9yIGEgdHdvLXN0ZXAgcHJvY2Vzcy4gDQoNCmB3YiA8LSBsb2FkV29ya2Jvb2soImZpbGUueGxzeCIpYA0KDQpgc2hlZXQxIDwtIHJlYWRXb3Jrc2hlZXQod2IsIHNoZWV0ID0gMSwgc3RhcnRSb3cgPSAwLCBzdGFydENvbCA9IDAsICBlbmRSb3cgPSAxMDAsIGVuZENvbCA9IDMpYA0KDQoNCllvdSBjYW4gY29tYmluZSB0aGVzZSB0d28gc3RlcHMgd2l0aCByZWFkV29ya3NoZWV0RnJvbUZpbGUuIEl0IHRha2VzIHRoZSBmaWxlIGFyZ3VtZW50IGZyb20gbG9hZFdvcmtib29rIGFuZCBjb21iaW5lcyBpdCB3aXRoIHRoZSBhcmd1bWVudHMgZnJvbSByZWFkV29ya3NoZWV0LiBZb3UgY2FuIHVzZSBpdCB0byByZWFkIG9uZSBvciBtb3JlIHNoZWV0cyBzdHJhaWdodCBmcm9tIGFuIEV4Y2VsIGZpbGU6DQoNCmBzaGVldDEgPC0gcmVhZFdvcmtzaGVldEZyb21GaWxlKCJmaWxlLnhsc3giLCBzaGVldCA9IDEsIHN0YXJ0Um93ID0gMCwgIHN0YXJ0Q29sID0gMCwgZW5kUm93ID0gMTAwLCBlbmRDb2wgPSAzKWANCg0KKiBXcml0aW5nIFNwcmVhZHNoZWV0cw0KDQpXcml0aW5nIHRvIGFuIEV4Y2VsIHNwcmVhZHNoZWV0IGlzIGEgZm91ci1zdGVwIHByb2Nlc3M6DQoNCjEuIGBiIDwtIGxvYWRXb3JrYm9vaygiZmlsZS54bHN4IiwgY3JlYXRlID0gVFJVRSlgIA0KMi4gYGNyZWF0ZVNoZWV0KHdiLCAiU2hlZXQgMSIpYA0KMy4gYHdyaXRlV29ya3NoZWV0KHdiLCBkYXRhID0gcG9rZXIsIHNoZWV0ID0gIlNoZWV0IDEiKWANCjQuIGB3cml0ZVdvcmtzaGVldFRvRmlsZSgiZmlsZS54bHN4IiwgZGF0YSA9IHBva2VyLCBzaGVldCA9ICJTaGVldCAxIiwgIHN0YXJ0Um93ID0gMSwgc3RhcnRDb2wgPSAxKWAgDQoNCg0KKipMb2FkaW5nIEZpbGVzIGZyb20gT3RoZXIgUHJvZ3JhbXM6ICoqDQoNCllvdSBzaG91bGQgZm9sbG93IHRoZSBzYW1lIGFkdmljZSBJIGdhdmUgeW91IGZvciBFeGNlbCBmaWxlcyB3aGVuZXZlciB5b3Ugd2lzaCB0byB3b3JrIHdpdGggZmlsZSBmb3JtYXRzIG5hdGl2ZSB0byBvdGhlciBwcm9ncmFtczogb3BlbiB0aGUgZmlsZSBpbiB0aGUgb3JpZ2luYWwgcHJvZ3JhbSBhbmQgZXhwb3J0IHRoZSBkYXRhIGFzIGEgcGxhaW4tdGV4dCBmaWxlLCB1c3VhbGx5IGEgQ1NWLiBUaGlzIHdpbGwgZW5zdXJlIHRoZSBtb3N0IGZhaXRoZnVsIHRyYW5zY3JpcHRpb24gb2YgdGhlIGRhdGEgaW4gdGhlIGZpbGUsIGFuZCBpdCB3aWxsIHVzdWFsbHkgZ2l2ZSB5b3UgdGhlIG1vc3Qgb3B0aW9ucyBmb3IgY3VzdG9taXppbmcgaG93IHRoZSBkYXRhIGlzIHRyYW5zY3JpYmVkLiANCg0KU29tZXRpbWVzLCBob3dldmVyLCB5b3UgbWF5IGFjcXVpcmUgYSBmaWxlIGJ1dCBub3QgdGhlIHByb2dyYW0gaXQgY2FtZSBmcm9tLiBBcyBhIHJlc3VsdCwgeW91IHdvbid0IGJlIGFibGUgdG8gb3BlbiB0aGUgZmlsZSBpbiBpdHMgbmF0aXZlIHByb2dyYW0gYW5kIGV4cG9ydCBpdCBhcyBhIHRleHQgZmlsZS4gSW4gdGhpcyBjYXNlLCB5b3UgY2FuIHVzZSBvbmUgb2YgdGhlIGZ1bmN0aW9ucyBpbiBUYWJsZSBELTQgdG8gb3BlbiB0aGUgZmlsZS4gDQoNCiogQ29ubmVjdGluZyB0byBEYXRhYmFzZXMNCg0KV29ya2luZyB3aXRoIGEgZGF0YWJhc2Ugd2lsbCByZXF1aXJlIGV4cGVyaWVuY2UgdGhhdCBnb2VzIGJleW9uZCB0aGUgc2tpbGwgc2V0IG9mIGEgdHlwaWNhbCBSIHVzZXIuIA0KSG93ZXZlciwgaWYgeW91IGFyZSBpbnRlcmVzdGVkIGluIGRvaW5nIHRoaXMsIHRoZSBiZXN0IHBsYWNlIHRvIHN0YXJ0IGlzIGJ5IGRvd25sb2FkaW5nIHRoZXNlIFIgcGFja2FnZXMgYW5kIHJlYWRpbmcgdGhlaXIgZG9jdW1lbnRhdGlvbi4gVXNlIHRoZSBEQkkgcGFja2FnZSB0byBjb25uZWN0IHRvIGRhdGFiYXNlcyB0aHJvdWdoIGluZGl2aWR1YWwgZHJpdmVycy4gDQoNCkZvciBNeVNRTCB1c2UgUk15U1FMLCBmb3IgU1FMaXRlIHVzZSBSU1FMaXRlLCBmb3IgT3JhY2xlIHVzZSBST3JhY2xlLCBmb3IgUG9zdGdyZVNRTCB1c2UgUlBvc3RncmVTUUwsIGFuZCBmb3IgZGF0YWJhc2VzIHRoYXQgdXNlIGRyaXZlcnMgYmFzZWQgb24gdGhlIEphdmEgRGF0YWJhc2UgQ29ubmVjdGl2aXR5IChKREJDKSBBUEkgdXNlIFJKREJDLiBPbmNlIHlvdSBoYXZlIGxvYWRlZCB0aGUgYXBwcm9wcmlhdGUgZHJpdmVyIHBhY2thZ2UsIHlvdSBjYW4gdXNlIHRoZSBjb21tYW5kcyBwcm92aWRlZCBieSBEQkkgdG8gYWNjZXNzIHlvdXIgZGF0YWJhc2UuDQoNCg0KDQoNCiMjRS4gRGVidWdnaW5nIFIgQ29kZS1YDQoNCiNDaGFuZ2UgbG9nIHVwZGF0ZQ0KDQoqIDE5LjAxLjIwMTkNCiogMTMuMDQuMjAxOQ0KKiAxNC4wNC4yMDE5DQoqIDE1LjA0LjIwMTkNCiogMTYuMDQuMjAxOQ0KKiAxNy4wNC4yMDE5DQoNCg0KDQo8QnI+DQoNCiNQcmVmZXJlbmNlcw0KDQoqIFtIYW5kcy1PbiBQcm9ncmFtbWluZyB3aXRoIFJdKGh0dHBzOi8vcnN0dWRpby1lZHVjYXRpb24uZ2l0aHViLmlvL2hvcHIvKQ0KDQoNCiNMaWNlbnNlDQoNCltNSVRdKGh0dHBzOi8vb3BlbnNvdXJjZS5vcmcvbGljZW5zZXMvTUlUKQ0K