Memodelkan Data dengan Menggunakan Metode Random Forest

1 Introduction

1.1 Background Story

Pada tugas STA581 ini diminta untuk membuat model klasifikasi dengan mettode Random Forest pada data Investrment Risk Level berdasarkan beberapa variabel berikut ini:
- X1 capital adequacy ratio (%) average from last 5 years
- X2 GDP per capita (USD)
- X3 Gross External Debt (% of GDP) average from last 5 years
- X4 growth of consumer price (%) average from last 5 years
- X5 growth of population (%) average from last 5 years
- X6 growth of Real GDP (%) average from last 5 years
- X7 growth of Real GDP per cap. (%) average from last 5 years
- X8 Loan-deposit ratio (%) average from last 5 years
- X9 Net External Debt (% of GDP) average from last 5 years
- X10 Nominal GDP (USD bn)
- X11 Non-performing loans (% of gross loans) average from last 5 years
- X12 percentage of gross domestic investment to GDP (%) average from last 5 years
- X13 percentage of gross domestic saving to GDP (%) average from last 5 years
- X14 unemployment rate (% labour force) average from last 5 years

1.2 Workflow

Adapun workflows yang dilakukan adalah sebagai berikut:
- Introduction
- Import dan Cleanning data
- Import data ke ekosistem mlr3
- Menentukan model yang digunakan
- Menentukan cara pembagian data
- Melakukan interpretasi model
- Melakukan training dan menghitung performa model
- Kesimpulan

Adapun Packages yang digunakan dalan pengerjaan tugas ini diantaranya:

1.3 Libraries Usied

#Libraries Used
library(readxl)
library(mice)
library(tidyverse)
library(mlr3verse)
library(remotes)
library(mlr3extralearners)
library(rpart.plot)
library(ranger)

2 Import dan Cleaning Data

2.1 Import Data

adapun sintax yang digunakan untuk menginput data Investrment Risk Level adalah sebagai berikut:

#input Data
investment_risk <- read_excel("tugas STA581.xlsx")
investment_risk <- investment_risk[,-1]
str(investment_risk)
tibble [117 x 15] (S3: tbl_df/tbl/data.frame)
 $ X1        : num [1:117] 17.5 18.2 18.7 NA 14 ...
 $ X2        : num [1:117] 38675 40105 76038 27883 4251 ...
 $ X3        : num [1:117] 172.8 103.5 31 24.8 89.6 ...
 $ X4        : num [1:117] 0.68 1.77 2.63 1.29 1.44 ...
 $ X5        : num [1:117] 1.221 0.87 1.489 1.753 0.256 ...
 $ X6        : num [1:117] 1.79 2.66 1.85 2.23 4.75 ...
 $ X7        : num [1:117] -2.084 -0.725 -1.901 -1.135 2.332 ...
 $ X8        : num [1:117] 55 103 103 103 167 ...
 $ X9        : num [1:117] -26.5 -13.6 -56.2 24.8 47.3 ...
 $ X10       : num [1:117] 2.86 352.91 199.93 10.11 12.65 ...
 $ X11       : num [1:117] 8 8.15 8.15 NA 6.6 ...
 $ X12       : num [1:117] 23.1 24.9 20.4 21.7 19.4 ...
 $ X13       : num [1:117] 26.9 32.5 31 17.3 15.1 ...
 $ X14       : num [1:117] 3 2.45 NA NA 18.5 ...
 $ Risk Level: chr [1:117] "low" "low" "low" "low" ...

Dari output diatas dapat dilihat ada kemungkinan terdapat missing value pada data Investrment Risk Level, sehingga langkah selanjutnya yaitu mengecek missing value pada data tersebut

2.2 Mengecek Mising Value

Adapun sintaks yang digunakan untuk mengecek missing value adalah sebagai berikut:

#Mengecek Missing data
sum(is.na(investment_risk))
[1] 55
summary(is.na(investment_risk))
     X1              X2              X3              X4         
 Mode :logical   Mode :logical   Mode :logical   Mode :logical  
 FALSE:104       FALSE:117       FALSE:117       FALSE:117      
 TRUE :13                                                       
     X5              X6              X7              X8         
 Mode :logical   Mode :logical   Mode :logical   Mode :logical  
 FALSE:117       FALSE:117       FALSE:117       FALSE:108      
                                                 TRUE :9        
     X9             X10             X11             X12         
 Mode :logical   Mode :logical   Mode :logical   Mode :logical  
 FALSE:117       FALSE:117       FALSE:96        FALSE:117      
                                 TRUE :21                       
    X13             X14          Risk Level     
 Mode :logical   Mode :logical   Mode :logical  
 FALSE:117       FALSE:105       FALSE:117      
                 TRUE :12                       
md.pattern(investment_risk)
   X2 X3 X4 X5 X6 X7 X9 X10 X12 X13 Risk Level X8 X14 X1 X11   
76  1  1  1  1  1  1  1   1   1   1          1  1   1  1   1  0
15  1  1  1  1  1  1  1   1   1   1          1  1   1  1   0  1
7   1  1  1  1  1  1  1   1   1   1          1  1   1  0   1  1
1   1  1  1  1  1  1  1   1   1   1          1  1   1  0   0  2
8   1  1  1  1  1  1  1   1   1   1          1  1   0  1   1  1
1   1  1  1  1  1  1  1   1   1   1          1  1   0  0   0  3
3   1  1  1  1  1  1  1   1   1   1          1  0   1  1   1  1
1   1  1  1  1  1  1  1   1   1   1          1  0   1  1   0  2
1   1  1  1  1  1  1  1   1   1   1          1  0   1  0   1  2
1   1  1  1  1  1  1  1   1   1   1          1  0   1  0   0  3
1   1  1  1  1  1  1  1   1   1   1          1  0   0  1   1  2
2   1  1  1  1  1  1  1   1   1   1          1  0   0  0   0  4
    0  0  0  0  0  0  0   0   0   0          0  9  12 13  21 55

Dari hasil output diatas dapat dilihat bahwa terdapat missing value pada data Investrment Risk Level, sehingga langkah selanjutnya adalah mengestimasi missing value. Adapun metode yang akan di gunakan yaitu metode Expectation-Maximization (EM).

2.3 Menduga Missing Value

Adapun sintaks yang digunakan untuk menduga missing value adalah sebagai berikut:

#Menduga missing data
impute <- mice(investment_risk[,1:14], m = 3, seed = 123)

 iter imp variable
  1   1  X1  X8  X11  X14
  1   2  X1  X8  X11  X14
  1   3  X1  X8  X11  X14
  2   1  X1  X8  X11  X14
  2   2  X1  X8  X11  X14
  2   3  X1  X8  X11  X14
  3   1  X1  X8  X11  X14
  3   2  X1  X8  X11  X14
  3   3  X1  X8  X11  X14
  4   1  X1  X8  X11  X14
  4   2  X1  X8  X11  X14
  4   3  X1  X8  X11  X14
  5   1  X1  X8  X11  X14
  5   2  X1  X8  X11  X14
  5   3  X1  X8  X11  X14
data_lengkap<- complete(impute,1)
Y<-investment_risk$`Risk Level`
Y<-as.factor(Y)
data<-cbind(data_lengkap,Y)
summary(is.na(data))
     X1              X2              X3              X4         
 Mode :logical   Mode :logical   Mode :logical   Mode :logical  
 FALSE:117       FALSE:117       FALSE:117       FALSE:117      
     X5              X6              X7              X8         
 Mode :logical   Mode :logical   Mode :logical   Mode :logical  
 FALSE:117       FALSE:117       FALSE:117       FALSE:117      
     X9             X10             X11             X12         
 Mode :logical   Mode :logical   Mode :logical   Mode :logical  
 FALSE:117       FALSE:117       FALSE:117       FALSE:117      
    X13             X14              Y          
 Mode :logical   Mode :logical   Mode :logical  
 FALSE:117       FALSE:117       FALSE:117      

Dari hasil output diatas dapat dilihat bahwa sudah tidak ada missing value pada data Investrment Risk Level. sehingga data sudah siap untuk dilakukan pemodelan.

3 Import dara ke mlr3

Adapun sintaks yang digunakan adalah sebagai berikut:

#import data ke mlr3
task_risk = TaskClassif$new(id="risk", backend = data,
                                target ="Y",positive = "low")

4 Menentukan model yang digunakan

seperti yang sudah di tentukan sebelumnya bahwa medel yang akan digunakan untuk mengklasifikasikan data yaitu Random forest. Adapun sintaks yang digunakan adalah sebagai berikut

#Menentukan Model 
model_rf_classif <-lrn("classif.ranger",predict_type="prob",importance="impurity")

5 Menentukan cara pembagian data

Dalam melakukan pembagian data akan digunakan metode Cross Validation dengan fold 10. Adapun sintaks yang dgunakan adalah sebagai berikut:

#Menentukan Cara Pembagian Data 
resample_cv_classif = rsmp("cv", folds = 10)
set.seed(123)
resample_cv_classif$instantiate(task = task_risk)

6 Melakukan Interpretasi Model

Adapun sintaks yang digunakan adalah:

#Melakukan interfretasi model
model_rf_classif$train(task=task_risk)
model_rf_classif$model$variable.importance
       X1       X10       X11       X12       X13       X14 
 1.393666  5.345288  4.325685  1.698773  3.317513  3.737622 
       X2        X3        X4        X5        X6        X7 
14.039241  2.774893  4.106053  1.443611  0.951623  1.072926 
       X8        X9 
 1.417225  5.372877 
importance_classif <- data.frame(Predictors = names(model_rf_classif$model$variable.importance),
                         impurity = model_rf_classif$model$variable.importance
                         )
rownames(importance_classif) <- NULL

importance_classif %>% arrange(desc(impurity))

Dari hasil output diatas dapat dilihat bahwa variabel prediktor yang paling berpengaruh yaitu X2,X9, X10 dan X11.

7 Melakukan Trainning dan menghitung performa

pada tahap ini akan di terapkan model yang sudah di definisikan sebelumnya pada data training dan kemudian mengevaluasi kemampuan prediiksi dengan data testing. Adapun sintaks yang akan di gunakan adalah sebagai berikut:

#menerapkan model pada data Train
train_test_classif = resample(task = task_risk,
                               learner = model_rf_classif,
                            resampling = resample_cv_classif,
                               store_models = TRUE
                               )
INFO  [12:15:20.398] [mlr3] Applying learner 'classif.ranger' on task 'risk' (iter 6/10) 
INFO  [12:15:20.454] [mlr3] Applying learner 'classif.ranger' on task 'risk' (iter 7/10) 
INFO  [12:15:20.510] [mlr3] Applying learner 'classif.ranger' on task 'risk' (iter 3/10) 
INFO  [12:15:20.570] [mlr3] Applying learner 'classif.ranger' on task 'risk' (iter 2/10) 
INFO  [12:15:20.625] [mlr3] Applying learner 'classif.ranger' on task 'risk' (iter 5/10) 
INFO  [12:15:20.684] [mlr3] Applying learner 'classif.ranger' on task 'risk' (iter 10/10) 
INFO  [12:15:20.738] [mlr3] Applying learner 'classif.ranger' on task 'risk' (iter 8/10) 
INFO  [12:15:20.798] [mlr3] Applying learner 'classif.ranger' on task 'risk' (iter 4/10) 
INFO  [12:15:20.867] [mlr3] Applying learner 'classif.ranger' on task 'risk' (iter 9/10) 
INFO  [12:15:20.932] [mlr3] Applying learner 'classif.ranger' on task 'risk' (iter 1/10) 
#memprediksi dengan data testing
prediksi_test = as.data.table(train_test_classif$prediction(),)
head(prediksi_test)
#Confusion matrix
train_test_classif$prediction()$confusion
        truth
response low high
    low   45    7
    high   8   57
#melihat akurasi model
train_test_classif$aggregate(msr("classif.acc"))
classif.acc 
  0.8727273 
#Menampilkan Kurtva ROC
autoplot(bmr_classif,type = "roc")

autoplot(bmr_classif,measure = msr("classif.acc"))

8 Kesimpulan

Berdasarkan Hasil perhitungan diatas data Investrment Risk Level diklasifikasikan dengan metode Random Forest dan diperoleh tingkat keakurasian sebesar 87,27% dan diperoleh beberapa variabel yang paling berpengaruh yaitu X2,X9, X10 dan X11.

LS0tDQp0aXRsZTogIlR1Z2FzIFNhaW5zIERhdGEgUGVydGVtdWFuIDEzIg0KYXV0aG9yOiAiTmVuaSBIZXJtYXdhdGkgKEcxNTAxMjExMDI4KSINCmRhdGU6ICIxMS8yNi8yMDIxIg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOg0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdGhlbWU6IHNwYWNlbGFiDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0b2NfZmxvYXQ6IHllcw0KICB3b3JkX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiAnNCcNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRoZW1lOiBzcGFjZWxhYg0KICAgIGRmX3ByaW50OiBwYWdlZA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiAnNCcNCiAgICB0b2NfZmxvYXQ6IHllcw0KICBwZGZfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6ICc0Jw0KLS0tDQoNCmBgYHs9aHRtbH0NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoNCmJvZHl7IC8qIE5vcm1hbCAgKi8NCiAgICAgIGZvbnQtc2l6ZTogMTJweDsNCiAgfQ0KdGQgeyAgLyogVGFibGUgICovDQogIGZvbnQtc2l6ZTogMTJweDsNCn0NCmgxLnRpdGxlIHsNCiAgZm9udC1zaXplOiAzOHB4Ow0KICBjb2xvcjogbGlnaHRibHVlOw0KICBmb250LXdlaWdodDogYm9sZDsNCn0NCmgxIHsgLyogSGVhZGVyIDEgKi8NCiAgZm9udC1zaXplOiAyNHB4Ow0KICBjb2xvcjogRGFya0JsdWU7DQp9DQpoMiB7IC8qIEhlYWRlciAyICovDQogIGZvbnQtc2l6ZTogMjBweDsNCiAgY29sb3I6IERhcmtCbHVlOw0KfQ0KaDMgeyAvKiBIZWFkZXIgMyAqLw0KICBmb250LXNpemU6IDE2cHg7DQojICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgY29sb3I6IERhcmtCbHVlOw0KfQ0KaDQgeyAvKiBIZWFkZXIgNCAqLw0KICBmb250LXNpemU6IDE0cHg7DQogIGNvbG9yOiBEYXJrQmx1ZTsNCn0NCmNvZGUucnsgLyogQ29kZSBibG9jayAqLw0KICAgIGZvbnQtc2l6ZTogMTJweDsNCn0NCnByZSB7IC8qIENvZGUgYmxvY2sgLSBkZXRlcm1pbmVzIGNvZGUgc3BhY2luZyBiZXR3ZWVuIGxpbmVzICovDQogICAgZm9udC1zaXplOiAxMnB4Ow0KfQ0KPC9zdHlsZT4NCmBgYA0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQoja25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG89VFJVRSwgZmlnLmhlaWdodD0zLjUsIGZpZy53aWR0aD05LjIsIHJlc3VsdHM9J2hvbGQnLCB3YXJuaW5nPUZBTFNFLCBmaWcuc2hvdz0naG9sZCcsIG1lc3NhZ2U9RkFMU0UpIA0Kb3B0aW9ucyhzY2lwZW4gPSA5OSkNCmBgYA0KDQoqKk1lbW9kZWxrYW4gRGF0YSBkZW5nYW4gTWVuZ2d1bmFrYW4gTWV0b2RlIFJhbmRvbSBGb3Jlc3QqKg0KDQojIEludHJvZHVjdGlvbg0KIyMgQmFja2dyb3VuZCBTdG9yeQ0KUGFkYSB0dWdhcyBTVEE1ODEgaW5pIGRpbWludGEgdW50dWsgbWVtYnVhdCBtb2RlbCBrbGFzaWZpa2FzaSBkZW5nYW4gbWV0dG9kZSBSYW5kb20gRm9yZXN0IHBhZGEgZGF0YSBJbnZlc3RybWVudCBSaXNrIExldmVsIGJlcmRhc2Fya2FuIGJlYmVyYXBhIHZhcmlhYmVsIGJlcmlrdXQgaW5pOlwNCi0gWDEgY2FwaXRhbCBhZGVxdWFjeSByYXRpbyAoJSkgYXZlcmFnZSBmcm9tIGxhc3QgNSB5ZWFyc1wNCi0gWDIgR0RQIHBlciBjYXBpdGEgKFVTRClcDQotIFgzIEdyb3NzIEV4dGVybmFsIERlYnQgKCUgb2YgR0RQKSBhdmVyYWdlIGZyb20gbGFzdCA1IHllYXJzXA0KLSBYNCBncm93dGggb2YgY29uc3VtZXIgcHJpY2UgKCUpIGF2ZXJhZ2UgZnJvbSBsYXN0IDUgeWVhcnNcDQotIFg1IGdyb3d0aCBvZiBwb3B1bGF0aW9uICglKSBhdmVyYWdlIGZyb20gbGFzdCA1IHllYXJzXA0KLSBYNiBncm93dGggb2YgUmVhbCBHRFAgKCUpIGF2ZXJhZ2UgZnJvbSBsYXN0IDUgeWVhcnNcDQotIFg3IGdyb3d0aCBvZiBSZWFsIEdEUCBwZXIgY2FwLiAoJSkgYXZlcmFnZSBmcm9tIGxhc3QgNSB5ZWFyc1wNCi0gWDggTG9hbi1kZXBvc2l0IHJhdGlvICglKSBhdmVyYWdlIGZyb20gbGFzdCA1IHllYXJzXA0KLSBYOSBOZXQgRXh0ZXJuYWwgRGVidCAoJSBvZiBHRFApIGF2ZXJhZ2UgZnJvbSBsYXN0IDUgeWVhcnNcDQotIFgxMCBOb21pbmFsIEdEUCAoVVNEIGJuKVwNCi0gWDExIE5vbi1wZXJmb3JtaW5nIGxvYW5zICglIG9mIGdyb3NzIGxvYW5zKSBhdmVyYWdlIGZyb20gbGFzdCA1IHllYXJzXA0KLSBYMTIgcGVyY2VudGFnZSBvZiBncm9zcyBkb21lc3RpYyBpbnZlc3RtZW50IHRvIEdEUCAoJSkgYXZlcmFnZSBmcm9tIGxhc3QgNSB5ZWFyc1wNCi0gWDEzIHBlcmNlbnRhZ2Ugb2YgZ3Jvc3MgZG9tZXN0aWMgc2F2aW5nIHRvIEdEUCAoJSkgYXZlcmFnZSBmcm9tIGxhc3QgNSB5ZWFyc1wNCi0gWDE0IHVuZW1wbG95bWVudCByYXRlICglIGxhYm91ciBmb3JjZSkgYXZlcmFnZSBmcm9tIGxhc3QgNSB5ZWFycyANCg0KIyMgV29ya2Zsb3cNCkFkYXB1biB3b3JrZmxvd3MgeWFuZyBkaWxha3VrYW4gYWRhbGFoIHNlYmFnYWkgYmVyaWt1dDpcDQotIEludHJvZHVjdGlvblwNCi0gSW1wb3J0IGRhbiBDbGVhbm5pbmcgZGF0YVwNCi0gSW1wb3J0IGRhdGEga2UgZWtvc2lzdGVtIG1scjNcDQotIE1lbmVudHVrYW4gbW9kZWwgeWFuZyBkaWd1bmFrYW5cDQotIE1lbmVudHVrYW4gY2FyYSBwZW1iYWdpYW4gZGF0YVwNCi0gTWVsYWt1a2FuIGludGVycHJldGFzaSBtb2RlbFwNCi0gTWVsYWt1a2FuIHRyYWluaW5nIGRhbiBtZW5naGl0dW5nIHBlcmZvcm1hIG1vZGVsXA0KLSBLZXNpbXB1bGFuXA0KDQpBZGFwdW4gUGFja2FnZXMgeWFuZyBkaWd1bmFrYW4gZGFsYW4gcGVuZ2VyamFhbiB0dWdhcyBpbmkgZGlhbnRhcmFueWE6DQoNCiMjIExpYnJhcmllcyBVc2llZA0KDQpgYGB7cn0NCiNMaWJyYXJpZXMgVXNlZA0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KG1pY2UpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkobWxyM3ZlcnNlKQ0KbGlicmFyeShyZW1vdGVzKQ0KbGlicmFyeShtbHIzZXh0cmFsZWFybmVycykNCmxpYnJhcnkocnBhcnQucGxvdCkNCmxpYnJhcnkocmFuZ2VyKQ0KYGBgDQoNCiMgSW1wb3J0IGRhbiBDbGVhbmluZyBEYXRhIA0KDQojIyBJbXBvcnQgRGF0YQ0KDQphZGFwdW4gc2ludGF4IHlhbmcgZGlndW5ha2FuIHVudHVrIG1lbmdpbnB1dCBkYXRhIEludmVzdHJtZW50IFJpc2sgTGV2ZWwgYWRhbGFoIHNlYmFnYWkgYmVyaWt1dDoNCg0KYGBge3J9DQojaW5wdXQgRGF0YQ0KaW52ZXN0bWVudF9yaXNrIDwtIHJlYWRfZXhjZWwoInR1Z2FzIFNUQTU4MS54bHN4IikNCmludmVzdG1lbnRfcmlzayA8LSBpbnZlc3RtZW50X3Jpc2tbLC0xXQ0Kc3RyKGludmVzdG1lbnRfcmlzaykNCmBgYA0KDQpEYXJpIG91dHB1dCBkaWF0YXMgZGFwYXQgZGlsaWhhdCBhZGEga2VtdW5na2luYW4gdGVyZGFwYXQgbWlzc2luZyB2YWx1ZSBwYWRhIGRhdGEgSW52ZXN0cm1lbnQgUmlzayBMZXZlbCwgc2VoaW5nZ2EgbGFuZ2thaCBzZWxhbmp1dG55YSB5YWl0dSBtZW5nZWNlayBtaXNzaW5nIHZhbHVlIHBhZGEgZGF0YSB0ZXJzZWJ1dA0KDQojIyBNZW5nZWNlayBNaXNpbmcgVmFsdWUNCg0KQWRhcHVuIHNpbnRha3MgeWFuZyBkaWd1bmFrYW4gdW50dWsgbWVuZ2VjZWsgbWlzc2luZyB2YWx1ZSBhZGFsYWggc2ViYWdhaSBiZXJpa3V0Og0KDQpgYGB7cn0NCiNNZW5nZWNlayBNaXNzaW5nIGRhdGENCnN1bShpcy5uYShpbnZlc3RtZW50X3Jpc2spKQ0Kc3VtbWFyeShpcy5uYShpbnZlc3RtZW50X3Jpc2spKQ0KbWQucGF0dGVybihpbnZlc3RtZW50X3Jpc2spDQpgYGANCg0KRGFyaSBoYXNpbCBvdXRwdXQgZGlhdGFzIGRhcGF0IGRpbGloYXQgYmFod2EgdGVyZGFwYXQgbWlzc2luZyB2YWx1ZSBwYWRhIGRhdGEgSW52ZXN0cm1lbnQgUmlzayBMZXZlbCwgc2VoaW5nZ2EgbGFuZ2thaCBzZWxhbmp1dG55YSBhZGFsYWggbWVuZ2VzdGltYXNpIG1pc3NpbmcgdmFsdWUuIEFkYXB1biBtZXRvZGUgeWFuZyBha2FuIGRpIGd1bmFrYW4geWFpdHUgbWV0b2RlIEV4cGVjdGF0aW9uLU1heGltaXphdGlvbiAoRU0pLg0KDQojIyBNZW5kdWdhIE1pc3NpbmcgVmFsdWUNCg0KQWRhcHVuIHNpbnRha3MgeWFuZyBkaWd1bmFrYW4gdW50dWsgbWVuZHVnYSBtaXNzaW5nIHZhbHVlIGFkYWxhaCBzZWJhZ2FpIGJlcmlrdXQ6DQoNCmBgYHtyfQ0KI01lbmR1Z2EgbWlzc2luZyBkYXRhDQppbXB1dGUgPC0gbWljZShpbnZlc3RtZW50X3Jpc2tbLDE6MTRdLCBtID0gMywgc2VlZCA9IDEyMykNCmRhdGFfbGVuZ2thcDwtIGNvbXBsZXRlKGltcHV0ZSwxKQ0KWTwtaW52ZXN0bWVudF9yaXNrJGBSaXNrIExldmVsYA0KWTwtYXMuZmFjdG9yKFkpDQpkYXRhPC1jYmluZChkYXRhX2xlbmdrYXAsWSkNCnN1bW1hcnkoaXMubmEoZGF0YSkpDQpgYGANCg0KRGFyaSBoYXNpbCBvdXRwdXQgZGlhdGFzIGRhcGF0IGRpbGloYXQgYmFod2Egc3VkYWggdGlkYWsgYWRhIG1pc3NpbmcgdmFsdWUgcGFkYSBkYXRhIEludmVzdHJtZW50IFJpc2sgTGV2ZWwuIHNlaGluZ2dhIGRhdGEgc3VkYWggc2lhcCB1bnR1ayBkaWxha3VrYW4gcGVtb2RlbGFuLg0KDQoNCiMgSW1wb3J0IGRhcmEga2UgbWxyMw0KDQpBZGFwdW4gc2ludGFrcyB5YW5nIGRpZ3VuYWthbiBhZGFsYWggc2ViYWdhaSBiZXJpa3V0Og0KDQpgYGB7cn0NCiNpbXBvcnQgZGF0YSBrZSBtbHIzDQp0YXNrX3Jpc2sgPSBUYXNrQ2xhc3NpZiRuZXcoaWQ9InJpc2siLCBiYWNrZW5kID0gZGF0YSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0ID0iWSIscG9zaXRpdmUgPSAibG93IikNCmBgYA0KDQojIE1lbmVudHVrYW4gbW9kZWwgeWFuZyBkaWd1bmFrYW4gDQpzZXBlcnRpIHlhbmcgc3VkYWggZGkgdGVudHVrYW4gc2ViZWx1bW55YSBiYWh3YSBtZWRlbCB5YW5nIGFrYW4gZGlndW5ha2FuIHVudHVrIG1lbmdrbGFzaWZpa2FzaWthbiBkYXRhIHlhaXR1ICoqUmFuZG9tIGZvcmVzdCoqLiBBZGFwdW4gc2ludGFrcyB5YW5nIGRpZ3VuYWthbiBhZGFsYWggc2ViYWdhaSBiZXJpa3V0DQoNCmBgYHtyfQ0KI01lbmVudHVrYW4gTW9kZWwgDQptb2RlbF9yZl9jbGFzc2lmIDwtbHJuKCJjbGFzc2lmLnJhbmdlciIscHJlZGljdF90eXBlPSJwcm9iIixpbXBvcnRhbmNlPSJpbXB1cml0eSIpDQpgYGANCg0KDQojIE1lbmVudHVrYW4gY2FyYSBwZW1iYWdpYW4gZGF0YQ0KRGFsYW0gbWVsYWt1a2FuIHBlbWJhZ2lhbiBkYXRhIGFrYW4gZGlndW5ha2FuIG1ldG9kZSAqKkNyb3NzIFZhbGlkYXRpb24qKiBkZW5nYW4gZm9sZCAxMC4gQWRhcHVuIHNpbnRha3MgeWFuZyBkZ3VuYWthbiBhZGFsYWggc2ViYWdhaSBiZXJpa3V0Og0KYGBge3J9DQojTWVuZW50dWthbiBDYXJhIFBlbWJhZ2lhbiBEYXRhIA0KcmVzYW1wbGVfY3ZfY2xhc3NpZiA9IHJzbXAoImN2IiwgZm9sZHMgPSAxMCkNCnNldC5zZWVkKDEyMykNCnJlc2FtcGxlX2N2X2NsYXNzaWYkaW5zdGFudGlhdGUodGFzayA9IHRhc2tfcmlzaykNCmBgYA0KDQojIE1lbGFrdWthbiBJbnRlcnByZXRhc2kgTW9kZWwNCkFkYXB1biBzaW50YWtzIHlhbmcgZGlndW5ha2FuIGFkYWxhaDoNCmBgYHtyfQ0KI01lbGFrdWthbiBpbnRlcmZyZXRhc2kgbW9kZWwNCm1vZGVsX3JmX2NsYXNzaWYkdHJhaW4odGFzaz10YXNrX3Jpc2spDQptb2RlbF9yZl9jbGFzc2lmJG1vZGVsJHZhcmlhYmxlLmltcG9ydGFuY2UNCg0KaW1wb3J0YW5jZV9jbGFzc2lmIDwtIGRhdGEuZnJhbWUoUHJlZGljdG9ycyA9IG5hbWVzKG1vZGVsX3JmX2NsYXNzaWYkbW9kZWwkdmFyaWFibGUuaW1wb3J0YW5jZSksDQogICAgICAgICAgICAgICAgICAgICAgICAgaW1wdXJpdHkgPSBtb2RlbF9yZl9jbGFzc2lmJG1vZGVsJHZhcmlhYmxlLmltcG9ydGFuY2UNCiAgICAgICAgICAgICAgICAgICAgICAgICApDQpyb3duYW1lcyhpbXBvcnRhbmNlX2NsYXNzaWYpIDwtIE5VTEwNCg0KaW1wb3J0YW5jZV9jbGFzc2lmICU+JSBhcnJhbmdlKGRlc2MoaW1wdXJpdHkpKQ0KYGBgDQpEYXJpIGhhc2lsIG91dHB1dCBkaWF0YXMgZGFwYXQgZGlsaWhhdCBiYWh3YSB2YXJpYWJlbCBwcmVkaWt0b3IgeWFuZyBwYWxpbmcgYmVycGVuZ2FydWggeWFpdHUgWDIsWDksIFgxMCBkYW4gWDExLg0KDQojIE1lbGFrdWthbiBUcmFpbm5pbmcgZGFuIG1lbmdoaXR1bmcgcGVyZm9ybWENCnBhZGEgdGFoYXAgaW5pIGFrYW4gZGkgdGVyYXBrYW4gbW9kZWwgeWFuZyBzdWRhaCBkaSBkZWZpbmlzaWthbiBzZWJlbHVtbnlhIHBhZGEgZGF0YSB0cmFpbmluZyBkYW4ga2VtdWRpYW4gbWVuZ2V2YWx1YXNpIGtlbWFtcHVhbiBwcmVkaWlrc2kgZGVuZ2FuIGRhdGEgdGVzdGluZy4gQWRhcHVuIHNpbnRha3MgeWFuZyBha2FuIGRpIGd1bmFrYW4gYWRhbGFoIHNlYmFnYWkgYmVyaWt1dDoNCmBgYHtyfQ0KI21lbmVyYXBrYW4gbW9kZWwgcGFkYSBkYXRhIFRyYWluDQp0cmFpbl90ZXN0X2NsYXNzaWYgPSByZXNhbXBsZSh0YXNrID0gdGFza19yaXNrLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlYXJuZXIgPSBtb2RlbF9yZl9jbGFzc2lmLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc2FtcGxpbmcgPSByZXNhbXBsZV9jdl9jbGFzc2lmLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0b3JlX21vZGVscyA9IFRSVUUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApDQojbWVtcHJlZGlrc2kgZGVuZ2FuIGRhdGEgdGVzdGluZw0KcHJlZGlrc2lfdGVzdCA9IGFzLmRhdGEudGFibGUodHJhaW5fdGVzdF9jbGFzc2lmJHByZWRpY3Rpb24oKSwpDQpoZWFkKHByZWRpa3NpX3Rlc3QpDQojQ29uZnVzaW9uIG1hdHJpeA0KdHJhaW5fdGVzdF9jbGFzc2lmJHByZWRpY3Rpb24oKSRjb25mdXNpb24NCiNtZWxpaGF0IGFrdXJhc2kgbW9kZWwNCnRyYWluX3Rlc3RfY2xhc3NpZiRhZ2dyZWdhdGUobXNyKCJjbGFzc2lmLmFjYyIpKQ0KI01lbmFtcGlsa2FuIEt1cnR2YSBST0MNCmF1dG9wbG90KGJtcl9jbGFzc2lmLHR5cGUgPSAicm9jIikNCmF1dG9wbG90KGJtcl9jbGFzc2lmLG1lYXN1cmUgPSBtc3IoImNsYXNzaWYuYWNjIikpDQpgYGANCg0KIyBLZXNpbXB1bGFuIA0KQmVyZGFzYXJrYW4gSGFzaWwgcGVyaGl0dW5nYW4gZGlhdGFzIGRhdGEgSW52ZXN0cm1lbnQgUmlzayBMZXZlbCAgZGlrbGFzaWZpa2FzaWthbiBkZW5nYW4gbWV0b2RlIFJhbmRvbSBGb3Jlc3QgZGFuIGRpcGVyb2xlaCB0aW5na2F0IGtlYWt1cmFzaWFuIHNlYmVzYXIgODcsMjclIGRhbiBkaXBlcm9sZWggYmViZXJhcGEgdmFyaWFiZWwgeWFuZyBwYWxpbmcgYmVycGVuZ2FydWggeWFpdHUgWDIsWDksIFgxMCBkYW4gWDExLg0KDQoNCg0KDQoNCg0K