Go back to the Contents page.


Press Show to reveal the code chunks.


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.

# Create a clipboard button on the rendered HTML page
source(here::here("clipboard.R")); clipboard
# Set seed for reproducibility
set.seed(593) 
# 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 = FALSE,       
  # 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)
}
# Define the function to truncate a number to two decimal places
truncate_to_two <- function(x) {
  truncated <- floor(x * 100) / 100
  sprintf("%.2f", truncated)
}

1 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::here() starts from the home directory

library(slackr)
source("keys.R")
slackr_setup(token = token) # token comes from keys.R
## [1] "Successfully connected to Slack"
capture.output(
  knitr::purl(here::here("functionality1.Rmd"), output = here::here("functionality1.R")),
  file = here::here("old/purl_log.txt")
)
source(here::here("functionality1.R"))

2 Interval graph


Press Show to reveal the code chunks.


# 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::here("data_files/Error_interval_DEF.RData"))

2.1 Plotting the errors

load(here::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" = "$\\rho = 0.1$", "0.5" = "$\\rho = 0.5$", "1" = "$\\rho = 1$", "2" = "$\\rho = 2$")
levels(dat$L) = c("L2" = "$L_2(\\Gamma\\times\\Gamma)$", "Linf" = "$L_\\infty(\\Gamma\\times\\Gamma)$")


p_err_int <- ggplot(dat, aes(nu, error, colour = as.factor(m))) + 
  facet_grid(L ~ rho) +
  geom_line(size = 1.3) +
  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(hjust = 0.5, 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 = "$\\alpha\\mbox{ }(\\mbox{Smoothness parameter})$", y = "$\\mbox{Covariance Error}$", color = "$m$") +
  ggtitle("$\\mbox{Interval graph}$") 

myggsave(p_err_int, width = 12, height = 6)
knitr::include_graphics(here::here("data_files/tikzpic/p_err_int.pdf"))

Figure 1: Covariance error for the interval graph.

3 Circle graph


Press Show to reveal the code chunks.


# 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::here("data_files/Error_circle_DEF.RData"))

3.1 Plotting the errors

load(here::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" = "$\\rho = 0.1$", "0.5" = "$\\rho = 0.5$", "1" = "$\\rho = 1$", "2" = "$\\rho = 2$")
levels(dat$L) = c("L2" = "$L_2(\\Gamma\\times\\Gamma)$", "Linf" = "$L_\\infty(\\Gamma\\times\\Gamma)$")


p_err_cir <- ggplot(dat, aes(nu, error, colour = as.factor(m))) + 
  facet_grid(L ~ rho) +
  geom_line(size = 1.3) +
  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(hjust = 0.5, 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 = "$\\alpha\\mbox{ }(\\mbox{Smoothness parameter})$", y = "$\\mbox{Covariance Error}$", color = "$m$") +
  ggtitle("$\\mbox{Circle graph}$") 

myggsave(p_err_cir, width = 12, height = 6)
knitr::include_graphics(here::here("data_files/tikzpic/p_err_cir.pdf"))

Figure 2: Covariance error for the circle graph.

4 Tadpole graph

4.1 rho = 0.1


Press Show to reveal the code chunks.


# 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::here("data_files/Error_tadpole_DEF_rho0.1.RData"))

4.2 rho = 0.5


Press Show to reveal the code chunks.


# 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::here("data_files/Error_tadpole_DEF_rho0.5.RData"))

4.3 rho = 1


Press Show to reveal the code chunks.


# 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::here("data_files/Error_tadpole_DEF_rho1.RData"))

4.4 rho = 2


Press Show to reveal the code chunks.


# 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::here("data_files/Error_tadpole_DEF_rho2.RData"))

4.5 Plotting the errors

load(here::here("data_files/Error_tadpole_DEF_rho0.1.RData"))
load(here::here("data_files/Error_tadpole_DEF_rho0.5.RData"))
load(here::here("data_files/Error_tadpole_DEF_rho1.RData"))
load(here::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" = "$\\rho = 0.1$", "0.5" = "$\\rho = 0.5$", "1" = "$\\rho = 1$", "2" = "$\\rho = 2$")
levels(dat$L) = c("L2" = "$L_2(\\Gamma\\times\\Gamma)$", "Linf" = "$L_\\infty(\\Gamma\\times\\Gamma)$")


p_err_tad <- ggplot(dat, aes(nu, error, colour = as.factor(m))) + 
  facet_grid(L ~ rho) +
  geom_line(size = 1.3) +
  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(hjust = 0.5, 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 = "$\\alpha\\mbox{ }(\\mbox{Smoothness parameter})$", y = "$\\mbox{Covariance Error}$", color = "$m$") +
  ggtitle("$\\mbox{Tadpole graph}$") 

myggsave(p_err_tad, width = 12, height = 6)
knitr::include_graphics(here::here("data_files/tikzpic/p_err_tad.pdf"))

Figure 3: Covariance error for the tadpole graph.

5 References

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

We used R version 4.5.2 (R Core Team 2025a) and the following R packages: cowplot v. 1.2.0 (Wilke 2025), ggmap v. 4.0.2 (Kahle and Wickham 2013), ggpubr v. 0.6.3 (Kassambara 2026), ggtext v. 0.1.2 (Wilke and Wiernik 2022), glue v. 1.8.0 (Hester and Bryan 2024), grid v. 4.5.2 (R Core Team 2025b), here v. 1.0.1 (Müller 2020), htmltools v. 0.5.8.1 (Cheng et al. 2024), INLA v. 25.11.22 (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.13.0 (Yuan et al. 2017; Bachl et al. 2019), knitr v. 1.50 (Xie 2014, 2015, 2025), latex2exp v. 0.9.8 (Meschiari 2026), Matrix v. 1.7.3 (Bates, Maechler, and Jagan 2025), MetricGraph v. 1.5.0.9000 (Bolin, Simas, and Wallin 2023a, 2023b, 2024, 2025; Bolin et al. 2024), OpenStreetMap v. 0.4.1 (Fellows and Stotz 2025), patchwork v. 1.3.1 (Pedersen 2025), plotly v. 4.11.0 (Sievert 2020), plotrix v. 3.8.14 (J 2006), renv v. 1.1.7 (Ushey and Wickham 2026), reshape2 v. 1.4.4 (Wickham 2007), reticulate v. 1.44.1 (Ushey, Allaire, and Tang 2025), rmarkdown v. 2.30 (Xie, Allaire, and Grolemund 2018; Xie, Dervieux, and Riederer 2020; Allaire et al. 2025), rSPDE v. 2.5.2.9000 (Bolin and Kirchner 2020; Bolin and Simas 2023; Bolin, Simas, and Xiong 2024), scales v. 1.4.0 (Wickham, Pedersen, and Seidel 2025), sf v. 1.1.0 (E. Pebesma 2018; E. Pebesma and Bivand 2023), slackr v. 3.4.0 (Kaye et al. 2025), sp v. 2.2.1 (E. J. Pebesma and Bivand 2005; Bivand, Pebesma, and Gomez-Rubio 2013), tidyverse v. 2.0.0 (Wickham et al. 2019), tikzDevice v. 0.12.6 (Sharpsteen and Bracken 2023), viridis v. 0.6.5 (Garnier et al. 2024), 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://doi.org/10.32614/CRAN.package.xaringanExtra.
Allaire, JJ, Yihui Xie, Christophe Dervieux, Jonathan McPherson, Javier Luraschi, Kevin Ushey, Aron Atkins, et al. 2025. 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. 2025. Matrix: Sparse and Dense Matrix Classes and Methods. https://doi.org/10.32614/CRAN.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. MetricGraph: Random Fields on Metric Graphs. https://CRAN.R-project.org/package=MetricGraph.
———. 2023b. “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.
———. 2025. “Markov Properties of Gaussian Random Fields on Compact Metric Graphs.” Bernoulli. https://doi.org/10.48550/arXiv.2304.03190.
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://github.com/rstudio/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 Jan-Peter Stotz. 2025. OpenStreetMap: Access to Open Street Map Raster Images. https://doi.org/10.32614/CRAN.package.OpenStreetMap.
Garnier, Simon, Ross, Noam, Rudis, Robert, Camargo, et al. 2024. viridis(Lite) - Colorblind-Friendly Color Maps for r. https://doi.org/10.5281/zenodo.4679423.
Hester, Jim, and Jennifer Bryan. 2024. glue: Interpreted String Literals. https://glue.tidyverse.org/.
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. 2026. ggpubr: ggplot2 Based Publication Ready Plots. https://doi.org/10.32614/CRAN.package.ggpubr.
Kaye, Matt, Bob Rudis, Andrie de Vries, and Jonathan Sidi. 2025. slackr: Send Messages, Images, r Objects and Files to Slack Channels/Users. https://github.com/mrkaye97/slackr.
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.
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. 2026. Latex2exp: Use LaTeX Expressions in Plots. https://doi.org/10.32614/CRAN.package.latex2exp.
Müller, Kirill. 2020. here: A Simpler Way to Find Your Files. https://doi.org/10.32614/CRAN.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. 2025. patchwork: The Composer of Plots. https://doi.org/10.32614/CRAN.package.patchwork.
R Core Team. 2025a. R: A Language and Environment for Statistical Computing. Vienna, Austria: R Foundation for Statistical Computing. https://www.R-project.org/.
———. 2025b. 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.
Sharpsteen, Charlie, and Cameron Bracken. 2023. tikzDevice: R Graphics Output in LaTeX Format. https://doi.org/10.32614/CRAN.package.tikzDevice.
Sievert, Carson. 2020. Interactive Web-Based Data Visualization with r, Plotly, and Shiny. Chapman; Hall/CRC. https://plotly-r.com.
Ushey, Kevin, JJ Allaire, and Yuan Tang. 2025. reticulate: Interface to Python. https://doi.org/10.32614/CRAN.package.reticulate.
Ushey, Kevin, and Hadley Wickham. 2026. renv: Project Environments. https://doi.org/10.32614/CRAN.package.renv.
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. 2025. scales: Scale Functions for Visualization. https://scales.r-lib.org.
Wilke, Claus O. 2025. cowplot: Streamlined Plot Theme and Plot Annotations for ggplot2. https://doi.org/10.32614/CRAN.package.cowplot.
Wilke, Claus O., and Brenton M. Wiernik. 2022. ggtext: Improved Text Rendering Support for ggplot2. https://doi.org/10.32614/CRAN.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/.
———. 2025. 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.
LS0tCnRpdGxlOiAiTnVtZXJpY2FsIGVycm9yIgpkYXRlOiAiTGFzdCBtb2RpZmllZDogYHIgZm9ybWF0KFN5cy50aW1lKCksICclZC0lbS0lWS4nKWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgbWF0aGpheDogImh0dHBzOi8vY2RuLmpzZGVsaXZyLm5ldC9ucG0vbWF0aGpheEAzL2VzNS90ZXgtbW1sLWNodG1sLmpzIgogICAgaGlnaGxpZ2h0OiBweWdtZW50cwogICAgdGhlbWU6IGZsYXRseQogICAgY29kZV9mb2xkaW5nOiBoaWRlICMgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSIgdG8gaGlkZSBjb2RlIGFuZCBhZGQgYSBidXR0b24gdG8gc2hvdyBpdAogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiB0cnVlCiAgICAgIHNtb290aF9zY3JvbGw6IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgZmlnX2NhcHRpb246IHRydWUKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNzczogdmlzdWFsLmNzcwphbHdheXNfYWxsb3dfaHRtbDogdHJ1ZQpiaWJsaW9ncmFwaHk6IAogIC0gcmVmZXJlbmNlcy5iaWIKICAtIGdyYXRlZnVsLXJlZnMuYmliCmhlYWRlci1pbmNsdWRlczoKICAtIFxuZXdjb21tYW5ke1xhcn17XG1hdGhiYntSfX0KICAtIFxuZXdjb21tYW5ke1xsbGF2fVsxXXtcbGVmdFx7IzFccmlnaHRcfX0KICAtIFxuZXdjb21tYW5ke1xwYXJlfVsxXXtcbGVmdCgjMVxyaWdodCl9CiAgLSBcbmV3Y29tbWFuZHtcTmNhbH17XG1hdGhjYWx7Tn19CiAgLSBcbmV3Y29tbWFuZHtcVmNhbH17XG1hdGhjYWx7Vn19CiAgLSBcbmV3Y29tbWFuZHtcRWNhbH17XG1hdGhjYWx7RX19CiAgLSBcbmV3Y29tbWFuZHtcV2NhbH17XG1hdGhjYWx7V319CiAgLSBcbmV3Y29tbWFuZHtcYWxtb3N0ZXZlcnl3aGVyZX17XG1hdGhybXthLmUufVw7fQotLS0KCkdvIGJhY2sgdG8gdGhlIFtDb250ZW50c10oYWJvdXQuaHRtbCkgcGFnZS4KCjxkaXYgc3R5bGU9ImNvbG9yOiAjMmMzZTUwOyB0ZXh0LWFsaWduOiByaWdodDsiPgoqKioqKioqKiAgCjxzdHJvbmc+UHJlc3MgU2hvdyB0byByZXZlYWwgdGhlIGNvZGUgY2h1bmtzLjwvc3Ryb25nPiAgCgoqKioqKioqKgo8L2Rpdj4KCgpHbyBiYWNrIHRvIHRoZSBbQWJvdXQgcGFnZV0oYWJvdXQuaHRtbCkuIFRoaXMgW2xpbmtdKGRhdGFfZmlsZXMvUkVBRE1FLmh0bWwpIG1pZ2h0IGJlIHVzZWZ1bCB0byBrZWVwIHRyYWNrIG9mIHRoZSBmaWxlcyBjcmVhdGVkIGR1cmluZyB0aGUgcHJlcHJvY2Vzc2luZy4KCkxldCB1cyBzZXQgc29tZSBnbG9iYWwgb3B0aW9ucyBmb3IgYWxsIGNvZGUgY2h1bmtzIGluIHRoaXMgZG9jdW1lbnQuCgoKYGBge3J9CiMgQ3JlYXRlIGEgY2xpcGJvYXJkIGJ1dHRvbiBvbiB0aGUgcmVuZGVyZWQgSFRNTCBwYWdlCnNvdXJjZShoZXJlOjpoZXJlKCJjbGlwYm9hcmQuUiIpKTsgY2xpcGJvYXJkCiMgU2V0IHNlZWQgZm9yIHJlcHJvZHVjaWJpbGl0eQpzZXQuc2VlZCg1OTMpIAojIFNldCBnbG9iYWwgb3B0aW9ucyBmb3IgYWxsIGNvZGUgY2h1bmtzCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICAjIERpc2FibGUgbWVzc2FnZXMgcHJpbnRlZCBieSBSIGNvZGUgY2h1bmtzCiAgbWVzc2FnZSA9IEZBTFNFLCAgICAKICAjIERpc2FibGUgd2FybmluZ3MgcHJpbnRlZCBieSBSIGNvZGUgY2h1bmtzCiAgd2FybmluZyA9IEZBTFNFLCAgICAKICAjIFNob3cgUiBjb2RlIHdpdGhpbiBjb2RlIGNodW5rcyBpbiBvdXRwdXQKICBlY2hvID0gVFJVRSwgICAgICAgIAogICMgSW5jbHVkZSBib3RoIFIgY29kZSBhbmQgaXRzIHJlc3VsdHMgaW4gb3V0cHV0CiAgaW5jbHVkZSA9IFRSVUUsICAgICAKICAjIEV2YWx1YXRlIFIgY29kZSBjaHVua3MKICBldmFsID0gRkFMU0UsICAgICAgIAogICMgRW5hYmxlIGNhY2hpbmcgb2YgUiBjb2RlIGNodW5rcyBmb3IgZmFzdGVyIHJlbmRlcmluZwogIGNhY2hlID0gRkFMU0UsICAgICAgCiAgIyBBbGlnbiBmaWd1cmVzIGluIHRoZSBjZW50ZXIgb2YgdGhlIG91dHB1dAogIGZpZy5hbGlnbiA9ICJjZW50ZXIiLAogICMgRW5hYmxlIHJldGluYSBkaXNwbGF5IGZvciBoaWdoLXJlc29sdXRpb24gZmlndXJlcwogIHJldGluYSA9IDIsCiAgIyBTaG93IGVycm9ycyBpbiB0aGUgb3V0cHV0IGluc3RlYWQgb2Ygc3RvcHBpbmcgcmVuZGVyaW5nCiAgZXJyb3IgPSBUUlVFLAogICMgRG8gbm90IGNvbGxhcHNlIGNvZGUgYW5kIG91dHB1dCBpbnRvIGEgc2luZ2xlIGJsb2NrCiAgY29sbGFwc2UgPSBGQUxTRQopCiMgU3RhcnQgdGhlIGZpZ3VyZSBjb3VudGVyCmZpZ19jb3VudCA8LSAwCiMgRGVmaW5lIHRoZSBjYXB0aW9uZXIgZnVuY3Rpb24KY2FwdGlvbmVyIDwtIGZ1bmN0aW9uKGNhcHRpb24pIHsKICBmaWdfY291bnQgPDwtIGZpZ19jb3VudCArIDEKICBwYXN0ZTAoIkZpZ3VyZSAiLCBmaWdfY291bnQsICI6ICIsIGNhcHRpb24pCn0KIyBEZWZpbmUgdGhlIGZ1bmN0aW9uIHRvIHRydW5jYXRlIGEgbnVtYmVyIHRvIHR3byBkZWNpbWFsIHBsYWNlcwp0cnVuY2F0ZV90b190d28gPC0gZnVuY3Rpb24oeCkgewogIHRydW5jYXRlZCA8LSBmbG9vcih4ICogMTAwKSAvIDEwMAogIHNwcmludGYoIiUuMmYiLCB0cnVuY2F0ZWQpCn0KYGBgCgojIEltcG9ydCBsaWJyYXJpZXMKCmBgYHtyLCBldmFsID0gVFJVRX0KbGlicmFyeShNZXRyaWNHcmFwaCkKbGlicmFyeShNYXRyaXgpCmxpYnJhcnkoclNQREUpCgpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShwbG90bHkpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShsYXRleDJleHApCmxpYnJhcnkoZ2d0ZXh0KQoKbGlicmFyeShncmF0ZWZ1bCkgIyBDaXRlIGFsbCBsb2FkZWQgcGFja2FnZXMKbGlicmFyeShoZXJlKSAjIGhlcmU6OmhlcmUoKSBzdGFydHMgZnJvbSB0aGUgaG9tZSBkaXJlY3RvcnkKCmxpYnJhcnkoc2xhY2tyKQpzb3VyY2UoImtleXMuUiIpCnNsYWNrcl9zZXR1cCh0b2tlbiA9IHRva2VuKSAjIHRva2VuIGNvbWVzIGZyb20ga2V5cy5SCmBgYAoKCmBgYHtyfQpjYXB0dXJlLm91dHB1dCgKICBrbml0cjo6cHVybChoZXJlOjpoZXJlKCJmdW5jdGlvbmFsaXR5MS5SbWQiKSwgb3V0cHV0ID0gaGVyZTo6aGVyZSgiZnVuY3Rpb25hbGl0eTEuUiIpKSwKICBmaWxlID0gaGVyZTo6aGVyZSgib2xkL3B1cmxfbG9nLnR4dCIpCikKc291cmNlKGhlcmU6OmhlcmUoImZ1bmN0aW9uYWxpdHkxLlIiKSkKYGBgCgoKIyBJbnRlcnZhbCBncmFwaAoKCjxkaXYgc3R5bGU9ImNvbG9yOiAjMmMzZTUwOyB0ZXh0LWFsaWduOiByaWdodDsiPgoqKioqKioqKiAgCjxzdHJvbmc+UHJlc3MgU2hvdyB0byByZXZlYWwgdGhlIGNvZGUgY2h1bmtzLjwvc3Ryb25nPiAgCgoqKioqKioqKgo8L2Rpdj4KCgoKYGBge3IsIGV2YWwgPSBGQUxTRX0KIyBsaWJyYXJ5IGNhbGxzCmxpYnJhcnkoTWV0cmljR3JhcGgpCmxpYnJhcnkoTWF0cml4KQpsaWJyYXJ5KHJTUERFKQoKIyBmdW5jdGlvbiAxCmdldHNfZ3JhcGhfaW50ZXJ2YWwgPC0gZnVuY3Rpb24obil7CiAgZWRnZSA8LSByYmluZChjKDAsMCksYygxLDApKQogIGVkZ2VzID0gbGlzdChlZGdlKQogIGdyYXBoIDwtIG1ldHJpY19ncmFwaCRuZXcoZWRnZXMgPSBlZGdlcykKICBncmFwaCRidWlsZF9tZXNoKG4gPSBuKQogIHJldHVybihncmFwaCkKfQoKIyBtYXRlcm4gY292YXJpYW5jZSBmdW5jdGlvbi4gU2FtZSBhcyBpbiB0aGUgcGFja2FnZQptYXRlcm4uY292YXJpYW5jZSA8LSBmdW5jdGlvbihoLCBrYXBwYSwgbnUsIHNpZ21hKSB7CiAgaWYgKG51ID09IDEgLyAyKSB7CiAgICBDIDwtIHNpZ21hXjIgKiBleHAoLWthcHBhICogYWJzKGgpKQogIH0gZWxzZSB7CiAgICBDIDwtIChzaWdtYV4yIC8gKDJeKG51IC0gMSkgKiBnYW1tYShudSkpKSAqCiAgICAgICgoa2FwcGEgKiBhYnMoaCkpXm51KSAqIGJlc3NlbEsoa2FwcGEgKiBhYnMoaCksIG51KQogIH0KICBDW2ggPT0gMF0gPC0gc2lnbWFeMgogIHJldHVybihhcy5tYXRyaXgoQykpCn0KCiMgZm9sZGVkLm1hdGVybi5jb3ZhcmlhbmNlLjFkIEkgZWRpdGVkCmZvbGRlZC5tYXRlcm4uY292YXJpYW5jZS4xZC5sb2NhbCA8LSBmdW5jdGlvbih4LCBrYXBwYSwgbnUsIHNpZ21hLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTCA9IDEsIE4gPSAxMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvdW5kYXJ5ID0gYygibmV1bWFubiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImRpcmljaGxldCIsICJwZXJpb2RpYyIpKSB7CiAgYm91bmRhcnkgPC0gdG9sb3dlcihib3VuZGFyeVsxXSkKICBpZiAoIShib3VuZGFyeSAlaW4lIGMoIm5ldW1hbm4iLCAiZGlyaWNobGV0IiwgInBlcmlvZGljIikpKSB7CiAgICBzdG9wKCJUaGUgcG9zc2libGUgYm91bmRhcnkgY29uZGl0aW9ucyBhcmUgJ25ldW1hbm4nLAogICAgJ2RpcmljaGxldCcgb3IgJ3BlcmlvZGljJyEiKQogIH0KICBhZGRpID0gdChvdXRlcih4LCB4LCAiKyIpKQogIGRpZmYgPSB0KG91dGVyKHgsIHgsICItIikpCiAgczEgPC0gc2FwcGx5KC1OOk4sIGZ1bmN0aW9uKGopIHsgCiAgICBkaWZmICsgMiAqIGogKiBMCiAgfSkKICBzMiA8LSBzYXBwbHkoLU46TiwgZnVuY3Rpb24oaikgewogICAgYWRkaSArIDIgKiBqICogTAogIH0pCiAgaWYgKGJvdW5kYXJ5ID09ICJuZXVtYW5uIikgewogICAgQyA8LSByb3dTdW1zKG1hdGVybi5jb3ZhcmlhbmNlKGggPSBzMSwga2FwcGEgPSBrYXBwYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBudSA9IG51LCBzaWdtYSA9IHNpZ21hKSArCiAgICAgICAgICAgICAgICAgICBtYXRlcm4uY292YXJpYW5jZShoID0gczIsIGthcHBhID0ga2FwcGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBudSA9IG51LCBzaWdtYSA9IHNpZ21hKSkKICB9IGVsc2UgaWYgKGJvdW5kYXJ5ID09ICJkaXJpY2hsZXQiKSB7CiAgICBDIDwtIHJvd1N1bXMobWF0ZXJuLmNvdmFyaWFuY2UoaCA9IHMxLCBrYXBwYSA9IGthcHBhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51ID0gbnUsIHNpZ21hID0gc2lnbWEpIC0KICAgICAgICAgICAgICAgICAgIG1hdGVybi5jb3ZhcmlhbmNlKGggPSBzMiwga2FwcGEgPSBrYXBwYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51ID0gbnUsIHNpZ21hID0gc2lnbWEpKQogIH0gZWxzZSB7CiAgICBDIDwtIHJvd1N1bXMobWF0ZXJuLmNvdmFyaWFuY2UoaCA9IHMxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGthcHBhID0ga2FwcGEsIG51ID0gbnUsIHNpZ21hID0gc2lnbWEpKQogIH0KICByZXR1cm4obWF0cml4KEMsIG5yb3cgPSBsZW5ndGgoeCkpKQp9CgojIGZ1bmN0aW9uIDIKZ2V0c190cnVlX2Nvdl9tYXQgPSBmdW5jdGlvbihncmFwaCwga2FwcGEsIG51LCBzaWdtYSwgTiwgYm91bmRhcnkpewogIGggPSBncmFwaCRtZXNoJFZbLDFdIAogIHRydWVfY292X21hdCA9IGZvbGRlZC5tYXRlcm4uY292YXJpYW5jZS4xZC5sb2NhbCh4ID0gaCwga2FwcGEgPSBrYXBwYSwgbnUgPSBudSwgc2lnbWEgPSBzaWdtYSwgTiA9IE4sIGJvdW5kYXJ5ID0gYm91bmRhcnkpCiAgcmV0dXJuKHRydWVfY292X21hdCkKfQoKCiMgcGFyYW1ldGVycwpuX3ZlY3RvciA9IGMoOTk4LCAxOTgsIDk4LCA4KQp0eXBlX3ZlY3RvciA9IGMoImNvdmFyaWFuY2UiLCAib3BlcmF0b3IiKQp0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yID0gYygiY2hlYmZ1biIsICJicmFzaWwiLCAiY2hlYmZ1bkxCIikKcmhvX3ZlY3RvciA9IGMoMC4xLCAwLjUsIDEsIDIpCm1fdmVjdG9yID0gYygwLDEsMiwzLDQsNSkKbnVfdmVjdG9yID0gYyhzZXEoMC4xLDAuNCxieT0wLjA1KSwgc2VxKDAuNDEsMC41OSxieT0wLjAxKSwgc2VxKDAuNiwxLjQsYnk9MC4wNSksIHNlcSgxLjQxLDEuNTksYnk9MC4wMSksIHNlcSgxLjYsMi40LGJ5PTAuMDUpLCBzZXEoMi40MSwyLjQ5LGJ5PTAuMDEpKQpib3VuZGFyeSA9ICJuZXVtYW5uIgpzaWdtYSA9IDEKTi5mb2xkZWQgPSAxMAoKRXJyb3IgPSBsaXN0KCkKZm9yIChzIGluIGMoMSwyLDMsNCkpIHsgIyBsb29wIG92ZXIgbl92ZWN0b3IKICBFcnJvcltbYXMuY2hhcmFjdGVyKG5fdmVjdG9yW3NdKV1dID0gbGlzdCgpCiAgbiA9IG5fdmVjdG9yW3NdCiAgZ3JhcGggPSBnZXRzX2dyYXBoX2ludGVydmFsKG4gPSBuKQogIGZvciAoaSBpbiBjKDEpKSB7ICMgbG9vcCBvdmVyIHR5cGVfdmVjdG9yCiAgICBFcnJvcltbYXMuY2hhcmFjdGVyKG5fdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dID0gbGlzdCgpCiAgICB0eXBlID0gdHlwZV92ZWN0b3JbaV0KICAgIGZvciAoaiBpbiBjKDEsMiwzKSkgeyAjIGxvb3Agb3ZlciB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yCiAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIobl92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXSA9IGxpc3QoKQogICAgICB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24gPSB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdCiAgICAgIGZvciAoayBpbiBjKDEsMiwzLDQpKSB7ICMgbG9vcCBvdmVyIHJob192ZWN0b3IKICAgICAgICBFcnJvcltbYXMuY2hhcmFjdGVyKG5fdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dW1t0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdXV1bW2FzLmNoYXJhY3RlcihyaG9fdmVjdG9yW2tdKV1dID0gbGlzdCgpCiAgICAgICAgcmhvID0gcmhvX3ZlY3RvcltrXQogICAgICAgIGZvciAobCBpbiAxOmxlbmd0aChtX3ZlY3RvcikpIHsgIyBsb29wIG92ZXIgbV92ZWN0b3IKICAgICAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIobl92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXSA9IG1hdHJpeChOQSwgbnJvdyA9IGxlbmd0aChudV92ZWN0b3IpLCBuY29sID0gMikKICAgICAgICAgIGNvbG5hbWVzKEVycm9yW1thcy5jaGFyYWN0ZXIobl92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXSkgPSBjKCJMX2luZl9lcnJvciIsICJMXzJfZXJyb3IiKQogICAgICAgICAgbSA9IG1fdmVjdG9yW2xdCiAgICAgICAgICBmb3IgKHIgaW4gMTpsZW5ndGgobnVfdmVjdG9yKSkgeyAjIGxvb3Agb3ZlciBudV92ZWN0b3IKICAgICAgICAgICAgbnUgPSBudV92ZWN0b3Jbcl0KICAgICAgICAgICAgCiAgICAgICAgICAgIGthcHBhID0gc3FydCg4Km51KS9yaG8KICAgICAgICAgICAgdGF1ID0gc3FydChnYW1tYShudSkgLyAoc2lnbWFeMiAqIGthcHBhXigyKm51KSAqICg0KnBpKV4oMS8yKSAqIGdhbW1hKG51ICsgMS8yKSkpICAjc2lnbWEgPSAxLCBkID0gMQogICAgICAgICAgICBhbHBoYSA9IG51ICsgMS8yCiAgICAgICAgICAgIAogICAgICAgICAgICB0cnlDYXRjaCh7CiAgICAgICAgICAgICAgIyBnZXR0aW5nIHRydWUgY292YXJpYW5jZQogICAgICAgICAgICAgIHRydWVfY292X21hdCA9IGdldHNfdHJ1ZV9jb3ZfbWF0KGdyYXBoID0gZ3JhcGgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2FwcGEgPSBrYXBwYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBudSA9IG51LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZ21hID0gc2lnbWEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTiA9IE4uZm9sZGVkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvdW5kYXJ5ID0gYm91bmRhcnkpCiAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgIyBnZXR0aW5nIHRoZSBhcHByb3hpbWF0ZSBjb3ZhcmlhbmNlIG1hdHJpeAogICAgICAgICAgICAgIG9wID0gbWF0ZXJuLm9wZXJhdG9ycyhhbHBoYSA9IGFscGhhLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2FwcGEgPSBrYXBwYSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhdSA9IHRhdSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbSA9IG0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmFwaCA9IGdyYXBoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gdHlwZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uID0gdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uKQogICAgICAgICAgICAgIAogICAgICAgICAgICAgIGFwcHJfY292X21hdCA9IG9wJGNvdmFyaWFuY2VfbWVzaCgpCiAgICAgICAgICAgIAogICAgICAgICAgICAjIGNvbXB1dGluZyB0aGUgZXJyb3JzCiAgICAgICAgICAgIExfaW5mX2Vycm9yID0gbWF4KGFicyh0cnVlX2Nvdl9tYXQgLSBhcHByX2Nvdl9tYXQpKQogICAgICAgICAgICBMXzJfZXJyb3IgPSBzcXJ0KGFzLmRvdWJsZSh0KGdyYXBoJG1lc2gkd2VpZ2h0cyklKiUodHJ1ZV9jb3ZfbWF0IC0gYXBwcl9jb3ZfbWF0KV4yJSolZ3JhcGgkbWVzaCR3ZWlnaHRzKSkKICAgICAgICAgICAgCiAgICAgICAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIobl92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXVtyLDFdID0gTF9pbmZfZXJyb3IKICAgICAgICAgICAgRXJyb3JbW2FzLmNoYXJhY3RlcihuX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dW1thcy5jaGFyYWN0ZXIocmhvX3ZlY3RvcltrXSldXVtbYXMuY2hhcmFjdGVyKG1fdmVjdG9yW2xdKV1dW3IsMl0gPSBMXzJfZXJyb3IKICAgICAgICAgICAgfSwgZXJyb3IgPSBmdW5jdGlvbihlcnIpewogICAgICAgICAgICAgIHdhcm5pbmcocGFzdGUoIkVycm9yIG9jY3VycmVkIGF0IGl0ZXJhdGlvbiBuPSIsIG4sICIsdHlwZT0iLCB0eXBlLCAiLHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbj0iLCB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24sICIscmhvPSIsIHJobywgIixtPSIsIG0sICIsbnU9IiwgbnUsICJFcnJvcjoiLCBjb25kaXRpb25NZXNzYWdlKGVycikpKQogICAgICAgICAgICAgIHByaW50KHBhc3RlKCJFcnJvciBvY2N1cnJlZCBhdCBpdGVyYXRpb24gbj0iLCBuLCAiLHR5cGU9IiwgdHlwZSwgIix0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb249IiwgdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uLCAiLHJobz0iLCByaG8sICIsbT0iLCBtLCAiLG51PSIsIG51LCAiRXJyb3I6IiwgY29uZGl0aW9uTWVzc2FnZShlcnIpKSkKICAgICAgICAgICAgICBFcnJvcltbYXMuY2hhcmFjdGVyKG5fdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dW1t0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdXV1bW2FzLmNoYXJhY3RlcihyaG9fdmVjdG9yW2tdKV1dW1thcy5jaGFyYWN0ZXIobV92ZWN0b3JbbF0pXV1bciwxXSA9IE5BCiAgICAgICAgICAgICAgRXJyb3JbW2FzLmNoYXJhY3RlcihuX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dW1thcy5jaGFyYWN0ZXIocmhvX3ZlY3RvcltrXSldXVtbYXMuY2hhcmFjdGVyKG1fdmVjdG9yW2xdKV1dW3IsMl0gPSBOQQogICAgICAgICAgICB9KQogICAgICAgICAgICBwcmludChwYXN0ZSgibj0iLCBuLCAiLHR5cGU9IiwgdHlwZSwgIix0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb249IiwgdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uLCAiLHJobz0iLCByaG8sICIsbT0iLCBtLCAiLG51PSIsIG51KSkKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgIH0KICB9Cn0KCkVycm9yX2ludGVydmFsX0RFRiA9IEVycm9yCnNhdmUoRXJyb3JfaW50ZXJ2YWxfREVGLCBmaWxlID0gaGVyZTo6aGVyZSgiZGF0YV9maWxlcy9FcnJvcl9pbnRlcnZhbF9ERUYuUkRhdGEiKSkKYGBgCgojIyBQbG90dGluZyB0aGUgZXJyb3JzCgpgYGB7cn0KbG9hZChoZXJlOjpoZXJlKCJkYXRhX2ZpbGVzL0Vycm9yX2ludGVydmFsX0RFRi5SRGF0YSIpKQoKbl92ZWN0b3IgPSBjKCI5OTgiLCAiMTk4IiwgIjk4IiwgIjgiKSAKdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvciA9IGMoImNoZWJmdW4iLCAiYnJhc2lsIiwgImNoZWJmdW5MQiIpCm51X21heCA9IDUzCm51X3ZlY3RvciA9IDAuNSArIGMoc2VxKDAuMSwwLjQsYnk9MC4wNSksIHNlcSgwLjQxLDAuNTksYnk9MC4wMSksIHNlcSgwLjYsMS40LGJ5PTAuMDUpLCBzZXEoMS40MSwxLjU5LGJ5PTAuMDEpLCBzZXEoMS42LDIuNCxieT0wLjA1KSwgc2VxKDIuNDEsMi40OSxieT0wLjAxKSlbMTpudV9tYXhdCgpuID0gIjk5OCIKdCA9ICJjaGViZnVuIgoKCmRhdCA9IHJiaW5kKApkYXRhLmZyYW1lKG51ID0gcmVwKG51X3ZlY3Rvciw1KSwgCiAgICAgICAgICAgcmhvID0gcmVwKDAuMSwgdGltZXMgPSA1Km51X21heCksCiAgICAgICAgICAgbSA9IHJlcCgxOjUsIGVhY2ggPSBudV9tYXgpLAogICAgICAgICAgIGVycm9yID0gYyhFcnJvcl9pbnRlcnZhbF9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuMSJdXVtbIjEiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC4xIl1dW1siMiJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjEiXV1bWyIzIl1dWzE6bnVfbWF4LDFdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9pbnRlcnZhbF9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuMSJdXVtbIjQiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC4xIl1dW1siNSJdXVsxOm51X21heCwxXSksCiAgICAgICAgICAgTCA9IHJlcCgiTGluZiIsIHRpbWVzID0gNSpudV9tYXgpCiksCgpkYXRhLmZyYW1lKG51ID0gcmVwKG51X3ZlY3Rvciw1KSwgCiAgICAgICAgICAgcmhvID0gYyhyZXAoMC41LCB0aW1lcyA9IDUqbnVfbWF4KSksCiAgICAgICAgICAgbSA9IHJlcCgxOjUsIGVhY2ggPSBudV9tYXgpLAogICAgICAgICAgIGVycm9yID0gYyhFcnJvcl9pbnRlcnZhbF9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuNSJdXVtbIjEiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC41Il1dW1siMiJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjUiXV1bWyIzIl1dWzE6bnVfbWF4LDFdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9pbnRlcnZhbF9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuNSJdXVtbIjQiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC41Il1dW1siNSJdXVsxOm51X21heCwxXSksCiAgICAgICAgICAgTCA9IHJlcCgiTGluZiIsIHRpbWVzID0gNSpudV9tYXgpCiksCgpkYXRhLmZyYW1lKG51ID0gcmVwKG51X3ZlY3Rvciw1KSwgCiAgICAgICAgICAgcmhvID0gYyhyZXAoMSwgdGltZXMgPSA1Km51X21heCkpLAogICAgICAgICAgIG0gPSByZXAoMTo1LCBlYWNoID0gbnVfbWF4KSwKICAgICAgICAgICBlcnJvciA9IGMoRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIxIl1dW1siMSJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIxIl1dW1siMiJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIxIl1dW1siMyJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIxIl1dW1siNCJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIxIl1dW1siNSJdXVsxOm51X21heCwxXSksCiAgICAgICAgICAgTCA9IHJlcCgiTGluZiIsIHRpbWVzID0gNSpudV9tYXgpCiksCgpkYXRhLmZyYW1lKG51ID0gcmVwKG51X3ZlY3Rvciw1KSwgCiAgICAgICAgICAgcmhvID0gYyhyZXAoMiwgdGltZXMgPSA1Km51X21heCkpLAogICAgICAgICAgIG0gPSByZXAoMTo1LCBlYWNoID0gbnVfbWF4KSwKICAgICAgICAgICBlcnJvciA9IGMoRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIyIl1dW1siMSJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIyIl1dW1siMiJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIyIl1dW1siMyJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIyIl1dW1siNCJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIyIl1dW1siNSJdXVsxOm51X21heCwxXSksCiAgICAgICAgICAgTCA9IHJlcCgiTGluZiIsIHRpbWVzID0gNSpudV9tYXgpCiksCgojIyBMMgoKZGF0YS5mcmFtZShudSA9IHJlcChudV92ZWN0b3IsNSksIAogICAgICAgICAgIHJobyA9IHJlcCgwLjEsIHRpbWVzID0gNSpudV9tYXgpLAogICAgICAgICAgIG0gPSByZXAoMTo1LCBlYWNoID0gbnVfbWF4KSwKICAgICAgICAgICBlcnJvciA9IGMoRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjEiXV1bWyIxIl1dWzE6bnVfbWF4LDJdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9pbnRlcnZhbF9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuMSJdXVtbIjIiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC4xIl1dW1siMyJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjEiXV1bWyI0Il1dWzE6bnVfbWF4LDJdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9pbnRlcnZhbF9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuMSJdXVtbIjUiXV1bMTpudV9tYXgsMl0pLAogICAgICAgICAgIEwgPSByZXAoIkwyIiwgdGltZXMgPSA1Km51X21heCkKKSwKCmRhdGEuZnJhbWUobnUgPSByZXAobnVfdmVjdG9yLDUpLCAKICAgICAgICAgICByaG8gPSBjKHJlcCgwLjUsIHRpbWVzID0gNSpudV9tYXgpKSwKICAgICAgICAgICBtID0gcmVwKDE6NSwgZWFjaCA9IG51X21heCksCiAgICAgICAgICAgZXJyb3IgPSBjKEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC41Il1dW1siMSJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjUiXV1bWyIyIl1dWzE6bnVfbWF4LDJdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9pbnRlcnZhbF9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuNSJdXVtbIjMiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC41Il1dW1siNCJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjUiXV1bWyI1Il1dWzE6bnVfbWF4LDJdKSwKICAgICAgICAgICBMID0gcmVwKCJMMiIsIHRpbWVzID0gNSpudV9tYXgpCiksCgpkYXRhLmZyYW1lKG51ID0gcmVwKG51X3ZlY3Rvciw1KSwgCiAgICAgICAgICAgcmhvID0gYyhyZXAoMSwgdGltZXMgPSA1Km51X21heCkpLAogICAgICAgICAgIG0gPSByZXAoMTo1LCBlYWNoID0gbnVfbWF4KSwKICAgICAgICAgICBlcnJvciA9IGMoRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIxIl1dW1siMSJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIxIl1dW1siMiJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIxIl1dW1siMyJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIxIl1dW1siNCJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfaW50ZXJ2YWxfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIxIl1dW1siNSJdXVsxOm51X21heCwyXSksCiAgICAgICAgICAgTCA9IHJlcCgiTDIiLCB0aW1lcyA9IDUqbnVfbWF4KQopLAoKZGF0YS5mcmFtZShudSA9IHJlcChudV92ZWN0b3IsNSksIAogICAgICAgICAgIHJobyA9IGMocmVwKDIsIHRpbWVzID0gNSpudV9tYXgpKSwKICAgICAgICAgICBtID0gcmVwKDE6NSwgZWFjaCA9IG51X21heCksCiAgICAgICAgICAgZXJyb3IgPSBjKEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMiJdXVtbIjEiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMiJdXVtbIjIiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMiJdXVtbIjMiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMiJdXVtbIjQiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2ludGVydmFsX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMiJdXVtbIjUiXV1bMTpudV9tYXgsMl0pLAogICAgICAgICAgIEwgPSByZXAoIkwyIiwgdGltZXMgPSA1Km51X21heCkKKQopCgoKZGF0JHJobyA9IGZhY3RvcihkYXQkcmhvLCBsZXZlbHMgPSBjKCIwLjEiLCAiMC41IiwgIjEiLCAiMiIpKQpkYXQkTCA9IGZhY3RvcihkYXQkTCwgbGV2ZWxzID0gYygiTDIiLCAiTGluZiIpKQpsZXZlbHMoZGF0JHJobykgPSBjKCIwLjEiID0gIiRcXHJobyA9IDAuMSQiLCAiMC41IiA9ICIkXFxyaG8gPSAwLjUkIiwgIjEiID0gIiRcXHJobyA9IDEkIiwgIjIiID0gIiRcXHJobyA9IDIkIikKbGV2ZWxzKGRhdCRMKSA9IGMoIkwyIiA9ICIkTF8yKFxcR2FtbWFcXHRpbWVzXFxHYW1tYSkkIiwgIkxpbmYiID0gIiRMX1xcaW5mdHkoXFxHYW1tYVxcdGltZXNcXEdhbW1hKSQiKQoKCnBfZXJyX2ludCA8LSBnZ3Bsb3QoZGF0LCBhZXMobnUsIGVycm9yLCBjb2xvdXIgPSBhcy5mYWN0b3IobSkpKSArIAogIGZhY2V0X2dyaWQoTCB+IHJobykgKwogIGdlb21fbGluZShzaXplID0gMS4zKSArCiAgc2NhbGVfeV9sb2cxMChuLmJyZWFrcyA9IDUpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobi5icmVha3MgPSAxMCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLnNwYWNpbmcgPSB1bml0KDAuMywgImNtIiksIAogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIlBhbGF0aW5vIiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE2KSwKICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksICAgICAgICAjIFBhbmVsIHRpdGxlcwogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwgICAgICAgICMgQXhpcyB0aXRsZXMKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwgICAgICAgICAjIEF4aXMgdGV4dAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLCAgICAgICMgTGVnZW5kIHRpdGxlCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkgKwogIGxhYnMoeCA9ICIkXFxhbHBoYVxcbWJveHsgfShcXG1ib3h7U21vb3RobmVzcyBwYXJhbWV0ZXJ9KSQiLCB5ID0gIiRcXG1ib3h7Q292YXJpYW5jZSBFcnJvcn0kIiwgY29sb3IgPSAiJG0kIikgKwogIGdndGl0bGUoIiRcXG1ib3h7SW50ZXJ2YWwgZ3JhcGh9JCIpIAoKbXlnZ3NhdmUocF9lcnJfaW50LCB3aWR0aCA9IDEyLCBoZWlnaHQgPSA2KQpgYGAKCgpgYGB7ciwgZXZhbCA9IFRSVUUsIG91dC53aWR0aD0iMTIwMHB4Iiwgb3V0LmhlaWdodD0iNjAwcHgiLCBmaWcuY2FwID0gY2FwdGlvbmVyKCJDb3ZhcmlhbmNlIGVycm9yIGZvciB0aGUgaW50ZXJ2YWwgZ3JhcGguIil9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImRhdGFfZmlsZXMvdGlrenBpYy9wX2Vycl9pbnQucGRmIikpCmBgYAoKCgojIENpcmNsZSBncmFwaAoKCjxkaXYgc3R5bGU9ImNvbG9yOiAjMmMzZTUwOyB0ZXh0LWFsaWduOiByaWdodDsiPgoqKioqKioqKiAgCjxzdHJvbmc+UHJlc3MgU2hvdyB0byByZXZlYWwgdGhlIGNvZGUgY2h1bmtzLjwvc3Ryb25nPiAgCgoqKioqKioqKgo8L2Rpdj4KCgoKYGBge3IsIGV2YWwgPSBGQUxTRX0KIyBsaWJyYXJ5IGNhbGxzCmxpYnJhcnkoTWV0cmljR3JhcGgpCmxpYnJhcnkoTWF0cml4KQpsaWJyYXJ5KHJTUERFKQoKIyBmdW5jdGlvbiAxCmdldHNfZ3JhcGhfY2lyY2xlIDwtIGZ1bmN0aW9uKG4pewogIHIgPSAxLyhwaSkKICB0aGV0YSA8LSBzZXEoZnJvbT0tcGksdG89cGksbGVuZ3RoLm91dCA9IDEwMDAwKQogIGVkZ2UgPC0gY2JpbmQoMStyK3IqY29zKHRoZXRhKSxyKnNpbih0aGV0YSkpCiAgZWRnZXMgPSBsaXN0KGVkZ2UpCiAgZ3JhcGggPC0gbWV0cmljX2dyYXBoJG5ldyhlZGdlcyA9IGVkZ2VzKQogIGdyYXBoJHNldF9tYW51YWxfZWRnZV9sZW5ndGhzKGVkZ2VfbGVuZ3RocyA9IDIpCiAgZ3JhcGgkYnVpbGRfbWVzaChuID0gbikKICByZXR1cm4oZ3JhcGgpCn0KCiMgbWF0ZXJuIGNvdmFyaWFuY2UgZnVuY3Rpb24uIFNhbWUgYXMgaW4gdGhlIHBhY2thZ2UKbWF0ZXJuLmNvdmFyaWFuY2UgPC0gZnVuY3Rpb24oaCwga2FwcGEsIG51LCBzaWdtYSkgewogIGlmIChudSA9PSAxIC8gMikgewogICAgQyA8LSBzaWdtYV4yICogZXhwKC1rYXBwYSAqIGFicyhoKSkKICB9IGVsc2UgewogICAgQyA8LSAoc2lnbWFeMiAvICgyXihudSAtIDEpICogZ2FtbWEobnUpKSkgKgogICAgICAoKGthcHBhICogYWJzKGgpKV5udSkgKiBiZXNzZWxLKGthcHBhICogYWJzKGgpLCBudSkKICB9CiAgQ1toID09IDBdIDwtIHNpZ21hXjIKICByZXR1cm4oYXMubWF0cml4KEMpKQp9CgojIGZvbGRlZC5tYXRlcm4uY292YXJpYW5jZS4xZCBJIGVkaXRlZApmb2xkZWQubWF0ZXJuLmNvdmFyaWFuY2UuMWQubG9jYWwgPC0gZnVuY3Rpb24oeCwga2FwcGEsIG51LCBzaWdtYSwgTCA9IDEsIE4gPSAxMCwgYm91bmRhcnkgPSBjKCJuZXVtYW5uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZGlyaWNobGV0IiwgInBlcmlvZGljIikpIHsKICBib3VuZGFyeSA8LSB0b2xvd2VyKGJvdW5kYXJ5WzFdKQogIGlmICghKGJvdW5kYXJ5ICVpbiUgYygibmV1bWFubiIsICJkaXJpY2hsZXQiLCAicGVyaW9kaWMiKSkpIHsKICAgIHN0b3AoIlRoZSBwb3NzaWJsZSBib3VuZGFyeSBjb25kaXRpb25zIGFyZSAnbmV1bWFubicsCiAgICAnZGlyaWNobGV0JyBvciAncGVyaW9kaWMnISIpCiAgfQogIGFkZGkgPSB0KG91dGVyKHgsIHgsICIrIikpCiAgZGlmZiA9IHQob3V0ZXIoeCwgeCwgIi0iKSkKICBzMSA8LSBzYXBwbHkoLU46TiwgZnVuY3Rpb24oaikgeyAjIHMxIGlzIGEgbWF0cml4IG9mIHNpemUgbGVuZ3RoKGgpeCgyTisxKQogICAgZGlmZiArIDIgKiBqICogTAogIH0pCiAgczIgPC0gc2FwcGx5KC1OOk4sIGZ1bmN0aW9uKGopIHsKICAgIGFkZGkgKyAyICogaiAqIEwKICB9KQogIGlmIChib3VuZGFyeSA9PSAibmV1bWFubiIpIHsKICAgIEMgPC0gcm93U3VtcyhtYXRlcm4uY292YXJpYW5jZShoID0gczEsIGthcHBhID0ga2FwcGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnUgPSBudSwgc2lnbWEgPSBzaWdtYSkgKwogICAgICAgICAgICAgICAgICAgbWF0ZXJuLmNvdmFyaWFuY2UoaCA9IHMyLCBrYXBwYSA9IGthcHBhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnUgPSBudSwgc2lnbWEgPSBzaWdtYSkpCiAgfSBlbHNlIGlmIChib3VuZGFyeSA9PSAiZGlyaWNobGV0IikgewogICAgQyA8LSByb3dTdW1zKG1hdGVybi5jb3ZhcmlhbmNlKGggPSBzMSwga2FwcGEgPSBrYXBwYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBudSA9IG51LCBzaWdtYSA9IHNpZ21hKSAtCiAgICAgICAgICAgICAgICAgICBtYXRlcm4uY292YXJpYW5jZShoID0gczIsIGthcHBhID0ga2FwcGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBudSA9IG51LCBzaWdtYSA9IHNpZ21hKSkKICB9IGVsc2UgewogICAgQyA8LSByb3dTdW1zKG1hdGVybi5jb3ZhcmlhbmNlKGggPSBzMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrYXBwYSA9IGthcHBhLCBudSA9IG51LCBzaWdtYSA9IHNpZ21hKSkKICB9CiAgcmV0dXJuKG1hdHJpeChDLCBucm93ID0gbGVuZ3RoKHgpKSkKfQoKIyBmdW5jdGlvbiAyCmdldHNfdHJ1ZV9jb3ZfbWF0ID0gZnVuY3Rpb24oZ3JhcGgsIGthcHBhLCBudSwgc2lnbWEsIE4sIGJvdW5kYXJ5KXsKICBoID0gYygwLGdyYXBoJGdldF9lZGdlX2xlbmd0aHMoKVsxXSpncmFwaCRtZXNoJFB0RVssMl0pCiAgdHJ1ZV9jb3ZfbWF0ID0gZm9sZGVkLm1hdGVybi5jb3ZhcmlhbmNlLjFkLmxvY2FsKHggPSBoLCBrYXBwYSA9IGthcHBhLCBudSA9IG51LCBzaWdtYSA9IHNpZ21hLCBOID0gTiwgYm91bmRhcnkgPSBib3VuZGFyeSkKICByZXR1cm4odHJ1ZV9jb3ZfbWF0KQp9CgoKIyBwYXJhbWV0ZXJzCm5fdmVjdG9yID0gMipjKDk5OCwgMTk4LCA5OCwgOCkKdHlwZV92ZWN0b3IgPSBjKCJjb3ZhcmlhbmNlIiwgIm9wZXJhdG9yIikKdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvciA9IGMoImNoZWJmdW4iLCAiYnJhc2lsIiwgImNoZWJmdW5MQiIpCnJob192ZWN0b3IgPSBjKDAuMSwgMC41LCAxLCAyKQptX3ZlY3RvciA9IGMoMCwxLDIsMyw0LDUpCm51X3ZlY3RvciA9IGMoc2VxKDAuMSwwLjQsYnk9MC4wNSksIHNlcSgwLjQxLDAuNTksYnk9MC4wMSksIHNlcSgwLjYsMS40LGJ5PTAuMDUpLCBzZXEoMS40MSwxLjU5LGJ5PTAuMDEpLCBzZXEoMS42LDIuNCxieT0wLjA1KSwgc2VxKDIuNDEsMi40OSxieT0wLjAxKSkKYm91bmRhcnkgPSAicGVyaW9kaWMiCnNpZ21hID0gMQpOLmZvbGRlZCA9IDEwCgpFcnJvciA9IGxpc3QoKQpmb3IgKHMgaW4gYygxLDIsMyw0KSkgeyAjIGxvb3Agb3ZlciBuX3ZlY3RvcgogIEVycm9yW1thcy5jaGFyYWN0ZXIobl92ZWN0b3Jbc10pXV0gPSBsaXN0KCkKICBuID0gbl92ZWN0b3Jbc10KICBncmFwaCA9IGdldHNfZ3JhcGhfY2lyY2xlKG4gPSBuKQogIGZvciAoaSBpbiBjKDEpKSB7ICMgbG9vcCBvdmVyIHR5cGVfdmVjdG9yCiAgICBFcnJvcltbYXMuY2hhcmFjdGVyKG5fdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dID0gbGlzdCgpCiAgICB0eXBlID0gdHlwZV92ZWN0b3JbaV0KICAgIGZvciAoaiBpbiBjKDEsMiwzKSkgeyAjIGxvb3Agb3ZlciB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yCiAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIobl92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXSA9IGxpc3QoKQogICAgICB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24gPSB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdCiAgICAgIGZvciAoayBpbiBjKDEsMiwzLDQpKSB7ICMgbG9vcCBvdmVyIHJob192ZWN0b3IKICAgICAgICBFcnJvcltbYXMuY2hhcmFjdGVyKG5fdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dW1t0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdXV1bW2FzLmNoYXJhY3RlcihyaG9fdmVjdG9yW2tdKV1dID0gbGlzdCgpCiAgICAgICAgcmhvID0gcmhvX3ZlY3RvcltrXQogICAgICAgIGZvciAobCBpbiAxOmxlbmd0aChtX3ZlY3RvcikpIHsgIyBsb29wIG92ZXIgbV92ZWN0b3IKICAgICAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIobl92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXSA9IG1hdHJpeChOQSwgbnJvdyA9IGxlbmd0aChudV92ZWN0b3IpLCBuY29sID0gMikKICAgICAgICAgIGNvbG5hbWVzKEVycm9yW1thcy5jaGFyYWN0ZXIobl92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXSkgPSBjKCJMX2luZl9lcnJvciIsICJMXzJfZXJyb3IiKQogICAgICAgICAgbSA9IG1fdmVjdG9yW2xdCiAgICAgICAgICBmb3IgKHIgaW4gMTpsZW5ndGgobnVfdmVjdG9yKSkgeyAjIGxvb3Agb3ZlciBudV92ZWN0b3IKICAgICAgICAgICAgbnUgPSBudV92ZWN0b3Jbcl0KICAgICAgICAgICAgCiAgICAgICAgICAgIGthcHBhID0gc3FydCg4Km51KS9yaG8KICAgICAgICAgICAgdGF1ID0gc3FydChnYW1tYShudSkgLyAoc2lnbWFeMiAqIGthcHBhXigyKm51KSAqICg0KnBpKV4oMS8yKSAqIGdhbW1hKG51ICsgMS8yKSkpICAjc2lnbWEgPSAxLCBkID0gMQogICAgICAgICAgICBhbHBoYSA9IG51ICsgMS8yCiAgICAgICAgICAgIAogICAgICAgICAgICB0cnlDYXRjaCh7CiAgICAgICAgICAgICAgIyBnZXR0aW5nIHRydWUgY292YXJpYW5jZQogICAgICAgICAgICAgIHRydWVfY292X21hdCA9IGdldHNfdHJ1ZV9jb3ZfbWF0KGdyYXBoID0gZ3JhcGgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2FwcGEgPSBrYXBwYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBudSA9IG51LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpZ21hID0gc2lnbWEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTiA9IE4uZm9sZGVkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvdW5kYXJ5ID0gYm91bmRhcnkpCiAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgIyBnZXR0aW5nIHRoZSBhcHByb3hpbWF0ZSBjb3ZhcmlhbmNlIG1hdHJpeAogICAgICAgICAgICAgIG9wID0gbWF0ZXJuLm9wZXJhdG9ycyhhbHBoYSA9IGFscGhhLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2FwcGEgPSBrYXBwYSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhdSA9IHRhdSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbSA9IG0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmFwaCA9IGdyYXBoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gdHlwZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uID0gdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uKQogICAgICAgICAgICAgIAogICAgICAgICAgICAgIGFwcHJfY292X21hdCA9IG9wJGNvdmFyaWFuY2VfbWVzaCgpCiAgICAgICAgICAgIAogICAgICAgICAgICAjIGNvbXB1dGluZyB0aGUgZXJyb3JzCiAgICAgICAgICAgIExfaW5mX2Vycm9yID0gbWF4KGFicyh0cnVlX2Nvdl9tYXQgLSBhcHByX2Nvdl9tYXQpKQogICAgICAgICAgICBMXzJfZXJyb3IgPSBzcXJ0KGFzLmRvdWJsZSh0KGdyYXBoJG1lc2gkd2VpZ2h0cyklKiUodHJ1ZV9jb3ZfbWF0IC0gYXBwcl9jb3ZfbWF0KV4yJSolZ3JhcGgkbWVzaCR3ZWlnaHRzKSkKICAgICAgICAgICAgCiAgICAgICAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIobl92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXVtyLDFdID0gTF9pbmZfZXJyb3IKICAgICAgICAgICAgRXJyb3JbW2FzLmNoYXJhY3RlcihuX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dW1thcy5jaGFyYWN0ZXIocmhvX3ZlY3RvcltrXSldXVtbYXMuY2hhcmFjdGVyKG1fdmVjdG9yW2xdKV1dW3IsMl0gPSBMXzJfZXJyb3IKICAgICAgICAgICAgfSwgZXJyb3IgPSBmdW5jdGlvbihlcnIpewogICAgICAgICAgICAgIHdhcm5pbmcocGFzdGUoIkVycm9yIG9jY3VycmVkIGF0IGl0ZXJhdGlvbiBuPSIsIG4sICIsdHlwZT0iLCB0eXBlLCAiLHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbj0iLCB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24sICIscmhvPSIsIHJobywgIixtPSIsIG0sICIsbnU9IiwgbnUsICJFcnJvcjoiLCBjb25kaXRpb25NZXNzYWdlKGVycikpKQogICAgICAgICAgICAgIHByaW50KHBhc3RlKCJFcnJvciBvY2N1cnJlZCBhdCBpdGVyYXRpb24gbj0iLCBuLCAiLHR5cGU9IiwgdHlwZSwgIix0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb249IiwgdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uLCAiLHJobz0iLCByaG8sICIsbT0iLCBtLCAiLG51PSIsIG51LCAiRXJyb3I6IiwgY29uZGl0aW9uTWVzc2FnZShlcnIpKSkKICAgICAgICAgICAgICBFcnJvcltbYXMuY2hhcmFjdGVyKG5fdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dW1t0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdXV1bW2FzLmNoYXJhY3RlcihyaG9fdmVjdG9yW2tdKV1dW1thcy5jaGFyYWN0ZXIobV92ZWN0b3JbbF0pXV1bciwxXSA9IE5BCiAgICAgICAgICAgICAgRXJyb3JbW2FzLmNoYXJhY3RlcihuX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dW1thcy5jaGFyYWN0ZXIocmhvX3ZlY3RvcltrXSldXVtbYXMuY2hhcmFjdGVyKG1fdmVjdG9yW2xdKV1dW3IsMl0gPSBOQQogICAgICAgICAgICB9KQogICAgICAgICAgICBwcmludChwYXN0ZSgibj0iLCBuLCAiLHR5cGU9IiwgdHlwZSwgIix0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb249IiwgdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uLCAiLHJobz0iLCByaG8sICIsbT0iLCBtLCAiLG51PSIsIG51KSkKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgIH0KICB9Cn0KRXJyb3JfY2lyY2xlX0RFRiA9IEVycm9yCnNhdmUoRXJyb3JfY2lyY2xlX0RFRiwgZmlsZSA9IGhlcmU6OmhlcmUoImRhdGFfZmlsZXMvRXJyb3JfY2lyY2xlX0RFRi5SRGF0YSIpKQpgYGAKCgojIyBQbG90dGluZyB0aGUgZXJyb3JzCgpgYGB7cn0KbG9hZChoZXJlOjpoZXJlKCJkYXRhX2ZpbGVzL0Vycm9yX2NpcmNsZV9ERUYuUkRhdGEiKSkKCm5fdmVjdG9yID0gYygiMTk5NiIsICIzOTYiLCAiMTk2IiwgIjE2IikgCnR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3IgPSBjKCJjaGViZnVuIiwgImJyYXNpbCIsICJjaGViZnVuTEIiKQpudV9tYXggPSA1MwpudV92ZWN0b3IgPSAwLjUgKyBjKHNlcSgwLjEsMC40LGJ5PTAuMDUpLCBzZXEoMC40MSwwLjU5LGJ5PTAuMDEpLCBzZXEoMC42LDEuNCxieT0wLjA1KSwgc2VxKDEuNDEsMS41OSxieT0wLjAxKSwgc2VxKDEuNiwyLjQsYnk9MC4wNSksIHNlcSgyLjQxLDIuNDksYnk9MC4wMSkpWzE6bnVfbWF4XQoKbiA9ICIxOTk2Igp0ID0gImNoZWJmdW4iCiAgCgpkYXQgPSByYmluZCgKZGF0YS5mcmFtZShudSA9IHJlcChudV92ZWN0b3IsNSksIAogICAgICAgICAgIHJobyA9IHJlcCgwLjEsIHRpbWVzID0gNSpudV9tYXgpLAogICAgICAgICAgIG0gPSByZXAoMTo1LCBlYWNoID0gbnVfbWF4KSwKICAgICAgICAgICBlcnJvciA9IGMoRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC4xIl1dW1siMSJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC4xIl1dW1siMiJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC4xIl1dW1siMyJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC4xIl1dW1siNCJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC4xIl1dW1siNSJdXVsxOm51X21heCwxXSksCiAgICAgICAgICAgTCA9IHJlcCgiTGluZiIsIHRpbWVzID0gNSpudV9tYXgpCiksCgpkYXRhLmZyYW1lKG51ID0gcmVwKG51X3ZlY3Rvciw1KSwgCiAgICAgICAgICAgcmhvID0gYyhyZXAoMC41LCB0aW1lcyA9IDUqbnVfbWF4KSksCiAgICAgICAgICAgbSA9IHJlcCgxOjUsIGVhY2ggPSBudV9tYXgpLAogICAgICAgICAgIGVycm9yID0gYyhFcnJvcl9jaXJjbGVfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjUiXV1bWyIxIl1dWzE6bnVfbWF4LDFdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9jaXJjbGVfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjUiXV1bWyIyIl1dWzE6bnVfbWF4LDFdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9jaXJjbGVfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjUiXV1bWyIzIl1dWzE6bnVfbWF4LDFdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9jaXJjbGVfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjUiXV1bWyI0Il1dWzE6bnVfbWF4LDFdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9jaXJjbGVfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjUiXV1bWyI1Il1dWzE6bnVfbWF4LDFdKSwKICAgICAgICAgICBMID0gcmVwKCJMaW5mIiwgdGltZXMgPSA1Km51X21heCkKKSwKCmRhdGEuZnJhbWUobnUgPSByZXAobnVfdmVjdG9yLDUpLCAKICAgICAgICAgICByaG8gPSBjKHJlcCgxLCB0aW1lcyA9IDUqbnVfbWF4KSksCiAgICAgICAgICAgbSA9IHJlcCgxOjUsIGVhY2ggPSBudV9tYXgpLAogICAgICAgICAgIGVycm9yID0gYyhFcnJvcl9jaXJjbGVfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIxIl1dW1siMSJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMSJdXVtbIjIiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2NpcmNsZV9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjEiXV1bWyIzIl1dWzE6bnVfbWF4LDFdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9jaXJjbGVfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIxIl1dW1siNCJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMSJdXVtbIjUiXV1bMTpudV9tYXgsMV0pLAogICAgICAgICAgIEwgPSByZXAoIkxpbmYiLCB0aW1lcyA9IDUqbnVfbWF4KQopLAoKZGF0YS5mcmFtZShudSA9IHJlcChudV92ZWN0b3IsNSksIAogICAgICAgICAgIHJobyA9IGMocmVwKDIsIHRpbWVzID0gNSpudV9tYXgpKSwKICAgICAgICAgICBtID0gcmVwKDE6NSwgZWFjaCA9IG51X21heCksCiAgICAgICAgICAgZXJyb3IgPSBjKEVycm9yX2NpcmNsZV9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjIiXV1bWyIxIl1dWzE6bnVfbWF4LDFdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9jaXJjbGVfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIyIl1dW1siMiJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMiJdXVtbIjMiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2NpcmNsZV9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjIiXV1bWyI0Il1dWzE6bnVfbWF4LDFdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9jaXJjbGVfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIyIl1dW1siNSJdXVsxOm51X21heCwxXSksCiAgICAgICAgICAgTCA9IHJlcCgiTGluZiIsIHRpbWVzID0gNSpudV9tYXgpCiksCgojIyBMMgoKZGF0YS5mcmFtZShudSA9IHJlcChudV92ZWN0b3IsNSksIAogICAgICAgICAgIHJobyA9IHJlcCgwLjEsIHRpbWVzID0gNSpudV9tYXgpLAogICAgICAgICAgIG0gPSByZXAoMTo1LCBlYWNoID0gbnVfbWF4KSwKICAgICAgICAgICBlcnJvciA9IGMoRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC4xIl1dW1siMSJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC4xIl1dW1siMiJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC4xIl1dW1siMyJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC4xIl1dW1siNCJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC4xIl1dW1siNSJdXVsxOm51X21heCwyXSksCiAgICAgICAgICAgTCA9IHJlcCgiTDIiLCB0aW1lcyA9IDUqbnVfbWF4KQopLAoKZGF0YS5mcmFtZShudSA9IHJlcChudV92ZWN0b3IsNSksIAogICAgICAgICAgIHJobyA9IGMocmVwKDAuNSwgdGltZXMgPSA1Km51X21heCkpLAogICAgICAgICAgIG0gPSByZXAoMTo1LCBlYWNoID0gbnVfbWF4KSwKICAgICAgICAgICBlcnJvciA9IGMoRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC41Il1dW1siMSJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC41Il1dW1siMiJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC41Il1dW1siMyJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC41Il1dW1siNCJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC41Il1dW1siNSJdXVsxOm51X21heCwyXSksCiAgICAgICAgICAgTCA9IHJlcCgiTDIiLCB0aW1lcyA9IDUqbnVfbWF4KQopLAoKZGF0YS5mcmFtZShudSA9IHJlcChudV92ZWN0b3IsNSksIAogICAgICAgICAgIHJobyA9IGMocmVwKDEsIHRpbWVzID0gNSpudV9tYXgpKSwKICAgICAgICAgICBtID0gcmVwKDE6NSwgZWFjaCA9IG51X21heCksCiAgICAgICAgICAgZXJyb3IgPSBjKEVycm9yX2NpcmNsZV9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjEiXV1bWyIxIl1dWzE6bnVfbWF4LDJdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9jaXJjbGVfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIxIl1dW1siMiJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMSJdXVtbIjMiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2NpcmNsZV9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjEiXV1bWyI0Il1dWzE6bnVfbWF4LDJdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9jaXJjbGVfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIxIl1dW1siNSJdXVsxOm51X21heCwyXSksCiAgICAgICAgICAgTCA9IHJlcCgiTDIiLCB0aW1lcyA9IDUqbnVfbWF4KQopLAoKZGF0YS5mcmFtZShudSA9IHJlcChudV92ZWN0b3IsNSksIAogICAgICAgICAgIHJobyA9IGMocmVwKDIsIHRpbWVzID0gNSpudV9tYXgpKSwKICAgICAgICAgICBtID0gcmVwKDE6NSwgZWFjaCA9IG51X21heCksCiAgICAgICAgICAgZXJyb3IgPSBjKEVycm9yX2NpcmNsZV9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjIiXV1bWyIxIl1dWzE6bnVfbWF4LDJdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9jaXJjbGVfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIyIl1dW1siMiJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfY2lyY2xlX0RFRltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMiJdXVtbIjMiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX2NpcmNsZV9ERUZbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjIiXV1bWyI0Il1dWzE6bnVfbWF4LDJdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl9jaXJjbGVfREVGW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIyIl1dW1siNSJdXVsxOm51X21heCwyXSksCiAgICAgICAgICAgTCA9IHJlcCgiTDIiLCB0aW1lcyA9IDUqbnVfbWF4KQopCikKCmRhdCRyaG8gPSBmYWN0b3IoZGF0JHJobywgbGV2ZWxzID0gYygiMC4xIiwgIjAuNSIsICIxIiwgIjIiKSkKZGF0JEwgPSBmYWN0b3IoZGF0JEwsIGxldmVscyA9IGMoIkwyIiwgIkxpbmYiKSkKbGV2ZWxzKGRhdCRyaG8pID0gYygiMC4xIiA9ICIkXFxyaG8gPSAwLjEkIiwgIjAuNSIgPSAiJFxccmhvID0gMC41JCIsICIxIiA9ICIkXFxyaG8gPSAxJCIsICIyIiA9ICIkXFxyaG8gPSAyJCIpCmxldmVscyhkYXQkTCkgPSBjKCJMMiIgPSAiJExfMihcXEdhbW1hXFx0aW1lc1xcR2FtbWEpJCIsICJMaW5mIiA9ICIkTF9cXGluZnR5KFxcR2FtbWFcXHRpbWVzXFxHYW1tYSkkIikKCgpwX2Vycl9jaXIgPC0gZ2dwbG90KGRhdCwgYWVzKG51LCBlcnJvciwgY29sb3VyID0gYXMuZmFjdG9yKG0pKSkgKyAKICBmYWNldF9ncmlkKEwgfiByaG8pICsKICBnZW9tX2xpbmUoc2l6ZSA9IDEuMykgKwogIHNjYWxlX3lfbG9nMTAobi5icmVha3MgPSA1KSArCiAgc2NhbGVfeF9jb250aW51b3VzKG4uYnJlYWtzID0gMTApICsKICB0aGVtZV9idygpICsKICB0aGVtZShwYW5lbC5zcGFjaW5nID0gdW5pdCgwLjMsICJjbSIpLCAKICAgICAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJQYWxhdGlubyIpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxNiksCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLCAgICAgICAgIyBQYW5lbCB0aXRsZXMKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksICAgICAgICAjIEF4aXMgdGl0bGVzCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksICAgICAgICAgIyBBeGlzIHRleHQKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwgICAgICAjIExlZ2VuZCB0aXRsZQogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikpICsKICBsYWJzKHggPSAiJFxcYWxwaGFcXG1ib3h7IH0oXFxtYm94e1Ntb290aG5lc3MgcGFyYW1ldGVyfSkkIiwgeSA9ICIkXFxtYm94e0NvdmFyaWFuY2UgRXJyb3J9JCIsIGNvbG9yID0gIiRtJCIpICsKICBnZ3RpdGxlKCIkXFxtYm94e0NpcmNsZSBncmFwaH0kIikgCgpteWdnc2F2ZShwX2Vycl9jaXIsIHdpZHRoID0gMTIsIGhlaWdodCA9IDYpCmBgYAoKCmBgYHtyLCBldmFsID0gVFJVRSwgb3V0LndpZHRoPSIxMjAwcHgiLCBvdXQuaGVpZ2h0PSI2MDBweCIsIGZpZy5jYXAgPSBjYXB0aW9uZXIoIkNvdmFyaWFuY2UgZXJyb3IgZm9yIHRoZSBjaXJjbGUgZ3JhcGguIil9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImRhdGFfZmlsZXMvdGlrenBpYy9wX2Vycl9jaXIucGRmIikpCmBgYAoKCgoKCgoKCgoKCiMgVGFkcG9sZSBncmFwaAoKCgojIyBgcmhvID0gMC4xYAoKPGRpdiBzdHlsZT0iY29sb3I6ICMyYzNlNTA7IHRleHQtYWxpZ246IHJpZ2h0OyI+CioqKioqKioqICAKPHN0cm9uZz5QcmVzcyBTaG93IHRvIHJldmVhbCB0aGUgY29kZSBjaHVua3MuPC9zdHJvbmc+ICAKCioqKioqKioqCjwvZGl2PgoKCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQojIGxpYnJhcnkgY2FsbHMKbGlicmFyeShNZXRyaWNHcmFwaCkKbGlicmFyeShNYXRyaXgpCmxpYnJhcnkoclNQREUpCgojIGZ1bmN0aW9uIDEKdGFkcG9sZS5laWcgPC0gZnVuY3Rpb24oayxncmFwaCl7CiAgeDEgPC0gYygwLGdyYXBoJGdldF9lZGdlX2xlbmd0aHMoKVsxXSpncmFwaCRtZXNoJFB0RVtncmFwaCRtZXNoJFB0RVssMV09PTEsMl0pIAogIHgyIDwtIGMoMCxncmFwaCRnZXRfZWRnZV9sZW5ndGhzKClbMl0qZ3JhcGgkbWVzaCRQdEVbZ3JhcGgkbWVzaCRQdEVbLDFdPT0yLDJdKSAKICAKICBpZihrPT0wKXsgCiAgICBmLmUxIDwtIHJlcCgxLGxlbmd0aCh4MSkpIAogICAgZi5lMiA8LSByZXAoMSxsZW5ndGgoeDIpKSAKICAgIGYxID0gYyhmLmUxWzFdLGYuZTJbMV0sZi5lMVstMV0sIGYuZTJbLTFdKSAKICAgIGYgPSBsaXN0KHBoaT1mMS9zcXJ0KDMpKSAKICAgIAogIH0gZWxzZSB7CiAgICBmLmUxIDwtIC0yKnNpbihwaSprKjEvMikqY29zKHBpKmsqeDEvMikgCiAgICBmLmUyIDwtIHNpbihwaSprKngyLzIpICAgICAgICAgICAgICAgICAgCiAgICAKICAgIGYxID0gYyhmLmUxWzFdLGYuZTJbMV0sZi5lMVstMV0sIGYuZTJbLTFdKSAKICAgIAogICAgaWYoKGsgJSUgMik9PTEpeyAKICAgICAgZiA9IGxpc3QocGhpPWYxL3NxcnQoMykpIAogICAgfSBlbHNlIHsgCiAgICAgIGYuZTEgPC0gKC0xKV57ay8yfSpjb3MocGkqayp4MS8yKQogICAgICBmLmUyIDwtIGNvcyhwaSprKngyLzIpCiAgICAgIGYyID0gYyhmLmUxWzFdLGYuZTJbMV0sZi5lMVstMV0sZi5lMlstMV0pIAogICAgICBmIDwtIGxpc3QocGhpPWYxLHBzaT1mMi9zcXJ0KDMvMikpCiAgICB9CiAgfQogIAogIHJldHVybihmKQp9CgojIGZ1bmN0aW9uIDIKZ2V0c19ncmFwaCA8LSBmdW5jdGlvbihoKXsKICBlZGdlMSA8LSByYmluZChjKDAsMCksYygxLDApKQogIHRoZXRhIDwtIHNlcShmcm9tPS1waSx0bz1waSxsZW5ndGgub3V0ID0gMTAwMDApCiAgZWRnZTIgPC0gY2JpbmQoMSsxL3BpK2Nvcyh0aGV0YSkvcGksc2luKHRoZXRhKS9waSkKICBlZGdlcyA9IGxpc3QoZWRnZTEsIGVkZ2UyKQogIGdyYXBoIDwtIG1ldHJpY19ncmFwaCRuZXcoZWRnZXMgPSBlZGdlcykKICBncmFwaCRzZXRfbWFudWFsX2VkZ2VfbGVuZ3RocyhlZGdlX2xlbmd0aHMgPSBjKDEsMikpCiAgZ3JhcGgkYnVpbGRfbWVzaChoPWgpCiAgcmV0dXJuKGdyYXBoKQp9CgojZnVuY3Rpb24gMwpnZXRzX3RydWVfY292X21hdCA8LSBmdW5jdGlvbihncmFwaCwga2FwcGEsIHRhdSwgYWxwaGEsIG4ub3ZlcmtpbGwpewogIFNpZ21hLmtsIDwtIG1hdHJpeCgwLG5yb3cgPSBkaW0oZ3JhcGgkbWVzaCRWKVsxXSxuY29sID0gZGltKGdyYXBoJG1lc2gkVilbMV0pCiAgZm9yKGkgaW4gMDpuLm92ZXJraWxsKXsKICAgIHBoaSA8LSB0YWRwb2xlLmVpZyhpLGdyYXBoKSRwaGkKICAgIFNpZ21hLmtsIDwtIFNpZ21hLmtsICsgKDEvKGthcHBhXjIgKyAoaSpwaS8yKV4yKV4oYWxwaGEpKSpwaGklKiV0KHBoaSkKICAgIGlmKGk+MCAmJiAoaSAlJSAyKT09MCl7IAogICAgICBwc2kgPC0gdGFkcG9sZS5laWcoaSxncmFwaCkkcHNpCiAgICAgIFNpZ21hLmtsIDwtIFNpZ21hLmtsICsgKDEvKGthcHBhXjIgKyAoaSpwaS8yKV4yKV4oYWxwaGEpKSpwc2klKiV0KHBzaSkKICAgIH0KICAgIAogIH0KICBTaWdtYS5rbCA8LSBTaWdtYS5rbC90YXVeMgogIHJldHVybihTaWdtYS5rbCkKfQoKIyBwYXJhbWV0ZXJzCmhfdmVjdG9yID0gYygwLjAwMSwgMC4wMDUsIDAuMDEsIDAuMSkKdHlwZV92ZWN0b3IgPSBjKCJjb3ZhcmlhbmNlIiwgIm9wZXJhdG9yIikKdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvciA9IGMoImNoZWJmdW4iLCAiYnJhc2lsIiwgImNoZWJmdW5MQiIpCnJob192ZWN0b3IgPSBjKDAuMSwgMC41LCAxLCAyKQptX3ZlY3RvciA9IGMoMCwxLDIsMyw0LDUpCm51X3ZlY3RvciA9IGMoc2VxKDAuMSwwLjQsYnk9MC4wNSksIHNlcSgwLjQxLDAuNTksYnk9MC4wMSksIHNlcSgwLjYsMS40LGJ5PTAuMDUpLCBzZXEoMS40MSwxLjU5LGJ5PTAuMDEpLCBzZXEoMS42LDIuNCxieT0wLjA1KSwgc2VxKDIuNDEsMi40OSxieT0wLjAxKSkKbi5vdmVya2lsbCA9IDEwMDAKc2lnbWEgPSAxCgpFcnJvciA9IGxpc3QoKQpmb3IgKHMgaW4gYygxLDIsMyw0KSkgeyAjIGxvb3Agb3ZlciBoX3ZlY3RvcgogIEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV0gPSBsaXN0KCkKICBoID0gaF92ZWN0b3Jbc10KICBncmFwaCA9IGdldHNfZ3JhcGgoaCA9IGgpCiAgZm9yIChpIGluIGMoMSkpIHsgIyBsb29wIG92ZXIgdHlwZV92ZWN0b3IKICAgIEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV0gPSBsaXN0KCkKICAgIHR5cGUgPSB0eXBlX3ZlY3RvcltpXQogICAgZm9yIChqIGluIGMoMSwyLDMpKSB7ICMgbG9vcCBvdmVyIHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3IKICAgICAgRXJyb3JbW2FzLmNoYXJhY3RlcihoX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dID0gbGlzdCgpCiAgICAgIHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbiA9IHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal0KICAgICAgZm9yIChrIGluIGMoMSkpIHsgIyBsb29wIG92ZXIgcmhvX3ZlY3RvcgogICAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV0gPSBsaXN0KCkKICAgICAgICByaG8gPSByaG9fdmVjdG9yW2tdCiAgICAgICAgZm9yIChsIGluIDE6bGVuZ3RoKG1fdmVjdG9yKSkgeyAjIGxvb3Agb3ZlciBtX3ZlY3RvcgogICAgICAgICAgRXJyb3JbW2FzLmNoYXJhY3RlcihoX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dW1thcy5jaGFyYWN0ZXIocmhvX3ZlY3RvcltrXSldXVtbYXMuY2hhcmFjdGVyKG1fdmVjdG9yW2xdKV1dID0gbWF0cml4KE5BLCBucm93ID0gbGVuZ3RoKG51X3ZlY3RvciksIG5jb2wgPSAyKQogICAgICAgICAgY29sbmFtZXMoRXJyb3JbW2FzLmNoYXJhY3RlcihoX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dW1thcy5jaGFyYWN0ZXIocmhvX3ZlY3RvcltrXSldXVtbYXMuY2hhcmFjdGVyKG1fdmVjdG9yW2xdKV1dKSA9IGMoIkxfaW5mX2Vycm9yIiwgIkxfMl9lcnJvciIpCiAgICAgICAgICBtID0gbV92ZWN0b3JbbF0KICAgICAgICAgIGZvciAobiBpbiAxOmxlbmd0aChudV92ZWN0b3IpKSB7ICMgbG9vcCBvdmVyIG51X3ZlY3RvcgogICAgICAgICAgICBudSA9IG51X3ZlY3RvcltuXQogICAgICAgICAgICAKICAgICAgICAgICAga2FwcGEgPSBzcXJ0KDgqbnUpL3JobwogICAgICAgICAgICB0YXUgPSBzcXJ0KGdhbW1hKG51KSAvIChzaWdtYV4yICoga2FwcGFeKDIqbnUpICogKDQqcGkpXigxLzIpICogZ2FtbWEobnUgKyAxLzIpKSkgICNzaWdtYSA9IDEsIGQgPSAxCiAgICAgICAgICAgIGFscGhhID0gbnUgKyAxLzIKICAgICAgICAgICAgCiAgICAgICAgICAgIHRyeUNhdGNoKHsKICAgICAgICAgICAgIyBnZXR0aW5nIHRydWUgY292YXJpYW5jZQogICAgICAgICAgICB0cnVlX2Nvdl9tYXQgPSBnZXRzX3RydWVfY292X21hdChncmFwaCA9IGdyYXBoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrYXBwYSA9IGthcHBhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXUgPSB0YXUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gYWxwaGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4ub3ZlcmtpbGwgPSBuLm92ZXJraWxsKQogICAgICAgICAgICAKICAgICAgICAgICAgIyBnZXR0aW5nIHRoZSBhcHByb3hpbWF0ZSBjb3ZhcmlhbmNlIG1hdHJpeAogICAgICAgICAgICBvcCA9IG1hdGVybi5vcGVyYXRvcnMoYWxwaGEgPSBhbHBoYSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrYXBwYSA9IGthcHBhLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhdSA9IHRhdSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG0gPSBtLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyYXBoID0gZ3JhcGgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gdHlwZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbiA9IHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbikKICAgICAgICAgICAgYXBwcl9jb3ZfbWF0ID0gb3AkY292YXJpYW5jZV9tZXNoKCkKICAgICAgICAgICAgCiAgICAgICAgICAgICMgY29tcHV0aW5nIHRoZSBlcnJvcnMKICAgICAgICAgICAgTF9pbmZfZXJyb3IgPSBtYXgoYWJzKHRydWVfY292X21hdCAtIGFwcHJfY292X21hdCkpCiAgICAgICAgICAgIExfMl9lcnJvciA9IHNxcnQoYXMuZG91YmxlKHQoZ3JhcGgkbWVzaCR3ZWlnaHRzKSUqJSh0cnVlX2Nvdl9tYXQgLSBhcHByX2Nvdl9tYXQpXjIlKiVncmFwaCRtZXNoJHdlaWdodHMpKQogICAgICAgICAgICAKICAgICAgICAgICAgRXJyb3JbW2FzLmNoYXJhY3RlcihoX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dW1thcy5jaGFyYWN0ZXIocmhvX3ZlY3RvcltrXSldXVtbYXMuY2hhcmFjdGVyKG1fdmVjdG9yW2xdKV1dW24sMV0gPSBMX2luZl9lcnJvcgogICAgICAgICAgICBFcnJvcltbYXMuY2hhcmFjdGVyKGhfdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dW1t0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdXV1bW2FzLmNoYXJhY3RlcihyaG9fdmVjdG9yW2tdKV1dW1thcy5jaGFyYWN0ZXIobV92ZWN0b3JbbF0pXV1bbiwyXSA9IExfMl9lcnJvcgogICAgICAgICAgICB9LCBlcnJvciA9IGZ1bmN0aW9uKGVycil7CiAgICAgICAgICAgICAgd2FybmluZyhwYXN0ZSgiRXJyb3Igb2NjdXJyZWQgYXQgaXRlcmF0aW9uIGg9IiwgaCwgIix0eXBlPSIsIHR5cGUsICIsdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uPSIsIHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbiwgIixyaG89IiwgcmhvLCAiLG09IiwgbSwgIixudT0iLCBudSwgIkVycm9yOiIsIGNvbmRpdGlvbk1lc3NhZ2UoZXJyKSkpCiAgICAgICAgICAgICAgcHJpbnQocGFzdGUoIkVycm9yIG9jY3VycmVkIGF0IGl0ZXJhdGlvbiBoPSIsIGgsICIsdHlwZT0iLCB0eXBlLCAiLHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbj0iLCB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24sICIscmhvPSIsIHJobywgIixtPSIsIG0sICIsbnU9IiwgbnUsICJFcnJvcjoiLCBjb25kaXRpb25NZXNzYWdlKGVycikpKQogICAgICAgICAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXVtuLDFdID0gTkEKICAgICAgICAgICAgICBFcnJvcltbYXMuY2hhcmFjdGVyKGhfdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dW1t0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdXV1bW2FzLmNoYXJhY3RlcihyaG9fdmVjdG9yW2tdKV1dW1thcy5jaGFyYWN0ZXIobV92ZWN0b3JbbF0pXV1bbiwyXSA9IE5BCiAgICAgICAgICAgIH0pCiAgICAgICAgICAgIHByaW50KHBhc3RlKCJoPSIsIGgsICIsdHlwZT0iLCB0eXBlLCAiLHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbj0iLCB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24sICIscmhvPSIsIHJobywgIixtPSIsIG0sICIsbnU9IiwgbnUpKQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgfQogIH0KfQoKRXJyb3JfdGFkcG9sZV9ERUZfcmhvMC4xID0gRXJyb3IKc2F2ZShFcnJvcl90YWRwb2xlX0RFRl9yaG8wLjEsIGZpbGUgPSBoZXJlOjpoZXJlKCJkYXRhX2ZpbGVzL0Vycm9yX3RhZHBvbGVfREVGX3JobzAuMS5SRGF0YSIpKQpgYGAKCgojIyBgcmhvID0gMC41YAoKCjxkaXYgc3R5bGU9ImNvbG9yOiAjMmMzZTUwOyB0ZXh0LWFsaWduOiByaWdodDsiPgoqKioqKioqKiAgCjxzdHJvbmc+UHJlc3MgU2hvdyB0byByZXZlYWwgdGhlIGNvZGUgY2h1bmtzLjwvc3Ryb25nPiAgCgoqKioqKioqKgo8L2Rpdj4KCgoKYGBge3IsIGV2YWwgPSBGQUxTRX0KIyBsaWJyYXJ5IGNhbGxzCmxpYnJhcnkoTWV0cmljR3JhcGgpCmxpYnJhcnkoTWF0cml4KQpsaWJyYXJ5KHJTUERFKQoKIyBmdW5jdGlvbiAxCnRhZHBvbGUuZWlnIDwtIGZ1bmN0aW9uKGssZ3JhcGgpewogIHgxIDwtIGMoMCxncmFwaCRnZXRfZWRnZV9sZW5ndGhzKClbMV0qZ3JhcGgkbWVzaCRQdEVbZ3JhcGgkbWVzaCRQdEVbLDFdPT0xLDJdKSAKICB4MiA8LSBjKDAsZ3JhcGgkZ2V0X2VkZ2VfbGVuZ3RocygpWzJdKmdyYXBoJG1lc2gkUHRFW2dyYXBoJG1lc2gkUHRFWywxXT09MiwyXSkgCiAgCiAgaWYoaz09MCl7IAogICAgZi5lMSA8LSByZXAoMSxsZW5ndGgoeDEpKSAKICAgIGYuZTIgPC0gcmVwKDEsbGVuZ3RoKHgyKSkgCiAgICBmMSA9IGMoZi5lMVsxXSxmLmUyWzFdLGYuZTFbLTFdLCBmLmUyWy0xXSkgCiAgICBmID0gbGlzdChwaGk9ZjEvc3FydCgzKSkgCiAgICAKICB9IGVsc2UgewogICAgZi5lMSA8LSAtMipzaW4ocGkqayoxLzIpKmNvcyhwaSprKngxLzIpIAogICAgZi5lMiA8LSBzaW4ocGkqayp4Mi8yKSAgICAgICAgICAgICAgICAgIAogICAgCiAgICBmMSA9IGMoZi5lMVsxXSxmLmUyWzFdLGYuZTFbLTFdLCBmLmUyWy0xXSkgCiAgICAKICAgIGlmKChrICUlIDIpPT0xKXsgCiAgICAgIGYgPSBsaXN0KHBoaT1mMS9zcXJ0KDMpKSAKICAgIH0gZWxzZSB7IAogICAgICBmLmUxIDwtICgtMSlee2svMn0qY29zKHBpKmsqeDEvMikKICAgICAgZi5lMiA8LSBjb3MocGkqayp4Mi8yKQogICAgICBmMiA9IGMoZi5lMVsxXSxmLmUyWzFdLGYuZTFbLTFdLGYuZTJbLTFdKSAKICAgICAgZiA8LSBsaXN0KHBoaT1mMSxwc2k9ZjIvc3FydCgzLzIpKQogICAgfQogIH0KICAKICByZXR1cm4oZikKfQoKIyBmdW5jdGlvbiAyCmdldHNfZ3JhcGggPC0gZnVuY3Rpb24oaCl7CiAgZWRnZTEgPC0gcmJpbmQoYygwLDApLGMoMSwwKSkKICB0aGV0YSA8LSBzZXEoZnJvbT0tcGksdG89cGksbGVuZ3RoLm91dCA9IDEwMDAwKQogIGVkZ2UyIDwtIGNiaW5kKDErMS9waStjb3ModGhldGEpL3BpLHNpbih0aGV0YSkvcGkpCiAgZWRnZXMgPSBsaXN0KGVkZ2UxLCBlZGdlMikKICBncmFwaCA8LSBtZXRyaWNfZ3JhcGgkbmV3KGVkZ2VzID0gZWRnZXMpCiAgZ3JhcGgkc2V0X21hbnVhbF9lZGdlX2xlbmd0aHMoZWRnZV9sZW5ndGhzID0gYygxLDIpKQogIGdyYXBoJGJ1aWxkX21lc2goaD1oKQogIHJldHVybihncmFwaCkKfQoKI2Z1bmN0aW9uIDMKZ2V0c190cnVlX2Nvdl9tYXQgPC0gZnVuY3Rpb24oZ3JhcGgsIGthcHBhLCB0YXUsIGFscGhhLCBuLm92ZXJraWxsKXsKICBTaWdtYS5rbCA8LSBtYXRyaXgoMCxucm93ID0gZGltKGdyYXBoJG1lc2gkVilbMV0sbmNvbCA9IGRpbShncmFwaCRtZXNoJFYpWzFdKQogIGZvcihpIGluIDA6bi5vdmVya2lsbCl7CiAgICBwaGkgPC0gdGFkcG9sZS5laWcoaSxncmFwaCkkcGhpCiAgICBTaWdtYS5rbCA8LSBTaWdtYS5rbCArICgxLyhrYXBwYV4yICsgKGkqcGkvMileMileKGFscGhhKSkqcGhpJSoldChwaGkpCiAgICBpZihpPjAgJiYgKGkgJSUgMik9PTApeyAKICAgICAgcHNpIDwtIHRhZHBvbGUuZWlnKGksZ3JhcGgpJHBzaQogICAgICBTaWdtYS5rbCA8LSBTaWdtYS5rbCArICgxLyhrYXBwYV4yICsgKGkqcGkvMileMileKGFscGhhKSkqcHNpJSoldChwc2kpCiAgICB9CiAgICAKICB9CiAgU2lnbWEua2wgPC0gU2lnbWEua2wvdGF1XjIKICByZXR1cm4oU2lnbWEua2wpCn0KCiMgcGFyYW1ldGVycwpoX3ZlY3RvciA9IGMoMC4wMDEsIDAuMDA1LCAwLjAxLCAwLjEpCnR5cGVfdmVjdG9yID0gYygiY292YXJpYW5jZSIsICJvcGVyYXRvciIpCnR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3IgPSBjKCJjaGViZnVuIiwgImJyYXNpbCIsICJjaGViZnVuTEIiKQpyaG9fdmVjdG9yID0gYygwLjEsIDAuNSwgMSwgMikKbV92ZWN0b3IgPSBjKDAsMSwyLDMsNCw1KQpudV92ZWN0b3IgPSBjKHNlcSgwLjEsMC40LGJ5PTAuMDUpLCBzZXEoMC40MSwwLjU5LGJ5PTAuMDEpLCBzZXEoMC42LDEuNCxieT0wLjA1KSwgc2VxKDEuNDEsMS41OSxieT0wLjAxKSwgc2VxKDEuNiwyLjQsYnk9MC4wNSksIHNlcSgyLjQxLDIuNDksYnk9MC4wMSkpCm4ub3ZlcmtpbGwgPSAxMDAwCnNpZ21hID0gMQoKRXJyb3IgPSBsaXN0KCkKZm9yIChzIGluIGMoMSwyLDMsNCkpIHsgIyBsb29wIG92ZXIgaF92ZWN0b3IKICBFcnJvcltbYXMuY2hhcmFjdGVyKGhfdmVjdG9yW3NdKV1dID0gbGlzdCgpCiAgaCA9IGhfdmVjdG9yW3NdCiAgZ3JhcGggPSBnZXRzX2dyYXBoKGggPSBoKQogIGZvciAoaSBpbiBjKDEpKSB7ICMgbG9vcCBvdmVyIHR5cGVfdmVjdG9yCiAgICBFcnJvcltbYXMuY2hhcmFjdGVyKGhfdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dID0gbGlzdCgpCiAgICB0eXBlID0gdHlwZV92ZWN0b3JbaV0KICAgIGZvciAoaiBpbiBjKDEsMiwzKSkgeyAjIGxvb3Agb3ZlciB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yCiAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXSA9IGxpc3QoKQogICAgICB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24gPSB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdCiAgICAgIGZvciAoayBpbiBjKDIpKSB7ICMgbG9vcCBvdmVyIHJob192ZWN0b3IKICAgICAgICBFcnJvcltbYXMuY2hhcmFjdGVyKGhfdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dW1t0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdXV1bW2FzLmNoYXJhY3RlcihyaG9fdmVjdG9yW2tdKV1dID0gbGlzdCgpCiAgICAgICAgcmhvID0gcmhvX3ZlY3RvcltrXQogICAgICAgIGZvciAobCBpbiAxOmxlbmd0aChtX3ZlY3RvcikpIHsgIyBsb29wIG92ZXIgbV92ZWN0b3IKICAgICAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXSA9IG1hdHJpeChOQSwgbnJvdyA9IGxlbmd0aChudV92ZWN0b3IpLCBuY29sID0gMikKICAgICAgICAgIGNvbG5hbWVzKEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXSkgPSBjKCJMX2luZl9lcnJvciIsICJMXzJfZXJyb3IiKQogICAgICAgICAgbSA9IG1fdmVjdG9yW2xdCiAgICAgICAgICBmb3IgKG4gaW4gMTpsZW5ndGgobnVfdmVjdG9yKSkgeyAjIGxvb3Agb3ZlciBudV92ZWN0b3IKICAgICAgICAgICAgbnUgPSBudV92ZWN0b3Jbbl0KICAgICAgICAgICAgCiAgICAgICAgICAgIGthcHBhID0gc3FydCg4Km51KS9yaG8KICAgICAgICAgICAgdGF1ID0gc3FydChnYW1tYShudSkgLyAoc2lnbWFeMiAqIGthcHBhXigyKm51KSAqICg0KnBpKV4oMS8yKSAqIGdhbW1hKG51ICsgMS8yKSkpICAjc2lnbWEgPSAxLCBkID0gMQogICAgICAgICAgICBhbHBoYSA9IG51ICsgMS8yCiAgICAgICAgICAgIAogICAgICAgICAgICB0cnlDYXRjaCh7CiAgICAgICAgICAgICMgZ2V0dGluZyB0cnVlIGNvdmFyaWFuY2UKICAgICAgICAgICAgdHJ1ZV9jb3ZfbWF0ID0gZ2V0c190cnVlX2Nvdl9tYXQoZ3JhcGggPSBncmFwaCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2FwcGEgPSBrYXBwYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGF1ID0gdGF1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IGFscGhhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLm92ZXJraWxsID0gbi5vdmVya2lsbCkKICAgICAgICAgICAgCiAgICAgICAgICAgICMgZ2V0dGluZyB0aGUgYXBwcm94aW1hdGUgY292YXJpYW5jZSBtYXRyaXgKICAgICAgICAgICAgb3AgPSBtYXRlcm4ub3BlcmF0b3JzKGFscGhhID0gYWxwaGEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2FwcGEgPSBrYXBwYSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXUgPSB0YXUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtID0gbSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmFwaCA9IGdyYXBoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9IHR5cGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24gPSB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24pCiAgICAgICAgICAgIGFwcHJfY292X21hdCA9IG9wJGNvdmFyaWFuY2VfbWVzaCgpCiAgICAgICAgICAgIAogICAgICAgICAgICAjIGNvbXB1dGluZyB0aGUgZXJyb3JzCiAgICAgICAgICAgIExfaW5mX2Vycm9yID0gbWF4KGFicyh0cnVlX2Nvdl9tYXQgLSBhcHByX2Nvdl9tYXQpKQogICAgICAgICAgICBMXzJfZXJyb3IgPSBzcXJ0KGFzLmRvdWJsZSh0KGdyYXBoJG1lc2gkd2VpZ2h0cyklKiUodHJ1ZV9jb3ZfbWF0IC0gYXBwcl9jb3ZfbWF0KV4yJSolZ3JhcGgkbWVzaCR3ZWlnaHRzKSkKICAgICAgICAgICAgCiAgICAgICAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXVtuLDFdID0gTF9pbmZfZXJyb3IKICAgICAgICAgICAgRXJyb3JbW2FzLmNoYXJhY3RlcihoX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dW1thcy5jaGFyYWN0ZXIocmhvX3ZlY3RvcltrXSldXVtbYXMuY2hhcmFjdGVyKG1fdmVjdG9yW2xdKV1dW24sMl0gPSBMXzJfZXJyb3IKICAgICAgICAgICAgfSwgZXJyb3IgPSBmdW5jdGlvbihlcnIpewogICAgICAgICAgICAgIHdhcm5pbmcocGFzdGUoIkVycm9yIG9jY3VycmVkIGF0IGl0ZXJhdGlvbiBoPSIsIGgsICIsdHlwZT0iLCB0eXBlLCAiLHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbj0iLCB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24sICIscmhvPSIsIHJobywgIixtPSIsIG0sICIsbnU9IiwgbnUsICJFcnJvcjoiLCBjb25kaXRpb25NZXNzYWdlKGVycikpKQogICAgICAgICAgICAgIHByaW50KHBhc3RlKCJFcnJvciBvY2N1cnJlZCBhdCBpdGVyYXRpb24gaD0iLCBoLCAiLHR5cGU9IiwgdHlwZSwgIix0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb249IiwgdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uLCAiLHJobz0iLCByaG8sICIsbT0iLCBtLCAiLG51PSIsIG51LCAiRXJyb3I6IiwgY29uZGl0aW9uTWVzc2FnZShlcnIpKSkKICAgICAgICAgICAgICBFcnJvcltbYXMuY2hhcmFjdGVyKGhfdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dW1t0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdXV1bW2FzLmNoYXJhY3RlcihyaG9fdmVjdG9yW2tdKV1dW1thcy5jaGFyYWN0ZXIobV92ZWN0b3JbbF0pXV1bbiwxXSA9IE5BCiAgICAgICAgICAgICAgRXJyb3JbW2FzLmNoYXJhY3RlcihoX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dW1thcy5jaGFyYWN0ZXIocmhvX3ZlY3RvcltrXSldXVtbYXMuY2hhcmFjdGVyKG1fdmVjdG9yW2xdKV1dW24sMl0gPSBOQQogICAgICAgICAgICB9KQogICAgICAgICAgICBwcmludChwYXN0ZSgiaD0iLCBoLCAiLHR5cGU9IiwgdHlwZSwgIix0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb249IiwgdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uLCAiLHJobz0iLCByaG8sICIsbT0iLCBtLCAiLG51PSIsIG51KSkKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgIH0KICB9Cn0KCkVycm9yX3RhZHBvbGVfREVGX3JobzAuNSA9IEVycm9yCnNhdmUoRXJyb3JfdGFkcG9sZV9ERUZfcmhvMC41LCBmaWxlID0gaGVyZTo6aGVyZSgiZGF0YV9maWxlcy9FcnJvcl90YWRwb2xlX0RFRl9yaG8wLjUuUkRhdGEiKSkKYGBgCgoKIyMgYHJobyA9IDFgCgoKPGRpdiBzdHlsZT0iY29sb3I6ICMyYzNlNTA7IHRleHQtYWxpZ246IHJpZ2h0OyI+CioqKioqKioqICAKPHN0cm9uZz5QcmVzcyBTaG93IHRvIHJldmVhbCB0aGUgY29kZSBjaHVua3MuPC9zdHJvbmc+ICAKCioqKioqKioqCjwvZGl2PgoKCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQojIGxpYnJhcnkgY2FsbHMKbGlicmFyeShNZXRyaWNHcmFwaCkKbGlicmFyeShNYXRyaXgpCmxpYnJhcnkoclNQREUpCgojIGZ1bmN0aW9uIDEKdGFkcG9sZS5laWcgPC0gZnVuY3Rpb24oayxncmFwaCl7CiAgeDEgPC0gYygwLGdyYXBoJGdldF9lZGdlX2xlbmd0aHMoKVsxXSpncmFwaCRtZXNoJFB0RVtncmFwaCRtZXNoJFB0RVssMV09PTEsMl0pIAogIHgyIDwtIGMoMCxncmFwaCRnZXRfZWRnZV9sZW5ndGhzKClbMl0qZ3JhcGgkbWVzaCRQdEVbZ3JhcGgkbWVzaCRQdEVbLDFdPT0yLDJdKSAKICAKICBpZihrPT0wKXsgCiAgICBmLmUxIDwtIHJlcCgxLGxlbmd0aCh4MSkpIAogICAgZi5lMiA8LSByZXAoMSxsZW5ndGgoeDIpKSAKICAgIGYxID0gYyhmLmUxWzFdLGYuZTJbMV0sZi5lMVstMV0sIGYuZTJbLTFdKSAKICAgIGYgPSBsaXN0KHBoaT1mMS9zcXJ0KDMpKSAKICAgIAogIH0gZWxzZSB7CiAgICBmLmUxIDwtIC0yKnNpbihwaSprKjEvMikqY29zKHBpKmsqeDEvMikgCiAgICBmLmUyIDwtIHNpbihwaSprKngyLzIpICAgICAgICAgICAgICAgICAgCiAgICAKICAgIGYxID0gYyhmLmUxWzFdLGYuZTJbMV0sZi5lMVstMV0sIGYuZTJbLTFdKSAKICAgIAogICAgaWYoKGsgJSUgMik9PTEpeyAKICAgICAgZiA9IGxpc3QocGhpPWYxL3NxcnQoMykpIAogICAgfSBlbHNlIHsgCiAgICAgIGYuZTEgPC0gKC0xKV57ay8yfSpjb3MocGkqayp4MS8yKQogICAgICBmLmUyIDwtIGNvcyhwaSprKngyLzIpCiAgICAgIGYyID0gYyhmLmUxWzFdLGYuZTJbMV0sZi5lMVstMV0sZi5lMlstMV0pIAogICAgICBmIDwtIGxpc3QocGhpPWYxLHBzaT1mMi9zcXJ0KDMvMikpCiAgICB9CiAgfQogIAogIHJldHVybihmKQp9CgojIGZ1bmN0aW9uIDIKZ2V0c19ncmFwaCA8LSBmdW5jdGlvbihoKXsKICBlZGdlMSA8LSByYmluZChjKDAsMCksYygxLDApKQogIHRoZXRhIDwtIHNlcShmcm9tPS1waSx0bz1waSxsZW5ndGgub3V0ID0gMTAwMDApCiAgZWRnZTIgPC0gY2JpbmQoMSsxL3BpK2Nvcyh0aGV0YSkvcGksc2luKHRoZXRhKS9waSkKICBlZGdlcyA9IGxpc3QoZWRnZTEsIGVkZ2UyKQogIGdyYXBoIDwtIG1ldHJpY19ncmFwaCRuZXcoZWRnZXMgPSBlZGdlcykKICBncmFwaCRzZXRfbWFudWFsX2VkZ2VfbGVuZ3RocyhlZGdlX2xlbmd0aHMgPSBjKDEsMikpCiAgZ3JhcGgkYnVpbGRfbWVzaChoPWgpCiAgcmV0dXJuKGdyYXBoKQp9CgojZnVuY3Rpb24gMwpnZXRzX3RydWVfY292X21hdCA8LSBmdW5jdGlvbihncmFwaCwga2FwcGEsIHRhdSwgYWxwaGEsIG4ub3ZlcmtpbGwpewogIFNpZ21hLmtsIDwtIG1hdHJpeCgwLG5yb3cgPSBkaW0oZ3JhcGgkbWVzaCRWKVsxXSxuY29sID0gZGltKGdyYXBoJG1lc2gkVilbMV0pCiAgZm9yKGkgaW4gMDpuLm92ZXJraWxsKXsKICAgIHBoaSA8LSB0YWRwb2xlLmVpZyhpLGdyYXBoKSRwaGkKICAgIFNpZ21hLmtsIDwtIFNpZ21hLmtsICsgKDEvKGthcHBhXjIgKyAoaSpwaS8yKV4yKV4oYWxwaGEpKSpwaGklKiV0KHBoaSkKICAgIGlmKGk+MCAmJiAoaSAlJSAyKT09MCl7IAogICAgICBwc2kgPC0gdGFkcG9sZS5laWcoaSxncmFwaCkkcHNpCiAgICAgIFNpZ21hLmtsIDwtIFNpZ21hLmtsICsgKDEvKGthcHBhXjIgKyAoaSpwaS8yKV4yKV4oYWxwaGEpKSpwc2klKiV0KHBzaSkKICAgIH0KICAgIAogIH0KICBTaWdtYS5rbCA8LSBTaWdtYS5rbC90YXVeMgogIHJldHVybihTaWdtYS5rbCkKfQoKIyBwYXJhbWV0ZXJzCmhfdmVjdG9yID0gYygwLjAwMSwgMC4wMDUsIDAuMDEsIDAuMSkKdHlwZV92ZWN0b3IgPSBjKCJjb3ZhcmlhbmNlIiwgIm9wZXJhdG9yIikKdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvciA9IGMoImNoZWJmdW4iLCAiYnJhc2lsIiwgImNoZWJmdW5MQiIpCnJob192ZWN0b3IgPSBjKDAuMSwgMC41LCAxLCAyKQptX3ZlY3RvciA9IGMoMCwxLDIsMyw0LDUpCm51X3ZlY3RvciA9IGMoc2VxKDAuMSwwLjQsYnk9MC4wNSksIHNlcSgwLjQxLDAuNTksYnk9MC4wMSksIHNlcSgwLjYsMS40LGJ5PTAuMDUpLCBzZXEoMS40MSwxLjU5LGJ5PTAuMDEpLCBzZXEoMS42LDIuNCxieT0wLjA1KSwgc2VxKDIuNDEsMi40OSxieT0wLjAxKSkgCm4ub3ZlcmtpbGwgPSAxMDAwCnNpZ21hID0gMQoKRXJyb3IgPSBsaXN0KCkKZm9yIChzIGluIGMoMSwyLDMsNCkpIHsgIyBsb29wIG92ZXIgaF92ZWN0b3IKICBFcnJvcltbYXMuY2hhcmFjdGVyKGhfdmVjdG9yW3NdKV1dID0gbGlzdCgpCiAgaCA9IGhfdmVjdG9yW3NdCiAgZ3JhcGggPSBnZXRzX2dyYXBoKGggPSBoKQogIGZvciAoaSBpbiBjKDEpKSB7ICMgbG9vcCBvdmVyIHR5cGVfdmVjdG9yCiAgICBFcnJvcltbYXMuY2hhcmFjdGVyKGhfdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dID0gbGlzdCgpCiAgICB0eXBlID0gdHlwZV92ZWN0b3JbaV0KICAgIGZvciAoaiBpbiBjKDEsMiwzKSkgeyAjIGxvb3Agb3ZlciB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yCiAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXSA9IGxpc3QoKQogICAgICB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24gPSB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdCiAgICAgIGZvciAoayBpbiBjKDMpKSB7ICMgbG9vcCBvdmVyIHJob192ZWN0b3IKICAgICAgICBFcnJvcltbYXMuY2hhcmFjdGVyKGhfdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dW1t0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdXV1bW2FzLmNoYXJhY3RlcihyaG9fdmVjdG9yW2tdKV1dID0gbGlzdCgpCiAgICAgICAgcmhvID0gcmhvX3ZlY3RvcltrXQogICAgICAgIGZvciAobCBpbiAxOmxlbmd0aChtX3ZlY3RvcikpIHsgIyBsb29wIG92ZXIgbV92ZWN0b3IKICAgICAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXSA9IG1hdHJpeChOQSwgbnJvdyA9IGxlbmd0aChudV92ZWN0b3IpLCBuY29sID0gMikKICAgICAgICAgIGNvbG5hbWVzKEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXSkgPSBjKCJMX2luZl9lcnJvciIsICJMXzJfZXJyb3IiKQogICAgICAgICAgbSA9IG1fdmVjdG9yW2xdCiAgICAgICAgICBmb3IgKG4gaW4gMTpsZW5ndGgobnVfdmVjdG9yKSkgeyAjIGxvb3Agb3ZlciBudV92ZWN0b3IKICAgICAgICAgICAgbnUgPSBudV92ZWN0b3Jbbl0KICAgICAgICAgICAgCiAgICAgICAgICAgIGthcHBhID0gc3FydCg4Km51KS9yaG8KICAgICAgICAgICAgdGF1ID0gc3FydChnYW1tYShudSkgLyAoc2lnbWFeMiAqIGthcHBhXigyKm51KSAqICg0KnBpKV4oMS8yKSAqIGdhbW1hKG51ICsgMS8yKSkpICAjc2lnbWEgPSAxLCBkID0gMQogICAgICAgICAgICBhbHBoYSA9IG51ICsgMS8yCiAgICAgICAgICAgIAogICAgICAgICAgICB0cnlDYXRjaCh7CiAgICAgICAgICAgICMgZ2V0dGluZyB0cnVlIGNvdmFyaWFuY2UKICAgICAgICAgICAgdHJ1ZV9jb3ZfbWF0ID0gZ2V0c190cnVlX2Nvdl9tYXQoZ3JhcGggPSBncmFwaCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2FwcGEgPSBrYXBwYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGF1ID0gdGF1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IGFscGhhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLm92ZXJraWxsID0gbi5vdmVya2lsbCkKICAgICAgICAgICAgCiAgICAgICAgICAgICMgZ2V0dGluZyB0aGUgYXBwcm94aW1hdGUgY292YXJpYW5jZSBtYXRyaXgKICAgICAgICAgICAgb3AgPSBtYXRlcm4ub3BlcmF0b3JzKGFscGhhID0gYWxwaGEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2FwcGEgPSBrYXBwYSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXUgPSB0YXUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtID0gbSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmFwaCA9IGdyYXBoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9IHR5cGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24gPSB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24pCiAgICAgICAgICAgIGFwcHJfY292X21hdCA9IG9wJGNvdmFyaWFuY2VfbWVzaCgpCiAgICAgICAgICAgIAogICAgICAgICAgICAjIGNvbXB1dGluZyB0aGUgZXJyb3JzCiAgICAgICAgICAgIExfaW5mX2Vycm9yID0gbWF4KGFicyh0cnVlX2Nvdl9tYXQgLSBhcHByX2Nvdl9tYXQpKQogICAgICAgICAgICBMXzJfZXJyb3IgPSBzcXJ0KGFzLmRvdWJsZSh0KGdyYXBoJG1lc2gkd2VpZ2h0cyklKiUodHJ1ZV9jb3ZfbWF0IC0gYXBwcl9jb3ZfbWF0KV4yJSolZ3JhcGgkbWVzaCR3ZWlnaHRzKSkKICAgICAgICAgICAgCiAgICAgICAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXVtuLDFdID0gTF9pbmZfZXJyb3IKICAgICAgICAgICAgRXJyb3JbW2FzLmNoYXJhY3RlcihoX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dW1thcy5jaGFyYWN0ZXIocmhvX3ZlY3RvcltrXSldXVtbYXMuY2hhcmFjdGVyKG1fdmVjdG9yW2xdKV1dW24sMl0gPSBMXzJfZXJyb3IKICAgICAgICAgICAgfSwgZXJyb3IgPSBmdW5jdGlvbihlcnIpewogICAgICAgICAgICAgIHdhcm5pbmcocGFzdGUoIkVycm9yIG9jY3VycmVkIGF0IGl0ZXJhdGlvbiBoPSIsIGgsICIsdHlwZT0iLCB0eXBlLCAiLHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbj0iLCB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24sICIscmhvPSIsIHJobywgIixtPSIsIG0sICIsbnU9IiwgbnUsICJFcnJvcjoiLCBjb25kaXRpb25NZXNzYWdlKGVycikpKQogICAgICAgICAgICAgIHByaW50KHBhc3RlKCJFcnJvciBvY2N1cnJlZCBhdCBpdGVyYXRpb24gaD0iLCBoLCAiLHR5cGU9IiwgdHlwZSwgIix0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb249IiwgdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uLCAiLHJobz0iLCByaG8sICIsbT0iLCBtLCAiLG51PSIsIG51LCAiRXJyb3I6IiwgY29uZGl0aW9uTWVzc2FnZShlcnIpKSkKICAgICAgICAgICAgICBFcnJvcltbYXMuY2hhcmFjdGVyKGhfdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dW1t0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdXV1bW2FzLmNoYXJhY3RlcihyaG9fdmVjdG9yW2tdKV1dW1thcy5jaGFyYWN0ZXIobV92ZWN0b3JbbF0pXV1bbiwxXSA9IE5BCiAgICAgICAgICAgICAgRXJyb3JbW2FzLmNoYXJhY3RlcihoX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dW1thcy5jaGFyYWN0ZXIocmhvX3ZlY3RvcltrXSldXVtbYXMuY2hhcmFjdGVyKG1fdmVjdG9yW2xdKV1dW24sMl0gPSBOQQogICAgICAgICAgICB9KQogICAgICAgICAgICBwcmludChwYXN0ZSgiaD0iLCBoLCAiLHR5cGU9IiwgdHlwZSwgIix0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb249IiwgdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uLCAiLHJobz0iLCByaG8sICIsbT0iLCBtLCAiLG51PSIsIG51KSkKICAgICAgICAgIH0KICAgICAgICB9CiAgICAgIH0KICAgIH0KICB9Cn0KCkVycm9yX3RhZHBvbGVfREVGX3JobzEgPSBFcnJvcgpzYXZlKEVycm9yX3RhZHBvbGVfREVGX3JobzEsIGZpbGUgPSBoZXJlOjpoZXJlKCJkYXRhX2ZpbGVzL0Vycm9yX3RhZHBvbGVfREVGX3JobzEuUkRhdGEiKSkKYGBgCgoKIyMgYHJobyA9IDJgCgo8ZGl2IHN0eWxlPSJjb2xvcjogIzJjM2U1MDsgdGV4dC1hbGlnbjogcmlnaHQ7Ij4KKioqKioqKiogIAo8c3Ryb25nPlByZXNzIFNob3cgdG8gcmV2ZWFsIHRoZSBjb2RlIGNodW5rcy48L3N0cm9uZz4gIAoKKioqKioqKioKPC9kaXY+CgoKCmBgYHtyLCBldmFsID0gRkFMU0V9CiMgbGlicmFyeSBjYWxscwpsaWJyYXJ5KE1ldHJpY0dyYXBoKQpsaWJyYXJ5KE1hdHJpeCkKbGlicmFyeShyU1BERSkKCiMgZnVuY3Rpb24gMQp0YWRwb2xlLmVpZyA8LSBmdW5jdGlvbihrLGdyYXBoKXsKICB4MSA8LSBjKDAsZ3JhcGgkZ2V0X2VkZ2VfbGVuZ3RocygpWzFdKmdyYXBoJG1lc2gkUHRFW2dyYXBoJG1lc2gkUHRFWywxXT09MSwyXSkgCiAgeDIgPC0gYygwLGdyYXBoJGdldF9lZGdlX2xlbmd0aHMoKVsyXSpncmFwaCRtZXNoJFB0RVtncmFwaCRtZXNoJFB0RVssMV09PTIsMl0pIAogIAogIGlmKGs9PTApeyAKICAgIGYuZTEgPC0gcmVwKDEsbGVuZ3RoKHgxKSkgCiAgICBmLmUyIDwtIHJlcCgxLGxlbmd0aCh4MikpIAogICAgZjEgPSBjKGYuZTFbMV0sZi5lMlsxXSxmLmUxWy0xXSwgZi5lMlstMV0pIAogICAgZiA9IGxpc3QocGhpPWYxL3NxcnQoMykpIAogICAgCiAgfSBlbHNlIHsKICAgIGYuZTEgPC0gLTIqc2luKHBpKmsqMS8yKSpjb3MocGkqayp4MS8yKSAKICAgIGYuZTIgPC0gc2luKHBpKmsqeDIvMikgICAgICAgICAgICAgICAgICAKICAgIAogICAgZjEgPSBjKGYuZTFbMV0sZi5lMlsxXSxmLmUxWy0xXSwgZi5lMlstMV0pIAogICAgCiAgICBpZigoayAlJSAyKT09MSl7IAogICAgICBmID0gbGlzdChwaGk9ZjEvc3FydCgzKSkgCiAgICB9IGVsc2UgeyAKICAgICAgZi5lMSA8LSAoLTEpXntrLzJ9KmNvcyhwaSprKngxLzIpCiAgICAgIGYuZTIgPC0gY29zKHBpKmsqeDIvMikKICAgICAgZjIgPSBjKGYuZTFbMV0sZi5lMlsxXSxmLmUxWy0xXSxmLmUyWy0xXSkgCiAgICAgIGYgPC0gbGlzdChwaGk9ZjEscHNpPWYyL3NxcnQoMy8yKSkKICAgIH0KICB9CiAgCiAgcmV0dXJuKGYpCn0KCiMgZnVuY3Rpb24gMgpnZXRzX2dyYXBoIDwtIGZ1bmN0aW9uKGgpewogIGVkZ2UxIDwtIHJiaW5kKGMoMCwwKSxjKDEsMCkpCiAgdGhldGEgPC0gc2VxKGZyb209LXBpLHRvPXBpLGxlbmd0aC5vdXQgPSAxMDAwMCkKICBlZGdlMiA8LSBjYmluZCgxKzEvcGkrY29zKHRoZXRhKS9waSxzaW4odGhldGEpL3BpKQogIGVkZ2VzID0gbGlzdChlZGdlMSwgZWRnZTIpCiAgZ3JhcGggPC0gbWV0cmljX2dyYXBoJG5ldyhlZGdlcyA9IGVkZ2VzKQogIGdyYXBoJHNldF9tYW51YWxfZWRnZV9sZW5ndGhzKGVkZ2VfbGVuZ3RocyA9IGMoMSwyKSkKICBncmFwaCRidWlsZF9tZXNoKGg9aCkKICByZXR1cm4oZ3JhcGgpCn0KCiNmdW5jdGlvbiAzCmdldHNfdHJ1ZV9jb3ZfbWF0IDwtIGZ1bmN0aW9uKGdyYXBoLCBrYXBwYSwgdGF1LCBhbHBoYSwgbi5vdmVya2lsbCl7CiAgU2lnbWEua2wgPC0gbWF0cml4KDAsbnJvdyA9IGRpbShncmFwaCRtZXNoJFYpWzFdLG5jb2wgPSBkaW0oZ3JhcGgkbWVzaCRWKVsxXSkKICBmb3IoaSBpbiAwOm4ub3ZlcmtpbGwpewogICAgcGhpIDwtIHRhZHBvbGUuZWlnKGksZ3JhcGgpJHBoaQogICAgU2lnbWEua2wgPC0gU2lnbWEua2wgKyAoMS8oa2FwcGFeMiArIChpKnBpLzIpXjIpXihhbHBoYSkpKnBoaSUqJXQocGhpKQogICAgaWYoaT4wICYmIChpICUlIDIpPT0wKXsgCiAgICAgIHBzaSA8LSB0YWRwb2xlLmVpZyhpLGdyYXBoKSRwc2kKICAgICAgU2lnbWEua2wgPC0gU2lnbWEua2wgKyAoMS8oa2FwcGFeMiArIChpKnBpLzIpXjIpXihhbHBoYSkpKnBzaSUqJXQocHNpKQogICAgfQogICAgCiAgfQogIFNpZ21hLmtsIDwtIFNpZ21hLmtsL3RhdV4yCiAgcmV0dXJuKFNpZ21hLmtsKQp9CgojIHBhcmFtZXRlcnMKaF92ZWN0b3IgPSBjKDAuMDAxLCAwLjAwNSwgMC4wMSwgMC4xKQp0eXBlX3ZlY3RvciA9IGMoImNvdmFyaWFuY2UiLCAib3BlcmF0b3IiKQp0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yID0gYygiY2hlYmZ1biIsICJicmFzaWwiLCAiY2hlYmZ1bkxCIikKcmhvX3ZlY3RvciA9IGMoMC4xLCAwLjUsIDEsIDIpCm1fdmVjdG9yID0gYygwLDEsMiwzLDQsNSkKbnVfdmVjdG9yID0gYyhzZXEoMC4xLDAuNCxieT0wLjA1KSwgc2VxKDAuNDEsMC41OSxieT0wLjAxKSwgc2VxKDAuNiwxLjQsYnk9MC4wNSksIHNlcSgxLjQxLDEuNTksYnk9MC4wMSksIHNlcSgxLjYsMi40LGJ5PTAuMDUpLCBzZXEoMi40MSwyLjQ5LGJ5PTAuMDEpKSAKbi5vdmVya2lsbCA9IDEwMDAKc2lnbWEgPSAxCgpFcnJvciA9IGxpc3QoKQpmb3IgKHMgaW4gYygxLDIsMyw0KSkgeyAjIGxvb3Agb3ZlciBoX3ZlY3RvcgogIEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV0gPSBsaXN0KCkKICBoID0gaF92ZWN0b3Jbc10KICBncmFwaCA9IGdldHNfZ3JhcGgoaCA9IGgpCiAgZm9yIChpIGluIGMoMSkpIHsgIyBsb29wIG92ZXIgdHlwZV92ZWN0b3IKICAgIEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV0gPSBsaXN0KCkKICAgIHR5cGUgPSB0eXBlX3ZlY3RvcltpXQogICAgZm9yIChqIGluIGMoMSwyLDMpKSB7ICMgbG9vcCBvdmVyIHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3IKICAgICAgRXJyb3JbW2FzLmNoYXJhY3RlcihoX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dID0gbGlzdCgpCiAgICAgIHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbiA9IHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal0KICAgICAgZm9yIChrIGluIGMoNCkpIHsgIyBsb29wIG92ZXIgcmhvX3ZlY3RvcgogICAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV0gPSBsaXN0KCkKICAgICAgICByaG8gPSByaG9fdmVjdG9yW2tdCiAgICAgICAgZm9yIChsIGluIDE6bGVuZ3RoKG1fdmVjdG9yKSkgeyAjIGxvb3Agb3ZlciBtX3ZlY3RvcgogICAgICAgICAgRXJyb3JbW2FzLmNoYXJhY3RlcihoX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dW1thcy5jaGFyYWN0ZXIocmhvX3ZlY3RvcltrXSldXVtbYXMuY2hhcmFjdGVyKG1fdmVjdG9yW2xdKV1dID0gbWF0cml4KE5BLCBucm93ID0gbGVuZ3RoKG51X3ZlY3RvciksIG5jb2wgPSAyKQogICAgICAgICAgY29sbmFtZXMoRXJyb3JbW2FzLmNoYXJhY3RlcihoX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dW1thcy5jaGFyYWN0ZXIocmhvX3ZlY3RvcltrXSldXVtbYXMuY2hhcmFjdGVyKG1fdmVjdG9yW2xdKV1dKSA9IGMoIkxfaW5mX2Vycm9yIiwgIkxfMl9lcnJvciIpCiAgICAgICAgICBtID0gbV92ZWN0b3JbbF0KICAgICAgICAgIGZvciAobiBpbiAxOmxlbmd0aChudV92ZWN0b3IpKSB7ICMgbG9vcCBvdmVyIG51X3ZlY3RvcgogICAgICAgICAgICBudSA9IG51X3ZlY3RvcltuXQogICAgICAgICAgICAKICAgICAgICAgICAga2FwcGEgPSBzcXJ0KDgqbnUpL3JobwogICAgICAgICAgICB0YXUgPSBzcXJ0KGdhbW1hKG51KSAvIChzaWdtYV4yICoga2FwcGFeKDIqbnUpICogKDQqcGkpXigxLzIpICogZ2FtbWEobnUgKyAxLzIpKSkgICNzaWdtYSA9IDEsIGQgPSAxCiAgICAgICAgICAgIGFscGhhID0gbnUgKyAxLzIKICAgICAgICAgICAgCiAgICAgICAgICAgIHRyeUNhdGNoKHsKICAgICAgICAgICAgIyBnZXR0aW5nIHRydWUgY292YXJpYW5jZQogICAgICAgICAgICB0cnVlX2Nvdl9tYXQgPSBnZXRzX3RydWVfY292X21hdChncmFwaCA9IGdyYXBoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrYXBwYSA9IGthcHBhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXUgPSB0YXUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gYWxwaGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4ub3ZlcmtpbGwgPSBuLm92ZXJraWxsKQogICAgICAgICAgICAKICAgICAgICAgICAgIyBnZXR0aW5nIHRoZSBhcHByb3hpbWF0ZSBjb3ZhcmlhbmNlIG1hdHJpeAogICAgICAgICAgICBvcCA9IG1hdGVybi5vcGVyYXRvcnMoYWxwaGEgPSBhbHBoYSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrYXBwYSA9IGthcHBhLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhdSA9IHRhdSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG0gPSBtLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyYXBoID0gZ3JhcGgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gdHlwZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbiA9IHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbikKICAgICAgICAgICAgYXBwcl9jb3ZfbWF0ID0gb3AkY292YXJpYW5jZV9tZXNoKCkKICAgICAgICAgICAgCiAgICAgICAgICAgICMgY29tcHV0aW5nIHRoZSBlcnJvcnMKICAgICAgICAgICAgTF9pbmZfZXJyb3IgPSBtYXgoYWJzKHRydWVfY292X21hdCAtIGFwcHJfY292X21hdCkpCiAgICAgICAgICAgIExfMl9lcnJvciA9IHNxcnQoYXMuZG91YmxlKHQoZ3JhcGgkbWVzaCR3ZWlnaHRzKSUqJSh0cnVlX2Nvdl9tYXQgLSBhcHByX2Nvdl9tYXQpXjIlKiVncmFwaCRtZXNoJHdlaWdodHMpKQogICAgICAgICAgICAKICAgICAgICAgICAgRXJyb3JbW2FzLmNoYXJhY3RlcihoX3ZlY3RvcltzXSldXVtbdHlwZV92ZWN0b3JbaV1dXVtbdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uX3ZlY3RvcltqXV1dW1thcy5jaGFyYWN0ZXIocmhvX3ZlY3RvcltrXSldXVtbYXMuY2hhcmFjdGVyKG1fdmVjdG9yW2xdKV1dW24sMV0gPSBMX2luZl9lcnJvcgogICAgICAgICAgICBFcnJvcltbYXMuY2hhcmFjdGVyKGhfdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dW1t0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdXV1bW2FzLmNoYXJhY3RlcihyaG9fdmVjdG9yW2tdKV1dW1thcy5jaGFyYWN0ZXIobV92ZWN0b3JbbF0pXV1bbiwyXSA9IExfMl9lcnJvcgogICAgICAgICAgICB9LCBlcnJvciA9IGZ1bmN0aW9uKGVycil7CiAgICAgICAgICAgICAgd2FybmluZyhwYXN0ZSgiRXJyb3Igb2NjdXJyZWQgYXQgaXRlcmF0aW9uIGg9IiwgaCwgIix0eXBlPSIsIHR5cGUsICIsdHlwZV9yYXRpb25hbF9hcHByb3hpbWF0aW9uPSIsIHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbiwgIixyaG89IiwgcmhvLCAiLG09IiwgbSwgIixudT0iLCBudSwgIkVycm9yOiIsIGNvbmRpdGlvbk1lc3NhZ2UoZXJyKSkpCiAgICAgICAgICAgICAgcHJpbnQocGFzdGUoIkVycm9yIG9jY3VycmVkIGF0IGl0ZXJhdGlvbiBoPSIsIGgsICIsdHlwZT0iLCB0eXBlLCAiLHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbj0iLCB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24sICIscmhvPSIsIHJobywgIixtPSIsIG0sICIsbnU9IiwgbnUsICJFcnJvcjoiLCBjb25kaXRpb25NZXNzYWdlKGVycikpKQogICAgICAgICAgICAgIEVycm9yW1thcy5jaGFyYWN0ZXIoaF92ZWN0b3Jbc10pXV1bW3R5cGVfdmVjdG9yW2ldXV1bW3R5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbl92ZWN0b3Jbal1dXVtbYXMuY2hhcmFjdGVyKHJob192ZWN0b3Jba10pXV1bW2FzLmNoYXJhY3RlcihtX3ZlY3RvcltsXSldXVtuLDFdID0gTkEKICAgICAgICAgICAgICBFcnJvcltbYXMuY2hhcmFjdGVyKGhfdmVjdG9yW3NdKV1dW1t0eXBlX3ZlY3RvcltpXV1dW1t0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yW2pdXV1bW2FzLmNoYXJhY3RlcihyaG9fdmVjdG9yW2tdKV1dW1thcy5jaGFyYWN0ZXIobV92ZWN0b3JbbF0pXV1bbiwyXSA9IE5BCiAgICAgICAgICAgIH0pCiAgICAgICAgICAgIHByaW50KHBhc3RlKCJoPSIsIGgsICIsdHlwZT0iLCB0eXBlLCAiLHR5cGVfcmF0aW9uYWxfYXBwcm94aW1hdGlvbj0iLCB0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb24sICIscmhvPSIsIHJobywgIixtPSIsIG0sICIsbnU9IiwgbnUpKQogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgfQogIH0KfQoKRXJyb3JfdGFkcG9sZV9ERUZfcmhvMiA9IEVycm9yCnNhdmUoRXJyb3JfdGFkcG9sZV9ERUZfcmhvMiwgZmlsZSA9IGhlcmU6OmhlcmUoImRhdGFfZmlsZXMvRXJyb3JfdGFkcG9sZV9ERUZfcmhvMi5SRGF0YSIpKQpgYGAKCiMjIFBsb3R0aW5nIHRoZSBlcnJvcnMKCmBgYHtyfQpsb2FkKGhlcmU6OmhlcmUoImRhdGFfZmlsZXMvRXJyb3JfdGFkcG9sZV9ERUZfcmhvMC4xLlJEYXRhIikpCmxvYWQoaGVyZTo6aGVyZSgiZGF0YV9maWxlcy9FcnJvcl90YWRwb2xlX0RFRl9yaG8wLjUuUkRhdGEiKSkKbG9hZChoZXJlOjpoZXJlKCJkYXRhX2ZpbGVzL0Vycm9yX3RhZHBvbGVfREVGX3JobzEuUkRhdGEiKSkKbG9hZChoZXJlOjpoZXJlKCJkYXRhX2ZpbGVzL0Vycm9yX3RhZHBvbGVfREVGX3JobzIuUkRhdGEiKSkKCmhfdmVjdG9yID0gYygiMC4wMDEiLCAiMC4wMDUiLCAiMC4wMSIsICIwLjEiKQp0eXBlX3JhdGlvbmFsX2FwcHJveGltYXRpb25fdmVjdG9yID0gYygiY2hlYmZ1biIsICJicmFzaWwiLCAiY2hlYmZ1bkxCIikKbnVfbWF4ID0gNTMKbnVfdmVjdG9yID0gMC41ICsgYyhzZXEoMC4xLDAuNCxieT0wLjA1KSwgc2VxKDAuNDEsMC41OSxieT0wLjAxKSwgc2VxKDAuNiwxLjQsYnk9MC4wNSksIHNlcSgxLjQxLDEuNTksYnk9MC4wMSksIHNlcSgxLjYsMi40LGJ5PTAuMDUpLCBzZXEoMi40MSwyLjQ5LGJ5PTAuMDEpKVsxOm51X21heF0KCm4gPSAiMC4wMDEiCnQgPSAiY2hlYmZ1biIKCgpkYXQgPSByYmluZCgKZGF0YS5mcmFtZShudSA9IHJlcChudV92ZWN0b3IsNSksIAogICAgICAgICAgIHJobyA9IHJlcCgwLjEsIHRpbWVzID0gNSpudV9tYXgpLAogICAgICAgICAgIG0gPSByZXAoMTo1LCBlYWNoID0gbnVfbWF4KSwKICAgICAgICAgICBlcnJvciA9IGMoRXJyb3JfdGFkcG9sZV9ERUZfcmhvMC4xW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjEiXV1bWyIxIl1dWzE6bnVfbWF4LDFdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl90YWRwb2xlX0RFRl9yaG8wLjFbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuMSJdXVtbIjIiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX3RhZHBvbGVfREVGX3JobzAuMVtbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC4xIl1dW1siMyJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfdGFkcG9sZV9ERUZfcmhvMC4xW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjEiXV1bWyI0Il1dWzE6bnVfbWF4LDFdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl90YWRwb2xlX0RFRl9yaG8wLjFbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuMSJdXVtbIjUiXV1bMTpudV9tYXgsMV0pLAogICAgICAgICAgIEwgPSByZXAoIkxpbmYiLCB0aW1lcyA9IDUqbnVfbWF4KQopLAoKZGF0YS5mcmFtZShudSA9IHJlcChudV92ZWN0b3IsNSksIAogICAgICAgICAgIHJobyA9IGMocmVwKDAuNSwgdGltZXMgPSA1Km51X21heCkpLAogICAgICAgICAgIG0gPSByZXAoMTo1LCBlYWNoID0gbnVfbWF4KSwKICAgICAgICAgICBlcnJvciA9IGMoRXJyb3JfdGFkcG9sZV9ERUZfcmhvMC41W1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjUiXV1bWyIxIl1dWzE6bnVfbWF4LDFdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl90YWRwb2xlX0RFRl9yaG8wLjVbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuNSJdXVtbIjIiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX3RhZHBvbGVfREVGX3JobzAuNVtbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC41Il1dW1siMyJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfdGFkcG9sZV9ERUZfcmhvMC41W1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjUiXV1bWyI0Il1dWzE6bnVfbWF4LDFdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl90YWRwb2xlX0RFRl9yaG8wLjVbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuNSJdXVtbIjUiXV1bMTpudV9tYXgsMV0pLAogICAgICAgICAgIEwgPSByZXAoIkxpbmYiLCB0aW1lcyA9IDUqbnVfbWF4KQopLAoKZGF0YS5mcmFtZShudSA9IHJlcChudV92ZWN0b3IsNSksIAogICAgICAgICAgIHJobyA9IGMocmVwKDEsIHRpbWVzID0gNSpudV9tYXgpKSwKICAgICAgICAgICBtID0gcmVwKDE6NSwgZWFjaCA9IG51X21heCksCiAgICAgICAgICAgZXJyb3IgPSBjKEVycm9yX3RhZHBvbGVfREVGX3JobzFbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjEiXV1bWyIxIl1dWzE6bnVfbWF4LDFdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl90YWRwb2xlX0RFRl9yaG8xW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIxIl1dW1siMiJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfdGFkcG9sZV9ERUZfcmhvMVtbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMSJdXVtbIjMiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX3RhZHBvbGVfREVGX3JobzFbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjEiXV1bWyI0Il1dWzE6bnVfbWF4LDFdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl90YWRwb2xlX0RFRl9yaG8xW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIxIl1dW1siNSJdXVsxOm51X21heCwxXSksCiAgICAgICAgICAgTCA9IHJlcCgiTGluZiIsIHRpbWVzID0gNSpudV9tYXgpCiksCgpkYXRhLmZyYW1lKG51ID0gcmVwKG51X3ZlY3Rvciw1KSwgCiAgICAgICAgICAgcmhvID0gYyhyZXAoMiwgdGltZXMgPSA1Km51X21heCkpLAogICAgICAgICAgIG0gPSByZXAoMTo1LCBlYWNoID0gbnVfbWF4KSwKICAgICAgICAgICBlcnJvciA9IGMoRXJyb3JfdGFkcG9sZV9ERUZfcmhvMltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMiJdXVtbIjEiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX3RhZHBvbGVfREVGX3JobzJbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjIiXV1bWyIyIl1dWzE6bnVfbWF4LDFdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl90YWRwb2xlX0RFRl9yaG8yW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIyIl1dW1siMyJdXVsxOm51X21heCwxXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfdGFkcG9sZV9ERUZfcmhvMltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMiJdXVtbIjQiXV1bMTpudV9tYXgsMV0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX3RhZHBvbGVfREVGX3JobzJbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjIiXV1bWyI1Il1dWzE6bnVfbWF4LDFdKSwKICAgICAgICAgICBMID0gcmVwKCJMaW5mIiwgdGltZXMgPSA1Km51X21heCkKKSwKCiMjIEwyCgpkYXRhLmZyYW1lKG51ID0gcmVwKG51X3ZlY3Rvciw1KSwgCiAgICAgICAgICAgcmhvID0gcmVwKDAuMSwgdGltZXMgPSA1Km51X21heCksCiAgICAgICAgICAgbSA9IHJlcCgxOjUsIGVhY2ggPSBudV9tYXgpLAogICAgICAgICAgIGVycm9yID0gYyhFcnJvcl90YWRwb2xlX0RFRl9yaG8wLjFbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuMSJdXVtbIjEiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX3RhZHBvbGVfREVGX3JobzAuMVtbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC4xIl1dW1siMiJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfdGFkcG9sZV9ERUZfcmhvMC4xW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjEiXV1bWyIzIl1dWzE6bnVfbWF4LDJdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl90YWRwb2xlX0RFRl9yaG8wLjFbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuMSJdXVtbIjQiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX3RhZHBvbGVfREVGX3JobzAuMVtbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC4xIl1dW1siNSJdXVsxOm51X21heCwyXSksCiAgICAgICAgICAgTCA9IHJlcCgiTDIiLCB0aW1lcyA9IDUqbnVfbWF4KQopLAoKZGF0YS5mcmFtZShudSA9IHJlcChudV92ZWN0b3IsNSksIAogICAgICAgICAgIHJobyA9IGMocmVwKDAuNSwgdGltZXMgPSA1Km51X21heCkpLAogICAgICAgICAgIG0gPSByZXAoMTo1LCBlYWNoID0gbnVfbWF4KSwKICAgICAgICAgICBlcnJvciA9IGMoRXJyb3JfdGFkcG9sZV9ERUZfcmhvMC41W1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjUiXV1bWyIxIl1dWzE6bnVfbWF4LDJdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl90YWRwb2xlX0RFRl9yaG8wLjVbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuNSJdXVtbIjIiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX3RhZHBvbGVfREVGX3JobzAuNVtbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMC41Il1dW1siMyJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfdGFkcG9sZV9ERUZfcmhvMC41W1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIwLjUiXV1bWyI0Il1dWzE6bnVfbWF4LDJdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl90YWRwb2xlX0RFRl9yaG8wLjVbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjAuNSJdXVtbIjUiXV1bMTpudV9tYXgsMl0pLAogICAgICAgICAgIEwgPSByZXAoIkwyIiwgdGltZXMgPSA1Km51X21heCkKKSwKCmRhdGEuZnJhbWUobnUgPSByZXAobnVfdmVjdG9yLDUpLCAKICAgICAgICAgICByaG8gPSBjKHJlcCgxLCB0aW1lcyA9IDUqbnVfbWF4KSksCiAgICAgICAgICAgbSA9IHJlcCgxOjUsIGVhY2ggPSBudV9tYXgpLAogICAgICAgICAgIGVycm9yID0gYyhFcnJvcl90YWRwb2xlX0RFRl9yaG8xW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIxIl1dW1siMSJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfdGFkcG9sZV9ERUZfcmhvMVtbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMSJdXVtbIjIiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX3RhZHBvbGVfREVGX3JobzFbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjEiXV1bWyIzIl1dWzE6bnVfbWF4LDJdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl90YWRwb2xlX0RFRl9yaG8xW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIxIl1dW1siNCJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfdGFkcG9sZV9ERUZfcmhvMVtbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMSJdXVtbIjUiXV1bMTpudV9tYXgsMl0pLAogICAgICAgICAgIEwgPSByZXAoIkwyIiwgdGltZXMgPSA1Km51X21heCkKKSwKCmRhdGEuZnJhbWUobnUgPSByZXAobnVfdmVjdG9yLDUpLCAKICAgICAgICAgICByaG8gPSBjKHJlcCgyLCB0aW1lcyA9IDUqbnVfbWF4KSksCiAgICAgICAgICAgbSA9IHJlcCgxOjUsIGVhY2ggPSBudV9tYXgpLAogICAgICAgICAgIGVycm9yID0gYyhFcnJvcl90YWRwb2xlX0RFRl9yaG8yW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIyIl1dW1siMSJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfdGFkcG9sZV9ERUZfcmhvMltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMiJdXVtbIjIiXV1bMTpudV9tYXgsMl0sCiAgICAgICAgICAgICAgICAgICAgIEVycm9yX3RhZHBvbGVfREVGX3JobzJbW25dXVtbImNvdmFyaWFuY2UiXV1bW3RdXVtbIjIiXV1bWyIzIl1dWzE6bnVfbWF4LDJdLAogICAgICAgICAgICAgICAgICAgICBFcnJvcl90YWRwb2xlX0RFRl9yaG8yW1tuXV1bWyJjb3ZhcmlhbmNlIl1dW1t0XV1bWyIyIl1dW1siNCJdXVsxOm51X21heCwyXSwKICAgICAgICAgICAgICAgICAgICAgRXJyb3JfdGFkcG9sZV9ERUZfcmhvMltbbl1dW1siY292YXJpYW5jZSJdXVtbdF1dW1siMiJdXVtbIjUiXV1bMTpudV9tYXgsMl0pLAogICAgICAgICAgIEwgPSByZXAoIkwyIiwgdGltZXMgPSA1Km51X21heCkKKQopCgoKZGF0JHJobyA9IGZhY3RvcihkYXQkcmhvLCBsZXZlbHMgPSBjKCIwLjEiLCAiMC41IiwgIjEiLCAiMiIpKQpkYXQkTCA9IGZhY3RvcihkYXQkTCwgbGV2ZWxzID0gYygiTDIiLCAiTGluZiIpKQpsZXZlbHMoZGF0JHJobykgPSBjKCIwLjEiID0gIiRcXHJobyA9IDAuMSQiLCAiMC41IiA9ICIkXFxyaG8gPSAwLjUkIiwgIjEiID0gIiRcXHJobyA9IDEkIiwgIjIiID0gIiRcXHJobyA9IDIkIikKbGV2ZWxzKGRhdCRMKSA9IGMoIkwyIiA9ICIkTF8yKFxcR2FtbWFcXHRpbWVzXFxHYW1tYSkkIiwgIkxpbmYiID0gIiRMX1xcaW5mdHkoXFxHYW1tYVxcdGltZXNcXEdhbW1hKSQiKQoKCnBfZXJyX3RhZCA8LSBnZ3Bsb3QoZGF0LCBhZXMobnUsIGVycm9yLCBjb2xvdXIgPSBhcy5mYWN0b3IobSkpKSArIAogIGZhY2V0X2dyaWQoTCB+IHJobykgKwogIGdlb21fbGluZShzaXplID0gMS4zKSArCiAgc2NhbGVfeV9sb2cxMChuLmJyZWFrcyA9IDUpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobi5icmVha3MgPSAxMCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLnNwYWNpbmcgPSB1bml0KDAuMywgImNtIiksIAogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIlBhbGF0aW5vIiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE2KSwKICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksICAgICAgICAjIFBhbmVsIHRpdGxlcwogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwgICAgICAgICMgQXhpcyB0aXRsZXMKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwgICAgICAgICAjIEF4aXMgdGV4dAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLCAgICAgICMgTGVnZW5kIHRpdGxlCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkgKwogIGxhYnMoeCA9ICIkXFxhbHBoYVxcbWJveHsgfShcXG1ib3h7U21vb3RobmVzcyBwYXJhbWV0ZXJ9KSQiLCB5ID0gIiRcXG1ib3h7Q292YXJpYW5jZSBFcnJvcn0kIiwgY29sb3IgPSAiJG0kIikgKwogIGdndGl0bGUoIiRcXG1ib3h7VGFkcG9sZSBncmFwaH0kIikgCgpteWdnc2F2ZShwX2Vycl90YWQsIHdpZHRoID0gMTIsIGhlaWdodCA9IDYpCmBgYAoKCmBgYHtyLCBldmFsID0gVFJVRSwgb3V0LndpZHRoPSIxMjAwcHgiLCBvdXQuaGVpZ2h0PSI2MDBweCIsIGZpZy5jYXAgPSBjYXB0aW9uZXIoIkNvdmFyaWFuY2UgZXJyb3IgZm9yIHRoZSB0YWRwb2xlIGdyYXBoLiIpfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJkYXRhX2ZpbGVzL3Rpa3pwaWMvcF9lcnJfdGFkLnBkZiIpKQpgYGAKCgoKCgoKIyBSZWZlcmVuY2VzCgoKYGBge3IsIGV2YWwgPSBUUlVFfQpncmF0ZWZ1bDo6Y2l0ZV9wYWNrYWdlcyhvdXRwdXQgPSAicGFyYWdyYXBoIiwgb3V0LmRpciA9ICIuIikKYGBgCgoK