1 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.


1.1 Keunggulan Fungsi apply dan keluarganya

  1. Mengganti Loop Tradisional
    Daripada menggunakan perulangan for, keluarga apply memungkinkan untuk menulis kode deklaratif yang lebih mudah dibaca.

  2. Efisiensi Kinerja
    Fungsi apply umumnya lebih cepat daripada for loop karena optimalisasi internal oleh interpreter R.

  3. Fleksibilitas Tinggi
    Dapat digunakan untuk berbagai struktur data: vektor, matriks, list, array, dan bahkan kombinasi antar-objek.

  4. Output yang Konsisten dan Dapat Disesuaikan
    Beberapa fungsi seperti vapply() memungkinkan kamu mengontrol tipe dan panjang hasil output, menambah keamanan dalam pemrosesan data besar.

  5. Sintaks yang ringkas — cukup satu baris kode dibandingkan blok loop yang panjang :contentReferenceoaicite:1.

  6. Kinerja lebih baik, terutama pada dataset besar, karena pemrosesan yang lebih cepat dibanding dengan iterasi manual :contentReferenceoaicite:2.


2 Fungsi apply dan Keluarganya

2.1 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.

2.1.1 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.

2.1.2 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

2.2 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).

2.2.1 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.

2.2.2 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

2.3 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.

2.3.1 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

2.3.2 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

2.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).

2.4.1 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

2.4.2 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

3 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.

4 Tabel perbandingan

Fungsi Input Output Contoh Penggunaan
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

5 Referensi

LS0tDQp0aXRsZTogIioqRnVuZ3NpIEFwcGx5IGFuZCBGYW1pbHkqKiINCmF1dGhvcjogfA0KICAqKktlbG9tcG9rIDEqKg0KZGF0ZTogImByIGZvcm1hdChTeXMuRGF0ZSgpLCAnJWQgJUIgJVknKWAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdGhlbWU6IHVuaXRlZCAgICAgICAgIyBUZW1hIGNlcmFoIGRlbmdhbiBha3NlbiBvcmFueWUtbWVyYWggeWFuZyB2aWJyYW50DQogICAgaGlnaGxpZ2h0OiB0YW5nbyAgICAgIyBTa2VtYSB3YXJuYSBrb2RlIHlhbmcgbGViaWggaGlkdXANCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZGVwdGg6IDMNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IGZhbHNlDQogICAgICBzbW9vdGhfc2Nyb2xsOiB0cnVlDQogICAgICB0b2NfY29sb3I6ICIjNTc4RkNBIiAgDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgIHNlY3Rpb25fZGl2czogdHJ1ZSAgICAjIE1lbWJ1YXQgc2VjdGlvbiBsZWJpaCB0ZXJwaXNhaCBzZWNhcmEgdmlzdWFsDQogICAgZmlnX3dpZHRoOiAxMA0KICAgIGZpZ19oZWlnaHQ6IDYNCiAgICBmaWdfYWxpZ246ICdjZW50ZXInDQogICAgY3NzOiB8DQogICAgICBib2R5IHsNCiAgICAgICAgY29sb3I6ICMzMzMzMzM7DQogICAgICB9DQogICAgICBoMSwgaDIsIGgzIHsNCiAgICAgICAgY29sb3I6ICMyQzNFNTA7DQogICAgICAgIGJvcmRlci1ib3R0b206IDJweCBzb2xpZCAjRTY5RjAwOw0KICAgICAgICBwYWRkaW5nLWJvdHRvbTogNXB4Ow0KICAgICAgfQ0KICAgICAgYSB7DQogICAgICAgIGNvbG9yOiAjRTc0QzNDOw0KICAgICAgfQ0KICAgICAgLm1haW4tY29udGFpbmVyIHsNCiAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogI0Y5RjlGOTsNCiAgICAgICAgcGFkZGluZzogMjBweDsNCiAgICAgIH0NCi0tLQ0KDQoNCi0tLQ0KDQojICoqUGVuZGFodWx1YW4qKg0KDQpEYWxhbSBwZW1yb2dyYW1hbiBSLCBlZmlzaWVuc2kgZGFuIGtldGVyYmFjYWFuIGtvZGUgc2VyaW5na2FsaSBtZW5qYWRpIGt1bmNpIGRhbGFtIHBlbmdvbGFoYW4gZGF0YSB5YW5nIGtvbXBsZWtzLiBVbnR1ayBtZW5jYXBhaSBoYWwgdGVyc2VidXQsIFIgbWVueWVkaWFrYW4gc2VrdW1wdWxhbiBmdW5nc2kgeWFuZyBkaWtlbmFsIHNlYmFnYWkga2VsdWFyZ2EgYXBwbHkoKSwgeWFpdHUgYXBwbHkoKSwgbGFwcGx5KCksIHNhcHBseSgpLCBkYW4gdGFwcGx5KCkuIEZ1bmdzaS1mdW5nc2kgaW5pIG1lbmR1a3VuZyBwcmluc2lwIHZlY3Rvcml6YXRpb24gZGFuIGZ1bmN0aW9uYWwgcHJvZ3JhbW1pbmcsIHlhbmcgbWVtdWRhaGthbiBwZW1yb3Nlc2FuIGVsZW1lbiBkYXRhIHRhbnBhIHBlcmx1IG1lbmdndW5ha2FuIGZvciBsb29wIHNlY2FyYSBla3NwbGlzaXQuDQoNCi0gYXBwbHkoKSBkaWd1bmFrYW4gdW50dWsgbWVuZXJhcGthbiBmdW5nc2kga2Ugc2VsdXJ1aCBiYXJpcyBhdGF1IGtvbG9tIG1hdHJpa3MgYXRhdSBhcnJheS4NCi0gbGFwcGx5KCkgZGlndW5ha2FuIHVudHVrIG1lbmVyYXBrYW4gZnVuZ3NpIGtlIHNldGlhcCBlbGVtZW4gZGFsYW0gbGlzdCBkYW4gbWVuZ2VtYmFsaWthbiBsaXN0IGhhc2lsbnlhLg0KLSBzYXBwbHkoKSBtZW5jb2JhIG1lbnllZGVyaGFuYWthbiBoYXNpbCBsYXBwbHkoKSBtZW5qYWRpIHZla3RvciBhdGF1IG1hdHJpa3MsIGppa2EgbWVtdW5na2lua2FuLg0KLSB0YXBwbHkoKSBpZGVhbCB1bnR1ayBhZ3JlZ2FzaSBkYXRhIGJlcmRhc2Fya2FuIGtlbG9tcG9rL2Zha3RvciB0ZXJ0ZW50dS4NCg0KUGVuZ2d1bmFhbiBmdW5nc2ktZnVuZ3NpIGluaSB0aWRhayBoYW55YSBtZW1wZXJjZXBhdCBla3Nla3VzaSwgdGV0YXBpIGp1Z2EgbWVtcGVyamVsYXMgYWx1ciBsb2dpa2EgcGVtcm9ncmFtYW4uIE1lcmVrYSBqdWdhIG1lcnVwYWthbiBwZXJ3dWp1ZGFuIGRhcmkgc3RyYXRlZ2kgc3BsaXTigJNhcHBseeKAk2NvbWJpbmUsIHlhaXR1IHBlbmRla2F0YW4gZGkgbWFuYSBkYXRhIGRpYmFnaSBtZW5qYWRpIGtlbG9tcG9rLCBmdW5nc2kgZGl0ZXJhcGthbiBwYWRhIHRpYXAga2Vsb21wb2ssIGRhbiBoYXNpbG55YSBkaWdhYnVuZ2thbiBrZW1iYWxpLg0KDQotLS0NCg0KIyMgKipLZXVuZ2d1bGFuIEZ1bmdzaSBhcHBseSBkYW4ga2VsdWFyZ2FueWEgKioNCg0KMS4gKipNZW5nZ2FudGkgTG9vcCBUcmFkaXNpb25hbCoqICANCiAgIERhcmlwYWRhIG1lbmdndW5ha2FuIHBlcnVsYW5nYW4gYGZvcmAsIGtlbHVhcmdhIGFwcGx5IG1lbXVuZ2tpbmthbiB1bnR1ayBtZW51bGlzIGtvZGUgZGVrbGFyYXRpZiB5YW5nIGxlYmloIG11ZGFoIGRpYmFjYS4NCg0KMi4gKipFZmlzaWVuc2kgS2luZXJqYSoqICANCiAgIEZ1bmdzaSBhcHBseSB1bXVtbnlhIGxlYmloIGNlcGF0IGRhcmlwYWRhIGBmb3JgIGxvb3Aga2FyZW5hIG9wdGltYWxpc2FzaSBpbnRlcm5hbCBvbGVoIGludGVycHJldGVyIFIuDQoNCjMuICoqRmxla3NpYmlsaXRhcyBUaW5nZ2kqKiAgDQogICBEYXBhdCBkaWd1bmFrYW4gdW50dWsgYmVyYmFnYWkgc3RydWt0dXIgZGF0YTogdmVrdG9yLCBtYXRyaWtzLCBsaXN0LCBhcnJheSwgZGFuIGJhaGthbiBrb21iaW5hc2kgYW50YXItb2JqZWsuDQoNCjQuICoqT3V0cHV0IHlhbmcgS29uc2lzdGVuIGRhbiBEYXBhdCBEaXNlc3VhaWthbioqICANCiAgIEJlYmVyYXBhIGZ1bmdzaSBzZXBlcnRpIGB2YXBwbHkoKWAgbWVtdW5na2lua2FuIGthbXUgbWVuZ29udHJvbCB0aXBlIGRhbiBwYW5qYW5nIGhhc2lsIG91dHB1dCwgbWVuYW1iYWgga2VhbWFuYW4gZGFsYW0gcGVtcm9zZXNhbiBkYXRhIGJlc2FyLg0KICAgDQo1LiAqKlNpbnRha3MgeWFuZyByaW5na2FzKiog4oCUIGN1a3VwIHNhdHUgYmFyaXMga29kZSBkaWJhbmRpbmdrYW4gYmxvayBsb29wIHlhbmcgcGFuamFuZyA6Y29udGVudFJlZmVyZW5jZVtvYWljaXRlOjFde2luZGV4PTF9Lg0KDQo2LiAqKktpbmVyamEgbGViaWggYmFpayoqLCB0ZXJ1dGFtYSBwYWRhIGRhdGFzZXQgYmVzYXIsIGthcmVuYSBwZW1yb3Nlc2FuIHlhbmcgbGViaWggY2VwYXQgZGliYW5kaW5nIGRlbmdhbiBpdGVyYXNpIG1hbnVhbCA6Y29udGVudFJlZmVyZW5jZVtvYWljaXRlOjJde2luZGV4PTJ9Lg0KDQotLS0NCg0KIyAqKkZ1bmdzaSBgYXBwbHlgIGRhbiBLZWx1YXJnYW55YSoqDQoNCiMjICAqKkZ1bmdzaSBgYXBwbHkoKWAuKioNCg0KRnVuZ3NpIGBhcHBseSgpYCBhZGFsYWggZnVuZ3NpIGRpIFIgeWFuZyBkaWd1bmFrYW4gdW50dWsgbWVuZXJhcGthbiBzdWF0dSBmdW5nc2kgdGVydGVudHUsIHNlcGVydGkgcGVuanVtbGFoYW4sIHJhdGEtcmF0YSwgYXRhdSBuaWxhaSBtYWtzaW11bSwga2Ugc2VsdXJ1aCBiYXJpcyBhdGF1IGtvbG9tIGRhcmkgZGF0YSB5YW5nIGJlcmJlbnR1ayBtYXRyaWtzLCBhcnJheSwgYXRhdSBkYXRhIGZyYW1lLiBEZW5nYW4gbWVuZ2d1bmFrYW4gYXBwbHkoKSwga2l0YSBiaXNhIG1lbGFrdWthbiBwZXJoaXR1bmdhbiBzZWNhcmEgZWZpc2llbiB0YW5wYSBoYXJ1cyBtZW5ndWxhbmcgcGVyaW50YWggdW50dWsgdGlhcCBiYXJpcyBhdGF1IGtvbG9tIHNlY2FyYSBtYW51YWwuDQoNCiMjIyAqKlN0cnVrdHVyIFVtdW0qKg0KDQphcHBseShYLCBNQVJHSU4sIEZVTiwgLi4uKQ0KDQpLZXRlcmFuZ2FuOg0KDQotIFg6IE9iamVrIHlhbmcgYWthbiBkaWl0ZXJhc2ksIHNlcGVydGkgbWF0cmlrcyBhdGF1IGFycmF5Lg0KLSBNQVJHSU46IEFuZ2thIHlhbmcgbWVudW5qdWtrYW4gZGltZW5zaSB5YW5nIGFrYW4gZGl0ZXJhcGthbiBmdW5nc2kuIDEgdW50dWsgYmFyaXMsIDIgdW50dWsga29sb20sIGRhbiBjKDEsIDIpIHVudHVrIHNlbHVydWggZWxlbWVuLg0KLSBGVU46IEZ1bmdzaSB5YW5nIGFrYW4gZGl0ZXJhcGthbiBwYWRhIHNldGlhcCBiYXJpcyBhdGF1IGtvbG9tLg0KLSAuLi46IEFyZ3VtZW4gdGFtYmFoYW4geWFuZyBha2FuIGRpdGVydXNrYW4ga2UgZnVuZ3NpIEZVTi4NCg0KIyMjICoqQ29udG9oIFBlbmdndW5hYW4qKg0KDQpgYGB7cn0NCiMgTWVtYnVhdCBtYXRyaXggbmlsYWkgc2lzd2ENCm5pbGFpIDwtIG1hdHJpeCgNCiAgYyg4MCwgNzAsIDk1LCAgICMgTWF0ZW1hdGlrYQ0KICAgIDg1LCA2NSwgOTAsICAgIyBGaXNpa2ENCiAgICA5MCwgNzUsIDg1LCAgICMgS2ltaWENCiAgICA3NSwgNjAsIDgwKSwgICMgQmlvbG9naQ0KICBucm93ID0gMywNCiAgYnlyb3cgPSBGQUxTRQ0KKQ0KDQojIFRhbWJhaGthbiBuYW1hIGJhcmlzIGRhbiBrb2xvbQ0Kcm93bmFtZXMobmlsYWkpIDwtIGMoIlNpc3dhMSIsICJTaXN3YTIiLCAiU2lzd2EzIikNCmNvbG5hbWVzKG5pbGFpKSA8LSBjKCJNYXRlbWF0aWthIiwgIkZpc2lrYSIsICJLaW1pYSIsICJCaW9sb2dpIikNCg0KIyBUYW1waWxrYW4gbWF0cml4DQpuaWxhaQ0KDQojIE1lbmFtcGlsa2FuIGhhc2lsIGFwcGx5DQphcHBseShuaWxhaSwgMSwgc3VtKSAgICAgIyB0b3RhbCBuaWxhaSBwZXIgc2lzd2ENCmFwcGx5KG5pbGFpLCAxLCBtZWFuKSAgICAjIHJhdGEtcmF0YSBuaWxhaSBwZXIgc2lzd2ENCmFwcGx5KG5pbGFpLCAyLCBtZWFuKSAgICAjIHJhdGEtcmF0YSBwZXIgbWF0YSBwZWxhamFyYW4NCmFwcGx5KG5pbGFpLCAxLCBtYXgpICAgICAjIG5pbGFpIHRlcnRpbmdnaSB0aWFwIHNpc3dhDQphcHBseShuaWxhaSwgMSwgc29ydCkgICAgIyB1cnV0a2FuIG5pbGFpIHRpYXAgc2lzd2ENCmBgYA0KDQojIyAgKipGdW5nc2kgYGxhcHBseSgpYC4qKg0KDQpGdW5nc2kgYGxhcHBseSgpYCBkaSBSIGRpZ3VuYWthbiB1bnR1ayBtZW5qYWxhbmthbiBzdWF0dSBmdW5nc2kgcGFkYSBzZXRpYXAgZWxlbWVuIGRhcmkgc2VidWFoIGxpc3QsIHZla3RvciwgYXRhdSBkYXRhIGZyYW1lLCBsYWx1IGhhc2lsbnlhIGFrYW4gZGlrZW1iYWxpa2FuIGRhbGFtIGJlbnR1ayBsaXN0IGp1Z2EsIGRlbmdhbiBqdW1sYWggZWxlbWVuIHlhbmcgc2FtYSBzZXBlcnRpIGlucHV0bnlhLiBLYXJlbmEgYGxhcHBseSgpYCBsYW5nc3VuZyBiZWtlcmphIHBhZGEgc2V0aWFwIGVsZW1lbiBkYWxhbSBsaXN0LCBraXRhIHRpZGFrIHBlcmx1IG1lbmVudHVrYW4gYmFyaXMgYXRhdSBrb2xvbSAodGlkYWsgcGVybHUgcGFrYWkgYE1BUkdJTmApLg0KDQojIyMgKipTdHJ1a3R1ciBVbXVtKioNCg0KbGFwcGx5KFgsIEZVTiwgLi4uKQ0KDQpLZXRlcmFuZ2FuOg0KDQotIFg6IE9iamVrIHlhbmcgYWthbiBkaWl0ZXJhc2ksIHNlcGVydGkgbGlzdCBhdGF1IHZla3Rvci4NCi0gRlVOOiBGdW5nc2kgeWFuZyBha2FuIGRpdGVyYXBrYW4gcGFkYSBzZXRpYXAgZWxlbWVuIGRhcmkgYFhgLg0KLSAuLi46IEFyZ3VtZW4gdGFtYmFoYW4geWFuZyBha2FuIGRpdGVydXNrYW4ga2UgZnVuZ3NpIGBGVU5gLg0KDQojIyMgKipDb250b2ggUGVuZ2d1bmFhbioqDQoNCmBgYHtyfQ0KIyBMaXN0IGJlcmlzaSBuaWxhaSBkYXJpIGJlYmVyYXBhIHNpc3dhDQpuaWxhaV9zaXN3YSA8LSBsaXN0KA0KICBTaXN3YTEgPSBjKDgwLCA4NSwgOTApLA0KICBTaXN3YTIgPSBjKDc1LCA3MCwgODApLA0KICBTaXN3YTMgPSBjKDkwLCA5NSwgODUpDQopDQoNCiMgSGl0dW5nIHJhdGEtcmF0YSBuaWxhaSBzZXRpYXAgc2lzd2ENCmxhcHBseShuaWxhaV9zaXN3YSwgbWVhbikNCmBgYA0KDQojIyAgKipGdW5nc2kgYHNhcHBseSgpYC4qKg0KDQpGdW5nc2kgYHNhcHBseSgpYCBhZGFsYWggc2FsYWggc2F0dSBmdW5nc2kgZGFyaSBrZWx1YXJnYSBhcHBseSBkaSBSIHlhbmcgZGlndW5ha2FuIHVudHVrIG1lbmVyYXBrYW4gc3VhdHUgZnVuZ3NpIGtlIHNldGlhcCBlbGVtZW4gZGFyaSBsaXN0LCB2ZWN0b3IsIGF0YXUgZGF0YSBmcmFtZS4gRnVuZ3NpIGluaSBiZWtlcmphIG1pcmlwIHNlcGVydGkgYGxhcHBseSgpYCwgdGV0YXBpIGBzYXBwbHkoKWAgKipzZWNhcmEgb3RvbWF0aXMgbWVuY29iYSBtZW55ZWRlcmhhbmFrYW4gaGFzaWxueWEgbWVuamFkaSBiZW50dWsgeWFuZyBsZWJpaCBzZWRlcmhhbmEqKiwgeWFpdHUgYmVydXBhICoqdmVjdG9yKiosICoqbWF0cml4KiosIGF0YXUgKiphcnJheSoqLCBqaWthIG1lbXVuZ2tpbmthbi4gRnVuZ3NpIGBzYXBwbHkoKWAgc2FuZ2F0IGJlcmd1bmEgdW50dWsgbWVuZ2hpbmRhcmkgaGFzaWwgYmVydXBhIGxpc3QgamlrYSBoYXNpbCB5YW5nIGxlYmloIHNlZGVyaGFuYSBkYXBhdCBkaWJ1YXQuDQoNCiMjIyAqKlN0cnVrdHVyIHVtdW0qKg0KDQpzYXBwbHkoWCwgRlVOLCAuLi4pDQoNCktldGVyYW5nYW46DQoNCi0gWCA9IGxpc3QsIHZlY3RvciwgYXRhdSBkYXRhIGZyYW1lIHlhbmcgYWthbiBkaXByb3Nlcw0KLSBGVU4gPSBmdW5nc2kgeWFuZyBha2FuIGRpdGVyYXBrYW4gcGFkYSBzZXRpYXAgZWxlbWVuDQotIC4uLiA9IGFyZ3VtZW4gdGFtYmFoYW4gdW50dWsgZnVuZ3NpIHRlcnNlYnV0DQoNCiMjIyAqKkNvbnRvaCBQZW5nZ3VuYWFuKioNCmBgYHtyfQ0KI0t1YWRyYXQgYW5na2EgMSBzYW1wYWkgNQ0KaGFzaWxfa3VhZHJhdCA8LSBzYXBwbHkoMTo1LCBmdW5jdGlvbih4KSB4XjIpDQpoYXNpbF9rdWFkcmF0DQoNCiMjIENvbnRvaCBkYXRhIGp1bWxhaCBzb2FsDQpqdW1sYWhfc29hbCA8LSBjKDUsIDYsIDcsIDgsIDkpDQoNCiNIaXR1bmcgc29hbCBnZW5hcCBkYWxhbSBzYXR1IHNhcHBseQ0KaGFzaWxfc2FwcGx5IDwtIHNhcHBseShqdW1sYWhfc29hbCwgZnVuY3Rpb24obikgew0KICBzb2FsIDwtIDE6biAgICAgICAgICMgQnVhdCB1cnV0YW4gMSBzYW1wYWkgbg0KICBzdW0oc29hbCAlJSAyID09IDApICMgSGl0dW5nIGJlcmFwYSB5YW5nIGdlbmFwDQp9KQ0KDQpoYXNpbF9zYXBwbHkNCmBgYA0KDQojIyAgKipGdW5nc2kgYHRhcHBseSgpYC4qKg0KDQpGdW5nc2kgYHRhcHBseSgpYCBtZXJ1cGFrYW4gc2FsYWggc2F0dSBmdW5nc2kgcGVudGluZyBkaSBSIHlhbmcgZGlndW5ha2FuIHVudHVrIG1lbWJ1YXQgcmluZ2thc2FuIGRhdGEgZGFsYW0gYmVudHVrIHRhYmVsLiBGdW5nc2kgaW5pIGJla2VyamEgZGVuZ2FuIGNhcmEgbWVuZXJhcGthbiBzdWF0dSBmdW5nc2kgdGVydGVudHUgKHNlcGVydGkgbWVhbiBhdGF1IHZhcmlhbmNlKSBwYWRhIGtlbG9tcG9rIGRhdGEgYmVyZGFzYXJrYW4ga2F0ZWdvcmkgdGVydGVudHUgKGZha3RvcikuDQoNCiMjIyAqKlN0cnVrdHVyIHVtdW0qKg0KDQp0YXBwbHkoWCwgSU5ERVgsIEZVTiwgLi4uKQ0KDQpLZXRlcmFuZ2FuOg0KDQotIFggPSB2ZWt0b3IgeWFuZyBiZXJpc2kgZGF0YSBudW1lcmlrIGF0YXUga2FyYWt0ZXIgIA0KLSBJTkRFWCA9IGZha3RvciAoYXRhdSBsaXN0IGZha3RvcikgeWFuZyBtZW5kZWZpbmlzaWthbiBrZWxvbXBvayAgDQotIEZVTiA9IGZ1bmdzaSB5YW5nIGFrYW4gZGl0ZXJhcGthbiBrZSBtYXNpbmctbWFzaW5nIGtlbG9tcG9rICANCi0gLi4uID0gYXJndW1lbiB0YW1iYWhhbiB1bnR1ayBmdW5nc2kgIA0KDQojIyMgKipDb250b2ggUGVuZ2d1bmFhbioqDQoNCmBgYHtyIGRhdGEtbmlsYWl9DQojIERhdGEgbmlsYWkgc2lzd2ENCm5pbGFpIDwtIGMoODAsIDc1LCA5MCwgODUsIDcwLCA5NSwgODgsIDc3KQ0KDQojIERhdGEgamVuaXMga2VsYW1pbiAoTCA9IGxha2ktbGFraSwgUCA9IHBlcmVtcHVhbikNCmdlbmRlciA8LSBjKCJMIiwgIlAiLCAiTCIsICJQIiwgIlAiLCAiTCIsICJMIiwgIlAiKQ0KDQojIFRhbXBpbGthbiBzZWJhZ2FpIGRhdGEgZnJhbWUNCmRhdGEuZnJhbWUoTmlsYWkgPSBuaWxhaSwgR2VuZGVyID0gZ2VuZGVyKQ0KdGFwcGx5KG5pbGFpLCBnZW5kZXIsIG1lYW4pDQp0YXBwbHkobmlsYWksIGdlbmRlciwgbGVuZ3RoKQ0KYGBgDQoNCg0KIyAqKktlc2ltcHVsYW4qKg0KS2VsdWFyZ2EgZnVuZ3NpIGBhcHBseWAgZGkgUiBtZW55ZWRpYWthbiBjYXJhIHlhbmcgZWZpc2llbiBkYW4gaWRpb21hdGlrIHVudHVrIG1lbmVyYXBrYW4gZnVuZ3NpIHBhZGEgZWxlbWVuLWVsZW1lbiBkYXJpIHN0cnVrdHVyIGRhdGEgc2VwZXJ0aSB2ZWt0b3IsIG1hdHJpa3MsIGxpc3QsIGRhbiBkYXRhIGZyYW1lLiBEZW5nYW4gbWVuZ2d1bmFrYW4gZnVuZ3NpLWZ1bmdzaSBzZXBlcnRpIGBhcHBseSgpYCwgYGxhcHBseSgpYCwgYHNhcHBseSgpYCwgYHRhcHBseSgpYCwgYHZhcHBseSgpYCwgYG1hcHBseSgpYCwgZGFuIGByYXBwbHkoKWAsIHBlbmdndW5hIGRhcGF0IG1lbmdoaW5kYXJpIHBlbmdndW5hYW4gcGVydWxhbmdhbiBla3NwbGlzaXQsIG1lbWJ1YXQga29kZSBsZWJpaCByaW5na2FzLCBkYW4gbWVuaW5na2F0a2FuIGtpbmVyamEgcGVtcm9zZXNhbiBkYXRhLg0KDQojICoqVGFiZWwgcGVyYmFuZGluZ2FuKioNCnwgRnVuZ3NpICAgIHwgSW5wdXQgICAgICAgICB8IE91dHB1dCAgICAgICAgfCBDb250b2ggUGVuZ2d1bmFhbiAgICAgICAgICAgICAgICAgICAgICB8DQp8LS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfA0KfCBgYXBwbHkoKWAgfCBNYXRyaWtzL0FycmF5IHwgVmVrdG9yICAgICAgICB8IE1lbmdoaXR1bmcgcmF0YS1yYXRhIHBlciBrb2xvbSAgICAgICAgIHwNCnwgYGxhcHBseSgpYHwgTGlzdC9WZWt0b3IgICB8IExpc3QgICAgICAgICAgfCBNZW5naGl0dW5nIHBhbmphbmcgc2V0aWFwIGVsZW1lbiAgICAgICB8DQp8IGBzYXBwbHkoKWB8IExpc3QvVmVrdG9yICAgfCBWZWt0b3IvTWF0cml4IHwgTWVuZ2hpdHVuZyBrdWFkcmF0IHNldGlhcCBlbGVtZW4gICAgICAgfA0KfCBgdGFwcGx5KClgfCBWZWt0b3IgICAgICAgIHwgQXJyYXkgICAgICAgICB8IE1lbmdoaXR1bmcgcmF0YS1yYXRhIGJlcmRhc2Fya2FuIGdydXAgICB8DQoNCiMgKipSZWZlcmVuc2kqKg0KLSBHZWVrc2ZvckdlZWtzLiAoMjAyMikuICphcHBseSgpLCBsYXBwbHkoKSwgc2FwcGx5KCksIGFuZCB0YXBwbHkoKSBpbiBSKi4gUmV0cmlldmVkIGZyb20gPGh0dHBzOi8vd3d3LmdlZWtzZm9yZ2Vla3Mub3JnL2FwcGx5LWxhcHBseS1zYXBwbHktYW5kLXRhcHBseS1pbi1yLz4NCi0gRGF0YXF1ZXN0LiAoMjAyMSkuIEFwcGx5IEZ1bmN0aW9ucyBpbiBSIHdpdGggRXhhbXBsZXMuIDxodHRwczovL3d3dy5kYXRhcXVlc3QuaW8vYmxvZy9hcHBseS1mdW5jdGlvbnMtaW4tci8+DQoNCg0KDQoNCg==