Go back to the Contents page.


Press Show to reveal the code chunks.


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

library(ggplot2)
library(reshape2)
library(plotly)

1 Optimal control of fractional diffusion equations on metric graphs

1.1 Problem statement

Let \(\Gamma = (\mathcal{V},\mathcal{E})\) be a metric graph. Let \(u_d: \Gamma \times(0, T) \rightarrow \mathbb{R}\) be the desired state and \(\mu>0\) a regularization parameter. We define the cost functional

\[\begin{equation} \label{eq:costfun} \tag{1} J(u, z)=\frac{1}{2} \int_0^T\left(\left\|u-u_d\right\|_{L_2(\Gamma)}^2+\mu\|z\|_{L_2(\Gamma)}^2\right) dt \end{equation}\]

Let \(f:\Gamma\times (0,T)\rightarrow\mathbb{R}\) and \(u_0: \Gamma \rightarrow \mathbb{R}\) be fixed functions. We will call them right-hand side and initial datum, respectively. Let \(\alpha\in(0,2]\) and \(z: \Gamma \times(0, T) \rightarrow \mathbb{R}\) denote the control variable. We shall be concerned with the following PDE-constrained optimization problem: Find

\[\begin{equation} \label{eq:min_pro} \tag{2} \min\; J(u, z) \end{equation}\] subject to the fractional diffusion equation \[\begin{equation} \label{eq:maineq} \tag{3} \left\{ \begin{aligned} \partial_t u(s,t) + (\kappa^2 - \Delta_\Gamma)^{\alpha/2} u(s,t) &= f(s,t)+z(s,t), && \quad (s,t) \in \Gamma \times (0, T), \\ u(s,0) &= u_0(s), && \quad s \in \Gamma, \end{aligned} \right. \end{equation}\] with \(u(\cdot,t)\) satisfying the Kirchhoff vertex conditions \[\begin{equation} \label{eq:Kcond} \tag{4} \mathcal{K} = \left\{\phi\in C(\Gamma)\;\middle|\; \forall v\in \mathcal{V}:\; \sum_{e\in\mathcal{E}_v}\partial_e \phi(v)=0 \right\} \end{equation}\] and the control constraints \[\begin{align} \label{control_constraints} \tag{5} a(s,t)\leq z(s,t)\leq b(s,t)\;\text{a.e.} (s,t)\in\Gamma \times(0, T). \end{align}\]

1.2 Optimal solution

The optimal variables \((\bar{u}, \bar{p}, \bar{z})\) satisfy

\[\begin{equation} \label{eq:maineqoptimal} \tag{6} \left\{ \begin{aligned} \partial_t \bar{u}(s,t) + (\kappa^2 - \Delta_\Gamma)^{\alpha/2} \bar{u}(s,t) &= f(s,t)+\bar{z}(s,t), && \quad (s,t) \in \Gamma \times (0, T), \\ \bar{u}(s,0) &= u_0(s), && \quad s \in \Gamma, \end{aligned} \right. \end{equation}\] and \[\begin{equation} \label{eq:adjointeq} \tag{7} \left\{ \begin{aligned} -\partial_t \bar{p}(s,t) + (\kappa^2 - \Delta_\Gamma)^{\alpha/2} \bar{p}(s,t) &= \bar{u}(s,t)-u_d(s,t), && \quad (s,t) \in \Gamma \times (0, T), \\ \bar{p}(s,T) &= 0, && \quad s \in \Gamma, \end{aligned} \right. \end{equation}\] with \[\begin{align} \label{zz} \tag{8} \bar{z}(s,t) = \max\left\{a(s,t),\min\left\{b(s,t),-\dfrac{1}{\mu}\bar{p}(s,t)\right\}\right\}. \end{align}\]

1.3 Numerical Scheme

1.3.1 Discretization by time reversal strategy

By considering the change of variable \(t^* = T-t\) and defining \(\bar{q}(s,t^*): = \bar{p}(s,T-t^*)\), the fractional adjoint problem \(\eqref{eq:adjointeq}\) becomes a forward-in-time problem where the transformed adjoint state \(\bar{q}\) satisfies the Kirchhoff vertex conditions \(\eqref{eq:Kcond}\) and solves \[\begin{equation} \label{transformed_adjoint_state} \tag{9} \left\{ \begin{aligned} \partial_{t^*} \bar{q}(s,t^*) + (\kappa^2 - \Delta_\Gamma)^{\alpha/2} \bar{q}(s,t^*) &= \bar{v}(s,t^*)-v_d(s,t^*), && \quad (s,t^*) \in \Gamma \times (0, T), \\ \bar{q}(s,0) &= 0, && \quad s \in \Gamma, \end{aligned} \right. \end{equation}\] since \(\partial_t\bar{p}(s,t) = -\partial_{t^*}\bar{q}(s,t^*)\) and \(\bar{q}(s, 0)= \bar{p}(s,T)=0\). Here, \(\bar{v}(s,t^*) = \bar{u}(s,T-t^*)\) and \(v_d(s,t^*) = u_d(s,T-t^*)\).

Given \(\bar{u}\) and \(u_d\), we can time-reverse them to obtain \(\bar{v}\) and \(v_d\) and then use the same numerical scheme we use for the forward problem \(\eqref{eq:maineqoptimal}\) to solve the adjoint problem \(\eqref{transformed_adjoint_state}\). The control variable \(\bar{z}\) is then computed using \(\eqref{zz}\).

The numerical scheme for \(\eqref{eq:maineqoptimal}\) and \(\eqref{transformed_adjoint_state}\) are given by (see the Functionality page)

\[\begin{align} \tag{10} \label{numericalscheme1} \begin{cases} &\mathbf{\bar{U}}_{k+1} = \mathbf{R}\mathbf{C}\mathbf{\bar{U}}_k+\tau \mathbf{R}(\mathbf{F}_{k+1}+\mathbf{C}\mathbf{\bar{Z}}_{k+1}),\quad k = 0,\dots, N-1,\\ &\mathbf{\bar{U}}_{0} = [u_0(s_1), \dots, u_0(s_{N_h})]^\top, \end{cases} \end{align}\] and \[\begin{align} \tag{11} \label{thenumericalscheme2} \begin{cases} &\mathbf{\bar{Q}}_{k+1} = \mathbf{R}\mathbf{C}\mathbf{\bar{Q}}_k+\tau\mathbf{R} ((\mathbf{C}\mathbf{\bar{U}}\mathbf{J}_{N+1})_{k+1}-(\mathbf{D}\mathbf{J}_{N+1})_{k+1}),\quad k = 0,\dots, N-1,\\ &\mathbf{\bar{Q}}_{0} = \mathbf{0}, \end{cases} \end{align}\] where \(\mathbf{R} = \sum_{k=1}^{m+1} a_k\left(\mathbf{L}/\kappa^2-p_k\mathbf{C}\right)^{-1}\). Observe that \(\eqref{numericalscheme1}\)-\(\eqref{thenumericalscheme2}\) is a coupled problem.

Here

  • \(\mathbf{\bar{U}}\) has entries \(\mathbf{U}_{j,k} = \bar{u}(s_j,t_k)\),
  • \(\mathbf{F}\) has entries \(\mathbf{F}_{j,k} =(f^{k},\psi^j_h)_{L_2(\Gamma)}\),
  • \(\mathbf{\bar{Z}}\) has entries \(\mathbf{\bar{Z}}_{j,k} = \bar{z}(s_j,t_k)\),
  • \(\mathbf{D}\) has entries \(\mathbf{D}_{j,k} =(u_d^{k},\psi^j_h)_{L_2(\Gamma)}\),
  • \(\mathbf{\bar{P}} = \mathbf{\bar{Q}}\mathbf{J}_{N+1}\) and has entries \(\mathbf{\bar{P}}_{j,k} = \bar{p}(s_j,t_k)\).

If we change \(\eqref{thenumericalscheme2}\) to \(\mathbf{\bar{P}}\), then we obtain \[\begin{align} \tag{12} \label{thenumericalscheme3} \begin{cases} &\mathbf{\bar{P}}_{k} = \mathbf{R}\mathbf{C}\mathbf{\bar{P}}_{k+1}+\tau \mathbf{R}(\mathbf{C}\mathbf{\bar{U}}_{k}-\mathbf{D}_{k}),\quad k = N-1,\dots, 0,\\ &\mathbf{\bar{P}}_{N} = \mathbf{0}. \end{cases} \end{align}\]

1.3.2 Discretization by directly solving the adjoint problem

The discrete version \(\bar{P}_h^\tau\subset V_h\) of the adjoint optimal state \(\bar{p}\) in problem \(\eqref{eq:adjointeq}\) solves

\[\begin{equation} \label{discrete_adjoint} \left\{ \begin{aligned} \langle\bar{\delta} \bar{P}_h^{k},\phi\rangle + \mathfrak{a}(\bar{P}_h^{k},\phi) &= \langle \bar{U}_h^{k+1}-u_d^{k+1},\phi\rangle, \quad\forall\phi\in V_h,\quad k=N-1,\dots, 0, \\ \bar{P}^N_h &= 0 \end{aligned} \right. \end{equation}\] The above expression can be equivalently written as \[\begin{equation} \left\{ \begin{aligned} \langle\dfrac{\bar{P}_h^{k} - \bar{P}_h^{k+1}}{\tau},\phi\rangle + \mathfrak{a}( \bar{P}_h^{k},\phi) & = \langle \bar{U}_h^{k+1} - u_d^{k+1},\phi\rangle, \quad\forall\phi\in V_h,\quad k=N-1,\dots, 0, \\ \bar{P}^N_h &= 0 \end{aligned} \right. \end{equation}\] or \[\begin{equation} \label{disoptcons} \tag{13} \left\{ \begin{aligned} \langle \bar{P}_h^{k},\phi\rangle + \tau\mathfrak{a}( \bar{P}_h^{k},\phi) & = \langle \bar{P}_h^{k+1},\phi\rangle + \tau\langle \bar{U}_h^{k+1} - u_d^{k+1},\phi\rangle, \quad\forall\phi\in V_h,\quad k=N-1,\dots, 0, \\ \bar{P}^N_h &= 0 \end{aligned} \right. \end{equation}\]

At each time step \(t_k\), the finite element solution \(\bar{P}_h^k\in V_h\) to \(\eqref{disoptcons}\) can be expressed as a linear combination of the basis functions \(\{\psi^i_h\}_{i=1}^{N_h}\) introduced in the Preliminaries page, namely, \[\begin{align} \label{num_sol2} \tag{14} \bar{P}_h^k(s) = \sum_{i=1}^{N_h}p_i^k\psi^i_h(s), \;s\in\Gamma. \end{align}\] Replacing \(\eqref{num_sol2}\) into \(\eqref{disoptcons}\) yields the following system \[\begin{align*} \sum_{j=1}^{N_h}p_j^{k}[(\psi_h^j,\psi_h^i)_{L_2(\Gamma)}+ \tau\mathfrak{a}(\psi_h^j,\psi_h^i)] = \sum_{j=1}^{N_h}p_j^{k+1}(\psi_h^j,\psi_h^i)_{L_2(\Gamma)}+\tau(\bar{U}_h^{k+1} - u_d^{k+1},\psi_h^i)_{L_2(\Gamma)},\quad i = 1,\dots, N_h. \end{align*}\] In matrix notation, \[\begin{align} \label{diff_eq_discrete_adjoint} (\mathbf{C}+\tau \mathbf{L}^{\alpha/2})\mathbf{\bar{P}}_{k} = \mathbf{C}\mathbf{\bar{P}}_{k+1}+\tau( \boldsymbol{\bar{\mathfrak{U}}}_{k+1} - \mathbf{D}_{k+1}), \end{align}\] or by introducing the scaling parameter \(\kappa^2>0\), \[\begin{align} (\mathbf{C}+\tau (\kappa^2)^{\alpha/2}(\mathbf{L}/\kappa^2)^{\alpha/2})\mathbf{\bar{P}}_{k} = \mathbf{C}\mathbf{\bar{P}}_{k+1}+\tau ( \boldsymbol{\bar{\mathfrak{U}}}_{k+1} - \mathbf{D}_{k+1}), \end{align}\] where \(\mathbf{C}\) has entries \(\mathbf{C}_{i,j} = (\psi_h^j,\psi_h^i)_{L_2(\Gamma)}\), \(\mathbf{L}^{\alpha/2}\) has entries \(\mathfrak{a}(\psi_h^j,\psi_h^i)\), \(\mathbf{\bar{P}}^k\) has components \(p_j^k\), and \(\boldsymbol{\bar{\mathfrak{U}}}^k\) has components \(( \bar{u}^{k},\psi_h^i)_{L_2(\Gamma)}\). Applying \((\mathbf{L}/\kappa^2)^{-\alpha/2}\) to both sides yields \[\begin{equation} ((\mathbf{L}/\kappa^2)^{-\alpha/2}\mathbf{C}+\tau (\kappa^2)^{\alpha/2}\mathbf{I})\mathbf{\bar{P}}_{k} = (\mathbf{L}/\kappa^2)^{-\alpha/2}(\mathbf{C}\mathbf{\bar{P}}_{k+1}+\tau ( \boldsymbol{\bar{\mathfrak{U}}}_{k+1} - \mathbf{D}_{k+1})). \end{equation}\] Following Bolin and Kirchner (2020), we approximate \((\mathbf{L}/\kappa^2)^{-\alpha/2}\) by \(\mathbf{P}_\ell^{-\top}\mathbf{P}_r^\top\) to arrive at \[\begin{equation} \label{eq:scheme2adjoint} \tag{15} (\mathbf{P}_\ell^{-\top}\mathbf{P}_r^\top \mathbf{C}+\tau(\kappa^2)^{\alpha/2} \mathbf{I})\mathbf{\bar{P}}_{k} = \mathbf{P}_\ell^{-\top}\mathbf{P}_r^\top(\mathbf{C}\mathbf{\bar{P}}_{k+1}+\tau ( \boldsymbol{\bar{\mathfrak{U}}}_{k+1} - \mathbf{D}_{k+1})). \end{equation}\] where \[\begin{equation} \label{eq:PLPRbolinadjoint} \tag{16} \mathbf{P}_r = \prod_{i=1}^m \left(\mathbf{I}-r_{1i}\dfrac{\mathbf{C}^{-1}\mathbf{L}}{\kappa^2}\right)\quad\text{and}\quad \mathbf{P}_\ell = \dfrac{\kappa^{2\beta}}{\texttt{factor}}\mathbf{C}\prod_{j=1}^{m+1} \left(\mathbf{I}-r_{2j}\dfrac{\mathbf{C}^{-1}\mathbf{L}}{\kappa^2}\right), \end{equation}\] and \(\texttt{factor} = \dfrac{c_m}{b_{m+1}}\), and \(\{r_{1i}\}_{i=1}^m\) and \(\{r_{2j}\}_{j=1}^{m+1}\) are the roots of \(q_1(x) =\sum_{i=0}^mc_ix^{i}\) and \(q_2(x)=\sum_{j=0}^{m+1}b_jx^{j}\), respectively. The coefficients \(\{c_i\}_{i=0}^m\) and \(\{b_j\}_{j=0}^{m+1}\) are determined as the best rational approximation \(q_1/q_2\) of the function \(x^{\alpha/2-1}\) over the interval \(J_h: = [\kappa^{2}\lambda_{N_h,h}^{-1}, \kappa^{2}\lambda_{1,h}^{-1}]\), where \(\lambda_{1,h}, \lambda_{N_h,h}>0\) are the smallest and the largest eigenvalue of \(L_h\), respectively.

For the sake of clarity, we note that the numerical implementation of Bolin and Kirchner (2020) actually defines \(\mathbf{P}_r\) and \(\mathbf{P}_\ell\) as \[\begin{equation} \label{eq:PLPRbolin} \tag{17} \mathbf{P}_r = \prod_{i=1}^m \left(\mathbf{I}-r_{1i}\dfrac{\mathbf{C}^{-1}\mathbf{L}}{\kappa^2}\right)\quad\text{and}\quad \mathbf{P}_\ell = \dfrac{\kappa^{2\beta}}{\texttt{factor}}\mathbf{C}\prod_{j=1}^{m+1} \left(\mathbf{I}-r_{2j}\dfrac{\mathbf{C}^{-1}\mathbf{L}}{\kappa^2}\right), \end{equation}\] where \(\beta = \alpha/2\) and the scaling factor \((\kappa^2)^{\alpha/2}\) or \(\kappa^{2\beta}\) is already incorporated in \(\mathbf{P}_\ell\), a convention we adopt in the following. With this under consideration, we can rewrite \(\eqref{eq:scheme2adjoint}\) as \[\begin{equation} \tag{18} (\mathbf{P}_r^\top \mathbf{C}+\tau \mathbf{P}_\ell^\top)\mathbf{\bar{P}}_{k} = \mathbf{P}_r^\top(\mathbf{C}\mathbf{\bar{P}}_{k+1}+\tau ( \boldsymbol{\bar{\mathfrak{U}}}_{k+1} - \mathbf{D}_{k+1})), \label{eq:schemeadjoint} \end{equation}\] where
\[\begin{equation} \mathbf{P}_r^\top = \prod_{i=1}^m \left(\mathbf{I}-r_{1i}\dfrac{\mathbf{L}\mathbf{C}^{-1}}{\kappa^2}\right)\quad\text{and}\quad \mathbf{P}_\ell^\top = \dfrac{\kappa^{2\beta}}{\texttt{factor}}\prod_{j=1}^{m+1} \left(\mathbf{I}-r_{2j}\dfrac{\mathbf{L}\mathbf{C}^{-1}}{\kappa^2}\right)\cdot \mathbf{C} \end{equation}\] since \(\mathbf{L}\) and \(\mathbf{C}^{-1}\) are symmetric and the factors in the product commute. Replacing these two into \(\eqref{eq:schemeadjoint}\) yields \[\begin{equation} \left(\prod_{i=1}^m \left(\mathbf{I}-r_{1i}\dfrac{\mathbf{L}\mathbf{C}^{-1}}{\kappa^2}\right)+\dfrac{\tau \kappa^{2\beta}}{\texttt{factor}}\prod_{j=1}^{m+1} \left(\mathbf{I}-r_{2j}\dfrac{\mathbf{L}\mathbf{C}^{-1}}{\kappa^2}\right)\right)\mathbf{C}\mathbf{\bar{P}}_{k} = \prod_{i=1}^m \left(\mathbf{I}-r_{1i}\dfrac{\mathbf{L}\mathbf{C}^{-1}}{\kappa^2}\right)\cdot (\mathbf{C}\mathbf{\bar{P}}_{k+1}+\tau ( \boldsymbol{\bar{\mathfrak{U}}}_{k+1} - \mathbf{D}_{k+1})), \end{equation}\] that is, \[\begin{equation} \label{eq:final_schemeadjoint} \tag{19} \mathbf{\bar{P}}_{k} = \mathbf{C}^{-1}\left(\prod_{i=1}^m \left(\mathbf{I}-r_{1i}\dfrac{\mathbf{L}\mathbf{C}^{-1}}{\kappa^2}\right)+\dfrac{\tau \kappa^{2\beta}}{\texttt{factor}}\prod_{j=1}^{m+1} \left(\mathbf{I}-r_{2j}\dfrac{\mathbf{L}\mathbf{C}^{-1}}{\kappa^2}\right)\right)^{-1} \prod_{i=1}^m \left(\mathbf{I}-r_{1i}\dfrac{\mathbf{L}\mathbf{C}^{-1}}{\kappa^2}\right)\cdot (\mathbf{C}\mathbf{\bar{P}}_{k+1}+\tau ( \boldsymbol{\bar{\mathfrak{U}}}_{k+1} - \mathbf{D}_{k+1})). \end{equation}\] Considering the partial fraction decomposition \[\begin{equation} \label{eq:partial_fractionadjoint} \tag{20} \dfrac{\prod_{i=1}^m (1-r_{1i}x)}{\prod_{i=1}^m (1-r_{1i}x)+\dfrac{\tau \kappa^{2\beta}}{\texttt{factor}} \prod_{j=1}^{m+1} (1-r_{2j}x)}=\sum_{k=1}^{m+1} a_k(x-p_k)^{-1} + r, \end{equation}\] scheme \(\eqref{eq:final_schemeadjoint}\) can be expressed as \[\begin{equation} \label{eq:final_scheme3adjoint} \tag{21} \mathbf{\bar{P}}_{k} = \mathbf{C}^{-1}\left(\sum_{k=1}^{m+1} a_k\left( \dfrac{\mathbf{L}\mathbf{C}^{-1}}{\kappa^2}-p_k\mathbf{I}\right)^{-1} + r\mathbf{I}\right) (\mathbf{C}\mathbf{\bar{P}}_{k+1}+\tau ( \boldsymbol{\bar{\mathfrak{U}}}_{k+1} - \mathbf{D}_{k+1})). \end{equation}\] In practice, since the rational function in \(\eqref{eq:partial_fractionadjoint}\) is proper, there is no remainder \(r\). Moreover, since \(\left( \dfrac{\mathbf{L}\mathbf{C}^{-1}}{\kappa^2}-p_k\mathbf{I}\right)^{-1} = \mathbf{C}\left( \dfrac{\mathbf{L}}{\kappa^2}-p_k\mathbf{C}\right)^{-1}\), we have that \(\eqref{eq:final_scheme3adjoint}\) can be rewritten as

\[\begin{equation} \label{eq:final_schemefinaladjoint} \tag{21} \mathbf{\bar{P}}_{k} = \mathbf{R} (\mathbf{C}\mathbf{\bar{P}}_{k+1}+\tau ( \boldsymbol{\bar{\mathfrak{U}}}_{k+1} - \mathbf{D}_{k+1})),\quad \mathbf{R} = \left(\sum_{k=1}^{m+1} a_k\left( \dfrac{\mathbf{L}}{\kappa^2}-p_k\mathbf{C}\right)^{-1}\right). \end{equation}\]

That is, \[\begin{align} \tag{22} \label{thenumericalscheme4} \begin{cases} &\mathbf{\bar{P}}_{k} = \mathbf{R}\mathbf{C}\mathbf{\bar{P}}_{k+1}+\tau \mathbf{R}(\mathbf{C}\mathbf{\bar{U}}_{k+1}-\mathbf{D}_{k+1}),\quad k = N-1,\dots, 0,\\ &\mathbf{\bar{P}}_{N} = \mathbf{0}, \end{cases} \end{align}\]

Observe that the only difference between \(\eqref{thenumericalscheme3}\) and \(\eqref{thenumericalscheme4}\) is in the right-hand side, where in \(\eqref{thenumericalscheme4}\) we have \(\mathbf{C}\mathbf{\bar{U}}_{k+1}-\mathbf{D}_{k+1}\) instead of \(\mathbf{C}\mathbf{\bar{U}}_{k}-\mathbf{D}_{k}\).

1.4 Fixed point iteration algorithm for the optimal control problem

Let \((h_\star, \tau_\star)\) denote the integration space–time mesh parameters, with \(\tau_\star = T/N_\star\) and nodes \((s_i^\star, t_\ell^\star)\) for \(i = 1,\dots,N_{h_\star}\) and \(\ell = 0,\dots,N_\star\). The computation space-time mesh is defined analogously by \((h, \tau)\), with \(\tau = T/N\) and nodes \((s_j, t_k)\) for \(j = 1,\dots,N_{h}\) and \(k = 0,\dots,N\). Let \(\boldsymbol{\mathfrak{F}},\boldsymbol{\mathfrak{D}}\in \mathbb{R}^{N_{h_\star}\times (N+1)}\) denote the evaluations of \(f\) and \(u_d\) on a mixed mesh (that uses the spatial nodes of the integration mesh and the temporal nodes of the computation mesh), respectively, i.e., \(\boldsymbol{\mathfrak{F}}_{i,k} = f(s_i^\star, t_k)\) and \(\boldsymbol{\mathfrak{D}}_{i,k} = u_d(s_i^\star, t_k)\). With this notation at hand, we now introduce the next algorithm.

  • 1. Initialization: Initialize \(\mathbf{\bar{Z}}\in \mathbb{R}^{N_{h}\times (N+1)}\) on the computation mesh and approximate \(\boldsymbol{\bar{\mathcal{Z}}}\in \mathbb{R}^{N_{h}\times (N+1)}\), with entries \(\boldsymbol{\bar{\mathcal{Z}}}_{j,k} =(\bar{z}^{k},\psi^j_h)_{L_2(\Gamma)}\), by \(\boldsymbol{\bar{\mathcal{Z}}}\approx\boldsymbol{\Psi}^\top \mathbf{C}^{\star} \boldsymbol{\Psi} \mathbf{\bar{Z}} = \mathbf{C} \mathbf{\bar{Z}}\), where the last equality is thanks to the nestedness of the spatial meshes. Similarly, approximate \(\mathbf{F}\in \mathbb{R}^{N_{h}\times (N+1)}\), with entries \(\mathbf{F}_{j,k} =(f^{k},\psi^j_h)_{L_2(\Gamma)}\), by \(\mathbf{F} \approx \boldsymbol{\Psi}^\top \mathbf{C}^{\star} \boldsymbol{\mathfrak{F}}\).

  • 2. State solve: Given \(\boldsymbol{\bar{\mathcal{Z}}}\), \(\mathbf{F}\), and \(\mathbf{\bar{U}}_{0}\in \mathbb{R}^{N_{h}}\) with components \(u_0(s_j)\), compute \(\mathbf{\bar{U}}\in \mathbb{R}^{N_{h}\times (N+1)}\), the numerical solution corresponding to \(\bar{u}\) in \(\eqref{eq:maineqoptimal}\), with the scheme

\[\begin{align} \label{statesolve} \tag{FS} \begin{cases} \mathbf{\bar{U}}_{k+1} &= \mathbf{R}\mathbf{C}\mathbf{\bar{U}}_k+\tau \mathbf{R}(\mathbf{F}_{k+1}+\mathbf{C}\mathbf{\bar{Z}}_{k+1})\\ & = (\mathbf{R}\mathbf{C})^{k+1}\mathbf{\bar{U}}_0 + \tau \sum_{i=0}^{k} (\mathbf{R}\mathbf{C})^{k-i}\mathbf{R}(\mathbf{F}_{i+1}+\mathbf{C} \mathbf{\bar{Z}}_{i+1}), \quad k = 0,\dots, N-1,\\ \mathbf{\bar{U}}_{0} &= [u_0(s_1), \dots, u_0(s_{N_h})]^\top, \end{cases} \end{align}\]

  • 3. Adjoint solve: Given \(\mathbf{\bar{U}}\) from before, approximate \(\boldsymbol{\bar{\mathfrak{U}}}\in \mathbb{R}^{N_{h}\times (N+1)}\), with entries \(\boldsymbol{\bar{\mathfrak{U}}}_{j,k} =(\bar{u}^{k},\psi^j_h)_{L_2(\Gamma)}\), by \(\boldsymbol{\bar{\mathfrak{U}}} \approx \boldsymbol{\Psi}^\top \mathbf{C}^{\star} \boldsymbol{\Psi} \mathbf{\bar{U}}=\mathbf{C}\mathbf{\bar{U}}\). Similarly, approximate \(\mathbf{D}\in \mathbb{R}^{N_{h}\times (N+1)}\), with entries \(\mathbf{D}_{j,k} =(u_d^{k},\psi^j_h)_{L_2(\Gamma)}\), by \(\mathbf{D} \approx \boldsymbol{\Psi}^\top \mathbf{C}^{\star} \boldsymbol{\mathfrak{D}}\). Compute \(\mathbf{\bar{P}}\in \mathbb{R}^{N_{h}\times (N+1)}\), the numerical solution corresponding to \(\bar{p}\) in \(\eqref{eq:adjointeq}\), with the scheme

\[\begin{align} \label{adjointsolve} \tag{BS} \begin{cases} \mathbf{\bar{P}}_{k} & = \mathbf{R}\mathbf{C}\mathbf{\bar{P}}_{k+1}+\tau \mathbf{R}(\mathbf{C}\mathbf{\bar{U}}_{k+1}-\mathbf{D}_{k+1})\\ &= \tau \sum_{i=0}^{N-k-1} (\mathbf{R}\mathbf{C})^{i}\mathbf{R}(\mathbf{C}\mathbf{\bar{U}}_{k+i+1}-\mathbf{D}_{k+i+1}), \quad k = N-1,\dots, 0,\\ \mathbf{\bar{P}}_{N} & = \mathbf{0}, \end{cases} \end{align}\]

  • 4. Control update: Given \(\mathbf{\bar{P}}\) from before and matrices \(\mathbf{A},\mathbf{B}\in \mathbb{R}^{N_{h}\times (N+1)}\) with constant entries \(\mathbf{A}_{j,k} = a\) and \(\mathbf{B}_{j,k} = b\), respectively, update \[\begin{align} \label{entrywisez} \mathbf{\bar{Z}} = \max\{\mathbf{A},\min\{\mathbf{B},-\mathbf{\bar{P}}/\mu\}\}\quad \text{(entry-wise)}. \end{align}\]

  • 5. Iteration: Repeat steps 2–4 until convergence.

1.5 Convergence analysis of the FBSM iteration

For illustration purposes, along with the general case \(N\), we consider the particular case \(N=3\). From \(\eqref{statesolve}\) and \(\eqref{adjointsolve}\), we have

\[\begin{align} \mathbf{\bar{U}}_{0} & = \mathbf{\bar{U}}_{0} \\ & \\ \mathbf{\bar{U}}_{1} & = (\mathbf{R}\mathbf{C})^1\mathbf{\bar{U}}_0+\tau \mathbf{R}(\mathbf{F}_{1}+\mathbf{C}\mathbf{\bar{Z}}_{1})\\ & \\ \mathbf{\bar{U}}_{2} & = \mathbf{R}\mathbf{C}\mathbf{\bar{U}}_1+\tau \mathbf{R}(\mathbf{F}_{2}+\mathbf{C}\mathbf{\bar{Z}}_{2})\\ & = \mathbf{R}\mathbf{C}((\mathbf{R}\mathbf{C})^1\mathbf{\bar{U}}_0+\tau \mathbf{R}(\mathbf{F}_{1}+\mathbf{C}\mathbf{\bar{Z}}_{1}))+\tau \mathbf{R}(\mathbf{F}_{2}+\mathbf{C}\mathbf{\bar{Z}}_{2})\\ & = (\mathbf{R}\mathbf{C})^2\mathbf{\bar{U}}_0+\tau (\mathbf{R}\mathbf{C})^1\mathbf{R}(\mathbf{F}_{1}+\mathbf{C}\mathbf{\bar{Z}}_{1})+\tau \mathbf{R}(\mathbf{F}_{2}+\mathbf{C}\mathbf{\bar{Z}}_{2})\\ & \\ \mathbf{\bar{U}}_{3} & = \mathbf{R}\mathbf{C}\mathbf{\bar{U}}_2+\tau \mathbf{R}(\mathbf{F}_{3}+\mathbf{C}\mathbf{\bar{Z}}_{3})\\ & = \mathbf{R}\mathbf{C}((\mathbf{R}\mathbf{C})^2\mathbf{\bar{U}}_0+\tau (\mathbf{R}\mathbf{C})^1\mathbf{R}(\mathbf{F}_{1}+\mathbf{C}\mathbf{\bar{Z}}_{1})+\tau \mathbf{R}(\mathbf{F}_{2}+\mathbf{C}\mathbf{\bar{Z}}_{2}))+\tau \mathbf{R}(\mathbf{F}_{3}+\mathbf{C}\mathbf{\bar{Z}}_{3})\\ & = (\mathbf{R}\mathbf{C})^3\mathbf{\bar{U}}_0+\tau (\mathbf{R}\mathbf{C})^2\mathbf{R}(\mathbf{F}_{1}+\mathbf{C}\mathbf{\bar{Z}}_{1})+\tau (\mathbf{R}\mathbf{C})^1\mathbf{R}(\mathbf{F}_{2}+\mathbf{C}\mathbf{\bar{Z}}_{2})+\tau \mathbf{R}(\mathbf{F}_{3}+\mathbf{C}\mathbf{\bar{Z}}_{3}) \end{align}\] and \[\begin{align} \mathbf{\bar{P}}_{3} &= \mathbf{0}, \\ &\\ \mathbf{\bar{P}}_{2} &= \mathbf{R}\mathbf{C}\mathbf{\bar{P}}_{3} + \tau\mathbf{R}(\mathbf{C}\mathbf{\bar{U}}_{3}-\mathbf{D}_{3})\\ &= \tau\mathbf{R}(\mathbf{C}\mathbf{\bar{U}}_{3}-\mathbf{D}_{3}), \\ &\\ \mathbf{\bar{P}}_{1} &= \mathbf{R}\mathbf{C}\mathbf{\bar{P}}_{2} + \tau\mathbf{R}(\mathbf{C}\mathbf{\bar{U}}_{2}-\mathbf{D}_{2}) \\ &= \tau(\mathbf{R}\mathbf{C})^1\mathbf{R}(\mathbf{C}\mathbf{\bar{U}}_{3}-\mathbf{D}_{3}) + \tau\mathbf{R}(\mathbf{C}\mathbf{\bar{U}}_{2}-\mathbf{D}_{2}), \\ &\\ \mathbf{\bar{P}}_{0} &= \mathbf{R}\mathbf{C}\mathbf{\bar{P}}_{1} + \tau\mathbf{R}(\mathbf{C}\mathbf{\bar{U}}_{1}-\mathbf{D}_{1}) \\ &= \tau(\mathbf{R}\mathbf{C})^{2}\mathbf{R}(\mathbf{C}\mathbf{\bar{U}}_{3}-\mathbf{D}_{3}) + \tau(\mathbf{R}\mathbf{C})^1\mathbf{R}(\mathbf{C}\mathbf{\bar{U}}_{2}-\mathbf{D}_{2}) + \tau\mathbf{R}(\mathbf{C}\mathbf{\bar{U}}_{1}-\mathbf{D}_{1}). \end{align}\]

In block-matrix notation \[\begin{align} \begin{bmatrix} \mathbf{\bar{U}}_{0} \\[1mm] \mathbf{\bar{U}}_{1} \\[1mm] \mathbf{\bar{U}}_{2} \\[1mm] \mathbf{\bar{U}}_{3} \end{bmatrix} = \begin{bmatrix} \mathbf{\bar{U}}_{0} \\[1mm] (\mathbf{R}\mathbf{C})^1\mathbf{\bar{U}}_{0} \\[1mm] (\mathbf{R}\mathbf{C})^2\mathbf{\bar{U}}_{0} \\[1mm] (\mathbf{R}\mathbf{C})^3\mathbf{\bar{U}}_{0} \end{bmatrix} +\tau \begin{bmatrix} \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} \\[1mm] \mathbf{0} & \mathbf{I} & \mathbf{0} & \mathbf{0} \\[1mm] \mathbf{0} & (\mathbf{R}\mathbf{C})^1 & \mathbf{I} & \mathbf{0} \\[1mm] \mathbf{0} & (\mathbf{R}\mathbf{C})^2 & (\mathbf{R}\mathbf{C})^1 & \mathbf{I} \end{bmatrix} \begin{bmatrix} \mathbf{R}(\mathbf{\bar{F}}_{0}+\mathbf{C}\mathbf{\bar{Z}}_{0}) \\[1mm] \mathbf{R}(\mathbf{\bar{F}}_{1}+\mathbf{C}\mathbf{\bar{Z}}_{1}) \\[1mm] \mathbf{R}(\mathbf{\bar{F}}_{2}+\mathbf{C}\mathbf{\bar{Z}}_{2}) \\[1mm] \mathbf{R}(\mathbf{\bar{F}}_{3}+\mathbf{C}\mathbf{\bar{Z}}_{3}) \end{bmatrix} \end{align}\] and \[\begin{align} \begin{bmatrix} \mathbf{\bar{P}}_{0} \\[1mm] \mathbf{\bar{P}}_{1} \\[1mm] \mathbf{\bar{P}}_{2} \\[1mm] \mathbf{\bar{P}}_{3} \end{bmatrix} = \tau \begin{bmatrix} \mathbf{0} & \mathbf{I} & (\mathbf{R}\mathbf{C}) & (\mathbf{R}\mathbf{C})^{2} \\[1mm] \mathbf{0} & \mathbf{0} & \mathbf{I} & (\mathbf{R}\mathbf{C}) \\[1mm] \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{I} \\[1mm] \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} \end{bmatrix} \begin{bmatrix} \mathbf{R}(\mathbf{C}\mathbf{\bar{U}}_{0}-\mathbf{D}_{0}) \\[1mm] \mathbf{R}(\mathbf{C}\mathbf{\bar{U}}_{1}-\mathbf{D}_{1}) \\[1mm] \mathbf{R}(\mathbf{C}\mathbf{\bar{U}}_{2}-\mathbf{D}_{2}) \\[1mm] \mathbf{R}(\mathbf{C}\mathbf{\bar{U}}_{3}-\mathbf{D}_{3}) \end{bmatrix}. \end{align}\]

In general, \[\begin{align} \begin{bmatrix} \mathbf{\bar{U}}_{0} \\[1mm] \mathbf{\bar{U}}_{1} \\[1mm] \mathbf{\bar{U}}_{2} \\[1mm] \vdots \\[1mm] \mathbf{\bar{U}}_{N} \end{bmatrix} &= \begin{bmatrix} \mathbf{\bar{U}}_{0} \\[1mm] (\mathbf{R}\mathbf{C})^1\mathbf{\bar{U}}_{0} \\[1mm] (\mathbf{R}\mathbf{C})^2\mathbf{\bar{U}}_{0} \\[1mm] \vdots \\[1mm] (\mathbf{R}\mathbf{C})^N\mathbf{\bar{U}}_{0} \end{bmatrix} +\tau \begin{bmatrix} \mathbf{0} & \mathbf{0} & \mathbf{0} & \cdots & \mathbf{0} \\[1mm] \mathbf{0} & \mathbf{I} & \mathbf{0} & \cdots & \mathbf{0} \\[1mm] \mathbf{0} & (\mathbf{R}\mathbf{C})^1 & \mathbf{I} & \cdots & \mathbf{0} \\[1mm] \vdots & \vdots & \vdots & \ddots & \vdots \\[1mm] \mathbf{0} & (\mathbf{R}\mathbf{C})^{N-1} & (\mathbf{R}\mathbf{C})^{N-2} & \cdots & \mathbf{I} \end{bmatrix} \begin{bmatrix} \mathbf{R}(\mathbf{\bar{F}}_{0}+\mathbf{C}\mathbf{\bar{Z}}_{0}) \\[1mm] \mathbf{R}(\mathbf{\bar{F}}_{1}+\mathbf{C}\mathbf{\bar{Z}}_{1}) \\[1mm] \mathbf{R}(\mathbf{\bar{F}}_{2}+\mathbf{C}\mathbf{\bar{Z}}_{2}) \\[1mm] \vdots \\[1mm] \mathbf{R}(\mathbf{\bar{F}}_{N}+\mathbf{C}\mathbf{\bar{Z}}_{N}) \end{bmatrix}. \end{align}\] and \[\begin{align} \begin{bmatrix} \mathbf{\bar{P}}_{0} \\[1mm] \mathbf{\bar{P}}_{1} \\[1mm] \vdots \\[1mm] \mathbf{\bar{P}}_{N-1} \\[1mm] \mathbf{\bar{P}}_{N} \end{bmatrix} = \tau \begin{bmatrix} \mathbf{0} & \mathbf{I} & (\mathbf{R}\mathbf{C}) & \cdots & (\mathbf{R}\mathbf{C})^{N-1} \\[1mm] \mathbf{0} & \mathbf{0} & \mathbf{I} & \cdots & (\mathbf{R}\mathbf{C})^{N-2} \\[1mm] \vdots & \vdots & \vdots & \ddots & \vdots \\[1mm] \mathbf{0} & \mathbf{0} & \mathbf{0} & \cdots & \mathbf{I} \\[1mm] \mathbf{0} & \mathbf{0} & \mathbf{0} & \cdots & \mathbf{0} \end{bmatrix} \begin{bmatrix} \mathbf{R}(\mathbf{C}\mathbf{\bar{U}}_{0}-\mathbf{D}_{0}) \\[1mm] \mathbf{R}(\mathbf{C}\mathbf{\bar{U}}_{1}-\mathbf{D}_{1}) \\[1mm] \vdots \\[1mm] \mathbf{R}(\mathbf{C}\mathbf{\bar{U}}_{N-1}-\mathbf{D}_{N-1}) \\[1mm] \mathbf{R}(\mathbf{C}\mathbf{\bar{U}}_{N}-\mathbf{D}_{N}) \end{bmatrix}. \end{align}\] By defining stacked vectors of length \((N+1)N_h\), \[\begin{align*} \mathbf{\bar{u}} = \text{vec}(\mathbf{\bar{U}}),\quad \mathbf{\bar{p}} = \text{vec}(\mathbf{\bar{P}}),\quad \mathbf{\bar{z}} = \text{vec}(\mathbf{\bar{Z}}),\quad \mathbf{f} = \text{vec}(\mathbf{F}),\quad \mathbf{d} =\text{vec}(\mathbf{D}), \end{align*}\] \[\begin{align*} \mathbf{a} =\text{vec}(\mathbf{A}),\quad \mathbf{b} = \text{vec}(\mathbf{B}),\quad\mathbf{h}= [\mathbf{\bar{U}}_{0}^\top ((\mathbf{R}\mathbf{C})^{1}\mathbf{\bar{U}}_{0})^\top ((\mathbf{R}\mathbf{C})^{2} \mathbf{\bar{U}}_{0})^\top\dots ((\mathbf{R}\mathbf{C})^{N}\mathbf{\bar{U}}_{0})^\top]^\top, \end{align*}\] and block matrices of dimension \((N+1)N_h\times (N+1)N_h\), \[\begin{align*} \mathbf{M} = \mathbf{I}_{N+1}\otimes \mathbf{C},\quad \mathbf{\hat{J}}_{N+1} = \mathbf{J}_{N+1}\otimes \mathbf{I}_{N_h},\quad \mathbf{\hat{R}} = \mathbf{I}_{N+1}\otimes \mathbf{R} , \end{align*}\] \[\begin{align} \mathbf{S}_{\mathrm{F}} = \tau \begin{bmatrix} \mathbf{0} & \mathbf{0} & \mathbf{0} & \cdots & \mathbf{0} \\[1mm] \mathbf{0} & \mathbf{I} & \mathbf{0} & \cdots & \mathbf{0} \\[1mm] \mathbf{0} & (\mathbf{R}\mathbf{C})^1 & \mathbf{I} & \cdots & \mathbf{0} \\[1mm] \vdots & \vdots & \vdots & \ddots & \vdots \\[1mm] \mathbf{0} & (\mathbf{R}\mathbf{C})^{N-1} & (\mathbf{R}\mathbf{C})^{N-2} & \cdots & \mathbf{I} \end{bmatrix}\quad \text{and}\quad \mathbf{S}_{\mathrm{B}} = \tau \begin{bmatrix} \mathbf{0} & \mathbf{I} & (\mathbf{R}\mathbf{C}) & \cdots & (\mathbf{R}\mathbf{C})^{N-1} \\[1mm] \mathbf{0} & \mathbf{0} & \mathbf{I} & \cdots & (\mathbf{R}\mathbf{C})^{N-2} \\[1mm] \vdots & \vdots & \vdots & \ddots & \vdots \\[1mm] \mathbf{0} & \mathbf{0} & \mathbf{0} & \cdots & \mathbf{I} \\[1mm] \mathbf{0} & \mathbf{0} & \mathbf{0} & \cdots & \mathbf{0} \end{bmatrix}, \end{align}\] then the vectorized form \[\begin{align} \label{iterationvectorized} \begin{cases} \mathbf{\bar{u}} &= \mathbf{h} + \mathbf{S}_{\mathrm{F}}\mathbf{\hat{R}}(\mathbf{f}+\mathbf{M}\mathbf{\bar{z}})\\ \mathbf{\bar{p}} & = \mathbf{S}_{\mathrm{B}}\mathbf{\hat{R}}(\mathbf{M}\mathbf{\bar{u}} - \mathbf{d})\\ \mathbf{\bar{z}} & = \max\{\mathbf{a}, \min\{\mathbf{b}, -\mathbf{\bar{p}}/\mu\}\} \quad \text{(componentwise)}. \end{cases} \end{align}\] We need to estimate \(\gamma = (1/\mu)\|\boldsymbol{\mathfrak{L}}\|_{\mathbf{C}_{N+1}}\) where \(\boldsymbol{\mathfrak{L}} = \mathbf{S}_{\mathrm{B}}\mathbf{\hat{R}}\mathbf{M}\mathbf{S}_{\mathrm{F}}\mathbf{\hat{R}}\mathbf{M}\). We have \[\begin{align} \mathbf{S}_{\mathrm{F}}\mathbf{\hat{R}}\mathbf{M} = \tau \begin{bmatrix} \mathbf{0} & \mathbf{0} & \mathbf{0} & \cdots & \mathbf{0} \\[1mm] \mathbf{0} & \mathbf{R}\mathbf{C} & \mathbf{0} & \cdots & \mathbf{0} \\[1mm] \mathbf{0} & (\mathbf{R}\mathbf{C})^2 & \mathbf{R}\mathbf{C} & \cdots & \mathbf{0} \\[1mm] \vdots & \vdots & \vdots & \ddots & \vdots \\[1mm] \mathbf{0} & (\mathbf{R}\mathbf{C})^{N} & (\mathbf{R}\mathbf{C})^{N-1} & \cdots & \mathbf{R}\mathbf{C} \end{bmatrix}\quad \text{and}\quad \mathbf{S}_{\mathrm{B}}\mathbf{\hat{R}}\mathbf{M} = \tau \begin{bmatrix} \mathbf{0} & \mathbf{R}\mathbf{C} & (\mathbf{R}\mathbf{C})^2 & \cdots & (\mathbf{R}\mathbf{C})^{N} \\[1mm] \mathbf{0} & \mathbf{0} & \mathbf{R}\mathbf{C} & \cdots & (\mathbf{R}\mathbf{C})^{N-1} \\[1mm] \vdots & \vdots & \vdots & \ddots & \vdots \\[1mm] \mathbf{0} & \mathbf{0} & \mathbf{0} & \cdots & \mathbf{R}\mathbf{C} \\[1mm] \mathbf{0} & \mathbf{0} & \mathbf{0} & \cdots & \mathbf{0} \end{bmatrix} \end{align}\] If \(N=3\), then \[\begin{align} \boldsymbol{\mathfrak{L}} = \mathbf{S}_{\mathrm{B}}\mathbf{\hat{R}}\mathbf{M}\mathbf{S}_{\mathrm{F}}\mathbf{\hat{R}}\mathbf{M} &= \tau^2 \begin{bmatrix} \mathbf{0} & \mathbf{R}\mathbf{C} & (\mathbf{R}\mathbf{C})^2 & (\mathbf{R}\mathbf{C})^{3} \\[1mm] \mathbf{0} & \mathbf{0} & \mathbf{R}\mathbf{C} & (\mathbf{R}\mathbf{C})^2 \\[1mm] \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{R}\mathbf{C} \\[1mm] \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} \end{bmatrix} \begin{bmatrix} \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} \\[1mm] \mathbf{0} & \mathbf{R}\mathbf{C} & \mathbf{0} & \mathbf{0} \\[1mm] \mathbf{0} & (\mathbf{R}\mathbf{C})^2 & \mathbf{R}\mathbf{C} & \mathbf{0} \\[1mm] \mathbf{0} & (\mathbf{R}\mathbf{C})^3 & (\mathbf{R}\mathbf{C})^2 & \mathbf{R}\mathbf{C} \end{bmatrix}\\ &\\ & = \tau^2 \begin{bmatrix} \mathbf{0} & (\mathbf{R}\mathbf{C})^2 + (\mathbf{R}\mathbf{C})^4 + (\mathbf{R}\mathbf{C})^6 & (\mathbf{R}\mathbf{C})^3 + (\mathbf{R}\mathbf{C})^5 & (\mathbf{R}\mathbf{C})^4 \\[1mm] \mathbf{0} & (\mathbf{R}\mathbf{C})^3 + (\mathbf{R}\mathbf{C})^5 & (\mathbf{R}\mathbf{C})^2 + (\mathbf{R}\mathbf{C})^4 & (\mathbf{R}\mathbf{C})^3 \\[1mm] \mathbf{0} & (\mathbf{R}\mathbf{C})^4 & (\mathbf{R}\mathbf{C})^3 & (\mathbf{R}\mathbf{C})^2 \\[1mm] \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} \end{bmatrix} \end{align}\]

Let \[\begin{align} \boldsymbol{\hat{\mathfrak{L}}} = \begin{bmatrix} \sum_{k=1}^{N}(\mathbf{R}\mathbf{C})^{2k+(N-N)} & \cdots & \sum_{k=1}^{3}(\mathbf{R}\mathbf{C})^{2k+(N-3)} & \sum_{k=1}^{2}(\mathbf{R}\mathbf{C})^{2k+(N-2)} & \sum_{k=1}^{1}(\mathbf{R}\mathbf{C})^{2k+(N-1)} \\[1mm] \vdots & \ddots & \vdots & \vdots & \vdots \\[1mm] \sum_{k=1}^{3}(\mathbf{R}\mathbf{C})^{2k+(N-3)} & \cdots & \sum_{k=1}^{3}(\mathbf{R}\mathbf{C})^{2k} & \sum_{k=1}^{2}(\mathbf{R}\mathbf{C})^{2k+1} & \sum_{k=1}^{1}(\mathbf{R}\mathbf{C})^{2k+2} \\[1mm] \sum_{k=1}^{2}(\mathbf{R}\mathbf{C})^{2k+(N-2)} & \cdots & \sum_{k=1}^{2}(\mathbf{R}\mathbf{C})^{2k+1} & \sum_{k=1}^{2}(\mathbf{R}\mathbf{C})^{2k} & \sum_{k=1}^{1}(\mathbf{R}\mathbf{C})^{2k+1} \\[1mm] \sum_{k=1}^{1}(\mathbf{R}\mathbf{C})^{2k+(N-1)} & \cdots & \sum_{k=1}^{1}(\mathbf{R}\mathbf{C})^{2k+2} & \sum_{k=1}^{1}(\mathbf{R}\mathbf{C})^{2k+1} & \sum_{k=1}^{1}(\mathbf{R}\mathbf{C})^{2k} \end{bmatrix} \end{align}\]

Then we can write

\[\begin{align} \boldsymbol{\mathfrak{L}} = \tau^2 \begin{bmatrix} \mathbf{0} & \boldsymbol{\hat{\mathfrak{L}}} \\[1mm] \mathbf{0} & \mathbf{0} \end{bmatrix} \end{align}\]

Let \(\boldsymbol{\mathfrak{B}} = \mathbf{C}_{N+1}^{\frac{1}{2}}\boldsymbol{\mathfrak{L}}\mathbf{C}_{N+1}^{-\frac{1}{2}}\). Note for example that \[\begin{align*} \mathbf{C}^{\frac{1}{2}}(\mathbf{R}\mathbf{C})^{3}\mathbf{C}^{-\frac{1}{2}} = \mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}\mathbf{R}\mathbf{C}\mathbf{R}\mathbf{C}\mathbf{C}^{-\frac{1}{2}} = (\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^3. \end{align*}\] Therefore \[\begin{align} \boldsymbol{\mathfrak{B}} = \tau^2 \begin{bmatrix} \mathbf{0} & (\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^2 + (\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^4 + (\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^6 & (\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^3 + (\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^5 & (\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^4 \\[1mm] \mathbf{0} & (\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^3 + (\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^5 & (\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^2 + (\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^4 & (\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^3 \\[1mm] \mathbf{0} & (\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^4 & (\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^3 & (\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^2 \\[1mm] \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} \end{bmatrix} \end{align}\] In general, \[\begin{align} \boldsymbol{\mathfrak{B}} = \tau^2 \begin{bmatrix} \mathbf{0} & \boldsymbol{\hat{\mathfrak{B}}} \\[1mm] \mathbf{0} & \mathbf{0} \end{bmatrix},\quad \boldsymbol{\hat{\mathfrak{B}}} = \mathbf{C}_{N}^{\frac{1}{2}}\boldsymbol{\hat{\mathfrak{L}}}\mathbf{C}_{N}^{-\frac{1}{2}} = \begin{bmatrix} \sum_{k=1}^{N}(\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^{2k+(N-N)} & \cdots & \sum_{k=1}^{3}(\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^{2k+(N-3)} & \sum_{k=1}^{2}(\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^{2k+(N-2)} & \sum_{k=1}^{1}(\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^{2k+(N-1)} \\[1mm] \vdots & \ddots & \vdots & \vdots & \vdots \\[1mm] \sum_{k=1}^{3}(\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^{2k+(N-3)} & \cdots & \sum_{k=1}^{3}(\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^{2k} & \sum_{k=1}^{2}(\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^{2k+1} & \sum_{k=1}^{1}(\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^{2k+2} \\[1mm] \sum_{k=1}^{2}(\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^{2k+(N-2)} & \cdots & \sum_{k=1}^{2}(\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^{2k+1} & \sum_{k=1}^{2}(\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^{2k} & \sum_{k=1}^{1}(\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^{2k+1} \\[1mm] \sum_{k=1}^{1}(\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^{2k+(N-1)} & \cdots & \sum_{k=1}^{1}(\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^{2k+2} & \sum_{k=1}^{1}(\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^{2k+1} & \sum_{k=1}^{1}(\mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}})^{2k} \end{bmatrix} \end{align}\]

By letting \(\mathbf{\Omega} = \mathbf{C}^{\frac{1}{2}}\mathbf{R}\mathbf{C}^{\frac{1}{2}}\), we can write \[\begin{align} \label{matrixB} \tag{23} \boldsymbol{\mathfrak{B}} = \tau^2 \begin{bmatrix} \mathbf{0} & \mathbf{\Omega}^2 + \mathbf{\Omega}^4 + \mathbf{\Omega}^6 & \mathbf{\Omega}^3 + \mathbf{\Omega}^5 & \mathbf{\Omega}^4 \\[1mm] \mathbf{0} & \mathbf{\Omega}^3 + \mathbf{\Omega}^5 & \mathbf{\Omega}^2 + \mathbf{\Omega}^4 & \mathbf{\Omega}^3 \\[1mm] \mathbf{0} & \mathbf{\Omega}^4 & \mathbf{\Omega}^3 & \mathbf{\Omega}^2 \\[1mm] \mathbf{0} & \mathbf{0} & \mathbf{0} & \mathbf{0} \end{bmatrix} = \tau^2 \begin{bmatrix} \mathbf{0} & \boldsymbol{\hat{\mathfrak{B}}} \\[1mm] \mathbf{0} & \mathbf{0} \end{bmatrix},\quad \boldsymbol{\hat{\mathfrak{B}}} = \begin{bmatrix} \mathbf{\Omega}^2 + \mathbf{\Omega}^4 + \mathbf{\Omega}^6 & \mathbf{\Omega}^3 + \mathbf{\Omega}^5 & \mathbf{\Omega}^4 \\[1mm] \mathbf{\Omega}^3 + \mathbf{\Omega}^5 & \mathbf{\Omega}^2 + \mathbf{\Omega}^4 & \mathbf{\Omega}^3 \\[1mm] \mathbf{\Omega}^4 & \mathbf{\Omega}^3 & \mathbf{\Omega}^2 \end{bmatrix} \end{align}\] In general, \[\begin{align} \boldsymbol{\mathfrak{B}} = \tau^2 \begin{bmatrix} \mathbf{0} & \boldsymbol{\hat{\mathfrak{B}}} \\[1mm] \mathbf{0} & \mathbf{0} \end{bmatrix},\quad \boldsymbol{\hat{\mathfrak{B}}} = \mathbf{C}_{N}^{\frac{1}{2}}\boldsymbol{\hat{\mathfrak{L}}}\mathbf{C}_{N}^{-\frac{1}{2}} = \begin{bmatrix} \sum_{k=1}^{N}\mathbf{\Omega}^{2k+(N-N)} & \cdots & \sum_{k=1}^{3}\mathbf{\Omega}^{2k+(N-3)} & \sum_{k=1}^{2}\mathbf{\Omega}^{2k+(N-2)} & \sum_{k=1}^{1}\mathbf{\Omega}^{2k+(N-1)} \\[1mm] \vdots & \ddots & \vdots & \vdots & \vdots \\[1mm] \sum_{k=1}^{3}\mathbf{\Omega}^{2k+(N-3)} & \cdots & \sum_{k=1}^{3}\mathbf{\Omega}^{2k} & \sum_{k=1}^{2}\mathbf{\Omega}^{2k+1} & \sum_{k=1}^{1}\mathbf{\Omega}^{2k+2} \\[1mm] \sum_{k=1}^{2}\mathbf{\Omega}^{2k+(N-2)} & \cdots & \sum_{k=1}^{2}\mathbf{\Omega}^{2k+1} & \sum_{k=1}^{2}\mathbf{\Omega}^{2k} & \sum_{k=1}^{1}\mathbf{\Omega}^{2k+1} \\[1mm] \sum_{k=1}^{1}\mathbf{\Omega}^{2k+(N-1)} & \cdots & \sum_{k=1}^{1}\mathbf{\Omega}^{2k+2} & \sum_{k=1}^{1}\mathbf{\Omega}^{2k+1} & \sum_{k=1}^{1}\mathbf{\Omega}^{2k} \end{bmatrix} \end{align}\]

Note that \[\begin{align} \boldsymbol{\mathfrak{B}} \mathbf{\hat{J}}_{N+1} = \begin{bmatrix} \boldsymbol{\hat{\mathfrak{B}}}\mathbf{\hat{J}}_{N} & \mathbf{0} \\[1mm] \mathbf{0} & \mathbf{0} \end{bmatrix} \end{align}\]

Hence

\[\begin{align} \label{chain1} \|\boldsymbol{\mathfrak{L}}\|_{\mathbf{C}_{N+1}} = \|\boldsymbol{\mathfrak{B}}\|_2= \|\boldsymbol{\mathfrak{B}} \mathbf{\hat{J}}_{N+1} \|_2= \tau^2 \| \begin{bmatrix} \boldsymbol{\hat{\mathfrak{B}}}\mathbf{\hat{J}}_{N} & \mathbf{0} \\[1mm] \mathbf{0} & \mathbf{0} \end{bmatrix}\|_2 = \tau^2 \|\boldsymbol{\hat{\mathfrak{B}}}\mathbf{\hat{J}}_{N} \|_2 = \tau^2 \|\boldsymbol{\hat{\mathfrak{B}}}\|_2 \end{align}\]

We have that \(\mathbf{Q}^\top\boldsymbol{\Omega}^k\mathbf{Q} = \boldsymbol{\Delta}^k\). Let \(\mathbf{V} = \mathbf{I}_{N}\otimes \mathbf{Q}\). By , \(\mathbf{V}\) is orthogonal and \[\begin{align*} \mathbf{V}^\top \boldsymbol{\hat{\mathfrak{B}}} \mathbf{V} = \begin{bmatrix} \mathbf{\Delta}^2 + \mathbf{\Delta}^4 + \mathbf{\Delta}^6 & \mathbf{\Delta}^3 + \mathbf{\Delta}^5 & \mathbf{\Delta}^4 \\[1mm] \mathbf{\Delta}^3 + \mathbf{\Delta}^5 & \mathbf{\Delta}^2 + \mathbf{\Delta}^4 & \mathbf{\Delta}^3 \\[1mm] \mathbf{\Delta}^4 & \mathbf{\Delta}^3 & \mathbf{\Delta}^2 \end{bmatrix} \end{align*}\] In general, \[\begin{align*} \mathbf{V}^\top \boldsymbol{\hat{\mathfrak{B}}} \mathbf{V} = \begin{bmatrix} \sum_{k=1}^{N}\mathbf{\Delta}^{2k+(N-N)} & \cdots & \sum_{k=1}^{3}\mathbf{\Delta}^{2k+(N-3)} & \sum_{k=1}^{2}\mathbf{\Delta}^{2k+(N-2)} & \sum_{k=1}^{1}\mathbf{\Delta}^{2k+(N-1)} \\[1mm] \vdots & \ddots & \vdots & \vdots & \vdots \\[1mm] \sum_{k=1}^{3}\mathbf{\Delta}^{2k+(N-3)} & \cdots & \sum_{k=1}^{3}\mathbf{\Delta}^{2k} & \sum_{k=1}^{2}\mathbf{\Delta}^{2k+1} & \sum_{k=1}^{1}\mathbf{\Delta}^{2k+2} \\[1mm] \sum_{k=1}^{2}\mathbf{\Delta}^{2k+(N-2)} & \cdots & \sum_{k=1}^{2}\mathbf{\Delta}^{2k+1} & \sum_{k=1}^{2}\mathbf{\Delta}^{2k} & \sum_{k=1}^{1}\mathbf{\Delta}^{2k+1} \\[1mm] \sum_{k=1}^{1}\mathbf{\Delta}^{2k+(N-1)} & \cdots & \sum_{k=1}^{1}\mathbf{\Delta}^{2k+2} & \sum_{k=1}^{1}\mathbf{\Delta}^{2k+1} & \sum_{k=1}^{1}\mathbf{\Delta}^{2k} \end{bmatrix} \end{align*}\] For example, if \(\mathbf{\Delta} = \text{diag}(\mu_1, \mu_2,\mu_3)\), then \[\begin{align} \mathbf{V}^\top \boldsymbol{\hat{\mathfrak{B}}} \mathbf{V} = \begin{bmatrix} \mu_1^2+\mu_1^4+\mu_1^6 & 0 & 0 & \mu_1^3+\mu_1^5 & 0 & 0 & \mu_1^4 & 0 & 0 \\[1mm] 0 & \mu_2^2+\mu_2^4+\mu_2^6 & 0 & 0 & \mu_2^3+\mu_2^5 & 0 & 0 & \mu_2^4 & 0 \\[1mm] 0 & 0 & \mu_3^2+\mu_3^4+\mu_3^6 & 0 & 0 & \mu_3^3+\mu_3^5 & 0 & 0 & \mu_3^4 \\[2mm] \mu_1^3+\mu_1^5 & 0 & 0 & \mu_1^2+\mu_1^4 & 0 & 0 & \mu_1^3 & 0 & 0 \\[1mm] 0 & \mu_2^3+\mu_2^5 & 0 & 0 & \mu_2^2+\mu_2^4 & 0 & 0 & \mu_2^3 & 0 \\[1mm] 0 & 0 & \mu_3^3+\mu_3^5 & 0 & 0 & \mu_3^2+\mu_3^4 & 0 & 0 & \mu_3^3 \\[2mm] \mu_1^4 & 0 & 0 & \mu_1^3 & 0 & 0 & \mu_1^2 & 0 & 0 \\[1mm] 0 & \mu_2^4 & 0 & 0 & \mu_2^3 & 0 & 0 & \mu_2^2 & 0 \\[1mm] 0 & 0 & \mu_3^4 & 0 & 0 & \mu_3^3 & 0 & 0 & \mu_3^2 \end{bmatrix} \end{align}\] If \[\begin{align} \mathbf{P} = \begin{bmatrix} 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\[1mm] 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \\[1mm] 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\[1mm] 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\[1mm] 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 \\[1mm] 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \\[1mm] 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\[1mm] 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\[1mm] 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \end{bmatrix} \end{align}\] then \[\begin{align} \mathbf{P}\mathbf{V}^\top \boldsymbol{\hat{\mathfrak{B}}} \mathbf{V}\mathbf{P}^\top = \begin{bmatrix} \mu_1^2+\mu_1^4+\mu_1^6 & \mu_1^3+\mu_1^5 & \mu_1^4 & 0 & 0 & 0 & 0 & 0 & 0 \\[1mm] \mu_1^3+\mu_1^5 & \mu_1^2+\mu_1^4 & \mu_1^3 & 0 & 0 & 0 & 0 & 0 & 0 \\[1mm] \mu_1^4 & \mu_1^3 & \mu_1^2 & 0 & 0 & 0 & 0 & 0 & 0 \\[2mm] 0 & 0 & 0 & \mu_2^2+\mu_2^4+\mu_2^6 & \mu_2^3+\mu_2^5 & \mu_2^4 & 0 & 0 & 0 \\[1mm] 0 & 0 & 0 & \mu_2^3+\mu_2^5 & \mu_2^2+\mu_2^4 & \mu_2^3 & 0 & 0 & 0 \\[1mm] 0 & 0 & 0 & \mu_2^4 & \mu_2^3 & \mu_2^2 & 0 & 0 & 0 \\[2mm] 0 & 0 & 0 & 0 & 0 & 0 & \mu_3^2+\mu_3^4+\mu_3^6 & \mu_3^3+\mu_3^5 & \mu_3^4 \\[1mm] 0 & 0 & 0 & 0 & 0 & 0 & \mu_3^3+\mu_3^5 & \mu_3^2+\mu_3^4 & \mu_3^3 \\[1mm] 0 & 0 & 0 & 0 & 0 & 0 & \mu_3^4 & \mu_3^3 & \mu_3^2 \end{bmatrix} \end{align}\]

The code below shows matrix how to build matrix \(\mathbf{V}^\top \boldsymbol{\hat{\mathfrak{B}}} \mathbf{V}\) and \(\mathbf{P}\) and verifies that \(\mathbf{P}\mathbf{V}^\top \boldsymbol{\hat{\mathfrak{B}}} \mathbf{V}\mathbf{P}^\top\) is block diagonal with blocks \(\mathbf{T}(\mu_i)\).

make_matrix <- function(a, N) {
  v <- a^(0:(N - 1))
  toeplitz(v)
}
build_T_fast <- function(a, N) {
  M <- make_matrix(a, N)
  R <- matrix(0, N, N)
  coef <- (a^2)^(1:N)  # correct power order
  for (k in N:1) {
    R[1:k, 1:k] <- R[1:k, 1:k] + coef[N - k + 1] * M[1:k, 1:k]
  }
  R
}
build_block_matrix <- function(egs, Nh) {
  N <- length(egs)
  # total size
  m <- N * Nh
  AA <- matrix(0, nrow = m, ncol = m)
  for (j in 1:N) {
    rows <- ((j - 1) * Nh + 1):(j * Nh)
    cols <- ((j - 1) * Nh + 1):(j * Nh)
    AA[rows, cols] <- build_T_fast(egs[j], Nh)
  }
  return(AA)
}
build_perm_matrix_general <- function(N, Nh) {
  m <- N * Nh
  # target indices
  perm <- as.vector(sapply(1:Nh, function(i) i + Nh*(0:(N-1))))
  P <- diag(m)[perm, ]
  return(P)
}
Nh <- 3
egs <- c(1,3,5)
P <- build_perm_matrix_general(length(egs), Nh)
P
##       [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
##  [1,]    1    0    0    0    0    0    0    0    0
##  [2,]    0    0    0    1    0    0    0    0    0
##  [3,]    0    0    0    0    0    0    1    0    0
##  [4,]    0    1    0    0    0    0    0    0    0
##  [5,]    0    0    0    0    1    0    0    0    0
##  [6,]    0    0    0    0    0    0    0    1    0
##  [7,]    0    0    1    0    0    0    0    0    0
##  [8,]    0    0    0    0    0    1    0    0    0
##  [9,]    0    0    0    0    0    0    0    0    1
aux <- build_block_matrix(egs, Nh)
tVhatBV <- t(P) %*% aux %*% P
tVhatBV
##       [,1] [,2]  [,3] [,4] [,5] [,6] [,7] [,8] [,9]
##  [1,]    3    0     0    2    0    0    1    0    0
##  [2,]    0  819     0    0  270    0    0   81    0
##  [3,]    0    0 16275    0    0 3250    0    0  625
##  [4,]    2    0     0    2    0    0    1    0    0
##  [5,]    0  270     0    0   90    0    0   27    0
##  [6,]    0    0  3250    0    0  650    0    0  125
##  [7,]    1    0     0    1    0    0    1    0    0
##  [8,]    0   81     0    0   27    0    0    9    0
##  [9,]    0    0   625    0    0  125    0    0   25
PtVhatBVtP <- P %*% tVhatBV %*% t(P)
PtVhatBVtP
##       [,1] [,2] [,3] [,4] [,5] [,6]  [,7] [,8] [,9]
##  [1,]    3    2    1    0    0    0     0    0    0
##  [2,]    2    2    1    0    0    0     0    0    0
##  [3,]    1    1    1    0    0    0     0    0    0
##  [4,]    0    0    0  819  270   81     0    0    0
##  [5,]    0    0    0  270   90   27     0    0    0
##  [6,]    0    0    0   81   27    9     0    0    0
##  [7,]    0    0    0    0    0    0 16275 3250  625
##  [8,]    0    0    0    0    0    0  3250  650  125
##  [9,]    0    0    0    0    0    0   625  125   25

That is, in general, \[\begin{align*} \mathbf{P}\mathbf{V}^\top \boldsymbol{\hat{\mathfrak{B}}}\mathbf{V}\mathbf{P}^\top = \text{blkdiag}(\mathbf{T}(\mu_1), \mathbf{T}(\mu_2), \dots, \mathbf{T}(\mu_{N_h})), \end{align*}\] where \[\begin{align} \mathbf{T}(\mu_i) = \begin{bmatrix} \sum_{k=1}^{N}\mu_i^{2k+(N-N)} & \cdots & \sum_{k=1}^{3}\mu_i^{2k+(N-3)} & \sum_{k=1}^{2}\mu_i^{2k+(N-2)} & \sum_{k=1}^{1}\mu_i^{2k+(N-1)} \\[1mm] \vdots & \ddots & \vdots & \vdots & \vdots \\[1mm] \sum_{k=1}^{3}\mu_i^{2k+(N-3)} & \cdots & \sum_{k=1}^{3}\mu_i^{2k} & \sum_{k=1}^{2}\mu_i^{2k+1} & \sum_{k=1}^{1}\mu_i^{2k+2} \\[1mm] \sum_{k=1}^{2}\mu_i^{2k+(N-2)} & \cdots & \sum_{k=1}^{2}\mu_i^{2k+1} & \sum_{k=1}^{2}\mu_i^{2k} & \sum_{k=1}^{1}\mu_i^{2k+1} \\[1mm] \sum_{k=1}^{1}\mu_i^{2k+(N-1)} & \cdots & \sum_{k=1}^{1}\mu_i^{2k+2} & \sum_{k=1}^{1}\mu_i^{2k+1} & \sum_{k=1}^{1}\mu_i^{2k} \end{bmatrix} \end{align}\] Let \(\mathbf{T} = \mathbf{T}(\omega)\). That is, \[\begin{align} \label{matrixT} \tag{24} \mathbf{T} = \mathbf{T}(\omega) = \begin{bmatrix} \sum_{k=1}^{N}\omega^{2k+(N-N)} & \cdots & \sum_{k=1}^{3}\omega^{2k+(N-3)} & \sum_{k=1}^{2}\omega^{2k+(N-2)} & \sum_{k=1}^{1}\omega^{2k+(N-1)} \\[1mm] \vdots & \ddots & \vdots & \vdots & \vdots \\[1mm] \sum_{k=1}^{3}\omega^{2k+(N-3)} & \cdots & \sum_{k=1}^{3}\omega^{2k} & \sum_{k=1}^{2}\omega^{2k+1} & \sum_{k=1}^{1}\omega^{2k+2} \\[1mm] \sum_{k=1}^{2}\omega^{2k+(N-2)} & \cdots & \sum_{k=1}^{2}\omega^{2k+1} & \sum_{k=1}^{2}\omega^{2k} & \sum_{k=1}^{1}\omega^{2k+1} \\[1mm] \sum_{k=1}^{1}\omega^{2k+(N-1)} & \cdots & \sum_{k=1}^{1}\omega^{2k+2} & \sum_{k=1}^{1}\omega^{2k+1} & \sum_{k=1}^{1}\omega^{2k} \end{bmatrix} \end{align}\] Then \[\begin{align} \label{chain2} \|\boldsymbol{\mathfrak{L}}\|_{\mathbf{C}_{N+1}} = \tau^2 \|\boldsymbol{\hat{\mathfrak{B}}}\|_2 = \tau^2 \|\mathbf{P}\mathbf{V}^\top \boldsymbol{\hat{\mathfrak{B}}} \mathbf{V}\mathbf{P}^\top\|_2 = \tau^2 \max_{i = 1,\dots, N_h}\|\mathbf{T}(\mu_i)\|_2= \tau^2\|\mathbf{T}(\omega)\|_2= \tau^2\|\mathbf{T}\|_2. \end{align}\]

To see an example where we show that \(\|\boldsymbol{\mathfrak{B}}\|_2 = \tau^2 \|\mathbf{T}\|_2\), go to the this section.

Following with our example, we have that \[\begin{align*} \mathbf{T} & = \begin{bmatrix} \omega^2 & \omega^3 & \omega^4 \\[1mm] \omega^3& \omega^2 & \omega^3 \\[1mm] \omega^4 & \omega^3 & \omega^2 \\[2mm] \end{bmatrix} + \begin{bmatrix} \omega^4 & \omega^5 & 0 \\[1mm] \omega^5 & \omega^4 & 0 \\[1mm] 0 & 0 & 0 \\[2mm] \end{bmatrix} + \begin{bmatrix} \omega^6 & 0 & 0 \\[1mm] 0 & 0 & 0 \\[1mm] 0 & 0 & 0 \\[2mm] \end{bmatrix} \end{align*}\] or equivalently, \[\begin{align*} \mathbf{T}& = \omega^2 \begin{bmatrix} 1 & \omega & \omega^2 \\[1mm] \omega& 1 & \omega \\[1mm] \omega^2 & \omega & 1 \\[2mm] \end{bmatrix} + \omega^4\begin{bmatrix} 1 & \omega & 0 \\[1mm] \omega & 1 & 0 \\[1mm] 0 & 0 & 0 \\[2mm] \end{bmatrix} + \omega^6\begin{bmatrix} 1 & 0 & 0 \\[1mm] 0 & 0 & 0 \\[1mm] 0 & 0 & 0 \\[2mm] \end{bmatrix} \\ & = \omega^2 \begin{bmatrix} 1 & 0 & 0 \\[1mm] 0 & 1 & 0 \\[1mm] 0 & 0 & 1 \\[2mm] \end{bmatrix} \begin{bmatrix} 1 & \omega & \omega^2 \\[1mm] \omega& 1 & \omega \\[1mm] \omega^2 & \omega & 1 \\[2mm] \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 \\[1mm] 0 & 1 & 0 \\[1mm] 0 & 0 & 1 \\[2mm] \end{bmatrix} \\ &+ \omega^4 \begin{bmatrix} 1 & 0 & 0 \\[1mm] 0 & 1 & 0 \\[1mm] 0 & 0 & 0 \\[2mm] \end{bmatrix} \begin{bmatrix} 1 & \omega & \omega^2 \\[1mm] \omega& 1 & \omega \\[1mm] \omega^2 & \omega & 1 \\[2mm] \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 \\[1mm] 0 & 1 & 0 \\[1mm] 0 & 0 & 0 \\[2mm] \end{bmatrix}\\ &+ \omega^6 \begin{bmatrix} 1 & 0 & 0 \\[1mm] 0 & 0 & 0 \\[1mm] 0 & 0 & 0 \\[2mm] \end{bmatrix} \begin{bmatrix} 1 & \omega & \omega^2 \\[1mm] \omega& 1 & \omega \\[1mm] \omega^2 & \omega & 1 \\[2mm] \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 \\[1mm] 0 & 0 & 0 \\[1mm] 0 & 0 & 0 \\[2mm] \end{bmatrix} \end{align*}\]

The code below builds matrix \(\mathbf{T}\) and shows the intermediate steps.

build_T <- function(a, N){
  H <- make_matrix(a, N) 
  R <- H*0
  for (i in N:1) {
    K_i <- diag(c(rep(1, i), rep(0, N - i)))
    temp <- a^(2*(N - i + 1)) * K_i %*% H %*% K_i
    print(a^(2*(N - i + 1)))
    print(cbind(rep("|", N), K_i, rep("|", N), H, rep("|", N), K_i, rep("|", N)), quote = FALSE)
    R <- R + temp
  }
  return(R)
}

T_aux <- build_T(2, 3)
## [1] 4
##      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13]
## [1,] |    1    0    0    |    1    2    4    |    1     0     0     |    
## [2,] |    0    1    0    |    2    1    2    |    0     1     0     |    
## [3,] |    0    0    1    |    4    2    1    |    0     0     1     |    
## [1] 16
##      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13]
## [1,] |    1    0    0    |    1    2    4    |    1     0     0     |    
## [2,] |    0    1    0    |    2    1    2    |    0     1     0     |    
## [3,] |    0    0    0    |    4    2    1    |    0     0     0     |    
## [1] 64
##      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13]
## [1,] |    1    0    0    |    1    2    4    |    1     0     0     |    
## [2,] |    0    0    0    |    2    1    2    |    0     0     0     |    
## [3,] |    0    0    0    |    4    2    1    |    0     0     0     |

That is, in general, \[\begin{align*} \mathbf{T} = \sum_{i=1}^N \omega^{2(N-i+1)} \mathbf{K}_i\mathbf{H}\mathbf{K}_i, \end{align*}\] where \[\begin{align*} \mathbf{H} = \begin{bmatrix} 1 & \omega & \omega^2 & \cdots & \omega^{N-1} \\ \omega & 1 & \omega & \cdots & \omega^{N-2} \\ \omega^2 & \omega & 1 & \cdots & \omega^{N-3} \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ \omega^{N-1} & \omega^{N-2} & \omega^{N-3} & \cdots & 1 \end{bmatrix},\quad \mathbf{K}_i = \mathrm{diag}(\underbrace{1, \dots, 1}_{i}, \underbrace{0, \dots, 0}_{N-i}). \end{align*}\] and \(\mathbf{K}_i\) satisfies \(\|\mathbf{K}_i\|_2 = 1\) for all \(i=1,\dots, N\).

1.6 Numerical implementation

1.6.1 Function my.get.roots()

For each rational order \(m\) (1,2,3,4,5,6,7,8) and smoothness parameter \(\beta\) (= \(\alpha/2\) with \(\alpha\) between 0.5 and 2), function my.get.roots() (adapted from the rSPDE package) returns \(\texttt{factor} = \dfrac{c_m}{b_{m+1}}\), and the roots \(\{r_{1i}\}_{i=1}^m\) and \(\{r_{2j}\}_{j=1}^{m+1}\).

The file data_files/chebfun_tables.RDS contains the precomputed tables for the roots and factors for rational orders 1 to 8. These tables were generated using the matlab/chebfun.m and matlab/chebfun_tables.R scripts.

# Function to compute the roots and factor for the rational approximation
my.get.roots <- function(m, # rational order, m = 1, 2, 3, 4, 5, 6, 7, or 8
                         beta # smoothness parameter, beta = alpha/2 with alpha between 0.5 and 2
                         ) {
  # m1table <- rSPDE:::m1table
  # m2table <- rSPDE:::m2table
  # m3table <- rSPDE:::m3table
  # m4table <- rSPDE:::m4table
  # mt <- get(paste0("m", m, "table"))
  mt <- readRDS("data_files/chebfun_tables.RDS")[[m]]
  rb <- rep(0, m + 1)
  rc <- rep(0, m)
  if(m == 1) {
    rc = approx(mt$beta, mt[[paste0("rc")]], beta)$y
  } else {
    rc = sapply(1:m, function(i) {
      approx(mt$beta, mt[[paste0("rc.", i)]], beta)$y
    })
  }
  rb = sapply(1:(m+1), function(i) {
    approx(mt$beta, mt[[paste0("rb.", i)]], xout = beta)$y
  })
  factor = approx(mt$beta, mt$factor, xout = beta)$y
  return(list(pl_roots = rb, # roots \{r_{2j}\}_{j=1}^{m+1}
              pr_roots = rc, # roots \{r_{1i}\}_{i=1}^m
              factor = factor # this is c_m/b_{m+1}
              ))
}

1.6.2 Function poly.from.roots()

Function poly.from.roots() computes the coefficients of a polynomial from its roots.

# Function to compute polynomial coefficients from roots
poly.from.roots <- function(roots) {
  coef <- 1
  for (r in roots) {coef <- convolve(coef, c(1, -r), type = "open")}
  return(coef) # returned in increasing order like a+bx+cx^2+...
}

1.6.3 Function compute.partial.fraction.param()

Given factor\(=\texttt{factor} = \dfrac{c_m}{b_{m+1}}\), pr_roots\(=\{r_{1i}\}_{i=1}^m\), pl_roots\(=\{r_{2j}\}_{j=1}^{m+1}\), time_step\(=\tau\), and scaling\(=\kappa^{2\beta}\), function compute.partial.fraction.param() computes the parameters for the partial fraction decomposition \(\eqref{eq:partial_fractionadjoint}\).

# Function to compute the parameters for the partial fraction decomposition
compute.partial.fraction.param <- function(factor, # c_m/b_{m+1}
                                           pr_roots, # roots \{r_{1i}\}_{i=1}^m
                                           pl_roots, # roots \{r_{2j}\}_{j=1}^{m+1}
                                           time_step, # \tau
                                           scaling # \kappa^{2\beta}
                                           ) {
  pr_coef <- poly.from.roots(pr_roots)
  pl_coef <- poly.from.roots(pl_roots)
  pr_plus_pl_coef <- c(0, pr_coef) + ((scaling * time_step)/factor) * pl_coef
  poles <- Re(polyroot(rev(pr_plus_pl_coef)))
  num_vals <- pracma::polyval(pr_coef, poles)
  den_deriv <- Re(pracma::polyval(pracma::polyder(pr_plus_pl_coef), poles))
  residues <- Re(num_vals / den_deriv)
  return(list(r = residues, # residues \{a_k\}_{k=1}^{m+1}
              p = poles, # poles \{p_k\}_{k=1}^{m+1}
              k = 0 # remainder r
              )) 
}

1.6.4 Function my.fractional.operators.frac()

Given the Laplacian matrix L, the smoothness parameter beta, the mass matrix C (not lumped), the scaling factor scale.factor\(=\kappa^2\), the rational order m, and the time step time_step\(=\tau\), function my.fractional.operators.frac() computes the fractional operator and returns a list containing the necessary matrices and parameters for the fractional diffusion equation.

# Function to compute the fractional operator
my.fractional.operators.frac <- function(L, # Laplacian matrix
                                         beta, # smoothness parameter beta
                                         C, # mass matrix (not lumped)
                                         scale.factor, # scaling parameter = kappa^2
                                         m = 1, # rational order, m = 1, 2, 3, or 4
                                         time_step # time step = tau
                                         ) {
  I <- Matrix::Diagonal(dim(C)[1])
  L <- L / scale.factor 
  if(beta == 1){
    L <- L * scale.factor^beta
    return(list(C = C, # mass matrix
                L = L, # Laplacian matrix scaled
                m = m, # rational order
                beta = beta, # smoothness parameter
                LHS = C + time_step * L # left-hand side of the linear system
                ))
  } else {
    scaling <- scale.factor^beta
    roots <- my.get.roots(m, beta)
    poles_rs_k <- compute.partial.fraction.param(roots$factor, roots$pr_roots, roots$pl_roots, time_step, scaling)

    partial_fraction_terms <- list()
    for (i in 1:(m+1)) {
      # Here is where the terms in the sum in eq 12 are computed
      partial_fraction_terms[[i]] <- (L - poles_rs_k$p[i] * C)#/poles_rs_k$r[i]
      }
    return(list(C = C, # mass matrix
                L = L, # Laplacian matrix scaled
                m = m, # rational order
                beta = beta, # smoothness parameter
                partial_fraction_terms = partial_fraction_terms, # partial fraction terms
                residues = poles_rs_k$r # residues \{a_k\}_{k=1}^{m+1}
                ))
  }
}

1.6.5 Function my.solver.frac()

Given the object returned by my.fractional.operators.frac() and a vector v, function my.solver.frac() solves the system \(\eqref{thenumericalscheme4}\) for the vector v. If beta = 1, it solves the system directly; otherwise, it uses the partial fraction decomposition.

# Function to solve the iteration
my.solver.frac <- function(obj, # object returned by my.fractional.operators.frac()
                           v # vector to be solved for
                           ){
  beta <- obj$beta
  m <- obj$m
  if (beta == 1){
    return(solve(obj$LHS, v) # solve the linear system directly for beta = 1
           )
  } else {
    partial_fraction_terms <- obj$partial_fraction_terms
    residues <- obj$residues
    output <- v*0
    for (i in 1:(m+1)) {output <- output + residues[i] * solve(partial_fraction_terms[[i]], v)}
    return(output # solve the linear system using the partial fraction decomposition
           )
  }
}

1.6.6 Function solve_forward_evolution()

Given the object returned by my.fractional.operators.frac(), the time step time_step\(=\tau\), the time sequence time_seq, the right-hand side term RHST, and the initial value val_at_0, function solve_forward_evolution() solves the forward evolution problem \(\eqref{statesolve}\).

solve_forward_evolution <- function(my_op_frac, time_step, time_seq, RHST, val_at_0) {
  CC <- my_op_frac$C
  N <- length(time_seq)
  SOL <- matrix(NA, nrow = nrow(CC), ncol = N)
  SOL[, 1] <- val_at_0
  for (k in 1:(N - 1)) {
    rhs <- CC %*% SOL[, k] + time_step * RHST[, k + 1]
    SOL[, k + 1] <- as.matrix(my.solver.frac(my_op_frac, rhs))
  }
  return(SOL)
}

1.6.7 Function solve_backward_evolution()

Given the object returned by my.fractional.operators.frac(), the time step time_step\(=\tau\), the time sequence time_seq, and the right-hand side term RHST, function solve_backward_evolution() solves the backward evolution problem \(\eqref{adjointsolve}\).

solve_backward_evolution <- function(my_op_frac, time_step, time_seq, RHST) {
  CC <- my_op_frac$C
  N <- length(time_seq)
  SOL <- matrix(NA, nrow = nrow(CC), ncol = N)
  SOL[, N] <- 0
  for (k in (N - 1):1) {
    rhs <- CC %*% SOL[, k + 1] + time_step * RHST[, k + 1] #this is how it should be in theory
    #rhs <- CC %*% SOL[, k + 1] + time_step * RHST[, k]
    SOL[, k] <- as.matrix(my.solver.frac(my_op_frac, rhs))
  }
  return(SOL)
}

1.7 Auxiliary functions

1.7.1 Function gets.graph.tadpole()

Given a mesh size h, function gets.graph.tadpole() builds a tadpole graph and creates a mesh.

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

1.7.2 Function tadpole.eig()

Given a mode number k and a tadpole graph graph, function tadpole.eig() computes the eigenpairs of the tadpole graph.

# Function to compute the eigenfunctions of the tadpole graph
tadpole.eig <- function(k,graph){
x1 <- c(0,graph$get_edge_lengths()[1]*graph$mesh$PtE[graph$mesh$PtE[,1]==1,2]) 
x2 <- c(0,graph$get_edge_lengths()[2]*graph$mesh$PtE[graph$mesh$PtE[,1]==2,2]) 

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

1.7.3 Function gets.eigen.params()

Given a finite number of modes N_finite, a scaling parameter kappa, a smoothness parameter alpha, and a tadpole graph graph, function gets.eigen.params() computes EIGENVAL_ALPHA (a vector with entries \(\lambda_j^{\alpha/2}\)), EIGENVAL_MINUS_ALPHA (a vector with entries \(\lambda_j^{-\alpha/2}\)), and EIGENFUN (a matrix with columns \(e_j\) on the mesh of graph).

# Function to compute the eigenpairs of the tadpole graph
gets.eigen.params <- function(N_finite = 4, kappa = 1, alpha = 0.5, graph){
  EIGENVAL <- NULL
  EIGENVAL_ALPHA <- NULL
  EIGENVAL_MINUS_ALPHA <- NULL
  EIGENFUN <- NULL
  INDEX <- NULL
  for (j in 0:N_finite) {
    lambda_j <- kappa^2 + (j*pi/2)^2
    lambda_j_alpha_half <- lambda_j^(alpha/2)
    lambda_j_minus_alpha_half <- lambda_j^(-alpha/2)
    e_j <- tadpole.eig(j,graph)$phi
    EIGENVAL <- c(EIGENVAL, lambda_j)
    EIGENVAL_ALPHA <- c(EIGENVAL_ALPHA, lambda_j_alpha_half)  
    EIGENVAL_MINUS_ALPHA <- c(EIGENVAL_MINUS_ALPHA, lambda_j_minus_alpha_half)
    EIGENFUN <- cbind(EIGENFUN, e_j)
    INDEX <- c(INDEX, j)
    if (j>0 && (j %% 2 == 0)) {
      lambda_j <- kappa^2 + (j*pi/2)^2
      lambda_j_alpha_half <- lambda_j^(alpha/2)
      lambda_j_minus_alpha_half <- lambda_j^(-alpha/2)
      e_j <- tadpole.eig(j,graph)$psi
      EIGENVAL <- c(EIGENVAL, lambda_j)
      EIGENVAL_ALPHA <- c(EIGENVAL_ALPHA, lambda_j_alpha_half)    
      EIGENVAL_MINUS_ALPHA <- c(EIGENVAL_MINUS_ALPHA, lambda_j_minus_alpha_half)
      EIGENFUN <- cbind(EIGENFUN, e_j)
      INDEX <- c(INDEX, j+0.1)
      }
    }
  return(list(EIGENVAL = EIGENVAL,
              EIGENVAL_ALPHA = EIGENVAL_ALPHA, 
              EIGENVAL_MINUS_ALPHA = EIGENVAL_MINUS_ALPHA,
              EIGENFUN = EIGENFUN,
              INDEX = INDEX))
}

1.7.4 Function construct_piecewise_projection()

Given a matrix projected_U_approx with approximated values at discrete time points, a sequence of time points time_seq, and an extended sequence of time points overkill_time_seq, function construct_piecewise_projection() constructs a piecewise constant projection of the approximated values over the extended time sequence.

# Function to construct a piecewise constant projection of approximated values
construct_piecewise_projection <- function(projected_U_approx, time_seq, overkill_time_seq) {
  projected_U_piecewise <- matrix(NA, nrow = nrow(projected_U_approx), ncol = length(overkill_time_seq))
  
  # Assign value at t = 0
  projected_U_piecewise[, which(overkill_time_seq == 0)] <- projected_U_approx[, 1]
  
  # Assign values for intervals (t_{k-1}, t_k]
  for (k in 2:length(time_seq)) {
    idxs <- which(overkill_time_seq > time_seq[k - 1] & overkill_time_seq <= time_seq[k])
    projected_U_piecewise[, idxs] <- projected_U_approx[, k]
  }
  
  return(projected_U_piecewise)
}

1.7.5 Functions for computing the true line rates

loglog_line_equation <- function(x1, y1, slope) {
  b <- log10(y1 / (x1 ^ slope))
  
  function(x) {
    (x ^ slope) * (10 ^ b)
  }
}
exp_line_equation <- function(x1, y1, slope) {
  lnC <- log(y1) - slope * x1
  
  function(x) {
    exp(lnC + slope * x)
  }
}
compute_guiding_lines <- function(x_axis_vector, errors, theoretical_rates, line_equation_fun) {
  guiding_lines <- matrix(NA, nrow = length(x_axis_vector), ncol = length(theoretical_rates))
  
  for (j in seq_along(theoretical_rates)) {
    guiding_lines_aux <- matrix(NA, nrow = length(x_axis_vector), ncol = length(x_axis_vector))
    
    for (k in seq_along(x_axis_vector)) {
      point_x1 <- x_axis_vector[k]
      point_y1 <- errors[k, j]
      slope <- theoretical_rates[j]
      
      line <- line_equation_fun(x1 = point_x1, y1 = point_y1, slope = slope)
      guiding_lines_aux[, k] <- line(x_axis_vector)
    }
    
    guiding_lines[, j] <- rowMeans(guiding_lines_aux)
  }
  
  return(guiding_lines)
}
# Functions to compute the exact solution to the fractional diffusion equation
g_linear <- function(r, A, lambda_j_alpha_half) {
  return(A * exp(-lambda_j_alpha_half * r))
  }
G_linear <- function(t, A) {
  return(A * t)
  }
g_exp <- function(r, A, mu) {
  return(A * exp(mu * r))
  }
G_exp <- function(t, A, lambda_j_alpha_half, mu) {
  exponent <- lambda_j_alpha_half + mu
  return(A * (exp(exponent * t) - 1) / exponent)
  }
g_poly <- function(r, A, n) {
  return(A * r^n)
}
G_poly <- function(t, A, lambda_j_alpha_half, n) {
  t <- as.vector(t)
  k_vals <- 0:n
  sum_term <- sapply(t, function(tt) {
    sum(((-lambda_j_alpha_half * tt)^k_vals) / factorial(k_vals))
  })
  coeff <- ((-1)^(n + 1)) * factorial(n) / (lambda_j_alpha_half^(n + 1))
  return(A * coeff * (1 - exp(lambda_j_alpha_half * t) * sum_term))
}
g_sin <- function(r, A, omega) {
  return(A * sin(omega * r))
}
G_sin <- function(t, A, lambda_j_alpha_half, omega) {
  denom <- lambda_j_alpha_half^2 + omega^2
  numerator <- exp(lambda_j_alpha_half * t) * (lambda_j_alpha_half * sin(omega * t) - omega * cos(omega * t)) + omega
  return(A * numerator / denom)
}
g_cos <- function(r, A, theta) {
  return(A * cos(theta * r)) 
}
G_cos <- function(t, A, lambda_j_alpha_half, theta) {
  denom <- lambda_j_alpha_half^2 + theta^2
  numerator <- exp(lambda_j_alpha_half * t) * (lambda_j_alpha_half * cos(theta * t) + theta * sin(theta * t)) - lambda_j_alpha_half
  return(A * numerator / denom)
}

1.7.6 Function reversecolumns()

Given a matrix mat, function reversecolumns() reverses the order of its columns.

reversecolumns <- function(mat) {
  return(mat[, rev(seq_len(ncol(mat)))])
}
# helper: measure change relative to the size of the previous iterate 
change_comparer <- function(X_new, X_old, time_step, C, relative = TRUE) {
  XX <- X_new - X_old
  num <- sqrt(as.double(time_step * sum(XX * (C %*% XX))))
  if (!relative) {
    return(num)
    }
  den <- sqrt(as.double(time_step * sum(X_new * (C %*% X_new))))
  if (den < .Machine$double.eps) {
    return(ifelse(num < .Machine$double.eps, 0, num))
  } else {
    return(num / den)
  }
}
# Coupled solver with multi-criteria convergence
solve_coupled_system_multi_tol <- function(
  my_op_frac,           # operator
  time_step,            # tau
  time_seq,             # vector of times 
  u_0,                  # initial state U^0 
  F_proj,               # matrix of F 
  Z_ini,
  V_d,                  # matrix of 
  u_d,
  Psi,                  # Psi matrix
  R,                    # R matrix
  a, b, C,                # lower/upper bounds (vector or matrix broadcastable to time grid)
  mu,                   # positive scalar
  tol = 1e-8,           # scalar or named list: list(Z=..., U=..., P=...)
  maxit = 200,
  verbose = FALSE,
  nested_spatial_mesh = FALSE,
  true_sol
) {

  if (is.numeric(tol) && length(tol) == 1) {
    tol_list <- list(Z = tol, U = tol, P = tol)
  } else if (is.list(tol)) {
    tol_list <- modifyList(list(Z = 1e-8, U = 1e-8, P = 1e-8), tol)
  } else stop("tol must be scalar or list(Z=...,U=...,P=...)")

  it <- 0
  converged <- FALSE
  
  rel_history <- data.frame(iter = integer(0), variable = character(0), value = numeric(0))
  abs_history <- data.frame(iter = integer(0), variable = character(0), value = numeric(0))
  min_history <- data.frame(iter = integer(0), variable = character(0), value = numeric(0))

  Z_list <- list()
  U_list <- list()
  P_list <- list()
  
  z_prev <- Z_ini
  if(nested_spatial_mesh == TRUE){Z_mat <- C %*% z_prev}else{Z_mat <- R %*% Psi %*% z_prev}
  U_prev <- F_proj*0
  P_prev <- F_proj*0

  repeat {
    it <- it + 1

    U_mat <- solve_forward_evolution(my_op_frac, time_step, time_seq, RHST = F_proj + Z_mat, val_at_0 = u_0)
    if(nested_spatial_mesh == TRUE){V_mat <- C %*% U_mat}else{V_mat <- R %*% Psi %*% U_mat}
    P_mat <- solve_backward_evolution(my_op_frac, time_step, time_seq, RHST = V_mat - V_d)
    z_new <- matrix(pmax(a, pmin(b, - P_mat / mu)), dim(P_mat))
    if(nested_spatial_mesh == TRUE){Z_mat <- C %*% z_new}else{Z_mat <- R %*% Psi %*% z_new}
    
    # relative changes
    rel_changes_Z <- change_comparer(z_new, z_prev, time_step, C, relative = TRUE)  
    rel_changes_U <- change_comparer(U_mat, U_prev, time_step, C, relative = TRUE)
    rel_changes_P <- change_comparer(P_mat, P_prev, time_step, C, relative = TRUE)
    abs_changes_Z <- change_comparer(z_new, true_sol$z_bar, time_step, C, relative = FALSE)
    abs_changes_U <- change_comparer(U_mat, true_sol$u_bar, time_step, C, relative = FALSE)
    abs_changes_P <- change_comparer(P_mat, true_sol$p_bar, time_step, C, relative = FALSE)
    XX <- U_mat - u_d
    min_change <- 0.5 * as.double(time_step * sum(XX * (C %*% XX)))  + 0.5 * mu * as.double(time_step * sum(z_new * (C %*% z_new)))
    rel_history <- rbind(rel_history,
      data.frame(iter = it, variable = "Z", value = rel_changes_Z),
      data.frame(iter = it, variable = "U", value = rel_changes_U),
      data.frame(iter = it, variable = "P", value = rel_changes_P))
    abs_history <- rbind(abs_history,
      data.frame(iter = it, variable = "Z", value = abs_changes_Z),
      data.frame(iter = it, variable = "U", value = abs_changes_U),
      data.frame(iter = it, variable = "P", value = abs_changes_P))
    min_history <- rbind(min_history,
      data.frame(iter = it, variable = "min", value = min_change))
    
    if (verbose) {message(sprintf("iter %3d: rel(Z) = %.3e, rel(U) = %.3e, rel(P) = %.3e", it, rel_changes_Z, rel_changes_U, rel_changes_P))}

    # update stored previous iterates
    z_prev <- z_new
    U_prev <- U_mat
    P_prev <- P_mat
    
    Z_list[[paste0("iteration ", it)]] <- z_new
    U_list[[paste0("iteration ",it)]] <- U_mat
    P_list[[paste0("iteration ",it)]] <- P_mat

    # convergence check: require all rel_changes <= respective tol
    cond_Z <- rel_changes_Z <= tol_list$Z
    cond_U <- rel_changes_U <= tol_list$U
    cond_P <- rel_changes_P <= tol_list$P

    if ((cond_Z && cond_U && cond_P) || it >= maxit) {
      converged <- (cond_Z && cond_U && cond_P)
      break
    }
  }

  if (verbose && !converged) {
    message(sprintf(
      "Stopped at maxit=%d; rel_changes: Z = %.3e (tol %.3e), U = %.3e (tol %.3e), P = %.3e (tol %.3e)",
      it, rel_changes_Z, tol_list$Z, rel_changes_U, tol_list$U, rel_changes_P, tol_list$P
    ))
  }

  return(list(U = U_mat,  # solution U
              Z = z_new,  # solution z
              P = P_mat, # solution P
              iterations = it,
              converged = converged,
              tol_list = tol_list,
              rel_history = rel_history,
              abs_history = abs_history,
              min_history = min_history,
              Z_list = Z_list,
              U_list = U_list,
              P_list = P_list))
}
plot_convergence_history <- function(history_df, tol_list = NULL, type = "relative") {
  if (type == "relative"){
    text_title <- "|X_{iter} - X_{iter-1}| / |X_{iter}|"
  } else if (type == "absolute") {
    text_title <- "|X_{exact} - X_{iter}|"
  } else if (type == "minimum") {
    text_title <- "J(U_{iter},z_{iter})"
  }

  p <- ggplot(history_df, aes(x = iter, y = value, color = variable)) +
    geom_line() +
    geom_point(size = 1.5) +
    scale_y_log10() +
    labs(
      title = text_title,
      x = "Iteration",
      y = "Error",
      color = "Quantity"
    ) +
    theme_minimal()
  
  # Add tolerance lines if provided
  if (!is.null(tol_list)) {
    tol_df <- data.frame(
      variable = names(tol_list),
      tol = unlist(tol_list)
    )
    p <- p + geom_hline(
      data = tol_df,
      aes(yintercept = tol, color = variable),
      linetype = "dashed"
    )
  }
  
  return(plotly::ggplotly(p))
}
largest_nested_h <- function(h_fine, h_candidate) {
  Nfine <- round(1 / h_fine)       # number of intervals in fine mesh
  m0 <- floor(h_candidate / h_fine)
  
  best <- 0
  r <- floor(sqrt(Nfine))
  
  for (a in 1:r) {
    if (Nfine %% a == 0) {
      b <- Nfine / a
      if (a <= m0 && a > best) best <- a
      if (b <= m0 && b > best) best <- b
    }
  }
  
  # if no divisor found, default to h_fine
  if (best == 0) best <- 1
  
  h_coarse <- best * h_fine
  return(h_coarse)
}
trunc_first_signi_digit <- function(x){
  aux <- floor(log10(x))
  return(floor(x / 10^aux) * 10^aux)
}

1.8 Plotting functions

1.8.1 Function plotting.order()

Given a vector v and a graph object graph, function plotting.order() orders the mesh values for plotting.

# Function to order the vertices for plotting
plotting.order <- function(v, graph){
  edge_number <- graph$mesh$VtE[, 1]
  pos <- sum(edge_number == 1)+1
  return(c(v[1], v[3:pos], v[2], v[(pos+1):length(v)], v[2]))
}

1.8.2 Function global.scene.setter()

Given ranges for the x, y, and z axes, and an optional aspect ratio for the z axis, function global.scene.setter() sets the scene for 3D plots so that all plots have the same aspect ratio and camera position.

# Function to set the scene for 3D plots
global.scene.setter <- function(x_range, y_range, z_range, z_aspectratio = 4) {
  
  return(list(xaxis = list(title = "x", range = x_range),
              yaxis = list(title = "y", range = y_range),
              zaxis = list(title = "z", range = z_range),
              aspectratio = list(x = 2*(1+2/pi), 
                                 y = 2*(2/pi), 
                                 z = z_aspectratio*(2/pi)),
              camera = list(eye = list(x = (1+2/pi)/2, 
                                       y = 4, 
                                       z = 2),
                            center = list(x = (1+2/pi)/2, 
                                          y = 0, 
                                          z = 0))))
}

1.8.3 Function graph.plotter.3d()

Given a graph object graph, a sequence of time points time_seq, and one or more matrices ... representing function values defined on the mesh of graph at each time in time_seq, the graph.plotter.3d() function generates an interactive 3D visualization of these values over time.

# Function to plot in 3D
graph.plotter.3d.old <- function(graph, time_seq, frame_val_to_display, ...) {
  U_list <- list(...)
  U_names <- sapply(substitute(list(...))[-1], deparse)

  # Spatial coordinates
  x <- plotting.order(graph$mesh$V[, 1], graph)
  y <- plotting.order(graph$mesh$V[, 2], graph)
  weights <- graph$mesh$weights

  # Apply plotting.order to each U
  U_list <- lapply(U_list, function(U) apply(U, 2, plotting.order, graph = graph))
  n_vars <- length(U_list)

  # Create plot_data frame with time and position replicated
  n_time <- ncol(U_list[[1]])
  base_data <- data.frame(
    x = rep(x, times = n_time),
    y = rep(y, times = n_time),
    the_graph = 0,
    frame = rep(time_seq, each = length(x))
  )

  # Add U columns to plot_data
  for (i in seq_along(U_list)) {
    base_data[[paste0("u", i)]] <- as.vector(U_list[[i]])
  }

  plot_data <- base_data

  # Generate vertical lines
  vertical_lines_list <- lapply(seq_along(U_list), function(i) {
    do.call(rbind, lapply(time_seq, function(t) {
      idx <- which(plot_data$frame == t)
      z_vals <- plot_data[[paste0("u", i)]][idx]
      data.frame(
        x = rep(plot_data$x[idx], each = 3),
        y = rep(plot_data$y[idx], each = 3),
        z = as.vector(t(cbind(0, z_vals, NA))),
        frame = rep(t, each = length(idx) * 3)
      )
    }))
  })

  # Set axis ranges
  z_range <- range(unlist(U_list))
  x_range <- range(x)
  y_range <- range(y)

  # Create plot
  p <- plot_ly(plot_data, frame = ~frame) %>%
    add_trace(x = ~x, y = ~y, z = ~the_graph, type = "scatter3d", mode = "lines",
              name = "", showlegend = FALSE,
              line = list(color = "black", width = 3))

  # Add traces for each variable
  colors <- rev(viridisLite::viridis(n_vars)) #RColorBrewer::brewer.pal(min(n_vars, 8), "Set1")
  for (i in seq_along(U_list)) {
    p <- add_trace(p,
      x = ~x, y = ~y, z = as.formula(paste0("~u", i)),
      type = "scatter3d", mode = "lines", name = U_names[i],
      line = list(color = colors[i], width = 3))
  }

  # Add vertical lines
  for (i in seq_along(vertical_lines_list)) {
    p <- add_trace(p,
      data = vertical_lines_list[[i]],
      x = ~x, y = ~y, z = ~z, frame = ~frame,
      type = "scatter3d", mode = "lines",
      line = list(color = "gray", width = 0.5),
      name = "Vertical lines",
      showlegend = FALSE)
  }
  frame_name <- deparse(substitute(frame_val_to_display))
  # Layout and animation controls
  p <- p %>%
    layout(
      scene = global.scene.setter(x_range, y_range, z_range),
      updatemenus = list(list(type = "buttons", showactive = FALSE,
                              buttons = list(
                                list(label = "Play", method = "animate",
                                     args = list(NULL, list(frame = list(duration = 2000 / length(time_seq), redraw = TRUE), fromcurrent = TRUE))),
                                list(label = "Pause", method = "animate",
                                     args = list(NULL, list(mode = "immediate", frame = list(duration = 0), redraw = FALSE)))
                              )
      )),
      title = paste0(frame_name,": ", formatC(frame_val_to_display[1], format = "f", digits = 4))
    ) %>%
    plotly_build()

  for (i in seq_along(p$x$frames)) {
    p$x$frames[[i]]$layout <- list(title = paste0(frame_name,": ", formatC(frame_val_to_display[i], format = "f", digits = 4)))
  }

  return(p)
}
graph.plotter.3d <- function(graph, time_seq, frame_val_to_display, U_list) {
  U_names <- names(U_list) 
  # Spatial coordinates
  x <- plotting.order(graph$mesh$V[, 1], graph)
  y <- plotting.order(graph$mesh$V[, 2], graph)
  weights <- graph$mesh$weights

  # Apply plotting.order to each U
  U_list <- lapply(U_list, function(U) apply(U, 2, plotting.order, graph = graph))
  n_vars <- length(U_list)
  
  # Create plot_data frame with time and position replicated
  n_time <- ncol(U_list[[1]])
  base_data <- data.frame(
    x = rep(x, times = n_time),
    y = rep(y, times = n_time),
    the_graph = 0,
    frame = rep(time_seq, each = length(x))
  )

  # Add U columns to plot_data
  for (i in seq_along(U_list)) {
    base_data[[paste0("u", i)]] <- as.vector(U_list[[i]])
  }

  plot_data <- base_data

  # Generate vertical lines
  vertical_lines_list <- lapply(seq_along(U_list), function(i) {
    do.call(rbind, lapply(time_seq, function(t) {
      idx <- which(plot_data$frame == t)
      z_vals <- plot_data[[paste0("u", i)]][idx]
      data.frame(
        x = rep(plot_data$x[idx], each = 3),
        y = rep(plot_data$y[idx], each = 3),
        z = as.vector(t(cbind(0, z_vals, NA))),
        frame = rep(t, each = length(idx) * 3)
      )
    }))
  })

  # Set axis ranges
  z_range <- range(unlist(U_list))
  x_range <- range(x)
  y_range <- range(y)

  # Create plot
  p <- plot_ly(plot_data, frame = ~frame) %>%
    add_trace(x = ~x, y = ~y, z = ~the_graph, type = "scatter3d", mode = "lines",
              name = "", showlegend = FALSE,
              line = list(color = "black", width = 3))

  if (n_vars == 2) {
    colors <- RColorBrewer::brewer.pal(min(n_vars, 8), "Set1") 
    } else {
    colors <- rev(viridisLite::viridis(n_vars)) 
  }
  # RColorBrewer::brewer.pal(min(n_vars, 8), "Set1")
  for (i in seq_along(U_list)) {
    p <- add_trace(p,
      x = ~x, y = ~y, z = as.formula(paste0("~u", i)),
      type = "scatter3d", mode = "lines", name = U_names[i],
      line = list(color = colors[i], width = 3))
  }

  # Add vertical lines
  for (i in seq_along(vertical_lines_list)) {
    p <- add_trace(p,
      data = vertical_lines_list[[i]],
      x = ~x, y = ~y, z = ~z, frame = ~frame,
      type = "scatter3d", mode = "lines",
      line = list(color = "gray", width = 0.5),
      name = "Vertical lines",
      showlegend = FALSE)
  }
  frame_name <- deparse(substitute(frame_val_to_display))
  # Layout and animation controls
  p <- p %>%
    layout(
      scene = global.scene.setter(x_range, y_range, z_range),
      updatemenus = list(list(type = "buttons", showactive = FALSE,
                              buttons = list(
                                list(label = "Play", method = "animate",
                                     args = list(NULL, list(frame = list(duration = 2000 / length(time_seq), redraw = TRUE), fromcurrent = TRUE))),
                                list(label = "Pause", method = "animate",
                                     args = list(NULL, list(mode = "immediate", frame = list(duration = 0), redraw = FALSE)))
                              )
      )),
      title = paste0(frame_name,": ", formatC(frame_val_to_display[1], format = "f", digits = 4))
    ) %>%
    plotly_build()

  for (i in seq_along(p$x$frames)) {
    p$x$frames[[i]]$layout <- list(title = paste0(frame_name,": ", formatC(frame_val_to_display[i], format = "f", digits = 4)))
  }

  return(p)
}

1.8.4 Function error.at.each.time.plotter()

Given a graph object graph, a matrix U_true of true values, a matrix U_approx of approximated values, a sequence of time points time_seq, and a time step time_step, function error.at.each.time.plotter() computes the error at each time step and generates a plot showing the error over time.

# Function to plot the error at each time step
error.at.each.time.plotter <- function(graph, U_true, U_approx, time_seq, time_step) {
  weights <- graph$mesh$weights
  error_at_each_time <- t(weights) %*% (U_true - U_approx)^2
  error <- sqrt(as.double(t(weights) %*% (U_true - U_approx)^2 %*% rep(time_step, ncol(U_true))))
  p <- plot_ly() %>% 
  add_trace(
  x = ~time_seq, y = ~error_at_each_time, type = 'scatter', mode = 'lines+markers',
  line = list(color = 'blue', width = 2),
  marker = list(color = 'blue', size = 4),
  name = "",
  showlegend = TRUE
) %>% 
  layout(
  title = paste0("Error at Each Time Step (Total error = ", formatC(error, format = "f", digits = 9), ")"),
  xaxis = list(title = "t"),
  yaxis = list(title = "Error"),
  legend = list(x = 0.1, y = 0.9)
)
  return(p)
}

1.8.5 Function graph.plotter.3d.comparer()

Given a graph object graph, matrices U_true and U_approx representing true and approximated values, and a sequence of time points time_seq, function graph.plotter.3d.comparer() generates a 3D plot comparing the true and approximated values over time, with color-coded traces for each time point.

# Function to plot the 3D comparison of U_true and U_approx
graph.plotter.3d.comparer <- function(graph, U_true, U_approx, time_seq) {
  x <- graph$mesh$V[, 1]; y <- graph$mesh$V[, 2]
  x <- plotting.order(x, graph); y <- plotting.order(y, graph)

  U_true <- apply(U_true, 2, plotting.order, graph = graph)
  U_approx <- apply(U_approx, 2, plotting.order, graph = graph)
  n_times <- length(time_seq)
  
  x_range <- range(x); y_range <- range(y); z_range <- range(c(U_true, U_approx))
  
  # Normalize time_seq
  time_normalized <- (time_seq - min(time_seq)) / (max(time_seq) - min(time_seq))
  blues <- colorRampPalette(c("lightblue", "blue"))(n_times)
  reds <- colorRampPalette(c("mistyrose", "red"))(n_times)
  
  # Accurate colorscales
  colorscale_greens <- Map(function(t, col) list(t, col), time_normalized, blues)
  colorscale_reds <- Map(function(t, col) list(t, col), time_normalized, reds)
  
  p <- plot_ly()
  
  # Static black graph structure
  p <- p %>%
    add_trace(x = x, y = y, z = rep(0, length(x)),
              type = "scatter3d", mode = "lines",
              line = list(color = "black", width = 4),
              name = "Graph", showlegend = FALSE)
  
  # U_true traces (green)
  for (i in seq_len(n_times)) {
    z <- U_true[, i]
    p <- add_trace(
      p,
      type = "scatter3d",
      mode = "lines",
      x = x, y = y, z = z,
      line = list(color = blues[i], width = 4),
      showlegend = FALSE,
      scene = "scene"
    )
  }
  
  # U_approx traces (dashed red)
  for (i in seq_len(n_times)) {
    z <- U_approx[, i]
    p <- add_trace(
      p,
      type = "scatter3d",
      mode = "lines",
      x = x, y = y, z = z,
      line = list(color = reds[i], width = 4, dash = "dot"),
      showlegend = FALSE,
      scene = "scene"
    )
  }
  
  # Dummy green colorbar (True) – with ticks
  p <- add_trace(
    p,
    type = "heatmap",
    z = matrix(time_seq, nrow = 1),
    showscale = TRUE,
    colorscale = colorscale_greens,
    colorbar = list(
      title = list(font = list(size = 12, color = "black"), text = "Time", side = "top"),
      len = 0.9,
      thickness = 15,
      x = 1.02,
      xanchor = "left",
      y = 0.5,
      yanchor = "middle",
      tickvals = NULL,   # hide tick values
      ticktext = NULL,
      ticks = ""         # also hides tick marks
    ),
    x = matrix(time_seq, nrow = 1),
    y = matrix(1, nrow = 1),
    hoverinfo = "skip",
    opacity = 0
  )

# Dummy red colorbar (Approx) – no ticks
  p <- add_trace(
    p,
    type = "heatmap",
    z = matrix(time_seq, nrow = 1),
    showscale = TRUE,
    colorscale = colorscale_reds,
    colorbar = list(
      title = list(font = list(size = 12, color = "black"), text = ".", side = "top"),
      len = 0.9,
      thickness = 15,
      x = 1.05,
      xanchor = "left",
      y = 0.5,
      yanchor = "middle"
    ),
    x = matrix(time_seq, nrow = 1),
    y = matrix(1, nrow = 1),
    hoverinfo = "skip",
    opacity = 0
  )
  p <- p %>%
    add_trace(x = x, y = y, z = rep(0, length(x)),
              type = "scatter3d", mode = "lines",
              line = list(color = "black", width = 4),
              name = "Graph", showlegend = FALSE)
  p <- layout(p,
            scene = global.scene.setter(x_range, y_range, z_range),
            xaxis = list(visible = FALSE),
            yaxis = list(visible = FALSE),
            annotations = list(
  list(
    text = "Exact",
    x = 1.045,
    y = 0.5,
    xref = "paper",
    yref = "paper",
    showarrow = FALSE,
    font = list(size = 12, color = "black"),
    textangle = -90
  ),
  list(
    text = "Approx",
    x = 1.075,
    y = 0.5,
    xref = "paper",
    yref = "paper",
    showarrow = FALSE,
    font = list(size = 12, color = "black"),
    textangle = -90
  )
)

)

  
  return(p)
}

1.8.6 Function graph.plotter.3d.single()

Given a graph object graph, a matrix U_true representing true values, and a sequence of time points time_seq, function graph.plotter.3d.single() generates a 3D plot of the true values over time, with color-coded traces for each time point.

# Function to plot a single 3D line for 
graph.plotter.3d.single <- function(graph, U_true, time_seq) {
  x <- graph$mesh$V[, 1]; y <- graph$mesh$V[, 2]
  x <- plotting.order(x, graph); y <- plotting.order(y, graph)

  U_true <- apply(U_true, 2, plotting.order, graph = graph)
  n_times <- length(time_seq)
  
  x_range <- range(x); y_range <- range(y); z_range <- range(U_true)
  z_range[1] <- z_range[1] - 10^-6
  viridis_colors <- viridisLite::viridis(100)
  
  # Normalize time_seq
  time_normalized <- (time_seq - min(time_seq)) / (max(time_seq) - min(time_seq))
  #greens <- colorRampPalette(c("palegreen", "darkgreen"))(n_times)
  greens <- colorRampPalette(c(viridis_colors[1], viridis_colors[50],  viridis_colors[100]))(n_times)
  # Accurate colorscales
  colorscale_greens <- Map(function(t, col) list(t, col), time_normalized, greens)
  
  p <- plot_ly()
  
  # Add the 3D lines with fading green color
  for (i in seq_len(n_times)) {
    z <- U_true[, i]
    
    p <- add_trace(
      p,
      type = "scatter3d",
      mode = "lines",
      x = x,
      y = y,
      z = z,
      line = list(color = greens[i], width = 2),
      showlegend = FALSE,
      scene = "scene"
    )
  }
  p <- p %>%
    add_trace(x = x, y = y, z = rep(0, length(x)),
              type = "scatter3d", mode = "lines",
              line = list(color = "black", width = 5),
              name = "Graph", showlegend = FALSE)
  # Add dummy heatmap to show colorbar (not part of scene)
  p <- add_trace(
    p,
    type = "heatmap",
    z = matrix(time_seq, nrow = 1),
    showscale = TRUE,
    colorscale = colorscale_greens,
    colorbar = list(
    title = list(font = list(size = 12, color = "black"), text = "Time", side = "top"),
    len = 0.9,         # height (0 to 1)
    thickness = 15,     # width in pixels
    x = 1.02,           # shift it slightly right of the plot
    xanchor = "left",
    y = 0.5,
    yanchor = "middle"),
    x = matrix(time_seq, nrow = 1),
    y = matrix(1, nrow = 1),
    hoverinfo = "skip",
    opacity = 0
  )
  
  p <- layout(p,
              scene = global.scene.setter(x_range, y_range, z_range),
              xaxis = list(visible = FALSE),
              yaxis = list(visible = FALSE)
  )
  
  return(p)
}

1.8.7 Function error.convergence.plotter()

# Function to plot the error convergence
error.convergence.plotter <- function(x_axis_vector, 
                                      alpha_vector, 
                                      errors, 
                                      theoretical_rates, 
                                      observed_rates,
                                      line_equation_fun,
                                      fig_title,
                                      x_axis_label,
                                      apply_sqrt = FALSE) {
  
  x_vec <- if (apply_sqrt) sqrt(x_axis_vector) else x_axis_vector
  
  guiding_lines <- compute_guiding_lines(x_axis_vector = x_vec, 
                                         errors = errors, 
                                         theoretical_rates = theoretical_rates, 
                                         line_equation_fun = line_equation_fun)
  
  default_colors <- scales::hue_pal()(length(alpha_vector))
  
  plot_lines <- lapply(1:ncol(guiding_lines), function(i) {
    geom_line(
      data = data.frame(x = x_vec, y = guiding_lines[, i]),
      aes(x = x, y = y),
      color = default_colors[i],
      linetype = "dashed",
      show.legend = FALSE
    )
  })
  
  df <- as.data.frame(cbind(x_vec, errors))
  colnames(df) <- c("x_axis_vector", alpha_vector)
  df_melted <- melt(df, id.vars = "x_axis_vector", variable.name = "column", value.name = "value")
  
  custom_labels <- paste0(formatC(alpha_vector, format = "f", digits = 2), 
                          " | ", 
                          formatC(theoretical_rates, format = "f", digits = 4), 
                          " | ", 
                          formatC(observed_rates, format = "f", digits = 4))
  
  df_melted$column <- factor(df_melted$column, levels = alpha_vector, labels = custom_labels)

  p <- ggplot() +
    geom_line(data = df_melted, aes(x = x_axis_vector, y = value, color = column)) +
    geom_point(data = df_melted, aes(x = x_axis_vector, y = value, color = column)) +
    plot_lines +
    labs(
      title = fig_title,
      x = x_axis_label,
      y = expression(Error),
      color = "          Ξ±  | theo  | obs"
    ) +
    (if (apply_sqrt) {
      scale_x_continuous(breaks = x_vec, labels = round(x_axis_vector, 4))
    } else {
      scale_x_log10(breaks = x_axis_vector, labels = round(x_axis_vector, 4))
    }) +
    (if (apply_sqrt) {
      scale_y_continuous(trans = "log", labels = scales::scientific_format())
    } else {
      scale_y_log10(labels = scales::scientific_format())
    }) +
    theme_minimal() +
    theme(text = element_text(family = "Palatino"),
          legend.position = "bottom",
          legend.direction = "vertical",
          plot.margin = margin(0, 0, 0, 0),
          plot.title = element_text(hjust = 0.5, size = 18, face = "bold"))
  
  return(p)
}
graph.plotter.3d.static <- function(graph, z_list) {
  x <- plotting.order(graph$mesh$V[, 1], graph)
  y <- plotting.order(graph$mesh$V[, 2], graph)
  U_names <- names(z_list)
  n_vars <- length(z_list)
  z_list <- lapply(z_list, function(z) plotting.order(z, graph))

  # Axis ranges
  z_range <- range(unlist(z_list))
  x_range <- range(x)
  y_range <- range(y)

  if (n_vars == 2) {
    colors <- RColorBrewer::brewer.pal(min(n_vars, 8), "Set1") 
    } else {
    colors <- rev(viridisLite::viridis(n_vars)) 
  }
  p <- plot_ly()

  for (i in seq_along(z_list)) {
    z <- z_list[[i]]

    # Main 3D curve
    p <- add_trace(
      p,
      x = x, y = y, z = z,
      type = "scatter3d", mode = "lines",
      line = list(color = colors[i], width = 3),
      name = U_names[i], showlegend = TRUE
    )

    # Efficient vertical lines: one trace with breaks (NA)
    x_vert <- rep(x, each = 3)
    y_vert <- rep(y, each = 3)
    z_vert <- unlist(lapply(z, function(zj) c(0, zj, NA)))

    p <- add_trace(
      p,
      x = x_vert, y = y_vert, z = z_vert,
      type = "scatter3d", mode = "lines",
      line = list(color = "gray", width = 0.5),
      showlegend = FALSE
    )
  }
  p <- p %>% add_trace(x = x, y = y, z = x*0, type = "scatter3d", mode = "lines",
              line = list(color = "black", width = 3),
              name = "thegraph", showlegend = FALSE) %>%
    layout(scene = global.scene.setter(x_range, y_range, z_range))
  return(p)
}
graph.plotter.3d.two.meshes.time <- function(graph_finer, graph_coarser, 
                                             time_seq, frame_val_to_display,
                                             fs_finer = list(), fs_coarser = list()) {
  # Spatial coordinates (ordered for plotting)
  x_finer <- plotting.order(graph_finer$mesh$V[, 1], graph_finer)
  y_finer <- plotting.order(graph_finer$mesh$V[, 2], graph_finer)
  x_coarser <- plotting.order(graph_coarser$mesh$V[, 1], graph_coarser)
  y_coarser <- plotting.order(graph_coarser$mesh$V[, 2], graph_coarser)
  
  n_time <- if (length(fs_finer) > 0) ncol(fs_finer[[1]]) else ncol(fs_coarser[[1]])

  # Helper: make dataframe from one function
  make_df <- function(f_mat, graph, x, y, mesh_name) {
    z <- apply(f_mat, 2, plotting.order, graph = graph)
    data.frame(
      x = rep(x, times = n_time),
      y = rep(y, times = n_time),
      z = as.vector(z),
      frame = rep(time_seq, each = length(x)),
      mesh = mesh_name
    )
  }
  
  # Build data for finer functions
  data_finer_list <- lapply(names(fs_finer), function(nm) {
    make_df(fs_finer[[nm]], graph_finer, x_finer, y_finer, nm)
  })
  
  # Build data for coarser functions
  data_coarser_list <- lapply(names(fs_coarser), function(nm) {
    make_df(fs_coarser[[nm]], graph_coarser, x_coarser, y_coarser, nm)
  })
  
  # Combine
  all_data <- c(data_finer_list, data_coarser_list)
  
  # Baseline graph (on finer mesh for consistency)
  data_graph <- data.frame(
    x = rep(x_finer, times = n_time),
    y = rep(y_finer, times = n_time),
    z = 0,
    frame = rep(time_seq, each = length(x_finer)),
    mesh = "Graph"
  )
  
# --------- Vertical lines helper ----------
vertical_lines <- function(x, y, z, frame_vals, mesh_name) {
  do.call(rbind, lapply(seq_along(frame_vals), function(i) {
    idx <- ((i - 1) * length(x) + 1):(i * length(x))
    data.frame(
      x = rep(x, each = 3),
      y = rep(y, each = 3),
      z = as.vector(t(cbind(0, z[idx], NA))),
      frame = rep(frame_vals[i], each = length(x) * 3),
      mesh = mesh_name
    )
  }))
}

# --------- Compute vertical lines per mesh using max absolute value ---------
make_vertical_from_list <- function(data_list, x, y, mesh_name) {
  if (length(data_list) == 0) return(NULL)
  
  # Reshape each function's z back to matrix: (nodes Γ— time)
  z_mats <- lapply(data_list, function(df) {
    matrix(df$z, nrow = length(x), ncol = length(time_seq))
  })
  
  # Stack into 3D array: (nodes Γ— time Γ— functions)
  arr <- array(unlist(z_mats), dim = c(length(x), length(time_seq), length(z_mats)))
  
  # For each node Γ— time, select the entry with largest absolute value (keep sign)
  idx <- apply(arr, c(1, 2), function(v) which.max(abs(v)))
  z_signed_max <- mapply(function(i, j) arr[i, j, idx[i, j]],
                         rep(1:length(x), times = length(time_seq)),
                         rep(1:length(time_seq), each = length(x)))
  
  # Flatten back into long vector
  z_signed_max <- as.vector(z_signed_max)
  
  vertical_lines(x, y, z_signed_max, time_seq, mesh_name)
}


vertical_finer   <- make_vertical_from_list(data_finer_list,   x_finer,   y_finer,   "finer")
vertical_coarser <- make_vertical_from_list(data_coarser_list, x_coarser, y_coarser, "coarser")

  
  # Compute ranges
  all_z <- unlist(lapply(all_data, function(df) df$z))
  x_range <- range(c(x_finer, x_coarser))
  y_range <- range(c(y_finer, y_coarser))
  z_range <- range(all_z)
  
  # --------- Plotly object ----------
  p <- plot_ly(frame = ~frame)
  
  # Add traces for finer + coarser (looping automatically with names)
  for (df in all_data) {
    p <- p %>%
      add_trace(data = df,
                x = ~x, y = ~y, z = ~z,
                type = "scatter3d", mode = "lines",
                line = list(width = 3),
                name = unique(df$mesh))
  }
  
  # Add baseline
  p <- p %>%
    add_trace(data = data_graph,
              x = ~x, y = ~y, z = ~z,
              type = "scatter3d", mode = "lines",
              line = list(color = "black", width = 2),
              name = "Graph", showlegend = FALSE)
  
# Add verticals (one per mesh, envelope of all functions)
if (!is.null(vertical_finer)) {
  p <- p %>%
    add_trace(data = vertical_finer,
              x = ~x, y = ~y, z = ~z,
              type = "scatter3d", mode = "lines",
              line = list(color = "gray", width = 0.5),
              name = "Vertical finer", showlegend = FALSE)
}
if (!is.null(vertical_coarser)) {
  p <- p %>%
    add_trace(data = vertical_coarser,
              x = ~x, y = ~y, z = ~z,
              type = "scatter3d", mode = "lines",
              line = list(color = "gray", width = 0.5),
              name = "Vertical coarser", showlegend = FALSE)
}

  
  frame_name <- deparse(substitute(frame_val_to_display))
  
  p <- p %>%
    layout(
      scene = global.scene.setter(x_range, y_range, z_range),
      updatemenus = list(list(
        type = "buttons", showactive = FALSE,
        buttons = list(
          list(label = "Play", method = "animate",
               args = list(NULL, list(frame = list(duration = 2000 / length(time_seq), redraw = TRUE),
                                      fromcurrent = TRUE))),
          list(label = "Pause", method = "animate",
               args = list(NULL, list(mode = "immediate", 
                                      frame = list(duration = 0), redraw = FALSE)))
        )
      )),
      title = paste0(frame_name, ": ", formatC(frame_val_to_display[1], format = "f", digits = 4))
    ) %>%
    plotly_build()
  
  # Update frame titles
  for (i in seq_along(p$x$frames)) {
    p$x$frames[[i]]$layout <- list(
      title = paste0(frame_name, ": ", formatC(frame_val_to_display[i], format = "f", digits = 4))
    )
  }
  
  return(p)
}

1.9 Check norm identity

The following code builds matrix \(\boldsymbol{\mathfrak{B}}\) in \(\eqref{matrixB}\) (object big_matrix below) and compares its 2-norm to that of matrix \(\mathbf{T}\) in \(\eqref{matrixT}\) (object TT below) times \(\tau^2\).

# check norm identity
T_final <- 2
time_step <- 0.001 
h <- 1
kappa <- 15
alpha <- 0.5 
m = 1
beta <- alpha/2

graph <- gets.graph.tadpole(h = h)
graph$compute_fem()
G <- graph$mesh$G
C <- graph$mesh$C
L <- kappa^2*C + G
I <- Matrix::Diagonal(nrow(C))

# Numerical solution
obj <- my.fractional.operators.frac(L, beta, C, scale.factor = kappa^2, m = m, time_step)
partial_fraction_terms <- obj$partial_fraction_terms
residues <- obj$residues
output <- I*0
for (i in 1:(m+1)) {output <- output + residues[i] * solve(partial_fraction_terms[[i]], I)}
R <- output

C_sqrt <- expm::sqrtm(C)       # matrix square root
Omega <- C_sqrt %*% R %*% C_sqrt
n <- nrow(Omega)
Omega2 <- Omega %*% Omega
Omega3 <- Omega2 %*% Omega
Omega4 <- Omega2 %*% Omega2
Omega5 <- Omega3 %*% Omega2
Omega6 <- Omega3 %*% Omega3
B11 <- matrix(0, nrow = n, ncol = n)
B12 <- Omega2 + Omega4 + Omega6
B13 <- Omega3 + Omega5
B14 <- Omega4

B21 <- matrix(0, nrow = n, ncol = n)
B22 <- Omega3 + Omega5
B23 <- Omega2 + Omega4
B24 <- Omega3

B31 <- matrix(0, nrow = n, ncol = n)
B32 <- Omega4
B33 <- Omega3
B34 <- Omega2

B41 <- matrix(0, nrow = n, ncol = n)
B42 <- matrix(0, nrow = n, ncol = n)
B43 <- matrix(0, nrow = n, ncol = n)
B44 <- matrix(0, nrow = n, ncol = n)

big_matrix <- time_step^2 * rbind(
  cbind(B11, B12, B13, B14),
  cbind(B21, B22, B23, B24),
  cbind(B31, B32, B33, B34),
  cbind(B41, B42, B43, B44)
)

omega <- 1/(1+time_step * kappa^(2*beta))

TT <- build_T_fast(omega, 3)

time_step^2 * norm(TT, type = "2")
## [1] 4.976473e-06
norm(big_matrix, type = "2")
## [1] 4.976097e-06

1.10 Comparison between \(\gamma\) and its upper bound \(1/(\mu \kappa^{4 \beta})\)

# --- 3. Parameter grid ---
T_final <- 2
tau_vector <- c(0.001, 0.01, 0.1)
N_vector <- T_final / tau_vector
kappa_vector <- c(1, 4, 16)
beta_vector <- c(0.5, 0.7, 0.9)
mu_vector <- c(0.1, 1, 10)

results <- expand.grid(
  tau = tau_vector,
  kappa = kappa_vector,
  beta = beta_vector,
  mu = mu_vector
)

# --- 4. Parallel computation with caching (A depends on Ο‰ and N only) ---
cache <- new.env(hash = TRUE)

results$L_c <- unlist(pbmclapply(
  1:nrow(results),
  function(i) {
    tau <- results$tau[i]
    kappa <- results$kappa[i]
    beta <- results$beta[i]
    mu <- results$mu[i]
    
    omega <- 1 / (1 + tau * kappa^(2 * beta))
    N <- as.integer(T_final / tau)
    key <- paste0(round(omega, 10), "_", N)
    
    if (exists(key, envir = cache)) {
      lambda_max <- get(key, envir = cache)
    } else {
      A <- build_T_fast(omega, N)
      lambda_max <- max(eigen(A, symmetric = TRUE, only.values = TRUE)$values)
      assign(key, lambda_max, envir = cache)
    }
    
    (tau^2 * lambda_max) / mu
  },
  mc.cores = parallel::detectCores()
))

save(results, file = here::here("data_files/contraction_constant_results2.RData"))
library(pbmcapply)
library(ggplot2)
library(scales)
library(dplyr)
library(patchwork)
T_final <- 2
load(here::here("data_files/contraction_constant_results2.RData"))
all_results <- results %>% 
  mutate(upperbound = 1/(mu*kappa^(4*beta))) %>%
  mutate(T_final = T_final) %>%
  mutate(N = T_final/tau) %>%
  mutate(L_cless1 = L_c < 1) %>%
  mutate(Tlessmukappa2beta = T_final < (mu * kappa^(2*beta))) %>%
  mutate(onelessmukappa4beta  = upperbound < 1) 


# Find combined y-limits
ymin <- min(all_results$L_c, all_results$upperbound, na.rm = TRUE)
ymax <- max(all_results$L_c, all_results$upperbound, na.rm = TRUE)

p <- ggplot(all_results, aes(x = N, y = L_c,
                             color = factor(kappa),
                             shape = factor(beta),
                             linetype = factor(mu))) +
  geom_point(size = 3) +
  geom_line(aes(group = interaction(kappa, beta, mu)), alpha = 1) +
  scale_x_log10() +
  scale_y_log10(
    limits = c(ymin, ymax),
    breaks = trans_breaks("log10", function(x) 10^x),
    labels = label_scientific()
  ) +
  scale_linetype_manual(values = c("solid", "dashed", "dotted")) +
  labs(x = "N",
       y = expression(gamma),
       color = expression(kappa),
       shape = expression(beta),
       linetype = expression(mu)) +
  theme_minimal(base_size = 14, base_family = "Palatino")

q <- ggplot(all_results, aes(x = N, y = upperbound,
                             color = factor(kappa),
                             shape = factor(beta),
                             linetype = factor(mu))) +
  geom_point(size = 3) +
  geom_line(aes(group = interaction(kappa, beta, mu)), alpha = 1) +
  scale_x_log10() +
  scale_y_log10(
    limits = c(ymin, ymax),
    breaks = trans_breaks("log10", function(x) 10^x),
    labels = label_scientific(),
    position = "right"
  ) +
  scale_linetype_manual(values = c("solid", "dashed", "dotted")) +
  labs(x = "N",
       y = expression(1 / mu * kappa^{4 * beta}),
       color = expression(kappa),
       shape = expression(beta),
       linetype = expression(mu)) +
  theme_minimal(base_size = 14, base_family = "Palatino")


combined2 <- (p | q) + 
  plot_annotation(
    title = expression("Contraction constant " * gamma * " and its upper bound " * 1 / mu * kappa^{4 * beta}),
    theme = theme(plot.title = element_text(size = 18, face = "bold", hjust = 0.5, 
                                            family = "Palatino"))
  ) +
  plot_layout(guides = "collect") & 
  theme(legend.position = "bottom")
combined2
Figure 1: Comparison of the contraction constant $\gamma =  \tau^2\|\mathbf{T}\|_2/\mu$ and its theoretical upper bound $1 / (\mu \kappa^{4 \beta})$ as functions of the sample size $N$ for $T = 2$. Different colors, shapes, and line types correspond to variations in $\kappa$, $\beta$, and $\mu$, respectively. Both plots have their x- and y-axes on a $\log_{10}$ scale, and they share the same y-axis limits for direct comparability.

Figure 1: Comparison of the contraction constant \(\gamma = \tau^2\|\mathbf{T}\|_2/\mu\) and its theoretical upper bound \(1 / (\mu \kappa^{4 \beta})\) as functions of the sample size \(N\) for \(T = 2\). Different colors, shapes, and line types correspond to variations in \(\kappa\), \(\beta\), and \(\mu\), respectively. Both plots have their x- and y-axes on a \(\log_{10}\) scale, and they share the same y-axis limits for direct comparability.

ggsave(
  here::here("data_files/fixedpointconvergence_combined2.png"),
  width = 12, height = 7, plot = combined2, dpi = 300
)

1.11 References

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

We used R version 4.5.2 (R Core Team 2025) and the following R packages: akima v. 0.6.3.6 (Akima and Gebhardt 2025), expm v. 1.0.0 (Maechler, Dutang, and Goulet 2024), fmesher v. 0.5.0 (Lindgren 2025), gsignal v. 0.3.7 (Van Boxtel, G.J.M., et al. 2021), 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, 2025a), 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), neuralnet v. 1.44.2 (Fritsch, Guenther, and Wright 2019), orthopolynom v. 1.0.6.1 (Novomestky 2022), patchwork v. 1.3.1 (Pedersen 2025), pbmcapply v. 1.5.1 (Kuang, Kong, and Napolitano 2022), plotly v. 4.11.0 (Sievert 2020), posterdown v. 1.0 (Thorne 2019), pracma v. 2.4.4 (Borchers 2023), qrcode v. 0.3.0 (Onkelinx and Teh 2024), RColorBrewer v. 1.1.3 (Neuwirth 2022), RefManageR v. 1.4.0 (McLean 2014, 2017), renv v. 1.1.5 (Ushey and Wickham 2025), 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.1.9000 (Bolin and Kirchner 2020; Bolin and Simas 2023; Bolin, Simas, and Xiong 2024), RSpectra v. 0.16.2 (Qiu and Mei 2024), scales v. 1.4.0 (Wickham, Pedersen, and Seidel 2025), slackr v. 3.4.0 (Kaye et al. 2025), tidyverse v. 2.0.0 (Wickham et al. 2019), viridisLite v. 0.4.2 (Garnier et al. 2023), xaringan v. 0.31 (Xie 2025b), xaringanExtra v. 0.8.0 (Aden-Buie and Warkentin 2024), xaringanthemer v. 0.4.4 (Aden-Buie 2025).

Aden-Buie, Garrick. 2025. xaringanthemer: Custom β€œxaringan” CSS Themes. https://doi.org/10.32614/CRAN.package.xaringanthemer.
Aden-Buie, Garrick, and Matthew T. Warkentin. 2024. xaringanExtra: Extras and Extensions for β€œxaringan” Slides. https://doi.org/10.32614/CRAN.package.xaringanExtra.
Akima, Hiroshi, and Albrecht Gebhardt. 2025. akima: Interpolation of Irregularly and Regularly Spaced Data. https://doi.org/10.32614/CRAN.package.akima.
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.
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.
Fritsch, Stefan, Frauke Guenther, and Marvin N. Wright. 2019. neuralnet: Training of Neural Networks. https://doi.org/10.32614/CRAN.package.neuralnet.
Garnier, Simon, Ross, Noam, Rudis, Robert, Camargo, et al. 2023. viridis(Lite) - Colorblind-Friendly Color Maps for r. https://doi.org/10.5281/zenodo.4678327.
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.
Kuang, Kevin, Quyu Kong, and Francesco Napolitano. 2022. pbmcapply: Tracking the Progress of Mc*pply with Progress Bar. https://doi.org/10.32614/CRAN.package.pbmcapply.
Lindgren, Finn. 2025. fmesher: Triangle Meshes and Related Geometry Tools. https://github.com/inlabru-org/fmesher.
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.
Maechler, Martin, Christophe Dutang, and Vincent Goulet. 2024. expm: Matrix Exponential, Log, β€œetc”. https://doi.org/10.32614/CRAN.package.expm.
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.
McLean, Mathew William. 2014. Straightforward Bibliography Management in r Using the RefManager Package. https://arxiv.org/abs/1403.2036.
β€”β€”β€”. 2017. β€œRefManageR: Import and Manage BibTeX and BibLaTeX References in r.” The Journal of Open Source Software. https://doi.org/10.21105/joss.00338.
MΓΌller, Kirill. 2020. here: A Simpler Way to Find Your Files. https://doi.org/10.32614/CRAN.package.here.
Neuwirth, Erich. 2022. RColorBrewer: ColorBrewer Palettes.
Novomestky, Frederick. 2022. orthopolynom: Collection of Functions for Orthogonal and Orthonormal Polynomials. https://doi.org/10.32614/CRAN.package.orthopolynom.
Onkelinx, Thierry, and Victor Teh. 2024. qrcode: Generate QRcodes with r. Version 0.3.0. https://doi.org/10.5281/zenodo.5040088.
Pedersen, Thomas Lin. 2025. patchwork: The Composer of Plots. https://doi.org/10.32614/CRAN.package.patchwork.
Qiu, Yixuan, and Jiali Mei. 2024. RSpectra: Solvers for Large-Scale Eigenvalue and SVD Problems. https://doi.org/10.32614/CRAN.package.RSpectra.
R Core Team. 2025. R: A Language and Environment for Statistical Computing. Vienna, Austria: R Foundation for Statistical Computing. https://www.R-project.org/.
Rue, HΓ₯vard, Sara Martino, and Nicholas Chopin. 2009. β€œApproximate Bayesian Inference for Latent Gaussian Models Using Integrated Nested Laplace Approximations (with Discussion).” Journal of the Royal Statistical Society B 71: 319–92.
Rue, HΓ₯vard, Andrea I. Riebler, Sigrunn H. SΓΈrbye, Janine B. Illian, Daniel P. Simpson, and Finn K. Lindgren. 2017. β€œBayesian Computing with INLA: A Review.” Annual Reviews of Statistics and Its Applications 4 (March): 395–421. http://arxiv.org/abs/1604.00860.
Sievert, Carson. 2020. Interactive Web-Based Data Visualization with r, Plotly, and Shiny. Chapman; Hall/CRC. https://plotly-r.com.
Thorne, W. Brent. 2019. posterdown: An r Package Built to Generate Reproducible Conference Posters for the Academic and Professional World Where Powerpoint and Pages Just Won’t Cut It. https://github.com/brentthorne/posterdown.
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. 2025. renv: Project Environments. https://rstudio.github.io/renv/.
Van Boxtel, G.J.M., et al. 2021. gsignal: Signal Processing. https://github.com/gjmvanboxtel/gsignal.
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.
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/.
β€”β€”β€”. 2025a. knitr: A General-Purpose Package for Dynamic Report Generation in R. https://yihui.org/knitr/.
β€”β€”β€”. 2025b. xaringan: Presentation Ninja. https://doi.org/10.32614/CRAN.package.xaringan.
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.
LS0tCnRpdGxlOiAiQ29udHJvbCBGdW5jdGlvbmFsaXR5IgpkYXRlOiAiTGFzdCBtb2RpZmllZDogYHIgZm9ybWF0KFN5cy50aW1lKCksICclZC0lbS0lWS4nKWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgbWF0aGpheDogImh0dHBzOi8vY2RuLmpzZGVsaXZyLm5ldC9ucG0vbWF0aGpheEAzL2VzNS90ZXgtbW1sLWNodG1sLmpzIgogICAgaGlnaGxpZ2h0OiBweWdtZW50cwogICAgdGhlbWU6IGZsYXRseQogICAgY29kZV9mb2xkaW5nOiBzaG93ICMgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSIgdG8gaGlkZSBjb2RlIGFuZCBhZGQgYSBidXR0b24gdG8gc2hvdyBpdAogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiB0cnVlCiAgICAgIHNtb290aF9zY3JvbGw6IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgZmlnX2NhcHRpb246IHRydWUKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNzczogdmlzdWFsLmNzcwphbHdheXNfYWxsb3dfaHRtbDogdHJ1ZQpiaWJsaW9ncmFwaHk6IAogIC0gcmVmZXJlbmNlcy5iaWIKICAtIGdyYXRlZnVsLXJlZnMuYmliCmhlYWRlci1pbmNsdWRlczoKICAtIFxuZXdjb21tYW5ke1xhcn17XG1hdGhiYntSfX0KICAtIFxuZXdjb21tYW5ke1xsbGF2fVsxXXtcbGVmdFx7IzFccmlnaHRcfX0KICAtIFxuZXdjb21tYW5ke1xwYXJlfVsxXXtcbGVmdCgjMVxyaWdodCl9CiAgLSBcbmV3Y29tbWFuZHtcTmNhbH17XG1hdGhjYWx7Tn19CiAgLSBcbmV3Y29tbWFuZHtcVmNhbH17XG1hdGhjYWx7Vn19CiAgLSBcbmV3Y29tbWFuZHtcRWNhbH17XG1hdGhjYWx7RX19CiAgLSBcbmV3Y29tbWFuZHtcV2NhbH17XG1hdGhjYWx7V319Ci0tLQoKR28gYmFjayB0byB0aGUgW0NvbnRlbnRzXShhYm91dC5odG1sKSBwYWdlLgoKPGRpdiBzdHlsZT0iY29sb3I6ICMyYzNlNTA7IHRleHQtYWxpZ246IHJpZ2h0OyI+CioqKioqKioqICAKPHN0cm9uZz5QcmVzcyBTaG93IHRvIHJldmVhbCB0aGUgY29kZSBjaHVua3MuPC9zdHJvbmc+ICAKCioqKioqKioqCjwvZGl2PgoKCmBgYHtyLCBwdXJsID0gRkFMU0UsIGVjaG8gPSBGQUxTRX0KIyBDcmVhdGUgYSBjbGlwYm9hcmQgYnV0dG9uIG9uIHRoZSByZW5kZXJlZCBIVE1MIHBhZ2UKc291cmNlKGhlcmU6OmhlcmUoImNsaXBib2FyZC5SIikpOyBjbGlwYm9hcmQKYGBgCgoKYGBge3IsIHB1cmwgPSBGQUxTRSwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CiMgU2V0IHNlZWQgZm9yIHJlcHJvZHVjaWJpbGl0eQpzZXQuc2VlZCgxOTgyKSAKIyBTZXQgZ2xvYmFsIG9wdGlvbnMgZm9yIGFsbCBjb2RlIGNodW5rcwprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgIyBEaXNhYmxlIG1lc3NhZ2VzIHByaW50ZWQgYnkgUiBjb2RlIGNodW5rcwogIG1lc3NhZ2UgPSBGQUxTRSwgICAgCiAgIyBEaXNhYmxlIHdhcm5pbmdzIHByaW50ZWQgYnkgUiBjb2RlIGNodW5rcwogIHdhcm5pbmcgPSBGQUxTRSwgICAgCiAgIyBTaG93IFIgY29kZSB3aXRoaW4gY29kZSBjaHVua3MgaW4gb3V0cHV0CiAgZWNobyA9IFRSVUUsICAgICAgICAKICAjIEluY2x1ZGUgYm90aCBSIGNvZGUgYW5kIGl0cyByZXN1bHRzIGluIG91dHB1dAogIGluY2x1ZGUgPSBUUlVFLCAgICAgCiAgIyBFdmFsdWF0ZSBSIGNvZGUgY2h1bmtzCiAgZXZhbCA9IFRSVUUsICAgICAgIAogICMgRW5hYmxlIGNhY2hpbmcgb2YgUiBjb2RlIGNodW5rcyBmb3IgZmFzdGVyIHJlbmRlcmluZwogIGNhY2hlID0gRkFMU0UsICAgICAgCiAgIyBBbGlnbiBmaWd1cmVzIGluIHRoZSBjZW50ZXIgb2YgdGhlIG91dHB1dAogIGZpZy5hbGlnbiA9ICJjZW50ZXIiLAogICMgRW5hYmxlIHJldGluYSBkaXNwbGF5IGZvciBoaWdoLXJlc29sdXRpb24gZmlndXJlcwogIHJldGluYSA9IDIsCiAgIyBTaG93IGVycm9ycyBpbiB0aGUgb3V0cHV0IGluc3RlYWQgb2Ygc3RvcHBpbmcgcmVuZGVyaW5nCiAgZXJyb3IgPSBUUlVFLAogICMgRG8gbm90IGNvbGxhcHNlIGNvZGUgYW5kIG91dHB1dCBpbnRvIGEgc2luZ2xlIGJsb2NrCiAgY29sbGFwc2UgPSBGQUxTRQopCiMgU3RhcnQgdGhlIGZpZ3VyZSBjb3VudGVyCmZpZ19jb3VudCA8LSAwCiMgRGVmaW5lIHRoZSBjYXB0aW9uZXIgZnVuY3Rpb24KY2FwdGlvbmVyIDwtIGZ1bmN0aW9uKGNhcHRpb24pIHsKICBmaWdfY291bnQgPDwtIGZpZ19jb3VudCArIDEKICBwYXN0ZTAoIkZpZ3VyZSAiLCBmaWdfY291bnQsICI6ICIsIGNhcHRpb24pCn0KYGBgCgoKCmBgYHtyfQojIHJlbW90ZXM6Omluc3RhbGxfZ2l0aHViKCJkYXZpZGJvbGluL3JzcGRlIiwgcmVmID0gImRldmVsIikKIyByZW1vdGVzOjppbnN0YWxsX2dpdGh1YigiZGF2aWRib2xpbi9tZXRyaWNncmFwaCIsIHJlZiA9ICJkZXZlbCIpCmxpYnJhcnkoclNQREUpCmxpYnJhcnkoTWV0cmljR3JhcGgpCmxpYnJhcnkoZ3JhdGVmdWwpCgpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocmVzaGFwZTIpCmxpYnJhcnkocGxvdGx5KQpgYGAKCgojIE9wdGltYWwgY29udHJvbCBvZiBmcmFjdGlvbmFsIGRpZmZ1c2lvbiBlcXVhdGlvbnMgb24gbWV0cmljIGdyYXBocwoKIyMgUHJvYmxlbSBzdGF0ZW1lbnQgeyNvcHRpbWFsX2NvbnRyb2xfcHJvYmxlbX0KCkxldCAkXEdhbW1hID0gKFxtYXRoY2Fse1Z9LFxtYXRoY2Fse0V9KSQgYmUgYSBtZXRyaWMgZ3JhcGguIExldCAkdV9kOiBcR2FtbWEgXHRpbWVzKDAsIFQpIFxyaWdodGFycm93IFxtYXRoYmJ7Un0kIGJlIHRoZSBkZXNpcmVkIHN0YXRlIGFuZCAgJFxtdT4wJCBhIHJlZ3VsYXJpemF0aW9uIHBhcmFtZXRlci4gV2UgZGVmaW5lIHRoZSBjb3N0IGZ1bmN0aW9uYWwKClxiZWdpbntlcXVhdGlvbn0KXGxhYmVse2VxOmNvc3RmdW59Clx0YWd7MX0KICAgIEoodSwgeik9XGZyYWN7MX17Mn0gXGludF8wXlRcbGVmdChcbGVmdFx8dS11X2RccmlnaHRcfF97TF8yKFxHYW1tYSl9XjIrXG11XHx6XHxfe0xfMihcR2FtbWEpfV4yXHJpZ2h0KSBkdApcZW5ke2VxdWF0aW9ufQoKCkxldCAkZjpcR2FtbWFcdGltZXMgKDAsVClccmlnaHRhcnJvd1xhciQgYW5kICR1XzA6IFxHYW1tYSBccmlnaHRhcnJvdyBcbWF0aGJie1J9JCBiZSBmaXhlZCBmdW5jdGlvbnMuIFdlIHdpbGwgY2FsbCB0aGVtIHJpZ2h0LWhhbmQgc2lkZSBhbmQgaW5pdGlhbCBkYXR1bSwgcmVzcGVjdGl2ZWx5LiBMZXQgJFxhbHBoYVxpbigwLDJdJCBhbmQgJHo6IFxHYW1tYSBcdGltZXMoMCwgVCkgXHJpZ2h0YXJyb3cgXG1hdGhiYntSfSQgZGVub3RlIHRoZSBjb250cm9sIHZhcmlhYmxlLiBXZSBzaGFsbCBiZSBjb25jZXJuZWQgd2l0aCB0aGUgZm9sbG93aW5nIFBERS1jb25zdHJhaW5lZCBvcHRpbWl6YXRpb24gcHJvYmxlbTogRmluZAoKXGJlZ2lue2VxdWF0aW9ufQpcbGFiZWx7ZXE6bWluX3Byb30KXHRhZ3syfQogICAgXG1pblw7IEoodSwgeikKXGVuZHtlcXVhdGlvbn0Kc3ViamVjdCB0byB0aGUgZnJhY3Rpb25hbCBkaWZmdXNpb24gZXF1YXRpb24KXGJlZ2lue2VxdWF0aW9ufQpcbGFiZWx7ZXE6bWFpbmVxfQpcdGFnezN9ClxsZWZ0XHsKXGJlZ2lue2FsaWduZWR9CiAgICBccGFydGlhbF90IHUocyx0KSArIChca2FwcGFeMiAtIFxEZWx0YV9cR2FtbWEpXntcYWxwaGEvMn0gdShzLHQpICY9IGYocyx0KSt6KHMsdCksICYmIFxxdWFkIChzLHQpIFxpbiBcR2FtbWEgXHRpbWVzICgwLCBUKSwgXFwKICAgIHUocywwKSAmPSB1XzAocyksICYmIFxxdWFkIHMgXGluIFxHYW1tYSwKXGVuZHthbGlnbmVkfQpccmlnaHQuClxlbmR7ZXF1YXRpb259CndpdGggJHUoXGNkb3QsdCkkIHNhdGlzZnlpbmcgdGhlIEtpcmNoaG9mZiB2ZXJ0ZXggY29uZGl0aW9ucwpcYmVnaW57ZXF1YXRpb259ClxsYWJlbHtlcTpLY29uZH0KXHRhZ3s0fQogICBcbWF0aGNhbHtLfSA9ICBcbGVmdFx7XHBoaVxpbiBDKFxHYW1tYSlcO1xtaWRkbGV8XDsgXGZvcmFsbCB2XGluIFxtYXRoY2Fse1Z9Olw7IFxzdW1fe2VcaW5cbWF0aGNhbHtFfV92fVxwYXJ0aWFsX2UgXHBoaSh2KT0wIFxyaWdodFx9ClxlbmR7ZXF1YXRpb259CmFuZCB0aGUgY29udHJvbCBjb25zdHJhaW50cyAKXGJlZ2lue2FsaWdufQpcbGFiZWx7Y29udHJvbF9jb25zdHJhaW50c30KXHRhZ3s1fQogICAgYShzLHQpXGxlcSB6KHMsdClcbGVxIGIocyx0KVw7XHRleHR7YS5lLn0gKHMsdClcaW5cR2FtbWEgXHRpbWVzKDAsIFQpLgpcZW5ke2FsaWdufQoKCiMjIE9wdGltYWwgc29sdXRpb24gCgpUaGUgb3B0aW1hbCB2YXJpYWJsZXMgJChcYmFye3V9LCBcYmFye3B9LCBcYmFye3p9KSQgc2F0aXNmeQoKXGJlZ2lue2VxdWF0aW9ufQpcbGFiZWx7ZXE6bWFpbmVxb3B0aW1hbH0KXHRhZ3s2fQpcbGVmdFx7ClxiZWdpbnthbGlnbmVkfQogICAgXHBhcnRpYWxfdCBcYmFye3V9KHMsdCkgKyAoXGthcHBhXjIgLSBcRGVsdGFfXEdhbW1hKV57XGFscGhhLzJ9IFxiYXJ7dX0ocyx0KSAmPSBmKHMsdCkrXGJhcnt6fShzLHQpLCAmJiBccXVhZCAocyx0KSBcaW4gXEdhbW1hIFx0aW1lcyAoMCwgVCksIFxcCiAgICBcYmFye3V9KHMsMCkgJj0gdV8wKHMpLCAmJiBccXVhZCBzIFxpbiBcR2FtbWEsClxlbmR7YWxpZ25lZH0KXHJpZ2h0LgpcZW5ke2VxdWF0aW9ufQphbmQKXGJlZ2lue2VxdWF0aW9ufQpcbGFiZWx7ZXE6YWRqb2ludGVxfQpcdGFnezd9ClxsZWZ0XHsKXGJlZ2lue2FsaWduZWR9CiAgICAtXHBhcnRpYWxfdCBcYmFye3B9KHMsdCkgKyAoXGthcHBhXjIgLSBcRGVsdGFfXEdhbW1hKV57XGFscGhhLzJ9IFxiYXJ7cH0ocyx0KSAmPSBcYmFye3V9KHMsdCktdV9kKHMsdCksICYmIFxxdWFkIChzLHQpIFxpbiBcR2FtbWEgXHRpbWVzICgwLCBUKSwgXFwKICAgIFxiYXJ7cH0ocyxUKSAmPSAwLCAmJiBccXVhZCBzIFxpbiBcR2FtbWEsClxlbmR7YWxpZ25lZH0KXHJpZ2h0LgpcZW5ke2VxdWF0aW9ufQp3aXRoIApcYmVnaW57YWxpZ259ClxsYWJlbHt6en0KXHRhZ3s4fQogICAgICAgIFxiYXJ7en0ocyx0KSA9IFxtYXhcbGVmdFx7YShzLHQpLFxtaW5cbGVmdFx7YihzLHQpLC1cZGZyYWN7MX17XG11fVxiYXJ7cH0ocyx0KVxyaWdodFx9XHJpZ2h0XH0uClxlbmR7YWxpZ259CgojIyBOdW1lcmljYWwgU2NoZW1lIHsjbnVtX3NjaGVtZV9vcHRpbV9jb250cm9sfQoKIyMjIERpc2NyZXRpemF0aW9uIGJ5IHRpbWUgcmV2ZXJzYWwgc3RyYXRlZ3kKCkJ5IGNvbnNpZGVyaW5nIHRoZSBjaGFuZ2Ugb2YgdmFyaWFibGUgJHReKiA9IFQtdCQgYW5kIGRlZmluaW5nICRcYmFye3F9KHMsdF4qKTogPSBcYmFye3B9KHMsVC10XiopJCwgdGhlIGZyYWN0aW9uYWwgYWRqb2ludCBwcm9ibGVtIFxlcXJlZntlcTphZGpvaW50ZXF9IGJlY29tZXMgYSBmb3J3YXJkLWluLXRpbWUgcHJvYmxlbSB3aGVyZSB0aGUgdHJhbnNmb3JtZWQgYWRqb2ludCBzdGF0ZSAkXGJhcntxfSQgc2F0aXNmaWVzIHRoZSBLaXJjaGhvZmYgdmVydGV4IGNvbmRpdGlvbnMgXGVxcmVme2VxOktjb25kfSBhbmQgc29sdmVzCiAgICBcYmVnaW57ZXF1YXRpb259CiAgICBcbGFiZWx7dHJhbnNmb3JtZWRfYWRqb2ludF9zdGF0ZX0KICAgIFx0YWd7OX0KICAgIFxsZWZ0XHsKICAgIFxiZWdpbnthbGlnbmVkfQogICAgICAgIFxwYXJ0aWFsX3t0Xip9IFxiYXJ7cX0ocyx0XiopICsgKFxrYXBwYV4yIC0gXERlbHRhX1xHYW1tYSlee1xhbHBoYS8yfSBcYmFye3F9KHMsdF4qKSAmPSBcYmFye3Z9KHMsdF4qKS12X2Qocyx0XiopLCAmJiBccXVhZCAocyx0XiopIFxpbiBcR2FtbWEgXHRpbWVzICgwLCBUKSwgXFwKICAgICAgICBcYmFye3F9KHMsMCkgJj0gMCwgJiYgXHF1YWQgcyBcaW4gXEdhbW1hLAogICAgXGVuZHthbGlnbmVkfQogICAgXHJpZ2h0LgogICAgXGVuZHtlcXVhdGlvbn0KICAgIHNpbmNlICRccGFydGlhbF90XGJhcntwfShzLHQpID0gLVxwYXJ0aWFsX3t0Xip9XGJhcntxfShzLHReKikkIGFuZCAkXGJhcntxfShzLCAwKT0gXGJhcntwfShzLFQpPTAkLiBIZXJlLCAkXGJhcnt2fShzLHReKikgPSBcYmFye3V9KHMsVC10XiopJCBhbmQgJHZfZChzLHReKikgPSB1X2QocyxULXReKikkLgogICAgCiAgICAKR2l2ZW4gJFxiYXJ7dX0kIGFuZCAkdV9kJCwgd2UgY2FuIHRpbWUtcmV2ZXJzZSB0aGVtIHRvIG9idGFpbiAkXGJhcnt2fSQgYW5kICR2X2QkIGFuZCB0aGVuIHVzZSB0aGUgc2FtZSBudW1lcmljYWwgc2NoZW1lIHdlIHVzZSBmb3IgdGhlIGZvcndhcmQgcHJvYmxlbSBcZXFyZWZ7ZXE6bWFpbmVxb3B0aW1hbH0gdG8gc29sdmUgdGhlIGFkam9pbnQgcHJvYmxlbSBcZXFyZWZ7dHJhbnNmb3JtZWRfYWRqb2ludF9zdGF0ZX0uIFRoZSBjb250cm9sIHZhcmlhYmxlICRcYmFye3p9JCBpcyB0aGVuIGNvbXB1dGVkIHVzaW5nIFxlcXJlZnt6en0uCgoKClRoZSBudW1lcmljYWwgc2NoZW1lIGZvciBcZXFyZWZ7ZXE6bWFpbmVxb3B0aW1hbH0gYW5kIFxlcXJlZnt0cmFuc2Zvcm1lZF9hZGpvaW50X3N0YXRlfSBhcmUgZ2l2ZW4gYnkgKHNlZSB0aGUgW0Z1bmN0aW9uYWxpdHldKGZ1bmN0aW9uYWxpdHkuaHRtbCNudW1fc2NoZW1lKSBwYWdlKQoKXGJlZ2lue2FsaWdufQpcdGFnezEwfQogICAgXGxhYmVse251bWVyaWNhbHNjaGVtZTF9CiAgICBcYmVnaW57Y2FzZXN9CiAgICAmXG1hdGhiZntcYmFye1V9fV97aysxfSAgPSBcbWF0aGJme1J9XG1hdGhiZntDfVxtYXRoYmZ7XGJhcntVfX1faytcdGF1IFxtYXRoYmZ7Un0oXG1hdGhiZntGfV97aysxfStcbWF0aGJme0N9XG1hdGhiZntcYmFye1p9fV97aysxfSksXHF1YWQgayA9IDAsXGRvdHMsIE4tMSxcXAogICAgJlxtYXRoYmZ7XGJhcntVfX1fezB9ICA9IFt1XzAoc18xKSwgXGRvdHMsIHVfMChzX3tOX2h9KV1eXHRvcCwKICAgIFxlbmR7Y2FzZXN9ClxlbmR7YWxpZ259CmFuZApcYmVnaW57YWxpZ259Clx0YWd7MTF9CiAgICBcbGFiZWx7dGhlbnVtZXJpY2Fsc2NoZW1lMn0KICAgIFxiZWdpbntjYXNlc30KICAgICZcbWF0aGJme1xiYXJ7UX19X3trKzF9ICA9IFxtYXRoYmZ7Un1cbWF0aGJme0N9XG1hdGhiZntcYmFye1F9fV9rK1x0YXVcbWF0aGJme1J9ICgoXG1hdGhiZntDfVxtYXRoYmZ7XGJhcntVfX1cbWF0aGJme0p9X3tOKzF9KV97aysxfS0oXG1hdGhiZntEfVxtYXRoYmZ7Sn1fe04rMX0pX3trKzF9KSxccXVhZCBrID0gMCxcZG90cywgTi0xLFxcCiAgICAmXG1hdGhiZntcYmFye1F9fV97MH0gID0gXG1hdGhiZnswfSwKICAgIFxlbmR7Y2FzZXN9ClxlbmR7YWxpZ259CndoZXJlICRcbWF0aGJme1J9ID0gXHN1bV97az0xfV57bSsxfSBhX2tcbGVmdChcbWF0aGJme0x9L1xrYXBwYV4yLXBfa1xtYXRoYmZ7Q31ccmlnaHQpXnstMX0kLiBPYnNlcnZlIHRoYXQgXGVxcmVme251bWVyaWNhbHNjaGVtZTF9LVxlcXJlZnt0aGVudW1lcmljYWxzY2hlbWUyfSBpcyBhIGNvdXBsZWQgcHJvYmxlbS4KCkhlcmUKCi0gJFxtYXRoYmZ7XGJhcntVfX0kIGhhcyBlbnRyaWVzICRcbWF0aGJme1V9X3tqLGt9ICA9IFxiYXJ7dX0oc19qLHRfaykkLAotICRcbWF0aGJme0Z9JCBoYXMgZW50cmllcyAkXG1hdGhiZntGfV97aixrfSA9KGZee2t9LFxwc2leal9oKV97TF8yKFxHYW1tYSl9JCwKLSAkXG1hdGhiZntcYmFye1p9fSQgaGFzIGVudHJpZXMgJFxtYXRoYmZ7XGJhcntafX1fe2osa30gPSBcYmFye3p9KHNfaix0X2spJCwKLSAkXG1hdGhiZntEfSQgaGFzIGVudHJpZXMgJFxtYXRoYmZ7RH1fe2osa30gPSh1X2Ree2t9LFxwc2leal9oKV97TF8yKFxHYW1tYSl9JCwKLSAkXG1hdGhiZntcYmFye1B9fSA9IFxtYXRoYmZ7XGJhcntRfX1cbWF0aGJme0p9X3tOKzF9JCBhbmQgaGFzIGVudHJpZXMgJFxtYXRoYmZ7XGJhcntQfX1fe2osa30gPSBcYmFye3B9KHNfaix0X2spJC4KCgpJZiB3ZSBjaGFuZ2UgXGVxcmVme3RoZW51bWVyaWNhbHNjaGVtZTJ9IHRvICRcbWF0aGJme1xiYXJ7UH19JCwgdGhlbiB3ZSBvYnRhaW4gClxiZWdpbnthbGlnbn0KXHRhZ3sxMn0KICAgIFxsYWJlbHt0aGVudW1lcmljYWxzY2hlbWUzfQogICAgXGJlZ2lue2Nhc2VzfQogICAgJlxtYXRoYmZ7XGJhcntQfX1fe2t9ICA9IFxtYXRoYmZ7Un1cbWF0aGJme0N9XG1hdGhiZntcYmFye1B9fV97aysxfStcdGF1IFxtYXRoYmZ7Un0oXG1hdGhiZntDfVxtYXRoYmZ7XGJhcntVfX1fe2t9LVxtYXRoYmZ7RH1fe2t9KSxccXVhZCBrID0gTi0xLFxkb3RzLCAwLFxcCiAgICAmXG1hdGhiZntcYmFye1B9fV97Tn0gID0gXG1hdGhiZnswfS4KICAgIFxlbmR7Y2FzZXN9ClxlbmR7YWxpZ259CgojIyMgRGlzY3JldGl6YXRpb24gYnkgZGlyZWN0bHkgc29sdmluZyB0aGUgYWRqb2ludCBwcm9ibGVtCgpUaGUgZGlzY3JldGUgdmVyc2lvbiAkXGJhcntQfV9oXlx0YXVcc3Vic2V0IFZfaCQgb2YgdGhlIGFkam9pbnQgb3B0aW1hbCBzdGF0ZSAkXGJhcntwfSQgaW4gcHJvYmxlbSBcZXFyZWZ7ZXE6YWRqb2ludGVxfSBzb2x2ZXMgCgpcYmVnaW57ZXF1YXRpb259ClxsYWJlbHtkaXNjcmV0ZV9hZGpvaW50fQogICAgXGxlZnRcewpcYmVnaW57YWxpZ25lZH0KICAgIFxsYW5nbGVcYmFye1xkZWx0YX0gXGJhcntQfV9oXntrfSxccGhpXHJhbmdsZSArIFxtYXRoZnJha3thfShcYmFye1B9X2hee2t9LFxwaGkpICY9IFxsYW5nbGUgXGJhcntVfV9oXntrKzF9LXVfZF57aysxfSxccGhpXHJhbmdsZSwgXHF1YWRcZm9yYWxsXHBoaVxpbiBWX2gsXHF1YWQgaz1OLTEsXGRvdHMsIDAsIFxcCiAgICBcYmFye1B9Xk5faCAmPSAwClxlbmR7YWxpZ25lZH0KXHJpZ2h0LgpcZW5ke2VxdWF0aW9ufQpUaGUgYWJvdmUgZXhwcmVzc2lvbiBjYW4gYmUgZXF1aXZhbGVudGx5IHdyaXR0ZW4gYXMKXGJlZ2lue2VxdWF0aW9ufQogICAgXGxlZnRcewpcYmVnaW57YWxpZ25lZH0KICAgIFxsYW5nbGVcZGZyYWN7XGJhcntQfV9oXntrfSAtIFxiYXJ7UH1faF57aysxfX17XHRhdX0sXHBoaVxyYW5nbGUgKyBcbWF0aGZyYWt7YX0oCiAgICAgICAgXGJhcntQfV9oXntrfSxccGhpKSAmID0gXGxhbmdsZSBcYmFye1V9X2hee2srMX0gLSB1X2Ree2srMX0sXHBoaVxyYW5nbGUsIFxxdWFkXGZvcmFsbFxwaGlcaW4gVl9oLFxxdWFkIGs9Ti0xLFxkb3RzLCAwLCBcXAogICAgXGJhcntQfV5OX2ggJj0gMApcZW5ke2FsaWduZWR9ClxyaWdodC4KXGVuZHtlcXVhdGlvbn0Kb3IKXGJlZ2lue2VxdWF0aW9ufQpcbGFiZWx7ZGlzb3B0Y29uc30KXHRhZ3sxM30KICAgIFxsZWZ0XHsKXGJlZ2lue2FsaWduZWR9CiAgICBcbGFuZ2xlIFxiYXJ7UH1faF57a30sXHBoaVxyYW5nbGUgKyBcdGF1XG1hdGhmcmFre2F9KAogICAgICAgIFxiYXJ7UH1faF57a30sXHBoaSkgJiA9IFxsYW5nbGUgXGJhcntQfV9oXntrKzF9LFxwaGlccmFuZ2xlICsgXHRhdVxsYW5nbGUgXGJhcntVfV9oXntrKzF9IC0gdV9kXntrKzF9LFxwaGlccmFuZ2xlLCBccXVhZFxmb3JhbGxccGhpXGluIFZfaCxccXVhZCBrPU4tMSxcZG90cywgMCwgXFwKICAgIFxiYXJ7UH1eTl9oICY9IDAKXGVuZHthbGlnbmVkfQpccmlnaHQuClxlbmR7ZXF1YXRpb259CgpBdCBlYWNoIHRpbWUgc3RlcCAkdF9rJCwgdGhlIGZpbml0ZSBlbGVtZW50IHNvbHV0aW9uICRcYmFye1B9X2hea1xpbiBWX2gkIHRvIFxlcXJlZntkaXNvcHRjb25zfSBjYW4gYmUgZXhwcmVzc2VkIGFzIGEgbGluZWFyIGNvbWJpbmF0aW9uIG9mIHRoZSBiYXNpcyBmdW5jdGlvbnMgICRce1xwc2leaV9oXH1fe2k9MX1ee05faH0kIGludHJvZHVjZWQgaW4gdGhlIFtQcmVsaW1pbmFyaWVzXShwcmVsaW1pbmFyaWVzLmh0bWwjZmVtLWJhc2lzKSBwYWdlLCBuYW1lbHksIApcYmVnaW57YWxpZ259ClxsYWJlbHtudW1fc29sMn0KXHRhZ3sxNH0KICAgIFxiYXJ7UH1faF5rKHMpID0gIFxzdW1fe2k9MX1ee05faH1wX2lea1xwc2leaV9oKHMpLCBcO3NcaW5cR2FtbWEuClxlbmR7YWxpZ259ClJlcGxhY2luZyBcZXFyZWZ7bnVtX3NvbDJ9IGludG8gXGVxcmVme2Rpc29wdGNvbnN9IHlpZWxkcyB0aGUgZm9sbG93aW5nIHN5c3RlbQpcYmVnaW57YWxpZ24qfQogICAgXHN1bV97aj0xfV57Tl9ofXBfal57a31bKFxwc2lfaF5qLFxwc2lfaF5pKV97TF8yKFxHYW1tYSl9KyBcdGF1XG1hdGhmcmFre2F9KFxwc2lfaF5qLFxwc2lfaF5pKV0gPSBcc3VtX3tqPTF9XntOX2h9cF9qXntrKzF9KFxwc2lfaF5qLFxwc2lfaF5pKV97TF8yKFxHYW1tYSl9K1x0YXUoXGJhcntVfV9oXntrKzF9IC0gdV9kXntrKzF9LFxwc2lfaF5pKV97TF8yKFxHYW1tYSl9LFxxdWFkIGkgPSAxLFxkb3RzLCBOX2guClxlbmR7YWxpZ24qfQpJbiBtYXRyaXggbm90YXRpb24sClxiZWdpbnthbGlnbn0KXGxhYmVse2RpZmZfZXFfZGlzY3JldGVfYWRqb2ludH0KICAgIChcbWF0aGJme0N9K1x0YXUgXG1hdGhiZntMfV57XGFscGhhLzJ9KVxtYXRoYmZ7XGJhcntQfX1fe2t9ID0gXG1hdGhiZntDfVxtYXRoYmZ7XGJhcntQfX1fe2srMX0rXHRhdSggXGJvbGRzeW1ib2x7XGJhcntcbWF0aGZyYWt7VX19fV97aysxfSAtIFxtYXRoYmZ7RH1fe2srMX0pLApcZW5ke2FsaWdufQpvciBieSBpbnRyb2R1Y2luZyB0aGUgc2NhbGluZyBwYXJhbWV0ZXIgJFxrYXBwYV4yPjAkLApcYmVnaW57YWxpZ259CiAgICAoXG1hdGhiZntDfStcdGF1IChca2FwcGFeMilee1xhbHBoYS8yfShcbWF0aGJme0x9L1xrYXBwYV4yKV57XGFscGhhLzJ9KVxtYXRoYmZ7XGJhcntQfX1fe2t9ID0gXG1hdGhiZntDfVxtYXRoYmZ7XGJhcntQfX1fe2srMX0rXHRhdSAoIFxib2xkc3ltYm9se1xiYXJ7XG1hdGhmcmFre1V9fX1fe2srMX0gLSBcbWF0aGJme0R9X3trKzF9KSwKXGVuZHthbGlnbn0Kd2hlcmUgJFxtYXRoYmZ7Q30kIGhhcyBlbnRyaWVzICRcbWF0aGJme0N9X3tpLGp9ID0gKFxwc2lfaF5qLFxwc2lfaF5pKV97TF8yKFxHYW1tYSl9JCwgJFxtYXRoYmZ7TH1ee1xhbHBoYS8yfSQgaGFzIGVudHJpZXMgJFxtYXRoZnJha3thfShccHNpX2heaixccHNpX2heaSkkLCAkXG1hdGhiZntcYmFye1B9fV5rJCBoYXMgY29tcG9uZW50cyAkcF9qXmskLCBhbmQgJFxib2xkc3ltYm9se1xiYXJ7XG1hdGhmcmFre1V9fX1eayQgaGFzIGNvbXBvbmVudHMgJCggXGJhcnt1fV57a30sXHBzaV9oXmkpX3tMXzIoXEdhbW1hKX0kLiBBcHBseWluZyAkKFxtYXRoYmZ7TH0vXGthcHBhXjIpXnstXGFscGhhLzJ9JCB0byBib3RoIHNpZGVzIHlpZWxkcwpcYmVnaW57ZXF1YXRpb259CigoXG1hdGhiZntMfS9ca2FwcGFeMileey1cYWxwaGEvMn1cbWF0aGJme0N9K1x0YXUgKFxrYXBwYV4yKV57XGFscGhhLzJ9XG1hdGhiZntJfSlcbWF0aGJme1xiYXJ7UH19X3trfSA9IChcbWF0aGJme0x9L1xrYXBwYV4yKV57LVxhbHBoYS8yfShcbWF0aGJme0N9XG1hdGhiZntcYmFye1B9fV97aysxfStcdGF1ICggXGJvbGRzeW1ib2x7XGJhcntcbWF0aGZyYWt7VX19fV97aysxfSAtIFxtYXRoYmZ7RH1fe2srMX0pKS4KXGVuZHtlcXVhdGlvbn0KRm9sbG93aW5nIEByU1BERTIwMjAsIHdlIGFwcHJveGltYXRlICQoXG1hdGhiZntMfS9ca2FwcGFeMileey1cYWxwaGEvMn0kIGJ5ICRcbWF0aGJme1B9X1xlbGxeey1cdG9wfVxtYXRoYmZ7UH1fcl5cdG9wJCB0byBhcnJpdmUgYXQKXGJlZ2lue2VxdWF0aW9ufQpcbGFiZWx7ZXE6c2NoZW1lMmFkam9pbnR9Clx0YWd7MTV9CihcbWF0aGJme1B9X1xlbGxeey1cdG9wfVxtYXRoYmZ7UH1fcl5cdG9wIFxtYXRoYmZ7Q30rXHRhdShca2FwcGFeMilee1xhbHBoYS8yfSBcbWF0aGJme0l9KVxtYXRoYmZ7XGJhcntQfX1fe2t9ID0gXG1hdGhiZntQfV9cZWxsXnstXHRvcH1cbWF0aGJme1B9X3JeXHRvcChcbWF0aGJme0N9XG1hdGhiZntcYmFye1B9fV97aysxfStcdGF1ICggXGJvbGRzeW1ib2x7XGJhcntcbWF0aGZyYWt7VX19fV97aysxfSAtIFxtYXRoYmZ7RH1fe2srMX0pKS4KXGVuZHtlcXVhdGlvbn0Kd2hlcmUKXGJlZ2lue2VxdWF0aW9ufQpcbGFiZWx7ZXE6UExQUmJvbGluYWRqb2ludH0KXHRhZ3sxNn0KXG1hdGhiZntQfV9yID0gXHByb2Rfe2k9MX1ebSBcbGVmdChcbWF0aGJme0l9LXJfezFpfVxkZnJhY3tcbWF0aGJme0N9XnstMX1cbWF0aGJme0x9fXtca2FwcGFeMn1ccmlnaHQpXHF1YWRcdGV4dHthbmR9XHF1YWQgXG1hdGhiZntQfV9cZWxsID0gXGRmcmFje1xrYXBwYV57MlxiZXRhfX17XHRleHR0dHtmYWN0b3J9fVxtYXRoYmZ7Q31ccHJvZF97aj0xfV57bSsxfSBcbGVmdChcbWF0aGJme0l9LXJfezJqfVxkZnJhY3tcbWF0aGJme0N9XnstMX1cbWF0aGJme0x9fXtca2FwcGFeMn1ccmlnaHQpLApcZW5ke2VxdWF0aW9ufQphbmQgJFx0ZXh0dHR7ZmFjdG9yfSA9IFxkZnJhY3tjX219e2Jfe20rMX19JCwgYW5kCiRce3JfezFpfVx9X3tpPTF9Xm0kIGFuZCAkXHtyX3syan1cfV97aj0xfV57bSsxfSQgYXJlIHRoZSByb290cyBvZiAkcV8xKHgpID1cc3VtX3tpPTB9Xm1jX2l4XntpfSQgYW5kICAkcV8yKHgpPVxzdW1fe2o9MH1ee20rMX1iX2p4XntqfSQsIHJlc3BlY3RpdmVseS4gVGhlIGNvZWZmaWNpZW50cyAgJFx7Y19pXH1fe2k9MH1ebSQgYW5kICAkXHtiX2pcfV97aj0wfV57bSsxfSQgYXJlIGRldGVybWluZWQgYXMgdGhlIGJlc3QgcmF0aW9uYWwgYXBwcm94aW1hdGlvbiAkcV8xL3FfMiQgb2YgdGhlIGZ1bmN0aW9uICR4XntcYWxwaGEvMi0xfSQgb3ZlciB0aGUgaW50ZXJ2YWwgJEpfaDogPSBbXGthcHBhXnsyfVxsYW1iZGFfe05faCxofV57LTF9LCBca2FwcGFeezJ9XGxhbWJkYV97MSxofV57LTF9XSQsIHdoZXJlICRcbGFtYmRhX3sxLGh9LCBcbGFtYmRhX3tOX2gsaH0+MCQgYXJlIHRoZSBzbWFsbGVzdCBhbmQgdGhlIGxhcmdlc3QgZWlnZW52YWx1ZSBvZiAkTF9oJCwgcmVzcGVjdGl2ZWx5LgoKCkZvciB0aGUgc2FrZSBvZiBjbGFyaXR5LCB3ZSBub3RlIHRoYXQgdGhlIG51bWVyaWNhbCBpbXBsZW1lbnRhdGlvbiBvZiBAclNQREUyMDIwIGFjdHVhbGx5IGRlZmluZXMgJFxtYXRoYmZ7UH1fciQgYW5kICRcbWF0aGJme1B9X1xlbGwkIGFzClxiZWdpbntlcXVhdGlvbn0KXGxhYmVse2VxOlBMUFJib2xpbn0KXHRhZ3sxN30KXG1hdGhiZntQfV9yID0gXHByb2Rfe2k9MX1ebSBcbGVmdChcbWF0aGJme0l9LXJfezFpfVxkZnJhY3tcbWF0aGJme0N9XnstMX1cbWF0aGJme0x9fXtca2FwcGFeMn1ccmlnaHQpXHF1YWRcdGV4dHthbmR9XHF1YWQgXG1hdGhiZntQfV9cZWxsID0gXGRmcmFje1xrYXBwYV57MlxiZXRhfX17XHRleHR0dHtmYWN0b3J9fVxtYXRoYmZ7Q31ccHJvZF97aj0xfV57bSsxfSBcbGVmdChcbWF0aGJme0l9LXJfezJqfVxkZnJhY3tcbWF0aGJme0N9XnstMX1cbWF0aGJme0x9fXtca2FwcGFeMn1ccmlnaHQpLApcZW5ke2VxdWF0aW9ufQp3aGVyZSAkXGJldGEgPSBcYWxwaGEvMiQgYW5kIHRoZSBzY2FsaW5nIGZhY3RvciAkKFxrYXBwYV4yKV57XGFscGhhLzJ9JCBvciAkXGthcHBhXnsyXGJldGF9JCBpcyBhbHJlYWR5IGluY29ycG9yYXRlZCBpbiAkXG1hdGhiZntQfV9cZWxsJCwgYSBjb252ZW50aW9uIHdlIGFkb3B0IGluIHRoZSBmb2xsb3dpbmcuIFdpdGggdGhpcyB1bmRlciBjb25zaWRlcmF0aW9uLCB3ZSBjYW4gcmV3cml0ZSBcZXFyZWZ7ZXE6c2NoZW1lMmFkam9pbnR9IGFzClxiZWdpbntlcXVhdGlvbn0KXHRhZ3sxOH0KKFxtYXRoYmZ7UH1fcl5cdG9wIFxtYXRoYmZ7Q30rXHRhdSBcbWF0aGJme1B9X1xlbGxeXHRvcClcbWF0aGJme1xiYXJ7UH19X3trfSA9IFxtYXRoYmZ7UH1fcl5cdG9wKFxtYXRoYmZ7Q31cbWF0aGJme1xiYXJ7UH19X3trKzF9K1x0YXUgKCBcYm9sZHN5bWJvbHtcYmFye1xtYXRoZnJha3tVfX19X3trKzF9IC0gXG1hdGhiZntEfV97aysxfSkpLApcbGFiZWx7ZXE6c2NoZW1lYWRqb2ludH0KXGVuZHtlcXVhdGlvbn0Kd2hlcmUgIApcYmVnaW57ZXF1YXRpb259ClxtYXRoYmZ7UH1fcl5cdG9wID0gXHByb2Rfe2k9MX1ebSBcbGVmdChcbWF0aGJme0l9LXJfezFpfVxkZnJhY3tcbWF0aGJme0x9XG1hdGhiZntDfV57LTF9fXtca2FwcGFeMn1ccmlnaHQpXHF1YWRcdGV4dHthbmR9XHF1YWQgXG1hdGhiZntQfV9cZWxsXlx0b3AgPSBcZGZyYWN7XGthcHBhXnsyXGJldGF9fXtcdGV4dHR0e2ZhY3Rvcn19XHByb2Rfe2o9MX1ee20rMX0gXGxlZnQoXG1hdGhiZntJfS1yX3syan1cZGZyYWN7XG1hdGhiZntMfVxtYXRoYmZ7Q31eey0xfX17XGthcHBhXjJ9XHJpZ2h0KVxjZG90IFxtYXRoYmZ7Q30KXGVuZHtlcXVhdGlvbn0Kc2luY2UgJFxtYXRoYmZ7TH0kIGFuZCAkXG1hdGhiZntDfV57LTF9JCBhcmUgc3ltbWV0cmljIGFuZCB0aGUgZmFjdG9ycyBpbiB0aGUgcHJvZHVjdCBjb21tdXRlLiBSZXBsYWNpbmcgdGhlc2UgdHdvIGludG8gXGVxcmVme2VxOnNjaGVtZWFkam9pbnR9IHlpZWxkcwpcYmVnaW57ZXF1YXRpb259ClxsZWZ0KFxwcm9kX3tpPTF9Xm0gXGxlZnQoXG1hdGhiZntJfS1yX3sxaX1cZGZyYWN7XG1hdGhiZntMfVxtYXRoYmZ7Q31eey0xfX17XGthcHBhXjJ9XHJpZ2h0KStcZGZyYWN7XHRhdSBca2FwcGFeezJcYmV0YX19e1x0ZXh0dHR7ZmFjdG9yfX1ccHJvZF97aj0xfV57bSsxfSBcbGVmdChcbWF0aGJme0l9LXJfezJqfVxkZnJhY3tcbWF0aGJme0x9XG1hdGhiZntDfV57LTF9fXtca2FwcGFeMn1ccmlnaHQpXHJpZ2h0KVxtYXRoYmZ7Q31cbWF0aGJme1xiYXJ7UH19X3trfSA9IFxwcm9kX3tpPTF9Xm0gXGxlZnQoXG1hdGhiZntJfS1yX3sxaX1cZGZyYWN7XG1hdGhiZntMfVxtYXRoYmZ7Q31eey0xfX17XGthcHBhXjJ9XHJpZ2h0KVxjZG90IChcbWF0aGJme0N9XG1hdGhiZntcYmFye1B9fV97aysxfStcdGF1ICggXGJvbGRzeW1ib2x7XGJhcntcbWF0aGZyYWt7VX19fV97aysxfSAtIFxtYXRoYmZ7RH1fe2srMX0pKSwKXGVuZHtlcXVhdGlvbn0KdGhhdCBpcywKXGJlZ2lue2VxdWF0aW9ufQpcbGFiZWx7ZXE6ZmluYWxfc2NoZW1lYWRqb2ludH0KXHRhZ3sxOX0KXG1hdGhiZntcYmFye1B9fV97a30gPSBcbWF0aGJme0N9XnstMX1cbGVmdChccHJvZF97aT0xfV5tIFxsZWZ0KFxtYXRoYmZ7SX0tcl97MWl9XGRmcmFje1xtYXRoYmZ7TH1cbWF0aGJme0N9XnstMX19e1xrYXBwYV4yfVxyaWdodCkrXGRmcmFje1x0YXUgXGthcHBhXnsyXGJldGF9fXtcdGV4dHR0e2ZhY3Rvcn19XHByb2Rfe2o9MX1ee20rMX0gXGxlZnQoXG1hdGhiZntJfS1yX3syan1cZGZyYWN7XG1hdGhiZntMfVxtYXRoYmZ7Q31eey0xfX17XGthcHBhXjJ9XHJpZ2h0KVxyaWdodCleey0xfSBccHJvZF97aT0xfV5tIFxsZWZ0KFxtYXRoYmZ7SX0tcl97MWl9XGRmcmFje1xtYXRoYmZ7TH1cbWF0aGJme0N9XnstMX19e1xrYXBwYV4yfVxyaWdodClcY2RvdCAoXG1hdGhiZntDfVxtYXRoYmZ7XGJhcntQfX1fe2srMX0rXHRhdSAoIFxib2xkc3ltYm9se1xiYXJ7XG1hdGhmcmFre1V9fX1fe2srMX0gLSBcbWF0aGJme0R9X3trKzF9KSkuClxlbmR7ZXF1YXRpb259CkNvbnNpZGVyaW5nIHRoZSBwYXJ0aWFsIGZyYWN0aW9uIGRlY29tcG9zaXRpb24KXGJlZ2lue2VxdWF0aW9ufQpcbGFiZWx7ZXE6cGFydGlhbF9mcmFjdGlvbmFkam9pbnR9Clx0YWd7MjB9ClxkZnJhY3tccHJvZF97aT0xfV5tICgxLXJfezFpfXgpfXtccHJvZF97aT0xfV5tICgxLXJfezFpfXgpK1xkZnJhY3tcdGF1IFxrYXBwYV57MlxiZXRhfX17XHRleHR0dHtmYWN0b3J9fSBccHJvZF97aj0xfV57bSsxfSAoMS1yX3syan14KX09XHN1bV97az0xfV57bSsxfSBhX2soeC1wX2spXnstMX0gKyByLApcZW5ke2VxdWF0aW9ufQpzY2hlbWUgXGVxcmVme2VxOmZpbmFsX3NjaGVtZWFkam9pbnR9IGNhbiBiZSBleHByZXNzZWQgYXMKXGJlZ2lue2VxdWF0aW9ufQpcbGFiZWx7ZXE6ZmluYWxfc2NoZW1lM2Fkam9pbnR9Clx0YWd7MjF9ClxtYXRoYmZ7XGJhcntQfX1fe2t9ID0gXG1hdGhiZntDfV57LTF9XGxlZnQoXHN1bV97az0xfV57bSsxfSBhX2tcbGVmdCggXGRmcmFje1xtYXRoYmZ7TH1cbWF0aGJme0N9XnstMX19e1xrYXBwYV4yfS1wX2tcbWF0aGJme0l9XHJpZ2h0KV57LTF9ICsgclxtYXRoYmZ7SX1ccmlnaHQpIChcbWF0aGJme0N9XG1hdGhiZntcYmFye1B9fV97aysxfStcdGF1ICggXGJvbGRzeW1ib2x7XGJhcntcbWF0aGZyYWt7VX19fV97aysxfSAtIFxtYXRoYmZ7RH1fe2srMX0pKS4KXGVuZHtlcXVhdGlvbn0KSW4gcHJhY3RpY2UsIHNpbmNlIHRoZSByYXRpb25hbCBmdW5jdGlvbiBpbiBcZXFyZWZ7ZXE6cGFydGlhbF9mcmFjdGlvbmFkam9pbnR9IGlzIHByb3BlciwgdGhlcmUgaXMgbm8gcmVtYWluZGVyICRyJC4gTW9yZW92ZXIsIHNpbmNlICRcbGVmdCggXGRmcmFje1xtYXRoYmZ7TH1cbWF0aGJme0N9XnstMX19e1xrYXBwYV4yfS1wX2tcbWF0aGJme0l9XHJpZ2h0KV57LTF9ICA9IFxtYXRoYmZ7Q31cbGVmdCggXGRmcmFje1xtYXRoYmZ7TH19e1xrYXBwYV4yfS1wX2tcbWF0aGJme0N9XHJpZ2h0KV57LTF9JCwgd2UgaGF2ZSB0aGF0IFxlcXJlZntlcTpmaW5hbF9zY2hlbWUzYWRqb2ludH0gY2FuIGJlIHJld3JpdHRlbiBhcwoKXGJlZ2lue2VxdWF0aW9ufQpcbGFiZWx7ZXE6ZmluYWxfc2NoZW1lZmluYWxhZGpvaW50fQpcdGFnezIxfQpcbWF0aGJme1xiYXJ7UH19X3trfSA9IFxtYXRoYmZ7Un0gKFxtYXRoYmZ7Q31cbWF0aGJme1xiYXJ7UH19X3trKzF9K1x0YXUgKCBcYm9sZHN5bWJvbHtcYmFye1xtYXRoZnJha3tVfX19X3trKzF9IC0gXG1hdGhiZntEfV97aysxfSkpLFxxdWFkIFxtYXRoYmZ7Un0gPSBcbGVmdChcc3VtX3trPTF9XnttKzF9IGFfa1xsZWZ0KCBcZGZyYWN7XG1hdGhiZntMfX17XGthcHBhXjJ9LXBfa1xtYXRoYmZ7Q31ccmlnaHQpXnstMX1ccmlnaHQpLgpcZW5ke2VxdWF0aW9ufQoKVGhhdCBpcywKXGJlZ2lue2FsaWdufQpcdGFnezIyfQpcbGFiZWx7dGhlbnVtZXJpY2Fsc2NoZW1lNH0KICAgIFxiZWdpbntjYXNlc30KICAgICZcbWF0aGJme1xiYXJ7UH19X3trfSAgPSBcbWF0aGJme1J9XG1hdGhiZntDfVxtYXRoYmZ7XGJhcntQfX1fe2srMX0rXHRhdSBcbWF0aGJme1J9KFxtYXRoYmZ7Q31cbWF0aGJme1xiYXJ7VX19X3trKzF9LVxtYXRoYmZ7RH1fe2srMX0pLFxxdWFkIGsgPSBOLTEsXGRvdHMsIDAsXFwKICAgICZcbWF0aGJme1xiYXJ7UH19X3tOfSAgPSBcbWF0aGJmezB9LAogICAgXGVuZHtjYXNlc30KXGVuZHthbGlnbn0KCk9ic2VydmUgdGhhdCB0aGUgb25seSBkaWZmZXJlbmNlIGJldHdlZW4gXGVxcmVme3RoZW51bWVyaWNhbHNjaGVtZTN9IGFuZCBcZXFyZWZ7dGhlbnVtZXJpY2Fsc2NoZW1lNH0gaXMgaW4gdGhlIHJpZ2h0LWhhbmQgc2lkZSwgd2hlcmUgaW4gXGVxcmVme3RoZW51bWVyaWNhbHNjaGVtZTR9IHdlIGhhdmUgJFxtYXRoYmZ7Q31cbWF0aGJme1xiYXJ7VX19X3trKzF9LVxtYXRoYmZ7RH1fe2srMX0kIGluc3RlYWQgb2YgJFxtYXRoYmZ7Q31cbWF0aGJme1xiYXJ7VX19X3trfS1cbWF0aGJme0R9X3trfSQuCgoKIyMgRml4ZWQgcG9pbnQgaXRlcmF0aW9uIGFsZ29yaXRobSBmb3IgdGhlIG9wdGltYWwgY29udHJvbCBwcm9ibGVtCgpMZXQgJChoX1xzdGFyLCBcdGF1X1xzdGFyKSQgZGVub3RlIHRoZSBpbnRlZ3JhdGlvbiBzcGFjZeKAk3RpbWUgbWVzaCBwYXJhbWV0ZXJzLCB3aXRoICRcdGF1X1xzdGFyID0gVC9OX1xzdGFyJCBhbmQgbm9kZXMgJChzX2leXHN0YXIsIHRfXGVsbF5cc3RhcikkIGZvciAkaSA9IDEsXGRvdHMsTl97aF9cc3Rhcn0kIGFuZCAkXGVsbCA9IDAsXGRvdHMsTl9cc3RhciQuIFRoZSBjb21wdXRhdGlvbiBzcGFjZS10aW1lIG1lc2ggaXMgZGVmaW5lZCBhbmFsb2dvdXNseSBieSAkKGgsIFx0YXUpJCwgd2l0aCAkXHRhdSA9IFQvTiQgYW5kIG5vZGVzICQoc19qLCB0X2spJCBmb3IgJGogPSAxLFxkb3RzLE5fe2h9JCBhbmQgJGsgPSAwLFxkb3RzLE4kLiBMZXQgJFxib2xkc3ltYm9se1xtYXRoZnJha3tGfX0sXGJvbGRzeW1ib2x7XG1hdGhmcmFre0R9fVxpbiBcbWF0aGJie1J9XntOX3toX1xzdGFyfVx0aW1lcyAoTisxKX0kIGRlbm90ZSB0aGUgZXZhbHVhdGlvbnMgb2YgJGYkIGFuZCAkdV9kJCBvbiBhIG1peGVkIG1lc2ggKHRoYXQgdXNlcyB0aGUgc3BhdGlhbCBub2RlcyBvZiB0aGUgaW50ZWdyYXRpb24gbWVzaCBhbmQgdGhlIHRlbXBvcmFsIG5vZGVzIG9mIHRoZSBjb21wdXRhdGlvbiBtZXNoKSwgcmVzcGVjdGl2ZWx5LCBpLmUuLCAkXGJvbGRzeW1ib2x7XG1hdGhmcmFre0Z9fV97aSxrfSA9IGYoc19pXlxzdGFyLCB0X2spJCBhbmQgJFxib2xkc3ltYm9se1xtYXRoZnJha3tEfX1fe2ksa30gPSB1X2Qoc19pXlxzdGFyLCB0X2spJC4gV2l0aCB0aGlzIG5vdGF0aW9uIGF0IGhhbmQsIHdlIG5vdyBpbnRyb2R1Y2UgdGhlIG5leHQgYWxnb3JpdGhtLgoKLSAqKjEuIEluaXRpYWxpemF0aW9uOioqIEluaXRpYWxpemUgJFxtYXRoYmZ7XGJhcntafX1caW4gXG1hdGhiYntSfV57Tl97aH1cdGltZXMgKE4rMSl9JCBvbiB0aGUgY29tcHV0YXRpb24gbWVzaCBhbmQgYXBwcm94aW1hdGUgJFxib2xkc3ltYm9se1xiYXJ7XG1hdGhjYWx7Wn19fVxpbiBcbWF0aGJie1J9XntOX3tofVx0aW1lcyAoTisxKX0kLCB3aXRoIGVudHJpZXMgJFxib2xkc3ltYm9se1xiYXJ7XG1hdGhjYWx7Wn19fV97aixrfSA9KFxiYXJ7en1ee2t9LFxwc2leal9oKV97TF8yKFxHYW1tYSl9JCwgYnkgJFxib2xkc3ltYm9se1xiYXJ7XG1hdGhjYWx7Wn19fVxhcHByb3hcYm9sZHN5bWJvbHtcUHNpfV5cdG9wIFxtYXRoYmZ7Q31ee1xzdGFyfSBcYm9sZHN5bWJvbHtcUHNpfSBcbWF0aGJme1xiYXJ7Wn19ID0gXG1hdGhiZntDfSBcbWF0aGJme1xiYXJ7Wn19JCwgd2hlcmUgdGhlIGxhc3QgZXF1YWxpdHkgaXMgdGhhbmtzIHRvIHRoZSBuZXN0ZWRuZXNzIG9mIHRoZSBzcGF0aWFsIG1lc2hlcy4gU2ltaWxhcmx5LCBhcHByb3hpbWF0ZSAkXG1hdGhiZntGfVxpbiBcbWF0aGJie1J9XntOX3tofVx0aW1lcyAoTisxKX0kLCB3aXRoIGVudHJpZXMgJFxtYXRoYmZ7Rn1fe2osa30gPShmXntrfSxccHNpXmpfaClfe0xfMihcR2FtbWEpfSQsIGJ5ICRcbWF0aGJme0Z9IFxhcHByb3ggXGJvbGRzeW1ib2x7XFBzaX1eXHRvcCBcbWF0aGJme0N9Xntcc3Rhcn0gXGJvbGRzeW1ib2x7XG1hdGhmcmFre0Z9fSQuCgotICoqMi4gU3RhdGUgc29sdmU6KiogR2l2ZW4gJFxib2xkc3ltYm9se1xiYXJ7XG1hdGhjYWx7Wn19fSQsICRcbWF0aGJme0Z9JCwgYW5kICRcbWF0aGJme1xiYXJ7VX19X3swfVxpbiBcbWF0aGJie1J9XntOX3tofX0kIHdpdGggY29tcG9uZW50cyAkdV8wKHNfaikkLCBjb21wdXRlICRcbWF0aGJme1xiYXJ7VX19XGluIFxtYXRoYmJ7Un1ee05fe2h9XHRpbWVzIChOKzEpfSQsIHRoZSBudW1lcmljYWwgc29sdXRpb24gY29ycmVzcG9uZGluZyB0byAkXGJhcnt1fSQgaW4gXGVxcmVme2VxOm1haW5lcW9wdGltYWx9LCB3aXRoIHRoZSBzY2hlbWUKClxiZWdpbnthbGlnbn0KXGxhYmVse3N0YXRlc29sdmV9Clx0YWd7RlN9CiAgICBcYmVnaW57Y2FzZXN9CiAgICBcbWF0aGJme1xiYXJ7VX19X3trKzF9ICAmPSBcbWF0aGJme1J9XG1hdGhiZntDfVxtYXRoYmZ7XGJhcntVfX1faytcdGF1IFxtYXRoYmZ7Un0oXG1hdGhiZntGfV97aysxfStcbWF0aGJme0N9XG1hdGhiZntcYmFye1p9fV97aysxfSlcXAogICAgJiA9IChcbWF0aGJme1J9XG1hdGhiZntDfSlee2srMX1cbWF0aGJme1xiYXJ7VX19XzAKKyBcdGF1IFxzdW1fe2k9MH1ee2t9IChcbWF0aGJme1J9XG1hdGhiZntDfSlee2staX1cbWF0aGJme1J9KFxtYXRoYmZ7Rn1fe2krMX0rXG1hdGhiZntDfSBcbWF0aGJme1xiYXJ7Wn19X3tpKzF9KSwgXHF1YWQgayA9IDAsXGRvdHMsIE4tMSxcXAogICAgXG1hdGhiZntcYmFye1V9fV97MH0gICY9IFt1XzAoc18xKSwgXGRvdHMsIHVfMChzX3tOX2h9KV1eXHRvcCwKICAgIFxlbmR7Y2FzZXN9ClxlbmR7YWxpZ259CgotICoqMy4gQWRqb2ludCBzb2x2ZToqKiBHaXZlbiAkXG1hdGhiZntcYmFye1V9fSQgZnJvbSBiZWZvcmUsIGFwcHJveGltYXRlICRcYm9sZHN5bWJvbHtcYmFye1xtYXRoZnJha3tVfX19XGluIFxtYXRoYmJ7Un1ee05fe2h9XHRpbWVzIChOKzEpfSQsIHdpdGggZW50cmllcyAkXGJvbGRzeW1ib2x7XGJhcntcbWF0aGZyYWt7VX19fV97aixrfSA9KFxiYXJ7dX1ee2t9LFxwc2leal9oKV97TF8yKFxHYW1tYSl9JCwgYnkgJFxib2xkc3ltYm9se1xiYXJ7XG1hdGhmcmFre1V9fX0gXGFwcHJveCBcYm9sZHN5bWJvbHtcUHNpfV5cdG9wIFxtYXRoYmZ7Q31ee1xzdGFyfSBcYm9sZHN5bWJvbHtcUHNpfSBcbWF0aGJme1xiYXJ7VX19PVxtYXRoYmZ7Q31cbWF0aGJme1xiYXJ7VX19JC4gU2ltaWxhcmx5LCBhcHByb3hpbWF0ZSAkXG1hdGhiZntEfVxpbiBcbWF0aGJie1J9XntOX3tofVx0aW1lcyAoTisxKX0kLCB3aXRoIGVudHJpZXMgJFxtYXRoYmZ7RH1fe2osa30gPSh1X2Ree2t9LFxwc2leal9oKV97TF8yKFxHYW1tYSl9JCwgYnkgJFxtYXRoYmZ7RH0gXGFwcHJveCBcYm9sZHN5bWJvbHtcUHNpfV5cdG9wIFxtYXRoYmZ7Q31ee1xzdGFyfSBcYm9sZHN5bWJvbHtcbWF0aGZyYWt7RH19JC4gQ29tcHV0ZSAkXG1hdGhiZntcYmFye1B9fVxpbiBcbWF0aGJie1J9XntOX3tofVx0aW1lcyAoTisxKX0kLCB0aGUgbnVtZXJpY2FsIHNvbHV0aW9uIGNvcnJlc3BvbmRpbmcgdG8gJFxiYXJ7cH0kIGluIFxlcXJlZntlcTphZGpvaW50ZXF9LCB3aXRoIHRoZSBzY2hlbWUKClxiZWdpbnthbGlnbn0KXGxhYmVse2Fkam9pbnRzb2x2ZX0KXHRhZ3tCU30KICAgIFxiZWdpbntjYXNlc30KICAgIFxtYXRoYmZ7XGJhcntQfX1fe2t9ICAmID0gXG1hdGhiZntSfVxtYXRoYmZ7Q31cbWF0aGJme1xiYXJ7UH19X3trKzF9K1x0YXUgXG1hdGhiZntSfShcbWF0aGJme0N9XG1hdGhiZntcYmFye1V9fV97aysxfS1cbWF0aGJme0R9X3trKzF9KVxcCiAgICAmPSAgXHRhdSBcc3VtX3tpPTB9XntOLWstMX0gKFxtYXRoYmZ7Un1cbWF0aGJme0N9KV57aX1cbWF0aGJme1J9KFxtYXRoYmZ7Q31cbWF0aGJme1xiYXJ7VX19X3trK2krMX0tXG1hdGhiZntEfV97aytpKzF9KSwgXHF1YWQgayA9IE4tMSxcZG90cywgMCxcXAogICAgXG1hdGhiZntcYmFye1B9fV97Tn0gJiAgPSBcbWF0aGJmezB9LAogICAgXGVuZHtjYXNlc30KXGVuZHthbGlnbn0KCi0gKio0LiBDb250cm9sIHVwZGF0ZToqKiBHaXZlbiAkXG1hdGhiZntcYmFye1B9fSQgZnJvbSBiZWZvcmUgYW5kIG1hdHJpY2VzICRcbWF0aGJme0F9LFxtYXRoYmZ7Qn1caW4gXG1hdGhiYntSfV57Tl97aH1cdGltZXMgKE4rMSl9JCB3aXRoIGNvbnN0YW50IGVudHJpZXMgICRcbWF0aGJme0F9X3tqLGt9ID0gYSQgYW5kICRcbWF0aGJme0J9X3tqLGt9ID0gYiQsIHJlc3BlY3RpdmVseSwgdXBkYXRlIAogICAgXGJlZ2lue2FsaWdufQogICAgXGxhYmVse2VudHJ5d2lzZXp9CiAgICAgICAgXG1hdGhiZntcYmFye1p9fSA9IFxtYXhce1xtYXRoYmZ7QX0sXG1pblx7XG1hdGhiZntCfSwtXG1hdGhiZntcYmFye1B9fS9cbXVcfVx9XHF1YWQgXHRleHR7KGVudHJ5LXdpc2UpfS4KICAgIFxlbmR7YWxpZ259CgotICoqNS4gSXRlcmF0aW9uOioqIFJlcGVhdCBzdGVwcyAyLS00IHVudGlsIGNvbnZlcmdlbmNlLgogICAgCiMjIENvbnZlcmdlbmNlIGFuYWx5c2lzIG9mIHRoZSBGQlNNIGl0ZXJhdGlvbiB7I2NvbnZfRkJTTX0KCkZvciBpbGx1c3RyYXRpb24gcHVycG9zZXMsIGFsb25nIHdpdGggdGhlIGdlbmVyYWwgY2FzZSAkTiQsIHdlIGNvbnNpZGVyIHRoZSBwYXJ0aWN1bGFyIGNhc2UgJE49MyQuIEZyb20gXGVxcmVme3N0YXRlc29sdmV9IGFuZCBcZXFyZWZ7YWRqb2ludHNvbHZlfSwgd2UgaGF2ZQoKXGJlZ2lue2FsaWdufQpcbWF0aGJme1xiYXJ7VX19X3swfSAmID0gXG1hdGhiZntcYmFye1V9fV97MH0gXFwKJiBcXApcbWF0aGJme1xiYXJ7VX19X3sxfSAmID0gIChcbWF0aGJme1J9XG1hdGhiZntDfSleMVxtYXRoYmZ7XGJhcntVfX1fMCtcdGF1IFxtYXRoYmZ7Un0oXG1hdGhiZntGfV97MX0rXG1hdGhiZntDfVxtYXRoYmZ7XGJhcntafX1fezF9KVxcCiYgXFwKXG1hdGhiZntcYmFye1V9fV97Mn0gJiA9ICBcbWF0aGJme1J9XG1hdGhiZntDfVxtYXRoYmZ7XGJhcntVfX1fMStcdGF1IFxtYXRoYmZ7Un0oXG1hdGhiZntGfV97Mn0rXG1hdGhiZntDfVxtYXRoYmZ7XGJhcntafX1fezJ9KVxcCiYgPSBcbWF0aGJme1J9XG1hdGhiZntDfSgoXG1hdGhiZntSfVxtYXRoYmZ7Q30pXjFcbWF0aGJme1xiYXJ7VX19XzArXHRhdSBcbWF0aGJme1J9KFxtYXRoYmZ7Rn1fezF9K1xtYXRoYmZ7Q31cbWF0aGJme1xiYXJ7Wn19X3sxfSkpK1x0YXUgXG1hdGhiZntSfShcbWF0aGJme0Z9X3syfStcbWF0aGJme0N9XG1hdGhiZntcYmFye1p9fV97Mn0pXFwKJiA9IChcbWF0aGJme1J9XG1hdGhiZntDfSleMlxtYXRoYmZ7XGJhcntVfX1fMCtcdGF1IChcbWF0aGJme1J9XG1hdGhiZntDfSleMVxtYXRoYmZ7Un0oXG1hdGhiZntGfV97MX0rXG1hdGhiZntDfVxtYXRoYmZ7XGJhcntafX1fezF9KStcdGF1IFxtYXRoYmZ7Un0oXG1hdGhiZntGfV97Mn0rXG1hdGhiZntDfVxtYXRoYmZ7XGJhcntafX1fezJ9KVxcCiYgXFwKXG1hdGhiZntcYmFye1V9fV97M30gJiA9ICBcbWF0aGJme1J9XG1hdGhiZntDfVxtYXRoYmZ7XGJhcntVfX1fMitcdGF1IFxtYXRoYmZ7Un0oXG1hdGhiZntGfV97M30rXG1hdGhiZntDfVxtYXRoYmZ7XGJhcntafX1fezN9KVxcCiYgPSAgXG1hdGhiZntSfVxtYXRoYmZ7Q30oKFxtYXRoYmZ7Un1cbWF0aGJme0N9KV4yXG1hdGhiZntcYmFye1V9fV8wK1x0YXUgKFxtYXRoYmZ7Un1cbWF0aGJme0N9KV4xXG1hdGhiZntSfShcbWF0aGJme0Z9X3sxfStcbWF0aGJme0N9XG1hdGhiZntcYmFye1p9fV97MX0pK1x0YXUgXG1hdGhiZntSfShcbWF0aGJme0Z9X3syfStcbWF0aGJme0N9XG1hdGhiZntcYmFye1p9fV97Mn0pKStcdGF1IFxtYXRoYmZ7Un0oXG1hdGhiZntGfV97M30rXG1hdGhiZntDfVxtYXRoYmZ7XGJhcntafX1fezN9KVxcCiYgPSAgKFxtYXRoYmZ7Un1cbWF0aGJme0N9KV4zXG1hdGhiZntcYmFye1V9fV8wK1x0YXUgKFxtYXRoYmZ7Un1cbWF0aGJme0N9KV4yXG1hdGhiZntSfShcbWF0aGJme0Z9X3sxfStcbWF0aGJme0N9XG1hdGhiZntcYmFye1p9fV97MX0pK1x0YXUgKFxtYXRoYmZ7Un1cbWF0aGJme0N9KV4xXG1hdGhiZntSfShcbWF0aGJme0Z9X3syfStcbWF0aGJme0N9XG1hdGhiZntcYmFye1p9fV97Mn0pK1x0YXUgXG1hdGhiZntSfShcbWF0aGJme0Z9X3szfStcbWF0aGJme0N9XG1hdGhiZntcYmFye1p9fV97M30pClxlbmR7YWxpZ259CmFuZApcYmVnaW57YWxpZ259ClxtYXRoYmZ7XGJhcntQfX1fezN9ICY9IFxtYXRoYmZ7MH0sIFxcCiZcXApcbWF0aGJme1xiYXJ7UH19X3syfSAmPSBcbWF0aGJme1J9XG1hdGhiZntDfVxtYXRoYmZ7XGJhcntQfX1fezN9ICsgXHRhdVxtYXRoYmZ7Un0oXG1hdGhiZntDfVxtYXRoYmZ7XGJhcntVfX1fezN9LVxtYXRoYmZ7RH1fezN9KVxcCiY9IFx0YXVcbWF0aGJme1J9KFxtYXRoYmZ7Q31cbWF0aGJme1xiYXJ7VX19X3szfS1cbWF0aGJme0R9X3szfSksIFxcCiZcXApcbWF0aGJme1xiYXJ7UH19X3sxfSAmPSBcbWF0aGJme1J9XG1hdGhiZntDfVxtYXRoYmZ7XGJhcntQfX1fezJ9ICsgXHRhdVxtYXRoYmZ7Un0oXG1hdGhiZntDfVxtYXRoYmZ7XGJhcntVfX1fezJ9LVxtYXRoYmZ7RH1fezJ9KSBcXAomPSBcdGF1KFxtYXRoYmZ7Un1cbWF0aGJme0N9KV4xXG1hdGhiZntSfShcbWF0aGJme0N9XG1hdGhiZntcYmFye1V9fV97M30tXG1hdGhiZntEfV97M30pCisgXHRhdVxtYXRoYmZ7Un0oXG1hdGhiZntDfVxtYXRoYmZ7XGJhcntVfX1fezJ9LVxtYXRoYmZ7RH1fezJ9KSwgXFwKJlxcClxtYXRoYmZ7XGJhcntQfX1fezB9ICY9IFxtYXRoYmZ7Un1cbWF0aGJme0N9XG1hdGhiZntcYmFye1B9fV97MX0gKyBcdGF1XG1hdGhiZntSfShcbWF0aGJme0N9XG1hdGhiZntcYmFye1V9fV97MX0tXG1hdGhiZntEfV97MX0pIFxcCiY9IFx0YXUoXG1hdGhiZntSfVxtYXRoYmZ7Q30pXnsyfVxtYXRoYmZ7Un0oXG1hdGhiZntDfVxtYXRoYmZ7XGJhcntVfX1fezN9LVxtYXRoYmZ7RH1fezN9KQorIFx0YXUoXG1hdGhiZntSfVxtYXRoYmZ7Q30pXjFcbWF0aGJme1J9KFxtYXRoYmZ7Q31cbWF0aGJme1xiYXJ7VX19X3syfS1cbWF0aGJme0R9X3syfSkKKyBcdGF1XG1hdGhiZntSfShcbWF0aGJme0N9XG1hdGhiZntcYmFye1V9fV97MX0tXG1hdGhiZntEfV97MX0pLgpcZW5ke2FsaWdufQoKCgpJbiBibG9jay1tYXRyaXggbm90YXRpb24KXGJlZ2lue2FsaWdufQpcYmVnaW57Ym1hdHJpeH0KXG1hdGhiZntcYmFye1V9fV97MH0gXFxbMW1tXQpcbWF0aGJme1xiYXJ7VX19X3sxfSBcXFsxbW1dClxtYXRoYmZ7XGJhcntVfX1fezJ9IFxcWzFtbV0KXG1hdGhiZntcYmFye1V9fV97M30KXGVuZHtibWF0cml4fQo9IApcYmVnaW57Ym1hdHJpeH0KXG1hdGhiZntcYmFye1V9fV97MH0gXFxbMW1tXQooXG1hdGhiZntSfVxtYXRoYmZ7Q30pXjFcbWF0aGJme1xiYXJ7VX19X3swfSBcXFsxbW1dCihcbWF0aGJme1J9XG1hdGhiZntDfSleMlxtYXRoYmZ7XGJhcntVfX1fezB9IFxcWzFtbV0KKFxtYXRoYmZ7Un1cbWF0aGJme0N9KV4zXG1hdGhiZntcYmFye1V9fV97MH0KXGVuZHtibWF0cml4fQorXHRhdQpcYmVnaW57Ym1hdHJpeH0KXG1hdGhiZnswfSAmIFxtYXRoYmZ7MH0gJiBcbWF0aGJmezB9ICYgXG1hdGhiZnswfSAgXFxbMW1tXQpcbWF0aGJmezB9ICYgXG1hdGhiZntJfSAmIFxtYXRoYmZ7MH0gJiBcbWF0aGJmezB9ICBcXFsxbW1dClxtYXRoYmZ7MH0gJiAoXG1hdGhiZntSfVxtYXRoYmZ7Q30pXjEgJiBcbWF0aGJme0l9ICYgXG1hdGhiZnswfSAgXFxbMW1tXQpcbWF0aGJmezB9ICYgKFxtYXRoYmZ7Un1cbWF0aGJme0N9KV4yICYgKFxtYXRoYmZ7Un1cbWF0aGJme0N9KV4xICYgXG1hdGhiZntJfSAKXGVuZHtibWF0cml4fQpcYmVnaW57Ym1hdHJpeH0KXG1hdGhiZntSfShcbWF0aGJme1xiYXJ7Rn19X3swfStcbWF0aGJme0N9XG1hdGhiZntcYmFye1p9fV97MH0pIFxcWzFtbV0KXG1hdGhiZntSfShcbWF0aGJme1xiYXJ7Rn19X3sxfStcbWF0aGJme0N9XG1hdGhiZntcYmFye1p9fV97MX0pIFxcWzFtbV0KXG1hdGhiZntSfShcbWF0aGJme1xiYXJ7Rn19X3syfStcbWF0aGJme0N9XG1hdGhiZntcYmFye1p9fV97Mn0pIFxcWzFtbV0KXG1hdGhiZntSfShcbWF0aGJme1xiYXJ7Rn19X3szfStcbWF0aGJme0N9XG1hdGhiZntcYmFye1p9fV97M30pClxlbmR7Ym1hdHJpeH0KXGVuZHthbGlnbn0KYW5kClxiZWdpbnthbGlnbn0KXGJlZ2lue2JtYXRyaXh9ClxtYXRoYmZ7XGJhcntQfX1fezB9IFxcWzFtbV0KXG1hdGhiZntcYmFye1B9fV97MX0gXFxbMW1tXQpcbWF0aGJme1xiYXJ7UH19X3syfSBcXFsxbW1dClxtYXRoYmZ7XGJhcntQfX1fezN9ClxlbmR7Ym1hdHJpeH0KPQpcdGF1ClxiZWdpbntibWF0cml4fQpcbWF0aGJmezB9ICYgXG1hdGhiZntJfSAmIChcbWF0aGJme1J9XG1hdGhiZntDfSkgJiAoXG1hdGhiZntSfVxtYXRoYmZ7Q30pXnsyfSBcXFsxbW1dClxtYXRoYmZ7MH0gJiBcbWF0aGJmezB9ICYgXG1hdGhiZntJfSAmIChcbWF0aGJme1J9XG1hdGhiZntDfSkgXFxbMW1tXQpcbWF0aGJmezB9ICYgXG1hdGhiZnswfSAmIFxtYXRoYmZ7MH0gJiBcbWF0aGJme0l9IFxcWzFtbV0KXG1hdGhiZnswfSAmIFxtYXRoYmZ7MH0gJiBcbWF0aGJmezB9ICYgXG1hdGhiZnswfQpcZW5ke2JtYXRyaXh9ClxiZWdpbntibWF0cml4fQpcbWF0aGJme1J9KFxtYXRoYmZ7Q31cbWF0aGJme1xiYXJ7VX19X3swfS1cbWF0aGJme0R9X3swfSkgXFxbMW1tXQpcbWF0aGJme1J9KFxtYXRoYmZ7Q31cbWF0aGJme1xiYXJ7VX19X3sxfS1cbWF0aGJme0R9X3sxfSkgXFxbMW1tXQpcbWF0aGJme1J9KFxtYXRoYmZ7Q31cbWF0aGJme1xiYXJ7VX19X3syfS1cbWF0aGJme0R9X3syfSkgXFxbMW1tXQpcbWF0aGJme1J9KFxtYXRoYmZ7Q31cbWF0aGJme1xiYXJ7VX19X3szfS1cbWF0aGJme0R9X3szfSkKXGVuZHtibWF0cml4fS4KXGVuZHthbGlnbn0KCgoKSW4gZ2VuZXJhbCwKXGJlZ2lue2FsaWdufQpcYmVnaW57Ym1hdHJpeH0KXG1hdGhiZntcYmFye1V9fV97MH0gXFxbMW1tXQpcbWF0aGJme1xiYXJ7VX19X3sxfSBcXFsxbW1dClxtYXRoYmZ7XGJhcntVfX1fezJ9IFxcWzFtbV0KXHZkb3RzIFxcWzFtbV0KXG1hdGhiZntcYmFye1V9fV97Tn0KXGVuZHtibWF0cml4fQomPQpcYmVnaW57Ym1hdHJpeH0KXG1hdGhiZntcYmFye1V9fV97MH0gXFxbMW1tXQooXG1hdGhiZntSfVxtYXRoYmZ7Q30pXjFcbWF0aGJme1xiYXJ7VX19X3swfSBcXFsxbW1dCihcbWF0aGJme1J9XG1hdGhiZntDfSleMlxtYXRoYmZ7XGJhcntVfX1fezB9IFxcWzFtbV0KXHZkb3RzIFxcWzFtbV0KKFxtYXRoYmZ7Un1cbWF0aGJme0N9KV5OXG1hdGhiZntcYmFye1V9fV97MH0KXGVuZHtibWF0cml4fQoKK1x0YXUKXGJlZ2lue2JtYXRyaXh9ClxtYXRoYmZ7MH0gJiBcbWF0aGJmezB9ICYgXG1hdGhiZnswfSAmIFxjZG90cyAmIFxtYXRoYmZ7MH0gXFxbMW1tXQpcbWF0aGJmezB9ICYgXG1hdGhiZntJfSAmIFxtYXRoYmZ7MH0gJiBcY2RvdHMgJiBcbWF0aGJmezB9IFxcWzFtbV0KXG1hdGhiZnswfSAmIChcbWF0aGJme1J9XG1hdGhiZntDfSleMSAmIFxtYXRoYmZ7SX0gJiBcY2RvdHMgJiBcbWF0aGJmezB9IFxcWzFtbV0KXHZkb3RzICYgXHZkb3RzICYgXHZkb3RzICYgXGRkb3RzICYgXHZkb3RzIFxcWzFtbV0KXG1hdGhiZnswfSAmIChcbWF0aGJme1J9XG1hdGhiZntDfSlee04tMX0gJiAoXG1hdGhiZntSfVxtYXRoYmZ7Q30pXntOLTJ9ICYgXGNkb3RzICYgXG1hdGhiZntJfQpcZW5ke2JtYXRyaXh9ClxiZWdpbntibWF0cml4fQpcbWF0aGJme1J9KFxtYXRoYmZ7XGJhcntGfX1fezB9K1xtYXRoYmZ7Q31cbWF0aGJme1xiYXJ7Wn19X3swfSkgXFxbMW1tXQpcbWF0aGJme1J9KFxtYXRoYmZ7XGJhcntGfX1fezF9K1xtYXRoYmZ7Q31cbWF0aGJme1xiYXJ7Wn19X3sxfSkgXFxbMW1tXQpcbWF0aGJme1J9KFxtYXRoYmZ7XGJhcntGfX1fezJ9K1xtYXRoYmZ7Q31cbWF0aGJme1xiYXJ7Wn19X3syfSkgXFxbMW1tXQpcdmRvdHMgXFxbMW1tXQpcbWF0aGJme1J9KFxtYXRoYmZ7XGJhcntGfX1fe059K1xtYXRoYmZ7Q31cbWF0aGJme1xiYXJ7Wn19X3tOfSkKXGVuZHtibWF0cml4fS4KXGVuZHthbGlnbn0KYW5kIFxiZWdpbnthbGlnbn0KXGJlZ2lue2JtYXRyaXh9ClxtYXRoYmZ7XGJhcntQfX1fezB9IFxcWzFtbV0KXG1hdGhiZntcYmFye1B9fV97MX0gXFxbMW1tXQpcdmRvdHMgXFxbMW1tXQpcbWF0aGJme1xiYXJ7UH19X3tOLTF9IFxcWzFtbV0KXG1hdGhiZntcYmFye1B9fV97Tn0KXGVuZHtibWF0cml4fQo9Clx0YXUKXGJlZ2lue2JtYXRyaXh9ClxtYXRoYmZ7MH0gJiBcbWF0aGJme0l9ICYgKFxtYXRoYmZ7Un1cbWF0aGJme0N9KSAmIFxjZG90cyAmIChcbWF0aGJme1J9XG1hdGhiZntDfSlee04tMX0gXFxbMW1tXQpcbWF0aGJmezB9ICYgXG1hdGhiZnswfSAmIFxtYXRoYmZ7SX0gJiBcY2RvdHMgJiAoXG1hdGhiZntSfVxtYXRoYmZ7Q30pXntOLTJ9IFxcWzFtbV0KXHZkb3RzICYgXHZkb3RzICYgXHZkb3RzICYgXGRkb3RzICYgXHZkb3RzIFxcWzFtbV0KXG1hdGhiZnswfSAmIFxtYXRoYmZ7MH0gJiBcbWF0aGJmezB9ICYgXGNkb3RzICYgXG1hdGhiZntJfSBcXFsxbW1dClxtYXRoYmZ7MH0gJiBcbWF0aGJmezB9ICYgXG1hdGhiZnswfSAmIFxjZG90cyAmIFxtYXRoYmZ7MH0KXGVuZHtibWF0cml4fQpcYmVnaW57Ym1hdHJpeH0KXG1hdGhiZntSfShcbWF0aGJme0N9XG1hdGhiZntcYmFye1V9fV97MH0tXG1hdGhiZntEfV97MH0pIFxcWzFtbV0KXG1hdGhiZntSfShcbWF0aGJme0N9XG1hdGhiZntcYmFye1V9fV97MX0tXG1hdGhiZntEfV97MX0pIFxcWzFtbV0KXHZkb3RzIFxcWzFtbV0KXG1hdGhiZntSfShcbWF0aGJme0N9XG1hdGhiZntcYmFye1V9fV97Ti0xfS1cbWF0aGJme0R9X3tOLTF9KSBcXFsxbW1dClxtYXRoYmZ7Un0oXG1hdGhiZntDfVxtYXRoYmZ7XGJhcntVfX1fe059LVxtYXRoYmZ7RH1fe059KQpcZW5ke2JtYXRyaXh9LgpcZW5ke2FsaWdufQpCeSBkZWZpbmluZyBzdGFja2VkIHZlY3RvcnMgb2YgbGVuZ3RoICQoTisxKU5faCQsClxiZWdpbnthbGlnbip9CiBcbWF0aGJme1xiYXJ7dX19ID0gXHRleHR7dmVjfShcbWF0aGJme1xiYXJ7VX19KSxccXVhZCAKXG1hdGhiZntcYmFye3B9fSA9IFx0ZXh0e3ZlY30oXG1hdGhiZntcYmFye1B9fSksXHF1YWQKXG1hdGhiZntcYmFye3p9fSA9IFx0ZXh0e3ZlY30oXG1hdGhiZntcYmFye1p9fSksXHF1YWQgXG1hdGhiZntmfSA9IFx0ZXh0e3ZlY30oXG1hdGhiZntGfSksXHF1YWQKXG1hdGhiZntkfSA9XHRleHR7dmVjfShcbWF0aGJme0R9KSwKXGVuZHthbGlnbip9ClxiZWdpbnthbGlnbip9CiAgICBcbWF0aGJme2F9ID1cdGV4dHt2ZWN9KFxtYXRoYmZ7QX0pLFxxdWFkClxtYXRoYmZ7Yn0gPSBcdGV4dHt2ZWN9KFxtYXRoYmZ7Qn0pLFxxdWFkXG1hdGhiZntofT0gW1xtYXRoYmZ7XGJhcntVfX1fezB9Xlx0b3AgKChcbWF0aGJme1J9XG1hdGhiZntDfSleezF9XG1hdGhiZntcYmFye1V9fV97MH0pXlx0b3AgKChcbWF0aGJme1J9XG1hdGhiZntDfSleezJ9IFxtYXRoYmZ7XGJhcntVfX1fezB9KV5cdG9wXGRvdHMgKChcbWF0aGJme1J9XG1hdGhiZntDfSlee059XG1hdGhiZntcYmFye1V9fV97MH0pXlx0b3BdXlx0b3AsClxlbmR7YWxpZ24qfQphbmQgYmxvY2sgbWF0cmljZXMgb2YgZGltZW5zaW9uICQoTisxKU5faFx0aW1lcyAoTisxKU5faCQsClxiZWdpbnthbGlnbip9ClxtYXRoYmZ7TX0gPSBcbWF0aGJme0l9X3tOKzF9XG90aW1lcyAgXG1hdGhiZntDfSxccXVhZCBcbWF0aGJme1xoYXR7Sn19X3tOKzF9ID0gXG1hdGhiZntKfV97TisxfVxvdGltZXMgXG1hdGhiZntJfV97Tl9ofSxccXVhZCBcbWF0aGJme1xoYXR7Un19ID0gXG1hdGhiZntJfV97TisxfVxvdGltZXMgIFxtYXRoYmZ7Un0gLApcZW5ke2FsaWduKn0KXGJlZ2lue2FsaWdufQpcbWF0aGJme1N9X3tcbWF0aHJte0Z9fQo9IFx0YXUKXGJlZ2lue2JtYXRyaXh9ClxtYXRoYmZ7MH0gJiBcbWF0aGJmezB9ICYgXG1hdGhiZnswfSAmIFxjZG90cyAmIFxtYXRoYmZ7MH0gXFxbMW1tXQpcbWF0aGJmezB9ICYgXG1hdGhiZntJfSAmIFxtYXRoYmZ7MH0gJiBcY2RvdHMgJiBcbWF0aGJmezB9IFxcWzFtbV0KXG1hdGhiZnswfSAmIChcbWF0aGJme1J9XG1hdGhiZntDfSleMSAmIFxtYXRoYmZ7SX0gJiBcY2RvdHMgJiBcbWF0aGJmezB9IFxcWzFtbV0KXHZkb3RzICYgXHZkb3RzICYgXHZkb3RzICYgXGRkb3RzICYgXHZkb3RzIFxcWzFtbV0KXG1hdGhiZnswfSAmIChcbWF0aGJme1J9XG1hdGhiZntDfSlee04tMX0gJiAoXG1hdGhiZntSfVxtYXRoYmZ7Q30pXntOLTJ9ICYgXGNkb3RzICYgXG1hdGhiZntJfQpcZW5ke2JtYXRyaXh9XHF1YWQgXHRleHR7YW5kfVxxdWFkClxtYXRoYmZ7U31fe1xtYXRocm17Qn19Cj0gXHRhdQpcYmVnaW57Ym1hdHJpeH0KXG1hdGhiZnswfSAmIFxtYXRoYmZ7SX0gJiAoXG1hdGhiZntSfVxtYXRoYmZ7Q30pICYgXGNkb3RzICYgKFxtYXRoYmZ7Un1cbWF0aGJme0N9KV57Ti0xfSBcXFsxbW1dClxtYXRoYmZ7MH0gJiBcbWF0aGJmezB9ICYgXG1hdGhiZntJfSAmIFxjZG90cyAmIChcbWF0aGJme1J9XG1hdGhiZntDfSlee04tMn0gXFxbMW1tXQpcdmRvdHMgJiBcdmRvdHMgJiBcdmRvdHMgJiBcZGRvdHMgJiBcdmRvdHMgXFxbMW1tXQpcbWF0aGJmezB9ICYgXG1hdGhiZnswfSAmIFxtYXRoYmZ7MH0gJiBcY2RvdHMgJiBcbWF0aGJme0l9IFxcWzFtbV0KXG1hdGhiZnswfSAmIFxtYXRoYmZ7MH0gJiBcbWF0aGJmezB9ICYgXGNkb3RzICYgXG1hdGhiZnswfQpcZW5ke2JtYXRyaXh9LApcZW5ke2FsaWdufQp0aGVuIHRoZSB2ZWN0b3JpemVkIGZvcm0gClxiZWdpbnthbGlnbn0KXGxhYmVse2l0ZXJhdGlvbnZlY3Rvcml6ZWR9CiAgICBcYmVnaW57Y2FzZXN9CiAgICBcbWF0aGJme1xiYXJ7dX19ICY9IFxtYXRoYmZ7aH0gKyBcbWF0aGJme1N9X3tcbWF0aHJte0Z9fVxtYXRoYmZ7XGhhdHtSfX0oXG1hdGhiZntmfStcbWF0aGJme019XG1hdGhiZntcYmFye3p9fSlcXAogICAgXG1hdGhiZntcYmFye3B9fSAmID0gXG1hdGhiZntTfV97XG1hdGhybXtCfX1cbWF0aGJme1xoYXR7Un19KFxtYXRoYmZ7TX1cbWF0aGJme1xiYXJ7dX19IC0gXG1hdGhiZntkfSlcXAogICAgXG1hdGhiZntcYmFye3p9fSAmID0gXG1heFx7XG1hdGhiZnthfSwgXG1pblx7XG1hdGhiZntifSwgLVxtYXRoYmZ7XGJhcntwfX0vXG11XH1cfSBccXVhZCBcdGV4dHsoY29tcG9uZW50d2lzZSl9LgogICAgIFxlbmR7Y2FzZXN9ClxlbmR7YWxpZ259CldlIG5lZWQgdG8gZXN0aW1hdGUgJFxnYW1tYSA9ICgxL1xtdSlcfFxib2xkc3ltYm9se1xtYXRoZnJha3tMfX1cfF97XG1hdGhiZntDfV97TisxfX0kIHdoZXJlICRcYm9sZHN5bWJvbHtcbWF0aGZyYWt7TH19ID0gXG1hdGhiZntTfV97XG1hdGhybXtCfX1cbWF0aGJme1xoYXR7Un19XG1hdGhiZntNfVxtYXRoYmZ7U31fe1xtYXRocm17Rn19XG1hdGhiZntcaGF0e1J9fVxtYXRoYmZ7TX0kLiBXZSBoYXZlClxiZWdpbnthbGlnbn0KXG1hdGhiZntTfV97XG1hdGhybXtGfX1cbWF0aGJme1xoYXR7Un19XG1hdGhiZntNfQo9IFx0YXUKXGJlZ2lue2JtYXRyaXh9ClxtYXRoYmZ7MH0gJiBcbWF0aGJmezB9ICYgXG1hdGhiZnswfSAmIFxjZG90cyAmIFxtYXRoYmZ7MH0gXFxbMW1tXQpcbWF0aGJmezB9ICYgXG1hdGhiZntSfVxtYXRoYmZ7Q30gJiBcbWF0aGJmezB9ICYgXGNkb3RzICYgXG1hdGhiZnswfSBcXFsxbW1dClxtYXRoYmZ7MH0gJiAoXG1hdGhiZntSfVxtYXRoYmZ7Q30pXjIgJiBcbWF0aGJme1J9XG1hdGhiZntDfSAmIFxjZG90cyAmIFxtYXRoYmZ7MH0gXFxbMW1tXQpcdmRvdHMgJiBcdmRvdHMgJiBcdmRvdHMgJiBcZGRvdHMgJiBcdmRvdHMgXFxbMW1tXQpcbWF0aGJmezB9ICYgKFxtYXRoYmZ7Un1cbWF0aGJme0N9KV57Tn0gJiAoXG1hdGhiZntSfVxtYXRoYmZ7Q30pXntOLTF9ICYgXGNkb3RzICYgXG1hdGhiZntSfVxtYXRoYmZ7Q30KXGVuZHtibWF0cml4fVxxdWFkIFx0ZXh0e2FuZH1ccXVhZApcbWF0aGJme1N9X3tcbWF0aHJte0J9fVxtYXRoYmZ7XGhhdHtSfX1cbWF0aGJme019Cj0gXHRhdQpcYmVnaW57Ym1hdHJpeH0KXG1hdGhiZnswfSAmIFxtYXRoYmZ7Un1cbWF0aGJme0N9ICYgKFxtYXRoYmZ7Un1cbWF0aGJme0N9KV4yICYgXGNkb3RzICYgKFxtYXRoYmZ7Un1cbWF0aGJme0N9KV57Tn0gXFxbMW1tXQpcbWF0aGJmezB9ICYgXG1hdGhiZnswfSAmIFxtYXRoYmZ7Un1cbWF0aGJme0N9ICYgXGNkb3RzICYgKFxtYXRoYmZ7Un1cbWF0aGJme0N9KV57Ti0xfSBcXFsxbW1dClx2ZG90cyAmIFx2ZG90cyAmIFx2ZG90cyAmIFxkZG90cyAmIFx2ZG90cyBcXFsxbW1dClxtYXRoYmZ7MH0gJiBcbWF0aGJmezB9ICYgXG1hdGhiZnswfSAmIFxjZG90cyAmIFxtYXRoYmZ7Un1cbWF0aGJme0N9IFxcWzFtbV0KXG1hdGhiZnswfSAmIFxtYXRoYmZ7MH0gJiBcbWF0aGJmezB9ICYgXGNkb3RzICYgXG1hdGhiZnswfQpcZW5ke2JtYXRyaXh9ClxlbmR7YWxpZ259CklmICROPTMkLCB0aGVuClxiZWdpbnthbGlnbn0KXGJvbGRzeW1ib2x7XG1hdGhmcmFre0x9fSA9IFxtYXRoYmZ7U31fe1xtYXRocm17Qn19XG1hdGhiZntcaGF0e1J9fVxtYXRoYmZ7TX1cbWF0aGJme1N9X3tcbWF0aHJte0Z9fVxtYXRoYmZ7XGhhdHtSfX1cbWF0aGJme019IAomPSBcdGF1XjIKXGJlZ2lue2JtYXRyaXh9ClxtYXRoYmZ7MH0gJiBcbWF0aGJme1J9XG1hdGhiZntDfSAmIChcbWF0aGJme1J9XG1hdGhiZntDfSleMiAmIChcbWF0aGJme1J9XG1hdGhiZntDfSleezN9IFxcWzFtbV0KXG1hdGhiZnswfSAmIFxtYXRoYmZ7MH0gJiBcbWF0aGJme1J9XG1hdGhiZntDfSAmIChcbWF0aGJme1J9XG1hdGhiZntDfSleMiBcXFsxbW1dClxtYXRoYmZ7MH0gJiBcbWF0aGJmezB9ICYgXG1hdGhiZnswfSAmIFxtYXRoYmZ7Un1cbWF0aGJme0N9IFxcWzFtbV0KXG1hdGhiZnswfSAmIFxtYXRoYmZ7MH0gJiBcbWF0aGJmezB9ICYgXG1hdGhiZnswfQpcZW5ke2JtYXRyaXh9ClxiZWdpbntibWF0cml4fQpcbWF0aGJmezB9ICYgXG1hdGhiZnswfSAmIFxtYXRoYmZ7MH0gJiBcbWF0aGJmezB9ICBcXFsxbW1dClxtYXRoYmZ7MH0gJiBcbWF0aGJme1J9XG1hdGhiZntDfSAmIFxtYXRoYmZ7MH0gJiBcbWF0aGJmezB9ICBcXFsxbW1dClxtYXRoYmZ7MH0gJiAoXG1hdGhiZntSfVxtYXRoYmZ7Q30pXjIgJiBcbWF0aGJme1J9XG1hdGhiZntDfSAmIFxtYXRoYmZ7MH0gIFxcWzFtbV0KXG1hdGhiZnswfSAmIChcbWF0aGJme1J9XG1hdGhiZntDfSleMyAmIChcbWF0aGJme1J9XG1hdGhiZntDfSleMiAmIFxtYXRoYmZ7Un1cbWF0aGJme0N9ClxlbmR7Ym1hdHJpeH1cXAomXFwKJiA9IFx0YXVeMgpcYmVnaW57Ym1hdHJpeH0KXG1hdGhiZnswfSAmIChcbWF0aGJme1J9XG1hdGhiZntDfSleMiArIChcbWF0aGJme1J9XG1hdGhiZntDfSleNCArIChcbWF0aGJme1J9XG1hdGhiZntDfSleNiAKICAgICAgICAgICAmIChcbWF0aGJme1J9XG1hdGhiZntDfSleMyArIChcbWF0aGJme1J9XG1hdGhiZntDfSleNSAKICAgICAgICAgICAmIChcbWF0aGJme1J9XG1hdGhiZntDfSleNCBcXFsxbW1dClxtYXRoYmZ7MH0gJiAoXG1hdGhiZntSfVxtYXRoYmZ7Q30pXjMgKyAoXG1hdGhiZntSfVxtYXRoYmZ7Q30pXjUgCiAgICAgICAgICAgJiAoXG1hdGhiZntSfVxtYXRoYmZ7Q30pXjIgKyAoXG1hdGhiZntSfVxtYXRoYmZ7Q30pXjQgCiAgICAgICAgICAgJiAoXG1hdGhiZntSfVxtYXRoYmZ7Q30pXjMgXFxbMW1tXQpcbWF0aGJmezB9ICYgKFxtYXRoYmZ7Un1cbWF0aGJme0N9KV40IAogICAgICAgICAgICYgKFxtYXRoYmZ7Un1cbWF0aGJme0N9KV4zIAogICAgICAgICAgICYgKFxtYXRoYmZ7Un1cbWF0aGJme0N9KV4yIFxcWzFtbV0KXG1hdGhiZnswfSAmIFxtYXRoYmZ7MH0gCiAgICAgICAgICAgJiBcbWF0aGJmezB9IAogICAgICAgICAgICYgXG1hdGhiZnswfQpcZW5ke2JtYXRyaXh9ClxlbmR7YWxpZ259CgpMZXQgClxiZWdpbnthbGlnbn0KXGJvbGRzeW1ib2x7XGhhdHtcbWF0aGZyYWt7TH19fSA9ICAKXGJlZ2lue2JtYXRyaXh9ClxzdW1fe2s9MX1ee059KFxtYXRoYmZ7Un1cbWF0aGJme0N9KV57MmsrKE4tTil9ICAgJiBcY2RvdHMgICYgXHN1bV97az0xfV57M30oXG1hdGhiZntSfVxtYXRoYmZ7Q30pXnsyaysoTi0zKX0gJiBcc3VtX3trPTF9XnsyfShcbWF0aGJme1J9XG1hdGhiZntDfSleezJrKyhOLTIpfSAgJiBcc3VtX3trPTF9XnsxfShcbWF0aGJme1J9XG1hdGhiZntDfSleezJrKyhOLTEpfSAgXFxbMW1tXQpcdmRvdHMgJiBcZGRvdHMgJiBcdmRvdHMgJiBcdmRvdHMgJiBcdmRvdHMgIFxcWzFtbV0KXHN1bV97az0xfV57M30oXG1hdGhiZntSfVxtYXRoYmZ7Q30pXnsyaysoTi0zKX0gJiBcY2RvdHMgJiBcc3VtX3trPTF9XnszfShcbWF0aGJme1J9XG1hdGhiZntDfSleezJrfSAgJiBcc3VtX3trPTF9XnsyfShcbWF0aGJme1J9XG1hdGhiZntDfSleezJrKzF9ICAmIFxzdW1fe2s9MX1eezF9KFxtYXRoYmZ7Un1cbWF0aGJme0N9KV57MmsrMn0gXFxbMW1tXQpcc3VtX3trPTF9XnsyfShcbWF0aGJme1J9XG1hdGhiZntDfSleezJrKyhOLTIpfSAgICAmIFxjZG90cyAmIFxzdW1fe2s9MX1eezJ9KFxtYXRoYmZ7Un1cbWF0aGJme0N9KV57MmsrMX0gICYgXHN1bV97az0xfV57Mn0oXG1hdGhiZntSfVxtYXRoYmZ7Q30pXnsya30gICYgXHN1bV97az0xfV57MX0oXG1hdGhiZntSfVxtYXRoYmZ7Q30pXnsyaysxfSBcXFsxbW1dClxzdW1fe2s9MX1eezF9KFxtYXRoYmZ7Un1cbWF0aGJme0N9KV57MmsrKE4tMSl9ICAgJiBcY2RvdHMgICYgXHN1bV97az0xfV57MX0oXG1hdGhiZntSfVxtYXRoYmZ7Q30pXnsyaysyfSAgICYgXHN1bV97az0xfV57MX0oXG1hdGhiZntSfVxtYXRoYmZ7Q30pXnsyaysxfSAgJiBcc3VtX3trPTF9XnsxfShcbWF0aGJme1J9XG1hdGhiZntDfSleezJrfSAKXGVuZHtibWF0cml4fQpcZW5ke2FsaWdufQoKVGhlbiB3ZSBjYW4gd3JpdGUKClxiZWdpbnthbGlnbn0KXGJvbGRzeW1ib2x7XG1hdGhmcmFre0x9fSA9ICBcdGF1XjIKXGJlZ2lue2JtYXRyaXh9CiBcbWF0aGJmezB9ICYgXGJvbGRzeW1ib2x7XGhhdHtcbWF0aGZyYWt7TH19fSBcXFsxbW1dCiBcbWF0aGJmezB9ICYgXG1hdGhiZnswfSAKXGVuZHtibWF0cml4fQpcZW5ke2FsaWdufQoKCgoKTGV0ICRcYm9sZHN5bWJvbHtcbWF0aGZyYWt7Qn19ID0gXG1hdGhiZntDfV97TisxfV57XGZyYWN7MX17Mn19XGJvbGRzeW1ib2x7XG1hdGhmcmFre0x9fVxtYXRoYmZ7Q31fe04rMX1eey1cZnJhY3sxfXsyfX0kLiBOb3RlIGZvciBleGFtcGxlIHRoYXQKXGJlZ2lue2FsaWduKn0KIFxtYXRoYmZ7Q31ee1xmcmFjezF9ezJ9fShcbWF0aGJme1J9XG1hdGhiZntDfSleezN9XG1hdGhiZntDfV57LVxmcmFjezF9ezJ9fSAgPSAgXG1hdGhiZntDfV57XGZyYWN7MX17Mn19XG1hdGhiZntSfVxtYXRoYmZ7Q31cbWF0aGJme1J9XG1hdGhiZntDfVxtYXRoYmZ7Un1cbWF0aGJme0N9XG1hdGhiZntDfV57LVxmcmFjezF9ezJ9fSA9ICAoXG1hdGhiZntDfV57XGZyYWN7MX17Mn19XG1hdGhiZntSfVxtYXRoYmZ7Q31ee1xmcmFjezF9ezJ9fSleMy4KXGVuZHthbGlnbip9ClRoZXJlZm9yZQpcYmVnaW57YWxpZ259Clxib2xkc3ltYm9se1xtYXRoZnJha3tCfX0gID0gXHRhdV4yClxiZWdpbntibWF0cml4fQpcbWF0aGJmezB9ICYgKFxtYXRoYmZ7Q31ee1xmcmFjezF9ezJ9fVxtYXRoYmZ7Un1cbWF0aGJme0N9XntcZnJhY3sxfXsyfX0pXjIgKyAoXG1hdGhiZntDfV57XGZyYWN7MX17Mn19XG1hdGhiZntSfVxtYXRoYmZ7Q31ee1xmcmFjezF9ezJ9fSleNCArIChcbWF0aGJme0N9XntcZnJhY3sxfXsyfX1cbWF0aGJme1J9XG1hdGhiZntDfV57XGZyYWN7MX17Mn19KV42IAogICAgICAgICAgICYgKFxtYXRoYmZ7Q31ee1xmcmFjezF9ezJ9fVxtYXRoYmZ7Un1cbWF0aGJme0N9XntcZnJhY3sxfXsyfX0pXjMgKyAoXG1hdGhiZntDfV57XGZyYWN7MX17Mn19XG1hdGhiZntSfVxtYXRoYmZ7Q31ee1xmcmFjezF9ezJ9fSleNSAKICAgICAgICAgICAmIChcbWF0aGJme0N9XntcZnJhY3sxfXsyfX1cbWF0aGJme1J9XG1hdGhiZntDfV57XGZyYWN7MX17Mn19KV40IFxcWzFtbV0KXG1hdGhiZnswfSAmIChcbWF0aGJme0N9XntcZnJhY3sxfXsyfX1cbWF0aGJme1J9XG1hdGhiZntDfV57XGZyYWN7MX17Mn19KV4zICsgKFxtYXRoYmZ7Q31ee1xmcmFjezF9ezJ9fVxtYXRoYmZ7Un1cbWF0aGJme0N9XntcZnJhY3sxfXsyfX0pXjUgCiAgICAgICAgICAgJiAoXG1hdGhiZntDfV57XGZyYWN7MX17Mn19XG1hdGhiZntSfVxtYXRoYmZ7Q31ee1xmcmFjezF9ezJ9fSleMiArIChcbWF0aGJme0N9XntcZnJhY3sxfXsyfX1cbWF0aGJme1J9XG1hdGhiZntDfV57XGZyYWN7MX17Mn19KV40IAogICAgICAgICAgICYgKFxtYXRoYmZ7Q31ee1xmcmFjezF9ezJ9fVxtYXRoYmZ7Un1cbWF0aGJme0N9XntcZnJhY3sxfXsyfX0pXjMgXFxbMW1tXQpcbWF0aGJmezB9ICYgKFxtYXRoYmZ7Q31ee1xmcmFjezF9ezJ9fVxtYXRoYmZ7Un1cbWF0aGJme0N9XntcZnJhY3sxfXsyfX0pXjQgCiAgICAgICAgICAgJiAoXG1hdGhiZntDfV57XGZyYWN7MX17Mn19XG1hdGhiZntSfVxtYXRoYmZ7Q31ee1xmcmFjezF9ezJ9fSleMyAKICAgICAgICAgICAmIChcbWF0aGJme0N9XntcZnJhY3sxfXsyfX1cbWF0aGJme1J9XG1hdGhiZntDfV57XGZyYWN7MX17Mn19KV4yIFxcWzFtbV0KXG1hdGhiZnswfSAmIFxtYXRoYmZ7MH0gCiAgICAgICAgICAgJiBcbWF0aGJmezB9IAogICAgICAgICAgICYgXG1hdGhiZnswfQpcZW5ke2JtYXRyaXh9ClxlbmR7YWxpZ259CkluIGdlbmVyYWwsClxiZWdpbnthbGlnbn0KXGJvbGRzeW1ib2x7XG1hdGhmcmFre0J9fSA9ICBcdGF1XjIKXGJlZ2lue2JtYXRyaXh9CiBcbWF0aGJmezB9ICYgXGJvbGRzeW1ib2x7XGhhdHtcbWF0aGZyYWt7Qn19fSBcXFsxbW1dCiBcbWF0aGJmezB9ICYgXG1hdGhiZnswfSAKXGVuZHtibWF0cml4fSxccXVhZCAKXGJvbGRzeW1ib2x7XGhhdHtcbWF0aGZyYWt7Qn19fSA9IFxtYXRoYmZ7Q31fe059XntcZnJhY3sxfXsyfX1cYm9sZHN5bWJvbHtcaGF0e1xtYXRoZnJha3tMfX19XG1hdGhiZntDfV97Tn1eey1cZnJhY3sxfXsyfX0gPSAKIFxiZWdpbntibWF0cml4fQpcc3VtX3trPTF9XntOfShcbWF0aGJme0N9XntcZnJhY3sxfXsyfX1cbWF0aGJme1J9XG1hdGhiZntDfV57XGZyYWN7MX17Mn19KV57MmsrKE4tTil9ICAgJiBcY2RvdHMgICYgXHN1bV97az0xfV57M30oXG1hdGhiZntDfV57XGZyYWN7MX17Mn19XG1hdGhiZntSfVxtYXRoYmZ7Q31ee1xmcmFjezF9ezJ9fSleezJrKyhOLTMpfSAmIFxzdW1fe2s9MX1eezJ9KFxtYXRoYmZ7Q31ee1xmcmFjezF9ezJ9fVxtYXRoYmZ7Un1cbWF0aGJme0N9XntcZnJhY3sxfXsyfX0pXnsyaysoTi0yKX0gICYgXHN1bV97az0xfV57MX0oXG1hdGhiZntDfV57XGZyYWN7MX17Mn19XG1hdGhiZntSfVxtYXRoYmZ7Q31ee1xmcmFjezF9ezJ9fSleezJrKyhOLTEpfSAgXFxbMW1tXQpcdmRvdHMgJiBcZGRvdHMgJiBcdmRvdHMgJiBcdmRvdHMgJiBcdmRvdHMgIFxcWzFtbV0KXHN1bV97az0xfV57M30oXG1hdGhiZntDfV57XGZyYWN7MX17Mn19XG1hdGhiZntSfVxtYXRoYmZ7Q31ee1xmcmFjezF9ezJ9fSleezJrKyhOLTMpfSAmIFxjZG90cyAmIFxzdW1fe2s9MX1eezN9KFxtYXRoYmZ7Q31ee1xmcmFjezF9ezJ9fVxtYXRoYmZ7Un1cbWF0aGJme0N9XntcZnJhY3sxfXsyfX0pXnsya30gICYgXHN1bV97az0xfV57Mn0oXG1hdGhiZntDfV57XGZyYWN7MX17Mn19XG1hdGhiZntSfVxtYXRoYmZ7Q31ee1xmcmFjezF9ezJ9fSleezJrKzF9ICAmIFxzdW1fe2s9MX1eezF9KFxtYXRoYmZ7Q31ee1xmcmFjezF9ezJ9fVxtYXRoYmZ7Un1cbWF0aGJme0N9XntcZnJhY3sxfXsyfX0pXnsyaysyfSBcXFsxbW1dClxzdW1fe2s9MX1eezJ9KFxtYXRoYmZ7Q31ee1xmcmFjezF9ezJ9fVxtYXRoYmZ7Un1cbWF0aGJme0N9XntcZnJhY3sxfXsyfX0pXnsyaysoTi0yKX0gICAgJiBcY2RvdHMgJiBcc3VtX3trPTF9XnsyfShcbWF0aGJme0N9XntcZnJhY3sxfXsyfX1cbWF0aGJme1J9XG1hdGhiZntDfV57XGZyYWN7MX17Mn19KV57MmsrMX0gICYgXHN1bV97az0xfV57Mn0oXG1hdGhiZntDfV57XGZyYWN7MX17Mn19XG1hdGhiZntSfVxtYXRoYmZ7Q31ee1xmcmFjezF9ezJ9fSleezJrfSAgJiBcc3VtX3trPTF9XnsxfShcbWF0aGJme0N9XntcZnJhY3sxfXsyfX1cbWF0aGJme1J9XG1hdGhiZntDfV57XGZyYWN7MX17Mn19KV57MmsrMX0gXFxbMW1tXQpcc3VtX3trPTF9XnsxfShcbWF0aGJme0N9XntcZnJhY3sxfXsyfX1cbWF0aGJme1J9XG1hdGhiZntDfV57XGZyYWN7MX17Mn19KV57MmsrKE4tMSl9ICAgJiBcY2RvdHMgICYgXHN1bV97az0xfV57MX0oXG1hdGhiZntDfV57XGZyYWN7MX17Mn19XG1hdGhiZntSfVxtYXRoYmZ7Q31ee1xmcmFjezF9ezJ9fSleezJrKzJ9ICAgJiBcc3VtX3trPTF9XnsxfShcbWF0aGJme0N9XntcZnJhY3sxfXsyfX1cbWF0aGJme1J9XG1hdGhiZntDfV57XGZyYWN7MX17Mn19KV57MmsrMX0gICYgXHN1bV97az0xfV57MX0oXG1hdGhiZntDfV57XGZyYWN7MX17Mn19XG1hdGhiZntSfVxtYXRoYmZ7Q31ee1xmcmFjezF9ezJ9fSleezJrfSAKXGVuZHtibWF0cml4fQpcZW5ke2FsaWdufQoKCgpCeSBsZXR0aW5nICRcbWF0aGJme1xPbWVnYX0gPSBcbWF0aGJme0N9XntcZnJhY3sxfXsyfX1cbWF0aGJme1J9XG1hdGhiZntDfV57XGZyYWN7MX17Mn19JCwgd2UgY2FuIHdyaXRlClxiZWdpbnthbGlnbn0KXGxhYmVse21hdHJpeEJ9Clx0YWd7MjN9Clxib2xkc3ltYm9se1xtYXRoZnJha3tCfX0gID0gXHRhdV4yClxiZWdpbntibWF0cml4fQpcbWF0aGJmezB9ICYgXG1hdGhiZntcT21lZ2F9XjIgKyBcbWF0aGJme1xPbWVnYX1eNCArIFxtYXRoYmZ7XE9tZWdhfV42IAogICAgICAgICAgICYgXG1hdGhiZntcT21lZ2F9XjMgKyBcbWF0aGJme1xPbWVnYX1eNSAKICAgICAgICAgICAmIFxtYXRoYmZ7XE9tZWdhfV40IFxcWzFtbV0KXG1hdGhiZnswfSAmIFxtYXRoYmZ7XE9tZWdhfV4zICsgXG1hdGhiZntcT21lZ2F9XjUgCiAgICAgICAgICAgJiBcbWF0aGJme1xPbWVnYX1eMiArIFxtYXRoYmZ7XE9tZWdhfV40IAogICAgICAgICAgICYgXG1hdGhiZntcT21lZ2F9XjMgXFxbMW1tXQpcbWF0aGJmezB9ICYgXG1hdGhiZntcT21lZ2F9XjQgCiAgICAgICAgICAgJiBcbWF0aGJme1xPbWVnYX1eMyAKICAgICAgICAgICAmIFxtYXRoYmZ7XE9tZWdhfV4yIFxcWzFtbV0KXG1hdGhiZnswfSAmIFxtYXRoYmZ7MH0gCiAgICAgICAgICAgJiBcbWF0aGJmezB9IAogICAgICAgICAgICYgXG1hdGhiZnswfQpcZW5ke2JtYXRyaXh9ID0gClx0YXVeMgpcYmVnaW57Ym1hdHJpeH0KIFxtYXRoYmZ7MH0gJiBcYm9sZHN5bWJvbHtcaGF0e1xtYXRoZnJha3tCfX19IFxcWzFtbV0KIFxtYXRoYmZ7MH0gJiBcbWF0aGJmezB9IApcZW5ke2JtYXRyaXh9LFxxdWFkClxib2xkc3ltYm9se1xoYXR7XG1hdGhmcmFre0J9fX0gPSBcYmVnaW57Ym1hdHJpeH0KIFxtYXRoYmZ7XE9tZWdhfV4yICsgXG1hdGhiZntcT21lZ2F9XjQgKyBcbWF0aGJme1xPbWVnYX1eNiAKICAgICAgICAgICAmIFxtYXRoYmZ7XE9tZWdhfV4zICsgXG1hdGhiZntcT21lZ2F9XjUgCiAgICAgICAgICAgJiBcbWF0aGJme1xPbWVnYX1eNCBcXFsxbW1dCiBcbWF0aGJme1xPbWVnYX1eMyArIFxtYXRoYmZ7XE9tZWdhfV41IAogICAgICAgICAgICYgXG1hdGhiZntcT21lZ2F9XjIgKyBcbWF0aGJme1xPbWVnYX1eNCAKICAgICAgICAgICAmIFxtYXRoYmZ7XE9tZWdhfV4zIFxcWzFtbV0KIFxtYXRoYmZ7XE9tZWdhfV40IAogICAgICAgICAgICYgXG1hdGhiZntcT21lZ2F9XjMgCiAgICAgICAgICAgJiBcbWF0aGJme1xPbWVnYX1eMiAKXGVuZHtibWF0cml4fQpcZW5ke2FsaWdufQpJbiBnZW5lcmFsLApcYmVnaW57YWxpZ259Clxib2xkc3ltYm9se1xtYXRoZnJha3tCfX0gPSAgXHRhdV4yClxiZWdpbntibWF0cml4fQogXG1hdGhiZnswfSAmIFxib2xkc3ltYm9se1xoYXR7XG1hdGhmcmFre0J9fX0gXFxbMW1tXQogXG1hdGhiZnswfSAmIFxtYXRoYmZ7MH0gClxlbmR7Ym1hdHJpeH0sXHF1YWQgClxib2xkc3ltYm9se1xoYXR7XG1hdGhmcmFre0J9fX0gPSBcbWF0aGJme0N9X3tOfV57XGZyYWN7MX17Mn19XGJvbGRzeW1ib2x7XGhhdHtcbWF0aGZyYWt7TH19fVxtYXRoYmZ7Q31fe059XnstXGZyYWN7MX17Mn19ID0gCiBcYmVnaW57Ym1hdHJpeH0KXHN1bV97az0xfV57Tn1cbWF0aGJme1xPbWVnYX1eezJrKyhOLU4pfSAgICYgXGNkb3RzICAmIFxzdW1fe2s9MX1eezN9XG1hdGhiZntcT21lZ2F9XnsyaysoTi0zKX0gJiBcc3VtX3trPTF9XnsyfVxtYXRoYmZ7XE9tZWdhfV57MmsrKE4tMil9ICAmIFxzdW1fe2s9MX1eezF9XG1hdGhiZntcT21lZ2F9XnsyaysoTi0xKX0gIFxcWzFtbV0KXHZkb3RzICYgXGRkb3RzICYgXHZkb3RzICYgXHZkb3RzICYgXHZkb3RzICBcXFsxbW1dClxzdW1fe2s9MX1eezN9XG1hdGhiZntcT21lZ2F9XnsyaysoTi0zKX0gJiBcY2RvdHMgJiBcc3VtX3trPTF9XnszfVxtYXRoYmZ7XE9tZWdhfV57Mmt9ICAmIFxzdW1fe2s9MX1eezJ9XG1hdGhiZntcT21lZ2F9XnsyaysxfSAgJiBcc3VtX3trPTF9XnsxfVxtYXRoYmZ7XE9tZWdhfV57MmsrMn0gXFxbMW1tXQpcc3VtX3trPTF9XnsyfVxtYXRoYmZ7XE9tZWdhfV57MmsrKE4tMil9ICAgICYgXGNkb3RzICYgXHN1bV97az0xfV57Mn1cbWF0aGJme1xPbWVnYX1eezJrKzF9ICAmIFxzdW1fe2s9MX1eezJ9XG1hdGhiZntcT21lZ2F9Xnsya30gICYgXHN1bV97az0xfV57MX1cbWF0aGJme1xPbWVnYX1eezJrKzF9IFxcWzFtbV0KXHN1bV97az0xfV57MX1cbWF0aGJme1xPbWVnYX1eezJrKyhOLTEpfSAgICYgXGNkb3RzICAmIFxzdW1fe2s9MX1eezF9XG1hdGhiZntcT21lZ2F9XnsyaysyfSAgICYgXHN1bV97az0xfV57MX1cbWF0aGJme1xPbWVnYX1eezJrKzF9ICAmIFxzdW1fe2s9MX1eezF9XG1hdGhiZntcT21lZ2F9Xnsya30gClxlbmR7Ym1hdHJpeH0KXGVuZHthbGlnbn0KCk5vdGUgdGhhdApcYmVnaW57YWxpZ259Clxib2xkc3ltYm9se1xtYXRoZnJha3tCfX0gXG1hdGhiZntcaGF0e0p9fV97TisxfSA9IFxiZWdpbntibWF0cml4fQogXGJvbGRzeW1ib2x7XGhhdHtcbWF0aGZyYWt7Qn19fVxtYXRoYmZ7XGhhdHtKfX1fe059ICYgXG1hdGhiZnswfSBcXFsxbW1dCiBcbWF0aGJmezB9ICYgXG1hdGhiZnswfSAKXGVuZHtibWF0cml4fQpcZW5ke2FsaWdufQoKSGVuY2UKClxiZWdpbnthbGlnbn0KXGxhYmVse2NoYWluMX0KICAgIFx8XGJvbGRzeW1ib2x7XG1hdGhmcmFre0x9fVx8X3tcbWF0aGJme0N9X3tOKzF9fSAgPSBcfFxib2xkc3ltYm9se1xtYXRoZnJha3tCfX1cfF8yPSBcfFxib2xkc3ltYm9se1xtYXRoZnJha3tCfX0gXG1hdGhiZntcaGF0e0p9fV97TisxfSBcfF8yPSBcdGF1XjIgIFx8IFxiZWdpbntibWF0cml4fQogXGJvbGRzeW1ib2x7XGhhdHtcbWF0aGZyYWt7Qn19fVxtYXRoYmZ7XGhhdHtKfX1fe059ICYgXG1hdGhiZnswfSBcXFsxbW1dCiBcbWF0aGJmezB9ICYgXG1hdGhiZnswfSAKXGVuZHtibWF0cml4fVx8XzIgID0gXHRhdV4yICBcfFxib2xkc3ltYm9se1xoYXR7XG1hdGhmcmFre0J9fX1cbWF0aGJme1xoYXR7Sn19X3tOfSBcfF8yID0gXHRhdV4yICBcfFxib2xkc3ltYm9se1xoYXR7XG1hdGhmcmFre0J9fX1cfF8yClxlbmR7YWxpZ259CgoKV2UgaGF2ZSB0aGF0ICRcbWF0aGJme1F9Xlx0b3BcYm9sZHN5bWJvbHtcT21lZ2F9XmtcbWF0aGJme1F9ICA9ICBcYm9sZHN5bWJvbHtcRGVsdGF9XmskLiBMZXQgJFxtYXRoYmZ7Vn0gPSBcbWF0aGJme0l9X3tOfVxvdGltZXMgIFxtYXRoYmZ7UX0kLiBCeSAsICAkXG1hdGhiZntWfSQgaXMgb3J0aG9nb25hbCBhbmQKXGJlZ2lue2FsaWduKn0KXG1hdGhiZntWfV5cdG9wIFxib2xkc3ltYm9se1xoYXR7XG1hdGhmcmFre0J9fX0gXG1hdGhiZntWfSA9IApcYmVnaW57Ym1hdHJpeH0KIFxtYXRoYmZ7XERlbHRhfV4yICsgXG1hdGhiZntcRGVsdGF9XjQgKyBcbWF0aGJme1xEZWx0YX1eNiAKICAgICAgICAgICAmIFxtYXRoYmZ7XERlbHRhfV4zICsgXG1hdGhiZntcRGVsdGF9XjUgCiAgICAgICAgICAgJiBcbWF0aGJme1xEZWx0YX1eNCBcXFsxbW1dCiBcbWF0aGJme1xEZWx0YX1eMyArIFxtYXRoYmZ7XERlbHRhfV41IAogICAgICAgICAgICYgXG1hdGhiZntcRGVsdGF9XjIgKyBcbWF0aGJme1xEZWx0YX1eNCAKICAgICAgICAgICAmIFxtYXRoYmZ7XERlbHRhfV4zIFxcWzFtbV0KIFxtYXRoYmZ7XERlbHRhfV40IAogICAgICAgICAgICYgXG1hdGhiZntcRGVsdGF9XjMgCiAgICAgICAgICAgJiBcbWF0aGJme1xEZWx0YX1eMiAKXGVuZHtibWF0cml4fQpcZW5ke2FsaWduKn0KSW4gZ2VuZXJhbCwKXGJlZ2lue2FsaWduKn0KXG1hdGhiZntWfV5cdG9wIFxib2xkc3ltYm9se1xoYXR7XG1hdGhmcmFre0J9fX0gXG1hdGhiZntWfSA9IAogXGJlZ2lue2JtYXRyaXh9ClxzdW1fe2s9MX1ee059XG1hdGhiZntcRGVsdGF9XnsyaysoTi1OKX0gICAmIFxjZG90cyAgJiBcc3VtX3trPTF9XnszfVxtYXRoYmZ7XERlbHRhfV57MmsrKE4tMyl9ICYgXHN1bV97az0xfV57Mn1cbWF0aGJme1xEZWx0YX1eezJrKyhOLTIpfSAgJiBcc3VtX3trPTF9XnsxfVxtYXRoYmZ7XERlbHRhfV57MmsrKE4tMSl9ICBcXFsxbW1dClx2ZG90cyAmIFxkZG90cyAmIFx2ZG90cyAmIFx2ZG90cyAmIFx2ZG90cyAgXFxbMW1tXQpcc3VtX3trPTF9XnszfVxtYXRoYmZ7XERlbHRhfV57MmsrKE4tMyl9ICYgXGNkb3RzICYgXHN1bV97az0xfV57M31cbWF0aGJme1xEZWx0YX1eezJrfSAgJiBcc3VtX3trPTF9XnsyfVxtYXRoYmZ7XERlbHRhfV57MmsrMX0gICYgXHN1bV97az0xfV57MX1cbWF0aGJme1xEZWx0YX1eezJrKzJ9IFxcWzFtbV0KXHN1bV97az0xfV57Mn1cbWF0aGJme1xEZWx0YX1eezJrKyhOLTIpfSAgICAmIFxjZG90cyAmIFxzdW1fe2s9MX1eezJ9XG1hdGhiZntcRGVsdGF9XnsyaysxfSAgJiBcc3VtX3trPTF9XnsyfVxtYXRoYmZ7XERlbHRhfV57Mmt9ICAmIFxzdW1fe2s9MX1eezF9XG1hdGhiZntcRGVsdGF9XnsyaysxfSBcXFsxbW1dClxzdW1fe2s9MX1eezF9XG1hdGhiZntcRGVsdGF9XnsyaysoTi0xKX0gICAmIFxjZG90cyAgJiBcc3VtX3trPTF9XnsxfVxtYXRoYmZ7XERlbHRhfV57MmsrMn0gICAmIFxzdW1fe2s9MX1eezF9XG1hdGhiZntcRGVsdGF9XnsyaysxfSAgJiBcc3VtX3trPTF9XnsxfVxtYXRoYmZ7XERlbHRhfV57Mmt9IApcZW5ke2JtYXRyaXh9ClxlbmR7YWxpZ24qfQpGb3IgZXhhbXBsZSwgaWYgJFxtYXRoYmZ7XERlbHRhfSA9IFx0ZXh0e2RpYWd9KFxtdV8xLCBcbXVfMixcbXVfMykkLCB0aGVuClxiZWdpbnthbGlnbn0KXG1hdGhiZntWfV5cdG9wIFxib2xkc3ltYm9se1xoYXR7XG1hdGhmcmFre0J9fX0gXG1hdGhiZntWfSA9ClxiZWdpbntibWF0cml4fQpcbXVfMV4yK1xtdV8xXjQrXG11XzFeNiAmIDAgJiAwICYgXG11XzFeMytcbXVfMV41ICYgMCAmIDAgJiBcbXVfMV40ICYgMCAmIDAgXFxbMW1tXQowICYgXG11XzJeMitcbXVfMl40K1xtdV8yXjYgJiAwICYgMCAmIFxtdV8yXjMrXG11XzJeNSAmIDAgJiAwICYgXG11XzJeNCAmIDAgXFxbMW1tXQowICYgMCAmIFxtdV8zXjIrXG11XzNeNCtcbXVfM142ICYgMCAmIDAgJiBcbXVfM14zK1xtdV8zXjUgJiAwICYgMCAmIFxtdV8zXjQgXFxbMm1tXQpcbXVfMV4zK1xtdV8xXjUgJiAwICYgMCAmIFxtdV8xXjIrXG11XzFeNCAmIDAgJiAwICYgXG11XzFeMyAmIDAgJiAwIFxcWzFtbV0KMCAmIFxtdV8yXjMrXG11XzJeNSAmIDAgJiAwICYgXG11XzJeMitcbXVfMl40ICYgMCAmIDAgJiBcbXVfMl4zICYgMCBcXFsxbW1dCjAgJiAwICYgXG11XzNeMytcbXVfM141ICYgMCAmIDAgJiBcbXVfM14yK1xtdV8zXjQgJiAwICYgMCAmIFxtdV8zXjMgXFxbMm1tXQpcbXVfMV40ICYgMCAmIDAgJiBcbXVfMV4zICYgMCAmIDAgJiBcbXVfMV4yICYgMCAmIDAgXFxbMW1tXQowICYgXG11XzJeNCAmIDAgJiAwICYgXG11XzJeMyAmIDAgJiAwICYgXG11XzJeMiAmIDAgXFxbMW1tXQowICYgMCAmIFxtdV8zXjQgJiAwICYgMCAmIFxtdV8zXjMgJiAwICYgMCAmIFxtdV8zXjIKXGVuZHtibWF0cml4fQpcZW5ke2FsaWdufQpJZiAKXGJlZ2lue2FsaWdufQpcbWF0aGJme1B9ID0KXGJlZ2lue2JtYXRyaXh9CjEgJiAwICYgMCAmIDAgJiAwICYgMCAmIDAgJiAwICYgMCBcXFsxbW1dCjAgJiAwICYgMCAmIDEgJiAwICYgMCAmIDAgJiAwICYgMCBcXFsxbW1dCjAgJiAwICYgMCAmIDAgJiAwICYgMCAmIDEgJiAwICYgMCBcXFsxbW1dCjAgJiAxICYgMCAmIDAgJiAwICYgMCAmIDAgJiAwICYgMCBcXFsxbW1dCjAgJiAwICYgMCAmIDAgJiAxICYgMCAmIDAgJiAwICYgMCBcXFsxbW1dCjAgJiAwICYgMCAmIDAgJiAwICYgMCAmIDAgJiAxICYgMCBcXFsxbW1dCjAgJiAwICYgMSAmIDAgJiAwICYgMCAmIDAgJiAwICYgMCBcXFsxbW1dCjAgJiAwICYgMCAmIDAgJiAwICYgMSAmIDAgJiAwICYgMCBcXFsxbW1dCjAgJiAwICYgMCAmIDAgJiAwICYgMCAmIDAgJiAwICYgMQpcZW5ke2JtYXRyaXh9ClxlbmR7YWxpZ259CnRoZW4KXGJlZ2lue2FsaWdufQpcbWF0aGJme1B9XG1hdGhiZntWfV5cdG9wIFxib2xkc3ltYm9se1xoYXR7XG1hdGhmcmFre0J9fX0gXG1hdGhiZntWfVxtYXRoYmZ7UH1eXHRvcCA9IApcYmVnaW57Ym1hdHJpeH0KXG11XzFeMitcbXVfMV40K1xtdV8xXjYgJiBcbXVfMV4zK1xtdV8xXjUgJiBcbXVfMV40ICYgMCAmIDAgJiAwICYgMCAmIDAgJiAwIFxcWzFtbV0KXG11XzFeMytcbXVfMV41ICYgXG11XzFeMitcbXVfMV40ICYgXG11XzFeMyAmIDAgJiAwICYgMCAmIDAgJiAwICYgMCBcXFsxbW1dClxtdV8xXjQgJiBcbXVfMV4zICYgXG11XzFeMiAmIDAgJiAwICYgMCAmIDAgJiAwICYgMCBcXFsybW1dCjAgJiAwICYgMCAmIFxtdV8yXjIrXG11XzJeNCtcbXVfMl42ICYgXG11XzJeMytcbXVfMl41ICYgXG11XzJeNCAmIDAgJiAwICYgMCBcXFsxbW1dCjAgJiAwICYgMCAmIFxtdV8yXjMrXG11XzJeNSAmIFxtdV8yXjIrXG11XzJeNCAmIFxtdV8yXjMgJiAwICYgMCAmIDAgXFxbMW1tXQowICYgMCAmIDAgJiBcbXVfMl40ICYgXG11XzJeMyAmIFxtdV8yXjIgJiAwICYgMCAmIDAgXFxbMm1tXQowICYgMCAmIDAgJiAwICYgMCAmIDAgJiBcbXVfM14yK1xtdV8zXjQrXG11XzNeNiAmIFxtdV8zXjMrXG11XzNeNSAmIFxtdV8zXjQgXFxbMW1tXQowICYgMCAmIDAgJiAwICYgMCAmIDAgJiBcbXVfM14zK1xtdV8zXjUgJiBcbXVfM14yK1xtdV8zXjQgJiBcbXVfM14zIFxcWzFtbV0KMCAmIDAgJiAwICYgMCAmIDAgJiAwICYgXG11XzNeNCAmIFxtdV8zXjMgJiBcbXVfM14yClxlbmR7Ym1hdHJpeH0KXGVuZHthbGlnbn0KClRoZSBjb2RlIGJlbG93IHNob3dzIG1hdHJpeCBob3cgdG8gYnVpbGQgbWF0cml4ICRcbWF0aGJme1Z9Xlx0b3AgXGJvbGRzeW1ib2x7XGhhdHtcbWF0aGZyYWt7Qn19fSBcbWF0aGJme1Z9JCBhbmQgJFxtYXRoYmZ7UH0kIGFuZCB2ZXJpZmllcyB0aGF0ICRcbWF0aGJme1B9XG1hdGhiZntWfV5cdG9wIFxib2xkc3ltYm9se1xoYXR7XG1hdGhmcmFre0J9fX0gXG1hdGhiZntWfVxtYXRoYmZ7UH1eXHRvcCQgaXMgYmxvY2sgZGlhZ29uYWwgd2l0aCBibG9ja3MgJFxtYXRoYmZ7VH0oXG11X2kpJC4KCmBgYHtyLCBwdXJsID0gRkFMU0V9Cm1ha2VfbWF0cml4IDwtIGZ1bmN0aW9uKGEsIE4pIHsKICB2IDwtIGFeKDA6KE4gLSAxKSkKICB0b2VwbGl0eih2KQp9CmJ1aWxkX1RfZmFzdCA8LSBmdW5jdGlvbihhLCBOKSB7CiAgTSA8LSBtYWtlX21hdHJpeChhLCBOKQogIFIgPC0gbWF0cml4KDAsIE4sIE4pCiAgY29lZiA8LSAoYV4yKV4oMTpOKSAgIyBjb3JyZWN0IHBvd2VyIG9yZGVyCiAgZm9yIChrIGluIE46MSkgewogICAgUlsxOmssIDE6a10gPC0gUlsxOmssIDE6a10gKyBjb2VmW04gLSBrICsgMV0gKiBNWzE6aywgMTprXQogIH0KICBSCn0KYnVpbGRfYmxvY2tfbWF0cml4IDwtIGZ1bmN0aW9uKGVncywgTmgpIHsKICBOIDwtIGxlbmd0aChlZ3MpCiAgIyB0b3RhbCBzaXplCiAgbSA8LSBOICogTmgKICBBQSA8LSBtYXRyaXgoMCwgbnJvdyA9IG0sIG5jb2wgPSBtKQogIGZvciAoaiBpbiAxOk4pIHsKICAgIHJvd3MgPC0gKChqIC0gMSkgKiBOaCArIDEpOihqICogTmgpCiAgICBjb2xzIDwtICgoaiAtIDEpICogTmggKyAxKTooaiAqIE5oKQogICAgQUFbcm93cywgY29sc10gPC0gYnVpbGRfVF9mYXN0KGVnc1tqXSwgTmgpCiAgfQogIHJldHVybihBQSkKfQpidWlsZF9wZXJtX21hdHJpeF9nZW5lcmFsIDwtIGZ1bmN0aW9uKE4sIE5oKSB7CiAgbSA8LSBOICogTmgKICAjIHRhcmdldCBpbmRpY2VzCiAgcGVybSA8LSBhcy52ZWN0b3Ioc2FwcGx5KDE6TmgsIGZ1bmN0aW9uKGkpIGkgKyBOaCooMDooTi0xKSkpKQogIFAgPC0gZGlhZyhtKVtwZXJtLCBdCiAgcmV0dXJuKFApCn0KTmggPC0gMwplZ3MgPC0gYygxLDMsNSkKUCA8LSBidWlsZF9wZXJtX21hdHJpeF9nZW5lcmFsKGxlbmd0aChlZ3MpLCBOaCkKUAphdXggPC0gYnVpbGRfYmxvY2tfbWF0cml4KGVncywgTmgpCnRWaGF0QlYgPC0gdChQKSAlKiUgYXV4ICUqJSBQCnRWaGF0QlYKUHRWaGF0QlZ0UCA8LSBQICUqJSB0VmhhdEJWICUqJSB0KFApClB0VmhhdEJWdFAKYGBgCgpUaGF0IGlzLCBpbiBnZW5lcmFsLApcYmVnaW57YWxpZ24qfQogICAgXG1hdGhiZntQfVxtYXRoYmZ7Vn1eXHRvcCBcYm9sZHN5bWJvbHtcaGF0e1xtYXRoZnJha3tCfX19XG1hdGhiZntWfVxtYXRoYmZ7UH1eXHRvcCA9IFx0ZXh0e2Jsa2RpYWd9KFxtYXRoYmZ7VH0oXG11XzEpLCBcbWF0aGJme1R9KFxtdV8yKSwgXGRvdHMsIFxtYXRoYmZ7VH0oXG11X3tOX2h9KSksClxlbmR7YWxpZ24qfQp3aGVyZQpcYmVnaW57YWxpZ259ClxtYXRoYmZ7VH0oXG11X2kpID0gCiBcYmVnaW57Ym1hdHJpeH0KXHN1bV97az0xfV57Tn1cbXVfaV57MmsrKE4tTil9ICAgJiBcY2RvdHMgICYgXHN1bV97az0xfV57M31cbXVfaV57MmsrKE4tMyl9ICYgXHN1bV97az0xfV57Mn1cbXVfaV57MmsrKE4tMil9ICAmIFxzdW1fe2s9MX1eezF9XG11X2leezJrKyhOLTEpfSAgXFxbMW1tXQpcdmRvdHMgJiBcZGRvdHMgJiBcdmRvdHMgJiBcdmRvdHMgJiBcdmRvdHMgIFxcWzFtbV0KXHN1bV97az0xfV57M31cbXVfaV57MmsrKE4tMyl9ICYgXGNkb3RzICYgXHN1bV97az0xfV57M31cbXVfaV57Mmt9ICAmIFxzdW1fe2s9MX1eezJ9XG11X2leezJrKzF9ICAmIFxzdW1fe2s9MX1eezF9XG11X2leezJrKzJ9IFxcWzFtbV0KXHN1bV97az0xfV57Mn1cbXVfaV57MmsrKE4tMil9ICAgICYgXGNkb3RzICYgXHN1bV97az0xfV57Mn1cbXVfaV57MmsrMX0gICYgXHN1bV97az0xfV57Mn1cbXVfaV57Mmt9ICAmIFxzdW1fe2s9MX1eezF9XG11X2leezJrKzF9IFxcWzFtbV0KXHN1bV97az0xfV57MX1cbXVfaV57MmsrKE4tMSl9ICAgJiBcY2RvdHMgICYgXHN1bV97az0xfV57MX1cbXVfaV57MmsrMn0gICAmIFxzdW1fe2s9MX1eezF9XG11X2leezJrKzF9ICAmIFxzdW1fe2s9MX1eezF9XG11X2leezJrfSAKXGVuZHtibWF0cml4fQpcZW5ke2FsaWdufQpMZXQgJFxtYXRoYmZ7VH0gPSBcbWF0aGJme1R9KFxvbWVnYSkkLiBUaGF0IGlzLApcYmVnaW57YWxpZ259ClxsYWJlbHttYXRyaXhUfQpcdGFnezI0fQpcbWF0aGJme1R9ID0gXG1hdGhiZntUfShcb21lZ2EpID0gCiBcYmVnaW57Ym1hdHJpeH0KXHN1bV97az0xfV57Tn1cb21lZ2FeezJrKyhOLU4pfSAgICYgXGNkb3RzICAmIFxzdW1fe2s9MX1eezN9XG9tZWdhXnsyaysoTi0zKX0gJiBcc3VtX3trPTF9XnsyfVxvbWVnYV57MmsrKE4tMil9ICAmIFxzdW1fe2s9MX1eezF9XG9tZWdhXnsyaysoTi0xKX0gIFxcWzFtbV0KXHZkb3RzICYgXGRkb3RzICYgXHZkb3RzICYgXHZkb3RzICYgXHZkb3RzICBcXFsxbW1dClxzdW1fe2s9MX1eezN9XG9tZWdhXnsyaysoTi0zKX0gJiBcY2RvdHMgJiBcc3VtX3trPTF9XnszfVxvbWVnYV57Mmt9ICAmIFxzdW1fe2s9MX1eezJ9XG9tZWdhXnsyaysxfSAgJiBcc3VtX3trPTF9XnsxfVxvbWVnYV57MmsrMn0gXFxbMW1tXQpcc3VtX3trPTF9XnsyfVxvbWVnYV57MmsrKE4tMil9ICAgICYgXGNkb3RzICYgXHN1bV97az0xfV57Mn1cb21lZ2FeezJrKzF9ICAmIFxzdW1fe2s9MX1eezJ9XG9tZWdhXnsya30gICYgXHN1bV97az0xfV57MX1cb21lZ2FeezJrKzF9IFxcWzFtbV0KXHN1bV97az0xfV57MX1cb21lZ2FeezJrKyhOLTEpfSAgICYgXGNkb3RzICAmIFxzdW1fe2s9MX1eezF9XG9tZWdhXnsyaysyfSAgICYgXHN1bV97az0xfV57MX1cb21lZ2FeezJrKzF9ICAmIFxzdW1fe2s9MX1eezF9XG9tZWdhXnsya30gClxlbmR7Ym1hdHJpeH0KXGVuZHthbGlnbn0KVGhlbgpcYmVnaW57YWxpZ259ClxsYWJlbHtjaGFpbjJ9CiAgICBcfFxib2xkc3ltYm9se1xtYXRoZnJha3tMfX1cfF97XG1hdGhiZntDfV97TisxfX0gICA9IFx0YXVeMgogICAgXHxcYm9sZHN5bWJvbHtcaGF0e1xtYXRoZnJha3tCfX19XHxfMiA9IFx0YXVeMgogICAgXHxcbWF0aGJme1B9XG1hdGhiZntWfV5cdG9wIFxib2xkc3ltYm9se1xoYXR7XG1hdGhmcmFre0J9fX0gXG1hdGhiZntWfVxtYXRoYmZ7UH1eXHRvcFx8XzIgPSBcdGF1XjIgXG1heF97aSA9IDEsXGRvdHMsIE5faH1cfFxtYXRoYmZ7VH0oXG11X2kpXHxfMj0gXHRhdV4yXHxcbWF0aGJme1R9KFxvbWVnYSlcfF8yPSBcdGF1XjJcfFxtYXRoYmZ7VH1cfF8yLgpcZW5ke2FsaWdufQoKVG8gc2VlIGFuIGV4YW1wbGUgd2hlcmUgd2Ugc2hvdyB0aGF0ICRcfFxib2xkc3ltYm9se1xtYXRoZnJha3tCfX1cfF8yID0gXHRhdV4yIFx8XG1hdGhiZntUfVx8XzIkLCBnbyB0byB0aGUgW3RoaXNdKGNvbnRyb2xfZnVuY3Rpb25hbGl0eS5odG1sI25vcm1faWRlbnRpdHkpIHNlY3Rpb24uCgpGb2xsb3dpbmcgd2l0aCBvdXIgZXhhbXBsZSwgd2UgaGF2ZSB0aGF0IApcYmVnaW57YWxpZ24qfQogICAgXG1hdGhiZntUfSAmID0gIApcYmVnaW57Ym1hdHJpeH0KXG9tZWdhXjIgJiBcb21lZ2FeMyAmIFxvbWVnYV40ICBcXFsxbW1dClxvbWVnYV4zJiBcb21lZ2FeMiAmIFxvbWVnYV4zICBcXFsxbW1dClxvbWVnYV40ICYgXG9tZWdhXjMgJiBcb21lZ2FeMiAgXFxbMm1tXQpcZW5ke2JtYXRyaXh9CisKXGJlZ2lue2JtYXRyaXh9ClxvbWVnYV40ICYgXG9tZWdhXjUgJiAwICBcXFsxbW1dClxvbWVnYV41ICYgXG9tZWdhXjQgJiAwICBcXFsxbW1dCjAgJiAwICYgMCAgXFxbMm1tXQpcZW5ke2JtYXRyaXh9CisgClxiZWdpbntibWF0cml4fQpcb21lZ2FeNiAmIDAgJiAwICBcXFsxbW1dCjAgJiAwICYgMCAgXFxbMW1tXQowICYgMCAmIDAgIFxcWzJtbV0KXGVuZHtibWF0cml4fQpcZW5ke2FsaWduKn0Kb3IgZXF1aXZhbGVudGx5LApcYmVnaW57YWxpZ24qfQogICAgXG1hdGhiZntUfSYgPSAKICAgIFxvbWVnYV4yIFxiZWdpbntibWF0cml4fQoxICYgXG9tZWdhICYgXG9tZWdhXjIgIFxcWzFtbV0KXG9tZWdhJiAxICYgXG9tZWdhICBcXFsxbW1dClxvbWVnYV4yICYgXG9tZWdhICYgMSAgXFxbMm1tXQpcZW5ke2JtYXRyaXh9CisKXG9tZWdhXjRcYmVnaW57Ym1hdHJpeH0KMSAmIFxvbWVnYSAmIDAgIFxcWzFtbV0KXG9tZWdhICYgMSAmIDAgIFxcWzFtbV0KMCAmIDAgJiAwICBcXFsybW1dClxlbmR7Ym1hdHJpeH0KKyAKXG9tZWdhXjZcYmVnaW57Ym1hdHJpeH0KMSAmIDAgJiAwICBcXFsxbW1dCjAgJiAwICYgMCAgXFxbMW1tXQowICYgMCAmIDAgIFxcWzJtbV0KXGVuZHtibWF0cml4fQpcXAomID0gXG9tZWdhXjIgClxiZWdpbntibWF0cml4fQoxICYgMCAmIDAgIFxcWzFtbV0KMCAmIDEgJiAwICBcXFsxbW1dCjAgJiAwICYgMSAgXFxbMm1tXQpcZW5ke2JtYXRyaXh9ClxiZWdpbntibWF0cml4fQoxICYgXG9tZWdhICYgXG9tZWdhXjIgIFxcWzFtbV0KXG9tZWdhJiAxICYgXG9tZWdhICBcXFsxbW1dClxvbWVnYV4yICYgXG9tZWdhICYgMSAgXFxbMm1tXQpcZW5ke2JtYXRyaXh9ClxiZWdpbntibWF0cml4fQoxICYgMCAmIDAgIFxcWzFtbV0KMCAmIDEgJiAwICBcXFsxbW1dCjAgJiAwICYgMSAgXFxbMm1tXQpcZW5ke2JtYXRyaXh9ClxcCiYrClxvbWVnYV40ClxiZWdpbntibWF0cml4fQoxICYgMCAmIDAgIFxcWzFtbV0KMCAmIDEgJiAwICBcXFsxbW1dCjAgJiAwICYgMCAgXFxbMm1tXQpcZW5ke2JtYXRyaXh9ClxiZWdpbntibWF0cml4fQoxICYgXG9tZWdhICYgXG9tZWdhXjIgIFxcWzFtbV0KXG9tZWdhJiAxICYgXG9tZWdhICBcXFsxbW1dClxvbWVnYV4yICYgXG9tZWdhICYgMSAgXFxbMm1tXQpcZW5ke2JtYXRyaXh9ClxiZWdpbntibWF0cml4fQoxICYgMCAmIDAgIFxcWzFtbV0KMCAmIDEgJiAwICBcXFsxbW1dCjAgJiAwICYgMCAgXFxbMm1tXQpcZW5ke2JtYXRyaXh9XFwKJisgClxvbWVnYV42ClxiZWdpbntibWF0cml4fQoxICYgMCAmIDAgIFxcWzFtbV0KMCAmIDAgJiAwICBcXFsxbW1dCjAgJiAwICYgMCAgXFxbMm1tXQpcZW5ke2JtYXRyaXh9ClxiZWdpbntibWF0cml4fQoxICYgXG9tZWdhICYgXG9tZWdhXjIgIFxcWzFtbV0KXG9tZWdhJiAxICYgXG9tZWdhICBcXFsxbW1dClxvbWVnYV4yICYgXG9tZWdhICYgMSAgXFxbMm1tXQpcZW5ke2JtYXRyaXh9ClxiZWdpbntibWF0cml4fQoxICYgMCAmIDAgIFxcWzFtbV0KMCAmIDAgJiAwICBcXFsxbW1dCjAgJiAwICYgMCAgXFxbMm1tXQpcZW5ke2JtYXRyaXh9ClxlbmR7YWxpZ24qfQoKVGhlIGNvZGUgYmVsb3cgYnVpbGRzIG1hdHJpeCAkXG1hdGhiZntUfSQgYW5kIHNob3dzIHRoZSBpbnRlcm1lZGlhdGUgc3RlcHMuCgpgYGB7ciwgcHVybCA9IEZBTFNFfQpidWlsZF9UIDwtIGZ1bmN0aW9uKGEsIE4pewogIEggPC0gbWFrZV9tYXRyaXgoYSwgTikgCiAgUiA8LSBIKjAKICBmb3IgKGkgaW4gTjoxKSB7CiAgICBLX2kgPC0gZGlhZyhjKHJlcCgxLCBpKSwgcmVwKDAsIE4gLSBpKSkpCiAgICB0ZW1wIDwtIGFeKDIqKE4gLSBpICsgMSkpICogS19pICUqJSBIICUqJSBLX2kKICAgIHByaW50KGFeKDIqKE4gLSBpICsgMSkpKQogICAgcHJpbnQoY2JpbmQocmVwKCJ8IiwgTiksIEtfaSwgcmVwKCJ8IiwgTiksIEgsIHJlcCgifCIsIE4pLCBLX2ksIHJlcCgifCIsIE4pKSwgcXVvdGUgPSBGQUxTRSkKICAgIFIgPC0gUiArIHRlbXAKICB9CiAgcmV0dXJuKFIpCn0KClRfYXV4IDwtIGJ1aWxkX1QoMiwgMykKYGBgCgoKVGhhdCBpcywgaW4gZ2VuZXJhbCwKXGJlZ2lue2FsaWduKn0KICAgIFxtYXRoYmZ7VH0gPSBcc3VtX3tpPTF9Xk4gXG9tZWdhXnsyKE4taSsxKX0gXG1hdGhiZntLfV9pXG1hdGhiZntIfVxtYXRoYmZ7S31faSwKXGVuZHthbGlnbip9CndoZXJlIApcYmVnaW57YWxpZ24qfQpcbWF0aGJme0h9ID0gXGJlZ2lue2JtYXRyaXh9CjEgJiBcb21lZ2EgJiBcb21lZ2FeMiAmIFxjZG90cyAmIFxvbWVnYV57Ti0xfSBcXApcb21lZ2EgJiAxICYgXG9tZWdhICYgXGNkb3RzICYgXG9tZWdhXntOLTJ9IFxcClxvbWVnYV4yICYgXG9tZWdhICYgMSAmIFxjZG90cyAmIFxvbWVnYV57Ti0zfSBcXApcdmRvdHMgJiBcdmRvdHMgJiBcdmRvdHMgJiBcZGRvdHMgJiBcdmRvdHMgXFwKXG9tZWdhXntOLTF9ICYgXG9tZWdhXntOLTJ9ICYgXG9tZWdhXntOLTN9ICYgXGNkb3RzICYgMQpcZW5ke2JtYXRyaXh9LFxxdWFkIApcbWF0aGJme0t9X2kgPSAKXG1hdGhybXtkaWFnfShcdW5kZXJicmFjZXsxLCBcZG90cywgMX1fe2l9LCBcdW5kZXJicmFjZXswLCBcZG90cywgMH1fe04taX0pLgpcZW5ke2FsaWduKn0KYW5kICRcbWF0aGJme0t9X2kkIHNhdGlzZmllcyAkXHxcbWF0aGJme0t9X2lcfF8yID0gMSQgZm9yIGFsbCAkaT0xLFxkb3RzLCBOJC4KCgoKCiMjIE51bWVyaWNhbCBpbXBsZW1lbnRhdGlvbiB7I251bV9pbXBsZW1lbnRhdGlvbn0KCiMjIyBGdW5jdGlvbiBgbXkuZ2V0LnJvb3RzKClgCgpGb3IgZWFjaCByYXRpb25hbCBvcmRlciAkbSQgKDEsMiwzLDQsNSw2LDcsOCkgYW5kIHNtb290aG5lc3MgcGFyYW1ldGVyICRcYmV0YSQgKD0gJFxhbHBoYS8yJCB3aXRoICRcYWxwaGEkIGJldHdlZW4gMC41IGFuZCAyKSwgZnVuY3Rpb24gYG15LmdldC5yb290cygpYCAoYWRhcHRlZCBmcm9tIHRoZSBgclNQREVgIHBhY2thZ2UpIHJldHVybnMgJFx0ZXh0dHR7ZmFjdG9yfSA9IFxkZnJhY3tjX219e2Jfe20rMX19JCwgYW5kIHRoZSByb290cyAkXHtyX3sxaX1cfV97aT0xfV5tJCBhbmQgJFx7cl97Mmp9XH1fe2o9MX1ee20rMX0kLgoKVGhlIGZpbGUgW2BkYXRhX2ZpbGVzL2NoZWJmdW5fdGFibGVzLlJEU2BdKGh0dHBzOi8vZ2l0aHViLmNvbS9sZW5pbnJhZmFlbHJpZXJhc2VndXJhL05BRkRFTUcvYmxvYi9tYWluL2RhdGFfZmlsZXMvY2hlYmZ1bl90YWJsZXMuUkRTKSBjb250YWlucyB0aGUgcHJlY29tcHV0ZWQgdGFibGVzIGZvciB0aGUgcm9vdHMgYW5kIGZhY3RvcnMgZm9yIHJhdGlvbmFsIG9yZGVycyAxIHRvIDguIFRoZXNlIHRhYmxlcyB3ZXJlIGdlbmVyYXRlZCB1c2luZyB0aGUgW2BtYXRsYWIvY2hlYmZ1bi5tYF0oaHR0cHM6Ly9naXRodWIuY29tL2xlbmlucmFmYWVscmllcmFzZWd1cmEvTkFGREVNRy9ibG9iL21haW4vbWF0bGFiL2NoZWJmdW4ubSkgYW5kIFtgbWF0bGFiL2NoZWJmdW5fdGFibGVzLlJgXShodHRwczovL2dpdGh1Yi5jb20vbGVuaW5yYWZhZWxyaWVyYXNlZ3VyYS9OQUZERU1HL2Jsb2IvbWFpbi9tYXRsYWIvY2hlYmZ1bl90YWJsZXMuUikgc2NyaXB0cy4KCmBgYHtyfQojIEZ1bmN0aW9uIHRvIGNvbXB1dGUgdGhlIHJvb3RzIGFuZCBmYWN0b3IgZm9yIHRoZSByYXRpb25hbCBhcHByb3hpbWF0aW9uCm15LmdldC5yb290cyA8LSBmdW5jdGlvbihtLCAjIHJhdGlvbmFsIG9yZGVyLCBtID0gMSwgMiwgMywgNCwgNSwgNiwgNywgb3IgOAogICAgICAgICAgICAgICAgICAgICAgICAgYmV0YSAjIHNtb290aG5lc3MgcGFyYW1ldGVyLCBiZXRhID0gYWxwaGEvMiB3aXRoIGFscGhhIGJldHdlZW4gMC41IGFuZCAyCiAgICAgICAgICAgICAgICAgICAgICAgICApIHsKICAjIG0xdGFibGUgPC0gclNQREU6OjptMXRhYmxlCiAgIyBtMnRhYmxlIDwtIHJTUERFOjo6bTJ0YWJsZQogICMgbTN0YWJsZSA8LSByU1BERTo6Om0zdGFibGUKICAjIG00dGFibGUgPC0gclNQREU6OjptNHRhYmxlCiAgIyBtdCA8LSBnZXQocGFzdGUwKCJtIiwgbSwgInRhYmxlIikpCiAgbXQgPC0gcmVhZFJEUygiZGF0YV9maWxlcy9jaGViZnVuX3RhYmxlcy5SRFMiKVtbbV1dCiAgcmIgPC0gcmVwKDAsIG0gKyAxKQogIHJjIDwtIHJlcCgwLCBtKQogIGlmKG0gPT0gMSkgewogICAgcmMgPSBhcHByb3gobXQkYmV0YSwgbXRbW3Bhc3RlMCgicmMiKV1dLCBiZXRhKSR5CiAgfSBlbHNlIHsKICAgIHJjID0gc2FwcGx5KDE6bSwgZnVuY3Rpb24oaSkgewogICAgICBhcHByb3gobXQkYmV0YSwgbXRbW3Bhc3RlMCgicmMuIiwgaSldXSwgYmV0YSkkeQogICAgfSkKICB9CiAgcmIgPSBzYXBwbHkoMToobSsxKSwgZnVuY3Rpb24oaSkgewogICAgYXBwcm94KG10JGJldGEsIG10W1twYXN0ZTAoInJiLiIsIGkpXV0sIHhvdXQgPSBiZXRhKSR5CiAgfSkKICBmYWN0b3IgPSBhcHByb3gobXQkYmV0YSwgbXQkZmFjdG9yLCB4b3V0ID0gYmV0YSkkeQogIHJldHVybihsaXN0KHBsX3Jvb3RzID0gcmIsICMgcm9vdHMgXHtyX3syan1cfV97aj0xfV57bSsxfQogICAgICAgICAgICAgIHByX3Jvb3RzID0gcmMsICMgcm9vdHMgXHtyX3sxaX1cfV97aT0xfV5tCiAgICAgICAgICAgICAgZmFjdG9yID0gZmFjdG9yICMgdGhpcyBpcyBjX20vYl97bSsxfQogICAgICAgICAgICAgICkpCn0KYGBgCgojIyMgRnVuY3Rpb24gYHBvbHkuZnJvbS5yb290cygpYAoKRnVuY3Rpb24gYHBvbHkuZnJvbS5yb290cygpYCBjb21wdXRlcyB0aGUgY29lZmZpY2llbnRzIG9mIGEgcG9seW5vbWlhbCBmcm9tIGl0cyByb290cy4KCmBgYHtyfQojIEZ1bmN0aW9uIHRvIGNvbXB1dGUgcG9seW5vbWlhbCBjb2VmZmljaWVudHMgZnJvbSByb290cwpwb2x5LmZyb20ucm9vdHMgPC0gZnVuY3Rpb24ocm9vdHMpIHsKICBjb2VmIDwtIDEKICBmb3IgKHIgaW4gcm9vdHMpIHtjb2VmIDwtIGNvbnZvbHZlKGNvZWYsIGMoMSwgLXIpLCB0eXBlID0gIm9wZW4iKX0KICByZXR1cm4oY29lZikgIyByZXR1cm5lZCBpbiBpbmNyZWFzaW5nIG9yZGVyIGxpa2UgYStieCtjeF4yKy4uLgp9CmBgYAoKIyMjIEZ1bmN0aW9uIGBjb21wdXRlLnBhcnRpYWwuZnJhY3Rpb24ucGFyYW0oKWAKCkdpdmVuIGBmYWN0b3JgJD1cdGV4dHR0e2ZhY3Rvcn0gPSBcZGZyYWN7Y19tfXtiX3ttKzF9fSQsIGBwcl9yb290c2AkPVx7cl97MWl9XH1fe2k9MX1ebSQsIGBwbF9yb290c2AkPVx7cl97Mmp9XH1fe2o9MX1ee20rMX0kLCBgdGltZV9zdGVwYCQ9XHRhdSQsIGFuZCBgc2NhbGluZ2AkPVxrYXBwYV57MlxiZXRhfSQsIGZ1bmN0aW9uIGBjb21wdXRlLnBhcnRpYWwuZnJhY3Rpb24ucGFyYW0oKWAgY29tcHV0ZXMgdGhlIHBhcmFtZXRlcnMgZm9yIHRoZSBwYXJ0aWFsIGZyYWN0aW9uIGRlY29tcG9zaXRpb24gXGVxcmVme2VxOnBhcnRpYWxfZnJhY3Rpb25hZGpvaW50fS4KCmBgYHtyfQojIEZ1bmN0aW9uIHRvIGNvbXB1dGUgdGhlIHBhcmFtZXRlcnMgZm9yIHRoZSBwYXJ0aWFsIGZyYWN0aW9uIGRlY29tcG9zaXRpb24KY29tcHV0ZS5wYXJ0aWFsLmZyYWN0aW9uLnBhcmFtIDwtIGZ1bmN0aW9uKGZhY3RvciwgIyBjX20vYl97bSsxfQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJfcm9vdHMsICMgcm9vdHMgXHtyX3sxaX1cfV97aT0xfV5tCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbF9yb290cywgIyByb290cyBce3JfezJqfVx9X3tqPTF9XnttKzF9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aW1lX3N0ZXAsICMgXHRhdQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGluZyAjIFxrYXBwYV57MlxiZXRhfQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSB7CiAgcHJfY29lZiA8LSBwb2x5LmZyb20ucm9vdHMocHJfcm9vdHMpCiAgcGxfY29lZiA8LSBwb2x5LmZyb20ucm9vdHMocGxfcm9vdHMpCiAgcHJfcGx1c19wbF9jb2VmIDwtIGMoMCwgcHJfY29lZikgKyAoKHNjYWxpbmcgKiB0aW1lX3N0ZXApL2ZhY3RvcikgKiBwbF9jb2VmCiAgcG9sZXMgPC0gUmUocG9seXJvb3QocmV2KHByX3BsdXNfcGxfY29lZikpKQogIG51bV92YWxzIDwtIHByYWNtYTo6cG9seXZhbChwcl9jb2VmLCBwb2xlcykKICBkZW5fZGVyaXYgPC0gUmUocHJhY21hOjpwb2x5dmFsKHByYWNtYTo6cG9seWRlcihwcl9wbHVzX3BsX2NvZWYpLCBwb2xlcykpCiAgcmVzaWR1ZXMgPC0gUmUobnVtX3ZhbHMgLyBkZW5fZGVyaXYpCiAgcmV0dXJuKGxpc3QociA9IHJlc2lkdWVzLCAjIHJlc2lkdWVzIFx7YV9rXH1fe2s9MX1ee20rMX0KICAgICAgICAgICAgICBwID0gcG9sZXMsICMgcG9sZXMgXHtwX2tcfV97az0xfV57bSsxfQogICAgICAgICAgICAgIGsgPSAwICMgcmVtYWluZGVyIHIKICAgICAgICAgICAgICApKSAKfQpgYGAKCiMjIyBGdW5jdGlvbiBgbXkuZnJhY3Rpb25hbC5vcGVyYXRvcnMuZnJhYygpYAoKR2l2ZW4gdGhlIExhcGxhY2lhbiBtYXRyaXggYExgLCB0aGUgc21vb3RobmVzcyBwYXJhbWV0ZXIgYGJldGFgLCB0aGUgbWFzcyBtYXRyaXggYENgIChub3QgbHVtcGVkKSwgdGhlIHNjYWxpbmcgZmFjdG9yIGBzY2FsZS5mYWN0b3JgJD1ca2FwcGFeMiQsIHRoZSByYXRpb25hbCBvcmRlciBgbWAsIGFuZCB0aGUgdGltZSBzdGVwIGB0aW1lX3N0ZXBgJD1cdGF1JCwgZnVuY3Rpb24gYG15LmZyYWN0aW9uYWwub3BlcmF0b3JzLmZyYWMoKWAgY29tcHV0ZXMgdGhlIGZyYWN0aW9uYWwgb3BlcmF0b3IgYW5kIHJldHVybnMgYSBsaXN0IGNvbnRhaW5pbmcgdGhlIG5lY2Vzc2FyeSBtYXRyaWNlcyBhbmQgcGFyYW1ldGVycyBmb3IgdGhlIGZyYWN0aW9uYWwgZGlmZnVzaW9uIGVxdWF0aW9uLgoKYGBge3J9CiMgRnVuY3Rpb24gdG8gY29tcHV0ZSB0aGUgZnJhY3Rpb25hbCBvcGVyYXRvcgpteS5mcmFjdGlvbmFsLm9wZXJhdG9ycy5mcmFjIDwtIGZ1bmN0aW9uKEwsICMgTGFwbGFjaWFuIG1hdHJpeAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJldGEsICMgc21vb3RobmVzcyBwYXJhbWV0ZXIgYmV0YQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEMsICMgbWFzcyBtYXRyaXggKG5vdCBsdW1wZWQpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGUuZmFjdG9yLCAjIHNjYWxpbmcgcGFyYW1ldGVyID0ga2FwcGFeMgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG0gPSAxLCAjIHJhdGlvbmFsIG9yZGVyLCBtID0gMSwgMiwgMywgb3IgNAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpbWVfc3RlcCAjIHRpbWUgc3RlcCA9IHRhdQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgewogIEkgPC0gTWF0cml4OjpEaWFnb25hbChkaW0oQylbMV0pCiAgTCA8LSBMIC8gc2NhbGUuZmFjdG9yIAogIGlmKGJldGEgPT0gMSl7CiAgICBMIDwtIEwgKiBzY2FsZS5mYWN0b3JeYmV0YQogICAgcmV0dXJuKGxpc3QoQyA9IEMsICMgbWFzcyBtYXRyaXgKICAgICAgICAgICAgICAgIEwgPSBMLCAjIExhcGxhY2lhbiBtYXRyaXggc2NhbGVkCiAgICAgICAgICAgICAgICBtID0gbSwgIyByYXRpb25hbCBvcmRlcgogICAgICAgICAgICAgICAgYmV0YSA9IGJldGEsICMgc21vb3RobmVzcyBwYXJhbWV0ZXIKICAgICAgICAgICAgICAgIExIUyA9IEMgKyB0aW1lX3N0ZXAgKiBMICMgbGVmdC1oYW5kIHNpZGUgb2YgdGhlIGxpbmVhciBzeXN0ZW0KICAgICAgICAgICAgICAgICkpCiAgfSBlbHNlIHsKICAgIHNjYWxpbmcgPC0gc2NhbGUuZmFjdG9yXmJldGEKICAgIHJvb3RzIDwtIG15LmdldC5yb290cyhtLCBiZXRhKQogICAgcG9sZXNfcnNfayA8LSBjb21wdXRlLnBhcnRpYWwuZnJhY3Rpb24ucGFyYW0ocm9vdHMkZmFjdG9yLCByb290cyRwcl9yb290cywgcm9vdHMkcGxfcm9vdHMsIHRpbWVfc3RlcCwgc2NhbGluZykKCiAgICBwYXJ0aWFsX2ZyYWN0aW9uX3Rlcm1zIDwtIGxpc3QoKQogICAgZm9yIChpIGluIDE6KG0rMSkpIHsKICAgICAgIyBIZXJlIGlzIHdoZXJlIHRoZSB0ZXJtcyBpbiB0aGUgc3VtIGluIGVxIDEyIGFyZSBjb21wdXRlZAogICAgICBwYXJ0aWFsX2ZyYWN0aW9uX3Rlcm1zW1tpXV0gPC0gKEwgLSBwb2xlc19yc19rJHBbaV0gKiBDKSMvcG9sZXNfcnNfayRyW2ldCiAgICAgIH0KICAgIHJldHVybihsaXN0KEMgPSBDLCAjIG1hc3MgbWF0cml4CiAgICAgICAgICAgICAgICBMID0gTCwgIyBMYXBsYWNpYW4gbWF0cml4IHNjYWxlZAogICAgICAgICAgICAgICAgbSA9IG0sICMgcmF0aW9uYWwgb3JkZXIKICAgICAgICAgICAgICAgIGJldGEgPSBiZXRhLCAjIHNtb290aG5lc3MgcGFyYW1ldGVyCiAgICAgICAgICAgICAgICBwYXJ0aWFsX2ZyYWN0aW9uX3Rlcm1zID0gcGFydGlhbF9mcmFjdGlvbl90ZXJtcywgIyBwYXJ0aWFsIGZyYWN0aW9uIHRlcm1zCiAgICAgICAgICAgICAgICByZXNpZHVlcyA9IHBvbGVzX3JzX2skciAjIHJlc2lkdWVzIFx7YV9rXH1fe2s9MX1ee20rMX0KICAgICAgICAgICAgICAgICkpCiAgfQp9CmBgYAoKIyMjIEZ1bmN0aW9uIGBteS5zb2x2ZXIuZnJhYygpYAoKR2l2ZW4gdGhlIG9iamVjdCByZXR1cm5lZCBieSBgbXkuZnJhY3Rpb25hbC5vcGVyYXRvcnMuZnJhYygpYCBhbmQgYSB2ZWN0b3IgYHZgLCBmdW5jdGlvbiBgbXkuc29sdmVyLmZyYWMoKWAgc29sdmVzIHRoZSBzeXN0ZW0gXGVxcmVme3RoZW51bWVyaWNhbHNjaGVtZTR9IGZvciB0aGUgdmVjdG9yIGB2YC4gSWYgYGJldGEgPSAxYCwgaXQgc29sdmVzIHRoZSBzeXN0ZW0gZGlyZWN0bHk7IG90aGVyd2lzZSwgaXQgdXNlcyB0aGUgcGFydGlhbCBmcmFjdGlvbiBkZWNvbXBvc2l0aW9uLgoKYGBge3J9CiMgRnVuY3Rpb24gdG8gc29sdmUgdGhlIGl0ZXJhdGlvbgpteS5zb2x2ZXIuZnJhYyA8LSBmdW5jdGlvbihvYmosICMgb2JqZWN0IHJldHVybmVkIGJ5IG15LmZyYWN0aW9uYWwub3BlcmF0b3JzLmZyYWMoKQogICAgICAgICAgICAgICAgICAgICAgICAgICB2ICMgdmVjdG9yIHRvIGJlIHNvbHZlZCBmb3IKICAgICAgICAgICAgICAgICAgICAgICAgICAgKXsKICBiZXRhIDwtIG9iaiRiZXRhCiAgbSA8LSBvYmokbQogIGlmIChiZXRhID09IDEpewogICAgcmV0dXJuKHNvbHZlKG9iaiRMSFMsIHYpICMgc29sdmUgdGhlIGxpbmVhciBzeXN0ZW0gZGlyZWN0bHkgZm9yIGJldGEgPSAxCiAgICAgICAgICAgKQogIH0gZWxzZSB7CiAgICBwYXJ0aWFsX2ZyYWN0aW9uX3Rlcm1zIDwtIG9iaiRwYXJ0aWFsX2ZyYWN0aW9uX3Rlcm1zCiAgICByZXNpZHVlcyA8LSBvYmokcmVzaWR1ZXMKICAgIG91dHB1dCA8LSB2KjAKICAgIGZvciAoaSBpbiAxOihtKzEpKSB7b3V0cHV0IDwtIG91dHB1dCArIHJlc2lkdWVzW2ldICogc29sdmUocGFydGlhbF9mcmFjdGlvbl90ZXJtc1tbaV1dLCB2KX0KICAgIHJldHVybihvdXRwdXQgIyBzb2x2ZSB0aGUgbGluZWFyIHN5c3RlbSB1c2luZyB0aGUgcGFydGlhbCBmcmFjdGlvbiBkZWNvbXBvc2l0aW9uCiAgICAgICAgICAgKQogIH0KfQpgYGAKCgojIyMgRnVuY3Rpb24gYHNvbHZlX2ZvcndhcmRfZXZvbHV0aW9uKClgIAoKR2l2ZW4gdGhlIG9iamVjdCByZXR1cm5lZCBieSBgbXkuZnJhY3Rpb25hbC5vcGVyYXRvcnMuZnJhYygpYCwgdGhlIHRpbWUgc3RlcCBgdGltZV9zdGVwYCQ9XHRhdSQsIHRoZSB0aW1lIHNlcXVlbmNlIGB0aW1lX3NlcWAsIHRoZSByaWdodC1oYW5kIHNpZGUgdGVybSBgUkhTVGAsIGFuZCB0aGUgaW5pdGlhbCB2YWx1ZSBgdmFsX2F0XzBgLCBmdW5jdGlvbiBgc29sdmVfZm9yd2FyZF9ldm9sdXRpb24oKWAgc29sdmVzIHRoZSBmb3J3YXJkIGV2b2x1dGlvbiBwcm9ibGVtIFxlcXJlZntzdGF0ZXNvbHZlfS4KCgpgYGB7cn0Kc29sdmVfZm9yd2FyZF9ldm9sdXRpb24gPC0gZnVuY3Rpb24obXlfb3BfZnJhYywgdGltZV9zdGVwLCB0aW1lX3NlcSwgUkhTVCwgdmFsX2F0XzApIHsKICBDQyA8LSBteV9vcF9mcmFjJEMKICBOIDwtIGxlbmd0aCh0aW1lX3NlcSkKICBTT0wgPC0gbWF0cml4KE5BLCBucm93ID0gbnJvdyhDQyksIG5jb2wgPSBOKQogIFNPTFssIDFdIDwtIHZhbF9hdF8wCiAgZm9yIChrIGluIDE6KE4gLSAxKSkgewogICAgcmhzIDwtIENDICUqJSBTT0xbLCBrXSArIHRpbWVfc3RlcCAqIFJIU1RbLCBrICsgMV0KICAgIFNPTFssIGsgKyAxXSA8LSBhcy5tYXRyaXgobXkuc29sdmVyLmZyYWMobXlfb3BfZnJhYywgcmhzKSkKICB9CiAgcmV0dXJuKFNPTCkKfQpgYGAKCgojIyMgRnVuY3Rpb24gYHNvbHZlX2JhY2t3YXJkX2V2b2x1dGlvbigpYAoKR2l2ZW4gdGhlIG9iamVjdCByZXR1cm5lZCBieSBgbXkuZnJhY3Rpb25hbC5vcGVyYXRvcnMuZnJhYygpYCwgdGhlIHRpbWUgc3RlcCBgdGltZV9zdGVwYCQ9XHRhdSQsIHRoZSB0aW1lIHNlcXVlbmNlIGB0aW1lX3NlcWAsIGFuZCB0aGUgcmlnaHQtaGFuZCBzaWRlIHRlcm0gYFJIU1RgLCBmdW5jdGlvbiBgc29sdmVfYmFja3dhcmRfZXZvbHV0aW9uKClgIHNvbHZlcyB0aGUgYmFja3dhcmQgZXZvbHV0aW9uIHByb2JsZW0gXGVxcmVme2Fkam9pbnRzb2x2ZX0uCgoKYGBge3J9CnNvbHZlX2JhY2t3YXJkX2V2b2x1dGlvbiA8LSBmdW5jdGlvbihteV9vcF9mcmFjLCB0aW1lX3N0ZXAsIHRpbWVfc2VxLCBSSFNUKSB7CiAgQ0MgPC0gbXlfb3BfZnJhYyRDCiAgTiA8LSBsZW5ndGgodGltZV9zZXEpCiAgU09MIDwtIG1hdHJpeChOQSwgbnJvdyA9IG5yb3coQ0MpLCBuY29sID0gTikKICBTT0xbLCBOXSA8LSAwCiAgZm9yIChrIGluIChOIC0gMSk6MSkgewogICAgcmhzIDwtIENDICUqJSBTT0xbLCBrICsgMV0gKyB0aW1lX3N0ZXAgKiBSSFNUWywgayArIDFdICN0aGlzIGlzIGhvdyBpdCBzaG91bGQgYmUgaW4gdGhlb3J5CiAgICAjcmhzIDwtIENDICUqJSBTT0xbLCBrICsgMV0gKyB0aW1lX3N0ZXAgKiBSSFNUWywga10KICAgIFNPTFssIGtdIDwtIGFzLm1hdHJpeChteS5zb2x2ZXIuZnJhYyhteV9vcF9mcmFjLCByaHMpKQogIH0KICByZXR1cm4oU09MKQp9CmBgYAoKCiMjIEF1eGlsaWFyeSBmdW5jdGlvbnMgeyNhdXhpbGlhcnlfZnVuY3Rpb25zfQoKIyMjIEZ1bmN0aW9uIGBnZXRzLmdyYXBoLnRhZHBvbGUoKWAKCkdpdmVuIGEgbWVzaCBzaXplIGBoYCwgZnVuY3Rpb24gYGdldHMuZ3JhcGgudGFkcG9sZSgpYCBidWlsZHMgYSB0YWRwb2xlIGdyYXBoIGFuZCBjcmVhdGVzIGEgbWVzaC4KCgpgYGB7cn0KIyBGdW5jdGlvbiB0byBidWlsZCBhIHRhZHBvbGUgZ3JhcGggYW5kIGNyZWF0ZSBhIG1lc2gKZ2V0cy5ncmFwaC50YWRwb2xlIDwtIGZ1bmN0aW9uKGgpewogIGVkZ2UxIDwtIHJiaW5kKGMoMCwwKSxjKDEsMCkpCiAgdGhldGEgPC0gc2VxKGZyb209LXBpLHRvPXBpLGxlbmd0aC5vdXQgPSAxMDAwMCkKICBlZGdlMiA8LSBjYmluZCgxKzEvcGkrY29zKHRoZXRhKS9waSxzaW4odGhldGEpL3BpKQogIGVkZ2VzIDwtIGxpc3QoZWRnZTEsIGVkZ2UyKQogIGdyYXBoIDwtIG1ldHJpY19ncmFwaCRuZXcoZWRnZXMgPSBlZGdlcywgdmVyYm9zZSA9IDApCiAgZ3JhcGgkc2V0X21hbnVhbF9lZGdlX2xlbmd0aHMoZWRnZV9sZW5ndGhzID0gYygxLDIpKQogIGdyYXBoJGJ1aWxkX21lc2goaCA9IGgpCiAgcmV0dXJuKGdyYXBoKQp9CmBgYAoKCiMjIyBGdW5jdGlvbiBgdGFkcG9sZS5laWcoKWAKCkdpdmVuIGEgbW9kZSBudW1iZXIgYGtgIGFuZCBhIHRhZHBvbGUgZ3JhcGggYGdyYXBoYCwgZnVuY3Rpb24gYHRhZHBvbGUuZWlnKClgIGNvbXB1dGVzIHRoZSBlaWdlbnBhaXJzIG9mIHRoZSB0YWRwb2xlIGdyYXBoLgoKCmBgYHtyfQojIEZ1bmN0aW9uIHRvIGNvbXB1dGUgdGhlIGVpZ2VuZnVuY3Rpb25zIG9mIHRoZSB0YWRwb2xlIGdyYXBoCnRhZHBvbGUuZWlnIDwtIGZ1bmN0aW9uKGssZ3JhcGgpewp4MSA8LSBjKDAsZ3JhcGgkZ2V0X2VkZ2VfbGVuZ3RocygpWzFdKmdyYXBoJG1lc2gkUHRFW2dyYXBoJG1lc2gkUHRFWywxXT09MSwyXSkgCngyIDwtIGMoMCxncmFwaCRnZXRfZWRnZV9sZW5ndGhzKClbMl0qZ3JhcGgkbWVzaCRQdEVbZ3JhcGgkbWVzaCRQdEVbLDFdPT0yLDJdKSAKCmlmKGs9PTApeyAKICBmLmUxIDwtIHJlcCgxLGxlbmd0aCh4MSkpIAogIGYuZTIgPC0gcmVwKDEsbGVuZ3RoKHgyKSkgCiAgZjEgPSBjKGYuZTFbMV0sZi5lMlsxXSxmLmUxWy0xXSwgZi5lMlstMV0pIAogIGYgPSBsaXN0KHBoaT1mMS9zcXJ0KDMpKSAKICAKfSBlbHNlIHsKICBmLmUxIDwtIC0yKnNpbihwaSprKjEvMikqY29zKHBpKmsqeDEvMikgCiAgZi5lMiA8LSBzaW4ocGkqayp4Mi8yKSAgICAgICAgICAgICAgICAgIAogIAogIGYxID0gYyhmLmUxWzFdLGYuZTJbMV0sZi5lMVstMV0sIGYuZTJbLTFdKSAKICAKICBpZigoayAlJSAyKT09MSl7IAogICAgZiA9IGxpc3QocGhpPWYxL3NxcnQoMykpIAogIH0gZWxzZSB7IAogICAgZi5lMSA8LSAoLTEpXntrLzJ9KmNvcyhwaSprKngxLzIpCiAgICBmLmUyIDwtIGNvcyhwaSprKngyLzIpCiAgICBmMiA9IGMoZi5lMVsxXSxmLmUyWzFdLGYuZTFbLTFdLGYuZTJbLTFdKSAKICAgIGYgPC0gbGlzdChwaGk9ZjEscHNpPWYyL3NxcnQoMy8yKSkKICB9Cn0KcmV0dXJuKGYpCn0KYGBgCgojIyMgRnVuY3Rpb24gYGdldHMuZWlnZW4ucGFyYW1zKClgCgpHaXZlbiBhIGZpbml0ZSBudW1iZXIgb2YgbW9kZXMgYE5fZmluaXRlYCwgYSBzY2FsaW5nIHBhcmFtZXRlciBga2FwcGFgLCBhIHNtb290aG5lc3MgcGFyYW1ldGVyIGBhbHBoYWAsIGFuZCBhIHRhZHBvbGUgZ3JhcGggYGdyYXBoYCwgZnVuY3Rpb24gYGdldHMuZWlnZW4ucGFyYW1zKClgIGNvbXB1dGVzIGBFSUdFTlZBTF9BTFBIQWAgKGEgdmVjdG9yIHdpdGggZW50cmllcyAkXGxhbWJkYV9qXntcYWxwaGEvMn0kKSwgYEVJR0VOVkFMX01JTlVTX0FMUEhBYCAoYSB2ZWN0b3Igd2l0aCBlbnRyaWVzICRcbGFtYmRhX2peey1cYWxwaGEvMn0kKSwgYW5kIGBFSUdFTkZVTmAgKGEgbWF0cml4IHdpdGggY29sdW1ucyAkZV9qJCBvbiB0aGUgbWVzaCBvZiBgZ3JhcGhgKS4KCgpgYGB7cn0KIyBGdW5jdGlvbiB0byBjb21wdXRlIHRoZSBlaWdlbnBhaXJzIG9mIHRoZSB0YWRwb2xlIGdyYXBoCmdldHMuZWlnZW4ucGFyYW1zIDwtIGZ1bmN0aW9uKE5fZmluaXRlID0gNCwga2FwcGEgPSAxLCBhbHBoYSA9IDAuNSwgZ3JhcGgpewogIEVJR0VOVkFMIDwtIE5VTEwKICBFSUdFTlZBTF9BTFBIQSA8LSBOVUxMCiAgRUlHRU5WQUxfTUlOVVNfQUxQSEEgPC0gTlVMTAogIEVJR0VORlVOIDwtIE5VTEwKICBJTkRFWCA8LSBOVUxMCiAgZm9yIChqIGluIDA6Tl9maW5pdGUpIHsKICAgIGxhbWJkYV9qIDwtIGthcHBhXjIgKyAoaipwaS8yKV4yCiAgICBsYW1iZGFfal9hbHBoYV9oYWxmIDwtIGxhbWJkYV9qXihhbHBoYS8yKQogICAgbGFtYmRhX2pfbWludXNfYWxwaGFfaGFsZiA8LSBsYW1iZGFfal4oLWFscGhhLzIpCiAgICBlX2ogPC0gdGFkcG9sZS5laWcoaixncmFwaCkkcGhpCiAgICBFSUdFTlZBTCA8LSBjKEVJR0VOVkFMLCBsYW1iZGFfaikKICAgIEVJR0VOVkFMX0FMUEhBIDwtIGMoRUlHRU5WQUxfQUxQSEEsIGxhbWJkYV9qX2FscGhhX2hhbGYpICAKICAgIEVJR0VOVkFMX01JTlVTX0FMUEhBIDwtIGMoRUlHRU5WQUxfTUlOVVNfQUxQSEEsIGxhbWJkYV9qX21pbnVzX2FscGhhX2hhbGYpCiAgICBFSUdFTkZVTiA8LSBjYmluZChFSUdFTkZVTiwgZV9qKQogICAgSU5ERVggPC0gYyhJTkRFWCwgaikKICAgIGlmIChqPjAgJiYgKGogJSUgMiA9PSAwKSkgewogICAgICBsYW1iZGFfaiA8LSBrYXBwYV4yICsgKGoqcGkvMileMgogICAgICBsYW1iZGFfal9hbHBoYV9oYWxmIDwtIGxhbWJkYV9qXihhbHBoYS8yKQogICAgICBsYW1iZGFfal9taW51c19hbHBoYV9oYWxmIDwtIGxhbWJkYV9qXigtYWxwaGEvMikKICAgICAgZV9qIDwtIHRhZHBvbGUuZWlnKGosZ3JhcGgpJHBzaQogICAgICBFSUdFTlZBTCA8LSBjKEVJR0VOVkFMLCBsYW1iZGFfaikKICAgICAgRUlHRU5WQUxfQUxQSEEgPC0gYyhFSUdFTlZBTF9BTFBIQSwgbGFtYmRhX2pfYWxwaGFfaGFsZikgICAgCiAgICAgIEVJR0VOVkFMX01JTlVTX0FMUEhBIDwtIGMoRUlHRU5WQUxfTUlOVVNfQUxQSEEsIGxhbWJkYV9qX21pbnVzX2FscGhhX2hhbGYpCiAgICAgIEVJR0VORlVOIDwtIGNiaW5kKEVJR0VORlVOLCBlX2opCiAgICAgIElOREVYIDwtIGMoSU5ERVgsIGorMC4xKQogICAgICB9CiAgICB9CiAgcmV0dXJuKGxpc3QoRUlHRU5WQUwgPSBFSUdFTlZBTCwKICAgICAgICAgICAgICBFSUdFTlZBTF9BTFBIQSA9IEVJR0VOVkFMX0FMUEhBLCAKICAgICAgICAgICAgICBFSUdFTlZBTF9NSU5VU19BTFBIQSA9IEVJR0VOVkFMX01JTlVTX0FMUEhBLAogICAgICAgICAgICAgIEVJR0VORlVOID0gRUlHRU5GVU4sCiAgICAgICAgICAgICAgSU5ERVggPSBJTkRFWCkpCn0KYGBgCgoKIyMjIEZ1bmN0aW9uIGBjb25zdHJ1Y3RfcGllY2V3aXNlX3Byb2plY3Rpb24oKWAgeyNjb25zdHJ1Y3RfcGllY2V3aXNlX3Byb2plY3Rpb259CgpHaXZlbiBhIG1hdHJpeCBgcHJvamVjdGVkX1VfYXBwcm94YCB3aXRoIGFwcHJveGltYXRlZCB2YWx1ZXMgYXQgZGlzY3JldGUgdGltZSBwb2ludHMsIGEgc2VxdWVuY2Ugb2YgdGltZSBwb2ludHMgYHRpbWVfc2VxYCwgYW5kIGFuIGV4dGVuZGVkIHNlcXVlbmNlIG9mIHRpbWUgcG9pbnRzIGBvdmVya2lsbF90aW1lX3NlcWAsIGZ1bmN0aW9uIGBjb25zdHJ1Y3RfcGllY2V3aXNlX3Byb2plY3Rpb24oKWAgY29uc3RydWN0cyBhIHBpZWNld2lzZSBjb25zdGFudCBwcm9qZWN0aW9uIG9mIHRoZSBhcHByb3hpbWF0ZWQgdmFsdWVzIG92ZXIgdGhlIGV4dGVuZGVkIHRpbWUgc2VxdWVuY2UuCgpgYGB7cn0KIyBGdW5jdGlvbiB0byBjb25zdHJ1Y3QgYSBwaWVjZXdpc2UgY29uc3RhbnQgcHJvamVjdGlvbiBvZiBhcHByb3hpbWF0ZWQgdmFsdWVzCmNvbnN0cnVjdF9waWVjZXdpc2VfcHJvamVjdGlvbiA8LSBmdW5jdGlvbihwcm9qZWN0ZWRfVV9hcHByb3gsIHRpbWVfc2VxLCBvdmVya2lsbF90aW1lX3NlcSkgewogIHByb2plY3RlZF9VX3BpZWNld2lzZSA8LSBtYXRyaXgoTkEsIG5yb3cgPSBucm93KHByb2plY3RlZF9VX2FwcHJveCksIG5jb2wgPSBsZW5ndGgob3ZlcmtpbGxfdGltZV9zZXEpKQogIAogICMgQXNzaWduIHZhbHVlIGF0IHQgPSAwCiAgcHJvamVjdGVkX1VfcGllY2V3aXNlWywgd2hpY2gob3ZlcmtpbGxfdGltZV9zZXEgPT0gMCldIDwtIHByb2plY3RlZF9VX2FwcHJveFssIDFdCiAgCiAgIyBBc3NpZ24gdmFsdWVzIGZvciBpbnRlcnZhbHMgKHRfe2stMX0sIHRfa10KICBmb3IgKGsgaW4gMjpsZW5ndGgodGltZV9zZXEpKSB7CiAgICBpZHhzIDwtIHdoaWNoKG92ZXJraWxsX3RpbWVfc2VxID4gdGltZV9zZXFbayAtIDFdICYgb3ZlcmtpbGxfdGltZV9zZXEgPD0gdGltZV9zZXFba10pCiAgICBwcm9qZWN0ZWRfVV9waWVjZXdpc2VbLCBpZHhzXSA8LSBwcm9qZWN0ZWRfVV9hcHByb3hbLCBrXQogIH0KICAKICByZXR1cm4ocHJvamVjdGVkX1VfcGllY2V3aXNlKQp9CmBgYAoKIyMjIEZ1bmN0aW9ucyBmb3IgY29tcHV0aW5nIHRoZSB0cnVlIGxpbmUgcmF0ZXMKCmBgYHtyfQpsb2dsb2dfbGluZV9lcXVhdGlvbiA8LSBmdW5jdGlvbih4MSwgeTEsIHNsb3BlKSB7CiAgYiA8LSBsb2cxMCh5MSAvICh4MSBeIHNsb3BlKSkKICAKICBmdW5jdGlvbih4KSB7CiAgICAoeCBeIHNsb3BlKSAqICgxMCBeIGIpCiAgfQp9CmV4cF9saW5lX2VxdWF0aW9uIDwtIGZ1bmN0aW9uKHgxLCB5MSwgc2xvcGUpIHsKICBsbkMgPC0gbG9nKHkxKSAtIHNsb3BlICogeDEKICAKICBmdW5jdGlvbih4KSB7CiAgICBleHAobG5DICsgc2xvcGUgKiB4KQogIH0KfQpjb21wdXRlX2d1aWRpbmdfbGluZXMgPC0gZnVuY3Rpb24oeF9heGlzX3ZlY3RvciwgZXJyb3JzLCB0aGVvcmV0aWNhbF9yYXRlcywgbGluZV9lcXVhdGlvbl9mdW4pIHsKICBndWlkaW5nX2xpbmVzIDwtIG1hdHJpeChOQSwgbnJvdyA9IGxlbmd0aCh4X2F4aXNfdmVjdG9yKSwgbmNvbCA9IGxlbmd0aCh0aGVvcmV0aWNhbF9yYXRlcykpCiAgCiAgZm9yIChqIGluIHNlcV9hbG9uZyh0aGVvcmV0aWNhbF9yYXRlcykpIHsKICAgIGd1aWRpbmdfbGluZXNfYXV4IDwtIG1hdHJpeChOQSwgbnJvdyA9IGxlbmd0aCh4X2F4aXNfdmVjdG9yKSwgbmNvbCA9IGxlbmd0aCh4X2F4aXNfdmVjdG9yKSkKICAgIAogICAgZm9yIChrIGluIHNlcV9hbG9uZyh4X2F4aXNfdmVjdG9yKSkgewogICAgICBwb2ludF94MSA8LSB4X2F4aXNfdmVjdG9yW2tdCiAgICAgIHBvaW50X3kxIDwtIGVycm9yc1trLCBqXQogICAgICBzbG9wZSA8LSB0aGVvcmV0aWNhbF9yYXRlc1tqXQogICAgICAKICAgICAgbGluZSA8LSBsaW5lX2VxdWF0aW9uX2Z1bih4MSA9IHBvaW50X3gxLCB5MSA9IHBvaW50X3kxLCBzbG9wZSA9IHNsb3BlKQogICAgICBndWlkaW5nX2xpbmVzX2F1eFssIGtdIDwtIGxpbmUoeF9heGlzX3ZlY3RvcikKICAgIH0KICAgIAogICAgZ3VpZGluZ19saW5lc1ssIGpdIDwtIHJvd01lYW5zKGd1aWRpbmdfbGluZXNfYXV4KQogIH0KICAKICByZXR1cm4oZ3VpZGluZ19saW5lcykKfQpgYGAKCgpgYGB7cn0KIyBGdW5jdGlvbnMgdG8gY29tcHV0ZSB0aGUgZXhhY3Qgc29sdXRpb24gdG8gdGhlIGZyYWN0aW9uYWwgZGlmZnVzaW9uIGVxdWF0aW9uCmdfbGluZWFyIDwtIGZ1bmN0aW9uKHIsIEEsIGxhbWJkYV9qX2FscGhhX2hhbGYpIHsKICByZXR1cm4oQSAqIGV4cCgtbGFtYmRhX2pfYWxwaGFfaGFsZiAqIHIpKQogIH0KR19saW5lYXIgPC0gZnVuY3Rpb24odCwgQSkgewogIHJldHVybihBICogdCkKICB9CmdfZXhwIDwtIGZ1bmN0aW9uKHIsIEEsIG11KSB7CiAgcmV0dXJuKEEgKiBleHAobXUgKiByKSkKICB9CkdfZXhwIDwtIGZ1bmN0aW9uKHQsIEEsIGxhbWJkYV9qX2FscGhhX2hhbGYsIG11KSB7CiAgZXhwb25lbnQgPC0gbGFtYmRhX2pfYWxwaGFfaGFsZiArIG11CiAgcmV0dXJuKEEgKiAoZXhwKGV4cG9uZW50ICogdCkgLSAxKSAvIGV4cG9uZW50KQogIH0KZ19wb2x5IDwtIGZ1bmN0aW9uKHIsIEEsIG4pIHsKICByZXR1cm4oQSAqIHJebikKfQpHX3BvbHkgPC0gZnVuY3Rpb24odCwgQSwgbGFtYmRhX2pfYWxwaGFfaGFsZiwgbikgewogIHQgPC0gYXMudmVjdG9yKHQpCiAga192YWxzIDwtIDA6bgogIHN1bV90ZXJtIDwtIHNhcHBseSh0LCBmdW5jdGlvbih0dCkgewogICAgc3VtKCgoLWxhbWJkYV9qX2FscGhhX2hhbGYgKiB0dClea192YWxzKSAvIGZhY3RvcmlhbChrX3ZhbHMpKQogIH0pCiAgY29lZmYgPC0gKCgtMSleKG4gKyAxKSkgKiBmYWN0b3JpYWwobikgLyAobGFtYmRhX2pfYWxwaGFfaGFsZl4obiArIDEpKQogIHJldHVybihBICogY29lZmYgKiAoMSAtIGV4cChsYW1iZGFfal9hbHBoYV9oYWxmICogdCkgKiBzdW1fdGVybSkpCn0KZ19zaW4gPC0gZnVuY3Rpb24ociwgQSwgb21lZ2EpIHsKICByZXR1cm4oQSAqIHNpbihvbWVnYSAqIHIpKQp9Ckdfc2luIDwtIGZ1bmN0aW9uKHQsIEEsIGxhbWJkYV9qX2FscGhhX2hhbGYsIG9tZWdhKSB7CiAgZGVub20gPC0gbGFtYmRhX2pfYWxwaGFfaGFsZl4yICsgb21lZ2FeMgogIG51bWVyYXRvciA8LSBleHAobGFtYmRhX2pfYWxwaGFfaGFsZiAqIHQpICogKGxhbWJkYV9qX2FscGhhX2hhbGYgKiBzaW4ob21lZ2EgKiB0KSAtIG9tZWdhICogY29zKG9tZWdhICogdCkpICsgb21lZ2EKICByZXR1cm4oQSAqIG51bWVyYXRvciAvIGRlbm9tKQp9CmdfY29zIDwtIGZ1bmN0aW9uKHIsIEEsIHRoZXRhKSB7CiAgcmV0dXJuKEEgKiBjb3ModGhldGEgKiByKSkgCn0KR19jb3MgPC0gZnVuY3Rpb24odCwgQSwgbGFtYmRhX2pfYWxwaGFfaGFsZiwgdGhldGEpIHsKICBkZW5vbSA8LSBsYW1iZGFfal9hbHBoYV9oYWxmXjIgKyB0aGV0YV4yCiAgbnVtZXJhdG9yIDwtIGV4cChsYW1iZGFfal9hbHBoYV9oYWxmICogdCkgKiAobGFtYmRhX2pfYWxwaGFfaGFsZiAqIGNvcyh0aGV0YSAqIHQpICsgdGhldGEgKiBzaW4odGhldGEgKiB0KSkgLSBsYW1iZGFfal9hbHBoYV9oYWxmCiAgcmV0dXJuKEEgKiBudW1lcmF0b3IgLyBkZW5vbSkKfQpgYGAKCiMjIyBGdW5jdGlvbiBgcmV2ZXJzZWNvbHVtbnMoKWAKCkdpdmVuIGEgbWF0cml4IGBtYXRgLCBmdW5jdGlvbiBgcmV2ZXJzZWNvbHVtbnMoKWAgcmV2ZXJzZXMgdGhlIG9yZGVyIG9mIGl0cyBjb2x1bW5zLgoKCmBgYHtyfQpyZXZlcnNlY29sdW1ucyA8LSBmdW5jdGlvbihtYXQpIHsKICByZXR1cm4obWF0WywgcmV2KHNlcV9sZW4obmNvbChtYXQpKSldKQp9CmBgYAoKCmBgYHtyfQojIGhlbHBlcjogbWVhc3VyZSBjaGFuZ2UgcmVsYXRpdmUgdG8gdGhlIHNpemUgb2YgdGhlIHByZXZpb3VzIGl0ZXJhdGUgCmNoYW5nZV9jb21wYXJlciA8LSBmdW5jdGlvbihYX25ldywgWF9vbGQsIHRpbWVfc3RlcCwgQywgcmVsYXRpdmUgPSBUUlVFKSB7CiAgWFggPC0gWF9uZXcgLSBYX29sZAogIG51bSA8LSBzcXJ0KGFzLmRvdWJsZSh0aW1lX3N0ZXAgKiBzdW0oWFggKiAoQyAlKiUgWFgpKSkpCiAgaWYgKCFyZWxhdGl2ZSkgewogICAgcmV0dXJuKG51bSkKICAgIH0KICBkZW4gPC0gc3FydChhcy5kb3VibGUodGltZV9zdGVwICogc3VtKFhfbmV3ICogKEMgJSolIFhfbmV3KSkpKQogIGlmIChkZW4gPCAuTWFjaGluZSRkb3VibGUuZXBzKSB7CiAgICByZXR1cm4oaWZlbHNlKG51bSA8IC5NYWNoaW5lJGRvdWJsZS5lcHMsIDAsIG51bSkpCiAgfSBlbHNlIHsKICAgIHJldHVybihudW0gLyBkZW4pCiAgfQp9CmBgYAoKCmBgYHtyfQojIENvdXBsZWQgc29sdmVyIHdpdGggbXVsdGktY3JpdGVyaWEgY29udmVyZ2VuY2UKc29sdmVfY291cGxlZF9zeXN0ZW1fbXVsdGlfdG9sIDwtIGZ1bmN0aW9uKAogIG15X29wX2ZyYWMsICAgICAgICAgICAjIG9wZXJhdG9yCiAgdGltZV9zdGVwLCAgICAgICAgICAgICMgdGF1CiAgdGltZV9zZXEsICAgICAgICAgICAgICMgdmVjdG9yIG9mIHRpbWVzIAogIHVfMCwgICAgICAgICAgICAgICAgICAjIGluaXRpYWwgc3RhdGUgVV4wIAogIEZfcHJvaiwgICAgICAgICAgICAgICAjIG1hdHJpeCBvZiBGIAogIFpfaW5pLAogIFZfZCwgICAgICAgICAgICAgICAgICAjIG1hdHJpeCBvZiAKICB1X2QsCiAgUHNpLCAgICAgICAgICAgICAgICAgICMgUHNpIG1hdHJpeAogIFIsICAgICAgICAgICAgICAgICAgICAjIFIgbWF0cml4CiAgYSwgYiwgQywgICAgICAgICAgICAgICAgIyBsb3dlci91cHBlciBib3VuZHMgKHZlY3RvciBvciBtYXRyaXggYnJvYWRjYXN0YWJsZSB0byB0aW1lIGdyaWQpCiAgbXUsICAgICAgICAgICAgICAgICAgICMgcG9zaXRpdmUgc2NhbGFyCiAgdG9sID0gMWUtOCwgICAgICAgICAgICMgc2NhbGFyIG9yIG5hbWVkIGxpc3Q6IGxpc3QoWj0uLi4sIFU9Li4uLCBQPS4uLikKICBtYXhpdCA9IDIwMCwKICB2ZXJib3NlID0gRkFMU0UsCiAgbmVzdGVkX3NwYXRpYWxfbWVzaCA9IEZBTFNFLAogIHRydWVfc29sCikgewoKICBpZiAoaXMubnVtZXJpYyh0b2wpICYmIGxlbmd0aCh0b2wpID09IDEpIHsKICAgIHRvbF9saXN0IDwtIGxpc3QoWiA9IHRvbCwgVSA9IHRvbCwgUCA9IHRvbCkKICB9IGVsc2UgaWYgKGlzLmxpc3QodG9sKSkgewogICAgdG9sX2xpc3QgPC0gbW9kaWZ5TGlzdChsaXN0KFogPSAxZS04LCBVID0gMWUtOCwgUCA9IDFlLTgpLCB0b2wpCiAgfSBlbHNlIHN0b3AoInRvbCBtdXN0IGJlIHNjYWxhciBvciBsaXN0KFo9Li4uLFU9Li4uLFA9Li4uKSIpCgogIGl0IDwtIDAKICBjb252ZXJnZWQgPC0gRkFMU0UKICAKICByZWxfaGlzdG9yeSA8LSBkYXRhLmZyYW1lKGl0ZXIgPSBpbnRlZ2VyKDApLCB2YXJpYWJsZSA9IGNoYXJhY3RlcigwKSwgdmFsdWUgPSBudW1lcmljKDApKQogIGFic19oaXN0b3J5IDwtIGRhdGEuZnJhbWUoaXRlciA9IGludGVnZXIoMCksIHZhcmlhYmxlID0gY2hhcmFjdGVyKDApLCB2YWx1ZSA9IG51bWVyaWMoMCkpCiAgbWluX2hpc3RvcnkgPC0gZGF0YS5mcmFtZShpdGVyID0gaW50ZWdlcigwKSwgdmFyaWFibGUgPSBjaGFyYWN0ZXIoMCksIHZhbHVlID0gbnVtZXJpYygwKSkKCiAgWl9saXN0IDwtIGxpc3QoKQogIFVfbGlzdCA8LSBsaXN0KCkKICBQX2xpc3QgPC0gbGlzdCgpCiAgCiAgel9wcmV2IDwtIFpfaW5pCiAgaWYobmVzdGVkX3NwYXRpYWxfbWVzaCA9PSBUUlVFKXtaX21hdCA8LSBDICUqJSB6X3ByZXZ9ZWxzZXtaX21hdCA8LSBSICUqJSBQc2kgJSolIHpfcHJldn0KICBVX3ByZXYgPC0gRl9wcm9qKjAKICBQX3ByZXYgPC0gRl9wcm9qKjAKCiAgcmVwZWF0IHsKICAgIGl0IDwtIGl0ICsgMQoKICAgIFVfbWF0IDwtIHNvbHZlX2ZvcndhcmRfZXZvbHV0aW9uKG15X29wX2ZyYWMsIHRpbWVfc3RlcCwgdGltZV9zZXEsIFJIU1QgPSBGX3Byb2ogKyBaX21hdCwgdmFsX2F0XzAgPSB1XzApCiAgICBpZihuZXN0ZWRfc3BhdGlhbF9tZXNoID09IFRSVUUpe1ZfbWF0IDwtIEMgJSolIFVfbWF0fWVsc2V7Vl9tYXQgPC0gUiAlKiUgUHNpICUqJSBVX21hdH0KICAgIFBfbWF0IDwtIHNvbHZlX2JhY2t3YXJkX2V2b2x1dGlvbihteV9vcF9mcmFjLCB0aW1lX3N0ZXAsIHRpbWVfc2VxLCBSSFNUID0gVl9tYXQgLSBWX2QpCiAgICB6X25ldyA8LSBtYXRyaXgocG1heChhLCBwbWluKGIsIC0gUF9tYXQgLyBtdSkpLCBkaW0oUF9tYXQpKQogICAgaWYobmVzdGVkX3NwYXRpYWxfbWVzaCA9PSBUUlVFKXtaX21hdCA8LSBDICUqJSB6X25ld31lbHNle1pfbWF0IDwtIFIgJSolIFBzaSAlKiUgel9uZXd9CiAgICAKICAgICMgcmVsYXRpdmUgY2hhbmdlcwogICAgcmVsX2NoYW5nZXNfWiA8LSBjaGFuZ2VfY29tcGFyZXIoel9uZXcsIHpfcHJldiwgdGltZV9zdGVwLCBDLCByZWxhdGl2ZSA9IFRSVUUpICAKICAgIHJlbF9jaGFuZ2VzX1UgPC0gY2hhbmdlX2NvbXBhcmVyKFVfbWF0LCBVX3ByZXYsIHRpbWVfc3RlcCwgQywgcmVsYXRpdmUgPSBUUlVFKQogICAgcmVsX2NoYW5nZXNfUCA8LSBjaGFuZ2VfY29tcGFyZXIoUF9tYXQsIFBfcHJldiwgdGltZV9zdGVwLCBDLCByZWxhdGl2ZSA9IFRSVUUpCiAgICBhYnNfY2hhbmdlc19aIDwtIGNoYW5nZV9jb21wYXJlcih6X25ldywgdHJ1ZV9zb2wkel9iYXIsIHRpbWVfc3RlcCwgQywgcmVsYXRpdmUgPSBGQUxTRSkKICAgIGFic19jaGFuZ2VzX1UgPC0gY2hhbmdlX2NvbXBhcmVyKFVfbWF0LCB0cnVlX3NvbCR1X2JhciwgdGltZV9zdGVwLCBDLCByZWxhdGl2ZSA9IEZBTFNFKQogICAgYWJzX2NoYW5nZXNfUCA8LSBjaGFuZ2VfY29tcGFyZXIoUF9tYXQsIHRydWVfc29sJHBfYmFyLCB0aW1lX3N0ZXAsIEMsIHJlbGF0aXZlID0gRkFMU0UpCiAgICBYWCA8LSBVX21hdCAtIHVfZAogICAgbWluX2NoYW5nZSA8LSAwLjUgKiBhcy5kb3VibGUodGltZV9zdGVwICogc3VtKFhYICogKEMgJSolIFhYKSkpICArIDAuNSAqIG11ICogYXMuZG91YmxlKHRpbWVfc3RlcCAqIHN1bSh6X25ldyAqIChDICUqJSB6X25ldykpKQogICAgcmVsX2hpc3RvcnkgPC0gcmJpbmQocmVsX2hpc3RvcnksCiAgICAgIGRhdGEuZnJhbWUoaXRlciA9IGl0LCB2YXJpYWJsZSA9ICJaIiwgdmFsdWUgPSByZWxfY2hhbmdlc19aKSwKICAgICAgZGF0YS5mcmFtZShpdGVyID0gaXQsIHZhcmlhYmxlID0gIlUiLCB2YWx1ZSA9IHJlbF9jaGFuZ2VzX1UpLAogICAgICBkYXRhLmZyYW1lKGl0ZXIgPSBpdCwgdmFyaWFibGUgPSAiUCIsIHZhbHVlID0gcmVsX2NoYW5nZXNfUCkpCiAgICBhYnNfaGlzdG9yeSA8LSByYmluZChhYnNfaGlzdG9yeSwKICAgICAgZGF0YS5mcmFtZShpdGVyID0gaXQsIHZhcmlhYmxlID0gIloiLCB2YWx1ZSA9IGFic19jaGFuZ2VzX1opLAogICAgICBkYXRhLmZyYW1lKGl0ZXIgPSBpdCwgdmFyaWFibGUgPSAiVSIsIHZhbHVlID0gYWJzX2NoYW5nZXNfVSksCiAgICAgIGRhdGEuZnJhbWUoaXRlciA9IGl0LCB2YXJpYWJsZSA9ICJQIiwgdmFsdWUgPSBhYnNfY2hhbmdlc19QKSkKICAgIG1pbl9oaXN0b3J5IDwtIHJiaW5kKG1pbl9oaXN0b3J5LAogICAgICBkYXRhLmZyYW1lKGl0ZXIgPSBpdCwgdmFyaWFibGUgPSAibWluIiwgdmFsdWUgPSBtaW5fY2hhbmdlKSkKICAgIAogICAgaWYgKHZlcmJvc2UpIHttZXNzYWdlKHNwcmludGYoIml0ZXIgJTNkOiByZWwoWikgPSAlLjNlLCByZWwoVSkgPSAlLjNlLCByZWwoUCkgPSAlLjNlIiwgaXQsIHJlbF9jaGFuZ2VzX1osIHJlbF9jaGFuZ2VzX1UsIHJlbF9jaGFuZ2VzX1ApKX0KCiAgICAjIHVwZGF0ZSBzdG9yZWQgcHJldmlvdXMgaXRlcmF0ZXMKICAgIHpfcHJldiA8LSB6X25ldwogICAgVV9wcmV2IDwtIFVfbWF0CiAgICBQX3ByZXYgPC0gUF9tYXQKICAgIAogICAgWl9saXN0W1twYXN0ZTAoIml0ZXJhdGlvbiAiLCBpdCldXSA8LSB6X25ldwogICAgVV9saXN0W1twYXN0ZTAoIml0ZXJhdGlvbiAiLGl0KV1dIDwtIFVfbWF0CiAgICBQX2xpc3RbW3Bhc3RlMCgiaXRlcmF0aW9uICIsaXQpXV0gPC0gUF9tYXQKCiAgICAjIGNvbnZlcmdlbmNlIGNoZWNrOiByZXF1aXJlIGFsbCByZWxfY2hhbmdlcyA8PSByZXNwZWN0aXZlIHRvbAogICAgY29uZF9aIDwtIHJlbF9jaGFuZ2VzX1ogPD0gdG9sX2xpc3QkWgogICAgY29uZF9VIDwtIHJlbF9jaGFuZ2VzX1UgPD0gdG9sX2xpc3QkVQogICAgY29uZF9QIDwtIHJlbF9jaGFuZ2VzX1AgPD0gdG9sX2xpc3QkUAoKICAgIGlmICgoY29uZF9aICYmIGNvbmRfVSAmJiBjb25kX1ApIHx8IGl0ID49IG1heGl0KSB7CiAgICAgIGNvbnZlcmdlZCA8LSAoY29uZF9aICYmIGNvbmRfVSAmJiBjb25kX1ApCiAgICAgIGJyZWFrCiAgICB9CiAgfQoKICBpZiAodmVyYm9zZSAmJiAhY29udmVyZ2VkKSB7CiAgICBtZXNzYWdlKHNwcmludGYoCiAgICAgICJTdG9wcGVkIGF0IG1heGl0PSVkOyByZWxfY2hhbmdlczogWiA9ICUuM2UgKHRvbCAlLjNlKSwgVSA9ICUuM2UgKHRvbCAlLjNlKSwgUCA9ICUuM2UgKHRvbCAlLjNlKSIsCiAgICAgIGl0LCByZWxfY2hhbmdlc19aLCB0b2xfbGlzdCRaLCByZWxfY2hhbmdlc19VLCB0b2xfbGlzdCRVLCByZWxfY2hhbmdlc19QLCB0b2xfbGlzdCRQCiAgICApKQogIH0KCiAgcmV0dXJuKGxpc3QoVSA9IFVfbWF0LCAgIyBzb2x1dGlvbiBVCiAgICAgICAgICAgICAgWiA9IHpfbmV3LCAgIyBzb2x1dGlvbiB6CiAgICAgICAgICAgICAgUCA9IFBfbWF0LCAjIHNvbHV0aW9uIFAKICAgICAgICAgICAgICBpdGVyYXRpb25zID0gaXQsCiAgICAgICAgICAgICAgY29udmVyZ2VkID0gY29udmVyZ2VkLAogICAgICAgICAgICAgIHRvbF9saXN0ID0gdG9sX2xpc3QsCiAgICAgICAgICAgICAgcmVsX2hpc3RvcnkgPSByZWxfaGlzdG9yeSwKICAgICAgICAgICAgICBhYnNfaGlzdG9yeSA9IGFic19oaXN0b3J5LAogICAgICAgICAgICAgIG1pbl9oaXN0b3J5ID0gbWluX2hpc3RvcnksCiAgICAgICAgICAgICAgWl9saXN0ID0gWl9saXN0LAogICAgICAgICAgICAgIFVfbGlzdCA9IFVfbGlzdCwKICAgICAgICAgICAgICBQX2xpc3QgPSBQX2xpc3QpKQp9CmBgYAoKCmBgYHtyfQpwbG90X2NvbnZlcmdlbmNlX2hpc3RvcnkgPC0gZnVuY3Rpb24oaGlzdG9yeV9kZiwgdG9sX2xpc3QgPSBOVUxMLCB0eXBlID0gInJlbGF0aXZlIikgewogIGlmICh0eXBlID09ICJyZWxhdGl2ZSIpewogICAgdGV4dF90aXRsZSA8LSAifFhfe2l0ZXJ9IC0gWF97aXRlci0xfXwgLyB8WF97aXRlcn18IgogIH0gZWxzZSBpZiAodHlwZSA9PSAiYWJzb2x1dGUiKSB7CiAgICB0ZXh0X3RpdGxlIDwtICJ8WF97ZXhhY3R9IC0gWF97aXRlcn18IgogIH0gZWxzZSBpZiAodHlwZSA9PSAibWluaW11bSIpIHsKICAgIHRleHRfdGl0bGUgPC0gIkooVV97aXRlcn0sel97aXRlcn0pIgogIH0KCiAgcCA8LSBnZ3Bsb3QoaGlzdG9yeV9kZiwgYWVzKHggPSBpdGVyLCB5ID0gdmFsdWUsIGNvbG9yID0gdmFyaWFibGUpKSArCiAgICBnZW9tX2xpbmUoKSArCiAgICBnZW9tX3BvaW50KHNpemUgPSAxLjUpICsKICAgIHNjYWxlX3lfbG9nMTAoKSArCiAgICBsYWJzKAogICAgICB0aXRsZSA9IHRleHRfdGl0bGUsCiAgICAgIHggPSAiSXRlcmF0aW9uIiwKICAgICAgeSA9ICJFcnJvciIsCiAgICAgIGNvbG9yID0gIlF1YW50aXR5IgogICAgKSArCiAgICB0aGVtZV9taW5pbWFsKCkKICAKICAjIEFkZCB0b2xlcmFuY2UgbGluZXMgaWYgcHJvdmlkZWQKICBpZiAoIWlzLm51bGwodG9sX2xpc3QpKSB7CiAgICB0b2xfZGYgPC0gZGF0YS5mcmFtZSgKICAgICAgdmFyaWFibGUgPSBuYW1lcyh0b2xfbGlzdCksCiAgICAgIHRvbCA9IHVubGlzdCh0b2xfbGlzdCkKICAgICkKICAgIHAgPC0gcCArIGdlb21faGxpbmUoCiAgICAgIGRhdGEgPSB0b2xfZGYsCiAgICAgIGFlcyh5aW50ZXJjZXB0ID0gdG9sLCBjb2xvciA9IHZhcmlhYmxlKSwKICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIgogICAgKQogIH0KICAKICByZXR1cm4ocGxvdGx5OjpnZ3Bsb3RseShwKSkKfQpgYGAKCmBgYHtyfQpsYXJnZXN0X25lc3RlZF9oIDwtIGZ1bmN0aW9uKGhfZmluZSwgaF9jYW5kaWRhdGUpIHsKICBOZmluZSA8LSByb3VuZCgxIC8gaF9maW5lKSAgICAgICAjIG51bWJlciBvZiBpbnRlcnZhbHMgaW4gZmluZSBtZXNoCiAgbTAgPC0gZmxvb3IoaF9jYW5kaWRhdGUgLyBoX2ZpbmUpCiAgCiAgYmVzdCA8LSAwCiAgciA8LSBmbG9vcihzcXJ0KE5maW5lKSkKICAKICBmb3IgKGEgaW4gMTpyKSB7CiAgICBpZiAoTmZpbmUgJSUgYSA9PSAwKSB7CiAgICAgIGIgPC0gTmZpbmUgLyBhCiAgICAgIGlmIChhIDw9IG0wICYmIGEgPiBiZXN0KSBiZXN0IDwtIGEKICAgICAgaWYgKGIgPD0gbTAgJiYgYiA+IGJlc3QpIGJlc3QgPC0gYgogICAgfQogIH0KICAKICAjIGlmIG5vIGRpdmlzb3IgZm91bmQsIGRlZmF1bHQgdG8gaF9maW5lCiAgaWYgKGJlc3QgPT0gMCkgYmVzdCA8LSAxCiAgCiAgaF9jb2Fyc2UgPC0gYmVzdCAqIGhfZmluZQogIHJldHVybihoX2NvYXJzZSkKfQpgYGAKCmBgYHtyfQp0cnVuY19maXJzdF9zaWduaV9kaWdpdCA8LSBmdW5jdGlvbih4KXsKICBhdXggPC0gZmxvb3IobG9nMTAoeCkpCiAgcmV0dXJuKGZsb29yKHggLyAxMF5hdXgpICogMTBeYXV4KQp9CmBgYAoKIyMgUGxvdHRpbmcgZnVuY3Rpb25zIHsjcGxvdHRpbmdfZnVuY3Rpb25zfQoKIyMjIEZ1bmN0aW9uIGBwbG90dGluZy5vcmRlcigpYAoKR2l2ZW4gYSB2ZWN0b3IgYHZgIGFuZCBhIGdyYXBoIG9iamVjdCBgZ3JhcGhgLCBmdW5jdGlvbiBgcGxvdHRpbmcub3JkZXIoKWAgb3JkZXJzIHRoZSBtZXNoIHZhbHVlcyBmb3IgcGxvdHRpbmcuCgpgYGB7cn0KIyBGdW5jdGlvbiB0byBvcmRlciB0aGUgdmVydGljZXMgZm9yIHBsb3R0aW5nCnBsb3R0aW5nLm9yZGVyIDwtIGZ1bmN0aW9uKHYsIGdyYXBoKXsKICBlZGdlX251bWJlciA8LSBncmFwaCRtZXNoJFZ0RVssIDFdCiAgcG9zIDwtIHN1bShlZGdlX251bWJlciA9PSAxKSsxCiAgcmV0dXJuKGModlsxXSwgdlszOnBvc10sIHZbMl0sIHZbKHBvcysxKTpsZW5ndGgodildLCB2WzJdKSkKfQpgYGAKCiMjIyBGdW5jdGlvbiBgZ2xvYmFsLnNjZW5lLnNldHRlcigpYAoKR2l2ZW4gcmFuZ2VzIGZvciB0aGUgYHhgLCBgeWAsIGFuZCBgemAgYXhlcywgYW5kIGFuIG9wdGlvbmFsIGFzcGVjdCByYXRpbyBmb3IgdGhlIGB6YCBheGlzLCBmdW5jdGlvbiBgZ2xvYmFsLnNjZW5lLnNldHRlcigpYCBzZXRzIHRoZSBzY2VuZSBmb3IgM0QgcGxvdHMgc28gdGhhdCBhbGwgcGxvdHMgaGF2ZSB0aGUgc2FtZSBhc3BlY3QgcmF0aW8gYW5kIGNhbWVyYSBwb3NpdGlvbi4KCmBgYHtyfQojIEZ1bmN0aW9uIHRvIHNldCB0aGUgc2NlbmUgZm9yIDNEIHBsb3RzCmdsb2JhbC5zY2VuZS5zZXR0ZXIgPC0gZnVuY3Rpb24oeF9yYW5nZSwgeV9yYW5nZSwgel9yYW5nZSwgel9hc3BlY3RyYXRpbyA9IDQpIHsKICAKICByZXR1cm4obGlzdCh4YXhpcyA9IGxpc3QodGl0bGUgPSAieCIsIHJhbmdlID0geF9yYW5nZSksCiAgICAgICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gInkiLCByYW5nZSA9IHlfcmFuZ2UpLAogICAgICAgICAgICAgIHpheGlzID0gbGlzdCh0aXRsZSA9ICJ6IiwgcmFuZ2UgPSB6X3JhbmdlKSwKICAgICAgICAgICAgICBhc3BlY3RyYXRpbyA9IGxpc3QoeCA9IDIqKDErMi9waSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gMiooMi9waSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB6ID0gel9hc3BlY3RyYXRpbyooMi9waSkpLAogICAgICAgICAgICAgIGNhbWVyYSA9IGxpc3QoZXllID0gbGlzdCh4ID0gKDErMi9waSkvMiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSA0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeiA9IDIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY2VudGVyID0gbGlzdCh4ID0gKDErMi9waSkvMiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeiA9IDApKSkpCn0KYGBgCgojIyMgRnVuY3Rpb24gYGdyYXBoLnBsb3R0ZXIuM2QoKWAKCkdpdmVuIGEgZ3JhcGggb2JqZWN0IGBncmFwaGAsIGEgc2VxdWVuY2Ugb2YgdGltZSBwb2ludHMgYHRpbWVfc2VxYCwgYW5kIG9uZSBvciBtb3JlIG1hdHJpY2VzIGAuLi5gIHJlcHJlc2VudGluZyBmdW5jdGlvbiB2YWx1ZXMgZGVmaW5lZCBvbiB0aGUgbWVzaCBvZiBgZ3JhcGhgIGF0IGVhY2ggdGltZSBpbiBgdGltZV9zZXFgLCB0aGUgYGdyYXBoLnBsb3R0ZXIuM2QoKWAgZnVuY3Rpb24gZ2VuZXJhdGVzIGFuIGludGVyYWN0aXZlIDNEIHZpc3VhbGl6YXRpb24gb2YgdGhlc2UgdmFsdWVzIG92ZXIgdGltZS4KCmBgYHtyfQojIEZ1bmN0aW9uIHRvIHBsb3QgaW4gM0QKZ3JhcGgucGxvdHRlci4zZC5vbGQgPC0gZnVuY3Rpb24oZ3JhcGgsIHRpbWVfc2VxLCBmcmFtZV92YWxfdG9fZGlzcGxheSwgLi4uKSB7CiAgVV9saXN0IDwtIGxpc3QoLi4uKQogIFVfbmFtZXMgPC0gc2FwcGx5KHN1YnN0aXR1dGUobGlzdCguLi4pKVstMV0sIGRlcGFyc2UpCgogICMgU3BhdGlhbCBjb29yZGluYXRlcwogIHggPC0gcGxvdHRpbmcub3JkZXIoZ3JhcGgkbWVzaCRWWywgMV0sIGdyYXBoKQogIHkgPC0gcGxvdHRpbmcub3JkZXIoZ3JhcGgkbWVzaCRWWywgMl0sIGdyYXBoKQogIHdlaWdodHMgPC0gZ3JhcGgkbWVzaCR3ZWlnaHRzCgogICMgQXBwbHkgcGxvdHRpbmcub3JkZXIgdG8gZWFjaCBVCiAgVV9saXN0IDwtIGxhcHBseShVX2xpc3QsIGZ1bmN0aW9uKFUpIGFwcGx5KFUsIDIsIHBsb3R0aW5nLm9yZGVyLCBncmFwaCA9IGdyYXBoKSkKICBuX3ZhcnMgPC0gbGVuZ3RoKFVfbGlzdCkKCiAgIyBDcmVhdGUgcGxvdF9kYXRhIGZyYW1lIHdpdGggdGltZSBhbmQgcG9zaXRpb24gcmVwbGljYXRlZAogIG5fdGltZSA8LSBuY29sKFVfbGlzdFtbMV1dKQogIGJhc2VfZGF0YSA8LSBkYXRhLmZyYW1lKAogICAgeCA9IHJlcCh4LCB0aW1lcyA9IG5fdGltZSksCiAgICB5ID0gcmVwKHksIHRpbWVzID0gbl90aW1lKSwKICAgIHRoZV9ncmFwaCA9IDAsCiAgICBmcmFtZSA9IHJlcCh0aW1lX3NlcSwgZWFjaCA9IGxlbmd0aCh4KSkKICApCgogICMgQWRkIFUgY29sdW1ucyB0byBwbG90X2RhdGEKICBmb3IgKGkgaW4gc2VxX2Fsb25nKFVfbGlzdCkpIHsKICAgIGJhc2VfZGF0YVtbcGFzdGUwKCJ1IiwgaSldXSA8LSBhcy52ZWN0b3IoVV9saXN0W1tpXV0pCiAgfQoKICBwbG90X2RhdGEgPC0gYmFzZV9kYXRhCgogICMgR2VuZXJhdGUgdmVydGljYWwgbGluZXMKICB2ZXJ0aWNhbF9saW5lc19saXN0IDwtIGxhcHBseShzZXFfYWxvbmcoVV9saXN0KSwgZnVuY3Rpb24oaSkgewogICAgZG8uY2FsbChyYmluZCwgbGFwcGx5KHRpbWVfc2VxLCBmdW5jdGlvbih0KSB7CiAgICAgIGlkeCA8LSB3aGljaChwbG90X2RhdGEkZnJhbWUgPT0gdCkKICAgICAgel92YWxzIDwtIHBsb3RfZGF0YVtbcGFzdGUwKCJ1IiwgaSldXVtpZHhdCiAgICAgIGRhdGEuZnJhbWUoCiAgICAgICAgeCA9IHJlcChwbG90X2RhdGEkeFtpZHhdLCBlYWNoID0gMyksCiAgICAgICAgeSA9IHJlcChwbG90X2RhdGEkeVtpZHhdLCBlYWNoID0gMyksCiAgICAgICAgeiA9IGFzLnZlY3Rvcih0KGNiaW5kKDAsIHpfdmFscywgTkEpKSksCiAgICAgICAgZnJhbWUgPSByZXAodCwgZWFjaCA9IGxlbmd0aChpZHgpICogMykKICAgICAgKQogICAgfSkpCiAgfSkKCiAgIyBTZXQgYXhpcyByYW5nZXMKICB6X3JhbmdlIDwtIHJhbmdlKHVubGlzdChVX2xpc3QpKQogIHhfcmFuZ2UgPC0gcmFuZ2UoeCkKICB5X3JhbmdlIDwtIHJhbmdlKHkpCgogICMgQ3JlYXRlIHBsb3QKICBwIDwtIHBsb3RfbHkocGxvdF9kYXRhLCBmcmFtZSA9IH5mcmFtZSkgJT4lCiAgICBhZGRfdHJhY2UoeCA9IH54LCB5ID0gfnksIHogPSB+dGhlX2dyYXBoLCB0eXBlID0gInNjYXR0ZXIzZCIsIG1vZGUgPSAibGluZXMiLAogICAgICAgICAgICAgIG5hbWUgPSAiIiwgc2hvd2xlZ2VuZCA9IEZBTFNFLAogICAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gImJsYWNrIiwgd2lkdGggPSAzKSkKCiAgIyBBZGQgdHJhY2VzIGZvciBlYWNoIHZhcmlhYmxlCiAgY29sb3JzIDwtIHJldih2aXJpZGlzTGl0ZTo6dmlyaWRpcyhuX3ZhcnMpKSAjUkNvbG9yQnJld2VyOjpicmV3ZXIucGFsKG1pbihuX3ZhcnMsIDgpLCAiU2V0MSIpCiAgZm9yIChpIGluIHNlcV9hbG9uZyhVX2xpc3QpKSB7CiAgICBwIDwtIGFkZF90cmFjZShwLAogICAgICB4ID0gfngsIHkgPSB+eSwgeiA9IGFzLmZvcm11bGEocGFzdGUwKCJ+dSIsIGkpKSwKICAgICAgdHlwZSA9ICJzY2F0dGVyM2QiLCBtb2RlID0gImxpbmVzIiwgbmFtZSA9IFVfbmFtZXNbaV0sCiAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gY29sb3JzW2ldLCB3aWR0aCA9IDMpKQogIH0KCiAgIyBBZGQgdmVydGljYWwgbGluZXMKICBmb3IgKGkgaW4gc2VxX2Fsb25nKHZlcnRpY2FsX2xpbmVzX2xpc3QpKSB7CiAgICBwIDwtIGFkZF90cmFjZShwLAogICAgICBkYXRhID0gdmVydGljYWxfbGluZXNfbGlzdFtbaV1dLAogICAgICB4ID0gfngsIHkgPSB+eSwgeiA9IH56LCBmcmFtZSA9IH5mcmFtZSwKICAgICAgdHlwZSA9ICJzY2F0dGVyM2QiLCBtb2RlID0gImxpbmVzIiwKICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAiZ3JheSIsIHdpZHRoID0gMC41KSwKICAgICAgbmFtZSA9ICJWZXJ0aWNhbCBsaW5lcyIsCiAgICAgIHNob3dsZWdlbmQgPSBGQUxTRSkKICB9CiAgZnJhbWVfbmFtZSA8LSBkZXBhcnNlKHN1YnN0aXR1dGUoZnJhbWVfdmFsX3RvX2Rpc3BsYXkpKQogICMgTGF5b3V0IGFuZCBhbmltYXRpb24gY29udHJvbHMKICBwIDwtIHAgJT4lCiAgICBsYXlvdXQoCiAgICAgIHNjZW5lID0gZ2xvYmFsLnNjZW5lLnNldHRlcih4X3JhbmdlLCB5X3JhbmdlLCB6X3JhbmdlKSwKICAgICAgdXBkYXRlbWVudXMgPSBsaXN0KGxpc3QodHlwZSA9ICJidXR0b25zIiwgc2hvd2FjdGl2ZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBidXR0b25zID0gbGlzdCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaXN0KGxhYmVsID0gIlBsYXkiLCBtZXRob2QgPSAiYW5pbWF0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcmdzID0gbGlzdChOVUxMLCBsaXN0KGZyYW1lID0gbGlzdChkdXJhdGlvbiA9IDIwMDAgLyBsZW5ndGgodGltZV9zZXEpLCByZWRyYXcgPSBUUlVFKSwgZnJvbWN1cnJlbnQgPSBUUlVFKSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3QobGFiZWwgPSAiUGF1c2UiLCBtZXRob2QgPSAiYW5pbWF0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcmdzID0gbGlzdChOVUxMLCBsaXN0KG1vZGUgPSAiaW1tZWRpYXRlIiwgZnJhbWUgPSBsaXN0KGR1cmF0aW9uID0gMCksIHJlZHJhdyA9IEZBTFNFKSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgKSksCiAgICAgIHRpdGxlID0gcGFzdGUwKGZyYW1lX25hbWUsIjogIiwgZm9ybWF0QyhmcmFtZV92YWxfdG9fZGlzcGxheVsxXSwgZm9ybWF0ID0gImYiLCBkaWdpdHMgPSA0KSkKICAgICkgJT4lCiAgICBwbG90bHlfYnVpbGQoKQoKICBmb3IgKGkgaW4gc2VxX2Fsb25nKHAkeCRmcmFtZXMpKSB7CiAgICBwJHgkZnJhbWVzW1tpXV0kbGF5b3V0IDwtIGxpc3QodGl0bGUgPSBwYXN0ZTAoZnJhbWVfbmFtZSwiOiAiLCBmb3JtYXRDKGZyYW1lX3ZhbF90b19kaXNwbGF5W2ldLCBmb3JtYXQgPSAiZiIsIGRpZ2l0cyA9IDQpKSkKICB9CgogIHJldHVybihwKQp9CmBgYAoKYGBge3J9CmdyYXBoLnBsb3R0ZXIuM2QgPC0gZnVuY3Rpb24oZ3JhcGgsIHRpbWVfc2VxLCBmcmFtZV92YWxfdG9fZGlzcGxheSwgVV9saXN0KSB7CiAgVV9uYW1lcyA8LSBuYW1lcyhVX2xpc3QpIAogICMgU3BhdGlhbCBjb29yZGluYXRlcwogIHggPC0gcGxvdHRpbmcub3JkZXIoZ3JhcGgkbWVzaCRWWywgMV0sIGdyYXBoKQogIHkgPC0gcGxvdHRpbmcub3JkZXIoZ3JhcGgkbWVzaCRWWywgMl0sIGdyYXBoKQogIHdlaWdodHMgPC0gZ3JhcGgkbWVzaCR3ZWlnaHRzCgogICMgQXBwbHkgcGxvdHRpbmcub3JkZXIgdG8gZWFjaCBVCiAgVV9saXN0IDwtIGxhcHBseShVX2xpc3QsIGZ1bmN0aW9uKFUpIGFwcGx5KFUsIDIsIHBsb3R0aW5nLm9yZGVyLCBncmFwaCA9IGdyYXBoKSkKICBuX3ZhcnMgPC0gbGVuZ3RoKFVfbGlzdCkKICAKICAjIENyZWF0ZSBwbG90X2RhdGEgZnJhbWUgd2l0aCB0aW1lIGFuZCBwb3NpdGlvbiByZXBsaWNhdGVkCiAgbl90aW1lIDwtIG5jb2woVV9saXN0W1sxXV0pCiAgYmFzZV9kYXRhIDwtIGRhdGEuZnJhbWUoCiAgICB4ID0gcmVwKHgsIHRpbWVzID0gbl90aW1lKSwKICAgIHkgPSByZXAoeSwgdGltZXMgPSBuX3RpbWUpLAogICAgdGhlX2dyYXBoID0gMCwKICAgIGZyYW1lID0gcmVwKHRpbWVfc2VxLCBlYWNoID0gbGVuZ3RoKHgpKQogICkKCiAgIyBBZGQgVSBjb2x1bW5zIHRvIHBsb3RfZGF0YQogIGZvciAoaSBpbiBzZXFfYWxvbmcoVV9saXN0KSkgewogICAgYmFzZV9kYXRhW1twYXN0ZTAoInUiLCBpKV1dIDwtIGFzLnZlY3RvcihVX2xpc3RbW2ldXSkKICB9CgogIHBsb3RfZGF0YSA8LSBiYXNlX2RhdGEKCiAgIyBHZW5lcmF0ZSB2ZXJ0aWNhbCBsaW5lcwogIHZlcnRpY2FsX2xpbmVzX2xpc3QgPC0gbGFwcGx5KHNlcV9hbG9uZyhVX2xpc3QpLCBmdW5jdGlvbihpKSB7CiAgICBkby5jYWxsKHJiaW5kLCBsYXBwbHkodGltZV9zZXEsIGZ1bmN0aW9uKHQpIHsKICAgICAgaWR4IDwtIHdoaWNoKHBsb3RfZGF0YSRmcmFtZSA9PSB0KQogICAgICB6X3ZhbHMgPC0gcGxvdF9kYXRhW1twYXN0ZTAoInUiLCBpKV1dW2lkeF0KICAgICAgZGF0YS5mcmFtZSgKICAgICAgICB4ID0gcmVwKHBsb3RfZGF0YSR4W2lkeF0sIGVhY2ggPSAzKSwKICAgICAgICB5ID0gcmVwKHBsb3RfZGF0YSR5W2lkeF0sIGVhY2ggPSAzKSwKICAgICAgICB6ID0gYXMudmVjdG9yKHQoY2JpbmQoMCwgel92YWxzLCBOQSkpKSwKICAgICAgICBmcmFtZSA9IHJlcCh0LCBlYWNoID0gbGVuZ3RoKGlkeCkgKiAzKQogICAgICApCiAgICB9KSkKICB9KQoKICAjIFNldCBheGlzIHJhbmdlcwogIHpfcmFuZ2UgPC0gcmFuZ2UodW5saXN0KFVfbGlzdCkpCiAgeF9yYW5nZSA8LSByYW5nZSh4KQogIHlfcmFuZ2UgPC0gcmFuZ2UoeSkKCiAgIyBDcmVhdGUgcGxvdAogIHAgPC0gcGxvdF9seShwbG90X2RhdGEsIGZyYW1lID0gfmZyYW1lKSAlPiUKICAgIGFkZF90cmFjZSh4ID0gfngsIHkgPSB+eSwgeiA9IH50aGVfZ3JhcGgsIHR5cGUgPSAic2NhdHRlcjNkIiwgbW9kZSA9ICJsaW5lcyIsCiAgICAgICAgICAgICAgbmFtZSA9ICIiLCBzaG93bGVnZW5kID0gRkFMU0UsCiAgICAgICAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAiYmxhY2siLCB3aWR0aCA9IDMpKQoKICBpZiAobl92YXJzID09IDIpIHsKICAgIGNvbG9ycyA8LSBSQ29sb3JCcmV3ZXI6OmJyZXdlci5wYWwobWluKG5fdmFycywgOCksICJTZXQxIikgCiAgICB9IGVsc2UgewogICAgY29sb3JzIDwtIHJldih2aXJpZGlzTGl0ZTo6dmlyaWRpcyhuX3ZhcnMpKSAKICB9CiAgIyBSQ29sb3JCcmV3ZXI6OmJyZXdlci5wYWwobWluKG5fdmFycywgOCksICJTZXQxIikKICBmb3IgKGkgaW4gc2VxX2Fsb25nKFVfbGlzdCkpIHsKICAgIHAgPC0gYWRkX3RyYWNlKHAsCiAgICAgIHggPSB+eCwgeSA9IH55LCB6ID0gYXMuZm9ybXVsYShwYXN0ZTAoIn51IiwgaSkpLAogICAgICB0eXBlID0gInNjYXR0ZXIzZCIsIG1vZGUgPSAibGluZXMiLCBuYW1lID0gVV9uYW1lc1tpXSwKICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSBjb2xvcnNbaV0sIHdpZHRoID0gMykpCiAgfQoKICAjIEFkZCB2ZXJ0aWNhbCBsaW5lcwogIGZvciAoaSBpbiBzZXFfYWxvbmcodmVydGljYWxfbGluZXNfbGlzdCkpIHsKICAgIHAgPC0gYWRkX3RyYWNlKHAsCiAgICAgIGRhdGEgPSB2ZXJ0aWNhbF9saW5lc19saXN0W1tpXV0sCiAgICAgIHggPSB+eCwgeSA9IH55LCB6ID0gfnosIGZyYW1lID0gfmZyYW1lLAogICAgICB0eXBlID0gInNjYXR0ZXIzZCIsIG1vZGUgPSAibGluZXMiLAogICAgICBsaW5lID0gbGlzdChjb2xvciA9ICJncmF5Iiwgd2lkdGggPSAwLjUpLAogICAgICBuYW1lID0gIlZlcnRpY2FsIGxpbmVzIiwKICAgICAgc2hvd2xlZ2VuZCA9IEZBTFNFKQogIH0KICBmcmFtZV9uYW1lIDwtIGRlcGFyc2Uoc3Vic3RpdHV0ZShmcmFtZV92YWxfdG9fZGlzcGxheSkpCiAgIyBMYXlvdXQgYW5kIGFuaW1hdGlvbiBjb250cm9scwogIHAgPC0gcCAlPiUKICAgIGxheW91dCgKICAgICAgc2NlbmUgPSBnbG9iYWwuc2NlbmUuc2V0dGVyKHhfcmFuZ2UsIHlfcmFuZ2UsIHpfcmFuZ2UpLAogICAgICB1cGRhdGVtZW51cyA9IGxpc3QobGlzdCh0eXBlID0gImJ1dHRvbnMiLCBzaG93YWN0aXZlID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ1dHRvbnMgPSBsaXN0KAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3QobGFiZWwgPSAiUGxheSIsIG1ldGhvZCA9ICJhbmltYXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFyZ3MgPSBsaXN0KE5VTEwsIGxpc3QoZnJhbWUgPSBsaXN0KGR1cmF0aW9uID0gMjAwMCAvIGxlbmd0aCh0aW1lX3NlcSksIHJlZHJhdyA9IFRSVUUpLCBmcm9tY3VycmVudCA9IFRSVUUpKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdChsYWJlbCA9ICJQYXVzZSIsIG1ldGhvZCA9ICJhbmltYXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFyZ3MgPSBsaXN0KE5VTEwsIGxpc3QobW9kZSA9ICJpbW1lZGlhdGUiLCBmcmFtZSA9IGxpc3QoZHVyYXRpb24gPSAwKSwgcmVkcmF3ID0gRkFMU0UpKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICApKSwKICAgICAgdGl0bGUgPSBwYXN0ZTAoZnJhbWVfbmFtZSwiOiAiLCBmb3JtYXRDKGZyYW1lX3ZhbF90b19kaXNwbGF5WzFdLCBmb3JtYXQgPSAiZiIsIGRpZ2l0cyA9IDQpKQogICAgKSAlPiUKICAgIHBsb3RseV9idWlsZCgpCgogIGZvciAoaSBpbiBzZXFfYWxvbmcocCR4JGZyYW1lcykpIHsKICAgIHAkeCRmcmFtZXNbW2ldXSRsYXlvdXQgPC0gbGlzdCh0aXRsZSA9IHBhc3RlMChmcmFtZV9uYW1lLCI6ICIsIGZvcm1hdEMoZnJhbWVfdmFsX3RvX2Rpc3BsYXlbaV0sIGZvcm1hdCA9ICJmIiwgZGlnaXRzID0gNCkpKQogIH0KCiAgcmV0dXJuKHApCn0KYGBgCgojIyMgRnVuY3Rpb24gYGVycm9yLmF0LmVhY2gudGltZS5wbG90dGVyKClgCgpHaXZlbiBhIGdyYXBoIG9iamVjdCBgZ3JhcGhgLCBhIG1hdHJpeCBgVV90cnVlYCBvZiB0cnVlIHZhbHVlcywgYSBtYXRyaXggYFVfYXBwcm94YCBvZiBhcHByb3hpbWF0ZWQgdmFsdWVzLCBhIHNlcXVlbmNlIG9mIHRpbWUgcG9pbnRzIGB0aW1lX3NlcWAsIGFuZCBhIHRpbWUgc3RlcCBgdGltZV9zdGVwYCwgZnVuY3Rpb24gYGVycm9yLmF0LmVhY2gudGltZS5wbG90dGVyKClgIGNvbXB1dGVzIHRoZSBlcnJvciBhdCBlYWNoIHRpbWUgc3RlcCBhbmQgZ2VuZXJhdGVzIGEgcGxvdCBzaG93aW5nIHRoZSBlcnJvciBvdmVyIHRpbWUuCgpgYGB7cn0KIyBGdW5jdGlvbiB0byBwbG90IHRoZSBlcnJvciBhdCBlYWNoIHRpbWUgc3RlcAplcnJvci5hdC5lYWNoLnRpbWUucGxvdHRlciA8LSBmdW5jdGlvbihncmFwaCwgVV90cnVlLCBVX2FwcHJveCwgdGltZV9zZXEsIHRpbWVfc3RlcCkgewogIHdlaWdodHMgPC0gZ3JhcGgkbWVzaCR3ZWlnaHRzCiAgZXJyb3JfYXRfZWFjaF90aW1lIDwtIHQod2VpZ2h0cykgJSolIChVX3RydWUgLSBVX2FwcHJveCleMgogIGVycm9yIDwtIHNxcnQoYXMuZG91YmxlKHQod2VpZ2h0cykgJSolIChVX3RydWUgLSBVX2FwcHJveCleMiAlKiUgcmVwKHRpbWVfc3RlcCwgbmNvbChVX3RydWUpKSkpCiAgcCA8LSBwbG90X2x5KCkgJT4lIAogIGFkZF90cmFjZSgKICB4ID0gfnRpbWVfc2VxLCB5ID0gfmVycm9yX2F0X2VhY2hfdGltZSwgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcyttYXJrZXJzJywKICBsaW5lID0gbGlzdChjb2xvciA9ICdibHVlJywgd2lkdGggPSAyKSwKICBtYXJrZXIgPSBsaXN0KGNvbG9yID0gJ2JsdWUnLCBzaXplID0gNCksCiAgbmFtZSA9ICIiLAogIHNob3dsZWdlbmQgPSBUUlVFCikgJT4lIAogIGxheW91dCgKICB0aXRsZSA9IHBhc3RlMCgiRXJyb3IgYXQgRWFjaCBUaW1lIFN0ZXAgKFRvdGFsIGVycm9yID0gIiwgZm9ybWF0QyhlcnJvciwgZm9ybWF0ID0gImYiLCBkaWdpdHMgPSA5KSwgIikiKSwKICB4YXhpcyA9IGxpc3QodGl0bGUgPSAidCIpLAogIHlheGlzID0gbGlzdCh0aXRsZSA9ICJFcnJvciIpLAogIGxlZ2VuZCA9IGxpc3QoeCA9IDAuMSwgeSA9IDAuOSkKKQogIHJldHVybihwKQp9CmBgYAoKIyMjIEZ1bmN0aW9uIGBncmFwaC5wbG90dGVyLjNkLmNvbXBhcmVyKClgCgpHaXZlbiBhIGdyYXBoIG9iamVjdCBgZ3JhcGhgLCBtYXRyaWNlcyBgVV90cnVlYCBhbmQgYFVfYXBwcm94YCByZXByZXNlbnRpbmcgdHJ1ZSBhbmQgYXBwcm94aW1hdGVkIHZhbHVlcywgYW5kIGEgc2VxdWVuY2Ugb2YgdGltZSBwb2ludHMgYHRpbWVfc2VxYCwgZnVuY3Rpb24gYGdyYXBoLnBsb3R0ZXIuM2QuY29tcGFyZXIoKWAgZ2VuZXJhdGVzIGEgM0QgcGxvdCBjb21wYXJpbmcgdGhlIHRydWUgYW5kIGFwcHJveGltYXRlZCB2YWx1ZXMgb3ZlciB0aW1lLCB3aXRoIGNvbG9yLWNvZGVkIHRyYWNlcyBmb3IgZWFjaCB0aW1lIHBvaW50LgoKYGBge3J9CiMgRnVuY3Rpb24gdG8gcGxvdCB0aGUgM0QgY29tcGFyaXNvbiBvZiBVX3RydWUgYW5kIFVfYXBwcm94CmdyYXBoLnBsb3R0ZXIuM2QuY29tcGFyZXIgPC0gZnVuY3Rpb24oZ3JhcGgsIFVfdHJ1ZSwgVV9hcHByb3gsIHRpbWVfc2VxKSB7CiAgeCA8LSBncmFwaCRtZXNoJFZbLCAxXTsgeSA8LSBncmFwaCRtZXNoJFZbLCAyXQogIHggPC0gcGxvdHRpbmcub3JkZXIoeCwgZ3JhcGgpOyB5IDwtIHBsb3R0aW5nLm9yZGVyKHksIGdyYXBoKQoKICBVX3RydWUgPC0gYXBwbHkoVV90cnVlLCAyLCBwbG90dGluZy5vcmRlciwgZ3JhcGggPSBncmFwaCkKICBVX2FwcHJveCA8LSBhcHBseShVX2FwcHJveCwgMiwgcGxvdHRpbmcub3JkZXIsIGdyYXBoID0gZ3JhcGgpCiAgbl90aW1lcyA8LSBsZW5ndGgodGltZV9zZXEpCiAgCiAgeF9yYW5nZSA8LSByYW5nZSh4KTsgeV9yYW5nZSA8LSByYW5nZSh5KTsgel9yYW5nZSA8LSByYW5nZShjKFVfdHJ1ZSwgVV9hcHByb3gpKQogIAogICMgTm9ybWFsaXplIHRpbWVfc2VxCiAgdGltZV9ub3JtYWxpemVkIDwtICh0aW1lX3NlcSAtIG1pbih0aW1lX3NlcSkpIC8gKG1heCh0aW1lX3NlcSkgLSBtaW4odGltZV9zZXEpKQogIGJsdWVzIDwtIGNvbG9yUmFtcFBhbGV0dGUoYygibGlnaHRibHVlIiwgImJsdWUiKSkobl90aW1lcykKICByZWRzIDwtIGNvbG9yUmFtcFBhbGV0dGUoYygibWlzdHlyb3NlIiwgInJlZCIpKShuX3RpbWVzKQogIAogICMgQWNjdXJhdGUgY29sb3JzY2FsZXMKICBjb2xvcnNjYWxlX2dyZWVucyA8LSBNYXAoZnVuY3Rpb24odCwgY29sKSBsaXN0KHQsIGNvbCksIHRpbWVfbm9ybWFsaXplZCwgYmx1ZXMpCiAgY29sb3JzY2FsZV9yZWRzIDwtIE1hcChmdW5jdGlvbih0LCBjb2wpIGxpc3QodCwgY29sKSwgdGltZV9ub3JtYWxpemVkLCByZWRzKQogIAogIHAgPC0gcGxvdF9seSgpCiAgCiAgIyBTdGF0aWMgYmxhY2sgZ3JhcGggc3RydWN0dXJlCiAgcCA8LSBwICU+JQogICAgYWRkX3RyYWNlKHggPSB4LCB5ID0geSwgeiA9IHJlcCgwLCBsZW5ndGgoeCkpLAogICAgICAgICAgICAgIHR5cGUgPSAic2NhdHRlcjNkIiwgbW9kZSA9ICJsaW5lcyIsCiAgICAgICAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAiYmxhY2siLCB3aWR0aCA9IDQpLAogICAgICAgICAgICAgIG5hbWUgPSAiR3JhcGgiLCBzaG93bGVnZW5kID0gRkFMU0UpCiAgCiAgIyBVX3RydWUgdHJhY2VzIChncmVlbikKICBmb3IgKGkgaW4gc2VxX2xlbihuX3RpbWVzKSkgewogICAgeiA8LSBVX3RydWVbLCBpXQogICAgcCA8LSBhZGRfdHJhY2UoCiAgICAgIHAsCiAgICAgIHR5cGUgPSAic2NhdHRlcjNkIiwKICAgICAgbW9kZSA9ICJsaW5lcyIsCiAgICAgIHggPSB4LCB5ID0geSwgeiA9IHosCiAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gYmx1ZXNbaV0sIHdpZHRoID0gNCksCiAgICAgIHNob3dsZWdlbmQgPSBGQUxTRSwKICAgICAgc2NlbmUgPSAic2NlbmUiCiAgICApCiAgfQogIAogICMgVV9hcHByb3ggdHJhY2VzIChkYXNoZWQgcmVkKQogIGZvciAoaSBpbiBzZXFfbGVuKG5fdGltZXMpKSB7CiAgICB6IDwtIFVfYXBwcm94WywgaV0KICAgIHAgPC0gYWRkX3RyYWNlKAogICAgICBwLAogICAgICB0eXBlID0gInNjYXR0ZXIzZCIsCiAgICAgIG1vZGUgPSAibGluZXMiLAogICAgICB4ID0geCwgeSA9IHksIHogPSB6LAogICAgICBsaW5lID0gbGlzdChjb2xvciA9IHJlZHNbaV0sIHdpZHRoID0gNCwgZGFzaCA9ICJkb3QiKSwKICAgICAgc2hvd2xlZ2VuZCA9IEZBTFNFLAogICAgICBzY2VuZSA9ICJzY2VuZSIKICAgICkKICB9CiAgCiAgIyBEdW1teSBncmVlbiBjb2xvcmJhciAoVHJ1ZSkg4oCTIHdpdGggdGlja3MKICBwIDwtIGFkZF90cmFjZSgKICAgIHAsCiAgICB0eXBlID0gImhlYXRtYXAiLAogICAgeiA9IG1hdHJpeCh0aW1lX3NlcSwgbnJvdyA9IDEpLAogICAgc2hvd3NjYWxlID0gVFJVRSwKICAgIGNvbG9yc2NhbGUgPSBjb2xvcnNjYWxlX2dyZWVucywKICAgIGNvbG9yYmFyID0gbGlzdCgKICAgICAgdGl0bGUgPSBsaXN0KGZvbnQgPSBsaXN0KHNpemUgPSAxMiwgY29sb3IgPSAiYmxhY2siKSwgdGV4dCA9ICJUaW1lIiwgc2lkZSA9ICJ0b3AiKSwKICAgICAgbGVuID0gMC45LAogICAgICB0aGlja25lc3MgPSAxNSwKICAgICAgeCA9IDEuMDIsCiAgICAgIHhhbmNob3IgPSAibGVmdCIsCiAgICAgIHkgPSAwLjUsCiAgICAgIHlhbmNob3IgPSAibWlkZGxlIiwKICAgICAgdGlja3ZhbHMgPSBOVUxMLCAgICMgaGlkZSB0aWNrIHZhbHVlcwogICAgICB0aWNrdGV4dCA9IE5VTEwsCiAgICAgIHRpY2tzID0gIiIgICAgICAgICAjIGFsc28gaGlkZXMgdGljayBtYXJrcwogICAgKSwKICAgIHggPSBtYXRyaXgodGltZV9zZXEsIG5yb3cgPSAxKSwKICAgIHkgPSBtYXRyaXgoMSwgbnJvdyA9IDEpLAogICAgaG92ZXJpbmZvID0gInNraXAiLAogICAgb3BhY2l0eSA9IDAKICApCgojIER1bW15IHJlZCBjb2xvcmJhciAoQXBwcm94KSDigJMgbm8gdGlja3MKICBwIDwtIGFkZF90cmFjZSgKICAgIHAsCiAgICB0eXBlID0gImhlYXRtYXAiLAogICAgeiA9IG1hdHJpeCh0aW1lX3NlcSwgbnJvdyA9IDEpLAogICAgc2hvd3NjYWxlID0gVFJVRSwKICAgIGNvbG9yc2NhbGUgPSBjb2xvcnNjYWxlX3JlZHMsCiAgICBjb2xvcmJhciA9IGxpc3QoCiAgICAgIHRpdGxlID0gbGlzdChmb250ID0gbGlzdChzaXplID0gMTIsIGNvbG9yID0gImJsYWNrIiksIHRleHQgPSAiLiIsIHNpZGUgPSAidG9wIiksCiAgICAgIGxlbiA9IDAuOSwKICAgICAgdGhpY2tuZXNzID0gMTUsCiAgICAgIHggPSAxLjA1LAogICAgICB4YW5jaG9yID0gImxlZnQiLAogICAgICB5ID0gMC41LAogICAgICB5YW5jaG9yID0gIm1pZGRsZSIKICAgICksCiAgICB4ID0gbWF0cml4KHRpbWVfc2VxLCBucm93ID0gMSksCiAgICB5ID0gbWF0cml4KDEsIG5yb3cgPSAxKSwKICAgIGhvdmVyaW5mbyA9ICJza2lwIiwKICAgIG9wYWNpdHkgPSAwCiAgKQogIHAgPC0gcCAlPiUKICAgIGFkZF90cmFjZSh4ID0geCwgeSA9IHksIHogPSByZXAoMCwgbGVuZ3RoKHgpKSwKICAgICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIzZCIsIG1vZGUgPSAibGluZXMiLAogICAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gImJsYWNrIiwgd2lkdGggPSA0KSwKICAgICAgICAgICAgICBuYW1lID0gIkdyYXBoIiwgc2hvd2xlZ2VuZCA9IEZBTFNFKQogIHAgPC0gbGF5b3V0KHAsCiAgICAgICAgICAgIHNjZW5lID0gZ2xvYmFsLnNjZW5lLnNldHRlcih4X3JhbmdlLCB5X3JhbmdlLCB6X3JhbmdlKSwKICAgICAgICAgICAgeGF4aXMgPSBsaXN0KHZpc2libGUgPSBGQUxTRSksCiAgICAgICAgICAgIHlheGlzID0gbGlzdCh2aXNpYmxlID0gRkFMU0UpLAogICAgICAgICAgICBhbm5vdGF0aW9ucyA9IGxpc3QoCiAgbGlzdCgKICAgIHRleHQgPSAiRXhhY3QiLAogICAgeCA9IDEuMDQ1LAogICAgeSA9IDAuNSwKICAgIHhyZWYgPSAicGFwZXIiLAogICAgeXJlZiA9ICJwYXBlciIsCiAgICBzaG93YXJyb3cgPSBGQUxTRSwKICAgIGZvbnQgPSBsaXN0KHNpemUgPSAxMiwgY29sb3IgPSAiYmxhY2siKSwKICAgIHRleHRhbmdsZSA9IC05MAogICksCiAgbGlzdCgKICAgIHRleHQgPSAiQXBwcm94IiwKICAgIHggPSAxLjA3NSwKICAgIHkgPSAwLjUsCiAgICB4cmVmID0gInBhcGVyIiwKICAgIHlyZWYgPSAicGFwZXIiLAogICAgc2hvd2Fycm93ID0gRkFMU0UsCiAgICBmb250ID0gbGlzdChzaXplID0gMTIsIGNvbG9yID0gImJsYWNrIiksCiAgICB0ZXh0YW5nbGUgPSAtOTAKICApCikKCikKCiAgCiAgcmV0dXJuKHApCn0KYGBgCgojIyMgRnVuY3Rpb24gYGdyYXBoLnBsb3R0ZXIuM2Quc2luZ2xlKClgCgpHaXZlbiBhIGdyYXBoIG9iamVjdCBgZ3JhcGhgLCBhIG1hdHJpeCBgVV90cnVlYCByZXByZXNlbnRpbmcgdHJ1ZSB2YWx1ZXMsIGFuZCBhIHNlcXVlbmNlIG9mIHRpbWUgcG9pbnRzIGB0aW1lX3NlcWAsIGZ1bmN0aW9uIGBncmFwaC5wbG90dGVyLjNkLnNpbmdsZSgpYCBnZW5lcmF0ZXMgYSAzRCBwbG90IG9mIHRoZSB0cnVlIHZhbHVlcyBvdmVyIHRpbWUsIHdpdGggY29sb3ItY29kZWQgdHJhY2VzIGZvciBlYWNoIHRpbWUgcG9pbnQuCgpgYGB7cn0KIyBGdW5jdGlvbiB0byBwbG90IGEgc2luZ2xlIDNEIGxpbmUgZm9yIApncmFwaC5wbG90dGVyLjNkLnNpbmdsZSA8LSBmdW5jdGlvbihncmFwaCwgVV90cnVlLCB0aW1lX3NlcSkgewogIHggPC0gZ3JhcGgkbWVzaCRWWywgMV07IHkgPC0gZ3JhcGgkbWVzaCRWWywgMl0KICB4IDwtIHBsb3R0aW5nLm9yZGVyKHgsIGdyYXBoKTsgeSA8LSBwbG90dGluZy5vcmRlcih5LCBncmFwaCkKCiAgVV90cnVlIDwtIGFwcGx5KFVfdHJ1ZSwgMiwgcGxvdHRpbmcub3JkZXIsIGdyYXBoID0gZ3JhcGgpCiAgbl90aW1lcyA8LSBsZW5ndGgodGltZV9zZXEpCiAgCiAgeF9yYW5nZSA8LSByYW5nZSh4KTsgeV9yYW5nZSA8LSByYW5nZSh5KTsgel9yYW5nZSA8LSByYW5nZShVX3RydWUpCiAgel9yYW5nZVsxXSA8LSB6X3JhbmdlWzFdIC0gMTBeLTYKICB2aXJpZGlzX2NvbG9ycyA8LSB2aXJpZGlzTGl0ZTo6dmlyaWRpcygxMDApCiAgCiAgIyBOb3JtYWxpemUgdGltZV9zZXEKICB0aW1lX25vcm1hbGl6ZWQgPC0gKHRpbWVfc2VxIC0gbWluKHRpbWVfc2VxKSkgLyAobWF4KHRpbWVfc2VxKSAtIG1pbih0aW1lX3NlcSkpCiAgI2dyZWVucyA8LSBjb2xvclJhbXBQYWxldHRlKGMoInBhbGVncmVlbiIsICJkYXJrZ3JlZW4iKSkobl90aW1lcykKICBncmVlbnMgPC0gY29sb3JSYW1wUGFsZXR0ZShjKHZpcmlkaXNfY29sb3JzWzFdLCB2aXJpZGlzX2NvbG9yc1s1MF0sICB2aXJpZGlzX2NvbG9yc1sxMDBdKSkobl90aW1lcykKICAjIEFjY3VyYXRlIGNvbG9yc2NhbGVzCiAgY29sb3JzY2FsZV9ncmVlbnMgPC0gTWFwKGZ1bmN0aW9uKHQsIGNvbCkgbGlzdCh0LCBjb2wpLCB0aW1lX25vcm1hbGl6ZWQsIGdyZWVucykKICAKICBwIDwtIHBsb3RfbHkoKQogIAogICMgQWRkIHRoZSAzRCBsaW5lcyB3aXRoIGZhZGluZyBncmVlbiBjb2xvcgogIGZvciAoaSBpbiBzZXFfbGVuKG5fdGltZXMpKSB7CiAgICB6IDwtIFVfdHJ1ZVssIGldCiAgICAKICAgIHAgPC0gYWRkX3RyYWNlKAogICAgICBwLAogICAgICB0eXBlID0gInNjYXR0ZXIzZCIsCiAgICAgIG1vZGUgPSAibGluZXMiLAogICAgICB4ID0geCwKICAgICAgeSA9IHksCiAgICAgIHogPSB6LAogICAgICBsaW5lID0gbGlzdChjb2xvciA9IGdyZWVuc1tpXSwgd2lkdGggPSAyKSwKICAgICAgc2hvd2xlZ2VuZCA9IEZBTFNFLAogICAgICBzY2VuZSA9ICJzY2VuZSIKICAgICkKICB9CiAgcCA8LSBwICU+JQogICAgYWRkX3RyYWNlKHggPSB4LCB5ID0geSwgeiA9IHJlcCgwLCBsZW5ndGgoeCkpLAogICAgICAgICAgICAgIHR5cGUgPSAic2NhdHRlcjNkIiwgbW9kZSA9ICJsaW5lcyIsCiAgICAgICAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAiYmxhY2siLCB3aWR0aCA9IDUpLAogICAgICAgICAgICAgIG5hbWUgPSAiR3JhcGgiLCBzaG93bGVnZW5kID0gRkFMU0UpCiAgIyBBZGQgZHVtbXkgaGVhdG1hcCB0byBzaG93IGNvbG9yYmFyIChub3QgcGFydCBvZiBzY2VuZSkKICBwIDwtIGFkZF90cmFjZSgKICAgIHAsCiAgICB0eXBlID0gImhlYXRtYXAiLAogICAgeiA9IG1hdHJpeCh0aW1lX3NlcSwgbnJvdyA9IDEpLAogICAgc2hvd3NjYWxlID0gVFJVRSwKICAgIGNvbG9yc2NhbGUgPSBjb2xvcnNjYWxlX2dyZWVucywKICAgIGNvbG9yYmFyID0gbGlzdCgKICAgIHRpdGxlID0gbGlzdChmb250ID0gbGlzdChzaXplID0gMTIsIGNvbG9yID0gImJsYWNrIiksIHRleHQgPSAiVGltZSIsIHNpZGUgPSAidG9wIiksCiAgICBsZW4gPSAwLjksICAgICAgICAgIyBoZWlnaHQgKDAgdG8gMSkKICAgIHRoaWNrbmVzcyA9IDE1LCAgICAgIyB3aWR0aCBpbiBwaXhlbHMKICAgIHggPSAxLjAyLCAgICAgICAgICAgIyBzaGlmdCBpdCBzbGlnaHRseSByaWdodCBvZiB0aGUgcGxvdAogICAgeGFuY2hvciA9ICJsZWZ0IiwKICAgIHkgPSAwLjUsCiAgICB5YW5jaG9yID0gIm1pZGRsZSIpLAogICAgeCA9IG1hdHJpeCh0aW1lX3NlcSwgbnJvdyA9IDEpLAogICAgeSA9IG1hdHJpeCgxLCBucm93ID0gMSksCiAgICBob3ZlcmluZm8gPSAic2tpcCIsCiAgICBvcGFjaXR5ID0gMAogICkKICAKICBwIDwtIGxheW91dChwLAogICAgICAgICAgICAgIHNjZW5lID0gZ2xvYmFsLnNjZW5lLnNldHRlcih4X3JhbmdlLCB5X3JhbmdlLCB6X3JhbmdlKSwKICAgICAgICAgICAgICB4YXhpcyA9IGxpc3QodmlzaWJsZSA9IEZBTFNFKSwKICAgICAgICAgICAgICB5YXhpcyA9IGxpc3QodmlzaWJsZSA9IEZBTFNFKQogICkKICAKICByZXR1cm4ocCkKfQpgYGAKCiMjIyBGdW5jdGlvbiBgZXJyb3IuY29udmVyZ2VuY2UucGxvdHRlcigpYAoKYGBge3J9CiMgRnVuY3Rpb24gdG8gcGxvdCB0aGUgZXJyb3IgY29udmVyZ2VuY2UKZXJyb3IuY29udmVyZ2VuY2UucGxvdHRlciA8LSBmdW5jdGlvbih4X2F4aXNfdmVjdG9yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYV92ZWN0b3IsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9ycywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlb3JldGljYWxfcmF0ZXMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ic2VydmVkX3JhdGVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmVfZXF1YXRpb25fZnVuLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpZ190aXRsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4X2F4aXNfbGFiZWwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXBwbHlfc3FydCA9IEZBTFNFKSB7CiAgCiAgeF92ZWMgPC0gaWYgKGFwcGx5X3NxcnQpIHNxcnQoeF9heGlzX3ZlY3RvcikgZWxzZSB4X2F4aXNfdmVjdG9yCiAgCiAgZ3VpZGluZ19saW5lcyA8LSBjb21wdXRlX2d1aWRpbmdfbGluZXMoeF9heGlzX3ZlY3RvciA9IHhfdmVjLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJvcnMgPSBlcnJvcnMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW9yZXRpY2FsX3JhdGVzID0gdGhlb3JldGljYWxfcmF0ZXMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmVfZXF1YXRpb25fZnVuID0gbGluZV9lcXVhdGlvbl9mdW4pCiAgCiAgZGVmYXVsdF9jb2xvcnMgPC0gc2NhbGVzOjpodWVfcGFsKCkobGVuZ3RoKGFscGhhX3ZlY3RvcikpCiAgCiAgcGxvdF9saW5lcyA8LSBsYXBwbHkoMTpuY29sKGd1aWRpbmdfbGluZXMpLCBmdW5jdGlvbihpKSB7CiAgICBnZW9tX2xpbmUoCiAgICAgIGRhdGEgPSBkYXRhLmZyYW1lKHggPSB4X3ZlYywgeSA9IGd1aWRpbmdfbGluZXNbLCBpXSksCiAgICAgIGFlcyh4ID0geCwgeSA9IHkpLAogICAgICBjb2xvciA9IGRlZmF1bHRfY29sb3JzW2ldLAogICAgICBsaW5ldHlwZSA9ICJkYXNoZWQiLAogICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFCiAgICApCiAgfSkKICAKICBkZiA8LSBhcy5kYXRhLmZyYW1lKGNiaW5kKHhfdmVjLCBlcnJvcnMpKQogIGNvbG5hbWVzKGRmKSA8LSBjKCJ4X2F4aXNfdmVjdG9yIiwgYWxwaGFfdmVjdG9yKQogIGRmX21lbHRlZCA8LSBtZWx0KGRmLCBpZC52YXJzID0gInhfYXhpc192ZWN0b3IiLCB2YXJpYWJsZS5uYW1lID0gImNvbHVtbiIsIHZhbHVlLm5hbWUgPSAidmFsdWUiKQogIAogIGN1c3RvbV9sYWJlbHMgPC0gcGFzdGUwKGZvcm1hdEMoYWxwaGFfdmVjdG9yLCBmb3JtYXQgPSAiZiIsIGRpZ2l0cyA9IDIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAiIHwgIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZm9ybWF0Qyh0aGVvcmV0aWNhbF9yYXRlcywgZm9ybWF0ID0gImYiLCBkaWdpdHMgPSA0KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIiB8ICIsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1hdEMob2JzZXJ2ZWRfcmF0ZXMsIGZvcm1hdCA9ICJmIiwgZGlnaXRzID0gNCkpCiAgCiAgZGZfbWVsdGVkJGNvbHVtbiA8LSBmYWN0b3IoZGZfbWVsdGVkJGNvbHVtbiwgbGV2ZWxzID0gYWxwaGFfdmVjdG9yLCBsYWJlbHMgPSBjdXN0b21fbGFiZWxzKQoKICBwIDwtIGdncGxvdCgpICsKICAgIGdlb21fbGluZShkYXRhID0gZGZfbWVsdGVkLCBhZXMoeCA9IHhfYXhpc192ZWN0b3IsIHkgPSB2YWx1ZSwgY29sb3IgPSBjb2x1bW4pKSArCiAgICBnZW9tX3BvaW50KGRhdGEgPSBkZl9tZWx0ZWQsIGFlcyh4ID0geF9heGlzX3ZlY3RvciwgeSA9IHZhbHVlLCBjb2xvciA9IGNvbHVtbikpICsKICAgIHBsb3RfbGluZXMgKwogICAgbGFicygKICAgICAgdGl0bGUgPSBmaWdfdGl0bGUsCiAgICAgIHggPSB4X2F4aXNfbGFiZWwsCiAgICAgIHkgPSBleHByZXNzaW9uKEVycm9yKSwKICAgICAgY29sb3IgPSAiICAgICAgICAgIM6xICB8IHRoZW8gIHwgb2JzIgogICAgKSArCiAgICAoaWYgKGFwcGx5X3NxcnQpIHsKICAgICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHhfdmVjLCBsYWJlbHMgPSByb3VuZCh4X2F4aXNfdmVjdG9yLCA0KSkKICAgIH0gZWxzZSB7CiAgICAgIHNjYWxlX3hfbG9nMTAoYnJlYWtzID0geF9heGlzX3ZlY3RvciwgbGFiZWxzID0gcm91bmQoeF9heGlzX3ZlY3RvciwgNCkpCiAgICB9KSArCiAgICAoaWYgKGFwcGx5X3NxcnQpIHsKICAgICAgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zID0gImxvZyIsIGxhYmVscyA9IHNjYWxlczo6c2NpZW50aWZpY19mb3JtYXQoKSkKICAgIH0gZWxzZSB7CiAgICAgIHNjYWxlX3lfbG9nMTAobGFiZWxzID0gc2NhbGVzOjpzY2llbnRpZmljX2Zvcm1hdCgpKQogICAgfSkgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIlBhbGF0aW5vIiksCiAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICAgIGxlZ2VuZC5kaXJlY3Rpb24gPSAidmVydGljYWwiLAogICAgICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMCwgMCwgMCwgMCksCiAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTgsIGZhY2UgPSAiYm9sZCIpKQogIAogIHJldHVybihwKQp9CgpgYGAKCgpgYGB7cn0KZ3JhcGgucGxvdHRlci4zZC5zdGF0aWMgPC0gZnVuY3Rpb24oZ3JhcGgsIHpfbGlzdCkgewogIHggPC0gcGxvdHRpbmcub3JkZXIoZ3JhcGgkbWVzaCRWWywgMV0sIGdyYXBoKQogIHkgPC0gcGxvdHRpbmcub3JkZXIoZ3JhcGgkbWVzaCRWWywgMl0sIGdyYXBoKQogIFVfbmFtZXMgPC0gbmFtZXMoel9saXN0KQogIG5fdmFycyA8LSBsZW5ndGgoel9saXN0KQogIHpfbGlzdCA8LSBsYXBwbHkoel9saXN0LCBmdW5jdGlvbih6KSBwbG90dGluZy5vcmRlcih6LCBncmFwaCkpCgogICMgQXhpcyByYW5nZXMKICB6X3JhbmdlIDwtIHJhbmdlKHVubGlzdCh6X2xpc3QpKQogIHhfcmFuZ2UgPC0gcmFuZ2UoeCkKICB5X3JhbmdlIDwtIHJhbmdlKHkpCgogIGlmIChuX3ZhcnMgPT0gMikgewogICAgY29sb3JzIDwtIFJDb2xvckJyZXdlcjo6YnJld2VyLnBhbChtaW4obl92YXJzLCA4KSwgIlNldDEiKSAKICAgIH0gZWxzZSB7CiAgICBjb2xvcnMgPC0gcmV2KHZpcmlkaXNMaXRlOjp2aXJpZGlzKG5fdmFycykpIAogIH0KICBwIDwtIHBsb3RfbHkoKQoKICBmb3IgKGkgaW4gc2VxX2Fsb25nKHpfbGlzdCkpIHsKICAgIHogPC0gel9saXN0W1tpXV0KCiAgICAjIE1haW4gM0QgY3VydmUKICAgIHAgPC0gYWRkX3RyYWNlKAogICAgICBwLAogICAgICB4ID0geCwgeSA9IHksIHogPSB6LAogICAgICB0eXBlID0gInNjYXR0ZXIzZCIsIG1vZGUgPSAibGluZXMiLAogICAgICBsaW5lID0gbGlzdChjb2xvciA9IGNvbG9yc1tpXSwgd2lkdGggPSAzKSwKICAgICAgbmFtZSA9IFVfbmFtZXNbaV0sIHNob3dsZWdlbmQgPSBUUlVFCiAgICApCgogICAgIyBFZmZpY2llbnQgdmVydGljYWwgbGluZXM6IG9uZSB0cmFjZSB3aXRoIGJyZWFrcyAoTkEpCiAgICB4X3ZlcnQgPC0gcmVwKHgsIGVhY2ggPSAzKQogICAgeV92ZXJ0IDwtIHJlcCh5LCBlYWNoID0gMykKICAgIHpfdmVydCA8LSB1bmxpc3QobGFwcGx5KHosIGZ1bmN0aW9uKHpqKSBjKDAsIHpqLCBOQSkpKQoKICAgIHAgPC0gYWRkX3RyYWNlKAogICAgICBwLAogICAgICB4ID0geF92ZXJ0LCB5ID0geV92ZXJ0LCB6ID0gel92ZXJ0LAogICAgICB0eXBlID0gInNjYXR0ZXIzZCIsIG1vZGUgPSAibGluZXMiLAogICAgICBsaW5lID0gbGlzdChjb2xvciA9ICJncmF5Iiwgd2lkdGggPSAwLjUpLAogICAgICBzaG93bGVnZW5kID0gRkFMU0UKICAgICkKICB9CiAgcCA8LSBwICU+JSBhZGRfdHJhY2UoeCA9IHgsIHkgPSB5LCB6ID0geCowLCB0eXBlID0gInNjYXR0ZXIzZCIsIG1vZGUgPSAibGluZXMiLAogICAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gImJsYWNrIiwgd2lkdGggPSAzKSwKICAgICAgICAgICAgICBuYW1lID0gInRoZWdyYXBoIiwgc2hvd2xlZ2VuZCA9IEZBTFNFKSAlPiUKICAgIGxheW91dChzY2VuZSA9IGdsb2JhbC5zY2VuZS5zZXR0ZXIoeF9yYW5nZSwgeV9yYW5nZSwgel9yYW5nZSkpCiAgcmV0dXJuKHApCn0KCmBgYAoKCmBgYHtyfQpncmFwaC5wbG90dGVyLjNkLnR3by5tZXNoZXMudGltZSA8LSBmdW5jdGlvbihncmFwaF9maW5lciwgZ3JhcGhfY29hcnNlciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpbWVfc2VxLCBmcmFtZV92YWxfdG9fZGlzcGxheSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnNfZmluZXIgPSBsaXN0KCksIGZzX2NvYXJzZXIgPSBsaXN0KCkpIHsKICAjIFNwYXRpYWwgY29vcmRpbmF0ZXMgKG9yZGVyZWQgZm9yIHBsb3R0aW5nKQogIHhfZmluZXIgPC0gcGxvdHRpbmcub3JkZXIoZ3JhcGhfZmluZXIkbWVzaCRWWywgMV0sIGdyYXBoX2ZpbmVyKQogIHlfZmluZXIgPC0gcGxvdHRpbmcub3JkZXIoZ3JhcGhfZmluZXIkbWVzaCRWWywgMl0sIGdyYXBoX2ZpbmVyKQogIHhfY29hcnNlciA8LSBwbG90dGluZy5vcmRlcihncmFwaF9jb2Fyc2VyJG1lc2gkVlssIDFdLCBncmFwaF9jb2Fyc2VyKQogIHlfY29hcnNlciA8LSBwbG90dGluZy5vcmRlcihncmFwaF9jb2Fyc2VyJG1lc2gkVlssIDJdLCBncmFwaF9jb2Fyc2VyKQogIAogIG5fdGltZSA8LSBpZiAobGVuZ3RoKGZzX2ZpbmVyKSA+IDApIG5jb2woZnNfZmluZXJbWzFdXSkgZWxzZSBuY29sKGZzX2NvYXJzZXJbWzFdXSkKCiAgIyBIZWxwZXI6IG1ha2UgZGF0YWZyYW1lIGZyb20gb25lIGZ1bmN0aW9uCiAgbWFrZV9kZiA8LSBmdW5jdGlvbihmX21hdCwgZ3JhcGgsIHgsIHksIG1lc2hfbmFtZSkgewogICAgeiA8LSBhcHBseShmX21hdCwgMiwgcGxvdHRpbmcub3JkZXIsIGdyYXBoID0gZ3JhcGgpCiAgICBkYXRhLmZyYW1lKAogICAgICB4ID0gcmVwKHgsIHRpbWVzID0gbl90aW1lKSwKICAgICAgeSA9IHJlcCh5LCB0aW1lcyA9IG5fdGltZSksCiAgICAgIHogPSBhcy52ZWN0b3IoeiksCiAgICAgIGZyYW1lID0gcmVwKHRpbWVfc2VxLCBlYWNoID0gbGVuZ3RoKHgpKSwKICAgICAgbWVzaCA9IG1lc2hfbmFtZQogICAgKQogIH0KICAKICAjIEJ1aWxkIGRhdGEgZm9yIGZpbmVyIGZ1bmN0aW9ucwogIGRhdGFfZmluZXJfbGlzdCA8LSBsYXBwbHkobmFtZXMoZnNfZmluZXIpLCBmdW5jdGlvbihubSkgewogICAgbWFrZV9kZihmc19maW5lcltbbm1dXSwgZ3JhcGhfZmluZXIsIHhfZmluZXIsIHlfZmluZXIsIG5tKQogIH0pCiAgCiAgIyBCdWlsZCBkYXRhIGZvciBjb2Fyc2VyIGZ1bmN0aW9ucwogIGRhdGFfY29hcnNlcl9saXN0IDwtIGxhcHBseShuYW1lcyhmc19jb2Fyc2VyKSwgZnVuY3Rpb24obm0pIHsKICAgIG1ha2VfZGYoZnNfY29hcnNlcltbbm1dXSwgZ3JhcGhfY29hcnNlciwgeF9jb2Fyc2VyLCB5X2NvYXJzZXIsIG5tKQogIH0pCiAgCiAgIyBDb21iaW5lCiAgYWxsX2RhdGEgPC0gYyhkYXRhX2ZpbmVyX2xpc3QsIGRhdGFfY29hcnNlcl9saXN0KQogIAogICMgQmFzZWxpbmUgZ3JhcGggKG9uIGZpbmVyIG1lc2ggZm9yIGNvbnNpc3RlbmN5KQogIGRhdGFfZ3JhcGggPC0gZGF0YS5mcmFtZSgKICAgIHggPSByZXAoeF9maW5lciwgdGltZXMgPSBuX3RpbWUpLAogICAgeSA9IHJlcCh5X2ZpbmVyLCB0aW1lcyA9IG5fdGltZSksCiAgICB6ID0gMCwKICAgIGZyYW1lID0gcmVwKHRpbWVfc2VxLCBlYWNoID0gbGVuZ3RoKHhfZmluZXIpKSwKICAgIG1lc2ggPSAiR3JhcGgiCiAgKQogIAojIC0tLS0tLS0tLSBWZXJ0aWNhbCBsaW5lcyBoZWxwZXIgLS0tLS0tLS0tLQp2ZXJ0aWNhbF9saW5lcyA8LSBmdW5jdGlvbih4LCB5LCB6LCBmcmFtZV92YWxzLCBtZXNoX25hbWUpIHsKICBkby5jYWxsKHJiaW5kLCBsYXBwbHkoc2VxX2Fsb25nKGZyYW1lX3ZhbHMpLCBmdW5jdGlvbihpKSB7CiAgICBpZHggPC0gKChpIC0gMSkgKiBsZW5ndGgoeCkgKyAxKTooaSAqIGxlbmd0aCh4KSkKICAgIGRhdGEuZnJhbWUoCiAgICAgIHggPSByZXAoeCwgZWFjaCA9IDMpLAogICAgICB5ID0gcmVwKHksIGVhY2ggPSAzKSwKICAgICAgeiA9IGFzLnZlY3Rvcih0KGNiaW5kKDAsIHpbaWR4XSwgTkEpKSksCiAgICAgIGZyYW1lID0gcmVwKGZyYW1lX3ZhbHNbaV0sIGVhY2ggPSBsZW5ndGgoeCkgKiAzKSwKICAgICAgbWVzaCA9IG1lc2hfbmFtZQogICAgKQogIH0pKQp9CgojIC0tLS0tLS0tLSBDb21wdXRlIHZlcnRpY2FsIGxpbmVzIHBlciBtZXNoIHVzaW5nIG1heCBhYnNvbHV0ZSB2YWx1ZSAtLS0tLS0tLS0KbWFrZV92ZXJ0aWNhbF9mcm9tX2xpc3QgPC0gZnVuY3Rpb24oZGF0YV9saXN0LCB4LCB5LCBtZXNoX25hbWUpIHsKICBpZiAobGVuZ3RoKGRhdGFfbGlzdCkgPT0gMCkgcmV0dXJuKE5VTEwpCiAgCiAgIyBSZXNoYXBlIGVhY2ggZnVuY3Rpb24ncyB6IGJhY2sgdG8gbWF0cml4OiAobm9kZXMgw5cgdGltZSkKICB6X21hdHMgPC0gbGFwcGx5KGRhdGFfbGlzdCwgZnVuY3Rpb24oZGYpIHsKICAgIG1hdHJpeChkZiR6LCBucm93ID0gbGVuZ3RoKHgpLCBuY29sID0gbGVuZ3RoKHRpbWVfc2VxKSkKICB9KQogIAogICMgU3RhY2sgaW50byAzRCBhcnJheTogKG5vZGVzIMOXIHRpbWUgw5cgZnVuY3Rpb25zKQogIGFyciA8LSBhcnJheSh1bmxpc3Qoel9tYXRzKSwgZGltID0gYyhsZW5ndGgoeCksIGxlbmd0aCh0aW1lX3NlcSksIGxlbmd0aCh6X21hdHMpKSkKICAKICAjIEZvciBlYWNoIG5vZGUgw5cgdGltZSwgc2VsZWN0IHRoZSBlbnRyeSB3aXRoIGxhcmdlc3QgYWJzb2x1dGUgdmFsdWUgKGtlZXAgc2lnbikKICBpZHggPC0gYXBwbHkoYXJyLCBjKDEsIDIpLCBmdW5jdGlvbih2KSB3aGljaC5tYXgoYWJzKHYpKSkKICB6X3NpZ25lZF9tYXggPC0gbWFwcGx5KGZ1bmN0aW9uKGksIGopIGFycltpLCBqLCBpZHhbaSwgal1dLAogICAgICAgICAgICAgICAgICAgICAgICAgcmVwKDE6bGVuZ3RoKHgpLCB0aW1lcyA9IGxlbmd0aCh0aW1lX3NlcSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgcmVwKDE6bGVuZ3RoKHRpbWVfc2VxKSwgZWFjaCA9IGxlbmd0aCh4KSkpCiAgCiAgIyBGbGF0dGVuIGJhY2sgaW50byBsb25nIHZlY3RvcgogIHpfc2lnbmVkX21heCA8LSBhcy52ZWN0b3Ioel9zaWduZWRfbWF4KQogIAogIHZlcnRpY2FsX2xpbmVzKHgsIHksIHpfc2lnbmVkX21heCwgdGltZV9zZXEsIG1lc2hfbmFtZSkKfQoKCnZlcnRpY2FsX2ZpbmVyICAgPC0gbWFrZV92ZXJ0aWNhbF9mcm9tX2xpc3QoZGF0YV9maW5lcl9saXN0LCAgIHhfZmluZXIsICAgeV9maW5lciwgICAiZmluZXIiKQp2ZXJ0aWNhbF9jb2Fyc2VyIDwtIG1ha2VfdmVydGljYWxfZnJvbV9saXN0KGRhdGFfY29hcnNlcl9saXN0LCB4X2NvYXJzZXIsIHlfY29hcnNlciwgImNvYXJzZXIiKQoKICAKICAjIENvbXB1dGUgcmFuZ2VzCiAgYWxsX3ogPC0gdW5saXN0KGxhcHBseShhbGxfZGF0YSwgZnVuY3Rpb24oZGYpIGRmJHopKQogIHhfcmFuZ2UgPC0gcmFuZ2UoYyh4X2ZpbmVyLCB4X2NvYXJzZXIpKQogIHlfcmFuZ2UgPC0gcmFuZ2UoYyh5X2ZpbmVyLCB5X2NvYXJzZXIpKQogIHpfcmFuZ2UgPC0gcmFuZ2UoYWxsX3opCiAgCiAgIyAtLS0tLS0tLS0gUGxvdGx5IG9iamVjdCAtLS0tLS0tLS0tCiAgcCA8LSBwbG90X2x5KGZyYW1lID0gfmZyYW1lKQogIAogICMgQWRkIHRyYWNlcyBmb3IgZmluZXIgKyBjb2Fyc2VyIChsb29waW5nIGF1dG9tYXRpY2FsbHkgd2l0aCBuYW1lcykKICBmb3IgKGRmIGluIGFsbF9kYXRhKSB7CiAgICBwIDwtIHAgJT4lCiAgICAgIGFkZF90cmFjZShkYXRhID0gZGYsCiAgICAgICAgICAgICAgICB4ID0gfngsIHkgPSB+eSwgeiA9IH56LAogICAgICAgICAgICAgICAgdHlwZSA9ICJzY2F0dGVyM2QiLCBtb2RlID0gImxpbmVzIiwKICAgICAgICAgICAgICAgIGxpbmUgPSBsaXN0KHdpZHRoID0gMyksCiAgICAgICAgICAgICAgICBuYW1lID0gdW5pcXVlKGRmJG1lc2gpKQogIH0KICAKICAjIEFkZCBiYXNlbGluZQogIHAgPC0gcCAlPiUKICAgIGFkZF90cmFjZShkYXRhID0gZGF0YV9ncmFwaCwKICAgICAgICAgICAgICB4ID0gfngsIHkgPSB+eSwgeiA9IH56LAogICAgICAgICAgICAgIHR5cGUgPSAic2NhdHRlcjNkIiwgbW9kZSA9ICJsaW5lcyIsCiAgICAgICAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAiYmxhY2siLCB3aWR0aCA9IDIpLAogICAgICAgICAgICAgIG5hbWUgPSAiR3JhcGgiLCBzaG93bGVnZW5kID0gRkFMU0UpCiAgCiMgQWRkIHZlcnRpY2FscyAob25lIHBlciBtZXNoLCBlbnZlbG9wZSBvZiBhbGwgZnVuY3Rpb25zKQppZiAoIWlzLm51bGwodmVydGljYWxfZmluZXIpKSB7CiAgcCA8LSBwICU+JQogICAgYWRkX3RyYWNlKGRhdGEgPSB2ZXJ0aWNhbF9maW5lciwKICAgICAgICAgICAgICB4ID0gfngsIHkgPSB+eSwgeiA9IH56LAogICAgICAgICAgICAgIHR5cGUgPSAic2NhdHRlcjNkIiwgbW9kZSA9ICJsaW5lcyIsCiAgICAgICAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAiZ3JheSIsIHdpZHRoID0gMC41KSwKICAgICAgICAgICAgICBuYW1lID0gIlZlcnRpY2FsIGZpbmVyIiwgc2hvd2xlZ2VuZCA9IEZBTFNFKQp9CmlmICghaXMubnVsbCh2ZXJ0aWNhbF9jb2Fyc2VyKSkgewogIHAgPC0gcCAlPiUKICAgIGFkZF90cmFjZShkYXRhID0gdmVydGljYWxfY29hcnNlciwKICAgICAgICAgICAgICB4ID0gfngsIHkgPSB+eSwgeiA9IH56LAogICAgICAgICAgICAgIHR5cGUgPSAic2NhdHRlcjNkIiwgbW9kZSA9ICJsaW5lcyIsCiAgICAgICAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSAiZ3JheSIsIHdpZHRoID0gMC41KSwKICAgICAgICAgICAgICBuYW1lID0gIlZlcnRpY2FsIGNvYXJzZXIiLCBzaG93bGVnZW5kID0gRkFMU0UpCn0KCiAgCiAgZnJhbWVfbmFtZSA8LSBkZXBhcnNlKHN1YnN0aXR1dGUoZnJhbWVfdmFsX3RvX2Rpc3BsYXkpKQogIAogIHAgPC0gcCAlPiUKICAgIGxheW91dCgKICAgICAgc2NlbmUgPSBnbG9iYWwuc2NlbmUuc2V0dGVyKHhfcmFuZ2UsIHlfcmFuZ2UsIHpfcmFuZ2UpLAogICAgICB1cGRhdGVtZW51cyA9IGxpc3QobGlzdCgKICAgICAgICB0eXBlID0gImJ1dHRvbnMiLCBzaG93YWN0aXZlID0gRkFMU0UsCiAgICAgICAgYnV0dG9ucyA9IGxpc3QoCiAgICAgICAgICBsaXN0KGxhYmVsID0gIlBsYXkiLCBtZXRob2QgPSAiYW5pbWF0ZSIsCiAgICAgICAgICAgICAgIGFyZ3MgPSBsaXN0KE5VTEwsIGxpc3QoZnJhbWUgPSBsaXN0KGR1cmF0aW9uID0gMjAwMCAvIGxlbmd0aCh0aW1lX3NlcSksIHJlZHJhdyA9IFRSVUUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZyb21jdXJyZW50ID0gVFJVRSkpKSwKICAgICAgICAgIGxpc3QobGFiZWwgPSAiUGF1c2UiLCBtZXRob2QgPSAiYW5pbWF0ZSIsCiAgICAgICAgICAgICAgIGFyZ3MgPSBsaXN0KE5VTEwsIGxpc3QobW9kZSA9ICJpbW1lZGlhdGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmcmFtZSA9IGxpc3QoZHVyYXRpb24gPSAwKSwgcmVkcmF3ID0gRkFMU0UpKSkKICAgICAgICApCiAgICAgICkpLAogICAgICB0aXRsZSA9IHBhc3RlMChmcmFtZV9uYW1lLCAiOiAiLCBmb3JtYXRDKGZyYW1lX3ZhbF90b19kaXNwbGF5WzFdLCBmb3JtYXQgPSAiZiIsIGRpZ2l0cyA9IDQpKQogICAgKSAlPiUKICAgIHBsb3RseV9idWlsZCgpCiAgCiAgIyBVcGRhdGUgZnJhbWUgdGl0bGVzCiAgZm9yIChpIGluIHNlcV9hbG9uZyhwJHgkZnJhbWVzKSkgewogICAgcCR4JGZyYW1lc1tbaV1dJGxheW91dCA8LSBsaXN0KAogICAgICB0aXRsZSA9IHBhc3RlMChmcmFtZV9uYW1lLCAiOiAiLCBmb3JtYXRDKGZyYW1lX3ZhbF90b19kaXNwbGF5W2ldLCBmb3JtYXQgPSAiZiIsIGRpZ2l0cyA9IDQpKQogICAgKQogIH0KICAKICByZXR1cm4ocCkKfQoKYGBgCgojIyBDaGVjayBub3JtIGlkZW50aXR5IHsjbm9ybV9pZGVudGl0eX0KClRoZSBmb2xsb3dpbmcgY29kZSBidWlsZHMgbWF0cml4ICRcYm9sZHN5bWJvbHtcbWF0aGZyYWt7Qn19JCBpbiBcZXFyZWZ7bWF0cml4Qn0gKG9iamVjdCBgYmlnX21hdHJpeGAgYmVsb3cpIGFuZCBjb21wYXJlcyBpdHMgMi1ub3JtIHRvIHRoYXQgb2YgbWF0cml4ICRcbWF0aGJme1R9JCBpbiBcZXFyZWZ7bWF0cml4VH0gKG9iamVjdCBgVFRgIGJlbG93KSB0aW1lcyAkXHRhdV4yJC4KCmBgYHtyLCBwdXJsID0gRkFMU0V9CiMgY2hlY2sgbm9ybSBpZGVudGl0eQpUX2ZpbmFsIDwtIDIKdGltZV9zdGVwIDwtIDAuMDAxIApoIDwtIDEKa2FwcGEgPC0gMTUKYWxwaGEgPC0gMC41IAptID0gMQpiZXRhIDwtIGFscGhhLzIKCmdyYXBoIDwtIGdldHMuZ3JhcGgudGFkcG9sZShoID0gaCkKZ3JhcGgkY29tcHV0ZV9mZW0oKQpHIDwtIGdyYXBoJG1lc2gkRwpDIDwtIGdyYXBoJG1lc2gkQwpMIDwtIGthcHBhXjIqQyArIEcKSSA8LSBNYXRyaXg6OkRpYWdvbmFsKG5yb3coQykpCgojIE51bWVyaWNhbCBzb2x1dGlvbgpvYmogPC0gbXkuZnJhY3Rpb25hbC5vcGVyYXRvcnMuZnJhYyhMLCBiZXRhLCBDLCBzY2FsZS5mYWN0b3IgPSBrYXBwYV4yLCBtID0gbSwgdGltZV9zdGVwKQpwYXJ0aWFsX2ZyYWN0aW9uX3Rlcm1zIDwtIG9iaiRwYXJ0aWFsX2ZyYWN0aW9uX3Rlcm1zCnJlc2lkdWVzIDwtIG9iaiRyZXNpZHVlcwpvdXRwdXQgPC0gSSowCmZvciAoaSBpbiAxOihtKzEpKSB7b3V0cHV0IDwtIG91dHB1dCArIHJlc2lkdWVzW2ldICogc29sdmUocGFydGlhbF9mcmFjdGlvbl90ZXJtc1tbaV1dLCBJKX0KUiA8LSBvdXRwdXQKCkNfc3FydCA8LSBleHBtOjpzcXJ0bShDKSAgICAgICAjIG1hdHJpeCBzcXVhcmUgcm9vdApPbWVnYSA8LSBDX3NxcnQgJSolIFIgJSolIENfc3FydApuIDwtIG5yb3coT21lZ2EpCk9tZWdhMiA8LSBPbWVnYSAlKiUgT21lZ2EKT21lZ2EzIDwtIE9tZWdhMiAlKiUgT21lZ2EKT21lZ2E0IDwtIE9tZWdhMiAlKiUgT21lZ2EyCk9tZWdhNSA8LSBPbWVnYTMgJSolIE9tZWdhMgpPbWVnYTYgPC0gT21lZ2EzICUqJSBPbWVnYTMKQjExIDwtIG1hdHJpeCgwLCBucm93ID0gbiwgbmNvbCA9IG4pCkIxMiA8LSBPbWVnYTIgKyBPbWVnYTQgKyBPbWVnYTYKQjEzIDwtIE9tZWdhMyArIE9tZWdhNQpCMTQgPC0gT21lZ2E0CgpCMjEgPC0gbWF0cml4KDAsIG5yb3cgPSBuLCBuY29sID0gbikKQjIyIDwtIE9tZWdhMyArIE9tZWdhNQpCMjMgPC0gT21lZ2EyICsgT21lZ2E0CkIyNCA8LSBPbWVnYTMKCkIzMSA8LSBtYXRyaXgoMCwgbnJvdyA9IG4sIG5jb2wgPSBuKQpCMzIgPC0gT21lZ2E0CkIzMyA8LSBPbWVnYTMKQjM0IDwtIE9tZWdhMgoKQjQxIDwtIG1hdHJpeCgwLCBucm93ID0gbiwgbmNvbCA9IG4pCkI0MiA8LSBtYXRyaXgoMCwgbnJvdyA9IG4sIG5jb2wgPSBuKQpCNDMgPC0gbWF0cml4KDAsIG5yb3cgPSBuLCBuY29sID0gbikKQjQ0IDwtIG1hdHJpeCgwLCBucm93ID0gbiwgbmNvbCA9IG4pCgpiaWdfbWF0cml4IDwtIHRpbWVfc3RlcF4yICogcmJpbmQoCiAgY2JpbmQoQjExLCBCMTIsIEIxMywgQjE0KSwKICBjYmluZChCMjEsIEIyMiwgQjIzLCBCMjQpLAogIGNiaW5kKEIzMSwgQjMyLCBCMzMsIEIzNCksCiAgY2JpbmQoQjQxLCBCNDIsIEI0MywgQjQ0KQopCgpvbWVnYSA8LSAxLygxK3RpbWVfc3RlcCAqIGthcHBhXigyKmJldGEpKQoKVFQgPC0gYnVpbGRfVF9mYXN0KG9tZWdhLCAzKQoKdGltZV9zdGVwXjIgKiBub3JtKFRULCB0eXBlID0gIjIiKQpub3JtKGJpZ19tYXRyaXgsIHR5cGUgPSAiMiIpCmBgYAoKIyMgQ29tcGFyaXNvbiBiZXR3ZWVuICRcZ2FtbWEkIGFuZCBpdHMgdXBwZXIgYm91bmQgJDEvKFxtdSBca2FwcGFeezQgXGJldGF9KSQgeyNjb250cmFjdGlvbl9jb25zdGFudF9jb21wYXJpc29ufQoKYGBge3IsIGV2YWwgPSBGQUxTRSwgcHVybCA9IEZBTFNFfQojIC0tLSAzLiBQYXJhbWV0ZXIgZ3JpZCAtLS0KVF9maW5hbCA8LSAyCnRhdV92ZWN0b3IgPC0gYygwLjAwMSwgMC4wMSwgMC4xKQpOX3ZlY3RvciA8LSBUX2ZpbmFsIC8gdGF1X3ZlY3RvcgprYXBwYV92ZWN0b3IgPC0gYygxLCA0LCAxNikKYmV0YV92ZWN0b3IgPC0gYygwLjUsIDAuNywgMC45KQptdV92ZWN0b3IgPC0gYygwLjEsIDEsIDEwKQoKcmVzdWx0cyA8LSBleHBhbmQuZ3JpZCgKICB0YXUgPSB0YXVfdmVjdG9yLAogIGthcHBhID0ga2FwcGFfdmVjdG9yLAogIGJldGEgPSBiZXRhX3ZlY3RvciwKICBtdSA9IG11X3ZlY3RvcgopCgojIC0tLSA0LiBQYXJhbGxlbCBjb21wdXRhdGlvbiB3aXRoIGNhY2hpbmcgKEEgZGVwZW5kcyBvbiDPiSBhbmQgTiBvbmx5KSAtLS0KY2FjaGUgPC0gbmV3LmVudihoYXNoID0gVFJVRSkKCnJlc3VsdHMkTF9jIDwtIHVubGlzdChwYm1jbGFwcGx5KAogIDE6bnJvdyhyZXN1bHRzKSwKICBmdW5jdGlvbihpKSB7CiAgICB0YXUgPC0gcmVzdWx0cyR0YXVbaV0KICAgIGthcHBhIDwtIHJlc3VsdHMka2FwcGFbaV0KICAgIGJldGEgPC0gcmVzdWx0cyRiZXRhW2ldCiAgICBtdSA8LSByZXN1bHRzJG11W2ldCiAgICAKICAgIG9tZWdhIDwtIDEgLyAoMSArIHRhdSAqIGthcHBhXigyICogYmV0YSkpCiAgICBOIDwtIGFzLmludGVnZXIoVF9maW5hbCAvIHRhdSkKICAgIGtleSA8LSBwYXN0ZTAocm91bmQob21lZ2EsIDEwKSwgIl8iLCBOKQogICAgCiAgICBpZiAoZXhpc3RzKGtleSwgZW52aXIgPSBjYWNoZSkpIHsKICAgICAgbGFtYmRhX21heCA8LSBnZXQoa2V5LCBlbnZpciA9IGNhY2hlKQogICAgfSBlbHNlIHsKICAgICAgQSA8LSBidWlsZF9UX2Zhc3Qob21lZ2EsIE4pCiAgICAgIGxhbWJkYV9tYXggPC0gbWF4KGVpZ2VuKEEsIHN5bW1ldHJpYyA9IFRSVUUsIG9ubHkudmFsdWVzID0gVFJVRSkkdmFsdWVzKQogICAgICBhc3NpZ24oa2V5LCBsYW1iZGFfbWF4LCBlbnZpciA9IGNhY2hlKQogICAgfQogICAgCiAgICAodGF1XjIgKiBsYW1iZGFfbWF4KSAvIG11CiAgfSwKICBtYy5jb3JlcyA9IHBhcmFsbGVsOjpkZXRlY3RDb3JlcygpCikpCgpzYXZlKHJlc3VsdHMsIGZpbGUgPSBoZXJlOjpoZXJlKCJkYXRhX2ZpbGVzL2NvbnRyYWN0aW9uX2NvbnN0YW50X3Jlc3VsdHMyLlJEYXRhIikpCmBgYAoKCmBgYHtyLCBldmFsID0gVFJVRSwgcHVybCA9IEZBTFNFfQpsaWJyYXJ5KHBibWNhcHBseSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShkcGx5cikKbGlicmFyeShwYXRjaHdvcmspClRfZmluYWwgPC0gMgpsb2FkKGhlcmU6OmhlcmUoImRhdGFfZmlsZXMvY29udHJhY3Rpb25fY29uc3RhbnRfcmVzdWx0czIuUkRhdGEiKSkKYWxsX3Jlc3VsdHMgPC0gcmVzdWx0cyAlPiUgCiAgbXV0YXRlKHVwcGVyYm91bmQgPSAxLyhtdSprYXBwYV4oNCpiZXRhKSkpICU+JQogIG11dGF0ZShUX2ZpbmFsID0gVF9maW5hbCkgJT4lCiAgbXV0YXRlKE4gPSBUX2ZpbmFsL3RhdSkgJT4lCiAgbXV0YXRlKExfY2xlc3MxID0gTF9jIDwgMSkgJT4lCiAgbXV0YXRlKFRsZXNzbXVrYXBwYTJiZXRhID0gVF9maW5hbCA8IChtdSAqIGthcHBhXigyKmJldGEpKSkgJT4lCiAgbXV0YXRlKG9uZWxlc3NtdWthcHBhNGJldGEgID0gdXBwZXJib3VuZCA8IDEpIAoKCiMgRmluZCBjb21iaW5lZCB5LWxpbWl0cwp5bWluIDwtIG1pbihhbGxfcmVzdWx0cyRMX2MsIGFsbF9yZXN1bHRzJHVwcGVyYm91bmQsIG5hLnJtID0gVFJVRSkKeW1heCA8LSBtYXgoYWxsX3Jlc3VsdHMkTF9jLCBhbGxfcmVzdWx0cyR1cHBlcmJvdW5kLCBuYS5ybSA9IFRSVUUpCgpwIDwtIGdncGxvdChhbGxfcmVzdWx0cywgYWVzKHggPSBOLCB5ID0gTF9jLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gZmFjdG9yKGthcHBhKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IGZhY3RvcihiZXRhKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaW5ldHlwZSA9IGZhY3RvcihtdSkpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMykgKwogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBpbnRlcmFjdGlvbihrYXBwYSwgYmV0YSwgbXUpKSwgYWxwaGEgPSAxKSArCiAgc2NhbGVfeF9sb2cxMCgpICsKICBzY2FsZV95X2xvZzEwKAogICAgbGltaXRzID0gYyh5bWluLCB5bWF4KSwKICAgIGJyZWFrcyA9IHRyYW5zX2JyZWFrcygibG9nMTAiLCBmdW5jdGlvbih4KSAxMF54KSwKICAgIGxhYmVscyA9IGxhYmVsX3NjaWVudGlmaWMoKQogICkgKwogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKCJzb2xpZCIsICJkYXNoZWQiLCAiZG90dGVkIikpICsKICBsYWJzKHggPSAiTiIsCiAgICAgICB5ID0gZXhwcmVzc2lvbihnYW1tYSksCiAgICAgICBjb2xvciA9IGV4cHJlc3Npb24oa2FwcGEpLAogICAgICAgc2hhcGUgPSBleHByZXNzaW9uKGJldGEpLAogICAgICAgbGluZXR5cGUgPSBleHByZXNzaW9uKG11KSkgKwogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTQsIGJhc2VfZmFtaWx5ID0gIlBhbGF0aW5vIikKCnEgPC0gZ2dwbG90KGFsbF9yZXN1bHRzLCBhZXMoeCA9IE4sIHkgPSB1cHBlcmJvdW5kLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gZmFjdG9yKGthcHBhKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IGZhY3RvcihiZXRhKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaW5ldHlwZSA9IGZhY3RvcihtdSkpKSArCiAgZ2VvbV9wb2ludChzaXplID0gMykgKwogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBpbnRlcmFjdGlvbihrYXBwYSwgYmV0YSwgbXUpKSwgYWxwaGEgPSAxKSArCiAgc2NhbGVfeF9sb2cxMCgpICsKICBzY2FsZV95X2xvZzEwKAogICAgbGltaXRzID0gYyh5bWluLCB5bWF4KSwKICAgIGJyZWFrcyA9IHRyYW5zX2JyZWFrcygibG9nMTAiLCBmdW5jdGlvbih4KSAxMF54KSwKICAgIGxhYmVscyA9IGxhYmVsX3NjaWVudGlmaWMoKSwKICAgIHBvc2l0aW9uID0gInJpZ2h0IgogICkgKwogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKCJzb2xpZCIsICJkYXNoZWQiLCAiZG90dGVkIikpICsKICBsYWJzKHggPSAiTiIsCiAgICAgICB5ID0gZXhwcmVzc2lvbigxIC8gbXUgKiBrYXBwYV57NCAqIGJldGF9KSwKICAgICAgIGNvbG9yID0gZXhwcmVzc2lvbihrYXBwYSksCiAgICAgICBzaGFwZSA9IGV4cHJlc3Npb24oYmV0YSksCiAgICAgICBsaW5ldHlwZSA9IGV4cHJlc3Npb24obXUpKSArCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCwgYmFzZV9mYW1pbHkgPSAiUGFsYXRpbm8iKQoKCmNvbWJpbmVkMiA8LSAocCB8IHEpICsgCiAgcGxvdF9hbm5vdGF0aW9uKAogICAgdGl0bGUgPSBleHByZXNzaW9uKCJDb250cmFjdGlvbiBjb25zdGFudCAiICogZ2FtbWEgKiAiIGFuZCBpdHMgdXBwZXIgYm91bmQgIiAqIDEgLyBtdSAqIGthcHBhXns0ICogYmV0YX0pLAogICAgdGhlbWUgPSB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCwgZmFjZSA9ICJib2xkIiwgaGp1c3QgPSAwLjUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhbWlseSA9ICJQYWxhdGlubyIpKQogICkgKwogIHBsb3RfbGF5b3V0KGd1aWRlcyA9ICJjb2xsZWN0IikgJiAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKYGBgCgoKYGBge3IsIGV2YWwgPSBUUlVFLCBwdXJsID0gRkFMU0UsIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLmRpbT0gYygxMiw3KSwgZmlnLmNhcCA9IGNhcHRpb25lcigiQ29tcGFyaXNvbiBvZiB0aGUgY29udHJhY3Rpb24gY29uc3RhbnQgJFxcZ2FtbWEgPSAgXFx0YXVeMlxcfFxcbWF0aGJme1R9XFx8XzIvXFxtdSQgYW5kIGl0cyB0aGVvcmV0aWNhbCB1cHBlciBib3VuZCAkMSAvIChcXG11IFxca2FwcGFeezQgXFxiZXRhfSkkIGFzIGZ1bmN0aW9ucyBvZiB0aGUgc2FtcGxlIHNpemUgJE4kIGZvciAkVCA9IDIkLiBEaWZmZXJlbnQgY29sb3JzLCBzaGFwZXMsIGFuZCBsaW5lIHR5cGVzIGNvcnJlc3BvbmQgdG8gdmFyaWF0aW9ucyBpbiAkXFxrYXBwYSQsICRcXGJldGEkLCBhbmQgJFxcbXUkLCByZXNwZWN0aXZlbHkuIEJvdGggcGxvdHMgaGF2ZSB0aGVpciB4LSBhbmQgeS1heGVzIG9uIGEgJFxcbG9nX3sxMH0kIHNjYWxlLCBhbmQgdGhleSBzaGFyZSB0aGUgc2FtZSB5LWF4aXMgbGltaXRzIGZvciBkaXJlY3QgY29tcGFyYWJpbGl0eS4iKX0KY29tYmluZWQyCmBgYAoKCmBgYHtyLCBldmFsID0gVFJVRSwgcHVybCA9IEZBTFNFfQpnZ3NhdmUoCiAgaGVyZTo6aGVyZSgiZGF0YV9maWxlcy9maXhlZHBvaW50Y29udmVyZ2VuY2VfY29tYmluZWQyLnBuZyIpLAogIHdpZHRoID0gMTIsIGhlaWdodCA9IDcsIHBsb3QgPSBjb21iaW5lZDIsIGRwaSA9IDMwMAopCmBgYAoKCiMjIFJlZmVyZW5jZXMKCmBgYHtyLCBwdXJsID0gRkFMU0V9CmdyYXRlZnVsOjpjaXRlX3BhY2thZ2VzKG91dHB1dCA9ICJwYXJhZ3JhcGgiLCBvdXQuZGlyID0gIi4iKQpgYGAKCgo=