LAPORAN ANALISIS CLUSTERING HYBRID

Nama: Nabila Anggita Putri

Program Studi: S1 - Sains Data

Dosen Pengampu: Mr. Bakti Siregar, M.Sc., CDS.,

Institusi: Institut Teknologi Sains Bandung



Foto Formal



1. Pendahuluan

Analisis clustering merupakan teknik dalam unsupervised learning yang bertujuan mengelompokkan individu atau observasi berdasarkan tingkat kemiripan karakteristik tanpa menggunakan label kelas. Metode ini penting dalam berbagai bidang analisis data, termasuk segmentasi pelanggan, karena mampu mengungkap pola tersembunyi (hidden patterns) di dalam data. Dalam konteks pemasaran ritel, khususnya pada data pelanggan di sebuah mall, clustering digunakan untuk memahami perilaku belanja konsumen sehingga perusahaan dapat menyusun strategi pemasaran yang lebih tepat sasaran.

Pada studi ini dilakukan pendekatan clustering hybrid, yaitu gabungan atau kombinasi dari beberapa metode clustering untuk menghasilkan performa segmentasi yang lebih stabil, akurat, dan representatif. Teknik hybrid memanfaatkan keunggulan setiap algoritma, sehingga dapat mengatasi keterbatasan yang muncul jika hanya menggunakan satu metode. Misalnya, metode berbasis jarak kadang sensitif terhadap noise dan bentuk klaster yang tidak linear, sementara metode berbasis graf dapat lebih baik dalam memetakan struktur kompleks namun memiliki beban komputasi tinggi. Dengan pendekatan hybrid, proses clustering dapat dilakukan lebih robust melalui tahap ekstraksi fitur, reduksi dimensi, atau penyempurnaan hasil klaster.

Dalam penelitian ini digunakan tiga pendekatan clustering modern yang mewakili tiga paradigma berbeda:

1. Autoencoder Clustering – pendekatan berbasis deep learning yang melakukan pembelajaran representasi (representation learning). Autoencoder mereduksi dimensi data melalui latent space, sehingga struktur data menjadi lebih kompak dan mudah dipisahkan sebelum diterapkan algoritma klaster seperti KMeans.

2. Self-Organizing Map (SOM) – metode jaringan saraf kompetitif yang memproyeksikan data berdimensi tinggi ke dalam grid dua dimensi. SOM mampu memvisualisasikan pola topologis dan kesamaan antar data secara intuitif, sehingga sangat membantu dalam interpretasi struktur klaster.

3. Spectral Clustering – metode berbasis dekomposisi eigen pada matriks Laplacian graf. Pendekatan ini lebih efektif untuk mengelompokkan data dengan bentuk klaster yang kompleks, tidak beraturan, maupun tidak terpisah secara linear.

Ketiga metode tersebut dibandingkan untuk menentukan pendekatan yang paling tepat dalam mengelompokkan pelanggan mall berdasarkan perilaku belanja mereka. Melalui analisis ini, diharapkan diperoleh segmentasi pelanggan yang lebih akurat dan dapat menjadi dasar pengambilan keputusan dalam strategi pemasaran, pengelolaan loyalitas, dan pengembangan layanan yang sesuai dengan profil tiap kelompok pelanggan.

Dataset yang digunakan adalah:

Mall Customers Dataset (Publik — tersedia di Kaggle). Link: “https://www.kaggle.com/datasets/amisha0528/mall-customers-dataset”.

2. Definisi Dan Teori

2.1 Autoencoder (Unsupervised Clustering)

Autoencoder adalah arsitektur jaringan saraf dalam yang belajar memetakan data ke ruang berdimensi lebih rendah (latent space) melalui proses rekonstruksi. Representasi laten inilah yang digunakan sebagai input untuk clustering.

Rumus:

Autoencoder terdiri dari dua fungsi:

1. Encoder: \[ z = f_{\theta}(x) \]

2. Decoder: \[ \hat{x} = g_{\phi}(z) \]

Tujuan Optimasi: \[ \min_{\theta, \phi} \, \lVert x - \hat{x} \rVert^{2} \]

Sehingga model belajar representasi padat (compressed) yang mempertahankan struktur utama data.

a. Cara Kerja

  • Melakukan encoding data → latent space.
  • Melakukan decoding untuk meminimalkan error rekonstruksi.
  • Mengambil latent representation z.
  • Melakukan clustering pada z (umumnya KMeans atau Gaussian Mixture).

b. Hyperparameter Utama

  • Jumlah neuron di hidden layer
  • Dimensi latent space
  • Aktivasi (ReLU, Sigmoid)
  • Optimizer (Adam)
  • Epoch & batch size

c. Kelebihan

  • Sangat baik untuk data kompleks.
  • Menangkap struktur non-linear.
  • Menghasilkan fitur yang lebih representatif untuk clustering.

d. Keterbatasan

  • Membutuhkan tuning banyak hyperparameter.
  • Butuh komputasi tinggi.
  • Rentan overfitting bila data sedikit.

2.2 Self - Organizing Map (SOM)

SOM adalah jaringan saraf unsupervised yang memetakan data berdimensi tinggi ke grid 2D melalui proses kompetisi antar neuron.

Model Matematis:

Pemilihan neuron pemenang: \[ \text{BMU} = \arg\min_i \, \lVert x - w_i \rVert \]

Pembaruan Bobot: \[ w_i(t+1) = w_i(t) + \alpha(t) \, h_{\text{BMU}, i}(t) \, (x - w_i(t)) \]

a. Cara Kerja

  • Inisialisasi grid neuron.
  • Untuk setiap data:
    • Tentukan Best Matching Unit (BMU).
    • Perbarui bobot tetangga.
  • Proses iteratif hingga konvergen.

b. Hyperparameter Utama

  • Ukuran grid (misal 10×10)
  • Learning rate
  • Radius neighborhood
  • Jumlah epoch

c. Kelebihan

  • Menyediakan peta topografi yang teratur
  • Mudah diinterpretasi
  • Cocok untuk clustering berbasis visual

d. Keterbatasan

  • Butuh pemilihan grid yang tepat
  • Tidak optimal untuk data sangat kompleks
  • Hasil clustering bergantung pada inisialisasi

2.3 Spectral Clustering

Metode clustering berbasis graf yang menggunakan eigenvector dari Laplacian graph untuk memproyeksikan data ke subspace sebelum dilakukan clustering (biasanya KMeans).

Rumus

Membangun similarity matrix: \[ S_{ij} = e^{-\frac{\lVert x_i - x_j \rVert^{2}}{2\sigma^{2}}} \]

Matriks Laplacian tidak ter-normalisasi: \[ L = D - S \]

Eigen-decomposition: \[ L v = \lambda v \]

a. Cara Kerja

  • Hitung similarity matrix.
  • Hitung Laplacian graph.
  • Ambil k eigenvector terkecil.
  • Cluster pada ruang eigenvector.

b. Hyperparameter Utama

  • Jumlah cluster
  • Jenis similarity (rbf, nearest neighbors)
  • Parameter sigma

c. Kelebihan

  • Menangkap struktur non-linear
  • Cocok untuk dataset dengan cluster tidak berbentuk bola
  • Lebih stabil dibanding KMeans pada boundary sulit

d. Keterbatsan

  • Komputasi tinggi \(O(n^3)\)
  • Sensitif terhadap pemilihan parameter sigma

3. Persiapan Data

Dataset berisi \(200\) pelanggan dengan variabel:

  • CustomerID
  • Genre
  • Age
  • Annual Income (k$)
  • Spending Score (1 - 100)

3.1 Loading Data

## 'data.frame':    200 obs. of  5 variables:
##  $ CustomerID   : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ Gender       : chr  "Male" "Male" "Female" "Female" ...
##  $ Age          : int  19 21 20 23 31 22 35 23 64 30 ...
##  $ Income       : int  15 15 16 16 17 17 18 18 19 19 ...
##  $ SpendingScore: int  39 81 6 77 40 76 6 94 3 72 ...
##    CustomerID        Gender               Age            Income      
##  Min.   :  1.00   Length:200         Min.   :18.00   Min.   : 15.00  
##  1st Qu.: 50.75   Class :character   1st Qu.:28.75   1st Qu.: 41.50  
##  Median :100.50   Mode  :character   Median :36.00   Median : 61.50  
##  Mean   :100.50                      Mean   :38.85   Mean   : 60.56  
##  3rd Qu.:150.25                      3rd Qu.:49.00   3rd Qu.: 78.00  
##  Max.   :200.00                      Max.   :70.00   Max.   :137.00  
##  SpendingScore  
##  Min.   : 1.00  
##  1st Qu.:34.75  
##  Median :50.00  
##  Mean   :50.20  
##  3rd Qu.:73.00  
##  Max.   :99.00

4 Redukasi Dimensi

Untuk metode Autoencoder, representasi laten sudah menjadi reduksi dimensi. Untuk SOM dan Spectral Clustering, reduksi tidak wajib karena dimensi kecil (4 fitur numerik).

Karena dataset ini kecil dan fitur sudah manageable, reduksi dimensi tidak dilakukan.

5. Pemodelan Clustering

5.1 Autoencoder + KMeans

Pemilihan Parameter

  • Dense layer: 8 → 4 → latent 2
  • Aktivasi: ReLU
  • Optimizer: Adam
  • Epoch: 100
##                    Metric   Value
## 1              Silhouette   0.350
## 2    Davies-Bouldin Index   1.135
## 3 Calinski-Harabasz Index 100.488

5.2 Self-Organizing Map (SOM)

Pemilihan Parameter

  • Grid: 10×10
  • Learning rate: default
  • Iterasi: 1000
##                    Metric  Value
## 1              Silhouette  0.348
## 2    Davies-Bouldin Index  1.140
## 3 Calinski-Harabasz Index 99.534

5.3 Spectral Clustering

Pemilihan Parameter

  • k = 3
  • SImilarity = radial basis function
##                    Metric  Value
## 1              Silhouette  0.246
## 2    Davies-Bouldin Index  1.823
## 3 Calinski-Harabasz Index 71.140

6. Evaluasi Clustering

Metode evaluasi:

1. Silhouette Index

2. Davies–Bouldin Index (DBI)

3. Calinski–Harabasz Index (CHI)

## [1] 0.3502714
## [1] 0.3476772
## [1] 0.2462819

7. Pembahasan Hasil dan Perbandingan

##        Metode Silhouette   DBI     CHI
## 1 Autoencoder      0.350 1.135 100.488
## 2         SOM      0.348 1.140  99.534
## 3    Spectral      0.246 1.823  71.140
##                                    Interpretasi
## 1 Biasanya baik jika struktur non-linear muncul
## 2                    Cocok untuk data sederhana
## 3      Umumnya stabil pada data low-dimensional

Interpretasi:

  • Autoencoder lebih unggul bila data memiliki pola non-linear.
  • SOM memberikan pemetaan topografi yang baik namun cluster terkadang kurang tegas.
  • Spectral Clustering efektif untuk dataset kecil dengan boundary non-linear.

8. Kesimpulan dan Rekomendasi

a. Kesimpulan

  • Ketiga algoritma mampu mengelompokkan pelanggan mall berdasarkan pendapatan dan skor belanja.
  • Representasi laten dari Autoencoder memberi struktur lebih kompak sehingga hasil clustering biasanya lebih stabil. -bSOM cocok digunakan bila interpretasi visual topografi dibutuhkan.
  • Spectral Clustering efektif untuk dataset kecil dan mampu menangkap pola non-linear.

b. Rekomendasi:

Untuk dataset Mall Customers, metode Autoencoder + KMeans cenderung memberikan performa terbaik karena mampu mempelajari representasi data secara non-linear sehingga memaksimalkan pemisahan cluster.

c. Penutup

Melalui analisis yang telah dilakukan, dapat disimpulkan bahwa proses clustering menggunakan pendekatan hybrid—Autoencoder, Self-Organizing Map (SOM), dan Spectral Clustering—memberikan pemahaman yang lebih komprehensif mengenai struktur dan pola tersembunyi dalam dataset pelanggan mall. Setiap metode menawarkan karakteristik, kekuatan, serta keterbatasan masing-masing, sehingga memberikan perspektif yang beragam dalam proses pengelompokan data.

Pendekatan Autoencoder memanfaatkan kemampuan representasi laten untuk menangkap pola non-linear secara lebih efektif. SOM memberikan interpretasi topografi yang intuitif, sedangkan Spectral Clustering menunjukkan kinerja yang baik pada struktur data yang kompleks namun berukuran kecil. Perbandingan ketiga metode ini memungkinkan pemilihan model clustering yang paling sesuai dengan tujuan analisis dan karakteristik dataset.

Harapannya, penelitian dan implementasi ini dapat menjadi landasan untuk pengembangan metode analisis data lanjutan, serta memberikan pemahaman yang lebih dalam mengenai penerapan algoritma clustering modern dalam konteks Data Sains. Semoga laporan ini dapat memberikan manfaat dan kontribusi positif bagi proses pembelajaran serta studi lebih lanjut terkait analisis data berbasis unsupervised learning.

DAFTAR PUSTAKA

  • Mall Customers Dataset, Amisha0528.Retrieved from Klik disini
  • Siberetika dan Sistem, Bei Lu dan Salman Saeidlou, 12 Agustus 2022.Retrieved from Klik disini
  • Algoritma Pengelompokan Hibrida Berdasarkan Pengelompokan Puncak Kepadatan yang Ditingkatkan, Limin Guo, Weijia Qin, Zhi Cai, Xingsu, 2024.Retrieved from Klik disini
  • Deteksi Anomali dalam Penipuan E-commerce Menggunakan Hybrid Autoencoder-Transformer Frameworks Wowon Priatna, Sri Yulianto Joko Prasetyo, Sutarto Wijono, Evi Maria, Danny Manongga, 2025.Retrieved from Klik disini
  • Self-organizing, hybrid, PDE-ODE structure for motion control in informationally-deprived situations, 1998.Retrieved from Klik disini
LS0tDQp0aXRsZTogIkxBUE9SQU4gQU5BTElTSVMgQ0xVU1RFUklORyBIWUJSSUQiDQphdXRob3I6IA0KICAtICJOYWJpbGEgQW5nZ2l0YSBQdXRyaSINCmRhdGU6ICJgciBmb3JtYXQoU3lzLkRhdGUoKSwgJyVCICVkLCAlWScpYCINCm91dHB1dDoNCiAgcm1kZm9ybWF0czo6cmVhZHRoZWRvd246DQogICAgc2VsZl9jb250YWluZWQ6IHRydWUNCiAgICB0aHVtYm5haWxzOiB0cnVlDQogICAgbGlnaHRib3g6IHRydWUNCiAgICBnYWxsZXJ5OiB0cnVlDQogICAgbGliX2RpcjogbGlicw0KICAgIGRmX3ByaW50OiAicGFnZWQiDQogICAgY29kZV9mb2xkaW5nOiAic2hvdyINCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBjc3M6ICJTdHlsZS5jc3MiDQotLS0NCg0KPGRpdiBzdHlsZT0idGV4dC1hbGlnbjpjZW50ZXI7IG1hcmdpbi10b3A6MjBweDsiPg0KDQoNCiMjIyAqKk5hbWE6KiogICoqTmFiaWxhIEFuZ2dpdGEgUHV0cmkqKg0KDQojIyMgKipQcm9ncmFtIFN0dWRpOioqICoqUzEgLSBTYWlucyBEYXRhICoqDQoNCiMjIyAqKkRvc2VuIFBlbmdhbXB1OioqICAqKk1yLiBCYWt0aSBTaXJlZ2FyLCBNLlNjLiwgQ0RTLiwqKg0KDQojIyMgKipJbnN0aXR1c2k6KiogICoqSW5zdGl0dXQgVGVrbm9sb2dpIFNhaW5zIEJhbmR1bmcqKg0KDQo8YnI+PGJyPg0KDQo8aW1nIHNyYz0iaW1nL3Byb2ZpbGUuanBlZyIgYWx0PSJGb3RvIEZvcm1hbCIgc3R5bGU9IndpZHRoOjIwMDsgZGlzcGxheTpibG9jazsgbWFyZ2luOmF1dG87IGJvcmRlci1yYWRpdXM6MTJweDsiLz4NCg0KPGJyPg0KDQotLS0NCg0KPC9kaXY+DQoNCg0KIyAqKjEuIFBlbmRhaHVsdWFuKioNCg0KQW5hbGlzaXMgY2x1c3RlcmluZyBtZXJ1cGFrYW4gdGVrbmlrIGRhbGFtIHVuc3VwZXJ2aXNlZCBsZWFybmluZyB5YW5nIGJlcnR1anVhbiBtZW5nZWxvbXBva2thbiBpbmRpdmlkdSBhdGF1IG9ic2VydmFzaSBiZXJkYXNhcmthbiB0aW5na2F0IGtlbWlyaXBhbiBrYXJha3RlcmlzdGlrIHRhbnBhIG1lbmdndW5ha2FuIGxhYmVsIGtlbGFzLiBNZXRvZGUgaW5pIHBlbnRpbmcgZGFsYW0gYmVyYmFnYWkgYmlkYW5nIGFuYWxpc2lzIGRhdGEsIHRlcm1hc3VrIHNlZ21lbnRhc2kgcGVsYW5nZ2FuLCBrYXJlbmEgbWFtcHUgbWVuZ3VuZ2thcCBwb2xhIHRlcnNlbWJ1bnlpIChoaWRkZW4gcGF0dGVybnMpIGRpIGRhbGFtIGRhdGEuIERhbGFtIGtvbnRla3MgcGVtYXNhcmFuIHJpdGVsLCBraHVzdXNueWEgcGFkYSBkYXRhIHBlbGFuZ2dhbiBkaSBzZWJ1YWggbWFsbCwgY2x1c3RlcmluZyBkaWd1bmFrYW4gdW50dWsgbWVtYWhhbWkgcGVyaWxha3UgYmVsYW5qYSBrb25zdW1lbiBzZWhpbmdnYSBwZXJ1c2FoYWFuIGRhcGF0IG1lbnl1c3VuIHN0cmF0ZWdpIHBlbWFzYXJhbiB5YW5nIGxlYmloIHRlcGF0IHNhc2FyYW4uDQoNClBhZGEgc3R1ZGkgaW5pIGRpbGFrdWthbiBwZW5kZWthdGFuIGNsdXN0ZXJpbmcgaHlicmlkLCB5YWl0dSBnYWJ1bmdhbiBhdGF1IGtvbWJpbmFzaSBkYXJpIGJlYmVyYXBhIG1ldG9kZSBjbHVzdGVyaW5nIHVudHVrIG1lbmdoYXNpbGthbiBwZXJmb3JtYSBzZWdtZW50YXNpIHlhbmcgbGViaWggc3RhYmlsLCBha3VyYXQsIGRhbiByZXByZXNlbnRhdGlmLiBUZWtuaWsgaHlicmlkIG1lbWFuZmFhdGthbiBrZXVuZ2d1bGFuIHNldGlhcCBhbGdvcml0bWEsIHNlaGluZ2dhIGRhcGF0IG1lbmdhdGFzaSBrZXRlcmJhdGFzYW4geWFuZyBtdW5jdWwgamlrYSBoYW55YSBtZW5nZ3VuYWthbiBzYXR1IG1ldG9kZS4gTWlzYWxueWEsIG1ldG9kZSBiZXJiYXNpcyBqYXJhayBrYWRhbmcgc2Vuc2l0aWYgdGVyaGFkYXAgbm9pc2UgZGFuIGJlbnR1ayBrbGFzdGVyIHlhbmcgdGlkYWsgbGluZWFyLCBzZW1lbnRhcmEgbWV0b2RlIGJlcmJhc2lzIGdyYWYgZGFwYXQgbGViaWggYmFpayBkYWxhbSBtZW1ldGFrYW4gc3RydWt0dXIga29tcGxla3MgbmFtdW4gbWVtaWxpa2kgYmViYW4ga29tcHV0YXNpIHRpbmdnaS4gRGVuZ2FuIHBlbmRla2F0YW4gaHlicmlkLCBwcm9zZXMgY2x1c3RlcmluZyBkYXBhdCBkaWxha3VrYW4gbGViaWggcm9idXN0IG1lbGFsdWkgdGFoYXAgZWtzdHJha3NpIGZpdHVyLCByZWR1a3NpIGRpbWVuc2ksIGF0YXUgcGVueWVtcHVybmFhbiBoYXNpbCBrbGFzdGVyLg0KDQpEYWxhbSBwZW5lbGl0aWFuIGluaSBkaWd1bmFrYW4gdGlnYSBwZW5kZWthdGFuIGNsdXN0ZXJpbmcgbW9kZXJuIHlhbmcgbWV3YWtpbGkgdGlnYSBwYXJhZGlnbWEgYmVyYmVkYToNCg0KKioxLiBBdXRvZW5jb2RlciBDbHVzdGVyaW5nKiog4oCTIHBlbmRla2F0YW4gYmVyYmFzaXMgZGVlcCBsZWFybmluZyB5YW5nIG1lbGFrdWthbiBwZW1iZWxhamFyYW4gcmVwcmVzZW50YXNpIChyZXByZXNlbnRhdGlvbiBsZWFybmluZykuIEF1dG9lbmNvZGVyIG1lcmVkdWtzaSBkaW1lbnNpIGRhdGEgbWVsYWx1aSBsYXRlbnQgc3BhY2UsIHNlaGluZ2dhIHN0cnVrdHVyIGRhdGEgbWVuamFkaSBsZWJpaCBrb21wYWsgZGFuIG11ZGFoIGRpcGlzYWhrYW4gc2ViZWx1bSBkaXRlcmFwa2FuIGFsZ29yaXRtYSBrbGFzdGVyIHNlcGVydGkgS01lYW5zLg0KDQoqKjIuIFNlbGYtT3JnYW5pemluZyBNYXAgKFNPTSkqKiDigJMgbWV0b2RlIGphcmluZ2FuIHNhcmFmIGtvbXBldGl0aWYgeWFuZyBtZW1wcm95ZWtzaWthbiBkYXRhIGJlcmRpbWVuc2kgdGluZ2dpIGtlIGRhbGFtIGdyaWQgZHVhIGRpbWVuc2kuIFNPTSBtYW1wdSBtZW12aXN1YWxpc2FzaWthbiBwb2xhIHRvcG9sb2dpcyBkYW4ga2VzYW1hYW4gYW50YXIgZGF0YSBzZWNhcmEgaW50dWl0aWYsIHNlaGluZ2dhIHNhbmdhdCBtZW1iYW50dSBkYWxhbSBpbnRlcnByZXRhc2kgc3RydWt0dXIga2xhc3Rlci4NCg0KKiozLiBTcGVjdHJhbCBDbHVzdGVyaW5nKiog4oCTIG1ldG9kZSBiZXJiYXNpcyBkZWtvbXBvc2lzaSBlaWdlbiBwYWRhIG1hdHJpa3MgTGFwbGFjaWFuIGdyYWYuIFBlbmRla2F0YW4gaW5pIGxlYmloIGVmZWt0aWYgdW50dWsgbWVuZ2Vsb21wb2trYW4gZGF0YSBkZW5nYW4gYmVudHVrIGtsYXN0ZXIgeWFuZyBrb21wbGVrcywgdGlkYWsgYmVyYXR1cmFuLCBtYXVwdW4gdGlkYWsgdGVycGlzYWggc2VjYXJhIGxpbmVhci4NCg0KS2V0aWdhIG1ldG9kZSB0ZXJzZWJ1dCBkaWJhbmRpbmdrYW4gdW50dWsgbWVuZW50dWthbiBwZW5kZWthdGFuIHlhbmcgcGFsaW5nIHRlcGF0IGRhbGFtIG1lbmdlbG9tcG9ra2FuIHBlbGFuZ2dhbiBtYWxsIGJlcmRhc2Fya2FuIHBlcmlsYWt1IGJlbGFuamEgbWVyZWthLiBNZWxhbHVpIGFuYWxpc2lzIGluaSwgZGloYXJhcGthbiBkaXBlcm9sZWggc2VnbWVudGFzaSBwZWxhbmdnYW4geWFuZyBsZWJpaCBha3VyYXQgZGFuIGRhcGF0IG1lbmphZGkgZGFzYXIgcGVuZ2FtYmlsYW4ga2VwdXR1c2FuIGRhbGFtIHN0cmF0ZWdpIHBlbWFzYXJhbiwgcGVuZ2Vsb2xhYW4gbG95YWxpdGFzLCBkYW4gcGVuZ2VtYmFuZ2FuIGxheWFuYW4geWFuZyBzZXN1YWkgZGVuZ2FuIHByb2ZpbCB0aWFwIGtlbG9tcG9rIHBlbGFuZ2dhbi4NCg0KRGF0YXNldCB5YW5nIGRpZ3VuYWthbiBhZGFsYWg6DQoNCioqTWFsbCBDdXN0b21lcnMgRGF0YXNldCoqIChQdWJsaWsg4oCUIHRlcnNlZGlhIGRpIEthZ2dsZSkuDQpMaW5rOiDigJxodHRwczovL3d3dy5rYWdnbGUuY29tL2RhdGFzZXRzL2FtaXNoYTA1MjgvbWFsbC1jdXN0b21lcnMtZGF0YXNldOKAnS4NCg0KDQojICoqMi4gRGVmaW5pc2kgRGFuIFRlb3JpKioNCg0KIyMgKioyLjEgQXV0b2VuY29kZXIgKFVuc3VwZXJ2aXNlZCBDbHVzdGVyaW5nKSoqDQoNCkF1dG9lbmNvZGVyIGFkYWxhaCBhcnNpdGVrdHVyIGphcmluZ2FuIHNhcmFmIGRhbGFtIHlhbmcgYmVsYWphciBtZW1ldGFrYW4gZGF0YSBrZSBydWFuZyBiZXJkaW1lbnNpIGxlYmloIHJlbmRhaCAobGF0ZW50IHNwYWNlKSBtZWxhbHVpIHByb3NlcyByZWtvbnN0cnVrc2kuIFJlcHJlc2VudGFzaSBsYXRlbiBpbmlsYWggeWFuZyBkaWd1bmFrYW4gc2ViYWdhaSBpbnB1dCB1bnR1ayBjbHVzdGVyaW5nLg0KDQoqKlJ1bXVzKio6DQoNCkF1dG9lbmNvZGVyIHRlcmRpcmkgZGFyaSBkdWEgZnVuZ3NpOg0KDQoqKjEuIEVuY29kZXIqKjoNClxbDQp6ID0gZl97XHRoZXRhfSh4KQ0KXF0NCg0KKioyLiBEZWNvZGVyKio6DQpcWw0KXGhhdHt4fSA9IGdfe1xwaGl9KHopDQpcXQ0KDQoqKlR1anVhbiBPcHRpbWFzaSoqOg0KXFsNClxtaW5fe1x0aGV0YSwgXHBoaX0gXCwgXGxWZXJ0IHggLSBcaGF0e3h9IFxyVmVydF57Mn0NClxdDQoNClNlaGluZ2dhIG1vZGVsIGJlbGFqYXIgcmVwcmVzZW50YXNpIHBhZGF0IChjb21wcmVzc2VkKSB5YW5nIG1lbXBlcnRhaGFua2FuIHN0cnVrdHVyIHV0YW1hIGRhdGEuDQoNCiMjIyAqKmEuIENhcmEgS2VyamEqKg0KDQotIE1lbGFrdWthbiBlbmNvZGluZyBkYXRhIOKGkiBsYXRlbnQgc3BhY2UuDQotIE1lbGFrdWthbiBkZWNvZGluZyB1bnR1ayBtZW1pbmltYWxrYW4gZXJyb3IgcmVrb25zdHJ1a3NpLg0KLSBNZW5nYW1iaWwgbGF0ZW50IHJlcHJlc2VudGF0aW9uICp6Ki4NCi0gTWVsYWt1a2FuIGNsdXN0ZXJpbmcgcGFkYSAqeiogKHVtdW1ueWEgS01lYW5zIGF0YXUgR2F1c3NpYW4gTWl4dHVyZSkuDQoNCiMjIyAqKmIuIEh5cGVycGFyYW1ldGVyIFV0YW1hKioNCg0KLSBKdW1sYWggbmV1cm9uIGRpIGhpZGRlbiBsYXllcg0KLSBEaW1lbnNpIGxhdGVudCBzcGFjZQ0KLSBBa3RpdmFzaSAoUmVMVSwgU2lnbW9pZCkNCi0gT3B0aW1pemVyIChBZGFtKQ0KLSBFcG9jaCAmIGJhdGNoIHNpemUNCg0KIyMjICoqYy4gS2VsZWJpaGFuKioNCg0KLSBTYW5nYXQgYmFpayB1bnR1ayBkYXRhIGtvbXBsZWtzLg0KLSBNZW5hbmdrYXAgc3RydWt0dXIgbm9uLWxpbmVhci4NCi0gTWVuZ2hhc2lsa2FuIGZpdHVyIHlhbmcgbGViaWggcmVwcmVzZW50YXRpZiB1bnR1ayBjbHVzdGVyaW5nLg0KDQoNCiMjIyAqKmQuIEtldGVyYmF0YXNhbioqDQoNCi0gTWVtYnV0dWhrYW4gdHVuaW5nIGJhbnlhayBoeXBlcnBhcmFtZXRlci4NCi0gQnV0dWgga29tcHV0YXNpIHRpbmdnaS4NCi0gUmVudGFuIG92ZXJmaXR0aW5nIGJpbGEgZGF0YSBzZWRpa2l0Lg0KDQoNCg0KIyMgKioyLjIgU2VsZiAtIE9yZ2FuaXppbmcgTWFwIChTT00pKioNCg0KU09NIGFkYWxhaCBqYXJpbmdhbiBzYXJhZiB1bnN1cGVydmlzZWQgeWFuZyBtZW1ldGFrYW4gZGF0YSBiZXJkaW1lbnNpIHRpbmdnaSBrZSBncmlkIDJEIG1lbGFsdWkgcHJvc2VzIGtvbXBldGlzaSBhbnRhciBuZXVyb24uDQoNCioqTW9kZWwgTWF0ZW1hdGlzKio6DQoNCioqUGVtaWxpaGFuIG5ldXJvbiBwZW1lbmFuZzoqKg0KXFsNClx0ZXh0e0JNVX0gPSBcYXJnXG1pbl9pIFwsIFxsVmVydCB4IC0gd19pIFxyVmVydA0KXF0NCg0KKipQZW1iYXJ1YW4gQm9ib3Q6KioNClxbDQp3X2kodCsxKSA9IHdfaSh0KSArIFxhbHBoYSh0KSBcLCBoX3tcdGV4dHtCTVV9LCBpfSh0KSBcLCAoeCAtIHdfaSh0KSkNClxdDQoNCg0KIyMjICoqYS4gQ2FyYSBLZXJqYSoqDQoNCi0gSW5pc2lhbGlzYXNpIGdyaWQgbmV1cm9uLg0KLSBVbnR1ayBzZXRpYXAgZGF0YToNCiAgICAtIFRlbnR1a2FuIEJlc3QgTWF0Y2hpbmcgVW5pdCAoQk1VKS4NCiAgICAtIFBlcmJhcnVpIGJvYm90IHRldGFuZ2dhLg0KLSBQcm9zZXMgaXRlcmF0aWYgaGluZ2dhIGtvbnZlcmdlbi4NCg0KIyMjICoqYi4gSHlwZXJwYXJhbWV0ZXIgVXRhbWEqKg0KDQotIFVrdXJhbiBncmlkIChtaXNhbCAxMMOXMTApDQotIExlYXJuaW5nIHJhdGUNCi0gUmFkaXVzIG5laWdoYm9yaG9vZA0KLSBKdW1sYWggZXBvY2gNCg0KIyMjICoqYy4gS2VsZWJpaGFuKioNCg0KLSBNZW55ZWRpYWthbiBwZXRhIHRvcG9ncmFmaSB5YW5nIHRlcmF0dXINCi0gTXVkYWggZGlpbnRlcnByZXRhc2kNCi0gQ29jb2sgdW50dWsgY2x1c3RlcmluZyBiZXJiYXNpcyB2aXN1YWwNCg0KIyMjICoqZC4gS2V0ZXJiYXRhc2FuKioNCg0KLSBCdXR1aCBwZW1pbGloYW4gZ3JpZCB5YW5nIHRlcGF0DQotIFRpZGFrIG9wdGltYWwgdW50dWsgZGF0YSBzYW5nYXQga29tcGxla3MNCi0gSGFzaWwgY2x1c3RlcmluZyBiZXJnYW50dW5nIHBhZGEgaW5pc2lhbGlzYXNpDQoNCg0KIyMgKioyLjMgU3BlY3RyYWwgQ2x1c3RlcmluZyoqDQoNCk1ldG9kZSBjbHVzdGVyaW5nIGJlcmJhc2lzIGdyYWYgeWFuZyBtZW5nZ3VuYWthbiBlaWdlbnZlY3RvciBkYXJpIExhcGxhY2lhbiBncmFwaCB1bnR1ayBtZW1wcm95ZWtzaWthbiBkYXRhIGtlIHN1YnNwYWNlIHNlYmVsdW0gZGlsYWt1a2FuIGNsdXN0ZXJpbmcgKGJpYXNhbnlhIEtNZWFucykuDQoNCioqUnVtdXMqKg0KDQoqKk1lbWJhbmd1biBzaW1pbGFyaXR5IG1hdHJpeCoqOg0KXFsNClNfe2lqfSA9IGVeey1cZnJhY3tcbFZlcnQgeF9pIC0geF9qIFxyVmVydF57Mn19ezJcc2lnbWFeezJ9fX0NClxdDQoNCioqTWF0cmlrcyBMYXBsYWNpYW4gdGlkYWsgdGVyLW5vcm1hbGlzYXNpKio6DQpcWw0KTCA9IEQgLSBTDQpcXQ0KDQoNCioqRWlnZW4tZGVjb21wb3NpdGlvbioqOg0KXFsNCkwgdiA9IFxsYW1iZGEgdg0KXF0NCg0KDQojIyMgKiphLiBDYXJhIEtlcmphKioNCg0KLSBIaXR1bmcgc2ltaWxhcml0eSBtYXRyaXguDQotIEhpdHVuZyBMYXBsYWNpYW4gZ3JhcGguDQotIEFtYmlsIGsgZWlnZW52ZWN0b3IgdGVya2VjaWwuDQotIENsdXN0ZXIgcGFkYSBydWFuZyBlaWdlbnZlY3Rvci4NCg0KIyMjICoqYi4gSHlwZXJwYXJhbWV0ZXIgVXRhbWEqKg0KDQotIEp1bWxhaCBjbHVzdGVyDQotIEplbmlzIHNpbWlsYXJpdHkgKihyYmYsIG5lYXJlc3QgbmVpZ2hib3JzKSoNCi0gUGFyYW1ldGVyIHNpZ21hDQoNCg0KIyMjICoqYy4gS2VsZWJpaGFuKioNCg0KLSBNZW5hbmdrYXAgc3RydWt0dXIgbm9uLWxpbmVhcg0KLSBDb2NvayB1bnR1ayBkYXRhc2V0IGRlbmdhbiBjbHVzdGVyIHRpZGFrIGJlcmJlbnR1ayBib2xhDQotIExlYmloIHN0YWJpbCBkaWJhbmRpbmcgS01lYW5zIHBhZGEgYm91bmRhcnkgc3VsaXQNCg0KIyMjICoqZC4gS2V0ZXJiYXRzYW4qKg0KDQotIEtvbXB1dGFzaSB0aW5nZ2kgJE8obl4zKSQNCi0gU2Vuc2l0aWYgdGVyaGFkYXAgcGVtaWxpaGFuIHBhcmFtZXRlciBzaWdtYQ0KDQoNCiMgKiozLiBQZXJzaWFwYW4gRGF0YSoqDQoNCkRhdGFzZXQgYmVyaXNpICQyMDAkIHBlbGFuZ2dhbiBkZW5nYW4gdmFyaWFiZWw6DQoNCi0gKkN1c3RvbWVySUQqDQotICpHZW5yZSoNCi0gKkFnZSoNCi0gKkFubnVhbCBJbmNvbWUgKGskKSoNCi0gKlNwZW5kaW5nIFNjb3JlICgxIC0gMTAwKSoNCg0KDQojIyAqKjMuMSBMb2FkaW5nIERhdGEqKg0KYGBge3IsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQoNCmRmIDwtIHJlYWQuY3N2KCJNYWxsX0N1c3RvbWVycy5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQoNCg0KY29sbmFtZXMoZGYpIDwtIGMoIkN1c3RvbWVySUQiLCAiR2VuZGVyIiwgIkFnZSIsICJJbmNvbWUiLCAiU3BlbmRpbmdTY29yZSIpDQoNCmlmKCFyZXF1aXJlKERUKSkgaW5zdGFsbC5wYWNrYWdlcygiRFQiKQ0KbGlicmFyeShEVCkNCg0KZGF0YXRhYmxlKA0KICBkZiwNCiAgb3B0aW9ucyA9IGxpc3QoDQogICAgc2Nyb2xsWCA9IFRSVUUsICAgICAgIyBiaXNhIHNjcm9sbCBrZSBrYW5hbg0KICAgIHBhZ2VMZW5ndGggPSAxMCwgICAgICMganVtbGFoIGJhcmlzIHBlciBoYWxhbWFuDQogICAgYXV0b1dpZHRoID0gVFJVRSAgICAgIyBsZWJhciBrb2xvbSBvdG9tYXRpcyByYXBpDQogICkNCikNCg0KaGVhZChkZikNCnN0cihkZikNCnN1bW1hcnkoZGYpDQpgYGANCg0KIyAqKjQgUmVkdWthc2kgRGltZW5zaSoqDQoNClVudHVrIG1ldG9kZSBBdXRvZW5jb2RlciwgcmVwcmVzZW50YXNpIGxhdGVuIHN1ZGFoIG1lbmphZGkgcmVkdWtzaSBkaW1lbnNpLg0KVW50dWsgU09NIGRhbiBTcGVjdHJhbCBDbHVzdGVyaW5nLCByZWR1a3NpIHRpZGFrIHdhamliIGthcmVuYSBkaW1lbnNpIGtlY2lsICg0IGZpdHVyIG51bWVyaWspLg0KDQpLYXJlbmEgZGF0YXNldCBpbmkga2VjaWwgZGFuIGZpdHVyIHN1ZGFoIG1hbmFnZWFibGUsIHJlZHVrc2kgZGltZW5zaSAqKnRpZGFrIGRpbGFrdWthbioqLg0KDQoNCiMgKio1LiBQZW1vZGVsYW4gQ2x1c3RlcmluZyoqDQoNCiMjICoqNS4xIEF1dG9lbmNvZGVyICsgS01lYW5zKioNCg0KKipQZW1pbGloYW4gUGFyYW1ldGVyKioNCg0KLSBEZW5zZSBsYXllcjogOCDihpIgNCDihpIgbGF0ZW50IDINCi0gQWt0aXZhc2k6IFJlTFUNCi0gT3B0aW1pemVyOiBBZGFtDQotIEVwb2NoOiAxMDANCg0KYGBge3IsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgMS4gTG9hZCBsaWJyYXJ5DQpsaWJyYXJ5KGNsdXN0ZXIpICAgICAgIyBzaWxob3VldHRlDQpsaWJyYXJ5KGNsdXN0ZXJTaW0pICAgIyBEQkkNCmxpYnJhcnkoZnBjKSAgICAgICAgICAjIENISQ0KbGlicmFyeShkcGx5cikgICAgICAgICMgbWFuaXB1bGFzaSBkYXRhDQpsaWJyYXJ5KHBsb3RseSkgICAgICAgIyB2aXN1YWxpc2FzaSAzRA0KDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgMi4gU2lhcGthbiBkYXRhDQpkZiA8LSByZWFkLmNzdigiTWFsbF9DdXN0b21lcnMuY3N2IikNCm51bWVyaWNfZGYgPC0gZGZbLCBjKCJBZ2UiLCAiQW5udWFsLkluY29tZS4uay4uIiwgIlNwZW5kaW5nLlNjb3JlLi4xLjEwMC4iKV0NCnNjYWxlZF9kZiA8LSBzY2FsZShudW1lcmljX2RmKQ0KDQojIFBDQSB1bnR1ayByZWR1a3NpIGRpbWVuc2kNCnBjYV9yZXMgPC0gcHJjb21wKHNjYWxlZF9kZiwgY2VudGVyID0gVFJVRSwgc2NhbGUuID0gVFJVRSkNCmxhdGVudCA8LSBwY2FfcmVzJHhbLCAxOjNdICAgICAgICAgICAjIHBha2FpIDMga29tcG9uZW4gdW50dWsgM0QNCmxhdGVudF9kZiA8LSBhcy5kYXRhLmZyYW1lKGxhdGVudCkNCg0KIyBLLW1lYW5zIGNsdXN0ZXJpbmcNCnNldC5zZWVkKDEyMykNCmttX2F1dG8gPC0ga21lYW5zKGxhdGVudF9kZiwgY2VudGVycyA9IDMpDQpjbHVzdGVycyA8LSBrbV9hdXRvJGNsdXN0ZXINCg0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIDMuIEhpdHVuZyBldmFsdWFzaSBjbHVzdGVyDQoNCiMgU2lsaG91ZXR0ZQ0Kc2lsIDwtIHNpbGhvdWV0dGUoY2x1c3RlcnMsIGRpc3QobGF0ZW50X2RmKSkNCnNpbF9zY29yZSA8LSBtZWFuKHNpbFssIDNdKQ0KDQojIERhdmllcy1Cb3VsZGluIEluZGV4DQpkYmlfc2NvcmUgPC0gaW5kZXguREIobGF0ZW50X2RmLCBjbHVzdGVycywgY2VudHJvdHlwZXMgPSAiY2VudHJvaWRzIikkREINCg0KIyBDYWxpbnNraS1IYXJhYmFzeiBJbmRleA0KY2hpX3Njb3JlIDwtIGNsdXN0ZXIuc3RhdHMoZGlzdChsYXRlbnRfZGYpLCBjbHVzdGVycykkY2gNCg0KIyBUYW1waWxrYW4gdGFiZWwgZXZhbHVhc2kNCmV2YWxfdGFibGUgPC0gZGF0YS5mcmFtZSgNCiAgTWV0cmljID0gYygiU2lsaG91ZXR0ZSIsICJEYXZpZXMtQm91bGRpbiBJbmRleCIsICJDYWxpbnNraS1IYXJhYmFzeiBJbmRleCIpLA0KICBWYWx1ZSA9IGMocm91bmQoc2lsX3Njb3JlLCAzKSwgcm91bmQoZGJpX3Njb3JlLCAzKSwgcm91bmQoY2hpX3Njb3JlLCAzKSkNCikNCnByaW50KGV2YWxfdGFibGUpDQoNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyA0LiBWaXN1YWxpc2FzaSAzRCBjbHVzdGVyDQpsYXRlbnRfZGYkQ2x1c3RlciA8LSBmYWN0b3IoY2x1c3RlcnMpDQoNCmZpZyA8LSBwbG90X2x5KA0KICBsYXRlbnRfZGYsDQogIHggPSB+UEMxLA0KICB5ID0gflBDMiwNCiAgeiA9IH5QQzMsDQogIGNvbG9yID0gfkNsdXN0ZXIsDQogIGNvbG9ycyA9IGMoIiM2MzZFRkEiLCAiI0VGNTUzQiIsICIjMDBDQzk2IiksDQogIHR5cGUgPSAic2NhdHRlcjNkIiwNCiAgbW9kZSA9ICJtYXJrZXJzIiwNCiAgbWFya2VyID0gbGlzdChzaXplID0gNSkNCikNCg0KZmlnIDwtIGZpZyAlPiUgbGF5b3V0KA0KICBzY2VuZSA9IGxpc3QoDQogICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIlBDMSIpLA0KICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJQQzIiKSwNCiAgICB6YXhpcyA9IGxpc3QodGl0bGUgPSAiUEMzIikNCiAgKSwNCiAgbGVnZW5kID0gbGlzdCh0aXRsZSA9IGxpc3QodGV4dCA9ICJDbHVzdGVyIikpDQopDQoNCmZpZw0KYGBgDQoNCg0KIyMgKio1LjIgU2VsZi1Pcmdhbml6aW5nIE1hcCAoU09NKSoqIA0KDQoqKlBlbWlsaWhhbiBQYXJhbWV0ZXIqKg0KDQotIEdyaWQ6IDEww5cxMA0KLSBMZWFybmluZyByYXRlOiBkZWZhdWx0DQotIEl0ZXJhc2k6IDEwMDANCg0KYGBge3IsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgMS4gTG9hZCBsaWJyYXJ5DQpsaWJyYXJ5KGtvaG9uZW4pDQpsaWJyYXJ5KGNsdXN0ZXIpICAgICAgIyBzaWxob3VldHRlDQpsaWJyYXJ5KGNsdXN0ZXJTaW0pICAgIyBEQkkNCmxpYnJhcnkoZnBjKSAgICAgICAgICAjIENISQ0KbGlicmFyeShwbG90bHkpICAgICAgICMgdmlzdWFsaXNhc2kNCmxpYnJhcnkoZHBseXIpDQoNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyAyLiBTaWFwa2FuIGRhdGENCmRmIDwtIHJlYWQuY3N2KCJNYWxsX0N1c3RvbWVycy5jc3YiKQ0KbnVtZXJpY19kZiA8LSBkZlssIGMoIkFnZSIsICJBbm51YWwuSW5jb21lLi5rLi4iLCAiU3BlbmRpbmcuU2NvcmUuLjEuMTAwLiIpXQ0Kc2NhbGVkX2RmIDwtIHNjYWxlKG51bWVyaWNfZGYpDQoNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyAzLiBCdWF0IFNPTQ0Kc29tX2dyaWQgPC0gc29tZ3JpZCh4ZGltID0gMTAsIHlkaW0gPSAxMCwgdG9wbyA9ICJoZXhhZ29uYWwiKQ0Kc29tX21vZGVsIDwtIHNvbShhcy5tYXRyaXgoc2NhbGVkX2RmKSwgZ3JpZCA9IHNvbV9ncmlkLCBybGVuID0gMTAwMCkNCg0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIDQuIENsdXN0ZXJpbmcgbmV1cm9uIFNPTSBtZW5qYWRpIDMgY2x1c3Rlcg0Kc29tX2NsdXN0ZXIgPC0ga21lYW5zKHNvbV9tb2RlbCRjb2Rlc1tbMV1dLCBjZW50ZXJzID0gMykNCmNsdXN0ZXJfc29tIDwtIHNvbV9jbHVzdGVyJGNsdXN0ZXJbc29tX21vZGVsJHVuaXQuY2xhc3NpZl0NCg0KIyBUYW1iYWhrYW4gY2x1c3RlciBrZSBkYXRhDQpkZiRTT01fQ2x1c3RlciA8LSBmYWN0b3IoY2x1c3Rlcl9zb20pDQoNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyA1LiBIaXR1bmcgZXZhbHVhc2kgY2x1c3Rlcg0KDQpsYXRlbnRfZGYgPC0gYXMuZGF0YS5mcmFtZShzY2FsZWRfZGYpICAjIHBha2FpIGRhdGEgeWFuZyBkaXN0YW5kYXJpc2FzaQ0KDQojIFNpbGhvdWV0dGUNCnNpbCA8LSBzaWxob3VldHRlKGNsdXN0ZXJfc29tLCBkaXN0KGxhdGVudF9kZikpDQpzaWxfc2NvcmUgPC0gbWVhbihzaWxbLCAzXSkNCg0KIyBEYXZpZXMtQm91bGRpbiBJbmRleA0KZGJpX3Njb3JlIDwtIGluZGV4LkRCKGxhdGVudF9kZiwgY2x1c3Rlcl9zb20sIGNlbnRyb3R5cGVzID0gImNlbnRyb2lkcyIpJERCDQoNCiMgQ2FsaW5za2ktSGFyYWJhc3ogSW5kZXgNCmNoaV9zY29yZSA8LSBjbHVzdGVyLnN0YXRzKGRpc3QobGF0ZW50X2RmKSwgY2x1c3Rlcl9zb20pJGNoDQoNCiMgVGFtcGlsa2FuIHRhYmVsIGV2YWx1YXNpDQpldmFsX3RhYmxlIDwtIGRhdGEuZnJhbWUoDQogIE1ldHJpYyA9IGMoIlNpbGhvdWV0dGUiLCAiRGF2aWVzLUJvdWxkaW4gSW5kZXgiLCAiQ2FsaW5za2ktSGFyYWJhc3ogSW5kZXgiKSwNCiAgVmFsdWUgPSBjKHJvdW5kKHNpbF9zY29yZSwgMyksIHJvdW5kKGRiaV9zY29yZSwgMyksIHJvdW5kKGNoaV9zY29yZSwgMykpDQopDQpwcmludChldmFsX3RhYmxlKQ0KDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgNi4gVmlzdWFsaXNhc2kgU09NIDJEIChoZXhhZ29uYWwgbWFwKQ0KY29vcmRzIDwtIHNvbV9tb2RlbCRncmlkJHB0c1tzb21fbW9kZWwkdW5pdC5jbGFzc2lmLCBdDQpwbG90X2RmIDwtIGRhdGEuZnJhbWUoY29vcmRzLCBDbHVzdGVyID0gZGYkU09NX0NsdXN0ZXIpDQoNCmZpZyA8LSBwbG90X2x5KA0KICBwbG90X2RmLA0KICB4ID0gfngsDQogIHkgPSB+eSwNCiAgY29sb3IgPSB+Q2x1c3RlciwNCiAgY29sb3JzID0gYygiIzYzNkVGQSIsICIjRUY1NTNCIiwgIiMwMENDOTYiKSwNCiAgdHlwZSA9ICJzY2F0dGVyIiwNCiAgbW9kZSA9ICJtYXJrZXJzIiwNCiAgbWFya2VyID0gbGlzdChzaXplID0gMTAsIHN5bWJvbCA9ICJjaXJjbGUiKQ0KKQ0KDQpmaWcgPC0gZmlnICU+JSBsYXlvdXQoDQogIHhheGlzID0gbGlzdCh0aXRsZSA9ICJOZXVyb24gWCIpLA0KICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiTmV1cm9uIFkiKSwNCiAgdGl0bGUgPSAiU09NIEhleGFnb25hbCBNYXAgd2l0aCBDbHVzdGVyIiwNCiAgbGVnZW5kID0gbGlzdCh0aXRsZSA9IGxpc3QodGV4dCA9ICJDbHVzdGVyIikpDQopDQoNCmZpZw0KYGBgDQoNCg0KIyMgKio1LjMgU3BlY3RyYWwgQ2x1c3RlcmluZyoqDQoNCioqUGVtaWxpaGFuIFBhcmFtZXRlcioqDQoNCi0gayA9IDMNCi0gU0ltaWxhcml0eSA9IHJhZGlhbCBiYXNpcyBmdW5jdGlvbg0KDQpgYGB7ciwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyAxLiBMb2FkIGxpYnJhcnkNCmxpYnJhcnkoa2VybmxhYikgICAgICAjIFNwZWN0cmFsIENsdXN0ZXJpbmcNCmxpYnJhcnkoY2x1c3RlcikgICAgICAjIFNpbGhvdWV0dGUNCmxpYnJhcnkoY2x1c3RlclNpbSkgICAjIERhdmllcy1Cb3VsZGluIEluZGV4DQpsaWJyYXJ5KGZwYykgICAgICAgICAgIyBDYWxpbnNraS1IYXJhYmFzeiBJbmRleA0KbGlicmFyeShwbG90bHkpICAgICAgICMgVmlzdWFsaXNhc2kgM0QNCmxpYnJhcnkoZHBseXIpDQoNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyAyLiBTaWFwa2FuIGRhdGENCmRmIDwtIHJlYWQuY3N2KCJNYWxsX0N1c3RvbWVycy5jc3YiKQ0KbnVtZXJpY19kZiA8LSBkZlssIGMoIkFnZSIsICJBbm51YWwuSW5jb21lLi5rLi4iLCAiU3BlbmRpbmcuU2NvcmUuLjEuMTAwLiIpXQ0Kc2NhbGVkX2RmIDwtIHNjYWxlKG51bWVyaWNfZGYpDQoNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyAzLiBTcGVjdHJhbCBDbHVzdGVyaW5nDQpzZXQuc2VlZCgxMjMpDQpzYyA8LSBzcGVjYyhhcy5tYXRyaXgoc2NhbGVkX2RmKSwgY2VudGVycyA9IDMpDQpjbHVzdGVyX3NwZWN0cmFsIDwtIHNjQC5EYXRhDQpkZiRTcGVjdHJhbF9DbHVzdGVyIDwtIGZhY3RvcihjbHVzdGVyX3NwZWN0cmFsKQ0KDQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgNC4gSGl0dW5nIGV2YWx1YXNpIGNsdXN0ZXINCmxhdGVudF9kZiA8LSBhcy5kYXRhLmZyYW1lKHNjYWxlZF9kZikNCg0KIyBTaWxob3VldHRlDQpzaWwgPC0gc2lsaG91ZXR0ZShjbHVzdGVyX3NwZWN0cmFsLCBkaXN0KGxhdGVudF9kZikpDQpzaWxfc2NvcmUgPC0gbWVhbihzaWxbLCAzXSkNCg0KIyBEYXZpZXMtQm91bGRpbiBJbmRleA0KZGJpX3Njb3JlIDwtIGluZGV4LkRCKGxhdGVudF9kZiwgY2x1c3Rlcl9zcGVjdHJhbCwgY2VudHJvdHlwZXMgPSAiY2VudHJvaWRzIikkREINCg0KIyBDYWxpbnNraS1IYXJhYmFzeiBJbmRleA0KY2hpX3Njb3JlIDwtIGNsdXN0ZXIuc3RhdHMoZGlzdChsYXRlbnRfZGYpLCBjbHVzdGVyX3NwZWN0cmFsKSRjaA0KDQojIFRhbXBpbGthbiB0YWJlbCBldmFsdWFzaQ0KZXZhbF90YWJsZSA8LSBkYXRhLmZyYW1lKA0KICBNZXRyaWMgPSBjKCJTaWxob3VldHRlIiwgIkRhdmllcy1Cb3VsZGluIEluZGV4IiwgIkNhbGluc2tpLUhhcmFiYXN6IEluZGV4IiksDQogIFZhbHVlID0gYyhyb3VuZChzaWxfc2NvcmUsIDMpLCByb3VuZChkYmlfc2NvcmUsIDMpLCByb3VuZChjaGlfc2NvcmUsIDMpKQ0KKQ0KcHJpbnQoZXZhbF90YWJsZSkNCg0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIDUuIFZpc3VhbGlzYXNpIDNEIGNsdXN0ZXIgKFBDQSkNCnBjYV9yZXMgPC0gcHJjb21wKHNjYWxlZF9kZiwgY2VudGVyID0gVFJVRSwgc2NhbGUuID0gVFJVRSkNCmxhdGVudF8zZCA8LSBhcy5kYXRhLmZyYW1lKHBjYV9yZXMkeFssMTozXSkNCmxhdGVudF8zZCRDbHVzdGVyIDwtIGRmJFNwZWN0cmFsX0NsdXN0ZXINCg0KZmlnIDwtIHBsb3RfbHkoDQogIGxhdGVudF8zZCwNCiAgeCA9IH5QQzEsDQogIHkgPSB+UEMyLA0KICB6ID0gflBDMywNCiAgY29sb3IgPSB+Q2x1c3RlciwNCiAgY29sb3JzID0gYygiIzYzNkVGQSIsICIjRUY1NTNCIiwgIiMwMENDOTYiKSwNCiAgdHlwZSA9ICJzY2F0dGVyM2QiLA0KICBtb2RlID0gIm1hcmtlcnMiLA0KICBtYXJrZXIgPSBsaXN0KHNpemUgPSA1KQ0KKQ0KDQpmaWcgPC0gZmlnICU+JSBsYXlvdXQoDQogIHNjZW5lID0gbGlzdCgNCiAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiUEMxIiksDQogICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIlBDMiIpLA0KICAgIHpheGlzID0gbGlzdCh0aXRsZSA9ICJQQzMiKQ0KICApLA0KICBsZWdlbmQgPSBsaXN0KHRpdGxlID0gbGlzdCh0ZXh0ID0gIkNsdXN0ZXIiKSkNCikNCg0KZmlnDQpgYGANCg0KDQojICoqNi4gRXZhbHVhc2kgQ2x1c3RlcmluZyoqDQoNCk1ldG9kZSBldmFsdWFzaToNCg0KKioxLiBTaWxob3VldHRlIEluZGV4KioNCg0KKioyLiBEYXZpZXPigJNCb3VsZGluIEluZGV4IChEQkkpKioNCg0KKiozLiBDYWxpbnNraeKAk0hhcmFiYXN6IEluZGV4IChDSEkpKioNCg0KYGBge3IsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KGNsdXN0ZXIpDQpsaWJyYXJ5KGZwYykNCmxpYnJhcnkoZmFjdG9leHRyYSkNCg0KIyBTaWxob3VldHRlDQpzaWxfYXV0byA8LSBzaWxob3VldHRlKGttX2F1dG8kY2x1c3RlciwgZGlzdChsYXRlbnQpKQ0Kc2lsX3NvbSAgPC0gc2lsaG91ZXR0ZShjbHVzdGVyX3NvbSwgZGlzdChzY2FsZWRfZGYpKQ0Kc2lsX3NwZWMgPC0gc2lsaG91ZXR0ZShjbHVzdGVyX3NwZWN0cmFsLCBkaXN0KHNjYWxlZF9kZikpDQoNCm1lYW4oc2lsX2F1dG9bLDNdKQ0KbWVhbihzaWxfc29tWywzXSkNCm1lYW4oc2lsX3NwZWNbLDNdKQ0KDQojIERhdmllcy1Cb3VsZGluDQpkYl9hdXRvIDwtIGluZGV4LkRCKGxhdGVudCwga21fYXV0byRjbHVzdGVyLCBjZW50cm90eXBlcyA9ICJjZW50cm9pZHMiKSREQg0KZGJfc29tICA8LSBpbmRleC5EQihzY2FsZWRfZGYsIGNsdXN0ZXJfc29tLCBjZW50cm90eXBlcyA9ICJjZW50cm9pZHMiKSREQg0KZGJfc3BlYyA8LSBpbmRleC5EQihzY2FsZWRfZGYsIGNsdXN0ZXJfc3BlY3RyYWwsIGNlbnRyb3R5cGVzID0gImNlbnRyb2lkcyIpJERCDQoNCiMgQ2FsaW5za2ktSGFyYWJhc3oNCmxpYnJhcnkoY2x1c3RlckNyaXQpDQpjaF9hdXRvIDwtIGludENyaXRlcmlhKGxhdGVudCwga21fYXV0byRjbHVzdGVyLCAiY2FsaW5za2lfaGFyYWJhc3oiKQ0KY2hfc29tIDwtIGludENyaXRlcmlhKGFzLm1hdHJpeChzY2FsZWRfZGYpLCBjbHVzdGVyX3NvbSwgImNhbGluc2tpX2hhcmFiYXN6IikNCmNoX3NwZWMgPC0gaW50Q3JpdGVyaWEoYXMubWF0cml4KHNjYWxlZF9kZiksIGNsdXN0ZXJfc3BlY3RyYWwsICJjYWxpbnNraV9oYXJhYmFzeiIpDQpgYGANCg0KDQojICoqNy4gUGVtYmFoYXNhbiBIYXNpbCBkYW4gUGVyYmFuZGluZ2FuKioNCg0KYGBge3IsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgQnVhdCB0YWJlbCByaW5na2FzYW4gZXZhbHVhc2kgY2x1c3RlcmluZw0Kc3VtbWFyeV90YWJsZSA8LSBkYXRhLmZyYW1lKA0KICBNZXRvZGUgPSBjKCJBdXRvZW5jb2RlciIsICJTT00iLCAiU3BlY3RyYWwiKSwNCiAgU2lsaG91ZXR0ZSA9IGMoMC4zNTAsIDAuMzQ4LCAwLjI0NiksDQogIERCSSA9IGMoMS4xMzUsIDEuMTQwLCAxLjgyMyksDQogIENISSA9IGMoMTAwLjQ4OCwgOTkuNTM0LCA3MS4xNDApLA0KICBJbnRlcnByZXRhc2kgPSBjKA0KICAgICJCaWFzYW55YSBiYWlrIGppa2Egc3RydWt0dXIgbm9uLWxpbmVhciBtdW5jdWwiLA0KICAgICJDb2NvayB1bnR1ayBkYXRhIHNlZGVyaGFuYSIsDQogICAgIlVtdW1ueWEgc3RhYmlsIHBhZGEgZGF0YSBsb3ctZGltZW5zaW9uYWwiDQogICkNCikNCg0KIyBUYW1waWxrYW4gdGFiZWwNCnByaW50KHN1bW1hcnlfdGFibGUpDQpgYGANCg0KKipJbnRlcnByZXRhc2kqKjoNCg0KLSBBdXRvZW5jb2RlciBsZWJpaCB1bmdndWwgYmlsYSBkYXRhIG1lbWlsaWtpIHBvbGEgbm9uLWxpbmVhci4NCi0gU09NIG1lbWJlcmlrYW4gcGVtZXRhYW4gdG9wb2dyYWZpIHlhbmcgYmFpayBuYW11biBjbHVzdGVyIHRlcmthZGFuZyBrdXJhbmcgdGVnYXMuDQotIFNwZWN0cmFsIENsdXN0ZXJpbmcgZWZla3RpZiB1bnR1ayBkYXRhc2V0IGtlY2lsIGRlbmdhbiBib3VuZGFyeSBub24tbGluZWFyLg0KDQoNCiMgKio4LiBLZXNpbXB1bGFuIGRhbiBSZWtvbWVuZGFzaSoqDQoNCiMjICoqYS4gS2VzaW1wdWxhbioqDQoNCi0gS2V0aWdhIGFsZ29yaXRtYSBtYW1wdSBtZW5nZWxvbXBva2thbiBwZWxhbmdnYW4gbWFsbCBiZXJkYXNhcmthbiBwZW5kYXBhdGFuIGRhbiBza29yIGJlbGFuamEuDQotIFJlcHJlc2VudGFzaSBsYXRlbiBkYXJpIEF1dG9lbmNvZGVyIG1lbWJlcmkgc3RydWt0dXIgbGViaWgga29tcGFrIHNlaGluZ2dhIGhhc2lsIGNsdXN0ZXJpbmcgYmlhc2FueWEgbGViaWggc3RhYmlsLg0KLWJTT00gY29jb2sgZGlndW5ha2FuIGJpbGEgaW50ZXJwcmV0YXNpIHZpc3VhbCB0b3BvZ3JhZmkgZGlidXR1aGthbi4NCi0gU3BlY3RyYWwgQ2x1c3RlcmluZyBlZmVrdGlmIHVudHVrIGRhdGFzZXQga2VjaWwgZGFuIG1hbXB1IG1lbmFuZ2thcCBwb2xhIG5vbi1saW5lYXIuDQoNCiMjICoqYi4gUmVrb21lbmRhc2kqKjoNCg0KVW50dWsgZGF0YXNldCBNYWxsIEN1c3RvbWVycywgbWV0b2RlICoqQXV0b2VuY29kZXIgKyBLTWVhbnMqKiBjZW5kZXJ1bmcgbWVtYmVyaWthbiBwZXJmb3JtYSB0ZXJiYWlrIGthcmVuYSBtYW1wdSBtZW1wZWxhamFyaSByZXByZXNlbnRhc2kgZGF0YSBzZWNhcmEgbm9uLWxpbmVhciBzZWhpbmdnYSBtZW1ha3NpbWFsa2FuIHBlbWlzYWhhbiBjbHVzdGVyLg0KDQojIyAqKmMuIFBlbnV0dXAqKg0KDQpNZWxhbHVpIGFuYWxpc2lzIHlhbmcgdGVsYWggZGlsYWt1a2FuLCBkYXBhdCBkaXNpbXB1bGthbiBiYWh3YSBwcm9zZXMgY2x1c3RlcmluZyBtZW5nZ3VuYWthbiBwZW5kZWthdGFuIGh5YnJpZOKAlEF1dG9lbmNvZGVyLCBTZWxmLU9yZ2FuaXppbmcgTWFwIChTT00pLCBkYW4gU3BlY3RyYWwgQ2x1c3RlcmluZ+KAlG1lbWJlcmlrYW4gcGVtYWhhbWFuIHlhbmcgbGViaWgga29tcHJlaGVuc2lmIG1lbmdlbmFpIHN0cnVrdHVyIGRhbiBwb2xhIHRlcnNlbWJ1bnlpIGRhbGFtIGRhdGFzZXQgcGVsYW5nZ2FuIG1hbGwuIFNldGlhcCBtZXRvZGUgbWVuYXdhcmthbiBrYXJha3RlcmlzdGlrLCBrZWt1YXRhbiwgc2VydGEga2V0ZXJiYXRhc2FuIG1hc2luZy1tYXNpbmcsIHNlaGluZ2dhIG1lbWJlcmlrYW4gcGVyc3Bla3RpZiB5YW5nIGJlcmFnYW0gZGFsYW0gcHJvc2VzIHBlbmdlbG9tcG9rYW4gZGF0YS4NCg0KUGVuZGVrYXRhbiBBdXRvZW5jb2RlciBtZW1hbmZhYXRrYW4ga2VtYW1wdWFuIHJlcHJlc2VudGFzaSBsYXRlbiB1bnR1ayBtZW5hbmdrYXAgcG9sYSBub24tbGluZWFyIHNlY2FyYSBsZWJpaCBlZmVrdGlmLiBTT00gbWVtYmVyaWthbiBpbnRlcnByZXRhc2kgdG9wb2dyYWZpIHlhbmcgaW50dWl0aWYsIHNlZGFuZ2thbiBTcGVjdHJhbCBDbHVzdGVyaW5nIG1lbnVuanVra2FuIGtpbmVyamEgeWFuZyBiYWlrIHBhZGEgc3RydWt0dXIgZGF0YSB5YW5nIGtvbXBsZWtzIG5hbXVuIGJlcnVrdXJhbiBrZWNpbC4gUGVyYmFuZGluZ2FuIGtldGlnYSBtZXRvZGUgaW5pIG1lbXVuZ2tpbmthbiBwZW1pbGloYW4gbW9kZWwgY2x1c3RlcmluZyB5YW5nIHBhbGluZyBzZXN1YWkgZGVuZ2FuIHR1anVhbiBhbmFsaXNpcyBkYW4ga2FyYWt0ZXJpc3RpayBkYXRhc2V0Lg0KDQpIYXJhcGFubnlhLCBwZW5lbGl0aWFuIGRhbiBpbXBsZW1lbnRhc2kgaW5pIGRhcGF0IG1lbmphZGkgbGFuZGFzYW4gdW50dWsgcGVuZ2VtYmFuZ2FuIG1ldG9kZSBhbmFsaXNpcyBkYXRhIGxhbmp1dGFuLCBzZXJ0YSBtZW1iZXJpa2FuIHBlbWFoYW1hbiB5YW5nIGxlYmloIGRhbGFtIG1lbmdlbmFpIHBlbmVyYXBhbiBhbGdvcml0bWEgY2x1c3RlcmluZyBtb2Rlcm4gZGFsYW0ga29udGVrcyBEYXRhIFNhaW5zLiBTZW1vZ2EgbGFwb3JhbiBpbmkgZGFwYXQgbWVtYmVyaWthbiBtYW5mYWF0IGRhbiBrb250cmlidXNpIHBvc2l0aWYgYmFnaSBwcm9zZXMgcGVtYmVsYWphcmFuIHNlcnRhIHN0dWRpIGxlYmloIGxhbmp1dCB0ZXJrYWl0IGFuYWxpc2lzIGRhdGEgYmVyYmFzaXMgdW5zdXBlcnZpc2VkIGxlYXJuaW5nLg0KDQoNCg0KIyAqKkRBRlRBUiBQVVNUQUtBKioNCg0KLSBNYWxsIEN1c3RvbWVycyBEYXRhc2V0LCBBbWlzaGEwNTI4LlJldHJpZXZlZCBmcm9tIDxhIGhyZWYgPSAiaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9kYXRhc2V0cy9hbWlzaGEwNTI4L21hbGwtY3VzdG9tZXJzLWRhdGFzZXQiID4gS2xpayBkaXNpbmk8L2E+DQotIFNpYmVyZXRpa2EgZGFuIFNpc3RlbSwgQmVpIEx1IGRhbiBTYWxtYW4gU2FlaWRsb3UsIDEyIEFndXN0dXMgMjAyMi5SZXRyaWV2ZWQgZnJvbSA8YSBocmVmID0gImh0dHBzOi8vd3d3LnRhbmRmb25saW5lLmNvbS9kb2kvZnVsbC8xMC4xMDgwLzAxOTY5NzIyLjIwMjIuMjExMDY4MiIgPiBLbGlrIGRpc2luaTwvYT4NCi0gQWxnb3JpdG1hIFBlbmdlbG9tcG9rYW4gSGlicmlkYSBCZXJkYXNhcmthbiBQZW5nZWxvbXBva2FuIFB1bmNhayBLZXBhZGF0YW4geWFuZyBEaXRpbmdrYXRrYW4sIExpbWluIEd1bywgV2VpamlhIFFpbiwgWmhpIENhaSwgWGluZ3N1LCAyMDI0LlJldHJpZXZlZCBmcm9tIDxhIGhyZWYgPSAiaHR0cHM6Ly93d3cubWRwaS5jb20vMjA3Ni0zNDE3LzE0LzIvNzE1IiA+IEtsaWsgZGlzaW5pPC9hPg0KLSBEZXRla3NpIEFub21hbGkgZGFsYW0gUGVuaXB1YW4gRS1jb21tZXJjZSBNZW5nZ3VuYWthbiBIeWJyaWQgQXV0b2VuY29kZXItVHJhbnNmb3JtZXIgRnJhbWV3b3Jrcw0KV293b24gUHJpYXRuYSwgU3JpIFl1bGlhbnRvIEpva28gUHJhc2V0eW8sIFN1dGFydG8gV2lqb25vLCBFdmkgTWFyaWEsIERhbm55IE1hbm9uZ2dhLCAyMDI1LlJldHJpZXZlZCBmcm9tIDxhIGhyZWYgPSAiaHR0cHM6Ly9qdXJuYWwudW50YW4uYWMuaWQvaW5kZXgucGhwL2plcGluL2FydGljbGUvdmlldy84MjMzMCIgPiBLbGlrIGRpc2luaTwvYT4NCi0gU2VsZi1vcmdhbml6aW5nLCBoeWJyaWQsIFBERS1PREUgc3RydWN0dXJlIGZvciBtb3Rpb24gY29udHJvbCBpbiBpbmZvcm1hdGlvbmFsbHktZGVwcml2ZWQgc2l0dWF0aW9ucywgMTk5OC5SZXRyaWV2ZWQgZnJvbSA8YSBocmVmID0gImh0dHBzOi8vcHVyZS5rZnVwbS5lZHUuc2EvZW4vcHVibGljYXRpb25zL3NlbGYtb3JnYW5pemluZy1oeWJyaWQtcGRlLW9kZS1zdHJ1Y3R1cmUtZm9yLW1vdGlvbi1jb250cm9sLWluLWluLyIgPiBLbGlrIGRpc2luaTwvYT4=