Pendahuluan
Dalam pemrograman R, efisiensi dan keterbacaan kode seringkali
menjadi kunci dalam pengolahan data yang kompleks. Untuk mencapai hal
tersebut, R menyediakan sekumpulan fungsi yang dikenal sebagai keluarga
apply(), yaitu apply(), lapply(), sapply(), dan tapply(). Fungsi-fungsi
ini mendukung prinsip vectorization dan functional programming, yang
memudahkan pemrosesan elemen data tanpa perlu menggunakan for loop
secara eksplisit.
- apply() digunakan untuk menerapkan fungsi ke seluruh baris atau
kolom matriks atau array.
- lapply() digunakan untuk menerapkan fungsi ke setiap elemen dalam
list dan mengembalikan list hasilnya.
- sapply() mencoba menyederhanakan hasil lapply() menjadi vektor atau
matriks, jika memungkinkan.
- tapply() ideal untuk agregasi data berdasarkan kelompok/faktor
tertentu.
Penggunaan fungsi-fungsi ini tidak hanya mempercepat eksekusi, tetapi
juga memperjelas alur logika pemrograman. Mereka juga merupakan
perwujudan dari strategi split–apply–combine, yaitu pendekatan di mana
data dibagi menjadi kelompok, fungsi diterapkan pada tiap kelompok, dan
hasilnya digabungkan kembali.
Keunggulan
Fungsi apply dan keluarganya
Mengganti Loop Tradisional
Daripada menggunakan perulangan for, keluarga apply
memungkinkan untuk menulis kode deklaratif yang lebih mudah
dibaca.
Efisiensi Kinerja
Fungsi apply umumnya lebih cepat daripada for loop karena
optimalisasi internal oleh interpreter R.
Fleksibilitas Tinggi
Dapat digunakan untuk berbagai struktur data: vektor, matriks, list,
array, dan bahkan kombinasi antar-objek.
Output yang Konsisten dan Dapat
Disesuaikan
Beberapa fungsi seperti vapply() memungkinkan kamu
mengontrol tipe dan panjang hasil output, menambah keamanan dalam
pemrosesan data besar.
Sintaks yang ringkas — cukup satu baris kode
dibandingkan blok loop yang panjang :contentReferenceoaicite:1.
Kinerja lebih baik, terutama pada dataset besar,
karena pemrosesan yang lebih cepat dibanding dengan iterasi manual
:contentReferenceoaicite:2.
Fungsi
apply dan Keluarganya
Fungsi
apply().
Fungsi apply() adalah fungsi di R yang digunakan untuk
menerapkan suatu fungsi tertentu, seperti penjumlahan, rata-rata, atau
nilai maksimum, ke seluruh baris atau kolom dari data yang berbentuk
matriks, array, atau data frame. Dengan menggunakan apply(), kita bisa
melakukan perhitungan secara efisien tanpa harus mengulang perintah
untuk tiap baris atau kolom secara manual.
Struktur
Umum
apply(X, MARGIN, FUN, …)
Keterangan:
- X: Objek yang akan diiterasi, seperti matriks atau array.
- MARGIN: Angka yang menunjukkan dimensi yang akan diterapkan fungsi.
1 untuk baris, 2 untuk kolom, dan c(1, 2) untuk seluruh elemen.
- FUN: Fungsi yang akan diterapkan pada setiap baris atau kolom.
- …: Argumen tambahan yang akan diteruskan ke fungsi FUN.
Contoh
Penggunaan
# Membuat matrix nilai siswa
nilai <- matrix(
c(80, 70, 95, # Matematika
85, 65, 90, # Fisika
90, 75, 85, # Kimia
75, 60, 80), # Biologi
nrow = 3,
byrow = FALSE
)
# Tambahkan nama baris dan kolom
rownames(nilai) <- c("Siswa1", "Siswa2", "Siswa3")
colnames(nilai) <- c("Matematika", "Fisika", "Kimia", "Biologi")
# Tampilkan matrix
nilai
## Matematika Fisika Kimia Biologi
## Siswa1 80 85 90 75
## Siswa2 70 65 75 60
## Siswa3 95 90 85 80
# Menampilkan hasil apply
apply(nilai, 1, sum) # total nilai per siswa
## Siswa1 Siswa2 Siswa3
## 330 270 350
apply(nilai, 1, mean) # rata-rata nilai per siswa
## Siswa1 Siswa2 Siswa3
## 82.5 67.5 87.5
apply(nilai, 2, mean) # rata-rata per mata pelajaran
## Matematika Fisika Kimia Biologi
## 81.66667 80.00000 83.33333 71.66667
apply(nilai, 1, max) # nilai tertinggi tiap siswa
## Siswa1 Siswa2 Siswa3
## 90 75 95
apply(nilai, 1, sort) # urutkan nilai tiap siswa
## Siswa1 Siswa2 Siswa3
## [1,] 75 60 80
## [2,] 80 65 85
## [3,] 85 70 90
## [4,] 90 75 95
Fungsi
lapply().
Fungsi lapply() di R digunakan untuk menjalankan suatu
fungsi pada setiap elemen dari sebuah list, vektor, atau data frame,
lalu hasilnya akan dikembalikan dalam bentuk list juga, dengan jumlah
elemen yang sama seperti inputnya. Karena lapply() langsung
bekerja pada setiap elemen dalam list, kita tidak perlu menentukan baris
atau kolom (tidak perlu pakai MARGIN).
Struktur
Umum
lapply(X, FUN, …)
Keterangan:
- X: Objek yang akan diiterasi, seperti list atau vektor.
- FUN: Fungsi yang akan diterapkan pada setiap elemen dari
X.
- …: Argumen tambahan yang akan diteruskan ke fungsi
FUN.
Contoh
Penggunaan
# List berisi nilai dari beberapa siswa
nilai_siswa <- list(
Siswa1 = c(80, 85, 90),
Siswa2 = c(75, 70, 80),
Siswa3 = c(90, 95, 85)
)
# Hitung rata-rata nilai setiap siswa
lapply(nilai_siswa, mean)
## $Siswa1
## [1] 85
##
## $Siswa2
## [1] 75
##
## $Siswa3
## [1] 90
Fungsi
sapply().
Fungsi sapply() adalah salah satu fungsi dari keluarga
apply di R yang digunakan untuk menerapkan suatu fungsi ke setiap elemen
dari list, vector, atau data frame. Fungsi ini bekerja mirip seperti
lapply(), tetapi sapply() secara
otomatis mencoba menyederhanakan hasilnya menjadi bentuk yang lebih
sederhana, yaitu berupa vector,
matrix, atau array, jika memungkinkan.
Fungsi sapply() sangat berguna untuk menghindari hasil
berupa list jika hasil yang lebih sederhana dapat dibuat.
Struktur
umum
sapply(X, FUN, …)
Keterangan:
- X = list, vector, atau data frame yang akan diproses
- FUN = fungsi yang akan diterapkan pada setiap elemen
- … = argumen tambahan untuk fungsi tersebut
Contoh
Penggunaan
#Kuadrat angka 1 sampai 5
hasil_kuadrat <- sapply(1:5, function(x) x^2)
hasil_kuadrat
## [1] 1 4 9 16 25
## Contoh data jumlah soal
jumlah_soal <- c(5, 6, 7, 8, 9)
#Hitung soal genap dalam satu sapply
hasil_sapply <- sapply(jumlah_soal, function(n) {
soal <- 1:n # Buat urutan 1 sampai n
sum(soal %% 2 == 0) # Hitung berapa yang genap
})
hasil_sapply
## [1] 2 3 3 4 4
Fungsi
tapply().
Fungsi tapply() merupakan salah satu fungsi penting di R
yang digunakan untuk membuat ringkasan data dalam bentuk tabel. Fungsi
ini bekerja dengan cara menerapkan suatu fungsi tertentu (seperti mean
atau variance) pada kelompok data berdasarkan kategori tertentu
(faktor).
Struktur
umum
tapply(X, INDEX, FUN, …)
Keterangan:
- X = vektor yang berisi data numerik atau karakter
- INDEX = faktor (atau list faktor) yang mendefinisikan kelompok
- FUN = fungsi yang akan diterapkan ke masing-masing kelompok
- … = argumen tambahan untuk fungsi
Contoh
Penggunaan
# Data nilai siswa
nilai <- c(80, 75, 90, 85, 70, 95, 88, 77)
# Data jenis kelamin (L = laki-laki, P = perempuan)
gender <- c("L", "P", "L", "P", "P", "L", "L", "P")
# Tampilkan sebagai data frame
data.frame(Nilai = nilai, Gender = gender)
## Nilai Gender
## 1 80 L
## 2 75 P
## 3 90 L
## 4 85 P
## 5 70 P
## 6 95 L
## 7 88 L
## 8 77 P
tapply(nilai, gender, mean)
## L P
## 88.25 76.75
tapply(nilai, gender, length)
## L P
## 4 4
Kesimpulan
Keluarga fungsi apply di R menyediakan cara yang efisien
dan idiomatik untuk menerapkan fungsi pada elemen-elemen dari struktur
data seperti vektor, matriks, list, dan data frame. Dengan menggunakan
fungsi-fungsi seperti apply(), lapply(),
sapply(), tapply(), vapply(),
mapply(), dan rapply(), pengguna dapat
menghindari penggunaan perulangan eksplisit, membuat kode lebih ringkas,
dan meningkatkan kinerja pemrosesan data.
Tabel
perbandingan
apply() |
Matriks/Array |
Vektor |
Menghitung rata-rata per kolom |
lapply() |
List/Vektor |
List |
Menghitung panjang setiap elemen |
sapply() |
List/Vektor |
Vektor/Matrix |
Menghitung kuadrat setiap elemen |
tapply() |
Vektor |
Array |
Menghitung rata-rata berdasarkan grup |
LS0tDQp0aXRsZTogIioqRnVuZ3NpIEFwcGx5IGFuZCBGYW1pbHkqKiINCmF1dGhvcjogfA0KICAqKktlbG9tcG9rIDEqKg0KZGF0ZTogImByIGZvcm1hdChTeXMuRGF0ZSgpLCAnJWQgJUIgJVknKWAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdGhlbWU6IHVuaXRlZCAgICAgICAgIyBUZW1hIGNlcmFoIGRlbmdhbiBha3NlbiBvcmFueWUtbWVyYWggeWFuZyB2aWJyYW50DQogICAgaGlnaGxpZ2h0OiB0YW5nbyAgICAgIyBTa2VtYSB3YXJuYSBrb2RlIHlhbmcgbGViaWggaGlkdXANCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZGVwdGg6IDMNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IGZhbHNlDQogICAgICBzbW9vdGhfc2Nyb2xsOiB0cnVlDQogICAgICB0b2NfY29sb3I6ICIjNTc4RkNBIiAgDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgIHNlY3Rpb25fZGl2czogdHJ1ZSAgICAjIE1lbWJ1YXQgc2VjdGlvbiBsZWJpaCB0ZXJwaXNhaCBzZWNhcmEgdmlzdWFsDQogICAgZmlnX3dpZHRoOiAxMA0KICAgIGZpZ19oZWlnaHQ6IDYNCiAgICBmaWdfYWxpZ246ICdjZW50ZXInDQogICAgY3NzOiB8DQogICAgICBib2R5IHsNCiAgICAgICAgY29sb3I6ICMzMzMzMzM7DQogICAgICB9DQogICAgICBoMSwgaDIsIGgzIHsNCiAgICAgICAgY29sb3I6ICMyQzNFNTA7DQogICAgICAgIGJvcmRlci1ib3R0b206IDJweCBzb2xpZCAjRTY5RjAwOw0KICAgICAgICBwYWRkaW5nLWJvdHRvbTogNXB4Ow0KICAgICAgfQ0KICAgICAgYSB7DQogICAgICAgIGNvbG9yOiAjRTc0QzNDOw0KICAgICAgfQ0KICAgICAgLm1haW4tY29udGFpbmVyIHsNCiAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogI0Y5RjlGOTsNCiAgICAgICAgcGFkZGluZzogMjBweDsNCiAgICAgIH0NCi0tLQ0KDQoNCi0tLQ0KDQojICoqUGVuZGFodWx1YW4qKg0KDQpEYWxhbSBwZW1yb2dyYW1hbiBSLCBlZmlzaWVuc2kgZGFuIGtldGVyYmFjYWFuIGtvZGUgc2VyaW5na2FsaSBtZW5qYWRpIGt1bmNpIGRhbGFtIHBlbmdvbGFoYW4gZGF0YSB5YW5nIGtvbXBsZWtzLiBVbnR1ayBtZW5jYXBhaSBoYWwgdGVyc2VidXQsIFIgbWVueWVkaWFrYW4gc2VrdW1wdWxhbiBmdW5nc2kgeWFuZyBkaWtlbmFsIHNlYmFnYWkga2VsdWFyZ2EgYXBwbHkoKSwgeWFpdHUgYXBwbHkoKSwgbGFwcGx5KCksIHNhcHBseSgpLCBkYW4gdGFwcGx5KCkuIEZ1bmdzaS1mdW5nc2kgaW5pIG1lbmR1a3VuZyBwcmluc2lwIHZlY3Rvcml6YXRpb24gZGFuIGZ1bmN0aW9uYWwgcHJvZ3JhbW1pbmcsIHlhbmcgbWVtdWRhaGthbiBwZW1yb3Nlc2FuIGVsZW1lbiBkYXRhIHRhbnBhIHBlcmx1IG1lbmdndW5ha2FuIGZvciBsb29wIHNlY2FyYSBla3NwbGlzaXQuDQoNCi0gYXBwbHkoKSBkaWd1bmFrYW4gdW50dWsgbWVuZXJhcGthbiBmdW5nc2kga2Ugc2VsdXJ1aCBiYXJpcyBhdGF1IGtvbG9tIG1hdHJpa3MgYXRhdSBhcnJheS4NCi0gbGFwcGx5KCkgZGlndW5ha2FuIHVudHVrIG1lbmVyYXBrYW4gZnVuZ3NpIGtlIHNldGlhcCBlbGVtZW4gZGFsYW0gbGlzdCBkYW4gbWVuZ2VtYmFsaWthbiBsaXN0IGhhc2lsbnlhLg0KLSBzYXBwbHkoKSBtZW5jb2JhIG1lbnllZGVyaGFuYWthbiBoYXNpbCBsYXBwbHkoKSBtZW5qYWRpIHZla3RvciBhdGF1IG1hdHJpa3MsIGppa2EgbWVtdW5na2lua2FuLg0KLSB0YXBwbHkoKSBpZGVhbCB1bnR1ayBhZ3JlZ2FzaSBkYXRhIGJlcmRhc2Fya2FuIGtlbG9tcG9rL2Zha3RvciB0ZXJ0ZW50dS4NCg0KUGVuZ2d1bmFhbiBmdW5nc2ktZnVuZ3NpIGluaSB0aWRhayBoYW55YSBtZW1wZXJjZXBhdCBla3Nla3VzaSwgdGV0YXBpIGp1Z2EgbWVtcGVyamVsYXMgYWx1ciBsb2dpa2EgcGVtcm9ncmFtYW4uIE1lcmVrYSBqdWdhIG1lcnVwYWthbiBwZXJ3dWp1ZGFuIGRhcmkgc3RyYXRlZ2kgc3BsaXTigJNhcHBseeKAk2NvbWJpbmUsIHlhaXR1IHBlbmRla2F0YW4gZGkgbWFuYSBkYXRhIGRpYmFnaSBtZW5qYWRpIGtlbG9tcG9rLCBmdW5nc2kgZGl0ZXJhcGthbiBwYWRhIHRpYXAga2Vsb21wb2ssIGRhbiBoYXNpbG55YSBkaWdhYnVuZ2thbiBrZW1iYWxpLg0KDQotLS0NCg0KIyMgKipLZXVuZ2d1bGFuIEZ1bmdzaSBhcHBseSBkYW4ga2VsdWFyZ2FueWEgKioNCg0KMS4gKipNZW5nZ2FudGkgTG9vcCBUcmFkaXNpb25hbCoqICANCiAgIERhcmlwYWRhIG1lbmdndW5ha2FuIHBlcnVsYW5nYW4gYGZvcmAsIGtlbHVhcmdhIGFwcGx5IG1lbXVuZ2tpbmthbiB1bnR1ayBtZW51bGlzIGtvZGUgZGVrbGFyYXRpZiB5YW5nIGxlYmloIG11ZGFoIGRpYmFjYS4NCg0KMi4gKipFZmlzaWVuc2kgS2luZXJqYSoqICANCiAgIEZ1bmdzaSBhcHBseSB1bXVtbnlhIGxlYmloIGNlcGF0IGRhcmlwYWRhIGBmb3JgIGxvb3Aga2FyZW5hIG9wdGltYWxpc2FzaSBpbnRlcm5hbCBvbGVoIGludGVycHJldGVyIFIuDQoNCjMuICoqRmxla3NpYmlsaXRhcyBUaW5nZ2kqKiAgDQogICBEYXBhdCBkaWd1bmFrYW4gdW50dWsgYmVyYmFnYWkgc3RydWt0dXIgZGF0YTogdmVrdG9yLCBtYXRyaWtzLCBsaXN0LCBhcnJheSwgZGFuIGJhaGthbiBrb21iaW5hc2kgYW50YXItb2JqZWsuDQoNCjQuICoqT3V0cHV0IHlhbmcgS29uc2lzdGVuIGRhbiBEYXBhdCBEaXNlc3VhaWthbioqICANCiAgIEJlYmVyYXBhIGZ1bmdzaSBzZXBlcnRpIGB2YXBwbHkoKWAgbWVtdW5na2lua2FuIGthbXUgbWVuZ29udHJvbCB0aXBlIGRhbiBwYW5qYW5nIGhhc2lsIG91dHB1dCwgbWVuYW1iYWgga2VhbWFuYW4gZGFsYW0gcGVtcm9zZXNhbiBkYXRhIGJlc2FyLg0KICAgDQo1LiAqKlNpbnRha3MgeWFuZyByaW5na2FzKiog4oCUIGN1a3VwIHNhdHUgYmFyaXMga29kZSBkaWJhbmRpbmdrYW4gYmxvayBsb29wIHlhbmcgcGFuamFuZyA6Y29udGVudFJlZmVyZW5jZVtvYWljaXRlOjFde2luZGV4PTF9Lg0KDQo2LiAqKktpbmVyamEgbGViaWggYmFpayoqLCB0ZXJ1dGFtYSBwYWRhIGRhdGFzZXQgYmVzYXIsIGthcmVuYSBwZW1yb3Nlc2FuIHlhbmcgbGViaWggY2VwYXQgZGliYW5kaW5nIGRlbmdhbiBpdGVyYXNpIG1hbnVhbCA6Y29udGVudFJlZmVyZW5jZVtvYWljaXRlOjJde2luZGV4PTJ9Lg0KDQotLS0NCg0KIyAqKkZ1bmdzaSBgYXBwbHlgIGRhbiBLZWx1YXJnYW55YSoqDQoNCiMjICAqKkZ1bmdzaSBgYXBwbHkoKWAuKioNCg0KRnVuZ3NpIGBhcHBseSgpYCBhZGFsYWggZnVuZ3NpIGRpIFIgeWFuZyBkaWd1bmFrYW4gdW50dWsgbWVuZXJhcGthbiBzdWF0dSBmdW5nc2kgdGVydGVudHUsIHNlcGVydGkgcGVuanVtbGFoYW4sIHJhdGEtcmF0YSwgYXRhdSBuaWxhaSBtYWtzaW11bSwga2Ugc2VsdXJ1aCBiYXJpcyBhdGF1IGtvbG9tIGRhcmkgZGF0YSB5YW5nIGJlcmJlbnR1ayBtYXRyaWtzLCBhcnJheSwgYXRhdSBkYXRhIGZyYW1lLiBEZW5nYW4gbWVuZ2d1bmFrYW4gYXBwbHkoKSwga2l0YSBiaXNhIG1lbGFrdWthbiBwZXJoaXR1bmdhbiBzZWNhcmEgZWZpc2llbiB0YW5wYSBoYXJ1cyBtZW5ndWxhbmcgcGVyaW50YWggdW50dWsgdGlhcCBiYXJpcyBhdGF1IGtvbG9tIHNlY2FyYSBtYW51YWwuDQoNCiMjIyAqKlN0cnVrdHVyIFVtdW0qKg0KDQphcHBseShYLCBNQVJHSU4sIEZVTiwgLi4uKQ0KDQpLZXRlcmFuZ2FuOg0KDQotIFg6IE9iamVrIHlhbmcgYWthbiBkaWl0ZXJhc2ksIHNlcGVydGkgbWF0cmlrcyBhdGF1IGFycmF5Lg0KLSBNQVJHSU46IEFuZ2thIHlhbmcgbWVudW5qdWtrYW4gZGltZW5zaSB5YW5nIGFrYW4gZGl0ZXJhcGthbiBmdW5nc2kuIDEgdW50dWsgYmFyaXMsIDIgdW50dWsga29sb20sIGRhbiBjKDEsIDIpIHVudHVrIHNlbHVydWggZWxlbWVuLg0KLSBGVU46IEZ1bmdzaSB5YW5nIGFrYW4gZGl0ZXJhcGthbiBwYWRhIHNldGlhcCBiYXJpcyBhdGF1IGtvbG9tLg0KLSAuLi46IEFyZ3VtZW4gdGFtYmFoYW4geWFuZyBha2FuIGRpdGVydXNrYW4ga2UgZnVuZ3NpIEZVTi4NCg0KIyMjICoqQ29udG9oIFBlbmdndW5hYW4qKg0KDQpgYGB7cn0NCiMgTWVtYnVhdCBtYXRyaXggbmlsYWkgc2lzd2ENCm5pbGFpIDwtIG1hdHJpeCgNCiAgYyg4MCwgNzAsIDk1LCAgICMgTWF0ZW1hdGlrYQ0KICAgIDg1LCA2NSwgOTAsICAgIyBGaXNpa2ENCiAgICA5MCwgNzUsIDg1LCAgICMgS2ltaWENCiAgICA3NSwgNjAsIDgwKSwgICMgQmlvbG9naQ0KICBucm93ID0gMywNCiAgYnlyb3cgPSBGQUxTRQ0KKQ0KDQojIFRhbWJhaGthbiBuYW1hIGJhcmlzIGRhbiBrb2xvbQ0Kcm93bmFtZXMobmlsYWkpIDwtIGMoIlNpc3dhMSIsICJTaXN3YTIiLCAiU2lzd2EzIikNCmNvbG5hbWVzKG5pbGFpKSA8LSBjKCJNYXRlbWF0aWthIiwgIkZpc2lrYSIsICJLaW1pYSIsICJCaW9sb2dpIikNCg0KIyBUYW1waWxrYW4gbWF0cml4DQpuaWxhaQ0KDQojIE1lbmFtcGlsa2FuIGhhc2lsIGFwcGx5DQphcHBseShuaWxhaSwgMSwgc3VtKSAgICAgIyB0b3RhbCBuaWxhaSBwZXIgc2lzd2ENCmFwcGx5KG5pbGFpLCAxLCBtZWFuKSAgICAjIHJhdGEtcmF0YSBuaWxhaSBwZXIgc2lzd2ENCmFwcGx5KG5pbGFpLCAyLCBtZWFuKSAgICAjIHJhdGEtcmF0YSBwZXIgbWF0YSBwZWxhamFyYW4NCmFwcGx5KG5pbGFpLCAxLCBtYXgpICAgICAjIG5pbGFpIHRlcnRpbmdnaSB0aWFwIHNpc3dhDQphcHBseShuaWxhaSwgMSwgc29ydCkgICAgIyB1cnV0a2FuIG5pbGFpIHRpYXAgc2lzd2ENCmBgYA0KDQojIyAgKipGdW5nc2kgYGxhcHBseSgpYC4qKg0KDQpGdW5nc2kgYGxhcHBseSgpYCBkaSBSIGRpZ3VuYWthbiB1bnR1ayBtZW5qYWxhbmthbiBzdWF0dSBmdW5nc2kgcGFkYSBzZXRpYXAgZWxlbWVuIGRhcmkgc2VidWFoIGxpc3QsIHZla3RvciwgYXRhdSBkYXRhIGZyYW1lLCBsYWx1IGhhc2lsbnlhIGFrYW4gZGlrZW1iYWxpa2FuIGRhbGFtIGJlbnR1ayBsaXN0IGp1Z2EsIGRlbmdhbiBqdW1sYWggZWxlbWVuIHlhbmcgc2FtYSBzZXBlcnRpIGlucHV0bnlhLiBLYXJlbmEgYGxhcHBseSgpYCBsYW5nc3VuZyBiZWtlcmphIHBhZGEgc2V0aWFwIGVsZW1lbiBkYWxhbSBsaXN0LCBraXRhIHRpZGFrIHBlcmx1IG1lbmVudHVrYW4gYmFyaXMgYXRhdSBrb2xvbSAodGlkYWsgcGVybHUgcGFrYWkgYE1BUkdJTmApLg0KDQojIyMgKipTdHJ1a3R1ciBVbXVtKioNCg0KbGFwcGx5KFgsIEZVTiwgLi4uKQ0KDQpLZXRlcmFuZ2FuOg0KDQotIFg6IE9iamVrIHlhbmcgYWthbiBkaWl0ZXJhc2ksIHNlcGVydGkgbGlzdCBhdGF1IHZla3Rvci4NCi0gRlVOOiBGdW5nc2kgeWFuZyBha2FuIGRpdGVyYXBrYW4gcGFkYSBzZXRpYXAgZWxlbWVuIGRhcmkgYFhgLg0KLSAuLi46IEFyZ3VtZW4gdGFtYmFoYW4geWFuZyBha2FuIGRpdGVydXNrYW4ga2UgZnVuZ3NpIGBGVU5gLg0KDQojIyMgKipDb250b2ggUGVuZ2d1bmFhbioqDQoNCmBgYHtyfQ0KIyBMaXN0IGJlcmlzaSBuaWxhaSBkYXJpIGJlYmVyYXBhIHNpc3dhDQpuaWxhaV9zaXN3YSA8LSBsaXN0KA0KICBTaXN3YTEgPSBjKDgwLCA4NSwgOTApLA0KICBTaXN3YTIgPSBjKDc1LCA3MCwgODApLA0KICBTaXN3YTMgPSBjKDkwLCA5NSwgODUpDQopDQoNCiMgSGl0dW5nIHJhdGEtcmF0YSBuaWxhaSBzZXRpYXAgc2lzd2ENCmxhcHBseShuaWxhaV9zaXN3YSwgbWVhbikNCmBgYA0KDQojIyAgKipGdW5nc2kgYHNhcHBseSgpYC4qKg0KDQpGdW5nc2kgYHNhcHBseSgpYCBhZGFsYWggc2FsYWggc2F0dSBmdW5nc2kgZGFyaSBrZWx1YXJnYSBhcHBseSBkaSBSIHlhbmcgZGlndW5ha2FuIHVudHVrIG1lbmVyYXBrYW4gc3VhdHUgZnVuZ3NpIGtlIHNldGlhcCBlbGVtZW4gZGFyaSBsaXN0LCB2ZWN0b3IsIGF0YXUgZGF0YSBmcmFtZS4gRnVuZ3NpIGluaSBiZWtlcmphIG1pcmlwIHNlcGVydGkgYGxhcHBseSgpYCwgdGV0YXBpIGBzYXBwbHkoKWAgKipzZWNhcmEgb3RvbWF0aXMgbWVuY29iYSBtZW55ZWRlcmhhbmFrYW4gaGFzaWxueWEgbWVuamFkaSBiZW50dWsgeWFuZyBsZWJpaCBzZWRlcmhhbmEqKiwgeWFpdHUgYmVydXBhICoqdmVjdG9yKiosICoqbWF0cml4KiosIGF0YXUgKiphcnJheSoqLCBqaWthIG1lbXVuZ2tpbmthbi4gRnVuZ3NpIGBzYXBwbHkoKWAgc2FuZ2F0IGJlcmd1bmEgdW50dWsgbWVuZ2hpbmRhcmkgaGFzaWwgYmVydXBhIGxpc3QgamlrYSBoYXNpbCB5YW5nIGxlYmloIHNlZGVyaGFuYSBkYXBhdCBkaWJ1YXQuDQoNCiMjIyAqKlN0cnVrdHVyIHVtdW0qKg0KDQpzYXBwbHkoWCwgRlVOLCAuLi4pDQoNCktldGVyYW5nYW46DQoNCi0gWCA9IGxpc3QsIHZlY3RvciwgYXRhdSBkYXRhIGZyYW1lIHlhbmcgYWthbiBkaXByb3Nlcw0KLSBGVU4gPSBmdW5nc2kgeWFuZyBha2FuIGRpdGVyYXBrYW4gcGFkYSBzZXRpYXAgZWxlbWVuDQotIC4uLiA9IGFyZ3VtZW4gdGFtYmFoYW4gdW50dWsgZnVuZ3NpIHRlcnNlYnV0DQoNCiMjIyAqKkNvbnRvaCBQZW5nZ3VuYWFuKioNCmBgYHtyfQ0KI0t1YWRyYXQgYW5na2EgMSBzYW1wYWkgNQ0KaGFzaWxfa3VhZHJhdCA8LSBzYXBwbHkoMTo1LCBmdW5jdGlvbih4KSB4XjIpDQpoYXNpbF9rdWFkcmF0DQoNCiMjIENvbnRvaCBkYXRhIGp1bWxhaCBzb2FsDQpqdW1sYWhfc29hbCA8LSBjKDUsIDYsIDcsIDgsIDkpDQoNCiNIaXR1bmcgc29hbCBnZW5hcCBkYWxhbSBzYXR1IHNhcHBseQ0KaGFzaWxfc2FwcGx5IDwtIHNhcHBseShqdW1sYWhfc29hbCwgZnVuY3Rpb24obikgew0KICBzb2FsIDwtIDE6biAgICAgICAgICMgQnVhdCB1cnV0YW4gMSBzYW1wYWkgbg0KICBzdW0oc29hbCAlJSAyID09IDApICMgSGl0dW5nIGJlcmFwYSB5YW5nIGdlbmFwDQp9KQ0KDQpoYXNpbF9zYXBwbHkNCmBgYA0KDQojIyAgKipGdW5nc2kgYHRhcHBseSgpYC4qKg0KDQpGdW5nc2kgYHRhcHBseSgpYCBtZXJ1cGFrYW4gc2FsYWggc2F0dSBmdW5nc2kgcGVudGluZyBkaSBSIHlhbmcgZGlndW5ha2FuIHVudHVrIG1lbWJ1YXQgcmluZ2thc2FuIGRhdGEgZGFsYW0gYmVudHVrIHRhYmVsLiBGdW5nc2kgaW5pIGJla2VyamEgZGVuZ2FuIGNhcmEgbWVuZXJhcGthbiBzdWF0dSBmdW5nc2kgdGVydGVudHUgKHNlcGVydGkgbWVhbiBhdGF1IHZhcmlhbmNlKSBwYWRhIGtlbG9tcG9rIGRhdGEgYmVyZGFzYXJrYW4ga2F0ZWdvcmkgdGVydGVudHUgKGZha3RvcikuDQoNCiMjIyAqKlN0cnVrdHVyIHVtdW0qKg0KDQp0YXBwbHkoWCwgSU5ERVgsIEZVTiwgLi4uKQ0KDQpLZXRlcmFuZ2FuOg0KDQotIFggPSB2ZWt0b3IgeWFuZyBiZXJpc2kgZGF0YSBudW1lcmlrIGF0YXUga2FyYWt0ZXIgIA0KLSBJTkRFWCA9IGZha3RvciAoYXRhdSBsaXN0IGZha3RvcikgeWFuZyBtZW5kZWZpbmlzaWthbiBrZWxvbXBvayAgDQotIEZVTiA9IGZ1bmdzaSB5YW5nIGFrYW4gZGl0ZXJhcGthbiBrZSBtYXNpbmctbWFzaW5nIGtlbG9tcG9rICANCi0gLi4uID0gYXJndW1lbiB0YW1iYWhhbiB1bnR1ayBmdW5nc2kgIA0KDQojIyMgKipDb250b2ggUGVuZ2d1bmFhbioqDQoNCmBgYHtyIGRhdGEtbmlsYWl9DQojIERhdGEgbmlsYWkgc2lzd2ENCm5pbGFpIDwtIGMoODAsIDc1LCA5MCwgODUsIDcwLCA5NSwgODgsIDc3KQ0KDQojIERhdGEgamVuaXMga2VsYW1pbiAoTCA9IGxha2ktbGFraSwgUCA9IHBlcmVtcHVhbikNCmdlbmRlciA8LSBjKCJMIiwgIlAiLCAiTCIsICJQIiwgIlAiLCAiTCIsICJMIiwgIlAiKQ0KDQojIFRhbXBpbGthbiBzZWJhZ2FpIGRhdGEgZnJhbWUNCmRhdGEuZnJhbWUoTmlsYWkgPSBuaWxhaSwgR2VuZGVyID0gZ2VuZGVyKQ0KdGFwcGx5KG5pbGFpLCBnZW5kZXIsIG1lYW4pDQp0YXBwbHkobmlsYWksIGdlbmRlciwgbGVuZ3RoKQ0KYGBgDQoNCg0KIyAqKktlc2ltcHVsYW4qKg0KS2VsdWFyZ2EgZnVuZ3NpIGBhcHBseWAgZGkgUiBtZW55ZWRpYWthbiBjYXJhIHlhbmcgZWZpc2llbiBkYW4gaWRpb21hdGlrIHVudHVrIG1lbmVyYXBrYW4gZnVuZ3NpIHBhZGEgZWxlbWVuLWVsZW1lbiBkYXJpIHN0cnVrdHVyIGRhdGEgc2VwZXJ0aSB2ZWt0b3IsIG1hdHJpa3MsIGxpc3QsIGRhbiBkYXRhIGZyYW1lLiBEZW5nYW4gbWVuZ2d1bmFrYW4gZnVuZ3NpLWZ1bmdzaSBzZXBlcnRpIGBhcHBseSgpYCwgYGxhcHBseSgpYCwgYHNhcHBseSgpYCwgYHRhcHBseSgpYCwgYHZhcHBseSgpYCwgYG1hcHBseSgpYCwgZGFuIGByYXBwbHkoKWAsIHBlbmdndW5hIGRhcGF0IG1lbmdoaW5kYXJpIHBlbmdndW5hYW4gcGVydWxhbmdhbiBla3NwbGlzaXQsIG1lbWJ1YXQga29kZSBsZWJpaCByaW5na2FzLCBkYW4gbWVuaW5na2F0a2FuIGtpbmVyamEgcGVtcm9zZXNhbiBkYXRhLg0KDQojICoqVGFiZWwgcGVyYmFuZGluZ2FuKioNCnwgRnVuZ3NpICAgIHwgSW5wdXQgICAgICAgICB8IE91dHB1dCAgICAgICAgfCBDb250b2ggUGVuZ2d1bmFhbiAgICAgICAgICAgICAgICAgICAgICB8DQp8LS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfA0KfCBgYXBwbHkoKWAgfCBNYXRyaWtzL0FycmF5IHwgVmVrdG9yICAgICAgICB8IE1lbmdoaXR1bmcgcmF0YS1yYXRhIHBlciBrb2xvbSAgICAgICAgIHwNCnwgYGxhcHBseSgpYHwgTGlzdC9WZWt0b3IgICB8IExpc3QgICAgICAgICAgfCBNZW5naGl0dW5nIHBhbmphbmcgc2V0aWFwIGVsZW1lbiAgICAgICB8DQp8IGBzYXBwbHkoKWB8IExpc3QvVmVrdG9yICAgfCBWZWt0b3IvTWF0cml4IHwgTWVuZ2hpdHVuZyBrdWFkcmF0IHNldGlhcCBlbGVtZW4gICAgICAgfA0KfCBgdGFwcGx5KClgfCBWZWt0b3IgICAgICAgIHwgQXJyYXkgICAgICAgICB8IE1lbmdoaXR1bmcgcmF0YS1yYXRhIGJlcmRhc2Fya2FuIGdydXAgICB8DQoNCiMgKipSZWZlcmVuc2kqKg0KLSBHZWVrc2ZvckdlZWtzLiAoMjAyMikuICphcHBseSgpLCBsYXBwbHkoKSwgc2FwcGx5KCksIGFuZCB0YXBwbHkoKSBpbiBSKi4gUmV0cmlldmVkIGZyb20gPGh0dHBzOi8vd3d3LmdlZWtzZm9yZ2Vla3Mub3JnL2FwcGx5LWxhcHBseS1zYXBwbHktYW5kLXRhcHBseS1pbi1yLz4NCi0gRGF0YXF1ZXN0LiAoMjAyMSkuIEFwcGx5IEZ1bmN0aW9ucyBpbiBSIHdpdGggRXhhbXBsZXMuIDxodHRwczovL3d3dy5kYXRhcXVlc3QuaW8vYmxvZy9hcHBseS1mdW5jdGlvbnMtaW4tci8+DQoNCg0KDQoNCg==