Learning Objectives


Upon completing today’s lab activity, students should be able to do the following using R and RStudio:

  1. Produce basic R Markdown html lab report documents and use inline R codes within R Markdown.

  2. Produce basic R scripts and run them using the console or within R Markdown.

  3. Produce intermediate plots within R Markdown.

  4. Create custom data frames, create and call functions, use conditional statements, and use for-loops and while-loops.


Basic R Scripting


In RStudio, go to New File -> R Script. Copy and paste the code below into your R script and save it as “example-r-script.R”.

## This is an example R script

# print the text "Hello R!"
print("Hello R!")

# declaring variables, perform math operations, and print the results
x <- 2
y <- 2
z <- x^2 + y^2 # the operator "^" indicates exponents

# print strings and variables while concatenating them together
cat("x^2 + y^2 =", z, "where x =", x, "and y =", y)

You can also use paste to concatenate strings and print them using print.

The lines with # characters indicate that you are writing a comment and the machine will ignore those lines.

Now, there are three ways to run the script.

  1. You can do line by line runs by clicking a specific line in the script and click the “Run” button located in the upper right corner of the R studio panel.

  2. You can run the entire script by clicking the “Source” button located in the upper right corner of the R studio panel.

  3. You can type the source command into the console.

source("1-files/example-r-script.R")
## [1] "Hello R!"
## x^2 + y^2 = 8 where x = 2 and y = 2

Note that you must put the path of the R script correctly. In this case, the R script “example-r-script.R” is in the “1-files” directory or folder.


R Markdown


To make reproducible reports, R Markdown provides quick and easy typesetting method. R Markdown can embed executable R code snippets and can run codes that produces plots. You can write your report along with R code snippets with the knitr syntax. You can then convert your document into several common formats such as pdf or html. Visit rmarkdown.rstudio.com for more details.


For HTML File

In RStudio, go to New File -> R Markdown. Then, choose “From Template” and then choose “Lab Report” from the list of templates. This template will only exist if you have installed the openintro package.


For PDF File

In RStudio, go to New File -> R Markdown. Then, choose “Document” and then choose “PDF” from the list of output format. This template will work if you have latexpdf package installed.

Please put the code snippet - shown below - at the beginning of the Rmd assignment template file if it does not exist.

---
title: '**Lab 1 - MATH 141**'
header-includes: |
  \usepackage{fancyhdr}
  \pagestyle{fancy}
  \fancyhead[CO,C]{Homework 1 - MATH 141}
  \fancyfoot[CO,C]{}
  \fancyfoot[C]{\thepage}
  \usepackage{float}
output:
  bookdown::pdf_document2:
    fig_caption: yes
    toc: no
    number_section: no
urlcolor: red
---


Data Frames


A data frame is a table or a two-dimensional array-like structure in which each column contains values of one variable and each row contains one set of values from each column.

Characteristics of a data frame:

  • The column names should be non-empty.

  • The row names should be unique.

  • The data stored in a data frame can be of numeric, factor or character type.

  • Each column should contain same number of data items.


Creating Data Frames

library(tidyverse)
# Create the data frame.
data_example <- data.frame(
   my_ranking = c(1:5),
   superheroes = c("Spiderman","Shang-Chi","Scarlet Witch","Doctor Strange","Black Panther"),
   subjective_power_scale = c(10000,1000,1000,900,900)
)
# Print the data frame.         
glimpse(data_example)
## Rows: 5
## Columns: 3
## $ my_ranking             <int> 1, 2, 3, 4, 5
## $ superheroes            <chr> "Spiderman", "Shang-Chi", "Scarlet Witch", "Doc…
## $ subjective_power_scale <dbl> 10000, 1000, 1000, 900, 900

The keyword for creating a dataframe in R is data.frame. Each parameter corresponds to the columns while the items in the lists corresponds to the rows. Notice that the name of the variable for each list is the default name for the columns. The rows are automatically have integer indices. This type of data structure is the same as you have seen in the previous lab.


Adding Columns

# Add the "subjective_pair" column.
data_example$subjective_pair <- c("Black Panther","Doctor Strange","Shang-Chi","Doctor Strange","Scarlet Witch")
# Add the "enemy" column.
data_example$enemy <- c("Green Goblin","Wenwu","Agatha Harkness","Dormammu","Erik Killmonger")
v <- data_example
glimpse(v)
## Rows: 5
## Columns: 5
## $ my_ranking             <int> 1, 2, 3, 4, 5
## $ superheroes            <chr> "Spiderman", "Shang-Chi", "Scarlet Witch", "Doc…
## $ subjective_power_scale <dbl> 10000, 1000, 1000, 900, 900
## $ subjective_pair        <chr> "Black Panther", "Doctor Strange", "Shang-Chi",…
## $ enemy                  <chr> "Green Goblin", "Wenwu", "Agatha Harkness", "Do…


Adding Rows

# Create the second data frame
data_new <- data.frame(
   my_ranking = c(6:8), 
   superheroes = c("Naruto","Saitama","Black Widow"),
   subjective_power_scale = c(700,700,800), 
   subjective_pair = c("Spiderman","Doctor Strange","Shang-Chi"),
   enemy = c("Sasuke","Unknown","General Dreykov")
)

# Bind the two data frames.
data_example_final <- rbind(data_example,data_new)
glimpse(data_example_final)
## Rows: 8
## Columns: 5
## $ my_ranking             <int> 1, 2, 3, 4, 5, 6, 7, 8
## $ superheroes            <chr> "Spiderman", "Shang-Chi", "Scarlet Witch", "Doc…
## $ subjective_power_scale <dbl> 10000, 1000, 1000, 900, 900, 700, 700, 800
## $ subjective_pair        <chr> "Black Panther", "Doctor Strange", "Shang-Chi",…
## $ enemy                  <chr> "Green Goblin", "Wenwu", "Agatha Harkness", "Do…

The keyword for adding rows to an existing data frame in R is rbind where the inputs must be data frames with the same columns.


Conditional Statements


Conditional statements in programming are define one or more conditions to be evaluated or tested by the program, as well as a statement or statements to be performed if the condition is true, and optionally, other statements to be executed if the condition is false.


if Statement

x <- 5
if(x > 0){
print("positive number")
}
## [1] "positive number"


if-else statement

x <- -5
if (x > 0) {
  print("positive number")
} else {
  print("negative number")
}
## [1] "negative number"


else-if statement

x <- 0
if (x > 0) {
  print("positive number")
} else if (x == 0) {
  print("zero")
} else {
  print("negative number")
}
## [1] "zero"


Conditional Subsetting

The code snippet below are generated using the iris data set, which is part of the base R installation.


  • Option A
# subsetting by category
setosa_sub <- iris[iris$Species == "setosa", ]
glimpse(setosa_sub)
## Rows: 50
## Columns: 5
## $ Sepal.Length <dbl> 5.1, 4.9, 4.7, 4.6, 5.0, 5.4, 4.6, 5.0, 4.4, 4.9, 5.4, 4.…
## $ Sepal.Width  <dbl> 3.5, 3.0, 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3.1, 3.7, 3.…
## $ Petal.Length <dbl> 1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4, 1.5, 1.4, 1.5, 1.5, 1.…
## $ Petal.Width  <dbl> 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0.1, 0.2, 0.…
## $ Species      <fct> setosa, setosa, setosa, setosa, setosa, setosa, setosa, s…
# subsetting numerical values
sepal_length_sub <- iris[iris$Sepal.Length >= 4, ]
glimpse(sepal_length_sub)
## Rows: 150
## Columns: 5
## $ Sepal.Length <dbl> 5.1, 4.9, 4.7, 4.6, 5.0, 5.4, 4.6, 5.0, 4.4, 4.9, 5.4, 4.…
## $ Sepal.Width  <dbl> 3.5, 3.0, 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3.1, 3.7, 3.…
## $ Petal.Length <dbl> 1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4, 1.5, 1.4, 1.5, 1.5, 1.…
## $ Petal.Width  <dbl> 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0.1, 0.2, 0.…
## $ Species      <fct> setosa, setosa, setosa, setosa, setosa, setosa, setosa, s…
# subsetting numerical values within a range
sepal_length_sub_range <- iris[iris$Sepal.Length >= 5.10 & iris$Sepal.Length <= 6.40, ]
glimpse(sepal_length_sub_range)
## Rows: 83
## Columns: 5
## $ Sepal.Length <dbl> 5.1, 5.4, 5.4, 5.8, 5.7, 5.4, 5.1, 5.7, 5.1, 5.4, 5.1, 5.…
## $ Sepal.Width  <dbl> 3.5, 3.9, 3.7, 4.0, 4.4, 3.9, 3.5, 3.8, 3.8, 3.4, 3.7, 3.…
## $ Petal.Length <dbl> 1.4, 1.7, 1.5, 1.2, 1.5, 1.3, 1.4, 1.7, 1.5, 1.7, 1.5, 1.…
## $ Petal.Width  <dbl> 0.2, 0.4, 0.2, 0.2, 0.4, 0.4, 0.3, 0.3, 0.3, 0.2, 0.4, 0.…
## $ Species      <fct> setosa, setosa, setosa, setosa, setosa, setosa, setosa, s…


  • Option B
# subsetting by category
setosa_sub<- subset(iris, Species == "setosa")
glimpse(setosa_sub)
## Rows: 50
## Columns: 5
## $ Sepal.Length <dbl> 5.1, 4.9, 4.7, 4.6, 5.0, 5.4, 4.6, 5.0, 4.4, 4.9, 5.4, 4.…
## $ Sepal.Width  <dbl> 3.5, 3.0, 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3.1, 3.7, 3.…
## $ Petal.Length <dbl> 1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4, 1.5, 1.4, 1.5, 1.5, 1.…
## $ Petal.Width  <dbl> 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0.1, 0.2, 0.…
## $ Species      <fct> setosa, setosa, setosa, setosa, setosa, setosa, setosa, s…
# subsetting numerical values
sepal_length_sub <- subset(iris, Sepal.Length >= 4)
glimpse(sepal_length_sub)
## Rows: 150
## Columns: 5
## $ Sepal.Length <dbl> 5.1, 4.9, 4.7, 4.6, 5.0, 5.4, 4.6, 5.0, 4.4, 4.9, 5.4, 4.…
## $ Sepal.Width  <dbl> 3.5, 3.0, 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3.1, 3.7, 3.…
## $ Petal.Length <dbl> 1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4, 1.5, 1.4, 1.5, 1.5, 1.…
## $ Petal.Width  <dbl> 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0.1, 0.2, 0.…
## $ Species      <fct> setosa, setosa, setosa, setosa, setosa, setosa, setosa, s…
# subsetting numerical values within a range
sepal_length_sub_range <- subset(iris, Sepal.Length >= 5.10 & Sepal.Length <= 6.40)
glimpse(sepal_length_sub_range)
## Rows: 83
## Columns: 5
## $ Sepal.Length <dbl> 5.1, 5.4, 5.4, 5.8, 5.7, 5.4, 5.1, 5.7, 5.1, 5.4, 5.1, 5.…
## $ Sepal.Width  <dbl> 3.5, 3.9, 3.7, 4.0, 4.4, 3.9, 3.5, 3.8, 3.8, 3.4, 3.7, 3.…
## $ Petal.Length <dbl> 1.4, 1.7, 1.5, 1.2, 1.5, 1.3, 1.4, 1.7, 1.5, 1.7, 1.5, 1.…
## $ Petal.Width  <dbl> 0.2, 0.4, 0.2, 0.2, 0.4, 0.4, 0.3, 0.3, 0.3, 0.2, 0.4, 0.…
## $ Species      <fct> setosa, setosa, setosa, setosa, setosa, setosa, setosa, s…


Loops


You may find yourself in a position where you need to run a block of code multiple times. Statements are typically executed in order. A function’s first statement is executed first, then the second, and so on.


for-loops

A for-loop iterates on a list until it reaches the last element.


  • Iterating through a vector of integers
for(i in 1:10) { # Head of for-loop
 
  x1 <- i^2      # Code block where each interger is squared
  print(x1)      # Print results
}
## [1] 1
## [1] 4
## [1] 9
## [1] 16
## [1] 25
## [1] 36
## [1] 49
## [1] 64
## [1] 81
## [1] 100


  • Iterating through a vector of strings
letters_vector = c('A','B','C','D','E')
for(i in letters_vector) { # loop over character vector
  cat("My answer is", i, "for sure. \n")  # concatenate strings while printing in every new line
}
## My answer is A for sure. 
## My answer is B for sure. 
## My answer is C for sure. 
## My answer is D for sure. 
## My answer is E for sure.

You can also use paste to concatenate strings and print them using print.


  • Storing iterated results in to a vector by appending.
x <- numeric() # Create empty data numeric object

for(i in 1:10) {  # Head of for-loop
  x <- c(x, i^2)  # Code block where each interger is squared
}
print(x)
##  [1]   1   4   9  16  25  36  49  64  81 100
  • Iterating through a vector but must stop if a condition is met.
x <- numeric() # Create empty data numeric object

for(i in 1:100) {  # Head of for-loop
  x <- c(x, i^2)  # Code block where each interger is squared
  
  # conditional statement: if i^2 > 2000, the loop will stop
  if (i^2 > 2000) {
    break
  }
}
print(x)
##  [1]    1    4    9   16   25   36   49   64   81  100  121  144  169  196  225
## [16]  256  289  324  361  400  441  484  529  576  625  676  729  784  841  900
## [31]  961 1024 1089 1156 1225 1296 1369 1444 1521 1600 1681 1764 1849 1936 2025


while-loops

A while-loop is method of iterating while a condition is true. While a given condition is true, it repeats a statement or a series of statements. Before performing the loop body, it checks the condition.


  • Iterating until a condition is met or not met.
i <- 1
while (i < 6) { # iterate while i is less than 6
print(i)
i = i+1 # add 1 in each iteration. if you miss this part you will end up in an infinit loop
print(i)
}
## [1] 1
## [1] 2
## [1] 2
## [1] 3
## [1] 3
## [1] 4
## [1] 4
## [1] 5
## [1] 5
## [1] 6

The for-loop and while-loop can be similar but the while-loop needs a condition in order for it to work.


Creating and Calling Functions


A function is a collection of statements that work together to accomplish a specified goal. R comes with a vast variety of built-in functions, and users can also construct their own.

A function in R is an object, which allows the R interpreter to send control to the function as well as any parameters that may be required for the function to complete the operations.

The function then completes its duty and returns control as well as any results that may have been saved in other objects to the interpreter.

R function syntax:

function_1 <- function(...) {
   # put operations here
}


Function with one variable.

# Create a function to print squares of numbers in sequence.
function_1 <- function(a) {
   for(i in 1:a) {
      b <- i^2
      print(b) # only prints the output
   }
}

# Call the function new.function supplying 6 as an argument.
function_1(6)
## [1] 1
## [1] 4
## [1] 9
## [1] 16
## [1] 25
## [1] 36


Function with two variables.

# Create a function to print sum of squares of two numbers.
function_2 <- function(a,b) {
   c <- a^2 + b^2
   print(c) # only prints the output
}

# Call the function supplying 6 as an argument.
function_2(6,6)
## [1] 72


Function using Return

# Create a function to print sum of squares of two numbers.
function_2 <- function(a,b) {
   c <- a^2 + b^2
   return(c) # returns value c
}

# Call the function supplying 6 as an argument.
function_2(6,6)
## [1] 72


Intermediate Figures


Scatter Plots with Groups

The figures below are generated using the iris data set, which is part of the base R installation.


  • Using Base R.
plot(iris$Sepal.Length, iris$Sepal.Width, # x and y data
     pch=21, # dot design
     bg=c("red","green3","blue")[unclass(iris$Species)], # color for each group
     main="Edgar Anderson's Iris Data",  # plot title
     xlab = "Sepal Length", # x label
     ylab = "Sepal Width") # y label
legend('topright',levels(iris$Species),col=c("red","green3","blue"),pch=c(21,21,21))


  • Using ggplot2.
library(ggplot2)
scatter <- ggplot(data=iris, aes(x = Sepal.Length, y = Sepal.Width)) # using the iris data
scatter + geom_point(aes(color=Species, shape=Species), size = 1.5) + # scatter plot
  xlab("Sepal Length") +  ylab("Sepal Width") + # x and y label
  ggtitle("Edgar Anderson's Iris Data")


Histograms with Groups

The figures below are generated using the iris data set, which is part of the base R installation.


  • Using ggplot2.
library(ggplot2)
histogram <- ggplot(data=iris, aes(x=Sepal.Length))
histogram + geom_histogram(binwidth=0.2, color="black", aes(fill=Species)) + 
  xlab("Sepal Length") +  ylab("Frequency") + ggtitle("Histogram of Sepal Length")


Boxplots with Groups

The figures below are generated using the iris data set, which is part of the base R installation.


  • Using ggplot2.
library(ggplot2)
boxplot <- ggplot(data=iris, aes(x=Sepal.Length))
boxplot + geom_boxplot(color="black", aes(fill=Species)) + 
  xlab("Sepal Length") + ggtitle("Boxplot of Sepal Length") + 
  theme(axis.ticks.y = element_blank(), # it removes the y axis ticks and texts
        axis.text.y = element_blank())


Line Plots with Groups


The plots below are generated using a synthentic data.

  • Using ggplot2.
# create synthetic data
groups <- c("A","B")
x_vals_seq <- seq(0, 1, length.out = 9) # generate a sequence of equally spaced numbers
x_values <- rep(x_vals_seq,2) # replicate vector twice
y_values <- c(1, 2, 2, 4, 5, 4, 4, 3, 1, 2, 4, 4, 8, 10, 8, 8, 6, 2)
df2 <- data.frame(letter=rep(groups, each=9), # replicate A and B 9 times each
                  x=rep(x_values,2), # independent variable
                  y=y_values) # dependent variable
glimpse(df2)
## Rows: 36
## Columns: 3
## $ letter <chr> "A", "A", "A", "A", "A", "A", "A", "A", "A", "B", "B", "B", "B"…
## $ x      <dbl> 0.000, 0.125, 0.250, 0.375, 0.500, 0.625, 0.750, 0.875, 1.000, …
## $ y      <dbl> 1, 2, 2, 4, 5, 4, 4, 3, 1, 2, 4, 4, 8, 10, 8, 8, 6, 2, 1, 2, 2,…
library(ggplot2)
p<-ggplot(df2, aes(x=x, y=y, group=letter)) +
  geom_line(aes(color=letter))+
  geom_point(aes(color=letter))
p


Lab Exercises


I. Linear Function

Consider the linear function written below with parameters \(a\) and \(b\).

\[y(x;a,b) = ax + b\] where \(x\) is the independent variable and \(y\) is the dependent variable. Here, the slope of the line is \(a\) and intercept is \(b\).

  1. Write an R function which outputs the dependent variable \(y\) and takes in the independent variable \(x\), and the parameters \(a\) and \(b\).

  2. Using 3 different values of \(a\) and \(b\) (A:\(a=1,b=1\), B:\(a=1.25,b=1.2\), and C:\(a=2,b=1.5\)), create a dataframe with columns “line”, “x”, and “y”. Use the seq command to create a vector of \(x\) values from 0 to 1 with length 10. Use the rep command to generate \(x\) values for the three groups. Use your R function to generate \(y\) values using your \(x\) values as inputs. The “line” column should contain the line groups A, B, and C. Use glimpse to show your dataframe.

  3. Use ggplot to plot the lines on the same figure with proper line group labels.


II. United States Counties

Consider the county data set, which can be found in the usdata R package. Also, this dataset can be accessed as a csv file, county.

  1. Use ggplot to plot histograms of “pop_change” variable with categories from the “metro” variable. Make sure to label the x and y axis properly. What can you tell about the change in population whether the county has access to a metro or not?

  2. Use ggplot to plot histograms of “per_capita_income” variable with categories from the “median_edu” variable. Make sure to label the x and y axis properly. Describe the distributions between the levels of the “median_edu” variable. Is there a strong association between “median_edu” and “per_capita_income”? Explain why.

  3. Use ggplot to plot a scatterplot of “unemployment_rate” versus “poverty _rate” variables with categories from the “median_edu”. Make sure to label the x and y axis properly. Is there an association between “unemployment_rate” and “poverty _rate”? Are there any differences across the “median_edu” levels?

  4. Create a subset of the data where we only take rows with the states Washington, Oregon, and California.

  5. Using the subset you just created, create boxplots of “pop_change” variable with categories from the “state” variable. Make sure to label the x and y axis properly. Based on the medians shown on the boxplots, which state has the lowest and highest population change?

  6. Using the subset you just created, create boxplots of “per_capita_income” variable with categories from the “median_edu” variable. Make sure to label the x and y axis properly. Based on the medians shown on the boxplots, which state has the lowest and highest per capita income?


LS0tCnRpdGxlOiAiMSAtIFIgc2NyaXB0aW5nIGFuZCBSIE1hcmtkb3duIgphdXRob3I6ICJBbGV4IEpvaG4gUXVpamFubyIKZGF0ZTogIjA5LzA3LzIwMjEiCm91dHB1dDogb3BlbmludHJvOjpsYWJfcmVwb3J0Ci0tLQoKIyMgKipMZWFybmluZyBPYmplY3RpdmVzKioKCjxicj4KClVwb24gY29tcGxldGluZyB0b2RheSdzIGxhYiBhY3Rpdml0eSwgc3R1ZGVudHMgc2hvdWxkIGJlIGFibGUgdG8gZG8gdGhlIGZvbGxvd2luZyB1c2luZyBSIGFuZCBSU3R1ZGlvOgoKICAxLiBQcm9kdWNlIGJhc2ljIFIgTWFya2Rvd24gaHRtbCBsYWIgcmVwb3J0IGRvY3VtZW50cyBhbmQgdXNlIGlubGluZSBSIGNvZGVzIHdpdGhpbiBSIE1hcmtkb3duLgogIAogIDIuIFByb2R1Y2UgYmFzaWMgUiBzY3JpcHRzIGFuZCBydW4gdGhlbSB1c2luZyB0aGUgY29uc29sZSBvciB3aXRoaW4gUiBNYXJrZG93bi4KICAKICAzLiBQcm9kdWNlIGludGVybWVkaWF0ZSBwbG90cyB3aXRoaW4gUiBNYXJrZG93bi4KICAKICA0LiBDcmVhdGUgY3VzdG9tIGRhdGEgZnJhbWVzLCBjcmVhdGUgYW5kIGNhbGwgZnVuY3Rpb25zLCB1c2UgY29uZGl0aW9uYWwgc3RhdGVtZW50cywgYW5kIHVzZSBmb3ItbG9vcHMgYW5kIHdoaWxlLWxvb3BzLgogIAo8YnI+CgojIyAqKkJhc2ljIFIgU2NyaXB0aW5nKioKCjxicj4KCkluIFJTdHVkaW8sIGdvIHRvIE5ldyBGaWxlIC0+IFIgU2NyaXB0LiBDb3B5IGFuZCBwYXN0ZSB0aGUgY29kZSBiZWxvdyBpbnRvIHlvdXIgUiBzY3JpcHQgYW5kIHNhdmUgaXQgYXMgImV4YW1wbGUtci1zY3JpcHQuUiIuCgpgYGAKIyMgVGhpcyBpcyBhbiBleGFtcGxlIFIgc2NyaXB0CgojIHByaW50IHRoZSB0ZXh0ICJIZWxsbyBSISIKcHJpbnQoIkhlbGxvIFIhIikKCiMgZGVjbGFyaW5nIHZhcmlhYmxlcywgcGVyZm9ybSBtYXRoIG9wZXJhdGlvbnMsIGFuZCBwcmludCB0aGUgcmVzdWx0cwp4IDwtIDIKeSA8LSAyCnogPC0geF4yICsgeV4yICMgdGhlIG9wZXJhdG9yICJeIiBpbmRpY2F0ZXMgZXhwb25lbnRzCgojIHByaW50IHN0cmluZ3MgYW5kIHZhcmlhYmxlcyB3aGlsZSBjb25jYXRlbmF0aW5nIHRoZW0gdG9nZXRoZXIKY2F0KCJ4XjIgKyB5XjIgPSIsIHosICJ3aGVyZSB4ID0iLCB4LCAiYW5kIHkgPSIsIHkpCmBgYAoKWW91IGNhbiBhbHNvIHVzZSBgcGFzdGVgIHRvIGNvbmNhdGVuYXRlIHN0cmluZ3MgYW5kIHByaW50IHRoZW0gdXNpbmcgYHByaW50YC4KClRoZSBsaW5lcyB3aXRoIGAjYCBjaGFyYWN0ZXJzIGluZGljYXRlIHRoYXQgeW91IGFyZSB3cml0aW5nIGEgY29tbWVudCBhbmQgdGhlIG1hY2hpbmUgd2lsbCBpZ25vcmUgdGhvc2UgbGluZXMuCgpOb3csIHRoZXJlIGFyZSB0aHJlZSB3YXlzIHRvIHJ1biB0aGUgc2NyaXB0LgoKICAxLiBZb3UgY2FuIGRvIGxpbmUgYnkgbGluZSBydW5zIGJ5IGNsaWNraW5nIGEgc3BlY2lmaWMgbGluZSBpbiB0aGUgc2NyaXB0IGFuZCBjbGljayB0aGUgIlJ1biIgYnV0dG9uIGxvY2F0ZWQgaW4gdGhlIHVwcGVyIHJpZ2h0IGNvcm5lciBvZiB0aGUgUiBzdHVkaW8gcGFuZWwuCiAgCiAgMi4gWW91IGNhbiBydW4gdGhlIGVudGlyZSBzY3JpcHQgYnkgY2xpY2tpbmcgdGhlICJTb3VyY2UiIGJ1dHRvbiBsb2NhdGVkIGluIHRoZSB1cHBlciByaWdodCBjb3JuZXIgb2YgdGhlIFIgc3R1ZGlvIHBhbmVsLgogIAogIDMuIFlvdSBjYW4gdHlwZSB0aGUgYHNvdXJjZWAgY29tbWFuZCBpbnRvIHRoZSBjb25zb2xlLgogIApgYGB7ciBzb3VyY2luZy1zY3JpcHQsIG1lc3NhZ2U9RkFMU0V9CnNvdXJjZSgiMS1maWxlcy9leGFtcGxlLXItc2NyaXB0LlIiKQpgYGAKCk5vdGUgdGhhdCB5b3UgbXVzdCBwdXQgdGhlIHBhdGggb2YgdGhlIFIgc2NyaXB0IGNvcnJlY3RseS4gSW4gdGhpcyBjYXNlLCB0aGUgUiBzY3JpcHQgImV4YW1wbGUtci1zY3JpcHQuUiIgaXMgaW4gdGhlICIxLWZpbGVzIiBkaXJlY3Rvcnkgb3IgZm9sZGVyLgoKPGJyPgoKIyMgKipSIE1hcmtkb3duKioKCjxicj4KClRvIG1ha2UgcmVwcm9kdWNpYmxlIHJlcG9ydHMsIFIgTWFya2Rvd24gcHJvdmlkZXMgcXVpY2sgYW5kIGVhc3kgdHlwZXNldHRpbmcgbWV0aG9kLiBSIE1hcmtkb3duIGNhbiBlbWJlZCBleGVjdXRhYmxlIFIgY29kZSBzbmlwcGV0cyBhbmQgY2FuIHJ1biBjb2RlcyB0aGF0IHByb2R1Y2VzIHBsb3RzLiBZb3UgY2FuIHdyaXRlIHlvdXIgcmVwb3J0IGFsb25nIHdpdGggUiBjb2RlIHNuaXBwZXRzIHdpdGggdGhlIGtuaXRyIHN5bnRheC4gWW91IGNhbiB0aGVuIGNvbnZlcnQgeW91ciBkb2N1bWVudCBpbnRvIHNldmVyYWwgY29tbW9uIGZvcm1hdHMgc3VjaCBhcyBwZGYgb3IgaHRtbC4gVmlzaXQgW3JtYXJrZG93bi5yc3R1ZGlvLmNvbV0oaHR0cHM6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20pe3RhcmdldD0iX2JsYW5rIn0gZm9yIG1vcmUgZGV0YWlscy4KCjxicj4KCiMjIyBGb3IgSFRNTCBGaWxlCgpJbiBSU3R1ZGlvLCBnbyB0byBOZXcgRmlsZSAtPiBSIE1hcmtkb3duLiBUaGVuLCBjaG9vc2Ug4oCcRnJvbSBUZW1wbGF0ZeKAnSBhbmQgdGhlbiBjaG9vc2UgIkxhYiBSZXBvcnQiIGZyb20gdGhlIGxpc3Qgb2YgdGVtcGxhdGVzLiBUaGlzIHRlbXBsYXRlIHdpbGwgb25seSBleGlzdCBpZiB5b3UgaGF2ZSBpbnN0YWxsZWQgdGhlIGBvcGVuaW50cm9gIHBhY2thZ2UuCgo8YnI+CgojIyMgRm9yIFBERiBGaWxlCgpJbiBSU3R1ZGlvLCBnbyB0byBOZXcgRmlsZSAtPiBSIE1hcmtkb3duLiBUaGVuLCBjaG9vc2Ug4oCcRG9jdW1lbnTigJ0gYW5kIHRoZW4gY2hvb3NlICJQREYiIGZyb20gdGhlIGxpc3Qgb2Ygb3V0cHV0IGZvcm1hdC4gVGhpcyB0ZW1wbGF0ZSB3aWxsIHdvcmsgaWYgeW91IGhhdmUgYGxhdGV4cGRmYCBwYWNrYWdlIGluc3RhbGxlZC4KClBsZWFzZSBwdXQgdGhlIGNvZGUgc25pcHBldCAtIHNob3duIGJlbG93IC0gYXQgdGhlIGJlZ2lubmluZyBvZiB0aGUgUm1kIGFzc2lnbm1lbnQgdGVtcGxhdGUgZmlsZSBpZiBpdCBkb2VzIG5vdCBleGlzdC4KCmBgYAotLS0KdGl0bGU6ICcqKkxhYiAxIC0gTUFUSCAxNDEqKicKaGVhZGVyLWluY2x1ZGVzOiB8CiAgXHVzZXBhY2thZ2V7ZmFuY3loZHJ9CiAgXHBhZ2VzdHlsZXtmYW5jeX0KICBcZmFuY3loZWFkW0NPLENde0hvbWV3b3JrIDEgLSBNQVRIIDE0MX0KICBcZmFuY3lmb290W0NPLENde30KICBcZmFuY3lmb290W0Nde1x0aGVwYWdlfQogIFx1c2VwYWNrYWdle2Zsb2F0fQpvdXRwdXQ6CiAgYm9va2Rvd246OnBkZl9kb2N1bWVudDI6CiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICB0b2M6IG5vCiAgICBudW1iZXJfc2VjdGlvbjogbm8KdXJsY29sb3I6IHJlZAotLS0KYGBgCgo8YnI+CgojIyAqKkRhdGEgRnJhbWVzKioKCjxicj4KCkEgKipkYXRhIGZyYW1lKiogaXMgYSB0YWJsZSBvciBhIHR3by1kaW1lbnNpb25hbCBhcnJheS1saWtlIHN0cnVjdHVyZSBpbiB3aGljaCBlYWNoIGNvbHVtbiBjb250YWlucyB2YWx1ZXMgb2Ygb25lIHZhcmlhYmxlIGFuZCBlYWNoIHJvdyBjb250YWlucyBvbmUgc2V0IG9mIHZhbHVlcyBmcm9tIGVhY2ggY29sdW1uLgoKQ2hhcmFjdGVyaXN0aWNzIG9mIGEgZGF0YSBmcmFtZToKCiAgKiBUaGUgY29sdW1uIG5hbWVzIHNob3VsZCBiZSBub24tZW1wdHkuCiAgCiAgKiBUaGUgcm93IG5hbWVzIHNob3VsZCBiZSB1bmlxdWUuCiAgCiAgKiBUaGUgZGF0YSBzdG9yZWQgaW4gYSBkYXRhIGZyYW1lIGNhbiBiZSBvZiBudW1lcmljLCBmYWN0b3Igb3IgY2hhcmFjdGVyIHR5cGUuCgogICogRWFjaCBjb2x1bW4gc2hvdWxkIGNvbnRhaW4gc2FtZSBudW1iZXIgb2YgZGF0YSBpdGVtcy4KICAKPGJyPgoKIyMjIENyZWF0aW5nIERhdGEgRnJhbWVzCgpgYGB7ciBjcmVhdGluZy1kYXRhLWZyYW1lcywgbWVzc2FnZT1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCiMgQ3JlYXRlIHRoZSBkYXRhIGZyYW1lLgpkYXRhX2V4YW1wbGUgPC0gZGF0YS5mcmFtZSgKICAgbXlfcmFua2luZyA9IGMoMTo1KSwKICAgc3VwZXJoZXJvZXMgPSBjKCJTcGlkZXJtYW4iLCJTaGFuZy1DaGkiLCJTY2FybGV0IFdpdGNoIiwiRG9jdG9yIFN0cmFuZ2UiLCJCbGFjayBQYW50aGVyIiksCiAgIHN1YmplY3RpdmVfcG93ZXJfc2NhbGUgPSBjKDEwMDAwLDEwMDAsMTAwMCw5MDAsOTAwKQopCiMgUHJpbnQgdGhlIGRhdGEgZnJhbWUuCQkJCmdsaW1wc2UoZGF0YV9leGFtcGxlKQpgYGAKClRoZSBrZXl3b3JkIGZvciBjcmVhdGluZyBhIGRhdGFmcmFtZSBpbiBSIGlzIGBkYXRhLmZyYW1lYC4gRWFjaCBwYXJhbWV0ZXIgY29ycmVzcG9uZHMgdG8gdGhlIGNvbHVtbnMgd2hpbGUgdGhlIGl0ZW1zIGluIHRoZSBsaXN0cyBjb3JyZXNwb25kcyB0byB0aGUgcm93cy4gTm90aWNlIHRoYXQgdGhlIG5hbWUgb2YgdGhlIHZhcmlhYmxlIGZvciBlYWNoIGxpc3QgaXMgdGhlIGRlZmF1bHQgbmFtZSBmb3IgdGhlIGNvbHVtbnMuIFRoZSByb3dzIGFyZSBhdXRvbWF0aWNhbGx5IGhhdmUgaW50ZWdlciBpbmRpY2VzLiBUaGlzIHR5cGUgb2YgZGF0YSBzdHJ1Y3R1cmUgaXMgdGhlIHNhbWUgYXMgeW91IGhhdmUgc2VlbiBpbiB0aGUgcHJldmlvdXMgbGFiLgoKPGJyPgoKIyMjIEFkZGluZyBDb2x1bW5zCgpgYGB7ciBhZGRpbmctY29sdW1uLWRhdGEtZnJhbWUsIG1lc3NhZ2U9RkFMU0V9CiMgQWRkIHRoZSAic3ViamVjdGl2ZV9wYWlyIiBjb2x1bW4uCmRhdGFfZXhhbXBsZSRzdWJqZWN0aXZlX3BhaXIgPC0gYygiQmxhY2sgUGFudGhlciIsIkRvY3RvciBTdHJhbmdlIiwiU2hhbmctQ2hpIiwiRG9jdG9yIFN0cmFuZ2UiLCJTY2FybGV0IFdpdGNoIikKIyBBZGQgdGhlICJlbmVteSIgY29sdW1uLgpkYXRhX2V4YW1wbGUkZW5lbXkgPC0gYygiR3JlZW4gR29ibGluIiwiV2Vud3UiLCJBZ2F0aGEgSGFya25lc3MiLCJEb3JtYW1tdSIsIkVyaWsgS2lsbG1vbmdlciIpCnYgPC0gZGF0YV9leGFtcGxlCmdsaW1wc2UodikKYGBgCgo8YnI+CgojIyMgQWRkaW5nIFJvd3MKCmBgYHtyIGFkZGluZy1yb3ctZGF0YS1mcmFtLCBtZXNzYWdlPUZBTFNFfQojIENyZWF0ZSB0aGUgc2Vjb25kIGRhdGEgZnJhbWUKZGF0YV9uZXcgPC0gZGF0YS5mcmFtZSgKICAgbXlfcmFua2luZyA9IGMoNjo4KSwgCiAgIHN1cGVyaGVyb2VzID0gYygiTmFydXRvIiwiU2FpdGFtYSIsIkJsYWNrIFdpZG93IiksCiAgIHN1YmplY3RpdmVfcG93ZXJfc2NhbGUgPSBjKDcwMCw3MDAsODAwKSwgCiAgIHN1YmplY3RpdmVfcGFpciA9IGMoIlNwaWRlcm1hbiIsIkRvY3RvciBTdHJhbmdlIiwiU2hhbmctQ2hpIiksCiAgIGVuZW15ID0gYygiU2FzdWtlIiwiVW5rbm93biIsIkdlbmVyYWwgRHJleWtvdiIpCikKCiMgQmluZCB0aGUgdHdvIGRhdGEgZnJhbWVzLgpkYXRhX2V4YW1wbGVfZmluYWwgPC0gcmJpbmQoZGF0YV9leGFtcGxlLGRhdGFfbmV3KQpnbGltcHNlKGRhdGFfZXhhbXBsZV9maW5hbCkKYGBgCgpUaGUga2V5d29yZCBmb3IgYWRkaW5nIHJvd3MgdG8gYW4gZXhpc3RpbmcgZGF0YSBmcmFtZSBpbiBSIGlzIGByYmluZGAgd2hlcmUgdGhlIGlucHV0cyBtdXN0IGJlIGRhdGEgZnJhbWVzIHdpdGggdGhlIHNhbWUgY29sdW1ucy4KCjxicj4KCiMjICoqQ29uZGl0aW9uYWwgU3RhdGVtZW50cyoqCgo8YnI+CgpDb25kaXRpb25hbCBzdGF0ZW1lbnRzIGluIHByb2dyYW1taW5nIGFyZSBkZWZpbmUgb25lIG9yIG1vcmUgY29uZGl0aW9ucyB0byBiZSBldmFsdWF0ZWQgb3IgdGVzdGVkIGJ5IHRoZSBwcm9ncmFtLCBhcyB3ZWxsIGFzIGEgc3RhdGVtZW50IG9yIHN0YXRlbWVudHMgdG8gYmUgcGVyZm9ybWVkIGlmIHRoZSBjb25kaXRpb24gaXMgdHJ1ZSwgYW5kIG9wdGlvbmFsbHksIG90aGVyIHN0YXRlbWVudHMgdG8gYmUgZXhlY3V0ZWQgaWYgdGhlIGNvbmRpdGlvbiBpcyBmYWxzZS4KCjxicj4KCiMjIyBpZiBTdGF0ZW1lbnQKCmBgYHtyIGlmLXN0YXRlbWVudCwgbWVzc2FnZT1GQUxTRX0KeCA8LSA1CmlmKHggPiAwKXsKcHJpbnQoInBvc2l0aXZlIG51bWJlciIpCn0KYGBgCgo8YnI+CgojIyMgaWYtZWxzZSBzdGF0ZW1lbnQKCmBgYHtyIGlmLWVsc2Utc3RhdGVtZW50LCBtZXNzYWdlPUZBTFNFfQp4IDwtIC01CmlmICh4ID4gMCkgewogIHByaW50KCJwb3NpdGl2ZSBudW1iZXIiKQp9IGVsc2UgewogIHByaW50KCJuZWdhdGl2ZSBudW1iZXIiKQp9CmBgYAoKPGJyPgoKIyMjIGVsc2UtaWYgc3RhdGVtZW50CgpgYGB7ciBlbHNlLWlmLXN0YXRlbWVudCwgbWVzc2FnZT1GQUxTRX0KeCA8LSAwCmlmICh4ID4gMCkgewogIHByaW50KCJwb3NpdGl2ZSBudW1iZXIiKQp9IGVsc2UgaWYgKHggPT0gMCkgewogIHByaW50KCJ6ZXJvIikKfSBlbHNlIHsKICBwcmludCgibmVnYXRpdmUgbnVtYmVyIikKfQpgYGAKCjxicj4KCiMjIyBDb25kaXRpb25hbCBTdWJzZXR0aW5nCgpUaGUgY29kZSBzbmlwcGV0IGJlbG93IGFyZSBnZW5lcmF0ZWQgdXNpbmcgdGhlIGBpcmlzYCBkYXRhIHNldCwgd2hpY2ggaXMgcGFydCBvZiB0aGUgYmFzZSBSIGluc3RhbGxhdGlvbi4KCjxicj4KCiAgKiBPcHRpb24gQQoKYGBge3Igc3Vic2V0dGluZy1kYXRhLWZyYW1lLXVzaW5nLWNvbmRpdGlvbnMtMSwgbWVzc2FnZT1GQUxTRX0KIyBzdWJzZXR0aW5nIGJ5IGNhdGVnb3J5CnNldG9zYV9zdWIgPC0gaXJpc1tpcmlzJFNwZWNpZXMgPT0gInNldG9zYSIsIF0KZ2xpbXBzZShzZXRvc2Ffc3ViKQoKIyBzdWJzZXR0aW5nIG51bWVyaWNhbCB2YWx1ZXMKc2VwYWxfbGVuZ3RoX3N1YiA8LSBpcmlzW2lyaXMkU2VwYWwuTGVuZ3RoID49IDQsIF0KZ2xpbXBzZShzZXBhbF9sZW5ndGhfc3ViKQoKIyBzdWJzZXR0aW5nIG51bWVyaWNhbCB2YWx1ZXMgd2l0aGluIGEgcmFuZ2UKc2VwYWxfbGVuZ3RoX3N1Yl9yYW5nZSA8LSBpcmlzW2lyaXMkU2VwYWwuTGVuZ3RoID49IDUuMTAgJiBpcmlzJFNlcGFsLkxlbmd0aCA8PSA2LjQwLCBdCmdsaW1wc2Uoc2VwYWxfbGVuZ3RoX3N1Yl9yYW5nZSkKYGBgCgo8YnI+CgogICogT3B0aW9uIEIKICAKYGBge3Igc3Vic2V0dGluZy1kYXRhLWZyYW1lLXVzaW5nLWNvbmRpdGlvbnMtMiwgbWVzc2FnZT1GQUxTRX0KIyBzdWJzZXR0aW5nIGJ5IGNhdGVnb3J5CnNldG9zYV9zdWI8LSBzdWJzZXQoaXJpcywgU3BlY2llcyA9PSAic2V0b3NhIikKZ2xpbXBzZShzZXRvc2Ffc3ViKQoKIyBzdWJzZXR0aW5nIG51bWVyaWNhbCB2YWx1ZXMKc2VwYWxfbGVuZ3RoX3N1YiA8LSBzdWJzZXQoaXJpcywgU2VwYWwuTGVuZ3RoID49IDQpCmdsaW1wc2Uoc2VwYWxfbGVuZ3RoX3N1YikKCiMgc3Vic2V0dGluZyBudW1lcmljYWwgdmFsdWVzIHdpdGhpbiBhIHJhbmdlCnNlcGFsX2xlbmd0aF9zdWJfcmFuZ2UgPC0gc3Vic2V0KGlyaXMsIFNlcGFsLkxlbmd0aCA+PSA1LjEwICYgU2VwYWwuTGVuZ3RoIDw9IDYuNDApCmdsaW1wc2Uoc2VwYWxfbGVuZ3RoX3N1Yl9yYW5nZSkKYGBgCgo8YnI+CgojIyAqKkxvb3BzKioKCjxicj4KCllvdSBtYXkgZmluZCB5b3Vyc2VsZiBpbiBhIHBvc2l0aW9uIHdoZXJlIHlvdSBuZWVkIHRvIHJ1biBhIGJsb2NrIG9mIGNvZGUgbXVsdGlwbGUgdGltZXMuIFN0YXRlbWVudHMgYXJlIHR5cGljYWxseSBleGVjdXRlZCBpbiBvcmRlci4gQSBmdW5jdGlvbidzIGZpcnN0IHN0YXRlbWVudCBpcyBleGVjdXRlZCBmaXJzdCwgdGhlbiB0aGUgc2Vjb25kLCBhbmQgc28gb24uCgo8YnI+CgojIyMgZm9yLWxvb3BzCgpBICoqZm9yLWxvb3AqKiBpdGVyYXRlcyBvbiBhIGxpc3QgdW50aWwgaXQgcmVhY2hlcyB0aGUgbGFzdCBlbGVtZW50LgoKPGJyPgoKICAqIEl0ZXJhdGluZyB0aHJvdWdoIGEgdmVjdG9yIG9mIGludGVnZXJzCgpgYGB7ciBmb3ItbG9vcC0xLCBtZXNzYWdlPUZBTFNFfQpmb3IoaSBpbiAxOjEwKSB7ICMgSGVhZCBvZiBmb3ItbG9vcAogCiAgeDEgPC0gaV4yICAgICAgIyBDb2RlIGJsb2NrIHdoZXJlIGVhY2ggaW50ZXJnZXIgaXMgc3F1YXJlZAogIHByaW50KHgxKSAgICAgICMgUHJpbnQgcmVzdWx0cwp9CmBgYAoKPGJyPgoKICAqIEl0ZXJhdGluZyB0aHJvdWdoIGEgdmVjdG9yIG9mIHN0cmluZ3MKICAKYGBge3IgZm9yLWxvb3AtMiwgbWVzc2FnZT1GQUxTRX0KbGV0dGVyc192ZWN0b3IgPSBjKCdBJywnQicsJ0MnLCdEJywnRScpCmZvcihpIGluIGxldHRlcnNfdmVjdG9yKSB7ICMgbG9vcCBvdmVyIGNoYXJhY3RlciB2ZWN0b3IKICBjYXQoIk15IGFuc3dlciBpcyIsIGksICJmb3Igc3VyZS4gXG4iKSAgIyBjb25jYXRlbmF0ZSBzdHJpbmdzIHdoaWxlIHByaW50aW5nIGluIGV2ZXJ5IG5ldyBsaW5lCn0KYGBgCgpZb3UgY2FuIGFsc28gdXNlIGBwYXN0ZWAgdG8gY29uY2F0ZW5hdGUgc3RyaW5ncyBhbmQgcHJpbnQgdGhlbSB1c2luZyBgcHJpbnRgLgoKPGJyPgoKICAqIFN0b3JpbmcgaXRlcmF0ZWQgcmVzdWx0cyBpbiB0byBhIHZlY3RvciBieSBhcHBlbmRpbmcuCiAgCmBgYHtyIGZvci1sb29wLTMsIG1lc3NhZ2U9RkFMU0V9CnggPC0gbnVtZXJpYygpICMgQ3JlYXRlIGVtcHR5IGRhdGEgbnVtZXJpYyBvYmplY3QKCmZvcihpIGluIDE6MTApIHsgICMgSGVhZCBvZiBmb3ItbG9vcAogIHggPC0gYyh4LCBpXjIpICAjIENvZGUgYmxvY2sgd2hlcmUgZWFjaCBpbnRlcmdlciBpcyBzcXVhcmVkCn0KcHJpbnQoeCkKYGBgCgogICogSXRlcmF0aW5nIHRocm91Z2ggYSB2ZWN0b3IgYnV0IG11c3Qgc3RvcCBpZiBhIGNvbmRpdGlvbiBpcyBtZXQuCiAgCmBgYHtyIGZvci1sb29wLTQsIG1lc3NhZ2U9RkFMU0V9CnggPC0gbnVtZXJpYygpICMgQ3JlYXRlIGVtcHR5IGRhdGEgbnVtZXJpYyBvYmplY3QKCmZvcihpIGluIDE6MTAwKSB7ICAjIEhlYWQgb2YgZm9yLWxvb3AKICB4IDwtIGMoeCwgaV4yKSAgIyBDb2RlIGJsb2NrIHdoZXJlIGVhY2ggaW50ZXJnZXIgaXMgc3F1YXJlZAogIAogICMgY29uZGl0aW9uYWwgc3RhdGVtZW50OiBpZiBpXjIgPiAyMDAwLCB0aGUgbG9vcCB3aWxsIHN0b3AKICBpZiAoaV4yID4gMjAwMCkgewogICAgYnJlYWsKICB9Cn0KcHJpbnQoeCkKYGBgCgo8YnI+CgojIyMgd2hpbGUtbG9vcHMKCkEgKip3aGlsZS1sb29wKiogaXMgbWV0aG9kIG9mIGl0ZXJhdGluZyB3aGlsZSBhIGNvbmRpdGlvbiBpcyB0cnVlLiBXaGlsZSBhIGdpdmVuIGNvbmRpdGlvbiBpcyB0cnVlLCBpdCByZXBlYXRzIGEgc3RhdGVtZW50IG9yIGEgc2VyaWVzIG9mIHN0YXRlbWVudHMuIEJlZm9yZSBwZXJmb3JtaW5nIHRoZSBsb29wIGJvZHksIGl0IGNoZWNrcyB0aGUgY29uZGl0aW9uLgoKPGJyPgoKICAqIEl0ZXJhdGluZyB1bnRpbCBhIGNvbmRpdGlvbiBpcyBtZXQgb3Igbm90IG1ldC4KCmBgYHtyIHdoaWxlLWxvb3AtMSwgbWVzc2FnZT1GQUxTRX0KaSA8LSAxCndoaWxlIChpIDwgNikgeyAjIGl0ZXJhdGUgd2hpbGUgaSBpcyBsZXNzIHRoYW4gNgpwcmludChpKQppID0gaSsxICMgYWRkIDEgaW4gZWFjaCBpdGVyYXRpb24uIGlmIHlvdSBtaXNzIHRoaXMgcGFydCB5b3Ugd2lsbCBlbmQgdXAgaW4gYW4gaW5maW5pdCBsb29wCnByaW50KGkpCn0KYGBgCgpUaGUgZm9yLWxvb3AgYW5kIHdoaWxlLWxvb3AgY2FuIGJlIHNpbWlsYXIgYnV0IHRoZSB3aGlsZS1sb29wIG5lZWRzIGEgY29uZGl0aW9uIGluIG9yZGVyIGZvciBpdCB0byB3b3JrLgoKPGJyPgoKIyMgKipDcmVhdGluZyBhbmQgQ2FsbGluZyBGdW5jdGlvbnMqKgoKPGJyPgoKQSBmdW5jdGlvbiBpcyBhIGNvbGxlY3Rpb24gb2Ygc3RhdGVtZW50cyB0aGF0IHdvcmsgdG9nZXRoZXIgdG8gYWNjb21wbGlzaCBhIHNwZWNpZmllZCBnb2FsLiBSIGNvbWVzIHdpdGggYSB2YXN0IHZhcmlldHkgb2YgYnVpbHQtaW4gZnVuY3Rpb25zLCBhbmQgdXNlcnMgY2FuIGFsc28gY29uc3RydWN0IHRoZWlyIG93bi4KCkEgZnVuY3Rpb24gaW4gUiBpcyBhbiBvYmplY3QsIHdoaWNoIGFsbG93cyB0aGUgUiBpbnRlcnByZXRlciB0byBzZW5kIGNvbnRyb2wgdG8gdGhlIGZ1bmN0aW9uIGFzIHdlbGwgYXMgYW55IHBhcmFtZXRlcnMgdGhhdCBtYXkgYmUgcmVxdWlyZWQgZm9yIHRoZSBmdW5jdGlvbiB0byBjb21wbGV0ZSB0aGUgb3BlcmF0aW9ucy4KClRoZSBmdW5jdGlvbiB0aGVuIGNvbXBsZXRlcyBpdHMgZHV0eSBhbmQgcmV0dXJucyBjb250cm9sIGFzIHdlbGwgYXMgYW55IHJlc3VsdHMgdGhhdCBtYXkgaGF2ZSBiZWVuIHNhdmVkIGluIG90aGVyIG9iamVjdHMgdG8gdGhlIGludGVycHJldGVyLgoKKlIgZnVuY3Rpb24gc3ludGF4OioKCmBgYApmdW5jdGlvbl8xIDwtIGZ1bmN0aW9uKC4uLikgewogICAjIHB1dCBvcGVyYXRpb25zIGhlcmUKfQpgYGAKCjxicj4KCiMjIyBGdW5jdGlvbiB3aXRoIG9uZSB2YXJpYWJsZS4KCmBgYHtyIGZ1bmN0aW9ucy0xLCBtZXNzYWdlPUZBTFNFfQojIENyZWF0ZSBhIGZ1bmN0aW9uIHRvIHByaW50IHNxdWFyZXMgb2YgbnVtYmVycyBpbiBzZXF1ZW5jZS4KZnVuY3Rpb25fMSA8LSBmdW5jdGlvbihhKSB7CiAgIGZvcihpIGluIDE6YSkgewogICAgICBiIDwtIGleMgogICAgICBwcmludChiKSAjIG9ubHkgcHJpbnRzIHRoZSBvdXRwdXQKICAgfQp9CgojIENhbGwgdGhlIGZ1bmN0aW9uIG5ldy5mdW5jdGlvbiBzdXBwbHlpbmcgNiBhcyBhbiBhcmd1bWVudC4KZnVuY3Rpb25fMSg2KQpgYGAKCjxicj4KCiMjIyBGdW5jdGlvbiB3aXRoIHR3byB2YXJpYWJsZXMuCiAgCmBgYHtyIGZ1bmN0aW9ucy0yLCBtZXNzYWdlPUZBTFNFfQojIENyZWF0ZSBhIGZ1bmN0aW9uIHRvIHByaW50IHN1bSBvZiBzcXVhcmVzIG9mIHR3byBudW1iZXJzLgpmdW5jdGlvbl8yIDwtIGZ1bmN0aW9uKGEsYikgewogICBjIDwtIGFeMiArIGJeMgogICBwcmludChjKSAjIG9ubHkgcHJpbnRzIHRoZSBvdXRwdXQKfQoKIyBDYWxsIHRoZSBmdW5jdGlvbiBzdXBwbHlpbmcgNiBhcyBhbiBhcmd1bWVudC4KZnVuY3Rpb25fMig2LDYpCmBgYAogIAo8YnI+CgojIyMgRnVuY3Rpb24gdXNpbmcgUmV0dXJuCgpgYGB7ciBmdW5jdGlvbnMtMywgbWVzc2FnZT1GQUxTRX0KIyBDcmVhdGUgYSBmdW5jdGlvbiB0byBwcmludCBzdW0gb2Ygc3F1YXJlcyBvZiB0d28gbnVtYmVycy4KZnVuY3Rpb25fMiA8LSBmdW5jdGlvbihhLGIpIHsKICAgYyA8LSBhXjIgKyBiXjIKICAgcmV0dXJuKGMpICMgcmV0dXJucyB2YWx1ZSBjCn0KCiMgQ2FsbCB0aGUgZnVuY3Rpb24gc3VwcGx5aW5nIDYgYXMgYW4gYXJndW1lbnQuCmZ1bmN0aW9uXzIoNiw2KQpgYGAKICAKPGJyPgoKIyMgKipJbnRlcm1lZGlhdGUgRmlndXJlcyoqCgo8YnI+CgojIyMgU2NhdHRlciBQbG90cyB3aXRoIEdyb3VwcwoKVGhlIGZpZ3VyZXMgYmVsb3cgYXJlIGdlbmVyYXRlZCB1c2luZyB0aGUgYGlyaXNgIGRhdGEgc2V0LCB3aGljaCBpcyBwYXJ0IG9mIHRoZSBiYXNlIFIgaW5zdGFsbGF0aW9uLgoKPGJyPgoKICAqIFVzaW5nIEJhc2UgUi4KCmBgYHtyIGZpZ3VyZXMtaW50LTEsIG1lc3NhZ2UgPSBGQUxTRSwgZmlnLndpZHRoID0gNSwgZmlnLnBvcz0iSCJ9CnBsb3QoaXJpcyRTZXBhbC5MZW5ndGgsIGlyaXMkU2VwYWwuV2lkdGgsICMgeCBhbmQgeSBkYXRhCiAgICAgcGNoPTIxLCAjIGRvdCBkZXNpZ24KICAgICBiZz1jKCJyZWQiLCJncmVlbjMiLCJibHVlIilbdW5jbGFzcyhpcmlzJFNwZWNpZXMpXSwgIyBjb2xvciBmb3IgZWFjaCBncm91cAogICAgIG1haW49IkVkZ2FyIEFuZGVyc29uJ3MgSXJpcyBEYXRhIiwgICMgcGxvdCB0aXRsZQogICAgIHhsYWIgPSAiU2VwYWwgTGVuZ3RoIiwgIyB4IGxhYmVsCiAgICAgeWxhYiA9ICJTZXBhbCBXaWR0aCIpICMgeSBsYWJlbApsZWdlbmQoJ3RvcHJpZ2h0JyxsZXZlbHMoaXJpcyRTcGVjaWVzKSxjb2w9YygicmVkIiwiZ3JlZW4zIiwiYmx1ZSIpLHBjaD1jKDIxLDIxLDIxKSkKYGBgCgo8YnI+CgogICogVXNpbmcgYGdncGxvdDJgLgogIApgYGB7ciBmaWd1cmVzLWludC0yLCBtZXNzYWdlID0gRkFMU0UsIGZpZy53aWR0aCA9IDYsIGZpZy5wb3M9IkgifQpsaWJyYXJ5KGdncGxvdDIpCnNjYXR0ZXIgPC0gZ2dwbG90KGRhdGE9aXJpcywgYWVzKHggPSBTZXBhbC5MZW5ndGgsIHkgPSBTZXBhbC5XaWR0aCkpICMgdXNpbmcgdGhlIGlyaXMgZGF0YQpzY2F0dGVyICsgZ2VvbV9wb2ludChhZXMoY29sb3I9U3BlY2llcywgc2hhcGU9U3BlY2llcyksIHNpemUgPSAxLjUpICsgIyBzY2F0dGVyIHBsb3QKICB4bGFiKCJTZXBhbCBMZW5ndGgiKSArICB5bGFiKCJTZXBhbCBXaWR0aCIpICsgIyB4IGFuZCB5IGxhYmVsCiAgZ2d0aXRsZSgiRWRnYXIgQW5kZXJzb24ncyBJcmlzIERhdGEiKQpgYGAKCjxicj4KCiMjIyBIaXN0b2dyYW1zIHdpdGggR3JvdXBzCgpUaGUgZmlndXJlcyBiZWxvdyBhcmUgZ2VuZXJhdGVkIHVzaW5nIHRoZSBgaXJpc2AgZGF0YSBzZXQsIHdoaWNoIGlzIHBhcnQgb2YgdGhlIGJhc2UgUiBpbnN0YWxsYXRpb24uCgo8YnI+CgogICogVXNpbmcgYGdncGxvdDJgLgoKYGBge3IgZmlndXJlcy1pbnQtNCwgbWVzc2FnZSA9IEZBTFNFLCBmaWcud2lkdGggPSA2LCBmaWcucG9zPSJIIn0KbGlicmFyeShnZ3Bsb3QyKQpoaXN0b2dyYW0gPC0gZ2dwbG90KGRhdGE9aXJpcywgYWVzKHg9U2VwYWwuTGVuZ3RoKSkKaGlzdG9ncmFtICsgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGg9MC4yLCBjb2xvcj0iYmxhY2siLCBhZXMoZmlsbD1TcGVjaWVzKSkgKyAKICB4bGFiKCJTZXBhbCBMZW5ndGgiKSArICB5bGFiKCJGcmVxdWVuY3kiKSArIGdndGl0bGUoIkhpc3RvZ3JhbSBvZiBTZXBhbCBMZW5ndGgiKQpgYGAgIAoKPGJyPgoKIyMjIEJveHBsb3RzIHdpdGggR3JvdXBzCgpUaGUgZmlndXJlcyBiZWxvdyBhcmUgZ2VuZXJhdGVkIHVzaW5nIHRoZSBgaXJpc2AgZGF0YSBzZXQsIHdoaWNoIGlzIHBhcnQgb2YgdGhlIGJhc2UgUiBpbnN0YWxsYXRpb24uCgo8YnI+CgogICogVXNpbmcgYGdncGxvdDJgLgoKYGBge3IgZmlndXJlcy1pbnQtNSwgbWVzc2FnZSA9IEZBTFNFLCBmaWcud2lkdGggPSA2LCBmaWcucG9zPSJIIn0KbGlicmFyeShnZ3Bsb3QyKQpib3hwbG90IDwtIGdncGxvdChkYXRhPWlyaXMsIGFlcyh4PVNlcGFsLkxlbmd0aCkpCmJveHBsb3QgKyBnZW9tX2JveHBsb3QoY29sb3I9ImJsYWNrIiwgYWVzKGZpbGw9U3BlY2llcykpICsgCiAgeGxhYigiU2VwYWwgTGVuZ3RoIikgKyBnZ3RpdGxlKCJCb3hwbG90IG9mIFNlcGFsIExlbmd0aCIpICsgCiAgdGhlbWUoYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLCAjIGl0IHJlbW92ZXMgdGhlIHkgYXhpcyB0aWNrcyBhbmQgdGV4dHMKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgICAKCjxicj4KCiMjIyBMaW5lIFBsb3RzIHdpdGggR3JvdXBzCgo8YnI+CgpUaGUgcGxvdHMgYmVsb3cgYXJlIGdlbmVyYXRlZCB1c2luZyBhIHN5bnRoZW50aWMgZGF0YS4KCiAgKiBVc2luZyBgZ2dwbG90MmAuCgpgYGB7ciBzeW50aGV0aWMtZGF0YSwgbWVzc2FnZSA9IEZBTFNFfQojIGNyZWF0ZSBzeW50aGV0aWMgZGF0YQpncm91cHMgPC0gYygiQSIsIkIiKQp4X3ZhbHNfc2VxIDwtIHNlcSgwLCAxLCBsZW5ndGgub3V0ID0gOSkgIyBnZW5lcmF0ZSBhIHNlcXVlbmNlIG9mIGVxdWFsbHkgc3BhY2VkIG51bWJlcnMKeF92YWx1ZXMgPC0gcmVwKHhfdmFsc19zZXEsMikgIyByZXBsaWNhdGUgdmVjdG9yIHR3aWNlCnlfdmFsdWVzIDwtIGMoMSwgMiwgMiwgNCwgNSwgNCwgNCwgMywgMSwgMiwgNCwgNCwgOCwgMTAsIDgsIDgsIDYsIDIpCmRmMiA8LSBkYXRhLmZyYW1lKGxldHRlcj1yZXAoZ3JvdXBzLCBlYWNoPTkpLCAjIHJlcGxpY2F0ZSBBIGFuZCBCIDkgdGltZXMgZWFjaAogICAgICAgICAgICAgICAgICB4PXJlcCh4X3ZhbHVlcywyKSwgIyBpbmRlcGVuZGVudCB2YXJpYWJsZQogICAgICAgICAgICAgICAgICB5PXlfdmFsdWVzKSAjIGRlcGVuZGVudCB2YXJpYWJsZQpnbGltcHNlKGRmMikKYGBgCgpgYGB7ciBmaWd1cmVzLWludC02LCBtZXNzYWdlID0gRkFMU0UsIGZpZy53aWR0aCA9IDYsIGZpZy5wb3M9IkgifQpsaWJyYXJ5KGdncGxvdDIpCnA8LWdncGxvdChkZjIsIGFlcyh4PXgsIHk9eSwgZ3JvdXA9bGV0dGVyKSkgKwogIGdlb21fbGluZShhZXMoY29sb3I9bGV0dGVyKSkrCiAgZ2VvbV9wb2ludChhZXMoY29sb3I9bGV0dGVyKSkKcApgYGAKCjxicj4KCiMjICoqTGFiIEV4ZXJjaXNlcyoqCgo8YnI+CgojIyMgSS4gTGluZWFyIEZ1bmN0aW9uCgpDb25zaWRlciB0aGUgbGluZWFyIGZ1bmN0aW9uIHdyaXR0ZW4gYmVsb3cgd2l0aCBwYXJhbWV0ZXJzICRhJCBhbmQgJGIkLgogIAogICQkeSh4O2EsYikgPSBheCArIGIkJAogIHdoZXJlICR4JCBpcyB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGUgYW5kICR5JCBpcyB0aGUgZGVwZW5kZW50IHZhcmlhYmxlLiBIZXJlLCB0aGUgc2xvcGUgb2YgdGhlIGxpbmUgaXMgJGEkIGFuZCBpbnRlcmNlcHQgaXMgJGIkLiAKICAKICAxLiBXcml0ZSBhbiBSIGZ1bmN0aW9uIHdoaWNoIG91dHB1dHMgdGhlIGRlcGVuZGVudCB2YXJpYWJsZSAkeSQgYW5kIHRha2VzIGluIHRoZSBpbmRlcGVuZGVudCB2YXJpYWJsZSAkeCQsIGFuZCB0aGUgcGFyYW1ldGVycyAkYSQgYW5kICRiJC4KICAKICAyLiBVc2luZyAzIGRpZmZlcmVudCB2YWx1ZXMgb2YgJGEkIGFuZCAkYiQgKEE6JGE9MSxiPTEkLCBCOiRhPTEuMjUsYj0xLjIkLCBhbmQgQzokYT0yLGI9MS41JCksIGNyZWF0ZSBhIGRhdGFmcmFtZSB3aXRoIGNvbHVtbnMgImxpbmUiLCAieCIsIGFuZCAieSIuIFVzZSB0aGUgYHNlcWAgY29tbWFuZCB0byBjcmVhdGUgYSB2ZWN0b3Igb2YgJHgkIHZhbHVlcyBmcm9tIDAgdG8gMSB3aXRoIGxlbmd0aCAxMC4gVXNlIHRoZSBgcmVwYCBjb21tYW5kIHRvIGdlbmVyYXRlICR4JCB2YWx1ZXMgZm9yIHRoZSB0aHJlZSBncm91cHMuIFVzZSB5b3VyIFIgZnVuY3Rpb24gdG8gZ2VuZXJhdGUgJHkkIHZhbHVlcyB1c2luZyB5b3VyICR4JCB2YWx1ZXMgYXMgaW5wdXRzLiBUaGUgImxpbmUiIGNvbHVtbiBzaG91bGQgY29udGFpbiB0aGUgbGluZSBncm91cHMgQSwgQiwgYW5kIEMuIFVzZSBgZ2xpbXBzZWAgdG8gc2hvdyB5b3VyIGRhdGFmcmFtZS4KICAKICAzLiBVc2UgYGdncGxvdGAgdG8gcGxvdCB0aGUgbGluZXMgb24gdGhlIHNhbWUgZmlndXJlIHdpdGggcHJvcGVyIGxpbmUgZ3JvdXAgbGFiZWxzLgoKPGJyPgoKIyMjIElJLiBVbml0ZWQgU3RhdGVzIENvdW50aWVzCgpDb25zaWRlciB0aGUgYGNvdW50eWAgZGF0YSBzZXQsIHdoaWNoIGNhbiBiZSBmb3VuZCBpbiB0aGUgYHVzZGF0YWAgUiBwYWNrYWdlLiBBbHNvLCB0aGlzIGRhdGFzZXQgY2FuIGJlIGFjY2Vzc2VkIGFzIGEgY3N2IGZpbGUsIFtjb3VudHldKGRhdGEtc2V0cy9jb3VudHkuY3N2KXt0YXJnZXQ9Il9ibGFuayJ9LgoKICAxLiBVc2UgYGdncGxvdGAgdG8gcGxvdCBoaXN0b2dyYW1zIG9mICJwb3BcX2NoYW5nZSIgdmFyaWFibGUgd2l0aCBjYXRlZ29yaWVzIGZyb20gdGhlICJtZXRybyIgdmFyaWFibGUuIE1ha2Ugc3VyZSB0byBsYWJlbCB0aGUgeCBhbmQgeSBheGlzIHByb3Blcmx5LiBXaGF0IGNhbiB5b3UgdGVsbCBhYm91dCB0aGUgY2hhbmdlIGluIHBvcHVsYXRpb24gd2hldGhlciB0aGUgY291bnR5IGhhcyBhY2Nlc3MgdG8gYSBtZXRybyBvciBub3Q/CiAgCiAgMi4gVXNlIGBnZ3Bsb3RgIHRvIHBsb3QgaGlzdG9ncmFtcyBvZiAicGVyXF9jYXBpdGFcX2luY29tZSIgdmFyaWFibGUgd2l0aCBjYXRlZ29yaWVzIGZyb20gdGhlICJtZWRpYW5cX2VkdSIgdmFyaWFibGUuIE1ha2Ugc3VyZSB0byBsYWJlbCB0aGUgeCBhbmQgeSBheGlzIHByb3Blcmx5LiBEZXNjcmliZSB0aGUgZGlzdHJpYnV0aW9ucyBiZXR3ZWVuIHRoZSBsZXZlbHMgb2YgdGhlICJtZWRpYW5cX2VkdSIgdmFyaWFibGUuIElzIHRoZXJlIGEgc3Ryb25nIGFzc29jaWF0aW9uIGJldHdlZW4gIm1lZGlhblxfZWR1IiBhbmQgInBlclxfY2FwaXRhXF9pbmNvbWUiPyBFeHBsYWluIHdoeS4KICAKICAzLiBVc2UgYGdncGxvdGAgdG8gcGxvdCBhIHNjYXR0ZXJwbG90IG9mICJ1bmVtcGxveW1lbnRcX3JhdGUiIHZlcnN1cyAicG92ZXJ0eQogIFxfcmF0ZSIgdmFyaWFibGVzIHdpdGggY2F0ZWdvcmllcyBmcm9tIHRoZSAibWVkaWFuXF9lZHUiLiBNYWtlIHN1cmUgdG8gbGFiZWwgdGhlIHggYW5kIHkgYXhpcyBwcm9wZXJseS4gSXMgdGhlcmUgYW4gYXNzb2NpYXRpb24gYmV0d2VlbiAidW5lbXBsb3ltZW50XF9yYXRlIiBhbmQgInBvdmVydHkKICBcX3JhdGUiPyBBcmUgdGhlcmUgYW55IGRpZmZlcmVuY2VzIGFjcm9zcyB0aGUgIm1lZGlhblxfZWR1IiBsZXZlbHM/CiAgCiAgNC4gQ3JlYXRlIGEgc3Vic2V0IG9mIHRoZSBkYXRhIHdoZXJlIHdlIG9ubHkgdGFrZSByb3dzIHdpdGggdGhlIHN0YXRlcyBXYXNoaW5ndG9uLCBPcmVnb24sIGFuZCBDYWxpZm9ybmlhLgogIAogIDUuIFVzaW5nIHRoZSBzdWJzZXQgeW91IGp1c3QgY3JlYXRlZCwgY3JlYXRlIGJveHBsb3RzIG9mICJwb3BcX2NoYW5nZSIgdmFyaWFibGUgd2l0aCBjYXRlZ29yaWVzIGZyb20gdGhlICJzdGF0ZSIgdmFyaWFibGUuIE1ha2Ugc3VyZSB0byBsYWJlbCB0aGUgeCBhbmQgeSBheGlzIHByb3Blcmx5LiBCYXNlZCBvbiB0aGUgbWVkaWFucyBzaG93biBvbiB0aGUgYm94cGxvdHMsIHdoaWNoIHN0YXRlIGhhcyB0aGUgbG93ZXN0IGFuZCBoaWdoZXN0IHBvcHVsYXRpb24gY2hhbmdlPwogIAogIDYuIFVzaW5nIHRoZSBzdWJzZXQgeW91IGp1c3QgY3JlYXRlZCwgY3JlYXRlIGJveHBsb3RzIG9mICJwZXJcX2NhcGl0YVxfaW5jb21lIiB2YXJpYWJsZSB3aXRoIGNhdGVnb3JpZXMgZnJvbSB0aGUgIm1lZGlhblxfZWR1IiB2YXJpYWJsZS4gTWFrZSBzdXJlIHRvIGxhYmVsIHRoZSB4IGFuZCB5IGF4aXMgcHJvcGVybHkuIEJhc2VkIG9uIHRoZSBtZWRpYW5zIHNob3duIG9uIHRoZSBib3hwbG90cywgd2hpY2ggc3RhdGUgaGFzIHRoZSBsb3dlc3QgYW5kIGhpZ2hlc3QgcGVyIGNhcGl0YSBpbmNvbWU/Cgo8YnI+Cg==