Kontak : \(\downarrow\)
Email
RPubs https://rpubs.com/evelintrivena/
Jurusan Fisika Medis

Pendahuluan

R adalah bahasa pemrograman yang banyak digunakan untuk analisis statistik. Menghubungkan dengan data merupakan hal yang paling mendasar dalam pengolahan data. Berikut adalah cara menggunakan bahasa pemrograman R dalam proses antarmuka data yang sangat sederhana. Secara garis besar, R dapat membaca data dari file yang tersimpan di dalam dan di luar direktorinya. Tidak hanya itu, sistem operasi R juga dapat mengimpor dan mengekspor data dalam berbagai format file, seperti csv, excel, txt, rds, xml, json, dll.

Impor / ekspor CSV

Ada beberapa cara yang bisa digunakan untuk melakukan impor dan ekspor data dengan menggunakan R. Berikut ini, 3 cara yang dapat dilakukan :

Cara 1

Pertama, pastikan working directory sudah tepat. untuk mendapatkan informasi working directory / lokasinya dapat mengunakan fungsi getwd()

print(getwd())
## [1] "C:/Users/Acer.LAPTOP-FHQA6U69/Documents/data"
getwd()
## [1] "C:/Users/Acer.LAPTOP-FHQA6U69/Documents/data"

Untuk mengubah / mengatur working directory baru dapat menggunakan fungsi setwd()

setwd(getwd())
  • Impor data CSV dengan fungsi read.csv()
df1 <- read.csv("input/input1.csv", sep=",")
df1
##    id    name salary start_date      dept
## 1   1  Julian 623.00   1/1/2022        DS
## 2   2 Vanessa 515.00  9/23/2022        DS
## 3   3  Jeffry 611.00 11/15/2022        BA
## 4   4   Angel 729.00  5/11/2022        DA
## 5   5   Nikki 843.25  3/27/2022        DS
## 6   6  Ardifo 578.00  5/21/2022 Actuaries
## 7   7   Irene 722.50  7/30/2022 Actuaries
## 8   8   Kefas 632.79  6/17/2022        CA
## 9   9  Sherly 632.79  7/30/2022        DE
## 10 10   Bakti     NA   9/3/2018  Lecturer
df2 <- read.csv("input/input2.csv", sep=";")
df2
##    id    name salary start_date      dept
## 1   1  Julian  623,3 2022-01-01        DS
## 2   2 Vanessa  515,2 2022-09-23        DS
## 3   3  Jeffry    611 2022-11-15        BA
## 4   4   Angel    729 2022-05-11        DA
## 5   5   Nikki 843,25 2022-03-27        DS
## 6   6  Ardifo    578 2022-05-21 Actuaries
## 7   7   Irene  722,5 2022-07-30 Actuaries
## 8   8   Kefas  632,8 2022-06-17        CA
## 9   9  Sherly  632,8 2022-07-30        DE
## 10 10   Bakti   <NA> 2018-09-03  Lecturer
  • Ekspor data CSV dengan fungsi write.csv() Ekspor data (menyimpan data) csv ke directory yang diinginkan dapa menggunakan fungsi write.csv() untuk file yang menggunakan simbol koma(,) sebagai delimiternya, dan menggunakan fungsi write.csv2() untuk file csv yang menggunakan titik koma (;) sebagai delimiternya.
write.csv(df1,"output/test1.csv", row.names=FALSE)
write.csv(df2,"output/test2.csv", row.names=FALSE)

Cara 2

Koneksi directory secara automatis, dapat dilakukan dengan cara berikut.

# setting directory
(swd<-getwd())
## [1] "C:/Users/Acer.LAPTOP-FHQA6U69/Documents/data"
if (!is.null(swd)) setwd(swd)
  • Impor data CSV
df1<-read.csv(file.path(swd,'input', 'input1.csv'))
df1
##    id    name salary start_date      dept
## 1   1  Julian 623.00   1/1/2022        DS
## 2   2 Vanessa 515.00  9/23/2022        DS
## 3   3  Jeffry 611.00 11/15/2022        BA
## 4   4   Angel 729.00  5/11/2022        DA
## 5   5   Nikki 843.25  3/27/2022        DS
## 6   6  Ardifo 578.00  5/21/2022 Actuaries
## 7   7   Irene 722.50  7/30/2022 Actuaries
## 8   8   Kefas 632.79  6/17/2022        CA
## 9   9  Sherly 632.79  7/30/2022        DE
## 10 10   Bakti     NA   9/3/2018  Lecturer
df2<-read.csv(file.path(swd,'input', 'input2.csv'))
df2
##        id.name.salary.start_date.dept
## 1        1;Julian;623,3;2022-01-01;DS
## 2       2;Vanessa;515,2;2022-09-23;DS
## 3          3;Jeffry;611;2022-11-15;BA
## 4           4;Angel;729;2022-05-11;DA
## 5        5;Nikki;843,25;2022-03-27;DS
## 6   6;Ardifo;578;2022-05-21;Actuaries
## 7  7;Irene;722,5;2022-07-30;Actuaries
## 8         8;Kefas;632,8;2022-06-17;CA
## 9        9;Sherly;632,8;2022-07-30;DE
## 10    10;Bakti;NA;2018-09-03;Lecturer
  • Ekspor data CSV
write.csv(df1, file.path(swd, 'output', 'output1.csv'), row.names = FALSE)
write.csv(df2, file.path(swd, 'output', 'output2.csv'), row.names = FALSE)

Cara 3

Cara ini merupakan langkah alternatif, untuk dapat mengimpor dan mengekspor data csv dengan memilih data yang disimpan tanpa mengatur direktori terlebih dahulu. Fungsi yang digunakan adalah file.choose()

df<-read.csv(file.choose())
df
##    id    name salary start_date      dept
## 1   1  Julian 623.00   1/1/2022        DS
## 2   2 Vanessa 515.00  9/23/2022        DS
## 3   3  Jeffry 611.00 11/15/2022        BA
## 4   4   Angel 729.00  5/11/2022        DA
## 5   5   Nikki 843.25  3/27/2022        DS
## 6   6  Ardifo 578.00  5/21/2022 Actuaries
## 7   7   Irene 722.50  7/30/2022 Actuaries
## 8   8   Kefas 632.79  6/17/2022        CA
## 9   9  Sherly 632.79  7/30/2022        DE
## 10 10   Bakti     NA   9/3/2018  Lecturer

Impor/ekspor Excel

Microsoft Excel merupakan program spreadsheet yang paling banyak digunakan untuk menyimpan data dalam bentuk .xls atau .xlsx . R dapat menggunakan packages readxl dan writexl untuk membaca langsung dari file-file ini.

# install.packages(c("readxl", "writexl"))   # install `readxl & writexl` 
pacman::p_load(readxl, writexl)              # load `readxl & writexl`

Impor Data

df3<-read_excel("Input/input4.xls")          # impor data xls (97-2003)
df3
## # A tibble: 14 x 5
##       id name    salary start_date dept     
##    <dbl> <chr>   <chr>  <chr>      <chr>    
##  1     1 Julian  623    44562      DS       
##  2     2 Vanessa 515    44827      DS       
##  3     3 Jeffry  611    44880      BA       
##  4     4 Angel   729    44692      DA       
##  5     5 Nikki   843.25 44647      DS       
##  6     6 Ardifo  578    44702      Actuaries
##  7     7 Irene   722.5  44772      Actuaries
##  8     8 Kefas   632.79 44729      CA       
##  9     9 Sherly  632.79 44772      DE       
## 10    10 Bakti   NA     43346      Lecturer 
## 11    11 Ardifo  632.79 44711      DA       
## 12    12 Siana   632.79 2/30/2022  BA       
## 13    13 Fallen  632.79 44742      DS       
## 14    14 Lala    632.79 44650      BA
df4<-read_excel("Input/input3.xlsx",sheet=1) # impor data xlsx (2003-up)
df4
## # A tibble: 14 x 5
##       id name    salary start_date dept     
##    <dbl> <chr>   <chr>  <chr>      <chr>    
##  1     1 Julian  623    44562      DS       
##  2     2 Vanessa 515    44827      DS       
##  3     3 Jeffry  611    44880      BA       
##  4     4 Angel   729    44692      DA       
##  5     5 Nikki   843.25 44647      DS       
##  6     6 Ardifo  578    44702      Actuaries
##  7     7 Irene   722.5  44772      Actuaries
##  8     8 Kefas   632.79 44729      CA       
##  9     9 Sherly  632.79 44772      DE       
## 10    10 Bakti   NA     43346      Lecturer 
## 11    11 Ardifo  632.79 44711      DA       
## 12    12 Siana   632.79 2/30/2022  BA       
## 13    13 Fallen  632.79 44742      DS       
## 14    14 Lala    632.79 44650      BA

Ekspor Data

write_xlsx(df3,"output/output3.xls") 
write_xlsx(df4,"output/output4.xlsx")

Impor / ekspor TXT dan RDS

Format data ini banyak digunakan untuk file/data yang lebih besar. Dalam format CSV dan Excel ukuran filenya cenderung lebih besar dibandingkan format TXT atau file biner R (RDS). Sehingga data dalam format CSV atau Excel akan dicompress menjadi TXT atau RDS.

Impor data

df5<-read.table('input/input5.txt')
df5
##    id    name salary start_date      dept
## 1   1  Julian  623,3   1/1/2022        DS
## 2   2 Vanessa  515,2  9/23/2022        DS
## 3   3  Jeffry    611 11/15/2022        BA
## 4   4   Angel    729  5/11/2022        DA
## 5   5   Nikki 843,25  3/27/2022        DS
## 6   6  Ardifo    578  5/21/2022 Actuaries
## 7   7   Irene  722,5  7/30/2022 Actuaries
## 8   8   Kefas  632,8  6/17/2022        CA
## 9   9  Sherly  632,8  7/30/2022        DE
## 10 10   Bakti   <NA>   9/3/2018  Lecturer
df6<-source('input/input6.Rdmpd')
df6
## $value
##    id    name salary start_date      dept
## 1   1  Julian  623,3   1/1/2022        DS
## 2   2 Vanessa  515,2  9/23/2022        DS
## 3   3  Jeffry    611 11/15/2022        BA
## 4   4   Angel    729  5/11/2022        DA
## 5   5   Nikki 843,25  3/27/2022        DS
## 6   6  Ardifo    578  5/21/2022 Actuaries
## 7   7   Irene  722,5  7/30/2022 Actuaries
## 8   8   Kefas  632,8  6/17/2022        CA
## 9   9  Sherly  632,8  7/30/2022        DE
## 10 10   Bakti   <NA>   9/3/2018  Lecturer
## 
## $visible
## [1] FALSE
df7<-readRDS('input/input7.rds')
df7
##    id    name salary start_date      dept
## 1   1  Julian  623,3   1/1/2022        DS
## 2   2 Vanessa  515,2  9/23/2022        DS
## 3   3  Jeffry    611 11/15/2022        BA
## 4   4   Angel    729  5/11/2022        DA
## 5   5   Nikki 843,25  3/27/2022        DS
## 6   6  Ardifo    578  5/21/2022 Actuaries
## 7   7   Irene  722,5  7/30/2022 Actuaries
## 8   8   Kefas  632,8  6/17/2022        CA
## 9   9  Sherly  632,8  7/30/2022        DE
## 10 10   Bakti   <NA>   9/3/2018  Lecturer
df8<-readRDS('input/input8.ascii')
df8
## # A tibble: 14 x 5
##       id name    salary start_date dept     
##    <dbl> <chr>   <chr>  <chr>      <chr>    
##  1     1 Julian  623    44562      DS       
##  2     2 Vanessa 515    44827      DS       
##  3     3 Jeffry  611    44880      BA       
##  4     4 Angel   729    44692      DA       
##  5     5 Nikki   843.25 44647      DS       
##  6     6 Ardifo  578    44702      Actuaries
##  7     7 Irene   722.5  44772      Actuaries
##  8     8 Kefas   632.79 44729      CA       
##  9     9 Sherly  632.79 44772      DE       
## 10    10 Bakti   NA     43346      Lecturer 
## 11    11 Ardifo  632.79 44711      DA       
## 12    12 Siana   632.79 2/30/2022  BA       
## 13    13 Fallen  632.79 44742      DS       
## 14    14 Lala    632.79 44650      BA

Ekspor Data

write.table(df5,'output/output5.txt')
dump('df6','output/output6.Rdmpd')
saveRDS(df7,'output/output7.rds')
saveRDS(df8,'output/output8.ascii',ascii=TRUE)

Impor / ekspor XML

XML adalah kumpulan berbagai format file dan data di World Wide Web, internet, dan di tempat lain menggunakan teks ASCII standar. XML merupakan singkatan dari eXtensible Markup Language yang berfungsi untuk menyederhanakan proses penyimpanan dan pengiriman data antarserver. XML dan HTML sangat mirip, sintaks nya berisi markup. Akan tetapi, fungsi utama XML adalah untuk menyimpan dan mengirimkan data. Sedangkan fungsi utama HTML adalah untuk menampilkan data. Untuk melakukan impor/ekspor dengan format XML perlu untuk menginstal packages XML, kulife, dan methods.

pacman::p_load(XML,kulife,methods)        # Load packages

Impor data dan Ekspor data

df9<-xmlParse('input/input9.xml')          # Impor data XML

xml_df<-xmlToDataFrame(df9)                # Konversi dataframe
xml_df
##    id    name salary start_date      dept
## 1   1  Julian  623.3   1/1/2022        DS
## 2   2 Vanessa  515.2  9/23/2022        DS
## 3   3  Jeffry    611 11/15/2022        BA
## 4   4   Angel    729  5/11/2022        BA
## 5   5   Nikki 843.25  3/27/2022        DS
## 6   6  Ardifo    578  5/21/2022 Actuaries
## 7   7   Irene  722.5  7/30/2022 Actuaries
## 8   8   Kefas  632.8  6/17/2022        CA
## 9   9  Sherly  632.8  7/30/2022        DE
## 10 10   Bakti     NA  9/03/2018  Lecturer
write.xml(xml_df,'output/output9.xml')     # Ekspor data XML

Impor / ekspor JSON

JavaScript Object Notation atau JSON adalah format yang digunakan untuk menyimpan dan mentransfer data. Untuk melakukan impor/ekspor file JSON perlu untuk menginstal packages jsonlite.

pacman::p_load(jsonlite)                  # Load packages

Impor data dan Ekspor data

df10<-fromJSON('input/input10.json')          # Impor data JSON

json_df<-as.data.frame(df10)                # Konversi dataframe
json_df
##    id    name salary start_date      dept
## 1   1  Julian  623.3   1/1/2022        DS
## 2   2 Vanessa  515.2  9/23/2022        DS
## 3   3  Jeffry    611 11/15/2022        BA
## 4   4   Angel    729  5/11/2022        DA
## 5   5   Nikki 843.25  3/27/2022        DS
## 6   6  Ardifo    578  5/21/2022 Actuaries
## 7   7   Irene  722.5  7/30/2022 Actuaries
## 8   8   Kefas  632.8  6/17/2022        CA
## 9   9  Sherly  632.8  7/30/2022        DE
## 10 10   Bakti     NA   9/3/2018  Lecturer
write_json(json_df,'output/output10.json')     # Ekspor data JSON

Impor Data dari Web

Dengan program R, dapat dilakukan pengekstrakan data spesifik dari berbagai situs web secara terprogram.Berikut contoh mengimpor data dari web.

CSV

web_csv<-read.csv("https://github.com/Bakti-Siregar/dataset/raw/master/Bookdown-Data-Science-for-Beginners/csv1.csv")
web_csv
##    id    name salary start_date      dept
## 1   1  Julian  623,3   1/1/2022        DS
## 2   2 Vanessa  515,2  9/23/2022        DS
## 3   3  Jeffry    611 11/15/2022        BA
## 4   4   Angel    729  5/11/2022        DA
## 5   5   Nikki 843,25  3/27/2022        DS
## 6   6  Ardifo    578  5/21/2022 Actuaries
## 7   7   Irene  722,5  7/30/2022 Actuaries
## 8   8   Kefas  632,8  6/17/2022        CA
## 9   9  Sherly  632,8  7/30/2022        DE
## 10 10   Bakti   <NA>   9/3/2018  Lecturer

XLSX

Terlebih dahulu instal package rio untuk mengimpor data dari github

pacman::p_load(rio)       
install_formats()
## [1] TRUE
web_xlsx<-rio::import('https://github.com/Bakti-Siregar/dataset/blob/master/Bookdown-Data-Science-for-Beginners/xlsx1.xlsx?raw=true')
web_xlsx
##    id    name salary start_date      dept
## 1   1  Julian    623 2022-01-01        DS
## 2   2 Vanessa    515 2022-09-23        DS
## 3   3  Jeffry    611 2022-11-15        BA
## 4   4   Angel    729 2022-05-11        DA
## 5   5   Nikki 843.25 2022-03-27        DS
## 6   6  Ardifo    578 2022-05-21 Actuaries
## 7   7   Irene  722.5 2022-07-30 Actuaries
## 8   8   Kefas 632.79 2022-06-17        CA
## 9   9  Sherly 632.79 2022-07-30        DE
## 10 10   Bakti     NA 2018-09-03  Lecturer

Lainnya (TXT, RDS, ASCII, XML, JSON)

web_txt <- read.table     # TXT
web_rds <- readRDS        # RDS
web_ascii <- readRDS      # ASCII

web_xml<- xmlParse        # XML
xmlToDataFrame            # Konversi dataframe

web_json <- fromJSON      # JSON
as.data.frame             # Konversi dataframe

Basis Data R

Sistem basis data atau database adalah data relasional yang disimpan dalam format yang dinormalisasi/standar. Untuk melakukan perhitungan statistik dibutuhkan query SQL yang sangat canggih dan kompleks. Namun demikian, R dapat dengan mudah terhubung ke banyak database relasional seperti MySql, Oracle, dll. Setelah itu, biasanya basis data diubah menjadi dataframe. Setelah data tersedia di lingkungan R, kemudian dimanimulasi atau dianalisis lebih lanjut.

Menambang Data Web

Pengikisan data dari web atau webscraping data adalah proses menggunakan bot untuk mengekstrak konten dan data dari sebuah website. Tidak seperti screen scraping yang hanya menyalin pixcel yang ditampilkan pada layar. Webscraping mengekstrak koda HTML yang mendasarinya , yang pada dasarnya disimpan dalam sebuah data set. Web scraping sangat berguna dalam bisnis online, baik itu untuk riset pasar, riset kompetitor, atau mencari leads. Namun, manfaatnya lebih dari sekedar itu.Kemudian, data tersebut disimpan dalam sebuah spreadsheet. Webscraping data dapat mereplikasi seluruh kontan dari berbagai situs web yang ditarget.

LS0tDQp0aXRsZTogIkFMR09SSVRNQSBEQU4gU1RSVUtUVVIgREFUQSINCnN1YnRpdGxlOiAiflR1Z2FzIDUgLSBBbnRhcm11a2EgRGF0YSBkZW5hZyBSIH4iDQphdXRob3I6ICJFdmVsaW4gVHJpZW5hIFMgKDIwMjE0NTIwMDEwKSINCmRhdGU6ICJgciBmb3JtYXQoU3lzLkRhdGUoKSwgJyVCICVkLCAlWScpYCINCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIGh0bWxfZG9jdW1lbnQ6IG51bGwNCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiBubw0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHRoZW1lOiBzYW5kc3RvbmUNCiAgICBjc3M6IHN0eWxlLmNzcw0KICAgIGhpZ2hsaWdodDogbW9ub2Nocm9tZQ0KDQotLS0NCg0KPGJyPg0KDQo8aW1nIHN0eWxlPSJmbG9hdDogcmlnaHQ7IG1hcmdpbjogLTUwcHggNTBweCAwcHggNTBweDsgd2lkdGg6MjUlIiBzcmM9InZlbmEuanBnIi8+IA0KDQp8DQo6LS0tLSB8Oi0tLS0NCioqS29udGFrKip8ICoqOiAkXGRvd25hcnJvdyQqKg0KRW1haWx8IGV2ZWxpbi5zYW1hbGl3dUBzdHVkZW50Lm1hdGFuYXVuaXZlcnNpdHkuYWMuaWQNClJQdWJzICB8IGh0dHBzOi8vcnB1YnMuY29tL2V2ZWxpbnRyaXZlbmEvIA0KSnVydXNhbiB8IEZpc2lrYSBNZWRpcyANCg0KKioqDQoNCiMgUGVuZGFodWx1YW4NClIgYWRhbGFoIGJhaGFzYSBwZW1yb2dyYW1hbiB5YW5nIGJhbnlhayBkaWd1bmFrYW4gdW50dWsgYW5hbGlzaXMgc3RhdGlzdGlrLiBNZW5naHVidW5na2FuIGRlbmdhbiBkYXRhIG1lcnVwYWthbiBoYWwgeWFuZyBwYWxpbmcgbWVuZGFzYXIgZGFsYW0gcGVuZ29sYWhhbiBkYXRhLiBCZXJpa3V0IGFkYWxhaCBjYXJhIG1lbmdndW5ha2FuIGJhaGFzYSBwZW1yb2dyYW1hbiBSIGRhbGFtIHByb3NlcyBhbnRhcm11a2EgZGF0YSB5YW5nIHNhbmdhdCBzZWRlcmhhbmEuIFNlY2FyYSBnYXJpcyBiZXNhciwgUiBkYXBhdCBtZW1iYWNhIGRhdGEgZGFyaSBmaWxlIHlhbmcgdGVyc2ltcGFuIGRpIGRhbGFtIGRhbiBkaSBsdWFyIGRpcmVrdG9yaW55YS4gVGlkYWsgaGFueWEgaXR1LCBzaXN0ZW0gb3BlcmFzaSBSIGp1Z2EgZGFwYXQgbWVuZ2ltcG9yIGRhbiBtZW5nZWtzcG9yIGRhdGEgZGFsYW0gYmVyYmFnYWkgZm9ybWF0IGZpbGUsIHNlcGVydGkgY3N2LCBleGNlbCwgdHh0LCByZHMsIHhtbCwganNvbiwgZGxsLg0KDQo8aW1nIHN0eWxlPSJmbG9hdDogcmlnaHQ7IG1hcmdpbjogMHB4IDBweCAwcHggMHB4OyB3aWR0aDoxMDAlIiBzcmM9ImFudGFybXVrYS5wbmciLz4NCg0KIyBJbXBvciAvIGVrc3BvciBDU1Ygey50YWJzZXQgLnRhYnNldC1waWxsc30NCkFkYSBiZWJlcmFwYSBjYXJhIHlhbmcgYmlzYSBkaWd1bmFrYW4gdW50dWsgbWVsYWt1a2FuIGltcG9yIGRhbiBla3Nwb3IgZGF0YSBkZW5nYW4gbWVuZ2d1bmFrYW4gUi4gQmVyaWt1dCBpbmksIDMgY2FyYSB5YW5nIGRhcGF0IGRpbGFrdWthbiA6DQoNCiMjIENhcmEgMQ0KUGVydGFtYSwgcGFzdGlrYW4gd29ya2luZyBkaXJlY3Rvcnkgc3VkYWggdGVwYXQuIHVudHVrIG1lbmRhcGF0a2FuIGluZm9ybWFzaSB3b3JraW5nIGRpcmVjdG9yeSAvIGxva2FzaW55YSBkYXBhdCBtZW5ndW5ha2FuIGZ1bmdzaSBgZ2V0d2QoKWANCg0KYGBge3J9DQpwcmludChnZXR3ZCgpKQ0KZ2V0d2QoKQ0KYGBgDQoNClVudHVrIG1lbmd1YmFoIC8gbWVuZ2F0dXIgd29ya2luZyBkaXJlY3RvcnkgYmFydSBkYXBhdCBtZW5nZ3VuYWthbiBmdW5nc2kgYHNldHdkKClgDQoNCmBgYHtyfQ0Kc2V0d2QoZ2V0d2QoKSkNCmBgYA0KDQogKiBJbXBvciBkYXRhIENTViBkZW5nYW4gZnVuZ3NpIGByZWFkLmNzdigpYA0KDQpgYGB7cn0NCmRmMSA8LSByZWFkLmNzdigiaW5wdXQvaW5wdXQxLmNzdiIsIHNlcD0iLCIpDQpkZjENCmRmMiA8LSByZWFkLmNzdigiaW5wdXQvaW5wdXQyLmNzdiIsIHNlcD0iOyIpDQpkZjINCmBgYA0KDQogKiBFa3Nwb3IgZGF0YSBDU1YgZGVuZ2FuIGZ1bmdzaSBgd3JpdGUuY3N2KClgDQpFa3Nwb3IgZGF0YSAobWVueWltcGFuIGRhdGEpIGNzdiBrZSBkaXJlY3RvcnkgeWFuZyBkaWluZ2lua2FuIGRhcGEgbWVuZ2d1bmFrYW4gZnVuZ3NpIGB3cml0ZS5jc3YoKWAgdW50dWsgZmlsZSB5YW5nIG1lbmdndW5ha2FuIHNpbWJvbCBrb21hKCwpIHNlYmFnYWkgZGVsaW1pdGVybnlhLCBkYW4gbWVuZ2d1bmFrYW4gZnVuZ3NpIGB3cml0ZS5jc3YyKClgIHVudHVrIGZpbGUgY3N2IHlhbmcgbWVuZ2d1bmFrYW4gdGl0aWsga29tYSAoOykgc2ViYWdhaSBkZWxpbWl0ZXJueWEuIA0KDQpgYGB7cn0NCndyaXRlLmNzdihkZjEsIm91dHB1dC90ZXN0MS5jc3YiLCByb3cubmFtZXM9RkFMU0UpDQp3cml0ZS5jc3YoZGYyLCJvdXRwdXQvdGVzdDIuY3N2Iiwgcm93Lm5hbWVzPUZBTFNFKQ0KYGBgDQoNCiMjIENhcmEgMg0KS29uZWtzaSBkaXJlY3Rvcnkgc2VjYXJhIGF1dG9tYXRpcywgZGFwYXQgZGlsYWt1a2FuIGRlbmdhbiBjYXJhIGJlcmlrdXQuDQoNCmBgYHtyfQ0KIyBzZXR0aW5nIGRpcmVjdG9yeQ0KKHN3ZDwtZ2V0d2QoKSkNCmlmICghaXMubnVsbChzd2QpKSBzZXR3ZChzd2QpDQpgYGANCiAqIEltcG9yIGRhdGEgQ1NWDQoNCmBgYHtyfQ0KZGYxPC1yZWFkLmNzdihmaWxlLnBhdGgoc3dkLCdpbnB1dCcsICdpbnB1dDEuY3N2JykpDQpkZjENCmRmMjwtcmVhZC5jc3YoZmlsZS5wYXRoKHN3ZCwnaW5wdXQnLCAnaW5wdXQyLmNzdicpKQ0KZGYyDQpgYGANCg0KICogRWtzcG9yIGRhdGEgQ1NWDQoNCmBgYHtyfQ0Kd3JpdGUuY3N2KGRmMSwgZmlsZS5wYXRoKHN3ZCwgJ291dHB1dCcsICdvdXRwdXQxLmNzdicpLCByb3cubmFtZXMgPSBGQUxTRSkNCndyaXRlLmNzdihkZjIsIGZpbGUucGF0aChzd2QsICdvdXRwdXQnLCAnb3V0cHV0Mi5jc3YnKSwgcm93Lm5hbWVzID0gRkFMU0UpDQpgYGANCg0KIyMgQ2FyYSAzDQpDYXJhIGluaSBtZXJ1cGFrYW4gbGFuZ2thaCBhbHRlcm5hdGlmLCB1bnR1ayBkYXBhdCBtZW5naW1wb3IgZGFuIG1lbmdla3Nwb3IgZGF0YSBjc3YgZGVuZ2FuIG1lbWlsaWggZGF0YSB5YW5nIGRpc2ltcGFuIHRhbnBhIG1lbmdhdHVyIGRpcmVrdG9yaSB0ZXJsZWJpaCBkYWh1bHUuIEZ1bmdzaSB5YW5nIGRpZ3VuYWthbiBhZGFsYWggYGZpbGUuY2hvb3NlKClgDQoNCmBgYHtyfQ0KZGY8LXJlYWQuY3N2KGZpbGUuY2hvb3NlKCkpDQpkZg0KYGBgDQoNCiMgSW1wb3IvZWtzcG9yIEV4Y2VsIHsudGFic2V0IC50YWJzZXQtcGlsbHN9DQpNaWNyb3NvZnQgRXhjZWwgbWVydXBha2FuIHByb2dyYW0gc3ByZWFkc2hlZXQgeWFuZyBwYWxpbmcgYmFueWFrIGRpZ3VuYWthbiB1bnR1ayBtZW55aW1wYW4gZGF0YSBkYWxhbSBiZW50dWsgYC54bHNgIGF0YXUgYC54bHN4YCAuIFIgZGFwYXQgbWVuZ2d1bmFrYW4gcGFja2FnZXMgYHJlYWR4bGAgZGFuIGB3cml0ZXhsYCB1bnR1ayBtZW1iYWNhIGxhbmdzdW5nIGRhcmkgZmlsZS1maWxlIGluaS4gDQogICAgICAgICAgICAgICAgIA0KYGBge3J9DQojIGluc3RhbGwucGFja2FnZXMoYygicmVhZHhsIiwgIndyaXRleGwiKSkgICAjIGluc3RhbGwgYHJlYWR4bCAmIHdyaXRleGxgIA0KcGFjbWFuOjpwX2xvYWQocmVhZHhsLCB3cml0ZXhsKSAgICAgICAgICAgICAgIyBsb2FkIGByZWFkeGwgJiB3cml0ZXhsYA0KYGBgDQoNCiMjIEltcG9yIERhdGENCmBgYHtyfQ0KZGYzPC1yZWFkX2V4Y2VsKCJJbnB1dC9pbnB1dDQueGxzIikgICAgICAgICAgIyBpbXBvciBkYXRhIHhscyAoOTctMjAwMykNCmRmMw0KZGY0PC1yZWFkX2V4Y2VsKCJJbnB1dC9pbnB1dDMueGxzeCIsc2hlZXQ9MSkgIyBpbXBvciBkYXRhIHhsc3ggKDIwMDMtdXApDQpkZjQNCmBgYA0KDQojIyBFa3Nwb3IgRGF0YQ0KYGBge3J9DQp3cml0ZV94bHN4KGRmMywib3V0cHV0L291dHB1dDMueGxzIikgDQp3cml0ZV94bHN4KGRmNCwib3V0cHV0L291dHB1dDQueGxzeCIpDQpgYGANCg0KIyBJbXBvciAvIGVrc3BvciBUWFQgZGFuIFJEUyB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KRm9ybWF0IGRhdGEgaW5pIGJhbnlhayBkaWd1bmFrYW4gdW50dWsgZmlsZS9kYXRhIHlhbmcgbGViaWggYmVzYXIuIERhbGFtIGZvcm1hdCBDU1YgZGFuIEV4Y2VsIHVrdXJhbiBmaWxlbnlhIGNlbmRlcnVuZyBsZWJpaCBiZXNhciBkaWJhbmRpbmdrYW4gZm9ybWF0IFRYVCBhdGF1IGZpbGUgYmluZXIgUiAoUkRTKS4gU2VoaW5nZ2EgZGF0YSBkYWxhbSBmb3JtYXQgQ1NWIGF0YXUgRXhjZWwgYWthbiBkaWNvbXByZXNzIG1lbmphZGkgVFhUIGF0YXUgUkRTLiANCg0KIyMgSW1wb3IgZGF0YQ0KDQpgYGB7cn0NCmRmNTwtcmVhZC50YWJsZSgnaW5wdXQvaW5wdXQ1LnR4dCcpDQpkZjUNCmRmNjwtc291cmNlKCdpbnB1dC9pbnB1dDYuUmRtcGQnKQ0KZGY2DQpkZjc8LXJlYWRSRFMoJ2lucHV0L2lucHV0Ny5yZHMnKQ0KZGY3DQpkZjg8LXJlYWRSRFMoJ2lucHV0L2lucHV0OC5hc2NpaScpDQpkZjgNCmBgYA0KDQojIyBFa3Nwb3IgRGF0YQ0KDQpgYGB7cn0NCndyaXRlLnRhYmxlKGRmNSwnb3V0cHV0L291dHB1dDUudHh0JykNCmR1bXAoJ2RmNicsJ291dHB1dC9vdXRwdXQ2LlJkbXBkJykNCnNhdmVSRFMoZGY3LCdvdXRwdXQvb3V0cHV0Ny5yZHMnKQ0Kc2F2ZVJEUyhkZjgsJ291dHB1dC9vdXRwdXQ4LmFzY2lpJyxhc2NpaT1UUlVFKQ0KYGBgDQoNCiMgSW1wb3IgLyBla3Nwb3IgWE1MIA0KWE1MIGFkYWxhaCBrdW1wdWxhbiBiZXJiYWdhaSBmb3JtYXQgZmlsZSBkYW4gZGF0YSBkaSBXb3JsZCBXaWRlIFdlYiwgaW50ZXJuZXQsIGRhbiBkaSB0ZW1wYXQgbGFpbiBtZW5nZ3VuYWthbiB0ZWtzIEFTQ0lJIHN0YW5kYXIuIFhNTCBtZXJ1cGFrYW4gc2luZ2thdGFuIGRhcmkgZVh0ZW5zaWJsZSBNYXJrdXAgTGFuZ3VhZ2UgeWFuZyBiZXJmdW5nc2kgdW50dWsgbWVueWVkZXJoYW5ha2FuIHByb3NlcyBwZW55aW1wYW5hbiBkYW4gcGVuZ2lyaW1hbiBkYXRhIGFudGFyc2VydmVyLiBYTUwgZGFuIEhUTUwgc2FuZ2F0IG1pcmlwLCBzaW50YWtzIG55YSBiZXJpc2kgbWFya3VwLiBBa2FuIHRldGFwaSwgZnVuZ3NpIHV0YW1hIFhNTCBhZGFsYWggdW50dWsgbWVueWltcGFuIGRhbiBtZW5naXJpbWthbiBkYXRhLiBTZWRhbmdrYW4gZnVuZ3NpIHV0YW1hIEhUTUwgYWRhbGFoIHVudHVrIG1lbmFtcGlsa2FuIGRhdGEuIFVudHVrIG1lbGFrdWthbiBpbXBvci9la3Nwb3IgZGVuZ2FuIGZvcm1hdCBYTUwgcGVybHUgdW50dWsgbWVuZ2luc3RhbCBwYWNrYWdlcyBgWE1MYCwgYGt1bGlmZWAsIGRhbiBgbWV0aG9kc2AuDQoNCmBgYHtyfQ0KcGFjbWFuOjpwX2xvYWQoWE1MLGt1bGlmZSxtZXRob2RzKSAgICAgICAgIyBMb2FkIHBhY2thZ2VzDQpgYGANCiMjIEltcG9yIGRhdGEgZGFuIEVrc3BvciBkYXRhDQoNCmBgYHtyfQ0KZGY5PC14bWxQYXJzZSgnaW5wdXQvaW5wdXQ5LnhtbCcpICAgICAgICAgICMgSW1wb3IgZGF0YSBYTUwNCg0KeG1sX2RmPC14bWxUb0RhdGFGcmFtZShkZjkpICAgICAgICAgICAgICAgICMgS29udmVyc2kgZGF0YWZyYW1lDQp4bWxfZGYNCg0Kd3JpdGUueG1sKHhtbF9kZiwnb3V0cHV0L291dHB1dDkueG1sJykgICAgICMgRWtzcG9yIGRhdGEgWE1MDQpgYGANCg0KIyBJbXBvciAvIGVrc3BvciBKU09ODQpKYXZhU2NyaXB0IE9iamVjdCBOb3RhdGlvbiBhdGF1IEpTT04gYWRhbGFoIGZvcm1hdCB5YW5nIGRpZ3VuYWthbiB1bnR1ayBtZW55aW1wYW4gZGFuIG1lbnRyYW5zZmVyIGRhdGEuIFVudHVrIG1lbGFrdWthbiBpbXBvci9la3Nwb3IgZmlsZSBKU09OIHBlcmx1IHVudHVrIG1lbmdpbnN0YWwgcGFja2FnZXMgYGpzb25saXRlYC4gDQoNCmBgYHtyfQ0KcGFjbWFuOjpwX2xvYWQoanNvbmxpdGUpICAgICAgICAgICAgICAgICAgIyBMb2FkIHBhY2thZ2VzDQpgYGANCg0KIyMgSW1wb3IgZGF0YSBkYW4gRWtzcG9yIGRhdGENCg0KYGBge3J9DQpkZjEwPC1mcm9tSlNPTignaW5wdXQvaW5wdXQxMC5qc29uJykgICAgICAgICAgIyBJbXBvciBkYXRhIEpTT04NCg0KanNvbl9kZjwtYXMuZGF0YS5mcmFtZShkZjEwKSAgICAgICAgICAgICAgICAjIEtvbnZlcnNpIGRhdGFmcmFtZQ0KanNvbl9kZg0KDQp3cml0ZV9qc29uKGpzb25fZGYsJ291dHB1dC9vdXRwdXQxMC5qc29uJykgICAgICMgRWtzcG9yIGRhdGEgSlNPTg0KYGBgDQoNCiMgSW1wb3IgRGF0YSBkYXJpIFdlYg0KRGVuZ2FuIHByb2dyYW0gUiwgZGFwYXQgZGlsYWt1a2FuIHBlbmdla3N0cmFrYW4gZGF0YSBzcGVzaWZpayBkYXJpIGJlcmJhZ2FpIHNpdHVzIHdlYiBzZWNhcmEgdGVycHJvZ3JhbS5CZXJpa3V0IGNvbnRvaCBtZW5naW1wb3IgZGF0YSBkYXJpIHdlYi4NCg0KIyMgQ1NWDQpgYGB7cn0NCndlYl9jc3Y8LXJlYWQuY3N2KCJodHRwczovL2dpdGh1Yi5jb20vQmFrdGktU2lyZWdhci9kYXRhc2V0L3Jhdy9tYXN0ZXIvQm9va2Rvd24tRGF0YS1TY2llbmNlLWZvci1CZWdpbm5lcnMvY3N2MS5jc3YiKQ0Kd2ViX2Nzdg0KYGBgDQojIyBYTFNYDQpUZXJsZWJpaCBkYWh1bHUgaW5zdGFsIHBhY2thZ2UgYHJpb2AgdW50dWsgbWVuZ2ltcG9yIGRhdGEgZGFyaSBnaXRodWINCmBgYHtyfQ0KcGFjbWFuOjpwX2xvYWQocmlvKSAgICAgICANCmluc3RhbGxfZm9ybWF0cygpDQpgYGANCg0KYGBge3J9DQp3ZWJfeGxzeDwtcmlvOjppbXBvcnQoJ2h0dHBzOi8vZ2l0aHViLmNvbS9CYWt0aS1TaXJlZ2FyL2RhdGFzZXQvYmxvYi9tYXN0ZXIvQm9va2Rvd24tRGF0YS1TY2llbmNlLWZvci1CZWdpbm5lcnMveGxzeDEueGxzeD9yYXc9dHJ1ZScpDQp3ZWJfeGxzeA0KYGBgDQoNCiMjIExhaW5ueWEgKFRYVCwgUkRTLCBBU0NJSSwgWE1MLCBKU09OKQ0KDQpgYGB7ciBlY2hvPVRSVUUsIHJlc3VsdHM9J2hpZGUnLG1lc3NhZ2U9RkFMU0V9DQp3ZWJfdHh0IDwtIHJlYWQudGFibGUgICAgICMgVFhUDQp3ZWJfcmRzIDwtIHJlYWRSRFMgICAgICAgICMgUkRTDQp3ZWJfYXNjaWkgPC0gcmVhZFJEUyAgICAgICMgQVNDSUkNCg0Kd2ViX3htbDwtIHhtbFBhcnNlICAgICAgICAjIFhNTA0KeG1sVG9EYXRhRnJhbWUgICAgICAgICAgICAjIEtvbnZlcnNpIGRhdGFmcmFtZQ0KDQp3ZWJfanNvbiA8LSBmcm9tSlNPTiAgICAgICMgSlNPTg0KYXMuZGF0YS5mcmFtZSAgICAgICAgICAgICAjIEtvbnZlcnNpIGRhdGFmcmFtZQ0KYGBgDQoNCiMgQmFzaXMgRGF0YSBSDQoNClNpc3RlbSBiYXNpcyBkYXRhIGF0YXUgZGF0YWJhc2UgYWRhbGFoIGRhdGEgcmVsYXNpb25hbCB5YW5nIGRpc2ltcGFuIGRhbGFtIGZvcm1hdCB5YW5nIGRpbm9ybWFsaXNhc2kvc3RhbmRhci4gVW50dWsgbWVsYWt1a2FuIHBlcmhpdHVuZ2FuIHN0YXRpc3RpayBkaWJ1dHVoa2FuIHF1ZXJ5IFNRTCB5YW5nIHNhbmdhdCBjYW5nZ2loIGRhbiBrb21wbGVrcy4gTmFtdW4gZGVtaWtpYW4sIFIgZGFwYXQgZGVuZ2FuIG11ZGFoIHRlcmh1YnVuZyBrZSBiYW55YWsgZGF0YWJhc2UgcmVsYXNpb25hbCBzZXBlcnRpIE15U3FsLCBPcmFjbGUsIGRsbC4gU2V0ZWxhaCBpdHUsIGJpYXNhbnlhIGJhc2lzIGRhdGEgZGl1YmFoIG1lbmphZGkgZGF0YWZyYW1lLiBTZXRlbGFoIGRhdGEgdGVyc2VkaWEgZGkgbGluZ2t1bmdhbiBSLCBrZW11ZGlhbiBkaW1hbmltdWxhc2kgYXRhdSBkaWFuYWxpc2lzIGxlYmloIGxhbmp1dC4gDQoNCiMgTWVuYW1iYW5nIERhdGEgV2ViDQoNClBlbmdpa2lzYW4gZGF0YSBkYXJpIHdlYiBhdGF1IGB3ZWJzY3JhcGluZyBkYXRhYCBhZGFsYWggcHJvc2VzIG1lbmdndW5ha2FuIGJvdCB1bnR1ayBtZW5nZWtzdHJhayBrb250ZW4gZGFuIGRhdGEgZGFyaSBzZWJ1YWggd2Vic2l0ZS4gVGlkYWsgc2VwZXJ0aSBzY3JlZW4gc2NyYXBpbmcgeWFuZyBoYW55YSBtZW55YWxpbiBwaXhjZWwgeWFuZyBkaXRhbXBpbGthbiBwYWRhIGxheWFyLiBXZWJzY3JhcGluZyBtZW5nZWtzdHJhayBrb2RhIEhUTUwgeWFuZyBtZW5kYXNhcmlueWEgLCB5YW5nIHBhZGEgZGFzYXJueWEgZGlzaW1wYW4gZGFsYW0gc2VidWFoIGRhdGEgc2V0LiBXZWIgc2NyYXBpbmcgc2FuZ2F0IGJlcmd1bmEgZGFsYW0gYmlzbmlzIG9ubGluZSwgYmFpayBpdHUgdW50dWsgcmlzZXQgcGFzYXIsIHJpc2V0IGtvbXBldGl0b3IsIGF0YXUgbWVuY2FyaSBsZWFkcy4gTmFtdW4sIG1hbmZhYXRueWEgbGViaWggZGFyaSBzZWtlZGFyIGl0dS5LZW11ZGlhbiwgZGF0YSB0ZXJzZWJ1dCBkaXNpbXBhbiBkYWxhbSBzZWJ1YWggc3ByZWFkc2hlZXQuIFdlYnNjcmFwaW5nIGRhdGEgZGFwYXQgbWVyZXBsaWthc2kgc2VsdXJ1aCBrb250YW4gZGFyaSBiZXJiYWdhaSBzaXR1cyB3ZWIgeWFuZyBkaXRhcmdldC4NCg0KIyBSZWZlcmVuc2kNCjEuIGh0dHBzOi8vcnB1YnMuY29tL2RzY2llbmNlbGFicy9hc2QxMA0KMi4gaHR0cHM6Ly9ib29rZG93bi5vcmcvQmFrdGlTaXJlZ2FyL2RhdGEtc2NpZW5jZS1mb3ItYmVnaW5uZXJzLw0KNC4gaHR0cHM6Ly93d3cubmlhZ2Fob3N0ZXIuY28uaWQvYmxvZy93ZWItc2NyYXBpbmcvDQoNCg==