0. Apa itu R

R adalah bahasa pemrograman yang umumnya digunakan untuk analisis data. R populer digunakan oleh profesional di data science, business analytics, atau di bidang penelitian akademik. R bersifat open source, dan terdapat berbagai komunitas pengembang yang memperbarui R dengan berbagai package dengan fungsi yang beragam.

Mengapa menggunakan R daripada SPSS?

  • R bersifat gratis, tidak perlu menghabiskan uang atau khawatir dengan software bajakan
  • R bersifat open source. Artinya, R memiliki banyak package yang kemungkinan bisa menyelesaikan problem apapun yang Anda temui.
  • Troubleshooting lebih mudah. Karena gratis dan banyak dipakai, permasalahan yang Anda temui kemungkinan besar pernah dibahas di stackoverflow atau situs lain. Karena itu, umumnya lebih mudah untuk mencari solusi di R dibanding SPSS.
  • Cukup mudah dipelajari. Karena penggunanya banyak ada banyak sekali resource gratis yang dapat digunakan untuk mencoba mempelajari R. Selain itu, proses set-up dan maintenance yang sederhana membuat barrier to entry ke R tidak terlalu tinggi. Secara logika bahasa, R juga relatif lebih mudah dipahami.

Apa yang akan dipelajari hari ini?

Tujuan dari sesi hari ini adalah mengenal building block paling dasar dari penggunaan R: variabel. Memahami jenis, operasi, dan cara untuk menavigasi variabel di R adalah prasyarat dari menggunakan R untuk hal lain yang lebih kompleks, seperti memanipulasi tabel-tabel, membersihkan data, dan menggunakan function.

Topik yang akan dibahas:

Catatan: Sumber utama tutorial adalah buku Danielle Navarro: Learning Statistics with R (https://learningstatisticswithr.com/)

1. Jenis-jenis variabel

Umumnya R memiliki 3 jenis variabel: Numeric, Character, dan Logical. Sepanjang kita menggunakan R, kita mostly akan menggunakan tiga variabel ini.

  1. Numeric

Variabel angka. Angka-angka yang termasuk di dalam variabel ini adalah angka rasional, yang bisa bersifat negatif, integer, maupun desimal.

1
[1] 1
class(1)
[1] "numeric"
  1. Character

Variabel berbentuk teks, yang adapat terdiri dari elemen alfabetik, numerik, maupun simbol. Seringkali juga disebut dengan ‘string’. Ditandai dengan tanda kutip di antara teks tersebut(“” atau ’’).

"halo"
[1] "halo"
class("halo") 
[1] "character"
  1. Logical

Variabel berbentuk pernyataan TRUE atau FALSE. Variabel ini dibentuk dari komparasi nilai menggunakan operator-operator relasi.

2+2 == 4
[1] TRUE
class(2+2 == 4)
[1] "logical"

Berikut adalah tabel operator yang digunakan untuk membuat variabel logical:

Operator Deskripsi
< Kurang dari
> Lebih dari
== Sama dengan
!= Tidak sama dengan
>= Lebih dari atau sama dengan
<= Kurang dari atau sama dengan

2. Operasi dengan numeric variables

Salah satu hal yang paling mendasar yang bisa dilakukan di R adalah menggunakan program ini sebagai kalkulator.


# Penjumlahan
1 + 1
[1] 2
# Pengurangan  
2 - 1
[1] 1
  # Perkalian
3 * 2
[1] 6
  # Pembagian
3/2
[1] 1.5
  # Pangkat
5 ** 2
[1] 25
5 ^ 2
[1] 25
  # Akar (menggunakan operasi pangkat)
9 ** 0.5
[1] 3

Kalkulasi di dalam R menggunakan prinsip BEDMAS, yang menunjukkan urutan kalkulasi dalam rumus yang memiliki lebih dari satu jenis kalkulasi.

Urutan BEDMAS: Brackets (), Exponents ** atau ^, Division /, Multiplication *, Addition +, lalu Subtraction -.

5**2+2*(5-2)
[1] 31

Beberapa kalkulasi dapat dilakukan menggunakan fungsi.Hal ini akan dibahas lebih lanjut di diskusi tentang summary statistics pada pertemuan kedua.

sqrt(9)
[1] 3

3. Operasi Variabel

Variabel-variabel seperti yang kita telah buat di atas dapat disimpan sebagai sebuah objek. Objek dibuat dengan memberikan tanda panah <-, yang akan menandai suatu nilai sebagai objek tersebut mengeksekusi objek akan memunculkan nilainya.

 # objek numeric
bulan_numeric <- 2
bulan_numeric
[1] 2
  # objek character
bulan_char <- "Februari"
bulan_char
[1] "Februari"
  # objek logical
bulan_logic <- bulan_char == "Februari"
bulan_logic
[1] TRUE

Satu object bisa memiliki satu nilai saja. Jika nilai lain disimpan dengan nama objek yang sama maka nilai lama akan terhapus dan digantikan dengan nilai yang baru disimpan. Dengan kata lain, objek memiliki sifat ekslusif.

bulan_numeric
[1] 2
bulan_numeric <- 1
bulan_numeric
[1] 1

4. Vector

Walau suatu objek dapat menyimpan hanya satu nilai, elemen di dalam suatu objek dapat berbentuk deret, atau menyimpan lebih dari satu angka, teks, atau logic. Hal ini disebut sebagai vector.

  # vector berisi nilai numeric
month_num <- c(1, 2, 3)
sales_permonth <- c(150, 200, 125)

  # vector berisi nilai character
month_cha <- c("Januari", "Februari", "Maret")

  # vector berisi nilai logical
sales_underperform <- sales_permonth < 150

Khusus untuk vektor numerik, ada berbagai cara yang bisa kita lakukan untuk membuat deret angka. Pertama dengan tanda :

  # membuat deret dengan ":"
c(1:10)
 [1]  1  2  3  4  5  6  7  8  9 10
c(10:1) #Bisa dilakukan secara terbalik
 [1] 10  9  8  7  6  5  4  3  2  1

Dan, jika kita ingin membuat deret yang memiliki interval tertentu, bisa dengan menggunakan fungsi seq()

seq(from=1, to=10, by=3)
[1]  1  4  7 10

Karena bentuknya adalah deret, elemen di dalam vector memiliki urutan. Urutan atau indeks ini adalah hal yang bisa digunakan untuk memanipulasi atau memanggil suatu elemen di dalam vector secara spesifik.

  # Misalnya kita ingin mengambil elemen dengan urutan ke-3 saja di nama bulan di quartal 1
month_cha[3]
[1] "Maret"
  # Atau kita ingin mengambil nama bulan pertama dan ketiga
month_cha[c(1, 3)]
[1] "Januari" "Maret"  
  # Atau hanya dua bulan pertama
month_cha[c(1:2)]
[1] "Januari"  "Februari"

Fungsi indexing ini dapat digunakan untuk jenis vector apapun, bahkan untuk vector berisi data logical. Misalnya kita ingin tahu apakah sales di bulan Maret underperform dengan cara indexing:

sales_underperform[3]
[1] TRUE

5. Tabel dan dataframe

Setelah memahami apa itu vector, kita sekarang akan membahas tentang tabel. Pada dasarnya, tabel atau matrix adalah objek yang terdiri dari beberapa vector. Di bagian ini kita akan mencoba membuat tabel dari vector yang telah kita buat sebelumnya.

# Kita memiliki beberapa vector yang sama panjang (jumlah elemennya sama)
month_cha
[1] "Januari"  "Februari" "Maret"   
sales_permonth
[1] 150 200 125
sales_underperform
[1] FALSE FALSE  TRUE

Kita bisa memeriksa ukuran dari vector dengan menggunakan beberapa cara berikut

  # Melihat panjang vector spesifik
length(month_cha)
[1] 3
  # Melihat karakteristik seluruh vector di dalam environment
lsr::who()
   -- Name --           -- Class --   -- Size --
   bulan_char           character     1         
   bulan_logic          logical       1         
   bulan_numeric        numeric       1         
   month_cha            character     3         
   month_num            numeric       3         
   sales_permonth       numeric       3         
   sales_underperform   logical       3         

Karena ketiga vector di atas sama panjang, kita bisa membuat tabel dari vector-vector tersebut. Di dalam R suatu tabel umumnya disimpan dalam objek dengan tipe dataframe. Untuk membuat sebuah dataframe, kita gunakan fungsi data.frame().

df_salesq1 <- data.frame(month_cha, sales_permonth, sales_underperform)
df_salesq1

Kita bisa mengakses lagi tiap variabel yang sudah masuk di dalam dataframe menggunakan beberapa cara. Utamanya, memanggil nama dari variabel tersebut dan menggunakan indeks kolom.

  # menggunakan nama dari variabel
df_salesq1$sales_permonth
[1] 150 200 125
  # atau menggunakan indeks dari kolom (urutan kolom ke berapa variabel yang kita inginkan)
df_salesq1[, 2]
[1] 150 200 125

Menggunakan fungsi logic, kita juga bisa memanggil tabel dengan data yang kita inginkan berdasarkan kriteria tertentu.

  # Misalkan, kita ingin mengambil tabel untuk bulan Januari saja
df_salesq1[(df_salesq1$month_cha == "Januari"), ]

  # Atau kita ingin mengambil tabel yang tidak underperform
df_salesq1[(df_salesq1$sales_underperform == FALSE), ]

Sama seperti variabel, setelah kita melakukan slicing, kita bisa menyimpan tabel menjadi objek baru

  # Contoh, kita membuat tabel khusus untuk bulan yang tidak underperform
df_salesq1_nonunderperform <- df_salesq1[(df_salesq1$sales_underperform == FALSE), ]
df_salesq1_nonunderperform

6. Manipulasi dataframe dasar

Kita akan pelajari beberapa manipulasi dasar yang sering dilakukan di tabel.

Menambah kolom baru

Pertama, menambah kolom baru, yang dapat dilakukan menggunakan beberapa fungsi.

  • fungsi cbind: digunakan untuk melakukan merger dari dua vector, bisa untuk menambahkan kolom baru dari vektor yang ada. Di fungsi ini cukup masukan nama kedua tabel yang ingin digabungkan.

df_salesq1_merged <- cbind(df_salesq1, month_num)
df_salesq1_merged
  • Menggunakan $: kita bisa memaksakan kolom baru dengan langsung membuat kolom yang Mebelumnya tidak ada dan memberikan nilai untuk kolom tersebut. Kurang lebih,Metode ini seperti membuat sebuah vector di dalam kolom.
df_salesq1_merged$spendings <- c(160, 170, 150)
df_salesq1_merged

Menambah row

Sebelum demonstrasi, mari kita buat satu dataframe lain terlebih dahulu untuk nantinya ditambahkan ke tabel. Perlu diperhatikan bahwa dataframe baru ini perlu memiliki kolom-kolom yang sama dengan data yang ingin di-merge dengannya

df_salesq2to3 <- 
  data.frame(
    month_cha=c("April", "Mei", "Juni", "Juli", "Agustus", "September"), 
    sales_permonth=c(180, 210, 230, 200, 190, 240), 
    sales_underperform=c(FALSE, FALSE, FALSE, FALSE, FALSE, FALSE), 
    month_num=c(4, 5, 6, 7, 8, 9), 
    spendings=c(170, 180, 140, 140, 170, 150)
  )
df_salesq2to3

Sekarang kita bisa menambahkan tabel tersebut menggunakan fungsi rbind. Sama seperti cbind, cukup masukkan nama tabel yang ingin ditambahkan di dalam fungsi tersebut, lalu simpan dengan <-.

df_sales_merged <- rbind(df_salesq1_merged, df_salesq2to3)
df_sales_merged
LS0tDQp0aXRsZTogIjEuIFN0YXJ0aW5nIFIiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCmBgYA0KDQojIyAwLiBBcGEgaXR1IFINCg0KUiBhZGFsYWggYmFoYXNhIHBlbXJvZ3JhbWFuIHlhbmcgdW11bW55YSBkaWd1bmFrYW4gdW50dWsgYW5hbGlzaXMgZGF0YS4gUiBwb3B1bGVyIGRpZ3VuYWthbiBvbGVoIHByb2Zlc2lvbmFsIGRpIGRhdGEgc2NpZW5jZSwgYnVzaW5lc3MgYW5hbHl0aWNzLCBhdGF1IGRpIGJpZGFuZyBwZW5lbGl0aWFuIGFrYWRlbWlrLiBSIGJlcnNpZmF0IG9wZW4gc291cmNlLCBkYW4gdGVyZGFwYXQgYmVyYmFnYWkga29tdW5pdGFzIHBlbmdlbWJhbmcgeWFuZyBtZW1wZXJiYXJ1aSBSIGRlbmdhbiBiZXJiYWdhaSAqcGFja2FnZSogZGVuZ2FuIGZ1bmdzaSB5YW5nIGJlcmFnYW0uICANCg0KIyMjIE1lbmdhcGEgbWVuZ2d1bmFrYW4gUiBkYXJpcGFkYSBTUFNTPw0KLSAqKlIgYmVyc2lmYXQgZ3JhdGlzKiosIHRpZGFrIHBlcmx1IG1lbmdoYWJpc2thbiB1YW5nIGF0YXUga2hhd2F0aXIgZGVuZ2FuIHNvZnR3YXJlIGJhamFrYW4NCi0gKipSIGJlcnNpZmF0IG9wZW4gc291cmNlKiouIEFydGlueWEsIFIgbWVtaWxpa2kgYmFueWFrICpwYWNrYWdlKiB5YW5nIGtlbXVuZ2tpbmFuIGJpc2EgbWVueWVsZXNhaWthbiBwcm9ibGVtIGFwYXB1biB5YW5nIEFuZGEgdGVtdWkuIA0KLSAqKlRyb3VibGVzaG9vdGluZyBsZWJpaCBtdWRhaCoqLiBLYXJlbmEgZ3JhdGlzIGRhbiBiYW55YWsgZGlwYWthaSwgcGVybWFzYWxhaGFuIHlhbmcgQW5kYSB0ZW11aSBrZW11bmdraW5hbiBiZXNhciBwZXJuYWggZGliYWhhcyBkaSBzdGFja292ZXJmbG93IGF0YXUgc2l0dXMgbGFpbi4gS2FyZW5hIGl0dSwgdW11bW55YSBsZWJpaCBtdWRhaCB1bnR1ayBtZW5jYXJpIHNvbHVzaSBkaSBSIGRpYmFuZGluZyBTUFNTLg0KLSAqKkN1a3VwIG11ZGFoIGRpcGVsYWphcmkqKi4gS2FyZW5hIHBlbmdndW5hbnlhIGJhbnlhayBhZGEgYmFueWFrIHNla2FsaSByZXNvdXJjZSBncmF0aXMgeWFuZyBkYXBhdCBkaWd1bmFrYW4gdW50dWsgbWVuY29iYSBtZW1wZWxhamFyaSBSLiBTZWxhaW4gaXR1LCBwcm9zZXMgc2V0LXVwIGRhbiBtYWludGVuYW5jZSB5YW5nIHNlZGVyaGFuYSBtZW1idWF0IGJhcnJpZXIgdG8gZW50cnkga2UgUiB0aWRhayB0ZXJsYWx1IHRpbmdnaS4gU2VjYXJhIGxvZ2lrYSBiYWhhc2EsIFIganVnYSByZWxhdGlmIGxlYmloIG11ZGFoIGRpcGFoYW1pLg0KDQoNCiMjIEFwYSB5YW5nIGFrYW4gZGlwZWxhamFyaSBoYXJpIGluaT8NClR1anVhbiBkYXJpIHNlc2kgaGFyaSBpbmkgYWRhbGFoIG1lbmdlbmFsICpidWlsZGluZyBibG9jayogcGFsaW5nIGRhc2FyIGRhcmkgcGVuZ2d1bmFhbiBSOiB2YXJpYWJlbC4NCk1lbWFoYW1pIGplbmlzLCBvcGVyYXNpLCBkYW4gY2FyYSB1bnR1ayBtZW5hdmlnYXNpIHZhcmlhYmVsIGRpIFIgYWRhbGFoIHByYXN5YXJhdCBkYXJpIG1lbmdndW5ha2FuIFIgdW50dWsgaGFsIGxhaW4geWFuZyBsZWJpaCBrb21wbGVrcywgc2VwZXJ0aSBtZW1hbmlwdWxhc2kgdGFiZWwtdGFiZWwsIG1lbWJlcnNpaGthbiBkYXRhLCBkYW4gbWVuZ2d1bmFrYW4gZnVuY3Rpb24uDQoNClRvcGlrIHlhbmcgYWthbiBkaWJhaGFzOg0KDQotICoqSmVuaXMgdmFyaWFiZWwgZGkgUioqDQotICoqT3BlcmFzaSBkYXNhciBkYW4gbWFuaXB1bGFzaSB2YXJpYWJlbCoqDQotICoqVGFiZWwqKg0KDQoqKipDYXRhdGFuOiAgU3VtYmVyIHV0YW1hIHR1dG9yaWFsIGFkYWxhaCAgYnVrdSBEYW5pZWxsZSBOYXZhcnJvOiBMZWFybmluZyBTdGF0aXN0aWNzIHdpdGggUiAoaHR0cHM6Ly9sZWFybmluZ3N0YXRpc3RpY3N3aXRoci5jb20vKSoqKg0KDQojIyAxLiBKZW5pcy1qZW5pcyB2YXJpYWJlbA0KVW11bW55YSBSIG1lbWlsaWtpIDMgamVuaXMgdmFyaWFiZWw6IE51bWVyaWMsIENoYXJhY3RlciwgZGFuIExvZ2ljYWwuIFNlcGFuamFuZyBraXRhIG1lbmdndW5ha2FuIFIsIGtpdGEgbW9zdGx5IGFrYW4gbWVuZ2d1bmFrYW4gdGlnYSB2YXJpYWJlbCBpbmkuIA0KDQoxLiAqKk51bWVyaWMqKg0KDQpWYXJpYWJlbCBhbmdrYS4gQW5na2EtYW5na2EgeWFuZyB0ZXJtYXN1ayBkaSBkYWxhbSB2YXJpYWJlbCBpbmkgYWRhbGFoIGFuZ2thIHJhc2lvbmFsLCB5YW5nIGJpc2EgYmVyc2lmYXQgbmVnYXRpZiwgaW50ZWdlciwgbWF1cHVuIGRlc2ltYWwuDQoNCmBgYHtyfQ0KMQ0KY2xhc3MoMSkNCg0KYGBgDQoNCg0KMi4gKipDaGFyYWN0ZXIqKg0KDQpWYXJpYWJlbCBiZXJiZW50dWsgdGVrcywgeWFuZyBhZGFwYXQgdGVyZGlyaSBkYXJpIGVsZW1lbiBhbGZhYmV0aWssIG51bWVyaWssIG1hdXB1biBzaW1ib2wuIFNlcmluZ2thbGkganVnYSBkaXNlYnV0IGRlbmdhbiAnc3RyaW5nJy4gRGl0YW5kYWkgZGVuZ2FuIHRhbmRhIGt1dGlwIGRpIGFudGFyYSB0ZWtzIHRlcnNlYnV0KCIiIGF0YXUgJycpLg0KDQpgYGB7cn0NCiJoYWxvIg0KY2xhc3MoImhhbG8iKSANCg0KYGBgDQoNCjMuICoqTG9naWNhbCoqDQoNClZhcmlhYmVsIGJlcmJlbnR1ayBwZXJueWF0YWFuIGBUUlVFYCBhdGF1IGBGQUxTRWAuIFZhcmlhYmVsIGluaSBkaWJlbnR1ayBkYXJpIGtvbXBhcmFzaSBuaWxhaSBtZW5nZ3VuYWthbiBvcGVyYXRvci1vcGVyYXRvciByZWxhc2kuDQoNCmBgYHtyfQ0KMisyID09IDQNCmNsYXNzKDIrMiA9PSA0KQ0KYGBgDQoNCg0KQmVyaWt1dCBhZGFsYWggdGFiZWwgb3BlcmF0b3IgeWFuZyBkaWd1bmFrYW4gdW50dWsgbWVtYnVhdCB2YXJpYWJlbCBsb2dpY2FsOg0KDQp8IE9wZXJhdG9yIHwgRGVza3JpcHNpIHwNCnwgLS0tLS0tLS0tLS0gfCAtLS0tLS0tLS0tLSB8DQp8IDwgfCBLdXJhbmcgZGFyaSB8DQp8ID4gfCBMZWJpaCBkYXJpIHwNCnwgPT0gfCBTYW1hIGRlbmdhbiB8DQp8ICE9IHwgVGlkYWsgc2FtYSBkZW5nYW4gfA0KfCA+PSB8IExlYmloIGRhcmkgYXRhdSBzYW1hIGRlbmdhbiB8DQp8IDw9IHwgS3VyYW5nIGRhcmkgYXRhdSBzYW1hIGRlbmdhbiB8DQoNCg0KIyMgMi4gT3BlcmFzaSBkZW5nYW4gbnVtZXJpYyB2YXJpYWJsZXMNClNhbGFoIHNhdHUgaGFsIHlhbmcgcGFsaW5nIG1lbmRhc2FyIHlhbmcgYmlzYSBkaWxha3VrYW4gZGkgUiBhZGFsYWggbWVuZ2d1bmFrYW4gcHJvZ3JhbSBpbmkgc2ViYWdhaSBrYWxrdWxhdG9yLiANCg0KYGBge3J9DQojIFBlbmp1bWxhaGFuDQoxICsgMQ0KDQojIFBlbmd1cmFuZ2FuICANCjIgLSAxDQoNCiAgIyBQZXJrYWxpYW4NCjMgKiAyDQoNCiAgIyBQZW1iYWdpYW4NCjMvMg0KDQogICMgUGFuZ2thdA0KNSAqKiAyDQoNCjUgXiAyDQoNCiAgIyBBa2FyIChtZW5nZ3VuYWthbiBvcGVyYXNpIHBhbmdrYXQpDQo5ICoqIDAuNQ0KYGBgDQoNCg0KS2Fsa3VsYXNpIGRpIGRhbGFtIFIgbWVuZ2d1bmFrYW4gcHJpbnNpcCAqKkJFRE1BUyoqLCB5YW5nIG1lbnVuanVra2FuIHVydXRhbiBrYWxrdWxhc2kgZGFsYW0gcnVtdXMgeWFuZyBtZW1pbGlraSBsZWJpaCBkYXJpIHNhdHUgamVuaXMga2Fsa3VsYXNpLg0KDQpVcnV0YW4gQkVETUFTOiBCcmFja2V0cyBgKClgLCBFeHBvbmVudHMgYCoqYCBhdGF1IGBeYCwgRGl2aXNpb24gYC9gLCBNdWx0aXBsaWNhdGlvbiBgKmAsIEFkZGl0aW9uIGArYCwgbGFsdSBTdWJ0cmFjdGlvbiBgLWAuDQpgYGB7cn0NCjUqKjIrMiooNS0yKQ0KYGBgDQoNCg0KQmViZXJhcGEga2Fsa3VsYXNpIGRhcGF0IGRpbGFrdWthbiBtZW5nZ3VuYWthbiBmdW5nc2kuSGFsIGluaSBha2FuIGRpYmFoYXMgbGViaWggbGFuanV0IGRpIGRpc2t1c2kgdGVudGFuZyBzdW1tYXJ5IHN0YXRpc3RpY3MgcGFkYSBwZXJ0ZW11YW4ga2VkdWEuIA0KDQpgYGB7cn0NCnNxcnQoOSkNCmBgYA0KDQoNCiMjIDMuIE9wZXJhc2kgVmFyaWFiZWwNClZhcmlhYmVsLXZhcmlhYmVsIHNlcGVydGkgeWFuZyBraXRhIHRlbGFoIGJ1YXQgZGkgYXRhcyBkYXBhdCBkaXNpbXBhbiBzZWJhZ2FpIHNlYnVhaCBvYmplay4gT2JqZWsgZGlidWF0IGRlbmdhbiBtZW1iZXJpa2FuIHRhbmRhIHBhbmFoIGA8LWAsIHlhbmcgYWthbiBtZW5hbmRhaSBzdWF0dSBuaWxhaSBzZWJhZ2FpIG9iamVrIHRlcnNlYnV0IG1lbmdla3Nla3VzaSBvYmplayBha2FuIG1lbXVuY3Vsa2FuIG5pbGFpbnlhLg0KDQpgYGB7cn0NCiAjIG9iamVrIG51bWVyaWMNCmJ1bGFuX251bWVyaWMgPC0gMg0KYnVsYW5fbnVtZXJpYw0KDQogICMgb2JqZWsgY2hhcmFjdGVyDQpidWxhbl9jaGFyIDwtICJGZWJydWFyaSINCmJ1bGFuX2NoYXINCg0KICAjIG9iamVrIGxvZ2ljYWwNCmJ1bGFuX2xvZ2ljIDwtIGJ1bGFuX2NoYXIgPT0gIkZlYnJ1YXJpIg0KYnVsYW5fbG9naWMNCmBgYA0KDQpTYXR1IG9iamVjdCBiaXNhIG1lbWlsaWtpIHNhdHUgbmlsYWkgc2FqYS4gSmlrYSBuaWxhaSBsYWluIGRpc2ltcGFuIGRlbmdhbiBuYW1hIG9iamVrIHlhbmcgc2FtYSBtYWthIG5pbGFpIGxhbWEgYWthbiB0ZXJoYXB1cyBkYW4gZGlnYW50aWthbiBkZW5nYW4gbmlsYWkgeWFuZyBiYXJ1IGRpc2ltcGFuLiBEZW5nYW4ga2F0YSBsYWluLCBvYmplayBtZW1pbGlraSBzaWZhdCBla3NsdXNpZi4NCmBgYHtyfQ0KYnVsYW5fbnVtZXJpYw0KYnVsYW5fbnVtZXJpYyA8LSAxDQpidWxhbl9udW1lcmljDQpgYGANCg0KDQojIyA0LiBWZWN0b3INCldhbGF1IHN1YXR1IG9iamVrIGRhcGF0IG1lbnlpbXBhbiBoYW55YSBzYXR1IG5pbGFpLCBlbGVtZW4gZGkgZGFsYW0gc3VhdHUgb2JqZWsgZGFwYXQgYmVyYmVudHVrIGRlcmV0LCANCmF0YXUgbWVueWltcGFuIGxlYmloIGRhcmkgc2F0dSBhbmdrYSwgdGVrcywgYXRhdSBsb2dpYy4gSGFsIGluaSBkaXNlYnV0IHNlYmFnYWkgYHZlY3RvcmAuDQogDQpgYGB7cn0NCiAgIyB2ZWN0b3IgYmVyaXNpIG5pbGFpIG51bWVyaWMNCm1vbnRoX251bSA8LSBjKDEsIDIsIDMpDQpzYWxlc19wZXJtb250aCA8LSBjKDE1MCwgMjAwLCAxMjUpDQoNCiAgIyB2ZWN0b3IgYmVyaXNpIG5pbGFpIGNoYXJhY3Rlcg0KbW9udGhfY2hhIDwtIGMoIkphbnVhcmkiLCAiRmVicnVhcmkiLCAiTWFyZXQiKQ0KDQogICMgdmVjdG9yIGJlcmlzaSBuaWxhaSBsb2dpY2FsDQpzYWxlc191bmRlcnBlcmZvcm0gPC0gc2FsZXNfcGVybW9udGggPCAxNTANCmBgYA0KDQpLaHVzdXMgdW50dWsgdmVrdG9yIG51bWVyaWssIGFkYSBiZXJiYWdhaSBjYXJhIHlhbmcgYmlzYSBraXRhIGxha3VrYW4gdW50dWsgbWVtYnVhdCBkZXJldCBhbmdrYS4gUGVydGFtYSBkZW5nYW4gdGFuZGEgYDpgDQpgYGB7cn0NCiAgIyBtZW1idWF0IGRlcmV0IGRlbmdhbiAiOiINCmMoMToxMCkNCmMoMTA6MSkgI0Jpc2EgZGlsYWt1a2FuIHNlY2FyYSB0ZXJiYWxpaw0KYGBgDQpEYW4sIGppa2Ega2l0YSBpbmdpbiBtZW1idWF0IGRlcmV0IHlhbmcgbWVtaWxpa2kgaW50ZXJ2YWwgdGVydGVudHUsIGJpc2EgZGVuZ2FuIG1lbmdndW5ha2FuIGZ1bmdzaSBgc2VxKClgDQpgYGB7cn0NCnNlcShmcm9tPTEsIHRvPTEwLCBieT0zKQ0KYGBgDQoNCg0KS2FyZW5hIGJlbnR1a255YSBhZGFsYWggZGVyZXQsIGVsZW1lbiBkaSBkYWxhbSB2ZWN0b3IgbWVtaWxpa2kgdXJ1dGFuLiBVcnV0YW4NCmF0YXUgaW5kZWtzIGluaSBhZGFsYWggaGFsIHlhbmcgYmlzYSBkaWd1bmFrYW4gdW50dWsgbWVtYW5pcHVsYXNpIGF0YXUgbWVtYW5nZ2lsIA0Kc3VhdHUgZWxlbWVuIGRpIGRhbGFtIHZlY3RvciBzZWNhcmEgc3Blc2lmaWsuIA0KDQpgYGB7cn0NCiAgIyBNaXNhbG55YSBraXRhIGluZ2luIG1lbmdhbWJpbCBlbGVtZW4gZGVuZ2FuIHVydXRhbiBrZS0zIHNhamEgZGkgbmFtYSBidWxhbiBkaSBxdWFydGFsIDENCm1vbnRoX2NoYVszXQ0KDQogICMgQXRhdSBraXRhIGluZ2luIG1lbmdhbWJpbCBuYW1hIGJ1bGFuIHBlcnRhbWEgZGFuIGtldGlnYQ0KbW9udGhfY2hhW2MoMSwgMyldDQoNCiAgIyBBdGF1IGhhbnlhIGR1YSBidWxhbiBwZXJ0YW1hDQptb250aF9jaGFbYygxOjIpXQ0KYGBgDQoNCg0KRnVuZ3NpIGluZGV4aW5nIGluaSBkYXBhdCBkaWd1bmFrYW4gdW50dWsgamVuaXMgdmVjdG9yIGFwYXB1biwgYmFoa2FuIHVudHVrIHZlY3RvciBiZXJpc2kgZGF0YSBsb2dpY2FsLiBNaXNhbG55YSBraXRhIGluZ2luIHRhaHUgYXBha2FoIHNhbGVzIGRpIGJ1bGFuIE1hcmV0IHVuZGVycGVyZm9ybSBkZW5nYW4gY2FyYSBpbmRleGluZzoNCg0KYGBge3J9DQpzYWxlc191bmRlcnBlcmZvcm1bM10NCmBgYA0KDQoNCiMjIDUuIFRhYmVsIGRhbiBkYXRhZnJhbWUNCg0KU2V0ZWxhaCBtZW1haGFtaSBhcGEgaXR1IHZlY3Rvciwga2l0YSBzZWthcmFuZyBha2FuIG1lbWJhaGFzIHRlbnRhbmcgdGFiZWwuIFBhZGEgZGFzYXJueWEsIHRhYmVsIGF0YXUgbWF0cml4IGFkYWxhaCBvYmplayB5YW5nIHRlcmRpcmkgZGFyaSBiZWJlcmFwYSB2ZWN0b3IuIERpIGJhZ2lhbiBpbmkga2l0YSBha2FuIG1lbmNvYmEgbWVtYnVhdCB0YWJlbCBkYXJpIHZlY3RvciB5YW5nIHRlbGFoIGtpdGEgYnVhdCBzZWJlbHVtbnlhLg0KDQpgYGB7cn0NCiMgS2l0YSBtZW1pbGlraSBiZWJlcmFwYSB2ZWN0b3IgeWFuZyBzYW1hIHBhbmphbmcgKGp1bWxhaCBlbGVtZW5ueWEgc2FtYSkNCm1vbnRoX2NoYQ0Kc2FsZXNfcGVybW9udGgNCnNhbGVzX3VuZGVycGVyZm9ybQ0KYGBgDQoNCg0KS2l0YSBiaXNhIG1lbWVyaWtzYSB1a3VyYW4gZGFyaSB2ZWN0b3IgZGVuZ2FuIG1lbmdndW5ha2FuIGJlYmVyYXBhIGNhcmEgYmVyaWt1dA0KYGBge3J9DQogICMgTWVsaWhhdCBwYW5qYW5nIHZlY3RvciBzcGVzaWZpaw0KbGVuZ3RoKG1vbnRoX2NoYSkNCiAgIyBNZWxpaGF0IGthcmFrdGVyaXN0aWsgc2VsdXJ1aCB2ZWN0b3IgZGkgZGFsYW0gZW52aXJvbm1lbnQNCmxzcjo6d2hvKCkNCg0KYGBgDQoNCg0KS2FyZW5hIGtldGlnYSB2ZWN0b3IgZGkgYXRhcyBzYW1hIHBhbmphbmcsIGtpdGEgYmlzYSBtZW1idWF0IHRhYmVsIGRhcmkgdmVjdG9yLXZlY3RvciB0ZXJzZWJ1dC4gRGkgZGFsYW0gUiBzdWF0dSB0YWJlbCB1bXVtbnlhIGRpc2ltcGFuIGRhbGFtIG9iamVrIGRlbmdhbiB0aXBlIGBkYXRhZnJhbWVgLiBVbnR1ayBtZW1idWF0IHNlYnVhaCBgZGF0YWZyYW1lYCwga2l0YSBndW5ha2FuIGZ1bmdzaSBgZGF0YS5mcmFtZSgpYC4NCmBgYHtyfQ0KZGZfc2FsZXNxMSA8LSBkYXRhLmZyYW1lKG1vbnRoX2NoYSwgc2FsZXNfcGVybW9udGgsIHNhbGVzX3VuZGVycGVyZm9ybSkNCmRmX3NhbGVzcTENCmBgYA0KDQoNCktpdGEgYmlzYSBtZW5nYWtzZXMgbGFnaSB0aWFwIHZhcmlhYmVsIHlhbmcgc3VkYWggbWFzdWsgZGkgZGFsYW0gZGF0YWZyYW1lIG1lbmdndW5ha2FuIGJlYmVyYXBhIGNhcmEuIFV0YW1hbnlhLCBtZW1hbmdnaWwgbmFtYSBkYXJpIHZhcmlhYmVsIHRlcnNlYnV0IGRhbiBtZW5nZ3VuYWthbiBpbmRla3Mga29sb20uDQoNCmBgYHtyfQ0KICAjIG1lbmdndW5ha2FuIG5hbWEgZGFyaSB2YXJpYWJlbA0KZGZfc2FsZXNxMSRzYWxlc19wZXJtb250aA0KICAjIGF0YXUgbWVuZ2d1bmFrYW4gaW5kZWtzIGRhcmkga29sb20gKHVydXRhbiBrb2xvbSBrZSBiZXJhcGEgdmFyaWFiZWwgeWFuZyBraXRhIGluZ2lua2FuKQ0KZGZfc2FsZXNxMVssIDJdDQpgYGANCg0KDQpNZW5nZ3VuYWthbiBmdW5nc2kgbG9naWMsIGtpdGEganVnYSBiaXNhIG1lbWFuZ2dpbCB0YWJlbCBkZW5nYW4gZGF0YSB5YW5nIGtpdGEgaW5naW5rYW4gYmVyZGFzYXJrYW4ga3JpdGVyaWEgdGVydGVudHUuIA0KDQpgYGB7cn0NCiAgIyBNaXNhbGthbiwga2l0YSBpbmdpbiBtZW5nYW1iaWwgdGFiZWwgdW50dWsgYnVsYW4gSmFudWFyaSBzYWphDQpkZl9zYWxlc3ExWyhkZl9zYWxlc3ExJG1vbnRoX2NoYSA9PSAiSmFudWFyaSIpLCBdDQoNCiAgIyBBdGF1IGtpdGEgaW5naW4gbWVuZ2FtYmlsIHRhYmVsIHlhbmcgdGlkYWsgdW5kZXJwZXJmb3JtDQpkZl9zYWxlc3ExWyhkZl9zYWxlc3ExJHNhbGVzX3VuZGVycGVyZm9ybSA9PSBGQUxTRSksIF0NCmBgYA0KDQoNClNhbWEgc2VwZXJ0aSB2YXJpYWJlbCwgc2V0ZWxhaCBraXRhIG1lbGFrdWthbiBzbGljaW5nLCBraXRhIGJpc2EgbWVueWltcGFuIHRhYmVsIG1lbmphZGkgb2JqZWsgYmFydQ0KYGBge3J9DQogICMgQ29udG9oLCBraXRhIG1lbWJ1YXQgdGFiZWwga2h1c3VzIHVudHVrIGJ1bGFuIHlhbmcgdGlkYWsgdW5kZXJwZXJmb3JtDQpkZl9zYWxlc3ExX25vbnVuZGVycGVyZm9ybSA8LSBkZl9zYWxlc3ExWyhkZl9zYWxlc3ExJHNhbGVzX3VuZGVycGVyZm9ybSA9PSBGQUxTRSksIF0NCmRmX3NhbGVzcTFfbm9udW5kZXJwZXJmb3JtDQpgYGANCg0KDQoNCiMjIDYuIE1hbmlwdWxhc2kgZGF0YWZyYW1lIGRhc2FyDQpLaXRhIGFrYW4gcGVsYWphcmkgYmViZXJhcGEgbWFuaXB1bGFzaSBkYXNhciB5YW5nIHNlcmluZyBkaWxha3VrYW4gZGkgdGFiZWwuIA0KDQoNCiMjIyBNZW5hbWJhaCBrb2xvbSBiYXJ1DQpQZXJ0YW1hLCBtZW5hbWJhaCBrb2xvbSBiYXJ1LCB5YW5nIGRhcGF0IGRpbGFrdWthbiBtZW5nZ3VuYWthbiBiZWJlcmFwYSBmdW5nc2kuIA0KDQotIGZ1bmdzaSBgY2JpbmRgOiBkaWd1bmFrYW4gdW50dWsgbWVsYWt1a2FuIG1lcmdlciBkYXJpIGR1YSB2ZWN0b3IsIGJpc2EgdW50dWsgbWVuYW1iYWhrYW4ga29sb20gYmFydSBkYXJpIHZla3RvciB5YW5nIGFkYS4gRGkgZnVuZ3NpIGluaSBjdWt1cCBtYXN1a2FuIG5hbWEga2VkdWEgdGFiZWwgeWFuZyBpbmdpbiBkaWdhYnVuZ2thbi4NCg0KYGBge3J9DQoNCmRmX3NhbGVzcTFfbWVyZ2VkIDwtIGNiaW5kKGRmX3NhbGVzcTEsIG1vbnRoX251bSkNCmRmX3NhbGVzcTFfbWVyZ2VkDQpgYGANCiANCg0KLSBNZW5nZ3VuYWthbiBgJGA6IGtpdGEgYmlzYSBtZW1ha3Nha2FuIGtvbG9tIGJhcnUgZGVuZ2FuIGxhbmdzdW5nIG1lbWJ1YXQga29sb20geWFuZyBNZWJlbHVtbnlhIHRpZGFrIGFkYSBkYW4gbWVtYmVyaWthbiBuaWxhaSB1bnR1ayBrb2xvbSB0ZXJzZWJ1dC4gS3VyYW5nIGxlYmloLE1ldG9kZSBpbmkgc2VwZXJ0aSBtZW1idWF0IHNlYnVhaCB2ZWN0b3IgZGkgZGFsYW0ga29sb20uDQpgYGB7cn0NCmRmX3NhbGVzcTFfbWVyZ2VkJHNwZW5kaW5ncyA8LSBjKDE2MCwgMTcwLCAxNTApDQpkZl9zYWxlc3ExX21lcmdlZA0KYGBgDQoNCg0KDQojIyMgTWVuYW1iYWggcm93DQoNClNlYmVsdW0gZGVtb25zdHJhc2ksIG1hcmkga2l0YSBidWF0IHNhdHUgZGF0YWZyYW1lIGxhaW4gdGVybGViaWggZGFodWx1IHVudHVrIG5hbnRpbnlhIGRpdGFtYmFoa2FuIGtlIHRhYmVsLiBQZXJsdSBkaXBlcmhhdGlrYW4gYmFod2EgZGF0YWZyYW1lIGJhcnUgaW5pIHBlcmx1IG1lbWlsaWtpIGtvbG9tLWtvbG9tIHlhbmcgc2FtYSBkZW5nYW4gZGF0YSB5YW5nIGluZ2luIGRpLW1lcmdlIGRlbmdhbm55YQ0KYGBge3J9DQpkZl9zYWxlc3EydG8zIDwtIA0KICBkYXRhLmZyYW1lKA0KICAgIG1vbnRoX2NoYT1jKCJBcHJpbCIsICJNZWkiLCAiSnVuaSIsICJKdWxpIiwgIkFndXN0dXMiLCAiU2VwdGVtYmVyIiksIA0KICAgIHNhbGVzX3Blcm1vbnRoPWMoMTgwLCAyMTAsIDIzMCwgMjAwLCAxOTAsIDI0MCksIA0KICAgIHNhbGVzX3VuZGVycGVyZm9ybT1jKEZBTFNFLCBGQUxTRSwgRkFMU0UsIEZBTFNFLCBGQUxTRSwgRkFMU0UpLCANCiAgICBtb250aF9udW09Yyg0LCA1LCA2LCA3LCA4LCA5KSwgDQogICAgc3BlbmRpbmdzPWMoMTcwLCAxODAsIDE0MCwgMTQwLCAxNzAsIDE1MCkNCiAgKQ0KZGZfc2FsZXNxMnRvMw0KYGBgDQoNClNla2FyYW5nIGtpdGEgYmlzYSBtZW5hbWJhaGthbiB0YWJlbCB0ZXJzZWJ1dCBtZW5nZ3VuYWthbiBmdW5nc2kgYHJiaW5kYC4gU2FtYSBzZXBlcnRpIGBjYmluZGAsIGN1a3VwIG1hc3Vra2FuIG5hbWEgdGFiZWwgeWFuZyBpbmdpbiBkaXRhbWJhaGthbiBkaSBkYWxhbSBmdW5nc2kgdGVyc2VidXQsIGxhbHUgc2ltcGFuIGRlbmdhbiBgPC1gLg0KYGBge3J9DQpkZl9zYWxlc19tZXJnZWQgPC0gcmJpbmQoZGZfc2FsZXNxMV9tZXJnZWQsIGRmX3NhbGVzcTJ0bzMpDQpkZl9zYWxlc19tZXJnZWQNCmBgYA0KDQoNCg==