1. Load dataset

Dataset yang digunakan berasal dari kaggle dengan link: https://www.kaggle.com/datasets/arjunbhasin2013/ccdata?utm_source=chatgpt.com

data <- read.csv("/Users/nabilanasywazen/Downloads/CC GENERAL.csv")
data

2. Seleksi Fitur

features <- data[, c('BALANCE', 
                     'CREDIT_LIMIT', 
                     'PAYMENTS', 
                     'MINIMUM_PAYMENTS', 
                     'PRC_FULL_PAYMENT', 
                     'CASH_ADVANCE', 
                     'CASH_ADVANCE_FREQUENCY', 
                     'TENURE')]
features

3. Handling Missing Value

3.1 Cek Missing Value Pada Fitur yang Dipilih

colSums(is.na(features))
               BALANCE           CREDIT_LIMIT               PAYMENTS       MINIMUM_PAYMENTS       PRC_FULL_PAYMENT           CASH_ADVANCE 
                     0                      1                      0                    313                      0                      0 
CASH_ADVANCE_FREQUENCY                 TENURE 
                     0                      0 

3.2 Drop Baris Data yang Mengandung Missing Value

df <- features[!is.na(features$MINIMUM_PAYMENTS) & !is.na(features$CREDIT_LIMIT), ]
colSums(is.na(df))
               BALANCE           CREDIT_LIMIT               PAYMENTS       MINIMUM_PAYMENTS       PRC_FULL_PAYMENT           CASH_ADVANCE 
                     0                      0                      0                      0                      0                      0 
CASH_ADVANCE_FREQUENCY                 TENURE 
                     0                      0 

4. Visualisasi Box Plot untuk Deteksi Outliers

library(ggplot2)
library(tidyr)
library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
numeric_data <- df %>% select_if(is.numeric)
long_data <- pivot_longer(numeric_data, cols = everything(), names_to = "Feature", values_to = "Value")

ggplot(long_data, aes(x = Value, y = Feature)) +
  geom_boxplot(fill = "lightblue", color = "navy") +
  theme_minimal() +
  labs(title = "Boxplot Semua Fitur", x = "Value", y = "Feature")

Boxplot menunjukkan hampir semua fitur yang digunakan mengandung outliers dalam jumlah yang signifikam. Terlihat jelas pada fitur “MINIMUM_PAYMENTS”, “PAYMENTS”, dan “CASH_ADVANCE” menunjukkan adanya variasi ekstrem dalam perilaku nasabah.

5. Normalisasi Data

Normalisasi pada semua fitur numerik dilakukan untuk membuat semua fitur berada pada range nilai yang sama.

minmax_scaled <- as.data.frame(lapply(df, function(x) (x - min(x)) / (max(x) - min(x))))
numeric_data <- minmax_scaled %>% select_if(is.numeric)
long_data <- pivot_longer(numeric_data, cols = everything(), names_to = "Feature", values_to = "Value")

ggplot(long_data, aes(x = Value, y = Feature)) +
  geom_boxplot(fill = "lightblue", color = "navy") +
  theme_minimal() +
  labs(title = "Boxplot Setelah Normalisasi", x = "Value", y = "Feature")

6. Clustering

Ketiga fitur ini dipilih karena melengkapi penggambaran menyeluruh tentang perilaku kredit nasabah.

library(meanShiftR)
library(scatterplot3d)

scaled_data <- as.matrix(minmax_scaled[, c("BALANCE", "PAYMENTS", "CREDIT_LIMIT")])
bandwidth_estimate <- rep(0.1293, ncol(scaled_data))

ms_result <- meanShift(scaled_data, bandwidth = bandwidth_estimate)
cluster_centers <- ms_result$centers

colors <- rainbow(length(unique(ms_result$assignment)))
plot3d <- scatterplot3d(scaled_data[, 1], scaled_data[, 2], scaled_data[, 3], 
                        pch = 16, 
                        color = colors[ms_result$assignment],
                        xlab = colnames(scaled_data)[1], 
                        ylab = colnames(scaled_data)[2], 
                        zlab = colnames(scaled_data)[3],
                        main = "MeanShift Clustering 3D Plot")

plot3d$points3d(cluster_centers[, 1], cluster_centers[, 2], cluster_centers[, 3],
                col = "black", pch = 4, cex = 3, lwd = 2) 

Clustering menggunakan MeanSHift dengan bandwidth 0.1293 dihasilkan 14 cluster dengan visualisasi warna yang berbeda-beda.

length(unique(ms_result$assignment))
[1] 14

7. Analisis Karakteristik Tiap CLuster

7.1 Menghitung Rata-rata, Nilai Min, dan Nilai Max Untuk Tiap Fitur

library(dplyr)

df$Cluster <- as.factor(ms_result$assignment)
cluster_summary <- df %>%
  group_by(Cluster) %>%
  summarise(
    avg_balance = mean(BALANCE, na.rm = TRUE),
    avg_payments = mean(PAYMENTS, na.rm = TRUE),
    avg_credit_limit = mean(CREDIT_LIMIT, na.rm = TRUE),
    min_balance = min(BALANCE, na.rm = TRUE),
    max_balance = max(BALANCE, na.rm = TRUE),
    min_payments = min(PAYMENTS, na.rm = TRUE),
    max_payments = max(PAYMENTS, na.rm = TRUE),
    min_credit_limit = min(CREDIT_LIMIT, na.rm = TRUE),
    max_credit_limit = max(CREDIT_LIMIT, na.rm = TRUE)
  )

print(cluster_summary)

7.2 Analisis Tingkat Risiko Tiap Cluster

library(dplyr)

cluster_risk <- cluster_summary %>%
  mutate(
    bcl_ratio = avg_balance / avg_credit_limit,              
    pb_ratio  = avg_payments / avg_balance,                  
    risk_level = case_when(
      bcl_ratio >= 0.8 & pb_ratio < 0.5  ~ "Tinggi",
      bcl_ratio >= 0.6 & pb_ratio < 1.0  ~ "Sedang",
      pb_ratio >= 1.0                    ~ "Rendah",
      TRUE                               ~ "Sedang"  
    )
  )

# Lihat hasil akhir
print(cluster_risk %>% select(Cluster, avg_balance, avg_payments, avg_credit_limit, bcl_ratio, pb_ratio, risk_level))

8. Evaluasi Silhouette Score

Silhouette Index digunakan untuk menggambarkan seberapa baik kualitas hasil clustering yang telah dilakukan.

library(cluster)

sil <- silhouette(ms_result$assignment, dist(scaled_data))
mean_silhouette_score <- mean(sil[, 3])
print(mean_silhouette_score)
[1] 0.7425532
LS0tCnRpdGxlOiAiQW5hbGlzaXMgQ2x1c3RlcmluZyBQcm9maWwgTmFzYWJhaCBLcmVkaXQgTWVuZ2d1bmFrYW4gTWVhblNoaWZ0IgphdXRob3I6Ci0gMS4gSGFzbmEgTGVzdGFyaSAoMjMwMzE1NTQwMzMpCi0gMi4gTmFiaWxhIE5hc3l3YSBaZW4gKDIzMDMxNTU0MTE1KQotIDMuIERhZmlubmEgQXJ0aGEgS2lyYW5hICgyMzAzMTU1NDE1NykKLSAiRG9zZW4gUGVuZ2FtcHU6IElrZSBGaXRyaXlhbmluZ3NpaCwgTS5TaSIgCi0gIk1hdGEgS3VsaWFoOiBBbmFsaXNpcyBNdWx0aXZhcmlhdCIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAyCiAgICB0aGVtZTogdW5pdGVkCiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAyCiAgICBkZl9wcmludDogcGFnZWQKICAgIHRoZW1lOiBzaW1wbGV4Ci0tLQoKIyAxLiBMb2FkIGRhdGFzZXQKRGF0YXNldCB5YW5nIGRpZ3VuYWthbiBiZXJhc2FsIGRhcmkga2FnZ2xlIGRlbmdhbiBsaW5rOiBodHRwczovL3d3dy5rYWdnbGUuY29tL2RhdGFzZXRzL2FyanVuYmhhc2luMjAxMy9jY2RhdGE/dXRtX3NvdXJjZT1jaGF0Z3B0LmNvbQpgYGB7cn0KZGF0YSA8LSByZWFkLmNzdigiL1VzZXJzL25hYmlsYW5hc3l3YXplbi9Eb3dubG9hZHMvQ0MgR0VORVJBTC5jc3YiKQpkYXRhCmBgYAojIDIuIFNlbGVrc2kgRml0dXIKYGBge3J9CmZlYXR1cmVzIDwtIGRhdGFbLCBjKCdCQUxBTkNFJywgCiAgICAgICAgICAgICAgICAgICAgICdDUkVESVRfTElNSVQnLCAKICAgICAgICAgICAgICAgICAgICAgJ1BBWU1FTlRTJywgCiAgICAgICAgICAgICAgICAgICAgICdNSU5JTVVNX1BBWU1FTlRTJywgCiAgICAgICAgICAgICAgICAgICAgICdQUkNfRlVMTF9QQVlNRU5UJywgCiAgICAgICAgICAgICAgICAgICAgICdDQVNIX0FEVkFOQ0UnLCAKICAgICAgICAgICAgICAgICAgICAgJ0NBU0hfQURWQU5DRV9GUkVRVUVOQ1knLCAKICAgICAgICAgICAgICAgICAgICAgJ1RFTlVSRScpXQpmZWF0dXJlcwpgYGAKIyAzLiBIYW5kbGluZyBNaXNzaW5nIFZhbHVlCiMjIDMuMSBDZWsgTWlzc2luZyBWYWx1ZSBQYWRhIEZpdHVyIHlhbmcgRGlwaWxpaApgYGB7cn0KY29sU3Vtcyhpcy5uYShmZWF0dXJlcykpCmBgYAoKIyMgMy4yIERyb3AgQmFyaXMgRGF0YSB5YW5nIE1lbmdhbmR1bmcgTWlzc2luZyBWYWx1ZQpgYGB7cn0KZGYgPC0gZmVhdHVyZXNbIWlzLm5hKGZlYXR1cmVzJE1JTklNVU1fUEFZTUVOVFMpICYgIWlzLm5hKGZlYXR1cmVzJENSRURJVF9MSU1JVCksIF0KY29sU3Vtcyhpcy5uYShkZikpCmBgYAojIDQuIFZpc3VhbGlzYXNpIEJveCBQbG90IHVudHVrIERldGVrc2kgT3V0bGllcnMKYGBge3J9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeSh0aWR5cikKbGlicmFyeShkcGx5cikKCm51bWVyaWNfZGF0YSA8LSBkZiAlPiUgc2VsZWN0X2lmKGlzLm51bWVyaWMpCmxvbmdfZGF0YSA8LSBwaXZvdF9sb25nZXIobnVtZXJpY19kYXRhLCBjb2xzID0gZXZlcnl0aGluZygpLCBuYW1lc190byA9ICJGZWF0dXJlIiwgdmFsdWVzX3RvID0gIlZhbHVlIikKCmdncGxvdChsb25nX2RhdGEsIGFlcyh4ID0gVmFsdWUsIHkgPSBGZWF0dXJlKSkgKwogIGdlb21fYm94cGxvdChmaWxsID0gImxpZ2h0Ymx1ZSIsIGNvbG9yID0gIm5hdnkiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIkJveHBsb3QgU2VtdWEgRml0dXIiLCB4ID0gIlZhbHVlIiwgeSA9ICJGZWF0dXJlIikKCmBgYApCb3hwbG90IG1lbnVuanVra2FuIGhhbXBpciBzZW11YSBmaXR1ciB5YW5nIGRpZ3VuYWthbiBtZW5nYW5kdW5nIG91dGxpZXJzIGRhbGFtIGp1bWxhaCB5YW5nIHNpZ25pZmlrYW0uIFRlcmxpaGF0IGplbGFzIHBhZGEgZml0dXIgIk1JTklNVU1fUEFZTUVOVFMiLCAiUEFZTUVOVFMiLCBkYW4gIkNBU0hfQURWQU5DRSIgbWVudW5qdWtrYW4gYWRhbnlhIHZhcmlhc2kgZWtzdHJlbSBkYWxhbSBwZXJpbGFrdSBuYXNhYmFoLiAKCiMgNS4gTm9ybWFsaXNhc2kgRGF0YSAKTm9ybWFsaXNhc2kgcGFkYSBzZW11YSBmaXR1ciBudW1lcmlrIGRpbGFrdWthbiB1bnR1ayBtZW1idWF0IHNlbXVhIGZpdHVyIGJlcmFkYSBwYWRhIHJhbmdlIG5pbGFpIHlhbmcgc2FtYS4gCmBgYHtyfQptaW5tYXhfc2NhbGVkIDwtIGFzLmRhdGEuZnJhbWUobGFwcGx5KGRmLCBmdW5jdGlvbih4KSAoeCAtIG1pbih4KSkgLyAobWF4KHgpIC0gbWluKHgpKSkpCm51bWVyaWNfZGF0YSA8LSBtaW5tYXhfc2NhbGVkICU+JSBzZWxlY3RfaWYoaXMubnVtZXJpYykKbG9uZ19kYXRhIDwtIHBpdm90X2xvbmdlcihudW1lcmljX2RhdGEsIGNvbHMgPSBldmVyeXRoaW5nKCksIG5hbWVzX3RvID0gIkZlYXR1cmUiLCB2YWx1ZXNfdG8gPSAiVmFsdWUiKQoKZ2dwbG90KGxvbmdfZGF0YSwgYWVzKHggPSBWYWx1ZSwgeSA9IEZlYXR1cmUpKSArCiAgZ2VvbV9ib3hwbG90KGZpbGwgPSAibGlnaHRibHVlIiwgY29sb3IgPSAibmF2eSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiQm94cGxvdCBTZXRlbGFoIE5vcm1hbGlzYXNpIiwgeCA9ICJWYWx1ZSIsIHkgPSAiRmVhdHVyZSIpCmBgYAojIDYuIENsdXN0ZXJpbmcKS2V0aWdhIGZpdHVyIGluaSBkaXBpbGloIGthcmVuYSBtZWxlbmdrYXBpIHBlbmdnYW1iYXJhbiBtZW55ZWx1cnVoIHRlbnRhbmcgcGVyaWxha3Uga3JlZGl0IG5hc2FiYWguIAoKLSAiQkFMQU5DRSIgPSBNZW5nZ2FtYmFya2FuIHRlbnRhbmcgc2ViZXJhcGEgYmVzYXIgcGluamFtYW4gY3JlZGl0IG5hc2FiYWgKLSAiUEFZTUVOVFMiID0gTWVuZ2dhbWJhcmthbiB0ZW50YW5nIHBlbWJheWFyYW0gcGluamFtYW4gY3JlZGl0IHlhbmcgdGVsYWggZGlsYWt1a2FuIG9sZWggbmFzYWJhaAotICJDUkVESVRfTElNSVQiID0gTWVuZ2dhbWJhcmthbiB0ZW50YW5nIHNlYmVyYXBhIGJlYXIga2FwYXNpdGFzIG5hc2FiYWggZGFsYW0gbWVtaWxpa2kgcGluamFtYW4gY3JlZGl0IApgYGB7cn0KbGlicmFyeShtZWFuU2hpZnRSKQpsaWJyYXJ5KHNjYXR0ZXJwbG90M2QpCgpzY2FsZWRfZGF0YSA8LSBhcy5tYXRyaXgobWlubWF4X3NjYWxlZFssIGMoIkJBTEFOQ0UiLCAiUEFZTUVOVFMiLCAiQ1JFRElUX0xJTUlUIildKQpiYW5kd2lkdGhfZXN0aW1hdGUgPC0gcmVwKDAuMTI5MywgbmNvbChzY2FsZWRfZGF0YSkpCgptc19yZXN1bHQgPC0gbWVhblNoaWZ0KHNjYWxlZF9kYXRhLCBiYW5kd2lkdGggPSBiYW5kd2lkdGhfZXN0aW1hdGUpCmNsdXN0ZXJfY2VudGVycyA8LSBtc19yZXN1bHQkY2VudGVycwoKY29sb3JzIDwtIHJhaW5ib3cobGVuZ3RoKHVuaXF1ZShtc19yZXN1bHQkYXNzaWdubWVudCkpKQpwbG90M2QgPC0gc2NhdHRlcnBsb3QzZChzY2FsZWRfZGF0YVssIDFdLCBzY2FsZWRfZGF0YVssIDJdLCBzY2FsZWRfZGF0YVssIDNdLCAKICAgICAgICAgICAgICAgICAgICAgICAgcGNoID0gMTYsIAogICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGNvbG9yc1ttc19yZXN1bHQkYXNzaWdubWVudF0sCiAgICAgICAgICAgICAgICAgICAgICAgIHhsYWIgPSBjb2xuYW1lcyhzY2FsZWRfZGF0YSlbMV0sIAogICAgICAgICAgICAgICAgICAgICAgICB5bGFiID0gY29sbmFtZXMoc2NhbGVkX2RhdGEpWzJdLCAKICAgICAgICAgICAgICAgICAgICAgICAgemxhYiA9IGNvbG5hbWVzKHNjYWxlZF9kYXRhKVszXSwKICAgICAgICAgICAgICAgICAgICAgICAgbWFpbiA9ICJNZWFuU2hpZnQgQ2x1c3RlcmluZyAzRCBQbG90IikKCnBsb3QzZCRwb2ludHMzZChjbHVzdGVyX2NlbnRlcnNbLCAxXSwgY2x1c3Rlcl9jZW50ZXJzWywgMl0sIGNsdXN0ZXJfY2VudGVyc1ssIDNdLAogICAgICAgICAgICAgICAgY29sID0gImJsYWNrIiwgcGNoID0gNCwgY2V4ID0gMywgbHdkID0gMikgCmBgYApDbHVzdGVyaW5nIG1lbmdndW5ha2FuIE1lYW5TSGlmdCBkZW5nYW4gYmFuZHdpZHRoIDAuMTI5MyBkaWhhc2lsa2FuIDE0IGNsdXN0ZXIgZGVuZ2FuIHZpc3VhbGlzYXNpIHdhcm5hIHlhbmcgYmVyYmVkYS1iZWRhLgpgYGB7cn0KbGVuZ3RoKHVuaXF1ZShtc19yZXN1bHQkYXNzaWdubWVudCkpCmBgYAojIDcuIEFuYWxpc2lzIEthcmFrdGVyaXN0aWsgVGlhcCBDTHVzdGVyCiMjIDcuMSBNZW5naGl0dW5nIFJhdGEtcmF0YSwgTmlsYWkgTWluLCBkYW4gTmlsYWkgTWF4IFVudHVrIFRpYXAgRml0dXIKYGBge3J9CmxpYnJhcnkoZHBseXIpCgpkZiRDbHVzdGVyIDwtIGFzLmZhY3Rvcihtc19yZXN1bHQkYXNzaWdubWVudCkKY2x1c3Rlcl9zdW1tYXJ5IDwtIGRmICU+JQogIGdyb3VwX2J5KENsdXN0ZXIpICU+JQogIHN1bW1hcmlzZSgKICAgIGF2Z19iYWxhbmNlID0gbWVhbihCQUxBTkNFLCBuYS5ybSA9IFRSVUUpLAogICAgYXZnX3BheW1lbnRzID0gbWVhbihQQVlNRU5UUywgbmEucm0gPSBUUlVFKSwKICAgIGF2Z19jcmVkaXRfbGltaXQgPSBtZWFuKENSRURJVF9MSU1JVCwgbmEucm0gPSBUUlVFKSwKICAgIG1pbl9iYWxhbmNlID0gbWluKEJBTEFOQ0UsIG5hLnJtID0gVFJVRSksCiAgICBtYXhfYmFsYW5jZSA9IG1heChCQUxBTkNFLCBuYS5ybSA9IFRSVUUpLAogICAgbWluX3BheW1lbnRzID0gbWluKFBBWU1FTlRTLCBuYS5ybSA9IFRSVUUpLAogICAgbWF4X3BheW1lbnRzID0gbWF4KFBBWU1FTlRTLCBuYS5ybSA9IFRSVUUpLAogICAgbWluX2NyZWRpdF9saW1pdCA9IG1pbihDUkVESVRfTElNSVQsIG5hLnJtID0gVFJVRSksCiAgICBtYXhfY3JlZGl0X2xpbWl0ID0gbWF4KENSRURJVF9MSU1JVCwgbmEucm0gPSBUUlVFKQogICkKCnByaW50KGNsdXN0ZXJfc3VtbWFyeSkKYGBgCiMjIDcuMiBBbmFsaXNpcyBUaW5na2F0IFJpc2lrbyBUaWFwIENsdXN0ZXIKYGBge3J9CmxpYnJhcnkoZHBseXIpCgpjbHVzdGVyX3Jpc2sgPC0gY2x1c3Rlcl9zdW1tYXJ5ICU+JQogIG11dGF0ZSgKICAgIGJjbF9yYXRpbyA9IGF2Z19iYWxhbmNlIC8gYXZnX2NyZWRpdF9saW1pdCwgICAgICAgICAgICAgIAogICAgcGJfcmF0aW8gID0gYXZnX3BheW1lbnRzIC8gYXZnX2JhbGFuY2UsICAgICAgICAgICAgICAgICAgCiAgICByaXNrX2xldmVsID0gY2FzZV93aGVuKAogICAgICBiY2xfcmF0aW8gPj0gMC44ICYgcGJfcmF0aW8gPCAwLjUgIH4gIlRpbmdnaSIsCiAgICAgIGJjbF9yYXRpbyA+PSAwLjYgJiBwYl9yYXRpbyA8IDEuMCAgfiAiU2VkYW5nIiwKICAgICAgcGJfcmF0aW8gPj0gMS4wICAgICAgICAgICAgICAgICAgICB+ICJSZW5kYWgiLAogICAgICBUUlVFICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH4gIlNlZGFuZyIgIAogICAgKQogICkKCiMgTGloYXQgaGFzaWwgYWtoaXIKcHJpbnQoY2x1c3Rlcl9yaXNrICU+JSBzZWxlY3QoQ2x1c3RlciwgYXZnX2JhbGFuY2UsIGF2Z19wYXltZW50cywgYXZnX2NyZWRpdF9saW1pdCwgYmNsX3JhdGlvLCBwYl9yYXRpbywgcmlza19sZXZlbCkpCmBgYAojIDguIEV2YWx1YXNpIFNpbGhvdWV0dGUgU2NvcmUgClNpbGhvdWV0dGUgSW5kZXggZGlndW5ha2FuIHVudHVrIG1lbmdnYW1iYXJrYW4gc2ViZXJhcGEgYmFpayBrdWFsaXRhcyBoYXNpbCBjbHVzdGVyaW5nIHlhbmcgdGVsYWggZGlsYWt1a2FuLiAgCgotIE5pbGFpIG1lbmRla2F0aSAxIGJlcmFydGkgZGF0YSB0ZXJzZWJ1dCBjb2NvayBkZW5nYW4ga2xhc3RlciBkYXRhIGl0dSBzZW5kaXJpIGRhbiBqYXVoIGRhcmkga2Fsc3RlciBsYWluCi0gTmlsYWkgbWVuZGVrYXRpIDAgYmVyYXJ0aSBkYXRhIG1lbmdhbGFtaSBvdmVybGFwcGluZyAKLSBOaWxhaSBtZW5kZWthdGkgLTEgZGF0YSBtdW5na2luIG1lbmdhbGFtaSBzYWxhaCBjbHVzdGVyaW5nCmBgYHtyfQpsaWJyYXJ5KGNsdXN0ZXIpCgpzaWwgPC0gc2lsaG91ZXR0ZShtc19yZXN1bHQkYXNzaWdubWVudCwgZGlzdChzY2FsZWRfZGF0YSkpCm1lYW5fc2lsaG91ZXR0ZV9zY29yZSA8LSBtZWFuKHNpbFssIDNdKQpwcmludChtZWFuX3NpbGhvdWV0dGVfc2NvcmUpCgpgYGAK