

Email : diyasaryanugroho@gmail.com
RPubs : https://rpubs.com/diyasarya/
Jurusan : Statistika
Address : ARA Center, Matana University Tower
Jl. CBD Barat Kav, RT.1, Curug Sangereng, Kelapa Dua, Tangerang, Banten 15810.
R Vs Python
R dan Python adalah bahasa pemrograman yang sangat populer, dinamis, digunakan secara luas dalam komunitas data science. R lebih banyak digunakan dalam analisis statistik sementara Python menyediakan pendekatan yang lebih umum mengenal sains data (sehingga dianggap lebih mudah untuk digunakan oleh pemula). Mempelajari kedua bahasa pemrograman ini adalah solusi yang lebih bijak karena keduanya mempunyai kelebihan dan kekurangan masing masing. R dan Python membutuhkan investasi waktu, latihan dengan tutorial, dan melakukan projek projek kecil berbasis LAB hingga penerapan sains data pada kasus-kasus yang sebenarnya.
Persamaan
- R dan Python adalah bahasa pemrograman multi-paradigma. Keduanya mendukung Pemrograman Berorientasi Objek, Pemrograman Imperatif, Pemrograman Prosedural, dll.
- Keduanya adalah bahasa yang ditafsirkan.
- Keduanya dapat digunakan untuk mengembangkan algoritme.
- Keduanya adalah bahasa pemrograman tingkat tinggi.
- Keduanya gratis dan open source.
- Keduanya dapat diintegrasikan dengan aplikasi lain seperti MySQL, Oracle, GitHub, dll.
- Keduanya mendukung file yang berbeda seperti file CSV, file excel, file XML dan file JSON.
- Kedua bahasa tersebut mudah digunakan dan dipelajari.
Perbedaan
| Kriteria |
R |
Python |
| Ruang lingkup |
Data science dan statistik |
Aplikasi dan industri |
| Pengguna |
Akademis dan peneliti |
Programmers & developers |
| IDE (user interface) |
RStudio |
Spyder, Jupyter Notebook, Pycharm, dll |
| Ekstensi |
.R dan .Rmd |
.py dan .ipynb |
| Struktur data |
vektor, list, matriks, array, faktor, dan bingkai data |
list, dictionary, dan tupel |
| Packages dan library |
tidyverse, ggplot2, caret, zoo |
pandas, scipy, scikit-learn, TensorFlow, caret |
| Kelebihan |
memiliki lebih banyak library dan kualitas visualisasi grafik yang dihasilkan sangat tinggi |
sistematika penulisan script yang mudah dibaca, fokus pada kecepatan komputasi, pengembangan web, jaringan otomatisasi, dll |
| Kekurangan |
ketergantungan antar library |
library lebih sedikit dibanding R |
| Integrasi |
fitur RMarkdown dan Shiny |
integrasi aplikasi lebih luas |
Sintaks Dasar
Suatu program di R dan Python terdiri dari tiga hal mendasar: Variabel, operan (nilai) dan Komentar. Variabel digunakan untuk menyimpan suatu nilai, sedangkan Komentar digunakan untuk meningkatkan pemahaman pengguna mengenai skrip atau koding.
Penugasan Variable
R
Perintah penugasan variable ini, dinotasikan dengan 3 cara:
= , digunakan untuk penugasan sederhana.
<- , digunakan untuk penugasan dari sisi kiri.
-> , digunakan untuk penugasan dari sisi kanan.
x = 2
y <- 4
6 -> z
print(c(x,y,z))
## [1] 2 4 6
Python
Perintah penugasan variable ini cukup simple hanya menggunakan = sebagai penugasan sederhana.Untuk menjalankan Python di Rstudio harus menginstall anaconda dan upgrade python menggunakan CMD.exe dan menginstall beberapa packages. untuk menjalankan koding di Rstudio ganti {r} menjadi{python} pada chunk Rmd.
x = 3
y = 5
z = 7
print(c(x,y,z))
## [1] 3 5 7
Catatan: karena saya tidak menginstall anconda di pc maka saya tidak menggunakan ```{python} pada chunk Rmd. Untuk menjalankan yang ada di chunk seharusnya print(x,y,z) saja jika menggunakan python.
Menambahkan Komentar
Menambahkan/Memberikan komentar dalam skrip/koding R dan Python adalah untuk memudahkan anda memahami arti/makna penggunaan suatu perintah/program. Komentar yang ditulis dalam sebuah program tersebut hanya bersifat penjelasan tentang apa yang dilakukannya atau apa yang seharusnya dilakukan oleh sebuah skrip/koding. Perlu dicatat bahwa komentar yang bersifat informasi tidak ada hubungannya dengan logika pemrogaram yang sedang anda gunakan. Mereka benar-benar diabaikan oleh kompiler dan dengan demikian tidak pernah tercermin pada input. Biasanya komentar dituliskan pada satu baris yang tersedia di R dan Python, dengan menggunakan # di awal maupun di akhir pernyataan.
R
# Mengganti nilai x yang sudah direkam (komentar di awal pernyataan)
z <- x + y # Mengganti nilai z yang sudah direkam (komentar di akhir pernyataan)
x + y -> z # sama dengan diatas
Python
# Mengganti nilai x yang sudah direkam (komentar di awal pernyataan)
x=18
z = x + y # Mengganti nilai z yang sudah direkam (komentar di akhir pernyataan)
Operator
Operator adalah simbol yang mengarahkan compiler untuk melakukan berbagai macam operasi terhadap beberapa penugasan. Operator mensimulasikan berbagai operasi matematis, logika, dan keputusan yang dilakukan pada sekumpulan Bilangan Kompleks, Integer, dan Numerik sebagai penugasan masukan (input). R dan Python mendukung sebagian besar empat jenis operator biner antara satu set penugasan. Dalam ini, kita akan melihat berbagai jenis operator yang tersedia di R dan Python dan penggunaannya.
Aritmatika
Penggunaan operator aritmatika dalam program R dan Python adalah untuk mensimulasikan berbagai operasi matematika, seperti penambahan, pengurangan, perkalian, pembagian, dan modulo. Operator aritmatika yang dilakukan bisa saja berupa nilai skalar, bilangan kompleks, atau vektor.
| Operator |
R |
Python |
| Penjumlahan |
+ |
+ |
| Pengurangan |
- |
- |
| Perkalian |
* |
* |
| Divisi/Pembagian |
/ |
/ |
| Pemangkatan |
^ |
** |
| Modulo |
%% |
% |
Berikut contoh penggunaan operator aritmatika di R:
x <- c(2,4,6) # memuat vektor x
y <- c(3,1,5) # memuat vektor y
x+y # hasil penjumlahan vektor x dan y
## [1] 5 5 11
print (x+y) # hasil penjumlahan vektor x dan y
## [1] 5 5 11
print (x-y) # hasil pengurangan vektor x dan y
## [1] -1 3 1
print (x*y) # hasil perkalian vektor x dan y
## [1] 6 4 30
print (x/y) # hasil pembagian vektor x dan y
## [1] 0.6666667 4.0000000 1.2000000
print (x^y) # hasil pemangkatan vektor x dan y
## [1] 8 4 7776
print (x%%y) # hasil modulo vektor x dan y
## [1] 2 0 1
Relasional
Operator relasional melakukan operasi perbandingan antara elemen yang bersesuaian pada setiap operan. Mengembalikan nilai Boolean TRUE jika operan pertama memenuhi relasi dibandingkan dengan operan kedua. Nilai TRUE selalu dianggap lebih besar dari FALSE.
| Operator |
R |
Python |
Keterangan |
| Kurang dari |
< |
< |
Mengembalikan TRUE jika elemen yang bersesuaian pada operan pertama lebih kecil dari operan kedua. Selain itu akan mengambalikan FALSE. |
| Kurang dari sama dengan |
<= |
<= |
Mengembalikan TRUE jika elemen yang bersesuaian pada operan pertama kurang dari atau sama dengan elemen operan kedua. Selain itu akan mengembalikan FALSE. |
| Lebih besar dari |
> |
> |
Mengembalikan TRUE jika elemen yang bersesuaian pada operan pertama lebih besar dari operan kedua. Selain itu akan mengembalikan FALSE. |
| Lebih besar sama dengan |
>= |
>= |
Mengembalikan BENAR jika elemen yang bersesuaian pada operan pertama lebih besar atau sama dengan dari operan kedua. Selain itu akan mengembalikan FALSE. |
| Sama dengan |
== |
== |
Mengembalikan BENAR jika dan hanya jika kedua sisi bernilai sama. |
| Tidak sama dengan |
!= |
!= |
Mengembalikan BENAR jika elemen yang bersesuaian pada operan pertama tidak sama dengan dari operan kedua. |
Berikut contoh penggunaan operator relasional di R:
x <- c(2,1,5) # memuat vektor x
y <- c(3,1,2) # memuat vektor y
cat("Vektor x kurang dari Vektor y:", x < y, "\n")
## Vektor x kurang dari Vektor y: TRUE FALSE FALSE
cat("Vektor x kurang dari sama dengan Vektor y:", x <= y, "\n")
## Vektor x kurang dari sama dengan Vektor y: TRUE TRUE FALSE
cat("Vektor x lebih besar dari Vektor y:", x > y, "\n")
## Vektor x lebih besar dari Vektor y: FALSE FALSE TRUE
cat("Vektor x lebih besar dari sama dengan Vektor y:", x >= y, "\n")
## Vektor x lebih besar dari sama dengan Vektor y: FALSE TRUE TRUE
cat("Vektor x sama dengan Vektor y:", x == y, "\n")
## Vektor x sama dengan Vektor y: FALSE TRUE FALSE
cat("Vektor x tidak sama dengan Vektor y:", x != y, "\n")
## Vektor x tidak sama dengan Vektor y: TRUE FALSE TRUE
Logika
Operator logis mensimulasikan operasi keputusan, berdasarkan operator yang ditentukan antara operan, yang kemudian dievaluasi ke nilai Boolean Benar atau Salah. Nilai bilangan bulat bukan nol dianggap sebagai nilai BENAR, baik itu bilangan kompleks atau bilangan real.
| Operator |
R |
Python |
Keterangan |
| NOT |
! |
! |
Operasi negasi/kebalikan pada status elemen operan |
| AND |
& |
& |
Mengembalikan TRUE jika kedua operan bernilai Benar |
| OR |
\(|\) |
\(|\) |
Mengembalikan TRUE jika salah satu operan Benar |
| XOR |
^ |
^ |
Mengembalikan TRUE jika salah satu dari kedua elemen pertama operan bernilai Benar |
x <- c(1, FALSE, TRUE)
y <- c(FALSE, 0, 5+6i)
# Melakukan operasi logika pada operan
cat("Logika Negasi (~) untuk vektor x:", !x, "\n")
## Logika Negasi (~) untuk vektor x: FALSE TRUE FALSE
cat("Logika Negasi (~) untuk Vektor y:", !y, "\n")
## Logika Negasi (~) untuk Vektor y: TRUE TRUE FALSE
cat("Logika Konjungsi (DAN) :", x & y, "\n")
## Logika Konjungsi (DAN) : FALSE FALSE TRUE
cat("Logika Disjungsi (Atau) :", x | y, "\n")
## Logika Disjungsi (Atau) : TRUE FALSE TRUE
cat("Logika Disjungsi Parsial :", x || y, "\n")
## Logika Disjungsi Parsial : TRUE
Lain-Lain
Berikut ini juga ada beberapa operator yang kemungkinan besar juga akan anda perlukan pada saat akan menggunakan R.
x <- c(2,1,5) # memuat vektor x
y <- c(3,1,2) # memuat vektor y
sqrt(x*y) # Bentuk akar
## [1] 2.449490 1.000000 3.162278
## [1] 0.6931472 0.0000000 1.6094379
## [1] 20.085537 2.718282 7.389056
## [1] 3.666667 2.000000 4.500000
Tipe Data
Dalam pemrograman seperti R dan Python, tipe data merupakan konsep penting. Keduanya dapat menggunakan variabel untuk menyimpan tipe yang berbeda-beda, berikut adalah tipe data paling mendasar yang harus diketahui:
| Tipe Data |
R |
Python |
Penjelasan |
| Double/Float |
5.6 |
5.6 |
Bilangan desimal |
| Integer |
5 |
5 |
Bilangan bulat 1,2,3….n |
| Bolean/Logical |
TRUE/FALSE |
True/False |
Benar bernilai 1 dan Salah bernilai 0 |
| String/Character |
‘Diyasarya’ |
‘Diyasarya’ |
Karakter/kalimat bisa berupa angka, huruf, dll. (diapit dengan tanda ’ atau") |
| Complex |
1+5i |
1+5j |
Pasangan angka real dan imajiner |
Berikut ini adalah koding R yang dapat digunakan untuk menetapkan kelima tipe data diatas:
d1 = 5.6 # Tetapkan nilai desimal
d2 = as.integer(5) # Tetapkan nilai integer
d2 = 5L # cara lain untuk memuat nilai integer di R
d3 = c(TRUE,FALSE) # Bolean/Logical
d3 = as.logical(c(0,1)) # cara lain untuk memuat Bolean/Logical
d5 = c("a", "b", "123") # String/Character
d5 = 1 + 5i # Complex
Untuk memeriksa tipe data dalam R:
class(d1) # cetak nama kelas variabel
## [1] "numeric"
typeof(d1) # cetak tipe variabel
## [1] "double"
Bantuan
Salah satu bagian terpenting dalam bekerja dengan bahasa R adalah mengetahui di mana mencari bantuan. R memiliki beberapa fasilitas in-line, selain berbagai sumber daya bantuan di ekosistem R. Anda dapat menggunakan bantuan untuk fungsi tertentu.
help.start() # menu dimana Anda dapat menavigasi bantuan lokal berbasis web
?help # menu dimana Anda dapat menavigasi bantuan lokal berbasis web
?class # mendapatkan bantuan untuk fungsi 'class'
help(class) # mendapatkan bantuan untuk fungsi 'class'
??class # jika Anda tidak tahu nama fungsi yang Anda cari
help.search('class') # jika Anda tidak tahu nama fungsi yang Anda cari
LS0tDQp0aXRsZTogIlR1Z2FzIDIiDQpzdWJ0aXRsZTogIkFsZ29yaXRtYSBkYW4gU3RydWt0dXIgRGF0YSINCmF1dGhvcjogIkRpeWFzIEFyeWEgTnVncm9obyAoMjAyMTQ5MjAwMDcpIg0KZGF0ZTogImByIGZvcm1hdChTeXMuRGF0ZSgpLCAnJUIgJWQsICVZJylgIg0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDogDQogICAgaHRtbF9kb2N1bWVudDogbnVsbA0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHRoZW1lOiBzYW5kc3RvbmUNCiAgICBjc3M6IHN0eWxlMS5jc3MNCiAgICBoaWdobGlnaHQ6IG1vbm9jaHJvbWUNCi0tLQ0KDQoNCjxpbWcgc3R5bGU9ImZsb2F0OiByaWdodDsgbWFyZ2luOiAwcHggMTAwcHggMHB4IDBweDsgd2lkdGg6MjUlIiBzcmM9InByb2ZpbC5wbmciLz4gDQoNCmBgYHtyIGxvZ28sIGVjaG89RkFMU0UsZmlnLmFsaWduPSdjZW50ZXInLCBvdXQud2lkdGggPSAnMzAlJ30NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJsb2dvbWF0YW5hLnBuZyIpDQpgYGANCg0KRW1haWwgJm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7Jm5ic3A7OiBkaXlhc2FyeWFudWdyb2hvQGdtYWlsLmNvbSA8YnI+DQpSUHVicyAgJm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7OiBodHRwczovL3JwdWJzLmNvbS9kaXlhc2FyeWEvIDxicj4NCkp1cnVzYW4gJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOzogW1N0YXRpc3Rpa2FdKGh0dHBzOi8vbWF0YW5hdW5pdmVyc2l0eS5hYy5pZC8/bHk9YWNhZGVtaWMmYz1zYikgPGJyPg0KQWRkcmVzcyAgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7IDogQVJBIENlbnRlciwgTWF0YW5hIFVuaXZlcnNpdHkgVG93ZXIgPGJyPg0KJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsmbmJzcDsgSmwuIENCRCBCYXJhdCBLYXYsIFJULjEsIEN1cnVnIFNhbmdlcmVuZywgS2VsYXBhIER1YSwgVGFuZ2VyYW5nLCBCYW50ZW4gMTU4MTAuDQoNCioqKioNCg0KDQojIFIgVnMgUHl0aG9uDQoNClIgZGFuIFB5dGhvbiBhZGFsYWggYmFoYXNhIHBlbXJvZ3JhbWFuIHlhbmcgc2FuZ2F0IHBvcHVsZXIsIGRpbmFtaXMsIGRpZ3VuYWthbiBzZWNhcmEgbHVhcyBkYWxhbSBrb211bml0YXMgZGF0YSBzY2llbmNlLiBSIGxlYmloIGJhbnlhayBkaWd1bmFrYW4gZGFsYW0gYW5hbGlzaXMgc3RhdGlzdGlrIHNlbWVudGFyYSBQeXRob24gbWVueWVkaWFrYW4gcGVuZGVrYXRhbiB5YW5nIGxlYmloIHVtdW0gbWVuZ2VuYWwgc2FpbnMgZGF0YSAoc2VoaW5nZ2EgZGlhbmdnYXAgbGViaWggbXVkYWggdW50dWsgZGlndW5ha2FuIG9sZWggcGVtdWxhKS4gTWVtcGVsYWphcmkga2VkdWEgYmFoYXNhIHBlbXJvZ3JhbWFuIGluaSBhZGFsYWggc29sdXNpIHlhbmcgbGViaWggYmlqYWsga2FyZW5hIGtlZHVhbnlhIG1lbXB1bnlhaSBrZWxlYmloYW4gZGFuIGtla3VyYW5nYW4gbWFzaW5nIG1hc2luZy4gUiBkYW4gUHl0aG9uIG1lbWJ1dHVoa2FuIGludmVzdGFzaSB3YWt0dSwgbGF0aWhhbiBkZW5nYW4gdHV0b3JpYWwsIGRhbiBtZWxha3VrYW4gcHJvamVrIHByb2playBrZWNpbCBiZXJiYXNpcyBMQUIgaGluZ2dhIHBlbmVyYXBhbiBzYWlucyBkYXRhIHBhZGEga2FzdXMta2FzdXMgeWFuZyBzZWJlbmFybnlhLiANCg0KIyMjIFBlcnNhbWFhbg0KDQotIFIgZGFuIFB5dGhvbiBhZGFsYWggYmFoYXNhIHBlbXJvZ3JhbWFuIG11bHRpLXBhcmFkaWdtYS4gS2VkdWFueWEgbWVuZHVrdW5nIFBlbXJvZ3JhbWFuIEJlcm9yaWVudGFzaSBPYmplaywgUGVtcm9ncmFtYW4gSW1wZXJhdGlmLCBQZW1yb2dyYW1hbiBQcm9zZWR1cmFsLCBkbGwuDQotIEtlZHVhbnlhIGFkYWxhaCBiYWhhc2EgeWFuZyBkaXRhZnNpcmthbi4NCi0gS2VkdWFueWEgZGFwYXQgZGlndW5ha2FuIHVudHVrIG1lbmdlbWJhbmdrYW4gYWxnb3JpdG1lLg0KLSBLZWR1YW55YSBhZGFsYWggYmFoYXNhIHBlbXJvZ3JhbWFuIHRpbmdrYXQgdGluZ2dpLg0KLSBLZWR1YW55YSBncmF0aXMgZGFuIG9wZW4gc291cmNlLg0KLSBLZWR1YW55YSBkYXBhdCBkaWludGVncmFzaWthbiBkZW5nYW4gYXBsaWthc2kgbGFpbiBzZXBlcnRpIE15U1FMLCBPcmFjbGUsIEdpdEh1YiwgZGxsLg0KLSBLZWR1YW55YSBtZW5kdWt1bmcgZmlsZSB5YW5nIGJlcmJlZGEgc2VwZXJ0aSBmaWxlIENTViwgZmlsZSBleGNlbCwgZmlsZSBYTUwgZGFuIGZpbGUgSlNPTi4NCi0gS2VkdWEgYmFoYXNhIHRlcnNlYnV0IG11ZGFoIGRpZ3VuYWthbiBkYW4gZGlwZWxhamFyaS4NCg0KIyMjIFBlcmJlZGFhbiANCg0KfHx8fA0KfDotLS0tLS06fDotLS0tLS06fDotLS0tLS06fA0KfCoqS3JpdGVyaWEqKnwqKlIqKnwqKlB5dGhvbioqfA0KfFJ1YW5nIGxpbmdrdXB8RGF0YSBzY2llbmNlIGRhbiBzdGF0aXN0aWt8QXBsaWthc2kgZGFuIGluZHVzdHJpfA0KfFBlbmdndW5hfEFrYWRlbWlzIGRhbiBwZW5lbGl0aXxQcm9ncmFtbWVycyAmIGRldmVsb3BlcnN8DQp8SURFICh1c2VyIGludGVyZmFjZSl8UlN0dWRpb3xTcHlkZXIsIEp1cHl0ZXIgTm90ZWJvb2ssIFB5Y2hhcm0sIGRsbHwNCnxFa3N0ZW5zaXxgYGAuUmBgYCBkYW4gYGBgLlJtZGBgYHxgYGAucHlgYGAgZGFuIGBgYC5pcHluYmBgYHwNCnxTdHJ1a3R1ciBkYXRhfHZla3RvciwgbGlzdCwgbWF0cmlrcywgYXJyYXksIGZha3RvciwgZGFuIGJpbmdrYWkgZGF0YXxsaXN0LCBkaWN0aW9uYXJ5LCBkYW4gdHVwZWx8DQp8UGFja2FnZXMgZGFuIGxpYnJhcnl8dGlkeXZlcnNlLCBnZ3Bsb3QyLCBjYXJldCwgem9vfHBhbmRhcywgc2NpcHksIHNjaWtpdC1sZWFybiwgVGVuc29yRmxvdywgY2FyZXR8DQp8S2VsZWJpaGFufG1lbWlsaWtpIGxlYmloIGJhbnlhayBsaWJyYXJ5IGRhbiBrdWFsaXRhcyB2aXN1YWxpc2FzaSBncmFmaWsgeWFuZyBkaWhhc2lsa2FuIHNhbmdhdCB0aW5nZ2l8c2lzdGVtYXRpa2EgcGVudWxpc2FuIHNjcmlwdCB5YW5nIG11ZGFoIGRpYmFjYSwgZm9rdXMgcGFkYSBrZWNlcGF0YW4ga29tcHV0YXNpLCBwZW5nZW1iYW5nYW4gd2ViLCBqYXJpbmdhbiBvdG9tYXRpc2FzaSwgZGxsfA0KfEtla3VyYW5nYW58a2V0ZXJnYW50dW5nYW4gYW50YXIgbGlicmFyeXxsaWJyYXJ5IGxlYmloIHNlZGlraXQgZGliYW5kaW5nIFJ8DQp8SW50ZWdyYXNpfGZpdHVyIFJNYXJrZG93biBkYW4gU2hpbnl8aW50ZWdyYXNpIGFwbGlrYXNpIGxlYmloIGx1YXN8DQoNCiMgU2ludGFrcyBEYXNhcg0KDQpTdWF0dSBwcm9ncmFtIGRpIFIgZGFuIFB5dGhvbiB0ZXJkaXJpIGRhcmkgdGlnYSBoYWwgbWVuZGFzYXI6IFZhcmlhYmVsLCBvcGVyYW4gKG5pbGFpKSBkYW4gS29tZW50YXIuIFZhcmlhYmVsIGRpZ3VuYWthbiB1bnR1ayBtZW55aW1wYW4gc3VhdHUgbmlsYWksIHNlZGFuZ2thbiBLb21lbnRhciBkaWd1bmFrYW4gdW50dWsgbWVuaW5na2F0a2FuIHBlbWFoYW1hbiBwZW5nZ3VuYSBtZW5nZW5haSBza3JpcCBhdGF1IGtvZGluZy4NCg0KIyMgUGVudWdhc2FuIFZhcmlhYmxlDQoNCiMjIyBSDQoNClBlcmludGFoIHBlbnVnYXNhbiB2YXJpYWJsZSBpbmksIGRpbm90YXNpa2FuIGRlbmdhbiAzIGNhcmE6DQoNCi0gYGBgPWBgYCAsIGRpZ3VuYWthbiB1bnR1ayBwZW51Z2FzYW4gc2VkZXJoYW5hLg0KLSBgYGA8LWBgYCAsIGRpZ3VuYWthbiB1bnR1ayBwZW51Z2FzYW4gZGFyaSBzaXNpIGtpcmkuDQotIGBgYC0+YGBgICwgZGlndW5ha2FuIHVudHVrIHBlbnVnYXNhbiBkYXJpIHNpc2kga2FuYW4uDQoNCmBgYHtyfQ0KeCA9IDINCnkgPC0gNA0KNiAtPiB6DQpwcmludChjKHgseSx6KSkNCmBgYA0KDQojIyMgUHl0aG9uDQoNClBlcmludGFoIHBlbnVnYXNhbiB2YXJpYWJsZSBpbmkgY3VrdXAgc2ltcGxlIGhhbnlhIG1lbmdndW5ha2FuIGBgYD1gYGAgc2ViYWdhaSBwZW51Z2FzYW4gc2VkZXJoYW5hLlVudHVrIG1lbmphbGFua2FuIFB5dGhvbiBkaSBSc3R1ZGlvIGhhcnVzIG1lbmdpbnN0YWxsIGFuYWNvbmRhIGRhbiB1cGdyYWRlIHB5dGhvbiBtZW5nZ3VuYWthbiAqKkNNRC5leGUqKiBkYW4gbWVuZ2luc3RhbGwgYmViZXJhcGEgcGFja2FnZXMuIHVudHVrIG1lbmphbGFua2FuIGtvZGluZyBkaSBSc3R1ZGlvIGdhbnRpIGBgYHtyfSBtZW5qYWRpIGBgYHtweXRob259IHBhZGEgY2h1bmsgUm1kLg0KDQpgYGB7cn0NCnggPSAzDQp5ID0gNQ0KeiA9IDcNCnByaW50KGMoeCx5LHopKQ0KYGBgDQpDYXRhdGFuOiBrYXJlbmEgc2F5YSB0aWRhayBtZW5naW5zdGFsbCBhbmNvbmRhIGRpIHBjIG1ha2Egc2F5YSB0aWRhayBtZW5nZ3VuYWthbiBgYGB7cHl0aG9ufSBwYWRhIGNodW5rIFJtZC4gVW50dWsgbWVuamFsYW5rYW4geWFuZyBhZGEgZGkgY2h1bmsgc2VoYXJ1c255YSBwcmludCh4LHkseikgc2FqYSBqaWthIG1lbmdndW5ha2FuIHB5dGhvbi4NCg0KDQojIyBNZW5hbWJhaGthbiBLb21lbnRhcg0KDQpNZW5hbWJhaGthbi9NZW1iZXJpa2FuIGtvbWVudGFyIGRhbGFtIHNrcmlwL2tvZGluZyBSIGRhbiBQeXRob24gYWRhbGFoIHVudHVrIG1lbXVkYWhrYW4gYW5kYSBtZW1haGFtaSBhcnRpL21ha25hIHBlbmdndW5hYW4gc3VhdHUgcGVyaW50YWgvcHJvZ3JhbS4gS29tZW50YXIgeWFuZyBkaXR1bGlzIGRhbGFtIHNlYnVhaCBwcm9ncmFtIHRlcnNlYnV0IGhhbnlhIGJlcnNpZmF0IHBlbmplbGFzYW4gdGVudGFuZyBhcGEgeWFuZyBkaWxha3VrYW5ueWEgYXRhdSBhcGEgeWFuZyBzZWhhcnVzbnlhIGRpbGFrdWthbiBvbGVoIHNlYnVhaCBza3JpcC9rb2RpbmcuIFBlcmx1IGRpY2F0YXQgYmFod2Ega29tZW50YXIgeWFuZyBiZXJzaWZhdCBpbmZvcm1hc2kgdGlkYWsgYWRhIGh1YnVuZ2FubnlhIGRlbmdhbiBsb2dpa2EgcGVtcm9nYXJhbSB5YW5nIHNlZGFuZyBhbmRhIGd1bmFrYW4uIE1lcmVrYSBiZW5hci1iZW5hciBkaWFiYWlrYW4gb2xlaCBrb21waWxlciBkYW4gZGVuZ2FuIGRlbWlraWFuIHRpZGFrIHBlcm5haCB0ZXJjZXJtaW4gcGFkYSBpbnB1dC4gQmlhc2FueWEga29tZW50YXIgZGl0dWxpc2thbiBwYWRhIHNhdHUgYmFyaXMgeWFuZyB0ZXJzZWRpYSBkaSBSIGRhbiBQeXRob24sIGRlbmdhbiBtZW5nZ3VuYWthbiAgIyBkaSBhd2FsIG1hdXB1biBkaSBha2hpciBwZXJueWF0YWFuLg0KDQojIyMgUg0KDQpgYGB7cn0NCiMgTWVuZ2dhbnRpIG5pbGFpIHggeWFuZyBzdWRhaCBkaXJla2FtIChrb21lbnRhciBkaSBhd2FsIHBlcm55YXRhYW4pDQp6IDwtIHggKyB5ICAgIyBNZW5nZ2FudGkgbmlsYWkgeiB5YW5nIHN1ZGFoIGRpcmVrYW0gKGtvbWVudGFyIGRpIGFraGlyIHBlcm55YXRhYW4pDQp4ICsgeSAtPiB6ICAgIyBzYW1hIGRlbmdhbiBkaWF0YXMNCmBgYA0KDQojIyMgUHl0aG9uDQoNCmBgYHtyfQ0KIyBNZW5nZ2FudGkgbmlsYWkgeCB5YW5nIHN1ZGFoIGRpcmVrYW0gKGtvbWVudGFyIGRpIGF3YWwgcGVybnlhdGFhbikNCng9MTgNCnogPSB4ICsgeSAgICMgTWVuZ2dhbnRpIG5pbGFpIHogeWFuZyBzdWRhaCBkaXJla2FtIChrb21lbnRhciBkaSBha2hpciBwZXJueWF0YWFuKQ0KYGBgDQoNCiMgT3BlcmF0b3INCg0KT3BlcmF0b3IgYWRhbGFoIHNpbWJvbCB5YW5nIG1lbmdhcmFoa2FuIGNvbXBpbGVyIHVudHVrIG1lbGFrdWthbiBiZXJiYWdhaSBtYWNhbSBvcGVyYXNpIHRlcmhhZGFwIGJlYmVyYXBhIHBlbnVnYXNhbi4gT3BlcmF0b3IgbWVuc2ltdWxhc2lrYW4gYmVyYmFnYWkgb3BlcmFzaSBtYXRlbWF0aXMsIGxvZ2lrYSwgZGFuIGtlcHV0dXNhbiB5YW5nIGRpbGFrdWthbiBwYWRhIHNla3VtcHVsYW4gQmlsYW5nYW4gS29tcGxla3MsIEludGVnZXIsIGRhbiBOdW1lcmlrIHNlYmFnYWkgcGVudWdhc2FuIG1hc3VrYW4gKGlucHV0KS4gUiBkYW4gUHl0aG9uIG1lbmR1a3VuZyBzZWJhZ2lhbiBiZXNhciBlbXBhdCBqZW5pcyBvcGVyYXRvciBiaW5lciBhbnRhcmEgc2F0dSBzZXQgcGVudWdhc2FuLiBEYWxhbSBpbmksIGtpdGEgYWthbiBtZWxpaGF0IGJlcmJhZ2FpIGplbmlzIG9wZXJhdG9yIHlhbmcgdGVyc2VkaWEgZGkgUiBkYW4gUHl0aG9uIGRhbiBwZW5nZ3VuYWFubnlhLg0KDQojIyBBcml0bWF0aWthDQoNClBlbmdndW5hYW4gb3BlcmF0b3IgYXJpdG1hdGlrYSBkYWxhbSBwcm9ncmFtIFIgZGFuIFB5dGhvbiBhZGFsYWggdW50dWsgbWVuc2ltdWxhc2lrYW4gYmVyYmFnYWkgb3BlcmFzaSBtYXRlbWF0aWthLCBzZXBlcnRpIHBlbmFtYmFoYW4sIHBlbmd1cmFuZ2FuLCBwZXJrYWxpYW4sIHBlbWJhZ2lhbiwgZGFuIG1vZHVsby4gT3BlcmF0b3IgYXJpdG1hdGlrYSB5YW5nIGRpbGFrdWthbiBiaXNhIHNhamEgYmVydXBhIG5pbGFpIHNrYWxhciwgYmlsYW5nYW4ga29tcGxla3MsIGF0YXUgdmVrdG9yLg0KDQp8fHx8DQp8Oi0tLS0tLTp8Oi0tLS0tLTp8Oi0tLS0tLTp8DQp8KipPcGVyYXRvcioqfCoqUioqfCoqUHl0aG9uKip8DQp8UGVuanVtbGFoYW58K3wrfA0KfFBlbmd1cmFuZ2FufC18LXwNCnxQZXJrYWxpYW58KnwqfA0KfERpdmlzaS9QZW1iYWdpYW58L3wvfA0KfFBlbWFuZ2thdGFufF58Kip8DQp8TW9kdWxvfCUlfCV8DQoNCkJlcmlrdXQgY29udG9oIHBlbmdndW5hYW4gb3BlcmF0b3IgYXJpdG1hdGlrYSBkaSBSOg0KDQpgYGB7cn0NCnggPC0gYygyLDQsNikgICAjIG1lbXVhdCB2ZWt0b3IgeA0KeSA8LSBjKDMsMSw1KSAgICMgbWVtdWF0IHZla3RvciB5DQp4K3kgICAgICAgICAgICAgIyBoYXNpbCBwZW5qdW1sYWhhbiB2ZWt0b3IgeCBkYW4geSANCmBgYA0KYGBge3J9DQpwcmludCAoeCt5KSAgICAjIGhhc2lsIHBlbmp1bWxhaGFuIHZla3RvciB4IGRhbiB5DQpgYGANCmBgYHtyfQ0KcHJpbnQgKHgteSkgICAgIyBoYXNpbCBwZW5ndXJhbmdhbiB2ZWt0b3IgeCBkYW4geQ0KYGBgDQpgYGB7cn0NCnByaW50ICh4KnkpICAgICMgaGFzaWwgcGVya2FsaWFuIHZla3RvciB4IGRhbiB5DQpgYGANCmBgYHtyfQ0KcHJpbnQgKHgveSkgICAgIyBoYXNpbCBwZW1iYWdpYW4gdmVrdG9yIHggZGFuIHkNCmBgYA0KYGBge3J9DQpwcmludCAoeF55KSAgICAjIGhhc2lsIHBlbWFuZ2thdGFuIHZla3RvciB4IGRhbiB5IA0KYGBgDQpgYGB7cn0NCnByaW50ICh4JSV5KSAgICMgaGFzaWwgbW9kdWxvIHZla3RvciB4IGRhbiB5DQpgYGANCg0KIyMgUmVsYXNpb25hbA0KDQpPcGVyYXRvciByZWxhc2lvbmFsIG1lbGFrdWthbiBvcGVyYXNpIHBlcmJhbmRpbmdhbiBhbnRhcmEgZWxlbWVuIHlhbmcgYmVyc2VzdWFpYW4gcGFkYSBzZXRpYXAgb3BlcmFuLiBNZW5nZW1iYWxpa2FuIG5pbGFpIEJvb2xlYW4gVFJVRSBqaWthIG9wZXJhbiBwZXJ0YW1hIG1lbWVudWhpIHJlbGFzaSBkaWJhbmRpbmdrYW4gZGVuZ2FuIG9wZXJhbiBrZWR1YS4gTmlsYWkgVFJVRSBzZWxhbHUgZGlhbmdnYXAgbGViaWggYmVzYXIgZGFyaSBGQUxTRS4NCg0KfHx8fA0KfDotLS0tLS06fDotLS0tLS06fDotLS0tLS06fDotLS0tLS0tOnwNCnwqKk9wZXJhdG9yKip8KipSKip8KipQeXRob24qKnwqKktldGVyYW5nYW4qKnwNCnxLdXJhbmcgZGFyaXw8fDx8TWVuZ2VtYmFsaWthbiBUUlVFIGppa2EgZWxlbWVuIHlhbmcgYmVyc2VzdWFpYW4gcGFkYSBvcGVyYW4gcGVydGFtYSBsZWJpaCBrZWNpbCBkYXJpIG9wZXJhbiBrZWR1YS4gU2VsYWluIGl0dSBha2FuIG1lbmdhbWJhbGlrYW4gRkFMU0UufA0KfEt1cmFuZyBkYXJpIHNhbWEgZGVuZ2FufDw9fDw9fE1lbmdlbWJhbGlrYW4gVFJVRSBqaWthIGVsZW1lbiB5YW5nIGJlcnNlc3VhaWFuIHBhZGEgb3BlcmFuIHBlcnRhbWEga3VyYW5nIGRhcmkgYXRhdSBzYW1hIGRlbmdhbiBlbGVtZW4gb3BlcmFuIGtlZHVhLiBTZWxhaW4gaXR1IGFrYW4gbWVuZ2VtYmFsaWthbiBGQUxTRS58DQp8TGViaWggYmVzYXIgZGFyaXw+fD58TWVuZ2VtYmFsaWthbiBUUlVFIGppa2EgZWxlbWVuIHlhbmcgYmVyc2VzdWFpYW4gcGFkYSBvcGVyYW4gcGVydGFtYSBsZWJpaCBiZXNhciBkYXJpIG9wZXJhbiBrZWR1YS4gU2VsYWluIGl0dSBha2FuIG1lbmdlbWJhbGlrYW4gRkFMU0UufA0KfExlYmloIGJlc2FyIHNhbWEgZGVuZ2FufD49fD49fE1lbmdlbWJhbGlrYW4gQkVOQVIgamlrYSBlbGVtZW4geWFuZyBiZXJzZXN1YWlhbiBwYWRhIG9wZXJhbiBwZXJ0YW1hIGxlYmloIGJlc2FyIGF0YXUgc2FtYSBkZW5nYW4gZGFyaSBvcGVyYW4ga2VkdWEuIFNlbGFpbiBpdHUgYWthbiBtZW5nZW1iYWxpa2FuIEZBTFNFLnwNCnxTYW1hIGRlbmdhbnw9PXw9PXxNZW5nZW1iYWxpa2FuIEJFTkFSIGppa2EgZGFuIGhhbnlhIGppa2Ega2VkdWEgc2lzaSBiZXJuaWxhaSBzYW1hLnwNCnxUaWRhayBzYW1hIGRlbmdhbnwhPXwhPXxNZW5nZW1iYWxpa2FuIEJFTkFSIGppa2EgZWxlbWVuIHlhbmcgYmVyc2VzdWFpYW4gcGFkYSBvcGVyYW4gcGVydGFtYSB0aWRhayBzYW1hIGRlbmdhbiBkYXJpIG9wZXJhbiBrZWR1YS58DQoNCkJlcmlrdXQgY29udG9oIHBlbmdndW5hYW4gb3BlcmF0b3IgcmVsYXNpb25hbCBkaSBSOg0KDQpgYGB7cn0NCnggPC0gYygyLDEsNSkgICAgICMgbWVtdWF0IHZla3RvciB4DQp5IDwtIGMoMywxLDIpICAgICAjIG1lbXVhdCB2ZWt0b3IgeQ0KY2F0KCJWZWt0b3IgeCBrdXJhbmcgZGFyaSBWZWt0b3IgeToiLCB4IDwgeSwgIlxuIikNCmBgYA0KDQpgYGB7cn0NCmNhdCgiVmVrdG9yIHgga3VyYW5nIGRhcmkgc2FtYSBkZW5nYW4gVmVrdG9yIHk6IiwgeCA8PSB5LCAiXG4iKQ0KYGBgDQpgYGB7cn0NCmNhdCgiVmVrdG9yIHggbGViaWggYmVzYXIgZGFyaSBWZWt0b3IgeToiLCB4ID4geSwgIlxuIikNCmBgYA0KYGBge3J9DQpjYXQoIlZla3RvciB4IGxlYmloIGJlc2FyIGRhcmkgc2FtYSBkZW5nYW4gVmVrdG9yIHk6IiwgeCA+PSB5LCAiXG4iKQ0KYGBgDQpgYGB7cn0NCmNhdCgiVmVrdG9yIHggc2FtYSBkZW5nYW4gVmVrdG9yIHk6IiwgeCA9PSB5LCAiXG4iKQ0KYGBgDQpgYGB7cn0NCmNhdCgiVmVrdG9yIHggdGlkYWsgc2FtYSBkZW5nYW4gVmVrdG9yIHk6IiwgeCAhPSB5LCAiXG4iKQ0KYGBgDQoNCg0KIyMgTG9naWthDQoNCk9wZXJhdG9yIGxvZ2lzIG1lbnNpbXVsYXNpa2FuIG9wZXJhc2kga2VwdXR1c2FuLCBiZXJkYXNhcmthbiBvcGVyYXRvciB5YW5nIGRpdGVudHVrYW4gYW50YXJhIG9wZXJhbiwgeWFuZyBrZW11ZGlhbiBkaWV2YWx1YXNpIGtlIG5pbGFpIEJvb2xlYW4gQmVuYXIgYXRhdSBTYWxhaC4gTmlsYWkgYmlsYW5nYW4gYnVsYXQgYnVrYW4gbm9sIGRpYW5nZ2FwIHNlYmFnYWkgbmlsYWkgQkVOQVIsIGJhaWsgaXR1IGJpbGFuZ2FuIGtvbXBsZWtzIGF0YXUgYmlsYW5nYW4gcmVhbC4NCg0KfHx8fA0KfDotLS0tLS06fDotLS0tLS06fDotLS0tLS06fDotLS0tLS0tOnwNCnwqKk9wZXJhdG9yKip8KipSKip8KipQeXRob24qKnwqKktldGVyYW5nYW4qKnwNCnxOT1R8IXwhfE9wZXJhc2kgbmVnYXNpL2tlYmFsaWthbiBwYWRhIHN0YXR1cyBlbGVtZW4gb3BlcmFufA0KfEFORHwmfCZ8TWVuZ2VtYmFsaWthbiBUUlVFIGppa2Ega2VkdWEgb3BlcmFuIGJlcm5pbGFpIEJlbmFyfA0KfE9SfCAkfCQgfCAkfCQgfE1lbmdlbWJhbGlrYW4gVFJVRSBqaWthIHNhbGFoIHNhdHUgb3BlcmFuIEJlbmFyfA0KfFhPUnxefF58TWVuZ2VtYmFsaWthbiBUUlVFIGppa2Egc2FsYWggc2F0dSBkYXJpIGtlZHVhIGVsZW1lbiBwZXJ0YW1hIG9wZXJhbiBiZXJuaWxhaSBCZW5hcnwNCg0KYGBge3J9DQp4IDwtIGMoMSwgRkFMU0UsIFRSVUUpDQp5IDwtIGMoRkFMU0UsIDAsIDUrNmkpDQoNCiMgTWVsYWt1a2FuIG9wZXJhc2kgbG9naWthIHBhZGEgb3BlcmFuDQpjYXQoIkxvZ2lrYSBOZWdhc2kgKH4pIHVudHVrIHZla3RvciB4OiIsICF4LCAiXG4iKQ0KYGBgDQpgYGB7cn0NCmNhdCgiTG9naWthIE5lZ2FzaSAofikgdW50dWsgVmVrdG9yIHk6IiwgIXksICJcbiIpDQpgYGANCmBgYHtyfQ0KY2F0KCJMb2dpa2EgS29uanVuZ3NpIChEQU4pIDoiLCB4ICYgeSwgIlxuIikNCmBgYA0KYGBge3J9DQpjYXQoIkxvZ2lrYSBEaXNqdW5nc2kgKEF0YXUpIDoiLCB4IHwgeSwgIlxuIikNCmBgYA0KYGBge3J9DQpjYXQoIkxvZ2lrYSBEaXNqdW5nc2kgUGFyc2lhbCA6IiwgeCB8fCB5LCAiXG4iKQ0KYGBgDQoNCg0KIyMgTGFpbi1MYWluIA0KDQpCZXJpa3V0IGluaSBqdWdhIGFkYSBiZWJlcmFwYSBvcGVyYXRvciB5YW5nIGtlbXVuZ2tpbmFuIGJlc2FyIGp1Z2EgYWthbiBhbmRhIHBlcmx1a2FuIHBhZGEgc2FhdCBha2FuIG1lbmdndW5ha2FuIFIuDQoNCmBgYHtyfQ0KeCA8LSBjKDIsMSw1KSAgICAgIyBtZW11YXQgdmVrdG9yIHgNCnkgPC0gYygzLDEsMikgICAgICMgbWVtdWF0IHZla3RvciB5DQpzcXJ0KHgqeSkgICAgICAgICAjIEJlbnR1ayBha2FyDQpgYGANCmBgYHtyfQ0KbG9nKHgpICAgICAgICAgICAgIyBMb2dhcml0bWENCmBgYA0KYGBge3J9DQpleHAoeSkgICAgICAgICAgICAjIEVrc3BvbmVuDQpgYGANCmBgYHtyfQ0KKHgveSkgKyB5ICAgICAgICAgIyBUYW5kYSBrdXJ1bmcNCmBgYA0KDQojIFRpcGUgRGF0YQ0KDQpEYWxhbSBwZW1yb2dyYW1hbiBzZXBlcnRpIFIgZGFuIFB5dGhvbiwgdGlwZSBkYXRhIG1lcnVwYWthbiBrb25zZXAgcGVudGluZy4gS2VkdWFueWEgZGFwYXQgbWVuZ2d1bmFrYW4gdmFyaWFiZWwgdW50dWsgbWVueWltcGFuIHRpcGUgeWFuZyBiZXJiZWRhLWJlZGEsIGJlcmlrdXQgYWRhbGFoIHRpcGUgZGF0YSBwYWxpbmcgbWVuZGFzYXIgeWFuZyBoYXJ1cyBkaWtldGFodWk6DQoNCnx8fHwNCnw6LS0tLS0tOnw6LS0tLS0tOnw6LS0tLS0tOnw6LS0tLS0tLTp8DQp8KipUaXBlIERhdGEqKnwqKlIqKnwqKlB5dGhvbioqfCoqUGVuamVsYXNhbioqfA0KfERvdWJsZS9GbG9hdHw1LjZ8NS42fEJpbGFuZ2FuIGRlc2ltYWx8DQp8SW50ZWdlcnw1fDV8QmlsYW5nYW4gYnVsYXQgMSwyLDMuLi4ubnwNCnxCb2xlYW4vTG9naWNhbHxUUlVFL0ZBTFNFfFRydWUvRmFsc2V8QmVuYXIgYmVybmlsYWkgMSBkYW4gU2FsYWggYmVybmlsYWkgMHwNCnxTdHJpbmcvQ2hhcmFjdGVyfCdEaXlhc2FyeWEnfCdEaXlhc2FyeWEnfEthcmFrdGVyL2thbGltYXQgYmlzYSBiZXJ1cGEgYW5na2EsIGh1cnVmLCBkbGwuIChkaWFwaXQgZGVuZ2FuIHRhbmRhICcgYXRhdSIpfA0KfENvbXBsZXh8MSs1aXwxKzVqfFBhc2FuZ2FuIGFuZ2thIHJlYWwgZGFuIGltYWppbmVyfA0KDQpCZXJpa3V0IGluaSBhZGFsYWgga29kaW5nIFIgeWFuZyBkYXBhdCBkaWd1bmFrYW4gdW50dWsgbWVuZXRhcGthbiBrZWxpbWEgdGlwZSBkYXRhIGRpYXRhczoNCg0KYGBge3J9DQpkMSA9IDUuNiAgICAgICAgICAgICAgICAgICAjIFRldGFwa2FuIG5pbGFpIGRlc2ltYWwNCmQyID0gYXMuaW50ZWdlcig1KSAgICAgICAgICMgVGV0YXBrYW4gbmlsYWkgaW50ZWdlcg0KZDIgPSA1TCAgICAgICAgICAgICAgICAgICAgIyBjYXJhIGxhaW4gdW50dWsgbWVtdWF0IG5pbGFpIGludGVnZXIgZGkgUg0KZDMgPSBjKFRSVUUsRkFMU0UpICAgICAgICAgIyBCb2xlYW4vTG9naWNhbA0KZDMgPSBhcy5sb2dpY2FsKGMoMCwxKSkgICAgIyBjYXJhIGxhaW4gdW50dWsgbWVtdWF0IEJvbGVhbi9Mb2dpY2FsDQpkNSA9IGMoImEiLCAiYiIsICIxMjMiKSAgICAjIFN0cmluZy9DaGFyYWN0ZXINCmQ1ID0gMSArIDVpICAgICAgICAgICAgICAgICMgQ29tcGxleA0KYGBgDQoNClVudHVrIG1lbWVyaWtzYSB0aXBlIGRhdGEgZGFsYW0gUjoNCg0KYGBge3J9DQpjbGFzcyhkMSkgICAgICAjIGNldGFrIG5hbWEga2VsYXMgdmFyaWFiZWwNCmBgYA0KYGBge3J9DQp0eXBlb2YoZDEpICAgICAjIGNldGFrIHRpcGUgdmFyaWFiZWwNCmBgYA0KDQojIEJhbnR1YW4gDQoNClNhbGFoIHNhdHUgYmFnaWFuIHRlcnBlbnRpbmcgZGFsYW0gYmVrZXJqYSBkZW5nYW4gYmFoYXNhIFIgYWRhbGFoIG1lbmdldGFodWkgZGkgbWFuYSBtZW5jYXJpIGJhbnR1YW4uIFIgbWVtaWxpa2kgYmViZXJhcGEgZmFzaWxpdGFzIGluLWxpbmUsIHNlbGFpbiBiZXJiYWdhaSBzdW1iZXIgZGF5YSBiYW50dWFuIGRpIGVrb3Npc3RlbSBSLiBBbmRhIGRhcGF0IG1lbmdndW5ha2FuIGJhbnR1YW4gdW50dWsgZnVuZ3NpIHRlcnRlbnR1Lg0KDQoNCmBgYHtyfSMNCmhlbHAuc3RhcnQoKSAgICAgICAgICAgICAjIG1lbnUgZGltYW5hIEFuZGEgZGFwYXQgbWVuYXZpZ2FzaSBiYW50dWFuIGxva2FsIGJlcmJhc2lzIHdlYg0KP2hlbHAgICAgICAgICAgICAgICAgICAgICMgbWVudSBkaW1hbmEgQW5kYSBkYXBhdCBtZW5hdmlnYXNpIGJhbnR1YW4gbG9rYWwgYmVyYmFzaXMgd2ViDQo/Y2xhc3MgICAgICAgICAgICAgICAgICAgIyBtZW5kYXBhdGthbiBiYW50dWFuIHVudHVrIGZ1bmdzaSAnY2xhc3MnDQpoZWxwKGNsYXNzKSAgICAgICAgICAgICAgIyBtZW5kYXBhdGthbiBiYW50dWFuIHVudHVrIGZ1bmdzaSAnY2xhc3MnDQo/P2NsYXNzICAgICAgICAgICAgICAgICAgIyBqaWthIEFuZGEgdGlkYWsgdGFodSBuYW1hIGZ1bmdzaSB5YW5nIEFuZGEgY2FyaQ0KaGVscC5zZWFyY2goJ2NsYXNzJykgICAgICMgamlrYSBBbmRhIHRpZGFrIHRhaHUgbmFtYSBmdW5nc2kgeWFuZyBBbmRhIGNhcmkNCmBgYA0K