Preface

This is an interactive R Markdown Notebook file that follows Chapter 2 of Getting started with R: an introduction for biologists, 2nd edition by Andrew P. Beckerman, Dylan Z. Childs, and Owen L. Petchey.

The first thing you should do is click File, and then Save As on the menu bar above and rename the file “Your Last Name_ch2.Rmd”

Learning objectives

By the end of this tutorial, you will be able to:

Load packages

At the beginning of every Notbook or script, load the specific add-on packages you will need for that analysis into R.

We will need the tidyverse and lubridate packages; in the code chunk below, type library(tidyverse), hit Enter and type library(lubridate), then hit Run:

library(diplyr)
Error in library(diplyr) : there is no package called ‘diplyr’

Tidy data

“Happy families are all alike; every unhappy family is unhappy in its own way.” –– Leo Tolstoy (author of Anna Karenina)

“Tidy datasets are all alike, but every messy dataset is messy in its own way.” –– Hadley Wickham (Chief Scientist at RStudio)

As in much of life, careful preparation is the key to good results. R likes data in which there is one observation in a row, and each variable is represented by its own column. Such data is called “long format” or “tidy data”. Getting your data into this format requires some upfront work, but that work pays off in the long term. Once you have tidy data and the tidy tools provided by packages in the tidyverse, you will spend much less time munging data from one representation to another, allowing you to spend more time on the analytic questions at hand.

Getting data ready for R

Let’s take a look at a sample data sheet in Excel (or some other spreadsheet software, e.g. Google Docs or LibreOffice). Open the file called ‘fiddler_crab_temps.xlsx’ by clicking on the file name in the Files tab in the lower right pane, and then View File.

These particular data are the body temperatures (Tbs) selected by fiddler crabs in a laboratory thermal gradient; small and large crabs were tested on either wet or dry sand. For complete details of the study, see the associated publication: Allen et al. 2012 J Exp Mar Biol Ecol.pdf, also available in the file list. Note that the column names are informative, brief, and simple. In general, it is best not to use spaces or special symbols, which R can deal with but may not do so particularly well. Also, given categorical variables such as sex (male, female), it is best to use the actual category names rather than codes for them (e.g. don’t use 1 = male, 2 = female). R can easily deal with variables that contain words (so-called character strings), and this will make subsequent tasks in R much more efficient and reliable.

All cells in a data sheet should have an entry, even if it is something saying “no observation was made”. The expected placeholder for missing data in R is NA (e.g., see the third observation listed in the fiddler crab data set). Other options are possible, but not recommended - a blank cell is ambiguous: perhaps nothing was seen in that instance (in which case a zero should be used to indicate an actual null value), or perhaps no observation was made for whatever reason.

Althogh Excel has many features that make it convenient to organize and display data, most data scientists would argue that you should convert your .xls or .xlsx file to a “comma-separated values” (.csv) file before trying to import it into R. A .csv file is easily transported with a low memory and small size footprint among computing platforms. In Excel, or other spreadsheet programs, after you click Save As you can change the format of the file to “comma-separated values” (sometimes also called “comma delimited”), then press Save. Excel might then, or when you close the file, ask if you’re sure you’d like to save your data in this format. Yes, you are sure! Note that you can only save a single worksheet in a .csv file, so if you have your data organized as multiple worksheets in Excel, you will need to create a separate .csv file for each. You will also lose any formating in the worksheets (e.g., bolding, centering, highlighting, etc.). Do that now - use Save As to save the fiddler crab data as “fiddler_crab_data.csv” in the same folder as the other files.

One of the remarkable things about R is that once a copy of your “raw data” is established, the use of R for data visualization and analysis will never require you to alter the original file (unless you collect more data!). With R, your original data file can and must always remain unmanipulated; if any adjustments do occur, they occur in an R copy only and only via your explicit instructions harboured in the script.

Ideally, your data will be tidy before you ever try to import them into R. If your data are not tidy to start with, you can of course rearrange them in Excel. This can, however, cause errors, be awfully time-consuming, and is tedious and boring for big datasets. The alternative is to do it in R; we’ll practice that shortly.

Project-oriented workflow

You should generally plan to organize each separate data analysis into a project: a folder on your computer that holds all the files relevant to that particular piece of work, starting with the .csv data file. Any associated R script should be written assuming that it will be run from a fresh R process/session, with the working directory (the location on your computer where R will look for files to open or save) set to the project directory (main folder). You can then create sub-folders for specific types of files, such as data, figures, function files, and manuscripts. Using a consistent folder structure and file naming system across projects makes it easier to navigate the project contents, resume work after a hiatus, and re-use code in multiple projects.

Revisiting Jenny Bryan’s post on project-oriented workflow, this work style is so crucial that RStudio has an official notion of a Project (with a capital “P”). You can designate a new or existing folder as a Project. All this means is that RStudio leaves a file, e.g., foofy.Rproj, in the folder, which is used to store settings specific to that project. Double-click on a .Rproj file to open a fresh instance of RStudio, with the working directory and file browser pointed at the project folder. This convention guarantees that the project can be moved around on your computer or onto other computers and will still “just work”. RStudio fully supports Project-based workflows, making it easy to switch from one to another, have many projects open at once, re-launch recently used Projects, etc. You can create an RStudio project either in a brand new directory or an existing directory where you already have R code and data, by clicking File, and then New Project or the “Create a Project” button on the toolbar above. Although neither new, nor unique to R, this is arguably the only practical approach that creates reliable, polite behavior across different computers or users and over time.

All of which is to say that if you organize your R life around a project-oriented workflow, you can ignore all concerns about setting the working directory and specifying file paths.

Getting your data into R

In the next few sections, we will work with several datasets already in the project folder (also available for download as a zip file at the companian website for the book). There are at least four really easy ways to get R to import the data, without having to do anything tricky like type the path to your data file; however, we are going to focus on just two:

Rstudio provides menu-based import functionality via the Import Dataset button on the Environment tab in the upper right pane of RStudio. This will allow you to navigate to your data file, select it, and click the Open button. Given our focus on .csv files, select “From Text (base)” as your option. A window will open with a list of all the files in this particular project folder choose fiddler_crab_temps.csv and click Open. A new dialogue box will displaying the first 20 rows of data and the default set of import options for the read.csv() function; note for the future that the option “Strings as factors” is checked - that means that R will convert columns that are detected to be character strings (i.e., words) to be factor variables. So a variable like “small or large” will be encoded as “1 or 2”, where each number represents a different level of the factor. Although this can be useful for statistical modeling, it can be problematic in other contexts; most newer R packages (e.g., tidyverse) no longer have stringsAsFactors = TRUE as the default setting. This import pathway relies on the read.csv() function, instead of the newer read_csv() function associated with the tidyverse package. For this reason, we will not use it again.

Instead, we will select “From Text (readr)”. A new dialogue box will open; if you don’t see the data file you want, click the Browse button, navigate to the file in the window that pops up, and click Open. You should then see the first 50 rows of data and the default set of import options for the read_csv() function from the readr package (NOT the same as the read.csv() function above!). Among other differences, stringsAsFactors = FALSE is the default setting for read_csv(). You can check this in the Data Preview window by looking at the data type listed for each column: body size (character), sand (character), and Tb (double). Double-precision floating-point format (double) is a computer number format for fractional or decimal values; (integer) is for integer values. If you try to import an Excel file, you get an error message. You can, however, choose “From Excel” and it will work… however, if you have missing data (e.g., NAs), odd things may happen during the import. Basically, stick to .csv files!

Before you click the Import button, copy the associated line(s) of code in the Code Preview pane on the bottom right of the dialogue box. You’ve just told R to import the data stored in the fiddler_crab_temps.csv file, assign it to an object called fiddler_crab_temps, and show you resulting object in a new tab. Once you paste this code into your Notebook (or script), you don’t have to use the Import Dataset tool again; just run these lines of code and your data will be read in (assuming you don’t move the file, which you shouldn’t if you are using a project folder). The beauty of this approach is that now your script is complete - each time you (or anyone) runs your code, the correct data will be imported at the correct spot in the analysis. Nice!

Try that now: copy and paste the code from the Code Preview pane into the chunk below and hit Run:

library(readr)
fiddler_crab_temps <- read_csv("fiddler_crab_temps.csv")
View(fiddler_crab_temps)

But wait - you should know that while the Import Dataset button clearly worked, the associated import data code you just copied will not run unless you first load the add-on package readr. Remember that it is best to list all of the required packages for a given analysis at the beginning of your Notebook or script. You could move “library(readr)” to the first code chunk at top of this document, but as readr is part of the tidyverse package that we already loaded, doing so would be redundant.

In the interest of having clean and efficient code, there are several additional things that you can do here: delete library(readr), name the object to which the data are assigned something simpler (e.g., crab_tbs), and replace View(fiddler_crab_temps) with crab_tbs. Do this below and hit Run:

crab_tbs <- read_csv("fiddler_crab_temps.csv")
Parsed with column specification:
cols(
  `body size` = col_character(),
  sand = col_character(),
  Tb = col_double()
)
View(crab_tbs)

As you can see, the data were imported and assigned to the object “crab_tbs” (you can also provide a name for the object to which the data will be assigned in the dialogue box) and you are able to preview it in the same window. This preview is called a “tibble” - part of the tidyverse. Tibbles show only the first 10 rows, and all the columns that fit on screen; this makes it much easier to work with large data. In addition to its name, each column reports its type (e.g., in this case, character sting or double ). In general, we will work with tibbles instead of R’s traditional data.frame. Tibbles are data frames, but they tweak some older behaviours to make life a little easier. Most of the time, you can use the terms tibble and data frame interchangeably.

Alternatively, if you have your data and R Notebook or script in the same folder - as you would if you are using R Project - you can just click on the data file you want to import from the list in the Files tab of the lower left pane of RStudio (you may have to click the Update button to refresh the window). Although the book states that “you often don’t want your data in the same folder as your script;” many data scientists would suggest that is incorrect. In fact, storing all of the files in the same project folder is exactly what you want to do!

Checking that your data are your data

Now that we are ready to move on, take a moment and import the compensation.csv data into R; paste the associated code in the chunk below (but not library(readr)) and modify it to produce a tibble:

compensation <- read_csv("compensation.csv")
Parsed with column specification:
cols(
  Root = col_double(),
  Fruit = col_double(),
  Grazing = col_character()
)
View(compensation)

Once you have imported a data set, a very sensible next step is to make sure the data you got in R are actually the data you wanted. Some basic things to check are:

At this point, the book introduces several functions you can use to investigate your data: names() tells you the names assigned each column; head() returns the first six rows of the dataset (guess what tail() does?); and dim() tells you the numbers of rows and columns - the dimension - of the dataset. Perhaps the most useful function is str(), which returns the structure of the dataset, combining nearly all of the previous functions into one.

Type str(compensation) and hit Run:

str(compensation)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   40 obs. of  3 variables:
 $ Root   : num  6.22 6.49 4.92 5.13 5.42 ...
 $ Fruit  : num  59.8 61 14.7 19.3 34.2 ...
 $ Grazing: chr  "Ungrazed" "Ungrazed" "Ungrazed" "Ungrazed" ...
 - attr(*, "spec")=
  .. cols(
  ..   Root = col_double(),
  ..   Fruit = col_double(),
  ..   Grazing = col_character()
  .. )

This output looks a little different than what is shown in the book - this is because the data assigned to “compensation” are structured somewhat differently. Specifically, the grazing category in the book example is classified as factor, whereas it is a character string in the output above. Remember that read_csv() specifies stringsAsFactors = FALSE… We’ll explore the implications of these differences later.

One potentially useful feature of str() is that the column names are color-coded by data type; this makes it easier to spot when a column differs from the rest or when guessing by R leads to import with an unexpected type. Otherwise, all of this information is already available in the tibble above. The glimpse() and as_tibble() (formerly tbl_df()) functions in dplyr are also now redundant: glimpse() provides a horizontal view of the data, whereas as_tibble() provides - wait for it - a tibble.

Basic troubleshooting while importing data

At this point you know how to create a .csv file, import the associated data, and make sure you got the data in R that you wanted, using several functions. These tasks are the basic first steps in any process of quantitative problem solving, and they are the foundation. They are not optional steps. Forget these, get these wrong, and everything else will be wrong also. So focus on having rock-solid data in R. Of course, along the way, bad things will happen. The book presents several examples of different kinds of problems you might encounter; have a look at them.

Advanced activity: dealing with untidy data

As was implied above, there are lots of ways data can be untidy and it’s not possible to deal with them all now. Nevertheless, here is a somewhat typical example in which observations of the same thing (bacterial density) have been recorded on multiple dates, and the observation from each date placed in a separate column. Rows of the data correspond to experimental units (defined here by the protist species consuming the bacteria, and the environmental temperature) (another variable, Bottle, is a unique identifier for the experimental unit).

Let’s import the data (located in a file called “nasty_format.csv”), check them, and then tidy them:

The tibble above has 37 observations and 11 variables, but the experiment involved only 36 experimental units. Looking at the data on the fourth page of the tibble, or by clicking on the nasty_format text in the Rstudio Environment pane and scrolling down in the displayed data, shows there is a 37th row containing no data. This is a particular error usually caused by something odd that was done in Excel. Let’s remove that row; start by identifying what is unique about it, compared with all the other rows. Importantly, it lacks an entry in the Bottle variable. So we tell R to keep only rows that have an entry in the Bottle variable, using the filter() function in the dplyr package (more about this add-on package, and filter(), in the next chapter):

Start by asking R for help with filter() by typing ?filter() and hitting Run:

Surprise! As you can see in the Help tab in the lower left pane, there are two different functions called filter() - one in the dplyr package and another in the stats package. Luckily, we know that we are using dplyr (and that we haven’t even loaded stats), so it’s easy enough to figure out which link to click for more information. The two main arguments are .data (the tibble you want to filter) and … (logical predicates; i.e., how you want R to filter the data). The help file also provides a list of logical operators: ! indicates logical negation (NOT).

Type nasty_format <- filter(nasty_format, Bottle != ""), hit Enter and type nasty_format (to view the resulting tibble), then hit Run:

nasty_format<-filter(nasty_format,Bottle != "")
nasty_format

Problem solved! Now we make the data tidy. We need a new variable that contains the date on which observations were made, and a new variable containing the observations of bacterial abundance that are currently stored in columns 4 to 11. And then we need to move the data into these new columns. This is all very straightforward, thanks to the gather() function in the tidyr package. pivot_longer() and pivot_wider() have recently replaced the older spread() and gather() functions in tidyr, so you may eventually need to figure out how they differ, but don’t worry about it for now. Keeping on top of the continued updates and improvements to packages in R is one of the more difficult challenges to working with this platform…

Type tidy_format <- gather(data = nasty_format, Date, Abundance, 4:11), hit Enter and type tidy_format, then hit Run:

library(tidyr)
tidy_format<- gather(data=nasty_format,Date, Abundance, 4:11)
tidy_format
NA

The first argument of gather is the data frame to work on: nasty_format. The second is the name of the new variable that will contain the dates (we call it Date). The third is the name of the new variable that will contain the bacterial abundances (we call it Abundance). The fourth argument is the location in the nasty_format data frame of the observations of bacterial abundance that are to be put into the new Abundance variable. Examine the tibble above and/or use str(tidy_format) below to see if it worked:

str(tidy_format)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   288 obs. of  5 variables:
 $ Species  : chr  "P.caudatum" "P.caudatum" "P.caudatum" "P.caudatum" ...
 $ Bottle   : chr  "7-P.c" "8-P.c" "9-P.c" "22-P.c" ...
 $ Temp     : num  22 22 22 20 20 20 15 15 15 22 ...
 $ Date     : chr  "1.2.13" "1.2.13" "1.2.13" "1.2.13" ...
 $ Abundance: num  100 62.5 75 75 50 87.5 75 50 75 37.5 ...

Yes, super! We have 288 observations (36 experimental units (bottles), each observed on eight dates). We have the new Date variable, a character string-type (NOT factor-type, as the book suggests - remember that stringsAsFactors = FALSE in read_csv()) variable with eight levels, and the new Abundance variable, which is double precision numbers.

The data are now officially tidy. The Date variable still needs a bit of work, however. We need to make R recognize that these are dates (i.e. change the variable type from a character-type to a date-type variable). We do this within the mutate() function of the dplyr add-on package, which provides a neat way of changing (or adding) variables in a data frame (much more about this in the next chapter). Technically, we are going to parse the information in the date variable so that R regards it as a date. This will allow us to use the Date variable as a continuous variable, for example to make a graph with the date on the x-axis, or even to calculate the number of days, months, or years between two or more dates.

We will use a function in the lubridate package that we loaded in the first code chunk above. This package contains the functions ymd(), ydm(), dym(), dmy(), myd(), and mdy(), among others. Which of these functions should we use for our data?

Take a look at the date values by typing unique(tidy_format$Date) and hitting Run:

unique(tidy_format$Date)
[1] "1.2.13"  "2.2.13"  "3.2.13"  "4.2.13"  "6.2.13"  "8.2.13"  "10.2.13" "12.2.13"

We’ve used a bit of classic R here, the dollar sign, to refer to a variable inside a data frame. Not too much sleuthing shows that our date has the format day.month.year. So we use the function dmy(). This is a quite intelligent function, able to deal with, e.g., different separators (ours is a dot but others work) and dates that include leading zeros.

Parse the Date data into the appropriate format (day.month.year); type tidy_format <- mutate(tidy_format, Date = dmy(Date)), hit Enter and type tidy_format, then hit Run:

Date is now a date-type variable, as it should be. So what can we do now, with this tidy data? Well, imagine we want to view the dynamics of bacterial abundance in each bottle. We can now do this with very little code. ggplot2 is a powerful and flexible plotting package available as part of the tidyverse package. We will explore ggplot() in more detail in Chapter 4, but for now we will tell ggplot() the data frame to look in for variables, the x- and y-variables, to plot points, and to then produce a separate graph (i.e. facet) for each of the bottles.

Type ggplot(data = tidy_format, aes(x=Date, y=Abundance)) +, hit Enter and type geom_point() +, hit Enter and type facet_wrap(~Bottle), and then hit Run:

library(tidyverse)
ggplot(data=tidy_format, aes(x=Date,y=Abundance))+
  geom_point()+
  facet_wrap(~Bottle)

NA
NA

Separating each component of the graph building process onto its own line of code makes it easier to see what functions have been called, to modify any of the associated arguments, and to add new functions. It can also help with coding errors, as you will see exactly where any problem occurs. The resulting panel of graphs has correct dates on the x-axis, and is really useful for data exploration, or even publication after some polishing (e.g. making the x-axis tick labels legible). A panel of graphs like this would have been considerably more hassle to make if the data were not tidy, i.e. if the data were left as they were in the data file, with one variable for each date.

Functions for dealing with messy data

As we mentioned, there are many ways in which data can be untidy and messy. Fortunately, there are lots of nice functions for dealing with untidy and messy data. In the base, tidyr, and dplyr packages there are (in addition to the ones we’ve already seen):

You will probably find that tidying data, especially data that you didn’t prepare, can take a lot of time and effort. However, it’s investment well made, as having tidy and clean data makes everything following ten times easier. We’ve used functions from several add-on packages: tidyr, lubridate, dplyr, and ggplot2. It would be well worth your while to review these, and make notes about which functions we used from each of these packages, why we used them, and the associated arguments.

Wrapping up

Save your file and exit the R session.

LS0tDQp0aXRsZTogIkNoYXB0ZXIgMiBHZXR0aW5nIFlvdXIgRGF0YSBJbnRvIFIiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0DQotLS0NCg0KIyMjIFByZWZhY2UNClRoaXMgaXMgYW4gaW50ZXJhY3RpdmUgW1IgTWFya2Rvd25dKGh0dHA6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20pIE5vdGVib29rIGZpbGUgdGhhdCBmb2xsb3dzIENoYXB0ZXIgMiBvZiBbKkdldHRpbmcgc3RhcnRlZCB3aXRoIFI6IGFuIGludHJvZHVjdGlvbiBmb3IgYmlvbG9naXN0cywgMm5kIGVkaXRpb24qXShodHRwOi8vcjRhbGwub3JnLykgYnkgQW5kcmV3IFAuIEJlY2tlcm1hbiwgRHlsYW4gWi4gQ2hpbGRzLCBhbmQgT3dlbiBMLiBQZXRjaGV5Lg0KDQpUaGUgZmlyc3QgdGhpbmcgeW91IHNob3VsZCBkbyBpcyBjbGljayAqRmlsZSosIGFuZCB0aGVuICpTYXZlIEFzKiBvbiB0aGUgbWVudSBiYXIgYWJvdmUgYW5kIHJlbmFtZSB0aGUgZmlsZSAiWW91ciBMYXN0IE5hbWVfY2gyLlJtZCINCg0KIyMjIExlYXJuaW5nIG9iamVjdGl2ZXMNCkJ5IHRoZSBlbmQgb2YgdGhpcyB0dXRvcmlhbCwgeW91IHdpbGwgYmUgYWJsZSB0bzoNCg0KKiBEZWZpbmUgdGlkeSBkYXRhOw0KDQoqIFByZXBhcmUgeW91ciBkYXRhIHRvIGltcG9ydCBpbnRvIFIsIGluY2x1ZGluZyBzYXZpbmcgaXQgYXMgYSAuY3N2IGZpbGU7DQoNCiogSW1wb3J0IHlvdXIgZGF0YSBpbnRvIFIgdXNpbmcgb25lIG9mIHNldmVyYWwgcG9zc2libGUgbWV0aG9kczsNCg0KKiBDaGVjayB0aGF0IHlvdXIgZGF0YSB3ZXJlIGNvcnJlY3RseSBpbXBvcnRlZCwgYW5kIHRyb3VibGVzaG9vdCBjb21tb24gcHJvYmxlbXMgaWYgdGhleSB3ZXJlIG5vdDsNCg0KKiBMaXN0IGRpZmZlcm50IGZ1bmN0aW9ucyBpbiB0aGUgXyoqZHBseXIqKl8gcGFja2FnZSB0aGF0IGNhbiBiZSB1c2VkIHRvIGRlYWwgd2l0aCBtZXNzeSBkYXRhLg0KDQojIyMgTG9hZCBwYWNrYWdlcw0KQXQgdGhlIGJlZ2lubmluZyBvZiBldmVyeSBOb3Rib29rIG9yIHNjcmlwdCwgbG9hZCB0aGUgc3BlY2lmaWMgYWRkLW9uIHBhY2thZ2VzIHlvdSB3aWxsIG5lZWQgZm9yIHRoYXQgYW5hbHlzaXMgaW50byBSLg0KDQpXZSB3aWxsIG5lZWQgdGhlIF8qKnRpZHl2ZXJzZSoqXyBhbmQgXyoqbHVicmlkYXRlKipfIHBhY2thZ2VzOyBpbiB0aGUgY29kZSBjaHVuayBiZWxvdywgdHlwZSBsaWJyYXJ5KHRpZHl2ZXJzZSksIGhpdCBFbnRlciBhbmQgdHlwZSBsaWJyYXJ5KGx1YnJpZGF0ZSksIHRoZW4gaGl0IFJ1bjoNCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KGRwbHlyKQ0KYGBgDQoNCiMjIyBUaWR5IGRhdGENCj7igJxIYXBweSBmYW1pbGllcyBhcmUgYWxsIGFsaWtlOyBldmVyeSB1bmhhcHB5IGZhbWlseSBpcyB1bmhhcHB5IGluIGl0cyBvd24gd2F5LuKAnSDigJPigJMgTGVvIFRvbHN0b3kgKGF1dGhvciBvZiBbKkFubmEgS2FyZW5pbmEqXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Bbm5hX0thcmVuaW5hKSkNCg0KPuKAnFRpZHkgZGF0YXNldHMgYXJlIGFsbCBhbGlrZSwgYnV0IGV2ZXJ5IG1lc3N5IGRhdGFzZXQgaXMgbWVzc3kgaW4gaXRzIG93biB3YXku4oCdIOKAk+KAkyBbSGFkbGV5IFdpY2toYW1dKGh0dHA6Ly9oYWRsZXkubnovKSAoQ2hpZWYgU2NpZW50aXN0IGF0IFJTdHVkaW8pDQoNCkFzIGluIG11Y2ggb2YgbGlmZSwgY2FyZWZ1bCBwcmVwYXJhdGlvbiBpcyB0aGUga2V5IHRvIGdvb2QgcmVzdWx0cy4gUiBsaWtlcyBkYXRhIGluIHdoaWNoIHRoZXJlIGlzIG9uZSBvYnNlcnZhdGlvbiBpbiBhIHJvdywgYW5kIGVhY2ggdmFyaWFibGUgaXMgcmVwcmVzZW50ZWQgYnkgaXRzIG93biBjb2x1bW4uIFN1Y2ggZGF0YSBpcyBjYWxsZWQgImxvbmcgZm9ybWF0IiBvciAidGlkeSBkYXRhIi4gR2V0dGluZyB5b3VyIGRhdGEgaW50byB0aGlzIGZvcm1hdCByZXF1aXJlcyBzb21lIHVwZnJvbnQgd29yaywgYnV0IHRoYXQgd29yayBwYXlzIG9mZiBpbiB0aGUgbG9uZyB0ZXJtLiBPbmNlIHlvdSBoYXZlIHRpZHkgZGF0YSBhbmQgdGhlIHRpZHkgdG9vbHMgcHJvdmlkZWQgYnkgcGFja2FnZXMgaW4gdGhlIHRpZHl2ZXJzZSwgeW91IHdpbGwgc3BlbmQgbXVjaCBsZXNzIHRpbWUgbXVuZ2luZyBkYXRhIGZyb20gb25lIHJlcHJlc2VudGF0aW9uIHRvIGFub3RoZXIsIGFsbG93aW5nIHlvdSB0byBzcGVuZCBtb3JlIHRpbWUgb24gdGhlIGFuYWx5dGljIHF1ZXN0aW9ucyBhdCBoYW5kLg0KDQojIyMgR2V0dGluZyBkYXRhIHJlYWR5IGZvciBSDQpMZXQncyB0YWtlIGEgbG9vayBhdCBhIHNhbXBsZSBkYXRhIHNoZWV0IGluIEV4Y2VsIChvciBzb21lIG90aGVyIHNwcmVhZHNoZWV0IHNvZnR3YXJlLCBlLmcuIFtHb29nbGUgRG9jc10oaHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS9kb2NzL2Fib3V0Lykgb3IgW0xpYnJlT2ZmaWNlXShodHRwczovL3d3dy5saWJyZW9mZmljZS5vcmcvKSkuIE9wZW4gdGhlIGZpbGUgY2FsbGVkICdmaWRkbGVyX2NyYWJfdGVtcHMueGxzeCcgYnkgY2xpY2tpbmcgb24gdGhlIGZpbGUgbmFtZSBpbiB0aGUgKkZpbGVzKiB0YWIgaW4gdGhlIGxvd2VyIHJpZ2h0IHBhbmUsIGFuZCB0aGVuICpWaWV3IEZpbGUqLg0KDQpUaGVzZSBwYXJ0aWN1bGFyIGRhdGEgYXJlIHRoZSBib2R5IHRlbXBlcmF0dXJlcyAoKlQqYnMpIHNlbGVjdGVkIGJ5IGZpZGRsZXIgY3JhYnMgaW4gYSBsYWJvcmF0b3J5IHRoZXJtYWwgZ3JhZGllbnQ7IHNtYWxsIGFuZCBsYXJnZSBjcmFicyB3ZXJlIHRlc3RlZCBvbiBlaXRoZXIgd2V0IG9yIGRyeSBzYW5kLiBGb3IgY29tcGxldGUgZGV0YWlscyBvZiB0aGUgc3R1ZHksIHNlZSB0aGUgYXNzb2NpYXRlZCBwdWJsaWNhdGlvbjogQWxsZW4gZXQgYWwuIDIwMTIgSiBFeHAgTWFyIEJpb2wgRWNvbC5wZGYsIGFsc28gYXZhaWxhYmxlIGluIHRoZSBmaWxlIGxpc3QuIE5vdGUgdGhhdCB0aGUgY29sdW1uIG5hbWVzIGFyZSBpbmZvcm1hdGl2ZSwgYnJpZWYsIGFuZCBzaW1wbGUuIEluIGdlbmVyYWwsIGl0IGlzIGJlc3Qgbm90IHRvIHVzZSBzcGFjZXMgb3Igc3BlY2lhbCBzeW1ib2xzLCB3aGljaCBSIGNhbiBkZWFsIHdpdGggYnV0IG1heSBub3QgZG8gc28gcGFydGljdWxhcmx5IHdlbGwuIEFsc28sIGdpdmVuIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyBzdWNoIGFzIHNleCAobWFsZSwgZmVtYWxlKSwgaXQgaXMgYmVzdCB0byB1c2UgdGhlIGFjdHVhbCBjYXRlZ29yeSBuYW1lcyByYXRoZXIgdGhhbiBjb2RlcyBmb3IgdGhlbSAoZS5nLiBkb27igJl0IHVzZSAxID0gbWFsZSwgMiA9IGZlbWFsZSkuIFIgY2FuIGVhc2lseSBkZWFsIHdpdGggdmFyaWFibGVzIHRoYXQgY29udGFpbiB3b3JkcyAoc28tY2FsbGVkIGNoYXJhY3RlciBzdHJpbmdzKSwgYW5kIHRoaXMgd2lsbCBtYWtlIHN1YnNlcXVlbnQgdGFza3MgaW4gUiBtdWNoIG1vcmUgZWZmaWNpZW50IGFuZCByZWxpYWJsZS4NCg0KQWxsIGNlbGxzIGluIGEgZGF0YSBzaGVldCBzaG91bGQgaGF2ZSBhbiBlbnRyeSwgZXZlbiBpZiBpdCBpcyBzb21ldGhpbmcgc2F5aW5nICJubyBvYnNlcnZhdGlvbiB3YXMgbWFkZSIuIFRoZSBleHBlY3RlZCBwbGFjZWhvbGRlciBmb3IgbWlzc2luZyBkYXRhIGluIFIgaXMgTkEgKGUuZy4sIHNlZSB0aGUgdGhpcmQgb2JzZXJ2YXRpb24gbGlzdGVkIGluIHRoZSBmaWRkbGVyIGNyYWIgZGF0YSBzZXQpLiBPdGhlciBvcHRpb25zIGFyZSBwb3NzaWJsZSwgYnV0IG5vdCByZWNvbW1lbmRlZCAtIGEgYmxhbmsgY2VsbCBpcyBhbWJpZ3VvdXM6IHBlcmhhcHMgbm90aGluZyB3YXMgc2VlbiBpbiB0aGF0IGluc3RhbmNlIChpbiB3aGljaCBjYXNlIGEgemVybyBzaG91bGQgYmUgdXNlZCB0byBpbmRpY2F0ZSBhbiBhY3R1YWwgbnVsbCB2YWx1ZSksIG9yIHBlcmhhcHMgbm8gb2JzZXJ2YXRpb24gd2FzIG1hZGUgZm9yIHdoYXRldmVyIHJlYXNvbi4gDQoNCkFsdGhvZ2ggRXhjZWwgaGFzIG1hbnkgZmVhdHVyZXMgdGhhdCBtYWtlIGl0IGNvbnZlbmllbnQgdG8gb3JnYW5pemUgYW5kIGRpc3BsYXkgZGF0YSwgbW9zdCBkYXRhIHNjaWVudGlzdHMgd291bGQgYXJndWUgdGhhdCB5b3Ugc2hvdWxkIGNvbnZlcnQgeW91ciAueGxzIG9yIC54bHN4IGZpbGUgdG8gYSAiY29tbWEtc2VwYXJhdGVkIHZhbHVlcyIgKC5jc3YpIGZpbGUgYmVmb3JlIHRyeWluZyB0byBpbXBvcnQgaXQgaW50byBSLiBBIC5jc3YgZmlsZSBpcyBlYXNpbHkgdHJhbnNwb3J0ZWQgd2l0aCBhIGxvdyBtZW1vcnkgYW5kIHNtYWxsIHNpemUgZm9vdHByaW50IGFtb25nIGNvbXB1dGluZyBwbGF0Zm9ybXMuIEluIEV4Y2VsLCBvciBvdGhlciBzcHJlYWRzaGVldCBwcm9ncmFtcywgYWZ0ZXIgeW91IGNsaWNrICpTYXZlIEFzKiB5b3UgY2FuIGNoYW5nZSB0aGUgZm9ybWF0IG9mIHRoZSBmaWxlIHRvICJjb21tYS1zZXBhcmF0ZWQgdmFsdWVzIiAoc29tZXRpbWVzIGFsc28gY2FsbGVkICJjb21tYSBkZWxpbWl0ZWQiKSwgdGhlbiBwcmVzcyAqU2F2ZSouIEV4Y2VsIG1pZ2h0IHRoZW4sIG9yIHdoZW4geW91IGNsb3NlIHRoZSBmaWxlLCBhc2sgaWYgeW914oCZcmUgc3VyZSB5b3XigJlkIGxpa2UgdG8gc2F2ZSB5b3VyIGRhdGEgaW4gdGhpcyBmb3JtYXQuIFllcywgeW91IGFyZSBzdXJlISBOb3RlIHRoYXQgeW91IGNhbiBvbmx5IHNhdmUgYSBzaW5nbGUgd29ya3NoZWV0IGluIGEgLmNzdiBmaWxlLCBzbyBpZiB5b3UgaGF2ZSB5b3VyIGRhdGEgb3JnYW5pemVkIGFzIG11bHRpcGxlIHdvcmtzaGVldHMgaW4gRXhjZWwsIHlvdSB3aWxsIG5lZWQgdG8gY3JlYXRlIGEgc2VwYXJhdGUgLmNzdiBmaWxlIGZvciBlYWNoLiBZb3Ugd2lsbCBhbHNvIGxvc2UgYW55IGZvcm1hdGluZyBpbiB0aGUgd29ya3NoZWV0cyAoZS5nLiwgYm9sZGluZywgY2VudGVyaW5nLCBoaWdobGlnaHRpbmcsIGV0Yy4pLiBEbyB0aGF0IG5vdyAtIHVzZSAqU2F2ZSBBcyogdG8gc2F2ZSB0aGUgZmlkZGxlciBjcmFiIGRhdGEgYXMgImZpZGRsZXJfY3JhYl9kYXRhLmNzdiIgaW4gdGhlIHNhbWUgZm9sZGVyIGFzIHRoZSBvdGhlciBmaWxlcy4NCg0KT25lIG9mIHRoZSByZW1hcmthYmxlIHRoaW5ncyBhYm91dCBSIGlzIHRoYXQgb25jZSBhIGNvcHkgb2YgeW91ciAicmF3IGRhdGEiIGlzIGVzdGFibGlzaGVkLCB0aGUgdXNlIG9mIFIgZm9yIGRhdGEgdmlzdWFsaXphdGlvbiBhbmQgYW5hbHlzaXMgd2lsbCBuZXZlciByZXF1aXJlIHlvdSB0byBhbHRlciB0aGUgb3JpZ2luYWwgZmlsZSAodW5sZXNzIHlvdSBjb2xsZWN0IG1vcmUgZGF0YSEpLiBXaXRoIFIsIHlvdXIgb3JpZ2luYWwgZGF0YSBmaWxlIGNhbiBhbmQgbXVzdCBhbHdheXMgcmVtYWluIHVubWFuaXB1bGF0ZWQ7IGlmIGFueSBhZGp1c3RtZW50cyBkbyBvY2N1ciwgdGhleSBvY2N1ciBpbiBhbiBSIGNvcHkgb25seSBhbmQgb25seSB2aWEgeW91ciBleHBsaWNpdCBpbnN0cnVjdGlvbnMgaGFyYm91cmVkIGluIHRoZSBzY3JpcHQuDQoNCklkZWFsbHksIHlvdXIgZGF0YSB3aWxsIGJlIHRpZHkgYmVmb3JlIHlvdSBldmVyIHRyeSB0byBpbXBvcnQgdGhlbSBpbnRvIFIuIElmIHlvdXIgZGF0YSBhcmUgbm90IHRpZHkgdG8gc3RhcnQgd2l0aCwgeW91IGNhbiBvZiBjb3Vyc2UgcmVhcnJhbmdlIHRoZW0gaW4gRXhjZWwuIFRoaXMgY2FuLCBob3dldmVyLCBjYXVzZSBlcnJvcnMsIGJlIGF3ZnVsbHkgdGltZS1jb25zdW1pbmcsIGFuZCBpcyB0ZWRpb3VzIGFuZCBib3JpbmcgZm9yIGJpZyBkYXRhc2V0cy4gVGhlIGFsdGVybmF0aXZlIGlzIHRvIGRvIGl0IGluIFI7IHdlJ2xsIHByYWN0aWNlIHRoYXQgc2hvcnRseS4NCg0KIyMjIFByb2plY3Qtb3JpZW50ZWQgd29ya2Zsb3cNCllvdSBzaG91bGQgZ2VuZXJhbGx5IHBsYW4gdG8gb3JnYW5pemUgZWFjaCBzZXBhcmF0ZSBkYXRhIGFuYWx5c2lzIGludG8gYSBwcm9qZWN0OiBhIGZvbGRlciBvbiB5b3VyIGNvbXB1dGVyIHRoYXQgaG9sZHMgYWxsIHRoZSBmaWxlcyByZWxldmFudCB0byB0aGF0IHBhcnRpY3VsYXIgcGllY2Ugb2Ygd29yaywgc3RhcnRpbmcgd2l0aCB0aGUgLmNzdiBkYXRhIGZpbGUuIEFueSBhc3NvY2lhdGVkIFIgc2NyaXB0IHNob3VsZCBiZSB3cml0dGVuIGFzc3VtaW5nIHRoYXQgaXQgd2lsbCBiZSBydW4gZnJvbSBhIGZyZXNoIFIgcHJvY2Vzcy9zZXNzaW9uLCB3aXRoIHRoZSB3b3JraW5nIGRpcmVjdG9yeSAodGhlIGxvY2F0aW9uIG9uIHlvdXIgY29tcHV0ZXIgd2hlcmUgUiB3aWxsIGxvb2sgZm9yIGZpbGVzIHRvIG9wZW4gb3Igc2F2ZSkgc2V0IHRvIHRoZSBwcm9qZWN0IGRpcmVjdG9yeSAobWFpbiBmb2xkZXIpLiBZb3UgY2FuIHRoZW4gY3JlYXRlIHN1Yi1mb2xkZXJzIGZvciBzcGVjaWZpYyB0eXBlcyBvZiBmaWxlcywgc3VjaCBhcyBkYXRhLCBmaWd1cmVzLCBmdW5jdGlvbiBmaWxlcywgYW5kIG1hbnVzY3JpcHRzLiBVc2luZyBhIGNvbnNpc3RlbnQgZm9sZGVyIHN0cnVjdHVyZSBhbmQgZmlsZSBuYW1pbmcgc3lzdGVtIGFjcm9zcyBwcm9qZWN0cyBtYWtlcyBpdCBlYXNpZXIgdG8gbmF2aWdhdGUgdGhlIHByb2plY3QgY29udGVudHMsIHJlc3VtZSB3b3JrIGFmdGVyIGEgaGlhdHVzLCBhbmQgcmUtdXNlIGNvZGUgaW4gbXVsdGlwbGUgcHJvamVjdHMuDQoNClJldmlzaXRpbmcgSmVubnkgQnJ5YW4ncyBwb3N0IG9uIFtwcm9qZWN0LW9yaWVudGVkIHdvcmtmbG93XShodHRwczovL3d3dy50aWR5dmVyc2Uub3JnL2FydGljbGVzLzIwMTcvMTIvd29ya2Zsb3ctdnMtc2NyaXB0LyksIHRoaXMgd29yayBzdHlsZSBpcyBzbyBjcnVjaWFsIHRoYXQgUlN0dWRpbyBoYXMgYW4gb2ZmaWNpYWwgbm90aW9uIG9mIGEgWypQcm9qZWN0Kl0oaHR0cHM6Ly9zdXBwb3J0LnJzdHVkaW8uY29tL2hjL2VuLXVzL2FydGljbGVzLzIwMDUyNjIwNy1Vc2luZy1Qcm9qZWN0cykgKHdpdGggYSBjYXBpdGFsIOKAnFDigJ0pLiBZb3UgY2FuIGRlc2lnbmF0ZSBhIG5ldyBvciBleGlzdGluZyBmb2xkZXIgYXMgYSBQcm9qZWN0LiBBbGwgdGhpcyBtZWFucyBpcyB0aGF0IFJTdHVkaW8gbGVhdmVzIGEgZmlsZSwgZS5nLiwgZm9vZnkuUnByb2osIGluIHRoZSBmb2xkZXIsIHdoaWNoIGlzIHVzZWQgdG8gc3RvcmUgc2V0dGluZ3Mgc3BlY2lmaWMgdG8gdGhhdCBwcm9qZWN0LiBEb3VibGUtY2xpY2sgb24gYSAuUnByb2ogZmlsZSB0byBvcGVuIGEgZnJlc2ggaW5zdGFuY2Ugb2YgUlN0dWRpbywgd2l0aCB0aGUgd29ya2luZyBkaXJlY3RvcnkgYW5kIGZpbGUgYnJvd3NlciBwb2ludGVkIGF0IHRoZSBwcm9qZWN0IGZvbGRlci4gVGhpcyBjb252ZW50aW9uIGd1YXJhbnRlZXMgdGhhdCB0aGUgcHJvamVjdCBjYW4gYmUgbW92ZWQgYXJvdW5kIG9uIHlvdXIgY29tcHV0ZXIgb3Igb250byBvdGhlciBjb21wdXRlcnMgYW5kIHdpbGwgc3RpbGwg4oCcanVzdCB3b3Jr4oCdLiBSU3R1ZGlvIGZ1bGx5IHN1cHBvcnRzIFByb2plY3QtYmFzZWQgd29ya2Zsb3dzLCBtYWtpbmcgaXQgZWFzeSB0byBzd2l0Y2ggZnJvbSBvbmUgdG8gYW5vdGhlciwgaGF2ZSBtYW55IHByb2plY3RzIG9wZW4gYXQgb25jZSwgcmUtbGF1bmNoIHJlY2VudGx5IHVzZWQgUHJvamVjdHMsIGV0Yy4gWW91IGNhbiBjcmVhdGUgYW4gUlN0dWRpbyBwcm9qZWN0IGVpdGhlciBpbiBhIGJyYW5kIG5ldyBkaXJlY3Rvcnkgb3IgYW4gZXhpc3RpbmcgZGlyZWN0b3J5IHdoZXJlIHlvdSBhbHJlYWR5IGhhdmUgUiBjb2RlIGFuZCBkYXRhLCBieSBjbGlja2luZyAqRmlsZSosIGFuZCB0aGVuICpOZXcgUHJvamVjdCogb3IgdGhlICJDcmVhdGUgYSBQcm9qZWN0IiBidXR0b24gb24gdGhlIHRvb2xiYXIgYWJvdmUuIEFsdGhvdWdoIG5laXRoZXIgbmV3LCBub3IgdW5pcXVlIHRvIFIsIHRoaXMgaXMgYXJndWFibHkgdGhlIG9ubHkgcHJhY3RpY2FsIGFwcHJvYWNoIHRoYXQgY3JlYXRlcyByZWxpYWJsZSwgcG9saXRlIGJlaGF2aW9yIGFjcm9zcyBkaWZmZXJlbnQgY29tcHV0ZXJzIG9yIHVzZXJzIGFuZCBvdmVyIHRpbWUuIA0KDQpBbGwgb2Ygd2hpY2ggaXMgdG8gc2F5IHRoYXQgaWYgeW91IG9yZ2FuaXplIHlvdXIgUiBsaWZlIGFyb3VuZCBhIHByb2plY3Qtb3JpZW50ZWQgd29ya2Zsb3csIHlvdSBjYW4gaWdub3JlIGFsbCBjb25jZXJucyBhYm91dCBzZXR0aW5nIHRoZSB3b3JraW5nIGRpcmVjdG9yeSBhbmQgc3BlY2lmeWluZyBmaWxlIHBhdGhzLiANCg0KIyMjIEdldHRpbmcgeW91ciBkYXRhIGludG8gUg0KSW4gdGhlIG5leHQgZmV3IHNlY3Rpb25zLCB3ZSB3aWxsIHdvcmsgd2l0aCBzZXZlcmFsIGRhdGFzZXRzIGFscmVhZHkgaW4gdGhlIHByb2plY3QgZm9sZGVyIChhbHNvIGF2YWlsYWJsZSBmb3IgZG93bmxvYWQgYXMgYSB6aXAgZmlsZSBhdCB0aGUgW2NvbXBhbmlhbiB3ZWJzaXRlXShodHRwOi8vcjRhbGwub3JnL2Jvb2tzL2RhdGFzZXRzLykgZm9yIHRoZSBib29rKS4gVGhlcmUgYXJlIGF0IGxlYXN0IGZvdXIgcmVhbGx5IGVhc3kgd2F5cyB0byBnZXQgUiB0byBpbXBvcnQgdGhlIGRhdGEsIHdpdGhvdXQgaGF2aW5nIHRvIGRvIGFueXRoaW5nIHRyaWNreSBsaWtlIHR5cGUgdGhlIHBhdGggdG8geW91ciBkYXRhIGZpbGU7IGhvd2V2ZXIsIHdlIGFyZSBnb2luZyB0byBmb2N1cyBvbiBqdXN0IHR3bzoNCg0KUnN0dWRpbyBwcm92aWRlcyBtZW51LWJhc2VkIGltcG9ydCBmdW5jdGlvbmFsaXR5IHZpYSB0aGUgKkltcG9ydCBEYXRhc2V0KiBidXR0b24gb24gdGhlIEVudmlyb25tZW50IHRhYiBpbiB0aGUgdXBwZXIgcmlnaHQgcGFuZSBvZiBSU3R1ZGlvLiBUaGlzIHdpbGwgYWxsb3cgeW91IHRvIG5hdmlnYXRlIHRvIHlvdXIgZGF0YSBmaWxlLCBzZWxlY3QgaXQsIGFuZCBjbGljayB0aGUgKk9wZW4qIGJ1dHRvbi4gR2l2ZW4gb3VyIGZvY3VzIG9uIC5jc3YgZmlsZXMsIHNlbGVjdCAiRnJvbSBUZXh0IChiYXNlKSIgYXMgeW91ciBvcHRpb24uIEEgd2luZG93IHdpbGwgb3BlbiB3aXRoIGEgbGlzdCBvZiBhbGwgdGhlIGZpbGVzIGluIHRoaXMgcGFydGljdWxhciBwcm9qZWN0IGZvbGRlciBjaG9vc2UgZmlkZGxlcl9jcmFiX3RlbXBzLmNzdiBhbmQgY2xpY2sgT3Blbi4gQSBuZXcgZGlhbG9ndWUgYm94IHdpbGwgZGlzcGxheWluZyB0aGUgZmlyc3QgMjAgcm93cyBvZiBkYXRhIGFuZCB0aGUgZGVmYXVsdCBzZXQgb2YgaW1wb3J0IG9wdGlvbnMgZm9yIHRoZSByZWFkLmNzdigpIGZ1bmN0aW9uOyBub3RlIGZvciB0aGUgZnV0dXJlIHRoYXQgdGhlIG9wdGlvbiAiU3RyaW5ncyBhcyBmYWN0b3JzIiBpcyBjaGVja2VkIC0gdGhhdCBtZWFucyB0aGF0IFIgd2lsbCBjb252ZXJ0IGNvbHVtbnMgdGhhdCBhcmUgZGV0ZWN0ZWQgdG8gYmUgY2hhcmFjdGVyIHN0cmluZ3MgKGkuZS4sIHdvcmRzKSB0byBiZSBmYWN0b3IgdmFyaWFibGVzLiBTbyBhIHZhcmlhYmxlIGxpa2UgInNtYWxsIG9yIGxhcmdlIiB3aWxsIGJlIGVuY29kZWQgYXMgIjEgb3IgMiIsIHdoZXJlIGVhY2ggbnVtYmVyIHJlcHJlc2VudHMgYSBkaWZmZXJlbnQgbGV2ZWwgb2YgdGhlIGZhY3Rvci4gQWx0aG91Z2ggdGhpcyBjYW4gYmUgdXNlZnVsIGZvciBzdGF0aXN0aWNhbCBtb2RlbGluZywgaXQgY2FuIGJlIHByb2JsZW1hdGljIGluIG90aGVyIGNvbnRleHRzOyBtb3N0IG5ld2VyIFIgcGFja2FnZXMgKGUuZy4sIF8qKnRpZHl2ZXJzZSoqXykgbm8gbG9uZ2VyIGhhdmUgc3RyaW5nc0FzRmFjdG9ycyA9IFRSVUUgYXMgdGhlIGRlZmF1bHQgc2V0dGluZy4gVGhpcyBpbXBvcnQgcGF0aHdheSByZWxpZXMgb24gdGhlICoqcmVhZC5jc3YqKigpIGZ1bmN0aW9uLCBpbnN0ZWFkIG9mIHRoZSBuZXdlciAqKnJlYWRfY3N2KiooKSBmdW5jdGlvbiBhc3NvY2lhdGVkIHdpdGggdGhlIF8qKnRpZHl2ZXJzZSoqXyBwYWNrYWdlLiBGb3IgdGhpcyByZWFzb24sIHdlIHdpbGwgbm90IHVzZSBpdCBhZ2Fpbi4NCg0KSW5zdGVhZCwgd2Ugd2lsbCBzZWxlY3QgIkZyb20gVGV4dCAocmVhZHIpIi4gQSBuZXcgZGlhbG9ndWUgYm94IHdpbGwgb3BlbjsgaWYgeW91IGRvbid0IHNlZSB0aGUgZGF0YSBmaWxlIHlvdSB3YW50LCBjbGljayB0aGUgKkJyb3dzZSogYnV0dG9uLCBuYXZpZ2F0ZSB0byB0aGUgZmlsZSBpbiB0aGUgd2luZG93IHRoYXQgcG9wcyB1cCwgYW5kIGNsaWNrICpPcGVuKi4gWW91IHNob3VsZCB0aGVuIHNlZSB0aGUgZmlyc3QgNTAgcm93cyBvZiBkYXRhIGFuZCB0aGUgZGVmYXVsdCBzZXQgb2YgaW1wb3J0IG9wdGlvbnMgZm9yIHRoZSAqKnJlYWRfY3N2KiooKSBmdW5jdGlvbiBmcm9tIHRoZSBfKipyZWFkcioqXyBwYWNrYWdlIChOT1QgdGhlIHNhbWUgYXMgdGhlICoqcmVhZC5jc3YqKigpIGZ1bmN0aW9uIGFib3ZlISkuIEFtb25nIG90aGVyIGRpZmZlcmVuY2VzLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UgaXMgdGhlIGRlZmF1bHQgc2V0dGluZyBmb3IgKipyZWFkX2NzdioqKCkuIFlvdSBjYW4gY2hlY2sgdGhpcyBpbiB0aGUgRGF0YSBQcmV2aWV3IHdpbmRvdyBieSBsb29raW5nIGF0IHRoZSBkYXRhIHR5cGUgbGlzdGVkIGZvciBlYWNoIGNvbHVtbjogYm9keSBzaXplIChjaGFyYWN0ZXIpLCBzYW5kIChjaGFyYWN0ZXIpLCBhbmQgKlQqYiAoZG91YmxlKS4gRG91YmxlLXByZWNpc2lvbiBmbG9hdGluZy1wb2ludCBmb3JtYXQgKGRvdWJsZSkgaXMgYSBjb21wdXRlciBudW1iZXIgZm9ybWF0IGZvciBmcmFjdGlvbmFsIG9yIGRlY2ltYWwgdmFsdWVzOyAoaW50ZWdlcikgaXMgZm9yIGludGVnZXIgdmFsdWVzLiBJZiB5b3UgdHJ5IHRvIGltcG9ydCBhbiBFeGNlbCBmaWxlLCB5b3UgZ2V0IGFuIGVycm9yIG1lc3NhZ2UuIFlvdSBjYW4sIGhvd2V2ZXIsIGNob29zZSAiRnJvbSBFeGNlbCIgYW5kIGl0IHdpbGwgd29yay4uLiBob3dldmVyLCBpZiB5b3UgaGF2ZSBtaXNzaW5nIGRhdGEgKGUuZy4sIE5BcyksIG9kZCB0aGluZ3MgbWF5IGhhcHBlbiBkdXJpbmcgdGhlIGltcG9ydC4gQmFzaWNhbGx5LCBzdGljayB0byAuY3N2IGZpbGVzIQ0KDQpCZWZvcmUgeW91IGNsaWNrIHRoZSAqSW1wb3J0KiBidXR0b24sIGNvcHkgdGhlIGFzc29jaWF0ZWQgbGluZShzKSBvZiBjb2RlIGluIHRoZSAqQ29kZSBQcmV2aWV3KiBwYW5lIG9uIHRoZSBib3R0b20gcmlnaHQgb2YgdGhlIGRpYWxvZ3VlIGJveC4gWW91J3ZlIGp1c3QgdG9sZCBSIHRvIGltcG9ydCB0aGUgZGF0YSBzdG9yZWQgaW4gdGhlIGZpZGRsZXJfY3JhYl90ZW1wcy5jc3YgZmlsZSwgYXNzaWduIGl0IHRvIGFuIG9iamVjdCBjYWxsZWQgZmlkZGxlcl9jcmFiX3RlbXBzLCBhbmQgc2hvdyB5b3UgcmVzdWx0aW5nIG9iamVjdCBpbiBhIG5ldyB0YWIuIE9uY2UgeW91IHBhc3RlIHRoaXMgY29kZSBpbnRvIHlvdXIgTm90ZWJvb2sgKG9yIHNjcmlwdCksIHlvdSBkb27igJl0IGhhdmUgdG8gdXNlIHRoZSBJbXBvcnQgRGF0YXNldCB0b29sIGFnYWluOyBqdXN0IHJ1biB0aGVzZSBsaW5lcyBvZiBjb2RlIGFuZCB5b3VyIGRhdGEgd2lsbCBiZSByZWFkIGluIChhc3N1bWluZyB5b3UgZG9u4oCZdCBtb3ZlIHRoZSBmaWxlLCB3aGljaCB5b3Ugc2hvdWxkbid0IGlmIHlvdSBhcmUgdXNpbmcgYSBwcm9qZWN0IGZvbGRlcikuIFRoZSBiZWF1dHkgb2YgdGhpcyBhcHByb2FjaCBpcyB0aGF0IG5vdyB5b3VyIHNjcmlwdCBpcyBjb21wbGV0ZSAtIGVhY2ggdGltZSB5b3UgKG9yIGFueW9uZSkgcnVucyB5b3VyIGNvZGUsIHRoZSBjb3JyZWN0IGRhdGEgd2lsbCBiZSBpbXBvcnRlZCBhdCB0aGUgY29ycmVjdCBzcG90IGluIHRoZSBhbmFseXNpcy4gTmljZSENCg0KVHJ5IHRoYXQgbm93OiBjb3B5IGFuZCBwYXN0ZSB0aGUgY29kZSBmcm9tIHRoZSBDb2RlIFByZXZpZXcgcGFuZSBpbnRvIHRoZSBjaHVuayBiZWxvdyBhbmQgaGl0IFJ1bjoNCmBgYHtyfQ0KbGlicmFyeShyZWFkcikNCmZpZGRsZXJfY3JhYl90ZW1wcyA8LSByZWFkX2NzdigiZmlkZGxlcl9jcmFiX3RlbXBzLmNzdiIpDQpWaWV3KGZpZGRsZXJfY3JhYl90ZW1wcykNCmBgYA0KDQpCdXQgd2FpdCAtIHlvdSBzaG91bGQga25vdyB0aGF0IHdoaWxlIHRoZSAqSW1wb3J0IERhdGFzZXQqIGJ1dHRvbiBjbGVhcmx5IHdvcmtlZCwgdGhlIGFzc29jaWF0ZWQgaW1wb3J0IGRhdGEgY29kZSB5b3UganVzdCBjb3BpZWQgd2lsbCBub3QgcnVuIHVubGVzcyB5b3UgZmlyc3QgbG9hZCB0aGUgYWRkLW9uIHBhY2thZ2UgXyoqcmVhZHIqKl8uIFJlbWVtYmVyIHRoYXQgaXQgaXMgYmVzdCB0byBsaXN0IGFsbCBvZiB0aGUgcmVxdWlyZWQgcGFja2FnZXMgZm9yIGEgZ2l2ZW4gYW5hbHlzaXMgYXQgdGhlIGJlZ2lubmluZyBvZiB5b3VyIE5vdGVib29rIG9yIHNjcmlwdC4gWW91IGNvdWxkIG1vdmUgImxpYnJhcnkocmVhZHIpIiB0byB0aGUgZmlyc3QgY29kZSBjaHVuayBhdCB0b3Agb2YgdGhpcyBkb2N1bWVudCwgYnV0IGFzIF8qKnJlYWRyKipfIGlzIHBhcnQgb2YgdGhlIF8qKnRpZHl2ZXJzZSoqXyBwYWNrYWdlIHRoYXQgd2UgYWxyZWFkeSBsb2FkZWQsIGRvaW5nIHNvIHdvdWxkIGJlIHJlZHVuZGFudC4NCg0KSW4gdGhlIGludGVyZXN0IG9mIGhhdmluZyBjbGVhbiBhbmQgZWZmaWNpZW50IGNvZGUsIHRoZXJlIGFyZSBzZXZlcmFsIGFkZGl0aW9uYWwgdGhpbmdzIHRoYXQgeW91IGNhbiBkbyBoZXJlOiBkZWxldGUgbGlicmFyeShyZWFkciksIG5hbWUgdGhlIG9iamVjdCB0byB3aGljaCB0aGUgZGF0YSBhcmUgYXNzaWduZWQgc29tZXRoaW5nIHNpbXBsZXIgKGUuZy4sIGNyYWJfdGJzKSwgYW5kIHJlcGxhY2UgVmlldyhmaWRkbGVyX2NyYWJfdGVtcHMpIHdpdGggY3JhYl90YnMuIERvIHRoaXMgYmVsb3cgYW5kIGhpdCBSdW46DQpgYGB7cn0NCmNyYWJfdGJzIDwtIHJlYWRfY3N2KCJmaWRkbGVyX2NyYWJfdGVtcHMuY3N2IikNClZpZXcoY3JhYl90YnMpDQpgYGANCg0KQXMgeW91IGNhbiBzZWUsIHRoZSBkYXRhIHdlcmUgaW1wb3J0ZWQgYW5kIGFzc2lnbmVkIHRvIHRoZSBvYmplY3QgImNyYWJfdGJzIiAoeW91IGNhbiBhbHNvIHByb3ZpZGUgYSBuYW1lIGZvciB0aGUgb2JqZWN0IHRvIHdoaWNoIHRoZSBkYXRhIHdpbGwgYmUgYXNzaWduZWQgaW4gdGhlIGRpYWxvZ3VlIGJveCkgYW5kIHlvdSBhcmUgYWJsZSB0byBwcmV2aWV3IGl0IGluIHRoZSBzYW1lIHdpbmRvdy4gVGhpcyBwcmV2aWV3IGlzIGNhbGxlZCBhICJ0aWJibGUiIC0gcGFydCBvZiB0aGUgdGlkeXZlcnNlLiBUaWJibGVzIHNob3cgb25seSB0aGUgZmlyc3QgMTAgcm93cywgYW5kIGFsbCB0aGUgY29sdW1ucyB0aGF0IGZpdCBvbiBzY3JlZW47IHRoaXMgbWFrZXMgaXQgbXVjaCBlYXNpZXIgdG8gd29yayB3aXRoIGxhcmdlIGRhdGEuIEluIGFkZGl0aW9uIHRvIGl0cyBuYW1lLCBlYWNoIGNvbHVtbiByZXBvcnRzIGl0cyB0eXBlIChlLmcuLCBpbiB0aGlzIGNhc2UsIGNoYXJhY3RlciBzdGluZyA8Y2hyPiBvciBkb3VibGUgPGRibD4pLiBJbiBnZW5lcmFsLCB3ZSB3aWxsIHdvcmsgd2l0aCB0aWJibGVzIGluc3RlYWQgb2YgUuKAmXMgdHJhZGl0aW9uYWwgZGF0YS5mcmFtZS4gVGliYmxlcyAqYXJlKiBkYXRhIGZyYW1lcywgYnV0IHRoZXkgdHdlYWsgc29tZSBvbGRlciBiZWhhdmlvdXJzIHRvIG1ha2UgbGlmZSBhIGxpdHRsZSBlYXNpZXIuIE1vc3Qgb2YgdGhlIHRpbWUsIHlvdSBjYW4gdXNlIHRoZSB0ZXJtcyB0aWJibGUgYW5kIGRhdGEgZnJhbWUgaW50ZXJjaGFuZ2VhYmx5Lg0KDQpBbHRlcm5hdGl2ZWx5LCBpZiB5b3UgaGF2ZSB5b3VyIGRhdGEgYW5kIFIgTm90ZWJvb2sgb3Igc2NyaXB0IGluIHRoZSBzYW1lIGZvbGRlciAtIGFzIHlvdSB3b3VsZCBpZiB5b3UgYXJlIHVzaW5nIFIgUHJvamVjdCAtIHlvdSBjYW4ganVzdCBjbGljayBvbiB0aGUgZGF0YSBmaWxlIHlvdSB3YW50IHRvIGltcG9ydCBmcm9tIHRoZSBsaXN0IGluIHRoZSBGaWxlcyB0YWIgb2YgdGhlIGxvd2VyIGxlZnQgcGFuZSBvZiBSU3R1ZGlvICh5b3UgbWF5IGhhdmUgdG8gY2xpY2sgdGhlICpVcGRhdGUqIGJ1dHRvbiB0byByZWZyZXNoIHRoZSB3aW5kb3cpLiBBbHRob3VnaCB0aGUgYm9vayBzdGF0ZXMgdGhhdCAieW91IG9mdGVuIGRvbuKAmXQgd2FudCB5b3VyIGRhdGEgaW4gdGhlIHNhbWUgZm9sZGVyIGFzIHlvdXIgc2NyaXB0OyIgbWFueSBkYXRhIHNjaWVudGlzdHMgd291bGQgc3VnZ2VzdCB0aGF0IGlzIGluY29ycmVjdC4gSW4gZmFjdCwgc3RvcmluZyBhbGwgb2YgdGhlIGZpbGVzIGluIHRoZSBzYW1lIHByb2plY3QgZm9sZGVyIGlzIGV4YWN0bHkgd2hhdCB5b3Ugd2FudCB0byBkbyENCg0KIyMjIENoZWNraW5nIHRoYXQgeW91ciBkYXRhIGFyZSB5b3VyIGRhdGENCk5vdyB0aGF0IHdlIGFyZSByZWFkeSB0byBtb3ZlIG9uLCB0YWtlIGEgbW9tZW50IGFuZCBpbXBvcnQgdGhlIGNvbXBlbnNhdGlvbi5jc3YgZGF0YSBpbnRvIFI7IHBhc3RlIHRoZSBhc3NvY2lhdGVkIGNvZGUgaW4gdGhlIGNodW5rIGJlbG93IChidXQgbm90IGxpYnJhcnkocmVhZHIpKSBhbmQgbW9kaWZ5IGl0IHRvIHByb2R1Y2UgYSB0aWJibGU6DQpgYGB7cn0NCmNvbXBlbnNhdGlvbiA8LSByZWFkX2NzdigiY29tcGVuc2F0aW9uLmNzdiIpDQpWaWV3KGNvbXBlbnNhdGlvbikNCmBgYA0KDQpPbmNlIHlvdSBoYXZlIGltcG9ydGVkIGEgZGF0YSBzZXQsIGEgdmVyeSBzZW5zaWJsZSBuZXh0IHN0ZXAgaXMgdG8gbWFrZSBzdXJlIHRoZSBkYXRhIHlvdSBnb3QgaW4gUiBhcmUgYWN0dWFsbHkgdGhlIGRhdGEgeW91IHdhbnRlZC4gU29tZSBiYXNpYyB0aGluZ3MgdG8gY2hlY2sgYXJlOg0KDQoqIFRoZSBjb3JyZWN0IG51bWJlciBvZiByb3dzIGFyZSBpbiBSOyANCg0KKiBUaGUgY29ycmVjdCBuYW1lcyBhbmQgbnVtYmVyIG9mIHZhcmlhYmxlcyBhcmUgaW4gUjsNCg0KKiBUaGUgdmFyaWFibGUgYXJlIG9mIHRoZSBjb3JyZWN0IHR5cGUgKGUuZy4gUiByZWNvZ25pemVzIG51bWVyaWMgdmFyaWFibGVzIHRvIGJlIG51bWVyaWMpOyANCg0KKiBWYXJpYWJsZXMgZGVzY3JpYmluZyB0eXBlcyBvZiB0aGluZ3MgKGUuZy4gc2V4KSBoYXZlIHRoZSBjb3JyZWN0IG51bWJlciBvZiBjYXRlZ29yaWVzIChsZXZlbHMpLg0KDQpBdCB0aGlzIHBvaW50LCB0aGUgYm9vayBpbnRyb2R1Y2VzIHNldmVyYWwgZnVuY3Rpb25zIHlvdSBjYW4gdXNlIHRvIGludmVzdGlnYXRlIHlvdXIgZGF0YTogKipuYW1lcyoqKCkgdGVsbHMgeW91IHRoZSBuYW1lcyBhc3NpZ25lZCBlYWNoIGNvbHVtbjsgKipoZWFkKiooKSByZXR1cm5zIHRoZSBmaXJzdCBzaXggcm93cyBvZiB0aGUgZGF0YXNldCAoZ3Vlc3Mgd2hhdCAqKnRhaWwqKigpIGRvZXM/KTsgYW5kICoqZGltKiooKSB0ZWxscyB5b3UgdGhlIG51bWJlcnMgb2Ygcm93cyBhbmQgY29sdW1ucyAtIHRoZSAqZGltZW5zaW9uKiAtIG9mIHRoZSBkYXRhc2V0LiBQZXJoYXBzIHRoZSBtb3N0IHVzZWZ1bCBmdW5jdGlvbiBpcyAqKnN0cioqKCksIHdoaWNoIHJldHVybnMgdGhlIHN0cnVjdHVyZSBvZiB0aGUgZGF0YXNldCwgY29tYmluaW5nIG5lYXJseSBhbGwgb2YgdGhlIHByZXZpb3VzIGZ1bmN0aW9ucyBpbnRvIG9uZS4NCg0KVHlwZSBzdHIoY29tcGVuc2F0aW9uKSBhbmQgaGl0IFJ1bjogDQpgYGB7cn0NCnN0cihjb21wZW5zYXRpb24pDQoNCmBgYA0KDQpUaGlzIG91dHB1dCBsb29rcyBhIGxpdHRsZSBkaWZmZXJlbnQgdGhhbiB3aGF0IGlzIHNob3duIGluIHRoZSBib29rIC0gdGhpcyBpcyBiZWNhdXNlIHRoZSBkYXRhIGFzc2lnbmVkIHRvICJjb21wZW5zYXRpb24iIGFyZSBzdHJ1Y3R1cmVkIHNvbWV3aGF0IGRpZmZlcmVudGx5LiBTcGVjaWZpY2FsbHksIHRoZSBncmF6aW5nIGNhdGVnb3J5IGluIHRoZSBib29rIGV4YW1wbGUgaXMgY2xhc3NpZmllZCBhcyBmYWN0b3IsIHdoZXJlYXMgaXQgaXMgYSBjaGFyYWN0ZXIgc3RyaW5nIGluIHRoZSBvdXRwdXQgYWJvdmUuIFJlbWVtYmVyIHRoYXQgKipyZWFkX2NzdioqKCkgc3BlY2lmaWVzIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRS4uLiBXZSdsbCBleHBsb3JlIHRoZSBpbXBsaWNhdGlvbnMgb2YgdGhlc2UgZGlmZmVyZW5jZXMgbGF0ZXIuDQoNCk9uZSBwb3RlbnRpYWxseSB1c2VmdWwgZmVhdHVyZSBvZiAqKnN0cioqKCkgaXMgdGhhdCB0aGUgY29sdW1uIG5hbWVzIGFyZSBjb2xvci1jb2RlZCBieSBkYXRhIHR5cGU7IHRoaXMgbWFrZXMgaXQgZWFzaWVyIHRvIHNwb3Qgd2hlbiBhIGNvbHVtbiBkaWZmZXJzIGZyb20gdGhlIHJlc3Qgb3Igd2hlbiBndWVzc2luZyBieSBSIGxlYWRzIHRvIGltcG9ydCB3aXRoIGFuIHVuZXhwZWN0ZWQgdHlwZS4gT3RoZXJ3aXNlLCBhbGwgb2YgdGhpcyBpbmZvcm1hdGlvbiBpcyBhbHJlYWR5IGF2YWlsYWJsZSBpbiB0aGUgdGliYmxlIGFib3ZlLiBUaGUgKipnbGltcHNlKiooKSBhbmQgKiphc190aWJibGUqKigpIChmb3JtZXJseSAqKnRibF9kZioqKCkpIGZ1bmN0aW9ucyBpbiBfKipkcGx5cioqXyBhcmUgYWxzbyBub3cgcmVkdW5kYW50OiAqKmdsaW1wc2UqKigpIHByb3ZpZGVzIGEgaG9yaXpvbnRhbCB2aWV3IG9mIHRoZSBkYXRhLCB3aGVyZWFzICoqYXNfdGliYmxlKiooKSBwcm92aWRlcyAtIHdhaXQgZm9yIGl0IC0gYSB0aWJibGUuDQoNCiMjIyBCYXNpYyB0cm91Ymxlc2hvb3Rpbmcgd2hpbGUgaW1wb3J0aW5nIGRhdGENCkF0IHRoaXMgcG9pbnQgeW91IGtub3cgaG93IHRvIGNyZWF0ZSBhIC5jc3YgZmlsZSwgaW1wb3J0IHRoZSBhc3NvY2lhdGVkIGRhdGEsIGFuZCBtYWtlIHN1cmUgeW91IGdvdCB0aGUgZGF0YSBpbiBSIHRoYXQgeW91IHdhbnRlZCwgdXNpbmcgc2V2ZXJhbCBmdW5jdGlvbnMuIFRoZXNlIHRhc2tzIGFyZSB0aGUgYmFzaWMgZmlyc3Qgc3RlcHMgaW4gYW55IHByb2Nlc3Mgb2YgcXVhbnRpdGF0aXZlIHByb2JsZW0gc29sdmluZywgYW5kIHRoZXkgYXJlIHRoZSBmb3VuZGF0aW9uLiBUaGV5IGFyZSBub3Qgb3B0aW9uYWwgc3RlcHMuIEZvcmdldCB0aGVzZSwgZ2V0IHRoZXNlIHdyb25nLCBhbmQgZXZlcnl0aGluZyBlbHNlIHdpbGwgYmUgd3JvbmcgYWxzby4gU28gZm9jdXMgb24gaGF2aW5nIHJvY2stc29saWQgZGF0YSBpbiBSLiBPZiBjb3Vyc2UsIGFsb25nIHRoZSB3YXksIGJhZCB0aGluZ3Mgd2lsbCBoYXBwZW4uIFRoZSBib29rIHByZXNlbnRzIHNldmVyYWwgZXhhbXBsZXMgb2YgZGlmZmVyZW50IGtpbmRzIG9mIHByb2JsZW1zIHlvdSBtaWdodCBlbmNvdW50ZXI7IGhhdmUgYSBsb29rIGF0IHRoZW0uDQoNCiMjIyBBZHZhbmNlZCBhY3Rpdml0eTogZGVhbGluZyB3aXRoIHVudGlkeSBkYXRhDQpBcyB3YXMgaW1wbGllZCBhYm92ZSwgdGhlcmUgYXJlIGxvdHMgb2Ygd2F5cyBkYXRhIGNhbiBiZSB1bnRpZHkgYW5kIGl04oCZcyBub3QgcG9zc2libGUgdG8gZGVhbCB3aXRoIHRoZW0gYWxsIG5vdy4gTmV2ZXJ0aGVsZXNzLCBoZXJlIGlzIGEgc29tZXdoYXQgdHlwaWNhbCBleGFtcGxlIGluIHdoaWNoIG9ic2VydmF0aW9ucyBvZiB0aGUgc2FtZSB0aGluZyAgKGJhY3RlcmlhbCBkZW5zaXR5KSBoYXZlIGJlZW4gcmVjb3JkZWQgb24gbXVsdGlwbGUgZGF0ZXMsIGFuZCB0aGUgb2JzZXJ2YXRpb24gZnJvbSBlYWNoIGRhdGUgcGxhY2VkIGluIGEgc2VwYXJhdGUgY29sdW1uLiBSb3dzIG9mIHRoZSBkYXRhIGNvcnJlc3BvbmQgdG8gZXhwZXJpbWVudGFsIHVuaXRzIChkZWZpbmVkIGhlcmUgYnkgdGhlIHByb3Rpc3Qgc3BlY2llcyBjb25zdW1pbmcgdGhlIGJhY3RlcmlhLCBhbmQgdGhlIGVudmlyb25tZW50YWwgdGVtcGVyYXR1cmUpIChhbm90aGVyIHZhcmlhYmxlLCBCb3R0bGUsIGlzIGEgdW5pcXVlIGlkZW50aWZpZXIgZm9yIHRoZSBleHBlcmltZW50YWwgdW5pdCkuDQoNCkxldOKAmXMgaW1wb3J0IHRoZSBkYXRhIChsb2NhdGVkIGluIGEgZmlsZSBjYWxsZWQgIm5hc3R5X2Zvcm1hdC5jc3YiKSwgY2hlY2sgdGhlbSwgYW5kIHRoZW4gdGlkeSB0aGVtOg0KYGBge3J9DQoNCm5hc3R5X2Zvcm1hdCA8LSByZWFkX2NzdigibmFzdHlfZm9ybWF0LmNzdiIpDQpWaWV3KG5hc3R5X2Zvcm1hdCkNCg0Kc3RyKG5hc3R5X2Zvcm1hdCkNCmFzX3RpYmJsZShuYXN0eV9mb3JtYXQpDQoNCmBgYA0KDQpUaGUgdGliYmxlIGFib3ZlIGhhcyAzNyBvYnNlcnZhdGlvbnMgYW5kIDExIHZhcmlhYmxlcywgYnV0IHRoZSBleHBlcmltZW50IGludm9sdmVkIG9ubHkgMzYgZXhwZXJpbWVudGFsIHVuaXRzLiBMb29raW5nIGF0IHRoZSBkYXRhIG9uIHRoZSBmb3VydGggcGFnZSBvZiB0aGUgdGliYmxlLCBvciBieSBjbGlja2luZyBvbiB0aGUgbmFzdHlfZm9ybWF0IHRleHQgaW4gdGhlIFJzdHVkaW8gRW52aXJvbm1lbnQgcGFuZSBhbmQgc2Nyb2xsaW5nIGRvd24gaW4gdGhlIGRpc3BsYXllZCBkYXRhLCBzaG93cyB0aGVyZSBpcyBhIDM3dGggcm93IGNvbnRhaW5pbmcgbm8gZGF0YS4gVGhpcyBpcyBhIHBhcnRpY3VsYXIgZXJyb3IgdXN1YWxseSBjYXVzZWQgYnkgc29tZXRoaW5nIG9kZCB0aGF0IHdhcyBkb25lIGluIEV4Y2VsLiBMZXTigJlzIHJlbW92ZSB0aGF0IHJvdzsgc3RhcnQgYnkgaWRlbnRpZnlpbmcgd2hhdCBpcyB1bmlxdWUgYWJvdXQgaXQsIGNvbXBhcmVkIHdpdGggYWxsIHRoZSBvdGhlciByb3dzLiBJbXBvcnRhbnRseSwgaXQgbGFja3MgYW4gZW50cnkgaW4gdGhlIEJvdHRsZSB2YXJpYWJsZS4gU28gd2UgdGVsbCBSIHRvIGtlZXAgb25seSByb3dzIHRoYXQgaGF2ZSBhbiBlbnRyeSBpbiB0aGUgQm90dGxlIHZhcmlhYmxlLCB1c2luZyB0aGUgKipmaWx0ZXIqKigpIGZ1bmN0aW9uIGluIHRoZSBfKipkcGx5cioqXyBwYWNrYWdlIChtb3JlIGFib3V0IHRoaXMgYWRkLW9uIHBhY2thZ2UsIGFuZCAqKmZpbHRlcioqKCksIGluIHRoZSBuZXh0IGNoYXB0ZXIpOg0KDQpTdGFydCBieSBhc2tpbmcgUiBmb3IgaGVscCB3aXRoICoqZmlsdGVyKiooKSBieSB0eXBpbmcgP2ZpbHRlcigpIGFuZCBoaXR0aW5nIFJ1bjoNCmBgYHtyfQ0KP2ZpbHRlcigpDQoNCmBgYA0KDQpTdXJwcmlzZSEgQXMgeW91IGNhbiBzZWUgaW4gdGhlIEhlbHAgdGFiIGluIHRoZSBsb3dlciBsZWZ0IHBhbmUsIHRoZXJlIGFyZSB0d28gZGlmZmVyZW50IGZ1bmN0aW9ucyBjYWxsZWQgKipmaWx0ZXIqKigpIC0gb25lIGluIHRoZSBfKipkcGx5cioqXyBwYWNrYWdlIGFuZCBhbm90aGVyIGluIHRoZSBfKipzdGF0cyoqXyBwYWNrYWdlLiBMdWNraWx5LCB3ZSBrbm93IHRoYXQgd2UgYXJlIHVzaW5nIF8qKmRwbHlyKipfIChhbmQgdGhhdCB3ZSBoYXZlbid0IGV2ZW4gbG9hZGVkIF8qKnN0YXRzKipfKSwgc28gaXQncyBlYXN5IGVub3VnaCB0byBmaWd1cmUgb3V0IHdoaWNoIGxpbmsgdG8gY2xpY2sgZm9yIG1vcmUgaW5mb3JtYXRpb24uIFRoZSB0d28gbWFpbiBhcmd1bWVudHMgYXJlIC5kYXRhICh0aGUgdGliYmxlIHlvdSB3YW50IHRvIGZpbHRlcikgYW5kIC4uLiAobG9naWNhbCBwcmVkaWNhdGVzOyBpLmUuLCBob3cgeW91IHdhbnQgUiB0byBmaWx0ZXIgdGhlIGRhdGEpLiBUaGUgaGVscCBmaWxlIGFsc28gcHJvdmlkZXMgYSBsaXN0IG9mIGxvZ2ljYWwgb3BlcmF0b3JzOiAhIGluZGljYXRlcyBsb2dpY2FsIG5lZ2F0aW9uIChOT1QpLg0KDQpUeXBlIG5hc3R5X2Zvcm1hdCA8LSBmaWx0ZXIobmFzdHlfZm9ybWF0LCBCb3R0bGUgIT0gIiIpLCBoaXQgRW50ZXIgYW5kIHR5cGUgbmFzdHlfZm9ybWF0ICh0byB2aWV3IHRoZSByZXN1bHRpbmcgdGliYmxlKSwgdGhlbiBoaXQgUnVuOg0KYGBge3J9DQpuYXN0eV9mb3JtYXQ8LWZpbHRlcihuYXN0eV9mb3JtYXQsQm90dGxlICE9ICIiKQ0KbmFzdHlfZm9ybWF0DQpgYGANCg0KUHJvYmxlbSBzb2x2ZWQhIE5vdyB3ZSBtYWtlIHRoZSBkYXRhIHRpZHkuIFdlIG5lZWQgYSBuZXcgdmFyaWFibGUgdGhhdCBjb250YWlucyB0aGUgZGF0ZSBvbiB3aGljaCBvYnNlcnZhdGlvbnMgd2VyZSBtYWRlLCBhbmQgYSBuZXcgdmFyaWFibGUgY29udGFpbmluZyB0aGUgb2JzZXJ2YXRpb25zIG9mIGJhY3RlcmlhbCBhYnVuZGFuY2UgdGhhdCBhcmUgY3VycmVudGx5IHN0b3JlZCBpbiBjb2x1bW5zIDQgdG8gMTEuIEFuZCB0aGVuIHdlIG5lZWQgdG8gbW92ZSB0aGUgZGF0YSBpbnRvIHRoZXNlIG5ldyBjb2x1bW5zLiBUaGlzIGlzIGFsbCB2ZXJ5IHN0cmFpZ2h0Zm9yd2FyZCwgdGhhbmtzIHRvIHRoZSAqKmdhdGhlcioqKCkgZnVuY3Rpb24gaW4gdGhlIF8qKnRpZHlyKipfIHBhY2thZ2UuICoqcGl2b3RfbG9uZ2VyKiooKSBhbmQgKipwaXZvdF93aWRlcioqKCkgaGF2ZSByZWNlbnRseSByZXBsYWNlZCB0aGUgb2xkZXIgKipzcHJlYWQqKigpIGFuZCAqKmdhdGhlcioqKCkgZnVuY3Rpb25zIGluIF8qKnRpZHlyKipfLCBzbyB5b3UgbWF5IGV2ZW50dWFsbHkgbmVlZCB0byBmaWd1cmUgb3V0IGhvdyB0aGV5IGRpZmZlciwgYnV0IGRvbid0IHdvcnJ5IGFib3V0IGl0IGZvciBub3cuIEtlZXBpbmcgb24gdG9wIG9mIHRoZSBjb250aW51ZWQgdXBkYXRlcyBhbmQgaW1wcm92ZW1lbnRzIHRvIHBhY2thZ2VzIGluIFIgaXMgb25lIG9mIHRoZSBtb3JlIGRpZmZpY3VsdCBjaGFsbGVuZ2VzIHRvIHdvcmtpbmcgd2l0aCB0aGlzIHBsYXRmb3JtLi4uDQoNClR5cGUgdGlkeV9mb3JtYXQgPC0gZ2F0aGVyKGRhdGEgPSBuYXN0eV9mb3JtYXQsIERhdGUsIEFidW5kYW5jZSwgNDoxMSksIGhpdCBFbnRlciBhbmQgdHlwZSB0aWR5X2Zvcm1hdCwgdGhlbiBoaXQgUnVuOg0KYGBge3J9DQoNCnRpZHlfZm9ybWF0PC0gZ2F0aGVyKGRhdGE9bmFzdHlfZm9ybWF0LERhdGUsIEFidW5kYW5jZSwgNDoxMSkNCnRpZHlfZm9ybWF0DQoNCmBgYA0KDQpUaGUgZmlyc3QgYXJndW1lbnQgb2YgZ2F0aGVyIGlzIHRoZSBkYXRhIGZyYW1lIHRvIHdvcmsgb246IG5hc3R5X2Zvcm1hdC4gVGhlIHNlY29uZCBpcyB0aGUgbmFtZSBvZiB0aGUgbmV3IHZhcmlhYmxlIHRoYXQgd2lsbCBjb250YWluIHRoZSBkYXRlcyAod2UgY2FsbCBpdCBEYXRlKS4gVGhlIHRoaXJkIGlzIHRoZSBuYW1lIG9mIHRoZSBuZXcgdmFyaWFibGUgdGhhdCB3aWxsIGNvbnRhaW4gdGhlIGJhY3RlcmlhbCBhYnVuZGFuY2VzICh3ZSBjYWxsIGl0IEFidW5kYW5jZSkuIFRoZSBmb3VydGggYXJndW1lbnQgaXMgdGhlIGxvY2F0aW9uIGluIHRoZSBuYXN0eV9mb3JtYXQgZGF0YSBmcmFtZSBvZiB0aGUgb2JzZXJ2YXRpb25zIG9mIGJhY3RlcmlhbCBhYnVuZGFuY2UgdGhhdCBhcmUgdG8gYmUgcHV0IGludG8gdGhlIG5ldyBBYnVuZGFuY2UgdmFyaWFibGUuIEV4YW1pbmUgdGhlIHRpYmJsZSBhYm92ZSBhbmQvb3IgdXNlIHN0cih0aWR5X2Zvcm1hdCkgYmVsb3cgdG8gc2VlIGlmIGl0IHdvcmtlZDoNCmBgYHtyfQ0Kc3RyKHRpZHlfZm9ybWF0KQ0KDQpgYGANCg0KWWVzLCBzdXBlciEgV2UgaGF2ZSAyODggb2JzZXJ2YXRpb25zICgzNiBleHBlcmltZW50YWwgdW5pdHMgKGJvdHRsZXMpLCBlYWNoIG9ic2VydmVkIG9uIGVpZ2h0IGRhdGVzKS4gV2UgaGF2ZSB0aGUgbmV3IERhdGUgdmFyaWFibGUsIGEgY2hhcmFjdGVyIHN0cmluZy10eXBlIChOT1QgZmFjdG9yLXR5cGUsIGFzIHRoZSBib29rIHN1Z2dlc3RzIC0gcmVtZW1iZXIgdGhhdCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UgaW4gKipyZWFkX2NzdioqKCkpIHZhcmlhYmxlIHdpdGggZWlnaHQgbGV2ZWxzLCBhbmQgdGhlIG5ldyBBYnVuZGFuY2UgdmFyaWFibGUsIHdoaWNoIGlzIGRvdWJsZSBwcmVjaXNpb24gbnVtYmVycy4NCg0KVGhlIGRhdGEgYXJlIG5vdyBvZmZpY2lhbGx5IHRpZHkuIFRoZSBEYXRlIHZhcmlhYmxlIHN0aWxsIG5lZWRzIGEgYml0IG9mIHdvcmssIGhvd2V2ZXIuIFdlIG5lZWQgdG8gbWFrZSBSIHJlY29nbml6ZSB0aGF0IHRoZXNlIGFyZSBkYXRlcyAoaS5lLiBjaGFuZ2UgdGhlIHZhcmlhYmxlIHR5cGUgZnJvbSBhIGNoYXJhY3Rlci10eXBlIHRvIGEgZGF0ZS10eXBlIHZhcmlhYmxlKS4gV2UgZG8gdGhpcyB3aXRoaW4gdGhlICoqbXV0YXRlKiooKSBmdW5jdGlvbiBvZiB0aGUgXyoqZHBseXIqKl8gYWRkLW9uIHBhY2thZ2UsIHdoaWNoIHByb3ZpZGVzIGEgbmVhdCB3YXkgb2YgY2hhbmdpbmcgKG9yIGFkZGluZykgdmFyaWFibGVzIGluIGEgZGF0YSBmcmFtZSAobXVjaCBtb3JlIGFib3V0IHRoaXMgaW4gdGhlIG5leHQgY2hhcHRlcikuIFRlY2huaWNhbGx5LCB3ZSBhcmUgZ29pbmcgdG8gcGFyc2UgdGhlIGluZm9ybWF0aW9uIGluIHRoZSBkYXRlIHZhcmlhYmxlIHNvIHRoYXQgUiByZWdhcmRzIGl0IGFzIGEgZGF0ZS4gVGhpcyB3aWxsIGFsbG93IHVzIHRvIHVzZSB0aGUgRGF0ZSB2YXJpYWJsZSBhcyBhIGNvbnRpbnVvdXMgdmFyaWFibGUsIGZvciBleGFtcGxlIHRvIG1ha2UgYSBncmFwaCB3aXRoIHRoZSBkYXRlIG9uIHRoZSB4LWF4aXMsIG9yIGV2ZW4gdG8gY2FsY3VsYXRlIHRoZSBudW1iZXIgb2YgZGF5cywgbW9udGhzLCBvciB5ZWFycyBiZXR3ZWVuIHR3byBvciBtb3JlIGRhdGVzLg0KDQpXZSB3aWxsIHVzZSBhIGZ1bmN0aW9uIGluIHRoZSBfKipsdWJyaWRhdGUqKl8gcGFja2FnZSB0aGF0IHdlIGxvYWRlZCBpbiB0aGUgZmlyc3QgY29kZSBjaHVuayBhYm92ZS4gVGhpcyBwYWNrYWdlIGNvbnRhaW5zIHRoZSBmdW5jdGlvbnMgKip5bWQqKigpLCAqKnlkbSoqKCksICoqZHltKiooKSwgKipkbXkqKigpLCAqKm15ZCoqKCksIGFuZCAqKm1keSoqKCksIGFtb25nIG90aGVycy4gV2hpY2ggb2YgdGhlc2UgZnVuY3Rpb25zIHNob3VsZCB3ZSB1c2UgZm9yIG91ciBkYXRhPw0KDQpUYWtlIGEgbG9vayBhdCB0aGUgZGF0ZSB2YWx1ZXMgYnkgdHlwaW5nIHVuaXF1ZSh0aWR5X2Zvcm1hdCREYXRlKSBhbmQgaGl0dGluZyBSdW46DQpgYGB7cn0NCnVuaXF1ZSh0aWR5X2Zvcm1hdCREYXRlKQ0KYGBgDQoNCldl4oCZdmUgdXNlZCBhIGJpdCBvZiBjbGFzc2ljIFIgaGVyZSwgdGhlIGRvbGxhciBzaWduLCB0byByZWZlciB0byBhIHZhcmlhYmxlIGluc2lkZSBhIGRhdGEgZnJhbWUuIE5vdCB0b28gbXVjaCBzbGV1dGhpbmcgc2hvd3MgdGhhdCBvdXIgZGF0ZSBoYXMgdGhlIGZvcm1hdCBkYXkubW9udGgueWVhci4gU28gd2UgdXNlIHRoZSBmdW5jdGlvbiAqKmRteSoqKCkuIFRoaXMgaXMgYSBxdWl0ZSBpbnRlbGxpZ2VudCBmdW5jdGlvbiwgYWJsZSB0byBkZWFsIHdpdGgsIGUuZy4sIGRpZmZlcmVudCBzZXBhcmF0b3JzIChvdXJzIGlzIGEgZG90IGJ1dCBvdGhlcnMgd29yaykgYW5kIGRhdGVzIHRoYXQgaW5jbHVkZSBsZWFkaW5nIHplcm9zLiANCg0KUGFyc2UgdGhlIERhdGUgZGF0YSBpbnRvIHRoZSBhcHByb3ByaWF0ZSBmb3JtYXQgKGRheS5tb250aC55ZWFyKTsgdHlwZSB0aWR5X2Zvcm1hdCA8LSBtdXRhdGUodGlkeV9mb3JtYXQsIERhdGUgPSBkbXkoRGF0ZSkpLCBoaXQgRW50ZXIgYW5kIHR5cGUgdGlkeV9mb3JtYXQsIHRoZW4gaGl0IFJ1bjoNCmBgYHtyfQ0KDQo/ZG15KCkNCnRpZHlfZm9ybWF0PC1tdXRhdGUodGlkeV9mb3JtYXQsIERhdGUgPSBkbXkoRGF0ZSkpDQp0aWR5X2Zvcm1hdA0KDQpgYGANCg0KRGF0ZSBpcyBub3cgYSBkYXRlLXR5cGUgdmFyaWFibGUsIGFzIGl0IHNob3VsZCBiZS4gU28gd2hhdCBjYW4gd2UgZG8gbm93LCB3aXRoIHRoaXMgdGlkeSBkYXRhPyBXZWxsLCBpbWFnaW5lIHdlIHdhbnQgdG8gdmlldyB0aGUgZHluYW1pY3Mgb2YgYmFjdGVyaWFsIGFidW5kYW5jZSBpbiBlYWNoIGJvdHRsZS4gV2UgY2FuIG5vdyBkbyB0aGlzIHdpdGggdmVyeSBsaXR0bGUgY29kZS4gXyoqZ2dwbG90MioqXyBpcyBhIHBvd2VyZnVsIGFuZCBmbGV4aWJsZSBwbG90dGluZyBwYWNrYWdlIGF2YWlsYWJsZSBhcyBwYXJ0IG9mIHRoZSBfKip0aWR5dmVyc2UqKl8gcGFja2FnZS4gV2Ugd2lsbCBleHBsb3JlICoqZ2dwbG90KiooKSBpbiBtb3JlIGRldGFpbCBpbiBDaGFwdGVyIDQsIGJ1dCBmb3Igbm93IHdlIHdpbGwgdGVsbCAqKmdncGxvdCoqKCkgdGhlIGRhdGEgZnJhbWUgdG8gbG9vayBpbiBmb3IgdmFyaWFibGVzLCB0aGUgKngqLSBhbmQgKnkqLXZhcmlhYmxlcywgdG8gcGxvdCBwb2ludHMsIGFuZCB0byB0aGVuIHByb2R1Y2UgYSBzZXBhcmF0ZSBncmFwaCAoaS5lLiBmYWNldCkgZm9yIGVhY2ggb2YgdGhlIGJvdHRsZXMuDQoNClR5cGUgZ2dwbG90KGRhdGEgPSB0aWR5X2Zvcm1hdCwgYWVzKHg9RGF0ZSwgeT1BYnVuZGFuY2UpKSArLCBoaXQgRW50ZXIgYW5kIHR5cGUgZ2VvbV9wb2ludCgpICssIGhpdCBFbnRlciBhbmQgdHlwZSBmYWNldF93cmFwKH5Cb3R0bGUpLCBhbmQgdGhlbiBoaXQgUnVuOg0KYGBge3J9DQoNCmdncGxvdChkYXRhPXRpZHlfZm9ybWF0LCBhZXMoeD1EYXRlLHk9QWJ1bmRhbmNlKSkrDQogIGdlb21fcG9pbnQoKSsNCiAgZmFjZXRfd3JhcCh+Qm90dGxlKQ0KICAgICAgICAgICAgDQoNCmBgYA0KDQpTZXBhcmF0aW5nIGVhY2ggY29tcG9uZW50IG9mIHRoZSBncmFwaCBidWlsZGluZyBwcm9jZXNzIG9udG8gaXRzIG93biBsaW5lIG9mIGNvZGUgbWFrZXMgaXQgZWFzaWVyIHRvIHNlZSB3aGF0IGZ1bmN0aW9ucyBoYXZlIGJlZW4gY2FsbGVkLCB0byBtb2RpZnkgYW55IG9mIHRoZSBhc3NvY2lhdGVkIGFyZ3VtZW50cywgYW5kIHRvIGFkZCBuZXcgZnVuY3Rpb25zLiBJdCBjYW4gYWxzbyBoZWxwIHdpdGggY29kaW5nIGVycm9ycywgYXMgeW91IHdpbGwgc2VlIGV4YWN0bHkgd2hlcmUgYW55IHByb2JsZW0gb2NjdXJzLiBUaGUgcmVzdWx0aW5nIHBhbmVsIG9mIGdyYXBocyBoYXMgY29ycmVjdCBkYXRlcyBvbiB0aGUgKngqLWF4aXMsIGFuZCBpcyByZWFsbHkgdXNlZnVsIGZvciBkYXRhIGV4cGxvcmF0aW9uLCBvciBldmVuIHB1YmxpY2F0aW9uIGFmdGVyIHNvbWUgcG9saXNoaW5nIChlLmcuIG1ha2luZyB0aGUgKngqLWF4aXMgdGljayBsYWJlbHMgbGVnaWJsZSkuIEEgcGFuZWwgb2YgZ3JhcGhzIGxpa2UgdGhpcyB3b3VsZCBoYXZlIGJlZW4gY29uc2lkZXJhYmx5IG1vcmUgaGFzc2xlIHRvIG1ha2UgaWYgdGhlIGRhdGEgd2VyZSBub3QgdGlkeSwgaS5lLiBpZiB0aGUgZGF0YSB3ZXJlIGxlZnQgYXMgdGhleSB3ZXJlIGluIHRoZSBkYXRhIGZpbGUsIHdpdGggb25lIHZhcmlhYmxlIGZvciBlYWNoIGRhdGUuDQoNCiMjIyBGdW5jdGlvbnMgZm9yIGRlYWxpbmcgd2l0aCBtZXNzeSBkYXRhICANCkFzIHdlIG1lbnRpb25lZCwgdGhlcmUgYXJlIG1hbnkgd2F5cyBpbiB3aGljaCBkYXRhIGNhbiBiZSB1bnRpZHkgYW5kIG1lc3N5LiBGb3J0dW5hdGVseSwgdGhlcmUgYXJlIGxvdHMgb2YgbmljZSBmdW5jdGlvbnMgZm9yIGRlYWxpbmcgd2l0aCB1bnRpZHkgYW5kIG1lc3N5IGRhdGEuIEluIHRoZSBiYXNlLCB0aWR5ciwgYW5kIGRwbHlyIHBhY2thZ2VzIHRoZXJlIGFyZSAoaW4gYWRkaXRpb24gdG8gdGhlIG9uZXMgd2UndmUgYWxyZWFkeSBzZWVuKToNCg0KKiAqKnNwcmVhZCoqKCk6IGRvZXMgdGhlIG9wcG9zaXRlIG9mIGdhdGhlci4gVXNlZnVsIGZvciBwcmVwYXJpbmcgZGF0YSBmb3IgbXVsdGl2YXJpYXRlIG1ldGhvZHM7DQoNCiogKipzZXBhcmF0ZSoqKCk6IHNlcGFyYXRlcyBpbmZvcm1hdGlvbiBwcmVzZW50IGluIG9uZSBjb2x1bW4gaW50byBtdWx0aXBsZSBuZXcgY29sdW1uczsNCg0KKiAqKnVuaXRlKiooKTogcHV0cyBpbmZvcm1hdGlvbiBmcm9tIHNldmVyYWwgY29sdW1ucyBpbnRvIG9uZSBjb2x1bW47DQoNCiogKipyZW5hbWUqKigpOiByZW5hbWVzIHRoZSBjb2x1bW5zIG9mIHlvdXIgZGF0YTsNCg0KKiAqKnJiaW5kKiooKTogcHV0cyB0d28gZGF0YXNldHMgd2l0aCBleGFjdGx5IHRoZSBzYW1lIGNvbHVtbnMgdG9nZXRoZXIgKGkuZS4gaXQgYmluZHMgcm93cyB0b2dldGhlcik7DQoNCiogKipjYmluZCoqKCk6IHB1dHMgdHdvIGRhdGFzZXRzIHdpdGggZXhhY3RseSB0aGUgc2FtZSByb3dzIHRvZ2V0aGVyIChpLmUuIGl0IGJpbmRzIGNvbHVtbnMgdG9nZXRoZXIsIGJ1dCBpdCBpcyBvZnRlbiBiZXR0ZXIgdG8gdXNlIHRoZSBuZXh0IGZ1bmN0aW9uKTsNCg0KKiAqKmpvaW4qKigpOiBhIHN1aXRlIG9mIGZ1bmN0aW9ucywgc3VjaCBhcyAqKmZ1bGxfam9pbioqKCksIHdoaWNoIGFsbG93cyBqb2luaW5nIHRvZ2V0aGVyIHR3byBkYXRhc2V0cyB3aXRoIG9uZSBvciBtb3JlIGNvbHVtbnMgaW4gY29tbW9uLiAoU2FtZSBhcyB0aGUgKiptZXJnZSoqKCkgZnVuY3Rpb24gaW4gdGhlIF8qKmJhc2UqKl8gcGFja2FnZS4pDQoNCllvdSB3aWxsIHByb2JhYmx5IGZpbmQgdGhhdCB0aWR5aW5nIGRhdGEsIGVzcGVjaWFsbHkgZGF0YSB0aGF0IHlvdSBkaWRu4oCZdCBwcmVwYXJlLCBjYW4gdGFrZSBhIGxvdCBvZiB0aW1lIGFuZCBlZmZvcnQuIEhvd2V2ZXIsIGl04oCZcyBpbnZlc3RtZW50IHdlbGwgbWFkZSwgYXMgaGF2aW5nIHRpZHkgYW5kIGNsZWFuIGRhdGEgbWFrZXMgZXZlcnl0aGluZyBmb2xsb3dpbmcgdGVuIHRpbWVzIGVhc2llci4gV2XigJl2ZSB1c2VkIGZ1bmN0aW9ucyBmcm9tIHNldmVyYWwgYWRkLW9uIHBhY2thZ2VzOiBfKip0aWR5cioqXywgXyoqbHVicmlkYXRlKipfLCBfKipkcGx5cioqXywgYW5kIF8qKmdncGxvdDIqKl8uIEl0IHdvdWxkIGJlIHdlbGwgd29ydGggeW91ciB3aGlsZSB0byByZXZpZXcgdGhlc2UsIGFuZCBtYWtlIG5vdGVzIGFib3V0IHdoaWNoIGZ1bmN0aW9ucyB3ZSB1c2VkIGZyb20gZWFjaCBvZiB0aGVzZSBwYWNrYWdlcywgd2h5IHdlIHVzZWQgdGhlbSwgYW5kIHRoZSBhc3NvY2lhdGVkIGFyZ3VtZW50cy4NCg0KIyMjIFdyYXBwaW5nIHVwDQpTYXZlIHlvdXIgZmlsZSBhbmQgZXhpdCB0aGUgUiBzZXNzaW9uLg0K