1. Citra masukan ground truth dan normalisasi

Pada citra grayscale, setiap piksel memiliki satu nilai intensitas yang menunjukkan tingkat kecerahan. Apabila nilai intensitas telah dinormalisasi ke rentang \([0,1]\), maka nilai 0 menunjukkan piksel paling gelap (hitam), nilai 1 menunjukkan piksel paling terang (putih), sedangkan nilai di antara 0 dan 1 menunjukkan gradasi abu-abu. Semakin mendekati 0, piksel semakin gelap; semakin mendekati 1, piksel semakin terang.

Dalam ilustrasi ini, matriks citra awal masih menggunakan skala intensitas 0–255. Oleh karena itu, nilai 0 merepresentasikan hitam, nilai 255 merepresentasikan putih, dan nilai seperti 64, 128, atau 192 menunjukkan tingkat abu-abu yang berbeda. Dimensi matriks adalah \(5\times5\). Pada implementasi sebenarnya, citra NCCT satu kanal direplikasi menjadi tiga kanal agar sesuai dengan masukan encoder MobileViTv3. Namun, ilustrasi perhitungan berikut hanya menelusuri satu kanal.

a. Citra masukan

\[ \mathbf{I}= \begin{bmatrix} 0 & 64 & 192 & 160 & 32\\ 0 & 80 & 208 & 176 & 40\\ 0 & 80 & 208 & 176 & 40\\ 0 & 72 & 192 & 160 & 32\\ 8 & 48 & 144 & 112 & 24 \end{bmatrix}. \]

b. Ground truth biner

\[ \mathbf{M}= \begin{bmatrix} 0 & 0 & 1 & 1 & 0\\ 0 & 1 & 1 & 1 & 0\\ 0 & 1 & 1 & 1 & 0\\ 0 & 0 & 1 & 1 & 0\\ 0 & 0 & 0 & 0 & 0 \end{bmatrix}. \]

Ground truth \(M\) berada di awal sebagai target evaluasi, dengan nilai 0 menyatakan latar belakang dan nilai 1 menyatakan wilayah lesi. Matriks \(M\) bukan merupakan masukan encoder.

c. Normalisasi kanal

  • Normalisasi pretrained ImageNet diterapkan per kanal:

\[ \mathbf{X}_R=\frac{I_R/255-0.485}{0.229},\qquad \mathbf{X}_G=\frac{I_G/255-0.456}{0.224},\qquad \mathbf{X}_B=\frac{I_B/255-0.406}{0.225}. \]

  • Contoh:

\[ \begin{aligned} X_{1,3} &= \frac{192/255-0.485}{0.229}\\ &= 1.17. \end{aligned} \]

Pada ilustrasi ini, hanya satu kanal yang digunakan Oleh karena itu, setiap elemen feature map masukan \(X\) dihitung menggunakan

\[ X_{i,j} = \frac{I_{i,j}/255-0.485}{0.229}. \]

Aturan yang sama diterapkan pada seluruh elemen matriks. Dengan nilai presisi penuh yang kemudian ditampilkan hingga dua angka desimal, diperoleh

\[ \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}. \]

2. Representasi lokal MobileViTv3-v2

Pada ilustrasi ini, matriks \(X\) merupakan satu irisan kanal dari feature map masukan blok \(\mathbf F^{(0)}\) setelah normalisasi. Matriks \(X\) memiliki dimensi \(5\times5\). Tahap representasi lokal dimulai dengan depthwise convolution \(3\times3\), dilanjutkan dengan fungsi aktivasi Swish. Proyeksi pointwise \(1\times1\) baru diterapkan setelah feature map lokal diperoleh.

a. Depthwise Convolution

Pada ilustrasi ini, matriks \(\mathbf{X}\) merupakan satu kanal feature map masukan berukuran \(5\times5\). Operasi depthwise convolution diterapkan secara independen pada kanal tersebut menggunakan kernel \(3\times3\), stride \(1\), zero padding sebesar \(1\) pada setiap sisi, dan tanpa bias. Keluaran sebelum aktivasi dinyatakan sebagai \(\mathbf{F}_{\mathrm{dw}}\).

Matriks feature map masukan yang digunakan adalah:

\[ \mathbf{X} = \begin{bmatrix} -2.12 & -1.02 & 1.17 & 0.62 & -1.57\\ -2.12 & -0.75 & 1.44 & 0.90 & -1.43\\ -2.12 & -0.75 & 1.44 & 0.90 & -1.43\\ -2.12 & -0.88 & 1.17 & 0.62 & -1.57\\ -1.98 & -1.30 & 0.35 & -0.20 & -1.71 \end{bmatrix}. \]

  • Penambahan Zero Padding:

Sebelum operasi depthwise convolution dilakukan, satu lapisan nilai nol ditambahkan pada keempat sisi matriks masukan, yaitu sisi atas, bawah, kiri, dan kanan. Penambahan zero padding ini bertujuan mempertahankan ukuran spasial feature map setelah proses konvolusi.

Ukuran keluaran dihitung menggunakan:

\[ o = \left\lfloor \frac{i+2p-k}{s} \right\rfloor+1, \]

dengan \(i\) menyatakan ukuran spasial masukan, \(p\) merupakan jumlah padding pada setiap sisi, \(k\) merupakan ukuran kernel, dan \(s\) merupakan stride.

Pada ilustrasi ini, digunakan \(i=5\), \(p=1\), \(k=3\), dan \(s=1\), sehingga:

\[ \begin{aligned} o &= \left\lfloor \frac{5+2(1)-3}{1} \right\rfloor+1\\ &= \left\lfloor \frac{4}{1} \right\rfloor+1\\ &=5. \end{aligned} \]

Dengan demikian, ukuran spasial keluaran tetap \(5\times5\). Setelah penambahan zero padding, ukuran matriks masukan sementara berubah dari \(5\times5\) menjadi \(7\times7\).

Matriks setelah penambahan zero padding adalah:

\[ \mathbf{X}_{\mathrm{pad}} = \begin{bmatrix} 0.00 & 0.00 & 0.00 & 0.00 & 0.00 & 0.00 & 0.00\\ 0.00 & -2.12 & -1.02 & 1.17 & 0.62 & -1.57 & 0.00\\ 0.00 & -2.12 & -0.75 & 1.44 & 0.90 & -1.43 & 0.00\\ 0.00 & -2.12 & -0.75 & 1.44 & 0.90 & -1.43 & 0.00\\ 0.00 & -2.12 & -0.88 & 1.17 & 0.62 & -1.57 & 0.00\\ 0.00 & -1.98 & -1.30 & 0.35 & -0.20 & -1.71 & 0.00\\ 0.00 & 0.00 & 0.00 & 0.00 & 0.00 & 0.00 & 0.00 \end{bmatrix}. \]

  • Filter atau Bobot Kernel Depthwise Convolution:

Pada ilustrasi ini, matriks bobot kernel depthwise convolution ditetapkan sebagai:

\[ \mathbf{W}_{\mathrm{dw}} = \begin{bmatrix} 0.05 & 0.10 & 0.05\\ 0.10 & 0.40 & 0.10\\ 0.05 & 0.10 & 0.05 \end{bmatrix}. \]

Kernel tersebut berukuran \(3\times3\). Bobot pusat sebesar \(0.40\) memberikan kontribusi terbesar dari elemen pusat, sedangkan elemen-elemen di sekitarnya memberikan kontribusi melalui bobot \(0.05\) dan \(0.10\).

Setiap hasil konvolusi diperoleh melalui perkalian sembilan elemen pada area feature map dengan sembilan bobot kernel yang bersesuaian, kemudian seluruh hasil perkalian dijumlahkan.

  • Rumus:

Secara umum, operasi depthwise convolution pada feature map multikanal dinyatakan sebagai:

\[ F_{\mathrm{dw},k,l,m} = \sum_{u=1}^{3} \sum_{v=1}^{3} W_{\mathrm{dw},u,v,m} X_{\mathrm{pad},k+u-1,l+v-1,m}, \]

dengan \(m\) menyatakan indeks kanal, sedangkan \(u\) dan \(v\) merupakan indeks baris dan kolom kernel.

Pada ilustrasi satu kanal, perhitungan setiap elemen keluaran dinyatakan sebagai:

\[ F_{\mathrm{dw},k,l} = \sum_{u=1}^{3} \sum_{v=1}^{3} W_{\mathrm{dw},u,v} X_{\mathrm{pad},k+u-1,l+v-1}, \]

dengan \(k,l=1,2,\ldots,5\).

Pada setiap posisi, kernel mencakup area berukuran \(3\times3\). Karena stride bernilai \(1\), kernel bergeser satu kolom ke kanan untuk menghitung elemen berikutnya pada baris keluaran yang sama. Setelah mencapai posisi terakhir pada baris tersebut, kernel kembali ke sisi kiri dan bergeser satu baris ke bawah.

  • Contoh Perhitungan Konvolusi:

1. Perhitungan elemen pada posisi \((1,1)\)

Untuk menghasilkan elemen pertama dari feature map keluaran, kernel ditempatkan pada area \(3\times3\) di pojok kiri atas matriks yang telah diberi zero padding.

Area feature map yang diproses adalah:

\[ \begin{bmatrix} 0.00 & 0.00 & 0.00\\ 0.00 & -2.12 & -1.02\\ 0.00 & -2.12 & -0.75 \end{bmatrix}. \]

Area tersebut dikalikan secara elemen demi elemen dengan bobot kernel \(\mathbf{W}_{\mathrm{dw}}\), kemudian seluruh hasil perkalian dijumlahkan sebagai berikut:

\[ \begin{aligned} F_{\mathrm{dw},1,1} ={}& (0.00)(0.05) +(0.00)(0.10) +(0.00)(0.05)\\ &+(0.00)(0.10) +(-2.12)(0.40) +(-1.02)(0.10)\\ &+(0.00)(0.05) +(-2.12)(0.10) +(-0.75)(0.05)\\ ={}& -0.848-0.102-0.212-0.0375\\ ={}&-1.1995. \end{aligned} \]

Dengan pembulatan dua angka desimal, hasil perhitungan tersebut adalah:

\[ F_{\mathrm{dw},1,1}=-1.20. \]

2. Perhitungan elemen pada posisi \((2,2)\)

Untuk menghitung elemen pada posisi \((2,2)\), kernel ditempatkan pada area yang dimulai dari baris kedua dan kolom kedua matriks setelah padding. Posisi ini berada satu baris di bawah dan satu kolom di kanan dibandingkan posisi awal.

Area feature map yang diproses adalah:

\[ \begin{bmatrix} -2.12 & -1.02 & 1.17\\ -2.12 & -0.75 & 1.44\\ -2.12 & -0.75 & 1.44 \end{bmatrix}. \]

Perhitungan konvolusi dilakukan menggunakan bobot kernel yang sama:

\[ \begin{aligned} F_{\mathrm{dw},2,2} ={}& (-2.12)(0.05) +(-1.02)(0.10) +(1.17)(0.05)\\ &+(-2.12)(0.10) +(-0.75)(0.40) +(1.44)(0.10)\\ &+(-2.12)(0.05) +(-0.75)(0.10) +(1.44)(0.05)\\ ={}& -0.106-0.102+0.0585\\ &-0.212-0.300+0.144\\ &-0.106-0.075+0.072\\ ={}&-0.6265. \end{aligned} \]

Hasil perhitungan dari nilai masukan dua desimal adalah \(-0.6265\). Pada matriks ilustrasi sebelumnya, elemen ini tercatat sebesar \(-0.62\). Nilai pada matriks dipertahankan sementara hingga validasi numerik menyeluruh dilakukan.

Prosedur yang sama diterapkan pada seluruh posisi kernel. Pada setiap posisi, elemen-elemen dalam area konvolusi dikalikan dengan bobot kernel yang bersesuaian, kemudian seluruh hasil perkalian dijumlahkan untuk membentuk satu elemen feature map keluaran.

Matriks hasil depthwise convolution yang digunakan sementara dalam ilustrasi ini adalah:

\[ \mathbf{F}_{\mathrm{dw}} = \begin{bmatrix} -1.20 & -0.61 & 0.58 & 0.30 & -0.66\\ -1.43 & -0.62 & 0.84 & 0.49 & -0.71\\ -1.43 & -0.61 & 0.85 & 0.49 & -0.71\\ -1.45 & -0.77 & 0.55 & 0.21 & -0.84\\ -1.18 & -0.82 & 0.09 & -0.17 & -0.83 \end{bmatrix}. \]

Matriks tersebut mempertahankan nilai pada ilustrasi sebelumnya dan akan diperiksa kembali melalui perhitungan numerik untuk memastikan konsistensi seluruh tahapan.

Keluaran depthwise convolution selanjutnya diproses menggunakan fungsi aktivasi Swish untuk membentuk feature map lokal \(\mathbf{L}\).

  • Rumus Aktivasi Swish:

Fungsi aktivasi Swish diterapkan secara elemen demi elemen pada matriks hasil depthwise convolution:

\[ \begin{aligned} L_{i,j} &= \operatorname{Swish} \left( F_{\mathrm{dw},i,j} \right)\\ &= \frac{F_{\mathrm{dw},i,j}} {1+e^{-F_{\mathrm{dw},i,j}}}. \end{aligned} \]

  • Contoh Perhitungan pada Posisi \((1,1)\):

Untuk elemen pada posisi \((1,1)\), nilai yang digunakan sesuai dengan matriks hasil depthwise convolution, yaitu \(-1.20\).

\[ \begin{aligned} L_{1,1} &= \operatorname{Swish}(-1.20)\\ &= \frac{-1.20}{1+e^{-(-1.20)}}\\ &= \frac{-1.20}{1+e^{1.20}}\\ &= \frac{-1.20}{1+3.32}\\ &=-0.28. \end{aligned} \]

Dengan menerapkan fungsi aktivasi Swish pada seluruh elemen matriks hasil depthwise convolution, diperoleh feature map lokal:

\[ \mathbf{L} = \begin{bmatrix} -0.28 & -0.22 & 0.37 & 0.17 & -0.23\\ -0.28 & -0.22 & 0.59 & 0.31 & -0.23\\ -0.28 & -0.22 & 0.59 & 0.31 & -0.23\\ -0.28 & -0.24 & 0.35 & 0.12 & -0.25\\ -0.28 & -0.25 & 0.05 & -0.08 & -0.25 \end{bmatrix}. \]

Matriks \(\mathbf{L}\) merupakan representasi lokal setelah penerapan fungsi aktivasi Swish dan digunakan sebagai masukan pada tahap berikutnya. Nilai matriks tersebut dipertahankan sesuai ilustrasi sebelumnya hingga dilakukan validasi numerik secara menyeluruh.

b. Pointwise Convolution dan Tokenisasi

Feature map lokal \(\mathbf{L}\) memiliki satu kanal dengan dimensi \(5\times5\times1\). Selanjutnya, pointwise convolution \(1\times1\) diterapkan secara independen pada setiap posisi spasial. Operasi ini tidak melibatkan piksel tetangga, tetapi memproyeksikan satu kanal masukan menjadi dua kanal keluaran yang membentuk vektor token.

  • Bobot pointwise convolution:

\[ \mathbf{W}_{\mathrm{pw}}^{(\mathrm{tok})} = \begin{bmatrix} 0.80 & -0.60 \end{bmatrix}. \]

Bobot \(\mathbf{W}_{\mathrm{pw}}^{(\mathrm{tok})}\) berdimensi \(1\times2\). Oleh karena itu, setiap nilai feature map lokal diproyeksikan menjadi vektor dengan dua elemen.

  • Rumus:

Untuk setiap posisi spasial \((i,j)\), token ke-\(t\) dirumuskan sebagai:

\[ T_{t,n} = \sum_{m=1}^{C_L} W_{\mathrm{pw},m,n}^{(\mathrm{tok})} L_{i,j,m}, \qquad t=5(i-1)+j. \]

Pada ilustrasi ini, \(C_L=1\) dan \(n=1,2\). Oleh karena itu, perhitungan token dapat disederhanakan menjadi:

\[ \mathbf{T}_t = L_{i,j} \mathbf{W}_{\mathrm{pw}}^{(\mathrm{tok})}. \]

Matriks token \(\mathbf{T}\) berdimensi \(25\times2\).

  • Contoh perhitungan pada posisi \((1,1)\):

\[ \begin{aligned} \mathbf{T}_1 &= L_{1,1} \mathbf{W}_{\mathrm{pw}}^{(\mathrm{tok})}\\ &= (-0.28) \begin{bmatrix} 0.80 & -0.60 \end{bmatrix}\\ &= \begin{bmatrix} -0.22 & 0.17 \end{bmatrix}. \end{aligned} \]

Posisi spasial \((1,1)\) merupakan token pertama karena:

\[ t=5(1-1)+1=1. \]

Dengan perhitungan yang sama pada seluruh posisi berdasarkan urutan raster dari kiri ke kanan dan dari atas ke bawah, diperoleh matriks token:

\[ \mathbf{T} = \begin{bmatrix} -0.22 & 0.17\\ -0.17 & 0.13\\ 0.30 & -0.22\\ 0.14 & -0.10\\ -0.18 & 0.14\\ -0.22 & 0.17\\ -0.17 & 0.13\\ 0.47 & -0.35\\ 0.24 & -0.18\\ -0.19 & 0.14\\ -0.22 & 0.17\\ -0.17 & 0.13\\ 0.48 & -0.36\\ 0.24 & -0.18\\ -0.19 & 0.14\\ -0.22 & 0.17\\ -0.19 & 0.15\\ 0.28 & -0.21\\ 0.09 & -0.07\\ -0.20 & 0.15\\ -0.22 & 0.17\\ -0.20 & 0.15\\ 0.04 & -0.03\\ -0.06 & 0.05\\ -0.20 & 0.15 \end{bmatrix}. \]

3. Linear Transformer (Separable Self-Attention)

Pada MobileViTv3-v2, matriks token \(\mathbf{T}\) diproses menggunakan mekanisme separable self-attention (SSA). Berbeda dengan Transformer v1 yang menghitung hubungan perhatian antarsetiap pasangan token, SSA membentuk vektor koefisien konteks untuk merangkum informasi global dari seluruh token. Keluaran SSA kemudian digabungkan dengan token masukan melalui residual connection dan diproses oleh feed-forward network.

Pada formulasi SSA di Bab II, \(\mathbf{X}\) menyatakan matriks token masukan secara umum. Dalam ilustrasi perhitungan ini, matriks tersebut direalisasikan oleh \(\mathbf{T}\), sehingga:

\[ \mathbf{X} = \mathbf{T}. \]

a. Proyeksi Attention Score

Setiap token pada \(\mathbf{T}\) diproyeksikan menjadi satu nilai attention score menggunakan matriks bobot \(\mathbf{W}^{I}\). Nilai attention score sebelum proses softmax dinyatakan sebagai vektor \(\mathbf{s}\).

  • Bobot proyeksi attention score:

\[ \mathbf{W}^{I} = \begin{bmatrix} 0.60\\ -0.35 \end{bmatrix}. \]

Matriks \(\mathbf{W}^{I}\) berukuran \(2\times1\). Oleh karena itu, vektor attention score \(\mathbf{s}\) berukuran \(25\times1\).

  • Rumus:

\[ \mathbf{s} = \mathbf{T}\mathbf{W}^{I}. \]

Secara elemen, attention score token ke-\(t\) dihitung sebagai:

\[ s_t = \sum_{n=1}^{2} T_{t,n}W_{n,1}^{I}. \]

  • Contoh perhitungan token pertama:

\[ \begin{aligned} s_1 &= \begin{bmatrix} -0.22 & 0.17 \end{bmatrix} \begin{bmatrix} 0.60\\ -0.35 \end{bmatrix}\\ &= 0.60(-0.22)-0.35(0.17)\\ &= -0.132-0.0595\\ &= -0.19. \end{aligned} \]

Dengan aturan yang sama, diperoleh vektor attention score sebagai berikut.

\[ \mathbf{s} = \begin{bmatrix} -0.19\\ -0.15\\ 0.26\\ 0.12\\ -0.16\\ -0.19\\ -0.15\\ 0.40\\ 0.21\\ -0.16\\ -0.19\\ -0.15\\ 0.41\\ 0.21\\ -0.16\\ -0.19\\ -0.17\\ 0.24\\ 0.08\\ -0.17\\ -0.19\\ -0.17\\ 0.03\\ -0.05\\ -0.17 \end{bmatrix}. \]

b. Koefisien konteks

Nilai attention score kemudian dinormalisasi menggunakan softmax untuk menghasilkan koefisien konteks \(c_s\). Jumlah seluruh koefisien konteks bernilai satu. Nilai attention score \(q\) dinormalisasi menggunakan fungsi softmax untuk menghasilkan koefisien konteks \(c_s\). Notasi \(e^{q_t}\) menyatakan nilai eksponensial dari attention score token yang sedang dihitung, yaitu token ke-\(t\). Sementara itu, \(\sum_{r=1}^{25}e^{q_r}\) menyatakan jumlah nilai eksponensial dari seluruh 25 token. Dengan demikian, setiap nilai \(c_{s,t}\) menunjukkan proporsi kontribusi token ke-\(t\) terhadap pembentukan vektor konteks global, dan jumlah seluruh koefisien konteks bernilai satu.

  • Rumus:

\[ c_{s,t} = \frac{e^{q_t}} {\sum_{r=1}^{25}e^{q_r}}. \]

  • Contoh token pertama:

Untuk menghitung koefisien konteks token pertama, nilai eksponensial attention score token pertama dibagi dengan jumlah nilai eksponensial dari seluruh 25 token sebagai berikut.

\[ \begin{aligned} c_{s,1} &= \frac{e^{-0.1916}} {e^{-0.1916}+e^{-0.1485}+\cdots+e^{-0.1738}}\\ &= \frac{0.8256} {0.8256+0.8620+\cdots+0.8405}\\ &= \frac{0.8256}{24.8734}\\ &= 0.0332\\ &= 0.03. \end{aligned} \]

Dengan aturan yang sama, diperoleh koefisien konteks sebagai berikut.

\[ c_s= \begin{bmatrix} 0.03\\ 0.03\\ 0.05\\ 0.05\\ 0.03\\ 0.03\\ 0.03\\ 0.07\\ 0.05\\ 0.03\\ 0.03\\ 0.03\\ 0.07\\ 0.05\\ 0.03\\ 0.03\\ 0.03\\ 0.06\\ 0.04\\ 0.03\\ 0.03\\ 0.03\\ 0.04\\ 0.04\\ 0.03 \end{bmatrix}. \]

c. Proyeksi Key

Pada formulasi separable self-attention, matriks key dibentuk dari matriks token masukan menggunakan bobot \(\mathbf{W}^{K}\). Dalam ilustrasi ini, matriks token \(\mathbf{T}\) merealisasikan \(\mathbf{X}\) pada Persamaan (2.21).

  • Bobot proyeksi key:

\[ \mathbf{W}^{K} = \begin{bmatrix} 0.55 & 0.10\\ -0.15 & 0.45 \end{bmatrix}. \]

Matriks \(\mathbf{W}^{K}\) berukuran \(2\times2\).

  • Rumus:

\[ \mathbf{K} = \mathbf{T}\mathbf{W}^{K}. \]

Matriks key \(\mathbf{K}\) berukuran \(25\times2\).

Secara elemen, komponen key ke-\(n\) pada token ke-\(t\) dihitung sebagai:

\[ K_{t,n} = \sum_{m=1}^{2} T_{t,m}W_{m,n}^{K}. \]

  • Contoh perhitungan token pertama:

\[ \begin{aligned} \mathbf{K}_1 &= \begin{bmatrix} -0.22 & 0.17 \end{bmatrix} \begin{bmatrix} 0.55 & 0.10\\ -0.15 & 0.45 \end{bmatrix}\\ &= \begin{bmatrix} (-0.22)(0.55)+(0.17)(-0.15) & (-0.22)(0.10)+(0.17)(0.45) \end{bmatrix}\\ &= \begin{bmatrix} -0.1465 & 0.0545 \end{bmatrix}\\ &= \begin{bmatrix} -0.15 & 0.05 \end{bmatrix}. \end{aligned} \]

Dengan aturan yang sama, diperoleh matriks key sebagai berikut.

\[ \mathbf{K} = \begin{bmatrix} -0.15 & 0.05\\ -0.11 & 0.04\\ 0.20 & -0.07\\ 0.09 & -0.03\\ -0.12 & 0.04\\ -0.15 & 0.05\\ -0.12 & 0.04\\ 0.31 & -0.11\\ 0.16 & -0.06\\ -0.12 & 0.04\\ -0.15 & 0.05\\ -0.11 & 0.04\\ 0.31 & -0.11\\ 0.16 & -0.06\\ -0.12 & 0.04\\ -0.15 & 0.05\\ -0.13 & 0.05\\ 0.19 & -0.07\\ 0.06 & -0.02\\ -0.13 & 0.05\\ -0.15 & 0.05\\ -0.13 & 0.05\\ 0.03 & -0.01\\ -0.04 & 0.02\\ -0.13 & 0.05 \end{bmatrix}. \]

d. Proyeksi Value

Pada formulasi separable self-attention, matriks value dibentuk dari matriks token masukan menggunakan bobot proyeksi \(\mathbf{W}^{V}\). Dalam ilustrasi ini, matriks token \(\mathbf{T}\) merealisasikan \(\mathbf{X}\) pada Persamaan (2.22).

  • Bobot proyeksi value:

\[ \mathbf{W}^{V} = \begin{bmatrix} 0.70 & -0.20\\ 0.25 & 0.60 \end{bmatrix}. \]

Matriks \(\mathbf{W}^{V}\) berukuran \(2\times2\). Karena matriks \(\mathbf{T}\) berukuran \(25\times2\), maka matriks value \(\mathbf{V}\) berukuran \(25\times2\).

  • Rumus:

\[ \mathbf{V} = \mathbf{T}\mathbf{W}^{V}. \]

Secara elemen, komponen value ke-\(n\) pada token ke-\(t\) dihitung sebagai:

\[ V_{t,n} = \sum_{m=1}^{2} T_{t,m}W_{m,n}^{V}. \]

  • Contoh perhitungan token pertama:

\[ \begin{aligned} \mathbf{V}_1 &= \begin{bmatrix} -0.22 & 0.17 \end{bmatrix} \begin{bmatrix} 0.70 & -0.20\\ 0.25 & 0.60 \end{bmatrix}\\ &= \begin{bmatrix} (-0.22)(0.70)+(0.17)(0.25) & (-0.22)(-0.20)+(0.17)(0.60) \end{bmatrix}\\ &= \begin{bmatrix} -0.1115 & 0.1460 \end{bmatrix}\\ &= \begin{bmatrix} -0.11 & 0.15 \end{bmatrix}. \end{aligned} \]

Pada tahap keluaran SSA, matriks \(\mathbf{V}\) selanjutnya diproses menggunakan fungsi ReLU sesuai Persamaan (2.22).

Dengan aturan yang sama, diperoleh matriks value sebagai berikut.

\[ \mathbf{V} = \begin{bmatrix} -0.11 & 0.14\\ -0.09 & 0.11\\ 0.15 & -0.19\\ 0.07 & -0.09\\ -0.09 & 0.12\\ -0.11 & 0.14\\ -0.09 & 0.11\\ 0.24 & -0.31\\ 0.13 & -0.16\\ -0.10 & 0.12\\ -0.11 & 0.14\\ -0.09 & 0.11\\ 0.24 & -0.31\\ 0.13 & -0.16\\ -0.10 & 0.12\\ -0.11 & 0.14\\ -0.10 & 0.13\\ 0.14 & -0.18\\ 0.05 & -0.06\\ -0.10 & 0.13\\ -0.11 & 0.14\\ -0.10 & 0.13\\ 0.02 & -0.03\\ -0.03 & 0.04\\ -0.10 & 0.13 \end{bmatrix}. \]

e. Pembentukan vektor konteks

Vektor konteks \(\mathbf{c}_v\) diperoleh dengan menggabungkan seluruh baris matriks key \(\mathbf{K}\) menggunakan koefisien konteks pada vektor \(\mathbf{c}_s\). Setiap token key diberi bobot sesuai nilai koefisien konteksnya. Token dengan nilai \(c_{s,t}\) yang lebih besar memberikan kontribusi yang lebih besar terhadap pembentukan vektor konteks global.

  • Rumus:

\[ \mathbf{c}_v = \mathbf{c}_s^{\mathsf{T}}\mathbf{K} = \sum_{t=1}^{25}c_{s,t}\mathbf{K}_{t,:}. \]

Karena \(\mathbf{c}_s^{\mathsf{T}}\) berukuran \(1\times25\) dan \(\mathbf{K}\) berukuran \(25\times2\), maka vektor konteks \(\mathbf{c}_v\) berukuran \(1\times2\).

\[ (1\times25)(25\times2)=(1\times2). \]

Untuk setiap elemen ke-\(n\), perhitungannya adalah:

\[ c_{v,n} = \sum_{t=1}^{25}c_{s,t}K_{t,n}, \qquad n=1,2. \]

  • Perhitungan elemen pertama:

\[ \begin{aligned} c_{v,1} &= c_{s,1}K_{1,1} +c_{s,2}K_{2,1} +\cdots +c_{s,25}K_{25,1}\\ &= (0.03)(-0.15) +(0.03)(-0.11) +\cdots +(0.03)(-0.13)\\ &=0.01. \end{aligned} \]

  • Perhitungan elemen kedua:

\[ \begin{aligned} c_{v,2} &= c_{s,1}K_{1,2} +c_{s,2}K_{2,2} +\cdots +c_{s,25}K_{25,2}\\ &= (0.03)(0.05) +(0.03)(0.04) +\cdots +(0.03)(0.05)\\ &=-0.005. \end{aligned} \]

Perhitungan dilakukan menggunakan nilai \(\mathbf{c}_s\) dan \(\mathbf{K}\) dengan presisi penuh sebelum hasil akhir ditampilkan. Nilai ditampilkan hingga dua angka di belakang koma, kecuali elemen kedua yang ditampilkan hingga tiga angka di belakang koma agar tidak menjadi \(-0.00\). Oleh karena itu, diperoleh vektor konteks:

\[ \mathbf{c}_v= \begin{bmatrix} 0.01 & -0.005 \end{bmatrix}. \]

f. Keluaran separable self-attention

Keluaran separable self-attention dibentuk dengan menerapkan fungsi ReLU pada setiap elemen matriks value \(\mathbf{V}\). Fungsi ReLU mempertahankan nilai positif dan mengubah nilai negatif menjadi nol. Hasil aktivasi tersebut kemudian dikalikan secara elemen demi elemen dengan vektor konteks global \(\mathbf{c}_v\), lalu diproyeksikan menggunakan bobot keluaran \(\mathbf{W}^{O}\).

Pada ilustrasi ini, vektor konteks global sebelum pembulatan adalah:

\[ \mathbf{c}_v= \begin{bmatrix} 0.0132 & -0.0047 \end{bmatrix}. \]

  • Bobot keluaran:

\[ \mathbf{W}^{O}= \begin{bmatrix} 50.00 & -20.00\\ 50.00 & 50.00 \end{bmatrix}. \]

Bobot \(\mathbf{W}^{O}\) merupakan bobot ilustratif yang digunakan untuk memproyeksikan hasil separable self-attention. Nilai tersebut dipilih agar keluaran tetap dapat ditampilkan secara jelas setelah pembulatan.

  • Rumus:

Sesuai Persamaan (2.22) pada draft, keluaran separable self-attention dirumuskan sebagai:

\[ \mathbf{Z}_{\mathrm{SSA}} = \left( \mathbf{c}_v \odot \operatorname{ReLU}(\mathbf{V}) \right) \mathbf{W}^{O}. \]

Vektor \(\mathbf{c}_v\) berukuran \(1\times2\) diterapkan pada setiap baris matriks \(\operatorname{ReLU}(\mathbf{V})\) yang berukuran \(25\times2\). Oleh karena itu, hasil perkalian elemen demi elemen berukuran \(25\times2\). Setelah dikalikan dengan \(\mathbf{W}^{O}\) yang berukuran \(2\times2\), diperoleh matriks \(\mathbf{Z}_{\mathrm{SSA}}\) berukuran \(25\times2\).

\[ \operatorname{ReLU}(V_{t,n}) = \max(0,V_{t,n}). \]

  • Contoh perhitungan token pertama:

\[ \begin{aligned} \mathbf{Z}_{\mathrm{SSA},1} &= \left( \mathbf{c}_v \odot \operatorname{ReLU}(\mathbf{V}_{1}) \right) \mathbf{W}^{O}\\ &= \left( \begin{bmatrix} 0.0132 & -0.0047 \end{bmatrix} \odot \operatorname{ReLU} \begin{bmatrix} -0.11 & 0.14 \end{bmatrix} \right) \begin{bmatrix} 50.00 & -20.00\\ 50.00 & 50.00 \end{bmatrix}\\ &= \left( \begin{bmatrix} 0.0132 & -0.0047 \end{bmatrix} \odot \begin{bmatrix} 0.00 & 0.14 \end{bmatrix} \right) \begin{bmatrix} 50.00 & -20.00\\ 50.00 & 50.00 \end{bmatrix}\\ &= \begin{bmatrix} 0.00 & -0.0007 \end{bmatrix} \begin{bmatrix} 50.00 & -20.00\\ 50.00 & 50.00 \end{bmatrix}\\ &= \begin{bmatrix} -0.03 & -0.03 \end{bmatrix}. \end{aligned} \]

Dengan aturan yang sama, diperoleh keluaran separable self-attention sebagai berikut.

\[ \mathbf{Z}_{\mathrm{SSA}}= \begin{bmatrix} -0.03 & -0.03\\ -0.03 & -0.03\\ 0.10 & -0.04\\ 0.05 & -0.02\\ -0.03 & -0.03\\ -0.03 & -0.03\\ -0.03 & -0.03\\ 0.16 & -0.06\\ 0.08 & -0.03\\ -0.03 & -0.03\\ -0.03 & -0.03\\ -0.03 & -0.03\\ 0.16 & -0.06\\ 0.08 & -0.03\\ -0.03 & -0.03\\ -0.03 & -0.03\\ -0.03 & -0.03\\ 0.10 & -0.04\\ 0.03 & -0.01\\ -0.03 & -0.03\\ -0.03 & -0.03\\ -0.03 & -0.03\\ 0.01 & -0.005\\ -0.01 & -0.01\\ -0.03 & -0.03 \end{bmatrix}. \]

Nilai dihitung menggunakan presisi penuh sebelum ditampilkan. Hasil ditulis hingga dua angka di belakang koma, kecuali nilai \(-0.005\) agar tidak ditampilkan sebagai \(-0.00\).

g. Residual separable self-attention

Keluaran separable self-attention \(\mathbf{Z}_{\mathrm{SSA}}\) selanjutnya digabungkan dengan matriks token masukan \(\mathbf{T}\) melalui residual connection. Proses ini mempertahankan informasi awal setiap token sekaligus menambahkan informasi konteks global yang diperoleh dari SSA.

  • Rumus:

\[ \mathbf{Z}' = \mathbf{T} + \mathbf{Z}_{\mathrm{SSA}}. \]

Matriks \(\mathbf{T}\) dan \(\mathbf{Z}_{\mathrm{SSA}}\) masing-masing berukuran \(25\times2\). Oleh karena itu, matriks hasil residual \(\mathbf{Z}'\) juga berukuran \(25\times2\).

  • Contoh perhitungan token pertama:

Perhitungan dilakukan menggunakan nilai presisi penuh sebelum hasil akhir ditampilkan. Untuk token pertama, diperoleh:

\[ \begin{aligned} \mathbf{Z}'_{1} &= \mathbf{T}_{1} + \mathbf{Z}_{\mathrm{SSA},1}\\ &= \begin{bmatrix} -0.2222 & 0.1666 \end{bmatrix} + \begin{bmatrix} -0.0342 & -0.0342 \end{bmatrix}\\ &= \begin{bmatrix} -0.2564 & 0.1324 \end{bmatrix}\\ &= \begin{bmatrix} -0.26 & 0.13 \end{bmatrix}. \end{aligned} \]

  • Contoh perhitungan token ketiga:

\[ \begin{aligned} \mathbf{Z}'_{3} &= \mathbf{T}_{3} + \mathbf{Z}_{\mathrm{SSA},3}\\ &= \begin{bmatrix} 0.30 & -0.22 \end{bmatrix} + \begin{bmatrix} 0.10 & -0.04 \end{bmatrix}\\ &= \begin{bmatrix} 0.40 & -0.26 \end{bmatrix}. \end{aligned} \]

Dengan aturan yang sama, diperoleh matriks hasil residual separable self-attention sebagai berikut.

\[ \mathbf{Z}'= \begin{bmatrix} -0.26 & 0.13\\ -0.20 & 0.10\\ 0.40 & -0.26\\ 0.18 & -0.12\\ -0.21 & 0.11\\ -0.25 & 0.13\\ -0.20 & 0.10\\ 0.63 & -0.42\\ 0.33 & -0.22\\ -0.22 & 0.11\\ -0.26 & 0.13\\ -0.20 & 0.10\\ 0.64 & -0.42\\ 0.33 & -0.22\\ -0.22 & 0.11\\ -0.25 & 0.13\\ -0.22 & 0.12\\ 0.38 & -0.25\\ 0.12 & -0.08\\ -0.23 & 0.12\\ -0.26 & 0.13\\ -0.23 & 0.12\\ 0.05 & -0.035\\ -0.07 & 0.04\\ -0.23 & 0.12 \end{bmatrix}. \]

h. Normalisasi residual separable self-attention

Matriks hasil residual separable self-attention \(\mathbf{Z}'\) dinormalisasi per token menggunakan layer normalization. Normalisasi dilakukan pada dua elemen fitur dalam setiap token secara terpisah, bukan pada seluruh matriks sekaligus. Tahap ini menghasilkan \(\operatorname{LN}(\mathbf{Z}')\) sebagai masukan untuk MLP.

  • Rumus rata-rata token ke-\(t\):

\[ \mu_{Z',t} = \frac{1}{2} \sum_{n=1}^{2}Z'_{t,n}. \]

  • Rumus varians token ke-\(t\):

\[ \sigma_{Z',t}^{2} = \frac{1}{2} \sum_{n=1}^{2} \left( Z'_{t,n}-\mu_{Z',t} \right)^2. \]

  • Rumus normalisasi:

\[ \left[ \operatorname{LN}(\mathbf{Z}') \right]_{t,n} = \frac{ Z'_{t,n}-\mu_{Z',t} }{ \sqrt{ \sigma_{Z',t}^{2}+10^{-5} } }. \]

Matriks \(\operatorname{LN}(\mathbf{Z}')\) berukuran \(25\times2\).

  • Contoh perhitungan token pertama:

Nilai token pertama sebelum pembulatan adalah:

\[ \mathbf{Z}'_{1}= \begin{bmatrix} -0.2564 & 0.1324 \end{bmatrix}. \]

Rata-rata token pertama adalah:

\[ \begin{aligned} \mu_{Z',1} &= \frac{-0.2564+0.1324}{2}\\ &= -0.0620. \end{aligned} \]

Varians token pertama adalah:

\[ \begin{aligned} \sigma_{Z',1}^{2} &= \frac{ (-0.2564-(-0.0620))^2 + (0.1324-(-0.0620))^2 }{2}\\ &= \frac{(-0.1944)^2+(0.1944)^2}{2}\\ &= 0.0378. \end{aligned} \]

Maka:

\[ \begin{aligned} \operatorname{LN}(\mathbf{Z}'_{1}) &= \begin{bmatrix} \dfrac{-0.2564-(-0.0620)} {\sqrt{0.0378+10^{-5}}} & \dfrac{0.1324-(-0.0620)} {\sqrt{0.0378+10^{-5}}} \end{bmatrix}\\ &= \begin{bmatrix} -1.00 & 1.00 \end{bmatrix}. \end{aligned} \]

Dengan aturan yang sama, diperoleh matriks hasil normalisasi residual separable self-attention sebagai berikut.

\[ \operatorname{LN}(\mathbf{Z}')= \begin{bmatrix} -1.00 & 1.00\\ -1.00 & 1.00\\ 1.00 & -1.00\\ 1.00 & -1.00\\ -1.00 & 1.00\\ -1.00 & 1.00\\ -1.00 & 1.00\\ 1.00 & -1.00\\ 1.00 & -1.00\\ -1.00 & 1.00\\ -1.00 & 1.00\\ -1.00 & 1.00\\ 1.00 & -1.00\\ 1.00 & -1.00\\ -1.00 & 1.00\\ -1.00 & 1.00\\ -1.00 & 1.00\\ 1.00 & -1.00\\ 1.00 & -1.00\\ -1.00 & 1.00\\ -1.00 & 1.00\\ -1.00 & 1.00\\ 1.00 & -1.00\\ -1.00 & 1.00\\ -1.00 & 1.00 \end{bmatrix}. \]

i. Lapisan pertama MLP (feed-forward network)

Lapisan pertama MLP menerima token hasil normalisasi residual separable self-attention, yaitu \(\operatorname{LN}(\mathbf{Z}')\). Lapisan ini memproyeksikan setiap token dari dua elemen fitur menjadi tiga elemen fitur, kemudian menerapkan fungsi aktivasi ReLU. Proses tersebut sesuai dengan tahap pertama MLP pada Persamaan (2.17) di Bab II.

Pada ilustrasi ini, vektor bias lapisan pertama diabaikan atau ditetapkan sebagai \(\mathbf{b}_1=\mathbf{0}\).

  • Bobot lapisan pertama:

\[ \mathbf{W}_1= \begin{bmatrix} 0.45 & -0.35 & 0.25\\ -0.20 & 0.55 & 0.30 \end{bmatrix}. \]

Matriks \(\mathbf{W}_1\) berukuran \(2\times3\).

  • Rumus:

\[ \operatorname{ReLU} \left( \operatorname{LN}(\mathbf{Z}') \mathbf{W}_1 \right). \]

Matriks \(\operatorname{LN}(\mathbf{Z}')\) berukuran \(25\times2\). Oleh karena itu, hasil lapisan pertama MLP berukuran \(25\times3\).

  • Contoh perhitungan token pertama:

\[ \begin{aligned} \operatorname{ReLU} \left( \operatorname{LN}(\mathbf{Z}'_1) \mathbf{W}_1 \right) &= \operatorname{ReLU} \left( \begin{bmatrix} -1.00 & 1.00 \end{bmatrix} \begin{bmatrix} 0.45 & -0.35 & 0.25\\ -0.20 & 0.55 & 0.30 \end{bmatrix} \right)\\ &= \operatorname{ReLU} \left( \begin{bmatrix} -0.65 & 0.90 & 0.05 \end{bmatrix} \right)\\ &= \begin{bmatrix} 0.00 & 0.90 & 0.05 \end{bmatrix}. \end{aligned} \]

  • Contoh perhitungan token ketiga:

\[ \begin{aligned} \operatorname{ReLU} \left( \operatorname{LN}(\mathbf{Z}'_3) \mathbf{W}_1 \right) &= \operatorname{ReLU} \left( \begin{bmatrix} 1.00 & -1.00 \end{bmatrix} \begin{bmatrix} 0.45 & -0.35 & 0.25\\ -0.20 & 0.55 & 0.30 \end{bmatrix} \right)\\ &= \operatorname{ReLU} \left( \begin{bmatrix} 0.65 & -0.90 & -0.05 \end{bmatrix} \right)\\ &= \begin{bmatrix} 0.65 & 0.00 & 0.00 \end{bmatrix}. \end{aligned} \]

Dengan aturan yang sama, diperoleh hasil lapisan pertama MLP sebagai berikut.

\[ \operatorname{ReLU} \left( \operatorname{LN}(\mathbf{Z}') \mathbf{W}_1 \right) = \begin{bmatrix} 0.00 & 0.90 & 0.05\\ 0.00 & 0.90 & 0.05\\ 0.65 & 0.00 & 0.00\\ 0.65 & 0.00 & 0.00\\ 0.00 & 0.90 & 0.05\\ 0.00 & 0.90 & 0.05\\ 0.00 & 0.90 & 0.05\\ 0.65 & 0.00 & 0.00\\ 0.65 & 0.00 & 0.00\\ 0.00 & 0.90 & 0.05\\ 0.00 & 0.90 & 0.05\\ 0.00 & 0.90 & 0.05\\ 0.65 & 0.00 & 0.00\\ 0.65 & 0.00 & 0.00\\ 0.00 & 0.90 & 0.05\\ 0.00 & 0.90 & 0.05\\ 0.00 & 0.90 & 0.05\\ 0.65 & 0.00 & 0.00\\ 0.65 & 0.00 & 0.00\\ 0.00 & 0.90 & 0.05\\ 0.00 & 0.90 & 0.05\\ 0.00 & 0.90 & 0.05\\ 0.65 & 0.00 & 0.00\\ 0.00 & 0.90 & 0.05\\ 0.00 & 0.90 & 0.05 \end{bmatrix}. \]

j. Lapisan kedua MLP (feed-forward network)

Lapisan kedua MLP memproyeksikan tiga elemen fitur hasil lapisan pertama kembali menjadi dua elemen fitur. Pada tahap ini, keluaran proyeksi linear tidak diberi fungsi aktivasi tambahan. Proses ini sesuai dengan bagian kedua MLP pada Persamaan (2.17) di Bab II.

Pada ilustrasi ini, vektor bias lapisan kedua diabaikan atau ditetapkan sebagai \(\mathbf{b}_2=\mathbf{0}\).

  • Bobot lapisan kedua:

\[ \mathbf{W}_2= \begin{bmatrix} 0.35 & -0.25\\ 0.15 & 0.45\\ -0.20 & 0.30 \end{bmatrix}. \]

Matriks \(\mathbf{W}_2\) berukuran \(3\times2\).

  • Rumus:

\[ \operatorname{ReLU} \left( \operatorname{LN}(\mathbf{Z}') \mathbf{W}_1 \right) \mathbf{W}_2. \]

Hasil lapisan pertama MLP berukuran \(25\times3\). Oleh karena itu, keluaran lapisan kedua MLP berukuran \(25\times2\).

  • Contoh perhitungan token pertama:

\[ \begin{aligned} & \operatorname{ReLU} \left( \operatorname{LN}(\mathbf{Z}'_1) \mathbf{W}_1 \right) \mathbf{W}_2\\ &= \begin{bmatrix} 0.00 & 0.90 & 0.05 \end{bmatrix} \begin{bmatrix} 0.35 & -0.25\\ 0.15 & 0.45\\ -0.20 & 0.30 \end{bmatrix}\\ &= \begin{bmatrix} (0.00)(0.35)+(0.90)(0.15)+(0.05)(-0.20) & (0.00)(-0.25)+(0.90)(0.45)+(0.05)(0.30) \end{bmatrix}\\ &= \begin{bmatrix} 0.125 & 0.420 \end{bmatrix}\\ &= \begin{bmatrix} 0.13 & 0.42 \end{bmatrix}. \end{aligned} \]

  • Contoh perhitungan token ketiga:

\[ \begin{aligned} & \operatorname{ReLU} \left( \operatorname{LN}(\mathbf{Z}'_3) \mathbf{W}_1 \right) \mathbf{W}_2\\ &= \begin{bmatrix} 0.65 & 0.00 & 0.00 \end{bmatrix} \begin{bmatrix} 0.35 & -0.25\\ 0.15 & 0.45\\ -0.20 & 0.30 \end{bmatrix}\\ &= \begin{bmatrix} 0.23 & -0.16 \end{bmatrix}. \end{aligned} \]

Dengan aturan yang sama, diperoleh keluaran lapisan kedua MLP sebagai berikut.

\[ \operatorname{ReLU} \left( \operatorname{LN}(\mathbf{Z}') \mathbf{W}_1 \right) \mathbf{W}_2 = \begin{bmatrix} 0.13 & 0.42\\ 0.13 & 0.42\\ 0.23 & -0.16\\ 0.23 & -0.16\\ 0.13 & 0.42\\ 0.13 & 0.42\\ 0.13 & 0.42\\ 0.23 & -0.16\\ 0.23 & -0.16\\ 0.13 & 0.42\\ 0.13 & 0.42\\ 0.13 & 0.42\\ 0.23 & -0.16\\ 0.23 & -0.16\\ 0.13 & 0.42\\ 0.13 & 0.42\\ 0.13 & 0.42\\ 0.23 & -0.16\\ 0.23 & -0.16\\ 0.13 & 0.42\\ 0.13 & 0.42\\ 0.13 & 0.42\\ 0.23 & -0.16\\ 0.13 & 0.42\\ 0.13 & 0.42 \end{bmatrix}. \]

k. Residual MLP (feed-forward network)

Keluaran lapisan kedua MLP ditambahkan dengan representasi residual sebelumnya, yaitu \(\mathbf{Z}'\). Penjumlahan ini mempertahankan informasi hasil separable self-attention sekaligus menambahkan transformasi fitur dari MLP. Keluaran akhir blok linear Transformer dinotasikan sebagai \(\mathbf{Z}\).

  • Rumus:

\[ \mathbf{Z} = \mathbf{Z}' + \operatorname{ReLU} \left( \operatorname{LN}(\mathbf{Z}') \mathbf{W}_1 \right) \mathbf{W}_2. \]

Matriks \(\mathbf{Z}'\) dan keluaran lapisan kedua MLP masing-masing berukuran \(25\times2\). Oleh karena itu, matriks keluaran \(\mathbf{Z}\) juga berukuran \(25\times2\).

  • Contoh perhitungan token pertama:

\[ \begin{aligned} \mathbf{Z}_1 &= \mathbf{Z}'_1+ \operatorname{ReLU} \left( \operatorname{LN}(\mathbf{Z}'_1) \mathbf{W}_1 \right) \mathbf{W}_2\\ &= \begin{bmatrix} -0.26 & 0.13 \end{bmatrix} + \begin{bmatrix} 0.13 & 0.42 \end{bmatrix}\\ &= \begin{bmatrix} -0.13 & 0.55 \end{bmatrix}. \end{aligned} \]

  • Contoh perhitungan token ketiga:

\[ \begin{aligned} \mathbf{Z}_3 &= \begin{bmatrix} 0.40 & -0.26 \end{bmatrix} + \begin{bmatrix} 0.23 & -0.16 \end{bmatrix}\\ &= \begin{bmatrix} 0.63 & -0.43 \end{bmatrix}. \end{aligned} \]

Dengan aturan yang sama, diperoleh keluaran akhir blok linear Transformer sebagai berikut.

\[ \mathbf{Z}= \begin{bmatrix} -0.13 & 0.55\\ -0.07 & 0.52\\ 0.63 & -0.43\\ 0.41 & -0.28\\ -0.08 & 0.53\\ -0.13 & 0.55\\ -0.08 & 0.52\\ 0.86 & -0.58\\ 0.55 & -0.38\\ -0.09 & 0.53\\ -0.13 & 0.55\\ -0.07 & 0.52\\ 0.86 & -0.58\\ 0.55 & -0.38\\ -0.09 & 0.53\\ -0.13 & 0.55\\ -0.10 & 0.54\\ 0.60 & -0.41\\ 0.35 & -0.25\\ -0.11 & 0.54\\ -0.13 & 0.55\\ -0.11 & 0.54\\ 0.28 & -0.19\\ 0.05 & 0.46\\ -0.11 & 0.54 \end{bmatrix}. \]

l. Normalisasi akhir linear Transformer

Tahap terakhir pada ilustrasi linear Transformer adalah normalisasi per token terhadap matriks keluaran residual MLP \(\mathbf{Z}\). Hasil normalisasi dinotasikan sebagai \(\mathbf{G}\) dan digunakan sebagai representasi global sebelum proses folding.

  • Rumus:

\[ \mathbf{G} = \operatorname{LN}(\mathbf{Z}). \]

Untuk token ke-\(t\), rata-rata dan varians dihitung sebagai:

\[ \mu_{Z,t} = \frac{1}{2} \sum_{n=1}^{2}Z_{t,n}, \]

\[ \sigma_{Z,t}^{2} = \frac{1}{2} \sum_{n=1}^{2} \left( Z_{t,n}-\mu_{Z,t} \right)^2. \]

Selanjutnya, elemen hasil normalisasi dirumuskan sebagai:

\[ G_{t,n} = \frac{ Z_{t,n}-\mu_{Z,t} }{ \sqrt{ \sigma_{Z,t}^{2}+10^{-5} } }. \]

Matriks \(\mathbf{G}\) berukuran \(25\times2\).

  • Contoh perhitungan token pertama:

\[ \mathbf{Z}_{1}= \begin{bmatrix} -0.13 & 0.55 \end{bmatrix}. \]

Rata-rata token pertama adalah:

\[ \begin{aligned} \mu_{Z,1} &= \frac{-0.13+0.55}{2}\\ &= 0.21. \end{aligned} \]

Varians token pertama adalah:

\[ \begin{aligned} \sigma_{Z,1}^{2} &= \frac{ (-0.13-0.21)^2+ (0.55-0.21)^2 }{2}\\ &= \frac{(-0.34)^2+(0.34)^2}{2}\\ &= 0.1156. \end{aligned} \]

Maka:

\[ \begin{aligned} \mathbf{G}_{1} &= \begin{bmatrix} \dfrac{-0.13-0.21} {\sqrt{0.1156+10^{-5}}} & \dfrac{0.55-0.21} {\sqrt{0.1156+10^{-5}}} \end{bmatrix}\\ &= \begin{bmatrix} -1.00 & 1.00 \end{bmatrix}. \end{aligned} \]

Dengan aturan yang sama, diperoleh representasi global sebagai berikut.

\[ \mathbf{G}= \begin{bmatrix} -1.00 & 1.00\\ -1.00 & 1.00\\ 1.00 & -1.00\\ 1.00 & -1.00\\ -1.00 & 1.00\\ -1.00 & 1.00\\ -1.00 & 1.00\\ 1.00 & -1.00\\ 1.00 & -1.00\\ -1.00 & 1.00\\ -1.00 & 1.00\\ -1.00 & 1.00\\ 1.00 & -1.00\\ 1.00 & -1.00\\ -1.00 & 1.00\\ -1.00 & 1.00\\ -1.00 & 1.00\\ 1.00 & -1.00\\ 1.00 & -1.00\\ -1.00 & 1.00\\ -1.00 & 1.00\\ -1.00 & 1.00\\ 1.00 & -1.00\\ -1.00 & 1.00\\ -1.00 & 1.00 \end{bmatrix}. \]

4. Folding, Proyeksi Global, dan Fusi Residual

Keluaran linear Transformer \(\mathbf{G}\) masih berbentuk urutan token berukuran \(25\times2\). Pada tahap ini, token dikembalikan ke susunan spasial berukuran \(5\times5\) melalui proses folding. Selanjutnya, kedua kanal hasil folding diproyeksikan menjadi satu feature map global. Feature map global tersebut kemudian digabungkan dengan feature map lokal \(\mathbf{L}\) serta feature map masukan \(\mathbf{X}\) melalui fusi residual.

a. Folding keluaran linear Transformer

Matriks \(\mathbf{G}\) memiliki dua kolom. Kolom pertama dilipat kembali menjadi kanal pertama \(\mathbf{G}_1\), sedangkan kolom kedua dilipat kembali menjadi kanal kedua \(\mathbf{G}_2\). Posisi token ditentukan berdasarkan urutan raster dari kiri ke kanan dan dari atas ke bawah.

  • Rumus:

\[ t=5(i-1)+j, \qquad i,j=1,2,\ldots,5, \]

dengan \(i\) menyatakan indeks baris, \(j\) menyatakan indeks kolom, dan \(t\) menyatakan indeks token.

Untuk setiap posisi spasial \((i,j)\),

\[ G_{1,i,j}=G_{t,1}, \qquad G_{2,i,j}=G_{t,2}, \qquad t=5(i-1)+j. \]

  • Contoh:

Baris pertama pada matriks \(\mathbf{G}\) adalah:

\[ \mathbf{G}_{1}= \begin{bmatrix} -1.00 & 1.00 \end{bmatrix}. \]

Karena token pertama berada pada posisi \((1,1)\), maka:

\[ \begin{aligned} t &=5(1-1)+1\\ &=1. \end{aligned} \]

Dengan demikian, nilai hasil folding pada posisi \((1,1)\) adalah:

\[ G_{1,1,1}=-1.00, \qquad G_{2,1,1}=1.00. \]

Matriks kanal pertama setelah proses folding adalah:

\[ \mathbf{G}_1= \begin{bmatrix} -1.00 & -1.00 & 1.00 & 1.00 & -1.00\\ -1.00 & -1.00 & 1.00 & 1.00 & -1.00\\ -1.00 & -1.00 & 1.00 & 1.00 & -1.00\\ -1.00 & -1.00 & 1.00 & 1.00 & -1.00\\ -1.00 & -1.00 & 1.00 & -1.00 & -1.00 \end{bmatrix}. \]

Matriks kanal kedua setelah proses folding adalah:

\[ \mathbf{G}_2= \begin{bmatrix} 1.00 & 1.00 & -1.00 & -1.00 & 1.00\\ 1.00 & 1.00 & -1.00 & -1.00 & 1.00\\ 1.00 & 1.00 & -1.00 & -1.00 & 1.00\\ 1.00 & 1.00 & -1.00 & -1.00 & 1.00\\ 1.00 & 1.00 & -1.00 & 1.00 & 1.00 \end{bmatrix}. \]

Kedua matriks hasil folding, yaitu \(\mathbf{G}_1\) dan \(\mathbf{G}_2\), masing-masing berukuran \(5\times5\).

b. Proyeksi dan aktivasi feature map global

Dua kanal hasil folding, yaitu \(\mathbf{G}_1\) dan \(\mathbf{G}_2\), diproyeksikan menjadi satu kanal menggunakan pointwise convolution \(1\times1\) tanpa bias. Hasil proyeksi kemudian diterapkan fungsi Swish untuk membentuk feature map global \(\mathbf{G}_{\mathrm{glob}}\).

  • Bobot proyeksi global:

\[ \mathbf{W}_{\mathrm{glob}} = \begin{bmatrix} 0.55 & -0.30 \end{bmatrix}. \]

  • Rumus:

Nilai hasil proyeksi sebelum aktivasi dinotasikan sebagai \(F_{\mathrm{glob},i,j}\):

\[ F_{\mathrm{glob},i,j} = 0.55G_{1,i,j} - 0.30G_{2,i,j}. \]

Selanjutnya, fungsi Swish diterapkan sebagai berikut:

\[ \begin{aligned} G_{\mathrm{glob},i,j} &= \operatorname{Swish} \left( F_{\mathrm{glob},i,j} \right)\\ &= \frac{ F_{\mathrm{glob},i,j} }{ 1+e^{-F_{\mathrm{glob},i,j}} }. \end{aligned} \]

Matriks \(\mathbf{G}_{\mathrm{glob}}\) berukuran \(5\times5\).

  • Contoh perhitungan pada posisi \((1,1)\):

\[ \begin{aligned} F_{\mathrm{glob},1,1} &= 0.55G_{1,1,1} - 0.30G_{2,1,1}\\ &= 0.55(-1.00) - 0.30(1.00)\\ &= -0.85. \end{aligned} \]

\[ \begin{aligned} G_{\mathrm{glob},1,1} &= \operatorname{Swish}(-0.85)\\ &= \frac{-0.85}{1+e^{-(-0.85)}}\\ &= \frac{-0.85}{1+e^{0.85}}\\ &= \frac{-0.85}{1+2.34}\\ &= -0.25. \end{aligned} \]

Untuk posisi dengan \(G_{1,i,j}=1.00\) dan \(G_{2,i,j}=-1.00\), diperoleh nilai hasil proyeksi sebesar \(0.85\), sehingga nilai setelah aktivasi Swish adalah \(0.60\).

Dengan aturan yang sama, diperoleh feature map global sebagai berikut.

\[ \mathbf{G}_{\mathrm{glob}}= \begin{bmatrix} -0.25 & -0.25 & 0.60 & 0.60 & -0.25\\ -0.25 & -0.25 & 0.60 & 0.60 & -0.25\\ -0.25 & -0.25 & 0.60 & 0.60 & -0.25\\ -0.25 & -0.25 & 0.60 & 0.60 & -0.25\\ -0.25 & -0.25 & 0.60 & -0.25 & -0.25 \end{bmatrix}. \]

c. Fusi residual fitur lokal dan global

Feature map lokal \(\mathbf{L}\) dan feature map global \(\mathbf{G}_{\mathrm{glob}}\) digabungkan melalui operasi concatenate. Hasil penggabungan tersebut diproyeksikan menggunakan pointwise convolution \(1\times1\), kemudian ditambahkan dengan feature map masukan \(\mathbf{X}\) melalui residual connection. Keluaran fusi dinotasikan sebagai \(\mathbf{X}^{0,0}\).

Pada ilustrasi ini, pointwise convolution \(1\times1\) dilakukan tanpa bias. Bobot fusi untuk feature map lokal dan global ditetapkan sebagai berikut:

\[ \mathbf{W}_{\mathrm{fuse}} = \begin{bmatrix} 0.45 & 0.35 \end{bmatrix}. \]

Bobot pertama diterapkan pada \(\mathbf{L}\), sedangkan bobot kedua diterapkan pada \(\mathbf{G}_{\mathrm{glob}}\).

  • Rumus:

\[ \begin{aligned} \mathbf{X}^{0,0} &= \mathbf{X} + \operatorname{Conv}_{1\times1} \left( \operatorname{Concat} \left[ \mathbf{L}, \mathbf{G}_{\mathrm{glob}} \right] \right). \end{aligned} \]

Untuk setiap posisi spasial \((i,j)\), bentuk perhitungannya adalah:

\[ \begin{aligned} F_{\mathrm{fuse},i,j} &= 0.45L_{i,j} + 0.35G_{\mathrm{glob},i,j},\\ X^{0,0}_{i,j} &= X_{i,j} + F_{\mathrm{fuse},i,j}\\ &= X_{i,j} + 0.45L_{i,j} + 0.35G_{\mathrm{glob},i,j}. \end{aligned} \]

  • Contoh perhitungan pada posisi \((1,1)\):

\[ \begin{aligned} X^{0,0}_{1,1} &= X_{1,1} + 0.45L_{1,1} + 0.35G_{\mathrm{glob},1,1}\\ &= -2.12 + 0.45(-0.28) + 0.35(-0.25)\\ &= -2.12-0.126-0.0875\\ &= -2.33. \end{aligned} \]

Dengan perhitungan yang sama, diperoleh keluaran blok MobileViTv3-v2-1.0 sebagai berikut.

\[ \mathbf{X}^{0,0}= \begin{bmatrix} -2.33 & -1.21 & 1.55 & 0.91 & -1.76\\ -2.33 & -0.94 & 1.91 & 1.25 & -1.62\\ -2.33 & -0.94 & 1.92 & 1.25 & -1.62\\ -2.33 & -1.08 & 1.54 & 0.88 & -1.77\\ -2.19 & -1.50 & 0.58 & -0.32 & -1.91 \end{bmatrix}. \]

Matriks \(\mathbf{X}^{0,0}\) berukuran \(5\times5\). Keluaran ini menjadi masukan pada tahap encoder downsampling dan decoder UNet++.

5. Encoder Bertingkat

Pada tahap ini, feature map keluaran MobileViTv3-v2, yaitu (^{0,0}), diproses melalui tahapan encoder bertingkat untuk memperoleh representasi fitur pada berbagai skala spasial. Proses downsampling dilakukan menggunakan strided convolution untuk mengurangi dimensi spasial feature map secara bertahap. Setiap tahap menghasilkan representasi fitur dengan ukuran spasial yang lebih kecil, yang selanjutnya digunakan pada proses ekstraksi fitur bertingkat. Pada jalur encoder, tidak dilakukan operasi upsampling karena proses tersebut merupakan bagian dari tahapan decoder.

a. Downsampling encoder pertama \(\left(\mathbf{X}^{1,0}\right)\)

Feature map \(\mathbf{X}^{0,0}\) berukuran \(5\times5\) diproses menggunakan strided convolution dengan kernel \(3\times3\), stride \(2\), dan zero padding sebesar \(1\) pada setiap sisi. Pada ilustrasi ini, operasi konvolusi dilakukan tanpa bias. Keluaran konvolusi pada tahap ini dinotasikan sebagai \(\mathbf{F}_{\mathrm{enc}}^{(1)}\), dengan:

\[ \mathbf{X}^{1,0} = \mathbf{F}_{\mathrm{enc}}^{(1)}. \]

  • Penambahan Zero Padding:

Sebelum operasi strided convolution dilakukan, satu lapisan nilai nol ditambahkan pada keempat sisi feature map masukan, yaitu sisi atas, bawah, kiri, dan kanan. Penambahan zero padding memungkinkan kernel mencakup area tepi matriks selama proses konvolusi.

Matriks feature map masukan merupakan keluaran blok MobileViTv3-v2-1.0 yang diperoleh pada tahap sebelumnya, yaitu:

\[ \mathbf{X}^{0,0} = \begin{bmatrix} -2.33 & -1.21 & 1.55 & 0.91 & -1.76\\ -2.33 & -0.94 & 1.91 & 1.25 & -1.62\\ -2.33 & -0.94 & 1.92 & 1.25 & -1.62\\ -2.33 & -1.08 & 1.54 & 0.88 & -1.77\\ -2.19 & -1.50 & 0.58 & -0.32 & -1.91 \end{bmatrix}. \]

Setelah penambahan zero padding sebesar satu piksel pada setiap sisi, ukuran matriks berubah dari \(5\times5\) menjadi \(7\times7\), yaitu:

\[ \mathbf{X}_{\mathrm{pad}}^{0,0} = \begin{bmatrix} 0.00 & 0.00 & 0.00 & 0.00 & 0.00 & 0.00 & 0.00\\ 0.00 & -2.33 & -1.21 & 1.55 & 0.91 & -1.76 & 0.00\\ 0.00 & -2.33 & -0.94 & 1.91 & 1.25 & -1.62 & 0.00\\ 0.00 & -2.33 & -0.94 & 1.92 & 1.25 & -1.62 & 0.00\\ 0.00 & -2.33 & -1.08 & 1.54 & 0.88 & -1.77 & 0.00\\ 0.00 & -2.19 & -1.50 & 0.58 & -0.32 & -1.91 & 0.00\\ 0.00 & 0.00 & 0.00 & 0.00 & 0.00 & 0.00 & 0.00 \end{bmatrix}. \]

  • Kernel Encoder Pertama:

Pada ilustrasi ini, kernel disederhanakan dengan hanya elemen tengah bernilai satu dan elemen lainnya bernilai nol:

\[ \mathbf{W}_{\mathrm{enc}}^{(1)} = \begin{bmatrix} 0 & 0 & 0\\ 0 & 1 & 0\\ 0 & 0 & 0 \end{bmatrix}. \]

Kernel tersebut digunakan untuk mengilustrasikan operasi strided convolution. Pada setiap posisi, sembilan elemen dalam area konvolusi dikalikan dengan sembilan bobot kernel yang bersesuaian, kemudian seluruh hasil perkalian dijumlahkan.

Karena hanya bobot pusat kernel yang bernilai satu, hasil konvolusi pada ilustrasi ini ditentukan oleh elemen yang berada tepat di bawah pusat kernel. Sementara itu, penggunaan stride sebesar \(2\) menyebabkan kernel bergeser dua posisi pada setiap perpindahan.

Ukuran keluaran dihitung menggunakan:

\[ \begin{aligned} o &= \left\lfloor \frac{i+2p-k}{s} \right\rfloor+1\\ &= \left\lfloor \frac{5+2(1)-3}{2} \right\rfloor+1\\ &= \left\lfloor \frac{4}{2} \right\rfloor+1\\ &=3. \end{aligned} \]

Dengan demikian, ukuran spasial feature map berubah dari \(5\times5\) menjadi \(3\times3\).

  • Rumus:

Secara umum, operasi strided convolution dengan kernel \(3\times3\), stride \(2\), dan padding \(1\) dinyatakan sebagai:

\[ F_{\mathrm{enc},a,b}^{(1)} = \sum_{u=1}^{3} \sum_{v=1}^{3} W_{\mathrm{enc},u,v}^{(1)} X_{\mathrm{pad},2a+u-2,\,2b+v-2}^{0,0}, \]

dengan \(a,b=1,2,3\), sedangkan \(u\) dan \(v\) merupakan indeks baris dan kolom kernel.

Pada setiap posisi, kernel mencakup area berukuran \(3\times3\). Karena stride bernilai \(2\), kernel bergeser dua kolom ke kanan untuk menghitung elemen berikutnya pada baris keluaran yang sama. Setelah mencapai posisi terakhir pada baris tersebut, kernel kembali ke sisi kiri dan bergeser dua baris ke bawah.

  • Contoh Perhitungan Konvolusi:

1. Perhitungan elemen pada posisi \((1,1)\)

Untuk menghasilkan elemen pertama dari feature map keluaran, kernel ditempatkan pada area \(3\times3\) di pojok kiri atas matriks yang telah diberi zero padding.

Area feature map yang diproses adalah:

\[ \begin{bmatrix} 0.00 & 0.00 & 0.00\\ 0.00 & -2.33 & -1.21\\ 0.00 & -2.33 & -0.94 \end{bmatrix}. \]

Setiap elemen pada area tersebut dikalikan dengan bobot kernel yang bersesuaian, kemudian seluruh hasil perkalian dijumlahkan sebagai berikut:

\[ \begin{aligned} F_{\mathrm{enc},1,1}^{(1)} ={}& (0.00)(0) +(0.00)(0) +(0.00)(0)\\ &+(0.00)(0) +(-2.33)(1) +(-1.21)(0)\\ &+(0.00)(0) +(-2.33)(0) +(-0.94)(0)\\ ={}&-2.33. \end{aligned} \]

Dengan demikian, nilai elemen keluaran pada posisi \((1,1)\) adalah:

\[ X_{1,1}^{1,0} = F_{\mathrm{enc},1,1}^{(1)} = -2.33. \]

2. Perhitungan elemen pada posisi \((1,2)\)

Untuk menghitung elemen pada posisi \((1,2)\), kernel bergeser dua kolom ke kanan dari posisi sebelumnya karena stride yang digunakan bernilai \(2\).

Area feature map yang diproses adalah:

\[ \begin{bmatrix} 0.00 & 0.00 & 0.00\\ -1.21 & 1.55 & 0.91\\ -0.94 & 1.91 & 1.25 \end{bmatrix}. \]

Perhitungan konvolusi dilakukan menggunakan bobot kernel yang sama:

\[ \begin{aligned} F_{\mathrm{enc},1,2}^{(1)} ={}& (0.00)(0) +(0.00)(0) +(0.00)(0)\\ &+(-1.21)(0) +(1.55)(1) +(0.91)(0)\\ &+(-0.94)(0) +(1.91)(0) +(1.25)(0)\\ ={}&1.55. \end{aligned} \]

Dengan demikian, nilai elemen keluaran pada posisi \((1,2)\) adalah:

\[ X_{1,2}^{1,0} = F_{\mathrm{enc},1,2}^{(1)} = 1.55. \]

Prosedur yang sama diterapkan pada seluruh posisi kernel. Setiap elemen keluaran diperoleh melalui penjumlahan hasil perkalian elemen pada area konvolusi dengan bobot kernel yang bersesuaian.

Dengan menerapkan operasi strided convolution pada seluruh posisi, diperoleh feature map encoder pertama berukuran \(3\times3\), yaitu:

\[ \mathbf{X}^{1,0} = \begin{bmatrix} -2.33 & 1.55 & -1.76\\ -2.33 & 1.92 & -1.62\\ -2.19 & 0.58 & -1.91 \end{bmatrix}. \]

Hasil tersebut menunjukkan bahwa operasi strided convolution dengan stride \(2\) mengurangi ukuran spasial feature map dari \(5\times5\) menjadi \(3\times3\). Pada ilustrasi ini, penyederhanaan bobot kernel menyebabkan setiap elemen keluaran sama dengan elemen masukan yang berada pada posisi pusat kernel. Namun, pada implementasi model sebenarnya, bobot kernel dipelajari selama pelatihan sehingga keluaran konvolusi merupakan kombinasi berbobot dari elemen-elemen pada area yang diproses.

b. Downsampling encoder kedua \(\left(\mathbf{X}^{2,0}\right)\)

Feature map \(\mathbf{X}^{1,0}\) berukuran \(3\times3\) kembali diproses menggunakan strided convolution dengan kernel \(3\times3\), stride \(2\), dan zero padding sebesar \(1\) pada setiap sisi. Pada ilustrasi ini, operasi konvolusi dilakukan tanpa bias. Keluaran konvolusi pada tahap kedua dinotasikan sebagai \(\mathbf{F}_{\mathrm{enc}}^{(2)}\), dengan:

\[ \mathbf{X}^{2,0} = \mathbf{F}_{\mathrm{enc}}^{(2)}. \]

  • Penambahan Zero Padding:

Sebelum operasi strided convolution dilakukan, satu lapisan nilai nol ditambahkan pada keempat sisi feature map masukan, yaitu sisi atas, bawah, kiri, dan kanan. Penambahan zero padding memungkinkan kernel mencakup area tepi matriks selama proses konvolusi.

Matriks feature map masukan merupakan hasil downsampling encoder pertama, yaitu:

\[ \mathbf{X}^{1,0} = \begin{bmatrix} -2.33 & 1.55 & -1.76\\ -2.33 & 1.92 & -1.62\\ -2.19 & 0.58 & -1.91 \end{bmatrix}. \]

Setelah penambahan zero padding sebesar satu piksel pada setiap sisi, ukuran matriks berubah dari \(3\times3\) menjadi \(5\times5\), yaitu:

\[ \mathbf{X}_{\mathrm{pad}}^{1,0} = \begin{bmatrix} 0.00 & 0.00 & 0.00 & 0.00 & 0.00\\ 0.00 & -2.33 & 1.55 & -1.76 & 0.00\\ 0.00 & -2.33 & 1.92 & -1.62 & 0.00\\ 0.00 & -2.19 & 0.58 & -1.91 & 0.00\\ 0.00 & 0.00 & 0.00 & 0.00 & 0.00 \end{bmatrix}. \]

  • Kernel Encoder Kedua:

Pada ilustrasi ini, kernel kedua disederhanakan dengan hanya elemen tengah bernilai satu dan elemen lainnya bernilai nol:

\[ \mathbf{W}_{\mathrm{enc}}^{(2)} = \begin{bmatrix} 0 & 0 & 0\\ 0 & 1 & 0\\ 0 & 0 & 0 \end{bmatrix}. \]

Kernel tersebut digunakan untuk mengilustrasikan operasi strided convolution pada tahap kedua. Pada setiap posisi, sembilan elemen dalam area konvolusi dikalikan dengan sembilan bobot kernel yang bersesuaian, kemudian seluruh hasil perkalian dijumlahkan.

Karena hanya bobot pusat kernel yang bernilai satu, hasil konvolusi pada ilustrasi ini ditentukan oleh elemen yang berada tepat di bawah pusat kernel. Penggunaan stride sebesar \(2\) menyebabkan kernel bergeser dua posisi pada setiap perpindahan.

Ukuran keluaran dihitung menggunakan:

\[ \begin{aligned} o &= \left\lfloor \frac{i+2p-k}{s} \right\rfloor+1\\ &= \left\lfloor \frac{3+2(1)-3}{2} \right\rfloor+1\\ &= \left\lfloor \frac{2}{2} \right\rfloor+1\\ &=2. \end{aligned} \]

Dengan demikian, ukuran spasial feature map berubah dari \(3\times3\) menjadi \(2\times2\).

  • Rumus:

Secara umum, operasi strided convolution pada tahap kedua dengan kernel \(3\times3\), stride \(2\), dan padding \(1\) dinyatakan sebagai:

\[ F_{\mathrm{enc},a,b}^{(2)} = \sum_{u=1}^{3} \sum_{v=1}^{3} W_{\mathrm{enc},u,v}^{(2)} X_{\mathrm{pad},2a+u-2,\,2b+v-2}^{1,0}, \]

dengan \(a,b=1,2\), sedangkan \(u\) dan \(v\) merupakan indeks baris dan kolom kernel.

Pada setiap posisi, kernel mencakup area berukuran \(3\times3\). Karena stride bernilai \(2\), kernel bergeser dua kolom ke kanan untuk menghitung elemen berikutnya pada baris keluaran yang sama. Setelah mencapai posisi terakhir pada baris tersebut, kernel kembali ke sisi kiri dan bergeser dua baris ke bawah.

Karena hanya bobot pusat kernel yang bernilai satu, persamaan tersebut dapat disederhanakan menjadi:

\[ X_{a,b}^{2,0} = F_{\mathrm{enc},a,b}^{(2)} = X_{2a-1,\,2b-1}^{1,0}. \]

  • Contoh Perhitungan Konvolusi:

1. Perhitungan elemen pada posisi \((1,1)\)

Untuk menghasilkan elemen pertama dari feature map keluaran, kernel ditempatkan pada area \(3\times3\) di pojok kiri atas matriks yang telah diberi zero padding.

Area feature map yang diproses adalah:

\[ \begin{bmatrix} 0.00 & 0.00 & 0.00\\ 0.00 & -2.33 & 1.55\\ 0.00 & -2.33 & 1.92 \end{bmatrix}. \]

Setiap elemen pada area tersebut dikalikan dengan bobot kernel yang bersesuaian, kemudian seluruh hasil perkalian dijumlahkan sebagai berikut:

\[ \begin{aligned} F_{\mathrm{enc},1,1}^{(2)} ={}& (0.00)(0) +(0.00)(0) +(0.00)(0)\\ &+(0.00)(0) +(-2.33)(1) +(1.55)(0)\\ &+(0.00)(0) +(-2.33)(0) +(1.92)(0)\\ ={}&-2.33. \end{aligned} \]

Dengan demikian, nilai elemen keluaran pada posisi \((1,1)\) adalah:

\[ X_{1,1}^{2,0} = F_{\mathrm{enc},1,1}^{(2)} = -2.33. \]

2. Perhitungan elemen pada posisi \((1,2)\)

Untuk menghitung elemen pada posisi \((1,2)\), kernel bergeser dua kolom ke kanan dari posisi sebelumnya karena stride yang digunakan bernilai \(2\).

Area feature map yang diproses adalah:

\[ \begin{bmatrix} 0.00 & 0.00 & 0.00\\ 1.55 & -1.76 & 0.00\\ 1.92 & -1.62 & 0.00 \end{bmatrix}. \]

Perhitungan konvolusi dilakukan menggunakan bobot kernel yang sama:

\[ \begin{aligned} F_{\mathrm{enc},1,2}^{(2)} ={}& (0.00)(0) +(0.00)(0) +(0.00)(0)\\ &+(1.55)(0) +(-1.76)(1) +(0.00)(0)\\ &+(1.92)(0) +(-1.62)(0) +(0.00)(0)\\ ={}&-1.76. \end{aligned} \]

Dengan demikian, nilai elemen keluaran pada posisi \((1,2)\) adalah:

\[ X_{1,2}^{2,0} = F_{\mathrm{enc},1,2}^{(2)} = -1.76. \]

Prosedur yang sama diterapkan pada seluruh posisi kernel. Setiap elemen keluaran diperoleh melalui penjumlahan hasil perkalian elemen pada area konvolusi dengan bobot kernel yang bersesuaian.

Dengan menerapkan operasi strided convolution pada seluruh posisi, diperoleh feature map encoder kedua berukuran \(2\times2\), yaitu:

\[ \mathbf{X}^{2,0} = \begin{bmatrix} -2.33 & -1.76\\ -2.19 & -1.91 \end{bmatrix}. \]

Hasil tersebut menunjukkan bahwa operasi strided convolution dengan stride \(2\) mengurangi ukuran spasial feature map dari \(3\times3\) menjadi \(2\times2\). Pada ilustrasi ini, penyederhanaan bobot kernel menyebabkan setiap elemen keluaran sama dengan elemen masukan yang berada pada posisi pusat kernel. Namun, pada implementasi model sebenarnya, bobot kernel dipelajari selama pelatihan sehingga keluaran konvolusi merupakan kombinasi berbobot dari elemen-elemen pada area yang diproses.

6. Decoder UNet++

Decoder UNet++ mengembalikan ukuran spasial feature map secara bertahap melalui operasi upsampling. Pada ilustrasi perhitungan manual ini, upsampling dilakukan menggunakan interpolasi bilinear. Selanjutnya, feature map dari jalur encoder dan node decoder sebelumnya digabungkan pada dimensi kanal melalui operasi \(\operatorname{Concat}\).

Untuk menyederhanakan perhitungan manual, operasi pengolahan fitur pada setiap node decoder direpresentasikan menggunakan konvolusi \(1\times1\) tanpa bias yang diikuti fungsi aktivasi ReLU. Bobot konvolusi yang digunakan merupakan parameter ilustratif dan bukan bobot hasil pelatihan model.

a. Upsampling \(\mathbf{X}^{2,0}\) dan Node Decoder \(\mathbf{X}^{1,1}\)

Feature map encoder kedua \(\mathbf{X}^{2,0}\) berukuran \(2\times2\) diperbesar menjadi \(3\times3\) menggunakan interpolasi bilinear. Proses ini bertujuan untuk menyesuaikan ukuran spasial feature map sehingga dapat digabungkan dengan \(\mathbf{X}^{1,0}\) melalui nested skip connection.

Matriks feature map masukan adalah:

\[ \mathbf{X}^{2,0} = \begin{bmatrix} -2.33 & -1.76\\ -2.19 & -1.91 \end{bmatrix}. \]

  • Rumus interpolasi bilinear:

Interpolasi bilinear menentukan nilai keluaran berdasarkan jarak terhadap elemen-elemen pada feature map masukan. Elemen yang lebih dekat dengan posisi keluaran memiliki bobot lebih besar, sedangkan elemen yang berjarak satu satuan atau lebih pada salah satu arah memiliki bobot nol.

Pada feature map satu kanal, interpolasi bilinear dinyatakan sebagai:

\[ \left[ \operatorname{Up} \left( \mathbf{X}^{2,0} \right) \right]_{r,c} = \sum_{n=1}^{2} \sum_{m=1}^{2} X_{n,m}^{2,0} \max \left( 0, 1-\left|x_c-m\right| \right) \max \left( 0, 1-\left|y_r-n\right| \right). \]

Pada persamaan tersebut, \(r\) dan \(c\) menyatakan indeks baris dan kolom pada feature map keluaran, sedangkan \(n\) dan \(m\) menyatakan indeks baris dan kolom pada feature map masukan. Koordinat \(x_c\) menunjukkan posisi horizontal atau arah kolom, sedangkan \(y_r\) menunjukkan posisi vertikal atau arah baris.

Untuk mempermudah penjabaran, bobot interpolasi pada setiap elemen masukan dinotasikan sebagai:

\[ w_{n,m}^{(r,c)} = \max \left( 0, 1-\left|x_c-m\right| \right) \max \left( 0, 1-\left|y_r-n\right| \right). \]

Dengan demikian, rumus interpolasi bilinear dapat dituliskan sebagai:

\[ \left[ \operatorname{Up} \left( \mathbf{X}^{2,0} \right) \right]_{r,c} = \sum_{n=1}^{2} \sum_{m=1}^{2} w_{n,m}^{(r,c)}X_{n,m}^{2,0}. \]

  • Penentuan koordinat interpolasi:

Pada ilustrasi ini, koordinat matriks masukan menggunakan indeks yang dimulai dari \(1\). Karena ukuran feature map masukan adalah \(2\times2\) dan ukuran keluaran adalah \(3\times3\), koordinat interpolasi ditentukan sebagai:

\[ x_c = 1+(c-1)\frac{2-1}{3-1} = 1+\frac{c-1}{2}, \]

\[ y_r = 1+(r-1)\frac{2-1}{3-1} = 1+\frac{r-1}{2}, \]

dengan \(r,c=1,2,3\).

Angka \(1\) menunjukkan koordinat awal karena indeks matriks dimulai dari \(1\), sedangkan pembagian dengan \(2\) menunjukkan bahwa jarak antara dua koordinat masukan dibagi menjadi dua interval yang sama panjang.

Nilai koordinat yang diperoleh adalah:

Indeks keluaran Nilai koordinat
\(1\) \(1\)
\(2\) \(1.5\)
\(3\) \(2\)

Dengan demikian, koordinat interpolasi pada matriks keluaran dapat dituliskan sebagai:

\[ \begin{bmatrix} (1,1) & (1,1.5) & (1,2)\\ (1.5,1) & (1.5,1.5) & (1.5,2)\\ (2,1) & (2,1.5) & (2,2) \end{bmatrix}. \]

Setiap pasangan koordinat dituliskan dalam urutan \((y_r,x_c)\). Pada posisi sudut, nilai keluaran sama dengan nilai masukan karena koordinatnya berimpit. Sementara itu, posisi tengah sisi diperoleh dari dua elemen masukan, sedangkan posisi tengah matriks diperoleh dari empat elemen masukan.

  • Contoh perhitungan interpolasi bilinear pada posisi \((1,2)\):

Pada posisi \((1,2)\), koordinat interpolasi diperoleh sebagai berikut:

\[ y_1=1, \qquad x_2=1.5. \]

Posisi tersebut berada tepat di tengah antara kolom pertama dan kolom kedua pada baris pertama. Bobot interpolasi untuk elemen \(X_{1,1}^{2,0}\) dihitung sebagai:

\[ \begin{aligned} w_{1,1}^{(1,2)} &= \max(0,1-|1.5-1|) \max(0,1-|1-1|)\\ &= 0.5\times1\\ &= 0.5. \end{aligned} \]

Sementara itu, bobot untuk elemen \(X_{1,2}^{2,0}\) adalah:

\[ \begin{aligned} w_{1,2}^{(1,2)} &= \max(0,1-|1.5-2|) \max(0,1-|1-1|)\\ &= 0.5\times1\\ &= 0.5. \end{aligned} \]

Kedua elemen pada baris kedua memiliki bobot nol karena jarak vertikalnya terhadap posisi keluaran adalah satu satuan. Dengan demikian:

\[ w_{1,1}^{(1,2)} = w_{1,2}^{(1,2)} = 0.5, \qquad w_{2,1}^{(1,2)} = w_{2,2}^{(1,2)} = 0. \]

Dengan memasukkan bobot tersebut ke dalam rumus interpolasi bilinear, diperoleh:

\[ \begin{aligned} \left[ \operatorname{Up} \left( \mathbf{X}^{2,0} \right) \right]_{1,2} &= 0.5X_{1,1}^{2,0} + 0.5X_{1,2}^{2,0}\\ &= \frac{ X_{1,1}^{2,0} + X_{1,2}^{2,0} }{2}\\ &= \frac{-2.33-1.76}{2}\\ &= -2.045\\ &\approx -2.05. \end{aligned} \]

  • Contoh perhitungan interpolasi bilinear pada posisi tengah \((2,2)\):

Pada posisi \((2,2)\), koordinat interpolasi diperoleh sebagai berikut:

\[ y_2=1.5, \qquad x_2=1.5. \]

Posisi tersebut berada tepat di tengah empat elemen matriks masukan. Bobot interpolasi untuk elemen \(X_{1,1}^{2,0}\) dihitung sebagai:

\[ \begin{aligned} w_{1,1}^{(2,2)} &= \max(0,1-|1.5-1|) \max(0,1-|1.5-1|)\\ &= 0.5\times0.5\\ &= 0.25. \end{aligned} \]

Karena posisi tengah berjarak sama dari keempat elemen masukan, maka:

\[ w_{1,1}^{(2,2)} = w_{1,2}^{(2,2)} = w_{2,1}^{(2,2)} = w_{2,2}^{(2,2)} = 0.25. \]

Dengan demikian, rumus interpolasi bilinear menjadi:

\[ \begin{aligned} \left[ \operatorname{Up} \left( \mathbf{X}^{2,0} \right) \right]_{2,2} &= 0.25X_{1,1}^{2,0} + 0.25X_{1,2}^{2,0}\\ &\quad+ 0.25X_{2,1}^{2,0} + 0.25X_{2,2}^{2,0}\\ &= \frac{ X_{1,1}^{2,0} + X_{1,2}^{2,0} + X_{2,1}^{2,0} + X_{2,2}^{2,0} }{4}\\ &= \frac{-2.33-1.76-2.19-1.91}{4}\\ &= -2.0475\\ &\approx -2.05. \end{aligned} \]

Dengan menerapkan interpolasi bilinear pada seluruh posisi keluaran, diperoleh feature map hasil upsampling berukuran \(3\times3\), yaitu:

\[ \operatorname{Up} \left( \mathbf{X}^{2,0} \right) = \begin{bmatrix} -2.33 & -2.05 & -1.76\\ -2.26 & -2.05 & -1.84\\ -2.19 & -2.05 & -1.91 \end{bmatrix}. \]

Hasil tersebut menunjukkan bahwa interpolasi bilinear mempertahankan nilai pada posisi sudut dan menghitung nilai pada posisi lainnya berdasarkan bobot jarak terhadap elemen masukan. Nilai hasil interpolasi ditampilkan hingga dua angka desimal.

  • Rumus node decoder:

Sesuai dengan persamaan UNet++, nested skip connection pada node decoder pertama dirumuskan sebagai:

\[ \mathbf{X}^{1,1} = H^{(1,1)} \left( \operatorname{Concat} \left[ \mathbf{X}^{1,0}, \operatorname{Up} \left( \mathbf{X}^{2,0} \right) \right] \right). \]

Pada persamaan tersebut, \(H^{(1,1)}\) menyatakan operasi pengolahan fitur pada node decoder \(\mathbf{X}^{1,1}\). Dalam ilustrasi perhitungan manual ini, operasi tersebut disederhanakan menggunakan konvolusi \(1\times1\) tanpa bias yang diikuti fungsi aktivasi ReLU.

Karena kedua feature map yang digabungkan berukuran \(3\times3\) dan masing-masing direpresentasikan oleh satu kanal, hasil Concat memiliki dua kanal. Satu filter konvolusi \(1\times1\) digunakan untuk menggabungkan kedua kanal tersebut menjadi satu kanal keluaran.

Pada ilustrasi ini, bobot kernel ditentukan sebagai:

\[ W_{\mathrm{dec},1}^{(1,1)}=[1.00], \qquad W_{\mathrm{dec},2}^{(1,1)}=[0.20]. \]

Bobot pertama diterapkan pada \(\mathbf{X}^{1,0}\), sedangkan bobot kedua diterapkan pada \(\operatorname{Up}(\mathbf{X}^{2,0})\).

Dengan demikian, untuk setiap posisi spasial \((r,c)\), keluaran node decoder dihitung sebagai:

\[ X_{r,c}^{1,1} = \operatorname{ReLU} \left( W_{\mathrm{dec},1}^{(1,1)}X_{r,c}^{1,0} + W_{\mathrm{dec},2}^{(1,1)} \left[ \operatorname{Up} \left( \mathbf{X}^{2,0} \right) \right]_{r,c} \right). \]

  • Contoh perhitungan node decoder pada posisi \((1,2)\):

\[ \begin{aligned} X_{1,2}^{1,1} &= \operatorname{ReLU} \left( W_{\mathrm{dec},1}^{(1,1)}X_{1,2}^{1,0} + W_{\mathrm{dec},2}^{(1,1)} \left[ \operatorname{Up} \left( \mathbf{X}^{2,0} \right) \right]_{1,2} \right)\\ &= \operatorname{ReLU} \left( 1.00(1.55) + 0.20(-2.05) \right)\\ &= \operatorname{ReLU}(1.14)\\ &= 1.14. \end{aligned} \]

Dengan menerapkan operasi yang sama pada seluruh posisi spasial, diperoleh feature map node decoder pertama sebagai berikut:

\[ \mathbf{X}^{1,1} = \begin{bmatrix} 0.00 & 1.14 & 0.00\\ 0.00 & 1.51 & 0.00\\ 0.00 & 0.17 & 0.00 \end{bmatrix}. \]

Hasil tersebut menunjukkan bahwa feature map hasil upsampling digabungkan dengan feature map dari jalur encoder melalui nested skip connection. Pada ilustrasi ini, penggabungan dilakukan menggunakan Concat, konvolusi \(1\times1\), dan fungsi aktivasi ReLU. Feature map \(\mathbf{X}^{1,1}\) selanjutnya digunakan pada pembentukan node decoder berikutnya.

b. Upsampling \(\mathbf{X}^{1,0}\) dan Nested Skip Pertama \(\mathbf{X}^{0,1}\)

Feature map encoder pertama \(\mathbf{X}^{1,0}\) berukuran \(3\times3\) diperbesar menjadi \(5\times5\) menggunakan interpolasi bilinear. Proses ini bertujuan untuk menyesuaikan ukuran spasial feature map sehingga dapat digabungkan dengan \(\mathbf{X}^{0,0}\) melalui nested skip connection.

Matriks feature map masukan adalah:

\[ \mathbf{X}^{1,0} = \begin{bmatrix} -2.33 & 1.55 & -1.76\\ -2.33 & 1.92 & -1.62\\ -2.19 & 0.58 & -1.91 \end{bmatrix}. \]

  • Rumus interpolasi bilinear:

Interpolasi bilinear dilakukan menggunakan prinsip yang sama seperti pada subbagian sebelumnya. Nilai keluaran dihitung berdasarkan jarak terhadap elemen-elemen pada feature map masukan.

Pada feature map satu kanal, rumus interpolasi bilinear dinyatakan sebagai:

\[ \left[ \operatorname{Up} \left( \mathbf{X}^{1,0} \right) \right]_{r,c} = \sum_{n=1}^{3} \sum_{m=1}^{3} X_{n,m}^{1,0} \max \left( 0, 1-\left|x_c-m\right| \right) \max \left( 0, 1-\left|y_r-n\right| \right). \]

Pada persamaan tersebut, \(r\) dan \(c\) menyatakan indeks baris dan kolom pada feature map keluaran, sedangkan \(n\) dan \(m\) menyatakan indeks baris dan kolom pada feature map masukan. Koordinat \(x_c\) menunjukkan posisi horizontal atau arah kolom, sedangkan \(y_r\) menunjukkan posisi vertikal atau arah baris.

Bobot interpolasi pada setiap elemen masukan dinyatakan sebagai:

\[ w_{n,m}^{(r,c)} = \max \left( 0, 1-\left|x_c-m\right| \right) \max \left( 0, 1-\left|y_r-n\right| \right). \]

Dengan demikian, rumus interpolasi bilinear dapat dituliskan sebagai:

\[ \left[ \operatorname{Up} \left( \mathbf{X}^{1,0} \right) \right]_{r,c} = \sum_{n=1}^{3} \sum_{m=1}^{3} w_{n,m}^{(r,c)}X_{n,m}^{1,0}. \]

  • Penentuan koordinat interpolasi:

Pada ilustrasi ini, koordinat matriks menggunakan indeks yang dimulai dari \(1\). Karena ukuran feature map masukan adalah \(3\times3\) dan ukuran keluaran adalah \(5\times5\), koordinat interpolasi ditentukan sebagai:

\[ x_c = 1+(c-1)\frac{3-1}{5-1} = 1+\frac{c-1}{2}, \]

\[ y_r = 1+(r-1)\frac{3-1}{5-1} = 1+\frac{r-1}{2}, \]

dengan \(r,c=1,2,3,4,5\).

Angka \(1\) menunjukkan koordinat awal matriks masukan, sedangkan pembagian dengan \(2\) menunjukkan bahwa setiap interval antara dua koordinat masukan dibagi menjadi dua bagian yang sama panjang.

Nilai koordinat yang diperoleh adalah:

Indeks keluaran Nilai koordinat
\(1\) \(1\)
\(2\) \(1.5\)
\(3\) \(2\)
\(4\) \(2.5\)
\(5\) \(3\)

Dengan demikian, nilai pada posisi keluaran yang berimpit dengan koordinat masukan dipertahankan, sedangkan nilai pada posisi lainnya dihitung berdasarkan bobot jarak terhadap elemen-elemen masukan di sekitarnya.

  • Contoh perhitungan interpolasi bilinear pada posisi \((1,2)\):

Pada posisi \((1,2)\), koordinat interpolasi diperoleh sebagai berikut:

\[ y_1=1, \qquad x_2=1.5. \]

Posisi tersebut berada tepat di tengah antara kolom pertama dan kolom kedua pada baris pertama. Bobot interpolasi untuk elemen \(X_{1,1}^{1,0}\) dihitung sebagai:

\[ \begin{aligned} w_{1,1}^{(1,2)} &= \max(0,1-|1.5-1|) \max(0,1-|1-1|)\\ &= 0.5\times1\\ &= 0.5. \end{aligned} \]

Sementara itu, bobot untuk elemen \(X_{1,2}^{1,0}\) adalah:

\[ \begin{aligned} w_{1,2}^{(1,2)} &= \max(0,1-|1.5-2|) \max(0,1-|1-1|)\\ &= 0.5\times1\\ &= 0.5. \end{aligned} \]

Elemen lainnya memiliki bobot nol karena berada di luar jarak interpolasi pada posisi tersebut. Dengan demikian:

\[ w_{1,1}^{(1,2)} = w_{1,2}^{(1,2)} = 0.5. \]

Dengan memasukkan bobot tersebut ke dalam rumus interpolasi bilinear, diperoleh:

\[ \begin{aligned} \left[ \operatorname{Up} \left( \mathbf{X}^{1,0} \right) \right]_{1,2} &= 0.5X_{1,1}^{1,0} + 0.5X_{1,2}^{1,0}\\ &= \frac{ X_{1,1}^{1,0} + X_{1,2}^{1,0} }{2}\\ &= \frac{-2.33+1.55}{2}\\ &= -0.39. \end{aligned} \]

  • Contoh perhitungan interpolasi bilinear pada posisi \((2,2)\):

Pada posisi \((2,2)\), koordinat interpolasi diperoleh sebagai berikut:

\[ y_2=1.5, \qquad x_2=1.5. \]

Posisi tersebut berada tepat di tengah empat elemen masukan, yaitu \(X_{1,1}^{1,0}\), \(X_{1,2}^{1,0}\), \(X_{2,1}^{1,0}\), dan \(X_{2,2}^{1,0}\).

Bobot interpolasi untuk elemen \(X_{1,1}^{1,0}\) dihitung sebagai:

\[ \begin{aligned} w_{1,1}^{(2,2)} &= \max(0,1-|1.5-1|) \max(0,1-|1.5-1|)\\ &= 0.5\times0.5\\ &= 0.25. \end{aligned} \]

Karena posisi tersebut berjarak sama dari keempat elemen masukan, maka:

\[ w_{1,1}^{(2,2)} = w_{1,2}^{(2,2)} = w_{2,1}^{(2,2)} = w_{2,2}^{(2,2)} = 0.25. \]

Dengan demikian, rumus interpolasi bilinear menjadi:

\[ \begin{aligned} \left[ \operatorname{Up} \left( \mathbf{X}^{1,0} \right) \right]_{2,2} &= 0.25X_{1,1}^{1,0} + 0.25X_{1,2}^{1,0}\\ &\quad+ 0.25X_{2,1}^{1,0} + 0.25X_{2,2}^{1,0}\\ &= \frac{ X_{1,1}^{1,0} + X_{1,2}^{1,0} + X_{2,1}^{1,0} + X_{2,2}^{1,0} }{4}\\ &= \frac{-2.33+1.55-2.33+1.92}{4}\\ &= -0.2975\\ &\approx-0.30. \end{aligned} \]

Dengan menerapkan interpolasi bilinear pada seluruh posisi keluaran, diperoleh feature map hasil upsampling berukuran \(5\times5\), yaitu:

\[ \operatorname{Up} \left( \mathbf{X}^{1,0} \right) = \begin{bmatrix} -2.33 & -0.39 & 1.55 & -0.11 & -1.76\\ -2.33 & -0.30 & 1.73 & 0.02 & -1.69\\ -2.33 & -0.21 & 1.92 & 0.15 & -1.62\\ -2.26 & -0.51 & 1.25 & -0.26 & -1.77\\ -2.19 & -0.81 & 0.58 & -0.67 & -1.91 \end{bmatrix}. \]

Hasil tersebut menunjukkan bahwa interpolasi bilinear memperbesar ukuran spasial feature map dari \(3\times3\) menjadi \(5\times5\). Nilai pada posisi yang berimpit dengan koordinat masukan dipertahankan, sedangkan nilai pada posisi lainnya dihitung menggunakan bobot interpolasi berdasarkan jarak terhadap elemen masukan.

  • Rumus node decoder:

Sesuai dengan persamaan UNet++, nested skip connection pertama pada node decoder dirumuskan sebagai:

\[ \mathbf{X}^{0,1} = H^{(0,1)} \left( \operatorname{Concat} \left[ \mathbf{X}^{0,0}, \operatorname{Up} \left( \mathbf{X}^{1,0} \right) \right] \right). \]

Pada persamaan tersebut, \(H^{(0,1)}\) menyatakan operasi pengolahan fitur pada node decoder \(\mathbf{X}^{0,1}\). Dalam ilustrasi perhitungan manual ini, operasi tersebut disederhanakan menggunakan konvolusi \(1\times1\) tanpa bias yang diikuti fungsi aktivasi ReLU.

Karena kedua feature map yang digabungkan berukuran \(5\times5\) dan masing-masing direpresentasikan oleh satu kanal, hasil Concat memiliki dua kanal. Satu filter konvolusi \(1\times1\) digunakan untuk menggabungkan kedua kanal tersebut menjadi satu kanal keluaran.

Pada ilustrasi ini, bobot kernel ditentukan sebagai:

\[ W_{\mathrm{dec},1}^{(0,1)}=[1.00], \qquad W_{\mathrm{dec},2}^{(0,1)}=[1.00]. \]

Bobot pertama diterapkan pada \(\mathbf{X}^{0,0}\), sedangkan bobot kedua diterapkan pada \(\operatorname{Up}(\mathbf{X}^{1,0})\).

Dengan demikian, untuk setiap posisi spasial \((r,c)\), keluaran node decoder dihitung sebagai:

\[ X_{r,c}^{0,1} = \operatorname{ReLU} \left( W_{\mathrm{dec},1}^{(0,1)}X_{r,c}^{0,0} + W_{\mathrm{dec},2}^{(0,1)} \left[ \operatorname{Up} \left( \mathbf{X}^{1,0} \right) \right]_{r,c} \right). \]

  • Contoh perhitungan node decoder pada posisi \((2,2)\):

\[ \begin{aligned} X_{2,2}^{0,1} &= \operatorname{ReLU} \left( W_{\mathrm{dec},1}^{(0,1)}X_{2,2}^{0,0} + W_{\mathrm{dec},2}^{(0,1)} \left[ \operatorname{Up} \left( \mathbf{X}^{1,0} \right) \right]_{2,2} \right)\\ &= \operatorname{ReLU} \left( 1.00(-2.33) + 1.00(-0.30) \right)\\ &= \operatorname{ReLU}(-2.63)\\ &= 0.00. \end{aligned} \]

  • Contoh perhitungan node decoder pada posisi \((2,3)\):

\[ \begin{aligned} X_{2,3}^{0,1} &= \operatorname{ReLU} \left( W_{\mathrm{dec},1}^{(0,1)}X_{2,3}^{0,0} + W_{\mathrm{dec},2}^{(0,1)} \left[ \operatorname{Up} \left( \mathbf{X}^{1,0} \right) \right]_{2,3} \right)\\ &= \operatorname{ReLU} \left( 1.00(1.91) + 1.00(1.73) \right)\\ &= \operatorname{ReLU}(3.64)\\ &= 3.64. \end{aligned} \]

Dengan menerapkan operasi yang sama pada seluruh posisi spasial, diperoleh feature map node decoder sebagai berikut:

\[ \mathbf{X}^{0,1} = \begin{bmatrix} 0.00 & 0.00 & 3.09 & 0.80 & 0.00\\ 0.00 & 0.00 & 3.64 & 1.26 & 0.00\\ 0.00 & 0.00 & 3.83 & 1.39 & 0.00\\ 0.00 & 0.00 & 2.78 & 0.62 & 0.00\\ 0.00 & 0.00 & 1.16 & 0.00 & 0.00 \end{bmatrix}. \]

Hasil tersebut menunjukkan bahwa node \(\mathbf{X}^{0,1}\) menggabungkan informasi dari feature map encoder \(\mathbf{X}^{0,0}\) dan hasil upsampling \(\mathbf{X}^{1,0}\) melalui nested skip connection. Pada ilustrasi ini, penggabungan dilakukan menggunakan Concat, konvolusi \(1\times1\), dan fungsi aktivasi ReLU. Feature map \(\mathbf{X}^{0,1}\) selanjutnya digunakan pada pembentukan node decoder berikutnya.

c. Upsampling \(\mathbf{X}^{1,1}\) dan Nested Skip Kedua \(\mathbf{X}^{0,2}\)

Node decoder \(\mathbf{X}^{1,1}\) berukuran \(3\times3\) diperbesar menjadi \(5\times5\) menggunakan interpolasi bilinear. Proses ini bertujuan untuk menyesuaikan ukuran spasial feature map sehingga dapat digabungkan dengan \(\mathbf{X}^{0,0}\) dan \(\mathbf{X}^{0,1}\) melalui nested skip connection.

Matriks feature map masukan adalah:

\[ \mathbf{X}^{1,1} = \begin{bmatrix} 0.00 & 1.14 & 0.00\\ 0.00 & 1.51 & 0.00\\ 0.00 & 0.17 & 0.00 \end{bmatrix}. \]

  • Rumus interpolasi bilinear:

Interpolasi bilinear dilakukan dengan menentukan nilai keluaran berdasarkan jarak terhadap elemen-elemen pada feature map masukan.

Pada feature map satu kanal, rumus interpolasi bilinear dinyatakan sebagai:

\[ \left[ \operatorname{Up} \left( \mathbf{X}^{1,1} \right) \right]_{r,c} = \sum_{n=1}^{3} \sum_{m=1}^{3} X_{n,m}^{1,1} \max \left( 0, 1-\left|x_c-m\right| \right) \max \left( 0, 1-\left|y_r-n\right| \right). \]

Pada persamaan tersebut, \(r\) dan \(c\) menyatakan indeks baris dan kolom pada feature map keluaran, sedangkan \(n\) dan \(m\) menyatakan indeks baris dan kolom pada feature map masukan. Koordinat \(x_c\) menunjukkan posisi horizontal atau arah kolom, sedangkan \(y_r\) menunjukkan posisi vertikal atau arah baris.

Bobot interpolasi pada setiap elemen masukan dinyatakan sebagai:

\[ w_{n,m}^{(r,c)} = \max \left( 0, 1-\left|x_c-m\right| \right) \max \left( 0, 1-\left|y_r-n\right| \right). \]

Dengan demikian, rumus interpolasi bilinear dapat dituliskan sebagai:

\[ \left[ \operatorname{Up} \left( \mathbf{X}^{1,1} \right) \right]_{r,c} = \sum_{n=1}^{3} \sum_{m=1}^{3} w_{n,m}^{(r,c)}X_{n,m}^{1,1}. \]

  • Penentuan koordinat interpolasi:

Pada ilustrasi ini, koordinat matriks menggunakan indeks yang dimulai dari \(1\). Karena ukuran feature map masukan adalah \(3\times3\) dan ukuran keluaran adalah \(5\times5\), koordinat interpolasi ditentukan sebagai:

\[ x_c = 1+(c-1)\frac{3-1}{5-1} = 1+\frac{c-1}{2}, \]

\[ y_r = 1+(r-1)\frac{3-1}{5-1} = 1+\frac{r-1}{2}, \]

dengan \(r,c=1,2,3,4,5\).

Angka \(1\) menunjukkan koordinat awal matriks masukan, sedangkan pembagian dengan \(2\) menunjukkan bahwa setiap interval antara dua koordinat masukan dibagi menjadi dua bagian yang sama panjang.

Nilai koordinat yang diperoleh adalah:

Indeks keluaran Nilai koordinat
\(1\) \(1\)
\(2\) \(1.5\)
\(3\) \(2\)
\(4\) \(2.5\)
\(5\) \(3\)

Dengan demikian, nilai pada posisi keluaran yang berimpit dengan koordinat masukan dipertahankan, sedangkan nilai pada posisi lainnya dihitung berdasarkan bobot jarak terhadap elemen-elemen masukan di sekitarnya.

  • Contoh perhitungan interpolasi bilinear pada posisi \((2,2)\):

Pada posisi \((2,2)\), koordinat interpolasi diperoleh sebagai berikut:

\[ y_2=1.5, \qquad x_2=1.5. \]

Posisi tersebut berada tepat di tengah empat elemen masukan, yaitu \(X_{1,1}^{1,1}\), \(X_{1,2}^{1,1}\), \(X_{2,1}^{1,1}\), dan \(X_{2,2}^{1,1}\).

Bobot interpolasi untuk elemen \(X_{1,1}^{1,1}\) dihitung sebagai:

\[ \begin{aligned} w_{1,1}^{(2,2)} &= \max(0,1-|1.5-1|) \max(0,1-|1.5-1|)\\ &= 0.5\times0.5\\ &= 0.25. \end{aligned} \]

Karena posisi tersebut berjarak sama dari keempat elemen masukan, maka:

\[ w_{1,1}^{(2,2)} = w_{1,2}^{(2,2)} = w_{2,1}^{(2,2)} = w_{2,2}^{(2,2)} = 0.25. \]

Dengan demikian, rumus interpolasi bilinear menjadi:

\[ \begin{aligned} \left[ \operatorname{Up} \left( \mathbf{X}^{1,1} \right) \right]_{2,2} &= 0.25X_{1,1}^{1,1} + 0.25X_{1,2}^{1,1}\\ &\quad+ 0.25X_{2,1}^{1,1} + 0.25X_{2,2}^{1,1}\\ &= \frac{ X_{1,1}^{1,1} + X_{1,2}^{1,1} + X_{2,1}^{1,1} + X_{2,2}^{1,1} }{4}\\ &= \frac{0.00+1.14+0.00+1.51}{4}\\ &= 0.6625\\ &\approx0.66. \end{aligned} \]

  • Contoh perhitungan interpolasi bilinear pada posisi \((2,3)\):

Pada posisi \((2,3)\), koordinat interpolasi diperoleh sebagai berikut:

\[ y_2=1.5, \qquad x_3=2. \]

Posisi tersebut berada tepat di tengah secara vertikal antara baris pertama dan kedua, tetapi sejajar dengan kolom kedua. Oleh karena itu, hanya dua elemen pada kolom kedua yang memiliki bobot bukan nol.

Bobot interpolasi untuk elemen \(X_{1,2}^{1,1}\) dihitung sebagai:

\[ \begin{aligned} w_{1,2}^{(2,3)} &= \max(0,1-|2-2|) \max(0,1-|1.5-1|)\\ &= 1\times0.5\\ &= 0.5. \end{aligned} \]

Sementara itu, bobot untuk elemen \(X_{2,2}^{1,1}\) adalah:

\[ \begin{aligned} w_{2,2}^{(2,3)} &= \max(0,1-|2-2|) \max(0,1-|1.5-2|)\\ &= 1\times0.5\\ &= 0.5. \end{aligned} \]

Elemen lainnya memiliki bobot nol karena berada di luar jarak interpolasi pada posisi tersebut. Dengan demikian:

\[ w_{1,2}^{(2,3)} = w_{2,2}^{(2,3)} = 0.5. \]

Dengan memasukkan bobot tersebut ke dalam rumus interpolasi bilinear, diperoleh:

\[ \begin{aligned} \left[ \operatorname{Up} \left( \mathbf{X}^{1,1} \right) \right]_{2,3} &= 0.5X_{1,2}^{1,1} + 0.5X_{2,2}^{1,1}\\ &= \frac{ X_{1,2}^{1,1} + X_{2,2}^{1,1} }{2}\\ &= \frac{1.14+1.51}{2}\\ &= 1.325\\ &\approx1.32. \end{aligned} \]

Dengan menerapkan interpolasi bilinear pada seluruh posisi keluaran, diperoleh feature map hasil upsampling berukuran \(5\times5\), yaitu:

\[ \operatorname{Up} \left( \mathbf{X}^{1,1} \right) = \begin{bmatrix} 0.00 & 0.57 & 1.14 & 0.57 & 0.00\\ 0.00 & 0.66 & 1.32 & 0.66 & 0.00\\ 0.00 & 0.75 & 1.51 & 0.75 & 0.00\\ 0.00 & 0.42 & 0.84 & 0.42 & 0.00\\ 0.00 & 0.09 & 0.17 & 0.09 & 0.00 \end{bmatrix}. \]

Hasil tersebut menunjukkan bahwa interpolasi bilinear memperbesar ukuran spasial feature map dari \(3\times3\) menjadi \(5\times5\). Nilai pada posisi yang berimpit dengan koordinat masukan dipertahankan, sedangkan nilai pada posisi lainnya dihitung menggunakan bobot interpolasi berdasarkan jarak terhadap elemen masukan.

  • Rumus node decoder:

Sesuai dengan persamaan UNet++, nested skip connection kedua pada node decoder dirumuskan sebagai:

\[ \mathbf{X}^{0,2} = H^{(0,2)} \left( \operatorname{Concat} \left[ \mathbf{X}^{0,0}, \mathbf{X}^{0,1}, \operatorname{Up} \left( \mathbf{X}^{1,1} \right) \right] \right). \]

Pada persamaan tersebut, \(H^{(0,2)}\) menyatakan operasi pengolahan fitur pada node decoder \(\mathbf{X}^{0,2}\). Dalam ilustrasi perhitungan manual ini, operasi tersebut disederhanakan menggunakan konvolusi \(1\times1\) tanpa bias yang diikuti fungsi aktivasi ReLU.

Karena ketiga feature map yang digabungkan berukuran \(5\times5\) dan masing-masing direpresentasikan oleh satu kanal, hasil Concat memiliki tiga kanal. Satu filter konvolusi \(1\times1\) digunakan untuk menggabungkan ketiga kanal tersebut menjadi satu kanal keluaran.

Pada ilustrasi ini, bobot kernel ditentukan sebagai:

\[ W_{\mathrm{dec},1}^{(0,2)}=[0.25], \qquad W_{\mathrm{dec},2}^{(0,2)}=[0.50], \qquad W_{\mathrm{dec},3}^{(0,2)}=[0.25]. \]

Bobot pertama diterapkan pada \(\mathbf{X}^{0,0}\), bobot kedua diterapkan pada \(\mathbf{X}^{0,1}\), sedangkan bobot ketiga diterapkan pada \(\operatorname{Up}(\mathbf{X}^{1,1})\). Ketiga bobot tersebut merupakan parameter ilustratif untuk menyederhanakan perhitungan manual, bukan bobot hasil pelatihan model.

Dengan demikian, untuk setiap posisi spasial \((r,c)\), keluaran node decoder dihitung sebagai:

\[ \begin{aligned} X_{r,c}^{0,2} = \operatorname{ReLU} \Bigg( &0.25X_{r,c}^{0,0}\\ &+ 0.50X_{r,c}^{0,1}\\ &+ 0.25 \left[ \operatorname{Up} \left( \mathbf{X}^{1,1} \right) \right]_{r,c} \Bigg). \end{aligned} \]

  • Contoh perhitungan node decoder pada posisi \((2,2)\):

\[ \begin{aligned} X_{2,2}^{0,2} &= \operatorname{ReLU} \Bigg( 0.25X_{2,2}^{0,0} + 0.50X_{2,2}^{0,1}\\ &\qquad+ 0.25 \left[ \operatorname{Up} \left( \mathbf{X}^{1,1} \right) \right]_{2,2} \Bigg)\\ &= \operatorname{ReLU} \left( 0.25(-2.33) + 0.50(0.00) + 0.25(0.66) \right)\\ &= \operatorname{ReLU} \left( -0.5825+0.165 \right)\\ &= \operatorname{ReLU}(-0.4175)\\ &= 0.00. \end{aligned} \]

  • Contoh perhitungan node decoder pada posisi \((2,3)\):

\[ \begin{aligned} X_{2,3}^{0,2} &= \operatorname{ReLU} \Bigg( 0.25X_{2,3}^{0,0} + 0.50X_{2,3}^{0,1}\\ &\qquad+ 0.25 \left[ \operatorname{Up} \left( \mathbf{X}^{1,1} \right) \right]_{2,3} \Bigg)\\ &= \operatorname{ReLU} \left( 0.25(1.91) + 0.50(3.64) + 0.25(1.32) \right)\\ &= \operatorname{ReLU} \left( 0.4775+1.82+0.33 \right)\\ &= \operatorname{ReLU}(2.6275)\\ &\approx 2.63. \end{aligned} \]

Dengan menerapkan operasi yang sama pada seluruh posisi spasial dan menggunakan nilai presisi penuh sebelum pembulatan, diperoleh feature map keluaran akhir decoder sebagai berikut:

\[ \mathbf{X}^{0,2} = \begin{bmatrix} 0.00 & 0.00 & 2.22 & 0.77 & 0.00\\ 0.00 & 0.00 & 2.63 & 1.11 & 0.00\\ 0.00 & 0.00 & 2.77 & 1.20 & 0.00\\ 0.00 & 0.00 & 1.99 & 0.64 & 0.00\\ 0.00 & 0.00 & 0.77 & 0.00 & 0.00 \end{bmatrix}. \]

Hasil tersebut menunjukkan bahwa node \(\mathbf{X}^{0,2}\) menggabungkan informasi dari \(\mathbf{X}^{0,0}\), \(\mathbf{X}^{0,1}\), dan hasil upsampling \(\mathbf{X}^{1,1}\) melalui nested skip connection. Pada ilustrasi ini, penggabungan dilakukan menggunakan Concat, konvolusi \(1\times1\), dan fungsi aktivasi ReLU.

Feature map \(\mathbf{X}^{0,2}\) merupakan keluaran akhir decoder pada ilustrasi perhitungan manual ini dan selanjutnya digunakan sebagai masukan pada head segmentasi.

7. Head sigmoid dan mask segmentasi

Keluaran akhir decoder \(\mathbf{X}^{0,2}\) diteruskan ke head segmentasi menggunakan konvolusi \(1\times1\) tanpa bias. Konvolusi tersebut menghasilkan matriks logit \(\mathbf{z}\). Selanjutnya, fungsi sigmoid diterapkan pada setiap elemen logit untuk membentuk matriks probabilitas \(\mathbf{p}\). Berdasarkan ketentuan pada Bab III, piksel dengan probabilitas lebih dari \(0.50\) dikategorikan sebagai lesi, sedangkan piksel lainnya dikategorikan sebagai latar belakang.

a. Head segmentasi dan matriks logit

Pada ilustrasi ini, head segmentasi menggunakan konvolusi \(1\times1\) tanpa bias dengan kernel sebagai berikut.

\[ \mathbf{W}_{\mathrm{head}}= \begin{bmatrix} 1.00 \end{bmatrix}. \]

Karena feature map masukan hanya memiliki satu kanal, kernel tersebut diterapkan pada setiap nilai \(\mathbf{X}^{0,2}\).

  • Rumus:

\[ z_{i,j} = W_{\mathrm{head}} X^{0,2}_{i,j}. \]

Karena \(W_{\mathrm{head}}=1.00\), maka

\[ z_{i,j} = X^{0,2}_{i,j}. \]

Matriks logit \(\mathbf{z}\) berukuran \(5\times5\).

  • Contoh perhitungan pada posisi \((3,3)\):

\[ \begin{aligned} z_{3,3} &= W_{\mathrm{head}} X^{0,2}_{3,3}\\ &= 1.00(2.77)\\ &= 2.77. \end{aligned} \]

Dengan perhitungan menggunakan nilai presisi penuh sebelum pembulatan, diperoleh matriks logit berikut.

\[ \mathbf{z}= \begin{bmatrix} 0.00 & 0.00 & 2.22 & 0.77 & 0.00\\ 0.00 & 0.00 & 2.63 & 1.11 & 0.00\\ 0.00 & 0.00 & 2.77 & 1.20 & 0.00\\ 0.00 & 0.00 & 1.99 & 0.64 & 0.00\\ 0.00 & 0.00 & 0.77 & 0.00 & 0.00 \end{bmatrix}. \]

b. Probabilitas prediksi piksel

Fungsi sigmoid diterapkan pada setiap elemen matriks logit untuk menghasilkan probabilitas prediksi piksel pada rentang \([0,1]\).

  • Rumus:

\[ p_{i,j} = \sigma(z_{i,j}) = \frac{1}{1+e^{-z_{i,j}}}. \]

Matriks probabilitas \(\mathbf{p}\) berukuran \(5\times5\).

  • Contoh perhitungan pada posisi \((3,3)\):

\[ \begin{aligned} p_{3,3} &= \frac{1}{1+e^{-z_{3,3}}}\\ &= \frac{1}{1+e^{-2.77}}\\ &= \frac{1}{1+0.06}\\ &= 0.94. \end{aligned} \]

  • Contoh perhitungan pada posisi \((1,1)\):

\[ \begin{aligned} p_{1,1} &= \frac{1}{1+e^{-0.00}}\\ &= \frac{1}{1+1}\\ &= 0.50. \end{aligned} \]

Dengan perhitungan menggunakan nilai presisi penuh sebelum pembulatan, diperoleh matriks probabilitas berikut.

\[ \mathbf{p}= \begin{bmatrix} 0.50 & 0.50 & 0.90 & 0.68 & 0.50\\ 0.50 & 0.50 & 0.93 & 0.75 & 0.50\\ 0.50 & 0.50 & 0.94 & 0.77 & 0.50\\ 0.50 & 0.50 & 0.88 & 0.65 & 0.50\\ 0.50 & 0.50 & 0.68 & 0.50 & 0.50 \end{bmatrix}. \]

c. Mask segmentasi biner

Matriks probabilitas dikonversi menjadi mask segmentasi biner menggunakan nilai ambang lebih dari \(0.50\). Piksel dengan probabilitas tepat \(0.50\) dikategorikan sebagai latar belakang.

  • Rumus:

\[ \widehat{M}_{i,j} = \mathbb{1} \left[ p_{i,j}>0.50 \right]. \]

dengan

\[ \widehat{M}_{i,j} = \begin{cases} 1, & \text{jika } p_{i,j}>0.50 \text{ (lesi)},\\ 0, & \text{jika } p_{i,j}\leq0.50 \text{ (latar belakang)}. \end{cases} \]

Matriks mask segmentasi \(\widehat{\mathbf{M}}\) berukuran \(5\times5\).

  • Contoh perhitungan pada posisi \((3,3)\):

\[ \begin{aligned} \widehat{M}_{3,3} &= \mathbb{1} \left[ p_{3,3}>0.50 \right]\\ &= \mathbb{1} \left[ 0.94>0.50 \right]\\ &= 1. \end{aligned} \]

  • Contoh perhitungan pada posisi \((1,1)\):

\[ \begin{aligned} \widehat{M}_{1,1} &= \mathbb{1} \left[ p_{1,1}>0.50 \right]\\ &= \mathbb{1} \left[ 0.50>0.50 \right]\\ &= 0. \end{aligned} \]

Dengan aturan yang sama, diperoleh mask segmentasi biner berikut.

\[ \widehat{\mathbf{M}}= \begin{bmatrix} 0 & 0 & 1 & 1 & 0\\ 0 & 0 & 1 & 1 & 0\\ 0 & 0 & 1 & 1 & 0\\ 0 & 0 & 1 & 1 & 0\\ 0 & 0 & 1 & 0 & 0 \end{bmatrix}. \]

Keterangan proses pelatihan: Mask biner \(\widehat{M}\) pada ilustrasi ini ditampilkan untuk memperlihatkan bentuk akhir hasil segmentasi dan untuk menghitung metrik evaluasi. Pada proses pelatihan, mask biner tersebut tidak digunakan untuk memperbarui bobot model. Pembaruan bobot dilakukan menggunakan probabilitas prediksi \(p\) dan ground truth \(M\) melalui BCE-Dice loss.

LS0tDQp0aXRsZTogIklsdXN0cmFzaSBQZW1iZW50dWthbiBTZWdtZW50YXNpIFVOZXQrKyBkZW5nYW4gRW5jb2RlciBNb2JpbGVWaVR2MyBWMiINCg0KYXV0aG9yOiB8DQogIDxkaXYgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsgZm9udC1zaXplOiAxNHB4OyBjb2xvcjogIzU1NTU1NTsgbGluZS1oZWlnaHQ6IDEuNjsgbWFyZ2luLXRvcDogMTBweDsiPg0KICBTcmkgWXVsaWFuYSAoMTQwNzIwMjUwMDMpIDxicj4NCg0KICBQcm9ncmFtIFN0dWRpIE1hZ2lzdGVyIFN0YXRpc3Rpa2EgVGVyYXBhbiA8YnI+DQogIDwvZGl2Pg0KICANCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZGVwdGg6IDMNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogIHBkZl9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUNCiAgd29yZF9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUNCmNzczogc3R5bGUuY3NzDQotLS0NCg0KIyMgMS4gQ2l0cmEgbWFzdWthbiBncm91bmQgdHJ1dGggZGFuIG5vcm1hbGlzYXNpDQoNClBhZGEgY2l0cmEgZ3JheXNjYWxlLCBzZXRpYXAgcGlrc2VsIG1lbWlsaWtpIHNhdHUgbmlsYWkgaW50ZW5zaXRhcyB5YW5nIG1lbnVuanVra2FuIHRpbmdrYXQga2VjZXJhaGFuLiBBcGFiaWxhIG5pbGFpIGludGVuc2l0YXMgdGVsYWggZGlub3JtYWxpc2FzaSBrZSByZW50YW5nIFwoWzAsMV1cKSwgbWFrYSBuaWxhaSAwIG1lbnVuanVra2FuIHBpa3NlbCBwYWxpbmcgZ2VsYXAgKGhpdGFtKSwgbmlsYWkgMSBtZW51bmp1a2thbiBwaWtzZWwgcGFsaW5nIHRlcmFuZyAocHV0aWgpLCBzZWRhbmdrYW4gbmlsYWkgZGkgYW50YXJhIDAgZGFuIDEgbWVudW5qdWtrYW4gZ3JhZGFzaSBhYnUtYWJ1LiBTZW1ha2luIG1lbmRla2F0aSAwLCBwaWtzZWwgc2VtYWtpbiBnZWxhcDsgc2VtYWtpbiBtZW5kZWthdGkgMSwgcGlrc2VsIHNlbWFraW4gdGVyYW5nLiAgDQoNCkRhbGFtIGlsdXN0cmFzaSBpbmksIG1hdHJpa3MgY2l0cmEgYXdhbCBtYXNpaCBtZW5nZ3VuYWthbiBza2FsYSBpbnRlbnNpdGFzIDAtLTI1NS4gT2xlaCBrYXJlbmEgaXR1LCBuaWxhaSAwIG1lcmVwcmVzZW50YXNpa2FuIGhpdGFtLCBuaWxhaSAyNTUgbWVyZXByZXNlbnRhc2lrYW4gcHV0aWgsIGRhbiBuaWxhaSBzZXBlcnRpIDY0LCAxMjgsIGF0YXUgMTkyIG1lbnVuanVra2FuIHRpbmdrYXQgYWJ1LWFidSB5YW5nIGJlcmJlZGEuIERpbWVuc2kgbWF0cmlrcyBhZGFsYWggXCg1XHRpbWVzNVwpLiBQYWRhIGltcGxlbWVudGFzaSBzZWJlbmFybnlhLCBjaXRyYSBOQ0NUIHNhdHUga2FuYWwgZGlyZXBsaWthc2kgbWVuamFkaSB0aWdhIGthbmFsIGFnYXIgc2VzdWFpIGRlbmdhbiBtYXN1a2FuIGVuY29kZXIgTW9iaWxlVmlUdjMuIE5hbXVuLCBpbHVzdHJhc2kgcGVyaGl0dW5nYW4gYmVyaWt1dCBoYW55YSBtZW5lbHVzdXJpIHNhdHUga2FuYWwuDQoNCiMjIyBhLiBDaXRyYSBtYXN1a2FuDQoNClxbDQpcbWF0aGJme0l9PQ0KXGJlZ2lue2JtYXRyaXh9DQowICYgNjQgJiAxOTIgJiAxNjAgJiAzMlxcDQowICYgODAgJiAyMDggJiAxNzYgJiA0MFxcDQowICYgODAgJiAyMDggJiAxNzYgJiA0MFxcDQowICYgNzIgJiAxOTIgJiAxNjAgJiAzMlxcDQo4ICYgNDggJiAxNDQgJiAxMTIgJiAyNA0KXGVuZHtibWF0cml4fS4NClxdDQoNCiMjIyBiLiBHcm91bmQgdHJ1dGggYmluZXINCg0KXFsNClxtYXRoYmZ7TX09DQpcYmVnaW57Ym1hdHJpeH0NCjAgJiAwICYgMSAmIDEgJiAwXFwNCjAgJiAxICYgMSAmIDEgJiAwXFwNCjAgJiAxICYgMSAmIDEgJiAwXFwNCjAgJiAwICYgMSAmIDEgJiAwXFwNCjAgJiAwICYgMCAmIDAgJiAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KR3JvdW5kIHRydXRoIFwoTVwpIGJlcmFkYSBkaSBhd2FsIHNlYmFnYWkgdGFyZ2V0IGV2YWx1YXNpLCBkZW5nYW4gbmlsYWkgMCBtZW55YXRha2FuIGxhdGFyIGJlbGFrYW5nIGRhbiBuaWxhaSAxIG1lbnlhdGFrYW4gd2lsYXlhaCBsZXNpLiBNYXRyaWtzIFwoTVwpIGJ1a2FuIG1lcnVwYWthbiBtYXN1a2FuIGVuY29kZXIuDQoNCiMjIyBjLiBOb3JtYWxpc2FzaSBrYW5hbA0KDQotICoqTm9ybWFsaXNhc2kgcHJldHJhaW5lZCBJbWFnZU5ldCBkaXRlcmFwa2FuIHBlciBrYW5hbDoqKg0KDQpcWw0KXG1hdGhiZntYfV9SPVxmcmFje0lfUi8yNTUtMC40ODV9ezAuMjI5fSxccXF1YWQNClxtYXRoYmZ7WH1fRz1cZnJhY3tJX0cvMjU1LTAuNDU2fXswLjIyNH0sXHFxdWFkDQpcbWF0aGJme1h9X0I9XGZyYWN7SV9CLzI1NS0wLjQwNn17MC4yMjV9Lg0KXF0NCg0KLSAqKkNvbnRvaDoqKg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpYX3sxLDN9DQomPQ0KXGZyYWN7MTkyLzI1NS0wLjQ4NX17MC4yMjl9XFwNCiY9DQoxLjE3Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KUGFkYSBpbHVzdHJhc2kgaW5pLCBoYW55YSBzYXR1IGthbmFsIHlhbmcgZGlndW5ha2FuIE9sZWgga2FyZW5hIGl0dSwgc2V0aWFwIGVsZW1lbiBmZWF0dXJlIG1hcCBtYXN1a2FuIFwoWFwpIGRpaGl0dW5nIG1lbmdndW5ha2FuDQoNClxbDQpYX3tpLGp9DQo9DQpcZnJhY3tJX3tpLGp9LzI1NS0wLjQ4NX17MC4yMjl9Lg0KXF0NCg0KQXR1cmFuIHlhbmcgc2FtYSBkaXRlcmFwa2FuIHBhZGEgc2VsdXJ1aCBlbGVtZW4gbWF0cmlrcy4gRGVuZ2FuIG5pbGFpIHByZXNpc2kgcGVudWggeWFuZyBrZW11ZGlhbiBkaXRhbXBpbGthbiBoaW5nZ2EgZHVhIGFuZ2thIGRlc2ltYWwsIGRpcGVyb2xlaA0KDQpcWw0KXG1hdGhiZntYfT0NClxiZWdpbntibWF0cml4fQ0KLTIuMTIgJiAtMS4wMiAmIDEuMTcgJiAwLjYyICYgLTEuNTdcXA0KLTIuMTIgJiAtMC43NSAmIDEuNDQgJiAwLjkwICYgLTEuNDNcXA0KLTIuMTIgJiAtMC43NSAmIDEuNDQgJiAwLjkwICYgLTEuNDNcXA0KLTIuMTIgJiAtMC44OCAmIDEuMTcgJiAwLjYyICYgLTEuNTdcXA0KLTEuOTggJiAtMS4zMCAmIDAuMzUgJiAtMC4yMCAmIC0xLjcxDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KIyMgMi4gUmVwcmVzZW50YXNpIGxva2FsIE1vYmlsZVZpVHYzLXYyDQoNClBhZGEgaWx1c3RyYXNpIGluaSwgbWF0cmlrcyBcKFhcKSBtZXJ1cGFrYW4gc2F0dSBpcmlzYW4ga2FuYWwgZGFyaSBmZWF0dXJlIG1hcCBtYXN1a2FuIGJsb2sgXChcbWF0aGJmIEZeeygwKX1cKSBzZXRlbGFoIG5vcm1hbGlzYXNpLiBNYXRyaWtzIFwoWFwpIG1lbWlsaWtpIGRpbWVuc2kgXCg1XHRpbWVzNVwpLiBUYWhhcCByZXByZXNlbnRhc2kgbG9rYWwgZGltdWxhaSBkZW5nYW4gKmRlcHRod2lzZSBjb252b2x1dGlvbiogXCgzXHRpbWVzM1wpLCBkaWxhbmp1dGthbiBkZW5nYW4gZnVuZ3NpIGFrdGl2YXNpIFN3aXNoLiBQcm95ZWtzaSBwb2ludHdpc2UgXCgxXHRpbWVzMVwpIGJhcnUgZGl0ZXJhcGthbiBzZXRlbGFoIGZlYXR1cmUgbWFwIGxva2FsIGRpcGVyb2xlaC4NCg0KDQojIyMgYS4gRGVwdGh3aXNlIENvbnZvbHV0aW9uDQoNClBhZGEgaWx1c3RyYXNpIGluaSwgbWF0cmlrcyBcKFxtYXRoYmZ7WH1cKSBtZXJ1cGFrYW4gc2F0dSBrYW5hbCAqZmVhdHVyZSBtYXAqIG1hc3VrYW4gYmVydWt1cmFuIFwoNVx0aW1lczVcKS4gT3BlcmFzaSAqZGVwdGh3aXNlIGNvbnZvbHV0aW9uKiBkaXRlcmFwa2FuIHNlY2FyYSBpbmRlcGVuZGVuIHBhZGEga2FuYWwgdGVyc2VidXQgbWVuZ2d1bmFrYW4ga2VybmVsIFwoM1x0aW1lczNcKSwgKnN0cmlkZSogXCgxXCksICp6ZXJvIHBhZGRpbmcqIHNlYmVzYXIgXCgxXCkgcGFkYSBzZXRpYXAgc2lzaSwgZGFuIHRhbnBhIGJpYXMuIEtlbHVhcmFuIHNlYmVsdW0gYWt0aXZhc2kgZGlueWF0YWthbiBzZWJhZ2FpIFwoXG1hdGhiZntGfV97XG1hdGhybXtkd319XCkuDQoNCk1hdHJpa3MgKmZlYXR1cmUgbWFwKiBtYXN1a2FuIHlhbmcgZGlndW5ha2FuIGFkYWxhaDoNCg0KXFsNClxtYXRoYmZ7WH0NCj0NClxiZWdpbntibWF0cml4fQ0KLTIuMTIgJiAtMS4wMiAmIDEuMTcgJiAwLjYyICYgLTEuNTdcXA0KLTIuMTIgJiAtMC43NSAmIDEuNDQgJiAwLjkwICYgLTEuNDNcXA0KLTIuMTIgJiAtMC43NSAmIDEuNDQgJiAwLjkwICYgLTEuNDNcXA0KLTIuMTIgJiAtMC44OCAmIDEuMTcgJiAwLjYyICYgLTEuNTdcXA0KLTEuOTggJiAtMS4zMCAmIDAuMzUgJiAtMC4yMCAmIC0xLjcxDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KLSAqKlBlbmFtYmFoYW4gWmVybyBQYWRkaW5nOioqDQoNClNlYmVsdW0gb3BlcmFzaSAqZGVwdGh3aXNlIGNvbnZvbHV0aW9uKiBkaWxha3VrYW4sIHNhdHUgbGFwaXNhbiBuaWxhaSBub2wgZGl0YW1iYWhrYW4gcGFkYSBrZWVtcGF0IHNpc2kgbWF0cmlrcyBtYXN1a2FuLCB5YWl0dSBzaXNpIGF0YXMsIGJhd2FoLCBraXJpLCBkYW4ga2FuYW4uIFBlbmFtYmFoYW4gKnplcm8gcGFkZGluZyogaW5pIGJlcnR1anVhbiBtZW1wZXJ0YWhhbmthbiB1a3VyYW4gc3Bhc2lhbCAqZmVhdHVyZSBtYXAqIHNldGVsYWggcHJvc2VzIGtvbnZvbHVzaS4NCg0KVWt1cmFuIGtlbHVhcmFuIGRpaGl0dW5nIG1lbmdndW5ha2FuOg0KDQpcWw0Kbw0KPQ0KXGxlZnRcbGZsb29yDQpcZnJhY3tpKzJwLWt9e3N9DQpccmlnaHRccmZsb29yKzEsDQpcXQ0KDQpkZW5nYW4gXChpXCkgbWVueWF0YWthbiB1a3VyYW4gc3Bhc2lhbCBtYXN1a2FuLCBcKHBcKSBtZXJ1cGFrYW4ganVtbGFoICpwYWRkaW5nKiBwYWRhIHNldGlhcCBzaXNpLCBcKGtcKSBtZXJ1cGFrYW4gdWt1cmFuIGtlcm5lbCwgZGFuIFwoc1wpIG1lcnVwYWthbiAqc3RyaWRlKi4NCg0KUGFkYSBpbHVzdHJhc2kgaW5pLCBkaWd1bmFrYW4gXChpPTVcKSwgXChwPTFcKSwgXChrPTNcKSwgZGFuIFwocz0xXCksIHNlaGluZ2dhOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpvDQomPQ0KXGxlZnRcbGZsb29yDQpcZnJhY3s1KzIoMSktM317MX0NClxyaWdodFxyZmxvb3IrMVxcDQomPQ0KXGxlZnRcbGZsb29yDQpcZnJhY3s0fXsxfQ0KXHJpZ2h0XHJmbG9vcisxXFwNCiY9NS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBkZW1pa2lhbiwgdWt1cmFuIHNwYXNpYWwga2VsdWFyYW4gdGV0YXAgXCg1XHRpbWVzNVwpLiBTZXRlbGFoIHBlbmFtYmFoYW4gKnplcm8gcGFkZGluZyosIHVrdXJhbiBtYXRyaWtzIG1hc3VrYW4gc2VtZW50YXJhIGJlcnViYWggZGFyaSBcKDVcdGltZXM1XCkgbWVuamFkaSBcKDdcdGltZXM3XCkuDQoNCk1hdHJpa3Mgc2V0ZWxhaCBwZW5hbWJhaGFuICp6ZXJvIHBhZGRpbmcqIGFkYWxhaDoNCg0KXFsNClxtYXRoYmZ7WH1fe1xtYXRocm17cGFkfX0NCj0NClxiZWdpbntibWF0cml4fQ0KMC4wMCAmIDAuMDAgJiAwLjAwICYgMC4wMCAmIDAuMDAgJiAwLjAwICYgMC4wMFxcDQowLjAwICYgLTIuMTIgJiAtMS4wMiAmIDEuMTcgJiAwLjYyICYgLTEuNTcgJiAwLjAwXFwNCjAuMDAgJiAtMi4xMiAmIC0wLjc1ICYgMS40NCAmIDAuOTAgJiAtMS40MyAmIDAuMDBcXA0KMC4wMCAmIC0yLjEyICYgLTAuNzUgJiAxLjQ0ICYgMC45MCAmIC0xLjQzICYgMC4wMFxcDQowLjAwICYgLTIuMTIgJiAtMC44OCAmIDEuMTcgJiAwLjYyICYgLTEuNTcgJiAwLjAwXFwNCjAuMDAgJiAtMS45OCAmIC0xLjMwICYgMC4zNSAmIC0wLjIwICYgLTEuNzEgJiAwLjAwXFwNCjAuMDAgJiAwLjAwICYgMC4wMCAmIDAuMDAgJiAwLjAwICYgMC4wMCAmIDAuMDANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQotICoqRmlsdGVyIGF0YXUgQm9ib3QgS2VybmVsIERlcHRod2lzZSBDb252b2x1dGlvbjoqKg0KDQpQYWRhIGlsdXN0cmFzaSBpbmksIG1hdHJpa3MgYm9ib3Qga2VybmVsICpkZXB0aHdpc2UgY29udm9sdXRpb24qIGRpdGV0YXBrYW4gc2ViYWdhaToNCg0KXFsNClxtYXRoYmZ7V31fe1xtYXRocm17ZHd9fQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjA1ICYgMC4xMCAmIDAuMDVcXA0KMC4xMCAmIDAuNDAgJiAwLjEwXFwNCjAuMDUgJiAwLjEwICYgMC4wNQ0KXGVuZHtibWF0cml4fS4NClxdDQoNCktlcm5lbCB0ZXJzZWJ1dCBiZXJ1a3VyYW4gXCgzXHRpbWVzM1wpLiBCb2JvdCBwdXNhdCBzZWJlc2FyIFwoMC40MFwpIG1lbWJlcmlrYW4ga29udHJpYnVzaSB0ZXJiZXNhciBkYXJpIGVsZW1lbiBwdXNhdCwgc2VkYW5na2FuIGVsZW1lbi1lbGVtZW4gZGkgc2VraXRhcm55YSBtZW1iZXJpa2FuIGtvbnRyaWJ1c2kgbWVsYWx1aSBib2JvdCBcKDAuMDVcKSBkYW4gXCgwLjEwXCkuDQoNClNldGlhcCBoYXNpbCBrb252b2x1c2kgZGlwZXJvbGVoIG1lbGFsdWkgcGVya2FsaWFuIHNlbWJpbGFuIGVsZW1lbiBwYWRhIGFyZWEgKmZlYXR1cmUgbWFwKiBkZW5nYW4gc2VtYmlsYW4gYm9ib3Qga2VybmVsIHlhbmcgYmVyc2VzdWFpYW4sIGtlbXVkaWFuIHNlbHVydWggaGFzaWwgcGVya2FsaWFuIGRpanVtbGFoa2FuLg0KDQotICoqUnVtdXM6KioNCg0KU2VjYXJhIHVtdW0sIG9wZXJhc2kgKmRlcHRod2lzZSBjb252b2x1dGlvbiogcGFkYSAqZmVhdHVyZSBtYXAqIG11bHRpa2FuYWwgZGlueWF0YWthbiBzZWJhZ2FpOg0KDQpcWw0KRl97XG1hdGhybXtkd30sayxsLG19DQo9DQpcc3VtX3t1PTF9XnszfQ0KXHN1bV97dj0xfV57M30NCldfe1xtYXRocm17ZHd9LHUsdixtfQ0KWF97XG1hdGhybXtwYWR9LGsrdS0xLGwrdi0xLG19LA0KXF0NCg0KZGVuZ2FuIFwobVwpIG1lbnlhdGFrYW4gaW5kZWtzIGthbmFsLCBzZWRhbmdrYW4gXCh1XCkgZGFuIFwodlwpIG1lcnVwYWthbiBpbmRla3MgYmFyaXMgZGFuIGtvbG9tIGtlcm5lbC4NCg0KUGFkYSBpbHVzdHJhc2kgc2F0dSBrYW5hbCwgcGVyaGl0dW5nYW4gc2V0aWFwIGVsZW1lbiBrZWx1YXJhbiBkaW55YXRha2FuIHNlYmFnYWk6DQoNClxbDQpGX3tcbWF0aHJte2R3fSxrLGx9DQo9DQpcc3VtX3t1PTF9XnszfQ0KXHN1bV97dj0xfV57M30NCldfe1xtYXRocm17ZHd9LHUsdn0NClhfe1xtYXRocm17cGFkfSxrK3UtMSxsK3YtMX0sDQpcXQ0KDQpkZW5nYW4gXChrLGw9MSwyLFxsZG90cyw1XCkuDQoNClBhZGEgc2V0aWFwIHBvc2lzaSwga2VybmVsIG1lbmNha3VwIGFyZWEgYmVydWt1cmFuIFwoM1x0aW1lczNcKS4gS2FyZW5hICpzdHJpZGUqIGJlcm5pbGFpIFwoMVwpLCBrZXJuZWwgYmVyZ2VzZXIgc2F0dSBrb2xvbSBrZSBrYW5hbiB1bnR1ayBtZW5naGl0dW5nIGVsZW1lbiBiZXJpa3V0bnlhIHBhZGEgYmFyaXMga2VsdWFyYW4geWFuZyBzYW1hLiBTZXRlbGFoIG1lbmNhcGFpIHBvc2lzaSB0ZXJha2hpciBwYWRhIGJhcmlzIHRlcnNlYnV0LCBrZXJuZWwga2VtYmFsaSBrZSBzaXNpIGtpcmkgZGFuIGJlcmdlc2VyIHNhdHUgYmFyaXMga2UgYmF3YWguDQoNCi0gKipDb250b2ggUGVyaGl0dW5nYW4gS29udm9sdXNpOioqDQoNCioqMS4gUGVyaGl0dW5nYW4gZWxlbWVuIHBhZGEgcG9zaXNpIFwoKDEsMSlcKSoqDQoNClVudHVrIG1lbmdoYXNpbGthbiBlbGVtZW4gcGVydGFtYSBkYXJpICpmZWF0dXJlIG1hcCoga2VsdWFyYW4sIGtlcm5lbCBkaXRlbXBhdGthbiBwYWRhIGFyZWEgXCgzXHRpbWVzM1wpIGRpIHBvam9rIGtpcmkgYXRhcyBtYXRyaWtzIHlhbmcgdGVsYWggZGliZXJpICp6ZXJvIHBhZGRpbmcqLg0KDQpBcmVhICpmZWF0dXJlIG1hcCogeWFuZyBkaXByb3NlcyBhZGFsYWg6DQoNClxbDQpcYmVnaW57Ym1hdHJpeH0NCjAuMDAgJiAwLjAwICYgMC4wMFxcDQowLjAwICYgLTIuMTIgJiAtMS4wMlxcDQowLjAwICYgLTIuMTIgJiAtMC43NQ0KXGVuZHtibWF0cml4fS4NClxdDQoNCkFyZWEgdGVyc2VidXQgZGlrYWxpa2FuIHNlY2FyYSBlbGVtZW4gZGVtaSBlbGVtZW4gZGVuZ2FuIGJvYm90IGtlcm5lbCBcKFxtYXRoYmZ7V31fe1xtYXRocm17ZHd9fVwpLCBrZW11ZGlhbiBzZWx1cnVoIGhhc2lsIHBlcmthbGlhbiBkaWp1bWxhaGthbiBzZWJhZ2FpIGJlcmlrdXQ6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NCkZfe1xtYXRocm17ZHd9LDEsMX0NCj17fSYNCigwLjAwKSgwLjA1KQ0KKygwLjAwKSgwLjEwKQ0KKygwLjAwKSgwLjA1KVxcDQomKygwLjAwKSgwLjEwKQ0KKygtMi4xMikoMC40MCkNCisoLTEuMDIpKDAuMTApXFwNCiYrKDAuMDApKDAuMDUpDQorKC0yLjEyKSgwLjEwKQ0KKygtMC43NSkoMC4wNSlcXA0KPXt9Jg0KLTAuODQ4LTAuMTAyLTAuMjEyLTAuMDM3NVxcDQo9e30mLTEuMTk5NS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBwZW1idWxhdGFuIGR1YSBhbmdrYSBkZXNpbWFsLCBoYXNpbCBwZXJoaXR1bmdhbiB0ZXJzZWJ1dCBhZGFsYWg6DQoNClxbDQpGX3tcbWF0aHJte2R3fSwxLDF9PS0xLjIwLg0KXF0NCg0KKioyLiBQZXJoaXR1bmdhbiBlbGVtZW4gcGFkYSBwb3Npc2kgXCgoMiwyKVwpKioNCg0KVW50dWsgbWVuZ2hpdHVuZyBlbGVtZW4gcGFkYSBwb3Npc2kgXCgoMiwyKVwpLCBrZXJuZWwgZGl0ZW1wYXRrYW4gcGFkYSBhcmVhIHlhbmcgZGltdWxhaSBkYXJpIGJhcmlzIGtlZHVhIGRhbiBrb2xvbSBrZWR1YSBtYXRyaWtzIHNldGVsYWggKnBhZGRpbmcqLiBQb3Npc2kgaW5pIGJlcmFkYSBzYXR1IGJhcmlzIGRpIGJhd2FoIGRhbiBzYXR1IGtvbG9tIGRpIGthbmFuIGRpYmFuZGluZ2thbiBwb3Npc2kgYXdhbC4NCg0KQXJlYSAqZmVhdHVyZSBtYXAqIHlhbmcgZGlwcm9zZXMgYWRhbGFoOg0KDQpcWw0KXGJlZ2lue2JtYXRyaXh9DQotMi4xMiAmIC0xLjAyICYgMS4xN1xcDQotMi4xMiAmIC0wLjc1ICYgMS40NFxcDQotMi4xMiAmIC0wLjc1ICYgMS40NA0KXGVuZHtibWF0cml4fS4NClxdDQoNClBlcmhpdHVuZ2FuIGtvbnZvbHVzaSBkaWxha3VrYW4gbWVuZ2d1bmFrYW4gYm9ib3Qga2VybmVsIHlhbmcgc2FtYToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KRl97XG1hdGhybXtkd30sMiwyfQ0KPXt9Jg0KKC0yLjEyKSgwLjA1KQ0KKygtMS4wMikoMC4xMCkNCisoMS4xNykoMC4wNSlcXA0KJisoLTIuMTIpKDAuMTApDQorKC0wLjc1KSgwLjQwKQ0KKygxLjQ0KSgwLjEwKVxcDQomKygtMi4xMikoMC4wNSkNCisoLTAuNzUpKDAuMTApDQorKDEuNDQpKDAuMDUpXFwNCj17fSYNCi0wLjEwNi0wLjEwMiswLjA1ODVcXA0KJi0wLjIxMi0wLjMwMCswLjE0NFxcDQomLTAuMTA2LTAuMDc1KzAuMDcyXFwNCj17fSYtMC42MjY1Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KSGFzaWwgcGVyaGl0dW5nYW4gZGFyaSBuaWxhaSBtYXN1a2FuIGR1YSBkZXNpbWFsIGFkYWxhaCBcKC0wLjYyNjVcKS4gUGFkYSBtYXRyaWtzIGlsdXN0cmFzaSBzZWJlbHVtbnlhLCBlbGVtZW4gaW5pIHRlcmNhdGF0IHNlYmVzYXIgXCgtMC42MlwpLiBOaWxhaSBwYWRhIG1hdHJpa3MgZGlwZXJ0YWhhbmthbiBzZW1lbnRhcmEgaGluZ2dhIHZhbGlkYXNpIG51bWVyaWsgbWVueWVsdXJ1aCBkaWxha3VrYW4uDQoNClByb3NlZHVyIHlhbmcgc2FtYSBkaXRlcmFwa2FuIHBhZGEgc2VsdXJ1aCBwb3Npc2kga2VybmVsLiBQYWRhIHNldGlhcCBwb3Npc2ksIGVsZW1lbi1lbGVtZW4gZGFsYW0gYXJlYSBrb252b2x1c2kgZGlrYWxpa2FuIGRlbmdhbiBib2JvdCBrZXJuZWwgeWFuZyBiZXJzZXN1YWlhbiwga2VtdWRpYW4gc2VsdXJ1aCBoYXNpbCBwZXJrYWxpYW4gZGlqdW1sYWhrYW4gdW50dWsgbWVtYmVudHVrIHNhdHUgZWxlbWVuICpmZWF0dXJlIG1hcCoga2VsdWFyYW4uDQoNCk1hdHJpa3MgaGFzaWwgKmRlcHRod2lzZSBjb252b2x1dGlvbiogeWFuZyBkaWd1bmFrYW4gc2VtZW50YXJhIGRhbGFtIGlsdXN0cmFzaSBpbmkgYWRhbGFoOg0KDQpcWw0KXG1hdGhiZntGfV97XG1hdGhybXtkd319DQo9DQpcYmVnaW57Ym1hdHJpeH0NCi0xLjIwICYgLTAuNjEgJiAwLjU4ICYgMC4zMCAmIC0wLjY2XFwNCi0xLjQzICYgLTAuNjIgJiAwLjg0ICYgMC40OSAmIC0wLjcxXFwNCi0xLjQzICYgLTAuNjEgJiAwLjg1ICYgMC40OSAmIC0wLjcxXFwNCi0xLjQ1ICYgLTAuNzcgJiAwLjU1ICYgMC4yMSAmIC0wLjg0XFwNCi0xLjE4ICYgLTAuODIgJiAwLjA5ICYgLTAuMTcgJiAtMC44Mw0KXGVuZHtibWF0cml4fS4NClxdDQoNCk1hdHJpa3MgdGVyc2VidXQgbWVtcGVydGFoYW5rYW4gbmlsYWkgcGFkYSBpbHVzdHJhc2kgc2ViZWx1bW55YSBkYW4gYWthbiBkaXBlcmlrc2Ega2VtYmFsaSBtZWxhbHVpIHBlcmhpdHVuZ2FuIG51bWVyaWsgdW50dWsgbWVtYXN0aWthbiBrb25zaXN0ZW5zaSBzZWx1cnVoIHRhaGFwYW4uDQoNCktlbHVhcmFuICpkZXB0aHdpc2UgY29udm9sdXRpb24qIHNlbGFuanV0bnlhIGRpcHJvc2VzIG1lbmdndW5ha2FuIGZ1bmdzaSBha3RpdmFzaSBTd2lzaCB1bnR1ayBtZW1iZW50dWsgKmZlYXR1cmUgbWFwKiBsb2thbCBcKFxtYXRoYmZ7TH1cKS4NCg0KLSAqKlJ1bXVzIEFrdGl2YXNpIFN3aXNoOioqDQoNCkZ1bmdzaSBha3RpdmFzaSBTd2lzaCBkaXRlcmFwa2FuIHNlY2FyYSBlbGVtZW4gZGVtaSBlbGVtZW4gcGFkYSBtYXRyaWtzIGhhc2lsICpkZXB0aHdpc2UgY29udm9sdXRpb24qOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpMX3tpLGp9DQomPQ0KXG9wZXJhdG9ybmFtZXtTd2lzaH0NClxsZWZ0KA0KRl97XG1hdGhybXtkd30saSxqfQ0KXHJpZ2h0KVxcDQomPQ0KXGZyYWN7Rl97XG1hdGhybXtkd30saSxqfX0NCnsxK2Veey1GX3tcbWF0aHJte2R3fSxpLGp9fX0uDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQotICoqQ29udG9oIFBlcmhpdHVuZ2FuIHBhZGEgUG9zaXNpIFwoKDEsMSlcKToqKg0KDQpVbnR1ayBlbGVtZW4gcGFkYSBwb3Npc2kgXCgoMSwxKVwpLCBuaWxhaSB5YW5nIGRpZ3VuYWthbiBzZXN1YWkgZGVuZ2FuIG1hdHJpa3MgaGFzaWwgKmRlcHRod2lzZSBjb252b2x1dGlvbiosIHlhaXR1IFwoLTEuMjBcKS4NCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KTF97MSwxfQ0KJj0NClxvcGVyYXRvcm5hbWV7U3dpc2h9KC0xLjIwKVxcDQomPQ0KXGZyYWN7LTEuMjB9ezErZV57LSgtMS4yMCl9fVxcDQomPQ0KXGZyYWN7LTEuMjB9ezErZV57MS4yMH19XFwNCiY9DQpcZnJhY3stMS4yMH17MSszLjMyfVxcDQomPS0wLjI4Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KRGVuZ2FuIG1lbmVyYXBrYW4gZnVuZ3NpIGFrdGl2YXNpIFN3aXNoIHBhZGEgc2VsdXJ1aCBlbGVtZW4gbWF0cmlrcyBoYXNpbCAqZGVwdGh3aXNlIGNvbnZvbHV0aW9uKiwgZGlwZXJvbGVoICpmZWF0dXJlIG1hcCogbG9rYWw6DQoNClxbDQpcbWF0aGJme0x9DQo9DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjI4ICYgLTAuMjIgJiAwLjM3ICYgMC4xNyAmIC0wLjIzXFwNCi0wLjI4ICYgLTAuMjIgJiAwLjU5ICYgMC4zMSAmIC0wLjIzXFwNCi0wLjI4ICYgLTAuMjIgJiAwLjU5ICYgMC4zMSAmIC0wLjIzXFwNCi0wLjI4ICYgLTAuMjQgJiAwLjM1ICYgMC4xMiAmIC0wLjI1XFwNCi0wLjI4ICYgLTAuMjUgJiAwLjA1ICYgLTAuMDggJiAtMC4yNQ0KXGVuZHtibWF0cml4fS4NClxdDQoNCk1hdHJpa3MgXChcbWF0aGJme0x9XCkgbWVydXBha2FuIHJlcHJlc2VudGFzaSBsb2thbCBzZXRlbGFoIHBlbmVyYXBhbiBmdW5nc2kgYWt0aXZhc2kgU3dpc2ggZGFuIGRpZ3VuYWthbiBzZWJhZ2FpIG1hc3VrYW4gcGFkYSB0YWhhcCBiZXJpa3V0bnlhLiBOaWxhaSBtYXRyaWtzIHRlcnNlYnV0IGRpcGVydGFoYW5rYW4gc2VzdWFpIGlsdXN0cmFzaSBzZWJlbHVtbnlhIGhpbmdnYSBkaWxha3VrYW4gdmFsaWRhc2kgbnVtZXJpayBzZWNhcmEgbWVueWVsdXJ1aC4NCg0KDQojIyMgYi4gUG9pbnR3aXNlIENvbnZvbHV0aW9uIGRhbiBUb2tlbmlzYXNpDQoNCipGZWF0dXJlIG1hcCogbG9rYWwgXChcbWF0aGJme0x9XCkgbWVtaWxpa2kgc2F0dSBrYW5hbCBkZW5nYW4gZGltZW5zaSBcKDVcdGltZXM1XHRpbWVzMVwpLiBTZWxhbmp1dG55YSwgKnBvaW50d2lzZSBjb252b2x1dGlvbiogXCgxXHRpbWVzMVwpIGRpdGVyYXBrYW4gc2VjYXJhIGluZGVwZW5kZW4gcGFkYSBzZXRpYXAgcG9zaXNpIHNwYXNpYWwuIE9wZXJhc2kgaW5pIHRpZGFrIG1lbGliYXRrYW4gcGlrc2VsIHRldGFuZ2dhLCB0ZXRhcGkgbWVtcHJveWVrc2lrYW4gc2F0dSBrYW5hbCBtYXN1a2FuIG1lbmphZGkgZHVhIGthbmFsIGtlbHVhcmFuIHlhbmcgbWVtYmVudHVrIHZla3RvciB0b2tlbi4NCg0KLSAqKkJvYm90ICpwb2ludHdpc2UgY29udm9sdXRpb24qOioqDQoNClxbDQpcbWF0aGJme1d9X3tcbWF0aHJte3B3fX1eeyhcbWF0aHJte3Rva30pfQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjgwICYgLTAuNjANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQpCb2JvdCBcKFxtYXRoYmZ7V31fe1xtYXRocm17cHd9fV57KFxtYXRocm17dG9rfSl9XCkgYmVyZGltZW5zaSBcKDFcdGltZXMyXCkuIE9sZWgga2FyZW5hIGl0dSwgc2V0aWFwIG5pbGFpICpmZWF0dXJlIG1hcCogbG9rYWwgZGlwcm95ZWtzaWthbiBtZW5qYWRpIHZla3RvciBkZW5nYW4gZHVhIGVsZW1lbi4NCg0KLSAqKlJ1bXVzOioqDQoNClVudHVrIHNldGlhcCBwb3Npc2kgc3Bhc2lhbCBcKChpLGopXCksIHRva2VuIGtlLVwodFwpIGRpcnVtdXNrYW4gc2ViYWdhaToNCg0KXFsNClRfe3Qsbn0NCj0NClxzdW1fe209MX1ee0NfTH0NCldfe1xtYXRocm17cHd9LG0sbn1eeyhcbWF0aHJte3Rva30pfQ0KTF97aSxqLG19LA0KXHFxdWFkDQp0PTUoaS0xKStqLg0KXF0NCg0KUGFkYSBpbHVzdHJhc2kgaW5pLCBcKENfTD0xXCkgZGFuIFwobj0xLDJcKS4gT2xlaCBrYXJlbmEgaXR1LCBwZXJoaXR1bmdhbiB0b2tlbiBkYXBhdCBkaXNlZGVyaGFuYWthbiBtZW5qYWRpOg0KDQpcWw0KXG1hdGhiZntUfV90DQo9DQpMX3tpLGp9DQpcbWF0aGJme1d9X3tcbWF0aHJte3B3fX1eeyhcbWF0aHJte3Rva30pfS4NClxdDQoNCk1hdHJpa3MgdG9rZW4gXChcbWF0aGJme1R9XCkgYmVyZGltZW5zaSBcKDI1XHRpbWVzMlwpLg0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuIHBhZGEgcG9zaXNpIFwoKDEsMSlcKToqKg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcbWF0aGJme1R9XzENCiY9DQpMX3sxLDF9DQpcbWF0aGJme1d9X3tcbWF0aHJte3B3fX1eeyhcbWF0aHJte3Rva30pfVxcDQomPQ0KKC0wLjI4KQ0KXGJlZ2lue2JtYXRyaXh9DQowLjgwICYgLTAuNjANClxlbmR7Ym1hdHJpeH1cXA0KJj0NClxiZWdpbntibWF0cml4fQ0KLTAuMjIgJiAwLjE3DQpcZW5ke2JtYXRyaXh9Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KUG9zaXNpIHNwYXNpYWwgXCgoMSwxKVwpIG1lcnVwYWthbiB0b2tlbiBwZXJ0YW1hIGthcmVuYToNCg0KXFsNCnQ9NSgxLTEpKzE9MS4NClxdDQoNCkRlbmdhbiBwZXJoaXR1bmdhbiB5YW5nIHNhbWEgcGFkYSBzZWx1cnVoIHBvc2lzaSBiZXJkYXNhcmthbiB1cnV0YW4gcmFzdGVyIGRhcmkga2lyaSBrZSBrYW5hbiBkYW4gZGFyaSBhdGFzIGtlIGJhd2FoLCBkaXBlcm9sZWggbWF0cmlrcyB0b2tlbjoNCg0KXFsNClxtYXRoYmZ7VH0NCj0NClxiZWdpbntibWF0cml4fQ0KLTAuMjIgJiAwLjE3XFwNCi0wLjE3ICYgMC4xM1xcDQowLjMwICYgLTAuMjJcXA0KMC4xNCAmIC0wLjEwXFwNCi0wLjE4ICYgMC4xNFxcDQotMC4yMiAmIDAuMTdcXA0KLTAuMTcgJiAwLjEzXFwNCjAuNDcgJiAtMC4zNVxcDQowLjI0ICYgLTAuMThcXA0KLTAuMTkgJiAwLjE0XFwNCi0wLjIyICYgMC4xN1xcDQotMC4xNyAmIDAuMTNcXA0KMC40OCAmIC0wLjM2XFwNCjAuMjQgJiAtMC4xOFxcDQotMC4xOSAmIDAuMTRcXA0KLTAuMjIgJiAwLjE3XFwNCi0wLjE5ICYgMC4xNVxcDQowLjI4ICYgLTAuMjFcXA0KMC4wOSAmIC0wLjA3XFwNCi0wLjIwICYgMC4xNVxcDQotMC4yMiAmIDAuMTdcXA0KLTAuMjAgJiAwLjE1XFwNCjAuMDQgJiAtMC4wM1xcDQotMC4wNiAmIDAuMDVcXA0KLTAuMjAgJiAwLjE1DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KDQojIyAzLiBMaW5lYXIgVHJhbnNmb3JtZXIgKCpTZXBhcmFibGUgU2VsZi1BdHRlbnRpb24qKQ0KDQpQYWRhIE1vYmlsZVZpVHYzLXYyLCBtYXRyaWtzIHRva2VuIFwoXG1hdGhiZntUfVwpIGRpcHJvc2VzIG1lbmdndW5ha2FuIG1la2FuaXNtZSAqc2VwYXJhYmxlIHNlbGYtYXR0ZW50aW9uKiAoU1NBKS4gQmVyYmVkYSBkZW5nYW4gVHJhbnNmb3JtZXIgdjEgeWFuZyBtZW5naGl0dW5nIGh1YnVuZ2FuIHBlcmhhdGlhbiBhbnRhcnNldGlhcCBwYXNhbmdhbiB0b2tlbiwgU1NBIG1lbWJlbnR1ayB2ZWt0b3Iga29lZmlzaWVuIGtvbnRla3MgdW50dWsgbWVyYW5na3VtIGluZm9ybWFzaSBnbG9iYWwgZGFyaSBzZWx1cnVoIHRva2VuLiBLZWx1YXJhbiBTU0Ega2VtdWRpYW4gZGlnYWJ1bmdrYW4gZGVuZ2FuIHRva2VuIG1hc3VrYW4gbWVsYWx1aSAqcmVzaWR1YWwgY29ubmVjdGlvbiogZGFuIGRpcHJvc2VzIG9sZWggKmZlZWQtZm9yd2FyZCBuZXR3b3JrKi4NCg0KUGFkYSBmb3JtdWxhc2kgU1NBIGRpIEJhYiBJSSwgXChcbWF0aGJme1h9XCkgbWVueWF0YWthbiBtYXRyaWtzIHRva2VuIG1hc3VrYW4gc2VjYXJhIHVtdW0uIERhbGFtIGlsdXN0cmFzaSBwZXJoaXR1bmdhbiBpbmksIG1hdHJpa3MgdGVyc2VidXQgZGlyZWFsaXNhc2lrYW4gb2xlaCBcKFxtYXRoYmZ7VH1cKSwgc2VoaW5nZ2E6DQoNClxbDQpcbWF0aGJme1h9DQo9DQpcbWF0aGJme1R9Lg0KXF0NCg0KIyMjIGEuIFByb3lla3NpICpBdHRlbnRpb24gU2NvcmUqDQoNClNldGlhcCB0b2tlbiBwYWRhIFwoXG1hdGhiZntUfVwpIGRpcHJveWVrc2lrYW4gbWVuamFkaSBzYXR1IG5pbGFpICphdHRlbnRpb24gc2NvcmUqIG1lbmdndW5ha2FuIG1hdHJpa3MgYm9ib3QgXChcbWF0aGJme1d9XntJfVwpLiBOaWxhaSAqYXR0ZW50aW9uIHNjb3JlKiBzZWJlbHVtIHByb3NlcyBzb2Z0bWF4IGRpbnlhdGFrYW4gc2ViYWdhaSB2ZWt0b3IgXChcbWF0aGJme3N9XCkuDQoNCi0gKipCb2JvdCBwcm95ZWtzaSAqYXR0ZW50aW9uIHNjb3JlKjoqKg0KDQpcWw0KXG1hdGhiZntXfV57SX0NCj0NClxiZWdpbntibWF0cml4fQ0KMC42MFxcDQotMC4zNQ0KXGVuZHtibWF0cml4fS4NClxdDQoNCk1hdHJpa3MgXChcbWF0aGJme1d9XntJfVwpIGJlcnVrdXJhbiBcKDJcdGltZXMxXCkuIE9sZWgga2FyZW5hIGl0dSwgdmVrdG9yICphdHRlbnRpb24gc2NvcmUqIFwoXG1hdGhiZntzfVwpIGJlcnVrdXJhbiBcKDI1XHRpbWVzMVwpLg0KDQotICoqUnVtdXM6KioNCg0KXFsNClxtYXRoYmZ7c30NCj0NClxtYXRoYmZ7VH1cbWF0aGJme1d9XntJfS4NClxdDQoNClNlY2FyYSBlbGVtZW4sICphdHRlbnRpb24gc2NvcmUqIHRva2VuIGtlLVwodFwpIGRpaGl0dW5nIHNlYmFnYWk6DQoNClxbDQpzX3QNCj0NClxzdW1fe249MX1eezJ9DQpUX3t0LG59V197biwxfV57SX0uDQpcXQ0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuIHRva2VuIHBlcnRhbWE6KioNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0Kc18xDQomPQ0KXGJlZ2lue2JtYXRyaXh9DQotMC4yMiAmIDAuMTcNClxlbmR7Ym1hdHJpeH0NClxiZWdpbntibWF0cml4fQ0KMC42MFxcDQotMC4zNQ0KXGVuZHtibWF0cml4fVxcDQomPQ0KMC42MCgtMC4yMiktMC4zNSgwLjE3KVxcDQomPQ0KLTAuMTMyLTAuMDU5NVxcDQomPQ0KLTAuMTkuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gYXR1cmFuIHlhbmcgc2FtYSwgZGlwZXJvbGVoIHZla3RvciAqYXR0ZW50aW9uIHNjb3JlKiBzZWJhZ2FpIGJlcmlrdXQuDQoNClxbDQpcbWF0aGJme3N9DQo9DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjE5XFwNCi0wLjE1XFwNCjAuMjZcXA0KMC4xMlxcDQotMC4xNlxcDQotMC4xOVxcDQotMC4xNVxcDQowLjQwXFwNCjAuMjFcXA0KLTAuMTZcXA0KLTAuMTlcXA0KLTAuMTVcXA0KMC40MVxcDQowLjIxXFwNCi0wLjE2XFwNCi0wLjE5XFwNCi0wLjE3XFwNCjAuMjRcXA0KMC4wOFxcDQotMC4xN1xcDQotMC4xOVxcDQotMC4xN1xcDQowLjAzXFwNCi0wLjA1XFwNCi0wLjE3DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KDQojIyMgYi4gS29lZmlzaWVuIGtvbnRla3MNCg0KTmlsYWkgYXR0ZW50aW9uIHNjb3JlIGtlbXVkaWFuIGRpbm9ybWFsaXNhc2kgbWVuZ2d1bmFrYW4gc29mdG1heCB1bnR1ayBtZW5naGFzaWxrYW4ga29lZmlzaWVuIGtvbnRla3MgXChjX3NcKS4gSnVtbGFoIHNlbHVydWgga29lZmlzaWVuIGtvbnRla3MgYmVybmlsYWkgc2F0dS4gTmlsYWkgYXR0ZW50aW9uIHNjb3JlIFwocVwpIGRpbm9ybWFsaXNhc2kgbWVuZ2d1bmFrYW4gZnVuZ3NpIHNvZnRtYXggdW50dWsgbWVuZ2hhc2lsa2FuIGtvZWZpc2llbiBrb250ZWtzIFwoY19zXCkuIE5vdGFzaSBcKGVee3FfdH1cKSBtZW55YXRha2FuIG5pbGFpIGVrc3BvbmVuc2lhbCBkYXJpIGF0dGVudGlvbiBzY29yZSB0b2tlbiB5YW5nIHNlZGFuZyBkaWhpdHVuZywgeWFpdHUgdG9rZW4ga2UtXCh0XCkuIFNlbWVudGFyYSBpdHUsIFwoXHN1bV97cj0xfV57MjV9ZV57cV9yfVwpIG1lbnlhdGFrYW4ganVtbGFoIG5pbGFpIGVrc3BvbmVuc2lhbCBkYXJpIHNlbHVydWggMjUgdG9rZW4uIERlbmdhbiBkZW1pa2lhbiwgc2V0aWFwIG5pbGFpIFwoY197cyx0fVwpIG1lbnVuanVra2FuIHByb3BvcnNpIGtvbnRyaWJ1c2kgdG9rZW4ga2UtXCh0XCkgdGVyaGFkYXAgcGVtYmVudHVrYW4gdmVrdG9yIGtvbnRla3MgZ2xvYmFsLCBkYW4ganVtbGFoIHNlbHVydWgga29lZmlzaWVuIGtvbnRla3MgYmVybmlsYWkgc2F0dS4NCg0KDQotICoqUnVtdXM6KioNCg0KXFsNCmNfe3MsdH0NCj0NClxmcmFje2Vee3FfdH19DQp7XHN1bV97cj0xfV57MjV9ZV57cV9yfX0uDQpcXQ0KDQotICoqQ29udG9oIHRva2VuIHBlcnRhbWE6KioNCg0KVW50dWsgbWVuZ2hpdHVuZyBrb2VmaXNpZW4ga29udGVrcyB0b2tlbiBwZXJ0YW1hLCBuaWxhaSBla3Nwb25lbnNpYWwgKmF0dGVudGlvbiBzY29yZSogdG9rZW4gcGVydGFtYSBkaWJhZ2kgZGVuZ2FuIGp1bWxhaCBuaWxhaSBla3Nwb25lbnNpYWwgZGFyaSBzZWx1cnVoIDI1IHRva2VuIHNlYmFnYWkgYmVyaWt1dC4NCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KY197cywxfQ0KJj0NClxmcmFje2Veey0wLjE5MTZ9fQ0Ke2Veey0wLjE5MTZ9K2Veey0wLjE0ODV9K1xjZG90cytlXnstMC4xNzM4fX1cXA0KJj0NClxmcmFjezAuODI1Nn0NCnswLjgyNTYrMC44NjIwK1xjZG90cyswLjg0MDV9XFwNCiY9DQpcZnJhY3swLjgyNTZ9ezI0Ljg3MzR9XFwNCiY9DQowLjAzMzJcXA0KJj0NCjAuMDMuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gYXR1cmFuIHlhbmcgc2FtYSwgZGlwZXJvbGVoIGtvZWZpc2llbiBrb250ZWtzIHNlYmFnYWkgYmVyaWt1dC4NCg0KXFsNCmNfcz0NClxiZWdpbntibWF0cml4fQ0KMC4wM1xcDQowLjAzXFwNCjAuMDVcXA0KMC4wNVxcDQowLjAzXFwNCjAuMDNcXA0KMC4wM1xcDQowLjA3XFwNCjAuMDVcXA0KMC4wM1xcDQowLjAzXFwNCjAuMDNcXA0KMC4wN1xcDQowLjA1XFwNCjAuMDNcXA0KMC4wM1xcDQowLjAzXFwNCjAuMDZcXA0KMC4wNFxcDQowLjAzXFwNCjAuMDNcXA0KMC4wM1xcDQowLjA0XFwNCjAuMDRcXA0KMC4wMw0KXGVuZHtibWF0cml4fS4NClxdDQoNCiMjIyBjLiBQcm95ZWtzaSAqS2V5Kg0KDQpQYWRhIGZvcm11bGFzaSAqc2VwYXJhYmxlIHNlbGYtYXR0ZW50aW9uKiwgbWF0cmlrcyAqa2V5KiBkaWJlbnR1ayBkYXJpIG1hdHJpa3MgdG9rZW4gbWFzdWthbiBtZW5nZ3VuYWthbiBib2JvdCBcKFxtYXRoYmZ7V31ee0t9XCkuIERhbGFtIGlsdXN0cmFzaSBpbmksIG1hdHJpa3MgdG9rZW4gXChcbWF0aGJme1R9XCkgbWVyZWFsaXNhc2lrYW4gXChcbWF0aGJme1h9XCkgcGFkYSBQZXJzYW1hYW4gKDIuMjEpLg0KDQotICoqQm9ib3QgcHJveWVrc2kgKmtleSo6KioNCg0KXFsNClxtYXRoYmZ7V31ee0t9DQo9DQpcYmVnaW57Ym1hdHJpeH0NCjAuNTUgJiAwLjEwXFwNCi0wLjE1ICYgMC40NQ0KXGVuZHtibWF0cml4fS4NClxdDQoNCk1hdHJpa3MgXChcbWF0aGJme1d9XntLfVwpIGJlcnVrdXJhbiBcKDJcdGltZXMyXCkuDQoNCi0gKipSdW11czoqKg0KDQpcWw0KXG1hdGhiZntLfQ0KPQ0KXG1hdGhiZntUfVxtYXRoYmZ7V31ee0t9Lg0KXF0NCg0KTWF0cmlrcyAqa2V5KiBcKFxtYXRoYmZ7S31cKSBiZXJ1a3VyYW4gXCgyNVx0aW1lczJcKS4NCg0KU2VjYXJhIGVsZW1lbiwga29tcG9uZW4gKmtleSoga2UtXChuXCkgcGFkYSB0b2tlbiBrZS1cKHRcKSBkaWhpdHVuZyBzZWJhZ2FpOg0KDQpcWw0KS197dCxufQ0KPQ0KXHN1bV97bT0xfV57Mn0NClRfe3QsbX1XX3ttLG59XntLfS4NClxdDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gdG9rZW4gcGVydGFtYToqKg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcbWF0aGJme0t9XzENCiY9DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjIyICYgMC4xNw0KXGVuZHtibWF0cml4fQ0KXGJlZ2lue2JtYXRyaXh9DQowLjU1ICYgMC4xMFxcDQotMC4xNSAmIDAuNDUNClxlbmR7Ym1hdHJpeH1cXA0KJj0NClxiZWdpbntibWF0cml4fQ0KKC0wLjIyKSgwLjU1KSsoMC4xNykoLTAuMTUpICYNCigtMC4yMikoMC4xMCkrKDAuMTcpKDAuNDUpDQpcZW5ke2JtYXRyaXh9XFwNCiY9DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjE0NjUgJiAwLjA1NDUNClxlbmR7Ym1hdHJpeH1cXA0KJj0NClxiZWdpbntibWF0cml4fQ0KLTAuMTUgJiAwLjA1DQpcZW5ke2JtYXRyaXh9Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KRGVuZ2FuIGF0dXJhbiB5YW5nIHNhbWEsIGRpcGVyb2xlaCBtYXRyaWtzICprZXkqIHNlYmFnYWkgYmVyaWt1dC4NCg0KXFsNClxtYXRoYmZ7S30NCj0NClxiZWdpbntibWF0cml4fQ0KLTAuMTUgJiAwLjA1XFwNCi0wLjExICYgMC4wNFxcDQowLjIwICYgLTAuMDdcXA0KMC4wOSAmIC0wLjAzXFwNCi0wLjEyICYgMC4wNFxcDQotMC4xNSAmIDAuMDVcXA0KLTAuMTIgJiAwLjA0XFwNCjAuMzEgJiAtMC4xMVxcDQowLjE2ICYgLTAuMDZcXA0KLTAuMTIgJiAwLjA0XFwNCi0wLjE1ICYgMC4wNVxcDQotMC4xMSAmIDAuMDRcXA0KMC4zMSAmIC0wLjExXFwNCjAuMTYgJiAtMC4wNlxcDQotMC4xMiAmIDAuMDRcXA0KLTAuMTUgJiAwLjA1XFwNCi0wLjEzICYgMC4wNVxcDQowLjE5ICYgLTAuMDdcXA0KMC4wNiAmIC0wLjAyXFwNCi0wLjEzICYgMC4wNVxcDQotMC4xNSAmIDAuMDVcXA0KLTAuMTMgJiAwLjA1XFwNCjAuMDMgJiAtMC4wMVxcDQotMC4wNCAmIDAuMDJcXA0KLTAuMTMgJiAwLjA1DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KIyMjIGQuIFByb3lla3NpICpWYWx1ZSoNCg0KUGFkYSBmb3JtdWxhc2kgKnNlcGFyYWJsZSBzZWxmLWF0dGVudGlvbiosIG1hdHJpa3MgKnZhbHVlKiBkaWJlbnR1ayBkYXJpIG1hdHJpa3MgdG9rZW4gbWFzdWthbiBtZW5nZ3VuYWthbiBib2JvdCBwcm95ZWtzaSBcKFxtYXRoYmZ7V31ee1Z9XCkuIERhbGFtIGlsdXN0cmFzaSBpbmksIG1hdHJpa3MgdG9rZW4gXChcbWF0aGJme1R9XCkgbWVyZWFsaXNhc2lrYW4gXChcbWF0aGJme1h9XCkgcGFkYSBQZXJzYW1hYW4gKDIuMjIpLg0KDQotICoqQm9ib3QgcHJveWVrc2kgKnZhbHVlKjoqKg0KDQpcWw0KXG1hdGhiZntXfV57Vn0NCj0NClxiZWdpbntibWF0cml4fQ0KMC43MCAmIC0wLjIwXFwNCjAuMjUgJiAwLjYwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KTWF0cmlrcyBcKFxtYXRoYmZ7V31ee1Z9XCkgYmVydWt1cmFuIFwoMlx0aW1lczJcKS4gS2FyZW5hIG1hdHJpa3MgXChcbWF0aGJme1R9XCkgYmVydWt1cmFuIFwoMjVcdGltZXMyXCksIG1ha2EgbWF0cmlrcyAqdmFsdWUqIFwoXG1hdGhiZntWfVwpIGJlcnVrdXJhbiBcKDI1XHRpbWVzMlwpLg0KDQotICoqUnVtdXM6KioNCg0KXFsNClxtYXRoYmZ7Vn0NCj0NClxtYXRoYmZ7VH1cbWF0aGJme1d9XntWfS4NClxdDQoNClNlY2FyYSBlbGVtZW4sIGtvbXBvbmVuICp2YWx1ZSoga2UtXChuXCkgcGFkYSB0b2tlbiBrZS1cKHRcKSBkaWhpdHVuZyBzZWJhZ2FpOg0KDQpcWw0KVl97dCxufQ0KPQ0KXHN1bV97bT0xfV57Mn0NClRfe3QsbX1XX3ttLG59XntWfS4NClxdDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gdG9rZW4gcGVydGFtYToqKg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcbWF0aGJme1Z9XzENCiY9DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjIyICYgMC4xNw0KXGVuZHtibWF0cml4fQ0KXGJlZ2lue2JtYXRyaXh9DQowLjcwICYgLTAuMjBcXA0KMC4yNSAmIDAuNjANClxlbmR7Ym1hdHJpeH1cXA0KJj0NClxiZWdpbntibWF0cml4fQ0KKC0wLjIyKSgwLjcwKSsoMC4xNykoMC4yNSkNCiYNCigtMC4yMikoLTAuMjApKygwLjE3KSgwLjYwKQ0KXGVuZHtibWF0cml4fVxcDQomPQ0KXGJlZ2lue2JtYXRyaXh9DQotMC4xMTE1ICYgMC4xNDYwDQpcZW5ke2JtYXRyaXh9XFwNCiY9DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjExICYgMC4xNQ0KXGVuZHtibWF0cml4fS4NClxlbmR7YWxpZ25lZH0NClxdDQoNClBhZGEgdGFoYXAga2VsdWFyYW4gU1NBLCBtYXRyaWtzIFwoXG1hdGhiZntWfVwpIHNlbGFuanV0bnlhIGRpcHJvc2VzIG1lbmdndW5ha2FuIGZ1bmdzaSBSZUxVIHNlc3VhaSBQZXJzYW1hYW4gKDIuMjIpLg0KDQpEZW5nYW4gYXR1cmFuIHlhbmcgc2FtYSwgZGlwZXJvbGVoIG1hdHJpa3MgKnZhbHVlKiBzZWJhZ2FpIGJlcmlrdXQuDQoNClxbDQpcbWF0aGJme1Z9DQo9DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjExICYgMC4xNFxcDQotMC4wOSAmIDAuMTFcXA0KMC4xNSAmIC0wLjE5XFwNCjAuMDcgJiAtMC4wOVxcDQotMC4wOSAmIDAuMTJcXA0KLTAuMTEgJiAwLjE0XFwNCi0wLjA5ICYgMC4xMVxcDQowLjI0ICYgLTAuMzFcXA0KMC4xMyAmIC0wLjE2XFwNCi0wLjEwICYgMC4xMlxcDQotMC4xMSAmIDAuMTRcXA0KLTAuMDkgJiAwLjExXFwNCjAuMjQgJiAtMC4zMVxcDQowLjEzICYgLTAuMTZcXA0KLTAuMTAgJiAwLjEyXFwNCi0wLjExICYgMC4xNFxcDQotMC4xMCAmIDAuMTNcXA0KMC4xNCAmIC0wLjE4XFwNCjAuMDUgJiAtMC4wNlxcDQotMC4xMCAmIDAuMTNcXA0KLTAuMTEgJiAwLjE0XFwNCi0wLjEwICYgMC4xM1xcDQowLjAyICYgLTAuMDNcXA0KLTAuMDMgJiAwLjA0XFwNCi0wLjEwICYgMC4xMw0KXGVuZHtibWF0cml4fS4NClxdDQoNCiMjIyBlLiBQZW1iZW50dWthbiB2ZWt0b3Iga29udGVrcw0KDQpWZWt0b3Iga29udGVrcyBcKFxtYXRoYmZ7Y31fdlwpIGRpcGVyb2xlaCBkZW5nYW4gbWVuZ2dhYnVuZ2thbiBzZWx1cnVoIGJhcmlzIG1hdHJpa3Mga2V5IFwoXG1hdGhiZntLfVwpIG1lbmdndW5ha2FuIGtvZWZpc2llbiBrb250ZWtzIHBhZGEgdmVrdG9yIFwoXG1hdGhiZntjfV9zXCkuIFNldGlhcCB0b2tlbiBrZXkgZGliZXJpIGJvYm90IHNlc3VhaSBuaWxhaSBrb2VmaXNpZW4ga29udGVrc255YS4gVG9rZW4gZGVuZ2FuIG5pbGFpIFwoY197cyx0fVwpIHlhbmcgbGViaWggYmVzYXIgbWVtYmVyaWthbiBrb250cmlidXNpIHlhbmcgbGViaWggYmVzYXIgdGVyaGFkYXAgcGVtYmVudHVrYW4gdmVrdG9yIGtvbnRla3MgZ2xvYmFsLg0KDQotICoqUnVtdXM6KioNCg0KXFsNClxtYXRoYmZ7Y31fdg0KPQ0KXG1hdGhiZntjfV9zXntcbWF0aHNme1R9fVxtYXRoYmZ7S30NCj0NClxzdW1fe3Q9MX1eezI1fWNfe3MsdH1cbWF0aGJme0t9X3t0LDp9Lg0KXF0NCg0KS2FyZW5hIFwoXG1hdGhiZntjfV9zXntcbWF0aHNme1R9fVwpIGJlcnVrdXJhbiBcKDFcdGltZXMyNVwpIGRhbiBcKFxtYXRoYmZ7S31cKSBiZXJ1a3VyYW4gXCgyNVx0aW1lczJcKSwgbWFrYSB2ZWt0b3Iga29udGVrcyBcKFxtYXRoYmZ7Y31fdlwpIGJlcnVrdXJhbiBcKDFcdGltZXMyXCkuDQoNClxbDQooMVx0aW1lczI1KSgyNVx0aW1lczIpPSgxXHRpbWVzMikuDQpcXQ0KDQpVbnR1ayBzZXRpYXAgZWxlbWVuIGtlLVwoblwpLCBwZXJoaXR1bmdhbm55YSBhZGFsYWg6DQoNClxbDQpjX3t2LG59DQo9DQpcc3VtX3t0PTF9XnsyNX1jX3tzLHR9S197dCxufSwNClxxcXVhZCBuPTEsMi4NClxdDQoNCi0gKipQZXJoaXR1bmdhbiBlbGVtZW4gcGVydGFtYToqKg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpjX3t2LDF9DQomPQ0KY197cywxfUtfezEsMX0NCitjX3tzLDJ9S197MiwxfQ0KK1xjZG90cw0KK2Nfe3MsMjV9S197MjUsMX1cXA0KJj0NCigwLjAzKSgtMC4xNSkNCisoMC4wMykoLTAuMTEpDQorXGNkb3RzDQorKDAuMDMpKC0wLjEzKVxcDQomPTAuMDEuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQotICoqUGVyaGl0dW5nYW4gZWxlbWVuIGtlZHVhOioqDQoNClxbDQpcYmVnaW57YWxpZ25lZH0NCmNfe3YsMn0NCiY9DQpjX3tzLDF9S197MSwyfQ0KK2Nfe3MsMn1LX3syLDJ9DQorXGNkb3RzDQorY197cywyNX1LX3syNSwyfVxcDQomPQ0KKDAuMDMpKDAuMDUpDQorKDAuMDMpKDAuMDQpDQorXGNkb3RzDQorKDAuMDMpKDAuMDUpXFwNCiY9LTAuMDA1Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KUGVyaGl0dW5nYW4gZGlsYWt1a2FuIG1lbmdndW5ha2FuIG5pbGFpIFwoXG1hdGhiZntjfV9zXCkgZGFuIFwoXG1hdGhiZntLfVwpIGRlbmdhbiBwcmVzaXNpIHBlbnVoIHNlYmVsdW0gaGFzaWwgYWtoaXIgZGl0YW1waWxrYW4uIE5pbGFpIGRpdGFtcGlsa2FuIGhpbmdnYSBkdWEgYW5na2EgZGkgYmVsYWthbmcga29tYSwga2VjdWFsaSBlbGVtZW4ga2VkdWEgeWFuZyBkaXRhbXBpbGthbiBoaW5nZ2EgdGlnYSBhbmdrYSBkaSBiZWxha2FuZyBrb21hIGFnYXIgdGlkYWsgbWVuamFkaSBcKC0wLjAwXCkuIE9sZWgga2FyZW5hIGl0dSwgZGlwZXJvbGVoIHZla3RvciBrb250ZWtzOg0KDQpcWw0KXG1hdGhiZntjfV92PQ0KXGJlZ2lue2JtYXRyaXh9DQowLjAxICYgLTAuMDA1DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KIyMjIGYuIEtlbHVhcmFuIHNlcGFyYWJsZSBzZWxmLWF0dGVudGlvbg0KDQpLZWx1YXJhbiAqc2VwYXJhYmxlIHNlbGYtYXR0ZW50aW9uKiBkaWJlbnR1ayBkZW5nYW4gbWVuZXJhcGthbiBmdW5nc2kgUmVMVSBwYWRhIHNldGlhcCBlbGVtZW4gbWF0cmlrcyB2YWx1ZSBcKFxtYXRoYmZ7Vn1cKS4gRnVuZ3NpIFJlTFUgbWVtcGVydGFoYW5rYW4gbmlsYWkgcG9zaXRpZiBkYW4gbWVuZ3ViYWggbmlsYWkgbmVnYXRpZiBtZW5qYWRpIG5vbC4gSGFzaWwgYWt0aXZhc2kgdGVyc2VidXQga2VtdWRpYW4gZGlrYWxpa2FuIHNlY2FyYSBlbGVtZW4gZGVtaSBlbGVtZW4gZGVuZ2FuIHZla3RvciBrb250ZWtzIGdsb2JhbCBcKFxtYXRoYmZ7Y31fdlwpLCBsYWx1IGRpcHJveWVrc2lrYW4gbWVuZ2d1bmFrYW4gYm9ib3Qga2VsdWFyYW4gXChcbWF0aGJme1d9XntPfVwpLg0KDQpQYWRhIGlsdXN0cmFzaSBpbmksIHZla3RvciBrb250ZWtzIGdsb2JhbCBzZWJlbHVtIHBlbWJ1bGF0YW4gYWRhbGFoOg0KDQpcWw0KXG1hdGhiZntjfV92PQ0KXGJlZ2lue2JtYXRyaXh9DQowLjAxMzIgJiAtMC4wMDQ3DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KLSAqKkJvYm90IGtlbHVhcmFuOioqDQoNClxbDQpcbWF0aGJme1d9XntPfT0NClxiZWdpbntibWF0cml4fQ0KNTAuMDAgJiAtMjAuMDBcXA0KNTAuMDAgJiA1MC4wMA0KXGVuZHtibWF0cml4fS4NClxdDQoNCkJvYm90IFwoXG1hdGhiZntXfV57T31cKSBtZXJ1cGFrYW4gYm9ib3QgaWx1c3RyYXRpZiB5YW5nIGRpZ3VuYWthbiB1bnR1ayBtZW1wcm95ZWtzaWthbiBoYXNpbCAqc2VwYXJhYmxlIHNlbGYtYXR0ZW50aW9uKi4gTmlsYWkgdGVyc2VidXQgZGlwaWxpaCBhZ2FyIGtlbHVhcmFuIHRldGFwIGRhcGF0IGRpdGFtcGlsa2FuIHNlY2FyYSBqZWxhcyBzZXRlbGFoIHBlbWJ1bGF0YW4uDQoNCi0gKipSdW11czoqKg0KDQpTZXN1YWkgUGVyc2FtYWFuICgyLjIyKSBwYWRhIGRyYWZ0LCBrZWx1YXJhbiAqc2VwYXJhYmxlIHNlbGYtYXR0ZW50aW9uKiBkaXJ1bXVza2FuIHNlYmFnYWk6DQoNClxbDQpcbWF0aGJme1p9X3tcbWF0aHJte1NTQX19DQo9DQpcbGVmdCgNClxtYXRoYmZ7Y31fdg0KXG9kb3QNClxvcGVyYXRvcm5hbWV7UmVMVX0oXG1hdGhiZntWfSkNClxyaWdodCkNClxtYXRoYmZ7V31ee099Lg0KXF0NCg0KVmVrdG9yIFwoXG1hdGhiZntjfV92XCkgYmVydWt1cmFuIFwoMVx0aW1lczJcKSBkaXRlcmFwa2FuIHBhZGEgc2V0aWFwIGJhcmlzIG1hdHJpa3MgXChcb3BlcmF0b3JuYW1le1JlTFV9KFxtYXRoYmZ7Vn0pXCkgeWFuZyBiZXJ1a3VyYW4gXCgyNVx0aW1lczJcKS4gT2xlaCBrYXJlbmEgaXR1LCBoYXNpbCBwZXJrYWxpYW4gZWxlbWVuIGRlbWkgZWxlbWVuIGJlcnVrdXJhbiBcKDI1XHRpbWVzMlwpLiBTZXRlbGFoIGRpa2FsaWthbiBkZW5nYW4gXChcbWF0aGJme1d9XntPfVwpIHlhbmcgYmVydWt1cmFuIFwoMlx0aW1lczJcKSwgZGlwZXJvbGVoIG1hdHJpa3MgXChcbWF0aGJme1p9X3tcbWF0aHJte1NTQX19XCkgYmVydWt1cmFuIFwoMjVcdGltZXMyXCkuDQoNClxbDQpcb3BlcmF0b3JuYW1le1JlTFV9KFZfe3Qsbn0pDQo9DQpcbWF4KDAsVl97dCxufSkuDQpcXQ0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuIHRva2VuIHBlcnRhbWE6KioNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KXG1hdGhiZntafV97XG1hdGhybXtTU0F9LDF9DQomPQ0KXGxlZnQoDQpcbWF0aGJme2N9X3YNClxvZG90DQpcb3BlcmF0b3JuYW1le1JlTFV9KFxtYXRoYmZ7Vn1fezF9KQ0KXHJpZ2h0KQ0KXG1hdGhiZntXfV57T31cXA0KJj0NClxsZWZ0KA0KXGJlZ2lue2JtYXRyaXh9DQowLjAxMzIgJiAtMC4wMDQ3DQpcZW5ke2JtYXRyaXh9DQpcb2RvdA0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGJlZ2lue2JtYXRyaXh9DQotMC4xMSAmIDAuMTQNClxlbmR7Ym1hdHJpeH0NClxyaWdodCkNClxiZWdpbntibWF0cml4fQ0KNTAuMDAgJiAtMjAuMDBcXA0KNTAuMDAgJiA1MC4wMA0KXGVuZHtibWF0cml4fVxcDQomPQ0KXGxlZnQoDQpcYmVnaW57Ym1hdHJpeH0NCjAuMDEzMiAmIC0wLjAwNDcNClxlbmR7Ym1hdHJpeH0NClxvZG90DQpcYmVnaW57Ym1hdHJpeH0NCjAuMDAgJiAwLjE0DQpcZW5ke2JtYXRyaXh9DQpccmlnaHQpDQpcYmVnaW57Ym1hdHJpeH0NCjUwLjAwICYgLTIwLjAwXFwNCjUwLjAwICYgNTAuMDANClxlbmR7Ym1hdHJpeH1cXA0KJj0NClxiZWdpbntibWF0cml4fQ0KMC4wMCAmIC0wLjAwMDcNClxlbmR7Ym1hdHJpeH0NClxiZWdpbntibWF0cml4fQ0KNTAuMDAgJiAtMjAuMDBcXA0KNTAuMDAgJiA1MC4wMA0KXGVuZHtibWF0cml4fVxcDQomPQ0KXGJlZ2lue2JtYXRyaXh9DQotMC4wMyAmIC0wLjAzDQpcZW5ke2JtYXRyaXh9Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KRGVuZ2FuIGF0dXJhbiB5YW5nIHNhbWEsIGRpcGVyb2xlaCBrZWx1YXJhbiAqc2VwYXJhYmxlIHNlbGYtYXR0ZW50aW9uKiBzZWJhZ2FpIGJlcmlrdXQuDQoNClxbDQpcbWF0aGJme1p9X3tcbWF0aHJte1NTQX19PQ0KXGJlZ2lue2JtYXRyaXh9DQotMC4wMyAmIC0wLjAzXFwNCi0wLjAzICYgLTAuMDNcXA0KMC4xMCAmIC0wLjA0XFwNCjAuMDUgJiAtMC4wMlxcDQotMC4wMyAmIC0wLjAzXFwNCi0wLjAzICYgLTAuMDNcXA0KLTAuMDMgJiAtMC4wM1xcDQowLjE2ICYgLTAuMDZcXA0KMC4wOCAmIC0wLjAzXFwNCi0wLjAzICYgLTAuMDNcXA0KLTAuMDMgJiAtMC4wM1xcDQotMC4wMyAmIC0wLjAzXFwNCjAuMTYgJiAtMC4wNlxcDQowLjA4ICYgLTAuMDNcXA0KLTAuMDMgJiAtMC4wM1xcDQotMC4wMyAmIC0wLjAzXFwNCi0wLjAzICYgLTAuMDNcXA0KMC4xMCAmIC0wLjA0XFwNCjAuMDMgJiAtMC4wMVxcDQotMC4wMyAmIC0wLjAzXFwNCi0wLjAzICYgLTAuMDNcXA0KLTAuMDMgJiAtMC4wM1xcDQowLjAxICYgLTAuMDA1XFwNCi0wLjAxICYgLTAuMDFcXA0KLTAuMDMgJiAtMC4wMw0KXGVuZHtibWF0cml4fS4NClxdDQoNCk5pbGFpIGRpaGl0dW5nIG1lbmdndW5ha2FuIHByZXNpc2kgcGVudWggc2ViZWx1bSBkaXRhbXBpbGthbi4gSGFzaWwgZGl0dWxpcyBoaW5nZ2EgZHVhIGFuZ2thIGRpIGJlbGFrYW5nIGtvbWEsIGtlY3VhbGkgbmlsYWkgXCgtMC4wMDVcKSBhZ2FyIHRpZGFrIGRpdGFtcGlsa2FuIHNlYmFnYWkgXCgtMC4wMFwpLg0KDQoNCiMjIyBnLiBSZXNpZHVhbCBzZXBhcmFibGUgc2VsZi1hdHRlbnRpb24NCg0KS2VsdWFyYW4gKnNlcGFyYWJsZSBzZWxmLWF0dGVudGlvbiogXChcbWF0aGJme1p9X3tcbWF0aHJte1NTQX19XCkgc2VsYW5qdXRueWEgZGlnYWJ1bmdrYW4gZGVuZ2FuIG1hdHJpa3MgdG9rZW4gbWFzdWthbiBcKFxtYXRoYmZ7VH1cKSBtZWxhbHVpICpyZXNpZHVhbCBjb25uZWN0aW9uKi4gUHJvc2VzIGluaSBtZW1wZXJ0YWhhbmthbiBpbmZvcm1hc2kgYXdhbCBzZXRpYXAgdG9rZW4gc2VrYWxpZ3VzIG1lbmFtYmFoa2FuIGluZm9ybWFzaSBrb250ZWtzIGdsb2JhbCB5YW5nIGRpcGVyb2xlaCBkYXJpIFNTQS4NCg0KLSAqKlJ1bXVzOioqDQoNClxbDQpcbWF0aGJme1p9Jw0KPQ0KXG1hdGhiZntUfQ0KKw0KXG1hdGhiZntafV97XG1hdGhybXtTU0F9fS4NClxdDQoNCk1hdHJpa3MgXChcbWF0aGJme1R9XCkgZGFuIFwoXG1hdGhiZntafV97XG1hdGhybXtTU0F9fVwpIG1hc2luZy1tYXNpbmcgYmVydWt1cmFuIFwoMjVcdGltZXMyXCkuIE9sZWgga2FyZW5hIGl0dSwgbWF0cmlrcyBoYXNpbCByZXNpZHVhbCBcKFxtYXRoYmZ7Wn0nXCkganVnYSBiZXJ1a3VyYW4gXCgyNVx0aW1lczJcKS4NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiB0b2tlbiBwZXJ0YW1hOioqDQoNClBlcmhpdHVuZ2FuIGRpbGFrdWthbiBtZW5nZ3VuYWthbiBuaWxhaSBwcmVzaXNpIHBlbnVoIHNlYmVsdW0gaGFzaWwgYWtoaXIgZGl0YW1waWxrYW4uIFVudHVrIHRva2VuIHBlcnRhbWEsIGRpcGVyb2xlaDoNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KXG1hdGhiZntafSdfezF9DQomPQ0KXG1hdGhiZntUfV97MX0NCisNClxtYXRoYmZ7Wn1fe1xtYXRocm17U1NBfSwxfVxcDQomPQ0KXGJlZ2lue2JtYXRyaXh9DQotMC4yMjIyICYgMC4xNjY2DQpcZW5ke2JtYXRyaXh9DQorDQpcYmVnaW57Ym1hdHJpeH0NCi0wLjAzNDIgJiAtMC4wMzQyDQpcZW5ke2JtYXRyaXh9XFwNCiY9DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjI1NjQgJiAwLjEzMjQNClxlbmR7Ym1hdHJpeH1cXA0KJj0NClxiZWdpbntibWF0cml4fQ0KLTAuMjYgJiAwLjEzDQpcZW5ke2JtYXRyaXh9Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiB0b2tlbiBrZXRpZ2E6KioNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KXG1hdGhiZntafSdfezN9DQomPQ0KXG1hdGhiZntUfV97M30NCisNClxtYXRoYmZ7Wn1fe1xtYXRocm17U1NBfSwzfVxcDQomPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjMwICYgLTAuMjINClxlbmR7Ym1hdHJpeH0NCisNClxiZWdpbntibWF0cml4fQ0KMC4xMCAmIC0wLjA0DQpcZW5ke2JtYXRyaXh9XFwNCiY9DQpcYmVnaW57Ym1hdHJpeH0NCjAuNDAgJiAtMC4yNg0KXGVuZHtibWF0cml4fS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBhdHVyYW4geWFuZyBzYW1hLCBkaXBlcm9sZWggbWF0cmlrcyBoYXNpbCAqcmVzaWR1YWwgc2VwYXJhYmxlIHNlbGYtYXR0ZW50aW9uKiBzZWJhZ2FpIGJlcmlrdXQuDQoNClxbDQpcbWF0aGJme1p9Jz0NClxiZWdpbntibWF0cml4fQ0KLTAuMjYgJiAwLjEzXFwNCi0wLjIwICYgMC4xMFxcDQowLjQwICYgLTAuMjZcXA0KMC4xOCAmIC0wLjEyXFwNCi0wLjIxICYgMC4xMVxcDQotMC4yNSAmIDAuMTNcXA0KLTAuMjAgJiAwLjEwXFwNCjAuNjMgJiAtMC40MlxcDQowLjMzICYgLTAuMjJcXA0KLTAuMjIgJiAwLjExXFwNCi0wLjI2ICYgMC4xM1xcDQotMC4yMCAmIDAuMTBcXA0KMC42NCAmIC0wLjQyXFwNCjAuMzMgJiAtMC4yMlxcDQotMC4yMiAmIDAuMTFcXA0KLTAuMjUgJiAwLjEzXFwNCi0wLjIyICYgMC4xMlxcDQowLjM4ICYgLTAuMjVcXA0KMC4xMiAmIC0wLjA4XFwNCi0wLjIzICYgMC4xMlxcDQotMC4yNiAmIDAuMTNcXA0KLTAuMjMgJiAwLjEyXFwNCjAuMDUgJiAtMC4wMzVcXA0KLTAuMDcgJiAwLjA0XFwNCi0wLjIzICYgMC4xMg0KXGVuZHtibWF0cml4fS4NClxdDQoNCg0KIyMjIGguIE5vcm1hbGlzYXNpIHJlc2lkdWFsIHNlcGFyYWJsZSBzZWxmLWF0dGVudGlvbg0KDQpNYXRyaWtzIGhhc2lsIHJlc2lkdWFsICpzZXBhcmFibGUgc2VsZi1hdHRlbnRpb24qIFwoXG1hdGhiZntafSdcKSBkaW5vcm1hbGlzYXNpIHBlciB0b2tlbiBtZW5nZ3VuYWthbiAqbGF5ZXIgbm9ybWFsaXphdGlvbiouIE5vcm1hbGlzYXNpIGRpbGFrdWthbiBwYWRhIGR1YSBlbGVtZW4gZml0dXIgZGFsYW0gc2V0aWFwIHRva2VuIHNlY2FyYSB0ZXJwaXNhaCwgYnVrYW4gcGFkYSBzZWx1cnVoIG1hdHJpa3Mgc2VrYWxpZ3VzLiBUYWhhcCBpbmkgbWVuZ2hhc2lsa2FuIFwoXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntafScpXCkgc2ViYWdhaSBtYXN1a2FuIHVudHVrIE1MUC4NCg0KLSAqKlJ1bXVzIHJhdGEtcmF0YSB0b2tlbiBrZS1cKHRcKToqKg0KDQpcWw0KXG11X3taJyx0fQ0KPQ0KXGZyYWN7MX17Mn0NClxzdW1fe249MX1eezJ9Widfe3Qsbn0uDQpcXQ0KDQotICoqUnVtdXMgdmFyaWFucyB0b2tlbiBrZS1cKHRcKToqKg0KDQpcWw0KXHNpZ21hX3taJyx0fV57Mn0NCj0NClxmcmFjezF9ezJ9DQpcc3VtX3tuPTF9XnsyfQ0KXGxlZnQoDQpaJ197dCxufS1cbXVfe1onLHR9DQpccmlnaHQpXjIuDQpcXQ0KDQotICoqUnVtdXMgbm9ybWFsaXNhc2k6KioNCg0KXFsNClxsZWZ0Ww0KXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntafScpDQpccmlnaHRdX3t0LG59DQo9DQpcZnJhY3sNClonX3t0LG59LVxtdV97WicsdH0NCn17DQpcc3FydHsNClxzaWdtYV97WicsdH1eezJ9KzEwXnstNX0NCn0NCn0uDQpcXQ0KDQpNYXRyaWtzIFwoXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntafScpXCkgYmVydWt1cmFuIFwoMjVcdGltZXMyXCkuDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gdG9rZW4gcGVydGFtYToqKg0KDQpOaWxhaSB0b2tlbiBwZXJ0YW1hIHNlYmVsdW0gcGVtYnVsYXRhbiBhZGFsYWg6DQoNClxbDQpcbWF0aGJme1p9J197MX09DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjI1NjQgJiAwLjEzMjQNClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQpSYXRhLXJhdGEgdG9rZW4gcGVydGFtYSBhZGFsYWg6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClxtdV97WicsMX0NCiY9DQpcZnJhY3stMC4yNTY0KzAuMTMyNH17Mn1cXA0KJj0NCi0wLjA2MjAuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpWYXJpYW5zIHRva2VuIHBlcnRhbWEgYWRhbGFoOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcc2lnbWFfe1onLDF9XnsyfQ0KJj0NClxmcmFjew0KKC0wLjI1NjQtKC0wLjA2MjApKV4yDQorDQooMC4xMzI0LSgtMC4wNjIwKSleMg0KfXsyfVxcDQomPQ0KXGZyYWN7KC0wLjE5NDQpXjIrKDAuMTk0NCleMn17Mn1cXA0KJj0NCjAuMDM3OC4NClxlbmR7YWxpZ25lZH0NClxdDQoNCk1ha2E6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClxvcGVyYXRvcm5hbWV7TE59KFxtYXRoYmZ7Wn0nX3sxfSkNCiY9DQpcYmVnaW57Ym1hdHJpeH0NClxkZnJhY3stMC4yNTY0LSgtMC4wNjIwKX0NCntcc3FydHswLjAzNzgrMTBeey01fX19DQomDQpcZGZyYWN7MC4xMzI0LSgtMC4wNjIwKX0NCntcc3FydHswLjAzNzgrMTBeey01fX19DQpcZW5ke2JtYXRyaXh9XFwNCiY9DQpcYmVnaW57Ym1hdHJpeH0NCi0xLjAwICYgMS4wMA0KXGVuZHtibWF0cml4fS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBhdHVyYW4geWFuZyBzYW1hLCBkaXBlcm9sZWggbWF0cmlrcyBoYXNpbCBub3JtYWxpc2FzaSByZXNpZHVhbCAqc2VwYXJhYmxlIHNlbGYtYXR0ZW50aW9uKiBzZWJhZ2FpIGJlcmlrdXQuDQoNClxbDQpcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1p9Jyk9DQpcYmVnaW57Ym1hdHJpeH0NCi0xLjAwICYgMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KMS4wMCAmIC0xLjAwXFwNCjEuMDAgJiAtMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMFxcDQoxLjAwICYgLTEuMDBcXA0KMS4wMCAmIC0xLjAwXFwNCi0xLjAwICYgMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCjEuMDAgJiAtMS4wMFxcDQoxLjAwICYgLTEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KMS4wMCAmIC0xLjAwXFwNCjEuMDAgJiAtMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMFxcDQoxLjAwICYgLTEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMA0KXGVuZHtibWF0cml4fS4NClxdDQoNCiMjIyBpLiBMYXBpc2FuIHBlcnRhbWEgTUxQICgqZmVlZC1mb3J3YXJkIG5ldHdvcmsqKQ0KDQpMYXBpc2FuIHBlcnRhbWEgTUxQIG1lbmVyaW1hIHRva2VuIGhhc2lsIG5vcm1hbGlzYXNpIHJlc2lkdWFsICpzZXBhcmFibGUgc2VsZi1hdHRlbnRpb24qLCB5YWl0dSBcKFxvcGVyYXRvcm5hbWV7TE59KFxtYXRoYmZ7Wn0nKVwpLiBMYXBpc2FuIGluaSBtZW1wcm95ZWtzaWthbiBzZXRpYXAgdG9rZW4gZGFyaSBkdWEgZWxlbWVuIGZpdHVyIG1lbmphZGkgdGlnYSBlbGVtZW4gZml0dXIsIGtlbXVkaWFuIG1lbmVyYXBrYW4gZnVuZ3NpIGFrdGl2YXNpIFJlTFUuIFByb3NlcyB0ZXJzZWJ1dCBzZXN1YWkgZGVuZ2FuIHRhaGFwIHBlcnRhbWEgTUxQIHBhZGEgUGVyc2FtYWFuICgyLjE3KSBkaSBCYWIgSUkuDQoNClBhZGEgaWx1c3RyYXNpIGluaSwgdmVrdG9yIGJpYXMgbGFwaXNhbiBwZXJ0YW1hIGRpYWJhaWthbiBhdGF1IGRpdGV0YXBrYW4gc2ViYWdhaSBcKFxtYXRoYmZ7Yn1fMT1cbWF0aGJmezB9XCkuDQoNCi0gKipCb2JvdCBsYXBpc2FuIHBlcnRhbWE6KioNCg0KXFsNClxtYXRoYmZ7V31fMT0NClxiZWdpbntibWF0cml4fQ0KMC40NSAmIC0wLjM1ICYgMC4yNVxcDQotMC4yMCAmIDAuNTUgJiAwLjMwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KTWF0cmlrcyBcKFxtYXRoYmZ7V31fMVwpIGJlcnVrdXJhbiBcKDJcdGltZXMzXCkuDQoNCi0gKipSdW11czoqKg0KDQpcWw0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQpcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1p9JykNClxtYXRoYmZ7V31fMQ0KXHJpZ2h0KS4NClxdDQoNCk1hdHJpa3MgXChcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1p9JylcKSBiZXJ1a3VyYW4gXCgyNVx0aW1lczJcKS4gT2xlaCBrYXJlbmEgaXR1LCBoYXNpbCBsYXBpc2FuIHBlcnRhbWEgTUxQIGJlcnVrdXJhbiBcKDI1XHRpbWVzM1wpLg0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuIHRva2VuIHBlcnRhbWE6KioNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQpcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1p9J18xKQ0KXG1hdGhiZntXfV8xDQpccmlnaHQpDQomPQ0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQpcYmVnaW57Ym1hdHJpeH0NCi0xLjAwICYgMS4wMA0KXGVuZHtibWF0cml4fQ0KXGJlZ2lue2JtYXRyaXh9DQowLjQ1ICYgLTAuMzUgJiAwLjI1XFwNCi0wLjIwICYgMC41NSAmIDAuMzANClxlbmR7Ym1hdHJpeH0NClxyaWdodClcXA0KJj0NClxvcGVyYXRvcm5hbWV7UmVMVX0NClxsZWZ0KA0KXGJlZ2lue2JtYXRyaXh9DQotMC42NSAmIDAuOTAgJiAwLjA1DQpcZW5ke2JtYXRyaXh9DQpccmlnaHQpXFwNCiY9DQpcYmVnaW57Ym1hdHJpeH0NCjAuMDAgJiAwLjkwICYgMC4wNQ0KXGVuZHtibWF0cml4fS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gdG9rZW4ga2V0aWdhOioqDQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClxvcGVyYXRvcm5hbWV7UmVMVX0NClxsZWZ0KA0KXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntafSdfMykNClxtYXRoYmZ7V31fMQ0KXHJpZ2h0KQ0KJj0NClxvcGVyYXRvcm5hbWV7UmVMVX0NClxsZWZ0KA0KXGJlZ2lue2JtYXRyaXh9DQoxLjAwICYgLTEuMDANClxlbmR7Ym1hdHJpeH0NClxiZWdpbntibWF0cml4fQ0KMC40NSAmIC0wLjM1ICYgMC4yNVxcDQotMC4yMCAmIDAuNTUgJiAwLjMwDQpcZW5ke2JtYXRyaXh9DQpccmlnaHQpXFwNCiY9DQpcb3BlcmF0b3JuYW1le1JlTFV9DQpcbGVmdCgNClxiZWdpbntibWF0cml4fQ0KMC42NSAmIC0wLjkwICYgLTAuMDUNClxlbmR7Ym1hdHJpeH0NClxyaWdodClcXA0KJj0NClxiZWdpbntibWF0cml4fQ0KMC42NSAmIDAuMDAgJiAwLjAwDQpcZW5ke2JtYXRyaXh9Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KRGVuZ2FuIGF0dXJhbiB5YW5nIHNhbWEsIGRpcGVyb2xlaCBoYXNpbCBsYXBpc2FuIHBlcnRhbWEgTUxQIHNlYmFnYWkgYmVyaWt1dC4NCg0KXFsNClxvcGVyYXRvcm5hbWV7UmVMVX0NClxsZWZ0KA0KXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntafScpDQpcbWF0aGJme1d9XzENClxyaWdodCkNCj0NClxiZWdpbntibWF0cml4fQ0KMC4wMCAmIDAuOTAgJiAwLjA1XFwNCjAuMDAgJiAwLjkwICYgMC4wNVxcDQowLjY1ICYgMC4wMCAmIDAuMDBcXA0KMC42NSAmIDAuMDAgJiAwLjAwXFwNCjAuMDAgJiAwLjkwICYgMC4wNVxcDQowLjAwICYgMC45MCAmIDAuMDVcXA0KMC4wMCAmIDAuOTAgJiAwLjA1XFwNCjAuNjUgJiAwLjAwICYgMC4wMFxcDQowLjY1ICYgMC4wMCAmIDAuMDBcXA0KMC4wMCAmIDAuOTAgJiAwLjA1XFwNCjAuMDAgJiAwLjkwICYgMC4wNVxcDQowLjAwICYgMC45MCAmIDAuMDVcXA0KMC42NSAmIDAuMDAgJiAwLjAwXFwNCjAuNjUgJiAwLjAwICYgMC4wMFxcDQowLjAwICYgMC45MCAmIDAuMDVcXA0KMC4wMCAmIDAuOTAgJiAwLjA1XFwNCjAuMDAgJiAwLjkwICYgMC4wNVxcDQowLjY1ICYgMC4wMCAmIDAuMDBcXA0KMC42NSAmIDAuMDAgJiAwLjAwXFwNCjAuMDAgJiAwLjkwICYgMC4wNVxcDQowLjAwICYgMC45MCAmIDAuMDVcXA0KMC4wMCAmIDAuOTAgJiAwLjA1XFwNCjAuNjUgJiAwLjAwICYgMC4wMFxcDQowLjAwICYgMC45MCAmIDAuMDVcXA0KMC4wMCAmIDAuOTAgJiAwLjA1DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KIyMjIGouIExhcGlzYW4ga2VkdWEgTUxQICgqZmVlZC1mb3J3YXJkIG5ldHdvcmsqKQ0KDQpMYXBpc2FuIGtlZHVhIE1MUCBtZW1wcm95ZWtzaWthbiB0aWdhIGVsZW1lbiBmaXR1ciBoYXNpbCBsYXBpc2FuIHBlcnRhbWEga2VtYmFsaSBtZW5qYWRpIGR1YSBlbGVtZW4gZml0dXIuIFBhZGEgdGFoYXAgaW5pLCBrZWx1YXJhbiBwcm95ZWtzaSBsaW5lYXIgdGlkYWsgZGliZXJpIGZ1bmdzaSBha3RpdmFzaSB0YW1iYWhhbi4gUHJvc2VzIGluaSBzZXN1YWkgZGVuZ2FuIGJhZ2lhbiBrZWR1YSBNTFAgcGFkYSBQZXJzYW1hYW4gKDIuMTcpIGRpIEJhYiBJSS4NCg0KUGFkYSBpbHVzdHJhc2kgaW5pLCB2ZWt0b3IgYmlhcyBsYXBpc2FuIGtlZHVhIGRpYWJhaWthbiBhdGF1IGRpdGV0YXBrYW4gc2ViYWdhaSBcKFxtYXRoYmZ7Yn1fMj1cbWF0aGJmezB9XCkuDQoNCi0gKipCb2JvdCBsYXBpc2FuIGtlZHVhOioqDQoNClxbDQpcbWF0aGJme1d9XzI9DQpcYmVnaW57Ym1hdHJpeH0NCjAuMzUgJiAtMC4yNVxcDQowLjE1ICYgMC40NVxcDQotMC4yMCAmIDAuMzANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQpNYXRyaWtzIFwoXG1hdGhiZntXfV8yXCkgYmVydWt1cmFuIFwoM1x0aW1lczJcKS4NCg0KLSAqKlJ1bXVzOioqDQoNClxbDQpcb3BlcmF0b3JuYW1le1JlTFV9DQpcbGVmdCgNClxvcGVyYXRvcm5hbWV7TE59KFxtYXRoYmZ7Wn0nKQ0KXG1hdGhiZntXfV8xDQpccmlnaHQpDQpcbWF0aGJme1d9XzIuDQpcXQ0KDQpIYXNpbCBsYXBpc2FuIHBlcnRhbWEgTUxQIGJlcnVrdXJhbiBcKDI1XHRpbWVzM1wpLiBPbGVoIGthcmVuYSBpdHUsIGtlbHVhcmFuIGxhcGlzYW4ga2VkdWEgTUxQIGJlcnVrdXJhbiBcKDI1XHRpbWVzMlwpLg0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuIHRva2VuIHBlcnRhbWE6KioNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KJg0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQpcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1p9J18xKQ0KXG1hdGhiZntXfV8xDQpccmlnaHQpDQpcbWF0aGJme1d9XzJcXA0KJj0NClxiZWdpbntibWF0cml4fQ0KMC4wMCAmIDAuOTAgJiAwLjA1DQpcZW5ke2JtYXRyaXh9DQpcYmVnaW57Ym1hdHJpeH0NCjAuMzUgJiAtMC4yNVxcDQowLjE1ICYgMC40NVxcDQotMC4yMCAmIDAuMzANClxlbmR7Ym1hdHJpeH1cXA0KJj0NClxiZWdpbntibWF0cml4fQ0KKDAuMDApKDAuMzUpKygwLjkwKSgwLjE1KSsoMC4wNSkoLTAuMjApDQomDQooMC4wMCkoLTAuMjUpKygwLjkwKSgwLjQ1KSsoMC4wNSkoMC4zMCkNClxlbmR7Ym1hdHJpeH1cXA0KJj0NClxiZWdpbntibWF0cml4fQ0KMC4xMjUgJiAwLjQyMA0KXGVuZHtibWF0cml4fVxcDQomPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjEzICYgMC40Mg0KXGVuZHtibWF0cml4fS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gdG9rZW4ga2V0aWdhOioqDQoNClxbDQpcYmVnaW57YWxpZ25lZH0NCiYNClxvcGVyYXRvcm5hbWV7UmVMVX0NClxsZWZ0KA0KXG9wZXJhdG9ybmFtZXtMTn0oXG1hdGhiZntafSdfMykNClxtYXRoYmZ7V31fMQ0KXHJpZ2h0KQ0KXG1hdGhiZntXfV8yXFwNCiY9DQpcYmVnaW57Ym1hdHJpeH0NCjAuNjUgJiAwLjAwICYgMC4wMA0KXGVuZHtibWF0cml4fQ0KXGJlZ2lue2JtYXRyaXh9DQowLjM1ICYgLTAuMjVcXA0KMC4xNSAmIDAuNDVcXA0KLTAuMjAgJiAwLjMwDQpcZW5ke2JtYXRyaXh9XFwNCiY9DQpcYmVnaW57Ym1hdHJpeH0NCjAuMjMgJiAtMC4xNg0KXGVuZHtibWF0cml4fS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBhdHVyYW4geWFuZyBzYW1hLCBkaXBlcm9sZWgga2VsdWFyYW4gbGFwaXNhbiBrZWR1YSBNTFAgc2ViYWdhaSBiZXJpa3V0Lg0KDQpcWw0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQpcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1p9JykNClxtYXRoYmZ7V31fMQ0KXHJpZ2h0KQ0KXG1hdGhiZntXfV8yDQo9DQpcYmVnaW57Ym1hdHJpeH0NCjAuMTMgJiAwLjQyXFwNCjAuMTMgJiAwLjQyXFwNCjAuMjMgJiAtMC4xNlxcDQowLjIzICYgLTAuMTZcXA0KMC4xMyAmIDAuNDJcXA0KMC4xMyAmIDAuNDJcXA0KMC4xMyAmIDAuNDJcXA0KMC4yMyAmIC0wLjE2XFwNCjAuMjMgJiAtMC4xNlxcDQowLjEzICYgMC40MlxcDQowLjEzICYgMC40MlxcDQowLjEzICYgMC40MlxcDQowLjIzICYgLTAuMTZcXA0KMC4yMyAmIC0wLjE2XFwNCjAuMTMgJiAwLjQyXFwNCjAuMTMgJiAwLjQyXFwNCjAuMTMgJiAwLjQyXFwNCjAuMjMgJiAtMC4xNlxcDQowLjIzICYgLTAuMTZcXA0KMC4xMyAmIDAuNDJcXA0KMC4xMyAmIDAuNDJcXA0KMC4xMyAmIDAuNDJcXA0KMC4yMyAmIC0wLjE2XFwNCjAuMTMgJiAwLjQyXFwNCjAuMTMgJiAwLjQyDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KIyMjIGsuIFJlc2lkdWFsIE1MUCAoKmZlZWQtZm9yd2FyZCBuZXR3b3JrKikNCg0KS2VsdWFyYW4gbGFwaXNhbiBrZWR1YSBNTFAgZGl0YW1iYWhrYW4gZGVuZ2FuIHJlcHJlc2VudGFzaSByZXNpZHVhbCBzZWJlbHVtbnlhLCB5YWl0dSBcKFxtYXRoYmZ7Wn0nXCkuIFBlbmp1bWxhaGFuIGluaSBtZW1wZXJ0YWhhbmthbiBpbmZvcm1hc2kgaGFzaWwgKnNlcGFyYWJsZSBzZWxmLWF0dGVudGlvbiogc2VrYWxpZ3VzIG1lbmFtYmFoa2FuIHRyYW5zZm9ybWFzaSBmaXR1ciBkYXJpIE1MUC4gS2VsdWFyYW4gYWtoaXIgYmxvayAqbGluZWFyIFRyYW5zZm9ybWVyKiBkaW5vdGFzaWthbiBzZWJhZ2FpIFwoXG1hdGhiZntafVwpLg0KDQotICoqUnVtdXM6KioNCg0KXFsNClxtYXRoYmZ7Wn0NCj0NClxtYXRoYmZ7Wn0nDQorDQpcb3BlcmF0b3JuYW1le1JlTFV9DQpcbGVmdCgNClxvcGVyYXRvcm5hbWV7TE59KFxtYXRoYmZ7Wn0nKQ0KXG1hdGhiZntXfV8xDQpccmlnaHQpDQpcbWF0aGJme1d9XzIuDQpcXQ0KDQpNYXRyaWtzIFwoXG1hdGhiZntafSdcKSBkYW4ga2VsdWFyYW4gbGFwaXNhbiBrZWR1YSBNTFAgbWFzaW5nLW1hc2luZyBiZXJ1a3VyYW4gXCgyNVx0aW1lczJcKS4gT2xlaCBrYXJlbmEgaXR1LCBtYXRyaWtzIGtlbHVhcmFuIFwoXG1hdGhiZntafVwpIGp1Z2EgYmVydWt1cmFuIFwoMjVcdGltZXMyXCkuDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gdG9rZW4gcGVydGFtYToqKg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcbWF0aGJme1p9XzENCiY9DQpcbWF0aGJme1p9J18xKw0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQpcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1p9J18xKQ0KXG1hdGhiZntXfV8xDQpccmlnaHQpDQpcbWF0aGJme1d9XzJcXA0KJj0NClxiZWdpbntibWF0cml4fQ0KLTAuMjYgJiAwLjEzDQpcZW5ke2JtYXRyaXh9DQorDQpcYmVnaW57Ym1hdHJpeH0NCjAuMTMgJiAwLjQyDQpcZW5ke2JtYXRyaXh9XFwNCiY9DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjEzICYgMC41NQ0KXGVuZHtibWF0cml4fS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gdG9rZW4ga2V0aWdhOioqDQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClxtYXRoYmZ7Wn1fMw0KJj0NClxiZWdpbntibWF0cml4fQ0KMC40MCAmIC0wLjI2DQpcZW5ke2JtYXRyaXh9DQorDQpcYmVnaW57Ym1hdHJpeH0NCjAuMjMgJiAtMC4xNg0KXGVuZHtibWF0cml4fVxcDQomPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjYzICYgLTAuNDMNClxlbmR7Ym1hdHJpeH0uDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gYXR1cmFuIHlhbmcgc2FtYSwgZGlwZXJvbGVoIGtlbHVhcmFuIGFraGlyIGJsb2sgKmxpbmVhciBUcmFuc2Zvcm1lciogc2ViYWdhaSBiZXJpa3V0Lg0KDQpcWw0KXG1hdGhiZntafT0NClxiZWdpbntibWF0cml4fQ0KLTAuMTMgJiAwLjU1XFwNCi0wLjA3ICYgMC41MlxcDQowLjYzICYgLTAuNDNcXA0KMC40MSAmIC0wLjI4XFwNCi0wLjA4ICYgMC41M1xcDQotMC4xMyAmIDAuNTVcXA0KLTAuMDggJiAwLjUyXFwNCjAuODYgJiAtMC41OFxcDQowLjU1ICYgLTAuMzhcXA0KLTAuMDkgJiAwLjUzXFwNCi0wLjEzICYgMC41NVxcDQotMC4wNyAmIDAuNTJcXA0KMC44NiAmIC0wLjU4XFwNCjAuNTUgJiAtMC4zOFxcDQotMC4wOSAmIDAuNTNcXA0KLTAuMTMgJiAwLjU1XFwNCi0wLjEwICYgMC41NFxcDQowLjYwICYgLTAuNDFcXA0KMC4zNSAmIC0wLjI1XFwNCi0wLjExICYgMC41NFxcDQotMC4xMyAmIDAuNTVcXA0KLTAuMTEgJiAwLjU0XFwNCjAuMjggJiAtMC4xOVxcDQowLjA1ICYgMC40NlxcDQotMC4xMSAmIDAuNTQNClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQoNCiMjIyBsLiBOb3JtYWxpc2FzaSBha2hpciAqbGluZWFyIFRyYW5zZm9ybWVyKg0KDQpUYWhhcCB0ZXJha2hpciBwYWRhIGlsdXN0cmFzaSAqbGluZWFyIFRyYW5zZm9ybWVyKiBhZGFsYWggbm9ybWFsaXNhc2kgcGVyIHRva2VuIHRlcmhhZGFwIG1hdHJpa3Mga2VsdWFyYW4gcmVzaWR1YWwgTUxQIFwoXG1hdGhiZntafVwpLiBIYXNpbCBub3JtYWxpc2FzaSBkaW5vdGFzaWthbiBzZWJhZ2FpIFwoXG1hdGhiZntHfVwpIGRhbiBkaWd1bmFrYW4gc2ViYWdhaSByZXByZXNlbnRhc2kgZ2xvYmFsIHNlYmVsdW0gcHJvc2VzICpmb2xkaW5nKi4NCg0KLSAqKlJ1bXVzOioqDQoNClxbDQpcbWF0aGJme0d9DQo9DQpcb3BlcmF0b3JuYW1le0xOfShcbWF0aGJme1p9KS4NClxdDQoNClVudHVrIHRva2VuIGtlLVwodFwpLCByYXRhLXJhdGEgZGFuIHZhcmlhbnMgZGloaXR1bmcgc2ViYWdhaToNCg0KXFsNClxtdV97Wix0fQ0KPQ0KXGZyYWN7MX17Mn0NClxzdW1fe249MX1eezJ9Wl97dCxufSwNClxdDQoNClxbDQpcc2lnbWFfe1osdH1eezJ9DQo9DQpcZnJhY3sxfXsyfQ0KXHN1bV97bj0xfV57Mn0NClxsZWZ0KA0KWl97dCxufS1cbXVfe1osdH0NClxyaWdodCleMi4NClxdDQoNClNlbGFuanV0bnlhLCBlbGVtZW4gaGFzaWwgbm9ybWFsaXNhc2kgZGlydW11c2thbiBzZWJhZ2FpOg0KDQpcWw0KR197dCxufQ0KPQ0KXGZyYWN7DQpaX3t0LG59LVxtdV97Wix0fQ0KfXsNClxzcXJ0ew0KXHNpZ21hX3taLHR9XnsyfSsxMF57LTV9DQp9DQp9Lg0KXF0NCg0KTWF0cmlrcyBcKFxtYXRoYmZ7R31cKSBiZXJ1a3VyYW4gXCgyNVx0aW1lczJcKS4NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiB0b2tlbiBwZXJ0YW1hOioqDQoNClxbDQpcbWF0aGJme1p9X3sxfT0NClxiZWdpbntibWF0cml4fQ0KLTAuMTMgJiAwLjU1DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KUmF0YS1yYXRhIHRva2VuIHBlcnRhbWEgYWRhbGFoOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcbXVfe1osMX0NCiY9DQpcZnJhY3stMC4xMyswLjU1fXsyfVxcDQomPQ0KMC4yMS4NClxlbmR7YWxpZ25lZH0NClxdDQoNClZhcmlhbnMgdG9rZW4gcGVydGFtYSBhZGFsYWg6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClxzaWdtYV97WiwxfV57Mn0NCiY9DQpcZnJhY3sNCigtMC4xMy0wLjIxKV4yKw0KKDAuNTUtMC4yMSleMg0KfXsyfVxcDQomPQ0KXGZyYWN7KC0wLjM0KV4yKygwLjM0KV4yfXsyfVxcDQomPQ0KMC4xMTU2Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KTWFrYToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KXG1hdGhiZntHfV97MX0NCiY9DQpcYmVnaW57Ym1hdHJpeH0NClxkZnJhY3stMC4xMy0wLjIxfQ0Ke1xzcXJ0ezAuMTE1NisxMF57LTV9fX0NCiYNClxkZnJhY3swLjU1LTAuMjF9DQp7XHNxcnR7MC4xMTU2KzEwXnstNX19fQ0KXGVuZHtibWF0cml4fVxcDQomPQ0KXGJlZ2lue2JtYXRyaXh9DQotMS4wMCAmIDEuMDANClxlbmR7Ym1hdHJpeH0uDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gYXR1cmFuIHlhbmcgc2FtYSwgZGlwZXJvbGVoIHJlcHJlc2VudGFzaSBnbG9iYWwgc2ViYWdhaSBiZXJpa3V0Lg0KDQpcWw0KXG1hdGhiZntHfT0NClxiZWdpbntibWF0cml4fQ0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMFxcDQoxLjAwICYgLTEuMDBcXA0KMS4wMCAmIC0xLjAwXFwNCi0xLjAwICYgMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCjEuMDAgJiAtMS4wMFxcDQoxLjAwICYgLTEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KMS4wMCAmIC0xLjAwXFwNCjEuMDAgJiAtMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCi0xLjAwICYgMS4wMFxcDQoxLjAwICYgLTEuMDBcXA0KMS4wMCAmIC0xLjAwXFwNCi0xLjAwICYgMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KLTEuMDAgJiAxLjAwXFwNCjEuMDAgJiAtMS4wMFxcDQotMS4wMCAmIDEuMDBcXA0KLTEuMDAgJiAxLjAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KIyMgNC4gRm9sZGluZywgUHJveWVrc2kgR2xvYmFsLCBkYW4gRnVzaSBSZXNpZHVhbA0KDQpLZWx1YXJhbiAqbGluZWFyIFRyYW5zZm9ybWVyKiBcKFxtYXRoYmZ7R31cKSBtYXNpaCBiZXJiZW50dWsgdXJ1dGFuIHRva2VuIGJlcnVrdXJhbiBcKDI1XHRpbWVzMlwpLiBQYWRhIHRhaGFwIGluaSwgdG9rZW4gZGlrZW1iYWxpa2FuIGtlIHN1c3VuYW4gc3Bhc2lhbCBiZXJ1a3VyYW4gXCg1XHRpbWVzNVwpIG1lbGFsdWkgcHJvc2VzICpmb2xkaW5nKi4gU2VsYW5qdXRueWEsIGtlZHVhIGthbmFsIGhhc2lsICpmb2xkaW5nKiBkaXByb3lla3Npa2FuIG1lbmphZGkgc2F0dSAqZmVhdHVyZSBtYXAqIGdsb2JhbC4gKkZlYXR1cmUgbWFwKiBnbG9iYWwgdGVyc2VidXQga2VtdWRpYW4gZGlnYWJ1bmdrYW4gZGVuZ2FuICpmZWF0dXJlIG1hcCogbG9rYWwgXChcbWF0aGJme0x9XCkgc2VydGEgKmZlYXR1cmUgbWFwKiBtYXN1a2FuIFwoXG1hdGhiZntYfVwpIG1lbGFsdWkgZnVzaSByZXNpZHVhbC4NCg0KIyMjIGEuIEZvbGRpbmcga2VsdWFyYW4gbGluZWFyIFRyYW5zZm9ybWVyDQoNCk1hdHJpa3MgXChcbWF0aGJme0d9XCkgbWVtaWxpa2kgZHVhIGtvbG9tLiBLb2xvbSBwZXJ0YW1hIGRpbGlwYXQga2VtYmFsaSBtZW5qYWRpIGthbmFsIHBlcnRhbWEgXChcbWF0aGJme0d9XzFcKSwgc2VkYW5na2FuIGtvbG9tIGtlZHVhIGRpbGlwYXQga2VtYmFsaSBtZW5qYWRpIGthbmFsIGtlZHVhIFwoXG1hdGhiZntHfV8yXCkuIFBvc2lzaSB0b2tlbiBkaXRlbnR1a2FuIGJlcmRhc2Fya2FuIHVydXRhbiByYXN0ZXIgZGFyaSBraXJpIGtlIGthbmFuIGRhbiBkYXJpIGF0YXMga2UgYmF3YWguDQoNCi0gKipSdW11czoqKg0KDQpcWw0KdD01KGktMSkraiwNClxxcXVhZA0KaSxqPTEsMixcbGRvdHMsNSwNClxdDQoNCmRlbmdhbiBcKGlcKSBtZW55YXRha2FuIGluZGVrcyBiYXJpcywgXChqXCkgbWVueWF0YWthbiBpbmRla3Mga29sb20sIGRhbiBcKHRcKSBtZW55YXRha2FuIGluZGVrcyB0b2tlbi4NCg0KVW50dWsgc2V0aWFwIHBvc2lzaSBzcGFzaWFsIFwoKGksailcKSwNCg0KXFsNCkdfezEsaSxqfT1HX3t0LDF9LA0KXHFxdWFkDQpHX3syLGksan09R197dCwyfSwNClxxcXVhZA0KdD01KGktMSkrai4NClxdDQoNCi0gKipDb250b2g6KioNCg0KQmFyaXMgcGVydGFtYSBwYWRhIG1hdHJpa3MgXChcbWF0aGJme0d9XCkgYWRhbGFoOg0KDQpcWw0KXG1hdGhiZntHfV97MX09DQpcYmVnaW57Ym1hdHJpeH0NCi0xLjAwICYgMS4wMA0KXGVuZHtibWF0cml4fS4NClxdDQoNCkthcmVuYSB0b2tlbiBwZXJ0YW1hIGJlcmFkYSBwYWRhIHBvc2lzaSBcKCgxLDEpXCksIG1ha2E6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NCnQNCiY9NSgxLTEpKzFcXA0KJj0xLg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KRGVuZ2FuIGRlbWlraWFuLCBuaWxhaSBoYXNpbCAqZm9sZGluZyogcGFkYSBwb3Npc2kgXCgoMSwxKVwpIGFkYWxhaDoNCg0KXFsNCkdfezEsMSwxfT0tMS4wMCwNClxxcXVhZA0KR197MiwxLDF9PTEuMDAuDQpcXQ0KDQpNYXRyaWtzIGthbmFsIHBlcnRhbWEgc2V0ZWxhaCBwcm9zZXMgKmZvbGRpbmcqIGFkYWxhaDoNCg0KXFsNClxtYXRoYmZ7R31fMT0NClxiZWdpbntibWF0cml4fQ0KLTEuMDAgJiAtMS4wMCAmIDEuMDAgJiAxLjAwICYgLTEuMDBcXA0KLTEuMDAgJiAtMS4wMCAmIDEuMDAgJiAxLjAwICYgLTEuMDBcXA0KLTEuMDAgJiAtMS4wMCAmIDEuMDAgJiAxLjAwICYgLTEuMDBcXA0KLTEuMDAgJiAtMS4wMCAmIDEuMDAgJiAxLjAwICYgLTEuMDBcXA0KLTEuMDAgJiAtMS4wMCAmIDEuMDAgJiAtMS4wMCAmIC0xLjAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KTWF0cmlrcyBrYW5hbCBrZWR1YSBzZXRlbGFoIHByb3NlcyAqZm9sZGluZyogYWRhbGFoOg0KDQpcWw0KXG1hdGhiZntHfV8yPQ0KXGJlZ2lue2JtYXRyaXh9DQoxLjAwICYgMS4wMCAmIC0xLjAwICYgLTEuMDAgJiAxLjAwXFwNCjEuMDAgJiAxLjAwICYgLTEuMDAgJiAtMS4wMCAmIDEuMDBcXA0KMS4wMCAmIDEuMDAgJiAtMS4wMCAmIC0xLjAwICYgMS4wMFxcDQoxLjAwICYgMS4wMCAmIC0xLjAwICYgLTEuMDAgJiAxLjAwXFwNCjEuMDAgJiAxLjAwICYgLTEuMDAgJiAxLjAwICYgMS4wMA0KXGVuZHtibWF0cml4fS4NClxdDQoNCktlZHVhIG1hdHJpa3MgaGFzaWwgKmZvbGRpbmcqLCB5YWl0dSBcKFxtYXRoYmZ7R31fMVwpIGRhbiBcKFxtYXRoYmZ7R31fMlwpLCBtYXNpbmctbWFzaW5nIGJlcnVrdXJhbiBcKDVcdGltZXM1XCkuDQoNCiMjIyBiLiBQcm95ZWtzaSBkYW4gYWt0aXZhc2kgKmZlYXR1cmUgbWFwKiBnbG9iYWwNCg0KRHVhIGthbmFsIGhhc2lsICpmb2xkaW5nKiwgeWFpdHUgXChcbWF0aGJme0d9XzFcKSBkYW4gXChcbWF0aGJme0d9XzJcKSwgZGlwcm95ZWtzaWthbiBtZW5qYWRpIHNhdHUga2FuYWwgbWVuZ2d1bmFrYW4gKnBvaW50d2lzZSBjb252b2x1dGlvbiogXCgxXHRpbWVzMVwpIHRhbnBhIGJpYXMuIEhhc2lsIHByb3lla3NpIGtlbXVkaWFuIGRpdGVyYXBrYW4gZnVuZ3NpIFN3aXNoIHVudHVrIG1lbWJlbnR1ayAqZmVhdHVyZSBtYXAqIGdsb2JhbCBcKFxtYXRoYmZ7R31fe1xtYXRocm17Z2xvYn19XCkuDQoNCi0gKipCb2JvdCBwcm95ZWtzaSBnbG9iYWw6KioNCg0KXFsNClxtYXRoYmZ7V31fe1xtYXRocm17Z2xvYn19DQo9DQpcYmVnaW57Ym1hdHJpeH0NCjAuNTUgJiAtMC4zMA0KXGVuZHtibWF0cml4fS4NClxdDQoNCi0gKipSdW11czoqKg0KDQpOaWxhaSBoYXNpbCBwcm95ZWtzaSBzZWJlbHVtIGFrdGl2YXNpIGRpbm90YXNpa2FuIHNlYmFnYWkgXChGX3tcbWF0aHJte2dsb2J9LGksan1cKToNCg0KXFsNCkZfe1xtYXRocm17Z2xvYn0saSxqfQ0KPQ0KMC41NUdfezEsaSxqfQ0KLQ0KMC4zMEdfezIsaSxqfS4NClxdDQoNClNlbGFuanV0bnlhLCBmdW5nc2kgU3dpc2ggZGl0ZXJhcGthbiBzZWJhZ2FpIGJlcmlrdXQ6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NCkdfe1xtYXRocm17Z2xvYn0saSxqfQ0KJj0NClxvcGVyYXRvcm5hbWV7U3dpc2h9DQpcbGVmdCgNCkZfe1xtYXRocm17Z2xvYn0saSxqfQ0KXHJpZ2h0KVxcDQomPQ0KXGZyYWN7DQpGX3tcbWF0aHJte2dsb2J9LGksan0NCn17DQoxK2Veey1GX3tcbWF0aHJte2dsb2J9LGksan19DQp9Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KTWF0cmlrcyBcKFxtYXRoYmZ7R31fe1xtYXRocm17Z2xvYn19XCkgYmVydWt1cmFuIFwoNVx0aW1lczVcKS4NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiBwYWRhIHBvc2lzaSBcKCgxLDEpXCk6KioNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KRl97XG1hdGhybXtnbG9ifSwxLDF9DQomPQ0KMC41NUdfezEsMSwxfQ0KLQ0KMC4zMEdfezIsMSwxfVxcDQomPQ0KMC41NSgtMS4wMCkNCi0NCjAuMzAoMS4wMClcXA0KJj0NCi0wLjg1Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KR197XG1hdGhybXtnbG9ifSwxLDF9DQomPQ0KXG9wZXJhdG9ybmFtZXtTd2lzaH0oLTAuODUpXFwNCiY9DQpcZnJhY3stMC44NX17MStlXnstKC0wLjg1KX19XFwNCiY9DQpcZnJhY3stMC44NX17MStlXnswLjg1fX1cXA0KJj0NClxmcmFjey0wLjg1fXsxKzIuMzR9XFwNCiY9DQotMC4yNS4NClxlbmR7YWxpZ25lZH0NClxdDQoNClVudHVrIHBvc2lzaSBkZW5nYW4gXChHX3sxLGksan09MS4wMFwpIGRhbiBcKEdfezIsaSxqfT0tMS4wMFwpLCBkaXBlcm9sZWggbmlsYWkgaGFzaWwgcHJveWVrc2kgc2ViZXNhciBcKDAuODVcKSwgc2VoaW5nZ2EgbmlsYWkgc2V0ZWxhaCBha3RpdmFzaSBTd2lzaCBhZGFsYWggXCgwLjYwXCkuDQoNCkRlbmdhbiBhdHVyYW4geWFuZyBzYW1hLCBkaXBlcm9sZWggKmZlYXR1cmUgbWFwKiBnbG9iYWwgc2ViYWdhaSBiZXJpa3V0Lg0KDQpcWw0KXG1hdGhiZntHfV97XG1hdGhybXtnbG9ifX09DQpcYmVnaW57Ym1hdHJpeH0NCi0wLjI1ICYgLTAuMjUgJiAwLjYwICYgMC42MCAmIC0wLjI1XFwNCi0wLjI1ICYgLTAuMjUgJiAwLjYwICYgMC42MCAmIC0wLjI1XFwNCi0wLjI1ICYgLTAuMjUgJiAwLjYwICYgMC42MCAmIC0wLjI1XFwNCi0wLjI1ICYgLTAuMjUgJiAwLjYwICYgMC42MCAmIC0wLjI1XFwNCi0wLjI1ICYgLTAuMjUgJiAwLjYwICYgLTAuMjUgJiAtMC4yNQ0KXGVuZHtibWF0cml4fS4NClxdDQoNCg0KIyMjIGMuIEZ1c2kgcmVzaWR1YWwgZml0dXIgbG9rYWwgZGFuIGdsb2JhbA0KDQoqRmVhdHVyZSBtYXAqIGxva2FsIFwoXG1hdGhiZntMfVwpIGRhbiAqZmVhdHVyZSBtYXAqIGdsb2JhbCBcKFxtYXRoYmZ7R31fe1xtYXRocm17Z2xvYn19XCkgZGlnYWJ1bmdrYW4gbWVsYWx1aSBvcGVyYXNpICpjb25jYXRlbmF0ZSouIEhhc2lsIHBlbmdnYWJ1bmdhbiB0ZXJzZWJ1dCBkaXByb3lla3Npa2FuIG1lbmdndW5ha2FuICpwb2ludHdpc2UgY29udm9sdXRpb24qIFwoMVx0aW1lczFcKSwga2VtdWRpYW4gZGl0YW1iYWhrYW4gZGVuZ2FuICpmZWF0dXJlIG1hcCogbWFzdWthbiBcKFxtYXRoYmZ7WH1cKSBtZWxhbHVpICpyZXNpZHVhbCBjb25uZWN0aW9uKi4gS2VsdWFyYW4gZnVzaSBkaW5vdGFzaWthbiBzZWJhZ2FpIFwoXG1hdGhiZntYfV57MCwwfVwpLg0KDQpQYWRhIGlsdXN0cmFzaSBpbmksICpwb2ludHdpc2UgY29udm9sdXRpb24qIFwoMVx0aW1lczFcKSBkaWxha3VrYW4gdGFucGEgYmlhcy4gQm9ib3QgZnVzaSB1bnR1ayAqZmVhdHVyZSBtYXAqIGxva2FsIGRhbiBnbG9iYWwgZGl0ZXRhcGthbiBzZWJhZ2FpIGJlcmlrdXQ6DQoNClxbDQpcbWF0aGJme1d9X3tcbWF0aHJte2Z1c2V9fQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjQ1ICYgMC4zNQ0KXGVuZHtibWF0cml4fS4NClxdDQoNCkJvYm90IHBlcnRhbWEgZGl0ZXJhcGthbiBwYWRhIFwoXG1hdGhiZntMfVwpLCBzZWRhbmdrYW4gYm9ib3Qga2VkdWEgZGl0ZXJhcGthbiBwYWRhIFwoXG1hdGhiZntHfV97XG1hdGhybXtnbG9ifX1cKS4NCg0KLSAqKlJ1bXVzOioqDQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClxtYXRoYmZ7WH1eezAsMH0NCiY9DQpcbWF0aGJme1h9DQorDQpcb3BlcmF0b3JuYW1le0NvbnZ9X3sxXHRpbWVzMX0NClxsZWZ0KA0KXG9wZXJhdG9ybmFtZXtDb25jYXR9DQpcbGVmdFsNClxtYXRoYmZ7TH0sDQpcbWF0aGJme0d9X3tcbWF0aHJte2dsb2J9fQ0KXHJpZ2h0XQ0KXHJpZ2h0KS4NClxlbmR7YWxpZ25lZH0NClxdDQoNClVudHVrIHNldGlhcCBwb3Npc2kgc3Bhc2lhbCBcKChpLGopXCksIGJlbnR1ayBwZXJoaXR1bmdhbm55YSBhZGFsYWg6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NCkZfe1xtYXRocm17ZnVzZX0saSxqfQ0KJj0NCjAuNDVMX3tpLGp9DQorDQowLjM1R197XG1hdGhybXtnbG9ifSxpLGp9LFxcDQpYXnswLDB9X3tpLGp9DQomPQ0KWF97aSxqfQ0KKw0KRl97XG1hdGhybXtmdXNlfSxpLGp9XFwNCiY9DQpYX3tpLGp9DQorDQowLjQ1TF97aSxqfQ0KKw0KMC4zNUdfe1xtYXRocm17Z2xvYn0saSxqfS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gcGFkYSBwb3Npc2kgXCgoMSwxKVwpOioqDQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClheezAsMH1fezEsMX0NCiY9DQpYX3sxLDF9DQorDQowLjQ1TF97MSwxfQ0KKw0KMC4zNUdfe1xtYXRocm17Z2xvYn0sMSwxfVxcDQomPQ0KLTIuMTINCisNCjAuNDUoLTAuMjgpDQorDQowLjM1KC0wLjI1KVxcDQomPQ0KLTIuMTItMC4xMjYtMC4wODc1XFwNCiY9DQotMi4zMy4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBwZXJoaXR1bmdhbiB5YW5nIHNhbWEsIGRpcGVyb2xlaCBrZWx1YXJhbiBibG9rIE1vYmlsZVZpVHYzLXYyLTEuMCBzZWJhZ2FpIGJlcmlrdXQuDQoNClxbDQpcbWF0aGJme1h9XnswLDB9PQ0KXGJlZ2lue2JtYXRyaXh9DQotMi4zMyAmIC0xLjIxICYgMS41NSAmIDAuOTEgJiAtMS43NlxcDQotMi4zMyAmIC0wLjk0ICYgMS45MSAmIDEuMjUgJiAtMS42MlxcDQotMi4zMyAmIC0wLjk0ICYgMS45MiAmIDEuMjUgJiAtMS42MlxcDQotMi4zMyAmIC0xLjA4ICYgMS41NCAmIDAuODggJiAtMS43N1xcDQotMi4xOSAmIC0xLjUwICYgMC41OCAmIC0wLjMyICYgLTEuOTENClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQpNYXRyaWtzIFwoXG1hdGhiZntYfV57MCwwfVwpIGJlcnVrdXJhbiBcKDVcdGltZXM1XCkuIEtlbHVhcmFuIGluaSBtZW5qYWRpIG1hc3VrYW4gcGFkYSB0YWhhcCAqZW5jb2RlciBkb3duc2FtcGxpbmcqIGRhbiBkZWNvZGVyIFVOZXQrKy4NCg0KIyMgNS4gKkVuY29kZXIqIEJlcnRpbmdrYXQgDQoNClBhZGEgdGFoYXAgaW5pLCBmZWF0dXJlIG1hcCBrZWx1YXJhbiBNb2JpbGVWaVR2My12MiwgeWFpdHUgKFxtYXRoYmZ7WH1eezAsMH0pLCBkaXByb3NlcyBtZWxhbHVpIHRhaGFwYW4gZW5jb2RlciBiZXJ0aW5na2F0IHVudHVrIG1lbXBlcm9sZWggcmVwcmVzZW50YXNpIGZpdHVyIHBhZGEgYmVyYmFnYWkgc2thbGEgc3Bhc2lhbC4gUHJvc2VzIGRvd25zYW1wbGluZyBkaWxha3VrYW4gbWVuZ2d1bmFrYW4gc3RyaWRlZCBjb252b2x1dGlvbiB1bnR1ayBtZW5ndXJhbmdpIGRpbWVuc2kgc3Bhc2lhbCBmZWF0dXJlIG1hcCBzZWNhcmEgYmVydGFoYXAuIFNldGlhcCB0YWhhcCBtZW5naGFzaWxrYW4gcmVwcmVzZW50YXNpIGZpdHVyIGRlbmdhbiB1a3VyYW4gc3Bhc2lhbCB5YW5nIGxlYmloIGtlY2lsLCB5YW5nIHNlbGFuanV0bnlhIGRpZ3VuYWthbiBwYWRhIHByb3NlcyBla3N0cmFrc2kgZml0dXIgYmVydGluZ2thdC4gUGFkYSBqYWx1ciBlbmNvZGVyLCB0aWRhayBkaWxha3VrYW4gb3BlcmFzaSB1cHNhbXBsaW5nIGthcmVuYSBwcm9zZXMgdGVyc2VidXQgbWVydXBha2FuIGJhZ2lhbiBkYXJpIHRhaGFwYW4gZGVjb2Rlci4NCg0KIyMjIGEuICpEb3duc2FtcGxpbmcgZW5jb2RlciogcGVydGFtYSBcKFxsZWZ0KFxtYXRoYmZ7WH1eezEsMH1ccmlnaHQpXCkNCg0KKkZlYXR1cmUgbWFwKiBcKFxtYXRoYmZ7WH1eezAsMH1cKSBiZXJ1a3VyYW4gXCg1XHRpbWVzNVwpIGRpcHJvc2VzIG1lbmdndW5ha2FuICpzdHJpZGVkIGNvbnZvbHV0aW9uKiBkZW5nYW4ga2VybmVsIFwoM1x0aW1lczNcKSwgKnN0cmlkZSogXCgyXCksIGRhbiAqemVybyBwYWRkaW5nKiBzZWJlc2FyIFwoMVwpIHBhZGEgc2V0aWFwIHNpc2kuIFBhZGEgaWx1c3RyYXNpIGluaSwgb3BlcmFzaSBrb252b2x1c2kgZGlsYWt1a2FuIHRhbnBhIGJpYXMuIEtlbHVhcmFuIGtvbnZvbHVzaSBwYWRhIHRhaGFwIGluaSBkaW5vdGFzaWthbiBzZWJhZ2FpIFwoXG1hdGhiZntGfV97XG1hdGhybXtlbmN9fV57KDEpfVwpLCBkZW5nYW46DQoNClxbDQpcbWF0aGJme1h9XnsxLDB9DQo9DQpcbWF0aGJme0Z9X3tcbWF0aHJte2VuY319XnsoMSl9Lg0KXF0NCg0KLSAqKlBlbmFtYmFoYW4gWmVybyBQYWRkaW5nOioqDQoNClNlYmVsdW0gb3BlcmFzaSAqc3RyaWRlZCBjb252b2x1dGlvbiogZGlsYWt1a2FuLCBzYXR1IGxhcGlzYW4gbmlsYWkgbm9sIGRpdGFtYmFoa2FuIHBhZGEga2VlbXBhdCBzaXNpICpmZWF0dXJlIG1hcCogbWFzdWthbiwgeWFpdHUgc2lzaSBhdGFzLCBiYXdhaCwga2lyaSwgZGFuIGthbmFuLiBQZW5hbWJhaGFuICp6ZXJvIHBhZGRpbmcqIG1lbXVuZ2tpbmthbiBrZXJuZWwgbWVuY2FrdXAgYXJlYSB0ZXBpIG1hdHJpa3Mgc2VsYW1hIHByb3NlcyBrb252b2x1c2kuDQoNCk1hdHJpa3MgKmZlYXR1cmUgbWFwKiBtYXN1a2FuIG1lcnVwYWthbiBrZWx1YXJhbiBibG9rIE1vYmlsZVZpVHYzLXYyLTEuMCB5YW5nIGRpcGVyb2xlaCBwYWRhIHRhaGFwIHNlYmVsdW1ueWEsIHlhaXR1Og0KDQpcWw0KXG1hdGhiZntYfV57MCwwfQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQotMi4zMyAmIC0xLjIxICYgMS41NSAmIDAuOTEgJiAtMS43NlxcDQotMi4zMyAmIC0wLjk0ICYgMS45MSAmIDEuMjUgJiAtMS42MlxcDQotMi4zMyAmIC0wLjk0ICYgMS45MiAmIDEuMjUgJiAtMS42MlxcDQotMi4zMyAmIC0xLjA4ICYgMS41NCAmIDAuODggJiAtMS43N1xcDQotMi4xOSAmIC0xLjUwICYgMC41OCAmIC0wLjMyICYgLTEuOTENClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQpTZXRlbGFoIHBlbmFtYmFoYW4gKnplcm8gcGFkZGluZyogc2ViZXNhciBzYXR1IHBpa3NlbCBwYWRhIHNldGlhcCBzaXNpLCB1a3VyYW4gbWF0cmlrcyBiZXJ1YmFoIGRhcmkgXCg1XHRpbWVzNVwpIG1lbmphZGkgXCg3XHRpbWVzN1wpLCB5YWl0dToNCg0KXFsNClxtYXRoYmZ7WH1fe1xtYXRocm17cGFkfX1eezAsMH0NCj0NClxiZWdpbntibWF0cml4fQ0KMC4wMCAmIDAuMDAgJiAwLjAwICYgMC4wMCAmIDAuMDAgJiAwLjAwICYgMC4wMFxcDQowLjAwICYgLTIuMzMgJiAtMS4yMSAmIDEuNTUgJiAwLjkxICYgLTEuNzYgJiAwLjAwXFwNCjAuMDAgJiAtMi4zMyAmIC0wLjk0ICYgMS45MSAmIDEuMjUgJiAtMS42MiAmIDAuMDBcXA0KMC4wMCAmIC0yLjMzICYgLTAuOTQgJiAxLjkyICYgMS4yNSAmIC0xLjYyICYgMC4wMFxcDQowLjAwICYgLTIuMzMgJiAtMS4wOCAmIDEuNTQgJiAwLjg4ICYgLTEuNzcgJiAwLjAwXFwNCjAuMDAgJiAtMi4xOSAmIC0xLjUwICYgMC41OCAmIC0wLjMyICYgLTEuOTEgJiAwLjAwXFwNCjAuMDAgJiAwLjAwICYgMC4wMCAmIDAuMDAgJiAwLjAwICYgMC4wMCAmIDAuMDANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQotICoqS2VybmVsIEVuY29kZXIgUGVydGFtYToqKg0KDQpQYWRhIGlsdXN0cmFzaSBpbmksIGtlcm5lbCBkaXNlZGVyaGFuYWthbiBkZW5nYW4gaGFueWEgZWxlbWVuIHRlbmdhaCBiZXJuaWxhaSBzYXR1IGRhbiBlbGVtZW4gbGFpbm55YSBiZXJuaWxhaSBub2w6DQoNClxbDQpcbWF0aGJme1d9X3tcbWF0aHJte2VuY319XnsoMSl9DQo9DQpcYmVnaW57Ym1hdHJpeH0NCjAgJiAwICYgMFxcDQowICYgMSAmIDBcXA0KMCAmIDAgJiAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KS2VybmVsIHRlcnNlYnV0IGRpZ3VuYWthbiB1bnR1ayBtZW5naWx1c3RyYXNpa2FuIG9wZXJhc2kgKnN0cmlkZWQgY29udm9sdXRpb24qLiBQYWRhIHNldGlhcCBwb3Npc2ksIHNlbWJpbGFuIGVsZW1lbiBkYWxhbSBhcmVhIGtvbnZvbHVzaSBkaWthbGlrYW4gZGVuZ2FuIHNlbWJpbGFuIGJvYm90IGtlcm5lbCB5YW5nIGJlcnNlc3VhaWFuLCBrZW11ZGlhbiBzZWx1cnVoIGhhc2lsIHBlcmthbGlhbiBkaWp1bWxhaGthbi4NCg0KS2FyZW5hIGhhbnlhIGJvYm90IHB1c2F0IGtlcm5lbCB5YW5nIGJlcm5pbGFpIHNhdHUsIGhhc2lsIGtvbnZvbHVzaSBwYWRhIGlsdXN0cmFzaSBpbmkgZGl0ZW50dWthbiBvbGVoIGVsZW1lbiB5YW5nIGJlcmFkYSB0ZXBhdCBkaSBiYXdhaCBwdXNhdCBrZXJuZWwuIFNlbWVudGFyYSBpdHUsIHBlbmdndW5hYW4gKnN0cmlkZSogc2ViZXNhciBcKDJcKSBtZW55ZWJhYmthbiBrZXJuZWwgYmVyZ2VzZXIgZHVhIHBvc2lzaSBwYWRhIHNldGlhcCBwZXJwaW5kYWhhbi4NCg0KVWt1cmFuIGtlbHVhcmFuIGRpaGl0dW5nIG1lbmdndW5ha2FuOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpvDQomPQ0KXGxlZnRcbGZsb29yDQpcZnJhY3tpKzJwLWt9e3N9DQpccmlnaHRccmZsb29yKzFcXA0KJj0NClxsZWZ0XGxmbG9vcg0KXGZyYWN7NSsyKDEpLTN9ezJ9DQpccmlnaHRccmZsb29yKzFcXA0KJj0NClxsZWZ0XGxmbG9vcg0KXGZyYWN7NH17Mn0NClxyaWdodFxyZmxvb3IrMVxcDQomPTMuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gZGVtaWtpYW4sIHVrdXJhbiBzcGFzaWFsICpmZWF0dXJlIG1hcCogYmVydWJhaCBkYXJpIFwoNVx0aW1lczVcKSBtZW5qYWRpIFwoM1x0aW1lczNcKS4NCg0KLSAqKlJ1bXVzOioqDQoNClNlY2FyYSB1bXVtLCBvcGVyYXNpICpzdHJpZGVkIGNvbnZvbHV0aW9uKiBkZW5nYW4ga2VybmVsIFwoM1x0aW1lczNcKSwgKnN0cmlkZSogXCgyXCksIGRhbiAqcGFkZGluZyogXCgxXCkgZGlueWF0YWthbiBzZWJhZ2FpOg0KDQpcWw0KRl97XG1hdGhybXtlbmN9LGEsYn1eeygxKX0NCj0NClxzdW1fe3U9MX1eezN9DQpcc3VtX3t2PTF9XnszfQ0KV197XG1hdGhybXtlbmN9LHUsdn1eeygxKX0NClhfe1xtYXRocm17cGFkfSwyYSt1LTIsXCwyYit2LTJ9XnswLDB9LA0KXF0NCg0KZGVuZ2FuIFwoYSxiPTEsMiwzXCksIHNlZGFuZ2thbiBcKHVcKSBkYW4gXCh2XCkgbWVydXBha2FuIGluZGVrcyBiYXJpcyBkYW4ga29sb20ga2VybmVsLg0KDQpQYWRhIHNldGlhcCBwb3Npc2ksIGtlcm5lbCBtZW5jYWt1cCBhcmVhIGJlcnVrdXJhbiBcKDNcdGltZXMzXCkuIEthcmVuYSAqc3RyaWRlKiBiZXJuaWxhaSBcKDJcKSwga2VybmVsIGJlcmdlc2VyIGR1YSBrb2xvbSBrZSBrYW5hbiB1bnR1ayBtZW5naGl0dW5nIGVsZW1lbiBiZXJpa3V0bnlhIHBhZGEgYmFyaXMga2VsdWFyYW4geWFuZyBzYW1hLiBTZXRlbGFoIG1lbmNhcGFpIHBvc2lzaSB0ZXJha2hpciBwYWRhIGJhcmlzIHRlcnNlYnV0LCBrZXJuZWwga2VtYmFsaSBrZSBzaXNpIGtpcmkgZGFuIGJlcmdlc2VyIGR1YSBiYXJpcyBrZSBiYXdhaC4NCg0KLSAqKkNvbnRvaCBQZXJoaXR1bmdhbiBLb252b2x1c2k6KioNCg0KKioxLiBQZXJoaXR1bmdhbiBlbGVtZW4gcGFkYSBwb3Npc2kgXCgoMSwxKVwpKioNCg0KVW50dWsgbWVuZ2hhc2lsa2FuIGVsZW1lbiBwZXJ0YW1hIGRhcmkgKmZlYXR1cmUgbWFwKiBrZWx1YXJhbiwga2VybmVsIGRpdGVtcGF0a2FuIHBhZGEgYXJlYSBcKDNcdGltZXMzXCkgZGkgcG9qb2sga2lyaSBhdGFzIG1hdHJpa3MgeWFuZyB0ZWxhaCBkaWJlcmkgKnplcm8gcGFkZGluZyouDQoNCkFyZWEgKmZlYXR1cmUgbWFwKiB5YW5nIGRpcHJvc2VzIGFkYWxhaDoNCg0KXFsNClxiZWdpbntibWF0cml4fQ0KMC4wMCAmIDAuMDAgJiAwLjAwXFwNCjAuMDAgJiAtMi4zMyAmIC0xLjIxXFwNCjAuMDAgJiAtMi4zMyAmIC0wLjk0DQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KU2V0aWFwIGVsZW1lbiBwYWRhIGFyZWEgdGVyc2VidXQgZGlrYWxpa2FuIGRlbmdhbiBib2JvdCBrZXJuZWwgeWFuZyBiZXJzZXN1YWlhbiwga2VtdWRpYW4gc2VsdXJ1aCBoYXNpbCBwZXJrYWxpYW4gZGlqdW1sYWhrYW4gc2ViYWdhaSBiZXJpa3V0Og0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpGX3tcbWF0aHJte2VuY30sMSwxfV57KDEpfQ0KPXt9Jg0KKDAuMDApKDApDQorKDAuMDApKDApDQorKDAuMDApKDApXFwNCiYrKDAuMDApKDApDQorKC0yLjMzKSgxKQ0KKygtMS4yMSkoMClcXA0KJisoMC4wMCkoMCkNCisoLTIuMzMpKDApDQorKC0wLjk0KSgwKVxcDQo9e30mLTIuMzMuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gZGVtaWtpYW4sIG5pbGFpIGVsZW1lbiBrZWx1YXJhbiBwYWRhIHBvc2lzaSBcKCgxLDEpXCkgYWRhbGFoOg0KDQpcWw0KWF97MSwxfV57MSwwfQ0KPQ0KRl97XG1hdGhybXtlbmN9LDEsMX1eeygxKX0NCj0NCi0yLjMzLg0KXF0NCg0KKioyLiBQZXJoaXR1bmdhbiBlbGVtZW4gcGFkYSBwb3Npc2kgXCgoMSwyKVwpKioNCg0KVW50dWsgbWVuZ2hpdHVuZyBlbGVtZW4gcGFkYSBwb3Npc2kgXCgoMSwyKVwpLCBrZXJuZWwgYmVyZ2VzZXIgZHVhIGtvbG9tIGtlIGthbmFuIGRhcmkgcG9zaXNpIHNlYmVsdW1ueWEga2FyZW5hICpzdHJpZGUqIHlhbmcgZGlndW5ha2FuIGJlcm5pbGFpIFwoMlwpLg0KDQpBcmVhICpmZWF0dXJlIG1hcCogeWFuZyBkaXByb3NlcyBhZGFsYWg6DQoNClxbDQpcYmVnaW57Ym1hdHJpeH0NCjAuMDAgJiAwLjAwICYgMC4wMFxcDQotMS4yMSAmIDEuNTUgJiAwLjkxXFwNCi0wLjk0ICYgMS45MSAmIDEuMjUNClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQpQZXJoaXR1bmdhbiBrb252b2x1c2kgZGlsYWt1a2FuIG1lbmdndW5ha2FuIGJvYm90IGtlcm5lbCB5YW5nIHNhbWE6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NCkZfe1xtYXRocm17ZW5jfSwxLDJ9XnsoMSl9DQo9e30mDQooMC4wMCkoMCkNCisoMC4wMCkoMCkNCisoMC4wMCkoMClcXA0KJisoLTEuMjEpKDApDQorKDEuNTUpKDEpDQorKDAuOTEpKDApXFwNCiYrKC0wLjk0KSgwKQ0KKygxLjkxKSgwKQ0KKygxLjI1KSgwKVxcDQo9e30mMS41NS4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBkZW1pa2lhbiwgbmlsYWkgZWxlbWVuIGtlbHVhcmFuIHBhZGEgcG9zaXNpIFwoKDEsMilcKSBhZGFsYWg6DQoNClxbDQpYX3sxLDJ9XnsxLDB9DQo9DQpGX3tcbWF0aHJte2VuY30sMSwyfV57KDEpfQ0KPQ0KMS41NS4NClxdDQoNClByb3NlZHVyIHlhbmcgc2FtYSBkaXRlcmFwa2FuIHBhZGEgc2VsdXJ1aCBwb3Npc2kga2VybmVsLiBTZXRpYXAgZWxlbWVuIGtlbHVhcmFuIGRpcGVyb2xlaCBtZWxhbHVpIHBlbmp1bWxhaGFuIGhhc2lsIHBlcmthbGlhbiBlbGVtZW4gcGFkYSBhcmVhIGtvbnZvbHVzaSBkZW5nYW4gYm9ib3Qga2VybmVsIHlhbmcgYmVyc2VzdWFpYW4uDQoNCkRlbmdhbiBtZW5lcmFwa2FuIG9wZXJhc2kgKnN0cmlkZWQgY29udm9sdXRpb24qIHBhZGEgc2VsdXJ1aCBwb3Npc2ksIGRpcGVyb2xlaCAqZmVhdHVyZSBtYXAgZW5jb2RlciogcGVydGFtYSBiZXJ1a3VyYW4gXCgzXHRpbWVzM1wpLCB5YWl0dToNCg0KXFsNClxtYXRoYmZ7WH1eezEsMH0NCj0NClxiZWdpbntibWF0cml4fQ0KLTIuMzMgJiAxLjU1ICYgLTEuNzZcXA0KLTIuMzMgJiAxLjkyICYgLTEuNjJcXA0KLTIuMTkgJiAwLjU4ICYgLTEuOTENClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQpIYXNpbCB0ZXJzZWJ1dCBtZW51bmp1a2thbiBiYWh3YSBvcGVyYXNpICpzdHJpZGVkIGNvbnZvbHV0aW9uKiBkZW5nYW4gKnN0cmlkZSogXCgyXCkgbWVuZ3VyYW5naSB1a3VyYW4gc3Bhc2lhbCAqZmVhdHVyZSBtYXAqIGRhcmkgXCg1XHRpbWVzNVwpIG1lbmphZGkgXCgzXHRpbWVzM1wpLiBQYWRhIGlsdXN0cmFzaSBpbmksIHBlbnllZGVyaGFuYWFuIGJvYm90IGtlcm5lbCBtZW55ZWJhYmthbiBzZXRpYXAgZWxlbWVuIGtlbHVhcmFuIHNhbWEgZGVuZ2FuIGVsZW1lbiBtYXN1a2FuIHlhbmcgYmVyYWRhIHBhZGEgcG9zaXNpIHB1c2F0IGtlcm5lbC4gTmFtdW4sIHBhZGEgaW1wbGVtZW50YXNpIG1vZGVsIHNlYmVuYXJueWEsIGJvYm90IGtlcm5lbCBkaXBlbGFqYXJpIHNlbGFtYSBwZWxhdGloYW4gc2VoaW5nZ2Ega2VsdWFyYW4ga29udm9sdXNpIG1lcnVwYWthbiBrb21iaW5hc2kgYmVyYm9ib3QgZGFyaSBlbGVtZW4tZWxlbWVuIHBhZGEgYXJlYSB5YW5nIGRpcHJvc2VzLg0KDQoNCg0KIyMjIGIuICpEb3duc2FtcGxpbmcgZW5jb2Rlcioga2VkdWEgXChcbGVmdChcbWF0aGJme1h9XnsyLDB9XHJpZ2h0KVwpDQoNCipGZWF0dXJlIG1hcCogXChcbWF0aGJme1h9XnsxLDB9XCkgYmVydWt1cmFuIFwoM1x0aW1lczNcKSBrZW1iYWxpIGRpcHJvc2VzIG1lbmdndW5ha2FuICpzdHJpZGVkIGNvbnZvbHV0aW9uKiBkZW5nYW4ga2VybmVsIFwoM1x0aW1lczNcKSwgKnN0cmlkZSogXCgyXCksIGRhbiAqemVybyBwYWRkaW5nKiBzZWJlc2FyIFwoMVwpIHBhZGEgc2V0aWFwIHNpc2kuIFBhZGEgaWx1c3RyYXNpIGluaSwgb3BlcmFzaSBrb252b2x1c2kgZGlsYWt1a2FuIHRhbnBhIGJpYXMuIEtlbHVhcmFuIGtvbnZvbHVzaSBwYWRhIHRhaGFwIGtlZHVhIGRpbm90YXNpa2FuIHNlYmFnYWkgXChcbWF0aGJme0Z9X3tcbWF0aHJte2VuY319XnsoMil9XCksIGRlbmdhbjoNCg0KXFsNClxtYXRoYmZ7WH1eezIsMH0NCj0NClxtYXRoYmZ7Rn1fe1xtYXRocm17ZW5jfX1eeygyKX0uDQpcXQ0KDQotICoqUGVuYW1iYWhhbiBaZXJvIFBhZGRpbmc6KioNCg0KU2ViZWx1bSBvcGVyYXNpICpzdHJpZGVkIGNvbnZvbHV0aW9uKiBkaWxha3VrYW4sIHNhdHUgbGFwaXNhbiBuaWxhaSBub2wgZGl0YW1iYWhrYW4gcGFkYSBrZWVtcGF0IHNpc2kgKmZlYXR1cmUgbWFwKiBtYXN1a2FuLCB5YWl0dSBzaXNpIGF0YXMsIGJhd2FoLCBraXJpLCBkYW4ga2FuYW4uIFBlbmFtYmFoYW4gKnplcm8gcGFkZGluZyogbWVtdW5na2lua2FuIGtlcm5lbCBtZW5jYWt1cCBhcmVhIHRlcGkgbWF0cmlrcyBzZWxhbWEgcHJvc2VzIGtvbnZvbHVzaS4NCg0KTWF0cmlrcyAqZmVhdHVyZSBtYXAqIG1hc3VrYW4gbWVydXBha2FuIGhhc2lsICpkb3duc2FtcGxpbmcgZW5jb2RlciogcGVydGFtYSwgeWFpdHU6DQoNClxbDQpcbWF0aGJme1h9XnsxLDB9DQo9DQpcYmVnaW57Ym1hdHJpeH0NCi0yLjMzICYgMS41NSAmIC0xLjc2XFwNCi0yLjMzICYgMS45MiAmIC0xLjYyXFwNCi0yLjE5ICYgMC41OCAmIC0xLjkxDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KU2V0ZWxhaCBwZW5hbWJhaGFuICp6ZXJvIHBhZGRpbmcqIHNlYmVzYXIgc2F0dSBwaWtzZWwgcGFkYSBzZXRpYXAgc2lzaSwgdWt1cmFuIG1hdHJpa3MgYmVydWJhaCBkYXJpIFwoM1x0aW1lczNcKSBtZW5qYWRpIFwoNVx0aW1lczVcKSwgeWFpdHU6DQoNClxbDQpcbWF0aGJme1h9X3tcbWF0aHJte3BhZH19XnsxLDB9DQo9DQpcYmVnaW57Ym1hdHJpeH0NCjAuMDAgJiAwLjAwICYgMC4wMCAmIDAuMDAgJiAwLjAwXFwNCjAuMDAgJiAtMi4zMyAmIDEuNTUgJiAtMS43NiAmIDAuMDBcXA0KMC4wMCAmIC0yLjMzICYgMS45MiAmIC0xLjYyICYgMC4wMFxcDQowLjAwICYgLTIuMTkgJiAwLjU4ICYgLTEuOTEgJiAwLjAwXFwNCjAuMDAgJiAwLjAwICYgMC4wMCAmIDAuMDAgJiAwLjAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KLSAqKktlcm5lbCBFbmNvZGVyIEtlZHVhOioqDQoNClBhZGEgaWx1c3RyYXNpIGluaSwga2VybmVsIGtlZHVhIGRpc2VkZXJoYW5ha2FuIGRlbmdhbiBoYW55YSBlbGVtZW4gdGVuZ2FoIGJlcm5pbGFpIHNhdHUgZGFuIGVsZW1lbiBsYWlubnlhIGJlcm5pbGFpIG5vbDoNCg0KXFsNClxtYXRoYmZ7V31fe1xtYXRocm17ZW5jfX1eeygyKX0NCj0NClxiZWdpbntibWF0cml4fQ0KMCAmIDAgJiAwXFwNCjAgJiAxICYgMFxcDQowICYgMCAmIDANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQpLZXJuZWwgdGVyc2VidXQgZGlndW5ha2FuIHVudHVrIG1lbmdpbHVzdHJhc2lrYW4gb3BlcmFzaSAqc3RyaWRlZCBjb252b2x1dGlvbiogcGFkYSB0YWhhcCBrZWR1YS4gUGFkYSBzZXRpYXAgcG9zaXNpLCBzZW1iaWxhbiBlbGVtZW4gZGFsYW0gYXJlYSBrb252b2x1c2kgZGlrYWxpa2FuIGRlbmdhbiBzZW1iaWxhbiBib2JvdCBrZXJuZWwgeWFuZyBiZXJzZXN1YWlhbiwga2VtdWRpYW4gc2VsdXJ1aCBoYXNpbCBwZXJrYWxpYW4gZGlqdW1sYWhrYW4uDQoNCkthcmVuYSBoYW55YSBib2JvdCBwdXNhdCBrZXJuZWwgeWFuZyBiZXJuaWxhaSBzYXR1LCBoYXNpbCBrb252b2x1c2kgcGFkYSBpbHVzdHJhc2kgaW5pIGRpdGVudHVrYW4gb2xlaCBlbGVtZW4geWFuZyBiZXJhZGEgdGVwYXQgZGkgYmF3YWggcHVzYXQga2VybmVsLiBQZW5nZ3VuYWFuICpzdHJpZGUqIHNlYmVzYXIgXCgyXCkgbWVueWViYWJrYW4ga2VybmVsIGJlcmdlc2VyIGR1YSBwb3Npc2kgcGFkYSBzZXRpYXAgcGVycGluZGFoYW4uDQoNClVrdXJhbiBrZWx1YXJhbiBkaWhpdHVuZyBtZW5nZ3VuYWthbjoNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0Kbw0KJj0NClxsZWZ0XGxmbG9vcg0KXGZyYWN7aSsycC1rfXtzfQ0KXHJpZ2h0XHJmbG9vcisxXFwNCiY9DQpcbGVmdFxsZmxvb3INClxmcmFjezMrMigxKS0zfXsyfQ0KXHJpZ2h0XHJmbG9vcisxXFwNCiY9DQpcbGVmdFxsZmxvb3INClxmcmFjezJ9ezJ9DQpccmlnaHRccmZsb29yKzFcXA0KJj0yLg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KRGVuZ2FuIGRlbWlraWFuLCB1a3VyYW4gc3Bhc2lhbCAqZmVhdHVyZSBtYXAqIGJlcnViYWggZGFyaSBcKDNcdGltZXMzXCkgbWVuamFkaSBcKDJcdGltZXMyXCkuDQoNCi0gKipSdW11czoqKg0KDQpTZWNhcmEgdW11bSwgb3BlcmFzaSAqc3RyaWRlZCBjb252b2x1dGlvbiogcGFkYSB0YWhhcCBrZWR1YSBkZW5nYW4ga2VybmVsIFwoM1x0aW1lczNcKSwgKnN0cmlkZSogXCgyXCksIGRhbiAqcGFkZGluZyogXCgxXCkgZGlueWF0YWthbiBzZWJhZ2FpOg0KDQpcWw0KRl97XG1hdGhybXtlbmN9LGEsYn1eeygyKX0NCj0NClxzdW1fe3U9MX1eezN9DQpcc3VtX3t2PTF9XnszfQ0KV197XG1hdGhybXtlbmN9LHUsdn1eeygyKX0NClhfe1xtYXRocm17cGFkfSwyYSt1LTIsXCwyYit2LTJ9XnsxLDB9LA0KXF0NCg0KZGVuZ2FuIFwoYSxiPTEsMlwpLCBzZWRhbmdrYW4gXCh1XCkgZGFuIFwodlwpIG1lcnVwYWthbiBpbmRla3MgYmFyaXMgZGFuIGtvbG9tIGtlcm5lbC4NCg0KUGFkYSBzZXRpYXAgcG9zaXNpLCBrZXJuZWwgbWVuY2FrdXAgYXJlYSBiZXJ1a3VyYW4gXCgzXHRpbWVzM1wpLiBLYXJlbmEgKnN0cmlkZSogYmVybmlsYWkgXCgyXCksIGtlcm5lbCBiZXJnZXNlciBkdWEga29sb20ga2Uga2FuYW4gdW50dWsgbWVuZ2hpdHVuZyBlbGVtZW4gYmVyaWt1dG55YSBwYWRhIGJhcmlzIGtlbHVhcmFuIHlhbmcgc2FtYS4gU2V0ZWxhaCBtZW5jYXBhaSBwb3Npc2kgdGVyYWtoaXIgcGFkYSBiYXJpcyB0ZXJzZWJ1dCwga2VybmVsIGtlbWJhbGkga2Ugc2lzaSBraXJpIGRhbiBiZXJnZXNlciBkdWEgYmFyaXMga2UgYmF3YWguDQoNCkthcmVuYSBoYW55YSBib2JvdCBwdXNhdCBrZXJuZWwgeWFuZyBiZXJuaWxhaSBzYXR1LCBwZXJzYW1hYW4gdGVyc2VidXQgZGFwYXQgZGlzZWRlcmhhbmFrYW4gbWVuamFkaToNCg0KXFsNClhfe2EsYn1eezIsMH0NCj0NCkZfe1xtYXRocm17ZW5jfSxhLGJ9XnsoMil9DQo9DQpYX3syYS0xLFwsMmItMX1eezEsMH0uDQpcXQ0KDQotICoqQ29udG9oIFBlcmhpdHVuZ2FuIEtvbnZvbHVzaToqKg0KDQoqKjEuIFBlcmhpdHVuZ2FuIGVsZW1lbiBwYWRhIHBvc2lzaSBcKCgxLDEpXCkqKg0KDQpVbnR1ayBtZW5naGFzaWxrYW4gZWxlbWVuIHBlcnRhbWEgZGFyaSAqZmVhdHVyZSBtYXAqIGtlbHVhcmFuLCBrZXJuZWwgZGl0ZW1wYXRrYW4gcGFkYSBhcmVhIFwoM1x0aW1lczNcKSBkaSBwb2pvayBraXJpIGF0YXMgbWF0cmlrcyB5YW5nIHRlbGFoIGRpYmVyaSAqemVybyBwYWRkaW5nKi4NCg0KQXJlYSAqZmVhdHVyZSBtYXAqIHlhbmcgZGlwcm9zZXMgYWRhbGFoOg0KDQpcWw0KXGJlZ2lue2JtYXRyaXh9DQowLjAwICYgMC4wMCAmIDAuMDBcXA0KMC4wMCAmIC0yLjMzICYgMS41NVxcDQowLjAwICYgLTIuMzMgJiAxLjkyDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KU2V0aWFwIGVsZW1lbiBwYWRhIGFyZWEgdGVyc2VidXQgZGlrYWxpa2FuIGRlbmdhbiBib2JvdCBrZXJuZWwgeWFuZyBiZXJzZXN1YWlhbiwga2VtdWRpYW4gc2VsdXJ1aCBoYXNpbCBwZXJrYWxpYW4gZGlqdW1sYWhrYW4gc2ViYWdhaSBiZXJpa3V0Og0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpGX3tcbWF0aHJte2VuY30sMSwxfV57KDIpfQ0KPXt9Jg0KKDAuMDApKDApDQorKDAuMDApKDApDQorKDAuMDApKDApXFwNCiYrKDAuMDApKDApDQorKC0yLjMzKSgxKQ0KKygxLjU1KSgwKVxcDQomKygwLjAwKSgwKQ0KKygtMi4zMykoMCkNCisoMS45MikoMClcXA0KPXt9Ji0yLjMzLg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KRGVuZ2FuIGRlbWlraWFuLCBuaWxhaSBlbGVtZW4ga2VsdWFyYW4gcGFkYSBwb3Npc2kgXCgoMSwxKVwpIGFkYWxhaDoNCg0KXFsNClhfezEsMX1eezIsMH0NCj0NCkZfe1xtYXRocm17ZW5jfSwxLDF9XnsoMil9DQo9DQotMi4zMy4NClxdDQoNCioqMi4gUGVyaGl0dW5nYW4gZWxlbWVuIHBhZGEgcG9zaXNpIFwoKDEsMilcKSoqDQoNClVudHVrIG1lbmdoaXR1bmcgZWxlbWVuIHBhZGEgcG9zaXNpIFwoKDEsMilcKSwga2VybmVsIGJlcmdlc2VyIGR1YSBrb2xvbSBrZSBrYW5hbiBkYXJpIHBvc2lzaSBzZWJlbHVtbnlhIGthcmVuYSAqc3RyaWRlKiB5YW5nIGRpZ3VuYWthbiBiZXJuaWxhaSBcKDJcKS4NCg0KQXJlYSAqZmVhdHVyZSBtYXAqIHlhbmcgZGlwcm9zZXMgYWRhbGFoOg0KDQpcWw0KXGJlZ2lue2JtYXRyaXh9DQowLjAwICYgMC4wMCAmIDAuMDBcXA0KMS41NSAmIC0xLjc2ICYgMC4wMFxcDQoxLjkyICYgLTEuNjIgJiAwLjAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KUGVyaGl0dW5nYW4ga29udm9sdXNpIGRpbGFrdWthbiBtZW5nZ3VuYWthbiBib2JvdCBrZXJuZWwgeWFuZyBzYW1hOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpGX3tcbWF0aHJte2VuY30sMSwyfV57KDIpfQ0KPXt9Jg0KKDAuMDApKDApDQorKDAuMDApKDApDQorKDAuMDApKDApXFwNCiYrKDEuNTUpKDApDQorKC0xLjc2KSgxKQ0KKygwLjAwKSgwKVxcDQomKygxLjkyKSgwKQ0KKygtMS42MikoMCkNCisoMC4wMCkoMClcXA0KPXt9Ji0xLjc2Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KRGVuZ2FuIGRlbWlraWFuLCBuaWxhaSBlbGVtZW4ga2VsdWFyYW4gcGFkYSBwb3Npc2kgXCgoMSwyKVwpIGFkYWxhaDoNCg0KXFsNClhfezEsMn1eezIsMH0NCj0NCkZfe1xtYXRocm17ZW5jfSwxLDJ9XnsoMil9DQo9DQotMS43Ni4NClxdDQoNClByb3NlZHVyIHlhbmcgc2FtYSBkaXRlcmFwa2FuIHBhZGEgc2VsdXJ1aCBwb3Npc2kga2VybmVsLiBTZXRpYXAgZWxlbWVuIGtlbHVhcmFuIGRpcGVyb2xlaCBtZWxhbHVpIHBlbmp1bWxhaGFuIGhhc2lsIHBlcmthbGlhbiBlbGVtZW4gcGFkYSBhcmVhIGtvbnZvbHVzaSBkZW5nYW4gYm9ib3Qga2VybmVsIHlhbmcgYmVyc2VzdWFpYW4uDQoNCkRlbmdhbiBtZW5lcmFwa2FuIG9wZXJhc2kgKnN0cmlkZWQgY29udm9sdXRpb24qIHBhZGEgc2VsdXJ1aCBwb3Npc2ksIGRpcGVyb2xlaCAqZmVhdHVyZSBtYXAgZW5jb2Rlcioga2VkdWEgYmVydWt1cmFuIFwoMlx0aW1lczJcKSwgeWFpdHU6DQoNClxbDQpcbWF0aGJme1h9XnsyLDB9DQo9DQpcYmVnaW57Ym1hdHJpeH0NCi0yLjMzICYgLTEuNzZcXA0KLTIuMTkgJiAtMS45MQ0KXGVuZHtibWF0cml4fS4NClxdDQoNCkhhc2lsIHRlcnNlYnV0IG1lbnVuanVra2FuIGJhaHdhIG9wZXJhc2kgKnN0cmlkZWQgY29udm9sdXRpb24qIGRlbmdhbiAqc3RyaWRlKiBcKDJcKSBtZW5ndXJhbmdpIHVrdXJhbiBzcGFzaWFsICpmZWF0dXJlIG1hcCogZGFyaSBcKDNcdGltZXMzXCkgbWVuamFkaSBcKDJcdGltZXMyXCkuIFBhZGEgaWx1c3RyYXNpIGluaSwgcGVueWVkZXJoYW5hYW4gYm9ib3Qga2VybmVsIG1lbnllYmFia2FuIHNldGlhcCBlbGVtZW4ga2VsdWFyYW4gc2FtYSBkZW5nYW4gZWxlbWVuIG1hc3VrYW4geWFuZyBiZXJhZGEgcGFkYSBwb3Npc2kgcHVzYXQga2VybmVsLiBOYW11biwgcGFkYSBpbXBsZW1lbnRhc2kgbW9kZWwgc2ViZW5hcm55YSwgYm9ib3Qga2VybmVsIGRpcGVsYWphcmkgc2VsYW1hIHBlbGF0aWhhbiBzZWhpbmdnYSBrZWx1YXJhbiBrb252b2x1c2kgbWVydXBha2FuIGtvbWJpbmFzaSBiZXJib2JvdCBkYXJpIGVsZW1lbi1lbGVtZW4gcGFkYSBhcmVhIHlhbmcgZGlwcm9zZXMuDQoNCg0KDQoNCiMjIDYuIERlY29kZXIgVU5ldCsrDQoNCipEZWNvZGVyKiBVTmV0KysgbWVuZ2VtYmFsaWthbiB1a3VyYW4gc3Bhc2lhbCAqZmVhdHVyZSBtYXAqIHNlY2FyYSBiZXJ0YWhhcCBtZWxhbHVpIG9wZXJhc2kgKnVwc2FtcGxpbmcqLiBQYWRhIGlsdXN0cmFzaSBwZXJoaXR1bmdhbiBtYW51YWwgaW5pLCAqdXBzYW1wbGluZyogZGlsYWt1a2FuIG1lbmdndW5ha2FuIGludGVycG9sYXNpIGJpbGluZWFyLiBTZWxhbmp1dG55YSwgKmZlYXR1cmUgbWFwKiBkYXJpIGphbHVyICplbmNvZGVyKiBkYW4gbm9kZSAqZGVjb2Rlciogc2ViZWx1bW55YSBkaWdhYnVuZ2thbiBwYWRhIGRpbWVuc2kga2FuYWwgbWVsYWx1aSBvcGVyYXNpIFwoXG9wZXJhdG9ybmFtZXtDb25jYXR9XCkuDQoNClVudHVrIG1lbnllZGVyaGFuYWthbiBwZXJoaXR1bmdhbiBtYW51YWwsIG9wZXJhc2kgcGVuZ29sYWhhbiBmaXR1ciBwYWRhIHNldGlhcCBub2RlICpkZWNvZGVyKiBkaXJlcHJlc2VudGFzaWthbiBtZW5nZ3VuYWthbiBrb252b2x1c2kgXCgxXHRpbWVzMVwpIHRhbnBhIGJpYXMgeWFuZyBkaWlrdXRpIGZ1bmdzaSBha3RpdmFzaSBSZUxVLiBCb2JvdCBrb252b2x1c2kgeWFuZyBkaWd1bmFrYW4gbWVydXBha2FuIHBhcmFtZXRlciBpbHVzdHJhdGlmIGRhbiBidWthbiBib2JvdCBoYXNpbCBwZWxhdGloYW4gbW9kZWwuDQoNCiMjIyBhLiAqVXBzYW1wbGluZyogXChcbWF0aGJme1h9XnsyLDB9XCkgZGFuIE5vZGUgKkRlY29kZXIqIFwoXG1hdGhiZntYfV57MSwxfVwpDQoNCipGZWF0dXJlIG1hcCBlbmNvZGVyKiBrZWR1YSBcKFxtYXRoYmZ7WH1eezIsMH1cKSBiZXJ1a3VyYW4gXCgyXHRpbWVzMlwpIGRpcGVyYmVzYXIgbWVuamFkaSBcKDNcdGltZXMzXCkgbWVuZ2d1bmFrYW4gaW50ZXJwb2xhc2kgYmlsaW5lYXIuIFByb3NlcyBpbmkgYmVydHVqdWFuIHVudHVrIG1lbnllc3VhaWthbiB1a3VyYW4gc3Bhc2lhbCAqZmVhdHVyZSBtYXAqIHNlaGluZ2dhIGRhcGF0IGRpZ2FidW5na2FuIGRlbmdhbiBcKFxtYXRoYmZ7WH1eezEsMH1cKSBtZWxhbHVpICpuZXN0ZWQgc2tpcCBjb25uZWN0aW9uKi4NCg0KTWF0cmlrcyAqZmVhdHVyZSBtYXAqIG1hc3VrYW4gYWRhbGFoOg0KDQpcWw0KXG1hdGhiZntYfV57MiwwfQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQotMi4zMyAmIC0xLjc2XFwNCi0yLjE5ICYgLTEuOTENClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQotICoqUnVtdXMgaW50ZXJwb2xhc2kgYmlsaW5lYXI6KioNCg0KSW50ZXJwb2xhc2kgYmlsaW5lYXIgbWVuZW50dWthbiBuaWxhaSBrZWx1YXJhbiBiZXJkYXNhcmthbiBqYXJhayB0ZXJoYWRhcCBlbGVtZW4tZWxlbWVuIHBhZGEgKmZlYXR1cmUgbWFwKiBtYXN1a2FuLiBFbGVtZW4geWFuZyBsZWJpaCBkZWthdCBkZW5nYW4gcG9zaXNpIGtlbHVhcmFuIG1lbWlsaWtpIGJvYm90IGxlYmloIGJlc2FyLCBzZWRhbmdrYW4gZWxlbWVuIHlhbmcgYmVyamFyYWsgc2F0dSBzYXR1YW4gYXRhdSBsZWJpaCBwYWRhIHNhbGFoIHNhdHUgYXJhaCBtZW1pbGlraSBib2JvdCBub2wuDQoNClBhZGEgKmZlYXR1cmUgbWFwKiBzYXR1IGthbmFsLCBpbnRlcnBvbGFzaSBiaWxpbmVhciBkaW55YXRha2FuIHNlYmFnYWk6DQoNClxbDQpcbGVmdFsNClxvcGVyYXRvcm5hbWV7VXB9DQpcbGVmdCgNClxtYXRoYmZ7WH1eezIsMH0NClxyaWdodCkNClxyaWdodF1fe3IsY30NCj0NClxzdW1fe249MX1eezJ9DQpcc3VtX3ttPTF9XnsyfQ0KWF97bixtfV57MiwwfQ0KXG1heA0KXGxlZnQoDQowLA0KMS1cbGVmdHx4X2MtbVxyaWdodHwNClxyaWdodCkNClxtYXgNClxsZWZ0KA0KMCwNCjEtXGxlZnR8eV9yLW5ccmlnaHR8DQpccmlnaHQpLg0KXF0NCg0KUGFkYSBwZXJzYW1hYW4gdGVyc2VidXQsIFwoclwpIGRhbiBcKGNcKSBtZW55YXRha2FuIGluZGVrcyBiYXJpcyBkYW4ga29sb20gcGFkYSAqZmVhdHVyZSBtYXAqIGtlbHVhcmFuLCBzZWRhbmdrYW4gXChuXCkgZGFuIFwobVwpIG1lbnlhdGFrYW4gaW5kZWtzIGJhcmlzIGRhbiBrb2xvbSBwYWRhICpmZWF0dXJlIG1hcCogbWFzdWthbi4gS29vcmRpbmF0IFwoeF9jXCkgbWVudW5qdWtrYW4gcG9zaXNpIGhvcml6b250YWwgYXRhdSBhcmFoIGtvbG9tLCBzZWRhbmdrYW4gXCh5X3JcKSBtZW51bmp1a2thbiBwb3Npc2kgdmVydGlrYWwgYXRhdSBhcmFoIGJhcmlzLg0KDQpVbnR1ayBtZW1wZXJtdWRhaCBwZW5qYWJhcmFuLCBib2JvdCBpbnRlcnBvbGFzaSBwYWRhIHNldGlhcCBlbGVtZW4gbWFzdWthbiBkaW5vdGFzaWthbiBzZWJhZ2FpOg0KDQpcWw0Kd197bixtfV57KHIsYyl9DQo9DQpcbWF4DQpcbGVmdCgNCjAsDQoxLVxsZWZ0fHhfYy1tXHJpZ2h0fA0KXHJpZ2h0KQ0KXG1heA0KXGxlZnQoDQowLA0KMS1cbGVmdHx5X3ItblxyaWdodHwNClxyaWdodCkuDQpcXQ0KDQpEZW5nYW4gZGVtaWtpYW4sIHJ1bXVzIGludGVycG9sYXNpIGJpbGluZWFyIGRhcGF0IGRpdHVsaXNrYW4gc2ViYWdhaToNCg0KXFsNClxsZWZ0Ww0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MiwwfQ0KXHJpZ2h0KQ0KXHJpZ2h0XV97cixjfQ0KPQ0KXHN1bV97bj0xfV57Mn0NClxzdW1fe209MX1eezJ9DQp3X3tuLG19XnsocixjKX1YX3tuLG19XnsyLDB9Lg0KXF0NCg0KLSAqKlBlbmVudHVhbiBrb29yZGluYXQgaW50ZXJwb2xhc2k6KioNCg0KUGFkYSBpbHVzdHJhc2kgaW5pLCBrb29yZGluYXQgbWF0cmlrcyBtYXN1a2FuIG1lbmdndW5ha2FuIGluZGVrcyB5YW5nIGRpbXVsYWkgZGFyaSBcKDFcKS4gS2FyZW5hIHVrdXJhbiAqZmVhdHVyZSBtYXAqIG1hc3VrYW4gYWRhbGFoIFwoMlx0aW1lczJcKSBkYW4gdWt1cmFuIGtlbHVhcmFuIGFkYWxhaCBcKDNcdGltZXMzXCksIGtvb3JkaW5hdCBpbnRlcnBvbGFzaSBkaXRlbnR1a2FuIHNlYmFnYWk6DQoNClxbDQp4X2MNCj0NCjErKGMtMSlcZnJhY3syLTF9ezMtMX0NCj0NCjErXGZyYWN7Yy0xfXsyfSwNClxdDQoNClxbDQp5X3INCj0NCjErKHItMSlcZnJhY3syLTF9ezMtMX0NCj0NCjErXGZyYWN7ci0xfXsyfSwNClxdDQoNCmRlbmdhbiBcKHIsYz0xLDIsM1wpLg0KDQpBbmdrYSBcKDFcKSBtZW51bmp1a2thbiBrb29yZGluYXQgYXdhbCBrYXJlbmEgaW5kZWtzIG1hdHJpa3MgZGltdWxhaSBkYXJpIFwoMVwpLCBzZWRhbmdrYW4gcGVtYmFnaWFuIGRlbmdhbiBcKDJcKSBtZW51bmp1a2thbiBiYWh3YSBqYXJhayBhbnRhcmEgZHVhIGtvb3JkaW5hdCBtYXN1a2FuIGRpYmFnaSBtZW5qYWRpIGR1YSBpbnRlcnZhbCB5YW5nIHNhbWEgcGFuamFuZy4NCg0KTmlsYWkga29vcmRpbmF0IHlhbmcgZGlwZXJvbGVoIGFkYWxhaDoNCg0KfCBJbmRla3Mga2VsdWFyYW4gfCBOaWxhaSBrb29yZGluYXQgfA0KfDotLS06fDotLS06fA0KfCBcKDFcKSB8IFwoMVwpIHwNCnwgXCgyXCkgfCBcKDEuNVwpIHwNCnwgXCgzXCkgfCBcKDJcKSB8DQoNCkRlbmdhbiBkZW1pa2lhbiwga29vcmRpbmF0IGludGVycG9sYXNpIHBhZGEgbWF0cmlrcyBrZWx1YXJhbiBkYXBhdCBkaXR1bGlza2FuIHNlYmFnYWk6DQoNClxbDQpcYmVnaW57Ym1hdHJpeH0NCigxLDEpICYgKDEsMS41KSAmICgxLDIpXFwNCigxLjUsMSkgJiAoMS41LDEuNSkgJiAoMS41LDIpXFwNCigyLDEpICYgKDIsMS41KSAmICgyLDIpDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KU2V0aWFwIHBhc2FuZ2FuIGtvb3JkaW5hdCBkaXR1bGlza2FuIGRhbGFtIHVydXRhbiBcKCh5X3IseF9jKVwpLiBQYWRhIHBvc2lzaSBzdWR1dCwgbmlsYWkga2VsdWFyYW4gc2FtYSBkZW5nYW4gbmlsYWkgbWFzdWthbiBrYXJlbmEga29vcmRpbmF0bnlhIGJlcmltcGl0LiBTZW1lbnRhcmEgaXR1LCBwb3Npc2kgdGVuZ2FoIHNpc2kgZGlwZXJvbGVoIGRhcmkgZHVhIGVsZW1lbiBtYXN1a2FuLCBzZWRhbmdrYW4gcG9zaXNpIHRlbmdhaCBtYXRyaWtzIGRpcGVyb2xlaCBkYXJpIGVtcGF0IGVsZW1lbiBtYXN1a2FuLg0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuIGludGVycG9sYXNpIGJpbGluZWFyIHBhZGEgcG9zaXNpIFwoKDEsMilcKToqKg0KDQpQYWRhIHBvc2lzaSBcKCgxLDIpXCksIGtvb3JkaW5hdCBpbnRlcnBvbGFzaSBkaXBlcm9sZWggc2ViYWdhaSBiZXJpa3V0Og0KDQpcWw0KeV8xPTEsDQpccXF1YWQNCnhfMj0xLjUuDQpcXQ0KDQpQb3Npc2kgdGVyc2VidXQgYmVyYWRhIHRlcGF0IGRpIHRlbmdhaCBhbnRhcmEga29sb20gcGVydGFtYSBkYW4ga29sb20ga2VkdWEgcGFkYSBiYXJpcyBwZXJ0YW1hLiBCb2JvdCBpbnRlcnBvbGFzaSB1bnR1ayBlbGVtZW4gXChYX3sxLDF9XnsyLDB9XCkgZGloaXR1bmcgc2ViYWdhaToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0Kd197MSwxfV57KDEsMil9DQomPQ0KXG1heCgwLDEtfDEuNS0xfCkNClxtYXgoMCwxLXwxLTF8KVxcDQomPQ0KMC41XHRpbWVzMVxcDQomPQ0KMC41Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KU2VtZW50YXJhIGl0dSwgYm9ib3QgdW50dWsgZWxlbWVuIFwoWF97MSwyfV57MiwwfVwpIGFkYWxhaDoNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0Kd197MSwyfV57KDEsMil9DQomPQ0KXG1heCgwLDEtfDEuNS0yfCkNClxtYXgoMCwxLXwxLTF8KVxcDQomPQ0KMC41XHRpbWVzMVxcDQomPQ0KMC41Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KS2VkdWEgZWxlbWVuIHBhZGEgYmFyaXMga2VkdWEgbWVtaWxpa2kgYm9ib3Qgbm9sIGthcmVuYSBqYXJhayB2ZXJ0aWthbG55YSB0ZXJoYWRhcCBwb3Npc2kga2VsdWFyYW4gYWRhbGFoIHNhdHUgc2F0dWFuLiBEZW5nYW4gZGVtaWtpYW46DQoNClxbDQp3X3sxLDF9XnsoMSwyKX0NCj0NCndfezEsMn1eeygxLDIpfQ0KPQ0KMC41LA0KXHFxdWFkDQp3X3syLDF9XnsoMSwyKX0NCj0NCndfezIsMn1eeygxLDIpfQ0KPQ0KMC4NClxdDQoNCkRlbmdhbiBtZW1hc3Vra2FuIGJvYm90IHRlcnNlYnV0IGtlIGRhbGFtIHJ1bXVzIGludGVycG9sYXNpIGJpbGluZWFyLCBkaXBlcm9sZWg6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClxsZWZ0Ww0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MiwwfQ0KXHJpZ2h0KQ0KXHJpZ2h0XV97MSwyfQ0KJj0NCjAuNVhfezEsMX1eezIsMH0NCisNCjAuNVhfezEsMn1eezIsMH1cXA0KJj0NClxmcmFjew0KWF97MSwxfV57MiwwfQ0KKw0KWF97MSwyfV57MiwwfQ0KfXsyfVxcDQomPQ0KXGZyYWN7LTIuMzMtMS43Nn17Mn1cXA0KJj0NCi0yLjA0NVxcDQomXGFwcHJveA0KLTIuMDUuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuIGludGVycG9sYXNpIGJpbGluZWFyIHBhZGEgcG9zaXNpIHRlbmdhaCBcKCgyLDIpXCk6KioNCg0KUGFkYSBwb3Npc2kgXCgoMiwyKVwpLCBrb29yZGluYXQgaW50ZXJwb2xhc2kgZGlwZXJvbGVoIHNlYmFnYWkgYmVyaWt1dDoNCg0KXFsNCnlfMj0xLjUsDQpccXF1YWQNCnhfMj0xLjUuDQpcXQ0KDQpQb3Npc2kgdGVyc2VidXQgYmVyYWRhIHRlcGF0IGRpIHRlbmdhaCBlbXBhdCBlbGVtZW4gbWF0cmlrcyBtYXN1a2FuLiBCb2JvdCBpbnRlcnBvbGFzaSB1bnR1ayBlbGVtZW4gXChYX3sxLDF9XnsyLDB9XCkgZGloaXR1bmcgc2ViYWdhaToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0Kd197MSwxfV57KDIsMil9DQomPQ0KXG1heCgwLDEtfDEuNS0xfCkNClxtYXgoMCwxLXwxLjUtMXwpXFwNCiY9DQowLjVcdGltZXMwLjVcXA0KJj0NCjAuMjUuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpLYXJlbmEgcG9zaXNpIHRlbmdhaCBiZXJqYXJhayBzYW1hIGRhcmkga2VlbXBhdCBlbGVtZW4gbWFzdWthbiwgbWFrYToNCg0KXFsNCndfezEsMX1eeygyLDIpfQ0KPQ0Kd197MSwyfV57KDIsMil9DQo9DQp3X3syLDF9XnsoMiwyKX0NCj0NCndfezIsMn1eeygyLDIpfQ0KPQ0KMC4yNS4NClxdDQoNCkRlbmdhbiBkZW1pa2lhbiwgcnVtdXMgaW50ZXJwb2xhc2kgYmlsaW5lYXIgbWVuamFkaToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KXGxlZnRbDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsyLDB9DQpccmlnaHQpDQpccmlnaHRdX3syLDJ9DQomPQ0KMC4yNVhfezEsMX1eezIsMH0NCisNCjAuMjVYX3sxLDJ9XnsyLDB9XFwNCiZccXVhZCsNCjAuMjVYX3syLDF9XnsyLDB9DQorDQowLjI1WF97MiwyfV57MiwwfVxcDQomPQ0KXGZyYWN7DQpYX3sxLDF9XnsyLDB9DQorDQpYX3sxLDJ9XnsyLDB9DQorDQpYX3syLDF9XnsyLDB9DQorDQpYX3syLDJ9XnsyLDB9DQp9ezR9XFwNCiY9DQpcZnJhY3stMi4zMy0xLjc2LTIuMTktMS45MX17NH1cXA0KJj0NCi0yLjA0NzVcXA0KJlxhcHByb3gNCi0yLjA1Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KRGVuZ2FuIG1lbmVyYXBrYW4gaW50ZXJwb2xhc2kgYmlsaW5lYXIgcGFkYSBzZWx1cnVoIHBvc2lzaSBrZWx1YXJhbiwgZGlwZXJvbGVoICpmZWF0dXJlIG1hcCogaGFzaWwgKnVwc2FtcGxpbmcqIGJlcnVrdXJhbiBcKDNcdGltZXMzXCksIHlhaXR1Og0KDQpcWw0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MiwwfQ0KXHJpZ2h0KQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQotMi4zMyAmIC0yLjA1ICYgLTEuNzZcXA0KLTIuMjYgJiAtMi4wNSAmIC0xLjg0XFwNCi0yLjE5ICYgLTIuMDUgJiAtMS45MQ0KXGVuZHtibWF0cml4fS4NClxdDQoNCkhhc2lsIHRlcnNlYnV0IG1lbnVuanVra2FuIGJhaHdhIGludGVycG9sYXNpIGJpbGluZWFyIG1lbXBlcnRhaGFua2FuIG5pbGFpIHBhZGEgcG9zaXNpIHN1ZHV0IGRhbiBtZW5naGl0dW5nIG5pbGFpIHBhZGEgcG9zaXNpIGxhaW5ueWEgYmVyZGFzYXJrYW4gYm9ib3QgamFyYWsgdGVyaGFkYXAgZWxlbWVuIG1hc3VrYW4uIE5pbGFpIGhhc2lsIGludGVycG9sYXNpIGRpdGFtcGlsa2FuIGhpbmdnYSBkdWEgYW5na2EgZGVzaW1hbC4NCg0KLSAqKlJ1bXVzIG5vZGUgZGVjb2RlcjoqKg0KDQpTZXN1YWkgZGVuZ2FuIHBlcnNhbWFhbiBVTmV0KyssICpuZXN0ZWQgc2tpcCBjb25uZWN0aW9uKiBwYWRhIG5vZGUgKmRlY29kZXIqIHBlcnRhbWEgZGlydW11c2thbiBzZWJhZ2FpOg0KDQpcWw0KXG1hdGhiZntYfV57MSwxfQ0KPQ0KSF57KDEsMSl9DQpcbGVmdCgNClxvcGVyYXRvcm5hbWV7Q29uY2F0fQ0KXGxlZnRbDQpcbWF0aGJme1h9XnsxLDB9LA0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MiwwfQ0KXHJpZ2h0KQ0KXHJpZ2h0XQ0KXHJpZ2h0KS4NClxdDQoNClBhZGEgcGVyc2FtYWFuIHRlcnNlYnV0LCBcKEheeygxLDEpfVwpIG1lbnlhdGFrYW4gb3BlcmFzaSBwZW5nb2xhaGFuIGZpdHVyIHBhZGEgbm9kZSAqZGVjb2RlciogXChcbWF0aGJme1h9XnsxLDF9XCkuIERhbGFtIGlsdXN0cmFzaSBwZXJoaXR1bmdhbiBtYW51YWwgaW5pLCBvcGVyYXNpIHRlcnNlYnV0IGRpc2VkZXJoYW5ha2FuIG1lbmdndW5ha2FuIGtvbnZvbHVzaSBcKDFcdGltZXMxXCkgdGFucGEgYmlhcyB5YW5nIGRpaWt1dGkgZnVuZ3NpIGFrdGl2YXNpIFJlTFUuDQoNCkthcmVuYSBrZWR1YSAqZmVhdHVyZSBtYXAqIHlhbmcgZGlnYWJ1bmdrYW4gYmVydWt1cmFuIFwoM1x0aW1lczNcKSBkYW4gbWFzaW5nLW1hc2luZyBkaXJlcHJlc2VudGFzaWthbiBvbGVoIHNhdHUga2FuYWwsIGhhc2lsICpDb25jYXQqIG1lbWlsaWtpIGR1YSBrYW5hbC4gU2F0dSBmaWx0ZXIga29udm9sdXNpIFwoMVx0aW1lczFcKSBkaWd1bmFrYW4gdW50dWsgbWVuZ2dhYnVuZ2thbiBrZWR1YSBrYW5hbCB0ZXJzZWJ1dCBtZW5qYWRpIHNhdHUga2FuYWwga2VsdWFyYW4uDQoNClBhZGEgaWx1c3RyYXNpIGluaSwgYm9ib3Qga2VybmVsIGRpdGVudHVrYW4gc2ViYWdhaToNCg0KXFsNCldfe1xtYXRocm17ZGVjfSwxfV57KDEsMSl9PVsxLjAwXSwNClxxcXVhZA0KV197XG1hdGhybXtkZWN9LDJ9XnsoMSwxKX09WzAuMjBdLg0KXF0NCg0KQm9ib3QgcGVydGFtYSBkaXRlcmFwa2FuIHBhZGEgXChcbWF0aGJme1h9XnsxLDB9XCksIHNlZGFuZ2thbiBib2JvdCBrZWR1YSBkaXRlcmFwa2FuIHBhZGEgXChcb3BlcmF0b3JuYW1le1VwfShcbWF0aGJme1h9XnsyLDB9KVwpLg0KDQpEZW5nYW4gZGVtaWtpYW4sIHVudHVrIHNldGlhcCBwb3Npc2kgc3Bhc2lhbCBcKChyLGMpXCksIGtlbHVhcmFuIG5vZGUgKmRlY29kZXIqIGRpaGl0dW5nIHNlYmFnYWk6DQoNClxbDQpYX3tyLGN9XnsxLDF9DQo9DQpcb3BlcmF0b3JuYW1le1JlTFV9DQpcbGVmdCgNCldfe1xtYXRocm17ZGVjfSwxfV57KDEsMSl9WF97cixjfV57MSwwfQ0KKw0KV197XG1hdGhybXtkZWN9LDJ9XnsoMSwxKX0NClxsZWZ0Ww0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MiwwfQ0KXHJpZ2h0KQ0KXHJpZ2h0XV97cixjfQ0KXHJpZ2h0KS4NClxdDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gbm9kZSBkZWNvZGVyIHBhZGEgcG9zaXNpIFwoKDEsMilcKToqKg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpYX3sxLDJ9XnsxLDF9DQomPQ0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQpXX3tcbWF0aHJte2RlY30sMX1eeygxLDEpfVhfezEsMn1eezEsMH0NCisNCldfe1xtYXRocm17ZGVjfSwyfV57KDEsMSl9DQpcbGVmdFsNClxvcGVyYXRvcm5hbWV7VXB9DQpcbGVmdCgNClxtYXRoYmZ7WH1eezIsMH0NClxyaWdodCkNClxyaWdodF1fezEsMn0NClxyaWdodClcXA0KJj0NClxvcGVyYXRvcm5hbWV7UmVMVX0NClxsZWZ0KA0KMS4wMCgxLjU1KQ0KKw0KMC4yMCgtMi4wNSkNClxyaWdodClcXA0KJj0NClxvcGVyYXRvcm5hbWV7UmVMVX0oMS4xNClcXA0KJj0NCjEuMTQuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gbWVuZXJhcGthbiBvcGVyYXNpIHlhbmcgc2FtYSBwYWRhIHNlbHVydWggcG9zaXNpIHNwYXNpYWwsIGRpcGVyb2xlaCAqZmVhdHVyZSBtYXAqIG5vZGUgKmRlY29kZXIqIHBlcnRhbWEgc2ViYWdhaSBiZXJpa3V0Og0KDQpcWw0KXG1hdGhiZntYfV57MSwxfQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjAwICYgMS4xNCAmIDAuMDBcXA0KMC4wMCAmIDEuNTEgJiAwLjAwXFwNCjAuMDAgJiAwLjE3ICYgMC4wMA0KXGVuZHtibWF0cml4fS4NClxdDQoNCkhhc2lsIHRlcnNlYnV0IG1lbnVuanVra2FuIGJhaHdhICpmZWF0dXJlIG1hcCogaGFzaWwgKnVwc2FtcGxpbmcqIGRpZ2FidW5na2FuIGRlbmdhbiAqZmVhdHVyZSBtYXAqIGRhcmkgamFsdXIgKmVuY29kZXIqIG1lbGFsdWkgKm5lc3RlZCBza2lwIGNvbm5lY3Rpb24qLiBQYWRhIGlsdXN0cmFzaSBpbmksIHBlbmdnYWJ1bmdhbiBkaWxha3VrYW4gbWVuZ2d1bmFrYW4gKkNvbmNhdCosIGtvbnZvbHVzaSBcKDFcdGltZXMxXCksIGRhbiBmdW5nc2kgYWt0aXZhc2kgUmVMVS4gKkZlYXR1cmUgbWFwKiBcKFxtYXRoYmZ7WH1eezEsMX1cKSBzZWxhbmp1dG55YSBkaWd1bmFrYW4gcGFkYSBwZW1iZW50dWthbiBub2RlICpkZWNvZGVyKiBiZXJpa3V0bnlhLg0KDQoNCiMjIyBiLiAqVXBzYW1wbGluZyogXChcbWF0aGJme1h9XnsxLDB9XCkgZGFuICpOZXN0ZWQgU2tpcCogUGVydGFtYSBcKFxtYXRoYmZ7WH1eezAsMX1cKQ0KDQoqRmVhdHVyZSBtYXAgZW5jb2RlciogcGVydGFtYSBcKFxtYXRoYmZ7WH1eezEsMH1cKSBiZXJ1a3VyYW4gXCgzXHRpbWVzM1wpIGRpcGVyYmVzYXIgbWVuamFkaSBcKDVcdGltZXM1XCkgbWVuZ2d1bmFrYW4gaW50ZXJwb2xhc2kgYmlsaW5lYXIuIFByb3NlcyBpbmkgYmVydHVqdWFuIHVudHVrIG1lbnllc3VhaWthbiB1a3VyYW4gc3Bhc2lhbCAqZmVhdHVyZSBtYXAqIHNlaGluZ2dhIGRhcGF0IGRpZ2FidW5na2FuIGRlbmdhbiBcKFxtYXRoYmZ7WH1eezAsMH1cKSBtZWxhbHVpICpuZXN0ZWQgc2tpcCBjb25uZWN0aW9uKi4NCg0KTWF0cmlrcyAqZmVhdHVyZSBtYXAqIG1hc3VrYW4gYWRhbGFoOg0KDQpcWw0KXG1hdGhiZntYfV57MSwwfQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQotMi4zMyAmIDEuNTUgJiAtMS43NlxcDQotMi4zMyAmIDEuOTIgJiAtMS42MlxcDQotMi4xOSAmIDAuNTggJiAtMS45MQ0KXGVuZHtibWF0cml4fS4NClxdDQoNCi0gKipSdW11cyBpbnRlcnBvbGFzaSBiaWxpbmVhcjoqKg0KDQpJbnRlcnBvbGFzaSBiaWxpbmVhciBkaWxha3VrYW4gbWVuZ2d1bmFrYW4gcHJpbnNpcCB5YW5nIHNhbWEgc2VwZXJ0aSBwYWRhIHN1YmJhZ2lhbiBzZWJlbHVtbnlhLiBOaWxhaSBrZWx1YXJhbiBkaWhpdHVuZyBiZXJkYXNhcmthbiBqYXJhayB0ZXJoYWRhcCBlbGVtZW4tZWxlbWVuIHBhZGEgKmZlYXR1cmUgbWFwKiBtYXN1a2FuLg0KDQpQYWRhICpmZWF0dXJlIG1hcCogc2F0dSBrYW5hbCwgcnVtdXMgaW50ZXJwb2xhc2kgYmlsaW5lYXIgZGlueWF0YWthbiBzZWJhZ2FpOg0KDQpcWw0KXGxlZnRbDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsxLDB9DQpccmlnaHQpDQpccmlnaHRdX3tyLGN9DQo9DQpcc3VtX3tuPTF9XnszfQ0KXHN1bV97bT0xfV57M30NClhfe24sbX1eezEsMH0NClxtYXgNClxsZWZ0KA0KMCwNCjEtXGxlZnR8eF9jLW1ccmlnaHR8DQpccmlnaHQpDQpcbWF4DQpcbGVmdCgNCjAsDQoxLVxsZWZ0fHlfci1uXHJpZ2h0fA0KXHJpZ2h0KS4NClxdDQoNClBhZGEgcGVyc2FtYWFuIHRlcnNlYnV0LCBcKHJcKSBkYW4gXChjXCkgbWVueWF0YWthbiBpbmRla3MgYmFyaXMgZGFuIGtvbG9tIHBhZGEgKmZlYXR1cmUgbWFwKiBrZWx1YXJhbiwgc2VkYW5na2FuIFwoblwpIGRhbiBcKG1cKSBtZW55YXRha2FuIGluZGVrcyBiYXJpcyBkYW4ga29sb20gcGFkYSAqZmVhdHVyZSBtYXAqIG1hc3VrYW4uIEtvb3JkaW5hdCBcKHhfY1wpIG1lbnVuanVra2FuIHBvc2lzaSBob3Jpem9udGFsIGF0YXUgYXJhaCBrb2xvbSwgc2VkYW5na2FuIFwoeV9yXCkgbWVudW5qdWtrYW4gcG9zaXNpIHZlcnRpa2FsIGF0YXUgYXJhaCBiYXJpcy4NCg0KQm9ib3QgaW50ZXJwb2xhc2kgcGFkYSBzZXRpYXAgZWxlbWVuIG1hc3VrYW4gZGlueWF0YWthbiBzZWJhZ2FpOg0KDQpcWw0Kd197bixtfV57KHIsYyl9DQo9DQpcbWF4DQpcbGVmdCgNCjAsDQoxLVxsZWZ0fHhfYy1tXHJpZ2h0fA0KXHJpZ2h0KQ0KXG1heA0KXGxlZnQoDQowLA0KMS1cbGVmdHx5X3ItblxyaWdodHwNClxyaWdodCkuDQpcXQ0KDQpEZW5nYW4gZGVtaWtpYW4sIHJ1bXVzIGludGVycG9sYXNpIGJpbGluZWFyIGRhcGF0IGRpdHVsaXNrYW4gc2ViYWdhaToNCg0KXFsNClxsZWZ0Ww0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MSwwfQ0KXHJpZ2h0KQ0KXHJpZ2h0XV97cixjfQ0KPQ0KXHN1bV97bj0xfV57M30NClxzdW1fe209MX1eezN9DQp3X3tuLG19XnsocixjKX1YX3tuLG19XnsxLDB9Lg0KXF0NCg0KLSAqKlBlbmVudHVhbiBrb29yZGluYXQgaW50ZXJwb2xhc2k6KioNCg0KUGFkYSBpbHVzdHJhc2kgaW5pLCBrb29yZGluYXQgbWF0cmlrcyBtZW5nZ3VuYWthbiBpbmRla3MgeWFuZyBkaW11bGFpIGRhcmkgXCgxXCkuIEthcmVuYSB1a3VyYW4gKmZlYXR1cmUgbWFwKiBtYXN1a2FuIGFkYWxhaCBcKDNcdGltZXMzXCkgZGFuIHVrdXJhbiBrZWx1YXJhbiBhZGFsYWggXCg1XHRpbWVzNVwpLCBrb29yZGluYXQgaW50ZXJwb2xhc2kgZGl0ZW50dWthbiBzZWJhZ2FpOg0KDQpcWw0KeF9jDQo9DQoxKyhjLTEpXGZyYWN7My0xfXs1LTF9DQo9DQoxK1xmcmFje2MtMX17Mn0sDQpcXQ0KDQpcWw0KeV9yDQo9DQoxKyhyLTEpXGZyYWN7My0xfXs1LTF9DQo9DQoxK1xmcmFje3ItMX17Mn0sDQpcXQ0KDQpkZW5nYW4gXChyLGM9MSwyLDMsNCw1XCkuDQoNCkFuZ2thIFwoMVwpIG1lbnVuanVra2FuIGtvb3JkaW5hdCBhd2FsIG1hdHJpa3MgbWFzdWthbiwgc2VkYW5na2FuIHBlbWJhZ2lhbiBkZW5nYW4gXCgyXCkgbWVudW5qdWtrYW4gYmFod2Egc2V0aWFwIGludGVydmFsIGFudGFyYSBkdWEga29vcmRpbmF0IG1hc3VrYW4gZGliYWdpIG1lbmphZGkgZHVhIGJhZ2lhbiB5YW5nIHNhbWEgcGFuamFuZy4NCg0KTmlsYWkga29vcmRpbmF0IHlhbmcgZGlwZXJvbGVoIGFkYWxhaDoNCg0KfCBJbmRla3Mga2VsdWFyYW4gfCBOaWxhaSBrb29yZGluYXQgfA0KfDotLS06fDotLS06fA0KfCBcKDFcKSB8IFwoMVwpIHwNCnwgXCgyXCkgfCBcKDEuNVwpIHwNCnwgXCgzXCkgfCBcKDJcKSB8DQp8IFwoNFwpIHwgXCgyLjVcKSB8DQp8IFwoNVwpIHwgXCgzXCkgfA0KDQpEZW5nYW4gZGVtaWtpYW4sIG5pbGFpIHBhZGEgcG9zaXNpIGtlbHVhcmFuIHlhbmcgYmVyaW1waXQgZGVuZ2FuIGtvb3JkaW5hdCBtYXN1a2FuIGRpcGVydGFoYW5rYW4sIHNlZGFuZ2thbiBuaWxhaSBwYWRhIHBvc2lzaSBsYWlubnlhIGRpaGl0dW5nIGJlcmRhc2Fya2FuIGJvYm90IGphcmFrIHRlcmhhZGFwIGVsZW1lbi1lbGVtZW4gbWFzdWthbiBkaSBzZWtpdGFybnlhLg0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuIGludGVycG9sYXNpIGJpbGluZWFyIHBhZGEgcG9zaXNpIFwoKDEsMilcKToqKg0KDQpQYWRhIHBvc2lzaSBcKCgxLDIpXCksIGtvb3JkaW5hdCBpbnRlcnBvbGFzaSBkaXBlcm9sZWggc2ViYWdhaSBiZXJpa3V0Og0KDQpcWw0KeV8xPTEsDQpccXF1YWQNCnhfMj0xLjUuDQpcXQ0KDQpQb3Npc2kgdGVyc2VidXQgYmVyYWRhIHRlcGF0IGRpIHRlbmdhaCBhbnRhcmEga29sb20gcGVydGFtYSBkYW4ga29sb20ga2VkdWEgcGFkYSBiYXJpcyBwZXJ0YW1hLiBCb2JvdCBpbnRlcnBvbGFzaSB1bnR1ayBlbGVtZW4gXChYX3sxLDF9XnsxLDB9XCkgZGloaXR1bmcgc2ViYWdhaToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0Kd197MSwxfV57KDEsMil9DQomPQ0KXG1heCgwLDEtfDEuNS0xfCkNClxtYXgoMCwxLXwxLTF8KVxcDQomPQ0KMC41XHRpbWVzMVxcDQomPQ0KMC41Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KU2VtZW50YXJhIGl0dSwgYm9ib3QgdW50dWsgZWxlbWVuIFwoWF97MSwyfV57MSwwfVwpIGFkYWxhaDoNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0Kd197MSwyfV57KDEsMil9DQomPQ0KXG1heCgwLDEtfDEuNS0yfCkNClxtYXgoMCwxLXwxLTF8KVxcDQomPQ0KMC41XHRpbWVzMVxcDQomPQ0KMC41Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KRWxlbWVuIGxhaW5ueWEgbWVtaWxpa2kgYm9ib3Qgbm9sIGthcmVuYSBiZXJhZGEgZGkgbHVhciBqYXJhayBpbnRlcnBvbGFzaSBwYWRhIHBvc2lzaSB0ZXJzZWJ1dC4gRGVuZ2FuIGRlbWlraWFuOg0KDQpcWw0Kd197MSwxfV57KDEsMil9DQo9DQp3X3sxLDJ9XnsoMSwyKX0NCj0NCjAuNS4NClxdDQoNCkRlbmdhbiBtZW1hc3Vra2FuIGJvYm90IHRlcnNlYnV0IGtlIGRhbGFtIHJ1bXVzIGludGVycG9sYXNpIGJpbGluZWFyLCBkaXBlcm9sZWg6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClxsZWZ0Ww0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MSwwfQ0KXHJpZ2h0KQ0KXHJpZ2h0XV97MSwyfQ0KJj0NCjAuNVhfezEsMX1eezEsMH0NCisNCjAuNVhfezEsMn1eezEsMH1cXA0KJj0NClxmcmFjew0KWF97MSwxfV57MSwwfQ0KKw0KWF97MSwyfV57MSwwfQ0KfXsyfVxcDQomPQ0KXGZyYWN7LTIuMzMrMS41NX17Mn1cXA0KJj0NCi0wLjM5Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiBpbnRlcnBvbGFzaSBiaWxpbmVhciBwYWRhIHBvc2lzaSBcKCgyLDIpXCk6KioNCg0KUGFkYSBwb3Npc2kgXCgoMiwyKVwpLCBrb29yZGluYXQgaW50ZXJwb2xhc2kgZGlwZXJvbGVoIHNlYmFnYWkgYmVyaWt1dDoNCg0KXFsNCnlfMj0xLjUsDQpccXF1YWQNCnhfMj0xLjUuDQpcXQ0KDQpQb3Npc2kgdGVyc2VidXQgYmVyYWRhIHRlcGF0IGRpIHRlbmdhaCBlbXBhdCBlbGVtZW4gbWFzdWthbiwgeWFpdHUgXChYX3sxLDF9XnsxLDB9XCksIFwoWF97MSwyfV57MSwwfVwpLCBcKFhfezIsMX1eezEsMH1cKSwgZGFuIFwoWF97MiwyfV57MSwwfVwpLg0KDQpCb2JvdCBpbnRlcnBvbGFzaSB1bnR1ayBlbGVtZW4gXChYX3sxLDF9XnsxLDB9XCkgZGloaXR1bmcgc2ViYWdhaToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0Kd197MSwxfV57KDIsMil9DQomPQ0KXG1heCgwLDEtfDEuNS0xfCkNClxtYXgoMCwxLXwxLjUtMXwpXFwNCiY9DQowLjVcdGltZXMwLjVcXA0KJj0NCjAuMjUuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpLYXJlbmEgcG9zaXNpIHRlcnNlYnV0IGJlcmphcmFrIHNhbWEgZGFyaSBrZWVtcGF0IGVsZW1lbiBtYXN1a2FuLCBtYWthOg0KDQpcWw0Kd197MSwxfV57KDIsMil9DQo9DQp3X3sxLDJ9XnsoMiwyKX0NCj0NCndfezIsMX1eeygyLDIpfQ0KPQ0Kd197MiwyfV57KDIsMil9DQo9DQowLjI1Lg0KXF0NCg0KRGVuZ2FuIGRlbWlraWFuLCBydW11cyBpbnRlcnBvbGFzaSBiaWxpbmVhciBtZW5qYWRpOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcbGVmdFsNClxvcGVyYXRvcm5hbWV7VXB9DQpcbGVmdCgNClxtYXRoYmZ7WH1eezEsMH0NClxyaWdodCkNClxyaWdodF1fezIsMn0NCiY9DQowLjI1WF97MSwxfV57MSwwfQ0KKw0KMC4yNVhfezEsMn1eezEsMH1cXA0KJlxxdWFkKw0KMC4yNVhfezIsMX1eezEsMH0NCisNCjAuMjVYX3syLDJ9XnsxLDB9XFwNCiY9DQpcZnJhY3sNClhfezEsMX1eezEsMH0NCisNClhfezEsMn1eezEsMH0NCisNClhfezIsMX1eezEsMH0NCisNClhfezIsMn1eezEsMH0NCn17NH1cXA0KJj0NClxmcmFjey0yLjMzKzEuNTUtMi4zMysxLjkyfXs0fVxcDQomPQ0KLTAuMjk3NVxcDQomXGFwcHJveC0wLjMwLg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KRGVuZ2FuIG1lbmVyYXBrYW4gaW50ZXJwb2xhc2kgYmlsaW5lYXIgcGFkYSBzZWx1cnVoIHBvc2lzaSBrZWx1YXJhbiwgZGlwZXJvbGVoICpmZWF0dXJlIG1hcCogaGFzaWwgKnVwc2FtcGxpbmcqIGJlcnVrdXJhbiBcKDVcdGltZXM1XCksIHlhaXR1Og0KDQpcWw0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MSwwfQ0KXHJpZ2h0KQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQotMi4zMyAmIC0wLjM5ICYgMS41NSAmIC0wLjExICYgLTEuNzZcXA0KLTIuMzMgJiAtMC4zMCAmIDEuNzMgJiAwLjAyICYgLTEuNjlcXA0KLTIuMzMgJiAtMC4yMSAmIDEuOTIgJiAwLjE1ICYgLTEuNjJcXA0KLTIuMjYgJiAtMC41MSAmIDEuMjUgJiAtMC4yNiAmIC0xLjc3XFwNCi0yLjE5ICYgLTAuODEgJiAwLjU4ICYgLTAuNjcgJiAtMS45MQ0KXGVuZHtibWF0cml4fS4NClxdDQoNCkhhc2lsIHRlcnNlYnV0IG1lbnVuanVra2FuIGJhaHdhIGludGVycG9sYXNpIGJpbGluZWFyIG1lbXBlcmJlc2FyIHVrdXJhbiBzcGFzaWFsICpmZWF0dXJlIG1hcCogZGFyaSBcKDNcdGltZXMzXCkgbWVuamFkaSBcKDVcdGltZXM1XCkuIE5pbGFpIHBhZGEgcG9zaXNpIHlhbmcgYmVyaW1waXQgZGVuZ2FuIGtvb3JkaW5hdCBtYXN1a2FuIGRpcGVydGFoYW5rYW4sIHNlZGFuZ2thbiBuaWxhaSBwYWRhIHBvc2lzaSBsYWlubnlhIGRpaGl0dW5nIG1lbmdndW5ha2FuIGJvYm90IGludGVycG9sYXNpIGJlcmRhc2Fya2FuIGphcmFrIHRlcmhhZGFwIGVsZW1lbiBtYXN1a2FuLg0KDQotICoqUnVtdXMgbm9kZSBkZWNvZGVyOioqDQoNClNlc3VhaSBkZW5nYW4gcGVyc2FtYWFuIFVOZXQrKywgKm5lc3RlZCBza2lwIGNvbm5lY3Rpb24qIHBlcnRhbWEgcGFkYSBub2RlICpkZWNvZGVyKiBkaXJ1bXVza2FuIHNlYmFnYWk6DQoNClxbDQpcbWF0aGJme1h9XnswLDF9DQo9DQpIXnsoMCwxKX0NClxsZWZ0KA0KXG9wZXJhdG9ybmFtZXtDb25jYXR9DQpcbGVmdFsNClxtYXRoYmZ7WH1eezAsMH0sDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsxLDB9DQpccmlnaHQpDQpccmlnaHRdDQpccmlnaHQpLg0KXF0NCg0KUGFkYSBwZXJzYW1hYW4gdGVyc2VidXQsIFwoSF57KDAsMSl9XCkgbWVueWF0YWthbiBvcGVyYXNpIHBlbmdvbGFoYW4gZml0dXIgcGFkYSBub2RlICpkZWNvZGVyKiBcKFxtYXRoYmZ7WH1eezAsMX1cKS4gRGFsYW0gaWx1c3RyYXNpIHBlcmhpdHVuZ2FuIG1hbnVhbCBpbmksIG9wZXJhc2kgdGVyc2VidXQgZGlzZWRlcmhhbmFrYW4gbWVuZ2d1bmFrYW4ga29udm9sdXNpIFwoMVx0aW1lczFcKSB0YW5wYSBiaWFzIHlhbmcgZGlpa3V0aSBmdW5nc2kgYWt0aXZhc2kgUmVMVS4NCg0KS2FyZW5hIGtlZHVhICpmZWF0dXJlIG1hcCogeWFuZyBkaWdhYnVuZ2thbiBiZXJ1a3VyYW4gXCg1XHRpbWVzNVwpIGRhbiBtYXNpbmctbWFzaW5nIGRpcmVwcmVzZW50YXNpa2FuIG9sZWggc2F0dSBrYW5hbCwgaGFzaWwgKkNvbmNhdCogbWVtaWxpa2kgZHVhIGthbmFsLiBTYXR1IGZpbHRlciBrb252b2x1c2kgXCgxXHRpbWVzMVwpIGRpZ3VuYWthbiB1bnR1ayBtZW5nZ2FidW5na2FuIGtlZHVhIGthbmFsIHRlcnNlYnV0IG1lbmphZGkgc2F0dSBrYW5hbCBrZWx1YXJhbi4NCg0KUGFkYSBpbHVzdHJhc2kgaW5pLCBib2JvdCBrZXJuZWwgZGl0ZW50dWthbiBzZWJhZ2FpOg0KDQpcWw0KV197XG1hdGhybXtkZWN9LDF9XnsoMCwxKX09WzEuMDBdLA0KXHFxdWFkDQpXX3tcbWF0aHJte2RlY30sMn1eeygwLDEpfT1bMS4wMF0uDQpcXQ0KDQpCb2JvdCBwZXJ0YW1hIGRpdGVyYXBrYW4gcGFkYSBcKFxtYXRoYmZ7WH1eezAsMH1cKSwgc2VkYW5na2FuIGJvYm90IGtlZHVhIGRpdGVyYXBrYW4gcGFkYSBcKFxvcGVyYXRvcm5hbWV7VXB9KFxtYXRoYmZ7WH1eezEsMH0pXCkuDQoNCkRlbmdhbiBkZW1pa2lhbiwgdW50dWsgc2V0aWFwIHBvc2lzaSBzcGFzaWFsIFwoKHIsYylcKSwga2VsdWFyYW4gbm9kZSAqZGVjb2RlciogZGloaXR1bmcgc2ViYWdhaToNCg0KXFsNClhfe3IsY31eezAsMX0NCj0NClxvcGVyYXRvcm5hbWV7UmVMVX0NClxsZWZ0KA0KV197XG1hdGhybXtkZWN9LDF9XnsoMCwxKX1YX3tyLGN9XnswLDB9DQorDQpXX3tcbWF0aHJte2RlY30sMn1eeygwLDEpfQ0KXGxlZnRbDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsxLDB9DQpccmlnaHQpDQpccmlnaHRdX3tyLGN9DQpccmlnaHQpLg0KXF0NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiBub2RlIGRlY29kZXIgcGFkYSBwb3Npc2kgXCgoMiwyKVwpOioqDQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClhfezIsMn1eezAsMX0NCiY9DQpcb3BlcmF0b3JuYW1le1JlTFV9DQpcbGVmdCgNCldfe1xtYXRocm17ZGVjfSwxfV57KDAsMSl9WF97MiwyfV57MCwwfQ0KKw0KV197XG1hdGhybXtkZWN9LDJ9XnsoMCwxKX0NClxsZWZ0Ww0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MSwwfQ0KXHJpZ2h0KQ0KXHJpZ2h0XV97MiwyfQ0KXHJpZ2h0KVxcDQomPQ0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQoxLjAwKC0yLjMzKQ0KKw0KMS4wMCgtMC4zMCkNClxyaWdodClcXA0KJj0NClxvcGVyYXRvcm5hbWV7UmVMVX0oLTIuNjMpXFwNCiY9DQowLjAwLg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiBub2RlIGRlY29kZXIgcGFkYSBwb3Npc2kgXCgoMiwzKVwpOioqDQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClhfezIsM31eezAsMX0NCiY9DQpcb3BlcmF0b3JuYW1le1JlTFV9DQpcbGVmdCgNCldfe1xtYXRocm17ZGVjfSwxfV57KDAsMSl9WF97MiwzfV57MCwwfQ0KKw0KV197XG1hdGhybXtkZWN9LDJ9XnsoMCwxKX0NClxsZWZ0Ww0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MSwwfQ0KXHJpZ2h0KQ0KXHJpZ2h0XV97MiwzfQ0KXHJpZ2h0KVxcDQomPQ0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQoxLjAwKDEuOTEpDQorDQoxLjAwKDEuNzMpDQpccmlnaHQpXFwNCiY9DQpcb3BlcmF0b3JuYW1le1JlTFV9KDMuNjQpXFwNCiY9DQozLjY0Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KRGVuZ2FuIG1lbmVyYXBrYW4gb3BlcmFzaSB5YW5nIHNhbWEgcGFkYSBzZWx1cnVoIHBvc2lzaSBzcGFzaWFsLCBkaXBlcm9sZWggKmZlYXR1cmUgbWFwKiBub2RlICpkZWNvZGVyKiBzZWJhZ2FpIGJlcmlrdXQ6DQoNClxbDQpcbWF0aGJme1h9XnswLDF9DQo9DQpcYmVnaW57Ym1hdHJpeH0NCjAuMDAgJiAwLjAwICYgMy4wOSAmIDAuODAgJiAwLjAwXFwNCjAuMDAgJiAwLjAwICYgMy42NCAmIDEuMjYgJiAwLjAwXFwNCjAuMDAgJiAwLjAwICYgMy44MyAmIDEuMzkgJiAwLjAwXFwNCjAuMDAgJiAwLjAwICYgMi43OCAmIDAuNjIgJiAwLjAwXFwNCjAuMDAgJiAwLjAwICYgMS4xNiAmIDAuMDAgJiAwLjAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KSGFzaWwgdGVyc2VidXQgbWVudW5qdWtrYW4gYmFod2Egbm9kZSBcKFxtYXRoYmZ7WH1eezAsMX1cKSBtZW5nZ2FidW5na2FuIGluZm9ybWFzaSBkYXJpICpmZWF0dXJlIG1hcCBlbmNvZGVyKiBcKFxtYXRoYmZ7WH1eezAsMH1cKSBkYW4gaGFzaWwgKnVwc2FtcGxpbmcqIFwoXG1hdGhiZntYfV57MSwwfVwpIG1lbGFsdWkgKm5lc3RlZCBza2lwIGNvbm5lY3Rpb24qLiBQYWRhIGlsdXN0cmFzaSBpbmksIHBlbmdnYWJ1bmdhbiBkaWxha3VrYW4gbWVuZ2d1bmFrYW4gKkNvbmNhdCosIGtvbnZvbHVzaSBcKDFcdGltZXMxXCksIGRhbiBmdW5nc2kgYWt0aXZhc2kgUmVMVS4gKkZlYXR1cmUgbWFwKiBcKFxtYXRoYmZ7WH1eezAsMX1cKSBzZWxhbmp1dG55YSBkaWd1bmFrYW4gcGFkYSBwZW1iZW50dWthbiBub2RlICpkZWNvZGVyKiBiZXJpa3V0bnlhLg0KDQoNCg0KIyMjIGMuICpVcHNhbXBsaW5nKiBcKFxtYXRoYmZ7WH1eezEsMX1cKSBkYW4gKk5lc3RlZCBTa2lwKiBLZWR1YSBcKFxtYXRoYmZ7WH1eezAsMn1cKQ0KDQpOb2RlICpkZWNvZGVyKiBcKFxtYXRoYmZ7WH1eezEsMX1cKSBiZXJ1a3VyYW4gXCgzXHRpbWVzM1wpIGRpcGVyYmVzYXIgbWVuamFkaSBcKDVcdGltZXM1XCkgbWVuZ2d1bmFrYW4gaW50ZXJwb2xhc2kgYmlsaW5lYXIuIFByb3NlcyBpbmkgYmVydHVqdWFuIHVudHVrIG1lbnllc3VhaWthbiB1a3VyYW4gc3Bhc2lhbCAqZmVhdHVyZSBtYXAqIHNlaGluZ2dhIGRhcGF0IGRpZ2FidW5na2FuIGRlbmdhbiBcKFxtYXRoYmZ7WH1eezAsMH1cKSBkYW4gXChcbWF0aGJme1h9XnswLDF9XCkgbWVsYWx1aSAqbmVzdGVkIHNraXAgY29ubmVjdGlvbiouDQoNCk1hdHJpa3MgKmZlYXR1cmUgbWFwKiBtYXN1a2FuIGFkYWxhaDoNCg0KXFsNClxtYXRoYmZ7WH1eezEsMX0NCj0NClxiZWdpbntibWF0cml4fQ0KMC4wMCAmIDEuMTQgJiAwLjAwXFwNCjAuMDAgJiAxLjUxICYgMC4wMFxcDQowLjAwICYgMC4xNyAmIDAuMDANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQotICoqUnVtdXMgaW50ZXJwb2xhc2kgYmlsaW5lYXI6KioNCg0KSW50ZXJwb2xhc2kgYmlsaW5lYXIgZGlsYWt1a2FuIGRlbmdhbiBtZW5lbnR1a2FuIG5pbGFpIGtlbHVhcmFuIGJlcmRhc2Fya2FuIGphcmFrIHRlcmhhZGFwIGVsZW1lbi1lbGVtZW4gcGFkYSAqZmVhdHVyZSBtYXAqIG1hc3VrYW4uDQoNClBhZGEgKmZlYXR1cmUgbWFwKiBzYXR1IGthbmFsLCBydW11cyBpbnRlcnBvbGFzaSBiaWxpbmVhciBkaW55YXRha2FuIHNlYmFnYWk6DQoNClxbDQpcbGVmdFsNClxvcGVyYXRvcm5hbWV7VXB9DQpcbGVmdCgNClxtYXRoYmZ7WH1eezEsMX0NClxyaWdodCkNClxyaWdodF1fe3IsY30NCj0NClxzdW1fe249MX1eezN9DQpcc3VtX3ttPTF9XnszfQ0KWF97bixtfV57MSwxfQ0KXG1heA0KXGxlZnQoDQowLA0KMS1cbGVmdHx4X2MtbVxyaWdodHwNClxyaWdodCkNClxtYXgNClxsZWZ0KA0KMCwNCjEtXGxlZnR8eV9yLW5ccmlnaHR8DQpccmlnaHQpLg0KXF0NCg0KUGFkYSBwZXJzYW1hYW4gdGVyc2VidXQsIFwoclwpIGRhbiBcKGNcKSBtZW55YXRha2FuIGluZGVrcyBiYXJpcyBkYW4ga29sb20gcGFkYSAqZmVhdHVyZSBtYXAqIGtlbHVhcmFuLCBzZWRhbmdrYW4gXChuXCkgZGFuIFwobVwpIG1lbnlhdGFrYW4gaW5kZWtzIGJhcmlzIGRhbiBrb2xvbSBwYWRhICpmZWF0dXJlIG1hcCogbWFzdWthbi4gS29vcmRpbmF0IFwoeF9jXCkgbWVudW5qdWtrYW4gcG9zaXNpIGhvcml6b250YWwgYXRhdSBhcmFoIGtvbG9tLCBzZWRhbmdrYW4gXCh5X3JcKSBtZW51bmp1a2thbiBwb3Npc2kgdmVydGlrYWwgYXRhdSBhcmFoIGJhcmlzLg0KDQpCb2JvdCBpbnRlcnBvbGFzaSBwYWRhIHNldGlhcCBlbGVtZW4gbWFzdWthbiBkaW55YXRha2FuIHNlYmFnYWk6DQoNClxbDQp3X3tuLG19XnsocixjKX0NCj0NClxtYXgNClxsZWZ0KA0KMCwNCjEtXGxlZnR8eF9jLW1ccmlnaHR8DQpccmlnaHQpDQpcbWF4DQpcbGVmdCgNCjAsDQoxLVxsZWZ0fHlfci1uXHJpZ2h0fA0KXHJpZ2h0KS4NClxdDQoNCkRlbmdhbiBkZW1pa2lhbiwgcnVtdXMgaW50ZXJwb2xhc2kgYmlsaW5lYXIgZGFwYXQgZGl0dWxpc2thbiBzZWJhZ2FpOg0KDQpcWw0KXGxlZnRbDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsxLDF9DQpccmlnaHQpDQpccmlnaHRdX3tyLGN9DQo9DQpcc3VtX3tuPTF9XnszfQ0KXHN1bV97bT0xfV57M30NCndfe24sbX1eeyhyLGMpfVhfe24sbX1eezEsMX0uDQpcXQ0KDQotICoqUGVuZW50dWFuIGtvb3JkaW5hdCBpbnRlcnBvbGFzaToqKg0KDQpQYWRhIGlsdXN0cmFzaSBpbmksIGtvb3JkaW5hdCBtYXRyaWtzIG1lbmdndW5ha2FuIGluZGVrcyB5YW5nIGRpbXVsYWkgZGFyaSBcKDFcKS4gS2FyZW5hIHVrdXJhbiAqZmVhdHVyZSBtYXAqIG1hc3VrYW4gYWRhbGFoIFwoM1x0aW1lczNcKSBkYW4gdWt1cmFuIGtlbHVhcmFuIGFkYWxhaCBcKDVcdGltZXM1XCksIGtvb3JkaW5hdCBpbnRlcnBvbGFzaSBkaXRlbnR1a2FuIHNlYmFnYWk6DQoNClxbDQp4X2MNCj0NCjErKGMtMSlcZnJhY3szLTF9ezUtMX0NCj0NCjErXGZyYWN7Yy0xfXsyfSwNClxdDQoNClxbDQp5X3INCj0NCjErKHItMSlcZnJhY3szLTF9ezUtMX0NCj0NCjErXGZyYWN7ci0xfXsyfSwNClxdDQoNCmRlbmdhbiBcKHIsYz0xLDIsMyw0LDVcKS4NCg0KQW5na2EgXCgxXCkgbWVudW5qdWtrYW4ga29vcmRpbmF0IGF3YWwgbWF0cmlrcyBtYXN1a2FuLCBzZWRhbmdrYW4gcGVtYmFnaWFuIGRlbmdhbiBcKDJcKSBtZW51bmp1a2thbiBiYWh3YSBzZXRpYXAgaW50ZXJ2YWwgYW50YXJhIGR1YSBrb29yZGluYXQgbWFzdWthbiBkaWJhZ2kgbWVuamFkaSBkdWEgYmFnaWFuIHlhbmcgc2FtYSBwYW5qYW5nLg0KDQpOaWxhaSBrb29yZGluYXQgeWFuZyBkaXBlcm9sZWggYWRhbGFoOg0KDQp8IEluZGVrcyBrZWx1YXJhbiB8IE5pbGFpIGtvb3JkaW5hdCB8DQp8Oi0tLTp8Oi0tLTp8DQp8IFwoMVwpIHwgXCgxXCkgfA0KfCBcKDJcKSB8IFwoMS41XCkgfA0KfCBcKDNcKSB8IFwoMlwpIHwNCnwgXCg0XCkgfCBcKDIuNVwpIHwNCnwgXCg1XCkgfCBcKDNcKSB8DQoNCkRlbmdhbiBkZW1pa2lhbiwgbmlsYWkgcGFkYSBwb3Npc2kga2VsdWFyYW4geWFuZyBiZXJpbXBpdCBkZW5nYW4ga29vcmRpbmF0IG1hc3VrYW4gZGlwZXJ0YWhhbmthbiwgc2VkYW5na2FuIG5pbGFpIHBhZGEgcG9zaXNpIGxhaW5ueWEgZGloaXR1bmcgYmVyZGFzYXJrYW4gYm9ib3QgamFyYWsgdGVyaGFkYXAgZWxlbWVuLWVsZW1lbiBtYXN1a2FuIGRpIHNla2l0YXJueWEuDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gaW50ZXJwb2xhc2kgYmlsaW5lYXIgcGFkYSBwb3Npc2kgXCgoMiwyKVwpOioqDQoNClBhZGEgcG9zaXNpIFwoKDIsMilcKSwga29vcmRpbmF0IGludGVycG9sYXNpIGRpcGVyb2xlaCBzZWJhZ2FpIGJlcmlrdXQ6DQoNClxbDQp5XzI9MS41LA0KXHFxdWFkDQp4XzI9MS41Lg0KXF0NCg0KUG9zaXNpIHRlcnNlYnV0IGJlcmFkYSB0ZXBhdCBkaSB0ZW5nYWggZW1wYXQgZWxlbWVuIG1hc3VrYW4sIHlhaXR1IFwoWF97MSwxfV57MSwxfVwpLCBcKFhfezEsMn1eezEsMX1cKSwgXChYX3syLDF9XnsxLDF9XCksIGRhbiBcKFhfezIsMn1eezEsMX1cKS4NCg0KQm9ib3QgaW50ZXJwb2xhc2kgdW50dWsgZWxlbWVuIFwoWF97MSwxfV57MSwxfVwpIGRpaGl0dW5nIHNlYmFnYWk6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NCndfezEsMX1eeygyLDIpfQ0KJj0NClxtYXgoMCwxLXwxLjUtMXwpDQpcbWF4KDAsMS18MS41LTF8KVxcDQomPQ0KMC41XHRpbWVzMC41XFwNCiY9DQowLjI1Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KS2FyZW5hIHBvc2lzaSB0ZXJzZWJ1dCBiZXJqYXJhayBzYW1hIGRhcmkga2VlbXBhdCBlbGVtZW4gbWFzdWthbiwgbWFrYToNCg0KXFsNCndfezEsMX1eeygyLDIpfQ0KPQ0Kd197MSwyfV57KDIsMil9DQo9DQp3X3syLDF9XnsoMiwyKX0NCj0NCndfezIsMn1eeygyLDIpfQ0KPQ0KMC4yNS4NClxdDQoNCkRlbmdhbiBkZW1pa2lhbiwgcnVtdXMgaW50ZXJwb2xhc2kgYmlsaW5lYXIgbWVuamFkaToNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KXGxlZnRbDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsxLDF9DQpccmlnaHQpDQpccmlnaHRdX3syLDJ9DQomPQ0KMC4yNVhfezEsMX1eezEsMX0NCisNCjAuMjVYX3sxLDJ9XnsxLDF9XFwNCiZccXVhZCsNCjAuMjVYX3syLDF9XnsxLDF9DQorDQowLjI1WF97MiwyfV57MSwxfVxcDQomPQ0KXGZyYWN7DQpYX3sxLDF9XnsxLDF9DQorDQpYX3sxLDJ9XnsxLDF9DQorDQpYX3syLDF9XnsxLDF9DQorDQpYX3syLDJ9XnsxLDF9DQp9ezR9XFwNCiY9DQpcZnJhY3swLjAwKzEuMTQrMC4wMCsxLjUxfXs0fVxcDQomPQ0KMC42NjI1XFwNCiZcYXBwcm94MC42Ni4NClxlbmR7YWxpZ25lZH0NClxdDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gaW50ZXJwb2xhc2kgYmlsaW5lYXIgcGFkYSBwb3Npc2kgXCgoMiwzKVwpOioqDQoNClBhZGEgcG9zaXNpIFwoKDIsMylcKSwga29vcmRpbmF0IGludGVycG9sYXNpIGRpcGVyb2xlaCBzZWJhZ2FpIGJlcmlrdXQ6DQoNClxbDQp5XzI9MS41LA0KXHFxdWFkDQp4XzM9Mi4NClxdDQoNClBvc2lzaSB0ZXJzZWJ1dCBiZXJhZGEgdGVwYXQgZGkgdGVuZ2FoIHNlY2FyYSB2ZXJ0aWthbCBhbnRhcmEgYmFyaXMgcGVydGFtYSBkYW4ga2VkdWEsIHRldGFwaSBzZWphamFyIGRlbmdhbiBrb2xvbSBrZWR1YS4gT2xlaCBrYXJlbmEgaXR1LCBoYW55YSBkdWEgZWxlbWVuIHBhZGEga29sb20ga2VkdWEgeWFuZyBtZW1pbGlraSBib2JvdCBidWthbiBub2wuDQoNCkJvYm90IGludGVycG9sYXNpIHVudHVrIGVsZW1lbiBcKFhfezEsMn1eezEsMX1cKSBkaWhpdHVuZyBzZWJhZ2FpOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQp3X3sxLDJ9XnsoMiwzKX0NCiY9DQpcbWF4KDAsMS18Mi0yfCkNClxtYXgoMCwxLXwxLjUtMXwpXFwNCiY9DQoxXHRpbWVzMC41XFwNCiY9DQowLjUuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpTZW1lbnRhcmEgaXR1LCBib2JvdCB1bnR1ayBlbGVtZW4gXChYX3syLDJ9XnsxLDF9XCkgYWRhbGFoOg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQp3X3syLDJ9XnsoMiwzKX0NCiY9DQpcbWF4KDAsMS18Mi0yfCkNClxtYXgoMCwxLXwxLjUtMnwpXFwNCiY9DQoxXHRpbWVzMC41XFwNCiY9DQowLjUuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpFbGVtZW4gbGFpbm55YSBtZW1pbGlraSBib2JvdCBub2wga2FyZW5hIGJlcmFkYSBkaSBsdWFyIGphcmFrIGludGVycG9sYXNpIHBhZGEgcG9zaXNpIHRlcnNlYnV0LiBEZW5nYW4gZGVtaWtpYW46DQoNClxbDQp3X3sxLDJ9XnsoMiwzKX0NCj0NCndfezIsMn1eeygyLDMpfQ0KPQ0KMC41Lg0KXF0NCg0KRGVuZ2FuIG1lbWFzdWtrYW4gYm9ib3QgdGVyc2VidXQga2UgZGFsYW0gcnVtdXMgaW50ZXJwb2xhc2kgYmlsaW5lYXIsIGRpcGVyb2xlaDoNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KXGxlZnRbDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsxLDF9DQpccmlnaHQpDQpccmlnaHRdX3syLDN9DQomPQ0KMC41WF97MSwyfV57MSwxfQ0KKw0KMC41WF97MiwyfV57MSwxfVxcDQomPQ0KXGZyYWN7DQpYX3sxLDJ9XnsxLDF9DQorDQpYX3syLDJ9XnsxLDF9DQp9ezJ9XFwNCiY9DQpcZnJhY3sxLjE0KzEuNTF9ezJ9XFwNCiY9DQoxLjMyNVxcDQomXGFwcHJveDEuMzIuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gbWVuZXJhcGthbiBpbnRlcnBvbGFzaSBiaWxpbmVhciBwYWRhIHNlbHVydWggcG9zaXNpIGtlbHVhcmFuLCBkaXBlcm9sZWggKmZlYXR1cmUgbWFwKiBoYXNpbCAqdXBzYW1wbGluZyogYmVydWt1cmFuIFwoNVx0aW1lczVcKSwgeWFpdHU6DQoNClxbDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsxLDF9DQpccmlnaHQpDQo9DQpcYmVnaW57Ym1hdHJpeH0NCjAuMDAgJiAwLjU3ICYgMS4xNCAmIDAuNTcgJiAwLjAwXFwNCjAuMDAgJiAwLjY2ICYgMS4zMiAmIDAuNjYgJiAwLjAwXFwNCjAuMDAgJiAwLjc1ICYgMS41MSAmIDAuNzUgJiAwLjAwXFwNCjAuMDAgJiAwLjQyICYgMC44NCAmIDAuNDIgJiAwLjAwXFwNCjAuMDAgJiAwLjA5ICYgMC4xNyAmIDAuMDkgJiAwLjAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KSGFzaWwgdGVyc2VidXQgbWVudW5qdWtrYW4gYmFod2EgaW50ZXJwb2xhc2kgYmlsaW5lYXIgbWVtcGVyYmVzYXIgdWt1cmFuIHNwYXNpYWwgKmZlYXR1cmUgbWFwKiBkYXJpIFwoM1x0aW1lczNcKSBtZW5qYWRpIFwoNVx0aW1lczVcKS4gTmlsYWkgcGFkYSBwb3Npc2kgeWFuZyBiZXJpbXBpdCBkZW5nYW4ga29vcmRpbmF0IG1hc3VrYW4gZGlwZXJ0YWhhbmthbiwgc2VkYW5na2FuIG5pbGFpIHBhZGEgcG9zaXNpIGxhaW5ueWEgZGloaXR1bmcgbWVuZ2d1bmFrYW4gYm9ib3QgaW50ZXJwb2xhc2kgYmVyZGFzYXJrYW4gamFyYWsgdGVyaGFkYXAgZWxlbWVuIG1hc3VrYW4uDQoNCi0gKipSdW11cyBub2RlIGRlY29kZXI6KioNCg0KU2VzdWFpIGRlbmdhbiBwZXJzYW1hYW4gVU5ldCsrLCAqbmVzdGVkIHNraXAgY29ubmVjdGlvbioga2VkdWEgcGFkYSBub2RlICpkZWNvZGVyKiBkaXJ1bXVza2FuIHNlYmFnYWk6DQoNClxbDQpcbWF0aGJme1h9XnswLDJ9DQo9DQpIXnsoMCwyKX0NClxsZWZ0KA0KXG9wZXJhdG9ybmFtZXtDb25jYXR9DQpcbGVmdFsNClxtYXRoYmZ7WH1eezAsMH0sDQpcbWF0aGJme1h9XnswLDF9LA0KXG9wZXJhdG9ybmFtZXtVcH0NClxsZWZ0KA0KXG1hdGhiZntYfV57MSwxfQ0KXHJpZ2h0KQ0KXHJpZ2h0XQ0KXHJpZ2h0KS4NClxdDQoNClBhZGEgcGVyc2FtYWFuIHRlcnNlYnV0LCBcKEheeygwLDIpfVwpIG1lbnlhdGFrYW4gb3BlcmFzaSBwZW5nb2xhaGFuIGZpdHVyIHBhZGEgbm9kZSAqZGVjb2RlciogXChcbWF0aGJme1h9XnswLDJ9XCkuIERhbGFtIGlsdXN0cmFzaSBwZXJoaXR1bmdhbiBtYW51YWwgaW5pLCBvcGVyYXNpIHRlcnNlYnV0IGRpc2VkZXJoYW5ha2FuIG1lbmdndW5ha2FuIGtvbnZvbHVzaSBcKDFcdGltZXMxXCkgdGFucGEgYmlhcyB5YW5nIGRpaWt1dGkgZnVuZ3NpIGFrdGl2YXNpIFJlTFUuDQoNCkthcmVuYSBrZXRpZ2EgKmZlYXR1cmUgbWFwKiB5YW5nIGRpZ2FidW5na2FuIGJlcnVrdXJhbiBcKDVcdGltZXM1XCkgZGFuIG1hc2luZy1tYXNpbmcgZGlyZXByZXNlbnRhc2lrYW4gb2xlaCBzYXR1IGthbmFsLCBoYXNpbCAqQ29uY2F0KiBtZW1pbGlraSB0aWdhIGthbmFsLiBTYXR1IGZpbHRlciBrb252b2x1c2kgXCgxXHRpbWVzMVwpIGRpZ3VuYWthbiB1bnR1ayBtZW5nZ2FidW5na2FuIGtldGlnYSBrYW5hbCB0ZXJzZWJ1dCBtZW5qYWRpIHNhdHUga2FuYWwga2VsdWFyYW4uDQoNClBhZGEgaWx1c3RyYXNpIGluaSwgYm9ib3Qga2VybmVsIGRpdGVudHVrYW4gc2ViYWdhaToNCg0KXFsNCldfe1xtYXRocm17ZGVjfSwxfV57KDAsMil9PVswLjI1XSwNClxxcXVhZA0KV197XG1hdGhybXtkZWN9LDJ9XnsoMCwyKX09WzAuNTBdLA0KXHFxdWFkDQpXX3tcbWF0aHJte2RlY30sM31eeygwLDIpfT1bMC4yNV0uDQpcXQ0KDQpCb2JvdCBwZXJ0YW1hIGRpdGVyYXBrYW4gcGFkYSBcKFxtYXRoYmZ7WH1eezAsMH1cKSwgYm9ib3Qga2VkdWEgZGl0ZXJhcGthbiBwYWRhIFwoXG1hdGhiZntYfV57MCwxfVwpLCBzZWRhbmdrYW4gYm9ib3Qga2V0aWdhIGRpdGVyYXBrYW4gcGFkYSBcKFxvcGVyYXRvcm5hbWV7VXB9KFxtYXRoYmZ7WH1eezEsMX0pXCkuIEtldGlnYSBib2JvdCB0ZXJzZWJ1dCBtZXJ1cGFrYW4gcGFyYW1ldGVyIGlsdXN0cmF0aWYgdW50dWsgbWVueWVkZXJoYW5ha2FuIHBlcmhpdHVuZ2FuIG1hbnVhbCwgYnVrYW4gYm9ib3QgaGFzaWwgcGVsYXRpaGFuIG1vZGVsLg0KDQpEZW5nYW4gZGVtaWtpYW4sIHVudHVrIHNldGlhcCBwb3Npc2kgc3Bhc2lhbCBcKChyLGMpXCksIGtlbHVhcmFuIG5vZGUgKmRlY29kZXIqIGRpaGl0dW5nIHNlYmFnYWk6DQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClhfe3IsY31eezAsMn0NCj0NClxvcGVyYXRvcm5hbWV7UmVMVX0NClxCaWdnKA0KJjAuMjVYX3tyLGN9XnswLDB9XFwNCiYrDQowLjUwWF97cixjfV57MCwxfVxcDQomKw0KMC4yNQ0KXGxlZnRbDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsxLDF9DQpccmlnaHQpDQpccmlnaHRdX3tyLGN9DQpcQmlnZykuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuIG5vZGUgZGVjb2RlciBwYWRhIHBvc2lzaSBcKCgyLDIpXCk6KioNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KWF97MiwyfV57MCwyfQ0KJj0NClxvcGVyYXRvcm5hbWV7UmVMVX0NClxCaWdnKA0KMC4yNVhfezIsMn1eezAsMH0NCisNCjAuNTBYX3syLDJ9XnswLDF9XFwNCiZccXF1YWQrDQowLjI1DQpcbGVmdFsNClxvcGVyYXRvcm5hbWV7VXB9DQpcbGVmdCgNClxtYXRoYmZ7WH1eezEsMX0NClxyaWdodCkNClxyaWdodF1fezIsMn0NClxCaWdnKVxcDQomPQ0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQowLjI1KC0yLjMzKQ0KKw0KMC41MCgwLjAwKQ0KKw0KMC4yNSgwLjY2KQ0KXHJpZ2h0KVxcDQomPQ0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQotMC41ODI1KzAuMTY1DQpccmlnaHQpXFwNCiY9DQpcb3BlcmF0b3JuYW1le1JlTFV9KC0wLjQxNzUpXFwNCiY9DQowLjAwLg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiBub2RlIGRlY29kZXIgcGFkYSBwb3Npc2kgXCgoMiwzKVwpOioqDQoNClxbDQpcYmVnaW57YWxpZ25lZH0NClhfezIsM31eezAsMn0NCiY9DQpcb3BlcmF0b3JuYW1le1JlTFV9DQpcQmlnZygNCjAuMjVYX3syLDN9XnswLDB9DQorDQowLjUwWF97MiwzfV57MCwxfVxcDQomXHFxdWFkKw0KMC4yNQ0KXGxlZnRbDQpcb3BlcmF0b3JuYW1le1VwfQ0KXGxlZnQoDQpcbWF0aGJme1h9XnsxLDF9DQpccmlnaHQpDQpccmlnaHRdX3syLDN9DQpcQmlnZylcXA0KJj0NClxvcGVyYXRvcm5hbWV7UmVMVX0NClxsZWZ0KA0KMC4yNSgxLjkxKQ0KKw0KMC41MCgzLjY0KQ0KKw0KMC4yNSgxLjMyKQ0KXHJpZ2h0KVxcDQomPQ0KXG9wZXJhdG9ybmFtZXtSZUxVfQ0KXGxlZnQoDQowLjQ3NzUrMS44MiswLjMzDQpccmlnaHQpXFwNCiY9DQpcb3BlcmF0b3JuYW1le1JlTFV9KDIuNjI3NSlcXA0KJlxhcHByb3gNCjIuNjMuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQpEZW5nYW4gbWVuZXJhcGthbiBvcGVyYXNpIHlhbmcgc2FtYSBwYWRhIHNlbHVydWggcG9zaXNpIHNwYXNpYWwgZGFuIG1lbmdndW5ha2FuIG5pbGFpIHByZXNpc2kgcGVudWggc2ViZWx1bSBwZW1idWxhdGFuLCBkaXBlcm9sZWggKmZlYXR1cmUgbWFwKiBrZWx1YXJhbiBha2hpciAqZGVjb2Rlciogc2ViYWdhaSBiZXJpa3V0Og0KDQpcWw0KXG1hdGhiZntYfV57MCwyfQ0KPQ0KXGJlZ2lue2JtYXRyaXh9DQowLjAwICYgMC4wMCAmIDIuMjIgJiAwLjc3ICYgMC4wMFxcDQowLjAwICYgMC4wMCAmIDIuNjMgJiAxLjExICYgMC4wMFxcDQowLjAwICYgMC4wMCAmIDIuNzcgJiAxLjIwICYgMC4wMFxcDQowLjAwICYgMC4wMCAmIDEuOTkgJiAwLjY0ICYgMC4wMFxcDQowLjAwICYgMC4wMCAmIDAuNzcgJiAwLjAwICYgMC4wMA0KXGVuZHtibWF0cml4fS4NClxdDQoNCkhhc2lsIHRlcnNlYnV0IG1lbnVuanVra2FuIGJhaHdhIG5vZGUgXChcbWF0aGJme1h9XnswLDJ9XCkgbWVuZ2dhYnVuZ2thbiBpbmZvcm1hc2kgZGFyaSBcKFxtYXRoYmZ7WH1eezAsMH1cKSwgXChcbWF0aGJme1h9XnswLDF9XCksIGRhbiBoYXNpbCAqdXBzYW1wbGluZyogXChcbWF0aGJme1h9XnsxLDF9XCkgbWVsYWx1aSAqbmVzdGVkIHNraXAgY29ubmVjdGlvbiouIFBhZGEgaWx1c3RyYXNpIGluaSwgcGVuZ2dhYnVuZ2FuIGRpbGFrdWthbiBtZW5nZ3VuYWthbiAqQ29uY2F0Kiwga29udm9sdXNpIFwoMVx0aW1lczFcKSwgZGFuIGZ1bmdzaSBha3RpdmFzaSBSZUxVLg0KDQoqRmVhdHVyZSBtYXAqIFwoXG1hdGhiZntYfV57MCwyfVwpIG1lcnVwYWthbiBrZWx1YXJhbiBha2hpciAqZGVjb2RlciogcGFkYSBpbHVzdHJhc2kgcGVyaGl0dW5nYW4gbWFudWFsIGluaSBkYW4gc2VsYW5qdXRueWEgZGlndW5ha2FuIHNlYmFnYWkgbWFzdWthbiBwYWRhICpoZWFkKiBzZWdtZW50YXNpLg0KDQoNCiMjIDcuIEhlYWQgc2lnbW9pZCBkYW4gbWFzayBzZWdtZW50YXNpDQoNCktlbHVhcmFuIGFraGlyIGRlY29kZXIgXChcbWF0aGJme1h9XnswLDJ9XCkgZGl0ZXJ1c2thbiBrZSAqaGVhZCogc2VnbWVudGFzaSBtZW5nZ3VuYWthbiBrb252b2x1c2kgXCgxXHRpbWVzMVwpIHRhbnBhIGJpYXMuIEtvbnZvbHVzaSB0ZXJzZWJ1dCBtZW5naGFzaWxrYW4gbWF0cmlrcyBsb2dpdCBcKFxtYXRoYmZ7en1cKS4gU2VsYW5qdXRueWEsIGZ1bmdzaSBzaWdtb2lkIGRpdGVyYXBrYW4gcGFkYSBzZXRpYXAgZWxlbWVuIGxvZ2l0IHVudHVrIG1lbWJlbnR1ayBtYXRyaWtzIHByb2JhYmlsaXRhcyBcKFxtYXRoYmZ7cH1cKS4gQmVyZGFzYXJrYW4ga2V0ZW50dWFuIHBhZGEgQmFiIElJSSwgcGlrc2VsIGRlbmdhbiBwcm9iYWJpbGl0YXMgbGViaWggZGFyaSBcKDAuNTBcKSBkaWthdGVnb3Jpa2FuIHNlYmFnYWkgbGVzaSwgc2VkYW5na2FuIHBpa3NlbCBsYWlubnlhIGRpa2F0ZWdvcmlrYW4gc2ViYWdhaSBsYXRhciBiZWxha2FuZy4NCg0KIyMjIGEuIEhlYWQgc2VnbWVudGFzaSBkYW4gbWF0cmlrcyBsb2dpdA0KDQpQYWRhIGlsdXN0cmFzaSBpbmksICpoZWFkKiBzZWdtZW50YXNpIG1lbmdndW5ha2FuIGtvbnZvbHVzaSBcKDFcdGltZXMxXCkgdGFucGEgYmlhcyBkZW5nYW4ga2VybmVsIHNlYmFnYWkgYmVyaWt1dC4NCg0KXFsNClxtYXRoYmZ7V31fe1xtYXRocm17aGVhZH19PQ0KXGJlZ2lue2JtYXRyaXh9DQoxLjAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KS2FyZW5hIGZlYXR1cmUgbWFwIG1hc3VrYW4gaGFueWEgbWVtaWxpa2kgc2F0dSBrYW5hbCwga2VybmVsIHRlcnNlYnV0IGRpdGVyYXBrYW4gcGFkYSBzZXRpYXAgbmlsYWkgXChcbWF0aGJme1h9XnswLDJ9XCkuDQoNCi0gKipSdW11czoqKg0KDQpcWw0Kel97aSxqfQ0KPQ0KV197XG1hdGhybXtoZWFkfX0NClheezAsMn1fe2ksan0uDQpcXQ0KDQpLYXJlbmEgXChXX3tcbWF0aHJte2hlYWR9fT0xLjAwXCksIG1ha2ENCg0KXFsNCnpfe2ksan0NCj0NClheezAsMn1fe2ksan0uDQpcXQ0KDQpNYXRyaWtzIGxvZ2l0IFwoXG1hdGhiZnt6fVwpIGJlcnVrdXJhbiBcKDVcdGltZXM1XCkuDQoNCi0gKipDb250b2ggcGVyaGl0dW5nYW4gcGFkYSBwb3Npc2kgXCgoMywzKVwpOioqDQoNClxbDQpcYmVnaW57YWxpZ25lZH0NCnpfezMsM30NCiY9DQpXX3tcbWF0aHJte2hlYWR9fQ0KWF57MCwyfV97MywzfVxcDQomPQ0KMS4wMCgyLjc3KVxcDQomPQ0KMi43Ny4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBwZXJoaXR1bmdhbiBtZW5nZ3VuYWthbiBuaWxhaSBwcmVzaXNpIHBlbnVoIHNlYmVsdW0gcGVtYnVsYXRhbiwgZGlwZXJvbGVoIG1hdHJpa3MgbG9naXQgYmVyaWt1dC4NCg0KXFsNClxtYXRoYmZ7en09DQpcYmVnaW57Ym1hdHJpeH0NCjAuMDAgJiAwLjAwICYgMi4yMiAmIDAuNzcgJiAwLjAwXFwNCjAuMDAgJiAwLjAwICYgMi42MyAmIDEuMTEgJiAwLjAwXFwNCjAuMDAgJiAwLjAwICYgMi43NyAmIDEuMjAgJiAwLjAwXFwNCjAuMDAgJiAwLjAwICYgMS45OSAmIDAuNjQgJiAwLjAwXFwNCjAuMDAgJiAwLjAwICYgMC43NyAmIDAuMDAgJiAwLjAwDQpcZW5ke2JtYXRyaXh9Lg0KXF0NCg0KIyMjIGIuIFByb2JhYmlsaXRhcyBwcmVkaWtzaSBwaWtzZWwNCg0KRnVuZ3NpIHNpZ21vaWQgZGl0ZXJhcGthbiBwYWRhIHNldGlhcCBlbGVtZW4gbWF0cmlrcyBsb2dpdCB1bnR1ayBtZW5naGFzaWxrYW4gcHJvYmFiaWxpdGFzIHByZWRpa3NpIHBpa3NlbCBwYWRhIHJlbnRhbmcgXChbMCwxXVwpLg0KDQotICoqUnVtdXM6KioNCg0KXFsNCnBfe2ksan0NCj0NClxzaWdtYSh6X3tpLGp9KQ0KPQ0KXGZyYWN7MX17MStlXnstel97aSxqfX19Lg0KXF0NCg0KTWF0cmlrcyBwcm9iYWJpbGl0YXMgXChcbWF0aGJme3B9XCkgYmVydWt1cmFuIFwoNVx0aW1lczVcKS4NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiBwYWRhIHBvc2lzaSBcKCgzLDMpXCk6KioNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KcF97MywzfQ0KJj0NClxmcmFjezF9ezErZV57LXpfezMsM319fVxcDQomPQ0KXGZyYWN7MX17MStlXnstMi43N319XFwNCiY9DQpcZnJhY3sxfXsxKzAuMDZ9XFwNCiY9DQowLjk0Lg0KXGVuZHthbGlnbmVkfQ0KXF0NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiBwYWRhIHBvc2lzaSBcKCgxLDEpXCk6KioNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KcF97MSwxfQ0KJj0NClxmcmFjezF9ezErZV57LTAuMDB9fVxcDQomPQ0KXGZyYWN7MX17MSsxfVxcDQomPQ0KMC41MC4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBwZXJoaXR1bmdhbiBtZW5nZ3VuYWthbiBuaWxhaSBwcmVzaXNpIHBlbnVoIHNlYmVsdW0gcGVtYnVsYXRhbiwgZGlwZXJvbGVoIG1hdHJpa3MgcHJvYmFiaWxpdGFzIGJlcmlrdXQuDQoNClxbDQpcbWF0aGJme3B9PQ0KXGJlZ2lue2JtYXRyaXh9DQowLjUwICYgMC41MCAmIDAuOTAgJiAwLjY4ICYgMC41MFxcDQowLjUwICYgMC41MCAmIDAuOTMgJiAwLjc1ICYgMC41MFxcDQowLjUwICYgMC41MCAmIDAuOTQgJiAwLjc3ICYgMC41MFxcDQowLjUwICYgMC41MCAmIDAuODggJiAwLjY1ICYgMC41MFxcDQowLjUwICYgMC41MCAmIDAuNjggJiAwLjUwICYgMC41MA0KXGVuZHtibWF0cml4fS4NClxdDQoNCiMjIyBjLiBNYXNrIHNlZ21lbnRhc2kgYmluZXINCg0KTWF0cmlrcyBwcm9iYWJpbGl0YXMgZGlrb252ZXJzaSBtZW5qYWRpIG1hc2sgc2VnbWVudGFzaSBiaW5lciBtZW5nZ3VuYWthbiBuaWxhaSBhbWJhbmcgbGViaWggZGFyaSBcKDAuNTBcKS4gUGlrc2VsIGRlbmdhbiBwcm9iYWJpbGl0YXMgdGVwYXQgXCgwLjUwXCkgZGlrYXRlZ29yaWthbiBzZWJhZ2FpIGxhdGFyIGJlbGFrYW5nLg0KDQotICoqUnVtdXM6KioNCg0KXFsNClx3aWRlaGF0e019X3tpLGp9DQo9DQpcbWF0aGJiezF9DQpcbGVmdFsNCnBfe2ksan0+MC41MA0KXHJpZ2h0XS4NClxdDQoNCmRlbmdhbg0KDQpcWw0KXHdpZGVoYXR7TX1fe2ksan0NCj0NClxiZWdpbntjYXNlc30NCjEsICYgXHRleHR7amlrYSB9IHBfe2ksan0+MC41MCBcdGV4dHsgKGxlc2kpfSxcXA0KMCwgJiBcdGV4dHtqaWthIH0gcF97aSxqfVxsZXEwLjUwIFx0ZXh0eyAobGF0YXIgYmVsYWthbmcpfS4NClxlbmR7Y2FzZXN9DQpcXQ0KDQpNYXRyaWtzIG1hc2sgc2VnbWVudGFzaSBcKFx3aWRlaGF0e1xtYXRoYmZ7TX19XCkgYmVydWt1cmFuIFwoNVx0aW1lczVcKS4NCg0KLSAqKkNvbnRvaCBwZXJoaXR1bmdhbiBwYWRhIHBvc2lzaSBcKCgzLDMpXCk6KioNCg0KXFsNClxiZWdpbnthbGlnbmVkfQ0KXHdpZGVoYXR7TX1fezMsM30NCiY9DQpcbWF0aGJiezF9DQpcbGVmdFsNCnBfezMsM30+MC41MA0KXHJpZ2h0XVxcDQomPQ0KXG1hdGhiYnsxfQ0KXGxlZnRbDQowLjk0PjAuNTANClxyaWdodF1cXA0KJj0NCjEuDQpcZW5ke2FsaWduZWR9DQpcXQ0KDQotICoqQ29udG9oIHBlcmhpdHVuZ2FuIHBhZGEgcG9zaXNpIFwoKDEsMSlcKToqKg0KDQpcWw0KXGJlZ2lue2FsaWduZWR9DQpcd2lkZWhhdHtNfV97MSwxfQ0KJj0NClxtYXRoYmJ7MX0NClxsZWZ0Ww0KcF97MSwxfT4wLjUwDQpccmlnaHRdXFwNCiY9DQpcbWF0aGJiezF9DQpcbGVmdFsNCjAuNTA+MC41MA0KXHJpZ2h0XVxcDQomPQ0KMC4NClxlbmR7YWxpZ25lZH0NClxdDQoNCkRlbmdhbiBhdHVyYW4geWFuZyBzYW1hLCBkaXBlcm9sZWggbWFzayBzZWdtZW50YXNpIGJpbmVyIGJlcmlrdXQuDQoNClxbDQpcd2lkZWhhdHtcbWF0aGJme019fT0NClxiZWdpbntibWF0cml4fQ0KMCAmIDAgJiAxICYgMSAmIDBcXA0KMCAmIDAgJiAxICYgMSAmIDBcXA0KMCAmIDAgJiAxICYgMSAmIDBcXA0KMCAmIDAgJiAxICYgMSAmIDBcXA0KMCAmIDAgJiAxICYgMCAmIDANClxlbmR7Ym1hdHJpeH0uDQpcXQ0KDQoNCj4gKipLZXRlcmFuZ2FuIHByb3NlcyBwZWxhdGloYW46KiogTWFzayBiaW5lciBcKFx3aWRlaGF0e019XCkgcGFkYSBpbHVzdHJhc2kgaW5pIGRpdGFtcGlsa2FuIHVudHVrIG1lbXBlcmxpaGF0a2FuIGJlbnR1ayBha2hpciBoYXNpbCBzZWdtZW50YXNpIGRhbiB1bnR1ayBtZW5naGl0dW5nIG1ldHJpayBldmFsdWFzaS4gUGFkYSBwcm9zZXMgcGVsYXRpaGFuLCBtYXNrIGJpbmVyIHRlcnNlYnV0IHRpZGFrIGRpZ3VuYWthbiB1bnR1ayBtZW1wZXJiYXJ1aSBib2JvdCBtb2RlbC4gUGVtYmFydWFuIGJvYm90IGRpbGFrdWthbiBtZW5nZ3VuYWthbiBwcm9iYWJpbGl0YXMgcHJlZGlrc2kgXChwXCkgZGFuIGdyb3VuZCB0cnV0aCBcKE1cKSBtZWxhbHVpIEJDRS1EaWNlIGxvc3MuDQoNCg==