1 Introduction

This module outlines the open-source computer software program R (https://www.r-project.org/) and the platform RStudio (https://posit.co/downloads/) to be used in this and subsequent statistics courses.

2 Download and Installation

Both R and RStudio are free and open-source. R is a programming language widely used in statistics and data science, including machine learning, while RStudio is a data science platform that simplifies working with R. In other words, we need to install both R and RStudio and then use R through RStudio.

The following YouTube video by Tony Carlsen demonstrates the steps for downloading and installing both programs.



Please follow the steps to install these two programs on your machine. You can also use R Studio on WCU’s Ramcloud.

3 Getting Started with R and RStudio

The next video shows how to use R through RStudio with some basic arithmetic operations and basic commands that will be used to compose some formulas in this course.



You can also change the appearance of the RStudio user interface (UI) to get a more comfortable and better UI by following the next few steps:

  • From the menu bar, go to Tools > Global Options
  • Click on Appearance
  • Change the Editor font size if you want to
  • Try out a few themes in the Editor theme box. (The default is Textmate. I prefer Pastel on Dark).
  • Once you find something you like (or just stick with Textmate if you are happy with the default appearance), click on OK, and continue with this tutorial.

My own RStudio UI (user interface) is shown below (File > New File > R Script)

After clearing the Console (bottom-left window) and minimizing the right side windows (top-right and bottom-right windows), we have the following UI with Script window and Console window.

It is convenient for you to save a single file that includes all of your code to be drafted during the semester. We will discuss how to effectively organize your code for different modules later.

4 Using R As A Calculator

R can be used as a powerful calculator by entering equations directly at the prompt in the command console. Simply type your arithmetic expression and press ENTER. R will evaluate the expressions and respond with the result. While this is a simple interaction interface, there could be problems if you are not careful. R will normally execute your arithmetic expression by evaluating each item from left to right, but some operators have precedence in the order of evaluation. Let’s start with some simple expressions as examples.

4.1 Simple Arithmetic Expressions

The operators R uses for basic arithmetic are: +, -, *, /, ^. The following table presents some examples.

Operator Meaning Example Expression Result
+ Addition 4 + 8 12
- Subtraction 5 - 8 -3
* Multiplication 4 * 8-2 30
/ Division 4 / 8 0.5
^ Exponentiation 4^3 64

Here is how I performed the above operations in RStudio:

  1. Open RStudio (click the RStudio icon, it will automatically open the script window, Console, and other windows on the right-hand side). Minimize the windows on the right-hand side to keep only Script and Console windows.

  2. Type the expressions in the Script window.

  3. Highlight the expression you want to run,

  4. You will view both code and results in the R Console

The following is the screenshot of my RStudio UI (with some annotations)

From the above screenshot, you see that using hashtags can make your code more organized.


4.2 Input Data in R

In statistics, a data set consists of values of multiple measurements from multiple characteristics. For example, a data set contains height, weight, and gender taken from a group of \(n\) students.

observation ID height (\(X\)) weight (\(Y\)) Gender (\(Z\))
1 \(x_1\) \(y_1\) F
2 \(x_2\) \(y_2\) M
\(\vdots\) \(\vdots\) \(\vdots\) \(\vdots\)
\(n-1\) \(x_{n-1}\) \(y_{n-1}\) M
\(n\) \(x_n\) \(y_n\) F

The above data set has \(n\) rows, each row records a student’s height, weight, and gender. Different columns represent different characteristics, which are commonly called variables. A dataset is usually saved in a different format. The most common formats of a flat data file are a text file .txt (plain text file). If Excel is used to store data, comma-separated values .csv, and Microsoft Excel spreadsheets (.xls) or Excel Open XML Spreadsheet (.xlsx). A data set with a different format required a different R function to read data into R.

As an example, I save the following data set in C:\cpeng\STA200 in plain text format with extension .txt and comma-separated values with extension .csv.

```{} ID height weight gender 1 60 120 F 2 64 119 M 3 68 145 M 4 71 132 F

When reading the data set into R, you need to provide the path to the data file. The following screenshot shows how to use appropriate R functions to read the dataset.

We can also define individual variables and then make a data frame using the R function data.frame() as shown in the following code chunk.

# define individual variables first
ID <- c(1,2,3,4)    # ID = observation id, lower case c() is an R function used to define a vector.
height <- c(60, 64, 68, 71)
weight <- c(120, 119, 145, 132)
gender <- c("F", "M", "M", "F")   # Categorical values must be enclosed in double quotes and separated by commas.
# put the above variables in a dataframe
height.weight.data <- data.frame(ID = ID, height = height, weight = weight, gender = gender)  # data.frame() is an  R function

You can also define the data frame directly using the following code.

height.weight.data.02 <- data.frame(
                             ID = c(1,2,3,4),       # CAUTION: "=" CANNOT be replaced by "<-"!!!!
                             height = c(60, 64, 68, 71),
                             weight = c(120, 119, 145, 132),
                             gender = c("F", "M", "M", "F")
)
height.weight.data.02
##   ID height weight gender
## 1  1     60    120      F
## 2  2     64    119      M
## 3  3     68    145      M
## 4  4     71    132      F

4.3 Working With Data Frame

Quite often, we only work with one or two variables in a data frame instead of the entire data set. For example, we want to calculate the mean and standard deviation of the variable height in the above data set. We can extract height from the data frame we defined using the following code.

height <- height.weight.data.02$height   # datasetname + $ + variablename
# Calculate mean and variance
xbar <- mean(height)  # compute the mean and store it in a variable under the name of xbar
xbar                  # print out the result
## [1] 65.75
var.height <- var(height)
var.height
## [1] 22.91667

4.4 Some Basic Statistics and Mathematics Functions

Most of you have experience using graphing calculators and relevant functions. R has similar built-in functions for basic mathematical and statistical calculations. We use height and weight in examples in the following table.

Math & Stats function R function Example Code Result
mean mean() mean(height) 65.75
variance var() var(height) 22.92
standard deviation sd() sd(height) 4.79
correlation coefficient cor() cor(height, weight) 0.691
summation of data values sum() sum(height) 263

4.5 Critical Values and Left-tail Probabilities

In testing hypotheses, we can use either the critical value or p-value methods to make a statistical decision. The next table lists the R functions for critical and p-values from normal and t tables.

Critical Value degrees of freedom Example Code Result
\(95\%\) normal critical value NA qnorm(0.975) 1.96
\(95\%\) normal critical value 25 qt(0.975, 25) 2.059539
left-tail Probability degrees of freedom Example Code Result
\(P(TS < 1.45)\) normal table NA pnorm(1.45) 0.9264707
\(P(TS < 1.45)\) t table 15 pt(1.45, 15) 0.9161772

4.6 Evaluate Formulas

Just like using a graphing calculator, we sometimes need to evaluate a formula. For example, when constructing a 95% normal confidence interval based on given descriptive statistics (rather than raw data), we use the following formula.

\[ \bar{X} \pm Z_{\alpha/2}\frac{s}{\sqrt{n}}. \]

We use an example to illustrate how to write the above formula in R to calculate the confidence interval.

Example: The Dean wants to estimate the mean number of hours that students worked per week. A sample of 49 students showed a mean of 24 hours with a standard deviation of 4 hours. The point estimate is 24 hours (sample mean). What is the 95% confidence interval for the average number of hours worked per week by the students?

reasoning process: since \(n=39 > 30\), we can use the central limit theorem (CLT) to claim that \(\bar{X}\) is approximated by a normal distribution. Therefore, \(Z_{\alpha/2}\) can be found using qnorm(1-alpha/2).

## Assign values to variables in the formula 
alpha = 1-0.95   # alpha
xbar = 24   # sample mean
stdev = 4   # standard deviation
n = 49
## critical value
Z.0.975 = qnorm(0.975)    # alpha = 1 - 95% - 1 - 0.95 = 0.05, 1 - alpha/2 = 1 -0.025 = 0.975
## lower and upper confidence limits
LCL = xbar - Z.0.975*(stdev/sqrt(n))   # no square and curly bracket should be used in R
UCL = xbar + Z.0.975*(stdev/sqrt(n)) 
## Write the confidence interval
cbind(LCL = LCL, UCL = UCL)    # combined the two limits in a two-column table with one row
##           LCL      UCL
## [1,] 22.88002 25.11998

5 R Built-in Statistics Function

R has a rich built-in functions for various statistical analyses. Next, we list some of the functions that can perform all the analyses in introductory statistics like MAT121 at WCU. These functions are called when you have raw data stored in variables. Remember, each column in a data frame is a variable.

For convenience, we use the following raw data set collected from a diabetes study, which can be found at https://pengdsci.github.io/STA200/dataset/diabetes-dataset.csv

We first read the above data using the command given previously and extract variables to perform one-sample, two-sample tests, correlation coefficient, and least squares regression.

Data loading and variable extraction

Statistical Task Built-in R Function Example with Data
correlation coefficient cor() cor(BMI, SkinThickness)
five-number-summary summary() summary(BMI)
histogram hist() hist(SkinThickness)
scatter plot plot() plot(BMI, SkinThickness)
frequency table (categorical data) table() table(Outcome)
linear regression lm() lm(BMI ~ diabets.status)

6 R Packages

An R package is a collection of functions, data, and documentation that extends the capabilities of base R. Different R functions in different packages allow users to perform different statistical tasks. In this course, we will use a few functions and some packages. To use an R function in a specific package, you need to load the package using the following command.

if (!require("packageName")) {
   install.packages("packageName")
   library(packageName)
}

For example, if you want to perform a z-test (i.e., normal test), we can use the R function z.test() in the package. The following is the code for testing BMI Ho: mu <= 30 vs Ha: mu > 30.

## install and load package
if (!require("BSDA")) {
   install.packages("BSDA")
   library(BSDA)
}
## Call the function to perform a normal test
# Ho: mu = 30 vs Ha: mu != 30, the alternative is !=, this is a two-sided test
# IF the test is right-tailed, the alternative MUST be specified as "greater",
# Similarly, if the test is left-tailed, the alternative MUST be specified as "less".
z.test(x = BMI, sigma.x = sd(BMI), mu = 30, alternative = "two.sided")
## 
##  One-sample z-Test
## 
## data:  BMI
## z = 7.0039, p-value = 2.489e-12
## alternative hypothesis: true mean is not equal to 30
## 95 percent confidence interval:
##  31.43498 32.55018
## sample estimates:
## mean of x 
##  31.99258

You can see that the output also provides a 95% confidence interval of the mean BMI.

Some commonly used packages come with the R base package - this means that you don’t need to install and load these packages when you use any R functions. These packages will be automatically loaded when you start an R session. For example, the following R function prop.test() for testing population proportion is in package {stats}:

prop.test(75, 137, p =0.57, alternative = "greater")
## 
##  1-sample proportions test with continuity correction
## 
## data:  75 out of 137, null probability 0.57
## X-squared = 0.19977, df = 1, p-value = 0.6725
## alternative hypothesis: true p is greater than 0.57
## 95 percent confidence interval:
##  0.4736288 1.0000000
## sample estimates:
##         p 
## 0.5474453

There are more than 20,000 (twenty thousand!) R packages are available for various applications. We will use about five packages that require installation and explicit loading to access specific R functions for analysis. You don’t need to memorize the names of these packages—I encourage you to use AI tools like ChatGPT or related Copilot assistants to find the R functions you need for your analysis. I will also provide this information in my example code within the lecture notes.

LS0tDQp0aXRsZTogIkdldHRpbmcgU3RhcnRlZCB3aXRoIFIgYW5kIFJTdHVkaW8iDQphdXRob3I6ICJDaGVuZyBQZW5nIg0KZGF0ZTogIiAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRvY19jb2xsYXBzZWQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogc2hvdw0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHNtb290aF9zY3JvbGw6IHllcw0KICAgIHRoZW1lOiBsdW1lbg0KICBwZGZfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgZmlnX3dpZHRoOiA1DQogICAgZmlnX2hlaWdodDogNA0KLS0tDQoNCmBgYHtjc3MgZWNobyA9IEZBTFNFfQ0KDQpkaXYjVE9DIGxpIHsNCiAgICBsaXN0LXN0eWxlOm5vbmU7DQogICAgYmFja2dyb3VuZC1pbWFnZTpub25lOw0KICAgIGJhY2tncm91bmQtcmVwZWF0Om5vbmU7DQogICAgYmFja2dyb3VuZC1wb3NpdGlvbjowOw0KfQ0KaDEudGl0bGUgew0KICBmb250LXNpemU6IDI0cHg7DQogIGNvbG9yOiBEYXJrUmVkOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQpoNC5hdXRob3IgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogIGNvbG9yOiBEYXJrUmVkOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQpoNC5kYXRlIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgZm9udC1zaXplOiAxOHB4Ow0KICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgY29sb3I6IERhcmtCbHVlOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCmgxIHsgLyogSGVhZGVyIDMgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDIwcHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KaDIgeyAvKiBIZWFkZXIgMyAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoMyB7IC8qIEhlYWRlciAzIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxNnB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQpgYGANCg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmlmICghcmVxdWlyZSgia25pdHIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KICAgbGlicmFyeShrbml0cikNCn0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gRkFMU0UsICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwgICANCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHQgPSBUUlVFLCAgIA0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSkNCmBgYA0KDQpcDQoNCiMgSW50cm9kdWN0aW9uDQoNClRoaXMgbW9kdWxlIG91dGxpbmVzIHRoZSBvcGVuLXNvdXJjZSBjb21wdXRlciBzb2Z0d2FyZSBwcm9ncmFtIFIgKDxodHRwczovL3d3dy5yLXByb2plY3Qub3JnLz4pIGFuZCB0aGUgcGxhdGZvcm0gUlN0dWRpbyAoPGh0dHBzOi8vcG9zaXQuY28vZG93bmxvYWRzLz4pIHRvIGJlIHVzZWQgaW4gdGhpcyBhbmQgc3Vic2VxdWVudCBzdGF0aXN0aWNzIGNvdXJzZXMuDQoNCg0KIyBEb3dubG9hZCBhbmQgSW5zdGFsbGF0aW9uDQoNCkJvdGggKipSKiogYW5kICoqUlN0dWRpbyoqIGFyZSBmcmVlIGFuZCBvcGVuLXNvdXJjZS4gKipSKiogaXMgYSBwcm9ncmFtbWluZyBsYW5ndWFnZSB3aWRlbHkgdXNlZCBpbiBzdGF0aXN0aWNzIGFuZCBkYXRhIHNjaWVuY2UsIGluY2x1ZGluZyBtYWNoaW5lIGxlYXJuaW5nLCB3aGlsZSAqKlJTdHVkaW8qKiBpcyBhIGRhdGEgc2NpZW5jZSBwbGF0Zm9ybSB0aGF0IHNpbXBsaWZpZXMgd29ya2luZyB3aXRoICoqUioqLiBJbiBvdGhlciB3b3Jkcywgd2UgbmVlZCB0byBpbnN0YWxsIGJvdGggKipSKiogYW5kICoqUlN0dWRpbyoqIGFuZCB0aGVuIHVzZSAqKlIqKiB0aHJvdWdoICoqUlN0dWRpbyoqLg0KDQpUaGUgZm9sbG93aW5nIFlvdVR1YmUgdmlkZW8gYnkgVG9ueSBDYXJsc2VuIGRlbW9uc3RyYXRlcyB0aGUgc3RlcHMgZm9yIGRvd25sb2FkaW5nIGFuZCBpbnN0YWxsaW5nIGJvdGggcHJvZ3JhbXMuDQoNClwNCjxjZW50ZXI+PGEgaHJlZj0iaHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj00QWpGYkpzTk5iOCIgdGFyZ2V0PSJwb3B1cCIgDQogICAgICAgICAgICAgICAgICAgb25jbGljaz0id2luZG93Lm9wZW4oJ2h0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9NEFqRmJKc05OYjgnLA0KICAgICAgICAgICAgICAgICAgICAgICduYW1lJywnd2lkdGg9ODUwLGhlaWdodD01MDAnKSI+PGltZyBzcmMgPSAiaHR0cHM6Ly9wZW5nZHNjaS5naXRodWIuaW8vTUFUMTIxVzUvaW1nL1ZpZGVvSWNvbi5wbmciIHdpZHRoPSIyMDAiIGhlaWdodD0iMTIwIj48L2E+DQo8L2NlbnRlcj4NClwNCg0KUGxlYXNlIGZvbGxvdyB0aGUgc3RlcHMgdG8gaW5zdGFsbCB0aGVzZSB0d28gcHJvZ3JhbXMgb24geW91ciBtYWNoaW5lLiBZb3UgY2FuIGFsc28gdXNlIFIgU3R1ZGlvIG9uIFdDVSdzIFJhbWNsb3VkLiANCg0KDQojIEdldHRpbmcgU3RhcnRlZCB3aXRoIFIgYW5kIFJTdHVkaW8NCg0KVGhlIG5leHQgdmlkZW8gc2hvd3MgaG93IHRvIHVzZSBSIHRocm91Z2ggUlN0dWRpbyB3aXRoIHNvbWUgYmFzaWMgYXJpdGhtZXRpYyBvcGVyYXRpb25zIGFuZCBiYXNpYyBjb21tYW5kcyB0aGF0IHdpbGwgYmUgdXNlZCB0byBjb21wb3NlIHNvbWUgZm9ybXVsYXMgaW4gdGhpcyBjb3Vyc2UuDQoNClwNCg0KPGNlbnRlcj48YSBocmVmPSJodHRwczovL3d3dy55b3V0dWJlLmNvbS93YXRjaD92PUs5LXpEbXE3MzdJIiB0YXJnZXQ9InBvcHVwIiANCiAgICAgICAgICAgICAgICAgICBvbmNsaWNrPSJ3aW5kb3cub3BlbignaHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj1LOS16RG1xNzM3SScsDQogICAgICAgICAgICAgICAgICAgICAgJ25hbWUnLCd3aWR0aD04NTAsaGVpZ2h0PTUwMCcpIj48aW1nIHNyYyA9ICJodHRwczovL3Blbmdkc2NpLmdpdGh1Yi5pby9NQVQxMjFXNS9pbWcvVmlkZW9JY29uLnBuZyIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIxMjAiPjwvYT4NCjwvY2VudGVyPg0KDQpcDQoNCllvdSBjYW4gYWxzbyBjaGFuZ2UgdGhlIGFwcGVhcmFuY2Ugb2YgdGhlIFJTdHVkaW8gdXNlciBpbnRlcmZhY2UgKFVJKSB0byBnZXQgYSBtb3JlIGNvbWZvcnRhYmxlIGFuZCBiZXR0ZXIgVUkgYnkgZm9sbG93aW5nIHRoZSBuZXh0IGZldyBzdGVwczogDQoNCiogRnJvbSB0aGUgbWVudSBiYXIsIGdvIHRvICoqVG9vbHMqKiA+ICoqR2xvYmFsIE9wdGlvbnMqKg0KKiBDbGljayBvbiAqKkFwcGVhcmFuY2UqKg0KKiBDaGFuZ2UgdGhlICoqRWRpdG9yIGZvbnQgc2l6ZSoqIGlmIHlvdSB3YW50IHRvDQoqIFRyeSBvdXQgYSBmZXcgdGhlbWVzIGluIHRoZSAqKkVkaXRvciB0aGVtZSBib3gqKi4gKFRoZSBkZWZhdWx0IGlzICoqVGV4dG1hdGUqKi4gSSBwcmVmZXIgKipQYXN0ZWwgb24gRGFyayoqKS4NCiogT25jZSB5b3UgZmluZCBzb21ldGhpbmcgeW91IGxpa2UgKG9yIGp1c3Qgc3RpY2sgd2l0aCAqKlRleHRtYXRlKiogaWYgeW91IGFyZSBoYXBweSB3aXRoIHRoZSBkZWZhdWx0IGFwcGVhcmFuY2UpLCBjbGljayBvbiAqKk9LKiosIGFuZCBjb250aW51ZSB3aXRoIHRoaXMgdHV0b3JpYWwuDQoNCg0KDQpgYGB7ciBlY2hvPUZBTFNFLCBmaWcuYWxpZ24gPSJjZW50ZXIiLCAgb3V0LndpZHRoID0gJzg1JSd9DQppZiAoa25pdHI6Ojppc19sYXRleF9vdXRwdXQoKSkgew0KICBrbml0cjo6YXNpc19vdXRwdXQoJ1xcdXJse2h0dHBzOi8vcGVuZ2RzY2kuZ2l0aHViLmlvL1NUQTIwMC9naWYvUnNldHVwLmdpZn0nKQ0KfSBlbHNlIHsNCiAga25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIlIvUnNldHVwLmdpZiIpDQp9DQpgYGANCg0KDQpNeSBvd24gUlN0dWRpbyBVSSAodXNlciBpbnRlcmZhY2UpIGlzIHNob3duIGJlbG93ICgqKkZpbGUgPiBOZXcgRmlsZSA+IFIgU2NyaXB0KiopDQoNCmBgYHtyIGVjaG8gPSBGQUxTRSwgZmlnLmFsaWduPSdjZW50ZXInLCBvdXQud2lkdGg9IjEwMCUifQ0KaW5jbHVkZV9ncmFwaGljcygiTW9kdWxlMDAvUlN0dWRpby1XaW5kb3dzLnBuZyIpDQpgYGANCg0KQWZ0ZXIgY2xlYXJpbmcgdGhlICoqQ29uc29sZSoqIChib3R0b20tbGVmdCB3aW5kb3cpIGFuZCBtaW5pbWl6aW5nIHRoZSByaWdodCBzaWRlIHdpbmRvd3MgKHRvcC1yaWdodCBhbmQgYm90dG9tLXJpZ2h0IHdpbmRvd3MpLCB3ZSBoYXZlIHRoZSBmb2xsb3dpbmcgVUkgd2l0aCAqKlNjcmlwdCoqIHdpbmRvdyBhbmQgKipDb25zb2xlKiogd2luZG93Lg0KDQoNCmBgYHtyIGVjaG8gPSBGQUxTRSwgZmlnLmFsaWduPSdjZW50ZXInLCBvdXQud2lkdGg9IjEwMCUifQ0KaW5jbHVkZV9ncmFwaGljcygiTW9kdWxlMDAvUlN0dWRpby1Xb3JraW5nLVdpbmRvdy5wbmciKQ0KYGBgDQoNCkl0IGlzIGNvbnZlbmllbnQgZm9yIHlvdSB0byBzYXZlIGEgc2luZ2xlIGZpbGUgdGhhdCBpbmNsdWRlcyBhbGwgb2YgeW91ciBjb2RlIHRvIGJlIGRyYWZ0ZWQgZHVyaW5nIHRoZSBzZW1lc3Rlci4gV2Ugd2lsbCBkaXNjdXNzIGhvdyB0byBlZmZlY3RpdmVseSBvcmdhbml6ZSB5b3VyIGNvZGUgZm9yIGRpZmZlcmVudCBtb2R1bGVzIGxhdGVyLiANCg0KDQoNCiMgVXNpbmcgUiBBcyBBIENhbGN1bGF0b3INCg0KUiBjYW4gYmUgdXNlZCBhcyBhIHBvd2VyZnVsIGNhbGN1bGF0b3IgYnkgZW50ZXJpbmcgZXF1YXRpb25zIGRpcmVjdGx5IGF0IHRoZSBwcm9tcHQgaW4gdGhlIGNvbW1hbmQgY29uc29sZS4gU2ltcGx5IHR5cGUgeW91ciBhcml0aG1ldGljIGV4cHJlc3Npb24gYW5kIHByZXNzIEVOVEVSLiBSIHdpbGwgZXZhbHVhdGUgdGhlIGV4cHJlc3Npb25zIGFuZCByZXNwb25kIHdpdGggdGhlIHJlc3VsdC4gV2hpbGUgdGhpcyBpcyBhIHNpbXBsZSBpbnRlcmFjdGlvbiBpbnRlcmZhY2UsIHRoZXJlIGNvdWxkIGJlIHByb2JsZW1zIGlmIHlvdSBhcmUgbm90IGNhcmVmdWwuIFIgd2lsbCBub3JtYWxseSBleGVjdXRlIHlvdXIgYXJpdGhtZXRpYyBleHByZXNzaW9uIGJ5IGV2YWx1YXRpbmcgZWFjaCBpdGVtIGZyb20gbGVmdCB0byByaWdodCwgYnV0IHNvbWUgb3BlcmF0b3JzIGhhdmUgcHJlY2VkZW5jZSBpbiB0aGUgb3JkZXIgb2YgZXZhbHVhdGlvbi4gTGV0J3Mgc3RhcnQgd2l0aCBzb21lIHNpbXBsZSBleHByZXNzaW9ucyBhcyBleGFtcGxlcy4NCg0KDQojIyAqKlNpbXBsZSBBcml0aG1ldGljIEV4cHJlc3Npb25zKioNCg0KVGhlIG9wZXJhdG9ycyBSIHVzZXMgZm9yIGJhc2ljIGFyaXRobWV0aWMgYXJlOiAgYCssIC0sICosIC8sIF5gLiBUaGUgZm9sbG93aW5nIHRhYmxlIHByZXNlbnRzIHNvbWUgZXhhbXBsZXMuDQoNCg0KfCAgT3BlcmF0b3IgfCAgTWVhbmluZyB8IEV4YW1wbGUgRXhwcmVzc2lvbiAgfCAgUmVzdWx0IHwNCnw6LS0tLS0tLS0tLXw6LS0tLS0tLS0tLS0tLS18Oi0tLS0tLS0tLS0tLS0tLXw6LS0tLS0tLS18DQp8YCtgICAgIHxBZGRpdGlvbiAgICAgICAgICAgIHwgYDQgKyA4YCB8IDEyIHwNCnxgLWAgICAgfFN1YnRyYWN0aW9uICAgICAgICAgfCBgNSAtIDhgIHwgLTMgfA0KfGAqYCAgICB8TXVsdGlwbGljYXRpb24gICAgICB8IGA0ICogOC0yYCB8IDMwIHwNCnxgL2AgICAgfERpdmlzaW9uICAgICAgICAgICAgfCBgNCAvIDhgIHwgMC41IHwNCnxgXmAgICAgfEV4cG9uZW50aWF0aW9uICAgICAgfCBgNF4zYCAgIHwgNjQgfA0KDQpIZXJlIGlzIGhvdyBJIHBlcmZvcm1lZCB0aGUgYWJvdmUgb3BlcmF0aW9ucyBpbiBSU3R1ZGlvOg0KDQoxLiAqKk9wZW4gUlN0dWRpbyoqIChjbGljayB0aGUgUlN0dWRpbyBpY29uLCBpdCB3aWxsIGF1dG9tYXRpY2FsbHkgb3BlbiB0aGUgc2NyaXB0IHdpbmRvdywgQ29uc29sZSwgYW5kIG90aGVyIHdpbmRvd3Mgb24gdGhlIHJpZ2h0LWhhbmQgc2lkZSkuIE1pbmltaXplIHRoZSB3aW5kb3dzIG9uIHRoZSByaWdodC1oYW5kIHNpZGUgdG8ga2VlcCBvbmx5IFNjcmlwdCBhbmQgQ29uc29sZSB3aW5kb3dzLg0KDQoyLiAqKlR5cGUgdGhlIGV4cHJlc3Npb25zKiogaW4gdGhlICoqU2NyaXB0IHdpbmRvdyoqLiANCg0KMy4gKipIaWdobGlnaHQgdGhlIGV4cHJlc3Npb24qKiB5b3Ugd2FudCB0byBydW4sDQoNCjQuIFlvdSB3aWxsIHZpZXcgKipib3RoIGNvZGUgYW5kIHJlc3VsdHMqKiBpbiB0aGUgKipSIENvbnNvbGUqKg0KDQpUaGUgZm9sbG93aW5nIGlzIHRoZSBzY3JlZW5zaG90IG9mIG15IFJTdHVkaW8gVUkgKHdpdGggc29tZSBhbm5vdGF0aW9ucykNCg0KDQpgYGB7ciBlY2hvID0gRkFMU0UsIGZpZy5hbGlnbj0nY2VudGVyJywgb3V0LndpZHRoPSIxMDAlIn0NCmluY2x1ZGVfZ3JhcGhpY3MoIk1vZHVsZTAwL2FyaXRobWV0aWMtb3BlcmF0aW9ucy5wbmciKQ0KYGBgDQoNCg0KRnJvbSB0aGUgYWJvdmUgc2NyZWVuc2hvdCwgeW91IHNlZSB0aGF0IHVzaW5nIGhhc2h0YWdzIGNhbiBtYWtlIHlvdXIgY29kZSBtb3JlIG9yZ2FuaXplZC4NCg0KXA0KDQoNCiMjICoqSW5wdXQgRGF0YSBpbiBSKioNCg0KSW4gc3RhdGlzdGljcywgYSBkYXRhIHNldCBjb25zaXN0cyBvZiB2YWx1ZXMgb2YgbXVsdGlwbGUgbWVhc3VyZW1lbnRzIGZyb20gbXVsdGlwbGUgY2hhcmFjdGVyaXN0aWNzLiBGb3IgZXhhbXBsZSwgYSBkYXRhIHNldCBjb250YWlucyAqKmhlaWdodCoqLCAqKndlaWdodCoqLCBhbmQgKipnZW5kZXIqKiB0YWtlbiBmcm9tIGEgZ3JvdXAgb2YgJG4kIHN0dWRlbnRzLiANCg0KfCBvYnNlcnZhdGlvbiBJRCAgfCAgIGhlaWdodCAoJFgkKSB8ICAgd2VpZ2h0ICgkWSQpIHwgIEdlbmRlciAoJFokKQ0KfDotLS0tLS0tLS0tLS0tLS0tfDotLS0tLS0tLS0tLS0tLS18Oi0tLS0tLS0tLS0tLS0tLXw6LS0tLS0tLS0tLXwNCnwgMSAgICAgICAgICAgIHwgICR4XzEkICAgICAgICAgfCAgICR5XzEkICAgICAgICB8ICAgRiAgICAgfA0KfCAyICAgICAgICAgICAgfCAgJHhfMiQgICAgICAgICB8ICAgJHlfMiQgICAgICAgIHwgICBNICAgICB8DQp8ICRcdmRvdHMkICAgICB8ICAkXHZkb3RzJCAgICAgIHwgICAkXHZkb3RzJCAgICAgfCRcdmRvdHMkIHwgICANCnwgJG4tMSQgICAgICAgIHwgICR4X3tuLTF9JCAgICAgfCAgICR5X3tuLTF9JCAgICB8ICAgTSAgICAgfA0KfCAkbiQgICAgICAgICAgfCAgJHhfbiQgICAgICAgICB8ICAgJHlfbiQgICAgICAgIHwgICBGICAgICB8DQoNClRoZSBhYm92ZSBkYXRhIHNldCBoYXMgJG4kIHJvd3MsIGVhY2ggcm93IHJlY29yZHMgYSBzdHVkZW50J3MgKipoZWlnaHQqKiwgKip3ZWlnaHQqKiwgYW5kICoqZ2VuZGVyKiouIERpZmZlcmVudCBjb2x1bW5zIHJlcHJlc2VudCBkaWZmZXJlbnQgY2hhcmFjdGVyaXN0aWNzLCB3aGljaCBhcmUgY29tbW9ubHkgY2FsbGVkIHZhcmlhYmxlcy4gQSBkYXRhc2V0IGlzIHVzdWFsbHkgc2F2ZWQgaW4gYSBkaWZmZXJlbnQgZm9ybWF0LiBUaGUgbW9zdCBjb21tb24gZm9ybWF0cyBvZiBhIGZsYXQgZGF0YSBmaWxlIGFyZSBhIHRleHQgZmlsZSBgLnR4dGAgKHBsYWluIHRleHQgZmlsZSkuIElmIEV4Y2VsIGlzIHVzZWQgdG8gc3RvcmUgZGF0YSwgKipjb21tYS1zZXBhcmF0ZWQgdmFsdWVzKiogYC5jc3ZgLCBhbmQgICoqTWljcm9zb2Z0IEV4Y2VsIHNwcmVhZHNoZWV0cyoqIChgLnhsc2ApIG9yICoqRXhjZWwgT3BlbiBYTUwgU3ByZWFkc2hlZXQqKiAoYC54bHN4YCkuIEEgZGF0YSBzZXQgd2l0aCBhIGRpZmZlcmVudCBmb3JtYXQgcmVxdWlyZWQgYSBkaWZmZXJlbnQgKipSIGZ1bmN0aW9uKiogdG8gcmVhZCBkYXRhIGludG8gUi4gIA0KDQpBcyBhbiBleGFtcGxlLCBJIHNhdmUgdGhlIGZvbGxvd2luZyBkYXRhIHNldCBpbiBgQzpcY3BlbmdcU1RBMjAwYCBpbiBwbGFpbiB0ZXh0IGZvcm1hdCB3aXRoIGV4dGVuc2lvbiBgLnR4dGAgYW5kIGNvbW1hLXNlcGFyYXRlZCB2YWx1ZXMgd2l0aCBleHRlbnNpb24gYC5jc3ZgLiANCg0KYGBgYGBge30NCklEICAgaGVpZ2h0ICAgIHdlaWdodCAgIGdlbmRlcg0KMSAgICAgNjAgICAgICAgICAxMjAgICAgICBGDQoyICAgICA2NCAgICAgICAgIDExOSAgICAgIE0NCjMgICAgIDY4ICAgICAgICAgMTQ1ICAgICAgTQ0KNCAgICAgNzEgICAgICAgICAxMzIgICAgICBGDQpgYGANCg0KV2hlbiByZWFkaW5nIHRoZSBkYXRhIHNldCBpbnRvIFIsIHlvdSBuZWVkIHRvIHByb3ZpZGUgdGhlIHBhdGggdG8gdGhlIGRhdGEgZmlsZS4gVGhlIGZvbGxvd2luZyBzY3JlZW5zaG90IHNob3dzIGhvdyB0byB1c2UgYXBwcm9wcmlhdGUgKipSIGZ1bmN0aW9ucyoqIHRvIHJlYWQgdGhlIGRhdGFzZXQuDQoNCmBgYHtyIGVjaG8gPSBGQUxTRSwgZmlnLmFsaWduPSdjZW50ZXInLCBvdXQud2lkdGg9IjEwMCUifQ0KaW5jbHVkZV9ncmFwaGljcygiTW9kdWxlMDAvUmVhZERhdGEyUi5wbmciKQ0KYGBgDQoNCldlIGNhbiBhbHNvIGRlZmluZSBpbmRpdmlkdWFsIHZhcmlhYmxlcyBhbmQgdGhlbiBtYWtlIGEgZGF0YSBmcmFtZSB1c2luZyB0aGUgKipSIGZ1bmN0aW9uKiogYGRhdGEuZnJhbWUoKWAgYXMgc2hvd24gaW4gdGhlIGZvbGxvd2luZyAqKmNvZGUgY2h1bmsqKi4NCg0KYGBge3IgZWNobyA9IFRSVUV9DQojIGRlZmluZSBpbmRpdmlkdWFsIHZhcmlhYmxlcyBmaXJzdA0KSUQgPC0gYygxLDIsMyw0KSAgICAjIElEID0gb2JzZXJ2YXRpb24gaWQsIGxvd2VyIGNhc2UgYygpIGlzIGFuIFIgZnVuY3Rpb24gdXNlZCB0byBkZWZpbmUgYSB2ZWN0b3IuDQpoZWlnaHQgPC0gYyg2MCwgNjQsIDY4LCA3MSkNCndlaWdodCA8LSBjKDEyMCwgMTE5LCAxNDUsIDEzMikNCmdlbmRlciA8LSBjKCJGIiwgIk0iLCAiTSIsICJGIikgICAjIENhdGVnb3JpY2FsIHZhbHVlcyBtdXN0IGJlIGVuY2xvc2VkIGluIGRvdWJsZSBxdW90ZXMgYW5kIHNlcGFyYXRlZCBieSBjb21tYXMuDQojIHB1dCB0aGUgYWJvdmUgdmFyaWFibGVzIGluIGEgZGF0YWZyYW1lDQpoZWlnaHQud2VpZ2h0LmRhdGEgPC0gZGF0YS5mcmFtZShJRCA9IElELCBoZWlnaHQgPSBoZWlnaHQsIHdlaWdodCA9IHdlaWdodCwgZ2VuZGVyID0gZ2VuZGVyKSAgIyBkYXRhLmZyYW1lKCkgaXMgYW4gIFIgZnVuY3Rpb24NCmBgYA0KDQpZb3UgY2FuIGFsc28gZGVmaW5lIHRoZSBkYXRhIGZyYW1lIGRpcmVjdGx5IHVzaW5nIHRoZSBmb2xsb3dpbmcgY29kZS4NCg0KYGBge3IgZWNobyA9IFRSVUV9DQpoZWlnaHQud2VpZ2h0LmRhdGEuMDIgPC0gZGF0YS5mcmFtZSgNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSUQgPSBjKDEsMiwzLDQpLCAgICAgICAjIENBVVRJT046ICI9IiBDQU5OT1QgYmUgcmVwbGFjZWQgYnkgIjwtIiEhISENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGVpZ2h0ID0gYyg2MCwgNjQsIDY4LCA3MSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdlaWdodCA9IGMoMTIwLCAxMTksIDE0NSwgMTMyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZGVyID0gYygiRiIsICJNIiwgIk0iLCAiRiIpDQopDQpoZWlnaHQud2VpZ2h0LmRhdGEuMDINCmBgYA0KDQojIyBXb3JraW5nIFdpdGggRGF0YSBGcmFtZSANCg0KUXVpdGUgb2Z0ZW4sIHdlIG9ubHkgd29yayB3aXRoIG9uZSBvciB0d28gdmFyaWFibGVzIGluIGEgZGF0YSBmcmFtZSBpbnN0ZWFkIG9mIHRoZSBlbnRpcmUgZGF0YSBzZXQuIEZvciBleGFtcGxlLCB3ZSB3YW50IHRvIGNhbGN1bGF0ZSB0aGUgbWVhbiBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIHRoZSB2YXJpYWJsZSBgaGVpZ2h0YCBpbiB0aGUgYWJvdmUgZGF0YSBzZXQuIFdlIGNhbiBleHRyYWN0IGBoZWlnaHRgIGZyb20gdGhlIGRhdGEgZnJhbWUgd2UgZGVmaW5lZCB1c2luZyB0aGUgZm9sbG93aW5nIGNvZGUuDQoNCmBgYHtyIGVjaG8gPSBUUlVFfQ0KaGVpZ2h0IDwtIGhlaWdodC53ZWlnaHQuZGF0YS4wMiRoZWlnaHQgICAjIGRhdGFzZXRuYW1lICsgJCArIHZhcmlhYmxlbmFtZQ0KIyBDYWxjdWxhdGUgbWVhbiBhbmQgdmFyaWFuY2UNCnhiYXIgPC0gbWVhbihoZWlnaHQpICAjIGNvbXB1dGUgdGhlIG1lYW4gYW5kIHN0b3JlIGl0IGluIGEgdmFyaWFibGUgdW5kZXIgdGhlIG5hbWUgb2YgeGJhcg0KeGJhciAgICAgICAgICAgICAgICAgICMgcHJpbnQgb3V0IHRoZSByZXN1bHQNCnZhci5oZWlnaHQgPC0gdmFyKGhlaWdodCkNCnZhci5oZWlnaHQNCmBgYA0KDQoNCg0KIyMgKipTb21lIEJhc2ljIFN0YXRpc3RpY3MgYW5kIE1hdGhlbWF0aWNzIEZ1bmN0aW9ucyoqDQoNCk1vc3Qgb2YgeW91IGhhdmUgZXhwZXJpZW5jZSB1c2luZyBncmFwaGluZyBjYWxjdWxhdG9ycyBhbmQgcmVsZXZhbnQgZnVuY3Rpb25zLiBSIGhhcyBzaW1pbGFyIGJ1aWx0LWluIGZ1bmN0aW9ucyBmb3IgYmFzaWMgbWF0aGVtYXRpY2FsIGFuZCBzdGF0aXN0aWNhbCBjYWxjdWxhdGlvbnMuIFdlIHVzZSBgaGVpZ2h0YCBhbmQgYHdlaWdodGAgaW4gZXhhbXBsZXMgaW4gdGhlIGZvbGxvd2luZyB0YWJsZS4NCg0KDQp8IE1hdGggJiBTdGF0cyBmdW5jdGlvbiAgfCBSIGZ1bmN0aW9uICB8ICAgIEV4YW1wbGUgIENvZGUgICAgICAgIHwgICBSZXN1bHQgICB8DQp8Oi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfDotLS0tLS0tLS0tLXw6LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXw6LS0tLS0tLS0tLS18DQp8IG1lYW4gICAgICAgICAgICAgICAgICAgfCBgbWVhbigpYCAgICB8ICBgbWVhbihoZWlnaHQpYCAgICAgICAgIHwgICAgNjUuNzUgICB8ICAgICAgDQp8IHZhcmlhbmNlICAgICAgICAgICAgICAgfCBgdmFyKClgICAgICB8ICBgdmFyKGhlaWdodClgICAgICAgICAgIHwgICAgMjIuOTIgICB8ICANCnwgc3RhbmRhcmQgZGV2aWF0aW9uICAgICB8IGBzZCgpYCAgICAgIHwgIGBzZChoZWlnaHQpYCAgICAgICAgICAgfCAgICAgNC43OSAgIHwNCnwgY29ycmVsYXRpb24gY29lZmZpY2llbnQgfCBgY29yKClgICAgIHwgIGBjb3IoaGVpZ2h0LCB3ZWlnaHQpYCAgfCAgICAwLjY5MSAgIHwNCnwgc3VtbWF0aW9uIG9mIGRhdGEgdmFsdWVzfCBgc3VtKClgICAgIHwgIGBzdW0oaGVpZ2h0KWAgICAgICAgICAgfCAgICAyNjMgICAgIHwNCg0KDQojIyBDcml0aWNhbCBWYWx1ZXMgYW5kIExlZnQtdGFpbCBQcm9iYWJpbGl0aWVzDQoNCkluIHRlc3RpbmcgaHlwb3RoZXNlcywgd2UgY2FuIHVzZSBlaXRoZXIgdGhlIGNyaXRpY2FsIHZhbHVlIG9yIHAtdmFsdWUgbWV0aG9kcyB0byBtYWtlIGEgc3RhdGlzdGljYWwgZGVjaXNpb24uIFRoZSBuZXh0IHRhYmxlIGxpc3RzIHRoZSBSIGZ1bmN0aW9ucyBmb3IgY3JpdGljYWwgYW5kIHAtdmFsdWVzIGZyb20gbm9ybWFsIGFuZCB0IHRhYmxlcy4NCg0KDQp8IENyaXRpY2FsIFZhbHVlICAgICAgICAgICAgICAgIHwgZGVncmVlcyBvZiBmcmVlZG9tICB8ICAgIEV4YW1wbGUgIENvZGUgICAgICAgIHwgICBSZXN1bHQgICAgICB8DQp8Oi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXw6LS0tLS0tLS0tLS0tLS0tLS0tLS18Oi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXw6LS0tLS0tLS0tLS0tLS18DQp8ICQ5NVwlJCBub3JtYWwgY3JpdGljYWwgdmFsdWUgIHwgIE5BICAgICAgICAgICAgICAgICB8ICBgcW5vcm0oMC45NzUpYCAgICAgICAgIHwgICAgMS45NiAgICAgICB8ICAgICAgDQp8JDk1XCUkIG5vcm1hbCBjcml0aWNhbCB2YWx1ZSAgIHwgMjUgICAgICAgICAgICAgICAgICB8ICBgcXQoMC45NzUsIDI1KWAgICAgICAgIHwgICAgMi4wNTk1MzkgICB8ICANCg0KDQoNCg0KfCBsZWZ0LXRhaWwgIFByb2JhYmlsaXR5ICAgICAgICB8IGRlZ3JlZXMgb2YgZnJlZWRvbSAgfCAgICBFeGFtcGxlICBDb2RlICAgICAgICB8ICAgUmVzdWx0ICAgICAgfA0KfDotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18Oi0tLS0tLS0tLS0tLS0tLS0tLS0tfDotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18Oi0tLS0tLS0tLS0tLS0tfA0KfCAkUChUUyA8IDEuNDUpJCBub3JtYWwgdGFibGUgICB8ICBOQSAgICAgICAgICAgICAgICAgfCAgYHBub3JtKDEuNDUpYCAgICAgICAgICB8ICAgIDAuOTI2NDcwNyAgfCAgICAgIA0KfCAkUChUUyA8IDEuNDUpJCB0IHRhYmxlICAgICAgICB8ICAxNSAgICAgICAgICAgICAgICAgfCAgYHB0KDEuNDUsIDE1KWAgICAgICAgICB8ICAgIDAuOTE2MTc3MiAgfCANCg0KDQoNCg0KDQoNCiMjIEV2YWx1YXRlIEZvcm11bGFzDQoNCkp1c3QgbGlrZSB1c2luZyBhIGdyYXBoaW5nIGNhbGN1bGF0b3IsIHdlIHNvbWV0aW1lcyBuZWVkIHRvIGV2YWx1YXRlIGEgZm9ybXVsYS4gRm9yIGV4YW1wbGUsIHdoZW4gY29uc3RydWN0aW5nIGEgOTUlIG5vcm1hbCBjb25maWRlbmNlIGludGVydmFsIGJhc2VkIG9uIGdpdmVuIGRlc2NyaXB0aXZlIHN0YXRpc3RpY3MgKHJhdGhlciB0aGFuIHJhdyBkYXRhKSwgd2UgdXNlIHRoZSBmb2xsb3dpbmcgZm9ybXVsYS4NCg0KDQoNCiQkDQpcYmFye1h9IFxwbSBaX3tcYWxwaGEvMn1cZnJhY3tzfXtcc3FydHtufX0uDQokJA0KDQpXZSB1c2UgYW4gZXhhbXBsZSB0byBpbGx1c3RyYXRlIGhvdyB0byB3cml0ZSB0aGUgYWJvdmUgZm9ybXVsYSBpbiBSIHRvIGNhbGN1bGF0ZSB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbC4NCg0KKipFeGFtcGxlKio6IFRoZSBEZWFuIHdhbnRzIHRvIGVzdGltYXRlIHRoZSBtZWFuIG51bWJlciBvZiBob3VycyB0aGF0IHN0dWRlbnRzIHdvcmtlZCBwZXIgd2Vlay4gIEEgc2FtcGxlIG9mIDQ5IHN0dWRlbnRzIHNob3dlZCBhIG1lYW4gb2YgMjQgaG91cnMgd2l0aCBhIHN0YW5kYXJkIGRldmlhdGlvbiBvZiA0IGhvdXJzLiBUaGUgcG9pbnQgZXN0aW1hdGUgaXMgMjQgaG91cnMgKHNhbXBsZSBtZWFuKS4gV2hhdCBpcyB0aGUgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgZm9yIHRoZSBhdmVyYWdlIG51bWJlciBvZiBob3VycyB3b3JrZWQgcGVyIHdlZWsgYnkgdGhlIHN0dWRlbnRzPw0KDQoqcmVhc29uaW5nIHByb2Nlc3MqOiBzaW5jZSAkbj0zOSA+IDMwJCwgd2UgY2FuIHVzZSB0aGUgY2VudHJhbCBsaW1pdCB0aGVvcmVtIChDTFQpIHRvIGNsYWltIHRoYXQgJFxiYXJ7WH0kIGlzIGFwcHJveGltYXRlZCBieSBhIG5vcm1hbCBkaXN0cmlidXRpb24uIFRoZXJlZm9yZSwgJFpfe1xhbHBoYS8yfSQgY2FuIGJlIGZvdW5kIHVzaW5nIGBxbm9ybSgxLWFscGhhLzIpYC4gDQoNCmBgYHtyIGVjaG8gPSBUUlVFfQ0KIyMgQXNzaWduIHZhbHVlcyB0byB2YXJpYWJsZXMgaW4gdGhlIGZvcm11bGEgDQphbHBoYSA9IDEtMC45NSAgICMgYWxwaGENCnhiYXIgPSAyNCAgICMgc2FtcGxlIG1lYW4NCnN0ZGV2ID0gNCAgICMgc3RhbmRhcmQgZGV2aWF0aW9uDQpuID0gNDkNCiMjIGNyaXRpY2FsIHZhbHVlDQpaLjAuOTc1ID0gcW5vcm0oMC45NzUpICAgICMgYWxwaGEgPSAxIC0gOTUlIC0gMSAtIDAuOTUgPSAwLjA1LCAxIC0gYWxwaGEvMiA9IDEgLTAuMDI1ID0gMC45NzUNCiMjIGxvd2VyIGFuZCB1cHBlciBjb25maWRlbmNlIGxpbWl0cw0KTENMID0geGJhciAtIFouMC45NzUqKHN0ZGV2L3NxcnQobikpICAgIyBubyBzcXVhcmUgYW5kIGN1cmx5IGJyYWNrZXQgc2hvdWxkIGJlIHVzZWQgaW4gUg0KVUNMID0geGJhciArIFouMC45NzUqKHN0ZGV2L3NxcnQobikpIA0KIyMgV3JpdGUgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWwNCmNiaW5kKExDTCA9IExDTCwgVUNMID0gVUNMKSAgICAjIGNvbWJpbmVkIHRoZSB0d28gbGltaXRzIGluIGEgdHdvLWNvbHVtbiB0YWJsZSB3aXRoIG9uZSByb3cNCmBgYA0KDQojIFIgQnVpbHQtaW4gU3RhdGlzdGljcyBGdW5jdGlvbg0KDQpSIGhhcyBhIHJpY2ggYnVpbHQtaW4gZnVuY3Rpb25zIGZvciB2YXJpb3VzIHN0YXRpc3RpY2FsIGFuYWx5c2VzLiBOZXh0LCB3ZSBsaXN0IHNvbWUgb2YgdGhlIGZ1bmN0aW9ucyB0aGF0IGNhbiBwZXJmb3JtIGFsbCB0aGUgYW5hbHlzZXMgaW4gaW50cm9kdWN0b3J5IHN0YXRpc3RpY3MgbGlrZSBNQVQxMjEgYXQgV0NVLiBUaGVzZSBmdW5jdGlvbnMgYXJlIGNhbGxlZCB3aGVuIHlvdSBoYXZlIHJhdyBkYXRhIHN0b3JlZCBpbiB2YXJpYWJsZXMuICoqUmVtZW1iZXIsIGVhY2ggY29sdW1uIGluIGEgZGF0YSBmcmFtZSBpcyBhIHZhcmlhYmxlLioqDQoNCkZvciBjb252ZW5pZW5jZSwgd2UgdXNlIHRoZSBmb2xsb3dpbmcgcmF3IGRhdGEgc2V0IGNvbGxlY3RlZCBmcm9tIGEgZGlhYmV0ZXMgc3R1ZHksIHdoaWNoIGNhbiBiZSBmb3VuZCBhdCA8aHR0cHM6Ly9wZW5nZHNjaS5naXRodWIuaW8vU1RBMjAwL2RhdGFzZXQvZGlhYmV0ZXMtZGF0YXNldC5jc3Y+DQoNCldlIGZpcnN0IHJlYWQgdGhlIGFib3ZlIGRhdGEgdXNpbmcgdGhlIGNvbW1hbmQgZ2l2ZW4gcHJldmlvdXNseSBhbmQgZXh0cmFjdCB2YXJpYWJsZXMgdG8gcGVyZm9ybSBvbmUtc2FtcGxlLCB0d28tc2FtcGxlIHRlc3RzLCBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCwgYW5kIGxlYXN0IHNxdWFyZXMgcmVncmVzc2lvbi4NCg0KKipEYXRhIGxvYWRpbmcgYW5kIHZhcmlhYmxlIGV4dHJhY3Rpb24qKg0KDQpgYGB7cn0NCiMjIGxvYWRpbmcgZGF0YQ0KZGlhYmV0ZXMgPC0gcmVhZC5jc3YoImh0dHBzOi8vcGVuZ2RzY2kuZ2l0aHViLmlvL1NUQTIwMC9kYXRhc2V0L2RpYWJldGVzLWRhdGFzZXQuY3N2IikNCmRpYWJldHMuc3RhdHVzIDwtIGRpYWJldGVzJE91dGNvbWUgICAgICAjIGRhdHNldE5hbWUkdmFyaWFibGVOYW1lIGV4dHJhY3QgdmFyaWFibGUgZnJvbSBhIGRhdGEgc2V0DQpTa2luVGhpY2tuZXNzIDwtIGRpYWJldGVzJFNraW5UaGlja25lc3MgIyBleHRyYWN0IHNraW4gdGhpY2tuZXNzDQpCTUkgPC0gZGlhYmV0ZXMkQk1JICAgICAgICAgICAgICAgICAgICAgIyBleHRyYWN0IEJNSSAoYm9keSBtYXNzIGluZGV4KQ0KYGBgIA0KYGBge3IgdGFibGUyLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5ncz1GQUxTRSwgcmVzdWx0cz0nYXNpcyd9DQp0YWJsIDwtICINCnwgU3RhdGlzdGljYWwgVGFzayB8ICBCdWlsdC1pbiBSIEZ1bmN0aW9uICB8ICBFeGFtcGxlIHdpdGggRGF0YSB8IA0KfDotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfDotLS0tLS0tLS18Oi0tLS0tLS0tLS0tLS0tfA0KfCBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCAgICAgICB8IGBjb3IoKWAgIHwgYGNvcihCTUksIFNraW5UaGlja25lc3MpYCB8DQp8IGZpdmUtbnVtYmVyLXN1bW1hcnkgICAgICAgICAgIHwgYHN1bW1hcnkoKWB8IGBzdW1tYXJ5KEJNSSlgIHwNCnwgaGlzdG9ncmFtICAgICAgICAgICAgICAgICAgICAgfCBgaGlzdCgpYCAgICB8IGBoaXN0KFNraW5UaGlja25lc3MpYHwNCnwgc2NhdHRlciBwbG90ICAgICAgICAgICAgICAgICAgfCBgcGxvdCgpYCAgICB8IGBwbG90KEJNSSwgU2tpblRoaWNrbmVzcylgIHwNCnwgZnJlcXVlbmN5IHRhYmxlIChjYXRlZ29yaWNhbCBkYXRhKXwgYHRhYmxlKClgIHwgYHRhYmxlKE91dGNvbWUpYCB8DQp8IGxpbmVhciByZWdyZXNzaW9uICAgICAgICAgICAgIHwgYGxtKClgICB8IGBsbShCTUkgfiBkaWFiZXRzLnN0YXR1cylgIHwNCiINCmNhdCh0YWJsKSAjIG91dHB1dCB0aGUgdGFibGUgaW4gYSBmb3JtYXQgZ29vZCBmb3IgSFRNTC9QREYvZG9jeCBjb252ZXJzaW9uDQpgYGANCg0KDQojIFIgUGFja2FnZXMNCg0KQW4gUiBwYWNrYWdlIGlzIGEgY29sbGVjdGlvbiBvZiBmdW5jdGlvbnMsIGRhdGEsIGFuZCBkb2N1bWVudGF0aW9uIHRoYXQgZXh0ZW5kcyB0aGUgY2FwYWJpbGl0aWVzIG9mIGJhc2UgUi4gRGlmZmVyZW50IFIgZnVuY3Rpb25zIGluIGRpZmZlcmVudCBwYWNrYWdlcyBhbGxvdyB1c2VycyB0byBwZXJmb3JtIGRpZmZlcmVudCBzdGF0aXN0aWNhbCB0YXNrcy4gSW4gdGhpcyBjb3Vyc2UsIHdlIHdpbGwgdXNlIGEgZmV3IGZ1bmN0aW9ucyBhbmQgc29tZSBwYWNrYWdlcy4gVG8gdXNlIGFuIFIgZnVuY3Rpb24gaW4gYSBzcGVjaWZpYyBwYWNrYWdlLCB5b3UgbmVlZCB0byBsb2FkIHRoZSBwYWNrYWdlIHVzaW5nIHRoZSBmb2xsb3dpbmcgY29tbWFuZC4NCg0KYGBge30NCmlmICghcmVxdWlyZSgicGFja2FnZU5hbWUiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygicGFja2FnZU5hbWUiKQ0KICAgbGlicmFyeShwYWNrYWdlTmFtZSkNCn0NCmBgYA0KDQpGb3IgZXhhbXBsZSwgaWYgeW91IHdhbnQgdG8gcGVyZm9ybSBhIHotdGVzdCAoaS5lLiwgbm9ybWFsIHRlc3QpLCB3ZSBjYW4gdXNlIHRoZSBSIGZ1bmN0aW9uIGB6LnRlc3QoKWAgaW4gdGhlIHBhY2thZ2UuIFRoZSBmb2xsb3dpbmcgaXMgdGhlIGNvZGUgZm9yIHRlc3RpbmcgQk1JIEhvOiBtdSA8PSAzMCB2cyBIYTogbXUgPiAzMC4NCg0KYGBge3IgZWNobyA9IFRSVUV9DQojIyBpbnN0YWxsIGFuZCBsb2FkIHBhY2thZ2UNCmlmICghcmVxdWlyZSgiQlNEQSIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJCU0RBIikNCiAgIGxpYnJhcnkoQlNEQSkNCn0NCiMjIENhbGwgdGhlIGZ1bmN0aW9uIHRvIHBlcmZvcm0gYSBub3JtYWwgdGVzdA0KIyBIbzogbXUgPSAzMCB2cyBIYTogbXUgIT0gMzAsIHRoZSBhbHRlcm5hdGl2ZSBpcyAhPSwgdGhpcyBpcyBhIHR3by1zaWRlZCB0ZXN0DQojIElGIHRoZSB0ZXN0IGlzIHJpZ2h0LXRhaWxlZCwgdGhlIGFsdGVybmF0aXZlIE1VU1QgYmUgc3BlY2lmaWVkIGFzICJncmVhdGVyIiwNCiMgU2ltaWxhcmx5LCBpZiB0aGUgdGVzdCBpcyBsZWZ0LXRhaWxlZCwgdGhlIGFsdGVybmF0aXZlIE1VU1QgYmUgc3BlY2lmaWVkIGFzICJsZXNzIi4NCnoudGVzdCh4ID0gQk1JLCBzaWdtYS54ID0gc2QoQk1JKSwgbXUgPSAzMCwgYWx0ZXJuYXRpdmUgPSAidHdvLnNpZGVkIikNCmBgYA0KDQpZb3UgY2FuIHNlZSB0aGF0IHRoZSBvdXRwdXQgYWxzbyBwcm92aWRlcyBhIDk1JSBjb25maWRlbmNlIGludGVydmFsIG9mIHRoZSBtZWFuIEJNSS4NCg0KKipTb21lIGNvbW1vbmx5IHVzZWQgcGFja2FnZXMgY29tZSB3aXRoIHRoZSBSIGJhc2UgcGFja2FnZSoqIC0gdGhpcyBtZWFucyB0aGF0IHlvdSBkb24ndCBuZWVkIHRvIGluc3RhbGwgYW5kIGxvYWQgdGhlc2UgcGFja2FnZXMgd2hlbiB5b3UgdXNlIGFueSBSIGZ1bmN0aW9ucy4gVGhlc2UgcGFja2FnZXMgd2lsbCBiZSBhdXRvbWF0aWNhbGx5IGxvYWRlZCB3aGVuIHlvdSBzdGFydCBhbiBSIHNlc3Npb24uIEZvciBleGFtcGxlLCB0aGUgZm9sbG93aW5nIFIgZnVuY3Rpb24gYHByb3AudGVzdCgpYCBmb3IgdGVzdGluZyBwb3B1bGF0aW9uIHByb3BvcnRpb24gaXMgaW4gcGFja2FnZSB7c3RhdHN9Og0KDQpgYGB7ciBlY2hvID0gVFJVRX0NCnByb3AudGVzdCg3NSwgMTM3LCBwID0wLjU3LCBhbHRlcm5hdGl2ZSA9ICJncmVhdGVyIikNCmBgYA0KDQoNCjxmb250IGNvbG9yID0gInJlZCI+KipcY29sb3J7cmVkfVRoZXJlIGFyZSBtb3JlIHRoYW4gMjAsMDAwICh0d2VudHkgdGhvdXNhbmQhKSBSIHBhY2thZ2VzIGFyZSBhdmFpbGFibGUgZm9yIHZhcmlvdXMgYXBwbGljYXRpb25zLioqIDwvZm9udD4gPGZvbnQgY29sb3IgPSAgImJsdWUiPioqXGNvbG9ye2JsdWV9IFdlIHdpbGwgdXNlIGFib3V0IGZpdmUgcGFja2FnZXMgdGhhdCByZXF1aXJlIGluc3RhbGxhdGlvbiBhbmQgZXhwbGljaXQgbG9hZGluZyB0byBhY2Nlc3Mgc3BlY2lmaWMgUiBmdW5jdGlvbnMgZm9yIGFuYWx5c2lzLiBZb3UgZG9u4oCZdCBuZWVkIHRvIG1lbW9yaXplIHRoZSBuYW1lcyBvZiB0aGVzZSBwYWNrYWdlc+KAlEkgZW5jb3VyYWdlIHlvdSB0byB1c2UgQUkgdG9vbHMgbGlrZSBDaGF0R1BUIG9yIHJlbGF0ZWQgQ29waWxvdCBhc3Npc3RhbnRzIHRvIGZpbmQgdGhlIFIgZnVuY3Rpb25zIHlvdSBuZWVkIGZvciB5b3VyIGFuYWx5c2lzLiBJIHdpbGwgYWxzbyBwcm92aWRlIHRoaXMgaW5mb3JtYXRpb24gaW4gbXkgZXhhbXBsZSBjb2RlIHdpdGhpbiB0aGUgbGVjdHVyZSBub3Rlcy4qKjwvZm9udD4NCg0KDQoNCg0KDQoNCg==