Dataset
Dataset yang digunakan adalah User Knowledge Modeling dari UCI
Machine Learning Repository. Dataset ini digunakan untuk menganalisis
tingkat pengetahuan pengguna berdasarkan aktivitas belajar.
Variabel dalam dataset ini dapat dijelaskan sebagai berikut:
1. STG (Study Time Goal) = Waktu belajar
2. SCG (Study Count Goal) = Jumlah pengulangan materi
3. STR (Study Time Real) = Waktu belajar aktual
4. LPR (Learning Process Rate) = Tingkat pemahaman selama
proses belajar
5. PEG (Performance Evaluation Grade) = Hasil evaluasi
belajar
6. UNS (User Knowledge Level) = Tingkat pengetahuan pengguna
(Target)
Import Data
library(readxl)
user <- read_excel("C:/Users/priya/Downloads/User Knowledge Modeling.xlsx")
head(user)
str(user)
## tibble [258 × 6] (S3: tbl_df/tbl/data.frame)
## $ STG: num [1:258] 0 0.08 0.06 0.1 0.08 0.09 0.1 0.15 0.2 0 ...
## $ SCG: num [1:258] 0 0.08 0.06 0.1 0.08 0.15 0.1 0.02 0.14 0 ...
## $ STR: num [1:258] 0 0.1 0.05 0.15 0.08 0.4 0.43 0.34 0.35 0.5 ...
## $ LPR: num [1:258] 0 0.24 0.25 0.65 0.98 0.1 0.29 0.4 0.72 0.2 ...
## $ PEG: num [1:258] 0 0.9 0.33 0.3 0.24 0.66 0.56 0.01 0.25 0.85 ...
## $ UNS: chr [1:258] "very_low" "High" "Low" "Middle" ...
Dataset terdiri dari 258 obs dengan 6 var yang menggambarkan
aktivitas belajar pengguna.
Preprocessing
Sebelum dilakukannya analisis, variabel UNS harus dipisahkan terlebih
dahulu karena clustering termasuk metode unsupervised. Selanjutnya data
dinormalisasikan agar setiap variabel memiliki skala yang sebanding
sehingga tidak ada variabel yang mendominasi perhitungan.
user_clust <- user[, -which(names(user) == "UNS")]
target <- user$UNS
str(user_clust)
## tibble [258 × 5] (S3: tbl_df/tbl/data.frame)
## $ STG: num [1:258] 0 0.08 0.06 0.1 0.08 0.09 0.1 0.15 0.2 0 ...
## $ SCG: num [1:258] 0 0.08 0.06 0.1 0.08 0.15 0.1 0.02 0.14 0 ...
## $ STR: num [1:258] 0 0.1 0.05 0.15 0.08 0.4 0.43 0.34 0.35 0.5 ...
## $ LPR: num [1:258] 0 0.24 0.25 0.65 0.98 0.1 0.29 0.4 0.72 0.2 ...
## $ PEG: num [1:258] 0 0.9 0.33 0.3 0.24 0.66 0.56 0.01 0.25 0.85 ...
user_scaled <- scale(user_clust)
Analisis Clustering
Model 1 - Euclidean Distance
Perhitungan jarak dilakukan untuk mengetahui tingkat kemiripan antar
data. Nilai jarak yang kecil menunjukkan bahwa dua data memiliki
karakteristik yang mirip, sedangkan nilai yang besar menunjukkan
perbedaan yang lebih jauh.
dist_matrix <- dist(user_scaled, method = "euclidean")
dist_mat <- as.matrix(dist_matrix)
dist_mat[1:5, 1:5]
## 1 2 3 4 5
## 1 0.000000 3.718118 1.700049 3.010984 4.108407
## 2 3.718118 0.000000 2.247041 2.883963 3.948448
## 3 1.700049 2.247041 0.000000 1.688235 2.968859
## 4 3.010984 2.883963 1.688235 0.000000 1.386833
## 5 4.108407 3.948448 2.968859 1.386833 0.000000
Model 2 - K-means Clustering
Untuk menentukan jumlah k optimal menggunakan metode Elbow.
wss <- numeric(10)
for (k in 1:10) {
kmeans_model <- kmeans(user_scaled, centers = k, nstart = 25)
wss[k] <- kmeans_model$tot.withinss
}
plot(1:10, wss, type="b",
xlab="Jumlah Cluster",
ylab="WSS",
main="Elbow Method")

Interpretasi:
Dari grafik Elbow terlihat bahwa penurunan WSS cukup besar hingga
cluster ke-3, sehingga jumlah cluster optimal adalah 3.
Selanjutnya dilakukan clustering menggunakan K-means dengan jumlah
cluster sebanyak 3.
set.seed(123)
kmeans_result <- kmeans(user_scaled, centers = 3, nstart = 25)
table(kmeans_result$cluster)
##
## 1 2 3
## 119 81 58
Hasil tersebut menunjukkan bahwa data terbagi menjadi 3 kelompok
dengan jumlah anggota yang berbeda, di mana cluster 1 terdiri dari 119
observasi, cluster 2 sebanyak 81 observasi, dan cluster 3 sebanyak 58
observasi.
library(factoextra)
## Loading required package: ggplot2
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
fviz_cluster(kmeans_result, data = user_scaled)

Interpretasi:
Visual cluster ini menunjukkan bahwa data terpisah menjadi tiga kelompok
yang cukup jelas, meskipun masih terdapat sedikit tumpang tindih antar
cluster. Hal ini menunjukkan bahwa metode K-Means mampu menangkap pola
utama dalam data dengan cukup baik.
Model 3 - Gaussian Mixture Model
library(mclust)
gmm <- Mclust(user_scaled)
summary(gmm)
## ----------------------------------------------------
## Gaussian finite mixture model fitted by EM algorithm
## ----------------------------------------------------
##
## Mclust EEI (diagonal, equal volume and shape) model with 4 components:
##
## log-likelihood n df BIC ICL
## -1700.6 258 28 -3556.683 -3585.376
##
## Clustering table:
## 1 2 3 4
## 54 28 104 72
Hasil dari GMM menunjukkan bahwa model terbaik membentuk 4 cluster.
GMM juga mendapatkan nilai log-likelihood sebesar -1700.6, nilai BIC
sebesar -3556.683, dan nilai ICL sebesar -3585.376. Nilai log-likelihood
menggambarkan seberapa baik model dalam menyesuaikan data, di mana nilai
yang lebih tinggi (atau lebih mendekati nol) menunjukkan model yang
lebih baik. Sementara itu, BIC digunakan untuk memilih model terbaik
dengan mempertimbangkan kompleksitas model, sehingga nilai BIC yang
lebih kecil menunjukkan model yang lebih optimal. Nilai ICL yang
mendekati BIC menunjukkan bahwa hasil clustering cukup konsisten dan
tidak terlalu ambigu.
plot(gmm, what = "classification")

Interpretasi:
Visual GMM ini menunjukkan bahwa pembagian cluster menjadi lebih detail
dan mampu menangkap pola-pola kecil dalam data. Hal ini menunjukkan
bahwa pendekatan berbasis probabilitas dapat memberikan representasi
yang lebih fleksibel terhadap data.
Model 4 - Fuzzy C-Means
library(e1071)
fuzzy <- cmeans(user_scaled, centers = 3, m = 2)
head(fuzzy$membership)
## 1 2 3
## [1,] 0.3738764 0.3125410 0.3135826
## [2,] 0.2815730 0.3577296 0.3606974
## [3,] 0.3785106 0.3098520 0.3116374
## [4,] 0.4830785 0.2581920 0.2587295
## [5,] 0.4595217 0.2702621 0.2702161
## [6,] 0.2498046 0.3729832 0.3772123
Hasil ini menunjukkan bahwa setiap data memiliki derajat keanggotaan
terhadap masing-masing cluster, sehingga tidak hanya masuk ke satu
kelompok saja.
fviz_cluster(list(data = user_scaled, cluster = fuzzy$cluster))

Interpretasi:
Visualisasi Fuzzy memperlihatkan adanya area tumpang tindih antar
cluster yang cukup jelas. Hal ini menunjukkan bahwa dalam data nyata,
karakteristik pengguna tidak selalu dapat dipisahkan secara tegas.
Beberapa pengguna memiliki pola belajar yang berada di antara dua
kelompok, sehingga metode Fuzzy lebih mampu merepresentasikan kondisi
tersebut dibandingkan metode K-Means yang bersifat kaku.
Mencari Model Terbaik
K-Means
table(kmeans_result$cluster, target)
## target
## High Low Middle very_low
## 1 38 15 66 0
## 2 0 49 9 23
## 3 25 19 13 1
Secara pola:
Cluster 2 sudah cukup jelas karena didominasi oleh kategori Low dan
very_low, artinya model berhasil mengelompokkan pengguna dengan
pengetahuan rendah. Namun pada cluster 1 dan 3 masih terlihat campuran
antara High, Middle, dan Low sehingga batas antar kelompok belum terlalu
tegas.
Artinya, K-Means cukup baik, tetapi belum optimal dalam memisahkan
semua tingkat pengetahuan secara jelas.
GMM
gmm_cluster <- gmm$classification
table(gmm_cluster, target)
## target
## gmm_cluster High Low Middle very_low
## 1 0 40 0 14
## 2 26 0 2 0
## 3 37 0 67 0
## 4 0 43 19 10
Secara pola:
Terdapat cluster yang secara spesifik hanya berisi kategori High,
sehingga menunjukkan bahwa model mampu memisahkan pengguna dengan
tingkat pengetahuan tinggi secara tegas. Selain itu, terdapat cluster
yang didominasi oleh Low dan very_low, yang menandakan bahwa pengguna
dengan tingkat pengetahuan rendah juga berhasil dikelompokkan dengan
konsisten. Namun, masih terdapat satu cluster yang berisi campuran
beberapa kategori, sehingga pemisahan belum sepenuhnya sempurna.
Artinya, GMM mampu menangkap struktur data dengan lebih detail dan
memberikan hasil yang lebih mendekati kondisi sebenarnya dibandingkan
metode lainnya.
Fuzzy
table(fuzzy$cluster, target)
## target
## High Low Middle very_low
## 1 7 64 21 23
## 2 21 15 20 1
## 3 35 4 47 0
Secara pola:
Terlihat bahwa setiap cluster cenderung berisi campuran berbagai
kategori seperti High, Middle, Low, dan very_low. Tidak ada cluster yang
benar-benar didominasi oleh satu kategori tertentu, sehingga batas antar
kelompok menjadi kurang jelas. Hal ini menunjukkan bahwa model tidak
mampu memisahkan tingkat pengetahuan secara tegas karena sifatnya yang
memperbolehkan satu data berada di beberapa cluster sekaligus.
Artinya, meskipun Fuzzy lebih fleksibel dalam merepresentasikan data,
namun untuk tujuan pemisahan kategori UNS, hasil yang diperoleh kurang
optimal.
Kesimpulan
Secara keseluruhan, hasil clustering menunjukkan bahwa setiap metode
memiliki kemampuan yang berbeda dalam mengelompokkan data berdasarkan
tingkat pengetahuan pengguna. K-Means mampu memberikan hasil yang cukup
baik dengan struktur cluster yang sederhana, namun masih terdapat
campuran kategori dalam beberapa cluster sehingga pemisahan belum
sepenuhnya jelas. Fuzzy C-Means menunjukkan sifat data yang saling
tumpang tindih, tetapi justru membuat batas antar kategori menjadi
kurang tegas dan sulit diinterpretasikan.
Di sisi lain, Gaussian Mixture Model (GMM) menunjukkan hasil yang
paling mendekati dengan nilai UNS. Hal ini terlihat dari adanya cluster
yang mampu merepresentasikan kategori tertentu secara lebih jelas,
seperti pemisahan kategori High serta pengelompokan Low dan very_low
yang konsisten. Meskipun masih terdapat sedikit campuran pada salah satu
cluster, secara keseluruhan GMM mampu menangkap struktur data dengan
lebih baik dan lebih realistis.
Dengan demikian, dapat disimpulkan bahwa model terbaik yang dipilih
adalah Gaussian Mixture Model (GMM) karena memiliki kemampuan paling
baik dalam merepresentasikan tingkat pengetahuan pengguna serta
menghasilkan pengelompokan yang paling sesuai dengan data aktual.
LS0tDQp0aXRsZTogIkNsdXN0ZXJpbmcgLSBVc2VyIEtub3dsZWRnZSBNb2RlbGluZyINCmF1dGhvcjogIlJhZmx5IFByaXlhbnRhbWEgUmFtYWRoYW4gQmFnYXNrYXJhIg0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgIGRmX3ByaW50OiAicGFnZWQiDQogICAgY29kZV9mb2xkaW5nOiAiaGlkZSINCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCi0tLQ0KDQojIERhdGFzZXQNCg0KRGF0YXNldCB5YW5nIGRpZ3VuYWthbiBhZGFsYWggVXNlciBLbm93bGVkZ2UgTW9kZWxpbmcgZGFyaSBVQ0kgTWFjaGluZSBMZWFybmluZyBSZXBvc2l0b3J5LiBEYXRhc2V0IGluaSBkaWd1bmFrYW4gdW50dWsgbWVuZ2FuYWxpc2lzIHRpbmdrYXQgcGVuZ2V0YWh1YW4gcGVuZ2d1bmEgYmVyZGFzYXJrYW4gYWt0aXZpdGFzIGJlbGFqYXIuDQoNClZhcmlhYmVsIGRhbGFtIGRhdGFzZXQgaW5pIGRhcGF0IGRpamVsYXNrYW4gc2ViYWdhaSBiZXJpa3V0OlwNCjEuICpTVEcgKFN0dWR5IFRpbWUgR29hbCkqID0gV2FrdHUgYmVsYWphclwNCjIuICpTQ0cgKFN0dWR5IENvdW50IEdvYWwpKiA9IEp1bWxhaCBwZW5ndWxhbmdhbiBtYXRlcmlcDQozLiAqU1RSIChTdHVkeSBUaW1lIFJlYWwpKiA9IFdha3R1IGJlbGFqYXIgYWt0dWFsXA0KNC4gKkxQUiAoTGVhcm5pbmcgUHJvY2VzcyBSYXRlKSogPSBUaW5na2F0IHBlbWFoYW1hbiBzZWxhbWEgcHJvc2VzIGJlbGFqYXJcDQo1LiAqUEVHIChQZXJmb3JtYW5jZSBFdmFsdWF0aW9uIEdyYWRlKSogPSBIYXNpbCBldmFsdWFzaSBiZWxhamFyXA0KNi4gKlVOUyAoVXNlciBLbm93bGVkZ2UgTGV2ZWwpKiA9IFRpbmdrYXQgcGVuZ2V0YWh1YW4gcGVuZ2d1bmEgKFRhcmdldCkNCg0KIyBJbXBvcnQgRGF0YQ0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRX0NCmxpYnJhcnkocmVhZHhsKQ0KdXNlciA8LSByZWFkX2V4Y2VsKCJDOi9Vc2Vycy9wcml5YS9Eb3dubG9hZHMvVXNlciBLbm93bGVkZ2UgTW9kZWxpbmcueGxzeCIpDQpoZWFkKHVzZXIpDQpzdHIodXNlcikNCmBgYA0KDQpEYXRhc2V0IHRlcmRpcmkgZGFyaSAyNTggb2JzIGRlbmdhbiA2IHZhciB5YW5nIG1lbmdnYW1iYXJrYW4gYWt0aXZpdGFzIGJlbGFqYXIgcGVuZ2d1bmEuDQoNCiMgUHJlcHJvY2Vzc2luZw0KDQpTZWJlbHVtIGRpbGFrdWthbm55YSBhbmFsaXNpcywgdmFyaWFiZWwgVU5TIGhhcnVzIGRpcGlzYWhrYW4gdGVybGViaWggZGFodWx1IGthcmVuYSBjbHVzdGVyaW5nIHRlcm1hc3VrIG1ldG9kZSB1bnN1cGVydmlzZWQuIFNlbGFuanV0bnlhIGRhdGEgZGlub3JtYWxpc2FzaWthbiBhZ2FyIHNldGlhcCB2YXJpYWJlbCBtZW1pbGlraSBza2FsYSB5YW5nIHNlYmFuZGluZyBzZWhpbmdnYSB0aWRhayBhZGEgdmFyaWFiZWwgeWFuZyBtZW5kb21pbmFzaSBwZXJoaXR1bmdhbi4NCg0KYGBge3J9DQp1c2VyX2NsdXN0IDwtIHVzZXJbLCAtd2hpY2gobmFtZXModXNlcikgPT0gIlVOUyIpXQ0KdGFyZ2V0IDwtIHVzZXIkVU5TDQpzdHIodXNlcl9jbHVzdCkNCnVzZXJfc2NhbGVkIDwtIHNjYWxlKHVzZXJfY2x1c3QpDQpgYGANCg0KIyBBbmFsaXNpcyBDbHVzdGVyaW5nDQoNCiMjIE1vZGVsIDEgLSBFdWNsaWRlYW4gRGlzdGFuY2UNCg0KUGVyaGl0dW5nYW4gamFyYWsgZGlsYWt1a2FuIHVudHVrIG1lbmdldGFodWkgdGluZ2thdCBrZW1pcmlwYW4gYW50YXIgZGF0YS4gTmlsYWkgamFyYWsgeWFuZyBrZWNpbCBtZW51bmp1a2thbiBiYWh3YSBkdWEgZGF0YSBtZW1pbGlraSBrYXJha3RlcmlzdGlrIHlhbmcgbWlyaXAsIHNlZGFuZ2thbiBuaWxhaSB5YW5nIGJlc2FyIG1lbnVuanVra2FuIHBlcmJlZGFhbiB5YW5nIGxlYmloIGphdWguDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQ0KZGlzdF9tYXRyaXggPC0gZGlzdCh1c2VyX3NjYWxlZCwgbWV0aG9kID0gImV1Y2xpZGVhbiIpDQpkaXN0X21hdCA8LSBhcy5tYXRyaXgoZGlzdF9tYXRyaXgpDQpkaXN0X21hdFsxOjUsIDE6NV0NCmBgYA0KDQojIyBNb2RlbCAyIC0gSy1tZWFucyBDbHVzdGVyaW5nDQoNClVudHVrIG1lbmVudHVrYW4ganVtbGFoIGsgb3B0aW1hbCBtZW5nZ3VuYWthbiBtZXRvZGUgRWxib3cuDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQ0Kd3NzIDwtIG51bWVyaWMoMTApDQoNCmZvciAoayBpbiAxOjEwKSB7DQogIGttZWFuc19tb2RlbCA8LSBrbWVhbnModXNlcl9zY2FsZWQsIGNlbnRlcnMgPSBrLCBuc3RhcnQgPSAyNSkNCiAgd3NzW2tdIDwtIGttZWFuc19tb2RlbCR0b3Qud2l0aGluc3MNCn0NCg0KcGxvdCgxOjEwLCB3c3MsIHR5cGU9ImIiLA0KICAgICB4bGFiPSJKdW1sYWggQ2x1c3RlciIsDQogICAgIHlsYWI9IldTUyIsDQogICAgIG1haW49IkVsYm93IE1ldGhvZCIpDQpgYGANCg0KKipJbnRlcnByZXRhc2kqKjpcDQpEYXJpIGdyYWZpayBFbGJvdyB0ZXJsaWhhdCBiYWh3YSBwZW51cnVuYW4gV1NTIGN1a3VwIGJlc2FyIGhpbmdnYSBjbHVzdGVyIGtlLTMsIHNlaGluZ2dhIGp1bWxhaCBjbHVzdGVyIG9wdGltYWwgYWRhbGFoIDMuDQoNClNlbGFuanV0bnlhIGRpbGFrdWthbiBjbHVzdGVyaW5nIG1lbmdndW5ha2FuIEstbWVhbnMgZGVuZ2FuIGp1bWxhaCBjbHVzdGVyIHNlYmFueWFrIDMuDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMTIzKQ0Ka21lYW5zX3Jlc3VsdCA8LSBrbWVhbnModXNlcl9zY2FsZWQsIGNlbnRlcnMgPSAzLCBuc3RhcnQgPSAyNSkNCnRhYmxlKGttZWFuc19yZXN1bHQkY2x1c3RlcikNCmBgYA0KDQpIYXNpbCB0ZXJzZWJ1dCBtZW51bmp1a2thbiBiYWh3YSBkYXRhIHRlcmJhZ2kgbWVuamFkaSAzIGtlbG9tcG9rIGRlbmdhbiBqdW1sYWggYW5nZ290YSB5YW5nIGJlcmJlZGEsIGRpIG1hbmEgY2x1c3RlciAxIHRlcmRpcmkgZGFyaSAxMTkgb2JzZXJ2YXNpLCBjbHVzdGVyIDIgc2ViYW55YWsgODEgb2JzZXJ2YXNpLCBkYW4gY2x1c3RlciAzIHNlYmFueWFrIDU4IG9ic2VydmFzaS4NCg0KYGBge3J9DQpsaWJyYXJ5KGZhY3RvZXh0cmEpDQpmdml6X2NsdXN0ZXIoa21lYW5zX3Jlc3VsdCwgZGF0YSA9IHVzZXJfc2NhbGVkKQ0KYGBgDQoNCioqSW50ZXJwcmV0YXNpKio6XA0KVmlzdWFsIGNsdXN0ZXIgaW5pIG1lbnVuanVra2FuIGJhaHdhIGRhdGEgdGVycGlzYWggbWVuamFkaSB0aWdhIGtlbG9tcG9rIHlhbmcgY3VrdXAgamVsYXMsIG1lc2tpcHVuIG1hc2loIHRlcmRhcGF0IHNlZGlraXQgdHVtcGFuZyB0aW5kaWggYW50YXIgY2x1c3Rlci4gSGFsIGluaSBtZW51bmp1a2thbiBiYWh3YSBtZXRvZGUgSy1NZWFucyBtYW1wdSBtZW5hbmdrYXAgcG9sYSB1dGFtYSBkYWxhbSBkYXRhIGRlbmdhbiBjdWt1cCBiYWlrLg0KDQojIyBNb2RlbCAzIC0gR2F1c3NpYW4gTWl4dHVyZSBNb2RlbA0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRX0NCmxpYnJhcnkobWNsdXN0KQ0KZ21tIDwtIE1jbHVzdCh1c2VyX3NjYWxlZCkNCnN1bW1hcnkoZ21tKQ0KYGBgDQoNCkhhc2lsIGRhcmkgR01NIG1lbnVuanVra2FuIGJhaHdhIG1vZGVsIHRlcmJhaWsgbWVtYmVudHVrIDQgY2x1c3Rlci4gR01NIGp1Z2EgbWVuZGFwYXRrYW4gbmlsYWkgbG9nLWxpa2VsaWhvb2Qgc2ViZXNhciAtMTcwMC42LCBuaWxhaSBCSUMgc2ViZXNhciAtMzU1Ni42ODMsIGRhbiBuaWxhaSBJQ0wgc2ViZXNhciAtMzU4NS4zNzYuIE5pbGFpIGxvZy1saWtlbGlob29kIG1lbmdnYW1iYXJrYW4gc2ViZXJhcGEgYmFpayBtb2RlbCBkYWxhbSBtZW55ZXN1YWlrYW4gZGF0YSwgZGkgbWFuYSBuaWxhaSB5YW5nIGxlYmloIHRpbmdnaSAoYXRhdSBsZWJpaCBtZW5kZWthdGkgbm9sKSBtZW51bmp1a2thbiBtb2RlbCB5YW5nIGxlYmloIGJhaWsuIFNlbWVudGFyYSBpdHUsIEJJQyBkaWd1bmFrYW4gdW50dWsgbWVtaWxpaCBtb2RlbCB0ZXJiYWlrIGRlbmdhbiBtZW1wZXJ0aW1iYW5na2FuIGtvbXBsZWtzaXRhcyBtb2RlbCwgc2VoaW5nZ2EgbmlsYWkgQklDIHlhbmcgbGViaWgga2VjaWwgbWVudW5qdWtrYW4gbW9kZWwgeWFuZyBsZWJpaCBvcHRpbWFsLiBOaWxhaSBJQ0wgeWFuZyBtZW5kZWthdGkgQklDIG1lbnVuanVra2FuIGJhaHdhIGhhc2lsIGNsdXN0ZXJpbmcgY3VrdXAga29uc2lzdGVuIGRhbiB0aWRhayB0ZXJsYWx1IGFtYmlndS4NCg0KYGBge1J9DQpwbG90KGdtbSwgd2hhdCA9ICJjbGFzc2lmaWNhdGlvbiIpDQpgYGANCg0KKipJbnRlcnByZXRhc2kqKjpcDQpWaXN1YWwgR01NIGluaSBtZW51bmp1a2thbiBiYWh3YSBwZW1iYWdpYW4gY2x1c3RlciBtZW5qYWRpIGxlYmloIGRldGFpbCBkYW4gbWFtcHUgbWVuYW5na2FwIHBvbGEtcG9sYSBrZWNpbCBkYWxhbSBkYXRhLiBIYWwgaW5pIG1lbnVuanVra2FuIGJhaHdhIHBlbmRla2F0YW4gYmVyYmFzaXMgcHJvYmFiaWxpdGFzIGRhcGF0IG1lbWJlcmlrYW4gcmVwcmVzZW50YXNpIHlhbmcgbGViaWggZmxla3NpYmVsIHRlcmhhZGFwIGRhdGEuDQoNCiMjIE1vZGVsIDQgLSBGdXp6eSBDLU1lYW5zDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQ0KbGlicmFyeShlMTA3MSkNCmZ1enp5IDwtIGNtZWFucyh1c2VyX3NjYWxlZCwgY2VudGVycyA9IDMsIG0gPSAyKQ0KaGVhZChmdXp6eSRtZW1iZXJzaGlwKQ0KYGBgDQoNCkhhc2lsIGluaSBtZW51bmp1a2thbiBiYWh3YSBzZXRpYXAgZGF0YSBtZW1pbGlraSBkZXJhamF0IGtlYW5nZ290YWFuIHRlcmhhZGFwIG1hc2luZy1tYXNpbmcgY2x1c3Rlciwgc2VoaW5nZ2EgdGlkYWsgaGFueWEgbWFzdWsga2Ugc2F0dSBrZWxvbXBvayBzYWphLg0KDQpgYGB7cn0NCmZ2aXpfY2x1c3RlcihsaXN0KGRhdGEgPSB1c2VyX3NjYWxlZCwgY2x1c3RlciA9IGZ1enp5JGNsdXN0ZXIpKQ0KYGBgDQoNCioqSW50ZXJwcmV0YXNpKio6XA0KVmlzdWFsaXNhc2kgRnV6enkgbWVtcGVybGloYXRrYW4gYWRhbnlhIGFyZWEgdHVtcGFuZyB0aW5kaWggYW50YXIgY2x1c3RlciB5YW5nIGN1a3VwIGplbGFzLiBIYWwgaW5pIG1lbnVuanVra2FuIGJhaHdhIGRhbGFtIGRhdGEgbnlhdGEsIGthcmFrdGVyaXN0aWsgcGVuZ2d1bmEgdGlkYWsgc2VsYWx1IGRhcGF0IGRpcGlzYWhrYW4gc2VjYXJhIHRlZ2FzLiBCZWJlcmFwYSBwZW5nZ3VuYSBtZW1pbGlraSBwb2xhIGJlbGFqYXIgeWFuZyBiZXJhZGEgZGkgYW50YXJhIGR1YSBrZWxvbXBvaywgc2VoaW5nZ2EgbWV0b2RlIEZ1enp5IGxlYmloIG1hbXB1IG1lcmVwcmVzZW50YXNpa2FuIGtvbmRpc2kgdGVyc2VidXQgZGliYW5kaW5na2FuIG1ldG9kZSBLLU1lYW5zIHlhbmcgYmVyc2lmYXQga2FrdS4NCg0KIyBNZW5jYXJpIE1vZGVsIFRlcmJhaWsNCg0KIyMgSy1NZWFucw0KDQpgYGB7cn0NCnRhYmxlKGttZWFuc19yZXN1bHQkY2x1c3RlciwgdGFyZ2V0KQ0KYGBgDQoNClNlY2FyYSBwb2xhOlwNCkNsdXN0ZXIgMiBzdWRhaCBjdWt1cCBqZWxhcyBrYXJlbmEgZGlkb21pbmFzaSBvbGVoIGthdGVnb3JpIExvdyBkYW4gdmVyeV9sb3csIGFydGlueWEgbW9kZWwgYmVyaGFzaWwgbWVuZ2Vsb21wb2trYW4gcGVuZ2d1bmEgZGVuZ2FuIHBlbmdldGFodWFuIHJlbmRhaC4gTmFtdW4gcGFkYSBjbHVzdGVyIDEgZGFuIDMgbWFzaWggdGVybGloYXQgY2FtcHVyYW4gYW50YXJhIEhpZ2gsIE1pZGRsZSwgZGFuIExvdyBzZWhpbmdnYSBiYXRhcyBhbnRhciBrZWxvbXBvayBiZWx1bSB0ZXJsYWx1IHRlZ2FzLg0KDQpBcnRpbnlhLCBLLU1lYW5zIGN1a3VwIGJhaWssIHRldGFwaSBiZWx1bSBvcHRpbWFsIGRhbGFtIG1lbWlzYWhrYW4gc2VtdWEgdGluZ2thdCBwZW5nZXRhaHVhbiBzZWNhcmEgamVsYXMuDQoNCiMjIEdNTQ0KDQpgYGB7cn0NCmdtbV9jbHVzdGVyIDwtIGdtbSRjbGFzc2lmaWNhdGlvbg0KdGFibGUoZ21tX2NsdXN0ZXIsIHRhcmdldCkNCmBgYA0KDQpTZWNhcmEgcG9sYTpcDQpUZXJkYXBhdCBjbHVzdGVyIHlhbmcgc2VjYXJhIHNwZXNpZmlrIGhhbnlhIGJlcmlzaSBrYXRlZ29yaSBIaWdoLCBzZWhpbmdnYSBtZW51bmp1a2thbiBiYWh3YSBtb2RlbCBtYW1wdSBtZW1pc2Foa2FuIHBlbmdndW5hIGRlbmdhbiB0aW5na2F0IHBlbmdldGFodWFuIHRpbmdnaSBzZWNhcmEgdGVnYXMuIFNlbGFpbiBpdHUsIHRlcmRhcGF0IGNsdXN0ZXIgeWFuZyBkaWRvbWluYXNpIG9sZWggTG93IGRhbiB2ZXJ5X2xvdywgeWFuZyBtZW5hbmRha2FuIGJhaHdhIHBlbmdndW5hIGRlbmdhbiB0aW5na2F0IHBlbmdldGFodWFuIHJlbmRhaCBqdWdhIGJlcmhhc2lsIGRpa2Vsb21wb2trYW4gZGVuZ2FuIGtvbnNpc3Rlbi4gTmFtdW4sIG1hc2loIHRlcmRhcGF0IHNhdHUgY2x1c3RlciB5YW5nIGJlcmlzaSBjYW1wdXJhbiBiZWJlcmFwYSBrYXRlZ29yaSwgc2VoaW5nZ2EgcGVtaXNhaGFuIGJlbHVtIHNlcGVudWhueWEgc2VtcHVybmEuDQoNCkFydGlueWEsIEdNTSBtYW1wdSBtZW5hbmdrYXAgc3RydWt0dXIgZGF0YSBkZW5nYW4gbGViaWggZGV0YWlsIGRhbiBtZW1iZXJpa2FuIGhhc2lsIHlhbmcgbGViaWggbWVuZGVrYXRpIGtvbmRpc2kgc2ViZW5hcm55YSBkaWJhbmRpbmdrYW4gbWV0b2RlIGxhaW5ueWEuDQoNCiMjIEZ1enp5DQoNCmBgYHtyfQ0KdGFibGUoZnV6enkkY2x1c3RlciwgdGFyZ2V0KQ0KYGBgDQoNClNlY2FyYSBwb2xhOlwNClRlcmxpaGF0IGJhaHdhIHNldGlhcCBjbHVzdGVyIGNlbmRlcnVuZyBiZXJpc2kgY2FtcHVyYW4gYmVyYmFnYWkga2F0ZWdvcmkgc2VwZXJ0aSBIaWdoLCBNaWRkbGUsIExvdywgZGFuIHZlcnlfbG93LiBUaWRhayBhZGEgY2x1c3RlciB5YW5nIGJlbmFyLWJlbmFyIGRpZG9taW5hc2kgb2xlaCBzYXR1IGthdGVnb3JpIHRlcnRlbnR1LCBzZWhpbmdnYSBiYXRhcyBhbnRhciBrZWxvbXBvayBtZW5qYWRpIGt1cmFuZyBqZWxhcy4gSGFsIGluaSBtZW51bmp1a2thbiBiYWh3YSBtb2RlbCB0aWRhayBtYW1wdSBtZW1pc2Foa2FuIHRpbmdrYXQgcGVuZ2V0YWh1YW4gc2VjYXJhIHRlZ2FzIGthcmVuYSBzaWZhdG55YSB5YW5nIG1lbXBlcmJvbGVoa2FuIHNhdHUgZGF0YSBiZXJhZGEgZGkgYmViZXJhcGEgY2x1c3RlciBzZWthbGlndXMuDQoNCkFydGlueWEsIG1lc2tpcHVuIEZ1enp5IGxlYmloIGZsZWtzaWJlbCBkYWxhbSBtZXJlcHJlc2VudGFzaWthbiBkYXRhLCBuYW11biB1bnR1ayB0dWp1YW4gcGVtaXNhaGFuIGthdGVnb3JpIFVOUywgaGFzaWwgeWFuZyBkaXBlcm9sZWgga3VyYW5nIG9wdGltYWwuDQoNCiMgS2VzaW1wdWxhbg0KDQpTZWNhcmEga2VzZWx1cnVoYW4sIGhhc2lsIGNsdXN0ZXJpbmcgbWVudW5qdWtrYW4gYmFod2Egc2V0aWFwIG1ldG9kZSBtZW1pbGlraSBrZW1hbXB1YW4geWFuZyBiZXJiZWRhIGRhbGFtIG1lbmdlbG9tcG9ra2FuIGRhdGEgYmVyZGFzYXJrYW4gdGluZ2thdCBwZW5nZXRhaHVhbiBwZW5nZ3VuYS4gSy1NZWFucyBtYW1wdSBtZW1iZXJpa2FuIGhhc2lsIHlhbmcgY3VrdXAgYmFpayBkZW5nYW4gc3RydWt0dXIgY2x1c3RlciB5YW5nIHNlZGVyaGFuYSwgbmFtdW4gbWFzaWggdGVyZGFwYXQgY2FtcHVyYW4ga2F0ZWdvcmkgZGFsYW0gYmViZXJhcGEgY2x1c3RlciBzZWhpbmdnYSBwZW1pc2FoYW4gYmVsdW0gc2VwZW51aG55YSBqZWxhcy4gRnV6enkgQy1NZWFucyBtZW51bmp1a2thbiBzaWZhdCBkYXRhIHlhbmcgc2FsaW5nIHR1bXBhbmcgdGluZGloLCB0ZXRhcGkganVzdHJ1IG1lbWJ1YXQgYmF0YXMgYW50YXIga2F0ZWdvcmkgbWVuamFkaSBrdXJhbmcgdGVnYXMgZGFuIHN1bGl0IGRpaW50ZXJwcmV0YXNpa2FuLg0KDQpEaSBzaXNpIGxhaW4sIEdhdXNzaWFuIE1peHR1cmUgTW9kZWwgKEdNTSkgbWVudW5qdWtrYW4gaGFzaWwgeWFuZyBwYWxpbmcgbWVuZGVrYXRpIGRlbmdhbiBuaWxhaSBVTlMuIEhhbCBpbmkgdGVybGloYXQgZGFyaSBhZGFueWEgY2x1c3RlciB5YW5nIG1hbXB1IG1lcmVwcmVzZW50YXNpa2FuIGthdGVnb3JpIHRlcnRlbnR1IHNlY2FyYSBsZWJpaCBqZWxhcywgc2VwZXJ0aSBwZW1pc2FoYW4ga2F0ZWdvcmkgSGlnaCBzZXJ0YSBwZW5nZWxvbXBva2FuIExvdyBkYW4gdmVyeV9sb3cgeWFuZyBrb25zaXN0ZW4uIE1lc2tpcHVuIG1hc2loIHRlcmRhcGF0IHNlZGlraXQgY2FtcHVyYW4gcGFkYSBzYWxhaCBzYXR1IGNsdXN0ZXIsIHNlY2FyYSBrZXNlbHVydWhhbiBHTU0gbWFtcHUgbWVuYW5na2FwIHN0cnVrdHVyIGRhdGEgZGVuZ2FuIGxlYmloIGJhaWsgZGFuIGxlYmloIHJlYWxpc3Rpcy4NCg0KRGVuZ2FuIGRlbWlraWFuLCBkYXBhdCBkaXNpbXB1bGthbiBiYWh3YSBtb2RlbCB0ZXJiYWlrIHlhbmcgZGlwaWxpaCBhZGFsYWggR2F1c3NpYW4gTWl4dHVyZSBNb2RlbCAoR01NKSBrYXJlbmEgbWVtaWxpa2kga2VtYW1wdWFuIHBhbGluZyBiYWlrIGRhbGFtIG1lcmVwcmVzZW50YXNpa2FuIHRpbmdrYXQgcGVuZ2V0YWh1YW4gcGVuZ2d1bmEgc2VydGEgbWVuZ2hhc2lsa2FuIHBlbmdlbG9tcG9rYW4geWFuZyBwYWxpbmcgc2VzdWFpIGRlbmdhbiBkYXRhIGFrdHVhbC4=