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 Theoretical stuff

We consider the equation

\[ \left(\kappa^{2}-\Delta\right)^{\alpha / 2}(\tau u)=\mathcal{W} \quad \text { on } \Gamma. \tag{0} \label{spde_equation} \]

The Matérn covariance function is given by

\[ \varrho_M(h)=\frac{\tau^{-2}}{2^{\nu-1} \Gamma(\nu+n / 2)(4 \pi)^{n / 2} \kappa^{2 \nu}}(\kappa|h|)^\nu K_\nu(\kappa|h|), \tag{1} \label{matern_cov} \]

where \(n=1\) and the parameters \(\tau, \kappa>0\) and \(0<\nu \leq 1 / 2\) control the variance, practical correlation range, and the sample path regularity, respectively. Further, \(K_\nu(\cdot)\) is a modified Bessel function of the second kind and \(\Gamma(\cdot)\) denotes the gamma function.

From (Bolin, Simas, and Wallin 2023c, Proposition 5), we know that

\[ \mathbf{r}: \mathbb{R} \times \mathbb{R} \mapsto \mathbb{R}^{\alpha \times \alpha}, \quad \mathbf{r}\left(t_1, t_2\right)=\left[\frac{\partial^{i-1}}{\partial t_2^{i-1}} \frac{\partial^{j-1}}{\partial t_1^{j-1}} \varrho_M\left(t_1-t_2\right)\right]_{i j \in\{1,2, \ldots, \alpha\}} \tag{2} \label{r_matrix} \] is the covariance function of \(\mathbf{x}(t)=\left[x(t), x'(t), \ldots, x^{(\alpha-1)}(t)\right]^{\top}\) if \(x\) is a centered Gaussian process on \(\mathbb{R}\) with Matérn covariance function with \(\nu = \alpha-1/2\) and \(\alpha \in \mathbb{N}\).

Let \(\mathbf{r}(\cdot, \cdot)\) be given by \(\eqref{r_matrix}\) with \(\alpha \in \mathbb{N}\). Then, from (Bolin, Simas, and Wallin 2023c, Proposition 6), for \(\ell>0\),

\[ \widetilde{\mathbf{r}}_{\ell}\left(t_1, t_2\right)=\mathbf{r}\left(t_1, t_2\right)+\left[\mathbf{r}\left(t_1, 0\right) \mathbf{r}\left(t_1, \ell\right)\right]\left[\begin{array}{cc} \mathbf{r}(0,0) & -\mathbf{r}(0, \ell) \\ -\mathbf{r}(\ell, 0) & \mathbf{r}(0,0) \end{array}\right]^{-1}\left[\begin{array}{l} \mathbf{r}\left(t_2, 0\right) \\ \mathbf{r}\left(t_2, \ell\right) \end{array}\right] \tag{3} \label{r_tilde_matrix} \]

is the multivariate covariance function of the multivariate process \(\widetilde{\mathbf{x}}(t)=\left[\widetilde{x}(t), \widetilde{x}^{\prime}(t), \ldots, \widetilde{x}^{(\alpha-1)}(t)\right]^{\top}\) on the interval \([0, \ell]\), where \(\widetilde{x}\) is the boundaryless Whittle–Matérn process on \([0, \ell]\).

Let

\[ \mathcal{K}_\alpha(x)=\left\{\omega \in \Omega: \forall v \in \mathcal{V} \text { and each pair } e, \widetilde{e} \in \mathcal{E}_v, x_e^{(2 k)}(v, \omega)=x_{\widetilde{e}}^{(2 k)}(v, \omega) \text {, and } \sum_{e \in \mathcal{E}_v} \partial_e x_e^{2 k+1}(v, \omega)=0, k=0, \ldots,\lceil\alpha-1 / 2\rceil-1\right\} \tag{4} \label{K_alpha} \]

and \(\widetilde{u} = \{\widetilde{u}_e:e\in\mathcal{E}\}\) be a family of independent boundaryless Whittle–Matérn process on the edges. Further, let

\[ \widetilde{\mathbf{u}}(s)=\left[\widetilde{u}(s), \widetilde{u}^{\prime}(s),\ldots, \widetilde{u}^{(\alpha-1)}(s)\right]^{\top}=\sum_{e \in \mathcal{E}} \mathbb{I}(s \in e) \widetilde{\mathbf{u}}_e(s) \in\mathbb{R}^{\alpha}. \tag{5} \label{u_vector} \] From (Bolin, Simas, and Wallin 2023c, Theorem 4), if we define

\[ \mathbf{u}(s) = \widetilde{\mathbf{u}}(s)| \mathcal{K}_\alpha(\widetilde{u}), \tag{6} \label{u_vector_constrained} \]

then \(u(\cdot)\), the first entry of \(\mathbf{u}(\cdot)\), is a solution to \(\eqref{spde_equation}\).

The precision matrix of \([\widetilde{\mathbf{u}}(0), \widetilde{\mathbf{u}}(\ell)]\) is

\[ \widetilde{\mathbf{Q}}_e=\mathbf{Q}_e-\frac{1}{2}\left[\begin{array}{cc} \mathbf{r}(0,0)^{-1} & \mathbf{0} \\ \mathbf{0} & \mathbf{r}(0,0)^{-1} \end{array}\right]\in\mathbb{R}^{2 \alpha \times 2 \alpha}, \tag{7} \label{Q_tilde_e} \]

where \(\mathbf{Q}_e\) is the precision matrix of \([\mathbf{u}(0), \mathbf{u}(\ell)]\).

Let \[ \mathbf{U}=\left[\mathbf{u}(\underline{e}_1)^{\top}, \mathbf{u}(\overline{e}_1)^{\top}, \mathbf{u}(\underline{e}_2)^{\top}, \mathbf{u}(\overline{e}_2)^{\top}, \ldots, \mathbf{u}(\underline{e}_{|\mathcal{E}|})^{\top}, \mathbf{u}(\overline{e}_{|\mathcal{E}|})^{\top}\right]^{\top}\in\mathbb{R}^{2 \alpha|\mathcal{E}|} \tag{8} \label{U_vector} \]

and

\[ \widetilde{\mathbf{U}}=\left[\widetilde{\mathbf{u}}_1(\underline{e}_1)^{\top}, \widetilde{\mathbf{u}}_1(\overline{e}_1)^{\top}, \widetilde{\mathbf{u}}_2(\underline{e}_2)^{\top}, \widetilde{\mathbf{u}}_2(\overline{e}_2)^{\top}, \ldots, \widetilde{\mathbf{u}}_{|\mathcal{E}|}(\underline{e}_{|\mathcal{E}|})^{\top}, \widetilde{\mathbf{u}}_{|\mathcal{E}|}(\overline{e}_{|\mathcal{E}|})^{\top}\right]^{\top}\in\mathbb{R}^{2 \alpha|\mathcal{E}|} \tag{9} \label{U_vector_tilde} \] We then have that

\[ \widetilde{\mathbf{U}}\sim \mathrm{N}\left(\mathbf{0}, \widetilde{\mathbf{Q}}^{-1}\right), \quad \widetilde{\mathbf{Q}} = \operatorname{diag}\left(\{\mathbf{Q}_e\}_{e\in\mathcal{E}}\right), \tag{10} \label{U_vector_tilde_distribution} \]

where \(\mathbf{Q}_e\) is the precision matrix of \([\widetilde{\mathbf{u}}_e(\underline{e}), \widetilde{\mathbf{u}}_e(\overline{e})]\).

The Kirchhoff conditions \(\eqref{K_alpha}\) can be written as a system of linear equations

\[ \mathbf{K} \widetilde{\mathbf{U}}=\mathbf{0}, \tag{11} \label{K_alpha_matrix} \]

where \(\mathbf{K}\in\mathbb{R}^{k\times 2\alpha|\mathcal{E}|}\) is a suitable matrix and \(k\) is the number of linear constraints given by \(\eqref{K_alpha}\).

Finally,

\[ \mathbf{U}=\widetilde{\mathbf{U}}| \{\mathbf{K} \widetilde{\mathbf{U}}=\mathbf{0}\}\sim\mathrm{N}\left(\mathbf{0}, \widetilde{\mathbf{Q}}^{-1}-\widetilde{\mathbf{Q}}^{-1} \mathbf{K}^{\top}\left(\mathbf{K} \widetilde{\mathbf{Q}}^{-1} \mathbf{K}^{\top}\right)^{-1} \mathbf{K} \widetilde{\mathbf{Q}}^{-1}\right). \tag{12} \label{U_vector_constrained} \]

Let \(\mathbf{A}\) (which is not unique) be a \(|\mathcal{V}| \times 2\alpha|\mathcal{E}|\) matrix such that

\[ \mathbf{U}_v = [u(v_1),u(v_2), \dots, u(v_{|\mathcal{V}|})]^{\top} = \mathbf{A} \mathbf{U}\sim\mathrm{N}\left(\mathbf{0},\mathbf{A}\left(\widetilde{\mathbf{Q}}^{-1}-\widetilde{\mathbf{Q}}^{-1} \mathbf{K}^{\top}\left(\mathbf{K} \widetilde{\mathbf{Q}}^{-1} \mathbf{K}^{\top}\right)^{-1} \mathbf{K} \widetilde{\mathbf{Q}}^{-1}\right) \mathbf{A}^{\top}\right), \tag{13} \label{A_matrix} \]


1.1 Case \(\alpha=1\)


For \(\alpha=1, \mathbf{U}_v\) in \(\eqref{A_matrix}\) satisfies

\[ \mathbf{U}_v \sim \mathrm{~N}\left(\mathbf{0}, \mathbf{Q}^{-1}\right), \tag{14} \label{U_v_distribution_alpha1} \]

where

\[ \mathbf{Q}_{i j}=2 \kappa \tau^2 . \begin{cases}\dfrac{1}{2}\mathbb{I}(\text{deg}(v_i) = 1) + \displaystyle\sum_{e \in \mathcal{E}_{v_i}}\left\{\left(\frac{1}{2}+\frac{e^{-2 \kappa \ell_e}}{1-e^{-2 \kappa \ell_e}}\right) \mathbb{I}(\bar{e} \neq \underline{e})+\tanh \left(\kappa \frac{l_e}{2}\right) \mathbb{I}(\bar{e}=\underline{e})\right\} & \text { if } i=j \\ \displaystyle\sum_{e \in \mathcal{E}_{v_i} \cap \mathcal{E}_{v_j}}-\frac{e^{-\kappa \ell_e}}{1-e^{-2 \kappa \ell_e}} & \text { if } i \neq j\end{cases} \tag{15} \label{Q_matrix} \]

and we have added \(\dfrac{1}{2}\mathbb{I}(\text{deg}(v_i) = 1)\) to correct for stationarity at vertices with degree one (see (Bolin, Simas, and Wallin 2023c, sec. 7)).


1.2 Case \(\alpha>1\)


Let \(\alpha>0\) and \(\mathbf{T}\) be the change-of-basis matrix such that

\[ \widetilde{\mathbf{U}}^\star = \mathbf{T} \widetilde{\mathbf{U}}, \tag{16} \label{T_matrix} \]

and the \(k\) constraints of \(\mathbf{K}\) are given by the first \(k\) rows of \(\widetilde{\mathbf{U}}^\star\). That is,

\[ \widetilde{\mathbf{U}}^\star\sim \mathrm{N}\left(\mathbf{0}, \mathbf{T}\widetilde{\mathbf{Q}}^{-1}\mathbf{T}^\top\right) \tag{17} \label{U_star_distribution} \]

Let \(\widetilde{\mathbf{Q}}^*=\mathbf{T} \widetilde{\mathbf{Q}} \mathbf{T}^{\top}\). Further, let \(\mathbf{T}_{\mathcal{U}}\) denote the matrix obtained by removing the first \(k\) rows from \(\mathbf{T}\), and let \(\widetilde{\mathbf{Q}}_{\mathcal{U} \mathcal{U}}^*\) denote the matrix obtained by removing the first \(k\) rows and the first \(k\) columns of \(\widetilde{\mathbf{Q}}^*\). Then

\[ \mathbf{U} \sim \mathrm{N}\left(\mathbf{0}, \mathbf{T}_{\mathcal{U}}^{\top}\left(\widetilde{\mathbf{Q}}_{\mathcal{U} \mathcal{U}}^*\right)^{-1} \mathbf{T}_{\mathcal{U}}\right) \mathbb{I}(\mathbf{K} \mathbf{U}=\mathbf{0}) \tag{18} \label{U_distribution_final} \] and

\[ \mathbf{U}_v \sim \mathrm{~N}\left(\mathbf{0}, \mathbf{A} \mathbf{T}_{\mathcal{U}}^{\top}\left(\widetilde{\mathbf{Q}}_{\mathcal{U} \mathcal{U}}^*\right)^{-1} \mathbf{T}_{\mathcal{U}} \mathbf{A}^{\top}\right). \tag{19} \label{U_v_distribution_final} \]

The matrices \(\mathbf{A}, \mathbf{T}_{\mathcal{U}}\) and \(\widetilde{\mathbf{Q}}_{\mathcal{U} \mathcal{U}}^*\) in \(\eqref{U_v_distribution_final}\) are sparse. Thus, we can simulate \(\mathbf{U}_v\) efficiently by simulating

\[ \mathbf{v} \sim \mathrm{N}\left(\mathbf{0},\left(\widetilde{\mathbf{Q}}_{\mathcal{U} \mathcal{U}}^*\right)^{-1}\right) \tag{20} \label{v_distribution} \] through sparse Cholesky factorization of \(\widetilde{\mathbf{Q}}_{\mathcal{U} \mathcal{U}}^*\) and then computing the sparse matrix vector product \(\mathbf{U}_v=\mathbf{A T}_{\mathcal{U}}^{\top} \mathbf{v}\).


2 Likelihood evaluation


Assume we have observations \(\mathbf{y} = [y_1,\dots,y_n]\) at locations \(s_1,\dots,s_n\in\Gamma\) such that (1) \(y_i = u(s_i)\) or (2) \(y_i|u(\cdot)\sim \mathrm{N}(u(s_i), \sigma^2)\).


2.1 Case \(\alpha=1\)


We add the locations \(s_1,\dots,s_n\) as vertices and called the extended graph as \(\overline{\Gamma}\). Let \(\mathbf{v} = (v_1, \dots, v_m)\) be the indices of the original vertices and \(\mathbf{s} = (s_1, \dots, s_n)\) the indices of the added locations.

3 Fractional case

We consider the covariance operator \(\mathcal{C} = \tau^{-2}L^{-\alpha}\), where \(L = \kappa^2 - \Delta_\Gamma\) and \(\alpha > 0\) is not necessarily an integer.

We consider an approximation

\[ \mathcal{C}_{m,\alpha} = \tau^{-2}L^{-\lfloor \alpha \rfloor} p(L^{-1})q(L^{-1})^{-1} = \tau^{-2}L^{-\lfloor \alpha \rfloor} \left(\sum_{i=1}^m r_i (L-p_iI)^{-1} + kI\right) = \tau^{-2}\left(kL^{-\lfloor \alpha \rfloor} + \sum_{i=1}^m r_i L^{-\lfloor \alpha \rfloor}(L-p_iI)^{-1}\right), \tag{21} \label{C_fractional_approx} \] So \(u(s) = u_0(s) + \sum_{i=1}^m u_i(s)\), where \(u_0\) and \(u_i\) satisfy

\[ \dfrac{1}{\sqrt{k}}(\kappa^2 - \Delta_\Gamma)^{\lfloor \alpha \rfloor / 2} (\tau u_0) = \mathcal{W},\text{ on }\Gamma \tag{22} \label{u0_equation} \]

and

\[ \dfrac{1}{\sqrt{r_i}}((\kappa^2 - \Delta_\Gamma)^{\lfloor \alpha \rfloor}(\kappa^2 - p_i-\Delta_\Gamma))^{1/2} (\tau u_i) = \mathcal{W}, \text{ on }\Gamma, \quad i = 1, \dots, m. \tag{23} \label{ui_equation} \]

3.1 Case \(\alpha \in (0,1)\)

In this case, \(\eqref{u0_equation}\) reduces to

\[ \dfrac{1}{\sqrt{k}}\tau u_0 = \mathcal{W},\text{ on }\Gamma \tag{24} \label{u0_equation_alpha01} \]

and \(\eqref{ui_equation}\) reduces to

\[ \dfrac{1}{\sqrt{r_i}}(\kappa^2 - p_i - \Delta_\Gamma)^{1/2} (\tau u_i) = \mathcal{W}, \text{ on }\Gamma, \quad i = 1, \dots, m. \tag{25} \label{ui_equation_alpha01} \]

Equation \(\eqref{ui_equation_alpha01}\) is just the case \(\alpha=1\) in the original setting but now with shifted parameter \(\kappa^2 - p_i\) instead of \(\kappa^2\) and with a constant factor \(1/\sqrt{r_i}\).

3.2 Case \(\alpha \in (1,2)\)

In this case, \(\eqref{u0_equation}\) reduces to \[ \dfrac{1}{\sqrt{k}}(\kappa^2 - \Delta_\Gamma)^{1/2}(\tau u_0) = \mathcal{W},\text{ on }\Gamma \tag{26} \label{u0_equation_alpha12} \]

and \(\eqref{ui_equation}\) reduces to

\[ \dfrac{1}{\sqrt{r_i}}((\kappa^2 - \Delta_\Gamma)(\kappa^2 - p_i - \Delta_\Gamma))^{1/2} (\tau u_i) = \mathcal{W}, \text{ on }\Gamma,\quad i = 1, \dots, m. \tag{27} \label{ui_equation_alpha12} \] Equation \(\eqref{u0_equation_alpha12}\) is just the case \(\alpha=1\) in the original setting but now with a constant factor \(1/\sqrt{k}\).

3.3 Case \(\alpha \in (2,3)\)

In this case, \(\eqref{u0_equation}\) reduces to

\[ \dfrac{1}{\sqrt{k}}(\kappa^2 - \Delta_\Gamma)(\tau u_0) = \mathcal{W}, \tag{28} \label{u0_equation_alpha23} \] and \(\eqref{ui_equation}\) reduces to \[ \dfrac{1}{\sqrt{r_i}}((\kappa^2 - \Delta_\Gamma)^2(\kappa^2 - p_i - \Delta_\Gamma))^{1/2} (\tau u_i) = \mathcal{W}, \quad i = 1, \dots, m. \tag{29} \label{ui_equation_alpha23} \]

Equation \(\eqref{u0_equation_alpha23}\) is just the case \(\alpha=2\) in the original setting but now with a constant factor \(1/\sqrt{k}\).

3.4 Matrix version

Let

\[ \mathbf{u}(s) = [u(s), u'(s), \dots, u^{(\lfloor \alpha \rfloor)}(s)]^\top\in\mathbb{R}^{\lfloor \alpha \rfloor + 1} \tag{30} \label{u_vector_fractional} \]

and

\[ \widetilde{\mathbf{u}}(s)=\left[\widetilde{u}(s), \widetilde{u}^{\prime}(s),\ldots, \widetilde{u}^{(\lfloor \alpha \rfloor)}(s)\right]^{\top} \in\mathbb{R}^{\lfloor \alpha \rfloor + 1} \tag{31} \]

and

\[ \mathbf{u}(\mathbf{s}) = \widetilde{\mathbf{u}}(\mathbf{s})| \mathcal{K}_{\lfloor\alpha\rfloor}(\widetilde{u}), \tag{32} \]

and

\[ \mathbf{u}(\mathbf{s}) = [\mathbf{u}(s_1), \mathbf{u}(s_2), \dots, \mathbf{u}(s_n)]^\top \in\mathbb{R}^{n(\lfloor \alpha \rfloor + 1)} \]

and

\[ \widetilde{\mathbf{u}}(\mathbf{s}) = [\widetilde{\mathbf{u}}(s_1), \widetilde{\mathbf{u}}(s_2), \dots, \widetilde{\mathbf{u}}(s_n)]^\top \in\mathbb{R}^{n(\lfloor \alpha \rfloor + 1)} \] and

\[ \mathbf{s} = [s_1, s_2, \dots, s_n]^\top\in\mathbb{R}^n,\quad s_1,s_2,\dots,s_n\in\Gamma \]

and

\[ \mathbf{U}=\left[\mathbf{u}(\underline{e}_1)^{\top}, \mathbf{u}(\overline{e}_1)^{\top}, \mathbf{u}(\underline{e}_2)^{\top}, \mathbf{u}(\overline{e}_2)^{\top}, \ldots, \mathbf{u}(\underline{e}_{|\mathcal{E}|})^{\top}, \mathbf{u}(\overline{e}_{|\mathcal{E}|})^{\top}\right]^{\top}\in\mathbb{R}^{2(\lfloor \alpha \rfloor + 1)|\mathcal{E}|} \tag{33} \]

and

\[ \widetilde{\mathbf{U}}=\left[\widetilde{\mathbf{u}}_1(\underline{e}_1)^{\top}, \widetilde{\mathbf{u}}_1(\overline{e}_1)^{\top}, \widetilde{\mathbf{u}}_2(\underline{e}_2)^{\top}, \widetilde{\mathbf{u}}_2(\overline{e}_2)^{\top}, \ldots, \widetilde{\mathbf{u}}_{|\mathcal{E}|}(\underline{e}_{|\mathcal{E}|})^{\top}, \widetilde{\mathbf{u}}_{|\mathcal{E}|}(\overline{e}_{|\mathcal{E}|})^{\top}\right]^{\top}\in\mathbb{R}^{2(\lfloor \alpha \rfloor + 1)|\mathcal{E}|} \tag{34} \]

We then have that

\[ \mathbf{u}_0(s) = \widetilde{\mathbf{u}}_0(s)| \mathcal{K}_{\lfloor\alpha\rfloor-1}(\widetilde{u}_0), \tag{35} \]

and

\[ \mathbf{u}_i(s) = \widetilde{\mathbf{u}}_i(s)| \mathcal{K}_{\lfloor\alpha\rfloor}(\widetilde{u}_i),\quad i=1,\dots,m, \tag{35} \]

where

\[ \widetilde{\mathbf{u}}_0(s)=\left[\widetilde{u}_0(s), \widetilde{u}_0^{\prime}(s),\ldots, \widetilde{u}_0^{(\lfloor \alpha \rfloor-1)}(s)\right]^{\top} \in\mathbb{R}^{\lfloor \alpha \rfloor} \tag{36} \]

has covariance function

Covariance of the boundaryless process on an interval \([0, \ell]\)

\[ \widetilde{\mathbf{r}}\left(t_1, t_2\right)=\mathbf{r}\left(t_1, t_2\right)+\left[\mathbf{r}\left(t_1, 0\right) \mathbf{r}\left(t_1, \ell\right)\right]\left[\begin{array}{cc} \mathbf{r}(0,0) & -\mathbf{r}(0, \ell) \\ -\mathbf{r}(\ell, 0) & \mathbf{r}(0,0) \end{array}\right]^{-1}\left[\begin{array}{l} \mathbf{r}\left(t_2, 0\right) \\ \mathbf{r}\left(t_2, \ell\right) \end{array}\right] \tag{37} \]

Covariance of the corresponding unrestricted process on \(\mathbb{R}\)

\[ \mathbf{r}: \mathbb{R} \times \mathbb{R} \mapsto \mathbb{R}^{\lfloor\alpha \rfloor\times \lfloor\alpha\rfloor}, \quad \mathbf{r}\left(t_1, t_2\right)=\left[\frac{\partial^{i-1}}{\partial t_2^{i-1}} \frac{\partial^{j-1}}{\partial t_1^{j-1}} \varrho_M\left(t_1-t_2\right)\right]_{i j \in\{1,2, \ldots, \lfloor\alpha\rfloor\}} \tag{38} \]

and

\[ \widetilde{\mathbf{u}}_i(s)=\left[\widetilde{u}_i(s), \widetilde{u}_i^{\prime}(s),\ldots, \widetilde{u}_i^{(\lfloor \alpha \rfloor)}(s)\right]^{\top} \in\mathbb{R}^{\lfloor \alpha \rfloor+1} \tag{39} \] has covariance function

Covariance of the shifted boundaryless process on an interval \([0, \ell]\)

\[ \widetilde{\mathbf{r}}_i\left(t_1, t_2\right)=\mathbf{r}_i\left(t_1, t_2\right)+\left[\mathbf{r}_i\left(t_1, 0\right) \mathbf{r}_i\left(t_1, \ell\right)\right]\left[\begin{array}{cc} \mathbf{r}_i(0,0) & -\mathbf{r}_i(0, \ell) \\ -\mathbf{r}_i(\ell, 0) & \mathbf{r}_i(0,0) \end{array}\right]^{-1}\left[\begin{array}{l} \mathbf{r}_i\left(t_2, 0\right) \\ \mathbf{r}_i\left(t_2, \ell\right) \end{array}\right] \tag{40} \]

Covariance of the corresponding unrestricted process on \(\mathbb{R}\)

\[ \mathbf{r}_i: \mathbb{R} \times \mathbb{R} \mapsto \mathbb{R}^{\lceil\alpha\rceil\times \lceil\alpha\rceil}, \quad \mathbf{r}_i\left(t_1, t_2\right)=\left[\frac{\partial^{i-1}}{\partial t_2^{i-1}} \frac{\partial^{j-1}}{\partial t_1^{j-1}} \dfrac{\varrho_{m, i}^\alpha\left(t_1-t_2\right)}{r_i\sigma^2}\right]_{i j \in\{1,2, \ldots, \lceil\alpha\rceil\}} \tag{41} \]

The precision matrix of \([\widetilde{\mathbf{u}}_{0,e}(0), \widetilde{\mathbf{u}}_{0,e}(\ell)]\) is

\[ \widetilde{\mathbf{Q}}_{0,e}=\mathbf{Q}_{0,e}-\frac{1}{2}\left[\begin{array}{cc} \mathbf{r}(0,0)^{-1} & \mathbf{0} \\ \mathbf{0} & \mathbf{r}(0,0)^{-1} \end{array}\right]\in\mathbb{R}^{2 \lfloor\alpha\rfloor \times 2 \lfloor\alpha\rfloor}, \]

where \(\mathbf{Q}_{0,e}\) is the precision matrix of \([\mathbf{u}_{0,e}(0), \mathbf{u}_{0,e}(\ell)]\).

The precision matrix of \([\widetilde{\mathbf{u}}_{i,e}(0), \widetilde{\mathbf{u}}_{i,e}(\ell)]\) is

\[ \widetilde{\mathbf{Q}}_{i,e}=\mathbf{Q}_{i,e}-\frac{1}{2}\left[\begin{array}{cc} \mathbf{r}_i(0,0)^{-1} & \mathbf{0} \\ \mathbf{0} & \mathbf{r}_i(0,0)^{-1} \end{array}\right]\in\mathbb{R}^{2 \lceil\alpha\rceil \times 2 \lceil\alpha\rceil}, \]

where \(\mathbf{Q}_{i,e}\) is the precision matrix of \([\mathbf{u}_{i,e}(0), \mathbf{u}_{i,e}(\ell)]\).

Define

\[ \widetilde{\mathbf{U}}_0=\left[\widetilde{\mathbf{u}}_{0,1}(\underline{e}_1)^{\top}, \widetilde{\mathbf{u}}_{0,1}(\overline{e}_1)^{\top}, \widetilde{\mathbf{u}}_{i,2}(\underline{e}_2)^{\top}, \widetilde{\mathbf{u}}_{0,2}(\overline{e}_2)^{\top}, \ldots, \widetilde{\mathbf{u}}_{0,|\mathcal{E}|}(\underline{e}_{|\mathcal{E}|})^{\top}, \widetilde{\mathbf{u}}_{0,|\mathcal{E}|}(\overline{e}_{|\mathcal{E}|})^{\top}\right]^{\top}\in\mathbb{R}^{2\lfloor \alpha \rfloor|\mathcal{E}|} \tag{42} \]

and

\[ \widetilde{\mathbf{U}}_i=\left[\widetilde{\mathbf{u}}_{i,1}(\underline{e}_1)^{\top}, \widetilde{\mathbf{u}}_{i,1}(\overline{e}_1)^{\top}, \widetilde{\mathbf{u}}_{i,2}(\underline{e}_2)^{\top}, \widetilde{\mathbf{u}}_{i,2}(\overline{e}_2)^{\top}, \ldots, \widetilde{\mathbf{u}}_{i,|\mathcal{E}|}(\underline{e}_{|\mathcal{E}|})^{\top}, \widetilde{\mathbf{u}}_{i,|\mathcal{E}|}(\overline{e}_{|\mathcal{E}|})^{\top}\right]^{\top}\in\mathbb{R}^{2(\lfloor \alpha \rfloor + 1)|\mathcal{E}|},\quad i=0,\dots,m, \tag{43} \]

Then

\[ \widetilde{\mathbf{U}}_0\sim \mathrm{N}\left(\mathbf{0}, \widetilde{\mathbf{Q}}_0^{-1}\right), \quad \widetilde{\mathbf{Q}}_0 = \operatorname{diag}\left(\{\widetilde{\mathbf{Q}}_{0,e}\}_{e\in\mathcal{E}}\right), \]

and

\[ \widetilde{\mathbf{U}}_i\sim \mathrm{N}\left(\mathbf{0}, \widetilde{\mathbf{Q}}_i^{-1}\right), \quad\widetilde{\mathbf{Q}}_i = \operatorname{diag}\left(\{\widetilde{\mathbf{Q}}_{i,e}\}_{e\in\mathcal{E}}\right),\quad i=1,\dots,m. \]

4 Auxiliary functions

4.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(flip_edge = FALSE){
  if(flip_edge) {
    edge1 <- rbind(c(0,0),c(1,0))[c(2,1),]
    } else {
    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)
}
# Eigenfunctions for 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)
}


# Function to compute the true covariance matrix
gets_true_cov_mat <- function(graph, kappa, tau, alpha, n.overkill){
  Sigma.kl <- matrix(0,nrow = dim(graph$mesh$V)[1],ncol = dim(graph$mesh$V)[1])
  for(i in 0:n.overkill){
    phi <- tadpole.eig(i,graph)$phi
    Sigma.kl <- Sigma.kl + (1/(kappa^2 + (i*pi/2)^2)^(alpha))*phi%*%t(phi)
    if(i>0 && (i %% 2)==0){ 
      psi <- tadpole.eig(i,graph)$psi
      Sigma.kl <- Sigma.kl + (1/(kappa^2 + (i*pi/2)^2)^(alpha))*psi%*%t(psi)
    }
    
  }
  Sigma.kl <- Sigma.kl/tau^2
  return(Sigma.kl)
}
Qalpha1 <- function(theta, graph, BC = 1, build = TRUE) {
  
  kappa <- theta[2]
  tau <- theta[1]
  i_ <- j_ <- x_ <- rep(0, dim(graph$V)[1]*4) # it has length 4*nV
  count <- 0
  for(i in 1:graph$nE){ # loop over edges
    l_e <- graph$edge_lengths[i]
    c1 <- exp(-kappa*l_e)
    c2 <- c1^2
    one_m_c2 = 1-c2
    c_1 = 0.5 + c2/one_m_c2
    c_2 = -c1/one_m_c2
    
    if (graph$E[i, 1] != graph$E[i, 2]) { # This is for non-circular edges and codes I(overline(e) != underline(e))
      
      i_[count + 1] <- graph$E[i, 1]
      j_[count + 1] <- graph$E[i, 1]
      x_[count + 1] <- c_1
      
      i_[count + 2] <- graph$E[i, 2]
      j_[count + 2] <- graph$E[i, 2]
      x_[count + 2] <- c_1
      
      
      i_[count + 3] <- graph$E[i, 1]
      j_[count + 3] <- graph$E[i, 2]
      x_[count + 3] <- c_2
      
      i_[count + 4] <- graph$E[i, 2]
      j_[count + 4] <- graph$E[i, 1]
      x_[count + 4] <- c_2
      count <- count + 4
    }else{ # This is for circular edges and codes I(overline(e) = underline(e))
      i_[count + 1] <- graph$E[i, 1]
      j_[count + 1] <- graph$E[i, 1]
      x_[count + 1] <- tanh(0.5 * kappa * l_e)
      count <- count + 1
    }

  }
  if(BC == 1){
    #does this work for circle?
    i.table <- table(i_[1:count])
    index = as.integer(names(which(i.table < 3)))
    i_ <- c(i_[1:count], index)
    j_ <- c(j_[1:count], index)
    x_ <- c(x_[1:count], rep(0.5, length(index))) # here is where we add the 0.5 for degree one vertices
    count <- count + length(index)
    # print(i_)
    # print(j_)
  }else if(BC==2){
    
    dV <- graph$get_vertices()$degree
    index <- 1:length(dV)
    i_ <- c(i_[1:count], index)
    j_ <- c(j_[1:count], index)
    x_ <- c(x_[1:count], -0.5*dV + 1)
    count <- count + length(index)
    
  }
  if(build){
    Q <- Matrix::sparseMatrix(i = i_[1:count],
                              j = j_[1:count],
                              x = (2 * kappa * tau^2) * x_[1:count], # This is the 2kappa*tau^2 factor
                              dims = c(graph$nV, graph$nV))
    
    
    return(Q)
  } else {
    return(list(i = i_[1:count],
                j = j_[1:count],
                x = (2 * kappa * tau^2) * x_[1:count],
                dims = c(graph$nV, graph$nV)))
  }
}
gives.indices <- function(graph, factor, constant){
  index.obs1 <- sapply(graph$PtV, 
                       function(i){
                         idx_temp <- i == graph$E[,1]
                         idx_temp <- which(idx_temp)
                         return(idx_temp[1])}
                       )
  index.obs1 <- (index.obs1 - 1) * factor + 1
  index.obs4 <- NULL
  na_obs1 <- is.na(index.obs1)
  if(any(na_obs1)){
    idx_na <- which(na_obs1)
    PtV_NA <- graph$PtV[idx_na]
    index.obs4 <- sapply(PtV_NA, 
                         function(i){
                           idx_temp <- i == graph$E[,2]
                           idx_temp <- which(idx_temp)
                           return(idx_temp[1])}
                         )
    index.obs1[na_obs1] <- (index.obs4 - 1 ) * factor + constant                                                                      
  }
  return(index.obs1)
}

conditioning <- function(graph, alpha = 1){
  i_  =  rep(0, 2 * graph$nE)
  j_  =  rep(0, 2 * graph$nE)
  x_  =  rep(0, 2 * graph$nE)

  count_constraint <- 0
  count <- 0
  for (v in 1:graph$nV) {
    edges_leaving_v  <- which(graph$E[, 1] %in% v) 
    edges_entering_v  <- which(graph$E[, 2] %in% v)
    n_leaving_edges <- length(edges_leaving_v)
    n_entering_edges <- length(edges_entering_v)
    n_e <- n_leaving_edges + n_entering_edges
    if (n_e > 1) { # the alternative is n_e = 1, which means v is a degree one vertex and so no conditioning is needed 
      if (n_entering_edges == 0) {
        edges <- cbind(edges_leaving_v, 1)
      } else if(n_leaving_edges == 0){
        edges <- cbind(edges_entering_v, 2)
      }else{
        edges <- rbind(cbind(edges_leaving_v, 1),
                       cbind(edges_entering_v, 2))
      }
      for (i in 2:n_e) {
        i_[count + 1:2] <- count_constraint + 1
        j_[count + 1:2] <- c(2 * (edges[i-1,1] - 1) + edges[i-1, 2],
                             2 * (edges[i,1]   - 1) + edges[i,   2])
        x_[count + 1:2] <- c(1,-1)
        count <- count + 2
        count_constraint <- count_constraint + 1
      }
    }
  }
  K <- Matrix::sparseMatrix(i = i_[1:count],
                            j = j_[1:count],
                            x = x_[1:count],
                            dims = c(count_constraint, 2*graph$nE))
                         
  CB <- MetricGraph:::c_basis2(K)
  return(CB)
}

Function matern.p.joint() computes

\[ \mathbf{r}_i: \mathbb{R} \times \mathbb{R} \mapsto \mathbb{R}^{\lceil\alpha\rceil\times \lceil\alpha\rceil}, \quad \mathbf{r}_i\left(t_1, t_2\right)=\left[\frac{\partial^{k-1}}{\partial t_2^{k-1}} \frac{\partial^{j-1}}{\partial t_1^{j-1}} \varrho_{i}\left(t_1-t_2\right)\right]_{k j \in\{1,2, \ldots, \lceil\alpha\rceil\}} \]

where \(\beta = \lfloor\alpha\rfloor\) if \(i=0\) and \(\beta = \lceil\alpha\rceil\) if \(i=1,\dots,m\), and

\[ \varrho_{i}(h)=\begin{cases}\dfrac{\varrho_{m, i}^\alpha(h)}{k \sigma^2}, & i=0 \\ \dfrac{\varrho_{m, i}^\alpha(h)}{r_i \sigma^2}, & i=1,\dots,m\end{cases} \]

and

\[ \varrho_{m, i}^\alpha(h)= \begin{cases} k \sigma^2 \varrho\left(h ;\lfloor\alpha\rfloor-\frac{1}{2}, \kappa, \frac{c_\alpha}{c_{\lfloor\alpha\rfloor}}\right), & i=0 \\ r_i \sigma^2 \left[\dfrac{1}{p_i^{\lfloor\alpha\rfloor}} \varrho\left(h ; \frac{1}{2}, \kappa_i, \frac{c_\alpha \sqrt{\pi}}{\sqrt{1-p_i}}\right)-\displaystyle\sum_{j=1}^{\lfloor\alpha\rfloor} \dfrac{1}{p_i^{\lfloor\alpha\rfloor+1-j}} \varrho\left(h ; j-\frac{1}{2}, \kappa, \frac{c_\alpha}{c_j}\right)\right], & i=1,\dots,m\end{cases} \]

and \(c_a:=\Gamma(a) / \Gamma(a-1 / 2), \kappa_i=\kappa \sqrt{1-p_i}\), and \(\varrho\) is the Matérn covariance

\[ \varrho(h; \nu, \kappa, \sigma^2)=\dfrac{\sigma^{2}}{2^{\nu-1} \Gamma(\nu)}(\kappa|h|)^\nu K_\nu(\kappa|h|),\quad \sigma^2 = \dfrac{\Gamma(\nu)}{\Gamma(\nu+1/2)(4\pi)^{1/2}\kappa^{2\nu}\tau^2} \]


5 Case \(i=0\)


\[ \widetilde{\mathbf{Q}}_{0,e}=\mathbf{Q}_{0,e}-\frac{1}{2}\left[\begin{array}{cc} \mathbf{r}(0,0)^{-1} & \mathbf{0} \\ \mathbf{0} & \mathbf{r}(0,0)^{-1} \end{array}\right]\in\mathbb{R}^{2 \lfloor\alpha\rfloor \times 2 \lfloor\alpha\rfloor}, \]

This is computed in R as follows

  • \(\mathbf{r}(0,0) =\) matern.p.joint(s = 0, t = 0, kappa = kappa, p = 0, alpha = floor(alpha)).

  • \(\mathbf{Q}_{0,e} =\) matern.p.precision(loc = c(0, L_e[e]), kappa = kappa, p = 0, equally_spaced = TRUE, alpha = floor(alpha))$Q.

  • Constant correction: \(\widetilde{\mathbf{Q}}_{0,e}=\dfrac{2\tau^2\kappa^{2\alpha}}{k\kappa}\widetilde{\mathbf{Q}}_{0,e}\)


6 Case \(i=1,\dots,m\)


\[ \widetilde{\mathbf{Q}}_{i,e}=\mathbf{Q}_{i,e}-\frac{1}{2}\left[\begin{array}{cc} \mathbf{r}_i(0,0)^{-1} & \mathbf{0} \\ \mathbf{0} & \mathbf{r}_i(0,0)^{-1} \end{array}\right]\in\mathbb{R}^{2 \lceil\alpha\rceil \times 2 \lceil\alpha\rceil}, \]

This is computed in R as follows

  • \(\mathbf{r}_i(0,0) =\) matern.p.joint(s = 0, t = 0, kappa = kappa, p = p_i, alpha = alpha).

  • \(\mathbf{Q}_{i,e} =\) matern.p.precision(loc = c(0, L_e[e]), kappa = kappa, p = p_i, equally_spaced = TRUE, alpha = alpha)$Q.

  • Constant correction: \(\widetilde{\mathbf{Q}}_{i,e}=\dfrac{2\tau^2\kappa^{2\alpha}c_\alpha\sqrt{\pi}}{r_i \kappa}\widetilde{\mathbf{Q}}_{i,e}\)

Then

\[ \widetilde{\mathbf{Q}}_0 = \operatorname{diag}\left(\{\widetilde{\mathbf{Q}}_{0,e}\}_{e\in\mathcal{E}}\right), \]

and

\[ \widetilde{\mathbf{Q}}_i = \operatorname{diag}\left(\{\widetilde{\mathbf{Q}}_{i,e}\}_{e\in\mathcal{E}}\right),\quad i=1,\dots,m. \]

# This is the correct version, it is corrected the constants
gets_cov_mat_rat_approx_alpha_1_to_2 <- function(graph, kappa, tau, alpha, m){
  
  if(alpha == 2){
    Q_unconstraint <- MetricGraph:::Qalpha2(theta = c(tau, kappa),
                                         graph = graph,
                                         BC = 3000,
                                         build = TRUE)
    graph$buildC(alpha = alpha, edge_constraint = TRUE) # should always be TRUE
    COND <- graph$CoB
    Tc <- COND$T[-c(1:length(COND$S)), ]

    Q_U <-  Tc %*% Q_unconstraint %*% t(Tc)

    index.obs_i <- gives.indices(graph = graph, factor = 4, constant = 3)
    A <- t(Tc)[index.obs_i, ] 

    Sigma <- A %*% solve(Q_U, t(A))
    return(Sigma)
  }

  # get rational approximation coefficients
  coeff <- rSPDE:::interp_rational_coefficients(
    order = m, 
    type_rational_approx = "chebfun", 
    type_interp = "spline", 
    alpha = alpha)
  
  r <- coeff$r
  p <- coeff$p
  k <- coeff$k
  
  # compute parameters
  fa <- floor(alpha)
  ca <- ceiling(alpha)
  
  nu <- alpha - 1/2
  sigma <- sqrt(gamma(nu) / (tau^2 * kappa^(2*nu) * (4*pi)^(1/2) * gamma(nu + 1/2)))
  c_alpha <- gamma(alpha)/gamma(alpha - 0.5)
  c_1 <- gamma(fa)/gamma(fa - 0.5)
  
  # get edge lengths
  L_e <- graph$edge_lengths
  
  # initialize Qtilde_i, a list containing block diagonal matrices with blocks Qtilde_{i,e} for each i
  Qtilde_i <- list() 
  for(i in 1:m){
    
    # compute r_(0,0)
    r00 <- matern.p.joint(
      s = 0, 
      t = 0, 
      kappa = kappa, 
      p = p[i], 
      alpha = alpha)
    
    # compute r_(0,0)^(-1)
    r00_inverse <- solve(r00, Diagonal(ca))
    
    # define zero block 
    zero_block <- matrix(0, ca, ca)
    
    # build correction term
    correction_term <- rbind(
      cbind(r00_inverse, zero_block),
      cbind(zero_block, r00_inverse))
    
    # initialize Qtilde_i[[i]], a list containing Qtilde_{i,e} for each edge e
    Qtilde_i[[i]] <- list()
    for(e in 1:length(L_e)){
      
      # compute Q_{i,e}
      Q_e <- matern.p.precision(
        loc = c(0, L_e[e]),
        kappa = kappa, 
        p = p[i],
        equally_spaced = FALSE, 
        alpha = alpha)$Q
      
      # store Qtilde_{i,e}
      Qtilde_i[[i]][[e]] <- Q_e - 0.5 * correction_term
    }
    # build block diagonal matrix Qtilde_i[[i]]
    Qtilde_i[[i]] <- bdiag(Qtilde_i[[i]])
  }
  
  # --------------------------------------------------
  # CASE i = 0
  # --------------------------------------------------
  
  # When I use MetricGraph:::Qalpha1, I am assuming that tau and sigma are related by tau^2 = gamma(nu) / (sigma^2 * kappa^(2*nu) * (4*pi)^(1/2) * gamma(nu + 1/2)) where nu = 1/2
  
  inv_factor_0 <- 1/(k*c_alpha/c_1)
  NU <- fa - 0.5
  TAU <- sqrt(gamma(NU) / (sigma^2 * kappa^(2*NU) * (4*pi)^(1/2) * gamma(NU + 1/2)))
    
  Qtilde_0_star_UU <- MetricGraph:::Qalpha1(
    theta = c(TAU, kappa), 
    graph = graph, 
    BC = 3000, 
    build = TRUE) * inv_factor_0
  
  A_0 <- graph$.__enclos_env__$private$A()

  # --------------------------------------------------
  # CASE i = 1,...,m
  # --------------------------------------------------
  
  # build conditioning matrix
  graph$buildC(alpha = 2, edge_constraint = TRUE) # should always be TRUE
  COND_i <- graph$CoB
  Tc <- COND_i$T[-c(1:length(COND_i$S)), ]
  
  inv_factor_i <- 1/(r*sigma^2)

  Qtilde_i_star_UU <- purrr::map2(
    Qtilde_i, 
    inv_factor_i, 
    function(Q, x) Tc %*% Q %*% t(Tc) * x)

  index.obs_i <- gives.indices(graph = graph, factor = 4, constant = 3)
  A_i <- t(Tc)[index.obs_i, ] 
  
  # Build matrix A and Q_UU
  A <- cbind(A_0, do.call(cbind, rep(list(A_i), m)))
  Q_UU <- bdiag(Qtilde_0_star_UU, bdiag(Qtilde_i_star_UU))
  # Return Sigma
  Sigma <- A %*% solve(Q_UU, t(A)) 
  return(Sigma)
}
gets_cov_mat_rat_approx_alpha_0_to_1 <- function(graph, kappa, tau, alpha, m){
  
  if(alpha == 1){
    I <- Matrix::Diagonal(graph$nV)  
    Q_U <- MetricGraph:::Qalpha1(
      theta = c(tau, kappa),
      graph = graph,
      BC = 3000,
      build = TRUE)
    Sigma <- solve(Q_U, I)
    return(Sigma)
  }

  coeff <- rSPDE:::interp_rational_coefficients(
    order = m, 
    type_rational_approx = "chebfun", 
    type_interp = "spline", 
    alpha = alpha)
  
  r <- coeff$r
  p <- coeff$p
  k <- coeff$k
  
  nu <- alpha - 1/2
  sigma <- sqrt(gamma(nu) / (tau^2 * kappa^(2*nu) * (4*pi)^(1/2) * gamma(nu + 1/2)))
  
  fa <- floor(alpha)
  ca <- ceiling(alpha)
  
  c_alpha <- gamma(alpha)/gamma(alpha - 0.5)
  
  # --------------------------------------------------
  # CASE i = 0
  # --------------------------------------------------
  
  inv_factor_0 <- 1/(k*c_alpha*sqrt(4*pi)*sigma^2/kappa)
  I <- Matrix::Diagonal(graph$nV)     
  Qtilde_0_star_UU <- I * inv_factor_0
  
  # --------------------------------------------------
  # CASE i = 1,...,m
  # --------------------------------------------------
  
  inv_factor_i <- 1/(r*c_alpha*sqrt(pi)/sqrt(1 - p))
    
  NU <- ca - 0.5
  
  Qtilde_i_star_UU <- list()
  for(i in 1:m){
    
    KAPPA <- kappa*sqrt(1 - p[i])
    TAU <- sqrt(gamma(NU) / (sigma^2 * KAPPA^(2*NU) * (4*pi)^(1/2) * gamma(NU + 1/2)))
    
    Qtilde_i_star_UU[[i]] <- MetricGraph:::Qalpha1(
      theta = c(TAU, KAPPA), 
      graph = graph, 
      BC = 3000, 
      build = TRUE) * inv_factor_i[i]
  
  }

  Q_UU <- c(list(Qtilde_0_star_UU), Qtilde_i_star_UU)
  
  Sigma <- Reduce(`+`, lapply(Q_UU, function(Qi) solve(Qi, I)))
  return(Sigma)
}
rat_covariance <- function(graph, kappa, tau, alpha, m){
  if(alpha <= 0.5){
    stop("alpha = ", alpha, ", alpha should be larger than 0.5")
  }
  else if(alpha > 0.5 && alpha <= 1){
    return(gets_cov_mat_rat_approx_alpha_0_to_1(graph = graph,
                                                kappa = kappa,
                                                tau = tau,
                                                alpha = alpha,
                                                m = m))
  }
  else if(alpha > 1 && alpha <= 2){
    return(gets_cov_mat_rat_approx_alpha_1_to_2(graph = graph,
                                                kappa = kappa,
                                                tau = tau,
                                                alpha = alpha,
                                                m = m))
  }
}
{r}
# Using V's implementation
gets_cov_mat_rat_approx_alpha_1_to_2 <- function(graph, kappa, tau, alpha, m){

  # get rational approximation coefficients
  coeff <- rSPDE:::interp_rational_coefficients(
    order = m, 
    type_rational_approx = "chebfun", 
    type_interp = "spline", 
    alpha = alpha)
  
  r <- coeff$r
  p <- coeff$p
  k <- coeff$k
  
  # reparameterization
  nu <- alpha - 1/2
  sigma <- sqrt(gamma(nu) / (tau^2 * kappa^(2*nu) * (4*pi)^(1/2) * gamma(nu + 1/2)))
  c_alpha <- gamma(alpha)/gamma(alpha - 0.5)
  c_1 <- gamma(floor(alpha))/gamma(floor(alpha) - 0.5)
  
  # get edge lengths
  L_e <- graph$edge_lengths
  
  Qtilde_i <- list() 
  for(order in 0:m){
    if(order == 0){
      P <- order
      ALPHA <- floor(alpha)
      FACTOR <- (2*tau^2)/(k*kappa)
      r00_inverse <- solve(matern.p.joint(s = 0, t = 0, kappa = kappa, p = P, alpha = ALPHA))
      correction_term <- rbind(cbind(r00_inverse, matrix(0, floor(alpha), floor(alpha))),
                               cbind(matrix(0, floor(alpha), floor(alpha)), r00_inverse))
    } else {
      P <- p[order]
      ALPHA <- alpha
      FACTOR <- (2*c_alpha*sqrt(pi)*tau^2)/(r[order] * kappa)
      r00_inverse <- solve(matern.p.joint(s = 0, t = 0, kappa = kappa, p = P, alpha = ALPHA))
      correction_term <- rbind(cbind(r00_inverse, matrix(0, ceiling(alpha), ceiling(alpha))),
                               cbind(matrix(0, ceiling(alpha), ceiling(alpha)), r00_inverse))
    }
    Qtilde_i[[paste0("m=",order)]] <- list()
    for(e in 1:length(L_e)){
      Q_e <- matern.p.precision(loc = c(0, L_e[e]), 
                                kappa = kappa, 
                                p = P,
                                equally_spaced = TRUE, 
                                alpha = ALPHA)$Q
      Qtilde_i[[paste0("m=",order)]][[e]] <- (Q_e - 0.5 * correction_term)*FACTOR*kappa^(2*alpha)
    }
    Qtilde_i[[paste0("m=",order)]] <- bdiag(Qtilde_i[[paste0("m=",order)]])
  }
  
  Qtilde_0 <- Qtilde_i[[paste0("m=",0)]] # extract Qtilde_0
  Qtilde_i <- Qtilde_i[-1] # remove Qtilde_0
  

  #####################################
  ## CASE m = 0
  #####################################
  COND_0 <- conditioning(graph = graph, alpha = 1)
  index.obs_0 <- gives.indices(graph = graph, factor = 2, constant = 2)
  nc_0 <- 1:length(COND_0$S) # number of constraints
  T_0 <- COND_0$T # change of basis matrix
  W_0 <- Diagonal(2*floor(alpha)*graph$nE)[,-nc_0] # matrix to remove constraints
  Qtilde_0_star_UU <- t(W_0) %*% t(T_0) %*% Qtilde_0 %*% (T_0) %*% W_0 
  A0 <- T_0[index.obs_0, -nc_0] # observation matrix after conditioning
  
  Qtilde_0_star_UU0 <- MetricGraph:::Qalpha1(theta = c(tau, kappa), 
                                            graph = graph, 
                                            BC = 3, 
                                            build = TRUE)*kappa^(-1)*c_1/(2 * k * c_alpha * sigma^2 * tau^2)
  A00 <- graph$.__enclos_env__$private$A()
  S0 <- A0 %*% solve(Qtilde_0_star_UU, t(A0))
  S00 <- A00 %*% solve(Qtilde_0_star_UU0, t(A00))
  print(S00/S0)
  #####################################
  ## CASE m > 0
  #####################################
  graph$buildC(alpha = 2, edge_constraint = TRUE)
  COND_i <- graph$CoB
  index.obs_i <- gives.indices(graph = graph, factor = 4, constant = 3)
  n_const <- length(COND_i$S)
  ind.const <- c(1:n_const)
  Tc <- COND_i$T[-ind.const, ]
  Qtilde_i_star_UU <- lapply(Qtilde_i, function(Q) Tc %*% Q %*% t(Tc)) 
  Ai <- t(Tc)[index.obs_i, ] # observation matrix after conditioning
  
  #####################################
  ## Build matrix A and Q_UU
  #####################################
  A <- cbind(A0, do.call(cbind, rep(list(Ai), m)))
  Q_UU <- bdiag(Qtilde_0_star_UU, do.call(bdiag, Qtilde_i_star_UU))
  # Return Sigma
  Sigma <- A %*% solve(Q_UU, t(A)) 
  return(Sigma)
}
# before I changed the constants

gets_cov_mat_rat_approx_alpha_1_to_2_old <- function(graph, kappa, tau, alpha, m){

  # get rational approximation coefficients
  coeff <- rSPDE:::interp_rational_coefficients(
    order = m, 
    type_rational_approx = "chebfun", 
    type_interp = "spline", 
    alpha = alpha)
  
  r <- coeff$r
  p <- coeff$p
  k <- coeff$k
  
  # compute parameters
  fa <- floor(alpha)
  ca <- ceiling(alpha)
  
  nu <- alpha - 1/2
  sigma <- sqrt(gamma(nu) / (tau^2 * kappa^(2*nu) * (4*pi)^(1/2) * gamma(nu + 1/2)))
  c_alpha <- gamma(alpha)/gamma(alpha - 0.5)
  c_1 <- gamma(fa)/gamma(fa - 0.5)
  
  # get edge lengths
  L_e <- graph$edge_lengths
  
  # initialize Qtilde_i, a list containing block diagonal matrices with blocks Qtilde_{i,e} for each i
  Qtilde_i <- list() 
  for(i in 1:m){
    
    # compute r_(0,0)
    r00 <- matern.p.joint(
      s = 0, 
      t = 0, 
      kappa = kappa, 
      p = p[i], 
      alpha = alpha)
    
    # compute r_(0,0)^(-1)
    r00_inverse <- solve(r00, Diagonal(ca))
    
    # define zero block 
    zero_block <- matrix(0, ca, ca)
    
    # build correction term
    correction_term <- rbind(
      cbind(r00_inverse, zero_block),
      cbind(zero_block, r00_inverse))
    
    # initialize Qtilde_i[[i]], a list containing Qtilde_{i,e} for each edge e
    Qtilde_i[[i]] <- list()
    for(e in 1:length(L_e)){
      
      # compute Q_{i,e}
      Q_e <- matern.p.precision(
        loc = c(0, L_e[e]),
        kappa = kappa, 
        p = p[i],
        equally_spaced = FALSE, 
        alpha = alpha)$Q
      
      # store Qtilde_{i,e}
      Qtilde_i[[i]][[e]] <- Q_e - 0.5 * correction_term
    }
    # build block diagonal matrix Qtilde_i[[i]]
    Qtilde_i[[i]] <- bdiag(Qtilde_i[[i]])
  }
  
  # --------------------------------------------------
  # CASE i = 0
  # --------------------------------------------------
  
  factor_0 <- c_1/(2 * k * c_alpha * kappa * sigma^2 * tau^2)

  
  Qtilde_0_star_UU <- MetricGraph:::Qalpha1(
    theta = c(tau, kappa), 
    graph = graph, 
    BC = 3000, 
    build = TRUE) * factor_0
  
  A_0 <- graph$.__enclos_env__$private$A()

  # --------------------------------------------------
  # CASE i = 1,...,m
  # --------------------------------------------------
  
  # build conditioning matrix
  graph$buildC(alpha = 2, edge_constraint = TRUE) # should always be TRUE
  COND_i <- graph$CoB
  Tc <- COND_i$T[-c(1:length(COND_i$S)), ]
  
  factor_i <- (2 * kappa^(2 * alpha - 1) * c_alpha * sqrt(pi) * tau^2)/r
  
  Qtilde_i_star_UU <- purrr::map2(
    Qtilde_i, 
    factor_i, 
    function(Q, x) Tc %*% Q %*% t(Tc) * x)

  index.obs_i <- gives.indices(graph = graph, factor = 4, constant = 3)
  A_i <- t(Tc)[index.obs_i, ] 
  
  # Build matrix A and Q_UU
  A <- cbind(A_0, do.call(cbind, rep(list(A_i), m)))
  Q_UU <- bdiag(Qtilde_0_star_UU, bdiag(Qtilde_i_star_UU))
  # Return Sigma
  Sigma <- A %*% solve(Q_UU, t(A)) 
  return(Sigma)
}

7 References

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

We used R version 4.5.2 (R Core Team 2025) and the following R packages: ggmap v. 4.0.2 (Kahle and Wickham 2013), gridExtra v. 2.3 (Auguie 2017), here v. 1.0.1 (Müller 2020), htmltools v. 0.5.8.1 (Cheng et al. 2024), knitr v. 1.50 (Xie 2014, 2015, 2025), latex2exp v. 0.9.8 (Meschiari 2026), Matrix v. 1.7.3 (Bates, Maechler, and Jagan 2025), MetricGraph v. 1.5.0.9000 (Bolin, Simas, and Wallin 2023a, 2023b, 2024, 2025; Bolin et al. 2024), patchwork v. 1.3.1 (Pedersen 2025), plotly v. 4.11.0 (Sievert 2020), qs v. 0.27.3 (Ching 2025), rdist v. 0.0.5 (Blaser 2020), renv v. 1.1.7 (Ushey and Wickham 2026), reshape2 v. 1.4.4 (Wickham 2007), rmarkdown v. 2.30 (Xie, Allaire, and Grolemund 2018; Xie, Dervieux, and Riederer 2020; Allaire et al. 2025), rSPDE v. 2.5.2.9000 (Bolin and Kirchner 2020; Bolin and Simas 2023; Bolin, Simas, and Xiong 2024), scales v. 1.4.0 (Wickham, Pedersen, and Seidel 2025), sf v. 1.1.0 (E. Pebesma 2018; E. Pebesma and Bivand 2023), slackr v. 3.4.0 (Kaye et al. 2025), sp v. 2.2.1 (E. J. Pebesma and Bivand 2005; Bivand, Pebesma, and Gomez-Rubio 2013), tidyverse v. 2.0.0 (Wickham et al. 2019), viridis v. 0.6.5 (Garnier et al. 2024), xaringanExtra v. 0.8.0 (Aden-Buie and Warkentin 2024), xtable v. 1.8.8 (Dahl et al. 2026).

Aden-Buie, Garrick, and Matthew T. Warkentin. 2024. xaringanExtra: Extras and Extensions for xaringan Slides. https://doi.org/10.32614/CRAN.package.xaringanExtra.
Allaire, JJ, Yihui Xie, Christophe Dervieux, Jonathan McPherson, Javier Luraschi, Kevin Ushey, Aron Atkins, et al. 2025. rmarkdown: Dynamic Documents for r. https://github.com/rstudio/rmarkdown.
Auguie, Baptiste. 2017. gridExtra: Miscellaneous Functions for Grid Graphics.
Bates, Douglas, Martin Maechler, and Mikael Jagan. 2025. Matrix: Sparse and Dense Matrix Classes and Methods. https://doi.org/10.32614/CRAN.package.Matrix.
Bivand, Roger S., Edzer Pebesma, and Virgilio Gomez-Rubio. 2013. Applied Spatial Data Analysis with R, Second Edition. Springer, NY. https://asdar-book.org/.
Blaser, Nello. 2020. rdist: Calculate Pairwise Distances. https://doi.org/10.32614/CRAN.package.rdist.
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.
Bolin, David, Alexandre Simas, and Jonas Wallin. 2023c. “Statistical Inference for Gaussian Whittle-Matérn Fields on Metric Graphs.” https://arxiv.org/abs/2304.10372.
Cheng, Joe, Carson Sievert, Barret Schloerke, Winston Chang, Yihui Xie, and Jeff Allen. 2024. htmltools: Tools for HTML. https://github.com/rstudio/htmltools.
Ching, Travers. 2025. qs: Quick Serialization of R Objects. https://doi.org/10.32614/CRAN.package.qs.
Dahl, David B., David Scott, Charles Roosen, Arni Magnusson, and Jonathan Swinton. 2026. xtable: Export Tables to LaTeX or HTML. https://doi.org/10.32614/CRAN.package.xtable.
Garnier, Simon, Ross, Noam, Rudis, Robert, Camargo, et al. 2024. viridis(Lite) - Colorblind-Friendly Color Maps for r. https://doi.org/10.5281/zenodo.4679423.
Kahle, David, and Hadley Wickham. 2013. ggmap: Spatial Visualization with Ggplot2.” The R Journal 5 (1): 144–61. https://journal.r-project.org/archive/2013-1/kahle-wickham.pdf.
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.
Meschiari, Stefano. 2026. Latex2exp: Use LaTeX Expressions in Plots. https://doi.org/10.32614/CRAN.package.latex2exp.
Müller, Kirill. 2020. here: A Simpler Way to Find Your Files. https://doi.org/10.32614/CRAN.package.here.
Pebesma, Edzer. 2018. Simple Features for R: Standardized Support for Spatial Vector Data.” The R Journal 10 (1): 439–46. https://doi.org/10.32614/RJ-2018-009.
Pebesma, Edzer J., and Roger Bivand. 2005. “Classes and Methods for Spatial Data in R.” R News 5 (2): 9–13. https://CRAN.R-project.org/doc/Rnews/.
Pebesma, Edzer, and Roger Bivand. 2023. Spatial Data Science: With applications in R. Chapman and Hall/CRC. https://doi.org/10.1201/9780429459016.
Pedersen, Thomas Lin. 2025. patchwork: The Composer of Plots. https://doi.org/10.32614/CRAN.package.patchwork.
R Core Team. 2025. R: A Language and Environment for Statistical Computing. Vienna, Austria: R Foundation for Statistical Computing. https://www.R-project.org/.
Sievert, Carson. 2020. Interactive Web-Based Data Visualization with r, Plotly, and Shiny. Chapman; Hall/CRC. https://plotly-r.com.
Ushey, Kevin, and Hadley Wickham. 2026. renv: Project Environments. https://doi.org/10.32614/CRAN.package.renv.
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/.
———. 2025. knitr: A General-Purpose Package for Dynamic Report Generation in R. https://yihui.org/knitr/.
Xie, Yihui, J. J. Allaire, and Garrett Grolemund. 2018. R Markdown: The Definitive Guide. Boca Raton, Florida: Chapman; Hall/CRC. https://bookdown.org/yihui/rmarkdown.
Xie, Yihui, Christophe Dervieux, and Emily Riederer. 2020. R Markdown Cookbook. Boca Raton, Florida: Chapman; Hall/CRC. https://bookdown.org/yihui/rmarkdown-cookbook.
LS0tCnRpdGxlOiAiQXV4aWxpYXJ5IEZ1bmN0aW9ucyIKZGF0ZTogIkxhc3QgbW9kaWZpZWQ6IGByIGZvcm1hdChTeXMudGltZSgpLCAnJWQtJW0tJVkuJylgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIG1hdGhqYXg6ICJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL21hdGhqYXhAMy9lczUvdGV4LW1tbC1jaHRtbC5qcyIKICAgIGhpZ2hsaWdodDogcHlnbWVudHMKICAgIHRoZW1lOiBmbGF0bHkKICAgIGNvZGVfZm9sZGluZzogc2hvdyAjIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUiIHRvIGhpZGUgY29kZSBhbmQgYWRkIGEgYnV0dG9uIHRvIHNob3cgaXQKICAgIGRmX3ByaW50OiBwYWdlZAogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogdHJ1ZQogICAgICBzbW9vdGhfc2Nyb2xsOiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjc3M6IHZpc3VhbC5jc3MKYWx3YXlzX2FsbG93X2h0bWw6IHRydWUKYmlibGlvZ3JhcGh5OiAKICAtIHJlZmVyZW5jZXMuYmliCiAgLSBncmF0ZWZ1bC1yZWZzLmJpYgpoZWFkZXItaW5jbHVkZXM6CiAgLSBcbmV3Y29tbWFuZHtcYXJ9e1xtYXRoYmJ7Un19CiAgLSBcbmV3Y29tbWFuZHtcbGxhdn1bMV17XGxlZnRceyMxXHJpZ2h0XH19CiAgLSBcbmV3Y29tbWFuZHtccGFyZX1bMV17XGxlZnQoIzFccmlnaHQpfQogIC0gXG5ld2NvbW1hbmR7XE5jYWx9e1xtYXRoY2Fse059fQogIC0gXG5ld2NvbW1hbmR7XFZjYWx9e1xtYXRoY2Fse1Z9fQogIC0gXG5ld2NvbW1hbmR7XEVjYWx9e1xtYXRoY2Fse0V9fQogIC0gXG5ld2NvbW1hbmR7XFdjYWx9e1xtYXRoY2Fse1d9fQotLS0KCkdvIGJhY2sgdG8gdGhlIFtDb250ZW50c10oYWJvdXQuaHRtbCkgcGFnZS4KCjxkaXYgc3R5bGU9ImNvbG9yOiAjMmMzZTUwOyB0ZXh0LWFsaWduOiByaWdodDsiPgoqKioqKioqKiAgCjxzdHJvbmc+UHJlc3MgU2hvdyB0byByZXZlYWwgdGhlIGNvZGUgY2h1bmtzLjwvc3Ryb25nPiAgCgoqKioqKioqKgo8L2Rpdj4KCgpgYGB7ciwgcHVybCA9IEZBTFNFLCBlY2hvID0gRkFMU0V9CiMgQ3JlYXRlIGEgY2xpcGJvYXJkIGJ1dHRvbiBvbiB0aGUgcmVuZGVyZWQgSFRNTCBwYWdlCnNvdXJjZShoZXJlOjpoZXJlKCJjbGlwYm9hcmQuUiIpKTsgY2xpcGJvYXJkCmBgYAoKCmBgYHtyLCBwdXJsID0gRkFMU0UsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQojIFNldCBzZWVkIGZvciByZXByb2R1Y2liaWxpdHkKc2V0LnNlZWQoMTk4MikgCiMgU2V0IGdsb2JhbCBvcHRpb25zIGZvciBhbGwgY29kZSBjaHVua3MKa25pdHI6Om9wdHNfY2h1bmskc2V0KAogICMgRGlzYWJsZSBtZXNzYWdlcyBwcmludGVkIGJ5IFIgY29kZSBjaHVua3MKICBtZXNzYWdlID0gRkFMU0UsICAgIAogICMgRGlzYWJsZSB3YXJuaW5ncyBwcmludGVkIGJ5IFIgY29kZSBjaHVua3MKICB3YXJuaW5nID0gRkFMU0UsICAgIAogICMgU2hvdyBSIGNvZGUgd2l0aGluIGNvZGUgY2h1bmtzIGluIG91dHB1dAogIGVjaG8gPSBUUlVFLCAgICAgICAgCiAgIyBJbmNsdWRlIGJvdGggUiBjb2RlIGFuZCBpdHMgcmVzdWx0cyBpbiBvdXRwdXQKICBpbmNsdWRlID0gVFJVRSwgICAgIAogICMgRXZhbHVhdGUgUiBjb2RlIGNodW5rcwogIGV2YWwgPSBUUlVFLCAgICAgICAKICAjIEVuYWJsZSBjYWNoaW5nIG9mIFIgY29kZSBjaHVua3MgZm9yIGZhc3RlciByZW5kZXJpbmcKICBjYWNoZSA9IEZBTFNFLCAgICAgIAogICMgQWxpZ24gZmlndXJlcyBpbiB0aGUgY2VudGVyIG9mIHRoZSBvdXRwdXQKICBmaWcuYWxpZ24gPSAiY2VudGVyIiwKICAjIEVuYWJsZSByZXRpbmEgZGlzcGxheSBmb3IgaGlnaC1yZXNvbHV0aW9uIGZpZ3VyZXMKICByZXRpbmEgPSAyLAogICMgU2hvdyBlcnJvcnMgaW4gdGhlIG91dHB1dCBpbnN0ZWFkIG9mIHN0b3BwaW5nIHJlbmRlcmluZwogIGVycm9yID0gVFJVRSwKICAjIERvIG5vdCBjb2xsYXBzZSBjb2RlIGFuZCBvdXRwdXQgaW50byBhIHNpbmdsZSBibG9jawogIGNvbGxhcHNlID0gRkFMU0UKKQojIFN0YXJ0IHRoZSBmaWd1cmUgY291bnRlcgpmaWdfY291bnQgPC0gMAojIERlZmluZSB0aGUgY2FwdGlvbmVyIGZ1bmN0aW9uCmNhcHRpb25lciA8LSBmdW5jdGlvbihjYXB0aW9uKSB7CiAgZmlnX2NvdW50IDw8LSBmaWdfY291bnQgKyAxCiAgcGFzdGUwKCJGaWd1cmUgIiwgZmlnX2NvdW50LCAiOiAiLCBjYXB0aW9uKQp9CmBgYAoKCgpgYGB7cn0KIyByZW1vdGVzOjppbnN0YWxsX2dpdGh1YigiZGF2aWRib2xpbi9yc3BkZSIsIHJlZiA9ICJkZXZlbCIpCiMgcmVtb3Rlczo6aW5zdGFsbF9naXRodWIoImRhdmlkYm9saW4vbWV0cmljZ3JhcGgiLCByZWYgPSAiZGV2ZWwiKQpsaWJyYXJ5KHJTUERFKQpsaWJyYXJ5KE1ldHJpY0dyYXBoKQpsaWJyYXJ5KGdyYXRlZnVsKQoKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHJlc2hhcGUyKQpsaWJyYXJ5KHBsb3RseSkKYGBgCgojIyBUaGVvcmV0aWNhbCBzdHVmZgoKV2UgY29uc2lkZXIgdGhlIGVxdWF0aW9uCgokJApcbGVmdChca2FwcGFeezJ9LVxEZWx0YVxyaWdodClee1xhbHBoYSAvIDJ9KFx0YXUgdSk9XG1hdGhjYWx7V30gXHF1YWQgXHRleHQgeyBvbiB9IFxHYW1tYS4KXHRhZ3swfQpcbGFiZWx7c3BkZV9lcXVhdGlvbn0KJCQKClRoZSBNYXTDqXJuIGNvdmFyaWFuY2UgZnVuY3Rpb24gaXMgZ2l2ZW4gYnkKCiQkClx2YXJyaG9fTShoKT1cZnJhY3tcdGF1XnstMn19ezJee1xudS0xfSBcR2FtbWEoXG51K24gLyAyKSg0IFxwaSlee24gLyAyfSBca2FwcGFeezIgXG51fX0oXGthcHBhfGh8KV5cbnUgS19cbnUoXGthcHBhfGh8KSwKXHRhZ3sxfQpcbGFiZWx7bWF0ZXJuX2Nvdn0KJCQKCndoZXJlICRuPTEkIGFuZCB0aGUgcGFyYW1ldGVycyAkXHRhdSwgXGthcHBhPjAkIGFuZCAkMDxcbnUgXGxlcSAxIC8gMiQgY29udHJvbCB0aGUgdmFyaWFuY2UsIHByYWN0aWNhbCBjb3JyZWxhdGlvbiByYW5nZSwgYW5kIHRoZSBzYW1wbGUgcGF0aCByZWd1bGFyaXR5LCByZXNwZWN0aXZlbHkuIEZ1cnRoZXIsICRLX1xudShcY2RvdCkkIGlzIGEgbW9kaWZpZWQgQmVzc2VsIGZ1bmN0aW9uIG9mIHRoZSBzZWNvbmQga2luZCBhbmQgJFxHYW1tYShcY2RvdCkkIGRlbm90ZXMgdGhlIGdhbW1hIGZ1bmN0aW9uLgoKRnJvbSBbQEJvbGluMjAyM3N0YXRpc3RpY2FsLCBQcm9wb3NpdGlvbiA1XSwgd2Uga25vdyB0aGF0IAoKCiQkClxtYXRoYmZ7cn06IFxtYXRoYmJ7Un0gXHRpbWVzIFxtYXRoYmJ7Un0gXG1hcHN0byBcbWF0aGJie1J9XntcYWxwaGEgXHRpbWVzIFxhbHBoYX0sIFxxdWFkIFxtYXRoYmZ7cn1cbGVmdCh0XzEsIHRfMlxyaWdodCk9XGxlZnRbXGZyYWN7XHBhcnRpYWxee2ktMX19e1xwYXJ0aWFsIHRfMl57aS0xfX0gXGZyYWN7XHBhcnRpYWxee2otMX19e1xwYXJ0aWFsIHRfMV57ai0xfX0gXHZhcnJob19NXGxlZnQodF8xLXRfMlxyaWdodClccmlnaHRdX3tpIGogXGluXHsxLDIsIFxsZG90cywgXGFscGhhXH19Clx0YWd7Mn0KXGxhYmVse3JfbWF0cml4fQokJAppcyB0aGUgY292YXJpYW5jZSBmdW5jdGlvbiBvZiAkXG1hdGhiZnt4fSh0KT1cbGVmdFt4KHQpLCB4Jyh0KSwgXGxkb3RzLCB4XnsoXGFscGhhLTEpfSh0KVxyaWdodF1ee1x0b3B9JCBpZiAkeCQgaXMgYSBjZW50ZXJlZCBHYXVzc2lhbiBwcm9jZXNzIG9uICRcbWF0aGJie1J9JCB3aXRoIE1hdMOpcm4gY292YXJpYW5jZSBmdW5jdGlvbiB3aXRoICRcbnUgPSBcYWxwaGEtMS8yJCBhbmQgJFxhbHBoYSBcaW4gXG1hdGhiYntOfSQuCgpMZXQgJFxtYXRoYmZ7cn0oXGNkb3QsIFxjZG90KSQgYmUgZ2l2ZW4gYnkgXGVxcmVme3JfbWF0cml4fSB3aXRoICRcYWxwaGEgXGluIFxtYXRoYmJ7Tn0kLiBUaGVuLCBmcm9tIFtAQm9saW4yMDIzc3RhdGlzdGljYWwsIFByb3Bvc2l0aW9uIDZdLCBmb3IgJFxlbGw+MCQsCgokJApcd2lkZXRpbGRle1xtYXRoYmZ7cn19X3tcZWxsfVxsZWZ0KHRfMSwgdF8yXHJpZ2h0KT1cbWF0aGJme3J9XGxlZnQodF8xLCB0XzJccmlnaHQpK1xsZWZ0W1xtYXRoYmZ7cn1cbGVmdCh0XzEsIDBccmlnaHQpIFxtYXRoYmZ7cn1cbGVmdCh0XzEsIFxlbGxccmlnaHQpXHJpZ2h0XVxsZWZ0W1xiZWdpbnthcnJheX17Y2N9ClxtYXRoYmZ7cn0oMCwwKSAmIC1cbWF0aGJme3J9KDAsIFxlbGwpIFxcCi1cbWF0aGJme3J9KFxlbGwsIDApICYgXG1hdGhiZntyfSgwLDApClxlbmR7YXJyYXl9XHJpZ2h0XV57LTF9XGxlZnRbXGJlZ2lue2FycmF5fXtsfQpcbWF0aGJme3J9XGxlZnQodF8yLCAwXHJpZ2h0KSBcXApcbWF0aGJme3J9XGxlZnQodF8yLCBcZWxsXHJpZ2h0KQpcZW5ke2FycmF5fVxyaWdodF0KXHRhZ3szfQpcbGFiZWx7cl90aWxkZV9tYXRyaXh9CiQkCgppcyB0aGUgbXVsdGl2YXJpYXRlIGNvdmFyaWFuY2UgZnVuY3Rpb24gb2YgdGhlIG11bHRpdmFyaWF0ZSBwcm9jZXNzICRcd2lkZXRpbGRle1xtYXRoYmZ7eH19KHQpPVxsZWZ0W1x3aWRldGlsZGV7eH0odCksIFx3aWRldGlsZGV7eH1ee1xwcmltZX0odCksIFxsZG90cywgXHdpZGV0aWxkZXt4fV57KFxhbHBoYS0xKX0odClccmlnaHRdXntcdG9wfSQgb24gdGhlIGludGVydmFsICRbMCwgXGVsbF0kLCB3aGVyZSAkXHdpZGV0aWxkZXt4fSQgaXMgdGhlIGJvdW5kYXJ5bGVzcyBXaGl0dGxlLS1NYXTDqXJuIHByb2Nlc3Mgb24gJFswLCBcZWxsXSQuCgpMZXQKCiQkClxtYXRoY2Fse0t9X1xhbHBoYSh4KT1cbGVmdFx7XG9tZWdhIFxpbiBcT21lZ2E6IFxmb3JhbGwgdiBcaW4gXG1hdGhjYWx7Vn0gXHRleHQgeyBhbmQgZWFjaCBwYWlyIH0gZSwgXHdpZGV0aWxkZXtlfSBcaW4gXG1hdGhjYWx7RX1fdiwgeF9lXnsoMiBrKX0odiwgXG9tZWdhKT14X3tcd2lkZXRpbGRle2V9fV57KDIgayl9KHYsIFxvbWVnYSkgXHRleHQgeywgYW5kIH0KXHN1bV97ZSBcaW4gXG1hdGhjYWx7RX1fdn0gXHBhcnRpYWxfZSB4X2VeezIgaysxfSh2LCBcb21lZ2EpPTAsIGs9MCwgXGxkb3RzLFxsY2VpbFxhbHBoYS0xIC8gMlxyY2VpbC0xXHJpZ2h0XH0KXHRhZ3s0fQpcbGFiZWx7S19hbHBoYX0KJCQKCmFuZCAkXHdpZGV0aWxkZXt1fSA9IFx7XHdpZGV0aWxkZXt1fV9lOmVcaW5cbWF0aGNhbHtFfVx9JCBiZSBhIGZhbWlseSBvZiBpbmRlcGVuZGVudCBib3VuZGFyeWxlc3MgV2hpdHRsZS0tTWF0w6lybiBwcm9jZXNzIG9uIHRoZSBlZGdlcy4gRnVydGhlciwgbGV0CgokJApcd2lkZXRpbGRle1xtYXRoYmZ7dX19KHMpPVxsZWZ0W1x3aWRldGlsZGV7dX0ocyksIFx3aWRldGlsZGV7dX1ee1xwcmltZX0ocyksXGxkb3RzLCBcd2lkZXRpbGRle3V9XnsoXGFscGhhLTEpfShzKVxyaWdodF1ee1x0b3B9PVxzdW1fe2UgXGluIFxtYXRoY2Fse0V9fSBcbWF0aGJie0l9KHMgXGluIGUpIFx3aWRldGlsZGV7XG1hdGhiZnt1fX1fZShzKSBcaW5cbWF0aGJie1J9XntcYWxwaGF9LgpcdGFnezV9ClxsYWJlbHt1X3ZlY3Rvcn0KJCQKRnJvbSBbQEJvbGluMjAyM3N0YXRpc3RpY2FsLCBUaGVvcmVtIDRdLCBpZiB3ZSBkZWZpbmUKCiQkClxtYXRoYmZ7dX0ocykgPSBcd2lkZXRpbGRle1xtYXRoYmZ7dX19KHMpfCBcbWF0aGNhbHtLfV9cYWxwaGEoXHdpZGV0aWxkZXt1fSksClx0YWd7Nn0KXGxhYmVse3VfdmVjdG9yX2NvbnN0cmFpbmVkfQokJAoKdGhlbiAkdShcY2RvdCkkLCB0aGUgZmlyc3QgZW50cnkgb2YgJFxtYXRoYmZ7dX0oXGNkb3QpJCwgaXMgYSBzb2x1dGlvbiB0byBcZXFyZWZ7c3BkZV9lcXVhdGlvbn0uCgpUaGUgcHJlY2lzaW9uIG1hdHJpeCBvZiAkW1x3aWRldGlsZGV7XG1hdGhiZnt1fX0oMCksIFx3aWRldGlsZGV7XG1hdGhiZnt1fX0oXGVsbCldJCBpcyAKCiQkClx3aWRldGlsZGV7XG1hdGhiZntRfX1fZT1cbWF0aGJme1F9X2UtXGZyYWN7MX17Mn1cbGVmdFtcYmVnaW57YXJyYXl9e2NjfQpcbWF0aGJme3J9KDAsMCleey0xfSAmIFxtYXRoYmZ7MH0gXFwKXG1hdGhiZnswfSAmIFxtYXRoYmZ7cn0oMCwwKV57LTF9ClxlbmR7YXJyYXl9XHJpZ2h0XVxpblxtYXRoYmJ7Un1eezIgXGFscGhhIFx0aW1lcyAyIFxhbHBoYX0sClx0YWd7N30KXGxhYmVse1FfdGlsZGVfZX0KJCQKCndoZXJlICRcbWF0aGJme1F9X2UkIGlzIHRoZSBwcmVjaXNpb24gbWF0cml4IG9mICRbXG1hdGhiZnt1fSgwKSwgXG1hdGhiZnt1fShcZWxsKV0kLgoKTGV0IAokJApcbWF0aGJme1V9PVxsZWZ0W1xtYXRoYmZ7dX0oXHVuZGVybGluZXtlfV8xKV57XHRvcH0sIFxtYXRoYmZ7dX0oXG92ZXJsaW5le2V9XzEpXntcdG9wfSwgXG1hdGhiZnt1fShcdW5kZXJsaW5le2V9XzIpXntcdG9wfSwgXG1hdGhiZnt1fShcb3ZlcmxpbmV7ZX1fMilee1x0b3B9LCBcbGRvdHMsIFxtYXRoYmZ7dX0oXHVuZGVybGluZXtlfV97fFxtYXRoY2Fse0V9fH0pXntcdG9wfSwgXG1hdGhiZnt1fShcb3ZlcmxpbmV7ZX1fe3xcbWF0aGNhbHtFfXx9KV57XHRvcH1ccmlnaHRdXntcdG9wfVxpblxtYXRoYmJ7Un1eezIgXGFscGhhfFxtYXRoY2Fse0V9fH0KXHRhZ3s4fQpcbGFiZWx7VV92ZWN0b3J9CiQkCgphbmQKCgokJApcd2lkZXRpbGRle1xtYXRoYmZ7VX19PVxsZWZ0W1x3aWRldGlsZGV7XG1hdGhiZnt1fX1fMShcdW5kZXJsaW5le2V9XzEpXntcdG9wfSwgXHdpZGV0aWxkZXtcbWF0aGJme3V9fV8xKFxvdmVybGluZXtlfV8xKV57XHRvcH0sIFx3aWRldGlsZGV7XG1hdGhiZnt1fX1fMihcdW5kZXJsaW5le2V9XzIpXntcdG9wfSwgXHdpZGV0aWxkZXtcbWF0aGJme3V9fV8yKFxvdmVybGluZXtlfV8yKV57XHRvcH0sIFxsZG90cywgXHdpZGV0aWxkZXtcbWF0aGJme3V9fV97fFxtYXRoY2Fse0V9fH0oXHVuZGVybGluZXtlfV97fFxtYXRoY2Fse0V9fH0pXntcdG9wfSwgXHdpZGV0aWxkZXtcbWF0aGJme3V9fV97fFxtYXRoY2Fse0V9fH0oXG92ZXJsaW5le2V9X3t8XG1hdGhjYWx7RX18fSlee1x0b3B9XHJpZ2h0XV57XHRvcH1caW5cbWF0aGJie1J9XnsyIFxhbHBoYXxcbWF0aGNhbHtFfXx9Clx0YWd7OX0KXGxhYmVse1VfdmVjdG9yX3RpbGRlfQokJApXZSB0aGVuIGhhdmUgdGhhdAoKJCQKXHdpZGV0aWxkZXtcbWF0aGJme1V9fVxzaW0gXG1hdGhybXtOfVxsZWZ0KFxtYXRoYmZ7MH0sIFx3aWRldGlsZGV7XG1hdGhiZntRfX1eey0xfVxyaWdodCksIFxxdWFkIFx3aWRldGlsZGV7XG1hdGhiZntRfX0gPSBcb3BlcmF0b3JuYW1le2RpYWd9XGxlZnQoXHtcbWF0aGJme1F9X2VcfV97ZVxpblxtYXRoY2Fse0V9fVxyaWdodCksClx0YWd7MTB9ClxsYWJlbHtVX3ZlY3Rvcl90aWxkZV9kaXN0cmlidXRpb259CiQkCgp3aGVyZSAkXG1hdGhiZntRfV9lJCBpcyB0aGUgcHJlY2lzaW9uIG1hdHJpeCBvZiAkW1x3aWRldGlsZGV7XG1hdGhiZnt1fX1fZShcdW5kZXJsaW5le2V9KSwgXHdpZGV0aWxkZXtcbWF0aGJme3V9fV9lKFxvdmVybGluZXtlfSldJC4KClRoZSBLaXJjaGhvZmYgY29uZGl0aW9ucyBcZXFyZWZ7S19hbHBoYX0gY2FuIGJlIHdyaXR0ZW4gYXMgYSBzeXN0ZW0gb2YgbGluZWFyIGVxdWF0aW9ucwoKJCQKXG1hdGhiZntLfSBcd2lkZXRpbGRle1xtYXRoYmZ7VX19PVxtYXRoYmZ7MH0sClx0YWd7MTF9ClxsYWJlbHtLX2FscGhhX21hdHJpeH0KJCQKCndoZXJlICRcbWF0aGJme0t9XGluXG1hdGhiYntSfV57a1x0aW1lcyAyXGFscGhhfFxtYXRoY2Fse0V9fH0kIGlzIGEgc3VpdGFibGUgbWF0cml4IGFuZCAkayQgaXMgdGhlIG51bWJlciBvZiBsaW5lYXIgY29uc3RyYWludHMgZ2l2ZW4gYnkgXGVxcmVme0tfYWxwaGF9LgoKRmluYWxseSwKCiQkClxtYXRoYmZ7VX09XHdpZGV0aWxkZXtcbWF0aGJme1V9fXwgXHtcbWF0aGJme0t9IFx3aWRldGlsZGV7XG1hdGhiZntVfX09XG1hdGhiZnswfVx9XHNpbVxtYXRocm17Tn1cbGVmdChcbWF0aGJmezB9LCBcd2lkZXRpbGRle1xtYXRoYmZ7UX19XnstMX0tXHdpZGV0aWxkZXtcbWF0aGJme1F9fV57LTF9IFxtYXRoYmZ7S31ee1x0b3B9XGxlZnQoXG1hdGhiZntLfSBcd2lkZXRpbGRle1xtYXRoYmZ7UX19XnstMX0gXG1hdGhiZntLfV57XHRvcH1ccmlnaHQpXnstMX0gXG1hdGhiZntLfSBcd2lkZXRpbGRle1xtYXRoYmZ7UX19XnstMX1ccmlnaHQpLgpcdGFnezEyfQpcbGFiZWx7VV92ZWN0b3JfY29uc3RyYWluZWR9CiQkCgpMZXQgJFxtYXRoYmZ7QX0kICh3aGljaCBpcyBub3QgdW5pcXVlKSBiZSBhICR8XG1hdGhjYWx7Vn18IFx0aW1lcyAyXGFscGhhfFxtYXRoY2Fse0V9fCQgbWF0cml4IHN1Y2ggdGhhdAoKJCQKXG1hdGhiZntVfV92ID0gW3Uodl8xKSx1KHZfMiksIFxkb3RzLCB1KHZfe3xcbWF0aGNhbHtWfXx9KV1ee1x0b3B9ID0gXG1hdGhiZntBfSBcbWF0aGJme1V9XHNpbVxtYXRocm17Tn1cbGVmdChcbWF0aGJmezB9LFxtYXRoYmZ7QX1cbGVmdChcd2lkZXRpbGRle1xtYXRoYmZ7UX19XnstMX0tXHdpZGV0aWxkZXtcbWF0aGJme1F9fV57LTF9IFxtYXRoYmZ7S31ee1x0b3B9XGxlZnQoXG1hdGhiZntLfSBcd2lkZXRpbGRle1xtYXRoYmZ7UX19XnstMX0gXG1hdGhiZntLfV57XHRvcH1ccmlnaHQpXnstMX0gXG1hdGhiZntLfSBcd2lkZXRpbGRle1xtYXRoYmZ7UX19XnstMX1ccmlnaHQpIFxtYXRoYmZ7QX1ee1x0b3B9XHJpZ2h0KSwKXHRhZ3sxM30KXGxhYmVse0FfbWF0cml4fQokJAoKCl9fX19fX19fX19fXwoKIyMjIENhc2UgJFxhbHBoYT0xJAoKX19fX19fX19fX19fCgpGb3IgJFxhbHBoYT0xLCBcbWF0aGJme1V9X3YkIGluIFxlcXJlZntBX21hdHJpeH0gc2F0aXNmaWVzCgo6Ojogey5jdXN0b20tYm94fQoKJCQKXG1hdGhiZntVfV92IFxzaW0gXG1hdGhybXt+Tn1cbGVmdChcbWF0aGJmezB9LCBcbWF0aGJme1F9XnstMX1ccmlnaHQpLApcdGFnezE0fQpcbGFiZWx7VV92X2Rpc3RyaWJ1dGlvbl9hbHBoYTF9CiQkCjo6OgoKd2hlcmUKCiQkClxtYXRoYmZ7UX1fe2kgan09MiBca2FwcGEgXHRhdV4yIC4gXGJlZ2lue2Nhc2VzfVxkZnJhY3sxfXsyfVxtYXRoYmJ7SX0oXHRleHR7ZGVnfSh2X2kpID0gMSkgKyBcZGlzcGxheXN0eWxlXHN1bV97ZSBcaW4gXG1hdGhjYWx7RX1fe3ZfaX19XGxlZnRce1xsZWZ0KFxmcmFjezF9ezJ9K1xmcmFje2Veey0yIFxrYXBwYSBcZWxsX2V9fXsxLWVeey0yIFxrYXBwYSBcZWxsX2V9fVxyaWdodCkgXG1hdGhiYntJfShcYmFye2V9IFxuZXEgXHVuZGVybGluZXtlfSkrXHRhbmggXGxlZnQoXGthcHBhIFxmcmFje2xfZX17Mn1ccmlnaHQpIFxtYXRoYmJ7SX0oXGJhcntlfT1cdW5kZXJsaW5le2V9KVxyaWdodFx9ICYgXHRleHQgeyBpZiB9IGk9aiBcXCBcZGlzcGxheXN0eWxlXHN1bV97ZSBcaW4gXG1hdGhjYWx7RX1fe3ZfaX0gXGNhcCBcbWF0aGNhbHtFfV97dl9qfX0tXGZyYWN7ZV57LVxrYXBwYSBcZWxsX2V9fXsxLWVeey0yIFxrYXBwYSBcZWxsX2V9fSAmIFx0ZXh0IHsgaWYgfSBpIFxuZXEgalxlbmR7Y2FzZXN9Clx0YWd7MTV9ClxsYWJlbHtRX21hdHJpeH0KJCQKCmFuZCB3ZSBoYXZlIGFkZGVkICRcZGZyYWN7MX17Mn1cbWF0aGJie0l9KFx0ZXh0e2RlZ30odl9pKSA9IDEpJCB0byBjb3JyZWN0IGZvciBzdGF0aW9uYXJpdHkgYXQgdmVydGljZXMgd2l0aCBkZWdyZWUgb25lIChzZWUgW0BCb2xpbjIwMjNzdGF0aXN0aWNhbCwgU2VjdGlvbiA3XSkuCgpfX19fX19fX19fX18KCiMjIyBDYXNlICRcYWxwaGE+MSQKCl9fX19fX19fX19fCgpMZXQgJFxhbHBoYT4wJCBhbmQgJFxtYXRoYmZ7VH0kIGJlIHRoZSBjaGFuZ2Utb2YtYmFzaXMgbWF0cml4IHN1Y2ggdGhhdAoKJCQKXHdpZGV0aWxkZXtcbWF0aGJme1V9fV5cc3RhciA9IFxtYXRoYmZ7VH0gXHdpZGV0aWxkZXtcbWF0aGJme1V9fSwKXHRhZ3sxNn0KXGxhYmVse1RfbWF0cml4fQokJAoKYW5kIHRoZSAkayQgY29uc3RyYWludHMgb2YgJFxtYXRoYmZ7S30kIGFyZSBnaXZlbiBieSB0aGUgZmlyc3QgJGskIHJvd3Mgb2YgJFx3aWRldGlsZGV7XG1hdGhiZntVfX1eXHN0YXIkLiBUaGF0IGlzLAoKJCQKXHdpZGV0aWxkZXtcbWF0aGJme1V9fV5cc3RhclxzaW0gXG1hdGhybXtOfVxsZWZ0KFxtYXRoYmZ7MH0sIFxtYXRoYmZ7VH1cd2lkZXRpbGRle1xtYXRoYmZ7UX19XnstMX1cbWF0aGJme1R9Xlx0b3BccmlnaHQpClx0YWd7MTd9ClxsYWJlbHtVX3N0YXJfZGlzdHJpYnV0aW9ufQokJAoKTGV0ICRcd2lkZXRpbGRle1xtYXRoYmZ7UX19Xio9XG1hdGhiZntUfSBcd2lkZXRpbGRle1xtYXRoYmZ7UX19IFxtYXRoYmZ7VH1ee1x0b3B9JC4gRnVydGhlciwgbGV0ICRcbWF0aGJme1R9X3tcbWF0aGNhbHtVfX0kIGRlbm90ZSB0aGUgbWF0cml4IG9idGFpbmVkIGJ5IHJlbW92aW5nIHRoZSBmaXJzdCAkayQgcm93cyBmcm9tICRcbWF0aGJme1R9JCwgYW5kIGxldCAkXHdpZGV0aWxkZXtcbWF0aGJme1F9fV97XG1hdGhjYWx7VX0gXG1hdGhjYWx7VX19XiokIGRlbm90ZSB0aGUgbWF0cml4IG9idGFpbmVkIGJ5IHJlbW92aW5nIHRoZSBmaXJzdCAkayQgcm93cyBhbmQgdGhlIGZpcnN0ICRrJCBjb2x1bW5zIG9mICRcd2lkZXRpbGRle1xtYXRoYmZ7UX19XiokLiBUaGVuIAoKJCQKXG1hdGhiZntVfSBcc2ltIFxtYXRocm17Tn1cbGVmdChcbWF0aGJmezB9LCBcbWF0aGJme1R9X3tcbWF0aGNhbHtVfX1ee1x0b3B9XGxlZnQoXHdpZGV0aWxkZXtcbWF0aGJme1F9fV97XG1hdGhjYWx7VX0gXG1hdGhjYWx7VX19XipccmlnaHQpXnstMX0gXG1hdGhiZntUfV97XG1hdGhjYWx7VX19XHJpZ2h0KSBcbWF0aGJie0l9KFxtYXRoYmZ7S30gXG1hdGhiZntVfT1cbWF0aGJmezB9KQpcdGFnezE4fQpcbGFiZWx7VV9kaXN0cmlidXRpb25fZmluYWx9CiQkIAphbmQKCjo6OiB7LmN1c3RvbS1ib3h9CgokJApcbWF0aGJme1V9X3YgXHNpbSBcbWF0aHJte35OfVxsZWZ0KFxtYXRoYmZ7MH0sIFxtYXRoYmZ7QX0gXG1hdGhiZntUfV97XG1hdGhjYWx7VX19XntcdG9wfVxsZWZ0KFx3aWRldGlsZGV7XG1hdGhiZntRfX1fe1xtYXRoY2Fse1V9IFxtYXRoY2Fse1V9fV4qXHJpZ2h0KV57LTF9IFxtYXRoYmZ7VH1fe1xtYXRoY2Fse1V9fSBcbWF0aGJme0F9XntcdG9wfVxyaWdodCkuClx0YWd7MTl9ClxsYWJlbHtVX3ZfZGlzdHJpYnV0aW9uX2ZpbmFsfQokJAo6OjoKCgpUaGUgbWF0cmljZXMgJFxtYXRoYmZ7QX0sIFxtYXRoYmZ7VH1fe1xtYXRoY2Fse1V9fSQgYW5kICRcd2lkZXRpbGRle1xtYXRoYmZ7UX19X3tcbWF0aGNhbHtVfSBcbWF0aGNhbHtVfX1eKiQgaW4gXGVxcmVme1Vfdl9kaXN0cmlidXRpb25fZmluYWx9IGFyZSBzcGFyc2UuIFRodXMsIHdlIGNhbiBzaW11bGF0ZSAkXG1hdGhiZntVfV92JCBlZmZpY2llbnRseSBieSBzaW11bGF0aW5nIAoKJCQKXG1hdGhiZnt2fSBcc2ltIFxtYXRocm17Tn1cbGVmdChcbWF0aGJmezB9LFxsZWZ0KFx3aWRldGlsZGV7XG1hdGhiZntRfX1fe1xtYXRoY2Fse1V9IFxtYXRoY2Fse1V9fV4qXHJpZ2h0KV57LTF9XHJpZ2h0KQpcdGFnezIwfQpcbGFiZWx7dl9kaXN0cmlidXRpb259CiQkCnRocm91Z2ggc3BhcnNlIENob2xlc2t5IGZhY3Rvcml6YXRpb24gb2YgJFx3aWRldGlsZGV7XG1hdGhiZntRfX1fe1xtYXRoY2Fse1V9IFxtYXRoY2Fse1V9fV4qJCBhbmQgdGhlbiBjb21wdXRpbmcgdGhlIHNwYXJzZSBtYXRyaXggdmVjdG9yIHByb2R1Y3QgJFxtYXRoYmZ7VX1fdj1cbWF0aGJme0EgVH1fe1xtYXRoY2Fse1V9fV57XHRvcH0gXG1hdGhiZnt2fSQuCgoKCgpfX19fX19fX19fX18KCiMjIExpa2VsaWhvb2QgZXZhbHVhdGlvbgoKX19fX19fX19fX18KCkFzc3VtZSB3ZSBoYXZlIG9ic2VydmF0aW9ucyAkXG1hdGhiZnt5fSA9IFt5XzEsXGRvdHMseV9uXSQgYXQgbG9jYXRpb25zICRzXzEsXGRvdHMsc19uXGluXEdhbW1hJCBzdWNoIHRoYXQgKDEpICR5X2kgPSB1KHNfaSkkIG9yICgyKSAkeV9pfHUoXGNkb3QpXHNpbSBcbWF0aHJte059KHUoc19pKSwgXHNpZ21hXjIpJC4KCgpfX19fX19fX19fX18KCiMjIyBDYXNlICRcYWxwaGE9MSQKCl9fX19fX19fX19fXwoKV2UgYWRkIHRoZSBsb2NhdGlvbnMgJHNfMSxcZG90cyxzX24kIGFzIHZlcnRpY2VzIGFuZCBjYWxsZWQgdGhlIGV4dGVuZGVkIGdyYXBoIGFzICRcb3ZlcmxpbmV7XEdhbW1hfSQuIExldCAkXG1hdGhiZnt2fSA9ICh2XzEsIFxkb3RzLCB2X20pJCBiZSB0aGUgaW5kaWNlcyBvZiB0aGUgb3JpZ2luYWwgdmVydGljZXMgYW5kICRcbWF0aGJme3N9ID0gKHNfMSwgXGRvdHMsIHNfbikkICB0aGUgaW5kaWNlcyBvZiB0aGUgYWRkZWQgbG9jYXRpb25zLgoKCiMjIEZyYWN0aW9uYWwgY2FzZQoKV2UgY29uc2lkZXIgdGhlIGNvdmFyaWFuY2Ugb3BlcmF0b3IgJFxtYXRoY2Fse0N9ID0gXHRhdV57LTJ9TF57LVxhbHBoYX0kLCB3aGVyZSAkTCA9IFxrYXBwYV4yIC0gXERlbHRhX1xHYW1tYSQgYW5kICRcYWxwaGEgPiAwJCBpcyBub3QgbmVjZXNzYXJpbHkgYW4gaW50ZWdlci4gCgo8IS0tIFRoZSBwcmVjaXNpb24gb3BlcmF0b3IgaXMgdGhlbiBnaXZlbiBieSAkXG1hdGhjYWx7UX0gPSBcdGF1XjIgTF57XGFscGhhfSQuIC0tPgoKCldlIGNvbnNpZGVyIGFuIGFwcHJveGltYXRpb24gCgokJApcbWF0aGNhbHtDfV97bSxcYWxwaGF9ID0gXHRhdV57LTJ9TF57LVxsZmxvb3IgXGFscGhhIFxyZmxvb3J9IHAoTF57LTF9KXEoTF57LTF9KV57LTF9ID0gXHRhdV57LTJ9TF57LVxsZmxvb3IgXGFscGhhIFxyZmxvb3J9IFxsZWZ0KFxzdW1fe2k9MX1ebSByX2kgKEwtcF9pSSleey0xfSArIGtJXHJpZ2h0KSA9IFx0YXVeey0yfVxsZWZ0KGtMXnstXGxmbG9vciBcYWxwaGEgXHJmbG9vcn0gKyBcc3VtX3tpPTF9Xm0gcl9pIExeey1cbGZsb29yIFxhbHBoYSBccmZsb29yfShMLXBfaUkpXnstMX1ccmlnaHQpLApcdGFnezIxfQpcbGFiZWx7Q19mcmFjdGlvbmFsX2FwcHJveH0KJCQKU28gJHUocykgPSB1XzAocykgKyBcc3VtX3tpPTF9Xm0gdV9pKHMpJCwgd2hlcmUgJHVfMCQgYW5kICR1X2kkIHNhdGlzZnkKCiQkClxkZnJhY3sxfXtcc3FydHtrfX0oXGthcHBhXjIgLSBcRGVsdGFfXEdhbW1hKV57XGxmbG9vciBcYWxwaGEgXHJmbG9vciAvIDJ9IChcdGF1IHVfMCkgPSBcbWF0aGNhbHtXfSxcdGV4dHsgb24gfVxHYW1tYQpcdGFnezIyfSAgClxsYWJlbHt1MF9lcXVhdGlvbn0KJCQKCmFuZCAKCiQkClxkZnJhY3sxfXtcc3FydHtyX2l9fSgoXGthcHBhXjIgLSBcRGVsdGFfXEdhbW1hKV57XGxmbG9vciBcYWxwaGEgXHJmbG9vcn0oXGthcHBhXjIgLSBwX2ktXERlbHRhX1xHYW1tYSkpXnsxLzJ9IChcdGF1IHVfaSkgPSBcbWF0aGNhbHtXfSwgXHRleHR7IG9uIH1cR2FtbWEsIFxxdWFkIGkgPSAxLCBcZG90cywgbS4KXHRhZ3syM30KXGxhYmVse3VpX2VxdWF0aW9ufQokJAoKCiMjIyBDYXNlICRcYWxwaGEgXGluICgwLDEpJAoKSW4gdGhpcyBjYXNlLCBcZXFyZWZ7dTBfZXF1YXRpb259IHJlZHVjZXMgdG8gCgokJApcZGZyYWN7MX17XHNxcnR7a319XHRhdSB1XzAgPSBcbWF0aGNhbHtXfSxcdGV4dHsgb24gfVxHYW1tYQpcdGFnezI0fQpcbGFiZWx7dTBfZXF1YXRpb25fYWxwaGEwMX0KJCQKCmFuZCBcZXFyZWZ7dWlfZXF1YXRpb259IHJlZHVjZXMgdG8KCiQkClxkZnJhY3sxfXtcc3FydHtyX2l9fShca2FwcGFeMiAtIHBfaSAtIFxEZWx0YV9cR2FtbWEpXnsxLzJ9IChcdGF1IHVfaSkgPSBcbWF0aGNhbHtXfSwgXHRleHR7IG9uIH1cR2FtbWEsIFxxdWFkIGkgPSAxLCBcZG90cywgbS4KXHRhZ3syNX0KXGxhYmVse3VpX2VxdWF0aW9uX2FscGhhMDF9ICAgCiQkCgpFcXVhdGlvbiBcZXFyZWZ7dWlfZXF1YXRpb25fYWxwaGEwMX0gaXMganVzdCB0aGUgY2FzZSAkXGFscGhhPTEkIGluIHRoZSBvcmlnaW5hbCBzZXR0aW5nIGJ1dCBub3cgd2l0aCBzaGlmdGVkIHBhcmFtZXRlciAkXGthcHBhXjIgLSBwX2kkIGluc3RlYWQgb2YgJFxrYXBwYV4yJCBhbmQgd2l0aCBhIGNvbnN0YW50IGZhY3RvciAkMS9cc3FydHtyX2l9JC4KCiMjIyBDYXNlICRcYWxwaGEgXGluICgxLDIpJAoKSW4gdGhpcyBjYXNlLCBcZXFyZWZ7dTBfZXF1YXRpb259IHJlZHVjZXMgdG8KJCQKXGRmcmFjezF9e1xzcXJ0e2t9fShca2FwcGFeMiAtIFxEZWx0YV9cR2FtbWEpXnsxLzJ9KFx0YXUgdV8wKSA9IFxtYXRoY2Fse1d9LFx0ZXh0eyBvbiB9XEdhbW1hClx0YWd7MjZ9ClxsYWJlbHt1MF9lcXVhdGlvbl9hbHBoYTEyfQokJAoKYW5kIFxlcXJlZnt1aV9lcXVhdGlvbn0gcmVkdWNlcyB0bwoKJCQKXGRmcmFjezF9e1xzcXJ0e3JfaX19KChca2FwcGFeMiAtIFxEZWx0YV9cR2FtbWEpKFxrYXBwYV4yIC0gcF9pIC0gXERlbHRhX1xHYW1tYSkpXnsxLzJ9IChcdGF1IHVfaSkgPSBcbWF0aGNhbHtXfSwgXHRleHR7IG9uIH1cR2FtbWEsXHF1YWQgaSA9IDEsIFxkb3RzLCBtLgpcdGFnezI3fQpcbGFiZWx7dWlfZXF1YXRpb25fYWxwaGExMn0gICAKJCQKRXF1YXRpb24gXGVxcmVme3UwX2VxdWF0aW9uX2FscGhhMTJ9IGlzIGp1c3QgdGhlIGNhc2UgJFxhbHBoYT0xJCBpbiB0aGUgb3JpZ2luYWwgc2V0dGluZyBidXQgbm93IHdpdGggYSBjb25zdGFudCBmYWN0b3IgJDEvXHNxcnR7a30kLgoKIyMjIENhc2UgJFxhbHBoYSBcaW4gKDIsMykkCgpJbiB0aGlzIGNhc2UsIFxlcXJlZnt1MF9lcXVhdGlvbn0gcmVkdWNlcyB0bwoKJCQKXGRmcmFjezF9e1xzcXJ0e2t9fShca2FwcGFeMiAtIFxEZWx0YV9cR2FtbWEpKFx0YXUgdV8wKSA9IFxtYXRoY2Fse1d9LApcdGFnezI4fQpcbGFiZWx7dTBfZXF1YXRpb25fYWxwaGEyM30KJCQKYW5kIFxlcXJlZnt1aV9lcXVhdGlvbn0gcmVkdWNlcyB0bwokJApcZGZyYWN7MX17XHNxcnR7cl9pfX0oKFxrYXBwYV4yIC0gXERlbHRhX1xHYW1tYSleMihca2FwcGFeMiAtIHBfaSAtIFxEZWx0YV9cR2FtbWEpKV57MS8yfSAoXHRhdSB1X2kpID0gXG1hdGhjYWx7V30sIFxxdWFkIGkgPSAxLCBcZG90cywgbS4KXHRhZ3syOX0KXGxhYmVse3VpX2VxdWF0aW9uX2FscGhhMjN9ICAgCiQkCgpFcXVhdGlvbiBcZXFyZWZ7dTBfZXF1YXRpb25fYWxwaGEyM30gaXMganVzdCB0aGUgY2FzZSAkXGFscGhhPTIkIGluIHRoZSBvcmlnaW5hbCBzZXR0aW5nIGJ1dCBub3cgd2l0aCBhIGNvbnN0YW50IGZhY3RvciAkMS9cc3FydHtrfSQuCgoKIyMjIE1hdHJpeCB2ZXJzaW9uCgpMZXQgCgokJApcbWF0aGJme3V9KHMpID0gW3UocyksIHUnKHMpLCBcZG90cywgdV57KFxsZmxvb3IgXGFscGhhIFxyZmxvb3IpfShzKV1eXHRvcFxpblxtYXRoYmJ7Un1ee1xsZmxvb3IgXGFscGhhIFxyZmxvb3IgKyAxfQpcdGFnezMwfQpcbGFiZWx7dV92ZWN0b3JfZnJhY3Rpb25hbH0KJCQKCmFuZCAKCiQkClx3aWRldGlsZGV7XG1hdGhiZnt1fX0ocyk9XGxlZnRbXHdpZGV0aWxkZXt1fShzKSwgXHdpZGV0aWxkZXt1fV57XHByaW1lfShzKSxcbGRvdHMsIFx3aWRldGlsZGV7dX1eeyhcbGZsb29yIFxhbHBoYSBccmZsb29yKX0ocylccmlnaHRdXntcdG9wfSBcaW5cbWF0aGJie1J9XntcbGZsb29yIFxhbHBoYSBccmZsb29yICsgMX0KXHRhZ3szMX0KJCQKCmFuZAoKCiQkClxtYXRoYmZ7dX0oXG1hdGhiZntzfSkgPSBcd2lkZXRpbGRle1xtYXRoYmZ7dX19KFxtYXRoYmZ7c30pfCBcbWF0aGNhbHtLfV97XGxmbG9vclxhbHBoYVxyZmxvb3J9KFx3aWRldGlsZGV7dX0pLApcdGFnezMyfQokJAoKYW5kIAoKJCQKXG1hdGhiZnt1fShcbWF0aGJme3N9KSA9IFtcbWF0aGJme3V9KHNfMSksIFxtYXRoYmZ7dX0oc18yKSwgXGRvdHMsIFxtYXRoYmZ7dX0oc19uKV1eXHRvcCBcaW5cbWF0aGJie1J9XntuKFxsZmxvb3IgXGFscGhhIFxyZmxvb3IgKyAxKX0KJCQKCmFuZAoKJCQKXHdpZGV0aWxkZXtcbWF0aGJme3V9fShcbWF0aGJme3N9KSA9IFtcd2lkZXRpbGRle1xtYXRoYmZ7dX19KHNfMSksIFx3aWRldGlsZGV7XG1hdGhiZnt1fX0oc18yKSwgXGRvdHMsIFx3aWRldGlsZGV7XG1hdGhiZnt1fX0oc19uKV1eXHRvcCBcaW5cbWF0aGJie1J9XntuKFxsZmxvb3IgXGFscGhhIFxyZmxvb3IgKyAxKX0KJCQKYW5kIAoKJCQKXG1hdGhiZntzfSA9IFtzXzEsIHNfMiwgXGRvdHMsIHNfbl1eXHRvcFxpblxtYXRoYmJ7Un1ebixccXVhZCBzXzEsc18yLFxkb3RzLHNfblxpblxHYW1tYQokJAoKYW5kIAoKJCQKXG1hdGhiZntVfT1cbGVmdFtcbWF0aGJme3V9KFx1bmRlcmxpbmV7ZX1fMSlee1x0b3B9LCBcbWF0aGJme3V9KFxvdmVybGluZXtlfV8xKV57XHRvcH0sIFxtYXRoYmZ7dX0oXHVuZGVybGluZXtlfV8yKV57XHRvcH0sIFxtYXRoYmZ7dX0oXG92ZXJsaW5le2V9XzIpXntcdG9wfSwgXGxkb3RzLCBcbWF0aGJme3V9KFx1bmRlcmxpbmV7ZX1fe3xcbWF0aGNhbHtFfXx9KV57XHRvcH0sIFxtYXRoYmZ7dX0oXG92ZXJsaW5le2V9X3t8XG1hdGhjYWx7RX18fSlee1x0b3B9XHJpZ2h0XV57XHRvcH1caW5cbWF0aGJie1J9XnsyKFxsZmxvb3IgXGFscGhhIFxyZmxvb3IgKyAxKXxcbWF0aGNhbHtFfXx9Clx0YWd7MzN9CiQkCgphbmQKCgokJApcd2lkZXRpbGRle1xtYXRoYmZ7VX19PVxsZWZ0W1x3aWRldGlsZGV7XG1hdGhiZnt1fX1fMShcdW5kZXJsaW5le2V9XzEpXntcdG9wfSwgXHdpZGV0aWxkZXtcbWF0aGJme3V9fV8xKFxvdmVybGluZXtlfV8xKV57XHRvcH0sIFx3aWRldGlsZGV7XG1hdGhiZnt1fX1fMihcdW5kZXJsaW5le2V9XzIpXntcdG9wfSwgXHdpZGV0aWxkZXtcbWF0aGJme3V9fV8yKFxvdmVybGluZXtlfV8yKV57XHRvcH0sIFxsZG90cywgXHdpZGV0aWxkZXtcbWF0aGJme3V9fV97fFxtYXRoY2Fse0V9fH0oXHVuZGVybGluZXtlfV97fFxtYXRoY2Fse0V9fH0pXntcdG9wfSwgXHdpZGV0aWxkZXtcbWF0aGJme3V9fV97fFxtYXRoY2Fse0V9fH0oXG92ZXJsaW5le2V9X3t8XG1hdGhjYWx7RX18fSlee1x0b3B9XHJpZ2h0XV57XHRvcH1caW5cbWF0aGJie1J9XnsyKFxsZmxvb3IgXGFscGhhIFxyZmxvb3IgKyAxKXxcbWF0aGNhbHtFfXx9Clx0YWd7MzR9CiQkCgpXZSB0aGVuIGhhdmUgdGhhdAoKJCQKXG1hdGhiZnt1fV8wKHMpID0gXHdpZGV0aWxkZXtcbWF0aGJme3V9fV8wKHMpfCBcbWF0aGNhbHtLfV97XGxmbG9vclxhbHBoYVxyZmxvb3ItMX0oXHdpZGV0aWxkZXt1fV8wKSwKXHRhZ3szNX0KJCQKCmFuZCAKCiQkClxtYXRoYmZ7dX1faShzKSA9IFx3aWRldGlsZGV7XG1hdGhiZnt1fX1faShzKXwgXG1hdGhjYWx7S31fe1xsZmxvb3JcYWxwaGFccmZsb29yfShcd2lkZXRpbGRle3V9X2kpLFxxdWFkIGk9MSxcZG90cyxtLApcdGFnezM1fQokJAoKd2hlcmUKCiQkClx3aWRldGlsZGV7XG1hdGhiZnt1fX1fMChzKT1cbGVmdFtcd2lkZXRpbGRle3V9XzAocyksIFx3aWRldGlsZGV7dX1fMF57XHByaW1lfShzKSxcbGRvdHMsIFx3aWRldGlsZGV7dX1fMF57KFxsZmxvb3IgXGFscGhhIFxyZmxvb3ItMSl9KHMpXHJpZ2h0XV57XHRvcH0gXGluXG1hdGhiYntSfV57XGxmbG9vciBcYWxwaGEgXHJmbG9vcn0KXHRhZ3szNn0KJCQKCmhhcyBjb3ZhcmlhbmNlIGZ1bmN0aW9uIAoKCjo6OiB7LmN1c3RvbS1ib3h9CgpDb3ZhcmlhbmNlIG9mIHRoZSBib3VuZGFyeWxlc3MgcHJvY2VzcyBvbiBhbiBpbnRlcnZhbCAkWzAsIFxlbGxdJAoKJCQKXHdpZGV0aWxkZXtcbWF0aGJme3J9fVxsZWZ0KHRfMSwgdF8yXHJpZ2h0KT1cbWF0aGJme3J9XGxlZnQodF8xLCB0XzJccmlnaHQpK1xsZWZ0W1xtYXRoYmZ7cn1cbGVmdCh0XzEsIDBccmlnaHQpIFxtYXRoYmZ7cn1cbGVmdCh0XzEsIFxlbGxccmlnaHQpXHJpZ2h0XVxsZWZ0W1xiZWdpbnthcnJheX17Y2N9ClxtYXRoYmZ7cn0oMCwwKSAmIC1cbWF0aGJme3J9KDAsIFxlbGwpIFxcCi1cbWF0aGJme3J9KFxlbGwsIDApICYgXG1hdGhiZntyfSgwLDApClxlbmR7YXJyYXl9XHJpZ2h0XV57LTF9XGxlZnRbXGJlZ2lue2FycmF5fXtsfQpcbWF0aGJme3J9XGxlZnQodF8yLCAwXHJpZ2h0KSBcXApcbWF0aGJme3J9XGxlZnQodF8yLCBcZWxsXHJpZ2h0KQpcZW5ke2FycmF5fVxyaWdodF0KXHRhZ3szN30KJCQKCjo6OgoKOjo6IHsuY3VzdG9tLWJveH0KCkNvdmFyaWFuY2Ugb2YgdGhlIGNvcnJlc3BvbmRpbmcgdW5yZXN0cmljdGVkIHByb2Nlc3Mgb24gJFxtYXRoYmJ7Un0kCgokJApcbWF0aGJme3J9OiBcbWF0aGJie1J9IFx0aW1lcyBcbWF0aGJie1J9IFxtYXBzdG8gXG1hdGhiYntSfV57XGxmbG9vclxhbHBoYSBccmZsb29yXHRpbWVzIFxsZmxvb3JcYWxwaGFccmZsb29yfSwgXHF1YWQgXG1hdGhiZntyfVxsZWZ0KHRfMSwgdF8yXHJpZ2h0KT1cbGVmdFtcZnJhY3tccGFydGlhbF57aS0xfX17XHBhcnRpYWwgdF8yXntpLTF9fSBcZnJhY3tccGFydGlhbF57ai0xfX17XHBhcnRpYWwgdF8xXntqLTF9fSBcdmFycmhvX01cbGVmdCh0XzEtdF8yXHJpZ2h0KVxyaWdodF1fe2kgaiBcaW5cezEsMiwgXGxkb3RzLCBcbGZsb29yXGFscGhhXHJmbG9vclx9fQpcdGFnezM4fQokJAo6OjoKCmFuZCAKCiQkClx3aWRldGlsZGV7XG1hdGhiZnt1fX1faShzKT1cbGVmdFtcd2lkZXRpbGRle3V9X2kocyksIFx3aWRldGlsZGV7dX1faV57XHByaW1lfShzKSxcbGRvdHMsIFx3aWRldGlsZGV7dX1faV57KFxsZmxvb3IgXGFscGhhIFxyZmxvb3IpfShzKVxyaWdodF1ee1x0b3B9IFxpblxtYXRoYmJ7Un1ee1xsZmxvb3IgXGFscGhhIFxyZmxvb3IrMX0KXHRhZ3szOX0KJCQKaGFzIGNvdmFyaWFuY2UgZnVuY3Rpb24gCgoKOjo6IHsuY3VzdG9tLWJveH0KCkNvdmFyaWFuY2Ugb2YgdGhlIHNoaWZ0ZWQgYm91bmRhcnlsZXNzIHByb2Nlc3Mgb24gYW4gaW50ZXJ2YWwgJFswLCBcZWxsXSQKCiQkClx3aWRldGlsZGV7XG1hdGhiZntyfX1faVxsZWZ0KHRfMSwgdF8yXHJpZ2h0KT1cbWF0aGJme3J9X2lcbGVmdCh0XzEsIHRfMlxyaWdodCkrXGxlZnRbXG1hdGhiZntyfV9pXGxlZnQodF8xLCAwXHJpZ2h0KSBcbWF0aGJme3J9X2lcbGVmdCh0XzEsIFxlbGxccmlnaHQpXHJpZ2h0XVxsZWZ0W1xiZWdpbnthcnJheX17Y2N9ClxtYXRoYmZ7cn1faSgwLDApICYgLVxtYXRoYmZ7cn1faSgwLCBcZWxsKSBcXAotXG1hdGhiZntyfV9pKFxlbGwsIDApICYgXG1hdGhiZntyfV9pKDAsMCkKXGVuZHthcnJheX1ccmlnaHRdXnstMX1cbGVmdFtcYmVnaW57YXJyYXl9e2x9ClxtYXRoYmZ7cn1faVxsZWZ0KHRfMiwgMFxyaWdodCkgXFwKXG1hdGhiZntyfV9pXGxlZnQodF8yLCBcZWxsXHJpZ2h0KQpcZW5ke2FycmF5fVxyaWdodF0KXHRhZ3s0MH0KJCQKCjo6OgoKCjo6OiB7LmN1c3RvbS1ib3h9CgpDb3ZhcmlhbmNlIG9mIHRoZSBjb3JyZXNwb25kaW5nIHVucmVzdHJpY3RlZCBwcm9jZXNzIG9uICRcbWF0aGJie1J9JAoKJCQKXG1hdGhiZntyfV9pOiBcbWF0aGJie1J9IFx0aW1lcyBcbWF0aGJie1J9IFxtYXBzdG8gXG1hdGhiYntSfV57XGxjZWlsXGFscGhhXHJjZWlsXHRpbWVzIFxsY2VpbFxhbHBoYVxyY2VpbH0sIFxxdWFkIFxtYXRoYmZ7cn1faVxsZWZ0KHRfMSwgdF8yXHJpZ2h0KT1cbGVmdFtcZnJhY3tccGFydGlhbF57aS0xfX17XHBhcnRpYWwgdF8yXntpLTF9fSBcZnJhY3tccGFydGlhbF57ai0xfX17XHBhcnRpYWwgdF8xXntqLTF9fSBcZGZyYWN7XHZhcnJob197bSwgaX1eXGFscGhhXGxlZnQodF8xLXRfMlxyaWdodCl9e3JfaVxzaWdtYV4yfVxyaWdodF1fe2kgaiBcaW5cezEsMiwgXGxkb3RzLCBcbGNlaWxcYWxwaGFccmNlaWxcfX0KXHRhZ3s0MX0KJCQKCjo6OgoKVGhlIHByZWNpc2lvbiBtYXRyaXggb2YgJFtcd2lkZXRpbGRle1xtYXRoYmZ7dX19X3swLGV9KDApLCBcd2lkZXRpbGRle1xtYXRoYmZ7dX19X3swLGV9KFxlbGwpXSQgaXMgCgokJApcd2lkZXRpbGRle1xtYXRoYmZ7UX19X3swLGV9PVxtYXRoYmZ7UX1fezAsZX0tXGZyYWN7MX17Mn1cbGVmdFtcYmVnaW57YXJyYXl9e2NjfQpcbWF0aGJme3J9KDAsMCleey0xfSAmIFxtYXRoYmZ7MH0gXFwKXG1hdGhiZnswfSAmIFxtYXRoYmZ7cn0oMCwwKV57LTF9ClxlbmR7YXJyYXl9XHJpZ2h0XVxpblxtYXRoYmJ7Un1eezIgXGxmbG9vclxhbHBoYVxyZmxvb3IgXHRpbWVzIDIgXGxmbG9vclxhbHBoYVxyZmxvb3J9LAokJAoKd2hlcmUgJFxtYXRoYmZ7UX1fezAsZX0kIGlzIHRoZSBwcmVjaXNpb24gbWF0cml4IG9mICRbXG1hdGhiZnt1fV97MCxlfSgwKSwgXG1hdGhiZnt1fV97MCxlfShcZWxsKV0kLgoKClRoZSBwcmVjaXNpb24gbWF0cml4IG9mICRbXHdpZGV0aWxkZXtcbWF0aGJme3V9fV97aSxlfSgwKSwgXHdpZGV0aWxkZXtcbWF0aGJme3V9fV97aSxlfShcZWxsKV0kIGlzIAoKJCQKXHdpZGV0aWxkZXtcbWF0aGJme1F9fV97aSxlfT1cbWF0aGJme1F9X3tpLGV9LVxmcmFjezF9ezJ9XGxlZnRbXGJlZ2lue2FycmF5fXtjY30KXG1hdGhiZntyfV9pKDAsMCleey0xfSAmIFxtYXRoYmZ7MH0gXFwKXG1hdGhiZnswfSAmIFxtYXRoYmZ7cn1faSgwLDApXnstMX0KXGVuZHthcnJheX1ccmlnaHRdXGluXG1hdGhiYntSfV57MiBcbGNlaWxcYWxwaGFccmNlaWwgXHRpbWVzIDIgXGxjZWlsXGFscGhhXHJjZWlsfSwKJCQKCndoZXJlICRcbWF0aGJme1F9X3tpLGV9JCBpcyB0aGUgcHJlY2lzaW9uIG1hdHJpeCBvZiAkW1xtYXRoYmZ7dX1fe2ksZX0oMCksIFxtYXRoYmZ7dX1fe2ksZX0oXGVsbCldJC4KCgpEZWZpbmUgCgokJApcd2lkZXRpbGRle1xtYXRoYmZ7VX19XzA9XGxlZnRbXHdpZGV0aWxkZXtcbWF0aGJme3V9fV97MCwxfShcdW5kZXJsaW5le2V9XzEpXntcdG9wfSwgXHdpZGV0aWxkZXtcbWF0aGJme3V9fV97MCwxfShcb3ZlcmxpbmV7ZX1fMSlee1x0b3B9LCBcd2lkZXRpbGRle1xtYXRoYmZ7dX19X3tpLDJ9KFx1bmRlcmxpbmV7ZX1fMilee1x0b3B9LCBcd2lkZXRpbGRle1xtYXRoYmZ7dX19X3swLDJ9KFxvdmVybGluZXtlfV8yKV57XHRvcH0sIFxsZG90cywgXHdpZGV0aWxkZXtcbWF0aGJme3V9fV97MCx8XG1hdGhjYWx7RX18fShcdW5kZXJsaW5le2V9X3t8XG1hdGhjYWx7RX18fSlee1x0b3B9LCBcd2lkZXRpbGRle1xtYXRoYmZ7dX19X3swLHxcbWF0aGNhbHtFfXx9KFxvdmVybGluZXtlfV97fFxtYXRoY2Fse0V9fH0pXntcdG9wfVxyaWdodF1ee1x0b3B9XGluXG1hdGhiYntSfV57MlxsZmxvb3IgXGFscGhhIFxyZmxvb3J8XG1hdGhjYWx7RX18fQpcdGFnezQyfQokJAoKYW5kCgoKJCQKXHdpZGV0aWxkZXtcbWF0aGJme1V9fV9pPVxsZWZ0W1x3aWRldGlsZGV7XG1hdGhiZnt1fX1fe2ksMX0oXHVuZGVybGluZXtlfV8xKV57XHRvcH0sIFx3aWRldGlsZGV7XG1hdGhiZnt1fX1fe2ksMX0oXG92ZXJsaW5le2V9XzEpXntcdG9wfSwgXHdpZGV0aWxkZXtcbWF0aGJme3V9fV97aSwyfShcdW5kZXJsaW5le2V9XzIpXntcdG9wfSwgXHdpZGV0aWxkZXtcbWF0aGJme3V9fV97aSwyfShcb3ZlcmxpbmV7ZX1fMilee1x0b3B9LCBcbGRvdHMsIFx3aWRldGlsZGV7XG1hdGhiZnt1fX1fe2ksfFxtYXRoY2Fse0V9fH0oXHVuZGVybGluZXtlfV97fFxtYXRoY2Fse0V9fH0pXntcdG9wfSwgXHdpZGV0aWxkZXtcbWF0aGJme3V9fV97aSx8XG1hdGhjYWx7RX18fShcb3ZlcmxpbmV7ZX1fe3xcbWF0aGNhbHtFfXx9KV57XHRvcH1ccmlnaHRdXntcdG9wfVxpblxtYXRoYmJ7Un1eezIoXGxmbG9vciBcYWxwaGEgXHJmbG9vciArIDEpfFxtYXRoY2Fse0V9fH0sXHF1YWQgaT0wLFxkb3RzLG0sClx0YWd7NDN9CiQkCgpUaGVuIAoKJCQKXHdpZGV0aWxkZXtcbWF0aGJme1V9fV8wXHNpbSBcbWF0aHJte059XGxlZnQoXG1hdGhiZnswfSwgXHdpZGV0aWxkZXtcbWF0aGJme1F9fV8wXnstMX1ccmlnaHQpLCBccXVhZCBcd2lkZXRpbGRle1xtYXRoYmZ7UX19XzAgPSBcb3BlcmF0b3JuYW1le2RpYWd9XGxlZnQoXHtcd2lkZXRpbGRle1xtYXRoYmZ7UX19X3swLGV9XH1fe2VcaW5cbWF0aGNhbHtFfX1ccmlnaHQpLAokJCAKCmFuZCAKCiQkClx3aWRldGlsZGV7XG1hdGhiZntVfX1faVxzaW0gXG1hdGhybXtOfVxsZWZ0KFxtYXRoYmZ7MH0sIFx3aWRldGlsZGV7XG1hdGhiZntRfX1faV57LTF9XHJpZ2h0KSwgXHF1YWRcd2lkZXRpbGRle1xtYXRoYmZ7UX19X2kgPSBcb3BlcmF0b3JuYW1le2RpYWd9XGxlZnQoXHtcd2lkZXRpbGRle1xtYXRoYmZ7UX19X3tpLGV9XH1fe2VcaW5cbWF0aGNhbHtFfX1ccmlnaHQpLFxxdWFkIGk9MSxcZG90cyxtLgokJAoKIyMgQXV4aWxpYXJ5IGZ1bmN0aW9ucyB7I2F1eGlsaWFyeV9mdW5jdGlvbnN9CgojIyMgRnVuY3Rpb24gYGdldHMuZ3JhcGgudGFkcG9sZSgpYAoKR2l2ZW4gYSBtZXNoIHNpemUgYGhgLCBmdW5jdGlvbiBgZ2V0cy5ncmFwaC50YWRwb2xlKClgIGJ1aWxkcyBhIHRhZHBvbGUgZ3JhcGggYW5kIGNyZWF0ZXMgYSBtZXNoLgoKCmBgYHtyfQojIEZ1bmN0aW9uIHRvIGJ1aWxkIGEgdGFkcG9sZSBncmFwaCBhbmQgY3JlYXRlIGEgbWVzaApnZXRzLmdyYXBoLnRhZHBvbGUgPC0gZnVuY3Rpb24oZmxpcF9lZGdlID0gRkFMU0UpewogIGlmKGZsaXBfZWRnZSkgewogICAgZWRnZTEgPC0gcmJpbmQoYygwLDApLGMoMSwwKSlbYygyLDEpLF0KICAgIH0gZWxzZSB7CiAgICBlZGdlMSA8LSByYmluZChjKDAsMCksYygxLDApKX0KICB0aGV0YSA8LSBzZXEoZnJvbT0tcGksdG89cGksbGVuZ3RoLm91dCA9IDEwMDAwKQogIGVkZ2UyIDwtIGNiaW5kKDErMS9waStjb3ModGhldGEpL3BpLHNpbih0aGV0YSkvcGkpCiAgZWRnZXMgPC0gbGlzdChlZGdlMSwgZWRnZTIpCiAgZ3JhcGggPC0gbWV0cmljX2dyYXBoJG5ldyhlZGdlcyA9IGVkZ2VzLCB2ZXJib3NlID0gMCkKICBncmFwaCRzZXRfbWFudWFsX2VkZ2VfbGVuZ3RocyhlZGdlX2xlbmd0aHMgPSBjKDEsMikpCiAgI2dyYXBoJGJ1aWxkX21lc2goaCA9IGgpCiAgcmV0dXJuKGdyYXBoKQp9CmBgYAoKCgpgYGB7cn0KIyBFaWdlbmZ1bmN0aW9ucyBmb3IgdGhlIHRhZHBvbGUgZ3JhcGgKdGFkcG9sZS5laWcgPC0gZnVuY3Rpb24oayxncmFwaCl7CiAgeDEgPC0gYygwLGdyYXBoJGdldF9lZGdlX2xlbmd0aHMoKVsxXSpncmFwaCRtZXNoJFB0RVtncmFwaCRtZXNoJFB0RVssMV09PTEsMl0pIAogIHgyIDwtIGMoMCxncmFwaCRnZXRfZWRnZV9sZW5ndGhzKClbMl0qZ3JhcGgkbWVzaCRQdEVbZ3JhcGgkbWVzaCRQdEVbLDFdPT0yLDJdKSAKICAKICBpZihrPT0wKXsgCiAgICBmLmUxIDwtIHJlcCgxLGxlbmd0aCh4MSkpIAogICAgZi5lMiA8LSByZXAoMSxsZW5ndGgoeDIpKSAKICAgIGYxID0gYyhmLmUxWzFdLGYuZTJbMV0sZi5lMVstMV0sIGYuZTJbLTFdKSAKICAgIGYgPSBsaXN0KHBoaT1mMS9zcXJ0KDMpKSAKICAgIAogIH0gZWxzZSB7CiAgICBmLmUxIDwtIC0yKnNpbihwaSprKjEvMikqY29zKHBpKmsqeDEvMikgCiAgICBmLmUyIDwtIHNpbihwaSprKngyLzIpICAgICAgICAgICAgICAgICAgCiAgICAKICAgIGYxID0gYyhmLmUxWzFdLGYuZTJbMV0sZi5lMVstMV0sIGYuZTJbLTFdKSAKICAgIAogICAgaWYoKGsgJSUgMik9PTEpeyAKICAgICAgZiA9IGxpc3QocGhpPWYxL3NxcnQoMykpIAogICAgfSBlbHNlIHsgCiAgICAgIGYuZTEgPC0gKC0xKV57ay8yfSpjb3MocGkqayp4MS8yKQogICAgICBmLmUyIDwtIGNvcyhwaSprKngyLzIpCiAgICAgIGYyID0gYyhmLmUxWzFdLGYuZTJbMV0sZi5lMVstMV0sZi5lMlstMV0pIAogICAgICBmIDwtIGxpc3QocGhpPWYxLHBzaT1mMi9zcXJ0KDMvMikpCiAgICB9CiAgfQogIAogIHJldHVybihmKQp9CgoKIyBGdW5jdGlvbiB0byBjb21wdXRlIHRoZSB0cnVlIGNvdmFyaWFuY2UgbWF0cml4CmdldHNfdHJ1ZV9jb3ZfbWF0IDwtIGZ1bmN0aW9uKGdyYXBoLCBrYXBwYSwgdGF1LCBhbHBoYSwgbi5vdmVya2lsbCl7CiAgU2lnbWEua2wgPC0gbWF0cml4KDAsbnJvdyA9IGRpbShncmFwaCRtZXNoJFYpWzFdLG5jb2wgPSBkaW0oZ3JhcGgkbWVzaCRWKVsxXSkKICBmb3IoaSBpbiAwOm4ub3ZlcmtpbGwpewogICAgcGhpIDwtIHRhZHBvbGUuZWlnKGksZ3JhcGgpJHBoaQogICAgU2lnbWEua2wgPC0gU2lnbWEua2wgKyAoMS8oa2FwcGFeMiArIChpKnBpLzIpXjIpXihhbHBoYSkpKnBoaSUqJXQocGhpKQogICAgaWYoaT4wICYmIChpICUlIDIpPT0wKXsgCiAgICAgIHBzaSA8LSB0YWRwb2xlLmVpZyhpLGdyYXBoKSRwc2kKICAgICAgU2lnbWEua2wgPC0gU2lnbWEua2wgKyAoMS8oa2FwcGFeMiArIChpKnBpLzIpXjIpXihhbHBoYSkpKnBzaSUqJXQocHNpKQogICAgfQogICAgCiAgfQogIFNpZ21hLmtsIDwtIFNpZ21hLmtsL3RhdV4yCiAgcmV0dXJuKFNpZ21hLmtsKQp9CmBgYAoKCmBgYHtyfQpRYWxwaGExIDwtIGZ1bmN0aW9uKHRoZXRhLCBncmFwaCwgQkMgPSAxLCBidWlsZCA9IFRSVUUpIHsKICAKICBrYXBwYSA8LSB0aGV0YVsyXQogIHRhdSA8LSB0aGV0YVsxXQogIGlfIDwtIGpfIDwtIHhfIDwtIHJlcCgwLCBkaW0oZ3JhcGgkVilbMV0qNCkgIyBpdCBoYXMgbGVuZ3RoIDQqblYKICBjb3VudCA8LSAwCiAgZm9yKGkgaW4gMTpncmFwaCRuRSl7ICMgbG9vcCBvdmVyIGVkZ2VzCiAgICBsX2UgPC0gZ3JhcGgkZWRnZV9sZW5ndGhzW2ldCiAgICBjMSA8LSBleHAoLWthcHBhKmxfZSkKICAgIGMyIDwtIGMxXjIKICAgIG9uZV9tX2MyID0gMS1jMgogICAgY18xID0gMC41ICsgYzIvb25lX21fYzIKICAgIGNfMiA9IC1jMS9vbmVfbV9jMgogICAgCiAgICBpZiAoZ3JhcGgkRVtpLCAxXSAhPSBncmFwaCRFW2ksIDJdKSB7ICMgVGhpcyBpcyBmb3Igbm9uLWNpcmN1bGFyIGVkZ2VzIGFuZCBjb2RlcyBJKG92ZXJsaW5lKGUpICE9IHVuZGVybGluZShlKSkKICAgICAgCiAgICAgIGlfW2NvdW50ICsgMV0gPC0gZ3JhcGgkRVtpLCAxXQogICAgICBqX1tjb3VudCArIDFdIDwtIGdyYXBoJEVbaSwgMV0KICAgICAgeF9bY291bnQgKyAxXSA8LSBjXzEKICAgICAgCiAgICAgIGlfW2NvdW50ICsgMl0gPC0gZ3JhcGgkRVtpLCAyXQogICAgICBqX1tjb3VudCArIDJdIDwtIGdyYXBoJEVbaSwgMl0KICAgICAgeF9bY291bnQgKyAyXSA8LSBjXzEKICAgICAgCiAgICAgIAogICAgICBpX1tjb3VudCArIDNdIDwtIGdyYXBoJEVbaSwgMV0KICAgICAgal9bY291bnQgKyAzXSA8LSBncmFwaCRFW2ksIDJdCiAgICAgIHhfW2NvdW50ICsgM10gPC0gY18yCiAgICAgIAogICAgICBpX1tjb3VudCArIDRdIDwtIGdyYXBoJEVbaSwgMl0KICAgICAgal9bY291bnQgKyA0XSA8LSBncmFwaCRFW2ksIDFdCiAgICAgIHhfW2NvdW50ICsgNF0gPC0gY18yCiAgICAgIGNvdW50IDwtIGNvdW50ICsgNAogICAgfWVsc2V7ICMgVGhpcyBpcyBmb3IgY2lyY3VsYXIgZWRnZXMgYW5kIGNvZGVzIEkob3ZlcmxpbmUoZSkgPSB1bmRlcmxpbmUoZSkpCiAgICAgIGlfW2NvdW50ICsgMV0gPC0gZ3JhcGgkRVtpLCAxXQogICAgICBqX1tjb3VudCArIDFdIDwtIGdyYXBoJEVbaSwgMV0KICAgICAgeF9bY291bnQgKyAxXSA8LSB0YW5oKDAuNSAqIGthcHBhICogbF9lKQogICAgICBjb3VudCA8LSBjb3VudCArIDEKICAgIH0KCiAgfQogIGlmKEJDID09IDEpewogICAgI2RvZXMgdGhpcyB3b3JrIGZvciBjaXJjbGU/CiAgICBpLnRhYmxlIDwtIHRhYmxlKGlfWzE6Y291bnRdKQogICAgaW5kZXggPSBhcy5pbnRlZ2VyKG5hbWVzKHdoaWNoKGkudGFibGUgPCAzKSkpCiAgICBpXyA8LSBjKGlfWzE6Y291bnRdLCBpbmRleCkKICAgIGpfIDwtIGMoal9bMTpjb3VudF0sIGluZGV4KQogICAgeF8gPC0gYyh4X1sxOmNvdW50XSwgcmVwKDAuNSwgbGVuZ3RoKGluZGV4KSkpICMgaGVyZSBpcyB3aGVyZSB3ZSBhZGQgdGhlIDAuNSBmb3IgZGVncmVlIG9uZSB2ZXJ0aWNlcwogICAgY291bnQgPC0gY291bnQgKyBsZW5ndGgoaW5kZXgpCiAgICAjIHByaW50KGlfKQogICAgIyBwcmludChqXykKICB9ZWxzZSBpZihCQz09Mil7CiAgICAKICAgIGRWIDwtIGdyYXBoJGdldF92ZXJ0aWNlcygpJGRlZ3JlZQogICAgaW5kZXggPC0gMTpsZW5ndGgoZFYpCiAgICBpXyA8LSBjKGlfWzE6Y291bnRdLCBpbmRleCkKICAgIGpfIDwtIGMoal9bMTpjb3VudF0sIGluZGV4KQogICAgeF8gPC0gYyh4X1sxOmNvdW50XSwgLTAuNSpkViArIDEpCiAgICBjb3VudCA8LSBjb3VudCArIGxlbmd0aChpbmRleCkKICAgIAogIH0KICBpZihidWlsZCl7CiAgICBRIDwtIE1hdHJpeDo6c3BhcnNlTWF0cml4KGkgPSBpX1sxOmNvdW50XSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaiA9IGpfWzE6Y291bnRdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gKDIgKiBrYXBwYSAqIHRhdV4yKSAqIHhfWzE6Y291bnRdLCAjIFRoaXMgaXMgdGhlIDJrYXBwYSp0YXVeMiBmYWN0b3IKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGltcyA9IGMoZ3JhcGgkblYsIGdyYXBoJG5WKSkKICAgIAogICAgCiAgICByZXR1cm4oUSkKICB9IGVsc2UgewogICAgcmV0dXJuKGxpc3QoaSA9IGlfWzE6Y291bnRdLAogICAgICAgICAgICAgICAgaiA9IGpfWzE6Y291bnRdLAogICAgICAgICAgICAgICAgeCA9ICgyICoga2FwcGEgKiB0YXVeMikgKiB4X1sxOmNvdW50XSwKICAgICAgICAgICAgICAgIGRpbXMgPSBjKGdyYXBoJG5WLCBncmFwaCRuVikpKQogIH0KfQpgYGAKCgpgYGB7cn0KZ2l2ZXMuaW5kaWNlcyA8LSBmdW5jdGlvbihncmFwaCwgZmFjdG9yLCBjb25zdGFudCl7CiAgaW5kZXgub2JzMSA8LSBzYXBwbHkoZ3JhcGgkUHRWLCAKICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbihpKXsKICAgICAgICAgICAgICAgICAgICAgICAgIGlkeF90ZW1wIDwtIGkgPT0gZ3JhcGgkRVssMV0KICAgICAgICAgICAgICAgICAgICAgICAgIGlkeF90ZW1wIDwtIHdoaWNoKGlkeF90ZW1wKQogICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuKGlkeF90ZW1wWzFdKX0KICAgICAgICAgICAgICAgICAgICAgICApCiAgaW5kZXgub2JzMSA8LSAoaW5kZXgub2JzMSAtIDEpICogZmFjdG9yICsgMQogIGluZGV4Lm9iczQgPC0gTlVMTAogIG5hX29iczEgPC0gaXMubmEoaW5kZXgub2JzMSkKICBpZihhbnkobmFfb2JzMSkpewogICAgaWR4X25hIDwtIHdoaWNoKG5hX29iczEpCiAgICBQdFZfTkEgPC0gZ3JhcGgkUHRWW2lkeF9uYV0KICAgIGluZGV4Lm9iczQgPC0gc2FwcGx5KFB0Vl9OQSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbihpKXsKICAgICAgICAgICAgICAgICAgICAgICAgICAgaWR4X3RlbXAgPC0gaSA9PSBncmFwaCRFWywyXQogICAgICAgICAgICAgICAgICAgICAgICAgICBpZHhfdGVtcCA8LSB3aGljaChpZHhfdGVtcCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuKGlkeF90ZW1wWzFdKX0KICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgIGluZGV4Lm9iczFbbmFfb2JzMV0gPC0gKGluZGV4Lm9iczQgLSAxICkgKiBmYWN0b3IgKyBjb25zdGFudCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICB9CiAgcmV0dXJuKGluZGV4Lm9iczEpCn0KCmNvbmRpdGlvbmluZyA8LSBmdW5jdGlvbihncmFwaCwgYWxwaGEgPSAxKXsKICBpXyAgPSAgcmVwKDAsIDIgKiBncmFwaCRuRSkKICBqXyAgPSAgcmVwKDAsIDIgKiBncmFwaCRuRSkKICB4XyAgPSAgcmVwKDAsIDIgKiBncmFwaCRuRSkKCiAgY291bnRfY29uc3RyYWludCA8LSAwCiAgY291bnQgPC0gMAogIGZvciAodiBpbiAxOmdyYXBoJG5WKSB7CiAgICBlZGdlc19sZWF2aW5nX3YgIDwtIHdoaWNoKGdyYXBoJEVbLCAxXSAlaW4lIHYpIAogICAgZWRnZXNfZW50ZXJpbmdfdiAgPC0gd2hpY2goZ3JhcGgkRVssIDJdICVpbiUgdikKICAgIG5fbGVhdmluZ19lZGdlcyA8LSBsZW5ndGgoZWRnZXNfbGVhdmluZ192KQogICAgbl9lbnRlcmluZ19lZGdlcyA8LSBsZW5ndGgoZWRnZXNfZW50ZXJpbmdfdikKICAgIG5fZSA8LSBuX2xlYXZpbmdfZWRnZXMgKyBuX2VudGVyaW5nX2VkZ2VzCiAgICBpZiAobl9lID4gMSkgeyAjIHRoZSBhbHRlcm5hdGl2ZSBpcyBuX2UgPSAxLCB3aGljaCBtZWFucyB2IGlzIGEgZGVncmVlIG9uZSB2ZXJ0ZXggYW5kIHNvIG5vIGNvbmRpdGlvbmluZyBpcyBuZWVkZWQgCiAgICAgIGlmIChuX2VudGVyaW5nX2VkZ2VzID09IDApIHsKICAgICAgICBlZGdlcyA8LSBjYmluZChlZGdlc19sZWF2aW5nX3YsIDEpCiAgICAgIH0gZWxzZSBpZihuX2xlYXZpbmdfZWRnZXMgPT0gMCl7CiAgICAgICAgZWRnZXMgPC0gY2JpbmQoZWRnZXNfZW50ZXJpbmdfdiwgMikKICAgICAgfWVsc2V7CiAgICAgICAgZWRnZXMgPC0gcmJpbmQoY2JpbmQoZWRnZXNfbGVhdmluZ192LCAxKSwKICAgICAgICAgICAgICAgICAgICAgICBjYmluZChlZGdlc19lbnRlcmluZ192LCAyKSkKICAgICAgfQogICAgICBmb3IgKGkgaW4gMjpuX2UpIHsKICAgICAgICBpX1tjb3VudCArIDE6Ml0gPC0gY291bnRfY29uc3RyYWludCArIDEKICAgICAgICBqX1tjb3VudCArIDE6Ml0gPC0gYygyICogKGVkZ2VzW2ktMSwxXSAtIDEpICsgZWRnZXNbaS0xLCAyXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAyICogKGVkZ2VzW2ksMV0gICAtIDEpICsgZWRnZXNbaSwgICAyXSkKICAgICAgICB4X1tjb3VudCArIDE6Ml0gPC0gYygxLC0xKQogICAgICAgIGNvdW50IDwtIGNvdW50ICsgMgogICAgICAgIGNvdW50X2NvbnN0cmFpbnQgPC0gY291bnRfY29uc3RyYWludCArIDEKICAgICAgfQogICAgfQogIH0KICBLIDwtIE1hdHJpeDo6c3BhcnNlTWF0cml4KGkgPSBpX1sxOmNvdW50XSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGogPSBqX1sxOmNvdW50XSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSB4X1sxOmNvdW50XSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpbXMgPSBjKGNvdW50X2NvbnN0cmFpbnQsIDIqZ3JhcGgkbkUpKQogICAgICAgICAgICAgICAgICAgICAgICAgCiAgQ0IgPC0gTWV0cmljR3JhcGg6OjpjX2Jhc2lzMihLKQogIHJldHVybihDQikKfQpgYGAKCgpGdW5jdGlvbiBgbWF0ZXJuLnAuam9pbnQoKWAgY29tcHV0ZXMKCiQkClxtYXRoYmZ7cn1faTogXG1hdGhiYntSfSBcdGltZXMgXG1hdGhiYntSfSBcbWFwc3RvIFxtYXRoYmJ7Un1ee1xsY2VpbFxhbHBoYVxyY2VpbFx0aW1lcyBcbGNlaWxcYWxwaGFccmNlaWx9LCBccXVhZCBcbWF0aGJme3J9X2lcbGVmdCh0XzEsIHRfMlxyaWdodCk9XGxlZnRbXGZyYWN7XHBhcnRpYWxee2stMX19e1xwYXJ0aWFsIHRfMl57ay0xfX0gXGZyYWN7XHBhcnRpYWxee2otMX19e1xwYXJ0aWFsIHRfMV57ai0xfX0gXHZhcnJob197aX1cbGVmdCh0XzEtdF8yXHJpZ2h0KVxyaWdodF1fe2sgaiBcaW5cezEsMiwgXGxkb3RzLCBcbGNlaWxcYWxwaGFccmNlaWxcfX0KJCQKCndoZXJlICRcYmV0YSA9IFxsZmxvb3JcYWxwaGFccmZsb29yJCBpZiAkaT0wJCBhbmQgJFxiZXRhID0gXGxjZWlsXGFscGhhXHJjZWlsJCBpZiAkaT0xLFxkb3RzLG0kLCBhbmQgCgoKJCQKXHZhcnJob197aX0oaCk9XGJlZ2lue2Nhc2VzfVxkZnJhY3tcdmFycmhvX3ttLCBpfV5cYWxwaGEoaCl9e2sgXHNpZ21hXjJ9LCAmIGk9MCBcXCAKXGRmcmFje1x2YXJyaG9fe20sIGl9XlxhbHBoYShoKX17cl9pIFxzaWdtYV4yfSwgJiBpPTEsXGRvdHMsbVxlbmR7Y2FzZXN9CiQkCgphbmQKCiQkClx2YXJyaG9fe20sIGl9XlxhbHBoYShoKT0gXGJlZ2lue2Nhc2VzfSBrIFxzaWdtYV4yIFx2YXJyaG9cbGVmdChoIDtcbGZsb29yXGFscGhhXHJmbG9vci1cZnJhY3sxfXsyfSwgXGthcHBhLCBcZnJhY3tjX1xhbHBoYX17Y197XGxmbG9vclxhbHBoYVxyZmxvb3J9fVxyaWdodCksICYgaT0wIFxcIHJfaSBcc2lnbWFeMiBcbGVmdFtcZGZyYWN7MX17cF9pXntcbGZsb29yXGFscGhhXHJmbG9vcn19IFx2YXJyaG9cbGVmdChoIDsgXGZyYWN7MX17Mn0sIFxrYXBwYV9pLCBcZnJhY3tjX1xhbHBoYSBcc3FydHtccGl9fXtcc3FydHsxLXBfaX19XHJpZ2h0KS1cZGlzcGxheXN0eWxlXHN1bV97aj0xfV57XGxmbG9vclxhbHBoYVxyZmxvb3J9IFxkZnJhY3sxfXtwX2lee1xsZmxvb3JcYWxwaGFccmZsb29yKzEtan19IFx2YXJyaG9cbGVmdChoIDsgai1cZnJhY3sxfXsyfSwgXGthcHBhLCBcZnJhY3tjX1xhbHBoYX17Y19qfVxyaWdodClccmlnaHRdLCAmICBpPTEsXGRvdHMsbVxlbmR7Y2FzZXN9CiQkCgoKYW5kICRjX2E6PVxHYW1tYShhKSAvIFxHYW1tYShhLTEgLyAyKSwgXGthcHBhX2k9XGthcHBhIFxzcXJ0ezEtcF9pfSQsIGFuZCAkXHZhcnJobyQgaXMgdGhlIE1hdMOpcm4gY292YXJpYW5jZQoKCiQkClx2YXJyaG8oaDsgXG51LCBca2FwcGEsIFxzaWdtYV4yKT1cZGZyYWN7XHNpZ21hXnsyfX17Ml57XG51LTF9IFxHYW1tYShcbnUpfShca2FwcGF8aHwpXlxudSBLX1xudShca2FwcGF8aHwpLFxxdWFkIFxzaWdtYV4yID0gXGRmcmFje1xHYW1tYShcbnUpfXtcR2FtbWEoXG51KzEvMikoNFxwaSleezEvMn1ca2FwcGFeezJcbnV9XHRhdV4yfQokJAoKLS0tLS0tLS0tLS0tLS0tLS0KCiMjIENhc2UgJGk9MCQKCi0tLS0tLS0tLS0tLS0tLS0tCgokJApcd2lkZXRpbGRle1xtYXRoYmZ7UX19X3swLGV9PVxtYXRoYmZ7UX1fezAsZX0tXGZyYWN7MX17Mn1cbGVmdFtcYmVnaW57YXJyYXl9e2NjfQpcbWF0aGJme3J9KDAsMCleey0xfSAmIFxtYXRoYmZ7MH0gXFwKXG1hdGhiZnswfSAmIFxtYXRoYmZ7cn0oMCwwKV57LTF9ClxlbmR7YXJyYXl9XHJpZ2h0XVxpblxtYXRoYmJ7Un1eezIgXGxmbG9vclxhbHBoYVxyZmxvb3IgXHRpbWVzIDIgXGxmbG9vclxhbHBoYVxyZmxvb3J9LAokJAoKVGhpcyBpcyBjb21wdXRlZCBpbiBgUmAgYXMgZm9sbG93cwoKLSAkXG1hdGhiZntyfSgwLDApID0kIGBtYXRlcm4ucC5qb2ludChzID0gMCwgdCA9IDAsIGthcHBhID0ga2FwcGEsIHAgPSAwLCBhbHBoYSA9IGZsb29yKGFscGhhKSlgLgoKLSAkXG1hdGhiZntRfV97MCxlfSA9JCBgbWF0ZXJuLnAucHJlY2lzaW9uKGxvYyA9IGMoMCwgTF9lW2VdKSwga2FwcGEgPSBrYXBwYSwgcCA9IDAsIGVxdWFsbHlfc3BhY2VkID0gVFJVRSwgYWxwaGEgPSBmbG9vcihhbHBoYSkpJFFgLgoKLSBDb25zdGFudCBjb3JyZWN0aW9uOiAkXHdpZGV0aWxkZXtcbWF0aGJme1F9fV97MCxlfT1cZGZyYWN7Mlx0YXVeMlxrYXBwYV57MlxhbHBoYX19e2tca2FwcGF9XHdpZGV0aWxkZXtcbWF0aGJme1F9fV97MCxlfSQKCi0tLS0tLS0tLS0tLS0tLS0tCgojIyBDYXNlICRpPTEsXGRvdHMsbSQKCi0tLS0tLS0tLS0tLS0tLS0tCgokJApcd2lkZXRpbGRle1xtYXRoYmZ7UX19X3tpLGV9PVxtYXRoYmZ7UX1fe2ksZX0tXGZyYWN7MX17Mn1cbGVmdFtcYmVnaW57YXJyYXl9e2NjfQpcbWF0aGJme3J9X2koMCwwKV57LTF9ICYgXG1hdGhiZnswfSBcXApcbWF0aGJmezB9ICYgXG1hdGhiZntyfV9pKDAsMCleey0xfQpcZW5ke2FycmF5fVxyaWdodF1caW5cbWF0aGJie1J9XnsyIFxsY2VpbFxhbHBoYVxyY2VpbCBcdGltZXMgMiBcbGNlaWxcYWxwaGFccmNlaWx9LAokJAoKVGhpcyBpcyBjb21wdXRlZCBpbiBgUmAgYXMgZm9sbG93cwoKLSAkXG1hdGhiZntyfV9pKDAsMCkgPSQgYG1hdGVybi5wLmpvaW50KHMgPSAwLCB0ID0gMCwga2FwcGEgPSBrYXBwYSwgcCA9IHBfaSwgYWxwaGEgPSBhbHBoYSlgLgoKLSAkXG1hdGhiZntRfV97aSxlfSA9JCBgbWF0ZXJuLnAucHJlY2lzaW9uKGxvYyA9IGMoMCwgTF9lW2VdKSwga2FwcGEgPSBrYXBwYSwgcCA9IHBfaSwgZXF1YWxseV9zcGFjZWQgPSBUUlVFLCBhbHBoYSA9IGFscGhhKSRRYC4KCi0gQ29uc3RhbnQgY29ycmVjdGlvbjogJFx3aWRldGlsZGV7XG1hdGhiZntRfX1fe2ksZX09XGRmcmFjezJcdGF1XjJca2FwcGFeezJcYWxwaGF9Y19cYWxwaGFcc3FydHtccGl9fXtyX2kgXGthcHBhfVx3aWRldGlsZGV7XG1hdGhiZntRfX1fe2ksZX0kCgpUaGVuIAoKJCQKXHdpZGV0aWxkZXtcbWF0aGJme1F9fV8wID0gXG9wZXJhdG9ybmFtZXtkaWFnfVxsZWZ0KFx7XHdpZGV0aWxkZXtcbWF0aGJme1F9fV97MCxlfVx9X3tlXGluXG1hdGhjYWx7RX19XHJpZ2h0KSwKJCQgCgphbmQgCgokJApcd2lkZXRpbGRle1xtYXRoYmZ7UX19X2kgPSBcb3BlcmF0b3JuYW1le2RpYWd9XGxlZnQoXHtcd2lkZXRpbGRle1xtYXRoYmZ7UX19X3tpLGV9XH1fe2VcaW5cbWF0aGNhbHtFfX1ccmlnaHQpLFxxdWFkIGk9MSxcZG90cyxtLgokJAoKCmBgYHtyfQojIFRoaXMgaXMgdGhlIGNvcnJlY3QgdmVyc2lvbiwgaXQgaXMgY29ycmVjdGVkIHRoZSBjb25zdGFudHMKZ2V0c19jb3ZfbWF0X3JhdF9hcHByb3hfYWxwaGFfMV90b18yIDwtIGZ1bmN0aW9uKGdyYXBoLCBrYXBwYSwgdGF1LCBhbHBoYSwgbSl7CiAgCiAgaWYoYWxwaGEgPT0gMil7CiAgICBRX3VuY29uc3RyYWludCA8LSBNZXRyaWNHcmFwaDo6OlFhbHBoYTIodGhldGEgPSBjKHRhdSwga2FwcGEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyYXBoID0gZ3JhcGgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQkMgPSAzMDAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ1aWxkID0gVFJVRSkKICAgIGdyYXBoJGJ1aWxkQyhhbHBoYSA9IGFscGhhLCBlZGdlX2NvbnN0cmFpbnQgPSBUUlVFKSAjIHNob3VsZCBhbHdheXMgYmUgVFJVRQogICAgQ09ORCA8LSBncmFwaCRDb0IKICAgIFRjIDwtIENPTkQkVFstYygxOmxlbmd0aChDT05EJFMpKSwgXQoKICAgIFFfVSA8LSAgVGMgJSolIFFfdW5jb25zdHJhaW50ICUqJSB0KFRjKQoKICAgIGluZGV4Lm9ic19pIDwtIGdpdmVzLmluZGljZXMoZ3JhcGggPSBncmFwaCwgZmFjdG9yID0gNCwgY29uc3RhbnQgPSAzKQogICAgQSA8LSB0KFRjKVtpbmRleC5vYnNfaSwgXSAKCiAgICBTaWdtYSA8LSBBICUqJSBzb2x2ZShRX1UsIHQoQSkpCiAgICByZXR1cm4oU2lnbWEpCiAgfQoKICAjIGdldCByYXRpb25hbCBhcHByb3hpbWF0aW9uIGNvZWZmaWNpZW50cwogIGNvZWZmIDwtIHJTUERFOjo6aW50ZXJwX3JhdGlvbmFsX2NvZWZmaWNpZW50cygKICAgIG9yZGVyID0gbSwgCiAgICB0eXBlX3JhdGlvbmFsX2FwcHJveCA9ICJjaGViZnVuIiwgCiAgICB0eXBlX2ludGVycCA9ICJzcGxpbmUiLCAKICAgIGFscGhhID0gYWxwaGEpCiAgCiAgciA8LSBjb2VmZiRyCiAgcCA8LSBjb2VmZiRwCiAgayA8LSBjb2VmZiRrCiAgCiAgIyBjb21wdXRlIHBhcmFtZXRlcnMKICBmYSA8LSBmbG9vcihhbHBoYSkKICBjYSA8LSBjZWlsaW5nKGFscGhhKQogIAogIG51IDwtIGFscGhhIC0gMS8yCiAgc2lnbWEgPC0gc3FydChnYW1tYShudSkgLyAodGF1XjIgKiBrYXBwYV4oMipudSkgKiAoNCpwaSleKDEvMikgKiBnYW1tYShudSArIDEvMikpKQogIGNfYWxwaGEgPC0gZ2FtbWEoYWxwaGEpL2dhbW1hKGFscGhhIC0gMC41KQogIGNfMSA8LSBnYW1tYShmYSkvZ2FtbWEoZmEgLSAwLjUpCiAgCiAgIyBnZXQgZWRnZSBsZW5ndGhzCiAgTF9lIDwtIGdyYXBoJGVkZ2VfbGVuZ3RocwogIAogICMgaW5pdGlhbGl6ZSBRdGlsZGVfaSwgYSBsaXN0IGNvbnRhaW5pbmcgYmxvY2sgZGlhZ29uYWwgbWF0cmljZXMgd2l0aCBibG9ja3MgUXRpbGRlX3tpLGV9IGZvciBlYWNoIGkKICBRdGlsZGVfaSA8LSBsaXN0KCkgCiAgZm9yKGkgaW4gMTptKXsKICAgIAogICAgIyBjb21wdXRlIHJfKDAsMCkKICAgIHIwMCA8LSBtYXRlcm4ucC5qb2ludCgKICAgICAgcyA9IDAsIAogICAgICB0ID0gMCwgCiAgICAgIGthcHBhID0ga2FwcGEsIAogICAgICBwID0gcFtpXSwgCiAgICAgIGFscGhhID0gYWxwaGEpCiAgICAKICAgICMgY29tcHV0ZSByXygwLDApXigtMSkKICAgIHIwMF9pbnZlcnNlIDwtIHNvbHZlKHIwMCwgRGlhZ29uYWwoY2EpKQogICAgCiAgICAjIGRlZmluZSB6ZXJvIGJsb2NrIAogICAgemVyb19ibG9jayA8LSBtYXRyaXgoMCwgY2EsIGNhKQogICAgCiAgICAjIGJ1aWxkIGNvcnJlY3Rpb24gdGVybQogICAgY29ycmVjdGlvbl90ZXJtIDwtIHJiaW5kKAogICAgICBjYmluZChyMDBfaW52ZXJzZSwgemVyb19ibG9jayksCiAgICAgIGNiaW5kKHplcm9fYmxvY2ssIHIwMF9pbnZlcnNlKSkKICAgIAogICAgIyBpbml0aWFsaXplIFF0aWxkZV9pW1tpXV0sIGEgbGlzdCBjb250YWluaW5nIFF0aWxkZV97aSxlfSBmb3IgZWFjaCBlZGdlIGUKICAgIFF0aWxkZV9pW1tpXV0gPC0gbGlzdCgpCiAgICBmb3IoZSBpbiAxOmxlbmd0aChMX2UpKXsKICAgICAgCiAgICAgICMgY29tcHV0ZSBRX3tpLGV9CiAgICAgIFFfZSA8LSBtYXRlcm4ucC5wcmVjaXNpb24oCiAgICAgICAgbG9jID0gYygwLCBMX2VbZV0pLAogICAgICAgIGthcHBhID0ga2FwcGEsIAogICAgICAgIHAgPSBwW2ldLAogICAgICAgIGVxdWFsbHlfc3BhY2VkID0gRkFMU0UsIAogICAgICAgIGFscGhhID0gYWxwaGEpJFEKICAgICAgCiAgICAgICMgc3RvcmUgUXRpbGRlX3tpLGV9CiAgICAgIFF0aWxkZV9pW1tpXV1bW2VdXSA8LSBRX2UgLSAwLjUgKiBjb3JyZWN0aW9uX3Rlcm0KICAgIH0KICAgICMgYnVpbGQgYmxvY2sgZGlhZ29uYWwgbWF0cml4IFF0aWxkZV9pW1tpXV0KICAgIFF0aWxkZV9pW1tpXV0gPC0gYmRpYWcoUXRpbGRlX2lbW2ldXSkKICB9CiAgCiAgIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogICMgQ0FTRSBpID0gMAogICMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAKICAjIFdoZW4gSSB1c2UgTWV0cmljR3JhcGg6OjpRYWxwaGExLCBJIGFtIGFzc3VtaW5nIHRoYXQgdGF1IGFuZCBzaWdtYSBhcmUgcmVsYXRlZCBieSB0YXVeMiA9IGdhbW1hKG51KSAvIChzaWdtYV4yICoga2FwcGFeKDIqbnUpICogKDQqcGkpXigxLzIpICogZ2FtbWEobnUgKyAxLzIpKSB3aGVyZSBudSA9IDEvMgogIAogIGludl9mYWN0b3JfMCA8LSAxLyhrKmNfYWxwaGEvY18xKQogIE5VIDwtIGZhIC0gMC41CiAgVEFVIDwtIHNxcnQoZ2FtbWEoTlUpIC8gKHNpZ21hXjIgKiBrYXBwYV4oMipOVSkgKiAoNCpwaSleKDEvMikgKiBnYW1tYShOVSArIDEvMikpKQogICAgCiAgUXRpbGRlXzBfc3Rhcl9VVSA8LSBNZXRyaWNHcmFwaDo6OlFhbHBoYTEoCiAgICB0aGV0YSA9IGMoVEFVLCBrYXBwYSksIAogICAgZ3JhcGggPSBncmFwaCwgCiAgICBCQyA9IDMwMDAsIAogICAgYnVpbGQgPSBUUlVFKSAqIGludl9mYWN0b3JfMAogIAogIEFfMCA8LSBncmFwaCQuX19lbmNsb3NfZW52X18kcHJpdmF0ZSRBKCkKCiAgIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogICMgQ0FTRSBpID0gMSwuLi4sbQogICMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAKICAjIGJ1aWxkIGNvbmRpdGlvbmluZyBtYXRyaXgKICBncmFwaCRidWlsZEMoYWxwaGEgPSAyLCBlZGdlX2NvbnN0cmFpbnQgPSBUUlVFKSAjIHNob3VsZCBhbHdheXMgYmUgVFJVRQogIENPTkRfaSA8LSBncmFwaCRDb0IKICBUYyA8LSBDT05EX2kkVFstYygxOmxlbmd0aChDT05EX2kkUykpLCBdCiAgCiAgaW52X2ZhY3Rvcl9pIDwtIDEvKHIqc2lnbWFeMikKCiAgUXRpbGRlX2lfc3Rhcl9VVSA8LSBwdXJycjo6bWFwMigKICAgIFF0aWxkZV9pLCAKICAgIGludl9mYWN0b3JfaSwgCiAgICBmdW5jdGlvbihRLCB4KSBUYyAlKiUgUSAlKiUgdChUYykgKiB4KQoKICBpbmRleC5vYnNfaSA8LSBnaXZlcy5pbmRpY2VzKGdyYXBoID0gZ3JhcGgsIGZhY3RvciA9IDQsIGNvbnN0YW50ID0gMykKICBBX2kgPC0gdChUYylbaW5kZXgub2JzX2ksIF0gCiAgCiAgIyBCdWlsZCBtYXRyaXggQSBhbmQgUV9VVQogIEEgPC0gY2JpbmQoQV8wLCBkby5jYWxsKGNiaW5kLCByZXAobGlzdChBX2kpLCBtKSkpCiAgUV9VVSA8LSBiZGlhZyhRdGlsZGVfMF9zdGFyX1VVLCBiZGlhZyhRdGlsZGVfaV9zdGFyX1VVKSkKICAjIFJldHVybiBTaWdtYQogIFNpZ21hIDwtIEEgJSolIHNvbHZlKFFfVVUsIHQoQSkpIAogIHJldHVybihTaWdtYSkKfQpgYGAKCgpgYGB7cn0KZ2V0c19jb3ZfbWF0X3JhdF9hcHByb3hfYWxwaGFfMF90b18xIDwtIGZ1bmN0aW9uKGdyYXBoLCBrYXBwYSwgdGF1LCBhbHBoYSwgbSl7CiAgCiAgaWYoYWxwaGEgPT0gMSl7CiAgICBJIDwtIE1hdHJpeDo6RGlhZ29uYWwoZ3JhcGgkblYpICAKICAgIFFfVSA8LSBNZXRyaWNHcmFwaDo6OlFhbHBoYTEoCiAgICAgIHRoZXRhID0gYyh0YXUsIGthcHBhKSwKICAgICAgZ3JhcGggPSBncmFwaCwKICAgICAgQkMgPSAzMDAwLAogICAgICBidWlsZCA9IFRSVUUpCiAgICBTaWdtYSA8LSBzb2x2ZShRX1UsIEkpCiAgICByZXR1cm4oU2lnbWEpCiAgfQoKICBjb2VmZiA8LSByU1BERTo6OmludGVycF9yYXRpb25hbF9jb2VmZmljaWVudHMoCiAgICBvcmRlciA9IG0sIAogICAgdHlwZV9yYXRpb25hbF9hcHByb3ggPSAiY2hlYmZ1biIsIAogICAgdHlwZV9pbnRlcnAgPSAic3BsaW5lIiwgCiAgICBhbHBoYSA9IGFscGhhKQogIAogIHIgPC0gY29lZmYkcgogIHAgPC0gY29lZmYkcAogIGsgPC0gY29lZmYkawogIAogIG51IDwtIGFscGhhIC0gMS8yCiAgc2lnbWEgPC0gc3FydChnYW1tYShudSkgLyAodGF1XjIgKiBrYXBwYV4oMipudSkgKiAoNCpwaSleKDEvMikgKiBnYW1tYShudSArIDEvMikpKQogIAogIGZhIDwtIGZsb29yKGFscGhhKQogIGNhIDwtIGNlaWxpbmcoYWxwaGEpCiAgCiAgY19hbHBoYSA8LSBnYW1tYShhbHBoYSkvZ2FtbWEoYWxwaGEgLSAwLjUpCiAgCiAgIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogICMgQ0FTRSBpID0gMAogICMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAKICBpbnZfZmFjdG9yXzAgPC0gMS8oaypjX2FscGhhKnNxcnQoNCpwaSkqc2lnbWFeMi9rYXBwYSkKICBJIDwtIE1hdHJpeDo6RGlhZ29uYWwoZ3JhcGgkblYpICAgICAKICBRdGlsZGVfMF9zdGFyX1VVIDwtIEkgKiBpbnZfZmFjdG9yXzAKICAKICAjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgIyBDQVNFIGkgPSAxLC4uLixtCiAgIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogIAogIGludl9mYWN0b3JfaSA8LSAxLyhyKmNfYWxwaGEqc3FydChwaSkvc3FydCgxIC0gcCkpCiAgICAKICBOVSA8LSBjYSAtIDAuNQogIAogIFF0aWxkZV9pX3N0YXJfVVUgPC0gbGlzdCgpCiAgZm9yKGkgaW4gMTptKXsKICAgIAogICAgS0FQUEEgPC0ga2FwcGEqc3FydCgxIC0gcFtpXSkKICAgIFRBVSA8LSBzcXJ0KGdhbW1hKE5VKSAvIChzaWdtYV4yICogS0FQUEFeKDIqTlUpICogKDQqcGkpXigxLzIpICogZ2FtbWEoTlUgKyAxLzIpKSkKICAgIAogICAgUXRpbGRlX2lfc3Rhcl9VVVtbaV1dIDwtIE1ldHJpY0dyYXBoOjo6UWFscGhhMSgKICAgICAgdGhldGEgPSBjKFRBVSwgS0FQUEEpLCAKICAgICAgZ3JhcGggPSBncmFwaCwgCiAgICAgIEJDID0gMzAwMCwgCiAgICAgIGJ1aWxkID0gVFJVRSkgKiBpbnZfZmFjdG9yX2lbaV0KICAKICB9CgogIFFfVVUgPC0gYyhsaXN0KFF0aWxkZV8wX3N0YXJfVVUpLCBRdGlsZGVfaV9zdGFyX1VVKQogIAogIFNpZ21hIDwtIFJlZHVjZShgK2AsIGxhcHBseShRX1VVLCBmdW5jdGlvbihRaSkgc29sdmUoUWksIEkpKSkKICByZXR1cm4oU2lnbWEpCn0KYGBgCgoKCmBgYHtyfQpyYXRfY292YXJpYW5jZSA8LSBmdW5jdGlvbihncmFwaCwga2FwcGEsIHRhdSwgYWxwaGEsIG0pewogIGlmKGFscGhhIDw9IDAuNSl7CiAgICBzdG9wKCJhbHBoYSA9ICIsIGFscGhhLCAiLCBhbHBoYSBzaG91bGQgYmUgbGFyZ2VyIHRoYW4gMC41IikKICB9CiAgZWxzZSBpZihhbHBoYSA+IDAuNSAmJiBhbHBoYSA8PSAxKXsKICAgIHJldHVybihnZXRzX2Nvdl9tYXRfcmF0X2FwcHJveF9hbHBoYV8wX3RvXzEoZ3JhcGggPSBncmFwaCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2FwcGEgPSBrYXBwYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGF1ID0gdGF1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IGFscGhhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtID0gbSkpCiAgfQogIGVsc2UgaWYoYWxwaGEgPiAxICYmIGFscGhhIDw9IDIpewogICAgcmV0dXJuKGdldHNfY292X21hdF9yYXRfYXBwcm94X2FscGhhXzFfdG9fMihncmFwaCA9IGdyYXBoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrYXBwYSA9IGthcHBhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXUgPSB0YXUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gYWxwaGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG0gPSBtKSkKICB9Cn0KYGBgCgoKYGBgCntyfQojIFVzaW5nIFYncyBpbXBsZW1lbnRhdGlvbgpnZXRzX2Nvdl9tYXRfcmF0X2FwcHJveF9hbHBoYV8xX3RvXzIgPC0gZnVuY3Rpb24oZ3JhcGgsIGthcHBhLCB0YXUsIGFscGhhLCBtKXsKCiAgIyBnZXQgcmF0aW9uYWwgYXBwcm94aW1hdGlvbiBjb2VmZmljaWVudHMKICBjb2VmZiA8LSByU1BERTo6OmludGVycF9yYXRpb25hbF9jb2VmZmljaWVudHMoCiAgICBvcmRlciA9IG0sIAogICAgdHlwZV9yYXRpb25hbF9hcHByb3ggPSAiY2hlYmZ1biIsIAogICAgdHlwZV9pbnRlcnAgPSAic3BsaW5lIiwgCiAgICBhbHBoYSA9IGFscGhhKQogIAogIHIgPC0gY29lZmYkcgogIHAgPC0gY29lZmYkcAogIGsgPC0gY29lZmYkawogIAogICMgcmVwYXJhbWV0ZXJpemF0aW9uCiAgbnUgPC0gYWxwaGEgLSAxLzIKICBzaWdtYSA8LSBzcXJ0KGdhbW1hKG51KSAvICh0YXVeMiAqIGthcHBhXigyKm51KSAqICg0KnBpKV4oMS8yKSAqIGdhbW1hKG51ICsgMS8yKSkpCiAgY19hbHBoYSA8LSBnYW1tYShhbHBoYSkvZ2FtbWEoYWxwaGEgLSAwLjUpCiAgY18xIDwtIGdhbW1hKGZsb29yKGFscGhhKSkvZ2FtbWEoZmxvb3IoYWxwaGEpIC0gMC41KQogIAogICMgZ2V0IGVkZ2UgbGVuZ3RocwogIExfZSA8LSBncmFwaCRlZGdlX2xlbmd0aHMKICAKICBRdGlsZGVfaSA8LSBsaXN0KCkgCiAgZm9yKG9yZGVyIGluIDA6bSl7CiAgICBpZihvcmRlciA9PSAwKXsKICAgICAgUCA8LSBvcmRlcgogICAgICBBTFBIQSA8LSBmbG9vcihhbHBoYSkKICAgICAgRkFDVE9SIDwtICgyKnRhdV4yKS8oayprYXBwYSkKICAgICAgcjAwX2ludmVyc2UgPC0gc29sdmUobWF0ZXJuLnAuam9pbnQocyA9IDAsIHQgPSAwLCBrYXBwYSA9IGthcHBhLCBwID0gUCwgYWxwaGEgPSBBTFBIQSkpCiAgICAgIGNvcnJlY3Rpb25fdGVybSA8LSByYmluZChjYmluZChyMDBfaW52ZXJzZSwgbWF0cml4KDAsIGZsb29yKGFscGhhKSwgZmxvb3IoYWxwaGEpKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYmluZChtYXRyaXgoMCwgZmxvb3IoYWxwaGEpLCBmbG9vcihhbHBoYSkpLCByMDBfaW52ZXJzZSkpCiAgICB9IGVsc2UgewogICAgICBQIDwtIHBbb3JkZXJdCiAgICAgIEFMUEhBIDwtIGFscGhhCiAgICAgIEZBQ1RPUiA8LSAoMipjX2FscGhhKnNxcnQocGkpKnRhdV4yKS8ocltvcmRlcl0gKiBrYXBwYSkKICAgICAgcjAwX2ludmVyc2UgPC0gc29sdmUobWF0ZXJuLnAuam9pbnQocyA9IDAsIHQgPSAwLCBrYXBwYSA9IGthcHBhLCBwID0gUCwgYWxwaGEgPSBBTFBIQSkpCiAgICAgIGNvcnJlY3Rpb25fdGVybSA8LSByYmluZChjYmluZChyMDBfaW52ZXJzZSwgbWF0cml4KDAsIGNlaWxpbmcoYWxwaGEpLCBjZWlsaW5nKGFscGhhKSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2JpbmQobWF0cml4KDAsIGNlaWxpbmcoYWxwaGEpLCBjZWlsaW5nKGFscGhhKSksIHIwMF9pbnZlcnNlKSkKICAgIH0KICAgIFF0aWxkZV9pW1twYXN0ZTAoIm09IixvcmRlcildXSA8LSBsaXN0KCkKICAgIGZvcihlIGluIDE6bGVuZ3RoKExfZSkpewogICAgICBRX2UgPC0gbWF0ZXJuLnAucHJlY2lzaW9uKGxvYyA9IGMoMCwgTF9lW2VdKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2FwcGEgPSBrYXBwYSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcCA9IFAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXF1YWxseV9zcGFjZWQgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IEFMUEhBKSRRCiAgICAgIFF0aWxkZV9pW1twYXN0ZTAoIm09IixvcmRlcildXVtbZV1dIDwtIChRX2UgLSAwLjUgKiBjb3JyZWN0aW9uX3Rlcm0pKkZBQ1RPUiprYXBwYV4oMiphbHBoYSkKICAgIH0KICAgIFF0aWxkZV9pW1twYXN0ZTAoIm09IixvcmRlcildXSA8LSBiZGlhZyhRdGlsZGVfaVtbcGFzdGUwKCJtPSIsb3JkZXIpXV0pCiAgfQogIAogIFF0aWxkZV8wIDwtIFF0aWxkZV9pW1twYXN0ZTAoIm09IiwwKV1dICMgZXh0cmFjdCBRdGlsZGVfMAogIFF0aWxkZV9pIDwtIFF0aWxkZV9pWy0xXSAjIHJlbW92ZSBRdGlsZGVfMAogIAoKICAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiAgIyMgQ0FTRSBtID0gMAogICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKICBDT05EXzAgPC0gY29uZGl0aW9uaW5nKGdyYXBoID0gZ3JhcGgsIGFscGhhID0gMSkKICBpbmRleC5vYnNfMCA8LSBnaXZlcy5pbmRpY2VzKGdyYXBoID0gZ3JhcGgsIGZhY3RvciA9IDIsIGNvbnN0YW50ID0gMikKICBuY18wIDwtIDE6bGVuZ3RoKENPTkRfMCRTKSAjIG51bWJlciBvZiBjb25zdHJhaW50cwogIFRfMCA8LSBDT05EXzAkVCAjIGNoYW5nZSBvZiBiYXNpcyBtYXRyaXgKICBXXzAgPC0gRGlhZ29uYWwoMipmbG9vcihhbHBoYSkqZ3JhcGgkbkUpWywtbmNfMF0gIyBtYXRyaXggdG8gcmVtb3ZlIGNvbnN0cmFpbnRzCiAgUXRpbGRlXzBfc3Rhcl9VVSA8LSB0KFdfMCkgJSolIHQoVF8wKSAlKiUgUXRpbGRlXzAgJSolIChUXzApICUqJSBXXzAgCiAgQTAgPC0gVF8wW2luZGV4Lm9ic18wLCAtbmNfMF0gIyBvYnNlcnZhdGlvbiBtYXRyaXggYWZ0ZXIgY29uZGl0aW9uaW5nCiAgCiAgUXRpbGRlXzBfc3Rhcl9VVTAgPC0gTWV0cmljR3JhcGg6OjpRYWxwaGExKHRoZXRhID0gYyh0YXUsIGthcHBhKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JhcGggPSBncmFwaCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQkMgPSAzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBidWlsZCA9IFRSVUUpKmthcHBhXigtMSkqY18xLygyICogayAqIGNfYWxwaGEgKiBzaWdtYV4yICogdGF1XjIpCiAgQTAwIDwtIGdyYXBoJC5fX2VuY2xvc19lbnZfXyRwcml2YXRlJEEoKQogIFMwIDwtIEEwICUqJSBzb2x2ZShRdGlsZGVfMF9zdGFyX1VVLCB0KEEwKSkKICBTMDAgPC0gQTAwICUqJSBzb2x2ZShRdGlsZGVfMF9zdGFyX1VVMCwgdChBMDApKQogIHByaW50KFMwMC9TMCkKICAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiAgIyMgQ0FTRSBtID4gMAogICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKICBncmFwaCRidWlsZEMoYWxwaGEgPSAyLCBlZGdlX2NvbnN0cmFpbnQgPSBUUlVFKQogIENPTkRfaSA8LSBncmFwaCRDb0IKICBpbmRleC5vYnNfaSA8LSBnaXZlcy5pbmRpY2VzKGdyYXBoID0gZ3JhcGgsIGZhY3RvciA9IDQsIGNvbnN0YW50ID0gMykKICBuX2NvbnN0IDwtIGxlbmd0aChDT05EX2kkUykKICBpbmQuY29uc3QgPC0gYygxOm5fY29uc3QpCiAgVGMgPC0gQ09ORF9pJFRbLWluZC5jb25zdCwgXQogIFF0aWxkZV9pX3N0YXJfVVUgPC0gbGFwcGx5KFF0aWxkZV9pLCBmdW5jdGlvbihRKSBUYyAlKiUgUSAlKiUgdChUYykpIAogIEFpIDwtIHQoVGMpW2luZGV4Lm9ic19pLCBdICMgb2JzZXJ2YXRpb24gbWF0cml4IGFmdGVyIGNvbmRpdGlvbmluZwogIAogICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKICAjIyBCdWlsZCBtYXRyaXggQSBhbmQgUV9VVQogICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKICBBIDwtIGNiaW5kKEEwLCBkby5jYWxsKGNiaW5kLCByZXAobGlzdChBaSksIG0pKSkKICBRX1VVIDwtIGJkaWFnKFF0aWxkZV8wX3N0YXJfVVUsIGRvLmNhbGwoYmRpYWcsIFF0aWxkZV9pX3N0YXJfVVUpKQogICMgUmV0dXJuIFNpZ21hCiAgU2lnbWEgPC0gQSAlKiUgc29sdmUoUV9VVSwgdChBKSkgCiAgcmV0dXJuKFNpZ21hKQp9CgpgYGAKCmBgYHtyfQoKCiMgYmVmb3JlIEkgY2hhbmdlZCB0aGUgY29uc3RhbnRzCgpnZXRzX2Nvdl9tYXRfcmF0X2FwcHJveF9hbHBoYV8xX3RvXzJfb2xkIDwtIGZ1bmN0aW9uKGdyYXBoLCBrYXBwYSwgdGF1LCBhbHBoYSwgbSl7CgogICMgZ2V0IHJhdGlvbmFsIGFwcHJveGltYXRpb24gY29lZmZpY2llbnRzCiAgY29lZmYgPC0gclNQREU6OjppbnRlcnBfcmF0aW9uYWxfY29lZmZpY2llbnRzKAogICAgb3JkZXIgPSBtLCAKICAgIHR5cGVfcmF0aW9uYWxfYXBwcm94ID0gImNoZWJmdW4iLCAKICAgIHR5cGVfaW50ZXJwID0gInNwbGluZSIsIAogICAgYWxwaGEgPSBhbHBoYSkKICAKICByIDwtIGNvZWZmJHIKICBwIDwtIGNvZWZmJHAKICBrIDwtIGNvZWZmJGsKICAKICAjIGNvbXB1dGUgcGFyYW1ldGVycwogIGZhIDwtIGZsb29yKGFscGhhKQogIGNhIDwtIGNlaWxpbmcoYWxwaGEpCiAgCiAgbnUgPC0gYWxwaGEgLSAxLzIKICBzaWdtYSA8LSBzcXJ0KGdhbW1hKG51KSAvICh0YXVeMiAqIGthcHBhXigyKm51KSAqICg0KnBpKV4oMS8yKSAqIGdhbW1hKG51ICsgMS8yKSkpCiAgY19hbHBoYSA8LSBnYW1tYShhbHBoYSkvZ2FtbWEoYWxwaGEgLSAwLjUpCiAgY18xIDwtIGdhbW1hKGZhKS9nYW1tYShmYSAtIDAuNSkKICAKICAjIGdldCBlZGdlIGxlbmd0aHMKICBMX2UgPC0gZ3JhcGgkZWRnZV9sZW5ndGhzCiAgCiAgIyBpbml0aWFsaXplIFF0aWxkZV9pLCBhIGxpc3QgY29udGFpbmluZyBibG9jayBkaWFnb25hbCBtYXRyaWNlcyB3aXRoIGJsb2NrcyBRdGlsZGVfe2ksZX0gZm9yIGVhY2ggaQogIFF0aWxkZV9pIDwtIGxpc3QoKSAKICBmb3IoaSBpbiAxOm0pewogICAgCiAgICAjIGNvbXB1dGUgcl8oMCwwKQogICAgcjAwIDwtIG1hdGVybi5wLmpvaW50KAogICAgICBzID0gMCwgCiAgICAgIHQgPSAwLCAKICAgICAga2FwcGEgPSBrYXBwYSwgCiAgICAgIHAgPSBwW2ldLCAKICAgICAgYWxwaGEgPSBhbHBoYSkKICAgIAogICAgIyBjb21wdXRlIHJfKDAsMCleKC0xKQogICAgcjAwX2ludmVyc2UgPC0gc29sdmUocjAwLCBEaWFnb25hbChjYSkpCiAgICAKICAgICMgZGVmaW5lIHplcm8gYmxvY2sgCiAgICB6ZXJvX2Jsb2NrIDwtIG1hdHJpeCgwLCBjYSwgY2EpCiAgICAKICAgICMgYnVpbGQgY29ycmVjdGlvbiB0ZXJtCiAgICBjb3JyZWN0aW9uX3Rlcm0gPC0gcmJpbmQoCiAgICAgIGNiaW5kKHIwMF9pbnZlcnNlLCB6ZXJvX2Jsb2NrKSwKICAgICAgY2JpbmQoemVyb19ibG9jaywgcjAwX2ludmVyc2UpKQogICAgCiAgICAjIGluaXRpYWxpemUgUXRpbGRlX2lbW2ldXSwgYSBsaXN0IGNvbnRhaW5pbmcgUXRpbGRlX3tpLGV9IGZvciBlYWNoIGVkZ2UgZQogICAgUXRpbGRlX2lbW2ldXSA8LSBsaXN0KCkKICAgIGZvcihlIGluIDE6bGVuZ3RoKExfZSkpewogICAgICAKICAgICAgIyBjb21wdXRlIFFfe2ksZX0KICAgICAgUV9lIDwtIG1hdGVybi5wLnByZWNpc2lvbigKICAgICAgICBsb2MgPSBjKDAsIExfZVtlXSksCiAgICAgICAga2FwcGEgPSBrYXBwYSwgCiAgICAgICAgcCA9IHBbaV0sCiAgICAgICAgZXF1YWxseV9zcGFjZWQgPSBGQUxTRSwgCiAgICAgICAgYWxwaGEgPSBhbHBoYSkkUQogICAgICAKICAgICAgIyBzdG9yZSBRdGlsZGVfe2ksZX0KICAgICAgUXRpbGRlX2lbW2ldXVtbZV1dIDwtIFFfZSAtIDAuNSAqIGNvcnJlY3Rpb25fdGVybQogICAgfQogICAgIyBidWlsZCBibG9jayBkaWFnb25hbCBtYXRyaXggUXRpbGRlX2lbW2ldXQogICAgUXRpbGRlX2lbW2ldXSA8LSBiZGlhZyhRdGlsZGVfaVtbaV1dKQogIH0KICAKICAjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgIyBDQVNFIGkgPSAwCiAgIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogIAogIGZhY3Rvcl8wIDwtIGNfMS8oMiAqIGsgKiBjX2FscGhhICoga2FwcGEgKiBzaWdtYV4yICogdGF1XjIpCgogIAogIFF0aWxkZV8wX3N0YXJfVVUgPC0gTWV0cmljR3JhcGg6OjpRYWxwaGExKAogICAgdGhldGEgPSBjKHRhdSwga2FwcGEpLCAKICAgIGdyYXBoID0gZ3JhcGgsIAogICAgQkMgPSAzMDAwLCAKICAgIGJ1aWxkID0gVFJVRSkgKiBmYWN0b3JfMAogIAogIEFfMCA8LSBncmFwaCQuX19lbmNsb3NfZW52X18kcHJpdmF0ZSRBKCkKCiAgIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogICMgQ0FTRSBpID0gMSwuLi4sbQogICMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAKICAjIGJ1aWxkIGNvbmRpdGlvbmluZyBtYXRyaXgKICBncmFwaCRidWlsZEMoYWxwaGEgPSAyLCBlZGdlX2NvbnN0cmFpbnQgPSBUUlVFKSAjIHNob3VsZCBhbHdheXMgYmUgVFJVRQogIENPTkRfaSA8LSBncmFwaCRDb0IKICBUYyA8LSBDT05EX2kkVFstYygxOmxlbmd0aChDT05EX2kkUykpLCBdCiAgCiAgZmFjdG9yX2kgPC0gKDIgKiBrYXBwYV4oMiAqIGFscGhhIC0gMSkgKiBjX2FscGhhICogc3FydChwaSkgKiB0YXVeMikvcgogIAogIFF0aWxkZV9pX3N0YXJfVVUgPC0gcHVycnI6Om1hcDIoCiAgICBRdGlsZGVfaSwgCiAgICBmYWN0b3JfaSwgCiAgICBmdW5jdGlvbihRLCB4KSBUYyAlKiUgUSAlKiUgdChUYykgKiB4KQoKICBpbmRleC5vYnNfaSA8LSBnaXZlcy5pbmRpY2VzKGdyYXBoID0gZ3JhcGgsIGZhY3RvciA9IDQsIGNvbnN0YW50ID0gMykKICBBX2kgPC0gdChUYylbaW5kZXgub2JzX2ksIF0gCiAgCiAgIyBCdWlsZCBtYXRyaXggQSBhbmQgUV9VVQogIEEgPC0gY2JpbmQoQV8wLCBkby5jYWxsKGNiaW5kLCByZXAobGlzdChBX2kpLCBtKSkpCiAgUV9VVSA8LSBiZGlhZyhRdGlsZGVfMF9zdGFyX1VVLCBiZGlhZyhRdGlsZGVfaV9zdGFyX1VVKSkKICAjIFJldHVybiBTaWdtYQogIFNpZ21hIDwtIEEgJSolIHNvbHZlKFFfVVUsIHQoQSkpIAogIHJldHVybihTaWdtYSkKfQoKYGBgCgoKCiMjIFJlZmVyZW5jZXMKCmBgYHtyLCBwdXJsID0gRkFMU0V9CmdyYXRlZnVsOjpjaXRlX3BhY2thZ2VzKG91dHB1dCA9ICJwYXJhZ3JhcGgiLCBvdXQuZGlyID0gIi4iKQpgYGAKCgo=