2. Representasi Lokal
Pada ilustrasi ini, matriks \(\mathbf{X}\) berukuran \(5\times5\) merepresentasikan satu kanal
dari feature map masukan blok \(\mathbf{F}^{(0)}\) yang telah
dinormalisasi. Pembentukan representasi lokal diawali dengan operasi
depthwise convolution menggunakan kernel \(3\times3\), stride \(1\), dan zero padding sebesar
\(1\) pada setiap sisi. Hasilnya
kemudian diproses melalui fungsi aktivasi Swish. Selanjutnya, proyeksi
pointwise convolution \(1\times1\) diterapkan pada feature
map lokal yang dihasilkan.
a. Depthwise Convolution
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
bertujuan mempertahankan ukuran spasial feature map setelah
operasi 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\). Penambahan zero
padding mengubah ukuran matriks masukan sementara 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}.
\]
Pada ilustrasi ini, matriks bobot kernel depthwise
convolution ditetapkan sebagai:
\[
\mathbf{W}_{\mathrm{dw}}
=
\begin{bmatrix}
0.00 & 0.10 & 0.00\\
0.10 & 0.60 & 0.10\\
0.00 & 0.10 & 0.00
\end{bmatrix}.
\]
Kernel tersebut memiliki bobot pusat sebesar \(0.60\), empat bobot sebesar \(0.10\) pada posisi atas, bawah, kiri, dan
kanan, serta empat bobot sudut bernilai \(0.00\).
Setiap hasil konvolusi diperoleh melalui perkalian sembilan elemen
pada area feature map dengan sembilan bobot kernel yang
bersesuaian, kemudian seluruh hasil perkalian dijumlahkan.
Operasi depthwise convolution untuk satu kanal masukan
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\),
sedangkan \(u\) dan \(v\) merupakan indeks baris dan kolom
kernel.
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.00)
+(0.00)(0.10)
+(0.00)(0.00)\\
&+(0.00)(0.10)
+(-2.12)(0.60)
+(-1.02)(0.10)\\
&+(0.00)(0.00)
+(-2.12)(0.10)
+(-0.75)(0.00)\\
={}&
-1.272-0.102-0.212\\
={}&-1.586.
\end{aligned}
\]
Hasil perkalian berdasarkan nilai masukan yang ditampilkan adalah
\(-1.586\). Pada matriks ilustrasi yang
telah disusun sebelumnya, elemen ini tercatat sebesar \(-1.58\). Nilai tersebut dipertahankan
sementara dan akan divalidasi kembali bersama seluruh tahapan
perhitungan.
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.00)
+(-1.02)(0.10)
+(1.17)(0.00)\\
&+(-2.12)(0.10)
+(-0.75)(0.60)
+(1.44)(0.10)\\
&+(-2.12)(0.00)
+(-0.75)(0.10)
+(1.44)(0.00)\\
={}&
-0.102-0.212-0.450\\
&+0.144-0.075\\
={}&-0.695.
\end{aligned}
\]
Hasil perkalian berdasarkan nilai masukan yang ditampilkan adalah
\(-0.695\). Pada matriks ilustrasi
sebelumnya, elemen ini tercatat sebesar \(-0.69\). Nilai tersebut juga dipertahankan
sementara hingga proses validasi numerik 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.58 & -0.78 & 0.81 & 0.42 & -1.02\\
-1.77 & -0.69 & 1.14 & 0.69 & -1.07\\
-1.77 & -0.68 & 1.14 & 0.69 & -1.07\\
-1.77 & -0.83 & 0.85 & 0.40 & -1.19\\
-1.53 & -1.03 & 0.18 & -0.19 & -1.20
\end{bmatrix}.
\]
Matriks tersebut mempertahankan nilai pada ilustrasi sebelumnya dan
akan diperiksa kembali melalui perhitungan numerik untuk memastikan
konsistensi seluruh tahapan.
Setelah operasi depthwise convolution, fungsi aktivasi Swish
diterapkan secara elemen demi elemen pada feature map yang
dihasilkan.
Rumus fungsi aktivasi Swish adalah:
\[
\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}
\]
Untuk elemen pada posisi \((1,1)\),
nilai yang digunakan sesuai dengan matriks hasil depthwise
convolution pada ilustrasi sebelumnya, yaitu \(-1.58\).
\[
\begin{aligned}
L_{1,1}
&=\operatorname{Swish}(-1.58)\\
&=\frac{-1.58}{1+e^{-(-1.58)}}\\
&=\frac{-1.58}{1+e^{1.58}}\\
&=\frac{-1.58}{1+4.85}\\
&=\frac{-1.58}{5.85}\\
&=-0.27.
\end{aligned}
\]
Berdasarkan penerapan fungsi aktivasi Swish pada matriks ilustrasi
sebelumnya, diperoleh:
\[
\mathbf{L}
=
\begin{bmatrix}
-0.27 & -0.25 & 0.56 & 0.26 & -0.27\\
-0.26 & -0.23 & 0.87 & 0.46 & -0.27\\
-0.26 & -0.23 & 0.87 & 0.46 & -0.27\\
-0.26 & -0.25 & 0.60 & 0.24 & -0.28\\
-0.27 & -0.27 & 0.10 & -0.09 & -0.28
\end{bmatrix}.
\]
Matriks \(\mathbf{L}\) merupakan
representasi lokal setelah penerapan fungsi aktivasi Swish dan digunakan
sebagai masukan pada tahap proyeksi pointwise convolution
berikutnya. Nilai matriks ini dipertahankan sesuai ilustrasi sebelumnya
hingga dilakukan validasi numerik secara menyeluruh.
b. Proyeksi Pointwise Convolution dan Tokenisasi
Feature map lokal \(\mathbf{L}\) memiliki dimensi \(5\times5\times1\). Selanjutnya,
pointwise convolution \(1\times1\) diterapkan secara independen
pada setiap posisi spasial. Berbeda dengan depthwise
convolution \(3\times3\), operasi
ini tidak melibatkan piksel tetangga, tetapi memproyeksikan satu kanal
masukan menjadi dua kanal keluaran.
Proyeksi tersebut menghasilkan vektor fitur berdimensi dua pada
setiap posisi spasial yang selanjutnya digunakan sebagai
embedding token untuk masukan Transformer. Jumlah dua kanal
digunakan sebagai penyederhanaan ilustrasi perhitungan manual agar
pembentukan token serta operasi Query, Key, dan Value dapat ditunjukkan
secara eksplisit. Pada implementasi MobileViTv3-v1-S sebenarnya, jumlah
kanal ditentukan berdasarkan konfigurasi arsitektur.
- Bobot pointwise convolution:
Pada ilustrasi ini, matriks bobot pointwise convolution
ditetapkan sebagai:
\[
\mathbf{W}_{\mathrm{pw}}^{(\mathrm{tok})}
=
\begin{bmatrix}
1.00 & -0.50
\end{bmatrix}.
\]
Matriks bobot \(\mathbf{W}_{\mathrm{pw}}^{(\mathrm{tok})}\)
berdimensi \(1\times2\), sehingga
setiap nilai pada feature map lokal diproyeksikan menjadi
vektor dengan dua elemen.
Untuk setiap posisi spasial \((i,j)\), elemen ke-\(n\) dari token ke-\(t\) dihitung menggunakan:
\[
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\). Dengan demikian, persamaan
tersebut dapat disederhanakan menjadi:
\[
\mathbf{T}_t
=
L_{i,j}
\mathbf{W}_{\mathrm{pw}}^{(\mathrm{tok})}.
\]
Dengan bobot yang digunakan, kanal keluaran pertama mempertahankan
nilai aktivasi lokal, sedangkan kanal kedua bernilai \(-0.50\) kali aktivasi lokal. Hasil proyeksi
membentuk feature map berdimensi \(25\times2\).
- Contoh perhitungan pada posisi \((1,1)\):
Diketahui \(L_{1,1}=-0.27\),
sehingga:
\[
\begin{aligned}
\mathbf{T}_1
&=
L_{1,1}
\mathbf{W}_{\mathrm{pw}}^{(\mathrm{tok})}\\
&=
(-0.27)
\begin{bmatrix}
1.00 & -0.50
\end{bmatrix}\\
&=
\begin{bmatrix}
(-0.27)(1.00) & (-0.27)(-0.50)
\end{bmatrix}\\
&=
\begin{bmatrix}
-0.27 & 0.135
\end{bmatrix}\\
&=
\begin{bmatrix}
-0.27 & 0.14
\end{bmatrix}.
\end{aligned}
\]
Posisi spasial \((1,1)\) merupakan
token pertama berdasarkan:
\[
t=5(1-1)+1=1.
\]
Setelah proyeksi pointwise convolution, vektor dua kanal
pada setiap posisi spasial disusun menjadi urutan token menggunakan
urutan raster, yaitu dari kiri ke kanan dan dari atas ke bawah. Indeks
token ditentukan oleh:
\[
t=5(i-1)+j.
\]
Sebagai contoh, posisi spasial \((1,1)\), \((1,3)\), \((2,1)\), dan \((5,5)\) masing-masing berkorespondensi
dengan token ke-1, ke-3, ke-6, dan ke-25.
Setiap vektor token dinyatakan sebagai:
\[
\begin{aligned}
\mathbf{T}_t
&=
L_{i,j,1}
\mathbf{W}_{\mathrm{pw}}^{(\mathrm{tok})}\\
&=
\begin{bmatrix}
L_{i,j,1} & -0.50L_{i,j,1}
\end{bmatrix}.
\end{aligned}
\]
Vektor token \(\mathbf{T}_t\)
berdimensi \(1\times2\). Dengan
menyusun seluruh 25 vektor token berdasarkan urutan raster, diperoleh
matriks \(\mathbf{T}\) berdimensi \(25\times2\):
\[
\mathbf{T}
=
\begin{bmatrix}
-0.27 & 0.13\\
-0.25 & 0.12\\
0.56 & -0.28\\
0.26 & -0.13\\
-0.27 & 0.14\\
-0.26 & 0.13\\
-0.23 & 0.12\\
0.87 & -0.43\\
0.46 & -0.23\\
-0.27 & 0.14\\
-0.26 & 0.13\\
-0.23 & 0.11\\
0.87 & -0.43\\
0.46 & -0.23\\
-0.27 & 0.14\\
-0.26 & 0.13\\
-0.25 & 0.13\\
0.60 & -0.30\\
0.24 & -0.12\\
-0.28 & 0.14\\
-0.27 & 0.14\\
-0.27 & 0.14\\
0.10 & -0.05\\
-0.09 & 0.04\\
-0.28 & 0.14
\end{bmatrix}.
\]
3. Transformer MobileViTv3-v1-S (Self-Attention)
a. Normalisasi Token
Sebelum memasuki mekanisme self-attention, setiap token pada
matriks \(\mathbf{T}\) dinormalisasi
menggunakan Layer Normalization (LN). Normalisasi dilakukan
secara independen pada setiap token, sehingga rata-rata dan varians
dihitung berdasarkan dua elemen fitur pada token yang sama.
Untuk token ke-\(t\), rata-rata dan
varians dihitung sebagai:
\[
\mu_t
=
\frac{1}{2}\sum_{k=1}^{2}T_{t,k},
\qquad
\sigma_t^2
=
\frac{1}{2}\sum_{k=1}^{2}(T_{t,k}-\mu_t)^2.
\]
Selanjutnya, elemen ke-\(k\) pada
token ke-\(t\) dinormalisasi
menggunakan:
\[
[\operatorname{LN}(\mathbf{T})]_{t,k}
=
\frac{T_{t,k}-\mu_t}
{\sqrt{\sigma_t^2+\varepsilon}},
\qquad
\varepsilon=10^{-5}.
\]
Matriks token \(\mathbf{T}\)
berdimensi \(25\times2\), sehingga
matriks hasil normalisasi \(\operatorname{LN}(\mathbf{T})\) juga
berdimensi \(25\times2\).
- Contoh perhitungan untuk token pertama:
Diketahui vektor token pertama adalah:
\[
\mathbf{T}_1
=
\begin{bmatrix}
-0.27 & 0.13
\end{bmatrix}.
\]
Rata-rata token pertama dihitung sebagai:
\[
\begin{aligned}
\mu_1
&=\frac{T_{1,1}+T_{1,2}}{2}\\
&=\frac{-0.27+0.13}{2}\\
&=\frac{-0.14}{2}\\
&=-0.07.
\end{aligned}
\]
Varians token pertama diperoleh:
\[
\begin{aligned}
\sigma_1^2
&=\frac{(T_{1,1}-\mu_1)^2+(T_{1,2}-\mu_1)^2}{2}\\
&=\frac{(-0.27-(-0.07))^2+(0.13-(-0.07))^2}{2}\\
&=\frac{(-0.20)^2+(0.20)^2}{2}\\
&=\frac{0.04+0.04}{2}\\
&=0.04.
\end{aligned}
\]
Selanjutnya, elemen pertama token dinormalisasi sebagai:
\[
\begin{aligned}
\left[\mathrm{LN}(\mathbf{T})\right]_{1,1}
&= \frac{T_{1,1}-\mu_1}{\sqrt{\sigma_1^2+\varepsilon}}\\
&= \frac{-0.27-(-0.07)}{\sqrt{0.04+10^{-5}}}\\
&= \frac{-0.20}{\sqrt{0.04+10^{-5}}}\\
&= \frac{-0.20}{0.20}\\
&= -1.00
\end{aligned}
\]
Dengan perhitungan yang sama, elemen kedua token pertama
diperoleh:
\[
[\operatorname{LN}(\mathbf{T})]_{1,2}
=1.00.
\]
Dengan demikian, hasil normalisasi token pertama adalah:
\[
[\operatorname{LN}(\mathbf{T})]_{1}
=
\begin{bmatrix}
-1.00 & 1.00
\end{bmatrix}.
\]
Proses normalisasi yang sama diterapkan pada seluruh token, sehingga
diperoleh matriks token ternormalisasi berukuran \(25\times2\) sebagai berikut:
\[
\operatorname{LN}(\mathbf{T})
=
\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\\
-1.00 & 1.00
\end{bmatrix}.
\]
b. Proyeksi Query
Setelah token dinormalisasi, setiap token diproyeksikan menjadi
Query (Q). Query merepresentasikan informasi yang dicari oleh
setiap token ketika menghitung hubungan dengan token-token lain melalui
mekanisme self-attention.
Pada ilustrasi ini, matriks bobot proyeksi Query ditetapkan
sebagai:
\[
\mathbf{W}_Q
=
0.50\mathbf{I}
=
\begin{bmatrix}
0.50 & 0.00\\
0.00 & 0.50
\end{bmatrix},
\]
dengan \(\mathbf{I}\) merupakan
matriks identitas berukuran \(2\times2\). Bobot tersebut mengalikan
setiap elemen token ternormalisasi dengan \(0.50\), tanpa mencampurkan informasi antara
kedua kanal fitur.
Proyeksi Query dirumuskan sebagai:
\[
\mathbf{Q}
=
\operatorname{LN}(\mathbf{T})\mathbf{W}_Q.
\]
Untuk token ke-\(t\), persamaan
tersebut dapat dituliskan sebagai:
\[
\begin{aligned}
\mathbf{Q}_t
&=
[\operatorname{LN}(\mathbf{T})]_{t}\mathbf{W}_Q\\
&=
\begin{bmatrix}
[\operatorname{LN}(\mathbf{T})]_{t,1} &
[\operatorname{LN}(\mathbf{T})]_{t,2}
\end{bmatrix}
\begin{bmatrix}
0.50 & 0.00\\
0.00 & 0.50
\end{bmatrix}.
\end{aligned}
\]
Matriks hasil normalisasi \(\operatorname{LN}(\mathbf{T})\) berukuran
\(25\times2\), sedangkan matriks bobot
\(\mathbf{W}_Q\) berukuran \(2\times2\). Dengan demikian, matriks Query
\(\mathbf{Q}\) berukuran \(25\times2\).
- Contoh perhitungan untuk token pertama:
Berdasarkan tahap normalisasi token sebelumnya, hasil normalisasi
token pertama yang ditampilkan dengan dua angka desimal adalah:
\[
[\operatorname{LN}(\mathbf{T})]_{1}
=
\begin{bmatrix}
-1.00 & 1.00
\end{bmatrix}.
\]
Selanjutnya, Query untuk token pertama dihitung sebagai:
\[
\begin{aligned}
\mathbf{Q}_1
&=
[\operatorname{LN}(\mathbf{T})]_{1}\mathbf{W}_Q\\
&=
\begin{bmatrix}
-1.00 & 1.00
\end{bmatrix}
\begin{bmatrix}
0.50 & 0.00\\
0.00 & 0.50
\end{bmatrix}\\
&=
\begin{bmatrix}
(-1.00)(0.50)+(1.00)(0.00) &
(-1.00)(0.00)+(1.00)(0.50)
\end{bmatrix}\\
&=
\begin{bmatrix}
-0.50 & 0.50
\end{bmatrix}.
\end{aligned}
\]
Dengan demikian, elemen Query untuk token pertama adalah:
\[
Q_{1,1}=-0.50,
\qquad
Q_{1,2}=0.50.
\]
Proses proyeksi yang sama diterapkan pada seluruh token. Dengan
menampilkan hasil hingga dua angka desimal, diperoleh matriks Query
berukuran \(25\times2\) sebagai
berikut:
\[
\mathbf{Q}
=
\begin{bmatrix}
-0.50 & 0.50\\
-0.50 & 0.50\\
0.50 & -0.50\\
0.50 & -0.50\\
-0.50 & 0.50\\
-0.50 & 0.50\\
-0.50 & 0.50\\
0.50 & -0.50\\
0.50 & -0.50\\
-0.50 & 0.50\\
-0.50 & 0.50\\
-0.50 & 0.50\\
0.50 & -0.50\\
0.50 & -0.50\\
-0.50 & 0.50\\
-0.50 & 0.50\\
-0.50 & 0.50\\
0.50 & -0.50\\
0.50 & -0.50\\
-0.50 & 0.50\\
-0.50 & 0.50\\
-0.50 & 0.50\\
0.50 & -0.50\\
-0.50 & 0.50\\
-0.50 & 0.50
\end{bmatrix}.
\]
c. Proyeksi Key
Setelah token dinormalisasi, setiap token juga diproyeksikan menjadi
Key (K). Pada mekanisme self-attention, Key berfungsi
sebagai representasi pembanding. Setiap Query dibandingkan dengan
seluruh Key untuk menentukan tingkat keterkaitan antartoken.
Pada ilustrasi ini, matriks bobot proyeksi Key ditetapkan
sebagai:
\[
\mathbf{W}_K
=
\begin{bmatrix}
0.40 & 0.00\\
0.00 & 0.60
\end{bmatrix}.
\]
Bobot tersebut memberikan skala yang berbeda pada komponen pertama
dan kedua dari setiap token ternormalisasi, tanpa mencampurkan informasi
antara kedua komponen fitur.
Proyeksi Key dirumuskan sebagai:
\[
\mathbf{K}
=
\operatorname{LN}(\mathbf{T})\mathbf{W}_K.
\]
Untuk token ke-\(t\), persamaan
tersebut dapat dituliskan sebagai:
\[
\begin{aligned}
\mathbf{K}_t
&=
[\operatorname{LN}(\mathbf{T})]_{t}\mathbf{W}_K\\
&=
\begin{bmatrix}
[\operatorname{LN}(\mathbf{T})]_{t,1} &
[\operatorname{LN}(\mathbf{T})]_{t,2}
\end{bmatrix}
\begin{bmatrix}
0.40 & 0.00\\
0.00 & 0.60
\end{bmatrix}.
\end{aligned}
\]
Matriks hasil normalisasi \(\operatorname{LN}(\mathbf{T})\) berukuran
\(25\times2\), sedangkan matriks bobot
\(\mathbf{W}_K\) berukuran \(2\times2\). Dengan demikian, matriks Key
\(\mathbf{K}\) berukuran \(25\times2\).
- Contoh perhitungan untuk token pertama:
Berdasarkan tahap normalisasi token sebelumnya, hasil normalisasi
token pertama yang ditampilkan dengan dua angka desimal adalah:
\[
[\operatorname{LN}(\mathbf{T})]_{1}
=
\begin{bmatrix}
-1.00 & 1.00
\end{bmatrix}.
\]
Selanjutnya, Key untuk token pertama dihitung sebagai:
\[
\begin{aligned}
\mathbf{K}_1
&=
[\operatorname{LN}(\mathbf{T})]_{1}\mathbf{W}_K\\
&=
\begin{bmatrix}
-1.00 & 1.00
\end{bmatrix}
\begin{bmatrix}
0.40 & 0.00\\
0.00 & 0.60
\end{bmatrix}\\
&=
\begin{bmatrix}
(-1.00)(0.40)+(1.00)(0.00) &
(-1.00)(0.00)+(1.00)(0.60)
\end{bmatrix}\\
&=
\begin{bmatrix}
-0.40 & 0.60
\end{bmatrix}.
\end{aligned}
\]
Dengan demikian, elemen Key untuk token pertama adalah:
\[
K_{1,1}=-0.40,
\qquad
K_{1,2}=0.60.
\]
Pada ilustrasi ini, matriks bobot \(\mathbf{W}_K\) ditetapkan berbeda dari
matriks bobot \(\mathbf{W}_Q\) untuk
menunjukkan bahwa Query dan Key dihasilkan melalui proyeksi yang
berbeda. Pada implementasi Transformer sebenarnya, kedua matriks bobot
tersebut merupakan parameter yang dipelajari secara terpisah selama
proses pelatihan.
Proses proyeksi yang sama diterapkan pada seluruh token. Dengan
menampilkan hasil hingga dua angka desimal, diperoleh matriks Key
berukuran \(25\times2\) sebagai
berikut:
\[
\mathbf{K}
=
\begin{bmatrix}
-0.40 & 0.60\\
-0.40 & 0.60\\
0.40 & -0.60\\
0.40 & -0.60\\
-0.40 & 0.60\\
-0.40 & 0.60\\
-0.40 & 0.60\\
0.40 & -0.60\\
0.40 & -0.60\\
-0.40 & 0.60\\
-0.40 & 0.60\\
-0.40 & 0.60\\
0.40 & -0.60\\
0.40 & -0.60\\
-0.40 & 0.60\\
-0.40 & 0.60\\
-0.40 & 0.60\\
0.40 & -0.60\\
0.40 & -0.60\\
-0.40 & 0.60\\
-0.40 & 0.60\\
-0.40 & 0.60\\
0.40 & -0.60\\
-0.40 & 0.60\\
-0.40 & 0.60
\end{bmatrix}.
\]
d. Proyeksi Value
Setelah token dinormalisasi, setiap token juga diproyeksikan menjadi
Value (V). Pada mekanisme self-attention, Value memuat
informasi fitur yang akan diagregasikan dari seluruh token berdasarkan
bobot attention yang dihitung melalui interaksi antara Query
dan Key.
Pada ilustrasi ini, matriks bobot proyeksi Value ditetapkan sebagai
matriks identitas:
\[
\mathbf{W}_V
=
\mathbf{I}
=
\begin{bmatrix}
1.00 & 0.00\\
0.00 & 1.00
\end{bmatrix}.
\]
Matriks identitas tidak mengubah nilai maupun mencampurkan kedua
elemen fitur token. Oleh karena itu, pada ilustrasi ini matriks Value
memiliki nilai yang sama dengan matriks token yang telah
dinormalisasi.
Proyeksi Value dirumuskan sebagai:
\[
\mathbf{V}
=
\operatorname{LN}(\mathbf{T})\mathbf{W}_V
=
\operatorname{LN}(\mathbf{T})\mathbf{I}
=
\operatorname{LN}(\mathbf{T}).
\]
Untuk token ke-\(t\), persamaan
tersebut dapat dituliskan sebagai:
\[
\begin{aligned}
\mathbf{V}_t
&=
[\operatorname{LN}(\mathbf{T})]_{t}\mathbf{W}_V\\
&=
\begin{bmatrix}
[\operatorname{LN}(\mathbf{T})]_{t,1} &
[\operatorname{LN}(\mathbf{T})]_{t,2}
\end{bmatrix}
\begin{bmatrix}
1.00 & 0.00\\
0.00 & 1.00
\end{bmatrix}.
\end{aligned}
\]
Matriks hasil normalisasi \(\operatorname{LN}(\mathbf{T})\) berukuran
\(25\times2\), sedangkan matriks bobot
\(\mathbf{W}_V\) berukuran \(2\times2\). Dengan demikian, matriks Value
\(\mathbf{V}\) berukuran \(25\times2\).
- Contoh perhitungan untuk token pertama:
Berdasarkan tahap normalisasi token sebelumnya, hasil normalisasi
token pertama yang ditampilkan dengan dua angka desimal adalah:
\[
[\operatorname{LN}(\mathbf{T})]_{1}
=
\begin{bmatrix}
-1.00 & 1.00
\end{bmatrix}.
\]
Selanjutnya, Value untuk token pertama dihitung sebagai:
\[
\begin{aligned}
\mathbf{V}_1
&=
[\operatorname{LN}(\mathbf{T})]_{1}\mathbf{W}_V\\
&=
\begin{bmatrix}
-1.00 & 1.00
\end{bmatrix}
\begin{bmatrix}
1.00 & 0.00\\
0.00 & 1.00
\end{bmatrix}\\
&=
\begin{bmatrix}
(-1.00)(1.00)+(1.00)(0.00) &
(-1.00)(0.00)+(1.00)(1.00)
\end{bmatrix}\\
&=
\begin{bmatrix}
-1.00 & 1.00
\end{bmatrix}.
\end{aligned}
\]
Dengan demikian, elemen Value untuk token pertama adalah:
\[
V_{1,1}=-1.00,
\qquad
V_{1,2}=1.00.
\]
Karena \(\mathbf{W}_V=\mathbf{I}\),
setiap baris pada matriks \(\mathbf{V}\) memiliki nilai yang sama
dengan baris yang bersesuaian pada matriks \(\operatorname{LN}(\mathbf{T})\). Pada
implementasi Transformer sebenarnya, matriks bobot \(\mathbf{W}_V\) merupakan parameter yang
dipelajari selama pelatihan dan tidak harus berbentuk matriks
identitas.
Proses proyeksi yang sama diterapkan pada seluruh token. Dengan
menampilkan hasil hingga dua angka desimal, diperoleh matriks Value
berukuran \(25\times2\) sebagai
berikut:
\[
\mathbf{V}
=
\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\\
-1.00 & 1.00
\end{bmatrix}.
\]
e. Scaled Dot-Product Attention
Setelah matriks Query \(\mathbf{Q}\)
dan matriks Key \(\mathbf{K}\)
diperoleh, tingkat keterkaitan antartoken dihitung menggunakan
scaled dot-product attention. Perhitungan ini menghasilkan
matriks skor perhatian \(\mathbf{S}\).
Elemen \(S_{t,u}\) menyatakan skor
kesesuaian antara Query token ke-\(t\)
dan Key token ke-\(u\). Semakin besar
skor yang diperoleh, semakin tinggi tingkat kesesuaian kedua
representasi tersebut.
Mengacu pada Persamaan (2.9), matriks skor perhatian dirumuskan
sebagai:
\[
\mathbf{S}
=
\frac{\mathbf{Q}\mathbf{K}^{\top}}{\sqrt{d_k}}.
\]
Pada ilustrasi ini, setiap Key memiliki dua komponen fitur,
sehingga:
\[
d_k=2.
\]
Untuk pasangan token ke-\(t\) dan
ke-\(u\), skor perhatian dihitung
menggunakan:
\[
S_{t,u}
=
\frac{\mathbf{Q}_t\mathbf{K}_u^{\top}}{\sqrt{2}}.
\]
Matriks \(\mathbf{Q}\) dan \(\mathbf{K}\) masing-masing berukuran \(25\times2\), sedangkan matriks \(\mathbf{K}^{\top}\) berukuran \(2\times25\). Dengan demikian, matriks skor
perhatian \(\mathbf{S}\) berukuran
\(25\times25\). Setiap baris
merepresentasikan token Query, sedangkan setiap kolom merepresentasikan
token Key.
- Contoh perhitungan skor perhatian token
pertama:
Berdasarkan hasil proyeksi sebelumnya, diperoleh Query dan Key token
pertama:
\[
\mathbf{Q}_1
=
\begin{bmatrix}
-0.50 & 0.50
\end{bmatrix},
\qquad
\mathbf{K}_1
=
\begin{bmatrix}
-0.40 & 0.60
\end{bmatrix}.
\]
Skor perhatian token pertama terhadap dirinya sendiri dihitung
sebagai:
\[
\begin{aligned}
S_{1,1}
&=
\frac{\mathbf{Q}_1\mathbf{K}_1^{\top}}{\sqrt{2}}\\
&=
\frac{
\begin{bmatrix}
-0.50 & 0.50
\end{bmatrix}
\begin{bmatrix}
-0.40\\
0.60
\end{bmatrix}
}{\sqrt{2}}\\
&=
\frac{(-0.50)(-0.40)+(0.50)(0.60)}{\sqrt{2}}\\
&=
\frac{0.20+0.30}{\sqrt{2}}\\
&=
\frac{0.50}{\sqrt{2}}\\
&=0.35.
\end{aligned}
\]
Sebagai pembanding, Key token ketiga adalah:
\[
\mathbf{K}_3
=
\begin{bmatrix}
0.40 & -0.60
\end{bmatrix}.
\]
Skor perhatian Query token pertama terhadap Key token ketiga dihitung
sebagai:
\[
\begin{aligned}
S_{1,3}
&=
\frac{\mathbf{Q}_1\mathbf{K}_3^{\top}}{\sqrt{2}}\\
&=
\frac{
\begin{bmatrix}
-0.50 & 0.50
\end{bmatrix}
\begin{bmatrix}
0.40\\
-0.60
\end{bmatrix}
}{\sqrt{2}}\\
&=
\frac{(-0.50)(0.40)+(0.50)(-0.60)}{\sqrt{2}}\\
&=
\frac{-0.20-0.30}{\sqrt{2}}\\
&=
\frac{-0.50}{\sqrt{2}}\\
&=-0.35.
\end{aligned}
\]
Proses yang sama diterapkan pada seluruh pasangan token. Dengan
menampilkan hasil hingga dua angka desimal, diperoleh matriks skor
perhatian \(\mathbf{S}\) berukuran
\(25\times25\) sebagai berikut:
\[
mathbf{S}
=\begin{bmatrix}
0.35 & 0.35 & -0.35 & -0.35 & 0.35 & 0.35 & 0.35
& -0.35 & -0.35 & 0.35 & 0.35 & 0.35 & -0.35
& -0.35 & 0.35 & 0.35 & 0.35 & -0.35 & -0.35
& 0.35 & 0.35 & 0.35 & -0.35 & 0.35 & 0.35\\
0.35 & 0.35 & -0.35 & -0.35 & 0.35 & 0.35 & 0.35
& -0.35 & -0.35 & 0.35 & 0.35 & 0.35 & -0.35
& -0.35 & 0.35 & 0.35 & 0.35 & -0.35 & -0.35
& 0.35 & 0.35 & 0.35 & -0.35 & 0.35 & 0.35\\
-0.35 & -0.35 & 0.35 & 0.35 & -0.35 & -0.35 &
-0.35 & 0.35 & 0.35 & -0.35 & -0.35 & -0.35 &
0.35 & 0.35 & -0.35 & -0.35 & -0.35 & 0.35 &
0.35 & -0.35 & -0.35 & -0.35 & 0.35 & -0.35 &
-0.35\\
-0.35 & -0.35 & 0.35 & 0.35 & -0.35 & -0.35 &
-0.35 & 0.35 & 0.35 & -0.35 & -0.35 & -0.35 &
0.35 & 0.35 & -0.35 & -0.35 & -0.35 & 0.35 &
0.35 & -0.35 & -0.35 & -0.35 & 0.35 & -0.35 &
-0.35\\
0.35 & 0.35 & -0.35 & -0.35 & 0.35 & 0.35 & 0.35
& -0.35 & -0.35 & 0.35 & 0.35 & 0.35 & -0.35
& -0.35 & 0.35 & 0.35 & 0.35 & -0.35 & -0.35
& 0.35 & 0.35 & 0.35 & -0.35 & 0.35 & 0.35\\
0.35 & 0.35 & -0.35 & -0.35 & 0.35 & 0.35 & 0.35
& -0.35 & -0.35 & 0.35 & 0.35 & 0.35 & -0.35
& -0.35 & 0.35 & 0.35 & 0.35 & -0.35 & -0.35
& 0.35 & 0.35 & 0.35 & -0.35 & 0.35 & 0.35\\
0.35 & 0.35 & -0.35 & -0.35 & 0.35 & 0.35 & 0.35
& -0.35 & -0.35 & 0.35 & 0.35 & 0.35 & -0.35
& -0.35 & 0.35 & 0.35 & 0.35 & -0.35 & -0.35
& 0.35 & 0.35 & 0.35 & -0.35 & 0.35 & 0.35\\
-0.35 & -0.35 & 0.35 & 0.35 & -0.35 & -0.35 &
-0.35 & 0.35 & 0.35 & -0.35 & -0.35 & -0.35 &
0.35 & 0.35 & -0.35 & -0.35 & -0.35 & 0.35 &
0.35 & -0.35 & -0.35 & -0.35 & 0.35 & -0.35 &
-0.35\\
-0.35 & -0.35 & 0.35 & 0.35 & -0.35 & -0.35 &
-0.35 & 0.35 & 0.35 & -0.35 & -0.35 & -0.35 &
0.35 & 0.35 & -0.35 & -0.35 & -0.35 & 0.35 &
0.35 & -0.35 & -0.35 & -0.35 & 0.35 & -0.35 &
-0.35\\
0.35 & 0.35 & -0.35 & -0.35 & 0.35 & 0.35 & 0.35
& -0.35 & -0.35 & 0.35 & 0.35 & 0.35 & -0.35
& -0.35 & 0.35 & 0.35 & 0.35 & -0.35 & -0.35
& 0.35 & 0.35 & 0.35 & -0.35 & 0.35 & 0.35\\
0.35 & 0.35 & -0.35 & -0.35 & 0.35 & 0.35 & 0.35
& -0.35 & -0.35 & 0.35 & 0.35 & 0.35 & -0.35
& -0.35 & 0.35 & 0.35 & 0.35 & -0.35 & -0.35
& 0.35 & 0.35 & 0.35 & -0.35 & 0.35 & 0.35\\
0.35 & 0.35 & -0.35 & -0.35 & 0.35 & 0.35 & 0.35
& -0.35 & -0.35 & 0.35 & 0.35 & 0.35 & -0.35
& -0.35 & 0.35 & 0.35 & 0.35 & -0.35 & -0.35
& 0.35 & 0.35 & 0.35 & -0.35 & 0.35 & 0.35\\
-0.35 & -0.35 & 0.35 & 0.35 & -0.35 & -0.35 &
-0.35 & 0.35 & 0.35 & -0.35 & -0.35 & -0.35 &
0.35 & 0.35 & -0.35 & -0.35 & -0.35 & 0.35 &
0.35 & -0.35 & -0.35 & -0.35 & 0.35 & -0.35 &
-0.35\\
-0.35 & -0.35 & 0.35 & 0.35 & -0.35 & -0.35 &
-0.35 & 0.35 & 0.35 & -0.35 & -0.35 & -0.35 &
0.35 & 0.35 & -0.35 & -0.35 & -0.35 & 0.35 &
0.35 & -0.35 & -0.35 & -0.35 & 0.35 & -0.35 &
-0.35\\
0.35 & 0.35 & -0.35 & -0.35 & 0.35 & 0.35 & 0.35
& -0.35 & -0.35 & 0.35 & 0.35 & 0.35 & -0.35
& -0.35 & 0.35 & 0.35 & 0.35 & -0.35 & -0.35
& 0.35 & 0.35 & 0.35 & -0.35 & 0.35 & 0.35\\
0.35 & 0.35 & -0.35 & -0.35 & 0.35 & 0.35 & 0.35
& -0.35 & -0.35 & 0.35 & 0.35 & 0.35 & -0.35
& -0.35 & 0.35 & 0.35 & 0.35 & -0.35 & -0.35
& 0.35 & 0.35 & 0.35 & -0.35 & 0.35 & 0.35\\
0.35 & 0.35 & -0.35 & -0.35 & 0.35 & 0.35 & 0.35
& -0.35 & -0.35 & 0.35 & 0.35 & 0.35 & -0.35
& -0.35 & 0.35 & 0.35 & 0.35 & -0.35 & -0.35
& 0.35 & 0.35 & 0.35 & -0.35 & 0.35 & 0.35\\
-0.35 & -0.35 & 0.35 & 0.35 & -0.35 & -0.35 &
-0.35 & 0.35 & 0.35 & -0.35 & -0.35 & -0.35 &
0.35 & 0.35 & -0.35 & -0.35 & -0.35 & 0.35 &
0.35 & -0.35 & -0.35 & -0.35 & 0.35 & -0.35 &
-0.35\\
-0.35 & -0.35 & 0.35 & 0.35 & -0.35 & -0.35 &
-0.35 & 0.35 & 0.35 & -0.35 & -0.35 & -0.35 &
0.35 & 0.35 & -0.35 & -0.35 & -0.35 & 0.35 &
0.35 & -0.35 & -0.35 & -0.35 & 0.35 & -0.35 &
-0.35\\
0.35 & 0.35 & -0.35 & -0.35 & 0.35 & 0.35 & 0.35
& -0.35 & -0.35 & 0.35 & 0.35 & 0.35 & -0.35
& -0.35 & 0.35 & 0.35 & 0.35 & -0.35 & -0.35
& 0.35 & 0.35 & 0.35 & -0.35 & 0.35 & 0.35\\
0.35 & 0.35 & -0.35 & -0.35 & 0.35 & 0.35 & 0.35
& -0.35 & -0.35 & 0.35 & 0.35 & 0.35 & -0.35
& -0.35 & 0.35 & 0.35 & 0.35 & -0.35 & -0.35
& 0.35 & 0.35 & 0.35 & -0.35 & 0.35 & 0.35\\
0.35 & 0.35 & -0.35 & -0.35 & 0.35 & 0.35 & 0.35
& -0.35 & -0.35 & 0.35 & 0.35 & 0.35 & -0.35
& -0.35 & 0.35 & 0.35 & 0.35 & -0.35 & -0.35
& 0.35 & 0.35 & 0.35 & -0.35 & 0.35 & 0.35\\
-0.35 & -0.35 & 0.35 & 0.35 & -0.35 & -0.35 &
-0.35 & 0.35 & 0.35 & -0.35 & -0.35 & -0.35 &
0.35 & 0.35 & -0.35 & -0.35 & -0.35 & 0.35 &
0.35 & -0.35 & -0.35 & -0.35 & 0.35 & -0.35 &
-0.35\\
0.35 & 0.35 & -0.35 & -0.35 & 0.35 & 0.35 & 0.35
& -0.35 & -0.35 & 0.35 & 0.35 & 0.35 & -0.35
& -0.35 & 0.35 & 0.35 & 0.35 & -0.35 & -0.35
& 0.35 & 0.35 & 0.35 & -0.35 & 0.35 & 0.35\\
0.35 & 0.35 & -0.35 & -0.35 & 0.35 & 0.35 & 0.35
& -0.35 & -0.35 & 0.35 & 0.35 & 0.35 & -0.35
& -0.35 & 0.35 & 0.35 & 0.35 & -0.35 & -0.35
& 0.35 & 0.35 & 0.35 & -0.35 & 0.35 & 0.35
\end{bmatrix}.
\]
Nilai positif menunjukkan bahwa pola Query dan Key kedua token
cenderung serupa, sedangkan nilai negatif menunjukkan pola yang
berlawanan. Matriks \(\mathbf{S}\)
selanjutnya dinormalisasi menggunakan fungsi softmax pada
setiap baris untuk menghasilkan matriks bobot perhatian \(\mathbf{A}\).
f. Softmax Attention
Matriks skor \(S\) selanjutnya
diubah menjadi bobot attention menggunakan fungsi softmax per baris.
Dengan demikian, setiap baris pada matriks \(A\) memiliki jumlah nilai sebesar satu.
\[
A_{t,u}
=
\frac{e^{S_{t,u}}}
{\sum_{r=1}^{25}e^{S_{t,r}}}.
\]
Matriks \(A\) memiliki dimensi \(25\times25\), sama seperti matriks skor
\(S\).
- Contoh perhitungan untuk \(A_{1,1}\):
Pada baris pertama matriks \(S\),
terdapat 16 skor bernilai \(0.35\) dan
9 skor bernilai \(-0.35\). Oleh karena
itu,
\[
\begin{aligned}
A_{1,1}
&=
\frac{e^{0.35}}
{16e^{0.35}+9e^{-0.35}}\\
&=
\frac{1.42}
{16(1.42)+9(0.70)}\\
&=
\frac{1.42}{22.72+6.30}\\
&=
\frac{1.42}{29.02}\\
&=0.05.
\end{aligned}
\]
Nilai \(0.05\) menunjukkan bahwa
token pertama memberi bobot perhatian lebih besar kepada token yang
memiliki pola Query–Key serupa, yaitu token dengan skor \(0.35\).
Aturan yang sama diterapkan pada seluruh baris, sehingga diperoleh
matriks bobot attention \(A\) berikut.
\[
A=\begin{bmatrix}
0.05 & 0.05 & 0.02 & 0.02 & 0.05 & 0.05 & 0.05
& 0.02 & 0.02 & 0.05 & 0.05 & 0.05 & 0.02 &
0.02 & 0.05 & 0.05 & 0.05 & 0.02 & 0.02 & 0.05
& 0.05 & 0.05 & 0.02 & 0.05 & 0.05\\
0.05 & 0.05 & 0.02 & 0.02 & 0.05 & 0.05 & 0.05
& 0.02 & 0.02 & 0.05 & 0.05 & 0.05 & 0.02 &
0.02 & 0.05 & 0.05 & 0.05 & 0.02 & 0.02 & 0.05
& 0.05 & 0.05 & 0.02 & 0.05 & 0.05\\
0.03 & 0.03 & 0.06 & 0.06 & 0.03 & 0.03 & 0.03
& 0.06 & 0.06 & 0.03 & 0.03 & 0.03 & 0.06 &
0.06 & 0.03 & 0.03 & 0.03 & 0.06 & 0.06 & 0.03
& 0.03 & 0.03 & 0.06 & 0.03 & 0.03\\
0.03 & 0.03 & 0.06 & 0.06 & 0.03 & 0.03 & 0.03
& 0.06 & 0.06 & 0.03 & 0.03 & 0.03 & 0.06 &
0.06 & 0.03 & 0.03 & 0.03 & 0.06 & 0.06 & 0.03
& 0.03 & 0.03 & 0.06 & 0.03 & 0.03\\
0.05 & 0.05 & 0.02 & 0.02 & 0.05 & 0.05 & 0.05
& 0.02 & 0.02 & 0.05 & 0.05 & 0.05 & 0.02 &
0.02 & 0.05 & 0.05 & 0.05 & 0.02 & 0.02 & 0.05
& 0.05 & 0.05 & 0.02 & 0.05 & 0.05\\
0.05 & 0.05 & 0.02 & 0.02 & 0.05 & 0.05 & 0.05
& 0.02 & 0.02 & 0.05 & 0.05 & 0.05 & 0.02 &
0.02 & 0.05 & 0.05 & 0.05 & 0.02 & 0.02 & 0.05
& 0.05 & 0.05 & 0.02 & 0.05 & 0.05\\
0.05 & 0.05 & 0.02 & 0.02 & 0.05 & 0.05 & 0.05
& 0.02 & 0.02 & 0.05 & 0.05 & 0.05 & 0.02 &
0.02 & 0.05 & 0.05 & 0.05 & 0.02 & 0.02 & 0.05
& 0.05 & 0.05 & 0.02 & 0.05 & 0.05\\
0.03 & 0.03 & 0.06 & 0.06 & 0.03 & 0.03 & 0.03
& 0.06 & 0.06 & 0.03 & 0.03 & 0.03 & 0.06 &
0.06 & 0.03 & 0.03 & 0.03 & 0.06 & 0.06 & 0.03
& 0.03 & 0.03 & 0.06 & 0.03 & 0.03\\
0.03 & 0.03 & 0.06 & 0.06 & 0.03 & 0.03 & 0.03
& 0.06 & 0.06 & 0.03 & 0.03 & 0.03 & 0.06 &
0.06 & 0.03 & 0.03 & 0.03 & 0.06 & 0.06 & 0.03
& 0.03 & 0.03 & 0.06 & 0.03 & 0.03\\
0.05 & 0.05 & 0.02 & 0.02 & 0.05 & 0.05 & 0.05
& 0.02 & 0.02 & 0.05 & 0.05 & 0.05 & 0.02 &
0.02 & 0.05 & 0.05 & 0.05 & 0.02 & 0.02 & 0.05
& 0.05 & 0.05 & 0.02 & 0.05 & 0.05\\
0.05 & 0.05 & 0.02 & 0.02 & 0.05 & 0.05 & 0.05
& 0.02 & 0.02 & 0.05 & 0.05 & 0.05 & 0.02 &
0.02 & 0.05 & 0.05 & 0.05 & 0.02 & 0.02 & 0.05
& 0.05 & 0.05 & 0.02 & 0.05 & 0.05\\
0.05 & 0.05 & 0.02 & 0.02 & 0.05 & 0.05 & 0.05
& 0.02 & 0.02 & 0.05 & 0.05 & 0.05 & 0.02 &
0.02 & 0.05 & 0.05 & 0.05 & 0.02 & 0.02 & 0.05
& 0.05 & 0.05 & 0.02 & 0.05 & 0.05\\
0.03 & 0.03 & 0.06 & 0.06 & 0.03 & 0.03 & 0.03
& 0.06 & 0.06 & 0.03 & 0.03 & 0.03 & 0.06 &
0.06 & 0.03 & 0.03 & 0.03 & 0.06 & 0.06 & 0.03
& 0.03 & 0.03 & 0.06 & 0.03 & 0.03\\
0.03 & 0.03 & 0.06 & 0.06 & 0.03 & 0.03 & 0.03
& 0.06 & 0.06 & 0.03 & 0.03 & 0.03 & 0.06 &
0.06 & 0.03 & 0.03 & 0.03 & 0.06 & 0.06 & 0.03
& 0.03 & 0.03 & 0.06 & 0.03 & 0.03\\
0.05 & 0.05 & 0.02 & 0.02 & 0.05 & 0.05 & 0.05
& 0.02 & 0.02 & 0.05 & 0.05 & 0.05 & 0.02 &
0.02 & 0.05 & 0.05 & 0.05 & 0.02 & 0.02 & 0.05
& 0.05 & 0.05 & 0.02 & 0.05 & 0.05\\
0.05 & 0.05 & 0.02 & 0.02 & 0.05 & 0.05 & 0.05
& 0.02 & 0.02 & 0.05 & 0.05 & 0.05 & 0.02 &
0.02 & 0.05 & 0.05 & 0.05 & 0.02 & 0.02 & 0.05
& 0.05 & 0.05 & 0.02 & 0.05 & 0.05\\
0.05 & 0.05 & 0.02 & 0.02 & 0.05 & 0.05 & 0.05
& 0.02 & 0.02 & 0.05 & 0.05 & 0.05 & 0.02 &
0.02 & 0.05 & 0.05 & 0.05 & 0.02 & 0.02 & 0.05
& 0.05 & 0.05 & 0.02 & 0.05 & 0.05\\
0.03 & 0.03 & 0.06 & 0.06 & 0.03 & 0.03 & 0.03
& 0.06 & 0.06 & 0.03 & 0.03 & 0.03 & 0.06 &
0.06 & 0.03 & 0.03 & 0.03 & 0.06 & 0.06 & 0.03
& 0.03 & 0.03 & 0.06 & 0.03 & 0.03\\
0.03 & 0.03 & 0.06 & 0.06 & 0.03 & 0.03 & 0.03
& 0.06 & 0.06 & 0.03 & 0.03 & 0.03 & 0.06 &
0.06 & 0.03 & 0.03 & 0.03 & 0.06 & 0.06 & 0.03
& 0.03 & 0.03 & 0.06 & 0.03 & 0.03\\
0.05 & 0.05 & 0.02 & 0.02 & 0.05 & 0.05 & 0.05
& 0.02 & 0.02 & 0.05 & 0.05 & 0.05 & 0.02 &
0.02 & 0.05 & 0.05 & 0.05 & 0.02 & 0.02 & 0.05
& 0.05 & 0.05 & 0.02 & 0.05 & 0.05\\
0.05 & 0.05 & 0.02 & 0.02 & 0.05 & 0.05 & 0.05
& 0.02 & 0.02 & 0.05 & 0.05 & 0.05 & 0.02 &
0.02 & 0.05 & 0.05 & 0.05 & 0.02 & 0.02 & 0.05
& 0.05 & 0.05 & 0.02 & 0.05 & 0.05\\
0.05 & 0.05 & 0.02 & 0.02 & 0.05 & 0.05 & 0.05
& 0.02 & 0.02 & 0.05 & 0.05 & 0.05 & 0.02 &
0.02 & 0.05 & 0.05 & 0.05 & 0.02 & 0.02 & 0.05
& 0.05 & 0.05 & 0.02 & 0.05 & 0.05\\
0.03 & 0.03 & 0.06 & 0.06 & 0.03 & 0.03 & 0.03
& 0.06 & 0.06 & 0.03 & 0.03 & 0.03 & 0.06 &
0.06 & 0.03 & 0.03 & 0.03 & 0.06 & 0.06 & 0.03
& 0.03 & 0.03 & 0.06 & 0.03 & 0.03\\
0.05 & 0.05 & 0.02 & 0.02 & 0.05 & 0.05 & 0.05
& 0.02 & 0.02 & 0.05 & 0.05 & 0.05 & 0.02 &
0.02 & 0.05 & 0.05 & 0.05 & 0.02 & 0.02 & 0.05
& 0.05 & 0.05 & 0.02 & 0.05 & 0.05\\
0.05 & 0.05 & 0.02 & 0.02 & 0.05 & 0.05 & 0.05
& 0.02 & 0.02 & 0.05 & 0.05 & 0.05 & 0.02 &
0.02 & 0.05 & 0.05 & 0.05 & 0.02 & 0.02 & 0.05
& 0.05 & 0.05 & 0.02 & 0.05 & 0.05
\end{bmatrix}.
\]
g. Agregasi Value Berbobot Attention
Matriks bobot attention \(\mathbf{A}\) digunakan untuk menggabungkan
seluruh Value \(\mathbf{V}\). Setiap
baris hasil \(\mathbf{A}\mathbf{V}\)
adalah jumlah berbobot dari seluruh token Value.
Pada ilustrasi perhitungan ini, mekanisme self-attention
disederhanakan menggunakan satu attention head. Oleh karena itu, operasi
concatenation pada Persamaan (2.14) tidak menggabungkan beberapa
keluaran head dan menghasilkan keluaran yang sama dengan head tunggal
tersebut. Matriks proyeksi keluaran \(\mathbf
W^O\) ditetapkan sebagai matriks identitas, sehingga proses
proyeksi keluaran tidak mengubah nilai hasil agregasi Value. Dengan
demikian, keluaran attention pada ilustrasi ini diperoleh dari perkalian
matriks bobot perhatian \(\mathbf A\)
dan matriks Value \(\mathbf V\).
\[
\mathbf{O}_{\mathrm{att}}=\mathbf{A}\mathbf{V}.
\]
Pada ilustrasi ini, karena bobot keluaran \(\mathbf{W}^{O}=\mathbf{I}\), maka:
\[
\mathbf{O}_{\mathrm{att}}
=
\mathbf{A}\mathbf{V}\mathbf{W}^{O}
=
\mathbf{A}\mathbf{V}.
\]
Matriks \(\mathbf{A}\) berdimensi
\(25\times25\), sedangkan \(\mathbf{V}\) berdimensi \(25\times2\). Oleh karena itu, hasil \(\mathbf{A}\mathbf{V}\) atau matriks
keluaran attention \(\mathbf{O}_{\mathrm{att}}\) berdimensi
\(25\times2\).
- Contoh perhitungan untuk \(O_{\mathrm{att},1,1}\):
Pada baris pertama, terdapat 16 token Value berpola \((-1,1)\) dengan bobot sekitar \(0.05\), serta 9 token Value berpola \((1,-1)\) dengan bobot sekitar \(0.02\). Maka, komponen pertama dihitung
sebagai:
\[
\begin{aligned}
O_{\mathrm{att},1,1}
&=
\sum_{u=1}^{25}A_{1,u}V_{u,1}\\
&=
16(0.05)(-1.00)+9(0.02)(1.00)\\
&=
-0.80+0.18\\
&=
-0.62.
\end{aligned}
\]
Dengan cara yang sama, komponen kedua adalah:
\[
\begin{aligned}
O_{\mathrm{att},1,2}
&=
\sum_{u=1}^{25}A_{1,u}V_{u,2}\\
&=
16(0.05)(1.00)+9(0.02)(-1.00)\\
&=
0.80-0.18\\
&=
0.62.
\end{aligned}
\]
Sehingga,
\[
\mathbf{O}_{\mathrm{att},1}=
\begin{bmatrix}
-0.62 & 0.62
\end{bmatrix}.
\]
Aturan yang sama diterapkan pada seluruh token, sehingga diperoleh
matriks \(AV\) berikut.
\[
\mathbf{O}_{\mathrm{att}}
=
\begin{bmatrix}
-0.62 & 0.62\\
-0.62 & 0.62\\
0.06 & -0.06\\
0.06 & -0.06\\
-0.62 & 0.62\\
-0.62 & 0.62\\
-0.62 & 0.62\\
0.06 & -0.06\\
0.06 & -0.06\\
-0.62 & 0.62\\
-0.62 & 0.62\\
-0.62 & 0.62\\
0.06 & -0.06\\
0.06 & -0.06\\
-0.62 & 0.62\\
-0.62 & 0.62\\
-0.62 & 0.62\\
0.06 & -0.06\\
0.06 & -0.06\\
-0.62 & 0.62\\
-0.62 & 0.62\\
-0.62 & 0.62\\
0.06 & -0.06\\
-0.62 & 0.62\\
-0.62 & 0.62
\end{bmatrix}.
\]
h. Residual Attention
Residual attention menggabungkan matriks token awal \(\mathbf{T}\) dengan keluaran attention
\(\mathbf{O}_{\mathrm{att}}\).
Tujuannya adalah mempertahankan informasi awal token sambil menambahkan
informasi global hasil self-attention.
\[
\mathbf{Z}'
=
\mathbf{T}
+
\mathbf{O}_{\mathrm{att}}.
\]
Matriks \(\mathbf{T}\) dan \(\mathbf{O}_{\mathrm{att}}\) keduanya
berdimensi \(25\times2\), sehingga
\(\mathbf{Z}'\) juga berdimensi
\(25\times2\).
- Contoh perhitungan untuk token pertama:
\[
\mathbf{T}_1=
\begin{bmatrix}
-0.27 & 0.13
\end{bmatrix},
\qquad
\mathbf{O}_{\mathrm{att},1}=
\begin{bmatrix}
-0.62 & 0.62
\end{bmatrix}.
\]
Maka,
\[
\begin{aligned}
\mathbf{Z}'_{1}
&=
\mathbf{T}_1+\mathbf{O}_{\mathrm{att},1}\\
&=
\begin{bmatrix}
-0.27 & 0.13
\end{bmatrix}
+
\begin{bmatrix}
-0.62 & 0.62
\end{bmatrix}\\
&=
\begin{bmatrix}
-0.89 & 0.75
\end{bmatrix}.
\end{aligned}
\]
Aturan yang sama diterapkan pada seluruh token, sehingga diperoleh
matriks residual attention \(\mathbf{Z}'\) berikut.
\[
\mathbf{Z}'=
\begin{bmatrix}
-0.89 & 0.75\\
-0.87 & 0.74\\
0.62 & -0.34\\
0.32 & -0.19\\
-0.89 & 0.76\\
-0.88 & 0.75\\
-0.85 & 0.74\\
0.93 & -0.49\\
0.52 & -0.29\\
-0.89 & 0.76\\
-0.88 & 0.75\\
-0.85 & 0.73\\
0.93 & -0.49\\
0.52 & -0.29\\
-0.89 & 0.76\\
-0.88 & 0.75\\
-0.87 & 0.75\\
0.66 & -0.36\\
0.30 & -0.18\\
-0.90 & 0.76\\
-0.89 & 0.76\\
-0.89 & 0.76\\
0.16 & -0.11\\
-0.71 & 0.66\\
-0.90 & 0.76
\end{bmatrix}.
\]
i. Normalisasi Keluaran Residual Attention
Matriks hasil residual attention \(\mathbf{Z}'\) dinormalisasi per token
menggunakan Layer Normalization, dengan prosedur yang sama
seperti normalisasi token sebelumnya.
\[
\left[\operatorname{LN}(\mathbf{Z}'_t)\right]_k
=
\frac{Z'_{t,k}-\mu_t}
{\sqrt{\sigma_t^{2}+10^{-5}}},
\]
dengan:
\[
\mu_t
=
\frac{1}{2}\sum_{k=1}^{2}Z'_{t,k},
\qquad
\sigma_t^{2}
=
\frac{1}{2}\sum_{k=1}^{2}(Z'_{t,k}-\mu_t)^2.
\]
- Contoh perhitungan untuk token pertama:
\[
\mathbf{Z}'_1=
\begin{bmatrix}
-0.89 & 0.75
\end{bmatrix}.
\]
Rata-rata token pertama adalah:
\[
\begin{aligned}
\mu_1
&=
\frac{-0.89+0.75}{2}\\
&=
-0.07.
\end{aligned}
\]
Variansnya adalah:
\[
\begin{aligned}
\sigma_1^2
&=
\frac{(-0.89-(-0.07))^2+(0.75-(-0.07))^2}{2}\\
&=
\frac{(-0.82)^2+(0.82)^2}{2}\\
&=
0.6724.
\end{aligned}
\]
Elemen pertama setelah normalisasi adalah:
\[
\begin{aligned}
\left[\operatorname{LN}(\mathbf{Z}'_1)\right]_1
&=
\frac{-0.89-(-0.07)}
{\sqrt{0.6724+10^{-5}}}\\
&=
\frac{-0.82}{0.82}\\
&=
-1.00.
\end{aligned}
\]
Dengan cara yang sama, \(\left[\operatorname{LN}(\mathbf{Z}'_1)\right]_2=1.00\).
Oleh karena itu:
\[
\operatorname{LN}(\mathbf{Z}'_1)=
\begin{bmatrix}
-1.00 & 1.00
\end{bmatrix}.
\]
Aturan yang sama diterapkan pada seluruh token, sehingga diperoleh
hasil normalisasi residual attention \(\operatorname{LN}(\mathbf{Z}')\)
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}.
\]
j. Lapisan Linear Pertama MLP (Feed-Forward Network)
Lapisan linear pertama pada MLP memproyeksikan setiap token dari dua
fitur menjadi tiga fitur. Tahap ini merupakan bagian pertama dari MLP
pada Persamaan (2.17). Pada ilustrasi perhitungan, fungsi aktivasi GELU
disederhanakan menjadi ReLU dan vektor bias tidak digunakan.
- Bobot lapisan linear pertama:
\[
\mathbf{W}_1=
\begin{bmatrix}
0.60 & -0.20 & 0.40\\
-0.30 & 0.50 & -0.40
\end{bmatrix}.
\]
\[
\operatorname{ReLU}
\left(
\operatorname{LN}(\mathbf{Z}')\mathbf{W}_1
\right).
\]
dengan:
\[
\operatorname{ReLU}(x)=\max(0,x).
\]
Matriks \(\operatorname{LN}(\mathbf{Z}')\)
berdimensi \(25\times2\) dan \(\mathbf{W}_1\) berdimensi \(2\times3\), sehingga hasil lapisan linear
pertama setelah aktivasi ReLU berdimensi \(25\times3\).
- Contoh perhitungan untuk token pertama:
\[
\operatorname{LN}(\mathbf{Z}'_1)=
\begin{bmatrix}
-1.00 & 1.00
\end{bmatrix}.
\]
Sebelum ReLU:
\[
\begin{aligned}
\operatorname{LN}(\mathbf{Z}'_1)\mathbf{W}_1
&=
\begin{bmatrix}
-1.00 & 1.00
\end{bmatrix}
\begin{bmatrix}
0.60 & -0.20 & 0.40\\
-0.30 & 0.50 & -0.40
\end{bmatrix}\\
&=
\begin{bmatrix}
-0.90 & 0.70 & -0.80
\end{bmatrix}.
\end{aligned}
\]
Setelah ReLU:
\[
\begin{aligned}
\operatorname{ReLU}
\left(
\operatorname{LN}(\mathbf{Z}'_1)\mathbf{W}_1
\right)
&=
\operatorname{ReLU}
\left(
\begin{bmatrix}
-0.90 & 0.70 & -0.80
\end{bmatrix}
\right)\\
&=
\begin{bmatrix}
0.00 & 0.70 & 0.00
\end{bmatrix}.
\end{aligned}
\]
Aturan yang sama diterapkan pada seluruh token, sehingga diperoleh
hasil lapisan linear pertama setelah aktivasi ReLU berikut.
\[
\operatorname{ReLU}
\left(
\operatorname{LN}(\mathbf{Z}')\mathbf{W}_1
\right)
=
\begin{bmatrix}
0.00 & 0.70 & 0.00\\
0.00 & 0.70 & 0.00\\
0.90 & 0.00 & 0.80\\
0.90 & 0.00 & 0.80\\
0.00 & 0.70 & 0.00\\
0.00 & 0.70 & 0.00\\
0.00 & 0.70 & 0.00\\
0.90 & 0.00 & 0.80\\
0.90 & 0.00 & 0.80\\
0.00 & 0.70 & 0.00\\
0.00 & 0.70 & 0.00\\
0.00 & 0.70 & 0.00\\
0.90 & 0.00 & 0.80\\
0.90 & 0.00 & 0.80\\
0.00 & 0.70 & 0.00\\
0.00 & 0.70 & 0.00\\
0.00 & 0.70 & 0.00\\
0.90 & 0.00 & 0.80\\
0.90 & 0.00 & 0.80\\
0.00 & 0.70 & 0.00\\
0.00 & 0.70 & 0.00\\
0.00 & 0.70 & 0.00\\
0.90 & 0.00 & 0.80\\
0.00 & 0.70 & 0.00\\
0.00 & 0.70 & 0.00
\end{bmatrix}.
\]
k. Lapisan Linear Kedua MLP (Feed-Forward Network)
Lapisan linear kedua MLP memproyeksikan kembali hasil lapisan linear
pertama dari tiga fitur menjadi dua fitur.
- Bobot lapisan linear kedua:
\[
\mathbf{W}_2=
\begin{bmatrix}
0.30 & -0.20\\
0.20 & 0.40\\
-0.10 & 0.30
\end{bmatrix}.
\]
\[
\operatorname{ReLU}
\left(
\operatorname{LN}(\mathbf{Z}')\mathbf{W}_1
\right)
\mathbf{W}_2.
\]
Hasil lapisan linear pertama setelah aktivasi ReLU berdimensi \(25\times3\) dan \(\mathbf{W}_2\) berdimensi \(3\times2\), sehingga keluaran lapisan
linear kedua berdimensi \(25\times2\).
- Contoh perhitungan untuk token pertama:
\[
\operatorname{ReLU}
\left(
\operatorname{LN}(\mathbf{Z}'_1)\mathbf{W}_1
\right)
=
\begin{bmatrix}
0.00 & 0.70 & 0.00
\end{bmatrix}.
\]
Maka,
\[
\begin{aligned}
\operatorname{ReLU}
\left(
\operatorname{LN}(\mathbf{Z}'_1)\mathbf{W}_1
\right)
\mathbf{W}_2
&=
\begin{bmatrix}
0.00 & 0.70 & 0.00
\end{bmatrix}
\begin{bmatrix}
0.30 & -0.20\\
0.20 & 0.40\\
-0.10 & 0.30
\end{bmatrix}\\
&=
\begin{bmatrix}
(0.00)(0.30)+(0.70)(0.20)+(0.00)(-0.10) &
(0.00)(-0.20)+(0.70)(0.40)+(0.00)(0.30)
\end{bmatrix}\\
&=
\begin{bmatrix}
0.14 & 0.28
\end{bmatrix}.
\end{aligned}
\]
Aturan yang sama diterapkan pada seluruh token, sehingga diperoleh
keluaran lapisan linear kedua MLP berikut.
\[
\operatorname{ReLU}
\left(
\operatorname{LN}(\mathbf{Z}')\mathbf{W}_1
\right)
\mathbf{W}_2
=
\begin{bmatrix}
0.14 & 0.28\\
0.14 & 0.28\\
0.19 & 0.06\\
0.19 & 0.06\\
0.14 & 0.28\\
0.14 & 0.28\\
0.14 & 0.28\\
0.19 & 0.06\\
0.19 & 0.06\\
0.14 & 0.28\\
0.14 & 0.28\\
0.14 & 0.28\\
0.19 & 0.06\\
0.19 & 0.06\\
0.14 & 0.28\\
0.14 & 0.28\\
0.14 & 0.28\\
0.19 & 0.06\\
0.19 & 0.06\\
0.14 & 0.28\\
0.14 & 0.28\\
0.14 & 0.28\\
0.19 & 0.06\\
0.14 & 0.28\\
0.14 & 0.28
\end{bmatrix}.
\]
l. Residual MLP (Feed-Forward Network)
Residual MLP menggabungkan keluaran MLP dengan representasi \(\mathbf{Z}'\), yaitu keluaran dari
residual attention. Operasi ini mempertahankan informasi dari tahap
attention setelah MLP menambahkan transformasi fitur.
\[
\mathbf{Z}
=
\operatorname{ReLU}
\left(
\operatorname{LN}(\mathbf{Z}')\mathbf{W}_1
\right)
\mathbf{W}_2
+
\mathbf{Z}'.
\]
Matriks \(\operatorname{ReLU}(\operatorname{LN}(\mathbf{Z}')\mathbf{W}_1)\mathbf{W}_2\)
dan \(\mathbf{Z}'\) sama-sama
berdimensi \(25\times2\), sehingga
\(\mathbf{Z}\) berdimensi \(25\times2\).
- Contoh perhitungan untuk token pertama:
\[
\mathbf{Z}'_1=
\begin{bmatrix}
-0.89 & 0.75
\end{bmatrix},
\]
\[
\operatorname{ReLU}
\left(
\operatorname{LN}(\mathbf{Z}'_1)\mathbf{W}_1
\right)
\mathbf{W}_2
=
\begin{bmatrix}
0.14 & 0.28
\end{bmatrix}.
\]
Maka,
\[
\begin{aligned}
\mathbf{Z}_1
&=
\operatorname{ReLU}
\left(
\operatorname{LN}(\mathbf{Z}'_1)\mathbf{W}_1
\right)
\mathbf{W}_2
+
\mathbf{Z}'_1\\
&=
\begin{bmatrix}
0.14 & 0.28
\end{bmatrix}
+
\begin{bmatrix}
-0.89 & 0.75
\end{bmatrix}\\
&=
\begin{bmatrix}
-0.75 & 1.03
\end{bmatrix}.
\end{aligned}
\]
Aturan yang sama diterapkan pada seluruh token, sehingga diperoleh
matriks \(\mathbf{Z}\) berikut.
\[
\mathbf{Z}=\begin{bmatrix}
-0.75 & 1.03\\
-0.73 & 1.02\\
0.81 & -0.28\\
0.51 & -0.13\\
-0.75 & 1.04\\
-0.74 & 1.03\\
-0.71 & 1.02\\
1.12 & -0.43\\
0.71 & -0.23\\
-0.75 & 1.04\\
-0.74 & 1.03\\
-0.71 & 1.01\\
1.12 & -0.43\\
0.71 & -0.23\\
-0.75 & 1.04\\
-0.74 & 1.03\\
-0.73 & 1.03\\
0.85 & -0.30\\
0.49 & -0.12\\
-0.76 & 1.04\\
-0.75 & 1.04\\
-0.75 & 1.04\\
0.35 & -0.05\\
-0.57 & 0.94\\
-0.76 & 1.04
\end{bmatrix}.
\]
m. Normalisasi Keluaran Transformer
Tahap terakhir Transformer adalah normalisasi per token terhadap
matriks keluaran residual MLP \(\mathbf{Z}\). Matriks hasil \(\mathbf{G}\) merupakan representasi global
yang akan dilipat kembali ke bentuk spasial pada tahap berikutnya.
\[
G_{t,k}
=
\frac{Z_{t,k}-\mu_{Z,t}}
{\sqrt{\sigma_{Z,t}^{2}+10^{-5}}}.
\]
- Contoh perhitungan untuk token pertama:
\[
\mathbf{Z}_{1}=
\begin{bmatrix}
-0.75 & 1.03
\end{bmatrix}.
\]
Rata-rata token pertama adalah:
\[
\begin{aligned}
\mu_{Z,1}
&=\frac{-0.75+1.03}{2}\\
&=0.14.
\end{aligned}
\]
Variansnya adalah:
\[
\begin{aligned}
\sigma_{Z,1}^2
&=\frac{(-0.75-0.14)^2+(1.03-0.14)^2}{2}\\
&=\frac{(-0.89)^2+(0.89)^2}{2}\\
&=0.7921.
\end{aligned}
\]
Elemen pertama setelah normalisasi adalah:
\[
\begin{aligned}
G_{1,1}
&=\frac{-0.75-0.14}{\sqrt{0.7921+10^{-5}}}\\
&=\frac{-0.89}{0.89}\\
&=-1.00.
\end{aligned}
\]
Dengan cara yang sama, \(G_{1,2}=1.00\). Maka:
\[
\mathbf{G}_{1}=
\begin{bmatrix}
-1.00 & 1.00
\end{bmatrix}.
\]
Aturan yang sama diterapkan pada seluruh token, sehingga diperoleh
representasi global Transformer \(\mathbf{G}\) 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 Fitur Global, dan Fusi Residual
Keluaran Transformer \(\mathbf{G}\)
masih berbentuk matriks token berdimensi \(25\times2\). Tahap folding
mengembalikan token tersebut ke susunan spasial \(5\times5\). Setelah itu, kedua kanal hasil
folding diproyeksikan menjadi satu feature map global
dan diaktifkan menggunakan fungsi Swish. Feature map global
tersebut kemudian difusikan dengan feature map lokal \(\mathbf{L}\) dan feature map
masukan \(\mathbf{X}\).
a. Folding Keluaran Transformer
Folding menempatkan kembali token ke-\(t\) pada posisi spasial \((i,j)\) berdasarkan urutan raster dari kiri
ke kanan dan dari atas ke bawah:
\[
t=W(i-1)+j,
\qquad W=5.
\]
Kolom pertama dari matriks token \(\mathbf{G}\) dilipat menjadi kanal pertama
\(\mathbf{G}_1\), sedangkan kolom kedua
dilipat menjadi kanal kedua \(\mathbf{G}_2\). Kedua matriks hasil
folding memiliki dimensi \(5\times5\).
\[
G_{n,i,j}=G_{t,n},
\qquad
n=1,2,
\qquad
t=W(i-1)+j.
\]
- Contoh perhitungan pada posisi \((1,1)\):
Posisi \((1,1)\) bersesuaian dengan
token pertama:
\[
\begin{aligned}
t&=5(1-1)+1\\
&=1.
\end{aligned}
\]
Karena token pertama adalah:
\[
\mathbf{G}_{t=1}=
\begin{bmatrix}
-1.00 & 1.00
\end{bmatrix},
\]
maka hasil folding pada posisi \((1,1)\) adalah:
\[
G_{1,1,1}=G_{1,1}=-1.00,
\qquad
G_{2,1,1}=G_{1,2}=1.00.
\]
Matriks kanal pertama setelah 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 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}.
\]
b. Proyeksi dan Aktivasi Fitur Global
Kedua kanal hasil folding, yaitu \(\mathbf{G}_1\) dan \(\mathbf{G}_2\), diproyeksikan menjadi satu
feature map global menggunakan pointwise convolution
\(1\times1\). Pada ilustrasi ini, bias
tidak digunakan. Bobot pointwise convolution untuk proyeksi
global ditetapkan sebagai:
\[
\mathbf{W}_{\mathrm{pw}}^{(\mathrm{glob})}
=
\begin{bmatrix}
0.60 & -0.40
\end{bmatrix}.
\]
\[
F_{\mathrm{pw},i,j,1}^{(\mathrm{glob})}
=
\sum_{n=1}^{2}
W_{\mathrm{pw},n,1}^{(\mathrm{glob})}
G_{n,i,j}.
\]
Berdasarkan bobot yang digunakan, diperoleh:
\[
F_{\mathrm{pw},i,j,1}^{(\mathrm{glob})}
=
0.60G_{1,i,j}-0.40G_{2,i,j}.
\]
Keluaran proyeksi kemudian diaktifkan menggunakan fungsi Swish:
\[
\begin{aligned}
G_{\mathrm{global},i,j}
&=
\operatorname{Swish}
\left(
F_{\mathrm{pw},i,j,1}^{(\mathrm{glob})}
\right)\\
&=
\frac{F_{\mathrm{pw},i,j,1}^{(\mathrm{glob})}}
{1+e^{-F_{\mathrm{pw},i,j,1}^{(\mathrm{glob})}}}.
\end{aligned}
\]
Matriks \(\mathbf{F}_{\mathrm{pw}}^{(\mathrm{glob})}\)
dan \(\mathbf{G}_{\mathrm{global}}\)
keduanya berdimensi \(5\times5\).
- Contoh perhitungan pada posisi \((1,1)\):
Diketahui:
\[
G_{1,1,1}=-1.00,
\qquad
G_{2,1,1}=1.00.
\]
Nilai hasil pointwise convolution sebelum aktivasi
adalah:
\[
\begin{aligned}
F_{\mathrm{pw},1,1,1}^{(\mathrm{glob})}
&=
0.60G_{1,1,1}-0.40G_{2,1,1}\\
&=
0.60(-1.00)-0.40(1.00)\\
&=
-0.60-0.40\\
&=
-1.00.
\end{aligned}
\]
Selanjutnya, nilai tersebut diaktifkan menggunakan fungsi Swish:
\[
\begin{aligned}
G_{\mathrm{global},1,1}
&=
\frac{F_{\mathrm{pw},1,1,1}^{(\mathrm{glob})}}
{1+e^{-F_{\mathrm{pw},1,1,1}^{(\mathrm{glob})}}}\\
&=
\frac{-1.00}{1+e^{-(-1.00)}}\\
&=
\frac{-1.00}{1+e^{1.00}}\\
&=
\frac{-1.00}{1+2.72}\\
&=
-0.27.
\end{aligned}
\]
Dengan perhitungan yang sama untuk seluruh posisi, diperoleh
feature map global:
\[
\mathbf{G}_{\mathrm{global}}=
\begin{bmatrix}
-0.27 & -0.27 & 0.73 & 0.73 & -0.27\\
-0.27 & -0.27 & 0.73 & 0.73 & -0.27\\
-0.27 & -0.27 & 0.73 & 0.73 & -0.27\\
-0.27 & -0.27 & 0.73 & 0.73 & -0.27\\
-0.27 & -0.27 & 0.73 & -0.27 & -0.27
\end{bmatrix}.
\]
c. Fusi Residual Fitur Lokal dan Global
Feature map masukan \(\mathbf{X}\), fitur lokal \(\mathbf{L}\), dan feature map
global \(\mathbf{G}_{\mathrm{global}}\)
digabungkan melalui fusi residual. Pada ilustrasi ini, pointwise
convolution \(1\times1\)
memproyeksikan fitur lokal dan fitur global menjadi satu kanal, kemudian
hasilnya ditambahkan dengan fitur masukan \(\mathbf{X}\).
\[
\mathbf{W}_{\mathrm{pw}}^{(\mathrm{fuse})}
=
\begin{bmatrix}
0.50 & 0.50
\end{bmatrix}.
\]
\[
F_{\mathrm{pw},i,j,1}^{(\mathrm{fuse})}
=
0.50L_{i,j}
+
0.50G_{\mathrm{global},i,j}.
\]
\[
X_{i,j}^{(0,0)}
=
X_{i,j}
+
F_{\mathrm{pw},i,j,1}^{(\mathrm{fuse})}.
\]
Secara keseluruhan, proses fusi residual dirumuskan sebagai:
\[
\mathbf{X}^{(0,0)}
=
\mathbf{X}
+
\operatorname{Conv}_{1\times1}^{(\mathrm{fuse})}
\left(
\operatorname{Concat}
\left[
\mathbf{L},
\mathbf{G}_{\mathrm{global}}
\right]
\right).
\]
Seluruh matriks pada operasi tersebut berdimensi \(5\times5\), sehingga hasil fusi \(\mathbf{X}^{(0,0)}\) juga berdimensi \(5\times5\).
- Contoh perhitungan pada posisi \((1,1)\):
Diketahui:
\[
X_{1,1}=-2.12,
\qquad
L_{1,1}=-0.27,
\qquad
G_{\mathrm{global},1,1}=-0.27.
\]
Nilai keluaran pointwise convolution adalah:
\[
\begin{aligned}
F_{\mathrm{pw},1,1,1}^{(\mathrm{fuse})}
&=
0.50L_{1,1}
+
0.50G_{\mathrm{global},1,1}\\
&=
0.50(-0.27)
+
0.50(-0.27)\\
&=
-0.135-0.135\\
&=
-0.27.
\end{aligned}
\]
Maka, hasil fusi residual pada posisi \((1,1)\) adalah:
\[
\begin{aligned}
X_{1,1}^{(0,0)}
&=
X_{1,1}
+
F_{\mathrm{pw},1,1,1}^{(\mathrm{fuse})}\\
&=
-2.12+(-0.27)\\
&=
-2.39.
\end{aligned}
\]
Aturan yang sama diterapkan pada seluruh posisi. Dengan menggunakan
nilai \(\mathbf{G}_{\mathrm{global}}\)
yang telah dibulatkan hingga dua angka di belakang koma, diperoleh
feature map hasil fusi berikut:
\[
\mathbf{X}^{(0,0)}
=
\begin{bmatrix}
-2.39 & -1.28 & 1.82 & 1.12 & -1.84\\
-2.38 & -1.00 & 2.24 & 1.50 & -1.70\\
-2.38 & -1.00 & 2.24 & 1.50 & -1.70\\
-2.38 & -1.14 & 1.84 & 1.11 & -1.85\\
-2.25 & -1.57 & 0.77 & -0.38 & -1.99
\end{bmatrix}.
\]
5. Encoder Bertingkat
a. Downsampling Encoder Pertama (\(\mathbf{X}^{1,0}\))
Feature map masukan \(\mathbf{X}^{0,0}\) berukuran \(5\times5\) diproses menggunakan strided
convolution dengan kernel \(3\times3\), stride \(2\), zero padding sebesar \(1\) pada setiap sisi, dan tanpa bias untuk
menghasilkan feature map \(\mathbf{X}^{1,0}\).
Matriks feature map masukan yang digunakan adalah:
\[
\mathbf{X}^{0,0}
=
\begin{bmatrix}
-2.39 & -1.28 & 1.82 & 1.12 & -1.84\\
-2.38 & -1.00 & 2.24 & 1.50 & -1.70\\
-2.38 & -1.00 & 2.24 & 1.50 & -1.70\\
-2.38 & -1.14 & 1.84 & 1.11 & -1.85\\
-2.25 & -1.57 & 0.77 & -0.38 & -1.99
\end{bmatrix}.
\]
Ukuran keluaran strided convolution 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\), \(k=3\), \(p=1\), dan \(s=2\), sehingga:
\[
\begin{aligned}
o
&=
\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 berkurang dari
\(5\times5\) menjadi \(3\times3\).
Sebelum operasi konvolusi dilakukan, satu lapisan nilai nol
ditambahkan pada keempat sisi matriks masukan, yaitu sisi atas, bawah,
kiri, dan kanan. Penambahan padding ini mengubah ukuran matriks
dari \(5\times5\) menjadi \(7\times7\).
Matriks setelah penambahan zero padding adalah:
\[
\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.39 & -1.28 & 1.82 & 1.12 & -1.84 &
0.00\\
0.00 & -2.38 & -1.00 & 2.24 & 1.50 & -1.70 &
0.00\\
0.00 & -2.38 & -1.00 & 2.24 & 1.50 & -1.70 &
0.00\\
0.00 & -2.38 & -1.14 & 1.84 & 1.11 & -1.85 &
0.00\\
0.00 & -2.25 & -1.57 & 0.77 & -0.38 & -1.99 &
0.00\\
0.00 & 0.00 & 0.00 & 0.00 & 0.00 & 0.00 & 0.00
\end{bmatrix}.
\]
Pada ilustrasi ini, matriks bobot kernel encoder pertama ditetapkan
sebagai:
\[
\mathbf{W}_{\mathrm{enc}}^{(1)}
=
\begin{bmatrix}
0.00 & 0.00 & 0.00\\
0.00 & 1.00 & 0.00\\
0.00 & 0.00 & 0.00
\end{bmatrix}.
\]
Kernel tersebut memiliki satu bobot bernilai \(1.00\) pada posisi tengah, sedangkan
delapan bobot lainnya bernilai \(0.00\). Oleh karena itu, setiap hasil
konvolusi diperoleh melalui perkalian sembilan elemen pada area
feature map dengan sembilan bobot kernel, kemudian seluruh
hasil perkalian dijumlahkan.
Operasi strided convolution dirumuskan sebagai:
\[
\mathbf{X}^{1,0}
=
\operatorname{Conv}_{3\times3,\,s=2,\,p=1}
\left(
\mathbf{X}^{0,0};
\mathbf{W}_{\mathrm{enc}}^{(1)}
\right).
\]
Untuk elemen keluaran pada baris ke-\(r\) dan kolom ke-\(c\), perhitungan konvolusi dapat dinyatakan
sebagai:
\[
X_{r,c}^{1,0}
=
\sum_{a=1}^{3}
\sum_{b=1}^{3}
W_{\mathrm{enc},a,b}^{(1)}
X_{\mathrm{pad},\,2r+a-2,\,2c+b-2}^{0,0},
\]
dengan \(r,c=1,2,3\), sedangkan
\(a\) dan \(b\) 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 \(\mathbf{X}^{1,0}\), kernel ditempatkan pada
area \(3\times3\) di pojok kiri atas
matriks yang telah diberi padding.
Area feature map yang diproses adalah:
\[
\begin{bmatrix}
0.00 & 0.00 & 0.00\\
0.00 & -2.39 & -1.28\\
0.00 & -2.38 & -1.00
\end{bmatrix}.
\]
Area tersebut dikalikan secara elemen demi elemen dengan bobot kernel
\(\mathbf{W}_{\mathrm{enc}}^{(1)}\),
kemudian hasilnya dijumlahkan sebagai berikut:
\[
\begin{aligned}
X_{1,1}^{1,0}
={}&
(0.00)(0.00)
+(0.00)(0.00)
+(0.00)(0.00)\\
&+(0.00)(0.00)
+(-2.39)(1.00)
+(-1.28)(0.00)\\
&+(0.00)(0.00)
+(-2.38)(0.00)
+(-1.00)(0.00)\\
={}&-2.39.
\end{aligned}
\]
Dengan demikian, elemen pertama pada feature map keluaran
adalah \(X_{1,1}^{1,0}=-2.39\).
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 adalah
\(2\).
Area feature map yang diproses menjadi:
\[
\begin{bmatrix}
0.00 & 0.00 & 0.00\\
-1.28 & 1.82 & 1.12\\
-1.00 & 2.24 & 1.50
\end{bmatrix}.
\]
Perhitungan konvolusi dilakukan menggunakan bobot kernel yang
sama:
\[
\begin{aligned}
X_{1,2}^{1,0}
={}&
(0.00)(0.00)
+(0.00)(0.00)
+(0.00)(0.00)\\
&+(-1.28)(0.00)
+(1.82)(1.00)
+(1.12)(0.00)\\
&+(-1.00)(0.00)
+(2.24)(0.00)
+(1.50)(0.00)\\
={}&1.82.
\end{aligned}
\]
Dengan demikian, elemen pada posisi \((1,2)\) dari feature map keluaran
adalah \(X_{1,2}^{1,0}=1.82\).
Prosedur yang sama diterapkan pada seluruh posisi kernel. Karena
hanya bobot tengah kernel yang bernilai \(1.00\), nilai keluaran pada setiap posisi
sama dengan nilai elemen tengah dari area feature map yang
sedang diproses. Hal tersebut merupakan konsekuensi dari bobot kernel
yang ditetapkan pada ilustrasi ini, bukan karakteristik umum dari
seluruh operasi konvolusi.
Setelah seluruh sembilan posisi konvolusi dihitung, diperoleh
feature map keluaran berukuran \(3\times3\) sebagai berikut:
\[
\mathbf{X}^{1,0}
=
\begin{bmatrix}
-2.39 & 1.82 & -1.84\\
-2.38 & 2.24 & -1.70\\
-2.25 & 0.77 & -1.99
\end{bmatrix}.
\]
Hasil tersebut menunjukkan bahwa operasi strided convolution
mengurangi ukuran spasial feature map dari \(5\times5\) menjadi \(3\times3\). Pada ilustrasi ini, nilai
keluaran ditentukan oleh elemen tengah pada setiap area konvolusi karena
bobot kernel lainnya bernilai nol.
b. Downsampling Encoder Kedua (\(\mathbf{X}^{2,0}\))
Feature map \(\mathbf{X}^{1,0}\) berukuran \(3\times3\) diproses kembali menggunakan
strided convolution dengan kernel \(3\times3\), stride \(2\), zero padding sebesar \(1\) pada setiap sisi, dan tanpa bias untuk
menghasilkan feature map \(\mathbf{X}^{2,0}\).
Matriks feature map masukan yang diperoleh dari tahap
downsampling encoder pertama adalah:
\[
\mathbf{X}^{1,0}
=
\begin{bmatrix}
-2.39 & 1.82 & -1.84\\
-2.38 & 2.24 & -1.70\\
-2.25 & 0.77 & -1.99
\end{bmatrix}.
\]
Ukuran keluaran strided convolution 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=3\), \(k=3\), \(p=1\), dan \(s=2\), sehingga:
\[
\begin{aligned}
o
&=
\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 berkurang dari
\(3\times3\) menjadi \(2\times2\).
Sebelum operasi konvolusi dilakukan, satu lapisan nilai nol
ditambahkan pada keempat sisi matriks masukan, yaitu sisi atas, bawah,
kiri, dan kanan. Penambahan padding ini mengubah ukuran matriks
dari \(3\times3\) menjadi \(5\times5\).
Matriks setelah penambahan zero padding adalah:
\[
\mathbf{X}_{\mathrm{pad}}^{1,0}
=
\begin{bmatrix}
0.00 & 0.00 & 0.00 & 0.00 & 0.00\\
0.00 & -2.39 & 1.82 & -1.84 & 0.00\\
0.00 & -2.38 & 2.24 & -1.70 & 0.00\\
0.00 & -2.25 & 0.77 & -1.99 & 0.00\\
0.00 & 0.00 & 0.00 & 0.00 & 0.00
\end{bmatrix}.
\]
Pada ilustrasi ini, matriks bobot kernel encoder kedua ditetapkan
sebagai:
\[
\mathbf{W}_{\mathrm{enc}}^{(2)}
=
\begin{bmatrix}
0.00 & 0.00 & 0.00\\
0.00 & 1.00 & 0.00\\
0.00 & 0.00 & 0.00
\end{bmatrix}.
\]
Kernel tersebut memiliki satu bobot bernilai \(1.00\) pada posisi tengah, sedangkan
delapan bobot lainnya bernilai \(0.00\). Oleh karena itu, setiap hasil
konvolusi diperoleh melalui perkalian sembilan elemen pada area
feature map dengan sembilan bobot kernel, kemudian seluruh
hasil perkalian dijumlahkan.
Operasi strided convolution pada encoder kedua dirumuskan
sebagai:
\[
\mathbf{X}^{2,0}
=
\operatorname{Conv}_{3\times3,\,s=2,\,p=1}
\left(
\mathbf{X}^{1,0};
\mathbf{W}_{\mathrm{enc}}^{(2)}
\right).
\]
Untuk elemen keluaran pada baris ke-\(r\) dan kolom ke-\(c\), perhitungan konvolusi dapat dinyatakan
sebagai:
\[
X_{r,c}^{2,0}
=
\sum_{a=1}^{3}
\sum_{b=1}^{3}
W_{\mathrm{enc},a,b}^{(2)}
X_{\mathrm{pad},\,2r+a-2,\,2c+b-2}^{1,0},
\]
dengan \(r,c=1,2\), sedangkan \(a\) dan \(b\) 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 \(\mathbf{X}^{2,0}\), kernel ditempatkan pada
area \(3\times3\) di pojok kiri atas
matriks yang telah diberi padding.
Area feature map yang diproses adalah:
\[
\begin{bmatrix}
0.00 & 0.00 & 0.00\\
0.00 & -2.39 & 1.82\\
0.00 & -2.38 & 2.24
\end{bmatrix}.
\]
Area tersebut dikalikan secara elemen demi elemen dengan bobot kernel
\(\mathbf{W}_{\mathrm{enc}}^{(2)}\),
kemudian seluruh hasil perkalian dijumlahkan sebagai berikut:
\[
\begin{aligned}
X_{1,1}^{2,0}
={}&
(0.00)(0.00)
+(0.00)(0.00)
+(0.00)(0.00)\\
&+(0.00)(0.00)
+(-2.39)(1.00)
+(1.82)(0.00)\\
&+(0.00)(0.00)
+(-2.38)(0.00)
+(2.24)(0.00)\\
={}&-2.39.
\end{aligned}
\]
Dengan demikian, elemen pertama pada feature map keluaran
adalah \(X_{1,1}^{2,0}=-2.39\).
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 adalah
\(2\).
Area feature map yang diproses menjadi:
\[
\begin{bmatrix}
0.00 & 0.00 & 0.00\\
1.82 & -1.84 & 0.00\\
2.24 & -1.70 & 0.00
\end{bmatrix}.
\]
Perhitungan konvolusi dilakukan menggunakan bobot kernel yang
sama:
\[
\begin{aligned}
X_{1,2}^{2,0}
={}&
(0.00)(0.00)
+(0.00)(0.00)
+(0.00)(0.00)\\
&+(1.82)(0.00)
+(-1.84)(1.00)
+(0.00)(0.00)\\
&+(2.24)(0.00)
+(-1.70)(0.00)
+(0.00)(0.00)\\
={}&-1.84.
\end{aligned}
\]
Dengan demikian, elemen pada posisi \((1,2)\) dari feature map keluaran
adalah \(X_{1,2}^{2,0}=-1.84\).
Prosedur yang sama diterapkan pada seluruh posisi kernel. Karena
hanya bobot tengah kernel yang bernilai \(1.00\), nilai keluaran pada setiap posisi
sama dengan nilai elemen tengah dari area feature map yang
sedang diproses. Hal tersebut merupakan konsekuensi dari bobot kernel
yang ditetapkan pada ilustrasi ini, bukan karakteristik umum dari
seluruh operasi konvolusi.
Setelah seluruh empat posisi konvolusi dihitung, diperoleh
feature map keluaran berukuran \(2\times2\) sebagai berikut:
\[
\mathbf{X}^{2,0}
=
\begin{bmatrix}
-2.39 & -1.84\\
-2.25 & -1.99
\end{bmatrix}.
\]
Hasil tersebut menunjukkan bahwa operasi strided convolution
pada encoder kedua mengurangi ukuran spasial feature map dari
\(3\times3\) menjadi \(2\times2\). Pada ilustrasi ini, nilai
keluaran ditentukan oleh elemen tengah pada setiap area konvolusi karena
bobot kernel lainnya bernilai nol.
6. Decoder UNet++
Pada tahap ini, decoder UNet++ mengembalikan resolusi
spasial feature map secara bertahap melalui operasi Upsampling.
Pada ilustrasi ini, \(\operatorname{Up}(\cdot)\) menyatakan
Upsampling menggunakan interpolasi bilinear. Operasi tersebut
memperbesar ukuran spasial feature map dengan menghitung nilai
pada posisi keluaran berdasarkan jarak terhadap elemen masukan di
sekitarnya.
Pada setiap node decoder, feature map hasil
Upsampling digabungkan dengan feature map dari jalur
encoder atau node decoder sebelumnya melalui
nested skip connection. Penggabungan dilakukan menggunakan
concatenation (Concat) pada dimensi kanal, kemudian
dilanjutkan dengan konvolusi \(1\times1\) dan fungsi aktivasi ReLU.
Untuk mempermudah ilustrasi perhitungan manual, operasi konvolusi
pada node decoder disederhanakan menjadi satu konvolusi \(1\times1\) tanpa bias. Bobot kernel
ditentukan secara ilustratif dan tidak merepresentasikan bobot hasil
pelatihan model. Penyederhanaan ini digunakan untuk menjelaskan
mekanisme penggabungan fitur, bukan keseluruhan blok konvolusi pada
implementasi UNet++.
Dengan demikian, pembentukan node decoder pada ilustrasi ini
dinyatakan sebagai:
\[
\begin{aligned}
\mathbf{X}^{1,1}
&=
\operatorname{ReLU}
\left(
\operatorname{Conv}_{1\times1}^{(1,1)}
\left(
\operatorname{Concat}
\left[
\mathbf{X}^{1,0},
\operatorname{Up}(\mathbf{X}^{2,0})
\right]
\right)
\right),\\[6pt]
\mathbf{X}^{0,1}
&=
\operatorname{ReLU}
\left(
\operatorname{Conv}_{1\times1}^{(0,1)}
\left(
\operatorname{Concat}
\left[
\mathbf{X}^{0,0},
\operatorname{Up}(\mathbf{X}^{1,0})
\right]
\right)
\right),\\[6pt]
\mathbf{X}^{0,2}
&=
\operatorname{ReLU}
\left(
\operatorname{Conv}_{1\times1}^{(0,2)}
\left(
\operatorname{Concat}
\left[
\mathbf{X}^{0,0},
\mathbf{X}^{0,1},
\operatorname{Up}(\mathbf{X}^{1,1})
\right]
\right)
\right).
\end{aligned}
\]
Pada node \(\mathbf{X}^{1,1}\) dan
\(\mathbf{X}^{0,1}\), masing-masing
kanal masukan diberi bobot ilustratif \(1.00\). Sementara itu, pada node \(\mathbf{X}^{0,2}\), tiga kanal masukan
diberi bobot ilustratif \(0.25\), \(0.50\), dan \(0.25\). Bobot tersebut digunakan untuk
mempertahankan mekanisme penggabungan fitur yang telah ditetapkan dalam
ilustrasi sebelumnya.
a. Upsampling \(\mathbf{X}^{2,0}\)
dan Node Decoder \(\mathbf{X}^{1,1}\)
Feature map \(\mathbf{X}^{2,0}\) berukuran \(2\times2\), yang diperoleh dari tahap
encoder sebelumnya, diperbesar menjadi \(3\times3\) menggunakan interpolasi
bilinear. Proses ini bertujuan untuk menyesuaikan ukuran spasial
feature map sehingga dapat digabungkan dengan feature
map \(\mathbf{X}^{1,0}\) dari
jalur encoder melalui nested skip connection.
Matriks feature map masukan adalah:
\[
\mathbf{X}^{2,0}
=
\begin{bmatrix}
-2.39 & -1.84\\
-2.25 & -1.99
\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.39-1.84}{2}\\
&=
-2.115\\
&
-2.12.
\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.39-1.84-2.25-1.99}{4}\\
&=
-2.1175\\
&
-2.12.
\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.39 & -2.12 & -1.84\\
-2.32 & -2.12 & -1.92\\
-2.25 & -2.12 & -1.99
\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)}=[1.00].
\]
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,1)\):
\[
\begin{aligned}
X_{1,1}^{1,1}
&=
\operatorname{ReLU}
\left(
W_{\mathrm{dec},1}^{(1,1)}X_{1,1}^{1,0}
+
W_{\mathrm{dec},2}^{(1,1)}
\left[
\operatorname{Up}
\left(
\mathbf{X}^{2,0}
\right)
\right]_{1,1}
\right)\\
&=
\operatorname{ReLU}
\left(
1.00(-2.39)+1.00(-2.39)
\right)\\
&=
\operatorname{ReLU}(-4.78)\\
&=
0.00.
\end{aligned}
\]
- Contoh perhitungan node decoder pada posisi tengah \((2,2)\):
\[
\begin{aligned}
X_{2,2}^{1,1}
&=
\operatorname{ReLU}
\left(
W_{\mathrm{dec},1}^{(1,1)}X_{2,2}^{1,0}
+
W_{\mathrm{dec},2}^{(1,1)}
\left[
\operatorname{Up}
\left(
\mathbf{X}^{2,0}
\right)
\right]_{2,2}
\right)\\
&=
\operatorname{ReLU}
\left(
1.00(2.24)+1.00(-2.12)
\right)\\
&=
\operatorname{ReLU}(0.12)\\
&=
0.12.
\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 & 0.00 & 0.00\\
0.00 & 0.12 & 0.00\\
0.00 & 0.00 & 0.00
\end{bmatrix}.
\]
Hasil tersebut menunjukkan bahwa feature map hasil
Upsampling dapat 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.39 & 1.82 & -1.84\\
-2.38 & 2.24 & -1.70\\
-2.25 & 0.77 & -1.99
\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.39+1.82}{2}\\
&=
-0.285\\
&\approx-0.29.
\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 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.39+1.82-2.38+2.24}{4}\\
&=
-0.1775\\
&\approx-0.18.
\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.39 & -0.29 & 1.82 & -0.01 & -1.84\\
-2.39 & -0.18 & 2.03 & 0.13 & -1.77\\
-2.38 & -0.07 & 2.24 & 0.27 & -1.70\\
-2.32 & -0.41 & 1.51 & -0.17 & -1.85\\
-2.25 & -0.74 & 0.77 & -0.61 & -1.99
\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 \((1,1)\):
\[
\begin{aligned}
X_{1,1}^{0,1}
&=
\operatorname{ReLU}
\left(
W_{\mathrm{dec},1}^{(0,1)}X_{1,1}^{0,0}
+
W_{\mathrm{dec},2}^{(0,1)}
\left[
\operatorname{Up}
\left(
\mathbf{X}^{1,0}
\right)
\right]_{1,1}
\right)\\
&=
\operatorname{ReLU}
\left(
1.00(-2.39)
+
1.00(-2.39)
\right)\\
&=
\operatorname{ReLU}(-4.78)\\
&=
0.00.
\end{aligned}
\]
- Contoh perhitungan node decoder pada posisi \((1,3)\):
\[
\begin{aligned}
X_{1,3}^{0,1}
&=
\operatorname{ReLU}
\left(
W_{\mathrm{dec},1}^{(0,1)}X_{1,3}^{0,0}
+
W_{\mathrm{dec},2}^{(0,1)}
\left[
\operatorname{Up}
\left(
\mathbf{X}^{1,0}
\right)
\right]_{1,3}
\right)\\
&=
\operatorname{ReLU}
\left(
1.00(1.82)
+
1.00(1.82)
\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.64 & 1.11 & 0.00\\
0.00 & 0.00 & 4.27 & 1.63 & 0.00\\
0.00 & 0.00 & 4.48 & 1.77 & 0.00\\
0.00 & 0.00 & 3.35 & 0.94 & 0.00\\
0.00 & 0.00 & 1.54 & 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 & 0.00 & 0.00\\
0.00 & 0.12 & 0.00\\
0.00 & 0.00 & 0.00
\end{bmatrix}.
\]
- Rumus interpolasi bilinear:
Interpolasi bilinear dilakukan menggunakan prinsip yang sama seperti
pada subbagian sebelumnya. Setiap 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,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,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{0.00+0.12}{2}\\
&=
0.06.
\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,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+0.00+0.00+0.12}{4}\\
&=
0.03.
\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.00 & 0.00 & 0.00 & 0.00\\
0.00 & 0.03 & 0.06 & 0.03 & 0.00\\
0.00 & 0.06 & 0.12 & 0.06 & 0.00\\
0.00 & 0.03 & 0.06 & 0.03 & 0.00\\
0.00 & 0.00 & 0.00 & 0.00 & 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:
\[
\mathbf{W}_{\mathrm{pw}}^{(0,2)}
=
\begin{bmatrix}
0.25 & 0.50 & 0.25
\end{bmatrix}.
\]
Bobot tersebut merupakan parameter ilustratif untuk menyederhanakan
perhitungan manual dan tidak merepresentasikan bobot hasil pelatihan
model.
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})\).
Dengan demikian, untuk setiap posisi spasial \((r,c)\), keluaran node decoder
dihitung sebagai:
\[
X_{r,c}^{0,2}
=
\operatorname{ReLU}
\left(
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}
\right).
\]
- Contoh perhitungan node decoder pada posisi \((1,1)\):
\[
\begin{aligned}
X_{1,1}^{0,2}
&=
\operatorname{ReLU}
\left(
0.25X_{1,1}^{0,0}
+
0.50X_{1,1}^{0,1}
+
0.25
\left[
\operatorname{Up}
\left(
\mathbf{X}^{1,1}
\right)
\right]_{1,1}
\right)\\
&=
\operatorname{ReLU}
\left(
0.25(-2.39)
+
0.50(0.00)
+
0.25(0.00)
\right)\\
&=
\operatorname{ReLU}(-0.60)\\
&=
0.00.
\end{aligned}
\]
- Contoh perhitungan node decoder pada posisi \((2,3)\):
\[
\begin{aligned}
X_{2,3}^{0,2}
&=
\operatorname{ReLU}
\left(
0.25X_{2,3}^{0,0}
+
0.50X_{2,3}^{0,1}
+
0.25
\left[
\operatorname{Up}
\left(
\mathbf{X}^{1,1}
\right)
\right]_{2,3}
\right)\\
&=
\operatorname{ReLU}
\left(
0.25(2.24)
+
0.50(4.27)
+
0.25(0.06)
\right)\\
&=
\operatorname{ReLU}
\left(
0.56+2.135+0.015
\right)\\
&=
\operatorname{ReLU}(2.71)\\
&=
2.71.
\end{aligned}
\]
Dengan menerapkan operasi yang sama pada seluruh posisi spasial dan
menampilkan hasil hingga dua angka desimal, diperoleh feature
map keluaran node decoder sebagai berikut:
\[
\mathbf{X}^{0,2}
=
\begin{bmatrix}
0.00 & 0.00 & 2.28 & 0.84 & 0.00\\
0.00 & 0.00 & 2.71 & 1.20 & 0.00\\
0.00 & 0.00 & 2.83 & 1.28 & 0.00\\
0.00 & 0.00 & 2.15 & 0.76 & 0.00\\
0.00 & 0.00 & 0.96 & 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.
LS0tDQp0aXRsZTogIklsdXN0cmFzaSBQZW1iZW50dWthbiBTZWdtZW50YXNpIFVOZXQrKyBkZW5nYW4gRW5jb2RlciBNb2JpbGVWaVR2MyBWMSINCg0KDQphdXRob3I6IHwNCiAgPGRpdiBzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyBmb250LXNpemU6IDE0cHg7IGNvbG9yOiAjNTU1NTU1OyBsaW5lLWhlaWdodDogMS42OyBtYXJnaW4tdG9wOiAxMHB4OyI+DQogIFNyaSBZdWxpYW5hICgxNDA3MjAyNTAwMykgPGJyPg0KDQogIFByb2dyYW0gU3R1ZGkgTWFnaXN0ZXIgU3RhdGlzdGlrYSBUZXJhcGFuIDxicj4NCiAgPC9kaXY+DQoNCg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgd29yZF9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUNCmNzczogc3R5bGUuY3NzDQotLS0NCg0KDQojIyAxLiBDaXRyYSBtYXN1a2FuIGdyb3VuZCB0cnV0aCBkYW4gbm9ybWFsaXNhc2kNCg0KUGFkYSBjaXRyYSBncmF5c2NhbGUsIHNldGlhcCBwaWtzZWwgbWVtaWxpa2kgc2F0dSBuaWxhaSBpbnRlbnNpdGFzIHlhbmcgbWVudW5qdWtrYW4gdGluZ2thdCBrZWNlcmFoYW4uIEFwYWJpbGEgbmlsYWkgaW50ZW5zaXRhcyB0ZWxhaCBkaW5vcm1hbGlzYXNpIGtlIHJlbnRhbmcgXChbMCwxXVwpLCBtYWthIG5pbGFpIDAgbWVudW5qdWtrYW4gcGlrc2VsIHBhbGluZyBnZWxhcCAoaGl0YW0pLCBuaWxhaSAxIG1lbnVuanVra2FuIHBpa3NlbCBwYWxpbmcgdGVyYW5nIChwdXRpaCksIHNlZGFuZ2thbiBuaWxhaSBkaSBhbnRhcmEgMCBkYW4gMSBtZW51bmp1a2thbiBncmFkYXNpIGFidS1hYnUuIFNlbWFraW4gbWVuZGVrYXRpIDAsIHBpa3NlbCBzZW1ha2luIGdlbGFwOyBzZW1ha2luIG1lbmRla2F0aSAxLCBwaWtzZWwgc2VtYWtpbiB0ZXJhbmcuICANCkRhbGFtIGlsdXN0cmFzaSBpbmksIG1hdHJpa3MgY2l0cmEgYXdhbCBtYXNpaCBtZW5nZ3VuYWthbiBza2FsYSBpbnRlbnNpdGFzIDAtMjU1LiBPbGVoIGthcmVuYSBpdHUsIG5pbGFpIDAgbWVyZXByZXNlbnRhc2lrYW4gaGl0YW0sIG5pbGFpIDI1NSBtZXJlcHJlc2VudGFzaWthbiBwdXRpaCwgZGFuIG5pbGFpIHNlcGVydGkgNjQsIDEyOCwgYXRhdSAxOTIgbWVudW5qdWtrYW4gdGluZ2thdCBhYnUtYWJ1IHlhbmcgYmVyYmVkYS4gRGltZW5zaSBtYXRyaWtzIGFkYWxhaCBcKDVcdGltZXM1XCkuIA0KDQojIyMgYS4gQ2l0cmEgTWFzdWthbg0KXFsNClxtYXRoYmZ7SX09XGJlZ2lue2JtYXRyaXh9DQowICYgNjQgJiAxOTIgJiAxNjAgJiAzMlxcDQowICYgODAgJiAyMDggJiAxNzYgJiA0MFxcDQowICYgODAgJiAyMDggJiAxNzYgJiA0MFxcDQowICYgNzIgJiAxOTIgJiAxNjAgJiAzMlxcDQo4ICYgNDggJiAxNDQgJiAxMTIgJiAyNA0KXGVuZHtibWF0cml4fQ0KXF0NCg0KIyMjIGIuIEdyb3VuZCB0cnV0aCBiaW5lciANCg0KXFsNClxtYXRoYmZ7TX09XGJlZ2lue2JtYXRyaXh9DQowICYgMCAmIDEgJiAxICYgMFxcDQowICYgMSAmIDEgJiAxICYgMFxcDQowICYgMSAmIDEgJiAxICYgMFxcDQowICYgMCAmIDEgJiAxICYgMFxcDQowICYgMCAmIDAgJiAwICYgMA0KXGVuZHtibWF0cml4fQ0KXF0NCg0KR3JvdW5kIHRydXRoIFwoXG1hdGhiZntNfVwpIGJlcmFkYSBkaSBhd2FsIHNlYmFnYWkgdGFyZ2V0IGV2YWx1YXNpIGRpbWFuYSBuaWxhaSAwIG1lcnVwYWthbiBsYXRhciBiZWxha2FuZyBkYW4gMSBtZXJ1cGFrYW4gd2lsYXlhaCBsZXNpLCBidWthbiBtYXN1a2FuIGVuY29kZXIuIA0KDQojIyMgYy4gTm9ybWFsaXNhc2kga2FuYWwNCg0KLSAqKk5vcm1hbGlzYXNpIHByZXRyYWluZWQgSW1hZ2VOZXQgZGl0ZXJhcGthbiBwZXIga2FuYWw6KioNCg0KXFsNClxtYXRoYmZ7WH1fUj1cZnJhY3tJX1IvMjU1LTAuNDg1fXswLjIyOX0sXHFxdWFkDQpcbWF0aGJme1h9X0c9XGZyYWN7SV9HLzI1NS0wLjQ1Nn17MC4yMjR9LFxxcXVhZA0KXG1hdGhiZntYfV9CPVxmcmFje0lfQi8yNTUtMC40MDZ9ezAuMjI1fS4NClxdDQoNCi0gKipDb250b2g6KioNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KXG1hdGhiZntYfV97MSwzfSY9XGZyYWN7KDE5Mi8yNTUtMC40ODUpfXswLjIyOX1cXA0KJj0xLjE3DQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpQYWRhIGlsdXN0cmFzaSBpbmkgbWVuZ2d1bmFrYW4gMSBrYW5hbCBqYWRpIHNldGlhcCBlbGVtZW4gZGloaXR1bmcgZGVuZ2FuIFwoWF97aSxqfT0oSV97aSxqfS8yNTUtMC40ODUpLzAuMjI5XCkuIEF0dXJhbiB5YW5nIHNhbWEgZGl0ZXJhcGthbiBwYWRhIHNlbHVydWggZWxlbWVuIG1hdHJpa3MgYmVyaWt1dC4NCg0KXFsNClxtYXRoYmZ7WH1fe1xtYXRocm17bm9ybX19PVxiZWdpbntibWF0cml4fQ0KLTIuMTIgJiAtMS4wMiAmIDEuMTcgJiAwLjYyICYgLTEuNTdcXA0KLTIuMTIgJiAtMC43NSAmIDEuNDQgJiAwLjkwICYgLTEuNDNcXA0KLTIuMTIgJiAtMC43NSAmIDEuNDQgJiAwLjkwICYgLTEuNDNcXA0KLTIuMTIgJiAtMC44OCAmIDEuMTcgJiAwLjYyICYgLTEuNTdcXA0KLTEuOTggJiAtMS4zMCAmIDAuMzUgJiAtMC4yMCAmIC0xLjcxDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KDQoNCg0KIyMgMi4gUmVwcmVzZW50YXNpIExva2FsDQoNClBhZGEgaWx1c3RyYXNpIGluaSwgbWF0cmlrcyBcKFxtYXRoYmZ7WH1cKSBiZXJ1a3VyYW4gXCg1XHRpbWVzNVwpIG1lcmVwcmVzZW50YXNpa2FuIHNhdHUga2FuYWwgZGFyaSAqZmVhdHVyZSBtYXAqIG1hc3VrYW4gYmxvayBcKFxtYXRoYmZ7Rn1eeygwKX1cKSB5YW5nIHRlbGFoIGRpbm9ybWFsaXNhc2kuIFBlbWJlbnR1a2FuIHJlcHJlc2VudGFzaSBsb2thbCBkaWF3YWxpIGRlbmdhbiBvcGVyYXNpICpkZXB0aHdpc2UgY29udm9sdXRpb24qIG1lbmdndW5ha2FuIGtlcm5lbCBcKDNcdGltZXMzXCksICpzdHJpZGUqIFwoMVwpLCBkYW4gKnplcm8gcGFkZGluZyogc2ViZXNhciBcKDFcKSBwYWRhIHNldGlhcCBzaXNpLiBIYXNpbG55YSBrZW11ZGlhbiBkaXByb3NlcyBtZWxhbHVpIGZ1bmdzaSBha3RpdmFzaSBTd2lzaC4gU2VsYW5qdXRueWEsIHByb3lla3NpICpwb2ludHdpc2UgY29udm9sdXRpb24qIFwoMVx0aW1lczFcKSBkaXRlcmFwa2FuIHBhZGEgKmZlYXR1cmUgbWFwKiBsb2thbCB5YW5nIGRpaGFzaWxrYW4uDQoNCiMjIyBhLiBEZXB0aHdpc2UgQ29udm9sdXRpb24NCg0KTWF0cmlrcyAqZmVhdHVyZSBtYXAqIG1hc3VrYW4geWFuZyBkaWd1bmFrYW4gYWRhbGFoOg0KDQpcWw0KXG1hdGhiZntYfQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQotMi4xMiAmIC0xLjAyICYgMS4xNyAmIDAuNjIgJiAtMS41N1xcDQotMi4xMiAmIC0wLjc1ICYgMS40NCAmIDAuOTAgJiAtMS40M1xcDQotMi4xMiAmIC0wLjc1ICYgMS40NCAmIDAuOTAgJiAtMS40M1xcDQotMi4xMiAmIC0wLjg4ICYgMS4xNyAmIDAuNjIgJiAtMS41N1xcDQotMS45OCAmIC0xLjMwICYgMC4zNSAmIC0wLjIwICYgLTEuNzENClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQotICoqUGVuYW1iYWhhbiBaZXJvIFBhZGRpbmc6KioNCg0KU2ViZWx1bSBvcGVyYXNpICpkZXB0aHdpc2UgY29udm9sdXRpb24qIGRpbGFrdWthbiwgc2F0dSBsYXBpc2FuIG5pbGFpIG5vbCBkaXRhbWJhaGthbiBwYWRhIGtlZW1wYXQgc2lzaSBtYXRyaWtzIG1hc3VrYW4sIHlhaXR1IHNpc2kgYXRhcywgYmF3YWgsIGtpcmksIGRhbiBrYW5hbi4gUGVuYW1iYWhhbiAqemVybyBwYWRkaW5nKiBiZXJ0dWp1YW4gbWVtcGVydGFoYW5rYW4gdWt1cmFuIHNwYXNpYWwgKmZlYXR1cmUgbWFwKiBzZXRlbGFoIG9wZXJhc2kga29udm9sdXNpLg0KDQpVa3VyYW4ga2VsdWFyYW4gZGloaXR1bmcgbWVuZ2d1bmFrYW46DQoNClxbDQpvDQo9DQpcbGVmdFxsZmxvb3INClxmcmFje2krMnAta317c30NClxyaWdodFxyZmxvb3IrMSwNClxdDQoNCmRlbmdhbiBcKGlcKSBtZW55YXRha2FuIHVrdXJhbiBzcGFzaWFsIG1hc3VrYW4sIFwocFwpIG1lcnVwYWthbiBqdW1sYWggKnBhZGRpbmcqIHBhZGEgc2V0aWFwIHNpc2ksIFwoa1wpIG1lcnVwYWthbiB1a3VyYW4ga2VybmVsLCBkYW4gXChzXCkgbWVydXBha2FuICpzdHJpZGUqLg0KDQpQYWRhIGlsdXN0cmFzaSBpbmkgZGlndW5ha2FuIFwoaT01XCksIFwocD0xXCksIFwoaz0zXCksIGRhbiBcKHM9MVwpLCBzZWhpbmdnYToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0Kbw0KJj0NClxsZWZ0XGxmbG9vcg0KXGZyYWN7NSsyKDEpLTN9ezF9DQpccmlnaHRccmZsb29yKzFcXA0KJj0NClxsZWZ0XGxmbG9vcg0KXGZyYWN7NH17MX0NClxyaWdodFxyZmxvb3IrMVxcDQomPTUuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gZGVtaWtpYW4sIHVrdXJhbiBzcGFzaWFsIGtlbHVhcmFuIHRldGFwIFwoNVx0aW1lczVcKS4gUGVuYW1iYWhhbiAqemVybyBwYWRkaW5nKiBtZW5ndWJhaCB1a3VyYW4gbWF0cmlrcyBtYXN1a2FuIHNlbWVudGFyYSBkYXJpIFwoNVx0aW1lczVcKSBtZW5qYWRpIFwoN1x0aW1lczdcKS4NCg0KTWF0cmlrcyBzZXRlbGFoIHBlbmFtYmFoYW4gKnplcm8gcGFkZGluZyogYWRhbGFoOg0KDQpcWw0KXG1hdGhiZntYfV97XG1hdGhybXtwYWR9fQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjAwICYgMC4wMCAmIDAuMDAgJiAwLjAwICYgMC4wMCAmIDAuMDAgJiAwLjAwXFwNCjAuMDAgJiAtMi4xMiAmIC0xLjAyICYgMS4xNyAmIDAuNjIgJiAtMS41NyAmIDAuMDBcXA0KMC4wMCAmIC0yLjEyICYgLTAuNzUgJiAxLjQ0ICYgMC45MCAmIC0xLjQzICYgMC4wMFxcDQowLjAwICYgLTIuMTIgJiAtMC43NSAmIDEuNDQgJiAwLjkwICYgLTEuNDMgJiAwLjAwXFwNCjAuMDAgJiAtMi4xMiAmIC0wLjg4ICYgMS4xNyAmIDAuNjIgJiAtMS41NyAmIDAuMDBcXA0KMC4wMCAmIC0xLjk4ICYgLTEuMzAgJiAwLjM1ICYgLTAuMjAgJiAtMS43MSAmIDAuMDBcXA0KMC4wMCAmIDAuMDAgJiAwLjAwICYgMC4wMCAmIDAuMDAgJiAwLjAwICYgMC4wMA0KXGVuZHtibWF0cml4fS4NClxdDQoNCi0gKipGaWx0ZXIgS2VybmVsOioqDQoNClBhZGEgaWx1c3RyYXNpIGluaSwgbWF0cmlrcyBib2JvdCBrZXJuZWwgKmRlcHRod2lzZSBjb252b2x1dGlvbiogZGl0ZXRhcGthbiBzZWJhZ2FpOg0KDQpcWw0KXG1hdGhiZntXfV97XG1hdGhybXtkd319DQo9DQpcYmVnaW57Ym1hdHJpeH0NCjAuMDAgJiAwLjEwICYgMC4wMFxcDQowLjEwICYgMC42MCAmIDAuMTBcXA0KMC4wMCAmIDAuMTAgJiAwLjAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KS2VybmVsIHRlcnNlYnV0IG1lbWlsaWtpIGJvYm90IHB1c2F0IHNlYmVzYXIgXCgwLjYwXCksIGVtcGF0IGJvYm90IHNlYmVzYXIgXCgwLjEwXCkgcGFkYSBwb3Npc2kgYXRhcywgYmF3YWgsIGtpcmksIGRhbiBrYW5hbiwgc2VydGEgZW1wYXQgYm9ib3Qgc3VkdXQgYmVybmlsYWkgXCgwLjAwXCkuDQoNClNldGlhcCBoYXNpbCBrb252b2x1c2kgZGlwZXJvbGVoIG1lbGFsdWkgcGVya2FsaWFuIHNlbWJpbGFuIGVsZW1lbiBwYWRhIGFyZWEgKmZlYXR1cmUgbWFwKiBkZW5nYW4gc2VtYmlsYW4gYm9ib3Qga2VybmVsIHlhbmcgYmVyc2VzdWFpYW4sIGtlbXVkaWFuIHNlbHVydWggaGFzaWwgcGVya2FsaWFuIGRpanVtbGFoa2FuLg0KDQotICoqUnVtdXM6KioNCg0KT3BlcmFzaSAqZGVwdGh3aXNlIGNvbnZvbHV0aW9uKiB1bnR1ayBzYXR1IGthbmFsIG1hc3VrYW4gZGlueWF0YWthbiBzZWJhZ2FpOg0KDQpcWw0KRl97XG1hdGhybXtkd30sayxsfQ0KPQ0KXHN1bV97dT0xfV57M30NClxzdW1fe3Y9MX1eezN9DQpXX3tcbWF0aHJte2R3fSx1LHZ9DQpYX3tcbWF0aHJte3BhZH0sayt1LTEsbCt2LTF9LA0KXF0NCg0KZGVuZ2FuIFwoayxsPTEsMixcbGRvdHMsNVwpLCBzZWRhbmdrYW4gXCh1XCkgZGFuIFwodlwpIG1lcnVwYWthbiBpbmRla3MgYmFyaXMgZGFuIGtvbG9tIGtlcm5lbC4NCg0KUGFkYSBzZXRpYXAgcG9zaXNpLCBrZXJuZWwgbWVuY2FrdXAgYXJlYSBiZXJ1a3VyYW4gXCgzXHRpbWVzM1wpLiBLYXJlbmEgKnN0cmlkZSogYmVybmlsYWkgXCgxXCksIGtlcm5lbCBiZXJnZXNlciBzYXR1IGtvbG9tIGtlIGthbmFuIHVudHVrIG1lbmdoaXR1bmcgZWxlbWVuIGJlcmlrdXRueWEgcGFkYSBiYXJpcyBrZWx1YXJhbiB5YW5nIHNhbWEuIFNldGVsYWggbWVuY2FwYWkgcG9zaXNpIHRlcmFraGlyIHBhZGEgYmFyaXMgdGVyc2VidXQsIGtlcm5lbCBrZW1iYWxpIGtlIHNpc2kga2lyaSBkYW4gYmVyZ2VzZXIgc2F0dSBiYXJpcyBrZSBiYXdhaC4NCg0KLSAqKkNvbnRvaCBQZXJoaXR1bmdhbiBLb252b2x1c2k6KioNCg0KKioxLiBQZXJoaXR1bmdhbiBlbGVtZW4gcGFkYSBwb3Npc2kgXCgoMSwxKVwpKioNCg0KVW50dWsgbWVuZ2hhc2lsa2FuIGVsZW1lbiBwZXJ0YW1hIGRhcmkgKmZlYXR1cmUgbWFwKiBrZWx1YXJhbiwga2VybmVsIGRpdGVtcGF0a2FuIHBhZGEgYXJlYSBcKDNcdGltZXMzXCkgZGkgcG9qb2sga2lyaSBhdGFzIG1hdHJpa3MgeWFuZyB0ZWxhaCBkaWJlcmkgKnplcm8gcGFkZGluZyouDQoNCkFyZWEgKmZlYXR1cmUgbWFwKiB5YW5nIGRpcHJvc2VzIGFkYWxhaDoNCg0KXFsNClxiZWdpbntibWF0cml4fQ0KMC4wMCAmIDAuMDAgJiAwLjAwXFwNCjAuMDAgJiAtMi4xMiAmIC0xLjAyXFwNCjAuMDAgJiAtMi4xMiAmIC0wLjc1DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KQXJlYSB0ZXJzZWJ1dCBkaWthbGlrYW4gc2VjYXJhIGVsZW1lbiBkZW1pIGVsZW1lbiBkZW5nYW4gYm9ib3Qga2VybmVsIFwoXG1hdGhiZntXfV97XG1hdGhybXtkd319XCksIGtlbXVkaWFuIHNlbHVydWggaGFzaWwgcGVya2FsaWFuIGRpanVtbGFoa2FuIHNlYmFnYWkgYmVyaWt1dDoNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KRl97XG1hdGhybXtkd30sMSwxfQ0KPXt9Jg0KKDAuMDApKDAuMDApDQorKDAuMDApKDAuMTApDQorKDAuMDApKDAuMDApXFwNCiYrKDAuMDApKDAuMTApDQorKC0yLjEyKSgwLjYwKQ0KKygtMS4wMikoMC4xMClcXA0KJisoMC4wMCkoMC4wMCkNCisoLTIuMTIpKDAuMTApDQorKC0wLjc1KSgwLjAwKVxcDQo9e30mDQotMS4yNzItMC4xMDItMC4yMTJcXA0KPXt9Ji0xLjU4Ni4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkhhc2lsIHBlcmthbGlhbiBiZXJkYXNhcmthbiBuaWxhaSBtYXN1a2FuIHlhbmcgZGl0YW1waWxrYW4gYWRhbGFoIFwoLTEuNTg2XCkuIFBhZGEgbWF0cmlrcyBpbHVzdHJhc2kgeWFuZyB0ZWxhaCBkaXN1c3VuIHNlYmVsdW1ueWEsIGVsZW1lbiBpbmkgdGVyY2F0YXQgc2ViZXNhciBcKC0xLjU4XCkuIE5pbGFpIHRlcnNlYnV0IGRpcGVydGFoYW5rYW4gc2VtZW50YXJhIGRhbiBha2FuIGRpdmFsaWRhc2kga2VtYmFsaSBiZXJzYW1hIHNlbHVydWggdGFoYXBhbiBwZXJoaXR1bmdhbi4NCg0KKioyLiBQZXJoaXR1bmdhbiBlbGVtZW4gcGFkYSBwb3Npc2kgXCgoMiwyKVwpKioNCg0KVW50dWsgbWVuZ2hpdHVuZyBlbGVtZW4gcGFkYSBwb3Npc2kgXCgoMiwyKVwpLCBrZXJuZWwgZGl0ZW1wYXRrYW4gcGFkYSBhcmVhIHlhbmcgZGltdWxhaSBkYXJpIGJhcmlzIGtlZHVhIGRhbiBrb2xvbSBrZWR1YSBtYXRyaWtzIHNldGVsYWggKnBhZGRpbmcqLiBQb3Npc2kgaW5pIGJlcmFkYSBzYXR1IGJhcmlzIGRpIGJhd2FoIGRhbiBzYXR1IGtvbG9tIGRpIGthbmFuIGRpYmFuZGluZ2thbiBwb3Npc2kgYXdhbC4NCg0KQXJlYSAqZmVhdHVyZSBtYXAqIHlhbmcgZGlwcm9zZXMgYWRhbGFoOg0KDQpcWw0KXGJlZ2lue2JtYXRyaXh9DQotMi4xMiAmIC0xLjAyICYgMS4xN1xcDQotMi4xMiAmIC0wLjc1ICYgMS40NFxcDQotMi4xMiAmIC0wLjc1ICYgMS40NA0KXGVuZHtibWF0cml4fS4NClxdDQoNClBlcmhpdHVuZ2FuIGtvbnZvbHVzaSBkaWxha3VrYW4gbWVuZ2d1bmFrYW4gYm9ib3Qga2VybmVsIHlhbmcgc2FtYToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KRl97XG1hdGhybXtkd30sMiwyfQ0KPXt9Jg0KKC0yLjEyKSgwLjAwKQ0KKygtMS4wMikoMC4xMCkNCisoMS4xNykoMC4wMClcXA0KJisoLTIuMTIpKDAuMTApDQorKC0wLjc1KSgwLjYwKQ0KKygxLjQ0KSgwLjEwKVxcDQomKygtMi4xMikoMC4wMCkNCisoLTAuNzUpKDAuMTApDQorKDEuNDQpKDAuMDApXFwNCj17fSYNCi0wLjEwMi0wLjIxMi0wLjQ1MFxcDQomKzAuMTQ0LTAuMDc1XFwNCj17fSYtMC42OTUuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpIYXNpbCBwZXJrYWxpYW4gYmVyZGFzYXJrYW4gbmlsYWkgbWFzdWthbiB5YW5nIGRpdGFtcGlsa2FuIGFkYWxhaCBcKC0wLjY5NVwpLiBQYWRhIG1hdHJpa3MgaWx1c3RyYXNpIHNlYmVsdW1ueWEsIGVsZW1lbiBpbmkgdGVyY2F0YXQgc2ViZXNhciBcKC0wLjY5XCkuIE5pbGFpIHRlcnNlYnV0IGp1Z2EgZGlwZXJ0YWhhbmthbiBzZW1lbnRhcmEgaGluZ2dhIHByb3NlcyB2YWxpZGFzaSBudW1lcmlrIGRpbGFrdWthbi4NCg0KUHJvc2VkdXIgeWFuZyBzYW1hIGRpdGVyYXBrYW4gcGFkYSBzZWx1cnVoIHBvc2lzaSBrZXJuZWwuIFBhZGEgc2V0aWFwIHBvc2lzaSwgZWxlbWVuLWVsZW1lbiBkYWxhbSBhcmVhIGtvbnZvbHVzaSBkaWthbGlrYW4gZGVuZ2FuIGJvYm90IGtlcm5lbCB5YW5nIGJlcnNlc3VhaWFuLCBrZW11ZGlhbiBzZWx1cnVoIGhhc2lsIHBlcmthbGlhbiBkaWp1bWxhaGthbiB1bnR1ayBtZW1iZW50dWsgc2F0dSBlbGVtZW4gKmZlYXR1cmUgbWFwKiBrZWx1YXJhbi4NCg0KTWF0cmlrcyBoYXNpbCAqZGVwdGh3aXNlIGNvbnZvbHV0aW9uKiB5YW5nIGRpZ3VuYWthbiBzZW1lbnRhcmEgZGFsYW0gaWx1c3RyYXNpIGluaSBhZGFsYWg6DQoNClxbDQpcbWF0aGJme0Z9X3tcbWF0aHJte2R3fX0NCj0NClxiZWdpbntibWF0cml4fQ0KLTEuNTggJiAtMC43OCAmIDAuODEgJiAwLjQyICYgLTEuMDJcXA0KLTEuNzcgJiAtMC42OSAmIDEuMTQgJiAwLjY5ICYgLTEuMDdcXA0KLTEuNzcgJiAtMC42OCAmIDEuMTQgJiAwLjY5ICYgLTEuMDdcXA0KLTEuNzcgJiAtMC44MyAmIDAuODUgJiAwLjQwICYgLTEuMTlcXA0KLTEuNTMgJiAtMS4wMyAmIDAuMTggJiAtMC4xOSAmIC0xLjIwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KTWF0cmlrcyB0ZXJzZWJ1dCBtZW1wZXJ0YWhhbmthbiBuaWxhaSBwYWRhIGlsdXN0cmFzaSBzZWJlbHVtbnlhIGRhbiBha2FuIGRpcGVyaWtzYSBrZW1iYWxpIG1lbGFsdWkgcGVyaGl0dW5nYW4gbnVtZXJpayB1bnR1ayBtZW1hc3Rpa2FuIGtvbnNpc3RlbnNpIHNlbHVydWggdGFoYXBhbi4NCg0KLSAqKkZ1bmdzaSBBa3RpdmFzaSBTd2lzaDoqKg0KDQpTZXRlbGFoIG9wZXJhc2kgKmRlcHRod2lzZSBjb252b2x1dGlvbiosIGZ1bmdzaSBha3RpdmFzaSBTd2lzaCBkaXRlcmFwa2FuIHNlY2FyYSBlbGVtZW4gZGVtaSBlbGVtZW4gcGFkYSAqZmVhdHVyZSBtYXAqIHlhbmcgZGloYXNpbGthbi4NCg0KUnVtdXMgZnVuZ3NpIGFrdGl2YXNpIFN3aXNoIGFkYWxhaDoNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KTF97aSxqfQ0KJj0NClxvcGVyYXRvcm5hbWV7U3dpc2h9DQpcbGVmdCgNCkZfe1xtYXRocm17ZHd9LGksan0NClxyaWdodClcXA0KJj0NClxmcmFje0Zfe1xtYXRocm17ZHd9LGksan19DQp7MStlXnstRl97XG1hdGhybXtkd30saSxqfX19Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KLSAqKkNvbnRvaCBQZXJoaXR1bmdhbjoqKg0KDQpVbnR1ayBlbGVtZW4gcGFkYSBwb3Npc2kgXCgoMSwxKVwpLCBuaWxhaSB5YW5nIGRpZ3VuYWthbiBzZXN1YWkgZGVuZ2FuIG1hdHJpa3MgaGFzaWwgKmRlcHRod2lzZSBjb252b2x1dGlvbiogcGFkYSBpbHVzdHJhc2kgc2ViZWx1bW55YSwgeWFpdHUgXCgtMS41OFwpLg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpMX3sxLDF9DQomPVxvcGVyYXRvcm5hbWV7U3dpc2h9KC0xLjU4KVxcDQomPVxmcmFjey0xLjU4fXsxK2Veey0oLTEuNTgpfX1cXA0KJj1cZnJhY3stMS41OH17MStlXnsxLjU4fX1cXA0KJj1cZnJhY3stMS41OH17MSs0Ljg1fVxcDQomPVxmcmFjey0xLjU4fXs1Ljg1fVxcDQomPS0wLjI3Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KQmVyZGFzYXJrYW4gcGVuZXJhcGFuIGZ1bmdzaSBha3RpdmFzaSBTd2lzaCBwYWRhIG1hdHJpa3MgaWx1c3RyYXNpIHNlYmVsdW1ueWEsIGRpcGVyb2xlaDoNCg0KXFsNClxtYXRoYmZ7TH0NCj0NClxiZWdpbntibWF0cml4fQ0KLTAuMjcgJiAtMC4yNSAmIDAuNTYgJiAwLjI2ICYgLTAuMjdcXA0KLTAuMjYgJiAtMC4yMyAmIDAuODcgJiAwLjQ2ICYgLTAuMjdcXA0KLTAuMjYgJiAtMC4yMyAmIDAuODcgJiAwLjQ2ICYgLTAuMjdcXA0KLTAuMjYgJiAtMC4yNSAmIDAuNjAgJiAwLjI0ICYgLTAuMjhcXA0KLTAuMjcgJiAtMC4yNyAmIDAuMTAgJiAtMC4wOSAmIC0wLjI4DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KTWF0cmlrcyBcKFxtYXRoYmZ7TH1cKSBtZXJ1cGFrYW4gcmVwcmVzZW50YXNpIGxva2FsIHNldGVsYWggcGVuZXJhcGFuIGZ1bmdzaSBha3RpdmFzaSBTd2lzaCBkYW4gZGlndW5ha2FuIHNlYmFnYWkgbWFzdWthbiBwYWRhIHRhaGFwIHByb3lla3NpICpwb2ludHdpc2UgY29udm9sdXRpb24qIGJlcmlrdXRueWEuIE5pbGFpIG1hdHJpa3MgaW5pIGRpcGVydGFoYW5rYW4gc2VzdWFpIGlsdXN0cmFzaSBzZWJlbHVtbnlhIGhpbmdnYSBkaWxha3VrYW4gdmFsaWRhc2kgbnVtZXJpayBzZWNhcmEgbWVueWVsdXJ1aC4NCg0KDQojIyMgYi4gUHJveWVrc2kgUG9pbnR3aXNlIENvbnZvbHV0aW9uIGRhbiBUb2tlbmlzYXNpDQoNCipGZWF0dXJlIG1hcCogbG9rYWwgXChcbWF0aGJme0x9XCkgbWVtaWxpa2kgZGltZW5zaSBcKDVcdGltZXM1XHRpbWVzMVwpLiBTZWxhbmp1dG55YSwgKnBvaW50d2lzZSBjb252b2x1dGlvbiogXCgxXHRpbWVzMVwpIGRpdGVyYXBrYW4gc2VjYXJhIGluZGVwZW5kZW4gcGFkYSBzZXRpYXAgcG9zaXNpIHNwYXNpYWwuIEJlcmJlZGEgZGVuZ2FuICpkZXB0aHdpc2UgY29udm9sdXRpb24qIFwoM1x0aW1lczNcKSwgb3BlcmFzaSBpbmkgdGlkYWsgbWVsaWJhdGthbiBwaWtzZWwgdGV0YW5nZ2EsIHRldGFwaSBtZW1wcm95ZWtzaWthbiBzYXR1IGthbmFsIG1hc3VrYW4gbWVuamFkaSBkdWEga2FuYWwga2VsdWFyYW4uDQoNClByb3lla3NpIHRlcnNlYnV0IG1lbmdoYXNpbGthbiB2ZWt0b3IgZml0dXIgYmVyZGltZW5zaSBkdWEgcGFkYSBzZXRpYXAgcG9zaXNpIHNwYXNpYWwgeWFuZyBzZWxhbmp1dG55YSBkaWd1bmFrYW4gc2ViYWdhaSAqZW1iZWRkaW5nKiB0b2tlbiB1bnR1ayBtYXN1a2FuIFRyYW5zZm9ybWVyLiBKdW1sYWggZHVhIGthbmFsIGRpZ3VuYWthbiBzZWJhZ2FpIHBlbnllZGVyaGFuYWFuIGlsdXN0cmFzaSBwZXJoaXR1bmdhbiBtYW51YWwgYWdhciBwZW1iZW50dWthbiB0b2tlbiBzZXJ0YSBvcGVyYXNpIFF1ZXJ5LCBLZXksIGRhbiBWYWx1ZSBkYXBhdCBkaXR1bmp1a2thbiBzZWNhcmEgZWtzcGxpc2l0LiBQYWRhIGltcGxlbWVudGFzaSBNb2JpbGVWaVR2My12MS1TIHNlYmVuYXJueWEsIGp1bWxhaCBrYW5hbCBkaXRlbnR1a2FuIGJlcmRhc2Fya2FuIGtvbmZpZ3VyYXNpIGFyc2l0ZWt0dXIuDQoNCi0gKipCb2JvdCAqcG9pbnR3aXNlIGNvbnZvbHV0aW9uKjoqKg0KDQpQYWRhIGlsdXN0cmFzaSBpbmksIG1hdHJpa3MgYm9ib3QgKnBvaW50d2lzZSBjb252b2x1dGlvbiogZGl0ZXRhcGthbiBzZWJhZ2FpOg0KDQpcWw0KXG1hdGhiZntXfV97XG1hdGhybXtwd319XnsoXG1hdGhybXt0b2t9KX0NCj0NClxiZWdpbntibWF0cml4fQ0KMS4wMCAmIC0wLjUwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KTWF0cmlrcyBib2JvdCBcKFxtYXRoYmZ7V31fe1xtYXRocm17cHd9fV57KFxtYXRocm17dG9rfSl9XCkgYmVyZGltZW5zaSBcKDFcdGltZXMyXCksIHNlaGluZ2dhIHNldGlhcCBuaWxhaSBwYWRhICpmZWF0dXJlIG1hcCogbG9rYWwgZGlwcm95ZWtzaWthbiBtZW5qYWRpIHZla3RvciBkZW5nYW4gZHVhIGVsZW1lbi4NCg0KLSAqKlJ1bXVzOioqDQoNClVudHVrIHNldGlhcCBwb3Npc2kgc3Bhc2lhbCBcKChpLGopXCksIGVsZW1lbiBrZS1cKG5cKSBkYXJpIHRva2VuIGtlLVwodFwpIGRpaGl0dW5nIG1lbmdndW5ha2FuOg0KDQpcWw0KVF97dCxufQ0KPQ0KXHN1bV97bT0xfV57Q19MfQ0KV197XG1hdGhybXtwd30sbSxufV57KFxtYXRocm17dG9rfSl9DQpMX3tpLGosbX0sDQpccXF1YWQNCnQ9NShpLTEpK2ouDQpcXQ0KDQpQYWRhIGlsdXN0cmFzaSBpbmksIFwoQ19MPTFcKSBkYW4gXChuPTEsMlwpLiBEZW5nYW4gZGVtaWtpYW4sIHBlcnNhbWFhbiB0ZXJzZWJ1dCBkYXBhdCBkaXNlZGVyaGFuYWthbiBtZW5qYWRpOg0KDQpcWw0KXG1hdGhiZntUfV90DQo9DQpMX3tpLGp9DQpcbWF0aGJme1d9X3tcbWF0aHJte3B3fX1eeyhcbWF0aHJte3Rva30pfS4NClxdDQoNCkRlbmdhbiBib2JvdCB5YW5nIGRpZ3VuYWthbiwga2FuYWwga2VsdWFyYW4gcGVydGFtYSBtZW1wZXJ0YWhhbmthbiBuaWxhaSBha3RpdmFzaSBsb2thbCwgc2VkYW5na2FuIGthbmFsIGtlZHVhIGJlcm5pbGFpIFwoLTAuNTBcKSBrYWxpIGFrdGl2YXNpIGxva2FsLiBIYXNpbCBwcm95ZWtzaSBtZW1iZW50dWsgKmZlYXR1cmUgbWFwKiBiZXJkaW1lbnNpIFwoMjVcdGltZXMyXCkuDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gcGFkYSBwb3Npc2kgXCgoMSwxKVwpOioqDQoNCkRpa2V0YWh1aSBcKExfezEsMX09LTAuMjdcKSwgc2VoaW5nZ2E6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClxtYXRoYmZ7VH1fMQ0KJj0NCkxfezEsMX0NClxtYXRoYmZ7V31fe1xtYXRocm17cHd9fV57KFxtYXRocm17dG9rfSl9XFwNCiY9DQooLTAuMjcpDQpcYmVnaW57Ym1hdHJpeH0NCjEuMDAgJiAtMC41MA0KXGVuZHtibWF0cml4fVxcDQomPQ0KXGJlZ2lue2JtYXRyaXh9DQooLTAuMjcpKDEuMDApICYgKC0wLjI3KSgtMC41MCkNClxlbmR7Ym1hdHJpeH1cXA0KJj0NClxiZWdpbntibWF0cml4fQ0KLTAuMjcgJiAwLjEzNQ0KXGVuZHtibWF0cml4fVxcDQomPQ0KXGJlZ2lue2JtYXRyaXh9DQotMC4yNyAmIDAuMTQNClxlbmR7Ym1hdHJpeH0uDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpQb3Npc2kgc3Bhc2lhbCBcKCgxLDEpXCkgbWVydXBha2FuIHRva2VuIHBlcnRhbWEgYmVyZGFzYXJrYW46DQoNClxbDQp0PTUoMS0xKSsxPTEuDQpcXQ0KDQotICoqVG9rZW5pc2FzaToqKg0KDQpTZXRlbGFoIHByb3lla3NpICpwb2ludHdpc2UgY29udm9sdXRpb24qLCB2ZWt0b3IgZHVhIGthbmFsIHBhZGEgc2V0aWFwIHBvc2lzaSBzcGFzaWFsIGRpc3VzdW4gbWVuamFkaSB1cnV0YW4gdG9rZW4gbWVuZ2d1bmFrYW4gdXJ1dGFuIHJhc3RlciwgeWFpdHUgZGFyaSBraXJpIGtlIGthbmFuIGRhbiBkYXJpIGF0YXMga2UgYmF3YWguIEluZGVrcyB0b2tlbiBkaXRlbnR1a2FuIG9sZWg6DQoNClxbDQp0PTUoaS0xKStqLg0KXF0NCg0KU2ViYWdhaSBjb250b2gsIHBvc2lzaSBzcGFzaWFsIFwoKDEsMSlcKSwgXCgoMSwzKVwpLCBcKCgyLDEpXCksIGRhbiBcKCg1LDUpXCkgbWFzaW5nLW1hc2luZyBiZXJrb3Jlc3BvbmRlbnNpIGRlbmdhbiB0b2tlbiBrZS0xLCBrZS0zLCBrZS02LCBkYW4ga2UtMjUuDQoNClNldGlhcCB2ZWt0b3IgdG9rZW4gZGlueWF0YWthbiBzZWJhZ2FpOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcbWF0aGJme1R9X3QNCiY9DQpMX3tpLGosMX0NClxtYXRoYmZ7V31fe1xtYXRocm17cHd9fV57KFxtYXRocm17dG9rfSl9XFwNCiY9DQpcYmVnaW57Ym1hdHJpeH0NCkxfe2ksaiwxfSAmIC0wLjUwTF97aSxqLDF9DQpcZW5ke2JtYXRyaXh9Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KVmVrdG9yIHRva2VuIFwoXG1hdGhiZntUfV90XCkgYmVyZGltZW5zaSBcKDFcdGltZXMyXCkuIERlbmdhbiBtZW55dXN1biBzZWx1cnVoIDI1IHZla3RvciB0b2tlbiBiZXJkYXNhcmthbiB1cnV0YW4gcmFzdGVyLCBkaXBlcm9sZWggbWF0cmlrcyBcKFxtYXRoYmZ7VH1cKSBiZXJkaW1lbnNpIFwoMjVcdGltZXMyXCk6DQoNClxbDQpcbWF0aGJme1R9DQo9DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjI3ICYgMC4xM1xcDQotMC4yNSAmIDAuMTJcXA0KMC41NiAmIC0wLjI4XFwNCjAuMjYgJiAtMC4xM1xcDQotMC4yNyAmIDAuMTRcXA0KLTAuMjYgJiAwLjEzXFwNCi0wLjIzICYgMC4xMlxcDQowLjg3ICYgLTAuNDNcXA0KMC40NiAmIC0wLjIzXFwNCi0wLjI3ICYgMC4xNFxcDQotMC4yNiAmIDAuMTNcXA0KLTAuMjMgJiAwLjExXFwNCjAuODcgJiAtMC40M1xcDQowLjQ2ICYgLTAuMjNcXA0KLTAuMjcgJiAwLjE0XFwNCi0wLjI2ICYgMC4xM1xcDQotMC4yNSAmIDAuMTNcXA0KMC42MCAmIC0wLjMwXFwNCjAuMjQgJiAtMC4xMlxcDQotMC4yOCAmIDAuMTRcXA0KLTAuMjcgJiAwLjE0XFwNCi0wLjI3ICYgMC4xNFxcDQowLjEwICYgLTAuMDVcXA0KLTAuMDkgJiAwLjA0XFwNCi0wLjI4ICYgMC4xNA0KXGVuZHtibWF0cml4fS4NClxdDQoNCg0KDQojIyAzLiBUcmFuc2Zvcm1lciBNb2JpbGVWaVR2My12MS1TIChTZWxmLUF0dGVudGlvbikNCg0KIyMjIGEuIE5vcm1hbGlzYXNpIFRva2VuDQoNClNlYmVsdW0gbWVtYXN1a2kgbWVrYW5pc21lICpzZWxmLWF0dGVudGlvbiosIHNldGlhcCB0b2tlbiBwYWRhIG1hdHJpa3MgXChcbWF0aGJme1R9XCkgZGlub3JtYWxpc2FzaSBtZW5nZ3VuYWthbiAqTGF5ZXIgTm9ybWFsaXphdGlvbiogKExOKS4gTm9ybWFsaXNhc2kgZGlsYWt1a2FuIHNlY2FyYSBpbmRlcGVuZGVuIHBhZGEgc2V0aWFwIHRva2VuLCBzZWhpbmdnYSByYXRhLXJhdGEgZGFuIHZhcmlhbnMgZGloaXR1bmcgYmVyZGFzYXJrYW4gZHVhIGVsZW1lbiBmaXR1ciBwYWRhIHRva2VuIHlhbmcgc2FtYS4NCg0KLSAqKlJ1bXVzOioqDQoNClVudHVrIHRva2VuIGtlLVwodFwpLCByYXRhLXJhdGEgZGFuIHZhcmlhbnMgZGloaXR1bmcgc2ViYWdhaToNCg0KXFsNClxtdV90DQo9DQpcZnJhY3sxfXsyfVxzdW1fe2s9MX1eezJ9VF97dCxrfSwNClxxcXVhZA0KXHNpZ21hX3ReMg0KPQ0KXGZyYWN7MX17Mn1cc3VtX3trPTF9XnsyfShUX3t0LGt9LVxtdV90KV4yLg0KXF0NCg0KU2VsYW5qdXRueWEsIGVsZW1lbiBrZS1cKGtcKSBwYWRhIHRva2VuIGtlLVwodFwpIGRpbm9ybWFsaXNhc2kgbWVuZ2d1bmFrYW46DQoNClxbDQpbXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntUfSldX3t0LGt9DQo9DQpcZnJhY3tUX3t0LGt9LVxtdV90fQ0Ke1xzcXJ0e1xzaWdtYV90XjIrXHZhcmVwc2lsb259fSwNClxxcXVhZA0KXHZhcmVwc2lsb249MTBeey01fS4NClxdDQoNCk1hdHJpa3MgdG9rZW4gXChcbWF0aGJme1R9XCkgYmVyZGltZW5zaSBcKDI1XHRpbWVzMlwpLCBzZWhpbmdnYSBtYXRyaWtzIGhhc2lsIG5vcm1hbGlzYXNpIFwoXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntUfSlcKSBqdWdhIGJlcmRpbWVuc2kgXCgyNVx0aW1lczJcKS4NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiB1bnR1ayB0b2tlbiBwZXJ0YW1hOioqDQoNCkRpa2V0YWh1aSB2ZWt0b3IgdG9rZW4gcGVydGFtYSBhZGFsYWg6DQoNClxbDQpcbWF0aGJme1R9XzENCj0NClxiZWdpbntibWF0cml4fQ0KLTAuMjcgJiAwLjEzDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KUmF0YS1yYXRhIHRva2VuIHBlcnRhbWEgZGloaXR1bmcgc2ViYWdhaToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KXG11XzENCiY9XGZyYWN7VF97MSwxfStUX3sxLDJ9fXsyfVxcDQomPVxmcmFjey0wLjI3KzAuMTN9ezJ9XFwNCiY9XGZyYWN7LTAuMTR9ezJ9XFwNCiY9LTAuMDcuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpWYXJpYW5zIHRva2VuIHBlcnRhbWEgZGlwZXJvbGVoOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcc2lnbWFfMV4yDQomPVxmcmFjeyhUX3sxLDF9LVxtdV8xKV4yKyhUX3sxLDJ9LVxtdV8xKV4yfXsyfVxcDQomPVxmcmFjeygtMC4yNy0oLTAuMDcpKV4yKygwLjEzLSgtMC4wNykpXjJ9ezJ9XFwNCiY9XGZyYWN7KC0wLjIwKV4yKygwLjIwKV4yfXsyfVxcDQomPVxmcmFjezAuMDQrMC4wNH17Mn1cXA0KJj0wLjA0Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KU2VsYW5qdXRueWEsIGVsZW1lbiBwZXJ0YW1hIHRva2VuIGRpbm9ybWFsaXNhc2kgc2ViYWdhaToNCg0KDQoNCg0KJCQNClxiZWdpbnthbGlnbmVkfQ0KXGxlZnRbXG1hdGhybXtMTn0oXG1hdGhiZntUfSlccmlnaHRdX3sxLDF9DQomPSBcZnJhY3tUX3sxLDF9LVxtdV8xfXtcc3FydHtcc2lnbWFfMV4yK1x2YXJlcHNpbG9ufX1cXA0KJj0gXGZyYWN7LTAuMjctKC0wLjA3KX17XHNxcnR7MC4wNCsxMF57LTV9fX1cXA0KJj0gXGZyYWN7LTAuMjB9e1xzcXJ0ezAuMDQrMTBeey01fX19XFwNCiY9IFxmcmFjey0wLjIwfXswLjIwfVxcDQomPSAtMS4wMA0KXGVuZHthbGlnbmVkfQ0KJCQNCg0KRGVuZ2FuIHBlcmhpdHVuZ2FuIHlhbmcgc2FtYSwgZWxlbWVuIGtlZHVhIHRva2VuIHBlcnRhbWEgZGlwZXJvbGVoOg0KDQpcWw0KW1xvcGVyYXRvcm5hbWV7TE59KFxtYXRoYmZ7VH0pXV97MSwyfQ0KPTEuMDAuDQpcXQ0KDQpEZW5nYW4gZGVtaWtpYW4sIGhhc2lsIG5vcm1hbGlzYXNpIHRva2VuIHBlcnRhbWEgYWRhbGFoOg0KDQpcWw0KW1xvcGVyYXRvcm5hbWV7TE59KFxtYXRoYmZ7VH0pXV97MX0NCj0NClxiZWdpbntibWF0cml4fQ0KLTEuMDAgJiAxLjAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KUHJvc2VzIG5vcm1hbGlzYXNpIHlhbmcgc2FtYSBkaXRlcmFwa2FuIHBhZGEgc2VsdXJ1aCB0b2tlbiwgc2VoaW5nZ2EgZGlwZXJvbGVoIG1hdHJpa3MgdG9rZW4gdGVybm9ybWFsaXNhc2kgYmVydWt1cmFuIFwoMjVcdGltZXMyXCkgc2ViYWdhaSBiZXJpa3V0Og0KDQpcWw0KXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntUfSkNCj0NClxiZWdpbntibWF0cml4fQ0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMFxcDQoxLjAwICYgLTEuMDBcXA0KMS4wMCAmIC0xLjAwXFwNCi0xLjAwICYgMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCjEuMDAgJiAtMS4wMFxcDQoxLjAwICYgLTEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KMS4wMCAmIC0xLjAwXFwNCjEuMDAgJiAtMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMFxcDQoxLjAwICYgLTEuMDBcXA0KMS4wMCAmIC0xLjAwXFwNCi0xLjAwICYgMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMFxcDQoxLjAwICYgLTEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMA0KXGVuZHtibWF0cml4fS4NClxdDQoNCg0KDQojIyMgYi4gUHJveWVrc2kgUXVlcnkNCg0KU2V0ZWxhaCB0b2tlbiBkaW5vcm1hbGlzYXNpLCBzZXRpYXAgdG9rZW4gZGlwcm95ZWtzaWthbiBtZW5qYWRpICpRdWVyeSogKFEpLiBRdWVyeSBtZXJlcHJlc2VudGFzaWthbiBpbmZvcm1hc2kgeWFuZyBkaWNhcmkgb2xlaCBzZXRpYXAgdG9rZW4ga2V0aWthIG1lbmdoaXR1bmcgaHVidW5nYW4gZGVuZ2FuIHRva2VuLXRva2VuIGxhaW4gbWVsYWx1aSBtZWthbmlzbWUgKnNlbGYtYXR0ZW50aW9uKi4NCg0KLSAqKkJvYm90IFF1ZXJ5OioqDQoNClBhZGEgaWx1c3RyYXNpIGluaSwgbWF0cmlrcyBib2JvdCBwcm95ZWtzaSBRdWVyeSBkaXRldGFwa2FuIHNlYmFnYWk6DQoNClxbDQpcbWF0aGJme1d9X1ENCj0NCjAuNTBcbWF0aGJme0l9DQo9DQpcYmVnaW57Ym1hdHJpeH0NCjAuNTAgJiAwLjAwXFwNCjAuMDAgJiAwLjUwDQpcZW5ke2JtYXRyaXh9LA0KXF0NCg0KZGVuZ2FuIFwoXG1hdGhiZntJfVwpIG1lcnVwYWthbiBtYXRyaWtzIGlkZW50aXRhcyBiZXJ1a3VyYW4gXCgyXHRpbWVzMlwpLiBCb2JvdCB0ZXJzZWJ1dCBtZW5nYWxpa2FuIHNldGlhcCBlbGVtZW4gdG9rZW4gdGVybm9ybWFsaXNhc2kgZGVuZ2FuIFwoMC41MFwpLCB0YW5wYSBtZW5jYW1wdXJrYW4gaW5mb3JtYXNpIGFudGFyYSBrZWR1YSBrYW5hbCBmaXR1ci4NCg0KLSAqKlJ1bXVzOioqDQoNClByb3lla3NpIFF1ZXJ5IGRpcnVtdXNrYW4gc2ViYWdhaToNCg0KXFsNClxtYXRoYmZ7UX0NCj0NClxvcGVyYXRvcm5hbWV7TE59KFxtYXRoYmZ7VH0pXG1hdGhiZntXfV9RLg0KXF0NCg0KVW50dWsgdG9rZW4ga2UtXCh0XCksIHBlcnNhbWFhbiB0ZXJzZWJ1dCBkYXBhdCBkaXR1bGlza2FuIHNlYmFnYWk6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClxtYXRoYmZ7UX1fdA0KJj0NCltcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1R9KV1fe3R9XG1hdGhiZntXfV9RXFwNCiY9DQpcYmVnaW57Ym1hdHJpeH0NCltcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1R9KV1fe3QsMX0gJg0KW1xvcGVyYXRvcm5hbWV7TE59KFxtYXRoYmZ7VH0pXV97dCwyfQ0KXGVuZHtibWF0cml4fQ0KXGJlZ2lue2JtYXRyaXh9DQowLjUwICYgMC4wMFxcDQowLjAwICYgMC41MA0KXGVuZHtibWF0cml4fS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCk1hdHJpa3MgaGFzaWwgbm9ybWFsaXNhc2kgXChcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1R9KVwpIGJlcnVrdXJhbiBcKDI1XHRpbWVzMlwpLCBzZWRhbmdrYW4gbWF0cmlrcyBib2JvdCBcKFxtYXRoYmZ7V31fUVwpIGJlcnVrdXJhbiBcKDJcdGltZXMyXCkuIERlbmdhbiBkZW1pa2lhbiwgbWF0cmlrcyBRdWVyeSBcKFxtYXRoYmZ7UX1cKSBiZXJ1a3VyYW4gXCgyNVx0aW1lczJcKS4NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiB1bnR1ayB0b2tlbiBwZXJ0YW1hOioqDQoNCkJlcmRhc2Fya2FuIHRhaGFwIG5vcm1hbGlzYXNpIHRva2VuIHNlYmVsdW1ueWEsIGhhc2lsIG5vcm1hbGlzYXNpIHRva2VuIHBlcnRhbWEgeWFuZyBkaXRhbXBpbGthbiBkZW5nYW4gZHVhIGFuZ2thIGRlc2ltYWwgYWRhbGFoOg0KDQpcWw0KW1xvcGVyYXRvcm5hbWV7TE59KFxtYXRoYmZ7VH0pXV97MX0NCj0NClxiZWdpbntibWF0cml4fQ0KLTEuMDAgJiAxLjAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KU2VsYW5qdXRueWEsIFF1ZXJ5IHVudHVrIHRva2VuIHBlcnRhbWEgZGloaXR1bmcgc2ViYWdhaToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KXG1hdGhiZntRfV8xDQomPQ0KW1xvcGVyYXRvcm5hbWV7TE59KFxtYXRoYmZ7VH0pXV97MX1cbWF0aGJme1d9X1FcXA0KJj0NClxiZWdpbntibWF0cml4fQ0KLTEuMDAgJiAxLjAwDQpcZW5ke2JtYXRyaXh9DQpcYmVnaW57Ym1hdHJpeH0NCjAuNTAgJiAwLjAwXFwNCjAuMDAgJiAwLjUwDQpcZW5ke2JtYXRyaXh9XFwNCiY9DQpcYmVnaW57Ym1hdHJpeH0NCigtMS4wMCkoMC41MCkrKDEuMDApKDAuMDApICYNCigtMS4wMCkoMC4wMCkrKDEuMDApKDAuNTApDQpcZW5ke2JtYXRyaXh9XFwNCiY9DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjUwICYgMC41MA0KXGVuZHtibWF0cml4fS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBkZW1pa2lhbiwgZWxlbWVuIFF1ZXJ5IHVudHVrIHRva2VuIHBlcnRhbWEgYWRhbGFoOg0KDQpcWw0KUV97MSwxfT0tMC41MCwNClxxcXVhZA0KUV97MSwyfT0wLjUwLg0KXF0NCg0KUHJvc2VzIHByb3lla3NpIHlhbmcgc2FtYSBkaXRlcmFwa2FuIHBhZGEgc2VsdXJ1aCB0b2tlbi4gRGVuZ2FuIG1lbmFtcGlsa2FuIGhhc2lsIGhpbmdnYSBkdWEgYW5na2EgZGVzaW1hbCwgZGlwZXJvbGVoIG1hdHJpa3MgUXVlcnkgYmVydWt1cmFuIFwoMjVcdGltZXMyXCkgc2ViYWdhaSBiZXJpa3V0Og0KDQpcWw0KXG1hdGhiZntRfQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQotMC41MCAmIDAuNTBcXA0KLTAuNTAgJiAwLjUwXFwNCjAuNTAgJiAtMC41MFxcDQowLjUwICYgLTAuNTBcXA0KLTAuNTAgJiAwLjUwXFwNCi0wLjUwICYgMC41MFxcDQotMC41MCAmIDAuNTBcXA0KMC41MCAmIC0wLjUwXFwNCjAuNTAgJiAtMC41MFxcDQotMC41MCAmIDAuNTBcXA0KLTAuNTAgJiAwLjUwXFwNCi0wLjUwICYgMC41MFxcDQowLjUwICYgLTAuNTBcXA0KMC41MCAmIC0wLjUwXFwNCi0wLjUwICYgMC41MFxcDQotMC41MCAmIDAuNTBcXA0KLTAuNTAgJiAwLjUwXFwNCjAuNTAgJiAtMC41MFxcDQowLjUwICYgLTAuNTBcXA0KLTAuNTAgJiAwLjUwXFwNCi0wLjUwICYgMC41MFxcDQotMC41MCAmIDAuNTBcXA0KMC41MCAmIC0wLjUwXFwNCi0wLjUwICYgMC41MFxcDQotMC41MCAmIDAuNTANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQoNCg0KIyMjIGMuIFByb3lla3NpIEtleQ0KDQpTZXRlbGFoIHRva2VuIGRpbm9ybWFsaXNhc2ksIHNldGlhcCB0b2tlbiBqdWdhIGRpcHJveWVrc2lrYW4gbWVuamFkaSAqS2V5KiAoSykuIFBhZGEgbWVrYW5pc21lICpzZWxmLWF0dGVudGlvbiosIEtleSBiZXJmdW5nc2kgc2ViYWdhaSByZXByZXNlbnRhc2kgcGVtYmFuZGluZy4gU2V0aWFwIFF1ZXJ5IGRpYmFuZGluZ2thbiBkZW5nYW4gc2VsdXJ1aCBLZXkgdW50dWsgbWVuZW50dWthbiB0aW5na2F0IGtldGVya2FpdGFuIGFudGFydG9rZW4uDQoNCi0gKipCb2JvdCBLZXk6KioNCg0KUGFkYSBpbHVzdHJhc2kgaW5pLCBtYXRyaWtzIGJvYm90IHByb3lla3NpIEtleSBkaXRldGFwa2FuIHNlYmFnYWk6DQoNClxbDQpcbWF0aGJme1d9X0sNCj0NClxiZWdpbntibWF0cml4fQ0KMC40MCAmIDAuMDBcXA0KMC4wMCAmIDAuNjANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQpCb2JvdCB0ZXJzZWJ1dCBtZW1iZXJpa2FuIHNrYWxhIHlhbmcgYmVyYmVkYSBwYWRhIGtvbXBvbmVuIHBlcnRhbWEgZGFuIGtlZHVhIGRhcmkgc2V0aWFwIHRva2VuIHRlcm5vcm1hbGlzYXNpLCB0YW5wYSBtZW5jYW1wdXJrYW4gaW5mb3JtYXNpIGFudGFyYSBrZWR1YSBrb21wb25lbiBmaXR1ci4NCg0KLSAqKlJ1bXVzOioqDQoNClByb3lla3NpIEtleSBkaXJ1bXVza2FuIHNlYmFnYWk6DQoNClxbDQpcbWF0aGJme0t9DQo9DQpcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1R9KVxtYXRoYmZ7V31fSy4NClxdDQoNClVudHVrIHRva2VuIGtlLVwodFwpLCBwZXJzYW1hYW4gdGVyc2VidXQgZGFwYXQgZGl0dWxpc2thbiBzZWJhZ2FpOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcbWF0aGJme0t9X3QNCiY9DQpbXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntUfSldX3t0fVxtYXRoYmZ7V31fS1xcDQomPQ0KXGJlZ2lue2JtYXRyaXh9DQpbXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntUfSldX3t0LDF9ICYNCltcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1R9KV1fe3QsMn0NClxlbmR7Ym1hdHJpeH0NClxiZWdpbntibWF0cml4fQ0KMC40MCAmIDAuMDBcXA0KMC4wMCAmIDAuNjANClxlbmR7Ym1hdHJpeH0uDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpNYXRyaWtzIGhhc2lsIG5vcm1hbGlzYXNpIFwoXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntUfSlcKSBiZXJ1a3VyYW4gXCgyNVx0aW1lczJcKSwgc2VkYW5na2FuIG1hdHJpa3MgYm9ib3QgXChcbWF0aGJme1d9X0tcKSBiZXJ1a3VyYW4gXCgyXHRpbWVzMlwpLiBEZW5nYW4gZGVtaWtpYW4sIG1hdHJpa3MgS2V5IFwoXG1hdGhiZntLfVwpIGJlcnVrdXJhbiBcKDI1XHRpbWVzMlwpLg0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuIHVudHVrIHRva2VuIHBlcnRhbWE6KioNCg0KQmVyZGFzYXJrYW4gdGFoYXAgbm9ybWFsaXNhc2kgdG9rZW4gc2ViZWx1bW55YSwgaGFzaWwgbm9ybWFsaXNhc2kgdG9rZW4gcGVydGFtYSB5YW5nIGRpdGFtcGlsa2FuIGRlbmdhbiBkdWEgYW5na2EgZGVzaW1hbCBhZGFsYWg6DQoNClxbDQpbXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntUfSldX3sxfQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQotMS4wMCAmIDEuMDANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQpTZWxhbmp1dG55YSwgS2V5IHVudHVrIHRva2VuIHBlcnRhbWEgZGloaXR1bmcgc2ViYWdhaToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KXG1hdGhiZntLfV8xDQomPQ0KW1xvcGVyYXRvcm5hbWV7TE59KFxtYXRoYmZ7VH0pXV97MX1cbWF0aGJme1d9X0tcXA0KJj0NClxiZWdpbntibWF0cml4fQ0KLTEuMDAgJiAxLjAwDQpcZW5ke2JtYXRyaXh9DQpcYmVnaW57Ym1hdHJpeH0NCjAuNDAgJiAwLjAwXFwNCjAuMDAgJiAwLjYwDQpcZW5ke2JtYXRyaXh9XFwNCiY9DQpcYmVnaW57Ym1hdHJpeH0NCigtMS4wMCkoMC40MCkrKDEuMDApKDAuMDApICYNCigtMS4wMCkoMC4wMCkrKDEuMDApKDAuNjApDQpcZW5ke2JtYXRyaXh9XFwNCiY9DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjQwICYgMC42MA0KXGVuZHtibWF0cml4fS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBkZW1pa2lhbiwgZWxlbWVuIEtleSB1bnR1ayB0b2tlbiBwZXJ0YW1hIGFkYWxhaDoNCg0KXFsNCktfezEsMX09LTAuNDAsDQpccXF1YWQNCktfezEsMn09MC42MC4NClxdDQoNClBhZGEgaWx1c3RyYXNpIGluaSwgbWF0cmlrcyBib2JvdCBcKFxtYXRoYmZ7V31fS1wpIGRpdGV0YXBrYW4gYmVyYmVkYSBkYXJpIG1hdHJpa3MgYm9ib3QgXChcbWF0aGJme1d9X1FcKSB1bnR1ayBtZW51bmp1a2thbiBiYWh3YSBRdWVyeSBkYW4gS2V5IGRpaGFzaWxrYW4gbWVsYWx1aSBwcm95ZWtzaSB5YW5nIGJlcmJlZGEuIFBhZGEgaW1wbGVtZW50YXNpIFRyYW5zZm9ybWVyIHNlYmVuYXJueWEsIGtlZHVhIG1hdHJpa3MgYm9ib3QgdGVyc2VidXQgbWVydXBha2FuIHBhcmFtZXRlciB5YW5nIGRpcGVsYWphcmkgc2VjYXJhIHRlcnBpc2FoIHNlbGFtYSBwcm9zZXMgcGVsYXRpaGFuLg0KDQpQcm9zZXMgcHJveWVrc2kgeWFuZyBzYW1hIGRpdGVyYXBrYW4gcGFkYSBzZWx1cnVoIHRva2VuLiBEZW5nYW4gbWVuYW1waWxrYW4gaGFzaWwgaGluZ2dhIGR1YSBhbmdrYSBkZXNpbWFsLCBkaXBlcm9sZWggbWF0cmlrcyBLZXkgYmVydWt1cmFuIFwoMjVcdGltZXMyXCkgc2ViYWdhaSBiZXJpa3V0Og0KDQpcWw0KXG1hdGhiZntLfQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQotMC40MCAmIDAuNjBcXA0KLTAuNDAgJiAwLjYwXFwNCjAuNDAgJiAtMC42MFxcDQowLjQwICYgLTAuNjBcXA0KLTAuNDAgJiAwLjYwXFwNCi0wLjQwICYgMC42MFxcDQotMC40MCAmIDAuNjBcXA0KMC40MCAmIC0wLjYwXFwNCjAuNDAgJiAtMC42MFxcDQotMC40MCAmIDAuNjBcXA0KLTAuNDAgJiAwLjYwXFwNCi0wLjQwICYgMC42MFxcDQowLjQwICYgLTAuNjBcXA0KMC40MCAmIC0wLjYwXFwNCi0wLjQwICYgMC42MFxcDQotMC40MCAmIDAuNjBcXA0KLTAuNDAgJiAwLjYwXFwNCjAuNDAgJiAtMC42MFxcDQowLjQwICYgLTAuNjBcXA0KLTAuNDAgJiAwLjYwXFwNCi0wLjQwICYgMC42MFxcDQotMC40MCAmIDAuNjBcXA0KMC40MCAmIC0wLjYwXFwNCi0wLjQwICYgMC42MFxcDQotMC40MCAmIDAuNjANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQoNCg0KIyMjIGQuIFByb3lla3NpIFZhbHVlDQoNClNldGVsYWggdG9rZW4gZGlub3JtYWxpc2FzaSwgc2V0aWFwIHRva2VuIGp1Z2EgZGlwcm95ZWtzaWthbiBtZW5qYWRpICpWYWx1ZSogKFYpLiBQYWRhIG1la2FuaXNtZSAqc2VsZi1hdHRlbnRpb24qLCBWYWx1ZSBtZW11YXQgaW5mb3JtYXNpIGZpdHVyIHlhbmcgYWthbiBkaWFncmVnYXNpa2FuIGRhcmkgc2VsdXJ1aCB0b2tlbiBiZXJkYXNhcmthbiBib2JvdCAqYXR0ZW50aW9uKiB5YW5nIGRpaGl0dW5nIG1lbGFsdWkgaW50ZXJha3NpIGFudGFyYSBRdWVyeSBkYW4gS2V5Lg0KDQotICoqQm9ib3QgVmFsdWU6KioNCg0KUGFkYSBpbHVzdHJhc2kgaW5pLCBtYXRyaWtzIGJvYm90IHByb3lla3NpIFZhbHVlIGRpdGV0YXBrYW4gc2ViYWdhaSBtYXRyaWtzIGlkZW50aXRhczoNCg0KXFsNClxtYXRoYmZ7V31fVg0KPQ0KXG1hdGhiZntJfQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQoxLjAwICYgMC4wMFxcDQowLjAwICYgMS4wMA0KXGVuZHtibWF0cml4fS4NClxdDQoNCk1hdHJpa3MgaWRlbnRpdGFzIHRpZGFrIG1lbmd1YmFoIG5pbGFpIG1hdXB1biBtZW5jYW1wdXJrYW4ga2VkdWEgZWxlbWVuIGZpdHVyIHRva2VuLiBPbGVoIGthcmVuYSBpdHUsIHBhZGEgaWx1c3RyYXNpIGluaSBtYXRyaWtzIFZhbHVlIG1lbWlsaWtpIG5pbGFpIHlhbmcgc2FtYSBkZW5nYW4gbWF0cmlrcyB0b2tlbiB5YW5nIHRlbGFoIGRpbm9ybWFsaXNhc2kuDQoNCi0gKipSdW11czoqKg0KDQpQcm95ZWtzaSBWYWx1ZSBkaXJ1bXVza2FuIHNlYmFnYWk6DQoNClxbDQpcbWF0aGJme1Z9DQo9DQpcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1R9KVxtYXRoYmZ7V31fVg0KPQ0KXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntUfSlcbWF0aGJme0l9DQo9DQpcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1R9KS4NClxdDQoNClVudHVrIHRva2VuIGtlLVwodFwpLCBwZXJzYW1hYW4gdGVyc2VidXQgZGFwYXQgZGl0dWxpc2thbiBzZWJhZ2FpOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcbWF0aGJme1Z9X3QNCiY9DQpbXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntUfSldX3t0fVxtYXRoYmZ7V31fVlxcDQomPQ0KXGJlZ2lue2JtYXRyaXh9DQpbXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntUfSldX3t0LDF9ICYNCltcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1R9KV1fe3QsMn0NClxlbmR7Ym1hdHJpeH0NClxiZWdpbntibWF0cml4fQ0KMS4wMCAmIDAuMDBcXA0KMC4wMCAmIDEuMDANClxlbmR7Ym1hdHJpeH0uDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpNYXRyaWtzIGhhc2lsIG5vcm1hbGlzYXNpIFwoXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntUfSlcKSBiZXJ1a3VyYW4gXCgyNVx0aW1lczJcKSwgc2VkYW5na2FuIG1hdHJpa3MgYm9ib3QgXChcbWF0aGJme1d9X1ZcKSBiZXJ1a3VyYW4gXCgyXHRpbWVzMlwpLiBEZW5nYW4gZGVtaWtpYW4sIG1hdHJpa3MgVmFsdWUgXChcbWF0aGJme1Z9XCkgYmVydWt1cmFuIFwoMjVcdGltZXMyXCkuDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gdW50dWsgdG9rZW4gcGVydGFtYToqKg0KDQpCZXJkYXNhcmthbiB0YWhhcCBub3JtYWxpc2FzaSB0b2tlbiBzZWJlbHVtbnlhLCBoYXNpbCBub3JtYWxpc2FzaSB0b2tlbiBwZXJ0YW1hIHlhbmcgZGl0YW1waWxrYW4gZGVuZ2FuIGR1YSBhbmdrYSBkZXNpbWFsIGFkYWxhaDoNCg0KXFsNCltcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1R9KV1fezF9DQo9DQpcYmVnaW57Ym1hdHJpeH0NCi0xLjAwICYgMS4wMA0KXGVuZHtibWF0cml4fS4NClxdDQoNClNlbGFuanV0bnlhLCBWYWx1ZSB1bnR1ayB0b2tlbiBwZXJ0YW1hIGRpaGl0dW5nIHNlYmFnYWk6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClxtYXRoYmZ7Vn1fMQ0KJj0NCltcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1R9KV1fezF9XG1hdGhiZntXfV9WXFwNCiY9DQpcYmVnaW57Ym1hdHJpeH0NCi0xLjAwICYgMS4wMA0KXGVuZHtibWF0cml4fQ0KXGJlZ2lue2JtYXRyaXh9DQoxLjAwICYgMC4wMFxcDQowLjAwICYgMS4wMA0KXGVuZHtibWF0cml4fVxcDQomPQ0KXGJlZ2lue2JtYXRyaXh9DQooLTEuMDApKDEuMDApKygxLjAwKSgwLjAwKSAmDQooLTEuMDApKDAuMDApKygxLjAwKSgxLjAwKQ0KXGVuZHtibWF0cml4fVxcDQomPQ0KXGJlZ2lue2JtYXRyaXh9DQotMS4wMCAmIDEuMDANClxlbmR7Ym1hdHJpeH0uDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gZGVtaWtpYW4sIGVsZW1lbiBWYWx1ZSB1bnR1ayB0b2tlbiBwZXJ0YW1hIGFkYWxhaDoNCg0KXFsNClZfezEsMX09LTEuMDAsDQpccXF1YWQNClZfezEsMn09MS4wMC4NClxdDQoNCkthcmVuYSBcKFxtYXRoYmZ7V31fVj1cbWF0aGJme0l9XCksIHNldGlhcCBiYXJpcyBwYWRhIG1hdHJpa3MgXChcbWF0aGJme1Z9XCkgbWVtaWxpa2kgbmlsYWkgeWFuZyBzYW1hIGRlbmdhbiBiYXJpcyB5YW5nIGJlcnNlc3VhaWFuIHBhZGEgbWF0cmlrcyBcKFxvcGVyYXRvcm5hbWV7TE59KFxtYXRoYmZ7VH0pXCkuIFBhZGEgaW1wbGVtZW50YXNpIFRyYW5zZm9ybWVyIHNlYmVuYXJueWEsIG1hdHJpa3MgYm9ib3QgXChcbWF0aGJme1d9X1ZcKSBtZXJ1cGFrYW4gcGFyYW1ldGVyIHlhbmcgZGlwZWxhamFyaSBzZWxhbWEgcGVsYXRpaGFuIGRhbiB0aWRhayBoYXJ1cyBiZXJiZW50dWsgbWF0cmlrcyBpZGVudGl0YXMuDQoNClByb3NlcyBwcm95ZWtzaSB5YW5nIHNhbWEgZGl0ZXJhcGthbiBwYWRhIHNlbHVydWggdG9rZW4uIERlbmdhbiBtZW5hbXBpbGthbiBoYXNpbCBoaW5nZ2EgZHVhIGFuZ2thIGRlc2ltYWwsIGRpcGVyb2xlaCBtYXRyaWtzIFZhbHVlIGJlcnVrdXJhbiBcKDI1XHRpbWVzMlwpIHNlYmFnYWkgYmVyaWt1dDoNCg0KXFsNClxtYXRoYmZ7Vn0NCj0NClxiZWdpbntibWF0cml4fQ0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMFxcDQoxLjAwICYgLTEuMDBcXA0KMS4wMCAmIC0xLjAwXFwNCi0xLjAwICYgMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCjEuMDAgJiAtMS4wMFxcDQoxLjAwICYgLTEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KMS4wMCAmIC0xLjAwXFwNCjEuMDAgJiAtMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMFxcDQoxLjAwICYgLTEuMDBcXA0KMS4wMCAmIC0xLjAwXFwNCi0xLjAwICYgMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMFxcDQoxLjAwICYgLTEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMA0KXGVuZHtibWF0cml4fS4NClxdDQoNCiMjIyBlLiBTY2FsZWQgRG90LVByb2R1Y3QgQXR0ZW50aW9uDQoNClNldGVsYWggbWF0cmlrcyBRdWVyeSBcKFxtYXRoYmZ7UX1cKSBkYW4gbWF0cmlrcyBLZXkgXChcbWF0aGJme0t9XCkgZGlwZXJvbGVoLCB0aW5na2F0IGtldGVya2FpdGFuIGFudGFydG9rZW4gZGloaXR1bmcgbWVuZ2d1bmFrYW4gKnNjYWxlZCBkb3QtcHJvZHVjdCBhdHRlbnRpb24qLiBQZXJoaXR1bmdhbiBpbmkgbWVuZ2hhc2lsa2FuIG1hdHJpa3Mgc2tvciBwZXJoYXRpYW4gXChcbWF0aGJme1N9XCkuIEVsZW1lbiBcKFNfe3QsdX1cKSBtZW55YXRha2FuIHNrb3Iga2VzZXN1YWlhbiBhbnRhcmEgUXVlcnkgdG9rZW4ga2UtXCh0XCkgZGFuIEtleSB0b2tlbiBrZS1cKHVcKS4gU2VtYWtpbiBiZXNhciBza29yIHlhbmcgZGlwZXJvbGVoLCBzZW1ha2luIHRpbmdnaSB0aW5na2F0IGtlc2VzdWFpYW4ga2VkdWEgcmVwcmVzZW50YXNpIHRlcnNlYnV0Lg0KDQotICoqUnVtdXM6KioNCg0KTWVuZ2FjdSBwYWRhIFBlcnNhbWFhbiAoMi45KSwgbWF0cmlrcyBza29yIHBlcmhhdGlhbiBkaXJ1bXVza2FuIHNlYmFnYWk6DQoNClxbDQpcbWF0aGJme1N9DQo9DQpcZnJhY3tcbWF0aGJme1F9XG1hdGhiZntLfV57XHRvcH19e1xzcXJ0e2Rfa319Lg0KXF0NCg0KUGFkYSBpbHVzdHJhc2kgaW5pLCBzZXRpYXAgS2V5IG1lbWlsaWtpIGR1YSBrb21wb25lbiBmaXR1ciwgc2VoaW5nZ2E6DQoNClxbDQpkX2s9Mi4NClxdDQoNClVudHVrIHBhc2FuZ2FuIHRva2VuIGtlLVwodFwpIGRhbiBrZS1cKHVcKSwgc2tvciBwZXJoYXRpYW4gZGloaXR1bmcgbWVuZ2d1bmFrYW46DQoNClxbDQpTX3t0LHV9DQo9DQpcZnJhY3tcbWF0aGJme1F9X3RcbWF0aGJme0t9X3Vee1x0b3B9fXtcc3FydHsyfX0uDQpcXQ0KDQpNYXRyaWtzIFwoXG1hdGhiZntRfVwpIGRhbiBcKFxtYXRoYmZ7S31cKSBtYXNpbmctbWFzaW5nIGJlcnVrdXJhbiBcKDI1XHRpbWVzMlwpLCBzZWRhbmdrYW4gbWF0cmlrcyBcKFxtYXRoYmZ7S31ee1x0b3B9XCkgYmVydWt1cmFuIFwoMlx0aW1lczI1XCkuIERlbmdhbiBkZW1pa2lhbiwgbWF0cmlrcyBza29yIHBlcmhhdGlhbiBcKFxtYXRoYmZ7U31cKSBiZXJ1a3VyYW4gXCgyNVx0aW1lczI1XCkuIFNldGlhcCBiYXJpcyBtZXJlcHJlc2VudGFzaWthbiB0b2tlbiBRdWVyeSwgc2VkYW5na2FuIHNldGlhcCBrb2xvbSBtZXJlcHJlc2VudGFzaWthbiB0b2tlbiBLZXkuDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gc2tvciBwZXJoYXRpYW4gdG9rZW4gcGVydGFtYToqKg0KDQpCZXJkYXNhcmthbiBoYXNpbCBwcm95ZWtzaSBzZWJlbHVtbnlhLCBkaXBlcm9sZWggUXVlcnkgZGFuIEtleSB0b2tlbiBwZXJ0YW1hOg0KDQpcWw0KXG1hdGhiZntRfV8xDQo9DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjUwICYgMC41MA0KXGVuZHtibWF0cml4fSwNClxxcXVhZA0KXG1hdGhiZntLfV8xDQo9DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjQwICYgMC42MA0KXGVuZHtibWF0cml4fS4NClxdDQoNClNrb3IgcGVyaGF0aWFuIHRva2VuIHBlcnRhbWEgdGVyaGFkYXAgZGlyaW55YSBzZW5kaXJpIGRpaGl0dW5nIHNlYmFnYWk6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClNfezEsMX0NCiY9DQpcZnJhY3tcbWF0aGJme1F9XzFcbWF0aGJme0t9XzFee1x0b3B9fXtcc3FydHsyfX1cXA0KJj0NClxmcmFjew0KXGJlZ2lue2JtYXRyaXh9DQotMC41MCAmIDAuNTANClxlbmR7Ym1hdHJpeH0NClxiZWdpbntibWF0cml4fQ0KLTAuNDBcXA0KMC42MA0KXGVuZHtibWF0cml4fQ0KfXtcc3FydHsyfX1cXA0KJj0NClxmcmFjeygtMC41MCkoLTAuNDApKygwLjUwKSgwLjYwKX17XHNxcnR7Mn19XFwNCiY9DQpcZnJhY3swLjIwKzAuMzB9e1xzcXJ0ezJ9fVxcDQomPQ0KXGZyYWN7MC41MH17XHNxcnR7Mn19XFwNCiY9MC4zNS4NClxlbmR7YWxpZ25lZH0NClxdDQoNClNlYmFnYWkgcGVtYmFuZGluZywgS2V5IHRva2VuIGtldGlnYSBhZGFsYWg6DQoNClxbDQpcbWF0aGJme0t9XzMNCj0NClxiZWdpbntibWF0cml4fQ0KMC40MCAmIC0wLjYwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KU2tvciBwZXJoYXRpYW4gUXVlcnkgdG9rZW4gcGVydGFtYSB0ZXJoYWRhcCBLZXkgdG9rZW4ga2V0aWdhIGRpaGl0dW5nIHNlYmFnYWk6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClNfezEsM30NCiY9DQpcZnJhY3tcbWF0aGJme1F9XzFcbWF0aGJme0t9XzNee1x0b3B9fXtcc3FydHsyfX1cXA0KJj0NClxmcmFjew0KXGJlZ2lue2JtYXRyaXh9DQotMC41MCAmIDAuNTANClxlbmR7Ym1hdHJpeH0NClxiZWdpbntibWF0cml4fQ0KMC40MFxcDQotMC42MA0KXGVuZHtibWF0cml4fQ0KfXtcc3FydHsyfX1cXA0KJj0NClxmcmFjeygtMC41MCkoMC40MCkrKDAuNTApKC0wLjYwKX17XHNxcnR7Mn19XFwNCiY9DQpcZnJhY3stMC4yMC0wLjMwfXtcc3FydHsyfX1cXA0KJj0NClxmcmFjey0wLjUwfXtcc3FydHsyfX1cXA0KJj0tMC4zNS4NClxlbmR7YWxpZ25lZH0NClxdDQoNClByb3NlcyB5YW5nIHNhbWEgZGl0ZXJhcGthbiBwYWRhIHNlbHVydWggcGFzYW5nYW4gdG9rZW4uIERlbmdhbiBtZW5hbXBpbGthbiBoYXNpbCBoaW5nZ2EgZHVhIGFuZ2thIGRlc2ltYWwsIGRpcGVyb2xlaCBtYXRyaWtzIHNrb3IgcGVyaGF0aWFuIFwoXG1hdGhiZntTfVwpIGJlcnVrdXJhbiBcKDI1XHRpbWVzMjVcKSBzZWJhZ2FpIGJlcmlrdXQ6DQoNCg0KDQpcWw0KbWF0aGJme1N9DQo9XGJlZ2lue2JtYXRyaXh9DQowLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1XFwNCjAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzVcXA0KLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzVcXA0KLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzVcXA0KMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNVxcDQowLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1XFwNCjAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzVcXA0KLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzVcXA0KLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzVcXA0KMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNVxcDQowLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1XFwNCjAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzVcXA0KLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzVcXA0KLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzVcXA0KMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNVxcDQowLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1XFwNCjAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzVcXA0KLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzVcXA0KLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzVcXA0KMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNVxcDQowLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1XFwNCjAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzVcXA0KLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzVcXA0KMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNVxcDQowLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIC0wLjM1ICYgMC4zNSAmIDAuMzUgJiAwLjM1ICYgLTAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1ICYgMC4zNSAmIC0wLjM1ICYgLTAuMzUgJiAwLjM1ICYgMC4zNSAmIDAuMzUgJiAtMC4zNSAmIDAuMzUgJiAwLjM1DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KTmlsYWkgcG9zaXRpZiBtZW51bmp1a2thbiBiYWh3YSBwb2xhIFF1ZXJ5IGRhbiBLZXkga2VkdWEgdG9rZW4gY2VuZGVydW5nIHNlcnVwYSwgc2VkYW5na2FuIG5pbGFpIG5lZ2F0aWYgbWVudW5qdWtrYW4gcG9sYSB5YW5nIGJlcmxhd2FuYW4uIE1hdHJpa3MgXChcbWF0aGJme1N9XCkgc2VsYW5qdXRueWEgZGlub3JtYWxpc2FzaSBtZW5nZ3VuYWthbiBmdW5nc2kgKnNvZnRtYXgqIHBhZGEgc2V0aWFwIGJhcmlzIHVudHVrIG1lbmdoYXNpbGthbiBtYXRyaWtzIGJvYm90IHBlcmhhdGlhbiBcKFxtYXRoYmZ7QX1cKS4NCg0KIyMjIGYuIFNvZnRtYXggQXR0ZW50aW9uIA0KDQpNYXRyaWtzIHNrb3IgXChTXCkgc2VsYW5qdXRueWEgZGl1YmFoIG1lbmphZGkgYm9ib3QgYXR0ZW50aW9uIG1lbmdndW5ha2FuIGZ1bmdzaSBzb2Z0bWF4IHBlciBiYXJpcy4gRGVuZ2FuIGRlbWlraWFuLCBzZXRpYXAgYmFyaXMgcGFkYSBtYXRyaWtzIFwoQVwpIG1lbWlsaWtpIGp1bWxhaCBuaWxhaSBzZWJlc2FyIHNhdHUuDQoNCi0gKipSdW11czoqKg0KDQpcWw0KQV97dCx1fQ0KPQ0KXGZyYWN7ZV57U197dCx1fX19DQp7XHN1bV97cj0xfV57MjV9ZV57U197dCxyfX19Lg0KXF0NCg0KTWF0cmlrcyBcKEFcKSBtZW1pbGlraSBkaW1lbnNpIFwoMjVcdGltZXMyNVwpLCBzYW1hIHNlcGVydGkgbWF0cmlrcyBza29yIFwoU1wpLg0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuIHVudHVrIFwoQV97MSwxfVwpOioqDQoNClBhZGEgYmFyaXMgcGVydGFtYSBtYXRyaWtzIFwoU1wpLCB0ZXJkYXBhdCAxNiBza29yIGJlcm5pbGFpIFwoMC4zNVwpIGRhbiA5IHNrb3IgYmVybmlsYWkgXCgtMC4zNVwpLiBPbGVoIGthcmVuYSBpdHUsDQoNClxbDQpcYmVnaW57YWxpZ25lZH0NCkFfezEsMX0NCiY9DQpcZnJhY3tlXnswLjM1fX0NCnsxNmVeezAuMzV9KzllXnstMC4zNX19XFwNCiY9DQpcZnJhY3sxLjQyfQ0KezE2KDEuNDIpKzkoMC43MCl9XFwNCiY9DQpcZnJhY3sxLjQyfXsyMi43Mis2LjMwfVxcDQomPQ0KXGZyYWN7MS40Mn17MjkuMDJ9XFwNCiY9MC4wNS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCk5pbGFpIFwoMC4wNVwpIG1lbnVuanVra2FuIGJhaHdhIHRva2VuIHBlcnRhbWEgbWVtYmVyaSBib2JvdCBwZXJoYXRpYW4gbGViaWggYmVzYXIga2VwYWRhIHRva2VuIHlhbmcgbWVtaWxpa2kgcG9sYSBRdWVyeS0tS2V5IHNlcnVwYSwgeWFpdHUgdG9rZW4gZGVuZ2FuIHNrb3IgXCgwLjM1XCkuDQoNCkF0dXJhbiB5YW5nIHNhbWEgZGl0ZXJhcGthbiBwYWRhIHNlbHVydWggYmFyaXMsIHNlaGluZ2dhIGRpcGVyb2xlaCBtYXRyaWtzIGJvYm90IGF0dGVudGlvbiBcKEFcKSBiZXJpa3V0Lg0KXFsNCkE9XGJlZ2lue2JtYXRyaXh9DQowLjA1ICYgMC4wNSAmIDAuMDIgJiAwLjAyICYgMC4wNSAmIDAuMDUgJiAwLjA1ICYgMC4wMiAmIDAuMDIgJiAwLjA1ICYgMC4wNSAmIDAuMDUgJiAwLjAyICYgMC4wMiAmIDAuMDUgJiAwLjA1ICYgMC4wNSAmIDAuMDIgJiAwLjAyICYgMC4wNSAmIDAuMDUgJiAwLjA1ICYgMC4wMiAmIDAuMDUgJiAwLjA1XFwNCjAuMDUgJiAwLjA1ICYgMC4wMiAmIDAuMDIgJiAwLjA1ICYgMC4wNSAmIDAuMDUgJiAwLjAyICYgMC4wMiAmIDAuMDUgJiAwLjA1ICYgMC4wNSAmIDAuMDIgJiAwLjAyICYgMC4wNSAmIDAuMDUgJiAwLjA1ICYgMC4wMiAmIDAuMDIgJiAwLjA1ICYgMC4wNSAmIDAuMDUgJiAwLjAyICYgMC4wNSAmIDAuMDVcXA0KMC4wMyAmIDAuMDMgJiAwLjA2ICYgMC4wNiAmIDAuMDMgJiAwLjAzICYgMC4wMyAmIDAuMDYgJiAwLjA2ICYgMC4wMyAmIDAuMDMgJiAwLjAzICYgMC4wNiAmIDAuMDYgJiAwLjAzICYgMC4wMyAmIDAuMDMgJiAwLjA2ICYgMC4wNiAmIDAuMDMgJiAwLjAzICYgMC4wMyAmIDAuMDYgJiAwLjAzICYgMC4wM1xcDQowLjAzICYgMC4wMyAmIDAuMDYgJiAwLjA2ICYgMC4wMyAmIDAuMDMgJiAwLjAzICYgMC4wNiAmIDAuMDYgJiAwLjAzICYgMC4wMyAmIDAuMDMgJiAwLjA2ICYgMC4wNiAmIDAuMDMgJiAwLjAzICYgMC4wMyAmIDAuMDYgJiAwLjA2ICYgMC4wMyAmIDAuMDMgJiAwLjAzICYgMC4wNiAmIDAuMDMgJiAwLjAzXFwNCjAuMDUgJiAwLjA1ICYgMC4wMiAmIDAuMDIgJiAwLjA1ICYgMC4wNSAmIDAuMDUgJiAwLjAyICYgMC4wMiAmIDAuMDUgJiAwLjA1ICYgMC4wNSAmIDAuMDIgJiAwLjAyICYgMC4wNSAmIDAuMDUgJiAwLjA1ICYgMC4wMiAmIDAuMDIgJiAwLjA1ICYgMC4wNSAmIDAuMDUgJiAwLjAyICYgMC4wNSAmIDAuMDVcXA0KMC4wNSAmIDAuMDUgJiAwLjAyICYgMC4wMiAmIDAuMDUgJiAwLjA1ICYgMC4wNSAmIDAuMDIgJiAwLjAyICYgMC4wNSAmIDAuMDUgJiAwLjA1ICYgMC4wMiAmIDAuMDIgJiAwLjA1ICYgMC4wNSAmIDAuMDUgJiAwLjAyICYgMC4wMiAmIDAuMDUgJiAwLjA1ICYgMC4wNSAmIDAuMDIgJiAwLjA1ICYgMC4wNVxcDQowLjA1ICYgMC4wNSAmIDAuMDIgJiAwLjAyICYgMC4wNSAmIDAuMDUgJiAwLjA1ICYgMC4wMiAmIDAuMDIgJiAwLjA1ICYgMC4wNSAmIDAuMDUgJiAwLjAyICYgMC4wMiAmIDAuMDUgJiAwLjA1ICYgMC4wNSAmIDAuMDIgJiAwLjAyICYgMC4wNSAmIDAuMDUgJiAwLjA1ICYgMC4wMiAmIDAuMDUgJiAwLjA1XFwNCjAuMDMgJiAwLjAzICYgMC4wNiAmIDAuMDYgJiAwLjAzICYgMC4wMyAmIDAuMDMgJiAwLjA2ICYgMC4wNiAmIDAuMDMgJiAwLjAzICYgMC4wMyAmIDAuMDYgJiAwLjA2ICYgMC4wMyAmIDAuMDMgJiAwLjAzICYgMC4wNiAmIDAuMDYgJiAwLjAzICYgMC4wMyAmIDAuMDMgJiAwLjA2ICYgMC4wMyAmIDAuMDNcXA0KMC4wMyAmIDAuMDMgJiAwLjA2ICYgMC4wNiAmIDAuMDMgJiAwLjAzICYgMC4wMyAmIDAuMDYgJiAwLjA2ICYgMC4wMyAmIDAuMDMgJiAwLjAzICYgMC4wNiAmIDAuMDYgJiAwLjAzICYgMC4wMyAmIDAuMDMgJiAwLjA2ICYgMC4wNiAmIDAuMDMgJiAwLjAzICYgMC4wMyAmIDAuMDYgJiAwLjAzICYgMC4wM1xcDQowLjA1ICYgMC4wNSAmIDAuMDIgJiAwLjAyICYgMC4wNSAmIDAuMDUgJiAwLjA1ICYgMC4wMiAmIDAuMDIgJiAwLjA1ICYgMC4wNSAmIDAuMDUgJiAwLjAyICYgMC4wMiAmIDAuMDUgJiAwLjA1ICYgMC4wNSAmIDAuMDIgJiAwLjAyICYgMC4wNSAmIDAuMDUgJiAwLjA1ICYgMC4wMiAmIDAuMDUgJiAwLjA1XFwNCjAuMDUgJiAwLjA1ICYgMC4wMiAmIDAuMDIgJiAwLjA1ICYgMC4wNSAmIDAuMDUgJiAwLjAyICYgMC4wMiAmIDAuMDUgJiAwLjA1ICYgMC4wNSAmIDAuMDIgJiAwLjAyICYgMC4wNSAmIDAuMDUgJiAwLjA1ICYgMC4wMiAmIDAuMDIgJiAwLjA1ICYgMC4wNSAmIDAuMDUgJiAwLjAyICYgMC4wNSAmIDAuMDVcXA0KMC4wNSAmIDAuMDUgJiAwLjAyICYgMC4wMiAmIDAuMDUgJiAwLjA1ICYgMC4wNSAmIDAuMDIgJiAwLjAyICYgMC4wNSAmIDAuMDUgJiAwLjA1ICYgMC4wMiAmIDAuMDIgJiAwLjA1ICYgMC4wNSAmIDAuMDUgJiAwLjAyICYgMC4wMiAmIDAuMDUgJiAwLjA1ICYgMC4wNSAmIDAuMDIgJiAwLjA1ICYgMC4wNVxcDQowLjAzICYgMC4wMyAmIDAuMDYgJiAwLjA2ICYgMC4wMyAmIDAuMDMgJiAwLjAzICYgMC4wNiAmIDAuMDYgJiAwLjAzICYgMC4wMyAmIDAuMDMgJiAwLjA2ICYgMC4wNiAmIDAuMDMgJiAwLjAzICYgMC4wMyAmIDAuMDYgJiAwLjA2ICYgMC4wMyAmIDAuMDMgJiAwLjAzICYgMC4wNiAmIDAuMDMgJiAwLjAzXFwNCjAuMDMgJiAwLjAzICYgMC4wNiAmIDAuMDYgJiAwLjAzICYgMC4wMyAmIDAuMDMgJiAwLjA2ICYgMC4wNiAmIDAuMDMgJiAwLjAzICYgMC4wMyAmIDAuMDYgJiAwLjA2ICYgMC4wMyAmIDAuMDMgJiAwLjAzICYgMC4wNiAmIDAuMDYgJiAwLjAzICYgMC4wMyAmIDAuMDMgJiAwLjA2ICYgMC4wMyAmIDAuMDNcXA0KMC4wNSAmIDAuMDUgJiAwLjAyICYgMC4wMiAmIDAuMDUgJiAwLjA1ICYgMC4wNSAmIDAuMDIgJiAwLjAyICYgMC4wNSAmIDAuMDUgJiAwLjA1ICYgMC4wMiAmIDAuMDIgJiAwLjA1ICYgMC4wNSAmIDAuMDUgJiAwLjAyICYgMC4wMiAmIDAuMDUgJiAwLjA1ICYgMC4wNSAmIDAuMDIgJiAwLjA1ICYgMC4wNVxcDQowLjA1ICYgMC4wNSAmIDAuMDIgJiAwLjAyICYgMC4wNSAmIDAuMDUgJiAwLjA1ICYgMC4wMiAmIDAuMDIgJiAwLjA1ICYgMC4wNSAmIDAuMDUgJiAwLjAyICYgMC4wMiAmIDAuMDUgJiAwLjA1ICYgMC4wNSAmIDAuMDIgJiAwLjAyICYgMC4wNSAmIDAuMDUgJiAwLjA1ICYgMC4wMiAmIDAuMDUgJiAwLjA1XFwNCjAuMDUgJiAwLjA1ICYgMC4wMiAmIDAuMDIgJiAwLjA1ICYgMC4wNSAmIDAuMDUgJiAwLjAyICYgMC4wMiAmIDAuMDUgJiAwLjA1ICYgMC4wNSAmIDAuMDIgJiAwLjAyICYgMC4wNSAmIDAuMDUgJiAwLjA1ICYgMC4wMiAmIDAuMDIgJiAwLjA1ICYgMC4wNSAmIDAuMDUgJiAwLjAyICYgMC4wNSAmIDAuMDVcXA0KMC4wMyAmIDAuMDMgJiAwLjA2ICYgMC4wNiAmIDAuMDMgJiAwLjAzICYgMC4wMyAmIDAuMDYgJiAwLjA2ICYgMC4wMyAmIDAuMDMgJiAwLjAzICYgMC4wNiAmIDAuMDYgJiAwLjAzICYgMC4wMyAmIDAuMDMgJiAwLjA2ICYgMC4wNiAmIDAuMDMgJiAwLjAzICYgMC4wMyAmIDAuMDYgJiAwLjAzICYgMC4wM1xcDQowLjAzICYgMC4wMyAmIDAuMDYgJiAwLjA2ICYgMC4wMyAmIDAuMDMgJiAwLjAzICYgMC4wNiAmIDAuMDYgJiAwLjAzICYgMC4wMyAmIDAuMDMgJiAwLjA2ICYgMC4wNiAmIDAuMDMgJiAwLjAzICYgMC4wMyAmIDAuMDYgJiAwLjA2ICYgMC4wMyAmIDAuMDMgJiAwLjAzICYgMC4wNiAmIDAuMDMgJiAwLjAzXFwNCjAuMDUgJiAwLjA1ICYgMC4wMiAmIDAuMDIgJiAwLjA1ICYgMC4wNSAmIDAuMDUgJiAwLjAyICYgMC4wMiAmIDAuMDUgJiAwLjA1ICYgMC4wNSAmIDAuMDIgJiAwLjAyICYgMC4wNSAmIDAuMDUgJiAwLjA1ICYgMC4wMiAmIDAuMDIgJiAwLjA1ICYgMC4wNSAmIDAuMDUgJiAwLjAyICYgMC4wNSAmIDAuMDVcXA0KMC4wNSAmIDAuMDUgJiAwLjAyICYgMC4wMiAmIDAuMDUgJiAwLjA1ICYgMC4wNSAmIDAuMDIgJiAwLjAyICYgMC4wNSAmIDAuMDUgJiAwLjA1ICYgMC4wMiAmIDAuMDIgJiAwLjA1ICYgMC4wNSAmIDAuMDUgJiAwLjAyICYgMC4wMiAmIDAuMDUgJiAwLjA1ICYgMC4wNSAmIDAuMDIgJiAwLjA1ICYgMC4wNVxcDQowLjA1ICYgMC4wNSAmIDAuMDIgJiAwLjAyICYgMC4wNSAmIDAuMDUgJiAwLjA1ICYgMC4wMiAmIDAuMDIgJiAwLjA1ICYgMC4wNSAmIDAuMDUgJiAwLjAyICYgMC4wMiAmIDAuMDUgJiAwLjA1ICYgMC4wNSAmIDAuMDIgJiAwLjAyICYgMC4wNSAmIDAuMDUgJiAwLjA1ICYgMC4wMiAmIDAuMDUgJiAwLjA1XFwNCjAuMDMgJiAwLjAzICYgMC4wNiAmIDAuMDYgJiAwLjAzICYgMC4wMyAmIDAuMDMgJiAwLjA2ICYgMC4wNiAmIDAuMDMgJiAwLjAzICYgMC4wMyAmIDAuMDYgJiAwLjA2ICYgMC4wMyAmIDAuMDMgJiAwLjAzICYgMC4wNiAmIDAuMDYgJiAwLjAzICYgMC4wMyAmIDAuMDMgJiAwLjA2ICYgMC4wMyAmIDAuMDNcXA0KMC4wNSAmIDAuMDUgJiAwLjAyICYgMC4wMiAmIDAuMDUgJiAwLjA1ICYgMC4wNSAmIDAuMDIgJiAwLjAyICYgMC4wNSAmIDAuMDUgJiAwLjA1ICYgMC4wMiAmIDAuMDIgJiAwLjA1ICYgMC4wNSAmIDAuMDUgJiAwLjAyICYgMC4wMiAmIDAuMDUgJiAwLjA1ICYgMC4wNSAmIDAuMDIgJiAwLjA1ICYgMC4wNVxcDQowLjA1ICYgMC4wNSAmIDAuMDIgJiAwLjAyICYgMC4wNSAmIDAuMDUgJiAwLjA1ICYgMC4wMiAmIDAuMDIgJiAwLjA1ICYgMC4wNSAmIDAuMDUgJiAwLjAyICYgMC4wMiAmIDAuMDUgJiAwLjA1ICYgMC4wNSAmIDAuMDIgJiAwLjAyICYgMC4wNSAmIDAuMDUgJiAwLjA1ICYgMC4wMiAmIDAuMDUgJiAwLjA1DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KDQojIyMgZy4gQWdyZWdhc2kgVmFsdWUgQmVyYm9ib3QgQXR0ZW50aW9uDQoNCk1hdHJpa3MgYm9ib3QgYXR0ZW50aW9uIFwoXG1hdGhiZntBfVwpIGRpZ3VuYWthbiB1bnR1ayBtZW5nZ2FidW5na2FuIHNlbHVydWggVmFsdWUgXChcbWF0aGJme1Z9XCkuIFNldGlhcCBiYXJpcyBoYXNpbCBcKFxtYXRoYmZ7QX1cbWF0aGJme1Z9XCkgYWRhbGFoIGp1bWxhaCBiZXJib2JvdCBkYXJpIHNlbHVydWggdG9rZW4gVmFsdWUuDQoNClBhZGEgaWx1c3RyYXNpIHBlcmhpdHVuZ2FuIGluaSwgbWVrYW5pc21lIHNlbGYtYXR0ZW50aW9uIGRpc2VkZXJoYW5ha2FuIG1lbmdndW5ha2FuIHNhdHUgYXR0ZW50aW9uIGhlYWQuIE9sZWgga2FyZW5hIGl0dSwgb3BlcmFzaSBjb25jYXRlbmF0aW9uIHBhZGEgUGVyc2FtYWFuICgyLjE0KSB0aWRhayBtZW5nZ2FidW5na2FuIGJlYmVyYXBhIGtlbHVhcmFuIGhlYWQgZGFuIG1lbmdoYXNpbGthbiBrZWx1YXJhbiB5YW5nIHNhbWEgZGVuZ2FuIGhlYWQgdHVuZ2dhbCB0ZXJzZWJ1dC4gTWF0cmlrcyBwcm95ZWtzaSBrZWx1YXJhbiBcKFxtYXRoYmYgV15PXCkgZGl0ZXRhcGthbiBzZWJhZ2FpIG1hdHJpa3MgaWRlbnRpdGFzLCBzZWhpbmdnYSBwcm9zZXMgcHJveWVrc2kga2VsdWFyYW4gdGlkYWsgbWVuZ3ViYWggbmlsYWkgaGFzaWwgYWdyZWdhc2kgVmFsdWUuIERlbmdhbiBkZW1pa2lhbiwga2VsdWFyYW4gYXR0ZW50aW9uIHBhZGEgaWx1c3RyYXNpIGluaSBkaXBlcm9sZWggZGFyaSBwZXJrYWxpYW4gbWF0cmlrcyBib2JvdCBwZXJoYXRpYW4gXChcbWF0aGJmIEFcKSBkYW4gbWF0cmlrcyBWYWx1ZSBcKFxtYXRoYmYgVlwpLg0KDQotICoqUnVtdXM6KioNCg0KXFsNClxtYXRoYmZ7T31fe1xtYXRocm17YXR0fX09XG1hdGhiZntBfVxtYXRoYmZ7Vn0uDQpcXQ0KDQpQYWRhIGlsdXN0cmFzaSBpbmksIGthcmVuYSBib2JvdCBrZWx1YXJhbiBcKFxtYXRoYmZ7V31ee099PVxtYXRoYmZ7SX1cKSwgbWFrYToNCg0KXFsNClxtYXRoYmZ7T31fe1xtYXRocm17YXR0fX0NCj0NClxtYXRoYmZ7QX1cbWF0aGJme1Z9XG1hdGhiZntXfV57T30NCj0NClxtYXRoYmZ7QX1cbWF0aGJme1Z9Lg0KXF0NCg0KTWF0cmlrcyBcKFxtYXRoYmZ7QX1cKSBiZXJkaW1lbnNpIFwoMjVcdGltZXMyNVwpLCBzZWRhbmdrYW4gXChcbWF0aGJme1Z9XCkgYmVyZGltZW5zaSBcKDI1XHRpbWVzMlwpLiBPbGVoIGthcmVuYSBpdHUsIGhhc2lsIFwoXG1hdGhiZntBfVxtYXRoYmZ7Vn1cKSBhdGF1IG1hdHJpa3Mga2VsdWFyYW4gYXR0ZW50aW9uIFwoXG1hdGhiZntPfV97XG1hdGhybXthdHR9fVwpIGJlcmRpbWVuc2kgXCgyNVx0aW1lczJcKS4NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiB1bnR1ayBcKE9fe1xtYXRocm17YXR0fSwxLDF9XCk6KioNCg0KUGFkYSBiYXJpcyBwZXJ0YW1hLCB0ZXJkYXBhdCAxNiB0b2tlbiBWYWx1ZSBiZXJwb2xhIFwoKC0xLDEpXCkgZGVuZ2FuIGJvYm90IHNla2l0YXIgXCgwLjA1XCksIHNlcnRhIDkgdG9rZW4gVmFsdWUgYmVycG9sYSBcKCgxLC0xKVwpIGRlbmdhbiBib2JvdCBzZWtpdGFyIFwoMC4wMlwpLiBNYWthLCBrb21wb25lbiBwZXJ0YW1hIGRpaGl0dW5nIHNlYmFnYWk6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NCk9fe1xtYXRocm17YXR0fSwxLDF9DQomPQ0KXHN1bV97dT0xfV57MjV9QV97MSx1fVZfe3UsMX1cXA0KJj0NCjE2KDAuMDUpKC0xLjAwKSs5KDAuMDIpKDEuMDApXFwNCiY9DQotMC44MCswLjE4XFwNCiY9DQotMC42Mi4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBjYXJhIHlhbmcgc2FtYSwga29tcG9uZW4ga2VkdWEgYWRhbGFoOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpPX3tcbWF0aHJte2F0dH0sMSwyfQ0KJj0NClxzdW1fe3U9MX1eezI1fUFfezEsdX1WX3t1LDJ9XFwNCiY9DQoxNigwLjA1KSgxLjAwKSs5KDAuMDIpKC0xLjAwKVxcDQomPQ0KMC44MC0wLjE4XFwNCiY9DQowLjYyLg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KU2VoaW5nZ2EsDQoNClxbDQpcbWF0aGJme099X3tcbWF0aHJte2F0dH0sMX09DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjYyICYgMC42Mg0KXGVuZHtibWF0cml4fS4NClxdDQoNCkF0dXJhbiB5YW5nIHNhbWEgZGl0ZXJhcGthbiBwYWRhIHNlbHVydWggdG9rZW4sIHNlaGluZ2dhIGRpcGVyb2xlaCBtYXRyaWtzIFwoQVZcKSBiZXJpa3V0Lg0KDQpcWw0KXG1hdGhiZntPfV97XG1hdGhybXthdHR9fQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQotMC42MiAmIDAuNjJcXA0KLTAuNjIgJiAwLjYyXFwNCjAuMDYgJiAtMC4wNlxcDQowLjA2ICYgLTAuMDZcXA0KLTAuNjIgJiAwLjYyXFwNCi0wLjYyICYgMC42MlxcDQotMC42MiAmIDAuNjJcXA0KMC4wNiAmIC0wLjA2XFwNCjAuMDYgJiAtMC4wNlxcDQotMC42MiAmIDAuNjJcXA0KLTAuNjIgJiAwLjYyXFwNCi0wLjYyICYgMC42MlxcDQowLjA2ICYgLTAuMDZcXA0KMC4wNiAmIC0wLjA2XFwNCi0wLjYyICYgMC42MlxcDQotMC42MiAmIDAuNjJcXA0KLTAuNjIgJiAwLjYyXFwNCjAuMDYgJiAtMC4wNlxcDQowLjA2ICYgLTAuMDZcXA0KLTAuNjIgJiAwLjYyXFwNCi0wLjYyICYgMC42MlxcDQotMC42MiAmIDAuNjJcXA0KMC4wNiAmIC0wLjA2XFwNCi0wLjYyICYgMC42MlxcDQotMC42MiAmIDAuNjINClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQoNCiMjIyBoLiBSZXNpZHVhbCBBdHRlbnRpb24NCg0KUmVzaWR1YWwgYXR0ZW50aW9uIG1lbmdnYWJ1bmdrYW4gbWF0cmlrcyB0b2tlbiBhd2FsIFwoXG1hdGhiZntUfVwpIGRlbmdhbiBrZWx1YXJhbiBhdHRlbnRpb24gXChcbWF0aGJme099X3tcbWF0aHJte2F0dH19XCkuIFR1anVhbm55YSBhZGFsYWggbWVtcGVydGFoYW5rYW4gaW5mb3JtYXNpIGF3YWwgdG9rZW4gc2FtYmlsIG1lbmFtYmFoa2FuIGluZm9ybWFzaSBnbG9iYWwgaGFzaWwgKnNlbGYtYXR0ZW50aW9uKi4NCg0KLSAqKlJ1bXVzOioqDQoNClxbDQpcbWF0aGJme1p9Jw0KPQ0KXG1hdGhiZntUfQ0KKw0KXG1hdGhiZntPfV97XG1hdGhybXthdHR9fS4NClxdDQoNCk1hdHJpa3MgXChcbWF0aGJme1R9XCkgZGFuIFwoXG1hdGhiZntPfV97XG1hdGhybXthdHR9fVwpIGtlZHVhbnlhIGJlcmRpbWVuc2kgXCgyNVx0aW1lczJcKSwgc2VoaW5nZ2EgXChcbWF0aGJme1p9J1wpIGp1Z2EgYmVyZGltZW5zaSBcKDI1XHRpbWVzMlwpLg0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuIHVudHVrIHRva2VuIHBlcnRhbWE6KioNCg0KXFsNClxtYXRoYmZ7VH1fMT0NClxiZWdpbntibWF0cml4fQ0KLTAuMjcgJiAwLjEzDQpcZW5ke2JtYXRyaXh9LA0KXHFxdWFkDQpcbWF0aGJme099X3tcbWF0aHJte2F0dH0sMX09DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjYyICYgMC42Mg0KXGVuZHtibWF0cml4fS4NClxdDQoNCk1ha2EsDQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClxtYXRoYmZ7Wn0nX3sxfQ0KJj0NClxtYXRoYmZ7VH1fMStcbWF0aGJme099X3tcbWF0aHJte2F0dH0sMX1cXA0KJj0NClxiZWdpbntibWF0cml4fQ0KLTAuMjcgJiAwLjEzDQpcZW5ke2JtYXRyaXh9DQorDQpcYmVnaW57Ym1hdHJpeH0NCi0wLjYyICYgMC42Mg0KXGVuZHtibWF0cml4fVxcDQomPQ0KXGJlZ2lue2JtYXRyaXh9DQotMC44OSAmIDAuNzUNClxlbmR7Ym1hdHJpeH0uDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpBdHVyYW4geWFuZyBzYW1hIGRpdGVyYXBrYW4gcGFkYSBzZWx1cnVoIHRva2VuLCBzZWhpbmdnYSBkaXBlcm9sZWggbWF0cmlrcyByZXNpZHVhbCBhdHRlbnRpb24gXChcbWF0aGJme1p9J1wpIGJlcmlrdXQuDQoNClxbDQpcbWF0aGJme1p9Jz0NClxiZWdpbntibWF0cml4fQ0KLTAuODkgJiAwLjc1XFwNCi0wLjg3ICYgMC43NFxcDQowLjYyICYgLTAuMzRcXA0KMC4zMiAmIC0wLjE5XFwNCi0wLjg5ICYgMC43NlxcDQotMC44OCAmIDAuNzVcXA0KLTAuODUgJiAwLjc0XFwNCjAuOTMgJiAtMC40OVxcDQowLjUyICYgLTAuMjlcXA0KLTAuODkgJiAwLjc2XFwNCi0wLjg4ICYgMC43NVxcDQotMC44NSAmIDAuNzNcXA0KMC45MyAmIC0wLjQ5XFwNCjAuNTIgJiAtMC4yOVxcDQotMC44OSAmIDAuNzZcXA0KLTAuODggJiAwLjc1XFwNCi0wLjg3ICYgMC43NVxcDQowLjY2ICYgLTAuMzZcXA0KMC4zMCAmIC0wLjE4XFwNCi0wLjkwICYgMC43NlxcDQotMC44OSAmIDAuNzZcXA0KLTAuODkgJiAwLjc2XFwNCjAuMTYgJiAtMC4xMVxcDQotMC43MSAmIDAuNjZcXA0KLTAuOTAgJiAwLjc2DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KIyMjIGkuIE5vcm1hbGlzYXNpIEtlbHVhcmFuIFJlc2lkdWFsIEF0dGVudGlvbg0KDQpNYXRyaWtzIGhhc2lsIHJlc2lkdWFsIGF0dGVudGlvbiBcKFxtYXRoYmZ7Wn0nXCkgZGlub3JtYWxpc2FzaSBwZXIgdG9rZW4gbWVuZ2d1bmFrYW4gKkxheWVyIE5vcm1hbGl6YXRpb24qLCBkZW5nYW4gcHJvc2VkdXIgeWFuZyBzYW1hIHNlcGVydGkgbm9ybWFsaXNhc2kgdG9rZW4gc2ViZWx1bW55YS4NCg0KLSAqKlJ1bXVzOioqDQoNClxbDQpcbGVmdFtcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1p9J190KVxyaWdodF1faw0KPQ0KXGZyYWN7Widfe3Qsa30tXG11X3R9DQp7XHNxcnR7XHNpZ21hX3ReezJ9KzEwXnstNX19fSwNClxdDQoNCmRlbmdhbjoNCg0KXFsNClxtdV90DQo9DQpcZnJhY3sxfXsyfVxzdW1fe2s9MX1eezJ9Widfe3Qsa30sDQpccXF1YWQNClxzaWdtYV90XnsyfQ0KPQ0KXGZyYWN7MX17Mn1cc3VtX3trPTF9XnsyfShaJ197dCxrfS1cbXVfdCleMi4NClxdDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gdW50dWsgdG9rZW4gcGVydGFtYToqKg0KDQpcWw0KXG1hdGhiZntafSdfMT0NClxiZWdpbntibWF0cml4fQ0KLTAuODkgJiAwLjc1DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KUmF0YS1yYXRhIHRva2VuIHBlcnRhbWEgYWRhbGFoOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcbXVfMQ0KJj0NClxmcmFjey0wLjg5KzAuNzV9ezJ9XFwNCiY9DQotMC4wNy4NClxlbmR7YWxpZ25lZH0NClxdDQoNClZhcmlhbnNueWEgYWRhbGFoOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcc2lnbWFfMV4yDQomPQ0KXGZyYWN7KC0wLjg5LSgtMC4wNykpXjIrKDAuNzUtKC0wLjA3KSleMn17Mn1cXA0KJj0NClxmcmFjeygtMC44MileMisoMC44MileMn17Mn1cXA0KJj0NCjAuNjcyNC4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkVsZW1lbiBwZXJ0YW1hIHNldGVsYWggbm9ybWFsaXNhc2kgYWRhbGFoOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcbGVmdFtcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1p9J18xKVxyaWdodF1fMQ0KJj0NClxmcmFjey0wLjg5LSgtMC4wNyl9DQp7XHNxcnR7MC42NzI0KzEwXnstNX19fVxcDQomPQ0KXGZyYWN7LTAuODJ9ezAuODJ9XFwNCiY9DQotMS4wMC4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBjYXJhIHlhbmcgc2FtYSwgXChcbGVmdFtcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1p9J18xKVxyaWdodF1fMj0xLjAwXCkuIE9sZWgga2FyZW5hIGl0dToNCg0KXFsNClxvcGVyYXRvcm5hbWV7TE59KFxtYXRoYmZ7Wn0nXzEpPQ0KXGJlZ2lue2JtYXRyaXh9DQotMS4wMCAmIDEuMDANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQpBdHVyYW4geWFuZyBzYW1hIGRpdGVyYXBrYW4gcGFkYSBzZWx1cnVoIHRva2VuLCBzZWhpbmdnYSBkaXBlcm9sZWggaGFzaWwgbm9ybWFsaXNhc2kgcmVzaWR1YWwgYXR0ZW50aW9uIFwoXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntafScpXCkgYmVyaWt1dC4NCg0KXFsNClxvcGVyYXRvcm5hbWV7TE59KFxtYXRoYmZ7Wn0nKT0NClxiZWdpbntibWF0cml4fQ0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMFxcDQoxLjAwICYgLTEuMDBcXA0KMS4wMCAmIC0xLjAwXFwNCi0xLjAwICYgMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCjEuMDAgJiAtMS4wMFxcDQoxLjAwICYgLTEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KMS4wMCAmIC0xLjAwXFwNCjEuMDAgJiAtMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMFxcDQoxLjAwICYgLTEuMDBcXA0KMS4wMCAmIC0xLjAwXFwNCi0xLjAwICYgMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCjEuMDAgJiAtMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KLTEuMDAgJiAxLjAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KDQojIyMgai4gTGFwaXNhbiBMaW5lYXIgUGVydGFtYSBNTFAgKCpGZWVkLUZvcndhcmQgTmV0d29yayopDQoNCkxhcGlzYW4gbGluZWFyIHBlcnRhbWEgcGFkYSBNTFAgbWVtcHJveWVrc2lrYW4gc2V0aWFwIHRva2VuIGRhcmkgZHVhIGZpdHVyIG1lbmphZGkgdGlnYSBmaXR1ci4gVGFoYXAgaW5pIG1lcnVwYWthbiBiYWdpYW4gcGVydGFtYSBkYXJpIE1MUCBwYWRhIFBlcnNhbWFhbiAoMi4xNykuIFBhZGEgaWx1c3RyYXNpIHBlcmhpdHVuZ2FuLCBmdW5nc2kgYWt0aXZhc2kgR0VMVSBkaXNlZGVyaGFuYWthbiBtZW5qYWRpIFJlTFUgZGFuIHZla3RvciBiaWFzIHRpZGFrIGRpZ3VuYWthbi4NCg0KLSAqKkJvYm90IGxhcGlzYW4gbGluZWFyIHBlcnRhbWE6KioNCg0KXFsNClxtYXRoYmZ7V31fMT0NClxiZWdpbntibWF0cml4fQ0KMC42MCAmIC0wLjIwICYgMC40MFxcDQotMC4zMCAmIDAuNTAgJiAtMC40MA0KXGVuZHtibWF0cml4fS4NClxdDQoNCi0gKipSdW11czoqKg0KDQpcWw0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQpcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1p9JylcbWF0aGJme1d9XzENClxyaWdodCkuDQpcXQ0KDQpkZW5nYW46DQoNClxbDQpcb3BlcmF0b3JuYW1le1JlTFV9KHgpPVxtYXgoMCx4KS4NClxdDQoNCk1hdHJpa3MgXChcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1p9JylcKSBiZXJkaW1lbnNpIFwoMjVcdGltZXMyXCkgZGFuIFwoXG1hdGhiZntXfV8xXCkgYmVyZGltZW5zaSBcKDJcdGltZXMzXCksIHNlaGluZ2dhIGhhc2lsIGxhcGlzYW4gbGluZWFyIHBlcnRhbWEgc2V0ZWxhaCBha3RpdmFzaSBSZUxVIGJlcmRpbWVuc2kgXCgyNVx0aW1lczNcKS4NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiB1bnR1ayB0b2tlbiBwZXJ0YW1hOioqDQoNClxbDQpcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1p9J18xKT0NClxiZWdpbntibWF0cml4fQ0KLTEuMDAgJiAxLjAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KU2ViZWx1bSBSZUxVOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1p9J18xKVxtYXRoYmZ7V31fMQ0KJj0NClxiZWdpbntibWF0cml4fQ0KLTEuMDAgJiAxLjAwDQpcZW5ke2JtYXRyaXh9DQpcYmVnaW57Ym1hdHJpeH0NCjAuNjAgJiAtMC4yMCAmIDAuNDBcXA0KLTAuMzAgJiAwLjUwICYgLTAuNDANClxlbmR7Ym1hdHJpeH1cXA0KJj0NClxiZWdpbntibWF0cml4fQ0KLTAuOTAgJiAwLjcwICYgLTAuODANClxlbmR7Ym1hdHJpeH0uDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpTZXRlbGFoIFJlTFU6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClxvcGVyYXRvcm5hbWV7UmVMVX0NClxsZWZ0KA0KXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntafSdfMSlcbWF0aGJme1d9XzENClxyaWdodCkNCiY9DQpcb3BlcmF0b3JuYW1le1JlTFV9DQpcbGVmdCgNClxiZWdpbntibWF0cml4fQ0KLTAuOTAgJiAwLjcwICYgLTAuODANClxlbmR7Ym1hdHJpeH0NClxyaWdodClcXA0KJj0NClxiZWdpbntibWF0cml4fQ0KMC4wMCAmIDAuNzAgJiAwLjAwDQpcZW5ke2JtYXRyaXh9Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KQXR1cmFuIHlhbmcgc2FtYSBkaXRlcmFwa2FuIHBhZGEgc2VsdXJ1aCB0b2tlbiwgc2VoaW5nZ2EgZGlwZXJvbGVoIGhhc2lsIGxhcGlzYW4gbGluZWFyIHBlcnRhbWEgc2V0ZWxhaCBha3RpdmFzaSBSZUxVIGJlcmlrdXQuDQoNClxbDQpcb3BlcmF0b3JuYW1le1JlTFV9DQpcbGVmdCgNClxvcGVyYXRvcm5hbWV7TE59KFxtYXRoYmZ7Wn0nKVxtYXRoYmZ7V31fMQ0KXHJpZ2h0KQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjAwICYgMC43MCAmIDAuMDBcXA0KMC4wMCAmIDAuNzAgJiAwLjAwXFwNCjAuOTAgJiAwLjAwICYgMC44MFxcDQowLjkwICYgMC4wMCAmIDAuODBcXA0KMC4wMCAmIDAuNzAgJiAwLjAwXFwNCjAuMDAgJiAwLjcwICYgMC4wMFxcDQowLjAwICYgMC43MCAmIDAuMDBcXA0KMC45MCAmIDAuMDAgJiAwLjgwXFwNCjAuOTAgJiAwLjAwICYgMC44MFxcDQowLjAwICYgMC43MCAmIDAuMDBcXA0KMC4wMCAmIDAuNzAgJiAwLjAwXFwNCjAuMDAgJiAwLjcwICYgMC4wMFxcDQowLjkwICYgMC4wMCAmIDAuODBcXA0KMC45MCAmIDAuMDAgJiAwLjgwXFwNCjAuMDAgJiAwLjcwICYgMC4wMFxcDQowLjAwICYgMC43MCAmIDAuMDBcXA0KMC4wMCAmIDAuNzAgJiAwLjAwXFwNCjAuOTAgJiAwLjAwICYgMC44MFxcDQowLjkwICYgMC4wMCAmIDAuODBcXA0KMC4wMCAmIDAuNzAgJiAwLjAwXFwNCjAuMDAgJiAwLjcwICYgMC4wMFxcDQowLjAwICYgMC43MCAmIDAuMDBcXA0KMC45MCAmIDAuMDAgJiAwLjgwXFwNCjAuMDAgJiAwLjcwICYgMC4wMFxcDQowLjAwICYgMC43MCAmIDAuMDANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQojIyMgay4gTGFwaXNhbiBMaW5lYXIgS2VkdWEgTUxQICgqRmVlZC1Gb3J3YXJkIE5ldHdvcmsqKQ0KDQpMYXBpc2FuIGxpbmVhciBrZWR1YSBNTFAgbWVtcHJveWVrc2lrYW4ga2VtYmFsaSBoYXNpbCBsYXBpc2FuIGxpbmVhciBwZXJ0YW1hIGRhcmkgdGlnYSBmaXR1ciBtZW5qYWRpIGR1YSBmaXR1ci4NCg0KLSAqKkJvYm90IGxhcGlzYW4gbGluZWFyIGtlZHVhOioqDQoNClxbDQpcbWF0aGJme1d9XzI9DQpcYmVnaW57Ym1hdHJpeH0NCjAuMzAgJiAtMC4yMFxcDQowLjIwICYgMC40MFxcDQotMC4xMCAmIDAuMzANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQotICoqUnVtdXM6KioNCg0KXFsNClxvcGVyYXRvcm5hbWV7UmVMVX0NClxsZWZ0KA0KXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntafScpXG1hdGhiZntXfV8xDQpccmlnaHQpDQpcbWF0aGJme1d9XzIuDQpcXQ0KDQpIYXNpbCBsYXBpc2FuIGxpbmVhciBwZXJ0YW1hIHNldGVsYWggYWt0aXZhc2kgUmVMVSBiZXJkaW1lbnNpIFwoMjVcdGltZXMzXCkgZGFuIFwoXG1hdGhiZntXfV8yXCkgYmVyZGltZW5zaSBcKDNcdGltZXMyXCksIHNlaGluZ2dhIGtlbHVhcmFuIGxhcGlzYW4gbGluZWFyIGtlZHVhIGJlcmRpbWVuc2kgXCgyNVx0aW1lczJcKS4NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiB1bnR1ayB0b2tlbiBwZXJ0YW1hOioqDQoNClxbDQpcb3BlcmF0b3JuYW1le1JlTFV9DQpcbGVmdCgNClxvcGVyYXRvcm5hbWV7TE59KFxtYXRoYmZ7Wn0nXzEpXG1hdGhiZntXfV8xDQpccmlnaHQpDQo9DQpcYmVnaW57Ym1hdHJpeH0NCjAuMDAgJiAwLjcwICYgMC4wMA0KXGVuZHtibWF0cml4fS4NClxdDQoNCk1ha2EsDQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClxvcGVyYXRvcm5hbWV7UmVMVX0NClxsZWZ0KA0KXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntafSdfMSlcbWF0aGJme1d9XzENClxyaWdodCkNClxtYXRoYmZ7V31fMg0KJj0NClxiZWdpbntibWF0cml4fQ0KMC4wMCAmIDAuNzAgJiAwLjAwDQpcZW5ke2JtYXRyaXh9DQpcYmVnaW57Ym1hdHJpeH0NCjAuMzAgJiAtMC4yMFxcDQowLjIwICYgMC40MFxcDQotMC4xMCAmIDAuMzANClxlbmR7Ym1hdHJpeH1cXA0KJj0NClxiZWdpbntibWF0cml4fQ0KKDAuMDApKDAuMzApKygwLjcwKSgwLjIwKSsoMC4wMCkoLTAuMTApICYNCigwLjAwKSgtMC4yMCkrKDAuNzApKDAuNDApKygwLjAwKSgwLjMwKQ0KXGVuZHtibWF0cml4fVxcDQomPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjE0ICYgMC4yOA0KXGVuZHtibWF0cml4fS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkF0dXJhbiB5YW5nIHNhbWEgZGl0ZXJhcGthbiBwYWRhIHNlbHVydWggdG9rZW4sIHNlaGluZ2dhIGRpcGVyb2xlaCBrZWx1YXJhbiBsYXBpc2FuIGxpbmVhciBrZWR1YSBNTFAgYmVyaWt1dC4NCg0KXFsNClxvcGVyYXRvcm5hbWV7UmVMVX0NClxsZWZ0KA0KXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntafScpXG1hdGhiZntXfV8xDQpccmlnaHQpDQpcbWF0aGJme1d9XzINCj0NClxiZWdpbntibWF0cml4fQ0KMC4xNCAmIDAuMjhcXA0KMC4xNCAmIDAuMjhcXA0KMC4xOSAmIDAuMDZcXA0KMC4xOSAmIDAuMDZcXA0KMC4xNCAmIDAuMjhcXA0KMC4xNCAmIDAuMjhcXA0KMC4xNCAmIDAuMjhcXA0KMC4xOSAmIDAuMDZcXA0KMC4xOSAmIDAuMDZcXA0KMC4xNCAmIDAuMjhcXA0KMC4xNCAmIDAuMjhcXA0KMC4xNCAmIDAuMjhcXA0KMC4xOSAmIDAuMDZcXA0KMC4xOSAmIDAuMDZcXA0KMC4xNCAmIDAuMjhcXA0KMC4xNCAmIDAuMjhcXA0KMC4xNCAmIDAuMjhcXA0KMC4xOSAmIDAuMDZcXA0KMC4xOSAmIDAuMDZcXA0KMC4xNCAmIDAuMjhcXA0KMC4xNCAmIDAuMjhcXA0KMC4xNCAmIDAuMjhcXA0KMC4xOSAmIDAuMDZcXA0KMC4xNCAmIDAuMjhcXA0KMC4xNCAmIDAuMjgNClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQoNCiMjIyBsLiBSZXNpZHVhbCBNTFAgKCpGZWVkLUZvcndhcmQgTmV0d29yayopDQoNClJlc2lkdWFsIE1MUCBtZW5nZ2FidW5na2FuIGtlbHVhcmFuIE1MUCBkZW5nYW4gcmVwcmVzZW50YXNpIFwoXG1hdGhiZntafSdcKSwgeWFpdHUga2VsdWFyYW4gZGFyaSByZXNpZHVhbCBhdHRlbnRpb24uIE9wZXJhc2kgaW5pIG1lbXBlcnRhaGFua2FuIGluZm9ybWFzaSBkYXJpIHRhaGFwIGF0dGVudGlvbiBzZXRlbGFoIE1MUCBtZW5hbWJhaGthbiB0cmFuc2Zvcm1hc2kgZml0dXIuDQoNCi0gKipSdW11czoqKg0KDQpcWw0KXG1hdGhiZntafQ0KPQ0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQpcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1p9JylcbWF0aGJme1d9XzENClxyaWdodCkNClxtYXRoYmZ7V31fMg0KKw0KXG1hdGhiZntafScuDQpcXQ0KDQpNYXRyaWtzIFwoXG9wZXJhdG9ybmFtZXtSZUxVfShcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1p9JylcbWF0aGJme1d9XzEpXG1hdGhiZntXfV8yXCkgZGFuIFwoXG1hdGhiZntafSdcKSBzYW1hLXNhbWEgYmVyZGltZW5zaSBcKDI1XHRpbWVzMlwpLCBzZWhpbmdnYSBcKFxtYXRoYmZ7Wn1cKSBiZXJkaW1lbnNpIFwoMjVcdGltZXMyXCkuDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gdW50dWsgdG9rZW4gcGVydGFtYToqKg0KDQpcWw0KXG1hdGhiZntafSdfMT0NClxiZWdpbntibWF0cml4fQ0KLTAuODkgJiAwLjc1DQpcZW5ke2JtYXRyaXh9LA0KXF0NCg0KXFsNClxvcGVyYXRvcm5hbWV7UmVMVX0NClxsZWZ0KA0KXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntafSdfMSlcbWF0aGJme1d9XzENClxyaWdodCkNClxtYXRoYmZ7V31fMg0KPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjE0ICYgMC4yOA0KXGVuZHtibWF0cml4fS4NClxdDQoNCk1ha2EsDQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClxtYXRoYmZ7Wn1fMQ0KJj0NClxvcGVyYXRvcm5hbWV7UmVMVX0NClxsZWZ0KA0KXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntafSdfMSlcbWF0aGJme1d9XzENClxyaWdodCkNClxtYXRoYmZ7V31fMg0KKw0KXG1hdGhiZntafSdfMVxcDQomPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjE0ICYgMC4yOA0KXGVuZHtibWF0cml4fQ0KKw0KXGJlZ2lue2JtYXRyaXh9DQotMC44OSAmIDAuNzUNClxlbmR7Ym1hdHJpeH1cXA0KJj0NClxiZWdpbntibWF0cml4fQ0KLTAuNzUgJiAxLjAzDQpcZW5ke2JtYXRyaXh9Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KQXR1cmFuIHlhbmcgc2FtYSBkaXRlcmFwa2FuIHBhZGEgc2VsdXJ1aCB0b2tlbiwgc2VoaW5nZ2EgZGlwZXJvbGVoIG1hdHJpa3MgXChcbWF0aGJme1p9XCkgYmVyaWt1dC4NCg0KXFsNClxtYXRoYmZ7Wn09XGJlZ2lue2JtYXRyaXh9DQotMC43NSAmIDEuMDNcXA0KLTAuNzMgJiAxLjAyXFwNCjAuODEgJiAtMC4yOFxcDQowLjUxICYgLTAuMTNcXA0KLTAuNzUgJiAxLjA0XFwNCi0wLjc0ICYgMS4wM1xcDQotMC43MSAmIDEuMDJcXA0KMS4xMiAmIC0wLjQzXFwNCjAuNzEgJiAtMC4yM1xcDQotMC43NSAmIDEuMDRcXA0KLTAuNzQgJiAxLjAzXFwNCi0wLjcxICYgMS4wMVxcDQoxLjEyICYgLTAuNDNcXA0KMC43MSAmIC0wLjIzXFwNCi0wLjc1ICYgMS4wNFxcDQotMC43NCAmIDEuMDNcXA0KLTAuNzMgJiAxLjAzXFwNCjAuODUgJiAtMC4zMFxcDQowLjQ5ICYgLTAuMTJcXA0KLTAuNzYgJiAxLjA0XFwNCi0wLjc1ICYgMS4wNFxcDQotMC43NSAmIDEuMDRcXA0KMC4zNSAmIC0wLjA1XFwNCi0wLjU3ICYgMC45NFxcDQotMC43NiAmIDEuMDQNClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQojIyMgbS4gTm9ybWFsaXNhc2kgS2VsdWFyYW4gVHJhbnNmb3JtZXINCg0KVGFoYXAgdGVyYWtoaXIgVHJhbnNmb3JtZXIgYWRhbGFoIG5vcm1hbGlzYXNpIHBlciB0b2tlbiB0ZXJoYWRhcCBtYXRyaWtzIGtlbHVhcmFuIHJlc2lkdWFsIE1MUCBcKFxtYXRoYmZ7Wn1cKS4gTWF0cmlrcyBoYXNpbCBcKFxtYXRoYmZ7R31cKSBtZXJ1cGFrYW4gcmVwcmVzZW50YXNpIGdsb2JhbCB5YW5nIGFrYW4gZGlsaXBhdCBrZW1iYWxpIGtlIGJlbnR1ayBzcGFzaWFsIHBhZGEgdGFoYXAgYmVyaWt1dG55YS4NCg0KLSAqKlJ1bXVzOioqDQoNClxbDQpHX3t0LGt9DQo9DQpcZnJhY3taX3t0LGt9LVxtdV97Wix0fX0NCntcc3FydHtcc2lnbWFfe1osdH1eezJ9KzEwXnstNX19fS4NClxdDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gdW50dWsgdG9rZW4gcGVydGFtYToqKg0KDQpcWw0KXG1hdGhiZntafV97MX09DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjc1ICYgMS4wMw0KXGVuZHtibWF0cml4fS4NClxdDQoNClJhdGEtcmF0YSB0b2tlbiBwZXJ0YW1hIGFkYWxhaDoNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KXG11X3taLDF9DQomPVxmcmFjey0wLjc1KzEuMDN9ezJ9XFwNCiY9MC4xNC4NClxlbmR7YWxpZ25lZH0NClxdDQoNClZhcmlhbnNueWEgYWRhbGFoOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcc2lnbWFfe1osMX1eMg0KJj1cZnJhY3soLTAuNzUtMC4xNCleMisoMS4wMy0wLjE0KV4yfXsyfVxcDQomPVxmcmFjeygtMC44OSleMisoMC44OSleMn17Mn1cXA0KJj0wLjc5MjEuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpFbGVtZW4gcGVydGFtYSBzZXRlbGFoIG5vcm1hbGlzYXNpIGFkYWxhaDoNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KR197MSwxfQ0KJj1cZnJhY3stMC43NS0wLjE0fXtcc3FydHswLjc5MjErMTBeey01fX19XFwNCiY9XGZyYWN7LTAuODl9ezAuODl9XFwNCiY9LTEuMDAuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gY2FyYSB5YW5nIHNhbWEsIFwoR197MSwyfT0xLjAwXCkuIE1ha2E6DQoNClxbDQpcbWF0aGJme0d9X3sxfT0NClxiZWdpbntibWF0cml4fQ0KLTEuMDAgJiAxLjAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KQXR1cmFuIHlhbmcgc2FtYSBkaXRlcmFwa2FuIHBhZGEgc2VsdXJ1aCB0b2tlbiwgc2VoaW5nZ2EgZGlwZXJvbGVoIHJlcHJlc2VudGFzaSBnbG9iYWwgVHJhbnNmb3JtZXIgXChcbWF0aGJme0d9XCkgYmVyaWt1dC4NCg0KXFsNClxtYXRoYmZ7R30NCj1cYmVnaW57Ym1hdHJpeH0NCi0xLjAwICYgMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KMS4wMCAmIC0xLjAwXFwNCjEuMDAgJiAtMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMFxcDQoxLjAwICYgLTEuMDBcXA0KMS4wMCAmIC0xLjAwXFwNCi0xLjAwICYgMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCjEuMDAgJiAtMS4wMFxcDQoxLjAwICYgLTEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KMS4wMCAmIC0xLjAwXFwNCjEuMDAgJiAtMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMFxcDQoxLjAwICYgLTEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMA0KXGVuZHtibWF0cml4fS4NClxdDQoNCg0KIyMgNC4gRm9sZGluZywgUHJveWVrc2kgRml0dXIgR2xvYmFsLCBkYW4gRnVzaSBSZXNpZHVhbA0KDQpLZWx1YXJhbiBUcmFuc2Zvcm1lciBcKFxtYXRoYmZ7R31cKSBtYXNpaCBiZXJiZW50dWsgbWF0cmlrcyB0b2tlbiBiZXJkaW1lbnNpIFwoMjVcdGltZXMyXCkuIFRhaGFwICpmb2xkaW5nKiBtZW5nZW1iYWxpa2FuIHRva2VuIHRlcnNlYnV0IGtlIHN1c3VuYW4gc3Bhc2lhbCBcKDVcdGltZXM1XCkuIFNldGVsYWggaXR1LCBrZWR1YSBrYW5hbCBoYXNpbCAqZm9sZGluZyogZGlwcm95ZWtzaWthbiBtZW5qYWRpIHNhdHUgKmZlYXR1cmUgbWFwKiBnbG9iYWwgZGFuIGRpYWt0aWZrYW4gbWVuZ2d1bmFrYW4gZnVuZ3NpIFN3aXNoLiAqRmVhdHVyZSBtYXAqIGdsb2JhbCB0ZXJzZWJ1dCBrZW11ZGlhbiBkaWZ1c2lrYW4gZGVuZ2FuICpmZWF0dXJlIG1hcCogbG9rYWwgXChcbWF0aGJme0x9XCkgZGFuICpmZWF0dXJlIG1hcCogbWFzdWthbiBcKFxtYXRoYmZ7WH1cKS4NCg0KIyMjIGEuIEZvbGRpbmcgS2VsdWFyYW4gVHJhbnNmb3JtZXINCg0KKkZvbGRpbmcqIG1lbmVtcGF0a2FuIGtlbWJhbGkgdG9rZW4ga2UtXCh0XCkgcGFkYSBwb3Npc2kgc3Bhc2lhbCBcKChpLGopXCkgYmVyZGFzYXJrYW4gdXJ1dGFuIHJhc3RlciBkYXJpIGtpcmkga2Uga2FuYW4gZGFuIGRhcmkgYXRhcyBrZSBiYXdhaDoNCg0KXFsNCnQ9VyhpLTEpK2osDQpccXF1YWQgVz01Lg0KXF0NCg0KS29sb20gcGVydGFtYSBkYXJpIG1hdHJpa3MgdG9rZW4gXChcbWF0aGJme0d9XCkgZGlsaXBhdCBtZW5qYWRpIGthbmFsIHBlcnRhbWEgXChcbWF0aGJme0d9XzFcKSwgc2VkYW5na2FuIGtvbG9tIGtlZHVhIGRpbGlwYXQgbWVuamFkaSBrYW5hbCBrZWR1YSBcKFxtYXRoYmZ7R31fMlwpLiBLZWR1YSBtYXRyaWtzIGhhc2lsICpmb2xkaW5nKiBtZW1pbGlraSBkaW1lbnNpIFwoNVx0aW1lczVcKS4NCg0KLSAqKlJ1bXVzOioqDQoNClxbDQpHX3tuLGksan09R197dCxufSwNClxxcXVhZA0Kbj0xLDIsDQpccXF1YWQNCnQ9VyhpLTEpK2ouDQpcXQ0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuIHBhZGEgcG9zaXNpIFwoKDEsMSlcKToqKg0KDQpQb3Npc2kgXCgoMSwxKVwpIGJlcnNlc3VhaWFuIGRlbmdhbiB0b2tlbiBwZXJ0YW1hOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQp0Jj01KDEtMSkrMVxcDQomPTEuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpLYXJlbmEgdG9rZW4gcGVydGFtYSBhZGFsYWg6DQoNClxbDQpcbWF0aGJme0d9X3t0PTF9PQ0KXGJlZ2lue2JtYXRyaXh9DQotMS4wMCAmIDEuMDANClxlbmR7Ym1hdHJpeH0sDQpcXQ0KDQptYWthIGhhc2lsICpmb2xkaW5nKiBwYWRhIHBvc2lzaSBcKCgxLDEpXCkgYWRhbGFoOg0KDQpcWw0KR197MSwxLDF9PUdfezEsMX09LTEuMDAsDQpccXF1YWQNCkdfezIsMSwxfT1HX3sxLDJ9PTEuMDAuDQpcXQ0KDQpNYXRyaWtzIGthbmFsIHBlcnRhbWEgc2V0ZWxhaCAqZm9sZGluZyogYWRhbGFoOg0KDQpcWw0KXG1hdGhiZntHfV8xPQ0KXGJlZ2lue2JtYXRyaXh9DQotMS4wMCAmIC0xLjAwICYgMS4wMCAmIDEuMDAgJiAtMS4wMFxcDQotMS4wMCAmIC0xLjAwICYgMS4wMCAmIDEuMDAgJiAtMS4wMFxcDQotMS4wMCAmIC0xLjAwICYgMS4wMCAmIDEuMDAgJiAtMS4wMFxcDQotMS4wMCAmIC0xLjAwICYgMS4wMCAmIDEuMDAgJiAtMS4wMFxcDQotMS4wMCAmIC0xLjAwICYgMS4wMCAmIC0xLjAwICYgLTEuMDANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQpNYXRyaWtzIGthbmFsIGtlZHVhIHNldGVsYWggKmZvbGRpbmcqIGFkYWxhaDoNCg0KXFsNClxtYXRoYmZ7R31fMj0NClxiZWdpbntibWF0cml4fQ0KMS4wMCAmIDEuMDAgJiAtMS4wMCAmIC0xLjAwICYgMS4wMFxcDQoxLjAwICYgMS4wMCAmIC0xLjAwICYgLTEuMDAgJiAxLjAwXFwNCjEuMDAgJiAxLjAwICYgLTEuMDAgJiAtMS4wMCAmIDEuMDBcXA0KMS4wMCAmIDEuMDAgJiAtMS4wMCAmIC0xLjAwICYgMS4wMFxcDQoxLjAwICYgMS4wMCAmIC0xLjAwICYgMS4wMCAmIDEuMDANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQojIyMgYi4gUHJveWVrc2kgZGFuIEFrdGl2YXNpIEZpdHVyIEdsb2JhbA0KDQpLZWR1YSBrYW5hbCBoYXNpbCAqZm9sZGluZyosIHlhaXR1IFwoXG1hdGhiZntHfV8xXCkgZGFuIFwoXG1hdGhiZntHfV8yXCksIGRpcHJveWVrc2lrYW4gbWVuamFkaSBzYXR1ICpmZWF0dXJlIG1hcCogZ2xvYmFsIG1lbmdndW5ha2FuICpwb2ludHdpc2UgY29udm9sdXRpb24qIFwoMVx0aW1lczFcKS4gUGFkYSBpbHVzdHJhc2kgaW5pLCBiaWFzIHRpZGFrIGRpZ3VuYWthbi4gQm9ib3QgKnBvaW50d2lzZSBjb252b2x1dGlvbiogdW50dWsgcHJveWVrc2kgZ2xvYmFsIGRpdGV0YXBrYW4gc2ViYWdhaToNCg0KXFsNClxtYXRoYmZ7V31fe1xtYXRocm17cHd9fV57KFxtYXRocm17Z2xvYn0pfQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjYwICYgLTAuNDANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQotICoqUnVtdXM6KioNCg0KXFsNCkZfe1xtYXRocm17cHd9LGksaiwxfV57KFxtYXRocm17Z2xvYn0pfQ0KPQ0KXHN1bV97bj0xfV57Mn0NCldfe1xtYXRocm17cHd9LG4sMX1eeyhcbWF0aHJte2dsb2J9KX0NCkdfe24saSxqfS4NClxdDQoNCkJlcmRhc2Fya2FuIGJvYm90IHlhbmcgZGlndW5ha2FuLCBkaXBlcm9sZWg6DQoNClxbDQpGX3tcbWF0aHJte3B3fSxpLGosMX1eeyhcbWF0aHJte2dsb2J9KX0NCj0NCjAuNjBHX3sxLGksan0tMC40MEdfezIsaSxqfS4NClxdDQoNCktlbHVhcmFuIHByb3lla3NpIGtlbXVkaWFuIGRpYWt0aWZrYW4gbWVuZ2d1bmFrYW4gZnVuZ3NpIFN3aXNoOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpHX3tcbWF0aHJte2dsb2JhbH0saSxqfQ0KJj0NClxvcGVyYXRvcm5hbWV7U3dpc2h9DQpcbGVmdCgNCkZfe1xtYXRocm17cHd9LGksaiwxfV57KFxtYXRocm17Z2xvYn0pfQ0KXHJpZ2h0KVxcDQomPQ0KXGZyYWN7Rl97XG1hdGhybXtwd30saSxqLDF9XnsoXG1hdGhybXtnbG9ifSl9fQ0KezErZV57LUZfe1xtYXRocm17cHd9LGksaiwxfV57KFxtYXRocm17Z2xvYn0pfX19Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KTWF0cmlrcyBcKFxtYXRoYmZ7Rn1fe1xtYXRocm17cHd9fV57KFxtYXRocm17Z2xvYn0pfVwpIGRhbiBcKFxtYXRoYmZ7R31fe1xtYXRocm17Z2xvYmFsfX1cKSBrZWR1YW55YSBiZXJkaW1lbnNpIFwoNVx0aW1lczVcKS4NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiBwYWRhIHBvc2lzaSBcKCgxLDEpXCk6KioNCg0KRGlrZXRhaHVpOg0KDQpcWw0KR197MSwxLDF9PS0xLjAwLA0KXHFxdWFkDQpHX3syLDEsMX09MS4wMC4NClxdDQoNCk5pbGFpIGhhc2lsICpwb2ludHdpc2UgY29udm9sdXRpb24qIHNlYmVsdW0gYWt0aXZhc2kgYWRhbGFoOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpGX3tcbWF0aHJte3B3fSwxLDEsMX1eeyhcbWF0aHJte2dsb2J9KX0NCiY9DQowLjYwR197MSwxLDF9LTAuNDBHX3syLDEsMX1cXA0KJj0NCjAuNjAoLTEuMDApLTAuNDAoMS4wMClcXA0KJj0NCi0wLjYwLTAuNDBcXA0KJj0NCi0xLjAwLg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KU2VsYW5qdXRueWEsIG5pbGFpIHRlcnNlYnV0IGRpYWt0aWZrYW4gbWVuZ2d1bmFrYW4gZnVuZ3NpIFN3aXNoOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpHX3tcbWF0aHJte2dsb2JhbH0sMSwxfQ0KJj0NClxmcmFje0Zfe1xtYXRocm17cHd9LDEsMSwxfV57KFxtYXRocm17Z2xvYn0pfX0NCnsxK2Veey1GX3tcbWF0aHJte3B3fSwxLDEsMX1eeyhcbWF0aHJte2dsb2J9KX19fVxcDQomPQ0KXGZyYWN7LTEuMDB9ezErZV57LSgtMS4wMCl9fVxcDQomPQ0KXGZyYWN7LTEuMDB9ezErZV57MS4wMH19XFwNCiY9DQpcZnJhY3stMS4wMH17MSsyLjcyfVxcDQomPQ0KLTAuMjcuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gcGVyaGl0dW5nYW4geWFuZyBzYW1hIHVudHVrIHNlbHVydWggcG9zaXNpLCBkaXBlcm9sZWggKmZlYXR1cmUgbWFwKiBnbG9iYWw6DQoNClxbDQpcbWF0aGJme0d9X3tcbWF0aHJte2dsb2JhbH19PQ0KXGJlZ2lue2JtYXRyaXh9DQotMC4yNyAmIC0wLjI3ICYgMC43MyAmIDAuNzMgJiAtMC4yN1xcDQotMC4yNyAmIC0wLjI3ICYgMC43MyAmIDAuNzMgJiAtMC4yN1xcDQotMC4yNyAmIC0wLjI3ICYgMC43MyAmIDAuNzMgJiAtMC4yN1xcDQotMC4yNyAmIC0wLjI3ICYgMC43MyAmIDAuNzMgJiAtMC4yN1xcDQotMC4yNyAmIC0wLjI3ICYgMC43MyAmIC0wLjI3ICYgLTAuMjcNClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQojIyMgYy4gRnVzaSBSZXNpZHVhbCBGaXR1ciBMb2thbCBkYW4gR2xvYmFsDQoNCipGZWF0dXJlIG1hcCogbWFzdWthbiBcKFxtYXRoYmZ7WH1cKSwgZml0dXIgbG9rYWwgXChcbWF0aGJme0x9XCksIGRhbiAqZmVhdHVyZSBtYXAqIGdsb2JhbCBcKFxtYXRoYmZ7R31fe1xtYXRocm17Z2xvYmFsfX1cKSBkaWdhYnVuZ2thbiBtZWxhbHVpIGZ1c2kgcmVzaWR1YWwuIFBhZGEgaWx1c3RyYXNpIGluaSwgKnBvaW50d2lzZSBjb252b2x1dGlvbiogXCgxXHRpbWVzMVwpIG1lbXByb3lla3Npa2FuIGZpdHVyIGxva2FsIGRhbiBmaXR1ciBnbG9iYWwgbWVuamFkaSBzYXR1IGthbmFsLCBrZW11ZGlhbiBoYXNpbG55YSBkaXRhbWJhaGthbiBkZW5nYW4gZml0dXIgbWFzdWthbiBcKFxtYXRoYmZ7WH1cKS4NCg0KLSAqKkJvYm90IGZ1c2k6KioNCg0KXFsNClxtYXRoYmZ7V31fe1xtYXRocm17cHd9fV57KFxtYXRocm17ZnVzZX0pfQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjUwICYgMC41MA0KXGVuZHtibWF0cml4fS4NClxdDQoNCi0gKipSdW11czoqKg0KDQpcWw0KRl97XG1hdGhybXtwd30saSxqLDF9XnsoXG1hdGhybXtmdXNlfSl9DQo9DQowLjUwTF97aSxqfQ0KKw0KMC41MEdfe1xtYXRocm17Z2xvYmFsfSxpLGp9Lg0KXF0NCg0KXFsNClhfe2ksan1eeygwLDApfQ0KPQ0KWF97aSxqfQ0KKw0KRl97XG1hdGhybXtwd30saSxqLDF9XnsoXG1hdGhybXtmdXNlfSl9Lg0KXF0NCg0KU2VjYXJhIGtlc2VsdXJ1aGFuLCBwcm9zZXMgZnVzaSByZXNpZHVhbCBkaXJ1bXVza2FuIHNlYmFnYWk6DQoNClxbDQpcbWF0aGJme1h9XnsoMCwwKX0NCj0NClxtYXRoYmZ7WH0NCisNClxvcGVyYXRvcm5hbWV7Q29udn1fezFcdGltZXMxfV57KFxtYXRocm17ZnVzZX0pfQ0KXGxlZnQoDQpcb3BlcmF0b3JuYW1le0NvbmNhdH0NClxsZWZ0Ww0KXG1hdGhiZntMfSwNClxtYXRoYmZ7R31fe1xtYXRocm17Z2xvYmFsfX0NClxyaWdodF0NClxyaWdodCkuDQpcXQ0KDQpTZWx1cnVoIG1hdHJpa3MgcGFkYSBvcGVyYXNpIHRlcnNlYnV0IGJlcmRpbWVuc2kgXCg1XHRpbWVzNVwpLCBzZWhpbmdnYSBoYXNpbCBmdXNpIFwoXG1hdGhiZntYfV57KDAsMCl9XCkganVnYSBiZXJkaW1lbnNpIFwoNVx0aW1lczVcKS4NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiBwYWRhIHBvc2lzaSBcKCgxLDEpXCk6KioNCg0KRGlrZXRhaHVpOg0KDQpcWw0KWF97MSwxfT0tMi4xMiwNClxxcXVhZA0KTF97MSwxfT0tMC4yNywNClxxcXVhZA0KR197XG1hdGhybXtnbG9iYWx9LDEsMX09LTAuMjcuDQpcXQ0KDQpOaWxhaSBrZWx1YXJhbiAqcG9pbnR3aXNlIGNvbnZvbHV0aW9uKiBhZGFsYWg6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NCkZfe1xtYXRocm17cHd9LDEsMSwxfV57KFxtYXRocm17ZnVzZX0pfQ0KJj0NCjAuNTBMX3sxLDF9DQorDQowLjUwR197XG1hdGhybXtnbG9iYWx9LDEsMX1cXA0KJj0NCjAuNTAoLTAuMjcpDQorDQowLjUwKC0wLjI3KVxcDQomPQ0KLTAuMTM1LTAuMTM1XFwNCiY9DQotMC4yNy4NClxlbmR7YWxpZ25lZH0NClxdDQoNCk1ha2EsIGhhc2lsIGZ1c2kgcmVzaWR1YWwgcGFkYSBwb3Npc2kgXCgoMSwxKVwpIGFkYWxhaDoNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KWF97MSwxfV57KDAsMCl9DQomPQ0KWF97MSwxfQ0KKw0KRl97XG1hdGhybXtwd30sMSwxLDF9XnsoXG1hdGhybXtmdXNlfSl9XFwNCiY9DQotMi4xMisoLTAuMjcpXFwNCiY9DQotMi4zOS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkF0dXJhbiB5YW5nIHNhbWEgZGl0ZXJhcGthbiBwYWRhIHNlbHVydWggcG9zaXNpLiBEZW5nYW4gbWVuZ2d1bmFrYW4gbmlsYWkgXChcbWF0aGJme0d9X3tcbWF0aHJte2dsb2JhbH19XCkgeWFuZyB0ZWxhaCBkaWJ1bGF0a2FuIGhpbmdnYSBkdWEgYW5na2EgZGkgYmVsYWthbmcga29tYSwgZGlwZXJvbGVoICpmZWF0dXJlIG1hcCogaGFzaWwgZnVzaSBiZXJpa3V0Og0KDQpcWw0KXG1hdGhiZntYfV57KDAsMCl9DQo9DQpcYmVnaW57Ym1hdHJpeH0NCi0yLjM5ICYgLTEuMjggJiAxLjgyICYgMS4xMiAmIC0xLjg0XFwNCi0yLjM4ICYgLTEuMDAgJiAyLjI0ICYgMS41MCAmIC0xLjcwXFwNCi0yLjM4ICYgLTEuMDAgJiAyLjI0ICYgMS41MCAmIC0xLjcwXFwNCi0yLjM4ICYgLTEuMTQgJiAxLjg0ICYgMS4xMSAmIC0xLjg1XFwNCi0yLjI1ICYgLTEuNTcgJiAwLjc3ICYgLTAuMzggJiAtMS45OQ0KXGVuZHtibWF0cml4fS4NClxdDQoNCg0KIyMgNS4gRW5jb2RlciBCZXJ0aW5na2F0IA0KDQojIyMgYS4gRG93bnNhbXBsaW5nIEVuY29kZXIgUGVydGFtYSAoXChcbWF0aGJme1h9XnsxLDB9XCkpDQoNCipGZWF0dXJlIG1hcCogbWFzdWthbiBcKFxtYXRoYmZ7WH1eezAsMH1cKSBiZXJ1a3VyYW4gXCg1XHRpbWVzNVwpIGRpcHJvc2VzIG1lbmdndW5ha2FuICpzdHJpZGVkIGNvbnZvbHV0aW9uKiBkZW5nYW4ga2VybmVsIFwoM1x0aW1lczNcKSwgKnN0cmlkZSogXCgyXCksICp6ZXJvIHBhZGRpbmcqIHNlYmVzYXIgXCgxXCkgcGFkYSBzZXRpYXAgc2lzaSwgZGFuIHRhbnBhIGJpYXMgdW50dWsgbWVuZ2hhc2lsa2FuICpmZWF0dXJlIG1hcCogXChcbWF0aGJme1h9XnsxLDB9XCkuDQoNCk1hdHJpa3MgKmZlYXR1cmUgbWFwKiBtYXN1a2FuIHlhbmcgZGlndW5ha2FuIGFkYWxhaDoNCg0KXFsNClxtYXRoYmZ7WH1eezAsMH0NCj0NClxiZWdpbntibWF0cml4fQ0KLTIuMzkgJiAtMS4yOCAmIDEuODIgJiAxLjEyICYgLTEuODRcXA0KLTIuMzggJiAtMS4wMCAmIDIuMjQgJiAxLjUwICYgLTEuNzBcXA0KLTIuMzggJiAtMS4wMCAmIDIuMjQgJiAxLjUwICYgLTEuNzBcXA0KLTIuMzggJiAtMS4xNCAmIDEuODQgJiAxLjExICYgLTEuODVcXA0KLTIuMjUgJiAtMS41NyAmIDAuNzcgJiAtMC4zOCAmIC0xLjk5DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KVWt1cmFuIGtlbHVhcmFuICpzdHJpZGVkIGNvbnZvbHV0aW9uKiBkaWhpdHVuZyBtZW5nZ3VuYWthbjoNCg0KXFsNCm8NCj0NClxsZWZ0XGxmbG9vcg0KXGZyYWN7aSsycC1rfXtzfQ0KXHJpZ2h0XHJmbG9vcisxLA0KXF0NCg0KZGVuZ2FuIFwoaVwpIG1lbnlhdGFrYW4gdWt1cmFuIHNwYXNpYWwgbWFzdWthbiwgXChwXCkgbWVydXBha2FuIGp1bWxhaCAqcGFkZGluZyogcGFkYSBzZXRpYXAgc2lzaSwgXChrXCkgbWVydXBha2FuIHVrdXJhbiBrZXJuZWwsIGRhbiBcKHNcKSBtZXJ1cGFrYW4gKnN0cmlkZSouDQoNClBhZGEgaWx1c3RyYXNpIGluaSwgZGlndW5ha2FuIFwoaT01XCksIFwoaz0zXCksIFwocD0xXCksIGRhbiBcKHM9MlwpLCBzZWhpbmdnYToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0Kbw0KJj0NClxsZWZ0XGxmbG9vcg0KXGZyYWN7NSsyKDEpLTN9ezJ9DQpccmlnaHRccmZsb29yKzFcXA0KJj0NClxsZWZ0XGxmbG9vcg0KXGZyYWN7NH17Mn0NClxyaWdodFxyZmxvb3IrMVxcDQomPTMuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gZGVtaWtpYW4sIHVrdXJhbiBzcGFzaWFsICpmZWF0dXJlIG1hcCogYmVya3VyYW5nIGRhcmkgXCg1XHRpbWVzNVwpIG1lbmphZGkgXCgzXHRpbWVzM1wpLg0KDQotICoqUGVuYW1iYWhhbiBaZXJvIFBhZGRpbmc6KioNCg0KU2ViZWx1bSBvcGVyYXNpIGtvbnZvbHVzaSBkaWxha3VrYW4sIHNhdHUgbGFwaXNhbiBuaWxhaSBub2wgZGl0YW1iYWhrYW4gcGFkYSBrZWVtcGF0IHNpc2kgbWF0cmlrcyBtYXN1a2FuLCB5YWl0dSBzaXNpIGF0YXMsIGJhd2FoLCBraXJpLCBkYW4ga2FuYW4uIFBlbmFtYmFoYW4gKnBhZGRpbmcqIGluaSBtZW5ndWJhaCB1a3VyYW4gbWF0cmlrcyBkYXJpIFwoNVx0aW1lczVcKSBtZW5qYWRpIFwoN1x0aW1lczdcKS4NCg0KTWF0cmlrcyBzZXRlbGFoIHBlbmFtYmFoYW4gKnplcm8gcGFkZGluZyogYWRhbGFoOg0KDQpcWw0KXG1hdGhiZntYfV97XG1hdGhybXtwYWR9fV57MCwwfQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjAwICYgMC4wMCAmIDAuMDAgJiAwLjAwICYgMC4wMCAmIDAuMDAgJiAwLjAwXFwNCjAuMDAgJiAtMi4zOSAmIC0xLjI4ICYgMS44MiAmIDEuMTIgJiAtMS44NCAmIDAuMDBcXA0KMC4wMCAmIC0yLjM4ICYgLTEuMDAgJiAyLjI0ICYgMS41MCAmIC0xLjcwICYgMC4wMFxcDQowLjAwICYgLTIuMzggJiAtMS4wMCAmIDIuMjQgJiAxLjUwICYgLTEuNzAgJiAwLjAwXFwNCjAuMDAgJiAtMi4zOCAmIC0xLjE0ICYgMS44NCAmIDEuMTEgJiAtMS44NSAmIDAuMDBcXA0KMC4wMCAmIC0yLjI1ICYgLTEuNTcgJiAwLjc3ICYgLTAuMzggJiAtMS45OSAmIDAuMDBcXA0KMC4wMCAmIDAuMDAgJiAwLjAwICYgMC4wMCAmIDAuMDAgJiAwLjAwICYgMC4wMA0KXGVuZHtibWF0cml4fS4NClxdDQoNCi0gKipLZXJuZWwgRW5jb2RlciBQZXJ0YW1hOioqDQoNClBhZGEgaWx1c3RyYXNpIGluaSwgbWF0cmlrcyBib2JvdCBrZXJuZWwgZW5jb2RlciBwZXJ0YW1hIGRpdGV0YXBrYW4gc2ViYWdhaToNCg0KXFsNClxtYXRoYmZ7V31fe1xtYXRocm17ZW5jfX1eeygxKX0NCj0NClxiZWdpbntibWF0cml4fQ0KMC4wMCAmIDAuMDAgJiAwLjAwXFwNCjAuMDAgJiAxLjAwICYgMC4wMFxcDQowLjAwICYgMC4wMCAmIDAuMDANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQpLZXJuZWwgdGVyc2VidXQgbWVtaWxpa2kgc2F0dSBib2JvdCBiZXJuaWxhaSBcKDEuMDBcKSBwYWRhIHBvc2lzaSB0ZW5nYWgsIHNlZGFuZ2thbiBkZWxhcGFuIGJvYm90IGxhaW5ueWEgYmVybmlsYWkgXCgwLjAwXCkuIE9sZWgga2FyZW5hIGl0dSwgc2V0aWFwIGhhc2lsIGtvbnZvbHVzaSBkaXBlcm9sZWggbWVsYWx1aSBwZXJrYWxpYW4gc2VtYmlsYW4gZWxlbWVuIHBhZGEgYXJlYSAqZmVhdHVyZSBtYXAqIGRlbmdhbiBzZW1iaWxhbiBib2JvdCBrZXJuZWwsIGtlbXVkaWFuIHNlbHVydWggaGFzaWwgcGVya2FsaWFuIGRpanVtbGFoa2FuLg0KDQotICoqUnVtdXM6KioNCg0KT3BlcmFzaSAqc3RyaWRlZCBjb252b2x1dGlvbiogZGlydW11c2thbiBzZWJhZ2FpOg0KDQpcWw0KXG1hdGhiZntYfV57MSwwfQ0KPQ0KXG9wZXJhdG9ybmFtZXtDb252fV97M1x0aW1lczMsXCxzPTIsXCxwPTF9DQpcbGVmdCgNClxtYXRoYmZ7WH1eezAsMH07DQpcbWF0aGJme1d9X3tcbWF0aHJte2VuY319XnsoMSl9DQpccmlnaHQpLg0KXF0NCg0KVW50dWsgZWxlbWVuIGtlbHVhcmFuIHBhZGEgYmFyaXMga2UtXChyXCkgZGFuIGtvbG9tIGtlLVwoY1wpLCBwZXJoaXR1bmdhbiBrb252b2x1c2kgZGFwYXQgZGlueWF0YWthbiBzZWJhZ2FpOg0KDQpcWw0KWF97cixjfV57MSwwfQ0KPQ0KXHN1bV97YT0xfV57M30NClxzdW1fe2I9MX1eezN9DQpXX3tcbWF0aHJte2VuY30sYSxifV57KDEpfQ0KWF97XG1hdGhybXtwYWR9LFwsMnIrYS0yLFwsMmMrYi0yfV57MCwwfSwNClxdDQoNCmRlbmdhbiBcKHIsYz0xLDIsM1wpLCBzZWRhbmdrYW4gXChhXCkgZGFuIFwoYlwpIG1lcnVwYWthbiBpbmRla3MgYmFyaXMgZGFuIGtvbG9tIGtlcm5lbC4NCg0KUGFkYSBzZXRpYXAgcG9zaXNpLCBrZXJuZWwgbWVuY2FrdXAgYXJlYSBiZXJ1a3VyYW4gXCgzXHRpbWVzM1wpLiBLYXJlbmEgKnN0cmlkZSogYmVybmlsYWkgXCgyXCksIGtlcm5lbCBiZXJnZXNlciBkdWEga29sb20ga2Uga2FuYW4gdW50dWsgbWVuZ2hpdHVuZyBlbGVtZW4gYmVyaWt1dG55YSBwYWRhIGJhcmlzIGtlbHVhcmFuIHlhbmcgc2FtYS4gU2V0ZWxhaCBtZW5jYXBhaSBwb3Npc2kgdGVyYWtoaXIgcGFkYSBiYXJpcyB0ZXJzZWJ1dCwga2VybmVsIGtlbWJhbGkga2Ugc2lzaSBraXJpIGRhbiBiZXJnZXNlciBkdWEgYmFyaXMga2UgYmF3YWguDQoNCi0gKipDb250b2ggUGVyaGl0dW5nYW4gS29udm9sdXNpOioqDQoNCioqMS4gUGVyaGl0dW5nYW4gZWxlbWVuIHBhZGEgcG9zaXNpIFwoKDEsMSlcKSoqDQoNClVudHVrIG1lbmdoYXNpbGthbiBlbGVtZW4gcGVydGFtYSBcKFxtYXRoYmZ7WH1eezEsMH1cKSwga2VybmVsIGRpdGVtcGF0a2FuIHBhZGEgYXJlYSBcKDNcdGltZXMzXCkgZGkgcG9qb2sga2lyaSBhdGFzIG1hdHJpa3MgeWFuZyB0ZWxhaCBkaWJlcmkgKnBhZGRpbmcqLg0KDQpBcmVhICpmZWF0dXJlIG1hcCogeWFuZyBkaXByb3NlcyBhZGFsYWg6DQoNClxbDQpcYmVnaW57Ym1hdHJpeH0NCjAuMDAgJiAwLjAwICYgMC4wMFxcDQowLjAwICYgLTIuMzkgJiAtMS4yOFxcDQowLjAwICYgLTIuMzggJiAtMS4wMA0KXGVuZHtibWF0cml4fS4NClxdDQoNCkFyZWEgdGVyc2VidXQgZGlrYWxpa2FuIHNlY2FyYSBlbGVtZW4gZGVtaSBlbGVtZW4gZGVuZ2FuIGJvYm90IGtlcm5lbCBcKFxtYXRoYmZ7V31fe1xtYXRocm17ZW5jfX1eeygxKX1cKSwga2VtdWRpYW4gaGFzaWxueWEgZGlqdW1sYWhrYW4gc2ViYWdhaSBiZXJpa3V0Og0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpYX3sxLDF9XnsxLDB9DQo9e30mDQooMC4wMCkoMC4wMCkNCisoMC4wMCkoMC4wMCkNCisoMC4wMCkoMC4wMClcXA0KJisoMC4wMCkoMC4wMCkNCisoLTIuMzkpKDEuMDApDQorKC0xLjI4KSgwLjAwKVxcDQomKygwLjAwKSgwLjAwKQ0KKygtMi4zOCkoMC4wMCkNCisoLTEuMDApKDAuMDApXFwNCj17fSYtMi4zOS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBkZW1pa2lhbiwgZWxlbWVuIHBlcnRhbWEgcGFkYSAqZmVhdHVyZSBtYXAqIGtlbHVhcmFuIGFkYWxhaCBcKFhfezEsMX1eezEsMH09LTIuMzlcKS4NCg0KKioyLiBQZXJoaXR1bmdhbiBlbGVtZW4gcGFkYSBwb3Npc2kgXCgoMSwyKVwpKioNCg0KVW50dWsgbWVuZ2hpdHVuZyBlbGVtZW4gcGFkYSBwb3Npc2kgXCgoMSwyKVwpLCBrZXJuZWwgYmVyZ2VzZXIgZHVhIGtvbG9tIGtlIGthbmFuIGRhcmkgcG9zaXNpIHNlYmVsdW1ueWEga2FyZW5hICpzdHJpZGUqIHlhbmcgZGlndW5ha2FuIGFkYWxhaCBcKDJcKS4NCg0KQXJlYSAqZmVhdHVyZSBtYXAqIHlhbmcgZGlwcm9zZXMgbWVuamFkaToNCg0KXFsNClxiZWdpbntibWF0cml4fQ0KMC4wMCAmIDAuMDAgJiAwLjAwXFwNCi0xLjI4ICYgMS44MiAmIDEuMTJcXA0KLTEuMDAgJiAyLjI0ICYgMS41MA0KXGVuZHtibWF0cml4fS4NClxdDQoNClBlcmhpdHVuZ2FuIGtvbnZvbHVzaSBkaWxha3VrYW4gbWVuZ2d1bmFrYW4gYm9ib3Qga2VybmVsIHlhbmcgc2FtYToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KWF97MSwyfV57MSwwfQ0KPXt9Jg0KKDAuMDApKDAuMDApDQorKDAuMDApKDAuMDApDQorKDAuMDApKDAuMDApXFwNCiYrKC0xLjI4KSgwLjAwKQ0KKygxLjgyKSgxLjAwKQ0KKygxLjEyKSgwLjAwKVxcDQomKygtMS4wMCkoMC4wMCkNCisoMi4yNCkoMC4wMCkNCisoMS41MCkoMC4wMClcXA0KPXt9JjEuODIuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gZGVtaWtpYW4sIGVsZW1lbiBwYWRhIHBvc2lzaSBcKCgxLDIpXCkgZGFyaSAqZmVhdHVyZSBtYXAqIGtlbHVhcmFuIGFkYWxhaCBcKFhfezEsMn1eezEsMH09MS44MlwpLg0KDQpQcm9zZWR1ciB5YW5nIHNhbWEgZGl0ZXJhcGthbiBwYWRhIHNlbHVydWggcG9zaXNpIGtlcm5lbC4gS2FyZW5hIGhhbnlhIGJvYm90IHRlbmdhaCBrZXJuZWwgeWFuZyBiZXJuaWxhaSBcKDEuMDBcKSwgbmlsYWkga2VsdWFyYW4gcGFkYSBzZXRpYXAgcG9zaXNpIHNhbWEgZGVuZ2FuIG5pbGFpIGVsZW1lbiB0ZW5nYWggZGFyaSBhcmVhICpmZWF0dXJlIG1hcCogeWFuZyBzZWRhbmcgZGlwcm9zZXMuIEhhbCB0ZXJzZWJ1dCBtZXJ1cGFrYW4ga29uc2VrdWVuc2kgZGFyaSBib2JvdCBrZXJuZWwgeWFuZyBkaXRldGFwa2FuIHBhZGEgaWx1c3RyYXNpIGluaSwgYnVrYW4ga2FyYWt0ZXJpc3RpayB1bXVtIGRhcmkgc2VsdXJ1aCBvcGVyYXNpIGtvbnZvbHVzaS4NCg0KU2V0ZWxhaCBzZWx1cnVoIHNlbWJpbGFuIHBvc2lzaSBrb252b2x1c2kgZGloaXR1bmcsIGRpcGVyb2xlaCAqZmVhdHVyZSBtYXAqIGtlbHVhcmFuIGJlcnVrdXJhbiBcKDNcdGltZXMzXCkgc2ViYWdhaSBiZXJpa3V0Og0KDQpcWw0KXG1hdGhiZntYfV57MSwwfQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQotMi4zOSAmIDEuODIgJiAtMS44NFxcDQotMi4zOCAmIDIuMjQgJiAtMS43MFxcDQotMi4yNSAmIDAuNzcgJiAtMS45OQ0KXGVuZHtibWF0cml4fS4NClxdDQoNCkhhc2lsIHRlcnNlYnV0IG1lbnVuanVra2FuIGJhaHdhIG9wZXJhc2kgKnN0cmlkZWQgY29udm9sdXRpb24qIG1lbmd1cmFuZ2kgdWt1cmFuIHNwYXNpYWwgKmZlYXR1cmUgbWFwKiBkYXJpIFwoNVx0aW1lczVcKSBtZW5qYWRpIFwoM1x0aW1lczNcKS4gUGFkYSBpbHVzdHJhc2kgaW5pLCBuaWxhaSBrZWx1YXJhbiBkaXRlbnR1a2FuIG9sZWggZWxlbWVuIHRlbmdhaCBwYWRhIHNldGlhcCBhcmVhIGtvbnZvbHVzaSBrYXJlbmEgYm9ib3Qga2VybmVsIGxhaW5ueWEgYmVybmlsYWkgbm9sLg0KDQoNCiMjIyBiLiBEb3duc2FtcGxpbmcgRW5jb2RlciBLZWR1YSAoXChcbWF0aGJme1h9XnsyLDB9XCkpDQoNCipGZWF0dXJlIG1hcCogXChcbWF0aGJme1h9XnsxLDB9XCkgYmVydWt1cmFuIFwoM1x0aW1lczNcKSBkaXByb3NlcyBrZW1iYWxpIG1lbmdndW5ha2FuICpzdHJpZGVkIGNvbnZvbHV0aW9uKiBkZW5nYW4ga2VybmVsIFwoM1x0aW1lczNcKSwgKnN0cmlkZSogXCgyXCksICp6ZXJvIHBhZGRpbmcqIHNlYmVzYXIgXCgxXCkgcGFkYSBzZXRpYXAgc2lzaSwgZGFuIHRhbnBhIGJpYXMgdW50dWsgbWVuZ2hhc2lsa2FuICpmZWF0dXJlIG1hcCogXChcbWF0aGJme1h9XnsyLDB9XCkuDQoNCk1hdHJpa3MgKmZlYXR1cmUgbWFwKiBtYXN1a2FuIHlhbmcgZGlwZXJvbGVoIGRhcmkgdGFoYXAgZG93bnNhbXBsaW5nIGVuY29kZXIgcGVydGFtYSBhZGFsYWg6DQoNClxbDQpcbWF0aGJme1h9XnsxLDB9DQo9DQpcYmVnaW57Ym1hdHJpeH0NCi0yLjM5ICYgMS44MiAmIC0xLjg0XFwNCi0yLjM4ICYgMi4yNCAmIC0xLjcwXFwNCi0yLjI1ICYgMC43NyAmIC0xLjk5DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KVWt1cmFuIGtlbHVhcmFuICpzdHJpZGVkIGNvbnZvbHV0aW9uKiBkaWhpdHVuZyBtZW5nZ3VuYWthbjoNCg0KXFsNCm8NCj0NClxsZWZ0XGxmbG9vcg0KXGZyYWN7aSsycC1rfXtzfQ0KXHJpZ2h0XHJmbG9vcisxLA0KXF0NCg0KZGVuZ2FuIFwoaVwpIG1lbnlhdGFrYW4gdWt1cmFuIHNwYXNpYWwgbWFzdWthbiwgXChwXCkgbWVydXBha2FuIGp1bWxhaCAqcGFkZGluZyogcGFkYSBzZXRpYXAgc2lzaSwgXChrXCkgbWVydXBha2FuIHVrdXJhbiBrZXJuZWwsIGRhbiBcKHNcKSBtZXJ1cGFrYW4gKnN0cmlkZSouDQoNClBhZGEgaWx1c3RyYXNpIGluaSwgZGlndW5ha2FuIFwoaT0zXCksIFwoaz0zXCksIFwocD0xXCksIGRhbiBcKHM9MlwpLCBzZWhpbmdnYToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0Kbw0KJj0NClxsZWZ0XGxmbG9vcg0KXGZyYWN7MysyKDEpLTN9ezJ9DQpccmlnaHRccmZsb29yKzFcXA0KJj0NClxsZWZ0XGxmbG9vcg0KXGZyYWN7Mn17Mn0NClxyaWdodFxyZmxvb3IrMVxcDQomPTIuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gZGVtaWtpYW4sIHVrdXJhbiBzcGFzaWFsICpmZWF0dXJlIG1hcCogYmVya3VyYW5nIGRhcmkgXCgzXHRpbWVzM1wpIG1lbmphZGkgXCgyXHRpbWVzMlwpLg0KDQotICoqUGVuYW1iYWhhbiBaZXJvIFBhZGRpbmc6KioNCg0KU2ViZWx1bSBvcGVyYXNpIGtvbnZvbHVzaSBkaWxha3VrYW4sIHNhdHUgbGFwaXNhbiBuaWxhaSBub2wgZGl0YW1iYWhrYW4gcGFkYSBrZWVtcGF0IHNpc2kgbWF0cmlrcyBtYXN1a2FuLCB5YWl0dSBzaXNpIGF0YXMsIGJhd2FoLCBraXJpLCBkYW4ga2FuYW4uIFBlbmFtYmFoYW4gKnBhZGRpbmcqIGluaSBtZW5ndWJhaCB1a3VyYW4gbWF0cmlrcyBkYXJpIFwoM1x0aW1lczNcKSBtZW5qYWRpIFwoNVx0aW1lczVcKS4NCg0KTWF0cmlrcyBzZXRlbGFoIHBlbmFtYmFoYW4gKnplcm8gcGFkZGluZyogYWRhbGFoOg0KDQpcWw0KXG1hdGhiZntYfV97XG1hdGhybXtwYWR9fV57MSwwfQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjAwICYgMC4wMCAmIDAuMDAgJiAwLjAwICYgMC4wMFxcDQowLjAwICYgLTIuMzkgJiAxLjgyICYgLTEuODQgJiAwLjAwXFwNCjAuMDAgJiAtMi4zOCAmIDIuMjQgJiAtMS43MCAmIDAuMDBcXA0KMC4wMCAmIC0yLjI1ICYgMC43NyAmIC0xLjk5ICYgMC4wMFxcDQowLjAwICYgMC4wMCAmIDAuMDAgJiAwLjAwICYgMC4wMA0KXGVuZHtibWF0cml4fS4NClxdDQoNCi0gKipLZXJuZWwgRW5jb2RlciBLZWR1YToqKg0KDQpQYWRhIGlsdXN0cmFzaSBpbmksIG1hdHJpa3MgYm9ib3Qga2VybmVsIGVuY29kZXIga2VkdWEgZGl0ZXRhcGthbiBzZWJhZ2FpOg0KDQpcWw0KXG1hdGhiZntXfV97XG1hdGhybXtlbmN9fV57KDIpfQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjAwICYgMC4wMCAmIDAuMDBcXA0KMC4wMCAmIDEuMDAgJiAwLjAwXFwNCjAuMDAgJiAwLjAwICYgMC4wMA0KXGVuZHtibWF0cml4fS4NClxdDQoNCktlcm5lbCB0ZXJzZWJ1dCBtZW1pbGlraSBzYXR1IGJvYm90IGJlcm5pbGFpIFwoMS4wMFwpIHBhZGEgcG9zaXNpIHRlbmdhaCwgc2VkYW5na2FuIGRlbGFwYW4gYm9ib3QgbGFpbm55YSBiZXJuaWxhaSBcKDAuMDBcKS4gT2xlaCBrYXJlbmEgaXR1LCBzZXRpYXAgaGFzaWwga29udm9sdXNpIGRpcGVyb2xlaCBtZWxhbHVpIHBlcmthbGlhbiBzZW1iaWxhbiBlbGVtZW4gcGFkYSBhcmVhICpmZWF0dXJlIG1hcCogZGVuZ2FuIHNlbWJpbGFuIGJvYm90IGtlcm5lbCwga2VtdWRpYW4gc2VsdXJ1aCBoYXNpbCBwZXJrYWxpYW4gZGlqdW1sYWhrYW4uDQoNCi0gKipSdW11czoqKg0KDQpPcGVyYXNpICpzdHJpZGVkIGNvbnZvbHV0aW9uKiBwYWRhIGVuY29kZXIga2VkdWEgZGlydW11c2thbiBzZWJhZ2FpOg0KDQpcWw0KXG1hdGhiZntYfV57MiwwfQ0KPQ0KXG9wZXJhdG9ybmFtZXtDb252fV97M1x0aW1lczMsXCxzPTIsXCxwPTF9DQpcbGVmdCgNClxtYXRoYmZ7WH1eezEsMH07DQpcbWF0aGJme1d9X3tcbWF0aHJte2VuY319XnsoMil9DQpccmlnaHQpLg0KXF0NCg0KVW50dWsgZWxlbWVuIGtlbHVhcmFuIHBhZGEgYmFyaXMga2UtXChyXCkgZGFuIGtvbG9tIGtlLVwoY1wpLCBwZXJoaXR1bmdhbiBrb252b2x1c2kgZGFwYXQgZGlueWF0YWthbiBzZWJhZ2FpOg0KDQpcWw0KWF97cixjfV57MiwwfQ0KPQ0KXHN1bV97YT0xfV57M30NClxzdW1fe2I9MX1eezN9DQpXX3tcbWF0aHJte2VuY30sYSxifV57KDIpfQ0KWF97XG1hdGhybXtwYWR9LFwsMnIrYS0yLFwsMmMrYi0yfV57MSwwfSwNClxdDQoNCmRlbmdhbiBcKHIsYz0xLDJcKSwgc2VkYW5na2FuIFwoYVwpIGRhbiBcKGJcKSBtZXJ1cGFrYW4gaW5kZWtzIGJhcmlzIGRhbiBrb2xvbSBrZXJuZWwuDQoNClBhZGEgc2V0aWFwIHBvc2lzaSwga2VybmVsIG1lbmNha3VwIGFyZWEgYmVydWt1cmFuIFwoM1x0aW1lczNcKS4gS2FyZW5hICpzdHJpZGUqIGJlcm5pbGFpIFwoMlwpLCBrZXJuZWwgYmVyZ2VzZXIgZHVhIGtvbG9tIGtlIGthbmFuIHVudHVrIG1lbmdoaXR1bmcgZWxlbWVuIGJlcmlrdXRueWEgcGFkYSBiYXJpcyBrZWx1YXJhbiB5YW5nIHNhbWEuIFNldGVsYWggbWVuY2FwYWkgcG9zaXNpIHRlcmFraGlyIHBhZGEgYmFyaXMgdGVyc2VidXQsIGtlcm5lbCBrZW1iYWxpIGtlIHNpc2kga2lyaSBkYW4gYmVyZ2VzZXIgZHVhIGJhcmlzIGtlIGJhd2FoLg0KDQotICoqQ29udG9oIFBlcmhpdHVuZ2FuIEtvbnZvbHVzaToqKg0KDQoqKjEuIFBlcmhpdHVuZ2FuIGVsZW1lbiBwYWRhIHBvc2lzaSBcKCgxLDEpXCkqKg0KDQpVbnR1ayBtZW5naGFzaWxrYW4gZWxlbWVuIHBlcnRhbWEgXChcbWF0aGJme1h9XnsyLDB9XCksIGtlcm5lbCBkaXRlbXBhdGthbiBwYWRhIGFyZWEgXCgzXHRpbWVzM1wpIGRpIHBvam9rIGtpcmkgYXRhcyBtYXRyaWtzIHlhbmcgdGVsYWggZGliZXJpICpwYWRkaW5nKi4NCg0KQXJlYSAqZmVhdHVyZSBtYXAqIHlhbmcgZGlwcm9zZXMgYWRhbGFoOg0KDQpcWw0KXGJlZ2lue2JtYXRyaXh9DQowLjAwICYgMC4wMCAmIDAuMDBcXA0KMC4wMCAmIC0yLjM5ICYgMS44MlxcDQowLjAwICYgLTIuMzggJiAyLjI0DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KQXJlYSB0ZXJzZWJ1dCBkaWthbGlrYW4gc2VjYXJhIGVsZW1lbiBkZW1pIGVsZW1lbiBkZW5nYW4gYm9ib3Qga2VybmVsIFwoXG1hdGhiZntXfV97XG1hdGhybXtlbmN9fV57KDIpfVwpLCBrZW11ZGlhbiBzZWx1cnVoIGhhc2lsIHBlcmthbGlhbiBkaWp1bWxhaGthbiBzZWJhZ2FpIGJlcmlrdXQ6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClhfezEsMX1eezIsMH0NCj17fSYNCigwLjAwKSgwLjAwKQ0KKygwLjAwKSgwLjAwKQ0KKygwLjAwKSgwLjAwKVxcDQomKygwLjAwKSgwLjAwKQ0KKygtMi4zOSkoMS4wMCkNCisoMS44MikoMC4wMClcXA0KJisoMC4wMCkoMC4wMCkNCisoLTIuMzgpKDAuMDApDQorKDIuMjQpKDAuMDApXFwNCj17fSYtMi4zOS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBkZW1pa2lhbiwgZWxlbWVuIHBlcnRhbWEgcGFkYSAqZmVhdHVyZSBtYXAqIGtlbHVhcmFuIGFkYWxhaCBcKFhfezEsMX1eezIsMH09LTIuMzlcKS4NCg0KKioyLiBQZXJoaXR1bmdhbiBlbGVtZW4gcGFkYSBwb3Npc2kgXCgoMSwyKVwpKioNCg0KVW50dWsgbWVuZ2hpdHVuZyBlbGVtZW4gcGFkYSBwb3Npc2kgXCgoMSwyKVwpLCBrZXJuZWwgYmVyZ2VzZXIgZHVhIGtvbG9tIGtlIGthbmFuIGRhcmkgcG9zaXNpIHNlYmVsdW1ueWEga2FyZW5hICpzdHJpZGUqIHlhbmcgZGlndW5ha2FuIGFkYWxhaCBcKDJcKS4NCg0KQXJlYSAqZmVhdHVyZSBtYXAqIHlhbmcgZGlwcm9zZXMgbWVuamFkaToNCg0KXFsNClxiZWdpbntibWF0cml4fQ0KMC4wMCAmIDAuMDAgJiAwLjAwXFwNCjEuODIgJiAtMS44NCAmIDAuMDBcXA0KMi4yNCAmIC0xLjcwICYgMC4wMA0KXGVuZHtibWF0cml4fS4NClxdDQoNClBlcmhpdHVuZ2FuIGtvbnZvbHVzaSBkaWxha3VrYW4gbWVuZ2d1bmFrYW4gYm9ib3Qga2VybmVsIHlhbmcgc2FtYToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KWF97MSwyfV57MiwwfQ0KPXt9Jg0KKDAuMDApKDAuMDApDQorKDAuMDApKDAuMDApDQorKDAuMDApKDAuMDApXFwNCiYrKDEuODIpKDAuMDApDQorKC0xLjg0KSgxLjAwKQ0KKygwLjAwKSgwLjAwKVxcDQomKygyLjI0KSgwLjAwKQ0KKygtMS43MCkoMC4wMCkNCisoMC4wMCkoMC4wMClcXA0KPXt9Ji0xLjg0Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KRGVuZ2FuIGRlbWlraWFuLCBlbGVtZW4gcGFkYSBwb3Npc2kgXCgoMSwyKVwpIGRhcmkgKmZlYXR1cmUgbWFwKiBrZWx1YXJhbiBhZGFsYWggXChYX3sxLDJ9XnsyLDB9PS0xLjg0XCkuDQoNClByb3NlZHVyIHlhbmcgc2FtYSBkaXRlcmFwa2FuIHBhZGEgc2VsdXJ1aCBwb3Npc2kga2VybmVsLiBLYXJlbmEgaGFueWEgYm9ib3QgdGVuZ2FoIGtlcm5lbCB5YW5nIGJlcm5pbGFpIFwoMS4wMFwpLCBuaWxhaSBrZWx1YXJhbiBwYWRhIHNldGlhcCBwb3Npc2kgc2FtYSBkZW5nYW4gbmlsYWkgZWxlbWVuIHRlbmdhaCBkYXJpIGFyZWEgKmZlYXR1cmUgbWFwKiB5YW5nIHNlZGFuZyBkaXByb3Nlcy4gSGFsIHRlcnNlYnV0IG1lcnVwYWthbiBrb25zZWt1ZW5zaSBkYXJpIGJvYm90IGtlcm5lbCB5YW5nIGRpdGV0YXBrYW4gcGFkYSBpbHVzdHJhc2kgaW5pLCBidWthbiBrYXJha3RlcmlzdGlrIHVtdW0gZGFyaSBzZWx1cnVoIG9wZXJhc2kga29udm9sdXNpLg0KDQpTZXRlbGFoIHNlbHVydWggZW1wYXQgcG9zaXNpIGtvbnZvbHVzaSBkaWhpdHVuZywgZGlwZXJvbGVoICpmZWF0dXJlIG1hcCoga2VsdWFyYW4gYmVydWt1cmFuIFwoMlx0aW1lczJcKSBzZWJhZ2FpIGJlcmlrdXQ6DQoNClxbDQpcbWF0aGJme1h9XnsyLDB9DQo9DQpcYmVnaW57Ym1hdHJpeH0NCi0yLjM5ICYgLTEuODRcXA0KLTIuMjUgJiAtMS45OQ0KXGVuZHtibWF0cml4fS4NClxdDQoNCkhhc2lsIHRlcnNlYnV0IG1lbnVuanVra2FuIGJhaHdhIG9wZXJhc2kgKnN0cmlkZWQgY29udm9sdXRpb24qIHBhZGEgZW5jb2RlciBrZWR1YSBtZW5ndXJhbmdpIHVrdXJhbiBzcGFzaWFsICpmZWF0dXJlIG1hcCogZGFyaSBcKDNcdGltZXMzXCkgbWVuamFkaSBcKDJcdGltZXMyXCkuIFBhZGEgaWx1c3RyYXNpIGluaSwgbmlsYWkga2VsdWFyYW4gZGl0ZW50dWthbiBvbGVoIGVsZW1lbiB0ZW5nYWggcGFkYSBzZXRpYXAgYXJlYSBrb252b2x1c2kga2FyZW5hIGJvYm90IGtlcm5lbCBsYWlubnlhIGJlcm5pbGFpIG5vbC4NCg0KDQoNCiMjIDYuIERlY29kZXIgVU5ldCsrDQoNClBhZGEgdGFoYXAgaW5pLCAqZGVjb2RlciogVU5ldCsrIG1lbmdlbWJhbGlrYW4gcmVzb2x1c2kgc3Bhc2lhbCAqZmVhdHVyZSBtYXAqIHNlY2FyYSBiZXJ0YWhhcCBtZWxhbHVpIG9wZXJhc2kgVXBzYW1wbGluZy4gUGFkYSBpbHVzdHJhc2kgaW5pLCBcKFxvcGVyYXRvcm5hbWV7VXB9KFxjZG90KVwpIG1lbnlhdGFrYW4gVXBzYW1wbGluZyBtZW5nZ3VuYWthbiBpbnRlcnBvbGFzaSBiaWxpbmVhci4gT3BlcmFzaSB0ZXJzZWJ1dCBtZW1wZXJiZXNhciB1a3VyYW4gc3Bhc2lhbCAqZmVhdHVyZSBtYXAqIGRlbmdhbiBtZW5naGl0dW5nIG5pbGFpIHBhZGEgcG9zaXNpIGtlbHVhcmFuIGJlcmRhc2Fya2FuIGphcmFrIHRlcmhhZGFwIGVsZW1lbiBtYXN1a2FuIGRpIHNla2l0YXJueWEuDQoNClBhZGEgc2V0aWFwIG5vZGUgKmRlY29kZXIqLCAqZmVhdHVyZSBtYXAqIGhhc2lsIFVwc2FtcGxpbmcgZGlnYWJ1bmdrYW4gZGVuZ2FuICpmZWF0dXJlIG1hcCogZGFyaSBqYWx1ciAqZW5jb2RlciogYXRhdSBub2RlICpkZWNvZGVyKiBzZWJlbHVtbnlhIG1lbGFsdWkgKm5lc3RlZCBza2lwIGNvbm5lY3Rpb24qLiBQZW5nZ2FidW5nYW4gZGlsYWt1a2FuIG1lbmdndW5ha2FuICpjb25jYXRlbmF0aW9uKiAoKkNvbmNhdCopIHBhZGEgZGltZW5zaSBrYW5hbCwga2VtdWRpYW4gZGlsYW5qdXRrYW4gZGVuZ2FuIGtvbnZvbHVzaSBcKDFcdGltZXMxXCkgZGFuIGZ1bmdzaSBha3RpdmFzaSBSZUxVLg0KDQpVbnR1ayBtZW1wZXJtdWRhaCBpbHVzdHJhc2kgcGVyaGl0dW5nYW4gbWFudWFsLCBvcGVyYXNpIGtvbnZvbHVzaSBwYWRhIG5vZGUgKmRlY29kZXIqIGRpc2VkZXJoYW5ha2FuIG1lbmphZGkgc2F0dSBrb252b2x1c2kgXCgxXHRpbWVzMVwpIHRhbnBhIGJpYXMuIEJvYm90IGtlcm5lbCBkaXRlbnR1a2FuIHNlY2FyYSBpbHVzdHJhdGlmIGRhbiB0aWRhayBtZXJlcHJlc2VudGFzaWthbiBib2JvdCBoYXNpbCBwZWxhdGloYW4gbW9kZWwuIFBlbnllZGVyaGFuYWFuIGluaSBkaWd1bmFrYW4gdW50dWsgbWVuamVsYXNrYW4gbWVrYW5pc21lIHBlbmdnYWJ1bmdhbiBmaXR1ciwgYnVrYW4ga2VzZWx1cnVoYW4gYmxvayBrb252b2x1c2kgcGFkYSBpbXBsZW1lbnRhc2kgVU5ldCsrLg0KDQpEZW5nYW4gZGVtaWtpYW4sIHBlbWJlbnR1a2FuIG5vZGUgKmRlY29kZXIqIHBhZGEgaWx1c3RyYXNpIGluaSBkaW55YXRha2FuIHNlYmFnYWk6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClxtYXRoYmZ7WH1eezEsMX0NCiY9DQpcb3BlcmF0b3JuYW1le1JlTFV9DQpcbGVmdCgNClxvcGVyYXRvcm5hbWV7Q29udn1fezFcdGltZXMxfV57KDEsMSl9DQpcbGVmdCgNClxvcGVyYXRvcm5hbWV7Q29uY2F0fQ0KXGxlZnRbDQpcbWF0aGJme1h9XnsxLDB9LA0KXG9wZXJhdG9ybmFtZXtVcH0oXG1hdGhiZntYfV57MiwwfSkNClxyaWdodF0NClxyaWdodCkNClxyaWdodCksXFxbNnB0XQ0KXG1hdGhiZntYfV57MCwxfQ0KJj0NClxvcGVyYXRvcm5hbWV7UmVMVX0NClxsZWZ0KA0KXG9wZXJhdG9ybmFtZXtDb252fV97MVx0aW1lczF9XnsoMCwxKX0NClxsZWZ0KA0KXG9wZXJhdG9ybmFtZXtDb25jYXR9DQpcbGVmdFsNClxtYXRoYmZ7WH1eezAsMH0sDQpcb3BlcmF0b3JuYW1le1VwfShcbWF0aGJme1h9XnsxLDB9KQ0KXHJpZ2h0XQ0KXHJpZ2h0KQ0KXHJpZ2h0KSxcXFs2cHRdDQpcbWF0aGJme1h9XnswLDJ9DQomPQ0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQpcb3BlcmF0b3JuYW1le0NvbnZ9X3sxXHRpbWVzMX1eeygwLDIpfQ0KXGxlZnQoDQpcb3BlcmF0b3JuYW1le0NvbmNhdH0NClxsZWZ0Ww0KXG1hdGhiZntYfV57MCwwfSwNClxtYXRoYmZ7WH1eezAsMX0sDQpcb3BlcmF0b3JuYW1le1VwfShcbWF0aGJme1h9XnsxLDF9KQ0KXHJpZ2h0XQ0KXHJpZ2h0KQ0KXHJpZ2h0KS4NClxlbmR7YWxpZ25lZH0NClxdDQoNClBhZGEgbm9kZSBcKFxtYXRoYmZ7WH1eezEsMX1cKSBkYW4gXChcbWF0aGJme1h9XnswLDF9XCksIG1hc2luZy1tYXNpbmcga2FuYWwgbWFzdWthbiBkaWJlcmkgYm9ib3QgaWx1c3RyYXRpZiBcKDEuMDBcKS4gU2VtZW50YXJhIGl0dSwgcGFkYSBub2RlIFwoXG1hdGhiZntYfV57MCwyfVwpLCB0aWdhIGthbmFsIG1hc3VrYW4gZGliZXJpIGJvYm90IGlsdXN0cmF0aWYgXCgwLjI1XCksIFwoMC41MFwpLCBkYW4gXCgwLjI1XCkuIEJvYm90IHRlcnNlYnV0IGRpZ3VuYWthbiB1bnR1ayBtZW1wZXJ0YWhhbmthbiBtZWthbmlzbWUgcGVuZ2dhYnVuZ2FuIGZpdHVyIHlhbmcgdGVsYWggZGl0ZXRhcGthbiBkYWxhbSBpbHVzdHJhc2kgc2ViZWx1bW55YS4NCg0KDQojIyMgYS4gVXBzYW1wbGluZyBcKFxtYXRoYmZ7WH1eezIsMH1cKSBkYW4gTm9kZSBEZWNvZGVyIFwoXG1hdGhiZntYfV57MSwxfVwpDQoNCipGZWF0dXJlIG1hcCogXChcbWF0aGJme1h9XnsyLDB9XCkgYmVydWt1cmFuIFwoMlx0aW1lczJcKSwgeWFuZyBkaXBlcm9sZWggZGFyaSB0YWhhcCAqZW5jb2Rlciogc2ViZWx1bW55YSwgZGlwZXJiZXNhciBtZW5qYWRpIFwoM1x0aW1lczNcKSBtZW5nZ3VuYWthbiBpbnRlcnBvbGFzaSBiaWxpbmVhci4gUHJvc2VzIGluaSBiZXJ0dWp1YW4gdW50dWsgbWVueWVzdWFpa2FuIHVrdXJhbiBzcGFzaWFsICpmZWF0dXJlIG1hcCogc2VoaW5nZ2EgZGFwYXQgZGlnYWJ1bmdrYW4gZGVuZ2FuICpmZWF0dXJlIG1hcCogXChcbWF0aGJme1h9XnsxLDB9XCkgZGFyaSBqYWx1ciAqZW5jb2RlciogbWVsYWx1aSAqbmVzdGVkIHNraXAgY29ubmVjdGlvbiouDQoNCk1hdHJpa3MgKmZlYXR1cmUgbWFwKiBtYXN1a2FuIGFkYWxhaDoNCg0KXFsNClxtYXRoYmZ7WH1eezIsMH0NCj0NClxiZWdpbntibWF0cml4fQ0KLTIuMzkgJiAtMS44NFxcDQotMi4yNSAmIC0xLjk5DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KLSAqKlJ1bXVzIGludGVycG9sYXNpIGJpbGluZWFyOioqDQoNCkludGVycG9sYXNpIGJpbGluZWFyIG1lbmVudHVrYW4gbmlsYWkga2VsdWFyYW4gYmVyZGFzYXJrYW4gamFyYWsgdGVyaGFkYXAgZWxlbWVuLWVsZW1lbiBwYWRhICpmZWF0dXJlIG1hcCogbWFzdWthbi4gRWxlbWVuIHlhbmcgbGViaWggZGVrYXQgZGVuZ2FuIHBvc2lzaSBrZWx1YXJhbiBtZW1pbGlraSBib2JvdCBsZWJpaCBiZXNhciwgc2VkYW5na2FuIGVsZW1lbiB5YW5nIGJlcmphcmFrIHNhdHUgc2F0dWFuIGF0YXUgbGViaWggcGFkYSBzYWxhaCBzYXR1IGFyYWggbWVtaWxpa2kgYm9ib3Qgbm9sLg0KDQpQYWRhICpmZWF0dXJlIG1hcCogc2F0dSBrYW5hbCwgaW50ZXJwb2xhc2kgYmlsaW5lYXIgZGlueWF0YWthbiBzZWJhZ2FpOg0KDQpcWw0KXGxlZnRbDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsyLDB9DQpccmlnaHQpDQpccmlnaHRdX3tyLGN9DQo9DQpcc3VtX3tuPTF9XnsyfQ0KXHN1bV97bT0xfV57Mn0NClhfe24sbX1eezIsMH0NClxtYXgNClxsZWZ0KA0KMCwNCjEtXGxlZnR8eF9jLW1ccmlnaHR8DQpccmlnaHQpDQpcbWF4DQpcbGVmdCgNCjAsDQoxLVxsZWZ0fHlfci1uXHJpZ2h0fA0KXHJpZ2h0KS4NClxdDQoNClBhZGEgcGVyc2FtYWFuIHRlcnNlYnV0LCBcKHJcKSBkYW4gXChjXCkgbWVueWF0YWthbiBpbmRla3MgYmFyaXMgZGFuIGtvbG9tIHBhZGEgKmZlYXR1cmUgbWFwKiBrZWx1YXJhbiwgc2VkYW5na2FuIFwoblwpIGRhbiBcKG1cKSBtZW55YXRha2FuIGluZGVrcyBiYXJpcyBkYW4ga29sb20gcGFkYSAqZmVhdHVyZSBtYXAqIG1hc3VrYW4uIEtvb3JkaW5hdCBcKHhfY1wpIG1lbnVuanVra2FuIHBvc2lzaSBob3Jpem9udGFsIGF0YXUgYXJhaCBrb2xvbSwgc2VkYW5na2FuIFwoeV9yXCkgbWVudW5qdWtrYW4gcG9zaXNpIHZlcnRpa2FsIGF0YXUgYXJhaCBiYXJpcy4NCg0KVW50dWsgbWVtcGVybXVkYWggcGVuamFiYXJhbiwgYm9ib3QgaW50ZXJwb2xhc2kgcGFkYSBzZXRpYXAgZWxlbWVuIG1hc3VrYW4gZGlub3Rhc2lrYW4gc2ViYWdhaToNCg0KXFsNCndfe24sbX1eeyhyLGMpfQ0KPQ0KXG1heA0KXGxlZnQoDQowLA0KMS1cbGVmdHx4X2MtbVxyaWdodHwNClxyaWdodCkNClxtYXgNClxsZWZ0KA0KMCwNCjEtXGxlZnR8eV9yLW5ccmlnaHR8DQpccmlnaHQpLg0KXF0NCg0KRGVuZ2FuIGRlbWlraWFuLCBydW11cyBpbnRlcnBvbGFzaSBiaWxpbmVhciBkYXBhdCBkaXR1bGlza2FuIHNlYmFnYWk6DQoNClxbDQpcbGVmdFsNClxvcGVyYXRvcm5hbWV7VXB9DQpcbGVmdCgNClxtYXRoYmZ7WH1eezIsMH0NClxyaWdodCkNClxyaWdodF1fe3IsY30NCj0NClxzdW1fe249MX1eezJ9DQpcc3VtX3ttPTF9XnsyfQ0Kd197bixtfV57KHIsYyl9WF97bixtfV57MiwwfS4NClxdDQoNCi0gKipQZW5lbnR1YW4ga29vcmRpbmF0IGludGVycG9sYXNpOioqDQoNClBhZGEgaWx1c3RyYXNpIGluaSwga29vcmRpbmF0IG1hdHJpa3MgbWFzdWthbiBtZW5nZ3VuYWthbiBpbmRla3MgeWFuZyBkaW11bGFpIGRhcmkgXCgxXCkuIEthcmVuYSB1a3VyYW4gKmZlYXR1cmUgbWFwKiBtYXN1a2FuIGFkYWxhaCBcKDJcdGltZXMyXCkgZGFuIHVrdXJhbiBrZWx1YXJhbiBhZGFsYWggXCgzXHRpbWVzM1wpLCBrb29yZGluYXQgaW50ZXJwb2xhc2kgZGl0ZW50dWthbiBzZWJhZ2FpOg0KDQpcWw0KeF9jDQo9DQoxKyhjLTEpXGZyYWN7Mi0xfXszLTF9DQo9DQoxK1xmcmFje2MtMX17Mn0sDQpcXQ0KDQpcWw0KeV9yDQo9DQoxKyhyLTEpXGZyYWN7Mi0xfXszLTF9DQo9DQoxK1xmcmFje3ItMX17Mn0sDQpcXQ0KDQpkZW5nYW4gXChyLGM9MSwyLDNcKS4NCg0KQW5na2EgXCgxXCkgbWVudW5qdWtrYW4ga29vcmRpbmF0IGF3YWwga2FyZW5hIGluZGVrcyBtYXRyaWtzIGRpbXVsYWkgZGFyaSBcKDFcKSwgc2VkYW5na2FuIHBlbWJhZ2lhbiBkZW5nYW4gXCgyXCkgbWVudW5qdWtrYW4gYmFod2EgamFyYWsgYW50YXJhIGR1YSBrb29yZGluYXQgbWFzdWthbiBkaWJhZ2kgbWVuamFkaSBkdWEgaW50ZXJ2YWwgeWFuZyBzYW1hIHBhbmphbmcuDQoNCk5pbGFpIGtvb3JkaW5hdCB5YW5nIGRpcGVyb2xlaCBhZGFsYWg6DQoNCnwgSW5kZWtzIGtlbHVhcmFuIHwgTmlsYWkga29vcmRpbmF0IHwNCnw6LS0tOnw6LS0tOnwNCnwgXCgxXCkgfCBcKDFcKSB8DQp8IFwoMlwpIHwgXCgxLjVcKSB8DQp8IFwoM1wpIHwgXCgyXCkgfA0KDQpEZW5nYW4gZGVtaWtpYW4sIGtvb3JkaW5hdCBpbnRlcnBvbGFzaSBwYWRhIG1hdHJpa3Mga2VsdWFyYW4gZGFwYXQgZGl0dWxpc2thbiBzZWJhZ2FpOg0KDQpcWw0KXGJlZ2lue2JtYXRyaXh9DQooMSwxKSAmICgxLDEuNSkgJiAoMSwyKVxcDQooMS41LDEpICYgKDEuNSwxLjUpICYgKDEuNSwyKVxcDQooMiwxKSAmICgyLDEuNSkgJiAoMiwyKQ0KXGVuZHtibWF0cml4fS4NClxdDQoNClNldGlhcCBwYXNhbmdhbiBrb29yZGluYXQgZGl0dWxpc2thbiBkYWxhbSB1cnV0YW4gXCgoeV9yLHhfYylcKS4gUGFkYSBwb3Npc2kgc3VkdXQsIG5pbGFpIGtlbHVhcmFuIHNhbWEgZGVuZ2FuIG5pbGFpIG1hc3VrYW4ga2FyZW5hIGtvb3JkaW5hdG55YSBiZXJpbXBpdC4gU2VtZW50YXJhIGl0dSwgcG9zaXNpIHRlbmdhaCBzaXNpIGRpcGVyb2xlaCBkYXJpIGR1YSBlbGVtZW4gbWFzdWthbiwgc2VkYW5na2FuIHBvc2lzaSB0ZW5nYWggbWF0cmlrcyBkaXBlcm9sZWggZGFyaSBlbXBhdCBlbGVtZW4gbWFzdWthbi4NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiBpbnRlcnBvbGFzaSBiaWxpbmVhciBwYWRhIHBvc2lzaSBcKCgxLDIpXCk6KioNCg0KUGFkYSBwb3Npc2kgXCgoMSwyKVwpLCBrb29yZGluYXQgaW50ZXJwb2xhc2kgZGlwZXJvbGVoIHNlYmFnYWkgYmVyaWt1dDoNCg0KXFsNCnlfMT0xLA0KXHFxdWFkDQp4XzI9MS41Lg0KXF0NCg0KUG9zaXNpIHRlcnNlYnV0IGJlcmFkYSB0ZXBhdCBkaSB0ZW5nYWggYW50YXJhIGtvbG9tIHBlcnRhbWEgZGFuIGtvbG9tIGtlZHVhIHBhZGEgYmFyaXMgcGVydGFtYS4gQm9ib3QgaW50ZXJwb2xhc2kgdW50dWsgZWxlbWVuIFwoWF97MSwxfV57MiwwfVwpIGRpaGl0dW5nIHNlYmFnYWk6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NCndfezEsMX1eeygxLDIpfQ0KJj0NClxtYXgoMCwxLXwxLjUtMXwpDQpcbWF4KDAsMS18MS0xfClcXA0KJj0NCjAuNVx0aW1lczFcXA0KJj0NCjAuNS4NClxlbmR7YWxpZ25lZH0NClxdDQoNClNlbWVudGFyYSBpdHUsIGJvYm90IHVudHVrIGVsZW1lbiBcKFhfezEsMn1eezIsMH1cKSBhZGFsYWg6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NCndfezEsMn1eeygxLDIpfQ0KJj0NClxtYXgoMCwxLXwxLjUtMnwpDQpcbWF4KDAsMS18MS0xfClcXA0KJj0NCjAuNVx0aW1lczFcXA0KJj0NCjAuNS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCktlZHVhIGVsZW1lbiBwYWRhIGJhcmlzIGtlZHVhIG1lbWlsaWtpIGJvYm90IG5vbCBrYXJlbmEgamFyYWsgdmVydGlrYWxueWEgdGVyaGFkYXAgcG9zaXNpIGtlbHVhcmFuIGFkYWxhaCBzYXR1IHNhdHVhbi4gRGVuZ2FuIGRlbWlraWFuOg0KDQpcWw0Kd197MSwxfV57KDEsMil9DQo9DQp3X3sxLDJ9XnsoMSwyKX0NCj0NCjAuNSwNClxxcXVhZA0Kd197MiwxfV57KDEsMil9DQo9DQp3X3syLDJ9XnsoMSwyKX0NCj0NCjAuDQpcXQ0KDQpEZW5nYW4gbWVtYXN1a2thbiBib2JvdCB0ZXJzZWJ1dCBrZSBkYWxhbSBydW11cyBpbnRlcnBvbGFzaSBiaWxpbmVhciwgZGlwZXJvbGVoOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcbGVmdFsNClxvcGVyYXRvcm5hbWV7VXB9DQpcbGVmdCgNClxtYXRoYmZ7WH1eezIsMH0NClxyaWdodCkNClxyaWdodF1fezEsMn0NCiY9DQowLjVYX3sxLDF9XnsyLDB9DQorDQowLjVYX3sxLDJ9XnsyLDB9XFwNCiY9DQpcZnJhY3sNClhfezEsMX1eezIsMH0NCisNClhfezEsMn1eezIsMH0NCn17Mn1cXA0KJj0NClxmcmFjey0yLjM5LTEuODR9ezJ9XFwNCiY9DQotMi4xMTVcXA0KJg0KLTIuMTIuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuIGludGVycG9sYXNpIGJpbGluZWFyIHBhZGEgcG9zaXNpIHRlbmdhaCBcKCgyLDIpXCk6KioNCg0KUGFkYSBwb3Npc2kgXCgoMiwyKVwpLCBrb29yZGluYXQgaW50ZXJwb2xhc2kgZGlwZXJvbGVoIHNlYmFnYWkgYmVyaWt1dDoNCg0KXFsNCnlfMj0xLjUsDQpccXF1YWQNCnhfMj0xLjUuDQpcXQ0KDQpQb3Npc2kgdGVyc2VidXQgYmVyYWRhIHRlcGF0IGRpIHRlbmdhaCBlbXBhdCBlbGVtZW4gbWF0cmlrcyBtYXN1a2FuLiBCb2JvdCBpbnRlcnBvbGFzaSB1bnR1ayBlbGVtZW4gXChYX3sxLDF9XnsyLDB9XCkgZGloaXR1bmcgc2ViYWdhaToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0Kd197MSwxfV57KDIsMil9DQomPQ0KXG1heCgwLDEtfDEuNS0xfCkNClxtYXgoMCwxLXwxLjUtMXwpXFwNCiY9DQowLjVcdGltZXMwLjVcXA0KJj0NCjAuMjUuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpLYXJlbmEgcG9zaXNpIHRlbmdhaCBiZXJqYXJhayBzYW1hIGRhcmkga2VlbXBhdCBlbGVtZW4gbWFzdWthbiwgbWFrYToNCg0KXFsNCndfezEsMX1eeygyLDIpfQ0KPQ0Kd197MSwyfV57KDIsMil9DQo9DQp3X3syLDF9XnsoMiwyKX0NCj0NCndfezIsMn1eeygyLDIpfQ0KPQ0KMC4yNS4NClxdDQoNCkRlbmdhbiBkZW1pa2lhbiwgcnVtdXMgaW50ZXJwb2xhc2kgYmlsaW5lYXIgbWVuamFkaToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KXGxlZnRbDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsyLDB9DQpccmlnaHQpDQpccmlnaHRdX3syLDJ9DQomPQ0KMC4yNVhfezEsMX1eezIsMH0NCisNCjAuMjVYX3sxLDJ9XnsyLDB9XFwNCiZccXVhZCsNCjAuMjVYX3syLDF9XnsyLDB9DQorDQowLjI1WF97MiwyfV57MiwwfVxcDQomPQ0KXGZyYWN7DQpYX3sxLDF9XnsyLDB9DQorDQpYX3sxLDJ9XnsyLDB9DQorDQpYX3syLDF9XnsyLDB9DQorDQpYX3syLDJ9XnsyLDB9DQp9ezR9XFwNCiY9DQpcZnJhY3stMi4zOS0xLjg0LTIuMjUtMS45OX17NH1cXA0KJj0NCi0yLjExNzVcXA0KJg0KLTIuMTIuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gbWVuZXJhcGthbiBpbnRlcnBvbGFzaSBiaWxpbmVhciBwYWRhIHNlbHVydWggcG9zaXNpIGtlbHVhcmFuLCBkaXBlcm9sZWggKmZlYXR1cmUgbWFwKiBoYXNpbCBVcHNhbXBsaW5nIGJlcnVrdXJhbiBcKDNcdGltZXMzXCksIHlhaXR1Og0KDQpcWw0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MiwwfQ0KXHJpZ2h0KQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQotMi4zOSAmIC0yLjEyICYgLTEuODRcXA0KLTIuMzIgJiAtMi4xMiAmIC0xLjkyXFwNCi0yLjI1ICYgLTIuMTIgJiAtMS45OQ0KXGVuZHtibWF0cml4fS4NClxdDQoNCkhhc2lsIHRlcnNlYnV0IG1lbnVuanVra2FuIGJhaHdhIGludGVycG9sYXNpIGJpbGluZWFyIG1lbXBlcnRhaGFua2FuIG5pbGFpIHBhZGEgcG9zaXNpIHN1ZHV0IGRhbiBtZW5naGl0dW5nIG5pbGFpIHBhZGEgcG9zaXNpIGxhaW5ueWEgYmVyZGFzYXJrYW4gYm9ib3QgamFyYWsgdGVyaGFkYXAgZWxlbWVuIG1hc3VrYW4uIE5pbGFpIGhhc2lsIGludGVycG9sYXNpIGRpdGFtcGlsa2FuIGhpbmdnYSBkdWEgYW5na2EgZGVzaW1hbC4NCg0KLSAqKlJ1bXVzIG5vZGUgZGVjb2RlcjoqKg0KDQpTZXN1YWkgZGVuZ2FuIHBlcnNhbWFhbiBVTmV0KyssICpuZXN0ZWQgc2tpcCBjb25uZWN0aW9uKiBwYWRhIG5vZGUgKmRlY29kZXIqIHBlcnRhbWEgZGlydW11c2thbiBzZWJhZ2FpOg0KDQpcWw0KXG1hdGhiZntYfV57MSwxfQ0KPQ0KSF57KDEsMSl9DQpcbGVmdCgNClxvcGVyYXRvcm5hbWV7Q29uY2F0fQ0KXGxlZnRbDQpcbWF0aGJme1h9XnsxLDB9LA0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MiwwfQ0KXHJpZ2h0KQ0KXHJpZ2h0XQ0KXHJpZ2h0KS4NClxdDQoNClBhZGEgcGVyc2FtYWFuIHRlcnNlYnV0LCBcKEheeygxLDEpfVwpIG1lbnlhdGFrYW4gb3BlcmFzaSBwZW5nb2xhaGFuIGZpdHVyIHBhZGEgbm9kZSAqZGVjb2RlciogXChcbWF0aGJme1h9XnsxLDF9XCkuIERhbGFtIGlsdXN0cmFzaSBwZXJoaXR1bmdhbiBtYW51YWwgaW5pLCBvcGVyYXNpIHRlcnNlYnV0IGRpc2VkZXJoYW5ha2FuIG1lbmdndW5ha2FuIGtvbnZvbHVzaSBcKDFcdGltZXMxXCkgdGFucGEgYmlhcyB5YW5nIGRpaWt1dGkgZnVuZ3NpIGFrdGl2YXNpIFJlTFUuDQoNCkthcmVuYSBrZWR1YSAqZmVhdHVyZSBtYXAqIHlhbmcgZGlnYWJ1bmdrYW4gYmVydWt1cmFuIFwoM1x0aW1lczNcKSBkYW4gbWFzaW5nLW1hc2luZyBkaXJlcHJlc2VudGFzaWthbiBvbGVoIHNhdHUga2FuYWwsIGhhc2lsICpDb25jYXQqIG1lbWlsaWtpIGR1YSBrYW5hbC4gU2F0dSBmaWx0ZXIga29udm9sdXNpIFwoMVx0aW1lczFcKSBkaWd1bmFrYW4gdW50dWsgbWVuZ2dhYnVuZ2thbiBrZWR1YSBrYW5hbCB0ZXJzZWJ1dCBtZW5qYWRpIHNhdHUga2FuYWwga2VsdWFyYW4uDQoNClBhZGEgaWx1c3RyYXNpIGluaSwgYm9ib3Qga2VybmVsIGRpdGVudHVrYW4gc2ViYWdhaToNCg0KXFsNCldfe1xtYXRocm17ZGVjfSwxfV57KDEsMSl9PVsxLjAwXSwNClxxcXVhZA0KV197XG1hdGhybXtkZWN9LDJ9XnsoMSwxKX09WzEuMDBdLg0KXF0NCg0KQm9ib3QgcGVydGFtYSBkaXRlcmFwa2FuIHBhZGEgXChcbWF0aGJme1h9XnsxLDB9XCksIHNlZGFuZ2thbiBib2JvdCBrZWR1YSBkaXRlcmFwa2FuIHBhZGEgXChcb3BlcmF0b3JuYW1le1VwfShcbWF0aGJme1h9XnsyLDB9KVwpLg0KDQpEZW5nYW4gZGVtaWtpYW4sIHVudHVrIHNldGlhcCBwb3Npc2kgc3Bhc2lhbCBcKChyLGMpXCksIGtlbHVhcmFuIG5vZGUgKmRlY29kZXIqIGRpaGl0dW5nIHNlYmFnYWk6DQoNClxbDQpYX3tyLGN9XnsxLDF9DQo9DQpcb3BlcmF0b3JuYW1le1JlTFV9DQpcbGVmdCgNCldfe1xtYXRocm17ZGVjfSwxfV57KDEsMSl9WF97cixjfV57MSwwfQ0KKw0KV197XG1hdGhybXtkZWN9LDJ9XnsoMSwxKX0NClxsZWZ0Ww0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MiwwfQ0KXHJpZ2h0KQ0KXHJpZ2h0XV97cixjfQ0KXHJpZ2h0KS4NClxdDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gbm9kZSBkZWNvZGVyIHBhZGEgcG9zaXNpIFwoKDEsMSlcKToqKg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpYX3sxLDF9XnsxLDF9DQomPQ0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQpXX3tcbWF0aHJte2RlY30sMX1eeygxLDEpfVhfezEsMX1eezEsMH0NCisNCldfe1xtYXRocm17ZGVjfSwyfV57KDEsMSl9DQpcbGVmdFsNClxvcGVyYXRvcm5hbWV7VXB9DQpcbGVmdCgNClxtYXRoYmZ7WH1eezIsMH0NClxyaWdodCkNClxyaWdodF1fezEsMX0NClxyaWdodClcXA0KJj0NClxvcGVyYXRvcm5hbWV7UmVMVX0NClxsZWZ0KA0KMS4wMCgtMi4zOSkrMS4wMCgtMi4zOSkNClxyaWdodClcXA0KJj0NClxvcGVyYXRvcm5hbWV7UmVMVX0oLTQuNzgpXFwNCiY9DQowLjAwLg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiBub2RlIGRlY29kZXIgcGFkYSBwb3Npc2kgdGVuZ2FoIFwoKDIsMilcKToqKg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpYX3syLDJ9XnsxLDF9DQomPQ0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQpXX3tcbWF0aHJte2RlY30sMX1eeygxLDEpfVhfezIsMn1eezEsMH0NCisNCldfe1xtYXRocm17ZGVjfSwyfV57KDEsMSl9DQpcbGVmdFsNClxvcGVyYXRvcm5hbWV7VXB9DQpcbGVmdCgNClxtYXRoYmZ7WH1eezIsMH0NClxyaWdodCkNClxyaWdodF1fezIsMn0NClxyaWdodClcXA0KJj0NClxvcGVyYXRvcm5hbWV7UmVMVX0NClxsZWZ0KA0KMS4wMCgyLjI0KSsxLjAwKC0yLjEyKQ0KXHJpZ2h0KVxcDQomPQ0KXG9wZXJhdG9ybmFtZXtSZUxVfSgwLjEyKVxcDQomPQ0KMC4xMi4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBtZW5lcmFwa2FuIG9wZXJhc2kgeWFuZyBzYW1hIHBhZGEgc2VsdXJ1aCBwb3Npc2kgc3Bhc2lhbCwgZGlwZXJvbGVoICpmZWF0dXJlIG1hcCogbm9kZSAqZGVjb2RlciogcGVydGFtYSBzZWJhZ2FpIGJlcmlrdXQ6DQoNClxbDQpcbWF0aGJme1h9XnsxLDF9DQo9DQpcYmVnaW57Ym1hdHJpeH0NCjAuMDAgJiAwLjAwICYgMC4wMFxcDQowLjAwICYgMC4xMiAmIDAuMDBcXA0KMC4wMCAmIDAuMDAgJiAwLjAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KSGFzaWwgdGVyc2VidXQgbWVudW5qdWtrYW4gYmFod2EgKmZlYXR1cmUgbWFwKiBoYXNpbCBVcHNhbXBsaW5nIGRhcGF0IGRpZ2FidW5na2FuIGRlbmdhbiAqZmVhdHVyZSBtYXAqIGRhcmkgamFsdXIgKmVuY29kZXIqIG1lbGFsdWkgKm5lc3RlZCBza2lwIGNvbm5lY3Rpb24qLiBQYWRhIGlsdXN0cmFzaSBpbmksIHBlbmdnYWJ1bmdhbiBkaWxha3VrYW4gbWVuZ2d1bmFrYW4gKkNvbmNhdCosIGtvbnZvbHVzaSBcKDFcdGltZXMxXCksIGRhbiBmdW5nc2kgYWt0aXZhc2kgUmVMVS4gKkZlYXR1cmUgbWFwKiBcKFxtYXRoYmZ7WH1eezEsMX1cKSBzZWxhbmp1dG55YSBkaWd1bmFrYW4gcGFkYSBwZW1iZW50dWthbiBub2RlICpkZWNvZGVyKiBiZXJpa3V0bnlhLg0KDQoNCg0KDQojIyMgYi4gVXBzYW1wbGluZyBcKFxtYXRoYmZ7WH1eezEsMH1cKSBkYW4gKk5lc3RlZCBTa2lwKiBQZXJ0YW1hIFwoXG1hdGhiZntYfV57MCwxfVwpDQoNCipGZWF0dXJlIG1hcCBlbmNvZGVyKiBwZXJ0YW1hIFwoXG1hdGhiZntYfV57MSwwfVwpIGJlcnVrdXJhbiBcKDNcdGltZXMzXCkgZGlwZXJiZXNhciBtZW5qYWRpIFwoNVx0aW1lczVcKSBtZW5nZ3VuYWthbiBpbnRlcnBvbGFzaSBiaWxpbmVhci4gUHJvc2VzIGluaSBiZXJ0dWp1YW4gdW50dWsgbWVueWVzdWFpa2FuIHVrdXJhbiBzcGFzaWFsICpmZWF0dXJlIG1hcCogc2VoaW5nZ2EgZGFwYXQgZGlnYWJ1bmdrYW4gZGVuZ2FuIFwoXG1hdGhiZntYfV57MCwwfVwpIG1lbGFsdWkgKm5lc3RlZCBza2lwIGNvbm5lY3Rpb24qLg0KDQpNYXRyaWtzICpmZWF0dXJlIG1hcCogbWFzdWthbiBhZGFsYWg6DQoNClxbDQpcbWF0aGJme1h9XnsxLDB9DQo9DQpcYmVnaW57Ym1hdHJpeH0NCi0yLjM5ICYgMS44MiAmIC0xLjg0XFwNCi0yLjM4ICYgMi4yNCAmIC0xLjcwXFwNCi0yLjI1ICYgMC43NyAmIC0xLjk5DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KLSAqKlJ1bXVzIGludGVycG9sYXNpIGJpbGluZWFyOioqDQoNCkludGVycG9sYXNpIGJpbGluZWFyIGRpbGFrdWthbiBtZW5nZ3VuYWthbiBwcmluc2lwIHlhbmcgc2FtYSBzZXBlcnRpIHBhZGEgc3ViYmFnaWFuIHNlYmVsdW1ueWEuIE5pbGFpIGtlbHVhcmFuIGRpaGl0dW5nIGJlcmRhc2Fya2FuIGphcmFrIHRlcmhhZGFwIGVsZW1lbi1lbGVtZW4gcGFkYSAqZmVhdHVyZSBtYXAqIG1hc3VrYW4uDQoNClBhZGEgKmZlYXR1cmUgbWFwKiBzYXR1IGthbmFsLCBydW11cyBpbnRlcnBvbGFzaSBiaWxpbmVhciBkaW55YXRha2FuIHNlYmFnYWk6DQoNClxbDQpcbGVmdFsNClxvcGVyYXRvcm5hbWV7VXB9DQpcbGVmdCgNClxtYXRoYmZ7WH1eezEsMH0NClxyaWdodCkNClxyaWdodF1fe3IsY30NCj0NClxzdW1fe249MX1eezN9DQpcc3VtX3ttPTF9XnszfQ0KWF97bixtfV57MSwwfQ0KXG1heA0KXGxlZnQoDQowLA0KMS1cbGVmdHx4X2MtbVxyaWdodHwNClxyaWdodCkNClxtYXgNClxsZWZ0KA0KMCwNCjEtXGxlZnR8eV9yLW5ccmlnaHR8DQpccmlnaHQpLg0KXF0NCg0KUGFkYSBwZXJzYW1hYW4gdGVyc2VidXQsIFwoclwpIGRhbiBcKGNcKSBtZW55YXRha2FuIGluZGVrcyBiYXJpcyBkYW4ga29sb20gcGFkYSAqZmVhdHVyZSBtYXAqIGtlbHVhcmFuLCBzZWRhbmdrYW4gXChuXCkgZGFuIFwobVwpIG1lbnlhdGFrYW4gaW5kZWtzIGJhcmlzIGRhbiBrb2xvbSBwYWRhICpmZWF0dXJlIG1hcCogbWFzdWthbi4gS29vcmRpbmF0IFwoeF9jXCkgbWVudW5qdWtrYW4gcG9zaXNpIGhvcml6b250YWwgYXRhdSBhcmFoIGtvbG9tLCBzZWRhbmdrYW4gXCh5X3JcKSBtZW51bmp1a2thbiBwb3Npc2kgdmVydGlrYWwgYXRhdSBhcmFoIGJhcmlzLg0KDQpCb2JvdCBpbnRlcnBvbGFzaSBwYWRhIHNldGlhcCBlbGVtZW4gbWFzdWthbiBkaW55YXRha2FuIHNlYmFnYWk6DQoNClxbDQp3X3tuLG19XnsocixjKX0NCj0NClxtYXgNClxsZWZ0KA0KMCwNCjEtXGxlZnR8eF9jLW1ccmlnaHR8DQpccmlnaHQpDQpcbWF4DQpcbGVmdCgNCjAsDQoxLVxsZWZ0fHlfci1uXHJpZ2h0fA0KXHJpZ2h0KS4NClxdDQoNCkRlbmdhbiBkZW1pa2lhbiwgcnVtdXMgaW50ZXJwb2xhc2kgYmlsaW5lYXIgZGFwYXQgZGl0dWxpc2thbiBzZWJhZ2FpOg0KDQpcWw0KXGxlZnRbDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsxLDB9DQpccmlnaHQpDQpccmlnaHRdX3tyLGN9DQo9DQpcc3VtX3tuPTF9XnszfQ0KXHN1bV97bT0xfV57M30NCndfe24sbX1eeyhyLGMpfVhfe24sbX1eezEsMH0uDQpcXQ0KDQotICoqUGVuZW50dWFuIGtvb3JkaW5hdCBpbnRlcnBvbGFzaToqKg0KDQpQYWRhIGlsdXN0cmFzaSBpbmksIGtvb3JkaW5hdCBtYXRyaWtzIG1lbmdndW5ha2FuIGluZGVrcyB5YW5nIGRpbXVsYWkgZGFyaSBcKDFcKS4gS2FyZW5hIHVrdXJhbiAqZmVhdHVyZSBtYXAqIG1hc3VrYW4gYWRhbGFoIFwoM1x0aW1lczNcKSBkYW4gdWt1cmFuIGtlbHVhcmFuIGFkYWxhaCBcKDVcdGltZXM1XCksIGtvb3JkaW5hdCBpbnRlcnBvbGFzaSBkaXRlbnR1a2FuIHNlYmFnYWk6DQoNClxbDQp4X2MNCj0NCjErKGMtMSlcZnJhY3szLTF9ezUtMX0NCj0NCjErXGZyYWN7Yy0xfXsyfSwNClxdDQoNClxbDQp5X3INCj0NCjErKHItMSlcZnJhY3szLTF9ezUtMX0NCj0NCjErXGZyYWN7ci0xfXsyfSwNClxdDQoNCmRlbmdhbiBcKHIsYz0xLDIsMyw0LDVcKS4NCg0KQW5na2EgXCgxXCkgbWVudW5qdWtrYW4ga29vcmRpbmF0IGF3YWwgbWF0cmlrcyBtYXN1a2FuLCBzZWRhbmdrYW4gcGVtYmFnaWFuIGRlbmdhbiBcKDJcKSBtZW51bmp1a2thbiBiYWh3YSBzZXRpYXAgaW50ZXJ2YWwgYW50YXJhIGR1YSBrb29yZGluYXQgbWFzdWthbiBkaWJhZ2kgbWVuamFkaSBkdWEgYmFnaWFuIHlhbmcgc2FtYSBwYW5qYW5nLg0KDQpOaWxhaSBrb29yZGluYXQgeWFuZyBkaXBlcm9sZWggYWRhbGFoOg0KDQp8IEluZGVrcyBrZWx1YXJhbiB8IE5pbGFpIGtvb3JkaW5hdCB8DQp8Oi0tLTp8Oi0tLTp8DQp8IFwoMVwpIHwgXCgxXCkgfA0KfCBcKDJcKSB8IFwoMS41XCkgfA0KfCBcKDNcKSB8IFwoMlwpIHwNCnwgXCg0XCkgfCBcKDIuNVwpIHwNCnwgXCg1XCkgfCBcKDNcKSB8DQoNCkRlbmdhbiBkZW1pa2lhbiwgbmlsYWkgcGFkYSBwb3Npc2kga2VsdWFyYW4geWFuZyBiZXJpbXBpdCBkZW5nYW4ga29vcmRpbmF0IG1hc3VrYW4gZGlwZXJ0YWhhbmthbiwgc2VkYW5na2FuIG5pbGFpIHBhZGEgcG9zaXNpIGxhaW5ueWEgZGloaXR1bmcgYmVyZGFzYXJrYW4gYm9ib3QgamFyYWsgdGVyaGFkYXAgZWxlbWVuLWVsZW1lbiBtYXN1a2FuIGRpIHNla2l0YXJueWEuDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gaW50ZXJwb2xhc2kgYmlsaW5lYXIgcGFkYSBwb3Npc2kgXCgoMSwyKVwpOioqDQoNClBhZGEgcG9zaXNpIFwoKDEsMilcKSwga29vcmRpbmF0IGludGVycG9sYXNpIGRpcGVyb2xlaCBzZWJhZ2FpIGJlcmlrdXQ6DQoNClxbDQp5XzE9MSwNClxxcXVhZA0KeF8yPTEuNS4NClxdDQoNClBvc2lzaSB0ZXJzZWJ1dCBiZXJhZGEgdGVwYXQgZGkgdGVuZ2FoIGFudGFyYSBrb2xvbSBwZXJ0YW1hIGRhbiBrb2xvbSBrZWR1YSBwYWRhIGJhcmlzIHBlcnRhbWEuIEJvYm90IGludGVycG9sYXNpIHVudHVrIGVsZW1lbiBcKFhfezEsMX1eezEsMH1cKSBkaWhpdHVuZyBzZWJhZ2FpOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQp3X3sxLDF9XnsoMSwyKX0NCiY9DQpcbWF4KDAsMS18MS41LTF8KQ0KXG1heCgwLDEtfDEtMXwpXFwNCiY9DQowLjVcdGltZXMxXFwNCiY9DQowLjUuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpTZW1lbnRhcmEgaXR1LCBib2JvdCB1bnR1ayBlbGVtZW4gXChYX3sxLDJ9XnsxLDB9XCkgYWRhbGFoOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQp3X3sxLDJ9XnsoMSwyKX0NCiY9DQpcbWF4KDAsMS18MS41LTJ8KQ0KXG1heCgwLDEtfDEtMXwpXFwNCiY9DQowLjVcdGltZXMxXFwNCiY9DQowLjUuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpFbGVtZW4gbGFpbm55YSBtZW1pbGlraSBib2JvdCBub2wga2FyZW5hIGJlcmFkYSBkaSBsdWFyIGphcmFrIGludGVycG9sYXNpIHBhZGEgcG9zaXNpIHRlcnNlYnV0LiBEZW5nYW4gZGVtaWtpYW46DQoNClxbDQp3X3sxLDF9XnsoMSwyKX0NCj0NCndfezEsMn1eeygxLDIpfQ0KPQ0KMC41Lg0KXF0NCg0KRGVuZ2FuIG1lbWFzdWtrYW4gYm9ib3QgdGVyc2VidXQga2UgZGFsYW0gcnVtdXMgaW50ZXJwb2xhc2kgYmlsaW5lYXIsIGRpcGVyb2xlaDoNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KXGxlZnRbDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsxLDB9DQpccmlnaHQpDQpccmlnaHRdX3sxLDJ9DQomPQ0KMC41WF97MSwxfV57MSwwfQ0KKw0KMC41WF97MSwyfV57MSwwfVxcDQomPQ0KXGZyYWN7DQpYX3sxLDF9XnsxLDB9DQorDQpYX3sxLDJ9XnsxLDB9DQp9ezJ9XFwNCiY9DQpcZnJhY3stMi4zOSsxLjgyfXsyfVxcDQomPQ0KLTAuMjg1XFwNCiZcYXBwcm94LTAuMjkuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuIGludGVycG9sYXNpIGJpbGluZWFyIHBhZGEgcG9zaXNpIHRlbmdhaCBcKCgyLDIpXCk6KioNCg0KUGFkYSBwb3Npc2kgXCgoMiwyKVwpLCBrb29yZGluYXQgaW50ZXJwb2xhc2kgZGlwZXJvbGVoIHNlYmFnYWkgYmVyaWt1dDoNCg0KXFsNCnlfMj0xLjUsDQpccXF1YWQNCnhfMj0xLjUuDQpcXQ0KDQpQb3Npc2kgdGVyc2VidXQgYmVyYWRhIHRlcGF0IGRpIHRlbmdhaCBlbXBhdCBlbGVtZW4gbWFzdWthbiwgeWFpdHUgXChYX3sxLDF9XnsxLDB9XCksIFwoWF97MSwyfV57MSwwfVwpLCBcKFhfezIsMX1eezEsMH1cKSwgZGFuIFwoWF97MiwyfV57MSwwfVwpLg0KDQpCb2JvdCBpbnRlcnBvbGFzaSB1bnR1ayBlbGVtZW4gXChYX3sxLDF9XnsxLDB9XCkgZGloaXR1bmcgc2ViYWdhaToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0Kd197MSwxfV57KDIsMil9DQomPQ0KXG1heCgwLDEtfDEuNS0xfCkNClxtYXgoMCwxLXwxLjUtMXwpXFwNCiY9DQowLjVcdGltZXMwLjVcXA0KJj0NCjAuMjUuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpLYXJlbmEgcG9zaXNpIHRlcnNlYnV0IGJlcmphcmFrIHNhbWEgZGFyaSBrZWVtcGF0IGVsZW1lbiBtYXN1a2FuLCBtYWthOg0KDQpcWw0Kd197MSwxfV57KDIsMil9DQo9DQp3X3sxLDJ9XnsoMiwyKX0NCj0NCndfezIsMX1eeygyLDIpfQ0KPQ0Kd197MiwyfV57KDIsMil9DQo9DQowLjI1Lg0KXF0NCg0KRGVuZ2FuIGRlbWlraWFuLCBydW11cyBpbnRlcnBvbGFzaSBiaWxpbmVhciBtZW5qYWRpOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcbGVmdFsNClxvcGVyYXRvcm5hbWV7VXB9DQpcbGVmdCgNClxtYXRoYmZ7WH1eezEsMH0NClxyaWdodCkNClxyaWdodF1fezIsMn0NCiY9DQowLjI1WF97MSwxfV57MSwwfQ0KKw0KMC4yNVhfezEsMn1eezEsMH1cXA0KJlxxdWFkKw0KMC4yNVhfezIsMX1eezEsMH0NCisNCjAuMjVYX3syLDJ9XnsxLDB9XFwNCiY9DQpcZnJhY3sNClhfezEsMX1eezEsMH0NCisNClhfezEsMn1eezEsMH0NCisNClhfezIsMX1eezEsMH0NCisNClhfezIsMn1eezEsMH0NCn17NH1cXA0KJj0NClxmcmFjey0yLjM5KzEuODItMi4zOCsyLjI0fXs0fVxcDQomPQ0KLTAuMTc3NVxcDQomXGFwcHJveC0wLjE4Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KRGVuZ2FuIG1lbmVyYXBrYW4gaW50ZXJwb2xhc2kgYmlsaW5lYXIgcGFkYSBzZWx1cnVoIHBvc2lzaSBrZWx1YXJhbiwgZGlwZXJvbGVoICpmZWF0dXJlIG1hcCogaGFzaWwgVXBzYW1wbGluZyBiZXJ1a3VyYW4gXCg1XHRpbWVzNVwpLCB5YWl0dToNCg0KXFsNClxvcGVyYXRvcm5hbWV7VXB9DQpcbGVmdCgNClxtYXRoYmZ7WH1eezEsMH0NClxyaWdodCkNCj0NClxiZWdpbntibWF0cml4fQ0KLTIuMzkgJiAtMC4yOSAmIDEuODIgJiAtMC4wMSAmIC0xLjg0XFwNCi0yLjM5ICYgLTAuMTggJiAyLjAzICYgMC4xMyAmIC0xLjc3XFwNCi0yLjM4ICYgLTAuMDcgJiAyLjI0ICYgMC4yNyAmIC0xLjcwXFwNCi0yLjMyICYgLTAuNDEgJiAxLjUxICYgLTAuMTcgJiAtMS44NVxcDQotMi4yNSAmIC0wLjc0ICYgMC43NyAmIC0wLjYxICYgLTEuOTkNClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQpIYXNpbCB0ZXJzZWJ1dCBtZW51bmp1a2thbiBiYWh3YSBpbnRlcnBvbGFzaSBiaWxpbmVhciBtZW1wZXJiZXNhciB1a3VyYW4gc3Bhc2lhbCAqZmVhdHVyZSBtYXAqIGRhcmkgXCgzXHRpbWVzM1wpIG1lbmphZGkgXCg1XHRpbWVzNVwpLiBOaWxhaSBwYWRhIHBvc2lzaSB5YW5nIGJlcmltcGl0IGRlbmdhbiBrb29yZGluYXQgbWFzdWthbiBkaXBlcnRhaGFua2FuLCBzZWRhbmdrYW4gbmlsYWkgcGFkYSBwb3Npc2kgbGFpbm55YSBkaWhpdHVuZyBtZW5nZ3VuYWthbiBib2JvdCBpbnRlcnBvbGFzaSBiZXJkYXNhcmthbiBqYXJhayB0ZXJoYWRhcCBlbGVtZW4gbWFzdWthbi4NCg0KLSAqKlJ1bXVzIG5vZGUgZGVjb2RlcjoqKg0KDQpTZXN1YWkgZGVuZ2FuIHBlcnNhbWFhbiBVTmV0KyssICpuZXN0ZWQgc2tpcCBjb25uZWN0aW9uKiBwZXJ0YW1hIHBhZGEgbm9kZSAqZGVjb2RlciogZGlydW11c2thbiBzZWJhZ2FpOg0KDQpcWw0KXG1hdGhiZntYfV57MCwxfQ0KPQ0KSF57KDAsMSl9DQpcbGVmdCgNClxvcGVyYXRvcm5hbWV7Q29uY2F0fQ0KXGxlZnRbDQpcbWF0aGJme1h9XnswLDB9LA0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MSwwfQ0KXHJpZ2h0KQ0KXHJpZ2h0XQ0KXHJpZ2h0KS4NClxdDQoNClBhZGEgcGVyc2FtYWFuIHRlcnNlYnV0LCBcKEheeygwLDEpfVwpIG1lbnlhdGFrYW4gb3BlcmFzaSBwZW5nb2xhaGFuIGZpdHVyIHBhZGEgbm9kZSAqZGVjb2RlciogXChcbWF0aGJme1h9XnswLDF9XCkuIERhbGFtIGlsdXN0cmFzaSBwZXJoaXR1bmdhbiBtYW51YWwgaW5pLCBvcGVyYXNpIHRlcnNlYnV0IGRpc2VkZXJoYW5ha2FuIG1lbmdndW5ha2FuIGtvbnZvbHVzaSBcKDFcdGltZXMxXCkgdGFucGEgYmlhcyB5YW5nIGRpaWt1dGkgZnVuZ3NpIGFrdGl2YXNpIFJlTFUuDQoNCkthcmVuYSBrZWR1YSAqZmVhdHVyZSBtYXAqIHlhbmcgZGlnYWJ1bmdrYW4gYmVydWt1cmFuIFwoNVx0aW1lczVcKSBkYW4gbWFzaW5nLW1hc2luZyBkaXJlcHJlc2VudGFzaWthbiBvbGVoIHNhdHUga2FuYWwsIGhhc2lsICpDb25jYXQqIG1lbWlsaWtpIGR1YSBrYW5hbC4gU2F0dSBmaWx0ZXIga29udm9sdXNpIFwoMVx0aW1lczFcKSBkaWd1bmFrYW4gdW50dWsgbWVuZ2dhYnVuZ2thbiBrZWR1YSBrYW5hbCB0ZXJzZWJ1dCBtZW5qYWRpIHNhdHUga2FuYWwga2VsdWFyYW4uDQoNClBhZGEgaWx1c3RyYXNpIGluaSwgYm9ib3Qga2VybmVsIGRpdGVudHVrYW4gc2ViYWdhaToNCg0KXFsNCldfe1xtYXRocm17ZGVjfSwxfV57KDAsMSl9PVsxLjAwXSwNClxxcXVhZA0KV197XG1hdGhybXtkZWN9LDJ9XnsoMCwxKX09WzEuMDBdLg0KXF0NCg0KQm9ib3QgcGVydGFtYSBkaXRlcmFwa2FuIHBhZGEgXChcbWF0aGJme1h9XnswLDB9XCksIHNlZGFuZ2thbiBib2JvdCBrZWR1YSBkaXRlcmFwa2FuIHBhZGEgXChcb3BlcmF0b3JuYW1le1VwfShcbWF0aGJme1h9XnsxLDB9KVwpLg0KDQpEZW5nYW4gZGVtaWtpYW4sIHVudHVrIHNldGlhcCBwb3Npc2kgc3Bhc2lhbCBcKChyLGMpXCksIGtlbHVhcmFuIG5vZGUgKmRlY29kZXIqIGRpaGl0dW5nIHNlYmFnYWk6DQoNClxbDQpYX3tyLGN9XnswLDF9DQo9DQpcb3BlcmF0b3JuYW1le1JlTFV9DQpcbGVmdCgNCldfe1xtYXRocm17ZGVjfSwxfV57KDAsMSl9WF97cixjfV57MCwwfQ0KKw0KV197XG1hdGhybXtkZWN9LDJ9XnsoMCwxKX0NClxsZWZ0Ww0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MSwwfQ0KXHJpZ2h0KQ0KXHJpZ2h0XV97cixjfQ0KXHJpZ2h0KS4NClxdDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gbm9kZSBkZWNvZGVyIHBhZGEgcG9zaXNpIFwoKDEsMSlcKToqKg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpYX3sxLDF9XnswLDF9DQomPQ0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQpXX3tcbWF0aHJte2RlY30sMX1eeygwLDEpfVhfezEsMX1eezAsMH0NCisNCldfe1xtYXRocm17ZGVjfSwyfV57KDAsMSl9DQpcbGVmdFsNClxvcGVyYXRvcm5hbWV7VXB9DQpcbGVmdCgNClxtYXRoYmZ7WH1eezEsMH0NClxyaWdodCkNClxyaWdodF1fezEsMX0NClxyaWdodClcXA0KJj0NClxvcGVyYXRvcm5hbWV7UmVMVX0NClxsZWZ0KA0KMS4wMCgtMi4zOSkNCisNCjEuMDAoLTIuMzkpDQpccmlnaHQpXFwNCiY9DQpcb3BlcmF0b3JuYW1le1JlTFV9KC00Ljc4KVxcDQomPQ0KMC4wMC4NClxlbmR7YWxpZ25lZH0NClxdDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gbm9kZSBkZWNvZGVyIHBhZGEgcG9zaXNpIFwoKDEsMylcKToqKg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpYX3sxLDN9XnswLDF9DQomPQ0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQpXX3tcbWF0aHJte2RlY30sMX1eeygwLDEpfVhfezEsM31eezAsMH0NCisNCldfe1xtYXRocm17ZGVjfSwyfV57KDAsMSl9DQpcbGVmdFsNClxvcGVyYXRvcm5hbWV7VXB9DQpcbGVmdCgNClxtYXRoYmZ7WH1eezEsMH0NClxyaWdodCkNClxyaWdodF1fezEsM30NClxyaWdodClcXA0KJj0NClxvcGVyYXRvcm5hbWV7UmVMVX0NClxsZWZ0KA0KMS4wMCgxLjgyKQ0KKw0KMS4wMCgxLjgyKQ0KXHJpZ2h0KVxcDQomPQ0KXG9wZXJhdG9ybmFtZXtSZUxVfSgzLjY0KVxcDQomPQ0KMy42NC4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBtZW5lcmFwa2FuIG9wZXJhc2kgeWFuZyBzYW1hIHBhZGEgc2VsdXJ1aCBwb3Npc2kgc3Bhc2lhbCwgZGlwZXJvbGVoICpmZWF0dXJlIG1hcCogbm9kZSAqZGVjb2Rlciogc2ViYWdhaSBiZXJpa3V0Og0KDQpcWw0KXG1hdGhiZntYfV57MCwxfQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjAwICYgMC4wMCAmIDMuNjQgJiAxLjExICYgMC4wMFxcDQowLjAwICYgMC4wMCAmIDQuMjcgJiAxLjYzICYgMC4wMFxcDQowLjAwICYgMC4wMCAmIDQuNDggJiAxLjc3ICYgMC4wMFxcDQowLjAwICYgMC4wMCAmIDMuMzUgJiAwLjk0ICYgMC4wMFxcDQowLjAwICYgMC4wMCAmIDEuNTQgJiAwLjAwICYgMC4wMA0KXGVuZHtibWF0cml4fS4NClxdDQoNCkhhc2lsIHRlcnNlYnV0IG1lbnVuanVra2FuIGJhaHdhIG5vZGUgXChcbWF0aGJme1h9XnswLDF9XCkgbWVuZ2dhYnVuZ2thbiBpbmZvcm1hc2kgZGFyaSAqZmVhdHVyZSBtYXAgZW5jb2RlciogXChcbWF0aGJme1h9XnswLDB9XCkgZGFuIGhhc2lsIFVwc2FtcGxpbmcgXChcbWF0aGJme1h9XnsxLDB9XCkgbWVsYWx1aSAqbmVzdGVkIHNraXAgY29ubmVjdGlvbiouIFBhZGEgaWx1c3RyYXNpIGluaSwgcGVuZ2dhYnVuZ2FuIGRpbGFrdWthbiBtZW5nZ3VuYWthbiAqQ29uY2F0Kiwga29udm9sdXNpIFwoMVx0aW1lczFcKSwgZGFuIGZ1bmdzaSBha3RpdmFzaSBSZUxVLiAqRmVhdHVyZSBtYXAqIFwoXG1hdGhiZntYfV57MCwxfVwpIHNlbGFuanV0bnlhIGRpZ3VuYWthbiBwYWRhIHBlbWJlbnR1a2FuIG5vZGUgKmRlY29kZXIqIGJlcmlrdXRueWEuDQoNCg0KDQojIyMgYy4gVXBzYW1wbGluZyBcKFxtYXRoYmZ7WH1eezEsMX1cKSBkYW4gKk5lc3RlZCBTa2lwKiBLZWR1YSBcKFxtYXRoYmZ7WH1eezAsMn1cKQ0KDQpOb2RlICpkZWNvZGVyKiBcKFxtYXRoYmZ7WH1eezEsMX1cKSBiZXJ1a3VyYW4gXCgzXHRpbWVzM1wpIGRpcGVyYmVzYXIgbWVuamFkaSBcKDVcdGltZXM1XCkgbWVuZ2d1bmFrYW4gaW50ZXJwb2xhc2kgYmlsaW5lYXIuIFByb3NlcyBpbmkgYmVydHVqdWFuIHVudHVrIG1lbnllc3VhaWthbiB1a3VyYW4gc3Bhc2lhbCAqZmVhdHVyZSBtYXAqIHNlaGluZ2dhIGRhcGF0IGRpZ2FidW5na2FuIGRlbmdhbiBcKFxtYXRoYmZ7WH1eezAsMH1cKSBkYW4gXChcbWF0aGJme1h9XnswLDF9XCkgbWVsYWx1aSAqbmVzdGVkIHNraXAgY29ubmVjdGlvbiouDQoNCk1hdHJpa3MgKmZlYXR1cmUgbWFwKiBtYXN1a2FuIGFkYWxhaDoNCg0KXFsNClxtYXRoYmZ7WH1eezEsMX0NCj0NClxiZWdpbntibWF0cml4fQ0KMC4wMCAmIDAuMDAgJiAwLjAwXFwNCjAuMDAgJiAwLjEyICYgMC4wMFxcDQowLjAwICYgMC4wMCAmIDAuMDANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQotICoqUnVtdXMgaW50ZXJwb2xhc2kgYmlsaW5lYXI6KioNCg0KSW50ZXJwb2xhc2kgYmlsaW5lYXIgZGlsYWt1a2FuIG1lbmdndW5ha2FuIHByaW5zaXAgeWFuZyBzYW1hIHNlcGVydGkgcGFkYSBzdWJiYWdpYW4gc2ViZWx1bW55YS4gU2V0aWFwIG5pbGFpIGtlbHVhcmFuIGRpaGl0dW5nIGJlcmRhc2Fya2FuIGphcmFrIHRlcmhhZGFwIGVsZW1lbi1lbGVtZW4gcGFkYSAqZmVhdHVyZSBtYXAqIG1hc3VrYW4uDQoNClBhZGEgKmZlYXR1cmUgbWFwKiBzYXR1IGthbmFsLCBydW11cyBpbnRlcnBvbGFzaSBiaWxpbmVhciBkaW55YXRha2FuIHNlYmFnYWk6DQoNClxbDQpcbGVmdFsNClxvcGVyYXRvcm5hbWV7VXB9DQpcbGVmdCgNClxtYXRoYmZ7WH1eezEsMX0NClxyaWdodCkNClxyaWdodF1fe3IsY30NCj0NClxzdW1fe249MX1eezN9DQpcc3VtX3ttPTF9XnszfQ0KWF97bixtfV57MSwxfQ0KXG1heA0KXGxlZnQoDQowLA0KMS1cbGVmdHx4X2MtbVxyaWdodHwNClxyaWdodCkNClxtYXgNClxsZWZ0KA0KMCwNCjEtXGxlZnR8eV9yLW5ccmlnaHR8DQpccmlnaHQpLg0KXF0NCg0KUGFkYSBwZXJzYW1hYW4gdGVyc2VidXQsIFwoclwpIGRhbiBcKGNcKSBtZW55YXRha2FuIGluZGVrcyBiYXJpcyBkYW4ga29sb20gcGFkYSAqZmVhdHVyZSBtYXAqIGtlbHVhcmFuLCBzZWRhbmdrYW4gXChuXCkgZGFuIFwobVwpIG1lbnlhdGFrYW4gaW5kZWtzIGJhcmlzIGRhbiBrb2xvbSBwYWRhICpmZWF0dXJlIG1hcCogbWFzdWthbi4gS29vcmRpbmF0IFwoeF9jXCkgbWVudW5qdWtrYW4gcG9zaXNpIGhvcml6b250YWwgYXRhdSBhcmFoIGtvbG9tLCBzZWRhbmdrYW4gXCh5X3JcKSBtZW51bmp1a2thbiBwb3Npc2kgdmVydGlrYWwgYXRhdSBhcmFoIGJhcmlzLg0KDQpCb2JvdCBpbnRlcnBvbGFzaSBwYWRhIHNldGlhcCBlbGVtZW4gbWFzdWthbiBkaW55YXRha2FuIHNlYmFnYWk6DQoNClxbDQp3X3tuLG19XnsocixjKX0NCj0NClxtYXgNClxsZWZ0KA0KMCwNCjEtXGxlZnR8eF9jLW1ccmlnaHR8DQpccmlnaHQpDQpcbWF4DQpcbGVmdCgNCjAsDQoxLVxsZWZ0fHlfci1uXHJpZ2h0fA0KXHJpZ2h0KS4NClxdDQoNCkRlbmdhbiBkZW1pa2lhbiwgcnVtdXMgaW50ZXJwb2xhc2kgYmlsaW5lYXIgZGFwYXQgZGl0dWxpc2thbiBzZWJhZ2FpOg0KDQpcWw0KXGxlZnRbDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsxLDF9DQpccmlnaHQpDQpccmlnaHRdX3tyLGN9DQo9DQpcc3VtX3tuPTF9XnszfQ0KXHN1bV97bT0xfV57M30NCndfe24sbX1eeyhyLGMpfVhfe24sbX1eezEsMX0uDQpcXQ0KDQotICoqUGVuZW50dWFuIGtvb3JkaW5hdCBpbnRlcnBvbGFzaToqKg0KDQpQYWRhIGlsdXN0cmFzaSBpbmksIGtvb3JkaW5hdCBtYXRyaWtzIG1lbmdndW5ha2FuIGluZGVrcyB5YW5nIGRpbXVsYWkgZGFyaSBcKDFcKS4gS2FyZW5hIHVrdXJhbiAqZmVhdHVyZSBtYXAqIG1hc3VrYW4gYWRhbGFoIFwoM1x0aW1lczNcKSBkYW4gdWt1cmFuIGtlbHVhcmFuIGFkYWxhaCBcKDVcdGltZXM1XCksIGtvb3JkaW5hdCBpbnRlcnBvbGFzaSBkaXRlbnR1a2FuIHNlYmFnYWk6DQoNClxbDQp4X2MNCj0NCjErKGMtMSlcZnJhY3szLTF9ezUtMX0NCj0NCjErXGZyYWN7Yy0xfXsyfSwNClxdDQoNClxbDQp5X3INCj0NCjErKHItMSlcZnJhY3szLTF9ezUtMX0NCj0NCjErXGZyYWN7ci0xfXsyfSwNClxdDQoNCmRlbmdhbiBcKHIsYz0xLDIsMyw0LDVcKS4NCg0KQW5na2EgXCgxXCkgbWVudW5qdWtrYW4ga29vcmRpbmF0IGF3YWwgbWF0cmlrcyBtYXN1a2FuLCBzZWRhbmdrYW4gcGVtYmFnaWFuIGRlbmdhbiBcKDJcKSBtZW51bmp1a2thbiBiYWh3YSBzZXRpYXAgaW50ZXJ2YWwgYW50YXJhIGR1YSBrb29yZGluYXQgbWFzdWthbiBkaWJhZ2kgbWVuamFkaSBkdWEgYmFnaWFuIHlhbmcgc2FtYSBwYW5qYW5nLg0KDQpOaWxhaSBrb29yZGluYXQgeWFuZyBkaXBlcm9sZWggYWRhbGFoOg0KDQp8IEluZGVrcyBrZWx1YXJhbiB8IE5pbGFpIGtvb3JkaW5hdCB8DQp8Oi0tLTp8Oi0tLTp8DQp8IFwoMVwpIHwgXCgxXCkgfA0KfCBcKDJcKSB8IFwoMS41XCkgfA0KfCBcKDNcKSB8IFwoMlwpIHwNCnwgXCg0XCkgfCBcKDIuNVwpIHwNCnwgXCg1XCkgfCBcKDNcKSB8DQoNCkRlbmdhbiBkZW1pa2lhbiwgbmlsYWkgcGFkYSBwb3Npc2kga2VsdWFyYW4geWFuZyBiZXJpbXBpdCBkZW5nYW4ga29vcmRpbmF0IG1hc3VrYW4gZGlwZXJ0YWhhbmthbiwgc2VkYW5na2FuIG5pbGFpIHBhZGEgcG9zaXNpIGxhaW5ueWEgZGloaXR1bmcgYmVyZGFzYXJrYW4gYm9ib3QgamFyYWsgdGVyaGFkYXAgZWxlbWVuLWVsZW1lbiBtYXN1a2FuIGRpIHNla2l0YXJueWEuDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gaW50ZXJwb2xhc2kgYmlsaW5lYXIgcGFkYSBwb3Npc2kgXCgoMiwzKVwpOioqDQoNClBhZGEgcG9zaXNpIFwoKDIsMylcKSwga29vcmRpbmF0IGludGVycG9sYXNpIGRpcGVyb2xlaCBzZWJhZ2FpIGJlcmlrdXQ6DQoNClxbDQp5XzI9MS41LA0KXHFxdWFkDQp4XzM9Mi4NClxdDQoNClBvc2lzaSB0ZXJzZWJ1dCBiZXJhZGEgdGVwYXQgZGkgdGVuZ2FoIHNlY2FyYSB2ZXJ0aWthbCBhbnRhcmEgYmFyaXMgcGVydGFtYSBkYW4ga2VkdWEsIHRldGFwaSBzZWphamFyIGRlbmdhbiBrb2xvbSBrZWR1YS4gT2xlaCBrYXJlbmEgaXR1LCBoYW55YSBkdWEgZWxlbWVuIHBhZGEga29sb20ga2VkdWEgeWFuZyBtZW1pbGlraSBib2JvdCBidWthbiBub2wuDQoNCkJvYm90IGludGVycG9sYXNpIHVudHVrIGVsZW1lbiBcKFhfezEsMn1eezEsMX1cKSBkaWhpdHVuZyBzZWJhZ2FpOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQp3X3sxLDJ9XnsoMiwzKX0NCiY9DQpcbWF4KDAsMS18Mi0yfCkNClxtYXgoMCwxLXwxLjUtMXwpXFwNCiY9DQoxXHRpbWVzMC41XFwNCiY9DQowLjUuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpTZW1lbnRhcmEgaXR1LCBib2JvdCB1bnR1ayBlbGVtZW4gXChYX3syLDJ9XnsxLDF9XCkgYWRhbGFoOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQp3X3syLDJ9XnsoMiwzKX0NCiY9DQpcbWF4KDAsMS18Mi0yfCkNClxtYXgoMCwxLXwxLjUtMnwpXFwNCiY9DQoxXHRpbWVzMC41XFwNCiY9DQowLjUuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpFbGVtZW4gbGFpbm55YSBtZW1pbGlraSBib2JvdCBub2wga2FyZW5hIGJlcmFkYSBkaSBsdWFyIGphcmFrIGludGVycG9sYXNpIHBhZGEgcG9zaXNpIHRlcnNlYnV0LiBEZW5nYW4gZGVtaWtpYW46DQoNClxbDQp3X3sxLDJ9XnsoMiwzKX0NCj0NCndfezIsMn1eeygyLDMpfQ0KPQ0KMC41Lg0KXF0NCg0KRGVuZ2FuIG1lbWFzdWtrYW4gYm9ib3QgdGVyc2VidXQga2UgZGFsYW0gcnVtdXMgaW50ZXJwb2xhc2kgYmlsaW5lYXIsIGRpcGVyb2xlaDoNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KXGxlZnRbDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsxLDF9DQpccmlnaHQpDQpccmlnaHRdX3syLDN9DQomPQ0KMC41WF97MSwyfV57MSwxfQ0KKw0KMC41WF97MiwyfV57MSwxfVxcDQomPQ0KXGZyYWN7DQpYX3sxLDJ9XnsxLDF9DQorDQpYX3syLDJ9XnsxLDF9DQp9ezJ9XFwNCiY9DQpcZnJhY3swLjAwKzAuMTJ9ezJ9XFwNCiY9DQowLjA2Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiBpbnRlcnBvbGFzaSBiaWxpbmVhciBwYWRhIHBvc2lzaSBcKCgyLDIpXCk6KioNCg0KUGFkYSBwb3Npc2kgXCgoMiwyKVwpLCBrb29yZGluYXQgaW50ZXJwb2xhc2kgZGlwZXJvbGVoIHNlYmFnYWkgYmVyaWt1dDoNCg0KXFsNCnlfMj0xLjUsDQpccXF1YWQNCnhfMj0xLjUuDQpcXQ0KDQpQb3Npc2kgdGVyc2VidXQgYmVyYWRhIHRlcGF0IGRpIHRlbmdhaCBlbXBhdCBlbGVtZW4gbWFzdWthbiwgeWFpdHUgXChYX3sxLDF9XnsxLDF9XCksIFwoWF97MSwyfV57MSwxfVwpLCBcKFhfezIsMX1eezEsMX1cKSwgZGFuIFwoWF97MiwyfV57MSwxfVwpLg0KDQpCb2JvdCBpbnRlcnBvbGFzaSB1bnR1ayBlbGVtZW4gXChYX3sxLDF9XnsxLDF9XCkgZGloaXR1bmcgc2ViYWdhaToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0Kd197MSwxfV57KDIsMil9DQomPQ0KXG1heCgwLDEtfDEuNS0xfCkNClxtYXgoMCwxLXwxLjUtMXwpXFwNCiY9DQowLjVcdGltZXMwLjVcXA0KJj0NCjAuMjUuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpLYXJlbmEgcG9zaXNpIHRlcnNlYnV0IGJlcmphcmFrIHNhbWEgZGFyaSBrZWVtcGF0IGVsZW1lbiBtYXN1a2FuLCBtYWthOg0KDQpcWw0Kd197MSwxfV57KDIsMil9DQo9DQp3X3sxLDJ9XnsoMiwyKX0NCj0NCndfezIsMX1eeygyLDIpfQ0KPQ0Kd197MiwyfV57KDIsMil9DQo9DQowLjI1Lg0KXF0NCg0KRGVuZ2FuIGRlbWlraWFuLCBydW11cyBpbnRlcnBvbGFzaSBiaWxpbmVhciBtZW5qYWRpOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcbGVmdFsNClxvcGVyYXRvcm5hbWV7VXB9DQpcbGVmdCgNClxtYXRoYmZ7WH1eezEsMX0NClxyaWdodCkNClxyaWdodF1fezIsMn0NCiY9DQowLjI1WF97MSwxfV57MSwxfQ0KKw0KMC4yNVhfezEsMn1eezEsMX1cXA0KJlxxdWFkKw0KMC4yNVhfezIsMX1eezEsMX0NCisNCjAuMjVYX3syLDJ9XnsxLDF9XFwNCiY9DQpcZnJhY3sNClhfezEsMX1eezEsMX0NCisNClhfezEsMn1eezEsMX0NCisNClhfezIsMX1eezEsMX0NCisNClhfezIsMn1eezEsMX0NCn17NH1cXA0KJj0NClxmcmFjezAuMDArMC4wMCswLjAwKzAuMTJ9ezR9XFwNCiY9DQowLjAzLg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KRGVuZ2FuIG1lbmVyYXBrYW4gaW50ZXJwb2xhc2kgYmlsaW5lYXIgcGFkYSBzZWx1cnVoIHBvc2lzaSBrZWx1YXJhbiwgZGlwZXJvbGVoICpmZWF0dXJlIG1hcCogaGFzaWwgVXBzYW1wbGluZyBiZXJ1a3VyYW4gXCg1XHRpbWVzNVwpLCB5YWl0dToNCg0KXFsNClxvcGVyYXRvcm5hbWV7VXB9DQpcbGVmdCgNClxtYXRoYmZ7WH1eezEsMX0NClxyaWdodCkNCj0NClxiZWdpbntibWF0cml4fQ0KMC4wMCAmIDAuMDAgJiAwLjAwICYgMC4wMCAmIDAuMDBcXA0KMC4wMCAmIDAuMDMgJiAwLjA2ICYgMC4wMyAmIDAuMDBcXA0KMC4wMCAmIDAuMDYgJiAwLjEyICYgMC4wNiAmIDAuMDBcXA0KMC4wMCAmIDAuMDMgJiAwLjA2ICYgMC4wMyAmIDAuMDBcXA0KMC4wMCAmIDAuMDAgJiAwLjAwICYgMC4wMCAmIDAuMDANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQpIYXNpbCB0ZXJzZWJ1dCBtZW51bmp1a2thbiBiYWh3YSBpbnRlcnBvbGFzaSBiaWxpbmVhciBtZW1wZXJiZXNhciB1a3VyYW4gc3Bhc2lhbCAqZmVhdHVyZSBtYXAqIGRhcmkgXCgzXHRpbWVzM1wpIG1lbmphZGkgXCg1XHRpbWVzNVwpLiBOaWxhaSBwYWRhIHBvc2lzaSB5YW5nIGJlcmltcGl0IGRlbmdhbiBrb29yZGluYXQgbWFzdWthbiBkaXBlcnRhaGFua2FuLCBzZWRhbmdrYW4gbmlsYWkgcGFkYSBwb3Npc2kgbGFpbm55YSBkaWhpdHVuZyBtZW5nZ3VuYWthbiBib2JvdCBpbnRlcnBvbGFzaSBiZXJkYXNhcmthbiBqYXJhayB0ZXJoYWRhcCBlbGVtZW4gbWFzdWthbi4NCg0KLSAqKlJ1bXVzIG5vZGUgZGVjb2RlcjoqKg0KDQpTZXN1YWkgZGVuZ2FuIHBlcnNhbWFhbiBVTmV0KyssICpuZXN0ZWQgc2tpcCBjb25uZWN0aW9uKiBrZWR1YSBwYWRhIG5vZGUgKmRlY29kZXIqIGRpcnVtdXNrYW4gc2ViYWdhaToNCg0KXFsNClxtYXRoYmZ7WH1eezAsMn0NCj0NCkheeygwLDIpfQ0KXGxlZnQoDQpcb3BlcmF0b3JuYW1le0NvbmNhdH0NClxsZWZ0Ww0KXG1hdGhiZntYfV57MCwwfSwNClxtYXRoYmZ7WH1eezAsMX0sDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsxLDF9DQpccmlnaHQpDQpccmlnaHRdDQpccmlnaHQpLg0KXF0NCg0KUGFkYSBwZXJzYW1hYW4gdGVyc2VidXQsIFwoSF57KDAsMil9XCkgbWVueWF0YWthbiBvcGVyYXNpIHBlbmdvbGFoYW4gZml0dXIgcGFkYSBub2RlICpkZWNvZGVyKiBcKFxtYXRoYmZ7WH1eezAsMn1cKS4gRGFsYW0gaWx1c3RyYXNpIHBlcmhpdHVuZ2FuIG1hbnVhbCBpbmksIG9wZXJhc2kgdGVyc2VidXQgZGlzZWRlcmhhbmFrYW4gbWVuZ2d1bmFrYW4ga29udm9sdXNpIFwoMVx0aW1lczFcKSB0YW5wYSBiaWFzIHlhbmcgZGlpa3V0aSBmdW5nc2kgYWt0aXZhc2kgUmVMVS4NCg0KS2FyZW5hIGtldGlnYSAqZmVhdHVyZSBtYXAqIHlhbmcgZGlnYWJ1bmdrYW4gYmVydWt1cmFuIFwoNVx0aW1lczVcKSBkYW4gbWFzaW5nLW1hc2luZyBkaXJlcHJlc2VudGFzaWthbiBvbGVoIHNhdHUga2FuYWwsIGhhc2lsICpDb25jYXQqIG1lbWlsaWtpIHRpZ2Ega2FuYWwuIFNhdHUgZmlsdGVyIGtvbnZvbHVzaSBcKDFcdGltZXMxXCkgZGlndW5ha2FuIHVudHVrIG1lbmdnYWJ1bmdrYW4ga2V0aWdhIGthbmFsIHRlcnNlYnV0IG1lbmphZGkgc2F0dSBrYW5hbCBrZWx1YXJhbi4NCg0KUGFkYSBpbHVzdHJhc2kgaW5pLCBib2JvdCBrZXJuZWwgZGl0ZW50dWthbiBzZWJhZ2FpOg0KDQpcWw0KXG1hdGhiZntXfV97XG1hdGhybXtwd319XnsoMCwyKX0NCj0NClxiZWdpbntibWF0cml4fQ0KMC4yNSAmIDAuNTAgJiAwLjI1DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KQm9ib3QgdGVyc2VidXQgbWVydXBha2FuIHBhcmFtZXRlciBpbHVzdHJhdGlmIHVudHVrIG1lbnllZGVyaGFuYWthbiBwZXJoaXR1bmdhbiBtYW51YWwgZGFuIHRpZGFrIG1lcmVwcmVzZW50YXNpa2FuIGJvYm90IGhhc2lsIHBlbGF0aWhhbiBtb2RlbC4NCg0KQm9ib3QgcGVydGFtYSBkaXRlcmFwa2FuIHBhZGEgXChcbWF0aGJme1h9XnswLDB9XCksIGJvYm90IGtlZHVhIGRpdGVyYXBrYW4gcGFkYSBcKFxtYXRoYmZ7WH1eezAsMX1cKSwgc2VkYW5na2FuIGJvYm90IGtldGlnYSBkaXRlcmFwa2FuIHBhZGEgXChcb3BlcmF0b3JuYW1le1VwfShcbWF0aGJme1h9XnsxLDF9KVwpLg0KDQpEZW5nYW4gZGVtaWtpYW4sIHVudHVrIHNldGlhcCBwb3Npc2kgc3Bhc2lhbCBcKChyLGMpXCksIGtlbHVhcmFuIG5vZGUgKmRlY29kZXIqIGRpaGl0dW5nIHNlYmFnYWk6DQoNClxbDQpYX3tyLGN9XnswLDJ9DQo9DQpcb3BlcmF0b3JuYW1le1JlTFV9DQpcbGVmdCgNCjAuMjVYX3tyLGN9XnswLDB9DQorDQowLjUwWF97cixjfV57MCwxfQ0KKw0KMC4yNQ0KXGxlZnRbDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsxLDF9DQpccmlnaHQpDQpccmlnaHRdX3tyLGN9DQpccmlnaHQpLg0KXF0NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiBub2RlIGRlY29kZXIgcGFkYSBwb3Npc2kgXCgoMSwxKVwpOioqDQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClhfezEsMX1eezAsMn0NCiY9DQpcb3BlcmF0b3JuYW1le1JlTFV9DQpcbGVmdCgNCjAuMjVYX3sxLDF9XnswLDB9DQorDQowLjUwWF97MSwxfV57MCwxfQ0KKw0KMC4yNQ0KXGxlZnRbDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsxLDF9DQpccmlnaHQpDQpccmlnaHRdX3sxLDF9DQpccmlnaHQpXFwNCiY9DQpcb3BlcmF0b3JuYW1le1JlTFV9DQpcbGVmdCgNCjAuMjUoLTIuMzkpDQorDQowLjUwKDAuMDApDQorDQowLjI1KDAuMDApDQpccmlnaHQpXFwNCiY9DQpcb3BlcmF0b3JuYW1le1JlTFV9KC0wLjYwKVxcDQomPQ0KMC4wMC4NClxlbmR7YWxpZ25lZH0NClxdDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gbm9kZSBkZWNvZGVyIHBhZGEgcG9zaXNpIFwoKDIsMylcKToqKg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpYX3syLDN9XnswLDJ9DQomPQ0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQowLjI1WF97MiwzfV57MCwwfQ0KKw0KMC41MFhfezIsM31eezAsMX0NCisNCjAuMjUNClxsZWZ0Ww0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MSwxfQ0KXHJpZ2h0KQ0KXHJpZ2h0XV97MiwzfQ0KXHJpZ2h0KVxcDQomPQ0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQowLjI1KDIuMjQpDQorDQowLjUwKDQuMjcpDQorDQowLjI1KDAuMDYpDQpccmlnaHQpXFwNCiY9DQpcb3BlcmF0b3JuYW1le1JlTFV9DQpcbGVmdCgNCjAuNTYrMi4xMzUrMC4wMTUNClxyaWdodClcXA0KJj0NClxvcGVyYXRvcm5hbWV7UmVMVX0oMi43MSlcXA0KJj0NCjIuNzEuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gbWVuZXJhcGthbiBvcGVyYXNpIHlhbmcgc2FtYSBwYWRhIHNlbHVydWggcG9zaXNpIHNwYXNpYWwgZGFuIG1lbmFtcGlsa2FuIGhhc2lsIGhpbmdnYSBkdWEgYW5na2EgZGVzaW1hbCwgZGlwZXJvbGVoICpmZWF0dXJlIG1hcCoga2VsdWFyYW4gbm9kZSAqZGVjb2Rlciogc2ViYWdhaSBiZXJpa3V0Og0KDQpcWw0KXG1hdGhiZntYfV57MCwyfQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjAwICYgMC4wMCAmIDIuMjggJiAwLjg0ICYgMC4wMFxcDQowLjAwICYgMC4wMCAmIDIuNzEgJiAxLjIwICYgMC4wMFxcDQowLjAwICYgMC4wMCAmIDIuODMgJiAxLjI4ICYgMC4wMFxcDQowLjAwICYgMC4wMCAmIDIuMTUgJiAwLjc2ICYgMC4wMFxcDQowLjAwICYgMC4wMCAmIDAuOTYgJiAwLjAwICYgMC4wMA0KXGVuZHtibWF0cml4fS4NClxdDQoNCkhhc2lsIHRlcnNlYnV0IG1lbnVuanVra2FuIGJhaHdhIG5vZGUgXChcbWF0aGJme1h9XnswLDJ9XCkgbWVuZ2dhYnVuZ2thbiBpbmZvcm1hc2kgZGFyaSBcKFxtYXRoYmZ7WH1eezAsMH1cKSwgXChcbWF0aGJme1h9XnswLDF9XCksIGRhbiBoYXNpbCBVcHNhbXBsaW5nIFwoXG1hdGhiZntYfV57MSwxfVwpIG1lbGFsdWkgKm5lc3RlZCBza2lwIGNvbm5lY3Rpb24qLiBQYWRhIGlsdXN0cmFzaSBpbmksIHBlbmdnYWJ1bmdhbiBkaWxha3VrYW4gbWVuZ2d1bmFrYW4gKkNvbmNhdCosIGtvbnZvbHVzaSBcKDFcdGltZXMxXCksIGRhbiBmdW5nc2kgYWt0aXZhc2kgUmVMVS4gKkZlYXR1cmUgbWFwKiBcKFxtYXRoYmZ7WH1eezAsMn1cKSBtZXJ1cGFrYW4ga2VsdWFyYW4gYWtoaXIgKmRlY29kZXIqIHBhZGEgaWx1c3RyYXNpIHBlcmhpdHVuZ2FuIG1hbnVhbCBpbmkuDQoNCg0KIyMgNy4gUHJlZGlrc2kgUHJvYmFiaWxpdGFzIFBpa3NlbCBkYW4gTWFzayBTZWdtZW50YXNpDQoNCktlbHVhcmFuIGFraGlyIGRlY29kZXIgXChcbWF0aGJme1h9XnswLDJ9XCkgZGlndW5ha2FuIHVudHVrIG1lbmdoYXNpbGthbiBwcmVkaWtzaSBwYWRhIHNldGlhcCBwaWtzZWwuIFRhaGFwIGluaSB0ZXJkaXJpIGF0YXMgcGVtYmVudHVrYW4gKmxvZ2l0Kiwga29udmVyc2kgKmxvZ2l0KiBtZW5qYWRpIHByb2JhYmlsaXRhcyBtZW5nZ3VuYWthbiBmdW5nc2kgc2lnbW9pZCwgZGFuIHBlbWJlbnR1a2FuICptYXNrKiBzZWdtZW50YXNpIGJpbmVyIG1lbmdndW5ha2FuIG5pbGFpIGFtYmFuZyBsZWJpaCBkYXJpIFwoMC41MFwpLg0KDQojIyMgYS4gSGVhZCBTZWdtZW50YXNpIGRhbiBNYXRyaWtzIExvZ2l0IChcKFxtYXRoYmZ7en1cKSkNCg0KUGFkYSBpbHVzdHJhc2kgaW5pLCAqaGVhZCogc2VnbWVudGFzaSBtZW5nZ3VuYWthbiAqY29udm9sdXRpb24qIFwoMVx0aW1lczFcKSB0YW5wYSBiaWFzIGRlbmdhbiBib2JvdCBcKDEuMDBcKS4gQm9ib3QgdGVyc2VidXQgZGlueWF0YWthbiBzZWJhZ2FpOg0KDQpcWw0KXG1hdGhiZntXfV97XG1hdGhybXtzZWd9fQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQoxLjAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KS2FyZW5hIGJvYm90ICpjb252b2x1dGlvbiogYmVybmlsYWkgXCgxLjAwXCkgZGFuIGJpYXMgdGlkYWsgZGlndW5ha2FuLCBuaWxhaSAqbG9naXQqIHNhbWEgZGVuZ2FuIGtlbHVhcmFuIGFraGlyIGRlY29kZXIuDQoNCi0gKipSdW11czoqKg0KDQpcWw0Kel97aSxqfQ0KPQ0KV197XG1hdGhybXtzZWd9LDEsMX0NClhfe2ksan1eezAsMn0uDQpcXQ0KDQpQYWRhIGlsdXN0cmFzaSBpbmksIHBlcnNhbWFhbiB0ZXJzZWJ1dCBkYXBhdCBkaXNlZGVyaGFuYWthbiBtZW5qYWRpOg0KDQpcWw0Kel97aSxqfQ0KPQ0KMS4wMFhfe2ksan1eezAsMn0NCj0NClhfe2ksan1eezAsMn0uDQpcXQ0KDQpNYXRyaWtzIFwoXG1hdGhiZnt6fVwpIGJlcmRpbWVuc2kgXCg1XHRpbWVzNVwpLg0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuOioqDQoNClxbDQpcYmVnaW57YWxpZ25lZH0NCnpfezMsM30NCiY9DQoxLjAwWF97MywzfV57MCwyfVxcDQomPQ0KMS4wMCgyLjgzKVxcDQomPQ0KMi44My4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBhdHVyYW4geWFuZyBzYW1hLCBkaXBlcm9sZWggbWF0cmlrcyAqbG9naXQqOg0KDQpcWw0KXG1hdGhiZnt6fQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjAwICYgMC4wMCAmIDIuMjggJiAwLjg0ICYgMC4wMFxcDQowLjAwICYgMC4wMCAmIDIuNzEgJiAxLjIwICYgMC4wMFxcDQowLjAwICYgMC4wMCAmIDIuODMgJiAxLjI4ICYgMC4wMFxcDQowLjAwICYgMC4wMCAmIDIuMTUgJiAwLjc2ICYgMC4wMFxcDQowLjAwICYgMC4wMCAmIDAuOTYgJiAwLjAwICYgMC4wMA0KXGVuZHtibWF0cml4fS4NClxdDQoNCiMjIyBiLiBQcm9iYWJpbGl0YXMgUHJlZGlrc2kgUGlrc2VsIChcKFxtYXRoYmZ7cH1cKSkNCg0KRnVuZ3NpIHNpZ21vaWQgZGl0ZXJhcGthbiBwYWRhIHNldGlhcCBlbGVtZW4gKmxvZ2l0KiB1bnR1ayBtZW5ndWJhaCBuaWxhaW55YSBtZW5qYWRpIHByb2JhYmlsaXRhcyBwYWRhIHJlbnRhbmcgXChbMCwxXVwpLiBOaWxhaSB5YW5nIG1lbmRla2F0aSBcKDFcKSBtZW51bmp1a2thbiBrZXlha2luYW4gbW9kZWwgeWFuZyBsZWJpaCB0aW5nZ2kgYmFod2EgcGlrc2VsIHRlcnNlYnV0IHRlcm1hc3VrIGtlbGFzIHRhcmdldC4NCg0KLSAqKlJ1bXVzOioqDQoNClxbDQpwX3tpLGp9DQo9DQpcc2lnbWEoel97aSxqfSkNCj0NClxmcmFjezF9ezErZV57LXpfe2ksan19fS4NClxdDQoNCk1hdHJpa3MgcHJvYmFiaWxpdGFzIFwoXG1hdGhiZntwfVwpIGJlcmRpbWVuc2kgXCg1XHRpbWVzNVwpLg0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuOioqDQoNClVudHVrIHBvc2lzaSBcKCgzLDMpXCksIGRpa2V0YWh1aSBcKHpfezMsM309Mi44M1wpLiBNYWthOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpwX3szLDN9DQomPQ0KXGZyYWN7MX17MStlXnstel97MywzfX19XFwNCiY9DQpcZnJhY3sxfXsxK2Veey0yLjgzfX1cXA0KJj0NClxmcmFjezF9ezErMC4wNTkwfVxcDQomPQ0KMC45NDQzXFwNCiY9DQowLjk0Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KVW50dWsgKmxvZ2l0KiBub2wsIHByb2JhYmlsaXRhc255YSBhZGFsYWg6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NCnBfezEsMX0NCiY9DQpcZnJhY3sxfXsxK2Veey0wLjAwfX1cXA0KJj0NClxmcmFjezF9ezErMX1cXA0KJj0NCjAuNTAuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gYXR1cmFuIHlhbmcgc2FtYSwgZGlwZXJvbGVoIG1hdHJpa3MgcHJvYmFiaWxpdGFzOg0KDQpcWw0KXG1hdGhiZntwfQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjUwICYgMC41MCAmIDAuOTEgJiAwLjcwICYgMC41MFxcDQowLjUwICYgMC41MCAmIDAuOTQgJiAwLjc3ICYgMC41MFxcDQowLjUwICYgMC41MCAmIDAuOTQgJiAwLjc4ICYgMC41MFxcDQowLjUwICYgMC41MCAmIDAuOTAgJiAwLjY4ICYgMC41MFxcDQowLjUwICYgMC41MCAmIDAuNzIgJiAwLjUwICYgMC41MA0KXGVuZHtibWF0cml4fS4NClxdDQoNCiMjIyBjLiBNYXNrIFNlZ21lbnRhc2kgQmluZXIgKFwoXHdpZGVoYXR7XG1hdGhiZntNfX1cKSkNCg0KTWF0cmlrcyBwcm9iYWJpbGl0YXMgZGl1YmFoIG1lbmphZGkgKm1hc2sqIHNlZ21lbnRhc2kgYmluZXIgbWVuZ2d1bmFrYW4gbmlsYWkgYW1iYW5nIGxlYmloIGRhcmkgXCgwLjUwXCkuIFBpa3NlbCBkZW5nYW4gcHJvYmFiaWxpdGFzIHRlcGF0IFwoMC41MFwpIGRpa2F0ZWdvcmlrYW4gc2ViYWdhaSBsYXRhciBiZWxha2FuZy4NCg0KLSAqKlJ1bXVzOioqDQoNClxbDQpcd2lkZWhhdHtNfV97aSxqfQ0KPQ0KXG1hdGhiYnsxfQ0KXGxlZnRbDQpwX3tpLGp9PjAuNTANClxyaWdodF0uDQpcXQ0KDQpkZW5nYW46DQoNClxbDQpcd2lkZWhhdHtNfV97aSxqfQ0KPQ0KXGJlZ2lue2Nhc2VzfQ0KMSwgJiBcdGV4dHtqaWthIH0gcF97aSxqfT4wLjUwIFx0ZXh0eyAod2lsYXlhaCBsZXNpKX0sXFwNCjAsICYgXHRleHR7amlrYSB9IHBfe2ksan1cbGVxMC41MCBcdGV4dHsgKGxhdGFyIGJlbGFrYW5nKX0uDQpcZW5ke2Nhc2VzfQ0KXF0NCg0KTWF0cmlrcyAqbWFzayogcHJlZGlrc2kgXChcd2lkZWhhdHtcbWF0aGJme019fVwpIGJlcmRpbWVuc2kgXCg1XHRpbWVzNVwpLg0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuOioqDQoNClVudHVrIHBvc2lzaSBcKCgzLDMpXCk6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClx3aWRlaGF0e019X3szLDN9DQomPQ0KXG1hdGhiYnsxfQ0KXGxlZnRbDQpwX3szLDN9PjAuNTANClxyaWdodF1cXA0KJj0NClxtYXRoYmJ7MX0NClxsZWZ0Ww0KMC45ND4wLjUwDQpccmlnaHRdXFwNCiY9DQoxLg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KVW50dWsgcG9zaXNpIFwoKDEsMSlcKToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KXHdpZGVoYXR7TX1fezEsMX0NCiY9DQpcbWF0aGJiezF9DQpcbGVmdFsNCnBfezEsMX0+MC41MA0KXHJpZ2h0XVxcDQomPQ0KXG1hdGhiYnsxfQ0KXGxlZnRbDQowLjUwPjAuNTANClxyaWdodF1cXA0KJj0NCjAuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gYXR1cmFuIHlhbmcgc2FtYSwgZGlwZXJvbGVoICptYXNrKiBzZWdtZW50YXNpIHByZWRpa3NpOg0KDQpcWw0KXHdpZGVoYXR7XG1hdGhiZntNfX0NCj0NClxiZWdpbntibWF0cml4fQ0KMCAmIDAgJiAxICYgMSAmIDBcXA0KMCAmIDAgJiAxICYgMSAmIDBcXA0KMCAmIDAgJiAxICYgMSAmIDBcXA0KMCAmIDAgJiAxICYgMSAmIDBcXA0KMCAmIDAgJiAxICYgMCAmIDANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQo+ICoqS2V0ZXJhbmdhbiBwcm9zZXMgcGVsYXRpaGFuOioqIE1hc2sgYmluZXIgXChcd2lkZWhhdHtNfVwpIHBhZGEgaWx1c3RyYXNpIGluaSBkaXRhbXBpbGthbiB1bnR1ayBtZW1wZXJsaWhhdGthbiBiZW50dWsgYWtoaXIgaGFzaWwgc2VnbWVudGFzaSBkYW4gdW50dWsgbWVuZ2hpdHVuZyBtZXRyaWsgZXZhbHVhc2kuIFBhZGEgcHJvc2VzIHBlbGF0aWhhbiwgbWFzayBiaW5lciB0ZXJzZWJ1dCB0aWRhayBkaWd1bmFrYW4gdW50dWsgbWVtcGVyYmFydWkgYm9ib3QgbW9kZWwuIFBlbWJhcnVhbiBib2JvdCBkaWxha3VrYW4gbWVuZ2d1bmFrYW4gcHJvYmFiaWxpdGFzIHByZWRpa3NpIFwocFwpIGRhbiBncm91bmQgdHJ1dGggXChNXCkgbWVsYWx1aSBCQ0UtRGljZSBsb3NzLg0KDQo=