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
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:
- DR : Koefisien positif dan signifikan → Dengan Nilai 0,000
(0,05)
- BOPO: Koefisien positif dan signifikan → Dengan Nilai 0,000
(0,05)
- FDR: Koefisien Negatif → Dengan Nilai 0.157 (>0,05)
- ROE: Koefisien Postif → Dengan Nilai 0,000 (0,05)
- 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
Jika p-value > 0.05, maka model dinyatakan fit terhadap
data.
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
McFadden R² berkisar antara 0 – 1
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==