

Email : yeni.arwanti@student.matanauniveristy.ac.id
RPubs : https://rpubs.com/yeninawn/
Jurusan : Fisika Medis
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
Berikut adalah tabel secara ringkas membandingkan dua bahasa pemrograman Python dan R:
| Kriteria |
R |
Python |
| Ruang lingkup |
Data science dan statistik |
Aplikasi dan industri |
| Pengguna |
Akademisi dab peneliti |
Programmers & developer |
| 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 |
| Package 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 Variabel
R
Dalam R penugasan suatu program biasanya menggunakan suatu variabel yang dicadangkan untuk dapat merekam berbagai jenis data sesuai nama yang diberikan ke lokasi penyimpanan/memori. Perintah penugasan variabel ini,dapat di notasikan dengan tiga cara:
- = ,di gunakan untuk penugasan
- <- ,di gunakan untuk penugasan dari sisi kiri
- -> ,di gunakan untukpenugasan dari sisi kanan
a=3
b<-1
3+1->c
print(c(a,b,c))
## [1] 3 1 4
Python
Untuk menjalankan Python dengan Rstudio, install-lah Anaconda pada PC anda dengan baik, dan jangan lupa melakukan upgrade python tersebut menggunakan CMD.exe pada anaconda navigator dengan menjalankan koding berikut:
conda update --all
conda create -n py38 python=3.8
conda activate py38
Kemudian jalankan koding berikut:
library(reticulate)
library(Rcpp)
# conda_list()
use_condaenv("py38", required = TRUE)
Setelah itu anda dapat menjalankan coding python pada Rstudio dengan mengganti {r} dengan menjadi{pthon} pada chunk Rmd anda, dan jalankan coding berikut:
x = 4
y = 5
z = 6
print(x,y,z)
## [1] 4
Selain menyimpan atau pengisian nilai, ada juga menjumlahkan, mengurangi, perkalian, pembagian, dsb.
| Operator |
Simbol |
| Penjumlahan |
+= |
| Pengurangan |
-= |
| Perkalian |
*= |
| Pembagian |
/= |
| Sisa Bagi |
%= |
| Pemangkatan |
**= |
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 bersifatinformasi tidak ada hubungannya dengan logika pemrogaram yang sedang anda gunakan. Merekabenar-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.
# Penjumlahan dari logaritma
a=5 # Nilai a
b=1 # Nilai b
c=a+b # Nilai c
d=log(c) # Nilai d
print(c(log(c)))
## [1] 1.791759
Berikut ini adalah contoh menambahkan komentar pada operasi penambahan R:
a=5 # Nilai a sama dengan 5, dan lebih besar dari nilai b
b=1 # Nilai a sama dengan 5, dan lebih besar dari nilai b
c=a+b # Nilai c sama dengan penambahan a dengan b
print(c(a+b+c)) # Hasil penambahan a,b, dan c
## [1] 12
print(c(a,b,c)) # Nilai a,b, dan c
## [1] 5 1 6
Berikut ini adalah contoh menambahkan komentar pada operasi pegurangan R:
a=5 # Nilai a sama dengan 5, dan lebih besar dari nilai b
b=1 # Nilai a sama dengan 1, dan lebih kecil dari nilai b
c=a-b # Nilai c sama dengan a dikurang b
print(c(a-b-c)) # Hasil pengurangan a,b, dan c
## [1] 0
Berikut ini adalah contoh menambahkan komentar pada operasi perkalian di dalam R:
a=5 # Nilai a sama dengan 5, dan lebih besar dari nilai b
b=1 # Nilai a sama dengan 1, dan lebih kecil dari nilai b
c=a*b # Nilai c sama dengan a dikali oleh b
print(c(a*b*c)) # Hasil perkalian a,b, dan c
## [1] 25
Berikut ini adalah contoh menambahkan komentar pada operasi pembagian di dalam R:
a=5 # Nilai a sama dengan 5, dan lebih besar dari nilai b
b=1 # Nilai a sama dengan 1, dan lebih kecil dari nilai b
c=a/b # Nilai c sama dengan a dibagi oleh b
print(c(a/b/c)) # Hasil pembagian a,b,c
## [1] 1
Berikut ini adalah contoh menambahkan komentar pada operasi pemangkatan di dalam R:
a=5 # Nilai a sama dengan 5, dan lebih besar dari nilai b
b=1 # Nilai a sama dengan 1, dan lebih kecil dari nilai b
c=a^b # Nilai c sama dengan a dipangkatkan oleh b
print(c(a^b^c)) # Hasil pemangkatan a,b,c
## [1] 5
Berikut ini adalah contoh menambahkan komentar pada operasi modulo di dalam R:
a=5 # Nilai a sama dengan 5, dan lebih besar dari nilai b
b=1 # Nilai a sama dengan 1, dan lebih kecil dari nilai b
print(c(a%%b)) # Hasil modulo a % b
## [1] 0
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 ini adalah contoh operasi Aritmatika penambahan R:
a=5 # Nilai a sama dengan 5, dan lebih besar dari nilai b
b=1 # Nilai a sama dengan 5, dan lebih besar dari nilai b
c=a+b # Nilai c sama dengan penambahan a dengan b
print(c(a+b+c)) # Hasil penambahan a,b, dan c
## [1] 12
print(c(a,b,c)) # Nilai a,b, dan c
## [1] 5 1 6
Berikut ini adalah contoh operasi Aritmatika pegurangan R:
a=5 # Nilai a sama dengan 5, dan lebih besar dari nilai b
b=1 # Nilai a sama dengan 1, dan lebih kecil dari nilai b
c=a-b # Nilai c sama dengan a dikurang b
print(c(a-b-c)) # Hasil pengurangan a,b, dan c
## [1] 0
Berikut ini adalah contoh operasi Aritmatika perkalian di dalam R:
a=5 # Nilai a sama dengan 5, dan lebih besar dari nilai b
b=1 # Nilai a sama dengan 1, dan lebih kecil dari nilai b
c=a*b # Nilai c sama dengan a dikali oleh b
print(c(a*b*c)) # Hasil perkalian a,b, dan c
## [1] 25
Berikut ini adalah contoh operasi Aritmatika pembagian di dalam R:
a=5 # Nilai a sama dengan 5, dan lebih besar dari nilai b
b=1 # Nilai a sama dengan 1, dan lebih kecil dari nilai b
c=a/b # Nilai c sama dengan a dibagi oleh b
print(c(a/b/c)) # Hasil pembagian a,b,c
## [1] 1
Berikut ini adalah contoh operasi Aritmatika pemangkatan di dalam R:
a=5 # Nilai a sama dengan 5, dan lebih besar dari nilai b
b=1 # Nilai a sama dengan 1, dan lebih kecil dari nilai b
c=a^b # Nilai c sama dengan a dipangkatkan oleh b
print(c(a^b^c)) # Hasil pemangkatan a,b,c
## [1] 5
Berikut ini adalah operasi Aritmatika modulo di dalam R:
a=5 # Nilai a sama dengan 5, dan lebih besar dari nilai b
b=1 # Nilai a sama dengan 1, dan lebih kecil dari nilai b
print(c(a%%b)) # Hasil modulo a % b
## [1] 0
Relasional
| Operator |
R |
Python |
| Kurang dari |
< |
< |
| Kurang dari sama dengan |
<= |
<= |
| Lebih besar dari |
>= |
>= |
| Lebih besar sama dengan |
>= |
>= |
| Sama dengan |
== |
== |
| Tidak Sama Dengan |
!= |
!= |
Berikut contoh penggunaan operator relasional di R:
x <- c(4,2,7) # memuat vektor x
y <- c(6,8,1) # memuat vektor y
cat("Vektor x kurang dari Vektor y:", x < y, "\n")
## Vektor x kurang dari Vektor y: TRUE TRUE 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 FALSE TRUE
cat("Vektor x sama dengan Vektor y:", x == y, "\n")
## Vektor x sama dengan Vektor y: FALSE FALSE FALSE
cat("Vektor x tidak sama dengan Vektor y:", x != y, "\n")
## Vektor x tidak sama dengan Vektor y: TRUE TRUE 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 |
|
|
|
| XOR |
^ |
^ |
Mengembalikan TRUE jika salah satu dari kedua elemen pertama operan bernilai Benar |
Berikut penggunaan logika di R:
x <- c(0,TRUE,FALSE)
y <- c(TRUE,0,1,4+3i)
# Melakukan Operasi Logika Operan
cat("Logika Negasi (~) untuk vektor x:", !x, "\n")
## Logika Negasi (~) untuk vektor x: TRUE FALSE TRUE
cat("Logika Negasi (~) untuk vektor y :", !y, "\n")
## Logika Negasi (~) untuk vektor y : FALSE TRUE FALSE FALSE
cat("Logika Konjungsi (Dan) :", x & y, "\n")
## Warning in x & y: longer object length is not a multiple of shorter object
## length
## Logika Konjungsi (Dan) : FALSE FALSE FALSE FALSE
cat("Logika Disjungsi (Atau) :", x | y, "\n")
## Warning in x | y: longer object length is not a multiple of shorter object
## length
## Logika Disjungsi (Atau) : TRUE TRUE TRUE TRUE
cat("Logika Disjungsi Parsial:", x || y, "\n")
## Logika Disjungsi Parsial: TRUE
Lain-Lain
Berikut ini terdapat beberapa operator yang juga anda perlukan pada saat akan menggunakan R :
x <- c(6,3,9) # memuat vektor x
y <- c(2,6,8) # memuat vektor y
sqrt(x*y) # Bentuk akar
## [1] 3.464102 4.242641 8.485281
## [1] 1.791759 1.098612 2.197225
## [1] 0.6931472 1.7917595 2.0794415
## [1] 403.42879 20.08554 8103.08393
## [1] 7.389056 403.428793 2980.957987
## [1] 5.000 6.500 9.125
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 |
‘Yeninawn’ |
‘Yeninawn’ |
Karakter/kalimat bisa berupa angka, huruf, dll. (diapit dengan tanda ’ atau") |
| Complex |
1+5i |
1+5j |
Pasangan angka dan imajiner |
R
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
class(d1) # cetak nama kelas variabel
## [1] "numeric"
typeof(d1) # cetak tipe variabel
## [1] "double"
Python
Berikut ini adalah koding Python yang dapat digunakan untuk menetapkan kelima tipe data diatas:
d1 = 5.6 # Tetapkan nilai desismal
d2 = 5 # Tetapkan nilai interger
d3 = [True,False] # List Bolean/Logical
d4 = ["a",'b','123'] # List String/Character
d5 = 1 + 5j # Complex
Untuk memeriksa tipe data python :
type(d5) # Cetak tipe variabel x
Bantuan
Salah satu bagian penting dalam bekerja dengan bahasa R adalah bagaimana mencari bantuan. R memiliki be-berapa fasilitas in-line,selain beberapa daya sumber bantuan di ekosistem R.Anda dapat mengunakan bantuan untuk fungsi tertentu.
Berikut bantuan pada R:
help.start() # menu di mana Anda dapat menavigasi bantuan lokal berbasis web
## starting httpd help server ... done
## If nothing happens, you should open
## 'http://127.0.0.1:29010/doc/html/index.html' yourself
?help # menu di mana 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
LS0tDQp0aXRsZTogIkFsZ29yaXRtYSBkYW4gU3RydWt0dXIgRGF0YSINCnN1YnRpdGxlOiAiVHVnYXMgMiINCmF1dGhvcjogIlllbmkgTnVyIEFyd2FudGkgKDIwMjE0NTIwMDExKSINCmRhdGU6ICJgciBmb3JtYXQoU3lzLkRhdGUoKSwgJyVCICVkLCAlWScpYCINCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIGh0bWxfZG9jdW1lbnQ6IG51bGwNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICB0aGVtZTogc2FuZHN0b25lDQogICAgY3NzOiBzdHlsZTEuY3NzDQogICAgaGlnaGxpZ2h0OiBtb25vY2hyb21lDQotLS0NCg0KDQo8aW1nIHN0eWxlPSJmbG9hdDogcmlnaHQ7IG1hcmdpbjogMHB4IDEwMHB4IDBweCAwcHg7IHdpZHRoOjIzJSIgc3JjPSJtZS5wbmciLz4gDQoNCmBgYHtyIGxvZ28sIGVjaG89RkFMU0UsZmlnLmFsaWduPSdjZW50ZXInLCBvdXQud2lkdGggPSAnMzAlJ30NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJsb2dvLnBuZyIpDQpgYGANCg0KRW1haWwgJm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7Jm5ic3A7OiAgeWVuaS5hcndhbnRpQHN0dWRlbnQubWF0YW5hdW5pdmVyaXN0eS5hYy5pZCA8YnI+DQpSUHVicyAgJm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7OiBodHRwczovL3JwdWJzLmNvbS95ZW5pbmF3bi8gPGJyPg0KSnVydXNhbiAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7OiBbRmlzaWthIE1lZGlzXShodHRwczovL21hdGFuYXVuaXZlcnNpdHkuYWMuaWQvP2x5PWFjYWRlbWljJmM9c2IpIDxicj4NCkFkZHJlc3MgICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyA6IEFSQSBDZW50ZXIsIE1hdGFuYSBVbml2ZXJzaXR5IFRvd2VyIDxicj4NCiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7Jm5ic3A7IEpsLiBDQkQgQmFyYXQgS2F2LCBSVC4xLCBDdXJ1ZyBTYW5nZXJlbmcsIEtlbGFwYSBEdWEsIFRhbmdlcmFuZywgQmFudGVuIDE1ODEwLg0KDQoqKioqDQoNCiMgUiBWcyBQeXRob24NCg0KUiBkYW4gUHl0aG9uIGFkYWxhaCBiYWhhc2EgcGVtcm9ncmFtYW4geWFuZyBzYW5nYXQgcG9wdWxlciwgZGluYW1pcywgZGlndW5ha2FuIHNlY2FyYSBsdWFzIGRhbGFtIGtvbXVuaXRhcyBkYXRhIHNjaWVuY2UuIFIgbGViaWggYmFueWFrIGRpZ3VuYWthbiBkYWxhbSBhbmFsaXNpcyBzdGF0aXN0aWsgc2VtZW50YXJhIFB5dGhvbiBtZW55ZWRpYWthbiBwZW5kZWthdGFuIHlhbmcgbGViaWggdW11bSBtZW5nZW5hbCBzYWlucyBkYXRhIChzZWhpbmdnYSBkaWFuZ2dhcCBsZWJpaCBtdWRhaCB1bnR1ayBkaWd1bmFrYW4gb2xlaCBwZW11bGEpLiBNZW1wZWxhamFyaSBrZWR1YSBiYWhhc2EgcGVtcm9ncmFtYW4gaW5pIGFkYWxhaCBzb2x1c2kgeWFuZyBsZWJpaCBiaWphayBrYXJlbmEga2VkdWFueWEgbWVtcHVueWFpIGtlbGViaWhhbiBkYW4ga2VrdXJhbmdhbiBtYXNpbmcgbWFzaW5nLiBSIGRhbiBQeXRob24gbWVtYnV0dWhrYW4gaW52ZXN0YXNpIHdha3R1LCBsYXRpaGFuIGRlbmdhbiB0dXRvcmlhbCwgZGFuIG1lbGFrdWthbiBwcm9qZWsgcHJvamVrIGtlY2lsIGJlcmJhc2lzIExBQiBoaW5nZ2EgcGVuZXJhcGFuIHNhaW5zIGRhdGEgcGFkYSBrYXN1cy1rYXN1cyB5YW5nIHNlYmVuYXJueWEuDQoNCiMjIFBlcnNhbWFhbg0KDQoqIFIgZGFuIFB5dGhvbiBhZGFsYWggYmFoYXNhIHBlbXJvZ3JhbWFuIG11bHRpLXBhcmFkaWdtYS4gS2VkdWFueWEgbWVuZHVrdW5nICBQZW1yb2dyYW1hbiBCZXJvcmllbnRhc2kgT2JqZWssIFBlbXJvZ3JhbWFuIEltcGVyYXRpZiwgUGVtcm9ncmFtYW4gUHJvc2VkdXJhbCwgZGxsLg0KKiBLZWR1YW55YSBhZGFsYWggYmFoYXNhIHlhbmcgZGl0YWZzaXJrYW4uDQoqIEtlZHVhbnlhIGRhcGF0IGRpZ3VuYWthbiB1bnR1ayBtZW5nZW1iYW5na2FuIGFsZ29yaXRtZS4NCiogS2VkdWFueWEgYWRhbGFoIGJhaGFzYSBwZW1yb2dyYW1hbiB0aW5na2F0IHRpbmdnaS4NCiogS2VkdWFueWEgZ3JhdGlzIGRhbiBvcGVuIHNvdXJjZS4NCiogS2VkdWFueWEgZGFwYXQgZGlpbnRlZ3Jhc2lrYW4gZGVuZ2FuIGFwbGlrYXNpIGxhaW4gc2VwZXJ0aSBNeVNRTCwgT3JhY2xlLCBHaXRIdWIsIGRsbC4NCiogS2VkdWFueWEgbWVuZHVrdW5nIGZpbGUgeWFuZyBiZXJiZWRhIHNlcGVydGkgZmlsZSBDU1YsIGZpbGUgZXhjZWwsIGZpbGUgWE1MIGRhbiBmaWxlIEpTT04uDQoqIEtlZHVhIGJhaGFzYSB0ZXJzZWJ1dCBtdWRhaCBkaWd1bmFrYW4gZGFuIGRpcGVsYWphcmkuDQoNCioqKg0KDQojIyBQZXJiZWRhYW4NCg0KQmVyaWt1dCBhZGFsYWggdGFiZWwgc2VjYXJhIHJpbmdrYXMgbWVtYmFuZGluZ2thbiBkdWEgYmFoYXNhIHBlbXJvZ3JhbWFuIFB5dGhvbiBkYW4gUjoNCg0KfHx8fA0KfDotLTp8Oi0tOnw6LS06fA0KfCoqS3JpdGVyaWEqKnwqKlIqKnwqKlB5dGhvbioqfA0KfFJ1YW5nIGxpbmdrdXB8IERhdGEgc2NpZW5jZSBkYW4gc3RhdGlzdGlrfCBBcGxpa2FzaSBkYW4gaW5kdXN0cmkgfA0KfFBlbmdndW5hIHwgQWthZGVtaXNpIGRhYiBwZW5lbGl0aXwgUHJvZ3JhbW1lcnMgJiBkZXZlbG9wZXIgfA0KfElERSAodXNlciBpbnRlcmZhY2UpfCBSU3R1ZGlvfCBTcHlkZXIsIEp1cHl0ZXIgTm90ZWJvb2ssIFB5Y2hhcm0sIGRsbHwNCnxFa3N0ZW5zaXxgLlJgIGRhbiBgLlJtZGB8IGAucHlgIGRhbiBgLmlweW5iYHwNCnxTdHJ1a3R1ciBkYXRhfHZla3RvciwgbGlzdCwgbWF0cmlrcywgYXJyYXksIGZha3RvciwgZGFuIGJpbmdrYWkgZGF0YXwgbGlzdCwgZGljdGlvbmFyeSwgZGFuIHR1cGVsfA0KfFBhY2thZ2UgZGFuIGxpYnJhcnl8dGlkeXZlcnNlLCBnZ3Bsb3QyLCBjYXJldCwgem9vIHxwYW5kYXMsIHNjaXB5LCBzY2lraXQtbGVhcm4sIFRlbnNvcmZsb3csIGNhcmV0fA0KfEtlbGViaWhhbnwgbWVtaWxpa2kgbGViaWggYmFueWFrIGxpYnJhcnkgZGFuIGt1YWxpdGFzIHZpc3VhbGlzYXNpIGdyYWZpayB5YW5nIGRpaGFzaWxrYW4gc2FuZ2F0IHRpbmdnaXxzaXN0ZW1hdGlrYSBwZW51bGlzYW4gc2NyaXB0IHlhbmcgbXVkYWggZGliYWNhLCBmb2t1cyBwYWRhIGtlY2VwYXRhbiBrb21wdXRhc2ksIHBlbmdlbWJhbmdhbiB3ZWIsIGphcmluZ2FuLCBvdG9tYXRpc2FzaSwgZGxsfA0KfEtla3VyYW5nYW4gfEtldGVyZ2FudHVuZ2FuIGFudGFyIGxpYnJhcnl8IGxpYnJhcnkgbGViaWggc2VkaWtpdCBkaWJhbmRpbmcgUiB8DQp8SW50ZWdyYXNpfGZpdHVyIFJtYXJrZG93biBkYW4gU2hpbnl8IGludGVncmFzaSBhcGxpa2FzaSBsZWJpaCBsdWFzfA0KDQoNCiMgU2ludGFrcyBEYXNhcg0KDQpTdWF0dSBwcm9ncmFtIGRpIFIgZGFuIFB5dGhvbiB0ZXJkaXJpIGRhcmkgdGlnYSBoYWwgbWVuZGFzYXI6IFZhcmlhYmVsLCBvcGVyYW4gKG5pbGFpKSBkYW4gS29tZW50YXIuIFZhcmlhYmVsIGRpZ3VuYWthbiB1bnR1ayBtZW55aW1wYW4gc3VhdHUgbmlsYWksIHNlZGFuZ2thbiBLb21lbnRhciBkaWd1bmFrYW4gdW50dWsgbWVuaW5na2F0a2FuIHBlbWFoYW1hbiBwZW5nZ3VuYSBtZW5nZW5haSBza3JpcCBhdGF1IGtvZGluZy4NCg0KDQojIyBQZW51Z2FzYW4gVmFyaWFiZWwNCg0KIyMjIFINCkRhbGFtIFIgcGVudWdhc2FuIHN1YXR1IHByb2dyYW0gYmlhc2FueWEgbWVuZ2d1bmFrYW4gc3VhdHUgdmFyaWFiZWwgeWFuZyBkaWNhZGFuZ2thbiB1bnR1ayBkYXBhdCBtZXJla2FtIGJlcmJhZ2FpIGplbmlzIGRhdGEgc2VzdWFpIG5hbWEgeWFuZyBkaWJlcmlrYW4ga2UgbG9rYXNpIHBlbnlpbXBhbmFuL21lbW9yaS4NClBlcmludGFoIHBlbnVnYXNhbiB2YXJpYWJlbCBpbmksZGFwYXQgZGkgbm90YXNpa2FuIGRlbmdhbiB0aWdhIGNhcmE6DQoNCiogPSAsZGkgZ3VuYWthbiB1bnR1ayBwZW51Z2FzYW4gDQoqIDwtICxkaSBndW5ha2FuIHVudHVrIHBlbnVnYXNhbiBkYXJpIHNpc2kga2lyaSANCiogLT4gLGRpIGd1bmFrYW4gdW50dWtwZW51Z2FzYW4gZGFyaSBzaXNpIGthbmFuDQoNCmBgYHtyfQ0KYT0zDQpiPC0xDQozKzEtPmMNCnByaW50KGMoYSxiLGMpKQ0KYGBgDQoNCiMjIyBQeXRob24NCg0KVW50dWsgbWVuamFsYW5rYW4gUHl0aG9uIGRlbmdhbiBSc3R1ZGlvLCBpbnN0YWxsLWxhaCBBbmFjb25kYSBwYWRhIFBDIGFuZGEgZGVuZ2FuIGJhaWssIGRhbiBqYW5nYW4gbHVwYSBtZWxha3VrYW4gdXBncmFkZSBweXRob24gdGVyc2VidXQgbWVuZ2d1bmFrYW4gKipDTUQuZXhlKiogcGFkYSBhbmFjb25kYSBuYXZpZ2F0b3IgZGVuZ2FuIG1lbmphbGFua2FuIGtvZGluZyBiZXJpa3V0Og0KDQpgYGANCmNvbmRhIHVwZGF0ZSAtLWFsbA0KY29uZGEgY3JlYXRlIC1uIHB5MzggcHl0aG9uPTMuOA0KY29uZGEgYWN0aXZhdGUgcHkzOA0KYGBgDQoNCktlbXVkaWFuIGphbGFua2FuIGtvZGluZyBiZXJpa3V0Og0KDQpgYGANCmxpYnJhcnkocmV0aWN1bGF0ZSkNCmxpYnJhcnkoUmNwcCkNCiMgY29uZGFfbGlzdCgpDQp1c2VfY29uZGFlbnYoInB5MzgiLCByZXF1aXJlZCA9IFRSVUUpDQpgYGANCg0KU2V0ZWxhaCBpdHUgYW5kYSBkYXBhdCBtZW5qYWxhbmthbiBjb2RpbmcgcHl0aG9uIHBhZGEgUnN0dWRpbyBkZW5nYW4gbWVuZ2dhbnRpIGBgYHtyfSBkZW5nYW4gbWVuamFkaSBgYGB7cHRob259IHBhZGEgY2h1bmsgUm1kIGFuZGEsIGRhbiBqYWxhbmthbiBjb2RpbmcgYmVyaWt1dDoNCg0KDQpgYGB7cn0NCnggPSA0DQp5ID0gNQ0KeiA9IDYNCnByaW50KHgseSx6KQ0KYGBgDQoNCg0KU2VsYWluIG1lbnlpbXBhbiBhdGF1IHBlbmdpc2lhbiBuaWxhaSwgYWRhIGp1Z2EgbWVuanVtbGFoa2FuLCBtZW5ndXJhbmdpLCBwZXJrYWxpYW4sIHBlbWJhZ2lhbiwgZHNiLg0KDQp8fHwNCnw6LS0tLS0tOnw6LS0tLS0tOnwNCnwqKk9wZXJhdG9yKip8ICoqU2ltYm9sKip8DQp8UGVuanVtbGFoYW58ICArPXwNCnxQZW5ndXJhbmdhbnwgIC09fA0KfFBlcmthbGlhbiAgfCAqPSB8DQp8UGVtYmFnaWFuICB8IC89IHwNCnxTaXNhIEJhZ2kgIHwlPSB8DQp8UGVtYW5na2F0YW58Kio9fA0KDQojIyBNZW5hbWJhaGthbiBLb21lbnRhcg0KDQpNZW5hbWJhaGthbi9NZW1iZXJpa2FuIGtvbWVudGFyIGRhbGFtIHNrcmlwL2tvZGluZyBSIGRhbiBQeXRob24gYWRhbGFoIHVudHVrIG1lbXVkYWhrYW4gYW5kYSBtZW1haGFtaSBhcnRpL21ha25hIHBlbmdndW5hYW4gc3VhdHUgcGVyaW50YWgvcHJvZ3JhbSBLb21lbnRhciB5YW5nIGRpdHVsaXMgZGFsYW0gc2VidWFoIHByb2dyYW0gdGVyc2VidXQgaGFueWEgYmVyc2lmYXQgcGVuamVsYXNhbiB0ZW50YW5nIGFwYSB5YW5nIGRpbGFrdWthbm55YSBhdGF1IGFwYSB5YW5nIHNlaGFydXNueWEgZGlsYWt1a2FuIG9sZWggc2VidWFoIHNrcmlwL2tvZGluZy4gUGVybHUgZGljYXRhdCBiYWh3YSBrb21lbnRhciB5YW5nIGJlcnNpZmF0aW5mb3JtYXNpIHRpZGFrIGFkYSBodWJ1bmdhbm55YSBkZW5nYW4gbG9naWthIHBlbXJvZ2FyYW0geWFuZyBzZWRhbmcgYW5kYSBndW5ha2FuLiBNZXJla2FiZW5hci1iZW5hciBkaWFiYWlrYW4gb2xlaCBrb21waWxlciBkYW4gZGVuZ2FuIGRlbWlraWFuIHRpZGFrIHBlcm5haCB0ZXJjZXJtaW4gcGFkYSBpbnB1dC4NCg0KQmlhc2FueWEga29tZW50YXIgZGl0dWxpc2thbiBwYWRhIHNhdHUgYmFyaXMgeWFuZyB0ZXJzZWRpYSBkaSBSIGRhbiBQeXRob24sIGRlbmdhbiBtZW5nZ3VuYWthbiAjIGRpIGF3YWwgbWF1cHVuIGRpIGFraGlyIHBlcm55YXRhYW4uIA0KDQpgYGB7cn0NCiMgUGVuanVtbGFoYW4gZGFyaSBsb2dhcml0bWENCmE9NSAgICAgICAgICAgICAgICAgICAgICMgTmlsYWkgYQ0KYj0xICAgICAgICAgICAgICAgICAgICAgIyBOaWxhaSBiDQpjPWErYiAgICAgICAgICAgICAgICAgICAjIE5pbGFpIGMNCmQ9bG9nKGMpICAgICAgICAgICAgICAgICMgTmlsYWkgZA0KcHJpbnQoYyhsb2coYykpKQ0KYGBgDQoNCkJlcmlrdXQgaW5pIGFkYWxhaCBjb250b2ggbWVuYW1iYWhrYW4ga29tZW50YXIgcGFkYSBvcGVyYXNpICoqcGVuYW1iYWhhbioqIFI6DQoNCmBgYHtyfQ0KYT01ICAgICAgICAgICAgICAgICAgICAgICMgTmlsYWkgYSBzYW1hIGRlbmdhbiA1LCBkYW4gbGViaWggYmVzYXIgZGFyaSBuaWxhaSBiDQpiPTEgICAgICAgICAgICAgICAgICAgICAgIyBOaWxhaSBhIHNhbWEgZGVuZ2FuIDUsIGRhbiBsZWJpaCBiZXNhciBkYXJpIG5pbGFpIGINCmM9YStiICAgICAgICAgICAgICAgICAgICAjIE5pbGFpIGMgc2FtYSBkZW5nYW4gcGVuYW1iYWhhbiBhIGRlbmdhbiBiDQpwcmludChjKGErYitjKSkgICAgICAgICAgIyBIYXNpbCBwZW5hbWJhaGFuIGEsYiwgZGFuIGMNCnByaW50KGMoYSxiLGMpKSAgICAgICAgICAjIE5pbGFpIGEsYiwgZGFuIGMNCmBgYA0KDQpCZXJpa3V0IGluaSBhZGFsYWggY29udG9oIG1lbmFtYmFoa2FuIGtvbWVudGFyIHBhZGEgb3BlcmFzaSAqKnBlZ3VyYW5nYW4qKiBSOg0KDQpgYGB7cn0NCmE9NSAgICAgICAgICAgICAgICAgICAgICAjIE5pbGFpIGEgc2FtYSBkZW5nYW4gNSwgZGFuIGxlYmloIGJlc2FyIGRhcmkgbmlsYWkgYg0KYj0xICAgICAgICAgICAgICAgICAgICAgICMgTmlsYWkgYSBzYW1hIGRlbmdhbiAxLCBkYW4gbGViaWgga2VjaWwgZGFyaSBuaWxhaSBiDQpjPWEtYiAgICAgICAgICAgICAgICAgICAgIyBOaWxhaSBjIHNhbWEgZGVuZ2FuIGEgZGlrdXJhbmcgYg0KcHJpbnQoYyhhLWItYykpICAgICAgICAgICMgSGFzaWwgcGVuZ3VyYW5nYW4gYSxiLCBkYW4gYw0KYGBgDQoNCkJlcmlrdXQgaW5pIGFkYWxhaCBjb250b2ggbWVuYW1iYWhrYW4ga29tZW50YXIgcGFkYSBvcGVyYXNpICoqcGVya2FsaWFuKiogZGkgZGFsYW0gUjoNCg0KYGBge3J9DQphPTUgICAgICAgICAgICAgICAgICAgICAgIyBOaWxhaSBhIHNhbWEgZGVuZ2FuIDUsIGRhbiBsZWJpaCBiZXNhciBkYXJpIG5pbGFpIGINCmI9MSAgICAgICAgICAgICAgICAgICAgICAjIE5pbGFpIGEgc2FtYSBkZW5nYW4gMSwgZGFuIGxlYmloIGtlY2lsIGRhcmkgbmlsYWkgYg0KYz1hKmIgICAgICAgICAgICAgICAgICAgICMgTmlsYWkgYyBzYW1hIGRlbmdhbiBhIGRpa2FsaSBvbGVoIGINCnByaW50KGMoYSpiKmMpKSAgICAgICAgICAjIEhhc2lsIHBlcmthbGlhbiBhLGIsIGRhbiBjDQpgYGANCg0KQmVyaWt1dCBpbmkgYWRhbGFoIGNvbnRvaCBtZW5hbWJhaGthbiBrb21lbnRhciBwYWRhIG9wZXJhc2kgKipwZW1iYWdpYW4qKiBkaSBkYWxhbSBSOg0KDQpgYGB7cn0NCmE9NSAgICAgICAgICAgICAgICAgICAgICAgIyBOaWxhaSBhIHNhbWEgZGVuZ2FuIDUsIGRhbiBsZWJpaCBiZXNhciBkYXJpIG5pbGFpIGINCmI9MSAgICAgICAgICAgICAgICAgICAgICAgIyBOaWxhaSBhIHNhbWEgZGVuZ2FuIDEsIGRhbiBsZWJpaCBrZWNpbCBkYXJpIG5pbGFpIGINCmM9YS9iICAgICAgICAgICAgICAgICAgICAgIyBOaWxhaSBjIHNhbWEgZGVuZ2FuIGEgZGliYWdpIG9sZWggYg0KcHJpbnQoYyhhL2IvYykpICAgICAgICAgICAjIEhhc2lsIHBlbWJhZ2lhbiBhLGIsYw0KYGBgDQoNCkJlcmlrdXQgaW5pIGFkYWxhaCBjb250b2ggbWVuYW1iYWhrYW4ga29tZW50YXIgcGFkYSBvcGVyYXNpICoqcGVtYW5na2F0YW4qKiBkaSBkYWxhbSBSOg0KDQpgYGB7cn0NCmE9NSAgICAgICAgICAgICAgICAgICAgICAgICMgTmlsYWkgYSBzYW1hIGRlbmdhbiA1LCBkYW4gbGViaWggYmVzYXIgZGFyaSBuaWxhaSBiDQpiPTEgICAgICAgICAgICAgICAgICAgICAgICAjIE5pbGFpIGEgc2FtYSBkZW5nYW4gMSwgZGFuIGxlYmloIGtlY2lsIGRhcmkgbmlsYWkgYg0KYz1hXmIgICAgICAgICAgICAgICAgICAgICAgIyBOaWxhaSBjIHNhbWEgZGVuZ2FuIGEgZGlwYW5na2F0a2FuIG9sZWggYg0KcHJpbnQoYyhhXmJeYykpICAgICAgICAgICAgIyBIYXNpbCBwZW1hbmdrYXRhbiBhLGIsYw0KYGBgDQoNCkJlcmlrdXQgaW5pIGFkYWxhaCBjb250b2ggbWVuYW1iYWhrYW4ga29tZW50YXIgcGFkYSBvcGVyYXNpICoqbW9kdWxvKiogZGkgZGFsYW0gUjoNCg0KYGBge3J9DQphPTUgICAgICAgICAgICAgICAgICAgICAgICAgIyBOaWxhaSBhIHNhbWEgZGVuZ2FuIDUsIGRhbiBsZWJpaCBiZXNhciBkYXJpIG5pbGFpIGINCmI9MSAgICAgICAgICAgICAgICAgICAgICAgICAjIE5pbGFpIGEgc2FtYSBkZW5nYW4gMSwgZGFuIGxlYmloIGtlY2lsIGRhcmkgbmlsYWkgYg0KcHJpbnQoYyhhJSViKSkgICAgICAgICAgICAgICMgSGFzaWwgbW9kdWxvIGEgJSBiDQpgYGANCg0KDQojIE9wZXJhdG9yDQoNCk9wZXJhdG9yIGFkYWxhaCBzaW1ib2wgeWFuZyBtZW5nYXJhaGthbiBjb21waWxlciB1bnR1ayBtZWxha3VrYW4gYmVyYmFnYWkgbWFjYW0gb3BlcmFzaSB0ZXJoYWRhcCBiZWJlcmFwYSBwZW51Z2FzYW4uIE9wZXJhdG9yIG1lbnNpbXVsYXNpa2FuIGJlcmJhZ2FpIG9wZXJhc2kgbWF0ZW1hdGlzLCBsb2dpa2EsIGRhbiBrZXB1dHVzYW4geWFuZyBkaWxha3VrYW4gcGFkYSBzZWt1bXB1bGFuIEJpbGFuZ2FuIEtvbXBsZWtzLCBJbnRlZ2VyLCBkYW4gTnVtZXJpayBzZWJhZ2FpIHBlbnVnYXNhbiBtYXN1a2FuIChpbnB1dCkuIFIgZGFuIFB5dGhvbiBtZW5kdWt1bmcgc2ViYWdpYW4gYmVzYXIgZW1wYXQgamVuaXMgb3BlcmF0b3IgYmluZXIgYW50YXJhIHNhdHUgc2V0IHBlbnVnYXNhbi4gRGFsYW0gaW5pLCBraXRhIGFrYW4gbWVsaWhhdCBiZXJiYWdhaSBqZW5pcyBvcGVyYXRvciB5YW5nIHRlcnNlZGlhIGRpIFIgZGFuIFB5dGhvbiBkYW4gcGVuZ2d1bmFhbm55YS4NCg0KDQojIyBBcml0bWF0aWthDQoNClBlbmdndW5hYW4gb3BlcmF0b3IgYXJpdG1hdGlrYSBkYWxhbSBwcm9ncmFtIFIgZGFuIFB5dGhvbiBhZGFsYWggdW50dWsgbWVuc2ltdWxhc2lrYW4gYmVyYmFnYWkgb3BlcmFzaSBtYXRlbWF0aWthLCBzZXBlcnRpIHBlbmFtYmFoYW4sIHBlbmd1cmFuZ2FuLCBwZXJrYWxpYW4sIHBlbWJhZ2lhbiwgZGFuIG1vZHVsby4gT3BlcmF0b3IgYXJpdG1hdGlrYSB5YW5nIGRpbGFrdWthbiBiaXNhIHNhamEgYmVydXBhIG5pbGFpIHNrYWxhciwgYmlsYW5nYW4ga29tcGxla3MsIGF0YXUgdmVrdG9yDQoNCnx8fHwNCnw6LS06fDotLTp8Oi0tOnwNCnwqKk9wZXJhdG9yKip8KipSKip8KipQeXRob24qKnwNCnwgUGVuanVtbGFoYW4gfCArIHwgKyB8DQp8IFBlbmd1cmFuZ2FuIHwgLSB8IC0gfA0KfCBQZXJrYWxpYW4gfCAqIHwgKiB8DQp8IERpdmlzaS9QZW1iYWdpYW4gfCAvIHwgLyB8DQp8IFBlbWFuZ2thdGFuIHwgKiB8ICoqIHwNCnwgTW9kdWxvIHwgJSUgfCAlIHwNCg0KQmVyaWt1dCBpbmkgYWRhbGFoIGNvbnRvaCBvcGVyYXNpIEFyaXRtYXRpa2EgKipwZW5hbWJhaGFuKiogUjoNCg0KYGBge3J9DQphPTUgICAgICAgICAgICAgICAgICAgICAgIyBOaWxhaSBhIHNhbWEgZGVuZ2FuIDUsIGRhbiBsZWJpaCBiZXNhciBkYXJpIG5pbGFpIGINCmI9MSAgICAgICAgICAgICAgICAgICAgICAjIE5pbGFpIGEgc2FtYSBkZW5nYW4gNSwgZGFuIGxlYmloIGJlc2FyIGRhcmkgbmlsYWkgYg0KYz1hK2IgICAgICAgICAgICAgICAgICAgICMgTmlsYWkgYyBzYW1hIGRlbmdhbiBwZW5hbWJhaGFuIGEgZGVuZ2FuIGINCnByaW50KGMoYStiK2MpKSAgICAgICAgICAjIEhhc2lsIHBlbmFtYmFoYW4gYSxiLCBkYW4gYw0KcHJpbnQoYyhhLGIsYykpICAgICAgICAgICMgTmlsYWkgYSxiLCBkYW4gYw0KYGBgDQoNCkJlcmlrdXQgaW5pIGFkYWxhaCBjb250b2ggb3BlcmFzaSBBcml0bWF0aWthICoqcGVndXJhbmdhbioqIFI6DQoNCmBgYHtyfQ0KYT01ICAgICAgICAgICAgICAgICAgICAgICMgTmlsYWkgYSBzYW1hIGRlbmdhbiA1LCBkYW4gbGViaWggYmVzYXIgZGFyaSBuaWxhaSBiDQpiPTEgICAgICAgICAgICAgICAgICAgICAgIyBOaWxhaSBhIHNhbWEgZGVuZ2FuIDEsIGRhbiBsZWJpaCBrZWNpbCBkYXJpIG5pbGFpIGINCmM9YS1iICAgICAgICAgICAgICAgICAgICAjIE5pbGFpIGMgc2FtYSBkZW5nYW4gYSBkaWt1cmFuZyBiDQpwcmludChjKGEtYi1jKSkgICAgICAgICAgIyBIYXNpbCBwZW5ndXJhbmdhbiBhLGIsIGRhbiBjDQpgYGANCg0KQmVyaWt1dCBpbmkgYWRhbGFoIGNvbnRvaCBvcGVyYXNpIEFyaXRtYXRpa2EgKipwZXJrYWxpYW4qKiBkaSBkYWxhbSBSOg0KDQpgYGB7cn0NCmE9NSAgICAgICAgICAgICAgICAgICAgICAjIE5pbGFpIGEgc2FtYSBkZW5nYW4gNSwgZGFuIGxlYmloIGJlc2FyIGRhcmkgbmlsYWkgYg0KYj0xICAgICAgICAgICAgICAgICAgICAgICMgTmlsYWkgYSBzYW1hIGRlbmdhbiAxLCBkYW4gbGViaWgga2VjaWwgZGFyaSBuaWxhaSBiDQpjPWEqYiAgICAgICAgICAgICAgICAgICAgIyBOaWxhaSBjIHNhbWEgZGVuZ2FuIGEgZGlrYWxpIG9sZWggYg0KcHJpbnQoYyhhKmIqYykpICAgICAgICAgICMgSGFzaWwgcGVya2FsaWFuIGEsYiwgZGFuIGMNCmBgYA0KDQpCZXJpa3V0IGluaSBhZGFsYWggY29udG9oIG9wZXJhc2kgQXJpdG1hdGlrYSAqKnBlbWJhZ2lhbioqIGRpIGRhbGFtIFI6DQoNCmBgYHtyfQ0KYT01ICAgICAgICAgICAgICAgICAgICAgICAjIE5pbGFpIGEgc2FtYSBkZW5nYW4gNSwgZGFuIGxlYmloIGJlc2FyIGRhcmkgbmlsYWkgYg0KYj0xICAgICAgICAgICAgICAgICAgICAgICAjIE5pbGFpIGEgc2FtYSBkZW5nYW4gMSwgZGFuIGxlYmloIGtlY2lsIGRhcmkgbmlsYWkgYg0KYz1hL2IgICAgICAgICAgICAgICAgICAgICAjIE5pbGFpIGMgc2FtYSBkZW5nYW4gYSBkaWJhZ2kgb2xlaCBiDQpwcmludChjKGEvYi9jKSkgICAgICAgICAgICMgSGFzaWwgcGVtYmFnaWFuIGEsYixjDQpgYGANCg0KQmVyaWt1dCBpbmkgYWRhbGFoIGNvbnRvaCBvcGVyYXNpIEFyaXRtYXRpa2EgKipwZW1hbmdrYXRhbioqIGRpIGRhbGFtIFI6DQoNCmBgYHtyfQ0KYT01ICAgICAgICAgICAgICAgICAgICAgICAgIyBOaWxhaSBhIHNhbWEgZGVuZ2FuIDUsIGRhbiBsZWJpaCBiZXNhciBkYXJpIG5pbGFpIGINCmI9MSAgICAgICAgICAgICAgICAgICAgICAgICMgTmlsYWkgYSBzYW1hIGRlbmdhbiAxLCBkYW4gbGViaWgga2VjaWwgZGFyaSBuaWxhaSBiDQpjPWFeYiAgICAgICAgICAgICAgICAgICAgICAjIE5pbGFpIGMgc2FtYSBkZW5nYW4gYSBkaXBhbmdrYXRrYW4gb2xlaCBiDQpwcmludChjKGFeYl5jKSkgICAgICAgICAgICAjIEhhc2lsIHBlbWFuZ2thdGFuIGEsYixjDQpgYGANCg0KQmVyaWt1dCBpbmkgYWRhbGFoIG9wZXJhc2kgQXJpdG1hdGlrYSAqKm1vZHVsbyoqIGRpIGRhbGFtIFI6DQoNCmBgYHtyfQ0KYT01ICAgICAgICAgICAgICAgICAgICAgICAgICMgTmlsYWkgYSBzYW1hIGRlbmdhbiA1LCBkYW4gbGViaWggYmVzYXIgZGFyaSBuaWxhaSBiDQpiPTEgICAgICAgICAgICAgICAgICAgICAgICAgIyBOaWxhaSBhIHNhbWEgZGVuZ2FuIDEsIGRhbiBsZWJpaCBrZWNpbCBkYXJpIG5pbGFpIGINCnByaW50KGMoYSUlYikpICAgICAgICAgICAgICAjIEhhc2lsIG1vZHVsbyBhICUgYg0KYGBgDQoNCg0KIyMgUmVsYXNpb25hbA0KDQp8fHx8fA0KfDotLTp8Oi0tOnw6LS06fA0KfCoqT3BlcmF0b3IqKnwqKlIqKnwqKlB5dGhvbioqfCoqS2V0ZXJhbmdhbioqfA0KfCBLdXJhbmcgZGFyaXw8fDx8TWVuZ2VtYmFsaWthbiBUUlVFIGppa2EgZWxlbWVuIHlhbmcgYmVyc2VzdWFpYW4gcGFkYSBvcGVyYW4gcGVydGFtYSBsZWJpaCBrZWNpbCBkYXJpIG9wZXJhbiBrZWR1YS4gU2VsYWluIGl0dSBha2FuIG1lbmdhbWJhbGlrYW4gRkFMU0UufA0KfCBLdXJhbmcgZGFyaSBzYW1hIGRlbmdhbnw8PXw8PXxNZW5nZW1iYWxpa2FuIFRSVUUgamlrYSBlbGVtZW4geWFuZyBiZXJzZXN1YWlhbiBwYWRhIG9wZXJhbiBwZXJ0YW1hIGt1cmFuZyBkYXJpIGF0YXUgc2FtYSBkZW5nYW4gZWxlbWVuIG9wZXJhbiBrZWR1YS4gU2VsYWluIGl0dSBha2FuIG1lbmdlbWJhbGlrYW4gRkFMU0UufA0KfCBMZWJpaCBiZXNhciBkYXJpCXw+PXw+PXxNZW5nZW1iYWxpa2FuIFRSVUUgamlrYSBlbGVtZW4geWFuZyBiZXJzZXN1YWlhbiBwYWRhIG9wZXJhbiBwZXJ0YW1hIGxlYmloIGJlc2FyIGRhcmkgb3BlcmFuIGtlZHVhLiBTZWxhaW4gaXR1IGFrYW4gbWVuZ2VtYmFsaWthbiBGQUxTRXwNCnwgTGViaWggYmVzYXIgc2FtYSBkZW5nYW4gfD49fD49fE1lbmdlbWJhbGlrYW4gQkVOQVIgamlrYSBlbGVtZW4geWFuZyBiZXJzZXN1YWlhbiBwYWRhIG9wZXJhbiBwZXJ0YW1hIGxlYmloIGJlc2FyIGF0YXUgc2FtYSBkZW5nYW4gZGFyaSBvcGVyYW4ga2VkdWEuIFNlbGFpbiBpdHUgYWthbiBtZW5nZW1iYWxpa2FuIEZBTFNFLnwNCnwgU2FtYSBkZW5nYW4gfD09fD09fE1lbmdlbWJhbGlrYW4gQkVOQVIgamlrYSBkYW4gaGFueWEgamlrYSBrZWR1YSBzaXNpIGJlcm5pbGFpIHNhbWEufA0KfCBUaWRhayBTYW1hIERlbmdhbiB8IT18IT18TWVuZ2VtYmFsaWthbiBCRU5BUiBqaWthIGVsZW1lbiB5YW5nIGJlcnNlc3VhaWFuIHBhZGEgb3BlcmFuIHBlcnRhbWEgdGlkYWsgc2FtYSBkZW5nYW4gZGFyaSBvcGVyYW4ga2VkdWEufA0KDQpCZXJpa3V0IGNvbnRvaCBwZW5nZ3VuYWFuIG9wZXJhdG9yIHJlbGFzaW9uYWwgZGkgUjoNCg0KYGBge3J9DQp4IDwtIGMoNCwyLDcpICAgICAgICAgICAgICMgbWVtdWF0IHZla3RvciB4DQp5IDwtIGMoNiw4LDEpICAgICAgICAgICAgICMgbWVtdWF0IHZla3RvciB5DQpjYXQoIlZla3RvciB4IGt1cmFuZyBkYXJpIFZla3RvciB5OiIsIHggPCB5LCAiXG4iKQ0KYGBgDQoNCmBgYHtyfQ0KY2F0KCJWZWt0b3IgeCBrdXJhbmcgZGFyaSBzYW1hIGRlbmdhbiBWZWt0b3IgeSA6IiwgeCA8PSB5LCAiXG4iKQ0KYGBgDQoNCmBgYHtyfQ0KY2F0KCJWZWt0b3IgeCBsZWJpaCBiZXNhciBkYXJpIFZla3RvciB5OiIsIHggPiB5LCAiXG4iKQ0KYGBgDQoNCmBgYHtyfQ0KY2F0KCJWZWt0b3IgeCBsZWJpaCBiZXNhciBkYXJpIHNhbWEgZGVuZ2FuIFZla3RvciB5OiIsIHggPj0geSwgIlxuIikNCmBgYA0KDQpgYGB7cn0NCmNhdCgiVmVrdG9yIHggc2FtYSBkZW5nYW4gVmVrdG9yIHk6IiwgeCA9PSB5LCAiXG4iKQ0KYGBgDQoNCmBgYHtyfQ0KY2F0KCJWZWt0b3IgeCB0aWRhayBzYW1hIGRlbmdhbiBWZWt0b3IgeToiLCB4ICE9IHksICJcbiIpDQpgYGANCg0KIyMgTG9naWthDQoNCk9wZXJhdG9yIGxvZ2lzIG1lbnNpbXVsYXNpa2FuIG9wZXJhc2kga2VwdXR1c2FuLCBiZXJkYXNhcmthbiBvcGVyYXRvciB5YW5nIGRpdGVudHVrYW4gYW50YXJhIG9wZXJhbiwgeWFuZyBrZW11ZGlhbiBkaWV2YWx1YXNpIGtlIG5pbGFpIEJvb2xlYW4gQmVuYXIgYXRhdSBTYWxhaC4gTmlsYWkgYmlsYW5nYW4gYnVsYXQgYnVrYW4gbm9sIGRpYW5nZ2FwIHNlYmFnYWkgbmlsYWkgQkVOQVIsIGJhaWsgaXR1IGJpbGFuZ2FuIGtvbXBsZWtzIGF0YXUgYmlsYW5nYW4gcmVhbC4NCg0KfHx8fHwNCnw6LS06fDotLTp8Oi0tOnw6LS06fA0KfCoqT3BlcmF0b3IqKnwqKlIqKnwqKlB5dGhvbioqfCoqS2V0ZXJhbmdhbioqfA0KfCBOT1QgfCF8IXxPcGVyYXNpIG5lZ2FzaS9rZWJhbGlrYW4gcGFkYSBzdGF0dXMgZWxlbWVuIG9wZXJhbnwNCnwgQU5EIHwmfCZ8TWVuZ2VtYmFsaWthbiBUUlVFIGppa2Ega2VkdWEgb3BlcmFuIGJlcm5pbGFpIEJlbmFyfA0KfCBPUiB8IHwgfCB8IHxNZW5nZW1iYWxpa2FuIFRSVUUgamlrYSBzYWxhaCBzYXR1IG9wZXJhbiBCZW5hcnwNCnwgWE9SIHxefF58TWVuZ2VtYmFsaWthbiBUUlVFIGppa2Egc2FsYWggc2F0dSBkYXJpIGtlZHVhIGVsZW1lbiBwZXJ0YW1hIG9wZXJhbiBiZXJuaWxhaSBCZW5hcnwNCg0KQmVyaWt1dCBwZW5nZ3VuYWFuIGxvZ2lrYSBkaSBSOg0KDQpgYGB7Un0NCnggPC0gYygwLFRSVUUsRkFMU0UpDQp5IDwtIGMoVFJVRSwwLDEsNCszaSkNCg0KIyBNZWxha3VrYW4gT3BlcmFzaSBMb2dpa2EgT3BlcmFuDQpjYXQoIkxvZ2lrYSBOZWdhc2kgKH4pIHVudHVrIHZla3RvciB4OiIsICF4LCAiXG4iKQ0KYGBgDQoNCmBgYHtyfQ0KY2F0KCJMb2dpa2EgTmVnYXNpICh+KSB1bnR1ayB2ZWt0b3IgeSA6IiwgIXksICJcbiIpDQpgYGANCg0KYGBge3J9DQpjYXQoIkxvZ2lrYSBLb25qdW5nc2kgKERhbikgOiIsIHggJiB5LCAiXG4iKQ0KYGBgDQoNCmBgYHtyfQ0KY2F0KCJMb2dpa2EgRGlzanVuZ3NpIChBdGF1KSA6IiwgeCB8IHksICJcbiIpDQpgYGANCg0KYGBge3J9DQpjYXQoIkxvZ2lrYSBEaXNqdW5nc2kgUGFyc2lhbDoiLCB4IHx8IHksICJcbiIpDQpgYGANCg0KDQojIyBMYWluLUxhaW4NCg0KQmVyaWt1dCBpbmkgdGVyZGFwYXQgYmViZXJhcGEgb3BlcmF0b3IgeWFuZyBqdWdhIGFuZGEgcGVybHVrYW4gcGFkYSBzYWF0IGFrYW4gbWVuZ2d1bmFrYW4gUiA6DQoNCmBgYHtyfQ0KeCA8LSBjKDYsMyw5KSAgICAgICAgICAgICAgIyBtZW11YXQgdmVrdG9yIHgNCnkgPC0gYygyLDYsOCkgICAgICAgICAgICAgICMgbWVtdWF0IHZla3RvciB5DQpzcXJ0KHgqeSkgICAgICAgICAgICAgICAgICAjIEJlbnR1ayBha2FyDQpgYGANCg0KYGBge3J9DQpsb2coeCkgICAgICAgICAgICAgICAgICAgICAjIExvZ2FyaXRtYSB4DQpgYGANCg0KYGBge3J9DQpsb2coeSkgICAgICAgICAgICAgICAgICAgICAjIExvZ3Jhcml0bWEgeQ0KYGBgDQoNCmBgYHtyfQ0KZXhwKHgpICAgICAgICAgICAgICAgICAgICAgIyBFa3Nwb25lbiB4DQpgYGANCg0KYGBge3J9DQpleHAoeSkgICAgICAgICAgICAgICAgICAgICAjIEVrc3BvbmVuIHkNCmBgYA0KDQpgYGB7cn0NCih4L3kpICsgeSAgICAgICAgICAgICAgICAgICMgVGFuZGEga3VydW5nDQpgYGANCg0KDQojIFRpcGUgRGF0YQ0KDQpEYWxhbSBwZW1yb2dyYW1hbiBzZXBlcnRpIFIgZGFuIFB5dGhvbiwgdGlwZSBkYXRhIG1lcnVwYWthbiBrb25zZXAgcGVudGluZy4gS2VkdWFueWEgZGFwYXQgbWVuZ2d1bmFrYW4gdmFyaWFiZWwgdW50dWsgbWVueWltcGFuIHRpcGUgeWFuZyBiZXJiZWRhLWJlZGEsIGJlcmlrdXQgYWRhbGFoIHRpcGUgZGF0YSBwYWxpbmcgbWVuZGFzYXIgeWFuZyBoYXJ1cyBkaWtldGFodWk6DQoNCnx8fHx8DQp8Oi0tOnw6LS06fDotLTp8Oi0tOnwNCnwqKlRpcGUgRGF0YSoqfCoqUioqfCoqUHl0aG9uKip8KipQZW5qZWxhc2FuKip8DQp8IERvdWJsZS9GbG9hdCB8NS42fDUuNnxCaWxhbmdhbiBkZXNpbWFsfA0KfCBJbnRlZ2VyIHw1fDV8QmlsYW5nYW4gYnVsYXQgMSwyLDMuLi4ubnwNCnwgQm9sZWFuL0xvZ2ljYWwgfFRSVUUvRkFMU0V8VHJ1ZS9GYWxzZXxCZW5hciBiZXJuaWxhaSAxIGRhbiBzYWxhaCBiZXJuaWxhaSAwfA0KfCBTdHJpbmcvQ2hhcmFjdGVyIHwnWWVuaW5hd24nfCdZZW5pbmF3bid8S2FyYWt0ZXIva2FsaW1hdCBiaXNhIGJlcnVwYSBhbmdrYSwgaHVydWYsIGRsbC4gKGRpYXBpdCBkZW5nYW4gdGFuZGEg4oCZIGF0YXUiKXwNCnwgQ29tcGxleCB8MSs1aXwxKzVqfFBhc2FuZ2FuIGFuZ2thIGRhbiBpbWFqaW5lcnwNCg0KDQojIyBSDQoNCkJlcmlrdXQgaW5pIGFkYWxhaCBrb2RpbmcgUiB5YW5nIGRhcGF0IGRpZ3VuYWthbiB1bnR1ayBtZW5ldGFwa2FuIGtlbGltYSB0aXBlIGRhdGEgZGlhdGFzOg0KDQpgYGB7cn0NCmQxID0gNS42ICAgICAgICAgICAgICAgICAgICMgVGV0YXBrYW4gbmlsYWkgZGVzaW1hbA0KZDIgPSBhcy5pbnRlZ2VyKDUpICAgICAgICAgIyBUZXRhcGthbiBuaWxhaSBpbnRlZ2VyDQpkMiA9IDVMICAgICAgICAgICAgICAgICAgICAjIGNhcmEgbGFpbiB1bnR1ayBtZW11YXQgbmlsYWkgaW50ZWdlciBkaSBSDQpkMyA9IGMoVFJVRSxGQUxTRSkgICAgICAgICAjIEJvbGVhbi9Mb2dpY2FsDQpkMyA9IGFzLmxvZ2ljYWwoYygwLDEpKSAgICAjIGNhcmEgbGFpbiB1bnR1ayBtZW11YXQgQm9sZWFuL0xvZ2ljYWwNCmQ1ID0gYygiYSIsICJiIiwgIjEyMyIpICAgICMgU3RyaW5nL0NoYXJhY3Rlcg0KZDUgPSAxICsgNWkgICAgICAgICAgICAgICAgIyBDb21wbGV4DQpgYGANCg0KYGBge3J9DQpjbGFzcyhkMSkgICAgICAgICAgICAgICAgICAjIGNldGFrIG5hbWEga2VsYXMgdmFyaWFiZWwNCmBgYA0KDQpgYGB7cn0NCnR5cGVvZihkMSkgICAgICAgICAgICAgICAgICMgY2V0YWsgdGlwZSB2YXJpYWJlbA0KYGBgDQoNCiMjIFB5dGhvbg0KDQpCZXJpa3V0IGluaSBhZGFsYWgga29kaW5nIFB5dGhvbiB5YW5nIGRhcGF0IGRpZ3VuYWthbiB1bnR1ayBtZW5ldGFwa2FuIGtlbGltYSB0aXBlIGRhdGEgZGlhdGFzOg0KDQpgYGANCmQxID0gNS42ICAgICAgICAgICAgICAgICAgIyBUZXRhcGthbiBuaWxhaSBkZXNpc21hbA0KZDIgPSA1ICAgICAgICAgICAgICAgICAgICAjIFRldGFwa2FuIG5pbGFpIGludGVyZ2VyDQpkMyA9IFtUcnVlLEZhbHNlXSAgICAgICAgICMgTGlzdCBCb2xlYW4vTG9naWNhbA0KZDQgPSBbImEiLCdiJywnMTIzJ10gICAgICAjIExpc3QgU3RyaW5nL0NoYXJhY3Rlcg0KZDUgPSAxICsgNWogICAgICAgICAgICAgICAjIENvbXBsZXgNCmBgYA0KDQpVbnR1ayBtZW1lcmlrc2EgdGlwZSBkYXRhIHB5dGhvbiA6DQoNCmBgYA0KdHlwZShkNSkgICAgICAgICAgICAgICAgICAjIENldGFrIHRpcGUgdmFyaWFiZWwgeA0KYGBgDQoNCiMgQmFudHVhbg0KDQpTYWxhaCBzYXR1IGJhZ2lhbiBwZW50aW5nIGRhbGFtIGJla2VyamEgZGVuZ2FuIGJhaGFzYSBSIGFkYWxhaCBiYWdhaW1hbmEgbWVuY2FyaSBiYW50dWFuLiBSIG1lbWlsaWtpIGJlLWJlcmFwYSBmYXNpbGl0YXMgaW4tbGluZSxzZWxhaW4gYmViZXJhcGEgZGF5YSBzdW1iZXIgYmFudHVhbiBkaSBla29zaXN0ZW0gUi5BbmRhIGRhcGF0IG1lbmd1bmFrYW4gYmFudHVhbiB1bnR1ayBmdW5nc2kgdGVydGVudHUuDQoNCkJlcmlrdXQgYmFudHVhbiBwYWRhIFI6DQoNCmBgYHtyfQ0KaGVscC5zdGFydCgpICAgICAgICAgICAgICAjIG1lbnUgZGkgbWFuYSBBbmRhIGRhcGF0IG1lbmF2aWdhc2kgYmFudHVhbiBsb2thbCBiZXJiYXNpcyB3ZWINCj9oZWxwICAgICAgICAgICAgICAgICAgICAgIyBtZW51IGRpIG1hbmEgQW5kYSBkYXBhdCBtZW5hdmlnYXNpIGJhbnR1YW4gbG9rYWwgYmVyYmFzaXMgd2ViDQo/Y2xhc3MgICAgICAgICAgICAgICAgICAgICMgbWVuZGFwYXRrYW4gYmFudHVhbiB1bnR1ayBmdW5nc2kgYGNsYXNzYA0KaGVscChjbGFzcykgICAgICAgICAgICAgICAjIG1lbmRhcGF0a2FuIGJhbnR1YW4gdW50dWsgZnVuZ3NpIGBjbGFzc2ANCj8/Y2xhc3MgICAgICAgICAgICAgICAgICAgIyBqaWthIEFuZGEgdGlkYWsgdGFodSBuYW1hIGZ1bmdzaSB5YW5nIEFuZGEgY2FyaQ0KaGVscC5zZWFyY2goJ2NsYXNzJykgICAgICAjIGppa2EgQW5kYSB0aWRhayB0YWh1IG5hbWEgZnVuZ3NpIHlhbmcgQW5kYSBjYXJpDQpgYGANCg0KIyBSZWZlcmVuc2kNCg0KKiBodHRwczovL3JwdWJzLmNvbS9kc2NpZW5jZWxhYnMvYXNkMg0K