Extreme Gradient Boosting (XGBoost) merupakan algoritma machine
learning berbasis ensemble learning dengan pendekatan
boosting, yang menggabungkan banyak model sederhana (umumnya
decision tree) secara bertahap untuk membentuk model yang lebih
kuat dan akurat. Prinsip utama dari metode ini adalah setiap model baru
dibangun untuk memperbaiki kesalahan dari model sebelumnya melalui
optimisasi berbasis gradient descent terhadap fungsi objektif
yang mencakup komponen loss function dan regularisasi. XGBoost
merupakan pengembangan dari metode Gradient Boosting yang
dirancang lebih efisien dan scalable, sehingga mampu menangani
data berukuran besar, mengakomodasi missing values, serta
mengurangi risiko overfitting melalui pengaturan parameter
seperti kedalaman pohon (max_depth), laju pembelajaran
(eta), dan subsampling (Chen & Guestrin, 2016;
Friedman, 2001).
Dalam praktiknya, XGBoost banyak digunakan untuk permasalahan
supervised learning seperti klasifikasi dan regresi, khususnya
ketika data memiliki hubungan yang kompleks dan tidak linear. Algoritma
ini sangat efektif dalam menghasilkan prediksi dengan tingkat akurasi
tinggi, sehingga sering digunakan dalam berbagai bidang seperti ekonomi,
kesehatan, hingga analisis sosial, termasuk dalam memprediksi backlog
kelayakhunian berbasis data rumah tangga. XGBoost umumnya digunakan
ketika tersedia dataset berukuran besar dengan banyak variabel
prediktor, serta ketika tujuan utama adalah memperoleh performa prediksi
yang optimal. Meskipun demikian, model ini cenderung lebih kompleks
untuk diinterpretasikan dibandingkan metode statistik tradisional,
sehingga penggunaannya sering dikombinasikan dengan teknik
interpretabilitas tambahan. Dengan keunggulan dalam akurasi, efisiensi,
dan kemampuan menangkap pola non-linear, XGBoost menjadi salah satu
metode yang paling populer dalam analisis data modern (James et al.,
2021).
knitr::opts_chunk$set(echo = TRUE)
Prepare Data ML
data_ml <- dataku %>%
mutate(
backlog_ml = ifelse(BACK_LOG == 100, 1, 0)
) %>%
select(
backlog_ml,
r1602, # status kepemilikan
luas_cap,
r1606, # atap
r1607, # dinding
r1608, # lantai
r1610a, # air minum
r1614a, # sanitasi
r301, # jumlah ART
r105 # karakteristik KRT
) %>%
drop_na()
## r1602 luas_cap r1606 r1607 r1608 r1610a r1614a r301 r105
## 1 1 60.0 3 1 2 2 4 2 1
## 2 1 48.0 2 1 5 2 5 1 1
## 3 1 50.0 5 1 2 5 5 1 1
## 4 1 31.5 2 1 5 6 6 2 2
## 5 1 22.5 2 1 2 2 4 4 1
## 6 1 10.0 2 1 2 5 5 4 2
## [1] 0 0 1 1 0 0
Train-Test Split
Pada tahap ini dilakukan proses pembagian data menjadi dua bagian,
yaitu data latih (training set) dan data uji (testing
set). Proses ini diawali dengan fungsi set.seed(123)
yang bertujuan untuk memastikan bahwa hasil pembagian data bersifat
reproducible, artinya hasil yang diperoleh akan tetap sama
setiap kali kode dijalankan. Selanjutnya, fungsi
createDataPartition(y, p = 0.8, list = FALSE) digunakan
untuk membagi data berdasarkan proporsi 80% untuk data latih dan 20%
untuk data uji, dengan mempertimbangkan distribusi variabel target (y)
agar tetap seimbang (stratified sampling). Indeks hasil
pembagian tersebut kemudian digunakan untuk memisahkan matriks fitur
(X) dan variabel target (y) menjadi
X_train, X_test, y_train, dan
y_test.
set.seed(123)
trainIndex <- createDataPartition(y, p = 0.8, list = FALSE)
X_train <- X[trainIndex, ]
X_test <- X[-trainIndex, ]
y_train <- y[trainIndex]
y_test <- y[-trainIndex]
Model XGBOOST
Model machine learning yang digunakan adalah algoritma
Extreme Gradient Boosting (XGBoost). Data latih dan
data uji terlebih dahulu dikonversi ke dalam format
xgb.DMatrix, yaitu struktur data yang dioptimalkan untuk
komputasi XGBoost. Selanjutnya, ditentukan parameter model seperti
objective = “binary:logistic” untuk klasifikasi biner, serta eval_metric
= “auc” untuk mengukur kemampuan model dalam membedakan rumah tangga
backlog dan tidak backlog. Parameter lain seperti max_depth, eta,
subsample, dan colsample_bytree digunakan untuk mengatur
kompleksitas model agar pembelajaran lebih stabil dan mengurangi risiko
overfitting.
Proses pelatihan dilakukan menggunakan fungsi xgb.train
dengan maksimum 100 iterasi, di mana performa model dimonitor pada data
latih dan data uji melalui watchlist. Mekanisme early
stopping diterapkan untuk menghentikan pelatihan secara otomatis
jika tidak terjadi peningkatan performa dalam beberapa iterasi, sehingga
model yang dihasilkan tetap optimal. Tujuan dari tahap ini adalah
membangun model prediktif yang mampu menangkap hubungan non-linear antar
variabel dan mengestimasi probabilitas backlog perumahan secara
akurat.
Hasilnya adalah model yang telah terlatih dan mampu melakukan
prediksi dengan baik. Peningkatan dan kestabilan nilai AUC pada data uji
menunjukkan bahwa model berhasil mempelajari pola yang relevan tanpa
mengalami overfitting. Dengan demikian, model XGBoost ini dapat
digunakan untuk mengidentifikasi rumah tangga dengan risiko backlog
serta mendukung perumusan kebijakan perumahan yang lebih tepat
sasaran.
dtrain <- xgb.DMatrix(data = X_train, label = y_train)
dtest <- xgb.DMatrix(data = X_test, label = y_test)
params <- list(
objective = "binary:logistic",
eval_metric = "auc",
max_depth = 6,
eta = 0.1,
subsample = 0.8,
colsample_bytree = 0.8
)
model_xgb <- xgb.train(
params = params,
data = dtrain,
nrounds = 100,
watchlist = list(train = dtrain, test = dtest),
early_stopping_rounds = 10,
print_every_n = 20
)
## [1] train-auc:0.845382 test-auc:0.844776
## Multiple eval metrics are present. Will use test_auc for early stopping.
## Will train until test_auc hasn't improved in 10 rounds.
##
## [21] train-auc:0.911918 test-auc:0.912659
## [41] train-auc:0.919002 test-auc:0.919931
## [61] train-auc:0.921596 test-auc:0.922524
## [81] train-auc:0.923140 test-auc:0.923807
## [100] train-auc:0.924289 test-auc:0.924736
Hasil pelatihan model XGBoost menunjukkan bahwa nilai Area
Under Curve (AUC) baik pada data latih maupun data uji
mengalami peningkatan secara konsisten seiring bertambahnya jumlah
iterasi (boosting rounds). Pada iterasi awal, nilai AUC berada di
kisaran 0,845 baik untuk data latih maupun data uji, yang
mengindikasikan bahwa model sudah memiliki kemampuan awal yang cukup
baik dalam membedakan rumah tangga backlog dan tidak backlog. Seiring
proses pelatihan, nilai AUC meningkat secara bertahap hingga mencapai
sekitar 0,924 pada iterasi ke-100 untuk data latih dan 0,925 untuk data
uji.
Nilai AUC yang mendekati 1 menunjukkan bahwa model memiliki kemampuan
diskriminasi yang sangat baik. Dalam konteks ini, nilai AUC sekitar
0,92–0,93 mengindikasikan bahwa model mampu mengklasifikasikan rumah
tangga backlog dan tidak backlog dengan tingkat akurasi yang tinggi.
Secara praktis, hal ini berarti bahwa terdapat probabilitas lebih dari
92% bahwa model akan memberikan skor probabilitas yang lebih tinggi
kepada rumah tangga yang benar-benar mengalami backlog dibandingkan yang
tidak.
Perbandingan antara nilai AUC pada data latih
(train-auc) dan data uji (test-auc)
menunjukkan bahwa kedua nilai tersebut sangat berdekatan di setiap
iterasi. Hal ini merupakan indikasi kuat bahwa model tidak mengalami
overfitting, karena performa pada data yang tidak dilatih (data
uji) tetap sejalan dengan performa pada data latih. Bahkan, dalam
beberapa iterasi, nilai AUC pada data uji sedikit lebih tinggi
dibandingkan data latih, yang menunjukkan bahwa model memiliki kemampuan
generalisasi yang baik terhadap data baru.
Evaluasi
pred_prob <- predict(model_xgb, dtest)
pred_class <- ifelse(pred_prob > 0.5, 1, 0)
confusionMatrix(as.factor(pred_class), as.factor(y_test))
## Confusion Matrix and Statistics
##
## Reference
## Prediction 0 1
## 0 49044 5605
## 1 406 13637
##
## Accuracy : 0.9125
## 95% CI : (0.9104, 0.9146)
## No Information Rate : 0.7199
## P-Value [Acc > NIR] : < 2.2e-16
##
## Kappa : 0.7635
##
## Mcnemar's Test P-Value : < 2.2e-16
##
## Sensitivity : 0.9918
## Specificity : 0.7087
## Pos Pred Value : 0.8974
## Neg Pred Value : 0.9711
## Prevalence : 0.7199
## Detection Rate : 0.7140
## Detection Prevalence : 0.7956
## Balanced Accuracy : 0.8502
##
## 'Positive' Class : 0
##
roc_obj <- roc(y_test, pred_prob)
## Setting levels: control = 0, case = 1
## Setting direction: controls < cases
auc(roc_obj)
## Area under the curve: 0.9247
Hasil evaluasi model menunjukkan bahwa performa klasifikasi yang
dihasilkan tergolong sangat baik. Nilai accuracy sebesar 0,9125
mengindikasikan bahwa sekitar 91,25% prediksi model sesuai dengan
kondisi sebenarnya. Nilai ini jauh lebih tinggi dibandingkan No
Information Rate (0,7199), yang berarti model memiliki kemampuan
prediksi yang signifikan secara statistik (p-value < 2.2e-16). Selain
itu, nilai Kappa sebesar 0,7635 menunjukkan tingkat kesepakatan yang
kuat antara hasil prediksi dan data aktual, setelah mengoreksi
kemungkinan kesesuaian yang terjadi secara kebetulan.
Dari confusion matrix, terlihat bahwa model sangat baik dalam
mengidentifikasi kelas tidak backlog (kelas 0) dengan nilai sensitivity
sebesar 0,9918, yang berarti hampir seluruh rumah tangga yang tidak
mengalami backlog berhasil dikenali dengan benar. Namun, kemampuan model
dalam mendeteksi rumah tangga backlog (kelas 1) relatif lebih rendah,
tercermin dari specificity sebesar 0,7087, yang menunjukkan masih
terdapat sebagian rumah tangga backlog yang tidak terdeteksi. Meskipun
demikian, nilai balanced accuracy sebesar 0,8502 menunjukkan bahwa
secara keseluruhan model tetap memiliki performa yang seimbang antara
kedua kelas.
Lebih lanjut, nilai Area Under Curve (AUC) sebesar 0,9247
mengindikasikan bahwa model memiliki kemampuan diskriminasi yang sangat
baik dalam membedakan rumah tangga backlog dan tidak backlog. Dengan
performa ini, model XGBoost dapat dianggap cukup andal untuk digunakan
dalam memprediksi probabilitas backlog perumahan serta mendukung
penentuan prioritas kebijakan berbasis data.
## Setting levels: control = 0, case = 1
## Setting direction: controls < cases

Feature Importance
importance_matrix <- xgb.importance(model = model_xgb)
xgb.plot.importance(importance_matrix)

Grafik menunjukkan tingkat kepentingan relatif (importance)
dari masing-masing variabel dalam memprediksi backlog perumahan. Semakin
panjang bar, semakin besar kontribusi variabel tersebut dalam
meningkatkan akurasi model.
Variabel yang paling dominan adalah r1614a (akses
sanitasi), diikuti oleh r1606 (jenis atap) dan
r1602 (status kepemilikan rumah). Hal ini mengindikasikan
bahwa kondisi sanitasi merupakan faktor paling penting dalam menentukan
apakah suatu rumah tangga mengalami backlog. Selanjutnya, kondisi fisik
bangunan seperti atap, serta status kepemilikan rumah, juga memiliki
pengaruh yang signifikan terhadap status kelayakhunian. Variabel
luas_cap (luas lantai per kapita) dan r1610a
(akses air minum) juga memiliki kontribusi yang cukup besar, yang
menunjukkan bahwa aspek kepadatan hunian dan akses air layak merupakan
indikator penting dalam menentukan kualitas perumahan.
Probability
Backlog
dataku$prob_backlog <- predict(model_xgb, xgb.DMatrix(X))
head(dataku$prob_backlog, 15)
## [1] 0.0655616596 0.1917896420 0.9990670085 0.9430428743 0.0770765394
## [6] 0.1093887314 0.0007621722 0.0001942274 0.1643930525 0.1319696307
## [11] 0.0648792610 0.1076658145 0.0834242180 0.9049150944 0.1102087647
Kode
dataku$prob_backlog <- predict(model_xgb, xgb.DMatrix(X))
digunakan untuk menghasilkan probabilitas backlog perumahan pada setiap
rumah tangga berdasarkan model XGBoost yang telah dilatih. Nilai yang
dihasilkan berada pada rentang 0 hingga 1, di mana semakin mendekati 1
menunjukkan semakin tinggi kemungkinan rumah tangga tersebut mengalami
backlog. Nilai probabilitas ini kemudian disimpan dalam variabel baru
prob_backlog, sehingga memungkinkan analisis yang lebih detail
dibandingkan sekadar klasifikasi biner (backlog vs tidak backlog).
Hasil head(dataku$prob_backlog, 15) menampilkan 15 observasi pertama
dari probabilitas tersebut. Terlihat bahwa terdapat variasi risiko yang
cukup lebar antar rumah tangga. Misalnya, nilai sangat rendah seperti
0,00019 atau 0,00076 menunjukkan rumah tangga dengan risiko backlog yang
hampir tidak ada, sementara nilai sangat tinggi seperti 0,99907 dan
0,94304 mengindikasikan rumah tangga dengan kemungkinan backlog yang
sangat besar. Nilai menengah seperti 0,10–0,19 mencerminkan risiko
rendah hingga sedang, sedangkan nilai di atas 0,90 dapat dikategorikan
sebagai prioritas tinggi untuk intervensi.
Dengan adanya probabilitas ini, model tidak hanya memberikan
keputusan klasifikasi, tetapi juga menyediakan skor risiko yang lebih
granular. Hal ini sangat bermanfaat dalam konteks kebijakan perumahan,
karena memungkinkan pemerintah atau pemangku kepentingan untuk melakukan
targeting program secara lebih tepat sasaran, misalnya dengan
memprioritaskan rumah tangga dengan probabilitas backlog tertinggi
sebagai penerima bantuan perumahan.

References
[1] Chen, T., & Guestrin, C. (2016). XGBoost: A scalable tree
boosting system. Proceedings of the 22nd ACM SIGKDD International
Conference on Knowledge Discovery and Data Mining, 785–794.
[2] Friedman, J. H. (2001). Greedy function approximation: A gradient
boosting machine. Annals of Statistics, 29(5), 1189–1232.
[3] James, G., Witten, D., Hastie, T., & Tibshirani, R. (2021).
An introduction to statistical learning: With applications in R (2nd
ed.). Springer.
Direktorat Statistik Kesejahteraan Rakyat, BPS, saptahas@bps.go.id
LS0tDQp0aXRsZTogIlByZWRpY3RpbmcgSG91c2luZyBCYWNrbG9nIGluIEluZG9uZXNpYSB1c2luZyBYR0Jvb3N0IChTdXNlbmFzIERhdGEpIg0KYXV0aG9yOiAiU2FwdGEgSGFzdGhvIFBvbmNvIg0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogc2hvdw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdGhlbWU6IGpvdXJuYWwNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogIHdvcmRfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCi0tLQ0KDQpgYGB7PWh0bWx9DQo8c3R5bGU+DQpib2R5ew0KdGV4dC1hbGlnbjoganVzdGlmeX0NCjwvc3R5bGU+DQpgYGANCg0KRXh0cmVtZSBHcmFkaWVudCBCb29zdGluZyAoWEdCb29zdCkgbWVydXBha2FuIGFsZ29yaXRtYSBtYWNoaW5lIGxlYXJuaW5nIGJlcmJhc2lzIF9lbnNlbWJsZSBsZWFybmluZ18gZGVuZ2FuIHBlbmRla2F0YW4gX2Jvb3N0aW5nXywgeWFuZyBtZW5nZ2FidW5na2FuIGJhbnlhayBtb2RlbCBzZWRlcmhhbmEgKHVtdW1ueWEgX2RlY2lzaW9uIHRyZWVfKSBzZWNhcmEgYmVydGFoYXAgdW50dWsgbWVtYmVudHVrIG1vZGVsIHlhbmcgbGViaWgga3VhdCBkYW4gYWt1cmF0LiBQcmluc2lwIHV0YW1hIGRhcmkgbWV0b2RlIGluaSBhZGFsYWggc2V0aWFwIG1vZGVsIGJhcnUgZGliYW5ndW4gdW50dWsgbWVtcGVyYmFpa2kga2VzYWxhaGFuIGRhcmkgbW9kZWwgc2ViZWx1bW55YSBtZWxhbHVpIG9wdGltaXNhc2kgYmVyYmFzaXMgX2dyYWRpZW50IGRlc2NlbnRfIHRlcmhhZGFwIGZ1bmdzaSBvYmpla3RpZiB5YW5nIG1lbmNha3VwIGtvbXBvbmVuIF9sb3NzIGZ1bmN0aW9uXyBkYW4gcmVndWxhcmlzYXNpLiBYR0Jvb3N0IG1lcnVwYWthbiBwZW5nZW1iYW5nYW4gZGFyaSBtZXRvZGUgX0dyYWRpZW50IEJvb3N0aW5nXyB5YW5nIGRpcmFuY2FuZyBsZWJpaCBlZmlzaWVuIGRhbiBfc2NhbGFibGVfLCBzZWhpbmdnYSBtYW1wdSBtZW5hbmdhbmkgZGF0YSBiZXJ1a3VyYW4gYmVzYXIsIG1lbmdha29tb2Rhc2kgX21pc3NpbmcgdmFsdWVzXywgc2VydGEgbWVuZ3VyYW5naSByaXNpa28gX292ZXJmaXR0aW5nXyBtZWxhbHVpIHBlbmdhdHVyYW4gcGFyYW1ldGVyIHNlcGVydGkga2VkYWxhbWFuIHBvaG9uIChgbWF4X2RlcHRoYCksIGxhanUgcGVtYmVsYWphcmFuIChgZXRhYCksIGRhbiBzdWJzYW1wbGluZyAoQ2hlbiAmIEd1ZXN0cmluLCAyMDE2OyBGcmllZG1hbiwgMjAwMSkuDQoNCkRhbGFtIHByYWt0aWtueWEsIFhHQm9vc3QgYmFueWFrIGRpZ3VuYWthbiB1bnR1ayBwZXJtYXNhbGFoYW4gX3N1cGVydmlzZWQgbGVhcm5pbmdfIHNlcGVydGkga2xhc2lmaWthc2kgZGFuIHJlZ3Jlc2ksIGtodXN1c255YSBrZXRpa2EgZGF0YSBtZW1pbGlraSBodWJ1bmdhbiB5YW5nIGtvbXBsZWtzIGRhbiB0aWRhayBsaW5lYXIuIEFsZ29yaXRtYSBpbmkgc2FuZ2F0IGVmZWt0aWYgZGFsYW0gbWVuZ2hhc2lsa2FuIHByZWRpa3NpIGRlbmdhbiB0aW5na2F0IGFrdXJhc2kgdGluZ2dpLCBzZWhpbmdnYSBzZXJpbmcgZGlndW5ha2FuIGRhbGFtIGJlcmJhZ2FpIGJpZGFuZyBzZXBlcnRpIGVrb25vbWksIGtlc2VoYXRhbiwgaGluZ2dhIGFuYWxpc2lzIHNvc2lhbCwgdGVybWFzdWsgZGFsYW0gbWVtcHJlZGlrc2kgYmFja2xvZyBrZWxheWFraHVuaWFuIGJlcmJhc2lzIGRhdGEgcnVtYWggdGFuZ2dhLiBYR0Jvb3N0IHVtdW1ueWEgZGlndW5ha2FuIGtldGlrYSB0ZXJzZWRpYSBkYXRhc2V0IGJlcnVrdXJhbiBiZXNhciBkZW5nYW4gYmFueWFrIHZhcmlhYmVsIHByZWRpa3Rvciwgc2VydGEga2V0aWthIHR1anVhbiB1dGFtYSBhZGFsYWggbWVtcGVyb2xlaCBwZXJmb3JtYSBwcmVkaWtzaSB5YW5nIG9wdGltYWwuIE1lc2tpcHVuIGRlbWlraWFuLCBtb2RlbCBpbmkgY2VuZGVydW5nIGxlYmloIGtvbXBsZWtzIHVudHVrIGRpaW50ZXJwcmV0YXNpa2FuIGRpYmFuZGluZ2thbiBtZXRvZGUgc3RhdGlzdGlrIHRyYWRpc2lvbmFsLCBzZWhpbmdnYSBwZW5nZ3VuYWFubnlhIHNlcmluZyBkaWtvbWJpbmFzaWthbiBkZW5nYW4gdGVrbmlrIGludGVycHJldGFiaWxpdGFzIHRhbWJhaGFuLiBEZW5nYW4ga2V1bmdndWxhbiBkYWxhbSBha3VyYXNpLCBlZmlzaWVuc2ksIGRhbiBrZW1hbXB1YW4gbWVuYW5na2FwIHBvbGEgbm9uLWxpbmVhciwgWEdCb29zdCBtZW5qYWRpIHNhbGFoIHNhdHUgbWV0b2RlIHlhbmcgcGFsaW5nIHBvcHVsZXIgZGFsYW0gYW5hbGlzaXMgZGF0YSBtb2Rlcm4gKEphbWVzIGV0IGFsLiwgMjAyMSkuDQoNCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9VFJVRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCmBgYA0KDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBlY2hvPUZBTFNFfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHN1cnZleSkNCmxpYnJhcnkoamFuaXRvcikNCmxpYnJhcnkoc2NhbGVzKQ0KbGlicmFyeShoYXZlbikNCmxpYnJhcnkob3Blbnhsc3gpDQpsaWJyYXJ5KHNmKQ0KbGlicmFyeSh2aXJpZGlzKQ0KYGBgDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0Kc2V0d2QoIkQ6XFwyLiBQZW5nZW1iYW5nYW4gZGlyaVxcMSBFeGVyY2lzZSBCYWd1c1xcSG91c2luZyBBbmFseXNpcyIpDQpgYGANCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89RkFMU0V9DQpkYXRha3UgPC0gcmVhZF9zYXYoIktPUjI1R0FCXzAzMDlfSE9VU0lORy5zYXYiKSAlPiUNCiAgY2xlYW5fbmFtZXMoKQ0KYGBgDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KIyBCYWNrbG9nIEtlbGF5YWtodW5pYW4NCmRhdGFrdSA8LSBkYXRha3UgJT4lDQogIG11dGF0ZShrYWJ1ID0gcjEwMSoxMDAgKyByMTAyKSAlPiUNCiAgcmVuYW1lKHByb3Y9InIxMDEiLCBrYWI9InIxMDIiKSAlPiUNCiAgbXV0YXRlKGRlbm9tPTEwMCkgJT4lDQogIG11dGF0ZShpbmRpYzFfbGF5YWsgPSBkcGx5cjo6Y2FzZV93aGVuKGRhdGFrdSRyMTYwOWE8PTMgJiBkYXRha3UkcjE2MDliPT0xICYgZGF0YWt1JHIxNjA5Yzw9Mn4xMDAsIChkYXRha3UkcjEwNSA9PTIgJiBkYXRha3UkcjE2MDlhPD0zICYgZGF0YWt1JHIxNjA5Yj09MSAmIGRhdGFrdSRyMTYwOWM9PTR+MTAwKSksDQogIGluZGljMV9sYXlhaz1jYXNlX3doZW4oaW5kaWMxX2xheWFrPT0xMDB+MTAwLGlzLm5hKGluZGljMV9sYXlhayl+MCkpICU+JQ0KICBtdXRhdGUoZHJpbmt3PWNhcjo6cmVjb2RlKGRhdGFrdSRyMTYxMGEsIjM6NT0xMDA7Nz0xMDA7MTA9MTAwO2Vsc2U9MCIpKSAlPiUNCiAgbXV0YXRlKGJvdHRsZT1jYXI6OnJlY29kZShkYXRha3UkcjE2MTBhLCIxOjI9MTAwO2Vsc2U9MCIpKSAlPiUNCiAgbXV0YXRlKGJhdGhpbmc9Y2FyOjpyZWNvZGUoZGF0YWt1JHIxNjE0YSwiMzo1PTEwMDs3PTEwMDsxMD0xMDA7ZWxzZT0wIikpICU+JQ0KICBtdXRhdGUoaW5kaWMyX2xheWFrID0gZHBseXI6OmNhc2Vfd2hlbihkcmlua3c9PTEwMCB8IChib3R0bGU9PTEwMCAmIGJhdGhpbmc9PTEwMCl+MTAwKSkgJT4lDQogIG11dGF0ZShpbmRpYzJfbGF5YWsgPSBpZmVsc2UoaXMubmEoaW5kaWMyX2xheWFrKSwgMCwgaW5kaWMyX2xheWFrKSkgJT4lDQogIG11dGF0ZShsdWFzX2NhcD1yMTYwNC9yMzAxKSAlPiUNCiAgbXV0YXRlKGluZGljM19sYXlhayA9IGRwbHlyOjpjYXNlX3doZW4obHVhc19jYXA+PTcuMjB+MTAwLGx1YXNfY2FwPDcuMjB+MCkpICU+JQ0KICBtdXRhdGUocm9vZj1jYXI6OnJlY29kZShkYXRha3UkcjE2MDYsIjE6ND0xMDA7ZWxzZT0wIikpICU+JQ0KICBtdXRhdGUod2FsbD1jYXI6OnJlY29kZShkYXRha3UkcjE2MDcsIjE6Mz0xMDA7ZWxzZT0wIikpICU+JQ0KICBtdXRhdGUoZmxvb3I9Y2FyOjpyZWNvZGUoZGF0YWt1JHIxNjA4LCIxOjU9MTAwO2Vsc2U9MCIpKSAlPiUNCiAgbXV0YXRlKGluZGljNF9sYXlhayA9IGRwbHlyOjpjYXNlX3doZW4oKHJvb2Y9PTEwMCAmIGZsb29yPT0xMDAgJiB3YWxsPT0xMDApfjEwMCkpICU+JQ0KICBtdXRhdGUoaW5kaWM0X2xheWFrID0gaWZlbHNlKGlzLm5hKGluZGljNF9sYXlhayksIDAsIGluZGljNF9sYXlhaykpDQoNCmRhdGFrdSA8LSBkYXRha3UgJT4lDQogIG11dGF0ZShSTEggPSBkcGx5cjo6Y2FzZV93aGVuKChpbmRpYzFfbGF5YWs9PTEwMCAmIGluZGljMl9sYXlhaz09MTAwICYgaW5kaWMzX2xheWFrPT0xMDAgJiBpbmRpYzRfbGF5YWs9PTEwMCl+MTAwKSkgJT4lDQogIG11dGF0ZShSTEggPSBpZmVsc2UoaXMubmEoUkxIKSwgMCwgUkxIKSkgJT4lIA0KICBtdXRhdGUoDQogICAgQkFDS19MT0cgPSBpZmVsc2UocjE2MDI9PSAxICYgUkxIID09IDAsIDEwMCwgMCksDQogICAgQkFDS19MT0dfTEFCRUwgPSBmYWN0b3IoDQogICAgICBCQUNLX0xPRywNCiAgICAgIGxldmVscyA9IGMoMCwgMTAwKSwNCiAgICAgIGxhYmVscyA9IGMoIlRpZGFrIiwgIkJhY2tsb2ciKQ0KICAgICkNCiAgKQ0KYGBgDQogIA0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1GQUxTRX0NCmxpYnJhcnkoY2FyZXQpDQpsaWJyYXJ5KHhnYm9vc3QpDQpsaWJyYXJ5KE1hdHJpeCkNCmxpYnJhcnkocFJPQykNCmxpYnJhcnkocGFyYWxsZWxseSkNCmBgYA0KDQoNCiMgUHJlcGFyZSBEYXRhIE1MDQoNCmBgYHtyfQ0KZGF0YV9tbCA8LSBkYXRha3UgJT4lDQogIG11dGF0ZSgNCiAgICBiYWNrbG9nX21sID0gaWZlbHNlKEJBQ0tfTE9HID09IDEwMCwgMSwgMCkNCiAgKSAlPiUNCiAgc2VsZWN0KA0KICAgIGJhY2tsb2dfbWwsDQogICAgcjE2MDIsICAgICAgICAjIHN0YXR1cyBrZXBlbWlsaWthbg0KICAgIGx1YXNfY2FwLA0KICAgIHIxNjA2LCAgICAgICAgIyBhdGFwDQogICAgcjE2MDcsICAgICAgICAjIGRpbmRpbmcNCiAgICByMTYwOCwgICAgICAgICMgbGFudGFpDQogICAgcjE2MTBhLCAgICAgICAjIGFpciBtaW51bQ0KICAgIHIxNjE0YSwgICAgICAgIyBzYW5pdGFzaQ0KICAgIHIzMDEsICAgICAgICAgIyBqdW1sYWggQVJUDQogICAgcjEwNSAgICAgICAgICAjIGthcmFrdGVyaXN0aWsgS1JUDQogICkgJT4lDQogIGRyb3BfbmEoKQ0KYGBgDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KIyBEdW1teSBFbmNvZGluZw0KZHVtbWllcyA8LSBkdW1teVZhcnMoYmFja2xvZ19tbCB+IC4sIGRhdGEgPSBkYXRhX21sKQ0KWCA8LSBwcmVkaWN0KGR1bW1pZXMsIG5ld2RhdGEgPSBkYXRhX21sKSAlPiUgYXMubWF0cml4KCkNCnkgPC0gZGF0YV9tbCRiYWNrbG9nX21sDQpoZWFkKFgpDQpoZWFkKHkpDQpgYGANCg0KIyBUcmFpbi1UZXN0IFNwbGl0DQoNClBhZGEgdGFoYXAgaW5pIGRpbGFrdWthbiBwcm9zZXMgcGVtYmFnaWFuIGRhdGEgbWVuamFkaSBkdWEgYmFnaWFuLCB5YWl0dSBkYXRhIGxhdGloIChfdHJhaW5pbmcgc2V0XykgZGFuIGRhdGEgdWppIChfdGVzdGluZyBzZXRfKS4gUHJvc2VzIGluaSBkaWF3YWxpIGRlbmdhbiBmdW5nc2kgYHNldC5zZWVkKDEyMylgIHlhbmcgYmVydHVqdWFuIHVudHVrIG1lbWFzdGlrYW4gYmFod2EgaGFzaWwgcGVtYmFnaWFuIGRhdGEgYmVyc2lmYXQgX3JlcHJvZHVjaWJsZV8sIGFydGlueWEgaGFzaWwgeWFuZyBkaXBlcm9sZWggYWthbiB0ZXRhcCBzYW1hIHNldGlhcCBrYWxpIGtvZGUgZGlqYWxhbmthbi4gU2VsYW5qdXRueWEsIGZ1bmdzaSBgY3JlYXRlRGF0YVBhcnRpdGlvbih5LCBwID0gMC44LCBsaXN0ID0gRkFMU0UpYCBkaWd1bmFrYW4gdW50dWsgbWVtYmFnaSBkYXRhIGJlcmRhc2Fya2FuIHByb3BvcnNpIDgwJSB1bnR1ayBkYXRhIGxhdGloIGRhbiAyMCUgdW50dWsgZGF0YSB1amksIGRlbmdhbiBtZW1wZXJ0aW1iYW5na2FuIGRpc3RyaWJ1c2kgdmFyaWFiZWwgdGFyZ2V0ICh5KSBhZ2FyIHRldGFwIHNlaW1iYW5nIChfc3RyYXRpZmllZCBzYW1wbGluZ18pLiBJbmRla3MgaGFzaWwgcGVtYmFnaWFuIHRlcnNlYnV0IGtlbXVkaWFuIGRpZ3VuYWthbiB1bnR1ayBtZW1pc2Foa2FuIG1hdHJpa3MgZml0dXIgKGBYYCkgZGFuIHZhcmlhYmVsIHRhcmdldCAoYHlgKSBtZW5qYWRpIGBYX3RyYWluYCwgYFhfdGVzdGAsIGB5X3RyYWluYCwgZGFuIGB5X3Rlc3RgLg0KDQpgYGB7cn0NCnNldC5zZWVkKDEyMykNCnRyYWluSW5kZXggPC0gY3JlYXRlRGF0YVBhcnRpdGlvbih5LCBwID0gMC44LCBsaXN0ID0gRkFMU0UpDQoNClhfdHJhaW4gPC0gWFt0cmFpbkluZGV4LCBdDQpYX3Rlc3QgIDwtIFhbLXRyYWluSW5kZXgsIF0NCnlfdHJhaW4gPC0geVt0cmFpbkluZGV4XQ0KeV90ZXN0ICA8LSB5Wy10cmFpbkluZGV4XQ0KYGBgDQoNCg0KDQoNCiMgTW9kZWwgWEdCT09TVA0KDQpNb2RlbCBtYWNoaW5lIGxlYXJuaW5nIHlhbmcgZGlndW5ha2FuIGFkYWxhaCBhbGdvcml0bWEgKipFeHRyZW1lIEdyYWRpZW50IEJvb3N0aW5nIChYR0Jvb3N0KSoqLiBEYXRhIGxhdGloIGRhbiBkYXRhIHVqaSB0ZXJsZWJpaCBkYWh1bHUgZGlrb252ZXJzaSBrZSBkYWxhbSBmb3JtYXQgYHhnYi5ETWF0cml4YCwgeWFpdHUgc3RydWt0dXIgZGF0YSB5YW5nIGRpb3B0aW1hbGthbiB1bnR1ayBrb21wdXRhc2kgWEdCb29zdC4gU2VsYW5qdXRueWEsIGRpdGVudHVrYW4gcGFyYW1ldGVyIG1vZGVsIHNlcGVydGkgb2JqZWN0aXZlID0gImJpbmFyeTpsb2dpc3RpYyIgdW50dWsga2xhc2lmaWthc2kgYmluZXIsIHNlcnRhIGV2YWxfbWV0cmljID0gImF1YyIgdW50dWsgbWVuZ3VrdXIga2VtYW1wdWFuIG1vZGVsIGRhbGFtIG1lbWJlZGFrYW4gcnVtYWggdGFuZ2dhIGJhY2tsb2cgZGFuIHRpZGFrIGJhY2tsb2cuIFBhcmFtZXRlciBsYWluIHNlcGVydGkgX21heF9kZXB0aCwgZXRhLCBzdWJzYW1wbGVfLCBkYW4gX2NvbHNhbXBsZV9ieXRyZWVfIGRpZ3VuYWthbiB1bnR1ayBtZW5nYXR1ciBrb21wbGVrc2l0YXMgbW9kZWwgYWdhciBwZW1iZWxhamFyYW4gbGViaWggc3RhYmlsIGRhbiBtZW5ndXJhbmdpIHJpc2lrbyBvdmVyZml0dGluZy4NCg0KUHJvc2VzIHBlbGF0aWhhbiBkaWxha3VrYW4gbWVuZ2d1bmFrYW4gZnVuZ3NpIGB4Z2IudHJhaW5gIGRlbmdhbiBtYWtzaW11bSAxMDAgaXRlcmFzaSwgZGkgbWFuYSBwZXJmb3JtYSBtb2RlbCBkaW1vbml0b3IgcGFkYSBkYXRhIGxhdGloIGRhbiBkYXRhIHVqaSBtZWxhbHVpIF93YXRjaGxpc3RfLiBNZWthbmlzbWUgX2Vhcmx5IHN0b3BwaW5nXyBkaXRlcmFwa2FuIHVudHVrIG1lbmdoZW50aWthbiBwZWxhdGloYW4gc2VjYXJhIG90b21hdGlzIGppa2EgdGlkYWsgdGVyamFkaSBwZW5pbmdrYXRhbiBwZXJmb3JtYSBkYWxhbSBiZWJlcmFwYSBpdGVyYXNpLCBzZWhpbmdnYSBtb2RlbCB5YW5nIGRpaGFzaWxrYW4gdGV0YXAgb3B0aW1hbC4gVHVqdWFuIGRhcmkgdGFoYXAgaW5pIGFkYWxhaCBtZW1iYW5ndW4gbW9kZWwgcHJlZGlrdGlmIHlhbmcgbWFtcHUgbWVuYW5na2FwIGh1YnVuZ2FuIG5vbi1saW5lYXIgYW50YXIgdmFyaWFiZWwgZGFuIG1lbmdlc3RpbWFzaSBwcm9iYWJpbGl0YXMgYmFja2xvZyBwZXJ1bWFoYW4gc2VjYXJhIGFrdXJhdC4NCg0KSGFzaWxueWEgYWRhbGFoIG1vZGVsIHlhbmcgdGVsYWggdGVybGF0aWggZGFuIG1hbXB1IG1lbGFrdWthbiBwcmVkaWtzaSBkZW5nYW4gYmFpay4gUGVuaW5na2F0YW4gZGFuIGtlc3RhYmlsYW4gbmlsYWkgQVVDIHBhZGEgZGF0YSB1amkgbWVudW5qdWtrYW4gYmFod2EgbW9kZWwgYmVyaGFzaWwgbWVtcGVsYWphcmkgcG9sYSB5YW5nIHJlbGV2YW4gdGFucGEgbWVuZ2FsYW1pIG92ZXJmaXR0aW5nLiBEZW5nYW4gZGVtaWtpYW4sIG1vZGVsIFhHQm9vc3QgaW5pIGRhcGF0IGRpZ3VuYWthbiB1bnR1ayBtZW5naWRlbnRpZmlrYXNpIHJ1bWFoIHRhbmdnYSBkZW5nYW4gcmlzaWtvIGJhY2tsb2cgc2VydGEgbWVuZHVrdW5nIHBlcnVtdXNhbiBrZWJpamFrYW4gcGVydW1haGFuIHlhbmcgbGViaWggdGVwYXQgc2FzYXJhbi4NCg0KYGBge3J9DQpkdHJhaW4gPC0geGdiLkRNYXRyaXgoZGF0YSA9IFhfdHJhaW4sIGxhYmVsID0geV90cmFpbikNCmR0ZXN0ICA8LSB4Z2IuRE1hdHJpeChkYXRhID0gWF90ZXN0LCBsYWJlbCA9IHlfdGVzdCkNCg0KcGFyYW1zIDwtIGxpc3QoDQogIG9iamVjdGl2ZSA9ICJiaW5hcnk6bG9naXN0aWMiLA0KICBldmFsX21ldHJpYyA9ICJhdWMiLA0KICBtYXhfZGVwdGggPSA2LA0KICBldGEgPSAwLjEsDQogIHN1YnNhbXBsZSA9IDAuOCwNCiAgY29sc2FtcGxlX2J5dHJlZSA9IDAuOA0KKQ0KDQptb2RlbF94Z2IgPC0geGdiLnRyYWluKA0KICBwYXJhbXMgPSBwYXJhbXMsDQogIGRhdGEgPSBkdHJhaW4sDQogIG5yb3VuZHMgPSAxMDAsDQogIHdhdGNobGlzdCA9IGxpc3QodHJhaW4gPSBkdHJhaW4sIHRlc3QgPSBkdGVzdCksDQogIGVhcmx5X3N0b3BwaW5nX3JvdW5kcyA9IDEwLA0KICBwcmludF9ldmVyeV9uID0gMjANCikNCmBgYA0KDQoNCkhhc2lsIHBlbGF0aWhhbiBtb2RlbCBYR0Jvb3N0IG1lbnVuanVra2FuIGJhaHdhIG5pbGFpICoqQXJlYSBVbmRlciBDdXJ2ZSAoQVVDKSoqIGJhaWsgcGFkYSBkYXRhIGxhdGloIG1hdXB1biBkYXRhIHVqaSBtZW5nYWxhbWkgcGVuaW5na2F0YW4gc2VjYXJhIGtvbnNpc3RlbiBzZWlyaW5nIGJlcnRhbWJhaG55YSBqdW1sYWggaXRlcmFzaSAoYm9vc3Rpbmcgcm91bmRzKS4gUGFkYSBpdGVyYXNpIGF3YWwsIG5pbGFpIEFVQyBiZXJhZGEgZGkga2lzYXJhbiAwLDg0NSBiYWlrIHVudHVrIGRhdGEgbGF0aWggbWF1cHVuIGRhdGEgdWppLCB5YW5nIG1lbmdpbmRpa2FzaWthbiBiYWh3YSBtb2RlbCBzdWRhaCBtZW1pbGlraSBrZW1hbXB1YW4gYXdhbCB5YW5nIGN1a3VwIGJhaWsgZGFsYW0gbWVtYmVkYWthbiBydW1haCB0YW5nZ2EgYmFja2xvZyBkYW4gdGlkYWsgYmFja2xvZy4gU2VpcmluZyBwcm9zZXMgcGVsYXRpaGFuLCBuaWxhaSBBVUMgbWVuaW5na2F0IHNlY2FyYSBiZXJ0YWhhcCBoaW5nZ2EgbWVuY2FwYWkgc2VraXRhciAwLDkyNCBwYWRhIGl0ZXJhc2kga2UtMTAwIHVudHVrIGRhdGEgbGF0aWggZGFuIDAsOTI1IHVudHVrIGRhdGEgdWppLg0KDQpOaWxhaSBBVUMgeWFuZyBtZW5kZWthdGkgMSBtZW51bmp1a2thbiBiYWh3YSBtb2RlbCBtZW1pbGlraSBrZW1hbXB1YW4gZGlza3JpbWluYXNpIHlhbmcgc2FuZ2F0IGJhaWsuIERhbGFtIGtvbnRla3MgaW5pLCBuaWxhaSBBVUMgc2VraXRhciAwLDky4oCTMCw5MyBtZW5naW5kaWthc2lrYW4gYmFod2EgbW9kZWwgbWFtcHUgbWVuZ2tsYXNpZmlrYXNpa2FuIHJ1bWFoIHRhbmdnYSBiYWNrbG9nIGRhbiB0aWRhayBiYWNrbG9nIGRlbmdhbiB0aW5na2F0IGFrdXJhc2kgeWFuZyB0aW5nZ2kuIFNlY2FyYSBwcmFrdGlzLCBoYWwgaW5pIGJlcmFydGkgYmFod2EgdGVyZGFwYXQgcHJvYmFiaWxpdGFzIGxlYmloIGRhcmkgOTIlIGJhaHdhIG1vZGVsIGFrYW4gbWVtYmVyaWthbiBza29yIHByb2JhYmlsaXRhcyB5YW5nIGxlYmloIHRpbmdnaSBrZXBhZGEgcnVtYWggdGFuZ2dhIHlhbmcgYmVuYXItYmVuYXIgbWVuZ2FsYW1pIGJhY2tsb2cgZGliYW5kaW5na2FuIHlhbmcgdGlkYWsuDQoNClBlcmJhbmRpbmdhbiBhbnRhcmEgbmlsYWkgQVVDIHBhZGEgZGF0YSBsYXRpaCAoYHRyYWluLWF1Y2ApIGRhbiBkYXRhIHVqaSAoYHRlc3QtYXVjYCkgbWVudW5qdWtrYW4gYmFod2Ega2VkdWEgbmlsYWkgdGVyc2VidXQgc2FuZ2F0IGJlcmRla2F0YW4gZGkgc2V0aWFwIGl0ZXJhc2kuIEhhbCBpbmkgbWVydXBha2FuIGluZGlrYXNpIGt1YXQgYmFod2EgbW9kZWwgdGlkYWsgbWVuZ2FsYW1pIF9vdmVyZml0dGluZ18sIGthcmVuYSBwZXJmb3JtYSBwYWRhIGRhdGEgeWFuZyB0aWRhayBkaWxhdGloIChkYXRhIHVqaSkgdGV0YXAgc2VqYWxhbiBkZW5nYW4gcGVyZm9ybWEgcGFkYSBkYXRhIGxhdGloLiBCYWhrYW4sIGRhbGFtIGJlYmVyYXBhIGl0ZXJhc2ksIG5pbGFpIEFVQyBwYWRhIGRhdGEgdWppIHNlZGlraXQgbGViaWggdGluZ2dpIGRpYmFuZGluZ2thbiBkYXRhIGxhdGloLCB5YW5nIG1lbnVuanVra2FuIGJhaHdhIG1vZGVsIG1lbWlsaWtpIGtlbWFtcHVhbiBnZW5lcmFsaXNhc2kgeWFuZyBiYWlrIHRlcmhhZGFwIGRhdGEgYmFydS4NCg0KIyBFdmFsdWFzaQ0KDQoNCg0KYGBge3J9DQpwcmVkX3Byb2IgPC0gcHJlZGljdChtb2RlbF94Z2IsIGR0ZXN0KQ0KcHJlZF9jbGFzcyA8LSBpZmVsc2UocHJlZF9wcm9iID4gMC41LCAxLCAwKQ0KDQpjb25mdXNpb25NYXRyaXgoYXMuZmFjdG9yKHByZWRfY2xhc3MpLCBhcy5mYWN0b3IoeV90ZXN0KSkNCg0Kcm9jX29iaiA8LSByb2MoeV90ZXN0LCBwcmVkX3Byb2IpDQphdWMocm9jX29iaikNCmBgYA0KDQpIYXNpbCBldmFsdWFzaSBtb2RlbCBtZW51bmp1a2thbiBiYWh3YSBwZXJmb3JtYSBrbGFzaWZpa2FzaSB5YW5nIGRpaGFzaWxrYW4gdGVyZ29sb25nIHNhbmdhdCBiYWlrLiBOaWxhaSBhY2N1cmFjeSBzZWJlc2FyIDAsOTEyNSBtZW5naW5kaWthc2lrYW4gYmFod2Egc2VraXRhciA5MSwyNSUgcHJlZGlrc2kgbW9kZWwgc2VzdWFpIGRlbmdhbiBrb25kaXNpIHNlYmVuYXJueWEuIE5pbGFpIGluaSBqYXVoIGxlYmloIHRpbmdnaSBkaWJhbmRpbmdrYW4gX05vIEluZm9ybWF0aW9uIFJhdGVfICgwLDcxOTkpLCB5YW5nIGJlcmFydGkgbW9kZWwgbWVtaWxpa2kga2VtYW1wdWFuIHByZWRpa3NpIHlhbmcgc2lnbmlmaWthbiBzZWNhcmEgc3RhdGlzdGlrIChwLXZhbHVlIDwgMi4yZS0xNikuIFNlbGFpbiBpdHUsIG5pbGFpIEthcHBhIHNlYmVzYXIgMCw3NjM1IG1lbnVuanVra2FuIHRpbmdrYXQga2VzZXBha2F0YW4geWFuZyBrdWF0IGFudGFyYSBoYXNpbCBwcmVkaWtzaSBkYW4gZGF0YSBha3R1YWwsIHNldGVsYWggbWVuZ29yZWtzaSBrZW11bmdraW5hbiBrZXNlc3VhaWFuIHlhbmcgdGVyamFkaSBzZWNhcmEga2ViZXR1bGFuLg0KDQpEYXJpIGNvbmZ1c2lvbiBtYXRyaXgsIHRlcmxpaGF0IGJhaHdhIG1vZGVsIHNhbmdhdCBiYWlrIGRhbGFtIG1lbmdpZGVudGlmaWthc2kga2VsYXMgdGlkYWsgYmFja2xvZyAoa2VsYXMgMCkgZGVuZ2FuIG5pbGFpIHNlbnNpdGl2aXR5IHNlYmVzYXIgMCw5OTE4LCB5YW5nIGJlcmFydGkgaGFtcGlyIHNlbHVydWggcnVtYWggdGFuZ2dhIHlhbmcgdGlkYWsgbWVuZ2FsYW1pIGJhY2tsb2cgYmVyaGFzaWwgZGlrZW5hbGkgZGVuZ2FuIGJlbmFyLiBOYW11biwga2VtYW1wdWFuIG1vZGVsIGRhbGFtIG1lbmRldGVrc2kgcnVtYWggdGFuZ2dhIGJhY2tsb2cgKGtlbGFzIDEpIHJlbGF0aWYgbGViaWggcmVuZGFoLCB0ZXJjZXJtaW4gZGFyaSBzcGVjaWZpY2l0eSBzZWJlc2FyIDAsNzA4NywgeWFuZyBtZW51bmp1a2thbiBtYXNpaCB0ZXJkYXBhdCBzZWJhZ2lhbiBydW1haCB0YW5nZ2EgYmFja2xvZyB5YW5nIHRpZGFrIHRlcmRldGVrc2kuIE1lc2tpcHVuIGRlbWlraWFuLCBuaWxhaSBiYWxhbmNlZCBhY2N1cmFjeSBzZWJlc2FyIDAsODUwMiBtZW51bmp1a2thbiBiYWh3YSBzZWNhcmEga2VzZWx1cnVoYW4gbW9kZWwgdGV0YXAgbWVtaWxpa2kgcGVyZm9ybWEgeWFuZyBzZWltYmFuZyBhbnRhcmEga2VkdWEga2VsYXMuDQoNCkxlYmloIGxhbmp1dCwgbmlsYWkgQXJlYSBVbmRlciBDdXJ2ZSAoQVVDKSBzZWJlc2FyIDAsOTI0NyBtZW5naW5kaWthc2lrYW4gYmFod2EgbW9kZWwgbWVtaWxpa2kga2VtYW1wdWFuIGRpc2tyaW1pbmFzaSB5YW5nIHNhbmdhdCBiYWlrIGRhbGFtIG1lbWJlZGFrYW4gcnVtYWggdGFuZ2dhIGJhY2tsb2cgZGFuIHRpZGFrIGJhY2tsb2cuIERlbmdhbiBwZXJmb3JtYSBpbmksIG1vZGVsIFhHQm9vc3QgZGFwYXQgZGlhbmdnYXAgY3VrdXAgYW5kYWwgdW50dWsgZGlndW5ha2FuIGRhbGFtIG1lbXByZWRpa3NpIHByb2JhYmlsaXRhcyBiYWNrbG9nIHBlcnVtYWhhbiBzZXJ0YSBtZW5kdWt1bmcgcGVuZW50dWFuIHByaW9yaXRhcyBrZWJpamFrYW4gYmVyYmFzaXMgZGF0YS4NCg0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCmxpYnJhcnkocFJPQykNCmxpYnJhcnkoZ2dwbG90MikNCg0Kcm9jX29iaiA8LSByb2MoeV90ZXN0LCBwcmVkX3Byb2IpDQoNCiMgUGxvdCBST0MNCnBsb3Qocm9jX29iaiwgDQogICAgIGNvbCA9ICJibHVlIiwgDQogICAgIGx3ZCA9IDIsDQogICAgIG1haW4gPSAiUk9DIEN1cnZlIC0gWEdCb29zdCBNb2RlbCIpDQoNCiMgVGFtYmFoa2FuIGdhcmlzIGRpYWdvbmFsIChyYW5kb20gbW9kZWwpDQphYmxpbmUoYSA9IDAsIGIgPSAxLCBsdHkgPSAyLCBjb2wgPSAicmVkIikNCg0KIyBUZWtzIEFVQw0KYXVjX3ZhbHVlIDwtIGF1Yyhyb2Nfb2JqKQ0KbGVnZW5kKCJib3R0b21yaWdodCIsIA0KICAgICAgIGxlZ2VuZCA9IHBhc3RlKCJBVUMgPSIsIHJvdW5kKGF1Y192YWx1ZSwgNCkpLA0KICAgICAgIGNvbCA9ICJibHVlIiwgDQogICAgICAgbHdkID0gMikNCmBgYA0KDQojIEZlYXR1cmUgSW1wb3J0YW5jZQ0KDQpgYGB7cn0NCmltcG9ydGFuY2VfbWF0cml4IDwtIHhnYi5pbXBvcnRhbmNlKG1vZGVsID0gbW9kZWxfeGdiKQ0KeGdiLnBsb3QuaW1wb3J0YW5jZShpbXBvcnRhbmNlX21hdHJpeCkNCmBgYA0KDQpHcmFmaWsgbWVudW5qdWtrYW4gdGluZ2thdCBrZXBlbnRpbmdhbiByZWxhdGlmIChfaW1wb3J0YW5jZV8pIGRhcmkgbWFzaW5nLW1hc2luZyB2YXJpYWJlbCBkYWxhbSBtZW1wcmVkaWtzaSBiYWNrbG9nIHBlcnVtYWhhbi4gU2VtYWtpbiBwYW5qYW5nIGJhciwgc2VtYWtpbiBiZXNhciBrb250cmlidXNpIHZhcmlhYmVsIHRlcnNlYnV0IGRhbGFtIG1lbmluZ2thdGthbiBha3VyYXNpIG1vZGVsLg0KDQpWYXJpYWJlbCB5YW5nIHBhbGluZyBkb21pbmFuIGFkYWxhaCBgcjE2MTRhYCAoYWtzZXMgc2FuaXRhc2kpLCBkaWlrdXRpIG9sZWggYHIxNjA2YCAoamVuaXMgYXRhcCkgZGFuIGByMTYwMmAgKHN0YXR1cyBrZXBlbWlsaWthbiBydW1haCkuIEhhbCBpbmkgbWVuZ2luZGlrYXNpa2FuIGJhaHdhIGtvbmRpc2kgc2FuaXRhc2kgbWVydXBha2FuIGZha3RvciBwYWxpbmcgcGVudGluZyBkYWxhbSBtZW5lbnR1a2FuIGFwYWthaCBzdWF0dSBydW1haCB0YW5nZ2EgbWVuZ2FsYW1pIGJhY2tsb2cuIFNlbGFuanV0bnlhLCBrb25kaXNpIGZpc2lrIGJhbmd1bmFuIHNlcGVydGkgYXRhcCwgc2VydGEgc3RhdHVzIGtlcGVtaWxpa2FuIHJ1bWFoLCBqdWdhIG1lbWlsaWtpIHBlbmdhcnVoIHlhbmcgc2lnbmlmaWthbiB0ZXJoYWRhcCBzdGF0dXMga2VsYXlha2h1bmlhbi4gVmFyaWFiZWwgYGx1YXNfY2FwYCAobHVhcyBsYW50YWkgcGVyIGthcGl0YSkgZGFuIGByMTYxMGFgIChha3NlcyBhaXIgbWludW0pIGp1Z2EgbWVtaWxpa2kga29udHJpYnVzaSB5YW5nIGN1a3VwIGJlc2FyLCB5YW5nIG1lbnVuanVra2FuIGJhaHdhIGFzcGVrIGtlcGFkYXRhbiBodW5pYW4gZGFuIGFrc2VzIGFpciBsYXlhayBtZXJ1cGFrYW4gaW5kaWthdG9yIHBlbnRpbmcgZGFsYW0gbWVuZW50dWthbiBrdWFsaXRhcyBwZXJ1bWFoYW4uDQoNCg0KIyBQcm9iYWJpbGl0eSBCYWNrbG9nDQoNCg0KYGBge3J9DQpkYXRha3UkcHJvYl9iYWNrbG9nIDwtIHByZWRpY3QobW9kZWxfeGdiLCB4Z2IuRE1hdHJpeChYKSkNCmhlYWQoZGF0YWt1JHByb2JfYmFja2xvZywgMTUpDQpgYGANCg0KS29kZSBgZGF0YWt1JHByb2JfYmFja2xvZyA8LSBwcmVkaWN0KG1vZGVsX3hnYiwgeGdiLkRNYXRyaXgoWCkpYCBkaWd1bmFrYW4gdW50dWsgbWVuZ2hhc2lsa2FuIHByb2JhYmlsaXRhcyBiYWNrbG9nIHBlcnVtYWhhbiBwYWRhIHNldGlhcCBydW1haCB0YW5nZ2EgYmVyZGFzYXJrYW4gbW9kZWwgWEdCb29zdCB5YW5nIHRlbGFoIGRpbGF0aWguIE5pbGFpIHlhbmcgZGloYXNpbGthbiBiZXJhZGEgcGFkYSByZW50YW5nIDAgaGluZ2dhIDEsIGRpIG1hbmEgc2VtYWtpbiBtZW5kZWthdGkgMSBtZW51bmp1a2thbiBzZW1ha2luIHRpbmdnaSBrZW11bmdraW5hbiBydW1haCB0YW5nZ2EgdGVyc2VidXQgbWVuZ2FsYW1pIGJhY2tsb2cuIE5pbGFpIHByb2JhYmlsaXRhcyBpbmkga2VtdWRpYW4gZGlzaW1wYW4gZGFsYW0gdmFyaWFiZWwgYmFydSBwcm9iX2JhY2tsb2csIHNlaGluZ2dhIG1lbXVuZ2tpbmthbiBhbmFsaXNpcyB5YW5nIGxlYmloIGRldGFpbCBkaWJhbmRpbmdrYW4gc2VrYWRhciBrbGFzaWZpa2FzaSBiaW5lciAoYmFja2xvZyB2cyB0aWRhayBiYWNrbG9nKS4NCg0KSGFzaWwgaGVhZChkYXRha3UkcHJvYl9iYWNrbG9nLCAxNSkgbWVuYW1waWxrYW4gMTUgb2JzZXJ2YXNpIHBlcnRhbWEgZGFyaSBwcm9iYWJpbGl0YXMgdGVyc2VidXQuIFRlcmxpaGF0IGJhaHdhIHRlcmRhcGF0IHZhcmlhc2kgcmlzaWtvIHlhbmcgY3VrdXAgbGViYXIgYW50YXIgcnVtYWggdGFuZ2dhLiBNaXNhbG55YSwgbmlsYWkgc2FuZ2F0IHJlbmRhaCBzZXBlcnRpIDAsMDAwMTkgYXRhdSAwLDAwMDc2IG1lbnVuanVra2FuIHJ1bWFoIHRhbmdnYSBkZW5nYW4gcmlzaWtvIGJhY2tsb2cgeWFuZyBoYW1waXIgdGlkYWsgYWRhLCBzZW1lbnRhcmEgbmlsYWkgc2FuZ2F0IHRpbmdnaSBzZXBlcnRpIDAsOTk5MDcgZGFuIDAsOTQzMDQgbWVuZ2luZGlrYXNpa2FuIHJ1bWFoIHRhbmdnYSBkZW5nYW4ga2VtdW5na2luYW4gYmFja2xvZyB5YW5nIHNhbmdhdCBiZXNhci4gTmlsYWkgbWVuZW5nYWggc2VwZXJ0aSAwLDEw4oCTMCwxOSBtZW5jZXJtaW5rYW4gcmlzaWtvIHJlbmRhaCBoaW5nZ2Egc2VkYW5nLCBzZWRhbmdrYW4gbmlsYWkgZGkgYXRhcyAwLDkwIGRhcGF0IGRpa2F0ZWdvcmlrYW4gc2ViYWdhaSBwcmlvcml0YXMgdGluZ2dpIHVudHVrIGludGVydmVuc2kuDQoNCkRlbmdhbiBhZGFueWEgcHJvYmFiaWxpdGFzIGluaSwgbW9kZWwgdGlkYWsgaGFueWEgbWVtYmVyaWthbiBrZXB1dHVzYW4ga2xhc2lmaWthc2ksIHRldGFwaSBqdWdhIG1lbnllZGlha2FuIHNrb3IgcmlzaWtvIHlhbmcgbGViaWggZ3JhbnVsYXIuIEhhbCBpbmkgc2FuZ2F0IGJlcm1hbmZhYXQgZGFsYW0ga29udGVrcyBrZWJpamFrYW4gcGVydW1haGFuLCBrYXJlbmEgbWVtdW5na2lua2FuIHBlbWVyaW50YWggYXRhdSBwZW1hbmdrdSBrZXBlbnRpbmdhbiB1bnR1ayBtZWxha3VrYW4gdGFyZ2V0aW5nIHByb2dyYW0gc2VjYXJhIGxlYmloIHRlcGF0IHNhc2FyYW4sIG1pc2FsbnlhIGRlbmdhbiBtZW1wcmlvcml0YXNrYW4gcnVtYWggdGFuZ2dhIGRlbmdhbiBwcm9iYWJpbGl0YXMgYmFja2xvZyB0ZXJ0aW5nZ2kgc2ViYWdhaSBwZW5lcmltYSBiYW50dWFuIHBlcnVtYWhhbi4NCg0KYGBge3IsIGVjaG89RkFMU0V9DQpnZ3Bsb3QoZGF0YWt1LCBhZXMoeCA9IHByb2JfYmFja2xvZykpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDMwLCBmaWxsID0gInN0ZWVsYmx1ZSIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJEaXN0cmlidXNpIFByb2JhYmlsaXRhcyBCYWNrbG9nIChYR0Jvb3N0KSIsDQogICAgeCA9ICJQcm9iYWJpbGl0YXMiLA0KICAgIHkgPSAiRnJla3VlbnNpIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KIyBfUmVmZXJlbmNlc18NCg0KWzFdIENoZW4sIFQuLCAmIEd1ZXN0cmluLCBDLiAoMjAxNikuIFhHQm9vc3Q6IEEgc2NhbGFibGUgdHJlZSBib29zdGluZyBzeXN0ZW0uIFByb2NlZWRpbmdzIG9mIHRoZSAyMm5kIEFDTSBTSUdLREQgSW50ZXJuYXRpb25hbCBDb25mZXJlbmNlIG9uIEtub3dsZWRnZSBEaXNjb3ZlcnkgYW5kIERhdGEgTWluaW5nLCA3ODXigJM3OTQuDQoNClsyXSBGcmllZG1hbiwgSi4gSC4gKDIwMDEpLiBHcmVlZHkgZnVuY3Rpb24gYXBwcm94aW1hdGlvbjogQSBncmFkaWVudCBib29zdGluZyBtYWNoaW5lLiBBbm5hbHMgb2YgU3RhdGlzdGljcywgMjkoNSksIDExODnigJMxMjMyLg0KDQpbM10gSmFtZXMsIEcuLCBXaXR0ZW4sIEQuLCBIYXN0aWUsIFQuLCAmIFRpYnNoaXJhbmksIFIuICgyMDIxKS4gQW4gaW50cm9kdWN0aW9uIHRvIHN0YXRpc3RpY2FsIGxlYXJuaW5nOiBXaXRoIGFwcGxpY2F0aW9ucyBpbiBSICgybmQgZWQuKS4gU3ByaW5nZXIuDQoNCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCj4gRGlyZWt0b3JhdCBTdGF0aXN0aWsgS2VzZWphaHRlcmFhbiBSYWt5YXQsIEJQUywgc2FwdGFoYXNAYnBzLmdvLmlkDQoNCg0KDQoNCg==