"""
%% 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)
Task 1: Simulate Exam Marks
- Generate exam marks for all 91 students using a normal
distribution:
- Mean = 77
- Standard Deviation = 1
- Use the function
rnorm() to generate the marks.
- Store the generated marks in a vector named
Marks.
- Set the random seed using
set.seed(209) to make the
results reproducible.
- 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
- Randomly select 10 students from the class
without replacement.
- Use the function
sample() to select the student
IDs.
- Set the random seed using
set.seed(2) before
sampling.
- 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
- Sort the selected student IDs in ascending
order.
- 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
- 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
- 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
- Read the Excel file using
openxlsx::read.xlsx() and
store it in:
- Read the CSV file using
read.csv() and store it
in:
- 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
- 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.
- 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.
- Verify Transpose: Find the transpose of
A1. Check if it is identical to B1,
A2, or B2.
- 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:
- 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\)
- 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
- Store the solution in a numeric vector
x:
- Assign names to the solution variables as
x1, x2, ..., xn
- 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==