Welcome to your first R workshop! 😁🥳

The aim of todays session is to give you an introduction to R, talk you through some of its uses, and how it might be useful to you as bioinformaticians.

The learning objectives for todays session are as follows:

We’ve got lots to cover, but no introduction can ever give you everything you need to know. The general idea here is to give you some level of familiarity with R, to remove the barrier to entry. Hopefully, you’ll be able to go away from these sessions with some confidence to practice, play, and gain some experience using everybodies (well, my) favourite coding language! We’ll have a quick introduction before we get into the coding proper, so bare with that and then we can play with some code! Right, let’s get cracking.

An introduction to R:

R is the coding language that I primarily use, and have used throughout my career thus far. I have dabbled in both Python and unix, but R is my favourite, and the one I return to most frequently. I never had a formal introduction to R, such as the one you guys are getting now - I taught myself out of necessity, as you can imagine, this took quite some time. Over the last decade, however, R has become increasingly wide spread and accessible - there are more courses than you can shake a stick at online.

Before we start proper, I also think it’s important to know that even people who have been using R for years still make mistakes. There’s a fair amount that I can do in R off of the top of my head (for example, I am currently making this document in RStudio!), but I regularly still have to google things. It’s really easy to feel a bit overwhelmed and unsure where to start with any coding language, but remember that nobody is expecting you to suddenly become fluent or memorise everything (as another example, I’ve just had to google how to code sub-bullet points to the above list!). We just want you to get some familiarity and experience.

Now then, I’ve said all of this, but haven’t answered one key question - what is R?!

R is a freely available programming language, developed in the early 1990s, made open source in 1995. R was developed on top of another language, S. S was a propriatory language, which ultimately, R became the open source version of.

R’s ethos was to develop something specifically for statistical computation and visualisataion - it was developed by researchers, for researchers.

So, in 2023, when you may have already begun to learn, for example, Python, why bother with R?

  • The statistics and data-vis packages in Python are very recent, they did not exist 10 years ago!
  • The “default” language varies from field to field, but certainly in ecology and evolution, you’re likely to be working with colleagues who use R (interestingly, ecologists were actually one of the first user bases of R)
  • R is designed to be an efficient, interpreted language in a way that is fundementally different to the initial design of Python, which is typically interacted with via a script. R is designed to be a sort of “statistical conversation” where you interactively program.
  • R was designed to have efficient data handling and storage mechanisms. There aer lots of types of data structures in R - these might seem unnecessary at first, but as we delve deeper into R and how it works, you’ll see why they’re important. R is written in a way that makes accessing reasonably sized datasets super efficient. Typically, this is not true of Python for a plethora of reasons that we don’t have the time to talk about (although admittedly this is getting better with the advent of modules such as Pandas)
  • R contains a large collection of tools specifically developed for data analysis, as well as some really good built in data visualisation features!
  • There is a huge multiverse that has been built around R with loads of different flavours associated with it. We’ll discuss this in more detail next week.
  • Finally, R is fundementally designed to be simple. This is why it’s taught to non-programmers. You don’t have to do complicated things like for loops if you don’t want to (although we’re going to!). These can be avoided and R can be used for it’s base functionality of data analysis and plotting with no fancy extras if you don’t want them.

More specifically:

  • R is a major part of the bioinformatic and biostatistics toolkits, and it isn’t going away any time soon.
  • It was explicitly designed to handle data, particularly in a format known as data.frames - this is extremely important to the way that R functions
  • It is free, and widely supported. In Evolution and Ecology papers in the last decade, 66% mention R. If you want to have a career in research, R is a vital skill.
  • R is used by loads of major tech companies for their analytics - including facebook, google, and twitter!

So, how do we interact with R?

How do we use R to have those statistical conversations that I referenced earlier? There are 2 main ways. The first way is to use R directly through an interface known as “base R” or “native R”. This is using R in it’s purest form, and is actually quite tricky. If we load base R, we see a window like this:

This console window contains a load of gobbledegook abut version numbers etc., which will vary between individual machines and R installs. The OS that you’re running will also dramatically impact how your R window looks - this is the MacOS R version. Essentially, R is waiting for you to enter commands and tell it what to do next. As you can see, it’s not overly user friendly. That being said, the MacOS version is much nicer. The Windows version is clunky, and even less friendly. MacOS R has features not available on Windows too, which means using R across multiple machines can be a bit of pain.

Here, we will use an R IDE, known as RStudio (although you might also hear it referred to as posit). An IDE, or an interactive developer environment, is a built-on interface that helps you to run a programming language more easily and effectively. Other examples of IDEs can be found in Python - you might have come across Spyder or Jupyter for example. RStudio is completely free, and the best R IDE I’ve found. It’s also the most well supported, which is useful. There are others, but RStudio is particularly good. It will help to make your R journey much smoother, and actually helps you to spot errors in your code, which is always a bonus!

It looks a bit like this:

You’ll notice that my version of RStudio is differently coloured to yours - this is just due to personal preference. I spend lots of time staring at my R window rather intently, so having it darker really helps!!!

RStudio standardises the R interface across all platforms - it looks the same whatever OS you might be running. It also has a lot of powerful features that makes running R more straightforward, we’ll talk about these in more detail in the coming sessions. It also has great project management tools, which are endlessly useful when you’re working on multiple projects all at the same time!

Now, let’s talk through what all the bits are about.

As you can see above, the RStudio interface is made up of various parts. The first of which is the console. This, like native R, is waiting for your input in the “statistical conversations” that you’ll be having with R. It gives you a bit of an odd blurb about versioning etc. Each of the versions has a slightly odd name, I’m not sure why. Some of them are named after various albums but that’s as far as I’ve got with figuring out the naming system!

Anyway, theres loads of other stuff over on the right hand side, most of which is not imortant or useful to you right now. The “Environment” section keeps track of what you’ve got loaded in terms of datasets and variables etc., which can prove incredibly useful. Underneath, you can find file trees, plots that you have created, help files, and loads of other stuff that we can talk more about later on.

Project Management in R

Starting with project management tools feels a bit bizarre, but as someone who used R for many many years without this functionality, trust me, it’s easiest to get to grips with it early doors. Something that people struggle with, and something you might have come across with other coding languages, is where files are stored on a computer. RStudio has a great feature that will make this much easier to deal with. So, to demonstrate what I mean, type the following code into your console window, and press enter.

getwd()

This is the get working directory command, and is similar to commands in unix and python - in unix, you’d use pwd(). This command prints the working directory. (A quick note on functions in R which we will come back to - anything followed by () is a function i.e. something that takes an input and does something with it) If you run the getwd() command, you will get an output with a filepath, this is your current working directory, or, where R is looking for files! You can use R by putting stuff places and then using loads of really long and difficult path names to navigate through your computers file system and then sticking to the same directory. This quickly becomes a nightmare if you’re working on multiple projects at once though, because you end up trying to read files from and write files to the wrong directories, which you have to keep changing!

A better idea is to set up R using projects. These contain everything you need which is associated with a single bit of analysis or a single project (see what I did?) that you’re using R to work on. We will create a project for this session, which will create a self-contained directory, which R will always open when looking for files associated with what we’re doing, so you don’t have to try and navigate through complicated file structures within R itself. This is relatively straight forward, and we’ll do it now.

Up in the right hand corner of your RStudio window, there should be a bit of text that reads project or similar. Click on this, and you’ll get a drop down menu appear. From this menu, select “new project”, which will give you some more options. Chose “new directory” and call it something sensible, like “LIFE4138-R”.

Note: Don’t ever use spaces in file or directory names. It’s a really easy way to make sure that R will kick off at you! Use an underscore instead!

Finally, click “create project” and R will do the rest for you. Now, if you try the getwd() function again, it should print of the location of the new directory! It will also have changed the information displayed in the “files” section, having created a new folder wherever you asked it to. The easiest way to access files now is to pop them directly into this folder. You could now send someone this .Rproj file, and they’d have all the stuff they needed to recreate your work!

Anyway, that was an odd place to start, but it is important to get this part right.

Interacting with the R environment

When we interact with R, generally we are typing in the console. You can also write scripts (if you don’t have a script already open, you can open a new one by clicking the new script option from the menu at the top left of the screen - the white rectangle with a green + in the top corner!). A script is effectively a record of what you have done using R, allowing you to keep track. When you’ve written commands in a script, you can run them with your cursor on the line of code you wish to run, and pressing ctrl+enter (cmd+enter on MacOS). You may have come across scripts in python and unix, but generally we run them a little differently in R. We tend to run scripts interactively, either a single line or a few lines at a time, assess an output, and then run some more.

Let’s get started using R!

R as a calculator

First things first, R can be used as a basic calculator. Try typing the following commands into your script window and running them with ctrl/cmd+enter.

4
4 + 3
50 - 5
50 * 2000
9 / 3
10 ^ 2

You can see by doing this that R is able to perform basic mathematical functions. You’ll have noticed when you gave it a single number input, it echoed this number back to you. Play around with this, and see what R is capable of! Whilst you’re unlikely to often use R explicitly as a calculator, it is important to understand that it can handle numerics.

Note: the “>” prompt in the console is waiting for you to ask it something - try running the examples directly in the console as well as in script form!

R and text input

R can also interpret text! You can give it a character string, and it will print it back to you - try running the following:

"Hello world!"
'Hello world!'
Hello world

Note that the last example of this does not work, because R is looking for an object called Hello world which it cannot find. Without the quotation marks (either type is fine, but be consistent), it does not recognise the text as a string.

You’ll have got a funky error in the last example, something about an unepexted symbol - it likely wont have made much sense to you. This is fairly typical of R error messages unfortunately, they are famed for being tricky to interpret. They take some getting used to, but eventually you will be able to translate these bizarre messages into something that actually makes sense. For example, here, the “unexpected symbol” is referring to the space between the words “Hello” and “world”. Without the quotation marks, R expects these things to be functions or objects rather than a character string, and cannot process the space.

R as a logical interpreter

R can tell you whether a statement is true or false. This seems basic, but it will build up to create a useful tool alongside the other parts of it’s functionality that we’re discussing. The logical interpreter within R is a key part of how R functions as a peice of software, and is commonly in-built into many sophisticated functions and analyses. R will tell you if something is logical, or if it makes sense, by returning either TRUE or FALSE to an input. This is possible with numerical input and character strings - try the following for example:

2 == 2
5 > 10
9 <= 10
"Mario" == "Mario"
"Mario" == "Luigi"

Note: you’ll notice that when we are asking R if things are equivelant to one another, we use a double == sign. This is because a single = sign is used in R to asign something to a variable name. I’ll explain more about that in a minute!

Right, time to start building up to using R practically.

Assigning objects

So, it’s useful to know how to make a variable in your R environment. You may already know this from your adventures with Python. In Python, you use an = to assign a variable. Whilst you can do this in R, it’s best practice to use the <- operator instead. Note this creates an object in R, not a variable. This is because of the statistical nature of R - in statistics, a variable means something entirely different. I use <- because it is how I was taught to use R, but it’s okay to use = if you’d prefer. It does get complicated because of the == function, so I like to use <- instead. Some programmers get a bit picky and judgy if you use a different way to them, but my philosophy with R is if it works, it works.

So, why asign? It saves time and makes your scripting easier! There are some rules, however. Assignment is case sensitive, so don’t type something with loads of varying cases. Your object name also can’t start with a number, and some words that are associated with common functions like if or else are not allowed and will bring up an error message. Try the following and take note of the error messages you see:

my_number <- 150302

my_number2 = 204211

my_text <- “Hello world”

1my_text <- "Hello world"

for <- "Hello world"

Also, it is important to make sure you don’t name an object the same as a variable in your data structure, or you’ll run into some trouble!!

A note on scripting:

Scripts are essentially a record of what you’ve done - like a live document you can edit and add to as you go. When I script, it’s almost literally a stream of consciousness, which includes bits of code that don’t work so I don’t make the same error again. You should leave comments to remind yourself of what you’re doing, because even if you think you’ll remember, I promise if you come back to it in six months, you’ll be lost! You denote a comment by starting a line with a #. R will ignore these lines (they will be greyed out in RStudio), so add as many as you like!

When you’re thinking about not using comments, remember the Voyrich manuscript. It was written in gibberish, and nobody knows what it means because there is no way of translating it, and no way to work out what the author was thinking. I go super over-board with comments to myself, particularly when I’m sharing scripts with others.

Data structures

Right, lets get to the real meat. Data structures. There are 4 main data structures that we’ll cover here (well, 3.5 because we’ll cover lists properly another time) - Vectors, Matricies, and Dataframes.

Vetors

We’ll start with vectors. We’ve already considered all three main classes of data above, numeric, character, and logical. We use these and others to build up our data structures in R.

A vector is just a 1-dimensional series of values - the length of the vector is its only dimension. This is the most basic data structure you’ll find in R, and the fundementals of accessing its contents are different to Python. So, we’ll start by creating a series of vectors, starting with a numeric vector: Note: c() is a useful function here, it’s short for concat or combine, we’ll talk more about functions later!

x <- c(1, 2, 3, 4, 5)

y <- 1:5

z <- seq(from = 1, to = 5, by = 1) 

All of these examples will give you a number vector that ranges from 1-5. The first combines all listed numbers, the second creates a series of numbers from 1:5 (the : essentially means from 1 to 5), and the third creates a sequence from 1 to 5, going up in 1s.

We can also create character vectors. Later, we will discuss how you access an individual component of each of these vectors, but for now, let’s build some character vectors (using my favourite nintendo examples!). Note that you can only create a character vector with the c() function. Without this, R is only expecting a single value in your assignment and will throw an error up. Let’s try:

a <- c(“Mario”, “Luigi”, “Peach”)

b <- c(“Link”, “Zelda”, “Gannon”

We can also create a vector of logical values. Remember that TRUE and FALSE have to be in caps for R to interpret them as logicals. Here, we’ll create a logical vector using logcal values, and then one from character vectors with ==:

e <- c(TRUE, FALSE, TRUE)

f <- a == b

Vector properties

It’s time to have a look at the properties of a vector - later we’ll move on to sticking vectors together to make new data structures, but for now, we’ll have a look at vectors as stand alone objects. We can do mathematical operations on entire numeric vectors - we can apply a single operation to all values in a vector, or we can perform operations on two different vectors:

x <- 1:10
x + 5
x – 5

y <- 11:20
x + y
x * y

Vector operations such as those above are a very important and powerful tool in R for rapid calculations across large sets of numbers.

Data structures in R have properties - the main property of a vector is its length. Once you know something about the length of a vector, you can more easily access the stuff inside of it. You find the length of a vector using length(x).

You will get warnings to do with the length of a vector in various circumstances, for e.g. if two vector lengths are not multiples of one another in some mathematical calculations. Try the following:

x <- 1:10
length(x)

y <- 1:5
x + y
x * y

z <- 1:3
y * z 

Here, you’ll notice that the operation causes the shorter vector (z) to be looped across until it fits the longer. So, your result from y * z is actually:

  • 1 * 1,
  • 2 * 2,
  • 3 * 3,
  • 4 * 1, and
  • 5 * 2

R will still perform these operations, but it will warn you that vector lengths are not multiples of one another.

So, how do we interact with vectors and start to pull items from them? Vectors are great, but they’re not overly useful unless we can get at the stuff inside of them. We’ll create another character vector, x.

x <- c("dog", "cat", "mouse")
x[] # This will print all vector values
x[1] # This will print the first value - note that R is indexed from 1 unlike Python!!
x[c(1, 3)] # This gives you the first and third values - note the use of c()
x[2:3] # this gives you values 2 through to 3.

So, now we can pull out whatever values we want, we can use this to manipulate the contents of our vector! If we wanted to, for example, replace the mouse with an elephant, we’d use the following:

x[3] # This prints "mouse"
x[3] <- "elephant" # This assigns the string "elephant" to the third index of the vector, replacing "mouse".
x

Now, what if we want to remove number 3 all together? We can do this by assignin it an NA value, which indicates to R that there is no value present at this location:

x[3] <- NA

A note on NA:

NA is a placeholder in R, for when data is “Not Available”, and it usually denotes missing data. For example, you might be collecting blood samples from patients in a longitudinal trial, and a patient is unable to provide a sample at point 3 of 5, so here, your value for whatever you’re measuring in the blood would be NA. Other commonly encountered missing value placeholders in R are NaN (Not A Number) and Inf (Infinity).

Functions

We’ll take a brief interlude from data structures for a brief word about functions now. Functions are the bread and butter of R. They are code that takes an input, processes it, and returns a result in the form of an output. We have already used some functions above, such as length() and seq(). There are thousands of functions available to you in R, from the very basic to the extremely complicated and involved. You can (and you will!) write your own functions, much like you can in Python, although the syntax is different. Pre-built functions often come with help files, try the following:

y <- 1:10
length(y)
?length

Use ?function or help("function") to access help. The help files generally contain a description of the function and details of all the arguments which may be supplied to it. These help files do take some getting used to, as true to R’s style, they can be quite tricky to interpret!

The anatomy of a function

Try running the following code:

y <- 1:10
sum(y)
y[5] <- NA # Replace the 5th index with NA
sum(y)

You’ll notice that if a vector contains NA, functions such as sum() will return NA. Something hasn’t quite worked here, so we need to add an additional argument to our function to deal with those pesky NAs…

sum(y, na.rm = TRUE)

Here, the na.rm argument is set to TRUE, so that NA is ignored (or, more accurately, removed). Note that the assignment of things inside of a function is always done with = and not <-.

Plotting and visualisation

Now is a good time to start thinking about what we can actually get out of what we’ve learned so far, so we’ll use Rs integrated plotting software to create some nice plots! You can have a look at what R has to offer using the now slightly outdated demo(graphics) command. Try taking a tour through the graph types.

Let’s use the skills we’ve learned so far to make a plot!

x <- 1:100
y <- x^2
plot(x, y)

Nice! You should have produced a scatter plot. What if we want to turn that into a line plot?

plot(x, y, type = "l")

Fabulous. The ways to customise graphics in R are almost endless - we’ll have a closer look later on! For now though, we’ll get back to our data structures.

Returning to data structures

Matricies

The second type of data structure we’ll look at is the humble matrix. These data structures store data in rows and columns (i.e. like a table!). They are very similar to vectors, only they are two-dimensional. In fact, we can build our first matrix from some vectors using the cbind() and rbind() functions:

x <- 1:4
y <- 21:24
z <- cbind(x, y)
z

cbind() binds vectors togther by column, whereas rbind() does it by row, effectively flipping our table. Try running z1 <- rbind(x, y) and looking at the output.

There is a simple way to determine whether your data structure is a matrix, which is by running the is.matrix(z) command. Try it! It should give a logical output of TRUE or FALSE. You can also access the dimensions of a matrix in a similar way to a vector (although slightly different). dim(z) tells you the dimensions overall, nrow() tells you the number of rows, and unsurprisingly, ncol() gives you information about the number of columns in the matrix. Try it with our matrix z.

An important consideration with matricies is that we refer to them by the row index, and then the column. This is something that is very easy to forget, and I often have to look it up, so don’t worry if you can’t remember. Matricies are also only capable of storing 1 type of data, either logical, character, or numeric. If your data is mixed in type, you’ll need a dataframe rather than a matrix, but we’ll get to that soon. Let’s see what happens if we try and store multiple data types:

x <- c(“Mario”, “Luigi”, “Peach”)
y <- c(“Toad”, “Bowser”, “Wario”)
z <- c(1, 2, 3)
m <- cbind(x, y, z)

Here you can see that the numbers in z are transformed into characters!

Anyway, how do we extract and access information stored in a matrix?! Like with vectors, we use square brackets. Let’s make a bigger matrix and have a go. Note that we are using the matrix() function here rather than cind().

m <- matrix(1:10, ncol = 2) # ncol = 2 tells R that we want the numbers 1-10 split into 2 columns
m[1, ] # return first row
m[, 2] # return second column
m[1,2] # return the information in the first row of the second column, in this example, 6.

Data frames

Right, on to our third (and probably final) data structure - data frames. Most “real” data that you come across in your travels will be in a dataframe. It’s a bit like a matrix, but capable of storing multuple data classes in the same object. Let’s make one from 3 vectors and have a look:

name <- c(“Mario”, “Luigi”, “Link”, “Zelda”)
height <- c(155, 160, 180.3, 180.3)
age <- c(26, 24, 17, 19)

df <- data.frame(name, height, age)

Note that the dataframe must have named columns! You can look at the first few rows of your data with head(df), and take note of the structure of it with str(df). Now, everything you’ve just learned about accessing data inside of a matrix stands true for dataframes also - they work in a very similar fashion with the rows and columns format. There is, however, another way to access data from your dataframe that I find more intuitive than using column indicies, which is referring to the column by its name (hence the need for named columns!). Try this:

# Accessing data as if it were a matrix
df[, 1]
df[3, ]
df[4, 3]

# Using column names as references

df[“name”]
df[, “name”]
df$name

When you extract a column in this way, it becomes a vector! Note that in df$name, the $ essentially just means “look inside” - so you’re telling R to look inside df to find the names column.

Accessing example data

Using the toy datasets as we just have is all well and good when you’re learning, and is a fun way to experiment and figure out how things work! But, what if we want to get hold of some actual data? There are loads of pre-loaded real life datasets that come with R, so let’s have a look at arguably the most famous of these, the iris dataset.

If we type data() into our R console/script and run it, R will load these datasets for us. We can then use the head() function to look at the iris dataset…

data()

head(iris)

?iris

Note that we can get more information about the dataset by running the help ? function. We will revisit these dataset in a minute, but first, what if you want to import your own data?!

The easy way: you can use RStudio to import data via the GUI, which is a good way to learn at first, but isn’t as flexible as learning functions to read data…

The (arguably) better way is to use the read.csv() function. I will use it here to upload a .csv file I have in my project directory which contains data from Netflix titles over the years. Try with your own data!

netflix <- read.csv("./netflix_titles.csv")
head(netflix)

You may also need to write data out of R, which can be good for saving your progress or saving filtered datasets. Here, we will write out a file of comma-separated variables (a .csv file).

df <- data.frame(name = c(“Mario”, “Luigi”, “Link”, “Zelda”),
            height = c(155, 160, 180.3, 180.3),
            age = c(26, 24, 17, 19))

write.csv(df, “./nintendo.csv”) 

Note: this is the nintendo dataframe we made earlier, so you may not need to remake it!

Extending beyond base R:

Packages, which are analagous to modules in Python, are a great way of extending your R universe. They can be installed in a multitude of ways, but perhaps the most common is installing them directly through the Comprehensive R Network - CRAN. There are currently over 18500 packages listed on CRAN, so it’s likely that if you’re trying to do something specific in R, there is already a package! Other repositories include GitHub and BioConductor.

Installing and loading R packages:

Installnig packages is usually straight forward… You also only need to do it once on each computer you use! We will install ggplot2 now, a package we will use lots in other sessions. Once installed, you must load your package into R with the library() function.

install.packages("ggplot2")
library(ggplot2)

Back to plots!

Visualising data is a fundementally important tool in R - think of it as a way to understand and properly explore your data. We wont use ggplot2 for this for now, although this is a fabulous plotting tool. We can use R to make a simple scatter plot, as we did before:

x <- seq(from = 1, to = 100, by = 5)
y <- x^2

plot(x, y)

We can customise almost anything on this plot, and we add to it iteratively as we go. You’ll see what I mean in the following examples. First, we’ll change the orientation of the y axis labels with the las = 1 argument in the plot() function:

plot(x, y, las = 1)

We can change the colour of the points, and then add a line:

plot(x, y, las = 1, col = “red”)
lines(x,y)

We can add a title:

plot(x, y, las = 1, col = “red”,
     main = “relationship between x & y”)
lines(x,y)

The possibilities are endless!

Right, lets make a basic histogram and a box and whisker, then we’ll call it a day.

Plotting the distribution of data with a histogram can be useful to identify outliers or have a look at the shape of your data. We can plot the normal distribution as an example - the following code will generate a series of numbers that follow a normal distribution and then plot it:

x <- rnorm(n = 1000, mean = 25.5, sd = 3)

hist(x)

Boxplots are useful to have a look at potential differences between groups of data - let’s plot the iris data and see how petal width might differ among species:

head(iris)

boxplot(iris$Petal.Width ~ iris$Species,
      las = 1, ylab = “Petal width”,
      xlab = “Species”)

A quick note about tilde (~)

In R, a tilde denotes the relatinship between two variables, and is commonly used in statistical functions. It’s slightly confusing, as it appears to be the wrong way around - you code the dependent variable and then the independent. So, Petal width ~ Species means how does petal width vary among species?!

Top tips for learning R:

LS0tCnRpdGxlOiAiTElGRSA0MTM4OiBSIFdvcmtzaG9wIDEgLSBIYW5uYWggSmFja3NvbiIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKCgpXZWxjb21lIHRvIHlvdXIgZmlyc3QgUiB3b3Jrc2hvcCEg8J+YgfCfpbMKClRoZSBhaW0gb2YgdG9kYXlzIHNlc3Npb24gaXMgdG8gZ2l2ZSB5b3UgYW4gaW50cm9kdWN0aW9uIHRvIFIsIHRhbGsgeW91IHRocm91Z2ggc29tZSBvZiBpdHMgdXNlcywgYW5kIGhvdyBpdCBtaWdodCBiZSB1c2VmdWwgdG8geW91IGFzIGJpb2luZm9ybWF0aWNpYW5zLgoKVGhlIGxlYXJuaW5nIG9iamVjdGl2ZXMgZm9yIHRvZGF5cyBzZXNzaW9uIGFyZSBhcyBmb2xsb3dzOgoKKiBUbyBsZWFybiB3aGF0IFIgaXMsIGFuZCBob3cgd2UgaW50ZXJhY3Qgd2l0aCBpdAogICsgRm9jdXMgb24gUlN0dWRpbyBhcyBhbiBpbnRlcmZhY2UgYW5kIHByb2plY3QgbWFuYWdlbWVudCBzeXN0ZW0KKiBUbyB1bmRlcnN0YW5kIGRhdGEgc3RydWN0dXJlcyBhbmQgYmFzaWMgZnVuY3Rpb25zIGluIFIKKiBUbyBiZWdpbiB0byB1c2UgUidzIHBsb3R0aW5nIGFuZCB2aXN1YWxpc2F0aW9uIHRvb2xzCiogVG8gcHJhY3RpY2UgcmVhZGluZyBpbiBkYXRhc2V0cwoqIFRvIGxlYXJuIGhvdyB0byBpbnN0YWxsIGFuZCBsb2FkIHBhY2thZ2VzCgpXZSd2ZSBnb3QgbG90cyB0byBjb3ZlciwgYnV0IG5vIGludHJvZHVjdGlvbiBjYW4gZXZlciBnaXZlIHlvdSBldmVyeXRoaW5nIHlvdSBuZWVkIHRvIGtub3cuIFRoZSBnZW5lcmFsIGlkZWEgaGVyZSBpcyB0byBnaXZlIHlvdSBzb21lIGxldmVsIG9mIGZhbWlsaWFyaXR5IHdpdGggUiwgdG8gcmVtb3ZlIHRoZSBiYXJyaWVyIHRvIGVudHJ5LiBIb3BlZnVsbHksIHlvdSdsbCBiZSBhYmxlIHRvIGdvIGF3YXkgZnJvbSB0aGVzZSBzZXNzaW9ucyB3aXRoIHNvbWUgY29uZmlkZW5jZSB0byBwcmFjdGljZSwgcGxheSwgYW5kIGdhaW4gc29tZSBleHBlcmllbmNlIHVzaW5nIGV2ZXJ5Ym9kaWVzICh3ZWxsLCBteSkgZmF2b3VyaXRlIGNvZGluZyBsYW5ndWFnZSEgIFdlJ2xsIGhhdmUgYSBxdWljayBpbnRyb2R1Y3Rpb24gYmVmb3JlIHdlIGdldCBpbnRvIHRoZSBjb2RpbmcgcHJvcGVyLCBzbyBiYXJlIHdpdGggdGhhdCBhbmQgdGhlbiB3ZSBjYW4gcGxheSB3aXRoIHNvbWUgY29kZSEgUmlnaHQsIGxldCdzIGdldCBjcmFja2luZy4KCiMgQW4gaW50cm9kdWN0aW9uIHRvIFI6CgpSIGlzIHRoZSBjb2RpbmcgbGFuZ3VhZ2UgdGhhdCBJIHByaW1hcmlseSB1c2UsIGFuZCBoYXZlIHVzZWQgdGhyb3VnaG91dCBteSBjYXJlZXIgdGh1cyBmYXIuIEkgaGF2ZSBkYWJibGVkIGluIGJvdGggUHl0aG9uIGFuZCB1bml4LCBidXQgUiBpcyBteSBmYXZvdXJpdGUsIGFuZCB0aGUgb25lIEkgcmV0dXJuIHRvIG1vc3QgZnJlcXVlbnRseS4gSSBuZXZlciBoYWQgYSBmb3JtYWwgaW50cm9kdWN0aW9uIHRvIFIsIHN1Y2ggYXMgdGhlIG9uZSB5b3UgZ3V5cyBhcmUgZ2V0dGluZyBub3cgLSBJIHRhdWdodCBteXNlbGYgb3V0IG9mIG5lY2Vzc2l0eSwgYXMgeW91IGNhbiBpbWFnaW5lLCB0aGlzIHRvb2sgcXVpdGUgc29tZSB0aW1lLiBPdmVyIHRoZSBsYXN0IGRlY2FkZSwgaG93ZXZlciwgUiBoYXMgYmVjb21lIGluY3JlYXNpbmdseSB3aWRlIHNwcmVhZCBhbmQgYWNjZXNzaWJsZSAtIHRoZXJlIGFyZSBtb3JlIGNvdXJzZXMgdGhhbiB5b3UgY2FuIHNoYWtlIGEgc3RpY2sgYXQgb25saW5lLgoKQmVmb3JlIHdlIHN0YXJ0IHByb3BlciwgSSBhbHNvIHRoaW5rIGl0J3MgaW1wb3J0YW50IHRvIGtub3cgdGhhdCBldmVuIHBlb3BsZSB3aG8gaGF2ZSBiZWVuIHVzaW5nIFIgZm9yIHllYXJzIHN0aWxsIG1ha2UgbWlzdGFrZXMuIFRoZXJlJ3MgYSBmYWlyIGFtb3VudCB0aGF0IEkgY2FuIGRvIGluIFIgb2ZmIG9mIHRoZSB0b3Agb2YgbXkgaGVhZCAoZm9yIGV4YW1wbGUsIEkgYW0gY3VycmVudGx5IG1ha2luZyB0aGlzIGRvY3VtZW50IGluIFJTdHVkaW8hKSwgYnV0IEkgcmVndWxhcmx5IHN0aWxsIGhhdmUgdG8gZ29vZ2xlIHRoaW5ncy4gSXQncyByZWFsbHkgZWFzeSB0byBmZWVsIGEgYml0IG92ZXJ3aGVsbWVkIGFuZCB1bnN1cmUgd2hlcmUgdG8gc3RhcnQgd2l0aCBhbnkgY29kaW5nIGxhbmd1YWdlLCBidXQgcmVtZW1iZXIgdGhhdCBub2JvZHkgaXMgZXhwZWN0aW5nIHlvdSB0byBzdWRkZW5seSBiZWNvbWUgZmx1ZW50IG9yIG1lbW9yaXNlIGV2ZXJ5dGhpbmcgKGFzIGFub3RoZXIgZXhhbXBsZSwgSSd2ZSBqdXN0IGhhZCB0byBnb29nbGUgaG93IHRvIGNvZGUgc3ViLWJ1bGxldCBwb2ludHMgdG8gdGhlIGFib3ZlIGxpc3QhKS4gV2UganVzdCB3YW50IHlvdSB0byBnZXQgc29tZSBmYW1pbGlhcml0eSBhbmQgZXhwZXJpZW5jZS4gCgojIyMgTm93IHRoZW4sIEkndmUgc2FpZCBhbGwgb2YgdGhpcywgYnV0IGhhdmVuJ3QgYW5zd2VyZWQgb25lIGtleSBxdWVzdGlvbiAtIHdoYXQgaXMgUj8hCgpSIGlzIGEgZnJlZWx5IGF2YWlsYWJsZSBwcm9ncmFtbWluZyBsYW5ndWFnZSwgZGV2ZWxvcGVkIGluIHRoZSBlYXJseSAxOTkwcywgbWFkZSBvcGVuIHNvdXJjZSBpbiAxOTk1LiBSIHdhcyBkZXZlbG9wZWQgb24gdG9wIG9mIGFub3RoZXIgbGFuZ3VhZ2UsIFMuIFMgd2FzIGEgcHJvcHJpYXRvcnkgbGFuZ3VhZ2UsIHdoaWNoIHVsdGltYXRlbHksIFIgYmVjYW1lIHRoZSBvcGVuIHNvdXJjZSB2ZXJzaW9uIG9mLgoKUidzIGV0aG9zIHdhcyB0byBkZXZlbG9wIHNvbWV0aGluZyBzcGVjaWZpY2FsbHkgZm9yIHN0YXRpc3RpY2FsIGNvbXB1dGF0aW9uIGFuZCB2aXN1YWxpc2F0YWlvbiAtIGl0IHdhcyBkZXZlbG9wZWQgKipieSoqIHJlc2VhcmNoZXJzLCAqKmZvcioqIHJlc2VhcmNoZXJzLgoKU28sIGluIDIwMjMsIHdoZW4geW91IG1heSBoYXZlIGFscmVhZHkgYmVndW4gdG8gbGVhcm4sIGZvciBleGFtcGxlLCBQeXRob24sIHdoeSBib3RoZXIgd2l0aCBSPwoKKiBUaGUgc3RhdGlzdGljcyBhbmQgZGF0YS12aXMgcGFja2FnZXMgaW4gUHl0aG9uIGFyZSB2ZXJ5IHJlY2VudCwgdGhleSBkaWQgbm90IGV4aXN0IDEwIHllYXJzIGFnbyEKKiBUaGUgImRlZmF1bHQiIGxhbmd1YWdlIHZhcmllcyBmcm9tIGZpZWxkIHRvIGZpZWxkLCBidXQgY2VydGFpbmx5IGluIGVjb2xvZ3kgYW5kIGV2b2x1dGlvbiwgeW91J3JlIGxpa2VseSB0byBiZSB3b3JraW5nIHdpdGggY29sbGVhZ3VlcyB3aG8gdXNlIFIgKGludGVyZXN0aW5nbHksIGVjb2xvZ2lzdHMgd2VyZSBhY3R1YWxseSBvbmUgb2YgdGhlIGZpcnN0IHVzZXIgYmFzZXMgb2YgUikKKiBSIGlzIGRlc2lnbmVkIHRvIGJlIGFuIGVmZmljaWVudCwgaW50ZXJwcmV0ZWQgbGFuZ3VhZ2UgaW4gYSB3YXkgdGhhdCBpcyBmdW5kZW1lbnRhbGx5IGRpZmZlcmVudCB0byB0aGUgaW5pdGlhbCBkZXNpZ24gb2YgUHl0aG9uLCB3aGljaCBpcyB0eXBpY2FsbHkgaW50ZXJhY3RlZCB3aXRoIHZpYSBhIHNjcmlwdC4gUiBpcyBkZXNpZ25lZCB0byBiZSBhIHNvcnQgb2YgInN0YXRpc3RpY2FsIGNvbnZlcnNhdGlvbiIgd2hlcmUgeW91IGludGVyYWN0aXZlbHkgcHJvZ3JhbS4KKiBSIHdhcyBkZXNpZ25lZCB0byBoYXZlIGVmZmljaWVudCBkYXRhIGhhbmRsaW5nIGFuZCBzdG9yYWdlIG1lY2hhbmlzbXMuIFRoZXJlIGFlciBsb3RzIG9mIHR5cGVzIG9mIGRhdGEgc3RydWN0dXJlcyBpbiBSIC0gdGhlc2UgbWlnaHQgc2VlbSB1bm5lY2Vzc2FyeSBhdCBmaXJzdCwgYnV0IGFzIHdlIGRlbHZlIGRlZXBlciBpbnRvIFIgYW5kIGhvdyBpdCB3b3JrcywgeW91J2xsIHNlZSB3aHkgdGhleSdyZSBpbXBvcnRhbnQuIFIgaXMgd3JpdHRlbiBpbiBhIHdheSB0aGF0IG1ha2VzIGFjY2Vzc2luZyByZWFzb25hYmx5IHNpemVkIGRhdGFzZXRzIHN1cGVyIGVmZmljaWVudC4gVHlwaWNhbGx5LCB0aGlzIGlzIG5vdCB0cnVlIG9mIFB5dGhvbiBmb3IgYSBwbGV0aG9yYSBvZiByZWFzb25zIHRoYXQgd2UgZG9uJ3QgaGF2ZSB0aGUgdGltZSB0byB0YWxrIGFib3V0IChhbHRob3VnaCBhZG1pdHRlZGx5IHRoaXMgaXMgZ2V0dGluZyBiZXR0ZXIgd2l0aCB0aGUgYWR2ZW50IG9mIG1vZHVsZXMgc3VjaCBhcyBQYW5kYXMpCiogUiBjb250YWlucyBhIGxhcmdlIGNvbGxlY3Rpb24gb2YgdG9vbHMgc3BlY2lmaWNhbGx5IGRldmVsb3BlZCBmb3IgZGF0YSBhbmFseXNpcywgYXMgd2VsbCBhcyBzb21lIHJlYWxseSBnb29kIGJ1aWx0IGluIGRhdGEgdmlzdWFsaXNhdGlvbiBmZWF0dXJlcyEKKiBUaGVyZSBpcyBhIGh1Z2UgbXVsdGl2ZXJzZSB0aGF0IGhhcyBiZWVuIGJ1aWx0IGFyb3VuZCBSIHdpdGggbG9hZHMgb2YgZGlmZmVyZW50IGZsYXZvdXJzIGFzc29jaWF0ZWQgd2l0aCBpdC4gV2UnbGwgZGlzY3VzcyB0aGlzIGluIG1vcmUgZGV0YWlsIG5leHQgd2Vlay4KKiBGaW5hbGx5LCBSIGlzIGZ1bmRlbWVudGFsbHkgZGVzaWduZWQgdG8gYmUgc2ltcGxlLiBUaGlzIGlzIHdoeSBpdCdzIHRhdWdodCB0byBub24tcHJvZ3JhbW1lcnMuIFlvdSBkb24ndCBoYXZlIHRvIGRvIGNvbXBsaWNhdGVkIHRoaW5ncyBsaWtlIGZvciBsb29wcyBpZiB5b3UgZG9uJ3Qgd2FudCB0byAoYWx0aG91Z2ggd2UncmUgZ29pbmcgdG8hKS4gVGhlc2UgY2FuIGJlIGF2b2lkZWQgYW5kIFIgY2FuIGJlIHVzZWQgZm9yIGl0J3MgYmFzZSBmdW5jdGlvbmFsaXR5IG9mIGRhdGEgYW5hbHlzaXMgYW5kIHBsb3R0aW5nIHdpdGggbm8gZmFuY3kgZXh0cmFzIGlmIHlvdSBkb24ndCB3YW50IHRoZW0uCgpNb3JlIHNwZWNpZmljYWxseToKCiogUiBpcyBhIG1ham9yIHBhcnQgb2YgdGhlIGJpb2luZm9ybWF0aWMgYW5kIGJpb3N0YXRpc3RpY3MgdG9vbGtpdHMsIGFuZCBpdCBpc24ndCBnb2luZyBhd2F5IGFueSB0aW1lIHNvb24uCiogSXQgd2FzIGV4cGxpY2l0bHkgZGVzaWduZWQgdG8gaGFuZGxlIGRhdGEsIHBhcnRpY3VsYXJseSBpbiBhIGZvcm1hdCBrbm93biBhcyBkYXRhLmZyYW1lcyAtIHRoaXMgaXMgZXh0cmVtZWx5IGltcG9ydGFudCB0byB0aGUgd2F5IHRoYXQgUiBmdW5jdGlvbnMKKiBJdCBpcyBmcmVlLCBhbmQgd2lkZWx5IHN1cHBvcnRlZC4gSW4gRXZvbHV0aW9uIGFuZCBFY29sb2d5IHBhcGVycyBpbiB0aGUgbGFzdCBkZWNhZGUsIDY2JSBtZW50aW9uIFIuIElmIHlvdSB3YW50IHRvIGhhdmUgYSBjYXJlZXIgaW4gcmVzZWFyY2gsIFIgaXMgYSB2aXRhbCBza2lsbC4KKiBSIGlzIHVzZWQgYnkgbG9hZHMgb2YgbWFqb3IgdGVjaCBjb21wYW5pZXMgZm9yIHRoZWlyIGFuYWx5dGljcyAtIGluY2x1ZGluZyBmYWNlYm9vaywgZ29vZ2xlLCBhbmQgdHdpdHRlciEKCgojIyMgU28sIGhvdyBkbyB3ZSBpbnRlcmFjdCB3aXRoIFI/CgpIb3cgZG8gd2UgdXNlIFIgdG8gaGF2ZSB0aG9zZSBzdGF0aXN0aWNhbCBjb252ZXJzYXRpb25zIHRoYXQgSSByZWZlcmVuY2VkIGVhcmxpZXI/IFRoZXJlIGFyZSAyIG1haW4gd2F5cy4gVGhlIGZpcnN0IHdheSBpcyB0byB1c2UgUiBkaXJlY3RseSB0aHJvdWdoIGFuIGludGVyZmFjZSBrbm93biBhcyAiYmFzZSBSIiBvciAibmF0aXZlIFIiLiBUaGlzIGlzIHVzaW5nIFIgaW4gaXQncyBwdXJlc3QgZm9ybSwgYW5kIGlzIGFjdHVhbGx5IHF1aXRlIHRyaWNreS4gSWYgd2UgbG9hZCBiYXNlIFIsIHdlIHNlZSBhIHdpbmRvdyBsaWtlIHRoaXM6CgohW10oYmFzZVIucG5nKQoKVGhpcyBjb25zb2xlIHdpbmRvdyBjb250YWlucyBhIGxvYWQgb2YgZ29iYmxlZGVnb29rIGFidXQgdmVyc2lvbiBudW1iZXJzIGV0Yy4sIHdoaWNoIHdpbGwgdmFyeSBiZXR3ZWVuIGluZGl2aWR1YWwgbWFjaGluZXMgYW5kIFIgaW5zdGFsbHMuIFRoZSBPUyB0aGF0IHlvdSdyZSBydW5uaW5nIHdpbGwgYWxzbyBkcmFtYXRpY2FsbHkgaW1wYWN0IGhvdyB5b3VyIFIgd2luZG93IGxvb2tzIC0gdGhpcyBpcyB0aGUgTWFjT1MgUiB2ZXJzaW9uLiBFc3NlbnRpYWxseSwgUiBpcyB3YWl0aW5nIGZvciB5b3UgdG8gZW50ZXIgY29tbWFuZHMgYW5kIHRlbGwgaXQgd2hhdCB0byBkbyBuZXh0LiBBcyB5b3UgY2FuIHNlZSwgaXQncyBub3Qgb3Zlcmx5IHVzZXIgZnJpZW5kbHkuIFRoYXQgYmVpbmcgc2FpZCwgdGhlIE1hY09TIHZlcnNpb24gaXMgbXVjaCBuaWNlci4gVGhlIFdpbmRvd3MgdmVyc2lvbiBpcyBjbHVua3ksIGFuZCBldmVuIGxlc3MgZnJpZW5kbHkuIE1hY09TIFIgaGFzIGZlYXR1cmVzIG5vdCBhdmFpbGFibGUgb24gV2luZG93cyB0b28sIHdoaWNoIG1lYW5zIHVzaW5nIFIgYWNyb3NzIG11bHRpcGxlIG1hY2hpbmVzIGNhbiBiZSBhIGJpdCBvZiBwYWluLiAKCkhlcmUsIHdlIHdpbGwgdXNlIGFuIFIgSURFLCBrbm93biBhcyBSU3R1ZGlvIChhbHRob3VnaCB5b3UgbWlnaHQgYWxzbyBoZWFyIGl0IHJlZmVycmVkIHRvIGFzIHBvc2l0KS4gQW4gSURFLCBvciBhbiAqaW50ZXJhY3RpdmUgZGV2ZWxvcGVyIGVudmlyb25tZW50KiwgaXMgYSBidWlsdC1vbiBpbnRlcmZhY2UgdGhhdCBoZWxwcyB5b3UgdG8gcnVuIGEgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2UgbW9yZSBlYXNpbHkgYW5kIGVmZmVjdGl2ZWx5LiBPdGhlciBleGFtcGxlcyBvZiBJREVzIGNhbiBiZSBmb3VuZCBpbiBQeXRob24gLSB5b3UgbWlnaHQgaGF2ZSBjb21lIGFjcm9zcyBTcHlkZXIgb3IgSnVweXRlciBmb3IgZXhhbXBsZS4gUlN0dWRpbyBpcyBjb21wbGV0ZWx5IGZyZWUsIGFuZCB0aGUgYmVzdCBSIElERSBJJ3ZlIGZvdW5kLiBJdCdzIGFsc28gdGhlIG1vc3Qgd2VsbCBzdXBwb3J0ZWQsIHdoaWNoIGlzIHVzZWZ1bC4gVGhlcmUgYXJlIG90aGVycywgYnV0IFJTdHVkaW8gaXMgcGFydGljdWxhcmx5IGdvb2QuIEl0IHdpbGwgaGVscCB0byBtYWtlIHlvdXIgUiBqb3VybmV5IG11Y2ggc21vb3RoZXIsIGFuZCBhY3R1YWxseSBoZWxwcyB5b3UgdG8gc3BvdCBlcnJvcnMgaW4geW91ciBjb2RlLCB3aGljaCBpcyBhbHdheXMgYSBib251cyEgIAoKSXQgbG9va3MgYSBiaXQgbGlrZSB0aGlzOgoKIVtdKFJTdHVkaW8ucG5nKQoKWW91J2xsIG5vdGljZSB0aGF0IG15IHZlcnNpb24gb2YgUlN0dWRpbyBpcyBkaWZmZXJlbnRseSBjb2xvdXJlZCB0byB5b3VycyAtIHRoaXMgaXMganVzdCBkdWUgdG8gcGVyc29uYWwgcHJlZmVyZW5jZS4gSSBzcGVuZCBsb3RzIG9mIHRpbWUgc3RhcmluZyBhdCBteSBSIHdpbmRvdyByYXRoZXIgaW50ZW50bHksIHNvIGhhdmluZyBpdCBkYXJrZXIgcmVhbGx5IGhlbHBzISEhCgpSU3R1ZGlvIHN0YW5kYXJkaXNlcyB0aGUgUiBpbnRlcmZhY2UgYWNyb3NzIGFsbCBwbGF0Zm9ybXMgLSBpdCBsb29rcyB0aGUgc2FtZSB3aGF0ZXZlciBPUyB5b3UgbWlnaHQgYmUgcnVubmluZy4gSXQgYWxzbyBoYXMgYSBsb3Qgb2YgcG93ZXJmdWwgZmVhdHVyZXMgdGhhdCBtYWtlcyBydW5uaW5nIFIgbW9yZSBzdHJhaWdodGZvcndhcmQsIHdlJ2xsIHRhbGsgYWJvdXQgdGhlc2UgaW4gbW9yZSBkZXRhaWwgaW4gdGhlIGNvbWluZyBzZXNzaW9ucy4gSXQgYWxzbyBoYXMgZ3JlYXQgcHJvamVjdCBtYW5hZ2VtZW50IHRvb2xzLCB3aGljaCBhcmUgZW5kbGVzc2x5IHVzZWZ1bCB3aGVuIHlvdSdyZSB3b3JraW5nIG9uIG11bHRpcGxlIHByb2plY3RzIGFsbCBhdCB0aGUgc2FtZSB0aW1lIQoKTm93LCBsZXQncyB0YWxrIHRocm91Z2ggd2hhdCBhbGwgdGhlIGJpdHMgYXJlIGFib3V0LgoKIVtdKFJTdHVkaW8yLnBuZykKCkFzIHlvdSBjYW4gc2VlIGFib3ZlLCB0aGUgUlN0dWRpbyBpbnRlcmZhY2UgaXMgbWFkZSB1cCBvZiB2YXJpb3VzIHBhcnRzLiBUaGUgZmlyc3Qgb2Ygd2hpY2ggaXMgdGhlIGNvbnNvbGUuIFRoaXMsIGxpa2UgbmF0aXZlIFIsIGlzIHdhaXRpbmcgZm9yIHlvdXIgaW5wdXQgaW4gdGhlICJzdGF0aXN0aWNhbCBjb252ZXJzYXRpb25zIiB0aGF0IHlvdSdsbCBiZSBoYXZpbmcgd2l0aCBSLiBJdCBnaXZlcyB5b3UgYSBiaXQgb2YgYW4gb2RkIGJsdXJiIGFib3V0IHZlcnNpb25pbmcgZXRjLiBFYWNoIG9mIHRoZSB2ZXJzaW9ucyBoYXMgYSBzbGlnaHRseSBvZGQgbmFtZSwgSSdtIG5vdCBzdXJlIHdoeS4gU29tZSBvZiB0aGVtIGFyZSBuYW1lZCBhZnRlciB2YXJpb3VzIGFsYnVtcyBidXQgdGhhdCdzIGFzIGZhciBhcyBJJ3ZlIGdvdCB3aXRoIGZpZ3VyaW5nIG91dCB0aGUgbmFtaW5nIHN5c3RlbSEKCkFueXdheSwgdGhlcmVzIGxvYWRzIG9mIG90aGVyIHN0dWZmIG92ZXIgb24gdGhlIHJpZ2h0IGhhbmQgc2lkZSwgbW9zdCBvZiB3aGljaCBpcyBub3QgaW1vcnRhbnQgb3IgdXNlZnVsIHRvIHlvdSByaWdodCBub3cuIFRoZSAiRW52aXJvbm1lbnQiIHNlY3Rpb24ga2VlcHMgdHJhY2sgb2Ygd2hhdCB5b3UndmUgZ290IGxvYWRlZCBpbiB0ZXJtcyBvZiBkYXRhc2V0cyBhbmQgdmFyaWFibGVzIGV0Yy4sIHdoaWNoIGNhbiBwcm92ZSBpbmNyZWRpYmx5IHVzZWZ1bC4gVW5kZXJuZWF0aCwgeW91IGNhbiBmaW5kIGZpbGUgdHJlZXMsIHBsb3RzIHRoYXQgeW91IGhhdmUgY3JlYXRlZCwgaGVscCBmaWxlcywgYW5kIGxvYWRzIG9mIG90aGVyIHN0dWZmIHRoYXQgd2UgY2FuIHRhbGsgbW9yZSBhYm91dCBsYXRlciBvbi4KCiMjIFByb2plY3QgTWFuYWdlbWVudCBpbiBSCgpTdGFydGluZyB3aXRoIHByb2plY3QgbWFuYWdlbWVudCB0b29scyBmZWVscyBhIGJpdCBiaXphcnJlLCBidXQgYXMgc29tZW9uZSB3aG8gdXNlZCBSIGZvciBtYW55IG1hbnkgeWVhcnMgd2l0aG91dCB0aGlzIGZ1bmN0aW9uYWxpdHksIHRydXN0IG1lLCBpdCdzIGVhc2llc3QgdG8gZ2V0IHRvIGdyaXBzIHdpdGggaXQgZWFybHkgZG9vcnMuIFNvbWV0aGluZyB0aGF0IHBlb3BsZSBzdHJ1Z2dsZSB3aXRoLCBhbmQgc29tZXRoaW5nIHlvdSBtaWdodCBoYXZlIGNvbWUgYWNyb3NzIHdpdGggb3RoZXIgY29kaW5nIGxhbmd1YWdlcywgaXMgd2hlcmUgZmlsZXMgYXJlIHN0b3JlZCBvbiBhIGNvbXB1dGVyLiBSU3R1ZGlvIGhhcyBhIGdyZWF0IGZlYXR1cmUgdGhhdCB3aWxsIG1ha2UgdGhpcyBtdWNoIGVhc2llciB0byBkZWFsIHdpdGguIFNvLCB0byBkZW1vbnN0cmF0ZSB3aGF0IEkgbWVhbiwgdHlwZSB0aGUgZm9sbG93aW5nIGNvZGUgaW50byB5b3VyIGNvbnNvbGUgd2luZG93LCBhbmQgcHJlc3MgZW50ZXIuCgpgYGB7cn0KZ2V0d2QoKQpgYGAKClRoaXMgaXMgdGhlIGdldCB3b3JraW5nIGRpcmVjdG9yeSBjb21tYW5kLCBhbmQgaXMgc2ltaWxhciB0byBjb21tYW5kcyBpbiB1bml4IGFuZCBweXRob24gLSBpbiB1bml4LCB5b3UnZCB1c2UgYGBgcHdkKClgYGAuIFRoaXMgY29tbWFuZCBwcmludHMgdGhlIHdvcmtpbmcgZGlyZWN0b3J5LiAoKkEgcXVpY2sgbm90ZSBvbiBmdW5jdGlvbnMgaW4gUiB3aGljaCB3ZSB3aWxsIGNvbWUgYmFjayB0byAtIGFueXRoaW5nIGZvbGxvd2VkIGJ5ICgpIGlzIGEgZnVuY3Rpb24gaS5lLiBzb21ldGhpbmcgdGhhdCB0YWtlcyBhbiBpbnB1dCBhbmQgZG9lcyBzb21ldGhpbmcgd2l0aCBpdCopIElmIHlvdSBydW4gdGhlIGBgYGdldHdkKClgYGAgY29tbWFuZCwgeW91IHdpbGwgZ2V0IGFuIG91dHB1dCB3aXRoIGEgZmlsZXBhdGgsIHRoaXMgaXMgeW91ciBjdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5LCBvciwgd2hlcmUgUiBpcyBsb29raW5nIGZvciBmaWxlcyEgWW91IGNhbiB1c2UgUiBieSBwdXR0aW5nIHN0dWZmIHBsYWNlcyBhbmQgdGhlbiB1c2luZyBsb2FkcyBvZiByZWFsbHkgbG9uZyBhbmQgZGlmZmljdWx0IHBhdGggbmFtZXMgdG8gbmF2aWdhdGUgdGhyb3VnaCB5b3VyIGNvbXB1dGVycyBmaWxlIHN5c3RlbSBhbmQgdGhlbiBzdGlja2luZyB0byB0aGUgc2FtZSBkaXJlY3RvcnkuIFRoaXMgcXVpY2tseSBiZWNvbWVzIGEgbmlnaHRtYXJlIGlmIHlvdSdyZSB3b3JraW5nIG9uIG11bHRpcGxlIHByb2plY3RzIGF0IG9uY2UgdGhvdWdoLCBiZWNhdXNlIHlvdSBlbmQgdXAgdHJ5aW5nIHRvIHJlYWQgZmlsZXMgZnJvbSBhbmQgd3JpdGUgZmlsZXMgdG8gdGhlIHdyb25nIGRpcmVjdG9yaWVzLCB3aGljaCB5b3UgaGF2ZSB0byBrZWVwIGNoYW5naW5nIQoKQSBiZXR0ZXIgaWRlYSBpcyB0byBzZXQgdXAgUiB1c2luZyBwcm9qZWN0cy4gVGhlc2UgY29udGFpbiBldmVyeXRoaW5nIHlvdSBuZWVkIHdoaWNoIGlzIGFzc29jaWF0ZWQgd2l0aCBhIHNpbmdsZSBiaXQgb2YgYW5hbHlzaXMgb3IgYSBzaW5nbGUgKnByb2plY3QqIChzZWUgd2hhdCBJIGRpZD8pIHRoYXQgeW91J3JlIHVzaW5nIFIgdG8gd29yayBvbi4gV2Ugd2lsbCBjcmVhdGUgYSBwcm9qZWN0IGZvciB0aGlzIHNlc3Npb24sIHdoaWNoIHdpbGwgY3JlYXRlIGEgc2VsZi1jb250YWluZWQgZGlyZWN0b3J5LCB3aGljaCBSIHdpbGwgYWx3YXlzIG9wZW4gd2hlbiBsb29raW5nIGZvciBmaWxlcyBhc3NvY2lhdGVkIHdpdGggd2hhdCB3ZSdyZSBkb2luZywgc28geW91IGRvbid0IGhhdmUgdG8gdHJ5IGFuZCBuYXZpZ2F0ZSB0aHJvdWdoIGNvbXBsaWNhdGVkIGZpbGUgc3RydWN0dXJlcyB3aXRoaW4gUiBpdHNlbGYuIFRoaXMgaXMgcmVsYXRpdmVseSBzdHJhaWdodCBmb3J3YXJkLCBhbmQgd2UnbGwgZG8gaXQgbm93LgoKVXAgaW4gdGhlIHJpZ2h0IGhhbmQgY29ybmVyIG9mIHlvdXIgUlN0dWRpbyB3aW5kb3csIHRoZXJlIHNob3VsZCBiZSBhIGJpdCBvZiB0ZXh0IHRoYXQgcmVhZHMgcHJvamVjdDxub25lPiBvciBzaW1pbGFyLiBDbGljayBvbiB0aGlzLCBhbmQgeW91J2xsIGdldCBhIGRyb3AgZG93biBtZW51IGFwcGVhci4gRnJvbSB0aGlzIG1lbnUsIHNlbGVjdCAibmV3IHByb2plY3QiLCB3aGljaCB3aWxsIGdpdmUgeW91IHNvbWUgbW9yZSBvcHRpb25zLiBDaG9zZSAibmV3IGRpcmVjdG9yeSIgYW5kIGNhbGwgaXQgc29tZXRoaW5nIHNlbnNpYmxlLCBsaWtlICJMSUZFNDEzOC1SIi4KCioqTm90ZTogRG9uJ3QgZXZlciB1c2Ugc3BhY2VzIGluIGZpbGUgb3IgZGlyZWN0b3J5IG5hbWVzLiBJdCdzIGEgcmVhbGx5IGVhc3kgd2F5IHRvIG1ha2Ugc3VyZSB0aGF0IFIgd2lsbCBraWNrIG9mZiBhdCB5b3UhIFVzZSBhbiB1bmRlcnNjb3JlIGluc3RlYWQhKioKCgpGaW5hbGx5LCBjbGljayAiY3JlYXRlIHByb2plY3QiIGFuZCBSIHdpbGwgZG8gdGhlIHJlc3QgZm9yIHlvdS4gTm93LCBpZiB5b3UgdHJ5IHRoZSBgYGBnZXR3ZCgpYGBgIGZ1bmN0aW9uIGFnYWluLCBpdCBzaG91bGQgcHJpbnQgb2YgdGhlIGxvY2F0aW9uIG9mIHRoZSBuZXcgZGlyZWN0b3J5ISBJdCB3aWxsIGFsc28gaGF2ZSBjaGFuZ2VkIHRoZSBpbmZvcm1hdGlvbiBkaXNwbGF5ZWQgaW4gdGhlICJmaWxlcyIgc2VjdGlvbiwgaGF2aW5nIGNyZWF0ZWQgYSBuZXcgZm9sZGVyIHdoZXJldmVyIHlvdSBhc2tlZCBpdCB0by4gVGhlIGVhc2llc3Qgd2F5IHRvIGFjY2VzcyBmaWxlcyBub3cgaXMgdG8gcG9wIHRoZW0gZGlyZWN0bHkgaW50byB0aGlzIGZvbGRlci4gWW91IGNvdWxkIG5vdyBzZW5kIHNvbWVvbmUgdGhpcyAuUnByb2ogZmlsZSwgYW5kIHRoZXknZCBoYXZlIGFsbCB0aGUgc3R1ZmYgdGhleSBuZWVkZWQgdG8gcmVjcmVhdGUgeW91ciB3b3JrIQoKQW55d2F5LCB0aGF0IHdhcyBhbiBvZGQgcGxhY2UgdG8gc3RhcnQsIGJ1dCBpdCBpcyBpbXBvcnRhbnQgdG8gZ2V0IHRoaXMgcGFydCByaWdodC4KCiMjIEludGVyYWN0aW5nIHdpdGggdGhlIFIgZW52aXJvbm1lbnQKCldoZW4gd2UgaW50ZXJhY3Qgd2l0aCBSLCBnZW5lcmFsbHkgd2UgYXJlIHR5cGluZyBpbiB0aGUgY29uc29sZS4gWW91IGNhbiBhbHNvIHdyaXRlIHNjcmlwdHMgKGlmIHlvdSBkb24ndCBoYXZlIGEgc2NyaXB0IGFscmVhZHkgb3BlbiwgeW91IGNhbiBvcGVuIGEgbmV3IG9uZSBieSBjbGlja2luZyB0aGUgbmV3IHNjcmlwdCBvcHRpb24gZnJvbSB0aGUgbWVudSBhdCB0aGUgdG9wIGxlZnQgb2YgdGhlIHNjcmVlbiAtIHRoZSB3aGl0ZSByZWN0YW5nbGUgd2l0aCBhIGdyZWVuICsgaW4gdGhlIHRvcCBjb3JuZXIhKS4gQSBzY3JpcHQgaXMgZWZmZWN0aXZlbHkgYSByZWNvcmQgb2Ygd2hhdCB5b3UgaGF2ZSBkb25lIHVzaW5nIFIsIGFsbG93aW5nIHlvdSB0byBrZWVwIHRyYWNrLiBXaGVuIHlvdSd2ZSB3cml0dGVuIGNvbW1hbmRzIGluIGEgc2NyaXB0LCB5b3UgY2FuIHJ1biB0aGVtIHdpdGggeW91ciBjdXJzb3Igb24gdGhlIGxpbmUgb2YgY29kZSB5b3Ugd2lzaCB0byBydW4sIGFuZCBwcmVzc2luZyBjdHJsK2VudGVyIChjbWQrZW50ZXIgb24gTWFjT1MpLiBZb3UgbWF5IGhhdmUgY29tZSBhY3Jvc3Mgc2NyaXB0cyBpbiBweXRob24gYW5kIHVuaXgsIGJ1dCBnZW5lcmFsbHkgd2UgcnVuIHRoZW0gYSBsaXR0bGUgZGlmZmVyZW50bHkgaW4gUi4gV2UgdGVuZCB0byBydW4gc2NyaXB0cyBpbnRlcmFjdGl2ZWx5LCBlaXRoZXIgYSBzaW5nbGUgbGluZSBvciBhIGZldyBsaW5lcyBhdCBhIHRpbWUsIGFzc2VzcyBhbiBvdXRwdXQsIGFuZCB0aGVuIHJ1biBzb21lIG1vcmUuCgojIExldCdzIGdldCBzdGFydGVkIHVzaW5nIFIhCgojIyMgUiBhcyBhIGNhbGN1bGF0b3IKCkZpcnN0IHRoaW5ncyBmaXJzdCwgUiBjYW4gYmUgdXNlZCBhcyBhIGJhc2ljIGNhbGN1bGF0b3IuIFRyeSB0eXBpbmcgdGhlIGZvbGxvd2luZyBjb21tYW5kcyBpbnRvIHlvdXIgc2NyaXB0IHdpbmRvdyBhbmQgcnVubmluZyB0aGVtIHdpdGggY3RybC9jbWQrZW50ZXIuCgpgYGB7cn0KNAo0ICsgMwo1MCAtIDUKNTAgKiAyMDAwCjkgLyAzCjEwIF4gMgpgYGAKCllvdSBjYW4gc2VlIGJ5IGRvaW5nIHRoaXMgdGhhdCBSIGlzIGFibGUgdG8gcGVyZm9ybSBiYXNpYyBtYXRoZW1hdGljYWwgZnVuY3Rpb25zLiBZb3UnbGwgaGF2ZSBub3RpY2VkIHdoZW4geW91IGdhdmUgaXQgYSBzaW5nbGUgbnVtYmVyIGlucHV0LCBpdCBlY2hvZWQgdGhpcyBudW1iZXIgYmFjayB0byB5b3UuIFBsYXkgYXJvdW5kIHdpdGggdGhpcywgYW5kIHNlZSB3aGF0IFIgaXMgY2FwYWJsZSBvZiEgV2hpbHN0IHlvdSdyZSB1bmxpa2VseSB0byBvZnRlbiB1c2UgUiBleHBsaWNpdGx5IGFzIGEgY2FsY3VsYXRvciwgaXQgaXMgaW1wb3J0YW50IHRvIHVuZGVyc3RhbmQgdGhhdCBpdCBjYW4gaGFuZGxlIG51bWVyaWNzLgoKKk5vdGU6IHRoZSAiPiIgcHJvbXB0IGluIHRoZSBjb25zb2xlIGlzIHdhaXRpbmcgZm9yIHlvdSB0byBhc2sgaXQgc29tZXRoaW5nIC0gdHJ5IHJ1bm5pbmcgdGhlIGV4YW1wbGVzIGRpcmVjdGx5IGluIHRoZSBjb25zb2xlIGFzIHdlbGwgYXMgaW4gc2NyaXB0IGZvcm0hKgoKIyMjIFIgYW5kIHRleHQgaW5wdXQKClIgY2FuIGFsc28gaW50ZXJwcmV0IHRleHQhIFlvdSBjYW4gZ2l2ZSBpdCBhIGNoYXJhY3RlciBzdHJpbmcsIGFuZCBpdCB3aWxsIHByaW50IGl0IGJhY2sgdG8geW91IC0gdHJ5IHJ1bm5pbmcgdGhlIGZvbGxvd2luZzoKCmBgYHtyfQoiSGVsbG8gd29ybGQhIgonSGVsbG8gd29ybGQhJwpIZWxsbyB3b3JsZApgYGAKTm90ZSB0aGF0IHRoZSBsYXN0IGV4YW1wbGUgb2YgdGhpcyBkb2VzIG5vdCB3b3JrLCBiZWNhdXNlIFIgaXMgbG9va2luZyBmb3IgYW4gKipvYmplY3QqKiBjYWxsZWQgSGVsbG8gd29ybGQgd2hpY2ggaXQgY2Fubm90IGZpbmQuIFdpdGhvdXQgdGhlIHF1b3RhdGlvbiBtYXJrcyAoZWl0aGVyIHR5cGUgaXMgZmluZSwgYnV0IGJlIGNvbnNpc3RlbnQpLCBpdCBkb2VzIG5vdCByZWNvZ25pc2UgdGhlIHRleHQgYXMgYSBzdHJpbmcuCgpZb3UnbGwgaGF2ZSBnb3QgYSBmdW5reSBlcnJvciBpbiB0aGUgbGFzdCBleGFtcGxlLCBzb21ldGhpbmcgYWJvdXQgYW4gdW5lcGV4dGVkIHN5bWJvbCAtIGl0IGxpa2VseSB3b250IGhhdmUgbWFkZSBtdWNoIHNlbnNlIHRvIHlvdS4gVGhpcyBpcyBmYWlybHkgdHlwaWNhbCBvZiBSIGVycm9yIG1lc3NhZ2VzIHVuZm9ydHVuYXRlbHksIHRoZXkgYXJlIGZhbWVkIGZvciBiZWluZyB0cmlja3kgdG8gaW50ZXJwcmV0LiBUaGV5IHRha2Ugc29tZSBnZXR0aW5nIHVzZWQgdG8sIGJ1dCBldmVudHVhbGx5IHlvdSB3aWxsIGJlIGFibGUgdG8gdHJhbnNsYXRlIHRoZXNlIGJpemFycmUgbWVzc2FnZXMgaW50byBzb21ldGhpbmcgdGhhdCBhY3R1YWxseSBtYWtlcyBzZW5zZS4gRm9yIGV4YW1wbGUsIGhlcmUsIHRoZSAidW5leHBlY3RlZCBzeW1ib2wiIGlzIHJlZmVycmluZyB0byB0aGUgc3BhY2UgYmV0d2VlbiB0aGUgd29yZHMgIkhlbGxvIiBhbmQgIndvcmxkIi4gV2l0aG91dCB0aGUgcXVvdGF0aW9uIG1hcmtzLCBSIGV4cGVjdHMgdGhlc2UgdGhpbmdzIHRvIGJlIGZ1bmN0aW9ucyBvciBvYmplY3RzIHJhdGhlciB0aGFuIGEgY2hhcmFjdGVyIHN0cmluZywgYW5kIGNhbm5vdCBwcm9jZXNzIHRoZSBzcGFjZS4KCgojIyMgUiBhcyBhIGxvZ2ljYWwgaW50ZXJwcmV0ZXIKClIgY2FuIHRlbGwgeW91IHdoZXRoZXIgYSBzdGF0ZW1lbnQgaXMgdHJ1ZSBvciBmYWxzZS4gVGhpcyBzZWVtcyBiYXNpYywgYnV0IGl0IHdpbGwgYnVpbGQgdXAgdG8gY3JlYXRlIGEgdXNlZnVsIHRvb2wgYWxvbmdzaWRlIHRoZSBvdGhlciBwYXJ0cyBvZiBpdCdzIGZ1bmN0aW9uYWxpdHkgdGhhdCB3ZSdyZSBkaXNjdXNzaW5nLiBUaGUgbG9naWNhbCBpbnRlcnByZXRlciB3aXRoaW4gUiBpcyBhIGtleSBwYXJ0IG9mIGhvdyBSIGZ1bmN0aW9ucyBhcyBhIHBlaWNlIG9mIHNvZnR3YXJlLCBhbmQgaXMgY29tbW9ubHkgaW4tYnVpbHQgaW50byBtYW55IHNvcGhpc3RpY2F0ZWQgZnVuY3Rpb25zIGFuZCBhbmFseXNlcy4gUiB3aWxsIHRlbGwgeW91IGlmIHNvbWV0aGluZyBpcyBsb2dpY2FsLCBvciBpZiBpdCBtYWtlcyBzZW5zZSwgYnkgcmV0dXJuaW5nIGVpdGhlciBgYGBUUlVFYGBgIG9yIGBgYEZBTFNFYGBgIHRvIGFuIGlucHV0LiBUaGlzIGlzIHBvc3NpYmxlIHdpdGggbnVtZXJpY2FsIGlucHV0ICoqYW5kKiogY2hhcmFjdGVyIHN0cmluZ3MgLSB0cnkgdGhlIGZvbGxvd2luZyBmb3IgZXhhbXBsZToKYGBge3J9CjIgPT0gMgo1ID4gMTAKOSA8PSAxMAoiTWFyaW8iID09ICJNYXJpbyIKIk1hcmlvIiA9PSAiTHVpZ2kiCmBgYAoKKk5vdGU6IHlvdSdsbCBub3RpY2UgdGhhdCB3aGVuIHdlIGFyZSBhc2tpbmcgUiBpZiB0aGluZ3MgYXJlIGVxdWl2ZWxhbnQgdG8gb25lIGFub3RoZXIsIHdlIHVzZSBhIGRvdWJsZSA9PSBzaWduLiBUaGlzIGlzIGJlY2F1c2UgYSBzaW5nbGUgPSBzaWduIGlzIHVzZWQgaW4gUiB0byBhc2lnbiBzb21ldGhpbmcgdG8gYSB2YXJpYWJsZSBuYW1lLiBJJ2xsIGV4cGxhaW4gbW9yZSBhYm91dCB0aGF0IGluIGEgbWludXRlISoKClJpZ2h0LCB0aW1lIHRvIHN0YXJ0IGJ1aWxkaW5nIHVwIHRvIHVzaW5nIFIgcHJhY3RpY2FsbHkuCgojIyMgQXNzaWduaW5nIG9iamVjdHMKClNvLCBpdCdzIHVzZWZ1bCB0byBrbm93IGhvdyB0byBtYWtlIGEgdmFyaWFibGUgaW4geW91ciBSIGVudmlyb25tZW50LiBZb3UgbWF5IGFscmVhZHkga25vdyB0aGlzIGZyb20geW91ciBhZHZlbnR1cmVzIHdpdGggUHl0aG9uLiBJbiBQeXRob24sIHlvdSB1c2UgYW4gPSB0byBhc3NpZ24gYSB2YXJpYWJsZS4gV2hpbHN0IHlvdSBjYW4gZG8gdGhpcyBpbiBSLCBpdCdzIGJlc3QgcHJhY3RpY2UgdG8gdXNlIHRoZSBgYGA8LWBgYCBvcGVyYXRvciBpbnN0ZWFkLiBOb3RlIHRoaXMgY3JlYXRlcyBhbiAqb2JqZWN0KiBpbiBSLCAqKm5vdCoqIGEgKnZhcmlhYmxlKi4gVGhpcyBpcyBiZWNhdXNlIG9mIHRoZSBzdGF0aXN0aWNhbCBuYXR1cmUgb2YgUiAtIGluIHN0YXRpc3RpY3MsIGEgdmFyaWFibGUgbWVhbnMgc29tZXRoaW5nIGVudGlyZWx5IGRpZmZlcmVudC4gSSB1c2UgPC0gYmVjYXVzZSBpdCBpcyBob3cgSSB3YXMgdGF1Z2h0IHRvIHVzZSBSLCBidXQgaXQncyBva2F5IHRvIHVzZSA9IGlmIHlvdSdkIHByZWZlci4gSXQgZG9lcyBnZXQgY29tcGxpY2F0ZWQgYmVjYXVzZSBvZiB0aGUgPT0gZnVuY3Rpb24sIHNvIEkgbGlrZSB0byB1c2UgPC0gaW5zdGVhZC4gU29tZSBwcm9ncmFtbWVycyBnZXQgYSBiaXQgcGlja3kgYW5kIGp1ZGd5IGlmIHlvdSB1c2UgYSBkaWZmZXJlbnQgd2F5IHRvIHRoZW0sIGJ1dCBteSBwaGlsb3NvcGh5IHdpdGggUiBpcyBpZiBpdCB3b3JrcywgaXQgd29ya3MuCgpTbywgd2h5IGFzaWduPyBJdCBzYXZlcyB0aW1lIGFuZCBtYWtlcyB5b3VyIHNjcmlwdGluZyBlYXNpZXIhIFRoZXJlIGFyZSBzb21lIHJ1bGVzLCBob3dldmVyLiBBc3NpZ25tZW50IGlzIGNhc2Ugc2Vuc2l0aXZlLCBzbyBkb24ndCB0eXBlIHNvbWV0aGluZyB3aXRoIGxvYWRzIG9mIHZhcnlpbmcgY2FzZXMuIFlvdXIgb2JqZWN0IG5hbWUgYWxzbyBjYW4ndCBzdGFydCB3aXRoIGEgbnVtYmVyLCBhbmQgc29tZSB3b3JkcyB0aGF0IGFyZSBhc3NvY2lhdGVkIHdpdGggY29tbW9uIGZ1bmN0aW9ucyBsaWtlIGBgYGlmYGBgIG9yIGBgYGVsc2VgYGAgYXJlIG5vdCBhbGxvd2VkIGFuZCB3aWxsIGJyaW5nIHVwIGFuIGVycm9yIG1lc3NhZ2UuIFRyeSB0aGUgZm9sbG93aW5nIGFuZCB0YWtlIG5vdGUgb2YgdGhlIGVycm9yIG1lc3NhZ2VzIHlvdSBzZWU6CmBgYHtyfQpteV9udW1iZXIgPC0gMTUwMzAyCgpteV9udW1iZXIyID0gMjA0MjExCgpteV90ZXh0IDwtIOKAnEhlbGxvIHdvcmxk4oCdCgoxbXlfdGV4dCA8LSAiSGVsbG8gd29ybGQiCgpmb3IgPC0gIkhlbGxvIHdvcmxkIgpgYGAKCkFsc28sIGl0IGlzIGltcG9ydGFudCB0byBtYWtlIHN1cmUgeW91IGRvbid0IG5hbWUgYW4gb2JqZWN0IHRoZSBzYW1lIGFzIGEgdmFyaWFibGUgaW4geW91ciBkYXRhIHN0cnVjdHVyZSwgb3IgeW91J2xsIHJ1biBpbnRvIHNvbWUgdHJvdWJsZSEhCgojIEEgbm90ZSBvbiBzY3JpcHRpbmc6CgpTY3JpcHRzIGFyZSBlc3NlbnRpYWxseSBhIHJlY29yZCBvZiB3aGF0IHlvdSd2ZSBkb25lIC0gbGlrZSBhIGxpdmUgZG9jdW1lbnQgeW91IGNhbiBlZGl0IGFuZCBhZGQgdG8gYXMgeW91IGdvLiBXaGVuIEkgc2NyaXB0LCBpdCdzIGFsbW9zdCBsaXRlcmFsbHkgYSBzdHJlYW0gb2YgY29uc2Npb3VzbmVzcywgd2hpY2ggaW5jbHVkZXMgYml0cyBvZiBjb2RlIHRoYXQgZG9uJ3Qgd29yayBzbyBJIGRvbid0IG1ha2UgdGhlIHNhbWUgZXJyb3IgYWdhaW4uIFlvdSBzaG91bGQgbGVhdmUgY29tbWVudHMgdG8gcmVtaW5kIHlvdXJzZWxmIG9mIHdoYXQgeW91J3JlIGRvaW5nLCBiZWNhdXNlIGV2ZW4gaWYgeW91IHRoaW5rIHlvdSdsbCByZW1lbWJlciwgSSBwcm9taXNlIGlmIHlvdSBjb21lIGJhY2sgdG8gaXQgaW4gc2l4IG1vbnRocywgeW91J2xsIGJlIGxvc3QhIFlvdSBkZW5vdGUgYSBjb21tZW50IGJ5IHN0YXJ0aW5nIGEgbGluZSB3aXRoIGEgYGBgI2BgYC4gUiB3aWxsIGlnbm9yZSB0aGVzZSBsaW5lcyAodGhleSB3aWxsIGJlIGdyZXllZCBvdXQgaW4gUlN0dWRpbyksIHNvIGFkZCBhcyBtYW55IGFzIHlvdSBsaWtlIQoKV2hlbiB5b3UncmUgdGhpbmtpbmcgYWJvdXQgbm90IHVzaW5nIGNvbW1lbnRzLCByZW1lbWJlciB0aGUgVm95cmljaCBtYW51c2NyaXB0LiBJdCB3YXMgd3JpdHRlbiBpbiBnaWJiZXJpc2gsIGFuZCBub2JvZHkga25vd3Mgd2hhdCBpdCBtZWFucyBiZWNhdXNlIHRoZXJlIGlzIG5vIHdheSBvZiB0cmFuc2xhdGluZyBpdCwgYW5kIG5vIHdheSB0byB3b3JrIG91dCB3aGF0IHRoZSBhdXRob3Igd2FzIHRoaW5raW5nLiBJIGdvIHN1cGVyIG92ZXItYm9hcmQgd2l0aCBjb21tZW50cyB0byBteXNlbGYsIHBhcnRpY3VsYXJseSB3aGVuIEknbSBzaGFyaW5nIHNjcmlwdHMgd2l0aCBvdGhlcnMuCgojIERhdGEgc3RydWN0dXJlcwoKUmlnaHQsIGxldHMgZ2V0IHRvIHRoZSByZWFsIG1lYXQuIERhdGEgc3RydWN0dXJlcy4gVGhlcmUgYXJlIDQgbWFpbiBkYXRhIHN0cnVjdHVyZXMgdGhhdCB3ZSdsbCBjb3ZlciBoZXJlICh3ZWxsLCAzLjUgYmVjYXVzZSB3ZSdsbCBjb3ZlciBsaXN0cyBwcm9wZXJseSBhbm90aGVyIHRpbWUpIC0gVmVjdG9ycywgTWF0cmljaWVzLCBhbmQgRGF0YWZyYW1lcy4KCiMjIFZldG9ycwoKV2UnbGwgc3RhcnQgd2l0aCB2ZWN0b3JzLiBXZSd2ZSBhbHJlYWR5IGNvbnNpZGVyZWQgYWxsIHRocmVlIG1haW4gY2xhc3NlcyBvZiBkYXRhIGFib3ZlLCBudW1lcmljLCBjaGFyYWN0ZXIsIGFuZCBsb2dpY2FsLiBXZSB1c2UgdGhlc2UgYW5kIG90aGVycyB0byBidWlsZCB1cCBvdXIgZGF0YSBzdHJ1Y3R1cmVzIGluIFIuCgpBIHZlY3RvciBpcyBqdXN0IGEgMS1kaW1lbnNpb25hbCBzZXJpZXMgb2YgdmFsdWVzIC0gdGhlIGxlbmd0aCBvZiB0aGUgdmVjdG9yIGlzIGl0cyBvbmx5IGRpbWVuc2lvbi4gVGhpcyBpcyB0aGUgbW9zdCBiYXNpYyBkYXRhIHN0cnVjdHVyZSB5b3UnbGwgZmluZCBpbiBSLCBhbmQgdGhlIGZ1bmRlbWVudGFscyBvZiBhY2Nlc3NpbmcgaXRzIGNvbnRlbnRzIGFyZSBkaWZmZXJlbnQgdG8gUHl0aG9uLiBTbywgd2UnbGwgc3RhcnQgYnkgY3JlYXRpbmcgYSBzZXJpZXMgb2YgdmVjdG9ycywgc3RhcnRpbmcgd2l0aCBhIG51bWVyaWMgdmVjdG9yOgoqTm90ZTogYygpIGlzIGEgdXNlZnVsIGZ1bmN0aW9uIGhlcmUsIGl0J3Mgc2hvcnQgZm9yIGNvbmNhdCBvciBjb21iaW5lLCB3ZSdsbCB0YWxrIG1vcmUgYWJvdXQgZnVuY3Rpb25zIGxhdGVyISoKCmBgYHtyfQp4IDwtIGMoMSwgMiwgMywgNCwgNSkKCnkgPC0gMTo1Cgp6IDwtIHNlcShmcm9tID0gMSwgdG8gPSA1LCBieSA9IDEpIAoKYGBgCkFsbCBvZiB0aGVzZSBleGFtcGxlcyB3aWxsIGdpdmUgeW91IGEgbnVtYmVyIHZlY3RvciB0aGF0IHJhbmdlcyBmcm9tIDEtNS4gVGhlIGZpcnN0IGNvbWJpbmVzIGFsbCBsaXN0ZWQgbnVtYmVycywgdGhlIHNlY29uZCBjcmVhdGVzIGEgc2VyaWVzIG9mIG51bWJlcnMgZnJvbSAxOjUgKHRoZSBgYGA6YGBgIGVzc2VudGlhbGx5IG1lYW5zIGZyb20gMSB0byA1KSwgYW5kIHRoZSB0aGlyZCBjcmVhdGVzIGEgc2VxdWVuY2UgZnJvbSAxIHRvIDUsIGdvaW5nIHVwIGluIDFzLgoKV2UgY2FuIGFsc28gY3JlYXRlIGNoYXJhY3RlciB2ZWN0b3JzLiBMYXRlciwgd2Ugd2lsbCBkaXNjdXNzIGhvdyB5b3UgYWNjZXNzIGFuIGluZGl2aWR1YWwgY29tcG9uZW50IG9mIGVhY2ggb2YgdGhlc2UgdmVjdG9ycywgYnV0IGZvciBub3csIGxldCdzIGJ1aWxkIHNvbWUgY2hhcmFjdGVyIHZlY3RvcnMgKHVzaW5nIG15IGZhdm91cml0ZSBuaW50ZW5kbyBleGFtcGxlcyEpLiBOb3RlIHRoYXQgeW91IGNhbiBvbmx5IGNyZWF0ZSBhIGNoYXJhY3RlciB2ZWN0b3Igd2l0aCB0aGUgYGBgYygpYGBgIGZ1bmN0aW9uLiBXaXRob3V0IHRoaXMsIFIgaXMgb25seSBleHBlY3RpbmcgYSBzaW5nbGUgdmFsdWUgaW4geW91ciBhc3NpZ25tZW50IGFuZCB3aWxsIHRocm93IGFuIGVycm9yIHVwLiBMZXQncyB0cnk6CgpgYGB7cn0KYSA8LSBjKOKAnE1hcmlv4oCdLCDigJxMdWlnaeKAnSwg4oCcUGVhY2jigJ0pCgpiIDwtIGMo4oCcTGlua+KAnSwg4oCcWmVsZGHigJ0sIOKAnEdhbm5vbuKAnQoKYGBgCgpXZSBjYW4gYWxzbyBjcmVhdGUgYSB2ZWN0b3Igb2YgbG9naWNhbCB2YWx1ZXMuICoqUmVtZW1iZXIgdGhhdCBUUlVFIGFuZCBGQUxTRSBoYXZlIHRvIGJlIGluIGNhcHMgZm9yIFIgdG8gaW50ZXJwcmV0IHRoZW0gYXMgbG9naWNhbHMqKi4gSGVyZSwgd2UnbGwgY3JlYXRlIGEgbG9naWNhbCB2ZWN0b3IgdXNpbmcgbG9nY2FsIHZhbHVlcywgYW5kIHRoZW4gb25lIGZyb20gY2hhcmFjdGVyIHZlY3RvcnMgd2l0aCBgYGA9PWBgYDoKCmBgYHtyfQplIDwtIGMoVFJVRSwgRkFMU0UsIFRSVUUpCgpmIDwtIGEgPT0gYgpgYGAKCiMjIyBWZWN0b3IgcHJvcGVydGllcwoKSXQncyB0aW1lIHRvIGhhdmUgYSBsb29rIGF0IHRoZSBwcm9wZXJ0aWVzIG9mIGEgdmVjdG9yIC0gbGF0ZXIgd2UnbGwgbW92ZSBvbiB0byBzdGlja2luZyB2ZWN0b3JzIHRvZ2V0aGVyIHRvIG1ha2UgbmV3IGRhdGEgc3RydWN0dXJlcywgYnV0IGZvciBub3csIHdlJ2xsIGhhdmUgYSBsb29rIGF0IHZlY3RvcnMgYXMgc3RhbmQgYWxvbmUgb2JqZWN0cy4gV2UgY2FuIGRvIG1hdGhlbWF0aWNhbCBvcGVyYXRpb25zIG9uIGVudGlyZSBudW1lcmljIHZlY3RvcnMgLSB3ZSBjYW4gYXBwbHkgYSBzaW5nbGUgb3BlcmF0aW9uIHRvIGFsbCB2YWx1ZXMgaW4gYSB2ZWN0b3IsIG9yIHdlIGNhbiBwZXJmb3JtIG9wZXJhdGlvbnMgb24gdHdvIGRpZmZlcmVudCB2ZWN0b3JzOgoKYGBge3J9CnggPC0gMToxMAp4ICsgNQp4IOKAkyA1Cgp5IDwtIDExOjIwCnggKyB5CnggKiB5CgpgYGAKClZlY3RvciBvcGVyYXRpb25zIHN1Y2ggYXMgdGhvc2UgYWJvdmUgYXJlIGEgdmVyeSBpbXBvcnRhbnQgYW5kIHBvd2VyZnVsIHRvb2wgaW4gUiBmb3IgcmFwaWQgY2FsY3VsYXRpb25zIGFjcm9zcyBsYXJnZSBzZXRzIG9mIG51bWJlcnMuCgpEYXRhIHN0cnVjdHVyZXMgaW4gUiBoYXZlIHByb3BlcnRpZXMgLSB0aGUgbWFpbiBwcm9wZXJ0eSBvZiBhIHZlY3RvciBpcyBpdHMgbGVuZ3RoLiBPbmNlIHlvdSBrbm93IHNvbWV0aGluZyBhYm91dCB0aGUgbGVuZ3RoIG9mIGEgdmVjdG9yLCB5b3UgY2FuIG1vcmUgZWFzaWx5IGFjY2VzcyB0aGUgc3R1ZmYgaW5zaWRlIG9mIGl0LiBZb3UgZmluZCB0aGUgbGVuZ3RoIG9mIGEgdmVjdG9yIHVzaW5nIGBgYGxlbmd0aCh4KWBgYC4gCgpZb3Ugd2lsbCBnZXQgd2FybmluZ3MgdG8gZG8gd2l0aCB0aGUgbGVuZ3RoIG9mIGEgdmVjdG9yIGluIHZhcmlvdXMgY2lyY3Vtc3RhbmNlcywgZm9yIGUuZy4gaWYgdHdvIHZlY3RvciBsZW5ndGhzIGFyZSBub3QgbXVsdGlwbGVzIG9mIG9uZSBhbm90aGVyIGluIHNvbWUgbWF0aGVtYXRpY2FsIGNhbGN1bGF0aW9ucy4gVHJ5IHRoZSBmb2xsb3dpbmc6CgpgYGB7cn0KeCA8LSAxOjEwCmxlbmd0aCh4KQoKeSA8LSAxOjUKeCArIHkKeCAqIHkKCnogPC0gMTozCnkgKiB6IAoKYGBgCkhlcmUsIHlvdSdsbCBub3RpY2UgdGhhdCB0aGUgb3BlcmF0aW9uIGNhdXNlcyB0aGUgc2hvcnRlciB2ZWN0b3IgKHopIHRvIGJlIGxvb3BlZCBhY3Jvc3MgdW50aWwgaXQgZml0cyB0aGUgbG9uZ2VyLiBTbywgeW91ciByZXN1bHQgZnJvbSBgYGB5ICogemBgYCBpcyBhY3R1YWxseToKCi0gMSAqIDEsIAotIDIgKiAyLAotIDMgKiAzLCAKLSA0ICogMSwgYW5kIAotIDUgKiAyCgpSIHdpbGwgc3RpbGwgcGVyZm9ybSB0aGVzZSBvcGVyYXRpb25zLCBidXQgaXQgd2lsbCB3YXJuIHlvdSB0aGF0IHZlY3RvciBsZW5ndGhzIGFyZSBub3QgbXVsdGlwbGVzIG9mIG9uZSBhbm90aGVyLgoKU28sIGhvdyBkbyB3ZSBpbnRlcmFjdCB3aXRoIHZlY3RvcnMgYW5kIHN0YXJ0IHRvIHB1bGwgaXRlbXMgZnJvbSB0aGVtPyBWZWN0b3JzIGFyZSBncmVhdCwgYnV0IHRoZXkncmUgbm90IG92ZXJseSB1c2VmdWwgdW5sZXNzIHdlIGNhbiBnZXQgYXQgdGhlIHN0dWZmIGluc2lkZSBvZiB0aGVtLiBXZSdsbCBjcmVhdGUgYW5vdGhlciBjaGFyYWN0ZXIgdmVjdG9yLCBgYGB4YGBgLgoKYGBge3J9CnggPC0gYygiZG9nIiwgImNhdCIsICJtb3VzZSIpCnhbXSAjIFRoaXMgd2lsbCBwcmludCBhbGwgdmVjdG9yIHZhbHVlcwp4WzFdICMgVGhpcyB3aWxsIHByaW50IHRoZSBmaXJzdCB2YWx1ZSAtIG5vdGUgdGhhdCBSIGlzIGluZGV4ZWQgZnJvbSAxIHVubGlrZSBQeXRob24hIQp4W2MoMSwgMyldICMgVGhpcyBnaXZlcyB5b3UgdGhlIGZpcnN0IGFuZCB0aGlyZCB2YWx1ZXMgLSBub3RlIHRoZSB1c2Ugb2YgYygpCnhbMjozXSAjIHRoaXMgZ2l2ZXMgeW91IHZhbHVlcyAyIHRocm91Z2ggdG8gMy4KCmBgYAoKU28sIG5vdyB3ZSBjYW4gcHVsbCBvdXQgd2hhdGV2ZXIgdmFsdWVzIHdlIHdhbnQsIHdlIGNhbiB1c2UgdGhpcyB0byBtYW5pcHVsYXRlIHRoZSBjb250ZW50cyBvZiBvdXIgdmVjdG9yISBJZiB3ZSB3YW50ZWQgdG8sIGZvciBleGFtcGxlLCByZXBsYWNlIHRoZSBtb3VzZSB3aXRoIGFuIGVsZXBoYW50LCB3ZSdkIHVzZSB0aGUgZm9sbG93aW5nOgoKYGBge3J9CnhbM10gIyBUaGlzIHByaW50cyAibW91c2UiCnhbM10gPC0gImVsZXBoYW50IiAjIFRoaXMgYXNzaWducyB0aGUgc3RyaW5nICJlbGVwaGFudCIgdG8gdGhlIHRoaXJkIGluZGV4IG9mIHRoZSB2ZWN0b3IsIHJlcGxhY2luZyAibW91c2UiLgp4CmBgYApOb3csIHdoYXQgaWYgd2Ugd2FudCB0byByZW1vdmUgbnVtYmVyIDMgYWxsIHRvZ2V0aGVyPyBXZSBjYW4gZG8gdGhpcyBieSBhc3NpZ25pbiBpdCBhbiBgYGBOQWBgYCB2YWx1ZSwgd2hpY2ggaW5kaWNhdGVzIHRvIFIgdGhhdCB0aGVyZSBpcyBubyB2YWx1ZSBwcmVzZW50IGF0IHRoaXMgbG9jYXRpb246CgpgYGB7cn0KeFszXSA8LSBOQQpgYGAKIyMjIEEgbm90ZSBvbiBOQToKCmBgYE5BYGBgIGlzIGEgcGxhY2Vob2xkZXIgaW4gUiwgZm9yIHdoZW4gZGF0YSBpcyAiTm90IEF2YWlsYWJsZSIsIGFuZCBpdCB1c3VhbGx5IGRlbm90ZXMgbWlzc2luZyBkYXRhLiBGb3IgZXhhbXBsZSwgeW91IG1pZ2h0IGJlIGNvbGxlY3RpbmcgYmxvb2Qgc2FtcGxlcyBmcm9tIHBhdGllbnRzIGluIGEgbG9uZ2l0dWRpbmFsIHRyaWFsLCBhbmQgYSBwYXRpZW50IGlzIHVuYWJsZSB0byBwcm92aWRlIGEgc2FtcGxlIGF0IHBvaW50IDMgb2YgNSwgc28gaGVyZSwgeW91ciB2YWx1ZSBmb3Igd2hhdGV2ZXIgeW91J3JlIG1lYXN1cmluZyBpbiB0aGUgYmxvb2Qgd291bGQgYmUgYGBgTkFgYGAuIE90aGVyIGNvbW1vbmx5IGVuY291bnRlcmVkIG1pc3NpbmcgdmFsdWUgcGxhY2Vob2xkZXJzIGluIFIgYXJlIGBgYE5hTmBgYCAoTm90IEEgTnVtYmVyKSBhbmQgYGBgSW5mYGBgIChJbmZpbml0eSkuCgoKIyBGdW5jdGlvbnMKCldlJ2xsIHRha2UgYSBicmllZiBpbnRlcmx1ZGUgZnJvbSBkYXRhIHN0cnVjdHVyZXMgZm9yIGEgYnJpZWYgd29yZCBhYm91dCBmdW5jdGlvbnMgbm93LiBGdW5jdGlvbnMgYXJlIHRoZSBicmVhZCBhbmQgYnV0dGVyIG9mIFIuIFRoZXkgYXJlIGNvZGUgdGhhdCB0YWtlcyBhbiBpbnB1dCwgcHJvY2Vzc2VzIGl0LCBhbmQgcmV0dXJucyBhIHJlc3VsdCBpbiB0aGUgZm9ybSBvZiBhbiBvdXRwdXQuIFdlIGhhdmUgYWxyZWFkeSB1c2VkIHNvbWUgZnVuY3Rpb25zIGFib3ZlLCBzdWNoIGFzIGBgYGxlbmd0aCgpYGBgIGFuZCBgYGBzZXEoKWBgYC4gVGhlcmUgYXJlIHRob3VzYW5kcyBvZiBmdW5jdGlvbnMgYXZhaWxhYmxlIHRvIHlvdSBpbiBSLCBmcm9tIHRoZSB2ZXJ5IGJhc2ljIHRvIHRoZSBleHRyZW1lbHkgY29tcGxpY2F0ZWQgYW5kIGludm9sdmVkLiBZb3UgY2FuIChhbmQgeW91IHdpbGwhKSB3cml0ZSB5b3VyIG93biBmdW5jdGlvbnMsIG11Y2ggbGlrZSB5b3UgY2FuIGluIFB5dGhvbiwgYWx0aG91Z2ggdGhlIHN5bnRheCBpcyBkaWZmZXJlbnQuIFByZS1idWlsdCBmdW5jdGlvbnMgb2Z0ZW4gY29tZSB3aXRoIGhlbHAgZmlsZXMsIHRyeSB0aGUgZm9sbG93aW5nOgoKYGBge3J9CnkgPC0gMToxMApsZW5ndGgoeSkKP2xlbmd0aApgYGAKVXNlIGBgYD9mdW5jdGlvbmBgYCBvciBgYGBoZWxwKCJmdW5jdGlvbiIpYGBgIHRvIGFjY2VzcyBoZWxwLiBUaGUgaGVscCBmaWxlcyBnZW5lcmFsbHkgY29udGFpbiBhIGRlc2NyaXB0aW9uIG9mIHRoZSBmdW5jdGlvbiBhbmQgZGV0YWlscyBvZiBhbGwgdGhlIGFyZ3VtZW50cyB3aGljaCBtYXkgYmUgc3VwcGxpZWQgdG8gaXQuIFRoZXNlIGhlbHAgZmlsZXMgZG8gdGFrZSBzb21lIGdldHRpbmcgdXNlZCB0bywgYXMgdHJ1ZSB0byBSJ3Mgc3R5bGUsIHRoZXkgY2FuIGJlIHF1aXRlIHRyaWNreSB0byBpbnRlcnByZXQhCgojIyBUaGUgYW5hdG9teSBvZiBhIGZ1bmN0aW9uCgpUcnkgcnVubmluZyB0aGUgZm9sbG93aW5nIGNvZGU6CgpgYGB7cn0KeSA8LSAxOjEwCnN1bSh5KQp5WzVdIDwtIE5BICMgUmVwbGFjZSB0aGUgNXRoIGluZGV4IHdpdGggTkEKc3VtKHkpCmBgYAoKCllvdSdsbCBub3RpY2UgdGhhdCBpZiBhIHZlY3RvciBjb250YWlucyBgYGBOQWBgYCwgZnVuY3Rpb25zIHN1Y2ggYXMgYGBgc3VtKClgYGAgd2lsbCByZXR1cm4gYGBgTkFgYGAuIFNvbWV0aGluZyBoYXNuJ3QgcXVpdGUgd29ya2VkIGhlcmUsIHNvIHdlIG5lZWQgdG8gYWRkIGFuIGFkZGl0aW9uYWwgYXJndW1lbnQgdG8gb3VyIGZ1bmN0aW9uIHRvIGRlYWwgd2l0aCB0aG9zZSBwZXNreSBgYGBOQWBgYHMuLi4KCmBgYHtyfQpzdW0oeSwgbmEucm0gPSBUUlVFKQpgYGAKCkhlcmUsIHRoZSBgYGBuYS5ybWBgYCBhcmd1bWVudCBpcyBzZXQgdG8gYGBgVFJVRWBgYCwgc28gdGhhdCBgYGBOQWBgYCBpcyBpZ25vcmVkIChvciwgbW9yZSBhY2N1cmF0ZWx5LCByZW1vdmVkKS4gTm90ZSB0aGF0IHRoZSBhc3NpZ25tZW50IG9mIHRoaW5ncyAqaW5zaWRlKiBvZiBhIGZ1bmN0aW9uIGlzIGFsd2F5cyBkb25lIHdpdGggYGBgPWBgYCBhbmQgbm90IGBgYDwtYGBgLiAKCiMgUGxvdHRpbmcgYW5kIHZpc3VhbGlzYXRpb24KCk5vdyBpcyBhIGdvb2QgdGltZSB0byBzdGFydCB0aGlua2luZyBhYm91dCB3aGF0IHdlIGNhbiBhY3R1YWxseSBnZXQgb3V0IG9mIHdoYXQgd2UndmUgbGVhcm5lZCBzbyBmYXIsIHNvIHdlJ2xsIHVzZSBScyBpbnRlZ3JhdGVkIHBsb3R0aW5nIHNvZnR3YXJlIHRvIGNyZWF0ZSBzb21lIG5pY2UgcGxvdHMhIFlvdSBjYW4gaGF2ZSBhIGxvb2sgYXQgd2hhdCBSIGhhcyB0byBvZmZlciB1c2luZyB0aGUgbm93IHNsaWdodGx5IG91dGRhdGVkIGBgYGRlbW8oZ3JhcGhpY3MpYGBgIGNvbW1hbmQuIFRyeSB0YWtpbmcgYSB0b3VyIHRocm91Z2ggdGhlIGdyYXBoIHR5cGVzLgoKTGV0J3MgdXNlIHRoZSBza2lsbHMgd2UndmUgbGVhcm5lZCBzbyBmYXIgdG8gbWFrZSBhIHBsb3QhCmBgYHtyfQp4IDwtIDE6MTAwCnkgPC0geF4yCnBsb3QoeCwgeSkKYGBgCgpOaWNlISBZb3Ugc2hvdWxkIGhhdmUgcHJvZHVjZWQgYSBzY2F0dGVyIHBsb3QuIFdoYXQgaWYgd2Ugd2FudCB0byB0dXJuIHRoYXQgaW50byBhIGxpbmUgcGxvdD8KCmBgYHtyfQpwbG90KHgsIHksIHR5cGUgPSAibCIpCmBgYAoKRmFidWxvdXMuIFRoZSB3YXlzIHRvIGN1c3RvbWlzZSBncmFwaGljcyBpbiBSIGFyZSBhbG1vc3QgZW5kbGVzcyAtIHdlJ2xsIGhhdmUgYSBjbG9zZXIgbG9vayBsYXRlciBvbiEgRm9yIG5vdyB0aG91Z2gsIHdlJ2xsIGdldCBiYWNrIHRvIG91ciBkYXRhIHN0cnVjdHVyZXMuCgojIFJldHVybmluZyB0byBkYXRhIHN0cnVjdHVyZXMKCiMjIE1hdHJpY2llcwoKVGhlIHNlY29uZCB0eXBlIG9mIGRhdGEgc3RydWN0dXJlIHdlJ2xsIGxvb2sgYXQgaXMgdGhlIGh1bWJsZSBtYXRyaXguIFRoZXNlIGRhdGEgc3RydWN0dXJlcyBzdG9yZSBkYXRhIGluIHJvd3MgYW5kIGNvbHVtbnMgKGkuZS4gbGlrZSBhIHRhYmxlISkuIFRoZXkgYXJlIHZlcnkgc2ltaWxhciB0byB2ZWN0b3JzLCBvbmx5IHRoZXkgYXJlIHR3by1kaW1lbnNpb25hbC4gSW4gZmFjdCwgd2UgY2FuIGJ1aWxkIG91ciBmaXJzdCBtYXRyaXggZnJvbSBzb21lIHZlY3RvcnMgdXNpbmcgdGhlIGBgYGNiaW5kKClgYGAgYW5kIGBgYHJiaW5kKClgYGAgZnVuY3Rpb25zOgoKYGBge3J9CnggPC0gMTo0CnkgPC0gMjE6MjQKeiA8LSBjYmluZCh4LCB5KQp6CmBgYAoKYGBgY2JpbmQoKWBgYCBiaW5kcyB2ZWN0b3JzIHRvZ3RoZXIgYnkgY29sdW1uLCB3aGVyZWFzIGBgYHJiaW5kKClgYGAgZG9lcyBpdCBieSByb3csIGVmZmVjdGl2ZWx5IGZsaXBwaW5nIG91ciB0YWJsZS4gVHJ5IHJ1bm5pbmcgYGBgejEgPC0gcmJpbmQoeCwgeSlgYGAgYW5kIGxvb2tpbmcgYXQgdGhlIG91dHB1dC4KClRoZXJlIGlzIGEgc2ltcGxlIHdheSB0byBkZXRlcm1pbmUgd2hldGhlciB5b3VyIGRhdGEgc3RydWN0dXJlIGlzIGEgbWF0cml4LCB3aGljaCBpcyBieSBydW5uaW5nIHRoZSBgYGBpcy5tYXRyaXgoeilgYGAgY29tbWFuZC4gVHJ5IGl0ISBJdCBzaG91bGQgZ2l2ZSBhIGxvZ2ljYWwgb3V0cHV0IG9mIFRSVUUgb3IgRkFMU0UuIFlvdSBjYW4gYWxzbyBhY2Nlc3MgdGhlIGRpbWVuc2lvbnMgb2YgYSBtYXRyaXggaW4gYSBzaW1pbGFyIHdheSB0byBhIHZlY3RvciAoYWx0aG91Z2ggc2xpZ2h0bHkgZGlmZmVyZW50KS4gYGBgZGltKHopYGBgIHRlbGxzIHlvdSB0aGUgZGltZW5zaW9ucyBvdmVyYWxsLCBgYGBucm93KClgYGAgdGVsbHMgeW91IHRoZSBudW1iZXIgb2Ygcm93cywgYW5kIHVuc3VycHJpc2luZ2x5LCBgYGBuY29sKClgYGAgZ2l2ZXMgeW91IGluZm9ybWF0aW9uIGFib3V0IHRoZSBudW1iZXIgb2YgY29sdW1ucyBpbiB0aGUgbWF0cml4LiBUcnkgaXQgd2l0aCBvdXIgbWF0cml4IGBgYHpgYGAuCgoqKkFuIGltcG9ydGFudCBjb25zaWRlcmF0aW9uIHdpdGggbWF0cmljaWVzIGlzIHRoYXQgd2UgcmVmZXIgdG8gdGhlbSBieSB0aGUgcm93IGluZGV4LCBhbmQgdGhlbiB0aGUgY29sdW1uKiouIFRoaXMgaXMgc29tZXRoaW5nIHRoYXQgaXMgdmVyeSBlYXN5IHRvIGZvcmdldCwgYW5kIEkgb2Z0ZW4gaGF2ZSB0byBsb29rIGl0IHVwLCBzbyBkb24ndCB3b3JyeSBpZiB5b3UgY2FuJ3QgcmVtZW1iZXIuIE1hdHJpY2llcyBhcmUgYWxzbyBvbmx5IGNhcGFibGUgb2Ygc3RvcmluZyAxIHR5cGUgb2YgZGF0YSwgZWl0aGVyIGxvZ2ljYWwsIGNoYXJhY3Rlciwgb3IgbnVtZXJpYy4gSWYgeW91ciBkYXRhIGlzIG1peGVkIGluIHR5cGUsIHlvdSdsbCBuZWVkIGEgZGF0YWZyYW1lIHJhdGhlciB0aGFuIGEgbWF0cml4LCBidXQgd2UnbGwgZ2V0IHRvIHRoYXQgc29vbi4gTGV0J3Mgc2VlIHdoYXQgaGFwcGVucyBpZiB3ZSB0cnkgYW5kIHN0b3JlIG11bHRpcGxlIGRhdGEgdHlwZXM6CgpgYGB7cn0KeCA8LSBjKOKAnE1hcmlv4oCdLCDigJxMdWlnaeKAnSwg4oCcUGVhY2jigJ0pCnkgPC0gYyjigJxUb2Fk4oCdLCDigJxCb3dzZXLigJ0sIOKAnFdhcmlv4oCdKQp6IDwtIGMoMSwgMiwgMykKbSA8LSBjYmluZCh4LCB5LCB6KQoKYGBgCkhlcmUgeW91IGNhbiBzZWUgdGhhdCB0aGUgbnVtYmVycyBpbiBgYGB6YGBgIGFyZSB0cmFuc2Zvcm1lZCBpbnRvIGNoYXJhY3RlcnMhCgpBbnl3YXksIGhvdyBkbyB3ZSBleHRyYWN0IGFuZCBhY2Nlc3MgaW5mb3JtYXRpb24gc3RvcmVkIGluIGEgbWF0cml4PyEgTGlrZSB3aXRoIHZlY3RvcnMsIHdlIHVzZSBzcXVhcmUgYnJhY2tldHMuIExldCdzIG1ha2UgYSBiaWdnZXIgbWF0cml4IGFuZCBoYXZlIGEgZ28uIE5vdGUgdGhhdCB3ZSBhcmUgdXNpbmcgdGhlIGBgYG1hdHJpeCgpYGBgIGZ1bmN0aW9uIGhlcmUgcmF0aGVyIHRoYW4gYGBgY2luZCgpYGBgLiAKCmBgYHtyfQptIDwtIG1hdHJpeCgxOjEwLCBuY29sID0gMikgIyBuY29sID0gMiB0ZWxscyBSIHRoYXQgd2Ugd2FudCB0aGUgbnVtYmVycyAxLTEwIHNwbGl0IGludG8gMiBjb2x1bW5zCm1bMSwgXSAjIHJldHVybiBmaXJzdCByb3cKbVssIDJdICMgcmV0dXJuIHNlY29uZCBjb2x1bW4KbVsxLDJdICMgcmV0dXJuIHRoZSBpbmZvcm1hdGlvbiBpbiB0aGUgZmlyc3Qgcm93IG9mIHRoZSBzZWNvbmQgY29sdW1uLCBpbiB0aGlzIGV4YW1wbGUsIDYuCmBgYAojIyBEYXRhIGZyYW1lcwoKUmlnaHQsIG9uIHRvIG91ciB0aGlyZCAoYW5kIHByb2JhYmx5IGZpbmFsKSBkYXRhIHN0cnVjdHVyZSAtIGRhdGEgZnJhbWVzLiBNb3N0ICJyZWFsIiBkYXRhIHRoYXQgeW91IGNvbWUgYWNyb3NzIGluIHlvdXIgdHJhdmVscyB3aWxsIGJlIGluIGEgZGF0YWZyYW1lLiBJdCdzIGEgYml0IGxpa2UgYSBtYXRyaXgsIGJ1dCBjYXBhYmxlIG9mIHN0b3JpbmcgbXVsdHVwbGUgZGF0YSBjbGFzc2VzIGluIHRoZSBzYW1lIG9iamVjdC4gTGV0J3MgbWFrZSBvbmUgZnJvbSAzIHZlY3RvcnMgYW5kIGhhdmUgYSBsb29rOgoKYGBge3J9Cm5hbWUgPC0gYyjigJxNYXJpb+KAnSwg4oCcTHVpZ2nigJ0sIOKAnExpbmvigJ0sIOKAnFplbGRh4oCdKQpoZWlnaHQgPC0gYygxNTUsIDE2MCwgMTgwLjMsIDE4MC4zKQphZ2UgPC0gYygyNiwgMjQsIDE3LCAxOSkKCmRmIDwtIGRhdGEuZnJhbWUobmFtZSwgaGVpZ2h0LCBhZ2UpCgpgYGAKTm90ZSB0aGF0IHRoZSBkYXRhZnJhbWUgbXVzdCBoYXZlIG5hbWVkIGNvbHVtbnMhIFlvdSBjYW4gbG9vayBhdCB0aGUgZmlyc3QgZmV3IHJvd3Mgb2YgeW91ciBkYXRhIHdpdGggYGBgaGVhZChkZilgYGAsIGFuZCB0YWtlIG5vdGUgb2YgdGhlIHN0cnVjdHVyZSBvZiBpdCB3aXRoIGBgYHN0cihkZilgYGAuIE5vdywgZXZlcnl0aGluZyB5b3UndmUganVzdCBsZWFybmVkIGFib3V0IGFjY2Vzc2luZyBkYXRhIGluc2lkZSBvZiBhIG1hdHJpeCBzdGFuZHMgdHJ1ZSBmb3IgZGF0YWZyYW1lcyBhbHNvIC0gdGhleSB3b3JrIGluIGEgdmVyeSBzaW1pbGFyIGZhc2hpb24gd2l0aCB0aGUgcm93cyBhbmQgY29sdW1ucyBmb3JtYXQuIFRoZXJlIGlzLCBob3dldmVyLCBhbm90aGVyIHdheSB0byBhY2Nlc3MgZGF0YSBmcm9tIHlvdXIgZGF0YWZyYW1lIHRoYXQgSSBmaW5kIG1vcmUgaW50dWl0aXZlIHRoYW4gdXNpbmcgY29sdW1uIGluZGljaWVzLCB3aGljaCBpcyByZWZlcnJpbmcgdG8gdGhlIGNvbHVtbiBieSBpdHMgbmFtZSAoaGVuY2UgdGhlIG5lZWQgZm9yIG5hbWVkIGNvbHVtbnMhKS4gVHJ5IHRoaXM6CgpgYGB7cn0KIyBBY2Nlc3NpbmcgZGF0YSBhcyBpZiBpdCB3ZXJlIGEgbWF0cml4CmRmWywgMV0KZGZbMywgXQpkZls0LCAzXQoKIyBVc2luZyBjb2x1bW4gbmFtZXMgYXMgcmVmZXJlbmNlcwoKZGZb4oCcbmFtZeKAnV0KZGZbLCDigJxuYW1l4oCdXQpkZiRuYW1lCgpgYGAKV2hlbiB5b3UgZXh0cmFjdCBhIGNvbHVtbiBpbiB0aGlzIHdheSwgaXQgYmVjb21lcyBhIHZlY3RvciEgTm90ZSB0aGF0IGluIGBgYGRmJG5hbWVgYGAsIHRoZSBgYGAkYGBgIGVzc2VudGlhbGx5IGp1c3QgbWVhbnMgImxvb2sgaW5zaWRlIiAtIHNvIHlvdSdyZSB0ZWxsaW5nIFIgdG8gbG9vayBpbnNpZGUgYGBgZGZgYGAgdG8gZmluZCB0aGUgYGBgbmFtZXNgYGAgY29sdW1uLiAKCgojIEFjY2Vzc2luZyBleGFtcGxlIGRhdGEKClVzaW5nIHRoZSB0b3kgZGF0YXNldHMgYXMgd2UganVzdCBoYXZlIGlzIGFsbCB3ZWxsIGFuZCBnb29kIHdoZW4geW91J3JlIGxlYXJuaW5nLCBhbmQgaXMgYSBmdW4gd2F5IHRvIGV4cGVyaW1lbnQgYW5kIGZpZ3VyZSBvdXQgaG93IHRoaW5ncyB3b3JrISBCdXQsIHdoYXQgaWYgd2Ugd2FudCB0byBnZXQgaG9sZCBvZiBzb21lIGFjdHVhbCBkYXRhPyBUaGVyZSBhcmUgbG9hZHMgb2YgcHJlLWxvYWRlZCByZWFsIGxpZmUgZGF0YXNldHMgdGhhdCBjb21lIHdpdGggUiwgc28gbGV0J3MgaGF2ZSBhIGxvb2sgYXQgYXJndWFibHkgdGhlIG1vc3QgZmFtb3VzIG9mIHRoZXNlLCB0aGUgaXJpcyBkYXRhc2V0LgoKSWYgd2UgdHlwZSBgYGBkYXRhKClgYGAgaW50byBvdXIgUiBjb25zb2xlL3NjcmlwdCBhbmQgcnVuIGl0LCBSIHdpbGwgbG9hZCB0aGVzZSBkYXRhc2V0cyBmb3IgdXMuIFdlIGNhbiB0aGVuIHVzZSB0aGUgYGBgaGVhZCgpYGBgIGZ1bmN0aW9uIHRvIGxvb2sgYXQgdGhlIGBgYGlyaXNgYGAgZGF0YXNldC4uLgoKYGBge3J9CmRhdGEoKQoKaGVhZChpcmlzKQoKP2lyaXMKYGBgCgpOb3RlIHRoYXQgd2UgY2FuIGdldCBtb3JlIGluZm9ybWF0aW9uIGFib3V0IHRoZSBkYXRhc2V0IGJ5IHJ1bm5pbmcgdGhlIGhlbHAgYGBgP2BgYCBmdW5jdGlvbi4gV2Ugd2lsbCByZXZpc2l0IHRoZXNlIGRhdGFzZXQgaW4gYSBtaW51dGUsIGJ1dCBmaXJzdCwgd2hhdCBpZiB5b3Ugd2FudCB0byBpbXBvcnQgeW91ciBvd24gZGF0YT8hCgpUaGUgZWFzeSB3YXk6IHlvdSBjYW4gdXNlIFJTdHVkaW8gdG8gaW1wb3J0IGRhdGEgdmlhIHRoZSBHVUksIHdoaWNoIGlzIGEgZ29vZCB3YXkgdG8gbGVhcm4gYXQgZmlyc3QsIGJ1dCBpc24ndCBhcyBmbGV4aWJsZSBhcyBsZWFybmluZyBmdW5jdGlvbnMgdG8gcmVhZCBkYXRhLi4uCgohW10oaW1wb3J0LnBuZykKClRoZSAoYXJndWFibHkpIGJldHRlciB3YXkgaXMgdG8gdXNlIHRoZSBgYGByZWFkLmNzdigpYGBgIGZ1bmN0aW9uLiBJIHdpbGwgdXNlIGl0IGhlcmUgdG8gdXBsb2FkIGEgLmNzdiBmaWxlIEkgaGF2ZSBpbiBteSBwcm9qZWN0IGRpcmVjdG9yeSB3aGljaCBjb250YWlucyBkYXRhIGZyb20gTmV0ZmxpeCB0aXRsZXMgb3ZlciB0aGUgeWVhcnMuIFRyeSB3aXRoIHlvdXIgb3duIGRhdGEhCgpgYGB7cn0KbmV0ZmxpeCA8LSByZWFkLmNzdigiLi9uZXRmbGl4X3RpdGxlcy5jc3YiKQpoZWFkKG5ldGZsaXgpCmBgYAoKWW91IG1heSBhbHNvIG5lZWQgdG8gd3JpdGUgZGF0YSBvdXQgb2YgUiwgd2hpY2ggY2FuIGJlIGdvb2QgZm9yIHNhdmluZyB5b3VyIHByb2dyZXNzIG9yIHNhdmluZyBmaWx0ZXJlZCBkYXRhc2V0cy4gSGVyZSwgd2Ugd2lsbCB3cml0ZSBvdXQgYSBmaWxlIG9mIGNvbW1hLXNlcGFyYXRlZCB2YXJpYWJsZXMgKGEgLmNzdiBmaWxlKS4KCmBgYHtyfQpkZiA8LSBkYXRhLmZyYW1lKG5hbWUgPSBjKOKAnE1hcmlv4oCdLCDigJxMdWlnaeKAnSwg4oCcTGlua+KAnSwg4oCcWmVsZGHigJ0pLAoJCSAgICBoZWlnaHQgPSBjKDE1NSwgMTYwLCAxODAuMywgMTgwLjMpLAoJCSAgICBhZ2UgPSBjKDI2LCAyNCwgMTcsIDE5KSkKCndyaXRlLmNzdihkZiwg4oCcLi9uaW50ZW5kby5jc3bigJ0pIAoKYGBgCipOb3RlOiB0aGlzIGlzIHRoZSBuaW50ZW5kbyBkYXRhZnJhbWUgd2UgbWFkZSBlYXJsaWVyLCBzbyB5b3UgbWF5IG5vdCBuZWVkIHRvIHJlbWFrZSBpdCEqCgojIEV4dGVuZGluZyBiZXlvbmQgYmFzZSBSOgoKUGFja2FnZXMsIHdoaWNoIGFyZSBhbmFsYWdvdXMgdG8gbW9kdWxlcyBpbiBQeXRob24sIGFyZSBhIGdyZWF0IHdheSBvZiBleHRlbmRpbmcgeW91ciBSIHVuaXZlcnNlLiBUaGV5IGNhbiBiZSBpbnN0YWxsZWQgaW4gYSBtdWx0aXR1ZGUgb2Ygd2F5cywgYnV0IHBlcmhhcHMgdGhlIG1vc3QgY29tbW9uIGlzIGluc3RhbGxpbmcgdGhlbSBkaXJlY3RseSB0aHJvdWdoIHRoZSBDb21wcmVoZW5zaXZlIFIgTmV0d29yayAtIENSQU4uIFRoZXJlIGFyZSBjdXJyZW50bHkgb3ZlciAxODUwMCBwYWNrYWdlcyBsaXN0ZWQgb24gQ1JBTiwgc28gaXQncyBsaWtlbHkgdGhhdCBpZiB5b3UncmUgdHJ5aW5nIHRvIGRvIHNvbWV0aGluZyBzcGVjaWZpYyBpbiBSLCB0aGVyZSBpcyBhbHJlYWR5IGEgcGFja2FnZSEgT3RoZXIgcmVwb3NpdG9yaWVzIGluY2x1ZGUgR2l0SHViIGFuZCBCaW9Db25kdWN0b3IuCgojIyBJbnN0YWxsaW5nIGFuZCBsb2FkaW5nIFIgcGFja2FnZXM6CgpJbnN0YWxsbmlnIHBhY2thZ2VzIGlzIHVzdWFsbHkgc3RyYWlnaHQgZm9yd2FyZC4uLiBZb3UgYWxzbyBvbmx5IG5lZWQgdG8gZG8gaXQgb25jZSBvbiBlYWNoIGNvbXB1dGVyIHlvdSB1c2UhIFdlIHdpbGwgaW5zdGFsbCBgYGBnZ3Bsb3QyYGBgIG5vdywgYSBwYWNrYWdlIHdlIHdpbGwgdXNlIGxvdHMgaW4gb3RoZXIgc2Vzc2lvbnMuIE9uY2UgaW5zdGFsbGVkLCB5b3UgbXVzdCBsb2FkIHlvdXIgcGFja2FnZSBpbnRvIFIgd2l0aCB0aGUgYGBgbGlicmFyeSgpYGBgIGZ1bmN0aW9uLgoKYGBge3J9Cmluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQpsaWJyYXJ5KGdncGxvdDIpCmBgYAoKIyBCYWNrIHRvIHBsb3RzIQoKVmlzdWFsaXNpbmcgZGF0YSBpcyBhIGZ1bmRlbWVudGFsbHkgaW1wb3J0YW50IHRvb2wgaW4gUiAtIHRoaW5rIG9mIGl0IGFzIGEgd2F5IHRvIHVuZGVyc3RhbmQgYW5kIHByb3Blcmx5IGV4cGxvcmUgeW91ciBkYXRhLiBXZSB3b250IHVzZSBnZ3Bsb3QyIGZvciB0aGlzIGZvciBub3csIGFsdGhvdWdoIHRoaXMgaXMgYSBmYWJ1bG91cyBwbG90dGluZyB0b29sLiBXZSBjYW4gdXNlIFIgdG8gbWFrZSBhIHNpbXBsZSBzY2F0dGVyIHBsb3QsIGFzIHdlIGRpZCBiZWZvcmU6CgpgYGB7cn0KeCA8LSBzZXEoZnJvbSA9IDEsIHRvID0gMTAwLCBieSA9IDUpCnkgPC0geF4yCgpwbG90KHgsIHkpCgpgYGAKIVtdKHBsb3QxLnBuZykKCldlIGNhbiBjdXN0b21pc2UgYWxtb3N0IGFueXRoaW5nIG9uIHRoaXMgcGxvdCwgYW5kIHdlIGFkZCB0byBpdCBpdGVyYXRpdmVseSBhcyB3ZSBnby4gWW91J2xsIHNlZSB3aGF0IEkgbWVhbiBpbiB0aGUgZm9sbG93aW5nIGV4YW1wbGVzLiBGaXJzdCwgd2UnbGwgY2hhbmdlIHRoZSBvcmllbnRhdGlvbiBvZiB0aGUgeSBheGlzIGxhYmVscyB3aXRoIHRoZSBgYGBsYXMgPSAxYGBgIGFyZ3VtZW50IGluIHRoZSBgYGBwbG90KClgYGAgZnVuY3Rpb246CgpgYGB7cn0KcGxvdCh4LCB5LCBsYXMgPSAxKQpgYGAKCiFbXShwbG90Mi5wbmcpCgpXZSBjYW4gY2hhbmdlIHRoZSBjb2xvdXIgb2YgdGhlIHBvaW50cywgYW5kIHRoZW4gYWRkIGEgbGluZToKCmBgYHtyfQpwbG90KHgsIHksIGxhcyA9IDEsIGNvbCA9IOKAnHJlZOKAnSkKbGluZXMoeCx5KQoKYGBgCgohW10ocGxvdDMucG5nKQoKV2UgY2FuIGFkZCBhIHRpdGxlOgoKYGBge3J9CnBsb3QoeCwgeSwgbGFzID0gMSwgY29sID0g4oCccmVk4oCdLAogICAgIG1haW4gPSDigJxyZWxhdGlvbnNoaXAgYmV0d2VlbiB4ICYgeeKAnSkKbGluZXMoeCx5KQoKYGBgCiFbXShwbG90NC5wbmcpCgpUaGUgcG9zc2liaWxpdGllcyBhcmUgZW5kbGVzcyEKClJpZ2h0LCBsZXRzIG1ha2UgYSBiYXNpYyBoaXN0b2dyYW0gYW5kIGEgYm94IGFuZCB3aGlza2VyLCB0aGVuIHdlJ2xsIGNhbGwgaXQgYSBkYXkuCgpQbG90dGluZyB0aGUgZGlzdHJpYnV0aW9uIG9mIGRhdGEgd2l0aCBhIGhpc3RvZ3JhbSBjYW4gYmUgdXNlZnVsIHRvIGlkZW50aWZ5IG91dGxpZXJzIG9yIGhhdmUgYSBsb29rIGF0IHRoZSBzaGFwZSBvZiB5b3VyIGRhdGEuIFdlIGNhbiBwbG90IHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uIGFzIGFuIGV4YW1wbGUgLSB0aGUgZm9sbG93aW5nIGNvZGUgd2lsbCBnZW5lcmF0ZSBhIHNlcmllcyBvZiBudW1iZXJzIHRoYXQgZm9sbG93IGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiBhbmQgdGhlbiBwbG90IGl0OgoKYGBge3J9CnggPC0gcm5vcm0obiA9IDEwMDAsIG1lYW4gPSAyNS41LCBzZCA9IDMpCgpoaXN0KHgpCgpgYGAKCiFbXShoaXN0MS5wbmcpCgpCb3hwbG90cyBhcmUgdXNlZnVsIHRvIGhhdmUgYSBsb29rIGF0IHBvdGVudGlhbCBkaWZmZXJlbmNlcyBiZXR3ZWVuIGdyb3VwcyBvZiBkYXRhIC0gbGV0J3MgcGxvdCB0aGUgaXJpcyBkYXRhIGFuZCBzZWUgaG93IHBldGFsIHdpZHRoIG1pZ2h0IGRpZmZlciBhbW9uZyBzcGVjaWVzOgoKYGBge3J9CmhlYWQoaXJpcykKCmJveHBsb3QoaXJpcyRQZXRhbC5XaWR0aCB+IGlyaXMkU3BlY2llcywKCSAgbGFzID0gMSwgeWxhYiA9IOKAnFBldGFsIHdpZHRo4oCdLAoJICB4bGFiID0g4oCcU3BlY2llc+KAnSkKCmBgYAoKIVtdKGJveDEucG5nKQoKIyMgQSBxdWljayBub3RlIGFib3V0IHRpbGRlICh+KQoKSW4gUiwgYSB0aWxkZSBkZW5vdGVzIHRoZSByZWxhdGluc2hpcCBiZXR3ZWVuIHR3byB2YXJpYWJsZXMsIGFuZCBpcyBjb21tb25seSB1c2VkIGluIHN0YXRpc3RpY2FsIGZ1bmN0aW9ucy4gSXQncyBzbGlnaHRseSBjb25mdXNpbmcsIGFzIGl0IGFwcGVhcnMgdG8gYmUgdGhlIHdyb25nIHdheSBhcm91bmQgLSB5b3UgY29kZSB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIGFuZCB0aGVuIHRoZSBpbmRlcGVuZGVudC4gU28sIGBgYFBldGFsIHdpZHRoIH4gU3BlY2llc2BgYCBtZWFucyBob3cgZG9lcyBwZXRhbCB3aWR0aCB2YXJ5IGFtb25nIHNwZWNpZXM/IQoKIyBUb3AgdGlwcyBmb3IgbGVhcm5pbmcgUjoKCiogRXhwZXJpbWVudCEgTm90IG11Y2ggY2FuIGdvIGhvcnJpYmx5IHdyb25nLi4uCiogUHJhY3RpY2UsIHByYWN0aWNlLCBwcmFjdGljZSEKKiBUaGVyZSBpcyBubyBzaW5nbGUgcmlnaHQgd2F5IC0gaWYgaXQgd29ya3MsIGl0IHdvcmtzLgoqIFVzZSByZXNvdXJjZXMgYXZhaWxhYmxlIG9ubGluZSAtIFN0YWNrT3ZlcmZsb3csIFR3aXR0ZXIsIFIgZm9ydW1zICh3aXRoIGNhdXRpb24hKQoqIFRha2UgYSBicmVhay4gQSB3YWxrIGFuZCBhIGJyZXcgZG9lcyB3b25kZXJzLgoKCgoKCgo=