2. Representasi lokal MobileViTv3-v2
Pada ilustrasi ini, matriks \(X\)
merupakan satu irisan kanal dari feature map masukan blok \(\mathbf F^{(0)}\) setelah normalisasi.
Matriks \(X\) memiliki dimensi \(5\times5\). Tahap representasi lokal
dimulai dengan depthwise convolution \(3\times3\), dilanjutkan dengan fungsi
aktivasi Swish. Proyeksi pointwise \(1\times1\) baru diterapkan setelah feature
map lokal diperoleh.
a. Depthwise Convolution
Pada ilustrasi ini, matriks \(\mathbf{X}\) merupakan satu kanal
feature map masukan berukuran \(5\times5\). Operasi depthwise
convolution diterapkan secara independen pada kanal tersebut
menggunakan kernel \(3\times3\),
stride \(1\), zero
padding sebesar \(1\) pada setiap
sisi, dan tanpa bias. Keluaran sebelum aktivasi dinyatakan sebagai \(\mathbf{F}_{\mathrm{dw}}\).
Matriks feature map masukan yang digunakan adalah:
\[
\mathbf{X}
=
\begin{bmatrix}
-2.12 & -1.02 & 1.17 & 0.62 & -1.57\\
-2.12 & -0.75 & 1.44 & 0.90 & -1.43\\
-2.12 & -0.75 & 1.44 & 0.90 & -1.43\\
-2.12 & -0.88 & 1.17 & 0.62 & -1.57\\
-1.98 & -1.30 & 0.35 & -0.20 & -1.71
\end{bmatrix}.
\]
Sebelum operasi depthwise convolution dilakukan, satu
lapisan nilai nol ditambahkan pada keempat sisi matriks masukan, yaitu
sisi atas, bawah, kiri, dan kanan. Penambahan zero padding ini
bertujuan mempertahankan ukuran spasial feature map setelah
proses konvolusi.
Ukuran keluaran dihitung menggunakan:
\[
o
=
\left\lfloor
\frac{i+2p-k}{s}
\right\rfloor+1,
\]
dengan \(i\) menyatakan ukuran
spasial masukan, \(p\) merupakan jumlah
padding pada setiap sisi, \(k\) merupakan ukuran kernel, dan \(s\) merupakan stride.
Pada ilustrasi ini, digunakan \(i=5\), \(p=1\), \(k=3\), dan \(s=1\), sehingga:
\[
\begin{aligned}
o
&=
\left\lfloor
\frac{5+2(1)-3}{1}
\right\rfloor+1\\
&=
\left\lfloor
\frac{4}{1}
\right\rfloor+1\\
&=5.
\end{aligned}
\]
Dengan demikian, ukuran spasial keluaran tetap \(5\times5\). Setelah penambahan zero
padding, ukuran matriks masukan sementara berubah dari \(5\times5\) menjadi \(7\times7\).
Matriks setelah penambahan zero padding adalah:
\[
\mathbf{X}_{\mathrm{pad}}
=
\begin{bmatrix}
0.00 & 0.00 & 0.00 & 0.00 & 0.00 & 0.00 & 0.00\\
0.00 & -2.12 & -1.02 & 1.17 & 0.62 & -1.57 &
0.00\\
0.00 & -2.12 & -0.75 & 1.44 & 0.90 & -1.43 &
0.00\\
0.00 & -2.12 & -0.75 & 1.44 & 0.90 & -1.43 &
0.00\\
0.00 & -2.12 & -0.88 & 1.17 & 0.62 & -1.57 &
0.00\\
0.00 & -1.98 & -1.30 & 0.35 & -0.20 & -1.71 &
0.00\\
0.00 & 0.00 & 0.00 & 0.00 & 0.00 & 0.00 & 0.00
\end{bmatrix}.
\]
- Filter atau Bobot Kernel Depthwise
Convolution:
Pada ilustrasi ini, matriks bobot kernel depthwise
convolution ditetapkan sebagai:
\[
\mathbf{W}_{\mathrm{dw}}
=
\begin{bmatrix}
0.05 & 0.10 & 0.05\\
0.10 & 0.40 & 0.10\\
0.05 & 0.10 & 0.05
\end{bmatrix}.
\]
Kernel tersebut berukuran \(3\times3\). Bobot pusat sebesar \(0.40\) memberikan kontribusi terbesar dari
elemen pusat, sedangkan elemen-elemen di sekitarnya memberikan
kontribusi melalui bobot \(0.05\) dan
\(0.10\).
Setiap hasil konvolusi diperoleh melalui perkalian sembilan elemen
pada area feature map dengan sembilan bobot kernel yang
bersesuaian, kemudian seluruh hasil perkalian dijumlahkan.
Secara umum, operasi depthwise convolution pada feature
map multikanal dinyatakan sebagai:
\[
F_{\mathrm{dw},k,l,m}
=
\sum_{u=1}^{3}
\sum_{v=1}^{3}
W_{\mathrm{dw},u,v,m}
X_{\mathrm{pad},k+u-1,l+v-1,m},
\]
dengan \(m\) menyatakan indeks
kanal, sedangkan \(u\) dan \(v\) merupakan indeks baris dan kolom
kernel.
Pada ilustrasi satu kanal, perhitungan setiap elemen keluaran
dinyatakan sebagai:
\[
F_{\mathrm{dw},k,l}
=
\sum_{u=1}^{3}
\sum_{v=1}^{3}
W_{\mathrm{dw},u,v}
X_{\mathrm{pad},k+u-1,l+v-1},
\]
dengan \(k,l=1,2,\ldots,5\).
Pada setiap posisi, kernel mencakup area berukuran \(3\times3\). Karena stride bernilai
\(1\), kernel bergeser satu kolom ke
kanan untuk menghitung elemen berikutnya pada baris keluaran yang sama.
Setelah mencapai posisi terakhir pada baris tersebut, kernel kembali ke
sisi kiri dan bergeser satu baris ke bawah.
- Contoh Perhitungan Konvolusi:
1. Perhitungan elemen pada posisi \((1,1)\)
Untuk menghasilkan elemen pertama dari feature map keluaran,
kernel ditempatkan pada area \(3\times3\) di pojok kiri atas matriks yang
telah diberi zero padding.
Area feature map yang diproses adalah:
\[
\begin{bmatrix}
0.00 & 0.00 & 0.00\\
0.00 & -2.12 & -1.02\\
0.00 & -2.12 & -0.75
\end{bmatrix}.
\]
Area tersebut dikalikan secara elemen demi elemen dengan bobot kernel
\(\mathbf{W}_{\mathrm{dw}}\), kemudian
seluruh hasil perkalian dijumlahkan sebagai berikut:
\[
\begin{aligned}
F_{\mathrm{dw},1,1}
={}&
(0.00)(0.05)
+(0.00)(0.10)
+(0.00)(0.05)\\
&+(0.00)(0.10)
+(-2.12)(0.40)
+(-1.02)(0.10)\\
&+(0.00)(0.05)
+(-2.12)(0.10)
+(-0.75)(0.05)\\
={}&
-0.848-0.102-0.212-0.0375\\
={}&-1.1995.
\end{aligned}
\]
Dengan pembulatan dua angka desimal, hasil perhitungan tersebut
adalah:
\[
F_{\mathrm{dw},1,1}=-1.20.
\]
2. Perhitungan elemen pada posisi \((2,2)\)
Untuk menghitung elemen pada posisi \((2,2)\), kernel ditempatkan pada area yang
dimulai dari baris kedua dan kolom kedua matriks setelah
padding. Posisi ini berada satu baris di bawah dan satu kolom
di kanan dibandingkan posisi awal.
Area feature map yang diproses adalah:
\[
\begin{bmatrix}
-2.12 & -1.02 & 1.17\\
-2.12 & -0.75 & 1.44\\
-2.12 & -0.75 & 1.44
\end{bmatrix}.
\]
Perhitungan konvolusi dilakukan menggunakan bobot kernel yang
sama:
\[
\begin{aligned}
F_{\mathrm{dw},2,2}
={}&
(-2.12)(0.05)
+(-1.02)(0.10)
+(1.17)(0.05)\\
&+(-2.12)(0.10)
+(-0.75)(0.40)
+(1.44)(0.10)\\
&+(-2.12)(0.05)
+(-0.75)(0.10)
+(1.44)(0.05)\\
={}&
-0.106-0.102+0.0585\\
&-0.212-0.300+0.144\\
&-0.106-0.075+0.072\\
={}&-0.6265.
\end{aligned}
\]
Hasil perhitungan dari nilai masukan dua desimal adalah \(-0.6265\). Pada matriks ilustrasi
sebelumnya, elemen ini tercatat sebesar \(-0.62\). Nilai pada matriks dipertahankan
sementara hingga validasi numerik menyeluruh dilakukan.
Prosedur yang sama diterapkan pada seluruh posisi kernel. Pada setiap
posisi, elemen-elemen dalam area konvolusi dikalikan dengan bobot kernel
yang bersesuaian, kemudian seluruh hasil perkalian dijumlahkan untuk
membentuk satu elemen feature map keluaran.
Matriks hasil depthwise convolution yang digunakan sementara
dalam ilustrasi ini adalah:
\[
\mathbf{F}_{\mathrm{dw}}
=
\begin{bmatrix}
-1.20 & -0.61 & 0.58 & 0.30 & -0.66\\
-1.43 & -0.62 & 0.84 & 0.49 & -0.71\\
-1.43 & -0.61 & 0.85 & 0.49 & -0.71\\
-1.45 & -0.77 & 0.55 & 0.21 & -0.84\\
-1.18 & -0.82 & 0.09 & -0.17 & -0.83
\end{bmatrix}.
\]
Matriks tersebut mempertahankan nilai pada ilustrasi sebelumnya dan
akan diperiksa kembali melalui perhitungan numerik untuk memastikan
konsistensi seluruh tahapan.
Keluaran depthwise convolution selanjutnya diproses
menggunakan fungsi aktivasi Swish untuk membentuk feature map
lokal \(\mathbf{L}\).
Fungsi aktivasi Swish diterapkan secara elemen demi elemen pada
matriks hasil depthwise convolution:
\[
\begin{aligned}
L_{i,j}
&=
\operatorname{Swish}
\left(
F_{\mathrm{dw},i,j}
\right)\\
&=
\frac{F_{\mathrm{dw},i,j}}
{1+e^{-F_{\mathrm{dw},i,j}}}.
\end{aligned}
\]
- Contoh Perhitungan pada Posisi \((1,1)\):
Untuk elemen pada posisi \((1,1)\),
nilai yang digunakan sesuai dengan matriks hasil depthwise
convolution, yaitu \(-1.20\).
\[
\begin{aligned}
L_{1,1}
&=
\operatorname{Swish}(-1.20)\\
&=
\frac{-1.20}{1+e^{-(-1.20)}}\\
&=
\frac{-1.20}{1+e^{1.20}}\\
&=
\frac{-1.20}{1+3.32}\\
&=-0.28.
\end{aligned}
\]
Dengan menerapkan fungsi aktivasi Swish pada seluruh elemen matriks
hasil depthwise convolution, diperoleh feature map
lokal:
\[
\mathbf{L}
=
\begin{bmatrix}
-0.28 & -0.22 & 0.37 & 0.17 & -0.23\\
-0.28 & -0.22 & 0.59 & 0.31 & -0.23\\
-0.28 & -0.22 & 0.59 & 0.31 & -0.23\\
-0.28 & -0.24 & 0.35 & 0.12 & -0.25\\
-0.28 & -0.25 & 0.05 & -0.08 & -0.25
\end{bmatrix}.
\]
Matriks \(\mathbf{L}\) merupakan
representasi lokal setelah penerapan fungsi aktivasi Swish dan digunakan
sebagai masukan pada tahap berikutnya. Nilai matriks tersebut
dipertahankan sesuai ilustrasi sebelumnya hingga dilakukan validasi
numerik secara menyeluruh.
b. Pointwise Convolution dan Tokenisasi
Feature map lokal \(\mathbf{L}\) memiliki satu kanal dengan
dimensi \(5\times5\times1\).
Selanjutnya, pointwise convolution \(1\times1\) diterapkan secara independen
pada setiap posisi spasial. Operasi ini tidak melibatkan piksel
tetangga, tetapi memproyeksikan satu kanal masukan menjadi dua kanal
keluaran yang membentuk vektor token.
- Bobot pointwise convolution:
\[
\mathbf{W}_{\mathrm{pw}}^{(\mathrm{tok})}
=
\begin{bmatrix}
0.80 & -0.60
\end{bmatrix}.
\]
Bobot \(\mathbf{W}_{\mathrm{pw}}^{(\mathrm{tok})}\)
berdimensi \(1\times2\). Oleh karena
itu, setiap nilai feature map lokal diproyeksikan menjadi
vektor dengan dua elemen.
Untuk setiap posisi spasial \((i,j)\), token ke-\(t\) dirumuskan sebagai:
\[
T_{t,n}
=
\sum_{m=1}^{C_L}
W_{\mathrm{pw},m,n}^{(\mathrm{tok})}
L_{i,j,m},
\qquad
t=5(i-1)+j.
\]
Pada ilustrasi ini, \(C_L=1\) dan
\(n=1,2\). Oleh karena itu, perhitungan
token dapat disederhanakan menjadi:
\[
\mathbf{T}_t
=
L_{i,j}
\mathbf{W}_{\mathrm{pw}}^{(\mathrm{tok})}.
\]
Matriks token \(\mathbf{T}\)
berdimensi \(25\times2\).
- Contoh perhitungan pada posisi \((1,1)\):
\[
\begin{aligned}
\mathbf{T}_1
&=
L_{1,1}
\mathbf{W}_{\mathrm{pw}}^{(\mathrm{tok})}\\
&=
(-0.28)
\begin{bmatrix}
0.80 & -0.60
\end{bmatrix}\\
&=
\begin{bmatrix}
-0.22 & 0.17
\end{bmatrix}.
\end{aligned}
\]
Posisi spasial \((1,1)\) merupakan
token pertama karena:
\[
t=5(1-1)+1=1.
\]
Dengan perhitungan yang sama pada seluruh posisi berdasarkan urutan
raster dari kiri ke kanan dan dari atas ke bawah, diperoleh matriks
token:
\[
\mathbf{T}
=
\begin{bmatrix}
-0.22 & 0.17\\
-0.17 & 0.13\\
0.30 & -0.22\\
0.14 & -0.10\\
-0.18 & 0.14\\
-0.22 & 0.17\\
-0.17 & 0.13\\
0.47 & -0.35\\
0.24 & -0.18\\
-0.19 & 0.14\\
-0.22 & 0.17\\
-0.17 & 0.13\\
0.48 & -0.36\\
0.24 & -0.18\\
-0.19 & 0.14\\
-0.22 & 0.17\\
-0.19 & 0.15\\
0.28 & -0.21\\
0.09 & -0.07\\
-0.20 & 0.15\\
-0.22 & 0.17\\
-0.20 & 0.15\\
0.04 & -0.03\\
-0.06 & 0.05\\
-0.20 & 0.15
\end{bmatrix}.
\]
3. Linear Transformer (Separable Self-Attention)
Pada MobileViTv3-v2, matriks token \(\mathbf{T}\) diproses menggunakan mekanisme
separable self-attention (SSA). Berbeda dengan Transformer v1
yang menghitung hubungan perhatian antarsetiap pasangan token, SSA
membentuk vektor koefisien konteks untuk merangkum informasi global dari
seluruh token. Keluaran SSA kemudian digabungkan dengan token masukan
melalui residual connection dan diproses oleh feed-forward
network.
Pada formulasi SSA di Bab II, \(\mathbf{X}\) menyatakan matriks token
masukan secara umum. Dalam ilustrasi perhitungan ini, matriks tersebut
direalisasikan oleh \(\mathbf{T}\),
sehingga:
\[
\mathbf{X}
=
\mathbf{T}.
\]
a. Proyeksi Attention Score
Setiap token pada \(\mathbf{T}\)
diproyeksikan menjadi satu nilai attention score menggunakan
matriks bobot \(\mathbf{W}^{I}\). Nilai
attention score sebelum proses softmax dinyatakan sebagai
vektor \(\mathbf{s}\).
- Bobot proyeksi attention score:
\[
\mathbf{W}^{I}
=
\begin{bmatrix}
0.60\\
-0.35
\end{bmatrix}.
\]
Matriks \(\mathbf{W}^{I}\) berukuran
\(2\times1\). Oleh karena itu, vektor
attention score \(\mathbf{s}\)
berukuran \(25\times1\).
\[
\mathbf{s}
=
\mathbf{T}\mathbf{W}^{I}.
\]
Secara elemen, attention score token ke-\(t\) dihitung sebagai:
\[
s_t
=
\sum_{n=1}^{2}
T_{t,n}W_{n,1}^{I}.
\]
- Contoh perhitungan token pertama:
\[
\begin{aligned}
s_1
&=
\begin{bmatrix}
-0.22 & 0.17
\end{bmatrix}
\begin{bmatrix}
0.60\\
-0.35
\end{bmatrix}\\
&=
0.60(-0.22)-0.35(0.17)\\
&=
-0.132-0.0595\\
&=
-0.19.
\end{aligned}
\]
Dengan aturan yang sama, diperoleh vektor attention score
sebagai berikut.
\[
\mathbf{s}
=
\begin{bmatrix}
-0.19\\
-0.15\\
0.26\\
0.12\\
-0.16\\
-0.19\\
-0.15\\
0.40\\
0.21\\
-0.16\\
-0.19\\
-0.15\\
0.41\\
0.21\\
-0.16\\
-0.19\\
-0.17\\
0.24\\
0.08\\
-0.17\\
-0.19\\
-0.17\\
0.03\\
-0.05\\
-0.17
\end{bmatrix}.
\]
b. Koefisien konteks
Nilai attention score kemudian dinormalisasi menggunakan softmax
untuk menghasilkan koefisien konteks \(c_s\). Jumlah seluruh koefisien konteks
bernilai satu. Nilai attention score \(q\) dinormalisasi menggunakan fungsi
softmax untuk menghasilkan koefisien konteks \(c_s\). Notasi \(e^{q_t}\) menyatakan nilai eksponensial
dari attention score token yang sedang dihitung, yaitu token ke-\(t\). Sementara itu, \(\sum_{r=1}^{25}e^{q_r}\) menyatakan jumlah
nilai eksponensial dari seluruh 25 token. Dengan demikian, setiap nilai
\(c_{s,t}\) menunjukkan proporsi
kontribusi token ke-\(t\) terhadap
pembentukan vektor konteks global, dan jumlah seluruh koefisien konteks
bernilai satu.
\[
c_{s,t}
=
\frac{e^{q_t}}
{\sum_{r=1}^{25}e^{q_r}}.
\]
Untuk menghitung koefisien konteks token pertama, nilai eksponensial
attention score token pertama dibagi dengan jumlah nilai
eksponensial dari seluruh 25 token sebagai berikut.
\[
\begin{aligned}
c_{s,1}
&=
\frac{e^{-0.1916}}
{e^{-0.1916}+e^{-0.1485}+\cdots+e^{-0.1738}}\\
&=
\frac{0.8256}
{0.8256+0.8620+\cdots+0.8405}\\
&=
\frac{0.8256}{24.8734}\\
&=
0.0332\\
&=
0.03.
\end{aligned}
\]
Dengan aturan yang sama, diperoleh koefisien konteks sebagai
berikut.
\[
c_s=
\begin{bmatrix}
0.03\\
0.03\\
0.05\\
0.05\\
0.03\\
0.03\\
0.03\\
0.07\\
0.05\\
0.03\\
0.03\\
0.03\\
0.07\\
0.05\\
0.03\\
0.03\\
0.03\\
0.06\\
0.04\\
0.03\\
0.03\\
0.03\\
0.04\\
0.04\\
0.03
\end{bmatrix}.
\]
c. Proyeksi Key
Pada formulasi separable self-attention, matriks
key dibentuk dari matriks token masukan menggunakan bobot \(\mathbf{W}^{K}\). Dalam ilustrasi ini,
matriks token \(\mathbf{T}\)
merealisasikan \(\mathbf{X}\) pada
Persamaan (2.21).
\[
\mathbf{W}^{K}
=
\begin{bmatrix}
0.55 & 0.10\\
-0.15 & 0.45
\end{bmatrix}.
\]
Matriks \(\mathbf{W}^{K}\) berukuran
\(2\times2\).
\[
\mathbf{K}
=
\mathbf{T}\mathbf{W}^{K}.
\]
Matriks key \(\mathbf{K}\)
berukuran \(25\times2\).
Secara elemen, komponen key ke-\(n\) pada token ke-\(t\) dihitung sebagai:
\[
K_{t,n}
=
\sum_{m=1}^{2}
T_{t,m}W_{m,n}^{K}.
\]
- Contoh perhitungan token pertama:
\[
\begin{aligned}
\mathbf{K}_1
&=
\begin{bmatrix}
-0.22 & 0.17
\end{bmatrix}
\begin{bmatrix}
0.55 & 0.10\\
-0.15 & 0.45
\end{bmatrix}\\
&=
\begin{bmatrix}
(-0.22)(0.55)+(0.17)(-0.15) &
(-0.22)(0.10)+(0.17)(0.45)
\end{bmatrix}\\
&=
\begin{bmatrix}
-0.1465 & 0.0545
\end{bmatrix}\\
&=
\begin{bmatrix}
-0.15 & 0.05
\end{bmatrix}.
\end{aligned}
\]
Dengan aturan yang sama, diperoleh matriks key sebagai
berikut.
\[
\mathbf{K}
=
\begin{bmatrix}
-0.15 & 0.05\\
-0.11 & 0.04\\
0.20 & -0.07\\
0.09 & -0.03\\
-0.12 & 0.04\\
-0.15 & 0.05\\
-0.12 & 0.04\\
0.31 & -0.11\\
0.16 & -0.06\\
-0.12 & 0.04\\
-0.15 & 0.05\\
-0.11 & 0.04\\
0.31 & -0.11\\
0.16 & -0.06\\
-0.12 & 0.04\\
-0.15 & 0.05\\
-0.13 & 0.05\\
0.19 & -0.07\\
0.06 & -0.02\\
-0.13 & 0.05\\
-0.15 & 0.05\\
-0.13 & 0.05\\
0.03 & -0.01\\
-0.04 & 0.02\\
-0.13 & 0.05
\end{bmatrix}.
\]
d. Proyeksi Value
Pada formulasi separable self-attention, matriks
value dibentuk dari matriks token masukan menggunakan bobot
proyeksi \(\mathbf{W}^{V}\). Dalam
ilustrasi ini, matriks token \(\mathbf{T}\) merealisasikan \(\mathbf{X}\) pada Persamaan (2.22).
\[
\mathbf{W}^{V}
=
\begin{bmatrix}
0.70 & -0.20\\
0.25 & 0.60
\end{bmatrix}.
\]
Matriks \(\mathbf{W}^{V}\) berukuran
\(2\times2\). Karena matriks \(\mathbf{T}\) berukuran \(25\times2\), maka matriks value
\(\mathbf{V}\) berukuran \(25\times2\).
\[
\mathbf{V}
=
\mathbf{T}\mathbf{W}^{V}.
\]
Secara elemen, komponen value ke-\(n\) pada token ke-\(t\) dihitung sebagai:
\[
V_{t,n}
=
\sum_{m=1}^{2}
T_{t,m}W_{m,n}^{V}.
\]
- Contoh perhitungan token pertama:
\[
\begin{aligned}
\mathbf{V}_1
&=
\begin{bmatrix}
-0.22 & 0.17
\end{bmatrix}
\begin{bmatrix}
0.70 & -0.20\\
0.25 & 0.60
\end{bmatrix}\\
&=
\begin{bmatrix}
(-0.22)(0.70)+(0.17)(0.25)
&
(-0.22)(-0.20)+(0.17)(0.60)
\end{bmatrix}\\
&=
\begin{bmatrix}
-0.1115 & 0.1460
\end{bmatrix}\\
&=
\begin{bmatrix}
-0.11 & 0.15
\end{bmatrix}.
\end{aligned}
\]
Pada tahap keluaran SSA, matriks \(\mathbf{V}\) selanjutnya diproses
menggunakan fungsi ReLU sesuai Persamaan (2.22).
Dengan aturan yang sama, diperoleh matriks value sebagai
berikut.
\[
\mathbf{V}
=
\begin{bmatrix}
-0.11 & 0.14\\
-0.09 & 0.11\\
0.15 & -0.19\\
0.07 & -0.09\\
-0.09 & 0.12\\
-0.11 & 0.14\\
-0.09 & 0.11\\
0.24 & -0.31\\
0.13 & -0.16\\
-0.10 & 0.12\\
-0.11 & 0.14\\
-0.09 & 0.11\\
0.24 & -0.31\\
0.13 & -0.16\\
-0.10 & 0.12\\
-0.11 & 0.14\\
-0.10 & 0.13\\
0.14 & -0.18\\
0.05 & -0.06\\
-0.10 & 0.13\\
-0.11 & 0.14\\
-0.10 & 0.13\\
0.02 & -0.03\\
-0.03 & 0.04\\
-0.10 & 0.13
\end{bmatrix}.
\]
e. Pembentukan vektor konteks
Vektor konteks \(\mathbf{c}_v\)
diperoleh dengan menggabungkan seluruh baris matriks key \(\mathbf{K}\) menggunakan koefisien konteks
pada vektor \(\mathbf{c}_s\). Setiap
token key diberi bobot sesuai nilai koefisien konteksnya. Token dengan
nilai \(c_{s,t}\) yang lebih besar
memberikan kontribusi yang lebih besar terhadap pembentukan vektor
konteks global.
\[
\mathbf{c}_v
=
\mathbf{c}_s^{\mathsf{T}}\mathbf{K}
=
\sum_{t=1}^{25}c_{s,t}\mathbf{K}_{t,:}.
\]
Karena \(\mathbf{c}_s^{\mathsf{T}}\)
berukuran \(1\times25\) dan \(\mathbf{K}\) berukuran \(25\times2\), maka vektor konteks \(\mathbf{c}_v\) berukuran \(1\times2\).
\[
(1\times25)(25\times2)=(1\times2).
\]
Untuk setiap elemen ke-\(n\),
perhitungannya adalah:
\[
c_{v,n}
=
\sum_{t=1}^{25}c_{s,t}K_{t,n},
\qquad n=1,2.
\]
- Perhitungan elemen pertama:
\[
\begin{aligned}
c_{v,1}
&=
c_{s,1}K_{1,1}
+c_{s,2}K_{2,1}
+\cdots
+c_{s,25}K_{25,1}\\
&=
(0.03)(-0.15)
+(0.03)(-0.11)
+\cdots
+(0.03)(-0.13)\\
&=0.01.
\end{aligned}
\]
- Perhitungan elemen kedua:
\[
\begin{aligned}
c_{v,2}
&=
c_{s,1}K_{1,2}
+c_{s,2}K_{2,2}
+\cdots
+c_{s,25}K_{25,2}\\
&=
(0.03)(0.05)
+(0.03)(0.04)
+\cdots
+(0.03)(0.05)\\
&=-0.005.
\end{aligned}
\]
Perhitungan dilakukan menggunakan nilai \(\mathbf{c}_s\) dan \(\mathbf{K}\) dengan presisi penuh sebelum
hasil akhir ditampilkan. Nilai ditampilkan hingga dua angka di belakang
koma, kecuali elemen kedua yang ditampilkan hingga tiga angka di
belakang koma agar tidak menjadi \(-0.00\). Oleh karena itu, diperoleh vektor
konteks:
\[
\mathbf{c}_v=
\begin{bmatrix}
0.01 & -0.005
\end{bmatrix}.
\]
f. Keluaran separable self-attention
Keluaran separable self-attention dibentuk dengan menerapkan
fungsi ReLU pada setiap elemen matriks value \(\mathbf{V}\). Fungsi ReLU mempertahankan
nilai positif dan mengubah nilai negatif menjadi nol. Hasil aktivasi
tersebut kemudian dikalikan secara elemen demi elemen dengan vektor
konteks global \(\mathbf{c}_v\), lalu
diproyeksikan menggunakan bobot keluaran \(\mathbf{W}^{O}\).
Pada ilustrasi ini, vektor konteks global sebelum pembulatan
adalah:
\[
\mathbf{c}_v=
\begin{bmatrix}
0.0132 & -0.0047
\end{bmatrix}.
\]
\[
\mathbf{W}^{O}=
\begin{bmatrix}
50.00 & -20.00\\
50.00 & 50.00
\end{bmatrix}.
\]
Bobot \(\mathbf{W}^{O}\) merupakan
bobot ilustratif yang digunakan untuk memproyeksikan hasil separable
self-attention. Nilai tersebut dipilih agar keluaran tetap dapat
ditampilkan secara jelas setelah pembulatan.
Sesuai Persamaan (2.22) pada draft, keluaran separable
self-attention dirumuskan sebagai:
\[
\mathbf{Z}_{\mathrm{SSA}}
=
\left(
\mathbf{c}_v
\odot
\operatorname{ReLU}(\mathbf{V})
\right)
\mathbf{W}^{O}.
\]
Vektor \(\mathbf{c}_v\) berukuran
\(1\times2\) diterapkan pada setiap
baris matriks \(\operatorname{ReLU}(\mathbf{V})\) yang
berukuran \(25\times2\). Oleh karena
itu, hasil perkalian elemen demi elemen berukuran \(25\times2\). Setelah dikalikan dengan \(\mathbf{W}^{O}\) yang berukuran \(2\times2\), diperoleh matriks \(\mathbf{Z}_{\mathrm{SSA}}\) berukuran \(25\times2\).
\[
\operatorname{ReLU}(V_{t,n})
=
\max(0,V_{t,n}).
\]
- Contoh perhitungan token pertama:
\[
\begin{aligned}
\mathbf{Z}_{\mathrm{SSA},1}
&=
\left(
\mathbf{c}_v
\odot
\operatorname{ReLU}(\mathbf{V}_{1})
\right)
\mathbf{W}^{O}\\
&=
\left(
\begin{bmatrix}
0.0132 & -0.0047
\end{bmatrix}
\odot
\operatorname{ReLU}
\begin{bmatrix}
-0.11 & 0.14
\end{bmatrix}
\right)
\begin{bmatrix}
50.00 & -20.00\\
50.00 & 50.00
\end{bmatrix}\\
&=
\left(
\begin{bmatrix}
0.0132 & -0.0047
\end{bmatrix}
\odot
\begin{bmatrix}
0.00 & 0.14
\end{bmatrix}
\right)
\begin{bmatrix}
50.00 & -20.00\\
50.00 & 50.00
\end{bmatrix}\\
&=
\begin{bmatrix}
0.00 & -0.0007
\end{bmatrix}
\begin{bmatrix}
50.00 & -20.00\\
50.00 & 50.00
\end{bmatrix}\\
&=
\begin{bmatrix}
-0.03 & -0.03
\end{bmatrix}.
\end{aligned}
\]
Dengan aturan yang sama, diperoleh keluaran separable
self-attention sebagai berikut.
\[
\mathbf{Z}_{\mathrm{SSA}}=
\begin{bmatrix}
-0.03 & -0.03\\
-0.03 & -0.03\\
0.10 & -0.04\\
0.05 & -0.02\\
-0.03 & -0.03\\
-0.03 & -0.03\\
-0.03 & -0.03\\
0.16 & -0.06\\
0.08 & -0.03\\
-0.03 & -0.03\\
-0.03 & -0.03\\
-0.03 & -0.03\\
0.16 & -0.06\\
0.08 & -0.03\\
-0.03 & -0.03\\
-0.03 & -0.03\\
-0.03 & -0.03\\
0.10 & -0.04\\
0.03 & -0.01\\
-0.03 & -0.03\\
-0.03 & -0.03\\
-0.03 & -0.03\\
0.01 & -0.005\\
-0.01 & -0.01\\
-0.03 & -0.03
\end{bmatrix}.
\]
Nilai dihitung menggunakan presisi penuh sebelum ditampilkan. Hasil
ditulis hingga dua angka di belakang koma, kecuali nilai \(-0.005\) agar tidak ditampilkan sebagai
\(-0.00\).
g. Residual separable self-attention
Keluaran separable self-attention \(\mathbf{Z}_{\mathrm{SSA}}\) selanjutnya
digabungkan dengan matriks token masukan \(\mathbf{T}\) melalui residual
connection. Proses ini mempertahankan informasi awal setiap token
sekaligus menambahkan informasi konteks global yang diperoleh dari
SSA.
\[
\mathbf{Z}'
=
\mathbf{T}
+
\mathbf{Z}_{\mathrm{SSA}}.
\]
Matriks \(\mathbf{T}\) dan \(\mathbf{Z}_{\mathrm{SSA}}\) masing-masing
berukuran \(25\times2\). Oleh karena
itu, matriks hasil residual \(\mathbf{Z}'\) juga berukuran \(25\times2\).
- Contoh perhitungan token pertama:
Perhitungan dilakukan menggunakan nilai presisi penuh sebelum hasil
akhir ditampilkan. Untuk token pertama, diperoleh:
\[
\begin{aligned}
\mathbf{Z}'_{1}
&=
\mathbf{T}_{1}
+
\mathbf{Z}_{\mathrm{SSA},1}\\
&=
\begin{bmatrix}
-0.2222 & 0.1666
\end{bmatrix}
+
\begin{bmatrix}
-0.0342 & -0.0342
\end{bmatrix}\\
&=
\begin{bmatrix}
-0.2564 & 0.1324
\end{bmatrix}\\
&=
\begin{bmatrix}
-0.26 & 0.13
\end{bmatrix}.
\end{aligned}
\]
- Contoh perhitungan token ketiga:
\[
\begin{aligned}
\mathbf{Z}'_{3}
&=
\mathbf{T}_{3}
+
\mathbf{Z}_{\mathrm{SSA},3}\\
&=
\begin{bmatrix}
0.30 & -0.22
\end{bmatrix}
+
\begin{bmatrix}
0.10 & -0.04
\end{bmatrix}\\
&=
\begin{bmatrix}
0.40 & -0.26
\end{bmatrix}.
\end{aligned}
\]
Dengan aturan yang sama, diperoleh matriks hasil residual
separable self-attention sebagai berikut.
\[
\mathbf{Z}'=
\begin{bmatrix}
-0.26 & 0.13\\
-0.20 & 0.10\\
0.40 & -0.26\\
0.18 & -0.12\\
-0.21 & 0.11\\
-0.25 & 0.13\\
-0.20 & 0.10\\
0.63 & -0.42\\
0.33 & -0.22\\
-0.22 & 0.11\\
-0.26 & 0.13\\
-0.20 & 0.10\\
0.64 & -0.42\\
0.33 & -0.22\\
-0.22 & 0.11\\
-0.25 & 0.13\\
-0.22 & 0.12\\
0.38 & -0.25\\
0.12 & -0.08\\
-0.23 & 0.12\\
-0.26 & 0.13\\
-0.23 & 0.12\\
0.05 & -0.035\\
-0.07 & 0.04\\
-0.23 & 0.12
\end{bmatrix}.
\]
h. Normalisasi residual separable self-attention
Matriks hasil residual separable self-attention \(\mathbf{Z}'\) dinormalisasi per token
menggunakan layer normalization. Normalisasi dilakukan pada dua
elemen fitur dalam setiap token secara terpisah, bukan pada seluruh
matriks sekaligus. Tahap ini menghasilkan \(\operatorname{LN}(\mathbf{Z}')\)
sebagai masukan untuk MLP.
- Rumus rata-rata token ke-\(t\):
\[
\mu_{Z',t}
=
\frac{1}{2}
\sum_{n=1}^{2}Z'_{t,n}.
\]
- Rumus varians token ke-\(t\):
\[
\sigma_{Z',t}^{2}
=
\frac{1}{2}
\sum_{n=1}^{2}
\left(
Z'_{t,n}-\mu_{Z',t}
\right)^2.
\]
\[
\left[
\operatorname{LN}(\mathbf{Z}')
\right]_{t,n}
=
\frac{
Z'_{t,n}-\mu_{Z',t}
}{
\sqrt{
\sigma_{Z',t}^{2}+10^{-5}
}
}.
\]
Matriks \(\operatorname{LN}(\mathbf{Z}')\)
berukuran \(25\times2\).
- Contoh perhitungan token pertama:
Nilai token pertama sebelum pembulatan adalah:
\[
\mathbf{Z}'_{1}=
\begin{bmatrix}
-0.2564 & 0.1324
\end{bmatrix}.
\]
Rata-rata token pertama adalah:
\[
\begin{aligned}
\mu_{Z',1}
&=
\frac{-0.2564+0.1324}{2}\\
&=
-0.0620.
\end{aligned}
\]
Varians token pertama adalah:
\[
\begin{aligned}
\sigma_{Z',1}^{2}
&=
\frac{
(-0.2564-(-0.0620))^2
+
(0.1324-(-0.0620))^2
}{2}\\
&=
\frac{(-0.1944)^2+(0.1944)^2}{2}\\
&=
0.0378.
\end{aligned}
\]
Maka:
\[
\begin{aligned}
\operatorname{LN}(\mathbf{Z}'_{1})
&=
\begin{bmatrix}
\dfrac{-0.2564-(-0.0620)}
{\sqrt{0.0378+10^{-5}}}
&
\dfrac{0.1324-(-0.0620)}
{\sqrt{0.0378+10^{-5}}}
\end{bmatrix}\\
&=
\begin{bmatrix}
-1.00 & 1.00
\end{bmatrix}.
\end{aligned}
\]
Dengan aturan yang sama, diperoleh matriks hasil normalisasi residual
separable self-attention sebagai berikut.
\[
\operatorname{LN}(\mathbf{Z}')=
\begin{bmatrix}
-1.00 & 1.00\\
-1.00 & 1.00\\
1.00 & -1.00\\
1.00 & -1.00\\
-1.00 & 1.00\\
-1.00 & 1.00\\
-1.00 & 1.00\\
1.00 & -1.00\\
1.00 & -1.00\\
-1.00 & 1.00\\
-1.00 & 1.00\\
-1.00 & 1.00\\
1.00 & -1.00\\
1.00 & -1.00\\
-1.00 & 1.00\\
-1.00 & 1.00\\
-1.00 & 1.00\\
1.00 & -1.00\\
1.00 & -1.00\\
-1.00 & 1.00\\
-1.00 & 1.00\\
-1.00 & 1.00\\
1.00 & -1.00\\
-1.00 & 1.00\\
-1.00 & 1.00
\end{bmatrix}.
\]
i. Lapisan pertama MLP (feed-forward network)
Lapisan pertama MLP menerima token hasil normalisasi residual
separable self-attention, yaitu \(\operatorname{LN}(\mathbf{Z}')\).
Lapisan ini memproyeksikan setiap token dari dua elemen fitur menjadi
tiga elemen fitur, kemudian menerapkan fungsi aktivasi ReLU. Proses
tersebut sesuai dengan tahap pertama MLP pada Persamaan (2.17) di Bab
II.
Pada ilustrasi ini, vektor bias lapisan pertama diabaikan atau
ditetapkan sebagai \(\mathbf{b}_1=\mathbf{0}\).
\[
\mathbf{W}_1=
\begin{bmatrix}
0.45 & -0.35 & 0.25\\
-0.20 & 0.55 & 0.30
\end{bmatrix}.
\]
Matriks \(\mathbf{W}_1\) berukuran
\(2\times3\).
\[
\operatorname{ReLU}
\left(
\operatorname{LN}(\mathbf{Z}')
\mathbf{W}_1
\right).
\]
Matriks \(\operatorname{LN}(\mathbf{Z}')\)
berukuran \(25\times2\). Oleh karena
itu, hasil lapisan pertama MLP berukuran \(25\times3\).
- Contoh perhitungan token pertama:
\[
\begin{aligned}
\operatorname{ReLU}
\left(
\operatorname{LN}(\mathbf{Z}'_1)
\mathbf{W}_1
\right)
&=
\operatorname{ReLU}
\left(
\begin{bmatrix}
-1.00 & 1.00
\end{bmatrix}
\begin{bmatrix}
0.45 & -0.35 & 0.25\\
-0.20 & 0.55 & 0.30
\end{bmatrix}
\right)\\
&=
\operatorname{ReLU}
\left(
\begin{bmatrix}
-0.65 & 0.90 & 0.05
\end{bmatrix}
\right)\\
&=
\begin{bmatrix}
0.00 & 0.90 & 0.05
\end{bmatrix}.
\end{aligned}
\]
- Contoh perhitungan token ketiga:
\[
\begin{aligned}
\operatorname{ReLU}
\left(
\operatorname{LN}(\mathbf{Z}'_3)
\mathbf{W}_1
\right)
&=
\operatorname{ReLU}
\left(
\begin{bmatrix}
1.00 & -1.00
\end{bmatrix}
\begin{bmatrix}
0.45 & -0.35 & 0.25\\
-0.20 & 0.55 & 0.30
\end{bmatrix}
\right)\\
&=
\operatorname{ReLU}
\left(
\begin{bmatrix}
0.65 & -0.90 & -0.05
\end{bmatrix}
\right)\\
&=
\begin{bmatrix}
0.65 & 0.00 & 0.00
\end{bmatrix}.
\end{aligned}
\]
Dengan aturan yang sama, diperoleh hasil lapisan pertama MLP sebagai
berikut.
\[
\operatorname{ReLU}
\left(
\operatorname{LN}(\mathbf{Z}')
\mathbf{W}_1
\right)
=
\begin{bmatrix}
0.00 & 0.90 & 0.05\\
0.00 & 0.90 & 0.05\\
0.65 & 0.00 & 0.00\\
0.65 & 0.00 & 0.00\\
0.00 & 0.90 & 0.05\\
0.00 & 0.90 & 0.05\\
0.00 & 0.90 & 0.05\\
0.65 & 0.00 & 0.00\\
0.65 & 0.00 & 0.00\\
0.00 & 0.90 & 0.05\\
0.00 & 0.90 & 0.05\\
0.00 & 0.90 & 0.05\\
0.65 & 0.00 & 0.00\\
0.65 & 0.00 & 0.00\\
0.00 & 0.90 & 0.05\\
0.00 & 0.90 & 0.05\\
0.00 & 0.90 & 0.05\\
0.65 & 0.00 & 0.00\\
0.65 & 0.00 & 0.00\\
0.00 & 0.90 & 0.05\\
0.00 & 0.90 & 0.05\\
0.00 & 0.90 & 0.05\\
0.65 & 0.00 & 0.00\\
0.00 & 0.90 & 0.05\\
0.00 & 0.90 & 0.05
\end{bmatrix}.
\]
j. Lapisan kedua MLP (feed-forward network)
Lapisan kedua MLP memproyeksikan tiga elemen fitur hasil lapisan
pertama kembali menjadi dua elemen fitur. Pada tahap ini, keluaran
proyeksi linear tidak diberi fungsi aktivasi tambahan. Proses ini sesuai
dengan bagian kedua MLP pada Persamaan (2.17) di Bab II.
Pada ilustrasi ini, vektor bias lapisan kedua diabaikan atau
ditetapkan sebagai \(\mathbf{b}_2=\mathbf{0}\).
\[
\mathbf{W}_2=
\begin{bmatrix}
0.35 & -0.25\\
0.15 & 0.45\\
-0.20 & 0.30
\end{bmatrix}.
\]
Matriks \(\mathbf{W}_2\) berukuran
\(3\times2\).
\[
\operatorname{ReLU}
\left(
\operatorname{LN}(\mathbf{Z}')
\mathbf{W}_1
\right)
\mathbf{W}_2.
\]
Hasil lapisan pertama MLP berukuran \(25\times3\). Oleh karena itu, keluaran
lapisan kedua MLP berukuran \(25\times2\).
- Contoh perhitungan token pertama:
\[
\begin{aligned}
&
\operatorname{ReLU}
\left(
\operatorname{LN}(\mathbf{Z}'_1)
\mathbf{W}_1
\right)
\mathbf{W}_2\\
&=
\begin{bmatrix}
0.00 & 0.90 & 0.05
\end{bmatrix}
\begin{bmatrix}
0.35 & -0.25\\
0.15 & 0.45\\
-0.20 & 0.30
\end{bmatrix}\\
&=
\begin{bmatrix}
(0.00)(0.35)+(0.90)(0.15)+(0.05)(-0.20)
&
(0.00)(-0.25)+(0.90)(0.45)+(0.05)(0.30)
\end{bmatrix}\\
&=
\begin{bmatrix}
0.125 & 0.420
\end{bmatrix}\\
&=
\begin{bmatrix}
0.13 & 0.42
\end{bmatrix}.
\end{aligned}
\]
- Contoh perhitungan token ketiga:
\[
\begin{aligned}
&
\operatorname{ReLU}
\left(
\operatorname{LN}(\mathbf{Z}'_3)
\mathbf{W}_1
\right)
\mathbf{W}_2\\
&=
\begin{bmatrix}
0.65 & 0.00 & 0.00
\end{bmatrix}
\begin{bmatrix}
0.35 & -0.25\\
0.15 & 0.45\\
-0.20 & 0.30
\end{bmatrix}\\
&=
\begin{bmatrix}
0.23 & -0.16
\end{bmatrix}.
\end{aligned}
\]
Dengan aturan yang sama, diperoleh keluaran lapisan kedua MLP sebagai
berikut.
\[
\operatorname{ReLU}
\left(
\operatorname{LN}(\mathbf{Z}')
\mathbf{W}_1
\right)
\mathbf{W}_2
=
\begin{bmatrix}
0.13 & 0.42\\
0.13 & 0.42\\
0.23 & -0.16\\
0.23 & -0.16\\
0.13 & 0.42\\
0.13 & 0.42\\
0.13 & 0.42\\
0.23 & -0.16\\
0.23 & -0.16\\
0.13 & 0.42\\
0.13 & 0.42\\
0.13 & 0.42\\
0.23 & -0.16\\
0.23 & -0.16\\
0.13 & 0.42\\
0.13 & 0.42\\
0.13 & 0.42\\
0.23 & -0.16\\
0.23 & -0.16\\
0.13 & 0.42\\
0.13 & 0.42\\
0.13 & 0.42\\
0.23 & -0.16\\
0.13 & 0.42\\
0.13 & 0.42
\end{bmatrix}.
\]
k. Residual MLP (feed-forward network)
Keluaran lapisan kedua MLP ditambahkan dengan representasi residual
sebelumnya, yaitu \(\mathbf{Z}'\).
Penjumlahan ini mempertahankan informasi hasil separable
self-attention sekaligus menambahkan transformasi fitur dari MLP.
Keluaran akhir blok linear Transformer dinotasikan sebagai
\(\mathbf{Z}\).
\[
\mathbf{Z}
=
\mathbf{Z}'
+
\operatorname{ReLU}
\left(
\operatorname{LN}(\mathbf{Z}')
\mathbf{W}_1
\right)
\mathbf{W}_2.
\]
Matriks \(\mathbf{Z}'\) dan
keluaran lapisan kedua MLP masing-masing berukuran \(25\times2\). Oleh karena itu, matriks
keluaran \(\mathbf{Z}\) juga berukuran
\(25\times2\).
- Contoh perhitungan token pertama:
\[
\begin{aligned}
\mathbf{Z}_1
&=
\mathbf{Z}'_1+
\operatorname{ReLU}
\left(
\operatorname{LN}(\mathbf{Z}'_1)
\mathbf{W}_1
\right)
\mathbf{W}_2\\
&=
\begin{bmatrix}
-0.26 & 0.13
\end{bmatrix}
+
\begin{bmatrix}
0.13 & 0.42
\end{bmatrix}\\
&=
\begin{bmatrix}
-0.13 & 0.55
\end{bmatrix}.
\end{aligned}
\]
- Contoh perhitungan token ketiga:
\[
\begin{aligned}
\mathbf{Z}_3
&=
\begin{bmatrix}
0.40 & -0.26
\end{bmatrix}
+
\begin{bmatrix}
0.23 & -0.16
\end{bmatrix}\\
&=
\begin{bmatrix}
0.63 & -0.43
\end{bmatrix}.
\end{aligned}
\]
Dengan aturan yang sama, diperoleh keluaran akhir blok linear
Transformer sebagai berikut.
\[
\mathbf{Z}=
\begin{bmatrix}
-0.13 & 0.55\\
-0.07 & 0.52\\
0.63 & -0.43\\
0.41 & -0.28\\
-0.08 & 0.53\\
-0.13 & 0.55\\
-0.08 & 0.52\\
0.86 & -0.58\\
0.55 & -0.38\\
-0.09 & 0.53\\
-0.13 & 0.55\\
-0.07 & 0.52\\
0.86 & -0.58\\
0.55 & -0.38\\
-0.09 & 0.53\\
-0.13 & 0.55\\
-0.10 & 0.54\\
0.60 & -0.41\\
0.35 & -0.25\\
-0.11 & 0.54\\
-0.13 & 0.55\\
-0.11 & 0.54\\
0.28 & -0.19\\
0.05 & 0.46\\
-0.11 & 0.54
\end{bmatrix}.
\]
l. Normalisasi akhir linear Transformer
Tahap terakhir pada ilustrasi linear Transformer adalah
normalisasi per token terhadap matriks keluaran residual MLP \(\mathbf{Z}\). Hasil normalisasi dinotasikan
sebagai \(\mathbf{G}\) dan digunakan
sebagai representasi global sebelum proses folding.
\[
\mathbf{G}
=
\operatorname{LN}(\mathbf{Z}).
\]
Untuk token ke-\(t\), rata-rata dan
varians dihitung sebagai:
\[
\mu_{Z,t}
=
\frac{1}{2}
\sum_{n=1}^{2}Z_{t,n},
\]
\[
\sigma_{Z,t}^{2}
=
\frac{1}{2}
\sum_{n=1}^{2}
\left(
Z_{t,n}-\mu_{Z,t}
\right)^2.
\]
Selanjutnya, elemen hasil normalisasi dirumuskan sebagai:
\[
G_{t,n}
=
\frac{
Z_{t,n}-\mu_{Z,t}
}{
\sqrt{
\sigma_{Z,t}^{2}+10^{-5}
}
}.
\]
Matriks \(\mathbf{G}\) berukuran
\(25\times2\).
- Contoh perhitungan token pertama:
\[
\mathbf{Z}_{1}=
\begin{bmatrix}
-0.13 & 0.55
\end{bmatrix}.
\]
Rata-rata token pertama adalah:
\[
\begin{aligned}
\mu_{Z,1}
&=
\frac{-0.13+0.55}{2}\\
&=
0.21.
\end{aligned}
\]
Varians token pertama adalah:
\[
\begin{aligned}
\sigma_{Z,1}^{2}
&=
\frac{
(-0.13-0.21)^2+
(0.55-0.21)^2
}{2}\\
&=
\frac{(-0.34)^2+(0.34)^2}{2}\\
&=
0.1156.
\end{aligned}
\]
Maka:
\[
\begin{aligned}
\mathbf{G}_{1}
&=
\begin{bmatrix}
\dfrac{-0.13-0.21}
{\sqrt{0.1156+10^{-5}}}
&
\dfrac{0.55-0.21}
{\sqrt{0.1156+10^{-5}}}
\end{bmatrix}\\
&=
\begin{bmatrix}
-1.00 & 1.00
\end{bmatrix}.
\end{aligned}
\]
Dengan aturan yang sama, diperoleh representasi global sebagai
berikut.
\[
\mathbf{G}=
\begin{bmatrix}
-1.00 & 1.00\\
-1.00 & 1.00\\
1.00 & -1.00\\
1.00 & -1.00\\
-1.00 & 1.00\\
-1.00 & 1.00\\
-1.00 & 1.00\\
1.00 & -1.00\\
1.00 & -1.00\\
-1.00 & 1.00\\
-1.00 & 1.00\\
-1.00 & 1.00\\
1.00 & -1.00\\
1.00 & -1.00\\
-1.00 & 1.00\\
-1.00 & 1.00\\
-1.00 & 1.00\\
1.00 & -1.00\\
1.00 & -1.00\\
-1.00 & 1.00\\
-1.00 & 1.00\\
-1.00 & 1.00\\
1.00 & -1.00\\
-1.00 & 1.00\\
-1.00 & 1.00
\end{bmatrix}.
\]
4. Folding, Proyeksi Global, dan Fusi Residual
Keluaran linear Transformer \(\mathbf{G}\) masih berbentuk urutan token
berukuran \(25\times2\). Pada tahap
ini, token dikembalikan ke susunan spasial berukuran \(5\times5\) melalui proses folding.
Selanjutnya, kedua kanal hasil folding diproyeksikan menjadi
satu feature map global. Feature map global tersebut
kemudian digabungkan dengan feature map lokal \(\mathbf{L}\) serta feature map
masukan \(\mathbf{X}\) melalui fusi
residual.
a. Folding keluaran linear Transformer
Matriks \(\mathbf{G}\) memiliki dua
kolom. Kolom pertama dilipat kembali menjadi kanal pertama \(\mathbf{G}_1\), sedangkan kolom kedua
dilipat kembali menjadi kanal kedua \(\mathbf{G}_2\). Posisi token ditentukan
berdasarkan urutan raster dari kiri ke kanan dan dari atas ke bawah.
\[
t=5(i-1)+j,
\qquad
i,j=1,2,\ldots,5,
\]
dengan \(i\) menyatakan indeks
baris, \(j\) menyatakan indeks kolom,
dan \(t\) menyatakan indeks token.
Untuk setiap posisi spasial \((i,j)\),
\[
G_{1,i,j}=G_{t,1},
\qquad
G_{2,i,j}=G_{t,2},
\qquad
t=5(i-1)+j.
\]
Baris pertama pada matriks \(\mathbf{G}\) adalah:
\[
\mathbf{G}_{1}=
\begin{bmatrix}
-1.00 & 1.00
\end{bmatrix}.
\]
Karena token pertama berada pada posisi \((1,1)\), maka:
\[
\begin{aligned}
t
&=5(1-1)+1\\
&=1.
\end{aligned}
\]
Dengan demikian, nilai hasil folding pada posisi \((1,1)\) adalah:
\[
G_{1,1,1}=-1.00,
\qquad
G_{2,1,1}=1.00.
\]
Matriks kanal pertama setelah proses folding adalah:
\[
\mathbf{G}_1=
\begin{bmatrix}
-1.00 & -1.00 & 1.00 & 1.00 & -1.00\\
-1.00 & -1.00 & 1.00 & 1.00 & -1.00\\
-1.00 & -1.00 & 1.00 & 1.00 & -1.00\\
-1.00 & -1.00 & 1.00 & 1.00 & -1.00\\
-1.00 & -1.00 & 1.00 & -1.00 & -1.00
\end{bmatrix}.
\]
Matriks kanal kedua setelah proses folding adalah:
\[
\mathbf{G}_2=
\begin{bmatrix}
1.00 & 1.00 & -1.00 & -1.00 & 1.00\\
1.00 & 1.00 & -1.00 & -1.00 & 1.00\\
1.00 & 1.00 & -1.00 & -1.00 & 1.00\\
1.00 & 1.00 & -1.00 & -1.00 & 1.00\\
1.00 & 1.00 & -1.00 & 1.00 & 1.00
\end{bmatrix}.
\]
Kedua matriks hasil folding, yaitu \(\mathbf{G}_1\) dan \(\mathbf{G}_2\), masing-masing berukuran
\(5\times5\).
b. Proyeksi dan aktivasi feature map global
Dua kanal hasil folding, yaitu \(\mathbf{G}_1\) dan \(\mathbf{G}_2\), diproyeksikan menjadi satu
kanal menggunakan pointwise convolution \(1\times1\) tanpa bias. Hasil proyeksi
kemudian diterapkan fungsi Swish untuk membentuk feature map
global \(\mathbf{G}_{\mathrm{glob}}\).
\[
\mathbf{W}_{\mathrm{glob}}
=
\begin{bmatrix}
0.55 & -0.30
\end{bmatrix}.
\]
Nilai hasil proyeksi sebelum aktivasi dinotasikan sebagai \(F_{\mathrm{glob},i,j}\):
\[
F_{\mathrm{glob},i,j}
=
0.55G_{1,i,j}
-
0.30G_{2,i,j}.
\]
Selanjutnya, fungsi Swish diterapkan sebagai berikut:
\[
\begin{aligned}
G_{\mathrm{glob},i,j}
&=
\operatorname{Swish}
\left(
F_{\mathrm{glob},i,j}
\right)\\
&=
\frac{
F_{\mathrm{glob},i,j}
}{
1+e^{-F_{\mathrm{glob},i,j}}
}.
\end{aligned}
\]
Matriks \(\mathbf{G}_{\mathrm{glob}}\) berukuran
\(5\times5\).
- Contoh perhitungan pada posisi \((1,1)\):
\[
\begin{aligned}
F_{\mathrm{glob},1,1}
&=
0.55G_{1,1,1}
-
0.30G_{2,1,1}\\
&=
0.55(-1.00)
-
0.30(1.00)\\
&=
-0.85.
\end{aligned}
\]
\[
\begin{aligned}
G_{\mathrm{glob},1,1}
&=
\operatorname{Swish}(-0.85)\\
&=
\frac{-0.85}{1+e^{-(-0.85)}}\\
&=
\frac{-0.85}{1+e^{0.85}}\\
&=
\frac{-0.85}{1+2.34}\\
&=
-0.25.
\end{aligned}
\]
Untuk posisi dengan \(G_{1,i,j}=1.00\) dan \(G_{2,i,j}=-1.00\), diperoleh nilai hasil
proyeksi sebesar \(0.85\), sehingga
nilai setelah aktivasi Swish adalah \(0.60\).
Dengan aturan yang sama, diperoleh feature map global
sebagai berikut.
\[
\mathbf{G}_{\mathrm{glob}}=
\begin{bmatrix}
-0.25 & -0.25 & 0.60 & 0.60 & -0.25\\
-0.25 & -0.25 & 0.60 & 0.60 & -0.25\\
-0.25 & -0.25 & 0.60 & 0.60 & -0.25\\
-0.25 & -0.25 & 0.60 & 0.60 & -0.25\\
-0.25 & -0.25 & 0.60 & -0.25 & -0.25
\end{bmatrix}.
\]
c. Fusi residual fitur lokal dan global
Feature map lokal \(\mathbf{L}\) dan feature map
global \(\mathbf{G}_{\mathrm{glob}}\)
digabungkan melalui operasi concatenate. Hasil penggabungan
tersebut diproyeksikan menggunakan pointwise convolution \(1\times1\), kemudian ditambahkan dengan
feature map masukan \(\mathbf{X}\) melalui residual
connection. Keluaran fusi dinotasikan sebagai \(\mathbf{X}^{0,0}\).
Pada ilustrasi ini, pointwise convolution \(1\times1\) dilakukan tanpa bias. Bobot fusi
untuk feature map lokal dan global ditetapkan sebagai
berikut:
\[
\mathbf{W}_{\mathrm{fuse}}
=
\begin{bmatrix}
0.45 & 0.35
\end{bmatrix}.
\]
Bobot pertama diterapkan pada \(\mathbf{L}\), sedangkan bobot kedua
diterapkan pada \(\mathbf{G}_{\mathrm{glob}}\).
\[
\begin{aligned}
\mathbf{X}^{0,0}
&=
\mathbf{X}
+
\operatorname{Conv}_{1\times1}
\left(
\operatorname{Concat}
\left[
\mathbf{L},
\mathbf{G}_{\mathrm{glob}}
\right]
\right).
\end{aligned}
\]
Untuk setiap posisi spasial \((i,j)\), bentuk perhitungannya adalah:
\[
\begin{aligned}
F_{\mathrm{fuse},i,j}
&=
0.45L_{i,j}
+
0.35G_{\mathrm{glob},i,j},\\
X^{0,0}_{i,j}
&=
X_{i,j}
+
F_{\mathrm{fuse},i,j}\\
&=
X_{i,j}
+
0.45L_{i,j}
+
0.35G_{\mathrm{glob},i,j}.
\end{aligned}
\]
- Contoh perhitungan pada posisi \((1,1)\):
\[
\begin{aligned}
X^{0,0}_{1,1}
&=
X_{1,1}
+
0.45L_{1,1}
+
0.35G_{\mathrm{glob},1,1}\\
&=
-2.12
+
0.45(-0.28)
+
0.35(-0.25)\\
&=
-2.12-0.126-0.0875\\
&=
-2.33.
\end{aligned}
\]
Dengan perhitungan yang sama, diperoleh keluaran blok
MobileViTv3-v2-1.0 sebagai berikut.
\[
\mathbf{X}^{0,0}=
\begin{bmatrix}
-2.33 & -1.21 & 1.55 & 0.91 & -1.76\\
-2.33 & -0.94 & 1.91 & 1.25 & -1.62\\
-2.33 & -0.94 & 1.92 & 1.25 & -1.62\\
-2.33 & -1.08 & 1.54 & 0.88 & -1.77\\
-2.19 & -1.50 & 0.58 & -0.32 & -1.91
\end{bmatrix}.
\]
Matriks \(\mathbf{X}^{0,0}\)
berukuran \(5\times5\). Keluaran ini
menjadi masukan pada tahap encoder downsampling dan decoder
UNet++.
5. Encoder Bertingkat
Pada tahap ini, feature map keluaran MobileViTv3-v2, yaitu (^{0,0}),
diproses melalui tahapan encoder bertingkat untuk memperoleh
representasi fitur pada berbagai skala spasial. Proses downsampling
dilakukan menggunakan strided convolution untuk mengurangi dimensi
spasial feature map secara bertahap. Setiap tahap menghasilkan
representasi fitur dengan ukuran spasial yang lebih kecil, yang
selanjutnya digunakan pada proses ekstraksi fitur bertingkat. Pada jalur
encoder, tidak dilakukan operasi upsampling karena proses tersebut
merupakan bagian dari tahapan decoder.
a. Downsampling encoder pertama \(\left(\mathbf{X}^{1,0}\right)\)
Feature map \(\mathbf{X}^{0,0}\) berukuran \(5\times5\) diproses menggunakan strided
convolution dengan kernel \(3\times3\), stride \(2\), dan zero padding sebesar
\(1\) pada setiap sisi. Pada ilustrasi
ini, operasi konvolusi dilakukan tanpa bias. Keluaran konvolusi pada
tahap ini dinotasikan sebagai \(\mathbf{F}_{\mathrm{enc}}^{(1)}\),
dengan:
\[
\mathbf{X}^{1,0}
=
\mathbf{F}_{\mathrm{enc}}^{(1)}.
\]
Sebelum operasi strided convolution dilakukan, satu lapisan
nilai nol ditambahkan pada keempat sisi feature map masukan,
yaitu sisi atas, bawah, kiri, dan kanan. Penambahan zero
padding memungkinkan kernel mencakup area tepi matriks selama
proses konvolusi.
Matriks feature map masukan merupakan keluaran blok
MobileViTv3-v2-1.0 yang diperoleh pada tahap sebelumnya, yaitu:
\[
\mathbf{X}^{0,0}
=
\begin{bmatrix}
-2.33 & -1.21 & 1.55 & 0.91 & -1.76\\
-2.33 & -0.94 & 1.91 & 1.25 & -1.62\\
-2.33 & -0.94 & 1.92 & 1.25 & -1.62\\
-2.33 & -1.08 & 1.54 & 0.88 & -1.77\\
-2.19 & -1.50 & 0.58 & -0.32 & -1.91
\end{bmatrix}.
\]
Setelah penambahan zero padding sebesar satu piksel pada
setiap sisi, ukuran matriks berubah dari \(5\times5\) menjadi \(7\times7\), yaitu:
\[
\mathbf{X}_{\mathrm{pad}}^{0,0}
=
\begin{bmatrix}
0.00 & 0.00 & 0.00 & 0.00 & 0.00 & 0.00 & 0.00\\
0.00 & -2.33 & -1.21 & 1.55 & 0.91 & -1.76 &
0.00\\
0.00 & -2.33 & -0.94 & 1.91 & 1.25 & -1.62 &
0.00\\
0.00 & -2.33 & -0.94 & 1.92 & 1.25 & -1.62 &
0.00\\
0.00 & -2.33 & -1.08 & 1.54 & 0.88 & -1.77 &
0.00\\
0.00 & -2.19 & -1.50 & 0.58 & -0.32 & -1.91 &
0.00\\
0.00 & 0.00 & 0.00 & 0.00 & 0.00 & 0.00 & 0.00
\end{bmatrix}.
\]
Pada ilustrasi ini, kernel disederhanakan dengan hanya elemen tengah
bernilai satu dan elemen lainnya bernilai nol:
\[
\mathbf{W}_{\mathrm{enc}}^{(1)}
=
\begin{bmatrix}
0 & 0 & 0\\
0 & 1 & 0\\
0 & 0 & 0
\end{bmatrix}.
\]
Kernel tersebut digunakan untuk mengilustrasikan operasi strided
convolution. Pada setiap posisi, sembilan elemen dalam area
konvolusi dikalikan dengan sembilan bobot kernel yang bersesuaian,
kemudian seluruh hasil perkalian dijumlahkan.
Karena hanya bobot pusat kernel yang bernilai satu, hasil konvolusi
pada ilustrasi ini ditentukan oleh elemen yang berada tepat di bawah
pusat kernel. Sementara itu, penggunaan stride sebesar \(2\) menyebabkan kernel bergeser dua posisi
pada setiap perpindahan.
Ukuran keluaran dihitung menggunakan:
\[
\begin{aligned}
o
&=
\left\lfloor
\frac{i+2p-k}{s}
\right\rfloor+1\\
&=
\left\lfloor
\frac{5+2(1)-3}{2}
\right\rfloor+1\\
&=
\left\lfloor
\frac{4}{2}
\right\rfloor+1\\
&=3.
\end{aligned}
\]
Dengan demikian, ukuran spasial feature map berubah dari
\(5\times5\) menjadi \(3\times3\).
Secara umum, operasi strided convolution dengan kernel \(3\times3\), stride \(2\), dan padding \(1\) dinyatakan sebagai:
\[
F_{\mathrm{enc},a,b}^{(1)}
=
\sum_{u=1}^{3}
\sum_{v=1}^{3}
W_{\mathrm{enc},u,v}^{(1)}
X_{\mathrm{pad},2a+u-2,\,2b+v-2}^{0,0},
\]
dengan \(a,b=1,2,3\), sedangkan
\(u\) dan \(v\) merupakan indeks baris dan kolom
kernel.
Pada setiap posisi, kernel mencakup area berukuran \(3\times3\). Karena stride bernilai
\(2\), kernel bergeser dua kolom ke
kanan untuk menghitung elemen berikutnya pada baris keluaran yang sama.
Setelah mencapai posisi terakhir pada baris tersebut, kernel kembali ke
sisi kiri dan bergeser dua baris ke bawah.
- Contoh Perhitungan Konvolusi:
1. Perhitungan elemen pada posisi \((1,1)\)
Untuk menghasilkan elemen pertama dari feature map keluaran,
kernel ditempatkan pada area \(3\times3\) di pojok kiri atas matriks yang
telah diberi zero padding.
Area feature map yang diproses adalah:
\[
\begin{bmatrix}
0.00 & 0.00 & 0.00\\
0.00 & -2.33 & -1.21\\
0.00 & -2.33 & -0.94
\end{bmatrix}.
\]
Setiap elemen pada area tersebut dikalikan dengan bobot kernel yang
bersesuaian, kemudian seluruh hasil perkalian dijumlahkan sebagai
berikut:
\[
\begin{aligned}
F_{\mathrm{enc},1,1}^{(1)}
={}&
(0.00)(0)
+(0.00)(0)
+(0.00)(0)\\
&+(0.00)(0)
+(-2.33)(1)
+(-1.21)(0)\\
&+(0.00)(0)
+(-2.33)(0)
+(-0.94)(0)\\
={}&-2.33.
\end{aligned}
\]
Dengan demikian, nilai elemen keluaran pada posisi \((1,1)\) adalah:
\[
X_{1,1}^{1,0}
=
F_{\mathrm{enc},1,1}^{(1)}
=
-2.33.
\]
2. Perhitungan elemen pada posisi \((1,2)\)
Untuk menghitung elemen pada posisi \((1,2)\), kernel bergeser dua kolom ke kanan
dari posisi sebelumnya karena stride yang digunakan bernilai
\(2\).
Area feature map yang diproses adalah:
\[
\begin{bmatrix}
0.00 & 0.00 & 0.00\\
-1.21 & 1.55 & 0.91\\
-0.94 & 1.91 & 1.25
\end{bmatrix}.
\]
Perhitungan konvolusi dilakukan menggunakan bobot kernel yang
sama:
\[
\begin{aligned}
F_{\mathrm{enc},1,2}^{(1)}
={}&
(0.00)(0)
+(0.00)(0)
+(0.00)(0)\\
&+(-1.21)(0)
+(1.55)(1)
+(0.91)(0)\\
&+(-0.94)(0)
+(1.91)(0)
+(1.25)(0)\\
={}&1.55.
\end{aligned}
\]
Dengan demikian, nilai elemen keluaran pada posisi \((1,2)\) adalah:
\[
X_{1,2}^{1,0}
=
F_{\mathrm{enc},1,2}^{(1)}
=
1.55.
\]
Prosedur yang sama diterapkan pada seluruh posisi kernel. Setiap
elemen keluaran diperoleh melalui penjumlahan hasil perkalian elemen
pada area konvolusi dengan bobot kernel yang bersesuaian.
Dengan menerapkan operasi strided convolution pada seluruh
posisi, diperoleh feature map encoder pertama berukuran \(3\times3\), yaitu:
\[
\mathbf{X}^{1,0}
=
\begin{bmatrix}
-2.33 & 1.55 & -1.76\\
-2.33 & 1.92 & -1.62\\
-2.19 & 0.58 & -1.91
\end{bmatrix}.
\]
Hasil tersebut menunjukkan bahwa operasi strided convolution
dengan stride \(2\) mengurangi
ukuran spasial feature map dari \(5\times5\) menjadi \(3\times3\). Pada ilustrasi ini,
penyederhanaan bobot kernel menyebabkan setiap elemen keluaran sama
dengan elemen masukan yang berada pada posisi pusat kernel. Namun, pada
implementasi model sebenarnya, bobot kernel dipelajari selama pelatihan
sehingga keluaran konvolusi merupakan kombinasi berbobot dari
elemen-elemen pada area yang diproses.
b. Downsampling encoder kedua \(\left(\mathbf{X}^{2,0}\right)\)
Feature map \(\mathbf{X}^{1,0}\) berukuran \(3\times3\) kembali diproses menggunakan
strided convolution dengan kernel \(3\times3\), stride \(2\), dan zero padding sebesar
\(1\) pada setiap sisi. Pada ilustrasi
ini, operasi konvolusi dilakukan tanpa bias. Keluaran konvolusi pada
tahap kedua dinotasikan sebagai \(\mathbf{F}_{\mathrm{enc}}^{(2)}\),
dengan:
\[
\mathbf{X}^{2,0}
=
\mathbf{F}_{\mathrm{enc}}^{(2)}.
\]
Sebelum operasi strided convolution dilakukan, satu lapisan
nilai nol ditambahkan pada keempat sisi feature map masukan,
yaitu sisi atas, bawah, kiri, dan kanan. Penambahan zero
padding memungkinkan kernel mencakup area tepi matriks selama
proses konvolusi.
Matriks feature map masukan merupakan hasil downsampling
encoder pertama, yaitu:
\[
\mathbf{X}^{1,0}
=
\begin{bmatrix}
-2.33 & 1.55 & -1.76\\
-2.33 & 1.92 & -1.62\\
-2.19 & 0.58 & -1.91
\end{bmatrix}.
\]
Setelah penambahan zero padding sebesar satu piksel pada
setiap sisi, ukuran matriks berubah dari \(3\times3\) menjadi \(5\times5\), yaitu:
\[
\mathbf{X}_{\mathrm{pad}}^{1,0}
=
\begin{bmatrix}
0.00 & 0.00 & 0.00 & 0.00 & 0.00\\
0.00 & -2.33 & 1.55 & -1.76 & 0.00\\
0.00 & -2.33 & 1.92 & -1.62 & 0.00\\
0.00 & -2.19 & 0.58 & -1.91 & 0.00\\
0.00 & 0.00 & 0.00 & 0.00 & 0.00
\end{bmatrix}.
\]
Pada ilustrasi ini, kernel kedua disederhanakan dengan hanya elemen
tengah bernilai satu dan elemen lainnya bernilai nol:
\[
\mathbf{W}_{\mathrm{enc}}^{(2)}
=
\begin{bmatrix}
0 & 0 & 0\\
0 & 1 & 0\\
0 & 0 & 0
\end{bmatrix}.
\]
Kernel tersebut digunakan untuk mengilustrasikan operasi strided
convolution pada tahap kedua. Pada setiap posisi, sembilan elemen
dalam area konvolusi dikalikan dengan sembilan bobot kernel yang
bersesuaian, kemudian seluruh hasil perkalian dijumlahkan.
Karena hanya bobot pusat kernel yang bernilai satu, hasil konvolusi
pada ilustrasi ini ditentukan oleh elemen yang berada tepat di bawah
pusat kernel. Penggunaan stride sebesar \(2\) menyebabkan kernel bergeser dua posisi
pada setiap perpindahan.
Ukuran keluaran dihitung menggunakan:
\[
\begin{aligned}
o
&=
\left\lfloor
\frac{i+2p-k}{s}
\right\rfloor+1\\
&=
\left\lfloor
\frac{3+2(1)-3}{2}
\right\rfloor+1\\
&=
\left\lfloor
\frac{2}{2}
\right\rfloor+1\\
&=2.
\end{aligned}
\]
Dengan demikian, ukuran spasial feature map berubah dari
\(3\times3\) menjadi \(2\times2\).
Secara umum, operasi strided convolution pada tahap kedua
dengan kernel \(3\times3\),
stride \(2\), dan
padding \(1\) dinyatakan
sebagai:
\[
F_{\mathrm{enc},a,b}^{(2)}
=
\sum_{u=1}^{3}
\sum_{v=1}^{3}
W_{\mathrm{enc},u,v}^{(2)}
X_{\mathrm{pad},2a+u-2,\,2b+v-2}^{1,0},
\]
dengan \(a,b=1,2\), sedangkan \(u\) dan \(v\) merupakan indeks baris dan kolom
kernel.
Pada setiap posisi, kernel mencakup area berukuran \(3\times3\). Karena stride bernilai
\(2\), kernel bergeser dua kolom ke
kanan untuk menghitung elemen berikutnya pada baris keluaran yang sama.
Setelah mencapai posisi terakhir pada baris tersebut, kernel kembali ke
sisi kiri dan bergeser dua baris ke bawah.
Karena hanya bobot pusat kernel yang bernilai satu, persamaan
tersebut dapat disederhanakan menjadi:
\[
X_{a,b}^{2,0}
=
F_{\mathrm{enc},a,b}^{(2)}
=
X_{2a-1,\,2b-1}^{1,0}.
\]
- Contoh Perhitungan Konvolusi:
1. Perhitungan elemen pada posisi \((1,1)\)
Untuk menghasilkan elemen pertama dari feature map keluaran,
kernel ditempatkan pada area \(3\times3\) di pojok kiri atas matriks yang
telah diberi zero padding.
Area feature map yang diproses adalah:
\[
\begin{bmatrix}
0.00 & 0.00 & 0.00\\
0.00 & -2.33 & 1.55\\
0.00 & -2.33 & 1.92
\end{bmatrix}.
\]
Setiap elemen pada area tersebut dikalikan dengan bobot kernel yang
bersesuaian, kemudian seluruh hasil perkalian dijumlahkan sebagai
berikut:
\[
\begin{aligned}
F_{\mathrm{enc},1,1}^{(2)}
={}&
(0.00)(0)
+(0.00)(0)
+(0.00)(0)\\
&+(0.00)(0)
+(-2.33)(1)
+(1.55)(0)\\
&+(0.00)(0)
+(-2.33)(0)
+(1.92)(0)\\
={}&-2.33.
\end{aligned}
\]
Dengan demikian, nilai elemen keluaran pada posisi \((1,1)\) adalah:
\[
X_{1,1}^{2,0}
=
F_{\mathrm{enc},1,1}^{(2)}
=
-2.33.
\]
2. Perhitungan elemen pada posisi \((1,2)\)
Untuk menghitung elemen pada posisi \((1,2)\), kernel bergeser dua kolom ke kanan
dari posisi sebelumnya karena stride yang digunakan bernilai
\(2\).
Area feature map yang diproses adalah:
\[
\begin{bmatrix}
0.00 & 0.00 & 0.00\\
1.55 & -1.76 & 0.00\\
1.92 & -1.62 & 0.00
\end{bmatrix}.
\]
Perhitungan konvolusi dilakukan menggunakan bobot kernel yang
sama:
\[
\begin{aligned}
F_{\mathrm{enc},1,2}^{(2)}
={}&
(0.00)(0)
+(0.00)(0)
+(0.00)(0)\\
&+(1.55)(0)
+(-1.76)(1)
+(0.00)(0)\\
&+(1.92)(0)
+(-1.62)(0)
+(0.00)(0)\\
={}&-1.76.
\end{aligned}
\]
Dengan demikian, nilai elemen keluaran pada posisi \((1,2)\) adalah:
\[
X_{1,2}^{2,0}
=
F_{\mathrm{enc},1,2}^{(2)}
=
-1.76.
\]
Prosedur yang sama diterapkan pada seluruh posisi kernel. Setiap
elemen keluaran diperoleh melalui penjumlahan hasil perkalian elemen
pada area konvolusi dengan bobot kernel yang bersesuaian.
Dengan menerapkan operasi strided convolution pada seluruh
posisi, diperoleh feature map encoder kedua berukuran \(2\times2\), yaitu:
\[
\mathbf{X}^{2,0}
=
\begin{bmatrix}
-2.33 & -1.76\\
-2.19 & -1.91
\end{bmatrix}.
\]
Hasil tersebut menunjukkan bahwa operasi strided convolution
dengan stride \(2\) mengurangi
ukuran spasial feature map dari \(3\times3\) menjadi \(2\times2\). Pada ilustrasi ini,
penyederhanaan bobot kernel menyebabkan setiap elemen keluaran sama
dengan elemen masukan yang berada pada posisi pusat kernel. Namun, pada
implementasi model sebenarnya, bobot kernel dipelajari selama pelatihan
sehingga keluaran konvolusi merupakan kombinasi berbobot dari
elemen-elemen pada area yang diproses.
6. Decoder UNet++
Decoder UNet++ mengembalikan ukuran spasial feature
map secara bertahap melalui operasi upsampling. Pada
ilustrasi perhitungan manual ini, upsampling dilakukan
menggunakan interpolasi bilinear. Selanjutnya, feature map dari
jalur encoder dan node decoder sebelumnya digabungkan
pada dimensi kanal melalui operasi \(\operatorname{Concat}\).
Untuk menyederhanakan perhitungan manual, operasi pengolahan fitur
pada setiap node decoder direpresentasikan menggunakan
konvolusi \(1\times1\) tanpa bias yang
diikuti fungsi aktivasi ReLU. Bobot konvolusi yang digunakan merupakan
parameter ilustratif dan bukan bobot hasil pelatihan model.
a. Upsampling \(\mathbf{X}^{2,0}\) dan Node
Decoder \(\mathbf{X}^{1,1}\)
Feature map encoder kedua \(\mathbf{X}^{2,0}\) berukuran \(2\times2\) diperbesar menjadi \(3\times3\) menggunakan interpolasi
bilinear. Proses ini bertujuan untuk menyesuaikan ukuran spasial
feature map sehingga dapat digabungkan dengan \(\mathbf{X}^{1,0}\) melalui nested skip
connection.
Matriks feature map masukan adalah:
\[
\mathbf{X}^{2,0}
=
\begin{bmatrix}
-2.33 & -1.76\\
-2.19 & -1.91
\end{bmatrix}.
\]
- Rumus interpolasi bilinear:
Interpolasi bilinear menentukan nilai keluaran berdasarkan jarak
terhadap elemen-elemen pada feature map masukan. Elemen yang
lebih dekat dengan posisi keluaran memiliki bobot lebih besar, sedangkan
elemen yang berjarak satu satuan atau lebih pada salah satu arah
memiliki bobot nol.
Pada feature map satu kanal, interpolasi bilinear dinyatakan
sebagai:
\[
\left[
\operatorname{Up}
\left(
\mathbf{X}^{2,0}
\right)
\right]_{r,c}
=
\sum_{n=1}^{2}
\sum_{m=1}^{2}
X_{n,m}^{2,0}
\max
\left(
0,
1-\left|x_c-m\right|
\right)
\max
\left(
0,
1-\left|y_r-n\right|
\right).
\]
Pada persamaan tersebut, \(r\) dan
\(c\) menyatakan indeks baris dan kolom
pada feature map keluaran, sedangkan \(n\) dan \(m\) menyatakan indeks baris dan kolom pada
feature map masukan. Koordinat \(x_c\) menunjukkan posisi horizontal atau
arah kolom, sedangkan \(y_r\)
menunjukkan posisi vertikal atau arah baris.
Untuk mempermudah penjabaran, bobot interpolasi pada setiap elemen
masukan dinotasikan sebagai:
\[
w_{n,m}^{(r,c)}
=
\max
\left(
0,
1-\left|x_c-m\right|
\right)
\max
\left(
0,
1-\left|y_r-n\right|
\right).
\]
Dengan demikian, rumus interpolasi bilinear dapat dituliskan
sebagai:
\[
\left[
\operatorname{Up}
\left(
\mathbf{X}^{2,0}
\right)
\right]_{r,c}
=
\sum_{n=1}^{2}
\sum_{m=1}^{2}
w_{n,m}^{(r,c)}X_{n,m}^{2,0}.
\]
- Penentuan koordinat interpolasi:
Pada ilustrasi ini, koordinat matriks masukan menggunakan indeks yang
dimulai dari \(1\). Karena ukuran
feature map masukan adalah \(2\times2\) dan ukuran keluaran adalah \(3\times3\), koordinat interpolasi
ditentukan sebagai:
\[
x_c
=
1+(c-1)\frac{2-1}{3-1}
=
1+\frac{c-1}{2},
\]
\[
y_r
=
1+(r-1)\frac{2-1}{3-1}
=
1+\frac{r-1}{2},
\]
dengan \(r,c=1,2,3\).
Angka \(1\) menunjukkan koordinat
awal karena indeks matriks dimulai dari \(1\), sedangkan pembagian dengan \(2\) menunjukkan bahwa jarak antara dua
koordinat masukan dibagi menjadi dua interval yang sama panjang.
Nilai koordinat yang diperoleh adalah:
| \(1\) |
\(1\) |
| \(2\) |
\(1.5\) |
| \(3\) |
\(2\) |
Dengan demikian, koordinat interpolasi pada matriks keluaran dapat
dituliskan sebagai:
\[
\begin{bmatrix}
(1,1) & (1,1.5) & (1,2)\\
(1.5,1) & (1.5,1.5) & (1.5,2)\\
(2,1) & (2,1.5) & (2,2)
\end{bmatrix}.
\]
Setiap pasangan koordinat dituliskan dalam urutan \((y_r,x_c)\). Pada posisi sudut, nilai
keluaran sama dengan nilai masukan karena koordinatnya berimpit.
Sementara itu, posisi tengah sisi diperoleh dari dua elemen masukan,
sedangkan posisi tengah matriks diperoleh dari empat elemen masukan.
- Contoh perhitungan interpolasi bilinear pada posisi \((1,2)\):
Pada posisi \((1,2)\), koordinat
interpolasi diperoleh sebagai berikut:
\[
y_1=1,
\qquad
x_2=1.5.
\]
Posisi tersebut berada tepat di tengah antara kolom pertama dan kolom
kedua pada baris pertama. Bobot interpolasi untuk elemen \(X_{1,1}^{2,0}\) dihitung sebagai:
\[
\begin{aligned}
w_{1,1}^{(1,2)}
&=
\max(0,1-|1.5-1|)
\max(0,1-|1-1|)\\
&=
0.5\times1\\
&=
0.5.
\end{aligned}
\]
Sementara itu, bobot untuk elemen \(X_{1,2}^{2,0}\) adalah:
\[
\begin{aligned}
w_{1,2}^{(1,2)}
&=
\max(0,1-|1.5-2|)
\max(0,1-|1-1|)\\
&=
0.5\times1\\
&=
0.5.
\end{aligned}
\]
Kedua elemen pada baris kedua memiliki bobot nol karena jarak
vertikalnya terhadap posisi keluaran adalah satu satuan. Dengan
demikian:
\[
w_{1,1}^{(1,2)}
=
w_{1,2}^{(1,2)}
=
0.5,
\qquad
w_{2,1}^{(1,2)}
=
w_{2,2}^{(1,2)}
=
0.
\]
Dengan memasukkan bobot tersebut ke dalam rumus interpolasi bilinear,
diperoleh:
\[
\begin{aligned}
\left[
\operatorname{Up}
\left(
\mathbf{X}^{2,0}
\right)
\right]_{1,2}
&=
0.5X_{1,1}^{2,0}
+
0.5X_{1,2}^{2,0}\\
&=
\frac{
X_{1,1}^{2,0}
+
X_{1,2}^{2,0}
}{2}\\
&=
\frac{-2.33-1.76}{2}\\
&=
-2.045\\
&\approx
-2.05.
\end{aligned}
\]
- Contoh perhitungan interpolasi bilinear pada posisi tengah
\((2,2)\):
Pada posisi \((2,2)\), koordinat
interpolasi diperoleh sebagai berikut:
\[
y_2=1.5,
\qquad
x_2=1.5.
\]
Posisi tersebut berada tepat di tengah empat elemen matriks masukan.
Bobot interpolasi untuk elemen \(X_{1,1}^{2,0}\) dihitung sebagai:
\[
\begin{aligned}
w_{1,1}^{(2,2)}
&=
\max(0,1-|1.5-1|)
\max(0,1-|1.5-1|)\\
&=
0.5\times0.5\\
&=
0.25.
\end{aligned}
\]
Karena posisi tengah berjarak sama dari keempat elemen masukan,
maka:
\[
w_{1,1}^{(2,2)}
=
w_{1,2}^{(2,2)}
=
w_{2,1}^{(2,2)}
=
w_{2,2}^{(2,2)}
=
0.25.
\]
Dengan demikian, rumus interpolasi bilinear menjadi:
\[
\begin{aligned}
\left[
\operatorname{Up}
\left(
\mathbf{X}^{2,0}
\right)
\right]_{2,2}
&=
0.25X_{1,1}^{2,0}
+
0.25X_{1,2}^{2,0}\\
&\quad+
0.25X_{2,1}^{2,0}
+
0.25X_{2,2}^{2,0}\\
&=
\frac{
X_{1,1}^{2,0}
+
X_{1,2}^{2,0}
+
X_{2,1}^{2,0}
+
X_{2,2}^{2,0}
}{4}\\
&=
\frac{-2.33-1.76-2.19-1.91}{4}\\
&=
-2.0475\\
&\approx
-2.05.
\end{aligned}
\]
Dengan menerapkan interpolasi bilinear pada seluruh posisi keluaran,
diperoleh feature map hasil upsampling berukuran \(3\times3\), yaitu:
\[
\operatorname{Up}
\left(
\mathbf{X}^{2,0}
\right)
=
\begin{bmatrix}
-2.33 & -2.05 & -1.76\\
-2.26 & -2.05 & -1.84\\
-2.19 & -2.05 & -1.91
\end{bmatrix}.
\]
Hasil tersebut menunjukkan bahwa interpolasi bilinear mempertahankan
nilai pada posisi sudut dan menghitung nilai pada posisi lainnya
berdasarkan bobot jarak terhadap elemen masukan. Nilai hasil interpolasi
ditampilkan hingga dua angka desimal.
Sesuai dengan persamaan UNet++, nested skip connection pada
node decoder pertama dirumuskan sebagai:
\[
\mathbf{X}^{1,1}
=
H^{(1,1)}
\left(
\operatorname{Concat}
\left[
\mathbf{X}^{1,0},
\operatorname{Up}
\left(
\mathbf{X}^{2,0}
\right)
\right]
\right).
\]
Pada persamaan tersebut, \(H^{(1,1)}\) menyatakan operasi pengolahan
fitur pada node decoder \(\mathbf{X}^{1,1}\). Dalam ilustrasi
perhitungan manual ini, operasi tersebut disederhanakan menggunakan
konvolusi \(1\times1\) tanpa bias yang
diikuti fungsi aktivasi ReLU.
Karena kedua feature map yang digabungkan berukuran \(3\times3\) dan masing-masing
direpresentasikan oleh satu kanal, hasil Concat memiliki dua
kanal. Satu filter konvolusi \(1\times1\) digunakan untuk menggabungkan
kedua kanal tersebut menjadi satu kanal keluaran.
Pada ilustrasi ini, bobot kernel ditentukan sebagai:
\[
W_{\mathrm{dec},1}^{(1,1)}=[1.00],
\qquad
W_{\mathrm{dec},2}^{(1,1)}=[0.20].
\]
Bobot pertama diterapkan pada \(\mathbf{X}^{1,0}\), sedangkan bobot kedua
diterapkan pada \(\operatorname{Up}(\mathbf{X}^{2,0})\).
Dengan demikian, untuk setiap posisi spasial \((r,c)\), keluaran node decoder
dihitung sebagai:
\[
X_{r,c}^{1,1}
=
\operatorname{ReLU}
\left(
W_{\mathrm{dec},1}^{(1,1)}X_{r,c}^{1,0}
+
W_{\mathrm{dec},2}^{(1,1)}
\left[
\operatorname{Up}
\left(
\mathbf{X}^{2,0}
\right)
\right]_{r,c}
\right).
\]
- Contoh perhitungan node decoder pada posisi \((1,2)\):
\[
\begin{aligned}
X_{1,2}^{1,1}
&=
\operatorname{ReLU}
\left(
W_{\mathrm{dec},1}^{(1,1)}X_{1,2}^{1,0}
+
W_{\mathrm{dec},2}^{(1,1)}
\left[
\operatorname{Up}
\left(
\mathbf{X}^{2,0}
\right)
\right]_{1,2}
\right)\\
&=
\operatorname{ReLU}
\left(
1.00(1.55)
+
0.20(-2.05)
\right)\\
&=
\operatorname{ReLU}(1.14)\\
&=
1.14.
\end{aligned}
\]
Dengan menerapkan operasi yang sama pada seluruh posisi spasial,
diperoleh feature map node decoder pertama sebagai
berikut:
\[
\mathbf{X}^{1,1}
=
\begin{bmatrix}
0.00 & 1.14 & 0.00\\
0.00 & 1.51 & 0.00\\
0.00 & 0.17 & 0.00
\end{bmatrix}.
\]
Hasil tersebut menunjukkan bahwa feature map hasil
upsampling digabungkan dengan feature map dari jalur
encoder melalui nested skip connection. Pada ilustrasi
ini, penggabungan dilakukan menggunakan Concat, konvolusi \(1\times1\), dan fungsi aktivasi ReLU.
Feature map \(\mathbf{X}^{1,1}\) selanjutnya digunakan
pada pembentukan node decoder berikutnya.
b. Upsampling \(\mathbf{X}^{1,0}\) dan Nested Skip
Pertama \(\mathbf{X}^{0,1}\)
Feature map encoder pertama \(\mathbf{X}^{1,0}\) berukuran \(3\times3\) diperbesar menjadi \(5\times5\) menggunakan interpolasi
bilinear. Proses ini bertujuan untuk menyesuaikan ukuran spasial
feature map sehingga dapat digabungkan dengan \(\mathbf{X}^{0,0}\) melalui nested skip
connection.
Matriks feature map masukan adalah:
\[
\mathbf{X}^{1,0}
=
\begin{bmatrix}
-2.33 & 1.55 & -1.76\\
-2.33 & 1.92 & -1.62\\
-2.19 & 0.58 & -1.91
\end{bmatrix}.
\]
- Rumus interpolasi bilinear:
Interpolasi bilinear dilakukan menggunakan prinsip yang sama seperti
pada subbagian sebelumnya. Nilai keluaran dihitung berdasarkan jarak
terhadap elemen-elemen pada feature map masukan.
Pada feature map satu kanal, rumus interpolasi bilinear
dinyatakan sebagai:
\[
\left[
\operatorname{Up}
\left(
\mathbf{X}^{1,0}
\right)
\right]_{r,c}
=
\sum_{n=1}^{3}
\sum_{m=1}^{3}
X_{n,m}^{1,0}
\max
\left(
0,
1-\left|x_c-m\right|
\right)
\max
\left(
0,
1-\left|y_r-n\right|
\right).
\]
Pada persamaan tersebut, \(r\) dan
\(c\) menyatakan indeks baris dan kolom
pada feature map keluaran, sedangkan \(n\) dan \(m\) menyatakan indeks baris dan kolom pada
feature map masukan. Koordinat \(x_c\) menunjukkan posisi horizontal atau
arah kolom, sedangkan \(y_r\)
menunjukkan posisi vertikal atau arah baris.
Bobot interpolasi pada setiap elemen masukan dinyatakan sebagai:
\[
w_{n,m}^{(r,c)}
=
\max
\left(
0,
1-\left|x_c-m\right|
\right)
\max
\left(
0,
1-\left|y_r-n\right|
\right).
\]
Dengan demikian, rumus interpolasi bilinear dapat dituliskan
sebagai:
\[
\left[
\operatorname{Up}
\left(
\mathbf{X}^{1,0}
\right)
\right]_{r,c}
=
\sum_{n=1}^{3}
\sum_{m=1}^{3}
w_{n,m}^{(r,c)}X_{n,m}^{1,0}.
\]
- Penentuan koordinat interpolasi:
Pada ilustrasi ini, koordinat matriks menggunakan indeks yang dimulai
dari \(1\). Karena ukuran feature
map masukan adalah \(3\times3\)
dan ukuran keluaran adalah \(5\times5\), koordinat interpolasi
ditentukan sebagai:
\[
x_c
=
1+(c-1)\frac{3-1}{5-1}
=
1+\frac{c-1}{2},
\]
\[
y_r
=
1+(r-1)\frac{3-1}{5-1}
=
1+\frac{r-1}{2},
\]
dengan \(r,c=1,2,3,4,5\).
Angka \(1\) menunjukkan koordinat
awal matriks masukan, sedangkan pembagian dengan \(2\) menunjukkan bahwa setiap interval
antara dua koordinat masukan dibagi menjadi dua bagian yang sama
panjang.
Nilai koordinat yang diperoleh adalah:
| \(1\) |
\(1\) |
| \(2\) |
\(1.5\) |
| \(3\) |
\(2\) |
| \(4\) |
\(2.5\) |
| \(5\) |
\(3\) |
Dengan demikian, nilai pada posisi keluaran yang berimpit dengan
koordinat masukan dipertahankan, sedangkan nilai pada posisi lainnya
dihitung berdasarkan bobot jarak terhadap elemen-elemen masukan di
sekitarnya.
- Contoh perhitungan interpolasi bilinear pada posisi \((1,2)\):
Pada posisi \((1,2)\), koordinat
interpolasi diperoleh sebagai berikut:
\[
y_1=1,
\qquad
x_2=1.5.
\]
Posisi tersebut berada tepat di tengah antara kolom pertama dan kolom
kedua pada baris pertama. Bobot interpolasi untuk elemen \(X_{1,1}^{1,0}\) dihitung sebagai:
\[
\begin{aligned}
w_{1,1}^{(1,2)}
&=
\max(0,1-|1.5-1|)
\max(0,1-|1-1|)\\
&=
0.5\times1\\
&=
0.5.
\end{aligned}
\]
Sementara itu, bobot untuk elemen \(X_{1,2}^{1,0}\) adalah:
\[
\begin{aligned}
w_{1,2}^{(1,2)}
&=
\max(0,1-|1.5-2|)
\max(0,1-|1-1|)\\
&=
0.5\times1\\
&=
0.5.
\end{aligned}
\]
Elemen lainnya memiliki bobot nol karena berada di luar jarak
interpolasi pada posisi tersebut. Dengan demikian:
\[
w_{1,1}^{(1,2)}
=
w_{1,2}^{(1,2)}
=
0.5.
\]
Dengan memasukkan bobot tersebut ke dalam rumus interpolasi bilinear,
diperoleh:
\[
\begin{aligned}
\left[
\operatorname{Up}
\left(
\mathbf{X}^{1,0}
\right)
\right]_{1,2}
&=
0.5X_{1,1}^{1,0}
+
0.5X_{1,2}^{1,0}\\
&=
\frac{
X_{1,1}^{1,0}
+
X_{1,2}^{1,0}
}{2}\\
&=
\frac{-2.33+1.55}{2}\\
&=
-0.39.
\end{aligned}
\]
- Contoh perhitungan interpolasi bilinear pada posisi \((2,2)\):
Pada posisi \((2,2)\), koordinat
interpolasi diperoleh sebagai berikut:
\[
y_2=1.5,
\qquad
x_2=1.5.
\]
Posisi tersebut berada tepat di tengah empat elemen masukan, yaitu
\(X_{1,1}^{1,0}\), \(X_{1,2}^{1,0}\), \(X_{2,1}^{1,0}\), dan \(X_{2,2}^{1,0}\).
Bobot interpolasi untuk elemen \(X_{1,1}^{1,0}\) dihitung sebagai:
\[
\begin{aligned}
w_{1,1}^{(2,2)}
&=
\max(0,1-|1.5-1|)
\max(0,1-|1.5-1|)\\
&=
0.5\times0.5\\
&=
0.25.
\end{aligned}
\]
Karena posisi tersebut berjarak sama dari keempat elemen masukan,
maka:
\[
w_{1,1}^{(2,2)}
=
w_{1,2}^{(2,2)}
=
w_{2,1}^{(2,2)}
=
w_{2,2}^{(2,2)}
=
0.25.
\]
Dengan demikian, rumus interpolasi bilinear menjadi:
\[
\begin{aligned}
\left[
\operatorname{Up}
\left(
\mathbf{X}^{1,0}
\right)
\right]_{2,2}
&=
0.25X_{1,1}^{1,0}
+
0.25X_{1,2}^{1,0}\\
&\quad+
0.25X_{2,1}^{1,0}
+
0.25X_{2,2}^{1,0}\\
&=
\frac{
X_{1,1}^{1,0}
+
X_{1,2}^{1,0}
+
X_{2,1}^{1,0}
+
X_{2,2}^{1,0}
}{4}\\
&=
\frac{-2.33+1.55-2.33+1.92}{4}\\
&=
-0.2975\\
&\approx-0.30.
\end{aligned}
\]
Dengan menerapkan interpolasi bilinear pada seluruh posisi keluaran,
diperoleh feature map hasil upsampling berukuran \(5\times5\), yaitu:
\[
\operatorname{Up}
\left(
\mathbf{X}^{1,0}
\right)
=
\begin{bmatrix}
-2.33 & -0.39 & 1.55 & -0.11 & -1.76\\
-2.33 & -0.30 & 1.73 & 0.02 & -1.69\\
-2.33 & -0.21 & 1.92 & 0.15 & -1.62\\
-2.26 & -0.51 & 1.25 & -0.26 & -1.77\\
-2.19 & -0.81 & 0.58 & -0.67 & -1.91
\end{bmatrix}.
\]
Hasil tersebut menunjukkan bahwa interpolasi bilinear memperbesar
ukuran spasial feature map dari \(3\times3\) menjadi \(5\times5\). Nilai pada posisi yang berimpit
dengan koordinat masukan dipertahankan, sedangkan nilai pada posisi
lainnya dihitung menggunakan bobot interpolasi berdasarkan jarak
terhadap elemen masukan.
Sesuai dengan persamaan UNet++, nested skip connection
pertama pada node decoder dirumuskan sebagai:
\[
\mathbf{X}^{0,1}
=
H^{(0,1)}
\left(
\operatorname{Concat}
\left[
\mathbf{X}^{0,0},
\operatorname{Up}
\left(
\mathbf{X}^{1,0}
\right)
\right]
\right).
\]
Pada persamaan tersebut, \(H^{(0,1)}\) menyatakan operasi pengolahan
fitur pada node decoder \(\mathbf{X}^{0,1}\). Dalam ilustrasi
perhitungan manual ini, operasi tersebut disederhanakan menggunakan
konvolusi \(1\times1\) tanpa bias yang
diikuti fungsi aktivasi ReLU.
Karena kedua feature map yang digabungkan berukuran \(5\times5\) dan masing-masing
direpresentasikan oleh satu kanal, hasil Concat memiliki dua
kanal. Satu filter konvolusi \(1\times1\) digunakan untuk menggabungkan
kedua kanal tersebut menjadi satu kanal keluaran.
Pada ilustrasi ini, bobot kernel ditentukan sebagai:
\[
W_{\mathrm{dec},1}^{(0,1)}=[1.00],
\qquad
W_{\mathrm{dec},2}^{(0,1)}=[1.00].
\]
Bobot pertama diterapkan pada \(\mathbf{X}^{0,0}\), sedangkan bobot kedua
diterapkan pada \(\operatorname{Up}(\mathbf{X}^{1,0})\).
Dengan demikian, untuk setiap posisi spasial \((r,c)\), keluaran node decoder
dihitung sebagai:
\[
X_{r,c}^{0,1}
=
\operatorname{ReLU}
\left(
W_{\mathrm{dec},1}^{(0,1)}X_{r,c}^{0,0}
+
W_{\mathrm{dec},2}^{(0,1)}
\left[
\operatorname{Up}
\left(
\mathbf{X}^{1,0}
\right)
\right]_{r,c}
\right).
\]
- Contoh perhitungan node decoder pada posisi \((2,2)\):
\[
\begin{aligned}
X_{2,2}^{0,1}
&=
\operatorname{ReLU}
\left(
W_{\mathrm{dec},1}^{(0,1)}X_{2,2}^{0,0}
+
W_{\mathrm{dec},2}^{(0,1)}
\left[
\operatorname{Up}
\left(
\mathbf{X}^{1,0}
\right)
\right]_{2,2}
\right)\\
&=
\operatorname{ReLU}
\left(
1.00(-2.33)
+
1.00(-0.30)
\right)\\
&=
\operatorname{ReLU}(-2.63)\\
&=
0.00.
\end{aligned}
\]
- Contoh perhitungan node decoder pada posisi \((2,3)\):
\[
\begin{aligned}
X_{2,3}^{0,1}
&=
\operatorname{ReLU}
\left(
W_{\mathrm{dec},1}^{(0,1)}X_{2,3}^{0,0}
+
W_{\mathrm{dec},2}^{(0,1)}
\left[
\operatorname{Up}
\left(
\mathbf{X}^{1,0}
\right)
\right]_{2,3}
\right)\\
&=
\operatorname{ReLU}
\left(
1.00(1.91)
+
1.00(1.73)
\right)\\
&=
\operatorname{ReLU}(3.64)\\
&=
3.64.
\end{aligned}
\]
Dengan menerapkan operasi yang sama pada seluruh posisi spasial,
diperoleh feature map node decoder sebagai
berikut:
\[
\mathbf{X}^{0,1}
=
\begin{bmatrix}
0.00 & 0.00 & 3.09 & 0.80 & 0.00\\
0.00 & 0.00 & 3.64 & 1.26 & 0.00\\
0.00 & 0.00 & 3.83 & 1.39 & 0.00\\
0.00 & 0.00 & 2.78 & 0.62 & 0.00\\
0.00 & 0.00 & 1.16 & 0.00 & 0.00
\end{bmatrix}.
\]
Hasil tersebut menunjukkan bahwa node \(\mathbf{X}^{0,1}\) menggabungkan informasi
dari feature map encoder \(\mathbf{X}^{0,0}\) dan hasil
upsampling \(\mathbf{X}^{1,0}\) melalui nested skip
connection. Pada ilustrasi ini, penggabungan dilakukan menggunakan
Concat, konvolusi \(1\times1\), dan fungsi aktivasi ReLU.
Feature map \(\mathbf{X}^{0,1}\) selanjutnya digunakan
pada pembentukan node decoder berikutnya.
c. Upsampling \(\mathbf{X}^{1,1}\) dan Nested Skip
Kedua \(\mathbf{X}^{0,2}\)
Node decoder \(\mathbf{X}^{1,1}\) berukuran \(3\times3\) diperbesar menjadi \(5\times5\) menggunakan interpolasi
bilinear. Proses ini bertujuan untuk menyesuaikan ukuran spasial
feature map sehingga dapat digabungkan dengan \(\mathbf{X}^{0,0}\) dan \(\mathbf{X}^{0,1}\) melalui nested skip
connection.
Matriks feature map masukan adalah:
\[
\mathbf{X}^{1,1}
=
\begin{bmatrix}
0.00 & 1.14 & 0.00\\
0.00 & 1.51 & 0.00\\
0.00 & 0.17 & 0.00
\end{bmatrix}.
\]
- Rumus interpolasi bilinear:
Interpolasi bilinear dilakukan dengan menentukan nilai keluaran
berdasarkan jarak terhadap elemen-elemen pada feature map
masukan.
Pada feature map satu kanal, rumus interpolasi bilinear
dinyatakan sebagai:
\[
\left[
\operatorname{Up}
\left(
\mathbf{X}^{1,1}
\right)
\right]_{r,c}
=
\sum_{n=1}^{3}
\sum_{m=1}^{3}
X_{n,m}^{1,1}
\max
\left(
0,
1-\left|x_c-m\right|
\right)
\max
\left(
0,
1-\left|y_r-n\right|
\right).
\]
Pada persamaan tersebut, \(r\) dan
\(c\) menyatakan indeks baris dan kolom
pada feature map keluaran, sedangkan \(n\) dan \(m\) menyatakan indeks baris dan kolom pada
feature map masukan. Koordinat \(x_c\) menunjukkan posisi horizontal atau
arah kolom, sedangkan \(y_r\)
menunjukkan posisi vertikal atau arah baris.
Bobot interpolasi pada setiap elemen masukan dinyatakan sebagai:
\[
w_{n,m}^{(r,c)}
=
\max
\left(
0,
1-\left|x_c-m\right|
\right)
\max
\left(
0,
1-\left|y_r-n\right|
\right).
\]
Dengan demikian, rumus interpolasi bilinear dapat dituliskan
sebagai:
\[
\left[
\operatorname{Up}
\left(
\mathbf{X}^{1,1}
\right)
\right]_{r,c}
=
\sum_{n=1}^{3}
\sum_{m=1}^{3}
w_{n,m}^{(r,c)}X_{n,m}^{1,1}.
\]
- Penentuan koordinat interpolasi:
Pada ilustrasi ini, koordinat matriks menggunakan indeks yang dimulai
dari \(1\). Karena ukuran feature
map masukan adalah \(3\times3\)
dan ukuran keluaran adalah \(5\times5\), koordinat interpolasi
ditentukan sebagai:
\[
x_c
=
1+(c-1)\frac{3-1}{5-1}
=
1+\frac{c-1}{2},
\]
\[
y_r
=
1+(r-1)\frac{3-1}{5-1}
=
1+\frac{r-1}{2},
\]
dengan \(r,c=1,2,3,4,5\).
Angka \(1\) menunjukkan koordinat
awal matriks masukan, sedangkan pembagian dengan \(2\) menunjukkan bahwa setiap interval
antara dua koordinat masukan dibagi menjadi dua bagian yang sama
panjang.
Nilai koordinat yang diperoleh adalah:
| \(1\) |
\(1\) |
| \(2\) |
\(1.5\) |
| \(3\) |
\(2\) |
| \(4\) |
\(2.5\) |
| \(5\) |
\(3\) |
Dengan demikian, nilai pada posisi keluaran yang berimpit dengan
koordinat masukan dipertahankan, sedangkan nilai pada posisi lainnya
dihitung berdasarkan bobot jarak terhadap elemen-elemen masukan di
sekitarnya.
- Contoh perhitungan interpolasi bilinear pada posisi \((2,2)\):
Pada posisi \((2,2)\), koordinat
interpolasi diperoleh sebagai berikut:
\[
y_2=1.5,
\qquad
x_2=1.5.
\]
Posisi tersebut berada tepat di tengah empat elemen masukan, yaitu
\(X_{1,1}^{1,1}\), \(X_{1,2}^{1,1}\), \(X_{2,1}^{1,1}\), dan \(X_{2,2}^{1,1}\).
Bobot interpolasi untuk elemen \(X_{1,1}^{1,1}\) dihitung sebagai:
\[
\begin{aligned}
w_{1,1}^{(2,2)}
&=
\max(0,1-|1.5-1|)
\max(0,1-|1.5-1|)\\
&=
0.5\times0.5\\
&=
0.25.
\end{aligned}
\]
Karena posisi tersebut berjarak sama dari keempat elemen masukan,
maka:
\[
w_{1,1}^{(2,2)}
=
w_{1,2}^{(2,2)}
=
w_{2,1}^{(2,2)}
=
w_{2,2}^{(2,2)}
=
0.25.
\]
Dengan demikian, rumus interpolasi bilinear menjadi:
\[
\begin{aligned}
\left[
\operatorname{Up}
\left(
\mathbf{X}^{1,1}
\right)
\right]_{2,2}
&=
0.25X_{1,1}^{1,1}
+
0.25X_{1,2}^{1,1}\\
&\quad+
0.25X_{2,1}^{1,1}
+
0.25X_{2,2}^{1,1}\\
&=
\frac{
X_{1,1}^{1,1}
+
X_{1,2}^{1,1}
+
X_{2,1}^{1,1}
+
X_{2,2}^{1,1}
}{4}\\
&=
\frac{0.00+1.14+0.00+1.51}{4}\\
&=
0.6625\\
&\approx0.66.
\end{aligned}
\]
- Contoh perhitungan interpolasi bilinear pada posisi \((2,3)\):
Pada posisi \((2,3)\), koordinat
interpolasi diperoleh sebagai berikut:
\[
y_2=1.5,
\qquad
x_3=2.
\]
Posisi tersebut berada tepat di tengah secara vertikal antara baris
pertama dan kedua, tetapi sejajar dengan kolom kedua. Oleh karena itu,
hanya dua elemen pada kolom kedua yang memiliki bobot bukan nol.
Bobot interpolasi untuk elemen \(X_{1,2}^{1,1}\) dihitung sebagai:
\[
\begin{aligned}
w_{1,2}^{(2,3)}
&=
\max(0,1-|2-2|)
\max(0,1-|1.5-1|)\\
&=
1\times0.5\\
&=
0.5.
\end{aligned}
\]
Sementara itu, bobot untuk elemen \(X_{2,2}^{1,1}\) adalah:
\[
\begin{aligned}
w_{2,2}^{(2,3)}
&=
\max(0,1-|2-2|)
\max(0,1-|1.5-2|)\\
&=
1\times0.5\\
&=
0.5.
\end{aligned}
\]
Elemen lainnya memiliki bobot nol karena berada di luar jarak
interpolasi pada posisi tersebut. Dengan demikian:
\[
w_{1,2}^{(2,3)}
=
w_{2,2}^{(2,3)}
=
0.5.
\]
Dengan memasukkan bobot tersebut ke dalam rumus interpolasi bilinear,
diperoleh:
\[
\begin{aligned}
\left[
\operatorname{Up}
\left(
\mathbf{X}^{1,1}
\right)
\right]_{2,3}
&=
0.5X_{1,2}^{1,1}
+
0.5X_{2,2}^{1,1}\\
&=
\frac{
X_{1,2}^{1,1}
+
X_{2,2}^{1,1}
}{2}\\
&=
\frac{1.14+1.51}{2}\\
&=
1.325\\
&\approx1.32.
\end{aligned}
\]
Dengan menerapkan interpolasi bilinear pada seluruh posisi keluaran,
diperoleh feature map hasil upsampling berukuran \(5\times5\), yaitu:
\[
\operatorname{Up}
\left(
\mathbf{X}^{1,1}
\right)
=
\begin{bmatrix}
0.00 & 0.57 & 1.14 & 0.57 & 0.00\\
0.00 & 0.66 & 1.32 & 0.66 & 0.00\\
0.00 & 0.75 & 1.51 & 0.75 & 0.00\\
0.00 & 0.42 & 0.84 & 0.42 & 0.00\\
0.00 & 0.09 & 0.17 & 0.09 & 0.00
\end{bmatrix}.
\]
Hasil tersebut menunjukkan bahwa interpolasi bilinear memperbesar
ukuran spasial feature map dari \(3\times3\) menjadi \(5\times5\). Nilai pada posisi yang berimpit
dengan koordinat masukan dipertahankan, sedangkan nilai pada posisi
lainnya dihitung menggunakan bobot interpolasi berdasarkan jarak
terhadap elemen masukan.
Sesuai dengan persamaan UNet++, nested skip connection kedua
pada node decoder dirumuskan sebagai:
\[
\mathbf{X}^{0,2}
=
H^{(0,2)}
\left(
\operatorname{Concat}
\left[
\mathbf{X}^{0,0},
\mathbf{X}^{0,1},
\operatorname{Up}
\left(
\mathbf{X}^{1,1}
\right)
\right]
\right).
\]
Pada persamaan tersebut, \(H^{(0,2)}\) menyatakan operasi pengolahan
fitur pada node decoder \(\mathbf{X}^{0,2}\). Dalam ilustrasi
perhitungan manual ini, operasi tersebut disederhanakan menggunakan
konvolusi \(1\times1\) tanpa bias yang
diikuti fungsi aktivasi ReLU.
Karena ketiga feature map yang digabungkan berukuran \(5\times5\) dan masing-masing
direpresentasikan oleh satu kanal, hasil Concat memiliki tiga
kanal. Satu filter konvolusi \(1\times1\) digunakan untuk menggabungkan
ketiga kanal tersebut menjadi satu kanal keluaran.
Pada ilustrasi ini, bobot kernel ditentukan sebagai:
\[
W_{\mathrm{dec},1}^{(0,2)}=[0.25],
\qquad
W_{\mathrm{dec},2}^{(0,2)}=[0.50],
\qquad
W_{\mathrm{dec},3}^{(0,2)}=[0.25].
\]
Bobot pertama diterapkan pada \(\mathbf{X}^{0,0}\), bobot kedua diterapkan
pada \(\mathbf{X}^{0,1}\), sedangkan
bobot ketiga diterapkan pada \(\operatorname{Up}(\mathbf{X}^{1,1})\).
Ketiga bobot tersebut merupakan parameter ilustratif untuk
menyederhanakan perhitungan manual, bukan bobot hasil pelatihan
model.
Dengan demikian, untuk setiap posisi spasial \((r,c)\), keluaran node decoder
dihitung sebagai:
\[
\begin{aligned}
X_{r,c}^{0,2}
=
\operatorname{ReLU}
\Bigg(
&0.25X_{r,c}^{0,0}\\
&+
0.50X_{r,c}^{0,1}\\
&+
0.25
\left[
\operatorname{Up}
\left(
\mathbf{X}^{1,1}
\right)
\right]_{r,c}
\Bigg).
\end{aligned}
\]
- Contoh perhitungan node decoder pada posisi \((2,2)\):
\[
\begin{aligned}
X_{2,2}^{0,2}
&=
\operatorname{ReLU}
\Bigg(
0.25X_{2,2}^{0,0}
+
0.50X_{2,2}^{0,1}\\
&\qquad+
0.25
\left[
\operatorname{Up}
\left(
\mathbf{X}^{1,1}
\right)
\right]_{2,2}
\Bigg)\\
&=
\operatorname{ReLU}
\left(
0.25(-2.33)
+
0.50(0.00)
+
0.25(0.66)
\right)\\
&=
\operatorname{ReLU}
\left(
-0.5825+0.165
\right)\\
&=
\operatorname{ReLU}(-0.4175)\\
&=
0.00.
\end{aligned}
\]
- Contoh perhitungan node decoder pada posisi \((2,3)\):
\[
\begin{aligned}
X_{2,3}^{0,2}
&=
\operatorname{ReLU}
\Bigg(
0.25X_{2,3}^{0,0}
+
0.50X_{2,3}^{0,1}\\
&\qquad+
0.25
\left[
\operatorname{Up}
\left(
\mathbf{X}^{1,1}
\right)
\right]_{2,3}
\Bigg)\\
&=
\operatorname{ReLU}
\left(
0.25(1.91)
+
0.50(3.64)
+
0.25(1.32)
\right)\\
&=
\operatorname{ReLU}
\left(
0.4775+1.82+0.33
\right)\\
&=
\operatorname{ReLU}(2.6275)\\
&\approx
2.63.
\end{aligned}
\]
Dengan menerapkan operasi yang sama pada seluruh posisi spasial dan
menggunakan nilai presisi penuh sebelum pembulatan, diperoleh
feature map keluaran akhir decoder sebagai
berikut:
\[
\mathbf{X}^{0,2}
=
\begin{bmatrix}
0.00 & 0.00 & 2.22 & 0.77 & 0.00\\
0.00 & 0.00 & 2.63 & 1.11 & 0.00\\
0.00 & 0.00 & 2.77 & 1.20 & 0.00\\
0.00 & 0.00 & 1.99 & 0.64 & 0.00\\
0.00 & 0.00 & 0.77 & 0.00 & 0.00
\end{bmatrix}.
\]
Hasil tersebut menunjukkan bahwa node \(\mathbf{X}^{0,2}\) menggabungkan informasi
dari \(\mathbf{X}^{0,0}\), \(\mathbf{X}^{0,1}\), dan hasil
upsampling \(\mathbf{X}^{1,1}\) melalui nested skip
connection. Pada ilustrasi ini, penggabungan dilakukan menggunakan
Concat, konvolusi \(1\times1\), dan fungsi aktivasi ReLU.
Feature map \(\mathbf{X}^{0,2}\) merupakan keluaran akhir
decoder pada ilustrasi perhitungan manual ini dan selanjutnya
digunakan sebagai masukan pada head segmentasi.
LS0tDQp0aXRsZTogIklsdXN0cmFzaSBQZW1iZW50dWthbiBTZWdtZW50YXNpIFVOZXQrKyBkZW5nYW4gRW5jb2RlciBNb2JpbGVWaVR2MyBWMiINCg0KYXV0aG9yOiB8DQogIDxkaXYgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzU1NTU1NTsgbGluZS1oZWlnaHQ6IDEuNjsgbWFyZ2luLXRvcDogMTBweDsiPg0KICBTcmkgWXVsaWFuYSAoMTQwNzIwMjUwMDMpIDxicj4NCg0KICBQcm9ncmFtIFN0dWRpIE1hZ2lzdGVyIFN0YXRpc3Rpa2EgVGVyYXBhbiA8YnI+DQogIDwvZGl2Pg0KICANCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZGVwdGg6IDMNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogIHBkZl9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUNCiAgd29yZF9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUNCmNzczogc3R5bGUuY3NzDQotLS0NCg0KIyMgMS4gQ2l0cmEgbWFzdWthbiBncm91bmQgdHJ1dGggZGFuIG5vcm1hbGlzYXNpDQoNClBhZGEgY2l0cmEgZ3JheXNjYWxlLCBzZXRpYXAgcGlrc2VsIG1lbWlsaWtpIHNhdHUgbmlsYWkgaW50ZW5zaXRhcyB5YW5nIG1lbnVuanVra2FuIHRpbmdrYXQga2VjZXJhaGFuLiBBcGFiaWxhIG5pbGFpIGludGVuc2l0YXMgdGVsYWggZGlub3JtYWxpc2FzaSBrZSByZW50YW5nIFwoWzAsMV1cKSwgbWFrYSBuaWxhaSAwIG1lbnVuanVra2FuIHBpa3NlbCBwYWxpbmcgZ2VsYXAgKGhpdGFtKSwgbmlsYWkgMSBtZW51bmp1a2thbiBwaWtzZWwgcGFsaW5nIHRlcmFuZyAocHV0aWgpLCBzZWRhbmdrYW4gbmlsYWkgZGkgYW50YXJhIDAgZGFuIDEgbWVudW5qdWtrYW4gZ3JhZGFzaSBhYnUtYWJ1LiBTZW1ha2luIG1lbmRla2F0aSAwLCBwaWtzZWwgc2VtYWtpbiBnZWxhcDsgc2VtYWtpbiBtZW5kZWthdGkgMSwgcGlrc2VsIHNlbWFraW4gdGVyYW5nLiAgDQoNCkRhbGFtIGlsdXN0cmFzaSBpbmksIG1hdHJpa3MgY2l0cmEgYXdhbCBtYXNpaCBtZW5nZ3VuYWthbiBza2FsYSBpbnRlbnNpdGFzIDAtLTI1NS4gT2xlaCBrYXJlbmEgaXR1LCBuaWxhaSAwIG1lcmVwcmVzZW50YXNpa2FuIGhpdGFtLCBuaWxhaSAyNTUgbWVyZXByZXNlbnRhc2lrYW4gcHV0aWgsIGRhbiBuaWxhaSBzZXBlcnRpIDY0LCAxMjgsIGF0YXUgMTkyIG1lbnVuanVra2FuIHRpbmdrYXQgYWJ1LWFidSB5YW5nIGJlcmJlZGEuIERpbWVuc2kgbWF0cmlrcyBhZGFsYWggXCg1XHRpbWVzNVwpLiBQYWRhIGltcGxlbWVudGFzaSBzZWJlbmFybnlhLCBjaXRyYSBOQ0NUIHNhdHUga2FuYWwgZGlyZXBsaWthc2kgbWVuamFkaSB0aWdhIGthbmFsIGFnYXIgc2VzdWFpIGRlbmdhbiBtYXN1a2FuIGVuY29kZXIgTW9iaWxlVmlUdjMuIE5hbXVuLCBpbHVzdHJhc2kgcGVyaGl0dW5nYW4gYmVyaWt1dCBoYW55YSBtZW5lbHVzdXJpIHNhdHUga2FuYWwuDQoNCiMjIyBhLiBDaXRyYSBtYXN1a2FuDQoNClxbDQpcbWF0aGJme0l9PQ0KXGJlZ2lue2JtYXRyaXh9DQowICYgNjQgJiAxOTIgJiAxNjAgJiAzMlxcDQowICYgODAgJiAyMDggJiAxNzYgJiA0MFxcDQowICYgODAgJiAyMDggJiAxNzYgJiA0MFxcDQowICYgNzIgJiAxOTIgJiAxNjAgJiAzMlxcDQo4ICYgNDggJiAxNDQgJiAxMTIgJiAyNA0KXGVuZHtibWF0cml4fS4NClxdDQoNCiMjIyBiLiBHcm91bmQgdHJ1dGggYmluZXINCg0KXFsNClxtYXRoYmZ7TX09DQpcYmVnaW57Ym1hdHJpeH0NCjAgJiAwICYgMSAmIDEgJiAwXFwNCjAgJiAxICYgMSAmIDEgJiAwXFwNCjAgJiAxICYgMSAmIDEgJiAwXFwNCjAgJiAwICYgMSAmIDEgJiAwXFwNCjAgJiAwICYgMCAmIDAgJiAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KR3JvdW5kIHRydXRoIFwoTVwpIGJlcmFkYSBkaSBhd2FsIHNlYmFnYWkgdGFyZ2V0IGV2YWx1YXNpLCBkZW5nYW4gbmlsYWkgMCBtZW55YXRha2FuIGxhdGFyIGJlbGFrYW5nIGRhbiBuaWxhaSAxIG1lbnlhdGFrYW4gd2lsYXlhaCBsZXNpLiBNYXRyaWtzIFwoTVwpIGJ1a2FuIG1lcnVwYWthbiBtYXN1a2FuIGVuY29kZXIuDQoNCiMjIyBjLiBOb3JtYWxpc2FzaSBrYW5hbA0KDQotICoqTm9ybWFsaXNhc2kgcHJldHJhaW5lZCBJbWFnZU5ldCBkaXRlcmFwa2FuIHBlciBrYW5hbDoqKg0KDQpcWw0KXG1hdGhiZntYfV9SPVxmcmFje0lfUi8yNTUtMC40ODV9ezAuMjI5fSxccXF1YWQNClxtYXRoYmZ7WH1fRz1cZnJhY3tJX0cvMjU1LTAuNDU2fXswLjIyNH0sXHFxdWFkDQpcbWF0aGJme1h9X0I9XGZyYWN7SV9CLzI1NS0wLjQwNn17MC4yMjV9Lg0KXF0NCg0KLSAqKkNvbnRvaDoqKg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpYX3sxLDN9DQomPQ0KXGZyYWN7MTkyLzI1NS0wLjQ4NX17MC4yMjl9XFwNCiY9DQoxLjE3Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KUGFkYSBpbHVzdHJhc2kgaW5pLCBoYW55YSBzYXR1IGthbmFsIHlhbmcgZGlndW5ha2FuIE9sZWgga2FyZW5hIGl0dSwgc2V0aWFwIGVsZW1lbiBmZWF0dXJlIG1hcCBtYXN1a2FuIFwoWFwpIGRpaGl0dW5nIG1lbmdndW5ha2FuDQoNClxbDQpYX3tpLGp9DQo9DQpcZnJhY3tJX3tpLGp9LzI1NS0wLjQ4NX17MC4yMjl9Lg0KXF0NCg0KQXR1cmFuIHlhbmcgc2FtYSBkaXRlcmFwa2FuIHBhZGEgc2VsdXJ1aCBlbGVtZW4gbWF0cmlrcy4gRGVuZ2FuIG5pbGFpIHByZXNpc2kgcGVudWggeWFuZyBrZW11ZGlhbiBkaXRhbXBpbGthbiBoaW5nZ2EgZHVhIGFuZ2thIGRlc2ltYWwsIGRpcGVyb2xlaA0KDQpcWw0KXG1hdGhiZntYfT0NClxiZWdpbntibWF0cml4fQ0KLTIuMTIgJiAtMS4wMiAmIDEuMTcgJiAwLjYyICYgLTEuNTdcXA0KLTIuMTIgJiAtMC43NSAmIDEuNDQgJiAwLjkwICYgLTEuNDNcXA0KLTIuMTIgJiAtMC43NSAmIDEuNDQgJiAwLjkwICYgLTEuNDNcXA0KLTIuMTIgJiAtMC44OCAmIDEuMTcgJiAwLjYyICYgLTEuNTdcXA0KLTEuOTggJiAtMS4zMCAmIDAuMzUgJiAtMC4yMCAmIC0xLjcxDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KIyMgMi4gUmVwcmVzZW50YXNpIGxva2FsIE1vYmlsZVZpVHYzLXYyDQoNClBhZGEgaWx1c3RyYXNpIGluaSwgbWF0cmlrcyBcKFhcKSBtZXJ1cGFrYW4gc2F0dSBpcmlzYW4ga2FuYWwgZGFyaSBmZWF0dXJlIG1hcCBtYXN1a2FuIGJsb2sgXChcbWF0aGJmIEZeeygwKX1cKSBzZXRlbGFoIG5vcm1hbGlzYXNpLiBNYXRyaWtzIFwoWFwpIG1lbWlsaWtpIGRpbWVuc2kgXCg1XHRpbWVzNVwpLiBUYWhhcCByZXByZXNlbnRhc2kgbG9rYWwgZGltdWxhaSBkZW5nYW4gKmRlcHRod2lzZSBjb252b2x1dGlvbiogXCgzXHRpbWVzM1wpLCBkaWxhbmp1dGthbiBkZW5nYW4gZnVuZ3NpIGFrdGl2YXNpIFN3aXNoLiBQcm95ZWtzaSBwb2ludHdpc2UgXCgxXHRpbWVzMVwpIGJhcnUgZGl0ZXJhcGthbiBzZXRlbGFoIGZlYXR1cmUgbWFwIGxva2FsIGRpcGVyb2xlaC4NCg0KDQojIyMgYS4gRGVwdGh3aXNlIENvbnZvbHV0aW9uDQoNClBhZGEgaWx1c3RyYXNpIGluaSwgbWF0cmlrcyBcKFxtYXRoYmZ7WH1cKSBtZXJ1cGFrYW4gc2F0dSBrYW5hbCAqZmVhdHVyZSBtYXAqIG1hc3VrYW4gYmVydWt1cmFuIFwoNVx0aW1lczVcKS4gT3BlcmFzaSAqZGVwdGh3aXNlIGNvbnZvbHV0aW9uKiBkaXRlcmFwa2FuIHNlY2FyYSBpbmRlcGVuZGVuIHBhZGEga2FuYWwgdGVyc2VidXQgbWVuZ2d1bmFrYW4ga2VybmVsIFwoM1x0aW1lczNcKSwgKnN0cmlkZSogXCgxXCksICp6ZXJvIHBhZGRpbmcqIHNlYmVzYXIgXCgxXCkgcGFkYSBzZXRpYXAgc2lzaSwgZGFuIHRhbnBhIGJpYXMuIEtlbHVhcmFuIHNlYmVsdW0gYWt0aXZhc2kgZGlueWF0YWthbiBzZWJhZ2FpIFwoXG1hdGhiZntGfV97XG1hdGhybXtkd319XCkuDQoNCk1hdHJpa3MgKmZlYXR1cmUgbWFwKiBtYXN1a2FuIHlhbmcgZGlndW5ha2FuIGFkYWxhaDoNCg0KXFsNClxtYXRoYmZ7WH0NCj0NClxiZWdpbntibWF0cml4fQ0KLTIuMTIgJiAtMS4wMiAmIDEuMTcgJiAwLjYyICYgLTEuNTdcXA0KLTIuMTIgJiAtMC43NSAmIDEuNDQgJiAwLjkwICYgLTEuNDNcXA0KLTIuMTIgJiAtMC43NSAmIDEuNDQgJiAwLjkwICYgLTEuNDNcXA0KLTIuMTIgJiAtMC44OCAmIDEuMTcgJiAwLjYyICYgLTEuNTdcXA0KLTEuOTggJiAtMS4zMCAmIDAuMzUgJiAtMC4yMCAmIC0xLjcxDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KLSAqKlBlbmFtYmFoYW4gWmVybyBQYWRkaW5nOioqDQoNClNlYmVsdW0gb3BlcmFzaSAqZGVwdGh3aXNlIGNvbnZvbHV0aW9uKiBkaWxha3VrYW4sIHNhdHUgbGFwaXNhbiBuaWxhaSBub2wgZGl0YW1iYWhrYW4gcGFkYSBrZWVtcGF0IHNpc2kgbWF0cmlrcyBtYXN1a2FuLCB5YWl0dSBzaXNpIGF0YXMsIGJhd2FoLCBraXJpLCBkYW4ga2FuYW4uIFBlbmFtYmFoYW4gKnplcm8gcGFkZGluZyogaW5pIGJlcnR1anVhbiBtZW1wZXJ0YWhhbmthbiB1a3VyYW4gc3Bhc2lhbCAqZmVhdHVyZSBtYXAqIHNldGVsYWggcHJvc2VzIGtvbnZvbHVzaS4NCg0KVWt1cmFuIGtlbHVhcmFuIGRpaGl0dW5nIG1lbmdndW5ha2FuOg0KDQpcWw0Kbw0KPQ0KXGxlZnRcbGZsb29yDQpcZnJhY3tpKzJwLWt9e3N9DQpccmlnaHRccmZsb29yKzEsDQpcXQ0KDQpkZW5nYW4gXChpXCkgbWVueWF0YWthbiB1a3VyYW4gc3Bhc2lhbCBtYXN1a2FuLCBcKHBcKSBtZXJ1cGFrYW4ganVtbGFoICpwYWRkaW5nKiBwYWRhIHNldGlhcCBzaXNpLCBcKGtcKSBtZXJ1cGFrYW4gdWt1cmFuIGtlcm5lbCwgZGFuIFwoc1wpIG1lcnVwYWthbiAqc3RyaWRlKi4NCg0KUGFkYSBpbHVzdHJhc2kgaW5pLCBkaWd1bmFrYW4gXChpPTVcKSwgXChwPTFcKSwgXChrPTNcKSwgZGFuIFwocz0xXCksIHNlaGluZ2dhOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpvDQomPQ0KXGxlZnRcbGZsb29yDQpcZnJhY3s1KzIoMSktM317MX0NClxyaWdodFxyZmxvb3IrMVxcDQomPQ0KXGxlZnRcbGZsb29yDQpcZnJhY3s0fXsxfQ0KXHJpZ2h0XHJmbG9vcisxXFwNCiY9NS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBkZW1pa2lhbiwgdWt1cmFuIHNwYXNpYWwga2VsdWFyYW4gdGV0YXAgXCg1XHRpbWVzNVwpLiBTZXRlbGFoIHBlbmFtYmFoYW4gKnplcm8gcGFkZGluZyosIHVrdXJhbiBtYXRyaWtzIG1hc3VrYW4gc2VtZW50YXJhIGJlcnViYWggZGFyaSBcKDVcdGltZXM1XCkgbWVuamFkaSBcKDdcdGltZXM3XCkuDQoNCk1hdHJpa3Mgc2V0ZWxhaCBwZW5hbWJhaGFuICp6ZXJvIHBhZGRpbmcqIGFkYWxhaDoNCg0KXFsNClxtYXRoYmZ7WH1fe1xtYXRocm17cGFkfX0NCj0NClxiZWdpbntibWF0cml4fQ0KMC4wMCAmIDAuMDAgJiAwLjAwICYgMC4wMCAmIDAuMDAgJiAwLjAwICYgMC4wMFxcDQowLjAwICYgLTIuMTIgJiAtMS4wMiAmIDEuMTcgJiAwLjYyICYgLTEuNTcgJiAwLjAwXFwNCjAuMDAgJiAtMi4xMiAmIC0wLjc1ICYgMS40NCAmIDAuOTAgJiAtMS40MyAmIDAuMDBcXA0KMC4wMCAmIC0yLjEyICYgLTAuNzUgJiAxLjQ0ICYgMC45MCAmIC0xLjQzICYgMC4wMFxcDQowLjAwICYgLTIuMTIgJiAtMC44OCAmIDEuMTcgJiAwLjYyICYgLTEuNTcgJiAwLjAwXFwNCjAuMDAgJiAtMS45OCAmIC0xLjMwICYgMC4zNSAmIC0wLjIwICYgLTEuNzEgJiAwLjAwXFwNCjAuMDAgJiAwLjAwICYgMC4wMCAmIDAuMDAgJiAwLjAwICYgMC4wMCAmIDAuMDANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQotICoqRmlsdGVyIGF0YXUgQm9ib3QgS2VybmVsIERlcHRod2lzZSBDb252b2x1dGlvbjoqKg0KDQpQYWRhIGlsdXN0cmFzaSBpbmksIG1hdHJpa3MgYm9ib3Qga2VybmVsICpkZXB0aHdpc2UgY29udm9sdXRpb24qIGRpdGV0YXBrYW4gc2ViYWdhaToNCg0KXFsNClxtYXRoYmZ7V31fe1xtYXRocm17ZHd9fQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjA1ICYgMC4xMCAmIDAuMDVcXA0KMC4xMCAmIDAuNDAgJiAwLjEwXFwNCjAuMDUgJiAwLjEwICYgMC4wNQ0KXGVuZHtibWF0cml4fS4NClxdDQoNCktlcm5lbCB0ZXJzZWJ1dCBiZXJ1a3VyYW4gXCgzXHRpbWVzM1wpLiBCb2JvdCBwdXNhdCBzZWJlc2FyIFwoMC40MFwpIG1lbWJlcmlrYW4ga29udHJpYnVzaSB0ZXJiZXNhciBkYXJpIGVsZW1lbiBwdXNhdCwgc2VkYW5na2FuIGVsZW1lbi1lbGVtZW4gZGkgc2VraXRhcm55YSBtZW1iZXJpa2FuIGtvbnRyaWJ1c2kgbWVsYWx1aSBib2JvdCBcKDAuMDVcKSBkYW4gXCgwLjEwXCkuDQoNClNldGlhcCBoYXNpbCBrb252b2x1c2kgZGlwZXJvbGVoIG1lbGFsdWkgcGVya2FsaWFuIHNlbWJpbGFuIGVsZW1lbiBwYWRhIGFyZWEgKmZlYXR1cmUgbWFwKiBkZW5nYW4gc2VtYmlsYW4gYm9ib3Qga2VybmVsIHlhbmcgYmVyc2VzdWFpYW4sIGtlbXVkaWFuIHNlbHVydWggaGFzaWwgcGVya2FsaWFuIGRpanVtbGFoa2FuLg0KDQotICoqUnVtdXM6KioNCg0KU2VjYXJhIHVtdW0sIG9wZXJhc2kgKmRlcHRod2lzZSBjb252b2x1dGlvbiogcGFkYSAqZmVhdHVyZSBtYXAqIG11bHRpa2FuYWwgZGlueWF0YWthbiBzZWJhZ2FpOg0KDQpcWw0KRl97XG1hdGhybXtkd30sayxsLG19DQo9DQpcc3VtX3t1PTF9XnszfQ0KXHN1bV97dj0xfV57M30NCldfe1xtYXRocm17ZHd9LHUsdixtfQ0KWF97XG1hdGhybXtwYWR9LGsrdS0xLGwrdi0xLG19LA0KXF0NCg0KZGVuZ2FuIFwobVwpIG1lbnlhdGFrYW4gaW5kZWtzIGthbmFsLCBzZWRhbmdrYW4gXCh1XCkgZGFuIFwodlwpIG1lcnVwYWthbiBpbmRla3MgYmFyaXMgZGFuIGtvbG9tIGtlcm5lbC4NCg0KUGFkYSBpbHVzdHJhc2kgc2F0dSBrYW5hbCwgcGVyaGl0dW5nYW4gc2V0aWFwIGVsZW1lbiBrZWx1YXJhbiBkaW55YXRha2FuIHNlYmFnYWk6DQoNClxbDQpGX3tcbWF0aHJte2R3fSxrLGx9DQo9DQpcc3VtX3t1PTF9XnszfQ0KXHN1bV97dj0xfV57M30NCldfe1xtYXRocm17ZHd9LHUsdn0NClhfe1xtYXRocm17cGFkfSxrK3UtMSxsK3YtMX0sDQpcXQ0KDQpkZW5nYW4gXChrLGw9MSwyLFxsZG90cyw1XCkuDQoNClBhZGEgc2V0aWFwIHBvc2lzaSwga2VybmVsIG1lbmNha3VwIGFyZWEgYmVydWt1cmFuIFwoM1x0aW1lczNcKS4gS2FyZW5hICpzdHJpZGUqIGJlcm5pbGFpIFwoMVwpLCBrZXJuZWwgYmVyZ2VzZXIgc2F0dSBrb2xvbSBrZSBrYW5hbiB1bnR1ayBtZW5naGl0dW5nIGVsZW1lbiBiZXJpa3V0bnlhIHBhZGEgYmFyaXMga2VsdWFyYW4geWFuZyBzYW1hLiBTZXRlbGFoIG1lbmNhcGFpIHBvc2lzaSB0ZXJha2hpciBwYWRhIGJhcmlzIHRlcnNlYnV0LCBrZXJuZWwga2VtYmFsaSBrZSBzaXNpIGtpcmkgZGFuIGJlcmdlc2VyIHNhdHUgYmFyaXMga2UgYmF3YWguDQoNCi0gKipDb250b2ggUGVyaGl0dW5nYW4gS29udm9sdXNpOioqDQoNCioqMS4gUGVyaGl0dW5nYW4gZWxlbWVuIHBhZGEgcG9zaXNpIFwoKDEsMSlcKSoqDQoNClVudHVrIG1lbmdoYXNpbGthbiBlbGVtZW4gcGVydGFtYSBkYXJpICpmZWF0dXJlIG1hcCoga2VsdWFyYW4sIGtlcm5lbCBkaXRlbXBhdGthbiBwYWRhIGFyZWEgXCgzXHRpbWVzM1wpIGRpIHBvam9rIGtpcmkgYXRhcyBtYXRyaWtzIHlhbmcgdGVsYWggZGliZXJpICp6ZXJvIHBhZGRpbmcqLg0KDQpBcmVhICpmZWF0dXJlIG1hcCogeWFuZyBkaXByb3NlcyBhZGFsYWg6DQoNClxbDQpcYmVnaW57Ym1hdHJpeH0NCjAuMDAgJiAwLjAwICYgMC4wMFxcDQowLjAwICYgLTIuMTIgJiAtMS4wMlxcDQowLjAwICYgLTIuMTIgJiAtMC43NQ0KXGVuZHtibWF0cml4fS4NClxdDQoNCkFyZWEgdGVyc2VidXQgZGlrYWxpa2FuIHNlY2FyYSBlbGVtZW4gZGVtaSBlbGVtZW4gZGVuZ2FuIGJvYm90IGtlcm5lbCBcKFxtYXRoYmZ7V31fe1xtYXRocm17ZHd9fVwpLCBrZW11ZGlhbiBzZWx1cnVoIGhhc2lsIHBlcmthbGlhbiBkaWp1bWxhaGthbiBzZWJhZ2FpIGJlcmlrdXQ6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NCkZfe1xtYXRocm17ZHd9LDEsMX0NCj17fSYNCigwLjAwKSgwLjA1KQ0KKygwLjAwKSgwLjEwKQ0KKygwLjAwKSgwLjA1KVxcDQomKygwLjAwKSgwLjEwKQ0KKygtMi4xMikoMC40MCkNCisoLTEuMDIpKDAuMTApXFwNCiYrKDAuMDApKDAuMDUpDQorKC0yLjEyKSgwLjEwKQ0KKygtMC43NSkoMC4wNSlcXA0KPXt9Jg0KLTAuODQ4LTAuMTAyLTAuMjEyLTAuMDM3NVxcDQo9e30mLTEuMTk5NS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBwZW1idWxhdGFuIGR1YSBhbmdrYSBkZXNpbWFsLCBoYXNpbCBwZXJoaXR1bmdhbiB0ZXJzZWJ1dCBhZGFsYWg6DQoNClxbDQpGX3tcbWF0aHJte2R3fSwxLDF9PS0xLjIwLg0KXF0NCg0KKioyLiBQZXJoaXR1bmdhbiBlbGVtZW4gcGFkYSBwb3Npc2kgXCgoMiwyKVwpKioNCg0KVW50dWsgbWVuZ2hpdHVuZyBlbGVtZW4gcGFkYSBwb3Npc2kgXCgoMiwyKVwpLCBrZXJuZWwgZGl0ZW1wYXRrYW4gcGFkYSBhcmVhIHlhbmcgZGltdWxhaSBkYXJpIGJhcmlzIGtlZHVhIGRhbiBrb2xvbSBrZWR1YSBtYXRyaWtzIHNldGVsYWggKnBhZGRpbmcqLiBQb3Npc2kgaW5pIGJlcmFkYSBzYXR1IGJhcmlzIGRpIGJhd2FoIGRhbiBzYXR1IGtvbG9tIGRpIGthbmFuIGRpYmFuZGluZ2thbiBwb3Npc2kgYXdhbC4NCg0KQXJlYSAqZmVhdHVyZSBtYXAqIHlhbmcgZGlwcm9zZXMgYWRhbGFoOg0KDQpcWw0KXGJlZ2lue2JtYXRyaXh9DQotMi4xMiAmIC0xLjAyICYgMS4xN1xcDQotMi4xMiAmIC0wLjc1ICYgMS40NFxcDQotMi4xMiAmIC0wLjc1ICYgMS40NA0KXGVuZHtibWF0cml4fS4NClxdDQoNClBlcmhpdHVuZ2FuIGtvbnZvbHVzaSBkaWxha3VrYW4gbWVuZ2d1bmFrYW4gYm9ib3Qga2VybmVsIHlhbmcgc2FtYToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KRl97XG1hdGhybXtkd30sMiwyfQ0KPXt9Jg0KKC0yLjEyKSgwLjA1KQ0KKygtMS4wMikoMC4xMCkNCisoMS4xNykoMC4wNSlcXA0KJisoLTIuMTIpKDAuMTApDQorKC0wLjc1KSgwLjQwKQ0KKygxLjQ0KSgwLjEwKVxcDQomKygtMi4xMikoMC4wNSkNCisoLTAuNzUpKDAuMTApDQorKDEuNDQpKDAuMDUpXFwNCj17fSYNCi0wLjEwNi0wLjEwMiswLjA1ODVcXA0KJi0wLjIxMi0wLjMwMCswLjE0NFxcDQomLTAuMTA2LTAuMDc1KzAuMDcyXFwNCj17fSYtMC42MjY1Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KSGFzaWwgcGVyaGl0dW5nYW4gZGFyaSBuaWxhaSBtYXN1a2FuIGR1YSBkZXNpbWFsIGFkYWxhaCBcKC0wLjYyNjVcKS4gUGFkYSBtYXRyaWtzIGlsdXN0cmFzaSBzZWJlbHVtbnlhLCBlbGVtZW4gaW5pIHRlcmNhdGF0IHNlYmVzYXIgXCgtMC42MlwpLiBOaWxhaSBwYWRhIG1hdHJpa3MgZGlwZXJ0YWhhbmthbiBzZW1lbnRhcmEgaGluZ2dhIHZhbGlkYXNpIG51bWVyaWsgbWVueWVsdXJ1aCBkaWxha3VrYW4uDQoNClByb3NlZHVyIHlhbmcgc2FtYSBkaXRlcmFwa2FuIHBhZGEgc2VsdXJ1aCBwb3Npc2kga2VybmVsLiBQYWRhIHNldGlhcCBwb3Npc2ksIGVsZW1lbi1lbGVtZW4gZGFsYW0gYXJlYSBrb252b2x1c2kgZGlrYWxpa2FuIGRlbmdhbiBib2JvdCBrZXJuZWwgeWFuZyBiZXJzZXN1YWlhbiwga2VtdWRpYW4gc2VsdXJ1aCBoYXNpbCBwZXJrYWxpYW4gZGlqdW1sYWhrYW4gdW50dWsgbWVtYmVudHVrIHNhdHUgZWxlbWVuICpmZWF0dXJlIG1hcCoga2VsdWFyYW4uDQoNCk1hdHJpa3MgaGFzaWwgKmRlcHRod2lzZSBjb252b2x1dGlvbiogeWFuZyBkaWd1bmFrYW4gc2VtZW50YXJhIGRhbGFtIGlsdXN0cmFzaSBpbmkgYWRhbGFoOg0KDQpcWw0KXG1hdGhiZntGfV97XG1hdGhybXtkd319DQo9DQpcYmVnaW57Ym1hdHJpeH0NCi0xLjIwICYgLTAuNjEgJiAwLjU4ICYgMC4zMCAmIC0wLjY2XFwNCi0xLjQzICYgLTAuNjIgJiAwLjg0ICYgMC40OSAmIC0wLjcxXFwNCi0xLjQzICYgLTAuNjEgJiAwLjg1ICYgMC40OSAmIC0wLjcxXFwNCi0xLjQ1ICYgLTAuNzcgJiAwLjU1ICYgMC4yMSAmIC0wLjg0XFwNCi0xLjE4ICYgLTAuODIgJiAwLjA5ICYgLTAuMTcgJiAtMC44Mw0KXGVuZHtibWF0cml4fS4NClxdDQoNCk1hdHJpa3MgdGVyc2VidXQgbWVtcGVydGFoYW5rYW4gbmlsYWkgcGFkYSBpbHVzdHJhc2kgc2ViZWx1bW55YSBkYW4gYWthbiBkaXBlcmlrc2Ega2VtYmFsaSBtZWxhbHVpIHBlcmhpdHVuZ2FuIG51bWVyaWsgdW50dWsgbWVtYXN0aWthbiBrb25zaXN0ZW5zaSBzZWx1cnVoIHRhaGFwYW4uDQoNCktlbHVhcmFuICpkZXB0aHdpc2UgY29udm9sdXRpb24qIHNlbGFuanV0bnlhIGRpcHJvc2VzIG1lbmdndW5ha2FuIGZ1bmdzaSBha3RpdmFzaSBTd2lzaCB1bnR1ayBtZW1iZW50dWsgKmZlYXR1cmUgbWFwKiBsb2thbCBcKFxtYXRoYmZ7TH1cKS4NCg0KLSAqKlJ1bXVzIEFrdGl2YXNpIFN3aXNoOioqDQoNCkZ1bmdzaSBha3RpdmFzaSBTd2lzaCBkaXRlcmFwa2FuIHNlY2FyYSBlbGVtZW4gZGVtaSBlbGVtZW4gcGFkYSBtYXRyaWtzIGhhc2lsICpkZXB0aHdpc2UgY29udm9sdXRpb24qOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpMX3tpLGp9DQomPQ0KXG9wZXJhdG9ybmFtZXtTd2lzaH0NClxsZWZ0KA0KRl97XG1hdGhybXtkd30saSxqfQ0KXHJpZ2h0KVxcDQomPQ0KXGZyYWN7Rl97XG1hdGhybXtkd30saSxqfX0NCnsxK2Veey1GX3tcbWF0aHJte2R3fSxpLGp9fX0uDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQotICoqQ29udG9oIFBlcmhpdHVuZ2FuIHBhZGEgUG9zaXNpIFwoKDEsMSlcKToqKg0KDQpVbnR1ayBlbGVtZW4gcGFkYSBwb3Npc2kgXCgoMSwxKVwpLCBuaWxhaSB5YW5nIGRpZ3VuYWthbiBzZXN1YWkgZGVuZ2FuIG1hdHJpa3MgaGFzaWwgKmRlcHRod2lzZSBjb252b2x1dGlvbiosIHlhaXR1IFwoLTEuMjBcKS4NCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KTF97MSwxfQ0KJj0NClxvcGVyYXRvcm5hbWV7U3dpc2h9KC0xLjIwKVxcDQomPQ0KXGZyYWN7LTEuMjB9ezErZV57LSgtMS4yMCl9fVxcDQomPQ0KXGZyYWN7LTEuMjB9ezErZV57MS4yMH19XFwNCiY9DQpcZnJhY3stMS4yMH17MSszLjMyfVxcDQomPS0wLjI4Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KRGVuZ2FuIG1lbmVyYXBrYW4gZnVuZ3NpIGFrdGl2YXNpIFN3aXNoIHBhZGEgc2VsdXJ1aCBlbGVtZW4gbWF0cmlrcyBoYXNpbCAqZGVwdGh3aXNlIGNvbnZvbHV0aW9uKiwgZGlwZXJvbGVoICpmZWF0dXJlIG1hcCogbG9rYWw6DQoNClxbDQpcbWF0aGJme0x9DQo9DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjI4ICYgLTAuMjIgJiAwLjM3ICYgMC4xNyAmIC0wLjIzXFwNCi0wLjI4ICYgLTAuMjIgJiAwLjU5ICYgMC4zMSAmIC0wLjIzXFwNCi0wLjI4ICYgLTAuMjIgJiAwLjU5ICYgMC4zMSAmIC0wLjIzXFwNCi0wLjI4ICYgLTAuMjQgJiAwLjM1ICYgMC4xMiAmIC0wLjI1XFwNCi0wLjI4ICYgLTAuMjUgJiAwLjA1ICYgLTAuMDggJiAtMC4yNQ0KXGVuZHtibWF0cml4fS4NClxdDQoNCk1hdHJpa3MgXChcbWF0aGJme0x9XCkgbWVydXBha2FuIHJlcHJlc2VudGFzaSBsb2thbCBzZXRlbGFoIHBlbmVyYXBhbiBmdW5nc2kgYWt0aXZhc2kgU3dpc2ggZGFuIGRpZ3VuYWthbiBzZWJhZ2FpIG1hc3VrYW4gcGFkYSB0YWhhcCBiZXJpa3V0bnlhLiBOaWxhaSBtYXRyaWtzIHRlcnNlYnV0IGRpcGVydGFoYW5rYW4gc2VzdWFpIGlsdXN0cmFzaSBzZWJlbHVtbnlhIGhpbmdnYSBkaWxha3VrYW4gdmFsaWRhc2kgbnVtZXJpayBzZWNhcmEgbWVueWVsdXJ1aC4NCg0KDQojIyMgYi4gUG9pbnR3aXNlIENvbnZvbHV0aW9uIGRhbiBUb2tlbmlzYXNpDQoNCipGZWF0dXJlIG1hcCogbG9rYWwgXChcbWF0aGJme0x9XCkgbWVtaWxpa2kgc2F0dSBrYW5hbCBkZW5nYW4gZGltZW5zaSBcKDVcdGltZXM1XHRpbWVzMVwpLiBTZWxhbmp1dG55YSwgKnBvaW50d2lzZSBjb252b2x1dGlvbiogXCgxXHRpbWVzMVwpIGRpdGVyYXBrYW4gc2VjYXJhIGluZGVwZW5kZW4gcGFkYSBzZXRpYXAgcG9zaXNpIHNwYXNpYWwuIE9wZXJhc2kgaW5pIHRpZGFrIG1lbGliYXRrYW4gcGlrc2VsIHRldGFuZ2dhLCB0ZXRhcGkgbWVtcHJveWVrc2lrYW4gc2F0dSBrYW5hbCBtYXN1a2FuIG1lbmphZGkgZHVhIGthbmFsIGtlbHVhcmFuIHlhbmcgbWVtYmVudHVrIHZla3RvciB0b2tlbi4NCg0KLSAqKkJvYm90ICpwb2ludHdpc2UgY29udm9sdXRpb24qOioqDQoNClxbDQpcbWF0aGJme1d9X3tcbWF0aHJte3B3fX1eeyhcbWF0aHJte3Rva30pfQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjgwICYgLTAuNjANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQpCb2JvdCBcKFxtYXRoYmZ7V31fe1xtYXRocm17cHd9fV57KFxtYXRocm17dG9rfSl9XCkgYmVyZGltZW5zaSBcKDFcdGltZXMyXCkuIE9sZWgga2FyZW5hIGl0dSwgc2V0aWFwIG5pbGFpICpmZWF0dXJlIG1hcCogbG9rYWwgZGlwcm95ZWtzaWthbiBtZW5qYWRpIHZla3RvciBkZW5nYW4gZHVhIGVsZW1lbi4NCg0KLSAqKlJ1bXVzOioqDQoNClVudHVrIHNldGlhcCBwb3Npc2kgc3Bhc2lhbCBcKChpLGopXCksIHRva2VuIGtlLVwodFwpIGRpcnVtdXNrYW4gc2ViYWdhaToNCg0KXFsNClRfe3Qsbn0NCj0NClxzdW1fe209MX1ee0NfTH0NCldfe1xtYXRocm17cHd9LG0sbn1eeyhcbWF0aHJte3Rva30pfQ0KTF97aSxqLG19LA0KXHFxdWFkDQp0PTUoaS0xKStqLg0KXF0NCg0KUGFkYSBpbHVzdHJhc2kgaW5pLCBcKENfTD0xXCkgZGFuIFwobj0xLDJcKS4gT2xlaCBrYXJlbmEgaXR1LCBwZXJoaXR1bmdhbiB0b2tlbiBkYXBhdCBkaXNlZGVyaGFuYWthbiBtZW5qYWRpOg0KDQpcWw0KXG1hdGhiZntUfV90DQo9DQpMX3tpLGp9DQpcbWF0aGJme1d9X3tcbWF0aHJte3B3fX1eeyhcbWF0aHJte3Rva30pfS4NClxdDQoNCk1hdHJpa3MgdG9rZW4gXChcbWF0aGJme1R9XCkgYmVyZGltZW5zaSBcKDI1XHRpbWVzMlwpLg0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuIHBhZGEgcG9zaXNpIFwoKDEsMSlcKToqKg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcbWF0aGJme1R9XzENCiY9DQpMX3sxLDF9DQpcbWF0aGJme1d9X3tcbWF0aHJte3B3fX1eeyhcbWF0aHJte3Rva30pfVxcDQomPQ0KKC0wLjI4KQ0KXGJlZ2lue2JtYXRyaXh9DQowLjgwICYgLTAuNjANClxlbmR7Ym1hdHJpeH1cXA0KJj0NClxiZWdpbntibWF0cml4fQ0KLTAuMjIgJiAwLjE3DQpcZW5ke2JtYXRyaXh9Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KUG9zaXNpIHNwYXNpYWwgXCgoMSwxKVwpIG1lcnVwYWthbiB0b2tlbiBwZXJ0YW1hIGthcmVuYToNCg0KXFsNCnQ9NSgxLTEpKzE9MS4NClxdDQoNCkRlbmdhbiBwZXJoaXR1bmdhbiB5YW5nIHNhbWEgcGFkYSBzZWx1cnVoIHBvc2lzaSBiZXJkYXNhcmthbiB1cnV0YW4gcmFzdGVyIGRhcmkga2lyaSBrZSBrYW5hbiBkYW4gZGFyaSBhdGFzIGtlIGJhd2FoLCBkaXBlcm9sZWggbWF0cmlrcyB0b2tlbjoNCg0KXFsNClxtYXRoYmZ7VH0NCj0NClxiZWdpbntibWF0cml4fQ0KLTAuMjIgJiAwLjE3XFwNCi0wLjE3ICYgMC4xM1xcDQowLjMwICYgLTAuMjJcXA0KMC4xNCAmIC0wLjEwXFwNCi0wLjE4ICYgMC4xNFxcDQotMC4yMiAmIDAuMTdcXA0KLTAuMTcgJiAwLjEzXFwNCjAuNDcgJiAtMC4zNVxcDQowLjI0ICYgLTAuMThcXA0KLTAuMTkgJiAwLjE0XFwNCi0wLjIyICYgMC4xN1xcDQotMC4xNyAmIDAuMTNcXA0KMC40OCAmIC0wLjM2XFwNCjAuMjQgJiAtMC4xOFxcDQotMC4xOSAmIDAuMTRcXA0KLTAuMjIgJiAwLjE3XFwNCi0wLjE5ICYgMC4xNVxcDQowLjI4ICYgLTAuMjFcXA0KMC4wOSAmIC0wLjA3XFwNCi0wLjIwICYgMC4xNVxcDQotMC4yMiAmIDAuMTdcXA0KLTAuMjAgJiAwLjE1XFwNCjAuMDQgJiAtMC4wM1xcDQotMC4wNiAmIDAuMDVcXA0KLTAuMjAgJiAwLjE1DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KDQojIyAzLiBMaW5lYXIgVHJhbnNmb3JtZXIgKCpTZXBhcmFibGUgU2VsZi1BdHRlbnRpb24qKQ0KDQpQYWRhIE1vYmlsZVZpVHYzLXYyLCBtYXRyaWtzIHRva2VuIFwoXG1hdGhiZntUfVwpIGRpcHJvc2VzIG1lbmdndW5ha2FuIG1la2FuaXNtZSAqc2VwYXJhYmxlIHNlbGYtYXR0ZW50aW9uKiAoU1NBKS4gQmVyYmVkYSBkZW5nYW4gVHJhbnNmb3JtZXIgdjEgeWFuZyBtZW5naGl0dW5nIGh1YnVuZ2FuIHBlcmhhdGlhbiBhbnRhcnNldGlhcCBwYXNhbmdhbiB0b2tlbiwgU1NBIG1lbWJlbnR1ayB2ZWt0b3Iga29lZmlzaWVuIGtvbnRla3MgdW50dWsgbWVyYW5na3VtIGluZm9ybWFzaSBnbG9iYWwgZGFyaSBzZWx1cnVoIHRva2VuLiBLZWx1YXJhbiBTU0Ega2VtdWRpYW4gZGlnYWJ1bmdrYW4gZGVuZ2FuIHRva2VuIG1hc3VrYW4gbWVsYWx1aSAqcmVzaWR1YWwgY29ubmVjdGlvbiogZGFuIGRpcHJvc2VzIG9sZWggKmZlZWQtZm9yd2FyZCBuZXR3b3JrKi4NCg0KUGFkYSBmb3JtdWxhc2kgU1NBIGRpIEJhYiBJSSwgXChcbWF0aGJme1h9XCkgbWVueWF0YWthbiBtYXRyaWtzIHRva2VuIG1hc3VrYW4gc2VjYXJhIHVtdW0uIERhbGFtIGlsdXN0cmFzaSBwZXJoaXR1bmdhbiBpbmksIG1hdHJpa3MgdGVyc2VidXQgZGlyZWFsaXNhc2lrYW4gb2xlaCBcKFxtYXRoYmZ7VH1cKSwgc2VoaW5nZ2E6DQoNClxbDQpcbWF0aGJme1h9DQo9DQpcbWF0aGJme1R9Lg0KXF0NCg0KIyMjIGEuIFByb3lla3NpICpBdHRlbnRpb24gU2NvcmUqDQoNClNldGlhcCB0b2tlbiBwYWRhIFwoXG1hdGhiZntUfVwpIGRpcHJveWVrc2lrYW4gbWVuamFkaSBzYXR1IG5pbGFpICphdHRlbnRpb24gc2NvcmUqIG1lbmdndW5ha2FuIG1hdHJpa3MgYm9ib3QgXChcbWF0aGJme1d9XntJfVwpLiBOaWxhaSAqYXR0ZW50aW9uIHNjb3JlKiBzZWJlbHVtIHByb3NlcyBzb2Z0bWF4IGRpbnlhdGFrYW4gc2ViYWdhaSB2ZWt0b3IgXChcbWF0aGJme3N9XCkuDQoNCi0gKipCb2JvdCBwcm95ZWtzaSAqYXR0ZW50aW9uIHNjb3JlKjoqKg0KDQpcWw0KXG1hdGhiZntXfV57SX0NCj0NClxiZWdpbntibWF0cml4fQ0KMC42MFxcDQotMC4zNQ0KXGVuZHtibWF0cml4fS4NClxdDQoNCk1hdHJpa3MgXChcbWF0aGJme1d9XntJfVwpIGJlcnVrdXJhbiBcKDJcdGltZXMxXCkuIE9sZWgga2FyZW5hIGl0dSwgdmVrdG9yICphdHRlbnRpb24gc2NvcmUqIFwoXG1hdGhiZntzfVwpIGJlcnVrdXJhbiBcKDI1XHRpbWVzMVwpLg0KDQotICoqUnVtdXM6KioNCg0KXFsNClxtYXRoYmZ7c30NCj0NClxtYXRoYmZ7VH1cbWF0aGJme1d9XntJfS4NClxdDQoNClNlY2FyYSBlbGVtZW4sICphdHRlbnRpb24gc2NvcmUqIHRva2VuIGtlLVwodFwpIGRpaGl0dW5nIHNlYmFnYWk6DQoNClxbDQpzX3QNCj0NClxzdW1fe249MX1eezJ9DQpUX3t0LG59V197biwxfV57SX0uDQpcXQ0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuIHRva2VuIHBlcnRhbWE6KioNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0Kc18xDQomPQ0KXGJlZ2lue2JtYXRyaXh9DQotMC4yMiAmIDAuMTcNClxlbmR7Ym1hdHJpeH0NClxiZWdpbntibWF0cml4fQ0KMC42MFxcDQotMC4zNQ0KXGVuZHtibWF0cml4fVxcDQomPQ0KMC42MCgtMC4yMiktMC4zNSgwLjE3KVxcDQomPQ0KLTAuMTMyLTAuMDU5NVxcDQomPQ0KLTAuMTkuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gYXR1cmFuIHlhbmcgc2FtYSwgZGlwZXJvbGVoIHZla3RvciAqYXR0ZW50aW9uIHNjb3JlKiBzZWJhZ2FpIGJlcmlrdXQuDQoNClxbDQpcbWF0aGJme3N9DQo9DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjE5XFwNCi0wLjE1XFwNCjAuMjZcXA0KMC4xMlxcDQotMC4xNlxcDQotMC4xOVxcDQotMC4xNVxcDQowLjQwXFwNCjAuMjFcXA0KLTAuMTZcXA0KLTAuMTlcXA0KLTAuMTVcXA0KMC40MVxcDQowLjIxXFwNCi0wLjE2XFwNCi0wLjE5XFwNCi0wLjE3XFwNCjAuMjRcXA0KMC4wOFxcDQotMC4xN1xcDQotMC4xOVxcDQotMC4xN1xcDQowLjAzXFwNCi0wLjA1XFwNCi0wLjE3DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KDQojIyMgYi4gS29lZmlzaWVuIGtvbnRla3MNCg0KTmlsYWkgYXR0ZW50aW9uIHNjb3JlIGtlbXVkaWFuIGRpbm9ybWFsaXNhc2kgbWVuZ2d1bmFrYW4gc29mdG1heCB1bnR1ayBtZW5naGFzaWxrYW4ga29lZmlzaWVuIGtvbnRla3MgXChjX3NcKS4gSnVtbGFoIHNlbHVydWgga29lZmlzaWVuIGtvbnRla3MgYmVybmlsYWkgc2F0dS4gTmlsYWkgYXR0ZW50aW9uIHNjb3JlIFwocVwpIGRpbm9ybWFsaXNhc2kgbWVuZ2d1bmFrYW4gZnVuZ3NpIHNvZnRtYXggdW50dWsgbWVuZ2hhc2lsa2FuIGtvZWZpc2llbiBrb250ZWtzIFwoY19zXCkuIE5vdGFzaSBcKGVee3FfdH1cKSBtZW55YXRha2FuIG5pbGFpIGVrc3BvbmVuc2lhbCBkYXJpIGF0dGVudGlvbiBzY29yZSB0b2tlbiB5YW5nIHNlZGFuZyBkaWhpdHVuZywgeWFpdHUgdG9rZW4ga2UtXCh0XCkuIFNlbWVudGFyYSBpdHUsIFwoXHN1bV97cj0xfV57MjV9ZV57cV9yfVwpIG1lbnlhdGFrYW4ganVtbGFoIG5pbGFpIGVrc3BvbmVuc2lhbCBkYXJpIHNlbHVydWggMjUgdG9rZW4uIERlbmdhbiBkZW1pa2lhbiwgc2V0aWFwIG5pbGFpIFwoY197cyx0fVwpIG1lbnVuanVra2FuIHByb3BvcnNpIGtvbnRyaWJ1c2kgdG9rZW4ga2UtXCh0XCkgdGVyaGFkYXAgcGVtYmVudHVrYW4gdmVrdG9yIGtvbnRla3MgZ2xvYmFsLCBkYW4ganVtbGFoIHNlbHVydWgga29lZmlzaWVuIGtvbnRla3MgYmVybmlsYWkgc2F0dS4NCg0KDQotICoqUnVtdXM6KioNCg0KXFsNCmNfe3MsdH0NCj0NClxmcmFje2Vee3FfdH19DQp7XHN1bV97cj0xfV57MjV9ZV57cV9yfX0uDQpcXQ0KDQotICoqQ29udG9oIHRva2VuIHBlcnRhbWE6KioNCg0KVW50dWsgbWVuZ2hpdHVuZyBrb2VmaXNpZW4ga29udGVrcyB0b2tlbiBwZXJ0YW1hLCBuaWxhaSBla3Nwb25lbnNpYWwgKmF0dGVudGlvbiBzY29yZSogdG9rZW4gcGVydGFtYSBkaWJhZ2kgZGVuZ2FuIGp1bWxhaCBuaWxhaSBla3Nwb25lbnNpYWwgZGFyaSBzZWx1cnVoIDI1IHRva2VuIHNlYmFnYWkgYmVyaWt1dC4NCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KY197cywxfQ0KJj0NClxmcmFje2Veey0wLjE5MTZ9fQ0Ke2Veey0wLjE5MTZ9K2Veey0wLjE0ODV9K1xjZG90cytlXnstMC4xNzM4fX1cXA0KJj0NClxmcmFjezAuODI1Nn0NCnswLjgyNTYrMC44NjIwK1xjZG90cyswLjg0MDV9XFwNCiY9DQpcZnJhY3swLjgyNTZ9ezI0Ljg3MzR9XFwNCiY9DQowLjAzMzJcXA0KJj0NCjAuMDMuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gYXR1cmFuIHlhbmcgc2FtYSwgZGlwZXJvbGVoIGtvZWZpc2llbiBrb250ZWtzIHNlYmFnYWkgYmVyaWt1dC4NCg0KXFsNCmNfcz0NClxiZWdpbntibWF0cml4fQ0KMC4wM1xcDQowLjAzXFwNCjAuMDVcXA0KMC4wNVxcDQowLjAzXFwNCjAuMDNcXA0KMC4wM1xcDQowLjA3XFwNCjAuMDVcXA0KMC4wM1xcDQowLjAzXFwNCjAuMDNcXA0KMC4wN1xcDQowLjA1XFwNCjAuMDNcXA0KMC4wM1xcDQowLjAzXFwNCjAuMDZcXA0KMC4wNFxcDQowLjAzXFwNCjAuMDNcXA0KMC4wM1xcDQowLjA0XFwNCjAuMDRcXA0KMC4wMw0KXGVuZHtibWF0cml4fS4NClxdDQoNCiMjIyBjLiBQcm95ZWtzaSAqS2V5Kg0KDQpQYWRhIGZvcm11bGFzaSAqc2VwYXJhYmxlIHNlbGYtYXR0ZW50aW9uKiwgbWF0cmlrcyAqa2V5KiBkaWJlbnR1ayBkYXJpIG1hdHJpa3MgdG9rZW4gbWFzdWthbiBtZW5nZ3VuYWthbiBib2JvdCBcKFxtYXRoYmZ7V31ee0t9XCkuIERhbGFtIGlsdXN0cmFzaSBpbmksIG1hdHJpa3MgdG9rZW4gXChcbWF0aGJme1R9XCkgbWVyZWFsaXNhc2lrYW4gXChcbWF0aGJme1h9XCkgcGFkYSBQZXJzYW1hYW4gKDIuMjEpLg0KDQotICoqQm9ib3QgcHJveWVrc2kgKmtleSo6KioNCg0KXFsNClxtYXRoYmZ7V31ee0t9DQo9DQpcYmVnaW57Ym1hdHJpeH0NCjAuNTUgJiAwLjEwXFwNCi0wLjE1ICYgMC40NQ0KXGVuZHtibWF0cml4fS4NClxdDQoNCk1hdHJpa3MgXChcbWF0aGJme1d9XntLfVwpIGJlcnVrdXJhbiBcKDJcdGltZXMyXCkuDQoNCi0gKipSdW11czoqKg0KDQpcWw0KXG1hdGhiZntLfQ0KPQ0KXG1hdGhiZntUfVxtYXRoYmZ7V31ee0t9Lg0KXF0NCg0KTWF0cmlrcyAqa2V5KiBcKFxtYXRoYmZ7S31cKSBiZXJ1a3VyYW4gXCgyNVx0aW1lczJcKS4NCg0KU2VjYXJhIGVsZW1lbiwga29tcG9uZW4gKmtleSoga2UtXChuXCkgcGFkYSB0b2tlbiBrZS1cKHRcKSBkaWhpdHVuZyBzZWJhZ2FpOg0KDQpcWw0KS197dCxufQ0KPQ0KXHN1bV97bT0xfV57Mn0NClRfe3QsbX1XX3ttLG59XntLfS4NClxdDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gdG9rZW4gcGVydGFtYToqKg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcbWF0aGJme0t9XzENCiY9DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjIyICYgMC4xNw0KXGVuZHtibWF0cml4fQ0KXGJlZ2lue2JtYXRyaXh9DQowLjU1ICYgMC4xMFxcDQotMC4xNSAmIDAuNDUNClxlbmR7Ym1hdHJpeH1cXA0KJj0NClxiZWdpbntibWF0cml4fQ0KKC0wLjIyKSgwLjU1KSsoMC4xNykoLTAuMTUpICYNCigtMC4yMikoMC4xMCkrKDAuMTcpKDAuNDUpDQpcZW5ke2JtYXRyaXh9XFwNCiY9DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjE0NjUgJiAwLjA1NDUNClxlbmR7Ym1hdHJpeH1cXA0KJj0NClxiZWdpbntibWF0cml4fQ0KLTAuMTUgJiAwLjA1DQpcZW5ke2JtYXRyaXh9Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KRGVuZ2FuIGF0dXJhbiB5YW5nIHNhbWEsIGRpcGVyb2xlaCBtYXRyaWtzICprZXkqIHNlYmFnYWkgYmVyaWt1dC4NCg0KXFsNClxtYXRoYmZ7S30NCj0NClxiZWdpbntibWF0cml4fQ0KLTAuMTUgJiAwLjA1XFwNCi0wLjExICYgMC4wNFxcDQowLjIwICYgLTAuMDdcXA0KMC4wOSAmIC0wLjAzXFwNCi0wLjEyICYgMC4wNFxcDQotMC4xNSAmIDAuMDVcXA0KLTAuMTIgJiAwLjA0XFwNCjAuMzEgJiAtMC4xMVxcDQowLjE2ICYgLTAuMDZcXA0KLTAuMTIgJiAwLjA0XFwNCi0wLjE1ICYgMC4wNVxcDQotMC4xMSAmIDAuMDRcXA0KMC4zMSAmIC0wLjExXFwNCjAuMTYgJiAtMC4wNlxcDQotMC4xMiAmIDAuMDRcXA0KLTAuMTUgJiAwLjA1XFwNCi0wLjEzICYgMC4wNVxcDQowLjE5ICYgLTAuMDdcXA0KMC4wNiAmIC0wLjAyXFwNCi0wLjEzICYgMC4wNVxcDQotMC4xNSAmIDAuMDVcXA0KLTAuMTMgJiAwLjA1XFwNCjAuMDMgJiAtMC4wMVxcDQotMC4wNCAmIDAuMDJcXA0KLTAuMTMgJiAwLjA1DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KIyMjIGQuIFByb3lla3NpICpWYWx1ZSoNCg0KUGFkYSBmb3JtdWxhc2kgKnNlcGFyYWJsZSBzZWxmLWF0dGVudGlvbiosIG1hdHJpa3MgKnZhbHVlKiBkaWJlbnR1ayBkYXJpIG1hdHJpa3MgdG9rZW4gbWFzdWthbiBtZW5nZ3VuYWthbiBib2JvdCBwcm95ZWtzaSBcKFxtYXRoYmZ7V31ee1Z9XCkuIERhbGFtIGlsdXN0cmFzaSBpbmksIG1hdHJpa3MgdG9rZW4gXChcbWF0aGJme1R9XCkgbWVyZWFsaXNhc2lrYW4gXChcbWF0aGJme1h9XCkgcGFkYSBQZXJzYW1hYW4gKDIuMjIpLg0KDQotICoqQm9ib3QgcHJveWVrc2kgKnZhbHVlKjoqKg0KDQpcWw0KXG1hdGhiZntXfV57Vn0NCj0NClxiZWdpbntibWF0cml4fQ0KMC43MCAmIC0wLjIwXFwNCjAuMjUgJiAwLjYwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KTWF0cmlrcyBcKFxtYXRoYmZ7V31ee1Z9XCkgYmVydWt1cmFuIFwoMlx0aW1lczJcKS4gS2FyZW5hIG1hdHJpa3MgXChcbWF0aGJme1R9XCkgYmVydWt1cmFuIFwoMjVcdGltZXMyXCksIG1ha2EgbWF0cmlrcyAqdmFsdWUqIFwoXG1hdGhiZntWfVwpIGJlcnVrdXJhbiBcKDI1XHRpbWVzMlwpLg0KDQotICoqUnVtdXM6KioNCg0KXFsNClxtYXRoYmZ7Vn0NCj0NClxtYXRoYmZ7VH1cbWF0aGJme1d9XntWfS4NClxdDQoNClNlY2FyYSBlbGVtZW4sIGtvbXBvbmVuICp2YWx1ZSoga2UtXChuXCkgcGFkYSB0b2tlbiBrZS1cKHRcKSBkaWhpdHVuZyBzZWJhZ2FpOg0KDQpcWw0KVl97dCxufQ0KPQ0KXHN1bV97bT0xfV57Mn0NClRfe3QsbX1XX3ttLG59XntWfS4NClxdDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gdG9rZW4gcGVydGFtYToqKg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcbWF0aGJme1Z9XzENCiY9DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjIyICYgMC4xNw0KXGVuZHtibWF0cml4fQ0KXGJlZ2lue2JtYXRyaXh9DQowLjcwICYgLTAuMjBcXA0KMC4yNSAmIDAuNjANClxlbmR7Ym1hdHJpeH1cXA0KJj0NClxiZWdpbntibWF0cml4fQ0KKC0wLjIyKSgwLjcwKSsoMC4xNykoMC4yNSkNCiYNCigtMC4yMikoLTAuMjApKygwLjE3KSgwLjYwKQ0KXGVuZHtibWF0cml4fVxcDQomPQ0KXGJlZ2lue2JtYXRyaXh9DQotMC4xMTE1ICYgMC4xNDYwDQpcZW5ke2JtYXRyaXh9XFwNCiY9DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjExICYgMC4xNQ0KXGVuZHtibWF0cml4fS4NClxlbmR7YWxpZ25lZH0NClxdDQoNClBhZGEgdGFoYXAga2VsdWFyYW4gU1NBLCBtYXRyaWtzIFwoXG1hdGhiZntWfVwpIHNlbGFuanV0bnlhIGRpcHJvc2VzIG1lbmdndW5ha2FuIGZ1bmdzaSBSZUxVIHNlc3VhaSBQZXJzYW1hYW4gKDIuMjIpLg0KDQpEZW5nYW4gYXR1cmFuIHlhbmcgc2FtYSwgZGlwZXJvbGVoIG1hdHJpa3MgKnZhbHVlKiBzZWJhZ2FpIGJlcmlrdXQuDQoNClxbDQpcbWF0aGJme1Z9DQo9DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjExICYgMC4xNFxcDQotMC4wOSAmIDAuMTFcXA0KMC4xNSAmIC0wLjE5XFwNCjAuMDcgJiAtMC4wOVxcDQotMC4wOSAmIDAuMTJcXA0KLTAuMTEgJiAwLjE0XFwNCi0wLjA5ICYgMC4xMVxcDQowLjI0ICYgLTAuMzFcXA0KMC4xMyAmIC0wLjE2XFwNCi0wLjEwICYgMC4xMlxcDQotMC4xMSAmIDAuMTRcXA0KLTAuMDkgJiAwLjExXFwNCjAuMjQgJiAtMC4zMVxcDQowLjEzICYgLTAuMTZcXA0KLTAuMTAgJiAwLjEyXFwNCi0wLjExICYgMC4xNFxcDQotMC4xMCAmIDAuMTNcXA0KMC4xNCAmIC0wLjE4XFwNCjAuMDUgJiAtMC4wNlxcDQotMC4xMCAmIDAuMTNcXA0KLTAuMTEgJiAwLjE0XFwNCi0wLjEwICYgMC4xM1xcDQowLjAyICYgLTAuMDNcXA0KLTAuMDMgJiAwLjA0XFwNCi0wLjEwICYgMC4xMw0KXGVuZHtibWF0cml4fS4NClxdDQoNCiMjIyBlLiBQZW1iZW50dWthbiB2ZWt0b3Iga29udGVrcw0KDQpWZWt0b3Iga29udGVrcyBcKFxtYXRoYmZ7Y31fdlwpIGRpcGVyb2xlaCBkZW5nYW4gbWVuZ2dhYnVuZ2thbiBzZWx1cnVoIGJhcmlzIG1hdHJpa3Mga2V5IFwoXG1hdGhiZntLfVwpIG1lbmdndW5ha2FuIGtvZWZpc2llbiBrb250ZWtzIHBhZGEgdmVrdG9yIFwoXG1hdGhiZntjfV9zXCkuIFNldGlhcCB0b2tlbiBrZXkgZGliZXJpIGJvYm90IHNlc3VhaSBuaWxhaSBrb2VmaXNpZW4ga29udGVrc255YS4gVG9rZW4gZGVuZ2FuIG5pbGFpIFwoY197cyx0fVwpIHlhbmcgbGViaWggYmVzYXIgbWVtYmVyaWthbiBrb250cmlidXNpIHlhbmcgbGViaWggYmVzYXIgdGVyaGFkYXAgcGVtYmVudHVrYW4gdmVrdG9yIGtvbnRla3MgZ2xvYmFsLg0KDQotICoqUnVtdXM6KioNCg0KXFsNClxtYXRoYmZ7Y31fdg0KPQ0KXG1hdGhiZntjfV9zXntcbWF0aHNme1R9fVxtYXRoYmZ7S30NCj0NClxzdW1fe3Q9MX1eezI1fWNfe3MsdH1cbWF0aGJme0t9X3t0LDp9Lg0KXF0NCg0KS2FyZW5hIFwoXG1hdGhiZntjfV9zXntcbWF0aHNme1R9fVwpIGJlcnVrdXJhbiBcKDFcdGltZXMyNVwpIGRhbiBcKFxtYXRoYmZ7S31cKSBiZXJ1a3VyYW4gXCgyNVx0aW1lczJcKSwgbWFrYSB2ZWt0b3Iga29udGVrcyBcKFxtYXRoYmZ7Y31fdlwpIGJlcnVrdXJhbiBcKDFcdGltZXMyXCkuDQoNClxbDQooMVx0aW1lczI1KSgyNVx0aW1lczIpPSgxXHRpbWVzMikuDQpcXQ0KDQpVbnR1ayBzZXRpYXAgZWxlbWVuIGtlLVwoblwpLCBwZXJoaXR1bmdhbm55YSBhZGFsYWg6DQoNClxbDQpjX3t2LG59DQo9DQpcc3VtX3t0PTF9XnsyNX1jX3tzLHR9S197dCxufSwNClxxcXVhZCBuPTEsMi4NClxdDQoNCi0gKipQZXJoaXR1bmdhbiBlbGVtZW4gcGVydGFtYToqKg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpjX3t2LDF9DQomPQ0KY197cywxfUtfezEsMX0NCitjX3tzLDJ9S197MiwxfQ0KK1xjZG90cw0KK2Nfe3MsMjV9S197MjUsMX1cXA0KJj0NCigwLjAzKSgtMC4xNSkNCisoMC4wMykoLTAuMTEpDQorXGNkb3RzDQorKDAuMDMpKC0wLjEzKVxcDQomPTAuMDEuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQotICoqUGVyaGl0dW5nYW4gZWxlbWVuIGtlZHVhOioqDQoNClxbDQpcYmVnaW57YWxpZ25lZH0NCmNfe3YsMn0NCiY9DQpjX3tzLDF9S197MSwyfQ0KK2Nfe3MsMn1LX3syLDJ9DQorXGNkb3RzDQorY197cywyNX1LX3syNSwyfVxcDQomPQ0KKDAuMDMpKDAuMDUpDQorKDAuMDMpKDAuMDQpDQorXGNkb3RzDQorKDAuMDMpKDAuMDUpXFwNCiY9LTAuMDA1Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KUGVyaGl0dW5nYW4gZGlsYWt1a2FuIG1lbmdndW5ha2FuIG5pbGFpIFwoXG1hdGhiZntjfV9zXCkgZGFuIFwoXG1hdGhiZntLfVwpIGRlbmdhbiBwcmVzaXNpIHBlbnVoIHNlYmVsdW0gaGFzaWwgYWtoaXIgZGl0YW1waWxrYW4uIE5pbGFpIGRpdGFtcGlsa2FuIGhpbmdnYSBkdWEgYW5na2EgZGkgYmVsYWthbmcga29tYSwga2VjdWFsaSBlbGVtZW4ga2VkdWEgeWFuZyBkaXRhbXBpbGthbiBoaW5nZ2EgdGlnYSBhbmdrYSBkaSBiZWxha2FuZyBrb21hIGFnYXIgdGlkYWsgbWVuamFkaSBcKC0wLjAwXCkuIE9sZWgga2FyZW5hIGl0dSwgZGlwZXJvbGVoIHZla3RvciBrb250ZWtzOg0KDQpcWw0KXG1hdGhiZntjfV92PQ0KXGJlZ2lue2JtYXRyaXh9DQowLjAxICYgLTAuMDA1DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KIyMjIGYuIEtlbHVhcmFuIHNlcGFyYWJsZSBzZWxmLWF0dGVudGlvbg0KDQpLZWx1YXJhbiAqc2VwYXJhYmxlIHNlbGYtYXR0ZW50aW9uKiBkaWJlbnR1ayBkZW5nYW4gbWVuZXJhcGthbiBmdW5nc2kgUmVMVSBwYWRhIHNldGlhcCBlbGVtZW4gbWF0cmlrcyB2YWx1ZSBcKFxtYXRoYmZ7Vn1cKS4gRnVuZ3NpIFJlTFUgbWVtcGVydGFoYW5rYW4gbmlsYWkgcG9zaXRpZiBkYW4gbWVuZ3ViYWggbmlsYWkgbmVnYXRpZiBtZW5qYWRpIG5vbC4gSGFzaWwgYWt0aXZhc2kgdGVyc2VidXQga2VtdWRpYW4gZGlrYWxpa2FuIHNlY2FyYSBlbGVtZW4gZGVtaSBlbGVtZW4gZGVuZ2FuIHZla3RvciBrb250ZWtzIGdsb2JhbCBcKFxtYXRoYmZ7Y31fdlwpLCBsYWx1IGRpcHJveWVrc2lrYW4gbWVuZ2d1bmFrYW4gYm9ib3Qga2VsdWFyYW4gXChcbWF0aGJme1d9XntPfVwpLg0KDQpQYWRhIGlsdXN0cmFzaSBpbmksIHZla3RvciBrb250ZWtzIGdsb2JhbCBzZWJlbHVtIHBlbWJ1bGF0YW4gYWRhbGFoOg0KDQpcWw0KXG1hdGhiZntjfV92PQ0KXGJlZ2lue2JtYXRyaXh9DQowLjAxMzIgJiAtMC4wMDQ3DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KLSAqKkJvYm90IGtlbHVhcmFuOioqDQoNClxbDQpcbWF0aGJme1d9XntPfT0NClxiZWdpbntibWF0cml4fQ0KNTAuMDAgJiAtMjAuMDBcXA0KNTAuMDAgJiA1MC4wMA0KXGVuZHtibWF0cml4fS4NClxdDQoNCkJvYm90IFwoXG1hdGhiZntXfV57T31cKSBtZXJ1cGFrYW4gYm9ib3QgaWx1c3RyYXRpZiB5YW5nIGRpZ3VuYWthbiB1bnR1ayBtZW1wcm95ZWtzaWthbiBoYXNpbCAqc2VwYXJhYmxlIHNlbGYtYXR0ZW50aW9uKi4gTmlsYWkgdGVyc2VidXQgZGlwaWxpaCBhZ2FyIGtlbHVhcmFuIHRldGFwIGRhcGF0IGRpdGFtcGlsa2FuIHNlY2FyYSBqZWxhcyBzZXRlbGFoIHBlbWJ1bGF0YW4uDQoNCi0gKipSdW11czoqKg0KDQpTZXN1YWkgUGVyc2FtYWFuICgyLjIyKSBwYWRhIGRyYWZ0LCBrZWx1YXJhbiAqc2VwYXJhYmxlIHNlbGYtYXR0ZW50aW9uKiBkaXJ1bXVza2FuIHNlYmFnYWk6DQoNClxbDQpcbWF0aGJme1p9X3tcbWF0aHJte1NTQX19DQo9DQpcbGVmdCgNClxtYXRoYmZ7Y31fdg0KXG9kb3QNClxvcGVyYXRvcm5hbWV7UmVMVX0oXG1hdGhiZntWfSkNClxyaWdodCkNClxtYXRoYmZ7V31ee099Lg0KXF0NCg0KVmVrdG9yIFwoXG1hdGhiZntjfV92XCkgYmVydWt1cmFuIFwoMVx0aW1lczJcKSBkaXRlcmFwa2FuIHBhZGEgc2V0aWFwIGJhcmlzIG1hdHJpa3MgXChcb3BlcmF0b3JuYW1le1JlTFV9KFxtYXRoYmZ7Vn0pXCkgeWFuZyBiZXJ1a3VyYW4gXCgyNVx0aW1lczJcKS4gT2xlaCBrYXJlbmEgaXR1LCBoYXNpbCBwZXJrYWxpYW4gZWxlbWVuIGRlbWkgZWxlbWVuIGJlcnVrdXJhbiBcKDI1XHRpbWVzMlwpLiBTZXRlbGFoIGRpa2FsaWthbiBkZW5nYW4gXChcbWF0aGJme1d9XntPfVwpIHlhbmcgYmVydWt1cmFuIFwoMlx0aW1lczJcKSwgZGlwZXJvbGVoIG1hdHJpa3MgXChcbWF0aGJme1p9X3tcbWF0aHJte1NTQX19XCkgYmVydWt1cmFuIFwoMjVcdGltZXMyXCkuDQoNClxbDQpcb3BlcmF0b3JuYW1le1JlTFV9KFZfe3Qsbn0pDQo9DQpcbWF4KDAsVl97dCxufSkuDQpcXQ0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuIHRva2VuIHBlcnRhbWE6KioNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KXG1hdGhiZntafV97XG1hdGhybXtTU0F9LDF9DQomPQ0KXGxlZnQoDQpcbWF0aGJme2N9X3YNClxvZG90DQpcb3BlcmF0b3JuYW1le1JlTFV9KFxtYXRoYmZ7Vn1fezF9KQ0KXHJpZ2h0KQ0KXG1hdGhiZntXfV57T31cXA0KJj0NClxsZWZ0KA0KXGJlZ2lue2JtYXRyaXh9DQowLjAxMzIgJiAtMC4wMDQ3DQpcZW5ke2JtYXRyaXh9DQpcb2RvdA0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGJlZ2lue2JtYXRyaXh9DQotMC4xMSAmIDAuMTQNClxlbmR7Ym1hdHJpeH0NClxyaWdodCkNClxiZWdpbntibWF0cml4fQ0KNTAuMDAgJiAtMjAuMDBcXA0KNTAuMDAgJiA1MC4wMA0KXGVuZHtibWF0cml4fVxcDQomPQ0KXGxlZnQoDQpcYmVnaW57Ym1hdHJpeH0NCjAuMDEzMiAmIC0wLjAwNDcNClxlbmR7Ym1hdHJpeH0NClxvZG90DQpcYmVnaW57Ym1hdHJpeH0NCjAuMDAgJiAwLjE0DQpcZW5ke2JtYXRyaXh9DQpccmlnaHQpDQpcYmVnaW57Ym1hdHJpeH0NCjUwLjAwICYgLTIwLjAwXFwNCjUwLjAwICYgNTAuMDANClxlbmR7Ym1hdHJpeH1cXA0KJj0NClxiZWdpbntibWF0cml4fQ0KMC4wMCAmIC0wLjAwMDcNClxlbmR7Ym1hdHJpeH0NClxiZWdpbntibWF0cml4fQ0KNTAuMDAgJiAtMjAuMDBcXA0KNTAuMDAgJiA1MC4wMA0KXGVuZHtibWF0cml4fVxcDQomPQ0KXGJlZ2lue2JtYXRyaXh9DQotMC4wMyAmIC0wLjAzDQpcZW5ke2JtYXRyaXh9Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KRGVuZ2FuIGF0dXJhbiB5YW5nIHNhbWEsIGRpcGVyb2xlaCBrZWx1YXJhbiAqc2VwYXJhYmxlIHNlbGYtYXR0ZW50aW9uKiBzZWJhZ2FpIGJlcmlrdXQuDQoNClxbDQpcbWF0aGJme1p9X3tcbWF0aHJte1NTQX19PQ0KXGJlZ2lue2JtYXRyaXh9DQotMC4wMyAmIC0wLjAzXFwNCi0wLjAzICYgLTAuMDNcXA0KMC4xMCAmIC0wLjA0XFwNCjAuMDUgJiAtMC4wMlxcDQotMC4wMyAmIC0wLjAzXFwNCi0wLjAzICYgLTAuMDNcXA0KLTAuMDMgJiAtMC4wM1xcDQowLjE2ICYgLTAuMDZcXA0KMC4wOCAmIC0wLjAzXFwNCi0wLjAzICYgLTAuMDNcXA0KLTAuMDMgJiAtMC4wM1xcDQotMC4wMyAmIC0wLjAzXFwNCjAuMTYgJiAtMC4wNlxcDQowLjA4ICYgLTAuMDNcXA0KLTAuMDMgJiAtMC4wM1xcDQotMC4wMyAmIC0wLjAzXFwNCi0wLjAzICYgLTAuMDNcXA0KMC4xMCAmIC0wLjA0XFwNCjAuMDMgJiAtMC4wMVxcDQotMC4wMyAmIC0wLjAzXFwNCi0wLjAzICYgLTAuMDNcXA0KLTAuMDMgJiAtMC4wM1xcDQowLjAxICYgLTAuMDA1XFwNCi0wLjAxICYgLTAuMDFcXA0KLTAuMDMgJiAtMC4wMw0KXGVuZHtibWF0cml4fS4NClxdDQoNCk5pbGFpIGRpaGl0dW5nIG1lbmdndW5ha2FuIHByZXNpc2kgcGVudWggc2ViZWx1bSBkaXRhbXBpbGthbi4gSGFzaWwgZGl0dWxpcyBoaW5nZ2EgZHVhIGFuZ2thIGRpIGJlbGFrYW5nIGtvbWEsIGtlY3VhbGkgbmlsYWkgXCgtMC4wMDVcKSBhZ2FyIHRpZGFrIGRpdGFtcGlsa2FuIHNlYmFnYWkgXCgtMC4wMFwpLg0KDQoNCiMjIyBnLiBSZXNpZHVhbCBzZXBhcmFibGUgc2VsZi1hdHRlbnRpb24NCg0KS2VsdWFyYW4gKnNlcGFyYWJsZSBzZWxmLWF0dGVudGlvbiogXChcbWF0aGJme1p9X3tcbWF0aHJte1NTQX19XCkgc2VsYW5qdXRueWEgZGlnYWJ1bmdrYW4gZGVuZ2FuIG1hdHJpa3MgdG9rZW4gbWFzdWthbiBcKFxtYXRoYmZ7VH1cKSBtZWxhbHVpICpyZXNpZHVhbCBjb25uZWN0aW9uKi4gUHJvc2VzIGluaSBtZW1wZXJ0YWhhbmthbiBpbmZvcm1hc2kgYXdhbCBzZXRpYXAgdG9rZW4gc2VrYWxpZ3VzIG1lbmFtYmFoa2FuIGluZm9ybWFzaSBrb250ZWtzIGdsb2JhbCB5YW5nIGRpcGVyb2xlaCBkYXJpIFNTQS4NCg0KLSAqKlJ1bXVzOioqDQoNClxbDQpcbWF0aGJme1p9Jw0KPQ0KXG1hdGhiZntUfQ0KKw0KXG1hdGhiZntafV97XG1hdGhybXtTU0F9fS4NClxdDQoNCk1hdHJpa3MgXChcbWF0aGJme1R9XCkgZGFuIFwoXG1hdGhiZntafV97XG1hdGhybXtTU0F9fVwpIG1hc2luZy1tYXNpbmcgYmVydWt1cmFuIFwoMjVcdGltZXMyXCkuIE9sZWgga2FyZW5hIGl0dSwgbWF0cmlrcyBoYXNpbCByZXNpZHVhbCBcKFxtYXRoYmZ7Wn0nXCkganVnYSBiZXJ1a3VyYW4gXCgyNVx0aW1lczJcKS4NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiB0b2tlbiBwZXJ0YW1hOioqDQoNClBlcmhpdHVuZ2FuIGRpbGFrdWthbiBtZW5nZ3VuYWthbiBuaWxhaSBwcmVzaXNpIHBlbnVoIHNlYmVsdW0gaGFzaWwgYWtoaXIgZGl0YW1waWxrYW4uIFVudHVrIHRva2VuIHBlcnRhbWEsIGRpcGVyb2xlaDoNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KXG1hdGhiZntafSdfezF9DQomPQ0KXG1hdGhiZntUfV97MX0NCisNClxtYXRoYmZ7Wn1fe1xtYXRocm17U1NBfSwxfVxcDQomPQ0KXGJlZ2lue2JtYXRyaXh9DQotMC4yMjIyICYgMC4xNjY2DQpcZW5ke2JtYXRyaXh9DQorDQpcYmVnaW57Ym1hdHJpeH0NCi0wLjAzNDIgJiAtMC4wMzQyDQpcZW5ke2JtYXRyaXh9XFwNCiY9DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjI1NjQgJiAwLjEzMjQNClxlbmR7Ym1hdHJpeH1cXA0KJj0NClxiZWdpbntibWF0cml4fQ0KLTAuMjYgJiAwLjEzDQpcZW5ke2JtYXRyaXh9Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiB0b2tlbiBrZXRpZ2E6KioNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KXG1hdGhiZntafSdfezN9DQomPQ0KXG1hdGhiZntUfV97M30NCisNClxtYXRoYmZ7Wn1fe1xtYXRocm17U1NBfSwzfVxcDQomPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjMwICYgLTAuMjINClxlbmR7Ym1hdHJpeH0NCisNClxiZWdpbntibWF0cml4fQ0KMC4xMCAmIC0wLjA0DQpcZW5ke2JtYXRyaXh9XFwNCiY9DQpcYmVnaW57Ym1hdHJpeH0NCjAuNDAgJiAtMC4yNg0KXGVuZHtibWF0cml4fS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBhdHVyYW4geWFuZyBzYW1hLCBkaXBlcm9sZWggbWF0cmlrcyBoYXNpbCAqcmVzaWR1YWwgc2VwYXJhYmxlIHNlbGYtYXR0ZW50aW9uKiBzZWJhZ2FpIGJlcmlrdXQuDQoNClxbDQpcbWF0aGJme1p9Jz0NClxiZWdpbntibWF0cml4fQ0KLTAuMjYgJiAwLjEzXFwNCi0wLjIwICYgMC4xMFxcDQowLjQwICYgLTAuMjZcXA0KMC4xOCAmIC0wLjEyXFwNCi0wLjIxICYgMC4xMVxcDQotMC4yNSAmIDAuMTNcXA0KLTAuMjAgJiAwLjEwXFwNCjAuNjMgJiAtMC40MlxcDQowLjMzICYgLTAuMjJcXA0KLTAuMjIgJiAwLjExXFwNCi0wLjI2ICYgMC4xM1xcDQotMC4yMCAmIDAuMTBcXA0KMC42NCAmIC0wLjQyXFwNCjAuMzMgJiAtMC4yMlxcDQotMC4yMiAmIDAuMTFcXA0KLTAuMjUgJiAwLjEzXFwNCi0wLjIyICYgMC4xMlxcDQowLjM4ICYgLTAuMjVcXA0KMC4xMiAmIC0wLjA4XFwNCi0wLjIzICYgMC4xMlxcDQotMC4yNiAmIDAuMTNcXA0KLTAuMjMgJiAwLjEyXFwNCjAuMDUgJiAtMC4wMzVcXA0KLTAuMDcgJiAwLjA0XFwNCi0wLjIzICYgMC4xMg0KXGVuZHtibWF0cml4fS4NClxdDQoNCg0KIyMjIGguIE5vcm1hbGlzYXNpIHJlc2lkdWFsIHNlcGFyYWJsZSBzZWxmLWF0dGVudGlvbg0KDQpNYXRyaWtzIGhhc2lsIHJlc2lkdWFsICpzZXBhcmFibGUgc2VsZi1hdHRlbnRpb24qIFwoXG1hdGhiZntafSdcKSBkaW5vcm1hbGlzYXNpIHBlciB0b2tlbiBtZW5nZ3VuYWthbiAqbGF5ZXIgbm9ybWFsaXphdGlvbiouIE5vcm1hbGlzYXNpIGRpbGFrdWthbiBwYWRhIGR1YSBlbGVtZW4gZml0dXIgZGFsYW0gc2V0aWFwIHRva2VuIHNlY2FyYSB0ZXJwaXNhaCwgYnVrYW4gcGFkYSBzZWx1cnVoIG1hdHJpa3Mgc2VrYWxpZ3VzLiBUYWhhcCBpbmkgbWVuZ2hhc2lsa2FuIFwoXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntafScpXCkgc2ViYWdhaSBtYXN1a2FuIHVudHVrIE1MUC4NCg0KLSAqKlJ1bXVzIHJhdGEtcmF0YSB0b2tlbiBrZS1cKHRcKToqKg0KDQpcWw0KXG11X3taJyx0fQ0KPQ0KXGZyYWN7MX17Mn0NClxzdW1fe249MX1eezJ9Widfe3Qsbn0uDQpcXQ0KDQotICoqUnVtdXMgdmFyaWFucyB0b2tlbiBrZS1cKHRcKToqKg0KDQpcWw0KXHNpZ21hX3taJyx0fV57Mn0NCj0NClxmcmFjezF9ezJ9DQpcc3VtX3tuPTF9XnsyfQ0KXGxlZnQoDQpaJ197dCxufS1cbXVfe1onLHR9DQpccmlnaHQpXjIuDQpcXQ0KDQotICoqUnVtdXMgbm9ybWFsaXNhc2k6KioNCg0KXFsNClxsZWZ0Ww0KXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntafScpDQpccmlnaHRdX3t0LG59DQo9DQpcZnJhY3sNClonX3t0LG59LVxtdV97WicsdH0NCn17DQpcc3FydHsNClxzaWdtYV97WicsdH1eezJ9KzEwXnstNX0NCn0NCn0uDQpcXQ0KDQpNYXRyaWtzIFwoXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntafScpXCkgYmVydWt1cmFuIFwoMjVcdGltZXMyXCkuDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gdG9rZW4gcGVydGFtYToqKg0KDQpOaWxhaSB0b2tlbiBwZXJ0YW1hIHNlYmVsdW0gcGVtYnVsYXRhbiBhZGFsYWg6DQoNClxbDQpcbWF0aGJme1p9J197MX09DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjI1NjQgJiAwLjEzMjQNClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQpSYXRhLXJhdGEgdG9rZW4gcGVydGFtYSBhZGFsYWg6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClxtdV97WicsMX0NCiY9DQpcZnJhY3stMC4yNTY0KzAuMTMyNH17Mn1cXA0KJj0NCi0wLjA2MjAuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpWYXJpYW5zIHRva2VuIHBlcnRhbWEgYWRhbGFoOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcc2lnbWFfe1onLDF9XnsyfQ0KJj0NClxmcmFjew0KKC0wLjI1NjQtKC0wLjA2MjApKV4yDQorDQooMC4xMzI0LSgtMC4wNjIwKSleMg0KfXsyfVxcDQomPQ0KXGZyYWN7KC0wLjE5NDQpXjIrKDAuMTk0NCleMn17Mn1cXA0KJj0NCjAuMDM3OC4NClxlbmR7YWxpZ25lZH0NClxdDQoNCk1ha2E6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClxvcGVyYXRvcm5hbWV7TE59KFxtYXRoYmZ7Wn0nX3sxfSkNCiY9DQpcYmVnaW57Ym1hdHJpeH0NClxkZnJhY3stMC4yNTY0LSgtMC4wNjIwKX0NCntcc3FydHswLjAzNzgrMTBeey01fX19DQomDQpcZGZyYWN7MC4xMzI0LSgtMC4wNjIwKX0NCntcc3FydHswLjAzNzgrMTBeey01fX19DQpcZW5ke2JtYXRyaXh9XFwNCiY9DQpcYmVnaW57Ym1hdHJpeH0NCi0xLjAwICYgMS4wMA0KXGVuZHtibWF0cml4fS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBhdHVyYW4geWFuZyBzYW1hLCBkaXBlcm9sZWggbWF0cmlrcyBoYXNpbCBub3JtYWxpc2FzaSByZXNpZHVhbCAqc2VwYXJhYmxlIHNlbGYtYXR0ZW50aW9uKiBzZWJhZ2FpIGJlcmlrdXQuDQoNClxbDQpcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1p9Jyk9DQpcYmVnaW57Ym1hdHJpeH0NCi0xLjAwICYgMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KMS4wMCAmIC0xLjAwXFwNCjEuMDAgJiAtMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMFxcDQoxLjAwICYgLTEuMDBcXA0KMS4wMCAmIC0xLjAwXFwNCi0xLjAwICYgMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCjEuMDAgJiAtMS4wMFxcDQoxLjAwICYgLTEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KMS4wMCAmIC0xLjAwXFwNCjEuMDAgJiAtMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMFxcDQoxLjAwICYgLTEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMA0KXGVuZHtibWF0cml4fS4NClxdDQoNCiMjIyBpLiBMYXBpc2FuIHBlcnRhbWEgTUxQICgqZmVlZC1mb3J3YXJkIG5ldHdvcmsqKQ0KDQpMYXBpc2FuIHBlcnRhbWEgTUxQIG1lbmVyaW1hIHRva2VuIGhhc2lsIG5vcm1hbGlzYXNpIHJlc2lkdWFsICpzZXBhcmFibGUgc2VsZi1hdHRlbnRpb24qLCB5YWl0dSBcKFxvcGVyYXRvcm5hbWV7TE59KFxtYXRoYmZ7Wn0nKVwpLiBMYXBpc2FuIGluaSBtZW1wcm95ZWtzaWthbiBzZXRpYXAgdG9rZW4gZGFyaSBkdWEgZWxlbWVuIGZpdHVyIG1lbmphZGkgdGlnYSBlbGVtZW4gZml0dXIsIGtlbXVkaWFuIG1lbmVyYXBrYW4gZnVuZ3NpIGFrdGl2YXNpIFJlTFUuIFByb3NlcyB0ZXJzZWJ1dCBzZXN1YWkgZGVuZ2FuIHRhaGFwIHBlcnRhbWEgTUxQIHBhZGEgUGVyc2FtYWFuICgyLjE3KSBkaSBCYWIgSUkuDQoNClBhZGEgaWx1c3RyYXNpIGluaSwgdmVrdG9yIGJpYXMgbGFwaXNhbiBwZXJ0YW1hIGRpYWJhaWthbiBhdGF1IGRpdGV0YXBrYW4gc2ViYWdhaSBcKFxtYXRoYmZ7Yn1fMT1cbWF0aGJmezB9XCkuDQoNCi0gKipCb2JvdCBsYXBpc2FuIHBlcnRhbWE6KioNCg0KXFsNClxtYXRoYmZ7V31fMT0NClxiZWdpbntibWF0cml4fQ0KMC40NSAmIC0wLjM1ICYgMC4yNVxcDQotMC4yMCAmIDAuNTUgJiAwLjMwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KTWF0cmlrcyBcKFxtYXRoYmZ7V31fMVwpIGJlcnVrdXJhbiBcKDJcdGltZXMzXCkuDQoNCi0gKipSdW11czoqKg0KDQpcWw0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQpcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1p9JykNClxtYXRoYmZ7V31fMQ0KXHJpZ2h0KS4NClxdDQoNCk1hdHJpa3MgXChcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1p9JylcKSBiZXJ1a3VyYW4gXCgyNVx0aW1lczJcKS4gT2xlaCBrYXJlbmEgaXR1LCBoYXNpbCBsYXBpc2FuIHBlcnRhbWEgTUxQIGJlcnVrdXJhbiBcKDI1XHRpbWVzM1wpLg0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuIHRva2VuIHBlcnRhbWE6KioNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQpcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1p9J18xKQ0KXG1hdGhiZntXfV8xDQpccmlnaHQpDQomPQ0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQpcYmVnaW57Ym1hdHJpeH0NCi0xLjAwICYgMS4wMA0KXGVuZHtibWF0cml4fQ0KXGJlZ2lue2JtYXRyaXh9DQowLjQ1ICYgLTAuMzUgJiAwLjI1XFwNCi0wLjIwICYgMC41NSAmIDAuMzANClxlbmR7Ym1hdHJpeH0NClxyaWdodClcXA0KJj0NClxvcGVyYXRvcm5hbWV7UmVMVX0NClxsZWZ0KA0KXGJlZ2lue2JtYXRyaXh9DQotMC42NSAmIDAuOTAgJiAwLjA1DQpcZW5ke2JtYXRyaXh9DQpccmlnaHQpXFwNCiY9DQpcYmVnaW57Ym1hdHJpeH0NCjAuMDAgJiAwLjkwICYgMC4wNQ0KXGVuZHtibWF0cml4fS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gdG9rZW4ga2V0aWdhOioqDQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClxvcGVyYXRvcm5hbWV7UmVMVX0NClxsZWZ0KA0KXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntafSdfMykNClxtYXRoYmZ7V31fMQ0KXHJpZ2h0KQ0KJj0NClxvcGVyYXRvcm5hbWV7UmVMVX0NClxsZWZ0KA0KXGJlZ2lue2JtYXRyaXh9DQoxLjAwICYgLTEuMDANClxlbmR7Ym1hdHJpeH0NClxiZWdpbntibWF0cml4fQ0KMC40NSAmIC0wLjM1ICYgMC4yNVxcDQotMC4yMCAmIDAuNTUgJiAwLjMwDQpcZW5ke2JtYXRyaXh9DQpccmlnaHQpXFwNCiY9DQpcb3BlcmF0b3JuYW1le1JlTFV9DQpcbGVmdCgNClxiZWdpbntibWF0cml4fQ0KMC42NSAmIC0wLjkwICYgLTAuMDUNClxlbmR7Ym1hdHJpeH0NClxyaWdodClcXA0KJj0NClxiZWdpbntibWF0cml4fQ0KMC42NSAmIDAuMDAgJiAwLjAwDQpcZW5ke2JtYXRyaXh9Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KRGVuZ2FuIGF0dXJhbiB5YW5nIHNhbWEsIGRpcGVyb2xlaCBoYXNpbCBsYXBpc2FuIHBlcnRhbWEgTUxQIHNlYmFnYWkgYmVyaWt1dC4NCg0KXFsNClxvcGVyYXRvcm5hbWV7UmVMVX0NClxsZWZ0KA0KXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntafScpDQpcbWF0aGJme1d9XzENClxyaWdodCkNCj0NClxiZWdpbntibWF0cml4fQ0KMC4wMCAmIDAuOTAgJiAwLjA1XFwNCjAuMDAgJiAwLjkwICYgMC4wNVxcDQowLjY1ICYgMC4wMCAmIDAuMDBcXA0KMC42NSAmIDAuMDAgJiAwLjAwXFwNCjAuMDAgJiAwLjkwICYgMC4wNVxcDQowLjAwICYgMC45MCAmIDAuMDVcXA0KMC4wMCAmIDAuOTAgJiAwLjA1XFwNCjAuNjUgJiAwLjAwICYgMC4wMFxcDQowLjY1ICYgMC4wMCAmIDAuMDBcXA0KMC4wMCAmIDAuOTAgJiAwLjA1XFwNCjAuMDAgJiAwLjkwICYgMC4wNVxcDQowLjAwICYgMC45MCAmIDAuMDVcXA0KMC42NSAmIDAuMDAgJiAwLjAwXFwNCjAuNjUgJiAwLjAwICYgMC4wMFxcDQowLjAwICYgMC45MCAmIDAuMDVcXA0KMC4wMCAmIDAuOTAgJiAwLjA1XFwNCjAuMDAgJiAwLjkwICYgMC4wNVxcDQowLjY1ICYgMC4wMCAmIDAuMDBcXA0KMC42NSAmIDAuMDAgJiAwLjAwXFwNCjAuMDAgJiAwLjkwICYgMC4wNVxcDQowLjAwICYgMC45MCAmIDAuMDVcXA0KMC4wMCAmIDAuOTAgJiAwLjA1XFwNCjAuNjUgJiAwLjAwICYgMC4wMFxcDQowLjAwICYgMC45MCAmIDAuMDVcXA0KMC4wMCAmIDAuOTAgJiAwLjA1DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KIyMjIGouIExhcGlzYW4ga2VkdWEgTUxQICgqZmVlZC1mb3J3YXJkIG5ldHdvcmsqKQ0KDQpMYXBpc2FuIGtlZHVhIE1MUCBtZW1wcm95ZWtzaWthbiB0aWdhIGVsZW1lbiBmaXR1ciBoYXNpbCBsYXBpc2FuIHBlcnRhbWEga2VtYmFsaSBtZW5qYWRpIGR1YSBlbGVtZW4gZml0dXIuIFBhZGEgdGFoYXAgaW5pLCBrZWx1YXJhbiBwcm95ZWtzaSBsaW5lYXIgdGlkYWsgZGliZXJpIGZ1bmdzaSBha3RpdmFzaSB0YW1iYWhhbi4gUHJvc2VzIGluaSBzZXN1YWkgZGVuZ2FuIGJhZ2lhbiBrZWR1YSBNTFAgcGFkYSBQZXJzYW1hYW4gKDIuMTcpIGRpIEJhYiBJSS4NCg0KUGFkYSBpbHVzdHJhc2kgaW5pLCB2ZWt0b3IgYmlhcyBsYXBpc2FuIGtlZHVhIGRpYWJhaWthbiBhdGF1IGRpdGV0YXBrYW4gc2ViYWdhaSBcKFxtYXRoYmZ7Yn1fMj1cbWF0aGJmezB9XCkuDQoNCi0gKipCb2JvdCBsYXBpc2FuIGtlZHVhOioqDQoNClxbDQpcbWF0aGJme1d9XzI9DQpcYmVnaW57Ym1hdHJpeH0NCjAuMzUgJiAtMC4yNVxcDQowLjE1ICYgMC40NVxcDQotMC4yMCAmIDAuMzANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQpNYXRyaWtzIFwoXG1hdGhiZntXfV8yXCkgYmVydWt1cmFuIFwoM1x0aW1lczJcKS4NCg0KLSAqKlJ1bXVzOioqDQoNClxbDQpcb3BlcmF0b3JuYW1le1JlTFV9DQpcbGVmdCgNClxvcGVyYXRvcm5hbWV7TE59KFxtYXRoYmZ7Wn0nKQ0KXG1hdGhiZntXfV8xDQpccmlnaHQpDQpcbWF0aGJme1d9XzIuDQpcXQ0KDQpIYXNpbCBsYXBpc2FuIHBlcnRhbWEgTUxQIGJlcnVrdXJhbiBcKDI1XHRpbWVzM1wpLiBPbGVoIGthcmVuYSBpdHUsIGtlbHVhcmFuIGxhcGlzYW4ga2VkdWEgTUxQIGJlcnVrdXJhbiBcKDI1XHRpbWVzMlwpLg0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuIHRva2VuIHBlcnRhbWE6KioNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KJg0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQpcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1p9J18xKQ0KXG1hdGhiZntXfV8xDQpccmlnaHQpDQpcbWF0aGJme1d9XzJcXA0KJj0NClxiZWdpbntibWF0cml4fQ0KMC4wMCAmIDAuOTAgJiAwLjA1DQpcZW5ke2JtYXRyaXh9DQpcYmVnaW57Ym1hdHJpeH0NCjAuMzUgJiAtMC4yNVxcDQowLjE1ICYgMC40NVxcDQotMC4yMCAmIDAuMzANClxlbmR7Ym1hdHJpeH1cXA0KJj0NClxiZWdpbntibWF0cml4fQ0KKDAuMDApKDAuMzUpKygwLjkwKSgwLjE1KSsoMC4wNSkoLTAuMjApDQomDQooMC4wMCkoLTAuMjUpKygwLjkwKSgwLjQ1KSsoMC4wNSkoMC4zMCkNClxlbmR7Ym1hdHJpeH1cXA0KJj0NClxiZWdpbntibWF0cml4fQ0KMC4xMjUgJiAwLjQyMA0KXGVuZHtibWF0cml4fVxcDQomPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjEzICYgMC40Mg0KXGVuZHtibWF0cml4fS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gdG9rZW4ga2V0aWdhOioqDQoNClxbDQpcYmVnaW57YWxpZ25lZH0NCiYNClxvcGVyYXRvcm5hbWV7UmVMVX0NClxsZWZ0KA0KXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntafSdfMykNClxtYXRoYmZ7V31fMQ0KXHJpZ2h0KQ0KXG1hdGhiZntXfV8yXFwNCiY9DQpcYmVnaW57Ym1hdHJpeH0NCjAuNjUgJiAwLjAwICYgMC4wMA0KXGVuZHtibWF0cml4fQ0KXGJlZ2lue2JtYXRyaXh9DQowLjM1ICYgLTAuMjVcXA0KMC4xNSAmIDAuNDVcXA0KLTAuMjAgJiAwLjMwDQpcZW5ke2JtYXRyaXh9XFwNCiY9DQpcYmVnaW57Ym1hdHJpeH0NCjAuMjMgJiAtMC4xNg0KXGVuZHtibWF0cml4fS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBhdHVyYW4geWFuZyBzYW1hLCBkaXBlcm9sZWgga2VsdWFyYW4gbGFwaXNhbiBrZWR1YSBNTFAgc2ViYWdhaSBiZXJpa3V0Lg0KDQpcWw0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQpcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1p9JykNClxtYXRoYmZ7V31fMQ0KXHJpZ2h0KQ0KXG1hdGhiZntXfV8yDQo9DQpcYmVnaW57Ym1hdHJpeH0NCjAuMTMgJiAwLjQyXFwNCjAuMTMgJiAwLjQyXFwNCjAuMjMgJiAtMC4xNlxcDQowLjIzICYgLTAuMTZcXA0KMC4xMyAmIDAuNDJcXA0KMC4xMyAmIDAuNDJcXA0KMC4xMyAmIDAuNDJcXA0KMC4yMyAmIC0wLjE2XFwNCjAuMjMgJiAtMC4xNlxcDQowLjEzICYgMC40MlxcDQowLjEzICYgMC40MlxcDQowLjEzICYgMC40MlxcDQowLjIzICYgLTAuMTZcXA0KMC4yMyAmIC0wLjE2XFwNCjAuMTMgJiAwLjQyXFwNCjAuMTMgJiAwLjQyXFwNCjAuMTMgJiAwLjQyXFwNCjAuMjMgJiAtMC4xNlxcDQowLjIzICYgLTAuMTZcXA0KMC4xMyAmIDAuNDJcXA0KMC4xMyAmIDAuNDJcXA0KMC4xMyAmIDAuNDJcXA0KMC4yMyAmIC0wLjE2XFwNCjAuMTMgJiAwLjQyXFwNCjAuMTMgJiAwLjQyDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KIyMjIGsuIFJlc2lkdWFsIE1MUCAoKmZlZWQtZm9yd2FyZCBuZXR3b3JrKikNCg0KS2VsdWFyYW4gbGFwaXNhbiBrZWR1YSBNTFAgZGl0YW1iYWhrYW4gZGVuZ2FuIHJlcHJlc2VudGFzaSByZXNpZHVhbCBzZWJlbHVtbnlhLCB5YWl0dSBcKFxtYXRoYmZ7Wn0nXCkuIFBlbmp1bWxhaGFuIGluaSBtZW1wZXJ0YWhhbmthbiBpbmZvcm1hc2kgaGFzaWwgKnNlcGFyYWJsZSBzZWxmLWF0dGVudGlvbiogc2VrYWxpZ3VzIG1lbmFtYmFoa2FuIHRyYW5zZm9ybWFzaSBmaXR1ciBkYXJpIE1MUC4gS2VsdWFyYW4gYWtoaXIgYmxvayAqbGluZWFyIFRyYW5zZm9ybWVyKiBkaW5vdGFzaWthbiBzZWJhZ2FpIFwoXG1hdGhiZntafVwpLg0KDQotICoqUnVtdXM6KioNCg0KXFsNClxtYXRoYmZ7Wn0NCj0NClxtYXRoYmZ7Wn0nDQorDQpcb3BlcmF0b3JuYW1le1JlTFV9DQpcbGVmdCgNClxvcGVyYXRvcm5hbWV7TE59KFxtYXRoYmZ7Wn0nKQ0KXG1hdGhiZntXfV8xDQpccmlnaHQpDQpcbWF0aGJme1d9XzIuDQpcXQ0KDQpNYXRyaWtzIFwoXG1hdGhiZntafSdcKSBkYW4ga2VsdWFyYW4gbGFwaXNhbiBrZWR1YSBNTFAgbWFzaW5nLW1hc2luZyBiZXJ1a3VyYW4gXCgyNVx0aW1lczJcKS4gT2xlaCBrYXJlbmEgaXR1LCBtYXRyaWtzIGtlbHVhcmFuIFwoXG1hdGhiZntafVwpIGp1Z2EgYmVydWt1cmFuIFwoMjVcdGltZXMyXCkuDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gdG9rZW4gcGVydGFtYToqKg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcbWF0aGJme1p9XzENCiY9DQpcbWF0aGJme1p9J18xKw0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQpcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1p9J18xKQ0KXG1hdGhiZntXfV8xDQpccmlnaHQpDQpcbWF0aGJme1d9XzJcXA0KJj0NClxiZWdpbntibWF0cml4fQ0KLTAuMjYgJiAwLjEzDQpcZW5ke2JtYXRyaXh9DQorDQpcYmVnaW57Ym1hdHJpeH0NCjAuMTMgJiAwLjQyDQpcZW5ke2JtYXRyaXh9XFwNCiY9DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjEzICYgMC41NQ0KXGVuZHtibWF0cml4fS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gdG9rZW4ga2V0aWdhOioqDQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClxtYXRoYmZ7Wn1fMw0KJj0NClxiZWdpbntibWF0cml4fQ0KMC40MCAmIC0wLjI2DQpcZW5ke2JtYXRyaXh9DQorDQpcYmVnaW57Ym1hdHJpeH0NCjAuMjMgJiAtMC4xNg0KXGVuZHtibWF0cml4fVxcDQomPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjYzICYgLTAuNDMNClxlbmR7Ym1hdHJpeH0uDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gYXR1cmFuIHlhbmcgc2FtYSwgZGlwZXJvbGVoIGtlbHVhcmFuIGFraGlyIGJsb2sgKmxpbmVhciBUcmFuc2Zvcm1lciogc2ViYWdhaSBiZXJpa3V0Lg0KDQpcWw0KXG1hdGhiZntafT0NClxiZWdpbntibWF0cml4fQ0KLTAuMTMgJiAwLjU1XFwNCi0wLjA3ICYgMC41MlxcDQowLjYzICYgLTAuNDNcXA0KMC40MSAmIC0wLjI4XFwNCi0wLjA4ICYgMC41M1xcDQotMC4xMyAmIDAuNTVcXA0KLTAuMDggJiAwLjUyXFwNCjAuODYgJiAtMC41OFxcDQowLjU1ICYgLTAuMzhcXA0KLTAuMDkgJiAwLjUzXFwNCi0wLjEzICYgMC41NVxcDQotMC4wNyAmIDAuNTJcXA0KMC44NiAmIC0wLjU4XFwNCjAuNTUgJiAtMC4zOFxcDQotMC4wOSAmIDAuNTNcXA0KLTAuMTMgJiAwLjU1XFwNCi0wLjEwICYgMC41NFxcDQowLjYwICYgLTAuNDFcXA0KMC4zNSAmIC0wLjI1XFwNCi0wLjExICYgMC41NFxcDQotMC4xMyAmIDAuNTVcXA0KLTAuMTEgJiAwLjU0XFwNCjAuMjggJiAtMC4xOVxcDQowLjA1ICYgMC40NlxcDQotMC4xMSAmIDAuNTQNClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQoNCiMjIyBsLiBOb3JtYWxpc2FzaSBha2hpciAqbGluZWFyIFRyYW5zZm9ybWVyKg0KDQpUYWhhcCB0ZXJha2hpciBwYWRhIGlsdXN0cmFzaSAqbGluZWFyIFRyYW5zZm9ybWVyKiBhZGFsYWggbm9ybWFsaXNhc2kgcGVyIHRva2VuIHRlcmhhZGFwIG1hdHJpa3Mga2VsdWFyYW4gcmVzaWR1YWwgTUxQIFwoXG1hdGhiZntafVwpLiBIYXNpbCBub3JtYWxpc2FzaSBkaW5vdGFzaWthbiBzZWJhZ2FpIFwoXG1hdGhiZntHfVwpIGRhbiBkaWd1bmFrYW4gc2ViYWdhaSByZXByZXNlbnRhc2kgZ2xvYmFsIHNlYmVsdW0gcHJvc2VzICpmb2xkaW5nKi4NCg0KLSAqKlJ1bXVzOioqDQoNClxbDQpcbWF0aGJme0d9DQo9DQpcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1p9KS4NClxdDQoNClVudHVrIHRva2VuIGtlLVwodFwpLCByYXRhLXJhdGEgZGFuIHZhcmlhbnMgZGloaXR1bmcgc2ViYWdhaToNCg0KXFsNClxtdV97Wix0fQ0KPQ0KXGZyYWN7MX17Mn0NClxzdW1fe249MX1eezJ9Wl97dCxufSwNClxdDQoNClxbDQpcc2lnbWFfe1osdH1eezJ9DQo9DQpcZnJhY3sxfXsyfQ0KXHN1bV97bj0xfV57Mn0NClxsZWZ0KA0KWl97dCxufS1cbXVfe1osdH0NClxyaWdodCleMi4NClxdDQoNClNlbGFuanV0bnlhLCBlbGVtZW4gaGFzaWwgbm9ybWFsaXNhc2kgZGlydW11c2thbiBzZWJhZ2FpOg0KDQpcWw0KR197dCxufQ0KPQ0KXGZyYWN7DQpaX3t0LG59LVxtdV97Wix0fQ0KfXsNClxzcXJ0ew0KXHNpZ21hX3taLHR9XnsyfSsxMF57LTV9DQp9DQp9Lg0KXF0NCg0KTWF0cmlrcyBcKFxtYXRoYmZ7R31cKSBiZXJ1a3VyYW4gXCgyNVx0aW1lczJcKS4NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiB0b2tlbiBwZXJ0YW1hOioqDQoNClxbDQpcbWF0aGJme1p9X3sxfT0NClxiZWdpbntibWF0cml4fQ0KLTAuMTMgJiAwLjU1DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KUmF0YS1yYXRhIHRva2VuIHBlcnRhbWEgYWRhbGFoOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcbXVfe1osMX0NCiY9DQpcZnJhY3stMC4xMyswLjU1fXsyfVxcDQomPQ0KMC4yMS4NClxlbmR7YWxpZ25lZH0NClxdDQoNClZhcmlhbnMgdG9rZW4gcGVydGFtYSBhZGFsYWg6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClxzaWdtYV97WiwxfV57Mn0NCiY9DQpcZnJhY3sNCigtMC4xMy0wLjIxKV4yKw0KKDAuNTUtMC4yMSleMg0KfXsyfVxcDQomPQ0KXGZyYWN7KC0wLjM0KV4yKygwLjM0KV4yfXsyfVxcDQomPQ0KMC4xMTU2Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KTWFrYToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KXG1hdGhiZntHfV97MX0NCiY9DQpcYmVnaW57Ym1hdHJpeH0NClxkZnJhY3stMC4xMy0wLjIxfQ0Ke1xzcXJ0ezAuMTE1NisxMF57LTV9fX0NCiYNClxkZnJhY3swLjU1LTAuMjF9DQp7XHNxcnR7MC4xMTU2KzEwXnstNX19fQ0KXGVuZHtibWF0cml4fVxcDQomPQ0KXGJlZ2lue2JtYXRyaXh9DQotMS4wMCAmIDEuMDANClxlbmR7Ym1hdHJpeH0uDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gYXR1cmFuIHlhbmcgc2FtYSwgZGlwZXJvbGVoIHJlcHJlc2VudGFzaSBnbG9iYWwgc2ViYWdhaSBiZXJpa3V0Lg0KDQpcWw0KXG1hdGhiZntHfT0NClxiZWdpbntibWF0cml4fQ0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMFxcDQoxLjAwICYgLTEuMDBcXA0KMS4wMCAmIC0xLjAwXFwNCi0xLjAwICYgMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCjEuMDAgJiAtMS4wMFxcDQoxLjAwICYgLTEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KMS4wMCAmIC0xLjAwXFwNCjEuMDAgJiAtMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMFxcDQoxLjAwICYgLTEuMDBcXA0KMS4wMCAmIC0xLjAwXFwNCi0xLjAwICYgMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCjEuMDAgJiAtMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KLTEuMDAgJiAxLjAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KIyMgNC4gRm9sZGluZywgUHJveWVrc2kgR2xvYmFsLCBkYW4gRnVzaSBSZXNpZHVhbA0KDQpLZWx1YXJhbiAqbGluZWFyIFRyYW5zZm9ybWVyKiBcKFxtYXRoYmZ7R31cKSBtYXNpaCBiZXJiZW50dWsgdXJ1dGFuIHRva2VuIGJlcnVrdXJhbiBcKDI1XHRpbWVzMlwpLiBQYWRhIHRhaGFwIGluaSwgdG9rZW4gZGlrZW1iYWxpa2FuIGtlIHN1c3VuYW4gc3Bhc2lhbCBiZXJ1a3VyYW4gXCg1XHRpbWVzNVwpIG1lbGFsdWkgcHJvc2VzICpmb2xkaW5nKi4gU2VsYW5qdXRueWEsIGtlZHVhIGthbmFsIGhhc2lsICpmb2xkaW5nKiBkaXByb3lla3Npa2FuIG1lbmphZGkgc2F0dSAqZmVhdHVyZSBtYXAqIGdsb2JhbC4gKkZlYXR1cmUgbWFwKiBnbG9iYWwgdGVyc2VidXQga2VtdWRpYW4gZGlnYWJ1bmdrYW4gZGVuZ2FuICpmZWF0dXJlIG1hcCogbG9rYWwgXChcbWF0aGJme0x9XCkgc2VydGEgKmZlYXR1cmUgbWFwKiBtYXN1a2FuIFwoXG1hdGhiZntYfVwpIG1lbGFsdWkgZnVzaSByZXNpZHVhbC4NCg0KIyMjIGEuIEZvbGRpbmcga2VsdWFyYW4gbGluZWFyIFRyYW5zZm9ybWVyDQoNCk1hdHJpa3MgXChcbWF0aGJme0d9XCkgbWVtaWxpa2kgZHVhIGtvbG9tLiBLb2xvbSBwZXJ0YW1hIGRpbGlwYXQga2VtYmFsaSBtZW5qYWRpIGthbmFsIHBlcnRhbWEgXChcbWF0aGJme0d9XzFcKSwgc2VkYW5na2FuIGtvbG9tIGtlZHVhIGRpbGlwYXQga2VtYmFsaSBtZW5qYWRpIGthbmFsIGtlZHVhIFwoXG1hdGhiZntHfV8yXCkuIFBvc2lzaSB0b2tlbiBkaXRlbnR1a2FuIGJlcmRhc2Fya2FuIHVydXRhbiByYXN0ZXIgZGFyaSBraXJpIGtlIGthbmFuIGRhbiBkYXJpIGF0YXMga2UgYmF3YWguDQoNCi0gKipSdW11czoqKg0KDQpcWw0KdD01KGktMSkraiwNClxxcXVhZA0KaSxqPTEsMixcbGRvdHMsNSwNClxdDQoNCmRlbmdhbiBcKGlcKSBtZW55YXRha2FuIGluZGVrcyBiYXJpcywgXChqXCkgbWVueWF0YWthbiBpbmRla3Mga29sb20sIGRhbiBcKHRcKSBtZW55YXRha2FuIGluZGVrcyB0b2tlbi4NCg0KVW50dWsgc2V0aWFwIHBvc2lzaSBzcGFzaWFsIFwoKGksailcKSwNCg0KXFsNCkdfezEsaSxqfT1HX3t0LDF9LA0KXHFxdWFkDQpHX3syLGksan09R197dCwyfSwNClxxcXVhZA0KdD01KGktMSkrai4NClxdDQoNCi0gKipDb250b2g6KioNCg0KQmFyaXMgcGVydGFtYSBwYWRhIG1hdHJpa3MgXChcbWF0aGJme0d9XCkgYWRhbGFoOg0KDQpcWw0KXG1hdGhiZntHfV97MX09DQpcYmVnaW57Ym1hdHJpeH0NCi0xLjAwICYgMS4wMA0KXGVuZHtibWF0cml4fS4NClxdDQoNCkthcmVuYSB0b2tlbiBwZXJ0YW1hIGJlcmFkYSBwYWRhIHBvc2lzaSBcKCgxLDEpXCksIG1ha2E6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NCnQNCiY9NSgxLTEpKzFcXA0KJj0xLg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KRGVuZ2FuIGRlbWlraWFuLCBuaWxhaSBoYXNpbCAqZm9sZGluZyogcGFkYSBwb3Npc2kgXCgoMSwxKVwpIGFkYWxhaDoNCg0KXFsNCkdfezEsMSwxfT0tMS4wMCwNClxxcXVhZA0KR197MiwxLDF9PTEuMDAuDQpcXQ0KDQpNYXRyaWtzIGthbmFsIHBlcnRhbWEgc2V0ZWxhaCBwcm9zZXMgKmZvbGRpbmcqIGFkYWxhaDoNCg0KXFsNClxtYXRoYmZ7R31fMT0NClxiZWdpbntibWF0cml4fQ0KLTEuMDAgJiAtMS4wMCAmIDEuMDAgJiAxLjAwICYgLTEuMDBcXA0KLTEuMDAgJiAtMS4wMCAmIDEuMDAgJiAxLjAwICYgLTEuMDBcXA0KLTEuMDAgJiAtMS4wMCAmIDEuMDAgJiAxLjAwICYgLTEuMDBcXA0KLTEuMDAgJiAtMS4wMCAmIDEuMDAgJiAxLjAwICYgLTEuMDBcXA0KLTEuMDAgJiAtMS4wMCAmIDEuMDAgJiAtMS4wMCAmIC0xLjAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KTWF0cmlrcyBrYW5hbCBrZWR1YSBzZXRlbGFoIHByb3NlcyAqZm9sZGluZyogYWRhbGFoOg0KDQpcWw0KXG1hdGhiZntHfV8yPQ0KXGJlZ2lue2JtYXRyaXh9DQoxLjAwICYgMS4wMCAmIC0xLjAwICYgLTEuMDAgJiAxLjAwXFwNCjEuMDAgJiAxLjAwICYgLTEuMDAgJiAtMS4wMCAmIDEuMDBcXA0KMS4wMCAmIDEuMDAgJiAtMS4wMCAmIC0xLjAwICYgMS4wMFxcDQoxLjAwICYgMS4wMCAmIC0xLjAwICYgLTEuMDAgJiAxLjAwXFwNCjEuMDAgJiAxLjAwICYgLTEuMDAgJiAxLjAwICYgMS4wMA0KXGVuZHtibWF0cml4fS4NClxdDQoNCktlZHVhIG1hdHJpa3MgaGFzaWwgKmZvbGRpbmcqLCB5YWl0dSBcKFxtYXRoYmZ7R31fMVwpIGRhbiBcKFxtYXRoYmZ7R31fMlwpLCBtYXNpbmctbWFzaW5nIGJlcnVrdXJhbiBcKDVcdGltZXM1XCkuDQoNCiMjIyBiLiBQcm95ZWtzaSBkYW4gYWt0aXZhc2kgKmZlYXR1cmUgbWFwKiBnbG9iYWwNCg0KRHVhIGthbmFsIGhhc2lsICpmb2xkaW5nKiwgeWFpdHUgXChcbWF0aGJme0d9XzFcKSBkYW4gXChcbWF0aGJme0d9XzJcKSwgZGlwcm95ZWtzaWthbiBtZW5qYWRpIHNhdHUga2FuYWwgbWVuZ2d1bmFrYW4gKnBvaW50d2lzZSBjb252b2x1dGlvbiogXCgxXHRpbWVzMVwpIHRhbnBhIGJpYXMuIEhhc2lsIHByb3lla3NpIGtlbXVkaWFuIGRpdGVyYXBrYW4gZnVuZ3NpIFN3aXNoIHVudHVrIG1lbWJlbnR1ayAqZmVhdHVyZSBtYXAqIGdsb2JhbCBcKFxtYXRoYmZ7R31fe1xtYXRocm17Z2xvYn19XCkuDQoNCi0gKipCb2JvdCBwcm95ZWtzaSBnbG9iYWw6KioNCg0KXFsNClxtYXRoYmZ7V31fe1xtYXRocm17Z2xvYn19DQo9DQpcYmVnaW57Ym1hdHJpeH0NCjAuNTUgJiAtMC4zMA0KXGVuZHtibWF0cml4fS4NClxdDQoNCi0gKipSdW11czoqKg0KDQpOaWxhaSBoYXNpbCBwcm95ZWtzaSBzZWJlbHVtIGFrdGl2YXNpIGRpbm90YXNpa2FuIHNlYmFnYWkgXChGX3tcbWF0aHJte2dsb2J9LGksan1cKToNCg0KXFsNCkZfe1xtYXRocm17Z2xvYn0saSxqfQ0KPQ0KMC41NUdfezEsaSxqfQ0KLQ0KMC4zMEdfezIsaSxqfS4NClxdDQoNClNlbGFuanV0bnlhLCBmdW5nc2kgU3dpc2ggZGl0ZXJhcGthbiBzZWJhZ2FpIGJlcmlrdXQ6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NCkdfe1xtYXRocm17Z2xvYn0saSxqfQ0KJj0NClxvcGVyYXRvcm5hbWV7U3dpc2h9DQpcbGVmdCgNCkZfe1xtYXRocm17Z2xvYn0saSxqfQ0KXHJpZ2h0KVxcDQomPQ0KXGZyYWN7DQpGX3tcbWF0aHJte2dsb2J9LGksan0NCn17DQoxK2Veey1GX3tcbWF0aHJte2dsb2J9LGksan19DQp9Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KTWF0cmlrcyBcKFxtYXRoYmZ7R31fe1xtYXRocm17Z2xvYn19XCkgYmVydWt1cmFuIFwoNVx0aW1lczVcKS4NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiBwYWRhIHBvc2lzaSBcKCgxLDEpXCk6KioNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KRl97XG1hdGhybXtnbG9ifSwxLDF9DQomPQ0KMC41NUdfezEsMSwxfQ0KLQ0KMC4zMEdfezIsMSwxfVxcDQomPQ0KMC41NSgtMS4wMCkNCi0NCjAuMzAoMS4wMClcXA0KJj0NCi0wLjg1Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KR197XG1hdGhybXtnbG9ifSwxLDF9DQomPQ0KXG9wZXJhdG9ybmFtZXtTd2lzaH0oLTAuODUpXFwNCiY9DQpcZnJhY3stMC44NX17MStlXnstKC0wLjg1KX19XFwNCiY9DQpcZnJhY3stMC44NX17MStlXnswLjg1fX1cXA0KJj0NClxmcmFjey0wLjg1fXsxKzIuMzR9XFwNCiY9DQotMC4yNS4NClxlbmR7YWxpZ25lZH0NClxdDQoNClVudHVrIHBvc2lzaSBkZW5nYW4gXChHX3sxLGksan09MS4wMFwpIGRhbiBcKEdfezIsaSxqfT0tMS4wMFwpLCBkaXBlcm9sZWggbmlsYWkgaGFzaWwgcHJveWVrc2kgc2ViZXNhciBcKDAuODVcKSwgc2VoaW5nZ2EgbmlsYWkgc2V0ZWxhaCBha3RpdmFzaSBTd2lzaCBhZGFsYWggXCgwLjYwXCkuDQoNCkRlbmdhbiBhdHVyYW4geWFuZyBzYW1hLCBkaXBlcm9sZWggKmZlYXR1cmUgbWFwKiBnbG9iYWwgc2ViYWdhaSBiZXJpa3V0Lg0KDQpcWw0KXG1hdGhiZntHfV97XG1hdGhybXtnbG9ifX09DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjI1ICYgLTAuMjUgJiAwLjYwICYgMC42MCAmIC0wLjI1XFwNCi0wLjI1ICYgLTAuMjUgJiAwLjYwICYgMC42MCAmIC0wLjI1XFwNCi0wLjI1ICYgLTAuMjUgJiAwLjYwICYgMC42MCAmIC0wLjI1XFwNCi0wLjI1ICYgLTAuMjUgJiAwLjYwICYgMC42MCAmIC0wLjI1XFwNCi0wLjI1ICYgLTAuMjUgJiAwLjYwICYgLTAuMjUgJiAtMC4yNQ0KXGVuZHtibWF0cml4fS4NClxdDQoNCg0KIyMjIGMuIEZ1c2kgcmVzaWR1YWwgZml0dXIgbG9rYWwgZGFuIGdsb2JhbA0KDQoqRmVhdHVyZSBtYXAqIGxva2FsIFwoXG1hdGhiZntMfVwpIGRhbiAqZmVhdHVyZSBtYXAqIGdsb2JhbCBcKFxtYXRoYmZ7R31fe1xtYXRocm17Z2xvYn19XCkgZGlnYWJ1bmdrYW4gbWVsYWx1aSBvcGVyYXNpICpjb25jYXRlbmF0ZSouIEhhc2lsIHBlbmdnYWJ1bmdhbiB0ZXJzZWJ1dCBkaXByb3lla3Npa2FuIG1lbmdndW5ha2FuICpwb2ludHdpc2UgY29udm9sdXRpb24qIFwoMVx0aW1lczFcKSwga2VtdWRpYW4gZGl0YW1iYWhrYW4gZGVuZ2FuICpmZWF0dXJlIG1hcCogbWFzdWthbiBcKFxtYXRoYmZ7WH1cKSBtZWxhbHVpICpyZXNpZHVhbCBjb25uZWN0aW9uKi4gS2VsdWFyYW4gZnVzaSBkaW5vdGFzaWthbiBzZWJhZ2FpIFwoXG1hdGhiZntYfV57MCwwfVwpLg0KDQpQYWRhIGlsdXN0cmFzaSBpbmksICpwb2ludHdpc2UgY29udm9sdXRpb24qIFwoMVx0aW1lczFcKSBkaWxha3VrYW4gdGFucGEgYmlhcy4gQm9ib3QgZnVzaSB1bnR1ayAqZmVhdHVyZSBtYXAqIGxva2FsIGRhbiBnbG9iYWwgZGl0ZXRhcGthbiBzZWJhZ2FpIGJlcmlrdXQ6DQoNClxbDQpcbWF0aGJme1d9X3tcbWF0aHJte2Z1c2V9fQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjQ1ICYgMC4zNQ0KXGVuZHtibWF0cml4fS4NClxdDQoNCkJvYm90IHBlcnRhbWEgZGl0ZXJhcGthbiBwYWRhIFwoXG1hdGhiZntMfVwpLCBzZWRhbmdrYW4gYm9ib3Qga2VkdWEgZGl0ZXJhcGthbiBwYWRhIFwoXG1hdGhiZntHfV97XG1hdGhybXtnbG9ifX1cKS4NCg0KLSAqKlJ1bXVzOioqDQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClxtYXRoYmZ7WH1eezAsMH0NCiY9DQpcbWF0aGJme1h9DQorDQpcb3BlcmF0b3JuYW1le0NvbnZ9X3sxXHRpbWVzMX0NClxsZWZ0KA0KXG9wZXJhdG9ybmFtZXtDb25jYXR9DQpcbGVmdFsNClxtYXRoYmZ7TH0sDQpcbWF0aGJme0d9X3tcbWF0aHJte2dsb2J9fQ0KXHJpZ2h0XQ0KXHJpZ2h0KS4NClxlbmR7YWxpZ25lZH0NClxdDQoNClVudHVrIHNldGlhcCBwb3Npc2kgc3Bhc2lhbCBcKChpLGopXCksIGJlbnR1ayBwZXJoaXR1bmdhbm55YSBhZGFsYWg6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NCkZfe1xtYXRocm17ZnVzZX0saSxqfQ0KJj0NCjAuNDVMX3tpLGp9DQorDQowLjM1R197XG1hdGhybXtnbG9ifSxpLGp9LFxcDQpYXnswLDB9X3tpLGp9DQomPQ0KWF97aSxqfQ0KKw0KRl97XG1hdGhybXtmdXNlfSxpLGp9XFwNCiY9DQpYX3tpLGp9DQorDQowLjQ1TF97aSxqfQ0KKw0KMC4zNUdfe1xtYXRocm17Z2xvYn0saSxqfS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gcGFkYSBwb3Npc2kgXCgoMSwxKVwpOioqDQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClheezAsMH1fezEsMX0NCiY9DQpYX3sxLDF9DQorDQowLjQ1TF97MSwxfQ0KKw0KMC4zNUdfe1xtYXRocm17Z2xvYn0sMSwxfVxcDQomPQ0KLTIuMTINCisNCjAuNDUoLTAuMjgpDQorDQowLjM1KC0wLjI1KVxcDQomPQ0KLTIuMTItMC4xMjYtMC4wODc1XFwNCiY9DQotMi4zMy4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBwZXJoaXR1bmdhbiB5YW5nIHNhbWEsIGRpcGVyb2xlaCBrZWx1YXJhbiBibG9rIE1vYmlsZVZpVHYzLXYyLTEuMCBzZWJhZ2FpIGJlcmlrdXQuDQoNClxbDQpcbWF0aGJme1h9XnswLDB9PQ0KXGJlZ2lue2JtYXRyaXh9DQotMi4zMyAmIC0xLjIxICYgMS41NSAmIDAuOTEgJiAtMS43NlxcDQotMi4zMyAmIC0wLjk0ICYgMS45MSAmIDEuMjUgJiAtMS42MlxcDQotMi4zMyAmIC0wLjk0ICYgMS45MiAmIDEuMjUgJiAtMS42MlxcDQotMi4zMyAmIC0xLjA4ICYgMS41NCAmIDAuODggJiAtMS43N1xcDQotMi4xOSAmIC0xLjUwICYgMC41OCAmIC0wLjMyICYgLTEuOTENClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQpNYXRyaWtzIFwoXG1hdGhiZntYfV57MCwwfVwpIGJlcnVrdXJhbiBcKDVcdGltZXM1XCkuIEtlbHVhcmFuIGluaSBtZW5qYWRpIG1hc3VrYW4gcGFkYSB0YWhhcCAqZW5jb2RlciBkb3duc2FtcGxpbmcqIGRhbiBkZWNvZGVyIFVOZXQrKy4NCg0KIyMgNS4gKkVuY29kZXIqIEJlcnRpbmdrYXQgDQoNClBhZGEgdGFoYXAgaW5pLCBmZWF0dXJlIG1hcCBrZWx1YXJhbiBNb2JpbGVWaVR2My12MiwgeWFpdHUgKFxtYXRoYmZ7WH1eezAsMH0pLCBkaXByb3NlcyBtZWxhbHVpIHRhaGFwYW4gZW5jb2RlciBiZXJ0aW5na2F0IHVudHVrIG1lbXBlcm9sZWggcmVwcmVzZW50YXNpIGZpdHVyIHBhZGEgYmVyYmFnYWkgc2thbGEgc3Bhc2lhbC4gUHJvc2VzIGRvd25zYW1wbGluZyBkaWxha3VrYW4gbWVuZ2d1bmFrYW4gc3RyaWRlZCBjb252b2x1dGlvbiB1bnR1ayBtZW5ndXJhbmdpIGRpbWVuc2kgc3Bhc2lhbCBmZWF0dXJlIG1hcCBzZWNhcmEgYmVydGFoYXAuIFNldGlhcCB0YWhhcCBtZW5naGFzaWxrYW4gcmVwcmVzZW50YXNpIGZpdHVyIGRlbmdhbiB1a3VyYW4gc3Bhc2lhbCB5YW5nIGxlYmloIGtlY2lsLCB5YW5nIHNlbGFuanV0bnlhIGRpZ3VuYWthbiBwYWRhIHByb3NlcyBla3N0cmFrc2kgZml0dXIgYmVydGluZ2thdC4gUGFkYSBqYWx1ciBlbmNvZGVyLCB0aWRhayBkaWxha3VrYW4gb3BlcmFzaSB1cHNhbXBsaW5nIGthcmVuYSBwcm9zZXMgdGVyc2VidXQgbWVydXBha2FuIGJhZ2lhbiBkYXJpIHRhaGFwYW4gZGVjb2Rlci4NCg0KIyMjIGEuICpEb3duc2FtcGxpbmcgZW5jb2RlciogcGVydGFtYSBcKFxsZWZ0KFxtYXRoYmZ7WH1eezEsMH1ccmlnaHQpXCkNCg0KKkZlYXR1cmUgbWFwKiBcKFxtYXRoYmZ7WH1eezAsMH1cKSBiZXJ1a3VyYW4gXCg1XHRpbWVzNVwpIGRpcHJvc2VzIG1lbmdndW5ha2FuICpzdHJpZGVkIGNvbnZvbHV0aW9uKiBkZW5nYW4ga2VybmVsIFwoM1x0aW1lczNcKSwgKnN0cmlkZSogXCgyXCksIGRhbiAqemVybyBwYWRkaW5nKiBzZWJlc2FyIFwoMVwpIHBhZGEgc2V0aWFwIHNpc2kuIFBhZGEgaWx1c3RyYXNpIGluaSwgb3BlcmFzaSBrb252b2x1c2kgZGlsYWt1a2FuIHRhbnBhIGJpYXMuIEtlbHVhcmFuIGtvbnZvbHVzaSBwYWRhIHRhaGFwIGluaSBkaW5vdGFzaWthbiBzZWJhZ2FpIFwoXG1hdGhiZntGfV97XG1hdGhybXtlbmN9fV57KDEpfVwpLCBkZW5nYW46DQoNClxbDQpcbWF0aGJme1h9XnsxLDB9DQo9DQpcbWF0aGJme0Z9X3tcbWF0aHJte2VuY319XnsoMSl9Lg0KXF0NCg0KLSAqKlBlbmFtYmFoYW4gWmVybyBQYWRkaW5nOioqDQoNClNlYmVsdW0gb3BlcmFzaSAqc3RyaWRlZCBjb252b2x1dGlvbiogZGlsYWt1a2FuLCBzYXR1IGxhcGlzYW4gbmlsYWkgbm9sIGRpdGFtYmFoa2FuIHBhZGEga2VlbXBhdCBzaXNpICpmZWF0dXJlIG1hcCogbWFzdWthbiwgeWFpdHUgc2lzaSBhdGFzLCBiYXdhaCwga2lyaSwgZGFuIGthbmFuLiBQZW5hbWJhaGFuICp6ZXJvIHBhZGRpbmcqIG1lbXVuZ2tpbmthbiBrZXJuZWwgbWVuY2FrdXAgYXJlYSB0ZXBpIG1hdHJpa3Mgc2VsYW1hIHByb3NlcyBrb252b2x1c2kuDQoNCk1hdHJpa3MgKmZlYXR1cmUgbWFwKiBtYXN1a2FuIG1lcnVwYWthbiBrZWx1YXJhbiBibG9rIE1vYmlsZVZpVHYzLXYyLTEuMCB5YW5nIGRpcGVyb2xlaCBwYWRhIHRhaGFwIHNlYmVsdW1ueWEsIHlhaXR1Og0KDQpcWw0KXG1hdGhiZntYfV57MCwwfQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQotMi4zMyAmIC0xLjIxICYgMS41NSAmIDAuOTEgJiAtMS43NlxcDQotMi4zMyAmIC0wLjk0ICYgMS45MSAmIDEuMjUgJiAtMS42MlxcDQotMi4zMyAmIC0wLjk0ICYgMS45MiAmIDEuMjUgJiAtMS42MlxcDQotMi4zMyAmIC0xLjA4ICYgMS41NCAmIDAuODggJiAtMS43N1xcDQotMi4xOSAmIC0xLjUwICYgMC41OCAmIC0wLjMyICYgLTEuOTENClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQpTZXRlbGFoIHBlbmFtYmFoYW4gKnplcm8gcGFkZGluZyogc2ViZXNhciBzYXR1IHBpa3NlbCBwYWRhIHNldGlhcCBzaXNpLCB1a3VyYW4gbWF0cmlrcyBiZXJ1YmFoIGRhcmkgXCg1XHRpbWVzNVwpIG1lbmphZGkgXCg3XHRpbWVzN1wpLCB5YWl0dToNCg0KXFsNClxtYXRoYmZ7WH1fe1xtYXRocm17cGFkfX1eezAsMH0NCj0NClxiZWdpbntibWF0cml4fQ0KMC4wMCAmIDAuMDAgJiAwLjAwICYgMC4wMCAmIDAuMDAgJiAwLjAwICYgMC4wMFxcDQowLjAwICYgLTIuMzMgJiAtMS4yMSAmIDEuNTUgJiAwLjkxICYgLTEuNzYgJiAwLjAwXFwNCjAuMDAgJiAtMi4zMyAmIC0wLjk0ICYgMS45MSAmIDEuMjUgJiAtMS42MiAmIDAuMDBcXA0KMC4wMCAmIC0yLjMzICYgLTAuOTQgJiAxLjkyICYgMS4yNSAmIC0xLjYyICYgMC4wMFxcDQowLjAwICYgLTIuMzMgJiAtMS4wOCAmIDEuNTQgJiAwLjg4ICYgLTEuNzcgJiAwLjAwXFwNCjAuMDAgJiAtMi4xOSAmIC0xLjUwICYgMC41OCAmIC0wLjMyICYgLTEuOTEgJiAwLjAwXFwNCjAuMDAgJiAwLjAwICYgMC4wMCAmIDAuMDAgJiAwLjAwICYgMC4wMCAmIDAuMDANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQotICoqS2VybmVsIEVuY29kZXIgUGVydGFtYToqKg0KDQpQYWRhIGlsdXN0cmFzaSBpbmksIGtlcm5lbCBkaXNlZGVyaGFuYWthbiBkZW5nYW4gaGFueWEgZWxlbWVuIHRlbmdhaCBiZXJuaWxhaSBzYXR1IGRhbiBlbGVtZW4gbGFpbm55YSBiZXJuaWxhaSBub2w6DQoNClxbDQpcbWF0aGJme1d9X3tcbWF0aHJte2VuY319XnsoMSl9DQo9DQpcYmVnaW57Ym1hdHJpeH0NCjAgJiAwICYgMFxcDQowICYgMSAmIDBcXA0KMCAmIDAgJiAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KS2VybmVsIHRlcnNlYnV0IGRpZ3VuYWthbiB1bnR1ayBtZW5naWx1c3RyYXNpa2FuIG9wZXJhc2kgKnN0cmlkZWQgY29udm9sdXRpb24qLiBQYWRhIHNldGlhcCBwb3Npc2ksIHNlbWJpbGFuIGVsZW1lbiBkYWxhbSBhcmVhIGtvbnZvbHVzaSBkaWthbGlrYW4gZGVuZ2FuIHNlbWJpbGFuIGJvYm90IGtlcm5lbCB5YW5nIGJlcnNlc3VhaWFuLCBrZW11ZGlhbiBzZWx1cnVoIGhhc2lsIHBlcmthbGlhbiBkaWp1bWxhaGthbi4NCg0KS2FyZW5hIGhhbnlhIGJvYm90IHB1c2F0IGtlcm5lbCB5YW5nIGJlcm5pbGFpIHNhdHUsIGhhc2lsIGtvbnZvbHVzaSBwYWRhIGlsdXN0cmFzaSBpbmkgZGl0ZW50dWthbiBvbGVoIGVsZW1lbiB5YW5nIGJlcmFkYSB0ZXBhdCBkaSBiYXdhaCBwdXNhdCBrZXJuZWwuIFNlbWVudGFyYSBpdHUsIHBlbmdndW5hYW4gKnN0cmlkZSogc2ViZXNhciBcKDJcKSBtZW55ZWJhYmthbiBrZXJuZWwgYmVyZ2VzZXIgZHVhIHBvc2lzaSBwYWRhIHNldGlhcCBwZXJwaW5kYWhhbi4NCg0KVWt1cmFuIGtlbHVhcmFuIGRpaGl0dW5nIG1lbmdndW5ha2FuOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpvDQomPQ0KXGxlZnRcbGZsb29yDQpcZnJhY3tpKzJwLWt9e3N9DQpccmlnaHRccmZsb29yKzFcXA0KJj0NClxsZWZ0XGxmbG9vcg0KXGZyYWN7NSsyKDEpLTN9ezJ9DQpccmlnaHRccmZsb29yKzFcXA0KJj0NClxsZWZ0XGxmbG9vcg0KXGZyYWN7NH17Mn0NClxyaWdodFxyZmxvb3IrMVxcDQomPTMuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gZGVtaWtpYW4sIHVrdXJhbiBzcGFzaWFsICpmZWF0dXJlIG1hcCogYmVydWJhaCBkYXJpIFwoNVx0aW1lczVcKSBtZW5qYWRpIFwoM1x0aW1lczNcKS4NCg0KLSAqKlJ1bXVzOioqDQoNClNlY2FyYSB1bXVtLCBvcGVyYXNpICpzdHJpZGVkIGNvbnZvbHV0aW9uKiBkZW5nYW4ga2VybmVsIFwoM1x0aW1lczNcKSwgKnN0cmlkZSogXCgyXCksIGRhbiAqcGFkZGluZyogXCgxXCkgZGlueWF0YWthbiBzZWJhZ2FpOg0KDQpcWw0KRl97XG1hdGhybXtlbmN9LGEsYn1eeygxKX0NCj0NClxzdW1fe3U9MX1eezN9DQpcc3VtX3t2PTF9XnszfQ0KV197XG1hdGhybXtlbmN9LHUsdn1eeygxKX0NClhfe1xtYXRocm17cGFkfSwyYSt1LTIsXCwyYit2LTJ9XnswLDB9LA0KXF0NCg0KZGVuZ2FuIFwoYSxiPTEsMiwzXCksIHNlZGFuZ2thbiBcKHVcKSBkYW4gXCh2XCkgbWVydXBha2FuIGluZGVrcyBiYXJpcyBkYW4ga29sb20ga2VybmVsLg0KDQpQYWRhIHNldGlhcCBwb3Npc2ksIGtlcm5lbCBtZW5jYWt1cCBhcmVhIGJlcnVrdXJhbiBcKDNcdGltZXMzXCkuIEthcmVuYSAqc3RyaWRlKiBiZXJuaWxhaSBcKDJcKSwga2VybmVsIGJlcmdlc2VyIGR1YSBrb2xvbSBrZSBrYW5hbiB1bnR1ayBtZW5naGl0dW5nIGVsZW1lbiBiZXJpa3V0bnlhIHBhZGEgYmFyaXMga2VsdWFyYW4geWFuZyBzYW1hLiBTZXRlbGFoIG1lbmNhcGFpIHBvc2lzaSB0ZXJha2hpciBwYWRhIGJhcmlzIHRlcnNlYnV0LCBrZXJuZWwga2VtYmFsaSBrZSBzaXNpIGtpcmkgZGFuIGJlcmdlc2VyIGR1YSBiYXJpcyBrZSBiYXdhaC4NCg0KLSAqKkNvbnRvaCBQZXJoaXR1bmdhbiBLb252b2x1c2k6KioNCg0KKioxLiBQZXJoaXR1bmdhbiBlbGVtZW4gcGFkYSBwb3Npc2kgXCgoMSwxKVwpKioNCg0KVW50dWsgbWVuZ2hhc2lsa2FuIGVsZW1lbiBwZXJ0YW1hIGRhcmkgKmZlYXR1cmUgbWFwKiBrZWx1YXJhbiwga2VybmVsIGRpdGVtcGF0a2FuIHBhZGEgYXJlYSBcKDNcdGltZXMzXCkgZGkgcG9qb2sga2lyaSBhdGFzIG1hdHJpa3MgeWFuZyB0ZWxhaCBkaWJlcmkgKnplcm8gcGFkZGluZyouDQoNCkFyZWEgKmZlYXR1cmUgbWFwKiB5YW5nIGRpcHJvc2VzIGFkYWxhaDoNCg0KXFsNClxiZWdpbntibWF0cml4fQ0KMC4wMCAmIDAuMDAgJiAwLjAwXFwNCjAuMDAgJiAtMi4zMyAmIC0xLjIxXFwNCjAuMDAgJiAtMi4zMyAmIC0wLjk0DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KU2V0aWFwIGVsZW1lbiBwYWRhIGFyZWEgdGVyc2VidXQgZGlrYWxpa2FuIGRlbmdhbiBib2JvdCBrZXJuZWwgeWFuZyBiZXJzZXN1YWlhbiwga2VtdWRpYW4gc2VsdXJ1aCBoYXNpbCBwZXJrYWxpYW4gZGlqdW1sYWhrYW4gc2ViYWdhaSBiZXJpa3V0Og0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpGX3tcbWF0aHJte2VuY30sMSwxfV57KDEpfQ0KPXt9Jg0KKDAuMDApKDApDQorKDAuMDApKDApDQorKDAuMDApKDApXFwNCiYrKDAuMDApKDApDQorKC0yLjMzKSgxKQ0KKygtMS4yMSkoMClcXA0KJisoMC4wMCkoMCkNCisoLTIuMzMpKDApDQorKC0wLjk0KSgwKVxcDQo9e30mLTIuMzMuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gZGVtaWtpYW4sIG5pbGFpIGVsZW1lbiBrZWx1YXJhbiBwYWRhIHBvc2lzaSBcKCgxLDEpXCkgYWRhbGFoOg0KDQpcWw0KWF97MSwxfV57MSwwfQ0KPQ0KRl97XG1hdGhybXtlbmN9LDEsMX1eeygxKX0NCj0NCi0yLjMzLg0KXF0NCg0KKioyLiBQZXJoaXR1bmdhbiBlbGVtZW4gcGFkYSBwb3Npc2kgXCgoMSwyKVwpKioNCg0KVW50dWsgbWVuZ2hpdHVuZyBlbGVtZW4gcGFkYSBwb3Npc2kgXCgoMSwyKVwpLCBrZXJuZWwgYmVyZ2VzZXIgZHVhIGtvbG9tIGtlIGthbmFuIGRhcmkgcG9zaXNpIHNlYmVsdW1ueWEga2FyZW5hICpzdHJpZGUqIHlhbmcgZGlndW5ha2FuIGJlcm5pbGFpIFwoMlwpLg0KDQpBcmVhICpmZWF0dXJlIG1hcCogeWFuZyBkaXByb3NlcyBhZGFsYWg6DQoNClxbDQpcYmVnaW57Ym1hdHJpeH0NCjAuMDAgJiAwLjAwICYgMC4wMFxcDQotMS4yMSAmIDEuNTUgJiAwLjkxXFwNCi0wLjk0ICYgMS45MSAmIDEuMjUNClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQpQZXJoaXR1bmdhbiBrb252b2x1c2kgZGlsYWt1a2FuIG1lbmdndW5ha2FuIGJvYm90IGtlcm5lbCB5YW5nIHNhbWE6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NCkZfe1xtYXRocm17ZW5jfSwxLDJ9XnsoMSl9DQo9e30mDQooMC4wMCkoMCkNCisoMC4wMCkoMCkNCisoMC4wMCkoMClcXA0KJisoLTEuMjEpKDApDQorKDEuNTUpKDEpDQorKDAuOTEpKDApXFwNCiYrKC0wLjk0KSgwKQ0KKygxLjkxKSgwKQ0KKygxLjI1KSgwKVxcDQo9e30mMS41NS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBkZW1pa2lhbiwgbmlsYWkgZWxlbWVuIGtlbHVhcmFuIHBhZGEgcG9zaXNpIFwoKDEsMilcKSBhZGFsYWg6DQoNClxbDQpYX3sxLDJ9XnsxLDB9DQo9DQpGX3tcbWF0aHJte2VuY30sMSwyfV57KDEpfQ0KPQ0KMS41NS4NClxdDQoNClByb3NlZHVyIHlhbmcgc2FtYSBkaXRlcmFwa2FuIHBhZGEgc2VsdXJ1aCBwb3Npc2kga2VybmVsLiBTZXRpYXAgZWxlbWVuIGtlbHVhcmFuIGRpcGVyb2xlaCBtZWxhbHVpIHBlbmp1bWxhaGFuIGhhc2lsIHBlcmthbGlhbiBlbGVtZW4gcGFkYSBhcmVhIGtvbnZvbHVzaSBkZW5nYW4gYm9ib3Qga2VybmVsIHlhbmcgYmVyc2VzdWFpYW4uDQoNCkRlbmdhbiBtZW5lcmFwa2FuIG9wZXJhc2kgKnN0cmlkZWQgY29udm9sdXRpb24qIHBhZGEgc2VsdXJ1aCBwb3Npc2ksIGRpcGVyb2xlaCAqZmVhdHVyZSBtYXAgZW5jb2RlciogcGVydGFtYSBiZXJ1a3VyYW4gXCgzXHRpbWVzM1wpLCB5YWl0dToNCg0KXFsNClxtYXRoYmZ7WH1eezEsMH0NCj0NClxiZWdpbntibWF0cml4fQ0KLTIuMzMgJiAxLjU1ICYgLTEuNzZcXA0KLTIuMzMgJiAxLjkyICYgLTEuNjJcXA0KLTIuMTkgJiAwLjU4ICYgLTEuOTENClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQpIYXNpbCB0ZXJzZWJ1dCBtZW51bmp1a2thbiBiYWh3YSBvcGVyYXNpICpzdHJpZGVkIGNvbnZvbHV0aW9uKiBkZW5nYW4gKnN0cmlkZSogXCgyXCkgbWVuZ3VyYW5naSB1a3VyYW4gc3Bhc2lhbCAqZmVhdHVyZSBtYXAqIGRhcmkgXCg1XHRpbWVzNVwpIG1lbmphZGkgXCgzXHRpbWVzM1wpLiBQYWRhIGlsdXN0cmFzaSBpbmksIHBlbnllZGVyaGFuYWFuIGJvYm90IGtlcm5lbCBtZW55ZWJhYmthbiBzZXRpYXAgZWxlbWVuIGtlbHVhcmFuIHNhbWEgZGVuZ2FuIGVsZW1lbiBtYXN1a2FuIHlhbmcgYmVyYWRhIHBhZGEgcG9zaXNpIHB1c2F0IGtlcm5lbC4gTmFtdW4sIHBhZGEgaW1wbGVtZW50YXNpIG1vZGVsIHNlYmVuYXJueWEsIGJvYm90IGtlcm5lbCBkaXBlbGFqYXJpIHNlbGFtYSBwZWxhdGloYW4gc2VoaW5nZ2Ega2VsdWFyYW4ga29udm9sdXNpIG1lcnVwYWthbiBrb21iaW5hc2kgYmVyYm9ib3QgZGFyaSBlbGVtZW4tZWxlbWVuIHBhZGEgYXJlYSB5YW5nIGRpcHJvc2VzLg0KDQoNCg0KIyMjIGIuICpEb3duc2FtcGxpbmcgZW5jb2Rlcioga2VkdWEgXChcbGVmdChcbWF0aGJme1h9XnsyLDB9XHJpZ2h0KVwpDQoNCipGZWF0dXJlIG1hcCogXChcbWF0aGJme1h9XnsxLDB9XCkgYmVydWt1cmFuIFwoM1x0aW1lczNcKSBrZW1iYWxpIGRpcHJvc2VzIG1lbmdndW5ha2FuICpzdHJpZGVkIGNvbnZvbHV0aW9uKiBkZW5nYW4ga2VybmVsIFwoM1x0aW1lczNcKSwgKnN0cmlkZSogXCgyXCksIGRhbiAqemVybyBwYWRkaW5nKiBzZWJlc2FyIFwoMVwpIHBhZGEgc2V0aWFwIHNpc2kuIFBhZGEgaWx1c3RyYXNpIGluaSwgb3BlcmFzaSBrb252b2x1c2kgZGlsYWt1a2FuIHRhbnBhIGJpYXMuIEtlbHVhcmFuIGtvbnZvbHVzaSBwYWRhIHRhaGFwIGtlZHVhIGRpbm90YXNpa2FuIHNlYmFnYWkgXChcbWF0aGJme0Z9X3tcbWF0aHJte2VuY319XnsoMil9XCksIGRlbmdhbjoNCg0KXFsNClxtYXRoYmZ7WH1eezIsMH0NCj0NClxtYXRoYmZ7Rn1fe1xtYXRocm17ZW5jfX1eeygyKX0uDQpcXQ0KDQotICoqUGVuYW1iYWhhbiBaZXJvIFBhZGRpbmc6KioNCg0KU2ViZWx1bSBvcGVyYXNpICpzdHJpZGVkIGNvbnZvbHV0aW9uKiBkaWxha3VrYW4sIHNhdHUgbGFwaXNhbiBuaWxhaSBub2wgZGl0YW1iYWhrYW4gcGFkYSBrZWVtcGF0IHNpc2kgKmZlYXR1cmUgbWFwKiBtYXN1a2FuLCB5YWl0dSBzaXNpIGF0YXMsIGJhd2FoLCBraXJpLCBkYW4ga2FuYW4uIFBlbmFtYmFoYW4gKnplcm8gcGFkZGluZyogbWVtdW5na2lua2FuIGtlcm5lbCBtZW5jYWt1cCBhcmVhIHRlcGkgbWF0cmlrcyBzZWxhbWEgcHJvc2VzIGtvbnZvbHVzaS4NCg0KTWF0cmlrcyAqZmVhdHVyZSBtYXAqIG1hc3VrYW4gbWVydXBha2FuIGhhc2lsICpkb3duc2FtcGxpbmcgZW5jb2RlciogcGVydGFtYSwgeWFpdHU6DQoNClxbDQpcbWF0aGJme1h9XnsxLDB9DQo9DQpcYmVnaW57Ym1hdHJpeH0NCi0yLjMzICYgMS41NSAmIC0xLjc2XFwNCi0yLjMzICYgMS45MiAmIC0xLjYyXFwNCi0yLjE5ICYgMC41OCAmIC0xLjkxDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KU2V0ZWxhaCBwZW5hbWJhaGFuICp6ZXJvIHBhZGRpbmcqIHNlYmVzYXIgc2F0dSBwaWtzZWwgcGFkYSBzZXRpYXAgc2lzaSwgdWt1cmFuIG1hdHJpa3MgYmVydWJhaCBkYXJpIFwoM1x0aW1lczNcKSBtZW5qYWRpIFwoNVx0aW1lczVcKSwgeWFpdHU6DQoNClxbDQpcbWF0aGJme1h9X3tcbWF0aHJte3BhZH19XnsxLDB9DQo9DQpcYmVnaW57Ym1hdHJpeH0NCjAuMDAgJiAwLjAwICYgMC4wMCAmIDAuMDAgJiAwLjAwXFwNCjAuMDAgJiAtMi4zMyAmIDEuNTUgJiAtMS43NiAmIDAuMDBcXA0KMC4wMCAmIC0yLjMzICYgMS45MiAmIC0xLjYyICYgMC4wMFxcDQowLjAwICYgLTIuMTkgJiAwLjU4ICYgLTEuOTEgJiAwLjAwXFwNCjAuMDAgJiAwLjAwICYgMC4wMCAmIDAuMDAgJiAwLjAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KLSAqKktlcm5lbCBFbmNvZGVyIEtlZHVhOioqDQoNClBhZGEgaWx1c3RyYXNpIGluaSwga2VybmVsIGtlZHVhIGRpc2VkZXJoYW5ha2FuIGRlbmdhbiBoYW55YSBlbGVtZW4gdGVuZ2FoIGJlcm5pbGFpIHNhdHUgZGFuIGVsZW1lbiBsYWlubnlhIGJlcm5pbGFpIG5vbDoNCg0KXFsNClxtYXRoYmZ7V31fe1xtYXRocm17ZW5jfX1eeygyKX0NCj0NClxiZWdpbntibWF0cml4fQ0KMCAmIDAgJiAwXFwNCjAgJiAxICYgMFxcDQowICYgMCAmIDANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQpLZXJuZWwgdGVyc2VidXQgZGlndW5ha2FuIHVudHVrIG1lbmdpbHVzdHJhc2lrYW4gb3BlcmFzaSAqc3RyaWRlZCBjb252b2x1dGlvbiogcGFkYSB0YWhhcCBrZWR1YS4gUGFkYSBzZXRpYXAgcG9zaXNpLCBzZW1iaWxhbiBlbGVtZW4gZGFsYW0gYXJlYSBrb252b2x1c2kgZGlrYWxpa2FuIGRlbmdhbiBzZW1iaWxhbiBib2JvdCBrZXJuZWwgeWFuZyBiZXJzZXN1YWlhbiwga2VtdWRpYW4gc2VsdXJ1aCBoYXNpbCBwZXJrYWxpYW4gZGlqdW1sYWhrYW4uDQoNCkthcmVuYSBoYW55YSBib2JvdCBwdXNhdCBrZXJuZWwgeWFuZyBiZXJuaWxhaSBzYXR1LCBoYXNpbCBrb252b2x1c2kgcGFkYSBpbHVzdHJhc2kgaW5pIGRpdGVudHVrYW4gb2xlaCBlbGVtZW4geWFuZyBiZXJhZGEgdGVwYXQgZGkgYmF3YWggcHVzYXQga2VybmVsLiBQZW5nZ3VuYWFuICpzdHJpZGUqIHNlYmVzYXIgXCgyXCkgbWVueWViYWJrYW4ga2VybmVsIGJlcmdlc2VyIGR1YSBwb3Npc2kgcGFkYSBzZXRpYXAgcGVycGluZGFoYW4uDQoNClVrdXJhbiBrZWx1YXJhbiBkaWhpdHVuZyBtZW5nZ3VuYWthbjoNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0Kbw0KJj0NClxsZWZ0XGxmbG9vcg0KXGZyYWN7aSsycC1rfXtzfQ0KXHJpZ2h0XHJmbG9vcisxXFwNCiY9DQpcbGVmdFxsZmxvb3INClxmcmFjezMrMigxKS0zfXsyfQ0KXHJpZ2h0XHJmbG9vcisxXFwNCiY9DQpcbGVmdFxsZmxvb3INClxmcmFjezJ9ezJ9DQpccmlnaHRccmZsb29yKzFcXA0KJj0yLg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KRGVuZ2FuIGRlbWlraWFuLCB1a3VyYW4gc3Bhc2lhbCAqZmVhdHVyZSBtYXAqIGJlcnViYWggZGFyaSBcKDNcdGltZXMzXCkgbWVuamFkaSBcKDJcdGltZXMyXCkuDQoNCi0gKipSdW11czoqKg0KDQpTZWNhcmEgdW11bSwgb3BlcmFzaSAqc3RyaWRlZCBjb252b2x1dGlvbiogcGFkYSB0YWhhcCBrZWR1YSBkZW5nYW4ga2VybmVsIFwoM1x0aW1lczNcKSwgKnN0cmlkZSogXCgyXCksIGRhbiAqcGFkZGluZyogXCgxXCkgZGlueWF0YWthbiBzZWJhZ2FpOg0KDQpcWw0KRl97XG1hdGhybXtlbmN9LGEsYn1eeygyKX0NCj0NClxzdW1fe3U9MX1eezN9DQpcc3VtX3t2PTF9XnszfQ0KV197XG1hdGhybXtlbmN9LHUsdn1eeygyKX0NClhfe1xtYXRocm17cGFkfSwyYSt1LTIsXCwyYit2LTJ9XnsxLDB9LA0KXF0NCg0KZGVuZ2FuIFwoYSxiPTEsMlwpLCBzZWRhbmdrYW4gXCh1XCkgZGFuIFwodlwpIG1lcnVwYWthbiBpbmRla3MgYmFyaXMgZGFuIGtvbG9tIGtlcm5lbC4NCg0KUGFkYSBzZXRpYXAgcG9zaXNpLCBrZXJuZWwgbWVuY2FrdXAgYXJlYSBiZXJ1a3VyYW4gXCgzXHRpbWVzM1wpLiBLYXJlbmEgKnN0cmlkZSogYmVybmlsYWkgXCgyXCksIGtlcm5lbCBiZXJnZXNlciBkdWEga29sb20ga2Uga2FuYW4gdW50dWsgbWVuZ2hpdHVuZyBlbGVtZW4gYmVyaWt1dG55YSBwYWRhIGJhcmlzIGtlbHVhcmFuIHlhbmcgc2FtYS4gU2V0ZWxhaCBtZW5jYXBhaSBwb3Npc2kgdGVyYWtoaXIgcGFkYSBiYXJpcyB0ZXJzZWJ1dCwga2VybmVsIGtlbWJhbGkga2Ugc2lzaSBraXJpIGRhbiBiZXJnZXNlciBkdWEgYmFyaXMga2UgYmF3YWguDQoNCkthcmVuYSBoYW55YSBib2JvdCBwdXNhdCBrZXJuZWwgeWFuZyBiZXJuaWxhaSBzYXR1LCBwZXJzYW1hYW4gdGVyc2VidXQgZGFwYXQgZGlzZWRlcmhhbmFrYW4gbWVuamFkaToNCg0KXFsNClhfe2EsYn1eezIsMH0NCj0NCkZfe1xtYXRocm17ZW5jfSxhLGJ9XnsoMil9DQo9DQpYX3syYS0xLFwsMmItMX1eezEsMH0uDQpcXQ0KDQotICoqQ29udG9oIFBlcmhpdHVuZ2FuIEtvbnZvbHVzaToqKg0KDQoqKjEuIFBlcmhpdHVuZ2FuIGVsZW1lbiBwYWRhIHBvc2lzaSBcKCgxLDEpXCkqKg0KDQpVbnR1ayBtZW5naGFzaWxrYW4gZWxlbWVuIHBlcnRhbWEgZGFyaSAqZmVhdHVyZSBtYXAqIGtlbHVhcmFuLCBrZXJuZWwgZGl0ZW1wYXRrYW4gcGFkYSBhcmVhIFwoM1x0aW1lczNcKSBkaSBwb2pvayBraXJpIGF0YXMgbWF0cmlrcyB5YW5nIHRlbGFoIGRpYmVyaSAqemVybyBwYWRkaW5nKi4NCg0KQXJlYSAqZmVhdHVyZSBtYXAqIHlhbmcgZGlwcm9zZXMgYWRhbGFoOg0KDQpcWw0KXGJlZ2lue2JtYXRyaXh9DQowLjAwICYgMC4wMCAmIDAuMDBcXA0KMC4wMCAmIC0yLjMzICYgMS41NVxcDQowLjAwICYgLTIuMzMgJiAxLjkyDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KU2V0aWFwIGVsZW1lbiBwYWRhIGFyZWEgdGVyc2VidXQgZGlrYWxpa2FuIGRlbmdhbiBib2JvdCBrZXJuZWwgeWFuZyBiZXJzZXN1YWlhbiwga2VtdWRpYW4gc2VsdXJ1aCBoYXNpbCBwZXJrYWxpYW4gZGlqdW1sYWhrYW4gc2ViYWdhaSBiZXJpa3V0Og0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpGX3tcbWF0aHJte2VuY30sMSwxfV57KDIpfQ0KPXt9Jg0KKDAuMDApKDApDQorKDAuMDApKDApDQorKDAuMDApKDApXFwNCiYrKDAuMDApKDApDQorKC0yLjMzKSgxKQ0KKygxLjU1KSgwKVxcDQomKygwLjAwKSgwKQ0KKygtMi4zMykoMCkNCisoMS45MikoMClcXA0KPXt9Ji0yLjMzLg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KRGVuZ2FuIGRlbWlraWFuLCBuaWxhaSBlbGVtZW4ga2VsdWFyYW4gcGFkYSBwb3Npc2kgXCgoMSwxKVwpIGFkYWxhaDoNCg0KXFsNClhfezEsMX1eezIsMH0NCj0NCkZfe1xtYXRocm17ZW5jfSwxLDF9XnsoMil9DQo9DQotMi4zMy4NClxdDQoNCioqMi4gUGVyaGl0dW5nYW4gZWxlbWVuIHBhZGEgcG9zaXNpIFwoKDEsMilcKSoqDQoNClVudHVrIG1lbmdoaXR1bmcgZWxlbWVuIHBhZGEgcG9zaXNpIFwoKDEsMilcKSwga2VybmVsIGJlcmdlc2VyIGR1YSBrb2xvbSBrZSBrYW5hbiBkYXJpIHBvc2lzaSBzZWJlbHVtbnlhIGthcmVuYSAqc3RyaWRlKiB5YW5nIGRpZ3VuYWthbiBiZXJuaWxhaSBcKDJcKS4NCg0KQXJlYSAqZmVhdHVyZSBtYXAqIHlhbmcgZGlwcm9zZXMgYWRhbGFoOg0KDQpcWw0KXGJlZ2lue2JtYXRyaXh9DQowLjAwICYgMC4wMCAmIDAuMDBcXA0KMS41NSAmIC0xLjc2ICYgMC4wMFxcDQoxLjkyICYgLTEuNjIgJiAwLjAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KUGVyaGl0dW5nYW4ga29udm9sdXNpIGRpbGFrdWthbiBtZW5nZ3VuYWthbiBib2JvdCBrZXJuZWwgeWFuZyBzYW1hOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpGX3tcbWF0aHJte2VuY30sMSwyfV57KDIpfQ0KPXt9Jg0KKDAuMDApKDApDQorKDAuMDApKDApDQorKDAuMDApKDApXFwNCiYrKDEuNTUpKDApDQorKC0xLjc2KSgxKQ0KKygwLjAwKSgwKVxcDQomKygxLjkyKSgwKQ0KKygtMS42MikoMCkNCisoMC4wMCkoMClcXA0KPXt9Ji0xLjc2Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KRGVuZ2FuIGRlbWlraWFuLCBuaWxhaSBlbGVtZW4ga2VsdWFyYW4gcGFkYSBwb3Npc2kgXCgoMSwyKVwpIGFkYWxhaDoNCg0KXFsNClhfezEsMn1eezIsMH0NCj0NCkZfe1xtYXRocm17ZW5jfSwxLDJ9XnsoMil9DQo9DQotMS43Ni4NClxdDQoNClByb3NlZHVyIHlhbmcgc2FtYSBkaXRlcmFwa2FuIHBhZGEgc2VsdXJ1aCBwb3Npc2kga2VybmVsLiBTZXRpYXAgZWxlbWVuIGtlbHVhcmFuIGRpcGVyb2xlaCBtZWxhbHVpIHBlbmp1bWxhaGFuIGhhc2lsIHBlcmthbGlhbiBlbGVtZW4gcGFkYSBhcmVhIGtvbnZvbHVzaSBkZW5nYW4gYm9ib3Qga2VybmVsIHlhbmcgYmVyc2VzdWFpYW4uDQoNCkRlbmdhbiBtZW5lcmFwa2FuIG9wZXJhc2kgKnN0cmlkZWQgY29udm9sdXRpb24qIHBhZGEgc2VsdXJ1aCBwb3Npc2ksIGRpcGVyb2xlaCAqZmVhdHVyZSBtYXAgZW5jb2Rlcioga2VkdWEgYmVydWt1cmFuIFwoMlx0aW1lczJcKSwgeWFpdHU6DQoNClxbDQpcbWF0aGJme1h9XnsyLDB9DQo9DQpcYmVnaW57Ym1hdHJpeH0NCi0yLjMzICYgLTEuNzZcXA0KLTIuMTkgJiAtMS45MQ0KXGVuZHtibWF0cml4fS4NClxdDQoNCkhhc2lsIHRlcnNlYnV0IG1lbnVuanVra2FuIGJhaHdhIG9wZXJhc2kgKnN0cmlkZWQgY29udm9sdXRpb24qIGRlbmdhbiAqc3RyaWRlKiBcKDJcKSBtZW5ndXJhbmdpIHVrdXJhbiBzcGFzaWFsICpmZWF0dXJlIG1hcCogZGFyaSBcKDNcdGltZXMzXCkgbWVuamFkaSBcKDJcdGltZXMyXCkuIFBhZGEgaWx1c3RyYXNpIGluaSwgcGVueWVkZXJoYW5hYW4gYm9ib3Qga2VybmVsIG1lbnllYmFia2FuIHNldGlhcCBlbGVtZW4ga2VsdWFyYW4gc2FtYSBkZW5nYW4gZWxlbWVuIG1hc3VrYW4geWFuZyBiZXJhZGEgcGFkYSBwb3Npc2kgcHVzYXQga2VybmVsLiBOYW11biwgcGFkYSBpbXBsZW1lbnRhc2kgbW9kZWwgc2ViZW5hcm55YSwgYm9ib3Qga2VybmVsIGRpcGVsYWphcmkgc2VsYW1hIHBlbGF0aWhhbiBzZWhpbmdnYSBrZWx1YXJhbiBrb252b2x1c2kgbWVydXBha2FuIGtvbWJpbmFzaSBiZXJib2JvdCBkYXJpIGVsZW1lbi1lbGVtZW4gcGFkYSBhcmVhIHlhbmcgZGlwcm9zZXMuDQoNCg0KDQoNCiMjIDYuIERlY29kZXIgVU5ldCsrDQoNCipEZWNvZGVyKiBVTmV0KysgbWVuZ2VtYmFsaWthbiB1a3VyYW4gc3Bhc2lhbCAqZmVhdHVyZSBtYXAqIHNlY2FyYSBiZXJ0YWhhcCBtZWxhbHVpIG9wZXJhc2kgKnVwc2FtcGxpbmcqLiBQYWRhIGlsdXN0cmFzaSBwZXJoaXR1bmdhbiBtYW51YWwgaW5pLCAqdXBzYW1wbGluZyogZGlsYWt1a2FuIG1lbmdndW5ha2FuIGludGVycG9sYXNpIGJpbGluZWFyLiBTZWxhbmp1dG55YSwgKmZlYXR1cmUgbWFwKiBkYXJpIGphbHVyICplbmNvZGVyKiBkYW4gbm9kZSAqZGVjb2Rlciogc2ViZWx1bW55YSBkaWdhYnVuZ2thbiBwYWRhIGRpbWVuc2kga2FuYWwgbWVsYWx1aSBvcGVyYXNpIFwoXG9wZXJhdG9ybmFtZXtDb25jYXR9XCkuDQoNClVudHVrIG1lbnllZGVyaGFuYWthbiBwZXJoaXR1bmdhbiBtYW51YWwsIG9wZXJhc2kgcGVuZ29sYWhhbiBmaXR1ciBwYWRhIHNldGlhcCBub2RlICpkZWNvZGVyKiBkaXJlcHJlc2VudGFzaWthbiBtZW5nZ3VuYWthbiBrb252b2x1c2kgXCgxXHRpbWVzMVwpIHRhbnBhIGJpYXMgeWFuZyBkaWlrdXRpIGZ1bmdzaSBha3RpdmFzaSBSZUxVLiBCb2JvdCBrb252b2x1c2kgeWFuZyBkaWd1bmFrYW4gbWVydXBha2FuIHBhcmFtZXRlciBpbHVzdHJhdGlmIGRhbiBidWthbiBib2JvdCBoYXNpbCBwZWxhdGloYW4gbW9kZWwuDQoNCiMjIyBhLiAqVXBzYW1wbGluZyogXChcbWF0aGJme1h9XnsyLDB9XCkgZGFuIE5vZGUgKkRlY29kZXIqIFwoXG1hdGhiZntYfV57MSwxfVwpDQoNCipGZWF0dXJlIG1hcCBlbmNvZGVyKiBrZWR1YSBcKFxtYXRoYmZ7WH1eezIsMH1cKSBiZXJ1a3VyYW4gXCgyXHRpbWVzMlwpIGRpcGVyYmVzYXIgbWVuamFkaSBcKDNcdGltZXMzXCkgbWVuZ2d1bmFrYW4gaW50ZXJwb2xhc2kgYmlsaW5lYXIuIFByb3NlcyBpbmkgYmVydHVqdWFuIHVudHVrIG1lbnllc3VhaWthbiB1a3VyYW4gc3Bhc2lhbCAqZmVhdHVyZSBtYXAqIHNlaGluZ2dhIGRhcGF0IGRpZ2FidW5na2FuIGRlbmdhbiBcKFxtYXRoYmZ7WH1eezEsMH1cKSBtZWxhbHVpICpuZXN0ZWQgc2tpcCBjb25uZWN0aW9uKi4NCg0KTWF0cmlrcyAqZmVhdHVyZSBtYXAqIG1hc3VrYW4gYWRhbGFoOg0KDQpcWw0KXG1hdGhiZntYfV57MiwwfQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQotMi4zMyAmIC0xLjc2XFwNCi0yLjE5ICYgLTEuOTENClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQotICoqUnVtdXMgaW50ZXJwb2xhc2kgYmlsaW5lYXI6KioNCg0KSW50ZXJwb2xhc2kgYmlsaW5lYXIgbWVuZW50dWthbiBuaWxhaSBrZWx1YXJhbiBiZXJkYXNhcmthbiBqYXJhayB0ZXJoYWRhcCBlbGVtZW4tZWxlbWVuIHBhZGEgKmZlYXR1cmUgbWFwKiBtYXN1a2FuLiBFbGVtZW4geWFuZyBsZWJpaCBkZWthdCBkZW5nYW4gcG9zaXNpIGtlbHVhcmFuIG1lbWlsaWtpIGJvYm90IGxlYmloIGJlc2FyLCBzZWRhbmdrYW4gZWxlbWVuIHlhbmcgYmVyamFyYWsgc2F0dSBzYXR1YW4gYXRhdSBsZWJpaCBwYWRhIHNhbGFoIHNhdHUgYXJhaCBtZW1pbGlraSBib2JvdCBub2wuDQoNClBhZGEgKmZlYXR1cmUgbWFwKiBzYXR1IGthbmFsLCBpbnRlcnBvbGFzaSBiaWxpbmVhciBkaW55YXRha2FuIHNlYmFnYWk6DQoNClxbDQpcbGVmdFsNClxvcGVyYXRvcm5hbWV7VXB9DQpcbGVmdCgNClxtYXRoYmZ7WH1eezIsMH0NClxyaWdodCkNClxyaWdodF1fe3IsY30NCj0NClxzdW1fe249MX1eezJ9DQpcc3VtX3ttPTF9XnsyfQ0KWF97bixtfV57MiwwfQ0KXG1heA0KXGxlZnQoDQowLA0KMS1cbGVmdHx4X2MtbVxyaWdodHwNClxyaWdodCkNClxtYXgNClxsZWZ0KA0KMCwNCjEtXGxlZnR8eV9yLW5ccmlnaHR8DQpccmlnaHQpLg0KXF0NCg0KUGFkYSBwZXJzYW1hYW4gdGVyc2VidXQsIFwoclwpIGRhbiBcKGNcKSBtZW55YXRha2FuIGluZGVrcyBiYXJpcyBkYW4ga29sb20gcGFkYSAqZmVhdHVyZSBtYXAqIGtlbHVhcmFuLCBzZWRhbmdrYW4gXChuXCkgZGFuIFwobVwpIG1lbnlhdGFrYW4gaW5kZWtzIGJhcmlzIGRhbiBrb2xvbSBwYWRhICpmZWF0dXJlIG1hcCogbWFzdWthbi4gS29vcmRpbmF0IFwoeF9jXCkgbWVudW5qdWtrYW4gcG9zaXNpIGhvcml6b250YWwgYXRhdSBhcmFoIGtvbG9tLCBzZWRhbmdrYW4gXCh5X3JcKSBtZW51bmp1a2thbiBwb3Npc2kgdmVydGlrYWwgYXRhdSBhcmFoIGJhcmlzLg0KDQpVbnR1ayBtZW1wZXJtdWRhaCBwZW5qYWJhcmFuLCBib2JvdCBpbnRlcnBvbGFzaSBwYWRhIHNldGlhcCBlbGVtZW4gbWFzdWthbiBkaW5vdGFzaWthbiBzZWJhZ2FpOg0KDQpcWw0Kd197bixtfV57KHIsYyl9DQo9DQpcbWF4DQpcbGVmdCgNCjAsDQoxLVxsZWZ0fHhfYy1tXHJpZ2h0fA0KXHJpZ2h0KQ0KXG1heA0KXGxlZnQoDQowLA0KMS1cbGVmdHx5X3ItblxyaWdodHwNClxyaWdodCkuDQpcXQ0KDQpEZW5nYW4gZGVtaWtpYW4sIHJ1bXVzIGludGVycG9sYXNpIGJpbGluZWFyIGRhcGF0IGRpdHVsaXNrYW4gc2ViYWdhaToNCg0KXFsNClxsZWZ0Ww0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MiwwfQ0KXHJpZ2h0KQ0KXHJpZ2h0XV97cixjfQ0KPQ0KXHN1bV97bj0xfV57Mn0NClxzdW1fe209MX1eezJ9DQp3X3tuLG19XnsocixjKX1YX3tuLG19XnsyLDB9Lg0KXF0NCg0KLSAqKlBlbmVudHVhbiBrb29yZGluYXQgaW50ZXJwb2xhc2k6KioNCg0KUGFkYSBpbHVzdHJhc2kgaW5pLCBrb29yZGluYXQgbWF0cmlrcyBtYXN1a2FuIG1lbmdndW5ha2FuIGluZGVrcyB5YW5nIGRpbXVsYWkgZGFyaSBcKDFcKS4gS2FyZW5hIHVrdXJhbiAqZmVhdHVyZSBtYXAqIG1hc3VrYW4gYWRhbGFoIFwoMlx0aW1lczJcKSBkYW4gdWt1cmFuIGtlbHVhcmFuIGFkYWxhaCBcKDNcdGltZXMzXCksIGtvb3JkaW5hdCBpbnRlcnBvbGFzaSBkaXRlbnR1a2FuIHNlYmFnYWk6DQoNClxbDQp4X2MNCj0NCjErKGMtMSlcZnJhY3syLTF9ezMtMX0NCj0NCjErXGZyYWN7Yy0xfXsyfSwNClxdDQoNClxbDQp5X3INCj0NCjErKHItMSlcZnJhY3syLTF9ezMtMX0NCj0NCjErXGZyYWN7ci0xfXsyfSwNClxdDQoNCmRlbmdhbiBcKHIsYz0xLDIsM1wpLg0KDQpBbmdrYSBcKDFcKSBtZW51bmp1a2thbiBrb29yZGluYXQgYXdhbCBrYXJlbmEgaW5kZWtzIG1hdHJpa3MgZGltdWxhaSBkYXJpIFwoMVwpLCBzZWRhbmdrYW4gcGVtYmFnaWFuIGRlbmdhbiBcKDJcKSBtZW51bmp1a2thbiBiYWh3YSBqYXJhayBhbnRhcmEgZHVhIGtvb3JkaW5hdCBtYXN1a2FuIGRpYmFnaSBtZW5qYWRpIGR1YSBpbnRlcnZhbCB5YW5nIHNhbWEgcGFuamFuZy4NCg0KTmlsYWkga29vcmRpbmF0IHlhbmcgZGlwZXJvbGVoIGFkYWxhaDoNCg0KfCBJbmRla3Mga2VsdWFyYW4gfCBOaWxhaSBrb29yZGluYXQgfA0KfDotLS06fDotLS06fA0KfCBcKDFcKSB8IFwoMVwpIHwNCnwgXCgyXCkgfCBcKDEuNVwpIHwNCnwgXCgzXCkgfCBcKDJcKSB8DQoNCkRlbmdhbiBkZW1pa2lhbiwga29vcmRpbmF0IGludGVycG9sYXNpIHBhZGEgbWF0cmlrcyBrZWx1YXJhbiBkYXBhdCBkaXR1bGlza2FuIHNlYmFnYWk6DQoNClxbDQpcYmVnaW57Ym1hdHJpeH0NCigxLDEpICYgKDEsMS41KSAmICgxLDIpXFwNCigxLjUsMSkgJiAoMS41LDEuNSkgJiAoMS41LDIpXFwNCigyLDEpICYgKDIsMS41KSAmICgyLDIpDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KU2V0aWFwIHBhc2FuZ2FuIGtvb3JkaW5hdCBkaXR1bGlza2FuIGRhbGFtIHVydXRhbiBcKCh5X3IseF9jKVwpLiBQYWRhIHBvc2lzaSBzdWR1dCwgbmlsYWkga2VsdWFyYW4gc2FtYSBkZW5nYW4gbmlsYWkgbWFzdWthbiBrYXJlbmEga29vcmRpbmF0bnlhIGJlcmltcGl0LiBTZW1lbnRhcmEgaXR1LCBwb3Npc2kgdGVuZ2FoIHNpc2kgZGlwZXJvbGVoIGRhcmkgZHVhIGVsZW1lbiBtYXN1a2FuLCBzZWRhbmdrYW4gcG9zaXNpIHRlbmdhaCBtYXRyaWtzIGRpcGVyb2xlaCBkYXJpIGVtcGF0IGVsZW1lbiBtYXN1a2FuLg0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuIGludGVycG9sYXNpIGJpbGluZWFyIHBhZGEgcG9zaXNpIFwoKDEsMilcKToqKg0KDQpQYWRhIHBvc2lzaSBcKCgxLDIpXCksIGtvb3JkaW5hdCBpbnRlcnBvbGFzaSBkaXBlcm9sZWggc2ViYWdhaSBiZXJpa3V0Og0KDQpcWw0KeV8xPTEsDQpccXF1YWQNCnhfMj0xLjUuDQpcXQ0KDQpQb3Npc2kgdGVyc2VidXQgYmVyYWRhIHRlcGF0IGRpIHRlbmdhaCBhbnRhcmEga29sb20gcGVydGFtYSBkYW4ga29sb20ga2VkdWEgcGFkYSBiYXJpcyBwZXJ0YW1hLiBCb2JvdCBpbnRlcnBvbGFzaSB1bnR1ayBlbGVtZW4gXChYX3sxLDF9XnsyLDB9XCkgZGloaXR1bmcgc2ViYWdhaToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0Kd197MSwxfV57KDEsMil9DQomPQ0KXG1heCgwLDEtfDEuNS0xfCkNClxtYXgoMCwxLXwxLTF8KVxcDQomPQ0KMC41XHRpbWVzMVxcDQomPQ0KMC41Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KU2VtZW50YXJhIGl0dSwgYm9ib3QgdW50dWsgZWxlbWVuIFwoWF97MSwyfV57MiwwfVwpIGFkYWxhaDoNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0Kd197MSwyfV57KDEsMil9DQomPQ0KXG1heCgwLDEtfDEuNS0yfCkNClxtYXgoMCwxLXwxLTF8KVxcDQomPQ0KMC41XHRpbWVzMVxcDQomPQ0KMC41Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KS2VkdWEgZWxlbWVuIHBhZGEgYmFyaXMga2VkdWEgbWVtaWxpa2kgYm9ib3Qgbm9sIGthcmVuYSBqYXJhayB2ZXJ0aWthbG55YSB0ZXJoYWRhcCBwb3Npc2kga2VsdWFyYW4gYWRhbGFoIHNhdHUgc2F0dWFuLiBEZW5nYW4gZGVtaWtpYW46DQoNClxbDQp3X3sxLDF9XnsoMSwyKX0NCj0NCndfezEsMn1eeygxLDIpfQ0KPQ0KMC41LA0KXHFxdWFkDQp3X3syLDF9XnsoMSwyKX0NCj0NCndfezIsMn1eeygxLDIpfQ0KPQ0KMC4NClxdDQoNCkRlbmdhbiBtZW1hc3Vra2FuIGJvYm90IHRlcnNlYnV0IGtlIGRhbGFtIHJ1bXVzIGludGVycG9sYXNpIGJpbGluZWFyLCBkaXBlcm9sZWg6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClxsZWZ0Ww0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MiwwfQ0KXHJpZ2h0KQ0KXHJpZ2h0XV97MSwyfQ0KJj0NCjAuNVhfezEsMX1eezIsMH0NCisNCjAuNVhfezEsMn1eezIsMH1cXA0KJj0NClxmcmFjew0KWF97MSwxfV57MiwwfQ0KKw0KWF97MSwyfV57MiwwfQ0KfXsyfVxcDQomPQ0KXGZyYWN7LTIuMzMtMS43Nn17Mn1cXA0KJj0NCi0yLjA0NVxcDQomXGFwcHJveA0KLTIuMDUuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuIGludGVycG9sYXNpIGJpbGluZWFyIHBhZGEgcG9zaXNpIHRlbmdhaCBcKCgyLDIpXCk6KioNCg0KUGFkYSBwb3Npc2kgXCgoMiwyKVwpLCBrb29yZGluYXQgaW50ZXJwb2xhc2kgZGlwZXJvbGVoIHNlYmFnYWkgYmVyaWt1dDoNCg0KXFsNCnlfMj0xLjUsDQpccXF1YWQNCnhfMj0xLjUuDQpcXQ0KDQpQb3Npc2kgdGVyc2VidXQgYmVyYWRhIHRlcGF0IGRpIHRlbmdhaCBlbXBhdCBlbGVtZW4gbWF0cmlrcyBtYXN1a2FuLiBCb2JvdCBpbnRlcnBvbGFzaSB1bnR1ayBlbGVtZW4gXChYX3sxLDF9XnsyLDB9XCkgZGloaXR1bmcgc2ViYWdhaToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0Kd197MSwxfV57KDIsMil9DQomPQ0KXG1heCgwLDEtfDEuNS0xfCkNClxtYXgoMCwxLXwxLjUtMXwpXFwNCiY9DQowLjVcdGltZXMwLjVcXA0KJj0NCjAuMjUuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpLYXJlbmEgcG9zaXNpIHRlbmdhaCBiZXJqYXJhayBzYW1hIGRhcmkga2VlbXBhdCBlbGVtZW4gbWFzdWthbiwgbWFrYToNCg0KXFsNCndfezEsMX1eeygyLDIpfQ0KPQ0Kd197MSwyfV57KDIsMil9DQo9DQp3X3syLDF9XnsoMiwyKX0NCj0NCndfezIsMn1eeygyLDIpfQ0KPQ0KMC4yNS4NClxdDQoNCkRlbmdhbiBkZW1pa2lhbiwgcnVtdXMgaW50ZXJwb2xhc2kgYmlsaW5lYXIgbWVuamFkaToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KXGxlZnRbDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsyLDB9DQpccmlnaHQpDQpccmlnaHRdX3syLDJ9DQomPQ0KMC4yNVhfezEsMX1eezIsMH0NCisNCjAuMjVYX3sxLDJ9XnsyLDB9XFwNCiZccXVhZCsNCjAuMjVYX3syLDF9XnsyLDB9DQorDQowLjI1WF97MiwyfV57MiwwfVxcDQomPQ0KXGZyYWN7DQpYX3sxLDF9XnsyLDB9DQorDQpYX3sxLDJ9XnsyLDB9DQorDQpYX3syLDF9XnsyLDB9DQorDQpYX3syLDJ9XnsyLDB9DQp9ezR9XFwNCiY9DQpcZnJhY3stMi4zMy0xLjc2LTIuMTktMS45MX17NH1cXA0KJj0NCi0yLjA0NzVcXA0KJlxhcHByb3gNCi0yLjA1Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KRGVuZ2FuIG1lbmVyYXBrYW4gaW50ZXJwb2xhc2kgYmlsaW5lYXIgcGFkYSBzZWx1cnVoIHBvc2lzaSBrZWx1YXJhbiwgZGlwZXJvbGVoICpmZWF0dXJlIG1hcCogaGFzaWwgKnVwc2FtcGxpbmcqIGJlcnVrdXJhbiBcKDNcdGltZXMzXCksIHlhaXR1Og0KDQpcWw0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MiwwfQ0KXHJpZ2h0KQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQotMi4zMyAmIC0yLjA1ICYgLTEuNzZcXA0KLTIuMjYgJiAtMi4wNSAmIC0xLjg0XFwNCi0yLjE5ICYgLTIuMDUgJiAtMS45MQ0KXGVuZHtibWF0cml4fS4NClxdDQoNCkhhc2lsIHRlcnNlYnV0IG1lbnVuanVra2FuIGJhaHdhIGludGVycG9sYXNpIGJpbGluZWFyIG1lbXBlcnRhaGFua2FuIG5pbGFpIHBhZGEgcG9zaXNpIHN1ZHV0IGRhbiBtZW5naGl0dW5nIG5pbGFpIHBhZGEgcG9zaXNpIGxhaW5ueWEgYmVyZGFzYXJrYW4gYm9ib3QgamFyYWsgdGVyaGFkYXAgZWxlbWVuIG1hc3VrYW4uIE5pbGFpIGhhc2lsIGludGVycG9sYXNpIGRpdGFtcGlsa2FuIGhpbmdnYSBkdWEgYW5na2EgZGVzaW1hbC4NCg0KLSAqKlJ1bXVzIG5vZGUgZGVjb2RlcjoqKg0KDQpTZXN1YWkgZGVuZ2FuIHBlcnNhbWFhbiBVTmV0KyssICpuZXN0ZWQgc2tpcCBjb25uZWN0aW9uKiBwYWRhIG5vZGUgKmRlY29kZXIqIHBlcnRhbWEgZGlydW11c2thbiBzZWJhZ2FpOg0KDQpcWw0KXG1hdGhiZntYfV57MSwxfQ0KPQ0KSF57KDEsMSl9DQpcbGVmdCgNClxvcGVyYXRvcm5hbWV7Q29uY2F0fQ0KXGxlZnRbDQpcbWF0aGJme1h9XnsxLDB9LA0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MiwwfQ0KXHJpZ2h0KQ0KXHJpZ2h0XQ0KXHJpZ2h0KS4NClxdDQoNClBhZGEgcGVyc2FtYWFuIHRlcnNlYnV0LCBcKEheeygxLDEpfVwpIG1lbnlhdGFrYW4gb3BlcmFzaSBwZW5nb2xhaGFuIGZpdHVyIHBhZGEgbm9kZSAqZGVjb2RlciogXChcbWF0aGJme1h9XnsxLDF9XCkuIERhbGFtIGlsdXN0cmFzaSBwZXJoaXR1bmdhbiBtYW51YWwgaW5pLCBvcGVyYXNpIHRlcnNlYnV0IGRpc2VkZXJoYW5ha2FuIG1lbmdndW5ha2FuIGtvbnZvbHVzaSBcKDFcdGltZXMxXCkgdGFucGEgYmlhcyB5YW5nIGRpaWt1dGkgZnVuZ3NpIGFrdGl2YXNpIFJlTFUuDQoNCkthcmVuYSBrZWR1YSAqZmVhdHVyZSBtYXAqIHlhbmcgZGlnYWJ1bmdrYW4gYmVydWt1cmFuIFwoM1x0aW1lczNcKSBkYW4gbWFzaW5nLW1hc2luZyBkaXJlcHJlc2VudGFzaWthbiBvbGVoIHNhdHUga2FuYWwsIGhhc2lsICpDb25jYXQqIG1lbWlsaWtpIGR1YSBrYW5hbC4gU2F0dSBmaWx0ZXIga29udm9sdXNpIFwoMVx0aW1lczFcKSBkaWd1bmFrYW4gdW50dWsgbWVuZ2dhYnVuZ2thbiBrZWR1YSBrYW5hbCB0ZXJzZWJ1dCBtZW5qYWRpIHNhdHUga2FuYWwga2VsdWFyYW4uDQoNClBhZGEgaWx1c3RyYXNpIGluaSwgYm9ib3Qga2VybmVsIGRpdGVudHVrYW4gc2ViYWdhaToNCg0KXFsNCldfe1xtYXRocm17ZGVjfSwxfV57KDEsMSl9PVsxLjAwXSwNClxxcXVhZA0KV197XG1hdGhybXtkZWN9LDJ9XnsoMSwxKX09WzAuMjBdLg0KXF0NCg0KQm9ib3QgcGVydGFtYSBkaXRlcmFwa2FuIHBhZGEgXChcbWF0aGJme1h9XnsxLDB9XCksIHNlZGFuZ2thbiBib2JvdCBrZWR1YSBkaXRlcmFwa2FuIHBhZGEgXChcb3BlcmF0b3JuYW1le1VwfShcbWF0aGJme1h9XnsyLDB9KVwpLg0KDQpEZW5nYW4gZGVtaWtpYW4sIHVudHVrIHNldGlhcCBwb3Npc2kgc3Bhc2lhbCBcKChyLGMpXCksIGtlbHVhcmFuIG5vZGUgKmRlY29kZXIqIGRpaGl0dW5nIHNlYmFnYWk6DQoNClxbDQpYX3tyLGN9XnsxLDF9DQo9DQpcb3BlcmF0b3JuYW1le1JlTFV9DQpcbGVmdCgNCldfe1xtYXRocm17ZGVjfSwxfV57KDEsMSl9WF97cixjfV57MSwwfQ0KKw0KV197XG1hdGhybXtkZWN9LDJ9XnsoMSwxKX0NClxsZWZ0Ww0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MiwwfQ0KXHJpZ2h0KQ0KXHJpZ2h0XV97cixjfQ0KXHJpZ2h0KS4NClxdDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gbm9kZSBkZWNvZGVyIHBhZGEgcG9zaXNpIFwoKDEsMilcKToqKg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpYX3sxLDJ9XnsxLDF9DQomPQ0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQpXX3tcbWF0aHJte2RlY30sMX1eeygxLDEpfVhfezEsMn1eezEsMH0NCisNCldfe1xtYXRocm17ZGVjfSwyfV57KDEsMSl9DQpcbGVmdFsNClxvcGVyYXRvcm5hbWV7VXB9DQpcbGVmdCgNClxtYXRoYmZ7WH1eezIsMH0NClxyaWdodCkNClxyaWdodF1fezEsMn0NClxyaWdodClcXA0KJj0NClxvcGVyYXRvcm5hbWV7UmVMVX0NClxsZWZ0KA0KMS4wMCgxLjU1KQ0KKw0KMC4yMCgtMi4wNSkNClxyaWdodClcXA0KJj0NClxvcGVyYXRvcm5hbWV7UmVMVX0oMS4xNClcXA0KJj0NCjEuMTQuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gbWVuZXJhcGthbiBvcGVyYXNpIHlhbmcgc2FtYSBwYWRhIHNlbHVydWggcG9zaXNpIHNwYXNpYWwsIGRpcGVyb2xlaCAqZmVhdHVyZSBtYXAqIG5vZGUgKmRlY29kZXIqIHBlcnRhbWEgc2ViYWdhaSBiZXJpa3V0Og0KDQpcWw0KXG1hdGhiZntYfV57MSwxfQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjAwICYgMS4xNCAmIDAuMDBcXA0KMC4wMCAmIDEuNTEgJiAwLjAwXFwNCjAuMDAgJiAwLjE3ICYgMC4wMA0KXGVuZHtibWF0cml4fS4NClxdDQoNCkhhc2lsIHRlcnNlYnV0IG1lbnVuanVra2FuIGJhaHdhICpmZWF0dXJlIG1hcCogaGFzaWwgKnVwc2FtcGxpbmcqIGRpZ2FidW5na2FuIGRlbmdhbiAqZmVhdHVyZSBtYXAqIGRhcmkgamFsdXIgKmVuY29kZXIqIG1lbGFsdWkgKm5lc3RlZCBza2lwIGNvbm5lY3Rpb24qLiBQYWRhIGlsdXN0cmFzaSBpbmksIHBlbmdnYWJ1bmdhbiBkaWxha3VrYW4gbWVuZ2d1bmFrYW4gKkNvbmNhdCosIGtvbnZvbHVzaSBcKDFcdGltZXMxXCksIGRhbiBmdW5nc2kgYWt0aXZhc2kgUmVMVS4gKkZlYXR1cmUgbWFwKiBcKFxtYXRoYmZ7WH1eezEsMX1cKSBzZWxhbmp1dG55YSBkaWd1bmFrYW4gcGFkYSBwZW1iZW50dWthbiBub2RlICpkZWNvZGVyKiBiZXJpa3V0bnlhLg0KDQoNCiMjIyBiLiAqVXBzYW1wbGluZyogXChcbWF0aGJme1h9XnsxLDB9XCkgZGFuICpOZXN0ZWQgU2tpcCogUGVydGFtYSBcKFxtYXRoYmZ7WH1eezAsMX1cKQ0KDQoqRmVhdHVyZSBtYXAgZW5jb2RlciogcGVydGFtYSBcKFxtYXRoYmZ7WH1eezEsMH1cKSBiZXJ1a3VyYW4gXCgzXHRpbWVzM1wpIGRpcGVyYmVzYXIgbWVuamFkaSBcKDVcdGltZXM1XCkgbWVuZ2d1bmFrYW4gaW50ZXJwb2xhc2kgYmlsaW5lYXIuIFByb3NlcyBpbmkgYmVydHVqdWFuIHVudHVrIG1lbnllc3VhaWthbiB1a3VyYW4gc3Bhc2lhbCAqZmVhdHVyZSBtYXAqIHNlaGluZ2dhIGRhcGF0IGRpZ2FidW5na2FuIGRlbmdhbiBcKFxtYXRoYmZ7WH1eezAsMH1cKSBtZWxhbHVpICpuZXN0ZWQgc2tpcCBjb25uZWN0aW9uKi4NCg0KTWF0cmlrcyAqZmVhdHVyZSBtYXAqIG1hc3VrYW4gYWRhbGFoOg0KDQpcWw0KXG1hdGhiZntYfV57MSwwfQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQotMi4zMyAmIDEuNTUgJiAtMS43NlxcDQotMi4zMyAmIDEuOTIgJiAtMS42MlxcDQotMi4xOSAmIDAuNTggJiAtMS45MQ0KXGVuZHtibWF0cml4fS4NClxdDQoNCi0gKipSdW11cyBpbnRlcnBvbGFzaSBiaWxpbmVhcjoqKg0KDQpJbnRlcnBvbGFzaSBiaWxpbmVhciBkaWxha3VrYW4gbWVuZ2d1bmFrYW4gcHJpbnNpcCB5YW5nIHNhbWEgc2VwZXJ0aSBwYWRhIHN1YmJhZ2lhbiBzZWJlbHVtbnlhLiBOaWxhaSBrZWx1YXJhbiBkaWhpdHVuZyBiZXJkYXNhcmthbiBqYXJhayB0ZXJoYWRhcCBlbGVtZW4tZWxlbWVuIHBhZGEgKmZlYXR1cmUgbWFwKiBtYXN1a2FuLg0KDQpQYWRhICpmZWF0dXJlIG1hcCogc2F0dSBrYW5hbCwgcnVtdXMgaW50ZXJwb2xhc2kgYmlsaW5lYXIgZGlueWF0YWthbiBzZWJhZ2FpOg0KDQpcWw0KXGxlZnRbDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsxLDB9DQpccmlnaHQpDQpccmlnaHRdX3tyLGN9DQo9DQpcc3VtX3tuPTF9XnszfQ0KXHN1bV97bT0xfV57M30NClhfe24sbX1eezEsMH0NClxtYXgNClxsZWZ0KA0KMCwNCjEtXGxlZnR8eF9jLW1ccmlnaHR8DQpccmlnaHQpDQpcbWF4DQpcbGVmdCgNCjAsDQoxLVxsZWZ0fHlfci1uXHJpZ2h0fA0KXHJpZ2h0KS4NClxdDQoNClBhZGEgcGVyc2FtYWFuIHRlcnNlYnV0LCBcKHJcKSBkYW4gXChjXCkgbWVueWF0YWthbiBpbmRla3MgYmFyaXMgZGFuIGtvbG9tIHBhZGEgKmZlYXR1cmUgbWFwKiBrZWx1YXJhbiwgc2VkYW5na2FuIFwoblwpIGRhbiBcKG1cKSBtZW55YXRha2FuIGluZGVrcyBiYXJpcyBkYW4ga29sb20gcGFkYSAqZmVhdHVyZSBtYXAqIG1hc3VrYW4uIEtvb3JkaW5hdCBcKHhfY1wpIG1lbnVuanVra2FuIHBvc2lzaSBob3Jpem9udGFsIGF0YXUgYXJhaCBrb2xvbSwgc2VkYW5na2FuIFwoeV9yXCkgbWVudW5qdWtrYW4gcG9zaXNpIHZlcnRpa2FsIGF0YXUgYXJhaCBiYXJpcy4NCg0KQm9ib3QgaW50ZXJwb2xhc2kgcGFkYSBzZXRpYXAgZWxlbWVuIG1hc3VrYW4gZGlueWF0YWthbiBzZWJhZ2FpOg0KDQpcWw0Kd197bixtfV57KHIsYyl9DQo9DQpcbWF4DQpcbGVmdCgNCjAsDQoxLVxsZWZ0fHhfYy1tXHJpZ2h0fA0KXHJpZ2h0KQ0KXG1heA0KXGxlZnQoDQowLA0KMS1cbGVmdHx5X3ItblxyaWdodHwNClxyaWdodCkuDQpcXQ0KDQpEZW5nYW4gZGVtaWtpYW4sIHJ1bXVzIGludGVycG9sYXNpIGJpbGluZWFyIGRhcGF0IGRpdHVsaXNrYW4gc2ViYWdhaToNCg0KXFsNClxsZWZ0Ww0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MSwwfQ0KXHJpZ2h0KQ0KXHJpZ2h0XV97cixjfQ0KPQ0KXHN1bV97bj0xfV57M30NClxzdW1fe209MX1eezN9DQp3X3tuLG19XnsocixjKX1YX3tuLG19XnsxLDB9Lg0KXF0NCg0KLSAqKlBlbmVudHVhbiBrb29yZGluYXQgaW50ZXJwb2xhc2k6KioNCg0KUGFkYSBpbHVzdHJhc2kgaW5pLCBrb29yZGluYXQgbWF0cmlrcyBtZW5nZ3VuYWthbiBpbmRla3MgeWFuZyBkaW11bGFpIGRhcmkgXCgxXCkuIEthcmVuYSB1a3VyYW4gKmZlYXR1cmUgbWFwKiBtYXN1a2FuIGFkYWxhaCBcKDNcdGltZXMzXCkgZGFuIHVrdXJhbiBrZWx1YXJhbiBhZGFsYWggXCg1XHRpbWVzNVwpLCBrb29yZGluYXQgaW50ZXJwb2xhc2kgZGl0ZW50dWthbiBzZWJhZ2FpOg0KDQpcWw0KeF9jDQo9DQoxKyhjLTEpXGZyYWN7My0xfXs1LTF9DQo9DQoxK1xmcmFje2MtMX17Mn0sDQpcXQ0KDQpcWw0KeV9yDQo9DQoxKyhyLTEpXGZyYWN7My0xfXs1LTF9DQo9DQoxK1xmcmFje3ItMX17Mn0sDQpcXQ0KDQpkZW5nYW4gXChyLGM9MSwyLDMsNCw1XCkuDQoNCkFuZ2thIFwoMVwpIG1lbnVuanVra2FuIGtvb3JkaW5hdCBhd2FsIG1hdHJpa3MgbWFzdWthbiwgc2VkYW5na2FuIHBlbWJhZ2lhbiBkZW5nYW4gXCgyXCkgbWVudW5qdWtrYW4gYmFod2Egc2V0aWFwIGludGVydmFsIGFudGFyYSBkdWEga29vcmRpbmF0IG1hc3VrYW4gZGliYWdpIG1lbmphZGkgZHVhIGJhZ2lhbiB5YW5nIHNhbWEgcGFuamFuZy4NCg0KTmlsYWkga29vcmRpbmF0IHlhbmcgZGlwZXJvbGVoIGFkYWxhaDoNCg0KfCBJbmRla3Mga2VsdWFyYW4gfCBOaWxhaSBrb29yZGluYXQgfA0KfDotLS06fDotLS06fA0KfCBcKDFcKSB8IFwoMVwpIHwNCnwgXCgyXCkgfCBcKDEuNVwpIHwNCnwgXCgzXCkgfCBcKDJcKSB8DQp8IFwoNFwpIHwgXCgyLjVcKSB8DQp8IFwoNVwpIHwgXCgzXCkgfA0KDQpEZW5nYW4gZGVtaWtpYW4sIG5pbGFpIHBhZGEgcG9zaXNpIGtlbHVhcmFuIHlhbmcgYmVyaW1waXQgZGVuZ2FuIGtvb3JkaW5hdCBtYXN1a2FuIGRpcGVydGFoYW5rYW4sIHNlZGFuZ2thbiBuaWxhaSBwYWRhIHBvc2lzaSBsYWlubnlhIGRpaGl0dW5nIGJlcmRhc2Fya2FuIGJvYm90IGphcmFrIHRlcmhhZGFwIGVsZW1lbi1lbGVtZW4gbWFzdWthbiBkaSBzZWtpdGFybnlhLg0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuIGludGVycG9sYXNpIGJpbGluZWFyIHBhZGEgcG9zaXNpIFwoKDEsMilcKToqKg0KDQpQYWRhIHBvc2lzaSBcKCgxLDIpXCksIGtvb3JkaW5hdCBpbnRlcnBvbGFzaSBkaXBlcm9sZWggc2ViYWdhaSBiZXJpa3V0Og0KDQpcWw0KeV8xPTEsDQpccXF1YWQNCnhfMj0xLjUuDQpcXQ0KDQpQb3Npc2kgdGVyc2VidXQgYmVyYWRhIHRlcGF0IGRpIHRlbmdhaCBhbnRhcmEga29sb20gcGVydGFtYSBkYW4ga29sb20ga2VkdWEgcGFkYSBiYXJpcyBwZXJ0YW1hLiBCb2JvdCBpbnRlcnBvbGFzaSB1bnR1ayBlbGVtZW4gXChYX3sxLDF9XnsxLDB9XCkgZGloaXR1bmcgc2ViYWdhaToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0Kd197MSwxfV57KDEsMil9DQomPQ0KXG1heCgwLDEtfDEuNS0xfCkNClxtYXgoMCwxLXwxLTF8KVxcDQomPQ0KMC41XHRpbWVzMVxcDQomPQ0KMC41Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KU2VtZW50YXJhIGl0dSwgYm9ib3QgdW50dWsgZWxlbWVuIFwoWF97MSwyfV57MSwwfVwpIGFkYWxhaDoNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0Kd197MSwyfV57KDEsMil9DQomPQ0KXG1heCgwLDEtfDEuNS0yfCkNClxtYXgoMCwxLXwxLTF8KVxcDQomPQ0KMC41XHRpbWVzMVxcDQomPQ0KMC41Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KRWxlbWVuIGxhaW5ueWEgbWVtaWxpa2kgYm9ib3Qgbm9sIGthcmVuYSBiZXJhZGEgZGkgbHVhciBqYXJhayBpbnRlcnBvbGFzaSBwYWRhIHBvc2lzaSB0ZXJzZWJ1dC4gRGVuZ2FuIGRlbWlraWFuOg0KDQpcWw0Kd197MSwxfV57KDEsMil9DQo9DQp3X3sxLDJ9XnsoMSwyKX0NCj0NCjAuNS4NClxdDQoNCkRlbmdhbiBtZW1hc3Vra2FuIGJvYm90IHRlcnNlYnV0IGtlIGRhbGFtIHJ1bXVzIGludGVycG9sYXNpIGJpbGluZWFyLCBkaXBlcm9sZWg6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClxsZWZ0Ww0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MSwwfQ0KXHJpZ2h0KQ0KXHJpZ2h0XV97MSwyfQ0KJj0NCjAuNVhfezEsMX1eezEsMH0NCisNCjAuNVhfezEsMn1eezEsMH1cXA0KJj0NClxmcmFjew0KWF97MSwxfV57MSwwfQ0KKw0KWF97MSwyfV57MSwwfQ0KfXsyfVxcDQomPQ0KXGZyYWN7LTIuMzMrMS41NX17Mn1cXA0KJj0NCi0wLjM5Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiBpbnRlcnBvbGFzaSBiaWxpbmVhciBwYWRhIHBvc2lzaSBcKCgyLDIpXCk6KioNCg0KUGFkYSBwb3Npc2kgXCgoMiwyKVwpLCBrb29yZGluYXQgaW50ZXJwb2xhc2kgZGlwZXJvbGVoIHNlYmFnYWkgYmVyaWt1dDoNCg0KXFsNCnlfMj0xLjUsDQpccXF1YWQNCnhfMj0xLjUuDQpcXQ0KDQpQb3Npc2kgdGVyc2VidXQgYmVyYWRhIHRlcGF0IGRpIHRlbmdhaCBlbXBhdCBlbGVtZW4gbWFzdWthbiwgeWFpdHUgXChYX3sxLDF9XnsxLDB9XCksIFwoWF97MSwyfV57MSwwfVwpLCBcKFhfezIsMX1eezEsMH1cKSwgZGFuIFwoWF97MiwyfV57MSwwfVwpLg0KDQpCb2JvdCBpbnRlcnBvbGFzaSB1bnR1ayBlbGVtZW4gXChYX3sxLDF9XnsxLDB9XCkgZGloaXR1bmcgc2ViYWdhaToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0Kd197MSwxfV57KDIsMil9DQomPQ0KXG1heCgwLDEtfDEuNS0xfCkNClxtYXgoMCwxLXwxLjUtMXwpXFwNCiY9DQowLjVcdGltZXMwLjVcXA0KJj0NCjAuMjUuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpLYXJlbmEgcG9zaXNpIHRlcnNlYnV0IGJlcmphcmFrIHNhbWEgZGFyaSBrZWVtcGF0IGVsZW1lbiBtYXN1a2FuLCBtYWthOg0KDQpcWw0Kd197MSwxfV57KDIsMil9DQo9DQp3X3sxLDJ9XnsoMiwyKX0NCj0NCndfezIsMX1eeygyLDIpfQ0KPQ0Kd197MiwyfV57KDIsMil9DQo9DQowLjI1Lg0KXF0NCg0KRGVuZ2FuIGRlbWlraWFuLCBydW11cyBpbnRlcnBvbGFzaSBiaWxpbmVhciBtZW5qYWRpOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcbGVmdFsNClxvcGVyYXRvcm5hbWV7VXB9DQpcbGVmdCgNClxtYXRoYmZ7WH1eezEsMH0NClxyaWdodCkNClxyaWdodF1fezIsMn0NCiY9DQowLjI1WF97MSwxfV57MSwwfQ0KKw0KMC4yNVhfezEsMn1eezEsMH1cXA0KJlxxdWFkKw0KMC4yNVhfezIsMX1eezEsMH0NCisNCjAuMjVYX3syLDJ9XnsxLDB9XFwNCiY9DQpcZnJhY3sNClhfezEsMX1eezEsMH0NCisNClhfezEsMn1eezEsMH0NCisNClhfezIsMX1eezEsMH0NCisNClhfezIsMn1eezEsMH0NCn17NH1cXA0KJj0NClxmcmFjey0yLjMzKzEuNTUtMi4zMysxLjkyfXs0fVxcDQomPQ0KLTAuMjk3NVxcDQomXGFwcHJveC0wLjMwLg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KRGVuZ2FuIG1lbmVyYXBrYW4gaW50ZXJwb2xhc2kgYmlsaW5lYXIgcGFkYSBzZWx1cnVoIHBvc2lzaSBrZWx1YXJhbiwgZGlwZXJvbGVoICpmZWF0dXJlIG1hcCogaGFzaWwgKnVwc2FtcGxpbmcqIGJlcnVrdXJhbiBcKDVcdGltZXM1XCksIHlhaXR1Og0KDQpcWw0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MSwwfQ0KXHJpZ2h0KQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQotMi4zMyAmIC0wLjM5ICYgMS41NSAmIC0wLjExICYgLTEuNzZcXA0KLTIuMzMgJiAtMC4zMCAmIDEuNzMgJiAwLjAyICYgLTEuNjlcXA0KLTIuMzMgJiAtMC4yMSAmIDEuOTIgJiAwLjE1ICYgLTEuNjJcXA0KLTIuMjYgJiAtMC41MSAmIDEuMjUgJiAtMC4yNiAmIC0xLjc3XFwNCi0yLjE5ICYgLTAuODEgJiAwLjU4ICYgLTAuNjcgJiAtMS45MQ0KXGVuZHtibWF0cml4fS4NClxdDQoNCkhhc2lsIHRlcnNlYnV0IG1lbnVuanVra2FuIGJhaHdhIGludGVycG9sYXNpIGJpbGluZWFyIG1lbXBlcmJlc2FyIHVrdXJhbiBzcGFzaWFsICpmZWF0dXJlIG1hcCogZGFyaSBcKDNcdGltZXMzXCkgbWVuamFkaSBcKDVcdGltZXM1XCkuIE5pbGFpIHBhZGEgcG9zaXNpIHlhbmcgYmVyaW1waXQgZGVuZ2FuIGtvb3JkaW5hdCBtYXN1a2FuIGRpcGVydGFoYW5rYW4sIHNlZGFuZ2thbiBuaWxhaSBwYWRhIHBvc2lzaSBsYWlubnlhIGRpaGl0dW5nIG1lbmdndW5ha2FuIGJvYm90IGludGVycG9sYXNpIGJlcmRhc2Fya2FuIGphcmFrIHRlcmhhZGFwIGVsZW1lbiBtYXN1a2FuLg0KDQotICoqUnVtdXMgbm9kZSBkZWNvZGVyOioqDQoNClNlc3VhaSBkZW5nYW4gcGVyc2FtYWFuIFVOZXQrKywgKm5lc3RlZCBza2lwIGNvbm5lY3Rpb24qIHBlcnRhbWEgcGFkYSBub2RlICpkZWNvZGVyKiBkaXJ1bXVza2FuIHNlYmFnYWk6DQoNClxbDQpcbWF0aGJme1h9XnswLDF9DQo9DQpIXnsoMCwxKX0NClxsZWZ0KA0KXG9wZXJhdG9ybmFtZXtDb25jYXR9DQpcbGVmdFsNClxtYXRoYmZ7WH1eezAsMH0sDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsxLDB9DQpccmlnaHQpDQpccmlnaHRdDQpccmlnaHQpLg0KXF0NCg0KUGFkYSBwZXJzYW1hYW4gdGVyc2VidXQsIFwoSF57KDAsMSl9XCkgbWVueWF0YWthbiBvcGVyYXNpIHBlbmdvbGFoYW4gZml0dXIgcGFkYSBub2RlICpkZWNvZGVyKiBcKFxtYXRoYmZ7WH1eezAsMX1cKS4gRGFsYW0gaWx1c3RyYXNpIHBlcmhpdHVuZ2FuIG1hbnVhbCBpbmksIG9wZXJhc2kgdGVyc2VidXQgZGlzZWRlcmhhbmFrYW4gbWVuZ2d1bmFrYW4ga29udm9sdXNpIFwoMVx0aW1lczFcKSB0YW5wYSBiaWFzIHlhbmcgZGlpa3V0aSBmdW5nc2kgYWt0aXZhc2kgUmVMVS4NCg0KS2FyZW5hIGtlZHVhICpmZWF0dXJlIG1hcCogeWFuZyBkaWdhYnVuZ2thbiBiZXJ1a3VyYW4gXCg1XHRpbWVzNVwpIGRhbiBtYXNpbmctbWFzaW5nIGRpcmVwcmVzZW50YXNpa2FuIG9sZWggc2F0dSBrYW5hbCwgaGFzaWwgKkNvbmNhdCogbWVtaWxpa2kgZHVhIGthbmFsLiBTYXR1IGZpbHRlciBrb252b2x1c2kgXCgxXHRpbWVzMVwpIGRpZ3VuYWthbiB1bnR1ayBtZW5nZ2FidW5na2FuIGtlZHVhIGthbmFsIHRlcnNlYnV0IG1lbmphZGkgc2F0dSBrYW5hbCBrZWx1YXJhbi4NCg0KUGFkYSBpbHVzdHJhc2kgaW5pLCBib2JvdCBrZXJuZWwgZGl0ZW50dWthbiBzZWJhZ2FpOg0KDQpcWw0KV197XG1hdGhybXtkZWN9LDF9XnsoMCwxKX09WzEuMDBdLA0KXHFxdWFkDQpXX3tcbWF0aHJte2RlY30sMn1eeygwLDEpfT1bMS4wMF0uDQpcXQ0KDQpCb2JvdCBwZXJ0YW1hIGRpdGVyYXBrYW4gcGFkYSBcKFxtYXRoYmZ7WH1eezAsMH1cKSwgc2VkYW5na2FuIGJvYm90IGtlZHVhIGRpdGVyYXBrYW4gcGFkYSBcKFxvcGVyYXRvcm5hbWV7VXB9KFxtYXRoYmZ7WH1eezEsMH0pXCkuDQoNCkRlbmdhbiBkZW1pa2lhbiwgdW50dWsgc2V0aWFwIHBvc2lzaSBzcGFzaWFsIFwoKHIsYylcKSwga2VsdWFyYW4gbm9kZSAqZGVjb2RlciogZGloaXR1bmcgc2ViYWdhaToNCg0KXFsNClhfe3IsY31eezAsMX0NCj0NClxvcGVyYXRvcm5hbWV7UmVMVX0NClxsZWZ0KA0KV197XG1hdGhybXtkZWN9LDF9XnsoMCwxKX1YX3tyLGN9XnswLDB9DQorDQpXX3tcbWF0aHJte2RlY30sMn1eeygwLDEpfQ0KXGxlZnRbDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsxLDB9DQpccmlnaHQpDQpccmlnaHRdX3tyLGN9DQpccmlnaHQpLg0KXF0NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiBub2RlIGRlY29kZXIgcGFkYSBwb3Npc2kgXCgoMiwyKVwpOioqDQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClhfezIsMn1eezAsMX0NCiY9DQpcb3BlcmF0b3JuYW1le1JlTFV9DQpcbGVmdCgNCldfe1xtYXRocm17ZGVjfSwxfV57KDAsMSl9WF97MiwyfV57MCwwfQ0KKw0KV197XG1hdGhybXtkZWN9LDJ9XnsoMCwxKX0NClxsZWZ0Ww0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MSwwfQ0KXHJpZ2h0KQ0KXHJpZ2h0XV97MiwyfQ0KXHJpZ2h0KVxcDQomPQ0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQoxLjAwKC0yLjMzKQ0KKw0KMS4wMCgtMC4zMCkNClxyaWdodClcXA0KJj0NClxvcGVyYXRvcm5hbWV7UmVMVX0oLTIuNjMpXFwNCiY9DQowLjAwLg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiBub2RlIGRlY29kZXIgcGFkYSBwb3Npc2kgXCgoMiwzKVwpOioqDQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClhfezIsM31eezAsMX0NCiY9DQpcb3BlcmF0b3JuYW1le1JlTFV9DQpcbGVmdCgNCldfe1xtYXRocm17ZGVjfSwxfV57KDAsMSl9WF97MiwzfV57MCwwfQ0KKw0KV197XG1hdGhybXtkZWN9LDJ9XnsoMCwxKX0NClxsZWZ0Ww0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MSwwfQ0KXHJpZ2h0KQ0KXHJpZ2h0XV97MiwzfQ0KXHJpZ2h0KVxcDQomPQ0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQoxLjAwKDEuOTEpDQorDQoxLjAwKDEuNzMpDQpccmlnaHQpXFwNCiY9DQpcb3BlcmF0b3JuYW1le1JlTFV9KDMuNjQpXFwNCiY9DQozLjY0Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KRGVuZ2FuIG1lbmVyYXBrYW4gb3BlcmFzaSB5YW5nIHNhbWEgcGFkYSBzZWx1cnVoIHBvc2lzaSBzcGFzaWFsLCBkaXBlcm9sZWggKmZlYXR1cmUgbWFwKiBub2RlICpkZWNvZGVyKiBzZWJhZ2FpIGJlcmlrdXQ6DQoNClxbDQpcbWF0aGJme1h9XnswLDF9DQo9DQpcYmVnaW57Ym1hdHJpeH0NCjAuMDAgJiAwLjAwICYgMy4wOSAmIDAuODAgJiAwLjAwXFwNCjAuMDAgJiAwLjAwICYgMy42NCAmIDEuMjYgJiAwLjAwXFwNCjAuMDAgJiAwLjAwICYgMy44MyAmIDEuMzkgJiAwLjAwXFwNCjAuMDAgJiAwLjAwICYgMi43OCAmIDAuNjIgJiAwLjAwXFwNCjAuMDAgJiAwLjAwICYgMS4xNiAmIDAuMDAgJiAwLjAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KSGFzaWwgdGVyc2VidXQgbWVudW5qdWtrYW4gYmFod2Egbm9kZSBcKFxtYXRoYmZ7WH1eezAsMX1cKSBtZW5nZ2FidW5na2FuIGluZm9ybWFzaSBkYXJpICpmZWF0dXJlIG1hcCBlbmNvZGVyKiBcKFxtYXRoYmZ7WH1eezAsMH1cKSBkYW4gaGFzaWwgKnVwc2FtcGxpbmcqIFwoXG1hdGhiZntYfV57MSwwfVwpIG1lbGFsdWkgKm5lc3RlZCBza2lwIGNvbm5lY3Rpb24qLiBQYWRhIGlsdXN0cmFzaSBpbmksIHBlbmdnYWJ1bmdhbiBkaWxha3VrYW4gbWVuZ2d1bmFrYW4gKkNvbmNhdCosIGtvbnZvbHVzaSBcKDFcdGltZXMxXCksIGRhbiBmdW5nc2kgYWt0aXZhc2kgUmVMVS4gKkZlYXR1cmUgbWFwKiBcKFxtYXRoYmZ7WH1eezAsMX1cKSBzZWxhbmp1dG55YSBkaWd1bmFrYW4gcGFkYSBwZW1iZW50dWthbiBub2RlICpkZWNvZGVyKiBiZXJpa3V0bnlhLg0KDQoNCg0KIyMjIGMuICpVcHNhbXBsaW5nKiBcKFxtYXRoYmZ7WH1eezEsMX1cKSBkYW4gKk5lc3RlZCBTa2lwKiBLZWR1YSBcKFxtYXRoYmZ7WH1eezAsMn1cKQ0KDQpOb2RlICpkZWNvZGVyKiBcKFxtYXRoYmZ7WH1eezEsMX1cKSBiZXJ1a3VyYW4gXCgzXHRpbWVzM1wpIGRpcGVyYmVzYXIgbWVuamFkaSBcKDVcdGltZXM1XCkgbWVuZ2d1bmFrYW4gaW50ZXJwb2xhc2kgYmlsaW5lYXIuIFByb3NlcyBpbmkgYmVydHVqdWFuIHVudHVrIG1lbnllc3VhaWthbiB1a3VyYW4gc3Bhc2lhbCAqZmVhdHVyZSBtYXAqIHNlaGluZ2dhIGRhcGF0IGRpZ2FidW5na2FuIGRlbmdhbiBcKFxtYXRoYmZ7WH1eezAsMH1cKSBkYW4gXChcbWF0aGJme1h9XnswLDF9XCkgbWVsYWx1aSAqbmVzdGVkIHNraXAgY29ubmVjdGlvbiouDQoNCk1hdHJpa3MgKmZlYXR1cmUgbWFwKiBtYXN1a2FuIGFkYWxhaDoNCg0KXFsNClxtYXRoYmZ7WH1eezEsMX0NCj0NClxiZWdpbntibWF0cml4fQ0KMC4wMCAmIDEuMTQgJiAwLjAwXFwNCjAuMDAgJiAxLjUxICYgMC4wMFxcDQowLjAwICYgMC4xNyAmIDAuMDANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQotICoqUnVtdXMgaW50ZXJwb2xhc2kgYmlsaW5lYXI6KioNCg0KSW50ZXJwb2xhc2kgYmlsaW5lYXIgZGlsYWt1a2FuIGRlbmdhbiBtZW5lbnR1a2FuIG5pbGFpIGtlbHVhcmFuIGJlcmRhc2Fya2FuIGphcmFrIHRlcmhhZGFwIGVsZW1lbi1lbGVtZW4gcGFkYSAqZmVhdHVyZSBtYXAqIG1hc3VrYW4uDQoNClBhZGEgKmZlYXR1cmUgbWFwKiBzYXR1IGthbmFsLCBydW11cyBpbnRlcnBvbGFzaSBiaWxpbmVhciBkaW55YXRha2FuIHNlYmFnYWk6DQoNClxbDQpcbGVmdFsNClxvcGVyYXRvcm5hbWV7VXB9DQpcbGVmdCgNClxtYXRoYmZ7WH1eezEsMX0NClxyaWdodCkNClxyaWdodF1fe3IsY30NCj0NClxzdW1fe249MX1eezN9DQpcc3VtX3ttPTF9XnszfQ0KWF97bixtfV57MSwxfQ0KXG1heA0KXGxlZnQoDQowLA0KMS1cbGVmdHx4X2MtbVxyaWdodHwNClxyaWdodCkNClxtYXgNClxsZWZ0KA0KMCwNCjEtXGxlZnR8eV9yLW5ccmlnaHR8DQpccmlnaHQpLg0KXF0NCg0KUGFkYSBwZXJzYW1hYW4gdGVyc2VidXQsIFwoclwpIGRhbiBcKGNcKSBtZW55YXRha2FuIGluZGVrcyBiYXJpcyBkYW4ga29sb20gcGFkYSAqZmVhdHVyZSBtYXAqIGtlbHVhcmFuLCBzZWRhbmdrYW4gXChuXCkgZGFuIFwobVwpIG1lbnlhdGFrYW4gaW5kZWtzIGJhcmlzIGRhbiBrb2xvbSBwYWRhICpmZWF0dXJlIG1hcCogbWFzdWthbi4gS29vcmRpbmF0IFwoeF9jXCkgbWVudW5qdWtrYW4gcG9zaXNpIGhvcml6b250YWwgYXRhdSBhcmFoIGtvbG9tLCBzZWRhbmdrYW4gXCh5X3JcKSBtZW51bmp1a2thbiBwb3Npc2kgdmVydGlrYWwgYXRhdSBhcmFoIGJhcmlzLg0KDQpCb2JvdCBpbnRlcnBvbGFzaSBwYWRhIHNldGlhcCBlbGVtZW4gbWFzdWthbiBkaW55YXRha2FuIHNlYmFnYWk6DQoNClxbDQp3X3tuLG19XnsocixjKX0NCj0NClxtYXgNClxsZWZ0KA0KMCwNCjEtXGxlZnR8eF9jLW1ccmlnaHR8DQpccmlnaHQpDQpcbWF4DQpcbGVmdCgNCjAsDQoxLVxsZWZ0fHlfci1uXHJpZ2h0fA0KXHJpZ2h0KS4NClxdDQoNCkRlbmdhbiBkZW1pa2lhbiwgcnVtdXMgaW50ZXJwb2xhc2kgYmlsaW5lYXIgZGFwYXQgZGl0dWxpc2thbiBzZWJhZ2FpOg0KDQpcWw0KXGxlZnRbDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsxLDF9DQpccmlnaHQpDQpccmlnaHRdX3tyLGN9DQo9DQpcc3VtX3tuPTF9XnszfQ0KXHN1bV97bT0xfV57M30NCndfe24sbX1eeyhyLGMpfVhfe24sbX1eezEsMX0uDQpcXQ0KDQotICoqUGVuZW50dWFuIGtvb3JkaW5hdCBpbnRlcnBvbGFzaToqKg0KDQpQYWRhIGlsdXN0cmFzaSBpbmksIGtvb3JkaW5hdCBtYXRyaWtzIG1lbmdndW5ha2FuIGluZGVrcyB5YW5nIGRpbXVsYWkgZGFyaSBcKDFcKS4gS2FyZW5hIHVrdXJhbiAqZmVhdHVyZSBtYXAqIG1hc3VrYW4gYWRhbGFoIFwoM1x0aW1lczNcKSBkYW4gdWt1cmFuIGtlbHVhcmFuIGFkYWxhaCBcKDVcdGltZXM1XCksIGtvb3JkaW5hdCBpbnRlcnBvbGFzaSBkaXRlbnR1a2FuIHNlYmFnYWk6DQoNClxbDQp4X2MNCj0NCjErKGMtMSlcZnJhY3szLTF9ezUtMX0NCj0NCjErXGZyYWN7Yy0xfXsyfSwNClxdDQoNClxbDQp5X3INCj0NCjErKHItMSlcZnJhY3szLTF9ezUtMX0NCj0NCjErXGZyYWN7ci0xfXsyfSwNClxdDQoNCmRlbmdhbiBcKHIsYz0xLDIsMyw0LDVcKS4NCg0KQW5na2EgXCgxXCkgbWVudW5qdWtrYW4ga29vcmRpbmF0IGF3YWwgbWF0cmlrcyBtYXN1a2FuLCBzZWRhbmdrYW4gcGVtYmFnaWFuIGRlbmdhbiBcKDJcKSBtZW51bmp1a2thbiBiYWh3YSBzZXRpYXAgaW50ZXJ2YWwgYW50YXJhIGR1YSBrb29yZGluYXQgbWFzdWthbiBkaWJhZ2kgbWVuamFkaSBkdWEgYmFnaWFuIHlhbmcgc2FtYSBwYW5qYW5nLg0KDQpOaWxhaSBrb29yZGluYXQgeWFuZyBkaXBlcm9sZWggYWRhbGFoOg0KDQp8IEluZGVrcyBrZWx1YXJhbiB8IE5pbGFpIGtvb3JkaW5hdCB8DQp8Oi0tLTp8Oi0tLTp8DQp8IFwoMVwpIHwgXCgxXCkgfA0KfCBcKDJcKSB8IFwoMS41XCkgfA0KfCBcKDNcKSB8IFwoMlwpIHwNCnwgXCg0XCkgfCBcKDIuNVwpIHwNCnwgXCg1XCkgfCBcKDNcKSB8DQoNCkRlbmdhbiBkZW1pa2lhbiwgbmlsYWkgcGFkYSBwb3Npc2kga2VsdWFyYW4geWFuZyBiZXJpbXBpdCBkZW5nYW4ga29vcmRpbmF0IG1hc3VrYW4gZGlwZXJ0YWhhbmthbiwgc2VkYW5na2FuIG5pbGFpIHBhZGEgcG9zaXNpIGxhaW5ueWEgZGloaXR1bmcgYmVyZGFzYXJrYW4gYm9ib3QgamFyYWsgdGVyaGFkYXAgZWxlbWVuLWVsZW1lbiBtYXN1a2FuIGRpIHNla2l0YXJueWEuDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gaW50ZXJwb2xhc2kgYmlsaW5lYXIgcGFkYSBwb3Npc2kgXCgoMiwyKVwpOioqDQoNClBhZGEgcG9zaXNpIFwoKDIsMilcKSwga29vcmRpbmF0IGludGVycG9sYXNpIGRpcGVyb2xlaCBzZWJhZ2FpIGJlcmlrdXQ6DQoNClxbDQp5XzI9MS41LA0KXHFxdWFkDQp4XzI9MS41Lg0KXF0NCg0KUG9zaXNpIHRlcnNlYnV0IGJlcmFkYSB0ZXBhdCBkaSB0ZW5nYWggZW1wYXQgZWxlbWVuIG1hc3VrYW4sIHlhaXR1IFwoWF97MSwxfV57MSwxfVwpLCBcKFhfezEsMn1eezEsMX1cKSwgXChYX3syLDF9XnsxLDF9XCksIGRhbiBcKFhfezIsMn1eezEsMX1cKS4NCg0KQm9ib3QgaW50ZXJwb2xhc2kgdW50dWsgZWxlbWVuIFwoWF97MSwxfV57MSwxfVwpIGRpaGl0dW5nIHNlYmFnYWk6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NCndfezEsMX1eeygyLDIpfQ0KJj0NClxtYXgoMCwxLXwxLjUtMXwpDQpcbWF4KDAsMS18MS41LTF8KVxcDQomPQ0KMC41XHRpbWVzMC41XFwNCiY9DQowLjI1Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KS2FyZW5hIHBvc2lzaSB0ZXJzZWJ1dCBiZXJqYXJhayBzYW1hIGRhcmkga2VlbXBhdCBlbGVtZW4gbWFzdWthbiwgbWFrYToNCg0KXFsNCndfezEsMX1eeygyLDIpfQ0KPQ0Kd197MSwyfV57KDIsMil9DQo9DQp3X3syLDF9XnsoMiwyKX0NCj0NCndfezIsMn1eeygyLDIpfQ0KPQ0KMC4yNS4NClxdDQoNCkRlbmdhbiBkZW1pa2lhbiwgcnVtdXMgaW50ZXJwb2xhc2kgYmlsaW5lYXIgbWVuamFkaToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KXGxlZnRbDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsxLDF9DQpccmlnaHQpDQpccmlnaHRdX3syLDJ9DQomPQ0KMC4yNVhfezEsMX1eezEsMX0NCisNCjAuMjVYX3sxLDJ9XnsxLDF9XFwNCiZccXVhZCsNCjAuMjVYX3syLDF9XnsxLDF9DQorDQowLjI1WF97MiwyfV57MSwxfVxcDQomPQ0KXGZyYWN7DQpYX3sxLDF9XnsxLDF9DQorDQpYX3sxLDJ9XnsxLDF9DQorDQpYX3syLDF9XnsxLDF9DQorDQpYX3syLDJ9XnsxLDF9DQp9ezR9XFwNCiY9DQpcZnJhY3swLjAwKzEuMTQrMC4wMCsxLjUxfXs0fVxcDQomPQ0KMC42NjI1XFwNCiZcYXBwcm94MC42Ni4NClxlbmR7YWxpZ25lZH0NClxdDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gaW50ZXJwb2xhc2kgYmlsaW5lYXIgcGFkYSBwb3Npc2kgXCgoMiwzKVwpOioqDQoNClBhZGEgcG9zaXNpIFwoKDIsMylcKSwga29vcmRpbmF0IGludGVycG9sYXNpIGRpcGVyb2xlaCBzZWJhZ2FpIGJlcmlrdXQ6DQoNClxbDQp5XzI9MS41LA0KXHFxdWFkDQp4XzM9Mi4NClxdDQoNClBvc2lzaSB0ZXJzZWJ1dCBiZXJhZGEgdGVwYXQgZGkgdGVuZ2FoIHNlY2FyYSB2ZXJ0aWthbCBhbnRhcmEgYmFyaXMgcGVydGFtYSBkYW4ga2VkdWEsIHRldGFwaSBzZWphamFyIGRlbmdhbiBrb2xvbSBrZWR1YS4gT2xlaCBrYXJlbmEgaXR1LCBoYW55YSBkdWEgZWxlbWVuIHBhZGEga29sb20ga2VkdWEgeWFuZyBtZW1pbGlraSBib2JvdCBidWthbiBub2wuDQoNCkJvYm90IGludGVycG9sYXNpIHVudHVrIGVsZW1lbiBcKFhfezEsMn1eezEsMX1cKSBkaWhpdHVuZyBzZWJhZ2FpOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQp3X3sxLDJ9XnsoMiwzKX0NCiY9DQpcbWF4KDAsMS18Mi0yfCkNClxtYXgoMCwxLXwxLjUtMXwpXFwNCiY9DQoxXHRpbWVzMC41XFwNCiY9DQowLjUuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpTZW1lbnRhcmEgaXR1LCBib2JvdCB1bnR1ayBlbGVtZW4gXChYX3syLDJ9XnsxLDF9XCkgYWRhbGFoOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQp3X3syLDJ9XnsoMiwzKX0NCiY9DQpcbWF4KDAsMS18Mi0yfCkNClxtYXgoMCwxLXwxLjUtMnwpXFwNCiY9DQoxXHRpbWVzMC41XFwNCiY9DQowLjUuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpFbGVtZW4gbGFpbm55YSBtZW1pbGlraSBib2JvdCBub2wga2FyZW5hIGJlcmFkYSBkaSBsdWFyIGphcmFrIGludGVycG9sYXNpIHBhZGEgcG9zaXNpIHRlcnNlYnV0LiBEZW5nYW4gZGVtaWtpYW46DQoNClxbDQp3X3sxLDJ9XnsoMiwzKX0NCj0NCndfezIsMn1eeygyLDMpfQ0KPQ0KMC41Lg0KXF0NCg0KRGVuZ2FuIG1lbWFzdWtrYW4gYm9ib3QgdGVyc2VidXQga2UgZGFsYW0gcnVtdXMgaW50ZXJwb2xhc2kgYmlsaW5lYXIsIGRpcGVyb2xlaDoNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KXGxlZnRbDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsxLDF9DQpccmlnaHQpDQpccmlnaHRdX3syLDN9DQomPQ0KMC41WF97MSwyfV57MSwxfQ0KKw0KMC41WF97MiwyfV57MSwxfVxcDQomPQ0KXGZyYWN7DQpYX3sxLDJ9XnsxLDF9DQorDQpYX3syLDJ9XnsxLDF9DQp9ezJ9XFwNCiY9DQpcZnJhY3sxLjE0KzEuNTF9ezJ9XFwNCiY9DQoxLjMyNVxcDQomXGFwcHJveDEuMzIuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gbWVuZXJhcGthbiBpbnRlcnBvbGFzaSBiaWxpbmVhciBwYWRhIHNlbHVydWggcG9zaXNpIGtlbHVhcmFuLCBkaXBlcm9sZWggKmZlYXR1cmUgbWFwKiBoYXNpbCAqdXBzYW1wbGluZyogYmVydWt1cmFuIFwoNVx0aW1lczVcKSwgeWFpdHU6DQoNClxbDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsxLDF9DQpccmlnaHQpDQo9DQpcYmVnaW57Ym1hdHJpeH0NCjAuMDAgJiAwLjU3ICYgMS4xNCAmIDAuNTcgJiAwLjAwXFwNCjAuMDAgJiAwLjY2ICYgMS4zMiAmIDAuNjYgJiAwLjAwXFwNCjAuMDAgJiAwLjc1ICYgMS41MSAmIDAuNzUgJiAwLjAwXFwNCjAuMDAgJiAwLjQyICYgMC44NCAmIDAuNDIgJiAwLjAwXFwNCjAuMDAgJiAwLjA5ICYgMC4xNyAmIDAuMDkgJiAwLjAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KSGFzaWwgdGVyc2VidXQgbWVudW5qdWtrYW4gYmFod2EgaW50ZXJwb2xhc2kgYmlsaW5lYXIgbWVtcGVyYmVzYXIgdWt1cmFuIHNwYXNpYWwgKmZlYXR1cmUgbWFwKiBkYXJpIFwoM1x0aW1lczNcKSBtZW5qYWRpIFwoNVx0aW1lczVcKS4gTmlsYWkgcGFkYSBwb3Npc2kgeWFuZyBiZXJpbXBpdCBkZW5nYW4ga29vcmRpbmF0IG1hc3VrYW4gZGlwZXJ0YWhhbmthbiwgc2VkYW5na2FuIG5pbGFpIHBhZGEgcG9zaXNpIGxhaW5ueWEgZGloaXR1bmcgbWVuZ2d1bmFrYW4gYm9ib3QgaW50ZXJwb2xhc2kgYmVyZGFzYXJrYW4gamFyYWsgdGVyaGFkYXAgZWxlbWVuIG1hc3VrYW4uDQoNCi0gKipSdW11cyBub2RlIGRlY29kZXI6KioNCg0KU2VzdWFpIGRlbmdhbiBwZXJzYW1hYW4gVU5ldCsrLCAqbmVzdGVkIHNraXAgY29ubmVjdGlvbioga2VkdWEgcGFkYSBub2RlICpkZWNvZGVyKiBkaXJ1bXVza2FuIHNlYmFnYWk6DQoNClxbDQpcbWF0aGJme1h9XnswLDJ9DQo9DQpIXnsoMCwyKX0NClxsZWZ0KA0KXG9wZXJhdG9ybmFtZXtDb25jYXR9DQpcbGVmdFsNClxtYXRoYmZ7WH1eezAsMH0sDQpcbWF0aGJme1h9XnswLDF9LA0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MSwxfQ0KXHJpZ2h0KQ0KXHJpZ2h0XQ0KXHJpZ2h0KS4NClxdDQoNClBhZGEgcGVyc2FtYWFuIHRlcnNlYnV0LCBcKEheeygwLDIpfVwpIG1lbnlhdGFrYW4gb3BlcmFzaSBwZW5nb2xhaGFuIGZpdHVyIHBhZGEgbm9kZSAqZGVjb2RlciogXChcbWF0aGJme1h9XnswLDJ9XCkuIERhbGFtIGlsdXN0cmFzaSBwZXJoaXR1bmdhbiBtYW51YWwgaW5pLCBvcGVyYXNpIHRlcnNlYnV0IGRpc2VkZXJoYW5ha2FuIG1lbmdndW5ha2FuIGtvbnZvbHVzaSBcKDFcdGltZXMxXCkgdGFucGEgYmlhcyB5YW5nIGRpaWt1dGkgZnVuZ3NpIGFrdGl2YXNpIFJlTFUuDQoNCkthcmVuYSBrZXRpZ2EgKmZlYXR1cmUgbWFwKiB5YW5nIGRpZ2FidW5na2FuIGJlcnVrdXJhbiBcKDVcdGltZXM1XCkgZGFuIG1hc2luZy1tYXNpbmcgZGlyZXByZXNlbnRhc2lrYW4gb2xlaCBzYXR1IGthbmFsLCBoYXNpbCAqQ29uY2F0KiBtZW1pbGlraSB0aWdhIGthbmFsLiBTYXR1IGZpbHRlciBrb252b2x1c2kgXCgxXHRpbWVzMVwpIGRpZ3VuYWthbiB1bnR1ayBtZW5nZ2FidW5na2FuIGtldGlnYSBrYW5hbCB0ZXJzZWJ1dCBtZW5qYWRpIHNhdHUga2FuYWwga2VsdWFyYW4uDQoNClBhZGEgaWx1c3RyYXNpIGluaSwgYm9ib3Qga2VybmVsIGRpdGVudHVrYW4gc2ViYWdhaToNCg0KXFsNCldfe1xtYXRocm17ZGVjfSwxfV57KDAsMil9PVswLjI1XSwNClxxcXVhZA0KV197XG1hdGhybXtkZWN9LDJ9XnsoMCwyKX09WzAuNTBdLA0KXHFxdWFkDQpXX3tcbWF0aHJte2RlY30sM31eeygwLDIpfT1bMC4yNV0uDQpcXQ0KDQpCb2JvdCBwZXJ0YW1hIGRpdGVyYXBrYW4gcGFkYSBcKFxtYXRoYmZ7WH1eezAsMH1cKSwgYm9ib3Qga2VkdWEgZGl0ZXJhcGthbiBwYWRhIFwoXG1hdGhiZntYfV57MCwxfVwpLCBzZWRhbmdrYW4gYm9ib3Qga2V0aWdhIGRpdGVyYXBrYW4gcGFkYSBcKFxvcGVyYXRvcm5hbWV7VXB9KFxtYXRoYmZ7WH1eezEsMX0pXCkuIEtldGlnYSBib2JvdCB0ZXJzZWJ1dCBtZXJ1cGFrYW4gcGFyYW1ldGVyIGlsdXN0cmF0aWYgdW50dWsgbWVueWVkZXJoYW5ha2FuIHBlcmhpdHVuZ2FuIG1hbnVhbCwgYnVrYW4gYm9ib3QgaGFzaWwgcGVsYXRpaGFuIG1vZGVsLg0KDQpEZW5nYW4gZGVtaWtpYW4sIHVudHVrIHNldGlhcCBwb3Npc2kgc3Bhc2lhbCBcKChyLGMpXCksIGtlbHVhcmFuIG5vZGUgKmRlY29kZXIqIGRpaGl0dW5nIHNlYmFnYWk6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClhfe3IsY31eezAsMn0NCj0NClxvcGVyYXRvcm5hbWV7UmVMVX0NClxCaWdnKA0KJjAuMjVYX3tyLGN9XnswLDB9XFwNCiYrDQowLjUwWF97cixjfV57MCwxfVxcDQomKw0KMC4yNQ0KXGxlZnRbDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsxLDF9DQpccmlnaHQpDQpccmlnaHRdX3tyLGN9DQpcQmlnZykuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuIG5vZGUgZGVjb2RlciBwYWRhIHBvc2lzaSBcKCgyLDIpXCk6KioNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KWF97MiwyfV57MCwyfQ0KJj0NClxvcGVyYXRvcm5hbWV7UmVMVX0NClxCaWdnKA0KMC4yNVhfezIsMn1eezAsMH0NCisNCjAuNTBYX3syLDJ9XnswLDF9XFwNCiZccXF1YWQrDQowLjI1DQpcbGVmdFsNClxvcGVyYXRvcm5hbWV7VXB9DQpcbGVmdCgNClxtYXRoYmZ7WH1eezEsMX0NClxyaWdodCkNClxyaWdodF1fezIsMn0NClxCaWdnKVxcDQomPQ0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQowLjI1KC0yLjMzKQ0KKw0KMC41MCgwLjAwKQ0KKw0KMC4yNSgwLjY2KQ0KXHJpZ2h0KVxcDQomPQ0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQotMC41ODI1KzAuMTY1DQpccmlnaHQpXFwNCiY9DQpcb3BlcmF0b3JuYW1le1JlTFV9KC0wLjQxNzUpXFwNCiY9DQowLjAwLg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiBub2RlIGRlY29kZXIgcGFkYSBwb3Npc2kgXCgoMiwzKVwpOioqDQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClhfezIsM31eezAsMn0NCiY9DQpcb3BlcmF0b3JuYW1le1JlTFV9DQpcQmlnZygNCjAuMjVYX3syLDN9XnswLDB9DQorDQowLjUwWF97MiwzfV57MCwxfVxcDQomXHFxdWFkKw0KMC4yNQ0KXGxlZnRbDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsxLDF9DQpccmlnaHQpDQpccmlnaHRdX3syLDN9DQpcQmlnZylcXA0KJj0NClxvcGVyYXRvcm5hbWV7UmVMVX0NClxsZWZ0KA0KMC4yNSgxLjkxKQ0KKw0KMC41MCgzLjY0KQ0KKw0KMC4yNSgxLjMyKQ0KXHJpZ2h0KVxcDQomPQ0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQowLjQ3NzUrMS44MiswLjMzDQpccmlnaHQpXFwNCiY9DQpcb3BlcmF0b3JuYW1le1JlTFV9KDIuNjI3NSlcXA0KJlxhcHByb3gNCjIuNjMuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gbWVuZXJhcGthbiBvcGVyYXNpIHlhbmcgc2FtYSBwYWRhIHNlbHVydWggcG9zaXNpIHNwYXNpYWwgZGFuIG1lbmdndW5ha2FuIG5pbGFpIHByZXNpc2kgcGVudWggc2ViZWx1bSBwZW1idWxhdGFuLCBkaXBlcm9sZWggKmZlYXR1cmUgbWFwKiBrZWx1YXJhbiBha2hpciAqZGVjb2Rlciogc2ViYWdhaSBiZXJpa3V0Og0KDQpcWw0KXG1hdGhiZntYfV57MCwyfQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjAwICYgMC4wMCAmIDIuMjIgJiAwLjc3ICYgMC4wMFxcDQowLjAwICYgMC4wMCAmIDIuNjMgJiAxLjExICYgMC4wMFxcDQowLjAwICYgMC4wMCAmIDIuNzcgJiAxLjIwICYgMC4wMFxcDQowLjAwICYgMC4wMCAmIDEuOTkgJiAwLjY0ICYgMC4wMFxcDQowLjAwICYgMC4wMCAmIDAuNzcgJiAwLjAwICYgMC4wMA0KXGVuZHtibWF0cml4fS4NClxdDQoNCkhhc2lsIHRlcnNlYnV0IG1lbnVuanVra2FuIGJhaHdhIG5vZGUgXChcbWF0aGJme1h9XnswLDJ9XCkgbWVuZ2dhYnVuZ2thbiBpbmZvcm1hc2kgZGFyaSBcKFxtYXRoYmZ7WH1eezAsMH1cKSwgXChcbWF0aGJme1h9XnswLDF9XCksIGRhbiBoYXNpbCAqdXBzYW1wbGluZyogXChcbWF0aGJme1h9XnsxLDF9XCkgbWVsYWx1aSAqbmVzdGVkIHNraXAgY29ubmVjdGlvbiouIFBhZGEgaWx1c3RyYXNpIGluaSwgcGVuZ2dhYnVuZ2FuIGRpbGFrdWthbiBtZW5nZ3VuYWthbiAqQ29uY2F0Kiwga29udm9sdXNpIFwoMVx0aW1lczFcKSwgZGFuIGZ1bmdzaSBha3RpdmFzaSBSZUxVLg0KDQoqRmVhdHVyZSBtYXAqIFwoXG1hdGhiZntYfV57MCwyfVwpIG1lcnVwYWthbiBrZWx1YXJhbiBha2hpciAqZGVjb2RlciogcGFkYSBpbHVzdHJhc2kgcGVyaGl0dW5nYW4gbWFudWFsIGluaSBkYW4gc2VsYW5qdXRueWEgZGlndW5ha2FuIHNlYmFnYWkgbWFzdWthbiBwYWRhICpoZWFkKiBzZWdtZW50YXNpLg0KDQoNCiMjIDcuIEhlYWQgc2lnbW9pZCBkYW4gbWFzayBzZWdtZW50YXNpDQoNCktlbHVhcmFuIGFraGlyIGRlY29kZXIgXChcbWF0aGJme1h9XnswLDJ9XCkgZGl0ZXJ1c2thbiBrZSAqaGVhZCogc2VnbWVudGFzaSBtZW5nZ3VuYWthbiBrb252b2x1c2kgXCgxXHRpbWVzMVwpIHRhbnBhIGJpYXMuIEtvbnZvbHVzaSB0ZXJzZWJ1dCBtZW5naGFzaWxrYW4gbWF0cmlrcyBsb2dpdCBcKFxtYXRoYmZ7en1cKS4gU2VsYW5qdXRueWEsIGZ1bmdzaSBzaWdtb2lkIGRpdGVyYXBrYW4gcGFkYSBzZXRpYXAgZWxlbWVuIGxvZ2l0IHVudHVrIG1lbWJlbnR1ayBtYXRyaWtzIHByb2JhYmlsaXRhcyBcKFxtYXRoYmZ7cH1cKS4gQmVyZGFzYXJrYW4ga2V0ZW50dWFuIHBhZGEgQmFiIElJSSwgcGlrc2VsIGRlbmdhbiBwcm9iYWJpbGl0YXMgbGViaWggZGFyaSBcKDAuNTBcKSBkaWthdGVnb3Jpa2FuIHNlYmFnYWkgbGVzaSwgc2VkYW5na2FuIHBpa3NlbCBsYWlubnlhIGRpa2F0ZWdvcmlrYW4gc2ViYWdhaSBsYXRhciBiZWxha2FuZy4NCg0KIyMjIGEuIEhlYWQgc2VnbWVudGFzaSBkYW4gbWF0cmlrcyBsb2dpdA0KDQpQYWRhIGlsdXN0cmFzaSBpbmksICpoZWFkKiBzZWdtZW50YXNpIG1lbmdndW5ha2FuIGtvbnZvbHVzaSBcKDFcdGltZXMxXCkgdGFucGEgYmlhcyBkZW5nYW4ga2VybmVsIHNlYmFnYWkgYmVyaWt1dC4NCg0KXFsNClxtYXRoYmZ7V31fe1xtYXRocm17aGVhZH19PQ0KXGJlZ2lue2JtYXRyaXh9DQoxLjAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KS2FyZW5hIGZlYXR1cmUgbWFwIG1hc3VrYW4gaGFueWEgbWVtaWxpa2kgc2F0dSBrYW5hbCwga2VybmVsIHRlcnNlYnV0IGRpdGVyYXBrYW4gcGFkYSBzZXRpYXAgbmlsYWkgXChcbWF0aGJme1h9XnswLDJ9XCkuDQoNCi0gKipSdW11czoqKg0KDQpcWw0Kel97aSxqfQ0KPQ0KV197XG1hdGhybXtoZWFkfX0NClheezAsMn1fe2ksan0uDQpcXQ0KDQpLYXJlbmEgXChXX3tcbWF0aHJte2hlYWR9fT0xLjAwXCksIG1ha2ENCg0KXFsNCnpfe2ksan0NCj0NClheezAsMn1fe2ksan0uDQpcXQ0KDQpNYXRyaWtzIGxvZ2l0IFwoXG1hdGhiZnt6fVwpIGJlcnVrdXJhbiBcKDVcdGltZXM1XCkuDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gcGFkYSBwb3Npc2kgXCgoMywzKVwpOioqDQoNClxbDQpcYmVnaW57YWxpZ25lZH0NCnpfezMsM30NCiY9DQpXX3tcbWF0aHJte2hlYWR9fQ0KWF57MCwyfV97MywzfVxcDQomPQ0KMS4wMCgyLjc3KVxcDQomPQ0KMi43Ny4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBwZXJoaXR1bmdhbiBtZW5nZ3VuYWthbiBuaWxhaSBwcmVzaXNpIHBlbnVoIHNlYmVsdW0gcGVtYnVsYXRhbiwgZGlwZXJvbGVoIG1hdHJpa3MgbG9naXQgYmVyaWt1dC4NCg0KXFsNClxtYXRoYmZ7en09DQpcYmVnaW57Ym1hdHJpeH0NCjAuMDAgJiAwLjAwICYgMi4yMiAmIDAuNzcgJiAwLjAwXFwNCjAuMDAgJiAwLjAwICYgMi42MyAmIDEuMTEgJiAwLjAwXFwNCjAuMDAgJiAwLjAwICYgMi43NyAmIDEuMjAgJiAwLjAwXFwNCjAuMDAgJiAwLjAwICYgMS45OSAmIDAuNjQgJiAwLjAwXFwNCjAuMDAgJiAwLjAwICYgMC43NyAmIDAuMDAgJiAwLjAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KIyMjIGIuIFByb2JhYmlsaXRhcyBwcmVkaWtzaSBwaWtzZWwNCg0KRnVuZ3NpIHNpZ21vaWQgZGl0ZXJhcGthbiBwYWRhIHNldGlhcCBlbGVtZW4gbWF0cmlrcyBsb2dpdCB1bnR1ayBtZW5naGFzaWxrYW4gcHJvYmFiaWxpdGFzIHByZWRpa3NpIHBpa3NlbCBwYWRhIHJlbnRhbmcgXChbMCwxXVwpLg0KDQotICoqUnVtdXM6KioNCg0KXFsNCnBfe2ksan0NCj0NClxzaWdtYSh6X3tpLGp9KQ0KPQ0KXGZyYWN7MX17MStlXnstel97aSxqfX19Lg0KXF0NCg0KTWF0cmlrcyBwcm9iYWJpbGl0YXMgXChcbWF0aGJme3B9XCkgYmVydWt1cmFuIFwoNVx0aW1lczVcKS4NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiBwYWRhIHBvc2lzaSBcKCgzLDMpXCk6KioNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KcF97MywzfQ0KJj0NClxmcmFjezF9ezErZV57LXpfezMsM319fVxcDQomPQ0KXGZyYWN7MX17MStlXnstMi43N319XFwNCiY9DQpcZnJhY3sxfXsxKzAuMDZ9XFwNCiY9DQowLjk0Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiBwYWRhIHBvc2lzaSBcKCgxLDEpXCk6KioNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KcF97MSwxfQ0KJj0NClxmcmFjezF9ezErZV57LTAuMDB9fVxcDQomPQ0KXGZyYWN7MX17MSsxfVxcDQomPQ0KMC41MC4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBwZXJoaXR1bmdhbiBtZW5nZ3VuYWthbiBuaWxhaSBwcmVzaXNpIHBlbnVoIHNlYmVsdW0gcGVtYnVsYXRhbiwgZGlwZXJvbGVoIG1hdHJpa3MgcHJvYmFiaWxpdGFzIGJlcmlrdXQuDQoNClxbDQpcbWF0aGJme3B9PQ0KXGJlZ2lue2JtYXRyaXh9DQowLjUwICYgMC41MCAmIDAuOTAgJiAwLjY4ICYgMC41MFxcDQowLjUwICYgMC41MCAmIDAuOTMgJiAwLjc1ICYgMC41MFxcDQowLjUwICYgMC41MCAmIDAuOTQgJiAwLjc3ICYgMC41MFxcDQowLjUwICYgMC41MCAmIDAuODggJiAwLjY1ICYgMC41MFxcDQowLjUwICYgMC41MCAmIDAuNjggJiAwLjUwICYgMC41MA0KXGVuZHtibWF0cml4fS4NClxdDQoNCiMjIyBjLiBNYXNrIHNlZ21lbnRhc2kgYmluZXINCg0KTWF0cmlrcyBwcm9iYWJpbGl0YXMgZGlrb252ZXJzaSBtZW5qYWRpIG1hc2sgc2VnbWVudGFzaSBiaW5lciBtZW5nZ3VuYWthbiBuaWxhaSBhbWJhbmcgbGViaWggZGFyaSBcKDAuNTBcKS4gUGlrc2VsIGRlbmdhbiBwcm9iYWJpbGl0YXMgdGVwYXQgXCgwLjUwXCkgZGlrYXRlZ29yaWthbiBzZWJhZ2FpIGxhdGFyIGJlbGFrYW5nLg0KDQotICoqUnVtdXM6KioNCg0KXFsNClx3aWRlaGF0e019X3tpLGp9DQo9DQpcbWF0aGJiezF9DQpcbGVmdFsNCnBfe2ksan0+MC41MA0KXHJpZ2h0XS4NClxdDQoNCmRlbmdhbg0KDQpcWw0KXHdpZGVoYXR7TX1fe2ksan0NCj0NClxiZWdpbntjYXNlc30NCjEsICYgXHRleHR7amlrYSB9IHBfe2ksan0+MC41MCBcdGV4dHsgKGxlc2kpfSxcXA0KMCwgJiBcdGV4dHtqaWthIH0gcF97aSxqfVxsZXEwLjUwIFx0ZXh0eyAobGF0YXIgYmVsYWthbmcpfS4NClxlbmR7Y2FzZXN9DQpcXQ0KDQpNYXRyaWtzIG1hc2sgc2VnbWVudGFzaSBcKFx3aWRlaGF0e1xtYXRoYmZ7TX19XCkgYmVydWt1cmFuIFwoNVx0aW1lczVcKS4NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiBwYWRhIHBvc2lzaSBcKCgzLDMpXCk6KioNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KXHdpZGVoYXR7TX1fezMsM30NCiY9DQpcbWF0aGJiezF9DQpcbGVmdFsNCnBfezMsM30+MC41MA0KXHJpZ2h0XVxcDQomPQ0KXG1hdGhiYnsxfQ0KXGxlZnRbDQowLjk0PjAuNTANClxyaWdodF1cXA0KJj0NCjEuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuIHBhZGEgcG9zaXNpIFwoKDEsMSlcKToqKg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcd2lkZWhhdHtNfV97MSwxfQ0KJj0NClxtYXRoYmJ7MX0NClxsZWZ0Ww0KcF97MSwxfT4wLjUwDQpccmlnaHRdXFwNCiY9DQpcbWF0aGJiezF9DQpcbGVmdFsNCjAuNTA+MC41MA0KXHJpZ2h0XVxcDQomPQ0KMC4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBhdHVyYW4geWFuZyBzYW1hLCBkaXBlcm9sZWggbWFzayBzZWdtZW50YXNpIGJpbmVyIGJlcmlrdXQuDQoNClxbDQpcd2lkZWhhdHtcbWF0aGJme019fT0NClxiZWdpbntibWF0cml4fQ0KMCAmIDAgJiAxICYgMSAmIDBcXA0KMCAmIDAgJiAxICYgMSAmIDBcXA0KMCAmIDAgJiAxICYgMSAmIDBcXA0KMCAmIDAgJiAxICYgMSAmIDBcXA0KMCAmIDAgJiAxICYgMCAmIDANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQoNCj4gKipLZXRlcmFuZ2FuIHByb3NlcyBwZWxhdGloYW46KiogTWFzayBiaW5lciBcKFx3aWRlaGF0e019XCkgcGFkYSBpbHVzdHJhc2kgaW5pIGRpdGFtcGlsa2FuIHVudHVrIG1lbXBlcmxpaGF0a2FuIGJlbnR1ayBha2hpciBoYXNpbCBzZWdtZW50YXNpIGRhbiB1bnR1ayBtZW5naGl0dW5nIG1ldHJpayBldmFsdWFzaS4gUGFkYSBwcm9zZXMgcGVsYXRpaGFuLCBtYXNrIGJpbmVyIHRlcnNlYnV0IHRpZGFrIGRpZ3VuYWthbiB1bnR1ayBtZW1wZXJiYXJ1aSBib2JvdCBtb2RlbC4gUGVtYmFydWFuIGJvYm90IGRpbGFrdWthbiBtZW5nZ3VuYWthbiBwcm9iYWJpbGl0YXMgcHJlZGlrc2kgXChwXCkgZGFuIGdyb3VuZCB0cnV0aCBcKE1cKSBtZWxhbHVpIEJDRS1EaWNlIGxvc3MuDQoNCg==