Go back to the About page. This link might be useful to keep track of the files created during the preprocessing.

Let us set some global options for all code chunks in this document.

# Set seed for reproducibility
set.seed(1982) 
# Set global options for all code chunks
knitr::opts_chunk$set(
  # Disable messages printed by R code chunks
  message = FALSE,    
  # Disable warnings printed by R code chunks
  warning = FALSE,    
  # Show R code within code chunks in output
  echo = TRUE,        
  # Include both R code and its results in output
  include = TRUE,     
  # Evaluate R code chunks
  eval = TRUE,       
  # Enable caching of R code chunks for faster rendering
  cache = FALSE,      
  # Align figures in the center of the output
  fig.align = "center",
  # Enable retina display for high-resolution figures
  retina = 2,
  # Show errors in the output instead of stopping rendering
  error = TRUE,
  # Do not collapse code and output into a single block
  collapse = FALSE
)
# Start the figure counter
fig_count <- 0
# Define the captioner function
captioner <- function(caption) {
  fig_count <<- fig_count + 1
  paste0("Figure ", fig_count, ": ", caption)
}

Import libraries

library(MetricGraph)
library(Matrix)
library(rSPDE)

library(dplyr)
library(tidyverse)
library(plotly)
library(ggplot2)
library(latex2exp)
library(ggtext)

library(grateful) # Cite all loaded packages
library(here) # here() starts from the home directory

Interval graph


Press the Show button below to reveal the code.


# library calls
library(MetricGraph)
library(Matrix)
library(rSPDE)

# function 1
gets_graph_interval <- function(n){
  edge <- rbind(c(0,0),c(1,0))
  edges = list(edge)
  graph <- metric_graph$new(edges = edges)
  graph$build_mesh(n = n)
  return(graph)
}

# matern covariance function. Same as in the package
matern.covariance <- function(h, kappa, nu, sigma) {
  if (nu == 1 / 2) {
    C <- sigma^2 * exp(-kappa * abs(h))
  } else {
    C <- (sigma^2 / (2^(nu - 1) * gamma(nu))) *
      ((kappa * abs(h))^nu) * besselK(kappa * abs(h), nu)
  }
  C[h == 0] <- sigma^2
  return(as.matrix(C))
}

# folded.matern.covariance.1d I edited
folded.matern.covariance.1d.local <- function(x, kappa, nu, sigma,
                                              L = 1, N = 10,
                                              boundary = c("neumann",
                                                           "dirichlet", "periodic")) {
  boundary <- tolower(boundary[1])
  if (!(boundary %in% c("neumann", "dirichlet", "periodic"))) {
    stop("The possible boundary conditions are 'neumann',
    'dirichlet' or 'periodic'!")
  }
  addi = t(outer(x, x, "+"))
  diff = t(outer(x, x, "-"))
  s1 <- sapply(-N:N, function(j) { 
    diff + 2 * j * L
  })
  s2 <- sapply(-N:N, function(j) {
    addi + 2 * j * L
  })
  if (boundary == "neumann") {
    C <- rowSums(matern.covariance(h = s1, kappa = kappa,
                                   nu = nu, sigma = sigma) +
                   matern.covariance(h = s2, kappa = kappa,
                                     nu = nu, sigma = sigma))
  } else if (boundary == "dirichlet") {
    C <- rowSums(matern.covariance(h = s1, kappa = kappa,
                                   nu = nu, sigma = sigma) -
                   matern.covariance(h = s2, kappa = kappa,
                                     nu = nu, sigma = sigma))
  } else {
    C <- rowSums(matern.covariance(h = s1,
                                   kappa = kappa, nu = nu, sigma = sigma))
  }
  return(matrix(C, nrow = length(x)))
}

# function 2
gets_true_cov_mat = function(graph, kappa, nu, sigma, N, boundary){
  h = graph$mesh$V[,1] 
  true_cov_mat = folded.matern.covariance.1d.local(x = h, kappa = kappa, nu = nu, sigma = sigma, N = N, boundary = boundary)
  return(true_cov_mat)
}


# parameters
n_vector = c(998, 198, 98, 8)
type_vector = c("covariance", "operator")
type_rational_approximation_vector = c("chebfun", "brasil", "chebfunLB")
rho_vector = c(0.1, 0.5, 1, 2)
m_vector = c(0,1,2,3,4,5)
nu_vector = c(seq(0.1,0.4,by=0.05), seq(0.41,0.59,by=0.01), seq(0.6,1.4,by=0.05), seq(1.41,1.59,by=0.01), seq(1.6,2.4,by=0.05), seq(2.41,2.49,by=0.01))
boundary = "neumann"
sigma = 1
N.folded = 10

Error = list()
for (s in c(1,2,3,4)) { # loop over n_vector
  Error[[as.character(n_vector[s])]] = list()
  n = n_vector[s]
  graph = gets_graph_interval(n = n)
  for (i in c(1)) { # loop over type_vector
    Error[[as.character(n_vector[s])]][[type_vector[i]]] = list()
    type = type_vector[i]
    for (j in c(1,2,3)) { # loop over type_rational_approximation_vector
      Error[[as.character(n_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]] = list()
      type_rational_approximation = type_rational_approximation_vector[j]
      for (k in c(1,2,3,4)) { # loop over rho_vector
        Error[[as.character(n_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]] = list()
        rho = rho_vector[k]
        for (l in 1:length(m_vector)) { # loop over m_vector
          Error[[as.character(n_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]] = matrix(NA, nrow = length(nu_vector), ncol = 2)
          colnames(Error[[as.character(n_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]]) = c("L_inf_error", "L_2_error")
          m = m_vector[l]
          for (r in 1:length(nu_vector)) { # loop over nu_vector
            nu = nu_vector[r]
            
            kappa = sqrt(8*nu)/rho
            tau = sqrt(gamma(nu) / (sigma^2 * kappa^(2*nu) * (4*pi)^(1/2) * gamma(nu + 1/2)))  #sigma = 1, d = 1
            alpha = nu + 1/2
            
            tryCatch({
              # getting true covariance
              true_cov_mat = gets_true_cov_mat(graph = graph,
                                               kappa = kappa,
                                               nu = nu,
                                               sigma = sigma,
                                               N = N.folded,
                                               boundary = boundary)
              
              # getting the approximate covariance matrix
              op = matern.operators(alpha = alpha, 
                                    kappa = kappa, 
                                    tau = tau,
                                    m = m, 
                                    graph = graph,
                                    type = type,
                                    type_rational_approximation = type_rational_approximation)
              
              appr_cov_mat = op$covariance_mesh()
            
            # computing the errors
            L_inf_error = max(abs(true_cov_mat - appr_cov_mat))
            L_2_error = sqrt(as.double(t(graph$mesh$weights)%*%(true_cov_mat - appr_cov_mat)^2%*%graph$mesh$weights))
            
            Error[[as.character(n_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]][r,1] = L_inf_error
            Error[[as.character(n_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]][r,2] = L_2_error
            }, error = function(err){
              warning(paste("Error occurred at iteration n=", n, ",type=", type, ",type_rational_approximation=", type_rational_approximation, ",rho=", rho, ",m=", m, ",nu=", nu, "Error:", conditionMessage(err)))
              print(paste("Error occurred at iteration n=", n, ",type=", type, ",type_rational_approximation=", type_rational_approximation, ",rho=", rho, ",m=", m, ",nu=", nu, "Error:", conditionMessage(err)))
              Error[[as.character(n_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]][r,1] = NA
              Error[[as.character(n_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]][r,2] = NA
            })
            print(paste("n=", n, ",type=", type, ",type_rational_approximation=", type_rational_approximation, ",rho=", rho, ",m=", m, ",nu=", nu))
          }
        }
      }
    }
  }
}

Error_interval_DEF = Error
save(Error_interval_DEF, file = here("data_files/Error_interval_DEF.RData"))

Plotting the errors

load(here("data_files/Error_interval_DEF.RData"))

n_vector = c("998", "198", "98", "8") 
type_rational_approximation_vector = c("chebfun", "brasil", "chebfunLB")
nu_max = 53
nu_vector = 0.5 + c(seq(0.1,0.4,by=0.05), seq(0.41,0.59,by=0.01), seq(0.6,1.4,by=0.05), seq(1.41,1.59,by=0.01), seq(1.6,2.4,by=0.05), seq(2.41,2.49,by=0.01))[1:nu_max]

n = "998"
t = "chebfun"


dat = rbind(
data.frame(nu = rep(nu_vector,5), 
           rho = rep(0.1, times = 5*nu_max),
           m = rep(1:5, each = nu_max),
           error = c(Error_interval_DEF[[n]][["covariance"]][[t]][["0.1"]][["1"]][1:nu_max,1],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["0.1"]][["2"]][1:nu_max,1],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["0.1"]][["3"]][1:nu_max,1],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["0.1"]][["4"]][1:nu_max,1],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["0.1"]][["5"]][1:nu_max,1]),
           L = rep("Linf", times = 5*nu_max)
),

data.frame(nu = rep(nu_vector,5), 
           rho = c(rep(0.5, times = 5*nu_max)),
           m = rep(1:5, each = nu_max),
           error = c(Error_interval_DEF[[n]][["covariance"]][[t]][["0.5"]][["1"]][1:nu_max,1],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["0.5"]][["2"]][1:nu_max,1],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["0.5"]][["3"]][1:nu_max,1],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["0.5"]][["4"]][1:nu_max,1],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["0.5"]][["5"]][1:nu_max,1]),
           L = rep("Linf", times = 5*nu_max)
),

data.frame(nu = rep(nu_vector,5), 
           rho = c(rep(1, times = 5*nu_max)),
           m = rep(1:5, each = nu_max),
           error = c(Error_interval_DEF[[n]][["covariance"]][[t]][["1"]][["1"]][1:nu_max,1],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["1"]][["2"]][1:nu_max,1],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["1"]][["3"]][1:nu_max,1],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["1"]][["4"]][1:nu_max,1],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["1"]][["5"]][1:nu_max,1]),
           L = rep("Linf", times = 5*nu_max)
),

data.frame(nu = rep(nu_vector,5), 
           rho = c(rep(2, times = 5*nu_max)),
           m = rep(1:5, each = nu_max),
           error = c(Error_interval_DEF[[n]][["covariance"]][[t]][["2"]][["1"]][1:nu_max,1],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["2"]][["2"]][1:nu_max,1],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["2"]][["3"]][1:nu_max,1],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["2"]][["4"]][1:nu_max,1],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["2"]][["5"]][1:nu_max,1]),
           L = rep("Linf", times = 5*nu_max)
),

## L2

data.frame(nu = rep(nu_vector,5), 
           rho = rep(0.1, times = 5*nu_max),
           m = rep(1:5, each = nu_max),
           error = c(Error_interval_DEF[[n]][["covariance"]][[t]][["0.1"]][["1"]][1:nu_max,2],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["0.1"]][["2"]][1:nu_max,2],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["0.1"]][["3"]][1:nu_max,2],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["0.1"]][["4"]][1:nu_max,2],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["0.1"]][["5"]][1:nu_max,2]),
           L = rep("L2", times = 5*nu_max)
),

data.frame(nu = rep(nu_vector,5), 
           rho = c(rep(0.5, times = 5*nu_max)),
           m = rep(1:5, each = nu_max),
           error = c(Error_interval_DEF[[n]][["covariance"]][[t]][["0.5"]][["1"]][1:nu_max,2],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["0.5"]][["2"]][1:nu_max,2],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["0.5"]][["3"]][1:nu_max,2],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["0.5"]][["4"]][1:nu_max,2],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["0.5"]][["5"]][1:nu_max,2]),
           L = rep("L2", times = 5*nu_max)
),

data.frame(nu = rep(nu_vector,5), 
           rho = c(rep(1, times = 5*nu_max)),
           m = rep(1:5, each = nu_max),
           error = c(Error_interval_DEF[[n]][["covariance"]][[t]][["1"]][["1"]][1:nu_max,2],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["1"]][["2"]][1:nu_max,2],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["1"]][["3"]][1:nu_max,2],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["1"]][["4"]][1:nu_max,2],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["1"]][["5"]][1:nu_max,2]),
           L = rep("L2", times = 5*nu_max)
),

data.frame(nu = rep(nu_vector,5), 
           rho = c(rep(2, times = 5*nu_max)),
           m = rep(1:5, each = nu_max),
           error = c(Error_interval_DEF[[n]][["covariance"]][[t]][["2"]][["1"]][1:nu_max,2],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["2"]][["2"]][1:nu_max,2],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["2"]][["3"]][1:nu_max,2],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["2"]][["4"]][1:nu_max,2],
                     Error_interval_DEF[[n]][["covariance"]][[t]][["2"]][["5"]][1:nu_max,2]),
           L = rep("L2", times = 5*nu_max)
)
)


dat$rho = factor(dat$rho, levels = c("0.1", "0.5", "1", "2"))
dat$L = factor(dat$L, levels = c("L2", "Linf"))
levels(dat$rho) = c("0.1" = latex2exp::TeX("$\\rho = 0.1$"), "0.5" = latex2exp::TeX("$\\rho = 0.5$"), "1" = latex2exp::TeX("$\\rho = 1$"), "2" = latex2exp::TeX("$\\rho = 2$"))
levels(dat$L) = c("L2" = latex2exp::TeX("$L_2(\\Gamma\\times\\Gamma)$ error"), "Linf" = latex2exp::TeX("$L_\\infty(\\Gamma\\times\\Gamma)$ error"))


p <- ggplot(dat, aes(nu, error, colour = as.factor(m))) + 
  facet_grid(L ~ rho, labeller = label_parsed) +
  geom_line() +
  scale_y_log10(n.breaks = 5) +
  scale_x_continuous(n.breaks = 10) +
  theme_bw() +
  theme(panel.spacing = unit(0.3, "cm"), text = element_text(family = "Palatino"),
        plot.title = element_text(size = 16),
        strip.text = element_text(size = 12),        # Panel titles
        axis.title = element_text(size = 14),        # Axis titles
        axis.text = element_text(size = 12),         # Axis text
        legend.title = element_text(size = 14),      # Legend title
        legend.text = element_text(size = 12)) +
  labs(x = bquote(alpha ~ "(smoothness parameter)"), y = "Covariance Error", color = "m") + ggtitle("Interval graph")
p
Figure 1: Covariance error for the interval graph.

Figure 1: Covariance error for the interval graph.

ggsave(here("data_files/new_interval_upto1.5.png"), width = 12, height = 6, plot = p, dpi = 300)

Circle graph


Press the Show button below to reveal the code.


# library calls
library(MetricGraph)
library(Matrix)
library(rSPDE)

# function 1
gets_graph_circle <- function(n){
  r = 1/(pi)
  theta <- seq(from=-pi,to=pi,length.out = 10000)
  edge <- cbind(1+r+r*cos(theta),r*sin(theta))
  edges = list(edge)
  graph <- metric_graph$new(edges = edges)
  graph$set_manual_edge_lengths(edge_lengths = 2)
  graph$build_mesh(n = n)
  return(graph)
}

# matern covariance function. Same as in the package
matern.covariance <- function(h, kappa, nu, sigma) {
  if (nu == 1 / 2) {
    C <- sigma^2 * exp(-kappa * abs(h))
  } else {
    C <- (sigma^2 / (2^(nu - 1) * gamma(nu))) *
      ((kappa * abs(h))^nu) * besselK(kappa * abs(h), nu)
  }
  C[h == 0] <- sigma^2
  return(as.matrix(C))
}

# folded.matern.covariance.1d I edited
folded.matern.covariance.1d.local <- function(x, kappa, nu, sigma, L = 1, N = 10, boundary = c("neumann",
                                                                                               "dirichlet", "periodic")) {
  boundary <- tolower(boundary[1])
  if (!(boundary %in% c("neumann", "dirichlet", "periodic"))) {
    stop("The possible boundary conditions are 'neumann',
    'dirichlet' or 'periodic'!")
  }
  addi = t(outer(x, x, "+"))
  diff = t(outer(x, x, "-"))
  s1 <- sapply(-N:N, function(j) { # s1 is a matrix of size length(h)x(2N+1)
    diff + 2 * j * L
  })
  s2 <- sapply(-N:N, function(j) {
    addi + 2 * j * L
  })
  if (boundary == "neumann") {
    C <- rowSums(matern.covariance(h = s1, kappa = kappa,
                                   nu = nu, sigma = sigma) +
                   matern.covariance(h = s2, kappa = kappa,
                                     nu = nu, sigma = sigma))
  } else if (boundary == "dirichlet") {
    C <- rowSums(matern.covariance(h = s1, kappa = kappa,
                                   nu = nu, sigma = sigma) -
                   matern.covariance(h = s2, kappa = kappa,
                                     nu = nu, sigma = sigma))
  } else {
    C <- rowSums(matern.covariance(h = s1,
                                   kappa = kappa, nu = nu, sigma = sigma))
  }
  return(matrix(C, nrow = length(x)))
}

# function 2
gets_true_cov_mat = function(graph, kappa, nu, sigma, N, boundary){
  h = c(0,graph$get_edge_lengths()[1]*graph$mesh$PtE[,2])
  true_cov_mat = folded.matern.covariance.1d.local(x = h, kappa = kappa, nu = nu, sigma = sigma, N = N, boundary = boundary)
  return(true_cov_mat)
}


# parameters
n_vector = 2*c(998, 198, 98, 8)
type_vector = c("covariance", "operator")
type_rational_approximation_vector = c("chebfun", "brasil", "chebfunLB")
rho_vector = c(0.1, 0.5, 1, 2)
m_vector = c(0,1,2,3,4,5)
nu_vector = c(seq(0.1,0.4,by=0.05), seq(0.41,0.59,by=0.01), seq(0.6,1.4,by=0.05), seq(1.41,1.59,by=0.01), seq(1.6,2.4,by=0.05), seq(2.41,2.49,by=0.01))
boundary = "periodic"
sigma = 1
N.folded = 10

Error = list()
for (s in c(1,2,3,4)) { # loop over n_vector
  Error[[as.character(n_vector[s])]] = list()
  n = n_vector[s]
  graph = gets_graph_circle(n = n)
  for (i in c(1)) { # loop over type_vector
    Error[[as.character(n_vector[s])]][[type_vector[i]]] = list()
    type = type_vector[i]
    for (j in c(1,2,3)) { # loop over type_rational_approximation_vector
      Error[[as.character(n_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]] = list()
      type_rational_approximation = type_rational_approximation_vector[j]
      for (k in c(1,2,3,4)) { # loop over rho_vector
        Error[[as.character(n_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]] = list()
        rho = rho_vector[k]
        for (l in 1:length(m_vector)) { # loop over m_vector
          Error[[as.character(n_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]] = matrix(NA, nrow = length(nu_vector), ncol = 2)
          colnames(Error[[as.character(n_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]]) = c("L_inf_error", "L_2_error")
          m = m_vector[l]
          for (r in 1:length(nu_vector)) { # loop over nu_vector
            nu = nu_vector[r]
            
            kappa = sqrt(8*nu)/rho
            tau = sqrt(gamma(nu) / (sigma^2 * kappa^(2*nu) * (4*pi)^(1/2) * gamma(nu + 1/2)))  #sigma = 1, d = 1
            alpha = nu + 1/2
            
            tryCatch({
              # getting true covariance
              true_cov_mat = gets_true_cov_mat(graph = graph,
                                               kappa = kappa,
                                               nu = nu,
                                               sigma = sigma,
                                               N = N.folded,
                                               boundary = boundary)
              
              # getting the approximate covariance matrix
              op = matern.operators(alpha = alpha, 
                                    kappa = kappa, 
                                    tau = tau,
                                    m = m, 
                                    graph = graph,
                                    type = type,
                                    type_rational_approximation = type_rational_approximation)
              
              appr_cov_mat = op$covariance_mesh()
            
            # computing the errors
            L_inf_error = max(abs(true_cov_mat - appr_cov_mat))
            L_2_error = sqrt(as.double(t(graph$mesh$weights)%*%(true_cov_mat - appr_cov_mat)^2%*%graph$mesh$weights))
            
            Error[[as.character(n_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]][r,1] = L_inf_error
            Error[[as.character(n_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]][r,2] = L_2_error
            }, error = function(err){
              warning(paste("Error occurred at iteration n=", n, ",type=", type, ",type_rational_approximation=", type_rational_approximation, ",rho=", rho, ",m=", m, ",nu=", nu, "Error:", conditionMessage(err)))
              print(paste("Error occurred at iteration n=", n, ",type=", type, ",type_rational_approximation=", type_rational_approximation, ",rho=", rho, ",m=", m, ",nu=", nu, "Error:", conditionMessage(err)))
              Error[[as.character(n_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]][r,1] = NA
              Error[[as.character(n_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]][r,2] = NA
            })
            print(paste("n=", n, ",type=", type, ",type_rational_approximation=", type_rational_approximation, ",rho=", rho, ",m=", m, ",nu=", nu))
          }
        }
      }
    }
  }
}
Error_circle_DEF = Error
save(Error_circle_DEF, file = here("data_files/Error_circle_DEF.RData"))

Plotting the errors

load(here("data_files/Error_circle_DEF.RData"))

n_vector = c("1996", "396", "196", "16") 
type_rational_approximation_vector = c("chebfun", "brasil", "chebfunLB")
nu_max = 53
nu_vector = 0.5 + c(seq(0.1,0.4,by=0.05), seq(0.41,0.59,by=0.01), seq(0.6,1.4,by=0.05), seq(1.41,1.59,by=0.01), seq(1.6,2.4,by=0.05), seq(2.41,2.49,by=0.01))[1:nu_max]

n = "1996"
t = "chebfun"
  

dat = rbind(
data.frame(nu = rep(nu_vector,5), 
           rho = rep(0.1, times = 5*nu_max),
           m = rep(1:5, each = nu_max),
           error = c(Error_circle_DEF[[n]][["covariance"]][[t]][["0.1"]][["1"]][1:nu_max,1],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["0.1"]][["2"]][1:nu_max,1],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["0.1"]][["3"]][1:nu_max,1],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["0.1"]][["4"]][1:nu_max,1],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["0.1"]][["5"]][1:nu_max,1]),
           L = rep("Linf", times = 5*nu_max)
),

data.frame(nu = rep(nu_vector,5), 
           rho = c(rep(0.5, times = 5*nu_max)),
           m = rep(1:5, each = nu_max),
           error = c(Error_circle_DEF[[n]][["covariance"]][[t]][["0.5"]][["1"]][1:nu_max,1],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["0.5"]][["2"]][1:nu_max,1],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["0.5"]][["3"]][1:nu_max,1],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["0.5"]][["4"]][1:nu_max,1],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["0.5"]][["5"]][1:nu_max,1]),
           L = rep("Linf", times = 5*nu_max)
),

data.frame(nu = rep(nu_vector,5), 
           rho = c(rep(1, times = 5*nu_max)),
           m = rep(1:5, each = nu_max),
           error = c(Error_circle_DEF[[n]][["covariance"]][[t]][["1"]][["1"]][1:nu_max,1],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["1"]][["2"]][1:nu_max,1],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["1"]][["3"]][1:nu_max,1],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["1"]][["4"]][1:nu_max,1],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["1"]][["5"]][1:nu_max,1]),
           L = rep("Linf", times = 5*nu_max)
),

data.frame(nu = rep(nu_vector,5), 
           rho = c(rep(2, times = 5*nu_max)),
           m = rep(1:5, each = nu_max),
           error = c(Error_circle_DEF[[n]][["covariance"]][[t]][["2"]][["1"]][1:nu_max,1],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["2"]][["2"]][1:nu_max,1],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["2"]][["3"]][1:nu_max,1],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["2"]][["4"]][1:nu_max,1],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["2"]][["5"]][1:nu_max,1]),
           L = rep("Linf", times = 5*nu_max)
),

## L2

data.frame(nu = rep(nu_vector,5), 
           rho = rep(0.1, times = 5*nu_max),
           m = rep(1:5, each = nu_max),
           error = c(Error_circle_DEF[[n]][["covariance"]][[t]][["0.1"]][["1"]][1:nu_max,2],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["0.1"]][["2"]][1:nu_max,2],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["0.1"]][["3"]][1:nu_max,2],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["0.1"]][["4"]][1:nu_max,2],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["0.1"]][["5"]][1:nu_max,2]),
           L = rep("L2", times = 5*nu_max)
),

data.frame(nu = rep(nu_vector,5), 
           rho = c(rep(0.5, times = 5*nu_max)),
           m = rep(1:5, each = nu_max),
           error = c(Error_circle_DEF[[n]][["covariance"]][[t]][["0.5"]][["1"]][1:nu_max,2],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["0.5"]][["2"]][1:nu_max,2],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["0.5"]][["3"]][1:nu_max,2],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["0.5"]][["4"]][1:nu_max,2],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["0.5"]][["5"]][1:nu_max,2]),
           L = rep("L2", times = 5*nu_max)
),

data.frame(nu = rep(nu_vector,5), 
           rho = c(rep(1, times = 5*nu_max)),
           m = rep(1:5, each = nu_max),
           error = c(Error_circle_DEF[[n]][["covariance"]][[t]][["1"]][["1"]][1:nu_max,2],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["1"]][["2"]][1:nu_max,2],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["1"]][["3"]][1:nu_max,2],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["1"]][["4"]][1:nu_max,2],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["1"]][["5"]][1:nu_max,2]),
           L = rep("L2", times = 5*nu_max)
),

data.frame(nu = rep(nu_vector,5), 
           rho = c(rep(2, times = 5*nu_max)),
           m = rep(1:5, each = nu_max),
           error = c(Error_circle_DEF[[n]][["covariance"]][[t]][["2"]][["1"]][1:nu_max,2],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["2"]][["2"]][1:nu_max,2],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["2"]][["3"]][1:nu_max,2],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["2"]][["4"]][1:nu_max,2],
                     Error_circle_DEF[[n]][["covariance"]][[t]][["2"]][["5"]][1:nu_max,2]),
           L = rep("L2", times = 5*nu_max)
)
)


dat$rho = factor(dat$rho, levels = c("0.1", "0.5", "1", "2"))
dat$L = factor(dat$L, levels = c("L2", "Linf"))
levels(dat$rho) = c("0.1" = latex2exp::TeX("$\\rho = 0.1$"), "0.5" = latex2exp::TeX("$\\rho = 0.5$"), "1" = latex2exp::TeX("$\\rho = 1$"), "2" = latex2exp::TeX("$\\rho = 2$"))
levels(dat$L) = c("L2" = latex2exp::TeX("$L_2(\\Gamma\\times\\Gamma)$ error"), "Linf" = latex2exp::TeX("$L_\\infty(\\Gamma\\times\\Gamma)$ error"))

p <- ggplot(dat, aes(nu, error, colour = as.factor(m))) + 
  facet_grid(L ~ rho, labeller = label_parsed) +
  geom_line() +
  scale_y_log10(n.breaks = 5) +
  scale_x_continuous(n.breaks = 10) +
  theme_bw() +
  theme(panel.spacing = unit(0.3, "cm"), text = element_text(family = "Palatino"),
        plot.title = element_text(size = 16),
        strip.text = element_text(size = 12),        # Panel titles
        axis.title = element_text(size = 14),        # Axis titles
        axis.text = element_text(size = 12),         # Axis text
        legend.title = element_text(size = 14),      # Legend title
        legend.text = element_text(size = 12)) +
  labs(x = bquote(alpha ~ "(smoothness parameter)"), y = "Covariance Error", color = "m") + ggtitle("Circle graph")
p
Figure 2: Covariance error for the circle graph.

Figure 2: Covariance error for the circle graph.

ggsave(here("data_files/new_circle_upto1.5.png"), width = 12, height = 6, plot = p, dpi = 300)

Tadpole graph

rho = 0.1


Press the Show button below to reveal the code.


# library calls
library(MetricGraph)
library(Matrix)
library(rSPDE)

# function 1
tadpole.eig <- function(k,graph){
  x1 <- c(0,graph$get_edge_lengths()[1]*graph$mesh$PtE[graph$mesh$PtE[,1]==1,2]) 
  x2 <- c(0,graph$get_edge_lengths()[2]*graph$mesh$PtE[graph$mesh$PtE[,1]==2,2]) 
  
  if(k==0){ 
    f.e1 <- rep(1,length(x1)) 
    f.e2 <- rep(1,length(x2)) 
    f1 = c(f.e1[1],f.e2[1],f.e1[-1], f.e2[-1]) 
    f = list(phi=f1/sqrt(3)) 
    
  } else {
    f.e1 <- -2*sin(pi*k*1/2)*cos(pi*k*x1/2) 
    f.e2 <- sin(pi*k*x2/2)                  
    
    f1 = c(f.e1[1],f.e2[1],f.e1[-1], f.e2[-1]) 
    
    if((k %% 2)==1){ 
      f = list(phi=f1/sqrt(3)) 
    } else { 
      f.e1 <- (-1)^{k/2}*cos(pi*k*x1/2)
      f.e2 <- cos(pi*k*x2/2)
      f2 = c(f.e1[1],f.e2[1],f.e1[-1],f.e2[-1]) 
      f <- list(phi=f1,psi=f2/sqrt(3/2))
    }
  }
  
  return(f)
}

# function 2
gets_graph <- function(h){
  edge1 <- rbind(c(0,0),c(1,0))
  theta <- seq(from=-pi,to=pi,length.out = 10000)
  edge2 <- cbind(1+1/pi+cos(theta)/pi,sin(theta)/pi)
  edges = list(edge1, edge2)
  graph <- metric_graph$new(edges = edges)
  graph$set_manual_edge_lengths(edge_lengths = c(1,2))
  graph$build_mesh(h=h)
  return(graph)
}

#function 3
gets_true_cov_mat <- function(graph, kappa, tau, alpha, n.overkill){
  Sigma.kl <- matrix(0,nrow = dim(graph$mesh$V)[1],ncol = dim(graph$mesh$V)[1])
  for(i in 0:n.overkill){
    phi <- tadpole.eig(i,graph)$phi
    Sigma.kl <- Sigma.kl + (1/(kappa^2 + (i*pi/2)^2)^(alpha))*phi%*%t(phi)
    if(i>0 && (i %% 2)==0){ 
      psi <- tadpole.eig(i,graph)$psi
      Sigma.kl <- Sigma.kl + (1/(kappa^2 + (i*pi/2)^2)^(alpha))*psi%*%t(psi)
    }
    
  }
  Sigma.kl <- Sigma.kl/tau^2
  return(Sigma.kl)
}

# parameters
h_vector = c(0.001, 0.005, 0.01, 0.1)
type_vector = c("covariance", "operator")
type_rational_approximation_vector = c("chebfun", "brasil", "chebfunLB")
rho_vector = c(0.1, 0.5, 1, 2)
m_vector = c(0,1,2,3,4,5)
nu_vector = c(seq(0.1,0.4,by=0.05), seq(0.41,0.59,by=0.01), seq(0.6,1.4,by=0.05), seq(1.41,1.59,by=0.01), seq(1.6,2.4,by=0.05), seq(2.41,2.49,by=0.01))
n.overkill = 1000
sigma = 1

Error = list()
for (s in c(1,2,3,4)) { # loop over h_vector
  Error[[as.character(h_vector[s])]] = list()
  h = h_vector[s]
  graph = gets_graph(h = h)
  for (i in c(1)) { # loop over type_vector
    Error[[as.character(h_vector[s])]][[type_vector[i]]] = list()
    type = type_vector[i]
    for (j in c(1,2,3)) { # loop over type_rational_approximation_vector
      Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]] = list()
      type_rational_approximation = type_rational_approximation_vector[j]
      for (k in c(1)) { # loop over rho_vector
        Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]] = list()
        rho = rho_vector[k]
        for (l in 1:length(m_vector)) { # loop over m_vector
          Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]] = matrix(NA, nrow = length(nu_vector), ncol = 2)
          colnames(Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]]) = c("L_inf_error", "L_2_error")
          m = m_vector[l]
          for (n in 1:length(nu_vector)) { # loop over nu_vector
            nu = nu_vector[n]
            
            kappa = sqrt(8*nu)/rho
            tau = sqrt(gamma(nu) / (sigma^2 * kappa^(2*nu) * (4*pi)^(1/2) * gamma(nu + 1/2)))  #sigma = 1, d = 1
            alpha = nu + 1/2
            
            tryCatch({
            # getting true covariance
            true_cov_mat = gets_true_cov_mat(graph = graph,
                                             kappa = kappa,
                                             tau = tau,
                                             alpha = alpha,
                                             n.overkill = n.overkill)
            
            # getting the approximate covariance matrix
            op = matern.operators(alpha = alpha, 
                                  kappa = kappa, 
                                  tau = tau,
                                  m = m, 
                                  graph = graph,
                                  type = type,
                                  type_rational_approximation = type_rational_approximation)
            appr_cov_mat = op$covariance_mesh()
            
            # computing the errors
            L_inf_error = max(abs(true_cov_mat - appr_cov_mat))
            L_2_error = sqrt(as.double(t(graph$mesh$weights)%*%(true_cov_mat - appr_cov_mat)^2%*%graph$mesh$weights))
            
            Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]][n,1] = L_inf_error
            Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]][n,2] = L_2_error
            }, error = function(err){
              warning(paste("Error occurred at iteration h=", h, ",type=", type, ",type_rational_approximation=", type_rational_approximation, ",rho=", rho, ",m=", m, ",nu=", nu, "Error:", conditionMessage(err)))
              print(paste("Error occurred at iteration h=", h, ",type=", type, ",type_rational_approximation=", type_rational_approximation, ",rho=", rho, ",m=", m, ",nu=", nu, "Error:", conditionMessage(err)))
              Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]][n,1] = NA
              Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]][n,2] = NA
            })
            print(paste("h=", h, ",type=", type, ",type_rational_approximation=", type_rational_approximation, ",rho=", rho, ",m=", m, ",nu=", nu))
          }
        }
      }
    }
  }
}

Error_tadpole_DEF_rho0.1 = Error
save(Error_tadpole_DEF_rho0.1, file = here("data_files/Error_tadpole_DEF_rho0.1.RData"))

rho = 0.5


Press the Show button below to reveal the code.


# library calls
library(MetricGraph)
library(Matrix)
library(rSPDE)

# function 1
tadpole.eig <- function(k,graph){
  x1 <- c(0,graph$get_edge_lengths()[1]*graph$mesh$PtE[graph$mesh$PtE[,1]==1,2]) 
  x2 <- c(0,graph$get_edge_lengths()[2]*graph$mesh$PtE[graph$mesh$PtE[,1]==2,2]) 
  
  if(k==0){ 
    f.e1 <- rep(1,length(x1)) 
    f.e2 <- rep(1,length(x2)) 
    f1 = c(f.e1[1],f.e2[1],f.e1[-1], f.e2[-1]) 
    f = list(phi=f1/sqrt(3)) 
    
  } else {
    f.e1 <- -2*sin(pi*k*1/2)*cos(pi*k*x1/2) 
    f.e2 <- sin(pi*k*x2/2)                  
    
    f1 = c(f.e1[1],f.e2[1],f.e1[-1], f.e2[-1]) 
    
    if((k %% 2)==1){ 
      f = list(phi=f1/sqrt(3)) 
    } else { 
      f.e1 <- (-1)^{k/2}*cos(pi*k*x1/2)
      f.e2 <- cos(pi*k*x2/2)
      f2 = c(f.e1[1],f.e2[1],f.e1[-1],f.e2[-1]) 
      f <- list(phi=f1,psi=f2/sqrt(3/2))
    }
  }
  
  return(f)
}

# function 2
gets_graph <- function(h){
  edge1 <- rbind(c(0,0),c(1,0))
  theta <- seq(from=-pi,to=pi,length.out = 10000)
  edge2 <- cbind(1+1/pi+cos(theta)/pi,sin(theta)/pi)
  edges = list(edge1, edge2)
  graph <- metric_graph$new(edges = edges)
  graph$set_manual_edge_lengths(edge_lengths = c(1,2))
  graph$build_mesh(h=h)
  return(graph)
}

#function 3
gets_true_cov_mat <- function(graph, kappa, tau, alpha, n.overkill){
  Sigma.kl <- matrix(0,nrow = dim(graph$mesh$V)[1],ncol = dim(graph$mesh$V)[1])
  for(i in 0:n.overkill){
    phi <- tadpole.eig(i,graph)$phi
    Sigma.kl <- Sigma.kl + (1/(kappa^2 + (i*pi/2)^2)^(alpha))*phi%*%t(phi)
    if(i>0 && (i %% 2)==0){ 
      psi <- tadpole.eig(i,graph)$psi
      Sigma.kl <- Sigma.kl + (1/(kappa^2 + (i*pi/2)^2)^(alpha))*psi%*%t(psi)
    }
    
  }
  Sigma.kl <- Sigma.kl/tau^2
  return(Sigma.kl)
}

# parameters
h_vector = c(0.001, 0.005, 0.01, 0.1)
type_vector = c("covariance", "operator")
type_rational_approximation_vector = c("chebfun", "brasil", "chebfunLB")
rho_vector = c(0.1, 0.5, 1, 2)
m_vector = c(0,1,2,3,4,5)
nu_vector = c(seq(0.1,0.4,by=0.05), seq(0.41,0.59,by=0.01), seq(0.6,1.4,by=0.05), seq(1.41,1.59,by=0.01), seq(1.6,2.4,by=0.05), seq(2.41,2.49,by=0.01))
n.overkill = 1000
sigma = 1

Error = list()
for (s in c(1,2,3,4)) { # loop over h_vector
  Error[[as.character(h_vector[s])]] = list()
  h = h_vector[s]
  graph = gets_graph(h = h)
  for (i in c(1)) { # loop over type_vector
    Error[[as.character(h_vector[s])]][[type_vector[i]]] = list()
    type = type_vector[i]
    for (j in c(1,2,3)) { # loop over type_rational_approximation_vector
      Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]] = list()
      type_rational_approximation = type_rational_approximation_vector[j]
      for (k in c(2)) { # loop over rho_vector
        Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]] = list()
        rho = rho_vector[k]
        for (l in 1:length(m_vector)) { # loop over m_vector
          Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]] = matrix(NA, nrow = length(nu_vector), ncol = 2)
          colnames(Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]]) = c("L_inf_error", "L_2_error")
          m = m_vector[l]
          for (n in 1:length(nu_vector)) { # loop over nu_vector
            nu = nu_vector[n]
            
            kappa = sqrt(8*nu)/rho
            tau = sqrt(gamma(nu) / (sigma^2 * kappa^(2*nu) * (4*pi)^(1/2) * gamma(nu + 1/2)))  #sigma = 1, d = 1
            alpha = nu + 1/2
            
            tryCatch({
            # getting true covariance
            true_cov_mat = gets_true_cov_mat(graph = graph,
                                             kappa = kappa,
                                             tau = tau,
                                             alpha = alpha,
                                             n.overkill = n.overkill)
            
            # getting the approximate covariance matrix
            op = matern.operators(alpha = alpha, 
                                  kappa = kappa, 
                                  tau = tau,
                                  m = m, 
                                  graph = graph,
                                  type = type,
                                  type_rational_approximation = type_rational_approximation)
            appr_cov_mat = op$covariance_mesh()
            
            # computing the errors
            L_inf_error = max(abs(true_cov_mat - appr_cov_mat))
            L_2_error = sqrt(as.double(t(graph$mesh$weights)%*%(true_cov_mat - appr_cov_mat)^2%*%graph$mesh$weights))
            
            Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]][n,1] = L_inf_error
            Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]][n,2] = L_2_error
            }, error = function(err){
              warning(paste("Error occurred at iteration h=", h, ",type=", type, ",type_rational_approximation=", type_rational_approximation, ",rho=", rho, ",m=", m, ",nu=", nu, "Error:", conditionMessage(err)))
              print(paste("Error occurred at iteration h=", h, ",type=", type, ",type_rational_approximation=", type_rational_approximation, ",rho=", rho, ",m=", m, ",nu=", nu, "Error:", conditionMessage(err)))
              Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]][n,1] = NA
              Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]][n,2] = NA
            })
            print(paste("h=", h, ",type=", type, ",type_rational_approximation=", type_rational_approximation, ",rho=", rho, ",m=", m, ",nu=", nu))
          }
        }
      }
    }
  }
}

Error_tadpole_DEF_rho0.5 = Error
save(Error_tadpole_DEF_rho0.5, file = here("data_files/Error_tadpole_DEF_rho0.5.RData"))

rho = 1


Press the Show button below to reveal the code.


# library calls
library(MetricGraph)
library(Matrix)
library(rSPDE)

# function 1
tadpole.eig <- function(k,graph){
  x1 <- c(0,graph$get_edge_lengths()[1]*graph$mesh$PtE[graph$mesh$PtE[,1]==1,2]) 
  x2 <- c(0,graph$get_edge_lengths()[2]*graph$mesh$PtE[graph$mesh$PtE[,1]==2,2]) 
  
  if(k==0){ 
    f.e1 <- rep(1,length(x1)) 
    f.e2 <- rep(1,length(x2)) 
    f1 = c(f.e1[1],f.e2[1],f.e1[-1], f.e2[-1]) 
    f = list(phi=f1/sqrt(3)) 
    
  } else {
    f.e1 <- -2*sin(pi*k*1/2)*cos(pi*k*x1/2) 
    f.e2 <- sin(pi*k*x2/2)                  
    
    f1 = c(f.e1[1],f.e2[1],f.e1[-1], f.e2[-1]) 
    
    if((k %% 2)==1){ 
      f = list(phi=f1/sqrt(3)) 
    } else { 
      f.e1 <- (-1)^{k/2}*cos(pi*k*x1/2)
      f.e2 <- cos(pi*k*x2/2)
      f2 = c(f.e1[1],f.e2[1],f.e1[-1],f.e2[-1]) 
      f <- list(phi=f1,psi=f2/sqrt(3/2))
    }
  }
  
  return(f)
}

# function 2
gets_graph <- function(h){
  edge1 <- rbind(c(0,0),c(1,0))
  theta <- seq(from=-pi,to=pi,length.out = 10000)
  edge2 <- cbind(1+1/pi+cos(theta)/pi,sin(theta)/pi)
  edges = list(edge1, edge2)
  graph <- metric_graph$new(edges = edges)
  graph$set_manual_edge_lengths(edge_lengths = c(1,2))
  graph$build_mesh(h=h)
  return(graph)
}

#function 3
gets_true_cov_mat <- function(graph, kappa, tau, alpha, n.overkill){
  Sigma.kl <- matrix(0,nrow = dim(graph$mesh$V)[1],ncol = dim(graph$mesh$V)[1])
  for(i in 0:n.overkill){
    phi <- tadpole.eig(i,graph)$phi
    Sigma.kl <- Sigma.kl + (1/(kappa^2 + (i*pi/2)^2)^(alpha))*phi%*%t(phi)
    if(i>0 && (i %% 2)==0){ 
      psi <- tadpole.eig(i,graph)$psi
      Sigma.kl <- Sigma.kl + (1/(kappa^2 + (i*pi/2)^2)^(alpha))*psi%*%t(psi)
    }
    
  }
  Sigma.kl <- Sigma.kl/tau^2
  return(Sigma.kl)
}

# parameters
h_vector = c(0.001, 0.005, 0.01, 0.1)
type_vector = c("covariance", "operator")
type_rational_approximation_vector = c("chebfun", "brasil", "chebfunLB")
rho_vector = c(0.1, 0.5, 1, 2)
m_vector = c(0,1,2,3,4,5)
nu_vector = c(seq(0.1,0.4,by=0.05), seq(0.41,0.59,by=0.01), seq(0.6,1.4,by=0.05), seq(1.41,1.59,by=0.01), seq(1.6,2.4,by=0.05), seq(2.41,2.49,by=0.01)) 
n.overkill = 1000
sigma = 1

Error = list()
for (s in c(1,2,3,4)) { # loop over h_vector
  Error[[as.character(h_vector[s])]] = list()
  h = h_vector[s]
  graph = gets_graph(h = h)
  for (i in c(1)) { # loop over type_vector
    Error[[as.character(h_vector[s])]][[type_vector[i]]] = list()
    type = type_vector[i]
    for (j in c(1,2,3)) { # loop over type_rational_approximation_vector
      Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]] = list()
      type_rational_approximation = type_rational_approximation_vector[j]
      for (k in c(3)) { # loop over rho_vector
        Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]] = list()
        rho = rho_vector[k]
        for (l in 1:length(m_vector)) { # loop over m_vector
          Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]] = matrix(NA, nrow = length(nu_vector), ncol = 2)
          colnames(Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]]) = c("L_inf_error", "L_2_error")
          m = m_vector[l]
          for (n in 1:length(nu_vector)) { # loop over nu_vector
            nu = nu_vector[n]
            
            kappa = sqrt(8*nu)/rho
            tau = sqrt(gamma(nu) / (sigma^2 * kappa^(2*nu) * (4*pi)^(1/2) * gamma(nu + 1/2)))  #sigma = 1, d = 1
            alpha = nu + 1/2
            
            tryCatch({
            # getting true covariance
            true_cov_mat = gets_true_cov_mat(graph = graph,
                                             kappa = kappa,
                                             tau = tau,
                                             alpha = alpha,
                                             n.overkill = n.overkill)
            
            # getting the approximate covariance matrix
            op = matern.operators(alpha = alpha, 
                                  kappa = kappa, 
                                  tau = tau,
                                  m = m, 
                                  graph = graph,
                                  type = type,
                                  type_rational_approximation = type_rational_approximation)
            appr_cov_mat = op$covariance_mesh()
            
            # computing the errors
            L_inf_error = max(abs(true_cov_mat - appr_cov_mat))
            L_2_error = sqrt(as.double(t(graph$mesh$weights)%*%(true_cov_mat - appr_cov_mat)^2%*%graph$mesh$weights))
            
            Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]][n,1] = L_inf_error
            Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]][n,2] = L_2_error
            }, error = function(err){
              warning(paste("Error occurred at iteration h=", h, ",type=", type, ",type_rational_approximation=", type_rational_approximation, ",rho=", rho, ",m=", m, ",nu=", nu, "Error:", conditionMessage(err)))
              print(paste("Error occurred at iteration h=", h, ",type=", type, ",type_rational_approximation=", type_rational_approximation, ",rho=", rho, ",m=", m, ",nu=", nu, "Error:", conditionMessage(err)))
              Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]][n,1] = NA
              Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]][n,2] = NA
            })
            print(paste("h=", h, ",type=", type, ",type_rational_approximation=", type_rational_approximation, ",rho=", rho, ",m=", m, ",nu=", nu))
          }
        }
      }
    }
  }
}

Error_tadpole_DEF_rho1 = Error
save(Error_tadpole_DEF_rho1, file = here("data_files/Error_tadpole_DEF_rho1.RData"))

rho = 2


Press the Show button below to reveal the code.


# library calls
library(MetricGraph)
library(Matrix)
library(rSPDE)

# function 1
tadpole.eig <- function(k,graph){
  x1 <- c(0,graph$get_edge_lengths()[1]*graph$mesh$PtE[graph$mesh$PtE[,1]==1,2]) 
  x2 <- c(0,graph$get_edge_lengths()[2]*graph$mesh$PtE[graph$mesh$PtE[,1]==2,2]) 
  
  if(k==0){ 
    f.e1 <- rep(1,length(x1)) 
    f.e2 <- rep(1,length(x2)) 
    f1 = c(f.e1[1],f.e2[1],f.e1[-1], f.e2[-1]) 
    f = list(phi=f1/sqrt(3)) 
    
  } else {
    f.e1 <- -2*sin(pi*k*1/2)*cos(pi*k*x1/2) 
    f.e2 <- sin(pi*k*x2/2)                  
    
    f1 = c(f.e1[1],f.e2[1],f.e1[-1], f.e2[-1]) 
    
    if((k %% 2)==1){ 
      f = list(phi=f1/sqrt(3)) 
    } else { 
      f.e1 <- (-1)^{k/2}*cos(pi*k*x1/2)
      f.e2 <- cos(pi*k*x2/2)
      f2 = c(f.e1[1],f.e2[1],f.e1[-1],f.e2[-1]) 
      f <- list(phi=f1,psi=f2/sqrt(3/2))
    }
  }
  
  return(f)
}

# function 2
gets_graph <- function(h){
  edge1 <- rbind(c(0,0),c(1,0))
  theta <- seq(from=-pi,to=pi,length.out = 10000)
  edge2 <- cbind(1+1/pi+cos(theta)/pi,sin(theta)/pi)
  edges = list(edge1, edge2)
  graph <- metric_graph$new(edges = edges)
  graph$set_manual_edge_lengths(edge_lengths = c(1,2))
  graph$build_mesh(h=h)
  return(graph)
}

#function 3
gets_true_cov_mat <- function(graph, kappa, tau, alpha, n.overkill){
  Sigma.kl <- matrix(0,nrow = dim(graph$mesh$V)[1],ncol = dim(graph$mesh$V)[1])
  for(i in 0:n.overkill){
    phi <- tadpole.eig(i,graph)$phi
    Sigma.kl <- Sigma.kl + (1/(kappa^2 + (i*pi/2)^2)^(alpha))*phi%*%t(phi)
    if(i>0 && (i %% 2)==0){ 
      psi <- tadpole.eig(i,graph)$psi
      Sigma.kl <- Sigma.kl + (1/(kappa^2 + (i*pi/2)^2)^(alpha))*psi%*%t(psi)
    }
    
  }
  Sigma.kl <- Sigma.kl/tau^2
  return(Sigma.kl)
}

# parameters
h_vector = c(0.001, 0.005, 0.01, 0.1)
type_vector = c("covariance", "operator")
type_rational_approximation_vector = c("chebfun", "brasil", "chebfunLB")
rho_vector = c(0.1, 0.5, 1, 2)
m_vector = c(0,1,2,3,4,5)
nu_vector = c(seq(0.1,0.4,by=0.05), seq(0.41,0.59,by=0.01), seq(0.6,1.4,by=0.05), seq(1.41,1.59,by=0.01), seq(1.6,2.4,by=0.05), seq(2.41,2.49,by=0.01)) 
n.overkill = 1000
sigma = 1

Error = list()
for (s in c(1,2,3,4)) { # loop over h_vector
  Error[[as.character(h_vector[s])]] = list()
  h = h_vector[s]
  graph = gets_graph(h = h)
  for (i in c(1)) { # loop over type_vector
    Error[[as.character(h_vector[s])]][[type_vector[i]]] = list()
    type = type_vector[i]
    for (j in c(1,2,3)) { # loop over type_rational_approximation_vector
      Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]] = list()
      type_rational_approximation = type_rational_approximation_vector[j]
      for (k in c(4)) { # loop over rho_vector
        Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]] = list()
        rho = rho_vector[k]
        for (l in 1:length(m_vector)) { # loop over m_vector
          Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]] = matrix(NA, nrow = length(nu_vector), ncol = 2)
          colnames(Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]]) = c("L_inf_error", "L_2_error")
          m = m_vector[l]
          for (n in 1:length(nu_vector)) { # loop over nu_vector
            nu = nu_vector[n]
            
            kappa = sqrt(8*nu)/rho
            tau = sqrt(gamma(nu) / (sigma^2 * kappa^(2*nu) * (4*pi)^(1/2) * gamma(nu + 1/2)))  #sigma = 1, d = 1
            alpha = nu + 1/2
            
            tryCatch({
            # getting true covariance
            true_cov_mat = gets_true_cov_mat(graph = graph,
                                             kappa = kappa,
                                             tau = tau,
                                             alpha = alpha,
                                             n.overkill = n.overkill)
            
            # getting the approximate covariance matrix
            op = matern.operators(alpha = alpha, 
                                  kappa = kappa, 
                                  tau = tau,
                                  m = m, 
                                  graph = graph,
                                  type = type,
                                  type_rational_approximation = type_rational_approximation)
            appr_cov_mat = op$covariance_mesh()
            
            # computing the errors
            L_inf_error = max(abs(true_cov_mat - appr_cov_mat))
            L_2_error = sqrt(as.double(t(graph$mesh$weights)%*%(true_cov_mat - appr_cov_mat)^2%*%graph$mesh$weights))
            
            Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]][n,1] = L_inf_error
            Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]][n,2] = L_2_error
            }, error = function(err){
              warning(paste("Error occurred at iteration h=", h, ",type=", type, ",type_rational_approximation=", type_rational_approximation, ",rho=", rho, ",m=", m, ",nu=", nu, "Error:", conditionMessage(err)))
              print(paste("Error occurred at iteration h=", h, ",type=", type, ",type_rational_approximation=", type_rational_approximation, ",rho=", rho, ",m=", m, ",nu=", nu, "Error:", conditionMessage(err)))
              Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]][n,1] = NA
              Error[[as.character(h_vector[s])]][[type_vector[i]]][[type_rational_approximation_vector[j]]][[as.character(rho_vector[k])]][[as.character(m_vector[l])]][n,2] = NA
            })
            print(paste("h=", h, ",type=", type, ",type_rational_approximation=", type_rational_approximation, ",rho=", rho, ",m=", m, ",nu=", nu))
          }
        }
      }
    }
  }
}

Error_tadpole_DEF_rho2 = Error
save(Error_tadpole_DEF_rho2, file = here("data_files/Error_tadpole_DEF_rho2.RData"))

Plotting the errors

load(here("data_files/Error_tadpole_DEF_rho0.1.RData"))
load(here("data_files/Error_tadpole_DEF_rho0.5.RData"))
load(here("data_files/Error_tadpole_DEF_rho1.RData"))
load(here("data_files/Error_tadpole_DEF_rho2.RData"))

h_vector = c("0.001", "0.005", "0.01", "0.1")
type_rational_approximation_vector = c("chebfun", "brasil", "chebfunLB")
nu_max = 53
nu_vector = 0.5 + c(seq(0.1,0.4,by=0.05), seq(0.41,0.59,by=0.01), seq(0.6,1.4,by=0.05), seq(1.41,1.59,by=0.01), seq(1.6,2.4,by=0.05), seq(2.41,2.49,by=0.01))[1:nu_max]

n = "0.001"
t = "chebfun"


dat = rbind(
data.frame(nu = rep(nu_vector,5), 
           rho = rep(0.1, times = 5*nu_max),
           m = rep(1:5, each = nu_max),
           error = c(Error_tadpole_DEF_rho0.1[[n]][["covariance"]][[t]][["0.1"]][["1"]][1:nu_max,1],
                     Error_tadpole_DEF_rho0.1[[n]][["covariance"]][[t]][["0.1"]][["2"]][1:nu_max,1],
                     Error_tadpole_DEF_rho0.1[[n]][["covariance"]][[t]][["0.1"]][["3"]][1:nu_max,1],
                     Error_tadpole_DEF_rho0.1[[n]][["covariance"]][[t]][["0.1"]][["4"]][1:nu_max,1],
                     Error_tadpole_DEF_rho0.1[[n]][["covariance"]][[t]][["0.1"]][["5"]][1:nu_max,1]),
           L = rep("Linf", times = 5*nu_max)
),

data.frame(nu = rep(nu_vector,5), 
           rho = c(rep(0.5, times = 5*nu_max)),
           m = rep(1:5, each = nu_max),
           error = c(Error_tadpole_DEF_rho0.5[[n]][["covariance"]][[t]][["0.5"]][["1"]][1:nu_max,1],
                     Error_tadpole_DEF_rho0.5[[n]][["covariance"]][[t]][["0.5"]][["2"]][1:nu_max,1],
                     Error_tadpole_DEF_rho0.5[[n]][["covariance"]][[t]][["0.5"]][["3"]][1:nu_max,1],
                     Error_tadpole_DEF_rho0.5[[n]][["covariance"]][[t]][["0.5"]][["4"]][1:nu_max,1],
                     Error_tadpole_DEF_rho0.5[[n]][["covariance"]][[t]][["0.5"]][["5"]][1:nu_max,1]),
           L = rep("Linf", times = 5*nu_max)
),

data.frame(nu = rep(nu_vector,5), 
           rho = c(rep(1, times = 5*nu_max)),
           m = rep(1:5, each = nu_max),
           error = c(Error_tadpole_DEF_rho1[[n]][["covariance"]][[t]][["1"]][["1"]][1:nu_max,1],
                     Error_tadpole_DEF_rho1[[n]][["covariance"]][[t]][["1"]][["2"]][1:nu_max,1],
                     Error_tadpole_DEF_rho1[[n]][["covariance"]][[t]][["1"]][["3"]][1:nu_max,1],
                     Error_tadpole_DEF_rho1[[n]][["covariance"]][[t]][["1"]][["4"]][1:nu_max,1],
                     Error_tadpole_DEF_rho1[[n]][["covariance"]][[t]][["1"]][["5"]][1:nu_max,1]),
           L = rep("Linf", times = 5*nu_max)
),

data.frame(nu = rep(nu_vector,5), 
           rho = c(rep(2, times = 5*nu_max)),
           m = rep(1:5, each = nu_max),
           error = c(Error_tadpole_DEF_rho2[[n]][["covariance"]][[t]][["2"]][["1"]][1:nu_max,1],
                     Error_tadpole_DEF_rho2[[n]][["covariance"]][[t]][["2"]][["2"]][1:nu_max,1],
                     Error_tadpole_DEF_rho2[[n]][["covariance"]][[t]][["2"]][["3"]][1:nu_max,1],
                     Error_tadpole_DEF_rho2[[n]][["covariance"]][[t]][["2"]][["4"]][1:nu_max,1],
                     Error_tadpole_DEF_rho2[[n]][["covariance"]][[t]][["2"]][["5"]][1:nu_max,1]),
           L = rep("Linf", times = 5*nu_max)
),

## L2

data.frame(nu = rep(nu_vector,5), 
           rho = rep(0.1, times = 5*nu_max),
           m = rep(1:5, each = nu_max),
           error = c(Error_tadpole_DEF_rho0.1[[n]][["covariance"]][[t]][["0.1"]][["1"]][1:nu_max,2],
                     Error_tadpole_DEF_rho0.1[[n]][["covariance"]][[t]][["0.1"]][["2"]][1:nu_max,2],
                     Error_tadpole_DEF_rho0.1[[n]][["covariance"]][[t]][["0.1"]][["3"]][1:nu_max,2],
                     Error_tadpole_DEF_rho0.1[[n]][["covariance"]][[t]][["0.1"]][["4"]][1:nu_max,2],
                     Error_tadpole_DEF_rho0.1[[n]][["covariance"]][[t]][["0.1"]][["5"]][1:nu_max,2]),
           L = rep("L2", times = 5*nu_max)
),

data.frame(nu = rep(nu_vector,5), 
           rho = c(rep(0.5, times = 5*nu_max)),
           m = rep(1:5, each = nu_max),
           error = c(Error_tadpole_DEF_rho0.5[[n]][["covariance"]][[t]][["0.5"]][["1"]][1:nu_max,2],
                     Error_tadpole_DEF_rho0.5[[n]][["covariance"]][[t]][["0.5"]][["2"]][1:nu_max,2],
                     Error_tadpole_DEF_rho0.5[[n]][["covariance"]][[t]][["0.5"]][["3"]][1:nu_max,2],
                     Error_tadpole_DEF_rho0.5[[n]][["covariance"]][[t]][["0.5"]][["4"]][1:nu_max,2],
                     Error_tadpole_DEF_rho0.5[[n]][["covariance"]][[t]][["0.5"]][["5"]][1:nu_max,2]),
           L = rep("L2", times = 5*nu_max)
),

data.frame(nu = rep(nu_vector,5), 
           rho = c(rep(1, times = 5*nu_max)),
           m = rep(1:5, each = nu_max),
           error = c(Error_tadpole_DEF_rho1[[n]][["covariance"]][[t]][["1"]][["1"]][1:nu_max,2],
                     Error_tadpole_DEF_rho1[[n]][["covariance"]][[t]][["1"]][["2"]][1:nu_max,2],
                     Error_tadpole_DEF_rho1[[n]][["covariance"]][[t]][["1"]][["3"]][1:nu_max,2],
                     Error_tadpole_DEF_rho1[[n]][["covariance"]][[t]][["1"]][["4"]][1:nu_max,2],
                     Error_tadpole_DEF_rho1[[n]][["covariance"]][[t]][["1"]][["5"]][1:nu_max,2]),
           L = rep("L2", times = 5*nu_max)
),

data.frame(nu = rep(nu_vector,5), 
           rho = c(rep(2, times = 5*nu_max)),
           m = rep(1:5, each = nu_max),
           error = c(Error_tadpole_DEF_rho2[[n]][["covariance"]][[t]][["2"]][["1"]][1:nu_max,2],
                     Error_tadpole_DEF_rho2[[n]][["covariance"]][[t]][["2"]][["2"]][1:nu_max,2],
                     Error_tadpole_DEF_rho2[[n]][["covariance"]][[t]][["2"]][["3"]][1:nu_max,2],
                     Error_tadpole_DEF_rho2[[n]][["covariance"]][[t]][["2"]][["4"]][1:nu_max,2],
                     Error_tadpole_DEF_rho2[[n]][["covariance"]][[t]][["2"]][["5"]][1:nu_max,2]),
           L = rep("L2", times = 5*nu_max)
)
)


dat$rho = factor(dat$rho, levels = c("0.1", "0.5", "1", "2"))
dat$L = factor(dat$L, levels = c("L2", "Linf"))
levels(dat$rho) = c("0.1" = latex2exp::TeX("$\\rho = 0.1$"), "0.5" = latex2exp::TeX("$\\rho = 0.5$"), "1" = latex2exp::TeX("$\\rho = 1$"), "2" = latex2exp::TeX("$\\rho = 2$"))
levels(dat$L) = c("L2" = latex2exp::TeX("$L_2(\\Gamma\\times\\Gamma)$ error"), "Linf" = latex2exp::TeX("$L_\\infty(\\Gamma\\times\\Gamma)$ error"))

p <- ggplot(dat, aes(nu, error, colour = as.factor(m))) + 
  facet_grid(L ~ rho, labeller = label_parsed) +
  geom_line() +
  scale_y_log10(n.breaks = 5) +
  scale_x_continuous(n.breaks = 10) +
  theme_bw() +
  theme(panel.spacing = unit(0.3, "cm"), text = element_text(family = "Palatino"),
        plot.title = element_text(size = 16),
        strip.text = element_text(size = 12),        # Panel titles
        axis.title = element_text(size = 14),        # Axis titles
        axis.text = element_text(size = 12),         # Axis text
        legend.title = element_text(size = 14),      # Legend title
        legend.text = element_text(size = 12)) +
  labs(x = bquote(alpha ~ "(smoothness parameter)"), y = "Covariance Error", color = "m") + ggtitle("Tadpole graph")
p
Figure 3: Covariance error for the tadpole graph.

Figure 3: Covariance error for the tadpole graph.

ggsave(here("data_files/new_tadpole_upto1.5.png"), width = 12, height = 6, plot = p, dpi = 300)

References

cite_packages(output = "paragraph", out.dir = ".")

We used R version 4.4.1 (R Core Team 2024a) and the following R packages: cowplot v. 1.1.3 (Wilke 2024), ggmap v. 4.0.0.900 (Kahle and Wickham 2013), ggpubr v. 0.6.0 (Kassambara 2023), ggtext v. 0.1.2 (Wilke and Wiernik 2022), grid v. 4.4.1 (R Core Team 2024b), here v. 1.0.1 (Müller 2020), htmltools v. 0.5.8.1 (Cheng et al. 2024), INLA v. 24.12.11 (Rue, Martino, and Chopin 2009; Lindgren, Rue, and Lindström 2011; Martins et al. 2013; Lindgren and Rue 2015; De Coninck et al. 2016; Rue et al. 2017; Verbosio et al. 2017; Bakka et al. 2018; Kourounis, Fuchs, and Schenk 2018), inlabru v. 2.12.0.9002 (Yuan et al. 2017; Bachl et al. 2019), knitr v. 1.48 (Xie 2014, 2015, 2024), latex2exp v. 0.9.6 (Meschiari 2022), Matrix v. 1.6.5 (Bates, Maechler, and Jagan 2024), MetricGraph v. 1.4.0.9000 (Bolin, Simas, and Wallin 2023b, 2023a, 2023c, 2024; Bolin et al. 2024), OpenStreetMap v. 0.4.0 (Fellows and JMapViewer library by Jan Peter Stotz 2023), osmdata v. 0.2.5 (Mark Padgham et al. 2017), patchwork v. 1.2.0 (Pedersen 2024), plotly v. 4.10.4 (Sievert 2020), plotrix v. 3.8.4 (J 2006), reshape2 v. 1.4.4 (Wickham 2007), rmarkdown v. 2.28 (Xie, Allaire, and Grolemund 2018; Xie, Dervieux, and Riederer 2020; Allaire et al. 2024), rSPDE v. 2.4.0.9000 (Bolin and Kirchner 2020; Bolin and Simas 2023; Bolin, Simas, and Xiong 2024), scales v. 1.3.0 (Wickham, Pedersen, and Seidel 2023), sf v. 1.0.19 (E. Pebesma 2018; E. Pebesma and Bivand 2023), sp v. 2.1.4 (E. J. Pebesma and Bivand 2005; Bivand, Pebesma, and Gomez-Rubio 2013), tidyverse v. 2.0.0 (Wickham et al. 2019), viridis v. 0.6.4 (Garnier et al. 2023), xaringanExtra v. 0.8.0 (Aden-Buie and Warkentin 2024).

Aden-Buie, Garrick, and Matthew T. Warkentin. 2024. xaringanExtra: Extras and Extensions for xaringan Slides. https://CRAN.R-project.org/package=xaringanExtra.
Allaire, JJ, Yihui Xie, Christophe Dervieux, Jonathan McPherson, Javier Luraschi, Kevin Ushey, Aron Atkins, et al. 2024. rmarkdown: Dynamic Documents for r. https://github.com/rstudio/rmarkdown.
Bachl, Fabian E., Finn Lindgren, David L. Borchers, and Janine B. Illian. 2019. inlabru: An R Package for Bayesian Spatial Modelling from Ecological Survey Data.” Methods in Ecology and Evolution 10: 760–66. https://doi.org/10.1111/2041-210X.13168.
Bakka, Haakon, Håvard Rue, Geir-Arne Fuglstad, Andrea I. Riebler, David Bolin, Janine Illian, Elias Krainski, Daniel P. Simpson, and Finn K. Lindgren. 2018. “Spatial Modelling with INLA: A Review.” WIRES (Invited Extended Review) xx (Feb): xx–. http://arxiv.org/abs/1802.06350.
Bates, Douglas, Martin Maechler, and Mikael Jagan. 2024. Matrix: Sparse and Dense Matrix Classes and Methods. https://CRAN.R-project.org/package=Matrix.
Bivand, Roger S., Edzer Pebesma, and Virgilio Gomez-Rubio. 2013. Applied Spatial Data Analysis with R, Second Edition. Springer, NY. https://asdar-book.org/.
Bolin, David, and Kristin Kirchner. 2020. “The Rational SPDE Approach for Gaussian Random Fields with General Smoothness.” Journal of Computational and Graphical Statistics 29 (2): 274–85. https://doi.org/10.1080/10618600.2019.1665537.
Bolin, David, Mihály Kovács, Vivek Kumar, and Alexandre B. Simas. 2024. “Regularity and Numerical Approximation of Fractional Elliptic Differential Equations on Compact Metric Graphs.” Mathematics of Computation 93 (349): 2439–72. https://doi.org/10.1090/mcom/3929.
Bolin, David, and Alexandre B. Simas. 2023. rSPDE: Rational Approximations of Fractional Stochastic Partial Differential Equations. https://CRAN.R-project.org/package=rSPDE.
Bolin, David, Alexandre B. Simas, and Jonas Wallin. 2023a. “Markov Properties of Gaussian Random Fields on Compact Metric Graphs.” arXiv Preprint arXiv:2304.03190. https://doi.org/10.48550/arXiv.2304.03190.
———. 2023b. MetricGraph: Random Fields on Metric Graphs. https://CRAN.R-project.org/package=MetricGraph.
———. 2023c. “Statistical Inference for Gaussian Whittle-Matérn Fields on Metric Graphs.” arXiv Preprint arXiv:2304.10372. https://doi.org/10.48550/arXiv.2304.10372.
———. 2024. “Gaussian Whittle-Matérn Fields on Metric Graphs.” Bernoulli 30 (2): 1611–39. https://doi.org/10.3150/23-BEJ1647.
Bolin, David, Alexandre B. Simas, and Zhen Xiong. 2024. “Covariance-Based Rational Approximations of Fractional SPDEs for Computationally Efficient Bayesian Inference.” Journal of Computational and Graphical Statistics 33 (1): 64–74. https://doi.org/10.1080/10618600.2023.2231051.
Cheng, Joe, Carson Sievert, Barret Schloerke, Winston Chang, Yihui Xie, and Jeff Allen. 2024. htmltools: Tools for HTML. https://CRAN.R-project.org/package=htmltools.
De Coninck, Arne, Bernard De Baets, Drosos Kourounis, Fabio Verbosio, Olaf Schenk, Steven Maenhout, and Jan Fostier. 2016. Needles: Toward Large-Scale Genomic Prediction with Marker-by-Environment Interaction.” Genetics 203 (1): 543–55. https://doi.org/10.1534/genetics.115.179887.
Fellows, Ian, and using the JMapViewer library by Jan Peter Stotz. 2023. OpenStreetMap: Access to Open Street Map Raster Images. https://CRAN.R-project.org/package=OpenStreetMap.
Garnier, Simon, Ross, Noam, Rudis, Robert, Camargo, et al. 2023. viridis(Lite) - Colorblind-Friendly Color Maps for r. https://doi.org/10.5281/zenodo.4679423.
J, Lemon. 2006. Plotrix: A Package in the Red Light District of r.” R-News 6 (4): 8–12.
Kahle, David, and Hadley Wickham. 2013. ggmap: Spatial Visualization with Ggplot2.” The R Journal 5 (1): 144–61. https://journal.r-project.org/archive/2013-1/kahle-wickham.pdf.
Kassambara, Alboukadel. 2023. ggpubr: ggplot2 Based Publication Ready Plots. https://CRAN.R-project.org/package=ggpubr.
Kourounis, D., A. Fuchs, and O. Schenk. 2018. “Towards the Next Generation of Multiperiod Optimal Power Flow Solvers.” IEEE Transactions on Power Systems PP (99): 1–10. https://doi.org/10.1109/TPWRS.2017.2789187.
Lindgren, Finn, and Håvard Rue. 2015. “Bayesian Spatial Modelling with R-INLA.” Journal of Statistical Software 63 (19): 1–25. http://www.jstatsoft.org/v63/i19/.
Lindgren, Finn, Håvard Rue, and Johan Lindström. 2011. “An Explicit Link Between Gaussian Fields and Gaussian Markov Random Fields: The Stochastic Partial Differential Equation Approach (with Discussion).” Journal of the Royal Statistical Society B 73 (4): 423–98.
Mark Padgham, Bob Rudis, Robin Lovelace, and Maëlle Salmon. 2017. “Osmdata.” Journal of Open Source Software 2 (14): 305. https://doi.org/10.21105/joss.00305.
Martins, Thiago G., Daniel Simpson, Finn Lindgren, and Håvard Rue. 2013. “Bayesian Computing with INLA: New Features.” Computational Statistics and Data Analysis 67: 68–83.
Meschiari, Stefano. 2022. Latex2exp: Use LaTeX Expressions in Plots. https://CRAN.R-project.org/package=latex2exp.
Müller, Kirill. 2020. here: A Simpler Way to Find Your Files. https://CRAN.R-project.org/package=here.
Pebesma, Edzer. 2018. Simple Features for R: Standardized Support for Spatial Vector Data.” The R Journal 10 (1): 439–46. https://doi.org/10.32614/RJ-2018-009.
Pebesma, Edzer J., and Roger Bivand. 2005. “Classes and Methods for Spatial Data in R.” R News 5 (2): 9–13. https://CRAN.R-project.org/doc/Rnews/.
Pebesma, Edzer, and Roger Bivand. 2023. Spatial Data Science: With applications in R. Chapman and Hall/CRC. https://doi.org/10.1201/9780429459016.
Pedersen, Thomas Lin. 2024. patchwork: The Composer of Plots. https://CRAN.R-project.org/package=patchwork.
R Core Team. 2024a. R: A Language and Environment for Statistical Computing. Vienna, Austria: R Foundation for Statistical Computing. https://www.R-project.org/.
———. 2024b. R: A Language and Environment for Statistical Computing. Vienna, Austria: R Foundation for Statistical Computing. https://www.R-project.org/.
Rue, Håvard, Sara Martino, and Nicholas Chopin. 2009. “Approximate Bayesian Inference for Latent Gaussian Models Using Integrated Nested Laplace Approximations (with Discussion).” Journal of the Royal Statistical Society B 71: 319–92.
Rue, Håvard, Andrea I. Riebler, Sigrunn H. Sørbye, Janine B. Illian, Daniel P. Simpson, and Finn K. Lindgren. 2017. “Bayesian Computing with INLA: A Review.” Annual Reviews of Statistics and Its Applications 4 (March): 395–421. http://arxiv.org/abs/1604.00860.
Sievert, Carson. 2020. Interactive Web-Based Data Visualization with r, Plotly, and Shiny. Chapman; Hall/CRC. https://plotly-r.com.
Verbosio, Fabio, Arne De Coninck, Drosos Kourounis, and Olaf Schenk. 2017. “Enhancing the Scalability of Selected Inversion Factorization Algorithms in Genomic Prediction.” Journal of Computational Science 22 (Supplement C): 99–108. https://doi.org/10.1016/j.jocs.2017.08.013.
Wickham, Hadley. 2007. “Reshaping Data with the reshape Package.” Journal of Statistical Software 21 (12): 1–20. http://www.jstatsoft.org/v21/i12/.
Wickham, Hadley, Mara Averick, Jennifer Bryan, Winston Chang, Lucy D’Agostino McGowan, Romain François, Garrett Grolemund, et al. 2019. “Welcome to the tidyverse.” Journal of Open Source Software 4 (43): 1686. https://doi.org/10.21105/joss.01686.
Wickham, Hadley, Thomas Lin Pedersen, and Dana Seidel. 2023. scales: Scale Functions for Visualization. https://CRAN.R-project.org/package=scales.
Wilke, Claus O. 2024. cowplot: Streamlined Plot Theme and Plot Annotations for ggplot2. https://CRAN.R-project.org/package=cowplot.
Wilke, Claus O., and Brenton M. Wiernik. 2022. ggtext: Improved Text Rendering Support for ggplot2. https://CRAN.R-project.org/package=ggtext.
Xie, Yihui. 2014. knitr: A Comprehensive Tool for Reproducible Research in R.” In Implementing Reproducible Computational Research, edited by Victoria Stodden, Friedrich Leisch, and Roger D. Peng. Chapman; Hall/CRC.
———. 2015. Dynamic Documents with R and Knitr. 2nd ed. Boca Raton, Florida: Chapman; Hall/CRC. https://yihui.org/knitr/.
———. 2024. knitr: A General-Purpose Package for Dynamic Report Generation in r. https://yihui.org/knitr/.
Xie, Yihui, J. J. Allaire, and Garrett Grolemund. 2018. R Markdown: The Definitive Guide. Boca Raton, Florida: Chapman; Hall/CRC. https://bookdown.org/yihui/rmarkdown.
Xie, Yihui, Christophe Dervieux, and Emily Riederer. 2020. R Markdown Cookbook. Boca Raton, Florida: Chapman; Hall/CRC. https://bookdown.org/yihui/rmarkdown-cookbook.
Yuan, Yuan, Bachl, Fabian E., Lindgren, Finn, Borchers, et al. 2017. “Point Process Models for Spatio-Temporal Distance Sampling Data from a Large-Scale Survey of Blue Whales.” Ann. Appl. Stat. 11 (4): 2270–97. https://doi.org/10.1214/17-AOAS1078.
LS0tCnRpdGxlOiAiTnVtZXJpY2FsIGVycm9yIgpkYXRlOiAiQ3JlYXRlZDogMDUtMDctMjAyNC4gTGFzdCBtb2RpZmllZDogYHIgZm9ybWF0KFN5cy50aW1lKCksICclZC0lbS0lWS4nKWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgbWF0aGpheDogImh0dHBzOi8vY2RuLmpzZGVsaXZyLm5ldC9ucG0vbWF0aGpheEAzL2VzNS90ZXgtbW1sLWNodG1sLmpzIgogICAgaGlnaGxpZ2h0OiBweWdtZW50cwogICAgdGhlbWU6IGZsYXRseQogICAgY29kZV9mb2xkaW5nOiBzaG93ICMgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSIgdG8gaGlkZSBjb2RlIGFuZCBhZGQgYSBidXR0b24gdG8gc2hvdyBpdAogICAgIyBkZl9wcmludDogcGFnZWQKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IHRydWUKICAgICAgc21vb3RoX3Njcm9sbDogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiBmYWxzZQogICAgZmlnX2NhcHRpb246IHRydWUKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKYWx3YXlzX2FsbG93X2h0bWw6IHRydWUKYmlibGlvZ3JhcGh5OiAKICAtIHJlZmVyZW5jZXMuYmliCiAgLSBncmF0ZWZ1bC1yZWZzLmJpYgpoZWFkZXItaW5jbHVkZXM6CiAgLSBcbmV3Y29tbWFuZHtcYXJ9e1xtYXRoYmJ7Un19CiAgLSBcbmV3Y29tbWFuZHtcbGxhdn1bMV17XGxlZnRceyMxXHJpZ2h0XH19CiAgLSBcbmV3Y29tbWFuZHtccGFyZX1bMV17XGxlZnQoIzFccmlnaHQpfQogIC0gXG5ld2NvbW1hbmR7XE5jYWx9e1xtYXRoY2Fse059fQogIC0gXG5ld2NvbW1hbmR7XFZjYWx9e1xtYXRoY2Fse1Z9fQogIC0gXG5ld2NvbW1hbmR7XEVjYWx9e1xtYXRoY2Fse0V9fQogIC0gXG5ld2NvbW1hbmR7XFdjYWx9e1xtYXRoY2Fse1d9fQotLS0KCgpgYGB7ciB4YXJpbmdhbkV4dHJhLWNsaXBib2FyZCwgZWNobyA9IEZBTFNFfQpodG1sdG9vbHM6OnRhZ0xpc3QoCiAgeGFyaW5nYW5FeHRyYTo6dXNlX2NsaXBib2FyZCgKICAgIGJ1dHRvbl90ZXh0ID0gIjxpIGNsYXNzPVwiZmEtc29saWQgZmEtY2xpcGJvYXJkXCIgc3R5bGU9XCJjb2xvcjogIzAwMDA4QlwiPjwvaT4iLAogICAgc3VjY2Vzc190ZXh0ID0gIjxpIGNsYXNzPVwiZmEgZmEtY2hlY2tcIiBzdHlsZT1cImNvbG9yOiAjOTBCRTZEXCI+PC9pPiIsCiAgICBlcnJvcl90ZXh0ID0gIjxpIGNsYXNzPVwiZmEgZmEtdGltZXMtY2lyY2xlXCIgc3R5bGU9XCJjb2xvcjogI0Y5NDE0NFwiPjwvaT4iCiAgKSwKICBybWFya2Rvd246Omh0bWxfZGVwZW5kZW5jeV9mb250X2F3ZXNvbWUoKQopCmBgYAoKCmBgYHtjc3MsIGVjaG8gPSBGQUxTRX0KYm9keSAubWFpbi1jb250YWluZXIgewogIG1heC13aWR0aDogMTAwJSAhaW1wb3J0YW50OwogIHdpZHRoOiAxMDAlICFpbXBvcnRhbnQ7Cn0KYm9keSB7CiAgbWF4LXdpZHRoOiAxMDAlICFpbXBvcnRhbnQ7Cn0KCmJvZHksIHRkIHsKICAgZm9udC1zaXplOiAxNnB4Owp9CmNvZGUucnsKICBmb250LXNpemU6IDE0cHg7Cn0KcHJlIHsKICBmb250LXNpemU6IDE0cHgKfQouY3VzdG9tLWJveCB7CiAgYmFja2dyb3VuZC1jb2xvcjogI2Y1ZjdmYTsgLyogTGlnaHQgZ3JleS1ibHVlIGJhY2tncm91bmQgKi8KICBib3JkZXItY29sb3I6ICNlMWU4ZWQ7IC8qIExpZ2h0IGJvcmRlciBjb2xvciAqLwogIGNvbG9yOiAjMmMzZTUwOyAvKiBEYXJrIHRleHQgY29sb3IgKi8KICBwYWRkaW5nOiAxNXB4OyAvKiBQYWRkaW5nIGluc2lkZSB0aGUgYm94ICovCiAgYm9yZGVyLXJhZGl1czogNXB4OyAvKiBSb3VuZGVkIGNvcm5lcnMgKi8KICBtYXJnaW4tYm90dG9tOiAyMHB4OyAvKiBTcGFjaW5nIGJlbG93IHRoZSBib3ggKi8KfQouY2FwdGlvbiB7CiAgbWFyZ2luOiBhdXRvOwogIHRleHQtYWxpZ246IGNlbnRlcjsKICBtYXJnaW4tYm90dG9tOiAyMHB4OyAvKiBTcGFjaW5nIGJlbG93IHRoZSBib3ggKi8KfQpgYGAKCgpHbyBiYWNrIHRvIHRoZSBbQWJvdXQgcGFnZV0oYWJvdXQuaHRtbCkuIFRoaXMgW2xpbmtdKGRhdGFfZmlsZXMvUkVBRE1FLmh0bWwpIG1pZ2h0IGJlIHVzZWZ1bCB0byBrZWVwIHRyYWNrIG9mIHRoZSBmaWxlcyBjcmVhdGVkIGR1cmluZyB0aGUgcHJlcHJvY2Vzc2luZy4KCkxldCB1cyBzZXQgc29tZSBnbG9iYWwgb3B0aW9ucyBmb3IgYWxsIGNvZGUgY2h1bmtzIGluIHRoaXMgZG9jdW1lbnQuCgoKYGBge3J9CiMgU2V0IHNlZWQgZm9yIHJlcHJvZHVjaWJpbGl0eQpzZXQuc2VlZCgxOTgyKSAKIyBTZXQgZ2xvYmFsIG9wdGlvbnMgZm9yIGFsbCBjb2RlIGNodW5rcwprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgIyBEaXNhYmxlIG1lc3NhZ2VzIHByaW50ZWQgYnkgUiBjb2RlIGNodW5rcwogIG1lc3NhZ2UgPSBGQUxTRSwgICAgCiAgIyBEaXNhYmxlIHdhcm5pbmdzIHByaW50ZWQgYnkgUiBjb2RlIGNodW5rcwogIHdhcm5pbmcgPSBGQUxTRSwgICAgCiAgIyBTaG93IFIgY29kZSB3aXRoaW4gY29kZSBjaHVua3MgaW4gb3V0cHV0CiAgZWNobyA9IFRSVUUsICAgICAgICAKICAjIEluY2x1ZGUgYm90aCBSIGNvZGUgYW5kIGl0cyByZXN1bHRzIGluIG91dHB1dAogIGluY2x1ZGUgPSBUUlVFLCAgICAgCiAgIyBFdmFsdWF0ZSBSIGNvZGUgY2h1bmtzCiAgZXZhbCA9IFRSVUUsICAgICAgIAogICMgRW5hYmxlIGNhY2hpbmcgb2YgUiBjb2RlIGNodW5rcyBmb3IgZmFzdGVyIHJlbmRlcmluZwogIGNhY2hlID0gRkFMU0UsICAgICAgCiAgIyBBbGlnbiBmaWd1cmVzIGluIHRoZSBjZW50ZXIgb2YgdGhlIG91dHB1dAogIGZpZy5hbGlnbiA9ICJjZW50ZXIiLAogICMgRW5hYmxlIHJldGluYSBkaXNwbGF5IGZvciBoaWdoLXJlc29sdXRpb24gZmlndXJlcwogIHJldGluYSA9IDIsCiAgIyBTaG93IGVycm9ycyBpbiB0aGUgb3V0cHV0IGluc3RlYWQgb2Ygc3RvcHBpbmcgcmVuZGVyaW5nCiAgZXJyb3IgPSBUUlVFLAogICMgRG8gbm90IGNvbGxhcHNlIGNvZGUgYW5kIG91dHB1dCBpbnRvIGEgc2luZ2xlIGJsb2NrCiAgY29sbGFwc2UgPSBGQUxTRQopCiMgU3RhcnQgdGhlIGZpZ3VyZSBjb3VudGVyCmZpZ19jb3VudCA8LSAwCiMgRGVmaW5lIHRoZSBjYXB0aW9uZXIgZnVuY3Rpb24KY2FwdGlvbmVyIDwtIGZ1bmN0aW9uKGNhcHRpb24pIHsKICBmaWdfY291bnQgPDwtIGZpZ19jb3VudCArIDEKICBwYXN0ZTAoIkZpZ3VyZSAiLCBmaWdfY291bnQsICI6ICIsIGNhcHRpb24pCn0KYGBgCgojIEltcG9ydCBsaWJyYXJpZXMKCmBgYHtyfQpsaWJyYXJ5KE1ldHJpY0dyYXBoKQpsaWJyYXJ5KE1hdHJpeCkKbGlicmFyeShyU1BERSkKCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGxhdGV4MmV4cCkKbGlicmFyeShnZ3RleHQpCgpsaWJyYXJ5KGdyYXRlZnVsKSAjIENpdGUgYWxsIGxvYWRlZCBwYWNrYWdlcwpsaWJyYXJ5KGhlcmUpICMgaGVyZSgpIHN0YXJ0cyBmcm9tIHRoZSBob21lIGRpcmVjdG9yeQpgYGAKCgojIEludGVydmFsIGdyYXBoCgoKPGRpdiBzdHlsZT0iY29sb3I6IGJsdWU7Ij4KKioqKioqKioKKipQcmVzcyB0aGUgU2hvdyBidXR0b24gYmVsb3cgdG8gcmV2ZWFsIHRoZSBjb2RlLioqCgoqKioqKioqKgo8L2Rpdj4KCgpgYGB7ciwgZXZhbCA9IEZBTFNFLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KIyBsaWJyYXJ5IGNhbGxzCmxpYnJhcnkoTWV0cmljR3JhcGgpCmxpYnJhcnkoTWF0cml4KQpsaWJyYXJ5KHJTUERFKQoKIyBmdW5jdGlvbiAxCmdldHNfZ3JhcGhfaW50ZXJ2YWwgPC0gZnVuY3Rpb24obil7CiAgZWRnZSA8LSByYmluZChjKDAsMCksYygxLDApKQogIGVkZ2VzID0gbGlzdChlZGdlKQogIGdyYXBoIDwtIG1ldHJpY19ncmFwaCRuZXcoZWRnZXMgPSBlZGdlcykKICBncmFwaCRidWlsZF9tZXNoKG4gPSBuKQogIHJldHVybihncmFwaCkKfQoKIyBtYXRlcm4gY292YXJpYW5jZSBmdW5jdGlvbi4gU2FtZSBhcyBpbiB0aGUgcGFja2FnZQptYXRlcm4uY292YXJpYW5jZSA8LSBmdW5jdGlvbihoLCBrYXBwYSwgbnUsIHNpZ21hKSB7CiAgaWYgKG51ID09IDEgLyAyKSB7CiAgICBDIDwtIHNpZ21hXjIgKiBleHAoLWthcHBhICogYWJzKGgpKQogIH0gZWxzZSB7CiAgICBDIDwtIChzaWdtYV4yIC8gKDJeKG51IC0gMSkgKiBnYW1tYShudSkpKSAqCiAgICAgICgoa2FwcGEgKiBhYnMoaCkpXm51KSAqIGJlc3NlbEsoa2FwcGEgKiBhYnMoaCksIG51KQogIH0KICBDW2ggPT0gMF0gPC0gc2lnbWFeMgogIHJldHVybihhcy5tYXRyaXgoQykpCn0KCiMgZm9sZGVkLm1hdGVybi5jb3ZhcmlhbmNlLjFkIEkgZWRpdGVkCmZvbGRlZC5tYXRlcm4uY292YXJpYW5jZS4xZC5sb2NhbCA8LSBmdW5jdGlvbih4LCBrYXBwYSwgbnUsIHNpZ21hLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTCA9IDEsIE4gPSAxMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvdW5kYXJ5ID0gYygibmV1bWFubiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImRpcmljaGxldCIsICJwZXJpb2RpYyIpKSB7CiAgYm91bmRhcnkgPC0gdG9sb3dlcihib3VuZGFyeVsxXSkKICBpZiAoIShib3VuZGFyeSAlaW4lIGMoIm5ldW1hbm4iLCAiZGlyaWNobGV0IiwgInBlcmlvZGljIikpKSB7CiAgICBzdG9wKCJUaGUgcG9zc2libGUgYm91bmRhcnkgY29uZGl0aW9ucyBhcmUgJ25ldW1hbm4nLAogICAgJ2RpcmljaGxldCcgb3IgJ3BlcmlvZGljJyEiKQogIH0KICBhZGRpID0gdChvdXRlcih4LCB4LCAiKyIpKQogIGRpZmYgPSB0KG91dGVyKHgsIHgsICItIikpCiAgczEgPC0gc2FwcGx5KC1OOk4sIGZ1bmN0aW9uKGopIHsgCiAgICBkaWZmICsgMiAqIGogKiBMCiAgfSkKICBzMiA8LSBzYXBwbHkoLU46TiwgZnVuY3Rpb24oaikgewogICAgYWRkaSArIDIgKiBqICogTAogIH0pCiAgaWYgKGJvdW5kYXJ5ID09ICJuZXVtYW5uIikgewogICAgQyA8LSByb3dTdW1zKG1hdGVybi5jb3ZhcmlhbmNlKGggPSBzMSwga2FwcGEgPSBrYXBwYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBudSA9IG51LCBzaWdtYSA9IHNpZ21hKSArCiAgICAgICAgICAgICAgICAgICBtYXRlcm4uY292YXJpYW5jZShoID0gczIsIGthcHBhID0ga2FwcGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBudSA9IG51LCBzaWdtYSA9IHNpZ21hKSkKICB9IGVsc2UgaWYgKGJvdW5kYXJ5ID09ICJkaXJpY2hsZXQiKSB7CiAgICBDIDwtIHJvd1N1bXMobWF0ZXJuLmNvdmFyaWFuY2UoaCA9IHMxLCBrYXBwYSA9IGthcHBhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51ID0gbnUsIHNpZ21hID0gc2lnbWEpIC0KICAgICAgICAgICAgICAgICAgIG1hdGVybi5jb3ZhcmlhbmNlKGggPSBzMiwga2FwcGEgPSBrYXBwYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51ID0gbnUsIHNpZ21hID0gc2lnbWEpKQogIH0gZWxzZSB7CiAgICBDIDwtIHJvd1N1bXMobWF0ZXJuLmNvdmFyaWFuY2UoaCA9IHMxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGthcHBhID0ga2FwcGEsIG51ID0gbnUsIHNpZ21hID0gc2lnbWEpKQogIH0KICByZXR1cm4obWF0cml4KEMsIG5yb3cgPSBsZW5ndGgoeCkpKQp9CgojIGZ1bmN0aW9uIDIKZ2V0c190cnVlX2Nvdl9tYXQgPSBmdW5jdGlvbihncmFwaCwga2FwcGEsIG51LCBzaWdtYSwgTiwgYm91bmRhcnkpewogIGggPSBncmFwaCRtZXNoJFZbLDFdIAogIHRydWVfY292X21hdCA9IGZvbGRlZC5tYXRlcm4uY292YXJpYW5jZS4xZC5sb2NhbCh4ID0gaCwga2FwcGEgPSBrYXBwYSwgbnUgPSBudSwgc2lnbWEgPSBzaWdtYSwgTiA9IE4sIGJvdW5kYXJ5ID0gYm91bmRhcnkpCiAgcmV0dXJuKHRydWVfY292X21hdCkKfQoKCiMgcGFyYW1ldGVycwpuX3ZlY3RvciA9IGMoOTk4LCAxOTgsIDk4LCA4KQp0eXBlX3ZlY3RvciA9IGMoImNvdmFyaWFuY2UiLCAib3BlcmF0b3IiKQp0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yID0gYygiY2hlYmZ1biIsICJicmFzaWwiLCAiY2hlYmZ1bkxCIikKcmhvX3ZlY3RvciA9IGMoMC4xLCAwLjUsIDEsIDIpCm1fdmVjdG9yID0gYygwLDEsMiwzLDQsNSkKbnVfdmVjdG9yID0gYyhzZXEoMC4xLDAuNCxieT0wLjA1KSwgc2VxKDAuNDEsMC41OSxieT0wLjAxKSwgc2VxKDAuNiwxLjQsYnk9MC4wNSksIHNlcSgxLjQxLDEuNTksYnk9MC4wMSksIHNlcSgxLjYsMi40LGJ5PTAuMDUpLCBzZXEoMi40MSwyLjQ5LGJ5PTAuMDEpKQpib3VuZGFyeSA9ICJuZXVtYW5uIgpzaWdtYSA9IDEKTi5mb2xkZWQgPSAxMAoKRXJyb3IgPSBsaXN0KCkKZm9yIChzIGluIGMoMSwyLDMsNCkpIHsgIyBsb29wIG92ZXIgbl92ZWN0b3IKICBFcnJvcltbYXMuY2hhcmFjdGVyKG5fdmVjdG9yW3NdKV1dID0gbGlzdCgpCiAgbiA9IG5fdmVjdG9yW3NdCiAgZ3JhcGggPSBnZXRzX2dyYXBoX2ludGVydmFsKG4gPSBuKQogIGZvciAoaSBpbiBjKDEpKSB7ICMgbG9vcCBvdmVyIHR5cGVfdmVjdG9yCiAgICBFcnJvcltbYXMuY2hhcmFjdGVyKG5fdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dID0gbGlzdCgpCiAgICB0eXBlID0gdHlwZV92ZWN0b3JbaV0KICAgIGZvciAoaiBpbiBjKDEsMiwzKSkgeyAjIGxvb3Agb3ZlciB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yCiAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIobl92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXSA9IGxpc3QoKQogICAgICB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24gPSB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdCiAgICAgIGZvciAoayBpbiBjKDEsMiwzLDQpKSB7ICMgbG9vcCBvdmVyIHJob192ZWN0b3IKICAgICAgICBFcnJvcltbYXMuY2hhcmFjdGVyKG5fdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dW1t0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdXV1bW2FzLmNoYXJhY3RlcihyaG9fdmVjdG9yW2tdKV1dID0gbGlzdCgpCiAgICAgICAgcmhvID0gcmhvX3ZlY3RvcltrXQogICAgICAgIGZvciAobCBpbiAxOmxlbmd0aChtX3ZlY3RvcikpIHsgIyBsb29wIG92ZXIgbV92ZWN0b3IKICAgICAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIobl92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXSA9IG1hdHJpeChOQSwgbnJvdyA9IGxlbmd0aChudV92ZWN0b3IpLCBuY29sID0gMikKICAgICAgICAgIGNvbG5hbWVzKEVycm9yW1thcy5jaGFyYWN0ZXIobl92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXSkgPSBjKCJMX2luZl9lcnJvciIsICJMXzJfZXJyb3IiKQogICAgICAgICAgbSA9IG1fdmVjdG9yW2xdCiAgICAgICAgICBmb3IgKHIgaW4gMTpsZW5ndGgobnVfdmVjdG9yKSkgeyAjIGxvb3Agb3ZlciBudV92ZWN0b3IKICAgICAgICAgICAgbnUgPSBudV92ZWN0b3Jbcl0KICAgICAgICAgICAgCiAgICAgICAgICAgIGthcHBhID0gc3FydCg4Km51KS9yaG8KICAgICAgICAgICAgdGF1ID0gc3FydChnYW1tYShudSkgLyAoc2lnbWFeMiAqIGthcHBhXigyKm51KSAqICg0KnBpKV4oMS8yKSAqIGdhbW1hKG51ICsgMS8yKSkpICAjc2lnbWEgPSAxLCBkID0gMQogICAgICAgICAgICBhbHBoYSA9IG51ICsgMS8yCiAgICAgICAgICAgIAogICAgICAgICAgICB0cnlDYXRjaCh7CiAgICAgICAgICAgICAgIyBnZXR0aW5nIHRydWUgY292YXJpYW5jZQogICAgICAgICAgICAgIHRydWVfY292X21hdCA9IGdldHNfdHJ1ZV9jb3ZfbWF0KGdyYXBoID0gZ3JhcGgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2FwcGEgPSBrYXBwYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBudSA9IG51LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZ21hID0gc2lnbWEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTiA9IE4uZm9sZGVkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvdW5kYXJ5ID0gYm91bmRhcnkpCiAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgIyBnZXR0aW5nIHRoZSBhcHByb3hpbWF0ZSBjb3ZhcmlhbmNlIG1hdHJpeAogICAgICAgICAgICAgIG9wID0gbWF0ZXJuLm9wZXJhdG9ycyhhbHBoYSA9IGFscGhhLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2FwcGEgPSBrYXBwYSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhdSA9IHRhdSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbSA9IG0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmFwaCA9IGdyYXBoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gdHlwZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uID0gdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uKQogICAgICAgICAgICAgIAogICAgICAgICAgICAgIGFwcHJfY292X21hdCA9IG9wJGNvdmFyaWFuY2VfbWVzaCgpCiAgICAgICAgICAgIAogICAgICAgICAgICAjIGNvbXB1dGluZyB0aGUgZXJyb3JzCiAgICAgICAgICAgIExfaW5mX2Vycm9yID0gbWF4KGFicyh0cnVlX2Nvdl9tYXQgLSBhcHByX2Nvdl9tYXQpKQogICAgICAgICAgICBMXzJfZXJyb3IgPSBzcXJ0KGFzLmRvdWJsZSh0KGdyYXBoJG1lc2gkd2VpZ2h0cyklKiUodHJ1ZV9jb3ZfbWF0IC0gYXBwcl9jb3ZfbWF0KV4yJSolZ3JhcGgkbWVzaCR3ZWlnaHRzKSkKICAgICAgICAgICAgCiAgICAgICAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIobl92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXVtyLDFdID0gTF9pbmZfZXJyb3IKICAgICAgICAgICAgRXJyb3JbW2FzLmNoYXJhY3RlcihuX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dW1thcy5jaGFyYWN0ZXIocmhvX3ZlY3RvcltrXSldXVtbYXMuY2hhcmFjdGVyKG1fdmVjdG9yW2xdKV1dW3IsMl0gPSBMXzJfZXJyb3IKICAgICAgICAgICAgfSwgZXJyb3IgPSBmdW5jdGlvbihlcnIpewogICAgICAgICAgICAgIHdhcm5pbmcocGFzdGUoIkVycm9yIG9jY3VycmVkIGF0IGl0ZXJhdGlvbiBuPSIsIG4sICIsdHlwZT0iLCB0eXBlLCAiLHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbj0iLCB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24sICIscmhvPSIsIHJobywgIixtPSIsIG0sICIsbnU9IiwgbnUsICJFcnJvcjoiLCBjb25kaXRpb25NZXNzYWdlKGVycikpKQogICAgICAgICAgICAgIHByaW50KHBhc3RlKCJFcnJvciBvY2N1cnJlZCBhdCBpdGVyYXRpb24gbj0iLCBuLCAiLHR5cGU9IiwgdHlwZSwgIix0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb249IiwgdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uLCAiLHJobz0iLCByaG8sICIsbT0iLCBtLCAiLG51PSIsIG51LCAiRXJyb3I6IiwgY29uZGl0aW9uTWVzc2FnZShlcnIpKSkKICAgICAgICAgICAgICBFcnJvcltbYXMuY2hhcmFjdGVyKG5fdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dW1t0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdXV1bW2FzLmNoYXJhY3RlcihyaG9fdmVjdG9yW2tdKV1dW1thcy5jaGFyYWN0ZXIobV92ZWN0b3JbbF0pXV1bciwxXSA9IE5BCiAgICAgICAgICAgICAgRXJyb3JbW2FzLmNoYXJhY3RlcihuX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dW1thcy5jaGFyYWN0ZXIocmhvX3ZlY3RvcltrXSldXVtbYXMuY2hhcmFjdGVyKG1fdmVjdG9yW2xdKV1dW3IsMl0gPSBOQQogICAgICAgICAgICB9KQogICAgICAgICAgICBwcmludChwYXN0ZSgibj0iLCBuLCAiLHR5cGU9IiwgdHlwZSwgIix0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb249IiwgdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uLCAiLHJobz0iLCByaG8sICIsbT0iLCBtLCAiLG51PSIsIG51KSkKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgIH0KICB9Cn0KCkVycm9yX2ludGVydmFsX0RFRiA9IEVycm9yCnNhdmUoRXJyb3JfaW50ZXJ2YWxfREVGLCBmaWxlID0gaGVyZSgiZGF0YV9maWxlcy9FcnJvcl9pbnRlcnZhbF9ERUYuUkRhdGEiKSkKYGBgCgojIyBQbG90dGluZyB0aGUgZXJyb3JzCgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmxvYWQoaGVyZSgiZGF0YV9maWxlcy9FcnJvcl9pbnRlcnZhbF9ERUYuUkRhdGEiKSkKCm5fdmVjdG9yID0gYygiOTk4IiwgIjE5OCIsICI5OCIsICI4IikgCnR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3IgPSBjKCJjaGViZnVuIiwgImJyYXNpbCIsICJjaGViZnVuTEIiKQpudV9tYXggPSA1MwpudV92ZWN0b3IgPSAwLjUgKyBjKHNlcSgwLjEsMC40LGJ5PTAuMDUpLCBzZXEoMC40MSwwLjU5LGJ5PTAuMDEpLCBzZXEoMC42LDEuNCxieT0wLjA1KSwgc2VxKDEuNDEsMS41OSxieT0wLjAxKSwgc2VxKDEuNiwyLjQsYnk9MC4wNSksIHNlcSgyLjQxLDIuNDksYnk9MC4wMSkpWzE6bnVfbWF4XQoKbiA9ICI5OTgiCnQgPSAiY2hlYmZ1biIKCgpkYXQgPSByYmluZCgKZGF0YS5mcmFtZShudSA9IHJlcChudV92ZWN0b3IsNSksIAogICAgICAgICAgIHJobyA9IHJlcCgwLjEsIHRpbWVzID0gNSpudV9tYXgpLAogICAgICAgICAgIG0gPSByZXAoMTo1LCBlYWNoID0gbnVfbWF4KSwKICAgICAgICAgICBlcnJvciA9IGMoRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjEiXV1bWyIxIl1dWzE6bnVfbWF4LDFdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9pbnRlcnZhbF9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuMSJdXVtbIjIiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC4xIl1dW1siMyJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjEiXV1bWyI0Il1dWzE6bnVfbWF4LDFdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9pbnRlcnZhbF9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuMSJdXVtbIjUiXV1bMTpudV9tYXgsMV0pLAogICAgICAgICAgIEwgPSByZXAoIkxpbmYiLCB0aW1lcyA9IDUqbnVfbWF4KQopLAoKZGF0YS5mcmFtZShudSA9IHJlcChudV92ZWN0b3IsNSksIAogICAgICAgICAgIHJobyA9IGMocmVwKDAuNSwgdGltZXMgPSA1Km51X21heCkpLAogICAgICAgICAgIG0gPSByZXAoMTo1LCBlYWNoID0gbnVfbWF4KSwKICAgICAgICAgICBlcnJvciA9IGMoRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjUiXV1bWyIxIl1dWzE6bnVfbWF4LDFdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9pbnRlcnZhbF9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuNSJdXVtbIjIiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC41Il1dW1siMyJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjUiXV1bWyI0Il1dWzE6bnVfbWF4LDFdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9pbnRlcnZhbF9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuNSJdXVtbIjUiXV1bMTpudV9tYXgsMV0pLAogICAgICAgICAgIEwgPSByZXAoIkxpbmYiLCB0aW1lcyA9IDUqbnVfbWF4KQopLAoKZGF0YS5mcmFtZShudSA9IHJlcChudV92ZWN0b3IsNSksIAogICAgICAgICAgIHJobyA9IGMocmVwKDEsIHRpbWVzID0gNSpudV9tYXgpKSwKICAgICAgICAgICBtID0gcmVwKDE6NSwgZWFjaCA9IG51X21heCksCiAgICAgICAgICAgZXJyb3IgPSBjKEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMSJdXVtbIjEiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMSJdXVtbIjIiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMSJdXVtbIjMiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMSJdXVtbIjQiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMSJdXVtbIjUiXV1bMTpudV9tYXgsMV0pLAogICAgICAgICAgIEwgPSByZXAoIkxpbmYiLCB0aW1lcyA9IDUqbnVfbWF4KQopLAoKZGF0YS5mcmFtZShudSA9IHJlcChudV92ZWN0b3IsNSksIAogICAgICAgICAgIHJobyA9IGMocmVwKDIsIHRpbWVzID0gNSpudV9tYXgpKSwKICAgICAgICAgICBtID0gcmVwKDE6NSwgZWFjaCA9IG51X21heCksCiAgICAgICAgICAgZXJyb3IgPSBjKEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMiJdXVtbIjEiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMiJdXVtbIjIiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMiJdXVtbIjMiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMiJdXVtbIjQiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMiJdXVtbIjUiXV1bMTpudV9tYXgsMV0pLAogICAgICAgICAgIEwgPSByZXAoIkxpbmYiLCB0aW1lcyA9IDUqbnVfbWF4KQopLAoKIyMgTDIKCmRhdGEuZnJhbWUobnUgPSByZXAobnVfdmVjdG9yLDUpLCAKICAgICAgICAgICByaG8gPSByZXAoMC4xLCB0aW1lcyA9IDUqbnVfbWF4KSwKICAgICAgICAgICBtID0gcmVwKDE6NSwgZWFjaCA9IG51X21heCksCiAgICAgICAgICAgZXJyb3IgPSBjKEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC4xIl1dW1siMSJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjEiXV1bWyIyIl1dWzE6bnVfbWF4LDJdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9pbnRlcnZhbF9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuMSJdXVtbIjMiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC4xIl1dW1siNCJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjEiXV1bWyI1Il1dWzE6bnVfbWF4LDJdKSwKICAgICAgICAgICBMID0gcmVwKCJMMiIsIHRpbWVzID0gNSpudV9tYXgpCiksCgpkYXRhLmZyYW1lKG51ID0gcmVwKG51X3ZlY3Rvciw1KSwgCiAgICAgICAgICAgcmhvID0gYyhyZXAoMC41LCB0aW1lcyA9IDUqbnVfbWF4KSksCiAgICAgICAgICAgbSA9IHJlcCgxOjUsIGVhY2ggPSBudV9tYXgpLAogICAgICAgICAgIGVycm9yID0gYyhFcnJvcl9pbnRlcnZhbF9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuNSJdXVtbIjEiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC41Il1dW1siMiJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjUiXV1bWyIzIl1dWzE6bnVfbWF4LDJdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9pbnRlcnZhbF9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuNSJdXVtbIjQiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC41Il1dW1siNSJdXVsxOm51X21heCwyXSksCiAgICAgICAgICAgTCA9IHJlcCgiTDIiLCB0aW1lcyA9IDUqbnVfbWF4KQopLAoKZGF0YS5mcmFtZShudSA9IHJlcChudV92ZWN0b3IsNSksIAogICAgICAgICAgIHJobyA9IGMocmVwKDEsIHRpbWVzID0gNSpudV9tYXgpKSwKICAgICAgICAgICBtID0gcmVwKDE6NSwgZWFjaCA9IG51X21heCksCiAgICAgICAgICAgZXJyb3IgPSBjKEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMSJdXVtbIjEiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMSJdXVtbIjIiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMSJdXVtbIjMiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMSJdXVtbIjQiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMSJdXVtbIjUiXV1bMTpudV9tYXgsMl0pLAogICAgICAgICAgIEwgPSByZXAoIkwyIiwgdGltZXMgPSA1Km51X21heCkKKSwKCmRhdGEuZnJhbWUobnUgPSByZXAobnVfdmVjdG9yLDUpLCAKICAgICAgICAgICByaG8gPSBjKHJlcCgyLCB0aW1lcyA9IDUqbnVfbWF4KSksCiAgICAgICAgICAgbSA9IHJlcCgxOjUsIGVhY2ggPSBudV9tYXgpLAogICAgICAgICAgIGVycm9yID0gYyhFcnJvcl9pbnRlcnZhbF9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjIiXV1bWyIxIl1dWzE6bnVfbWF4LDJdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9pbnRlcnZhbF9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjIiXV1bWyIyIl1dWzE6bnVfbWF4LDJdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9pbnRlcnZhbF9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjIiXV1bWyIzIl1dWzE6bnVfbWF4LDJdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9pbnRlcnZhbF9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjIiXV1bWyI0Il1dWzE6bnVfbWF4LDJdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9pbnRlcnZhbF9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjIiXV1bWyI1Il1dWzE6bnVfbWF4LDJdKSwKICAgICAgICAgICBMID0gcmVwKCJMMiIsIHRpbWVzID0gNSpudV9tYXgpCikKKQoKCmRhdCRyaG8gPSBmYWN0b3IoZGF0JHJobywgbGV2ZWxzID0gYygiMC4xIiwgIjAuNSIsICIxIiwgIjIiKSkKZGF0JEwgPSBmYWN0b3IoZGF0JEwsIGxldmVscyA9IGMoIkwyIiwgIkxpbmYiKSkKbGV2ZWxzKGRhdCRyaG8pID0gYygiMC4xIiA9IGxhdGV4MmV4cDo6VGVYKCIkXFxyaG8gPSAwLjEkIiksICIwLjUiID0gbGF0ZXgyZXhwOjpUZVgoIiRcXHJobyA9IDAuNSQiKSwgIjEiID0gbGF0ZXgyZXhwOjpUZVgoIiRcXHJobyA9IDEkIiksICIyIiA9IGxhdGV4MmV4cDo6VGVYKCIkXFxyaG8gPSAyJCIpKQpsZXZlbHMoZGF0JEwpID0gYygiTDIiID0gbGF0ZXgyZXhwOjpUZVgoIiRMXzIoXFxHYW1tYVxcdGltZXNcXEdhbW1hKSQgZXJyb3IiKSwgIkxpbmYiID0gbGF0ZXgyZXhwOjpUZVgoIiRMX1xcaW5mdHkoXFxHYW1tYVxcdGltZXNcXEdhbW1hKSQgZXJyb3IiKSkKCgpwIDwtIGdncGxvdChkYXQsIGFlcyhudSwgZXJyb3IsIGNvbG91ciA9IGFzLmZhY3RvcihtKSkpICsgCiAgZmFjZXRfZ3JpZChMIH4gcmhvLCBsYWJlbGxlciA9IGxhYmVsX3BhcnNlZCkgKwogIGdlb21fbGluZSgpICsKICBzY2FsZV95X2xvZzEwKG4uYnJlYWtzID0gNSkgKwogIHNjYWxlX3hfY29udGludW91cyhuLmJyZWFrcyA9IDEwKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuc3BhY2luZyA9IHVuaXQoMC4zLCAiY20iKSwgdGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAiUGFsYXRpbm8iKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLCAgICAgICAgIyBQYW5lbCB0aXRsZXMKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksICAgICAgICAjIEF4aXMgdGl0bGVzCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksICAgICAgICAgIyBBeGlzIHRleHQKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwgICAgICAjIExlZ2VuZCB0aXRsZQogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikpICsKICBsYWJzKHggPSBicXVvdGUoYWxwaGEgfiAiKHNtb290aG5lc3MgcGFyYW1ldGVyKSIpLCB5ID0gIkNvdmFyaWFuY2UgRXJyb3IiLCBjb2xvciA9ICJtIikgKyBnZ3RpdGxlKCJJbnRlcnZhbCBncmFwaCIpCmBgYAoKCmBgYHtyLCBmaWcuZGltID0gYygxMiw2KSwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSIsIGZpZy5jYXAgPSBjYXB0aW9uZXIoIkNvdmFyaWFuY2UgZXJyb3IgZm9yIHRoZSBpbnRlcnZhbCBncmFwaC4iKX0KcApnZ3NhdmUoaGVyZSgiZGF0YV9maWxlcy9uZXdfaW50ZXJ2YWxfdXB0bzEuNS5wbmciKSwgd2lkdGggPSAxMiwgaGVpZ2h0ID0gNiwgcGxvdCA9IHAsIGRwaSA9IDMwMCkKYGBgCgoKCiMgQ2lyY2xlIGdyYXBoCgoKPGRpdiBzdHlsZT0iY29sb3I6IGJsdWU7Ij4KKioqKioqKioKKipQcmVzcyB0aGUgU2hvdyBidXR0b24gYmVsb3cgdG8gcmV2ZWFsIHRoZSBjb2RlLioqCgoqKioqKioqKgo8L2Rpdj4KCgpgYGB7ciwgZXZhbCA9IEZBTFNFLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KIyBsaWJyYXJ5IGNhbGxzCmxpYnJhcnkoTWV0cmljR3JhcGgpCmxpYnJhcnkoTWF0cml4KQpsaWJyYXJ5KHJTUERFKQoKIyBmdW5jdGlvbiAxCmdldHNfZ3JhcGhfY2lyY2xlIDwtIGZ1bmN0aW9uKG4pewogIHIgPSAxLyhwaSkKICB0aGV0YSA8LSBzZXEoZnJvbT0tcGksdG89cGksbGVuZ3RoLm91dCA9IDEwMDAwKQogIGVkZ2UgPC0gY2JpbmQoMStyK3IqY29zKHRoZXRhKSxyKnNpbih0aGV0YSkpCiAgZWRnZXMgPSBsaXN0KGVkZ2UpCiAgZ3JhcGggPC0gbWV0cmljX2dyYXBoJG5ldyhlZGdlcyA9IGVkZ2VzKQogIGdyYXBoJHNldF9tYW51YWxfZWRnZV9sZW5ndGhzKGVkZ2VfbGVuZ3RocyA9IDIpCiAgZ3JhcGgkYnVpbGRfbWVzaChuID0gbikKICByZXR1cm4oZ3JhcGgpCn0KCiMgbWF0ZXJuIGNvdmFyaWFuY2UgZnVuY3Rpb24uIFNhbWUgYXMgaW4gdGhlIHBhY2thZ2UKbWF0ZXJuLmNvdmFyaWFuY2UgPC0gZnVuY3Rpb24oaCwga2FwcGEsIG51LCBzaWdtYSkgewogIGlmIChudSA9PSAxIC8gMikgewogICAgQyA8LSBzaWdtYV4yICogZXhwKC1rYXBwYSAqIGFicyhoKSkKICB9IGVsc2UgewogICAgQyA8LSAoc2lnbWFeMiAvICgyXihudSAtIDEpICogZ2FtbWEobnUpKSkgKgogICAgICAoKGthcHBhICogYWJzKGgpKV5udSkgKiBiZXNzZWxLKGthcHBhICogYWJzKGgpLCBudSkKICB9CiAgQ1toID09IDBdIDwtIHNpZ21hXjIKICByZXR1cm4oYXMubWF0cml4KEMpKQp9CgojIGZvbGRlZC5tYXRlcm4uY292YXJpYW5jZS4xZCBJIGVkaXRlZApmb2xkZWQubWF0ZXJuLmNvdmFyaWFuY2UuMWQubG9jYWwgPC0gZnVuY3Rpb24oeCwga2FwcGEsIG51LCBzaWdtYSwgTCA9IDEsIE4gPSAxMCwgYm91bmRhcnkgPSBjKCJuZXVtYW5uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZGlyaWNobGV0IiwgInBlcmlvZGljIikpIHsKICBib3VuZGFyeSA8LSB0b2xvd2VyKGJvdW5kYXJ5WzFdKQogIGlmICghKGJvdW5kYXJ5ICVpbiUgYygibmV1bWFubiIsICJkaXJpY2hsZXQiLCAicGVyaW9kaWMiKSkpIHsKICAgIHN0b3AoIlRoZSBwb3NzaWJsZSBib3VuZGFyeSBjb25kaXRpb25zIGFyZSAnbmV1bWFubicsCiAgICAnZGlyaWNobGV0JyBvciAncGVyaW9kaWMnISIpCiAgfQogIGFkZGkgPSB0KG91dGVyKHgsIHgsICIrIikpCiAgZGlmZiA9IHQob3V0ZXIoeCwgeCwgIi0iKSkKICBzMSA8LSBzYXBwbHkoLU46TiwgZnVuY3Rpb24oaikgeyAjIHMxIGlzIGEgbWF0cml4IG9mIHNpemUgbGVuZ3RoKGgpeCgyTisxKQogICAgZGlmZiArIDIgKiBqICogTAogIH0pCiAgczIgPC0gc2FwcGx5KC1OOk4sIGZ1bmN0aW9uKGopIHsKICAgIGFkZGkgKyAyICogaiAqIEwKICB9KQogIGlmIChib3VuZGFyeSA9PSAibmV1bWFubiIpIHsKICAgIEMgPC0gcm93U3VtcyhtYXRlcm4uY292YXJpYW5jZShoID0gczEsIGthcHBhID0ga2FwcGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnUgPSBudSwgc2lnbWEgPSBzaWdtYSkgKwogICAgICAgICAgICAgICAgICAgbWF0ZXJuLmNvdmFyaWFuY2UoaCA9IHMyLCBrYXBwYSA9IGthcHBhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnUgPSBudSwgc2lnbWEgPSBzaWdtYSkpCiAgfSBlbHNlIGlmIChib3VuZGFyeSA9PSAiZGlyaWNobGV0IikgewogICAgQyA8LSByb3dTdW1zKG1hdGVybi5jb3ZhcmlhbmNlKGggPSBzMSwga2FwcGEgPSBrYXBwYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBudSA9IG51LCBzaWdtYSA9IHNpZ21hKSAtCiAgICAgICAgICAgICAgICAgICBtYXRlcm4uY292YXJpYW5jZShoID0gczIsIGthcHBhID0ga2FwcGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBudSA9IG51LCBzaWdtYSA9IHNpZ21hKSkKICB9IGVsc2UgewogICAgQyA8LSByb3dTdW1zKG1hdGVybi5jb3ZhcmlhbmNlKGggPSBzMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrYXBwYSA9IGthcHBhLCBudSA9IG51LCBzaWdtYSA9IHNpZ21hKSkKICB9CiAgcmV0dXJuKG1hdHJpeChDLCBucm93ID0gbGVuZ3RoKHgpKSkKfQoKIyBmdW5jdGlvbiAyCmdldHNfdHJ1ZV9jb3ZfbWF0ID0gZnVuY3Rpb24oZ3JhcGgsIGthcHBhLCBudSwgc2lnbWEsIE4sIGJvdW5kYXJ5KXsKICBoID0gYygwLGdyYXBoJGdldF9lZGdlX2xlbmd0aHMoKVsxXSpncmFwaCRtZXNoJFB0RVssMl0pCiAgdHJ1ZV9jb3ZfbWF0ID0gZm9sZGVkLm1hdGVybi5jb3ZhcmlhbmNlLjFkLmxvY2FsKHggPSBoLCBrYXBwYSA9IGthcHBhLCBudSA9IG51LCBzaWdtYSA9IHNpZ21hLCBOID0gTiwgYm91bmRhcnkgPSBib3VuZGFyeSkKICByZXR1cm4odHJ1ZV9jb3ZfbWF0KQp9CgoKIyBwYXJhbWV0ZXJzCm5fdmVjdG9yID0gMipjKDk5OCwgMTk4LCA5OCwgOCkKdHlwZV92ZWN0b3IgPSBjKCJjb3ZhcmlhbmNlIiwgIm9wZXJhdG9yIikKdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvciA9IGMoImNoZWJmdW4iLCAiYnJhc2lsIiwgImNoZWJmdW5MQiIpCnJob192ZWN0b3IgPSBjKDAuMSwgMC41LCAxLCAyKQptX3ZlY3RvciA9IGMoMCwxLDIsMyw0LDUpCm51X3ZlY3RvciA9IGMoc2VxKDAuMSwwLjQsYnk9MC4wNSksIHNlcSgwLjQxLDAuNTksYnk9MC4wMSksIHNlcSgwLjYsMS40LGJ5PTAuMDUpLCBzZXEoMS40MSwxLjU5LGJ5PTAuMDEpLCBzZXEoMS42LDIuNCxieT0wLjA1KSwgc2VxKDIuNDEsMi40OSxieT0wLjAxKSkKYm91bmRhcnkgPSAicGVyaW9kaWMiCnNpZ21hID0gMQpOLmZvbGRlZCA9IDEwCgpFcnJvciA9IGxpc3QoKQpmb3IgKHMgaW4gYygxLDIsMyw0KSkgeyAjIGxvb3Agb3ZlciBuX3ZlY3RvcgogIEVycm9yW1thcy5jaGFyYWN0ZXIobl92ZWN0b3Jbc10pXV0gPSBsaXN0KCkKICBuID0gbl92ZWN0b3Jbc10KICBncmFwaCA9IGdldHNfZ3JhcGhfY2lyY2xlKG4gPSBuKQogIGZvciAoaSBpbiBjKDEpKSB7ICMgbG9vcCBvdmVyIHR5cGVfdmVjdG9yCiAgICBFcnJvcltbYXMuY2hhcmFjdGVyKG5fdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dID0gbGlzdCgpCiAgICB0eXBlID0gdHlwZV92ZWN0b3JbaV0KICAgIGZvciAoaiBpbiBjKDEsMiwzKSkgeyAjIGxvb3Agb3ZlciB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yCiAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIobl92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXSA9IGxpc3QoKQogICAgICB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24gPSB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdCiAgICAgIGZvciAoayBpbiBjKDEsMiwzLDQpKSB7ICMgbG9vcCBvdmVyIHJob192ZWN0b3IKICAgICAgICBFcnJvcltbYXMuY2hhcmFjdGVyKG5fdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dW1t0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdXV1bW2FzLmNoYXJhY3RlcihyaG9fdmVjdG9yW2tdKV1dID0gbGlzdCgpCiAgICAgICAgcmhvID0gcmhvX3ZlY3RvcltrXQogICAgICAgIGZvciAobCBpbiAxOmxlbmd0aChtX3ZlY3RvcikpIHsgIyBsb29wIG92ZXIgbV92ZWN0b3IKICAgICAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIobl92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXSA9IG1hdHJpeChOQSwgbnJvdyA9IGxlbmd0aChudV92ZWN0b3IpLCBuY29sID0gMikKICAgICAgICAgIGNvbG5hbWVzKEVycm9yW1thcy5jaGFyYWN0ZXIobl92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXSkgPSBjKCJMX2luZl9lcnJvciIsICJMXzJfZXJyb3IiKQogICAgICAgICAgbSA9IG1fdmVjdG9yW2xdCiAgICAgICAgICBmb3IgKHIgaW4gMTpsZW5ndGgobnVfdmVjdG9yKSkgeyAjIGxvb3Agb3ZlciBudV92ZWN0b3IKICAgICAgICAgICAgbnUgPSBudV92ZWN0b3Jbcl0KICAgICAgICAgICAgCiAgICAgICAgICAgIGthcHBhID0gc3FydCg4Km51KS9yaG8KICAgICAgICAgICAgdGF1ID0gc3FydChnYW1tYShudSkgLyAoc2lnbWFeMiAqIGthcHBhXigyKm51KSAqICg0KnBpKV4oMS8yKSAqIGdhbW1hKG51ICsgMS8yKSkpICAjc2lnbWEgPSAxLCBkID0gMQogICAgICAgICAgICBhbHBoYSA9IG51ICsgMS8yCiAgICAgICAgICAgIAogICAgICAgICAgICB0cnlDYXRjaCh7CiAgICAgICAgICAgICAgIyBnZXR0aW5nIHRydWUgY292YXJpYW5jZQogICAgICAgICAgICAgIHRydWVfY292X21hdCA9IGdldHNfdHJ1ZV9jb3ZfbWF0KGdyYXBoID0gZ3JhcGgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2FwcGEgPSBrYXBwYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBudSA9IG51LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZ21hID0gc2lnbWEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTiA9IE4uZm9sZGVkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvdW5kYXJ5ID0gYm91bmRhcnkpCiAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgIyBnZXR0aW5nIHRoZSBhcHByb3hpbWF0ZSBjb3ZhcmlhbmNlIG1hdHJpeAogICAgICAgICAgICAgIG9wID0gbWF0ZXJuLm9wZXJhdG9ycyhhbHBoYSA9IGFscGhhLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2FwcGEgPSBrYXBwYSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhdSA9IHRhdSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbSA9IG0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmFwaCA9IGdyYXBoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gdHlwZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uID0gdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uKQogICAgICAgICAgICAgIAogICAgICAgICAgICAgIGFwcHJfY292X21hdCA9IG9wJGNvdmFyaWFuY2VfbWVzaCgpCiAgICAgICAgICAgIAogICAgICAgICAgICAjIGNvbXB1dGluZyB0aGUgZXJyb3JzCiAgICAgICAgICAgIExfaW5mX2Vycm9yID0gbWF4KGFicyh0cnVlX2Nvdl9tYXQgLSBhcHByX2Nvdl9tYXQpKQogICAgICAgICAgICBMXzJfZXJyb3IgPSBzcXJ0KGFzLmRvdWJsZSh0KGdyYXBoJG1lc2gkd2VpZ2h0cyklKiUodHJ1ZV9jb3ZfbWF0IC0gYXBwcl9jb3ZfbWF0KV4yJSolZ3JhcGgkbWVzaCR3ZWlnaHRzKSkKICAgICAgICAgICAgCiAgICAgICAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIobl92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXVtyLDFdID0gTF9pbmZfZXJyb3IKICAgICAgICAgICAgRXJyb3JbW2FzLmNoYXJhY3RlcihuX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dW1thcy5jaGFyYWN0ZXIocmhvX3ZlY3RvcltrXSldXVtbYXMuY2hhcmFjdGVyKG1fdmVjdG9yW2xdKV1dW3IsMl0gPSBMXzJfZXJyb3IKICAgICAgICAgICAgfSwgZXJyb3IgPSBmdW5jdGlvbihlcnIpewogICAgICAgICAgICAgIHdhcm5pbmcocGFzdGUoIkVycm9yIG9jY3VycmVkIGF0IGl0ZXJhdGlvbiBuPSIsIG4sICIsdHlwZT0iLCB0eXBlLCAiLHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbj0iLCB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24sICIscmhvPSIsIHJobywgIixtPSIsIG0sICIsbnU9IiwgbnUsICJFcnJvcjoiLCBjb25kaXRpb25NZXNzYWdlKGVycikpKQogICAgICAgICAgICAgIHByaW50KHBhc3RlKCJFcnJvciBvY2N1cnJlZCBhdCBpdGVyYXRpb24gbj0iLCBuLCAiLHR5cGU9IiwgdHlwZSwgIix0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb249IiwgdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uLCAiLHJobz0iLCByaG8sICIsbT0iLCBtLCAiLG51PSIsIG51LCAiRXJyb3I6IiwgY29uZGl0aW9uTWVzc2FnZShlcnIpKSkKICAgICAgICAgICAgICBFcnJvcltbYXMuY2hhcmFjdGVyKG5fdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dW1t0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdXV1bW2FzLmNoYXJhY3RlcihyaG9fdmVjdG9yW2tdKV1dW1thcy5jaGFyYWN0ZXIobV92ZWN0b3JbbF0pXV1bciwxXSA9IE5BCiAgICAgICAgICAgICAgRXJyb3JbW2FzLmNoYXJhY3RlcihuX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dW1thcy5jaGFyYWN0ZXIocmhvX3ZlY3RvcltrXSldXVtbYXMuY2hhcmFjdGVyKG1fdmVjdG9yW2xdKV1dW3IsMl0gPSBOQQogICAgICAgICAgICB9KQogICAgICAgICAgICBwcmludChwYXN0ZSgibj0iLCBuLCAiLHR5cGU9IiwgdHlwZSwgIix0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb249IiwgdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uLCAiLHJobz0iLCByaG8sICIsbT0iLCBtLCAiLG51PSIsIG51KSkKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgIH0KICB9Cn0KRXJyb3JfY2lyY2xlX0RFRiA9IEVycm9yCnNhdmUoRXJyb3JfY2lyY2xlX0RFRiwgZmlsZSA9IGhlcmUoImRhdGFfZmlsZXMvRXJyb3JfY2lyY2xlX0RFRi5SRGF0YSIpKQpgYGAKCgojIyBQbG90dGluZyB0aGUgZXJyb3JzCgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmxvYWQoaGVyZSgiZGF0YV9maWxlcy9FcnJvcl9jaXJjbGVfREVGLlJEYXRhIikpCgpuX3ZlY3RvciA9IGMoIjE5OTYiLCAiMzk2IiwgIjE5NiIsICIxNiIpIAp0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yID0gYygiY2hlYmZ1biIsICJicmFzaWwiLCAiY2hlYmZ1bkxCIikKbnVfbWF4ID0gNTMKbnVfdmVjdG9yID0gMC41ICsgYyhzZXEoMC4xLDAuNCxieT0wLjA1KSwgc2VxKDAuNDEsMC41OSxieT0wLjAxKSwgc2VxKDAuNiwxLjQsYnk9MC4wNSksIHNlcSgxLjQxLDEuNTksYnk9MC4wMSksIHNlcSgxLjYsMi40LGJ5PTAuMDUpLCBzZXEoMi40MSwyLjQ5LGJ5PTAuMDEpKVsxOm51X21heF0KCm4gPSAiMTk5NiIKdCA9ICJjaGViZnVuIgogIAoKZGF0ID0gcmJpbmQoCmRhdGEuZnJhbWUobnUgPSByZXAobnVfdmVjdG9yLDUpLCAKICAgICAgICAgICByaG8gPSByZXAoMC4xLCB0aW1lcyA9IDUqbnVfbWF4KSwKICAgICAgICAgICBtID0gcmVwKDE6NSwgZWFjaCA9IG51X21heCksCiAgICAgICAgICAgZXJyb3IgPSBjKEVycm9yX2NpcmNsZV9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuMSJdXVtbIjEiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2NpcmNsZV9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuMSJdXVtbIjIiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2NpcmNsZV9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuMSJdXVtbIjMiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2NpcmNsZV9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuMSJdXVtbIjQiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2NpcmNsZV9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuMSJdXVtbIjUiXV1bMTpudV9tYXgsMV0pLAogICAgICAgICAgIEwgPSByZXAoIkxpbmYiLCB0aW1lcyA9IDUqbnVfbWF4KQopLAoKZGF0YS5mcmFtZShudSA9IHJlcChudV92ZWN0b3IsNSksIAogICAgICAgICAgIHJobyA9IGMocmVwKDAuNSwgdGltZXMgPSA1Km51X21heCkpLAogICAgICAgICAgIG0gPSByZXAoMTo1LCBlYWNoID0gbnVfbWF4KSwKICAgICAgICAgICBlcnJvciA9IGMoRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC41Il1dW1siMSJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC41Il1dW1siMiJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC41Il1dW1siMyJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC41Il1dW1siNCJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC41Il1dW1siNSJdXVsxOm51X21heCwxXSksCiAgICAgICAgICAgTCA9IHJlcCgiTGluZiIsIHRpbWVzID0gNSpudV9tYXgpCiksCgpkYXRhLmZyYW1lKG51ID0gcmVwKG51X3ZlY3Rvciw1KSwgCiAgICAgICAgICAgcmhvID0gYyhyZXAoMSwgdGltZXMgPSA1Km51X21heCkpLAogICAgICAgICAgIG0gPSByZXAoMTo1LCBlYWNoID0gbnVfbWF4KSwKICAgICAgICAgICBlcnJvciA9IGMoRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMSJdXVtbIjEiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2NpcmNsZV9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjEiXV1bWyIyIl1dWzE6bnVfbWF4LDFdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9jaXJjbGVfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIxIl1dW1siMyJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMSJdXVtbIjQiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2NpcmNsZV9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjEiXV1bWyI1Il1dWzE6bnVfbWF4LDFdKSwKICAgICAgICAgICBMID0gcmVwKCJMaW5mIiwgdGltZXMgPSA1Km51X21heCkKKSwKCmRhdGEuZnJhbWUobnUgPSByZXAobnVfdmVjdG9yLDUpLCAKICAgICAgICAgICByaG8gPSBjKHJlcCgyLCB0aW1lcyA9IDUqbnVfbWF4KSksCiAgICAgICAgICAgbSA9IHJlcCgxOjUsIGVhY2ggPSBudV9tYXgpLAogICAgICAgICAgIGVycm9yID0gYyhFcnJvcl9jaXJjbGVfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIyIl1dW1siMSJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMiJdXVtbIjIiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2NpcmNsZV9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjIiXV1bWyIzIl1dWzE6bnVfbWF4LDFdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9jaXJjbGVfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIyIl1dW1siNCJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMiJdXVtbIjUiXV1bMTpudV9tYXgsMV0pLAogICAgICAgICAgIEwgPSByZXAoIkxpbmYiLCB0aW1lcyA9IDUqbnVfbWF4KQopLAoKIyMgTDIKCmRhdGEuZnJhbWUobnUgPSByZXAobnVfdmVjdG9yLDUpLCAKICAgICAgICAgICByaG8gPSByZXAoMC4xLCB0aW1lcyA9IDUqbnVfbWF4KSwKICAgICAgICAgICBtID0gcmVwKDE6NSwgZWFjaCA9IG51X21heCksCiAgICAgICAgICAgZXJyb3IgPSBjKEVycm9yX2NpcmNsZV9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuMSJdXVtbIjEiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2NpcmNsZV9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuMSJdXVtbIjIiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2NpcmNsZV9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuMSJdXVtbIjMiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2NpcmNsZV9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuMSJdXVtbIjQiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2NpcmNsZV9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuMSJdXVtbIjUiXV1bMTpudV9tYXgsMl0pLAogICAgICAgICAgIEwgPSByZXAoIkwyIiwgdGltZXMgPSA1Km51X21heCkKKSwKCmRhdGEuZnJhbWUobnUgPSByZXAobnVfdmVjdG9yLDUpLCAKICAgICAgICAgICByaG8gPSBjKHJlcCgwLjUsIHRpbWVzID0gNSpudV9tYXgpKSwKICAgICAgICAgICBtID0gcmVwKDE6NSwgZWFjaCA9IG51X21heCksCiAgICAgICAgICAgZXJyb3IgPSBjKEVycm9yX2NpcmNsZV9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuNSJdXVtbIjEiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2NpcmNsZV9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuNSJdXVtbIjIiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2NpcmNsZV9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuNSJdXVtbIjMiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2NpcmNsZV9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuNSJdXVtbIjQiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2NpcmNsZV9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuNSJdXVtbIjUiXV1bMTpudV9tYXgsMl0pLAogICAgICAgICAgIEwgPSByZXAoIkwyIiwgdGltZXMgPSA1Km51X21heCkKKSwKCmRhdGEuZnJhbWUobnUgPSByZXAobnVfdmVjdG9yLDUpLCAKICAgICAgICAgICByaG8gPSBjKHJlcCgxLCB0aW1lcyA9IDUqbnVfbWF4KSksCiAgICAgICAgICAgbSA9IHJlcCgxOjUsIGVhY2ggPSBudV9tYXgpLAogICAgICAgICAgIGVycm9yID0gYyhFcnJvcl9jaXJjbGVfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIxIl1dW1siMSJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMSJdXVtbIjIiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2NpcmNsZV9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjEiXV1bWyIzIl1dWzE6bnVfbWF4LDJdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9jaXJjbGVfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIxIl1dW1siNCJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMSJdXVtbIjUiXV1bMTpudV9tYXgsMl0pLAogICAgICAgICAgIEwgPSByZXAoIkwyIiwgdGltZXMgPSA1Km51X21heCkKKSwKCmRhdGEuZnJhbWUobnUgPSByZXAobnVfdmVjdG9yLDUpLCAKICAgICAgICAgICByaG8gPSBjKHJlcCgyLCB0aW1lcyA9IDUqbnVfbWF4KSksCiAgICAgICAgICAgbSA9IHJlcCgxOjUsIGVhY2ggPSBudV9tYXgpLAogICAgICAgICAgIGVycm9yID0gYyhFcnJvcl9jaXJjbGVfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIyIl1dW1siMSJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMiJdXVtbIjIiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2NpcmNsZV9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjIiXV1bWyIzIl1dWzE6bnVfbWF4LDJdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9jaXJjbGVfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIyIl1dW1siNCJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMiJdXVtbIjUiXV1bMTpudV9tYXgsMl0pLAogICAgICAgICAgIEwgPSByZXAoIkwyIiwgdGltZXMgPSA1Km51X21heCkKKQopCgoKZGF0JHJobyA9IGZhY3RvcihkYXQkcmhvLCBsZXZlbHMgPSBjKCIwLjEiLCAiMC41IiwgIjEiLCAiMiIpKQpkYXQkTCA9IGZhY3RvcihkYXQkTCwgbGV2ZWxzID0gYygiTDIiLCAiTGluZiIpKQpsZXZlbHMoZGF0JHJobykgPSBjKCIwLjEiID0gbGF0ZXgyZXhwOjpUZVgoIiRcXHJobyA9IDAuMSQiKSwgIjAuNSIgPSBsYXRleDJleHA6OlRlWCgiJFxccmhvID0gMC41JCIpLCAiMSIgPSBsYXRleDJleHA6OlRlWCgiJFxccmhvID0gMSQiKSwgIjIiID0gbGF0ZXgyZXhwOjpUZVgoIiRcXHJobyA9IDIkIikpCmxldmVscyhkYXQkTCkgPSBjKCJMMiIgPSBsYXRleDJleHA6OlRlWCgiJExfMihcXEdhbW1hXFx0aW1lc1xcR2FtbWEpJCBlcnJvciIpLCAiTGluZiIgPSBsYXRleDJleHA6OlRlWCgiJExfXFxpbmZ0eShcXEdhbW1hXFx0aW1lc1xcR2FtbWEpJCBlcnJvciIpKQoKcCA8LSBnZ3Bsb3QoZGF0LCBhZXMobnUsIGVycm9yLCBjb2xvdXIgPSBhcy5mYWN0b3IobSkpKSArIAogIGZhY2V0X2dyaWQoTCB+IHJobywgbGFiZWxsZXIgPSBsYWJlbF9wYXJzZWQpICsKICBnZW9tX2xpbmUoKSArCiAgc2NhbGVfeV9sb2cxMChuLmJyZWFrcyA9IDUpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobi5icmVha3MgPSAxMCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLnNwYWNpbmcgPSB1bml0KDAuMywgImNtIiksIHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIlBhbGF0aW5vIiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpLAogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwgICAgICAgICMgUGFuZWwgdGl0bGVzCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLCAgICAgICAgIyBBeGlzIHRpdGxlcwogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLCAgICAgICAgICMgQXhpcyB0ZXh0CiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksICAgICAgIyBMZWdlbmQgdGl0bGUKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpKSArCiAgbGFicyh4ID0gYnF1b3RlKGFscGhhIH4gIihzbW9vdGhuZXNzIHBhcmFtZXRlcikiKSwgeSA9ICJDb3ZhcmlhbmNlIEVycm9yIiwgY29sb3IgPSAibSIpICsgZ2d0aXRsZSgiQ2lyY2xlIGdyYXBoIikKYGBgCgpgYGB7ciwgZmlnLmRpbSA9IGMoMTIsNiksIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUiLCBmaWcuY2FwID0gY2FwdGlvbmVyKCJDb3ZhcmlhbmNlIGVycm9yIGZvciB0aGUgY2lyY2xlIGdyYXBoLiIpfQpwCmdnc2F2ZShoZXJlKCJkYXRhX2ZpbGVzL25ld19jaXJjbGVfdXB0bzEuNS5wbmciKSwgd2lkdGggPSAxMiwgaGVpZ2h0ID0gNiwgcGxvdCA9IHAsIGRwaSA9IDMwMCkKYGBgCgojIFRhZHBvbGUgZ3JhcGgKCgojIyBgcmhvID0gMC4xYAoKPGRpdiBzdHlsZT0iY29sb3I6IGJsdWU7Ij4KKioqKioqKioKKipQcmVzcyB0aGUgU2hvdyBidXR0b24gYmVsb3cgdG8gcmV2ZWFsIHRoZSBjb2RlLioqCgoqKioqKioqKgo8L2Rpdj4KCgpgYGB7ciwgZXZhbCA9IEZBTFNFLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KIyBsaWJyYXJ5IGNhbGxzCmxpYnJhcnkoTWV0cmljR3JhcGgpCmxpYnJhcnkoTWF0cml4KQpsaWJyYXJ5KHJTUERFKQoKIyBmdW5jdGlvbiAxCnRhZHBvbGUuZWlnIDwtIGZ1bmN0aW9uKGssZ3JhcGgpewogIHgxIDwtIGMoMCxncmFwaCRnZXRfZWRnZV9sZW5ndGhzKClbMV0qZ3JhcGgkbWVzaCRQdEVbZ3JhcGgkbWVzaCRQdEVbLDFdPT0xLDJdKSAKICB4MiA8LSBjKDAsZ3JhcGgkZ2V0X2VkZ2VfbGVuZ3RocygpWzJdKmdyYXBoJG1lc2gkUHRFW2dyYXBoJG1lc2gkUHRFWywxXT09MiwyXSkgCiAgCiAgaWYoaz09MCl7IAogICAgZi5lMSA8LSByZXAoMSxsZW5ndGgoeDEpKSAKICAgIGYuZTIgPC0gcmVwKDEsbGVuZ3RoKHgyKSkgCiAgICBmMSA9IGMoZi5lMVsxXSxmLmUyWzFdLGYuZTFbLTFdLCBmLmUyWy0xXSkgCiAgICBmID0gbGlzdChwaGk9ZjEvc3FydCgzKSkgCiAgICAKICB9IGVsc2UgewogICAgZi5lMSA8LSAtMipzaW4ocGkqayoxLzIpKmNvcyhwaSprKngxLzIpIAogICAgZi5lMiA8LSBzaW4ocGkqayp4Mi8yKSAgICAgICAgICAgICAgICAgIAogICAgCiAgICBmMSA9IGMoZi5lMVsxXSxmLmUyWzFdLGYuZTFbLTFdLCBmLmUyWy0xXSkgCiAgICAKICAgIGlmKChrICUlIDIpPT0xKXsgCiAgICAgIGYgPSBsaXN0KHBoaT1mMS9zcXJ0KDMpKSAKICAgIH0gZWxzZSB7IAogICAgICBmLmUxIDwtICgtMSlee2svMn0qY29zKHBpKmsqeDEvMikKICAgICAgZi5lMiA8LSBjb3MocGkqayp4Mi8yKQogICAgICBmMiA9IGMoZi5lMVsxXSxmLmUyWzFdLGYuZTFbLTFdLGYuZTJbLTFdKSAKICAgICAgZiA8LSBsaXN0KHBoaT1mMSxwc2k9ZjIvc3FydCgzLzIpKQogICAgfQogIH0KICAKICByZXR1cm4oZikKfQoKIyBmdW5jdGlvbiAyCmdldHNfZ3JhcGggPC0gZnVuY3Rpb24oaCl7CiAgZWRnZTEgPC0gcmJpbmQoYygwLDApLGMoMSwwKSkKICB0aGV0YSA8LSBzZXEoZnJvbT0tcGksdG89cGksbGVuZ3RoLm91dCA9IDEwMDAwKQogIGVkZ2UyIDwtIGNiaW5kKDErMS9waStjb3ModGhldGEpL3BpLHNpbih0aGV0YSkvcGkpCiAgZWRnZXMgPSBsaXN0KGVkZ2UxLCBlZGdlMikKICBncmFwaCA8LSBtZXRyaWNfZ3JhcGgkbmV3KGVkZ2VzID0gZWRnZXMpCiAgZ3JhcGgkc2V0X21hbnVhbF9lZGdlX2xlbmd0aHMoZWRnZV9sZW5ndGhzID0gYygxLDIpKQogIGdyYXBoJGJ1aWxkX21lc2goaD1oKQogIHJldHVybihncmFwaCkKfQoKI2Z1bmN0aW9uIDMKZ2V0c190cnVlX2Nvdl9tYXQgPC0gZnVuY3Rpb24oZ3JhcGgsIGthcHBhLCB0YXUsIGFscGhhLCBuLm92ZXJraWxsKXsKICBTaWdtYS5rbCA8LSBtYXRyaXgoMCxucm93ID0gZGltKGdyYXBoJG1lc2gkVilbMV0sbmNvbCA9IGRpbShncmFwaCRtZXNoJFYpWzFdKQogIGZvcihpIGluIDA6bi5vdmVya2lsbCl7CiAgICBwaGkgPC0gdGFkcG9sZS5laWcoaSxncmFwaCkkcGhpCiAgICBTaWdtYS5rbCA8LSBTaWdtYS5rbCArICgxLyhrYXBwYV4yICsgKGkqcGkvMileMileKGFscGhhKSkqcGhpJSoldChwaGkpCiAgICBpZihpPjAgJiYgKGkgJSUgMik9PTApeyAKICAgICAgcHNpIDwtIHRhZHBvbGUuZWlnKGksZ3JhcGgpJHBzaQogICAgICBTaWdtYS5rbCA8LSBTaWdtYS5rbCArICgxLyhrYXBwYV4yICsgKGkqcGkvMileMileKGFscGhhKSkqcHNpJSoldChwc2kpCiAgICB9CiAgICAKICB9CiAgU2lnbWEua2wgPC0gU2lnbWEua2wvdGF1XjIKICByZXR1cm4oU2lnbWEua2wpCn0KCiMgcGFyYW1ldGVycwpoX3ZlY3RvciA9IGMoMC4wMDEsIDAuMDA1LCAwLjAxLCAwLjEpCnR5cGVfdmVjdG9yID0gYygiY292YXJpYW5jZSIsICJvcGVyYXRvciIpCnR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3IgPSBjKCJjaGViZnVuIiwgImJyYXNpbCIsICJjaGViZnVuTEIiKQpyaG9fdmVjdG9yID0gYygwLjEsIDAuNSwgMSwgMikKbV92ZWN0b3IgPSBjKDAsMSwyLDMsNCw1KQpudV92ZWN0b3IgPSBjKHNlcSgwLjEsMC40LGJ5PTAuMDUpLCBzZXEoMC40MSwwLjU5LGJ5PTAuMDEpLCBzZXEoMC42LDEuNCxieT0wLjA1KSwgc2VxKDEuNDEsMS41OSxieT0wLjAxKSwgc2VxKDEuNiwyLjQsYnk9MC4wNSksIHNlcSgyLjQxLDIuNDksYnk9MC4wMSkpCm4ub3ZlcmtpbGwgPSAxMDAwCnNpZ21hID0gMQoKRXJyb3IgPSBsaXN0KCkKZm9yIChzIGluIGMoMSwyLDMsNCkpIHsgIyBsb29wIG92ZXIgaF92ZWN0b3IKICBFcnJvcltbYXMuY2hhcmFjdGVyKGhfdmVjdG9yW3NdKV1dID0gbGlzdCgpCiAgaCA9IGhfdmVjdG9yW3NdCiAgZ3JhcGggPSBnZXRzX2dyYXBoKGggPSBoKQogIGZvciAoaSBpbiBjKDEpKSB7ICMgbG9vcCBvdmVyIHR5cGVfdmVjdG9yCiAgICBFcnJvcltbYXMuY2hhcmFjdGVyKGhfdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dID0gbGlzdCgpCiAgICB0eXBlID0gdHlwZV92ZWN0b3JbaV0KICAgIGZvciAoaiBpbiBjKDEsMiwzKSkgeyAjIGxvb3Agb3ZlciB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yCiAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXSA9IGxpc3QoKQogICAgICB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24gPSB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdCiAgICAgIGZvciAoayBpbiBjKDEpKSB7ICMgbG9vcCBvdmVyIHJob192ZWN0b3IKICAgICAgICBFcnJvcltbYXMuY2hhcmFjdGVyKGhfdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dW1t0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdXV1bW2FzLmNoYXJhY3RlcihyaG9fdmVjdG9yW2tdKV1dID0gbGlzdCgpCiAgICAgICAgcmhvID0gcmhvX3ZlY3RvcltrXQogICAgICAgIGZvciAobCBpbiAxOmxlbmd0aChtX3ZlY3RvcikpIHsgIyBsb29wIG92ZXIgbV92ZWN0b3IKICAgICAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXSA9IG1hdHJpeChOQSwgbnJvdyA9IGxlbmd0aChudV92ZWN0b3IpLCBuY29sID0gMikKICAgICAgICAgIGNvbG5hbWVzKEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXSkgPSBjKCJMX2luZl9lcnJvciIsICJMXzJfZXJyb3IiKQogICAgICAgICAgbSA9IG1fdmVjdG9yW2xdCiAgICAgICAgICBmb3IgKG4gaW4gMTpsZW5ndGgobnVfdmVjdG9yKSkgeyAjIGxvb3Agb3ZlciBudV92ZWN0b3IKICAgICAgICAgICAgbnUgPSBudV92ZWN0b3Jbbl0KICAgICAgICAgICAgCiAgICAgICAgICAgIGthcHBhID0gc3FydCg4Km51KS9yaG8KICAgICAgICAgICAgdGF1ID0gc3FydChnYW1tYShudSkgLyAoc2lnbWFeMiAqIGthcHBhXigyKm51KSAqICg0KnBpKV4oMS8yKSAqIGdhbW1hKG51ICsgMS8yKSkpICAjc2lnbWEgPSAxLCBkID0gMQogICAgICAgICAgICBhbHBoYSA9IG51ICsgMS8yCiAgICAgICAgICAgIAogICAgICAgICAgICB0cnlDYXRjaCh7CiAgICAgICAgICAgICMgZ2V0dGluZyB0cnVlIGNvdmFyaWFuY2UKICAgICAgICAgICAgdHJ1ZV9jb3ZfbWF0ID0gZ2V0c190cnVlX2Nvdl9tYXQoZ3JhcGggPSBncmFwaCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2FwcGEgPSBrYXBwYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGF1ID0gdGF1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IGFscGhhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLm92ZXJraWxsID0gbi5vdmVya2lsbCkKICAgICAgICAgICAgCiAgICAgICAgICAgICMgZ2V0dGluZyB0aGUgYXBwcm94aW1hdGUgY292YXJpYW5jZSBtYXRyaXgKICAgICAgICAgICAgb3AgPSBtYXRlcm4ub3BlcmF0b3JzKGFscGhhID0gYWxwaGEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2FwcGEgPSBrYXBwYSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXUgPSB0YXUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtID0gbSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmFwaCA9IGdyYXBoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9IHR5cGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24gPSB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24pCiAgICAgICAgICAgIGFwcHJfY292X21hdCA9IG9wJGNvdmFyaWFuY2VfbWVzaCgpCiAgICAgICAgICAgIAogICAgICAgICAgICAjIGNvbXB1dGluZyB0aGUgZXJyb3JzCiAgICAgICAgICAgIExfaW5mX2Vycm9yID0gbWF4KGFicyh0cnVlX2Nvdl9tYXQgLSBhcHByX2Nvdl9tYXQpKQogICAgICAgICAgICBMXzJfZXJyb3IgPSBzcXJ0KGFzLmRvdWJsZSh0KGdyYXBoJG1lc2gkd2VpZ2h0cyklKiUodHJ1ZV9jb3ZfbWF0IC0gYXBwcl9jb3ZfbWF0KV4yJSolZ3JhcGgkbWVzaCR3ZWlnaHRzKSkKICAgICAgICAgICAgCiAgICAgICAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXVtuLDFdID0gTF9pbmZfZXJyb3IKICAgICAgICAgICAgRXJyb3JbW2FzLmNoYXJhY3RlcihoX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dW1thcy5jaGFyYWN0ZXIocmhvX3ZlY3RvcltrXSldXVtbYXMuY2hhcmFjdGVyKG1fdmVjdG9yW2xdKV1dW24sMl0gPSBMXzJfZXJyb3IKICAgICAgICAgICAgfSwgZXJyb3IgPSBmdW5jdGlvbihlcnIpewogICAgICAgICAgICAgIHdhcm5pbmcocGFzdGUoIkVycm9yIG9jY3VycmVkIGF0IGl0ZXJhdGlvbiBoPSIsIGgsICIsdHlwZT0iLCB0eXBlLCAiLHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbj0iLCB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24sICIscmhvPSIsIHJobywgIixtPSIsIG0sICIsbnU9IiwgbnUsICJFcnJvcjoiLCBjb25kaXRpb25NZXNzYWdlKGVycikpKQogICAgICAgICAgICAgIHByaW50KHBhc3RlKCJFcnJvciBvY2N1cnJlZCBhdCBpdGVyYXRpb24gaD0iLCBoLCAiLHR5cGU9IiwgdHlwZSwgIix0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb249IiwgdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uLCAiLHJobz0iLCByaG8sICIsbT0iLCBtLCAiLG51PSIsIG51LCAiRXJyb3I6IiwgY29uZGl0aW9uTWVzc2FnZShlcnIpKSkKICAgICAgICAgICAgICBFcnJvcltbYXMuY2hhcmFjdGVyKGhfdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dW1t0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdXV1bW2FzLmNoYXJhY3RlcihyaG9fdmVjdG9yW2tdKV1dW1thcy5jaGFyYWN0ZXIobV92ZWN0b3JbbF0pXV1bbiwxXSA9IE5BCiAgICAgICAgICAgICAgRXJyb3JbW2FzLmNoYXJhY3RlcihoX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dW1thcy5jaGFyYWN0ZXIocmhvX3ZlY3RvcltrXSldXVtbYXMuY2hhcmFjdGVyKG1fdmVjdG9yW2xdKV1dW24sMl0gPSBOQQogICAgICAgICAgICB9KQogICAgICAgICAgICBwcmludChwYXN0ZSgiaD0iLCBoLCAiLHR5cGU9IiwgdHlwZSwgIix0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb249IiwgdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uLCAiLHJobz0iLCByaG8sICIsbT0iLCBtLCAiLG51PSIsIG51KSkKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgIH0KICB9Cn0KCkVycm9yX3RhZHBvbGVfREVGX3JobzAuMSA9IEVycm9yCnNhdmUoRXJyb3JfdGFkcG9sZV9ERUZfcmhvMC4xLCBmaWxlID0gaGVyZSgiZGF0YV9maWxlcy9FcnJvcl90YWRwb2xlX0RFRl9yaG8wLjEuUkRhdGEiKSkKYGBgCgoKIyMgYHJobyA9IDAuNWAKCgo8ZGl2IHN0eWxlPSJjb2xvcjogYmx1ZTsiPgoqKioqKioqKgoqKlByZXNzIHRoZSBTaG93IGJ1dHRvbiBiZWxvdyB0byByZXZlYWwgdGhlIGNvZGUuKioKCioqKioqKioqCjwvZGl2PgoKCmBgYHtyLCBldmFsID0gRkFMU0UsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQojIGxpYnJhcnkgY2FsbHMKbGlicmFyeShNZXRyaWNHcmFwaCkKbGlicmFyeShNYXRyaXgpCmxpYnJhcnkoclNQREUpCgojIGZ1bmN0aW9uIDEKdGFkcG9sZS5laWcgPC0gZnVuY3Rpb24oayxncmFwaCl7CiAgeDEgPC0gYygwLGdyYXBoJGdldF9lZGdlX2xlbmd0aHMoKVsxXSpncmFwaCRtZXNoJFB0RVtncmFwaCRtZXNoJFB0RVssMV09PTEsMl0pIAogIHgyIDwtIGMoMCxncmFwaCRnZXRfZWRnZV9sZW5ndGhzKClbMl0qZ3JhcGgkbWVzaCRQdEVbZ3JhcGgkbWVzaCRQdEVbLDFdPT0yLDJdKSAKICAKICBpZihrPT0wKXsgCiAgICBmLmUxIDwtIHJlcCgxLGxlbmd0aCh4MSkpIAogICAgZi5lMiA8LSByZXAoMSxsZW5ndGgoeDIpKSAKICAgIGYxID0gYyhmLmUxWzFdLGYuZTJbMV0sZi5lMVstMV0sIGYuZTJbLTFdKSAKICAgIGYgPSBsaXN0KHBoaT1mMS9zcXJ0KDMpKSAKICAgIAogIH0gZWxzZSB7CiAgICBmLmUxIDwtIC0yKnNpbihwaSprKjEvMikqY29zKHBpKmsqeDEvMikgCiAgICBmLmUyIDwtIHNpbihwaSprKngyLzIpICAgICAgICAgICAgICAgICAgCiAgICAKICAgIGYxID0gYyhmLmUxWzFdLGYuZTJbMV0sZi5lMVstMV0sIGYuZTJbLTFdKSAKICAgIAogICAgaWYoKGsgJSUgMik9PTEpeyAKICAgICAgZiA9IGxpc3QocGhpPWYxL3NxcnQoMykpIAogICAgfSBlbHNlIHsgCiAgICAgIGYuZTEgPC0gKC0xKV57ay8yfSpjb3MocGkqayp4MS8yKQogICAgICBmLmUyIDwtIGNvcyhwaSprKngyLzIpCiAgICAgIGYyID0gYyhmLmUxWzFdLGYuZTJbMV0sZi5lMVstMV0sZi5lMlstMV0pIAogICAgICBmIDwtIGxpc3QocGhpPWYxLHBzaT1mMi9zcXJ0KDMvMikpCiAgICB9CiAgfQogIAogIHJldHVybihmKQp9CgojIGZ1bmN0aW9uIDIKZ2V0c19ncmFwaCA8LSBmdW5jdGlvbihoKXsKICBlZGdlMSA8LSByYmluZChjKDAsMCksYygxLDApKQogIHRoZXRhIDwtIHNlcShmcm9tPS1waSx0bz1waSxsZW5ndGgub3V0ID0gMTAwMDApCiAgZWRnZTIgPC0gY2JpbmQoMSsxL3BpK2Nvcyh0aGV0YSkvcGksc2luKHRoZXRhKS9waSkKICBlZGdlcyA9IGxpc3QoZWRnZTEsIGVkZ2UyKQogIGdyYXBoIDwtIG1ldHJpY19ncmFwaCRuZXcoZWRnZXMgPSBlZGdlcykKICBncmFwaCRzZXRfbWFudWFsX2VkZ2VfbGVuZ3RocyhlZGdlX2xlbmd0aHMgPSBjKDEsMikpCiAgZ3JhcGgkYnVpbGRfbWVzaChoPWgpCiAgcmV0dXJuKGdyYXBoKQp9CgojZnVuY3Rpb24gMwpnZXRzX3RydWVfY292X21hdCA8LSBmdW5jdGlvbihncmFwaCwga2FwcGEsIHRhdSwgYWxwaGEsIG4ub3ZlcmtpbGwpewogIFNpZ21hLmtsIDwtIG1hdHJpeCgwLG5yb3cgPSBkaW0oZ3JhcGgkbWVzaCRWKVsxXSxuY29sID0gZGltKGdyYXBoJG1lc2gkVilbMV0pCiAgZm9yKGkgaW4gMDpuLm92ZXJraWxsKXsKICAgIHBoaSA8LSB0YWRwb2xlLmVpZyhpLGdyYXBoKSRwaGkKICAgIFNpZ21hLmtsIDwtIFNpZ21hLmtsICsgKDEvKGthcHBhXjIgKyAoaSpwaS8yKV4yKV4oYWxwaGEpKSpwaGklKiV0KHBoaSkKICAgIGlmKGk+MCAmJiAoaSAlJSAyKT09MCl7IAogICAgICBwc2kgPC0gdGFkcG9sZS5laWcoaSxncmFwaCkkcHNpCiAgICAgIFNpZ21hLmtsIDwtIFNpZ21hLmtsICsgKDEvKGthcHBhXjIgKyAoaSpwaS8yKV4yKV4oYWxwaGEpKSpwc2klKiV0KHBzaSkKICAgIH0KICAgIAogIH0KICBTaWdtYS5rbCA8LSBTaWdtYS5rbC90YXVeMgogIHJldHVybihTaWdtYS5rbCkKfQoKIyBwYXJhbWV0ZXJzCmhfdmVjdG9yID0gYygwLjAwMSwgMC4wMDUsIDAuMDEsIDAuMSkKdHlwZV92ZWN0b3IgPSBjKCJjb3ZhcmlhbmNlIiwgIm9wZXJhdG9yIikKdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvciA9IGMoImNoZWJmdW4iLCAiYnJhc2lsIiwgImNoZWJmdW5MQiIpCnJob192ZWN0b3IgPSBjKDAuMSwgMC41LCAxLCAyKQptX3ZlY3RvciA9IGMoMCwxLDIsMyw0LDUpCm51X3ZlY3RvciA9IGMoc2VxKDAuMSwwLjQsYnk9MC4wNSksIHNlcSgwLjQxLDAuNTksYnk9MC4wMSksIHNlcSgwLjYsMS40LGJ5PTAuMDUpLCBzZXEoMS40MSwxLjU5LGJ5PTAuMDEpLCBzZXEoMS42LDIuNCxieT0wLjA1KSwgc2VxKDIuNDEsMi40OSxieT0wLjAxKSkKbi5vdmVya2lsbCA9IDEwMDAKc2lnbWEgPSAxCgpFcnJvciA9IGxpc3QoKQpmb3IgKHMgaW4gYygxLDIsMyw0KSkgeyAjIGxvb3Agb3ZlciBoX3ZlY3RvcgogIEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV0gPSBsaXN0KCkKICBoID0gaF92ZWN0b3Jbc10KICBncmFwaCA9IGdldHNfZ3JhcGgoaCA9IGgpCiAgZm9yIChpIGluIGMoMSkpIHsgIyBsb29wIG92ZXIgdHlwZV92ZWN0b3IKICAgIEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV0gPSBsaXN0KCkKICAgIHR5cGUgPSB0eXBlX3ZlY3RvcltpXQogICAgZm9yIChqIGluIGMoMSwyLDMpKSB7ICMgbG9vcCBvdmVyIHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3IKICAgICAgRXJyb3JbW2FzLmNoYXJhY3RlcihoX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dID0gbGlzdCgpCiAgICAgIHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbiA9IHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal0KICAgICAgZm9yIChrIGluIGMoMikpIHsgIyBsb29wIG92ZXIgcmhvX3ZlY3RvcgogICAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV0gPSBsaXN0KCkKICAgICAgICByaG8gPSByaG9fdmVjdG9yW2tdCiAgICAgICAgZm9yIChsIGluIDE6bGVuZ3RoKG1fdmVjdG9yKSkgeyAjIGxvb3Agb3ZlciBtX3ZlY3RvcgogICAgICAgICAgRXJyb3JbW2FzLmNoYXJhY3RlcihoX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dW1thcy5jaGFyYWN0ZXIocmhvX3ZlY3RvcltrXSldXVtbYXMuY2hhcmFjdGVyKG1fdmVjdG9yW2xdKV1dID0gbWF0cml4KE5BLCBucm93ID0gbGVuZ3RoKG51X3ZlY3RvciksIG5jb2wgPSAyKQogICAgICAgICAgY29sbmFtZXMoRXJyb3JbW2FzLmNoYXJhY3RlcihoX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dW1thcy5jaGFyYWN0ZXIocmhvX3ZlY3RvcltrXSldXVtbYXMuY2hhcmFjdGVyKG1fdmVjdG9yW2xdKV1dKSA9IGMoIkxfaW5mX2Vycm9yIiwgIkxfMl9lcnJvciIpCiAgICAgICAgICBtID0gbV92ZWN0b3JbbF0KICAgICAgICAgIGZvciAobiBpbiAxOmxlbmd0aChudV92ZWN0b3IpKSB7ICMgbG9vcCBvdmVyIG51X3ZlY3RvcgogICAgICAgICAgICBudSA9IG51X3ZlY3RvcltuXQogICAgICAgICAgICAKICAgICAgICAgICAga2FwcGEgPSBzcXJ0KDgqbnUpL3JobwogICAgICAgICAgICB0YXUgPSBzcXJ0KGdhbW1hKG51KSAvIChzaWdtYV4yICoga2FwcGFeKDIqbnUpICogKDQqcGkpXigxLzIpICogZ2FtbWEobnUgKyAxLzIpKSkgICNzaWdtYSA9IDEsIGQgPSAxCiAgICAgICAgICAgIGFscGhhID0gbnUgKyAxLzIKICAgICAgICAgICAgCiAgICAgICAgICAgIHRyeUNhdGNoKHsKICAgICAgICAgICAgIyBnZXR0aW5nIHRydWUgY292YXJpYW5jZQogICAgICAgICAgICB0cnVlX2Nvdl9tYXQgPSBnZXRzX3RydWVfY292X21hdChncmFwaCA9IGdyYXBoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrYXBwYSA9IGthcHBhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXUgPSB0YXUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gYWxwaGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4ub3ZlcmtpbGwgPSBuLm92ZXJraWxsKQogICAgICAgICAgICAKICAgICAgICAgICAgIyBnZXR0aW5nIHRoZSBhcHByb3hpbWF0ZSBjb3ZhcmlhbmNlIG1hdHJpeAogICAgICAgICAgICBvcCA9IG1hdGVybi5vcGVyYXRvcnMoYWxwaGEgPSBhbHBoYSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrYXBwYSA9IGthcHBhLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhdSA9IHRhdSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG0gPSBtLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyYXBoID0gZ3JhcGgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gdHlwZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbiA9IHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbikKICAgICAgICAgICAgYXBwcl9jb3ZfbWF0ID0gb3AkY292YXJpYW5jZV9tZXNoKCkKICAgICAgICAgICAgCiAgICAgICAgICAgICMgY29tcHV0aW5nIHRoZSBlcnJvcnMKICAgICAgICAgICAgTF9pbmZfZXJyb3IgPSBtYXgoYWJzKHRydWVfY292X21hdCAtIGFwcHJfY292X21hdCkpCiAgICAgICAgICAgIExfMl9lcnJvciA9IHNxcnQoYXMuZG91YmxlKHQoZ3JhcGgkbWVzaCR3ZWlnaHRzKSUqJSh0cnVlX2Nvdl9tYXQgLSBhcHByX2Nvdl9tYXQpXjIlKiVncmFwaCRtZXNoJHdlaWdodHMpKQogICAgICAgICAgICAKICAgICAgICAgICAgRXJyb3JbW2FzLmNoYXJhY3RlcihoX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dW1thcy5jaGFyYWN0ZXIocmhvX3ZlY3RvcltrXSldXVtbYXMuY2hhcmFjdGVyKG1fdmVjdG9yW2xdKV1dW24sMV0gPSBMX2luZl9lcnJvcgogICAgICAgICAgICBFcnJvcltbYXMuY2hhcmFjdGVyKGhfdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dW1t0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdXV1bW2FzLmNoYXJhY3RlcihyaG9fdmVjdG9yW2tdKV1dW1thcy5jaGFyYWN0ZXIobV92ZWN0b3JbbF0pXV1bbiwyXSA9IExfMl9lcnJvcgogICAgICAgICAgICB9LCBlcnJvciA9IGZ1bmN0aW9uKGVycil7CiAgICAgICAgICAgICAgd2FybmluZyhwYXN0ZSgiRXJyb3Igb2NjdXJyZWQgYXQgaXRlcmF0aW9uIGg9IiwgaCwgIix0eXBlPSIsIHR5cGUsICIsdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uPSIsIHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbiwgIixyaG89IiwgcmhvLCAiLG09IiwgbSwgIixudT0iLCBudSwgIkVycm9yOiIsIGNvbmRpdGlvbk1lc3NhZ2UoZXJyKSkpCiAgICAgICAgICAgICAgcHJpbnQocGFzdGUoIkVycm9yIG9jY3VycmVkIGF0IGl0ZXJhdGlvbiBoPSIsIGgsICIsdHlwZT0iLCB0eXBlLCAiLHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbj0iLCB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24sICIscmhvPSIsIHJobywgIixtPSIsIG0sICIsbnU9IiwgbnUsICJFcnJvcjoiLCBjb25kaXRpb25NZXNzYWdlKGVycikpKQogICAgICAgICAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXVtuLDFdID0gTkEKICAgICAgICAgICAgICBFcnJvcltbYXMuY2hhcmFjdGVyKGhfdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dW1t0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdXV1bW2FzLmNoYXJhY3RlcihyaG9fdmVjdG9yW2tdKV1dW1thcy5jaGFyYWN0ZXIobV92ZWN0b3JbbF0pXV1bbiwyXSA9IE5BCiAgICAgICAgICAgIH0pCiAgICAgICAgICAgIHByaW50KHBhc3RlKCJoPSIsIGgsICIsdHlwZT0iLCB0eXBlLCAiLHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbj0iLCB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24sICIscmhvPSIsIHJobywgIixtPSIsIG0sICIsbnU9IiwgbnUpKQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgfQogIH0KfQoKRXJyb3JfdGFkcG9sZV9ERUZfcmhvMC41ID0gRXJyb3IKc2F2ZShFcnJvcl90YWRwb2xlX0RFRl9yaG8wLjUsIGZpbGUgPSBoZXJlKCJkYXRhX2ZpbGVzL0Vycm9yX3RhZHBvbGVfREVGX3JobzAuNS5SRGF0YSIpKQpgYGAKCgojIyBgcmhvID0gMWAKCgo8ZGl2IHN0eWxlPSJjb2xvcjogYmx1ZTsiPgoqKioqKioqKgoqKlByZXNzIHRoZSBTaG93IGJ1dHRvbiBiZWxvdyB0byByZXZlYWwgdGhlIGNvZGUuKioKCioqKioqKioqCjwvZGl2PgoKCmBgYHtyLCBldmFsID0gRkFMU0UsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQojIGxpYnJhcnkgY2FsbHMKbGlicmFyeShNZXRyaWNHcmFwaCkKbGlicmFyeShNYXRyaXgpCmxpYnJhcnkoclNQREUpCgojIGZ1bmN0aW9uIDEKdGFkcG9sZS5laWcgPC0gZnVuY3Rpb24oayxncmFwaCl7CiAgeDEgPC0gYygwLGdyYXBoJGdldF9lZGdlX2xlbmd0aHMoKVsxXSpncmFwaCRtZXNoJFB0RVtncmFwaCRtZXNoJFB0RVssMV09PTEsMl0pIAogIHgyIDwtIGMoMCxncmFwaCRnZXRfZWRnZV9sZW5ndGhzKClbMl0qZ3JhcGgkbWVzaCRQdEVbZ3JhcGgkbWVzaCRQdEVbLDFdPT0yLDJdKSAKICAKICBpZihrPT0wKXsgCiAgICBmLmUxIDwtIHJlcCgxLGxlbmd0aCh4MSkpIAogICAgZi5lMiA8LSByZXAoMSxsZW5ndGgoeDIpKSAKICAgIGYxID0gYyhmLmUxWzFdLGYuZTJbMV0sZi5lMVstMV0sIGYuZTJbLTFdKSAKICAgIGYgPSBsaXN0KHBoaT1mMS9zcXJ0KDMpKSAKICAgIAogIH0gZWxzZSB7CiAgICBmLmUxIDwtIC0yKnNpbihwaSprKjEvMikqY29zKHBpKmsqeDEvMikgCiAgICBmLmUyIDwtIHNpbihwaSprKngyLzIpICAgICAgICAgICAgICAgICAgCiAgICAKICAgIGYxID0gYyhmLmUxWzFdLGYuZTJbMV0sZi5lMVstMV0sIGYuZTJbLTFdKSAKICAgIAogICAgaWYoKGsgJSUgMik9PTEpeyAKICAgICAgZiA9IGxpc3QocGhpPWYxL3NxcnQoMykpIAogICAgfSBlbHNlIHsgCiAgICAgIGYuZTEgPC0gKC0xKV57ay8yfSpjb3MocGkqayp4MS8yKQogICAgICBmLmUyIDwtIGNvcyhwaSprKngyLzIpCiAgICAgIGYyID0gYyhmLmUxWzFdLGYuZTJbMV0sZi5lMVstMV0sZi5lMlstMV0pIAogICAgICBmIDwtIGxpc3QocGhpPWYxLHBzaT1mMi9zcXJ0KDMvMikpCiAgICB9CiAgfQogIAogIHJldHVybihmKQp9CgojIGZ1bmN0aW9uIDIKZ2V0c19ncmFwaCA8LSBmdW5jdGlvbihoKXsKICBlZGdlMSA8LSByYmluZChjKDAsMCksYygxLDApKQogIHRoZXRhIDwtIHNlcShmcm9tPS1waSx0bz1waSxsZW5ndGgub3V0ID0gMTAwMDApCiAgZWRnZTIgPC0gY2JpbmQoMSsxL3BpK2Nvcyh0aGV0YSkvcGksc2luKHRoZXRhKS9waSkKICBlZGdlcyA9IGxpc3QoZWRnZTEsIGVkZ2UyKQogIGdyYXBoIDwtIG1ldHJpY19ncmFwaCRuZXcoZWRnZXMgPSBlZGdlcykKICBncmFwaCRzZXRfbWFudWFsX2VkZ2VfbGVuZ3RocyhlZGdlX2xlbmd0aHMgPSBjKDEsMikpCiAgZ3JhcGgkYnVpbGRfbWVzaChoPWgpCiAgcmV0dXJuKGdyYXBoKQp9CgojZnVuY3Rpb24gMwpnZXRzX3RydWVfY292X21hdCA8LSBmdW5jdGlvbihncmFwaCwga2FwcGEsIHRhdSwgYWxwaGEsIG4ub3ZlcmtpbGwpewogIFNpZ21hLmtsIDwtIG1hdHJpeCgwLG5yb3cgPSBkaW0oZ3JhcGgkbWVzaCRWKVsxXSxuY29sID0gZGltKGdyYXBoJG1lc2gkVilbMV0pCiAgZm9yKGkgaW4gMDpuLm92ZXJraWxsKXsKICAgIHBoaSA8LSB0YWRwb2xlLmVpZyhpLGdyYXBoKSRwaGkKICAgIFNpZ21hLmtsIDwtIFNpZ21hLmtsICsgKDEvKGthcHBhXjIgKyAoaSpwaS8yKV4yKV4oYWxwaGEpKSpwaGklKiV0KHBoaSkKICAgIGlmKGk+MCAmJiAoaSAlJSAyKT09MCl7IAogICAgICBwc2kgPC0gdGFkcG9sZS5laWcoaSxncmFwaCkkcHNpCiAgICAgIFNpZ21hLmtsIDwtIFNpZ21hLmtsICsgKDEvKGthcHBhXjIgKyAoaSpwaS8yKV4yKV4oYWxwaGEpKSpwc2klKiV0KHBzaSkKICAgIH0KICAgIAogIH0KICBTaWdtYS5rbCA8LSBTaWdtYS5rbC90YXVeMgogIHJldHVybihTaWdtYS5rbCkKfQoKIyBwYXJhbWV0ZXJzCmhfdmVjdG9yID0gYygwLjAwMSwgMC4wMDUsIDAuMDEsIDAuMSkKdHlwZV92ZWN0b3IgPSBjKCJjb3ZhcmlhbmNlIiwgIm9wZXJhdG9yIikKdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvciA9IGMoImNoZWJmdW4iLCAiYnJhc2lsIiwgImNoZWJmdW5MQiIpCnJob192ZWN0b3IgPSBjKDAuMSwgMC41LCAxLCAyKQptX3ZlY3RvciA9IGMoMCwxLDIsMyw0LDUpCm51X3ZlY3RvciA9IGMoc2VxKDAuMSwwLjQsYnk9MC4wNSksIHNlcSgwLjQxLDAuNTksYnk9MC4wMSksIHNlcSgwLjYsMS40LGJ5PTAuMDUpLCBzZXEoMS40MSwxLjU5LGJ5PTAuMDEpLCBzZXEoMS42LDIuNCxieT0wLjA1KSwgc2VxKDIuNDEsMi40OSxieT0wLjAxKSkgCm4ub3ZlcmtpbGwgPSAxMDAwCnNpZ21hID0gMQoKRXJyb3IgPSBsaXN0KCkKZm9yIChzIGluIGMoMSwyLDMsNCkpIHsgIyBsb29wIG92ZXIgaF92ZWN0b3IKICBFcnJvcltbYXMuY2hhcmFjdGVyKGhfdmVjdG9yW3NdKV1dID0gbGlzdCgpCiAgaCA9IGhfdmVjdG9yW3NdCiAgZ3JhcGggPSBnZXRzX2dyYXBoKGggPSBoKQogIGZvciAoaSBpbiBjKDEpKSB7ICMgbG9vcCBvdmVyIHR5cGVfdmVjdG9yCiAgICBFcnJvcltbYXMuY2hhcmFjdGVyKGhfdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dID0gbGlzdCgpCiAgICB0eXBlID0gdHlwZV92ZWN0b3JbaV0KICAgIGZvciAoaiBpbiBjKDEsMiwzKSkgeyAjIGxvb3Agb3ZlciB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yCiAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXSA9IGxpc3QoKQogICAgICB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24gPSB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdCiAgICAgIGZvciAoayBpbiBjKDMpKSB7ICMgbG9vcCBvdmVyIHJob192ZWN0b3IKICAgICAgICBFcnJvcltbYXMuY2hhcmFjdGVyKGhfdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dW1t0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdXV1bW2FzLmNoYXJhY3RlcihyaG9fdmVjdG9yW2tdKV1dID0gbGlzdCgpCiAgICAgICAgcmhvID0gcmhvX3ZlY3RvcltrXQogICAgICAgIGZvciAobCBpbiAxOmxlbmd0aChtX3ZlY3RvcikpIHsgIyBsb29wIG92ZXIgbV92ZWN0b3IKICAgICAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXSA9IG1hdHJpeChOQSwgbnJvdyA9IGxlbmd0aChudV92ZWN0b3IpLCBuY29sID0gMikKICAgICAgICAgIGNvbG5hbWVzKEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXSkgPSBjKCJMX2luZl9lcnJvciIsICJMXzJfZXJyb3IiKQogICAgICAgICAgbSA9IG1fdmVjdG9yW2xdCiAgICAgICAgICBmb3IgKG4gaW4gMTpsZW5ndGgobnVfdmVjdG9yKSkgeyAjIGxvb3Agb3ZlciBudV92ZWN0b3IKICAgICAgICAgICAgbnUgPSBudV92ZWN0b3Jbbl0KICAgICAgICAgICAgCiAgICAgICAgICAgIGthcHBhID0gc3FydCg4Km51KS9yaG8KICAgICAgICAgICAgdGF1ID0gc3FydChnYW1tYShudSkgLyAoc2lnbWFeMiAqIGthcHBhXigyKm51KSAqICg0KnBpKV4oMS8yKSAqIGdhbW1hKG51ICsgMS8yKSkpICAjc2lnbWEgPSAxLCBkID0gMQogICAgICAgICAgICBhbHBoYSA9IG51ICsgMS8yCiAgICAgICAgICAgIAogICAgICAgICAgICB0cnlDYXRjaCh7CiAgICAgICAgICAgICMgZ2V0dGluZyB0cnVlIGNvdmFyaWFuY2UKICAgICAgICAgICAgdHJ1ZV9jb3ZfbWF0ID0gZ2V0c190cnVlX2Nvdl9tYXQoZ3JhcGggPSBncmFwaCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2FwcGEgPSBrYXBwYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGF1ID0gdGF1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IGFscGhhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLm92ZXJraWxsID0gbi5vdmVya2lsbCkKICAgICAgICAgICAgCiAgICAgICAgICAgICMgZ2V0dGluZyB0aGUgYXBwcm94aW1hdGUgY292YXJpYW5jZSBtYXRyaXgKICAgICAgICAgICAgb3AgPSBtYXRlcm4ub3BlcmF0b3JzKGFscGhhID0gYWxwaGEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2FwcGEgPSBrYXBwYSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXUgPSB0YXUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtID0gbSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmFwaCA9IGdyYXBoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9IHR5cGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24gPSB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24pCiAgICAgICAgICAgIGFwcHJfY292X21hdCA9IG9wJGNvdmFyaWFuY2VfbWVzaCgpCiAgICAgICAgICAgIAogICAgICAgICAgICAjIGNvbXB1dGluZyB0aGUgZXJyb3JzCiAgICAgICAgICAgIExfaW5mX2Vycm9yID0gbWF4KGFicyh0cnVlX2Nvdl9tYXQgLSBhcHByX2Nvdl9tYXQpKQogICAgICAgICAgICBMXzJfZXJyb3IgPSBzcXJ0KGFzLmRvdWJsZSh0KGdyYXBoJG1lc2gkd2VpZ2h0cyklKiUodHJ1ZV9jb3ZfbWF0IC0gYXBwcl9jb3ZfbWF0KV4yJSolZ3JhcGgkbWVzaCR3ZWlnaHRzKSkKICAgICAgICAgICAgCiAgICAgICAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXVtuLDFdID0gTF9pbmZfZXJyb3IKICAgICAgICAgICAgRXJyb3JbW2FzLmNoYXJhY3RlcihoX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dW1thcy5jaGFyYWN0ZXIocmhvX3ZlY3RvcltrXSldXVtbYXMuY2hhcmFjdGVyKG1fdmVjdG9yW2xdKV1dW24sMl0gPSBMXzJfZXJyb3IKICAgICAgICAgICAgfSwgZXJyb3IgPSBmdW5jdGlvbihlcnIpewogICAgICAgICAgICAgIHdhcm5pbmcocGFzdGUoIkVycm9yIG9jY3VycmVkIGF0IGl0ZXJhdGlvbiBoPSIsIGgsICIsdHlwZT0iLCB0eXBlLCAiLHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbj0iLCB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24sICIscmhvPSIsIHJobywgIixtPSIsIG0sICIsbnU9IiwgbnUsICJFcnJvcjoiLCBjb25kaXRpb25NZXNzYWdlKGVycikpKQogICAgICAgICAgICAgIHByaW50KHBhc3RlKCJFcnJvciBvY2N1cnJlZCBhdCBpdGVyYXRpb24gaD0iLCBoLCAiLHR5cGU9IiwgdHlwZSwgIix0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb249IiwgdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uLCAiLHJobz0iLCByaG8sICIsbT0iLCBtLCAiLG51PSIsIG51LCAiRXJyb3I6IiwgY29uZGl0aW9uTWVzc2FnZShlcnIpKSkKICAgICAgICAgICAgICBFcnJvcltbYXMuY2hhcmFjdGVyKGhfdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dW1t0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdXV1bW2FzLmNoYXJhY3RlcihyaG9fdmVjdG9yW2tdKV1dW1thcy5jaGFyYWN0ZXIobV92ZWN0b3JbbF0pXV1bbiwxXSA9IE5BCiAgICAgICAgICAgICAgRXJyb3JbW2FzLmNoYXJhY3RlcihoX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dW1thcy5jaGFyYWN0ZXIocmhvX3ZlY3RvcltrXSldXVtbYXMuY2hhcmFjdGVyKG1fdmVjdG9yW2xdKV1dW24sMl0gPSBOQQogICAgICAgICAgICB9KQogICAgICAgICAgICBwcmludChwYXN0ZSgiaD0iLCBoLCAiLHR5cGU9IiwgdHlwZSwgIix0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb249IiwgdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uLCAiLHJobz0iLCByaG8sICIsbT0iLCBtLCAiLG51PSIsIG51KSkKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgIH0KICB9Cn0KCkVycm9yX3RhZHBvbGVfREVGX3JobzEgPSBFcnJvcgpzYXZlKEVycm9yX3RhZHBvbGVfREVGX3JobzEsIGZpbGUgPSBoZXJlKCJkYXRhX2ZpbGVzL0Vycm9yX3RhZHBvbGVfREVGX3JobzEuUkRhdGEiKSkKYGBgCgoKIyMgYHJobyA9IDJgCgo8ZGl2IHN0eWxlPSJjb2xvcjogYmx1ZTsiPgoqKioqKioqKgoqKlByZXNzIHRoZSBTaG93IGJ1dHRvbiBiZWxvdyB0byByZXZlYWwgdGhlIGNvZGUuKioKCioqKioqKioqCjwvZGl2PgoKCmBgYHtyLCBldmFsID0gRkFMU0UsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQojIGxpYnJhcnkgY2FsbHMKbGlicmFyeShNZXRyaWNHcmFwaCkKbGlicmFyeShNYXRyaXgpCmxpYnJhcnkoclNQREUpCgojIGZ1bmN0aW9uIDEKdGFkcG9sZS5laWcgPC0gZnVuY3Rpb24oayxncmFwaCl7CiAgeDEgPC0gYygwLGdyYXBoJGdldF9lZGdlX2xlbmd0aHMoKVsxXSpncmFwaCRtZXNoJFB0RVtncmFwaCRtZXNoJFB0RVssMV09PTEsMl0pIAogIHgyIDwtIGMoMCxncmFwaCRnZXRfZWRnZV9sZW5ndGhzKClbMl0qZ3JhcGgkbWVzaCRQdEVbZ3JhcGgkbWVzaCRQdEVbLDFdPT0yLDJdKSAKICAKICBpZihrPT0wKXsgCiAgICBmLmUxIDwtIHJlcCgxLGxlbmd0aCh4MSkpIAogICAgZi5lMiA8LSByZXAoMSxsZW5ndGgoeDIpKSAKICAgIGYxID0gYyhmLmUxWzFdLGYuZTJbMV0sZi5lMVstMV0sIGYuZTJbLTFdKSAKICAgIGYgPSBsaXN0KHBoaT1mMS9zcXJ0KDMpKSAKICAgIAogIH0gZWxzZSB7CiAgICBmLmUxIDwtIC0yKnNpbihwaSprKjEvMikqY29zKHBpKmsqeDEvMikgCiAgICBmLmUyIDwtIHNpbihwaSprKngyLzIpICAgICAgICAgICAgICAgICAgCiAgICAKICAgIGYxID0gYyhmLmUxWzFdLGYuZTJbMV0sZi5lMVstMV0sIGYuZTJbLTFdKSAKICAgIAogICAgaWYoKGsgJSUgMik9PTEpeyAKICAgICAgZiA9IGxpc3QocGhpPWYxL3NxcnQoMykpIAogICAgfSBlbHNlIHsgCiAgICAgIGYuZTEgPC0gKC0xKV57ay8yfSpjb3MocGkqayp4MS8yKQogICAgICBmLmUyIDwtIGNvcyhwaSprKngyLzIpCiAgICAgIGYyID0gYyhmLmUxWzFdLGYuZTJbMV0sZi5lMVstMV0sZi5lMlstMV0pIAogICAgICBmIDwtIGxpc3QocGhpPWYxLHBzaT1mMi9zcXJ0KDMvMikpCiAgICB9CiAgfQogIAogIHJldHVybihmKQp9CgojIGZ1bmN0aW9uIDIKZ2V0c19ncmFwaCA8LSBmdW5jdGlvbihoKXsKICBlZGdlMSA8LSByYmluZChjKDAsMCksYygxLDApKQogIHRoZXRhIDwtIHNlcShmcm9tPS1waSx0bz1waSxsZW5ndGgub3V0ID0gMTAwMDApCiAgZWRnZTIgPC0gY2JpbmQoMSsxL3BpK2Nvcyh0aGV0YSkvcGksc2luKHRoZXRhKS9waSkKICBlZGdlcyA9IGxpc3QoZWRnZTEsIGVkZ2UyKQogIGdyYXBoIDwtIG1ldHJpY19ncmFwaCRuZXcoZWRnZXMgPSBlZGdlcykKICBncmFwaCRzZXRfbWFudWFsX2VkZ2VfbGVuZ3RocyhlZGdlX2xlbmd0aHMgPSBjKDEsMikpCiAgZ3JhcGgkYnVpbGRfbWVzaChoPWgpCiAgcmV0dXJuKGdyYXBoKQp9CgojZnVuY3Rpb24gMwpnZXRzX3RydWVfY292X21hdCA8LSBmdW5jdGlvbihncmFwaCwga2FwcGEsIHRhdSwgYWxwaGEsIG4ub3ZlcmtpbGwpewogIFNpZ21hLmtsIDwtIG1hdHJpeCgwLG5yb3cgPSBkaW0oZ3JhcGgkbWVzaCRWKVsxXSxuY29sID0gZGltKGdyYXBoJG1lc2gkVilbMV0pCiAgZm9yKGkgaW4gMDpuLm92ZXJraWxsKXsKICAgIHBoaSA8LSB0YWRwb2xlLmVpZyhpLGdyYXBoKSRwaGkKICAgIFNpZ21hLmtsIDwtIFNpZ21hLmtsICsgKDEvKGthcHBhXjIgKyAoaSpwaS8yKV4yKV4oYWxwaGEpKSpwaGklKiV0KHBoaSkKICAgIGlmKGk+MCAmJiAoaSAlJSAyKT09MCl7IAogICAgICBwc2kgPC0gdGFkcG9sZS5laWcoaSxncmFwaCkkcHNpCiAgICAgIFNpZ21hLmtsIDwtIFNpZ21hLmtsICsgKDEvKGthcHBhXjIgKyAoaSpwaS8yKV4yKV4oYWxwaGEpKSpwc2klKiV0KHBzaSkKICAgIH0KICAgIAogIH0KICBTaWdtYS5rbCA8LSBTaWdtYS5rbC90YXVeMgogIHJldHVybihTaWdtYS5rbCkKfQoKIyBwYXJhbWV0ZXJzCmhfdmVjdG9yID0gYygwLjAwMSwgMC4wMDUsIDAuMDEsIDAuMSkKdHlwZV92ZWN0b3IgPSBjKCJjb3ZhcmlhbmNlIiwgIm9wZXJhdG9yIikKdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvciA9IGMoImNoZWJmdW4iLCAiYnJhc2lsIiwgImNoZWJmdW5MQiIpCnJob192ZWN0b3IgPSBjKDAuMSwgMC41LCAxLCAyKQptX3ZlY3RvciA9IGMoMCwxLDIsMyw0LDUpCm51X3ZlY3RvciA9IGMoc2VxKDAuMSwwLjQsYnk9MC4wNSksIHNlcSgwLjQxLDAuNTksYnk9MC4wMSksIHNlcSgwLjYsMS40LGJ5PTAuMDUpLCBzZXEoMS40MSwxLjU5LGJ5PTAuMDEpLCBzZXEoMS42LDIuNCxieT0wLjA1KSwgc2VxKDIuNDEsMi40OSxieT0wLjAxKSkgCm4ub3ZlcmtpbGwgPSAxMDAwCnNpZ21hID0gMQoKRXJyb3IgPSBsaXN0KCkKZm9yIChzIGluIGMoMSwyLDMsNCkpIHsgIyBsb29wIG92ZXIgaF92ZWN0b3IKICBFcnJvcltbYXMuY2hhcmFjdGVyKGhfdmVjdG9yW3NdKV1dID0gbGlzdCgpCiAgaCA9IGhfdmVjdG9yW3NdCiAgZ3JhcGggPSBnZXRzX2dyYXBoKGggPSBoKQogIGZvciAoaSBpbiBjKDEpKSB7ICMgbG9vcCBvdmVyIHR5cGVfdmVjdG9yCiAgICBFcnJvcltbYXMuY2hhcmFjdGVyKGhfdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dID0gbGlzdCgpCiAgICB0eXBlID0gdHlwZV92ZWN0b3JbaV0KICAgIGZvciAoaiBpbiBjKDEsMiwzKSkgeyAjIGxvb3Agb3ZlciB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yCiAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXSA9IGxpc3QoKQogICAgICB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24gPSB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdCiAgICAgIGZvciAoayBpbiBjKDQpKSB7ICMgbG9vcCBvdmVyIHJob192ZWN0b3IKICAgICAgICBFcnJvcltbYXMuY2hhcmFjdGVyKGhfdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dW1t0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdXV1bW2FzLmNoYXJhY3RlcihyaG9fdmVjdG9yW2tdKV1dID0gbGlzdCgpCiAgICAgICAgcmhvID0gcmhvX3ZlY3RvcltrXQogICAgICAgIGZvciAobCBpbiAxOmxlbmd0aChtX3ZlY3RvcikpIHsgIyBsb29wIG92ZXIgbV92ZWN0b3IKICAgICAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXSA9IG1hdHJpeChOQSwgbnJvdyA9IGxlbmd0aChudV92ZWN0b3IpLCBuY29sID0gMikKICAgICAgICAgIGNvbG5hbWVzKEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXSkgPSBjKCJMX2luZl9lcnJvciIsICJMXzJfZXJyb3IiKQogICAgICAgICAgbSA9IG1fdmVjdG9yW2xdCiAgICAgICAgICBmb3IgKG4gaW4gMTpsZW5ndGgobnVfdmVjdG9yKSkgeyAjIGxvb3Agb3ZlciBudV92ZWN0b3IKICAgICAgICAgICAgbnUgPSBudV92ZWN0b3Jbbl0KICAgICAgICAgICAgCiAgICAgICAgICAgIGthcHBhID0gc3FydCg4Km51KS9yaG8KICAgICAgICAgICAgdGF1ID0gc3FydChnYW1tYShudSkgLyAoc2lnbWFeMiAqIGthcHBhXigyKm51KSAqICg0KnBpKV4oMS8yKSAqIGdhbW1hKG51ICsgMS8yKSkpICAjc2lnbWEgPSAxLCBkID0gMQogICAgICAgICAgICBhbHBoYSA9IG51ICsgMS8yCiAgICAgICAgICAgIAogICAgICAgICAgICB0cnlDYXRjaCh7CiAgICAgICAgICAgICMgZ2V0dGluZyB0cnVlIGNvdmFyaWFuY2UKICAgICAgICAgICAgdHJ1ZV9jb3ZfbWF0ID0gZ2V0c190cnVlX2Nvdl9tYXQoZ3JhcGggPSBncmFwaCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2FwcGEgPSBrYXBwYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGF1ID0gdGF1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IGFscGhhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLm92ZXJraWxsID0gbi5vdmVya2lsbCkKICAgICAgICAgICAgCiAgICAgICAgICAgICMgZ2V0dGluZyB0aGUgYXBwcm94aW1hdGUgY292YXJpYW5jZSBtYXRyaXgKICAgICAgICAgICAgb3AgPSBtYXRlcm4ub3BlcmF0b3JzKGFscGhhID0gYWxwaGEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2FwcGEgPSBrYXBwYSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXUgPSB0YXUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtID0gbSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmFwaCA9IGdyYXBoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9IHR5cGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24gPSB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24pCiAgICAgICAgICAgIGFwcHJfY292X21hdCA9IG9wJGNvdmFyaWFuY2VfbWVzaCgpCiAgICAgICAgICAgIAogICAgICAgICAgICAjIGNvbXB1dGluZyB0aGUgZXJyb3JzCiAgICAgICAgICAgIExfaW5mX2Vycm9yID0gbWF4KGFicyh0cnVlX2Nvdl9tYXQgLSBhcHByX2Nvdl9tYXQpKQogICAgICAgICAgICBMXzJfZXJyb3IgPSBzcXJ0KGFzLmRvdWJsZSh0KGdyYXBoJG1lc2gkd2VpZ2h0cyklKiUodHJ1ZV9jb3ZfbWF0IC0gYXBwcl9jb3ZfbWF0KV4yJSolZ3JhcGgkbWVzaCR3ZWlnaHRzKSkKICAgICAgICAgICAgCiAgICAgICAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXVtuLDFdID0gTF9pbmZfZXJyb3IKICAgICAgICAgICAgRXJyb3JbW2FzLmNoYXJhY3RlcihoX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dW1thcy5jaGFyYWN0ZXIocmhvX3ZlY3RvcltrXSldXVtbYXMuY2hhcmFjdGVyKG1fdmVjdG9yW2xdKV1dW24sMl0gPSBMXzJfZXJyb3IKICAgICAgICAgICAgfSwgZXJyb3IgPSBmdW5jdGlvbihlcnIpewogICAgICAgICAgICAgIHdhcm5pbmcocGFzdGUoIkVycm9yIG9jY3VycmVkIGF0IGl0ZXJhdGlvbiBoPSIsIGgsICIsdHlwZT0iLCB0eXBlLCAiLHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbj0iLCB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24sICIscmhvPSIsIHJobywgIixtPSIsIG0sICIsbnU9IiwgbnUsICJFcnJvcjoiLCBjb25kaXRpb25NZXNzYWdlKGVycikpKQogICAgICAgICAgICAgIHByaW50KHBhc3RlKCJFcnJvciBvY2N1cnJlZCBhdCBpdGVyYXRpb24gaD0iLCBoLCAiLHR5cGU9IiwgdHlwZSwgIix0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb249IiwgdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uLCAiLHJobz0iLCByaG8sICIsbT0iLCBtLCAiLG51PSIsIG51LCAiRXJyb3I6IiwgY29uZGl0aW9uTWVzc2FnZShlcnIpKSkKICAgICAgICAgICAgICBFcnJvcltbYXMuY2hhcmFjdGVyKGhfdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dW1t0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdXV1bW2FzLmNoYXJhY3RlcihyaG9fdmVjdG9yW2tdKV1dW1thcy5jaGFyYWN0ZXIobV92ZWN0b3JbbF0pXV1bbiwxXSA9IE5BCiAgICAgICAgICAgICAgRXJyb3JbW2FzLmNoYXJhY3RlcihoX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dW1thcy5jaGFyYWN0ZXIocmhvX3ZlY3RvcltrXSldXVtbYXMuY2hhcmFjdGVyKG1fdmVjdG9yW2xdKV1dW24sMl0gPSBOQQogICAgICAgICAgICB9KQogICAgICAgICAgICBwcmludChwYXN0ZSgiaD0iLCBoLCAiLHR5cGU9IiwgdHlwZSwgIix0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb249IiwgdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uLCAiLHJobz0iLCByaG8sICIsbT0iLCBtLCAiLG51PSIsIG51KSkKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgIH0KICB9Cn0KCkVycm9yX3RhZHBvbGVfREVGX3JobzIgPSBFcnJvcgpzYXZlKEVycm9yX3RhZHBvbGVfREVGX3JobzIsIGZpbGUgPSBoZXJlKCJkYXRhX2ZpbGVzL0Vycm9yX3RhZHBvbGVfREVGX3JobzIuUkRhdGEiKSkKYGBgCgojIyBQbG90dGluZyB0aGUgZXJyb3JzCgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmxvYWQoaGVyZSgiZGF0YV9maWxlcy9FcnJvcl90YWRwb2xlX0RFRl9yaG8wLjEuUkRhdGEiKSkKbG9hZChoZXJlKCJkYXRhX2ZpbGVzL0Vycm9yX3RhZHBvbGVfREVGX3JobzAuNS5SRGF0YSIpKQpsb2FkKGhlcmUoImRhdGFfZmlsZXMvRXJyb3JfdGFkcG9sZV9ERUZfcmhvMS5SRGF0YSIpKQpsb2FkKGhlcmUoImRhdGFfZmlsZXMvRXJyb3JfdGFkcG9sZV9ERUZfcmhvMi5SRGF0YSIpKQoKaF92ZWN0b3IgPSBjKCIwLjAwMSIsICIwLjAwNSIsICIwLjAxIiwgIjAuMSIpCnR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3IgPSBjKCJjaGViZnVuIiwgImJyYXNpbCIsICJjaGViZnVuTEIiKQpudV9tYXggPSA1MwpudV92ZWN0b3IgPSAwLjUgKyBjKHNlcSgwLjEsMC40LGJ5PTAuMDUpLCBzZXEoMC40MSwwLjU5LGJ5PTAuMDEpLCBzZXEoMC42LDEuNCxieT0wLjA1KSwgc2VxKDEuNDEsMS41OSxieT0wLjAxKSwgc2VxKDEuNiwyLjQsYnk9MC4wNSksIHNlcSgyLjQxLDIuNDksYnk9MC4wMSkpWzE6bnVfbWF4XQoKbiA9ICIwLjAwMSIKdCA9ICJjaGViZnVuIgoKCmRhdCA9IHJiaW5kKApkYXRhLmZyYW1lKG51ID0gcmVwKG51X3ZlY3Rvciw1KSwgCiAgICAgICAgICAgcmhvID0gcmVwKDAuMSwgdGltZXMgPSA1Km51X21heCksCiAgICAgICAgICAgbSA9IHJlcCgxOjUsIGVhY2ggPSBudV9tYXgpLAogICAgICAgICAgIGVycm9yID0gYyhFcnJvcl90YWRwb2xlX0RFRl9yaG8wLjFbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuMSJdXVtbIjEiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX3RhZHBvbGVfREVGX3JobzAuMVtbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC4xIl1dW1siMiJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfdGFkcG9sZV9ERUZfcmhvMC4xW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjEiXV1bWyIzIl1dWzE6bnVfbWF4LDFdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl90YWRwb2xlX0RFRl9yaG8wLjFbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuMSJdXVtbIjQiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX3RhZHBvbGVfREVGX3JobzAuMVtbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC4xIl1dW1siNSJdXVsxOm51X21heCwxXSksCiAgICAgICAgICAgTCA9IHJlcCgiTGluZiIsIHRpbWVzID0gNSpudV9tYXgpCiksCgpkYXRhLmZyYW1lKG51ID0gcmVwKG51X3ZlY3Rvciw1KSwgCiAgICAgICAgICAgcmhvID0gYyhyZXAoMC41LCB0aW1lcyA9IDUqbnVfbWF4KSksCiAgICAgICAgICAgbSA9IHJlcCgxOjUsIGVhY2ggPSBudV9tYXgpLAogICAgICAgICAgIGVycm9yID0gYyhFcnJvcl90YWRwb2xlX0RFRl9yaG8wLjVbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuNSJdXVtbIjEiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX3RhZHBvbGVfREVGX3JobzAuNVtbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC41Il1dW1siMiJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfdGFkcG9sZV9ERUZfcmhvMC41W1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjUiXV1bWyIzIl1dWzE6bnVfbWF4LDFdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl90YWRwb2xlX0RFRl9yaG8wLjVbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuNSJdXVtbIjQiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX3RhZHBvbGVfREVGX3JobzAuNVtbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC41Il1dW1siNSJdXVsxOm51X21heCwxXSksCiAgICAgICAgICAgTCA9IHJlcCgiTGluZiIsIHRpbWVzID0gNSpudV9tYXgpCiksCgpkYXRhLmZyYW1lKG51ID0gcmVwKG51X3ZlY3Rvciw1KSwgCiAgICAgICAgICAgcmhvID0gYyhyZXAoMSwgdGltZXMgPSA1Km51X21heCkpLAogICAgICAgICAgIG0gPSByZXAoMTo1LCBlYWNoID0gbnVfbWF4KSwKICAgICAgICAgICBlcnJvciA9IGMoRXJyb3JfdGFkcG9sZV9ERUZfcmhvMVtbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMSJdXVtbIjEiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX3RhZHBvbGVfREVGX3JobzFbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjEiXV1bWyIyIl1dWzE6bnVfbWF4LDFdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl90YWRwb2xlX0RFRl9yaG8xW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIxIl1dW1siMyJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfdGFkcG9sZV9ERUZfcmhvMVtbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMSJdXVtbIjQiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX3RhZHBvbGVfREVGX3JobzFbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjEiXV1bWyI1Il1dWzE6bnVfbWF4LDFdKSwKICAgICAgICAgICBMID0gcmVwKCJMaW5mIiwgdGltZXMgPSA1Km51X21heCkKKSwKCmRhdGEuZnJhbWUobnUgPSByZXAobnVfdmVjdG9yLDUpLCAKICAgICAgICAgICByaG8gPSBjKHJlcCgyLCB0aW1lcyA9IDUqbnVfbWF4KSksCiAgICAgICAgICAgbSA9IHJlcCgxOjUsIGVhY2ggPSBudV9tYXgpLAogICAgICAgICAgIGVycm9yID0gYyhFcnJvcl90YWRwb2xlX0RFRl9yaG8yW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIyIl1dW1siMSJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfdGFkcG9sZV9ERUZfcmhvMltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMiJdXVtbIjIiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX3RhZHBvbGVfREVGX3JobzJbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjIiXV1bWyIzIl1dWzE6bnVfbWF4LDFdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl90YWRwb2xlX0RFRl9yaG8yW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIyIl1dW1siNCJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfdGFkcG9sZV9ERUZfcmhvMltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMiJdXVtbIjUiXV1bMTpudV9tYXgsMV0pLAogICAgICAgICAgIEwgPSByZXAoIkxpbmYiLCB0aW1lcyA9IDUqbnVfbWF4KQopLAoKIyMgTDIKCmRhdGEuZnJhbWUobnUgPSByZXAobnVfdmVjdG9yLDUpLCAKICAgICAgICAgICByaG8gPSByZXAoMC4xLCB0aW1lcyA9IDUqbnVfbWF4KSwKICAgICAgICAgICBtID0gcmVwKDE6NSwgZWFjaCA9IG51X21heCksCiAgICAgICAgICAgZXJyb3IgPSBjKEVycm9yX3RhZHBvbGVfREVGX3JobzAuMVtbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC4xIl1dW1siMSJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfdGFkcG9sZV9ERUZfcmhvMC4xW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjEiXV1bWyIyIl1dWzE6bnVfbWF4LDJdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl90YWRwb2xlX0RFRl9yaG8wLjFbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuMSJdXVtbIjMiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX3RhZHBvbGVfREVGX3JobzAuMVtbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC4xIl1dW1siNCJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfdGFkcG9sZV9ERUZfcmhvMC4xW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjEiXV1bWyI1Il1dWzE6bnVfbWF4LDJdKSwKICAgICAgICAgICBMID0gcmVwKCJMMiIsIHRpbWVzID0gNSpudV9tYXgpCiksCgpkYXRhLmZyYW1lKG51ID0gcmVwKG51X3ZlY3Rvciw1KSwgCiAgICAgICAgICAgcmhvID0gYyhyZXAoMC41LCB0aW1lcyA9IDUqbnVfbWF4KSksCiAgICAgICAgICAgbSA9IHJlcCgxOjUsIGVhY2ggPSBudV9tYXgpLAogICAgICAgICAgIGVycm9yID0gYyhFcnJvcl90YWRwb2xlX0RFRl9yaG8wLjVbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuNSJdXVtbIjEiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX3RhZHBvbGVfREVGX3JobzAuNVtbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC41Il1dW1siMiJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfdGFkcG9sZV9ERUZfcmhvMC41W1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjUiXV1bWyIzIl1dWzE6bnVfbWF4LDJdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl90YWRwb2xlX0RFRl9yaG8wLjVbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuNSJdXVtbIjQiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX3RhZHBvbGVfREVGX3JobzAuNVtbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC41Il1dW1siNSJdXVsxOm51X21heCwyXSksCiAgICAgICAgICAgTCA9IHJlcCgiTDIiLCB0aW1lcyA9IDUqbnVfbWF4KQopLAoKZGF0YS5mcmFtZShudSA9IHJlcChudV92ZWN0b3IsNSksIAogICAgICAgICAgIHJobyA9IGMocmVwKDEsIHRpbWVzID0gNSpudV9tYXgpKSwKICAgICAgICAgICBtID0gcmVwKDE6NSwgZWFjaCA9IG51X21heCksCiAgICAgICAgICAgZXJyb3IgPSBjKEVycm9yX3RhZHBvbGVfREVGX3JobzFbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjEiXV1bWyIxIl1dWzE6bnVfbWF4LDJdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl90YWRwb2xlX0RFRl9yaG8xW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIxIl1dW1siMiJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfdGFkcG9sZV9ERUZfcmhvMVtbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMSJdXVtbIjMiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX3RhZHBvbGVfREVGX3JobzFbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjEiXV1bWyI0Il1dWzE6bnVfbWF4LDJdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl90YWRwb2xlX0RFRl9yaG8xW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIxIl1dW1siNSJdXVsxOm51X21heCwyXSksCiAgICAgICAgICAgTCA9IHJlcCgiTDIiLCB0aW1lcyA9IDUqbnVfbWF4KQopLAoKZGF0YS5mcmFtZShudSA9IHJlcChudV92ZWN0b3IsNSksIAogICAgICAgICAgIHJobyA9IGMocmVwKDIsIHRpbWVzID0gNSpudV9tYXgpKSwKICAgICAgICAgICBtID0gcmVwKDE6NSwgZWFjaCA9IG51X21heCksCiAgICAgICAgICAgZXJyb3IgPSBjKEVycm9yX3RhZHBvbGVfREVGX3JobzJbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjIiXV1bWyIxIl1dWzE6bnVfbWF4LDJdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl90YWRwb2xlX0RFRl9yaG8yW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIyIl1dW1siMiJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfdGFkcG9sZV9ERUZfcmhvMltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMiJdXVtbIjMiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX3RhZHBvbGVfREVGX3JobzJbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjIiXV1bWyI0Il1dWzE6bnVfbWF4LDJdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl90YWRwb2xlX0RFRl9yaG8yW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIyIl1dW1siNSJdXVsxOm51X21heCwyXSksCiAgICAgICAgICAgTCA9IHJlcCgiTDIiLCB0aW1lcyA9IDUqbnVfbWF4KQopCikKCgpkYXQkcmhvID0gZmFjdG9yKGRhdCRyaG8sIGxldmVscyA9IGMoIjAuMSIsICIwLjUiLCAiMSIsICIyIikpCmRhdCRMID0gZmFjdG9yKGRhdCRMLCBsZXZlbHMgPSBjKCJMMiIsICJMaW5mIikpCmxldmVscyhkYXQkcmhvKSA9IGMoIjAuMSIgPSBsYXRleDJleHA6OlRlWCgiJFxccmhvID0gMC4xJCIpLCAiMC41IiA9IGxhdGV4MmV4cDo6VGVYKCIkXFxyaG8gPSAwLjUkIiksICIxIiA9IGxhdGV4MmV4cDo6VGVYKCIkXFxyaG8gPSAxJCIpLCAiMiIgPSBsYXRleDJleHA6OlRlWCgiJFxccmhvID0gMiQiKSkKbGV2ZWxzKGRhdCRMKSA9IGMoIkwyIiA9IGxhdGV4MmV4cDo6VGVYKCIkTF8yKFxcR2FtbWFcXHRpbWVzXFxHYW1tYSkkIGVycm9yIiksICJMaW5mIiA9IGxhdGV4MmV4cDo6VGVYKCIkTF9cXGluZnR5KFxcR2FtbWFcXHRpbWVzXFxHYW1tYSkkIGVycm9yIikpCgpwIDwtIGdncGxvdChkYXQsIGFlcyhudSwgZXJyb3IsIGNvbG91ciA9IGFzLmZhY3RvcihtKSkpICsgCiAgZmFjZXRfZ3JpZChMIH4gcmhvLCBsYWJlbGxlciA9IGxhYmVsX3BhcnNlZCkgKwogIGdlb21fbGluZSgpICsKICBzY2FsZV95X2xvZzEwKG4uYnJlYWtzID0gNSkgKwogIHNjYWxlX3hfY29udGludW91cyhuLmJyZWFrcyA9IDEwKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuc3BhY2luZyA9IHVuaXQoMC4zLCAiY20iKSwgdGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAiUGFsYXRpbm8iKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLCAgICAgICAgIyBQYW5lbCB0aXRsZXMKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksICAgICAgICAjIEF4aXMgdGl0bGVzCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksICAgICAgICAgIyBBeGlzIHRleHQKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwgICAgICAjIExlZ2VuZCB0aXRsZQogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikpICsKICBsYWJzKHggPSBicXVvdGUoYWxwaGEgfiAiKHNtb290aG5lc3MgcGFyYW1ldGVyKSIpLCB5ID0gIkNvdmFyaWFuY2UgRXJyb3IiLCBjb2xvciA9ICJtIikgKyBnZ3RpdGxlKCJUYWRwb2xlIGdyYXBoIikKYGBgCgpgYGB7ciwgZmlnLmRpbSA9IGMoMTIsNiksIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUiLCBmaWcuY2FwID0gY2FwdGlvbmVyKCJDb3ZhcmlhbmNlIGVycm9yIGZvciB0aGUgdGFkcG9sZSBncmFwaC4iKX0KcApnZ3NhdmUoaGVyZSgiZGF0YV9maWxlcy9uZXdfdGFkcG9sZV91cHRvMS41LnBuZyIpLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSA2LCBwbG90ID0gcCwgZHBpID0gMzAwKQpgYGAKCiMgUmVmZXJlbmNlcwoKYGBge3J9CmNpdGVfcGFja2FnZXMob3V0cHV0ID0gInBhcmFncmFwaCIsIG91dC5kaXIgPSAiLiIpCmBgYAo=