Ujian Akhir Semester (UAS)

Nama :Elysabeth Putri Pamungkas

Nim :2024333320023

🎯 Tujuan

Menganalisis faktor-faktor keuangan yang memengaruhi kemungkinan terjadinya financial distress pada perusahaan, serta membangun model prediksi berbasis regresi logistik dengan evaluasi menyeluruh dan visualisasi pendukung.

Langkah 1 : Import library

# Load library
library(readxl)
library(ggplot2)
library(dplyr)
library(ResourceSelection)  # Hosmer-Lemeshow test
library(caret)              # Confusion Matrix
library(broom)              # Tidy output
library(pscl)               # McFadden's R²
library(pROC)               # ROC Curve
library(caret)

Penjelasan tentang library

Library Fungsi Utama Kegunaan dalam Analisis
readxl Membaca file Excel (.xlsx) Digunakan untuk membaca data dari file data analisis.xlsx dengan perintah: read_excel()
dplyr Manipulasi data (select, mutate, filter, dll) Digunakan untuk memilih kolom (select()), membuat kolom baru (mutate()), dan menyusun ulang data untuk tabel prediksi.
ggplot2 Visualisasi data Digunakan untuk membuat: plot koefisien, histogram probabilitas, dan visualisasi evaluasi model.
broom Merapikan output statistik model menjadi data frame Fungsi tidy() digunakan untuk mengubah hasil model (glm) menjadi format tabel yang bisa langsung dipakai untuk visualisasi koefisien.
pscl Statistik lanjutan termasuk McFadden’s R² Fungsi pR2() digunakan untuk menghitung pseudo R-squared pada model logistik, seperti McFadden, Cox-Snell, dan Nagelkerke.
ResourceSelection Uji kelayakan model logistik (Hosmer-Lemeshow) Fungsi hoslem.test() digunakan untuk mengevaluasi goodness-of-fit dari model logistik.
caret Evaluasi model prediksi (akurasi, confusion matrix, dll) Fungsi confusionMatrix() menghitung akurasi model, sensitivitas, spesifisitas, dan membuat evaluasi klasifikasi.
pROC ROC curve dan AUC (Area Under Curve) Fungsi roc() dan plot() digunakan untuk menampilkan kurva ROC, serta auc() untuk menghitung nilai AUC—mengukur seberapa baik model memisahkan dua kelas (distress vs non-distress).

📁 Langkah 2: Import data

# Import data
data <- read_excel("C:/Users/Modern/Downloads/data analisis.xlsx", 
                   sheet = "Data Untuk R")
head(data, n = 10)

🧪 Exploratory Data Analysis (EDA) – Financial Distress Dataset

library(dplyr)
library(tidyr)
library(GGally)               
# Buat label distress
df<-data
df$FD_label <- factor(df$FD, levels = c(0, 1), labels = c("Non-Distress", "Distress"))
# 2. Distribusi Data Target
ggplot(df, aes(x = FD_label, fill = FD_label)) +
  geom_bar(width = 0.5) +
  labs(title = "Distribusi Financial Distress", x = "Status", y = "Jumlah") +
  scale_fill_manual(values = c("steelblue", "salmon")) +
  theme_minimal()

# 3. Korelasi Antara Variabel Numerik
numeric_vars <- df %>% select(DR, FDR, NPF, ROE, BOPO)
ggcorr(numeric_vars, label = TRUE, label_size = 4, hjust = 0.8) +
  ggtitle("Matriks Korelasi Variabel Keuangan")

# 4. Boxplot Variabel Numerik Berdasarkan Status FD
numeric_names <- names(numeric_vars)
for (var in numeric_names) {
  print(
    ggplot(df, aes_string(x = "FD_label", y = var, fill = "FD_label")) +
      geom_boxplot() +
      labs(title = paste("Distribusi", var, "berdasarkan Status FD"), x = "Status FD", y = var) +
      theme_minimal()
  )
}


# 5. Density Plot: Distribusi Setiap Variabel
for (var in numeric_names) {
  print(
    ggplot(df, aes_string(x = var, fill = "FD_label")) +
      geom_density(alpha = 0.5) +
      labs(title = paste("Density Plot", var), x = var, y = "Density") +
      theme_minimal()
  )
}

🧠 Kesimpulan EDA Variabel seperti BOPO, NPF, dan ROE menunjukkan perbedaan mencolok antara Distress vs Non-Distress.

Dataset bersih, tidak ada missing value (berdasarkan summary()).

Tidak ditemukan outlier ekstrem yang mengganggu, namun perbedaan sebaran layak dicatat.

Korelasi antar beberapa variabel seperti DR dan BOPO perlu diperhatikan dalam modeling.

📁 Langkah 3: Persiapan Data

Data diambil dari sheet “Data Untuk R” dalam file Excel yang berisi 6 variabel keuangan:

FD: status financial distress (asli berupa 0/1 → diubah menjadi label “Distress” dan “Non-Distress”)

DR: Debt Ratio

FDR: Financing to Deposit Ratio

NPF: Non-Performing Financing

ROE: Return on Equity

BOPO: Rasio Beban Operasional terhadap Pendapatan Operasional

# Pastikan variabel FD adalah faktor
data$FD <- factor(data$FD, levels = c(0, 1), labels = c("Non-Distress", "Distress"))

Deskriptive statistic

# Melihat deskriptive statistic
summary(data)
            FD            DR              FDR              NPF               ROE                BOPO       
 Non-Distress:122   Min.   :0.0500   Min.   :  0.00   Min.   : 0.0000   Min.   :-94.0100   Min.   : 40.36  
 Distress    :326   1st Qu.:0.7200   1st Qu.: 85.63   1st Qu.: 0.1375   1st Qu.:  0.3075   1st Qu.: 85.37  
                    Median :0.8300   Median : 92.06   Median : 1.8000   Median :  3.0050   Median : 94.56  
                    Mean   :0.7589   Mean   : 96.97   Mean   : 1.9189   Mean   :  4.6160   Mean   :101.69  
                    3rd Qu.:0.8800   3rd Qu.: 96.31   3rd Qu.: 3.2250   3rd Qu.:  8.2350   3rd Qu.: 98.83  
                    Max.   :0.9700   Max.   :506.60   Max.   :13.5400   Max.   : 37.1600   Max.   :497.13  

⚙️ Langkah 4: Pemodelan Regresi Logistik

Model dibangun dengan persamaan:

logit(FD) = β₀ + β₁DR + β₂FDR + β₃NPF + β₄ROE + β₅*BOPO

# ========================
# 1. MODEL REGRESI LOGISTIK
# ========================
# Model regresi logistik
model <- glm(FD ~ DR + FDR + NPF + ROE + BOPO, data = data, family = "binomial")
summary(model)

Call:
glm(formula = FD ~ DR + FDR + NPF + ROE + BOPO, family = "binomial", 
    data = data)

Coefficients:
             Estimate Std. Error z value Pr(>|z|)    
(Intercept) -48.57356    9.78599  -4.964 6.92e-07 ***
DR           37.28003    8.46693   4.403 1.07e-05 ***
FDR           0.03639    0.02572   1.415    0.157    
NPF          -1.54530    0.39582  -3.904 9.46e-05 ***
ROE          -0.78178    0.17915  -4.364 1.28e-05 ***
BOPO          0.27688    0.06259   4.424 9.70e-06 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 524.657  on 447  degrees of freedom
Residual deviance:  48.256  on 442  degrees of freedom
AIC: 60.256

Number of Fisher Scoring iterations: 11

Interpretasi awal:

  1. DR : Koefisien positif dan signifikan → Dengan Nilai 0,000 (0,05)
  2. BOPO: Koefisien positif dan signifikan → Dengan Nilai 0,000 (0,05)
  3. FDR: Koefisien Negatif → Dengan Nilai 0.157 (>0,05)
  4. ROE: Koefisien Postif → Dengan Nilai 0,000 (0,05)
  5. NPF: Positif → Dengan Nilai 0,000 (0,05)

📐 Langkah 5: Uji Statistik & Evaluasi Model

✅ a. Uji Wald (Uji t) Diperoleh dari:

summary(model)

Call:
glm(formula = FD ~ DR + FDR + NPF + ROE + BOPO, family = "binomial", 
    data = data)

Coefficients:
             Estimate Std. Error z value Pr(>|z|)    
(Intercept) -48.57356    9.78599  -4.964 6.92e-07 ***
DR           37.28003    8.46693   4.403 1.07e-05 ***
FDR           0.03639    0.02572   1.415    0.157    
NPF          -1.54530    0.39582  -3.904 9.46e-05 ***
ROE          -0.78178    0.17915  -4.364 1.28e-05 ***
BOPO          0.27688    0.06259   4.424 9.70e-06 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 524.657  on 447  degrees of freedom
Residual deviance:  48.256  on 442  degrees of freedom
AIC: 60.256

Number of Fisher Scoring iterations: 11

Menunjukkan signifikansi masing-masing variabel (p-value). Variabel dengan p < 0.05 dianggap signifikan memengaruhi distress.

✅ b. Uji Kelayakan Model: Hosmer-Lemeshow Test

library(ResourceSelection)
hoslem.test(as.numeric(data$FD), fitted(model), g = 10)

    Hosmer and Lemeshow goodness of fit (GOF) test

data:  as.numeric(data$FD), fitted(model)
X-squared = 8.0196e+12, df = 8, p-value < 2.2e-16
  1. Jika p-value > 0.05, maka model dinyatakan fit terhadap data.

  2. Artinya, tidak ada perbedaan signifikan antara hasil yang diprediksi dan aktual.

✅ c. Koefisien Determinasi: McFadden R-Square

library(pscl)
pR2(model)
fitting null model for pseudo-r2
         llh      llhNull           G2     McFadden         r2ML         r2CU 
 -24.1280870 -262.3282543  476.4003346    0.9080233    0.6547179    0.9488984 
  1. McFadden R² berkisar antara 0 – 1

  2. Nilai > 0.2 = cukup baik dalam regresi logistik

Semakin tinggi → model makin baik menjelaskan variasi distress.

✅ d. Uji Akurasi & EPE (Expectation-Prediction Evaluation)

# Prediksi kelas
data$prob <- predict(model, type = "response")
data$pred_class <- ifelse(data$prob > 0.5, "Distress", "Non-Distress")
# Confusion Matrix
confusionMatrix(as.factor(data$pred_class), data$FD, positive = "Distress")
Confusion Matrix and Statistics

              Reference
Prediction     Non-Distress Distress
  Non-Distress          114        6
  Distress                8      320
                                          
               Accuracy : 0.9688          
                 95% CI : (0.9481, 0.9828)
    No Information Rate : 0.7277          
    P-Value [Acc > NIR] : <2e-16          
                                          
                  Kappa : 0.9207          
                                          
 Mcnemar's Test P-Value : 0.7893          
                                          
            Sensitivity : 0.9816          
            Specificity : 0.9344          
         Pos Pred Value : 0.9756          
         Neg Pred Value : 0.9500          
             Prevalence : 0.7277          
         Detection Rate : 0.7143          
   Detection Prevalence : 0.7321          
      Balanced Accuracy : 0.9580          
                                          
       'Positive' Class : Distress        
                                          

Menghasilkan akurasi, sensitivitas (recall), dan spesifisitas

Diperoleh pula evaluasi EPE (berapa persen prediksi yang benar vs salah)

📊 Langkah 6: Visualisasi Hasil

📌 a. Plot Koefisien

library(broom)
coef_df <- tidy(model)
coef_df

Menampilkan pengaruh tiap variabel terhadap risiko distress

Variabel seperti BOPO dan NPF memiliki pengaruh besar (positif)

ROE menunjukkan pengaruh negatif

📌 b. ROC Curve & AUC

library(pROC)
roc_obj <- roc(data$FD, data$prob)
plot(roc_obj)

auc(roc_obj)
Area under the curve: 0.9981

AUC > 0.7 → model tergolong baik dalam membedakan distress vs non-distress

# Prediksi probabilitas distress
data$Prob_Distress <- predict(model, type = "response")

# Prediksi label: jika Prob > 0.5 maka 'Distress', jika tidak 'Non-Distress'
data$Predicted_Label <- ifelse(data$Prob_Distress > 0.5, "Distress", "Non-Distress")

# Buat label aktual dari FD (0 = Non-Distress, 1 = Distress)
data$FD_label <- factor(data$FD, levels = c(0, 1), labels = c("Non-Distress", "Distress"))

# Buat tabel hasil prediksi
tabel_prediksi <- data %>%
  select(DR, FDR, NPF, ROE, BOPO, FD_label, Prob_Distress, Predicted_Label)
# Tampilkan 10 baris pertama
head(tabel_prediksi, 10)
LS0tDQp0aXRsZTogIkRFVEVSTUlOQU4gRklOQU5DSUFMIERJU1RSRVNTIE1FTkdHVU5BS0FODQpSRUdSRVNJIExPR0lTVElDIEJJTkVSIERBVEEgUEFORUwgUEFEQSBCQU5LDQpVTVVNIFNZQVJJQUggREkgSU5ET05FU0lBDQpQRVJJT0RFIDIwMTYtMjAyMiINCg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOiBkZWZhdWx0DQogIHBkZl9kb2N1bWVudDogZGVmYXVsdA0KLS0tDQpVamlhbiBBa2hpciBTZW1lc3RlciAoVUFTKQ0KDQoNCk5hbWEgOkVseXNhYmV0aCBQdXRyaSBQYW11bmdrYXMgDQoNCk5pbSAgOjIwMjQzMzMzMjAwMjMNCg0KDQojIyDwn46vIFR1anVhbg0KTWVuZ2FuYWxpc2lzIGZha3Rvci1mYWt0b3Iga2V1YW5nYW4geWFuZyBtZW1lbmdhcnVoaSBrZW11bmdraW5hbiB0ZXJqYWRpbnlhIGZpbmFuY2lhbCBkaXN0cmVzcyBwYWRhIHBlcnVzYWhhYW4sIHNlcnRhIG1lbWJhbmd1biBtb2RlbCBwcmVkaWtzaSBiZXJiYXNpcyByZWdyZXNpIGxvZ2lzdGlrIGRlbmdhbiBldmFsdWFzaSBtZW55ZWx1cnVoIGRhbiB2aXN1YWxpc2FzaSBwZW5kdWt1bmcuDQoNCiMjIExhbmdrYWggMSA6IEltcG9ydCBsaWJyYXJ5DQoNCmBgYHtyfQ0KIyBMb2FkIGxpYnJhcnkNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoUmVzb3VyY2VTZWxlY3Rpb24pICAjIEhvc21lci1MZW1lc2hvdyB0ZXN0DQpsaWJyYXJ5KGNhcmV0KSAgICAgICAgICAgICAgIyBDb25mdXNpb24gTWF0cml4DQpsaWJyYXJ5KGJyb29tKSAgICAgICAgICAgICAgIyBUaWR5IG91dHB1dA0KbGlicmFyeShwc2NsKSAgICAgICAgICAgICAgICMgTWNGYWRkZW4ncyBSwrINCmxpYnJhcnkocFJPQykgICAgICAgICAgICAgICAjIFJPQyBDdXJ2ZQ0KbGlicmFyeShjYXJldCkNCmBgYA0KDQoNCiMjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUGVuamVsYXNhbiB0ZW50YW5nIGxpYnJhcnkNCg0KfCBMaWJyYXJ5ICAgICAgICAgICAgICAgICB8IEZ1bmdzaSBVdGFtYSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgS2VndW5hYW4gZGFsYW0gQW5hbGlzaXMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIHwgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gfCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIHwNCnwgKipgcmVhZHhsYCoqICAgICAgICAgICAgfCBNZW1iYWNhIGZpbGUgRXhjZWwgKGAueGxzeGApICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IERpZ3VuYWthbiB1bnR1ayBtZW1iYWNhIGRhdGEgZGFyaSBmaWxlIGBkYXRhIGFuYWxpc2lzLnhsc3hgIGRlbmdhbiBwZXJpbnRhaDogYHJlYWRfZXhjZWwoKWAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCAqKmBkcGx5cmAqKiAgICAgICAgICAgICB8IE1hbmlwdWxhc2kgZGF0YSAoc2VsZWN0LCBtdXRhdGUsIGZpbHRlciwgZGxsKSAgICAgICAgICAgIHwgRGlndW5ha2FuIHVudHVrIG1lbWlsaWgga29sb20gKGBzZWxlY3QoKWApLCBtZW1idWF0IGtvbG9tIGJhcnUgKGBtdXRhdGUoKWApLCBkYW4gbWVueXVzdW4gdWxhbmcgZGF0YSB1bnR1ayB0YWJlbCBwcmVkaWtzaS4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8ICoqYGdncGxvdDJgKiogICAgICAgICAgIHwgVmlzdWFsaXNhc2kgZGF0YSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBEaWd1bmFrYW4gdW50dWsgbWVtYnVhdDogcGxvdCBrb2VmaXNpZW4sIGhpc3RvZ3JhbSBwcm9iYWJpbGl0YXMsIGRhbiB2aXN1YWxpc2FzaSBldmFsdWFzaSBtb2RlbC4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwgKipgYnJvb21gKiogICAgICAgICAgICAgfCBNZXJhcGlrYW4gb3V0cHV0IHN0YXRpc3RpayBtb2RlbCBtZW5qYWRpIGRhdGEgZnJhbWUgICAgICB8IEZ1bmdzaSBgdGlkeSgpYCBkaWd1bmFrYW4gdW50dWsgbWVuZ3ViYWggaGFzaWwgbW9kZWwgKGBnbG1gKSBtZW5qYWRpIGZvcm1hdCB0YWJlbCB5YW5nIGJpc2EgbGFuZ3N1bmcgZGlwYWthaSB1bnR1ayB2aXN1YWxpc2FzaSBrb2VmaXNpZW4uICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCAqKmBwc2NsYCoqICAgICAgICAgICAgICB8IFN0YXRpc3RpayBsYW5qdXRhbiB0ZXJtYXN1ayBNY0ZhZGRlbidzIFLCsiAgICAgICAgICAgICAgICB8IEZ1bmdzaSBgcFIyKClgIGRpZ3VuYWthbiB1bnR1ayBtZW5naGl0dW5nICoqcHNldWRvIFItc3F1YXJlZCoqIHBhZGEgbW9kZWwgbG9naXN0aWssIHNlcGVydGkgTWNGYWRkZW4sIENveC1TbmVsbCwgZGFuIE5hZ2Vsa2Vya2UuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCAqKmBSZXNvdXJjZVNlbGVjdGlvbmAqKiB8IFVqaSBrZWxheWFrYW4gbW9kZWwgbG9naXN0aWsgKEhvc21lci1MZW1lc2hvdykgICAgICAgICAgIHwgRnVuZ3NpIGBob3NsZW0udGVzdCgpYCBkaWd1bmFrYW4gdW50dWsgbWVuZ2V2YWx1YXNpICoqZ29vZG5lc3Mtb2YtZml0KiogZGFyaSBtb2RlbCBsb2dpc3Rpay4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8ICoqYGNhcmV0YCoqICAgICAgICAgICAgIHwgRXZhbHVhc2kgbW9kZWwgcHJlZGlrc2kgKGFrdXJhc2ksIGNvbmZ1c2lvbiBtYXRyaXgsIGRsbCkgfCBGdW5nc2kgYGNvbmZ1c2lvbk1hdHJpeCgpYCBtZW5naGl0dW5nIGFrdXJhc2kgbW9kZWwsIHNlbnNpdGl2aXRhcywgc3Blc2lmaXNpdGFzLCBkYW4gbWVtYnVhdCBldmFsdWFzaSBrbGFzaWZpa2FzaS4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwgKipgcFJPQ2AqKiAgICAgICAgICAgICAgfCBST0MgY3VydmUgZGFuIEFVQyAoQXJlYSBVbmRlciBDdXJ2ZSkgICAgICAgICAgICAgICAgICAgICB8IEZ1bmdzaSBgcm9jKClgIGRhbiBgcGxvdCgpYCBkaWd1bmFrYW4gdW50dWsgbWVuYW1waWxrYW4gKiprdXJ2YSBST0MqKiwgc2VydGEgYGF1YygpYCB1bnR1ayBtZW5naGl0dW5nIG5pbGFpICoqQVVDKirigJRtZW5ndWt1ciBzZWJlcmFwYSBiYWlrIG1vZGVsIG1lbWlzYWhrYW4gZHVhIGtlbGFzIChkaXN0cmVzcyB2cyBub24tZGlzdHJlc3MpLiB8DQoNCg0KDQojIyDwn5OBIExhbmdrYWggMjogSW1wb3J0IGRhdGENCmBgYHtyfQ0KIyBJbXBvcnQgZGF0YQ0KZGF0YSA8LSByZWFkX2V4Y2VsKCJDOi9Vc2Vycy9Nb2Rlcm4vRG93bmxvYWRzL2RhdGEgYW5hbGlzaXMueGxzeCIsIA0KICAgICAgICAgICAgICAgICAgIHNoZWV0ID0gIkRhdGEgVW50dWsgUiIpDQpoZWFkKGRhdGEsIG4gPSAxMCkNCmBgYCAgICAgICAgICAgICAgICAgIA0KDQoNCvCfp6ogRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcyAoRURBKSDigJMgRmluYW5jaWFsIERpc3RyZXNzIERhdGFzZXQNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KEdHYWxseSkgICAgICAgICAgICAgICANCiMgQnVhdCBsYWJlbCBkaXN0cmVzcw0KZGY8LWRhdGENCmRmJEZEX2xhYmVsIDwtIGZhY3RvcihkZiRGRCwgbGV2ZWxzID0gYygwLCAxKSwgbGFiZWxzID0gYygiTm9uLURpc3RyZXNzIiwgIkRpc3RyZXNzIikpDQpgYGANCg0KYGBge3J9DQojIDIuIERpc3RyaWJ1c2kgRGF0YSBUYXJnZXQNCmdncGxvdChkZiwgYWVzKHggPSBGRF9sYWJlbCwgZmlsbCA9IEZEX2xhYmVsKSkgKw0KICBnZW9tX2Jhcih3aWR0aCA9IDAuNSkgKw0KICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1c2kgRmluYW5jaWFsIERpc3RyZXNzIiwgeCA9ICJTdGF0dXMiLCB5ID0gIkp1bWxhaCIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygic3RlZWxibHVlIiwgInNhbG1vbiIpKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQpgYGB7cn0NCiMgMy4gS29yZWxhc2kgQW50YXJhIFZhcmlhYmVsIE51bWVyaWsNCm51bWVyaWNfdmFycyA8LSBkZiAlPiUgc2VsZWN0KERSLCBGRFIsIE5QRiwgUk9FLCBCT1BPKQ0KZ2djb3JyKG51bWVyaWNfdmFycywgbGFiZWwgPSBUUlVFLCBsYWJlbF9zaXplID0gNCwgaGp1c3QgPSAwLjgpICsNCiAgZ2d0aXRsZSgiTWF0cmlrcyBLb3JlbGFzaSBWYXJpYWJlbCBLZXVhbmdhbiIpDQpgYGANCmBgYHtyfQ0KIyA0LiBCb3hwbG90IFZhcmlhYmVsIE51bWVyaWsgQmVyZGFzYXJrYW4gU3RhdHVzIEZEDQpudW1lcmljX25hbWVzIDwtIG5hbWVzKG51bWVyaWNfdmFycykNCmZvciAodmFyIGluIG51bWVyaWNfbmFtZXMpIHsNCiAgcHJpbnQoDQogICAgZ2dwbG90KGRmLCBhZXNfc3RyaW5nKHggPSAiRkRfbGFiZWwiLCB5ID0gdmFyLCBmaWxsID0gIkZEX2xhYmVsIikpICsNCiAgICAgIGdlb21fYm94cGxvdCgpICsNCiAgICAgIGxhYnModGl0bGUgPSBwYXN0ZSgiRGlzdHJpYnVzaSIsIHZhciwgImJlcmRhc2Fya2FuIFN0YXR1cyBGRCIpLCB4ID0gIlN0YXR1cyBGRCIsIHkgPSB2YXIpICsNCiAgICAgIHRoZW1lX21pbmltYWwoKQ0KICApDQp9DQpgYGANCg0KYGBge3J9DQoNCiMgNS4gRGVuc2l0eSBQbG90OiBEaXN0cmlidXNpIFNldGlhcCBWYXJpYWJlbA0KZm9yICh2YXIgaW4gbnVtZXJpY19uYW1lcykgew0KICBwcmludCgNCiAgICBnZ3Bsb3QoZGYsIGFlc19zdHJpbmcoeCA9IHZhciwgZmlsbCA9ICJGRF9sYWJlbCIpKSArDQogICAgICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjUpICsNCiAgICAgIGxhYnModGl0bGUgPSBwYXN0ZSgiRGVuc2l0eSBQbG90IiwgdmFyKSwgeCA9IHZhciwgeSA9ICJEZW5zaXR5IikgKw0KICAgICAgdGhlbWVfbWluaW1hbCgpDQogICkNCn0NCg0KYGBgDQoNCvCfp6AgS2VzaW1wdWxhbiBFREENClZhcmlhYmVsIHNlcGVydGkgQk9QTywgTlBGLCBkYW4gUk9FIG1lbnVuanVra2FuIHBlcmJlZGFhbiBtZW5jb2xvayBhbnRhcmEgRGlzdHJlc3MgdnMgTm9uLURpc3RyZXNzLg0KDQpEYXRhc2V0IGJlcnNpaCwgdGlkYWsgYWRhIG1pc3NpbmcgdmFsdWUgKGJlcmRhc2Fya2FuIHN1bW1hcnkoKSkuDQoNClRpZGFrIGRpdGVtdWthbiBvdXRsaWVyIGVrc3RyZW0geWFuZyBtZW5nZ2FuZ2d1LCBuYW11biBwZXJiZWRhYW4gc2ViYXJhbiBsYXlhayBkaWNhdGF0Lg0KDQpLb3JlbGFzaSBhbnRhciBiZWJlcmFwYSB2YXJpYWJlbCBzZXBlcnRpIERSIGRhbiBCT1BPIHBlcmx1IGRpcGVyaGF0aWthbiBkYWxhbSBtb2RlbGluZy4NCg0KDQojIyDwn5OBIExhbmdrYWggMzogUGVyc2lhcGFuIERhdGENCkRhdGEgZGlhbWJpbCBkYXJpIHNoZWV0IOKAnERhdGEgVW50dWsgUuKAnSBkYWxhbSBmaWxlIEV4Y2VsIHlhbmcgYmVyaXNpIDYgdmFyaWFiZWwga2V1YW5nYW46DQoNCkZEOiBzdGF0dXMgZmluYW5jaWFsIGRpc3RyZXNzIChhc2xpIGJlcnVwYSAwLzEg4oaSIGRpdWJhaCBtZW5qYWRpIGxhYmVsICJEaXN0cmVzcyIgZGFuICJOb24tRGlzdHJlc3MiKQ0KDQpEUjogRGVidCBSYXRpbw0KDQpGRFI6IEZpbmFuY2luZyB0byBEZXBvc2l0IFJhdGlvDQoNCk5QRjogTm9uLVBlcmZvcm1pbmcgRmluYW5jaW5nDQoNClJPRTogUmV0dXJuIG9uIEVxdWl0eQ0KDQpCT1BPOiBSYXNpbyBCZWJhbiBPcGVyYXNpb25hbCB0ZXJoYWRhcCBQZW5kYXBhdGFuIE9wZXJhc2lvbmFsDQoNCmBgYHtyfQ0KIyBQYXN0aWthbiB2YXJpYWJlbCBGRCBhZGFsYWggZmFrdG9yDQpkYXRhJEZEIDwtIGZhY3RvcihkYXRhJEZELCBsZXZlbHMgPSBjKDAsIDEpLCBsYWJlbHMgPSBjKCJOb24tRGlzdHJlc3MiLCAiRGlzdHJlc3MiKSkNCmBgYA0KDQpEZXNrcmlwdGl2ZSBzdGF0aXN0aWMNCmBgYHtyfQ0KIyBNZWxpaGF0IGRlc2tyaXB0aXZlIHN0YXRpc3RpYw0Kc3VtbWFyeShkYXRhKQ0KYGBgDQoNCiMjIOKame+4jyBMYW5na2FoIDQ6IFBlbW9kZWxhbiBSZWdyZXNpIExvZ2lzdGlrDQpNb2RlbCBkaWJhbmd1biBkZW5nYW4gcGVyc2FtYWFuOg0KDQpsb2dpdChGRCkgPSDOsuKCgCArIM6y4oKBKkRSICsgzrLigoIqRkRSICsgzrLigoMqTlBGICsgzrLigoQqUk9FICsgzrLigoUqQk9QTw0KDQpgYGB7cn0NCiMgPT09PT09PT09PT09PT09PT09PT09PT09DQojIDEuIE1PREVMIFJFR1JFU0kgTE9HSVNUSUsNCiMgPT09PT09PT09PT09PT09PT09PT09PT09DQojIE1vZGVsIHJlZ3Jlc2kgbG9naXN0aWsNCm1vZGVsIDwtIGdsbShGRCB+IERSICsgRkRSICsgTlBGICsgUk9FICsgQk9QTywgZGF0YSA9IGRhdGEsIGZhbWlseSA9ICJiaW5vbWlhbCIpDQpzdW1tYXJ5KG1vZGVsKQ0KYGBgDQoNCkludGVycHJldGFzaSBhd2FsOg0KDQoxLiBEUiA6IEtvZWZpc2llbiBwb3NpdGlmIGRhbiBzaWduaWZpa2FuIOKGkiBEZW5nYW4gTmlsYWkgMCwwMDAgKDAsMDUpDQoyLiBCT1BPOiBLb2VmaXNpZW4gcG9zaXRpZiBkYW4gc2lnbmlmaWthbiDihpIgRGVuZ2FuIE5pbGFpIDAsMDAwICgwLDA1KQ0KMy4gRkRSOiBLb2VmaXNpZW4gTmVnYXRpZiDihpIgRGVuZ2FuIE5pbGFpIDAuMTU3ICg+MCwwNSkNCjQuIFJPRTogS29lZmlzaWVuIFBvc3RpZiDihpIgRGVuZ2FuIE5pbGFpIDAsMDAwICgwLDA1KQ0KNS4gTlBGOiBQb3NpdGlmIOKGkiBEZW5nYW4gTmlsYWkgMCwwMDAgKDAsMDUpDQoNCiMjIPCfk5AgTGFuZ2thaCA1OiBVamkgU3RhdGlzdGlrICYgRXZhbHVhc2kgTW9kZWwNCuKchSBhLiBVamkgV2FsZCAoVWppIHQpDQpEaXBlcm9sZWggZGFyaToNCg0KYGBge3J9DQpzdW1tYXJ5KG1vZGVsKQ0KYGBgDQoNCk1lbnVuanVra2FuIHNpZ25pZmlrYW5zaSBtYXNpbmctbWFzaW5nIHZhcmlhYmVsIChwLXZhbHVlKS4gVmFyaWFiZWwgZGVuZ2FuIHAgPCAwLjA1IGRpYW5nZ2FwIHNpZ25pZmlrYW4gbWVtZW5nYXJ1aGkgZGlzdHJlc3MuDQoNCuKchSBiLiBVamkgS2VsYXlha2FuIE1vZGVsOiBIb3NtZXItTGVtZXNob3cgVGVzdA0KYGBge3J9DQpsaWJyYXJ5KFJlc291cmNlU2VsZWN0aW9uKQ0KaG9zbGVtLnRlc3QoYXMubnVtZXJpYyhkYXRhJEZEKSwgZml0dGVkKG1vZGVsKSwgZyA9IDEwKQ0KYGBgDQoxLiBKaWthIHAtdmFsdWUgPiAwLjA1LCBtYWthIG1vZGVsIGRpbnlhdGFrYW4gZml0IHRlcmhhZGFwIGRhdGEuDQoNCjIuIEFydGlueWEsIHRpZGFrIGFkYSBwZXJiZWRhYW4gc2lnbmlmaWthbiBhbnRhcmEgaGFzaWwgeWFuZyBkaXByZWRpa3NpIGRhbiBha3R1YWwuDQoNCuKchSBjLiBLb2VmaXNpZW4gRGV0ZXJtaW5hc2k6IE1jRmFkZGVuIFItU3F1YXJlDQpgYGB7cn0NCmxpYnJhcnkocHNjbCkNCnBSMihtb2RlbCkNCmBgYA0KDQoxLiBNY0ZhZGRlbiBSwrIgYmVya2lzYXIgYW50YXJhIDAg4oCTIDENCg0KMi4gTmlsYWkgPiAwLjIgPSBjdWt1cCBiYWlrIGRhbGFtIHJlZ3Jlc2kgbG9naXN0aWsNCg0KU2VtYWtpbiB0aW5nZ2kg4oaSIG1vZGVsIG1ha2luIGJhaWsgbWVuamVsYXNrYW4gdmFyaWFzaSBkaXN0cmVzcy4NCg0KDQrinIUgZC4gVWppIEFrdXJhc2kgJiBFUEUgKEV4cGVjdGF0aW9uLVByZWRpY3Rpb24gRXZhbHVhdGlvbikNCmBgYHtyfQ0KIyBQcmVkaWtzaSBrZWxhcw0KZGF0YSRwcm9iIDwtIHByZWRpY3QobW9kZWwsIHR5cGUgPSAicmVzcG9uc2UiKQ0KZGF0YSRwcmVkX2NsYXNzIDwtIGlmZWxzZShkYXRhJHByb2IgPiAwLjUsICJEaXN0cmVzcyIsICJOb24tRGlzdHJlc3MiKQ0KYGBgDQoNCmBgYHtyfQ0KIyBDb25mdXNpb24gTWF0cml4DQpjb25mdXNpb25NYXRyaXgoYXMuZmFjdG9yKGRhdGEkcHJlZF9jbGFzcyksIGRhdGEkRkQsIHBvc2l0aXZlID0gIkRpc3RyZXNzIikNCmBgYA0KDQpNZW5naGFzaWxrYW4gYWt1cmFzaSwgc2Vuc2l0aXZpdGFzIChyZWNhbGwpLCBkYW4gc3Blc2lmaXNpdGFzDQoNCkRpcGVyb2xlaCBwdWxhIGV2YWx1YXNpIEVQRSAoYmVyYXBhIHBlcnNlbiBwcmVkaWtzaSB5YW5nIGJlbmFyIHZzIHNhbGFoKQ0KDQoNCiMjIPCfk4ogTGFuZ2thaCA2OiBWaXN1YWxpc2FzaSBIYXNpbA0K8J+TjCBhLiBQbG90IEtvZWZpc2llbg0KYGBge3J9DQpsaWJyYXJ5KGJyb29tKQ0KY29lZl9kZiA8LSB0aWR5KG1vZGVsKQ0KY29lZl9kZg0KYGBgDQpNZW5hbXBpbGthbiBwZW5nYXJ1aCB0aWFwIHZhcmlhYmVsIHRlcmhhZGFwIHJpc2lrbyBkaXN0cmVzcw0KDQpWYXJpYWJlbCBzZXBlcnRpIEJPUE8gZGFuIE5QRiBtZW1pbGlraSBwZW5nYXJ1aCBiZXNhciAocG9zaXRpZikNCg0KUk9FIG1lbnVuanVra2FuIHBlbmdhcnVoIG5lZ2F0aWYNCg0K8J+TjCBiLiBST0MgQ3VydmUgJiBBVUMNCmBgYHtyfQ0KbGlicmFyeShwUk9DKQ0Kcm9jX29iaiA8LSByb2MoZGF0YSRGRCwgZGF0YSRwcm9iKQ0KcGxvdChyb2Nfb2JqKQ0KYGBgDQoNCmBgYHtyfQ0KYXVjKHJvY19vYmopDQpgYGANCg0KQVVDID4gMC43IOKGkiBtb2RlbCB0ZXJnb2xvbmcgYmFpayBkYWxhbSBtZW1iZWRha2FuIGRpc3RyZXNzIHZzIG5vbi1kaXN0cmVzcw0KYGBge3J9DQojIFByZWRpa3NpIHByb2JhYmlsaXRhcyBkaXN0cmVzcw0KZGF0YSRQcm9iX0Rpc3RyZXNzIDwtIHByZWRpY3QobW9kZWwsIHR5cGUgPSAicmVzcG9uc2UiKQ0KDQojIFByZWRpa3NpIGxhYmVsOiBqaWthIFByb2IgPiAwLjUgbWFrYSAnRGlzdHJlc3MnLCBqaWthIHRpZGFrICdOb24tRGlzdHJlc3MnDQpkYXRhJFByZWRpY3RlZF9MYWJlbCA8LSBpZmVsc2UoZGF0YSRQcm9iX0Rpc3RyZXNzID4gMC41LCAiRGlzdHJlc3MiLCAiTm9uLURpc3RyZXNzIikNCg0KIyBCdWF0IGxhYmVsIGFrdHVhbCBkYXJpIEZEICgwID0gTm9uLURpc3RyZXNzLCAxID0gRGlzdHJlc3MpDQpkYXRhJEZEX2xhYmVsIDwtIGZhY3RvcihkYXRhJEZELCBsZXZlbHMgPSBjKDAsIDEpLCBsYWJlbHMgPSBjKCJOb24tRGlzdHJlc3MiLCAiRGlzdHJlc3MiKSkNCg0KIyBCdWF0IHRhYmVsIGhhc2lsIHByZWRpa3NpDQp0YWJlbF9wcmVkaWtzaSA8LSBkYXRhICU+JQ0KICBzZWxlY3QoRFIsIEZEUiwgTlBGLCBST0UsIEJPUE8sIEZEX2xhYmVsLCBQcm9iX0Rpc3RyZXNzLCBQcmVkaWN0ZWRfTGFiZWwpDQpgYGANCg0KYGBge3J9DQojIFRhbXBpbGthbiAxMCBiYXJpcyBwZXJ0YW1hDQpoZWFkKHRhYmVsX3ByZWRpa3NpLCAxMCkNCmBgYA0KDQoNCg==