Go back to the Contents page.


Press Show to reveal the code chunks.


# Create a clipboard button on the rendeblack HTML page
source(here::here("clipboard.R")); clipboard
# Set seed for reproducibility
set.seed(1982) 
# Set global options for all code chunks
knitr::opts_chunk$set(
  # Disable messages printed by R code chunks
  message = FALSE,    
  # Disable warnings printed by R code chunks
  warning = FALSE,    
  # Show R code within code chunks in output
  echo = TRUE,        
  # Include both R code and its results in output
  include = TRUE,     
  # Evaluate R code chunks
  eval = 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)
}
library(MetricGraph)
library(ggplot2)
library(reshape2)
library(dplyr)
library(viridis)
library(plotly)
library(patchwork)
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"))

For example, consider the regular curve \(\gamma(t) = (bt +c,a\cos(t), a\sin(t))\) for \(t\in[0,T]\), where \(a = 1\), \(b=0.5\), \(T=6\pi\), and \(c\) is a constant to be defined later. The curve has arc-length \(\ell = T\sqrt{a^2+b^2}\) and its arc-length parameterization is given by \(\tilde{\gamma}(s) = \gamma\left(s/\sqrt{a^2+b^2}\right)\) for \(s\in[0,\ell]\). Let \(\Gamma = (\mathcal{V}, \mathcal{E})\) denote the one edge graph induced by \(\tilde{\gamma}\), where \(\mathcal{V} = \{v_1 = \tilde{\gamma}(0), v_2 = \tilde{\gamma}(\ell)\}\) and \(\mathcal{E}=\{e = \tilde{\gamma}([0,\ell])\}\). Then we have the identification \(e=[0,\ell]\). For visualization purposes, we let \(c = T(\sqrt{a^2+b^2}-b)/2\). This makes the \(\gamma\) and the interval \([0,\ell]\) in Figure~\(\ref{arc_length_par}\) centered with respect to each other.

1 Helix function

library(plotly)

# Parameters
a <- 1
b <- 0.5
TT <- 6*pi
# Total arc-length
L <- sqrt(a^2 + b^2) * TT

half_L <- L / 2


max_x <- b * (L / sqrt(a^2 + b^2))

half_max_x <- max_x / 2

dist_to_move <- half_L - half_max_x

# Arc-length parametrization (helix around x-axis)
alpha_tilde <- function(s){
  t <- s / sqrt(a^2 + b^2)
  x_shift <- TT*(sqrt(a^2 + b^2) - b) / 2
  x <- b * t + x_shift
  y <- a * cos(t)
  z <- a * sin(t)
  data.frame(x=x, y=y, z=z)
}

a0 = alpha_tilde(0)
aL = alpha_tilde(L)
aLh = alpha_tilde(half_L)

hhhh <- 3
ff <- function(s) 2*abs(sin(hhhh*pi*s/L))
k <- 0:hhhh
s_special <- k*L/hhhh

# Smooth helix
n_smooth <- 500

#s_smooth <- seq(0, L, length.out = n_smooth)
s_smooth <- sort(unique(c(
  seq(0, L, length.out = n_smooth),
  s_special
)))
curve_smooth <- alpha_tilde(s_smooth)


# Points for mapping lines
n_map <- 100
s_map <- seq(0, L, length.out = n_map)
curve_map <- alpha_tilde(s_map)


#s_semi_coarse <- seq(0, L, length.out = n_smooth/2)

# Interval along x-axis
int_map <- data.frame(
  x = s_map,
  y = rep(0, n_map)+4,
  z = rep(0, n_map)
)


ff_eval_coarse <- ff(s_map)

ff_eval <- ff(s_smooth)

curve_smooth$height <- ff_eval

s_semi_coarse <- s_smooth
ff_s_semi_coarse <- ff(s_semi_coarse)
y_semi_coarse <- rep(0, length(s_semi_coarse)) + 4


ff_df <- data.frame(x = s_smooth, y = rep(0, length(s_smooth))+4, z = ff_eval)

ff_df_coarse <- data.frame(x = s_map, y = rep(0, length(s_map))+4, z = ff_eval_coarse)

# Build mapping lines
rows <- lapply(1:n_map, function(i) {
  list(int_map[i, ], curve_map[i, ], data.frame(x = NA, y = NA, z = NA))
})

result <- do.call(rbind, unlist(rows, recursive = FALSE))

# Build mapping lines
rows <- lapply(1:n_map, function(i) {
  list(curve_map[i, ], ff_df_coarse[i, ], data.frame(x = NA, y = NA, z = NA))
})

result2 <- do.call(rbind, unlist(rows, recursive = FALSE))


rows <- lapply(1:n_map, function(i) {
  val <- ff_eval_coarse[i]

  rbind(
    cbind(curve_map[i, ], val = val),
    cbind(ff_df_coarse[i, ], val = val),
    data.frame(x = NA, y = NA, z = NA, val = NA)
  )
})

result2 <- do.call(rbind, rows)

ff_df_coarse_new <- result2$val



zero <- int_map[1, ]
ell <- int_map[n_map, ]

vertex <- rbind(a0, aL, zero, ell)


ttt <- half_L / sqrt(a^2 + b^2)

u <- b
v <- -a*sin(ttt)
w <-  a*cos(ttt)

zmin <- min(ff_eval)
zmax <- max(ff_eval)

# Plot
p <- plot_ly() |>
  
  # Smooth helix
  add_trace(
    data = curve_smooth,
    x = ~x, y = ~y, z = ~z,
    type = "scatter3d",
    mode = "lines",
    line = list(color = ff_eval, 
                colorscale = "Viridis",
                cmin = zmin,
                cmax = zmax,
                width = 7),
    showlegend = FALSE
  ) |>
  
  # Interval [0,L]
  add_trace(
    data = int_map,
    x = ~x, y = ~y, z = ~z,
    type = "scatter3d",
    mode = "lines",
    line = list(color = "black", width = 7),
    showlegend = FALSE
  ) |>
  add_trace(
  data = result2,
  x = ~x, y = ~y, z = ~z,
  type = "scatter3d",
  mode = "lines",
  line = list(
    color = ff_df_coarse_new,
    colorscale = "Viridis",
    cmin = zmin,
    cmax = zmax,
    width = 1
  ),
  showlegend = FALSE
) |>
  add_trace(data = vertex,
  x = ~x,
  y = ~y,
  z = ~z,
  type = "scatter3d",
  mode = "markers",
  marker = list(size = 5, color = "black"),
    showlegend = FALSE
) |>
  add_trace(
    type = "cone",
    x = aLh$x,
    y = aLh$y,
    z = aLh$z,
    u = u,
    v = v,
    w = w,
    sizemode = "absolute",
    sizeref = 0.4,
    colorscale = list(c(0, 1), c("green", "green")),
    showscale = FALSE
  ) |>
  # function on interval
  add_trace(
    data = ff_df,
    x = ~x, y = ~y, z = ~z,
    type = "scatter3d",
    mode = "lines",
    line = list(
      color = ~z,                 # color based on height
      colorscale = "Viridis",     # choose any colorscale you like
    cmin = zmin,
    cmax = zmax,
      width = 7
    ),
    showlegend = FALSE
  ) |>
    add_trace(x = rep(s_semi_coarse, each = 3), 
            y = rep(y_semi_coarse, each = 3), 
            z = unlist(lapply(ff_s_semi_coarse, function(zj) c(0, zj, NA))),
            type = "scatter3d", 
            mode = "lines",
            line = list(color = "lightgray", width = 0.5),
            showlegend = FALSE)
 
dx <- int_map$x - curve_map$x
dy <- int_map$y - curve_map$y
dz <- int_map$z - curve_map$z

norm <- sqrt(dx^2 + dy^2 + dz^2)

u <- dx / norm
v <- dy / norm
w <- dz / norm

dx2 <- curve_map$x - ff_df_coarse$x
dy2 <- curve_map$y - ff_df_coarse$y
dz2 <- curve_map$z - ff_df_coarse$z

norm2 <- sqrt(dx2^2 + dy2^2 + dz2^2)

u2 <- dx2 / norm2
v2 <- dy2 / norm2
w2 <- dz2 / norm2

mag <- sqrt(u2^2 + v2^2 + w2^2)

scale <- ff_eval_coarse / mag

u_col <- u2 * scale
v_col <- v2 * scale
w_col <- w2 * scale

p <- p |>
add_trace(
  type = "cone",
  x = curve_map$x,
  y = curve_map$y,
  z = curve_map$z,
  u = u_col,
  v = v_col,
  w = w_col,
  colorscale = "Viridis",
  cmin = zmin,
  cmax = zmax,
  sizemode = "absolute",
  sizeref = 0.2,
  anchor = "tip",
  showscale = FALSE
)

rv <- 0.65
p2fhelix <- p |> config(mathjax = 'cdn') |>
            layout(p,
                   font = list(family = "Palatino"),
            margin = list(l = 0, r = 0, b = 0, t = 0),
            scene = list(xaxis = list(title = list(text = "x", font = list(color = colaxnn)),  tickfont = list(color = colaxnn),  range = c(0, L)),
              yaxis = list(title = list(text = "y", font = list(color = colaxnn)),  tickfont = list(color = colaxnn), range = c(-1, 4.1)),
              zaxis = list(title = list(text = "z", font = list(color = colaxnn)),  tickfont = list(color = colaxnn), range = c(-1, max(ff_eval))),
              #aspectmode="data",
              aspectratio = list(x = L/9, y = 5/3, z = (max(ff_eval)+1)/3),
              camera = list(eye = list(x = -3*rv, y = -6*rv, z = 6*rv),
                            center = list(x = 0, y = 0, z = 0)),
              annotations = list(
                list(
               x = zero$x, y = zero$y, z = zero$z,
               text = TeX("0"),
               textangle = 0, ax = 0, ay = -35,
               font = list(color = "black", size = gfsize),
               arrowcolor = "gray", arrowsize = 1, arrowwidth = 0.5, arrowhead = 1),
               list(
               x = ell$x, y = ell$y, z = ell$z,
               text = TeX("\\ell"),
               textangle = 0, ax = 0, ay = -35,
               font = list(color = "black", size = gfsize),
               arrowcolor = "gray", arrowsize = 1, arrowwidth = 0.5, arrowhead = 1),    
                list(
               x = aLh$x, y = aLh$y, z = aLh$z,
               text = TeX("e_1"),
               textangle = 0, ax = 0, ay = -35,
               font = list(color = "black", size = gfsize),
               arrowcolor = "gray", arrowsize = 1, arrowwidth = 0.5, arrowhead = 1),
               list(
               x = aL$x, y = aL$y, z = aL$z,
               text = TeX("v_2"),
               textangle = 0, ax = 0, ay = -35,
               font = list(color = "black", size = gfsize),
               arrowcolor = "gray", arrowsize = 1, arrowwidth = 0.5, arrowhead = 1),      
             list(
               x = a0$x, y = a0$y, z = a0$z,
               text = TeX("v_1"),
               textangle = 0, ax = 0, ay = -35,
               font = list(color = "black", size = gfsize),
               arrowcolor = "gray", arrowsize = 1, arrowwidth = 0.5, arrowhead = 1))
            )
)

save(p2fhelix, file = here::here("data_files/graphs6p2fhelix.Rdata"))
load(here::here("data_files/graphs6p2fhelix.Rdata"))
p2fhelix

2 Helix arc-length parametrization

library(plotly)

# Parameters
a <- 1
b <- 0.5
TT <- 6*pi
# Total arc-length
L <- sqrt(a^2 + b^2) * TT

half_L <- L / 2


max_x <- b * (L / sqrt(a^2 + b^2))

half_max_x <- max_x / 2

dist_to_move <- half_L - half_max_x

# Arc-length parametrization (helix around x-axis)
alpha_tilde <- function(s){
  t <- s / sqrt(a^2 + b^2)
  x_shift <- TT*(sqrt(a^2 + b^2) - b) / 2
  x <- b * t + x_shift
  y <- a * cos(t)
  z <- a * sin(t)
  data.frame(x=x, y=y, z=z)
}

a0 = alpha_tilde(0)
aL = alpha_tilde(L)
aLh = alpha_tilde(half_L)

# Smooth helix
n_smooth <- 500
s_smooth <- seq(0, L, length.out = n_smooth)
curve_smooth <- alpha_tilde(s_smooth)

# Points for mapping lines
n_map <- 100
s_map <- seq(0, L, length.out = n_map)
curve_map <- alpha_tilde(s_map)

# Interval along x-axis
int_map <- data.frame(
  x = s_map,
  y = rep(0, n_map)+4,
  z = rep(0, n_map)
)

zero <- int_map[1, ]
ell <- int_map[n_map, ]

vertex <- rbind(a0, aL, zero, ell)


ttt <- half_L / sqrt(a^2 + b^2)

u <- b
v <- -a*sin(ttt)
w <-  a*cos(ttt)

# Plot
p <- plot_ly() |>
  
  # Smooth helix
  add_trace(
    data = curve_smooth,
    x = ~x, y = ~y, z = ~z,
    type = "scatter3d",
    mode = "lines",
    line = list(color = "darkred", width = 7),
    showlegend = FALSE
  ) |>
  
  # Interval [0,L]
  add_trace(
    data = int_map,
    x = ~x, y = ~y, z = ~z,
    type = "scatter3d",
    mode = "lines",
    line = list(color = "#0000C8", width = 7),
    showlegend = FALSE
  ) |>
  add_trace(data = vertex,
  x = ~x,
  y = ~y,
  z = ~z,
  type = "scatter3d",
  mode = "markers",
  marker = list(size = 5, color = "black"),
    showlegend = FALSE
) |>
  add_trace(
    type = "cone",
    x = aLh$x,
    y = aLh$y,
    z = aLh$z,
    u = u,
    v = v,
    w = w,
    sizemode = "absolute",
    sizeref = 0.4,
    colorscale = list(c(0, 1), c("green", "green")),
    showscale = FALSE
  )

pal <- colorRampPalette(c(
  "#0000C8",  # dark navy
  "#0074D9",  # royalblue
  "#7FDBFF",  # cyan
  "#2ECC40",  # green
  "#FFDC00",  # yellow
  "#FF851B",  # orange
  "#FF4136",  # red
  "darkred"
))(100)

gradient_line <- function(p0, p1, n = 20){

  t <- seq(0,1,length.out = n)

  x <- (1-t)*p0$x + t*p1$x
  y <- (1-t)*p0$y + t*p1$y
  z <- (1-t)*p0$z + t*p1$z

  data.frame(x=x,y=y,z=z,t=t)
}


dx <- int_map$x - curve_map$x
dy <- int_map$y - curve_map$y
dz <- int_map$z - curve_map$z

norm <- sqrt(dx^2 + dy^2 + dz^2)

u <- dx / norm
v <- dy / norm
w <- dz / norm


p <- p |>
  add_trace(
    type = "cone",
    x = int_map$x,
    y = int_map$y,
    z = int_map$z,
    u = u,
    v = v,
    w = w,
    sizemode = "absolute",
    sizeref = 0.6,
    anchor = "tip",
    colorscale = list(c(0, "#0000C8"), c(1, "#0000C8")),
    showscale = FALSE
  ) 

for(i in 1:n_map){

  g <- gradient_line(int_map[i,], curve_map[i,])

  for(j in 1:(nrow(g)-1)){

    seg <- g[j:(j+1),]

    col <- pal[ round(seg$t[1]*(length(pal)-1))+1 ]

    p <- p |> add_trace(
      data = seg,
      x = ~x, y = ~y, z = ~z,
      type = "scatter3d",
      mode = "lines",
      line = list(color = col, width = 1),
      showlegend = FALSE
    )
  }
}

rv <- 0.65
p2 <- p |> config(mathjax = 'cdn') |>
            layout(p,
                   font = list(family = "Palatino"),
            margin = list(l = 0, r = 0, b = 0, t = 0),
            scene = list(xaxis = list(title = list(text = "x", font = list(color = colaxnn)),  tickfont = list(color = colaxnn),  range = c(0, L)),
              yaxis = list(title = list(text = "y", font = list(color = colaxnn)),  tickfont = list(color = colaxnn), range = c(-1, 4.1)),
              zaxis = list(title = list(text = "z", font = list(color = colaxnn)),  tickfont = list(color = colaxnn), range = c(-1, 2)),
              #aspectmode="data",
              aspectratio = list(x = L/9, y = 5/3, z = (2+1)/3),
              camera = list(eye = list(x = -3*rv, y = -6*rv, z = 6*rv),
                            center = list(x = 0, y = 0, z = 0)),
              annotations = list(
                list(
               x = zero$x, y = zero$y, z = zero$z,
               text = TeX("0"),
               textangle = 0, ax = 0, ay = -35,
               font = list(color = "black", size = gfsize),
               arrowcolor = "gray", arrowsize = 1, arrowwidth = 0.5, arrowhead = 1),
               list(
               x = ell$x, y = ell$y, z = ell$z,
               text = TeX("\\ell"),
               textangle = 0, ax = 0, ay = -35,
               font = list(color = "black", size = gfsize),
               arrowcolor = "gray", arrowsize = 1, arrowwidth = 0.5, arrowhead = 1),   
                list(
               x = aLh$x, y = aLh$y, z = aLh$z,
               text = TeX("e_1"),
               textangle = 0, ax = 0, ay = -35,
               font = list(color = "black", size = gfsize),
               arrowcolor = "gray", arrowsize = 1, arrowwidth = 0.5, arrowhead = 1),
               list(
               x = aL$x, y = aL$y, z = aL$z,
               text = TeX("v_2"),
               textangle = 0, ax = 0, ay = -35,
               font = list(color = "black", size = gfsize),
               arrowcolor = "gray", arrowsize = 1, arrowwidth = 0.5, arrowhead = 1),      
             list(
               x = a0$x, y = a0$y, z = a0$z,
               text = TeX("v_1"),
               textangle = 0, ax = 0, ay = -35,
               font = list(color = "black", size = gfsize),
               arrowcolor = "gray", arrowsize = 1, arrowwidth = 0.5, arrowhead = 1))
            )
)


save(p2, file = here::here("data_files/graphs6p2.Rdata"))
load(here::here("data_files/graphs6p2.Rdata"))
p2

3 Tadpole and function

library(plotly)
n_smooth <- 250

TT <- 3*pi
# parameter
t <- seq(0, TT, length.out = n_smooth)

# speed
speed <- sqrt(1 + cos(t)^2)

# arc-length function
s <- pracma::cumtrapz(t, speed)
L <- max(s)
# s <- cumsum(c(0, diff(t) * (head(speed,-1) + tail(speed,-1))/2))
f1 <- function(t) exp(t/4)


f1_on_curve <- f1(s)
y_up_range <- max(f1_on_curve)

f2 <- function(t) sin(3*pi*t/L) + y_up_range
f1df_int <- data.frame(x = s, y = rep(0, n_smooth), z = f1_on_curve)

half_L <- L / 2
half_TT <- TT / 2
dist_to_move <- abs(half_L - half_TT)

y_shift <- 4
# curve alpha(t)
x <- t + dist_to_move
y <- sin(t) + y_shift
z <- rep(0,length(t))

curve_smooth <- data.frame(x = x, y = y, z = z)
f1_on_curve_smooth <- data.frame(x = x, y = y, z = f1_on_curve)

n_map <- 25
# points where we draw connectors
idx <- seq(1, length(t), length.out = n_map)

f1df_int_map <- f1df_int[idx,]
f1_on_curve_smooth_map <- f1_on_curve_smooth[idx,]

# Build mapping lines
rows <- lapply(1:n_map, function(i) {
  list(f1df_int_map[i, ], f1_on_curve_smooth_map[i, ], data.frame(x = NA, y = NA, z = NA))
})

resultee1 <- do.call(rbind, unlist(rows, recursive = FALSE))





curve_map <- data.frame(x = x[idx], y = y[idx], z = z[idx])
int_map <- data.frame(x = s[idx], y = rep(0, n_map), z = rep(0, n_map))

# 
# # Build mapping lines
# rows <- lapply(1:n_map, function(i) {
#   list(int_map[i, ], curve_map[i, ], data.frame(x = NA, y = NA, z = NA))
# })
# 
# result <- do.call(rbind, unlist(rows, recursive = FALSE))

s_circ <- L
radius <- s_circ / (2*pi)
x_shift_for_circle <- radius + TT + dist_to_move

theta <- seq(from=-pi,to=pi,length.out = n_smooth)
circle_curve <- data.frame(x = radius*cos(theta) + x_shift_for_circle, 
                    y = radius*sin(theta) + y_shift, 
                    z = rep(0, length(theta)))

arclength_circle <- radius * (theta + pi)

dist_to_move_circle <- abs(half_L - y_shift)

f2_on_curve <- f2(arclength_circle)
f2df_int <- data.frame(x = rep(x_shift_for_circle +2*radius, n_smooth),
                       y = arclength_circle-dist_to_move_circle, 
                       z = f2_on_curve)

f2_on_curve_smooth <- data.frame(x = radius*cos(theta) + x_shift_for_circle, 
                                 y = radius*sin(theta) + y_shift,
                                 z = f2_on_curve)

f2df_int_map <- f2df_int[idx,]
f2_on_curve_smooth_map <- f2_on_curve_smooth[idx,]

# Build mapping lines
rows <- lapply(1:n_map, function(i) {
  list(f2df_int_map[i, ], f2_on_curve_smooth_map[i, ], data.frame(x = NA, y = NA, z = NA))
})

resultee2 <- do.call(rbind, unlist(rows, recursive = FALSE))



circle_map <- circle_curve[idx, ]
int_map_circle <- data.frame(x = rep(x_shift_for_circle +2*radius, n_map), 
                             y = s[idx]-dist_to_move_circle, 
                             z = rep(0, n_map))

# # Build mapping lines for circle
# rows <- lapply(1:n_map, function(i) {
#   list(int_map_circle[i, ], circle_map[i, ], data.frame(x = NA, y = NA, z = NA))
# })
# 
# result_for_circle <- do.call(rbind, unlist(rows, recursive = FALSE))

v1 <- curve_map[1, ]
v2 <- curve_map[n_map, ]
e1 <- curve_map[ceiling(n_map/2), ]
e2 <- circle_map[ceiling(n_map/2), ]
zero1 <- int_map[1, ]
le1 <- int_map[n_map, ]

zero2 <- int_map_circle[1, ]
le2 <- int_map_circle[n_map, ]

vertex <- rbind(v1, v2, zero1, zero2, le1, le2)

zmin <- min(f1_on_curve, f2_on_curve)
zmax <- max(f1_on_curve, f2_on_curve)

# plot vertical lines from edges to curves
vertical_lines1 <- data.frame(x = rep(f1df_int$x, each = 3), 
                             y = rep(f1df_int$y, each = 3), 
                             z = unlist(lapply(f1df_int$z, function(zj) c(0, zj, NA))))

vertical_lines2 <- data.frame(x = rep(f2df_int$x, each = 3), 
                             y = rep(f2df_int$y, each = 3), 
                             z = unlist(lapply(f2df_int$z, function(zj) c(0, zj, NA))))

vertical_lines3 <- data.frame(x = rep(f1_on_curve_smooth$x, each = 3), 
                             y = rep(f1_on_curve_smooth$y, each = 3), 
                             z = unlist(lapply(f1_on_curve_smooth$z, function(zj) c(0, zj, NA))))

vertical_lines4 <- data.frame(x = rep(f2_on_curve_smooth$x, each = 3), 
                             y = rep(f2_on_curve_smooth$y, each = 3), 
                             z = unlist(lapply(f2_on_curve_smooth$z, function(zj) c(0, zj, NA))))

vertical_lines <- rbind(vertical_lines1, vertical_lines2, vertical_lines3, vertical_lines4)

p <- plot_ly() |>
  add_trace(data = rbind(curve_smooth, #smooth sin edge
                         data.frame(x = NA, y = NA, z = NA),
                         circle_curve, # smooth circle edge
                         data.frame(x = NA, y = NA, z = NA),
                         int_map, # interval for sin edge
                         data.frame(x = NA, y = NA, z = NA),
                         int_map_circle), # interval for circle edge
            x = ~x, y = ~y, z = ~z,
            type = "scatter3d", mode = "lines",
            line = list(width = 7, color = "black"),
            showlegend = FALSE) |>
  add_trace(data = vertical_lines,
            x = ~x, y = ~y, z = ~z,
            type = "scatter3d", mode = "lines",
            line = list(color = "lightgray", width = 0.5),
            showlegend = FALSE) |>
  add_trace(data = rbind(f1df_int, 
                         data.frame(x = NA, y = NA, z = NA),
                         f2df_int, 
                         data.frame(x = NA, y = NA, z = NA),
                         f1_on_curve_smooth, 
                         data.frame(x = NA, y = NA, z = NA),
                         f2_on_curve_smooth),
            x = ~x, y = ~y, z = ~z,
            type = "scatter3d", mode = "lines",
            line = list(
              color = ~z,                 # color based on height
              colorscale = "Viridis",     # choose any colorscale you like
              cmin = zmin,
              cmax = zmax,
              width = 7
              ),
            showlegend = FALSE) |>
  add_trace(data = rbind(resultee1, # mapping lines for sin
                         resultee2), # mapping lines for circle
            x = ~x, y = ~y, z = ~z,
            type = "scatter3d", mode = "lines",
            line = list(
              color = ~z,                 # color based on height
              colorscale = "Viridis",     # choose any colorscale you like
              cmin = zmin,
              cmax = zmax,
              width = 1
              ),
    showlegend = FALSE) |>
  add_trace(data = vertex,
            x = ~x,
            y = ~y,
            z = ~z,
            type = "scatter3d",
            mode = "markers",
            marker = list(size = 5, color = "black"),
            showlegend = FALSE) |> 
  add_trace(
    type = "cone",
    x = e1$x,
    y = e1$y,
    z = e1$z,
    u = 1,
    v = 0,
    w = 0,
    sizemode = "absolute",
    sizeref = 0.6,
    colorscale = list(c(0, 1), c("green", "green")),
    showscale = FALSE) |>
  add_trace(
    type = "cone",
    x = e2$x,
    y = e2$y,
    z = e2$z,
    u = 0,
    v = 1,
    w = 0,
    sizemode = "absolute",
    sizeref = 0.6,
    colorscale = list(c(0, 1), c("green", "green")),
    showscale = FALSE
  )


rv <- 2
p4tadpole_arclength <- p |>
  config(mathjax = 'cdn') |> 
  layout(p,
         font = list(family = "Palatino"),
            margin = list(l = 0, r = 0, b = 0, t = 0),
            scene = list(xaxis = list(title = list(text = "x", font = list(color = colaxnn)),  tickfont = list(color = colaxnn),  range = c(0, x_shift_for_circle +2*radius)*1.01),
              yaxis = list(title = list(text = "y", font = list(color = colaxnn)),  tickfont = list(color = colaxnn), range = range(int_map_circle$y)),
              zaxis = list(title = list(text = "z", font = list(color = colaxnn)),  tickfont = list(color = colaxnn), range = c(0, y_up_range+1)),
    aspectratio = list(x = x_shift_for_circle +2*radius, y = L, z = 4),
              camera = list(eye = list(x = 7*rv, y = -15*rv, z = 6*rv),
                            center = list(x = 0, y = 0, z = 0)),
    annotations = list(
      list(
               x = zero1$x, y = zero1$y, z = zero1$z,
               text = TeX("0"),
               textangle = 0, ax = 0, ay = -35,
               font = list(color = "black", size = gfsize),
               arrowcolor = "gray", arrowsize = 1, arrowwidth = 0.5, arrowhead = 1),
      list(
               x = zero2$x, y = zero2$y, z = zero2$z,
               text = TeX("0"),
               textangle = 0, ax = 0, ay = -35,
               font = list(color = "black", size = gfsize),
               arrowcolor = "gray", arrowsize = 1, arrowwidth = 0.5, arrowhead = 1),
      list(
               x = le1$x, y = le1$y, z = le1$z,
               text = TeX("\\ell_{e_1}"),
               textangle = 0, ax = 0, ay = -35,
               font = list(color = "black", size = gfsize),
               arrowcolor = "gray", arrowsize = 1, arrowwidth = 0.5, arrowhead = 1),
      list(
               x = le2$x, y = le2$y, z = le2$z,
               text = TeX("\\ell_{e_2}"),
               textangle = 0, ax = 0, ay = -35,
               font = list(color = "black", size = gfsize),
               arrowcolor = "gray", arrowsize = 1, arrowwidth = 0.5, arrowhead = 1),
                list(
               x = v1$x, y = v1$y, z = v1$z,
               text = TeX("v_1"),
               textangle = 0, ax = 0, ay = -35,
               font = list(color = "black", size = gfsize),
               arrowcolor = "gray", arrowsize = 1, arrowwidth = 0.5, arrowhead = 1),
               list(
               x = v2$x, y = v2$y, z = v2$z,
               text = TeX("v_2"),
               textangle = 0, ax = 0, ay = -35,
               font = list(color = "black", size = gfsize),
               arrowcolor = "gray", arrowsize = 1, arrowwidth = 0.5, arrowhead = 1),
               list(
               x = e1$x, y = e1$y, z = e1$z,
               text = TeX("e_1"),
               textangle = 0, ax = 0, ay = -35,
               font = list(color = "black", size = gfsize),
               arrowcolor = "gray", arrowsize = 1, arrowwidth = 0.5, arrowhead = 1),
               list(
               x = e2$x, y = e2$y, z = e2$z,
               text = TeX("e_2"),
               textangle = 0, ax = 0, ay = -35,
               font = list(color = "black", size = gfsize),
               arrowcolor = "gray", arrowsize = 1, arrowwidth = 0.5, arrowhead = 1))

  )
)

save(p4tadpole_arclength, file = here::here("data_files/graphs6p4tadpole_arclength.Rdata"))
load(here::here("data_files/graphs6p4tadpole_arclength.Rdata"))
p4tadpole_arclength

4 Tadpole arc-length parametrization

library(plotly)
n_smooth <- 250

TT <- 3*pi
# parameter
t <- seq(0, TT, length.out = n_smooth)

# speed
speed <- sqrt(1 + cos(t)^2)

# arc-length function
s <- pracma::cumtrapz(t, speed)
# s <- cumsum(c(0, diff(t) * (head(speed,-1) + tail(speed,-1))/2))

L <- max(s)

half_L <- L / 2
half_TT <- TT / 2
dist_to_move <- abs(half_L - half_TT)

y_shift <- 4
# curve alpha(t)
x <- t + dist_to_move
y <- sin(t) + y_shift
z <- rep(0,length(t))

curve_smooth <- data.frame(x = x, y = y, z = z)

# the following lines are just to get the range of f1 on the curve, so that we can set the range so both plots are similar
f1 <- function(t) exp(t/4)
f1_on_curve <- f1(s)
y_up_range <- max(f1_on_curve)


n_map <- 50
# points where we draw connectors
idx <- seq(1, length(t), length.out = n_map)


curve_map <- data.frame(x = x[idx], y = y[idx], z = z[idx])
int_map <- data.frame(x = s[idx], y = rep(0, n_map), z = rep(0, n_map))



# Build mapping lines
rows <- lapply(1:n_map, function(i) {
  list(int_map[i, ], curve_map[i, ], data.frame(x = NA, y = NA, z = NA))
})

result <- do.call(rbind, unlist(rows, recursive = FALSE))

s_circ <- L
radius <- s_circ / (2*pi)
x_shift_for_circle <- radius + TT + dist_to_move

theta <- seq(from=-pi,to=pi,length.out = n_smooth)
circle_curve <- data.frame(x = radius*cos(theta) + x_shift_for_circle, 
                    y = radius*sin(theta) + y_shift, 
                    z = rep(0, length(theta)))


circle_map <- circle_curve[idx, ]
dist_to_move_circle <- abs(half_L - y_shift)
int_map_circle <- data.frame(x = rep(x_shift_for_circle +2*radius, n_map), y = s[idx]-dist_to_move_circle, z = rep(0, n_map))

# Build mapping lines for circle
rows <- lapply(1:n_map, function(i) {
  list(int_map_circle[i, ], circle_map[i, ], data.frame(x = NA, y = NA, z = NA))
})

result_for_circle <- do.call(rbind, unlist(rows, recursive = FALSE))

v1 <- curve_map[1, ]
v2 <- curve_map[n_map, ]
e1 <- curve_map[ceiling(n_map/2), ]
e2 <- circle_map[ceiling(n_map/2), ]
zero1 <- int_map[1, ]
le1 <- int_map[n_map, ]

zero2 <- int_map_circle[1, ]
le2 <- int_map_circle[n_map, ]

vertex <- rbind(v1, v2, zero1, zero2, le1, le2)

p <- plot_ly() |>
  # smooth sin curve
  add_trace(data = rbind(curve_smooth, # smooth sin curve
                         data.frame(x = NA, y = NA, z = NA),
                         circle_curve), # smooth circle curve
  x = ~x, y = ~y, z = ~z,
  type = "scatter3d",
  mode = "lines",
  line = list(width = 7, color = "darkred"),
    showlegend = FALSE
) |>
add_trace(data = rbind(int_map, # interval for sin
                       data.frame(x = NA, y = NA, z = NA),
                       int_map_circle), # interval for circle
  x = ~x,
  y = ~y,
  z = ~z,
  type = "scatter3d",
  mode = "lines",
  line = list(width = 7, color = "#0000C8"),
    showlegend = FALSE
) |>
  add_trace(data = vertex,
  x = ~x,
  y = ~y,
  z = ~z,
  type = "scatter3d",
  mode = "markers",
  marker = list(size = 5, color = "black"),
    showlegend = FALSE
) |> add_trace(
    type = "cone",
    x = e1$x,
    y = e1$y,
    z = e1$z,
    u = 1,
    v = 0,
    w = 0,
    sizemode = "absolute",
    sizeref = 0.6,
    colorscale = list(c(0, 1), c("green", "green")),
    showscale = FALSE
  ) |> add_trace(
    type = "cone",
    x = e2$x,
    y = e2$y,
    z = e2$z,
    u = 0,
    v = 1,
    w = 0,
    sizemode = "absolute",
    sizeref = 0.6,
    colorscale = list(c(0, 1), c("green", "green")),
    showscale = FALSE
  )

pal <- colorRampPalette(c(
  "#0000C8",  # dark navy
  "#0074D9",  # royalblue
  "#7FDBFF",  # cyan
  "#2ECC40",  # green
  "#FFDC00",  # yellow
  "#FF851B",  # orange
  "#FF4136",  # red
  "darkred"
))(100)

gradient_line <- function(p0, p1, n = 20){

  t <- seq(0,1,length.out = n)

  x <- (1-t)*p0$x + t*p1$x
  y <- (1-t)*p0$y + t*p1$y
  z <- (1-t)*p0$z + t*p1$z

  data.frame(x=x,y=y,z=z,t=t)
}


dx <- int_map$x - curve_map$x
dy <- int_map$y - curve_map$y
dz <- int_map$z - curve_map$z

norm <- sqrt(dx^2 + dy^2 + dz^2)

u <- dx / norm
v <- dy / norm
w <- dz / norm

dxc <- int_map_circle$x - circle_map$x
dyc <- int_map_circle$y - circle_map$y
dzc <- int_map_circle$z - circle_map$z

normc <- sqrt(dxc^2 + dyc^2 + dzc^2)

uc <- dxc / normc
vc <- dyc / normc
wc <- dzc / normc

p <- p |>
  add_trace(
    type = "cone",
    x = int_map$x,
    y = int_map$y,
    z = int_map$z,
    u = u,
    v = v,
    w = w,
    sizemode = "absolute",
    sizeref = 0.7,
    anchor = "tip",
    colorscale = list(c(0, "#0000C8"), c(1, "#0000C8")),
    showscale = FALSE
  ) |> add_trace(
    type = "cone",
    x = int_map_circle$x,
    y = int_map_circle$y,
    z = int_map_circle$z,
    u = uc,
    v = vc,
    w = wc,
    sizemode = "absolute",
    sizeref = 0.4,
    anchor = "tip",
    colorscale = list(c(0, "#0000C8"), c(1, "#0000C8")),
    showscale = FALSE
  )

for(i in 1:n_map){

  g <- gradient_line(int_map[i,], curve_map[i,])

  for(j in 1:(nrow(g)-1)){

    seg <- g[j:(j+1),]

    col <- pal[ round(seg$t[1]*(length(pal)-1))+1 ]

    p <- p |> add_trace(
      data = seg,
      x = ~x, y = ~y, z = ~z,
      type = "scatter3d",
      mode = "lines",
      line = list(color = col, width = 1),
      showlegend = FALSE
    )
  }
}

for(i in 1:n_map){

  g <- gradient_line(int_map_circle[i,], circle_map[i,])

  for(j in 1:(nrow(g)-1)){

    seg <- g[j:(j+1),]

    col <- pal[ round(seg$t[1]*(length(pal)-1))+1 ]

    p <- p |> add_trace(
      data = seg,
      x = ~x, y = ~y, z = ~z,
      type = "scatter3d",
      mode = "lines",
      line = list(color = col, width = 1),
      showlegend = FALSE
    )
  }
}


rv <- 2
p4 <- p |>
  config(mathjax = 'cdn') |> 
  layout(p,
         font = list(family = "Palatino"),
            margin = list(l = 0, r = 0, b = 0, t = 0),
            scene = list(xaxis = list(title = list(text = "x", font = list(color = colaxnn)),  tickfont = list(color = colaxnn),  range = c(0, x_shift_for_circle +2*radius)*1.01),
              yaxis = list(title = list(text = "y", font = list(color = colaxnn)),  tickfont = list(color = colaxnn), range = range(int_map_circle$y)),
              zaxis = list(title = list(text = "z", font = list(color = colaxnn)),  tickfont = list(color = colaxnn), range = c(0, y_up_range+1)),
    aspectratio = list(x = x_shift_for_circle +2*radius, y = L, z = 4),
              camera = list(eye = list(x = 7*rv, y = -15*rv, z = 6*rv),
                            center = list(x = 0, y = 0, z = 0)),
    annotations = list(
      list(
               x = zero1$x, y = zero1$y, z = zero1$z,
               text = TeX("0"),
               textangle = 0, ax = 0, ay = -35,
               font = list(color = "black", size = gfsize),
               arrowcolor = "gray", arrowsize = 1, arrowwidth = 0.5, arrowhead = 1),
      list(
               x = zero2$x, y = zero2$y, z = zero2$z,
               text = TeX("0"),
               textangle = 0, ax = 0, ay = -35,
               font = list(color = "black", size = gfsize),
               arrowcolor = "gray", arrowsize = 1, arrowwidth = 0.5, arrowhead = 1),
      list(
               x = le1$x, y = le1$y, z = le1$z,
               text = TeX("\\ell_{e_1}"),
               textangle = 0, ax = 0, ay = -35,
               font = list(color = "black", size = gfsize),
               arrowcolor = "gray", arrowsize = 1, arrowwidth = 0.5, arrowhead = 1),
      list(
               x = le2$x, y = le2$y, z = le2$z,
               text = TeX("\\ell_{e_2}"),
               textangle = 0, ax = 0, ay = -35,
               font = list(color = "black", size = gfsize),
               arrowcolor = "gray", arrowsize = 1, arrowwidth = 0.5, arrowhead = 1),
                list(
               x = v1$x, y = v1$y, z = v1$z,
               text = TeX("v_1"),
               textangle = 0, ax = 0, ay = -35,
               font = list(color = "black", size = gfsize),
               arrowcolor = "gray", arrowsize = 1, arrowwidth = 0.5, arrowhead = 1),
               list(
               x = v2$x, y = v2$y, z = v2$z,
               text = TeX("v_2"),
               textangle = 0, ax = 0, ay = -35,
               font = list(color = "black", size = gfsize),
               arrowcolor = "gray", arrowsize = 1, arrowwidth = 0.5, arrowhead = 1),
               list(
               x = e1$x, y = e1$y, z = e1$z,
               text = TeX("e_1"),
               textangle = 0, ax = 0, ay = -35,
               font = list(color = "black", size = gfsize),
               arrowcolor = "gray", arrowsize = 1, arrowwidth = 0.5, arrowhead = 1),
               list(
               x = e2$x, y = e2$y, z = e2$z,
               text = TeX("e_2"),
               textangle = 0, ax = 0, ay = -35,
               font = list(color = "black", size = gfsize),
               arrowcolor = "gray", arrowsize = 1, arrowwidth = 0.5, arrowhead = 1))
  )
)

save(p4, file = here::here("data_files/graphs6p4.Rdata"))
load(here::here("data_files/graphs6p4.Rdata"))
p4

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), pracma v. 2.4.4 (Borchers 2023), 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.
Borchers, Hans W. 2023. pracma: Practical Numerical Math Functions. https://doi.org/10.32614/CRAN.package.pracma.
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.
LS0tCnRpdGxlOiAiQXJjLWxlbmd0aCBwYXJhbWV0cml6YXRpb24iCmRhdGU6ICJMYXN0IG1vZGlmaWVkOiBgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkLSVtLSVZLicpYCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBtYXRoamF4OiAiaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L25wbS9tYXRoamF4QDMvZXM1L3RleC1tbWwtY2h0bWwuanMiCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCiAgICB0aGVtZTogZmxhdGx5CiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUgIyBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIiB0byBoaWRlIGNvZGUgYW5kIGFkZCBhIGJ1dHRvbiB0byBzaG93IGl0CiAgICBkZl9wcmludDogcGFnZWQKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IHRydWUKICAgICAgc21vb3RoX3Njcm9sbDogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgY3NzOiB2aXN1YWwuY3NzCmFsd2F5c19hbGxvd19odG1sOiB0cnVlCmJpYmxpb2dyYXBoeTogCiAgLSByZWZlcmVuY2VzLmJpYgogIC0gZ3JhdGVmdWwtcmVmcy5iaWIKaGVhZGVyLWluY2x1ZGVzOgogIC0gXG5ld2NvbW1hbmR7XGFyfXtcbWF0aGJie1J9fQogIC0gXG5ld2NvbW1hbmR7XGxsYXZ9WzFde1xsZWZ0XHsjMVxyaWdodFx9fQogIC0gXG5ld2NvbW1hbmR7XHBhcmV9WzFde1xsZWZ0KCMxXHJpZ2h0KX0KICAtIFxuZXdjb21tYW5ke1xOY2FsfXtcbWF0aGNhbHtOfX0KICAtIFxuZXdjb21tYW5ke1xWY2FsfXtcbWF0aGNhbHtWfX0KICAtIFxuZXdjb21tYW5ke1xFY2FsfXtcbWF0aGNhbHtFfX0KICAtIFxuZXdjb21tYW5ke1xXY2FsfXtcbWF0aGNhbHtXfX0KICAtIFxuZXdjb21tYW5ke1xhbG1vc3RldmVyeXdoZXJlfXtcbWF0aHJte2EuZS59XDt9Ci0tLQoKR28gYmFjayB0byB0aGUgW0NvbnRlbnRzXShhYm91dC5odG1sKSBwYWdlLgoKPGRpdiBzdHlsZT0iY29sb3I6ICMyYzNlNTA7IHRleHQtYWxpZ246IHJpZ2h0OyI+CioqKioqKioqICAKPHN0cm9uZz5QcmVzcyBTaG93IHRvIHJldmVhbCB0aGUgY29kZSBjaHVua3MuPC9zdHJvbmc+ICAKCioqKioqKioqCjwvZGl2PgoKCmBgYHtyfQojIENyZWF0ZSBhIGNsaXBib2FyZCBidXR0b24gb24gdGhlIHJlbmRlYmxhY2sgSFRNTCBwYWdlCnNvdXJjZShoZXJlOjpoZXJlKCJjbGlwYm9hcmQuUiIpKTsgY2xpcGJvYXJkCiMgU2V0IHNlZWQgZm9yIHJlcHJvZHVjaWJpbGl0eQpzZXQuc2VlZCgxOTgyKSAKIyBTZXQgZ2xvYmFsIG9wdGlvbnMgZm9yIGFsbCBjb2RlIGNodW5rcwprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgIyBEaXNhYmxlIG1lc3NhZ2VzIHByaW50ZWQgYnkgUiBjb2RlIGNodW5rcwogIG1lc3NhZ2UgPSBGQUxTRSwgICAgCiAgIyBEaXNhYmxlIHdhcm5pbmdzIHByaW50ZWQgYnkgUiBjb2RlIGNodW5rcwogIHdhcm5pbmcgPSBGQUxTRSwgICAgCiAgIyBTaG93IFIgY29kZSB3aXRoaW4gY29kZSBjaHVua3MgaW4gb3V0cHV0CiAgZWNobyA9IFRSVUUsICAgICAgICAKICAjIEluY2x1ZGUgYm90aCBSIGNvZGUgYW5kIGl0cyByZXN1bHRzIGluIG91dHB1dAogIGluY2x1ZGUgPSBUUlVFLCAgICAgCiAgIyBFdmFsdWF0ZSBSIGNvZGUgY2h1bmtzCiAgZXZhbCA9IEZBTFNFLCAgICAgICAKICAjIEVuYWJsZSBjYWNoaW5nIG9mIFIgY29kZSBjaHVua3MgZm9yIGZhc3RlciByZW5kZXJpbmcKICBjYWNoZSA9IEZBTFNFLCAgICAgIAogICMgQWxpZ24gZmlndXJlcyBpbiB0aGUgY2VudGVyIG9mIHRoZSBvdXRwdXQKICBmaWcuYWxpZ24gPSAiY2VudGVyIiwKICAjIEVuYWJsZSByZXRpbmEgZGlzcGxheSBmb3IgaGlnaC1yZXNvbHV0aW9uIGZpZ3VyZXMKICByZXRpbmEgPSAyLAogICMgU2hvdyBlcnJvcnMgaW4gdGhlIG91dHB1dCBpbnN0ZWFkIG9mIHN0b3BwaW5nIHJlbmRlcmluZwogIGVycm9yID0gVFJVRSwKICAjIERvIG5vdCBjb2xsYXBzZSBjb2RlIGFuZCBvdXRwdXQgaW50byBhIHNpbmdsZSBibG9jawogIGNvbGxhcHNlID0gRkFMU0UKKQojIFN0YXJ0IHRoZSBmaWd1cmUgY291bnRlcgpmaWdfY291bnQgPC0gMAojIERlZmluZSB0aGUgY2FwdGlvbmVyIGZ1bmN0aW9uCmNhcHRpb25lciA8LSBmdW5jdGlvbihjYXB0aW9uKSB7CiAgZmlnX2NvdW50IDw8LSBmaWdfY291bnQgKyAxCiAgcGFzdGUwKCJGaWd1cmUgIiwgZmlnX2NvdW50LCAiOiAiLCBjYXB0aW9uKQp9CgpgYGAKCmBgYHtyLCBldmFsID0gVFJVRX0KbGlicmFyeShNZXRyaWNHcmFwaCkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHJlc2hhcGUyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHZpcmlkaXMpCmxpYnJhcnkocGxvdGx5KQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShzbGFja3IpCnNvdXJjZSgia2V5cy5SIikKc2xhY2tyX3NldHVwKHRva2VuID0gdG9rZW4pICMgdG9rZW4gY29tZXMgZnJvbSBrZXlzLlIKYGBgCgoKYGBge3J9CmNhcHR1cmUub3V0cHV0KAogIGtuaXRyOjpwdXJsKGhlcmU6OmhlcmUoImZ1bmN0aW9uYWxpdHkxLlJtZCIpLCBvdXRwdXQgPSBoZXJlOjpoZXJlKCJmdW5jdGlvbmFsaXR5MS5SIikpLAogIGZpbGUgPSBoZXJlOjpoZXJlKCJvbGQvcHVybF9sb2cudHh0IikKKQpzb3VyY2UoaGVyZTo6aGVyZSgiZnVuY3Rpb25hbGl0eTEuUiIpKQpgYGAKCgpGb3IgZXhhbXBsZSwgY29uc2lkZXIgdGhlIHJlZ3VsYXIgY3VydmUgJFxnYW1tYSh0KSA9IChidCArYyxhXGNvcyh0KSwgYVxzaW4odCkpJCBmb3IgJHRcaW5bMCxUXSQsIHdoZXJlICRhID0gMSQsICRiPTAuNSQsICRUPTZccGkkLCBhbmQgJGMkIGlzIGEgY29uc3RhbnQgdG8gYmUgZGVmaW5lZCBsYXRlci4gVGhlIGN1cnZlIGhhcyBhcmMtbGVuZ3RoICRcZWxsID0gVFxzcXJ0e2FeMitiXjJ9JCBhbmQgaXRzIGFyYy1sZW5ndGggcGFyYW1ldGVyaXphdGlvbiBpcyBnaXZlbiBieSAkXHRpbGRle1xnYW1tYX0ocykgPSBcZ2FtbWFcbGVmdChzL1xzcXJ0e2FeMitiXjJ9XHJpZ2h0KSQgZm9yICRzXGluWzAsXGVsbF0kLiBMZXQgJFxHYW1tYSA9IChcbWF0aGNhbHtWfSwgXG1hdGhjYWx7RX0pJCBkZW5vdGUgdGhlIG9uZSBlZGdlIGdyYXBoIGluZHVjZWQgYnkgJFx0aWxkZXtcZ2FtbWF9JCwgd2hlcmUgJFxtYXRoY2Fse1Z9ID0gXHt2XzEgPSBcdGlsZGV7XGdhbW1hfSgwKSwgdl8yID0gXHRpbGRle1xnYW1tYX0oXGVsbClcfSQgYW5kICRcbWF0aGNhbHtFfT1ce2UgPSBcdGlsZGV7XGdhbW1hfShbMCxcZWxsXSlcfSQuIFRoZW4gd2UgaGF2ZSB0aGUgaWRlbnRpZmljYXRpb24gJGU9WzAsXGVsbF0kLiBGb3IgdmlzdWFsaXphdGlvbiBwdXJwb3Nlcywgd2UgbGV0ICRjID0gVChcc3FydHthXjIrYl4yfS1iKS8yJC4gVGhpcyBtYWtlcyB0aGUgJFxnYW1tYSQgYW5kIHRoZSBpbnRlcnZhbCAkWzAsXGVsbF0kIGluIEZpZ3VyZX5ccmVme2FyY19sZW5ndGhfcGFyfSBjZW50ZXJlZCB3aXRoIHJlc3BlY3QgdG8gZWFjaCBvdGhlci4KCgoKIyBIZWxpeCBmdW5jdGlvbgoKYGBge3J9CmxpYnJhcnkocGxvdGx5KQoKIyBQYXJhbWV0ZXJzCmEgPC0gMQpiIDwtIDAuNQpUVCA8LSA2KnBpCiMgVG90YWwgYXJjLWxlbmd0aApMIDwtIHNxcnQoYV4yICsgYl4yKSAqIFRUCgpoYWxmX0wgPC0gTCAvIDIKCgptYXhfeCA8LSBiICogKEwgLyBzcXJ0KGFeMiArIGJeMikpCgpoYWxmX21heF94IDwtIG1heF94IC8gMgoKZGlzdF90b19tb3ZlIDwtIGhhbGZfTCAtIGhhbGZfbWF4X3gKCiMgQXJjLWxlbmd0aCBwYXJhbWV0cml6YXRpb24gKGhlbGl4IGFyb3VuZCB4LWF4aXMpCmFscGhhX3RpbGRlIDwtIGZ1bmN0aW9uKHMpewogIHQgPC0gcyAvIHNxcnQoYV4yICsgYl4yKQogIHhfc2hpZnQgPC0gVFQqKHNxcnQoYV4yICsgYl4yKSAtIGIpIC8gMgogIHggPC0gYiAqIHQgKyB4X3NoaWZ0CiAgeSA8LSBhICogY29zKHQpCiAgeiA8LSBhICogc2luKHQpCiAgZGF0YS5mcmFtZSh4PXgsIHk9eSwgej16KQp9CgphMCA9IGFscGhhX3RpbGRlKDApCmFMID0gYWxwaGFfdGlsZGUoTCkKYUxoID0gYWxwaGFfdGlsZGUoaGFsZl9MKQoKaGhoaCA8LSAzCmZmIDwtIGZ1bmN0aW9uKHMpIDIqYWJzKHNpbihoaGhoKnBpKnMvTCkpCmsgPC0gMDpoaGhoCnNfc3BlY2lhbCA8LSBrKkwvaGhoaAoKIyBTbW9vdGggaGVsaXgKbl9zbW9vdGggPC0gNTAwCgojc19zbW9vdGggPC0gc2VxKDAsIEwsIGxlbmd0aC5vdXQgPSBuX3Ntb290aCkKc19zbW9vdGggPC0gc29ydCh1bmlxdWUoYygKICBzZXEoMCwgTCwgbGVuZ3RoLm91dCA9IG5fc21vb3RoKSwKICBzX3NwZWNpYWwKKSkpCmN1cnZlX3Ntb290aCA8LSBhbHBoYV90aWxkZShzX3Ntb290aCkKCgojIFBvaW50cyBmb3IgbWFwcGluZyBsaW5lcwpuX21hcCA8LSAxMDAKc19tYXAgPC0gc2VxKDAsIEwsIGxlbmd0aC5vdXQgPSBuX21hcCkKY3VydmVfbWFwIDwtIGFscGhhX3RpbGRlKHNfbWFwKQoKCiNzX3NlbWlfY29hcnNlIDwtIHNlcSgwLCBMLCBsZW5ndGgub3V0ID0gbl9zbW9vdGgvMikKCiMgSW50ZXJ2YWwgYWxvbmcgeC1heGlzCmludF9tYXAgPC0gZGF0YS5mcmFtZSgKICB4ID0gc19tYXAsCiAgeSA9IHJlcCgwLCBuX21hcCkrNCwKICB6ID0gcmVwKDAsIG5fbWFwKQopCgoKZmZfZXZhbF9jb2Fyc2UgPC0gZmYoc19tYXApCgpmZl9ldmFsIDwtIGZmKHNfc21vb3RoKQoKY3VydmVfc21vb3RoJGhlaWdodCA8LSBmZl9ldmFsCgpzX3NlbWlfY29hcnNlIDwtIHNfc21vb3RoCmZmX3Nfc2VtaV9jb2Fyc2UgPC0gZmYoc19zZW1pX2NvYXJzZSkKeV9zZW1pX2NvYXJzZSA8LSByZXAoMCwgbGVuZ3RoKHNfc2VtaV9jb2Fyc2UpKSArIDQKCgpmZl9kZiA8LSBkYXRhLmZyYW1lKHggPSBzX3Ntb290aCwgeSA9IHJlcCgwLCBsZW5ndGgoc19zbW9vdGgpKSs0LCB6ID0gZmZfZXZhbCkKCmZmX2RmX2NvYXJzZSA8LSBkYXRhLmZyYW1lKHggPSBzX21hcCwgeSA9IHJlcCgwLCBsZW5ndGgoc19tYXApKSs0LCB6ID0gZmZfZXZhbF9jb2Fyc2UpCgojIEJ1aWxkIG1hcHBpbmcgbGluZXMKcm93cyA8LSBsYXBwbHkoMTpuX21hcCwgZnVuY3Rpb24oaSkgewogIGxpc3QoaW50X21hcFtpLCBdLCBjdXJ2ZV9tYXBbaSwgXSwgZGF0YS5mcmFtZSh4ID0gTkEsIHkgPSBOQSwgeiA9IE5BKSkKfSkKCnJlc3VsdCA8LSBkby5jYWxsKHJiaW5kLCB1bmxpc3Qocm93cywgcmVjdXJzaXZlID0gRkFMU0UpKQoKIyBCdWlsZCBtYXBwaW5nIGxpbmVzCnJvd3MgPC0gbGFwcGx5KDE6bl9tYXAsIGZ1bmN0aW9uKGkpIHsKICBsaXN0KGN1cnZlX21hcFtpLCBdLCBmZl9kZl9jb2Fyc2VbaSwgXSwgZGF0YS5mcmFtZSh4ID0gTkEsIHkgPSBOQSwgeiA9IE5BKSkKfSkKCnJlc3VsdDIgPC0gZG8uY2FsbChyYmluZCwgdW5saXN0KHJvd3MsIHJlY3Vyc2l2ZSA9IEZBTFNFKSkKCgpyb3dzIDwtIGxhcHBseSgxOm5fbWFwLCBmdW5jdGlvbihpKSB7CiAgdmFsIDwtIGZmX2V2YWxfY29hcnNlW2ldCgogIHJiaW5kKAogICAgY2JpbmQoY3VydmVfbWFwW2ksIF0sIHZhbCA9IHZhbCksCiAgICBjYmluZChmZl9kZl9jb2Fyc2VbaSwgXSwgdmFsID0gdmFsKSwKICAgIGRhdGEuZnJhbWUoeCA9IE5BLCB5ID0gTkEsIHogPSBOQSwgdmFsID0gTkEpCiAgKQp9KQoKcmVzdWx0MiA8LSBkby5jYWxsKHJiaW5kLCByb3dzKQoKZmZfZGZfY29hcnNlX25ldyA8LSByZXN1bHQyJHZhbAoKCgp6ZXJvIDwtIGludF9tYXBbMSwgXQplbGwgPC0gaW50X21hcFtuX21hcCwgXQoKdmVydGV4IDwtIHJiaW5kKGEwLCBhTCwgemVybywgZWxsKQoKCnR0dCA8LSBoYWxmX0wgLyBzcXJ0KGFeMiArIGJeMikKCnUgPC0gYgp2IDwtIC1hKnNpbih0dHQpCncgPC0gIGEqY29zKHR0dCkKCnptaW4gPC0gbWluKGZmX2V2YWwpCnptYXggPC0gbWF4KGZmX2V2YWwpCgojIFBsb3QKcCA8LSBwbG90X2x5KCkgfD4KICAKICAjIFNtb290aCBoZWxpeAogIGFkZF90cmFjZSgKICAgIGRhdGEgPSBjdXJ2ZV9zbW9vdGgsCiAgICB4ID0gfngsIHkgPSB+eSwgeiA9IH56LAogICAgdHlwZSA9ICJzY2F0dGVyM2QiLAogICAgbW9kZSA9ICJsaW5lcyIsCiAgICBsaW5lID0gbGlzdChjb2xvciA9IGZmX2V2YWwsIAogICAgICAgICAgICAgICAgY29sb3JzY2FsZSA9ICJWaXJpZGlzIiwKICAgICAgICAgICAgICAgIGNtaW4gPSB6bWluLAogICAgICAgICAgICAgICAgY21heCA9IHptYXgsCiAgICAgICAgICAgICAgICB3aWR0aCA9IDcpLAogICAgc2hvd2xlZ2VuZCA9IEZBTFNFCiAgKSB8PgogIAogICMgSW50ZXJ2YWwgWzAsTF0KICBhZGRfdHJhY2UoCiAgICBkYXRhID0gaW50X21hcCwKICAgIHggPSB+eCwgeSA9IH55LCB6ID0gfnosCiAgICB0eXBlID0gInNjYXR0ZXIzZCIsCiAgICBtb2RlID0gImxpbmVzIiwKICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gImJsYWNrIiwgd2lkdGggPSA3KSwKICAgIHNob3dsZWdlbmQgPSBGQUxTRQogICkgfD4KICBhZGRfdHJhY2UoCiAgZGF0YSA9IHJlc3VsdDIsCiAgeCA9IH54LCB5ID0gfnksIHogPSB+eiwKICB0eXBlID0gInNjYXR0ZXIzZCIsCiAgbW9kZSA9ICJsaW5lcyIsCiAgbGluZSA9IGxpc3QoCiAgICBjb2xvciA9IGZmX2RmX2NvYXJzZV9uZXcsCiAgICBjb2xvcnNjYWxlID0gIlZpcmlkaXMiLAogICAgY21pbiA9IHptaW4sCiAgICBjbWF4ID0gem1heCwKICAgIHdpZHRoID0gMQogICksCiAgc2hvd2xlZ2VuZCA9IEZBTFNFCikgfD4KICBhZGRfdHJhY2UoZGF0YSA9IHZlcnRleCwKICB4ID0gfngsCiAgeSA9IH55LAogIHogPSB+eiwKICB0eXBlID0gInNjYXR0ZXIzZCIsCiAgbW9kZSA9ICJtYXJrZXJzIiwKICBtYXJrZXIgPSBsaXN0KHNpemUgPSA1LCBjb2xvciA9ICJibGFjayIpLAogICAgc2hvd2xlZ2VuZCA9IEZBTFNFCikgfD4KICBhZGRfdHJhY2UoCiAgICB0eXBlID0gImNvbmUiLAogICAgeCA9IGFMaCR4LAogICAgeSA9IGFMaCR5LAogICAgeiA9IGFMaCR6LAogICAgdSA9IHUsCiAgICB2ID0gdiwKICAgIHcgPSB3LAogICAgc2l6ZW1vZGUgPSAiYWJzb2x1dGUiLAogICAgc2l6ZXJlZiA9IDAuNCwKICAgIGNvbG9yc2NhbGUgPSBsaXN0KGMoMCwgMSksIGMoImdyZWVuIiwgImdyZWVuIikpLAogICAgc2hvd3NjYWxlID0gRkFMU0UKICApIHw+CiAgIyBmdW5jdGlvbiBvbiBpbnRlcnZhbAogIGFkZF90cmFjZSgKICAgIGRhdGEgPSBmZl9kZiwKICAgIHggPSB+eCwgeSA9IH55LCB6ID0gfnosCiAgICB0eXBlID0gInNjYXR0ZXIzZCIsCiAgICBtb2RlID0gImxpbmVzIiwKICAgIGxpbmUgPSBsaXN0KAogICAgICBjb2xvciA9IH56LCAgICAgICAgICAgICAgICAgIyBjb2xvciBiYXNlZCBvbiBoZWlnaHQKICAgICAgY29sb3JzY2FsZSA9ICJWaXJpZGlzIiwgICAgICMgY2hvb3NlIGFueSBjb2xvcnNjYWxlIHlvdSBsaWtlCiAgICBjbWluID0gem1pbiwKICAgIGNtYXggPSB6bWF4LAogICAgICB3aWR0aCA9IDcKICAgICksCiAgICBzaG93bGVnZW5kID0gRkFMU0UKICApIHw+CiAgICBhZGRfdHJhY2UoeCA9IHJlcChzX3NlbWlfY29hcnNlLCBlYWNoID0gMyksIAogICAgICAgICAgICB5ID0gcmVwKHlfc2VtaV9jb2Fyc2UsIGVhY2ggPSAzKSwgCiAgICAgICAgICAgIHogPSB1bmxpc3QobGFwcGx5KGZmX3Nfc2VtaV9jb2Fyc2UsIGZ1bmN0aW9uKHpqKSBjKDAsIHpqLCBOQSkpKSwKICAgICAgICAgICAgdHlwZSA9ICJzY2F0dGVyM2QiLCAKICAgICAgICAgICAgbW9kZSA9ICJsaW5lcyIsCiAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gImxpZ2h0Z3JheSIsIHdpZHRoID0gMC41KSwKICAgICAgICAgICAgc2hvd2xlZ2VuZCA9IEZBTFNFKQogCmR4IDwtIGludF9tYXAkeCAtIGN1cnZlX21hcCR4CmR5IDwtIGludF9tYXAkeSAtIGN1cnZlX21hcCR5CmR6IDwtIGludF9tYXAkeiAtIGN1cnZlX21hcCR6Cgpub3JtIDwtIHNxcnQoZHheMiArIGR5XjIgKyBkel4yKQoKdSA8LSBkeCAvIG5vcm0KdiA8LSBkeSAvIG5vcm0KdyA8LSBkeiAvIG5vcm0KCmR4MiA8LSBjdXJ2ZV9tYXAkeCAtIGZmX2RmX2NvYXJzZSR4CmR5MiA8LSBjdXJ2ZV9tYXAkeSAtIGZmX2RmX2NvYXJzZSR5CmR6MiA8LSBjdXJ2ZV9tYXAkeiAtIGZmX2RmX2NvYXJzZSR6Cgpub3JtMiA8LSBzcXJ0KGR4Ml4yICsgZHkyXjIgKyBkejJeMikKCnUyIDwtIGR4MiAvIG5vcm0yCnYyIDwtIGR5MiAvIG5vcm0yCncyIDwtIGR6MiAvIG5vcm0yCgptYWcgPC0gc3FydCh1Ml4yICsgdjJeMiArIHcyXjIpCgpzY2FsZSA8LSBmZl9ldmFsX2NvYXJzZSAvIG1hZwoKdV9jb2wgPC0gdTIgKiBzY2FsZQp2X2NvbCA8LSB2MiAqIHNjYWxlCndfY29sIDwtIHcyICogc2NhbGUKCnAgPC0gcCB8PgphZGRfdHJhY2UoCiAgdHlwZSA9ICJjb25lIiwKICB4ID0gY3VydmVfbWFwJHgsCiAgeSA9IGN1cnZlX21hcCR5LAogIHogPSBjdXJ2ZV9tYXAkeiwKICB1ID0gdV9jb2wsCiAgdiA9IHZfY29sLAogIHcgPSB3X2NvbCwKICBjb2xvcnNjYWxlID0gIlZpcmlkaXMiLAogIGNtaW4gPSB6bWluLAogIGNtYXggPSB6bWF4LAogIHNpemVtb2RlID0gImFic29sdXRlIiwKICBzaXplcmVmID0gMC4yLAogIGFuY2hvciA9ICJ0aXAiLAogIHNob3dzY2FsZSA9IEZBTFNFCikKCnJ2IDwtIDAuNjUKcDJmaGVsaXggPC0gcCB8PiBjb25maWcobWF0aGpheCA9ICdjZG4nKSB8PgogICAgICAgICAgICBsYXlvdXQocCwKICAgICAgICAgICAgICAgICAgIGZvbnQgPSBsaXN0KGZhbWlseSA9ICJQYWxhdGlubyIpLAogICAgICAgICAgICBtYXJnaW4gPSBsaXN0KGwgPSAwLCByID0gMCwgYiA9IDAsIHQgPSAwKSwKICAgICAgICAgICAgc2NlbmUgPSBsaXN0KHhheGlzID0gbGlzdCh0aXRsZSA9IGxpc3QodGV4dCA9ICJ4IiwgZm9udCA9IGxpc3QoY29sb3IgPSBjb2xheG5uKSksICB0aWNrZm9udCA9IGxpc3QoY29sb3IgPSBjb2xheG5uKSwgIHJhbmdlID0gYygwLCBMKSksCiAgICAgICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gbGlzdCh0ZXh0ID0gInkiLCBmb250ID0gbGlzdChjb2xvciA9IGNvbGF4bm4pKSwgIHRpY2tmb250ID0gbGlzdChjb2xvciA9IGNvbGF4bm4pLCByYW5nZSA9IGMoLTEsIDQuMSkpLAogICAgICAgICAgICAgIHpheGlzID0gbGlzdCh0aXRsZSA9IGxpc3QodGV4dCA9ICJ6IiwgZm9udCA9IGxpc3QoY29sb3IgPSBjb2xheG5uKSksICB0aWNrZm9udCA9IGxpc3QoY29sb3IgPSBjb2xheG5uKSwgcmFuZ2UgPSBjKC0xLCBtYXgoZmZfZXZhbCkpKSwKICAgICAgICAgICAgICAjYXNwZWN0bW9kZT0iZGF0YSIsCiAgICAgICAgICAgICAgYXNwZWN0cmF0aW8gPSBsaXN0KHggPSBMLzksIHkgPSA1LzMsIHogPSAobWF4KGZmX2V2YWwpKzEpLzMpLAogICAgICAgICAgICAgIGNhbWVyYSA9IGxpc3QoZXllID0gbGlzdCh4ID0gLTMqcnYsIHkgPSAtNipydiwgeiA9IDYqcnYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY2VudGVyID0gbGlzdCh4ID0gMCwgeSA9IDAsIHogPSAwKSksCiAgICAgICAgICAgICAgYW5ub3RhdGlvbnMgPSBsaXN0KAogICAgICAgICAgICAgICAgbGlzdCgKICAgICAgICAgICAgICAgeCA9IHplcm8keCwgeSA9IHplcm8keSwgeiA9IHplcm8keiwKICAgICAgICAgICAgICAgdGV4dCA9IFRlWCgiMCIpLAogICAgICAgICAgICAgICB0ZXh0YW5nbGUgPSAwLCBheCA9IDAsIGF5ID0gLTM1LAogICAgICAgICAgICAgICBmb250ID0gbGlzdChjb2xvciA9ICJibGFjayIsIHNpemUgPSBnZnNpemUpLAogICAgICAgICAgICAgICBhcnJvd2NvbG9yID0gImdyYXkiLCBhcnJvd3NpemUgPSAxLCBhcnJvd3dpZHRoID0gMC41LCBhcnJvd2hlYWQgPSAxKSwKICAgICAgICAgICAgICAgbGlzdCgKICAgICAgICAgICAgICAgeCA9IGVsbCR4LCB5ID0gZWxsJHksIHogPSBlbGwkeiwKICAgICAgICAgICAgICAgdGV4dCA9IFRlWCgiXFxlbGwiKSwKICAgICAgICAgICAgICAgdGV4dGFuZ2xlID0gMCwgYXggPSAwLCBheSA9IC0zNSwKICAgICAgICAgICAgICAgZm9udCA9IGxpc3QoY29sb3IgPSAiYmxhY2siLCBzaXplID0gZ2ZzaXplKSwKICAgICAgICAgICAgICAgYXJyb3djb2xvciA9ICJncmF5IiwgYXJyb3dzaXplID0gMSwgYXJyb3d3aWR0aCA9IDAuNSwgYXJyb3doZWFkID0gMSksICAgIAogICAgICAgICAgICAgICAgbGlzdCgKICAgICAgICAgICAgICAgeCA9IGFMaCR4LCB5ID0gYUxoJHksIHogPSBhTGgkeiwKICAgICAgICAgICAgICAgdGV4dCA9IFRlWCgiZV8xIiksCiAgICAgICAgICAgICAgIHRleHRhbmdsZSA9IDAsIGF4ID0gMCwgYXkgPSAtMzUsCiAgICAgICAgICAgICAgIGZvbnQgPSBsaXN0KGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IGdmc2l6ZSksCiAgICAgICAgICAgICAgIGFycm93Y29sb3IgPSAiZ3JheSIsIGFycm93c2l6ZSA9IDEsIGFycm93d2lkdGggPSAwLjUsIGFycm93aGVhZCA9IDEpLAogICAgICAgICAgICAgICBsaXN0KAogICAgICAgICAgICAgICB4ID0gYUwkeCwgeSA9IGFMJHksIHogPSBhTCR6LAogICAgICAgICAgICAgICB0ZXh0ID0gVGVYKCJ2XzIiKSwKICAgICAgICAgICAgICAgdGV4dGFuZ2xlID0gMCwgYXggPSAwLCBheSA9IC0zNSwKICAgICAgICAgICAgICAgZm9udCA9IGxpc3QoY29sb3IgPSAiYmxhY2siLCBzaXplID0gZ2ZzaXplKSwKICAgICAgICAgICAgICAgYXJyb3djb2xvciA9ICJncmF5IiwgYXJyb3dzaXplID0gMSwgYXJyb3d3aWR0aCA9IDAuNSwgYXJyb3doZWFkID0gMSksICAgICAgCiAgICAgICAgICAgICBsaXN0KAogICAgICAgICAgICAgICB4ID0gYTAkeCwgeSA9IGEwJHksIHogPSBhMCR6LAogICAgICAgICAgICAgICB0ZXh0ID0gVGVYKCJ2XzEiKSwKICAgICAgICAgICAgICAgdGV4dGFuZ2xlID0gMCwgYXggPSAwLCBheSA9IC0zNSwKICAgICAgICAgICAgICAgZm9udCA9IGxpc3QoY29sb3IgPSAiYmxhY2siLCBzaXplID0gZ2ZzaXplKSwKICAgICAgICAgICAgICAgYXJyb3djb2xvciA9ICJncmF5IiwgYXJyb3dzaXplID0gMSwgYXJyb3d3aWR0aCA9IDAuNSwgYXJyb3doZWFkID0gMSkpCiAgICAgICAgICAgICkKKQoKc2F2ZShwMmZoZWxpeCwgZmlsZSA9IGhlcmU6OmhlcmUoImRhdGFfZmlsZXMvZ3JhcGhzNnAyZmhlbGl4LlJkYXRhIikpCmBgYAoKCgpgYGB7ciwgZXZhbCA9VFJVRSwgZmlnLmhlaWdodCA9IDcsIG91dC53aWR0aCA9ICIxMDAlIn0KbG9hZChoZXJlOjpoZXJlKCJkYXRhX2ZpbGVzL2dyYXBoczZwMmZoZWxpeC5SZGF0YSIpKQpwMmZoZWxpeApgYGAKCgoKIyBIZWxpeCBhcmMtbGVuZ3RoIHBhcmFtZXRyaXphdGlvbgoKYGBge3J9CmxpYnJhcnkocGxvdGx5KQoKIyBQYXJhbWV0ZXJzCmEgPC0gMQpiIDwtIDAuNQpUVCA8LSA2KnBpCiMgVG90YWwgYXJjLWxlbmd0aApMIDwtIHNxcnQoYV4yICsgYl4yKSAqIFRUCgpoYWxmX0wgPC0gTCAvIDIKCgptYXhfeCA8LSBiICogKEwgLyBzcXJ0KGFeMiArIGJeMikpCgpoYWxmX21heF94IDwtIG1heF94IC8gMgoKZGlzdF90b19tb3ZlIDwtIGhhbGZfTCAtIGhhbGZfbWF4X3gKCiMgQXJjLWxlbmd0aCBwYXJhbWV0cml6YXRpb24gKGhlbGl4IGFyb3VuZCB4LWF4aXMpCmFscGhhX3RpbGRlIDwtIGZ1bmN0aW9uKHMpewogIHQgPC0gcyAvIHNxcnQoYV4yICsgYl4yKQogIHhfc2hpZnQgPC0gVFQqKHNxcnQoYV4yICsgYl4yKSAtIGIpIC8gMgogIHggPC0gYiAqIHQgKyB4X3NoaWZ0CiAgeSA8LSBhICogY29zKHQpCiAgeiA8LSBhICogc2luKHQpCiAgZGF0YS5mcmFtZSh4PXgsIHk9eSwgej16KQp9CgphMCA9IGFscGhhX3RpbGRlKDApCmFMID0gYWxwaGFfdGlsZGUoTCkKYUxoID0gYWxwaGFfdGlsZGUoaGFsZl9MKQoKIyBTbW9vdGggaGVsaXgKbl9zbW9vdGggPC0gNTAwCnNfc21vb3RoIDwtIHNlcSgwLCBMLCBsZW5ndGgub3V0ID0gbl9zbW9vdGgpCmN1cnZlX3Ntb290aCA8LSBhbHBoYV90aWxkZShzX3Ntb290aCkKCiMgUG9pbnRzIGZvciBtYXBwaW5nIGxpbmVzCm5fbWFwIDwtIDEwMApzX21hcCA8LSBzZXEoMCwgTCwgbGVuZ3RoLm91dCA9IG5fbWFwKQpjdXJ2ZV9tYXAgPC0gYWxwaGFfdGlsZGUoc19tYXApCgojIEludGVydmFsIGFsb25nIHgtYXhpcwppbnRfbWFwIDwtIGRhdGEuZnJhbWUoCiAgeCA9IHNfbWFwLAogIHkgPSByZXAoMCwgbl9tYXApKzQsCiAgeiA9IHJlcCgwLCBuX21hcCkKKQoKemVybyA8LSBpbnRfbWFwWzEsIF0KZWxsIDwtIGludF9tYXBbbl9tYXAsIF0KCnZlcnRleCA8LSByYmluZChhMCwgYUwsIHplcm8sIGVsbCkKCgp0dHQgPC0gaGFsZl9MIC8gc3FydChhXjIgKyBiXjIpCgp1IDwtIGIKdiA8LSAtYSpzaW4odHR0KQp3IDwtICBhKmNvcyh0dHQpCgojIFBsb3QKcCA8LSBwbG90X2x5KCkgfD4KICAKICAjIFNtb290aCBoZWxpeAogIGFkZF90cmFjZSgKICAgIGRhdGEgPSBjdXJ2ZV9zbW9vdGgsCiAgICB4ID0gfngsIHkgPSB+eSwgeiA9IH56LAogICAgdHlwZSA9ICJzY2F0dGVyM2QiLAogICAgbW9kZSA9ICJsaW5lcyIsCiAgICBsaW5lID0gbGlzdChjb2xvciA9ICJkYXJrcmVkIiwgd2lkdGggPSA3KSwKICAgIHNob3dsZWdlbmQgPSBGQUxTRQogICkgfD4KICAKICAjIEludGVydmFsIFswLExdCiAgYWRkX3RyYWNlKAogICAgZGF0YSA9IGludF9tYXAsCiAgICB4ID0gfngsIHkgPSB+eSwgeiA9IH56LAogICAgdHlwZSA9ICJzY2F0dGVyM2QiLAogICAgbW9kZSA9ICJsaW5lcyIsCiAgICBsaW5lID0gbGlzdChjb2xvciA9ICIjMDAwMEM4Iiwgd2lkdGggPSA3KSwKICAgIHNob3dsZWdlbmQgPSBGQUxTRQogICkgfD4KICBhZGRfdHJhY2UoZGF0YSA9IHZlcnRleCwKICB4ID0gfngsCiAgeSA9IH55LAogIHogPSB+eiwKICB0eXBlID0gInNjYXR0ZXIzZCIsCiAgbW9kZSA9ICJtYXJrZXJzIiwKICBtYXJrZXIgPSBsaXN0KHNpemUgPSA1LCBjb2xvciA9ICJibGFjayIpLAogICAgc2hvd2xlZ2VuZCA9IEZBTFNFCikgfD4KICBhZGRfdHJhY2UoCiAgICB0eXBlID0gImNvbmUiLAogICAgeCA9IGFMaCR4LAogICAgeSA9IGFMaCR5LAogICAgeiA9IGFMaCR6LAogICAgdSA9IHUsCiAgICB2ID0gdiwKICAgIHcgPSB3LAogICAgc2l6ZW1vZGUgPSAiYWJzb2x1dGUiLAogICAgc2l6ZXJlZiA9IDAuNCwKICAgIGNvbG9yc2NhbGUgPSBsaXN0KGMoMCwgMSksIGMoImdyZWVuIiwgImdyZWVuIikpLAogICAgc2hvd3NjYWxlID0gRkFMU0UKICApCgpwYWwgPC0gY29sb3JSYW1wUGFsZXR0ZShjKAogICIjMDAwMEM4IiwgICMgZGFyayBuYXZ5CiAgIiMwMDc0RDkiLCAgIyByb3lhbGJsdWUKICAiIzdGREJGRiIsICAjIGN5YW4KICAiIzJFQ0M0MCIsICAjIGdyZWVuCiAgIiNGRkRDMDAiLCAgIyB5ZWxsb3cKICAiI0ZGODUxQiIsICAjIG9yYW5nZQogICIjRkY0MTM2IiwgICMgcmVkCiAgImRhcmtyZWQiCikpKDEwMCkKCmdyYWRpZW50X2xpbmUgPC0gZnVuY3Rpb24ocDAsIHAxLCBuID0gMjApewoKICB0IDwtIHNlcSgwLDEsbGVuZ3RoLm91dCA9IG4pCgogIHggPC0gKDEtdCkqcDAkeCArIHQqcDEkeAogIHkgPC0gKDEtdCkqcDAkeSArIHQqcDEkeQogIHogPC0gKDEtdCkqcDAkeiArIHQqcDEkegoKICBkYXRhLmZyYW1lKHg9eCx5PXksej16LHQ9dCkKfQoKCmR4IDwtIGludF9tYXAkeCAtIGN1cnZlX21hcCR4CmR5IDwtIGludF9tYXAkeSAtIGN1cnZlX21hcCR5CmR6IDwtIGludF9tYXAkeiAtIGN1cnZlX21hcCR6Cgpub3JtIDwtIHNxcnQoZHheMiArIGR5XjIgKyBkel4yKQoKdSA8LSBkeCAvIG5vcm0KdiA8LSBkeSAvIG5vcm0KdyA8LSBkeiAvIG5vcm0KCgpwIDwtIHAgfD4KICBhZGRfdHJhY2UoCiAgICB0eXBlID0gImNvbmUiLAogICAgeCA9IGludF9tYXAkeCwKICAgIHkgPSBpbnRfbWFwJHksCiAgICB6ID0gaW50X21hcCR6LAogICAgdSA9IHUsCiAgICB2ID0gdiwKICAgIHcgPSB3LAogICAgc2l6ZW1vZGUgPSAiYWJzb2x1dGUiLAogICAgc2l6ZXJlZiA9IDAuNiwKICAgIGFuY2hvciA9ICJ0aXAiLAogICAgY29sb3JzY2FsZSA9IGxpc3QoYygwLCAiIzAwMDBDOCIpLCBjKDEsICIjMDAwMEM4IikpLAogICAgc2hvd3NjYWxlID0gRkFMU0UKICApIAoKZm9yKGkgaW4gMTpuX21hcCl7CgogIGcgPC0gZ3JhZGllbnRfbGluZShpbnRfbWFwW2ksXSwgY3VydmVfbWFwW2ksXSkKCiAgZm9yKGogaW4gMToobnJvdyhnKS0xKSl7CgogICAgc2VnIDwtIGdbajooaisxKSxdCgogICAgY29sIDwtIHBhbFsgcm91bmQoc2VnJHRbMV0qKGxlbmd0aChwYWwpLTEpKSsxIF0KCiAgICBwIDwtIHAgfD4gYWRkX3RyYWNlKAogICAgICBkYXRhID0gc2VnLAogICAgICB4ID0gfngsIHkgPSB+eSwgeiA9IH56LAogICAgICB0eXBlID0gInNjYXR0ZXIzZCIsCiAgICAgIG1vZGUgPSAibGluZXMiLAogICAgICBsaW5lID0gbGlzdChjb2xvciA9IGNvbCwgd2lkdGggPSAxKSwKICAgICAgc2hvd2xlZ2VuZCA9IEZBTFNFCiAgICApCiAgfQp9CgpydiA8LSAwLjY1CnAyIDwtIHAgfD4gY29uZmlnKG1hdGhqYXggPSAnY2RuJykgfD4KICAgICAgICAgICAgbGF5b3V0KHAsCiAgICAgICAgICAgICAgICAgICBmb250ID0gbGlzdChmYW1pbHkgPSAiUGFsYXRpbm8iKSwKICAgICAgICAgICAgbWFyZ2luID0gbGlzdChsID0gMCwgciA9IDAsIGIgPSAwLCB0ID0gMCksCiAgICAgICAgICAgIHNjZW5lID0gbGlzdCh4YXhpcyA9IGxpc3QodGl0bGUgPSBsaXN0KHRleHQgPSAieCIsIGZvbnQgPSBsaXN0KGNvbG9yID0gY29sYXhubikpLCAgdGlja2ZvbnQgPSBsaXN0KGNvbG9yID0gY29sYXhubiksICByYW5nZSA9IGMoMCwgTCkpLAogICAgICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9IGxpc3QodGV4dCA9ICJ5IiwgZm9udCA9IGxpc3QoY29sb3IgPSBjb2xheG5uKSksICB0aWNrZm9udCA9IGxpc3QoY29sb3IgPSBjb2xheG5uKSwgcmFuZ2UgPSBjKC0xLCA0LjEpKSwKICAgICAgICAgICAgICB6YXhpcyA9IGxpc3QodGl0bGUgPSBsaXN0KHRleHQgPSAieiIsIGZvbnQgPSBsaXN0KGNvbG9yID0gY29sYXhubikpLCAgdGlja2ZvbnQgPSBsaXN0KGNvbG9yID0gY29sYXhubiksIHJhbmdlID0gYygtMSwgMikpLAogICAgICAgICAgICAgICNhc3BlY3Rtb2RlPSJkYXRhIiwKICAgICAgICAgICAgICBhc3BlY3RyYXRpbyA9IGxpc3QoeCA9IEwvOSwgeSA9IDUvMywgeiA9ICgyKzEpLzMpLAogICAgICAgICAgICAgIGNhbWVyYSA9IGxpc3QoZXllID0gbGlzdCh4ID0gLTMqcnYsIHkgPSAtNipydiwgeiA9IDYqcnYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY2VudGVyID0gbGlzdCh4ID0gMCwgeSA9IDAsIHogPSAwKSksCiAgICAgICAgICAgICAgYW5ub3RhdGlvbnMgPSBsaXN0KAogICAgICAgICAgICAgICAgbGlzdCgKICAgICAgICAgICAgICAgeCA9IHplcm8keCwgeSA9IHplcm8keSwgeiA9IHplcm8keiwKICAgICAgICAgICAgICAgdGV4dCA9IFRlWCgiMCIpLAogICAgICAgICAgICAgICB0ZXh0YW5nbGUgPSAwLCBheCA9IDAsIGF5ID0gLTM1LAogICAgICAgICAgICAgICBmb250ID0gbGlzdChjb2xvciA9ICJibGFjayIsIHNpemUgPSBnZnNpemUpLAogICAgICAgICAgICAgICBhcnJvd2NvbG9yID0gImdyYXkiLCBhcnJvd3NpemUgPSAxLCBhcnJvd3dpZHRoID0gMC41LCBhcnJvd2hlYWQgPSAxKSwKICAgICAgICAgICAgICAgbGlzdCgKICAgICAgICAgICAgICAgeCA9IGVsbCR4LCB5ID0gZWxsJHksIHogPSBlbGwkeiwKICAgICAgICAgICAgICAgdGV4dCA9IFRlWCgiXFxlbGwiKSwKICAgICAgICAgICAgICAgdGV4dGFuZ2xlID0gMCwgYXggPSAwLCBheSA9IC0zNSwKICAgICAgICAgICAgICAgZm9udCA9IGxpc3QoY29sb3IgPSAiYmxhY2siLCBzaXplID0gZ2ZzaXplKSwKICAgICAgICAgICAgICAgYXJyb3djb2xvciA9ICJncmF5IiwgYXJyb3dzaXplID0gMSwgYXJyb3d3aWR0aCA9IDAuNSwgYXJyb3doZWFkID0gMSksICAgCiAgICAgICAgICAgICAgICBsaXN0KAogICAgICAgICAgICAgICB4ID0gYUxoJHgsIHkgPSBhTGgkeSwgeiA9IGFMaCR6LAogICAgICAgICAgICAgICB0ZXh0ID0gVGVYKCJlXzEiKSwKICAgICAgICAgICAgICAgdGV4dGFuZ2xlID0gMCwgYXggPSAwLCBheSA9IC0zNSwKICAgICAgICAgICAgICAgZm9udCA9IGxpc3QoY29sb3IgPSAiYmxhY2siLCBzaXplID0gZ2ZzaXplKSwKICAgICAgICAgICAgICAgYXJyb3djb2xvciA9ICJncmF5IiwgYXJyb3dzaXplID0gMSwgYXJyb3d3aWR0aCA9IDAuNSwgYXJyb3doZWFkID0gMSksCiAgICAgICAgICAgICAgIGxpc3QoCiAgICAgICAgICAgICAgIHggPSBhTCR4LCB5ID0gYUwkeSwgeiA9IGFMJHosCiAgICAgICAgICAgICAgIHRleHQgPSBUZVgoInZfMiIpLAogICAgICAgICAgICAgICB0ZXh0YW5nbGUgPSAwLCBheCA9IDAsIGF5ID0gLTM1LAogICAgICAgICAgICAgICBmb250ID0gbGlzdChjb2xvciA9ICJibGFjayIsIHNpemUgPSBnZnNpemUpLAogICAgICAgICAgICAgICBhcnJvd2NvbG9yID0gImdyYXkiLCBhcnJvd3NpemUgPSAxLCBhcnJvd3dpZHRoID0gMC41LCBhcnJvd2hlYWQgPSAxKSwgICAgICAKICAgICAgICAgICAgIGxpc3QoCiAgICAgICAgICAgICAgIHggPSBhMCR4LCB5ID0gYTAkeSwgeiA9IGEwJHosCiAgICAgICAgICAgICAgIHRleHQgPSBUZVgoInZfMSIpLAogICAgICAgICAgICAgICB0ZXh0YW5nbGUgPSAwLCBheCA9IDAsIGF5ID0gLTM1LAogICAgICAgICAgICAgICBmb250ID0gbGlzdChjb2xvciA9ICJibGFjayIsIHNpemUgPSBnZnNpemUpLAogICAgICAgICAgICAgICBhcnJvd2NvbG9yID0gImdyYXkiLCBhcnJvd3NpemUgPSAxLCBhcnJvd3dpZHRoID0gMC41LCBhcnJvd2hlYWQgPSAxKSkKICAgICAgICAgICAgKQopCgoKc2F2ZShwMiwgZmlsZSA9IGhlcmU6OmhlcmUoImRhdGFfZmlsZXMvZ3JhcGhzNnAyLlJkYXRhIikpCmBgYAoKCmBgYHtyLCBldmFsID1UUlVFLCBmaWcuaGVpZ2h0ID0gNywgb3V0LndpZHRoID0gIjEwMCUifQpsb2FkKGhlcmU6OmhlcmUoImRhdGFfZmlsZXMvZ3JhcGhzNnAyLlJkYXRhIikpCnAyCmBgYAoKCgojIFRhZHBvbGUgYW5kIGZ1bmN0aW9uCgoKYGBge3J9CmxpYnJhcnkocGxvdGx5KQpuX3Ntb290aCA8LSAyNTAKClRUIDwtIDMqcGkKIyBwYXJhbWV0ZXIKdCA8LSBzZXEoMCwgVFQsIGxlbmd0aC5vdXQgPSBuX3Ntb290aCkKCiMgc3BlZWQKc3BlZWQgPC0gc3FydCgxICsgY29zKHQpXjIpCgojIGFyYy1sZW5ndGggZnVuY3Rpb24KcyA8LSBwcmFjbWE6OmN1bXRyYXB6KHQsIHNwZWVkKQpMIDwtIG1heChzKQojIHMgPC0gY3Vtc3VtKGMoMCwgZGlmZih0KSAqIChoZWFkKHNwZWVkLC0xKSArIHRhaWwoc3BlZWQsLTEpKS8yKSkKZjEgPC0gZnVuY3Rpb24odCkgZXhwKHQvNCkKCgpmMV9vbl9jdXJ2ZSA8LSBmMShzKQp5X3VwX3JhbmdlIDwtIG1heChmMV9vbl9jdXJ2ZSkKCmYyIDwtIGZ1bmN0aW9uKHQpIHNpbigzKnBpKnQvTCkgKyB5X3VwX3JhbmdlCmYxZGZfaW50IDwtIGRhdGEuZnJhbWUoeCA9IHMsIHkgPSByZXAoMCwgbl9zbW9vdGgpLCB6ID0gZjFfb25fY3VydmUpCgpoYWxmX0wgPC0gTCAvIDIKaGFsZl9UVCA8LSBUVCAvIDIKZGlzdF90b19tb3ZlIDwtIGFicyhoYWxmX0wgLSBoYWxmX1RUKQoKeV9zaGlmdCA8LSA0CiMgY3VydmUgYWxwaGEodCkKeCA8LSB0ICsgZGlzdF90b19tb3ZlCnkgPC0gc2luKHQpICsgeV9zaGlmdAp6IDwtIHJlcCgwLGxlbmd0aCh0KSkKCmN1cnZlX3Ntb290aCA8LSBkYXRhLmZyYW1lKHggPSB4LCB5ID0geSwgeiA9IHopCmYxX29uX2N1cnZlX3Ntb290aCA8LSBkYXRhLmZyYW1lKHggPSB4LCB5ID0geSwgeiA9IGYxX29uX2N1cnZlKQoKbl9tYXAgPC0gMjUKIyBwb2ludHMgd2hlcmUgd2UgZHJhdyBjb25uZWN0b3JzCmlkeCA8LSBzZXEoMSwgbGVuZ3RoKHQpLCBsZW5ndGgub3V0ID0gbl9tYXApCgpmMWRmX2ludF9tYXAgPC0gZjFkZl9pbnRbaWR4LF0KZjFfb25fY3VydmVfc21vb3RoX21hcCA8LSBmMV9vbl9jdXJ2ZV9zbW9vdGhbaWR4LF0KCiMgQnVpbGQgbWFwcGluZyBsaW5lcwpyb3dzIDwtIGxhcHBseSgxOm5fbWFwLCBmdW5jdGlvbihpKSB7CiAgbGlzdChmMWRmX2ludF9tYXBbaSwgXSwgZjFfb25fY3VydmVfc21vb3RoX21hcFtpLCBdLCBkYXRhLmZyYW1lKHggPSBOQSwgeSA9IE5BLCB6ID0gTkEpKQp9KQoKcmVzdWx0ZWUxIDwtIGRvLmNhbGwocmJpbmQsIHVubGlzdChyb3dzLCByZWN1cnNpdmUgPSBGQUxTRSkpCgoKCgoKY3VydmVfbWFwIDwtIGRhdGEuZnJhbWUoeCA9IHhbaWR4XSwgeSA9IHlbaWR4XSwgeiA9IHpbaWR4XSkKaW50X21hcCA8LSBkYXRhLmZyYW1lKHggPSBzW2lkeF0sIHkgPSByZXAoMCwgbl9tYXApLCB6ID0gcmVwKDAsIG5fbWFwKSkKCiMgCiMgIyBCdWlsZCBtYXBwaW5nIGxpbmVzCiMgcm93cyA8LSBsYXBwbHkoMTpuX21hcCwgZnVuY3Rpb24oaSkgewojICAgbGlzdChpbnRfbWFwW2ksIF0sIGN1cnZlX21hcFtpLCBdLCBkYXRhLmZyYW1lKHggPSBOQSwgeSA9IE5BLCB6ID0gTkEpKQojIH0pCiMgCiMgcmVzdWx0IDwtIGRvLmNhbGwocmJpbmQsIHVubGlzdChyb3dzLCByZWN1cnNpdmUgPSBGQUxTRSkpCgpzX2NpcmMgPC0gTApyYWRpdXMgPC0gc19jaXJjIC8gKDIqcGkpCnhfc2hpZnRfZm9yX2NpcmNsZSA8LSByYWRpdXMgKyBUVCArIGRpc3RfdG9fbW92ZQoKdGhldGEgPC0gc2VxKGZyb209LXBpLHRvPXBpLGxlbmd0aC5vdXQgPSBuX3Ntb290aCkKY2lyY2xlX2N1cnZlIDwtIGRhdGEuZnJhbWUoeCA9IHJhZGl1cypjb3ModGhldGEpICsgeF9zaGlmdF9mb3JfY2lyY2xlLCAKICAgICAgICAgICAgICAgICAgICB5ID0gcmFkaXVzKnNpbih0aGV0YSkgKyB5X3NoaWZ0LCAKICAgICAgICAgICAgICAgICAgICB6ID0gcmVwKDAsIGxlbmd0aCh0aGV0YSkpKQoKYXJjbGVuZ3RoX2NpcmNsZSA8LSByYWRpdXMgKiAodGhldGEgKyBwaSkKCmRpc3RfdG9fbW92ZV9jaXJjbGUgPC0gYWJzKGhhbGZfTCAtIHlfc2hpZnQpCgpmMl9vbl9jdXJ2ZSA8LSBmMihhcmNsZW5ndGhfY2lyY2xlKQpmMmRmX2ludCA8LSBkYXRhLmZyYW1lKHggPSByZXAoeF9zaGlmdF9mb3JfY2lyY2xlICsyKnJhZGl1cywgbl9zbW9vdGgpLAogICAgICAgICAgICAgICAgICAgICAgIHkgPSBhcmNsZW5ndGhfY2lyY2xlLWRpc3RfdG9fbW92ZV9jaXJjbGUsIAogICAgICAgICAgICAgICAgICAgICAgIHogPSBmMl9vbl9jdXJ2ZSkKCmYyX29uX2N1cnZlX3Ntb290aCA8LSBkYXRhLmZyYW1lKHggPSByYWRpdXMqY29zKHRoZXRhKSArIHhfc2hpZnRfZm9yX2NpcmNsZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSByYWRpdXMqc2luKHRoZXRhKSArIHlfc2hpZnQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHogPSBmMl9vbl9jdXJ2ZSkKCmYyZGZfaW50X21hcCA8LSBmMmRmX2ludFtpZHgsXQpmMl9vbl9jdXJ2ZV9zbW9vdGhfbWFwIDwtIGYyX29uX2N1cnZlX3Ntb290aFtpZHgsXQoKIyBCdWlsZCBtYXBwaW5nIGxpbmVzCnJvd3MgPC0gbGFwcGx5KDE6bl9tYXAsIGZ1bmN0aW9uKGkpIHsKICBsaXN0KGYyZGZfaW50X21hcFtpLCBdLCBmMl9vbl9jdXJ2ZV9zbW9vdGhfbWFwW2ksIF0sIGRhdGEuZnJhbWUoeCA9IE5BLCB5ID0gTkEsIHogPSBOQSkpCn0pCgpyZXN1bHRlZTIgPC0gZG8uY2FsbChyYmluZCwgdW5saXN0KHJvd3MsIHJlY3Vyc2l2ZSA9IEZBTFNFKSkKCgoKY2lyY2xlX21hcCA8LSBjaXJjbGVfY3VydmVbaWR4LCBdCmludF9tYXBfY2lyY2xlIDwtIGRhdGEuZnJhbWUoeCA9IHJlcCh4X3NoaWZ0X2Zvcl9jaXJjbGUgKzIqcmFkaXVzLCBuX21hcCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBzW2lkeF0tZGlzdF90b19tb3ZlX2NpcmNsZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeiA9IHJlcCgwLCBuX21hcCkpCgojICMgQnVpbGQgbWFwcGluZyBsaW5lcyBmb3IgY2lyY2xlCiMgcm93cyA8LSBsYXBwbHkoMTpuX21hcCwgZnVuY3Rpb24oaSkgewojICAgbGlzdChpbnRfbWFwX2NpcmNsZVtpLCBdLCBjaXJjbGVfbWFwW2ksIF0sIGRhdGEuZnJhbWUoeCA9IE5BLCB5ID0gTkEsIHogPSBOQSkpCiMgfSkKIyAKIyByZXN1bHRfZm9yX2NpcmNsZSA8LSBkby5jYWxsKHJiaW5kLCB1bmxpc3Qocm93cywgcmVjdXJzaXZlID0gRkFMU0UpKQoKdjEgPC0gY3VydmVfbWFwWzEsIF0KdjIgPC0gY3VydmVfbWFwW25fbWFwLCBdCmUxIDwtIGN1cnZlX21hcFtjZWlsaW5nKG5fbWFwLzIpLCBdCmUyIDwtIGNpcmNsZV9tYXBbY2VpbGluZyhuX21hcC8yKSwgXQp6ZXJvMSA8LSBpbnRfbWFwWzEsIF0KbGUxIDwtIGludF9tYXBbbl9tYXAsIF0KCnplcm8yIDwtIGludF9tYXBfY2lyY2xlWzEsIF0KbGUyIDwtIGludF9tYXBfY2lyY2xlW25fbWFwLCBdCgp2ZXJ0ZXggPC0gcmJpbmQodjEsIHYyLCB6ZXJvMSwgemVybzIsIGxlMSwgbGUyKQoKem1pbiA8LSBtaW4oZjFfb25fY3VydmUsIGYyX29uX2N1cnZlKQp6bWF4IDwtIG1heChmMV9vbl9jdXJ2ZSwgZjJfb25fY3VydmUpCgojIHBsb3QgdmVydGljYWwgbGluZXMgZnJvbSBlZGdlcyB0byBjdXJ2ZXMKdmVydGljYWxfbGluZXMxIDwtIGRhdGEuZnJhbWUoeCA9IHJlcChmMWRmX2ludCR4LCBlYWNoID0gMyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSByZXAoZjFkZl9pbnQkeSwgZWFjaCA9IDMpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB6ID0gdW5saXN0KGxhcHBseShmMWRmX2ludCR6LCBmdW5jdGlvbih6aikgYygwLCB6aiwgTkEpKSkpCgp2ZXJ0aWNhbF9saW5lczIgPC0gZGF0YS5mcmFtZSh4ID0gcmVwKGYyZGZfaW50JHgsIGVhY2ggPSAzKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHJlcChmMmRmX2ludCR5LCBlYWNoID0gMyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHogPSB1bmxpc3QobGFwcGx5KGYyZGZfaW50JHosIGZ1bmN0aW9uKHpqKSBjKDAsIHpqLCBOQSkpKSkKCnZlcnRpY2FsX2xpbmVzMyA8LSBkYXRhLmZyYW1lKHggPSByZXAoZjFfb25fY3VydmVfc21vb3RoJHgsIGVhY2ggPSAzKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHJlcChmMV9vbl9jdXJ2ZV9zbW9vdGgkeSwgZWFjaCA9IDMpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB6ID0gdW5saXN0KGxhcHBseShmMV9vbl9jdXJ2ZV9zbW9vdGgkeiwgZnVuY3Rpb24oemopIGMoMCwgemosIE5BKSkpKQoKdmVydGljYWxfbGluZXM0IDwtIGRhdGEuZnJhbWUoeCA9IHJlcChmMl9vbl9jdXJ2ZV9zbW9vdGgkeCwgZWFjaCA9IDMpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gcmVwKGYyX29uX2N1cnZlX3Ntb290aCR5LCBlYWNoID0gMyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHogPSB1bmxpc3QobGFwcGx5KGYyX29uX2N1cnZlX3Ntb290aCR6LCBmdW5jdGlvbih6aikgYygwLCB6aiwgTkEpKSkpCgp2ZXJ0aWNhbF9saW5lcyA8LSByYmluZCh2ZXJ0aWNhbF9saW5lczEsIHZlcnRpY2FsX2xpbmVzMiwgdmVydGljYWxfbGluZXMzLCB2ZXJ0aWNhbF9saW5lczQpCgpwIDwtIHBsb3RfbHkoKSB8PgogIGFkZF90cmFjZShkYXRhID0gcmJpbmQoY3VydmVfc21vb3RoLCAjc21vb3RoIHNpbiBlZGdlCiAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhLmZyYW1lKHggPSBOQSwgeSA9IE5BLCB6ID0gTkEpLAogICAgICAgICAgICAgICAgICAgICAgICAgY2lyY2xlX2N1cnZlLCAjIHNtb290aCBjaXJjbGUgZWRnZQogICAgICAgICAgICAgICAgICAgICAgICAgZGF0YS5mcmFtZSh4ID0gTkEsIHkgPSBOQSwgeiA9IE5BKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGludF9tYXAsICMgaW50ZXJ2YWwgZm9yIHNpbiBlZGdlCiAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhLmZyYW1lKHggPSBOQSwgeSA9IE5BLCB6ID0gTkEpLAogICAgICAgICAgICAgICAgICAgICAgICAgaW50X21hcF9jaXJjbGUpLCAjIGludGVydmFsIGZvciBjaXJjbGUgZWRnZQogICAgICAgICAgICB4ID0gfngsIHkgPSB+eSwgeiA9IH56LAogICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIzZCIsIG1vZGUgPSAibGluZXMiLAogICAgICAgICAgICBsaW5lID0gbGlzdCh3aWR0aCA9IDcsIGNvbG9yID0gImJsYWNrIiksCiAgICAgICAgICAgIHNob3dsZWdlbmQgPSBGQUxTRSkgfD4KICBhZGRfdHJhY2UoZGF0YSA9IHZlcnRpY2FsX2xpbmVzLAogICAgICAgICAgICB4ID0gfngsIHkgPSB+eSwgeiA9IH56LAogICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIzZCIsIG1vZGUgPSAibGluZXMiLAogICAgICAgICAgICBsaW5lID0gbGlzdChjb2xvciA9ICJsaWdodGdyYXkiLCB3aWR0aCA9IDAuNSksCiAgICAgICAgICAgIHNob3dsZWdlbmQgPSBGQUxTRSkgfD4KICBhZGRfdHJhY2UoZGF0YSA9IHJiaW5kKGYxZGZfaW50LCAKICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEuZnJhbWUoeCA9IE5BLCB5ID0gTkEsIHogPSBOQSksCiAgICAgICAgICAgICAgICAgICAgICAgICBmMmRmX2ludCwgCiAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhLmZyYW1lKHggPSBOQSwgeSA9IE5BLCB6ID0gTkEpLAogICAgICAgICAgICAgICAgICAgICAgICAgZjFfb25fY3VydmVfc21vb3RoLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEuZnJhbWUoeCA9IE5BLCB5ID0gTkEsIHogPSBOQSksCiAgICAgICAgICAgICAgICAgICAgICAgICBmMl9vbl9jdXJ2ZV9zbW9vdGgpLAogICAgICAgICAgICB4ID0gfngsIHkgPSB+eSwgeiA9IH56LAogICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIzZCIsIG1vZGUgPSAibGluZXMiLAogICAgICAgICAgICBsaW5lID0gbGlzdCgKICAgICAgICAgICAgICBjb2xvciA9IH56LCAgICAgICAgICAgICAgICAgIyBjb2xvciBiYXNlZCBvbiBoZWlnaHQKICAgICAgICAgICAgICBjb2xvcnNjYWxlID0gIlZpcmlkaXMiLCAgICAgIyBjaG9vc2UgYW55IGNvbG9yc2NhbGUgeW91IGxpa2UKICAgICAgICAgICAgICBjbWluID0gem1pbiwKICAgICAgICAgICAgICBjbWF4ID0gem1heCwKICAgICAgICAgICAgICB3aWR0aCA9IDcKICAgICAgICAgICAgICApLAogICAgICAgICAgICBzaG93bGVnZW5kID0gRkFMU0UpIHw+CiAgYWRkX3RyYWNlKGRhdGEgPSByYmluZChyZXN1bHRlZTEsICMgbWFwcGluZyBsaW5lcyBmb3Igc2luCiAgICAgICAgICAgICAgICAgICAgICAgICByZXN1bHRlZTIpLCAjIG1hcHBpbmcgbGluZXMgZm9yIGNpcmNsZQogICAgICAgICAgICB4ID0gfngsIHkgPSB+eSwgeiA9IH56LAogICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIzZCIsIG1vZGUgPSAibGluZXMiLAogICAgICAgICAgICBsaW5lID0gbGlzdCgKICAgICAgICAgICAgICBjb2xvciA9IH56LCAgICAgICAgICAgICAgICAgIyBjb2xvciBiYXNlZCBvbiBoZWlnaHQKICAgICAgICAgICAgICBjb2xvcnNjYWxlID0gIlZpcmlkaXMiLCAgICAgIyBjaG9vc2UgYW55IGNvbG9yc2NhbGUgeW91IGxpa2UKICAgICAgICAgICAgICBjbWluID0gem1pbiwKICAgICAgICAgICAgICBjbWF4ID0gem1heCwKICAgICAgICAgICAgICB3aWR0aCA9IDEKICAgICAgICAgICAgICApLAogICAgc2hvd2xlZ2VuZCA9IEZBTFNFKSB8PgogIGFkZF90cmFjZShkYXRhID0gdmVydGV4LAogICAgICAgICAgICB4ID0gfngsCiAgICAgICAgICAgIHkgPSB+eSwKICAgICAgICAgICAgeiA9IH56LAogICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIzZCIsCiAgICAgICAgICAgIG1vZGUgPSAibWFya2VycyIsCiAgICAgICAgICAgIG1hcmtlciA9IGxpc3Qoc2l6ZSA9IDUsIGNvbG9yID0gImJsYWNrIiksCiAgICAgICAgICAgIHNob3dsZWdlbmQgPSBGQUxTRSkgfD4gCiAgYWRkX3RyYWNlKAogICAgdHlwZSA9ICJjb25lIiwKICAgIHggPSBlMSR4LAogICAgeSA9IGUxJHksCiAgICB6ID0gZTEkeiwKICAgIHUgPSAxLAogICAgdiA9IDAsCiAgICB3ID0gMCwKICAgIHNpemVtb2RlID0gImFic29sdXRlIiwKICAgIHNpemVyZWYgPSAwLjYsCiAgICBjb2xvcnNjYWxlID0gbGlzdChjKDAsIDEpLCBjKCJncmVlbiIsICJncmVlbiIpKSwKICAgIHNob3dzY2FsZSA9IEZBTFNFKSB8PgogIGFkZF90cmFjZSgKICAgIHR5cGUgPSAiY29uZSIsCiAgICB4ID0gZTIkeCwKICAgIHkgPSBlMiR5LAogICAgeiA9IGUyJHosCiAgICB1ID0gMCwKICAgIHYgPSAxLAogICAgdyA9IDAsCiAgICBzaXplbW9kZSA9ICJhYnNvbHV0ZSIsCiAgICBzaXplcmVmID0gMC42LAogICAgY29sb3JzY2FsZSA9IGxpc3QoYygwLCAxKSwgYygiZ3JlZW4iLCAiZ3JlZW4iKSksCiAgICBzaG93c2NhbGUgPSBGQUxTRQogICkKCgpydiA8LSAyCnA0dGFkcG9sZV9hcmNsZW5ndGggPC0gcCB8PgogIGNvbmZpZyhtYXRoamF4ID0gJ2NkbicpIHw+IAogIGxheW91dChwLAogICAgICAgICBmb250ID0gbGlzdChmYW1pbHkgPSAiUGFsYXRpbm8iKSwKICAgICAgICAgICAgbWFyZ2luID0gbGlzdChsID0gMCwgciA9IDAsIGIgPSAwLCB0ID0gMCksCiAgICAgICAgICAgIHNjZW5lID0gbGlzdCh4YXhpcyA9IGxpc3QodGl0bGUgPSBsaXN0KHRleHQgPSAieCIsIGZvbnQgPSBsaXN0KGNvbG9yID0gY29sYXhubikpLCAgdGlja2ZvbnQgPSBsaXN0KGNvbG9yID0gY29sYXhubiksICByYW5nZSA9IGMoMCwgeF9zaGlmdF9mb3JfY2lyY2xlICsyKnJhZGl1cykqMS4wMSksCiAgICAgICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gbGlzdCh0ZXh0ID0gInkiLCBmb250ID0gbGlzdChjb2xvciA9IGNvbGF4bm4pKSwgIHRpY2tmb250ID0gbGlzdChjb2xvciA9IGNvbGF4bm4pLCByYW5nZSA9IHJhbmdlKGludF9tYXBfY2lyY2xlJHkpKSwKICAgICAgICAgICAgICB6YXhpcyA9IGxpc3QodGl0bGUgPSBsaXN0KHRleHQgPSAieiIsIGZvbnQgPSBsaXN0KGNvbG9yID0gY29sYXhubikpLCAgdGlja2ZvbnQgPSBsaXN0KGNvbG9yID0gY29sYXhubiksIHJhbmdlID0gYygwLCB5X3VwX3JhbmdlKzEpKSwKICAgIGFzcGVjdHJhdGlvID0gbGlzdCh4ID0geF9zaGlmdF9mb3JfY2lyY2xlICsyKnJhZGl1cywgeSA9IEwsIHogPSA0KSwKICAgICAgICAgICAgICBjYW1lcmEgPSBsaXN0KGV5ZSA9IGxpc3QoeCA9IDcqcnYsIHkgPSAtMTUqcnYsIHogPSA2KnJ2KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNlbnRlciA9IGxpc3QoeCA9IDAsIHkgPSAwLCB6ID0gMCkpLAogICAgYW5ub3RhdGlvbnMgPSBsaXN0KAogICAgICBsaXN0KAogICAgICAgICAgICAgICB4ID0gemVybzEkeCwgeSA9IHplcm8xJHksIHogPSB6ZXJvMSR6LAogICAgICAgICAgICAgICB0ZXh0ID0gVGVYKCIwIiksCiAgICAgICAgICAgICAgIHRleHRhbmdsZSA9IDAsIGF4ID0gMCwgYXkgPSAtMzUsCiAgICAgICAgICAgICAgIGZvbnQgPSBsaXN0KGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IGdmc2l6ZSksCiAgICAgICAgICAgICAgIGFycm93Y29sb3IgPSAiZ3JheSIsIGFycm93c2l6ZSA9IDEsIGFycm93d2lkdGggPSAwLjUsIGFycm93aGVhZCA9IDEpLAogICAgICBsaXN0KAogICAgICAgICAgICAgICB4ID0gemVybzIkeCwgeSA9IHplcm8yJHksIHogPSB6ZXJvMiR6LAogICAgICAgICAgICAgICB0ZXh0ID0gVGVYKCIwIiksCiAgICAgICAgICAgICAgIHRleHRhbmdsZSA9IDAsIGF4ID0gMCwgYXkgPSAtMzUsCiAgICAgICAgICAgICAgIGZvbnQgPSBsaXN0KGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IGdmc2l6ZSksCiAgICAgICAgICAgICAgIGFycm93Y29sb3IgPSAiZ3JheSIsIGFycm93c2l6ZSA9IDEsIGFycm93d2lkdGggPSAwLjUsIGFycm93aGVhZCA9IDEpLAogICAgICBsaXN0KAogICAgICAgICAgICAgICB4ID0gbGUxJHgsIHkgPSBsZTEkeSwgeiA9IGxlMSR6LAogICAgICAgICAgICAgICB0ZXh0ID0gVGVYKCJcXGVsbF97ZV8xfSIpLAogICAgICAgICAgICAgICB0ZXh0YW5nbGUgPSAwLCBheCA9IDAsIGF5ID0gLTM1LAogICAgICAgICAgICAgICBmb250ID0gbGlzdChjb2xvciA9ICJibGFjayIsIHNpemUgPSBnZnNpemUpLAogICAgICAgICAgICAgICBhcnJvd2NvbG9yID0gImdyYXkiLCBhcnJvd3NpemUgPSAxLCBhcnJvd3dpZHRoID0gMC41LCBhcnJvd2hlYWQgPSAxKSwKICAgICAgbGlzdCgKICAgICAgICAgICAgICAgeCA9IGxlMiR4LCB5ID0gbGUyJHksIHogPSBsZTIkeiwKICAgICAgICAgICAgICAgdGV4dCA9IFRlWCgiXFxlbGxfe2VfMn0iKSwKICAgICAgICAgICAgICAgdGV4dGFuZ2xlID0gMCwgYXggPSAwLCBheSA9IC0zNSwKICAgICAgICAgICAgICAgZm9udCA9IGxpc3QoY29sb3IgPSAiYmxhY2siLCBzaXplID0gZ2ZzaXplKSwKICAgICAgICAgICAgICAgYXJyb3djb2xvciA9ICJncmF5IiwgYXJyb3dzaXplID0gMSwgYXJyb3d3aWR0aCA9IDAuNSwgYXJyb3doZWFkID0gMSksCiAgICAgICAgICAgICAgICBsaXN0KAogICAgICAgICAgICAgICB4ID0gdjEkeCwgeSA9IHYxJHksIHogPSB2MSR6LAogICAgICAgICAgICAgICB0ZXh0ID0gVGVYKCJ2XzEiKSwKICAgICAgICAgICAgICAgdGV4dGFuZ2xlID0gMCwgYXggPSAwLCBheSA9IC0zNSwKICAgICAgICAgICAgICAgZm9udCA9IGxpc3QoY29sb3IgPSAiYmxhY2siLCBzaXplID0gZ2ZzaXplKSwKICAgICAgICAgICAgICAgYXJyb3djb2xvciA9ICJncmF5IiwgYXJyb3dzaXplID0gMSwgYXJyb3d3aWR0aCA9IDAuNSwgYXJyb3doZWFkID0gMSksCiAgICAgICAgICAgICAgIGxpc3QoCiAgICAgICAgICAgICAgIHggPSB2MiR4LCB5ID0gdjIkeSwgeiA9IHYyJHosCiAgICAgICAgICAgICAgIHRleHQgPSBUZVgoInZfMiIpLAogICAgICAgICAgICAgICB0ZXh0YW5nbGUgPSAwLCBheCA9IDAsIGF5ID0gLTM1LAogICAgICAgICAgICAgICBmb250ID0gbGlzdChjb2xvciA9ICJibGFjayIsIHNpemUgPSBnZnNpemUpLAogICAgICAgICAgICAgICBhcnJvd2NvbG9yID0gImdyYXkiLCBhcnJvd3NpemUgPSAxLCBhcnJvd3dpZHRoID0gMC41LCBhcnJvd2hlYWQgPSAxKSwKICAgICAgICAgICAgICAgbGlzdCgKICAgICAgICAgICAgICAgeCA9IGUxJHgsIHkgPSBlMSR5LCB6ID0gZTEkeiwKICAgICAgICAgICAgICAgdGV4dCA9IFRlWCgiZV8xIiksCiAgICAgICAgICAgICAgIHRleHRhbmdsZSA9IDAsIGF4ID0gMCwgYXkgPSAtMzUsCiAgICAgICAgICAgICAgIGZvbnQgPSBsaXN0KGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IGdmc2l6ZSksCiAgICAgICAgICAgICAgIGFycm93Y29sb3IgPSAiZ3JheSIsIGFycm93c2l6ZSA9IDEsIGFycm93d2lkdGggPSAwLjUsIGFycm93aGVhZCA9IDEpLAogICAgICAgICAgICAgICBsaXN0KAogICAgICAgICAgICAgICB4ID0gZTIkeCwgeSA9IGUyJHksIHogPSBlMiR6LAogICAgICAgICAgICAgICB0ZXh0ID0gVGVYKCJlXzIiKSwKICAgICAgICAgICAgICAgdGV4dGFuZ2xlID0gMCwgYXggPSAwLCBheSA9IC0zNSwKICAgICAgICAgICAgICAgZm9udCA9IGxpc3QoY29sb3IgPSAiYmxhY2siLCBzaXplID0gZ2ZzaXplKSwKICAgICAgICAgICAgICAgYXJyb3djb2xvciA9ICJncmF5IiwgYXJyb3dzaXplID0gMSwgYXJyb3d3aWR0aCA9IDAuNSwgYXJyb3doZWFkID0gMSkpCgogICkKKQoKc2F2ZShwNHRhZHBvbGVfYXJjbGVuZ3RoLCBmaWxlID0gaGVyZTo6aGVyZSgiZGF0YV9maWxlcy9ncmFwaHM2cDR0YWRwb2xlX2FyY2xlbmd0aC5SZGF0YSIpKQpgYGAKCgoKCgpgYGB7ciwgZXZhbCA9VFJVRSwgZmlnLmhlaWdodCA9IDcsIG91dC53aWR0aCA9ICIxMDAlIn0KbG9hZChoZXJlOjpoZXJlKCJkYXRhX2ZpbGVzL2dyYXBoczZwNHRhZHBvbGVfYXJjbGVuZ3RoLlJkYXRhIikpCnA0dGFkcG9sZV9hcmNsZW5ndGgKYGBgCgoKCgojIFRhZHBvbGUgYXJjLWxlbmd0aCBwYXJhbWV0cml6YXRpb24KCmBgYHtyfQpsaWJyYXJ5KHBsb3RseSkKbl9zbW9vdGggPC0gMjUwCgpUVCA8LSAzKnBpCiMgcGFyYW1ldGVyCnQgPC0gc2VxKDAsIFRULCBsZW5ndGgub3V0ID0gbl9zbW9vdGgpCgojIHNwZWVkCnNwZWVkIDwtIHNxcnQoMSArIGNvcyh0KV4yKQoKIyBhcmMtbGVuZ3RoIGZ1bmN0aW9uCnMgPC0gcHJhY21hOjpjdW10cmFweih0LCBzcGVlZCkKIyBzIDwtIGN1bXN1bShjKDAsIGRpZmYodCkgKiAoaGVhZChzcGVlZCwtMSkgKyB0YWlsKHNwZWVkLC0xKSkvMikpCgpMIDwtIG1heChzKQoKaGFsZl9MIDwtIEwgLyAyCmhhbGZfVFQgPC0gVFQgLyAyCmRpc3RfdG9fbW92ZSA8LSBhYnMoaGFsZl9MIC0gaGFsZl9UVCkKCnlfc2hpZnQgPC0gNAojIGN1cnZlIGFscGhhKHQpCnggPC0gdCArIGRpc3RfdG9fbW92ZQp5IDwtIHNpbih0KSArIHlfc2hpZnQKeiA8LSByZXAoMCxsZW5ndGgodCkpCgpjdXJ2ZV9zbW9vdGggPC0gZGF0YS5mcmFtZSh4ID0geCwgeSA9IHksIHogPSB6KQoKIyB0aGUgZm9sbG93aW5nIGxpbmVzIGFyZSBqdXN0IHRvIGdldCB0aGUgcmFuZ2Ugb2YgZjEgb24gdGhlIGN1cnZlLCBzbyB0aGF0IHdlIGNhbiBzZXQgdGhlIHJhbmdlIHNvIGJvdGggcGxvdHMgYXJlIHNpbWlsYXIKZjEgPC0gZnVuY3Rpb24odCkgZXhwKHQvNCkKZjFfb25fY3VydmUgPC0gZjEocykKeV91cF9yYW5nZSA8LSBtYXgoZjFfb25fY3VydmUpCgoKbl9tYXAgPC0gNTAKIyBwb2ludHMgd2hlcmUgd2UgZHJhdyBjb25uZWN0b3JzCmlkeCA8LSBzZXEoMSwgbGVuZ3RoKHQpLCBsZW5ndGgub3V0ID0gbl9tYXApCgoKY3VydmVfbWFwIDwtIGRhdGEuZnJhbWUoeCA9IHhbaWR4XSwgeSA9IHlbaWR4XSwgeiA9IHpbaWR4XSkKaW50X21hcCA8LSBkYXRhLmZyYW1lKHggPSBzW2lkeF0sIHkgPSByZXAoMCwgbl9tYXApLCB6ID0gcmVwKDAsIG5fbWFwKSkKCgoKIyBCdWlsZCBtYXBwaW5nIGxpbmVzCnJvd3MgPC0gbGFwcGx5KDE6bl9tYXAsIGZ1bmN0aW9uKGkpIHsKICBsaXN0KGludF9tYXBbaSwgXSwgY3VydmVfbWFwW2ksIF0sIGRhdGEuZnJhbWUoeCA9IE5BLCB5ID0gTkEsIHogPSBOQSkpCn0pCgpyZXN1bHQgPC0gZG8uY2FsbChyYmluZCwgdW5saXN0KHJvd3MsIHJlY3Vyc2l2ZSA9IEZBTFNFKSkKCnNfY2lyYyA8LSBMCnJhZGl1cyA8LSBzX2NpcmMgLyAoMipwaSkKeF9zaGlmdF9mb3JfY2lyY2xlIDwtIHJhZGl1cyArIFRUICsgZGlzdF90b19tb3ZlCgp0aGV0YSA8LSBzZXEoZnJvbT0tcGksdG89cGksbGVuZ3RoLm91dCA9IG5fc21vb3RoKQpjaXJjbGVfY3VydmUgPC0gZGF0YS5mcmFtZSh4ID0gcmFkaXVzKmNvcyh0aGV0YSkgKyB4X3NoaWZ0X2Zvcl9jaXJjbGUsIAogICAgICAgICAgICAgICAgICAgIHkgPSByYWRpdXMqc2luKHRoZXRhKSArIHlfc2hpZnQsIAogICAgICAgICAgICAgICAgICAgIHogPSByZXAoMCwgbGVuZ3RoKHRoZXRhKSkpCgoKY2lyY2xlX21hcCA8LSBjaXJjbGVfY3VydmVbaWR4LCBdCmRpc3RfdG9fbW92ZV9jaXJjbGUgPC0gYWJzKGhhbGZfTCAtIHlfc2hpZnQpCmludF9tYXBfY2lyY2xlIDwtIGRhdGEuZnJhbWUoeCA9IHJlcCh4X3NoaWZ0X2Zvcl9jaXJjbGUgKzIqcmFkaXVzLCBuX21hcCksIHkgPSBzW2lkeF0tZGlzdF90b19tb3ZlX2NpcmNsZSwgeiA9IHJlcCgwLCBuX21hcCkpCgojIEJ1aWxkIG1hcHBpbmcgbGluZXMgZm9yIGNpcmNsZQpyb3dzIDwtIGxhcHBseSgxOm5fbWFwLCBmdW5jdGlvbihpKSB7CiAgbGlzdChpbnRfbWFwX2NpcmNsZVtpLCBdLCBjaXJjbGVfbWFwW2ksIF0sIGRhdGEuZnJhbWUoeCA9IE5BLCB5ID0gTkEsIHogPSBOQSkpCn0pCgpyZXN1bHRfZm9yX2NpcmNsZSA8LSBkby5jYWxsKHJiaW5kLCB1bmxpc3Qocm93cywgcmVjdXJzaXZlID0gRkFMU0UpKQoKdjEgPC0gY3VydmVfbWFwWzEsIF0KdjIgPC0gY3VydmVfbWFwW25fbWFwLCBdCmUxIDwtIGN1cnZlX21hcFtjZWlsaW5nKG5fbWFwLzIpLCBdCmUyIDwtIGNpcmNsZV9tYXBbY2VpbGluZyhuX21hcC8yKSwgXQp6ZXJvMSA8LSBpbnRfbWFwWzEsIF0KbGUxIDwtIGludF9tYXBbbl9tYXAsIF0KCnplcm8yIDwtIGludF9tYXBfY2lyY2xlWzEsIF0KbGUyIDwtIGludF9tYXBfY2lyY2xlW25fbWFwLCBdCgp2ZXJ0ZXggPC0gcmJpbmQodjEsIHYyLCB6ZXJvMSwgemVybzIsIGxlMSwgbGUyKQoKcCA8LSBwbG90X2x5KCkgfD4KICAjIHNtb290aCBzaW4gY3VydmUKICBhZGRfdHJhY2UoZGF0YSA9IHJiaW5kKGN1cnZlX3Ntb290aCwgIyBzbW9vdGggc2luIGN1cnZlCiAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhLmZyYW1lKHggPSBOQSwgeSA9IE5BLCB6ID0gTkEpLAogICAgICAgICAgICAgICAgICAgICAgICAgY2lyY2xlX2N1cnZlKSwgIyBzbW9vdGggY2lyY2xlIGN1cnZlCiAgeCA9IH54LCB5ID0gfnksIHogPSB+eiwKICB0eXBlID0gInNjYXR0ZXIzZCIsCiAgbW9kZSA9ICJsaW5lcyIsCiAgbGluZSA9IGxpc3Qod2lkdGggPSA3LCBjb2xvciA9ICJkYXJrcmVkIiksCiAgICBzaG93bGVnZW5kID0gRkFMU0UKKSB8PgphZGRfdHJhY2UoZGF0YSA9IHJiaW5kKGludF9tYXAsICMgaW50ZXJ2YWwgZm9yIHNpbgogICAgICAgICAgICAgICAgICAgICAgIGRhdGEuZnJhbWUoeCA9IE5BLCB5ID0gTkEsIHogPSBOQSksCiAgICAgICAgICAgICAgICAgICAgICAgaW50X21hcF9jaXJjbGUpLCAjIGludGVydmFsIGZvciBjaXJjbGUKICB4ID0gfngsCiAgeSA9IH55LAogIHogPSB+eiwKICB0eXBlID0gInNjYXR0ZXIzZCIsCiAgbW9kZSA9ICJsaW5lcyIsCiAgbGluZSA9IGxpc3Qod2lkdGggPSA3LCBjb2xvciA9ICIjMDAwMEM4IiksCiAgICBzaG93bGVnZW5kID0gRkFMU0UKKSB8PgogIGFkZF90cmFjZShkYXRhID0gdmVydGV4LAogIHggPSB+eCwKICB5ID0gfnksCiAgeiA9IH56LAogIHR5cGUgPSAic2NhdHRlcjNkIiwKICBtb2RlID0gIm1hcmtlcnMiLAogIG1hcmtlciA9IGxpc3Qoc2l6ZSA9IDUsIGNvbG9yID0gImJsYWNrIiksCiAgICBzaG93bGVnZW5kID0gRkFMU0UKKSB8PiBhZGRfdHJhY2UoCiAgICB0eXBlID0gImNvbmUiLAogICAgeCA9IGUxJHgsCiAgICB5ID0gZTEkeSwKICAgIHogPSBlMSR6LAogICAgdSA9IDEsCiAgICB2ID0gMCwKICAgIHcgPSAwLAogICAgc2l6ZW1vZGUgPSAiYWJzb2x1dGUiLAogICAgc2l6ZXJlZiA9IDAuNiwKICAgIGNvbG9yc2NhbGUgPSBsaXN0KGMoMCwgMSksIGMoImdyZWVuIiwgImdyZWVuIikpLAogICAgc2hvd3NjYWxlID0gRkFMU0UKICApIHw+IGFkZF90cmFjZSgKICAgIHR5cGUgPSAiY29uZSIsCiAgICB4ID0gZTIkeCwKICAgIHkgPSBlMiR5LAogICAgeiA9IGUyJHosCiAgICB1ID0gMCwKICAgIHYgPSAxLAogICAgdyA9IDAsCiAgICBzaXplbW9kZSA9ICJhYnNvbHV0ZSIsCiAgICBzaXplcmVmID0gMC42LAogICAgY29sb3JzY2FsZSA9IGxpc3QoYygwLCAxKSwgYygiZ3JlZW4iLCAiZ3JlZW4iKSksCiAgICBzaG93c2NhbGUgPSBGQUxTRQogICkKCnBhbCA8LSBjb2xvclJhbXBQYWxldHRlKGMoCiAgIiMwMDAwQzgiLCAgIyBkYXJrIG5hdnkKICAiIzAwNzREOSIsICAjIHJveWFsYmx1ZQogICIjN0ZEQkZGIiwgICMgY3lhbgogICIjMkVDQzQwIiwgICMgZ3JlZW4KICAiI0ZGREMwMCIsICAjIHllbGxvdwogICIjRkY4NTFCIiwgICMgb3JhbmdlCiAgIiNGRjQxMzYiLCAgIyByZWQKICAiZGFya3JlZCIKKSkoMTAwKQoKZ3JhZGllbnRfbGluZSA8LSBmdW5jdGlvbihwMCwgcDEsIG4gPSAyMCl7CgogIHQgPC0gc2VxKDAsMSxsZW5ndGgub3V0ID0gbikKCiAgeCA8LSAoMS10KSpwMCR4ICsgdCpwMSR4CiAgeSA8LSAoMS10KSpwMCR5ICsgdCpwMSR5CiAgeiA8LSAoMS10KSpwMCR6ICsgdCpwMSR6CgogIGRhdGEuZnJhbWUoeD14LHk9eSx6PXosdD10KQp9CgoKZHggPC0gaW50X21hcCR4IC0gY3VydmVfbWFwJHgKZHkgPC0gaW50X21hcCR5IC0gY3VydmVfbWFwJHkKZHogPC0gaW50X21hcCR6IC0gY3VydmVfbWFwJHoKCm5vcm0gPC0gc3FydChkeF4yICsgZHleMiArIGR6XjIpCgp1IDwtIGR4IC8gbm9ybQp2IDwtIGR5IC8gbm9ybQp3IDwtIGR6IC8gbm9ybQoKZHhjIDwtIGludF9tYXBfY2lyY2xlJHggLSBjaXJjbGVfbWFwJHgKZHljIDwtIGludF9tYXBfY2lyY2xlJHkgLSBjaXJjbGVfbWFwJHkKZHpjIDwtIGludF9tYXBfY2lyY2xlJHogLSBjaXJjbGVfbWFwJHoKCm5vcm1jIDwtIHNxcnQoZHhjXjIgKyBkeWNeMiArIGR6Y14yKQoKdWMgPC0gZHhjIC8gbm9ybWMKdmMgPC0gZHljIC8gbm9ybWMKd2MgPC0gZHpjIC8gbm9ybWMKCnAgPC0gcCB8PgogIGFkZF90cmFjZSgKICAgIHR5cGUgPSAiY29uZSIsCiAgICB4ID0gaW50X21hcCR4LAogICAgeSA9IGludF9tYXAkeSwKICAgIHogPSBpbnRfbWFwJHosCiAgICB1ID0gdSwKICAgIHYgPSB2LAogICAgdyA9IHcsCiAgICBzaXplbW9kZSA9ICJhYnNvbHV0ZSIsCiAgICBzaXplcmVmID0gMC43LAogICAgYW5jaG9yID0gInRpcCIsCiAgICBjb2xvcnNjYWxlID0gbGlzdChjKDAsICIjMDAwMEM4IiksIGMoMSwgIiMwMDAwQzgiKSksCiAgICBzaG93c2NhbGUgPSBGQUxTRQogICkgfD4gYWRkX3RyYWNlKAogICAgdHlwZSA9ICJjb25lIiwKICAgIHggPSBpbnRfbWFwX2NpcmNsZSR4LAogICAgeSA9IGludF9tYXBfY2lyY2xlJHksCiAgICB6ID0gaW50X21hcF9jaXJjbGUkeiwKICAgIHUgPSB1YywKICAgIHYgPSB2YywKICAgIHcgPSB3YywKICAgIHNpemVtb2RlID0gImFic29sdXRlIiwKICAgIHNpemVyZWYgPSAwLjQsCiAgICBhbmNob3IgPSAidGlwIiwKICAgIGNvbG9yc2NhbGUgPSBsaXN0KGMoMCwgIiMwMDAwQzgiKSwgYygxLCAiIzAwMDBDOCIpKSwKICAgIHNob3dzY2FsZSA9IEZBTFNFCiAgKQoKZm9yKGkgaW4gMTpuX21hcCl7CgogIGcgPC0gZ3JhZGllbnRfbGluZShpbnRfbWFwW2ksXSwgY3VydmVfbWFwW2ksXSkKCiAgZm9yKGogaW4gMToobnJvdyhnKS0xKSl7CgogICAgc2VnIDwtIGdbajooaisxKSxdCgogICAgY29sIDwtIHBhbFsgcm91bmQoc2VnJHRbMV0qKGxlbmd0aChwYWwpLTEpKSsxIF0KCiAgICBwIDwtIHAgfD4gYWRkX3RyYWNlKAogICAgICBkYXRhID0gc2VnLAogICAgICB4ID0gfngsIHkgPSB+eSwgeiA9IH56LAogICAgICB0eXBlID0gInNjYXR0ZXIzZCIsCiAgICAgIG1vZGUgPSAibGluZXMiLAogICAgICBsaW5lID0gbGlzdChjb2xvciA9IGNvbCwgd2lkdGggPSAxKSwKICAgICAgc2hvd2xlZ2VuZCA9IEZBTFNFCiAgICApCiAgfQp9Cgpmb3IoaSBpbiAxOm5fbWFwKXsKCiAgZyA8LSBncmFkaWVudF9saW5lKGludF9tYXBfY2lyY2xlW2ksXSwgY2lyY2xlX21hcFtpLF0pCgogIGZvcihqIGluIDE6KG5yb3coZyktMSkpewoKICAgIHNlZyA8LSBnW2o6KGorMSksXQoKICAgIGNvbCA8LSBwYWxbIHJvdW5kKHNlZyR0WzFdKihsZW5ndGgocGFsKS0xKSkrMSBdCgogICAgcCA8LSBwIHw+IGFkZF90cmFjZSgKICAgICAgZGF0YSA9IHNlZywKICAgICAgeCA9IH54LCB5ID0gfnksIHogPSB+eiwKICAgICAgdHlwZSA9ICJzY2F0dGVyM2QiLAogICAgICBtb2RlID0gImxpbmVzIiwKICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSBjb2wsIHdpZHRoID0gMSksCiAgICAgIHNob3dsZWdlbmQgPSBGQUxTRQogICAgKQogIH0KfQoKCnJ2IDwtIDIKcDQgPC0gcCB8PgogIGNvbmZpZyhtYXRoamF4ID0gJ2NkbicpIHw+IAogIGxheW91dChwLAogICAgICAgICBmb250ID0gbGlzdChmYW1pbHkgPSAiUGFsYXRpbm8iKSwKICAgICAgICAgICAgbWFyZ2luID0gbGlzdChsID0gMCwgciA9IDAsIGIgPSAwLCB0ID0gMCksCiAgICAgICAgICAgIHNjZW5lID0gbGlzdCh4YXhpcyA9IGxpc3QodGl0bGUgPSBsaXN0KHRleHQgPSAieCIsIGZvbnQgPSBsaXN0KGNvbG9yID0gY29sYXhubikpLCAgdGlja2ZvbnQgPSBsaXN0KGNvbG9yID0gY29sYXhubiksICByYW5nZSA9IGMoMCwgeF9zaGlmdF9mb3JfY2lyY2xlICsyKnJhZGl1cykqMS4wMSksCiAgICAgICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gbGlzdCh0ZXh0ID0gInkiLCBmb250ID0gbGlzdChjb2xvciA9IGNvbGF4bm4pKSwgIHRpY2tmb250ID0gbGlzdChjb2xvciA9IGNvbGF4bm4pLCByYW5nZSA9IHJhbmdlKGludF9tYXBfY2lyY2xlJHkpKSwKICAgICAgICAgICAgICB6YXhpcyA9IGxpc3QodGl0bGUgPSBsaXN0KHRleHQgPSAieiIsIGZvbnQgPSBsaXN0KGNvbG9yID0gY29sYXhubikpLCAgdGlja2ZvbnQgPSBsaXN0KGNvbG9yID0gY29sYXhubiksIHJhbmdlID0gYygwLCB5X3VwX3JhbmdlKzEpKSwKICAgIGFzcGVjdHJhdGlvID0gbGlzdCh4ID0geF9zaGlmdF9mb3JfY2lyY2xlICsyKnJhZGl1cywgeSA9IEwsIHogPSA0KSwKICAgICAgICAgICAgICBjYW1lcmEgPSBsaXN0KGV5ZSA9IGxpc3QoeCA9IDcqcnYsIHkgPSAtMTUqcnYsIHogPSA2KnJ2KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNlbnRlciA9IGxpc3QoeCA9IDAsIHkgPSAwLCB6ID0gMCkpLAogICAgYW5ub3RhdGlvbnMgPSBsaXN0KAogICAgICBsaXN0KAogICAgICAgICAgICAgICB4ID0gemVybzEkeCwgeSA9IHplcm8xJHksIHogPSB6ZXJvMSR6LAogICAgICAgICAgICAgICB0ZXh0ID0gVGVYKCIwIiksCiAgICAgICAgICAgICAgIHRleHRhbmdsZSA9IDAsIGF4ID0gMCwgYXkgPSAtMzUsCiAgICAgICAgICAgICAgIGZvbnQgPSBsaXN0KGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IGdmc2l6ZSksCiAgICAgICAgICAgICAgIGFycm93Y29sb3IgPSAiZ3JheSIsIGFycm93c2l6ZSA9IDEsIGFycm93d2lkdGggPSAwLjUsIGFycm93aGVhZCA9IDEpLAogICAgICBsaXN0KAogICAgICAgICAgICAgICB4ID0gemVybzIkeCwgeSA9IHplcm8yJHksIHogPSB6ZXJvMiR6LAogICAgICAgICAgICAgICB0ZXh0ID0gVGVYKCIwIiksCiAgICAgICAgICAgICAgIHRleHRhbmdsZSA9IDAsIGF4ID0gMCwgYXkgPSAtMzUsCiAgICAgICAgICAgICAgIGZvbnQgPSBsaXN0KGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IGdmc2l6ZSksCiAgICAgICAgICAgICAgIGFycm93Y29sb3IgPSAiZ3JheSIsIGFycm93c2l6ZSA9IDEsIGFycm93d2lkdGggPSAwLjUsIGFycm93aGVhZCA9IDEpLAogICAgICBsaXN0KAogICAgICAgICAgICAgICB4ID0gbGUxJHgsIHkgPSBsZTEkeSwgeiA9IGxlMSR6LAogICAgICAgICAgICAgICB0ZXh0ID0gVGVYKCJcXGVsbF97ZV8xfSIpLAogICAgICAgICAgICAgICB0ZXh0YW5nbGUgPSAwLCBheCA9IDAsIGF5ID0gLTM1LAogICAgICAgICAgICAgICBmb250ID0gbGlzdChjb2xvciA9ICJibGFjayIsIHNpemUgPSBnZnNpemUpLAogICAgICAgICAgICAgICBhcnJvd2NvbG9yID0gImdyYXkiLCBhcnJvd3NpemUgPSAxLCBhcnJvd3dpZHRoID0gMC41LCBhcnJvd2hlYWQgPSAxKSwKICAgICAgbGlzdCgKICAgICAgICAgICAgICAgeCA9IGxlMiR4LCB5ID0gbGUyJHksIHogPSBsZTIkeiwKICAgICAgICAgICAgICAgdGV4dCA9IFRlWCgiXFxlbGxfe2VfMn0iKSwKICAgICAgICAgICAgICAgdGV4dGFuZ2xlID0gMCwgYXggPSAwLCBheSA9IC0zNSwKICAgICAgICAgICAgICAgZm9udCA9IGxpc3QoY29sb3IgPSAiYmxhY2siLCBzaXplID0gZ2ZzaXplKSwKICAgICAgICAgICAgICAgYXJyb3djb2xvciA9ICJncmF5IiwgYXJyb3dzaXplID0gMSwgYXJyb3d3aWR0aCA9IDAuNSwgYXJyb3doZWFkID0gMSksCiAgICAgICAgICAgICAgICBsaXN0KAogICAgICAgICAgICAgICB4ID0gdjEkeCwgeSA9IHYxJHksIHogPSB2MSR6LAogICAgICAgICAgICAgICB0ZXh0ID0gVGVYKCJ2XzEiKSwKICAgICAgICAgICAgICAgdGV4dGFuZ2xlID0gMCwgYXggPSAwLCBheSA9IC0zNSwKICAgICAgICAgICAgICAgZm9udCA9IGxpc3QoY29sb3IgPSAiYmxhY2siLCBzaXplID0gZ2ZzaXplKSwKICAgICAgICAgICAgICAgYXJyb3djb2xvciA9ICJncmF5IiwgYXJyb3dzaXplID0gMSwgYXJyb3d3aWR0aCA9IDAuNSwgYXJyb3doZWFkID0gMSksCiAgICAgICAgICAgICAgIGxpc3QoCiAgICAgICAgICAgICAgIHggPSB2MiR4LCB5ID0gdjIkeSwgeiA9IHYyJHosCiAgICAgICAgICAgICAgIHRleHQgPSBUZVgoInZfMiIpLAogICAgICAgICAgICAgICB0ZXh0YW5nbGUgPSAwLCBheCA9IDAsIGF5ID0gLTM1LAogICAgICAgICAgICAgICBmb250ID0gbGlzdChjb2xvciA9ICJibGFjayIsIHNpemUgPSBnZnNpemUpLAogICAgICAgICAgICAgICBhcnJvd2NvbG9yID0gImdyYXkiLCBhcnJvd3NpemUgPSAxLCBhcnJvd3dpZHRoID0gMC41LCBhcnJvd2hlYWQgPSAxKSwKICAgICAgICAgICAgICAgbGlzdCgKICAgICAgICAgICAgICAgeCA9IGUxJHgsIHkgPSBlMSR5LCB6ID0gZTEkeiwKICAgICAgICAgICAgICAgdGV4dCA9IFRlWCgiZV8xIiksCiAgICAgICAgICAgICAgIHRleHRhbmdsZSA9IDAsIGF4ID0gMCwgYXkgPSAtMzUsCiAgICAgICAgICAgICAgIGZvbnQgPSBsaXN0KGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IGdmc2l6ZSksCiAgICAgICAgICAgICAgIGFycm93Y29sb3IgPSAiZ3JheSIsIGFycm93c2l6ZSA9IDEsIGFycm93d2lkdGggPSAwLjUsIGFycm93aGVhZCA9IDEpLAogICAgICAgICAgICAgICBsaXN0KAogICAgICAgICAgICAgICB4ID0gZTIkeCwgeSA9IGUyJHksIHogPSBlMiR6LAogICAgICAgICAgICAgICB0ZXh0ID0gVGVYKCJlXzIiKSwKICAgICAgICAgICAgICAgdGV4dGFuZ2xlID0gMCwgYXggPSAwLCBheSA9IC0zNSwKICAgICAgICAgICAgICAgZm9udCA9IGxpc3QoY29sb3IgPSAiYmxhY2siLCBzaXplID0gZ2ZzaXplKSwKICAgICAgICAgICAgICAgYXJyb3djb2xvciA9ICJncmF5IiwgYXJyb3dzaXplID0gMSwgYXJyb3d3aWR0aCA9IDAuNSwgYXJyb3doZWFkID0gMSkpCiAgKQopCgpzYXZlKHA0LCBmaWxlID0gaGVyZTo6aGVyZSgiZGF0YV9maWxlcy9ncmFwaHM2cDQuUmRhdGEiKSkKYGBgCgoKYGBge3IsIGV2YWwgPVRSVUUsIGZpZy5oZWlnaHQgPSA3LCBvdXQud2lkdGggPSAiMTAwJSJ9CmxvYWQoaGVyZTo6aGVyZSgiZGF0YV9maWxlcy9ncmFwaHM2cDQuUmRhdGEiKSkKcDQKYGBgCgoKIyBSZWZlcmVuY2VzCgpgYGB7ciwgZXZhbCA9IFRSVUV9CmdyYXRlZnVsOjpjaXRlX3BhY2thZ2VzKG91dHB1dCA9ICJwYXJhZ3JhcGgiLCBvdXQuZGlyID0gIi4iKQpgYGAKCg==