Sumber dan Deskripsi Data

Dataset yang digunakan dalam penelitian ini adalah User Knowledge Modeling Dataset yang diperoleh dari UCI Machine Learning Repository.

Sumber: https://archive.ics.uci.edu/dataset/257/user+knowledge+modeling

Dataset ini berisi data yang digunakan untuk menganalisis tingkat pengetahuan pengguna berdasarkan aktivitas belajar. Terdapat beberapa variabel numerik yang menggambarkan performa pengguna dalam proses pembelajaran, serta satu variabel kategorik yaitu UNS (User Knowledge Level) yang menunjukkan tingkat pengetahuan pengguna.

Load 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" ...

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

Eksplorasi Data Awal

Statistik Deskriptif

library(psych)
round(describe(user),4)
summary(user)
##       STG              SCG              STR              LPR        
##  Min.   :0.0000   Min.   :0.0000   Min.   :0.0000   Min.   :0.0000  
##  1st Qu.:0.2407   1st Qu.:0.2100   1st Qu.:0.2913   1st Qu.:0.2500  
##  Median :0.3270   Median :0.3025   Median :0.4900   Median :0.3300  
##  Mean   :0.3711   Mean   :0.3557   Mean   :0.4680   Mean   :0.4327  
##  3rd Qu.:0.4950   3rd Qu.:0.4975   3rd Qu.:0.6900   3rd Qu.:0.6475  
##  Max.   :0.9900   Max.   :0.9000   Max.   :0.9500   Max.   :0.9900  
##       PEG             UNS           
##  Min.   :0.0000   Length:258        
##  1st Qu.:0.2500   Class :character  
##  Median :0.5000   Mode  :character  
##  Mean   :0.4585                     
##  3rd Qu.:0.6600                     
##  Max.   :0.9300

Interpretasi:
Nilai seluruh variabel numerik berada pada rentang 0–1 yang menunjukkan bahwa data telah dinormalisasi. Mean dan median yang relatif berdekatan menunjukkan distribusi cukup seimbang. Namun, beberapa variabel seperti STG, SCG, dan LPR sedikit miring ke kanan, sedangkan PEG cenderung miring ke kiri. Variabel STR relatif simetris. Variabel UNS merupakan variabel kategorik dengan total 258 observasi.

Visualisasi Data

Histogram

hist(user$PEG,
     main="Distribution of PEG",
     xlab="PEG",
     col="lightblue",
     probability = TRUE)
lines(density(user$PEG), col = "red", lwd = 2)
legend("topright", legend=c("Density"), col="red", lwd=1)

Interpretasi:
Distribusi PEG tidak simetris dan memiliki beberapa puncak, menunjukkan adanya indikasi data terbagi ke dalam beberapa kelompok.

Scatter

plot(user$STG, user$PEG,
     main="STG vs PEG",
     xlab="STG",
     ylab="PEG",
     col= "blue", pch=19)
legend("bottomright", legend="Data", col="blue", pch=19)

Interpretasi:
Tidak terdapat hubungan yang kuat antara STG dan PEG karena pola sebaran data acak.

Line Plot

library(reshape2)
library(ggplot2)

avg_data <- aggregate(user[,c("STG","SCG","STR","LPR","PEG")],
                      by=list(user$UNS), mean)

data_melt <- melt(avg_data, id.vars="Group.1")

ggplot(data_melt, aes(x=variable, y=value, color=Group.1, group=Group.1)) +
  geom_line(size=1) +
  geom_point(size=2) +
  labs(title="Average Variable Values Across UNS Levels",
       x="Variables",
       y="Average Value",
       color="UNS") +
  theme_minimal()
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

Interpretasi:
Grafik menunjukkan perbedaan pola antar kategori UNS pada setiap variabel. Kategori dengan tingkat pengetahuan lebih tinggi cenderung memiliki nilai PEG dan variabel belajar yang lebih tinggi dibandingkan kategori lainnya.

Barplot

barplot(table(user$UNS),
        main="Distribution of User Knowledge Levels",
        xlab="Knowledge Level Category",
        ylab="Frequency",
        col=c("purple","blue","orange","red"))

legend("topright",
       legend=names(table(user$UNS)),
       fill=c("purple","blue","orange","red"))

Interpretasi:
Distribusi tidak merata, didominasi oleh kategori Middle dan Low.

Violin Plot

ggplot(user, aes(x=UNS, y=PEG, fill=UNS)) +
  geom_violin(trim=FALSE) +
  labs(title="Distribution of PEG Across UNS Categories",
       x="User Knowledge Level (UNS)",
       y="Performance Evaluation Grade (PEG)") +
  theme_minimal()

Interpretasi:
Terlihat bahwa kategori dengan tingkat pengetahuan yang lebih tinggi cenderung memiliki distribusi PEG yang lebih besar pada nilai tinggi. Selain itu, bentuk distribusi yang berbeda antar kategori menunjukkan adanya perbedaan karakteristik performa pada masing-masing kelompok pengguna.

Analisis Regresi

Standarisasi Data

user_std <- as.data.frame(scale(user[,c("STG","SCG","STR","LPR","PEG")]))
user_std$UNS <- user$UNS

Model Regresi

model_reg <- lm(PEG ~ STG + SCG + STR + LPR, data=user_std)
summary(model_reg)
## 
## Call:
## lm(formula = PEG ~ STG + SCG + STR + LPR, data = user_std)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1.97772 -0.78020 -0.05747  0.69512  2.19222 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  2.388e-16  5.694e-02   0.000 1.000000    
## STG          2.180e-01  5.751e-02   3.791 0.000188 ***
## SCG          1.868e-01  5.765e-02   3.240 0.001356 ** 
## STR          1.077e-01  5.730e-02   1.879 0.061385 .  
## LPR         -3.135e-01  5.759e-02  -5.444 1.23e-07 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.9145 on 253 degrees of freedom
## Multiple R-squared:  0.1766, Adjusted R-squared:  0.1636 
## F-statistic: 13.57 on 4 and 253 DF,  p-value: 4.899e-10

Hasil estimasi model regresi linier berganda menunjukkan bahwa variabel STG, SCG, dan STR memiliki pengaruh positif terhadap PEG, sedangkan LPR memiliki pengaruh negatif.

  • STG (0.218)
    Setiap peningkatan 1 standar deviasi pada waktu belajar akan meningkatkan PEG sebesar 0.218 standar deviasi. Variabel ini berpengaruh signifikan terhadap PEG.
  • SCG (0.187)
    Setiap peningkatan 1 standar deviasi pada frekuensi pengulangan materi akan meningkatkan PEG sebesar 0.187 standar deviasi dan berpengaruh signifikan.
  • STR (0.108)
    Memiliki pengaruh positif, namun relatif kecil dan tidak signifikan pada taraf 5%, sehingga kontribusinya terhadap model tidak terlalu kuat.
  • LPR (-0.314)
    Setiap peningkatan 1 standar deviasi pada tingkat pemahaman justru menurunkan PEG sebesar 0.314 standar deviasi. Variabel ini berpengaruh signifikan. Hubungan negatif ini mengindikasikan kemungkinan adanya ketidaksesuaian antara proses belajar dan hasil evaluasi.

Dari segi kekuatan model, nilai R-squared sebesar 0.1766 menunjukkan bahwa model hanya mampu menjelaskan 17.66% variasi PEG, sehingga masih terdapat banyak faktor lain di luar model yang mempengaruhi performa pengguna. Meskipun demikian, hasil uji F menunjukkan bahwa model secara keseluruhan signifikan.

Visualisasi

Scatter Plot + Garis Regresi

plot(user$STG, user$PEG,
     main="Relationship between STG and PEG",
     xlab="STG",
     ylab="PEG",
     pch=19, col="blue")
abline(lm(PEG ~ STG, data=user), col="red", lwd=2)
legend("bottomright",
       legend=c("Data","Regression Line"),
       col=c("blue","red"),
       pch=c(19, NA),
       lwd=c(NA,1))

Interpretasi:
Garis regresi menunjukkan hubungan positif antara variabel STG dan PEG. Hal ini berarti bahwa peningkatan waktu belajar cenderung diikuti oleh peningkatan performa pengguna. Namun, kemiringan garis yang relatif landai menunjukkan bahwa pengaruh STG terhadap PEG tidak terlalu kuat, sehingga terdapat faktor lain yang juga mempengaruhi nilai PEG.

Plot Residual

plot(model_reg$fitted.values, model_reg$residuals,
     main="Residual Plot",
     xlab="Predicted Values",
     ylab="Residuals",
     pch=19, col="darkgreen")
abline(h=0, col="red")
legend("bottomleft",
       legend=c("Residuals","Zero Line"),
       col=c("darkgreen","red"),
       pch=c(19, NA),
       lwd=c(NA,1))

Interpretasi:
Pola residual menunjukkan bahwa titik-titik menyebar secara acak di sekitar garis nol tanpa membentuk pola tertentu, sehingga tidak terdapat indikasi pelanggaran asumsi model. Penyebaran yang relatif merata ini juga menunjukkan bahwa asumsi homoskedastisitas dan linearitas masih terpenuhi.

Heatmap Korelasi

library(corrplot)
corrplot(cor(user[,c("STG","SCG","STR","LPR","PEG")]),
         method="color",
         addCoef.col="black",
         title="Correlation Heatmap of Variables",
         mar=c(0,0,2,0))

Interpretasi:
Korelasi antar variabel relatif lemah. Hubungan negatif antara LPR dan PEG konsisten dengan hasil regresi.

Analisis Klasifikasi

Model Decision Tree

library(caret)
library(rpart) 
library(rpart.plot) 

# Ubah ke Factor 
user$UNS <- as.factor(user$UNS)

# Model
model_tree <- rpart(UNS ~ STG + SCG + STR + LPR, 
                    data=user, 
                    method="class") 

rpart.plot(model_tree)

# Prediksi
pred <- predict(model_tree, type="class")
prob <- predict(model_tree, type = "prob") 

# Confusion Matrix
(cm <- confusionMatrix(pred, user$UNS))
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction High Low Middle very_low
##   High       29   2      3        3
##   Low        14  65     14        9
##   Middle     19  14     68        6
##   very_low    1   2      3        6
## 
## Overall Statistics
##                                           
##                Accuracy : 0.6512          
##                  95% CI : (0.5896, 0.7092)
##     No Information Rate : 0.3411          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.4959          
##                                           
##  Mcnemar's Test P-Value : 0.0001392       
## 
## Statistics by Class:
## 
##                      Class: High Class: Low Class: Middle Class: very_low
## Sensitivity               0.4603     0.7831        0.7727         0.25000
## Specificity               0.9590     0.7886        0.7706         0.97436
## Pos Pred Value            0.7838     0.6373        0.6355         0.50000
## Neg Pred Value            0.8462     0.8846        0.8675         0.92683
## Prevalence                0.2442     0.3217        0.3411         0.09302
## Detection Rate            0.1124     0.2519        0.2636         0.02326
## Detection Prevalence      0.1434     0.3953        0.4147         0.04651
## Balanced Accuracy         0.7096     0.7859        0.7717         0.61218

Berdasarkan hasil Confusion Matrix, diperoleh informasi sebagai berikut:

  • Akurasi (65,12%
    Model mampu mengklasifikasikan sekitar 65% data dengan benar, sehingga performanya tergolong cukup baik.

  • Kappa (0,4959)
    Menunjukkan tingkat kesesuaian model berada pada kategori moderat, yang berarti model memiliki kemampuan klasifikasi yang cukup baik dibandingkan tebakan acak.

  • Precision (Pos Pred Value)
    High (78%) menunjukkan prediksi pada kelas ini paling akurat
    Low (63%) menunjukkan masih terdapat kesalahan dalam prediksi
    Middle (63%) memiliki performa yang mirip dengan kelas Low
    very_low (50%) merupakan yang terendah, sehingga model kurang baik dalam memprediksi kelas ini

  • Sensitivity (Recall)
    Low (78%) dan Middle (77%) menunjukkan model mampu mengenali sebagian besar data pada kelas tersebut
    High (46%) menunjukkan masih banyak data yang tidak terdeteksi dengan baik
    very_low (25%) menunjukkan kemampuan model sangat rendah dalam mengenali kelas ini

  • Distribusi Data (Prevalence)
    Kelas Middle memiliki proporsi terbesar, sedangkan kelas very_low memiliki proporsi paling kecil. Hal ini menunjukkan adanya ketidakseimbangan data.

  • Kinerja Model
    Secara Keseluruhan Secara umum, model memiliki performa yang cukup baik dalam mengklasifikasikan data, terutama pada kelas dengan jumlah data yang besar seperti Low dan Middle. Namun, performa model masih belum merata di semua kelas.

  • Potensi Bias Model
    Model cenderung bias terhadap kelas mayoritas seperti Low dan Middle, dan kurang mampu mengenali kelas minoritas yaitu very_low. Hal ini disebabkan oleh ketidakseimbangan jumlah data (class imbalance), sehingga model lebih sering memprediksi kelas dengan proporsi yang lebih besar.

# Ubah jadi tabel
cm_table <- as.table(cm)

# Visualisasi
ggplot(as.data.frame(cm_table), 
       aes(x = Prediction, y = Reference, fill = Freq)) + 
  geom_tile() + 
  geom_text(aes(label = Freq), 
            color = "black", 
            size = 4) + 
  scale_fill_gradient(low = "white", 
                      high = "blue") + 
  labs(title = "Confusion Matrix", 
       x = "Predicted", 
       y = "Actual") + 
  theme_minimal()

Berdasarkan visualisasi confusion matrix, terlihat bahwa nilai pada diagonal utama menunjukkan jumlah prediksi yang benar. Model mampu mengklasifikasikan sebagian besar data dengan baik, terutama pada kelas Low dan Middle. Namun, masih terdapat kesalahan klasifikasi pada kelas High dan very_low, yang menunjukkan bahwa model kesulitan membedakan beberapa kelas tertentu, terutama kelas dengan jumlah data yang lebih sedikit.

Kurva ROC

library(pROC)

# ROC 
kelas <- colnames(prob)

auc_list <- sapply(kelas, function(k) {
  roc_obj <- roc(user$UNS == k, prob[, k])
  auc(roc_obj)
})
auc_list
##      High       Low    Middle  very_low 
## 0.7999593 0.8206196 0.8189505 0.7835648
# ROC Curve 
par(mfrow = c(2, 2))

for (k in kelas) {
  roc_obj <- roc(user$UNS == k, prob[, k])
  auc_val <- auc(roc_obj)
  
  plot(
    roc_obj,
    main = paste("ROC -", k, "\nAUC =", round(auc_val, 3))
  )
}

Interpretasi:
ROC Curve menggambarkan kemampuan model dalam membedakan masing-masing kelas menggunakan pendekatan One-vs-All. Kurva yang semakin mendekati sudut kiri atas menunjukkan performa model yang semakin baik. Hal ini diperkuat dengan nilai AUC pada setiap kelas yang berada di atas 0,7, yang menandakan bahwa model memiliki kemampuan klasifikasi yang cukup baik.

Analisis Klasterisasi

Scaling

user_scaled <- scale(user[,c("STG","SCG","STR","LPR","PEG")])

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="Number of Clusters (k)",
     ylab="Within-Cluster Sum of Squares (WSS)",
     main="Elbow Method")

Interpretasi:
Dari grafik Elbow terlihat bahwa penurunan WSS mulai melambat pada titik ke-3, sehingga jumlah cluster optimal adalah 3.

Selanjutnya dilakukan clustering menggunakan K-Means dengan jumlah cluster sebanyak 3.

K-Means

library(factoextra)
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
set.seed(123)
km <- kmeans(user_scaled, centers = 3, nstart = 25)

user$cluster <- as.factor(km$cluster)

fviz_cluster(km,
             data = user_scaled,
             geom = "point",
             ellipse.type = "convex",
             show.clust.cent = FALSE,
             labelsize = 0,
             palette = c("#F8766D", "#00BA38", "#619CFF"),
             ggtheme = theme_gray(),
             main = "K-Means Clustering")

aggregate(user[,c("STG","SCG","STR","LPR","PEG")],
          by=list(Cluster=user$cluster),
          mean)

Interpretasi:
Berdasarkan hasil pengelompokan menggunakan K-Means, data pengguna terbagi menjadi tiga kelompok utama:

  • Klaster 1 (High Performance Learners)
    STG = 0.373 (cukup tinggi)
    SCG = 0.377 (cukup tinggi)
    STR = 0.530 (tinggi)
    LPR = 0.253 (rendah)
    PEG = 0.634 (tertinggi di antara semua klaster)
    Klaster ini menunjukkan kelompok pengguna dengan performa terbaik. Mereka memiliki waktu belajar dan aktivitas belajar yang relatif tinggi, serta nilai evaluasi (PEG) yang paling tinggi. Menariknya, nilai LPR cenderung rendah, yang dapat mengindikasikan bahwa meskipun tingkat pemahaman yang dirasakan tidak terlalu tinggi, hasil evaluasi mereka tetap baik.
  • Klaster 2 (Low Engagement Group)
    STG = 0.260 (terendah)
    SCG = 0.280 (terendah)
    STR = 0.310 (rendah)
    LPR = 0.476 (sedang)
    PEG = 0.210 (terendah)
    Klaster ini merupakan kelompok dengan aktivitas belajar paling rendah. Semua indikator waktu dan intensitas belajar berada di level rendah, yang sejalan dengan rendahnya nilai PEG. Hal ini menunjukkan bahwa rendahnya keterlibatan belajar berpengaruh langsung terhadap performa pengguna.
  • Klaster 3 (High Effort – Inconsistent Outcome)
    STG = 0.522 (tertinggi)
    SCG = 0.417 (cukup tinggi)
    STR = 0.562 (tertinggi)
    LPR = 0.740 (tertinggi)
    PEG = 0.444 (menengah)
    Klaster ini menunjukkan pengguna dengan usaha belajar paling tinggi di semua variabel. Namun, meskipun aktivitas belajar tinggi, nilai PEG tidak setinggi Klaster 1. Hal ini menunjukkan adanya kemungkinan inefisiensi dalam proses belajar atau perbedaan kualitas pemahaman terhadap materi.

Insight dari Hasil Segmentasi

Hasil segmentasi menunjukkan bahwa pola belajar memiliki hubungan dengan performa pengguna, namun hubungan tersebut tidak sepenuhnya linear.

Beberapa hal yang bisa disimpulkan:

  • Pengguna dengan tingkat aktivitas belajar yang lebih tinggi cenderung memiliki performa yang lebih baik.
  • Klaster dengan performa rendah dapat menjadi fokus perhatian untuk peningkatan, misalnya melalui strategi pembelajaran tambahan atau pendekatan yang berbeda.
  • Segmentasi ini dapat digunakan sebagai dasar untuk menyusun strategi pembelajaran yang lebih tepat sasaran sesuai karakteristik masing-masing kelompok pengguna.
LS0tDQp0aXRsZTogIkFuYWxpc2lzIFVzZXIgS25vd2xlZGdlIE1vZGVsaW5nIg0KYXV0aG9yOiAiUmFmbHkgUHJpeWFudGFtYSBSYW1hZGhhbiBCYWdhc2thcmEiDQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICBwZGZfZG9jdW1lbnQ6DQogICAgdG9jOiB0cnVlDQogIHdvcmRfZG9jdW1lbnQ6DQogICAgdG9jOiB0cnVlDQotLS0NCg0KIyAqKlN1bWJlciBkYW4gRGVza3JpcHNpIERhdGEqKg0KDQpEYXRhc2V0IHlhbmcgZGlndW5ha2FuIGRhbGFtIHBlbmVsaXRpYW4gaW5pIGFkYWxhaCBVc2VyIEtub3dsZWRnZSBNb2RlbGluZyBEYXRhc2V0IHlhbmcgZGlwZXJvbGVoIGRhcmkgVUNJIE1hY2hpbmUgTGVhcm5pbmcgUmVwb3NpdG9yeS4NCg0KU3VtYmVyOiA8aHR0cHM6Ly9hcmNoaXZlLmljcy51Y2kuZWR1L2RhdGFzZXQvMjU3L3VzZXIra25vd2xlZGdlK21vZGVsaW5nPg0KDQpEYXRhc2V0IGluaSBiZXJpc2kgZGF0YSB5YW5nIGRpZ3VuYWthbiB1bnR1ayBtZW5nYW5hbGlzaXMgdGluZ2thdCBwZW5nZXRhaHVhbiBwZW5nZ3VuYSBiZXJkYXNhcmthbiBha3Rpdml0YXMgYmVsYWphci4gVGVyZGFwYXQgYmViZXJhcGEgdmFyaWFiZWwgbnVtZXJpayB5YW5nIG1lbmdnYW1iYXJrYW4gcGVyZm9ybWEgcGVuZ2d1bmEgZGFsYW0gcHJvc2VzIHBlbWJlbGFqYXJhbiwgc2VydGEgc2F0dSB2YXJpYWJlbCBrYXRlZ29yaWsgeWFpdHUgVU5TIChVc2VyIEtub3dsZWRnZSBMZXZlbCkgeWFuZyBtZW51bmp1a2thbiB0aW5na2F0IHBlbmdldGFodWFuIHBlbmdndW5hLg0KDQojIyAqKkxvYWQgRGF0YSoqDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQ0KbGlicmFyeShyZWFkeGwpDQp1c2VyIDwtIHJlYWRfZXhjZWwoIkM6L1VzZXJzL3ByaXlhL0Rvd25sb2Fkcy9Vc2VyIEtub3dsZWRnZSBNb2RlbGluZy54bHN4IikNCg0KaGVhZCh1c2VyKQ0Kc3RyKHVzZXIpDQpgYGANCg0KVmFyaWFiZWwgZGFsYW0gZGF0YXNldCBpbmkgZGFwYXQgZGlqZWxhc2thbiBzZWJhZ2FpIGJlcmlrdXQ6XA0KMS4gKlNURyAoU3R1ZHkgVGltZSBHb2FsKSogPSBXYWt0dSBiZWxhamFyXA0KMi4gKlNDRyAoU3R1ZHkgQ291bnQgR29hbCkqID0gSnVtbGFoIHBlbmd1bGFuZ2FuIG1hdGVyaVwNCjMuICpTVFIgKFN0dWR5IFRpbWUgUmVhbCkqID0gV2FrdHUgYmVsYWphciBha3R1YWxcDQo0LiAqTFBSIChMZWFybmluZyBQcm9jZXNzIFJhdGUpKiA9IFRpbmdrYXQgcGVtYWhhbWFuIHNlbGFtYSBwcm9zZXMgYmVsYWphclwNCjUuICpQRUcgKFBlcmZvcm1hbmNlIEV2YWx1YXRpb24gR3JhZGUpKiA9IEhhc2lsIGV2YWx1YXNpIGJlbGFqYXJcDQo2LiAqVU5TIChVc2VyIEtub3dsZWRnZSBMZXZlbCkqID0gVGluZ2thdCBwZW5nZXRhaHVhbiBwZW5nZ3VuYQ0KDQojICoqRWtzcGxvcmFzaSBEYXRhIEF3YWwqKg0KDQojIyAqKlN0YXRpc3RpayBEZXNrcmlwdGlmKioNCg0KYGBge3J9DQpsaWJyYXJ5KHBzeWNoKQ0Kcm91bmQoZGVzY3JpYmUodXNlciksNCkNCnN1bW1hcnkodXNlcikNCmBgYA0KDQoqKkludGVycHJldGFzaSoqOlwNCk5pbGFpIHNlbHVydWggdmFyaWFiZWwgbnVtZXJpayBiZXJhZGEgcGFkYSByZW50YW5nIDDigJMxIHlhbmcgbWVudW5qdWtrYW4gYmFod2EgZGF0YSB0ZWxhaCBkaW5vcm1hbGlzYXNpLiBNZWFuIGRhbiBtZWRpYW4geWFuZyByZWxhdGlmIGJlcmRla2F0YW4gbWVudW5qdWtrYW4gZGlzdHJpYnVzaSBjdWt1cCBzZWltYmFuZy4gTmFtdW4sIGJlYmVyYXBhIHZhcmlhYmVsIHNlcGVydGkgU1RHLCBTQ0csIGRhbiBMUFIgc2VkaWtpdCBtaXJpbmcga2Uga2FuYW4sIHNlZGFuZ2thbiBQRUcgY2VuZGVydW5nIG1pcmluZyBrZSBraXJpLiBWYXJpYWJlbCBTVFIgcmVsYXRpZiBzaW1ldHJpcy4gVmFyaWFiZWwgVU5TIG1lcnVwYWthbiB2YXJpYWJlbCBrYXRlZ29yaWsgZGVuZ2FuIHRvdGFsIDI1OCBvYnNlcnZhc2kuDQoNCiMjICoqVmlzdWFsaXNhc2kgRGF0YSoqDQoNCiMjIyAqKkhpc3RvZ3JhbSoqDQoNCmBgYHtyfQ0KaGlzdCh1c2VyJFBFRywNCiAgICAgbWFpbj0iRGlzdHJpYnV0aW9uIG9mIFBFRyIsDQogICAgIHhsYWI9IlBFRyIsDQogICAgIGNvbD0ibGlnaHRibHVlIiwNCiAgICAgcHJvYmFiaWxpdHkgPSBUUlVFKQ0KbGluZXMoZGVuc2l0eSh1c2VyJFBFRyksIGNvbCA9ICJyZWQiLCBsd2QgPSAyKQ0KbGVnZW5kKCJ0b3ByaWdodCIsIGxlZ2VuZD1jKCJEZW5zaXR5IiksIGNvbD0icmVkIiwgbHdkPTEpDQpgYGANCg0KKipJbnRlcnByZXRhc2kqKjpcDQpEaXN0cmlidXNpIFBFRyB0aWRhayBzaW1ldHJpcyBkYW4gbWVtaWxpa2kgYmViZXJhcGEgcHVuY2FrLCBtZW51bmp1a2thbiBhZGFueWEgaW5kaWthc2kgZGF0YSB0ZXJiYWdpIGtlIGRhbGFtIGJlYmVyYXBhIGtlbG9tcG9rLg0KDQojIyMgKipTY2F0dGVyKioNCg0KYGBge3J9DQpwbG90KHVzZXIkU1RHLCB1c2VyJFBFRywNCiAgICAgbWFpbj0iU1RHIHZzIFBFRyIsDQogICAgIHhsYWI9IlNURyIsDQogICAgIHlsYWI9IlBFRyIsDQogICAgIGNvbD0gImJsdWUiLCBwY2g9MTkpDQpsZWdlbmQoImJvdHRvbXJpZ2h0IiwgbGVnZW5kPSJEYXRhIiwgY29sPSJibHVlIiwgcGNoPTE5KQ0KYGBgDQoNCioqSW50ZXJwcmV0YXNpKio6XA0KVGlkYWsgdGVyZGFwYXQgaHVidW5nYW4geWFuZyBrdWF0IGFudGFyYSBTVEcgZGFuIFBFRyBrYXJlbmEgcG9sYSBzZWJhcmFuIGRhdGEgYWNhay4NCg0KIyMjICoqTGluZSBQbG90KioNCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0V9DQpsaWJyYXJ5KHJlc2hhcGUyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQphdmdfZGF0YSA8LSBhZ2dyZWdhdGUodXNlclssYygiU1RHIiwiU0NHIiwiU1RSIiwiTFBSIiwiUEVHIildLA0KICAgICAgICAgICAgICAgICAgICAgIGJ5PWxpc3QodXNlciRVTlMpLCBtZWFuKQ0KDQpkYXRhX21lbHQgPC0gbWVsdChhdmdfZGF0YSwgaWQudmFycz0iR3JvdXAuMSIpDQoNCmdncGxvdChkYXRhX21lbHQsIGFlcyh4PXZhcmlhYmxlLCB5PXZhbHVlLCBjb2xvcj1Hcm91cC4xLCBncm91cD1Hcm91cC4xKSkgKw0KICBnZW9tX2xpbmUoc2l6ZT0xKSArDQogIGdlb21fcG9pbnQoc2l6ZT0yKSArDQogIGxhYnModGl0bGU9IkF2ZXJhZ2UgVmFyaWFibGUgVmFsdWVzIEFjcm9zcyBVTlMgTGV2ZWxzIiwNCiAgICAgICB4PSJWYXJpYWJsZXMiLA0KICAgICAgIHk9IkF2ZXJhZ2UgVmFsdWUiLA0KICAgICAgIGNvbG9yPSJVTlMiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCioqSW50ZXJwcmV0YXNpKio6XA0KR3JhZmlrIG1lbnVuanVra2FuIHBlcmJlZGFhbiBwb2xhIGFudGFyIGthdGVnb3JpIFVOUyBwYWRhIHNldGlhcCB2YXJpYWJlbC4gS2F0ZWdvcmkgZGVuZ2FuIHRpbmdrYXQgcGVuZ2V0YWh1YW4gbGViaWggdGluZ2dpIGNlbmRlcnVuZyBtZW1pbGlraSBuaWxhaSBQRUcgZGFuIHZhcmlhYmVsIGJlbGFqYXIgeWFuZyBsZWJpaCB0aW5nZ2kgZGliYW5kaW5na2FuIGthdGVnb3JpIGxhaW5ueWEuDQoNCiMjIyAqKkJhcnBsb3QqKg0KDQpgYGB7cn0NCmJhcnBsb3QodGFibGUodXNlciRVTlMpLA0KICAgICAgICBtYWluPSJEaXN0cmlidXRpb24gb2YgVXNlciBLbm93bGVkZ2UgTGV2ZWxzIiwNCiAgICAgICAgeGxhYj0iS25vd2xlZGdlIExldmVsIENhdGVnb3J5IiwNCiAgICAgICAgeWxhYj0iRnJlcXVlbmN5IiwNCiAgICAgICAgY29sPWMoInB1cnBsZSIsImJsdWUiLCJvcmFuZ2UiLCJyZWQiKSkNCg0KbGVnZW5kKCJ0b3ByaWdodCIsDQogICAgICAgbGVnZW5kPW5hbWVzKHRhYmxlKHVzZXIkVU5TKSksDQogICAgICAgZmlsbD1jKCJwdXJwbGUiLCJibHVlIiwib3JhbmdlIiwicmVkIikpDQpgYGANCg0KKipJbnRlcnByZXRhc2kqKjpcDQpEaXN0cmlidXNpIHRpZGFrIG1lcmF0YSwgZGlkb21pbmFzaSBvbGVoIGthdGVnb3JpIE1pZGRsZSBkYW4gTG93Lg0KDQojIyMgKipWaW9saW4gUGxvdCoqDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQ0KZ2dwbG90KHVzZXIsIGFlcyh4PVVOUywgeT1QRUcsIGZpbGw9VU5TKSkgKw0KICBnZW9tX3Zpb2xpbih0cmltPUZBTFNFKSArDQogIGxhYnModGl0bGU9IkRpc3RyaWJ1dGlvbiBvZiBQRUcgQWNyb3NzIFVOUyBDYXRlZ29yaWVzIiwNCiAgICAgICB4PSJVc2VyIEtub3dsZWRnZSBMZXZlbCAoVU5TKSIsDQogICAgICAgeT0iUGVyZm9ybWFuY2UgRXZhbHVhdGlvbiBHcmFkZSAoUEVHKSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KKipJbnRlcnByZXRhc2kqKjpcDQpUZXJsaWhhdCBiYWh3YSBrYXRlZ29yaSBkZW5nYW4gdGluZ2thdCBwZW5nZXRhaHVhbiB5YW5nIGxlYmloIHRpbmdnaSBjZW5kZXJ1bmcgbWVtaWxpa2kgZGlzdHJpYnVzaSBQRUcgeWFuZyBsZWJpaCBiZXNhciBwYWRhIG5pbGFpIHRpbmdnaS4gU2VsYWluIGl0dSwgYmVudHVrIGRpc3RyaWJ1c2kgeWFuZyBiZXJiZWRhIGFudGFyIGthdGVnb3JpIG1lbnVuanVra2FuIGFkYW55YSBwZXJiZWRhYW4ga2FyYWt0ZXJpc3RpayBwZXJmb3JtYSBwYWRhIG1hc2luZy1tYXNpbmcga2Vsb21wb2sgcGVuZ2d1bmEuDQoNCiMgKipBbmFsaXNpcyBSZWdyZXNpKioNCg0KIyMgKipTdGFuZGFyaXNhc2kgRGF0YSoqDQoNCmBgYHtyfQ0KdXNlcl9zdGQgPC0gYXMuZGF0YS5mcmFtZShzY2FsZSh1c2VyWyxjKCJTVEciLCJTQ0ciLCJTVFIiLCJMUFIiLCJQRUciKV0pKQ0KdXNlcl9zdGQkVU5TIDwtIHVzZXIkVU5TDQpgYGANCg0KIyMgKipNb2RlbCBSZWdyZXNpKioNCg0KYGBge3J9DQptb2RlbF9yZWcgPC0gbG0oUEVHIH4gU1RHICsgU0NHICsgU1RSICsgTFBSLCBkYXRhPXVzZXJfc3RkKQ0Kc3VtbWFyeShtb2RlbF9yZWcpDQpgYGANCg0KSGFzaWwgZXN0aW1hc2kgbW9kZWwgcmVncmVzaSBsaW5pZXIgYmVyZ2FuZGEgbWVudW5qdWtrYW4gYmFod2EgdmFyaWFiZWwgU1RHLCBTQ0csIGRhbiBTVFIgbWVtaWxpa2kgcGVuZ2FydWggcG9zaXRpZiB0ZXJoYWRhcCBQRUcsIHNlZGFuZ2thbiBMUFIgbWVtaWxpa2kgcGVuZ2FydWggbmVnYXRpZi4NCg0KLSAgIFNURyAoMC4yMTgpXA0KICAgIFNldGlhcCBwZW5pbmdrYXRhbiAxIHN0YW5kYXIgZGV2aWFzaSBwYWRhIHdha3R1IGJlbGFqYXIgYWthbiBtZW5pbmdrYXRrYW4gUEVHIHNlYmVzYXIgMC4yMTggc3RhbmRhciBkZXZpYXNpLiBWYXJpYWJlbCBpbmkgYmVycGVuZ2FydWggc2lnbmlmaWthbiB0ZXJoYWRhcCBQRUcuDQotICAgU0NHICgwLjE4NylcDQogICAgU2V0aWFwIHBlbmluZ2thdGFuIDEgc3RhbmRhciBkZXZpYXNpIHBhZGEgZnJla3VlbnNpIHBlbmd1bGFuZ2FuIG1hdGVyaSBha2FuIG1lbmluZ2thdGthbiBQRUcgc2ViZXNhciAwLjE4NyBzdGFuZGFyIGRldmlhc2kgZGFuIGJlcnBlbmdhcnVoIHNpZ25pZmlrYW4uDQotICAgU1RSICgwLjEwOClcDQogICAgTWVtaWxpa2kgcGVuZ2FydWggcG9zaXRpZiwgbmFtdW4gcmVsYXRpZiBrZWNpbCBkYW4gdGlkYWsgc2lnbmlmaWthbiBwYWRhIHRhcmFmIDUlLCBzZWhpbmdnYSBrb250cmlidXNpbnlhIHRlcmhhZGFwIG1vZGVsIHRpZGFrIHRlcmxhbHUga3VhdC4NCi0gICBMUFIgKC0wLjMxNClcDQogICAgU2V0aWFwIHBlbmluZ2thdGFuIDEgc3RhbmRhciBkZXZpYXNpIHBhZGEgdGluZ2thdCBwZW1haGFtYW4ganVzdHJ1IG1lbnVydW5rYW4gUEVHIHNlYmVzYXIgMC4zMTQgc3RhbmRhciBkZXZpYXNpLiBWYXJpYWJlbCBpbmkgYmVycGVuZ2FydWggc2lnbmlmaWthbi4gSHVidW5nYW4gbmVnYXRpZiBpbmkgbWVuZ2luZGlrYXNpa2FuIGtlbXVuZ2tpbmFuIGFkYW55YSBrZXRpZGFrc2VzdWFpYW4gYW50YXJhIHByb3NlcyBiZWxhamFyIGRhbiBoYXNpbCBldmFsdWFzaS4NCg0KRGFyaSBzZWdpIGtla3VhdGFuIG1vZGVsLCBuaWxhaSBSLXNxdWFyZWQgc2ViZXNhciAwLjE3NjYgbWVudW5qdWtrYW4gYmFod2EgbW9kZWwgaGFueWEgbWFtcHUgbWVuamVsYXNrYW4gMTcuNjYlIHZhcmlhc2kgUEVHLCBzZWhpbmdnYSBtYXNpaCB0ZXJkYXBhdCBiYW55YWsgZmFrdG9yIGxhaW4gZGkgbHVhciBtb2RlbCB5YW5nIG1lbXBlbmdhcnVoaSBwZXJmb3JtYSBwZW5nZ3VuYS4gTWVza2lwdW4gZGVtaWtpYW4sIGhhc2lsIHVqaSBGIG1lbnVuanVra2FuIGJhaHdhIG1vZGVsIHNlY2FyYSBrZXNlbHVydWhhbiBzaWduaWZpa2FuLg0KDQojIyAqKlZpc3VhbGlzYXNpKioNCg0KIyMjICoqU2NhdHRlciBQbG90ICsgR2FyaXMgUmVncmVzaSoqDQoNCmBgYHtyfQ0KcGxvdCh1c2VyJFNURywgdXNlciRQRUcsDQogICAgIG1haW49IlJlbGF0aW9uc2hpcCBiZXR3ZWVuIFNURyBhbmQgUEVHIiwNCiAgICAgeGxhYj0iU1RHIiwNCiAgICAgeWxhYj0iUEVHIiwNCiAgICAgcGNoPTE5LCBjb2w9ImJsdWUiKQ0KYWJsaW5lKGxtKFBFRyB+IFNURywgZGF0YT11c2VyKSwgY29sPSJyZWQiLCBsd2Q9MikNCmxlZ2VuZCgiYm90dG9tcmlnaHQiLA0KICAgICAgIGxlZ2VuZD1jKCJEYXRhIiwiUmVncmVzc2lvbiBMaW5lIiksDQogICAgICAgY29sPWMoImJsdWUiLCJyZWQiKSwNCiAgICAgICBwY2g9YygxOSwgTkEpLA0KICAgICAgIGx3ZD1jKE5BLDEpKQ0KYGBgDQoNCioqSW50ZXJwcmV0YXNpKio6XA0KR2FyaXMgcmVncmVzaSBtZW51bmp1a2thbiBodWJ1bmdhbiBwb3NpdGlmIGFudGFyYSB2YXJpYWJlbCBTVEcgZGFuIFBFRy4gSGFsIGluaSBiZXJhcnRpIGJhaHdhIHBlbmluZ2thdGFuIHdha3R1IGJlbGFqYXIgY2VuZGVydW5nIGRpaWt1dGkgb2xlaCBwZW5pbmdrYXRhbiBwZXJmb3JtYSBwZW5nZ3VuYS4gTmFtdW4sIGtlbWlyaW5nYW4gZ2FyaXMgeWFuZyByZWxhdGlmIGxhbmRhaSBtZW51bmp1a2thbiBiYWh3YSBwZW5nYXJ1aCBTVEcgdGVyaGFkYXAgUEVHIHRpZGFrIHRlcmxhbHUga3VhdCwgc2VoaW5nZ2EgdGVyZGFwYXQgZmFrdG9yIGxhaW4geWFuZyBqdWdhIG1lbXBlbmdhcnVoaSBuaWxhaSBQRUcuDQoNCiMjIyAqKlBsb3QgUmVzaWR1YWwqKg0KDQpgYGB7cn0NCnBsb3QobW9kZWxfcmVnJGZpdHRlZC52YWx1ZXMsIG1vZGVsX3JlZyRyZXNpZHVhbHMsDQogICAgIG1haW49IlJlc2lkdWFsIFBsb3QiLA0KICAgICB4bGFiPSJQcmVkaWN0ZWQgVmFsdWVzIiwNCiAgICAgeWxhYj0iUmVzaWR1YWxzIiwNCiAgICAgcGNoPTE5LCBjb2w9ImRhcmtncmVlbiIpDQphYmxpbmUoaD0wLCBjb2w9InJlZCIpDQpsZWdlbmQoImJvdHRvbWxlZnQiLA0KICAgICAgIGxlZ2VuZD1jKCJSZXNpZHVhbHMiLCJaZXJvIExpbmUiKSwNCiAgICAgICBjb2w9YygiZGFya2dyZWVuIiwicmVkIiksDQogICAgICAgcGNoPWMoMTksIE5BKSwNCiAgICAgICBsd2Q9YyhOQSwxKSkNCmBgYA0KDQoqKkludGVycHJldGFzaSoqOlwNClBvbGEgcmVzaWR1YWwgbWVudW5qdWtrYW4gYmFod2EgdGl0aWstdGl0aWsgbWVueWViYXIgc2VjYXJhIGFjYWsgZGkgc2VraXRhciBnYXJpcyBub2wgdGFucGEgbWVtYmVudHVrIHBvbGEgdGVydGVudHUsIHNlaGluZ2dhIHRpZGFrIHRlcmRhcGF0IGluZGlrYXNpIHBlbGFuZ2dhcmFuIGFzdW1zaSBtb2RlbC4gUGVueWViYXJhbiB5YW5nIHJlbGF0aWYgbWVyYXRhIGluaSBqdWdhIG1lbnVuanVra2FuIGJhaHdhIGFzdW1zaSBob21vc2tlZGFzdGlzaXRhcyBkYW4gbGluZWFyaXRhcyBtYXNpaCB0ZXJwZW51aGkuDQoNCiMjIyAqKkhlYXRtYXAgS29yZWxhc2kqKg0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRX0NCmxpYnJhcnkoY29ycnBsb3QpDQpjb3JycGxvdChjb3IodXNlclssYygiU1RHIiwiU0NHIiwiU1RSIiwiTFBSIiwiUEVHIildKSwNCiAgICAgICAgIG1ldGhvZD0iY29sb3IiLA0KICAgICAgICAgYWRkQ29lZi5jb2w9ImJsYWNrIiwNCiAgICAgICAgIHRpdGxlPSJDb3JyZWxhdGlvbiBIZWF0bWFwIG9mIFZhcmlhYmxlcyIsDQogICAgICAgICBtYXI9YygwLDAsMiwwKSkNCmBgYA0KDQoqKkludGVycHJldGFzaSoqOlwNCktvcmVsYXNpIGFudGFyIHZhcmlhYmVsIHJlbGF0aWYgbGVtYWguIEh1YnVuZ2FuIG5lZ2F0aWYgYW50YXJhIExQUiBkYW4gUEVHIGtvbnNpc3RlbiBkZW5nYW4gaGFzaWwgcmVncmVzaS4NCg0KIyAqKkFuYWxpc2lzIEtsYXNpZmlrYXNpKioNCg0KIyMgKipNb2RlbCBEZWNpc2lvbiBUcmVlKioNCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD04fQ0KbGlicmFyeShjYXJldCkNCmxpYnJhcnkocnBhcnQpIA0KbGlicmFyeShycGFydC5wbG90KSANCg0KIyBVYmFoIGtlIEZhY3RvciANCnVzZXIkVU5TIDwtIGFzLmZhY3Rvcih1c2VyJFVOUykNCg0KIyBNb2RlbA0KbW9kZWxfdHJlZSA8LSBycGFydChVTlMgfiBTVEcgKyBTQ0cgKyBTVFIgKyBMUFIsIA0KICAgICAgICAgICAgICAgICAgICBkYXRhPXVzZXIsIA0KICAgICAgICAgICAgICAgICAgICBtZXRob2Q9ImNsYXNzIikgDQoNCnJwYXJ0LnBsb3QobW9kZWxfdHJlZSkNCg0KIyBQcmVkaWtzaQ0KcHJlZCA8LSBwcmVkaWN0KG1vZGVsX3RyZWUsIHR5cGU9ImNsYXNzIikNCnByb2IgPC0gcHJlZGljdChtb2RlbF90cmVlLCB0eXBlID0gInByb2IiKSANCg0KIyBDb25mdXNpb24gTWF0cml4DQooY20gPC0gY29uZnVzaW9uTWF0cml4KHByZWQsIHVzZXIkVU5TKSkNCmBgYA0KDQpCZXJkYXNhcmthbiBoYXNpbCBDb25mdXNpb24gTWF0cml4LCBkaXBlcm9sZWggaW5mb3JtYXNpIHNlYmFnYWkgYmVyaWt1dDoNCg0KLSAgIEFrdXJhc2kgKDY1LDEyJVwNCiAgICBNb2RlbCBtYW1wdSBtZW5na2xhc2lmaWthc2lrYW4gc2VraXRhciA2NSUgZGF0YSBkZW5nYW4gYmVuYXIsIHNlaGluZ2dhIHBlcmZvcm1hbnlhIHRlcmdvbG9uZyBjdWt1cCBiYWlrLg0KDQotICAgS2FwcGEgKDAsNDk1OSlcDQogICAgTWVudW5qdWtrYW4gdGluZ2thdCBrZXNlc3VhaWFuIG1vZGVsIGJlcmFkYSBwYWRhIGthdGVnb3JpIG1vZGVyYXQsIHlhbmcgYmVyYXJ0aSBtb2RlbCBtZW1pbGlraSBrZW1hbXB1YW4ga2xhc2lmaWthc2kgeWFuZyBjdWt1cCBiYWlrIGRpYmFuZGluZ2thbiB0ZWJha2FuIGFjYWsuDQoNCi0gICBQcmVjaXNpb24gKFBvcyBQcmVkIFZhbHVlKVwNCiAgICBIaWdoICg3OCUpIG1lbnVuanVra2FuIHByZWRpa3NpIHBhZGEga2VsYXMgaW5pIHBhbGluZyBha3VyYXRcDQogICAgTG93ICg2MyUpIG1lbnVuanVra2FuIG1hc2loIHRlcmRhcGF0IGtlc2FsYWhhbiBkYWxhbSBwcmVkaWtzaVwNCiAgICBNaWRkbGUgKDYzJSkgbWVtaWxpa2kgcGVyZm9ybWEgeWFuZyBtaXJpcCBkZW5nYW4ga2VsYXMgTG93XA0KICAgIHZlcnlfbG93ICg1MCUpIG1lcnVwYWthbiB5YW5nIHRlcmVuZGFoLCBzZWhpbmdnYSBtb2RlbCBrdXJhbmcgYmFpayBkYWxhbSBtZW1wcmVkaWtzaSBrZWxhcyBpbmkNCg0KLSAgIFNlbnNpdGl2aXR5IChSZWNhbGwpXA0KICAgIExvdyAoNzglKSBkYW4gTWlkZGxlICg3NyUpIG1lbnVuanVra2FuIG1vZGVsIG1hbXB1IG1lbmdlbmFsaSBzZWJhZ2lhbiBiZXNhciBkYXRhIHBhZGEga2VsYXMgdGVyc2VidXRcDQogICAgSGlnaCAoNDYlKSBtZW51bmp1a2thbiBtYXNpaCBiYW55YWsgZGF0YSB5YW5nIHRpZGFrIHRlcmRldGVrc2kgZGVuZ2FuIGJhaWtcDQogICAgdmVyeV9sb3cgKDI1JSkgbWVudW5qdWtrYW4ga2VtYW1wdWFuIG1vZGVsIHNhbmdhdCByZW5kYWggZGFsYW0gbWVuZ2VuYWxpIGtlbGFzIGluaQ0KDQotICAgRGlzdHJpYnVzaSBEYXRhIChQcmV2YWxlbmNlKVwNCiAgICBLZWxhcyBNaWRkbGUgbWVtaWxpa2kgcHJvcG9yc2kgdGVyYmVzYXIsIHNlZGFuZ2thbiBrZWxhcyB2ZXJ5X2xvdyBtZW1pbGlraSBwcm9wb3JzaSBwYWxpbmcga2VjaWwuIEhhbCBpbmkgbWVudW5qdWtrYW4gYWRhbnlhIGtldGlkYWtzZWltYmFuZ2FuIGRhdGEuDQoNCi0gICBLaW5lcmphIE1vZGVsXA0KICAgIFNlY2FyYSBLZXNlbHVydWhhbiBTZWNhcmEgdW11bSwgbW9kZWwgbWVtaWxpa2kgcGVyZm9ybWEgeWFuZyBjdWt1cCBiYWlrIGRhbGFtIG1lbmdrbGFzaWZpa2FzaWthbiBkYXRhLCB0ZXJ1dGFtYSBwYWRhIGtlbGFzIGRlbmdhbiBqdW1sYWggZGF0YSB5YW5nIGJlc2FyIHNlcGVydGkgTG93IGRhbiBNaWRkbGUuIE5hbXVuLCBwZXJmb3JtYSBtb2RlbCBtYXNpaCBiZWx1bSBtZXJhdGEgZGkgc2VtdWEga2VsYXMuDQoNCi0gICBQb3RlbnNpIEJpYXMgTW9kZWxcDQogICAgTW9kZWwgY2VuZGVydW5nIGJpYXMgdGVyaGFkYXAga2VsYXMgbWF5b3JpdGFzIHNlcGVydGkgTG93IGRhbiBNaWRkbGUsIGRhbiBrdXJhbmcgbWFtcHUgbWVuZ2VuYWxpIGtlbGFzIG1pbm9yaXRhcyB5YWl0dSB2ZXJ5X2xvdy4gSGFsIGluaSBkaXNlYmFia2FuIG9sZWgga2V0aWRha3NlaW1iYW5nYW4ganVtbGFoIGRhdGEgKGNsYXNzIGltYmFsYW5jZSksIHNlaGluZ2dhIG1vZGVsIGxlYmloIHNlcmluZyBtZW1wcmVkaWtzaSBrZWxhcyBkZW5nYW4gcHJvcG9yc2kgeWFuZyBsZWJpaCBiZXNhci4NCg0KYGBge3J9DQojIFViYWggamFkaSB0YWJlbA0KY21fdGFibGUgPC0gYXMudGFibGUoY20pDQoNCiMgVmlzdWFsaXNhc2kNCmdncGxvdChhcy5kYXRhLmZyYW1lKGNtX3RhYmxlKSwgDQogICAgICAgYWVzKHggPSBQcmVkaWN0aW9uLCB5ID0gUmVmZXJlbmNlLCBmaWxsID0gRnJlcSkpICsgDQogIGdlb21fdGlsZSgpICsgDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBGcmVxKSwgDQogICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIA0KICAgICAgICAgICAgc2l6ZSA9IDQpICsgDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gIndoaXRlIiwgDQogICAgICAgICAgICAgICAgICAgICAgaGlnaCA9ICJibHVlIikgKyANCiAgbGFicyh0aXRsZSA9ICJDb25mdXNpb24gTWF0cml4IiwgDQogICAgICAgeCA9ICJQcmVkaWN0ZWQiLCANCiAgICAgICB5ID0gIkFjdHVhbCIpICsgDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCkJlcmRhc2Fya2FuIHZpc3VhbGlzYXNpIGNvbmZ1c2lvbiBtYXRyaXgsIHRlcmxpaGF0IGJhaHdhIG5pbGFpIHBhZGEgZGlhZ29uYWwgdXRhbWEgbWVudW5qdWtrYW4ganVtbGFoIHByZWRpa3NpIHlhbmcgYmVuYXIuIE1vZGVsIG1hbXB1IG1lbmdrbGFzaWZpa2FzaWthbiBzZWJhZ2lhbiBiZXNhciBkYXRhIGRlbmdhbiBiYWlrLCB0ZXJ1dGFtYSBwYWRhIGtlbGFzIExvdyBkYW4gTWlkZGxlLiBOYW11biwgbWFzaWggdGVyZGFwYXQga2VzYWxhaGFuIGtsYXNpZmlrYXNpIHBhZGEga2VsYXMgSGlnaCBkYW4gdmVyeV9sb3csIHlhbmcgbWVudW5qdWtrYW4gYmFod2EgbW9kZWwga2VzdWxpdGFuIG1lbWJlZGFrYW4gYmViZXJhcGEga2VsYXMgdGVydGVudHUsIHRlcnV0YW1hIGtlbGFzIGRlbmdhbiBqdW1sYWggZGF0YSB5YW5nIGxlYmloIHNlZGlraXQuDQoNCiMjICoqS3VydmEgUk9DKioNCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0V9DQpsaWJyYXJ5KHBST0MpDQoNCiMgUk9DIA0Ka2VsYXMgPC0gY29sbmFtZXMocHJvYikNCg0KYXVjX2xpc3QgPC0gc2FwcGx5KGtlbGFzLCBmdW5jdGlvbihrKSB7DQogIHJvY19vYmogPC0gcm9jKHVzZXIkVU5TID09IGssIHByb2JbLCBrXSkNCiAgYXVjKHJvY19vYmopDQp9KQ0KYXVjX2xpc3QNCg0KIyBST0MgQ3VydmUgDQpwYXIobWZyb3cgPSBjKDIsIDIpKQ0KDQpmb3IgKGsgaW4ga2VsYXMpIHsNCiAgcm9jX29iaiA8LSByb2ModXNlciRVTlMgPT0gaywgcHJvYlssIGtdKQ0KICBhdWNfdmFsIDwtIGF1Yyhyb2Nfb2JqKQ0KICANCiAgcGxvdCgNCiAgICByb2Nfb2JqLA0KICAgIG1haW4gPSBwYXN0ZSgiUk9DIC0iLCBrLCAiXG5BVUMgPSIsIHJvdW5kKGF1Y192YWwsIDMpKQ0KICApDQp9DQpgYGANCg0KKipJbnRlcnByZXRhc2kqKjpcDQpST0MgQ3VydmUgbWVuZ2dhbWJhcmthbiBrZW1hbXB1YW4gbW9kZWwgZGFsYW0gbWVtYmVkYWthbiBtYXNpbmctbWFzaW5nIGtlbGFzIG1lbmdndW5ha2FuIHBlbmRla2F0YW4gT25lLXZzLUFsbC4gS3VydmEgeWFuZyBzZW1ha2luIG1lbmRla2F0aSBzdWR1dCBraXJpIGF0YXMgbWVudW5qdWtrYW4gcGVyZm9ybWEgbW9kZWwgeWFuZyBzZW1ha2luIGJhaWsuIEhhbCBpbmkgZGlwZXJrdWF0IGRlbmdhbiBuaWxhaSBBVUMgcGFkYSBzZXRpYXAga2VsYXMgeWFuZyBiZXJhZGEgZGkgYXRhcyAwLDcsIHlhbmcgbWVuYW5kYWthbiBiYWh3YSBtb2RlbCBtZW1pbGlraSBrZW1hbXB1YW4ga2xhc2lmaWthc2kgeWFuZyBjdWt1cCBiYWlrLg0KDQojICoqQW5hbGlzaXMgS2xhc3RlcmlzYXNpKioNCg0KIyMgKipTY2FsaW5nKioNCg0KYGBge3J9DQp1c2VyX3NjYWxlZCA8LSBzY2FsZSh1c2VyWyxjKCJTVEciLCJTQ0ciLCJTVFIiLCJMUFIiLCJQRUciKV0pDQpgYGANCg0KIyMgKipFbGJvdyoqDQoNCmBgYHtyfQ0Kd3NzIDwtIG51bWVyaWMoMTApDQoNCmZvciAoayBpbiAxOjEwKSB7DQogIGttZWFuc19tb2RlbCA8LSBrbWVhbnModXNlcl9zY2FsZWQsIGNlbnRlcnMgPSBrLCBuc3RhcnQgPSAyNSkNCiAgd3NzW2tdIDwtIGttZWFuc19tb2RlbCR0b3Qud2l0aGluc3MNCn0NCg0KcGxvdCgxOjEwLCB3c3MsIHR5cGU9ImIiLA0KICAgICB4bGFiPSJOdW1iZXIgb2YgQ2x1c3RlcnMgKGspIiwNCiAgICAgeWxhYj0iV2l0aGluLUNsdXN0ZXIgU3VtIG9mIFNxdWFyZXMgKFdTUykiLA0KICAgICBtYWluPSJFbGJvdyBNZXRob2QiKQ0KYGBgDQoNCioqSW50ZXJwcmV0YXNpKio6XA0KRGFyaSBncmFmaWsgRWxib3cgdGVybGloYXQgYmFod2EgcGVudXJ1bmFuIFdTUyBtdWxhaSBtZWxhbWJhdCBwYWRhIHRpdGlrIGtlLTMsIHNlaGluZ2dhIGp1bWxhaCBjbHVzdGVyIG9wdGltYWwgYWRhbGFoIDMuDQoNClNlbGFuanV0bnlhIGRpbGFrdWthbiBjbHVzdGVyaW5nIG1lbmdndW5ha2FuIEstTWVhbnMgZGVuZ2FuIGp1bWxhaCBjbHVzdGVyIHNlYmFueWFrIDMuDQoNCiMjICoqSy1NZWFucyoqDQoNCmBgYHtyfQ0KbGlicmFyeShmYWN0b2V4dHJhKQ0Kc2V0LnNlZWQoMTIzKQ0Ka20gPC0ga21lYW5zKHVzZXJfc2NhbGVkLCBjZW50ZXJzID0gMywgbnN0YXJ0ID0gMjUpDQoNCnVzZXIkY2x1c3RlciA8LSBhcy5mYWN0b3Ioa20kY2x1c3RlcikNCg0KZnZpel9jbHVzdGVyKGttLA0KICAgICAgICAgICAgIGRhdGEgPSB1c2VyX3NjYWxlZCwNCiAgICAgICAgICAgICBnZW9tID0gInBvaW50IiwNCiAgICAgICAgICAgICBlbGxpcHNlLnR5cGUgPSAiY29udmV4IiwNCiAgICAgICAgICAgICBzaG93LmNsdXN0LmNlbnQgPSBGQUxTRSwNCiAgICAgICAgICAgICBsYWJlbHNpemUgPSAwLA0KICAgICAgICAgICAgIHBhbGV0dGUgPSBjKCIjRjg3NjZEIiwgIiMwMEJBMzgiLCAiIzYxOUNGRiIpLA0KICAgICAgICAgICAgIGdndGhlbWUgPSB0aGVtZV9ncmF5KCksDQogICAgICAgICAgICAgbWFpbiA9ICJLLU1lYW5zIENsdXN0ZXJpbmciKQ0KDQphZ2dyZWdhdGUodXNlclssYygiU1RHIiwiU0NHIiwiU1RSIiwiTFBSIiwiUEVHIildLA0KICAgICAgICAgIGJ5PWxpc3QoQ2x1c3Rlcj11c2VyJGNsdXN0ZXIpLA0KICAgICAgICAgIG1lYW4pDQpgYGANCg0KKipJbnRlcnByZXRhc2kqKjpcDQpCZXJkYXNhcmthbiBoYXNpbCBwZW5nZWxvbXBva2FuIG1lbmdndW5ha2FuIEstTWVhbnMsIGRhdGEgcGVuZ2d1bmEgdGVyYmFnaSBtZW5qYWRpIHRpZ2Ega2Vsb21wb2sgdXRhbWE6DQoNCi0gICAqKktsYXN0ZXIgMSAoSGlnaCBQZXJmb3JtYW5jZSBMZWFybmVycykqKlwNCiAgICBTVEcgPSAwLjM3MyAoY3VrdXAgdGluZ2dpKVwNCiAgICBTQ0cgPSAwLjM3NyAoY3VrdXAgdGluZ2dpKVwNCiAgICBTVFIgPSAwLjUzMCAodGluZ2dpKVwNCiAgICBMUFIgPSAwLjI1MyAocmVuZGFoKVwNCiAgICBQRUcgPSAwLjYzNCAodGVydGluZ2dpIGRpIGFudGFyYSBzZW11YSBrbGFzdGVyKVwNCiAgICBLbGFzdGVyIGluaSBtZW51bmp1a2thbiBrZWxvbXBvayBwZW5nZ3VuYSBkZW5nYW4gcGVyZm9ybWEgdGVyYmFpay4gTWVyZWthIG1lbWlsaWtpIHdha3R1IGJlbGFqYXIgZGFuIGFrdGl2aXRhcyBiZWxhamFyIHlhbmcgcmVsYXRpZiB0aW5nZ2ksIHNlcnRhIG5pbGFpIGV2YWx1YXNpIChQRUcpIHlhbmcgcGFsaW5nIHRpbmdnaS4gTWVuYXJpa255YSwgbmlsYWkgTFBSIGNlbmRlcnVuZyByZW5kYWgsIHlhbmcgZGFwYXQgbWVuZ2luZGlrYXNpa2FuIGJhaHdhIG1lc2tpcHVuIHRpbmdrYXQgcGVtYWhhbWFuIHlhbmcgZGlyYXNha2FuIHRpZGFrIHRlcmxhbHUgdGluZ2dpLCBoYXNpbCBldmFsdWFzaSBtZXJla2EgdGV0YXAgYmFpay4NCi0gICAqKktsYXN0ZXIgMiAoTG93IEVuZ2FnZW1lbnQgR3JvdXApKipcDQogICAgU1RHID0gMC4yNjAgKHRlcmVuZGFoKVwNCiAgICBTQ0cgPSAwLjI4MCAodGVyZW5kYWgpXA0KICAgIFNUUiA9IDAuMzEwIChyZW5kYWgpXA0KICAgIExQUiA9IDAuNDc2IChzZWRhbmcpXA0KICAgIFBFRyA9IDAuMjEwICh0ZXJlbmRhaClcDQogICAgS2xhc3RlciBpbmkgbWVydXBha2FuIGtlbG9tcG9rIGRlbmdhbiBha3Rpdml0YXMgYmVsYWphciBwYWxpbmcgcmVuZGFoLiBTZW11YSBpbmRpa2F0b3Igd2FrdHUgZGFuIGludGVuc2l0YXMgYmVsYWphciBiZXJhZGEgZGkgbGV2ZWwgcmVuZGFoLCB5YW5nIHNlamFsYW4gZGVuZ2FuIHJlbmRhaG55YSBuaWxhaSBQRUcuIEhhbCBpbmkgbWVudW5qdWtrYW4gYmFod2EgcmVuZGFobnlhIGtldGVybGliYXRhbiBiZWxhamFyIGJlcnBlbmdhcnVoIGxhbmdzdW5nIHRlcmhhZGFwIHBlcmZvcm1hIHBlbmdndW5hLg0KLSAgICoqS2xhc3RlciAzIChIaWdoIEVmZm9ydCDigJMgSW5jb25zaXN0ZW50IE91dGNvbWUpKipcDQogICAgU1RHID0gMC41MjIgKHRlcnRpbmdnaSlcDQogICAgU0NHID0gMC40MTcgKGN1a3VwIHRpbmdnaSlcDQogICAgU1RSID0gMC41NjIgKHRlcnRpbmdnaSlcDQogICAgTFBSID0gMC43NDAgKHRlcnRpbmdnaSlcDQogICAgUEVHID0gMC40NDQgKG1lbmVuZ2FoKVwNCiAgICBLbGFzdGVyIGluaSBtZW51bmp1a2thbiBwZW5nZ3VuYSBkZW5nYW4gdXNhaGEgYmVsYWphciBwYWxpbmcgdGluZ2dpIGRpIHNlbXVhIHZhcmlhYmVsLiBOYW11biwgbWVza2lwdW4gYWt0aXZpdGFzIGJlbGFqYXIgdGluZ2dpLCBuaWxhaSBQRUcgdGlkYWsgc2V0aW5nZ2kgS2xhc3RlciAxLiBIYWwgaW5pIG1lbnVuanVra2FuIGFkYW55YSBrZW11bmdraW5hbiBpbmVmaXNpZW5zaSBkYWxhbSBwcm9zZXMgYmVsYWphciBhdGF1IHBlcmJlZGFhbiBrdWFsaXRhcyBwZW1haGFtYW4gdGVyaGFkYXAgbWF0ZXJpLg0KDQojIyAqKkluc2lnaHQgZGFyaSBIYXNpbCBTZWdtZW50YXNpKioNCg0KSGFzaWwgc2VnbWVudGFzaSBtZW51bmp1a2thbiBiYWh3YSBwb2xhIGJlbGFqYXIgbWVtaWxpa2kgaHVidW5nYW4gZGVuZ2FuIHBlcmZvcm1hIHBlbmdndW5hLCBuYW11biBodWJ1bmdhbiB0ZXJzZWJ1dCB0aWRhayBzZXBlbnVobnlhIGxpbmVhci4NCg0KQmViZXJhcGEgaGFsIHlhbmcgYmlzYSBkaXNpbXB1bGthbjoNCg0KLSAgIFBlbmdndW5hIGRlbmdhbiB0aW5na2F0IGFrdGl2aXRhcyBiZWxhamFyIHlhbmcgbGViaWggdGluZ2dpIGNlbmRlcnVuZyBtZW1pbGlraSBwZXJmb3JtYSB5YW5nIGxlYmloIGJhaWsuDQotICAgS2xhc3RlciBkZW5nYW4gcGVyZm9ybWEgcmVuZGFoIGRhcGF0IG1lbmphZGkgZm9rdXMgcGVyaGF0aWFuIHVudHVrIHBlbmluZ2thdGFuLCBtaXNhbG55YSBtZWxhbHVpIHN0cmF0ZWdpIHBlbWJlbGFqYXJhbiB0YW1iYWhhbiBhdGF1IHBlbmRla2F0YW4geWFuZyBiZXJiZWRhLg0KLSAgIFNlZ21lbnRhc2kgaW5pIGRhcGF0IGRpZ3VuYWthbiBzZWJhZ2FpIGRhc2FyIHVudHVrIG1lbnl1c3VuIHN0cmF0ZWdpIHBlbWJlbGFqYXJhbiB5YW5nIGxlYmloIHRlcGF0IHNhc2FyYW4gc2VzdWFpIGthcmFrdGVyaXN0aWsgbWFzaW5nLW1hc2luZyBrZWxvbXBvayBwZW5nZ3VuYS4NCg==