"""
%% is modulus operator
sink()
letters[1:5]            # "a" "b" "c" "d" "e"
LETTERS[3:8]  # "C" "D" "E" "F" "G" "H"
diag(1:5)           # Diagonal matrix with 1:5 on diagonal
matrix(NA, 5, 4)    # Empty matrix (all NA)
mat[1:3, c(2, 4)]  # Rows 1-3, columns 2 and 4
mat[1:3, 3] <- c(13, 19, 31)  # Replace part of column
U * V              # Element-wise multiplication
U[U < 5 | U > 17] <- 0  # Replace values meeting condition
cbind(A1, A2)      # Combine columns (side by side)
rbind(A1, B)       # Combine rows (stack vertically)
sapply()    # Apply to all elements
"""
'p' is not recognized as an internal or external command,
operable program or batch file.

Introduction to R & RStudio

📌 Key Points: R is a statistical programming language, open-source and free.

RStudio is an IDE (Integrated Development Environment) that makes coding in R easier.

R must be installed before RStudio.

CRAN is the official repository for R packages.

Rtools is needed for compiling packages with C/C++/Fortran code on Windows.

❓ Concept Check: What is the difference between R and RStudio?

Why is R considered “open-source”?

When do you need Rtools?

Important Commands:

# Check R version
version
R.version.string
# Check working directory
getwd()
# Set working directory
setwd("C:\\Users\\Dell\\OneDrive\\Desktop\\STATISTICS\\2nd Year\\R programming\\Incourse prep")
# Execute a script file named "my_script.R"
source("30 Nov.R")

Vectors, Matrices & Linear Algebra

# Start diverting output to a file named "output.txt"
sink("output.txt")
# Any output below will be written to "output.txt" instead of the console
print("This will be written to the file")
summary(c(1, 3, 5, 7, 9))
# Stop diverting output and return to the console
sink()

Vectors are ordered collections of the same type.

Created with c(), seq(), rep(), :

Matrices are 2D arrays of the same type.

Created with matrix().

Use %% for matrix multiplication (not ).

Important functions: t(), solve(), det(), eigen(), matrix(), dim(), rbind(), cbind(), diag()

Data Frames & Lists

Data frames are tables with columns of different types.

Lists can hold different types of objects.

data.frame() list() read.csv(), write.csv() read.xlsx(), write.xlsx() head(), summary() === View data lapply(), sapply() === Apply functions to lists

# Data frame
df <- data.frame(
  Name = c("Alice", "Bob"),
  Age = c(25, 30),
  Score = c(85, 90)
)

# Write to CSV
write.csv(df, "data.csv", row.names = FALSE)   # New csv file created & stored the data. 

# List
my_list <- list(
  vec = 1:5,
  mat = matrix(1:4, nrow = 2),
  df = df
)

my_list

Problem 1: Student Marks Simulation (From Assignment 1)

Simulating and Analyzing Student Exam Scores in R

In this assignment, you will simulate exam scores for a class and analyze a random sample of students using R.

Final Deliverables

Submit the following:

A. R code (separately written) for Questions 1–7
B. The data frame SampleData.df showing the IDs and marks of the 10 selected students
C. The numerical results from Task 7, clearly formatted (either printed neatly or shown in a data frame)


Class Information

  • Total number of students: 91
  • Student IDs: 001 to 091

Task 1: Simulate Exam Marks

  1. Generate exam marks for all 91 students using a normal distribution:
    • Mean = 77
    • Standard Deviation = 1
  2. Use the function rnorm() to generate the marks.
  3. Store the generated marks in a vector named Marks.
  4. Set the random seed using set.seed(209) to make the results reproducible.
  5. Create a vector ID containing student IDs as integers from 1 to 91.
set.seed(209)
ID <- 1:91
Marks <- rnorm(91, mean = 77, sd = 1)

Task 2: Randomly Select 10 Students

  1. Randomly select 10 students from the class without replacement.
  2. Use the function sample() to select the student IDs.
  3. Set the random seed using set.seed(2) before sampling.
  4. Extract the exam marks corresponding to the selected student IDs.
set.seed(2)
sample_id <- sample(ID, 10, replace = FALSE)
sample_marks <- Marks[sample_id]

Task 3: Sort the Sample

  1. Sort the selected student IDs in ascending order.
  2. Rearrange the corresponding marks so they match the sorted IDs.

Task 4: Create a Data Frame

Create a data frame named SampleData.df with the following columns: - ID: Sorted sampled student IDs
- Marks: Corresponding exam marks (rounded to 2 decimal places)

ord <- order(sample_id)

SampleData.df <- data.frame(
  ID = sample_id[ord],
  Marks = round(sample_marks[ord], 2)
)

Task 5: Save the Data Frame

Save SampleData.df in two formats:

Files to Save

  • Excel file: "Sample_Marks.xlsx"
  • Use openxlsx::write.xlsx()
  • CSV file: "SampleDataGPA.csv"
  • Use the base R function write.csv()

Instructions

  1. Create a new folder on your Desktop named:
    YourFirstName123
  • Replace YourFirstName with your actual first name
  • Replace 123 with the last three digits of your class roll number
  1. Set this folder as your working directory using setwd() before saving the files.
setwd("C:\\Users\\Dell\\OneDrive\\Desktop\\STATISTICS\\2nd Year\\R programming\\Incourse prep")

openxlsx::write.xlsx(SampleData.df, "Sample_Marks.xlsx")
write.csv(SampleData.df, "SampleDataGPA.csv", row.names = FALSE)

Task 6: Read the Files Back into R

  1. Read the Excel file using openxlsx::read.xlsx() and store it in:
  • SampleData_from_excel
  1. Read the CSV file using read.csv() and store it in:
  • SampleData_from_csv
  1. Display the first few rows of both data frames using the head() function.
SampleData_from_excel <- openxlsx::read.xlsx("Sample_Marks.xlsx")
SampleData_from_csv <- read.csv("SampleDataGPA.csv")

head(SampleData_from_excel)
head(SampleData_from_csv)

Task 7: Statistical Analysis (Using the 10 Sampled Marks)

Calculate the following statistics: 1. Mean
2. Standard Deviation
3. Standard Error
4. 2nd Central Moment
5. 4th Central Moment
6. Skewness
7. Kurtosis

x <- SampleData.df$Marks
n <- length(x)
x_bar <- mean(x)

results <- data.frame(
  Mean = mean(x),
  SD = sd(x),
  SE = sd(x)/sqrt(n),
  Central_Moment_2 = mean((x - x_bar)^2),
  Central_Moment_4 = mean((x - x_bar)^4),
  Skewness = mean((x - x_bar)^3)/(sd(x)^3),
  Kurtosis = mean((x - x_bar)^4)/(sd(x)^4)
)

results

Problem 2: Matrix Operations

# Create matrices
A <- matrix(1:4, nrow = 2)
A
B <- matrix(c(2, 0, 1, 3), nrow = 2)
B
# Compute: A² + 2B
result <- A %*% A + 2 * B
result

# Check if invertible
if(det(result) != 0) {
  inv_result <- solve(result)
  inv_result
}

IMPORTANT EXAM PROBLEM PATTERN:

# Task from lecture: Fill even rows with even numbers
A <- matrix(NA, 5, 4)
even_numbers <- seq(2, 20, by = 2)
k <- 1

for (i in 1:nrow(A)) {
    if (i %% 2 == 0) {  # Even rows
        for (j in 1:ncol(A)) {
            A[i, j] <- even_numbers[k]
            k <- k + 1
        }
    }
}
A

Eigenvalues and Eigenvectors:

For matrix A, if Av = λv, then: λ = eigenvalue (scalar) v = eigenvector (vector)

M <- matrix(c(2, 1, 1, 2), nrow = 2)
eigen_result <- eigen(M)

eigen_result$values    # Eigenvalues
eigen_result$vectors   # Eigenvectors

Matrix Operations Task

Problem Statement

  1. Create a Vector: Set the seed using the last 3 digits of your roll number (e.g., 245). Generate a vector v containing 8 random integers between 1 and 15, selected without replacement.
  2. Construct Matrices: Using vector v, create the following four matrices:
  • A1: matrix, filled row-wise.
  • B1: matrix, filled row-wise.
  • A2: matrix, filled column-wise.
  • B2: matrix, filled column-wise.
  1. Verify Transpose: Find the transpose of A1. Check if it is identical to B1, A2, or B2.
  2. Matrix Multiplication: Calculate the product of A1 and B1. Is the resulting matrix square? Is it invertible?
# 1. Create vector v
set.seed(245)  # Using last 3 digits of roll number
v <- sample(1:15, 8, replace = FALSE)

# 2. Create matrices
A1 <- matrix(v, nrow = 2, ncol = 4, byrow = TRUE)   # 2x4, row-wise
B1 <- matrix(v, nrow = 4, ncol = 2, byrow = TRUE)   # 4x2, row-wise
A2 <- matrix(v, nrow = 2, ncol = 4)                  # 2x4, column-wise
B2 <- matrix(v, nrow = 4, ncol = 2)                  # 4x2, column-wise

# 3. Check transposition
tA1 <- t(A1)
identical(tA1, B1)  # FALSE
identical(tA1, A2)  # FALSE
identical(tA1, B2)  # FALSE

# 4. Matrix multiplication
result <- A1 %*% B1
is_square <- nrow(result) == ncol(result)
is_invertible <- if(is_square) det(result) != 0 else FALSE

Question

Write an R function named gaussian_solver() that solves a system of linear equations using Gaussian Elimination with partial pivoting.

The function should meet the following requirements:

  1. The function must take two inputs:
    • A: a square coefficient matrix of order \(n \times n\)
    • b: a column vector of constants of length \(n\)
  2. Inside the function:
    • Create an augmented matrix by combining A and b
    • Perform forward elimination to convert the augmented matrix into an upper triangular form
    • Use partial pivoting at each step to improve numerical stability
    • Perform back substitution to compute the solution vector
  3. Store the solution in a numeric vector x:
    • Assign names to the solution variables as x1, x2, ..., xn
  4. The function should return the result as a list containing:
    • solution: the vector of solved values

Your function should work for any valid system of linear equations where a unique solution exists.

gaussian_solver_simple <- function(A, b) {
    n <- nrow(A)
    aug <- cbind(A, b)
    
    # Forward elimination
    for (i in 1:(n-1)) {
        # Find pivot row
        max_row <- which.max(abs(aug[i:n, i])) + i - 1
        if (max_row != i) {
            aug[c(i, max_row), ] <- aug[c(max_row, i), ]
        }
        
        # Eliminate below
        for (j in (i+1):n) {
            factor <- aug[j, i] / aug[i, i]
            aug[j, ] <- aug[j, ] - factor * aug[i, ]
        }
    }
    
    # Back substitution
    x <- numeric(n)
    for (i in n:1) {
        if (i == n) {
            x[i] <- aug[i, n+1] / aug[i, i]
        } else {
            x[i] <- (aug[i, n+1] - sum(aug[i, (i+1):n] * x[(i+1):n])) / aug[i, i]
        }
    }
    
    return(x)  # Just return the solution
}

# Test it
A <- matrix(c(2, 1, 0, 0, 0,
               1, 2, 1, 0, 0,
               0, 1, 2, 1, 0,
               0, 0, 1, 2, 1,
               0, 0, 0, 1, 2), 
             nrow = 5, byrow = TRUE)
b <- c(3, 5, 6, 7, 5)
solution <- gaussian_solver_simple(A, b)
print(solution)
LS0tDQp0aXRsZTogIlIgcHJhY3RpY2UiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KYGBge3B9DQoiIiINCiUlIGlzIG1vZHVsdXMgb3BlcmF0b3INCnNpbmsoKQ0KbGV0dGVyc1sxOjVdICAgICAgICAgICAgIyAiYSIgImIiICJjIiAiZCIgImUiDQpMRVRURVJTWzM6OF0gICMgIkMiICJEIiAiRSIgIkYiICJHIiAiSCINCmRpYWcoMTo1KSAgICAgICAgICAgIyBEaWFnb25hbCBtYXRyaXggd2l0aCAxOjUgb24gZGlhZ29uYWwNCm1hdHJpeChOQSwgNSwgNCkgICAgIyBFbXB0eSBtYXRyaXggKGFsbCBOQSkNCm1hdFsxOjMsIGMoMiwgNCldICAjIFJvd3MgMS0zLCBjb2x1bW5zIDIgYW5kIDQNCm1hdFsxOjMsIDNdIDwtIGMoMTMsIDE5LCAzMSkgICMgUmVwbGFjZSBwYXJ0IG9mIGNvbHVtbg0KVSAqIFYgICAgICAgICAgICAgICMgRWxlbWVudC13aXNlIG11bHRpcGxpY2F0aW9uDQpVW1UgPCA1IHwgVSA+IDE3XSA8LSAwICAjIFJlcGxhY2UgdmFsdWVzIG1lZXRpbmcgY29uZGl0aW9uDQpjYmluZChBMSwgQTIpICAgICAgIyBDb21iaW5lIGNvbHVtbnMgKHNpZGUgYnkgc2lkZSkNCnJiaW5kKEExLCBCKSAgICAgICAjIENvbWJpbmUgcm93cyAoc3RhY2sgdmVydGljYWxseSkNCnNhcHBseSgpICAgICMgQXBwbHkgdG8gYWxsIGVsZW1lbnRzDQoiIiINCmBgYA0KIyBJbnRyb2R1Y3Rpb24gdG8gUiAmIFJTdHVkaW8NCg0K8J+TjCBLZXkgUG9pbnRzOg0KUiBpcyBhIHN0YXRpc3RpY2FsIHByb2dyYW1taW5nIGxhbmd1YWdlLCBvcGVuLXNvdXJjZSBhbmQgZnJlZS4NCg0KUlN0dWRpbyBpcyBhbiBJREUgKEludGVncmF0ZWQgRGV2ZWxvcG1lbnQgRW52aXJvbm1lbnQpIHRoYXQgbWFrZXMgY29kaW5nIGluIFIgZWFzaWVyLg0KDQpSIG11c3QgYmUgaW5zdGFsbGVkIGJlZm9yZSBSU3R1ZGlvLg0KDQpDUkFOIGlzIHRoZSBvZmZpY2lhbCByZXBvc2l0b3J5IGZvciBSIHBhY2thZ2VzLg0KDQpSdG9vbHMgaXMgbmVlZGVkIGZvciBjb21waWxpbmcgcGFja2FnZXMgd2l0aCBDL0MrKy9Gb3J0cmFuIGNvZGUgb24gV2luZG93cy4NCg0KDQrinZMgQ29uY2VwdCBDaGVjazoNCldoYXQgaXMgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiBSIGFuZCBSU3R1ZGlvPw0KDQpXaHkgaXMgUiBjb25zaWRlcmVkICJvcGVuLXNvdXJjZSI/DQoNCldoZW4gZG8geW91IG5lZWQgUnRvb2xzPw0KDQoNCiMgSW1wb3J0YW50IENvbW1hbmRzOg0KYGBge3J9DQojIENoZWNrIFIgdmVyc2lvbg0KdmVyc2lvbg0KUi52ZXJzaW9uLnN0cmluZw0KIyBDaGVjayB3b3JraW5nIGRpcmVjdG9yeQ0KZ2V0d2QoKQ0KIyBTZXQgd29ya2luZyBkaXJlY3RvcnkNCnNldHdkKCJDOlxcVXNlcnNcXERlbGxcXE9uZURyaXZlXFxEZXNrdG9wXFxTVEFUSVNUSUNTXFwybmQgWWVhclxcUiBwcm9ncmFtbWluZ1xcSW5jb3Vyc2UgcHJlcCIpDQpgYGANCg0KDQpgYGB7cn0NCiMgRXhlY3V0ZSBhIHNjcmlwdCBmaWxlIG5hbWVkICJteV9zY3JpcHQuUiINCnNvdXJjZSgiMzAgTm92LlIiKQ0KYGBgDQojIFZlY3RvcnMsIE1hdHJpY2VzICYgTGluZWFyIEFsZ2VicmENCmBgYHtyfQ0KIyBTdGFydCBkaXZlcnRpbmcgb3V0cHV0IHRvIGEgZmlsZSBuYW1lZCAib3V0cHV0LnR4dCINCnNpbmsoIm91dHB1dC50eHQiKQ0KIyBBbnkgb3V0cHV0IGJlbG93IHdpbGwgYmUgd3JpdHRlbiB0byAib3V0cHV0LnR4dCIgaW5zdGVhZCBvZiB0aGUgY29uc29sZQ0KcHJpbnQoIlRoaXMgd2lsbCBiZSB3cml0dGVuIHRvIHRoZSBmaWxlIikNCnN1bW1hcnkoYygxLCAzLCA1LCA3LCA5KSkNCiMgU3RvcCBkaXZlcnRpbmcgb3V0cHV0IGFuZCByZXR1cm4gdG8gdGhlIGNvbnNvbGUNCnNpbmsoKQ0KYGBgDQoNClZlY3RvcnMgYXJlIG9yZGVyZWQgY29sbGVjdGlvbnMgb2YgdGhlIHNhbWUgdHlwZS4NCg0KQ3JlYXRlZCB3aXRoIGMoKSwgc2VxKCksIHJlcCgpLCA6DQoNCk1hdHJpY2VzIGFyZSAyRCBhcnJheXMgb2YgdGhlIHNhbWUgdHlwZS4NCg0KQ3JlYXRlZCB3aXRoIG1hdHJpeCgpLg0KDQpVc2UgJSolIGZvciBtYXRyaXggbXVsdGlwbGljYXRpb24gKG5vdCAqKS4NCg0KSW1wb3J0YW50IGZ1bmN0aW9uczogDQp0KCksIA0Kc29sdmUoKSwgDQpkZXQoKSwgDQplaWdlbigpLCANCm1hdHJpeCgpLCANCmRpbSgpLCANCnJiaW5kKCksIA0KY2JpbmQoKSwgDQpkaWFnKCkNCg0KIyBEYXRhIEZyYW1lcyAmIExpc3RzDQoNCkRhdGEgZnJhbWVzIGFyZSB0YWJsZXMgd2l0aCBjb2x1bW5zIG9mIGRpZmZlcmVudCB0eXBlcy4NCg0KTGlzdHMgY2FuIGhvbGQgZGlmZmVyZW50IHR5cGVzIG9mIG9iamVjdHMuDQoNCmRhdGEuZnJhbWUoKQ0KbGlzdCgpDQpyZWFkLmNzdigpLCB3cml0ZS5jc3YoKQ0KcmVhZC54bHN4KCksIHdyaXRlLnhsc3goKQ0KaGVhZCgpLCBzdW1tYXJ5KCkJPT09IFZpZXcgZGF0YQ0KbGFwcGx5KCksIHNhcHBseSgpID09PQlBcHBseSBmdW5jdGlvbnMgdG8gbGlzdHMNCg0KYGBge3J9DQojIERhdGEgZnJhbWUNCmRmIDwtIGRhdGEuZnJhbWUoDQogIE5hbWUgPSBjKCJBbGljZSIsICJCb2IiKSwNCiAgQWdlID0gYygyNSwgMzApLA0KICBTY29yZSA9IGMoODUsIDkwKQ0KKQ0KDQojIFdyaXRlIHRvIENTVg0Kd3JpdGUuY3N2KGRmLCAiZGF0YS5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkgICAjIE5ldyBjc3YgZmlsZSBjcmVhdGVkICYgc3RvcmVkIHRoZSBkYXRhLiANCg0KIyBMaXN0DQpteV9saXN0IDwtIGxpc3QoDQogIHZlYyA9IDE6NSwNCiAgbWF0ID0gbWF0cml4KDE6NCwgbnJvdyA9IDIpLA0KICBkZiA9IGRmDQopDQoNCm15X2xpc3QNCmBgYA0KIyBQcm9ibGVtIDE6IFN0dWRlbnQgTWFya3MgU2ltdWxhdGlvbiAoRnJvbSBBc3NpZ25tZW50IDEpDQoNCiMjIFNpbXVsYXRpbmcgYW5kIEFuYWx5emluZyBTdHVkZW50IEV4YW0gU2NvcmVzIGluIFINCg0KSW4gdGhpcyBhc3NpZ25tZW50LCB5b3Ugd2lsbCBzaW11bGF0ZSBleGFtIHNjb3JlcyBmb3IgYSBjbGFzcyBhbmQgYW5hbHl6ZSBhIHJhbmRvbSBzYW1wbGUgb2Ygc3R1ZGVudHMgdXNpbmcgKipSKiouDQoNCiMjIEZpbmFsIERlbGl2ZXJhYmxlcw0KU3VibWl0IHRoZSBmb2xsb3dpbmc6DQogIA0KKipBLioqIFIgY29kZSAoc2VwYXJhdGVseSB3cml0dGVuKSBmb3IgKipRdWVzdGlvbnMgMeKAkzcqKiAgDQoqKkIuKiogVGhlIGRhdGEgZnJhbWUgKipgU2FtcGxlRGF0YS5kZmAqKiBzaG93aW5nIHRoZSBJRHMgYW5kIG1hcmtzIG9mIHRoZSAxMCBzZWxlY3RlZCBzdHVkZW50cyAgDQoqKkMuKiogVGhlIG51bWVyaWNhbCByZXN1bHRzIGZyb20gKipUYXNrIDcqKiwgY2xlYXJseSBmb3JtYXR0ZWQgKGVpdGhlciBwcmludGVkIG5lYXRseSBvciBzaG93biBpbiBhIGRhdGEgZnJhbWUpDQoNCi0tLQ0KDQojIyBDbGFzcyBJbmZvcm1hdGlvbg0KLSBUb3RhbCBudW1iZXIgb2Ygc3R1ZGVudHM6ICoqOTEqKg0KLSBTdHVkZW50IElEczogKiowMDEgdG8gMDkxKioNCg0KLS0tDQoNCiMjIFRhc2sgMTogU2ltdWxhdGUgRXhhbSBNYXJrcw0KMS4gR2VuZXJhdGUgZXhhbSBtYXJrcyBmb3IgYWxsIDkxIHN0dWRlbnRzIHVzaW5nIGEgKipub3JtYWwgZGlzdHJpYnV0aW9uKio6DQogICAtIE1lYW4gPSAqKjc3KioNCiAgIC0gU3RhbmRhcmQgRGV2aWF0aW9uID0gKioxKioNCjIuIFVzZSB0aGUgZnVuY3Rpb24gYHJub3JtKClgIHRvIGdlbmVyYXRlIHRoZSBtYXJrcy4NCjMuIFN0b3JlIHRoZSBnZW5lcmF0ZWQgbWFya3MgaW4gYSB2ZWN0b3IgbmFtZWQgKipgTWFya3NgKiouDQo0LiBTZXQgdGhlIHJhbmRvbSBzZWVkIHVzaW5nIGBzZXQuc2VlZCgyMDkpYCB0byBtYWtlIHRoZSByZXN1bHRzIHJlcHJvZHVjaWJsZS4NCjUuIENyZWF0ZSBhIHZlY3RvciAqKmBJRGAqKiBjb250YWluaW5nIHN0dWRlbnQgSURzIGFzIGludGVnZXJzIGZyb20gKioxIHRvIDkxKiouDQpgYGB7cn0NCnNldC5zZWVkKDIwOSkNCklEIDwtIDE6OTENCk1hcmtzIDwtIHJub3JtKDkxLCBtZWFuID0gNzcsIHNkID0gMSkNCmBgYA0KIyMgVGFzayAyOiBSYW5kb21seSBTZWxlY3QgMTAgU3R1ZGVudHMNCjEuIFJhbmRvbWx5IHNlbGVjdCAqKjEwIHN0dWRlbnRzKiogZnJvbSB0aGUgY2xhc3MgKip3aXRob3V0IHJlcGxhY2VtZW50KiouDQoyLiBVc2UgdGhlIGZ1bmN0aW9uIGBzYW1wbGUoKWAgdG8gc2VsZWN0IHRoZSBzdHVkZW50IElEcy4NCjMuIFNldCB0aGUgcmFuZG9tIHNlZWQgdXNpbmcgYHNldC5zZWVkKDIpYCBiZWZvcmUgc2FtcGxpbmcuDQo0LiBFeHRyYWN0IHRoZSBleGFtIG1hcmtzIGNvcnJlc3BvbmRpbmcgdG8gdGhlIHNlbGVjdGVkIHN0dWRlbnQgSURzLg0KYGBge3J9DQpzZXQuc2VlZCgyKQ0Kc2FtcGxlX2lkIDwtIHNhbXBsZShJRCwgMTAsIHJlcGxhY2UgPSBGQUxTRSkNCnNhbXBsZV9tYXJrcyA8LSBNYXJrc1tzYW1wbGVfaWRdDQpgYGANCg0KIyMgVGFzayAzOiBTb3J0IHRoZSBTYW1wbGUNCjEuIFNvcnQgdGhlIHNlbGVjdGVkIHN0dWRlbnQgSURzIGluICoqYXNjZW5kaW5nIG9yZGVyKiouDQoyLiBSZWFycmFuZ2UgdGhlIGNvcnJlc3BvbmRpbmcgbWFya3Mgc28gdGhleSBtYXRjaCB0aGUgc29ydGVkIElEcy4NCg0KIyMgVGFzayA0OiBDcmVhdGUgYSBEYXRhIEZyYW1lDQpDcmVhdGUgYSBkYXRhIGZyYW1lIG5hbWVkICoqYFNhbXBsZURhdGEuZGZgKiogd2l0aCB0aGUgZm9sbG93aW5nIGNvbHVtbnM6DQotICoqSUQqKjogU29ydGVkIHNhbXBsZWQgc3R1ZGVudCBJRHMgIA0KLSAqKk1hcmtzKio6IENvcnJlc3BvbmRpbmcgZXhhbSBtYXJrcyAocm91bmRlZCB0byAqKjIgZGVjaW1hbCBwbGFjZXMqKikNCmBgYHtyfQ0Kb3JkIDwtIG9yZGVyKHNhbXBsZV9pZCkNCg0KU2FtcGxlRGF0YS5kZiA8LSBkYXRhLmZyYW1lKA0KICBJRCA9IHNhbXBsZV9pZFtvcmRdLA0KICBNYXJrcyA9IHJvdW5kKHNhbXBsZV9tYXJrc1tvcmRdLCAyKQ0KKQ0KDQpgYGANCiMjIFRhc2sgNTogU2F2ZSB0aGUgRGF0YSBGcmFtZQ0KICBTYXZlIGBTYW1wbGVEYXRhLmRmYCBpbiB0d28gZm9ybWF0czoNCiAgDQojIyMgRmlsZXMgdG8gU2F2ZQ0KLSAqKkV4Y2VsIGZpbGUqKjogYCJTYW1wbGVfTWFya3MueGxzeCJgICANCi0gVXNlIGBvcGVueGxzeDo6d3JpdGUueGxzeCgpYA0KLSAqKkNTViBmaWxlKio6IGAiU2FtcGxlRGF0YUdQQS5jc3YiYCAgDQotIFVzZSB0aGUgYmFzZSBSIGZ1bmN0aW9uIGB3cml0ZS5jc3YoKWANCg0KIyMjIEluc3RydWN0aW9ucw0KMS4gQ3JlYXRlIGEgbmV3IGZvbGRlciBvbiB5b3VyICoqRGVza3RvcCoqIG5hbWVkOiAgDQogICoqYFlvdXJGaXJzdE5hbWUxMjNgKiogIA0KICAtIFJlcGxhY2UgYFlvdXJGaXJzdE5hbWVgIHdpdGggeW91ciBhY3R1YWwgZmlyc3QgbmFtZSAgDQotIFJlcGxhY2UgYDEyM2Agd2l0aCB0aGUgbGFzdCB0aHJlZSBkaWdpdHMgb2YgeW91ciBjbGFzcyByb2xsIG51bWJlcg0KMi4gU2V0IHRoaXMgZm9sZGVyIGFzIHlvdXIgd29ya2luZyBkaXJlY3RvcnkgdXNpbmcgYHNldHdkKClgIGJlZm9yZSBzYXZpbmcgdGhlIGZpbGVzLg0KYGBge3J9DQpzZXR3ZCgiQzpcXFVzZXJzXFxEZWxsXFxPbmVEcml2ZVxcRGVza3RvcFxcU1RBVElTVElDU1xcMm5kIFllYXJcXFIgcHJvZ3JhbW1pbmdcXEluY291cnNlIHByZXAiKQ0KDQpvcGVueGxzeDo6d3JpdGUueGxzeChTYW1wbGVEYXRhLmRmLCAiU2FtcGxlX01hcmtzLnhsc3giKQ0Kd3JpdGUuY3N2KFNhbXBsZURhdGEuZGYsICJTYW1wbGVEYXRhR1BBLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQ0KDQpgYGANCiMjIFRhc2sgNjogUmVhZCB0aGUgRmlsZXMgQmFjayBpbnRvIFINCiAgMS4gUmVhZCB0aGUgRXhjZWwgZmlsZSB1c2luZyBgb3Blbnhsc3g6OnJlYWQueGxzeCgpYCBhbmQgc3RvcmUgaXQgaW46DQogIC0gKipgU2FtcGxlRGF0YV9mcm9tX2V4Y2VsYCoqDQogIDIuIFJlYWQgdGhlIENTViBmaWxlIHVzaW5nIGByZWFkLmNzdigpYCBhbmQgc3RvcmUgaXQgaW46DQogIC0gKipgU2FtcGxlRGF0YV9mcm9tX2NzdmAqKg0KICAzLiBEaXNwbGF5IHRoZSBmaXJzdCBmZXcgcm93cyBvZiBib3RoIGRhdGEgZnJhbWVzIHVzaW5nIHRoZSBgaGVhZCgpYCBmdW5jdGlvbi4NCmBgYHtyfQ0KU2FtcGxlRGF0YV9mcm9tX2V4Y2VsIDwtIG9wZW54bHN4OjpyZWFkLnhsc3goIlNhbXBsZV9NYXJrcy54bHN4IikNClNhbXBsZURhdGFfZnJvbV9jc3YgPC0gcmVhZC5jc3YoIlNhbXBsZURhdGFHUEEuY3N2IikNCg0KaGVhZChTYW1wbGVEYXRhX2Zyb21fZXhjZWwpDQpoZWFkKFNhbXBsZURhdGFfZnJvbV9jc3YpDQoNCmBgYA0KIyMgVGFzayA3OiBTdGF0aXN0aWNhbCBBbmFseXNpcyAoVXNpbmcgdGhlIDEwIFNhbXBsZWQgTWFya3MpDQpDYWxjdWxhdGUgdGhlIGZvbGxvd2luZyBzdGF0aXN0aWNzOg0KMS4gTWVhbiAgDQoyLiBTdGFuZGFyZCBEZXZpYXRpb24gIA0KMy4gU3RhbmRhcmQgRXJyb3IgIA0KNC4gMm5kIENlbnRyYWwgTW9tZW50ICANCjUuIDR0aCBDZW50cmFsIE1vbWVudCAgDQo2LiBTa2V3bmVzcyAgDQo3LiBLdXJ0b3NpcyAgDQpgYGB7cn0NCnggPC0gU2FtcGxlRGF0YS5kZiRNYXJrcw0KbiA8LSBsZW5ndGgoeCkNCnhfYmFyIDwtIG1lYW4oeCkNCg0KcmVzdWx0cyA8LSBkYXRhLmZyYW1lKA0KICBNZWFuID0gbWVhbih4KSwNCiAgU0QgPSBzZCh4KSwNCiAgU0UgPSBzZCh4KS9zcXJ0KG4pLA0KICBDZW50cmFsX01vbWVudF8yID0gbWVhbigoeCAtIHhfYmFyKV4yKSwNCiAgQ2VudHJhbF9Nb21lbnRfNCA9IG1lYW4oKHggLSB4X2JhcileNCksDQogIFNrZXduZXNzID0gbWVhbigoeCAtIHhfYmFyKV4zKS8oc2QoeCleMyksDQogIEt1cnRvc2lzID0gbWVhbigoeCAtIHhfYmFyKV40KS8oc2QoeCleNCkNCikNCg0KcmVzdWx0cw0KYGBgDQojIFByb2JsZW0gMjogTWF0cml4IE9wZXJhdGlvbnMNCmBgYHtyfQ0KIyBDcmVhdGUgbWF0cmljZXMNCkEgPC0gbWF0cml4KDE6NCwgbnJvdyA9IDIpDQpBDQpCIDwtIG1hdHJpeChjKDIsIDAsIDEsIDMpLCBucm93ID0gMikNCkINCiMgQ29tcHV0ZTogQcKyICsgMkINCnJlc3VsdCA8LSBBICUqJSBBICsgMiAqIEINCnJlc3VsdA0KDQojIENoZWNrIGlmIGludmVydGlibGUNCmlmKGRldChyZXN1bHQpICE9IDApIHsNCiAgaW52X3Jlc3VsdCA8LSBzb2x2ZShyZXN1bHQpDQogIGludl9yZXN1bHQNCn0NCg0KYGBgDQojIElNUE9SVEFOVCBFWEFNIFBST0JMRU0gUEFUVEVSTjoNCmBgYHtyfQ0KIyBUYXNrIGZyb20gbGVjdHVyZTogRmlsbCBldmVuIHJvd3Mgd2l0aCBldmVuIG51bWJlcnMNCkEgPC0gbWF0cml4KE5BLCA1LCA0KQ0KZXZlbl9udW1iZXJzIDwtIHNlcSgyLCAyMCwgYnkgPSAyKQ0KayA8LSAxDQoNCmZvciAoaSBpbiAxOm5yb3coQSkpIHsNCiAgICBpZiAoaSAlJSAyID09IDApIHsgICMgRXZlbiByb3dzDQogICAgICAgIGZvciAoaiBpbiAxOm5jb2woQSkpIHsNCiAgICAgICAgICAgIEFbaSwgal0gPC0gZXZlbl9udW1iZXJzW2tdDQogICAgICAgICAgICBrIDwtIGsgKyAxDQogICAgICAgIH0NCiAgICB9DQp9DQpBDQpgYGANCkVpZ2VudmFsdWVzIGFuZCBFaWdlbnZlY3RvcnM6DQoNCkZvciBtYXRyaXggQSwgaWYgQXYgPSDOu3YsIHRoZW46DQrOuyA9IGVpZ2VudmFsdWUgKHNjYWxhcikNCnYgPSBlaWdlbnZlY3RvciAodmVjdG9yKQ0KDQpgYGB7cn0NCk0gPC0gbWF0cml4KGMoMiwgMSwgMSwgMiksIG5yb3cgPSAyKQ0KZWlnZW5fcmVzdWx0IDwtIGVpZ2VuKE0pDQoNCmVpZ2VuX3Jlc3VsdCR2YWx1ZXMgICAgIyBFaWdlbnZhbHVlcw0KZWlnZW5fcmVzdWx0JHZlY3RvcnMgICAjIEVpZ2VudmVjdG9ycw0KYGBgDQoNCiMgTWF0cml4IE9wZXJhdGlvbnMgVGFzaw0KDQojIyMgUHJvYmxlbSBTdGF0ZW1lbnQNCg0KMS4gKipDcmVhdGUgYSBWZWN0b3I6KioNClNldCB0aGUgc2VlZCB1c2luZyB0aGUgbGFzdCAzIGRpZ2l0cyBvZiB5b3VyIHJvbGwgbnVtYmVyIChlLmcuLCAyNDUpLiBHZW5lcmF0ZSBhIHZlY3RvciBgdmAgY29udGFpbmluZyA4IHJhbmRvbSBpbnRlZ2VycyBiZXR3ZWVuIDEgYW5kIDE1LCBzZWxlY3RlZCB3aXRob3V0IHJlcGxhY2VtZW50Lg0KMi4gKipDb25zdHJ1Y3QgTWF0cmljZXM6KioNClVzaW5nIHZlY3RvciBgdmAsIGNyZWF0ZSB0aGUgZm9sbG93aW5nIGZvdXIgbWF0cmljZXM6DQoqICoqQTE6KiogIG1hdHJpeCwgZmlsbGVkIHJvdy13aXNlLg0KKiAqKkIxOioqICBtYXRyaXgsIGZpbGxlZCByb3ctd2lzZS4NCiogKipBMjoqKiAgbWF0cml4LCBmaWxsZWQgY29sdW1uLXdpc2UuDQoqICoqQjI6KiogIG1hdHJpeCwgZmlsbGVkIGNvbHVtbi13aXNlLg0KDQoNCjMuICoqVmVyaWZ5IFRyYW5zcG9zZToqKg0KRmluZCB0aGUgdHJhbnNwb3NlIG9mICoqQTEqKi4gQ2hlY2sgaWYgaXQgaXMgaWRlbnRpY2FsIHRvICoqQjEqKiwgKipBMioqLCBvciAqKkIyKiouDQo0LiAqKk1hdHJpeCBNdWx0aXBsaWNhdGlvbjoqKg0KQ2FsY3VsYXRlIHRoZSBwcm9kdWN0IG9mICoqQTEqKiBhbmQgKipCMSoqLiBJcyB0aGUgcmVzdWx0aW5nIG1hdHJpeCBzcXVhcmU/IElzIGl0IGludmVydGlibGU/DQoNCmBgYHtyfQ0KIyAxLiBDcmVhdGUgdmVjdG9yIHYNCnNldC5zZWVkKDI0NSkgICMgVXNpbmcgbGFzdCAzIGRpZ2l0cyBvZiByb2xsIG51bWJlcg0KdiA8LSBzYW1wbGUoMToxNSwgOCwgcmVwbGFjZSA9IEZBTFNFKQ0KDQojIDIuIENyZWF0ZSBtYXRyaWNlcw0KQTEgPC0gbWF0cml4KHYsIG5yb3cgPSAyLCBuY29sID0gNCwgYnlyb3cgPSBUUlVFKSAgICMgMng0LCByb3ctd2lzZQ0KQjEgPC0gbWF0cml4KHYsIG5yb3cgPSA0LCBuY29sID0gMiwgYnlyb3cgPSBUUlVFKSAgICMgNHgyLCByb3ctd2lzZQ0KQTIgPC0gbWF0cml4KHYsIG5yb3cgPSAyLCBuY29sID0gNCkgICAgICAgICAgICAgICAgICAjIDJ4NCwgY29sdW1uLXdpc2UNCkIyIDwtIG1hdHJpeCh2LCBucm93ID0gNCwgbmNvbCA9IDIpICAgICAgICAgICAgICAgICAgIyA0eDIsIGNvbHVtbi13aXNlDQoNCiMgMy4gQ2hlY2sgdHJhbnNwb3NpdGlvbg0KdEExIDwtIHQoQTEpDQppZGVudGljYWwodEExLCBCMSkgICMgRkFMU0UNCmlkZW50aWNhbCh0QTEsIEEyKSAgIyBGQUxTRQ0KaWRlbnRpY2FsKHRBMSwgQjIpICAjIEZBTFNFDQoNCiMgNC4gTWF0cml4IG11bHRpcGxpY2F0aW9uDQpyZXN1bHQgPC0gQTEgJSolIEIxDQppc19zcXVhcmUgPC0gbnJvdyhyZXN1bHQpID09IG5jb2wocmVzdWx0KQ0KaXNfaW52ZXJ0aWJsZSA8LSBpZihpc19zcXVhcmUpIGRldChyZXN1bHQpICE9IDAgZWxzZSBGQUxTRQ0KYGBgDQojIyBRdWVzdGlvbg0KDQpXcml0ZSBhbiBSIGZ1bmN0aW9uIG5hbWVkIGBnYXVzc2lhbl9zb2x2ZXIoKWAgdGhhdCBzb2x2ZXMgYSBzeXN0ZW0gb2YgbGluZWFyIGVxdWF0aW9ucyB1c2luZyAqKkdhdXNzaWFuIEVsaW1pbmF0aW9uIHdpdGggcGFydGlhbCBwaXZvdGluZyoqLg0KDQpUaGUgZnVuY3Rpb24gc2hvdWxkIG1lZXQgdGhlIGZvbGxvd2luZyByZXF1aXJlbWVudHM6DQoNCjEuIFRoZSBmdW5jdGlvbiBtdXN0IHRha2UgdHdvIGlucHV0czoNCiAgIC0gYEFgOiBhIHNxdWFyZSBjb2VmZmljaWVudCBtYXRyaXggb2Ygb3JkZXIgXCggbiBcdGltZXMgbiBcKQ0KICAgLSBgYmA6IGEgY29sdW1uIHZlY3RvciBvZiBjb25zdGFudHMgb2YgbGVuZ3RoIFwoIG4gXCkNCg0KMi4gSW5zaWRlIHRoZSBmdW5jdGlvbjoNCiAgIC0gQ3JlYXRlIGFuICoqYXVnbWVudGVkIG1hdHJpeCoqIGJ5IGNvbWJpbmluZyBgQWAgYW5kIGBiYA0KICAgLSBQZXJmb3JtICoqZm9yd2FyZCBlbGltaW5hdGlvbioqIHRvIGNvbnZlcnQgdGhlIGF1Z21lbnRlZCBtYXRyaXggaW50byBhbiB1cHBlciB0cmlhbmd1bGFyIGZvcm0NCiAgIC0gVXNlICoqcGFydGlhbCBwaXZvdGluZyoqIGF0IGVhY2ggc3RlcCB0byBpbXByb3ZlIG51bWVyaWNhbCBzdGFiaWxpdHkNCiAgIC0gUGVyZm9ybSAqKmJhY2sgc3Vic3RpdHV0aW9uKiogdG8gY29tcHV0ZSB0aGUgc29sdXRpb24gdmVjdG9yDQoNCjMuIFN0b3JlIHRoZSBzb2x1dGlvbiBpbiBhIG51bWVyaWMgdmVjdG9yIGB4YDoNCiAgIC0gQXNzaWduIG5hbWVzIHRvIHRoZSBzb2x1dGlvbiB2YXJpYWJsZXMgYXMgYHgxLCB4MiwgLi4uLCB4bmANCg0KNC4gVGhlIGZ1bmN0aW9uIHNob3VsZCByZXR1cm4gdGhlIHJlc3VsdCBhcyBhICoqbGlzdCoqIGNvbnRhaW5pbmc6DQogICAtIGBzb2x1dGlvbmA6IHRoZSB2ZWN0b3Igb2Ygc29sdmVkIHZhbHVlcw0KDQpZb3VyIGZ1bmN0aW9uIHNob3VsZCB3b3JrIGZvciBhbnkgdmFsaWQgc3lzdGVtIG9mIGxpbmVhciBlcXVhdGlvbnMgd2hlcmUgYSB1bmlxdWUgc29sdXRpb24gZXhpc3RzLg0KYGBge3J9DQpnYXVzc2lhbl9zb2x2ZXJfc2ltcGxlIDwtIGZ1bmN0aW9uKEEsIGIpIHsNCiAgICBuIDwtIG5yb3coQSkNCiAgICBhdWcgPC0gY2JpbmQoQSwgYikNCiAgICANCiAgICAjIEZvcndhcmQgZWxpbWluYXRpb24NCiAgICBmb3IgKGkgaW4gMToobi0xKSkgew0KICAgICAgICAjIEZpbmQgcGl2b3Qgcm93DQogICAgICAgIG1heF9yb3cgPC0gd2hpY2gubWF4KGFicyhhdWdbaTpuLCBpXSkpICsgaSAtIDENCiAgICAgICAgaWYgKG1heF9yb3cgIT0gaSkgew0KICAgICAgICAgICAgYXVnW2MoaSwgbWF4X3JvdyksIF0gPC0gYXVnW2MobWF4X3JvdywgaSksIF0NCiAgICAgICAgfQ0KICAgICAgICANCiAgICAgICAgIyBFbGltaW5hdGUgYmVsb3cNCiAgICAgICAgZm9yIChqIGluIChpKzEpOm4pIHsNCiAgICAgICAgICAgIGZhY3RvciA8LSBhdWdbaiwgaV0gLyBhdWdbaSwgaV0NCiAgICAgICAgICAgIGF1Z1tqLCBdIDwtIGF1Z1tqLCBdIC0gZmFjdG9yICogYXVnW2ksIF0NCiAgICAgICAgfQ0KICAgIH0NCiAgICANCiAgICAjIEJhY2sgc3Vic3RpdHV0aW9uDQogICAgeCA8LSBudW1lcmljKG4pDQogICAgZm9yIChpIGluIG46MSkgew0KICAgICAgICBpZiAoaSA9PSBuKSB7DQogICAgICAgICAgICB4W2ldIDwtIGF1Z1tpLCBuKzFdIC8gYXVnW2ksIGldDQogICAgICAgIH0gZWxzZSB7DQogICAgICAgICAgICB4W2ldIDwtIChhdWdbaSwgbisxXSAtIHN1bShhdWdbaSwgKGkrMSk6bl0gKiB4WyhpKzEpOm5dKSkgLyBhdWdbaSwgaV0NCiAgICAgICAgfQ0KICAgIH0NCiAgICANCiAgICByZXR1cm4oeCkgICMgSnVzdCByZXR1cm4gdGhlIHNvbHV0aW9uDQp9DQoNCiMgVGVzdCBpdA0KQSA8LSBtYXRyaXgoYygyLCAxLCAwLCAwLCAwLA0KICAgICAgICAgICAgICAgMSwgMiwgMSwgMCwgMCwNCiAgICAgICAgICAgICAgIDAsIDEsIDIsIDEsIDAsDQogICAgICAgICAgICAgICAwLCAwLCAxLCAyLCAxLA0KICAgICAgICAgICAgICAgMCwgMCwgMCwgMSwgMiksIA0KICAgICAgICAgICAgIG5yb3cgPSA1LCBieXJvdyA9IFRSVUUpDQpiIDwtIGMoMywgNSwgNiwgNywgNSkNCnNvbHV0aW9uIDwtIGdhdXNzaWFuX3NvbHZlcl9zaW1wbGUoQSwgYikNCnByaW50KHNvbHV0aW9uKQ0KYGBgDQoNCg0KDQoNCg==