Linear Equation Solve

1) Write a function to solve a system of 2 linear equations in 2 variables (2x2 system).

cat("The equations are:\n a1x + b1y = c1\n a2x + b2y = c2\n\n")
The equations are:
 a1x + b1y = c1
 a2x + b2y = c2
a1 <- as.numeric(readline(prompt = "a1 = "))
4
b1 <- as.numeric(readline(prompt = "b1 = "))
3
c1 <- as.numeric(readline(prompt = "c1 = "))
1

a2 <- as.numeric(readline(prompt = "a2 = "))
5
b2 <- as.numeric(readline(prompt = "b2 = "))
7
c2 <- as.numeric(readline(prompt = "c2 = "))
8


values <- c(a1,b1,c1,a2,b2,c2)
eqn_2by2_solver <- function(a1, b1, c1, a2, b2, c2){
  # Solving the system
  denominator <- (a1*b2 - a2*b1)
  
  if (denominator == 0) {
    cat("No unique solution exists.\n")
  } else {
    y <- (a1*c2 - a2*c1) / denominator
    x <- (c1 - b1*y) / a1
    cat(sprintf("Solution:\nx = %.4f \ny = %.4f\n", x, y))
  }
}
eqn_2by2_solver(a1,b1,c1,a2,b2,c2)
Solution:
x = -1.3077 
y = 2.0769
do.call(eqn_2by2_solver, as.list(values))
Solution:
x = -1.3077 
y = 2.0769

2) Write a function to solve a 3x3 system using Cramer’s rule.

cramer3by3 <- function(eqn1,eqn2,eqn3){
  D <- rbind(
    eqn1[1:3],
    eqn2[1:3],
    eqn3[1:3]
  )
  b <- c(eqn1[4],eqn2[4],eqn3[4])
  vars <- c("x","y","z")
  for (i in 1:3){
    E <- D
    E[,i] <- b
    cat(vars[i],"=",det(E)/det(D),"\n")
  }
  
}

eqn1 <- c(a1=2, b1=3, c1=-1, d1=8)
eqn2 <- c(a2=1, b2=-1, c2=4, d2=11)
eqn3 <- c(a3=3, b3=1, c3=2, d3=7)

cramer3by3(eqn1,eqn2,eqn3)
x = -3.428571 
y = 6.714286 
z = 5.285714 

3) Write a function to find the determinant of a 2x2 matrix.

det2by2 <- function(A){
  (A[1,1]*A[2,2])-(A[1,2]*A[2,1])
}
A <- matrix(c(2,9,4,5), nrow=2)
det2by2(A)
[1] -26

4) Write a function to find the determinant of a 3x3 matrix

det3by3 <- function(A){
  result <- A[1,1]*(A[2,2]*A[3,3]-A[3,2]*A[2,3])-A[1,2]*(A[2,1]*A[3,3]-A[3,1]*A[2,3])+A[1,3]*(A[2,1]*A[3,2]-A[3,1]*A[2,2])
  return(result)
}

A=matrix(c(1:8,11), nrow=3)
det3by3(A)
[1] -6
A
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6   11

5) Write a function to find the inverse of a 2x2 matrix using the determinant and adjugate.

inv2by2 <- function(A){
  det_A <- (A[1,1]*A[2,2]-A[2,1]*A[1,2])
  if (det_A!=0){
  inv_A <- matrix(c(A[2,2], -A[1,2], -A[2,1], A[1,1]), nrow=2)/det_A
  return(inv_A)
  }
  else{
    return("Inverse not possible")
  }
}

A <- matrix(c(1, 2, 2, 3), ncol = 2, byrow = TRUE)
inv2by2(A)
     [,1] [,2]
[1,]   -3    2
[2,]    2   -1

6) Write a function to solve a 2x2 system by finding the inverse matrix and multiplying.

solver2by2 <- function(A, b){
  sol <- inv2by2(A) %*% b
  cat("x = ",sol[1,],"\ny = ", sol[2,])
}

A <- matrix(c(2,3,4,-1), byrow=TRUE, nrow=2)

b <- matrix(c(8,2), nrow=2)
b
     [,1]
[1,]    8
[2,]    2
solver2by2(A,b)
x =  1.142857 
y =  1.428571

7) Write a function to check if a 2x2 system has a unique solution, no solution, or infinitely many solutions.

For the system
a₁x + b₁y = c₁
a₂x + b₂y = c₂

Compute
D = a₁b₂ − a₂b₁

• If D ≠ 0 → unique solution
• If D = 0 and a₁/a₂ = b₁/b₂ = c₁/c₂ → infinitely many solutions
• If D = 0 and a₁/a₂ = b₁/b₂ ≠ c₁/c₂ → no solution

sol_type_2by2 <- function(A,b){
  D <- A[1,1]*A[2,2]-A[2,1]*A[1,2]
  if (D!=0){
    return ("Unique")
  }
  else{
    if (A[1,1]/A[2,1]==A[1,2]*A[2,2] & b[1,]/b[2,]==A[1,1]/A[2,1]){
      return("Infinitely many")
    } else{
      return("No Solution")
    }
  }
}

A <- matrix(c(2,3,4,-1), byrow=TRUE, nrow=2)
b <- matrix(c(8,2), nrow=2)
sol_type_2by2(A,b)
[1] "Unique"

8) Check the nature of roots of a quadratic equation

quadric_root_nature <- function(a,b,c){
  D <- b^2 - 4*a*c 
    if (D > 0) {
    cat("Two distinct real roots")
  } else if (D == 0) {
    cat("Two equal real roots")
  } else {
    cat("No real roots")
  }
}

a <- 1
b <- -3
c <- 2

quadric_root_nature(a,b,c)
Two distinct real roots

9) Write a function to check if a 3x3 system has a unique solution (by checking determinant).

sol_type_3by3 <- function(A,b){
  if (det(A)!=0){
    cat("Unique Solution")
  } else{
    cat("Infinitely many or No solution")
  }
}
sol_type_3by3(A,b)
Unique Solution

10) Write a function to find the trace of a square matrix (2x2, 3x3).

trace_finder <- function(A){
  if (nrow(A)==ncol(A)){
    t <- 0
    for (i in 1:nrow(A)){
      t <- t+A[i,i]
    }
    cat("Trace:",t)
  }
  else {
    cat("Give Square Matrix")
  }
}

A <- matrix(1:9, nrow = 3, ncol = 3)
trace_finder(A)
Trace: 15

matrix is singular when determinant = 0


Linear Algebra for Coders: Essential Concepts and Algorithms

1. Row Echelon Form (REF)

Definition

A matrix is in Row Echelon Form when:

  • All nonzero rows are above rows of all zeros
  • Each leading coefficient (pivot) of a row is in a column to the right of the leading coefficient of the row above it
  • All entries in a column below a leading coefficient are zeros

Example

[ 1  2  3  4 ]
[ 0  1  5  6 ]   ✓ REF
[ 0  0  0  1 ]
[ 0  1  2 ]      ✗ Not REF (zero row above non-zero)
[ 1  0  3 ]

Algorithm to achieve REF

row_echelon_form <- function(mat) {
  rows <- nrow(mat)
  cols <- ncol(mat)
  pivot_row <- 1
  
  for (col in 1:cols) {
    # Find pivot in current column
    pivot <- find_pivot(mat, pivot_row, col)
    if (is.null(pivot)) {
      next
    }
    
    # Swap pivot row with current row
    mat <- swap_rows(mat, pivot, pivot_row)
    
    # Make all entries below pivot zero
    for (row in (pivot_row + 1):rows) {
      factor <- mat[row, col] / mat[pivot_row, col]
      mat[row, ] <- mat[row, ] - factor * mat[pivot_row, ]
    }
    
    pivot_row <- pivot_row + 1
    if (pivot_row > rows) {
      break
    }
  }
  return(mat)
}

2. Forward Elimination

Purpose

Convert a system of linear equations to upper triangular form.

Process

  1. Start with first equation
  2. Use it to eliminate first variable from subsequent equations
  3. Move to next equation, repeat

Example System

2x +  y +  z =  8
4x + 3y + 2z = 18
-2x +  y +  z =  2

After Forward Elimination

2x +  y +  z = 8
0x +  y + 0z = 2  (Second equation minus 2×first)
0x + 2y + 2z = 10 (Third equation plus first)

3. Gaussian Elimination

Complete Algorithm

  1. Forward Elimination: Convert to upper triangular matrix
  2. Back Substitution: Solve from bottom to top

Implementation Steps

gaussian_elimination <- function(A, b) {
  n <- nrow(A)
  
  # Augment matrix [A|b]
  Ab <- cbind(A, b)
  
  # Forward elimination
  for (i in 1:n) {
    # Partial pivoting for stability
    max_row <- which.max(abs(Ab[i:n, i])) + i - 1
    if (i != max_row) {
      Ab[c(i, max_row), ] <- Ab[c(max_row, i), ]
    }
    
    # Eliminate below pivot
    for (j in (i + 1):n) {
      factor <- Ab[j, i] / Ab[i, i]
      Ab[j, ] <- Ab[j, ] - factor * Ab[i, ]
    }
  }
  
  # Back substitution
  x <- numeric(n)
  for (i in n:1) {
    x[i] <- Ab[i, n + 1] / Ab[i, i]
    for (j in (i - 1):1) {
      Ab[j, n + 1] <- Ab[j, n + 1] - Ab[j, i] * x[i]
    }
  }
  
  return(x)
}


4. Rank Check

Definition

The rank of a matrix is the maximum number of linearly independent rows (or columns).

Properties

  • rank(A) ≤ min(m, n) for m×n matrix
  • Full rank: rank = min(m, n)
  • Singular matrix: rank < n for n×n matrix

Algorithm to Compute Rank

matrix_rank <- function(mat, augmented = FALSE) {
  ref_mat <- row_echelon_form(mat)
  rank <- 0
  cols <- ifelse(augmented, ncol(ref_mat) - 1, ncol(ref_mat))
  
  for (i in 1:nrow(ref_mat)) {
    if (any(abs(ref_mat[i, 1:cols]) > 1e-10)) {
      rank <- rank + 1
    }
  }
  return(rank)
}

Significance

  • Unique solution: rank(A) = rank([A|b]) = n
  • Infinite solutions: rank(A) = rank([A|b]) < n
  • No solution: rank(A) < rank([A|b])

5. Augmented Matrix

Definition

Combines coefficient matrix A and constant vector b into [A|b]

Purpose

Allows simultaneous operations on both sides during elimination.

Example

System:

2x + 3y = 8
4x - y = 2

Augmented Matrix:

[ 2  3 | 8 ]
[ 4 -1 | 2 ]

Implementation

augment_matrix <- function(A, b) {
  cbind(A, b)
}

6. Solution Types for Linear Systems

6.1 Unique Solution

  • Condition: rank(A) = rank([A|b]) = n
  • Determinant: det(A) ≠ 0
  • Interpretation: System has exactly one solution
  • Example: Intersection of two non-parallel lines

6.2 Inconsistent System (No Solution)

  • Condition: rank(A) < rank([A|b])
  • Interpretation: Equations contradict each other
  • Example: Parallel lines that don’t intersect
x + y = 3
x + y = 5  # Contradiction!

6.3 Infinite Solutions

  • Condition: rank(A) = rank([A|b]) < n
  • Free variables: n - rank(A)
  • Interpretation: System has infinitely many solutions
  • Example: Two equations representing the same line

7. Gauss-Jordan Elimination

Difference from Gaussian Elimination

  • Creates Reduced Row Echelon Form (RREF)
  • Both forward elimination AND backward elimination
  • Pivot elements become 1
  • All elements above and below pivots become 0

RREF Conditions

  1. In REF
  2. All pivot elements = 1
  3. Each pivot is the only non-zero entry in its column

Algorithm

gauss_jordan <- function(A, b) {
  n <- nrow(A)
  Ab <- cbind(A, b)
  
  for (i in 1:n) {
    pivot <- Ab[i, i]
    for (j in i:(n + 1)) {
      Ab[i, j] <- Ab[i, j] / pivot
    }
    
    for (k in 1:n) {
      if (k != i) {
        factor <- Ab[k, i]
        for (j in i:(n + 1)) {
          Ab[k, j] <- Ab[k, j] - factor * Ab[i, j]
        }
      }
    }
  }
  
  return(Ab[, n + 1])
}


🎯 Gaussian Solver: Complete Visual Workflow

Gaussian Workflow
Gaussian Workflow

📋 Problem Overview

Solve Ax = b using Gaussian elimination, determining solution type without built-in functions.

# System to solve:
# 2x₁ + x₂ = 5
# x₁ + 3x₂ = 6

A <- matrix(c(2, 1, 1, 3), nrow = 2, byrow = TRUE)
b <- c(5, 6)

🏗️ System Representation

Original System:
┌               ┐
│  2   1  |  5  │  Equation 1: 2x₁ + x₂ = 5
│  1   3  |  6  │  Equation 2: x₁ + 3x₂ = 6
└               ┘


🧮 Final Implementation with Comments

gaussian_solver <- function(A, b) {
  n <- nrow(A)
  
  # Create augmented matrix manually (without cbind)
  aug <- matrix(0, nrow = n, ncol = n + 1)
  for (i in 1:n) {
    for (j in 1:n) {
      aug[i, j] <- A[i, j]
    }
    aug[i, n + 1] <- b[i]
  }
  
  # Forward elimination (no pivoting for simplicity)
  for (i in 1:n) {
    if (abs(aug[i, i]) < 1e-10) {
      next
    }
    
    for (j in (i + 1):n) {
      factor <- aug[j, i] / aug[i, i]
      for (k in i:(n + 1)) {
        aug[j, k] <- aug[j, k] - factor * aug[i, k]
      }
    }
  }
  
  # Check solution type
  has_zero_row <- FALSE
  has_inconsistent <- FALSE
  
  for (i in 1:n) {
    all_zero <- all(abs(aug[i, 1:n]) < 1e-10)
    if (all_zero) {
      has_zero_row <- TRUE
      if (abs(aug[i, n + 1]) > 1e-10) {
        has_inconsistent <- TRUE
      }
    }
  }
  
  if (has_inconsistent) {
    return(list(status = "No solution", solution = NULL))
  }
  
  if (has_zero_row) {
    return(list(status = "Infinite solutions", solution = NULL))
  }
  
  # Back substitution
  x <- numeric(n)
  for (i in n:1) {
    sum_val <- aug[i, n + 1]
    for (j in (i + 1):n) {
      sum_val <- sum_val - aug[i, j] * x[j]
    }
    x[i] <- sum_val / aug[i, i]
  }
  
  names(x) <- paste0("x", 1:n)
  return(list(status = "Unique solution", solution = x))
}

# Test the function
A <- matrix(c(2, 1, 1, 3), nrow = 2, byrow = TRUE)
b <- c(5, 6)
result <- gaussian_solver(A, b)
result$status
result$solution

🎯 Key Learning Points

  1. Augmented Matrix: Combine A and b for simultaneous operations

  2. Partial Pivoting: Prevents division by zero and improves numerical stability

  3. Forward Elimination: Creates upper triangular form

  4. Solution Analysis:

    • Inconsistent if [0 0 ... 0 | c] with c ≠ 0
    • Infinite if rank(A) < n
    • Unique if rank(A) = n and consistent
  5. Back Substitution: Solve from bottom to top


LS0tDQp0aXRsZTogIlIgcXVlc3Rpb24gc29sdmUiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KIyBMaW5lYXIgRXF1YXRpb24gU29sdmUNCg0KIyMjIDEpIFdyaXRlIGEgZnVuY3Rpb24gdG8gc29sdmUgYSBzeXN0ZW0gb2YgMiBsaW5lYXIgZXF1YXRpb25zIGluIDIgdmFyaWFibGVzICgyeDIgc3lzdGVtKS4NCmBgYHtyfQ0KY2F0KCJUaGUgZXF1YXRpb25zIGFyZTpcbiBhMXggKyBiMXkgPSBjMVxuIGEyeCArIGIyeSA9IGMyXG5cbiIpDQoNCmExIDwtIGFzLm51bWVyaWMocmVhZGxpbmUocHJvbXB0ID0gImExID0gIikpDQpiMSA8LSBhcy5udW1lcmljKHJlYWRsaW5lKHByb21wdCA9ICJiMSA9ICIpKQ0KYzEgPC0gYXMubnVtZXJpYyhyZWFkbGluZShwcm9tcHQgPSAiYzEgPSAiKSkNCg0KYTIgPC0gYXMubnVtZXJpYyhyZWFkbGluZShwcm9tcHQgPSAiYTIgPSAiKSkNCmIyIDwtIGFzLm51bWVyaWMocmVhZGxpbmUocHJvbXB0ID0gImIyID0gIikpDQpjMiA8LSBhcy5udW1lcmljKHJlYWRsaW5lKHByb21wdCA9ICJjMiA9ICIpKQ0KDQoNCnZhbHVlcyA8LSBjKGExLGIxLGMxLGEyLGIyLGMyKQ0KZXFuXzJieTJfc29sdmVyIDwtIGZ1bmN0aW9uKGExLCBiMSwgYzEsIGEyLCBiMiwgYzIpew0KICAjIFNvbHZpbmcgdGhlIHN5c3RlbQ0KICBkZW5vbWluYXRvciA8LSAoYTEqYjIgLSBhMipiMSkNCiAgDQogIGlmIChkZW5vbWluYXRvciA9PSAwKSB7DQogICAgY2F0KCJObyB1bmlxdWUgc29sdXRpb24gZXhpc3RzLlxuIikNCiAgfSBlbHNlIHsNCiAgICB5IDwtIChhMSpjMiAtIGEyKmMxKSAvIGRlbm9taW5hdG9yDQogICAgeCA8LSAoYzEgLSBiMSp5KSAvIGExDQogICAgY2F0KHNwcmludGYoIlNvbHV0aW9uOlxueCA9ICUuNGYgXG55ID0gJS40ZlxuIiwgeCwgeSkpDQogIH0NCn0NCmVxbl8yYnkyX3NvbHZlcihhMSxiMSxjMSxhMixiMixjMikNCmRvLmNhbGwoZXFuXzJieTJfc29sdmVyLCBhcy5saXN0KHZhbHVlcykpDQoNCmBgYA0KIyMjIDIpIFdyaXRlIGEgZnVuY3Rpb24gdG8gc29sdmUgYSAzeDMgc3lzdGVtIHVzaW5nIENyYW1lcidzIHJ1bGUuDQpgYGB7cn0NCmNyYW1lcjNieTMgPC0gZnVuY3Rpb24oZXFuMSxlcW4yLGVxbjMpew0KICBEIDwtIHJiaW5kKA0KICAgIGVxbjFbMTozXSwNCiAgICBlcW4yWzE6M10sDQogICAgZXFuM1sxOjNdDQogICkNCiAgYiA8LSBjKGVxbjFbNF0sZXFuMls0XSxlcW4zWzRdKQ0KICB2YXJzIDwtIGMoIngiLCJ5IiwieiIpDQogIGZvciAoaSBpbiAxOjMpew0KICAgIEUgPC0gRA0KICAgIEVbLGldIDwtIGINCiAgICBjYXQodmFyc1tpXSwiPSIsZGV0KEUpL2RldChEKSwiXG4iKQ0KICB9DQogIA0KfQ0KDQplcW4xIDwtIGMoYTE9MiwgYjE9MywgYzE9LTEsIGQxPTgpDQplcW4yIDwtIGMoYTI9MSwgYjI9LTEsIGMyPTQsIGQyPTExKQ0KZXFuMyA8LSBjKGEzPTMsIGIzPTEsIGMzPTIsIGQzPTcpDQoNCmNyYW1lcjNieTMoZXFuMSxlcW4yLGVxbjMpDQoNCmBgYA0KIyMjIDMpIFdyaXRlIGEgZnVuY3Rpb24gdG8gZmluZCB0aGUgZGV0ZXJtaW5hbnQgb2YgYSAyeDIgbWF0cml4Lg0KYGBge3J9DQpkZXQyYnkyIDwtIGZ1bmN0aW9uKEEpew0KICAoQVsxLDFdKkFbMiwyXSktKEFbMSwyXSpBWzIsMV0pDQp9DQpBIDwtIG1hdHJpeChjKDIsOSw0LDUpLCBucm93PTIpDQpkZXQyYnkyKEEpDQpgYGANCiMjIyA0KSBXcml0ZSBhIGZ1bmN0aW9uIHRvIGZpbmQgdGhlIGRldGVybWluYW50IG9mIGEgM3gzIG1hdHJpeA0KYGBge3J9DQpkZXQzYnkzIDwtIGZ1bmN0aW9uKEEpew0KICByZXN1bHQgPC0gQVsxLDFdKihBWzIsMl0qQVszLDNdLUFbMywyXSpBWzIsM10pLUFbMSwyXSooQVsyLDFdKkFbMywzXS1BWzMsMV0qQVsyLDNdKStBWzEsM10qKEFbMiwxXSpBWzMsMl0tQVszLDFdKkFbMiwyXSkNCiAgcmV0dXJuKHJlc3VsdCkNCn0NCg0KQT1tYXRyaXgoYygxOjgsMTEpLCBucm93PTMpDQpkZXQzYnkzKEEpDQpBDQpgYGANCiMjIyA1KSBXcml0ZSBhIGZ1bmN0aW9uIHRvIGZpbmQgdGhlIGludmVyc2Ugb2YgYSAyeDIgbWF0cml4IHVzaW5nIHRoZSBkZXRlcm1pbmFudCBhbmQgYWRqdWdhdGUuDQpgYGB7cn0NCmludjJieTIgPC0gZnVuY3Rpb24oQSl7DQogIGRldF9BIDwtIChBWzEsMV0qQVsyLDJdLUFbMiwxXSpBWzEsMl0pDQogIGlmIChkZXRfQSE9MCl7DQogIGludl9BIDwtIG1hdHJpeChjKEFbMiwyXSwgLUFbMSwyXSwgLUFbMiwxXSwgQVsxLDFdKSwgbnJvdz0yKS9kZXRfQQ0KICByZXR1cm4oaW52X0EpDQogIH0NCiAgZWxzZXsNCiAgICByZXR1cm4oIkludmVyc2Ugbm90IHBvc3NpYmxlIikNCiAgfQ0KfQ0KDQpBIDwtIG1hdHJpeChjKDEsIDIsIDIsIDMpLCBuY29sID0gMiwgYnlyb3cgPSBUUlVFKQ0KaW52MmJ5MihBKQ0KYGBgDQojIyMgNikgV3JpdGUgYSBmdW5jdGlvbiB0byBzb2x2ZSBhIDJ4MiBzeXN0ZW0gYnkgZmluZGluZyB0aGUgaW52ZXJzZSBtYXRyaXggYW5kIG11bHRpcGx5aW5nLg0KYGBge3J9DQpzb2x2ZXIyYnkyIDwtIGZ1bmN0aW9uKEEsIGIpew0KICBzb2wgPC0gaW52MmJ5MihBKSAlKiUgYg0KICBjYXQoInggPSAiLHNvbFsxLF0sIlxueSA9ICIsIHNvbFsyLF0pDQp9DQoNCkEgPC0gbWF0cml4KGMoMiwzLDQsLTEpLCBieXJvdz1UUlVFLCBucm93PTIpDQoNCmIgPC0gbWF0cml4KGMoOCwyKSwgbnJvdz0yKQ0KYg0Kc29sdmVyMmJ5MihBLGIpDQpgYGANCiMjIyA3KSBXcml0ZSBhIGZ1bmN0aW9uIHRvIGNoZWNrIGlmIGEgMngyIHN5c3RlbSBoYXMgYSB1bmlxdWUgc29sdXRpb24sIG5vIHNvbHV0aW9uLCBvciBpbmZpbml0ZWx5IG1hbnkgc29sdXRpb25zLg0KDQpGb3IgdGhlIHN5c3RlbSAgDQph4oKBeCArIGLigoF5ID0gY+KCgSAgDQph4oKCeCArIGLigoJ5ID0gY+KCgiAgDQoNCkNvbXB1dGUgIA0KRCA9IGHigoFi4oKCIOKIkiBh4oKCYuKCgSAgDQoNCuKAoiBJZiBEIOKJoCAwIOKGkiAqKnVuaXF1ZSBzb2x1dGlvbioqICANCuKAoiBJZiBEID0gMCBhbmQgYeKCgS9h4oKCID0gYuKCgS9i4oKCID0gY+KCgS9j4oKCIOKGkiAqKmluZmluaXRlbHkgbWFueSBzb2x1dGlvbnMqKiAgDQrigKIgSWYgRCA9IDAgYW5kIGHigoEvYeKCgiA9IGLigoEvYuKCgiDiiaAgY+KCgS9j4oKCIOKGkiAqKm5vIHNvbHV0aW9uKioNCmBgYHtyfQ0Kc29sX3R5cGVfMmJ5MiA8LSBmdW5jdGlvbihBLGIpew0KICBEIDwtIEFbMSwxXSpBWzIsMl0tQVsyLDFdKkFbMSwyXQ0KICBpZiAoRCE9MCl7DQogICAgcmV0dXJuICgiVW5pcXVlIikNCiAgfQ0KICBlbHNlew0KICAgIGlmIChBWzEsMV0vQVsyLDFdPT1BWzEsMl0qQVsyLDJdICYgYlsxLF0vYlsyLF09PUFbMSwxXS9BWzIsMV0pew0KICAgICAgcmV0dXJuKCJJbmZpbml0ZWx5IG1hbnkiKQ0KICAgIH0gZWxzZXsNCiAgICAgIHJldHVybigiTm8gU29sdXRpb24iKQ0KICAgIH0NCiAgfQ0KfQ0KDQpBIDwtIG1hdHJpeChjKDIsMyw0LC0xKSwgYnlyb3c9VFJVRSwgbnJvdz0yKQ0KYiA8LSBtYXRyaXgoYyg4LDIpLCBucm93PTIpDQpzb2xfdHlwZV8yYnkyKEEsYikNCmBgYA0KIyMjIDgpIENoZWNrIHRoZSBuYXR1cmUgb2Ygcm9vdHMgb2YgYSBxdWFkcmF0aWMgZXF1YXRpb24NCmBgYHtyfQ0KcXVhZHJpY19yb290X25hdHVyZSA8LSBmdW5jdGlvbihhLGIsYyl7DQogIEQgPC0gYl4yIC0gNCphKmMgDQogICAgaWYgKEQgPiAwKSB7DQogICAgY2F0KCJUd28gZGlzdGluY3QgcmVhbCByb290cyIpDQogIH0gZWxzZSBpZiAoRCA9PSAwKSB7DQogICAgY2F0KCJUd28gZXF1YWwgcmVhbCByb290cyIpDQogIH0gZWxzZSB7DQogICAgY2F0KCJObyByZWFsIHJvb3RzIikNCiAgfQ0KfQ0KDQphIDwtIDENCmIgPC0gLTMNCmMgPC0gMg0KDQpxdWFkcmljX3Jvb3RfbmF0dXJlKGEsYixjKQ0KYGBgDQojIyMgOSkgV3JpdGUgYSBmdW5jdGlvbiB0byBjaGVjayBpZiBhIDN4MyBzeXN0ZW0gaGFzIGEgdW5pcXVlIHNvbHV0aW9uIChieSBjaGVja2luZyBkZXRlcm1pbmFudCkuDQpgYGB7cn0NCnNvbF90eXBlXzNieTMgPC0gZnVuY3Rpb24oQSxiKXsNCiAgaWYgKGRldChBKSE9MCl7DQogICAgY2F0KCJVbmlxdWUgU29sdXRpb24iKQ0KICB9IGVsc2V7DQogICAgY2F0KCJJbmZpbml0ZWx5IG1hbnkgb3IgTm8gc29sdXRpb24iKQ0KICB9DQp9DQpzb2xfdHlwZV8zYnkzKEEsYikNCmBgYA0KIyMjIDEwKSBXcml0ZSBhIGZ1bmN0aW9uIHRvIGZpbmQgdGhlIHRyYWNlIG9mIGEgc3F1YXJlIG1hdHJpeCAoMngyLCAzeDMpLg0KYGBge3J9DQp0cmFjZV9maW5kZXIgPC0gZnVuY3Rpb24oQSl7DQogIGlmIChucm93KEEpPT1uY29sKEEpKXsNCiAgICB0IDwtIDANCiAgICBmb3IgKGkgaW4gMTpucm93KEEpKXsNCiAgICAgIHQgPC0gdCtBW2ksaV0NCiAgICB9DQogICAgY2F0KCJUcmFjZToiLHQpDQogIH0NCiAgZWxzZSB7DQogICAgY2F0KCJHaXZlIFNxdWFyZSBNYXRyaXgiKQ0KICB9DQp9DQoNCkEgPC0gbWF0cml4KDE6OSwgbnJvdyA9IDMsIG5jb2wgPSAzKQ0KdHJhY2VfZmluZGVyKEEpDQpgYGANCm1hdHJpeCBpcyBzaW5ndWxhciB3aGVuIGRldGVybWluYW50ID0gMA0KDQoNCg0KLS0tDQoNCiMgTGluZWFyIEFsZ2VicmEgZm9yIENvZGVyczogRXNzZW50aWFsIENvbmNlcHRzIGFuZCBBbGdvcml0aG1zDQoNCiMjIDEuICoqUm93IEVjaGVsb24gRm9ybSAoUkVGKSoqDQoNCiMjIyBEZWZpbml0aW9uDQoNCkEgbWF0cml4IGlzIGluIFJvdyBFY2hlbG9uIEZvcm0gd2hlbjoNCg0KKiBBbGwgbm9uemVybyByb3dzIGFyZSBhYm92ZSByb3dzIG9mIGFsbCB6ZXJvcw0KKiBFYWNoIGxlYWRpbmcgY29lZmZpY2llbnQgKHBpdm90KSBvZiBhIHJvdyBpcyBpbiBhIGNvbHVtbiB0byB0aGUgcmlnaHQgb2YgdGhlIGxlYWRpbmcgY29lZmZpY2llbnQgb2YgdGhlIHJvdyBhYm92ZSBpdA0KKiBBbGwgZW50cmllcyBpbiBhIGNvbHVtbiBiZWxvdyBhIGxlYWRpbmcgY29lZmZpY2llbnQgYXJlIHplcm9zDQoNCiMjIyBFeGFtcGxlDQoNCmBgYA0KWyAxICAyICAzICA0IF0NClsgMCAgMSAgNSAgNiBdICAg4pyTIFJFRg0KWyAwICAwICAwICAxIF0NCmBgYA0KDQpgYGANClsgMCAgMSAgMiBdICAgICAg4pyXIE5vdCBSRUYgKHplcm8gcm93IGFib3ZlIG5vbi16ZXJvKQ0KWyAxICAwICAzIF0NCmBgYA0KDQojIyMgQWxnb3JpdGhtIHRvIGFjaGlldmUgUkVGDQoNCmBgYHINCnJvd19lY2hlbG9uX2Zvcm0gPC0gZnVuY3Rpb24obWF0KSB7DQogIHJvd3MgPC0gbnJvdyhtYXQpDQogIGNvbHMgPC0gbmNvbChtYXQpDQogIHBpdm90X3JvdyA8LSAxDQogIA0KICBmb3IgKGNvbCBpbiAxOmNvbHMpIHsNCiAgICAjIEZpbmQgcGl2b3QgaW4gY3VycmVudCBjb2x1bW4NCiAgICBwaXZvdCA8LSBmaW5kX3Bpdm90KG1hdCwgcGl2b3Rfcm93LCBjb2wpDQogICAgaWYgKGlzLm51bGwocGl2b3QpKSB7DQogICAgICBuZXh0DQogICAgfQ0KICAgIA0KICAgICMgU3dhcCBwaXZvdCByb3cgd2l0aCBjdXJyZW50IHJvdw0KICAgIG1hdCA8LSBzd2FwX3Jvd3MobWF0LCBwaXZvdCwgcGl2b3Rfcm93KQ0KICAgIA0KICAgICMgTWFrZSBhbGwgZW50cmllcyBiZWxvdyBwaXZvdCB6ZXJvDQogICAgZm9yIChyb3cgaW4gKHBpdm90X3JvdyArIDEpOnJvd3MpIHsNCiAgICAgIGZhY3RvciA8LSBtYXRbcm93LCBjb2xdIC8gbWF0W3Bpdm90X3JvdywgY29sXQ0KICAgICAgbWF0W3JvdywgXSA8LSBtYXRbcm93LCBdIC0gZmFjdG9yICogbWF0W3Bpdm90X3JvdywgXQ0KICAgIH0NCiAgICANCiAgICBwaXZvdF9yb3cgPC0gcGl2b3Rfcm93ICsgMQ0KICAgIGlmIChwaXZvdF9yb3cgPiByb3dzKSB7DQogICAgICBicmVhaw0KICAgIH0NCiAgfQ0KICByZXR1cm4obWF0KQ0KfQ0KYGBgDQoNCi0tLQ0KDQojIyAyLiAqKkZvcndhcmQgRWxpbWluYXRpb24qKg0KDQojIyMgUHVycG9zZQ0KDQpDb252ZXJ0IGEgc3lzdGVtIG9mIGxpbmVhciBlcXVhdGlvbnMgdG8gdXBwZXIgdHJpYW5ndWxhciBmb3JtLg0KDQojIyMgUHJvY2Vzcw0KDQoxLiBTdGFydCB3aXRoIGZpcnN0IGVxdWF0aW9uDQoyLiBVc2UgaXQgdG8gZWxpbWluYXRlIGZpcnN0IHZhcmlhYmxlIGZyb20gc3Vic2VxdWVudCBlcXVhdGlvbnMNCjMuIE1vdmUgdG8gbmV4dCBlcXVhdGlvbiwgcmVwZWF0DQoNCiMjIyBFeGFtcGxlIFN5c3RlbQ0KDQpgYGANCjJ4ICsgIHkgKyAgeiA9ICA4DQo0eCArIDN5ICsgMnogPSAxOA0KLTJ4ICsgIHkgKyAgeiA9ICAyDQpgYGANCg0KIyMjIEFmdGVyIEZvcndhcmQgRWxpbWluYXRpb24NCg0KYGBgDQoyeCArICB5ICsgIHogPSA4DQoweCArICB5ICsgMHogPSAyICAoU2Vjb25kIGVxdWF0aW9uIG1pbnVzIDLDl2ZpcnN0KQ0KMHggKyAyeSArIDJ6ID0gMTAgKFRoaXJkIGVxdWF0aW9uIHBsdXMgZmlyc3QpDQpgYGANCg0KLS0tDQoNCiMjIDMuICoqR2F1c3NpYW4gRWxpbWluYXRpb24qKg0KDQojIyMgQ29tcGxldGUgQWxnb3JpdGhtDQoNCjEuICoqRm9yd2FyZCBFbGltaW5hdGlvbioqOiBDb252ZXJ0IHRvIHVwcGVyIHRyaWFuZ3VsYXIgbWF0cml4DQoyLiAqKkJhY2sgU3Vic3RpdHV0aW9uKio6IFNvbHZlIGZyb20gYm90dG9tIHRvIHRvcA0KDQojIyMgSW1wbGVtZW50YXRpb24gU3RlcHMNCg0KYGBgcg0KZ2F1c3NpYW5fZWxpbWluYXRpb24gPC0gZnVuY3Rpb24oQSwgYikgew0KICBuIDwtIG5yb3coQSkNCiAgDQogICMgQXVnbWVudCBtYXRyaXggW0F8Yl0NCiAgQWIgPC0gY2JpbmQoQSwgYikNCiAgDQogICMgRm9yd2FyZCBlbGltaW5hdGlvbg0KICBmb3IgKGkgaW4gMTpuKSB7DQogICAgIyBQYXJ0aWFsIHBpdm90aW5nIGZvciBzdGFiaWxpdHkNCiAgICBtYXhfcm93IDwtIHdoaWNoLm1heChhYnMoQWJbaTpuLCBpXSkpICsgaSAtIDENCiAgICBpZiAoaSAhPSBtYXhfcm93KSB7DQogICAgICBBYltjKGksIG1heF9yb3cpLCBdIDwtIEFiW2MobWF4X3JvdywgaSksIF0NCiAgICB9DQogICAgDQogICAgIyBFbGltaW5hdGUgYmVsb3cgcGl2b3QNCiAgICBmb3IgKGogaW4gKGkgKyAxKTpuKSB7DQogICAgICBmYWN0b3IgPC0gQWJbaiwgaV0gLyBBYltpLCBpXQ0KICAgICAgQWJbaiwgXSA8LSBBYltqLCBdIC0gZmFjdG9yICogQWJbaSwgXQ0KICAgIH0NCiAgfQ0KICANCiAgIyBCYWNrIHN1YnN0aXR1dGlvbg0KICB4IDwtIG51bWVyaWMobikNCiAgZm9yIChpIGluIG46MSkgew0KICAgIHhbaV0gPC0gQWJbaSwgbiArIDFdIC8gQWJbaSwgaV0NCiAgICBmb3IgKGogaW4gKGkgLSAxKToxKSB7DQogICAgICBBYltqLCBuICsgMV0gPC0gQWJbaiwgbiArIDFdIC0gQWJbaiwgaV0gKiB4W2ldDQogICAgfQ0KICB9DQogIA0KICByZXR1cm4oeCkNCn0NCmBgYA0KDQotLS0NCg0KDQoNCi0tLQ0KDQojIyA0LiAqKlJhbmsgQ2hlY2sqKg0KDQojIyMgRGVmaW5pdGlvbg0KDQpUaGUgcmFuayBvZiBhIG1hdHJpeCBpcyB0aGUgbWF4aW11bSBudW1iZXIgb2YgbGluZWFybHkgaW5kZXBlbmRlbnQgcm93cyAob3IgY29sdW1ucykuDQoNCiMjIyBQcm9wZXJ0aWVzDQoNCiogcmFuayhBKSDiiaQgbWluKG0sIG4pIGZvciBtw5duIG1hdHJpeA0KKiBGdWxsIHJhbms6IHJhbmsgPSBtaW4obSwgbikNCiogU2luZ3VsYXIgbWF0cml4OiByYW5rIDwgbiBmb3IgbsOXbiBtYXRyaXgNCg0KIyMjIEFsZ29yaXRobSB0byBDb21wdXRlIFJhbmsNCg0KYGBgcg0KbWF0cml4X3JhbmsgPC0gZnVuY3Rpb24obWF0LCBhdWdtZW50ZWQgPSBGQUxTRSkgew0KICByZWZfbWF0IDwtIHJvd19lY2hlbG9uX2Zvcm0obWF0KQ0KICByYW5rIDwtIDANCiAgY29scyA8LSBpZmVsc2UoYXVnbWVudGVkLCBuY29sKHJlZl9tYXQpIC0gMSwgbmNvbChyZWZfbWF0KSkNCiAgDQogIGZvciAoaSBpbiAxOm5yb3cocmVmX21hdCkpIHsNCiAgICBpZiAoYW55KGFicyhyZWZfbWF0W2ksIDE6Y29sc10pID4gMWUtMTApKSB7DQogICAgICByYW5rIDwtIHJhbmsgKyAxDQogICAgfQ0KICB9DQogIHJldHVybihyYW5rKQ0KfQ0KYGBgDQoNCiMjIyBTaWduaWZpY2FuY2UNCg0KKiAqKlVuaXF1ZSBzb2x1dGlvbioqOiByYW5rKEEpID0gcmFuayhbQXxiXSkgPSBuDQoqICoqSW5maW5pdGUgc29sdXRpb25zKio6IHJhbmsoQSkgPSByYW5rKFtBfGJdKSA8IG4NCiogKipObyBzb2x1dGlvbioqOiByYW5rKEEpIDwgcmFuayhbQXxiXSkNCg0KLS0tDQoNCiMjIDUuICoqQXVnbWVudGVkIE1hdHJpeCoqDQoNCiMjIyBEZWZpbml0aW9uDQoNCkNvbWJpbmVzIGNvZWZmaWNpZW50IG1hdHJpeCBBIGFuZCBjb25zdGFudCB2ZWN0b3IgYiBpbnRvIFtBfGJdDQoNCiMjIyBQdXJwb3NlDQoNCkFsbG93cyBzaW11bHRhbmVvdXMgb3BlcmF0aW9ucyBvbiBib3RoIHNpZGVzIGR1cmluZyBlbGltaW5hdGlvbi4NCg0KIyMjIEV4YW1wbGUNCg0KU3lzdGVtOg0KDQpgYGANCjJ4ICsgM3kgPSA4DQo0eCAtIHkgPSAyDQpgYGANCg0KQXVnbWVudGVkIE1hdHJpeDoNCg0KYGBgDQpbIDIgIDMgfCA4IF0NClsgNCAtMSB8IDIgXQ0KYGBgDQoNCiMjIyBJbXBsZW1lbnRhdGlvbg0KDQpgYGByDQphdWdtZW50X21hdHJpeCA8LSBmdW5jdGlvbihBLCBiKSB7DQogIGNiaW5kKEEsIGIpDQp9DQpgYGANCg0KLS0tDQoNCiMjIDYuICoqU29sdXRpb24gVHlwZXMgZm9yIExpbmVhciBTeXN0ZW1zKioNCg0KIyMjIDYuMSAqKlVuaXF1ZSBTb2x1dGlvbioqDQoNCiogQ29uZGl0aW9uOiByYW5rKEEpID0gcmFuayhbQXxiXSkgPSBuDQoqIERldGVybWluYW50OiBkZXQoQSkg4omgIDANCiogSW50ZXJwcmV0YXRpb246IFN5c3RlbSBoYXMgZXhhY3RseSBvbmUgc29sdXRpb24NCiogRXhhbXBsZTogSW50ZXJzZWN0aW9uIG9mIHR3byBub24tcGFyYWxsZWwgbGluZXMNCg0KIyMjIDYuMiAqKkluY29uc2lzdGVudCBTeXN0ZW0gKE5vIFNvbHV0aW9uKSoqDQoNCiogQ29uZGl0aW9uOiByYW5rKEEpIDwgcmFuayhbQXxiXSkNCiogSW50ZXJwcmV0YXRpb246IEVxdWF0aW9ucyBjb250cmFkaWN0IGVhY2ggb3RoZXINCiogRXhhbXBsZTogUGFyYWxsZWwgbGluZXMgdGhhdCBkb24ndCBpbnRlcnNlY3QNCg0KYGBgDQp4ICsgeSA9IDMNCnggKyB5ID0gNSAgIyBDb250cmFkaWN0aW9uIQ0KYGBgDQoNCiMjIyA2LjMgKipJbmZpbml0ZSBTb2x1dGlvbnMqKg0KDQoqIENvbmRpdGlvbjogcmFuayhBKSA9IHJhbmsoW0F8Yl0pIDwgbg0KKiBGcmVlIHZhcmlhYmxlczogbiAtIHJhbmsoQSkNCiogSW50ZXJwcmV0YXRpb246IFN5c3RlbSBoYXMgaW5maW5pdGVseSBtYW55IHNvbHV0aW9ucw0KKiBFeGFtcGxlOiBUd28gZXF1YXRpb25zIHJlcHJlc2VudGluZyB0aGUgc2FtZSBsaW5lDQoNCi0tLQ0KDQojIyA3LiAqKkdhdXNzLUpvcmRhbiBFbGltaW5hdGlvbioqDQoNCiMjIyBEaWZmZXJlbmNlIGZyb20gR2F1c3NpYW4gRWxpbWluYXRpb24NCg0KKiBDcmVhdGVzIFJlZHVjZWQgUm93IEVjaGVsb24gRm9ybSAoUlJFRikNCiogQm90aCBmb3J3YXJkIGVsaW1pbmF0aW9uIEFORCBiYWNrd2FyZCBlbGltaW5hdGlvbg0KKiBQaXZvdCBlbGVtZW50cyBiZWNvbWUgMQ0KKiBBbGwgZWxlbWVudHMgYWJvdmUgYW5kIGJlbG93IHBpdm90cyBiZWNvbWUgMA0KDQojIyMgUlJFRiBDb25kaXRpb25zDQoNCjEuIEluIFJFRg0KMi4gQWxsIHBpdm90IGVsZW1lbnRzID0gMQ0KMy4gRWFjaCBwaXZvdCBpcyB0aGUgb25seSBub24temVybyBlbnRyeSBpbiBpdHMgY29sdW1uDQoNCiMjIyBBbGdvcml0aG0NCg0KYGBgcg0KZ2F1c3Nfam9yZGFuIDwtIGZ1bmN0aW9uKEEsIGIpIHsNCiAgbiA8LSBucm93KEEpDQogIEFiIDwtIGNiaW5kKEEsIGIpDQogIA0KICBmb3IgKGkgaW4gMTpuKSB7DQogICAgcGl2b3QgPC0gQWJbaSwgaV0NCiAgICBmb3IgKGogaW4gaToobiArIDEpKSB7DQogICAgICBBYltpLCBqXSA8LSBBYltpLCBqXSAvIHBpdm90DQogICAgfQ0KICAgIA0KICAgIGZvciAoayBpbiAxOm4pIHsNCiAgICAgIGlmIChrICE9IGkpIHsNCiAgICAgICAgZmFjdG9yIDwtIEFiW2ssIGldDQogICAgICAgIGZvciAoaiBpbiBpOihuICsgMSkpIHsNCiAgICAgICAgICBBYltrLCBqXSA8LSBBYltrLCBqXSAtIGZhY3RvciAqIEFiW2ksIGpdDQogICAgICAgIH0NCiAgICAgIH0NCiAgICB9DQogIH0NCiAgDQogIHJldHVybihBYlssIG4gKyAxXSkNCn0NCmBgYA0KDQotLS0NCg0KDQotLS0NCg0KIyDwn46vIEdhdXNzaWFuIFNvbHZlcjogQ29tcGxldGUgVmlzdWFsIFdvcmtmbG93DQoNCiFbR2F1c3NpYW4gV29ya2Zsb3ddKEM6L1VzZXJzL0RlbGwvRG93bmxvYWRzL2dhdXNzaWFuX3dvcmtmbG93LnBuZykNCg0KDQoNCiMjIPCfk4sgUHJvYmxlbSBPdmVydmlldw0KDQpTb2x2ZSAqKkF4ID0gYioqIHVzaW5nIEdhdXNzaWFuIGVsaW1pbmF0aW9uLCBkZXRlcm1pbmluZyBzb2x1dGlvbiB0eXBlIHdpdGhvdXQgYnVpbHQtaW4gZnVuY3Rpb25zLg0KDQpgYGByDQojIFN5c3RlbSB0byBzb2x2ZToNCiMgMnjigoEgKyB44oKCID0gNQ0KIyB44oKBICsgM3jigoIgPSA2DQoNCkEgPC0gbWF0cml4KGMoMiwgMSwgMSwgMyksIG5yb3cgPSAyLCBieXJvdyA9IFRSVUUpDQpiIDwtIGMoNSwgNikNCmBgYA0KDQotLS0NCg0KIyMg8J+Pl++4jyBTeXN0ZW0gUmVwcmVzZW50YXRpb24NCg0KYGBgDQpPcmlnaW5hbCBTeXN0ZW06DQrilIwgICAgICAgICAgICAgICDilJANCuKUgiAgMiAgIDEgIHwgIDUgIOKUgiAgRXF1YXRpb24gMTogMnjigoEgKyB44oKCID0gNQ0K4pSCICAxICAgMyAgfCAgNiAg4pSCICBFcXVhdGlvbiAyOiB44oKBICsgM3jigoIgPSA2DQrilJQgICAgICAgICAgICAgICDilJgNCmBgYA0KDQotLS0NCg0KDQotLS0NCg0KIyMg8J+nriBGaW5hbCBJbXBsZW1lbnRhdGlvbiB3aXRoIENvbW1lbnRzDQoNCmBgYHINCmdhdXNzaWFuX3NvbHZlciA8LSBmdW5jdGlvbihBLCBiKSB7DQogIG4gPC0gbnJvdyhBKQ0KICANCiAgIyBDcmVhdGUgYXVnbWVudGVkIG1hdHJpeCBtYW51YWxseSAod2l0aG91dCBjYmluZCkNCiAgYXVnIDwtIG1hdHJpeCgwLCBucm93ID0gbiwgbmNvbCA9IG4gKyAxKQ0KICBmb3IgKGkgaW4gMTpuKSB7DQogICAgZm9yIChqIGluIDE6bikgew0KICAgICAgYXVnW2ksIGpdIDwtIEFbaSwgal0NCiAgICB9DQogICAgYXVnW2ksIG4gKyAxXSA8LSBiW2ldDQogIH0NCiAgDQogICMgRm9yd2FyZCBlbGltaW5hdGlvbiAobm8gcGl2b3RpbmcgZm9yIHNpbXBsaWNpdHkpDQogIGZvciAoaSBpbiAxOm4pIHsNCiAgICBpZiAoYWJzKGF1Z1tpLCBpXSkgPCAxZS0xMCkgew0KICAgICAgbmV4dA0KICAgIH0NCiAgICANCiAgICBmb3IgKGogaW4gKGkgKyAxKTpuKSB7DQogICAgICBmYWN0b3IgPC0gYXVnW2osIGldIC8gYXVnW2ksIGldDQogICAgICBmb3IgKGsgaW4gaToobiArIDEpKSB7DQogICAgICAgIGF1Z1tqLCBrXSA8LSBhdWdbaiwga10gLSBmYWN0b3IgKiBhdWdbaSwga10NCiAgICAgIH0NCiAgICB9DQogIH0NCiAgDQogICMgQ2hlY2sgc29sdXRpb24gdHlwZQ0KICBoYXNfemVyb19yb3cgPC0gRkFMU0UNCiAgaGFzX2luY29uc2lzdGVudCA8LSBGQUxTRQ0KICANCiAgZm9yIChpIGluIDE6bikgew0KICAgIGFsbF96ZXJvIDwtIGFsbChhYnMoYXVnW2ksIDE6bl0pIDwgMWUtMTApDQogICAgaWYgKGFsbF96ZXJvKSB7DQogICAgICBoYXNfemVyb19yb3cgPC0gVFJVRQ0KICAgICAgaWYgKGFicyhhdWdbaSwgbiArIDFdKSA+IDFlLTEwKSB7DQogICAgICAgIGhhc19pbmNvbnNpc3RlbnQgPC0gVFJVRQ0KICAgICAgfQ0KICAgIH0NCiAgfQ0KICANCiAgaWYgKGhhc19pbmNvbnNpc3RlbnQpIHsNCiAgICByZXR1cm4obGlzdChzdGF0dXMgPSAiTm8gc29sdXRpb24iLCBzb2x1dGlvbiA9IE5VTEwpKQ0KICB9DQogIA0KICBpZiAoaGFzX3plcm9fcm93KSB7DQogICAgcmV0dXJuKGxpc3Qoc3RhdHVzID0gIkluZmluaXRlIHNvbHV0aW9ucyIsIHNvbHV0aW9uID0gTlVMTCkpDQogIH0NCiAgDQogICMgQmFjayBzdWJzdGl0dXRpb24NCiAgeCA8LSBudW1lcmljKG4pDQogIGZvciAoaSBpbiBuOjEpIHsNCiAgICBzdW1fdmFsIDwtIGF1Z1tpLCBuICsgMV0NCiAgICBmb3IgKGogaW4gKGkgKyAxKTpuKSB7DQogICAgICBzdW1fdmFsIDwtIHN1bV92YWwgLSBhdWdbaSwgal0gKiB4W2pdDQogICAgfQ0KICAgIHhbaV0gPC0gc3VtX3ZhbCAvIGF1Z1tpLCBpXQ0KICB9DQogIA0KICBuYW1lcyh4KSA8LSBwYXN0ZTAoIngiLCAxOm4pDQogIHJldHVybihsaXN0KHN0YXR1cyA9ICJVbmlxdWUgc29sdXRpb24iLCBzb2x1dGlvbiA9IHgpKQ0KfQ0KDQojIFRlc3QgdGhlIGZ1bmN0aW9uDQpBIDwtIG1hdHJpeChjKDIsIDEsIDEsIDMpLCBucm93ID0gMiwgYnlyb3cgPSBUUlVFKQ0KYiA8LSBjKDUsIDYpDQpyZXN1bHQgPC0gZ2F1c3NpYW5fc29sdmVyKEEsIGIpDQpyZXN1bHQkc3RhdHVzDQpyZXN1bHQkc29sdXRpb24NCmBgYA0KDQotLS0NCg0KIyMg8J+OryBLZXkgTGVhcm5pbmcgUG9pbnRzDQoNCjEuICoqQXVnbWVudGVkIE1hdHJpeCoqOiBDb21iaW5lIEEgYW5kIGIgZm9yIHNpbXVsdGFuZW91cyBvcGVyYXRpb25zDQoyLiAqKlBhcnRpYWwgUGl2b3RpbmcqKjogUHJldmVudHMgZGl2aXNpb24gYnkgemVybyBhbmQgaW1wcm92ZXMgbnVtZXJpY2FsIHN0YWJpbGl0eQ0KMy4gKipGb3J3YXJkIEVsaW1pbmF0aW9uKio6IENyZWF0ZXMgdXBwZXIgdHJpYW5ndWxhciBmb3JtDQo0LiAqKlNvbHV0aW9uIEFuYWx5c2lzKio6DQoNCiAgICogSW5jb25zaXN0ZW50IGlmIGBbMCAwIC4uLiAwIHwgY11gIHdpdGggYGMg4omgIDBgDQogICAqIEluZmluaXRlIGlmIHJhbmsoQSkgPCBuDQogICAqIFVuaXF1ZSBpZiByYW5rKEEpID0gbiBhbmQgY29uc2lzdGVudA0KNS4gKipCYWNrIFN1YnN0aXR1dGlvbioqOiBTb2x2ZSBmcm9tIGJvdHRvbSB0byB0b3ANCg0KLS0tDQoNCmBgYHtyfQ0KDQpgYGANCg0KDQoNCg==