Analisis Faktor-faktor yang Berpengaruh terhadap Sinta Score ITS

Alfidhia Rahman NJ

2022-09-11

package yang dibutuhkan:

Library

library(tidyverse)
library(kableExtra)
library(ggplot2)
library(ggthemes)
library(stringr)
library(reshape2)
library(mice)
library(nortest)
library(DescTools)
library(caret)
library(rpart)
library(rpart.plot)
library(ROCit)
library(PRROC)
library(ROCR)
library(vip)
library(googlesheets4)

Data

Authors Institut Teknologi Sepuluh Nopember

gs4_deauth()
df_authors_ok <- read_sheet("https://docs.google.com/spreadsheets/d/1bvFb92n4BfNqJQeBF2ULuD96REn_YSEmBSZaZZlWTec/edit?usp=sharing")
## v Reading from "Data Kelompok PSD kelompok 4".
## v Range 'Detail Authors ITS (417)'.
#struktur data sebelum formating
str(df_authors_ok)
## tibble [1,113 x 37] (S3: tbl_df/tbl/data.frame)
##  $ SINTA_ID                     : num [1:1113] 29555 6005015 5976088 29560 5977802 ...
##  $ Departemen_ID                : num [1:1113] 55001 90243 55101 55001 49101 ...
##  $ Nama                         : chr [1:1113] "RIYANARTO SARNO" "MAURIDHI HERY PURNOMO" "CHASTINE FATICHAH" "TOHARI AHMAD" ...
##  $ Universitas                  : chr [1:1113] "Institut Teknologi Sepuluh Nopember" "Institut Teknologi Sepuluh Nopember" "Institut Teknologi Sepuluh Nopember" "Institut Teknologi Sepuluh Nopember" ...
##  $ Departemen                   : chr [1:1113] "Ilmu Komputer" "Teknik Komputer" "Teknik Informatika" "Ilmu Komputer" ...
##  $ Jenjang                      : chr [1:1113] "S3" "S1" "S2" "S3" ...
##  $ Dept_Jenjang                 : chr [1:1113] "Ilmu Komputer - S3" "Teknik Komputer - S1" "Teknik Informatika - S2" "Ilmu Komputer - S3" ...
##  $ SINTA_Score_Overall          : num [1:1113] 9134 8887 4696 4070 3310 ...
##  $ SINTA_Score_3Yr              : num [1:1113] 3068 2544 1881 1624 1496 ...
##  $ Scopus_Artikel               : num [1:1113] 346 444 155 139 101 103 174 128 145 91 ...
##  $ Scopus_Citation              : num [1:1113] 2616 2187 657 903 313 ...
##  $ Scopus_Cited_Document        : num [1:1113] 279 333 107 94 68 85 132 84 122 67 ...
##  $ Scopus_H_Index               : num [1:1113] 26 19 14 15 9 14 17 8 17 10 ...
##  $ Scopus_i10_Index             : num [1:1113] 85 60 22 25 9 19 28 6 39 10 ...
##  $ Scopus_G_Index               : num [1:1113] 1 1 1 1 1 1 1 1 3 1 ...
##  $ GScholar_Artikel             : num [1:1113] 520 712 296 196 168 214 240 211 260 149 ...
##  $ GScholar_Citation            : num [1:1113] 4797 4228 1487 1363 701 ...
##  $ GScholar_Cited_Document      : num [1:1113] 365 487 208 121 104 144 173 122 189 98 ...
##  $ GScholar_H_Index             : num [1:1113] 32 27 20 17 14 20 19 12 23 13 ...
##  $ GScholar_i10_Index           : num [1:1113] 145 126 49 31 25 43 43 17 67 25 ...
##  $ GScholar_G_Index             : num [1:1113] 1 1 1 1 3 1 2 1 4 1 ...
##  $ WOS_Artikel                  : num [1:1113] 107 0 61 72 49 32 0 0 0 46 ...
##  $ WOS_Citation                 : num [1:1113] 570 0 259 363 135 369 0 0 0 174 ...
##  $ WOS_Cited_Document           : num [1:1113] 88 0 46 40 30 31 0 0 0 36 ...
##  $ WOS_H_Index                  : num [1:1113] 13 NA 8 9 7 11 NA NA NA 6 ...
##  $ WOS_i10_Index                : num [1:1113] 17 NA 7 9 3 13 NA NA NA 4 ...
##  $ WOS_G-Index                  : num [1:1113] 1 NA 1 1 4 14 NA NA NA 4 ...
##  $ SINTA_Score_Productivity_Dept: num [1:1113] 9275 1860 4025 9275 3199 ...
##  $ Akreditasi_Dept              : chr [1:1113] "Baik Sekali" "Unggul" "Unggul" "Baik Sekali" ...
##  $ Jumlah_Dosen_Total           : num [1:1113] 6 18 6 6 7 6 8 18 7 7 ...
##  $ Jumlah_Mahasiswa             : num [1:1113] 68 324 115 68 107 35 38 324 107 107 ...
##  $ Rasio_Dosen_per_Mahasiswa    : num [1:1113] 0.25 0.191 0.191 0.25 0.187 ...
##  $ STATUS_i10index_3sources     : chr [1:1113] "EXCELLENT" "EXCELLENT" "EXCELLENT" "GOOD" ...
##  $ STATUS_g-index_Scopus        : chr [1:1113] "NEUTRAL" "NEUTRAL" "NEUTRAL" "NEUTRAL" ...
##  $ STATUS_g-index_gscholar      : chr [1:1113] "NEUTRAL" "NEUTRAL" "NEUTRAL" "NEUTRAL" ...
##  $ STATUS_H-index_Scopus        : chr [1:1113] "SUCCESSFUL" "UNKNOWN" "UNKNOWN" "UNKNOWN" ...
##  $ STATUS_H-index_Gscholar      : chr [1:1113] "SUCCESSFUL" "SUCCESSFUL" "SUCCESSFUL" "UNKNOWN" ...

Data Formatting

df_authors_ok$Jenjang <- as.factor(df_authors_ok$Jenjang)
df_authors_ok$Departemen <- as.factor(df_authors_ok$Departemen)
df_authors_ok$Akreditasi_Dept  <- as.factor(df_authors_ok$Akreditasi_Dept)
df_authors_ok$Dept_Jenjang  <- as.factor(df_authors_ok$Dept_Jenjang)
#struktur data setelah formating
glimpse(df_authors_ok[,c("Jenjang", "Departemen", "Akreditasi_Dept", "Dept_Jenjang")])
## Rows: 1,113
## Columns: 4
## $ Jenjang         <fct> S3, S1, S2, S3, S2, S3, S3, S1, S2, S2, S2, S2, S2, S1~
## $ Departemen      <fct> Ilmu Komputer, Teknik Komputer, Teknik Informatika, Il~
## $ Akreditasi_Dept <fct> Baik Sekali, Unggul, Unggul, Baik Sekali, Unggul, Ungg~
## $ Dept_Jenjang    <fct> Ilmu Komputer - S3, Teknik Komputer - S1, Teknik Infor~

Check Jenjang Factor

levels(df_authors_ok$Jenjang) #Jenjang awal
## [1] "D3" "D4" "S1" "S2" "S3"
levels(df_authors_ok$Akreditasi_Dept)
## [1] "Baik"        "Baik Sekali" "Unggul"

Rumpun Ilmu dari Prodi

#Membentuk rumpun ilmu berdasarkan kode prodi 2 digit
df_rumpun <- df_authors_ok %>% 
  select(Departemen_ID,Departemen)  %>% 
  group_by(Departemen_ID,Departemen) %>%
  summarize() %>% 
  mutate(Departemen_ID_2Digit = substr(Departemen_ID,1,2)) %>%
  na.omit()
## `summarise()` has grouped output by 'Departemen_ID'. You can override using the
## `.groups` argument.
df_rumpun
#Membentuk rumpun ilmu berdasarkan kode prodi 2 digit
df_rumpun <- df_rumpun %>% 
  mutate(Rumpun_Ilmu = case_when(Departemen_ID_2Digit==11 ~ "Kesehatan",
                                 Departemen_ID_2Digit %in% c(20:38, 54:59) ~ "Teknik",
                                 Departemen_ID_2Digit %in% c(44:51,94) ~ "MIPA",
                                 Departemen_ID_2Digit %in% c(61:63,93) ~ "Ekonomi",
                                 Departemen_ID_2Digit %in% c(60) ~ "Sosial Humaniora",
                                 Departemen_ID_2Digit %in% c(41) ~ "Pertanian, Perikanan, dan Ternak",
                                 Departemen_ID_2Digit %in% c(90) ~ "Seni, Desain, Media"
                                 ))
df_rumpun
#dataframe rumpun ilmu yang akan digunakan untuk di merge dengan data awal
df_rumpun_oke <- df_rumpun %>% select(Departemen_ID,Rumpun_Ilmu)

Analisis

#struktur data
glimpse(df_authors_ok)
## Rows: 1,113
## Columns: 37
## $ SINTA_ID                      <dbl> 29555, 6005015, 5976088, 29560, 5977802,~
## $ Departemen_ID                 <dbl> 55001, 90243, 55101, 55001, 49101, 24001~
## $ Nama                          <chr> "RIYANARTO SARNO", "MAURIDHI HERY PURNOM~
## $ Universitas                   <chr> "Institut Teknologi Sepuluh Nopember", "~
## $ Departemen                    <fct> Ilmu Komputer, Teknik Komputer, Teknik I~
## $ Jenjang                       <fct> S3, S1, S2, S3, S2, S3, S3, S1, S2, S2, ~
## $ Dept_Jenjang                  <fct> Ilmu Komputer - S3, Teknik Komputer - S1~
## $ SINTA_Score_Overall           <dbl> 9134, 8887, 4696, 4070, 3310, 4195, 4049~
## $ SINTA_Score_3Yr               <dbl> 3068, 2544, 1881, 1624, 1496, 1316, 1279~
## $ Scopus_Artikel                <dbl> 346, 444, 155, 139, 101, 103, 174, 128, ~
## $ Scopus_Citation               <dbl> 2616, 2187, 657, 903, 313, 728, 935, 347~
## $ Scopus_Cited_Document         <dbl> 279, 333, 107, 94, 68, 85, 132, 84, 122,~
## $ Scopus_H_Index                <dbl> 26, 19, 14, 15, 9, 14, 17, 8, 17, 10, 15~
## $ Scopus_i10_Index              <dbl> 85, 60, 22, 25, 9, 19, 28, 6, 39, 10, 25~
## $ Scopus_G_Index                <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 2, 1, 1, 1~
## $ GScholar_Artikel              <dbl> 520, 712, 296, 196, 168, 214, 240, 211, ~
## $ GScholar_Citation             <dbl> 4797, 4228, 1487, 1363, 701, 1526, 1425,~
## $ GScholar_Cited_Document       <dbl> 365, 487, 208, 121, 104, 144, 173, 122, ~
## $ GScholar_H_Index              <dbl> 32, 27, 20, 17, 14, 20, 19, 12, 23, 13, ~
## $ GScholar_i10_Index            <dbl> 145, 126, 49, 31, 25, 43, 43, 17, 67, 25~
## $ GScholar_G_Index              <dbl> 1, 1, 1, 1, 3, 1, 2, 1, 4, 1, 1, 2, 1, 1~
## $ WOS_Artikel                   <dbl> 107, 0, 61, 72, 49, 32, 0, 0, 0, 46, 91,~
## $ WOS_Citation                  <dbl> 570, 0, 259, 363, 135, 369, 0, 0, 0, 174~
## $ WOS_Cited_Document            <dbl> 88, 0, 46, 40, 30, 31, 0, 0, 0, 36, 70, ~
## $ WOS_H_Index                   <dbl> 13, NA, 8, 9, 7, 11, NA, NA, NA, 6, 14, ~
## $ WOS_i10_Index                 <dbl> 17, NA, 7, 9, 3, 13, NA, NA, NA, 4, 21, ~
## $ `WOS_G-Index`                 <dbl> 1, NA, 1, 1, 4, 14, NA, NA, NA, 4, 2, 1,~
## $ SINTA_Score_Productivity_Dept <dbl> 9275, 1860, 4025, 9275, 3199, 3518, 2002~
## $ Akreditasi_Dept               <fct> Baik Sekali, Unggul, Unggul, Baik Sekali~
## $ Jumlah_Dosen_Total            <dbl> 6, 18, 6, 6, 7, 6, 8, 18, 7, 7, 6, 6, 6,~
## $ Jumlah_Mahasiswa              <dbl> 68, 324, 115, 68, 107, 35, 38, 324, 107,~
## $ Rasio_Dosen_per_Mahasiswa     <dbl> 0.2500000, 0.1912046, 0.1912046, 0.25000~
## $ STATUS_i10index_3sources      <chr> "EXCELLENT", "EXCELLENT", "EXCELLENT", "~
## $ `STATUS_g-index_Scopus`       <chr> "NEUTRAL", "NEUTRAL", "NEUTRAL", "NEUTRA~
## $ `STATUS_g-index_gscholar`     <chr> "NEUTRAL", "NEUTRAL", "NEUTRAL", "NEUTRA~
## $ `STATUS_H-index_Scopus`       <chr> "SUCCESSFUL", "UNKNOWN", "UNKNOWN", "UNK~
## $ `STATUS_H-index_Gscholar`     <chr> "SUCCESSFUL", "SUCCESSFUL", "SUCCESSFUL"~

Data

Unit Observasi = Authors

y = SINTA_Score_3Yr yang dikategorisasi menjadi tinggi dan rendah

x1 = Rumpun Ilmu (Ganjil 2021)

x2 = Jenjang (Ganjil 2021)

x3 = Akreditasi_Dept (Ganjil 2021)

x4 = Total Jumlah Dosen (Ganjil 2021)

x5 = Jumlah Mahasiswa (Ganjil 2021)

x6 = Rasio Dosen per Mahasiswa (Ganjil 2021)

data_1 <- df_authors_ok %>%  
  left_join(df_rumpun_oke, by="Departemen_ID") %>%  
  select(SINTA_Score_3Yr,Departemen,Rumpun_Ilmu,Jenjang,Akreditasi_Dept,Jumlah_Dosen_Total,
         Jumlah_Mahasiswa,Rasio_Dosen_per_Mahasiswa) %>% 
  mutate(y = ifelse(SINTA_Score_3Yr>=256,"1","0")) #kelas 1:SINTA_Score_3Yr yang tinggi
data_1$y <- as.factor(data_1$y)
data_1$Rumpun_Ilmu <- as.factor(data_1$Rumpun_Ilmu)
str(data_1)
## tibble [1,113 x 9] (S3: tbl_df/tbl/data.frame)
##  $ SINTA_Score_3Yr          : num [1:1113] 3068 2544 1881 1624 1496 ...
##  $ Departemen               : Factor w/ 54 levels "Arsitektur","Biologi",..: 10 36 33 10 23 35 8 36 23 23 ...
##  $ Rumpun_Ilmu              : Factor w/ 7 levels "Ekonomi","Kesehatan",..: 7 5 7 7 3 7 3 5 3 3 ...
##  $ Jenjang                  : Factor w/ 5 levels "D3","D4","S1",..: 5 3 4 5 4 5 5 3 4 4 ...
##  $ Akreditasi_Dept          : Factor w/ 3 levels "Baik","Baik Sekali",..: 2 3 3 2 3 3 3 3 3 3 ...
##  $ Jumlah_Dosen_Total       : num [1:1113] 6 18 6 6 7 6 8 18 7 7 ...
##  $ Jumlah_Mahasiswa         : num [1:1113] 68 324 115 68 107 35 38 324 107 107 ...
##  $ Rasio_Dosen_per_Mahasiswa: num [1:1113] 0.25 0.191 0.191 0.25 0.187 ...
##  $ y                        : Factor w/ 2 levels "0","1": 2 2 2 2 2 2 2 2 2 2 ...
#Cek missing values
md.pattern(data_1,rotate.names = TRUE)

##     SINTA_Score_3Yr y Departemen Rumpun_Ilmu Jenjang Jumlah_Dosen_Total
## 981               1 1          1           1       1                  1
## 44                1 1          1           1       1                  1
## 31                1 1          1           1       1                  1
## 6                 1 1          1           1       1                  1
## 51                1 1          0           0       0                  0
##                   0 0         51          51      51                 51
##     Jumlah_Mahasiswa Rasio_Dosen_per_Mahasiswa Akreditasi_Dept    
## 981                1                         1               1   0
## 44                 1                         1               0   1
## 31                 1                         0               1   1
## 6                  1                         0               0   2
## 51                 0                         0               0   7
##                   51                        88             101 444
data_1 <- data_1 %>% filter(!is.na(Departemen),!is.na(Jenjang),!is.na(Akreditasi_Dept),
                            Rasio_Dosen_per_Mahasiswa!=Inf)
head(data_1) #data yang akan digunakan

EDA Data

Peubah Respon (y)

#format data yang dibutuhkan
data_chart <- data_1 %>% 
  group_by(y) %>%  
  summarize(value=n()) %>%
  mutate(prop = round(value / sum(value) *100, digits = 2))

#pie chart: Sebaran Authors Berdasarkan Kategori SINTA_Score_3Yr
ggplot(data_chart, aes(x="", y=prop, fill=y)) +
  geom_bar(stat="identity", width=1, color="white") +
  coord_polar("y", start=0) +
  labs(title= "Proporsi Authors Menurut Kategori SINTA_Score_3Yr",
       subtitle = "Institut Teknologi Sepuluh Nopember") +
  theme_void() 

Peubah Prediktor (X) Numerik

#Density Jumlah_Dosen_Total
ggplot(data_1, aes(x=Jumlah_Dosen_Total)) +
  geom_histogram(fill="#69b3a2", color="#e9ecef", alpha=0.8, bins=15)+
  theme_light() +
  labs(x="Jumlah_Dosen_Total",
       y="Density",
       title= "Sebaran Jumlah_Dosen_Total",
       subtitle = "Institut Teknologi Sepuluh Nopember") 

#Density Jumlah_Mahasiswa
ggplot(data_1, aes(x=Jumlah_Mahasiswa)) +
  geom_histogram(fill="#69b3a2", color="#e9ecef", alpha=0.8, bins=15)+
  theme_light() +
  labs(x="Jumlah_Mahasiswa",
       y="Density",
       title= "Sebaran Jumlah_Mahasiswa",
       subtitle = "Institut Teknologi Sepuluh Nopember") 

#Density Rasio_Dosen_per_Mahasiswa
ggplot(data_1, aes(x=Rasio_Dosen_per_Mahasiswa)) +
  geom_histogram(fill="#69b3a2", color="#e9ecef", alpha=0.8, bins=20)+
  theme_light() +
  labs(x="Rasio_Dosen_per_Mahasiswa",
       y="Density",
       title= "Sebaran Rasio_Dosen_per_Mahasiswa",
       subtitle = "Institut Teknologi Sepuluh Nopember") 

Peubah Prediktor (X) Kategorik

# Akreditasi_Dept
data_bar_chart = data_1 %>%  
  group_by(Akreditasi_Dept)%>% 
  summarize(Jumlah=n())

ggplot(data_bar_chart, aes(x=Akreditasi_Dept, y=Jumlah)) + 
  geom_bar(stat = "identity",color="steelblue",fill="#69b3a2") +
  theme_light() +
  labs(x="",
       y="",
       title= "Sebaran Akreditasi_Dept",
       subtitle = "Institut Teknologi Sepuluh Nopember") +
  coord_flip()

# Jenjang
data_bar_chart = data_1 %>%  
  group_by(Jenjang)%>% 
  summarize(Jumlah=n())

ggplot(data_bar_chart, aes(x=Jenjang, y=Jumlah)) + 
  geom_bar(stat = "identity",fill="#69b3a2",color="steelblue") +
  theme_light() +
  labs(x="",
       y="",
       title= "Sebaran Jenjang",
       subtitle = "Institut Teknologi Sepuluh Nopember") +
  coord_flip()

# Rumpun Ilmu
data_bar_chart = data_1 %>%  
  group_by(Rumpun_Ilmu)%>% 
  summarize(Jumlah=n())

ggplot(data_bar_chart, aes(x=(Rumpun_Ilmu), y=Jumlah)) + 
  geom_bar(stat = "identity",fill="#69b3a2",color="steelblue") +
  theme_light() +
  labs(x="",
       y="",
       title= "Sebaran Rumpun_Ilmu",
       subtitle = "Institut Teknologi Sepuluh Nopember") +
  coord_flip()

Hubungan Peubah Prediktor dengan Peubah Respon

# Akreditasi_Dept & y
percentData <- data_1 %>% 
  group_by(Akreditasi_Dept) %>% 
  count(y) %>% 
  mutate(ratio=scales::percent(n/sum(n)))
ggplot(data_1,aes(x=factor(Akreditasi_Dept),fill=y,))+
    geom_bar(position="fill")+
    scale_fill_manual(values=c("#7be217", "#4f58ab"))+ 
    geom_text(data=percentData, aes(y=n,label=ratio), color="white",position=position_fill(vjust=0.5))+
    labs( 
       y = "", 
       x = "Akreditasi_Dept", 
       subtitle = "Institut Teknologi Sepuluh Nopember",
       title = "Proporsi Peubah Respon Menurut Akreditasi_Dept")

# Jenjang & y
percentData <- data_1 %>% 
  group_by(Jenjang) %>% 
  count(y) %>% 
  mutate(ratio=scales::percent(n/sum(n)))
ggplot(data_1,aes(x=factor(Jenjang),fill=y,))+
    geom_bar(position="fill")+
    scale_fill_manual(values=c("#7be217", "#4f58ab"))+ 
    geom_text(data=percentData, aes(y=n,label=ratio), color="white",position=position_fill(vjust=0.5))+
    labs( 
       y = "", 
       x = "Jenjang", 
       subtitle = "Institut Teknologi Sepuluh Nopember",
       title = "Proporsi Peubah Respon Menurut Jenjang")

# Rumpun_Ilmu & y
percentData <- data_1 %>% 
  group_by(Rumpun_Ilmu) %>% 
  count(y) %>% 
  mutate(ratio=scales::percent(n/sum(n)))
ggplot(data_1,aes(x=factor(Rumpun_Ilmu),fill=y,))+
    geom_bar(position="fill")+
    scale_fill_manual(values=c("#7be217", "#4f58ab"))+ 
    geom_text(data=percentData, aes(y=n,label=ratio), color="white",position=position_fill(vjust=0.5))+
    labs( 
       y = "", 
       x = "Rumpun_Ilmu", 
       subtitle = "Institut Teknologi Sepuluh Nopember",
       title = "Proporsi Peubah Respon Menurut Rumpun Ilmu")

# Jumlah_Mahasiswa & y

#Boxplot by kategori
ggplot(data_1, aes(y=y,x=Jumlah_Mahasiswa,fill=Jumlah_Mahasiswa,alpha=Jumlah_Mahasiswa)) + 
  geom_boxplot(fill="#69b3a2",  alpha=0.8) +
  theme_light() +
  labs(x="Jumlah_Mahasiswa",
       y="y",
       title= "Sebaran Jumlah Mahasiswa Menurut Peubah Respon",
       subtitle = "Institut Teknologi Sepuluh Nopember") 

# Jumlah_Dosen_Total & y

#Boxplot by kategori
ggplot(data_1, aes(y=y,x=Jumlah_Dosen_Total,fill=Jumlah_Dosen_Total,alpha=Jumlah_Dosen_Total)) + 
  geom_boxplot(fill="#69b3a2",  alpha=0.8) +
  theme_light() +
  labs(x="Jumlah_Dosen_Total",
       y="y",
       title= "Sebaran Jumlah Dosen Total Menurut Peubah Respon",
       subtitle = "Institut Teknologi Sepuluh Nopember") 

# Rasio_Dosen_per_Mahasiswa & y

#Boxplot by kategori
ggplot(data_1, aes(y=y,x=Rasio_Dosen_per_Mahasiswa,fill=Rasio_Dosen_per_Mahasiswa,alpha=Rasio_Dosen_per_Mahasiswa)) + 
  geom_boxplot(fill="#69b3a2",  alpha=0.8) +
  theme_light() +
  labs(x="Rasio_Dosen_per_Mahasiswa",
       y="y",
       title= "Sebaran Rasio Dosen per Mahasiswa Menurut Peubah Respon",
       subtitle = "Institut Teknologi Sepuluh Nopember") 

Data Model

#data yang akan digunakan untuk model
data_sinta <- data_1 %>% select(-c(SINTA_Score_3Yr,Departemen))
str(data_sinta)
## tibble [981 x 7] (S3: tbl_df/tbl/data.frame)
##  $ Rumpun_Ilmu              : Factor w/ 7 levels "Ekonomi","Kesehatan",..: 7 5 7 7 3 7 3 5 3 3 ...
##  $ Jenjang                  : Factor w/ 5 levels "D3","D4","S1",..: 5 3 4 5 4 5 5 3 4 4 ...
##  $ Akreditasi_Dept          : Factor w/ 3 levels "Baik","Baik Sekali",..: 2 3 3 2 3 3 3 3 3 3 ...
##  $ Jumlah_Dosen_Total       : num [1:981] 6 18 6 6 7 6 8 18 7 7 ...
##  $ Jumlah_Mahasiswa         : num [1:981] 68 324 115 68 107 35 38 324 107 107 ...
##  $ Rasio_Dosen_per_Mahasiswa: num [1:981] 0.25 0.191 0.191 0.25 0.187 ...
##  $ y                        : Factor w/ 2 levels "0","1": 2 2 2 2 2 2 2 2 2 2 ...

Splitting Data

set.seed(478)
in.train <- createDataPartition(as.factor(data_sinta$y),p=0.7,list=F) #partisi data
data_sinta_train <- data_sinta[in.train,] #data training utk modelling
data_sinta_test<- data_sinta[-in.train,] #data testing utk evaluasi model

#proporsi kelas peubah respon pada data
round(prop.table(table(data_sinta_train$y)), digits = 4)
## 
##     0     1 
## 0.738 0.262
round(prop.table(table(data_sinta_test$y)), digits = 4)
## 
##      0      1 
## 0.7381 0.2619

Regresi Logistik

Semua Peubah

model_reglog_1 <- glm(y~., data_sinta_train, family=binomial())
summary(model_reglog_1)
## 
## Call:
## glm(formula = y ~ ., family = binomial(), data = data_sinta_train)
## 
## Deviance Residuals: 
##     Min       1Q   Median       3Q      Max  
## -1.6651  -0.6778  -0.5008   0.8076   2.4864  
## 
## Coefficients:
##                                               Estimate Std. Error z value
## (Intercept)                                 -3.9719706  0.9823735  -4.043
## Rumpun_IlmuKesehatan                         1.4100554  1.1627189   1.213
## Rumpun_IlmuMIPA                              1.4284822  0.8015359   1.782
## Rumpun_IlmuPertanian, Perikanan, dan Ternak  2.0519434  2.1802276   0.941
## Rumpun_IlmuSeni, Desain, Media               0.6886598  0.9451778   0.729
## Rumpun_IlmuSosial Humaniora                  0.7492052  1.4772318   0.507
## Rumpun_IlmuTeknik                            0.7592913  0.7457920   1.018
## JenjangS1                                    0.4252569  0.5984613   0.711
## JenjangS2                                    2.4053081  0.6618051   3.634
## JenjangS3                                    3.0121964  0.6671171   4.515
## Akreditasi_DeptBaik Sekali                   0.5947276  0.4869130   1.221
## Akreditasi_DeptUnggul                        0.2623166  0.4418709   0.594
## Jumlah_Dosen_Total                          -0.0378814  0.0217827  -1.739
## Jumlah_Mahasiswa                             0.0024493  0.0008421   2.908
## Rasio_Dosen_per_Mahasiswa                    1.3038436  0.9184191   1.420
##                                             Pr(>|z|)    
## (Intercept)                                 5.27e-05 ***
## Rumpun_IlmuKesehatan                        0.225236    
## Rumpun_IlmuMIPA                             0.074720 .  
## Rumpun_IlmuPertanian, Perikanan, dan Ternak 0.346623    
## Rumpun_IlmuSeni, Desain, Media              0.466244    
## Rumpun_IlmuSosial Humaniora                 0.612037    
## Rumpun_IlmuTeknik                           0.308630    
## JenjangS1                                   0.477342    
## JenjangS2                                   0.000279 ***
## JenjangS3                                   6.32e-06 ***
## Akreditasi_DeptBaik Sekali                  0.221925    
## Akreditasi_DeptUnggul                       0.552746    
## Jumlah_Dosen_Total                          0.082024 .  
## Jumlah_Mahasiswa                            0.003633 ** 
## Rasio_Dosen_per_Mahasiswa                   0.155706    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 790.25  on 686  degrees of freedom
## Residual deviance: 658.43  on 672  degrees of freedom
## AIC: 688.43
## 
## Number of Fisher Scoring iterations: 5
# Prediksi pada Data Training
prediksi_prob_data_train <- predict(model_reglog_1, data_sinta_train, type = "response")
prediksi_data_train <- as.factor(ifelse(prediksi_prob_data_train > 0.5,"1","0"))
eval_reglog_1_train <- caret::confusionMatrix(prediksi_data_train, data_sinta_train$y, positive="1")
eval_reglog_1_train
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   0   1
##          0 461 102
##          1  46  78
##                                           
##                Accuracy : 0.7846          
##                  95% CI : (0.7519, 0.8148)
##     No Information Rate : 0.738           
##     P-Value [Acc > NIR] : 0.002697        
##                                           
##                   Kappa : 0.3808          
##                                           
##  Mcnemar's Test P-Value : 6.156e-06       
##                                           
##             Sensitivity : 0.4333          
##             Specificity : 0.9093          
##          Pos Pred Value : 0.6290          
##          Neg Pred Value : 0.8188          
##              Prevalence : 0.2620          
##          Detection Rate : 0.1135          
##    Detection Prevalence : 0.1805          
##       Balanced Accuracy : 0.6713          
##                                           
##        'Positive' Class : 1               
## 

Sensitivity: kemampuan model dalam memprediksi kelas positif

Specificity: kemampuan model dalam memprediksi kelas negatif

# Prediksi pada Data Testing
prediksi_prob_data_test <- predict(model_reglog_1, data_sinta_test, type = "response")
prediksi_data_test <- as.factor(ifelse(prediksi_prob_data_test > 0.5,"1","0"))
eval_reglog_1 <- caret::confusionMatrix(prediksi_data_test, data_sinta_test$y, positive="1")
eval_reglog_1
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   0   1
##          0 190  53
##          1  27  24
##                                           
##                Accuracy : 0.7279          
##                  95% CI : (0.6732, 0.7779)
##     No Information Rate : 0.7381          
##     P-Value [Acc > NIR] : 0.681686        
##                                           
##                   Kappa : 0.2102          
##                                           
##  Mcnemar's Test P-Value : 0.005189        
##                                           
##             Sensitivity : 0.31169         
##             Specificity : 0.87558         
##          Pos Pred Value : 0.47059         
##          Neg Pred Value : 0.78189         
##              Prevalence : 0.26190         
##          Detection Rate : 0.08163         
##    Detection Prevalence : 0.17347         
##       Balanced Accuracy : 0.59363         
##                                           
##        'Positive' Class : 1               
## 

Performa model pada data training dan data testing perlu diperhatikan untuk mengetahui adanya overfiting/underfiting

Overfiting terjadi ketika performa model pada data training jauh lebih tinggi jika dibandingkan dengan performa model pada data testing (mempelajari data terlalu baik)

Underfiting terjadi ketika performa model pada data testing jauh lebih tinggi jika dibandingkan dengan performa model pada data training (tidak mempelajari data dengan baik)

#fungsi utk membentuk plot ROC
rocplot=function(pred,truth, ...){
  predob=ROCR::prediction(pred,truth)
  perf=ROCR::performance(predob,"tpr","fpr")
  auc=ROCR::performance(predob,"auc")@y.values
  plot(perf,main = auc)
}
#ROC data training
rocplot(prediksi_prob_data_train,data_sinta_train$y) 

#ROC data testing
rocplot(prediksi_prob_data_test,data_sinta_test$y)

#variable importance
vip(model_reglog_1, num_features = 50)

Seleksi Peubah

model_reglog_2 <- glm(y~Jenjang+Jumlah_Mahasiswa , data_sinta, family=binomial())
summary(model_reglog_2)
## 
## Call:
## glm(formula = y ~ Jenjang + Jumlah_Mahasiswa, family = binomial(), 
##     data = data_sinta)
## 
## Deviance Residuals: 
##     Min       1Q   Median       3Q      Max  
## -1.3486  -0.6552  -0.6293   1.0365   2.2800  
## 
## Coefficients:
##                    Estimate Std. Error z value Pr(>|z|)    
## (Intercept)      -2.6209935  0.3946140  -6.642 3.10e-11 ***
## JenjangS1         0.9370228  0.3889559   2.409    0.016 *  
## JenjangS2         2.6796420  0.4140474   6.472 9.68e-11 ***
## JenjangS3         2.9373374  0.4403801   6.670 2.56e-11 ***
## Jumlah_Mahasiswa  0.0003598  0.0003758   0.957    0.338    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 1128.38  on 980  degrees of freedom
## Residual deviance:  994.74  on 976  degrees of freedom
## AIC: 1004.7
## 
## Number of Fisher Scoring iterations: 5
# Prediksi pada Data Training
prediksi_prob_data_train <- predict(model_reglog_2, data_sinta_train, type = "response")
prediksi_data_train <- as.factor(ifelse(prediksi_prob_data_train > 0.5,"1","0"))
eval_reglog_2_train <- caret::confusionMatrix(prediksi_data_train, data_sinta_train$y, positive="1")
eval_reglog_2_train
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   0   1
##          0 432  83
##          1  75  97
##                                          
##                Accuracy : 0.77           
##                  95% CI : (0.7367, 0.801)
##     No Information Rate : 0.738          
##     P-Value [Acc > NIR] : 0.0298         
##                                          
##                   Kappa : 0.3966         
##                                          
##  Mcnemar's Test P-Value : 0.5776         
##                                          
##             Sensitivity : 0.5389         
##             Specificity : 0.8521         
##          Pos Pred Value : 0.5640         
##          Neg Pred Value : 0.8388         
##              Prevalence : 0.2620         
##          Detection Rate : 0.1412         
##    Detection Prevalence : 0.2504         
##       Balanced Accuracy : 0.6955         
##                                          
##        'Positive' Class : 1              
## 
rocplot(prediksi_prob_data_train,data_sinta_train$y) 

# Prediksi pada Data Testing
prediksi_prob_data_test <- predict(model_reglog_2, data_sinta_test, type = "response")
prediksi_data_test <- as.factor(ifelse(prediksi_prob_data_test > 0.5,"1","0"))
eval_reglog_2 <- caret::confusionMatrix(prediksi_data_test, data_sinta_test$y, positive="1")
eval_reglog_2
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   0   1
##          0 186  44
##          1  31  33
##                                          
##                Accuracy : 0.7449         
##                  95% CI : (0.691, 0.7937)
##     No Information Rate : 0.7381         
##     P-Value [Acc > NIR] : 0.4251         
##                                          
##                   Kappa : 0.3022         
##                                          
##  Mcnemar's Test P-Value : 0.1659         
##                                          
##             Sensitivity : 0.4286         
##             Specificity : 0.8571         
##          Pos Pred Value : 0.5156         
##          Neg Pred Value : 0.8087         
##              Prevalence : 0.2619         
##          Detection Rate : 0.1122         
##    Detection Prevalence : 0.2177         
##       Balanced Accuracy : 0.6429         
##                                          
##        'Positive' Class : 1              
## 
rocplot(prediksi_prob_data_test,data_sinta_test$y)

vip(model_reglog_2, num_features = 50)

Classification Tree

Model 1 Default

Model dengan hyperparameter minsplit dan cp default

model_tree_1 <- rpart(y ~., data = data_sinta_train, method = "class",
               control=rpart.control(minsplit = 20, cp=0))
rpart.plot(model_tree_1, extra = 4)

# Prediksi pada Data Training
prediksi_prob_data_train <- predict(model_tree_1, data_sinta_train, type = "prob")
prediksi_data_train <- predict(model_tree_1, newdata=data_sinta_train, type = "class") 
eval_tree_1_train <- caret::confusionMatrix(prediksi_data_train, data_sinta_train$y, positive="1")
eval_tree_1_train
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   0   1
##          0 486 103
##          1  21  77
##                                           
##                Accuracy : 0.8195          
##                  95% CI : (0.7887, 0.8476)
##     No Information Rate : 0.738           
##     P-Value [Acc > NIR] : 2.877e-07       
##                                           
##                   Kappa : 0.4529          
##                                           
##  Mcnemar's Test P-Value : 3.490e-13       
##                                           
##             Sensitivity : 0.4278          
##             Specificity : 0.9586          
##          Pos Pred Value : 0.7857          
##          Neg Pred Value : 0.8251          
##              Prevalence : 0.2620          
##          Detection Rate : 0.1121          
##    Detection Prevalence : 0.1426          
##       Balanced Accuracy : 0.6932          
##                                           
##        'Positive' Class : 1               
## 
rocplot(prediksi_prob_data_train[,2],data_sinta_train$y) 

# Prediksi pada Data Testing
prediksi_prob_data_test <- predict(model_tree_1, data_sinta_test, type = "prob")
prediksi_data_test <- predict(model_tree_1, newdata=data_sinta_test, type = "class") 
eval_tree_1 <- caret::confusionMatrix(prediksi_data_test, data_sinta_test$y, positive="1")
eval_tree_1
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   0   1
##          0 200  54
##          1  17  23
##                                           
##                Accuracy : 0.7585          
##                  95% CI : (0.7054, 0.8063)
##     No Information Rate : 0.7381          
##     P-Value [Acc > NIR] : 0.2344          
##                                           
##                   Kappa : 0.2608          
##                                           
##  Mcnemar's Test P-Value : 1.934e-05       
##                                           
##             Sensitivity : 0.29870         
##             Specificity : 0.92166         
##          Pos Pred Value : 0.57500         
##          Neg Pred Value : 0.78740         
##              Prevalence : 0.26190         
##          Detection Rate : 0.07823         
##    Detection Prevalence : 0.13605         
##       Balanced Accuracy : 0.61018         
##                                           
##        'Positive' Class : 1               
## 
rocplot(prediksi_prob_data_test[,2],data_sinta_test$y)

vip(model_tree_1, num_features = 50)

Model 2

Model dengan hyperparameter minsplit dan cp yang ditentukan sendiri (minsplit=10 dan cp=0)

model_tree_2 <- rpart(y ~., data = data_sinta_train, method = "class",
               control=rpart.control(minsplit = 10, cp=0))
rpart.plot(model_tree_2)

# Prediksi pada Data Training
prediksi_prob_data_train <- predict(model_tree_2, data_sinta_train, type = "prob")
prediksi_data_train <- predict(model_tree_2, newdata=data_sinta_train, type = "class") 
eval_tree_2_train <- caret::confusionMatrix(prediksi_data_train, data_sinta_train$y, positive="1")
eval_tree_2_train
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   0   1
##          0 483  97
##          1  24  83
##                                           
##                Accuracy : 0.8239          
##                  95% CI : (0.7933, 0.8516)
##     No Information Rate : 0.738           
##     P-Value [Acc > NIR] : 6.348e-08       
##                                           
##                   Kappa : 0.476           
##                                           
##  Mcnemar's Test P-Value : 5.931e-11       
##                                           
##             Sensitivity : 0.4611          
##             Specificity : 0.9527          
##          Pos Pred Value : 0.7757          
##          Neg Pred Value : 0.8328          
##              Prevalence : 0.2620          
##          Detection Rate : 0.1208          
##    Detection Prevalence : 0.1557          
##       Balanced Accuracy : 0.7069          
##                                           
##        'Positive' Class : 1               
## 
ROC_model_tree_2_train <- rocit(score=prediksi_prob_data_train[,2], class=data_sinta_train$y)
plot(ROC_model_tree_2_train)

ROC_model_tree_2_train$AUC
## [1] 0.7900668
# Prediksi pada Data Testing
prediksi_prob_data_test <- predict(model_tree_2, data_sinta_test, type = "prob")
prediksi_data_test <- predict(model_tree_2, newdata=data_sinta_test, type = "class") 
eval_tree_2 <- caret::confusionMatrix(prediksi_data_test, data_sinta_test$y, positive="1")
eval_tree_2
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   0   1
##          0 199  52
##          1  18  25
##                                          
##                Accuracy : 0.7619         
##                  95% CI : (0.709, 0.8094)
##     No Information Rate : 0.7381         
##     P-Value [Acc > NIR] : 0.195          
##                                          
##                   Kappa : 0.2819         
##                                          
##  Mcnemar's Test P-Value : 8.005e-05      
##                                          
##             Sensitivity : 0.32468        
##             Specificity : 0.91705        
##          Pos Pred Value : 0.58140        
##          Neg Pred Value : 0.79283        
##              Prevalence : 0.26190        
##          Detection Rate : 0.08503        
##    Detection Prevalence : 0.14626        
##       Balanced Accuracy : 0.62086        
##                                          
##        'Positive' Class : 1              
## 
ROC_model_tree_2 <- rocit(score=prediksi_prob_data_test[,2], class=data_sinta_test$y)
plot(ROC_model_tree_2)

ROC_model_tree_2$AUC
## [1] 0.6928302
vip(model_tree_2, num_features = 50)

Model 3 Tuning Minsplit

Model dengan hyperparameter minsplit optimum

#mencari minsplit optimum
set.seed(478)
akurasi.semua <- NULL

for(ulangan in 1:100){
  acak <- createDataPartition(data_sinta$y, p=0.7, list=FALSE)
  data_sinta_train <- data_sinta[acak,]
  data_sinta_test <- data_sinta[-acak,]

  for (k in 1:30){
  pohon <- rpart(y ~ ., 
                 data=data_sinta_train,
                 method='class',
                 control=rpart.control(minsplit = k, cp=0))
  prediksi.prob <- predict(pohon, data_sinta_test)
  prediksi <- ifelse(prediksi.prob > 0.5, "1", "0")[,2]
  akurasi <- mean(prediksi == data_sinta_test$y)
  akurasi.semua <- rbind(akurasi.semua, c(k, akurasi))
  }
}
mean.akurasi <- tapply(akurasi.semua[,2], akurasi.semua[,1], mean)
plot(names(mean.akurasi),mean.akurasi, type="b", xlab="minsplit", ylab="rata-rata akurasi data testing")

model_tree_3 <- rpart(y ~., data = data_sinta_train, method = "class",
               control=rpart.control(minsplit = 4, cp=0))
rpart.plot(model_tree_3, extra=4)

# Prediksi pada Data Training
prediksi_prob_data_train <- predict(model_tree_3, data_sinta_train, type = "prob")
prediksi_data_train <- predict(model_tree_3, newdata=data_sinta_train, type = "class") 
eval_tree_3_train <- caret::confusionMatrix(prediksi_data_train, data_sinta_train$y, positive="1")
eval_tree_3_train
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   0   1
##          0 484 101
##          1  23  79
##                                           
##                Accuracy : 0.8195          
##                  95% CI : (0.7887, 0.8476)
##     No Information Rate : 0.738           
##     P-Value [Acc > NIR] : 2.877e-07       
##                                           
##                   Kappa : 0.4574          
##                                           
##  Mcnemar's Test P-Value : 4.685e-12       
##                                           
##             Sensitivity : 0.4389          
##             Specificity : 0.9546          
##          Pos Pred Value : 0.7745          
##          Neg Pred Value : 0.8274          
##              Prevalence : 0.2620          
##          Detection Rate : 0.1150          
##    Detection Prevalence : 0.1485          
##       Balanced Accuracy : 0.6968          
##                                           
##        'Positive' Class : 1               
## 
# Prediksi pada Data Testing
prediksi_prob_data_test <- predict(model_tree_3, data_sinta_test, type = "prob")
prediksi_data_test <- predict(model_tree_3, newdata=data_sinta_test, type = "class") 
eval_tree_3 <- caret::confusionMatrix(prediksi_data_test, data_sinta_test$y, positive="1")
eval_tree_3
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   0   1
##          0 200  43
##          1  17  34
##                                           
##                Accuracy : 0.7959          
##                  95% CI : (0.7453, 0.8405)
##     No Information Rate : 0.7381          
##     P-Value [Acc > NIR] : 0.012733        
##                                           
##                   Kappa : 0.4076          
##                                           
##  Mcnemar's Test P-Value : 0.001249        
##                                           
##             Sensitivity : 0.4416          
##             Specificity : 0.9217          
##          Pos Pred Value : 0.6667          
##          Neg Pred Value : 0.8230          
##              Prevalence : 0.2619          
##          Detection Rate : 0.1156          
##    Detection Prevalence : 0.1735          
##       Balanced Accuracy : 0.6816          
##                                           
##        'Positive' Class : 1               
## 
vip(model_tree_3, num_features = 50)

Model 4 Opsi CP

Model dengan hyperparameter cp optimum

set.seed(478)
model_tree_4 <- rpart(y ~ ., data=data_sinta_train,
               method='class',
               control=rpart.control(minsplit = 20, cp=0))
printcp(model_tree_4)
## 
## Classification tree:
## rpart(formula = y ~ ., data = data_sinta_train, method = "class", 
##     control = rpart.control(minsplit = 20, cp = 0))
## 
## Variables actually used in tree construction:
## [1] Jumlah_Mahasiswa          Rasio_Dosen_per_Mahasiswa
## [3] Rumpun_Ilmu              
## 
## Root node error: 180/687 = 0.26201
## 
## n= 687 
## 
##          CP nsplit rel error  xerror     xstd
## 1 0.1000000      0   1.00000 1.00000 0.064031
## 2 0.0666667      1   0.90000 1.01667 0.064371
## 3 0.0222222      2   0.83333 0.90556 0.061945
## 4 0.0194444      4   0.78889 0.92222 0.062334
## 5 0.0037037      6   0.75000 0.86111 0.060865
## 6 0.0000000      9   0.73889 0.88889 0.061548
model_tree_4 <- rpart(y ~ ., data=data_sinta_train,
               method='class',
               control=rpart.control(minsplit = 20, cp=0.0121212))
rpart.plot(model_tree_4)

# Prediksi pada Data Training
prediksi_prob_data_train <- predict(model_tree_4, data_sinta_train, type = "prob")
prediksi_data_train <- predict(model_tree_4, newdata=data_sinta_train, type = "class") 
eval_tree_4_train <- caret::confusionMatrix(prediksi_data_train, data_sinta_train$y, positive="1")
eval_tree_4_train
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   0   1
##          0 485 113
##          1  22  67
##                                           
##                Accuracy : 0.8035          
##                  95% CI : (0.7718, 0.8326)
##     No Information Rate : 0.738           
##     P-Value [Acc > NIR] : 3.565e-05       
##                                           
##                   Kappa : 0.3929          
##                                           
##  Mcnemar's Test P-Value : 9.486e-15       
##                                           
##             Sensitivity : 0.37222         
##             Specificity : 0.95661         
##          Pos Pred Value : 0.75281         
##          Neg Pred Value : 0.81104         
##              Prevalence : 0.26201         
##          Detection Rate : 0.09753         
##    Detection Prevalence : 0.12955         
##       Balanced Accuracy : 0.66441         
##                                           
##        'Positive' Class : 1               
## 
ROC_model_tree_4_train <- rocit(score=prediksi_prob_data_train[,2], class=data_sinta_train$y)
plot(ROC_model_tree_4_train)

ROC_model_tree_4_train$AUC
## [1] 0.6874151
# Prediksi pada Data Testing
prediksi_prob_data_test <- predict(model_tree_4, data_sinta_test, type = "prob")
prediksi_data_test <- predict(model_tree_4, newdata=data_sinta_test, type = "class") 
eval_tree_4 <- caret::confusionMatrix(prediksi_data_test, data_sinta_test$y, positive="1")
eval_tree_4
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   0   1
##          0 197  44
##          1  20  33
##                                           
##                Accuracy : 0.7823          
##                  95% CI : (0.7307, 0.8281)
##     No Information Rate : 0.7381          
##     P-Value [Acc > NIR] : 0.04662         
##                                           
##                   Kappa : 0.374           
##                                           
##  Mcnemar's Test P-Value : 0.00404         
##                                           
##             Sensitivity : 0.4286          
##             Specificity : 0.9078          
##          Pos Pred Value : 0.6226          
##          Neg Pred Value : 0.8174          
##              Prevalence : 0.2619          
##          Detection Rate : 0.1122          
##    Detection Prevalence : 0.1803          
##       Balanced Accuracy : 0.6682          
##                                           
##        'Positive' Class : 1               
## 
ROC_model_tree_4 <- rocit(score=prediksi_prob_data_test[,2], class=data_sinta_test$y)
plot(ROC_model_tree_4)

ROC_model_tree_4$AUC
## [1] 0.7061165
vip(model_tree_4, num_features = 50)

Bagging

Model Default

Model dengan hyperparameter nbagg default dan tree default

model_bag_1 <- ipred::bagging(y ~ ., data=data_sinta_train, coob = TRUE,
                              nbagg=25, 
                              control= rpart.control(minsplit=2, cp=0))
model_bag_1
## 
## Bagging classification trees with 25 bootstrap replications 
## 
## Call: bagging.data.frame(formula = y ~ ., data = data_sinta_train, 
##     coob = TRUE, nbagg = 25, control = rpart.control(minsplit = 2, 
##         cp = 0))
## 
## Out-of-bag estimate of misclassification error:  0.2242
# Prediksi pada Data Training
prediksi_prob_data_train <- predict(model_bag_1, data_sinta_train, type = "prob")
prediksi_data_train <- predict(model_bag_1, data_sinta_train,type="class")
eval_model_bag_1_train <- caret::confusionMatrix(prediksi_data_train, data_sinta_train$y, positive="1")
eval_model_bag_1_train
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   0   1
##          0 472  91
##          1  35  89
##                                           
##                Accuracy : 0.8166          
##                  95% CI : (0.7856, 0.8448)
##     No Information Rate : 0.738           
##     P-Value [Acc > NIR] : 7.511e-07       
##                                           
##                   Kappa : 0.4729          
##                                           
##  Mcnemar's Test P-Value : 9.594e-07       
##                                           
##             Sensitivity : 0.4944          
##             Specificity : 0.9310          
##          Pos Pred Value : 0.7177          
##          Neg Pred Value : 0.8384          
##              Prevalence : 0.2620          
##          Detection Rate : 0.1295          
##    Detection Prevalence : 0.1805          
##       Balanced Accuracy : 0.7127          
##                                           
##        'Positive' Class : 1               
## 
ROC_model_bag_1_train <- rocit(score=prediksi_prob_data_train[,2], class=data_sinta_train$y)
plot(ROC_model_bag_1_train)

ROC_model_bag_1_train$AUC
## [1] 0.818524
# Prediksi pada Data Testing
prediksi_prob_data_test <- predict(model_bag_1, data_sinta_test, type = "prob")
prediksi_data_test <- predict(model_bag_1, data_sinta_test,type="class")
eval_model_bag_1<- caret::confusionMatrix(prediksi_data_test, data_sinta_test$y, positive="1")
eval_model_bag_1
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   0   1
##          0 193  37
##          1  24  40
##                                           
##                Accuracy : 0.7925          
##                  95% CI : (0.7416, 0.8374)
##     No Information Rate : 0.7381          
##     P-Value [Acc > NIR] : 0.01811         
##                                           
##                   Kappa : 0.4324          
##                                           
##  Mcnemar's Test P-Value : 0.12443         
##                                           
##             Sensitivity : 0.5195          
##             Specificity : 0.8894          
##          Pos Pred Value : 0.6250          
##          Neg Pred Value : 0.8391          
##              Prevalence : 0.2619          
##          Detection Rate : 0.1361          
##    Detection Prevalence : 0.2177          
##       Balanced Accuracy : 0.7044          
##                                           
##        'Positive' Class : 1               
## 
ROC_model_bag_1 <- rocit(score=prediksi_prob_data_test[,2], class=data_sinta_test$y)
plot(ROC_model_bag_1)

ROC_model_bag_1$AUC
## [1] 0.7978335

Random Forest

Model 1 Default

Model dengan hyperparameter ntree, mtry default

model_rf_1 <- randomForest::randomForest(y ~ ., ntree=500,
                                         data=data_sinta_train)
# Prediksi pada Data Training
prediksi_prob_data_train <- predict(model_rf_1, data_sinta_train, type = "prob")
prediksi_data_train <- predict(model_rf_1, data_sinta_train,type="class")
eval_model_rf_1_train <- caret::confusionMatrix(prediksi_data_train, data_sinta_train$y, positive="1")
eval_model_rf_1_train
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   0   1
##          0 484 101
##          1  23  79
##                                           
##                Accuracy : 0.8195          
##                  95% CI : (0.7887, 0.8476)
##     No Information Rate : 0.738           
##     P-Value [Acc > NIR] : 2.877e-07       
##                                           
##                   Kappa : 0.4574          
##                                           
##  Mcnemar's Test P-Value : 4.685e-12       
##                                           
##             Sensitivity : 0.4389          
##             Specificity : 0.9546          
##          Pos Pred Value : 0.7745          
##          Neg Pred Value : 0.8274          
##              Prevalence : 0.2620          
##          Detection Rate : 0.1150          
##    Detection Prevalence : 0.1485          
##       Balanced Accuracy : 0.6968          
##                                           
##        'Positive' Class : 1               
## 
ROC_model_rf_1_train <- rocit(score=prediksi_prob_data_train[,2], class=data_sinta_train$y)
plot(ROC_model_rf_1_train)

ROC_model_rf_1_train$AUC
## [1] 0.8325115
# Prediksi pada Data Testing
prediksi_prob_data_test <- predict(model_rf_1, data_sinta_test, type = "prob")
prediksi_data_test <- predict(model_rf_1, data_sinta_test,type="class")
eval_model_rf_1<- caret::confusionMatrix(prediksi_data_test, data_sinta_test$y, positive="1")
eval_model_rf_1
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   0   1
##          0 200  43
##          1  17  34
##                                           
##                Accuracy : 0.7959          
##                  95% CI : (0.7453, 0.8405)
##     No Information Rate : 0.7381          
##     P-Value [Acc > NIR] : 0.012733        
##                                           
##                   Kappa : 0.4076          
##                                           
##  Mcnemar's Test P-Value : 0.001249        
##                                           
##             Sensitivity : 0.4416          
##             Specificity : 0.9217          
##          Pos Pred Value : 0.6667          
##          Neg Pred Value : 0.8230          
##              Prevalence : 0.2619          
##          Detection Rate : 0.1156          
##    Detection Prevalence : 0.1735          
##       Balanced Accuracy : 0.6816          
##                                           
##        'Positive' Class : 1               
## 
ROC_model_rf_1 <- rocit(score=prediksi_prob_data_test[,2], class=data_sinta_test$y)
plot(ROC_model_rf_1)

ROC_model_rf_1$AUC
## [1] 0.8048956
vip(model_rf_1, num_features = 50)

Perbandingan Hasil Model

hasil_eval <- rbind(
  c(eval_reglog_1$overall[1], eval_reglog_1$byClass[1], eval_reglog_1$byClass[2]),
  c(eval_reglog_2$overall[1], eval_reglog_2$byClass[1], eval_reglog_2$byClass[2]),
  c(eval_tree_1$overall[1], eval_tree_1$byClass[1], eval_tree_1$byClass[2]),
  c(eval_tree_2$overall[1], eval_tree_2$byClass[1], eval_tree_2$byClass[2]),
  c(eval_tree_3$overall[1], eval_tree_3$byClass[1], eval_tree_3$byClass[2]),
  c(eval_tree_4$overall[1], eval_tree_4$byClass[1], eval_tree_4$byClass[2]),
  c(eval_model_bag_1$overall[1], eval_model_bag_1$byClass[1], eval_model_bag_1$byClass[2]),
  c(eval_model_rf_1$overall[1], eval_model_rf_1$byClass[1], eval_model_rf_1$byClass[2]))
row.names(hasil_eval) <- 
  c("RegLog Semua Peubah","RegLog Seleksi Peubah",
    "ClassTree 1","ClassTree 2","ClassTree 3","ClassTree 4",
    "Bagging 1", "RandomForest 1")
hasil_eval <- as.data.frame(hasil_eval)
dplyr::arrange(.data = hasil_eval, desc(Accuracy))
LS0tDQp0aXRsZTogIkFuYWxpc2lzIEZha3Rvci1mYWt0b3IgeWFuZyBCZXJwZW5nYXJ1aCB0ZXJoYWRhcCBTaW50YSBTY29yZSBJVFMiDQphdXRob3I6ICJBbGZpZGhpYSBSYWhtYW4gTkoiDQpkYXRlOiAiMjAyMi0wOS0xMSINCm91dHB1dDoNCiAgcm1kZm9ybWF0czo6ZG93bmN1dGU6DQogICAgc2VsZl9jb250YWluZWQ6IHRydWUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgdG9jX2RlcHRoOiAzDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQogICAgdGhlbWU6IGNlcnVsZWFuDQogICAgaGlnaGxpZ2h0OiAia2F0ZSINCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChjYWNoZSA9IFRSVUUpDQpgYGANCg0KYHBhY2thZ2VgIHlhbmcgZGlidXR1aGthbjoNCg0KIyBMaWJyYXJ5DQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGNvbGxhcHNlPVRSVUV9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoa2FibGVFeHRyYSkNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZ2d0aGVtZXMpDQpsaWJyYXJ5KHN0cmluZ3IpDQpsaWJyYXJ5KHJlc2hhcGUyKQ0KbGlicmFyeShtaWNlKQ0KbGlicmFyeShub3J0ZXN0KQ0KbGlicmFyeShEZXNjVG9vbHMpDQpsaWJyYXJ5KGNhcmV0KQ0KbGlicmFyeShycGFydCkNCmxpYnJhcnkocnBhcnQucGxvdCkNCmxpYnJhcnkoUk9DaXQpDQpsaWJyYXJ5KFBSUk9DKQ0KbGlicmFyeShST0NSKQ0KbGlicmFyeSh2aXApDQpsaWJyYXJ5KGdvb2dsZXNoZWV0czQpDQpgYGANCg0KIyBEYXRhDQoNCiMjIEF1dGhvcnMgSW5zdGl0dXQgVGVrbm9sb2dpIFNlcHVsdWggTm9wZW1iZXINCg0KYGBge3J9DQpnczRfZGVhdXRoKCkNCmRmX2F1dGhvcnNfb2sgPC0gcmVhZF9zaGVldCgiaHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vc3ByZWFkc2hlZXRzL2QvMWJ2RmI5Mm40QmZOcUpRZUJGMlVMdUQ5NlJFbl9ZU0VtQlNaYVpabFdUZWMvZWRpdD91c3A9c2hhcmluZyIpDQoNCiNzdHJ1a3R1ciBkYXRhIHNlYmVsdW0gZm9ybWF0aW5nDQpzdHIoZGZfYXV0aG9yc19vaykNCmBgYA0KDQojIyBEYXRhIEZvcm1hdHRpbmcNCg0KYGBge3J9DQpkZl9hdXRob3JzX29rJEplbmphbmcgPC0gYXMuZmFjdG9yKGRmX2F1dGhvcnNfb2skSmVuamFuZykNCmRmX2F1dGhvcnNfb2skRGVwYXJ0ZW1lbiA8LSBhcy5mYWN0b3IoZGZfYXV0aG9yc19vayREZXBhcnRlbWVuKQ0KZGZfYXV0aG9yc19vayRBa3JlZGl0YXNpX0RlcHQgIDwtIGFzLmZhY3RvcihkZl9hdXRob3JzX29rJEFrcmVkaXRhc2lfRGVwdCkNCmRmX2F1dGhvcnNfb2skRGVwdF9KZW5qYW5nICA8LSBhcy5mYWN0b3IoZGZfYXV0aG9yc19vayREZXB0X0plbmphbmcpDQpgYGANCg0KYGBge3J9DQojc3RydWt0dXIgZGF0YSBzZXRlbGFoIGZvcm1hdGluZw0KZ2xpbXBzZShkZl9hdXRob3JzX29rWyxjKCJKZW5qYW5nIiwgIkRlcGFydGVtZW4iLCAiQWtyZWRpdGFzaV9EZXB0IiwgIkRlcHRfSmVuamFuZyIpXSkNCmBgYA0KDQojIyBDaGVjayBKZW5qYW5nIEZhY3Rvcg0KDQpgYGB7cn0NCmxldmVscyhkZl9hdXRob3JzX29rJEplbmphbmcpICNKZW5qYW5nIGF3YWwNCmxldmVscyhkZl9hdXRob3JzX29rJEFrcmVkaXRhc2lfRGVwdCkNCmBgYA0KDQojIyBSdW1wdW4gSWxtdSBkYXJpIFByb2RpDQoNCmBgYHtyfQ0KI01lbWJlbnR1ayBydW1wdW4gaWxtdSBiZXJkYXNhcmthbiBrb2RlIHByb2RpIDIgZGlnaXQNCmRmX3J1bXB1biA8LSBkZl9hdXRob3JzX29rICU+JSANCiAgc2VsZWN0KERlcGFydGVtZW5fSUQsRGVwYXJ0ZW1lbikgICU+JSANCiAgZ3JvdXBfYnkoRGVwYXJ0ZW1lbl9JRCxEZXBhcnRlbWVuKSAlPiUNCiAgc3VtbWFyaXplKCkgJT4lIA0KICBtdXRhdGUoRGVwYXJ0ZW1lbl9JRF8yRGlnaXQgPSBzdWJzdHIoRGVwYXJ0ZW1lbl9JRCwxLDIpKSAlPiUNCiAgbmEub21pdCgpDQpkZl9ydW1wdW4NCmBgYA0KDQpgYGB7cn0NCiNNZW1iZW50dWsgcnVtcHVuIGlsbXUgYmVyZGFzYXJrYW4ga29kZSBwcm9kaSAyIGRpZ2l0DQpkZl9ydW1wdW4gPC0gZGZfcnVtcHVuICU+JSANCiAgbXV0YXRlKFJ1bXB1bl9JbG11ID0gY2FzZV93aGVuKERlcGFydGVtZW5fSURfMkRpZ2l0PT0xMSB+ICJLZXNlaGF0YW4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRGVwYXJ0ZW1lbl9JRF8yRGlnaXQgJWluJSBjKDIwOjM4LCA1NDo1OSkgfiAiVGVrbmlrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlcGFydGVtZW5fSURfMkRpZ2l0ICVpbiUgYyg0NDo1MSw5NCkgfiAiTUlQQSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEZXBhcnRlbWVuX0lEXzJEaWdpdCAlaW4lIGMoNjE6NjMsOTMpIH4gIkVrb25vbWkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRGVwYXJ0ZW1lbl9JRF8yRGlnaXQgJWluJSBjKDYwKSB+ICJTb3NpYWwgSHVtYW5pb3JhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlcGFydGVtZW5fSURfMkRpZ2l0ICVpbiUgYyg0MSkgfiAiUGVydGFuaWFuLCBQZXJpa2FuYW4sIGRhbiBUZXJuYWsiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRGVwYXJ0ZW1lbl9JRF8yRGlnaXQgJWluJSBjKDkwKSB+ICJTZW5pLCBEZXNhaW4sIE1lZGlhIg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSkNCmRmX3J1bXB1bg0KYGBgDQoNCmBgYHtyfQ0KI2RhdGFmcmFtZSBydW1wdW4gaWxtdSB5YW5nIGFrYW4gZGlndW5ha2FuIHVudHVrIGRpIG1lcmdlIGRlbmdhbiBkYXRhIGF3YWwNCmRmX3J1bXB1bl9va2UgPC0gZGZfcnVtcHVuICU+JSBzZWxlY3QoRGVwYXJ0ZW1lbl9JRCxSdW1wdW5fSWxtdSkNCmBgYA0KDQojIEFuYWxpc2lzDQoNCmBgYHtyfQ0KI3N0cnVrdHVyIGRhdGENCmdsaW1wc2UoZGZfYXV0aG9yc19vaykNCmBgYA0KDQojIyBEYXRhDQoNClVuaXQgT2JzZXJ2YXNpID0gQXV0aG9ycw0KDQp5ID0gU0lOVEFfU2NvcmVfM1lyIHlhbmcgZGlrYXRlZ29yaXNhc2kgbWVuamFkaSBgdGluZ2dpYCBkYW4gYHJlbmRhaGANCg0KeDEgPSBSdW1wdW4gSWxtdSAoR2FuamlsIDIwMjEpDQoNCngyID0gSmVuamFuZyAoR2FuamlsIDIwMjEpDQoNCngzID0gQWtyZWRpdGFzaV9EZXB0IChHYW5qaWwgMjAyMSkNCg0KeDQgPSBUb3RhbCBKdW1sYWggRG9zZW4gKEdhbmppbCAyMDIxKQ0KDQp4NSA9IEp1bWxhaCBNYWhhc2lzd2EgKEdhbmppbCAyMDIxKQ0KDQp4NiA9IFJhc2lvIERvc2VuIHBlciBNYWhhc2lzd2EgKEdhbmppbCAyMDIxKQ0KDQpgYGB7cn0NCmRhdGFfMSA8LSBkZl9hdXRob3JzX29rICU+JSAgDQogIGxlZnRfam9pbihkZl9ydW1wdW5fb2tlLCBieT0iRGVwYXJ0ZW1lbl9JRCIpICU+JSAgDQogIHNlbGVjdChTSU5UQV9TY29yZV8zWXIsRGVwYXJ0ZW1lbixSdW1wdW5fSWxtdSxKZW5qYW5nLEFrcmVkaXRhc2lfRGVwdCxKdW1sYWhfRG9zZW5fVG90YWwsDQogICAgICAgICBKdW1sYWhfTWFoYXNpc3dhLFJhc2lvX0Rvc2VuX3Blcl9NYWhhc2lzd2EpICU+JSANCiAgbXV0YXRlKHkgPSBpZmVsc2UoU0lOVEFfU2NvcmVfM1lyPj0yNTYsIjEiLCIwIikpICNrZWxhcyAxOlNJTlRBX1Njb3JlXzNZciB5YW5nIHRpbmdnaQ0KZGF0YV8xJHkgPC0gYXMuZmFjdG9yKGRhdGFfMSR5KQ0KZGF0YV8xJFJ1bXB1bl9JbG11IDwtIGFzLmZhY3RvcihkYXRhXzEkUnVtcHVuX0lsbXUpDQpzdHIoZGF0YV8xKQ0KYGBgDQoNCmBgYHtyfQ0KI0NlayBtaXNzaW5nIHZhbHVlcw0KbWQucGF0dGVybihkYXRhXzEscm90YXRlLm5hbWVzID0gVFJVRSkNCmBgYA0KDQpgYGB7cn0NCmRhdGFfMSA8LSBkYXRhXzEgJT4lIGZpbHRlcighaXMubmEoRGVwYXJ0ZW1lbiksIWlzLm5hKEplbmphbmcpLCFpcy5uYShBa3JlZGl0YXNpX0RlcHQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIFJhc2lvX0Rvc2VuX3Blcl9NYWhhc2lzd2EhPUluZikNCmhlYWQoZGF0YV8xKSAjZGF0YSB5YW5nIGFrYW4gZGlndW5ha2FuDQpgYGANCg0KIyMgRURBIERhdGENCg0KIyMjIFBldWJhaCBSZXNwb24gKHkpDQoNCmBgYHtyfQ0KI2Zvcm1hdCBkYXRhIHlhbmcgZGlidXR1aGthbg0KZGF0YV9jaGFydCA8LSBkYXRhXzEgJT4lIA0KICBncm91cF9ieSh5KSAlPiUgIA0KICBzdW1tYXJpemUodmFsdWU9bigpKSAlPiUNCiAgbXV0YXRlKHByb3AgPSByb3VuZCh2YWx1ZSAvIHN1bSh2YWx1ZSkgKjEwMCwgZGlnaXRzID0gMikpDQoNCiNwaWUgY2hhcnQ6IFNlYmFyYW4gQXV0aG9ycyBCZXJkYXNhcmthbiBLYXRlZ29yaSBTSU5UQV9TY29yZV8zWXINCmdncGxvdChkYXRhX2NoYXJ0LCBhZXMoeD0iIiwgeT1wcm9wLCBmaWxsPXkpKSArDQogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5Iiwgd2lkdGg9MSwgY29sb3I9IndoaXRlIikgKw0KICBjb29yZF9wb2xhcigieSIsIHN0YXJ0PTApICsNCiAgbGFicyh0aXRsZT0gIlByb3BvcnNpIEF1dGhvcnMgTWVudXJ1dCBLYXRlZ29yaSBTSU5UQV9TY29yZV8zWXIiLA0KICAgICAgIHN1YnRpdGxlID0gIkluc3RpdHV0IFRla25vbG9naSBTZXB1bHVoIE5vcGVtYmVyIikgKw0KICB0aGVtZV92b2lkKCkgDQpgYGANCg0KIyMjIFBldWJhaCBQcmVkaWt0b3IgKFgpIE51bWVyaWsNCg0KYGBge3J9DQojRGVuc2l0eSBKdW1sYWhfRG9zZW5fVG90YWwNCmdncGxvdChkYXRhXzEsIGFlcyh4PUp1bWxhaF9Eb3Nlbl9Ub3RhbCkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbD0iIzY5YjNhMiIsIGNvbG9yPSIjZTllY2VmIiwgYWxwaGE9MC44LCBiaW5zPTE1KSsNCiAgdGhlbWVfbGlnaHQoKSArDQogIGxhYnMoeD0iSnVtbGFoX0Rvc2VuX1RvdGFsIiwNCiAgICAgICB5PSJEZW5zaXR5IiwNCiAgICAgICB0aXRsZT0gIlNlYmFyYW4gSnVtbGFoX0Rvc2VuX1RvdGFsIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJJbnN0aXR1dCBUZWtub2xvZ2kgU2VwdWx1aCBOb3BlbWJlciIpIA0KYGBgDQoNCmBgYHtyfQ0KI0RlbnNpdHkgSnVtbGFoX01haGFzaXN3YQ0KZ2dwbG90KGRhdGFfMSwgYWVzKHg9SnVtbGFoX01haGFzaXN3YSkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbD0iIzY5YjNhMiIsIGNvbG9yPSIjZTllY2VmIiwgYWxwaGE9MC44LCBiaW5zPTE1KSsNCiAgdGhlbWVfbGlnaHQoKSArDQogIGxhYnMoeD0iSnVtbGFoX01haGFzaXN3YSIsDQogICAgICAgeT0iRGVuc2l0eSIsDQogICAgICAgdGl0bGU9ICJTZWJhcmFuIEp1bWxhaF9NYWhhc2lzd2EiLA0KICAgICAgIHN1YnRpdGxlID0gIkluc3RpdHV0IFRla25vbG9naSBTZXB1bHVoIE5vcGVtYmVyIikgDQpgYGANCg0KYGBge3J9DQojRGVuc2l0eSBSYXNpb19Eb3Nlbl9wZXJfTWFoYXNpc3dhDQpnZ3Bsb3QoZGF0YV8xLCBhZXMoeD1SYXNpb19Eb3Nlbl9wZXJfTWFoYXNpc3dhKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShmaWxsPSIjNjliM2EyIiwgY29sb3I9IiNlOWVjZWYiLCBhbHBoYT0wLjgsIGJpbnM9MjApKw0KICB0aGVtZV9saWdodCgpICsNCiAgbGFicyh4PSJSYXNpb19Eb3Nlbl9wZXJfTWFoYXNpc3dhIiwNCiAgICAgICB5PSJEZW5zaXR5IiwNCiAgICAgICB0aXRsZT0gIlNlYmFyYW4gUmFzaW9fRG9zZW5fcGVyX01haGFzaXN3YSIsDQogICAgICAgc3VidGl0bGUgPSAiSW5zdGl0dXQgVGVrbm9sb2dpIFNlcHVsdWggTm9wZW1iZXIiKSANCmBgYA0KDQojIyMgUGV1YmFoIFByZWRpa3RvciAoWCkgS2F0ZWdvcmlrDQoNCmBgYHtyfQ0KIyBBa3JlZGl0YXNpX0RlcHQNCmRhdGFfYmFyX2NoYXJ0ID0gZGF0YV8xICU+JSAgDQogIGdyb3VwX2J5KEFrcmVkaXRhc2lfRGVwdCklPiUgDQogIHN1bW1hcml6ZShKdW1sYWg9bigpKQ0KDQpnZ3Bsb3QoZGF0YV9iYXJfY2hhcnQsIGFlcyh4PUFrcmVkaXRhc2lfRGVwdCwgeT1KdW1sYWgpKSArIA0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iixjb2xvcj0ic3RlZWxibHVlIixmaWxsPSIjNjliM2EyIikgKw0KICB0aGVtZV9saWdodCgpICsNCiAgbGFicyh4PSIiLA0KICAgICAgIHk9IiIsDQogICAgICAgdGl0bGU9ICJTZWJhcmFuIEFrcmVkaXRhc2lfRGVwdCIsDQogICAgICAgc3VidGl0bGUgPSAiSW5zdGl0dXQgVGVrbm9sb2dpIFNlcHVsdWggTm9wZW1iZXIiKSArDQogIGNvb3JkX2ZsaXAoKQ0KYGBgDQoNCmBgYHtyfQ0KIyBKZW5qYW5nDQpkYXRhX2Jhcl9jaGFydCA9IGRhdGFfMSAlPiUgIA0KICBncm91cF9ieShKZW5qYW5nKSU+JSANCiAgc3VtbWFyaXplKEp1bWxhaD1uKCkpDQoNCmdncGxvdChkYXRhX2Jhcl9jaGFydCwgYWVzKHg9SmVuamFuZywgeT1KdW1sYWgpKSArIA0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IixmaWxsPSIjNjliM2EyIixjb2xvcj0ic3RlZWxibHVlIikgKw0KICB0aGVtZV9saWdodCgpICsNCiAgbGFicyh4PSIiLA0KICAgICAgIHk9IiIsDQogICAgICAgdGl0bGU9ICJTZWJhcmFuIEplbmphbmciLA0KICAgICAgIHN1YnRpdGxlID0gIkluc3RpdHV0IFRla25vbG9naSBTZXB1bHVoIE5vcGVtYmVyIikgKw0KICBjb29yZF9mbGlwKCkNCmBgYA0KDQpgYGB7cn0NCiMgUnVtcHVuIElsbXUNCmRhdGFfYmFyX2NoYXJ0ID0gZGF0YV8xICU+JSAgDQogIGdyb3VwX2J5KFJ1bXB1bl9JbG11KSU+JSANCiAgc3VtbWFyaXplKEp1bWxhaD1uKCkpDQoNCmdncGxvdChkYXRhX2Jhcl9jaGFydCwgYWVzKHg9KFJ1bXB1bl9JbG11KSwgeT1KdW1sYWgpKSArIA0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IixmaWxsPSIjNjliM2EyIixjb2xvcj0ic3RlZWxibHVlIikgKw0KICB0aGVtZV9saWdodCgpICsNCiAgbGFicyh4PSIiLA0KICAgICAgIHk9IiIsDQogICAgICAgdGl0bGU9ICJTZWJhcmFuIFJ1bXB1bl9JbG11IiwNCiAgICAgICBzdWJ0aXRsZSA9ICJJbnN0aXR1dCBUZWtub2xvZ2kgU2VwdWx1aCBOb3BlbWJlciIpICsNCiAgY29vcmRfZmxpcCgpDQpgYGANCg0KIyMjIEh1YnVuZ2FuIFBldWJhaCBQcmVkaWt0b3IgZGVuZ2FuIFBldWJhaCBSZXNwb24NCg0KYGBge3IgfQ0KIyBBa3JlZGl0YXNpX0RlcHQgJiB5DQpwZXJjZW50RGF0YSA8LSBkYXRhXzEgJT4lIA0KICBncm91cF9ieShBa3JlZGl0YXNpX0RlcHQpICU+JSANCiAgY291bnQoeSkgJT4lIA0KICBtdXRhdGUocmF0aW89c2NhbGVzOjpwZXJjZW50KG4vc3VtKG4pKSkNCmdncGxvdChkYXRhXzEsYWVzKHg9ZmFjdG9yKEFrcmVkaXRhc2lfRGVwdCksZmlsbD15LCkpKw0KICAgIGdlb21fYmFyKHBvc2l0aW9uPSJmaWxsIikrDQogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIiM3YmUyMTciLCAiIzRmNThhYiIpKSsgDQogICAgZ2VvbV90ZXh0KGRhdGE9cGVyY2VudERhdGEsIGFlcyh5PW4sbGFiZWw9cmF0aW8pLCBjb2xvcj0id2hpdGUiLHBvc2l0aW9uPXBvc2l0aW9uX2ZpbGwodmp1c3Q9MC41KSkrDQogICAgbGFicyggDQogICAgICAgeSA9ICIiLCANCiAgICAgICB4ID0gIkFrcmVkaXRhc2lfRGVwdCIsIA0KICAgICAgIHN1YnRpdGxlID0gIkluc3RpdHV0IFRla25vbG9naSBTZXB1bHVoIE5vcGVtYmVyIiwNCiAgICAgICB0aXRsZSA9ICJQcm9wb3JzaSBQZXViYWggUmVzcG9uIE1lbnVydXQgQWtyZWRpdGFzaV9EZXB0IikNCmBgYA0KDQpgYGB7ciB9DQojIEplbmphbmcgJiB5DQpwZXJjZW50RGF0YSA8LSBkYXRhXzEgJT4lIA0KICBncm91cF9ieShKZW5qYW5nKSAlPiUgDQogIGNvdW50KHkpICU+JSANCiAgbXV0YXRlKHJhdGlvPXNjYWxlczo6cGVyY2VudChuL3N1bShuKSkpDQpnZ3Bsb3QoZGF0YV8xLGFlcyh4PWZhY3RvcihKZW5qYW5nKSxmaWxsPXksKSkrDQogICAgZ2VvbV9iYXIocG9zaXRpb249ImZpbGwiKSsNCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiIzdiZTIxNyIsICIjNGY1OGFiIikpKyANCiAgICBnZW9tX3RleHQoZGF0YT1wZXJjZW50RGF0YSwgYWVzKHk9bixsYWJlbD1yYXRpbyksIGNvbG9yPSJ3aGl0ZSIscG9zaXRpb249cG9zaXRpb25fZmlsbCh2anVzdD0wLjUpKSsNCiAgICBsYWJzKCANCiAgICAgICB5ID0gIiIsIA0KICAgICAgIHggPSAiSmVuamFuZyIsIA0KICAgICAgIHN1YnRpdGxlID0gIkluc3RpdHV0IFRla25vbG9naSBTZXB1bHVoIE5vcGVtYmVyIiwNCiAgICAgICB0aXRsZSA9ICJQcm9wb3JzaSBQZXViYWggUmVzcG9uIE1lbnVydXQgSmVuamFuZyIpDQpgYGANCg0KYGBge3IgfQ0KIyBSdW1wdW5fSWxtdSAmIHkNCnBlcmNlbnREYXRhIDwtIGRhdGFfMSAlPiUgDQogIGdyb3VwX2J5KFJ1bXB1bl9JbG11KSAlPiUgDQogIGNvdW50KHkpICU+JSANCiAgbXV0YXRlKHJhdGlvPXNjYWxlczo6cGVyY2VudChuL3N1bShuKSkpDQpnZ3Bsb3QoZGF0YV8xLGFlcyh4PWZhY3RvcihSdW1wdW5fSWxtdSksZmlsbD15LCkpKw0KICAgIGdlb21fYmFyKHBvc2l0aW9uPSJmaWxsIikrDQogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIiM3YmUyMTciLCAiIzRmNThhYiIpKSsgDQogICAgZ2VvbV90ZXh0KGRhdGE9cGVyY2VudERhdGEsIGFlcyh5PW4sbGFiZWw9cmF0aW8pLCBjb2xvcj0id2hpdGUiLHBvc2l0aW9uPXBvc2l0aW9uX2ZpbGwodmp1c3Q9MC41KSkrDQogICAgbGFicyggDQogICAgICAgeSA9ICIiLCANCiAgICAgICB4ID0gIlJ1bXB1bl9JbG11IiwgDQogICAgICAgc3VidGl0bGUgPSAiSW5zdGl0dXQgVGVrbm9sb2dpIFNlcHVsdWggTm9wZW1iZXIiLA0KICAgICAgIHRpdGxlID0gIlByb3BvcnNpIFBldWJhaCBSZXNwb24gTWVudXJ1dCBSdW1wdW4gSWxtdSIpDQpgYGANCg0KYGBge3J9DQojIEp1bWxhaF9NYWhhc2lzd2EgJiB5DQoNCiNCb3hwbG90IGJ5IGthdGVnb3JpDQpnZ3Bsb3QoZGF0YV8xLCBhZXMoeT15LHg9SnVtbGFoX01haGFzaXN3YSxmaWxsPUp1bWxhaF9NYWhhc2lzd2EsYWxwaGE9SnVtbGFoX01haGFzaXN3YSkpICsgDQogIGdlb21fYm94cGxvdChmaWxsPSIjNjliM2EyIiwgIGFscGhhPTAuOCkgKw0KICB0aGVtZV9saWdodCgpICsNCiAgbGFicyh4PSJKdW1sYWhfTWFoYXNpc3dhIiwNCiAgICAgICB5PSJ5IiwNCiAgICAgICB0aXRsZT0gIlNlYmFyYW4gSnVtbGFoIE1haGFzaXN3YSBNZW51cnV0IFBldWJhaCBSZXNwb24iLA0KICAgICAgIHN1YnRpdGxlID0gIkluc3RpdHV0IFRla25vbG9naSBTZXB1bHVoIE5vcGVtYmVyIikgDQpgYGANCg0KYGBge3J9DQojIEp1bWxhaF9Eb3Nlbl9Ub3RhbCAmIHkNCg0KI0JveHBsb3QgYnkga2F0ZWdvcmkNCmdncGxvdChkYXRhXzEsIGFlcyh5PXkseD1KdW1sYWhfRG9zZW5fVG90YWwsZmlsbD1KdW1sYWhfRG9zZW5fVG90YWwsYWxwaGE9SnVtbGFoX0Rvc2VuX1RvdGFsKSkgKyANCiAgZ2VvbV9ib3hwbG90KGZpbGw9IiM2OWIzYTIiLCAgYWxwaGE9MC44KSArDQogIHRoZW1lX2xpZ2h0KCkgKw0KICBsYWJzKHg9Ikp1bWxhaF9Eb3Nlbl9Ub3RhbCIsDQogICAgICAgeT0ieSIsDQogICAgICAgdGl0bGU9ICJTZWJhcmFuIEp1bWxhaCBEb3NlbiBUb3RhbCBNZW51cnV0IFBldWJhaCBSZXNwb24iLA0KICAgICAgIHN1YnRpdGxlID0gIkluc3RpdHV0IFRla25vbG9naSBTZXB1bHVoIE5vcGVtYmVyIikgDQpgYGANCg0KYGBge3J9DQojIFJhc2lvX0Rvc2VuX3Blcl9NYWhhc2lzd2EgJiB5DQoNCiNCb3hwbG90IGJ5IGthdGVnb3JpDQpnZ3Bsb3QoZGF0YV8xLCBhZXMoeT15LHg9UmFzaW9fRG9zZW5fcGVyX01haGFzaXN3YSxmaWxsPVJhc2lvX0Rvc2VuX3Blcl9NYWhhc2lzd2EsYWxwaGE9UmFzaW9fRG9zZW5fcGVyX01haGFzaXN3YSkpICsgDQogIGdlb21fYm94cGxvdChmaWxsPSIjNjliM2EyIiwgIGFscGhhPTAuOCkgKw0KICB0aGVtZV9saWdodCgpICsNCiAgbGFicyh4PSJSYXNpb19Eb3Nlbl9wZXJfTWFoYXNpc3dhIiwNCiAgICAgICB5PSJ5IiwNCiAgICAgICB0aXRsZT0gIlNlYmFyYW4gUmFzaW8gRG9zZW4gcGVyIE1haGFzaXN3YSBNZW51cnV0IFBldWJhaCBSZXNwb24iLA0KICAgICAgIHN1YnRpdGxlID0gIkluc3RpdHV0IFRla25vbG9naSBTZXB1bHVoIE5vcGVtYmVyIikgDQpgYGANCg0KIyBEYXRhIE1vZGVsDQoNCmBgYHtyfQ0KI2RhdGEgeWFuZyBha2FuIGRpZ3VuYWthbiB1bnR1ayBtb2RlbA0KZGF0YV9zaW50YSA8LSBkYXRhXzEgJT4lIHNlbGVjdCgtYyhTSU5UQV9TY29yZV8zWXIsRGVwYXJ0ZW1lbikpDQpzdHIoZGF0YV9zaW50YSkNCmBgYA0KDQojIyBTcGxpdHRpbmcgRGF0YQ0KDQpgYGB7cn0NCnNldC5zZWVkKDQ3OCkNCmluLnRyYWluIDwtIGNyZWF0ZURhdGFQYXJ0aXRpb24oYXMuZmFjdG9yKGRhdGFfc2ludGEkeSkscD0wLjcsbGlzdD1GKSAjcGFydGlzaSBkYXRhDQpkYXRhX3NpbnRhX3RyYWluIDwtIGRhdGFfc2ludGFbaW4udHJhaW4sXSAjZGF0YSB0cmFpbmluZyB1dGsgbW9kZWxsaW5nDQpkYXRhX3NpbnRhX3Rlc3Q8LSBkYXRhX3NpbnRhWy1pbi50cmFpbixdICNkYXRhIHRlc3RpbmcgdXRrIGV2YWx1YXNpIG1vZGVsDQoNCiNwcm9wb3JzaSBrZWxhcyBwZXViYWggcmVzcG9uIHBhZGEgZGF0YQ0Kcm91bmQocHJvcC50YWJsZSh0YWJsZShkYXRhX3NpbnRhX3RyYWluJHkpKSwgZGlnaXRzID0gNCkNCnJvdW5kKHByb3AudGFibGUodGFibGUoZGF0YV9zaW50YV90ZXN0JHkpKSwgZGlnaXRzID0gNCkNCmBgYA0KDQojIFJlZ3Jlc2kgTG9naXN0aWsNCg0KIyMgU2VtdWEgUGV1YmFoDQoNCmBgYHtyfQ0KbW9kZWxfcmVnbG9nXzEgPC0gZ2xtKHl+LiwgZGF0YV9zaW50YV90cmFpbiwgZmFtaWx5PWJpbm9taWFsKCkpDQpzdW1tYXJ5KG1vZGVsX3JlZ2xvZ18xKQ0KYGBgDQoNCmBgYHtyfQ0KIyBQcmVkaWtzaSBwYWRhIERhdGEgVHJhaW5pbmcNCnByZWRpa3NpX3Byb2JfZGF0YV90cmFpbiA8LSBwcmVkaWN0KG1vZGVsX3JlZ2xvZ18xLCBkYXRhX3NpbnRhX3RyYWluLCB0eXBlID0gInJlc3BvbnNlIikNCnByZWRpa3NpX2RhdGFfdHJhaW4gPC0gYXMuZmFjdG9yKGlmZWxzZShwcmVkaWtzaV9wcm9iX2RhdGFfdHJhaW4gPiAwLjUsIjEiLCIwIikpDQpldmFsX3JlZ2xvZ18xX3RyYWluIDwtIGNhcmV0Ojpjb25mdXNpb25NYXRyaXgocHJlZGlrc2lfZGF0YV90cmFpbiwgZGF0YV9zaW50YV90cmFpbiR5LCBwb3NpdGl2ZT0iMSIpDQpldmFsX3JlZ2xvZ18xX3RyYWluDQpgYGANCg0KPiBgU2Vuc2l0aXZpdHlgOiBrZW1hbXB1YW4gbW9kZWwgZGFsYW0gbWVtcHJlZGlrc2kga2VsYXMgYHBvc2l0aWZgDQoNCj4gYFNwZWNpZmljaXR5YDoga2VtYW1wdWFuIG1vZGVsIGRhbGFtIG1lbXByZWRpa3NpIGtlbGFzIGBuZWdhdGlmYA0KDQpgYGB7cn0NCiMgUHJlZGlrc2kgcGFkYSBEYXRhIFRlc3RpbmcNCnByZWRpa3NpX3Byb2JfZGF0YV90ZXN0IDwtIHByZWRpY3QobW9kZWxfcmVnbG9nXzEsIGRhdGFfc2ludGFfdGVzdCwgdHlwZSA9ICJyZXNwb25zZSIpDQpwcmVkaWtzaV9kYXRhX3Rlc3QgPC0gYXMuZmFjdG9yKGlmZWxzZShwcmVkaWtzaV9wcm9iX2RhdGFfdGVzdCA+IDAuNSwiMSIsIjAiKSkNCmV2YWxfcmVnbG9nXzEgPC0gY2FyZXQ6OmNvbmZ1c2lvbk1hdHJpeChwcmVkaWtzaV9kYXRhX3Rlc3QsIGRhdGFfc2ludGFfdGVzdCR5LCBwb3NpdGl2ZT0iMSIpDQpldmFsX3JlZ2xvZ18xDQpgYGANCg0KPiBQZXJmb3JtYSBtb2RlbCBwYWRhIGRhdGEgdHJhaW5pbmcgZGFuIGRhdGEgdGVzdGluZyBwZXJsdSBkaXBlcmhhdGlrYW4gdW50dWsgbWVuZ2V0YWh1aSBhZGFueWEgb3ZlcmZpdGluZy91bmRlcmZpdGluZw0KDQo+IE92ZXJmaXRpbmcgdGVyamFkaSBrZXRpa2EgcGVyZm9ybWEgbW9kZWwgcGFkYSBkYXRhIHRyYWluaW5nIGphdWggbGViaWggdGluZ2dpIGppa2EgZGliYW5kaW5na2FuIGRlbmdhbiBwZXJmb3JtYSBtb2RlbCBwYWRhIGRhdGEgdGVzdGluZyAobWVtcGVsYWphcmkgZGF0YSB0ZXJsYWx1IGJhaWspDQoNCj4gVW5kZXJmaXRpbmcgdGVyamFkaSBrZXRpa2EgcGVyZm9ybWEgbW9kZWwgcGFkYSBkYXRhIHRlc3RpbmcgamF1aCBsZWJpaCB0aW5nZ2kgamlrYSBkaWJhbmRpbmdrYW4gZGVuZ2FuIHBlcmZvcm1hIG1vZGVsIHBhZGEgZGF0YSB0cmFpbmluZyAodGlkYWsgbWVtcGVsYWphcmkgZGF0YSBkZW5nYW4gYmFpaykNCg0KYGBge3J9DQojZnVuZ3NpIHV0ayBtZW1iZW50dWsgcGxvdCBST0MNCnJvY3Bsb3Q9ZnVuY3Rpb24ocHJlZCx0cnV0aCwgLi4uKXsNCiAgcHJlZG9iPVJPQ1I6OnByZWRpY3Rpb24ocHJlZCx0cnV0aCkNCiAgcGVyZj1ST0NSOjpwZXJmb3JtYW5jZShwcmVkb2IsInRwciIsImZwciIpDQogIGF1Yz1ST0NSOjpwZXJmb3JtYW5jZShwcmVkb2IsImF1YyIpQHkudmFsdWVzDQogIHBsb3QocGVyZixtYWluID0gYXVjKQ0KfQ0KYGBgDQoNCmBgYHtyfQ0KI1JPQyBkYXRhIHRyYWluaW5nDQpyb2NwbG90KHByZWRpa3NpX3Byb2JfZGF0YV90cmFpbixkYXRhX3NpbnRhX3RyYWluJHkpIA0KYGBgDQoNCmBgYHtyfQ0KI1JPQyBkYXRhIHRlc3RpbmcNCnJvY3Bsb3QocHJlZGlrc2lfcHJvYl9kYXRhX3Rlc3QsZGF0YV9zaW50YV90ZXN0JHkpDQpgYGANCg0KYGBge3J9DQojdmFyaWFibGUgaW1wb3J0YW5jZQ0KdmlwKG1vZGVsX3JlZ2xvZ18xLCBudW1fZmVhdHVyZXMgPSA1MCkNCmBgYA0KDQojIyBTZWxla3NpIFBldWJhaA0KDQpgYGB7cn0NCm1vZGVsX3JlZ2xvZ18yIDwtIGdsbSh5fkplbmphbmcrSnVtbGFoX01haGFzaXN3YSAsIGRhdGFfc2ludGEsIGZhbWlseT1iaW5vbWlhbCgpKQ0Kc3VtbWFyeShtb2RlbF9yZWdsb2dfMikNCmBgYA0KDQpgYGB7cn0NCiMgUHJlZGlrc2kgcGFkYSBEYXRhIFRyYWluaW5nDQpwcmVkaWtzaV9wcm9iX2RhdGFfdHJhaW4gPC0gcHJlZGljdChtb2RlbF9yZWdsb2dfMiwgZGF0YV9zaW50YV90cmFpbiwgdHlwZSA9ICJyZXNwb25zZSIpDQpwcmVkaWtzaV9kYXRhX3RyYWluIDwtIGFzLmZhY3RvcihpZmVsc2UocHJlZGlrc2lfcHJvYl9kYXRhX3RyYWluID4gMC41LCIxIiwiMCIpKQ0KZXZhbF9yZWdsb2dfMl90cmFpbiA8LSBjYXJldDo6Y29uZnVzaW9uTWF0cml4KHByZWRpa3NpX2RhdGFfdHJhaW4sIGRhdGFfc2ludGFfdHJhaW4keSwgcG9zaXRpdmU9IjEiKQ0KZXZhbF9yZWdsb2dfMl90cmFpbg0KDQpyb2NwbG90KHByZWRpa3NpX3Byb2JfZGF0YV90cmFpbixkYXRhX3NpbnRhX3RyYWluJHkpIA0KYGBgDQoNCmBgYHtyfQ0KIyBQcmVkaWtzaSBwYWRhIERhdGEgVGVzdGluZw0KcHJlZGlrc2lfcHJvYl9kYXRhX3Rlc3QgPC0gcHJlZGljdChtb2RlbF9yZWdsb2dfMiwgZGF0YV9zaW50YV90ZXN0LCB0eXBlID0gInJlc3BvbnNlIikNCnByZWRpa3NpX2RhdGFfdGVzdCA8LSBhcy5mYWN0b3IoaWZlbHNlKHByZWRpa3NpX3Byb2JfZGF0YV90ZXN0ID4gMC41LCIxIiwiMCIpKQ0KZXZhbF9yZWdsb2dfMiA8LSBjYXJldDo6Y29uZnVzaW9uTWF0cml4KHByZWRpa3NpX2RhdGFfdGVzdCwgZGF0YV9zaW50YV90ZXN0JHksIHBvc2l0aXZlPSIxIikNCmV2YWxfcmVnbG9nXzINCg0Kcm9jcGxvdChwcmVkaWtzaV9wcm9iX2RhdGFfdGVzdCxkYXRhX3NpbnRhX3Rlc3QkeSkNCmBgYA0KDQpgYGB7cn0NCnZpcChtb2RlbF9yZWdsb2dfMiwgbnVtX2ZlYXR1cmVzID0gNTApDQpgYGANCg0KIyBDbGFzc2lmaWNhdGlvbiBUcmVlDQoNCiMjIE1vZGVsIDEgRGVmYXVsdA0KDQo+IE1vZGVsIGRlbmdhbiBoeXBlcnBhcmFtZXRlciBgbWluc3BsaXRgIGRhbiBgY3BgIGRlZmF1bHQNCg0KYGBge3J9DQptb2RlbF90cmVlXzEgPC0gcnBhcnQoeSB+LiwgZGF0YSA9IGRhdGFfc2ludGFfdHJhaW4sIG1ldGhvZCA9ICJjbGFzcyIsDQogICAgICAgICAgICAgICBjb250cm9sPXJwYXJ0LmNvbnRyb2wobWluc3BsaXQgPSAyMCwgY3A9MCkpDQpycGFydC5wbG90KG1vZGVsX3RyZWVfMSwgZXh0cmEgPSA0KQ0KYGBgDQoNCmBgYHtyfQ0KIyBQcmVkaWtzaSBwYWRhIERhdGEgVHJhaW5pbmcNCnByZWRpa3NpX3Byb2JfZGF0YV90cmFpbiA8LSBwcmVkaWN0KG1vZGVsX3RyZWVfMSwgZGF0YV9zaW50YV90cmFpbiwgdHlwZSA9ICJwcm9iIikNCnByZWRpa3NpX2RhdGFfdHJhaW4gPC0gcHJlZGljdChtb2RlbF90cmVlXzEsIG5ld2RhdGE9ZGF0YV9zaW50YV90cmFpbiwgdHlwZSA9ICJjbGFzcyIpIA0KZXZhbF90cmVlXzFfdHJhaW4gPC0gY2FyZXQ6OmNvbmZ1c2lvbk1hdHJpeChwcmVkaWtzaV9kYXRhX3RyYWluLCBkYXRhX3NpbnRhX3RyYWluJHksIHBvc2l0aXZlPSIxIikNCmV2YWxfdHJlZV8xX3RyYWluDQoNCnJvY3Bsb3QocHJlZGlrc2lfcHJvYl9kYXRhX3RyYWluWywyXSxkYXRhX3NpbnRhX3RyYWluJHkpIA0KYGBgDQoNCmBgYHtyfQ0KIyBQcmVkaWtzaSBwYWRhIERhdGEgVGVzdGluZw0KcHJlZGlrc2lfcHJvYl9kYXRhX3Rlc3QgPC0gcHJlZGljdChtb2RlbF90cmVlXzEsIGRhdGFfc2ludGFfdGVzdCwgdHlwZSA9ICJwcm9iIikNCnByZWRpa3NpX2RhdGFfdGVzdCA8LSBwcmVkaWN0KG1vZGVsX3RyZWVfMSwgbmV3ZGF0YT1kYXRhX3NpbnRhX3Rlc3QsIHR5cGUgPSAiY2xhc3MiKSANCmV2YWxfdHJlZV8xIDwtIGNhcmV0Ojpjb25mdXNpb25NYXRyaXgocHJlZGlrc2lfZGF0YV90ZXN0LCBkYXRhX3NpbnRhX3Rlc3QkeSwgcG9zaXRpdmU9IjEiKQ0KZXZhbF90cmVlXzENCg0Kcm9jcGxvdChwcmVkaWtzaV9wcm9iX2RhdGFfdGVzdFssMl0sZGF0YV9zaW50YV90ZXN0JHkpDQpgYGANCg0KYGBge3J9DQp2aXAobW9kZWxfdHJlZV8xLCBudW1fZmVhdHVyZXMgPSA1MCkNCmBgYA0KDQojIyBNb2RlbCAyDQoNCj4gTW9kZWwgZGVuZ2FuIGh5cGVycGFyYW1ldGVyIGBtaW5zcGxpdGAgZGFuIGBjcGAgeWFuZyBkaXRlbnR1a2FuIHNlbmRpcmkgKGBtaW5zcGxpdD0xMGAgZGFuIGBjcD0wYCkNCg0KYGBge3J9DQptb2RlbF90cmVlXzIgPC0gcnBhcnQoeSB+LiwgZGF0YSA9IGRhdGFfc2ludGFfdHJhaW4sIG1ldGhvZCA9ICJjbGFzcyIsDQogICAgICAgICAgICAgICBjb250cm9sPXJwYXJ0LmNvbnRyb2wobWluc3BsaXQgPSAxMCwgY3A9MCkpDQpycGFydC5wbG90KG1vZGVsX3RyZWVfMikNCmBgYA0KDQpgYGB7cn0NCiMgUHJlZGlrc2kgcGFkYSBEYXRhIFRyYWluaW5nDQpwcmVkaWtzaV9wcm9iX2RhdGFfdHJhaW4gPC0gcHJlZGljdChtb2RlbF90cmVlXzIsIGRhdGFfc2ludGFfdHJhaW4sIHR5cGUgPSAicHJvYiIpDQpwcmVkaWtzaV9kYXRhX3RyYWluIDwtIHByZWRpY3QobW9kZWxfdHJlZV8yLCBuZXdkYXRhPWRhdGFfc2ludGFfdHJhaW4sIHR5cGUgPSAiY2xhc3MiKSANCmV2YWxfdHJlZV8yX3RyYWluIDwtIGNhcmV0Ojpjb25mdXNpb25NYXRyaXgocHJlZGlrc2lfZGF0YV90cmFpbiwgZGF0YV9zaW50YV90cmFpbiR5LCBwb3NpdGl2ZT0iMSIpDQpldmFsX3RyZWVfMl90cmFpbg0KUk9DX21vZGVsX3RyZWVfMl90cmFpbiA8LSByb2NpdChzY29yZT1wcmVkaWtzaV9wcm9iX2RhdGFfdHJhaW5bLDJdLCBjbGFzcz1kYXRhX3NpbnRhX3RyYWluJHkpDQpwbG90KFJPQ19tb2RlbF90cmVlXzJfdHJhaW4pDQpST0NfbW9kZWxfdHJlZV8yX3RyYWluJEFVQw0KYGBgDQoNCmBgYHtyfQ0KIyBQcmVkaWtzaSBwYWRhIERhdGEgVGVzdGluZw0KcHJlZGlrc2lfcHJvYl9kYXRhX3Rlc3QgPC0gcHJlZGljdChtb2RlbF90cmVlXzIsIGRhdGFfc2ludGFfdGVzdCwgdHlwZSA9ICJwcm9iIikNCnByZWRpa3NpX2RhdGFfdGVzdCA8LSBwcmVkaWN0KG1vZGVsX3RyZWVfMiwgbmV3ZGF0YT1kYXRhX3NpbnRhX3Rlc3QsIHR5cGUgPSAiY2xhc3MiKSANCmV2YWxfdHJlZV8yIDwtIGNhcmV0Ojpjb25mdXNpb25NYXRyaXgocHJlZGlrc2lfZGF0YV90ZXN0LCBkYXRhX3NpbnRhX3Rlc3QkeSwgcG9zaXRpdmU9IjEiKQ0KZXZhbF90cmVlXzINClJPQ19tb2RlbF90cmVlXzIgPC0gcm9jaXQoc2NvcmU9cHJlZGlrc2lfcHJvYl9kYXRhX3Rlc3RbLDJdLCBjbGFzcz1kYXRhX3NpbnRhX3Rlc3QkeSkNCnBsb3QoUk9DX21vZGVsX3RyZWVfMikNClJPQ19tb2RlbF90cmVlXzIkQVVDDQpgYGANCg0KYGBge3J9DQp2aXAobW9kZWxfdHJlZV8yLCBudW1fZmVhdHVyZXMgPSA1MCkNCmBgYA0KDQojIyBNb2RlbCAzIFR1bmluZyBNaW5zcGxpdA0KDQo+IE1vZGVsIGRlbmdhbiBoeXBlcnBhcmFtZXRlciBgbWluc3BsaXRgIG9wdGltdW0NCg0KYGBge3J9DQojbWVuY2FyaSBtaW5zcGxpdCBvcHRpbXVtDQpzZXQuc2VlZCg0NzgpDQpha3VyYXNpLnNlbXVhIDwtIE5VTEwNCg0KZm9yKHVsYW5nYW4gaW4gMToxMDApew0KICBhY2FrIDwtIGNyZWF0ZURhdGFQYXJ0aXRpb24oZGF0YV9zaW50YSR5LCBwPTAuNywgbGlzdD1GQUxTRSkNCiAgZGF0YV9zaW50YV90cmFpbiA8LSBkYXRhX3NpbnRhW2FjYWssXQ0KICBkYXRhX3NpbnRhX3Rlc3QgPC0gZGF0YV9zaW50YVstYWNhayxdDQoNCiAgZm9yIChrIGluIDE6MzApew0KICBwb2hvbiA8LSBycGFydCh5IH4gLiwgDQogICAgICAgICAgICAgICAgIGRhdGE9ZGF0YV9zaW50YV90cmFpbiwNCiAgICAgICAgICAgICAgICAgbWV0aG9kPSdjbGFzcycsDQogICAgICAgICAgICAgICAgIGNvbnRyb2w9cnBhcnQuY29udHJvbChtaW5zcGxpdCA9IGssIGNwPTApKQ0KICBwcmVkaWtzaS5wcm9iIDwtIHByZWRpY3QocG9ob24sIGRhdGFfc2ludGFfdGVzdCkNCiAgcHJlZGlrc2kgPC0gaWZlbHNlKHByZWRpa3NpLnByb2IgPiAwLjUsICIxIiwgIjAiKVssMl0NCiAgYWt1cmFzaSA8LSBtZWFuKHByZWRpa3NpID09IGRhdGFfc2ludGFfdGVzdCR5KQ0KICBha3VyYXNpLnNlbXVhIDwtIHJiaW5kKGFrdXJhc2kuc2VtdWEsIGMoaywgYWt1cmFzaSkpDQogIH0NCn0NCm1lYW4uYWt1cmFzaSA8LSB0YXBwbHkoYWt1cmFzaS5zZW11YVssMl0sIGFrdXJhc2kuc2VtdWFbLDFdLCBtZWFuKQ0KcGxvdChuYW1lcyhtZWFuLmFrdXJhc2kpLG1lYW4uYWt1cmFzaSwgdHlwZT0iYiIsIHhsYWI9Im1pbnNwbGl0IiwgeWxhYj0icmF0YS1yYXRhIGFrdXJhc2kgZGF0YSB0ZXN0aW5nIikNCmBgYA0KDQpgYGB7cn0NCm1vZGVsX3RyZWVfMyA8LSBycGFydCh5IH4uLCBkYXRhID0gZGF0YV9zaW50YV90cmFpbiwgbWV0aG9kID0gImNsYXNzIiwNCiAgICAgICAgICAgICAgIGNvbnRyb2w9cnBhcnQuY29udHJvbChtaW5zcGxpdCA9IDQsIGNwPTApKQ0KcnBhcnQucGxvdChtb2RlbF90cmVlXzMsIGV4dHJhPTQpDQpgYGANCg0KYGBge3J9DQojIFByZWRpa3NpIHBhZGEgRGF0YSBUcmFpbmluZw0KcHJlZGlrc2lfcHJvYl9kYXRhX3RyYWluIDwtIHByZWRpY3QobW9kZWxfdHJlZV8zLCBkYXRhX3NpbnRhX3RyYWluLCB0eXBlID0gInByb2IiKQ0KcHJlZGlrc2lfZGF0YV90cmFpbiA8LSBwcmVkaWN0KG1vZGVsX3RyZWVfMywgbmV3ZGF0YT1kYXRhX3NpbnRhX3RyYWluLCB0eXBlID0gImNsYXNzIikgDQpldmFsX3RyZWVfM190cmFpbiA8LSBjYXJldDo6Y29uZnVzaW9uTWF0cml4KHByZWRpa3NpX2RhdGFfdHJhaW4sIGRhdGFfc2ludGFfdHJhaW4keSwgcG9zaXRpdmU9IjEiKQ0KZXZhbF90cmVlXzNfdHJhaW4NCmBgYA0KDQpgYGB7cn0NCiMgUHJlZGlrc2kgcGFkYSBEYXRhIFRlc3RpbmcNCnByZWRpa3NpX3Byb2JfZGF0YV90ZXN0IDwtIHByZWRpY3QobW9kZWxfdHJlZV8zLCBkYXRhX3NpbnRhX3Rlc3QsIHR5cGUgPSAicHJvYiIpDQpwcmVkaWtzaV9kYXRhX3Rlc3QgPC0gcHJlZGljdChtb2RlbF90cmVlXzMsIG5ld2RhdGE9ZGF0YV9zaW50YV90ZXN0LCB0eXBlID0gImNsYXNzIikgDQpldmFsX3RyZWVfMyA8LSBjYXJldDo6Y29uZnVzaW9uTWF0cml4KHByZWRpa3NpX2RhdGFfdGVzdCwgZGF0YV9zaW50YV90ZXN0JHksIHBvc2l0aXZlPSIxIikNCmV2YWxfdHJlZV8zDQpgYGANCg0KYGBge3J9DQp2aXAobW9kZWxfdHJlZV8zLCBudW1fZmVhdHVyZXMgPSA1MCkNCmBgYA0KDQojIyBNb2RlbCA0IE9wc2kgQ1ANCg0KPiBNb2RlbCBkZW5nYW4gaHlwZXJwYXJhbWV0ZXIgYGNwYCBvcHRpbXVtDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoNDc4KQ0KbW9kZWxfdHJlZV80IDwtIHJwYXJ0KHkgfiAuLCBkYXRhPWRhdGFfc2ludGFfdHJhaW4sDQogICAgICAgICAgICAgICBtZXRob2Q9J2NsYXNzJywNCiAgICAgICAgICAgICAgIGNvbnRyb2w9cnBhcnQuY29udHJvbChtaW5zcGxpdCA9IDIwLCBjcD0wKSkNCnByaW50Y3AobW9kZWxfdHJlZV80KQ0KYGBgDQoNCmBgYHtyfQ0KbW9kZWxfdHJlZV80IDwtIHJwYXJ0KHkgfiAuLCBkYXRhPWRhdGFfc2ludGFfdHJhaW4sDQogICAgICAgICAgICAgICBtZXRob2Q9J2NsYXNzJywNCiAgICAgICAgICAgICAgIGNvbnRyb2w9cnBhcnQuY29udHJvbChtaW5zcGxpdCA9IDIwLCBjcD0wLjAxMjEyMTIpKQ0KcnBhcnQucGxvdChtb2RlbF90cmVlXzQpDQpgYGANCg0KYGBge3J9DQojIFByZWRpa3NpIHBhZGEgRGF0YSBUcmFpbmluZw0KcHJlZGlrc2lfcHJvYl9kYXRhX3RyYWluIDwtIHByZWRpY3QobW9kZWxfdHJlZV80LCBkYXRhX3NpbnRhX3RyYWluLCB0eXBlID0gInByb2IiKQ0KcHJlZGlrc2lfZGF0YV90cmFpbiA8LSBwcmVkaWN0KG1vZGVsX3RyZWVfNCwgbmV3ZGF0YT1kYXRhX3NpbnRhX3RyYWluLCB0eXBlID0gImNsYXNzIikgDQpldmFsX3RyZWVfNF90cmFpbiA8LSBjYXJldDo6Y29uZnVzaW9uTWF0cml4KHByZWRpa3NpX2RhdGFfdHJhaW4sIGRhdGFfc2ludGFfdHJhaW4keSwgcG9zaXRpdmU9IjEiKQ0KZXZhbF90cmVlXzRfdHJhaW4NClJPQ19tb2RlbF90cmVlXzRfdHJhaW4gPC0gcm9jaXQoc2NvcmU9cHJlZGlrc2lfcHJvYl9kYXRhX3RyYWluWywyXSwgY2xhc3M9ZGF0YV9zaW50YV90cmFpbiR5KQ0KcGxvdChST0NfbW9kZWxfdHJlZV80X3RyYWluKQ0KUk9DX21vZGVsX3RyZWVfNF90cmFpbiRBVUMNCmBgYA0KDQpgYGB7cn0NCiMgUHJlZGlrc2kgcGFkYSBEYXRhIFRlc3RpbmcNCnByZWRpa3NpX3Byb2JfZGF0YV90ZXN0IDwtIHByZWRpY3QobW9kZWxfdHJlZV80LCBkYXRhX3NpbnRhX3Rlc3QsIHR5cGUgPSAicHJvYiIpDQpwcmVkaWtzaV9kYXRhX3Rlc3QgPC0gcHJlZGljdChtb2RlbF90cmVlXzQsIG5ld2RhdGE9ZGF0YV9zaW50YV90ZXN0LCB0eXBlID0gImNsYXNzIikgDQpldmFsX3RyZWVfNCA8LSBjYXJldDo6Y29uZnVzaW9uTWF0cml4KHByZWRpa3NpX2RhdGFfdGVzdCwgZGF0YV9zaW50YV90ZXN0JHksIHBvc2l0aXZlPSIxIikNCmV2YWxfdHJlZV80DQpST0NfbW9kZWxfdHJlZV80IDwtIHJvY2l0KHNjb3JlPXByZWRpa3NpX3Byb2JfZGF0YV90ZXN0WywyXSwgY2xhc3M9ZGF0YV9zaW50YV90ZXN0JHkpDQpwbG90KFJPQ19tb2RlbF90cmVlXzQpDQpST0NfbW9kZWxfdHJlZV80JEFVQw0KYGBgDQoNCmBgYHtyfQ0KdmlwKG1vZGVsX3RyZWVfNCwgbnVtX2ZlYXR1cmVzID0gNTApDQpgYGANCg0KIyBCYWdnaW5nDQoNCiMjIE1vZGVsIERlZmF1bHQNCg0KPiBNb2RlbCBkZW5nYW4gaHlwZXJwYXJhbWV0ZXIgYG5iYWdnYCBkZWZhdWx0IGRhbiBgdHJlZWAgZGVmYXVsdA0KDQpgYGB7cn0NCm1vZGVsX2JhZ18xIDwtIGlwcmVkOjpiYWdnaW5nKHkgfiAuLCBkYXRhPWRhdGFfc2ludGFfdHJhaW4sIGNvb2IgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmJhZ2c9MjUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJvbD0gcnBhcnQuY29udHJvbChtaW5zcGxpdD0yLCBjcD0wKSkNCm1vZGVsX2JhZ18xDQpgYGANCg0KYGBge3J9DQojIFByZWRpa3NpIHBhZGEgRGF0YSBUcmFpbmluZw0KcHJlZGlrc2lfcHJvYl9kYXRhX3RyYWluIDwtIHByZWRpY3QobW9kZWxfYmFnXzEsIGRhdGFfc2ludGFfdHJhaW4sIHR5cGUgPSAicHJvYiIpDQpwcmVkaWtzaV9kYXRhX3RyYWluIDwtIHByZWRpY3QobW9kZWxfYmFnXzEsIGRhdGFfc2ludGFfdHJhaW4sdHlwZT0iY2xhc3MiKQ0KZXZhbF9tb2RlbF9iYWdfMV90cmFpbiA8LSBjYXJldDo6Y29uZnVzaW9uTWF0cml4KHByZWRpa3NpX2RhdGFfdHJhaW4sIGRhdGFfc2ludGFfdHJhaW4keSwgcG9zaXRpdmU9IjEiKQ0KZXZhbF9tb2RlbF9iYWdfMV90cmFpbg0KUk9DX21vZGVsX2JhZ18xX3RyYWluIDwtIHJvY2l0KHNjb3JlPXByZWRpa3NpX3Byb2JfZGF0YV90cmFpblssMl0sIGNsYXNzPWRhdGFfc2ludGFfdHJhaW4keSkNCnBsb3QoUk9DX21vZGVsX2JhZ18xX3RyYWluKQ0KUk9DX21vZGVsX2JhZ18xX3RyYWluJEFVQw0KYGBgDQoNCmBgYHtyfQ0KIyBQcmVkaWtzaSBwYWRhIERhdGEgVGVzdGluZw0KcHJlZGlrc2lfcHJvYl9kYXRhX3Rlc3QgPC0gcHJlZGljdChtb2RlbF9iYWdfMSwgZGF0YV9zaW50YV90ZXN0LCB0eXBlID0gInByb2IiKQ0KcHJlZGlrc2lfZGF0YV90ZXN0IDwtIHByZWRpY3QobW9kZWxfYmFnXzEsIGRhdGFfc2ludGFfdGVzdCx0eXBlPSJjbGFzcyIpDQpldmFsX21vZGVsX2JhZ18xPC0gY2FyZXQ6OmNvbmZ1c2lvbk1hdHJpeChwcmVkaWtzaV9kYXRhX3Rlc3QsIGRhdGFfc2ludGFfdGVzdCR5LCBwb3NpdGl2ZT0iMSIpDQpldmFsX21vZGVsX2JhZ18xDQpST0NfbW9kZWxfYmFnXzEgPC0gcm9jaXQoc2NvcmU9cHJlZGlrc2lfcHJvYl9kYXRhX3Rlc3RbLDJdLCBjbGFzcz1kYXRhX3NpbnRhX3Rlc3QkeSkNCnBsb3QoUk9DX21vZGVsX2JhZ18xKQ0KUk9DX21vZGVsX2JhZ18xJEFVQw0KYGBgDQoNCiMgUmFuZG9tIEZvcmVzdA0KDQojIyBNb2RlbCAxIERlZmF1bHQNCg0KPiBNb2RlbCBkZW5nYW4gaHlwZXJwYXJhbWV0ZXIgYG50cmVlYCwgYG10cnlgIGRlZmF1bHQNCg0KYGBge3J9DQptb2RlbF9yZl8xIDwtIHJhbmRvbUZvcmVzdDo6cmFuZG9tRm9yZXN0KHkgfiAuLCBudHJlZT01MDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE9ZGF0YV9zaW50YV90cmFpbikNCmBgYA0KDQpgYGB7cn0NCiMgUHJlZGlrc2kgcGFkYSBEYXRhIFRyYWluaW5nDQpwcmVkaWtzaV9wcm9iX2RhdGFfdHJhaW4gPC0gcHJlZGljdChtb2RlbF9yZl8xLCBkYXRhX3NpbnRhX3RyYWluLCB0eXBlID0gInByb2IiKQ0KcHJlZGlrc2lfZGF0YV90cmFpbiA8LSBwcmVkaWN0KG1vZGVsX3JmXzEsIGRhdGFfc2ludGFfdHJhaW4sdHlwZT0iY2xhc3MiKQ0KZXZhbF9tb2RlbF9yZl8xX3RyYWluIDwtIGNhcmV0Ojpjb25mdXNpb25NYXRyaXgocHJlZGlrc2lfZGF0YV90cmFpbiwgZGF0YV9zaW50YV90cmFpbiR5LCBwb3NpdGl2ZT0iMSIpDQpldmFsX21vZGVsX3JmXzFfdHJhaW4NClJPQ19tb2RlbF9yZl8xX3RyYWluIDwtIHJvY2l0KHNjb3JlPXByZWRpa3NpX3Byb2JfZGF0YV90cmFpblssMl0sIGNsYXNzPWRhdGFfc2ludGFfdHJhaW4keSkNCnBsb3QoUk9DX21vZGVsX3JmXzFfdHJhaW4pDQpST0NfbW9kZWxfcmZfMV90cmFpbiRBVUMNCmBgYA0KDQpgYGB7cn0NCiMgUHJlZGlrc2kgcGFkYSBEYXRhIFRlc3RpbmcNCnByZWRpa3NpX3Byb2JfZGF0YV90ZXN0IDwtIHByZWRpY3QobW9kZWxfcmZfMSwgZGF0YV9zaW50YV90ZXN0LCB0eXBlID0gInByb2IiKQ0KcHJlZGlrc2lfZGF0YV90ZXN0IDwtIHByZWRpY3QobW9kZWxfcmZfMSwgZGF0YV9zaW50YV90ZXN0LHR5cGU9ImNsYXNzIikNCmV2YWxfbW9kZWxfcmZfMTwtIGNhcmV0Ojpjb25mdXNpb25NYXRyaXgocHJlZGlrc2lfZGF0YV90ZXN0LCBkYXRhX3NpbnRhX3Rlc3QkeSwgcG9zaXRpdmU9IjEiKQ0KZXZhbF9tb2RlbF9yZl8xDQpST0NfbW9kZWxfcmZfMSA8LSByb2NpdChzY29yZT1wcmVkaWtzaV9wcm9iX2RhdGFfdGVzdFssMl0sIGNsYXNzPWRhdGFfc2ludGFfdGVzdCR5KQ0KcGxvdChST0NfbW9kZWxfcmZfMSkNClJPQ19tb2RlbF9yZl8xJEFVQw0KYGBgDQoNCmBgYHtyfQ0KdmlwKG1vZGVsX3JmXzEsIG51bV9mZWF0dXJlcyA9IDUwKQ0KYGBgDQoNCiMgUGVyYmFuZGluZ2FuIEhhc2lsIE1vZGVsDQoNCmBgYHtyfQ0KaGFzaWxfZXZhbCA8LSByYmluZCgNCiAgYyhldmFsX3JlZ2xvZ18xJG92ZXJhbGxbMV0sIGV2YWxfcmVnbG9nXzEkYnlDbGFzc1sxXSwgZXZhbF9yZWdsb2dfMSRieUNsYXNzWzJdKSwNCiAgYyhldmFsX3JlZ2xvZ18yJG92ZXJhbGxbMV0sIGV2YWxfcmVnbG9nXzIkYnlDbGFzc1sxXSwgZXZhbF9yZWdsb2dfMiRieUNsYXNzWzJdKSwNCiAgYyhldmFsX3RyZWVfMSRvdmVyYWxsWzFdLCBldmFsX3RyZWVfMSRieUNsYXNzWzFdLCBldmFsX3RyZWVfMSRieUNsYXNzWzJdKSwNCiAgYyhldmFsX3RyZWVfMiRvdmVyYWxsWzFdLCBldmFsX3RyZWVfMiRieUNsYXNzWzFdLCBldmFsX3RyZWVfMiRieUNsYXNzWzJdKSwNCiAgYyhldmFsX3RyZWVfMyRvdmVyYWxsWzFdLCBldmFsX3RyZWVfMyRieUNsYXNzWzFdLCBldmFsX3RyZWVfMyRieUNsYXNzWzJdKSwNCiAgYyhldmFsX3RyZWVfNCRvdmVyYWxsWzFdLCBldmFsX3RyZWVfNCRieUNsYXNzWzFdLCBldmFsX3RyZWVfNCRieUNsYXNzWzJdKSwNCiAgYyhldmFsX21vZGVsX2JhZ18xJG92ZXJhbGxbMV0sIGV2YWxfbW9kZWxfYmFnXzEkYnlDbGFzc1sxXSwgZXZhbF9tb2RlbF9iYWdfMSRieUNsYXNzWzJdKSwNCiAgYyhldmFsX21vZGVsX3JmXzEkb3ZlcmFsbFsxXSwgZXZhbF9tb2RlbF9yZl8xJGJ5Q2xhc3NbMV0sIGV2YWxfbW9kZWxfcmZfMSRieUNsYXNzWzJdKSkNCnJvdy5uYW1lcyhoYXNpbF9ldmFsKSA8LSANCiAgYygiUmVnTG9nIFNlbXVhIFBldWJhaCIsIlJlZ0xvZyBTZWxla3NpIFBldWJhaCIsDQogICAgIkNsYXNzVHJlZSAxIiwiQ2xhc3NUcmVlIDIiLCJDbGFzc1RyZWUgMyIsIkNsYXNzVHJlZSA0IiwNCiAgICAiQmFnZ2luZyAxIiwgIlJhbmRvbUZvcmVzdCAxIikNCmhhc2lsX2V2YWwgPC0gYXMuZGF0YS5mcmFtZShoYXNpbF9ldmFsKQ0KZHBseXI6OmFycmFuZ2UoLmRhdGEgPSBoYXNpbF9ldmFsLCBkZXNjKEFjY3VyYWN5KSkNCmBgYA0K