1. Compositional spline

This code implements the compositional smoothing splines grounded on the theory of Bayes spaces. The below code is based on the function compositionalSpline() in the robCompositions package.

The code is based on the method in Machalova, J., Talska, R., Hron, K. Gaba, A. Compositional splines for representation of density functions. Comput Stat (2020). https://doi.org/10.1007/s00180-020-01042-7

The target is to estimate the fomular (19) in their formular

\[ \begin{aligned} J_{l}(\mathbf{z})=&(1-\alpha) \mathbf{z}^{\top} \mathbf{K}^{\top} \mathbf{D S}_{l}^{\top} \mathbf{M}_{k l} \mathbf{S}_{l} \mathbf{D} \mathbf{K} \mathbf{z}+\\ &+\alpha\left[\mathbf{y}-\mathbf{B}_{k+1}(\mathbf{x}) \mathbf{D} \mathbf{K}\right]^{\top} \mathbf{W}\left[\mathbf{y}-\mathbf{B}_{k+1}(\mathbf{x}) \mathbf{D K} \mathbf{z}\right] \end{aligned} \]

2. Simulation data

Simulate 10 design points: Here, denoted as knots. The notation in the paper is \(\lambda\) and then \(g = 8\).

Simulate a grid of 100 values based on normal density, here, denoted as t. The notation in the paper is \(x\) and then \(n = 100\)

#--their function
require(robCompositions)
require(splines)
# Example (normal density)
t =  seq(-4.7,4.7, length = 100)
t_step = diff(t[1:2])
mean = 0; sd = 1.5
f = dnorm(t, mean, sd)
f1 = f/trapzc(t_step,f)

Using fcenLR() function with above values

f.fcenLR = fcenLR(t, t_step,  f) 
length(f.fcenLR)
## [1] 100
knots <- seq(-4.7,4.7, length = 10)
knots 
##  [1] -4.7000000 -3.6555556 -2.6111111 -1.5666667 -0.5222222  0.5222222
##  [7]  1.5666667  2.6111111  3.6555556  4.7000000

3. Test each step in compositionalSpline()

Set \(order = 4 = k+1\).

Derivative \(l = der = 2\).

# der : for the penlized

order = 4
der = 2
k = order
r = length(knots)
r
## [1] 10
w = rep( 1/length(t), length(t))
# see w
length(w)
## [1] 100
clrf = f.fcenLR
length(clrf)
## [1] 100

3.1 Create knots

The below code create knots, as below. Then, the knots \(\lambda_{1}\), .., \(\lambda_{r}\) are knots inside the intervals and there are \(2*k\) extra knots. \[ \begin{aligned} &\Delta \lambda:=\lambda_{0}=u<\lambda_{1}<\cdots<\lambda_{10}<v=\dot{\lambda}_{r+1} \\ &\lambda_{-k}=\cdots=\lambda_{-1}=\lambda_{0}, \quad \lambda_{r+1}=\lambda_{r+2}=\cdots=\lambda_{r+k+1} \end{aligned} \]

Count both inside knots, 2 borders and extra knots

Celkova_Delka = 2 * (k - 1) + r  # 
Celkova_Delka
## [1] 16
lambda = c()
for (i in 1:(Celkova_Delka)) {
  if (i <= k - 1) {
    lambda[i] = knots[1]
  }
  if ((i > k - 1) && (i <= r + k - 1)) {
    lambda[i] = knots[i - (k - 1)]
  }
  if (i > r + k - 1) {
    lambda[i] = knots[r]
  }
}
lambda #### 16 knots = 8 insides + 2 borders + 6 extra knots #  6 = 2*(order -1)
##  [1] -4.7000000 -4.7000000 -4.7000000 -4.7000000 -3.6555556 -2.6111111
##  [7] -1.5666667 -0.5222222  0.5222222  1.5666667  2.6111111  3.6555556
## [13]  4.7000000  4.7000000  4.7000000  4.7000000

Then it means

\[ \begin{aligned} &\Delta \lambda:=\lambda_{0}=-4.7=u<\lambda_{1}=-3.66<\cdots<\lambda_{8}=3.66<v=4.7=\dot{\lambda}_{9} \\ &\lambda_{-3}=\lambda_{-2}=\lambda_{-1}=\lambda_{0}=-4.7, \quad \lambda_{9}=\lambda_{10}=\lambda_{11}=\lambda_{12} \end{aligned} \]

3.2. Create a B-splines basic at order \(4\), based on knots \(\lambad\)

splineDesign () is a function to Design Matrix for B-splines basic, given order \(4\), a total of 16 knots (inside, border and extra) and the value t

ord =  k
B = splineDesign(lambda, t, ord, outer.ok = TRUE)
dim(B) 
## [1] 100  12
length(t)
## [1] 100
length(lambda)- ord
## [1] 12

See matrix B

head(B, 12)
##               [,1]      [,2]       [,3]         [,4] [,5] [,6] [,7] [,8] [,9]
##  [1,] 1.0000000000 0.0000000 0.00000000 0.0000000000    0    0    0    0    0
##  [2,] 0.7513148009 0.2368520 0.01170799 0.0001252191    0    0    0    0    0
##  [3,] 0.5477084899 0.4072126 0.04407713 0.0010017531    0    0    0    0    0
##  [4,] 0.3846731781 0.5189707 0.09297521 0.0033809166    0    0    0    0    0
##  [5,] 0.2577009767 0.5800150 0.15426997 0.0080140245    0    0    0    0    0
##  [6,] 0.1622839970 0.5982344 0.22382920 0.0156523917    0    0    0    0    0
##  [7,] 0.0939143501 0.5815177 0.29752066 0.0270473328    0    0    0    0    0
##  [8,] 0.0480841473 0.5377536 0.37121212 0.0429501628    0    0    0    0    0
##  [9,] 0.0202854996 0.4748310 0.44077135 0.0641121963    0    0    0    0    0
## [10,] 0.0060105184 0.4006386 0.50206612 0.0912847483    0    0    0    0    0
## [11,] 0.0007513148 0.3230654 0.55096419 0.1252191335    0    0    0    0    0
## [12,] 0.0000000000 0.2500000 0.58333333 0.1666666667    0    0    0    0    0
##       [,10] [,11] [,12]
##  [1,]     0     0     0
##  [2,]     0     0     0
##  [3,]     0     0     0
##  [4,]     0     0     0
##  [5,]     0     0     0
##  [6,]     0     0     0
##  [7,]     0     0     0
##  [8,]     0     0     0
##  [9,]     0     0     0
## [10,]     0     0     0
## [11,]     0     0     0
## [12,]     0     0     0
tail(B, 12)
##        [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]         [,9]      [,10]
##  [89,]    0    0    0    0    0    0    0    0 0.1666666667 0.58333333
##  [90,]    0    0    0    0    0    0    0    0 0.1252191335 0.55096419
##  [91,]    0    0    0    0    0    0    0    0 0.0912847483 0.50206612
##  [92,]    0    0    0    0    0    0    0    0 0.0641121963 0.44077135
##  [93,]    0    0    0    0    0    0    0    0 0.0429501628 0.37121212
##  [94,]    0    0    0    0    0    0    0    0 0.0270473328 0.29752066
##  [95,]    0    0    0    0    0    0    0    0 0.0156523917 0.22382920
##  [96,]    0    0    0    0    0    0    0    0 0.0080140245 0.15426997
##  [97,]    0    0    0    0    0    0    0    0 0.0033809166 0.09297521
##  [98,]    0    0    0    0    0    0    0    0 0.0010017531 0.04407713
##  [99,]    0    0    0    0    0    0    0    0 0.0001252191 0.01170799
## [100,]    0    0    0    0    0    0    0    0 0.0000000000 0.00000000
##            [,11]        [,12]
##  [89,] 0.2500000 0.0000000000
##  [90,] 0.3230654 0.0007513148
##  [91,] 0.4006386 0.0060105184
##  [92,] 0.4748310 0.0202854996
##  [93,] 0.5377536 0.0480841473
##  [94,] 0.5815177 0.0939143501
##  [95,] 0.5982344 0.1622839970
##  [96,] 0.5800150 0.2577009767
##  [97,] 0.5189707 0.3846731781
##  [98,] 0.4072126 0.5477084899
##  [99,] 0.2368520 0.7513148009
## [100,] 0.0000000 1.0000000000

Plot the matrix B, then For the first 4 column, i.e the first 4 knots, it has values at 11 rows. It corresponds the back curve (up to 1). Then, the matrix 4x11 is moved until at the end of matrix B. Each block corresponds to each colorful curves. The last bock correspond to purple curve. (up to 1)

plot(range(t), c(0,1), type = "n", xlab = "x", ylab = "",
     main =  "B-splines at order = 4 - sum to 1 inside inner knots")
#mtext(expression(B[j](x) *"  and "* sum(B[j](x), j == 1, 6)), adj = 0)
abline(v = lambda, lty = 3, col = "light gray")
abline(v = lambda[c(4,length(lambda)-3)], lty = 3, col = "gray10")
#lines(x, rowSums(bb), col = "gray", lwd = 2)
matlines(t, B, ylim = c(0,1), lty = 1)

3.3 Matrix W

  W = diag(w)
dim(W)
## [1] 100 100

3.4. Create all B-splines up to order \(k+1 = 4\)

BB is a matrix to store all B-splines at knots l, evaluated at vector partition, order k.i.e \[ \boldsymbol{B}_{k+1} \]

  parnition = seq(min(lambda), max(lambda), length = 100)
head(  parnition, 20 )
##  [1] -4.700000 -4.605051 -4.510101 -4.415152 -4.320202 -4.225253 -4.130303
##  [8] -4.035354 -3.940404 -3.845455 -3.750505 -3.655556 -3.560606 -3.465657
## [15] -3.370707 -3.275758 -3.180808 -3.085859 -2.990909 -2.895960
  lambda_index = c(0:(r - 1))
  lambda_index
##  [1] 0 1 2 3 4 5 6 7 8 9

The lambda_index indicates the below knots

\[ \lambda_{0}=-4.7=u<\lambda_{1}=-3.66<\cdots<\lambda_{8}=3.66<v=4.7=\dot{\lambda}_{9} \]

g = lambda_index[length(lambda_index) - 1]
g
## [1] 8
k
## [1] 4
  N = g + (k - 1) + 1
  N
## [1] 12

Then \(g\) indicates the last inside knot, here, \(\lambda_8\).

Similar as above, \(N\) indicates the number of B-splines basic at order \(k=4\) given 8 insides knots. We then have a total of 16 knots (inside knots, border knots and extra knots). We have

\[Celkova_Delka = 2 * (k - 1) + r = length(lambda) \] The number of B-spline basis from splineDesign() is \[length(lambda)- ord = length(lambda)- k = 2 * (k - 1) + r - k = k+r -2 \] On the other sides, given \(r\) knots, there are \(r-2\) inside knots, i.e \(g = r-2\). Then, \[ N = g + (k - 1) + 1 = r - 2 +(k - 1) + 1 =r+k-2 \] Below, they create a B-splines, at order \(k\) and given values \(t = parnition = seq(min(lambda), max(lambda), length = 100)\). Check value \(l\) for the next chunk

  l = c()
  for (i in (1:N)) {
    for (j in 1:(k + 1)) {
      l[j] = lambda[i + j - 1]
      print(c(i , j, round(l, 1)))
    }
  }
## [1]  1.0  1.0 -4.7
## [1]  1.0  2.0 -4.7 -4.7
## [1]  1.0  3.0 -4.7 -4.7 -4.7
## [1]  1.0  4.0 -4.7 -4.7 -4.7 -4.7
## [1]  1.0  5.0 -4.7 -4.7 -4.7 -4.7 -3.7
## [1]  2.0  1.0 -4.7 -4.7 -4.7 -4.7 -3.7
## [1]  2.0  2.0 -4.7 -4.7 -4.7 -4.7 -3.7
## [1]  2.0  3.0 -4.7 -4.7 -4.7 -4.7 -3.7
## [1]  2.0  4.0 -4.7 -4.7 -4.7 -3.7 -3.7
## [1]  2.0  5.0 -4.7 -4.7 -4.7 -3.7 -2.6
## [1]  3.0  1.0 -4.7 -4.7 -4.7 -3.7 -2.6
## [1]  3.0  2.0 -4.7 -4.7 -4.7 -3.7 -2.6
## [1]  3.0  3.0 -4.7 -4.7 -3.7 -3.7 -2.6
## [1]  3.0  4.0 -4.7 -4.7 -3.7 -2.6 -2.6
## [1]  3.0  5.0 -4.7 -4.7 -3.7 -2.6 -1.6
## [1]  4.0  1.0 -4.7 -4.7 -3.7 -2.6 -1.6
## [1]  4.0  2.0 -4.7 -3.7 -3.7 -2.6 -1.6
## [1]  4.0  3.0 -4.7 -3.7 -2.6 -2.6 -1.6
## [1]  4.0  4.0 -4.7 -3.7 -2.6 -1.6 -1.6
## [1]  4.0  5.0 -4.7 -3.7 -2.6 -1.6 -0.5
## [1]  5.0  1.0 -3.7 -3.7 -2.6 -1.6 -0.5
## [1]  5.0  2.0 -3.7 -2.6 -2.6 -1.6 -0.5
## [1]  5.0  3.0 -3.7 -2.6 -1.6 -1.6 -0.5
## [1]  5.0  4.0 -3.7 -2.6 -1.6 -0.5 -0.5
## [1]  5.0  5.0 -3.7 -2.6 -1.6 -0.5  0.5
## [1]  6.0  1.0 -2.6 -2.6 -1.6 -0.5  0.5
## [1]  6.0  2.0 -2.6 -1.6 -1.6 -0.5  0.5
## [1]  6.0  3.0 -2.6 -1.6 -0.5 -0.5  0.5
## [1]  6.0  4.0 -2.6 -1.6 -0.5  0.5  0.5
## [1]  6.0  5.0 -2.6 -1.6 -0.5  0.5  1.6
## [1]  7.0  1.0 -1.6 -1.6 -0.5  0.5  1.6
## [1]  7.0  2.0 -1.6 -0.5 -0.5  0.5  1.6
## [1]  7.0  3.0 -1.6 -0.5  0.5  0.5  1.6
## [1]  7.0  4.0 -1.6 -0.5  0.5  1.6  1.6
## [1]  7.0  5.0 -1.6 -0.5  0.5  1.6  2.6
## [1]  8.0  1.0 -0.5 -0.5  0.5  1.6  2.6
## [1]  8.0  2.0 -0.5  0.5  0.5  1.6  2.6
## [1]  8.0  3.0 -0.5  0.5  1.6  1.6  2.6
## [1]  8.0  4.0 -0.5  0.5  1.6  2.6  2.6
## [1]  8.0  5.0 -0.5  0.5  1.6  2.6  3.7
## [1] 9.0 1.0 0.5 0.5 1.6 2.6 3.7
## [1] 9.0 2.0 0.5 1.6 1.6 2.6 3.7
## [1] 9.0 3.0 0.5 1.6 2.6 2.6 3.7
## [1] 9.0 4.0 0.5 1.6 2.6 3.7 3.7
## [1] 9.0 5.0 0.5 1.6 2.6 3.7 4.7
## [1] 10.0  1.0  1.6  1.6  2.6  3.7  4.7
## [1] 10.0  2.0  1.6  2.6  2.6  3.7  4.7
## [1] 10.0  3.0  1.6  2.6  3.7  3.7  4.7
## [1] 10.0  4.0  1.6  2.6  3.7  4.7  4.7
## [1] 10.0  5.0  1.6  2.6  3.7  4.7  4.7
## [1] 11.0  1.0  2.6  2.6  3.7  4.7  4.7
## [1] 11.0  2.0  2.6  3.7  3.7  4.7  4.7
## [1] 11.0  3.0  2.6  3.7  4.7  4.7  4.7
## [1] 11.0  4.0  2.6  3.7  4.7  4.7  4.7
## [1] 11.0  5.0  2.6  3.7  4.7  4.7  4.7
## [1] 12.0  1.0  3.7  3.7  4.7  4.7  4.7
## [1] 12.0  2.0  3.7  4.7  4.7  4.7  4.7
## [1] 12.0  3.0  3.7  4.7  4.7  4.7  4.7
## [1] 12.0  4.0  3.7  4.7  4.7  4.7  4.7
## [1] 12.0  5.0  3.7  4.7  4.7  4.7  4.7

From the above results, given i and j, the vector \(l\) has 1, 2, 3 or 4 knots (the most common). Then, they use the vector \(l\) knots to create B-splines basis, at order 4 and value parnition. Each B-spline is stored in matrix BB.

Question: Where do we apply matrix BB????? Answer: BB is use to plot the ZB-spline basis system, see again at the end of this file.

N 
## [1] 12
BB = array(0, c(length(parnition), N))
  l = c()
  for (i in (1:N)) {
    for (j in 1:(k + 1)) {
      l[j] = lambda[i + j - 1]
    }
    BB[, i] = splineDesign(l, parnition, k, outer.ok = TRUE)
  }
dim(BB)
## [1] 100  12

see again BB, seems to be simlar to B!!!, plot below

head(BB, 12)
##               [,1]      [,2]       [,3]         [,4] [,5] [,6] [,7] [,8] [,9]
##  [1,] 1.0000000000 0.0000000 0.00000000 0.0000000000    0    0    0    0    0
##  [2,] 0.7513148009 0.2368520 0.01170799 0.0001252191    0    0    0    0    0
##  [3,] 0.5477084899 0.4072126 0.04407713 0.0010017531    0    0    0    0    0
##  [4,] 0.3846731781 0.5189707 0.09297521 0.0033809166    0    0    0    0    0
##  [5,] 0.2577009767 0.5800150 0.15426997 0.0080140245    0    0    0    0    0
##  [6,] 0.1622839970 0.5982344 0.22382920 0.0156523917    0    0    0    0    0
##  [7,] 0.0939143501 0.5815177 0.29752066 0.0270473328    0    0    0    0    0
##  [8,] 0.0480841473 0.5377536 0.37121212 0.0429501628    0    0    0    0    0
##  [9,] 0.0202854996 0.4748310 0.44077135 0.0641121963    0    0    0    0    0
## [10,] 0.0060105184 0.4006386 0.50206612 0.0912847483    0    0    0    0    0
## [11,] 0.0007513148 0.3230654 0.55096419 0.1252191335    0    0    0    0    0
## [12,] 0.0000000000 0.2500000 0.58333333 0.1666666667    0    0    0    0    0
##       [,10] [,11] [,12]
##  [1,]     0     0     0
##  [2,]     0     0     0
##  [3,]     0     0     0
##  [4,]     0     0     0
##  [5,]     0     0     0
##  [6,]     0     0     0
##  [7,]     0     0     0
##  [8,]     0     0     0
##  [9,]     0     0     0
## [10,]     0     0     0
## [11,]     0     0     0
## [12,]     0     0     0

3.5. Check the order of derivative, Collocaton matrix.

Recall collocaton matrix \[ \begin{aligned} &\mathbf{B}_{k+1}(\mathbf{x})=\left(B_{i}^{k+1}\left(x_{j}\right)\right)_{j=1, i=-k}^{n, g} \\ &\mathbf{C}_{k+1}(\mathbf{x})=\left(\begin{array}{ccc} B_{-k}^{k+1}\left(x_{1}\right) & \cdots & B_{g}^{k+1}\left(x_{1}\right) \\ \vdots & \ddots & \vdots \\ B_{-k}^{k+1}\left(x_{n}\right) & \cdots & B_{g}^{k+1}\left(x_{n}\right) \end{array}\right) \in \mathbb{R}^{n, g+k+1} \end{aligned} \]

length(t) <= N
## [1] FALSE
qr(B)$rank != N
## [1] FALSE
  if (length(t) <= N) 
    stop("length(t) must be higher then Dimension(space of splines)")
  if (qr(B)$rank != N) 
    stop("Collocaton matrix does not have full column rank.")

3.6. Create matrix the Upper triangular matrix \(S\)

Matrix \(S_l\), with \(l\) is the \(l\)th derivative in the below equation

\[J_{l}\left(s_{k}\right)=(1-\alpha) \int_{a}^{b}\left[s_{k}^{(l)}(x)\right]^{2} \mathrm{~d} x+\alpha \sum_{i=1}^{n} w_{i}\left[y_{i}-s_{k}\left(x_{i}\right)\right]^{2}\]

3.6.1 The general form of \(S_l\)

\[ \mathbf{S}_{l}=\mathbf{D}_{l} \mathbf{L}_{l} \ldots \mathbf{D}_{1} \mathbf{L}_{1} \in \mathbb{R}^{g+k+1-l, g+k+1} \]

where \[ \mathbf{D}_{j}=(k+1-j) \operatorname{diag}\left(d_{-k+j}, \ldots, d_{g}\right) \] with \[ d_{i}=\frac{1}{\lambda_{i+k+1-j}-\lambda_{i}}, \quad i=-k+j, \ldots, g \] and \[ \mathbf{L}_{j}:=\left(\begin{array}{rrrr} -1 & 1 & & \\ & \ddots & \ddots & \\ & & -1 & 1 \end{array}\right) \in \mathbb{R}^{g+k+1-j, g+k+2-j} \]

3.6.2 The form of \(S_l\) when \(l=2\).

\[ \mathbf{S}_{2}=\mathbf{D}_{2} \mathbf{L}_{2} \mathbf{D}_{1} \mathbf{L}_{1} \in \mathbb{R}^{g+k+1-2, g+k+1} = \mathbb{R}^{g+k-1, g+k+1} \]

where

\[ \begin{align} &\mathbf{D}_{1}=(k+1-1) \operatorname{diag}\left(d_{-k+1}, \ldots, d_{g}\right) = k \operatorname{diag}\left(d_{-k+1}, \ldots, d_{g}\right),\quad d_{i}=\frac{1}{\lambda_{i+k+1-1}-\lambda_{i}}= \frac{1}{\lambda_{i+k}-\lambda_{i}}, \quad i=-k+1, \ldots, g\\ & \mathbf{D}_{2}=(k+1-2) \operatorname{diag}\left(d_{-k+2}, \ldots, d_{g}\right) = (k-1) \operatorname{diag}\left(d_{-k+2}, \ldots, d_{g}\right), \quad d_{i}=\frac{1}{\lambda_{i+k+1-2}-\lambda_{i}}= \frac{1}{\lambda_{i+k-1}-\lambda_{i}}, \quad i=-k+2, \ldots, g \end{align} \]

3.6.3 Check the code with \(l = der = 2\)

#S = array(0)
S_pom = diag(1, N, N)
    
for (j in 1:der) {
      D_mat = array(0)
      rozdil = lambda[(1 + k):(N + k - j)] - lambda[(1 +   j):(N)]
      D_mat = (k - j) * diag(1/rozdil)
      L_mat = array(0, c(N - j, N - j + 1))
          for (J in (1:(N - j))) {
              L_mat[J, J] = (-1)
              L_mat[J, J + 1] = 1
            }
      S_pom = D_mat %*% L_mat %*% S_pom
    }
    S = S_pom
    dim(S)
## [1] 10 12

The following code, we see the matrix D and matrix L, at value \(j = 1\)

S_pom = diag(1, N, N)
j = 1
D_mat = array(0)
rozdil = lambda[(1 + k):(N + k - j)] - lambda[(1 +   j):(N)]
D_mat = (k - j) * diag(1/rozdil)
L_mat = array(0, c(N - j, N - j + 1))
          for (J in (1:(N - j))) {
              L_mat[J, J] = (-1)
              L_mat[J, J + 1] = 1
          }
#print matrix
head(D_mat)
##         [,1]    [,2]      [,3]      [,4]      [,5]      [,6] [,7] [,8] [,9]
## [1,] 2.87234 0.00000 0.0000000 0.0000000 0.0000000 0.0000000    0    0    0
## [2,] 0.00000 1.43617 0.0000000 0.0000000 0.0000000 0.0000000    0    0    0
## [3,] 0.00000 0.00000 0.9574468 0.0000000 0.0000000 0.0000000    0    0    0
## [4,] 0.00000 0.00000 0.0000000 0.9574468 0.0000000 0.0000000    0    0    0
## [5,] 0.00000 0.00000 0.0000000 0.0000000 0.9574468 0.0000000    0    0    0
## [6,] 0.00000 0.00000 0.0000000 0.0000000 0.0000000 0.9574468    0    0    0
##      [,10] [,11]
## [1,]     0     0
## [2,]     0     0
## [3,]     0     0
## [4,]     0     0
## [5,]     0     0
## [6,]     0     0
head(L_mat)
##      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
## [1,]   -1    1    0    0    0    0    0    0    0     0     0     0
## [2,]    0   -1    1    0    0    0    0    0    0     0     0     0
## [3,]    0    0   -1    1    0    0    0    0    0     0     0     0
## [4,]    0    0    0   -1    1    0    0    0    0     0     0     0
## [5,]    0    0    0    0   -1    1    0    0    0     0     0     0
## [6,]    0    0    0    0    0   -1    1    0    0     0     0     0

The following code, we see the matrix D and matrix L, at value \(j = 2\)

S_pom = diag(1, N, N)
j = 2
D_mat = array(0)
rozdil = lambda[(1 + k):(N + k - j)] - lambda[(1 +   j):(N)]
D_mat = (k - j) * diag(1/rozdil)
L_mat = array(0, c(N - j, N - j + 1))
          for (J in (1:(N - j))) {
              L_mat[J, J] = (-1)
              L_mat[J, J + 1] = 1
          }
#print matrix
head(D_mat)
##          [,1]      [,2]      [,3]      [,4]      [,5]      [,6] [,7] [,8] [,9]
## [1,] 1.914894 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000    0    0    0
## [2,] 0.000000 0.9574468 0.0000000 0.0000000 0.0000000 0.0000000    0    0    0
## [3,] 0.000000 0.0000000 0.9574468 0.0000000 0.0000000 0.0000000    0    0    0
## [4,] 0.000000 0.0000000 0.0000000 0.9574468 0.0000000 0.0000000    0    0    0
## [5,] 0.000000 0.0000000 0.0000000 0.0000000 0.9574468 0.0000000    0    0    0
## [6,] 0.000000 0.0000000 0.0000000 0.0000000 0.0000000 0.9574468    0    0    0
##      [,10]
## [1,]     0
## [2,]     0
## [3,]     0
## [4,]     0
## [5,]     0
## [6,]     0
head(L_mat)
##      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11]
## [1,]   -1    1    0    0    0    0    0    0    0     0     0
## [2,]    0   -1    1    0    0    0    0    0    0     0     0
## [3,]    0    0   -1    1    0    0    0    0    0     0     0
## [4,]    0    0    0   -1    1    0    0    0    0     0     0
## [5,]    0    0    0    0   -1    1    0    0    0     0     0
## [6,]    0    0    0    0    0   -1    1    0    0     0     0

3.7 Prepare matrix $M_{kl} = M_{3,2} $

Recall matrix \(M_{kl}\) is \[ \mathbf{M}_{k l}=\left(m_{i j}^{k l}\right)_{i, j=-k+l}^{g}, \quad \text { with } \quad m_{i j}^{k l}=\int_{a}^{b} B_{i}^{k+1-l}(x) B_{j}^{k+1-l}(x) \mathrm{d} x \] In the below code, kk means \(kk = k+1 - l\). However, as Christine reminding, we usually work with \(l = 2.\)

Then, given order kk, we need a total of celkova_delka knots (inside knots, border knots and extra knots )

kk = k - der
kk
## [1] 2
  celkova_delka = 2 * (kk - 1) + r
   celkova_delka 
## [1] 12

The below code create a total knots for B-spline order \(kk\)!!! They create extra knots based on the given Lambda knots (including inside knots and border knots).

  Lambda = c()
  for (i in 1:celkova_delka) {
    if (i <= (kk - 1)) {
      Lambda[i] = knots[1]
    }
    if ((i > kk - 1) && (i <= r + kk - 1)) {
      Lambda[i] = knots[i - (kk - 1)]
    }
    if (i > (r + (kk - 1))) {
      Lambda[i] = knots[r]
    }
  }
Lambda
##  [1] -4.7000000 -4.7000000 -3.6555556 -2.6111111 -1.5666667 -0.5222222
##  [7]  0.5222222  1.5666667  2.6111111  3.6555556  4.7000000  4.7000000

correspond to

\[ \begin{aligned} &\Delta \lambda:=\lambda_{0}=-4.7=u<\lambda_{1}=-3.66<\cdots<\lambda_{8}=3.66<v=4.7=\dot{\lambda}_{9} \\ &\lambda_{-1}=\lambda_{0}=-4.7, \quad \lambda_{9} = \lambda_{10}=4.7 \end{aligned} \] The following code create a B-spline at order kk based on Lambda knots.

 Parnition = seq(min(Lambda), max(Lambda), length = 100)
 BBB = splineDesign(Lambda, Parnition, kk, outer.ok = TRUE)

 dim(BBB)
## [1] 100  10

plot the BBB basic, it is correct since they are at order \(kk=1.\)

plot(range(Parnition), c(0,1), type = "n", xlab = "x", ylab = "",
     main =  "B-splines at order kk = 1, using knots Lambda")
#mtext(expression(B[j](x) *"  and "* sum(B[j](x), j == 1, 6)), adj = 0)
abline(v =  Lambda, lty = 3, col = "light gray")
abline(v =  Lambda[c(4,length(Lambda)-3)], lty = 3, col = "gray10")
#lines(x, rowSums(bb), col = "gray", lwd = 2)
matlines(Parnition, BBB, ylim = c(0,1), lty = 1)

The following code finishes the calculation of M

\[ m_{i j}^{k l}=\int_{a}^{b} B_{i}^{k+1-l}(x) B_{j}^{k+1-l}(x) \mathrm{d} x \]

     Lambda_index = c(0:(r - 1)) 
  G = Lambda_index[length(Lambda_index) - 1]
  NN = G + (kk - 1) + 1
  step = diff(Parnition[1:2])
  M = array(0, c(NN, NN))
  for (i in 1:NN) {
    for (j in 1:NN) {
      nenulove = c()
      soucin = BBB[, i] * BBB[, j]
      for (m in 1:length(Parnition)) {
        if (soucin[m] != 0) {
          nenulove[m] = soucin[m]
        }
      }
      M[i, j] = trapzc(step, soucin)
    }
  }
 dim(M)
## [1] 10 10

4. Find the optimal function

4.1 Create matrix D, K, U and G

\[ \mathbf{D}_{j}=(k+1-j) \operatorname{diag}\left(d_{-k+j}, \ldots, d_{g}\right) \] with \[ d_{i}=\frac{1}{\lambda_{i+k+1-j}-\lambda_{i}}, \quad i=-k+j, \ldots, g \]

difference = lambda[(1 + k):(r + 2 * (k - 1))] - lambda[(1:(r +  k - 2))]
D = (k) * diag(1/difference)
K = array(0, c(N, N - 1))
K[1, 1] = 1
K[N, N - 1] = -1
for (j in (2:(N - 1))) {
  K[j, j - 1] = (-1)
  K[j, j] = 1
}
# See matrix D and matrix K
dim(D)
## [1] 12 12
dim(K)
## [1] 12 11

Then, Using the notation \[\mathbf{U}:=\mathbf{D K}\]

U = D %*% K
dim(U)
## [1] 12 11

Then, calculate matrix G \[ \mathbf{G}:=\mathbf{U}^{\top}\left[(1-\alpha) \mathbf{S}_{l}^{\top} \mathbf{M}_{k l} \mathbf{S}_{l}+\alpha \mathbf{B}_{k+1}^{\top}(\mathbf{x}) \mathbf{W B}_{k+1}(\mathbf{x})\right] \mathbf{U} \]

alpha = 0.5891077 #1.950193
GG = t(U) %*% ((1 - alpha) * t(S) %*% M %*% S + alpha * t(B) %*%  W %*% B) %*% U
dim(GG)
## [1] 11 11

Then, calculate matrix \(g\) as below

\[ \mathbf{g}:=\alpha \mathbf{K}^{\top} \mathbf{D} \mathbf{B}_{k+1}^{\top}(\mathbf{x}) \mathbf{W} \mathbf{y} \]

gg = alpha * t(K) %*% t(D) %*% t(B) %*% W %*% clrf
dim(gg)
## [1] 11  1

See clrf, i,e y

length(clrf)
## [1] 100
dim(alpha * t(K) %*% t(D) %*% t(B) %*% W)
## [1]  11 100
length(clrf)
## [1] 100

4.2 Solve the optimal

The optimal solution

z = solve(GG) %*% gg
length(z)
## [1] 11
z
##                [,1]
##  [1,] -5.495245e-01
##  [2,] -1.456176e+00
##  [3,] -2.235599e+00
##  [4,] -2.196856e+00
##  [5,] -1.325074e+00
##  [6,]  1.245115e-13
##  [7,]  1.325074e+00
##  [8,]  2.196856e+00
##  [9,]  2.235599e+00
## [10,]  1.456176e+00
## [11,]  5.495245e-01

The optimal ZB-spline, i.e Zbasis and it is the BDK in the following equations:

\[ s_{k}^{*}(x)=\mathbf{B}_{k+1}(x) \mathbf{D K z}^{*} \]

Zbasis = B %*% D %*% K
dim(Zbasis)
## [1] 100  11
Zbasis_finner = BB %*% D %*% K
dim(Zbasis_finner)
## [1] 100  11

5. Plot the final results

5.1. Plot the ZB-spline basis system

#if (basis.plot == TRUE) {
  matplot(parnition, Zbasis_finner, type = "l", lty = 1, 
          las = 1, xlab = "t", ylab = "fcenLR(density)", 
          col = rainbow(dim(Zbasis_finner)[2]), main = "ZB-spline basis")
  abline(v = knots, col = "gray", lty = 2)

#}

5.2 Plot the optimal spline

spline0 = Zbasis_finner %*% z
dim(spline0)
## [1] 100   1
head(spline0)
##           [,1]
## [1,] -2.104562
## [2,] -2.004042
## [3,] -1.903485
## [4,] -1.802961
## [5,] -1.702538
## [6,] -1.602287

parnition is a grid of point spline0 is the optimal spline evaluated at the grid point “parnition”

#if (spline.plot == TRUE) {
  matplot(parnition, spline0, type = "l", las = 1, 
          xlab = "t", ylab = "fcenLR(density)", 
          col = "darkblue", lwd = 2, cex.lab = 1.2, cex.axis = 1.2, 
          ylim = c(min(c(min(clrf), min(spline0))), max(c(max(clrf), 
                                                          max(spline0)))), main = paste("Compositional spline of degree k =",  k - 1))

 # matpoints(t, clrf, pch = 8, col = "darkblue", cex = 1.3)
  #abline(h = 0, col = "red", lty = 2, lwd = 1) # The horizontal line
  #abline(v = knots, col = "gray", lty = 2, lwd = 1)
#}

The line with pch = 8 is the original grid points and the initial \(y = clr(f)\) points.

#if (spline.plot == TRUE) {
  matplot(parnition, spline0, type = "l", las = 1, 
          xlab = "t", ylab = "fcenLR(density)", 
          col = "darkblue", lwd = 2, cex.lab = 1.2, cex.axis = 1.2, 
          ylim = c(min(c(min(clrf), min(spline0))), max(c(max(clrf), 
                                                          max(spline0)))), main = paste("Compositional spline of degree k =",  k - 1))
  matpoints(t, clrf, pch = 8, col = "darkblue", cex = 1.3)

  #abline(h = 0, col = "red", lty = 2, lwd = 1) # The horizontal line
  #abline(v = knots, col = "gray", lty = 2, lwd = 1)
#}

Check again knots

knots
##  [1] -4.7000000 -3.6555556 -2.6111111 -1.5666667 -0.5222222  0.5222222
##  [7]  1.5666667  2.6111111  3.6555556  4.7000000

The below figure are the original code of the Talska team.

#if (spline.plot == TRUE) {
  matplot(parnition, spline0, type = "l", las = 1, 
          xlab = "t", ylab = "fcenLR(density)", 
          col = "darkblue", lwd = 2, cex.lab = 1.2, cex.axis = 1.2, 
          ylim = c(min(c(min(clrf), min(spline0))), max(c(max(clrf), 
                                                          max(spline0)))), main = paste("Compositional spline of degree k =",  k - 1))
  matpoints(t, clrf, pch = 8, col = "darkblue", cex = 1.3)
  abline(h = 0, col = "red", lty = 2, lwd = 1) # The horizontal line
  abline(v = knots, col = "gray", lty = 2, lwd = 1) # The grid vertical lines

#}

It seems done!!

6. Smoothing parameter alpha

clrf = as.matrix(clrf)
Hmat = (B %*% D %*% K) %*% solve(GG) %*% (alpha * t(K) %*% 
                                            t(D) %*% t(B) %*% W)
clrfhat = (B %*% D %*% K) %*% z
reziduals = (clrf - clrfhat)
Hmat_diag = c()
for (i in 1:length(clrf)) Hmat_diag[i] = Hmat[i, i]
Hmat_diag_mean = (1/length(clrf)) * sum(Hmat_diag)
CV = (1/length(clrf)) * sum((reziduals/(rep(1, length(Hmat_diag)) - 
                                          Hmat_diag))^2)
CV
## [1] 0.2173018
GCV = (1/length(clrf)) * (sum((reziduals)^2))/((1 - Hmat_diag_mean)^2)
J = (1 - alpha) * t(z) %*% t(U) %*% t(S) %*% M %*% S %*% 
  U %*% z + alpha * t(clrf - B %*% D %*% K %*% z) %*% W %*% 
  (clrf - B %*% D %*% K %*% z)

GCV
## [1] 0.2079652
LS0tDQp0aXRsZTogIlVuZGVyc3RhbmQgc21vb3RoaW5nIHNwbGluZXMiDQphdXRob3I6ICJIdW9uZyINCmRhdGU6ICIxMS8zLzIwMjEiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgaGlnaGxpZ2h0OiBweWdtZW50cw0KICAgIHRoZW1lOiBmbGF0bHkNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogIHdvcmRfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCi0tLQ0KDQpgYGB7ciBzZXR1cCxpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSkNCmBgYA0KDQojIyAxLiBDb21wb3NpdGlvbmFsIHNwbGluZQ0KDQpUaGlzIGNvZGUgaW1wbGVtZW50cyB0aGUgY29tcG9zaXRpb25hbCBzbW9vdGhpbmcgc3BsaW5lcyBncm91bmRlZCBvbiB0aGUgdGhlb3J5IG9mIEJheWVzIHNwYWNlcy4gVGhlIGJlbG93IGNvZGUgaXMgYmFzZWQgb24gdGhlIGZ1bmN0aW9uIGNvbXBvc2l0aW9uYWxTcGxpbmUoKSBpbiB0aGUgcm9iQ29tcG9zaXRpb25zIHBhY2thZ2UuDQoNClRoZSBjb2RlIGlzIGJhc2VkIG9uIHRoZSBtZXRob2QgaW4gTWFjaGFsb3ZhLCBKLiwgVGFsc2thLCBSLiwgSHJvbiwgSy4gR2FiYSwgQS4gQ29tcG9zaXRpb25hbCBzcGxpbmVzIGZvciByZXByZXNlbnRhdGlvbiBvZiBkZW5zaXR5IGZ1bmN0aW9ucy4gQ29tcHV0IFN0YXQgKDIwMjApLiA8aHR0cHM6Ly9kb2kub3JnLzEwLjEwMDcvczAwMTgwLTAyMC0wMTA0Mi03Pg0KDQpUaGUgdGFyZ2V0IGlzIHRvIGVzdGltYXRlIHRoZSBmb211bGFyICgxOSkgaW4gdGhlaXIgZm9ybXVsYXINCg0KDQokJA0KXGJlZ2lue2FsaWduZWR9DQpKX3tsfShcbWF0aGJme3p9KT0mKDEtXGFscGhhKSBcbWF0aGJme3p9XntcdG9wfSBcbWF0aGJme0t9XntcdG9wfSBcbWF0aGJme0QgU31fe2x9XntcdG9wfSBcbWF0aGJme019X3trIGx9IFxtYXRoYmZ7U31fe2x9IFxtYXRoYmZ7RH0gXG1hdGhiZntLfSBcbWF0aGJme3p9K1xcDQomK1xhbHBoYVxsZWZ0W1xtYXRoYmZ7eX0tXG1hdGhiZntCfV97aysxfShcbWF0aGJme3h9KSBcbWF0aGJme0R9IFxtYXRoYmZ7S31ccmlnaHRdXntcdG9wfSBcbWF0aGJme1d9XGxlZnRbXG1hdGhiZnt5fS1cbWF0aGJme0J9X3trKzF9KFxtYXRoYmZ7eH0pIFxtYXRoYmZ7RCBLfSBcbWF0aGJme3p9XHJpZ2h0XQ0KXGVuZHthbGlnbmVkfQ0KJCQNCg0KIyMgMi4gU2ltdWxhdGlvbiBkYXRhDQogU2ltdWxhdGUgMTAgZGVzaWduIHBvaW50czogSGVyZSwgZGVub3RlZCBhcyBrbm90cy4gVGhlIG5vdGF0aW9uIGluIHRoZSBwYXBlciBpcyAkXGxhbWJkYSQgYW5kIHRoZW4gJGcgPSA4JC4NCiANCiBTaW11bGF0ZSBhIGdyaWQgb2YgMTAwIHZhbHVlcyBiYXNlZCBvbiBub3JtYWwgZGVuc2l0eSwgaGVyZSwgZGVub3RlZCBhcyB0LiBUaGUgbm90YXRpb24gaW4gdGhlIHBhcGVyIGlzICR4JCBhbmQgdGhlbiAkbiA9IDEwMCQNCiANCmBgYHtyfQ0KIy0tdGhlaXIgZnVuY3Rpb24NCnJlcXVpcmUocm9iQ29tcG9zaXRpb25zKQ0KcmVxdWlyZShzcGxpbmVzKQ0KIyBFeGFtcGxlIChub3JtYWwgZGVuc2l0eSkNCnQgPSAgc2VxKC00LjcsNC43LCBsZW5ndGggPSAxMDApDQp0X3N0ZXAgPSBkaWZmKHRbMToyXSkNCm1lYW4gPSAwOyBzZCA9IDEuNQ0KZiA9IGRub3JtKHQsIG1lYW4sIHNkKQ0KZjEgPSBmL3RyYXB6Yyh0X3N0ZXAsZikNCmBgYA0KDQpVc2luZyBmY2VuTFIoKSBmdW5jdGlvbiB3aXRoIGFib3ZlIHZhbHVlcw0KDQpgYGB7cn0NCmYuZmNlbkxSID0gZmNlbkxSKHQsIHRfc3RlcCwgIGYpIA0KbGVuZ3RoKGYuZmNlbkxSKQ0KYGBgDQoNCmBgYHtyfQ0Ka25vdHMgPC0gc2VxKC00LjcsNC43LCBsZW5ndGggPSAxMCkNCmtub3RzIA0KYGBgDQoNCg0KDQojIyAzLiBUZXN0IGVhY2ggc3RlcCBpbiBjb21wb3NpdGlvbmFsU3BsaW5lKCkNCg0KU2V0ICRvcmRlciA9IDQgPSBrKzEkLg0KDQpEZXJpdmF0aXZlICRsID0gZGVyID0gMiQuDQoNCg0KYGBge3J9DQojIGRlciA6IGZvciB0aGUgcGVubGl6ZWQNCg0Kb3JkZXIgPSA0DQpkZXIgPSAyDQprID0gb3JkZXINCnIgPSBsZW5ndGgoa25vdHMpDQpyDQp3ID0gcmVwKCAxL2xlbmd0aCh0KSwgbGVuZ3RoKHQpKQ0KIyBzZWUgdw0KbGVuZ3RoKHcpDQpjbHJmID0gZi5mY2VuTFINCmxlbmd0aChjbHJmKQ0KYGBgDQoNCiMjIyAzLjEgQ3JlYXRlIGtub3RzDQpUaGUgYmVsb3cgY29kZSBjcmVhdGUga25vdHMsIGFzIGJlbG93LiBUaGVuLCB0aGUga25vdHMgJFxsYW1iZGFfezF9JCwgLi4sICRcbGFtYmRhX3tyfSQgYXJlIGtub3RzIGluc2lkZSB0aGUgaW50ZXJ2YWxzIGFuZCB0aGVyZSBhcmUgJDIqayQgZXh0cmEga25vdHMuIA0KJCQNClxiZWdpbnthbGlnbmVkfQ0KJlxEZWx0YSBcbGFtYmRhOj1cbGFtYmRhX3swfT11PFxsYW1iZGFfezF9PFxjZG90czxcbGFtYmRhX3sxMH08dj1cZG90e1xsYW1iZGF9X3tyKzF9IFxcDQomXGxhbWJkYV97LWt9PVxjZG90cz1cbGFtYmRhX3stMX09XGxhbWJkYV97MH0sIFxxdWFkIFxsYW1iZGFfe3IrMX09XGxhbWJkYV97cisyfT1cY2RvdHM9XGxhbWJkYV97citrKzF9DQpcZW5ke2FsaWduZWR9DQokJA0KDQpDb3VudCBib3RoIGluc2lkZSBrbm90cywgMiBib3JkZXJzIGFuZCBleHRyYSBrbm90cw0KDQpgYGB7cn0NCkNlbGtvdmFfRGVsa2EgPSAyICogKGsgLSAxKSArIHIgICMgDQpDZWxrb3ZhX0RlbGthDQpgYGANCg0KYGBge3J9DQpsYW1iZGEgPSBjKCkNCmZvciAoaSBpbiAxOihDZWxrb3ZhX0RlbGthKSkgew0KICBpZiAoaSA8PSBrIC0gMSkgew0KICAgIGxhbWJkYVtpXSA9IGtub3RzWzFdDQogIH0NCiAgaWYgKChpID4gayAtIDEpICYmIChpIDw9IHIgKyBrIC0gMSkpIHsNCiAgICBsYW1iZGFbaV0gPSBrbm90c1tpIC0gKGsgLSAxKV0NCiAgfQ0KICBpZiAoaSA+IHIgKyBrIC0gMSkgew0KICAgIGxhbWJkYVtpXSA9IGtub3RzW3JdDQogIH0NCn0NCmxhbWJkYSAjIyMjIDE2IGtub3RzID0gOCBpbnNpZGVzICsgMiBib3JkZXJzICsgNiBleHRyYSBrbm90cyAjICA2ID0gMioob3JkZXIgLTEpDQpgYGANClRoZW4gaXQgbWVhbnMNCg0KJCQNClxiZWdpbnthbGlnbmVkfQ0KJlxEZWx0YSBcbGFtYmRhOj1cbGFtYmRhX3swfT0tNC43PXU8XGxhbWJkYV97MX09LTMuNjY8XGNkb3RzPFxsYW1iZGFfezh9PTMuNjY8dj00Ljc9XGRvdHtcbGFtYmRhfV97OX0gXFwNCiZcbGFtYmRhX3stM309XGxhbWJkYV97LTJ9PVxsYW1iZGFfey0xfT1cbGFtYmRhX3swfT0tNC43LCBccXVhZCAgXGxhbWJkYV97OX09XGxhbWJkYV97MTB9PVxsYW1iZGFfezExfT1cbGFtYmRhX3sxMn0NClxlbmR7YWxpZ25lZH0NCiQkDQoNCiMjIyAzLjIuIENyZWF0ZSBhIEItc3BsaW5lcyBiYXNpYyBhdCBvcmRlciAkNCQsIGJhc2VkIG9uIGtub3RzICRcbGFtYmFkJA0KDQpzcGxpbmVEZXNpZ24gKCkgaXMgYSBmdW5jdGlvbiB0byBEZXNpZ24gTWF0cml4IGZvciBCLXNwbGluZXMgYmFzaWMsIGdpdmVuIG9yZGVyICQ0JCwgYSB0b3RhbCBvZiAxNiBrbm90cyAoaW5zaWRlLCBib3JkZXIgYW5kIGV4dHJhKSBhbmQgdGhlIHZhbHVlIHQgDQoNCmBgYHtyfQ0Kb3JkID0gIGsNCkIgPSBzcGxpbmVEZXNpZ24obGFtYmRhLCB0LCBvcmQsIG91dGVyLm9rID0gVFJVRSkNCmRpbShCKSANCmxlbmd0aCh0KQ0KbGVuZ3RoKGxhbWJkYSktIG9yZA0KDQpgYGANCg0KU2VlIG1hdHJpeCBCDQoNCmBgYHtyfQ0KaGVhZChCLCAxMikNCmBgYA0KDQoNCmBgYHtyfQ0KdGFpbChCLCAxMikNCmBgYA0KUGxvdCB0aGUgbWF0cml4IEIsIHRoZW4NCkZvciB0aGUgZmlyc3QgNCBjb2x1bW4sIGkuZSB0aGUgZmlyc3QgNCBrbm90cywgaXQgaGFzIHZhbHVlcyBhdCAxMSByb3dzLiBJdCBjb3JyZXNwb25kcyB0aGUgYmFjayBjdXJ2ZSAodXAgdG8gMSkuDQpUaGVuLCB0aGUgbWF0cml4IDR4MTEgaXMgbW92ZWQgdW50aWwgYXQgdGhlIGVuZCBvZiBtYXRyaXggQi4gRWFjaCBibG9jayBjb3JyZXNwb25kcyB0byBlYWNoIGNvbG9yZnVsIGN1cnZlcy4NClRoZSBsYXN0IGJvY2sgY29ycmVzcG9uZCB0byBwdXJwbGUgY3VydmUuICh1cCB0byAxKQ0KDQpgYGB7cn0NCnBsb3QocmFuZ2UodCksIGMoMCwxKSwgdHlwZSA9ICJuIiwgeGxhYiA9ICJ4IiwgeWxhYiA9ICIiLA0KICAgICBtYWluID0gICJCLXNwbGluZXMgYXQgb3JkZXIgPSA0IC0gc3VtIHRvIDEgaW5zaWRlIGlubmVyIGtub3RzIikNCiNtdGV4dChleHByZXNzaW9uKEJbal0oeCkgKiIgIGFuZCAiKiBzdW0oQltqXSh4KSwgaiA9PSAxLCA2KSksIGFkaiA9IDApDQphYmxpbmUodiA9IGxhbWJkYSwgbHR5ID0gMywgY29sID0gImxpZ2h0IGdyYXkiKQ0KYWJsaW5lKHYgPSBsYW1iZGFbYyg0LGxlbmd0aChsYW1iZGEpLTMpXSwgbHR5ID0gMywgY29sID0gImdyYXkxMCIpDQojbGluZXMoeCwgcm93U3VtcyhiYiksIGNvbCA9ICJncmF5IiwgbHdkID0gMikNCm1hdGxpbmVzKHQsIEIsIHlsaW0gPSBjKDAsMSksIGx0eSA9IDEpDQpgYGANCg0KDQojIyMgMy4zIE1hdHJpeCBXDQoNCmBgYHtyfQ0KICBXID0gZGlhZyh3KQ0KZGltKFcpDQpgYGANCg0KDQojIyMgMy40LiBDcmVhdGUgYWxsIEItc3BsaW5lcyB1cCB0byBvcmRlciAkaysxID0gNCQNCg0KDQpCQiBpcyBhIG1hdHJpeCB0byBzdG9yZSBhbGwgQi1zcGxpbmVzIGF0IGtub3RzIGwsIGV2YWx1YXRlZCBhdCB2ZWN0b3IgcGFydGl0aW9uLCBvcmRlciBrLmkuZQ0KJCQNClxib2xkc3ltYm9se0J9X3trKzF9DQokJA0KDQoNCmBgYHtyfQ0KICBwYXJuaXRpb24gPSBzZXEobWluKGxhbWJkYSksIG1heChsYW1iZGEpLCBsZW5ndGggPSAxMDApDQpoZWFkKCAgcGFybml0aW9uLCAyMCApDQogIGxhbWJkYV9pbmRleCA9IGMoMDoociAtIDEpKQ0KICBsYW1iZGFfaW5kZXgNCmBgYA0KVGhlIGxhbWJkYV9pbmRleCBpbmRpY2F0ZXMgdGhlIGJlbG93IGtub3RzDQoNCiQkDQpcbGFtYmRhX3swfT0tNC43PXU8XGxhbWJkYV97MX09LTMuNjY8XGNkb3RzPFxsYW1iZGFfezh9PTMuNjY8dj00Ljc9XGRvdHtcbGFtYmRhfV97OX0gDQokJA0KDQoNCmBgYHtyfQ0KDQpnID0gbGFtYmRhX2luZGV4W2xlbmd0aChsYW1iZGFfaW5kZXgpIC0gMV0NCmcNCmsNCiAgTiA9IGcgKyAoayAtIDEpICsgMQ0KICBODQpgYGANCg0KVGhlbiAkZyQgaW5kaWNhdGVzIHRoZSBsYXN0IGluc2lkZSBrbm90LCBoZXJlLCAkXGxhbWJkYV84JC4NCg0KU2ltaWxhciBhcyBhYm92ZSwgJE4kIGluZGljYXRlcyB0aGUgbnVtYmVyIG9mIEItc3BsaW5lcyBiYXNpYyBhdCBvcmRlciAkaz00JCBnaXZlbiA4IGluc2lkZXMga25vdHMuIFdlIHRoZW4gaGF2ZSBhIHRvdGFsIG9mIDE2IGtub3RzIChpbnNpZGUga25vdHMsIGJvcmRlciBrbm90cyBhbmQgZXh0cmEga25vdHMpLiBXZSBoYXZlDQoNCiQkQ2Vsa292YV9EZWxrYSA9IDIgKiAoayAtIDEpICsgciA9IGxlbmd0aChsYW1iZGEpICQkDQpUaGUgbnVtYmVyIG9mIEItc3BsaW5lIGJhc2lzIGZyb20gIHNwbGluZURlc2lnbigpIGlzDQokJGxlbmd0aChsYW1iZGEpLSBvcmQgPSBsZW5ndGgobGFtYmRhKS0gayA9ICAyICogKGsgLSAxKSArIHIgLSBrID0gaytyIC0yICQkDQpPbiB0aGUgb3RoZXIgc2lkZXMsIGdpdmVuICRyJCBrbm90cywgdGhlcmUgYXJlICRyLTIkIGluc2lkZSBrbm90cywgaS5lICRnID0gci0yJC4gVGhlbiwNCiQkIE4gPSBnICsgKGsgLSAxKSArIDEgPSByIC0gMiArKGsgLSAxKSArIDEgPXIray0yICQkDQpCZWxvdywgdGhleSBjcmVhdGUgYSBCLXNwbGluZXMsIGF0IG9yZGVyICRrJCBhbmQgZ2l2ZW4gdmFsdWVzICR0ID0gcGFybml0aW9uID0gc2VxKG1pbihsYW1iZGEpLCBtYXgobGFtYmRhKSwgbGVuZ3RoID0gMTAwKSQuIENoZWNrIHZhbHVlICRsJCBmb3IgdGhlIG5leHQgY2h1bmsNCg0KYGBge3J9DQogIGwgPSBjKCkNCiAgZm9yIChpIGluICgxOk4pKSB7DQogICAgZm9yIChqIGluIDE6KGsgKyAxKSkgew0KICAgICAgbFtqXSA9IGxhbWJkYVtpICsgaiAtIDFdDQogICAgICBwcmludChjKGkgLCBqLCByb3VuZChsLCAxKSkpDQogICAgfQ0KICB9DQpgYGANCg0KRnJvbSB0aGUgYWJvdmUgcmVzdWx0cywgZ2l2ZW4gaSBhbmQgaiwgdGhlIHZlY3RvciAkbCQgaGFzIDEsIDIsIDMgb3IgNCBrbm90cyAodGhlIG1vc3QgY29tbW9uKS4gVGhlbiwgdGhleSB1c2UgdGhlIHZlY3RvciAkbCQga25vdHMgdG8gY3JlYXRlIEItc3BsaW5lcyBiYXNpcywgYXQgb3JkZXIgNCBhbmQgdmFsdWUgIHBhcm5pdGlvbi4gRWFjaCBCLXNwbGluZSBpcyBzdG9yZWQgaW4gbWF0cml4IEJCLiANCg0KUXVlc3Rpb246IFdoZXJlIGRvIHdlIGFwcGx5IG1hdHJpeCBCQj8/Pz8/DQpBbnN3ZXI6IEJCIGlzIHVzZSB0byBwbG90IHRoZSBaQi1zcGxpbmUgYmFzaXMgc3lzdGVtLCBzZWUgYWdhaW4gYXQgdGhlIGVuZCBvZiB0aGlzIGZpbGUuDQoNCmBgYHtyfQ0KTiANCkJCID0gYXJyYXkoMCwgYyhsZW5ndGgocGFybml0aW9uKSwgTikpDQogIGwgPSBjKCkNCiAgZm9yIChpIGluICgxOk4pKSB7DQogICAgZm9yIChqIGluIDE6KGsgKyAxKSkgew0KICAgICAgbFtqXSA9IGxhbWJkYVtpICsgaiAtIDFdDQogICAgfQ0KICAgIEJCWywgaV0gPSBzcGxpbmVEZXNpZ24obCwgcGFybml0aW9uLCBrLCBvdXRlci5vayA9IFRSVUUpDQogIH0NCmRpbShCQikNCmBgYA0KDQpzZWUgYWdhaW4gQkIsIHNlZW1zIHRvIGJlIHNpbWxhciB0byBCISEhLCBwbG90IGJlbG93DQoNCmBgYHtyfQ0KaGVhZChCQiwgMTIpDQpgYGANCg0KYGBge3J9DQpgYGANCg0KDQojIyMgMy41LiBDaGVjayB0aGUgb3JkZXIgb2YgZGVyaXZhdGl2ZSwgQ29sbG9jYXRvbiBtYXRyaXguDQoNClJlY2FsbCBjb2xsb2NhdG9uIG1hdHJpeCANCiQkDQpcYmVnaW57YWxpZ25lZH0NCiZcbWF0aGJme0J9X3trKzF9KFxtYXRoYmZ7eH0pPVxsZWZ0KEJfe2l9XntrKzF9XGxlZnQoeF97an1ccmlnaHQpXHJpZ2h0KV97aj0xLCBpPS1rfV57biwgZ30gXFwNCiZcbWF0aGJme0N9X3trKzF9KFxtYXRoYmZ7eH0pPVxsZWZ0KFxiZWdpbnthcnJheX17Y2NjfQ0KQl97LWt9XntrKzF9XGxlZnQoeF97MX1ccmlnaHQpICYgXGNkb3RzICYgQl97Z31ee2srMX1cbGVmdCh4X3sxfVxyaWdodCkgXFwNClx2ZG90cyAmIFxkZG90cyAmIFx2ZG90cyBcXA0KQl97LWt9XntrKzF9XGxlZnQoeF97bn1ccmlnaHQpICYgXGNkb3RzICYgQl97Z31ee2srMX1cbGVmdCh4X3tufVxyaWdodCkNClxlbmR7YXJyYXl9XHJpZ2h0KSBcaW4gXG1hdGhiYntSfV57biwgZytrKzF9DQpcZW5ke2FsaWduZWR9DQokJA0KDQoNCmBgYHtyfQ0KbGVuZ3RoKHQpIDw9IE4NCg0KcXIoQikkcmFuayAhPSBODQoNCiAgaWYgKGxlbmd0aCh0KSA8PSBOKSANCiAgICBzdG9wKCJsZW5ndGgodCkgbXVzdCBiZSBoaWdoZXIgdGhlbiBEaW1lbnNpb24oc3BhY2Ugb2Ygc3BsaW5lcykiKQ0KICBpZiAocXIoQikkcmFuayAhPSBOKSANCiAgICBzdG9wKCJDb2xsb2NhdG9uIG1hdHJpeCBkb2VzIG5vdCBoYXZlIGZ1bGwgY29sdW1uIHJhbmsuIikNCg0KYGBgDQoNCiMjIyAzLjYuIENyZWF0ZSBtYXRyaXggdGhlIFVwcGVyIHRyaWFuZ3VsYXIgbWF0cml4ICRTJA0KDQpNYXRyaXggJFNfbCQsIHdpdGggJGwkIGlzIHRoZSAkbCR0aCBkZXJpdmF0aXZlIGluIHRoZSBiZWxvdyBlcXVhdGlvbg0KDQokJEpfe2x9XGxlZnQoc197a31ccmlnaHQpPSgxLVxhbHBoYSkgXGludF97YX1ee2J9XGxlZnRbc197a31eeyhsKX0oeClccmlnaHRdXnsyfSBcbWF0aHJte35kfSB4K1xhbHBoYSBcc3VtX3tpPTF9XntufSB3X3tpfVxsZWZ0W3lfe2l9LXNfe2t9XGxlZnQoeF97aX1ccmlnaHQpXHJpZ2h0XV57Mn0kJA0KDQojIyMjIDMuNi4xIFRoZSBnZW5lcmFsIGZvcm0gb2YgJFNfbCQNCg0KJCQNClxtYXRoYmZ7U31fe2x9PVxtYXRoYmZ7RH1fe2x9IFxtYXRoYmZ7TH1fe2x9IFxsZG90cyBcbWF0aGJme0R9X3sxfSBcbWF0aGJme0x9X3sxfSBcaW4gXG1hdGhiYntSfV57ZytrKzEtbCwgZytrKzF9DQokJA0KDQp3aGVyZSANCiQkDQpcbWF0aGJme0R9X3tqfT0oaysxLWopIFxvcGVyYXRvcm5hbWV7ZGlhZ31cbGVmdChkX3staytqfSwgXGxkb3RzLCBkX3tnfVxyaWdodCkNCiQkDQp3aXRoDQokJA0KZF97aX09XGZyYWN7MX17XGxhbWJkYV97aStrKzEtan0tXGxhbWJkYV97aX19LCBccXVhZCBpPS1rK2osIFxsZG90cywgZw0KJCQNCmFuZA0KJCQNClxtYXRoYmZ7TH1fe2p9Oj1cbGVmdChcYmVnaW57YXJyYXl9e3JycnJ9DQotMSAmIDEgJiAmIFxcDQomIFxkZG90cyAmIFxkZG90cyAmIFxcDQomICYgLTEgJiAxDQpcZW5ke2FycmF5fVxyaWdodCkgXGluIFxtYXRoYmJ7Un1ee2craysxLWosIGcraysyLWp9DQokJA0KDQojIyMjIDMuNi4yIFRoZSBmb3JtIG9mICRTX2wkIHdoZW4gJGw9MiQuDQoNCiQkDQpcbWF0aGJme1N9X3syfT1cbWF0aGJme0R9X3syfSBcbWF0aGJme0x9X3syfSBcbWF0aGJme0R9X3sxfSBcbWF0aGJme0x9X3sxfSBcaW4gXG1hdGhiYntSfV57ZytrKzEtMiwgZytrKzF9ID0gXG1hdGhiYntSfV57ZytrLTEsIGcraysxfQ0KJCQNCg0Kd2hlcmUNCg0KJCQNClxiZWdpbnthbGlnbn0NCiZcbWF0aGJme0R9X3sxfT0oaysxLTEpIFxvcGVyYXRvcm5hbWV7ZGlhZ31cbGVmdChkX3staysxfSwgXGxkb3RzLCBkX3tnfVxyaWdodCkgPSBrIFxvcGVyYXRvcm5hbWV7ZGlhZ31cbGVmdChkX3staysxfSwgXGxkb3RzLCBkX3tnfVxyaWdodCksXHF1YWQgZF97aX09XGZyYWN7MX17XGxhbWJkYV97aStrKzEtMX0tXGxhbWJkYV97aX19PSBcZnJhY3sxfXtcbGFtYmRhX3tpK2t9LVxsYW1iZGFfe2l9fSwgXHF1YWQgaT0taysxLCBcbGRvdHMsIGdcXA0KJiBcbWF0aGJme0R9X3syfT0oaysxLTIpIFxvcGVyYXRvcm5hbWV7ZGlhZ31cbGVmdChkX3staysyfSwgXGxkb3RzLCBkX3tnfVxyaWdodCkgPSAoay0xKSBcb3BlcmF0b3JuYW1le2RpYWd9XGxlZnQoZF97LWsrMn0sIFxsZG90cywgZF97Z31ccmlnaHQpLCBccXVhZCBkX3tpfT1cZnJhY3sxfXtcbGFtYmRhX3tpK2srMS0yfS1cbGFtYmRhX3tpfX09IFxmcmFjezF9e1xsYW1iZGFfe2kray0xfS1cbGFtYmRhX3tpfX0sIFxxdWFkIGk9LWsrMiwgXGxkb3RzLCBnDQpcZW5ke2FsaWdufQ0KJCQNCg0KIyMjIyAzLjYuMyBDaGVjayB0aGUgY29kZSB3aXRoICRsID0gZGVyID0gMiQNCg0KYGBge3J9DQojUyA9IGFycmF5KDApDQpTX3BvbSA9IGRpYWcoMSwgTiwgTikNCiAgICANCmZvciAoaiBpbiAxOmRlcikgew0KICAgICAgRF9tYXQgPSBhcnJheSgwKQ0KICAgICAgcm96ZGlsID0gbGFtYmRhWygxICsgayk6KE4gKyBrIC0gaildIC0gbGFtYmRhWygxICsgICBqKTooTildDQogICAgICBEX21hdCA9IChrIC0gaikgKiBkaWFnKDEvcm96ZGlsKQ0KICAgICAgTF9tYXQgPSBhcnJheSgwLCBjKE4gLSBqLCBOIC0gaiArIDEpKQ0KICAgICAgICAgIGZvciAoSiBpbiAoMTooTiAtIGopKSkgew0KICAgICAgICAgICAgICBMX21hdFtKLCBKXSA9ICgtMSkNCiAgICAgICAgICAgICAgTF9tYXRbSiwgSiArIDFdID0gMQ0KICAgICAgICAgICAgfQ0KICAgICAgU19wb20gPSBEX21hdCAlKiUgTF9tYXQgJSolIFNfcG9tDQogICAgfQ0KICAgIFMgPSBTX3BvbQ0KICAgIGRpbShTKQ0KDQpgYGANCg0KVGhlIGZvbGxvd2luZyBjb2RlLCB3ZSBzZWUgdGhlIG1hdHJpeCBEIGFuZCBtYXRyaXggTCwgYXQgdmFsdWUgJGogPSAxJA0KDQpgYGB7cn0NClNfcG9tID0gZGlhZygxLCBOLCBOKQ0KaiA9IDENCkRfbWF0ID0gYXJyYXkoMCkNCnJvemRpbCA9IGxhbWJkYVsoMSArIGspOihOICsgayAtIGopXSAtIGxhbWJkYVsoMSArICAgaik6KE4pXQ0KRF9tYXQgPSAoayAtIGopICogZGlhZygxL3JvemRpbCkNCkxfbWF0ID0gYXJyYXkoMCwgYyhOIC0gaiwgTiAtIGogKyAxKSkNCiAgICAgICAgICBmb3IgKEogaW4gKDE6KE4gLSBqKSkpIHsNCiAgICAgICAgICAgICAgTF9tYXRbSiwgSl0gPSAoLTEpDQogICAgICAgICAgICAgIExfbWF0W0osIEogKyAxXSA9IDENCiAgICAgICAgICB9DQojcHJpbnQgbWF0cml4DQpoZWFkKERfbWF0KQ0KaGVhZChMX21hdCkNCmBgYA0KDQoNClRoZSBmb2xsb3dpbmcgY29kZSwgd2Ugc2VlIHRoZSBtYXRyaXggRCBhbmQgbWF0cml4IEwsIGF0IHZhbHVlICRqID0gMiQNCg0KYGBge3J9DQpTX3BvbSA9IGRpYWcoMSwgTiwgTikNCmogPSAyDQpEX21hdCA9IGFycmF5KDApDQpyb3pkaWwgPSBsYW1iZGFbKDEgKyBrKTooTiArIGsgLSBqKV0gLSBsYW1iZGFbKDEgKyAgIGopOihOKV0NCkRfbWF0ID0gKGsgLSBqKSAqIGRpYWcoMS9yb3pkaWwpDQpMX21hdCA9IGFycmF5KDAsIGMoTiAtIGosIE4gLSBqICsgMSkpDQogICAgICAgICAgZm9yIChKIGluICgxOihOIC0gaikpKSB7DQogICAgICAgICAgICAgIExfbWF0W0osIEpdID0gKC0xKQ0KICAgICAgICAgICAgICBMX21hdFtKLCBKICsgMV0gPSAxDQogICAgICAgICAgfQ0KI3ByaW50IG1hdHJpeA0KaGVhZChEX21hdCkNCmhlYWQoTF9tYXQpDQpgYGANCg0KIyMjIyAzLjcgUHJlcGFyZSBtYXRyaXggJE1fe2tsfSA9IE1fezMsMn0gJA0KDQpSZWNhbGwgbWF0cml4ICRNX3trbH0kIGlzIA0KJCQNClxtYXRoYmZ7TX1fe2sgbH09XGxlZnQobV97aSBqfV57ayBsfVxyaWdodClfe2ksIGo9LWsrbH1ee2d9LCBccXVhZCBcdGV4dCB7IHdpdGggfSBccXVhZCBtX3tpIGp9XntrIGx9PVxpbnRfe2F9XntifSBCX3tpfV57aysxLWx9KHgpIEJfe2p9XntrKzEtbH0oeCkgXG1hdGhybXtkfSB4DQokJA0KSW4gdGhlIGJlbG93IGNvZGUsIGtrIG1lYW5zICRrayA9IGsrMSAtIGwkLiBIb3dldmVyLCBhcyBDaHJpc3RpbmUgcmVtaW5kaW5nLCB3ZSAgdXN1YWxseSB3b3JrIHdpdGggJGwgPSAyLiQgDQoNClRoZW4sIGdpdmVuIG9yZGVyIGtrLCB3ZSBuZWVkIGEgdG90YWwgb2YgY2Vsa292YV9kZWxrYSBrbm90cyAoaW5zaWRlIGtub3RzLCBib3JkZXIga25vdHMgYW5kIGV4dHJhIGtub3RzICkNCg0KYGBge3J9DQprayA9IGsgLSBkZXINCmtrDQogIGNlbGtvdmFfZGVsa2EgPSAyICogKGtrIC0gMSkgKyByDQogICBjZWxrb3ZhX2RlbGthIA0KYGBgDQoNClRoZSBiZWxvdyBjb2RlIGNyZWF0ZSBhIHRvdGFsIGtub3RzIGZvciBCLXNwbGluZSBvcmRlciAka2skISEhIFRoZXkgY3JlYXRlIGV4dHJhIGtub3RzIGJhc2VkIG9uIHRoZSBnaXZlbiBMYW1iZGEga25vdHMgKGluY2x1ZGluZyBpbnNpZGUga25vdHMgYW5kIGJvcmRlciBrbm90cykuDQoNCmBgYHtyfQ0KICBMYW1iZGEgPSBjKCkNCiAgZm9yIChpIGluIDE6Y2Vsa292YV9kZWxrYSkgew0KICAgIGlmIChpIDw9IChrayAtIDEpKSB7DQogICAgICBMYW1iZGFbaV0gPSBrbm90c1sxXQ0KICAgIH0NCiAgICBpZiAoKGkgPiBrayAtIDEpICYmIChpIDw9IHIgKyBrayAtIDEpKSB7DQogICAgICBMYW1iZGFbaV0gPSBrbm90c1tpIC0gKGtrIC0gMSldDQogICAgfQ0KICAgIGlmIChpID4gKHIgKyAoa2sgLSAxKSkpIHsNCiAgICAgIExhbWJkYVtpXSA9IGtub3RzW3JdDQogICAgfQ0KICB9DQpMYW1iZGENCmBgYA0KDQoNCmNvcnJlc3BvbmQgdG8NCg0KJCQNClxiZWdpbnthbGlnbmVkfQ0KJlxEZWx0YSBcbGFtYmRhOj1cbGFtYmRhX3swfT0tNC43PXU8XGxhbWJkYV97MX09LTMuNjY8XGNkb3RzPFxsYW1iZGFfezh9PTMuNjY8dj00Ljc9XGRvdHtcbGFtYmRhfV97OX0gXFwNCiZcbGFtYmRhX3stMX09XGxhbWJkYV97MH09LTQuNywgXHF1YWQgIFxsYW1iZGFfezl9ID0gXGxhbWJkYV97MTB9PTQuNyANClxlbmR7YWxpZ25lZH0NCiQkDQpUaGUgZm9sbG93aW5nIGNvZGUgY3JlYXRlIGEgQi1zcGxpbmUgYXQgb3JkZXIga2sgYmFzZWQgb24gTGFtYmRhIGtub3RzLg0KDQpgYGB7cn0NCiBQYXJuaXRpb24gPSBzZXEobWluKExhbWJkYSksIG1heChMYW1iZGEpLCBsZW5ndGggPSAxMDApDQogQkJCID0gc3BsaW5lRGVzaWduKExhbWJkYSwgUGFybml0aW9uLCBraywgb3V0ZXIub2sgPSBUUlVFKQ0KDQogZGltKEJCQikNCmBgYA0KDQoNCnBsb3QgdGhlIEJCQiBiYXNpYywgaXQgaXMgY29ycmVjdCBzaW5jZSB0aGV5IGFyZSBhdCBvcmRlciAka2s9MS4kDQoNCmBgYHtyfQ0KcGxvdChyYW5nZShQYXJuaXRpb24pLCBjKDAsMSksIHR5cGUgPSAibiIsIHhsYWIgPSAieCIsIHlsYWIgPSAiIiwNCiAgICAgbWFpbiA9ICAiQi1zcGxpbmVzIGF0IG9yZGVyIGtrID0gMSwgdXNpbmcga25vdHMgTGFtYmRhIikNCiNtdGV4dChleHByZXNzaW9uKEJbal0oeCkgKiIgIGFuZCAiKiBzdW0oQltqXSh4KSwgaiA9PSAxLCA2KSksIGFkaiA9IDApDQphYmxpbmUodiA9ICBMYW1iZGEsIGx0eSA9IDMsIGNvbCA9ICJsaWdodCBncmF5IikNCmFibGluZSh2ID0gIExhbWJkYVtjKDQsbGVuZ3RoKExhbWJkYSktMyldLCBsdHkgPSAzLCBjb2wgPSAiZ3JheTEwIikNCiNsaW5lcyh4LCByb3dTdW1zKGJiKSwgY29sID0gImdyYXkiLCBsd2QgPSAyKQ0KbWF0bGluZXMoUGFybml0aW9uLCBCQkIsIHlsaW0gPSBjKDAsMSksIGx0eSA9IDEpDQpgYGANCg0KVGhlIGZvbGxvd2luZyBjb2RlIGZpbmlzaGVzIHRoZSBjYWxjdWxhdGlvbiBvZiBNDQoNCiQkDQptX3tpIGp9XntrIGx9PVxpbnRfe2F9XntifSBCX3tpfV57aysxLWx9KHgpIEJfe2p9XntrKzEtbH0oeCkgXG1hdGhybXtkfSB4DQokJA0KDQpgYGB7cn0NCiAgICANCiAgICAgTGFtYmRhX2luZGV4ID0gYygwOihyIC0gMSkpIA0KICBHID0gTGFtYmRhX2luZGV4W2xlbmd0aChMYW1iZGFfaW5kZXgpIC0gMV0NCiAgTk4gPSBHICsgKGtrIC0gMSkgKyAxDQogIHN0ZXAgPSBkaWZmKFBhcm5pdGlvblsxOjJdKQ0KICBNID0gYXJyYXkoMCwgYyhOTiwgTk4pKQ0KICBmb3IgKGkgaW4gMTpOTikgew0KICAgIGZvciAoaiBpbiAxOk5OKSB7DQogICAgICBuZW51bG92ZSA9IGMoKQ0KICAgICAgc291Y2luID0gQkJCWywgaV0gKiBCQkJbLCBqXQ0KICAgICAgZm9yIChtIGluIDE6bGVuZ3RoKFBhcm5pdGlvbikpIHsNCiAgICAgICAgaWYgKHNvdWNpblttXSAhPSAwKSB7DQogICAgICAgICAgbmVudWxvdmVbbV0gPSBzb3VjaW5bbV0NCiAgICAgICAgfQ0KICAgICAgfQ0KICAgICAgTVtpLCBqXSA9IHRyYXB6YyhzdGVwLCBzb3VjaW4pDQogICAgfQ0KICB9DQogZGltKE0pDQpgYGANCg0KIyMgNC4gRmluZCB0aGUgb3B0aW1hbCBmdW5jdGlvbg0KDQojIyMgNC4xIENyZWF0ZSBtYXRyaXggRCwgSywgVSBhbmQgRw0KDQokJA0KXG1hdGhiZntEfV97an09KGsrMS1qKSBcb3BlcmF0b3JuYW1le2RpYWd9XGxlZnQoZF97LWsran0sIFxsZG90cywgZF97Z31ccmlnaHQpDQokJA0Kd2l0aA0KJCQNCmRfe2l9PVxmcmFjezF9e1xsYW1iZGFfe2kraysxLWp9LVxsYW1iZGFfe2l9fSwgXHF1YWQgaT0taytqLCBcbGRvdHMsIGcNCiQkDQoNCg0KYGBge3J9DQpkaWZmZXJlbmNlID0gbGFtYmRhWygxICsgayk6KHIgKyAyICogKGsgLSAxKSldIC0gbGFtYmRhWygxOihyICsgIGsgLSAyKSldDQpEID0gKGspICogZGlhZygxL2RpZmZlcmVuY2UpDQpLID0gYXJyYXkoMCwgYyhOLCBOIC0gMSkpDQpLWzEsIDFdID0gMQ0KS1tOLCBOIC0gMV0gPSAtMQ0KZm9yIChqIGluICgyOihOIC0gMSkpKSB7DQogIEtbaiwgaiAtIDFdID0gKC0xKQ0KICBLW2osIGpdID0gMQ0KfQ0KIyBTZWUgbWF0cml4IEQgYW5kIG1hdHJpeCBLDQpkaW0oRCkNCmRpbShLKQ0KYGBgDQoNCg0KVGhlbiwgVXNpbmcgdGhlIG5vdGF0aW9uIA0KJCRcbWF0aGJme1V9Oj1cbWF0aGJme0QgS30kJA0KDQpgYGB7cn0NClUgPSBEICUqJSBLDQpkaW0oVSkNCmBgYA0KDQpUaGVuLCBjYWxjdWxhdGUgbWF0cml4IEcNCiQkDQpcbWF0aGJme0d9Oj1cbWF0aGJme1V9XntcdG9wfVxsZWZ0WygxLVxhbHBoYSkgXG1hdGhiZntTfV97bH1ee1x0b3B9IFxtYXRoYmZ7TX1fe2sgbH0gXG1hdGhiZntTfV97bH0rXGFscGhhIFxtYXRoYmZ7Qn1fe2srMX1ee1x0b3B9KFxtYXRoYmZ7eH0pIFxtYXRoYmZ7VyBCfV97aysxfShcbWF0aGJme3h9KVxyaWdodF0gXG1hdGhiZntVfQ0KJCQNCg0KYGBge3J9DQphbHBoYSA9IDAuNTg5MTA3NyAjMS45NTAxOTMNCkdHID0gdChVKSAlKiUgKCgxIC0gYWxwaGEpICogdChTKSAlKiUgTSAlKiUgUyArIGFscGhhICogdChCKSAlKiUgIFcgJSolIEIpICUqJSBVDQpkaW0oR0cpDQpgYGANCg0KVGhlbiwgY2FsY3VsYXRlIG1hdHJpeCAkZyQgYXMgYmVsb3cNCg0KJCQNClxtYXRoYmZ7Z306PVxhbHBoYSBcbWF0aGJme0t9XntcdG9wfSBcbWF0aGJme0R9IFxtYXRoYmZ7Qn1fe2srMX1ee1x0b3B9KFxtYXRoYmZ7eH0pIFxtYXRoYmZ7V30gXG1hdGhiZnt5fQ0KJCQNCg0KDQpgYGB7cn0NCmdnID0gYWxwaGEgKiB0KEspICUqJSB0KEQpICUqJSB0KEIpICUqJSBXICUqJSBjbHJmDQpkaW0oZ2cpDQpgYGANCg0KU2VlIGNscmYsIGksZSB5DQoNCmBgYHtyfQ0KbGVuZ3RoKGNscmYpDQoNCmBgYA0KDQpgYGB7cn0NCmRpbShhbHBoYSAqIHQoSykgJSolIHQoRCkgJSolIHQoQikgJSolIFcpDQpsZW5ndGgoY2xyZikNCmBgYA0KDQojIyMgNC4yIFNvbHZlIHRoZSBvcHRpbWFsDQoNClRoZSBvcHRpbWFsIHNvbHV0aW9uDQoNCmBgYHtyfQ0KeiA9IHNvbHZlKEdHKSAlKiUgZ2cNCmxlbmd0aCh6KQ0Keg0KYGBgDQoNClRoZSBvcHRpbWFsIFpCLXNwbGluZSwgaS5lIFpiYXNpcyBhbmQgaXQgaXMgdGhlIEJESyBpbiB0aGUgZm9sbG93aW5nIGVxdWF0aW9uczoNCg0KJCQNCnNfe2t9XnsqfSh4KT1cbWF0aGJme0J9X3trKzF9KHgpIFxtYXRoYmZ7RCBLIHp9XnsqfQ0KJCQNCg0KYGBge3J9DQpaYmFzaXMgPSBCICUqJSBEICUqJSBLDQpkaW0oWmJhc2lzKQ0KWmJhc2lzX2Zpbm5lciA9IEJCICUqJSBEICUqJSBLDQpkaW0oWmJhc2lzX2Zpbm5lcikNCmBgYA0KDQojIyMgNS4gUGxvdCB0aGUgZmluYWwgcmVzdWx0cw0KIyMjIyA1LjEuIFBsb3QgdGhlIFpCLXNwbGluZSBiYXNpcyBzeXN0ZW0gDQoNCmBgYHtyfQ0KI2lmIChiYXNpcy5wbG90ID09IFRSVUUpIHsNCiAgbWF0cGxvdChwYXJuaXRpb24sIFpiYXNpc19maW5uZXIsIHR5cGUgPSAibCIsIGx0eSA9IDEsIA0KICAgICAgICAgIGxhcyA9IDEsIHhsYWIgPSAidCIsIHlsYWIgPSAiZmNlbkxSKGRlbnNpdHkpIiwgDQogICAgICAgICAgY29sID0gcmFpbmJvdyhkaW0oWmJhc2lzX2Zpbm5lcilbMl0pLCBtYWluID0gIlpCLXNwbGluZSBiYXNpcyIpDQogIGFibGluZSh2ID0ga25vdHMsIGNvbCA9ICJncmF5IiwgbHR5ID0gMikNCiN9DQpgYGANCg0KIyMjIyA1LjIgUGxvdCB0aGUgb3B0aW1hbCBzcGxpbmUNCg0KYGBge3J9DQpzcGxpbmUwID0gWmJhc2lzX2Zpbm5lciAlKiUgeg0KZGltKHNwbGluZTApDQpoZWFkKHNwbGluZTApDQpgYGANCg0KcGFybml0aW9uIGlzIGEgZ3JpZCBvZiBwb2ludA0Kc3BsaW5lMCBpcyB0aGUgb3B0aW1hbCBzcGxpbmUgZXZhbHVhdGVkIGF0IHRoZSBncmlkIHBvaW50ICJwYXJuaXRpb24iDQoNCmBgYHtyfQ0KI2lmIChzcGxpbmUucGxvdCA9PSBUUlVFKSB7DQogIG1hdHBsb3QocGFybml0aW9uLCBzcGxpbmUwLCB0eXBlID0gImwiLCBsYXMgPSAxLCANCiAgICAgICAgICB4bGFiID0gInQiLCB5bGFiID0gImZjZW5MUihkZW5zaXR5KSIsIA0KICAgICAgICAgIGNvbCA9ICJkYXJrYmx1ZSIsIGx3ZCA9IDIsIGNleC5sYWIgPSAxLjIsIGNleC5heGlzID0gMS4yLCANCiAgICAgICAgICB5bGltID0gYyhtaW4oYyhtaW4oY2xyZiksIG1pbihzcGxpbmUwKSkpLCBtYXgoYyhtYXgoY2xyZiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heChzcGxpbmUwKSkpKSwgbWFpbiA9IHBhc3RlKCJDb21wb3NpdGlvbmFsIHNwbGluZSBvZiBkZWdyZWUgayA9IiwgIGsgLSAxKSkNCiAjIG1hdHBvaW50cyh0LCBjbHJmLCBwY2ggPSA4LCBjb2wgPSAiZGFya2JsdWUiLCBjZXggPSAxLjMpDQogICNhYmxpbmUoaCA9IDAsIGNvbCA9ICJyZWQiLCBsdHkgPSAyLCBsd2QgPSAxKSAjIFRoZSBob3Jpem9udGFsIGxpbmUNCiAgI2FibGluZSh2ID0ga25vdHMsIGNvbCA9ICJncmF5IiwgbHR5ID0gMiwgbHdkID0gMSkNCiN9DQpgYGANCg0KVGhlIGxpbmUgd2l0aCBwY2ggPSA4IGlzIHRoZSBvcmlnaW5hbCBncmlkIHBvaW50cyBhbmQgdGhlIGluaXRpYWwgJHkgPSBjbHIoZikkIHBvaW50cy4NCg0KYGBge3J9DQojaWYgKHNwbGluZS5wbG90ID09IFRSVUUpIHsNCiAgbWF0cGxvdChwYXJuaXRpb24sIHNwbGluZTAsIHR5cGUgPSAibCIsIGxhcyA9IDEsIA0KICAgICAgICAgIHhsYWIgPSAidCIsIHlsYWIgPSAiZmNlbkxSKGRlbnNpdHkpIiwgDQogICAgICAgICAgY29sID0gImRhcmtibHVlIiwgbHdkID0gMiwgY2V4LmxhYiA9IDEuMiwgY2V4LmF4aXMgPSAxLjIsIA0KICAgICAgICAgIHlsaW0gPSBjKG1pbihjKG1pbihjbHJmKSwgbWluKHNwbGluZTApKSksIG1heChjKG1heChjbHJmKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4KHNwbGluZTApKSkpLCBtYWluID0gcGFzdGUoIkNvbXBvc2l0aW9uYWwgc3BsaW5lIG9mIGRlZ3JlZSBrID0iLCAgayAtIDEpKQ0KICBtYXRwb2ludHModCwgY2xyZiwgcGNoID0gOCwgY29sID0gImRhcmtibHVlIiwgY2V4ID0gMS4zKQ0KICAjYWJsaW5lKGggPSAwLCBjb2wgPSAicmVkIiwgbHR5ID0gMiwgbHdkID0gMSkgIyBUaGUgaG9yaXpvbnRhbCBsaW5lDQogICNhYmxpbmUodiA9IGtub3RzLCBjb2wgPSAiZ3JheSIsIGx0eSA9IDIsIGx3ZCA9IDEpDQojfQ0KYGBgDQpDaGVjayBhZ2FpbiBrbm90cw0KDQpgYGB7cn0NCmtub3RzDQpgYGANCg0KVGhlIGJlbG93IGZpZ3VyZSBhcmUgdGhlIG9yaWdpbmFsIGNvZGUgb2YgdGhlIFRhbHNrYSB0ZWFtLg0KDQpgYGB7cn0NCiNpZiAoc3BsaW5lLnBsb3QgPT0gVFJVRSkgew0KICBtYXRwbG90KHBhcm5pdGlvbiwgc3BsaW5lMCwgdHlwZSA9ICJsIiwgbGFzID0gMSwgDQogICAgICAgICAgeGxhYiA9ICJ0IiwgeWxhYiA9ICJmY2VuTFIoZGVuc2l0eSkiLCANCiAgICAgICAgICBjb2wgPSAiZGFya2JsdWUiLCBsd2QgPSAyLCBjZXgubGFiID0gMS4yLCBjZXguYXhpcyA9IDEuMiwgDQogICAgICAgICAgeWxpbSA9IGMobWluKGMobWluKGNscmYpLCBtaW4oc3BsaW5lMCkpKSwgbWF4KGMobWF4KGNscmYpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXgoc3BsaW5lMCkpKSksIG1haW4gPSBwYXN0ZSgiQ29tcG9zaXRpb25hbCBzcGxpbmUgb2YgZGVncmVlIGsgPSIsICBrIC0gMSkpDQogIG1hdHBvaW50cyh0LCBjbHJmLCBwY2ggPSA4LCBjb2wgPSAiZGFya2JsdWUiLCBjZXggPSAxLjMpDQogIGFibGluZShoID0gMCwgY29sID0gInJlZCIsIGx0eSA9IDIsIGx3ZCA9IDEpICMgVGhlIGhvcml6b250YWwgbGluZQ0KICBhYmxpbmUodiA9IGtub3RzLCBjb2wgPSAiZ3JheSIsIGx0eSA9IDIsIGx3ZCA9IDEpICMgVGhlIGdyaWQgdmVydGljYWwgbGluZXMNCiN9DQpgYGANCg0KSXQgc2VlbXMgZG9uZSEhDQoNCiMjIyA2LiBTbW9vdGhpbmcgcGFyYW1ldGVyIGFscGhhDQoNCmBgYHtyfQ0KY2xyZiA9IGFzLm1hdHJpeChjbHJmKQ0KSG1hdCA9IChCICUqJSBEICUqJSBLKSAlKiUgc29sdmUoR0cpICUqJSAoYWxwaGEgKiB0KEspICUqJSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdChEKSAlKiUgdChCKSAlKiUgVykNCmNscmZoYXQgPSAoQiAlKiUgRCAlKiUgSykgJSolIHoNCnJlemlkdWFscyA9IChjbHJmIC0gY2xyZmhhdCkNCkhtYXRfZGlhZyA9IGMoKQ0KZm9yIChpIGluIDE6bGVuZ3RoKGNscmYpKSBIbWF0X2RpYWdbaV0gPSBIbWF0W2ksIGldDQpIbWF0X2RpYWdfbWVhbiA9ICgxL2xlbmd0aChjbHJmKSkgKiBzdW0oSG1hdF9kaWFnKQ0KQ1YgPSAoMS9sZW5ndGgoY2xyZikpICogc3VtKChyZXppZHVhbHMvKHJlcCgxLCBsZW5ndGgoSG1hdF9kaWFnKSkgLSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEhtYXRfZGlhZykpXjIpDQpDVg0KDQpHQ1YgPSAoMS9sZW5ndGgoY2xyZikpICogKHN1bSgocmV6aWR1YWxzKV4yKSkvKCgxIC0gSG1hdF9kaWFnX21lYW4pXjIpDQpKID0gKDEgLSBhbHBoYSkgKiB0KHopICUqJSB0KFUpICUqJSB0KFMpICUqJSBNICUqJSBTICUqJSANCiAgVSAlKiUgeiArIGFscGhhICogdChjbHJmIC0gQiAlKiUgRCAlKiUgSyAlKiUgeikgJSolIFcgJSolIA0KICAoY2xyZiAtIEIgJSolIEQgJSolIEsgJSolIHopDQoNCkdDVg0KYGBgDQoNCg0KDQo=