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)

1 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

2 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]

3 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.

4 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

5 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.

6 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.

7 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,

LS0tDQp0aXRsZTogIlByZWRpY3RpbmcgSG91c2luZyBCYWNrbG9nIGluIEluZG9uZXNpYSB1c2luZyBYR0Jvb3N0IChTdXNlbmFzIERhdGEpIg0KYXV0aG9yOiAiU2FwdGEgSGFzdGhvIFBvbmNvIg0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogc2hvdw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdGhlbWU6IGpvdXJuYWwNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogIHdvcmRfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCi0tLQ0KDQpgYGB7PWh0bWx9DQo8c3R5bGU+DQpib2R5ew0KdGV4dC1hbGlnbjoganVzdGlmeX0NCjwvc3R5bGU+DQpgYGANCg0KRXh0cmVtZSBHcmFkaWVudCBCb29zdGluZyAoWEdCb29zdCkgbWVydXBha2FuIGFsZ29yaXRtYSBtYWNoaW5lIGxlYXJuaW5nIGJlcmJhc2lzIF9lbnNlbWJsZSBsZWFybmluZ18gZGVuZ2FuIHBlbmRla2F0YW4gX2Jvb3N0aW5nXywgeWFuZyBtZW5nZ2FidW5na2FuIGJhbnlhayBtb2RlbCBzZWRlcmhhbmEgKHVtdW1ueWEgX2RlY2lzaW9uIHRyZWVfKSBzZWNhcmEgYmVydGFoYXAgdW50dWsgbWVtYmVudHVrIG1vZGVsIHlhbmcgbGViaWgga3VhdCBkYW4gYWt1cmF0LiBQcmluc2lwIHV0YW1hIGRhcmkgbWV0b2RlIGluaSBhZGFsYWggc2V0aWFwIG1vZGVsIGJhcnUgZGliYW5ndW4gdW50dWsgbWVtcGVyYmFpa2kga2VzYWxhaGFuIGRhcmkgbW9kZWwgc2ViZWx1bW55YSBtZWxhbHVpIG9wdGltaXNhc2kgYmVyYmFzaXMgX2dyYWRpZW50IGRlc2NlbnRfIHRlcmhhZGFwIGZ1bmdzaSBvYmpla3RpZiB5YW5nIG1lbmNha3VwIGtvbXBvbmVuIF9sb3NzIGZ1bmN0aW9uXyBkYW4gcmVndWxhcmlzYXNpLiBYR0Jvb3N0IG1lcnVwYWthbiBwZW5nZW1iYW5nYW4gZGFyaSBtZXRvZGUgX0dyYWRpZW50IEJvb3N0aW5nXyB5YW5nIGRpcmFuY2FuZyBsZWJpaCBlZmlzaWVuIGRhbiBfc2NhbGFibGVfLCBzZWhpbmdnYSBtYW1wdSBtZW5hbmdhbmkgZGF0YSBiZXJ1a3VyYW4gYmVzYXIsIG1lbmdha29tb2Rhc2kgX21pc3NpbmcgdmFsdWVzXywgc2VydGEgbWVuZ3VyYW5naSByaXNpa28gX292ZXJmaXR0aW5nXyBtZWxhbHVpIHBlbmdhdHVyYW4gcGFyYW1ldGVyIHNlcGVydGkga2VkYWxhbWFuIHBvaG9uIChgbWF4X2RlcHRoYCksIGxhanUgcGVtYmVsYWphcmFuIChgZXRhYCksIGRhbiBzdWJzYW1wbGluZyAoQ2hlbiAmIEd1ZXN0cmluLCAyMDE2OyBGcmllZG1hbiwgMjAwMSkuDQoNCkRhbGFtIHByYWt0aWtueWEsIFhHQm9vc3QgYmFueWFrIGRpZ3VuYWthbiB1bnR1ayBwZXJtYXNhbGFoYW4gX3N1cGVydmlzZWQgbGVhcm5pbmdfIHNlcGVydGkga2xhc2lmaWthc2kgZGFuIHJlZ3Jlc2ksIGtodXN1c255YSBrZXRpa2EgZGF0YSBtZW1pbGlraSBodWJ1bmdhbiB5YW5nIGtvbXBsZWtzIGRhbiB0aWRhayBsaW5lYXIuIEFsZ29yaXRtYSBpbmkgc2FuZ2F0IGVmZWt0aWYgZGFsYW0gbWVuZ2hhc2lsa2FuIHByZWRpa3NpIGRlbmdhbiB0aW5na2F0IGFrdXJhc2kgdGluZ2dpLCBzZWhpbmdnYSBzZXJpbmcgZGlndW5ha2FuIGRhbGFtIGJlcmJhZ2FpIGJpZGFuZyBzZXBlcnRpIGVrb25vbWksIGtlc2VoYXRhbiwgaGluZ2dhIGFuYWxpc2lzIHNvc2lhbCwgdGVybWFzdWsgZGFsYW0gbWVtcHJlZGlrc2kgYmFja2xvZyBrZWxheWFraHVuaWFuIGJlcmJhc2lzIGRhdGEgcnVtYWggdGFuZ2dhLiBYR0Jvb3N0IHVtdW1ueWEgZGlndW5ha2FuIGtldGlrYSB0ZXJzZWRpYSBkYXRhc2V0IGJlcnVrdXJhbiBiZXNhciBkZW5nYW4gYmFueWFrIHZhcmlhYmVsIHByZWRpa3Rvciwgc2VydGEga2V0aWthIHR1anVhbiB1dGFtYSBhZGFsYWggbWVtcGVyb2xlaCBwZXJmb3JtYSBwcmVkaWtzaSB5YW5nIG9wdGltYWwuIE1lc2tpcHVuIGRlbWlraWFuLCBtb2RlbCBpbmkgY2VuZGVydW5nIGxlYmloIGtvbXBsZWtzIHVudHVrIGRpaW50ZXJwcmV0YXNpa2FuIGRpYmFuZGluZ2thbiBtZXRvZGUgc3RhdGlzdGlrIHRyYWRpc2lvbmFsLCBzZWhpbmdnYSBwZW5nZ3VuYWFubnlhIHNlcmluZyBkaWtvbWJpbmFzaWthbiBkZW5nYW4gdGVrbmlrIGludGVycHJldGFiaWxpdGFzIHRhbWJhaGFuLiBEZW5nYW4ga2V1bmdndWxhbiBkYWxhbSBha3VyYXNpLCBlZmlzaWVuc2ksIGRhbiBrZW1hbXB1YW4gbWVuYW5na2FwIHBvbGEgbm9uLWxpbmVhciwgWEdCb29zdCBtZW5qYWRpIHNhbGFoIHNhdHUgbWV0b2RlIHlhbmcgcGFsaW5nIHBvcHVsZXIgZGFsYW0gYW5hbGlzaXMgZGF0YSBtb2Rlcm4gKEphbWVzIGV0IGFsLiwgMjAyMSkuDQoNCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9VFJVRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCmBgYA0KDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBlY2hvPUZBTFNFfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHN1cnZleSkNCmxpYnJhcnkoamFuaXRvcikNCmxpYnJhcnkoc2NhbGVzKQ0KbGlicmFyeShoYXZlbikNCmxpYnJhcnkob3Blbnhsc3gpDQpsaWJyYXJ5KHNmKQ0KbGlicmFyeSh2aXJpZGlzKQ0KYGBgDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0Kc2V0d2QoIkQ6XFwyLiBQZW5nZW1iYW5nYW4gZGlyaVxcMSBFeGVyY2lzZSBCYWd1c1xcSG91c2luZyBBbmFseXNpcyIpDQpgYGANCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89RkFMU0V9DQpkYXRha3UgPC0gcmVhZF9zYXYoIktPUjI1R0FCXzAzMDlfSE9VU0lORy5zYXYiKSAlPiUNCiAgY2xlYW5fbmFtZXMoKQ0KYGBgDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KIyBCYWNrbG9nIEtlbGF5YWtodW5pYW4NCmRhdGFrdSA8LSBkYXRha3UgJT4lDQogIG11dGF0ZShrYWJ1ID0gcjEwMSoxMDAgKyByMTAyKSAlPiUNCiAgcmVuYW1lKHByb3Y9InIxMDEiLCBrYWI9InIxMDIiKSAlPiUNCiAgbXV0YXRlKGRlbm9tPTEwMCkgJT4lDQogIG11dGF0ZShpbmRpYzFfbGF5YWsgPSBkcGx5cjo6Y2FzZV93aGVuKGRhdGFrdSRyMTYwOWE8PTMgJiBkYXRha3UkcjE2MDliPT0xICYgZGF0YWt1JHIxNjA5Yzw9Mn4xMDAsIChkYXRha3UkcjEwNSA9PTIgJiBkYXRha3UkcjE2MDlhPD0zICYgZGF0YWt1JHIxNjA5Yj09MSAmIGRhdGFrdSRyMTYwOWM9PTR+MTAwKSksDQogIGluZGljMV9sYXlhaz1jYXNlX3doZW4oaW5kaWMxX2xheWFrPT0xMDB+MTAwLGlzLm5hKGluZGljMV9sYXlhayl+MCkpICU+JQ0KICBtdXRhdGUoZHJpbmt3PWNhcjo6cmVjb2RlKGRhdGFrdSRyMTYxMGEsIjM6NT0xMDA7Nz0xMDA7MTA9MTAwO2Vsc2U9MCIpKSAlPiUNCiAgbXV0YXRlKGJvdHRsZT1jYXI6OnJlY29kZShkYXRha3UkcjE2MTBhLCIxOjI9MTAwO2Vsc2U9MCIpKSAlPiUNCiAgbXV0YXRlKGJhdGhpbmc9Y2FyOjpyZWNvZGUoZGF0YWt1JHIxNjE0YSwiMzo1PTEwMDs3PTEwMDsxMD0xMDA7ZWxzZT0wIikpICU+JQ0KICBtdXRhdGUoaW5kaWMyX2xheWFrID0gZHBseXI6OmNhc2Vfd2hlbihkcmlua3c9PTEwMCB8IChib3R0bGU9PTEwMCAmIGJhdGhpbmc9PTEwMCl+MTAwKSkgJT4lDQogIG11dGF0ZShpbmRpYzJfbGF5YWsgPSBpZmVsc2UoaXMubmEoaW5kaWMyX2xheWFrKSwgMCwgaW5kaWMyX2xheWFrKSkgJT4lDQogIG11dGF0ZShsdWFzX2NhcD1yMTYwNC9yMzAxKSAlPiUNCiAgbXV0YXRlKGluZGljM19sYXlhayA9IGRwbHlyOjpjYXNlX3doZW4obHVhc19jYXA+PTcuMjB+MTAwLGx1YXNfY2FwPDcuMjB+MCkpICU+JQ0KICBtdXRhdGUocm9vZj1jYXI6OnJlY29kZShkYXRha3UkcjE2MDYsIjE6ND0xMDA7ZWxzZT0wIikpICU+JQ0KICBtdXRhdGUod2FsbD1jYXI6OnJlY29kZShkYXRha3UkcjE2MDcsIjE6Mz0xMDA7ZWxzZT0wIikpICU+JQ0KICBtdXRhdGUoZmxvb3I9Y2FyOjpyZWNvZGUoZGF0YWt1JHIxNjA4LCIxOjU9MTAwO2Vsc2U9MCIpKSAlPiUNCiAgbXV0YXRlKGluZGljNF9sYXlhayA9IGRwbHlyOjpjYXNlX3doZW4oKHJvb2Y9PTEwMCAmIGZsb29yPT0xMDAgJiB3YWxsPT0xMDApfjEwMCkpICU+JQ0KICBtdXRhdGUoaW5kaWM0X2xheWFrID0gaWZlbHNlKGlzLm5hKGluZGljNF9sYXlhayksIDAsIGluZGljNF9sYXlhaykpDQoNCmRhdGFrdSA8LSBkYXRha3UgJT4lDQogIG11dGF0ZShSTEggPSBkcGx5cjo6Y2FzZV93aGVuKChpbmRpYzFfbGF5YWs9PTEwMCAmIGluZGljMl9sYXlhaz09MTAwICYgaW5kaWMzX2xheWFrPT0xMDAgJiBpbmRpYzRfbGF5YWs9PTEwMCl+MTAwKSkgJT4lDQogIG11dGF0ZShSTEggPSBpZmVsc2UoaXMubmEoUkxIKSwgMCwgUkxIKSkgJT4lIA0KICBtdXRhdGUoDQogICAgQkFDS19MT0cgPSBpZmVsc2UocjE2MDI9PSAxICYgUkxIID09IDAsIDEwMCwgMCksDQogICAgQkFDS19MT0dfTEFCRUwgPSBmYWN0b3IoDQogICAgICBCQUNLX0xPRywNCiAgICAgIGxldmVscyA9IGMoMCwgMTAwKSwNCiAgICAgIGxhYmVscyA9IGMoIlRpZGFrIiwgIkJhY2tsb2ciKQ0KICAgICkNCiAgKQ0KYGBgDQogIA0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1GQUxTRX0NCmxpYnJhcnkoY2FyZXQpDQpsaWJyYXJ5KHhnYm9vc3QpDQpsaWJyYXJ5KE1hdHJpeCkNCmxpYnJhcnkocFJPQykNCmxpYnJhcnkocGFyYWxsZWxseSkNCmBgYA0KDQoNCiMgUHJlcGFyZSBEYXRhIE1MDQoNCmBgYHtyfQ0KZGF0YV9tbCA8LSBkYXRha3UgJT4lDQogIG11dGF0ZSgNCiAgICBiYWNrbG9nX21sID0gaWZlbHNlKEJBQ0tfTE9HID09IDEwMCwgMSwgMCkNCiAgKSAlPiUNCiAgc2VsZWN0KA0KICAgIGJhY2tsb2dfbWwsDQogICAgcjE2MDIsICAgICAgICAjIHN0YXR1cyBrZXBlbWlsaWthbg0KICAgIGx1YXNfY2FwLA0KICAgIHIxNjA2LCAgICAgICAgIyBhdGFwDQogICAgcjE2MDcsICAgICAgICAjIGRpbmRpbmcNCiAgICByMTYwOCwgICAgICAgICMgbGFudGFpDQogICAgcjE2MTBhLCAgICAgICAjIGFpciBtaW51bQ0KICAgIHIxNjE0YSwgICAgICAgIyBzYW5pdGFzaQ0KICAgIHIzMDEsICAgICAgICAgIyBqdW1sYWggQVJUDQogICAgcjEwNSAgICAgICAgICAjIGthcmFrdGVyaXN0aWsgS1JUDQogICkgJT4lDQogIGRyb3BfbmEoKQ0KYGBgDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KIyBEdW1teSBFbmNvZGluZw0KZHVtbWllcyA8LSBkdW1teVZhcnMoYmFja2xvZ19tbCB+IC4sIGRhdGEgPSBkYXRhX21sKQ0KWCA8LSBwcmVkaWN0KGR1bW1pZXMsIG5ld2RhdGEgPSBkYXRhX21sKSAlPiUgYXMubWF0cml4KCkNCnkgPC0gZGF0YV9tbCRiYWNrbG9nX21sDQpoZWFkKFgpDQpoZWFkKHkpDQpgYGANCg0KIyBUcmFpbi1UZXN0IFNwbGl0DQoNClBhZGEgdGFoYXAgaW5pIGRpbGFrdWthbiBwcm9zZXMgcGVtYmFnaWFuIGRhdGEgbWVuamFkaSBkdWEgYmFnaWFuLCB5YWl0dSBkYXRhIGxhdGloIChfdHJhaW5pbmcgc2V0XykgZGFuIGRhdGEgdWppIChfdGVzdGluZyBzZXRfKS4gUHJvc2VzIGluaSBkaWF3YWxpIGRlbmdhbiBmdW5nc2kgYHNldC5zZWVkKDEyMylgIHlhbmcgYmVydHVqdWFuIHVudHVrIG1lbWFzdGlrYW4gYmFod2EgaGFzaWwgcGVtYmFnaWFuIGRhdGEgYmVyc2lmYXQgX3JlcHJvZHVjaWJsZV8sIGFydGlueWEgaGFzaWwgeWFuZyBkaXBlcm9sZWggYWthbiB0ZXRhcCBzYW1hIHNldGlhcCBrYWxpIGtvZGUgZGlqYWxhbmthbi4gU2VsYW5qdXRueWEsIGZ1bmdzaSBgY3JlYXRlRGF0YVBhcnRpdGlvbih5LCBwID0gMC44LCBsaXN0ID0gRkFMU0UpYCBkaWd1bmFrYW4gdW50dWsgbWVtYmFnaSBkYXRhIGJlcmRhc2Fya2FuIHByb3BvcnNpIDgwJSB1bnR1ayBkYXRhIGxhdGloIGRhbiAyMCUgdW50dWsgZGF0YSB1amksIGRlbmdhbiBtZW1wZXJ0aW1iYW5na2FuIGRpc3RyaWJ1c2kgdmFyaWFiZWwgdGFyZ2V0ICh5KSBhZ2FyIHRldGFwIHNlaW1iYW5nIChfc3RyYXRpZmllZCBzYW1wbGluZ18pLiBJbmRla3MgaGFzaWwgcGVtYmFnaWFuIHRlcnNlYnV0IGtlbXVkaWFuIGRpZ3VuYWthbiB1bnR1ayBtZW1pc2Foa2FuIG1hdHJpa3MgZml0dXIgKGBYYCkgZGFuIHZhcmlhYmVsIHRhcmdldCAoYHlgKSBtZW5qYWRpIGBYX3RyYWluYCwgYFhfdGVzdGAsIGB5X3RyYWluYCwgZGFuIGB5X3Rlc3RgLg0KDQpgYGB7cn0NCnNldC5zZWVkKDEyMykNCnRyYWluSW5kZXggPC0gY3JlYXRlRGF0YVBhcnRpdGlvbih5LCBwID0gMC44LCBsaXN0ID0gRkFMU0UpDQoNClhfdHJhaW4gPC0gWFt0cmFpbkluZGV4LCBdDQpYX3Rlc3QgIDwtIFhbLXRyYWluSW5kZXgsIF0NCnlfdHJhaW4gPC0geVt0cmFpbkluZGV4XQ0KeV90ZXN0ICA8LSB5Wy10cmFpbkluZGV4XQ0KYGBgDQoNCg0KDQoNCiMgTW9kZWwgWEdCT09TVA0KDQpNb2RlbCBtYWNoaW5lIGxlYXJuaW5nIHlhbmcgZGlndW5ha2FuIGFkYWxhaCBhbGdvcml0bWEgKipFeHRyZW1lIEdyYWRpZW50IEJvb3N0aW5nIChYR0Jvb3N0KSoqLiBEYXRhIGxhdGloIGRhbiBkYXRhIHVqaSB0ZXJsZWJpaCBkYWh1bHUgZGlrb252ZXJzaSBrZSBkYWxhbSBmb3JtYXQgYHhnYi5ETWF0cml4YCwgeWFpdHUgc3RydWt0dXIgZGF0YSB5YW5nIGRpb3B0aW1hbGthbiB1bnR1ayBrb21wdXRhc2kgWEdCb29zdC4gU2VsYW5qdXRueWEsIGRpdGVudHVrYW4gcGFyYW1ldGVyIG1vZGVsIHNlcGVydGkgb2JqZWN0aXZlID0gImJpbmFyeTpsb2dpc3RpYyIgdW50dWsga2xhc2lmaWthc2kgYmluZXIsIHNlcnRhIGV2YWxfbWV0cmljID0gImF1YyIgdW50dWsgbWVuZ3VrdXIga2VtYW1wdWFuIG1vZGVsIGRhbGFtIG1lbWJlZGFrYW4gcnVtYWggdGFuZ2dhIGJhY2tsb2cgZGFuIHRpZGFrIGJhY2tsb2cuIFBhcmFtZXRlciBsYWluIHNlcGVydGkgX21heF9kZXB0aCwgZXRhLCBzdWJzYW1wbGVfLCBkYW4gX2NvbHNhbXBsZV9ieXRyZWVfIGRpZ3VuYWthbiB1bnR1ayBtZW5nYXR1ciBrb21wbGVrc2l0YXMgbW9kZWwgYWdhciBwZW1iZWxhamFyYW4gbGViaWggc3RhYmlsIGRhbiBtZW5ndXJhbmdpIHJpc2lrbyBvdmVyZml0dGluZy4NCg0KUHJvc2VzIHBlbGF0aWhhbiBkaWxha3VrYW4gbWVuZ2d1bmFrYW4gZnVuZ3NpIGB4Z2IudHJhaW5gIGRlbmdhbiBtYWtzaW11bSAxMDAgaXRlcmFzaSwgZGkgbWFuYSBwZXJmb3JtYSBtb2RlbCBkaW1vbml0b3IgcGFkYSBkYXRhIGxhdGloIGRhbiBkYXRhIHVqaSBtZWxhbHVpIF93YXRjaGxpc3RfLiBNZWthbmlzbWUgX2Vhcmx5IHN0b3BwaW5nXyBkaXRlcmFwa2FuIHVudHVrIG1lbmdoZW50aWthbiBwZWxhdGloYW4gc2VjYXJhIG90b21hdGlzIGppa2EgdGlkYWsgdGVyamFkaSBwZW5pbmdrYXRhbiBwZXJmb3JtYSBkYWxhbSBiZWJlcmFwYSBpdGVyYXNpLCBzZWhpbmdnYSBtb2RlbCB5YW5nIGRpaGFzaWxrYW4gdGV0YXAgb3B0aW1hbC4gVHVqdWFuIGRhcmkgdGFoYXAgaW5pIGFkYWxhaCBtZW1iYW5ndW4gbW9kZWwgcHJlZGlrdGlmIHlhbmcgbWFtcHUgbWVuYW5na2FwIGh1YnVuZ2FuIG5vbi1saW5lYXIgYW50YXIgdmFyaWFiZWwgZGFuIG1lbmdlc3RpbWFzaSBwcm9iYWJpbGl0YXMgYmFja2xvZyBwZXJ1bWFoYW4gc2VjYXJhIGFrdXJhdC4NCg0KSGFzaWxueWEgYWRhbGFoIG1vZGVsIHlhbmcgdGVsYWggdGVybGF0aWggZGFuIG1hbXB1IG1lbGFrdWthbiBwcmVkaWtzaSBkZW5nYW4gYmFpay4gUGVuaW5na2F0YW4gZGFuIGtlc3RhYmlsYW4gbmlsYWkgQVVDIHBhZGEgZGF0YSB1amkgbWVudW5qdWtrYW4gYmFod2EgbW9kZWwgYmVyaGFzaWwgbWVtcGVsYWphcmkgcG9sYSB5YW5nIHJlbGV2YW4gdGFucGEgbWVuZ2FsYW1pIG92ZXJmaXR0aW5nLiBEZW5nYW4gZGVtaWtpYW4sIG1vZGVsIFhHQm9vc3QgaW5pIGRhcGF0IGRpZ3VuYWthbiB1bnR1ayBtZW5naWRlbnRpZmlrYXNpIHJ1bWFoIHRhbmdnYSBkZW5nYW4gcmlzaWtvIGJhY2tsb2cgc2VydGEgbWVuZHVrdW5nIHBlcnVtdXNhbiBrZWJpamFrYW4gcGVydW1haGFuIHlhbmcgbGViaWggdGVwYXQgc2FzYXJhbi4NCg0KYGBge3J9DQpkdHJhaW4gPC0geGdiLkRNYXRyaXgoZGF0YSA9IFhfdHJhaW4sIGxhYmVsID0geV90cmFpbikNCmR0ZXN0ICA8LSB4Z2IuRE1hdHJpeChkYXRhID0gWF90ZXN0LCBsYWJlbCA9IHlfdGVzdCkNCg0KcGFyYW1zIDwtIGxpc3QoDQogIG9iamVjdGl2ZSA9ICJiaW5hcnk6bG9naXN0aWMiLA0KICBldmFsX21ldHJpYyA9ICJhdWMiLA0KICBtYXhfZGVwdGggPSA2LA0KICBldGEgPSAwLjEsDQogIHN1YnNhbXBsZSA9IDAuOCwNCiAgY29sc2FtcGxlX2J5dHJlZSA9IDAuOA0KKQ0KDQptb2RlbF94Z2IgPC0geGdiLnRyYWluKA0KICBwYXJhbXMgPSBwYXJhbXMsDQogIGRhdGEgPSBkdHJhaW4sDQogIG5yb3VuZHMgPSAxMDAsDQogIHdhdGNobGlzdCA9IGxpc3QodHJhaW4gPSBkdHJhaW4sIHRlc3QgPSBkdGVzdCksDQogIGVhcmx5X3N0b3BwaW5nX3JvdW5kcyA9IDEwLA0KICBwcmludF9ldmVyeV9uID0gMjANCikNCmBgYA0KDQoNCkhhc2lsIHBlbGF0aWhhbiBtb2RlbCBYR0Jvb3N0IG1lbnVuanVra2FuIGJhaHdhIG5pbGFpICoqQXJlYSBVbmRlciBDdXJ2ZSAoQVVDKSoqIGJhaWsgcGFkYSBkYXRhIGxhdGloIG1hdXB1biBkYXRhIHVqaSBtZW5nYWxhbWkgcGVuaW5na2F0YW4gc2VjYXJhIGtvbnNpc3RlbiBzZWlyaW5nIGJlcnRhbWJhaG55YSBqdW1sYWggaXRlcmFzaSAoYm9vc3Rpbmcgcm91bmRzKS4gUGFkYSBpdGVyYXNpIGF3YWwsIG5pbGFpIEFVQyBiZXJhZGEgZGkga2lzYXJhbiAwLDg0NSBiYWlrIHVudHVrIGRhdGEgbGF0aWggbWF1cHVuIGRhdGEgdWppLCB5YW5nIG1lbmdpbmRpa2FzaWthbiBiYWh3YSBtb2RlbCBzdWRhaCBtZW1pbGlraSBrZW1hbXB1YW4gYXdhbCB5YW5nIGN1a3VwIGJhaWsgZGFsYW0gbWVtYmVkYWthbiBydW1haCB0YW5nZ2EgYmFja2xvZyBkYW4gdGlkYWsgYmFja2xvZy4gU2VpcmluZyBwcm9zZXMgcGVsYXRpaGFuLCBuaWxhaSBBVUMgbWVuaW5na2F0IHNlY2FyYSBiZXJ0YWhhcCBoaW5nZ2EgbWVuY2FwYWkgc2VraXRhciAwLDkyNCBwYWRhIGl0ZXJhc2kga2UtMTAwIHVudHVrIGRhdGEgbGF0aWggZGFuIDAsOTI1IHVudHVrIGRhdGEgdWppLg0KDQpOaWxhaSBBVUMgeWFuZyBtZW5kZWthdGkgMSBtZW51bmp1a2thbiBiYWh3YSBtb2RlbCBtZW1pbGlraSBrZW1hbXB1YW4gZGlza3JpbWluYXNpIHlhbmcgc2FuZ2F0IGJhaWsuIERhbGFtIGtvbnRla3MgaW5pLCBuaWxhaSBBVUMgc2VraXRhciAwLDky4oCTMCw5MyBtZW5naW5kaWthc2lrYW4gYmFod2EgbW9kZWwgbWFtcHUgbWVuZ2tsYXNpZmlrYXNpa2FuIHJ1bWFoIHRhbmdnYSBiYWNrbG9nIGRhbiB0aWRhayBiYWNrbG9nIGRlbmdhbiB0aW5na2F0IGFrdXJhc2kgeWFuZyB0aW5nZ2kuIFNlY2FyYSBwcmFrdGlzLCBoYWwgaW5pIGJlcmFydGkgYmFod2EgdGVyZGFwYXQgcHJvYmFiaWxpdGFzIGxlYmloIGRhcmkgOTIlIGJhaHdhIG1vZGVsIGFrYW4gbWVtYmVyaWthbiBza29yIHByb2JhYmlsaXRhcyB5YW5nIGxlYmloIHRpbmdnaSBrZXBhZGEgcnVtYWggdGFuZ2dhIHlhbmcgYmVuYXItYmVuYXIgbWVuZ2FsYW1pIGJhY2tsb2cgZGliYW5kaW5na2FuIHlhbmcgdGlkYWsuDQoNClBlcmJhbmRpbmdhbiBhbnRhcmEgbmlsYWkgQVVDIHBhZGEgZGF0YSBsYXRpaCAoYHRyYWluLWF1Y2ApIGRhbiBkYXRhIHVqaSAoYHRlc3QtYXVjYCkgbWVudW5qdWtrYW4gYmFod2Ega2VkdWEgbmlsYWkgdGVyc2VidXQgc2FuZ2F0IGJlcmRla2F0YW4gZGkgc2V0aWFwIGl0ZXJhc2kuIEhhbCBpbmkgbWVydXBha2FuIGluZGlrYXNpIGt1YXQgYmFod2EgbW9kZWwgdGlkYWsgbWVuZ2FsYW1pIF9vdmVyZml0dGluZ18sIGthcmVuYSBwZXJmb3JtYSBwYWRhIGRhdGEgeWFuZyB0aWRhayBkaWxhdGloIChkYXRhIHVqaSkgdGV0YXAgc2VqYWxhbiBkZW5nYW4gcGVyZm9ybWEgcGFkYSBkYXRhIGxhdGloLiBCYWhrYW4sIGRhbGFtIGJlYmVyYXBhIGl0ZXJhc2ksIG5pbGFpIEFVQyBwYWRhIGRhdGEgdWppIHNlZGlraXQgbGViaWggdGluZ2dpIGRpYmFuZGluZ2thbiBkYXRhIGxhdGloLCB5YW5nIG1lbnVuanVra2FuIGJhaHdhIG1vZGVsIG1lbWlsaWtpIGtlbWFtcHVhbiBnZW5lcmFsaXNhc2kgeWFuZyBiYWlrIHRlcmhhZGFwIGRhdGEgYmFydS4NCg0KIyBFdmFsdWFzaQ0KDQoNCg0KYGBge3J9DQpwcmVkX3Byb2IgPC0gcHJlZGljdChtb2RlbF94Z2IsIGR0ZXN0KQ0KcHJlZF9jbGFzcyA8LSBpZmVsc2UocHJlZF9wcm9iID4gMC41LCAxLCAwKQ0KDQpjb25mdXNpb25NYXRyaXgoYXMuZmFjdG9yKHByZWRfY2xhc3MpLCBhcy5mYWN0b3IoeV90ZXN0KSkNCg0Kcm9jX29iaiA8LSByb2MoeV90ZXN0LCBwcmVkX3Byb2IpDQphdWMocm9jX29iaikNCmBgYA0KDQpIYXNpbCBldmFsdWFzaSBtb2RlbCBtZW51bmp1a2thbiBiYWh3YSBwZXJmb3JtYSBrbGFzaWZpa2FzaSB5YW5nIGRpaGFzaWxrYW4gdGVyZ29sb25nIHNhbmdhdCBiYWlrLiBOaWxhaSBhY2N1cmFjeSBzZWJlc2FyIDAsOTEyNSBtZW5naW5kaWthc2lrYW4gYmFod2Egc2VraXRhciA5MSwyNSUgcHJlZGlrc2kgbW9kZWwgc2VzdWFpIGRlbmdhbiBrb25kaXNpIHNlYmVuYXJueWEuIE5pbGFpIGluaSBqYXVoIGxlYmloIHRpbmdnaSBkaWJhbmRpbmdrYW4gX05vIEluZm9ybWF0aW9uIFJhdGVfICgwLDcxOTkpLCB5YW5nIGJlcmFydGkgbW9kZWwgbWVtaWxpa2kga2VtYW1wdWFuIHByZWRpa3NpIHlhbmcgc2lnbmlmaWthbiBzZWNhcmEgc3RhdGlzdGlrIChwLXZhbHVlIDwgMi4yZS0xNikuIFNlbGFpbiBpdHUsIG5pbGFpIEthcHBhIHNlYmVzYXIgMCw3NjM1IG1lbnVuanVra2FuIHRpbmdrYXQga2VzZXBha2F0YW4geWFuZyBrdWF0IGFudGFyYSBoYXNpbCBwcmVkaWtzaSBkYW4gZGF0YSBha3R1YWwsIHNldGVsYWggbWVuZ29yZWtzaSBrZW11bmdraW5hbiBrZXNlc3VhaWFuIHlhbmcgdGVyamFkaSBzZWNhcmEga2ViZXR1bGFuLg0KDQpEYXJpIGNvbmZ1c2lvbiBtYXRyaXgsIHRlcmxpaGF0IGJhaHdhIG1vZGVsIHNhbmdhdCBiYWlrIGRhbGFtIG1lbmdpZGVudGlmaWthc2kga2VsYXMgdGlkYWsgYmFja2xvZyAoa2VsYXMgMCkgZGVuZ2FuIG5pbGFpIHNlbnNpdGl2aXR5IHNlYmVzYXIgMCw5OTE4LCB5YW5nIGJlcmFydGkgaGFtcGlyIHNlbHVydWggcnVtYWggdGFuZ2dhIHlhbmcgdGlkYWsgbWVuZ2FsYW1pIGJhY2tsb2cgYmVyaGFzaWwgZGlrZW5hbGkgZGVuZ2FuIGJlbmFyLiBOYW11biwga2VtYW1wdWFuIG1vZGVsIGRhbGFtIG1lbmRldGVrc2kgcnVtYWggdGFuZ2dhIGJhY2tsb2cgKGtlbGFzIDEpIHJlbGF0aWYgbGViaWggcmVuZGFoLCB0ZXJjZXJtaW4gZGFyaSBzcGVjaWZpY2l0eSBzZWJlc2FyIDAsNzA4NywgeWFuZyBtZW51bmp1a2thbiBtYXNpaCB0ZXJkYXBhdCBzZWJhZ2lhbiBydW1haCB0YW5nZ2EgYmFja2xvZyB5YW5nIHRpZGFrIHRlcmRldGVrc2kuIE1lc2tpcHVuIGRlbWlraWFuLCBuaWxhaSBiYWxhbmNlZCBhY2N1cmFjeSBzZWJlc2FyIDAsODUwMiBtZW51bmp1a2thbiBiYWh3YSBzZWNhcmEga2VzZWx1cnVoYW4gbW9kZWwgdGV0YXAgbWVtaWxpa2kgcGVyZm9ybWEgeWFuZyBzZWltYmFuZyBhbnRhcmEga2VkdWEga2VsYXMuDQoNCkxlYmloIGxhbmp1dCwgbmlsYWkgQXJlYSBVbmRlciBDdXJ2ZSAoQVVDKSBzZWJlc2FyIDAsOTI0NyBtZW5naW5kaWthc2lrYW4gYmFod2EgbW9kZWwgbWVtaWxpa2kga2VtYW1wdWFuIGRpc2tyaW1pbmFzaSB5YW5nIHNhbmdhdCBiYWlrIGRhbGFtIG1lbWJlZGFrYW4gcnVtYWggdGFuZ2dhIGJhY2tsb2cgZGFuIHRpZGFrIGJhY2tsb2cuIERlbmdhbiBwZXJmb3JtYSBpbmksIG1vZGVsIFhHQm9vc3QgZGFwYXQgZGlhbmdnYXAgY3VrdXAgYW5kYWwgdW50dWsgZGlndW5ha2FuIGRhbGFtIG1lbXByZWRpa3NpIHByb2JhYmlsaXRhcyBiYWNrbG9nIHBlcnVtYWhhbiBzZXJ0YSBtZW5kdWt1bmcgcGVuZW50dWFuIHByaW9yaXRhcyBrZWJpamFrYW4gYmVyYmFzaXMgZGF0YS4NCg0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCmxpYnJhcnkocFJPQykNCmxpYnJhcnkoZ2dwbG90MikNCg0Kcm9jX29iaiA8LSByb2MoeV90ZXN0LCBwcmVkX3Byb2IpDQoNCiMgUGxvdCBST0MNCnBsb3Qocm9jX29iaiwgDQogICAgIGNvbCA9ICJibHVlIiwgDQogICAgIGx3ZCA9IDIsDQogICAgIG1haW4gPSAiUk9DIEN1cnZlIC0gWEdCb29zdCBNb2RlbCIpDQoNCiMgVGFtYmFoa2FuIGdhcmlzIGRpYWdvbmFsIChyYW5kb20gbW9kZWwpDQphYmxpbmUoYSA9IDAsIGIgPSAxLCBsdHkgPSAyLCBjb2wgPSAicmVkIikNCg0KIyBUZWtzIEFVQw0KYXVjX3ZhbHVlIDwtIGF1Yyhyb2Nfb2JqKQ0KbGVnZW5kKCJib3R0b21yaWdodCIsIA0KICAgICAgIGxlZ2VuZCA9IHBhc3RlKCJBVUMgPSIsIHJvdW5kKGF1Y192YWx1ZSwgNCkpLA0KICAgICAgIGNvbCA9ICJibHVlIiwgDQogICAgICAgbHdkID0gMikNCmBgYA0KDQojIEZlYXR1cmUgSW1wb3J0YW5jZQ0KDQpgYGB7cn0NCmltcG9ydGFuY2VfbWF0cml4IDwtIHhnYi5pbXBvcnRhbmNlKG1vZGVsID0gbW9kZWxfeGdiKQ0KeGdiLnBsb3QuaW1wb3J0YW5jZShpbXBvcnRhbmNlX21hdHJpeCkNCmBgYA0KDQpHcmFmaWsgbWVudW5qdWtrYW4gdGluZ2thdCBrZXBlbnRpbmdhbiByZWxhdGlmIChfaW1wb3J0YW5jZV8pIGRhcmkgbWFzaW5nLW1hc2luZyB2YXJpYWJlbCBkYWxhbSBtZW1wcmVkaWtzaSBiYWNrbG9nIHBlcnVtYWhhbi4gU2VtYWtpbiBwYW5qYW5nIGJhciwgc2VtYWtpbiBiZXNhciBrb250cmlidXNpIHZhcmlhYmVsIHRlcnNlYnV0IGRhbGFtIG1lbmluZ2thdGthbiBha3VyYXNpIG1vZGVsLg0KDQpWYXJpYWJlbCB5YW5nIHBhbGluZyBkb21pbmFuIGFkYWxhaCBgcjE2MTRhYCAoYWtzZXMgc2FuaXRhc2kpLCBkaWlrdXRpIG9sZWggYHIxNjA2YCAoamVuaXMgYXRhcCkgZGFuIGByMTYwMmAgKHN0YXR1cyBrZXBlbWlsaWthbiBydW1haCkuIEhhbCBpbmkgbWVuZ2luZGlrYXNpa2FuIGJhaHdhIGtvbmRpc2kgc2FuaXRhc2kgbWVydXBha2FuIGZha3RvciBwYWxpbmcgcGVudGluZyBkYWxhbSBtZW5lbnR1a2FuIGFwYWthaCBzdWF0dSBydW1haCB0YW5nZ2EgbWVuZ2FsYW1pIGJhY2tsb2cuIFNlbGFuanV0bnlhLCBrb25kaXNpIGZpc2lrIGJhbmd1bmFuIHNlcGVydGkgYXRhcCwgc2VydGEgc3RhdHVzIGtlcGVtaWxpa2FuIHJ1bWFoLCBqdWdhIG1lbWlsaWtpIHBlbmdhcnVoIHlhbmcgc2lnbmlmaWthbiB0ZXJoYWRhcCBzdGF0dXMga2VsYXlha2h1bmlhbi4gVmFyaWFiZWwgYGx1YXNfY2FwYCAobHVhcyBsYW50YWkgcGVyIGthcGl0YSkgZGFuIGByMTYxMGFgIChha3NlcyBhaXIgbWludW0pIGp1Z2EgbWVtaWxpa2kga29udHJpYnVzaSB5YW5nIGN1a3VwIGJlc2FyLCB5YW5nIG1lbnVuanVra2FuIGJhaHdhIGFzcGVrIGtlcGFkYXRhbiBodW5pYW4gZGFuIGFrc2VzIGFpciBsYXlhayBtZXJ1cGFrYW4gaW5kaWthdG9yIHBlbnRpbmcgZGFsYW0gbWVuZW50dWthbiBrdWFsaXRhcyBwZXJ1bWFoYW4uDQoNCg0KIyBQcm9iYWJpbGl0eSBCYWNrbG9nDQoNCg0KYGBge3J9DQpkYXRha3UkcHJvYl9iYWNrbG9nIDwtIHByZWRpY3QobW9kZWxfeGdiLCB4Z2IuRE1hdHJpeChYKSkNCmhlYWQoZGF0YWt1JHByb2JfYmFja2xvZywgMTUpDQpgYGANCg0KS29kZSBgZGF0YWt1JHByb2JfYmFja2xvZyA8LSBwcmVkaWN0KG1vZGVsX3hnYiwgeGdiLkRNYXRyaXgoWCkpYCBkaWd1bmFrYW4gdW50dWsgbWVuZ2hhc2lsa2FuIHByb2JhYmlsaXRhcyBiYWNrbG9nIHBlcnVtYWhhbiBwYWRhIHNldGlhcCBydW1haCB0YW5nZ2EgYmVyZGFzYXJrYW4gbW9kZWwgWEdCb29zdCB5YW5nIHRlbGFoIGRpbGF0aWguIE5pbGFpIHlhbmcgZGloYXNpbGthbiBiZXJhZGEgcGFkYSByZW50YW5nIDAgaGluZ2dhIDEsIGRpIG1hbmEgc2VtYWtpbiBtZW5kZWthdGkgMSBtZW51bmp1a2thbiBzZW1ha2luIHRpbmdnaSBrZW11bmdraW5hbiBydW1haCB0YW5nZ2EgdGVyc2VidXQgbWVuZ2FsYW1pIGJhY2tsb2cuIE5pbGFpIHByb2JhYmlsaXRhcyBpbmkga2VtdWRpYW4gZGlzaW1wYW4gZGFsYW0gdmFyaWFiZWwgYmFydSBwcm9iX2JhY2tsb2csIHNlaGluZ2dhIG1lbXVuZ2tpbmthbiBhbmFsaXNpcyB5YW5nIGxlYmloIGRldGFpbCBkaWJhbmRpbmdrYW4gc2VrYWRhciBrbGFzaWZpa2FzaSBiaW5lciAoYmFja2xvZyB2cyB0aWRhayBiYWNrbG9nKS4NCg0KSGFzaWwgaGVhZChkYXRha3UkcHJvYl9iYWNrbG9nLCAxNSkgbWVuYW1waWxrYW4gMTUgb2JzZXJ2YXNpIHBlcnRhbWEgZGFyaSBwcm9iYWJpbGl0YXMgdGVyc2VidXQuIFRlcmxpaGF0IGJhaHdhIHRlcmRhcGF0IHZhcmlhc2kgcmlzaWtvIHlhbmcgY3VrdXAgbGViYXIgYW50YXIgcnVtYWggdGFuZ2dhLiBNaXNhbG55YSwgbmlsYWkgc2FuZ2F0IHJlbmRhaCBzZXBlcnRpIDAsMDAwMTkgYXRhdSAwLDAwMDc2IG1lbnVuanVra2FuIHJ1bWFoIHRhbmdnYSBkZW5nYW4gcmlzaWtvIGJhY2tsb2cgeWFuZyBoYW1waXIgdGlkYWsgYWRhLCBzZW1lbnRhcmEgbmlsYWkgc2FuZ2F0IHRpbmdnaSBzZXBlcnRpIDAsOTk5MDcgZGFuIDAsOTQzMDQgbWVuZ2luZGlrYXNpa2FuIHJ1bWFoIHRhbmdnYSBkZW5nYW4ga2VtdW5na2luYW4gYmFja2xvZyB5YW5nIHNhbmdhdCBiZXNhci4gTmlsYWkgbWVuZW5nYWggc2VwZXJ0aSAwLDEw4oCTMCwxOSBtZW5jZXJtaW5rYW4gcmlzaWtvIHJlbmRhaCBoaW5nZ2Egc2VkYW5nLCBzZWRhbmdrYW4gbmlsYWkgZGkgYXRhcyAwLDkwIGRhcGF0IGRpa2F0ZWdvcmlrYW4gc2ViYWdhaSBwcmlvcml0YXMgdGluZ2dpIHVudHVrIGludGVydmVuc2kuDQoNCkRlbmdhbiBhZGFueWEgcHJvYmFiaWxpdGFzIGluaSwgbW9kZWwgdGlkYWsgaGFueWEgbWVtYmVyaWthbiBrZXB1dHVzYW4ga2xhc2lmaWthc2ksIHRldGFwaSBqdWdhIG1lbnllZGlha2FuIHNrb3IgcmlzaWtvIHlhbmcgbGViaWggZ3JhbnVsYXIuIEhhbCBpbmkgc2FuZ2F0IGJlcm1hbmZhYXQgZGFsYW0ga29udGVrcyBrZWJpamFrYW4gcGVydW1haGFuLCBrYXJlbmEgbWVtdW5na2lua2FuIHBlbWVyaW50YWggYXRhdSBwZW1hbmdrdSBrZXBlbnRpbmdhbiB1bnR1ayBtZWxha3VrYW4gdGFyZ2V0aW5nIHByb2dyYW0gc2VjYXJhIGxlYmloIHRlcGF0IHNhc2FyYW4sIG1pc2FsbnlhIGRlbmdhbiBtZW1wcmlvcml0YXNrYW4gcnVtYWggdGFuZ2dhIGRlbmdhbiBwcm9iYWJpbGl0YXMgYmFja2xvZyB0ZXJ0aW5nZ2kgc2ViYWdhaSBwZW5lcmltYSBiYW50dWFuIHBlcnVtYWhhbi4NCg0KYGBge3IsIGVjaG89RkFMU0V9DQpnZ3Bsb3QoZGF0YWt1LCBhZXMoeCA9IHByb2JfYmFja2xvZykpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDMwLCBmaWxsID0gInN0ZWVsYmx1ZSIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJEaXN0cmlidXNpIFByb2JhYmlsaXRhcyBCYWNrbG9nIChYR0Jvb3N0KSIsDQogICAgeCA9ICJQcm9iYWJpbGl0YXMiLA0KICAgIHkgPSAiRnJla3VlbnNpIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KIyBfUmVmZXJlbmNlc18NCg0KWzFdIENoZW4sIFQuLCAmIEd1ZXN0cmluLCBDLiAoMjAxNikuIFhHQm9vc3Q6IEEgc2NhbGFibGUgdHJlZSBib29zdGluZyBzeXN0ZW0uIFByb2NlZWRpbmdzIG9mIHRoZSAyMm5kIEFDTSBTSUdLREQgSW50ZXJuYXRpb25hbCBDb25mZXJlbmNlIG9uIEtub3dsZWRnZSBEaXNjb3ZlcnkgYW5kIERhdGEgTWluaW5nLCA3ODXigJM3OTQuDQoNClsyXSBGcmllZG1hbiwgSi4gSC4gKDIwMDEpLiBHcmVlZHkgZnVuY3Rpb24gYXBwcm94aW1hdGlvbjogQSBncmFkaWVudCBib29zdGluZyBtYWNoaW5lLiBBbm5hbHMgb2YgU3RhdGlzdGljcywgMjkoNSksIDExODnigJMxMjMyLg0KDQpbM10gSmFtZXMsIEcuLCBXaXR0ZW4sIEQuLCBIYXN0aWUsIFQuLCAmIFRpYnNoaXJhbmksIFIuICgyMDIxKS4gQW4gaW50cm9kdWN0aW9uIHRvIHN0YXRpc3RpY2FsIGxlYXJuaW5nOiBXaXRoIGFwcGxpY2F0aW9ucyBpbiBSICgybmQgZWQuKS4gU3ByaW5nZXIuDQoNCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCj4gRGlyZWt0b3JhdCBTdGF0aXN0aWsgS2VzZWphaHRlcmFhbiBSYWt5YXQsIEJQUywgc2FwdGFoYXNAYnBzLmdvLmlkDQoNCg0KDQoNCg==