This notebook uses first the Nelder-Mead “simplex” (polytope) method and then a genetic algorithm (GA) to search for a minimum of a function. Motivation comes from a question posed on OR Stack Exchange (https://or.stackexchange.com/questions/4248/linear-optimization-problem-with-user-defined-cost-function). The feasible region for that problem is an \(n-1\))-dimensional simplex in \(n\)-space, specifically \[\lbrace x\in \Re^n : x\ge 0, \sum_{i=1}^n x_i = 1 \rbrace.\]

Objective function

We import problem information from a sample posted on GitHub (https://github.com/emmaparker96/WorkingExampleForStackExchange/blob/master/Example_SLSQP.py). (Date imported: 28 May 2020.)

E0 <- c(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 135.93520968143184, 203.90281452214782, 271.8704193628637, 424.7975302544746, 577.7246411460854, 730.6517520376964, 883.5788629293072, 866.5869617191278, 849.5950605089494, 832.6031592987699, 815.6112580885913, 815.6112580885913, 815.6112580885913, 815.6112580885913, 815.6112580885913, 917.5626653496648, 1019.514072610739, 1121.465479871813, 1223.4168871328868, 1240.4087883430657, 1257.400689553245, 1274.3925907634236, 1291.3844919736027, 1206.4249859227077, 1121.465479871813, 1036.5059738209181, 951.5464677700232, 815.6112580885913, 679.6760484071592, 543.7408387257274, 407.80562904429564, 305.8542217832217, 203.90281452214782, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
E1 <- c(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3.095541959394951, 3.095541959394951, 3.095541959394951, 13.12973913827916, 13.12973913827916, 13.12973913827916, 13.12973913827916, 10.554775902905341, 10.554775902905341, 10.554775902905341, 10.554775902905341, 0.0, 0.0, 0.0, 0.0, 0.0, 16.149332376345804, 16.149332376345804, 16.149332376345804, 16.149332376345804, 42.31217083831925, 42.31217083831925, 42.31217083831925, 19.66200973015714, 19.66200973015714, 19.66200973015714, 19.66200973015714, 27.52091396934956, 27.52091396934956, 27.52091396934956, 27.52091396934956, 329.2237299969277, 329.2237299969277, 329.2237299969277, 329.2237299969277, 577.9124838502333, 577.9124838502333, 577.9124838502333, 577.9124838502333, 577.9124838502333, 573.0452854570782, 573.0452854570782, 573.0452854570782, 573.0452854570782, 370.91790620023994, 370.91790620023994, 370.91790620023994, 370.91790620023994, 329.2237299969277, 329.2237299969277, 329.2237299969277, 290.5411117368605, 290.5411117368605, 290.5411117368605, 290.5411117368605, 163.41893588842228, 163.41893588842228, 163.41893588842228, 163.41893588842228, 115.3233378968986, 115.3233378968986, 115.3233378968986, 115.3233378968986, 206.25698899144692, 206.25698899144692, 206.25698899144692, 206.25698899144692, 309.48366575039114, 309.48366575039114, 309.48366575039114, 309.48366575039114, 644.4723765004536, 644.4723765004536, 644.4723765004536, 644.4723765004536, 581.4832995209256, 581.4832995209256, 581.4832995209256, 581.4832995209256, 581.4832995209256, 618.3483641692815, 618.3483641692815, 618.3483641692815, 618.3483641692815, 587.1387035345958, 587.1387035345958, 587.1387035345958, 587.1387035345958, 592.9400328151568, 592.9400328151568, 592.9400328151568, 592.9400328151568)
E2 <- c(311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 311.451553946575, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
C <- c(-238.09793269388078, -231.98014945556884, -226.4038621346316, -221.67417756776217, -217.37730914414377, -213.3855475572187, -209.20793087018725, -204.65754678669694, -199.45910140420102, -193.97817318468344, -188.8894647725575, -185.2516524889065, -183.01356803540787, -181.95404595732737, -181.0848192035878, -179.78298774584653, -177.45038994792517, -175.08649914111214, -174.27266947068077, -176.0967558741133, -181.8608012484003, -189.52420539885912, -197.23962360463787, -202.906618363511, -205.1364566862883, -204.78123874751853, -203.7576613418135, -203.5832239611677, -205.9173018338339, -210.37021242341194, -211.4661020523664, -210.74636284785922, -220.03340899344477, -230.65484824115885, -241.94126392781988, -253.96729410841942, -266.31788353664484, -278.5346319200839, -290.0967643877901, -300.0375806921114, -308.34968045932357, -315.37813254423145, -321.5039504740156, -327.74902014038673, -334.4328262489882, -340.9470580796771, -346.59354323137114, -350.60962033196205, -352.39903069851476, -352.12056520722916, -349.403570854139, -344.65612539033117, -337.9934632066564, -329.52003529225306, -319.7257463876742, -308.9497450487453, -297.5394259620134, -286.3540782365023, -276.09420010503595, -267.58736478924817, -261.4672557191943, -257.1046296890537, -253.93853837051893, -251.06825056170987, -248.25991445293613, -246.2814773975382, -246.5599428888238, -250.58828346587217, -268.0030543533085, -285.1632523846266, -298.5845701711438, -311.97797797675736, -323.9109748876792, -334.81870287890183, -345.0030971983795, -355.14414647175744, -365.1991399706833, -373.6300685959841, -378.0062267380778, -375.8201563398988, -366.0300962203055, -351.06738630662676, -334.40681922132825, -319.42740560695745, -308.79962318176524, -301.6618570049859, -296.259584186196, -290.8943132360278, -284.2794363226875, -276.3143083635236, -267.24271881294186, -257.4477955906152, -247.21921046804047, -237.3232192845639, -228.54743324370762, -221.52278706528654, -238.20280656151755, -232.0850233232057, -226.4825175353592, -221.75283296848977)
P <- c(229.89065105694536, 229.89065105694536, 229.89065105694536, 229.89065105694536, 223.5974864170219, 223.5974864170219, 223.5974864170219, 223.5974864170219, 222.65129813706153, 222.65129813706153, 222.65129813706153, 222.65129813706153, 218.6168610254046, 218.6168610254046, 218.6168610254046, 218.6168610254046, 216.04875946585696, 216.04875946585696, 216.04875946585696, 216.04875946585696, 211.96472088144813, 211.96472088144813, 211.96472088144813, 211.96472088144813, 209.37181070216718, 209.37181070216718, 209.37181070216718, 209.37181070216718, 205.23837296306382, 205.23837296306382, 205.23837296306382, 205.23837296306382, 210.1355967615753, 210.1355967615753, 210.1355967615753, 210.1355967615753, 202.23145930691305, 202.23145930691305, 202.23145930691305, 202.23145930691305, 192.61562326955348, 192.61562326955348, 192.61562326955348, 192.61562326955348, 190.99145786088897, 190.99145786088897, 190.99145786088897, 190.99145786088897, 188.805123678349, 188.805123678349, 188.805123678349, 188.805123678349, 187.17321783204582, 187.17321783204582, 187.17321783204582, 187.17321783204582, 189.67465833392575, 189.67465833392575, 189.67465833392575, 189.67465833392575, 189.31792642901829, 189.31792642901829, 189.31792642901829, 189.31792642901829, 191.13084632879534, 191.13084632879534, 191.13084632879534, 191.13084632879534, 188.9656881806189, 188.9656881806189, 188.9656881806189, 188.9656881806189, 189.84290021396143, 189.84290021396143, 189.84290021396143, 189.84290021396143, 186.01353682427288, 186.01353682427288, 186.01353682427288, 186.01353682427288, 186.97045119661692, 186.97045119661692, 186.97045119661692, 186.97045119661692, 192.2104050349677, 192.2104050349677, 192.2104050349677, 192.2104050349677, 193.77823259796187, 193.77823259796187, 193.77823259796187, 193.77823259796187, 210.1315243148335, 210.1315243148335, 210.1315243148335, 210.1315243148335, 209.743383420093, 209.743383420093, 209.743383420093, 209.743383420093)

We import the objective function from the same source, using the “simplified” version,which handles zero arguments better than the original. (Date imported: 29 May 2020.) Indices are adjusted to account for Python using 0-based indexing and R using 1-based indexing.

cost_function <- function(x0) {
  value_to_minimize <-  0.0
  for (i in seq_along(E0)) {
    e <-  x0[1] * E0[i] + x0[2] * E1[i] + x0[3] * E2[i]
    v <-  (0.01 * (x0[1] * E0[i]) + 0.12 * (x0[2] * E1[i]) + 0.35 * (x0[3] * E2[i])) / e
    if (is.nan(v)) v <- 0
    value_to_minimize <- value_to_minimize + min(-C[i], e) * (P[i] - v)
  }
  -value_to_minimize
}

For readability, we specify the dimension of the example as a symbol.

dim <- 3

Benchmarks

A solution was reported by the producers of LocalSolver. They claim an objective value of -4683155.21625473.

local.solver <- c(0.0012157632500765, 0.286070665348843, 0.712713571407526)
cost_function(local.solver)
[1] -4683155

Emma, the original poster, reported the following solution (without specifying an objective value).

emma <- c(0.17023975, 0.19532928, 0.64296507)
cost_function(emma)
[1] -4495453

Emma’s solution is actually not quite feasible (the sum being slightly greater than 1).

sum(emma)
[1] 1.008534

Nelder-Mead algorithm

There is a neldermead package in CRAN which did not seem to work, and a few packages with Nelder-Mead algorithms that appear restricted to one dimensional lines searches. So we will code the algorithm as presented at https://en.wikipedia.org/wiki/Nelder%E2%80%93Mead_method.

Since Nelder-Mead starts with a polytope and modifies its vertices using linear combinations of the existing vertices and the center of the polytope, it will automatically remain on the hyperplane. Step sizes may need to be adjusted to preserve nonnegativity of all vertices.

Helper functions

The algorithm requires calculating the centroid of progressive simplices, so we create a function for that.

centroid <- function(s) {  # s is the simplex
  apply(s, 1, mean)
}

At various points the algorithm takes a step in a specified direction, starting from a point in the current polygon. The Nelder-Mead version used here might result in sign violations if step sizes are too large. To avoid that, we use a function to compute a “safe” step size, shrinking the proposed step size if necessary to preserve nonnegativity, and then take the designated step.

step <- function(step_size, origin, direction) {
  # Arguments:
  #  step_size = the proposed step size;
  #  origin = the starting point for the step;
  #  direction = the direction of the step.
  # Return value = the result of the step (guaranteed to remain feasible).
  i <- direction < 0  # indices of components where direction is negative
  s <- min(step_size, -origin[i] / direction[i]) # safe step size
  origin + s * direction  # resulting vector
}

The nm function will perform a single iteration of the Nelder-Mead algorithm. It takes a list containing the current simplex, the vector of objective values for the corners, the current incumbent and the current incumbent objective value as input and returns a modified list with the same items. The step size arguments default to values described as “standard” in the Wikipedia page.

nm <- function(x, reflection = 1.0, expansion = 2.0, contraction = 0.5, shrinking = 0.5) { 
  # Arguments:
  #   x = list containing the simplex vertices, their objective values, the current incumbent and its objective value
  #   reflection = step size for reflection steps ($\alpha$ in Wikipedia page)
  #   expansion = step size for expansion steps ($\gamma$ in Wikipedia page)
  #   contraction = step size for contraction steps ($\rho$ in Wikipedia page)
  #   shrinking = factor for shrinking the polytope ($\sigma$ in Wikipedia page)
  # Return value: a modified version of x.
  #
  # Set up a return list.
  result = list(simplex = x$simplex, obj = x$obj, incumbent = x$incumbent, incumbent.value = x$incumbent.value)
  # Identify the best and worst corners of the current simplex.
  best <- which.min(x$obj)   # index of best corner
  worst <- which.max(x$obj)  # index of the worst corner
  # We also need the index of the second worst corner, which we get by temporarily zapping the worst entry, finding the worst surviving entry, then restoring the worst entry.
  temp <- x$obj[worst]
  x$obj[worst] <- NA
  second.worst <- which.max(x$obj)
  x$obj[worst] <- temp
  # We will use the best, worst and second worst objective values below.
  f.best <- x$obj[best]
  f.worst <- x$obj[worst]
  f.second <- x$obj[second.worst]
#  cat(">>> Current obj = ", x$obj, " -- worst is index ", worst, "\n")
  # Calculate the centroid of the current simplex.
  center <- centroid(x$simplex)
  # Perform a reflection step to get a trial point and evaluate it.
  trial <- step(reflection, center, center - x$simplex[, worst])
  f.trial <- cost_function(trial)
  # Use the function value at the trial point to determine what to do next.
  if (f.trial < f.best) {
    # We have a new best vertex: try an expansion step to make it even better.
    trial2 <- step(expansion, center, trial - center)
    f.trial2 <- cost_function(trial2)
    if (f.trial2 < f.trial) {
      # The expansion step worked -- make it the new trial value.
      trial <- trial2
      f.trial <- f.trial2
#      cat("Expansion succeeded\n")
    } else {
      # The expansion step was worse, so stick with the trial value.
#      cat("Expansion failed\n")
    }
  } else if (f.trial >= f.second) {
    # The trial point is worse than the second worst corner of the current simplex. Try contracting.
#    cat("Contracting ...\n")
    trial2 <- step(contraction, center, x$simplex[, worst] - center)
    f.trial2 <- cost_function(trial2)
    if (f.trial2 < f.worst) {
      # Use the contracted point.
#      cat("Using contraction point ...\n")
      trial <- trial2
      f.trial <- f.trial2
    } else {
      # Abandon the trial point and resort to shrinking the polytope.
      f.trial <- NA
#      cat("Shrinking the polytope ...\n")
      result$simplex <- x$simplex[, best] + shrinking * (x$simplex - x$simplex[, best])
      result$obj <- apply(result$simplex, 2, cost_function)
    }
  } else {
    # We accept the trial point as-is.
#    cat("Accepting trial point\n")
  }
  # The trial point (if it survived) replaces the worst current vertex.
  if (is.na(f.trial)) {
    # Shrinkage occurred. Check whether it produced a new incumbent.
    best <- which.min(result$obj)
    if (result$obj[best] < result$incumbent.value) {
      cat("New incumbent with value ", result$obj[best], "\n")
      result$incumbent <- result$simplex[, best]
      result$incumbent.value <- result$obj[best]
    }
  } else {
    # Replace the previous worst vertex with the trial point.
#    cat("Trial value ", f.trial, " replaces obj value ", x$obj[worst], "\n")
    result$simplex[, worst] <- trial
    result$obj[worst] <- f.trial
    # See if the new point is a new incumbent.
    if (f.trial < x$incumbent.value) {
      # We have a new incumbent.
      cat("New incumbent with value ", f.trial, "\n")
      result$incumbent <- trial
      result$incumbent.value <- f.trial
    }
  }
#  cat("New obj vector = ", result$obj, "\n")
  result
}

Nelder-Mead solution

Our starting point is the unit simplex.

unit.simplex <- diag(dim)
unit.simplex.obj <- apply(unit.simplex, 2, cost_function)
temp <- which.min(unit.simplex.obj)
current <- list(simplex = unit.simplex, obj = unit.simplex.obj, incumbent = unit.simplex[, temp], incumbent.value = unit.simplex.obj[temp])
cat("Initial incumbent has objective value ", current$incumbent.value, "\n")
Initial incumbent has objective value  -4446458 

We will set two limits, one on the maximum number of iterations, and the other on the smallest change tolerated. If the maximum absolute change in any component of any vertex falls below the latter limit, we assume the algorithm has converged.

iteration.limit <- 100    # try at most 100 iterations
abs.diff.limit <- 0.0001  # stop if the biggest change in any component of any vertex is less than this

We perform Nelder-Mead steps until either a predefined limit of 100 steps is hit or the maximum absolute difference in consecutive simplices falls below 0.001.

# Nelder-Mead loop
steps <- 0
for (i in 1:iteration.limit) {
  steps <- steps + 1
  # Perform a Nelder-Mead iteration.
  temp <- nm(current)
  # Compute the change in the simplex (infinity norm).
  diff <- norm(temp$simplex - current$simplex, "M")
#  cat("Norm of difference = ", diff, "\n")
  # Update the current iterate.
  current <- temp
  # Break if changes are too small.
  if (diff < abs.diff.limit) {
    cat("Terminating due to small change in current solution.\n")
    break
  }
}
New incumbent with value  -4675058 
New incumbent with value  -4680306 
New incumbent with value  -4682931 
New incumbent with value  -4683001 
New incumbent with value  -4683095 
New incumbent with value  -4683097 
New incumbent with value  -4683099 
New incumbent with value  -4683104 
New incumbent with value  -4683104 
New incumbent with value  -4683105 
New incumbent with value  -4683105 
New incumbent with value  -4683106 
Terminating due to small change in current solution.
cat("Performed ", steps, " iterations.\n")
Performed  29  iterations.
cat("Incumbent solution = ", current$incumbent, "\n")
Incumbent solution =  0 0.2882197 0.7117803 
cat("Incumbent objective value = ", current$incumbent.value, "\n")
Incumbent objective value =  -4683106 

Genetic algorithm

Genetic algorithms generally assume unconstrained problems, but they can typically handle interval ranges for variables (by enforcing them during generation of new candidates and during mutation). Here we rely on the GA to preserve nonnegativity. Rather than ask the GA to handle the equation constraint, we define a new objective function which evaluates the original objective function on a scaled version of the GA’s solution. So if \(x\ge 0\) is the current GA solution as an \(n\)-vector and \(f\) is the original objective, the GA uses the objective function \[\hat{f}(x) = f\left(\frac{x}{\sum_{i=1}^n x_i}\right).\]

We will use the genalg R package.

library(genalg)

GA objective function

Now we define the scaled objective function that the GA will use.

obj_function <- function(x) {
  cost_function(x / sum(x))
}

GA solution

For reproducibility, we set the seed value for the random number generator.

set.seed(20200531)

Now we define and run the GA and extract the results.

# Run the GA.
results <- rbga(stringMin = rep(0, dim), stringMax = rep(1, dim), popSize = 200, iters = 100, evalFunc = obj_function, elitism = 10)
# Get the index of the best solution in the final population.
ix <- which.min(results$evaluations)
# Print the incumbent objective value.
cat("Incumbent objective value = ", results$evaluations[ix], "\n")
Incumbent objective value =  -4683175 
# Get and scale the incumbent, then print it.
incumbent <- results$population[ix, ] / sum(results$population[ix, ])
cat("Incumbent solution = ", incumbent, "\n")
Incumbent solution =  0.001182725 0.2869361 0.7118812 
# Confirm feasibility.
cat("Sum of incumbent weights = ", sum(incumbent), "\n")
Sum of incumbent weights =  1 
# Confirm the objective value.
cat("Original objective function evaluated at scaled incumbent = ", cost_function(incumbent), "\n")
Original objective function evaluated at scaled incumbent =  -4683175 

We can plot the results.

plot(results)

LS0tCnRpdGxlOiAiTmVsZGVyLU1lYWQiCm91dHB1dDogaHRtbF9ub3RlYm9vawphdXRob3I6IFBhdWwgQS4gUnViaW4gKHJ1YmluQG1zdS5lZHUpCi0tLQoKVGhpcyBub3RlYm9vayB1c2VzIGZpcnN0IHRoZSBOZWxkZXItTWVhZCAic2ltcGxleCIgKHBvbHl0b3BlKSBtZXRob2QgYW5kIHRoZW4gYSBnZW5ldGljIGFsZ29yaXRobSAoR0EpIHRvIHNlYXJjaCBmb3IgYSBtaW5pbXVtIG9mIGEgZnVuY3Rpb24uIE1vdGl2YXRpb24gY29tZXMgZnJvbSBhIHF1ZXN0aW9uIHBvc2VkIG9uIE9SIFN0YWNrIEV4Y2hhbmdlIChodHRwczovL29yLnN0YWNrZXhjaGFuZ2UuY29tL3F1ZXN0aW9ucy80MjQ4L2xpbmVhci1vcHRpbWl6YXRpb24tcHJvYmxlbS13aXRoLXVzZXItZGVmaW5lZC1jb3N0LWZ1bmN0aW9uKS4gVGhlIGZlYXNpYmxlIHJlZ2lvbiBmb3IgdGhhdCBwcm9ibGVtIGlzIGFuICRuLTEkKS1kaW1lbnNpb25hbCBzaW1wbGV4IGluICRuJC1zcGFjZSwgc3BlY2lmaWNhbGx5ICQkXGxicmFjZSB4XGluIFxSZV5uIDogeFxnZSAwLCBcc3VtX3tpPTF9Xm4geF9pID0gMSBccmJyYWNlLiQkCgojIE9iamVjdGl2ZSBmdW5jdGlvbgoKV2UgaW1wb3J0IHByb2JsZW0gaW5mb3JtYXRpb24gZnJvbSBhIHNhbXBsZSBwb3N0ZWQgb24gR2l0SHViIChodHRwczovL2dpdGh1Yi5jb20vZW1tYXBhcmtlcjk2L1dvcmtpbmdFeGFtcGxlRm9yU3RhY2tFeGNoYW5nZS9ibG9iL21hc3Rlci9FeGFtcGxlX1NMU1FQLnB5KS4gKERhdGUgaW1wb3J0ZWQ6IDI4IE1heSAyMDIwLikKCmBgYHtyfQpFMCA8LSBjKDAuMCwgMC4wLCAwLjAsIDAuMCwgMC4wLCAwLjAsIDAuMCwgMC4wLCAwLjAsIDAuMCwgMC4wLCAwLjAsIDAuMCwgMC4wLCAwLjAsIDAuMCwgMC4wLCAwLjAsIDAuMCwgMC4wLCAwLjAsIDAuMCwgMC4wLCAwLjAsIDAuMCwgMC4wLCAwLjAsIDAuMCwgMC4wLCAwLjAsIDEzNS45MzUyMDk2ODE0MzE4NCwgMjAzLjkwMjgxNDUyMjE0NzgyLCAyNzEuODcwNDE5MzYyODYzNywgNDI0Ljc5NzUzMDI1NDQ3NDYsIDU3Ny43MjQ2NDExNDYwODU0LCA3MzAuNjUxNzUyMDM3Njk2NCwgODgzLjU3ODg2MjkyOTMwNzIsIDg2Ni41ODY5NjE3MTkxMjc4LCA4NDkuNTk1MDYwNTA4OTQ5NCwgODMyLjYwMzE1OTI5ODc2OTksIDgxNS42MTEyNTgwODg1OTEzLCA4MTUuNjExMjU4MDg4NTkxMywgODE1LjYxMTI1ODA4ODU5MTMsIDgxNS42MTEyNTgwODg1OTEzLCA4MTUuNjExMjU4MDg4NTkxMywgOTE3LjU2MjY2NTM0OTY2NDgsIDEwMTkuNTE0MDcyNjEwNzM5LCAxMTIxLjQ2NTQ3OTg3MTgxMywgMTIyMy40MTY4ODcxMzI4ODY4LCAxMjQwLjQwODc4ODM0MzA2NTcsIDEyNTcuNDAwNjg5NTUzMjQ1LCAxMjc0LjM5MjU5MDc2MzQyMzYsIDEyOTEuMzg0NDkxOTczNjAyNywgMTIwNi40MjQ5ODU5MjI3MDc3LCAxMTIxLjQ2NTQ3OTg3MTgxMywgMTAzNi41MDU5NzM4MjA5MTgxLCA5NTEuNTQ2NDY3NzcwMDIzMiwgODE1LjYxMTI1ODA4ODU5MTMsIDY3OS42NzYwNDg0MDcxNTkyLCA1NDMuNzQwODM4NzI1NzI3NCwgNDA3LjgwNTYyOTA0NDI5NTY0LCAzMDUuODU0MjIxNzgzMjIxNywgMjAzLjkwMjgxNDUyMjE0NzgyLCAwLjAsIDAuMCwgMC4wLCAwLjAsIDAuMCwgMC4wLCAwLjAsIDAuMCwgMC4wLCAwLjAsIDAuMCwgMC4wLCAwLjAsIDAuMCwgMC4wLCAwLjAsIDAuMCwgMC4wLCAwLjAsIDAuMCwgMC4wLCAwLjAsIDAuMCwgMC4wLCAwLjAsIDAuMCwgMC4wLCAwLjAsIDAuMCwgMC4wLCAwLjAsIDAuMCwgMC4wLCAwLjAsIDAuMCwgMC4wLCAwLjApCkUxIDwtIGMoMC4wLCAwLjAsIDAuMCwgMC4wLCAwLjAsIDAuMCwgMC4wLCAwLjAsIDMuMDk1NTQxOTU5Mzk0OTUxLCAzLjA5NTU0MTk1OTM5NDk1MSwgMy4wOTU1NDE5NTkzOTQ5NTEsIDEzLjEyOTczOTEzODI3OTE2LCAxMy4xMjk3MzkxMzgyNzkxNiwgMTMuMTI5NzM5MTM4Mjc5MTYsIDEzLjEyOTczOTEzODI3OTE2LCAxMC41NTQ3NzU5MDI5MDUzNDEsIDEwLjU1NDc3NTkwMjkwNTM0MSwgMTAuNTU0Nzc1OTAyOTA1MzQxLCAxMC41NTQ3NzU5MDI5MDUzNDEsIDAuMCwgMC4wLCAwLjAsIDAuMCwgMC4wLCAxNi4xNDkzMzIzNzYzNDU4MDQsIDE2LjE0OTMzMjM3NjM0NTgwNCwgMTYuMTQ5MzMyMzc2MzQ1ODA0LCAxNi4xNDkzMzIzNzYzNDU4MDQsIDQyLjMxMjE3MDgzODMxOTI1LCA0Mi4zMTIxNzA4MzgzMTkyNSwgNDIuMzEyMTcwODM4MzE5MjUsIDE5LjY2MjAwOTczMDE1NzE0LCAxOS42NjIwMDk3MzAxNTcxNCwgMTkuNjYyMDA5NzMwMTU3MTQsIDE5LjY2MjAwOTczMDE1NzE0LCAyNy41MjA5MTM5NjkzNDk1NiwgMjcuNTIwOTEzOTY5MzQ5NTYsIDI3LjUyMDkxMzk2OTM0OTU2LCAyNy41MjA5MTM5NjkzNDk1NiwgMzI5LjIyMzcyOTk5NjkyNzcsIDMyOS4yMjM3Mjk5OTY5Mjc3LCAzMjkuMjIzNzI5OTk2OTI3NywgMzI5LjIyMzcyOTk5NjkyNzcsIDU3Ny45MTI0ODM4NTAyMzMzLCA1NzcuOTEyNDgzODUwMjMzMywgNTc3LjkxMjQ4Mzg1MDIzMzMsIDU3Ny45MTI0ODM4NTAyMzMzLCA1NzcuOTEyNDgzODUwMjMzMywgNTczLjA0NTI4NTQ1NzA3ODIsIDU3My4wNDUyODU0NTcwNzgyLCA1NzMuMDQ1Mjg1NDU3MDc4MiwgNTczLjA0NTI4NTQ1NzA3ODIsIDM3MC45MTc5MDYyMDAyMzk5NCwgMzcwLjkxNzkwNjIwMDIzOTk0LCAzNzAuOTE3OTA2MjAwMjM5OTQsIDM3MC45MTc5MDYyMDAyMzk5NCwgMzI5LjIyMzcyOTk5NjkyNzcsIDMyOS4yMjM3Mjk5OTY5Mjc3LCAzMjkuMjIzNzI5OTk2OTI3NywgMjkwLjU0MTExMTczNjg2MDUsIDI5MC41NDExMTE3MzY4NjA1LCAyOTAuNTQxMTExNzM2ODYwNSwgMjkwLjU0MTExMTczNjg2MDUsIDE2My40MTg5MzU4ODg0MjIyOCwgMTYzLjQxODkzNTg4ODQyMjI4LCAxNjMuNDE4OTM1ODg4NDIyMjgsIDE2My40MTg5MzU4ODg0MjIyOCwgMTE1LjMyMzMzNzg5Njg5ODYsIDExNS4zMjMzMzc4OTY4OTg2LCAxMTUuMzIzMzM3ODk2ODk4NiwgMTE1LjMyMzMzNzg5Njg5ODYsIDIwNi4yNTY5ODg5OTE0NDY5MiwgMjA2LjI1Njk4ODk5MTQ0NjkyLCAyMDYuMjU2OTg4OTkxNDQ2OTIsIDIwNi4yNTY5ODg5OTE0NDY5MiwgMzA5LjQ4MzY2NTc1MDM5MTE0LCAzMDkuNDgzNjY1NzUwMzkxMTQsIDMwOS40ODM2NjU3NTAzOTExNCwgMzA5LjQ4MzY2NTc1MDM5MTE0LCA2NDQuNDcyMzc2NTAwNDUzNiwgNjQ0LjQ3MjM3NjUwMDQ1MzYsIDY0NC40NzIzNzY1MDA0NTM2LCA2NDQuNDcyMzc2NTAwNDUzNiwgNTgxLjQ4MzI5OTUyMDkyNTYsIDU4MS40ODMyOTk1MjA5MjU2LCA1ODEuNDgzMjk5NTIwOTI1NiwgNTgxLjQ4MzI5OTUyMDkyNTYsIDU4MS40ODMyOTk1MjA5MjU2LCA2MTguMzQ4MzY0MTY5MjgxNSwgNjE4LjM0ODM2NDE2OTI4MTUsIDYxOC4zNDgzNjQxNjkyODE1LCA2MTguMzQ4MzY0MTY5MjgxNSwgNTg3LjEzODcwMzUzNDU5NTgsIDU4Ny4xMzg3MDM1MzQ1OTU4LCA1ODcuMTM4NzAzNTM0NTk1OCwgNTg3LjEzODcwMzUzNDU5NTgsIDU5Mi45NDAwMzI4MTUxNTY4LCA1OTIuOTQwMDMyODE1MTU2OCwgNTkyLjk0MDAzMjgxNTE1NjgsIDU5Mi45NDAwMzI4MTUxNTY4KQpFMiA8LSBjKDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDAuMCwgMC4wLCAwLjAsIDAuMCwgMC4wLCAwLjAsIDAuMCwgMC4wLCAwLjAsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDMxMS40NTE1NTM5NDY1NzUsIDAuMCwgMC4wLCAwLjAsIDAuMCwgMC4wLCAwLjApCkMgPC0gYygtMjM4LjA5NzkzMjY5Mzg4MDc4LCAtMjMxLjk4MDE0OTQ1NTU2ODg0LCAtMjI2LjQwMzg2MjEzNDYzMTYsIC0yMjEuNjc0MTc3NTY3NzYyMTcsIC0yMTcuMzc3MzA5MTQ0MTQzNzcsIC0yMTMuMzg1NTQ3NTU3MjE4NywgLTIwOS4yMDc5MzA4NzAxODcyNSwgLTIwNC42NTc1NDY3ODY2OTY5NCwgLTE5OS40NTkxMDE0MDQyMDEwMiwgLTE5My45NzgxNzMxODQ2ODM0NCwgLTE4OC44ODk0NjQ3NzI1NTc1LCAtMTg1LjI1MTY1MjQ4ODkwNjUsIC0xODMuMDEzNTY4MDM1NDA3ODcsIC0xODEuOTU0MDQ1OTU3MzI3MzcsIC0xODEuMDg0ODE5MjAzNTg3OCwgLTE3OS43ODI5ODc3NDU4NDY1MywgLTE3Ny40NTAzODk5NDc5MjUxNywgLTE3NS4wODY0OTkxNDExMTIxNCwgLTE3NC4yNzI2Njk0NzA2ODA3NywgLTE3Ni4wOTY3NTU4NzQxMTMzLCAtMTgxLjg2MDgwMTI0ODQwMDMsIC0xODkuNTI0MjA1Mzk4ODU5MTIsIC0xOTcuMjM5NjIzNjA0NjM3ODcsIC0yMDIuOTA2NjE4MzYzNTExLCAtMjA1LjEzNjQ1NjY4NjI4ODMsIC0yMDQuNzgxMjM4NzQ3NTE4NTMsIC0yMDMuNzU3NjYxMzQxODEzNSwgLTIwMy41ODMyMjM5NjExNjc3LCAtMjA1LjkxNzMwMTgzMzgzMzksIC0yMTAuMzcwMjEyNDIzNDExOTQsIC0yMTEuNDY2MTAyMDUyMzY2NCwgLTIxMC43NDYzNjI4NDc4NTkyMiwgLTIyMC4wMzM0MDg5OTM0NDQ3NywgLTIzMC42NTQ4NDgyNDExNTg4NSwgLTI0MS45NDEyNjM5Mjc4MTk4OCwgLTI1My45NjcyOTQxMDg0MTk0MiwgLTI2Ni4zMTc4ODM1MzY2NDQ4NCwgLTI3OC41MzQ2MzE5MjAwODM5LCAtMjkwLjA5Njc2NDM4Nzc5MDEsIC0zMDAuMDM3NTgwNjkyMTExNCwgLTMwOC4zNDk2ODA0NTkzMjM1NywgLTMxNS4zNzgxMzI1NDQyMzE0NSwgLTMyMS41MDM5NTA0NzQwMTU2LCAtMzI3Ljc0OTAyMDE0MDM4NjczLCAtMzM0LjQzMjgyNjI0ODk4ODIsIC0zNDAuOTQ3MDU4MDc5Njc3MSwgLTM0Ni41OTM1NDMyMzEzNzExNCwgLTM1MC42MDk2MjAzMzE5NjIwNSwgLTM1Mi4zOTkwMzA2OTg1MTQ3NiwgLTM1Mi4xMjA1NjUyMDcyMjkxNiwgLTM0OS40MDM1NzA4NTQxMzksIC0zNDQuNjU2MTI1MzkwMzMxMTcsIC0zMzcuOTkzNDYzMjA2NjU2NCwgLTMyOS41MjAwMzUyOTIyNTMwNiwgLTMxOS43MjU3NDYzODc2NzQyLCAtMzA4Ljk0OTc0NTA0ODc0NTMsIC0yOTcuNTM5NDI1OTYyMDEzNCwgLTI4Ni4zNTQwNzgyMzY1MDIzLCAtMjc2LjA5NDIwMDEwNTAzNTk1LCAtMjY3LjU4NzM2NDc4OTI0ODE3LCAtMjYxLjQ2NzI1NTcxOTE5NDMsIC0yNTcuMTA0NjI5Njg5MDUzNywgLTI1My45Mzg1MzgzNzA1MTg5MywgLTI1MS4wNjgyNTA1NjE3MDk4NywgLTI0OC4yNTk5MTQ0NTI5MzYxMywgLTI0Ni4yODE0NzczOTc1MzgyLCAtMjQ2LjU1OTk0Mjg4ODgyMzgsIC0yNTAuNTg4MjgzNDY1ODcyMTcsIC0yNjguMDAzMDU0MzUzMzA4NSwgLTI4NS4xNjMyNTIzODQ2MjY2LCAtMjk4LjU4NDU3MDE3MTE0MzgsIC0zMTEuOTc3OTc3OTc2NzU3MzYsIC0zMjMuOTEwOTc0ODg3Njc5MiwgLTMzNC44MTg3MDI4Nzg5MDE4MywgLTM0NS4wMDMwOTcxOTgzNzk1LCAtMzU1LjE0NDE0NjQ3MTc1NzQ0LCAtMzY1LjE5OTEzOTk3MDY4MzMsIC0zNzMuNjMwMDY4NTk1OTg0MSwgLTM3OC4wMDYyMjY3MzgwNzc4LCAtMzc1LjgyMDE1NjMzOTg5ODgsIC0zNjYuMDMwMDk2MjIwMzA1NSwgLTM1MS4wNjczODYzMDY2MjY3NiwgLTMzNC40MDY4MTkyMjEzMjgyNSwgLTMxOS40Mjc0MDU2MDY5NTc0NSwgLTMwOC43OTk2MjMxODE3NjUyNCwgLTMwMS42NjE4NTcwMDQ5ODU5LCAtMjk2LjI1OTU4NDE4NjE5NiwgLTI5MC44OTQzMTMyMzYwMjc4LCAtMjg0LjI3OTQzNjMyMjY4NzUsIC0yNzYuMzE0MzA4MzYzNTIzNiwgLTI2Ny4yNDI3MTg4MTI5NDE4NiwgLTI1Ny40NDc3OTU1OTA2MTUyLCAtMjQ3LjIxOTIxMDQ2ODA0MDQ3LCAtMjM3LjMyMzIxOTI4NDU2MzksIC0yMjguNTQ3NDMzMjQzNzA3NjIsIC0yMjEuNTIyNzg3MDY1Mjg2NTQsIC0yMzguMjAyODA2NTYxNTE3NTUsIC0yMzIuMDg1MDIzMzIzMjA1NywgLTIyNi40ODI1MTc1MzUzNTkyLCAtMjIxLjc1MjgzMjk2ODQ4OTc3KQpQIDwtIGMoMjI5Ljg5MDY1MTA1Njk0NTM2LCAyMjkuODkwNjUxMDU2OTQ1MzYsIDIyOS44OTA2NTEwNTY5NDUzNiwgMjI5Ljg5MDY1MTA1Njk0NTM2LCAyMjMuNTk3NDg2NDE3MDIxOSwgMjIzLjU5NzQ4NjQxNzAyMTksIDIyMy41OTc0ODY0MTcwMjE5LCAyMjMuNTk3NDg2NDE3MDIxOSwgMjIyLjY1MTI5ODEzNzA2MTUzLCAyMjIuNjUxMjk4MTM3MDYxNTMsIDIyMi42NTEyOTgxMzcwNjE1MywgMjIyLjY1MTI5ODEzNzA2MTUzLCAyMTguNjE2ODYxMDI1NDA0NiwgMjE4LjYxNjg2MTAyNTQwNDYsIDIxOC42MTY4NjEwMjU0MDQ2LCAyMTguNjE2ODYxMDI1NDA0NiwgMjE2LjA0ODc1OTQ2NTg1Njk2LCAyMTYuMDQ4NzU5NDY1ODU2OTYsIDIxNi4wNDg3NTk0NjU4NTY5NiwgMjE2LjA0ODc1OTQ2NTg1Njk2LCAyMTEuOTY0NzIwODgxNDQ4MTMsIDIxMS45NjQ3MjA4ODE0NDgxMywgMjExLjk2NDcyMDg4MTQ0ODEzLCAyMTEuOTY0NzIwODgxNDQ4MTMsIDIwOS4zNzE4MTA3MDIxNjcxOCwgMjA5LjM3MTgxMDcwMjE2NzE4LCAyMDkuMzcxODEwNzAyMTY3MTgsIDIwOS4zNzE4MTA3MDIxNjcxOCwgMjA1LjIzODM3Mjk2MzA2MzgyLCAyMDUuMjM4MzcyOTYzMDYzODIsIDIwNS4yMzgzNzI5NjMwNjM4MiwgMjA1LjIzODM3Mjk2MzA2MzgyLCAyMTAuMTM1NTk2NzYxNTc1MywgMjEwLjEzNTU5Njc2MTU3NTMsIDIxMC4xMzU1OTY3NjE1NzUzLCAyMTAuMTM1NTk2NzYxNTc1MywgMjAyLjIzMTQ1OTMwNjkxMzA1LCAyMDIuMjMxNDU5MzA2OTEzMDUsIDIwMi4yMzE0NTkzMDY5MTMwNSwgMjAyLjIzMTQ1OTMwNjkxMzA1LCAxOTIuNjE1NjIzMjY5NTUzNDgsIDE5Mi42MTU2MjMyNjk1NTM0OCwgMTkyLjYxNTYyMzI2OTU1MzQ4LCAxOTIuNjE1NjIzMjY5NTUzNDgsIDE5MC45OTE0NTc4NjA4ODg5NywgMTkwLjk5MTQ1Nzg2MDg4ODk3LCAxOTAuOTkxNDU3ODYwODg4OTcsIDE5MC45OTE0NTc4NjA4ODg5NywgMTg4LjgwNTEyMzY3ODM0OSwgMTg4LjgwNTEyMzY3ODM0OSwgMTg4LjgwNTEyMzY3ODM0OSwgMTg4LjgwNTEyMzY3ODM0OSwgMTg3LjE3MzIxNzgzMjA0NTgyLCAxODcuMTczMjE3ODMyMDQ1ODIsIDE4Ny4xNzMyMTc4MzIwNDU4MiwgMTg3LjE3MzIxNzgzMjA0NTgyLCAxODkuNjc0NjU4MzMzOTI1NzUsIDE4OS42NzQ2NTgzMzM5MjU3NSwgMTg5LjY3NDY1ODMzMzkyNTc1LCAxODkuNjc0NjU4MzMzOTI1NzUsIDE4OS4zMTc5MjY0MjkwMTgyOSwgMTg5LjMxNzkyNjQyOTAxODI5LCAxODkuMzE3OTI2NDI5MDE4MjksIDE4OS4zMTc5MjY0MjkwMTgyOSwgMTkxLjEzMDg0NjMyODc5NTM0LCAxOTEuMTMwODQ2MzI4Nzk1MzQsIDE5MS4xMzA4NDYzMjg3OTUzNCwgMTkxLjEzMDg0NjMyODc5NTM0LCAxODguOTY1Njg4MTgwNjE4OSwgMTg4Ljk2NTY4ODE4MDYxODksIDE4OC45NjU2ODgxODA2MTg5LCAxODguOTY1Njg4MTgwNjE4OSwgMTg5Ljg0MjkwMDIxMzk2MTQzLCAxODkuODQyOTAwMjEzOTYxNDMsIDE4OS44NDI5MDAyMTM5NjE0MywgMTg5Ljg0MjkwMDIxMzk2MTQzLCAxODYuMDEzNTM2ODI0MjcyODgsIDE4Ni4wMTM1MzY4MjQyNzI4OCwgMTg2LjAxMzUzNjgyNDI3Mjg4LCAxODYuMDEzNTM2ODI0MjcyODgsIDE4Ni45NzA0NTExOTY2MTY5MiwgMTg2Ljk3MDQ1MTE5NjYxNjkyLCAxODYuOTcwNDUxMTk2NjE2OTIsIDE4Ni45NzA0NTExOTY2MTY5MiwgMTkyLjIxMDQwNTAzNDk2NzcsIDE5Mi4yMTA0MDUwMzQ5Njc3LCAxOTIuMjEwNDA1MDM0OTY3NywgMTkyLjIxMDQwNTAzNDk2NzcsIDE5My43NzgyMzI1OTc5NjE4NywgMTkzLjc3ODIzMjU5Nzk2MTg3LCAxOTMuNzc4MjMyNTk3OTYxODcsIDE5My43NzgyMzI1OTc5NjE4NywgMjEwLjEzMTUyNDMxNDgzMzUsIDIxMC4xMzE1MjQzMTQ4MzM1LCAyMTAuMTMxNTI0MzE0ODMzNSwgMjEwLjEzMTUyNDMxNDgzMzUsIDIwOS43NDMzODM0MjAwOTMsIDIwOS43NDMzODM0MjAwOTMsIDIwOS43NDMzODM0MjAwOTMsIDIwOS43NDMzODM0MjAwOTMpCmBgYAoKV2UgaW1wb3J0IHRoZSBvYmplY3RpdmUgZnVuY3Rpb24gZnJvbSB0aGUgc2FtZSBzb3VyY2UsIHVzaW5nIHRoZSAic2ltcGxpZmllZCIgdmVyc2lvbix3aGljaCBoYW5kbGVzIHplcm8gYXJndW1lbnRzIGJldHRlciB0aGFuIHRoZSBvcmlnaW5hbC4gKERhdGUgaW1wb3J0ZWQ6IDI5IE1heSAyMDIwLikgSW5kaWNlcyBhcmUgYWRqdXN0ZWQgdG8gYWNjb3VudCBmb3IgUHl0aG9uIHVzaW5nIDAtYmFzZWQgaW5kZXhpbmcgYW5kIFIgdXNpbmcgMS1iYXNlZCBpbmRleGluZy4KCmBgYHtyfQpjb3N0X2Z1bmN0aW9uIDwtIGZ1bmN0aW9uKHgwKSB7CiAgdmFsdWVfdG9fbWluaW1pemUgPC0gIDAuMAogIGZvciAoaSBpbiBzZXFfYWxvbmcoRTApKSB7CiAgICBlIDwtICB4MFsxXSAqIEUwW2ldICsgeDBbMl0gKiBFMVtpXSArIHgwWzNdICogRTJbaV0KICAgIHYgPC0gICgwLjAxICogKHgwWzFdICogRTBbaV0pICsgMC4xMiAqICh4MFsyXSAqIEUxW2ldKSArIDAuMzUgKiAoeDBbM10gKiBFMltpXSkpIC8gZQogICAgaWYgKGlzLm5hbih2KSkgdiA8LSAwCiAgICB2YWx1ZV90b19taW5pbWl6ZSA8LSB2YWx1ZV90b19taW5pbWl6ZSArIG1pbigtQ1tpXSwgZSkgKiAoUFtpXSAtIHYpCiAgfQogIC12YWx1ZV90b19taW5pbWl6ZQp9CmBgYAoKRm9yIHJlYWRhYmlsaXR5LCB3ZSBzcGVjaWZ5IHRoZSBkaW1lbnNpb24gb2YgdGhlIGV4YW1wbGUgYXMgYSBzeW1ib2wuCgpgYGB7cn0KZGltIDwtIDMKYGBgCgojIEJlbmNobWFya3MKCkEgc29sdXRpb24gd2FzIHJlcG9ydGVkIGJ5IHRoZSBwcm9kdWNlcnMgb2YgTG9jYWxTb2x2ZXIuIFRoZXkgY2xhaW0gYW4gb2JqZWN0aXZlIHZhbHVlIG9mIC00NjgzMTU1LjIxNjI1NDczLgoKYGBge3J9CmxvY2FsLnNvbHZlciA8LSBjKDAuMDAxMjE1NzYzMjUwMDc2NSwgMC4yODYwNzA2NjUzNDg4NDMsIDAuNzEyNzEzNTcxNDA3NTI2KQpjb3N0X2Z1bmN0aW9uKGxvY2FsLnNvbHZlcikKYGBgCgpFbW1hLCB0aGUgb3JpZ2luYWwgcG9zdGVyLCByZXBvcnRlZCB0aGUgZm9sbG93aW5nIHNvbHV0aW9uICh3aXRob3V0IHNwZWNpZnlpbmcgYW4gb2JqZWN0aXZlIHZhbHVlKS4KCmBgYHtyfQplbW1hIDwtIGMoMC4xNzAyMzk3NSwgMC4xOTUzMjkyOCwgMC42NDI5NjUwNykKY29zdF9mdW5jdGlvbihlbW1hKQpgYGAKCkVtbWEncyBzb2x1dGlvbiBpcyBhY3R1YWxseSBub3QgcXVpdGUgZmVhc2libGUgKHRoZSBzdW0gYmVpbmcgc2xpZ2h0bHkgZ3JlYXRlciB0aGFuIDEpLgoKYGBge3J9CnN1bShlbW1hKQpgYGAKCiMgTmVsZGVyLU1lYWQgYWxnb3JpdGhtCgpUaGVyZSBpcyBhIG5lbGRlcm1lYWQgcGFja2FnZSBpbiBDUkFOIHdoaWNoIGRpZCBub3Qgc2VlbSB0byB3b3JrLCBhbmQgYSBmZXcgcGFja2FnZXMgd2l0aCBOZWxkZXItTWVhZCBhbGdvcml0aG1zIHRoYXQgYXBwZWFyIHJlc3RyaWN0ZWQgdG8gb25lIGRpbWVuc2lvbmFsIGxpbmVzIHNlYXJjaGVzLiBTbyB3ZSB3aWxsIGNvZGUgdGhlIGFsZ29yaXRobSBhcyBwcmVzZW50ZWQgIGF0IGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL05lbGRlciVFMiU4MCU5M01lYWRfbWV0aG9kLgoKU2luY2UgTmVsZGVyLU1lYWQgc3RhcnRzIHdpdGggYSBwb2x5dG9wZSBhbmQgbW9kaWZpZXMgaXRzIHZlcnRpY2VzIHVzaW5nIGxpbmVhciBjb21iaW5hdGlvbnMgb2YgdGhlIGV4aXN0aW5nIHZlcnRpY2VzIGFuZCB0aGUgY2VudGVyIG9mIHRoZSBwb2x5dG9wZSwgaXQgd2lsbCBhdXRvbWF0aWNhbGx5IHJlbWFpbiBvbiB0aGUgaHlwZXJwbGFuZS4gU3RlcCBzaXplcyBtYXkgbmVlZCB0byBiZSBhZGp1c3RlZCB0byBwcmVzZXJ2ZSBub25uZWdhdGl2aXR5IG9mIGFsbCB2ZXJ0aWNlcy4KCiMjIEhlbHBlciBmdW5jdGlvbnMKClRoZSBhbGdvcml0aG0gcmVxdWlyZXMgY2FsY3VsYXRpbmcgdGhlIGNlbnRyb2lkIG9mIHByb2dyZXNzaXZlIHNpbXBsaWNlcywgc28gd2UgY3JlYXRlIGEgZnVuY3Rpb24gZm9yIHRoYXQuCgpgYGB7cn0KY2VudHJvaWQgPC0gZnVuY3Rpb24ocykgeyAgIyBzIGlzIHRoZSBzaW1wbGV4CiAgYXBwbHkocywgMSwgbWVhbikKfQpgYGAKCkF0IHZhcmlvdXMgcG9pbnRzIHRoZSBhbGdvcml0aG0gdGFrZXMgYSBzdGVwIGluIGEgc3BlY2lmaWVkIGRpcmVjdGlvbiwgc3RhcnRpbmcgZnJvbSBhIHBvaW50IGluIHRoZSBjdXJyZW50IHBvbHlnb24uIFRoZSBOZWxkZXItTWVhZCB2ZXJzaW9uIHVzZWQgaGVyZSBtaWdodCByZXN1bHQgaW4gc2lnbiB2aW9sYXRpb25zIGlmIHN0ZXAgc2l6ZXMgYXJlIHRvbyBsYXJnZS4gVG8gYXZvaWQgdGhhdCwgd2UgdXNlIGEgZnVuY3Rpb24gdG8gY29tcHV0ZSBhICJzYWZlIiBzdGVwIHNpemUsIHNocmlua2luZyB0aGUgcHJvcG9zZWQgc3RlcCBzaXplIGlmIG5lY2Vzc2FyeSB0byBwcmVzZXJ2ZSBub25uZWdhdGl2aXR5LCBhbmQgdGhlbiB0YWtlIHRoZSBkZXNpZ25hdGVkIHN0ZXAuCgpgYGB7cn0Kc3RlcCA8LSBmdW5jdGlvbihzdGVwX3NpemUsIG9yaWdpbiwgZGlyZWN0aW9uKSB7CiAgIyBBcmd1bWVudHM6CiAgIyAgc3RlcF9zaXplID0gdGhlIHByb3Bvc2VkIHN0ZXAgc2l6ZTsKICAjICBvcmlnaW4gPSB0aGUgc3RhcnRpbmcgcG9pbnQgZm9yIHRoZSBzdGVwOwogICMgIGRpcmVjdGlvbiA9IHRoZSBkaXJlY3Rpb24gb2YgdGhlIHN0ZXAuCiAgIyBSZXR1cm4gdmFsdWUgPSB0aGUgcmVzdWx0IG9mIHRoZSBzdGVwIChndWFyYW50ZWVkIHRvIHJlbWFpbiBmZWFzaWJsZSkuCiAgaSA8LSBkaXJlY3Rpb24gPCAwICAjIGluZGljZXMgb2YgY29tcG9uZW50cyB3aGVyZSBkaXJlY3Rpb24gaXMgbmVnYXRpdmUKICBzIDwtIG1pbihzdGVwX3NpemUsIC1vcmlnaW5baV0gLyBkaXJlY3Rpb25baV0pICMgc2FmZSBzdGVwIHNpemUKICBvcmlnaW4gKyBzICogZGlyZWN0aW9uICAjIHJlc3VsdGluZyB2ZWN0b3IKfQpgYGAKClRoZSBgbm1gIGZ1bmN0aW9uIHdpbGwgcGVyZm9ybSBhIHNpbmdsZSBpdGVyYXRpb24gb2YgdGhlIE5lbGRlci1NZWFkIGFsZ29yaXRobS4gSXQgdGFrZXMgYSBsaXN0IGNvbnRhaW5pbmcgdGhlIGN1cnJlbnQgc2ltcGxleCwgdGhlIHZlY3RvciBvZiBvYmplY3RpdmUgdmFsdWVzIGZvciB0aGUgY29ybmVycywgdGhlIGN1cnJlbnQgaW5jdW1iZW50IGFuZCB0aGUgY3VycmVudCBpbmN1bWJlbnQgb2JqZWN0aXZlIHZhbHVlIGFzIGlucHV0IGFuZCByZXR1cm5zIGEgbW9kaWZpZWQgbGlzdCB3aXRoIHRoZSBzYW1lIGl0ZW1zLiBUaGUgc3RlcCBzaXplIGFyZ3VtZW50cyBkZWZhdWx0IHRvIHZhbHVlcyBkZXNjcmliZWQgYXMgInN0YW5kYXJkIiBpbiB0aGUgV2lraXBlZGlhIHBhZ2UuCgpgYGB7cn0Kbm0gPC0gZnVuY3Rpb24oeCwgcmVmbGVjdGlvbiA9IDEuMCwgZXhwYW5zaW9uID0gMi4wLCBjb250cmFjdGlvbiA9IDAuNSwgc2hyaW5raW5nID0gMC41KSB7IAogICMgQXJndW1lbnRzOgogICMgICB4ID0gbGlzdCBjb250YWluaW5nIHRoZSBzaW1wbGV4IHZlcnRpY2VzLCB0aGVpciBvYmplY3RpdmUgdmFsdWVzLCB0aGUgY3VycmVudCBpbmN1bWJlbnQgYW5kIGl0cyBvYmplY3RpdmUgdmFsdWUKICAjICAgcmVmbGVjdGlvbiA9IHN0ZXAgc2l6ZSBmb3IgcmVmbGVjdGlvbiBzdGVwcyAoJFxhbHBoYSQgaW4gV2lraXBlZGlhIHBhZ2UpCiAgIyAgIGV4cGFuc2lvbiA9IHN0ZXAgc2l6ZSBmb3IgZXhwYW5zaW9uIHN0ZXBzICgkXGdhbW1hJCBpbiBXaWtpcGVkaWEgcGFnZSkKICAjICAgY29udHJhY3Rpb24gPSBzdGVwIHNpemUgZm9yIGNvbnRyYWN0aW9uIHN0ZXBzICgkXHJobyQgaW4gV2lraXBlZGlhIHBhZ2UpCiAgIyAgIHNocmlua2luZyA9IGZhY3RvciBmb3Igc2hyaW5raW5nIHRoZSBwb2x5dG9wZSAoJFxzaWdtYSQgaW4gV2lraXBlZGlhIHBhZ2UpCiAgIyBSZXR1cm4gdmFsdWU6IGEgbW9kaWZpZWQgdmVyc2lvbiBvZiB4LgogICMKICAjIFNldCB1cCBhIHJldHVybiBsaXN0LgogIHJlc3VsdCA9IGxpc3Qoc2ltcGxleCA9IHgkc2ltcGxleCwgb2JqID0geCRvYmosIGluY3VtYmVudCA9IHgkaW5jdW1iZW50LCBpbmN1bWJlbnQudmFsdWUgPSB4JGluY3VtYmVudC52YWx1ZSkKICAjIElkZW50aWZ5IHRoZSBiZXN0IGFuZCB3b3JzdCBjb3JuZXJzIG9mIHRoZSBjdXJyZW50IHNpbXBsZXguCiAgYmVzdCA8LSB3aGljaC5taW4oeCRvYmopICAgIyBpbmRleCBvZiBiZXN0IGNvcm5lcgogIHdvcnN0IDwtIHdoaWNoLm1heCh4JG9iaikgICMgaW5kZXggb2YgdGhlIHdvcnN0IGNvcm5lcgogICMgV2UgYWxzbyBuZWVkIHRoZSBpbmRleCBvZiB0aGUgc2Vjb25kIHdvcnN0IGNvcm5lciwgd2hpY2ggd2UgZ2V0IGJ5IHRlbXBvcmFyaWx5IHphcHBpbmcgdGhlIHdvcnN0IGVudHJ5LCBmaW5kaW5nIHRoZSB3b3JzdCBzdXJ2aXZpbmcgZW50cnksIHRoZW4gcmVzdG9yaW5nIHRoZSB3b3JzdCBlbnRyeS4KICB0ZW1wIDwtIHgkb2JqW3dvcnN0XQogIHgkb2JqW3dvcnN0XSA8LSBOQQogIHNlY29uZC53b3JzdCA8LSB3aGljaC5tYXgoeCRvYmopCiAgeCRvYmpbd29yc3RdIDwtIHRlbXAKICAjIFdlIHdpbGwgdXNlIHRoZSBiZXN0LCB3b3JzdCBhbmQgc2Vjb25kIHdvcnN0IG9iamVjdGl2ZSB2YWx1ZXMgYmVsb3cuCiAgZi5iZXN0IDwtIHgkb2JqW2Jlc3RdCiAgZi53b3JzdCA8LSB4JG9ialt3b3JzdF0KICBmLnNlY29uZCA8LSB4JG9ialtzZWNvbmQud29yc3RdCiMgIGNhdCgiPj4+IEN1cnJlbnQgb2JqID0gIiwgeCRvYmosICIgLS0gd29yc3QgaXMgaW5kZXggIiwgd29yc3QsICJcbiIpCiAgIyBDYWxjdWxhdGUgdGhlIGNlbnRyb2lkIG9mIHRoZSBjdXJyZW50IHNpbXBsZXguCiAgY2VudGVyIDwtIGNlbnRyb2lkKHgkc2ltcGxleCkKICAjIFBlcmZvcm0gYSByZWZsZWN0aW9uIHN0ZXAgdG8gZ2V0IGEgdHJpYWwgcG9pbnQgYW5kIGV2YWx1YXRlIGl0LgogIHRyaWFsIDwtIHN0ZXAocmVmbGVjdGlvbiwgY2VudGVyLCBjZW50ZXIgLSB4JHNpbXBsZXhbLCB3b3JzdF0pCiAgZi50cmlhbCA8LSBjb3N0X2Z1bmN0aW9uKHRyaWFsKQogICMgVXNlIHRoZSBmdW5jdGlvbiB2YWx1ZSBhdCB0aGUgdHJpYWwgcG9pbnQgdG8gZGV0ZXJtaW5lIHdoYXQgdG8gZG8gbmV4dC4KICBpZiAoZi50cmlhbCA8IGYuYmVzdCkgewogICAgIyBXZSBoYXZlIGEgbmV3IGJlc3QgdmVydGV4OiB0cnkgYW4gZXhwYW5zaW9uIHN0ZXAgdG8gbWFrZSBpdCBldmVuIGJldHRlci4KICAgIHRyaWFsMiA8LSBzdGVwKGV4cGFuc2lvbiwgY2VudGVyLCB0cmlhbCAtIGNlbnRlcikKICAgIGYudHJpYWwyIDwtIGNvc3RfZnVuY3Rpb24odHJpYWwyKQogICAgaWYgKGYudHJpYWwyIDwgZi50cmlhbCkgewogICAgICAjIFRoZSBleHBhbnNpb24gc3RlcCB3b3JrZWQgLS0gbWFrZSBpdCB0aGUgbmV3IHRyaWFsIHZhbHVlLgogICAgICB0cmlhbCA8LSB0cmlhbDIKICAgICAgZi50cmlhbCA8LSBmLnRyaWFsMgojICAgICAgY2F0KCJFeHBhbnNpb24gc3VjY2VlZGVkXG4iKQogICAgfSBlbHNlIHsKICAgICAgIyBUaGUgZXhwYW5zaW9uIHN0ZXAgd2FzIHdvcnNlLCBzbyBzdGljayB3aXRoIHRoZSB0cmlhbCB2YWx1ZS4KIyAgICAgIGNhdCgiRXhwYW5zaW9uIGZhaWxlZFxuIikKICAgIH0KICB9IGVsc2UgaWYgKGYudHJpYWwgPj0gZi5zZWNvbmQpIHsKICAgICMgVGhlIHRyaWFsIHBvaW50IGlzIHdvcnNlIHRoYW4gdGhlIHNlY29uZCB3b3JzdCBjb3JuZXIgb2YgdGhlIGN1cnJlbnQgc2ltcGxleC4gVHJ5IGNvbnRyYWN0aW5nLgojICAgIGNhdCgiQ29udHJhY3RpbmcgLi4uXG4iKQogICAgdHJpYWwyIDwtIHN0ZXAoY29udHJhY3Rpb24sIGNlbnRlciwgeCRzaW1wbGV4Wywgd29yc3RdIC0gY2VudGVyKQogICAgZi50cmlhbDIgPC0gY29zdF9mdW5jdGlvbih0cmlhbDIpCiAgICBpZiAoZi50cmlhbDIgPCBmLndvcnN0KSB7CiAgICAgICMgVXNlIHRoZSBjb250cmFjdGVkIHBvaW50LgojICAgICAgY2F0KCJVc2luZyBjb250cmFjdGlvbiBwb2ludCAuLi5cbiIpCiAgICAgIHRyaWFsIDwtIHRyaWFsMgogICAgICBmLnRyaWFsIDwtIGYudHJpYWwyCiAgICB9IGVsc2UgewogICAgICAjIEFiYW5kb24gdGhlIHRyaWFsIHBvaW50IGFuZCByZXNvcnQgdG8gc2hyaW5raW5nIHRoZSBwb2x5dG9wZS4KICAgICAgZi50cmlhbCA8LSBOQQojICAgICAgY2F0KCJTaHJpbmtpbmcgdGhlIHBvbHl0b3BlIC4uLlxuIikKICAgICAgcmVzdWx0JHNpbXBsZXggPC0geCRzaW1wbGV4WywgYmVzdF0gKyBzaHJpbmtpbmcgKiAoeCRzaW1wbGV4IC0geCRzaW1wbGV4WywgYmVzdF0pCiAgICAgIHJlc3VsdCRvYmogPC0gYXBwbHkocmVzdWx0JHNpbXBsZXgsIDIsIGNvc3RfZnVuY3Rpb24pCiAgICB9CiAgfSBlbHNlIHsKICAgICMgV2UgYWNjZXB0IHRoZSB0cmlhbCBwb2ludCBhcy1pcy4KIyAgICBjYXQoIkFjY2VwdGluZyB0cmlhbCBwb2ludFxuIikKICB9CiAgIyBUaGUgdHJpYWwgcG9pbnQgKGlmIGl0IHN1cnZpdmVkKSByZXBsYWNlcyB0aGUgd29yc3QgY3VycmVudCB2ZXJ0ZXguCiAgaWYgKGlzLm5hKGYudHJpYWwpKSB7CiAgICAjIFNocmlua2FnZSBvY2N1cnJlZC4gQ2hlY2sgd2hldGhlciBpdCBwcm9kdWNlZCBhIG5ldyBpbmN1bWJlbnQuCiAgICBiZXN0IDwtIHdoaWNoLm1pbihyZXN1bHQkb2JqKQogICAgaWYgKHJlc3VsdCRvYmpbYmVzdF0gPCByZXN1bHQkaW5jdW1iZW50LnZhbHVlKSB7CiAgICAgIGNhdCgiTmV3IGluY3VtYmVudCB3aXRoIHZhbHVlICIsIHJlc3VsdCRvYmpbYmVzdF0sICJcbiIpCiAgICAgIHJlc3VsdCRpbmN1bWJlbnQgPC0gcmVzdWx0JHNpbXBsZXhbLCBiZXN0XQogICAgICByZXN1bHQkaW5jdW1iZW50LnZhbHVlIDwtIHJlc3VsdCRvYmpbYmVzdF0KICAgIH0KICB9IGVsc2UgewogICAgIyBSZXBsYWNlIHRoZSBwcmV2aW91cyB3b3JzdCB2ZXJ0ZXggd2l0aCB0aGUgdHJpYWwgcG9pbnQuCiMgICAgY2F0KCJUcmlhbCB2YWx1ZSAiLCBmLnRyaWFsLCAiIHJlcGxhY2VzIG9iaiB2YWx1ZSAiLCB4JG9ialt3b3JzdF0sICJcbiIpCiAgICByZXN1bHQkc2ltcGxleFssIHdvcnN0XSA8LSB0cmlhbAogICAgcmVzdWx0JG9ialt3b3JzdF0gPC0gZi50cmlhbAogICAgIyBTZWUgaWYgdGhlIG5ldyBwb2ludCBpcyBhIG5ldyBpbmN1bWJlbnQuCiAgICBpZiAoZi50cmlhbCA8IHgkaW5jdW1iZW50LnZhbHVlKSB7CiAgICAgICMgV2UgaGF2ZSBhIG5ldyBpbmN1bWJlbnQuCiAgICAgIGNhdCgiTmV3IGluY3VtYmVudCB3aXRoIHZhbHVlICIsIGYudHJpYWwsICJcbiIpCiAgICAgIHJlc3VsdCRpbmN1bWJlbnQgPC0gdHJpYWwKICAgICAgcmVzdWx0JGluY3VtYmVudC52YWx1ZSA8LSBmLnRyaWFsCiAgICB9CiAgfQojICBjYXQoIk5ldyBvYmogdmVjdG9yID0gIiwgcmVzdWx0JG9iaiwgIlxuIikKICByZXN1bHQKfQpgYGAKCiMjIE5lbGRlci1NZWFkIHNvbHV0aW9uCgpPdXIgc3RhcnRpbmcgcG9pbnQgaXMgdGhlIHVuaXQgc2ltcGxleC4KCmBgYHtyfQp1bml0LnNpbXBsZXggPC0gZGlhZyhkaW0pCnVuaXQuc2ltcGxleC5vYmogPC0gYXBwbHkodW5pdC5zaW1wbGV4LCAyLCBjb3N0X2Z1bmN0aW9uKQp0ZW1wIDwtIHdoaWNoLm1pbih1bml0LnNpbXBsZXgub2JqKQpjdXJyZW50IDwtIGxpc3Qoc2ltcGxleCA9IHVuaXQuc2ltcGxleCwgb2JqID0gdW5pdC5zaW1wbGV4Lm9iaiwgaW5jdW1iZW50ID0gdW5pdC5zaW1wbGV4WywgdGVtcF0sIGluY3VtYmVudC52YWx1ZSA9IHVuaXQuc2ltcGxleC5vYmpbdGVtcF0pCmNhdCgiSW5pdGlhbCBpbmN1bWJlbnQgaGFzIG9iamVjdGl2ZSB2YWx1ZSAiLCBjdXJyZW50JGluY3VtYmVudC52YWx1ZSwgIlxuIikKYGBgCgpXZSB3aWxsIHNldCB0d28gbGltaXRzLCBvbmUgb24gdGhlIG1heGltdW0gbnVtYmVyIG9mIGl0ZXJhdGlvbnMsIGFuZCB0aGUgb3RoZXIgb24gdGhlIHNtYWxsZXN0IGNoYW5nZSB0b2xlcmF0ZWQuIElmIHRoZSBtYXhpbXVtIGFic29sdXRlIGNoYW5nZSBpbiBhbnkgY29tcG9uZW50IG9mIGFueSB2ZXJ0ZXggZmFsbHMgYmVsb3cgdGhlIGxhdHRlciBsaW1pdCwgd2UgYXNzdW1lIHRoZSBhbGdvcml0aG0gaGFzIGNvbnZlcmdlZC4KCmBgYHtyfQppdGVyYXRpb24ubGltaXQgPC0gMTAwICAgICMgdHJ5IGF0IG1vc3QgMTAwIGl0ZXJhdGlvbnMKYWJzLmRpZmYubGltaXQgPC0gMC4wMDAxICAjIHN0b3AgaWYgdGhlIGJpZ2dlc3QgY2hhbmdlIGluIGFueSBjb21wb25lbnQgb2YgYW55IHZlcnRleCBpcyBsZXNzIHRoYW4gdGhpcwpgYGAKCldlIHBlcmZvcm0gTmVsZGVyLU1lYWQgc3RlcHMgdW50aWwgZWl0aGVyIGEgcHJlZGVmaW5lZCBsaW1pdCBvZiAxMDAgc3RlcHMgaXMgaGl0IG9yIHRoZSBtYXhpbXVtIGFic29sdXRlIGRpZmZlcmVuY2UgaW4gY29uc2VjdXRpdmUgc2ltcGxpY2VzIGZhbGxzIGJlbG93IDAuMDAxLgoKYGBge3J9CiMgTmVsZGVyLU1lYWQgbG9vcApzdGVwcyA8LSAwCmZvciAoaSBpbiAxOml0ZXJhdGlvbi5saW1pdCkgewogIHN0ZXBzIDwtIHN0ZXBzICsgMQogICMgUGVyZm9ybSBhIE5lbGRlci1NZWFkIGl0ZXJhdGlvbi4KICB0ZW1wIDwtIG5tKGN1cnJlbnQpCiAgIyBDb21wdXRlIHRoZSBjaGFuZ2UgaW4gdGhlIHNpbXBsZXggKGluZmluaXR5IG5vcm0pLgogIGRpZmYgPC0gbm9ybSh0ZW1wJHNpbXBsZXggLSBjdXJyZW50JHNpbXBsZXgsICJNIikKIyAgY2F0KCJOb3JtIG9mIGRpZmZlcmVuY2UgPSAiLCBkaWZmLCAiXG4iKQogICMgVXBkYXRlIHRoZSBjdXJyZW50IGl0ZXJhdGUuCiAgY3VycmVudCA8LSB0ZW1wCiAgIyBCcmVhayBpZiBjaGFuZ2VzIGFyZSB0b28gc21hbGwuCiAgaWYgKGRpZmYgPCBhYnMuZGlmZi5saW1pdCkgewogICAgY2F0KCJUZXJtaW5hdGluZyBkdWUgdG8gc21hbGwgY2hhbmdlIGluIGN1cnJlbnQgc29sdXRpb24uXG4iKQogICAgYnJlYWsKICB9Cn0KY2F0KCJQZXJmb3JtZWQgIiwgc3RlcHMsICIgaXRlcmF0aW9ucy5cbiIpCmNhdCgiSW5jdW1iZW50IHNvbHV0aW9uID0gIiwgY3VycmVudCRpbmN1bWJlbnQsICJcbiIpCmNhdCgiSW5jdW1iZW50IG9iamVjdGl2ZSB2YWx1ZSA9ICIsIGN1cnJlbnQkaW5jdW1iZW50LnZhbHVlLCAiXG4iKQpgYGAKCiMgR2VuZXRpYyBhbGdvcml0aG0KCkdlbmV0aWMgYWxnb3JpdGhtcyBnZW5lcmFsbHkgYXNzdW1lIHVuY29uc3RyYWluZWQgcHJvYmxlbXMsIGJ1dCB0aGV5IGNhbiB0eXBpY2FsbHkgaGFuZGxlIGludGVydmFsIHJhbmdlcyBmb3IgdmFyaWFibGVzIChieSBlbmZvcmNpbmcgdGhlbSBkdXJpbmcgZ2VuZXJhdGlvbiBvZiBuZXcgY2FuZGlkYXRlcyBhbmQgZHVyaW5nIG11dGF0aW9uKS4gSGVyZSB3ZSByZWx5IG9uIHRoZSBHQSB0byBwcmVzZXJ2ZSBub25uZWdhdGl2aXR5LiBSYXRoZXIgdGhhbiBhc2sgdGhlIEdBIHRvIGhhbmRsZSB0aGUgZXF1YXRpb24gY29uc3RyYWludCwgd2UgZGVmaW5lIGEgbmV3IG9iamVjdGl2ZSBmdW5jdGlvbiB3aGljaCBldmFsdWF0ZXMgdGhlIG9yaWdpbmFsIG9iamVjdGl2ZSBmdW5jdGlvbiBvbiBhIHNjYWxlZCB2ZXJzaW9uIG9mIHRoZSBHQSdzIHNvbHV0aW9uLiBTbyBpZiAkeFxnZSAwJCBpcyB0aGUgY3VycmVudCBHQSBzb2x1dGlvbiBhcyBhbiAkbiQtdmVjdG9yIGFuZCAkZiQgaXMgdGhlIG9yaWdpbmFsIG9iamVjdGl2ZSwgdGhlIEdBIHVzZXMgdGhlIG9iamVjdGl2ZSBmdW5jdGlvbiAkJFxoYXR7Zn0oeCkgPSBmXGxlZnQoXGZyYWN7eH17XHN1bV97aT0xfV5uIHhfaX1ccmlnaHQpLiQkCgpXZSB3aWxsIHVzZSB0aGUgYGdlbmFsZ2AgUiBwYWNrYWdlLgoKYGBge3J9CmxpYnJhcnkoZ2VuYWxnKQpgYGAKCiMjIEdBIG9iamVjdGl2ZSBmdW5jdGlvbgoKTm93IHdlIGRlZmluZSB0aGUgc2NhbGVkIG9iamVjdGl2ZSBmdW5jdGlvbiB0aGF0IHRoZSBHQSB3aWxsIHVzZS4KCmBgYHtyfQpvYmpfZnVuY3Rpb24gPC0gZnVuY3Rpb24oeCkgewogIGNvc3RfZnVuY3Rpb24oeCAvIHN1bSh4KSkKfQpgYGAKCiMjIEdBIHNvbHV0aW9uCgpGb3IgcmVwcm9kdWNpYmlsaXR5LCB3ZSBzZXQgdGhlIHNlZWQgdmFsdWUgZm9yIHRoZSByYW5kb20gbnVtYmVyIGdlbmVyYXRvci4KCmBgYHtyfQpzZXQuc2VlZCgyMDIwMDUzMSkKYGBgCgpOb3cgd2UgZGVmaW5lIGFuZCBydW4gdGhlIEdBIGFuZCBleHRyYWN0IHRoZSByZXN1bHRzLgoKYGBge3J9CiMgUnVuIHRoZSBHQS4KcmVzdWx0cyA8LSByYmdhKHN0cmluZ01pbiA9IHJlcCgwLCBkaW0pLCBzdHJpbmdNYXggPSByZXAoMSwgZGltKSwgcG9wU2l6ZSA9IDIwMCwgaXRlcnMgPSAxMDAsIGV2YWxGdW5jID0gb2JqX2Z1bmN0aW9uLCBlbGl0aXNtID0gMTApCiMgR2V0IHRoZSBpbmRleCBvZiB0aGUgYmVzdCBzb2x1dGlvbiBpbiB0aGUgZmluYWwgcG9wdWxhdGlvbi4KaXggPC0gd2hpY2gubWluKHJlc3VsdHMkZXZhbHVhdGlvbnMpCiMgUHJpbnQgdGhlIGluY3VtYmVudCBvYmplY3RpdmUgdmFsdWUuCmNhdCgiSW5jdW1iZW50IG9iamVjdGl2ZSB2YWx1ZSA9ICIsIHJlc3VsdHMkZXZhbHVhdGlvbnNbaXhdLCAiXG4iKQojIEdldCBhbmQgc2NhbGUgdGhlIGluY3VtYmVudCwgdGhlbiBwcmludCBpdC4KaW5jdW1iZW50IDwtIHJlc3VsdHMkcG9wdWxhdGlvbltpeCwgXSAvIHN1bShyZXN1bHRzJHBvcHVsYXRpb25baXgsIF0pCmNhdCgiSW5jdW1iZW50IHNvbHV0aW9uID0gIiwgaW5jdW1iZW50LCAiXG4iKQojIENvbmZpcm0gZmVhc2liaWxpdHkuCmNhdCgiU3VtIG9mIGluY3VtYmVudCB3ZWlnaHRzID0gIiwgc3VtKGluY3VtYmVudCksICJcbiIpCiMgQ29uZmlybSB0aGUgb2JqZWN0aXZlIHZhbHVlLgpjYXQoIk9yaWdpbmFsIG9iamVjdGl2ZSBmdW5jdGlvbiBldmFsdWF0ZWQgYXQgc2NhbGVkIGluY3VtYmVudCA9ICIsIGNvc3RfZnVuY3Rpb24oaW5jdW1iZW50KSwgIlxuIikKYGBgCgpXZSBjYW4gcGxvdCB0aGUgcmVzdWx0cy4KCmBgYHtyfQpwbG90KHJlc3VsdHMpCmBgYAo=