Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Cmd+Shift+Enter.

Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Cmd+Option+I.

When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Cmd+Shift+K to preview the HTML file).

summary(cars)
     speed           dist       
 Min.   : 4.0   Min.   :  2.00  
 1st Qu.:12.0   1st Qu.: 26.00  
 Median :15.0   Median : 36.00  
 Mean   :15.4   Mean   : 42.98  
 3rd Qu.:19.0   3rd Qu.: 56.00  
 Max.   :25.0   Max.   :120.00  
x = cars

##Variables

R Variable Naming Conventions:

# Numeric data type (floating-point number)
num_variable <- 42.5

# Integer data type
int_variable <- 10L

# Character data type (text)
char_variable <- "Hello, R!"

# Logical data type (TRUE or FALSE)
logical_variable <- TRUE

# Vector data type (1-dimensional array)
numeric_vector <- c(1, 2, 3, 4, 5)
char_vector <- c("apple", "banana", "orange", 'red', 'blue')
logical_vector <- c(TRUE, FALSE, TRUE)

# Matrix data type (2-dimensional array)
matrix_data <- matrix(c(1, 2, 3, 4, 5, 6), nrow = 2, ncol = 3)

# List data type (collection of different data types)
list_data <- list(name = "John", age = 30, married = TRUE)

print(list_data)
$name
[1] "John"

$age
[1] 30

$married
[1] TRUE
list_data$age <- 35
print(list_data)
$name
[1] "John"

$age
[1] 35

$married
[1] TRUE
print(list_data)
$name
[1] "John"

$age
[1] 35

$married
[1] TRUE

Arithmetic Operations


# Addition
result_add <- 10 + 5

# Subtraction
result_sub <- 20 - 8

# Multiplication
result_mul <- 6 * 7

# Division
result_div <- 15 / 3

# Modulo (remainder after division)
result_mod <- 17 %% 5

# Exponentiation (raising to a power)
result_exp <- 2^3

# Combined Arithmetic Operations
result_combined <- (5 + 3) * 2

String

1. Concatenation (Combining DNA Sequences)

# Using paste()
sequence1 <- "ATCG"
sequence2 <- "GCTA"
combined_sequence <- paste(sequence1, sequence2, sep = "")
print(combined_sequence)  # "ATCGGCTA"
[1] "ATCGGCTA"

2. Substring (Extracting Gene Segment):

# Using substr()
gene_sequence <- "ATCGATCGATCG"
gene_segment <- substr(gene_sequence, start = 1, stop = 4)
print(gene_segment)  # "ATCG"
[1] "ATCG"

3. String Length (Length of DNA Sequence):

# Using nchar()
dna_sequence <- "ATCGATCGATCG"
sequence_length <- nchar(dna_sequence)
print(sequence_length)  # 12
[1] 12

4. Changing Case

# To Uppercase
uppercase_dna <- toupper("atcg")
print(uppercase_dna)  # "ATCG"
[1] "ATCG"

5. Pattern Matching

# Using grepl()
gene_sequence <- "ATCGATCGATCG"
motif <- "ATC"
matches <- grepl(motif, gene_sequence)
print(matches)  # TRUE
[1] TRUE

6. Splitting Strings

# Using strsplit()
genes <- "GeneX,GeneY,GeneZ"
split_genes <- strsplit(genes, ",")[[1]]
print(split_genes)
[1] "GeneX" "GeneY" "GeneZ"
# ["GeneX", "GeneY", "GeneZ"]

7. Reversing a String

library(stringi)
dna_sequence <- "ATCGATCG"
reversed_sequence <- stri_reverse(dna_sequence)
print(reversed_sequence)  # "GCTAGCTA"
[1] "GCTAGCTA"

8. Find occurances

# DNA sequence
dna_sequence <- "ATCGATCGATCGATCGATCG"

# Substring to find frequency
substring_to_find <- "ATC"

# Using gregexpr to find positions of the substring
matches <- gregexpr(substring_to_find, dna_sequence)

match_positions = unlist(matches)
print(match_positions)
[1]  1  5  9 13 17
# Counting the number of matches
frequency <- sum(unlist(matches) != -1)

# Print the frequency
print(frequency)
[1] 5

Vector

Create a vector

# Create a numeric vector named ages
ages <- c(25, 30, 22, 28, 35)
print(ages)
[1] 25 30 22 28 35

Indexing

print(ages[1])
[1] 25
print(ages[2])
[1] 30

Append Elements

# Append the age 40 to the ages vector
ages <- c(ages, 40)
print(ages)
[1] 25 30 22 28 35 40

Slice

print(ages[1:3])
[1] 25 30 22
print(ages[2:4])
[1] 30 22 28
print(ages[2:8])
[1] 30 22 28 35 40 NA NA

Insert Element at Position

# Insert the age 45 at the third position in the ages vector
ages <- c(ages[1:2], 45, ages[3:length(ages)])
print(ages)
[1] 25 30 45 22 28 35 40

Remove Elements

# Remove the second element from the ages vector
ages <- ages[-2]
print(ages)
[1] 25 45 22 28 35 40

Conditional select


# Create a new vector named young_ages by slicing the ages vector
young_ages <- ages[ages < 30]
print(young_ages)
[1] 25 22 28

# Create a new vector with age group 25-35
age_25_35 <- ages[ages <= 35]
age_25_35 <- age_25_35[age_25_35 >= 25]
print(age_25_35)
[1] 25 28 35

sort

print(sort(ages))
[1] 22 25 28 35 40 45

Vector manipulation

# Create a numeric vector named scores
scores <- c(85, 92, 78, 89, 80, 95)
print(scores)
[1] 85 92 78 89 80 95
# Create a new vector adjusted_scores by adding 5 to each score
adjusted_scores <- scores + 5
print(adjusted_scores)
[1]  90  97  83  94  85 100

Vector Comparison

# Create a logical vector pass
pass <- scores >= 80
print(pass)
[1]  TRUE  TRUE FALSE  TRUE  TRUE  TRUE

Vector length

# Calculate and print the length of the ages vector
length_ages <- length(ages)
print(length_ages)
[1] 6

Simple statistics

# Calculate and print the sum of the elements in the ages vector
sum_ages <- sum(scores)
mean_scores <- mean(scores)
median_scores <- median(scores)

#sum
print(sum_ages)
[1] 519
# Mean
print(mean_scores)
[1] 86.5
# Median
print(median_scores)
[1] 87
# Min
print(min(scores))
[1] 78
# Max
print(max(scores))
[1] 95
#correlation
print(cor(scores, ages))
[1] 0.679584
# standard deviation
print(sd(scores))
[1] 6.715653
# variance
print(var(scores))
[1] 45.1
# Quantiles 
print(quantile(scores))
   0%   25%   50%   75%  100% 
78.00 81.25 87.00 91.25 95.00 

Vector arithmatics

# Vector Addition Example
vec1 <- c(1, 2, 3, 4, 5)
vec2 <- c(5, 4, 3, 2, 1)

result_addition <- vec1 + vec2
print("Vector Addition:")
[1] "Vector Addition:"
print(result_addition)
[1] 6 6 6 6 6
result_subtraction <- vec1 - vec2
print("Vector Subtraction:")
[1] "Vector Subtraction:"
print(result_subtraction)
[1] -4 -2  0  2  4

List

# 1. Create a list
my_list <- list(
  name = "John",
  age = 25,
  city = "New York",
  is_student = TRUE
)

# Display the original list
print("Original List:")
[1] "Original List:"
print(my_list)
$name
[1] "John"

$age
[1] 25

$city
[1] "New York"

$is_student
[1] TRUE
# 2. Delete an item
my_list$age <- NULL
# Display the modified list
print(my_list)
$name
[1] "John"

$city
[1] "New York"

$is_student
[1] TRUE
# 3. Add an item
my_list$occupation <- "Engineer"

# Display the list after adding 'occupation'
print("List after adding 'occupation':")
[1] "List after adding 'occupation':"
print(my_list)
$name
[1] "John"

$city
[1] "New York"

$is_student
[1] TRUE

$occupation
[1] "Engineer"
# 4. Change the value of an item
my_list$name <- "Jane"

# Display the list after changing 'name'
print("List after changing 'name':")
[1] "List after changing 'name':"
print(my_list)
$name
[1] "Jane"

$city
[1] "New York"

$is_student
[1] TRUE

$occupation
[1] "Engineer"
# 5. Length of list
list_length <- length(my_list)
print(paste("Length of the list:", list_length))
[1] "Length of the list: 4"
# 6. Merge 2 lists
another_list <- list(country = "USA", language = "English")

merged_list <- c(my_list, another_list)

# Display the merged list
print("Merged List:")
[1] "Merged List:"
print(merged_list)
$name
[1] "Jane"

$city
[1] "New York"

$is_student
[1] TRUE

$occupation
[1] "Engineer"

$country
[1] "USA"

$language
[1] "English"

Data Frame

# Given data frame
data <- data.frame(
  ID = c(1, 2, 3, 4, 5),
  Name = c("Alice", "Bob", "Charlie", "David", "Eva"),
  Age = c(25, 30, 22, 28, 35),
  Score = c(85, 92, 78, 89, 81)
)

print(data)
NA
# Create a scatter plot of Age vs. Score
plot(data$Age, data$Score, xlab = "Age", ylab = "Score", main = "Age vs. Score")


# Create a line plot of ID vs. Score
plot(data$ID, data$Score, type = "l", xlab = "ID", ylab = "Score", main = "ID vs. Score")


# Create a histogram of Age distribution
hist(data$Age, xlab = "Age", ylab = "Frequency", main = "Age Distribution")


# Create a pie chart of Age distribution
age_freq <- table(cut(data$Age, breaks = c(20, 25, 30, 40)))
age_freq

(20,25] (25,30] (30,40] 
      2       2       1 
pie(age_freq, labels = c("20-25", "26-30", "31-40"), main = "Age Distribution")


# Create a boxplot of Scores
boxplot(data$Score, xlab = "Scores", main = "Score Distribution")


# Create a bar plot of Scores by Name
barplot(data$Score, names.arg = data$Name, xlab = "Name", ylab = "Score", main = "Individual Scores")


# Create a bar plot of Mean Scores by Name
mean_scores <- tapply(data$Score, data$Name, mean)
barplot(mean_scores, xlab = "Name", ylab = "Mean Score", main = "Mean Scores by Name")

selected_rows <- data[2:4, ]
print(selected_rows)

selected_rows <- data[2, ]
print(selected_rows)


selected_rows <- data[,2:3 ]
print(selected_rows)

selected_rows <- data[2:4,2:3 ]
print(selected_rows)
# Select rows where age is greater than 25 and score is less than 90
selected_rows <- data[data$Age > 25 & data$Score < 90, ]

# Print the selected rows
print(selected_rows)
# Sort data by Age in descending order
sorted_data <- data[order(data$Age, decreasing = TRUE), ]
print("Sorted Data:")
[1] "Sorted Data:"
print(sorted_data)
# Check if any value in Age column is above 40
any_above_40 <- any(data$Age > 40)
print("Any value above 40 in Age column?")
[1] "Any value above 40 in Age column?"
print(any_above_40)
[1] FALSE
# Calculate the average age
average_age <- mean(data$Age)
print("Average Age:")
[1] "Average Age:"
print(average_age)
[1] 28
# Calculate the maximum score
max_score <- max(data$Score)
print("Maximum Score:")
[1] "Maximum Score:"
print(max_score)
[1] 92
# Subset rows with specific IDs
specific_ids <- data[data$ID_number %in% c(2, 4), ]
print("Rows with Specific IDs:")
[1] "Rows with Specific IDs:"
print(specific_ids)
print(data)
major = c('Math', 'Biology', 'CS', 'Physics', 'Chemistry')
data2 = cbind(data, major)
print(data2)

colnames(data2)[5] = 'Major'
print(data2)
v = c()
for(i in 1:5) {
  v[i] = i
}
v
[1] 1 2 3 4 5

Loop

Loop to Print Numbers

# Using for loop to print numbers
for (i in 1:5) {
  print(i)
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
# Using while loop to print numbers
i <- 1
while (i <= 5) {
  print(i)
  i <- i + 1
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5

Loop to Iterate a Vector

# Vector
my_vector <- c("apple", "banana", "orange")

# Using for loop to iterate vector
for (fruit in my_vector) {
  print(fruit)
}
[1] "apple"
[1] "banana"
[1] "orange"
# Using while loop to iterate vector
i <- 1
while (i <= length(my_vector)) {
  print(my_vector[i])
  i <- i + 1
}
[1] "apple"
[1] "banana"
[1] "orange"

Loop to Iterate a List

# List
my_list <- list(name = "John", age = 25, city = "New York")

# Using for loop to iterate list
for (item in my_list) {
  print(item)
}
[1] "John"
[1] 25
[1] "New York"
# Using while loop to iterate list
i <- 1
while (i <= length(my_list)) {
  print(my_list[[i]])
  i <- i + 1
}
[1] "John"
[1] 25
[1] "New York"

Loop to Iterate a Data Frame

data <- data.frame(
  ID = c(1, 2, 3, 4, 5),
  Name = c("Alice", "Bob", "Charlie", "David", "Eva"),
  Age = c(25, 30, 22, 28, 35),
  Score = c(85, 92, 78, 89, 81)
)

# Using a for loop to print column names
for (col_name in names(data)) {
  print(col_name)
}
[1] "ID"
[1] "Name"
[1] "Age"
[1] "Score"
for(i in data$Name) {
  print(i)
}
[1] "Alice"
[1] "Bob"
[1] "Charlie"
[1] "David"
[1] "Eva"
for(i in 1:ncol(data)) {
  print(data$ID[i])
  print(i)
}
[1] 1
[1] 1
[1] 2
[1] 2
[1] 3
[1] 3
[1] 4
[1] 4

Nested loop

# Nested for loop example
for (i in 1:4) {
  for (j in 1:3) {
    cat("i:", i, ", j:", j, "\n")
  }
}
i: 1 , j: 1 
i: 1 , j: 2 
i: 1 , j: 3 
i: 2 , j: 1 
i: 2 , j: 2 
i: 2 , j: 3 
i: 3 , j: 1 
i: 3 , j: 2 
i: 3 , j: 3 
i: 4 , j: 1 
i: 4 , j: 2 
i: 4 , j: 3 
# Define the size of the multiplication table
table_size <- 3

# Nested for loop to generate the multiplication table
for (i in 1:table_size) {
  cat("Multiplication table for", i, ":\n")
  for (j in 1:10) {
    result <- i * j
    cat(i, "x", j, "=", result, "\n")
  }
  cat("\n")
}
Multiplication table for 1 :
1 x 1 = 1 
1 x 2 = 2 
1 x 3 = 3 
1 x 4 = 4 
1 x 5 = 5 
1 x 6 = 6 
1 x 7 = 7 
1 x 8 = 8 
1 x 9 = 9 
1 x 10 = 10 

Multiplication table for 2 :
2 x 1 = 2 
2 x 2 = 4 
2 x 3 = 6 
2 x 4 = 8 
2 x 5 = 10 
2 x 6 = 12 
2 x 7 = 14 
2 x 8 = 16 
2 x 9 = 18 
2 x 10 = 20 

Multiplication table for 3 :
3 x 1 = 3 
3 x 2 = 6 
3 x 3 = 9 
3 x 4 = 12 
3 x 5 = 15 
3 x 6 = 18 
3 x 7 = 21 
3 x 8 = 24 
3 x 9 = 27 
3 x 10 = 30 

Conditional

print(30>50)
[1] FALSE
print(30<50)
[1] TRUE
# Define a variable
temperature <- 25

# Simple if-else statement
if (temperature > 30) {
  cat("It's a hot day!\n")
} else {
  cat("It's not too hot today.\n")
}
It's not too hot today.
scores = c(100, 80, 75, 60, 55, 20, 98)

for(i in scores) {
  if (i >= 80) {
    cat("Score", i , "is A+ \n")
  }
  else if (i >= 70) {
     cat("Score", i , "is A \n")
  }
  else if (i >= 60) {
    cat("Score", i , "is B \n")
  }
  else {
    cat("Score", i , "is fail\n")
  }
}
Score 100 is A+ 
Score 80 is A+ 
Score 75 is A 
Score 60 is B 
Score 55 is fail
Score 20 is fail
Score 98 is A+ 
DNA_vector = c('AGTC', 'AGTCCA', 'AGTGAC', 'TGAC', 'GATC')
pattern <- "TC"

for(DNA in DNA_vector) {
  matches <- grepl(pattern, DNA)
  if(matches) {
    cat(DNA, '\n')
  }
}
AGTC 
AGTCCA 
GATC 

Data Science

Plot basics (ggplot)

# Load necessary libraries
library(ggplot2)

# Create a sample dataset
data <- data.frame(
  work_year = c(1, 2, 3, 1, 2, 3, 1, 2, 3),
  salary = c(50000, 60000, 55000, 45000, 55000, 58000, 48000, 59000, 60000)
)

# Create a violin plot
ggplot(data, aes(x = factor(work_year), y = salary)) +
  geom_violin(fill = "lightblue", color = "black") +
  labs(title = "Violin Plot of Salary by Work Year",
       x = "Work Year",
       y = "Salary")

library(datasets)
data(iris)
head(iris)
iris = read.csv('datasets/iris.csv')
iris
iris_dataset = iris
# Convert species labels to numeric values
species_numeric <- as.numeric(factor(iris$variety))
species_numeric
  [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 [47] 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 [93] 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
[139] 3 3 3 3 3 3 3 3 3 3 3 3
# Create a scatter plot using the plot function
plot(iris$sepal.length, iris$sepal.width, 
     col = species_numeric,      # Set scatter icon colors based on species
     pch = 1,                # Set scatter plot symbol
     cex = 1,               # Set scatter plot size
     xlim = c(4, 8),          # Set x-axis limits
     ylim = c(1, 5),          # Set y-axis limits
     xlab = "Sepal Length",   # Set x-axis label
     ylab = "Sepal Width",    # Set y-axis label
     main = "Scatter Plot of Sepal Length vs Sepal Width",  # Set main title
     col.main = "blue",       # Set main title color
     col.axis = "green",      # Set axis text color
     cex.main = 1.2,          # Set main title size
     cex.lab = 1.2,
     cex.axis = 2)           # Set axis label size)      

Histrogram - Distribution

library(ggplot2)
# install install.packages("colorspace") if error occurs -> could not find function "ggplot"

ggplot(iris, aes(x = sepal.length)) +
  geom_histogram(binwidth = 0.1, fill = "lightblue", color = "black") +
  labs(title = "Histogram of Sepal Length",
       x = "Sepal Length",
       y = "Frequency")

Scatter plot

ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width, color = Species)) +
  geom_point() +
  labs(title = "Scatter Plot of Sepal Length vs. Sepal Width",
       x = "Sepal Length",
       y = "Sepal Width")
Error in `geom_point()`:
! Problem while computing aesthetics.
ℹ Error occurred in the 1st layer.
Caused by error:
! object 'Sepal.Length' not found
Backtrace:
  1. base (local) `<fn>`(x)
  2. ggplot2:::print.ggplot(x)
  4. ggplot2:::ggplot_build.ggplot(x)
  5. ggplot2:::by_layer(...)
 12. ggplot2 (local) f(l = layers[[i]], d = data[[i]])
 13. l$compute_aesthetics(d, plot)
 14. ggplot2 (local) compute_aesthetics(..., self = self)
 15. ggplot2:::scales_add_defaults(...)
 16. base::lapply(aesthetics[new_aesthetics], eval_tidy, data = data)
 17. rlang (local) FUN(X[[i]], ...)

set colors

# Load the ggplot2 library
library(ggplot2)

# Plotting the scatter plot
ggplot(iris, aes(x = sepal.length, y = sepal.width, color = variety)) +
  geom_point() +
  scale_color_manual(values = c("Setosa" = "red", "Versicolor" = "purple", "Virginica" = "blue")) +
  labs(title = "Scatter Plot of Sepal Length vs Sepal Width",
       x = "Sepal Length",
       y = "Sepal Width")

# Load the ggplot2 library
library(ggplot2)

# Plotting the scatter plot with various customizations

scatter_plot = ggplot(iris, aes(x = sepal.length, y = sepal.width, color = variety)) +
  geom_point(size = 4) +  # Set scatter point size
  scale_color_manual(values = c("Setosa" = "red", "Versicolor" = "purple", "Virginica" = "blue")) +  # Set class color
  labs(title = "Scatter Plot of Sepal Length vs Sepal Width",
       x = "Sepal Length",
       y = "Sepal Width",
       caption = "Source: Iris Dataset") +  # Add a caption
  #theme_minimal() +  # Use a minimal theme -> background white
  theme(legend.position = "right",  # Move legend to the bottom
        text = element_text(size = 12, color = "black"),  # Set label text size and color
        axis.text = element_text(size = 10, color = "black"),  # Set axis text size and color
        axis.text.x = element_text(size = 10, color = "green"),  # Set x-axis text size and color
        axis.text.y = element_text(size = 10, color = "blue"),   # Set y-axis text size and color
        axis.title = element_text(size = 14, color = "black"),  # Set axis title size and color
        plot.title = element_text(size = 18, color = "black"),
        panel.background = element_rect(fill = "lightgray"),  # Set background color
        panel.grid = element_blank() # Remove grid lines
        ) +  # Set plot title size and color
  xlim(4, 8) +  # Set x-axis limits
  ylim(1, 5) +    # Set y-axis limits
  coord_fixed() # Square graph

# Save the plot with 300 dpi
ggsave("scatter_plot.png", plot = scatter_plot, dpi = 700)
Saving 7 x 7 in image
scatter_plot

Pair plot

pairs(iris[, 1:4], col = iris$Species)

Box plot

ggplot(iris, aes(x = Species, y = Sepal.Length, fill = Species)) +
  geom_boxplot() +
  labs(title = "Box Plot of Sepal Length by Species",
       x = "Species",
       y = "Sepal Length")

Violine plot

Correlation Matrix

cor_matrix <- cor(iris[, 1:4])
print(cor_matrix)
             Sepal.Length Sepal.Width Petal.Length Petal.Width
Sepal.Length    1.0000000  -0.1175698    0.8717538   0.8179411
Sepal.Width    -0.1175698   1.0000000   -0.4284401  -0.3661259
Petal.Length    0.8717538  -0.4284401    1.0000000   0.9628654
Petal.Width     0.8179411  -0.3661259    0.9628654   1.0000000

Heat map

cor_matrix <- cor(iris[, 1:4])
print(cor_matrix)
             Sepal.Length Sepal.Width Petal.Length Petal.Width
Sepal.Length    1.0000000  -0.1175698    0.8717538   0.8179411
Sepal.Width    -0.1175698   1.0000000   -0.4284401  -0.3661259
Petal.Length    0.8717538  -0.4284401    1.0000000   0.9628654
Petal.Width     0.8179411  -0.3661259    0.9628654   1.0000000
library(reshape2)
melted_cormat <- melt(cor_matrix)
print(melted_cormat)


library(ggplot2)
ggplot(data = melted_cormat, aes(x=Var1, y=Var2, fill=value)) +
  geom_tile() #heat map

ggplot(data = melted_cormat, aes(x=Var1, y=Var2, fill=value)) +
  geom_tile()+ #heat map
  geom_text(aes(Var2, Var1, label = round(value, digits = 2)), color = "black", size = 4) +

   scale_fill_gradient2(low = "blue", high = "red", mid = "white", 
   midpoint = 0, limit = c(-1,1), 
   name="Correlation")


cormat = cor_matrix

# Get upper triangle of the correlation matrix
cormat[lower.tri(cormat)]<- NA

upper_tri = cormat

# Melt the correlation matrix
library(reshape2)
melted_cormat <- melt(upper_tri, na.rm = TRUE)
melted_cormat


# Heatmap
library(ggplot2)
ggplot(data = melted_cormat, aes(Var2, Var1, fill = value))+

  geom_tile()+ #heat map
  
  geom_text(aes(Var2, Var1, label = round(value, digits = 2)), color = "black", size = 4) +

   scale_fill_gradient2(low = "blue", high = "red", mid = "white", 
   midpoint = 0, limit = c(-1,1), 
   name="Correlation") +
  
  theme_minimal()+ 
 
  theme(axis.text.x = element_text(angle = 45, vjust = 1, size = 12, hjust = 1))+
 
  coord_fixed() # square figure shape

library(ggcorrplot)

cor_matrix <- cor(iris[, 1:4])
print(cor_matrix)
             Sepal.Length Sepal.Width Petal.Length Petal.Width
Sepal.Length    1.0000000  -0.1175698    0.8717538   0.8179411
Sepal.Width    -0.1175698   1.0000000   -0.4284401  -0.3661259
Petal.Length    0.8717538  -0.4284401    1.0000000   0.9628654
Petal.Width     0.8179411  -0.3661259    0.9628654   1.0000000
ggcorrplot(cor_matrix, type = "lower")

ggcorrplot(cor_matrix, type = "upper")

ggcorrplot(cor_matrix, 
           type = "upper",
           colors = c("#6D9EC1", "white", "#E46726"))

ggcorrplot(cor_matrix, 
           type = "upper",
           colors = c("#6D9EC1", "white", "#E46726"),
           lab = TRUE)

library(ggplot2)
library(GGally)
ggpairs(iris, aes(colour = Species))

Linear Regression

lm_model <- lm(Sepal.Length ~ Petal.Length, data = iris)
summary(lm_model)

Call:
lm(formula = Sepal.Length ~ Petal.Length, data = iris)

Residuals:
     Min       1Q   Median       3Q      Max 
-1.24675 -0.29657 -0.01515  0.27676  1.00269 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)   4.30660    0.07839   54.94   <2e-16 ***
Petal.Length  0.40892    0.01889   21.65   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.4071 on 148 degrees of freedom
Multiple R-squared:   0.76, Adjusted R-squared:  0.7583 
F-statistic: 468.6 on 1 and 148 DF,  p-value: < 2.2e-16
#define data
x <- iris$Petal.Length
y <- iris$Sepal.Length
 
#plot x vs. y
plot(x, y, pch=16, cex=0.5, col=iris$Species) 
 
#fit polynomial regression model
fit <- lm(y ~ x)
 
#use model to get predicted values
pred <- predict(fit)
ix <- sort(x, index.return=T)$ix # sort and return the index
ix
  [1]  23  14  15  36   3  17  37  39  41  42  43   1   2   5   7   9  13  18  29  34  38  46  48  50   4   8  10  11
 [29]  16  20  22  28  32  33  35  40  49  12  26  27  30  31  44  47   6  19  21  24  25  45  99  58  94  61  80  65
 [57]  82  81  60  70  83  54  63  72  90  93  68  89 100  62  95  96  97  75  98  66  76  88  91  52  56  67  69  79
 [85]  85  86 107  55  59  92  51  57  64  74  87  71  77 127 139  53  73 122 124 128  78 114 120 147  84 102 111 115
[113] 134 142 143 150 146 148 112 116 140 149 113 117 138 104 129 133 135 137 141 121 125 145 105 109 130 103 144 101
[141] 126 110 131 136 108 132 106 118 123 119
conf_interval <- predict(fit, newdata=data.frame(x=x), interval="confidence",level = 0.95)

#add polynomial curve to plot
lines(x[ix], pred[ix], col='red', lwd=2)
lines(x[ix], conf_interval[ix,2], col="blue", lty=2)
lines(x[ix], conf_interval[ix,3], col="blue", lty=2)

ggplot(iris, aes(x = Petal.Length, y = Sepal.Length)) +
  geom_point() +
  geom_smooth(method = "lm", se = TRUE, color = "blue") +
  labs(title = "Linear Regression: Sepal Length vs. Petal Length",
       x = "Petal Length",
       y = "Sepal Length")

x=c(1,2,3,4,5,6,7,8,9,0)

y=c(13,28,43,35,96,84,101,110,108,13)

lm.out <- lm(y ~ x)
newx = seq(min(x),max(x),by = 0.05)
conf_interval <- predict(lm.out, newdata=data.frame(x=newx), interval="confidence",
                         level = 0.95)
conf_interval
           fit         lwr       upr
1     6.290909 -12.0738277  24.65565
2     6.922121 -11.2978658  25.14211
3     7.553333 -10.5223815  25.62905
4     8.184545  -9.7473863  26.11648
5     8.815758  -8.9728920  26.60441
6     9.446970  -8.1989108  27.09285
7    10.078182  -7.4254554  27.58182
8    10.709394  -6.6525386  28.07133
9    11.340606  -5.8801736  28.56139
10   11.971818  -5.1083743  29.05201
11   12.603030  -4.3371547  29.54322
12   13.234242  -3.5665293  30.03501
13   13.865455  -2.7965129  30.52742
14   14.496667  -2.0271210  31.02045
15   15.127879  -1.2583693  31.51413
16   15.759091  -0.4902741  32.00846
17   16.390303   0.2771479  32.50346
18   17.021515   1.0438794  32.99915
19   17.652727   1.8099027  33.49555
20   18.283939   2.5751997  33.99268
21   18.915152   3.3397515  34.49055
22   19.546364   4.1035389  34.98919
23   20.177576   4.8665419  35.48861
24   20.808788   5.6287403  35.98884
25   21.440000   6.3901128  36.48989
26   22.071212   7.1506380  36.99179
27   22.702424   7.9102936  37.49455
28   23.333636   8.6690568  37.99822
29   23.964848   9.4269040  38.50279
30   24.596061  10.1838112  39.00831
31   25.227273  10.9397535  39.51479
32   25.858485  11.6947054  40.02226
33   26.489697  12.4486408  40.53075
34   27.120909  13.2015327  41.04029
35   27.752121  13.9533536  41.55089
36   28.383333  14.7040751  42.06259
37   29.014545  15.4536682  42.57542
38   29.645758  16.2021030  43.08941
39   30.276970  16.9493490  43.60459
40   30.908182  17.6953749  44.12099
41   31.539394  18.4401485  44.63864
42   32.170606  19.1836371  45.15758
43   32.801818  19.9258070  45.67783
44   33.433030  20.6666238  46.19944
45   34.064242  21.4060524  46.72243
46   34.695455  22.1440569  47.24685
47   35.326667  22.8806006  47.77273
48   35.957879  23.6156462  48.30011
49   36.589091  24.3491554  48.82903
50   37.220303  25.0810894  49.35952
51   37.851515  25.8114088  49.89162
52   38.482727  26.5400733  50.42538
53   39.113939  27.2670421  50.96084
54   39.745152  27.9922738  51.49803
55   40.376364  28.7157262  52.03700
56   41.007576  29.4373569  52.57779
57   41.638788  30.1571228  53.12045
58   42.270000  30.8749805  53.66502
59   42.901212  31.5908861  54.21154
60   43.532424  32.3047954  54.76005
61   44.163636  33.0166639  55.31061
62   44.794848  33.7264472  55.86325
63   45.426061  34.4341004  56.41802
64   46.057273  35.1395788  56.97497
65   46.688485  35.8428377  57.53413
66   47.319697  36.5438327  58.09556
67   47.950909  37.2425194  58.65930
68   48.582121  37.9388540  59.22539
69   49.213333  38.6327930  59.79387
70   49.844545  39.3242936  60.36480
71   50.475758  40.0133136  60.93820
72   51.106970  40.6998117  61.51413
73   51.738182  41.3837475  62.09262
74   52.369394  42.0650817  62.67371
75   53.000606  42.7437760  63.25744
76   53.631818  43.4197938  63.84384
77   54.263030  44.0930996  64.43296
78   54.894242  44.7636596  65.02483
79   55.525455  45.4314417  65.61947
80   56.156667  46.0964156  66.21692
81   56.787879  46.7585530  66.81720
82   57.419091  47.4178275  67.42035
83   58.050303  48.0742149  68.02639
84   58.681515  48.7276935  68.63534
85   59.312727  49.3782435  69.24721
86   59.943939  50.0258480  69.86203
87   60.575152  50.6704922  70.47981
88   61.206364  51.3121641  71.10056
89   61.837576  51.9508542  71.72430
90   62.468788  52.5865559  72.35102
91   63.100000  53.2192650  72.98074
92   63.731212  53.8489801  73.61344
93   64.362424  54.4757027  74.24915
94   64.993636  55.0994368  74.88784
95   65.624848  55.7201891  75.52951
96   66.256061  56.3379692  76.17415
97   66.887273  56.9527890  76.82176
98   67.518485  57.5646632  77.47231
99   68.149697  58.1736089  78.12579
100  68.780909  58.7796456  78.78217
101  69.412121  59.3827954  79.44145
102  70.043333  59.9830823  80.10358
103  70.674545  60.5805326  80.76856
104  71.305758  61.1751747  81.43634
105  71.936970  61.7670390  82.10690
106  72.568182  62.3561574  82.78021
107  73.199394  62.9425639  83.45622
108  73.830606  63.5262938  84.13492
109  74.461818  64.1073839  84.81625
110  75.093030  64.6858723  85.50019
111  75.724242  65.2617985  86.18669
112  76.355455  65.8352027  86.87571
113  76.986667  66.4061264  87.56721
114  77.617879  66.9746116  88.26115
115  78.249091  67.5407012  88.95748
116  78.880303  68.1044388  89.65617
117  79.511515  68.6658680  90.35716
118  80.142727  69.2250333  91.06042
119  80.773939  69.7819792  91.76590
120  81.405152  70.3367502  92.47355
121  82.036364  70.8893912  93.18334
122  82.667576  71.4399469  93.89520
123  83.298788  71.9884618  94.60911
124  83.930000  72.5349805  95.32502
125  84.561212  73.0795471  96.04288
126  85.192424  73.6222054  96.76264
127  85.823636  74.1629989  97.48427
128  86.454848  74.7019707  98.20773
129  87.086061  75.2391633  98.93296
130  87.717273  75.7746188  99.65993
131  88.348485  76.3083785 100.38859
132  88.979697  76.8404834 101.11891
133  89.610909  77.3709736 101.85084
134  90.242121  77.8998886 102.58435
135  90.873333  78.4272673 103.31940
136  91.504545  78.9531478 104.05594
137  92.135758  79.4775676 104.79395
138  92.766970  80.0005632 105.53338
139  93.398182  80.5221706 106.27419
140  94.029394  81.0424250 107.01636
141  94.660606  81.5613606 107.75985
142  95.291818  82.0790112 108.50463
143  95.923030  82.5954096 109.25065
144  96.554242  83.1105879 109.99790
145  97.185455  83.6245773 110.74633
146  97.816667  84.1374085 111.49592
147  98.447879  84.6491112 112.24665
148  99.079091  85.1597146 112.99847
149  99.710303  85.6692469 113.75136
150 100.341515  86.1777357 114.50529
151 100.972727  86.6852081 115.26025
152 101.603939  87.1916900 116.01619
153 102.235152  87.6972071 116.77310
154 102.866364  88.2017841 117.53094
155 103.497576  88.7054451 118.28971
156 104.128788  89.2082138 119.04936
157 104.760000  89.7101128 119.80989
158 105.391212  90.2111645 120.57126
159 106.022424  90.7113904 121.33346
160 106.653636  91.2108116 122.09646
161 107.284848  91.7094485 122.86025
162 107.916061  92.2073209 123.62480
163 108.547273  92.7044482 124.39010
164 109.178485  93.2008491 125.15612
165 109.809697  93.6965418 125.92285
166 110.440909  94.1915441 126.69027
167 111.072121  94.6858731 127.45837
168 111.703333  95.1795457 128.22712
169 112.334545  95.6725780 128.99651
170 112.965758  96.1649859 129.76653
171 113.596970  96.6567847 130.53715
172 114.228182  97.1479893 131.30837
173 114.859394  97.6386142 132.08017
174 115.490606  98.1286736 132.85254
175 116.121818  98.6181810 133.62546
176 116.753030  99.1071498 134.39891
177 117.384242  99.5955929 135.17289
178 118.015455 100.0835228 135.94739
179 118.646667 100.5709518 136.72238
180 119.277879 101.0578918 137.49787
181 119.909091 101.5443541 138.27383
plot(x, y, xlab="x", ylab="y", main="Regression")
abline(lm.out, col="lightblue")
lines(newx, conf_interval[,2], col="blue", lty=2)
lines(newx, conf_interval[,3], col="blue", lty=2)

Polynomial Regression

ggplot(iris, aes(x = Petal.Length, y = Sepal.Length, color=Species)) +
  geom_point() +
  geom_smooth(method = "lm", formula=y~poly(x, 2), level=0.95, se = TRUE, color = "blue", fill='lightblue') +
  labs(title = "Polynomial Regression: Sepal Length vs. Petal Length",
       x = "Petal Length",
       y = "Sepal Length")

#define data
x <- iris$Petal.Length
y <- iris$Sepal.Length
 
#plot x vs. y
plot(x, y, pch=16, cex=1.5) 
 
#fit polynomial regression model
fit <- lm(y ~ x + I(x^2) + I(x^3))
summary(fit) 

Call:
lm(formula = y ~ x + I(x^2) + I(x^3))

Residuals:
     Min       1Q   Median       3Q      Max 
-1.06434 -0.24523  0.00707  0.19869  0.92755 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  4.64817    0.45873  10.133   <2e-16 ***
x            0.27811    0.48046   0.579    0.564    
I(x^2)      -0.04428    0.13454  -0.329    0.743    
I(x^3)       0.01055    0.01123   0.939    0.349    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.364 on 146 degrees of freedom
Multiple R-squared:  0.8106,    Adjusted R-squared:  0.8067 
F-statistic: 208.3 on 3 and 146 DF,  p-value: < 2.2e-16
#use model to get predicted values
ix <- sort(x, index.return=T)$ix

conf_interval <- predict(fit, newdata=data.frame(x=x), interval="confidence",level = 0.95)
#conf_interval

#add polynomial curve to plot
#lines(x[ix], pred[ix], col='red', lwd=2)
lines(x[ix], conf_interval[ix,1], col="blue")
lines(x[ix], conf_interval[ix,2], col="blue", lty=2)
lines(x[ix], conf_interval[ix,3], col="blue", lty=2)

# Load necessary libraries
library(stats)

# Load the iris dataset (it's built-in)
data(iris)

# Perform polynomial regression (quadratic model)
poly_model <- lm(Sepal.Length ~ poly(Sepal.Width, 2) + poly(Petal.Length, 2) + poly(Petal.Width, 2), data = iris)

# Print summary of polynomial regression
summary(poly_model)

Call:
lm(formula = Sepal.Length ~ poly(Sepal.Width, 2) + poly(Petal.Length, 
    2) + poly(Petal.Width, 2), data = iris)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.85830 -0.21065  0.00061  0.19278  0.77325 

Coefficients:
                       Estimate Std. Error t value Pr(>|t|)    
(Intercept)             5.84333    0.02509 232.877  < 2e-16 ***
poly(Sepal.Width, 2)1   2.99803    0.40359   7.428 9.12e-12 ***
poly(Sepal.Width, 2)2   0.34547    0.31951   1.081  0.28141    
poly(Petal.Length, 2)1 12.74168    1.78665   7.132 4.54e-11 ***
poly(Petal.Length, 2)2  1.59442    0.58991   2.703  0.00771 ** 
poly(Petal.Width, 2)1  -2.82015    1.72498  -1.635  0.10427    
poly(Petal.Width, 2)2  -0.95176    0.67450  -1.411  0.16040    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.3073 on 143 degrees of freedom
Multiple R-squared:  0.8678,    Adjusted R-squared:  0.8623 
F-statistic: 156.5 on 6 and 143 DF,  p-value: < 2.2e-16

Clustering

set.seed(123)
k <- 3
kmeans_result <- kmeans(iris[, 1:4], centers = k)
print(kmeans_result)
K-means clustering with 3 clusters of sizes 50, 62, 38

Cluster means:
  Sepal.Length Sepal.Width Petal.Length Petal.Width
1     5.006000    3.428000     1.462000    0.246000
2     5.901613    2.748387     4.393548    1.433871
3     6.850000    3.073684     5.742105    2.071053

Clustering vector:
  [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 3 2 2 2
 [57] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 3 3 3 3 2 3 3 3 3 3
[113] 3 2 2 3 3 3 3 2 3 2 3 2 3 3 2 2 3 3 3 3 3 2 3 3 3 3 2 3 3 3 2 3 3 3 2 3 3 2

Within cluster sum of squares by cluster:
[1] 15.15100 39.82097 23.87947
 (between_SS / total_SS =  88.4 %)

Available components:

[1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss" "betweenss"    "size"        
[8] "iter"         "ifault"      
ggplot(iris, aes(x = Petal.Length, y = Sepal.Length, color = factor(kmeans_result$cluster))) +
  geom_point() +
  labs(title = "K-Means Clustering: Sepal Length vs. Petal Length",
       x = "Petal Length",
       y = "Sepal Length")

# Load necessary libraries
library(stats)
library(ggplot2)  # For data visualization

# Load the iris dataset (it's built-in)
data(iris)

# Select only the numeric columns for clustering
data_for_clustering <- iris[, c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width")]

# Perform K-Means clustering with 3 clusters
k <- 3  # Number of clusters
kmeans_result <- kmeans(data_for_clustering, centers = k)
library(cluster)
clusplot(iris, kmeans_result$cluster, color=T, shade=T, labels=0, lines=0)

Classification

LASSO

# Load necessary libraries
library(glmnet)
Loading required package: Matrix
Loaded glmnet 4.1-7
# Load the iris dataset (it's built-in)
data(iris)

# Prepare data matrix and response vector
X <- model.matrix(Sepal.Length ~ Sepal.Width + Petal.Length + Petal.Width, data = iris)
y <- iris$Sepal.Length

# Perform lasso regression with cross-validation using glmnet
lasso_model <- cv.glmnet(X, y, alpha = 1)

# Print summary of lasso regression
print(lasso_model)

Call:  cv.glmnet(x = X, y = y, alpha = 1) 

Measure: Mean-Squared Error 

      Lambda Index Measure      SE Nonzero
min 0.000611    77  0.1048 0.01041       3
1se 0.013171    44  0.1143 0.01135       3

SVM

# Load necessary libraries
library(e1071)  # For SVM
library(caret)   # For model evaluation
Loading required package: lattice
library(ggplot2) 
library(lattice)

# Load the iris dataset (it's built-in)
data(iris)

# Split the data into training and testing sets
set.seed(123)
train_indices <- createDataPartition(iris$Species, p = 0.8, list = FALSE)
train_data <- iris[train_indices, ]
test_data <- iris[-train_indices, ]

# Train an SVM classifier with a linear kernel
svm_model <- svm(Species ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width, data = train_data, kernel = "linear")

# Predict using the trained model
predictions <- predict(svm_model, newdata = test_data)

# Confusion matrix
conf_matrix <- confusionMatrix(predictions, test_data$Species)

# Print confusion matrix
print("Confusion Matrix:")
[1] "Confusion Matrix:"
print(conf_matrix)
Confusion Matrix and Statistics

            Reference
Prediction   setosa versicolor virginica
  setosa         10          0         0
  versicolor      0         10         1
  virginica       0          0         9

Overall Statistics
                                          
               Accuracy : 0.9667          
                 95% CI : (0.8278, 0.9992)
    No Information Rate : 0.3333          
    P-Value [Acc > NIR] : 2.963e-13       
                                          
                  Kappa : 0.95            
                                          
 Mcnemar's Test P-Value : NA              

Statistics by Class:

                     Class: setosa Class: versicolor Class: virginica
Sensitivity                 1.0000            1.0000           0.9000
Specificity                 1.0000            0.9500           1.0000
Pos Pred Value              1.0000            0.9091           1.0000
Neg Pred Value              1.0000            1.0000           0.9524
Prevalence                  0.3333            0.3333           0.3333
Detection Rate              0.3333            0.3333           0.3000
Detection Prevalence        0.3333            0.3667           0.3000
Balanced Accuracy           1.0000            0.9750           0.9500
# Accuracy
accuracy <- conf_matrix$overall["Accuracy"]
print(paste("Accuracy:", accuracy))
[1] "Accuracy: 0.966666666666667"
# F1 Score
f1_score <- conf_matrix$byClass["F1"]
print(paste("F1 Score:", f1_score))
[1] "F1 Score: NA"
# Load necessary libraries
library(e1071)  # For SVM
library(caret)   # For model evaluation
library(ggplot2) 
library(lattice)

# Load the iris dataset (it's built-in)
data(iris)

# Split the data into training and testing sets
set.seed(123)
train_indices <- createDataPartition(iris$Species, p = 0.8, list = FALSE)
train_data <- iris[train_indices, ]
test_data <- iris[-train_indices, ]

# Train an SVM classifier with a linear kernel
svm_model <- svm(Species ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width, data = train_data, kernel = "linear")

# Predict using the trained model
predictions <- predict(svm_model, newdata = test_data)

# Confusion matrix
conf_matrix <- confusionMatrix(predictions, test_data$Species)

# Print confusion matrix
print("Confusion Matrix:")
[1] "Confusion Matrix:"
print(conf_matrix)
Confusion Matrix and Statistics

            Reference
Prediction   setosa versicolor virginica
  setosa         10          0         0
  versicolor      0         10         1
  virginica       0          0         9

Overall Statistics
                                          
               Accuracy : 0.9667          
                 95% CI : (0.8278, 0.9992)
    No Information Rate : 0.3333          
    P-Value [Acc > NIR] : 2.963e-13       
                                          
                  Kappa : 0.95            
                                          
 Mcnemar's Test P-Value : NA              

Statistics by Class:

                     Class: setosa Class: versicolor Class: virginica
Sensitivity                 1.0000            1.0000           0.9000
Specificity                 1.0000            0.9500           1.0000
Pos Pred Value              1.0000            0.9091           1.0000
Neg Pred Value              1.0000            1.0000           0.9524
Prevalence                  0.3333            0.3333           0.3333
Detection Rate              0.3333            0.3333           0.3000
Detection Prevalence        0.3333            0.3667           0.3000
Balanced Accuracy           1.0000            0.9750           0.9500
# Accuracy
accuracy <- conf_matrix$overall["Accuracy"]
print(paste("Accuracy:", accuracy))
[1] "Accuracy: 0.966666666666667"
# F1 Score
f1_score <- conf_matrix$byClass["F1"]
print(paste("F1 Score:", f1_score))
[1] "F1 Score: NA"
# Plot the confusion matrix
conf_plot <- plot(conf_matrix$table, col = c("lightblue", "lightcoral"),
                  main = "Confusion Matrix for SVM on Iris Dataset",
                  xlab = "Predicted", ylab = "Actual")


# Display the plot
conf_plot
NULL
cm = conf_matrix

plt <- as.data.frame(cm$table)
plt$Prediction <- factor(plt$Prediction, levels=rev(levels(plt$Prediction)))

ggplot(plt, aes(Prediction,Reference, fill= Freq)) +
        geom_tile() + 
        geom_text(aes(label=Freq)) +
        scale_fill_gradient(low="white", high="skyblue") +
        labs(x = "Reference",
             y = "Prediction") 

rev(levels(plt$Prediction))
[1] "setosa"     "versicolor" "virginica" 
# Import caret library
library(caret)
 
# Create Data
actual <- factor(rep(c(1, 2),
                     times=c(16, 24)))
predicted <- factor(rep(c(1, 2, 1, 2),
                        times=c(12, 4, 7, 17)))
 
# create confusion matrix 
confusionMatrix(predicted, actual,
                mode = "everything",
                positive="1")
Confusion Matrix and Statistics

          Reference
Prediction  1  2
         1 12  7
         2  4 17
                                         
               Accuracy : 0.725          
                 95% CI : (0.5611, 0.854)
    No Information Rate : 0.6            
    P-Value [Acc > NIR] : 0.07095        
                                         
                  Kappa : 0.4444         
                                         
 Mcnemar's Test P-Value : 0.54649        
                                         
            Sensitivity : 0.7500         
            Specificity : 0.7083         
         Pos Pred Value : 0.6316         
         Neg Pred Value : 0.8095         
              Precision : 0.6316         
                 Recall : 0.7500         
                     F1 : 0.6857         
             Prevalence : 0.4000         
         Detection Rate : 0.3000         
   Detection Prevalence : 0.4750         
      Balanced Accuracy : 0.7292         
                                         
       'Positive' Class : 1              
                                         

Statistical Analysis

# Calculate probability
prob_setosa <- sum(iris$Species == "setosa") / nrow(iris)
print("Probability of Setosa:")
[1] "Probability of Setosa:"
print(prob_setosa)
[1] 0.3333333
# Normal distribution
hist(iris$Sepal.Length, probability = TRUE, main = "Histogram of Sepal Length")
lines(density(iris$Sepal.Length), col = "blue")

PCA

# Principal Component Analysis (PCA)
pca <- prcomp(iris[, -5])
summary(pca)
Importance of components:
                          PC1     PC2    PC3     PC4
Standard deviation     2.0563 0.49262 0.2797 0.15439
Proportion of Variance 0.9246 0.05307 0.0171 0.00521
Cumulative Proportion  0.9246 0.97769 0.9948 1.00000

T-test

setosa <- iris$Sepal.Length[iris$Species == "setosa"]
virginica <- iris$Sepal.Length[iris$Species == "virginica"]
t_test_result <- t.test(setosa, virginica)
print(t_test_result)

    Welch Two Sample t-test

data:  setosa and virginica
t = -15.386, df = 76.516, p-value < 2.2e-16
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -1.78676 -1.37724
sample estimates:
mean of x mean of y 
    5.006     6.588 
setosa <- iris$Sepal.Length[iris$Species == "setosa"]
virginica <- iris$Sepal.Length[iris$Species == "virginica"]
t_test_result <- t.test(setosa, virginica, alternative = "two.sided")
print(t_test_result)

    Welch Two Sample t-test

data:  setosa and virginica
t = -15.386, df = 76.516, p-value < 2.2e-16
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -1.78676 -1.37724
sample estimates:
mean of x mean of y 
    5.006     6.588 
# https://www.statology.org/interpret-t-test-results-in-r/

ANOVA

anova_result <- aov(Sepal.Length ~ Species, data = iris)
summary(anova_result)
             Df Sum Sq Mean Sq F value Pr(>F)    
Species       2  63.21  31.606   119.3 <2e-16 ***
Residuals   147  38.96   0.265                   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Tukey’s posthoc test

posthoc <- TukeyHSD(anova_result)
print(posthoc)

Chi-square test

# Load necessary libraries
library(stats)

# Load the iris dataset (it's built-in)
data(iris)

# Chi-square test (testing independence between species and petal length)
chisq.test(table(iris$Species, cut(iris$Petal.Length, breaks = c(1, 2, 3, 4, 5))))
# Load necessary libraries
library(ggplot2)
library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(reshape)

Attaching package: ‘reshape’

The following object is masked from ‘package:dplyr’:

    rename

The following object is masked from ‘package:plotly’:

    rename
# Load the iris dataset (it's built-in)
data(iris)

# Pairwise scatter plot with color by Species
ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width, color = Species)) +
  geom_point() +
  facet_grid(~Species) +
  labs(title = "Pairwise Scatter Plot",
       x = "Sepal Length", y = "Sepal Width")

# Load required library
library(ggplot2)
library(stats)

iris = read.csv('Class 4/iris.csv')

# Apply PCA
iris_pca <- prcomp(iris[, -5], center = TRUE, scale = TRUE)
iris_pca
Standard deviations (1, .., p=4):
[1] 1.7083611 0.9560494 0.3830886 0.1439265

Rotation (n x k) = (4 x 4):
                    PC1         PC2        PC3        PC4
sepal.length  0.5210659 -0.37741762  0.7195664  0.2612863
sepal.width  -0.2693474 -0.92329566 -0.2443818 -0.1235096
petal.length  0.5804131 -0.02449161 -0.1421264 -0.8014492
petal.width   0.5648565 -0.06694199 -0.6342727  0.5235971
summary(iris_pca)
Importance of components:
                          PC1    PC2     PC3     PC4
Standard deviation     1.7084 0.9560 0.38309 0.14393
Proportion of Variance 0.7296 0.2285 0.03669 0.00518
Cumulative Proportion  0.7296 0.9581 0.99482 1.00000
# Extract PC scores
pc_scores <- as.data.frame(iris_pca$x[, 1:2])
pc_scores

# Combine PC scores with Species
pc_data <- cbind(pc_scores, Species = iris$variety)
pc_data

# Plot PCA (2D)
ggplot(pc_data, aes(PC1, PC2, color = Species)) +
  geom_point() +
  labs(title = "PCA (2D) of Iris Dataset",
       x = "Principal Component 1",
       y = "Principal Component 2") +
  theme_minimal()


# http://www.sthda.com/english/articles/31-principal-component-methods-in-r-practical-guide/118-principal-component-analysis-in-r-prcomp-vs-princomp/
# https://www.datacamp.com/tutorial/pca-analysis-r
# http://www.sthda.com/english/articles/31-principal-component-methods-in-r-practical-guide/112-pca-principal-component-analysis-essentials/
fviz_cos2(iris_pca, choice = "var", axes = 1:2)

# Contributions of variables to PC1
fviz_contrib(iris_pca, choice = "var", axes = 1)

# Contributions of variables to PC2
fviz_contrib(iris_pca, choice = "var", axes = 2)

var <- get_pca_var(iris_pca)
var
Principal Component Analysis Results for variables
 ===================================================
  Name       Description                                    
1 "$coord"   "Coordinates for the variables"                
2 "$cor"     "Correlations between variables and dimensions"
3 "$cos2"    "Cos2 for the variables"                       
4 "$contrib" "contributions of the variables"               
library("corrplot")
corrplot(var$cos2, is.corr=FALSE)



var <- get_pca_var(iris_pca)
var$contrib
                 Dim.1       Dim.2     Dim.3     Dim.4
sepal.length 27.150969 14.24440565 51.777574  6.827052
sepal.width   7.254804 85.24748749  5.972245  1.525463
petal.length 33.687936  0.05998389  2.019990 64.232089
petal.width  31.906291  0.44812296 40.230191 27.415396
library(factoextra)
fviz_eig(iris_pca, addlabels = TRUE)

# Graph of the variables
fviz_pca_var(iris_pca, col.var = "contrib", # Color by contributions to the PC
             gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
             repel = TRUE )    # Avoid text overlapping)

fviz_pca_ind(iris_pca,
             col.ind = "cos2", # Color by the quality of representation
             gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
             repel = TRUE     # Avoid text overlapping
             )

fviz_pca_ind(iris_pca,
             geom.ind = "point", # show points only (nbut not "text")
             col.ind = "cos2", # Color by the quality of representation
             gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
             repel = TRUE     # Avoid text overlapping
             )

fviz_pca_ind(iris_pca,
             geom.ind = "point", # show points only (nbut not "text")
             col.ind = iris$variety, # color by groups
             palette = c("#00AFBB", "#E7B800", "#FC4E07"),
             addEllipses = TRUE, # Concentration ellipses
             legend.title = "Groups"
             )

Interactive plot

# Load required library
library(plotly)
Loading required package: ggplot2
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio

Attaching package: ‘plotly’

The following object is masked from ‘package:ggplot2’:

    last_plot

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout
iris = read.csv('datasets/iris.csv')

# Plot 3D Scatter Plot
plot_ly(data = iris, x = ~sepal.length, y = ~sepal.width, z = ~petal.length, color = ~variety,
        type = "scatter3d", mode = "markers") %>%
  layout(scene = list(xaxis = list(title = 'Sepal Length'),
                      yaxis = list(title = 'Sepal Width'),
                      zaxis = list(title = 'Petal Length')),
         margin = list(l = 0, r = 0, b = 0, t = 0))
NA
library(plotly)

fig <- iris %>%
  plot_ly(y = ~sepal.width,type = 'violin') 

fig
NA
fig <- iris %>%
  plot_ly(
    y = ~sepal.width,
    type = 'box'
  )

fig
fig <- iris %>%
  plot_ly(
    y = ~sepal.width,
    type = 'bar'
  ) 

fig
fig <- iris %>%
  plot_ly(
    x = ~sepal.width,
    type = 'histogram'
  ) 

fig

# Load required library
library(plotly)


# Create Boxplot
boxplot = plot_ly(iris, x = ~variety, y = ~sepal.length, type = "box") %>%
  layout(
    xaxis = list(title = "Category"),  # Set X-axis title
    yaxis = list(title = "Value")     # Set Y-axis title
  )

# Print the plot
boxplot
# Load required library
library(plotly)

# Load Iris dataset
data(iris)

# 1. Scatter Plot
scatter_plot <- plot_ly(iris, x = ~Sepal.Length, y = ~Sepal.Width, color = ~Species, type = "scatter", mode = "markers") %>%
  layout(xaxis = list(title = "Sepal Length"), yaxis = list(title = "Sepal Width"), title = "Scatter Plot")
scatter_plot


# 2. Box Plot
box_plot <- plot_ly(iris, x = ~Species, y = ~Petal.Length, type = "box") %>%
  layout(xaxis = list(title = "Species"), yaxis = list(title = "Petal Length"), title = "Box Plot")
box_plot


# 3. Violin Plot
violin_plot <- plot_ly(iris, x = ~Species, y = ~Petal.Width, type = "violin") %>%
  layout(xaxis = list(title = "Species"), yaxis = list(title = "Petal Width"), title = "Violin Plot")
violin_plot


# 4. Histogram
histogram_plot <- plot_ly(iris, x = ~Sepal.Length, type = "histogram") %>%
  layout(xaxis = list(title = "Sepal Length"), yaxis = list(title = "Frequency"), title = "Histogram")
histogram_plot


# 5. Heatmap of Correlation Matrix
correlation_matrix <- cor(iris[, c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width")])
heatmap_plot <- plot_ly(z = correlation_matrix, type = "heatmap", colorscale = "Viridis") %>%
  layout(xaxis = list(title = colnames(correlation_matrix)), yaxis = list(title = colnames(correlation_matrix)), title = "Correlation Heatmap")
heatmap_plot


# 6. Bar Plot
bar_plot <- plot_ly(iris, x = ~Species, type = "bar", marker = list(color = "blue")) %>%
  layout(xaxis = list(title = "Species"), yaxis = list(title = "Count"), title = "Bar Plot")
bar_plot


# 7. Line Plot after Sorting a Column
sorted_data <- iris[order(iris$Sepal.Length), ]
line_plot <- plot_ly(sorted_data, x = ~Sepal.Length, y = ~Sepal.Width, type = "scatter", mode = "lines") %>%
  layout(xaxis = list(title = "Sepal Length (Sorted)"), yaxis = list(title = "Sepal Width"), title = "Line Plot (Sorted)")
line_plot


# Display plots
#subplot(scatter_plot, box_plot, violin_plot, histogram_plot, heatmap_plot, bar_plot, line_plot, nrows = 4)
# Load required libraries
library(ggplot2)
library(plotly)

# Use plot_ly to create a 3D scatter plot
plot_ly(data = iris, x = ~sepal.length, y = ~sepal.width, z = ~petal.length, color = ~variety, type = "scatter3d", mode = "markers") %>%
  layout(scene = list(xaxis = list(title = "Sepal Length"),
                      yaxis = list(title = "Sepal Width"),
                      zaxis = list(title = "Petal Length")))
NA
# Load required libraries
library(plotly)

# Create sample data for the surface plot
x <- seq(-10, 10, length.out = 100)
y <- seq(-10, 10, length.out = 100)
z <- outer(x, y, function(x, y) sin(sqrt(x^2 + y^2)) / sqrt(x^2 + y^2))

# Define a custom color scale
color_scale <- c("#440154", "#482878", "#3E4989", "#31688E", "#26838E", "#1F9E89", "#35B779", "#6DCD59", "#B4DE2C", "#FDE725")

color_scale <- c("purple", "white", "red")

# Create a 3D surface plot
plot_ly(z = ~z, x = ~x, y = ~y, type = "surface", colors = color_scale) %>%
  layout(scene = list(
    xaxis = list(title = 'X-axis'),
    yaxis = list(title = 'Y-axis'),
    zaxis = list(title = 'Z-axis')
  ))
NA
library(reshape2)
library(tidyverse)
library(tidymodels)
library(plotly)
library(kernlab)
library(pracma) #For meshgrid()


data(iris)

mesh_size <- .02
margin <- 0


model <- svm_rbf(cost = 1.0) %>% 
  set_engine("kernlab") %>% 
  set_mode("regression") %>% 
  fit(Petal.Width ~ Sepal.Width + Sepal.Length, data = iris)

x_min <- min(X$Sepal.Width) - margin
x_max <- max(X$Sepal.Width) - margin
y_min <- min(X$Sepal.Length) - margin
y_max <- max(X$Sepal.Length) - margin
xrange <- seq(x_min, x_max, mesh_size)
yrange <- seq(y_min, y_max, mesh_size)
xy <- meshgrid(x = xrange, y = yrange)
xx <- xy$X
yy <- xy$Y
dim_val <- dim(xx)
xx1 <- matrix(xx, length(xx), 1)
yy1 <- matrix(yy, length(yy), 1)
final <- cbind(xx1, yy1)
pred <- model %>%
  predict(final)

pred <- pred$.pred
pred <- matrix(pred, dim_val[1], dim_val[2])

fig <- plot_ly(iris, x = ~Sepal.Width, y = ~Sepal.Length, z = ~Petal.Width ) %>% 
  add_markers(size = 5) %>% 
  add_surface(x=xrange, y=yrange, z=pred, alpha = 0.65, type = 'mesh3d', name = 'pred_surface')
fig
NA
NA
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OgogICAgZGZfcHJpbnQ6IHBhZ2VkCi0tLQoKVHJ5IGV4ZWN1dGluZyB0aGlzIGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqUnVuKiBidXR0b24gd2l0aGluIHRoZSBjaHVuayBvciBieSBwbGFjaW5nIHlvdXIgY3Vyc29yIGluc2lkZSBpdCBhbmQgcHJlc3NpbmcgKkNtZCtTaGlmdCtFbnRlciouIAoKQWRkIGEgbmV3IGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqSW5zZXJ0IENodW5rKiBidXR0b24gb24gdGhlIHRvb2xiYXIgb3IgYnkgcHJlc3NpbmcgKkNtZCtPcHRpb24rSSouCgpXaGVuIHlvdSBzYXZlIHRoZSBub3RlYm9vaywgYW4gSFRNTCBmaWxlIGNvbnRhaW5pbmcgdGhlIGNvZGUgYW5kIG91dHB1dCB3aWxsIGJlIHNhdmVkIGFsb25nc2lkZSBpdCAoY2xpY2sgdGhlICpQcmV2aWV3KiBidXR0b24gb3IgcHJlc3MgKkNtZCtTaGlmdCtLKiB0byBwcmV2aWV3IHRoZSBIVE1MIGZpbGUpLiAKCgpgYGB7ciwgZWNobz1GQUxTRX0KcGxvdChjYXJzKQpgYGAKYGBge3J9CnN1bW1hcnkoY2FycykKYGBgCgoKYGBge3J9CnggPSBjYXJzCmBgYAoKIyNWYXJpYWJsZXMKCiMjIyMgUiBWYXJpYWJsZSBOYW1pbmcgQ29udmVudGlvbnM6CgoqIFN0YXJ0IHdpdGggYSBMZXR0ZXIgb3IgYSBEb3Q6CiAgICArIENvcnJlY3Q6IHZhcmlhYmxlMSwgLnZhcmlhYmxlMiwgbXlfdmFyaWFibGUKICAgICsgSW5jb3JyZWN0OiAxdmFyaWFibGUsICZ2YXJpYWJsZSwgJXZhcgoqIFN1YnNlcXVlbnQgQ2hhcmFjdGVyczoKICAgICsgQ29ycmVjdDogdmFyaWFibGVfbmFtZSwgVmFyTmFtZSwgdG90YWxfY291bnQKICAgICsgSW5jb3JyZWN0OiB2YXJpYWJsZS1uYW1lLCB2YXJpYWJsZS5uYW1lLCBWYXJpYWJsZSBOYW1lCiogQXZvaWQgUmVzZXJ2ZWQgV29yZHM6CiAgICArIENvcnJlY3Q6IHZhciwgdmFyaWFibGUsIGEsIGIsIGMKICAgICsgSW5jb3JyZWN0OiBpZiwgZWxzZSwgZm9yCgoqIENhc2UgU2Vuc2l0aXZpdHk6CiAgICArIENvcnJlY3Q6IG15VmFyLCBNeVZhciwgbXl2YXIKICAgICsgSW5jb3JyZWN0OiBteXZhciBhbmQgTXlWYXIgaW4gdGhlIHNhbWUgc2NvcGUKCiogRGVzY3JpcHRpdmUgYW5kIENsZWFyOgogICAgKyBDb3JyZWN0OiB0b3RhbF9zYWxlcywgdXNlcl9hZ2UsIGN1c3RvbWVyX2lkCiAgICArIEluY29ycmVjdDogdGVtcCwgeCwgdjEKCiogVXNlIFVuZGVyc2NvcmUgZm9yIFJlYWRhYmlsaXR5OgogICAgKyBDb3JyZWN0OiB0b3RhbF9jb3VudCwgdXNlcl9uYW1lLCBhdmVyYWdlX3Njb3JlCiAgICArIEluY29ycmVjdDogdG90YWxDb3VudCwgdXNlck5hbWUsIEF2ZXJhZ2VTY29yZQoKKiBBdm9pZCBEb3RzIGluIFZhcmlhYmxlIE5hbWVzOgogICAgKyBDb3JyZWN0OiB0b3RhbF9jb3VudCwgdXNlcl9hZ2UKICAgICsgSW5jb3JyZWN0OiB0b3RhbC5jb3VudCwgdXNlci5hZ2UKCiogQXZvaWQgU3RhcnRpbmcgd2l0aCBEb3Q6CiAgICArIENvcnJlY3Q6IC52YXJpYWJsZSwgLmNvdW50CiAgICArIEluY29ycmVjdDogLmNvdW50LCAudG90YWwKCiogQXZvaWQgU3BlY2lhbCBDaGFyYWN0ZXJzOgogICAgKyBDb3JyZWN0OiB0b3RhbF9jb3VudCwgdXNlcl9hZ2UKICAgICsgSW5jb3JyZWN0OiB0b3RhbC1jb3VudCwgdXNlckBhZ2UKCiogQXZvaWQgU3RhcnRpbmcgd2l0aCBOdW1iZXJzOgogICAgKyBDb3JyZWN0OiB2YXIxLCB2YXJfMQogICAgKyBJbmNvcnJlY3Q6IDF2YXIsIDFfdmFyaWFibGUKCgpgYGB7cn0KIyBOdW1lcmljIGRhdGEgdHlwZSAoZmxvYXRpbmctcG9pbnQgbnVtYmVyKQpudW1fdmFyaWFibGUgPC0gNDIuNQoKIyBJbnRlZ2VyIGRhdGEgdHlwZQppbnRfdmFyaWFibGUgPC0gMTBMCgojIENoYXJhY3RlciBkYXRhIHR5cGUgKHRleHQpCmNoYXJfdmFyaWFibGUgPC0gIkhlbGxvLCBSISIKCiMgTG9naWNhbCBkYXRhIHR5cGUgKFRSVUUgb3IgRkFMU0UpCmxvZ2ljYWxfdmFyaWFibGUgPC0gVFJVRQoKIyBWZWN0b3IgZGF0YSB0eXBlICgxLWRpbWVuc2lvbmFsIGFycmF5KQpudW1lcmljX3ZlY3RvciA8LSBjKDEsIDIsIDMsIDQsIDUpCmNoYXJfdmVjdG9yIDwtIGMoImFwcGxlIiwgImJhbmFuYSIsICJvcmFuZ2UiLCAncmVkJywgJ2JsdWUnKQpsb2dpY2FsX3ZlY3RvciA8LSBjKFRSVUUsIEZBTFNFLCBUUlVFKQoKIyBNYXRyaXggZGF0YSB0eXBlICgyLWRpbWVuc2lvbmFsIGFycmF5KQptYXRyaXhfZGF0YSA8LSBtYXRyaXgoYygxLCAyLCAzLCA0LCA1LCA2KSwgbnJvdyA9IDIsIG5jb2wgPSAzKQoKIyBMaXN0IGRhdGEgdHlwZSAoY29sbGVjdGlvbiBvZiBkaWZmZXJlbnQgZGF0YSB0eXBlcykKbGlzdF9kYXRhIDwtIGxpc3QobmFtZSA9ICJKb2huIiwgYWdlID0gMzAsIG1hcnJpZWQgPSBUUlVFKQoKcHJpbnQobGlzdF9kYXRhKQpsaXN0X2RhdGEkYWdlIDwtIDM1CnByaW50KGxpc3RfZGF0YSkKYGBgCgpgYGB7cn0KcHJpbnQobGlzdF9kYXRhKQpgYGAKCiMjIEFyaXRobWV0aWMgT3BlcmF0aW9ucwpgYGB7cn0KCiMgQWRkaXRpb24KcmVzdWx0X2FkZCA8LSAxMCArIDUKCiMgU3VidHJhY3Rpb24KcmVzdWx0X3N1YiA8LSAyMCAtIDgKCiMgTXVsdGlwbGljYXRpb24KcmVzdWx0X211bCA8LSA2ICogNwoKIyBEaXZpc2lvbgpyZXN1bHRfZGl2IDwtIDE1IC8gMwoKIyBNb2R1bG8gKHJlbWFpbmRlciBhZnRlciBkaXZpc2lvbikKcmVzdWx0X21vZCA8LSAxNyAlJSA1CgojIEV4cG9uZW50aWF0aW9uIChyYWlzaW5nIHRvIGEgcG93ZXIpCnJlc3VsdF9leHAgPC0gMl4zCgojIENvbWJpbmVkIEFyaXRobWV0aWMgT3BlcmF0aW9ucwpyZXN1bHRfY29tYmluZWQgPC0gKDUgKyAzKSAqIDIKYGBgCgoKIyMgU3RyaW5nCgojIyMgMS4gQ29uY2F0ZW5hdGlvbiAoQ29tYmluaW5nIEROQSBTZXF1ZW5jZXMpCmBgYHtyfQojIFVzaW5nIHBhc3RlKCkKc2VxdWVuY2UxIDwtICJBVENHIgpzZXF1ZW5jZTIgPC0gIkdDVEEiCmNvbWJpbmVkX3NlcXVlbmNlIDwtIHBhc3RlKHNlcXVlbmNlMSwgc2VxdWVuY2UyLCBzZXAgPSAiIikKcHJpbnQoY29tYmluZWRfc2VxdWVuY2UpICAjICJBVENHR0NUQSIKCmBgYAoKIyMjIDIuIFN1YnN0cmluZyAoRXh0cmFjdGluZyBHZW5lIFNlZ21lbnQpOgpgYGB7cn0KIyBVc2luZyBzdWJzdHIoKQpnZW5lX3NlcXVlbmNlIDwtICJBVENHQVRDR0FUQ0ciCmdlbmVfc2VnbWVudCA8LSBzdWJzdHIoZ2VuZV9zZXF1ZW5jZSwgc3RhcnQgPSAxLCBzdG9wID0gNCkKcHJpbnQoZ2VuZV9zZWdtZW50KSAgIyAiQVRDRyIKCmBgYAoKIyMjIDMuIFN0cmluZyBMZW5ndGggKExlbmd0aCBvZiBETkEgU2VxdWVuY2UpOgpgYGB7cn0KIyBVc2luZyBuY2hhcigpCmRuYV9zZXF1ZW5jZSA8LSAiQVRDR0FUQ0dBVENHIgpzZXF1ZW5jZV9sZW5ndGggPC0gbmNoYXIoZG5hX3NlcXVlbmNlKQpwcmludChzZXF1ZW5jZV9sZW5ndGgpICAjIDEyCgpgYGAKCiMjIyA0LiBDaGFuZ2luZyBDYXNlIApgYGB7cn0KIyBUbyBVcHBlcmNhc2UKdXBwZXJjYXNlX2RuYSA8LSB0b3VwcGVyKCJhdGNnIikKcHJpbnQodXBwZXJjYXNlX2RuYSkgICMgIkFUQ0ciCmBgYAoKIyMjIDUuIFBhdHRlcm4gTWF0Y2hpbmcgCmBgYHtyfQojIFVzaW5nIGdyZXBsKCkKZ2VuZV9zZXF1ZW5jZSA8LSAiQVRDR0FUQ0dBVENHIgptb3RpZiA8LSAiQVRDIgptYXRjaGVzIDwtIGdyZXBsKG1vdGlmLCBnZW5lX3NlcXVlbmNlKQpwcmludChtYXRjaGVzKSAgIyBUUlVFCmBgYAoKIyMjIDYuIFNwbGl0dGluZyBTdHJpbmdzCmBgYHtyfQojIFVzaW5nIHN0cnNwbGl0KCkKZ2VuZXMgPC0gIkdlbmVYLEdlbmVZLEdlbmVaIgpzcGxpdF9nZW5lcyA8LSBzdHJzcGxpdChnZW5lcywgIiwiKVtbMV1dCnByaW50KHNwbGl0X2dlbmVzKQojIFsiR2VuZVgiLCAiR2VuZVkiLCAiR2VuZVoiXQoKYGBgCgojIyMgNy4gUmV2ZXJzaW5nIGEgU3RyaW5nCmBgYHtyfQpsaWJyYXJ5KHN0cmluZ2kpCmRuYV9zZXF1ZW5jZSA8LSAiQVRDR0FUQ0ciCnJldmVyc2VkX3NlcXVlbmNlIDwtIHN0cmlfcmV2ZXJzZShkbmFfc2VxdWVuY2UpCnByaW50KHJldmVyc2VkX3NlcXVlbmNlKSAgIyAiR0NUQUdDVEEiCmBgYAoKCiMjIyA4LiBGaW5kIG9jY3VyYW5jZXMKYGBge3J9CiMgRE5BIHNlcXVlbmNlCmRuYV9zZXF1ZW5jZSA8LSAiQVRDR0FUQ0dBVENHQVRDR0FUQ0ciCgojIFN1YnN0cmluZyB0byBmaW5kIGZyZXF1ZW5jeQpzdWJzdHJpbmdfdG9fZmluZCA8LSAiQVRDIgoKIyBVc2luZyBncmVnZXhwciB0byBmaW5kIHBvc2l0aW9ucyBvZiB0aGUgc3Vic3RyaW5nCm1hdGNoZXMgPC0gZ3JlZ2V4cHIoc3Vic3RyaW5nX3RvX2ZpbmQsIGRuYV9zZXF1ZW5jZSkKCm1hdGNoX3Bvc2l0aW9ucyA9IHVubGlzdChtYXRjaGVzKQpwcmludChtYXRjaF9wb3NpdGlvbnMpCgojIENvdW50aW5nIHRoZSBudW1iZXIgb2YgbWF0Y2hlcwpmcmVxdWVuY3kgPC0gc3VtKHVubGlzdChtYXRjaGVzKSAhPSAtMSkKCiMgUHJpbnQgdGhlIGZyZXF1ZW5jeQpwcmludChmcmVxdWVuY3kpCmBgYAoKCiMjIFZlY3RvcgojIyMgQ3JlYXRlIGEgdmVjdG9yCmBgYHtyfQojIENyZWF0ZSBhIG51bWVyaWMgdmVjdG9yIG5hbWVkIGFnZXMKYWdlcyA8LSBjKDI1LCAzMCwgMjIsIDI4LCAzNSkKcHJpbnQoYWdlcykKYGBgCgojIyMgSW5kZXhpbmcKYGBge3J9CnByaW50KGFnZXNbMV0pCnByaW50KGFnZXNbMl0pCmBgYAoKCiMjIyBBcHBlbmQgRWxlbWVudHMKYGBge3J9CiMgQXBwZW5kIHRoZSBhZ2UgNDAgdG8gdGhlIGFnZXMgdmVjdG9yCmFnZXMgPC0gYyhhZ2VzLCA0MCkKcHJpbnQoYWdlcykKYGBgCgojIyMgU2xpY2UKYGBge3J9CnByaW50KGFnZXNbMTozXSkKcHJpbnQoYWdlc1syOjRdKQpwcmludChhZ2VzWzI6OF0pCmBgYAoKIyMjIEluc2VydCBFbGVtZW50IGF0IFBvc2l0aW9uCmBgYHtyfQojIEluc2VydCB0aGUgYWdlIDQ1IGF0IHRoZSB0aGlyZCBwb3NpdGlvbiBpbiB0aGUgYWdlcyB2ZWN0b3IKYWdlcyA8LSBjKGFnZXNbMToyXSwgNDUsIGFnZXNbMzpsZW5ndGgoYWdlcyldKQpwcmludChhZ2VzKQoKYGBgCgojIyMgUmVtb3ZlIEVsZW1lbnRzCmBgYHtyfQojIFJlbW92ZSB0aGUgc2Vjb25kIGVsZW1lbnQgZnJvbSB0aGUgYWdlcyB2ZWN0b3IKYWdlcyA8LSBhZ2VzWy0yXQpwcmludChhZ2VzKQpgYGAKCiMjIyBDb25kaXRpb25hbCBzZWxlY3QKYGBge3J9CgojIENyZWF0ZSBhIG5ldyB2ZWN0b3IgbmFtZWQgeW91bmdfYWdlcyBieSBzbGljaW5nIHRoZSBhZ2VzIHZlY3Rvcgp5b3VuZ19hZ2VzIDwtIGFnZXNbYWdlcyA8IDMwXQpwcmludCh5b3VuZ19hZ2VzKQpgYGAKCmBgYHtyfQoKIyBDcmVhdGUgYSBuZXcgdmVjdG9yIHdpdGggYWdlIGdyb3VwIDI1LTM1CmFnZV8yNV8zNSA8LSBhZ2VzW2FnZXMgPD0gMzVdCmFnZV8yNV8zNSA8LSBhZ2VfMjVfMzVbYWdlXzI1XzM1ID49IDI1XQpwcmludChhZ2VfMjVfMzUpCmBgYAoKIyMjIHNvcnQKYGBge3J9CnByaW50KHNvcnQoYWdlcykpCmBgYAoKCiMjIyBWZWN0b3IgbWFuaXB1bGF0aW9uCmBgYHtyfQojIENyZWF0ZSBhIG51bWVyaWMgdmVjdG9yIG5hbWVkIHNjb3JlcwpzY29yZXMgPC0gYyg4NSwgOTIsIDc4LCA4OSwgODAsIDk1KQpwcmludChzY29yZXMpCiMgQ3JlYXRlIGEgbmV3IHZlY3RvciBhZGp1c3RlZF9zY29yZXMgYnkgYWRkaW5nIDUgdG8gZWFjaCBzY29yZQphZGp1c3RlZF9zY29yZXMgPC0gc2NvcmVzICsgNQpwcmludChhZGp1c3RlZF9zY29yZXMpCmBgYAoKIyMjIFZlY3RvciBDb21wYXJpc29uCmBgYHtyfQojIENyZWF0ZSBhIGxvZ2ljYWwgdmVjdG9yIHBhc3MKcGFzcyA8LSBzY29yZXMgPj0gODAKcHJpbnQocGFzcykKYGBgCgojIyMgVmVjdG9yIGxlbmd0aApgYGB7cn0KIyBDYWxjdWxhdGUgYW5kIHByaW50IHRoZSBsZW5ndGggb2YgdGhlIGFnZXMgdmVjdG9yCmxlbmd0aF9hZ2VzIDwtIGxlbmd0aChhZ2VzKQpwcmludChsZW5ndGhfYWdlcykKYGBgCgojIyMgU2ltcGxlIHN0YXRpc3RpY3MKYGBge3J9CiMgQ2FsY3VsYXRlIGFuZCBwcmludCB0aGUgc3VtIG9mIHRoZSBlbGVtZW50cyBpbiB0aGUgYWdlcyB2ZWN0b3IKc3VtX2FnZXMgPC0gc3VtKHNjb3JlcykKbWVhbl9zY29yZXMgPC0gbWVhbihzY29yZXMpCm1lZGlhbl9zY29yZXMgPC0gbWVkaWFuKHNjb3JlcykKCiNzdW0KcHJpbnQoc3VtX2FnZXMpCgojIE1lYW4KcHJpbnQobWVhbl9zY29yZXMpCgojIE1lZGlhbgpwcmludChtZWRpYW5fc2NvcmVzKQoKIyBNaW4KcHJpbnQobWluKHNjb3JlcykpCgojIE1heApwcmludChtYXgoc2NvcmVzKSkKCiNjb3JyZWxhdGlvbgpwcmludChjb3Ioc2NvcmVzLCBhZ2VzKSkKCiMgc3RhbmRhcmQgZGV2aWF0aW9uCnByaW50KHNkKHNjb3JlcykpCgojIHZhcmlhbmNlCnByaW50KHZhcihzY29yZXMpKQoKIyBRdWFudGlsZXMgCnByaW50KHF1YW50aWxlKHNjb3JlcykpCmBgYAoKIyMjIFZlY3RvciBhcml0aG1hdGljcwpgYGB7cn0KIyBWZWN0b3IgQWRkaXRpb24gRXhhbXBsZQp2ZWMxIDwtIGMoMSwgMiwgMywgNCwgNSkKdmVjMiA8LSBjKDUsIDQsIDMsIDIsIDEpCgpyZXN1bHRfYWRkaXRpb24gPC0gdmVjMSArIHZlYzIKcHJpbnQoIlZlY3RvciBBZGRpdGlvbjoiKQpwcmludChyZXN1bHRfYWRkaXRpb24pCgpyZXN1bHRfc3VidHJhY3Rpb24gPC0gdmVjMSAtIHZlYzIKcHJpbnQoIlZlY3RvciBTdWJ0cmFjdGlvbjoiKQpwcmludChyZXN1bHRfc3VidHJhY3Rpb24pCmBgYAoKIyBMaXN0CmBgYHtyfQojIDEuIENyZWF0ZSBhIGxpc3QKbXlfbGlzdCA8LSBsaXN0KAogIG5hbWUgPSAiSm9obiIsCiAgYWdlID0gMjUsCiAgY2l0eSA9ICJOZXcgWW9yayIsCiAgaXNfc3R1ZGVudCA9IFRSVUUKKQoKIyBEaXNwbGF5IHRoZSBvcmlnaW5hbCBsaXN0CnByaW50KCJPcmlnaW5hbCBMaXN0OiIpCnByaW50KG15X2xpc3QpCgojIDIuIERlbGV0ZSBhbiBpdGVtCm15X2xpc3QkYWdlIDwtIE5VTEwKIyBEaXNwbGF5IHRoZSBtb2RpZmllZCBsaXN0CnByaW50KG15X2xpc3QpCgojIDMuIEFkZCBhbiBpdGVtCm15X2xpc3Qkb2NjdXBhdGlvbiA8LSAiRW5naW5lZXIiCgojIERpc3BsYXkgdGhlIGxpc3QgYWZ0ZXIgYWRkaW5nICdvY2N1cGF0aW9uJwpwcmludCgiTGlzdCBhZnRlciBhZGRpbmcgJ29jY3VwYXRpb24nOiIpCnByaW50KG15X2xpc3QpCgojIDQuIENoYW5nZSB0aGUgdmFsdWUgb2YgYW4gaXRlbQpteV9saXN0JG5hbWUgPC0gIkphbmUiCgojIERpc3BsYXkgdGhlIGxpc3QgYWZ0ZXIgY2hhbmdpbmcgJ25hbWUnCnByaW50KCJMaXN0IGFmdGVyIGNoYW5naW5nICduYW1lJzoiKQpwcmludChteV9saXN0KQoKIyA1LiBMZW5ndGggb2YgbGlzdApsaXN0X2xlbmd0aCA8LSBsZW5ndGgobXlfbGlzdCkKcHJpbnQocGFzdGUoIkxlbmd0aCBvZiB0aGUgbGlzdDoiLCBsaXN0X2xlbmd0aCkpCgojIDYuIE1lcmdlIDIgbGlzdHMKYW5vdGhlcl9saXN0IDwtIGxpc3QoY291bnRyeSA9ICJVU0EiLCBsYW5ndWFnZSA9ICJFbmdsaXNoIikKCm1lcmdlZF9saXN0IDwtIGMobXlfbGlzdCwgYW5vdGhlcl9saXN0KQoKIyBEaXNwbGF5IHRoZSBtZXJnZWQgbGlzdApwcmludCgiTWVyZ2VkIExpc3Q6IikKcHJpbnQobWVyZ2VkX2xpc3QpCgpgYGAKCgoKIyBEYXRhIEZyYW1lCmBgYHtyfQojIEdpdmVuIGRhdGEgZnJhbWUKZGF0YSA8LSBkYXRhLmZyYW1lKAogIElEID0gYygxLCAyLCAzLCA0LCA1KSwKICBOYW1lID0gYygiQWxpY2UiLCAiQm9iIiwgIkNoYXJsaWUiLCAiRGF2aWQiLCAiRXZhIiksCiAgQWdlID0gYygyNSwgMzAsIDIyLCAyOCwgMzUpLAogIFNjb3JlID0gYyg4NSwgOTIsIDc4LCA4OSwgODEpCikKCnByaW50KGRhdGEpCgpgYGAKCgpgYGB7cn0KIyBDcmVhdGUgYSBzY2F0dGVyIHBsb3Qgb2YgQWdlIHZzLiBTY29yZQpwbG90KGRhdGEkQWdlLCBkYXRhJFNjb3JlLCB4bGFiID0gIkFnZSIsIHlsYWIgPSAiU2NvcmUiLCBtYWluID0gIkFnZSB2cy4gU2NvcmUiKQoKIyBDcmVhdGUgYSBsaW5lIHBsb3Qgb2YgSUQgdnMuIFNjb3JlCnBsb3QoZGF0YSRJRCwgZGF0YSRTY29yZSwgdHlwZSA9ICJsIiwgeGxhYiA9ICJJRCIsIHlsYWIgPSAiU2NvcmUiLCBtYWluID0gIklEIHZzLiBTY29yZSIpCgojIENyZWF0ZSBhIGhpc3RvZ3JhbSBvZiBBZ2UgZGlzdHJpYnV0aW9uCmhpc3QoZGF0YSRBZ2UsIHhsYWIgPSAiQWdlIiwgeWxhYiA9ICJGcmVxdWVuY3kiLCBtYWluID0gIkFnZSBEaXN0cmlidXRpb24iKQoKIyBDcmVhdGUgYSBwaWUgY2hhcnQgb2YgQWdlIGRpc3RyaWJ1dGlvbgphZ2VfZnJlcSA8LSB0YWJsZShjdXQoZGF0YSRBZ2UsIGJyZWFrcyA9IGMoMjAsIDI1LCAzMCwgNDApKSkKYWdlX2ZyZXEKcGllKGFnZV9mcmVxLCBsYWJlbHMgPSBjKCIyMC0yNSIsICIyNi0zMCIsICIzMS00MCIpLCBtYWluID0gIkFnZSBEaXN0cmlidXRpb24iKQoKIyBDcmVhdGUgYSBib3hwbG90IG9mIFNjb3Jlcwpib3hwbG90KGRhdGEkU2NvcmUsIHhsYWIgPSAiU2NvcmVzIiwgbWFpbiA9ICJTY29yZSBEaXN0cmlidXRpb24iKQoKIyBDcmVhdGUgYSBiYXIgcGxvdCBvZiBTY29yZXMgYnkgTmFtZQpiYXJwbG90KGRhdGEkU2NvcmUsIG5hbWVzLmFyZyA9IGRhdGEkTmFtZSwgeGxhYiA9ICJOYW1lIiwgeWxhYiA9ICJTY29yZSIsIG1haW4gPSAiSW5kaXZpZHVhbCBTY29yZXMiKQoKIyBDcmVhdGUgYSBiYXIgcGxvdCBvZiBNZWFuIFNjb3JlcyBieSBOYW1lCm1lYW5fc2NvcmVzIDwtIHRhcHBseShkYXRhJFNjb3JlLCBkYXRhJE5hbWUsIG1lYW4pCmJhcnBsb3QobWVhbl9zY29yZXMsIHhsYWIgPSAiTmFtZSIsIHlsYWIgPSAiTWVhbiBTY29yZSIsIG1haW4gPSAiTWVhbiBTY29yZXMgYnkgTmFtZSIpCgpgYGAKCmBgYHtyfQpzZWxlY3RlZF9yb3dzIDwtIGRhdGFbMjo0LCBdCnByaW50KHNlbGVjdGVkX3Jvd3MpCgpzZWxlY3RlZF9yb3dzIDwtIGRhdGFbMiwgXQpwcmludChzZWxlY3RlZF9yb3dzKQoKCnNlbGVjdGVkX3Jvd3MgPC0gZGF0YVssMjozIF0KcHJpbnQoc2VsZWN0ZWRfcm93cykKCnNlbGVjdGVkX3Jvd3MgPC0gZGF0YVsyOjQsMjozIF0KcHJpbnQoc2VsZWN0ZWRfcm93cykKYGBgCgoKYGBge3J9CiMgU2VsZWN0IHJvd3Mgd2hlcmUgYWdlIGlzIGdyZWF0ZXIgdGhhbiAyNSBhbmQgc2NvcmUgaXMgbGVzcyB0aGFuIDkwCnNlbGVjdGVkX3Jvd3MgPC0gZGF0YVtkYXRhJEFnZSA+IDI1ICYgZGF0YSRTY29yZSA8IDkwLCBdCgojIFByaW50IHRoZSBzZWxlY3RlZCByb3dzCnByaW50KHNlbGVjdGVkX3Jvd3MpCmBgYAoKYGBge3J9CiMgU29ydCBkYXRhIGJ5IEFnZSBpbiBkZXNjZW5kaW5nIG9yZGVyCnNvcnRlZF9kYXRhIDwtIGRhdGFbb3JkZXIoZGF0YSRBZ2UsIGRlY3JlYXNpbmcgPSBUUlVFKSwgXQpwcmludCgiU29ydGVkIERhdGE6IikKcHJpbnQoc29ydGVkX2RhdGEpCmBgYAoKCmBgYHtyfQojIENoZWNrIGlmIGFueSB2YWx1ZSBpbiBBZ2UgY29sdW1uIGlzIGFib3ZlIDQwCmFueV9hYm92ZV80MCA8LSBhbnkoZGF0YSRBZ2UgPiA0MCkKcHJpbnQoIkFueSB2YWx1ZSBhYm92ZSA0MCBpbiBBZ2UgY29sdW1uPyIpCnByaW50KGFueV9hYm92ZV80MCkKYGBgCgpgYGB7cn0KIyBDYWxjdWxhdGUgdGhlIGF2ZXJhZ2UgYWdlCmF2ZXJhZ2VfYWdlIDwtIG1lYW4oZGF0YSRBZ2UpCnByaW50KCJBdmVyYWdlIEFnZToiKQpwcmludChhdmVyYWdlX2FnZSkKCiMgQ2FsY3VsYXRlIHRoZSBtYXhpbXVtIHNjb3JlCm1heF9zY29yZSA8LSBtYXgoZGF0YSRTY29yZSkKcHJpbnQoIk1heGltdW0gU2NvcmU6IikKcHJpbnQobWF4X3Njb3JlKQpgYGAKYGBge3J9CiMgU3Vic2V0IHJvd3Mgd2l0aCBzcGVjaWZpYyBJRHMKc3BlY2lmaWNfaWRzIDwtIGRhdGFbZGF0YSRJRF9udW1iZXIgJWluJSBjKDIsIDQpLCBdCnByaW50KCJSb3dzIHdpdGggU3BlY2lmaWMgSURzOiIpCnByaW50KHNwZWNpZmljX2lkcykKYGBgCmBgYHtyfQpwcmludChkYXRhKQptYWpvciA9IGMoJ01hdGgnLCAnQmlvbG9neScsICdDUycsICdQaHlzaWNzJywgJ0NoZW1pc3RyeScpCmRhdGEyID0gY2JpbmQoZGF0YSwgbWFqb3IpCnByaW50KGRhdGEyKQoKY29sbmFtZXMoZGF0YTIpWzVdID0gJ01ham9yJwpwcmludChkYXRhMikKYGBgCmBgYHtyfQp2ID0gYygpCmZvcihpIGluIDE6NSkgewogIHZbaV0gPSBpCn0KdgpgYGAKCiMgTG9vcAoKIyMgTG9vcCB0byBQcmludCBOdW1iZXJzCmBgYHtyfQojIFVzaW5nIGZvciBsb29wIHRvIHByaW50IG51bWJlcnMKZm9yIChpIGluIDE6NSkgewogIHByaW50KGkpCn0KCiMgVXNpbmcgd2hpbGUgbG9vcCB0byBwcmludCBudW1iZXJzCmkgPC0gMQp3aGlsZSAoaSA8PSA1KSB7CiAgcHJpbnQoaSkKICBpIDwtIGkgKyAxCn0KCmBgYAojIyBMb29wIHRvIEl0ZXJhdGUgYSBWZWN0b3IKYGBge3J9CiMgVmVjdG9yCm15X3ZlY3RvciA8LSBjKCJhcHBsZSIsICJiYW5hbmEiLCAib3JhbmdlIikKCiMgVXNpbmcgZm9yIGxvb3AgdG8gaXRlcmF0ZSB2ZWN0b3IKZm9yIChmcnVpdCBpbiBteV92ZWN0b3IpIHsKICBwcmludChmcnVpdCkKfQoKIyBVc2luZyB3aGlsZSBsb29wIHRvIGl0ZXJhdGUgdmVjdG9yCmkgPC0gMQp3aGlsZSAoaSA8PSBsZW5ndGgobXlfdmVjdG9yKSkgewogIHByaW50KG15X3ZlY3RvcltpXSkKICBpIDwtIGkgKyAxCn0KCmBgYAoKIyMgTG9vcCB0byBJdGVyYXRlIGEgTGlzdApgYGB7cn0KIyBMaXN0Cm15X2xpc3QgPC0gbGlzdChuYW1lID0gIkpvaG4iLCBhZ2UgPSAyNSwgY2l0eSA9ICJOZXcgWW9yayIpCgojIFVzaW5nIGZvciBsb29wIHRvIGl0ZXJhdGUgbGlzdApmb3IgKGl0ZW0gaW4gbXlfbGlzdCkgewogIHByaW50KGl0ZW0pCn0KCiMgVXNpbmcgd2hpbGUgbG9vcCB0byBpdGVyYXRlIGxpc3QKaSA8LSAxCndoaWxlIChpIDw9IGxlbmd0aChteV9saXN0KSkgewogIHByaW50KG15X2xpc3RbW2ldXSkKICBpIDwtIGkgKyAxCn0KCmBgYAoKIyMgTG9vcCB0byBJdGVyYXRlIGEgRGF0YSBGcmFtZQpgYGB7cn0KZGF0YSA8LSBkYXRhLmZyYW1lKAogIElEID0gYygxLCAyLCAzLCA0LCA1KSwKICBOYW1lID0gYygiQWxpY2UiLCAiQm9iIiwgIkNoYXJsaWUiLCAiRGF2aWQiLCAiRXZhIiksCiAgQWdlID0gYygyNSwgMzAsIDIyLCAyOCwgMzUpLAogIFNjb3JlID0gYyg4NSwgOTIsIDc4LCA4OSwgODEpCikKCiMgVXNpbmcgYSBmb3IgbG9vcCB0byBwcmludCBjb2x1bW4gbmFtZXMKZm9yIChjb2xfbmFtZSBpbiBuYW1lcyhkYXRhKSkgewogIHByaW50KGNvbF9uYW1lKQp9Cgpmb3IoaSBpbiBkYXRhJE5hbWUpIHsKICBwcmludChpKQp9Cgpmb3IoaSBpbiAxOm5jb2woZGF0YSkpIHsKICBwcmludChkYXRhJElEW2ldKQogIHByaW50KGkpCn0KCmBgYAoKCiMjIE5lc3RlZCBsb29wCmBgYHtyfQojIE5lc3RlZCBmb3IgbG9vcCBleGFtcGxlCmZvciAoaSBpbiAxOjQpIHsKICBmb3IgKGogaW4gMTozKSB7CiAgICBjYXQoImk6IiwgaSwgIiwgajoiLCBqLCAiXG4iKQogIH0KfQpgYGAKYGBge3J9CiMgRGVmaW5lIHRoZSBzaXplIG9mIHRoZSBtdWx0aXBsaWNhdGlvbiB0YWJsZQp0YWJsZV9zaXplIDwtIDMKCiMgTmVzdGVkIGZvciBsb29wIHRvIGdlbmVyYXRlIHRoZSBtdWx0aXBsaWNhdGlvbiB0YWJsZQpmb3IgKGkgaW4gMTp0YWJsZV9zaXplKSB7CiAgY2F0KCJNdWx0aXBsaWNhdGlvbiB0YWJsZSBmb3IiLCBpLCAiOlxuIikKICBmb3IgKGogaW4gMToxMCkgewogICAgcmVzdWx0IDwtIGkgKiBqCiAgICBjYXQoaSwgIngiLCBqLCAiPSIsIHJlc3VsdCwgIlxuIikKICB9CiAgY2F0KCJcbiIpCn0KCmBgYAoKCiMgQ29uZGl0aW9uYWwKYGBge3J9CnByaW50KDMwPjUwKQpwcmludCgzMDw1MCkKYGBgCgpgYGB7cn0KIyBEZWZpbmUgYSB2YXJpYWJsZQp0ZW1wZXJhdHVyZSA8LSAyNQoKIyBTaW1wbGUgaWYtZWxzZSBzdGF0ZW1lbnQKaWYgKHRlbXBlcmF0dXJlID4gMzApIHsKICBjYXQoIkl0J3MgYSBob3QgZGF5IVxuIikKfSBlbHNlIHsKICBjYXQoIkl0J3Mgbm90IHRvbyBob3QgdG9kYXkuXG4iKQp9CgpgYGAKCmBgYHtyfQpzY29yZXMgPSBjKDEwMCwgODAsIDc1LCA2MCwgNTUsIDIwLCA5OCkKCmZvcihpIGluIHNjb3JlcykgewogIGlmIChpID49IDgwKSB7CiAgICBjYXQoIlNjb3JlIiwgaSAsICJpcyBBKyBcbiIpCiAgfQogIGVsc2UgaWYgKGkgPj0gNzApIHsKICAgICBjYXQoIlNjb3JlIiwgaSAsICJpcyBBIFxuIikKICB9CiAgZWxzZSBpZiAoaSA+PSA2MCkgewogICAgY2F0KCJTY29yZSIsIGkgLCAiaXMgQiBcbiIpCiAgfQogIGVsc2UgewogICAgY2F0KCJTY29yZSIsIGkgLCAiaXMgZmFpbFxuIikKICB9Cn0KYGBgCgoKYGBge3J9CkROQV92ZWN0b3IgPSBjKCdBR1RDJywgJ0FHVENDQScsICdBR1RHQUMnLCAnVEdBQycsICdHQVRDJykKcGF0dGVybiA8LSAiVEMiCgpmb3IoRE5BIGluIEROQV92ZWN0b3IpIHsKICBtYXRjaGVzIDwtIGdyZXBsKHBhdHRlcm4sIEROQSkKICBpZihtYXRjaGVzKSB7CiAgICBjYXQoRE5BLCAnXG4nKQogIH0KfQoKYGBgCgoKIyBEYXRhIFNjaWVuY2UKCiMjIFBsb3QgYmFzaWNzIChnZ3Bsb3QpCmBgYHtyfQojIExvYWQgbmVjZXNzYXJ5IGxpYnJhcmllcwpsaWJyYXJ5KGdncGxvdDIpCgojIENyZWF0ZSBhIHNhbXBsZSBkYXRhc2V0CmRhdGEgPC0gZGF0YS5mcmFtZSgKICB3b3JrX3llYXIgPSBjKDEsIDIsIDMsIDEsIDIsIDMsIDEsIDIsIDMpLAogIHNhbGFyeSA9IGMoNTAwMDAsIDYwMDAwLCA1NTAwMCwgNDUwMDAsIDU1MDAwLCA1ODAwMCwgNDgwMDAsIDU5MDAwLCA2MDAwMCkKKQoKIyBDcmVhdGUgYSB2aW9saW4gcGxvdApnZ3Bsb3QoZGF0YSwgYWVzKHggPSBmYWN0b3Iod29ya195ZWFyKSwgeSA9IHNhbGFyeSkpICsKICBnZW9tX3Zpb2xpbihmaWxsID0gImxpZ2h0Ymx1ZSIsIGNvbG9yID0gImJsYWNrIikgKwogIGxhYnModGl0bGUgPSAiVmlvbGluIFBsb3Qgb2YgU2FsYXJ5IGJ5IFdvcmsgWWVhciIsCiAgICAgICB4ID0gIldvcmsgWWVhciIsCiAgICAgICB5ID0gIlNhbGFyeSIpCgpgYGAKCgpgYGB7cn0KbGlicmFyeShkYXRhc2V0cykKZGF0YShpcmlzKQpoZWFkKGlyaXMpCmBgYAoKCmBgYHtyfQppcmlzID0gcmVhZC5jc3YoJ2RhdGFzZXRzL2lyaXMuY3N2JykKaXJpcwpgYGAKCgpgYGB7cn0KaXJpc19kYXRhc2V0ID0gaXJpcwpgYGAKCmBgYHtyfQojIENvbnZlcnQgc3BlY2llcyBsYWJlbHMgdG8gbnVtZXJpYyB2YWx1ZXMKc3BlY2llc19udW1lcmljIDwtIGFzLm51bWVyaWMoZmFjdG9yKGlyaXMkdmFyaWV0eSkpCnNwZWNpZXNfbnVtZXJpYwpgYGAKCgpgYGB7cn0KIyBDcmVhdGUgYSBzY2F0dGVyIHBsb3QgdXNpbmcgdGhlIHBsb3QgZnVuY3Rpb24KcGxvdChpcmlzJHNlcGFsLmxlbmd0aCwgaXJpcyRzZXBhbC53aWR0aCwgCiAgICAgY29sID0gc3BlY2llc19udW1lcmljLCAgICAgICMgU2V0IHNjYXR0ZXIgaWNvbiBjb2xvcnMgYmFzZWQgb24gc3BlY2llcwogICAgIHBjaCA9IDEsICAgICAgICAgICAgICAgICMgU2V0IHNjYXR0ZXIgcGxvdCBzeW1ib2wKICAgICBjZXggPSAxLCAgICAgICAgICAgICAgICMgU2V0IHNjYXR0ZXIgcGxvdCBzaXplCiAgICAgeGxpbSA9IGMoNCwgOCksICAgICAgICAgICMgU2V0IHgtYXhpcyBsaW1pdHMKICAgICB5bGltID0gYygxLCA1KSwgICAgICAgICAgIyBTZXQgeS1heGlzIGxpbWl0cwogICAgIHhsYWIgPSAiU2VwYWwgTGVuZ3RoIiwgICAjIFNldCB4LWF4aXMgbGFiZWwKICAgICB5bGFiID0gIlNlcGFsIFdpZHRoIiwgICAgIyBTZXQgeS1heGlzIGxhYmVsCiAgICAgbWFpbiA9ICJTY2F0dGVyIFBsb3Qgb2YgU2VwYWwgTGVuZ3RoIHZzIFNlcGFsIFdpZHRoIiwgICMgU2V0IG1haW4gdGl0bGUKICAgICBjb2wubWFpbiA9ICJibHVlIiwgICAgICAgIyBTZXQgbWFpbiB0aXRsZSBjb2xvcgogICAgIGNvbC5heGlzID0gImdyZWVuIiwgICAgICAjIFNldCBheGlzIHRleHQgY29sb3IKICAgICBjZXgubWFpbiA9IDEuMiwgICAgICAgICAgIyBTZXQgbWFpbiB0aXRsZSBzaXplCiAgICAgY2V4LmxhYiA9IDEuMiwKICAgICBjZXguYXhpcyA9IDIpICAgICAgICAgICAjIFNldCBheGlzIGxhYmVsIHNpemUpICAgICAgCmBgYAoKIyMgSGlzdHJvZ3JhbSAtIERpc3RyaWJ1dGlvbgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQojIGluc3RhbGwgaW5zdGFsbC5wYWNrYWdlcygiY29sb3JzcGFjZSIpIGlmIGVycm9yIG9jY3VycyAtPiBjb3VsZCBub3QgZmluZCBmdW5jdGlvbiAiZ2dwbG90IgoKZ2dwbG90KGlyaXMsIGFlcyh4ID0gc2VwYWwubGVuZ3RoKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMC4xLCBmaWxsID0gImxpZ2h0Ymx1ZSIsIGNvbG9yID0gImJsYWNrIikgKwogIGxhYnModGl0bGUgPSAiSGlzdG9ncmFtIG9mIFNlcGFsIExlbmd0aCIsCiAgICAgICB4ID0gIlNlcGFsIExlbmd0aCIsCiAgICAgICB5ID0gIkZyZXF1ZW5jeSIpCmBgYAoKCiMjIFNjYXR0ZXIgcGxvdAoKYGBge3J9CmdncGxvdChpcmlzLCBhZXMoeCA9IFNlcGFsLkxlbmd0aCwgeSA9IFNlcGFsLldpZHRoLCBjb2xvciA9IFNwZWNpZXMpKSArCiAgZ2VvbV9wb2ludCgpICsKICBsYWJzKHRpdGxlID0gIlNjYXR0ZXIgUGxvdCBvZiBTZXBhbCBMZW5ndGggdnMuIFNlcGFsIFdpZHRoIiwKICAgICAgIHggPSAiU2VwYWwgTGVuZ3RoIiwKICAgICAgIHkgPSAiU2VwYWwgV2lkdGgiKQoKYGBgCgojIyBzZXQgY29sb3JzCmBgYHtyfQojIExvYWQgdGhlIGdncGxvdDIgbGlicmFyeQpsaWJyYXJ5KGdncGxvdDIpCgojIFBsb3R0aW5nIHRoZSBzY2F0dGVyIHBsb3QKZ2dwbG90KGlyaXMsIGFlcyh4ID0gc2VwYWwubGVuZ3RoLCB5ID0gc2VwYWwud2lkdGgsIGNvbG9yID0gdmFyaWV0eSkpICsKICBnZW9tX3BvaW50KCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJTZXRvc2EiID0gInJlZCIsICJWZXJzaWNvbG9yIiA9ICJwdXJwbGUiLCAiVmlyZ2luaWNhIiA9ICJibHVlIikpICsKICBsYWJzKHRpdGxlID0gIlNjYXR0ZXIgUGxvdCBvZiBTZXBhbCBMZW5ndGggdnMgU2VwYWwgV2lkdGgiLAogICAgICAgeCA9ICJTZXBhbCBMZW5ndGgiLAogICAgICAgeSA9ICJTZXBhbCBXaWR0aCIpCgpgYGAKCgpgYGB7cn0KIyBMb2FkIHRoZSBnZ3Bsb3QyIGxpYnJhcnkKbGlicmFyeShnZ3Bsb3QyKQoKIyBQbG90dGluZyB0aGUgc2NhdHRlciBwbG90IHdpdGggdmFyaW91cyBjdXN0b21pemF0aW9ucwoKc2NhdHRlcl9wbG90ID0gZ2dwbG90KGlyaXMsIGFlcyh4ID0gc2VwYWwubGVuZ3RoLCB5ID0gc2VwYWwud2lkdGgsIGNvbG9yID0gdmFyaWV0eSkpICsKICBnZW9tX3BvaW50KHNpemUgPSA0KSArICAjIFNldCBzY2F0dGVyIHBvaW50IHNpemUKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiU2V0b3NhIiA9ICJyZWQiLCAiVmVyc2ljb2xvciIgPSAicHVycGxlIiwgIlZpcmdpbmljYSIgPSAiYmx1ZSIpKSArICAjIFNldCBjbGFzcyBjb2xvcgogIGxhYnModGl0bGUgPSAiU2NhdHRlciBQbG90IG9mIFNlcGFsIExlbmd0aCB2cyBTZXBhbCBXaWR0aCIsCiAgICAgICB4ID0gIlNlcGFsIExlbmd0aCIsCiAgICAgICB5ID0gIlNlcGFsIFdpZHRoIiwKICAgICAgIGNhcHRpb24gPSAiU291cmNlOiBJcmlzIERhdGFzZXQiKSArICAjIEFkZCBhIGNhcHRpb24KICAjdGhlbWVfbWluaW1hbCgpICsgICMgVXNlIGEgbWluaW1hbCB0aGVtZSAtPiBiYWNrZ3JvdW5kIHdoaXRlCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwgICMgTW92ZSBsZWdlbmQgdG8gdGhlIGJvdHRvbQogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBjb2xvciA9ICJibGFjayIpLCAgIyBTZXQgbGFiZWwgdGV4dCBzaXplIGFuZCBjb2xvcgogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsIGNvbG9yID0gImJsYWNrIiksICAjIFNldCBheGlzIHRleHQgc2l6ZSBhbmQgY29sb3IKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsIGNvbG9yID0gImdyZWVuIiksICAjIFNldCB4LWF4aXMgdGV4dCBzaXplIGFuZCBjb2xvcgogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwgY29sb3IgPSAiYmx1ZSIpLCAgICMgU2V0IHktYXhpcyB0ZXh0IHNpemUgYW5kIGNvbG9yCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGNvbG9yID0gImJsYWNrIiksICAjIFNldCBheGlzIHRpdGxlIHNpemUgYW5kIGNvbG9yCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGNvbG9yID0gImJsYWNrIiksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImxpZ2h0Z3JheSIpLCAgIyBTZXQgYmFja2dyb3VuZCBjb2xvcgogICAgICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCkgIyBSZW1vdmUgZ3JpZCBsaW5lcwogICAgICAgICkgKyAgIyBTZXQgcGxvdCB0aXRsZSBzaXplIGFuZCBjb2xvcgogIHhsaW0oNCwgOCkgKyAgIyBTZXQgeC1heGlzIGxpbWl0cwogIHlsaW0oMSwgNSkgKyAgICAjIFNldCB5LWF4aXMgbGltaXRzCiAgY29vcmRfZml4ZWQoKSAjIFNxdWFyZSBncmFwaAoKIyBTYXZlIHRoZSBwbG90IHdpdGggMzAwIGRwaQpnZ3NhdmUoInNjYXR0ZXJfcGxvdC5wbmciLCBwbG90ID0gc2NhdHRlcl9wbG90LCBkcGkgPSA3MDApCgpzY2F0dGVyX3Bsb3QKYGBgCgoKIyMgUGFpciBwbG90CmBgYHtyfQpwYWlycyhpcmlzWywgMTo0XSwgY29sID0gaXJpcyRTcGVjaWVzKQpgYGAKCiMjIEJveCBwbG90CmBgYHtyfQpnZ3Bsb3QoaXJpcywgYWVzKHggPSBTcGVjaWVzLCB5ID0gU2VwYWwuTGVuZ3RoLCBmaWxsID0gU3BlY2llcykpICsKICBnZW9tX2JveHBsb3QoKSArCiAgbGFicyh0aXRsZSA9ICJCb3ggUGxvdCBvZiBTZXBhbCBMZW5ndGggYnkgU3BlY2llcyIsCiAgICAgICB4ID0gIlNwZWNpZXMiLAogICAgICAgeSA9ICJTZXBhbCBMZW5ndGgiKQpgYGAKIyMgVmlvbGluZSBwbG90CmBgYHtyfQpnZ3Bsb3QoaXJpcywgYWVzKHggPSBTcGVjaWVzLCB5ID0gUGV0YWwuTGVuZ3RoLCBmaWxsID0gU3BlY2llcykpICsKICBnZW9tX3Zpb2xpbigpICsKICBsYWJzKHRpdGxlID0gIlZpb2xpbiBQbG90IG9mIFBldGFsIExlbmd0aCBieSBTcGVjaWVzIiwKICAgICAgIHggPSAiU3BlY2llcyIsCiAgICAgICB5ID0gIlBldGFsIExlbmd0aCIpCgpgYGAKCgojIyBDb3JyZWxhdGlvbiBNYXRyaXgKYGBge3J9CmNvcl9tYXRyaXggPC0gY29yKGlyaXNbLCAxOjRdKQpwcmludChjb3JfbWF0cml4KQpgYGAKIyMgSGVhdCBtYXAKCmBgYHtyfQpjb3JfbWF0cml4IDwtIGNvcihpcmlzWywgMTo0XSkKcHJpbnQoY29yX21hdHJpeCkKCmxpYnJhcnkocmVzaGFwZTIpCm1lbHRlZF9jb3JtYXQgPC0gbWVsdChjb3JfbWF0cml4KQpwcmludChtZWx0ZWRfY29ybWF0KQoKCmxpYnJhcnkoZ2dwbG90MikKZ2dwbG90KGRhdGEgPSBtZWx0ZWRfY29ybWF0LCBhZXMoeD1WYXIxLCB5PVZhcjIsIGZpbGw9dmFsdWUpKSArCiAgZ2VvbV90aWxlKCkgI2hlYXQgbWFwCgpgYGAKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IG1lbHRlZF9jb3JtYXQsIGFlcyh4PVZhcjEsIHk9VmFyMiwgZmlsbD12YWx1ZSkpICsKICBnZW9tX3RpbGUoKSsgI2hlYXQgbWFwCiAgZ2VvbV90ZXh0KGFlcyhWYXIyLCBWYXIxLCBsYWJlbCA9IHJvdW5kKHZhbHVlLCBkaWdpdHMgPSAyKSksIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDQpICsKCiAgIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKGxvdyA9ICJibHVlIiwgaGlnaCA9ICJyZWQiLCBtaWQgPSAid2hpdGUiLCAKICAgbWlkcG9pbnQgPSAwLCBsaW1pdCA9IGMoLTEsMSksIAogICBuYW1lPSJDb3JyZWxhdGlvbiIpCmBgYAoKCmBgYHtyfQoKY29ybWF0ID0gY29yX21hdHJpeAoKIyBHZXQgdXBwZXIgdHJpYW5nbGUgb2YgdGhlIGNvcnJlbGF0aW9uIG1hdHJpeApjb3JtYXRbbG93ZXIudHJpKGNvcm1hdCldPC0gTkEKCnVwcGVyX3RyaSA9IGNvcm1hdAoKIyBNZWx0IHRoZSBjb3JyZWxhdGlvbiBtYXRyaXgKbGlicmFyeShyZXNoYXBlMikKbWVsdGVkX2Nvcm1hdCA8LSBtZWx0KHVwcGVyX3RyaSwgbmEucm0gPSBUUlVFKQptZWx0ZWRfY29ybWF0CgoKIyBIZWF0bWFwCmxpYnJhcnkoZ2dwbG90MikKZ2dwbG90KGRhdGEgPSBtZWx0ZWRfY29ybWF0LCBhZXMoVmFyMiwgVmFyMSwgZmlsbCA9IHZhbHVlKSkrCgogIGdlb21fdGlsZSgpKyAjaGVhdCBtYXAKICAKICBnZW9tX3RleHQoYWVzKFZhcjIsIFZhcjEsIGxhYmVsID0gcm91bmQodmFsdWUsIGRpZ2l0cyA9IDIpKSwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gNCkgKwoKICAgc2NhbGVfZmlsbF9ncmFkaWVudDIobG93ID0gImJsdWUiLCBoaWdoID0gInJlZCIsIG1pZCA9ICJ3aGl0ZSIsIAogICBtaWRwb2ludCA9IDAsIGxpbWl0ID0gYygtMSwxKSwgCiAgIG5hbWU9IkNvcnJlbGF0aW9uIikgKwogIAogIHRoZW1lX21pbmltYWwoKSsgCiAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCB2anVzdCA9IDEsIHNpemUgPSAxMiwgaGp1c3QgPSAxKSkrCiAKICBjb29yZF9maXhlZCgpICMgc3F1YXJlIGZpZ3VyZSBzaGFwZQoKIyB0dXRvcmlhbDogaHR0cDovL3d3dy5zdGhkYS5jb20vZW5nbGlzaC93aWtpL2dncGxvdDItcXVpY2stY29ycmVsYXRpb24tbWF0cml4LWhlYXRtYXAtci1zb2Z0d2FyZS1hbmQtZGF0YS12aXN1YWxpemF0aW9uCmBgYApgYGB7cn0KbGlicmFyeShnZ2NvcnJwbG90KQoKY29yX21hdHJpeCA8LSBjb3IoaXJpc1ssIDE6NF0pCnByaW50KGNvcl9tYXRyaXgpCgoKZ2djb3JycGxvdChjb3JfbWF0cml4LCB0eXBlID0gImxvd2VyIikKCiMgcmVmOiBodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvZ2djb3JycGxvdC9yZWFkbWUvUkVBRE1FLmh0bWwKYGBgCgpgYGB7cn0KCmdnY29ycnBsb3QoY29yX21hdHJpeCwgdHlwZSA9ICJ1cHBlciIpCmBgYAoKYGBge3J9CmdnY29ycnBsb3QoY29yX21hdHJpeCwgCiAgICAgICAgICAgdHlwZSA9ICJ1cHBlciIsCiAgICAgICAgICAgY29sb3JzID0gYygiIzZEOUVDMSIsICJ3aGl0ZSIsICIjRTQ2NzI2IikpCmBgYAoKYGBge3J9CmdnY29ycnBsb3QoY29yX21hdHJpeCwgCiAgICAgICAgICAgdHlwZSA9ICJ1cHBlciIsCiAgICAgICAgICAgY29sb3JzID0gYygiIzZEOUVDMSIsICJ3aGl0ZSIsICIjRTQ2NzI2IiksCiAgICAgICAgICAgbGFiID0gVFJVRSkKYGBgCgoKYGBge3J9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShHR2FsbHkpCmdncGFpcnMoaXJpcywgYWVzKGNvbG91ciA9IFNwZWNpZXMpKQoKIyBodHRwczovL2dnb2JpLmdpdGh1Yi5pby9nZ2FsbHkvcmVmZXJlbmNlL2dncGFpcnMuaHRtbApgYGAKCgojIExpbmVhciBSZWdyZXNzaW9uCgpgYGB7cn0KbG1fbW9kZWwgPC0gbG0oU2VwYWwuTGVuZ3RoIH4gUGV0YWwuTGVuZ3RoLCBkYXRhID0gaXJpcykKc3VtbWFyeShsbV9tb2RlbCkKCiMgaHR0cHM6Ly9mZWxpcGVyZWdvLmdpdGh1Yi5pby9ibG9nLzIwMTUvMTAvMjMvSW50ZXJwcmV0aW5nLU1vZGVsLU91dHB1dC1Jbi1SCmBgYApgYGB7cn0KI2RlZmluZSBkYXRhCnggPC0gaXJpcyRQZXRhbC5MZW5ndGgKeSA8LSBpcmlzJFNlcGFsLkxlbmd0aAogCiNwbG90IHggdnMuIHkKcGxvdCh4LCB5LCBwY2g9MTYsIGNleD0wLjUsIGNvbD1pcmlzJFNwZWNpZXMpIAogCiNmaXQgcG9seW5vbWlhbCByZWdyZXNzaW9uIG1vZGVsCmZpdCA8LSBsbSh5IH4geCkKIAojdXNlIG1vZGVsIHRvIGdldCBwcmVkaWN0ZWQgdmFsdWVzCnByZWQgPC0gcHJlZGljdChmaXQpCml4IDwtIHNvcnQoeCwgaW5kZXgucmV0dXJuPVQpJGl4ICMgc29ydCBhbmQgcmV0dXJuIHRoZSBpbmRleAppeAoKCmNvbmZfaW50ZXJ2YWwgPC0gcHJlZGljdChmaXQsIG5ld2RhdGE9ZGF0YS5mcmFtZSh4PXgpLCBpbnRlcnZhbD0iY29uZmlkZW5jZSIsbGV2ZWwgPSAwLjk1KQoKI2FkZCBwb2x5bm9taWFsIGN1cnZlIHRvIHBsb3QKbGluZXMoeFtpeF0sIHByZWRbaXhdLCBjb2w9J3JlZCcsIGx3ZD0yKQpsaW5lcyh4W2l4XSwgY29uZl9pbnRlcnZhbFtpeCwyXSwgY29sPSJibHVlIiwgbHR5PTIpCmxpbmVzKHhbaXhdLCBjb25mX2ludGVydmFsW2l4LDNdLCBjb2w9ImJsdWUiLCBsdHk9MikKYGBgCgpgYGB7cn0KZ2dwbG90KGlyaXMsIGFlcyh4ID0gUGV0YWwuTGVuZ3RoLCB5ID0gU2VwYWwuTGVuZ3RoKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBUUlVFLCBjb2xvciA9ICJibHVlIikgKwogIGxhYnModGl0bGUgPSAiTGluZWFyIFJlZ3Jlc3Npb246IFNlcGFsIExlbmd0aCB2cy4gUGV0YWwgTGVuZ3RoIiwKICAgICAgIHggPSAiUGV0YWwgTGVuZ3RoIiwKICAgICAgIHkgPSAiU2VwYWwgTGVuZ3RoIikKCmBgYAoKCgpgYGB7cn0KeD1jKDEsMiwzLDQsNSw2LDcsOCw5LDApCgp5PWMoMTMsMjgsNDMsMzUsOTYsODQsMTAxLDExMCwxMDgsMTMpCgpsbS5vdXQgPC0gbG0oeSB+IHgpCm5ld3ggPSBzZXEobWluKHgpLG1heCh4KSxieSA9IDAuMDUpCmNvbmZfaW50ZXJ2YWwgPC0gcHJlZGljdChsbS5vdXQsIG5ld2RhdGE9ZGF0YS5mcmFtZSh4PW5ld3gpLCBpbnRlcnZhbD0iY29uZmlkZW5jZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbCA9IDAuOTUpCmNvbmZfaW50ZXJ2YWwKcGxvdCh4LCB5LCB4bGFiPSJ4IiwgeWxhYj0ieSIsIG1haW49IlJlZ3Jlc3Npb24iKQphYmxpbmUobG0ub3V0LCBjb2w9ImxpZ2h0Ymx1ZSIpCmxpbmVzKG5ld3gsIGNvbmZfaW50ZXJ2YWxbLDJdLCBjb2w9ImJsdWUiLCBsdHk9MikKbGluZXMobmV3eCwgY29uZl9pbnRlcnZhbFssM10sIGNvbD0iYmx1ZSIsIGx0eT0yKQpgYGAKCgojIFBvbHlub21pYWwgUmVncmVzc2lvbgoKYGBge3J9CmdncGxvdChpcmlzLCBhZXMoeCA9IFBldGFsLkxlbmd0aCwgeSA9IFNlcGFsLkxlbmd0aCwgY29sb3I9U3BlY2llcykpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGZvcm11bGE9eX5wb2x5KHgsIDIpLCBsZXZlbD0wLjk1LCBzZSA9IFRSVUUsIGNvbG9yID0gImJsdWUiLCBmaWxsPSdsaWdodGJsdWUnKSArCiAgbGFicyh0aXRsZSA9ICJQb2x5bm9taWFsIFJlZ3Jlc3Npb246IFNlcGFsIExlbmd0aCB2cy4gUGV0YWwgTGVuZ3RoIiwKICAgICAgIHggPSAiUGV0YWwgTGVuZ3RoIiwKICAgICAgIHkgPSAiU2VwYWwgTGVuZ3RoIikKCmBgYAoKYGBge3J9CiNkZWZpbmUgZGF0YQp4IDwtIGlyaXMkUGV0YWwuTGVuZ3RoCnkgPC0gaXJpcyRTZXBhbC5MZW5ndGgKIAojcGxvdCB4IHZzLiB5CnBsb3QoeCwgeSwgcGNoPTE2LCBjZXg9MS41KSAKIAojZml0IHBvbHlub21pYWwgcmVncmVzc2lvbiBtb2RlbApmaXQgPC0gbG0oeSB+IHggKyBJKHheMikgKyBJKHheMykpCnN1bW1hcnkoZml0KSAKI3VzZSBtb2RlbCB0byBnZXQgcHJlZGljdGVkIHZhbHVlcwppeCA8LSBzb3J0KHgsIGluZGV4LnJldHVybj1UKSRpeAoKY29uZl9pbnRlcnZhbCA8LSBwcmVkaWN0KGZpdCwgbmV3ZGF0YT1kYXRhLmZyYW1lKHg9eCksIGludGVydmFsPSJjb25maWRlbmNlIixsZXZlbCA9IDAuOTUpCiNjb25mX2ludGVydmFsCgojYWRkIHBvbHlub21pYWwgY3VydmUgdG8gcGxvdAojbGluZXMoeFtpeF0sIHByZWRbaXhdLCBjb2w9J3JlZCcsIGx3ZD0yKQpsaW5lcyh4W2l4XSwgY29uZl9pbnRlcnZhbFtpeCwxXSwgY29sPSJibHVlIikKbGluZXMoeFtpeF0sIGNvbmZfaW50ZXJ2YWxbaXgsMl0sIGNvbD0iYmx1ZSIsIGx0eT0yKQpsaW5lcyh4W2l4XSwgY29uZl9pbnRlcnZhbFtpeCwzXSwgY29sPSJibHVlIiwgbHR5PTIpCmBgYAoKCmBgYHtyfQojIExvYWQgbmVjZXNzYXJ5IGxpYnJhcmllcwpsaWJyYXJ5KHN0YXRzKQoKIyBMb2FkIHRoZSBpcmlzIGRhdGFzZXQgKGl0J3MgYnVpbHQtaW4pCmRhdGEoaXJpcykKCiMgUGVyZm9ybSBwb2x5bm9taWFsIHJlZ3Jlc3Npb24gKHF1YWRyYXRpYyBtb2RlbCkKcG9seV9tb2RlbCA8LSBsbShTZXBhbC5MZW5ndGggfiBwb2x5KFNlcGFsLldpZHRoLCAyKSArIHBvbHkoUGV0YWwuTGVuZ3RoLCAyKSArIHBvbHkoUGV0YWwuV2lkdGgsIDIpLCBkYXRhID0gaXJpcykKCiMgUHJpbnQgc3VtbWFyeSBvZiBwb2x5bm9taWFsIHJlZ3Jlc3Npb24Kc3VtbWFyeShwb2x5X21vZGVsKQoKYGBgCgoKCiMgQ2x1c3RlcmluZwpgYGB7cn0Kc2V0LnNlZWQoMTIzKQprIDwtIDMKa21lYW5zX3Jlc3VsdCA8LSBrbWVhbnMoaXJpc1ssIDE6NF0sIGNlbnRlcnMgPSBrKQpwcmludChrbWVhbnNfcmVzdWx0KQoKYGBgCgpgYGB7cn0KZ2dwbG90KGlyaXMsIGFlcyh4ID0gUGV0YWwuTGVuZ3RoLCB5ID0gU2VwYWwuTGVuZ3RoLCBjb2xvciA9IGZhY3RvcihrbWVhbnNfcmVzdWx0JGNsdXN0ZXIpKSkgKwogIGdlb21fcG9pbnQoKSArCiAgbGFicyh0aXRsZSA9ICJLLU1lYW5zIENsdXN0ZXJpbmc6IFNlcGFsIExlbmd0aCB2cy4gUGV0YWwgTGVuZ3RoIiwKICAgICAgIHggPSAiUGV0YWwgTGVuZ3RoIiwKICAgICAgIHkgPSAiU2VwYWwgTGVuZ3RoIikKCmBgYAoKCmBgYHtyfQojIExvYWQgbmVjZXNzYXJ5IGxpYnJhcmllcwpsaWJyYXJ5KHN0YXRzKQpsaWJyYXJ5KGdncGxvdDIpICAjIEZvciBkYXRhIHZpc3VhbGl6YXRpb24KCiMgTG9hZCB0aGUgaXJpcyBkYXRhc2V0IChpdCdzIGJ1aWx0LWluKQpkYXRhKGlyaXMpCgojIFNlbGVjdCBvbmx5IHRoZSBudW1lcmljIGNvbHVtbnMgZm9yIGNsdXN0ZXJpbmcKZGF0YV9mb3JfY2x1c3RlcmluZyA8LSBpcmlzWywgYygiU2VwYWwuTGVuZ3RoIiwgIlNlcGFsLldpZHRoIiwgIlBldGFsLkxlbmd0aCIsICJQZXRhbC5XaWR0aCIpXQoKIyBQZXJmb3JtIEstTWVhbnMgY2x1c3RlcmluZyB3aXRoIDMgY2x1c3RlcnMKayA8LSAzICAjIE51bWJlciBvZiBjbHVzdGVycwprbWVhbnNfcmVzdWx0IDwtIGttZWFucyhkYXRhX2Zvcl9jbHVzdGVyaW5nLCBjZW50ZXJzID0gaykKCgpgYGAKCgpgYGB7cn0KbGlicmFyeShjbHVzdGVyKQpjbHVzcGxvdChpcmlzLCBrbWVhbnNfcmVzdWx0JGNsdXN0ZXIsIGNvbG9yPVQsIHNoYWRlPVQsIGxhYmVscz0wLCBsaW5lcz0wKQpgYGAKCgojIyBDbGFzc2lmaWNhdGlvbgoKIyMjIExBU1NPCmBgYHtyfQojIExvYWQgbmVjZXNzYXJ5IGxpYnJhcmllcwpsaWJyYXJ5KGdsbW5ldCkKCiMgTG9hZCB0aGUgaXJpcyBkYXRhc2V0IChpdCdzIGJ1aWx0LWluKQpkYXRhKGlyaXMpCgojIFByZXBhcmUgZGF0YSBtYXRyaXggYW5kIHJlc3BvbnNlIHZlY3RvcgpYIDwtIG1vZGVsLm1hdHJpeChTZXBhbC5MZW5ndGggfiBTZXBhbC5XaWR0aCArIFBldGFsLkxlbmd0aCArIFBldGFsLldpZHRoLCBkYXRhID0gaXJpcykKeSA8LSBpcmlzJFNlcGFsLkxlbmd0aAoKIyBQZXJmb3JtIGxhc3NvIHJlZ3Jlc3Npb24gd2l0aCBjcm9zcy12YWxpZGF0aW9uIHVzaW5nIGdsbW5ldApsYXNzb19tb2RlbCA8LSBjdi5nbG1uZXQoWCwgeSwgYWxwaGEgPSAxKQoKIyBQcmludCBzdW1tYXJ5IG9mIGxhc3NvIHJlZ3Jlc3Npb24KcHJpbnQobGFzc29fbW9kZWwpCgpgYGAKCiMjIyBTVk0KYGBge3J9CiMgTG9hZCBuZWNlc3NhcnkgbGlicmFyaWVzCmxpYnJhcnkoZTEwNzEpICAjIEZvciBTVk0KbGlicmFyeShjYXJldCkgICAjIEZvciBtb2RlbCBldmFsdWF0aW9uCmxpYnJhcnkoZ2dwbG90MikgCmxpYnJhcnkobGF0dGljZSkKCiMgTG9hZCB0aGUgaXJpcyBkYXRhc2V0IChpdCdzIGJ1aWx0LWluKQpkYXRhKGlyaXMpCgojIFNwbGl0IHRoZSBkYXRhIGludG8gdHJhaW5pbmcgYW5kIHRlc3Rpbmcgc2V0cwpzZXQuc2VlZCgxMjMpCnRyYWluX2luZGljZXMgPC0gY3JlYXRlRGF0YVBhcnRpdGlvbihpcmlzJFNwZWNpZXMsIHAgPSAwLjgsIGxpc3QgPSBGQUxTRSkKdHJhaW5fZGF0YSA8LSBpcmlzW3RyYWluX2luZGljZXMsIF0KdGVzdF9kYXRhIDwtIGlyaXNbLXRyYWluX2luZGljZXMsIF0KCiMgVHJhaW4gYW4gU1ZNIGNsYXNzaWZpZXIgd2l0aCBhIGxpbmVhciBrZXJuZWwKc3ZtX21vZGVsIDwtIHN2bShTcGVjaWVzIH4gU2VwYWwuTGVuZ3RoICsgU2VwYWwuV2lkdGggKyBQZXRhbC5MZW5ndGggKyBQZXRhbC5XaWR0aCwgZGF0YSA9IHRyYWluX2RhdGEsIGtlcm5lbCA9ICJsaW5lYXIiKQoKIyBQcmVkaWN0IHVzaW5nIHRoZSB0cmFpbmVkIG1vZGVsCnByZWRpY3Rpb25zIDwtIHByZWRpY3Qoc3ZtX21vZGVsLCBuZXdkYXRhID0gdGVzdF9kYXRhKQoKIyBDb25mdXNpb24gbWF0cml4CmNvbmZfbWF0cml4IDwtIGNvbmZ1c2lvbk1hdHJpeChwcmVkaWN0aW9ucywgdGVzdF9kYXRhJFNwZWNpZXMpCgojIFByaW50IGNvbmZ1c2lvbiBtYXRyaXgKcHJpbnQoIkNvbmZ1c2lvbiBNYXRyaXg6IikKcHJpbnQoY29uZl9tYXRyaXgpCgojIEFjY3VyYWN5CmFjY3VyYWN5IDwtIGNvbmZfbWF0cml4JG92ZXJhbGxbIkFjY3VyYWN5Il0KcHJpbnQocGFzdGUoIkFjY3VyYWN5OiIsIGFjY3VyYWN5KSkKCiMgRjEgU2NvcmUKZjFfc2NvcmUgPC0gY29uZl9tYXRyaXgkYnlDbGFzc1siRjEiXQpwcmludChwYXN0ZSgiRjEgU2NvcmU6IiwgZjFfc2NvcmUpKQoKYGBgCgoKYGBge3J9CiMgTG9hZCBuZWNlc3NhcnkgbGlicmFyaWVzCmxpYnJhcnkoZTEwNzEpICAjIEZvciBTVk0KbGlicmFyeShjYXJldCkgICAjIEZvciBtb2RlbCBldmFsdWF0aW9uCmxpYnJhcnkoZ2dwbG90MikgCmxpYnJhcnkobGF0dGljZSkKCiMgTG9hZCB0aGUgaXJpcyBkYXRhc2V0IChpdCdzIGJ1aWx0LWluKQpkYXRhKGlyaXMpCgojIFNwbGl0IHRoZSBkYXRhIGludG8gdHJhaW5pbmcgYW5kIHRlc3Rpbmcgc2V0cwpzZXQuc2VlZCgxMjMpCnRyYWluX2luZGljZXMgPC0gY3JlYXRlRGF0YVBhcnRpdGlvbihpcmlzJFNwZWNpZXMsIHAgPSAwLjgsIGxpc3QgPSBGQUxTRSkKdHJhaW5fZGF0YSA8LSBpcmlzW3RyYWluX2luZGljZXMsIF0KdGVzdF9kYXRhIDwtIGlyaXNbLXRyYWluX2luZGljZXMsIF0KCiMgVHJhaW4gYW4gU1ZNIGNsYXNzaWZpZXIgd2l0aCBhIGxpbmVhciBrZXJuZWwKc3ZtX21vZGVsIDwtIHN2bShTcGVjaWVzIH4gU2VwYWwuTGVuZ3RoICsgU2VwYWwuV2lkdGggKyBQZXRhbC5MZW5ndGggKyBQZXRhbC5XaWR0aCwgZGF0YSA9IHRyYWluX2RhdGEsIGtlcm5lbCA9ICJsaW5lYXIiKQoKIyBQcmVkaWN0IHVzaW5nIHRoZSB0cmFpbmVkIG1vZGVsCnByZWRpY3Rpb25zIDwtIHByZWRpY3Qoc3ZtX21vZGVsLCBuZXdkYXRhID0gdGVzdF9kYXRhKQoKIyBDb25mdXNpb24gbWF0cml4CmNvbmZfbWF0cml4IDwtIGNvbmZ1c2lvbk1hdHJpeChwcmVkaWN0aW9ucywgdGVzdF9kYXRhJFNwZWNpZXMpCgojIFByaW50IGNvbmZ1c2lvbiBtYXRyaXgKcHJpbnQoIkNvbmZ1c2lvbiBNYXRyaXg6IikKcHJpbnQoY29uZl9tYXRyaXgpCgojIEFjY3VyYWN5CmFjY3VyYWN5IDwtIGNvbmZfbWF0cml4JG92ZXJhbGxbIkFjY3VyYWN5Il0KcHJpbnQocGFzdGUoIkFjY3VyYWN5OiIsIGFjY3VyYWN5KSkKCiMgRjEgU2NvcmUKZjFfc2NvcmUgPC0gY29uZl9tYXRyaXgkYnlDbGFzc1siRjEiXQpwcmludChwYXN0ZSgiRjEgU2NvcmU6IiwgZjFfc2NvcmUpKQoKCgojIFBsb3QgdGhlIGNvbmZ1c2lvbiBtYXRyaXgKY29uZl9wbG90IDwtIHBsb3QoY29uZl9tYXRyaXgkdGFibGUsIGNvbCA9IGMoImxpZ2h0Ymx1ZSIsICJsaWdodGNvcmFsIiksCiAgICAgICAgICAgICAgICAgIG1haW4gPSAiQ29uZnVzaW9uIE1hdHJpeCBmb3IgU1ZNIG9uIElyaXMgRGF0YXNldCIsCiAgICAgICAgICAgICAgICAgIHhsYWIgPSAiUHJlZGljdGVkIiwgeWxhYiA9ICJBY3R1YWwiKQoKIyBEaXNwbGF5IHRoZSBwbG90CmNvbmZfcGxvdAoKYGBgCgoKYGBge3J9CmNtID0gY29uZl9tYXRyaXgKCnBsdCA8LSBhcy5kYXRhLmZyYW1lKGNtJHRhYmxlKQpwbHQkUHJlZGljdGlvbiA8LSBmYWN0b3IocGx0JFByZWRpY3Rpb24sIGxldmVscz1yZXYobGV2ZWxzKHBsdCRQcmVkaWN0aW9uKSkpCgpnZ3Bsb3QocGx0LCBhZXMoUHJlZGljdGlvbixSZWZlcmVuY2UsIGZpbGw9IEZyZXEpKSArCiAgICAgICAgZ2VvbV90aWxlKCkgKyAKICAgICAgICBnZW9tX3RleHQoYWVzKGxhYmVsPUZyZXEpKSArCiAgICAgICAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9IndoaXRlIiwgaGlnaD0ic2t5Ymx1ZSIpICsKICAgICAgICBsYWJzKHggPSAiUmVmZXJlbmNlIiwKICAgICAgICAgICAgIHkgPSAiUHJlZGljdGlvbiIpIAoKYGBgCgpgYGB7cn0KcmV2KGxldmVscyhwbHQkUHJlZGljdGlvbikpCmBgYAoKCmBgYHtyfQojIEltcG9ydCBjYXJldCBsaWJyYXJ5CmxpYnJhcnkoY2FyZXQpCiAKIyBDcmVhdGUgRGF0YQphY3R1YWwgPC0gZmFjdG9yKHJlcChjKDEsIDIpLAogICAgICAgICAgICAgICAgICAgICB0aW1lcz1jKDE2LCAyNCkpKQpwcmVkaWN0ZWQgPC0gZmFjdG9yKHJlcChjKDEsIDIsIDEsIDIpLAogICAgICAgICAgICAgICAgICAgICAgICB0aW1lcz1jKDEyLCA0LCA3LCAxNykpKQogCiMgY3JlYXRlIGNvbmZ1c2lvbiBtYXRyaXggCmNvbmZ1c2lvbk1hdHJpeChwcmVkaWN0ZWQsIGFjdHVhbCwKICAgICAgICAgICAgICAgIG1vZGUgPSAiZXZlcnl0aGluZyIsCiAgICAgICAgICAgICAgICBwb3NpdGl2ZT0iMSIpCmBgYAoKCgoKIyBTdGF0aXN0aWNhbCBBbmFseXNpcwoKIyMKYGBge3J9CiMgQ2FsY3VsYXRlIHByb2JhYmlsaXR5CnByb2Jfc2V0b3NhIDwtIHN1bShpcmlzJFNwZWNpZXMgPT0gInNldG9zYSIpIC8gbnJvdyhpcmlzKQpwcmludCgiUHJvYmFiaWxpdHkgb2YgU2V0b3NhOiIpCnByaW50KHByb2Jfc2V0b3NhKQoKIyBOb3JtYWwgZGlzdHJpYnV0aW9uCmhpc3QoaXJpcyRTZXBhbC5MZW5ndGgsIHByb2JhYmlsaXR5ID0gVFJVRSwgbWFpbiA9ICJIaXN0b2dyYW0gb2YgU2VwYWwgTGVuZ3RoIikKbGluZXMoZGVuc2l0eShpcmlzJFNlcGFsLkxlbmd0aCksIGNvbCA9ICJibHVlIikKCmBgYAojIyBQQ0EKYGBge3J9CiMgUHJpbmNpcGFsIENvbXBvbmVudCBBbmFseXNpcyAoUENBKQpwY2EgPC0gcHJjb21wKGlyaXNbLCAtNV0pCnN1bW1hcnkocGNhKQoKYGBgCgojIyBULXRlc3QKYGBge3J9CnNldG9zYSA8LSBpcmlzJFNlcGFsLkxlbmd0aFtpcmlzJFNwZWNpZXMgPT0gInNldG9zYSJdCnZpcmdpbmljYSA8LSBpcmlzJFNlcGFsLkxlbmd0aFtpcmlzJFNwZWNpZXMgPT0gInZpcmdpbmljYSJdCnRfdGVzdF9yZXN1bHQgPC0gdC50ZXN0KHNldG9zYSwgdmlyZ2luaWNhKQpwcmludCh0X3Rlc3RfcmVzdWx0KQoKIyBodHRwczovL3d3dy5zdGF0b2xvZ3kub3JnL2ludGVycHJldC10LXRlc3QtcmVzdWx0cy1pbi1yLwpgYGAKCgpgYGB7cn0Kc2V0b3NhIDwtIGlyaXMkU2VwYWwuTGVuZ3RoW2lyaXMkU3BlY2llcyA9PSAic2V0b3NhIl0KdmlyZ2luaWNhIDwtIGlyaXMkU2VwYWwuTGVuZ3RoW2lyaXMkU3BlY2llcyA9PSAidmlyZ2luaWNhIl0KdF90ZXN0X3Jlc3VsdCA8LSB0LnRlc3Qoc2V0b3NhLCB2aXJnaW5pY2EsIGFsdGVybmF0aXZlID0gInR3by5zaWRlZCIpIAojIGFsdGVybmF0aXZlOiBUaGUgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcy4gT3B0aW9ucyBpbmNsdWRlIOKAnHR3by5zaWRlZOKAnSwg4oCcbGVzc+KAnSwgb3Ig4oCcZ3JlYXRlci7igJ0KcHJpbnQodF90ZXN0X3Jlc3VsdCkKCiMgaHR0cHM6Ly93d3cuc3RhdG9sb2d5Lm9yZy9pbnRlcnByZXQtdC10ZXN0LXJlc3VsdHMtaW4tci8KYGBgCgoKIyMgQU5PVkEKYGBge3J9CmFub3ZhX3Jlc3VsdCA8LSBhb3YoU2VwYWwuTGVuZ3RoIH4gU3BlY2llcywgZGF0YSA9IGlyaXMpCnN1bW1hcnkoYW5vdmFfcmVzdWx0KQoKYGBgCgojIyBUdWtleSdzIHBvc3Rob2MgdGVzdApgYGB7cn0KcG9zdGhvYyA8LSBUdWtleUhTRChhbm92YV9yZXN1bHQpCnByaW50KHBvc3Rob2MpCgpgYGAKIyMjIENoaS1zcXVhcmUgdGVzdApgYGB7cn0KIyBMb2FkIG5lY2Vzc2FyeSBsaWJyYXJpZXMKbGlicmFyeShzdGF0cykKCiMgTG9hZCB0aGUgaXJpcyBkYXRhc2V0IChpdCdzIGJ1aWx0LWluKQpkYXRhKGlyaXMpCgojIENoaS1zcXVhcmUgdGVzdCAodGVzdGluZyBpbmRlcGVuZGVuY2UgYmV0d2VlbiBzcGVjaWVzIGFuZCBwZXRhbCBsZW5ndGgpCmNoaXNxLnRlc3QodGFibGUoaXJpcyRTcGVjaWVzLCBjdXQoaXJpcyRQZXRhbC5MZW5ndGgsIGJyZWFrcyA9IGMoMSwgMiwgMywgNCwgNSkpKSkKCmBgYAoKCmBgYHtyfQojIExvYWQgbmVjZXNzYXJ5IGxpYnJhcmllcwpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkocmVzaGFwZSkKCiMgTG9hZCB0aGUgaXJpcyBkYXRhc2V0IChpdCdzIGJ1aWx0LWluKQpkYXRhKGlyaXMpCgojIFBhaXJ3aXNlIHNjYXR0ZXIgcGxvdCB3aXRoIGNvbG9yIGJ5IFNwZWNpZXMKZ2dwbG90KGlyaXMsIGFlcyh4ID0gU2VwYWwuTGVuZ3RoLCB5ID0gU2VwYWwuV2lkdGgsIGNvbG9yID0gU3BlY2llcykpICsKICBnZW9tX3BvaW50KCkgKwogIGZhY2V0X2dyaWQoflNwZWNpZXMpICsKICBsYWJzKHRpdGxlID0gIlBhaXJ3aXNlIFNjYXR0ZXIgUGxvdCIsCiAgICAgICB4ID0gIlNlcGFsIExlbmd0aCIsIHkgPSAiU2VwYWwgV2lkdGgiKQoKYGBgCgpgYGB7cn0KIyBMb2FkIHJlcXVpcmVkIGxpYnJhcnkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHN0YXRzKQoKaXJpcyA9IHJlYWQuY3N2KCdDbGFzcyA0L2lyaXMuY3N2JykKCiMgQXBwbHkgUENBCmlyaXNfcGNhIDwtIHByY29tcChpcmlzWywgLTVdLCBjZW50ZXIgPSBUUlVFLCBzY2FsZSA9IFRSVUUpCmlyaXNfcGNhCnN1bW1hcnkoaXJpc19wY2EpCgoKCgoKIyBFeHRyYWN0IFBDIHNjb3JlcwpwY19zY29yZXMgPC0gYXMuZGF0YS5mcmFtZShpcmlzX3BjYSR4WywgMToyXSkKcGNfc2NvcmVzCgojIENvbWJpbmUgUEMgc2NvcmVzIHdpdGggU3BlY2llcwpwY19kYXRhIDwtIGNiaW5kKHBjX3Njb3JlcywgU3BlY2llcyA9IGlyaXMkdmFyaWV0eSkKcGNfZGF0YQoKIyBQbG90IFBDQSAoMkQpCmdncGxvdChwY19kYXRhLCBhZXMoUEMxLCBQQzIsIGNvbG9yID0gU3BlY2llcykpICsKICBnZW9tX3BvaW50KCkgKwogIGxhYnModGl0bGUgPSAiUENBICgyRCkgb2YgSXJpcyBEYXRhc2V0IiwKICAgICAgIHggPSAiUHJpbmNpcGFsIENvbXBvbmVudCAxIiwKICAgICAgIHkgPSAiUHJpbmNpcGFsIENvbXBvbmVudCAyIikgKwogIHRoZW1lX21pbmltYWwoKQoKIyBodHRwOi8vd3d3LnN0aGRhLmNvbS9lbmdsaXNoL2FydGljbGVzLzMxLXByaW5jaXBhbC1jb21wb25lbnQtbWV0aG9kcy1pbi1yLXByYWN0aWNhbC1ndWlkZS8xMTgtcHJpbmNpcGFsLWNvbXBvbmVudC1hbmFseXNpcy1pbi1yLXByY29tcC12cy1wcmluY29tcC8KIyBodHRwczovL3d3dy5kYXRhY2FtcC5jb20vdHV0b3JpYWwvcGNhLWFuYWx5c2lzLXIKIyBodHRwOi8vd3d3LnN0aGRhLmNvbS9lbmdsaXNoL2FydGljbGVzLzMxLXByaW5jaXBhbC1jb21wb25lbnQtbWV0aG9kcy1pbi1yLXByYWN0aWNhbC1ndWlkZS8xMTItcGNhLXByaW5jaXBhbC1jb21wb25lbnQtYW5hbHlzaXMtZXNzZW50aWFscy8KYGBgCmBgYHtyfQpmdml6X2NvczIoaXJpc19wY2EsIGNob2ljZSA9ICJ2YXIiLCBheGVzID0gMToyKQpgYGAKCmBgYHtyfQojIENvbnRyaWJ1dGlvbnMgb2YgdmFyaWFibGVzIHRvIFBDMQpmdml6X2NvbnRyaWIoaXJpc19wY2EsIGNob2ljZSA9ICJ2YXIiLCBheGVzID0gMSkKIyBDb250cmlidXRpb25zIG9mIHZhcmlhYmxlcyB0byBQQzIKZnZpel9jb250cmliKGlyaXNfcGNhLCBjaG9pY2UgPSAidmFyIiwgYXhlcyA9IDIpCmBgYAoKCmBgYHtyfQp2YXIgPC0gZ2V0X3BjYV92YXIoaXJpc19wY2EpCnZhcgoKbGlicmFyeSgiY29ycnBsb3QiKQpjb3JycGxvdCh2YXIkY29zMiwgaXMuY29ycj1GQUxTRSkKCmBgYAoKCmBgYHtyfQoKCnZhciA8LSBnZXRfcGNhX3ZhcihpcmlzX3BjYSkKdmFyJGNvbnRyaWIKYGBgCgoKYGBge3J9CmxpYnJhcnkoZmFjdG9leHRyYSkKZnZpel9laWcoaXJpc19wY2EsIGFkZGxhYmVscyA9IFRSVUUpCmBgYAoKCmBgYHtyfQojIEdyYXBoIG9mIHRoZSB2YXJpYWJsZXMKZnZpel9wY2FfdmFyKGlyaXNfcGNhLCBjb2wudmFyID0gImNvbnRyaWIiLCAjIENvbG9yIGJ5IGNvbnRyaWJ1dGlvbnMgdG8gdGhlIFBDCiAgICAgICAgICAgICBncmFkaWVudC5jb2xzID0gYygiIzAwQUZCQiIsICIjRTdCODAwIiwgIiNGQzRFMDciKSwKICAgICAgICAgICAgIHJlcGVsID0gVFJVRSApICAgICMgQXZvaWQgdGV4dCBvdmVybGFwcGluZykKYGBgCgpgYGB7cn0KZnZpel9wY2FfaW5kKGlyaXNfcGNhLAogICAgICAgICAgICAgY29sLmluZCA9ICJjb3MyIiwgIyBDb2xvciBieSB0aGUgcXVhbGl0eSBvZiByZXByZXNlbnRhdGlvbgogICAgICAgICAgICAgZ3JhZGllbnQuY29scyA9IGMoIiMwMEFGQkIiLCAiI0U3QjgwMCIsICIjRkM0RTA3IiksCiAgICAgICAgICAgICByZXBlbCA9IFRSVUUgICAgICMgQXZvaWQgdGV4dCBvdmVybGFwcGluZwogICAgICAgICAgICAgKQpgYGAKCgpgYGB7cn0KZnZpel9wY2FfaW5kKGlyaXNfcGNhLAogICAgICAgICAgICAgZ2VvbS5pbmQgPSAicG9pbnQiLCAjIHNob3cgcG9pbnRzIG9ubHkgKG5idXQgbm90ICJ0ZXh0IikKICAgICAgICAgICAgIGNvbC5pbmQgPSAiY29zMiIsICMgQ29sb3IgYnkgdGhlIHF1YWxpdHkgb2YgcmVwcmVzZW50YXRpb24KICAgICAgICAgICAgIGdyYWRpZW50LmNvbHMgPSBjKCIjMDBBRkJCIiwgIiNFN0I4MDAiLCAiI0ZDNEUwNyIpLAogICAgICAgICAgICAgcmVwZWwgPSBUUlVFICAgICAjIEF2b2lkIHRleHQgb3ZlcmxhcHBpbmcKICAgICAgICAgICAgICkKYGBgCgoKCmBgYHtyfQpmdml6X3BjYV9pbmQoaXJpc19wY2EsCiAgICAgICAgICAgICBnZW9tLmluZCA9ICJwb2ludCIsICMgc2hvdyBwb2ludHMgb25seSAobmJ1dCBub3QgInRleHQiKQogICAgICAgICAgICAgY29sLmluZCA9IGlyaXMkdmFyaWV0eSwgIyBjb2xvciBieSBncm91cHMKICAgICAgICAgICAgIHBhbGV0dGUgPSBjKCIjMDBBRkJCIiwgIiNFN0I4MDAiLCAiI0ZDNEUwNyIpLAogICAgICAgICAgICAgYWRkRWxsaXBzZXMgPSBUUlVFLCAjIENvbmNlbnRyYXRpb24gZWxsaXBzZXMKICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9ICJHcm91cHMiCiAgICAgICAgICAgICApCmBgYAoKCgojIEludGVyYWN0aXZlIHBsb3QKYGBge3J9CiMgTG9hZCByZXF1aXJlZCBsaWJyYXJ5CmxpYnJhcnkocGxvdGx5KQppcmlzID0gcmVhZC5jc3YoJ2RhdGFzZXRzL2lyaXMuY3N2JykKCiMgUGxvdCAzRCBTY2F0dGVyIFBsb3QKcGxvdF9seShkYXRhID0gaXJpcywgeCA9IH5zZXBhbC5sZW5ndGgsIHkgPSB+c2VwYWwud2lkdGgsIHogPSB+cGV0YWwubGVuZ3RoLCBjb2xvciA9IH52YXJpZXR5LAogICAgICAgIHR5cGUgPSAic2NhdHRlcjNkIiwgbW9kZSA9ICJtYXJrZXJzIikgJT4lCiAgbGF5b3V0KHNjZW5lID0gbGlzdCh4YXhpcyA9IGxpc3QodGl0bGUgPSAnU2VwYWwgTGVuZ3RoJyksCiAgICAgICAgICAgICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAnU2VwYWwgV2lkdGgnKSwKICAgICAgICAgICAgICAgICAgICAgIHpheGlzID0gbGlzdCh0aXRsZSA9ICdQZXRhbCBMZW5ndGgnKSksCiAgICAgICAgIG1hcmdpbiA9IGxpc3QobCA9IDAsIHIgPSAwLCBiID0gMCwgdCA9IDApKQoKYGBgCgoKYGBge3J9CmxpYnJhcnkocGxvdGx5KQoKZmlnIDwtIGlyaXMgJT4lCiAgcGxvdF9seSh5ID0gfnNlcGFsLndpZHRoLHR5cGUgPSAndmlvbGluJykgCgpmaWcKCmBgYAoKCgpgYGB7cn0KZmlnIDwtIGlyaXMgJT4lCiAgcGxvdF9seSgKICAgIHkgPSB+c2VwYWwud2lkdGgsCiAgICB0eXBlID0gJ2JveCcKICApCgpmaWcKYGBgCgoKCgoKYGBge3J9CmZpZyA8LSBpcmlzICU+JQogIHBsb3RfbHkoCiAgICB5ID0gfnNlcGFsLndpZHRoLAogICAgdHlwZSA9ICdiYXInCiAgKSAKCmZpZwpgYGAKCgpgYGB7cn0KZmlnIDwtIGlyaXMgJT4lCiAgcGxvdF9seSgKICAgIHggPSB+c2VwYWwud2lkdGgsCiAgICB0eXBlID0gJ2hpc3RvZ3JhbScKICApIAoKZmlnCmBgYAoKCgpgYGB7cn0KCiMgTG9hZCByZXF1aXJlZCBsaWJyYXJ5CmxpYnJhcnkocGxvdGx5KQoKCiMgQ3JlYXRlIEJveHBsb3QKYm94cGxvdCA9IHBsb3RfbHkoaXJpcywgeCA9IH52YXJpZXR5LCB5ID0gfnNlcGFsLmxlbmd0aCwgdHlwZSA9ICJib3giKSAlPiUKICBsYXlvdXQoCiAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiQ2F0ZWdvcnkiKSwgICMgU2V0IFgtYXhpcyB0aXRsZQogICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIlZhbHVlIikgICAgICMgU2V0IFktYXhpcyB0aXRsZQogICkKCiMgUHJpbnQgdGhlIHBsb3QKYm94cGxvdApgYGAKCgpgYGB7cn0KIyBMb2FkIHJlcXVpcmVkIGxpYnJhcnkKbGlicmFyeShwbG90bHkpCgojIExvYWQgSXJpcyBkYXRhc2V0CmRhdGEoaXJpcykKCiMgMS4gU2NhdHRlciBQbG90CnNjYXR0ZXJfcGxvdCA8LSBwbG90X2x5KGlyaXMsIHggPSB+U2VwYWwuTGVuZ3RoLCB5ID0gflNlcGFsLldpZHRoLCBjb2xvciA9IH5TcGVjaWVzLCB0eXBlID0gInNjYXR0ZXIiLCBtb2RlID0gIm1hcmtlcnMiKSAlPiUKICBsYXlvdXQoeGF4aXMgPSBsaXN0KHRpdGxlID0gIlNlcGFsIExlbmd0aCIpLCB5YXhpcyA9IGxpc3QodGl0bGUgPSAiU2VwYWwgV2lkdGgiKSwgdGl0bGUgPSAiU2NhdHRlciBQbG90IikKc2NhdHRlcl9wbG90CgoKIyAyLiBCb3ggUGxvdApib3hfcGxvdCA8LSBwbG90X2x5KGlyaXMsIHggPSB+U3BlY2llcywgeSA9IH5QZXRhbC5MZW5ndGgsIHR5cGUgPSAiYm94IikgJT4lCiAgbGF5b3V0KHhheGlzID0gbGlzdCh0aXRsZSA9ICJTcGVjaWVzIiksIHlheGlzID0gbGlzdCh0aXRsZSA9ICJQZXRhbCBMZW5ndGgiKSwgdGl0bGUgPSAiQm94IFBsb3QiKQpib3hfcGxvdAoKCiMgMy4gVmlvbGluIFBsb3QKdmlvbGluX3Bsb3QgPC0gcGxvdF9seShpcmlzLCB4ID0gflNwZWNpZXMsIHkgPSB+UGV0YWwuV2lkdGgsIHR5cGUgPSAidmlvbGluIikgJT4lCiAgbGF5b3V0KHhheGlzID0gbGlzdCh0aXRsZSA9ICJTcGVjaWVzIiksIHlheGlzID0gbGlzdCh0aXRsZSA9ICJQZXRhbCBXaWR0aCIpLCB0aXRsZSA9ICJWaW9saW4gUGxvdCIpCnZpb2xpbl9wbG90CgoKIyA0LiBIaXN0b2dyYW0KaGlzdG9ncmFtX3Bsb3QgPC0gcGxvdF9seShpcmlzLCB4ID0gflNlcGFsLkxlbmd0aCwgdHlwZSA9ICJoaXN0b2dyYW0iKSAlPiUKICBsYXlvdXQoeGF4aXMgPSBsaXN0KHRpdGxlID0gIlNlcGFsIExlbmd0aCIpLCB5YXhpcyA9IGxpc3QodGl0bGUgPSAiRnJlcXVlbmN5IiksIHRpdGxlID0gIkhpc3RvZ3JhbSIpCmhpc3RvZ3JhbV9wbG90CgoKIyA1LiBIZWF0bWFwIG9mIENvcnJlbGF0aW9uIE1hdHJpeApjb3JyZWxhdGlvbl9tYXRyaXggPC0gY29yKGlyaXNbLCBjKCJTZXBhbC5MZW5ndGgiLCAiU2VwYWwuV2lkdGgiLCAiUGV0YWwuTGVuZ3RoIiwgIlBldGFsLldpZHRoIildKQpoZWF0bWFwX3Bsb3QgPC0gcGxvdF9seSh6ID0gY29ycmVsYXRpb25fbWF0cml4LCB0eXBlID0gImhlYXRtYXAiLCBjb2xvcnNjYWxlID0gIlZpcmlkaXMiKSAlPiUKICBsYXlvdXQoeGF4aXMgPSBsaXN0KHRpdGxlID0gY29sbmFtZXMoY29ycmVsYXRpb25fbWF0cml4KSksIHlheGlzID0gbGlzdCh0aXRsZSA9IGNvbG5hbWVzKGNvcnJlbGF0aW9uX21hdHJpeCkpLCB0aXRsZSA9ICJDb3JyZWxhdGlvbiBIZWF0bWFwIikKaGVhdG1hcF9wbG90CgoKIyA2LiBCYXIgUGxvdApiYXJfcGxvdCA8LSBwbG90X2x5KGlyaXMsIHggPSB+U3BlY2llcywgdHlwZSA9ICJiYXIiLCBtYXJrZXIgPSBsaXN0KGNvbG9yID0gImJsdWUiKSkgJT4lCiAgbGF5b3V0KHhheGlzID0gbGlzdCh0aXRsZSA9ICJTcGVjaWVzIiksIHlheGlzID0gbGlzdCh0aXRsZSA9ICJDb3VudCIpLCB0aXRsZSA9ICJCYXIgUGxvdCIpCmJhcl9wbG90CgoKIyA3LiBMaW5lIFBsb3QgYWZ0ZXIgU29ydGluZyBhIENvbHVtbgpzb3J0ZWRfZGF0YSA8LSBpcmlzW29yZGVyKGlyaXMkU2VwYWwuTGVuZ3RoKSwgXQpsaW5lX3Bsb3QgPC0gcGxvdF9seShzb3J0ZWRfZGF0YSwgeCA9IH5TZXBhbC5MZW5ndGgsIHkgPSB+U2VwYWwuV2lkdGgsIHR5cGUgPSAic2NhdHRlciIsIG1vZGUgPSAibGluZXMiKSAlPiUKICBsYXlvdXQoeGF4aXMgPSBsaXN0KHRpdGxlID0gIlNlcGFsIExlbmd0aCAoU29ydGVkKSIpLCB5YXhpcyA9IGxpc3QodGl0bGUgPSAiU2VwYWwgV2lkdGgiKSwgdGl0bGUgPSAiTGluZSBQbG90IChTb3J0ZWQpIikKbGluZV9wbG90CgoKIyBEaXNwbGF5IHBsb3RzCiNzdWJwbG90KHNjYXR0ZXJfcGxvdCwgYm94X3Bsb3QsIHZpb2xpbl9wbG90LCBoaXN0b2dyYW1fcGxvdCwgaGVhdG1hcF9wbG90LCBiYXJfcGxvdCwgbGluZV9wbG90LCBucm93cyA9IDQpCgpgYGAKCgpgYGB7cn0KIyBMb2FkIHJlcXVpcmVkIGxpYnJhcmllcwpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocGxvdGx5KQoKIyBVc2UgcGxvdF9seSB0byBjcmVhdGUgYSAzRCBzY2F0dGVyIHBsb3QKcGxvdF9seShkYXRhID0gaXJpcywgeCA9IH5zZXBhbC5sZW5ndGgsIHkgPSB+c2VwYWwud2lkdGgsIHogPSB+cGV0YWwubGVuZ3RoLCBjb2xvciA9IH52YXJpZXR5LCB0eXBlID0gInNjYXR0ZXIzZCIsIG1vZGUgPSAibWFya2VycyIpICU+JQogIGxheW91dChzY2VuZSA9IGxpc3QoeGF4aXMgPSBsaXN0KHRpdGxlID0gIlNlcGFsIExlbmd0aCIpLAogICAgICAgICAgICAgICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIlNlcGFsIFdpZHRoIiksCiAgICAgICAgICAgICAgICAgICAgICB6YXhpcyA9IGxpc3QodGl0bGUgPSAiUGV0YWwgTGVuZ3RoIikpKQoKYGBgCgoKYGBge3J9CiMgTG9hZCByZXF1aXJlZCBsaWJyYXJpZXMKbGlicmFyeShwbG90bHkpCgojIENyZWF0ZSBzYW1wbGUgZGF0YSBmb3IgdGhlIHN1cmZhY2UgcGxvdAp4IDwtIHNlcSgtNSwgNSwgbGVuZ3RoLm91dCA9IDEwMCkKeSA8LSBzZXEoLTUsIDUsIGxlbmd0aC5vdXQgPSAxMDApCnogPC0gb3V0ZXIoeCwgeSwgZnVuY3Rpb24oeCwgeSkgc2luKHNxcnQoeF4yICsgeV4yKSkgLyBzcXJ0KHheMiArIHleMikpCgojIERlZmluZSBhIGN1c3RvbSBjb2xvciBzY2FsZQpjb2xvcl9zY2FsZSA8LSBjKCIjNDQwMTU0IiwgIiM0ODI4NzgiLCAiIzNFNDk4OSIsICIjMzE2ODhFIiwgIiMyNjgzOEUiLCAiIzFGOUU4OSIsICIjMzVCNzc5IiwgIiM2RENENTkiLCAiI0I0REUyQyIsICIjRkRFNzI1IikKCiMgQ3JlYXRlIGEgM0Qgc3VyZmFjZSBwbG90CnBsb3RfbHkoeiA9IH56LCB4ID0gfngsIHkgPSB+eSwgdHlwZSA9ICJzdXJmYWNlIiwgY29sb3JzID0gY29sb3Jfc2NhbGUpICU+JQogIGxheW91dChzY2VuZSA9IGxpc3QoCiAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAnWC1heGlzJyksCiAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAnWS1heGlzJyksCiAgICB6YXhpcyA9IGxpc3QodGl0bGUgPSAnWi1heGlzJykKICApKQoKYGBgCgoKCmBgYHtyfQpsaWJyYXJ5KHJlc2hhcGUyKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeSh0aWR5bW9kZWxzKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShrZXJubGFiKQpsaWJyYXJ5KHByYWNtYSkgI0ZvciBtZXNoZ3JpZCgpCgoKZGF0YShpcmlzKQoKbWVzaF9zaXplIDwtIC4wMgptYXJnaW4gPC0gMAoKWCA8LSBpcmlzICU+JSBzZWxlY3QoU2VwYWwuV2lkdGgsIFNlcGFsLkxlbmd0aCkKCnkgPC0gaXJpcyAlPiUgc2VsZWN0KFBldGFsLldpZHRoKQoKbW9kZWwgPC0gc3ZtX3JiZihjb3N0ID0gMS4wKSAlPiUgCiAgc2V0X2VuZ2luZSgia2VybmxhYiIpICU+JSAKICBzZXRfbW9kZSgicmVncmVzc2lvbiIpICU+JSAKICBmaXQoUGV0YWwuV2lkdGggfiBTZXBhbC5XaWR0aCArIFNlcGFsLkxlbmd0aCwgZGF0YSA9IGlyaXMpCgp4X21pbiA8LSBtaW4oWCRTZXBhbC5XaWR0aCkgLSBtYXJnaW4KeF9tYXggPC0gbWF4KFgkU2VwYWwuV2lkdGgpIC0gbWFyZ2luCnlfbWluIDwtIG1pbihYJFNlcGFsLkxlbmd0aCkgLSBtYXJnaW4KeV9tYXggPC0gbWF4KFgkU2VwYWwuTGVuZ3RoKSAtIG1hcmdpbgp4cmFuZ2UgPC0gc2VxKHhfbWluLCB4X21heCwgbWVzaF9zaXplKQp5cmFuZ2UgPC0gc2VxKHlfbWluLCB5X21heCwgbWVzaF9zaXplKQp4eSA8LSBtZXNoZ3JpZCh4ID0geHJhbmdlLCB5ID0geXJhbmdlKQp4eCA8LSB4eSRYCnl5IDwtIHh5JFkKZGltX3ZhbCA8LSBkaW0oeHgpCnh4MSA8LSBtYXRyaXgoeHgsIGxlbmd0aCh4eCksIDEpCnl5MSA8LSBtYXRyaXgoeXksIGxlbmd0aCh5eSksIDEpCmZpbmFsIDwtIGNiaW5kKHh4MSwgeXkxKQpwcmVkIDwtIG1vZGVsICU+JQogIHByZWRpY3QoZmluYWwpCgpwcmVkIDwtIHByZWQkLnByZWQKcHJlZCA8LSBtYXRyaXgocHJlZCwgZGltX3ZhbFsxXSwgZGltX3ZhbFsyXSkKCmZpZyA8LSBwbG90X2x5KGlyaXMsIHggPSB+U2VwYWwuV2lkdGgsIHkgPSB+U2VwYWwuTGVuZ3RoLCB6ID0gflBldGFsLldpZHRoICkgJT4lIAogIGFkZF9tYXJrZXJzKHNpemUgPSA1KSAlPiUgCiAgYWRkX3N1cmZhY2UoeD14cmFuZ2UsIHk9eXJhbmdlLCB6PXByZWQsIGFscGhhID0gMC42NSwgdHlwZSA9ICdtZXNoM2QnLCBuYW1lID0gJ3ByZWRfc3VyZmFjZScpCmZpZwoKCmBgYAoK