Email             :
RPubs            : https://rpubs.com/claradellaevania/
Jurusan          : Statistika Bisnis
Address         : ARA Center, Matana University Tower
                         Jl. CBD Barat Kav, RT.1, Curug Sangereng, Kelapa Dua, Tangerang, Banten 15810.


1 R Vs Python

R dan Python, keduanya merupakan Bahasa pemrograman yang sangat popular, dinamis, digunakan secara luas dalam komunitas data Science. Dalam hal Analisis, R lebih banyak digunankan, sedangkan dalam hal mengenai sains data, Python menyediakan pendekatan yang lebih umum agar dapat dianggap lebih mudah untuk digunakan oleh pemula. Kedua Bahasa pemrograman ini memiliki kelebihan dan kekurangan masing-masing. Solusi yang tepat untuk memahami kelebihan dan kekurangan tersebut kita bisa mempelajari kedua Bahasa pemrograman ini.

1.1 Persamaan

R dan Python merupakan Bahasa pemrograman multi-paradigma. Jadi mereka mendukung pemrograman beroirientasi objek, pemrograman imperative, pemrograman procedural dan lain-lain. Kedua Bahasa pemrograman ini merupakan Bahasa yang ditafsirkan dan Bahasa pemrograman tingkat tinggi, serta dapat digunakan dalam pengembangan Algoritma. R dan Python merupakan Bahasa pemrograman yang gratis dan opensource, serta dapat diintegarikan dengan database seperti MySQL, Oracle, dan lain-lain. Selain itu, keduanya juga mendukung file yang berbeda seperti file CSV, file Excel, file, XML, dan File JSON, serta Bahasa dari kedua pemrograman ini dapat mudah digunakan dan dipelajari.

1.2 Perbedaan

Perbedaan dari kedua Bahasa pemrograman ini adalah jika R dapat digunakan untuk komputasi statistic, Data sicence dan analitkik data serta paling sering digunakan oleh akademisi dan peneliti, sedangkan Python dapat digunakan untuk banyak aplikasi dan industry seperti pembelajaran mesin, pengembangan web, jaringan, dan lain sebagainya , serta paling sering digunakan oleh programmers dan developers. Dalam hal IDE Pemrograman, IDE umum untuk pemrograman R adalah R studio, sedangkan IDE umum untuk pemrograman Python adalah Spyder,Jupyter,Notebook,Pycharm,dll. Tidak hanya itu, Struktur Data, Script, Pacakges dan Library, serta Integrasi antara R dan Python sangatlah berbeda. R mendukung struktur data seperti vector, list, matriks, aarray, factor, dan bingkai data, sedangkan Python mendukung struktur data list, dictionary dan tupel. Script yang digunakan oleh R diakhiri dengan .R dan .Rmd . Sedangkan Python diakhiri dengan .py dan .ipynb. Dalam hal Packages dan library dari R yaitu tidyverse, ggplot2, caret,dan zoo, sedangkan Packages dan library dari Python yaitu pandas, scipy, scikit-learn, TensorFlow, dan caret. Lalu dalam hal Integrasi R mempunyai fitur Rmarkdown dan Shiny, sedangkan Python memiliki integrasi aplikasi lebih luas. Tentunya kedua Bahasa pemrograman ini memiliki Kelebihan dan Kekurangan yang sangat berbeda-beda juga. Kelebihan dari R adalah memiliki lebih banyak library dan kualitas visualisasi grafik yang dihasilkan sangat tinggi sedangkan Python memiliki kelebihan dalam hal sistematika penulisan script yang mudah dibaca, focus pada kecepatan komputasi . Namun sayangnya kekurangan dari Bahasa pemrograman R ini adalah ketergantungan antar library sedangkan pada Bahasa pemrograman Python.

2 Sintaks Dasar

Program dari Bahasa Pemrograman R dan Python terdiri dari tiga hal mendasar yaitu Variabel, Operan (nilai) dan Komentar. Variabel digunakan dalam menyimpan suatu nilai sedangkan Komentar digunakan untuk meningkatkan pemahaman penggunanya mengenai skrip atau koding.

2.1 Penugasan Variabel

Penugasan program dalam R menggunakan suatu variabel yang dicadangkan sehingga dapat merekam jenis data sesuai dengan nama yang diberikan dan disimpan pada lokasi penyimpanan/memori. Dengan cara menotasikannya adalah :

  • ==, digunakan untuk penugasan sederhana
  • <-, digunakan untuk penugasan dari sisi Kiri
  • ->, digunakan untuk penugasan dari sisi Kanan
x=6
y<-8
10->z
print(c(x,y,z))
## [1]  6  8 10

2.2 Menambahkan Komentar

Komentar dituliskan dalam satu baris dengan menggunakan Dalam script ataupun koding R, tujuan memberikan atau menambahkan komentar adalah untuk memudahkan serta memahami makna dari penggunaan perintah maupun proram. Komentar yang ditulis dalam sebuah program merupakan suatu penjelasan tentang sesuatu yang dilakukan ataupun sesuatu yang seharusnya dilakukan oleh sebuah script ataupun koding. Komentar yang bersifat informasi tidak memiliki hubungan dengan logika pemrograman yang sedang digunakan, jadi diabaikan oleh kompiler dan tidak pernah tercermin pada input.

# Mengganti nilai x yang sudah direkam (komentar di awal pernyataan)
x = 16
z <- x + y  # Mengganti nilai yang sudah direkam (Komentar yang ada di akhir pernyataan)
x + y -> z  #sama dengan diatas

3 Operator

Operator mengarahkan compiler untuk melakukan berbagai macam operasi pada beberapa penugasan, dan mensimulasikan operasi matematis, logika, dan keputusan yang dilakukan terhadap sekumpulan Bilangan Kompleks, Integer, dan Numerik sebagai input.

3.1 Aritmatika

Digunakan untuk mensimulasikan berbagai operasi matematika serta nilai skalar, bilangan kompleks atau vektor.

Operator Symbol pada R
Penjumlahan +
Pengurangan -
Perkalian *
Pembagian /
Pemangkatan ^
Modulo %%

3.1.1 Penerapan Aritmatika Pada R

x <- c(3,5,7)   # memuat vektor x
y <- c(2,4,6)   # memuat vektor y
x + y           # hasil penjumlahan vektor x dan y
## [1]  5  9 13

Penjumlahan pada R

print (x+y)  #hasil penjumlahan vektor x dan y
## [1]  5  9 13

Pengurangan pada R

print (x-y)  #hasil pengurangan vektor x dan y
## [1] 1 1 1

Perkalian pada R

print (x*y)  #hasil perkalian vektor x dan y
## [1]  6 20 42

Pembagian pada R

print (x/y)  #hasil pembagian vektor x dan y
## [1] 1.500000 1.250000 1.166667

Pemangkatan pada R

print (x^y)  #hasil pemangkatan vektor x dan y
## [1]      9    625 117649

Modulo pada R

print (x%%y)  #hasil modulo vektor x dan y
## [1] 1 1 1

Untuk menampilkan keterangan atau komentar sehingga dapat melekat pada perhitungan R itu sendiri seperti :

cat("Penjumlahan vektor x dan y:", x + y, "\n")
## Penjumlahan vektor x dan y: 5 9 13
cat("Pengurangan vektor x dan y:", x - y, "\n")
## Pengurangan vektor x dan y: 1 1 1
cat("Perkalian vektor x dan y:", x * y, "\n")
## Perkalian vektor x dan y: 6 20 42
cat("Pembagian vektor x dan y:", x / y, "\n")
## Pembagian vektor x dan y: 1.5 1.25 1.166667
cat("Pemangkatan vektor x dan y:", x ^ y, "\n")
## Pemangkatan vektor x dan y: 9 625 117649
cat("Modulo vektor x dan y:", x %% y, "\n")
## Modulo vektor x dan y: 1 1 1

3.2 Relasional

Merupakan operasi perbandingan antara elemen yang bersesuaian pada setiap pengoperasian. Nilai TRUE dianggap lebih besar dari FALSE

Operator Symbol pada R Keterangan
Kurang dari < mengembalikan TRUE jika operan pertama lebih kecil dari operan kedua. Selain itu akan mengembalikan FALSE
Kurang dari sama dengan <= mengembalikan TRUE jika operan pertama kurang dari atau sama dengan operan kedua. Selain itu akan mengembalikan FALSE
Lebih besar dari > mengembalikan TRUE jika operan pertama lebih besar dari operan kedua. Selain itu akan mengembalikan FALSE
Lebih besar sama dengan >= mengembalikan TRUE jika operan pertama lebih besar atau sama dengan operan kedua. Selain itu akan mengembalikan FALSE
Sama Dengan == Mengembalikan TRUE jika dan hanya jika kedua sisi memiliki nilai sama
Tidak sama dengan != Mengembalikan TRUE jika operan pertama tidak sama dengan operan kedua

Contohnya adalah sebagai berikut

kurang dari

x <- c(3,5,7)   # memuat vektor x
y <- c(2,4,6)   # memuat vektor y
cat("Vektor x kurang dari Vektor y;", x < y, "\n")
## Vektor x kurang dari Vektor y; FALSE FALSE FALSE

kurang dari sama dengan

cat("Vektor x kurang dari sama dengan Vektor y;", x <= y, "\n")
## Vektor x kurang dari sama dengan Vektor y; FALSE FALSE FALSE

lebih besar dari

cat("Vektor x lebih besar dari Vektor y;", x > y, "\n")
## Vektor x lebih besar dari Vektor y; TRUE TRUE TRUE

lebih besar sama dengan

cat("Vektor x lebih besar sama dengan Vektor y;", x >= y, "\n")
## Vektor x lebih besar sama dengan Vektor y; TRUE TRUE TRUE

sama dengan

cat("Vektor x sama dengan Vektor y;", x == y, "\n")
## Vektor x sama dengan Vektor y; FALSE FALSE FALSE

tidak sama dengan

cat("Vektor x tidak sama dengan Vektor y;", x != y, "\n")
## Vektor x tidak sama dengan Vektor y; TRUE TRUE TRUE

3.3 Logika

Operasi Keputusan disimulasikan oleh operator Logis, berdasarkan operator yang ditentukan antara operan lalu dievaluasi pada nilai Boolean Benar ataupun salah. Nilai bilangan bulat bukan nol dianggap sebagai dilai BENAR, baik bilangan kompleks maupun bilangan real

Operator Symbol pada R Keterangan
NOT ! Negasi/kebalikan
AND & Konjungsi
OR \(|\) Disjungsi
XOR ^ Disjungsi Parsial

Contohnya adalah sebagai berikut

Negasi vektor x

x <- c(0,TRUE,FALSE)
y <- c(TRUE,3+4i,8)

#Melakukan operasi logika pada operan
cat("Logika Negasi (~) untuk vektor x:", !x, "\n")
## Logika Negasi (~) untuk vektor x: TRUE FALSE TRUE

Negasi vektor y

cat("Logika Negasi (~) untuk vektor y:", !y, "\n")
## Logika Negasi (~) untuk vektor y: FALSE FALSE FALSE

konjungsi (Dan)

cat("Logika Konjungsi (Dan) :", x & y, "\n")
## Logika Konjungsi (Dan) : FALSE TRUE FALSE

Disjungsi (Atau)

cat("Logika Disjungsi (Atau) :", x & y, "\n")
## Logika Disjungsi (Atau) : FALSE TRUE FALSE

Disjungsi Parsial

cat("Logika Disjungsi Parsial :", x || y, "\n")
## Logika Disjungsi Parsial : TRUE

3.4 Lain-Lain

Operator lain yang digunakan dalam penggunaan R antara lain :

Bentuk akar

x <- c(3,5,7)   # memuat vektor x
y <- c(2,4,6)   # memuat vektor y
sqrt(x*y)       # Bentuk akar
## [1] 2.449490 4.472136 6.480741

Logaritma

log(x)      # Logaritma
## [1] 1.098612 1.609438 1.945910

Eksponen

exp(y)      # Eksponen
## [1]   7.389056  54.598150 403.428793

Tanda kurung

(x/y) + y    # Tanda Kurung
## [1] 3.500000 5.250000 7.166667

4 Tipe Data

Tipe data merupakan konsep penting dalam R, untuk menyimpan tipe yang berbeda dapat menggunakan variabel. Tipe data yang mendasar adalah

Tipe Data R Penjelasan
Double/Float 3.2 Bilangan yang mempunyai koma
Integer 3 Bilangan bulat n
Bolean TRUE/FALSE TRUE bernilai 1 dan FALSE bernilai 0
String/Character ‘Claradellae’ karakter/kalimat berupa huruf yang diapit tanda " atau ’
Complex 3+4i Pasangan angka real dan imajiner

Koding R yang dapat digunakan dengan menetapkan kelima tipe data adalah sebagai berikut :

c1 <- 3.2           # Tetapkan nilai desimal
c2 <- as.integer(3) # Tetapkan nilai integer
c2 <- 3L            # Cara lain untuk memuat nilai integer di R
c3 <- c(TRUE,FALSE) # Bolean/Logical
c3 <- as.logical(c(0,1)) # Cara lain untuk memuat Bolean/Logical
c4 <- c("d",'e', '456') #String/Character
c5 <- 4 + 8i        #Complex

Untuk memeriksa tipe data dalam R yaitu:

class(c1)       # Cetak nama kelas variabel
## [1] "numeric"
cat("cetak tipe data c1 :", class(c1),"\n")
## cetak tipe data c1 : numeric
typeof(c1)       # Cetak tipe variabel x
## [1] "double"
cat("cetak tipe variabel c1 :", typeof(c1),"\n")
## cetak tipe variabel c1 : double

5 Bantuan

Mengetahui dan mencari bantuan dalam R merupakan sesuatu bagian yang terpenting dalam bahasa R.

# help.start()         # Menu untuk mendapat menavigasi bantuan lokal berbasis web
# ?help                # Menu untuk mendapat menavigasi bantuan lokal berbasis web
# ? class              # mendapatkan bantuan untuk fungsi class
# help(class)          # mendapatkan bantuan untuk fungsi class
# ??class              # jika tidak mengetahui fungsi yang dicari
# help.search('class') # jika tidak mengetahui fungsi yang dicari

6 Referensi

LS0tDQp0aXRsZTogIkFsZ29yaXRtYSBkYW4gU3RydWt0dXIgRGF0YSINCnN1YnRpdGxlOiAiVHVnYXMgMiINCmF1dGhvcjogIkNsYXJhIERlbGxhIEV2YW5pYSAoMjAyMDQ5MjAwMTgpIg0KZGF0ZTogImByIGZvcm1hdChTeXMuRGF0ZSgpLCAnJUIgJWQsICVZJylgIg0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDogDQogICAgaHRtbF9kb2N1bWVudDogbnVsbA0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHRoZW1lOiBzYW5kc3RvbmUNCiAgICBjc3M6IHN0eWxlMS5jc3MNCiAgICBoaWdobGlnaHQ6IG1vbm9jaHJvbWUNCi0tLQ0KDQoNCjxpbWcgc3R5bGU9ImZsb2F0OiByaWdodDsgbWFyZ2luOiAwcHggMTAwcHggMHB4IDBweDsgd2lkdGg6MzAlIiBzcmM9Im1lLmpwZWciLz4gDQoNCmBgYHtyIGxvZ28sIGVjaG89RkFMU0UsZmlnLmFsaWduPSdjZW50ZXInLCBvdXQud2lkdGggPSAnMzAlJ30NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJMb2dvTWF0YW5hLnBuZyIpDQpgYGANCg0KRW1haWwgJm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7Jm5ic3A7OiAgY2xhcmEuZXZhbmlhQHN0dWRlbnQubWF0YW5hdW5pdmVyc2l0eS5hYy5pZCA8YnI+DQpSUHVicyAgJm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7OiBodHRwczovL3JwdWJzLmNvbS9jbGFyYWRlbGxhZXZhbmlhLyA8YnI+DQpKdXJ1c2FuICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDs6IFtTdGF0aXN0aWthIEJpc25pc10oaHR0cHM6Ly9tYXRhbmF1bml2ZXJzaXR5LmFjLmlkLz9seT1hY2FkZW1pYyZjPXNiKSA8YnI+DQpBZGRyZXNzICAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgOiBBUkEgQ2VudGVyLCBNYXRhbmEgVW5pdmVyc2l0eSBUb3dlciA8YnI+DQombmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyZuYnNwOyBKbC4gQ0JEIEJhcmF0IEthdiwgUlQuMSwgQ3VydWcgU2FuZ2VyZW5nLCBLZWxhcGEgRHVhLCBUYW5nZXJhbmcsIEJhbnRlbiAxNTgxMC4NCg0KKioqDQoNCiMgUiBWcyBQeXRob24gey50YWJzZXQgLnRhYnNldC1waWxsc30NCg0KUiBkYW4gUHl0aG9uLCBrZWR1YW55YSBtZXJ1cGFrYW4gQmFoYXNhIHBlbXJvZ3JhbWFuIHlhbmcgc2FuZ2F0IHBvcHVsYXIsIGRpbmFtaXMsIGRpZ3VuYWthbiBzZWNhcmEgbHVhcyBkYWxhbSBrb211bml0YXMgZGF0YSBTY2llbmNlLiBEYWxhbSBoYWwgQW5hbGlzaXMsIFIgbGViaWggYmFueWFrIGRpZ3VuYW5rYW4sIHNlZGFuZ2thbiBkYWxhbSBoYWwgbWVuZ2VuYWkgc2FpbnMgZGF0YSwgUHl0aG9uIG1lbnllZGlha2FuIHBlbmRla2F0YW4geWFuZyBsZWJpaCB1bXVtIGFnYXIgZGFwYXQgZGlhbmdnYXAgbGViaWggbXVkYWggdW50dWsgZGlndW5ha2FuIG9sZWggcGVtdWxhLiBLZWR1YSBCYWhhc2EgcGVtcm9ncmFtYW4gaW5pIG1lbWlsaWtpIGtlbGViaWhhbiBkYW4ga2VrdXJhbmdhbiBtYXNpbmctbWFzaW5nLiBTb2x1c2kgeWFuZyB0ZXBhdCB1bnR1ayBtZW1haGFtaSBrZWxlYmloYW4gZGFuIGtla3VyYW5nYW4gdGVyc2VidXQga2l0YSBiaXNhIG1lbXBlbGFqYXJpIGtlZHVhIEJhaGFzYSBwZW1yb2dyYW1hbiBpbmkuIA0KDQojIyBQZXJzYW1hYW4NCg0KUiBkYW4gUHl0aG9uIG1lcnVwYWthbiBCYWhhc2EgcGVtcm9ncmFtYW4gbXVsdGktcGFyYWRpZ21hLiBKYWRpIG1lcmVrYSBtZW5kdWt1bmcgcGVtcm9ncmFtYW4gYmVyb2lyaWVudGFzaSBvYmplaywgcGVtcm9ncmFtYW4gaW1wZXJhdGl2ZSwgcGVtcm9ncmFtYW4gcHJvY2VkdXJhbCBkYW4gbGFpbi1sYWluLiBLZWR1YSBCYWhhc2EgcGVtcm9ncmFtYW4gaW5pIG1lcnVwYWthbiBCYWhhc2EgeWFuZyBkaXRhZnNpcmthbiBkYW4gQmFoYXNhIHBlbXJvZ3JhbWFuIHRpbmdrYXQgdGluZ2dpLCBzZXJ0YSBkYXBhdCBkaWd1bmFrYW4gZGFsYW0gcGVuZ2VtYmFuZ2FuIEFsZ29yaXRtYS4gUiBkYW4gUHl0aG9uIG1lcnVwYWthbiBCYWhhc2EgcGVtcm9ncmFtYW4geWFuZyBncmF0aXMgZGFuIG9wZW5zb3VyY2UsIHNlcnRhIGRhcGF0IGRpaW50ZWdhcmlrYW4gZGVuZ2FuIGRhdGFiYXNlIHNlcGVydGkgTXlTUUwsIE9yYWNsZSwgZGFuIGxhaW4tbGFpbi4gU2VsYWluIGl0dSwga2VkdWFueWEganVnYSBtZW5kdWt1bmcgZmlsZSB5YW5nIGJlcmJlZGEgc2VwZXJ0aSBmaWxlIENTViwgZmlsZSBFeGNlbCwgZmlsZSwgWE1MLCBkYW4gRmlsZSBKU09OLCBzZXJ0YSBCYWhhc2EgZGFyaSBrZWR1YSBwZW1yb2dyYW1hbiBpbmkgZGFwYXQgbXVkYWggZGlndW5ha2FuIGRhbiBkaXBlbGFqYXJpLiANCg0KIyMgUGVyYmVkYWFuDQoNClBlcmJlZGFhbiBkYXJpIGtlZHVhIEJhaGFzYSBwZW1yb2dyYW1hbiBpbmkgYWRhbGFoIGppa2EgUiBkYXBhdCBkaWd1bmFrYW4gdW50dWsgKiprb21wdXRhc2kgc3RhdGlzdGljLCBEYXRhIHNpY2VuY2UgZGFuIGFuYWxpdGtpayBkYXRhIHNlcnRhIHBhbGluZyBzZXJpbmcgZGlndW5ha2FuIG9sZWggYWthZGVtaXNpIGRhbiBwZW5lbGl0aSoqLCBzZWRhbmdrYW4gUHl0aG9uIGRhcGF0IGRpZ3VuYWthbiB1bnR1ayAqKmJhbnlhayBhcGxpa2FzaSBkYW4gaW5kdXN0cnkgc2VwZXJ0aSBwZW1iZWxhamFyYW4gbWVzaW4sIHBlbmdlbWJhbmdhbiB3ZWIsIGphcmluZ2FuLCBkYW4gbGFpbiBzZWJhZ2FpbnlhICwgc2VydGEgcGFsaW5nIHNlcmluZyBkaWd1bmFrYW4gb2xlaCBwcm9ncmFtbWVycyBkYW4gZGV2ZWxvcGVycyoqLiBEYWxhbSBoYWwgSURFIFBlbXJvZ3JhbWFuLCAqSURFIHVtdW0qIHVudHVrIHBlbXJvZ3JhbWFuIFIgYWRhbGFoIFIgc3R1ZGlvLCBzZWRhbmdrYW4gSURFIHVtdW0gdW50dWsgcGVtcm9ncmFtYW4gUHl0aG9uIGFkYWxhaCBTcHlkZXIsSnVweXRlcixOb3RlYm9vayxQeWNoYXJtLGRsbC4gVGlkYWsgaGFueWEgaXR1LCAqKlN0cnVrdHVyIERhdGEsIFNjcmlwdCwgUGFjYWtnZXMgZGFuIExpYnJhcnksIHNlcnRhIEludGVncmFzaSBhbnRhcmEgUiBkYW4gUHl0aG9uKiogc2FuZ2F0bGFoIGJlcmJlZGEuIFIgbWVuZHVrdW5nICpzdHJ1a3R1ciBkYXRhKiBzZXBlcnRpIHZlY3RvciwgbGlzdCwgbWF0cmlrcywgYWFycmF5LCBmYWN0b3IsIGRhbiBiaW5na2FpIGRhdGEsIHNlZGFuZ2thbiBQeXRob24gbWVuZHVrdW5nIHN0cnVrdHVyIGRhdGEgbGlzdCwgZGljdGlvbmFyeSBkYW4gdHVwZWwuICpTY3JpcHQqIHlhbmcgZGlndW5ha2FuIG9sZWggUiBkaWFraGlyaSBkZW5nYW4gLlIgZGFuIC5SbWQgLiBTZWRhbmdrYW4gUHl0aG9uIGRpYWtoaXJpIGRlbmdhbiAucHkgZGFuIC5pcHluYi4gRGFsYW0gaGFsIFBhY2thZ2VzIGRhbiBsaWJyYXJ5IGRhcmkgUiB5YWl0dSB0aWR5dmVyc2UsIGdncGxvdDIsIGNhcmV0LGRhbiB6b28sIHNlZGFuZ2thbiAqUGFja2FnZXMgZGFuIGxpYnJhcnkqIGRhcmkgUHl0aG9uIHlhaXR1IHBhbmRhcywgc2NpcHksIHNjaWtpdC1sZWFybiwgVGVuc29yRmxvdywgZGFuIGNhcmV0LiBMYWx1IGRhbGFtIGhhbCAqSW50ZWdyYXNpKiBSIG1lbXB1bnlhaSBmaXR1ciBSbWFya2Rvd24gZGFuIFNoaW55LCBzZWRhbmdrYW4gUHl0aG9uIG1lbWlsaWtpIGludGVncmFzaSBhcGxpa2FzaSBsZWJpaCBsdWFzLiAgVGVudHVueWEga2VkdWEgQmFoYXNhIHBlbXJvZ3JhbWFuIGluaSBtZW1pbGlraSAqS2VsZWJpaGFuIGRhbiBLZWt1cmFuZ2FuKiB5YW5nIHNhbmdhdCBiZXJiZWRhLWJlZGEganVnYS4gS2VsZWJpaGFuIGRhcmkgUiBhZGFsYWggbWVtaWxpa2kgbGViaWggYmFueWFrIGxpYnJhcnkgZGFuIGt1YWxpdGFzIHZpc3VhbGlzYXNpIGdyYWZpayB5YW5nIGRpaGFzaWxrYW4gc2FuZ2F0IHRpbmdnaSBzZWRhbmdrYW4gUHl0aG9uIG1lbWlsaWtpIGtlbGViaWhhbiBkYWxhbSBoYWwgc2lzdGVtYXRpa2EgcGVudWxpc2FuIHNjcmlwdCB5YW5nIG11ZGFoIGRpYmFjYSwgZm9jdXMgcGFkYSBrZWNlcGF0YW4ga29tcHV0YXNpIC4gTmFtdW4gc2F5YW5nbnlhIGtla3VyYW5nYW4gZGFyaSBCYWhhc2EgcGVtcm9ncmFtYW4gUiBpbmkgYWRhbGFoIGtldGVyZ2FudHVuZ2FuIGFudGFyIGxpYnJhcnkgc2VkYW5na2FuIHBhZGEgQmFoYXNhIHBlbXJvZ3JhbWFuIFB5dGhvbi4gDQoNCiMgU2ludGFrcyBEYXNhcg0KDQpQcm9ncmFtIGRhcmkgQmFoYXNhIFBlbXJvZ3JhbWFuICBSIGRhbiBQeXRob24gdGVyZGlyaSBkYXJpIHRpZ2EgaGFsIG1lbmRhc2FyIHlhaXR1IFZhcmlhYmVsLCBPcGVyYW4gKG5pbGFpKSBkYW4gS29tZW50YXIuIFZhcmlhYmVsIGRpZ3VuYWthbiBkYWxhbSBtZW55aW1wYW4gc3VhdHUgbmlsYWkgc2VkYW5na2FuIEtvbWVudGFyIGRpZ3VuYWthbiB1bnR1ayBtZW5pbmdrYXRrYW4gcGVtYWhhbWFuIHBlbmdndW5hbnlhIG1lbmdlbmFpIHNrcmlwIGF0YXUga29kaW5nLg0KDQojIyBQZW51Z2FzYW4gVmFyaWFiZWwNCg0KUGVudWdhc2FuIHByb2dyYW0gZGFsYW0gUiBtZW5nZ3VuYWthbiBzdWF0dSB2YXJpYWJlbCB5YW5nIGRpY2FkYW5na2FuIHNlaGluZ2dhIGRhcGF0IG1lcmVrYW0gamVuaXMgZGF0YSBzZXN1YWkgZGVuZ2FuIG5hbWEgeWFuZyBkaWJlcmlrYW4gZGFuIGRpc2ltcGFuIHBhZGEgbG9rYXNpIHBlbnlpbXBhbmFuL21lbW9yaS4gRGVuZ2FuIGNhcmEgbWVub3Rhc2lrYW5ueWEgYWRhbGFoIDoNCg0KLSA9PSwgZGlndW5ha2FuIHVudHVrIHBlbnVnYXNhbiBzZWRlcmhhbmE8YnI+DQotIDwtLCBkaWd1bmFrYW4gdW50dWsgcGVudWdhc2FuIGRhcmkgc2lzaSBLaXJpPGJyPg0KLSAtPiwgZGlndW5ha2FuIHVudHVrIHBlbnVnYXNhbiBkYXJpIHNpc2kgS2FuYW48YnI+DQpgYGB7cn0NCng9Ng0KeTwtOA0KMTAtPnoNCnByaW50KGMoeCx5LHopKQ0KYGBgDQoNCiMjIE1lbmFtYmFoa2FuIEtvbWVudGFyDQoNCktvbWVudGFyIGRpdHVsaXNrYW4gZGFsYW0gc2F0dSBiYXJpcyBkZW5nYW4gbWVuZ2d1bmFrYW4gRGFsYW0gc2NyaXB0IGF0YXVwdW4ga29kaW5nIFIsIHR1anVhbiBtZW1iZXJpa2FuIGF0YXUgbWVuYW1iYWhrYW4ga29tZW50YXIgYWRhbGFoIHVudHVrIG1lbXVkYWhrYW4gc2VydGEgbWVtYWhhbWkgbWFrbmEgZGFyaSBwZW5nZ3VuYWFuIHBlcmludGFoIG1hdXB1biBwcm9yYW0uIEtvbWVudGFyIHlhbmcgZGl0dWxpcyBkYWxhbSBzZWJ1YWggcHJvZ3JhbSBtZXJ1cGFrYW4gc3VhdHUgcGVuamVsYXNhbiB0ZW50YW5nIHNlc3VhdHUgeWFuZyBkaWxha3VrYW4gYXRhdXB1biBzZXN1YXR1IHlhbmcgc2VoYXJ1c255YSBkaWxha3VrYW4gb2xlaCBzZWJ1YWggc2NyaXB0IGF0YXVwdW4ga29kaW5nLiBLb21lbnRhciB5YW5nIGJlcnNpZmF0IGluZm9ybWFzaSB0aWRhayBtZW1pbGlraSBodWJ1bmdhbiBkZW5nYW4gbG9naWthIHBlbXJvZ3JhbWFuIHlhbmcgc2VkYW5nIGRpZ3VuYWthbiwgamFkaSBkaWFiYWlrYW4gb2xlaCBrb21waWxlciBkYW4gdGlkYWsgcGVybmFoIHRlcmNlcm1pbiBwYWRhIGlucHV0LiANCg0KYGBge3J9DQojIE1lbmdnYW50aSBuaWxhaSB4IHlhbmcgc3VkYWggZGlyZWthbSAoa29tZW50YXIgZGkgYXdhbCBwZXJueWF0YWFuKQ0KeCA9IDE2DQp6IDwtIHggKyB5ICAjIE1lbmdnYW50aSBuaWxhaSB5YW5nIHN1ZGFoIGRpcmVrYW0gKEtvbWVudGFyIHlhbmcgYWRhIGRpIGFraGlyIHBlcm55YXRhYW4pDQp4ICsgeSAtPiB6ICAjc2FtYSBkZW5nYW4gZGlhdGFzDQpgYGANCg0KIyBPcGVyYXRvcg0KDQpPcGVyYXRvciBtZW5nYXJhaGthbiBjb21waWxlciB1bnR1ayBtZWxha3VrYW4gYmVyYmFnYWkgbWFjYW0gb3BlcmFzaSBwYWRhIGJlYmVyYXBhIHBlbnVnYXNhbiwgZGFuIG1lbnNpbXVsYXNpa2FuIG9wZXJhc2kgbWF0ZW1hdGlzLCBsb2dpa2EsIGRhbiBrZXB1dHVzYW4geWFuZyBkaWxha3VrYW4gdGVyaGFkYXAgc2VrdW1wdWxhbiBCaWxhbmdhbiBLb21wbGVrcywgSW50ZWdlciwgZGFuIE51bWVyaWsgc2ViYWdhaSBpbnB1dC4gDQoNCiMjIEFyaXRtYXRpa2ENCg0KRGlndW5ha2FuIHVudHVrIG1lbnNpbXVsYXNpa2FuIGJlcmJhZ2FpIG9wZXJhc2kgbWF0ZW1hdGlrYSBzZXJ0YSBuaWxhaSBza2FsYXIsIGJpbGFuZ2FuIGtvbXBsZWtzIGF0YXUgdmVrdG9yLiANCg0KfHwNCnw6LS0tLS06fDotLS0tLTp8DQp8KipPcGVyYXRvcioqfCoqU3ltYm9sIHBhZGEgUioqfA0KfFBlbmp1bWxhaGFufCt8DQp8UGVuZ3VyYW5nYW58LXwNCnxQZXJrYWxpYW58KnwNCnxQZW1iYWdpYW58L3wNCnxQZW1hbmdrYXRhbnxefA0KfE1vZHVsb3wlJXwNCnx8DQoNCiMjIyBQZW5lcmFwYW4gQXJpdG1hdGlrYSBQYWRhIFINCg0KYGBge3J9DQp4IDwtIGMoMyw1LDcpICAgIyBtZW11YXQgdmVrdG9yIHgNCnkgPC0gYygyLDQsNikgICAjIG1lbXVhdCB2ZWt0b3IgeQ0KeCArIHkgICAgICAgICAgICMgaGFzaWwgcGVuanVtbGFoYW4gdmVrdG9yIHggZGFuIHkNCmBgYA0KDQoqKlBlbmp1bWxhaGFuIHBhZGEgUioqDQpgYGB7cn0NCnByaW50ICh4K3kpICAjaGFzaWwgcGVuanVtbGFoYW4gdmVrdG9yIHggZGFuIHkNCmBgYA0KDQoqKlBlbmd1cmFuZ2FuIHBhZGEgUioqDQpgYGB7cn0NCnByaW50ICh4LXkpICAjaGFzaWwgcGVuZ3VyYW5nYW4gdmVrdG9yIHggZGFuIHkNCmBgYA0KDQoqKlBlcmthbGlhbiBwYWRhIFIqKg0KYGBge3J9DQpwcmludCAoeCp5KSAgI2hhc2lsIHBlcmthbGlhbiB2ZWt0b3IgeCBkYW4geQ0KYGBgDQoNCioqUGVtYmFnaWFuIHBhZGEgUioqDQpgYGB7cn0NCnByaW50ICh4L3kpICAjaGFzaWwgcGVtYmFnaWFuIHZla3RvciB4IGRhbiB5DQpgYGANCg0KKipQZW1hbmdrYXRhbiBwYWRhIFIqKg0KYGBge3J9DQpwcmludCAoeF55KSAgI2hhc2lsIHBlbWFuZ2thdGFuIHZla3RvciB4IGRhbiB5DQpgYGANCg0KKipNb2R1bG8gcGFkYSBSKioNCmBgYHtyfQ0KcHJpbnQgKHglJXkpICAjaGFzaWwgbW9kdWxvIHZla3RvciB4IGRhbiB5DQpgYGANCg0KVW50dWsgbWVuYW1waWxrYW4ga2V0ZXJhbmdhbiBhdGF1IGtvbWVudGFyIHNlaGluZ2dhIGRhcGF0IG1lbGVrYXQgcGFkYSBwZXJoaXR1bmdhbiBSIGl0dSBzZW5kaXJpIHNlcGVydGkgOg0KDQpgYGB7cn0NCmNhdCgiUGVuanVtbGFoYW4gdmVrdG9yIHggZGFuIHk6IiwgeCArIHksICJcbiIpDQpjYXQoIlBlbmd1cmFuZ2FuIHZla3RvciB4IGRhbiB5OiIsIHggLSB5LCAiXG4iKQ0KY2F0KCJQZXJrYWxpYW4gdmVrdG9yIHggZGFuIHk6IiwgeCAqIHksICJcbiIpDQpjYXQoIlBlbWJhZ2lhbiB2ZWt0b3IgeCBkYW4geToiLCB4IC8geSwgIlxuIikNCmNhdCgiUGVtYW5na2F0YW4gdmVrdG9yIHggZGFuIHk6IiwgeCBeIHksICJcbiIpDQpjYXQoIk1vZHVsbyB2ZWt0b3IgeCBkYW4geToiLCB4ICUlIHksICJcbiIpDQpgYGANCg0KIyMgUmVsYXNpb25hbA0KTWVydXBha2FuIG9wZXJhc2kgcGVyYmFuZGluZ2FuIGFudGFyYSBlbGVtZW4geWFuZyBiZXJzZXN1YWlhbiBwYWRhIHNldGlhcCBwZW5nb3BlcmFzaWFuLiBOaWxhaSBUUlVFIGRpYW5nZ2FwIGxlYmloIGJlc2FyIGRhcmkgRkFMU0UNCg0KfHx8DQp8Oi0tLS0tOnw6LS0tLS06fDotLS0tLTp8DQp8KipPcGVyYXRvcioqfCoqU3ltYm9sIHBhZGEgUioqfCoqS2V0ZXJhbmdhbioqfA0KfEt1cmFuZyBkYXJpfDx8bWVuZ2VtYmFsaWthbiBUUlVFIGppa2Egb3BlcmFuIHBlcnRhbWEgbGViaWgga2VjaWwgZGFyaSBvcGVyYW4ga2VkdWEuIFNlbGFpbiBpdHUgYWthbiBtZW5nZW1iYWxpa2FuIEZBTFNFfA0KfEt1cmFuZyBkYXJpIHNhbWEgZGVuZ2FufDw9fG1lbmdlbWJhbGlrYW4gVFJVRSBqaWthIG9wZXJhbiBwZXJ0YW1hIGt1cmFuZyBkYXJpIGF0YXUgc2FtYSBkZW5nYW4gb3BlcmFuIGtlZHVhLiBTZWxhaW4gaXR1IGFrYW4gbWVuZ2VtYmFsaWthbiBGQUxTRXwNCnxMZWJpaCBiZXNhciBkYXJpfD58bWVuZ2VtYmFsaWthbiBUUlVFIGppa2Egb3BlcmFuIHBlcnRhbWEgbGViaWggYmVzYXIgZGFyaSBvcGVyYW4ga2VkdWEuIFNlbGFpbiBpdHUgYWthbiBtZW5nZW1iYWxpa2FuIEZBTFNFfA0KfExlYmloIGJlc2FyIHNhbWEgZGVuZ2FufD49fG1lbmdlbWJhbGlrYW4gVFJVRSBqaWthIG9wZXJhbiBwZXJ0YW1hIGxlYmloIGJlc2FyIGF0YXUgc2FtYSBkZW5nYW4gb3BlcmFuIGtlZHVhLiBTZWxhaW4gaXR1IGFrYW4gbWVuZ2VtYmFsaWthbiBGQUxTRXwNCnxTYW1hIERlbmdhbnw9PXxNZW5nZW1iYWxpa2FuIFRSVUUgamlrYSBkYW4gaGFueWEgamlrYSBrZWR1YSBzaXNpIG1lbWlsaWtpIG5pbGFpIHNhbWF8DQp8VGlkYWsgc2FtYSBkZW5nYW58IT18TWVuZ2VtYmFsaWthbiBUUlVFIGppa2Egb3BlcmFuIHBlcnRhbWEgdGlkYWsgc2FtYSBkZW5nYW4gb3BlcmFuIGtlZHVhfA0KfHx8DQoNCioqQ29udG9obnlhIGFkYWxhaCBzZWJhZ2FpIGJlcmlrdXQqKg0KDQoqa3VyYW5nIGRhcmkqDQpgYGB7cn0NCnggPC0gYygzLDUsNykgICAjIG1lbXVhdCB2ZWt0b3IgeA0KeSA8LSBjKDIsNCw2KSAgICMgbWVtdWF0IHZla3RvciB5DQpjYXQoIlZla3RvciB4IGt1cmFuZyBkYXJpIFZla3RvciB5OyIsIHggPCB5LCAiXG4iKQ0KYGBgDQoNCiprdXJhbmcgZGFyaSBzYW1hIGRlbmdhbioNCmBgYHtyfQ0KY2F0KCJWZWt0b3IgeCBrdXJhbmcgZGFyaSBzYW1hIGRlbmdhbiBWZWt0b3IgeTsiLCB4IDw9IHksICJcbiIpDQpgYGANCg0KKmxlYmloIGJlc2FyIGRhcmkqDQpgYGB7cn0NCmNhdCgiVmVrdG9yIHggbGViaWggYmVzYXIgZGFyaSBWZWt0b3IgeTsiLCB4ID4geSwgIlxuIikNCmBgYA0KDQoqbGViaWggYmVzYXIgc2FtYSBkZW5nYW4qDQpgYGB7cn0NCmNhdCgiVmVrdG9yIHggbGViaWggYmVzYXIgc2FtYSBkZW5nYW4gVmVrdG9yIHk7IiwgeCA+PSB5LCAiXG4iKQ0KYGBgDQoNCipzYW1hIGRlbmdhbioNCmBgYHtyfQ0KY2F0KCJWZWt0b3IgeCBzYW1hIGRlbmdhbiBWZWt0b3IgeTsiLCB4ID09IHksICJcbiIpDQpgYGANCg0KKnRpZGFrIHNhbWEgZGVuZ2FuKg0KYGBge3J9DQpjYXQoIlZla3RvciB4IHRpZGFrIHNhbWEgZGVuZ2FuIFZla3RvciB5OyIsIHggIT0geSwgIlxuIikNCmBgYA0KDQojIyBMb2dpa2ENCg0KT3BlcmFzaSBLZXB1dHVzYW4gZGlzaW11bGFzaWthbiBvbGVoIG9wZXJhdG9yIExvZ2lzLCBiZXJkYXNhcmthbiBvcGVyYXRvciB5YW5nIGRpdGVudHVrYW4gYW50YXJhIG9wZXJhbiBsYWx1IGRpZXZhbHVhc2kgcGFkYSBuaWxhaSBCb29sZWFuIEJlbmFyIGF0YXVwdW4gc2FsYWguIE5pbGFpIGJpbGFuZ2FuIGJ1bGF0IGJ1a2FuIG5vbCBkaWFuZ2dhcCBzZWJhZ2FpIGRpbGFpIEJFTkFSLCBiYWlrIGJpbGFuZ2FuIGtvbXBsZWtzIG1hdXB1biBiaWxhbmdhbiByZWFsDQoNCnx8fA0KfDotLS0tLTp8Oi0tLS0tOnw6LS0tLS06fA0KfCoqT3BlcmF0b3IqKnwqKlN5bWJvbCBwYWRhIFIqKnwqKktldGVyYW5nYW4qKnwNCnxOT1R8IXxOZWdhc2kva2ViYWxpa2FufA0KfEFORHwmfEtvbmp1bmdzaXwNCnxPUnwkfCR8RGlzanVuZ3NpfA0KfFhPUnxefERpc2p1bmdzaSBQYXJzaWFsfA0KfHx8DQoNCioqQ29udG9obnlhIGFkYWxhaCBzZWJhZ2FpIGJlcmlrdXQqKg0KDQoqTmVnYXNpIHZla3RvciB4Kg0KYGBge3J9DQp4IDwtIGMoMCxUUlVFLEZBTFNFKQ0KeSA8LSBjKFRSVUUsMys0aSw4KQ0KDQojTWVsYWt1a2FuIG9wZXJhc2kgbG9naWthIHBhZGEgb3BlcmFuDQpjYXQoIkxvZ2lrYSBOZWdhc2kgKH4pIHVudHVrIHZla3RvciB4OiIsICF4LCAiXG4iKQ0KYGBgDQoNCipOZWdhc2kgdmVrdG9yIHkqDQpgYGB7cn0NCmNhdCgiTG9naWthIE5lZ2FzaSAofikgdW50dWsgdmVrdG9yIHk6IiwgIXksICJcbiIpDQpgYGANCg0KKmtvbmp1bmdzaSAoRGFuKSoNCmBgYHtyfQ0KY2F0KCJMb2dpa2EgS29uanVuZ3NpIChEYW4pIDoiLCB4ICYgeSwgIlxuIikNCmBgYA0KDQoqRGlzanVuZ3NpIChBdGF1KSoNCmBgYHtyfQ0KY2F0KCJMb2dpa2EgRGlzanVuZ3NpIChBdGF1KSA6IiwgeCAmIHksICJcbiIpDQpgYGANCg0KKkRpc2p1bmdzaSBQYXJzaWFsKg0KYGBge3J9DQpjYXQoIkxvZ2lrYSBEaXNqdW5nc2kgUGFyc2lhbCA6IiwgeCB8fCB5LCAiXG4iKQ0KYGBgDQoNCiMjIExhaW4tTGFpbg0KT3BlcmF0b3IgbGFpbiB5YW5nIGRpZ3VuYWthbiBkYWxhbSBwZW5nZ3VuYWFuIFIgYW50YXJhIGxhaW4gOg0KDQoqKkJlbnR1ayBha2FyKioNCmBgYHtyfQ0KeCA8LSBjKDMsNSw3KSAgICMgbWVtdWF0IHZla3RvciB4DQp5IDwtIGMoMiw0LDYpICAgIyBtZW11YXQgdmVrdG9yIHkNCnNxcnQoeCp5KSAgICAgICAjIEJlbnR1ayBha2FyDQpgYGANCg0KKipMb2dhcml0bWEqKg0KYGBge3J9DQpsb2coeCkgICAgICAjIExvZ2FyaXRtYQ0KYGBgDQoNCioqRWtzcG9uZW4qKg0KYGBge3J9DQpleHAoeSkgICAgICAjIEVrc3BvbmVuDQpgYGANCg0KKipUYW5kYSBrdXJ1bmcqKg0KYGBge3J9DQooeC95KSArIHkgICAgIyBUYW5kYSBLdXJ1bmcNCmBgYA0KDQojIFRpcGUgRGF0YQ0KVGlwZSBkYXRhIG1lcnVwYWthbiBrb25zZXAgcGVudGluZyBkYWxhbSBSLCB1bnR1ayBtZW55aW1wYW4gdGlwZSB5YW5nIGJlcmJlZGEgZGFwYXQgbWVuZ2d1bmFrYW4gdmFyaWFiZWwuIFRpcGUgZGF0YSB5YW5nIG1lbmRhc2FyIGFkYWxhaCANCg0KfHx8DQp8Oi0tLS0tOnw6LS0tLS06fDotLS0tLTp8DQp8KipUaXBlIERhdGEqKnwqKlIqKnwqKlBlbmplbGFzYW4qKnwNCnxEb3VibGUvRmxvYXR8My4yfEJpbGFuZ2FuIHlhbmcgbWVtcHVueWFpIGtvbWF8DQp8SW50ZWdlcnwzfEJpbGFuZ2FuIGJ1bGF0IG58DQp8Qm9sZWFufFRSVUUvRkFMU0V8VFJVRSBiZXJuaWxhaSAxIGRhbiBGQUxTRSBiZXJuaWxhaSAwfA0KfFN0cmluZy9DaGFyYWN0ZXJ8J0NsYXJhZGVsbGFlJ3xrYXJha3Rlci9rYWxpbWF0IGJlcnVwYSBodXJ1ZiB5YW5nIGRpYXBpdCB0YW5kYSAiIGF0YXUgJ3wNCnxDb21wbGV4fDMrNGl8UGFzYW5nYW4gYW5na2EgcmVhbCBkYW4gaW1hamluZXJ8DQp8fHwNCg0KS29kaW5nIFIgeWFuZyBkYXBhdCBkaWd1bmFrYW4gZGVuZ2FuIG1lbmV0YXBrYW4ga2VsaW1hIHRpcGUgZGF0YSBhZGFsYWggc2ViYWdhaSBiZXJpa3V0IDoNCg0KYGBge3J9DQpjMSA8LSAzLjIgICAgICAgICAgICMgVGV0YXBrYW4gbmlsYWkgZGVzaW1hbA0KYzIgPC0gYXMuaW50ZWdlcigzKSAjIFRldGFwa2FuIG5pbGFpIGludGVnZXINCmMyIDwtIDNMICAgICAgICAgICAgIyBDYXJhIGxhaW4gdW50dWsgbWVtdWF0IG5pbGFpIGludGVnZXIgZGkgUg0KYzMgPC0gYyhUUlVFLEZBTFNFKSAjIEJvbGVhbi9Mb2dpY2FsDQpjMyA8LSBhcy5sb2dpY2FsKGMoMCwxKSkgIyBDYXJhIGxhaW4gdW50dWsgbWVtdWF0IEJvbGVhbi9Mb2dpY2FsDQpjNCA8LSBjKCJkIiwnZScsICc0NTYnKSAjU3RyaW5nL0NoYXJhY3Rlcg0KYzUgPC0gNCArIDhpICAgICAgICAjQ29tcGxleA0KYGBgDQoNClVudHVrIG1lbWVyaWtzYSB0aXBlIGRhdGEgZGFsYW0gUiB5YWl0dToNCg0KYGBge3J9DQpjbGFzcyhjMSkgICAgICAgIyBDZXRhayBuYW1hIGtlbGFzIHZhcmlhYmVsDQpjYXQoImNldGFrIHRpcGUgZGF0YSBjMSA6IiwgY2xhc3MoYzEpLCJcbiIpDQpgYGANCg0KYGBge3J9DQp0eXBlb2YoYzEpICAgICAgICMgQ2V0YWsgdGlwZSB2YXJpYWJlbCB4DQpjYXQoImNldGFrIHRpcGUgdmFyaWFiZWwgYzEgOiIsIHR5cGVvZihjMSksIlxuIikNCmBgYA0KDQojIEJhbnR1YW4NCk1lbmdldGFodWkgZGFuIG1lbmNhcmkgYmFudHVhbiBkYWxhbSBSIG1lcnVwYWthbiBzZXN1YXR1IGJhZ2lhbiB5YW5nIHRlcnBlbnRpbmcgZGFsYW0gYmFoYXNhIFIuIA0KYGBge3J9DQojIGhlbHAuc3RhcnQoKSAgICAgICAgICMgTWVudSB1bnR1ayBtZW5kYXBhdCBtZW5hdmlnYXNpIGJhbnR1YW4gbG9rYWwgYmVyYmFzaXMgd2ViDQojID9oZWxwICAgICAgICAgICAgICAgICMgTWVudSB1bnR1ayBtZW5kYXBhdCBtZW5hdmlnYXNpIGJhbnR1YW4gbG9rYWwgYmVyYmFzaXMgd2ViDQojID8gY2xhc3MgICAgICAgICAgICAgICMgbWVuZGFwYXRrYW4gYmFudHVhbiB1bnR1ayBmdW5nc2kgY2xhc3MNCiMgaGVscChjbGFzcykgICAgICAgICAgIyBtZW5kYXBhdGthbiBiYW50dWFuIHVudHVrIGZ1bmdzaSBjbGFzcw0KIyA/P2NsYXNzICAgICAgICAgICAgICAjIGppa2EgdGlkYWsgbWVuZ2V0YWh1aSBmdW5nc2kgeWFuZyBkaWNhcmkNCiMgaGVscC5zZWFyY2goJ2NsYXNzJykgIyBqaWthIHRpZGFrIG1lbmdldGFodWkgZnVuZ3NpIHlhbmcgZGljYXJpDQpgYGANCg0KIyBSZWZlcmVuc2kgDQoqIFtkc2NpZW5jZWxhYnNdKGh0dHBzOi8vcnB1YnMuY29tL2RzY2llbmNlbGFicy9hc2QyKQ==